[Pkg-golang-commits] [golang] 01/01: Revert to latest release (moving 1.5 to experimental branch)

Tianon Gravi tianon at debian.org
Mon Sep 14 15:59:01 UTC 2015


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

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

commit d5faeb41804801f6e2ac69a3923cba00f19ddb51
Author: Tianon Gravi <tianon at debian.org>
Date:   Mon Sep 14 08:58:27 2015 -0700

    Revert to latest release (moving 1.5 to experimental branch)
---
 .hgignore                                          |   58 +
 .hgtags                                            |  138 +
 AUTHORS                                            |   99 +-
 CONTRIBUTORS                                       |  123 +-
 README                                             |   32 +
 VERSION                                            |    2 +-
 api/except.txt                                     |    1 -
 api/next.txt                                       |  141 +
 debian/changelog                                   |   15 -
 debian/control                                     |  314 +-
 debian/control.base                                |  103 +
 debian/control.cross                               |   18 +
 debian/copyright                                   |  182 +-
 debian/docs                                        |    2 +-
 debian/golang-doc.links                            |    2 +-
 debian/golang-go.install                           |    4 +-
 debian/golang-go.links                             |    2 +-
 debian/golang-go.postinst                          |   11 +-
 debian/golang-src.install                          |    1 +
 debian/rules                                       |   68 +-
 debian/source/lintian-overrides                    |   20 +-
 doc/articles/go_command.html                       |   13 +-
 doc/articles/wiki/final.go                         |   22 +
 doc/articles/wiki/test.bash                        |   20 +-
 doc/asm.html                                       |  375 +-
 doc/code.html                                      |   16 +-
 doc/contrib.html                                   |    5 -
 doc/contribute.html                                |  172 +-
 doc/devel/release.html                             |  456 +-
 doc/devel/weekly.html                              |    2 +-
 doc/effective_go.html                              |   58 +-
 doc/gccgo_contribute.html                          |   24 +-
 doc/gccgo_install.html                             |   51 +-
 doc/go1.1.html                                     |    2 +-
 doc/go1.4.html                                     |    2 +-
 doc/go1compat.html                                 |   12 -
 doc/go_faq.html                                    |  211 +-
 doc/go_mem.html                                    |    8 +-
 doc/go_spec.html                                   |  266 +-
 doc/gopher/README                                  |    2 +-
 doc/install-source.html                            |  111 +-
 doc/install.html                                   |  103 +-
 doc/logo-153x55.png                                |  Bin 0 -> 3382 bytes
 doc/play/peano.go                                  |    6 +-
 doc/progs/cgo1.go                                  |    3 +-
 doc/progs/cgo2.go                                  |    3 +-
 doc/progs/cgo3.go                                  |    3 +-
 doc/progs/cgo4.go                                  |    3 +-
 doc/progs/defer.go                                 |    2 +
 doc/progs/defer.out                                |    3 +
 doc/progs/defer2.go                                |    2 +
 doc/progs/defer2.out                               |   12 +
 doc/progs/eff_bytesize.go                          |    2 +
 doc/progs/eff_bytesize.out                         |    1 +
 doc/progs/eff_qr.go                                |    2 +
 doc/progs/eff_sequence.go                          |    2 +
 doc/progs/eff_sequence.out                         |    1 +
 doc/progs/eff_unused1.go                           |    2 +
 doc/progs/eff_unused2.go                           |    2 +
 doc/progs/error.go                                 |    2 +
 doc/progs/error2.go                                |    2 +
 doc/progs/error3.go                                |    2 +
 doc/progs/error4.go                                |    2 +
 doc/progs/go1.go                                   |    3 +
 doc/progs/gobs1.go                                 |    2 +
 doc/progs/gobs2.go                                 |    2 +
 doc/progs/image_draw.go                            |    2 +
 doc/progs/image_package1.go                        |    2 +
 doc/progs/image_package1.out                       |    1 +
 doc/progs/image_package2.go                        |    2 +
 doc/progs/image_package2.out                       |    1 +
 doc/progs/image_package3.go                        |    2 +
 doc/progs/image_package3.out                       |    1 +
 doc/progs/image_package4.go                        |    2 +
 doc/progs/image_package4.out                       |    1 +
 doc/progs/image_package5.go                        |    2 +
 doc/progs/image_package5.out                       |    1 +
 doc/progs/image_package6.go                        |    2 +
 doc/progs/image_package6.out                       |    2 +
 doc/progs/interface.go                             |    2 +
 doc/progs/interface2.go                            |    2 +
 doc/progs/interface2.out                           |    1 +
 doc/progs/json1.go                                 |    2 +
 doc/progs/json2.go                                 |    2 +
 doc/progs/json2.out                                |    2 +
 doc/progs/json3.go                                 |    2 +
 doc/progs/json4.go                                 |    2 +
 doc/progs/json5.go                                 |    2 +
 doc/progs/run                                      |  125 +
 doc/progs/slices.go                                |    2 +
 doc/progs/timeout1.go                              |    3 +-
 doc/progs/timeout2.go                              |    3 +-
 doc/progs/update.bash                              |   15 +
 doc/root.html                                      |    2 +-
 doc/sieve.gif                                      |  Bin 0 -> 11019 bytes
 include/README                                     |    6 +
 include/ar.h                                       |   47 +
 include/bio.h                                      |  144 +
 include/fmt.h                                      |  116 +
 include/libc.h                                     |  405 ++
 include/link.h                                     |  631 +++
 include/plan9/386/u.h                              |   17 +
 include/plan9/amd64/u.h                            |   17 +
 include/plan9/arm/u.h                              |   15 +
 include/plan9/bio.h                                |    8 +
 include/plan9/errno.h                              |    7 +
 include/plan9/fmt.h                                |   64 +
 include/plan9/libc.h                               |   33 +
 include/plan9/link.h                               |    5 +
 include/plan9/mklibc.rc                            |    8 +
 include/plan9/stdarg.h                             |    3 +
 include/plan9/utf.h                                |    5 +
 include/u.h                                        |  233 +
 include/utf.h                                      |    1 +
 lib/time/update.bash                               |    4 +-
 lib/time/zoneinfo.zip                              |  Bin 359824 -> 360713 bytes
 misc/android/README                                |    4 +-
 misc/android/go_android_exec.go                    |   82 +-
 misc/cgo/errors/test.bash                          |    2 -
 misc/cgo/gmp/gmp.go                                |    2 +-
 misc/cgo/test/backdoor/backdoor.go                 |    7 +
 misc/cgo/test/backdoor/runtime_gccgo.c             |   18 +
 misc/cgo/test/backdoor/thunk.s                     |   16 +
 misc/cgo/test/callback.go                          |   17 +-
 misc/cgo/test/callback_c_gc.c                      |   55 +
 misc/cgo/test/callback_c_gccgo.c                   |   49 +
 misc/cgo/test/cflags.go                            |    2 +-
 misc/cgo/test/cgo_linux_test.go                    |    8 +-
 misc/cgo/test/cgo_test.go                          |    4 +-
 misc/cgo/test/cthread_unix.c                       |    2 +-
 misc/cgo/test/issue3261.go                         |    6 -
 misc/cgo/test/issue3945.go                         |    2 +-
 misc/cgo/test/issue6997_linux.go                   |    2 +-
 misc/cgo/test/issue7234_test.go                    |    4 +-
 misc/cgo/test/issue7978.go                         |   25 +-
 misc/cgo/test/issue8428.go                         |    7 +-
 misc/cgo/test/setgid_linux.go                      |    2 +-
 misc/cgo/testcdefs/cdefstest.c                     |    9 +
 misc/cgo/testcdefs/cdefstest.go                    |   60 +
 misc/cgo/testcdefs/main.c                          |   76 +
 misc/cgo/testcdefs/main.go                         |   13 +
 misc/cgo/testcdefs/test.bash                       |   16 +
 misc/cgo/testgodefs/test.bash                      |    2 -
 misc/cgo/testso/cgoso.go                           |    1 -
 misc/cgo/testso/cgoso_unix.go                      |    2 +-
 misc/cgo/testso/test.bash                          |   22 +
 misc/cgo/testso/test.bat                           |   18 +
 misc/chrome/gophertool/gopher.js                   |   19 +-
 misc/chrome/gophertool/popup.html                  |   12 +-
 misc/dashboard/codereview/app.yaml                 |   24 +
 misc/dashboard/codereview/cron.yaml                |    4 +
 misc/dashboard/codereview/dashboard/cl.go          |  493 ++
 misc/dashboard/codereview/dashboard/front.go       |  299 ++
 misc/dashboard/codereview/dashboard/gc.go          |   47 +
 misc/dashboard/codereview/dashboard/mail.go        |   68 +
 misc/dashboard/codereview/dashboard/people.go      |   65 +
 misc/dashboard/codereview/index.yaml               |   25 +
 misc/dashboard/codereview/queue.yaml               |    4 +
 misc/dashboard/codereview/static/gopherstamp.jpg   |  Bin 0 -> 16996 bytes
 misc/dashboard/codereview/static/icon.png          |  Bin 0 -> 412 bytes
 misc/editors                                       |    2 +-
 misc/makerelease/darwin/Distribution               |   32 +
 misc/makerelease/darwin/Resources/bg.png           |  Bin 0 -> 11466 bytes
 misc/makerelease/darwin/etc/paths.d/go             |    1 +
 misc/makerelease/darwin/scripts/postinstall        |   10 +
 misc/makerelease/darwin/scripts/preinstall         |    8 +
 misc/makerelease/makerelease.go                    | 1075 ++++
 misc/makerelease/windows/LICENSE.rtf               |  Bin 0 -> 1687 bytes
 misc/makerelease/windows/README.txt                |   25 +
 misc/makerelease/windows/images/Banner.jpg         |  Bin 0 -> 6643 bytes
 misc/makerelease/windows/images/Dialog.jpg         |  Bin 0 -> 16428 bytes
 misc/makerelease/windows/images/DialogLeft.jpg     |  Bin 0 -> 12961 bytes
 misc/makerelease/windows/images/gopher.ico         |  Bin 0 -> 30166 bytes
 misc/makerelease/windows/installer.wxs             |  163 +
 misc/nacl/README                                   |   21 +-
 misc/nacl/testzip.proto                            |   23 -
 misc/swig/callback/callback_test.go                |   13 +-
 misc/swig/stdio/file_test.go                       |    2 +-
 src/androidtest.bash                               |   45 +-
 src/archive/tar/common.go                          |   28 +-
 src/archive/tar/example_test.go                    |    1 -
 src/archive/tar/reader.go                          |   17 +-
 src/archive/tar/reader_test.go                     |   61 +-
 src/archive/tar/tar_test.go                        |   63 +-
 src/archive/tar/writer.go                          |    2 +-
 src/archive/tar/writer_test.go                     |   55 -
 src/archive/zip/reader.go                          |   32 +-
 src/archive/zip/reader_test.go                     |   74 -
 src/archive/zip/struct.go                          |    6 +-
 src/archive/zip/testdata/readme.notzip             |  Bin 1906 -> 1905 bytes
 src/archive/zip/testdata/readme.zip                |  Bin 1886 -> 1885 bytes
 src/archive/zip/writer.go                          |   37 +-
 src/archive/zip/writer_test.go                     |   35 -
 src/archive/zip/zip_test.go                        |   36 +-
 src/bufio/bufio.go                                 |   34 +-
 src/bufio/bufio_test.go                            |  146 -
 src/bufio/scan.go                                  |    2 +-
 src/builtin/builtin.go                             |    8 +-
 src/bytes/buffer.go                                |    4 -
 src/bytes/buffer_test.go                           |   17 -
 src/bytes/bytes.go                                 |   15 +-
 src/bytes/bytes_decl.go                            |    2 +-
 src/bytes/bytes_test.go                            |   17 -
 src/bytes/compare_test.go                          |    3 -
 src/bytes/export_test.go                           |    4 +
 src/bytes/reader.go                                |    6 -
 src/bytes/reader_test.go                           |   12 -
 src/clean.bash                                     |   16 +-
 src/clean.bat                                      |    5 +-
 src/clean.rc                                       |    3 +-
 src/cmd/5a/Makefile                                |   10 +
 src/cmd/5a/a.h                                     |  169 +
 src/cmd/5a/a.y                                     |  747 +++
 src/cmd/5a/doc.go                                  |   20 +
 src/cmd/5a/lex.c                                   |  538 ++
 src/cmd/5a/y.tab.c                                 | 2936 +++++++++++
 src/cmd/5a/y.tab.h                                 |  188 +
 src/cmd/5c/Makefile                                |    5 +
 src/cmd/5c/cgen.c                                  | 1213 +++++
 src/cmd/5c/doc.go                                  |   16 +
 src/cmd/5c/gc.h                                    |  333 ++
 src/cmd/5c/list.c                                  |   39 +
 src/cmd/5c/mul.c                                   |  640 +++
 src/cmd/5c/peep.c                                  | 1478 ++++++
 src/cmd/5c/reg.c                                   | 1210 +++++
 src/cmd/5c/sgen.c                                  |  265 +
 src/cmd/5c/swt.c                                   |  461 ++
 src/cmd/5c/txt.c                                   | 1361 ++++++
 src/cmd/5g/Makefile                                |    5 +
 src/cmd/5g/cgen.c                                  | 1846 +++++++
 src/cmd/5g/cgen64.c                                |  760 +++
 src/cmd/5g/doc.go                                  |   15 +
 src/cmd/5g/galign.c                                |   49 +
 src/cmd/5g/gg.h                                    |  123 +
 src/cmd/5g/ggen.c                                  |  956 ++++
 src/cmd/5g/gobj.c                                  |  252 +
 src/cmd/5g/gsubr.c                                 | 2082 ++++++++
 src/cmd/5g/opt.h                                   |  221 +
 src/cmd/5g/peep.c                                  | 1629 +++++++
 src/cmd/5g/prog.c                                  |  151 +
 src/cmd/5g/reg.c                                   | 1453 ++++++
 src/cmd/5l/5.out.h                                 |  347 ++
 src/cmd/5l/Makefile                                |    5 +
 src/cmd/5l/asm.c                                   |  692 +++
 src/cmd/5l/doc.go                                  |   15 +
 src/cmd/5l/l.h                                     |  103 +
 src/cmd/5l/list.c                                  |   70 +
 src/cmd/5l/obj.c                                   |  116 +
 src/cmd/6a/Makefile                                |   10 +
 src/cmd/6a/a.h                                     |  184 +
 src/cmd/6a/a.y                                     |  691 +++
 src/cmd/6a/doc.go                                  |   20 +
 src/cmd/6a/lex.c                                   | 1136 +++++
 src/cmd/6a/y.tab.c                                 | 2801 +++++++++++
 src/cmd/6a/y.tab.h                                 |  139 +
 src/cmd/6c/Makefile                                |    5 +
 src/cmd/6c/cgen.c                                  | 2046 ++++++++
 src/cmd/6c/div.c                                   |  236 +
 src/cmd/6c/doc.go                                  |   16 +
 src/cmd/6c/gc.h                                    |  359 ++
 src/cmd/6c/list.c                                  |   38 +
 src/cmd/6c/machcap.c                               |  107 +
 src/cmd/6c/mul.c                                   |  458 ++
 src/cmd/6c/peep.c                                  |  902 ++++
 src/cmd/6c/reg.c                                   | 1523 ++++++
 src/cmd/6c/sgen.c                                  |  483 ++
 src/cmd/6c/swt.c                                   |  353 ++
 src/cmd/6c/txt.c                                   | 1674 +++++++
 src/cmd/6g/Makefile                                |    5 +
 src/cmd/6g/cgen.c                                  | 1732 +++++++
 src/cmd/6g/doc.go                                  |   15 +
 src/cmd/6g/galign.c                                |   66 +
 src/cmd/6g/gg.h                                    |  122 +
 src/cmd/6g/ggen.c                                  | 1228 +++++
 src/cmd/6g/gobj.c                                  |  235 +
 src/cmd/6g/gsubr.c                                 | 2296 +++++++++
 src/cmd/6g/opt.h                                   |  220 +
 src/cmd/6g/peep.c                                  |  990 ++++
 src/cmd/6g/prog.c                                  |  318 ++
 src/cmd/6g/reg.c                                   | 1315 +++++
 src/cmd/6l/6.out.h                                 |  890 ++++
 src/cmd/6l/Makefile                                |    5 +
 src/cmd/6l/asm.c                                   |  817 ++++
 src/cmd/6l/doc.go                                  |   15 +
 src/cmd/6l/l.h                                     |  109 +
 src/cmd/6l/list.c                                  |   67 +
 src/cmd/6l/obj.c                                   |  157 +
 src/cmd/8a/Makefile                                |   10 +
 src/cmd/8a/a.h                                     |  182 +
 src/cmd/8a/a.y                                     |  687 +++
 src/cmd/8a/doc.go                                  |   21 +
 src/cmd/8a/lex.c                                   |  910 ++++
 src/cmd/8a/y.tab.c                                 | 2779 +++++++++++
 src/cmd/8a/y.tab.h                                 |  139 +
 src/cmd/8c/Makefile                                |    5 +
 src/cmd/8c/cgen.c                                  | 1939 ++++++++
 src/cmd/8c/cgen64.c                                | 2657 ++++++++++
 src/cmd/8c/div.c                                   |  236 +
 src/cmd/8c/doc.go                                  |   16 +
 src/cmd/8c/gc.h                                    |  364 ++
 src/cmd/8c/list.c                                  |   38 +
 src/cmd/8c/machcap.c                               |  116 +
 src/cmd/8c/mul.c                                   |  458 ++
 src/cmd/8c/peep.c                                  |  807 +++
 src/cmd/8c/reg.c                                   | 1438 ++++++
 src/cmd/8c/sgen.c                                  |  483 ++
 src/cmd/8c/swt.c                                   |  341 ++
 src/cmd/8c/txt.c                                   | 1537 ++++++
 src/cmd/8g/Makefile                                |    5 +
 src/cmd/8g/cgen.c                                  | 1579 ++++++
 src/cmd/8g/cgen64.c                                |  549 +++
 src/cmd/8g/doc.go                                  |   15 +
 src/cmd/8g/galign.c                                |   47 +
 src/cmd/8g/gg.h                                    |  135 +
 src/cmd/8g/ggen.c                                  | 1342 +++++
 src/cmd/8g/gobj.c                                  |  246 +
 src/cmd/8g/gsubr.c                                 | 2401 +++++++++
 src/cmd/8g/opt.h                                   |  238 +
 src/cmd/8g/peep.c                                  |  779 +++
 src/cmd/8g/prog.c                                  |  349 ++
 src/cmd/8g/reg.c                                   | 1284 +++++
 src/cmd/8l/8.out.h                                 |  676 +++
 src/cmd/8l/Makefile                                |    5 +
 src/cmd/8l/asm.c                                   |  745 +++
 src/cmd/8l/doc.go                                  |   15 +
 src/cmd/8l/l.h                                     |   95 +
 src/cmd/8l/list.c                                  |   67 +
 src/cmd/8l/obj.c                                   |  138 +
 src/cmd/addr2line/addr2line_test.go                |   24 +-
 src/cmd/api/goapi.go                               |  211 +-
 src/cmd/api/goapi_test.go                          |   15 +-
 src/cmd/api/run.go                                 |  148 +-
 src/cmd/cc/Makefile                                |   10 +
 src/cmd/cc/acid.c                                  |  344 ++
 src/cmd/cc/bits.c                                  |  120 +
 src/cmd/cc/cc.h                                    |  835 ++++
 src/cmd/cc/cc.y                                    | 1220 +++++
 src/cmd/cc/com.c                                   | 1384 ++++++
 src/cmd/cc/com64.c                                 |  644 +++
 src/cmd/cc/dcl.c                                   | 1707 +++++++
 src/cmd/cc/doc.go                                  |   13 +
 src/cmd/cc/dpchk.c                                 |  793 +++
 src/cmd/cc/funct.c                                 |  431 ++
 src/cmd/cc/godefs.c                                |  367 ++
 src/cmd/cc/lex.c                                   | 1593 ++++++
 src/cmd/cc/lexbody                                 |  709 +++
 src/cmd/cc/mac.c                                   |   34 +
 src/cmd/cc/macbody                                 |  800 +++
 src/cmd/cc/omachcap.c                              |   40 +
 src/cmd/cc/pgen.c                                  |  622 +++
 src/cmd/cc/pswt.c                                  |  140 +
 src/cmd/cc/scon.c                                  |  640 +++
 src/cmd/cc/sub.c                                   | 2068 ++++++++
 src/cmd/cc/y.tab.c                                 | 3822 +++++++++++++++
 src/cmd/cc/y.tab.h                                 |  230 +
 src/cmd/cgo/ast.go                                 |    8 -
 src/cmd/cgo/doc.go                                 |  241 +-
 src/cmd/cgo/gcc.go                                 |   96 +-
 src/cmd/cgo/godefs.go                              |  167 +
 src/cmd/cgo/main.go                                |   52 +-
 src/cmd/cgo/out.go                                 |  331 +-
 src/cmd/cgo/util.go                                |    2 +-
 src/cmd/dist/README                                |   62 +-
 src/cmd/dist/a.h                                   |  165 +
 src/cmd/dist/arg.h                                 |   49 +
 src/cmd/dist/arm.c                                 |   72 +
 src/cmd/dist/buf.c                                 |  279 ++
 src/cmd/dist/build.c                               | 1804 +++++++
 src/cmd/dist/buildgc.c                             |  137 +
 src/cmd/dist/buildgo.c                             |   49 +
 src/cmd/dist/buildruntime.c                        |  468 ++
 src/cmd/dist/main.c                                |   42 +
 src/cmd/dist/plan9.c                               |  764 +++
 src/cmd/dist/unix.c                                |  843 ++++
 src/cmd/dist/windows.c                             |  989 ++++
 src/cmd/fix/fix.go                                 |   20 +-
 src/cmd/gc/Makefile                                |   17 +
 src/cmd/gc/align.c                                 |  680 +++
 src/cmd/gc/array.c                                 |  115 +
 src/cmd/gc/bisonerrors                             |  156 +
 src/cmd/gc/bits.c                                  |  163 +
 src/cmd/gc/builtin.c                               |  137 +
 src/cmd/gc/bv.c                                    |  213 +
 src/cmd/gc/closure.c                               |  467 ++
 src/cmd/gc/const.c                                 | 1674 +++++++
 src/cmd/gc/cplx.c                                  |  486 ++
 src/cmd/gc/dcl.c                                   | 1494 ++++++
 src/cmd/gc/doc.go                                  |   95 +
 src/cmd/gc/esc.c                                   | 1281 +++++
 src/cmd/gc/export.c                                |  521 ++
 src/cmd/gc/fmt.c                                   | 1691 +++++++
 src/cmd/gc/gen.c                                   |  991 ++++
 src/cmd/gc/go.errors                               |   79 +
 src/cmd/gc/go.h                                    | 1555 ++++++
 src/cmd/gc/go.y                                    | 2223 +++++++++
 src/cmd/gc/init.c                                  |  195 +
 src/cmd/gc/inl.c                                   |  986 ++++
 src/cmd/gc/lex.c                                   | 2414 +++++++++
 src/cmd/gc/md5.c                                   |  302 ++
 src/cmd/gc/md5.h                                   |   16 +
 src/cmd/gc/mkbuiltin                               |   32 +
 src/cmd/gc/mkbuiltin1.c                            |  102 +
 src/cmd/gc/mkopnames                               |   24 +
 src/cmd/gc/mparith1.c                              |  641 +++
 src/cmd/gc/mparith2.c                              |  716 +++
 src/cmd/gc/mparith3.c                              |  346 ++
 src/cmd/gc/obj.c                                   |  284 ++
 src/cmd/gc/order.c                                 | 1101 +++++
 src/cmd/gc/pgen.c                                  |  539 ++
 src/cmd/gc/plive.c                                 | 2017 ++++++++
 src/cmd/gc/popt.c                                  | 1005 ++++
 src/cmd/gc/popt.h                                  |   46 +
 src/cmd/gc/racewalk.c                              |  664 +++
 src/cmd/gc/range.c                                 |  296 ++
 src/cmd/gc/reflect.c                               | 1577 ++++++
 src/cmd/gc/runtime.go                              |  164 +
 src/cmd/gc/select.c                                |  377 ++
 src/cmd/gc/sinit.c                                 | 1505 ++++++
 src/cmd/gc/subr.c                                  | 3849 +++++++++++++++
 src/cmd/gc/swt.c                                   |  948 ++++
 src/cmd/gc/typecheck.c                             | 3582 ++++++++++++++
 src/cmd/gc/unsafe.c                                |  148 +
 src/cmd/gc/unsafe.go                               |   18 +
 src/cmd/gc/walk.c                                  | 3937 +++++++++++++++
 src/cmd/gc/y.tab.c                                 | 5132 ++++++++++++++++++++
 src/cmd/gc/y.tab.h                                 |  167 +
 src/cmd/gc/yerr.h                                  |   79 +
 src/cmd/go/bootstrap.go                            |   10 +-
 src/cmd/go/build.go                                | 1407 ++----
 src/cmd/go/doc.go                                  | 1224 ++++-
 src/cmd/go/env.go                                  |    2 +-
 src/cmd/go/fix.go                                  |    4 +-
 src/cmd/go/fmt.go                                  |   30 +-
 src/cmd/go/generate.go                             |   85 +-
 src/cmd/go/generate_test.go                        |    1 -
 src/cmd/go/get.go                                  |  117 +-
 src/cmd/go/help.go                                 |  246 +-
 src/cmd/go/http.go                                 |   30 +-
 src/cmd/go/list.go                                 |   13 +-
 src/cmd/go/main.go                                 |  148 +-
 src/cmd/go/mkdoc.sh                                |    9 +
 src/cmd/go/pkg.go                                  |  998 +---
 src/cmd/go/run.go                                  |    5 +-
 src/cmd/go/script                                  |   23 +
 src/cmd/go/script.txt                              |  352 ++
 src/cmd/go/test.bash                               | 1123 +++++
 src/cmd/go/test.go                                 |  134 +-
 src/cmd/go/testdata/generate/test3.go              |    2 +-
 src/cmd/go/testflag.go                             |  200 +-
 src/cmd/go/tool.go                                 |   15 +-
 src/cmd/go/vcs.go                                  |  378 +-
 src/cmd/go/vcs_test.go                             |   69 +-
 src/cmd/go/vet.go                                  |   10 +-
 src/cmd/gofmt/doc.go                               |    7 -
 src/cmd/gofmt/gofmt.go                             |  156 +-
 src/cmd/gofmt/long_test.go                         |    5 +-
 src/cmd/gofmt/rewrite.go                           |    2 +-
 src/cmd/internal/goobj/read.go                     |   68 +-
 src/cmd/internal/objfile/disasm.go                 |   10 +-
 src/cmd/internal/objfile/elf.go                    |    2 +-
 src/cmd/internal/objfile/macho.go                  |   13 +-
 src/cmd/internal/rsc.io/arm/armasm/ext_test.go     |    2 +-
 src/cmd/internal/rsc.io/x86/x86asm/ext_test.go     |    2 +-
 src/cmd/ld/data.c                                  | 1397 ++++++
 src/cmd/ld/decodesym.c                             |  248 +
 src/cmd/ld/doc.go                                  |  100 +
 src/cmd/ld/dwarf.c                                 | 2466 ++++++++++
 src/cmd/ld/dwarf.h                                 |   24 +
 src/cmd/ld/dwarf_defs.h                            |  504 ++
 src/cmd/ld/elf.c                                   | 1526 ++++++
 src/cmd/ld/elf.h                                   | 1027 ++++
 src/cmd/ld/go.c                                    |  861 ++++
 src/cmd/ld/ldelf.c                                 |  905 ++++
 src/cmd/ld/ldmacho.c                               |  850 ++++
 src/cmd/ld/ldpe.c                                  |  499 ++
 src/cmd/ld/lib.c                                   | 1617 ++++++
 src/cmd/ld/lib.h                                   |  289 ++
 src/cmd/ld/macho.c                                 |  769 +++
 src/cmd/ld/macho.h                                 |   91 +
 src/cmd/ld/pcln.c                                  |  244 +
 src/cmd/ld/pe.c                                    |  712 +++
 src/cmd/ld/pe.h                                    |  179 +
 src/cmd/ld/pobj.c                                  |  207 +
 src/cmd/ld/symtab.c                                |  441 ++
 src/cmd/ld/textflag.h                              |   36 +
 src/cmd/nm/nm_test.go                              |    6 +-
 src/cmd/objdump/main.go                            |    2 +-
 src/cmd/objdump/objdump_test.go                    |   26 +-
 src/cmd/pack/pack.go                               |    4 +-
 src/cmd/pack/pack_test.go                          |   47 +-
 src/cmd/pprof/doc.go                               |    2 +-
 src/cmd/pprof/internal/commands/commands.go        |   42 +-
 src/cmd/pprof/internal/driver/driver.go            |   19 +-
 src/cmd/pprof/internal/profile/encode.go           |    2 +-
 src/cmd/pprof/internal/profile/filter.go           |    1 -
 src/cmd/pprof/internal/profile/legacy_profile.go   |    3 +-
 src/cmd/pprof/internal/profile/profile.go          |   13 +-
 src/cmd/pprof/internal/report/report.go            |    2 +-
 src/cmd/pprof/internal/report/source.go            |    6 +-
 src/cmd/pprof/internal/svg/svg.go                  |   14 +-
 src/cmd/yacc/doc.go                                |   29 +-
 src/cmd/yacc/testdata/expr/expr.y                  |   10 +-
 src/cmd/yacc/testdata/expr/main.go                 |    2 +-
 src/cmd/yacc/yacc.go                               |  343 +-
 src/compress/bzip2/bzip2.go                        |    8 +-
 src/compress/bzip2/bzip2_test.go                   |    4 +-
 src/compress/flate/deflate.go                      |    2 +-
 src/compress/flate/deflate_test.go                 |    2 +-
 src/compress/flate/flate_test.go                   |  236 +-
 src/compress/flate/gen.go                          |  125 +-
 src/compress/flate/huffman_bit_writer.go           |    6 +-
 src/compress/flate/huffman_code.go                 |    4 +-
 src/compress/flate/inflate.go                      |  164 +-
 src/compress/lzw/reader.go                         |    7 +-
 src/compress/lzw/reader_test.go                    |    9 +-
 src/compress/lzw/writer.go                         |   15 +-
 src/compress/lzw/writer_test.go                    |   10 -
 src/crypto/cipher/cipher.go                        |    3 -
 src/crypto/cipher/gcm.go                           |   70 +-
 src/crypto/cipher/gcm_test.go                      |   31 +-
 src/crypto/crypto.go                               |   72 +-
 src/crypto/ecdsa/ecdsa.go                          |   61 +-
 src/crypto/ecdsa/ecdsa_test.go                     |   72 -
 src/crypto/elliptic/elliptic.go                    |   13 +-
 src/crypto/elliptic/elliptic_test.go               |   13 -
 src/crypto/elliptic/p224.go                        |    2 +-
 src/crypto/elliptic/p256.go                        |    2 +-
 src/crypto/hmac/hmac.go                            |    2 +-
 src/crypto/md5/md5block_arm.s                      |  348 +-
 src/crypto/rand/rand.go                            |    2 -
 src/crypto/rand/rand_linux.go                      |    6 +-
 src/crypto/rand/rand_unix.go                       |   18 +-
 src/crypto/rand/util_test.go                       |    2 +-
 src/crypto/rc4/rc4_arm.s                           |   78 +-
 src/crypto/rsa/pkcs1v15.go                         |   10 -
 src/crypto/rsa/pkcs1v15_test.go                    |   43 +-
 src/crypto/rsa/pss.go                              |    2 +-
 src/crypto/rsa/pss_test.go                         |    9 -
 src/crypto/rsa/rsa.go                              |   57 +-
 src/crypto/sha1/sha1block_arm.s                    |  274 +-
 src/crypto/sha512/sha512.go                        |  162 +-
 src/crypto/sha512/sha512_test.go                   |  372 +-
 src/crypto/tls/cipher_suites.go                    |   16 +-
 src/crypto/tls/common.go                           |  175 +-
 src/crypto/tls/conn.go                             |   22 +-
 src/crypto/tls/handshake_client.go                 |   60 +-
 src/crypto/tls/handshake_client_test.go            |  130 +-
 src/crypto/tls/handshake_messages.go               |   98 +-
 src/crypto/tls/handshake_messages_test.go          |   13 +-
 src/crypto/tls/handshake_server.go                 |  181 +-
 src/crypto/tls/handshake_server_test.go            |  285 +-
 src/crypto/tls/key_agreement.go                    |  108 +-
 src/crypto/tls/prf.go                              |  178 +-
 src/crypto/tls/prf_test.go                         |   18 +-
 .../testdata/Client-TLSv10-ClientCert-ECDSA-ECDSA  |  105 +-
 .../testdata/Client-TLSv10-ClientCert-ECDSA-RSA    |   65 +-
 .../testdata/Client-TLSv10-ClientCert-RSA-ECDSA    |  103 +-
 .../tls/testdata/Client-TLSv10-ClientCert-RSA-RSA  |   63 +-
 .../tls/testdata/Client-TLSv10-ECDHE-ECDSA-AES     |   83 +-
 .../tls/testdata/Client-TLSv10-ECDHE-RSA-AES       |   83 +-
 src/crypto/tls/testdata/Client-TLSv10-RSA-RC4      |   45 +-
 .../tls/testdata/Client-TLSv11-ECDHE-ECDSA-AES     |   85 +-
 .../tls/testdata/Client-TLSv11-ECDHE-RSA-AES       |   83 +-
 src/crypto/tls/testdata/Client-TLSv11-RSA-RC4      |   45 +-
 src/crypto/tls/testdata/Client-TLSv12-ALPN         |   78 +-
 src/crypto/tls/testdata/Client-TLSv12-ALPN-NoMatch |   79 +-
 .../testdata/Client-TLSv12-ClientCert-ECDSA-ECDSA  |  108 +-
 .../testdata/Client-TLSv12-ClientCert-ECDSA-RSA    |   69 +-
 .../testdata/Client-TLSv12-ClientCert-RSA-ECDSA    |  108 +-
 .../tls/testdata/Client-TLSv12-ClientCert-RSA-RSA  |   69 +-
 .../tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES     |   85 +-
 .../tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES-GCM |   79 +-
 .../tls/testdata/Client-TLSv12-ECDHE-RSA-AES       |   83 +-
 src/crypto/tls/testdata/Client-TLSv12-RSA-RC4      |   45 +-
 src/crypto/tls/testdata/Server-SSLv3-RSA-3DES      |  145 +-
 src/crypto/tls/testdata/Server-SSLv3-RSA-AES       |  147 +-
 src/crypto/tls/testdata/Server-SSLv3-RSA-RC4       |  137 +-
 .../tls/testdata/Server-TLSv10-ECDHE-ECDSA-AES     |   79 +-
 src/crypto/tls/testdata/Server-TLSv10-RSA-3DES     |  137 +-
 src/crypto/tls/testdata/Server-TLSv10-RSA-AES      |  143 +-
 src/crypto/tls/testdata/Server-TLSv10-RSA-RC4      |  131 +-
 src/crypto/tls/testdata/Server-TLSv11-RSA-RC4      |  131 +-
 src/crypto/tls/testdata/Server-TLSv12-ALPN         |  217 +-
 src/crypto/tls/testdata/Server-TLSv12-ALPN-NoMatch |  217 +-
 .../Server-TLSv12-CipherSuiteCertPreferenceECDSA   |  173 +-
 .../Server-TLSv12-CipherSuiteCertPreferenceRSA     |  189 +-
 .../Server-TLSv12-ClientAuthRequestedAndECDSAGiven |  157 +-
 .../Server-TLSv12-ClientAuthRequestedAndGiven      |  157 +-
 .../Server-TLSv12-ClientAuthRequestedNotGiven      |  139 +-
 .../tls/testdata/Server-TLSv12-ECDHE-ECDSA-AES     |   82 +-
 src/crypto/tls/testdata/Server-TLSv12-IssueTicket  |  154 +-
 .../testdata/Server-TLSv12-IssueTicketPreDisable   |  154 +-
 src/crypto/tls/testdata/Server-TLSv12-RSA-3DES     |  142 +-
 src/crypto/tls/testdata/Server-TLSv12-RSA-AES      |  146 +-
 src/crypto/tls/testdata/Server-TLSv12-RSA-AES-GCM  |  156 +-
 src/crypto/tls/testdata/Server-TLSv12-RSA-RC4      |  136 +-
 src/crypto/tls/testdata/Server-TLSv12-Resume       |   59 +-
 .../tls/testdata/Server-TLSv12-ResumeDisabled      |  156 +-
 src/crypto/tls/testdata/Server-TLSv12-SNI          |   56 +-
 src/crypto/tls/ticket.go                           |   43 +-
 src/crypto/tls/tls.go                              |   38 +-
 src/crypto/tls/tls_test.go                         |   54 +-
 src/crypto/x509/cert_pool.go                       |    2 +-
 src/crypto/x509/pem_decrypt.go                     |    9 +-
 src/crypto/x509/pem_decrypt_test.go                |   24 -
 src/crypto/x509/pkix/pkix.go                       |   45 +-
 src/crypto/x509/root_cgo_darwin.go                 |    2 +-
 src/crypto/x509/root_darwin.go                     |    2 -
 src/crypto/x509/root_darwin_test.go                |   14 +-
 src/crypto/x509/root_unix.go                       |   12 +
 src/crypto/x509/sec1.go                            |    2 +-
 src/crypto/x509/verify.go                          |    9 +-
 src/crypto/x509/verify_test.go                     |   11 -
 src/crypto/x509/x509.go                            |  396 +-
 src/crypto/x509/x509_test.go                       |  219 +-
 src/database/sql/fakedb_test.go                    |   23 +-
 src/database/sql/sql.go                            |  241 +-
 src/database/sql/sql_test.go                       |  226 +-
 src/debug/dwarf/buf.go                             |   11 -
 src/debug/dwarf/const.go                           |   28 -
 src/debug/dwarf/entry.go                           |  270 +-
 src/debug/dwarf/type.go                            |   10 -
 src/debug/dwarf/typeunit.go                        |   27 +-
 src/debug/dwarf/unit.go                            |   43 +-
 src/debug/elf/elf.go                               |  180 +-
 src/debug/elf/file.go                              |  227 +-
 src/debug/elf/file_test.go                         |   38 +-
 src/debug/gosym/pclntab_test.go                    |   22 +-
 src/debug/gosym/symtab.go                          |    2 +-
 src/debug/macho/file.go                            |   10 +-
 src/debug/pe/file.go                               |   13 +-
 src/debug/pe/file_test.go                          |  116 +-
 src/encoding/asn1/asn1.go                          |   50 +-
 src/encoding/asn1/asn1_test.go                     |   79 +-
 src/encoding/asn1/common.go                        |    5 -
 src/encoding/asn1/marshal.go                       |   12 +-
 src/encoding/asn1/marshal_test.go                  |   11 -
 src/encoding/base64/base64.go                      |  225 +-
 src/encoding/base64/base64_test.go                 |   74 +-
 src/encoding/binary/binary.go                      |   26 +-
 src/encoding/csv/reader.go                         |    7 +-
 src/encoding/csv/reader_test.go                    |   31 -
 src/encoding/csv/writer.go                         |    4 +-
 src/encoding/gob/codec_test.go                     |   19 -
 src/encoding/gob/decode.go                         |  107 +-
 src/encoding/gob/doc.go                            |   18 +-
 src/encoding/gob/encoder.go                        |    6 -
 src/encoding/gob/encoder_test.go                   |  104 +-
 src/encoding/json/bench_test.go                    |   34 -
 src/encoding/json/decode.go                        |   51 +-
 src/encoding/json/decode_test.go                   |   86 +-
 src/encoding/json/encode.go                        |   27 +-
 src/encoding/json/example_test.go                  |   91 -
 src/encoding/json/fold.go                          |    2 +-
 src/encoding/json/scanner.go                       |    9 +-
 src/encoding/json/scanner_test.go                  |    1 -
 src/encoding/json/stream.go                        |  326 +-
 src/encoding/json/stream_test.go                   |  148 -
 src/encoding/json/tagkey_test.go                   |    4 +-
 src/encoding/pem/pem.go                            |   35 +-
 src/encoding/pem/pem_test.go                       |  112 +-
 src/encoding/xml/marshal.go                        |   59 +-
 src/encoding/xml/marshal_test.go                   |  552 +--
 src/encoding/xml/read_test.go                      |    2 +-
 src/encoding/xml/xml.go                            |   44 +-
 src/encoding/xml/xml_test.go                       |   21 +-
 src/expvar/expvar.go                               |   41 +-
 src/expvar/expvar_test.go                          |  235 +-
 src/flag/flag.go                                   |  151 +-
 src/flag/flag_test.go                              |   38 -
 src/fmt/doc.go                                     |   77 +-
 src/fmt/fmt_test.go                                |  116 +-
 src/fmt/format.go                                  |   25 +-
 src/fmt/print.go                                   |   40 +-
 src/fmt/scan.go                                    |  103 +-
 src/fmt/scan_test.go                               |  168 +-
 src/go/ast/ast.go                                  |   14 +-
 src/go/ast/filter.go                               |   21 +-
 src/go/ast/scope.go                                |    2 +-
 src/go/ast/walk.go                                 |    6 +-
 src/go/build/build.go                              |   82 +-
 src/go/build/build_test.go                         |   55 +-
 src/go/build/deps_test.go                          |  259 +-
 src/go/build/doc.go                                |    3 +-
 src/go/build/read.go                               |   20 +-
 src/go/build/read_test.go                          |    6 +-
 src/go/build/syslist.go                            |    2 +-
 src/go/doc/doc.go                                  |    3 +-
 src/go/doc/exports.go                              |   65 +-
 src/go/doc/testdata/blank.0.golden                 |   28 +-
 src/go/doc/testdata/blank.1.golden                 |   31 +-
 src/go/doc/testdata/blank.2.golden                 |   28 +-
 src/go/doc/testdata/blank.go                       |   31 +-
 src/go/format/format.go                            |  157 +-
 src/go/format/format_test.go                       |    6 +-
 src/go/parser/error_test.go                        |   27 +-
 src/go/parser/interface.go                         |   40 +-
 src/go/parser/parser.go                            |   82 +-
 src/go/parser/parser_test.go                       |  106 +-
 src/go/parser/short_test.go                        |   15 +-
 src/go/parser/testdata/issue3106.src               |    2 +-
 src/go/printer/nodes.go                            |   48 +-
 src/go/printer/printer.go                          |   32 +-
 src/go/printer/testdata/comments.golden            |   62 -
 src/go/printer/testdata/comments.input             |   62 -
 src/go/printer/testdata/declarations.golden        |    9 -
 src/go/printer/testdata/declarations.input         |    9 -
 src/go/printer/testdata/parser.go                  |    4 +-
 src/go/scanner/errors.go                           |   18 +-
 src/go/scanner/scanner.go                          |    3 +-
 src/go/scanner/scanner_test.go                     |   35 -
 src/go/token/position.go                           |   12 +-
 src/hash/crc32/crc32.go                            |   49 +-
 src/hash/crc32/crc32_generic.go                    |    2 +-
 src/hash/crc32/crc32_test.go                       |   36 +-
 src/html/escape.go                                 |   57 +-
 src/html/escape_test.go                            |   40 +-
 src/html/template/clone_test.go                    |    4 +-
 src/html/template/content_test.go                  |    2 +-
 src/html/template/css.go                           |   76 +-
 src/html/template/doc.go                           |    2 +-
 src/html/template/escape.go                        |   12 +-
 src/html/template/escape_test.go                   |   59 -
 src/html/template/html.go                          |   13 +-
 src/html/template/html_test.go                     |    9 +-
 src/html/template/js.go                            |    8 +-
 src/html/template/template.go                      |   26 -
 src/html/template/transition.go                    |   42 +-
 src/image/color/color.go                           |   58 +-
 src/image/color/ycbcr.go                           |  140 +-
 src/image/color/ycbcr_test.go                      |  130 +-
 src/image/decode_example_test.go                   |   32 +-
 src/image/decode_test.go                           |   14 +-
 src/image/draw/bench_test.go                       |   55 +-
 src/image/draw/clip_test.go                        |   30 +-
 src/image/draw/draw.go                             |  219 +-
 src/image/draw/draw_test.go                        |   40 -
 src/image/geom.go                                  |   44 +-
 src/image/gif/reader.go                            |  159 +-
 src/image/gif/reader_test.go                       |   49 +-
 src/image/gif/writer.go                            |  127 +-
 src/image/gif/writer_test.go                       |  280 +-
 src/image/image.go                                 |   94 +-
 src/image/jpeg/huffman.go                          |    4 +-
 src/image/jpeg/reader.go                           |  451 +-
 src/image/jpeg/reader_test.go                      |   78 -
 src/image/jpeg/scan.go                             |   86 +-
 src/image/png/reader.go                            |   40 +-
 src/image/png/reader_test.go                       |   89 -
 src/image/ycbcr.go                                 |   29 +-
 src/image/ycbcr_test.go                            |   26 -
 src/internal/syscall/getrandom_linux.go            |   56 +
 src/io/io.go                                       |   27 +-
 src/io/io_test.go                                  |   50 +-
 src/io/ioutil/tempfile.go                          |    4 -
 src/io/pipe.go                                     |    5 +-
 src/lib9/Makefile                                  |    5 +
 src/lib9/_exits.c                                  |   37 +
 src/lib9/_p9dir.c                                  |  184 +
 src/lib9/atoi.c                                    |   47 +
 src/lib9/await.c                                   |  182 +
 src/lib9/cleanname.c                               |   80 +
 src/lib9/create.c                                  |   85 +
 src/lib9/ctime.c                                   |   30 +
 src/lib9/dirfstat.c                                |   56 +
 src/lib9/dirfwstat.c                               |   84 +
 src/lib9/dirstat.c                                 |   65 +
 src/lib9/dirwstat.c                                |   45 +
 src/lib9/dup.c                                     |   38 +
 src/lib9/errstr.c                                  |  107 +
 src/lib9/exec.c                                    |   35 +
 src/lib9/execl.c                                   |   55 +
 src/lib9/exitcode.c                                |   37 +
 src/lib9/exits.c                                   |   36 +
 src/lib9/flag.c                                    |  307 ++
 src/lib9/fmt/charstod.c                            |   88 +
 src/lib9/fmt/dofmt.c                               |  624 +++
 src/lib9/fmt/dorfmt.c                              |   64 +
 src/lib9/fmt/errfmt.c                              |   32 +
 src/lib9/fmt/fltfmt.c                              |  683 +++
 src/lib9/fmt/fmt.c                                 |  235 +
 src/lib9/fmt/fmtdef.h                              |  119 +
 src/lib9/fmt/fmtfd.c                               |   51 +
 src/lib9/fmt/fmtfdflush.c                          |   37 +
 src/lib9/fmt/fmtlocale.c                           |   69 +
 src/lib9/fmt/fmtlock.c                             |   31 +
 src/lib9/fmt/fmtnull.c                             |   48 +
 src/lib9/fmt/fmtprint.c                            |   39 +
 src/lib9/fmt/fmtquote.c                            |  274 ++
 src/lib9/fmt/fmtrune.c                             |   43 +
 src/lib9/fmt/fmtstr.c                              |   31 +
 src/lib9/fmt/fmtvprint.c                           |   52 +
 src/lib9/fmt/fprint.c                              |   33 +
 src/lib9/fmt/nan64.c                               |   93 +
 src/lib9/fmt/pow10.c                               |   60 +
 src/lib9/fmt/print.c                               |   33 +
 src/lib9/fmt/seprint.c                             |   33 +
 src/lib9/fmt/smprint.c                             |   33 +
 src/lib9/fmt/snprint.c                             |   34 +
 src/lib9/fmt/sprint.c                              |   45 +
 src/lib9/fmt/strtod.c                              |  533 ++
 src/lib9/fmt/test.c                                |   67 +
 src/lib9/fmt/vfprint.c                             |   37 +
 src/lib9/fmt/vseprint.c                            |   44 +
 src/lib9/fmt/vsmprint.c                            |   87 +
 src/lib9/fmt/vsnprint.c                            |   43 +
 src/lib9/fmtlock2.c                                |   40 +
 src/lib9/getenv.c                                  |   52 +
 src/lib9/getfields.c                               |   63 +
 src/lib9/getwd.c                                   |   56 +
 src/lib9/goos.c                                    |   59 +
 src/lib9/jmp.c                                     |   45 +
 src/lib9/main.c                                    |   60 +
 src/lib9/nan.c                                     |   54 +
 src/lib9/notify.c                                  |  300 ++
 src/lib9/nulldir.c                                 |   37 +
 src/lib9/open.c                                    |   70 +
 src/lib9/readn.c                                   |   50 +
 src/lib9/rfork.c                                   |  156 +
 src/lib9/run_plan9.c                               |   40 +
 src/lib9/run_unix.c                                |   43 +
 src/lib9/run_windows.c                             |   83 +
 src/lib9/seek.c                                    |   35 +
 src/lib9/strecpy.c                                 |   45 +
 src/lib9/sysfatal.c                                |   49 +
 src/lib9/tempdir_plan9.c                           |   56 +
 src/lib9/tempdir_unix.c                            |   52 +
 src/lib9/tempdir_windows.c                         |  113 +
 src/lib9/time.c                                    |   68 +
 src/lib9/tokenize.c                                |  135 +
 src/lib9/utf/Makefile                              |   30 +
 src/lib9/utf/mkrunetype.c                          |  734 +++
 src/lib9/utf/rune.c                                |  358 ++
 src/lib9/utf/runetype.c                            |   38 +
 src/lib9/utf/runetypebody-6.3.0.h                  | 1638 +++++++
 src/lib9/utf/utf.h                                 |  240 +
 src/lib9/utf/utfdef.h                              |   27 +
 src/lib9/utf/utfecpy.c                             |   36 +
 src/lib9/utf/utflen.c                              |   35 +
 src/lib9/utf/utfnlen.c                             |   39 +
 src/lib9/utf/utfrrune.c                            |   46 +
 src/lib9/utf/utfrune.c                             |   45 +
 src/lib9/utf/utfutf.c                              |   43 +
 src/lib9/win.h                                     |    8 +
 src/lib9/windows.c                                 |   31 +
 src/libbio/Makefile                                |    5 +
 src/libbio/bbuffered.c                             |   46 +
 src/libbio/bfildes.c                               |   35 +
 src/libbio/bflush.c                                |   59 +
 src/libbio/bgetc.c                                 |   99 +
 src/libbio/bgetd.c                                 |   62 +
 src/libbio/bgetrune.c                              |   72 +
 src/libbio/binit.c                                 |  179 +
 src/libbio/boffset.c                               |   51 +
 src/libbio/bprint.c                                |   82 +
 src/libbio/bputc.c                                 |   60 +
 src/libbio/bputrune.c                              |   49 +
 src/libbio/brdline.c                               |  120 +
 src/libbio/brdstr.c                                |   60 +
 src/libbio/bread.c                                 |   71 +
 src/libbio/bseek.c                                 |   93 +
 src/libbio/bwrite.c                                |   64 +
 src/liblink/Makefile                               |    5 +
 src/liblink/asm5.c                                 | 2696 ++++++++++
 src/liblink/asm6.c                                 | 3611 ++++++++++++++
 src/liblink/asm8.c                                 | 2785 +++++++++++
 src/liblink/data.c                                 |  372 ++
 src/liblink/go.c                                   |   74 +
 src/liblink/ld.c                                   |  276 ++
 src/liblink/list5.c                                |  373 ++
 src/liblink/list6.c                                |  406 ++
 src/liblink/list8.c                                |  354 ++
 src/liblink/obj.c                                  |  296 ++
 src/liblink/obj5.c                                 | 1094 +++++
 src/liblink/obj6.c                                 | 1094 +++++
 src/liblink/obj8.c                                 |  882 ++++
 src/liblink/objfile.c                              |  790 +++
 src/liblink/pass.c                                 |  115 +
 src/liblink/pcln.c                                 |  365 ++
 src/liblink/sym.c                                  |  268 +
 src/log/log.go                                     |   60 +-
 src/log/log_test.go                                |   67 +-
 src/log/syslog/syslog.go                           |    7 +
 src/log/syslog/syslog_plan9.go                     |    8 +
 src/log/syslog/syslog_test.go                      |   25 +-
 src/log/syslog/syslog_windows.go                   |    8 +
 src/make.bash                                      |   43 +-
 src/make.bat                                       |   51 +-
 src/make.rc                                        |   41 +-
 src/math/all_test.go                               |   90 +-
 src/math/big/arith.go                              |   89 +-
 src/math/big/arith_386.s                           |   22 +-
 src/math/big/arith_amd64.s                         |   87 +-
 src/math/big/arith_amd64p32.s                      |    2 -
 src/math/big/arith_arm.s                           |    2 -
 src/math/big/arith_decl.go                         |    2 -
 src/math/big/arith_test.go                         |    3 +-
 src/math/big/example_test.go                       |   77 -
 src/math/big/int.go                                |  331 +-
 src/math/big/int_test.go                           |  574 ++-
 src/math/big/nat.go                                |  590 ++-
 src/math/big/nat_test.go                           |  608 ++-
 src/math/big/rat.go                                |  164 +-
 src/math/big/rat_test.go                           |  424 ++
 src/math/cbrt.go                                   |   91 +-
 src/math/const.go                                  |   19 +-
 src/math/dim_amd64.s                               |   32 +-
 src/math/expm1.go                                  |    8 +-
 src/math/log10.go                                  |    5 -
 src/math/nextafter.go                              |   16 +-
 src/math/rand/example_test.go                      |    4 +-
 src/math/rand/rand.go                              |    3 -
 src/math/rand/rand_test.go                         |   13 +-
 src/math/rand/zipf.go                              |    6 +-
 src/math/sqrt.go                                   |    5 -
 src/mime/grammar.go                                |    6 +-
 src/mime/multipart/multipart.go                    |   38 +-
 src/mime/multipart/multipart_test.go               |   54 +-
 src/mime/multipart/quotedprintable.go              |  118 +
 src/mime/multipart/quotedprintable_test.go         |  204 +
 src/mime/multipart/writer.go                       |    3 +-
 src/mime/type.go                                   |  104 +-
 src/mime/type_plan9.go                             |   34 +-
 src/mime/type_test.go                              |  110 +-
 src/mime/type_unix.go                              |    6 +-
 src/mime/type_windows.go                           |   54 +-
 src/nacltest.bash                                  |   14 +-
 src/net/cgo_android.go                             |    4 +-
 src/net/cgo_bsd.go                                 |    8 +-
 src/net/cgo_linux.go                               |   16 +-
 src/net/cgo_netbsd.go                              |    4 +-
 src/net/cgo_openbsd.go                             |    4 +-
 src/net/cgo_stub.go                                |   16 +-
 src/net/cgo_unix.go                                |  180 +-
 src/net/cgo_unix_test.go                           |    6 +-
 src/net/conn_test.go                               |  107 +-
 src/net/dial.go                                    |  279 +-
 src/net/dial_gen.go                                |   20 +-
 src/net/dial_gen_test.go                           |   11 +
 src/net/dial_test.go                               |  867 ++--
 src/net/dialgoogle_test.go                         |  209 +
 src/net/dnsclient.go                               |   67 +-
 src/net/dnsclient_test.go                          |    2 +-
 src/net/dnsclient_unix.go                          |  403 +-
 src/net/dnsclient_unix_test.go                     |  375 +-
 src/net/dnsconfig_unix.go                          |   54 +-
 src/net/dnsconfig_unix_test.go                     |   63 +-
 src/net/dnsmsg.go                                  |   18 +-
 src/net/dnsmsg_test.go                             |  175 +-
 src/net/dnsname_test.go                            |   31 +-
 src/net/fd_plan9.go                                |   18 +-
 src/net/fd_poll_nacl.go                            |    9 +-
 src/net/fd_poll_runtime.go                         |   15 +-
 src/net/fd_unix.go                                 |  126 +-
 src/net/fd_unix_test.go                            |   58 +
 src/net/fd_windows.go                              |  114 +-
 src/net/file_plan9.go                              |   26 +-
 src/net/file_stub.go                               |   28 +-
 src/net/file_test.go                               |  130 +-
 src/net/file_unix.go                               |   88 +-
 src/net/file_windows.go                            |   24 +-
 src/net/hosts.go                                   |   35 +-
 src/net/hosts_test.go                              |  151 +-
 src/net/http/cgi/child.go                          |    6 +-
 src/net/http/cgi/child_test.go                     |   21 +-
 src/net/http/cgi/host.go                           |   10 +-
 src/net/http/cgi/host_test.go                      |   43 +-
 src/net/http/cgi/matryoshka_test.go                |   15 +-
 src/net/http/cgi/testdata/test.cgi                 |    2 +-
 src/net/http/client.go                             |   82 +-
 src/net/http/client_test.go                        |  126 +-
 src/net/http/cookie.go                             |   36 +-
 src/net/http/cookie_test.go                        |   18 +-
 src/net/http/example_test.go                       |   23 -
 src/net/http/export_test.go                        |   24 -
 src/net/http/fcgi/child.go                         |   25 +-
 src/net/http/fcgi/fcgi_test.go                     |  106 -
 src/net/http/fs.go                                 |   53 +-
 src/net/http/fs_test.go                            |   51 +-
 src/net/http/header.go                             |    2 -
 src/net/http/httptest/server.go                    |   42 +-
 src/net/http/httputil/dump.go                      |   17 +-
 src/net/http/httputil/dump_test.go                 |    8 +-
 src/net/http/httputil/reverseproxy.go              |   67 +-
 src/net/http/httputil/reverseproxy_test.go         |   70 -
 src/net/http/internal/chunked.go                   |   17 +-
 src/net/http/lex.go                                |   73 -
 src/net/http/lex_test.go                           |   70 -
 src/net/http/main_test.go                          |   26 +-
 src/net/http/npn_test.go                           |   22 +-
 src/net/http/pprof/pprof.go                        |   38 +-
 src/net/http/proxy_test.go                         |    2 +-
 src/net/http/readrequest_test.go                   |   88 -
 src/net/http/request.go                            |  139 +-
 src/net/http/request_test.go                       |  109 +-
 src/net/http/requestwrite_test.go                  |   69 +-
 src/net/http/response.go                           |   15 +-
 src/net/http/response_test.go                      |   51 -
 src/net/http/responsewrite_test.go                 |   15 -
 src/net/http/serve_test.go                         |  653 +--
 src/net/http/server.go                             |  279 +-
 src/net/http/sniff.go                              |   10 +-
 src/net/http/transfer.go                           |  144 +-
 src/net/http/transport.go                          |  360 +-
 src/net/http/transport_test.go                     |  528 +-
 src/net/interface.go                               |   44 +-
 src/net/interface_bsd.go                           |   93 +-
 src/net/interface_bsd_test.go                      |    4 +-
 src/net/interface_darwin.go                        |   43 +-
 src/net/interface_freebsd.go                       |   43 +-
 src/net/interface_linux.go                         |   34 +-
 src/net/interface_linux_test.go                    |   34 +-
 src/net/interface_test.go                          |  200 +-
 src/net/interface_unix_test.go                     |   74 +-
 src/net/interface_windows.go                       |  250 +-
 src/net/ip.go                                      |   77 +-
 src/net/ip_test.go                                 |   91 +-
 src/net/ipraw_test.go                              |  244 +-
 src/net/iprawsock.go                               |   18 +-
 src/net/iprawsock_plan9.go                         |   16 +-
 src/net/iprawsock_posix.go                         |   82 +-
 src/net/ipsock.go                                  |  201 +-
 src/net/ipsock_plan9.go                            |   67 +-
 src/net/ipsock_posix.go                            |   43 +-
 src/net/ipsock_test.go                             |  235 +-
 src/net/lookup.go                                  |   59 +-
 src/net/lookup_plan9.go                            |   21 +-
 src/net/lookup_stub.go                             |    2 +-
 src/net/lookup_test.go                             |  444 +-
 src/net/lookup_unix.go                             |  151 +-
 src/net/lookup_windows.go                          |  122 +-
 src/net/lookup_windows_test.go                     |   14 +-
 src/net/mac.go                                     |    6 +-
 src/net/mac_test.go                                |   19 +-
 src/net/mail/message.go                            |  260 +-
 src/net/mail/message_test.go                       |  274 --
 src/net/mockicmp_test.go                           |  116 +
 src/net/mockserver_test.go                         |  464 +-
 src/net/multicast_test.go                          |  188 +
 src/net/net.go                                     |  241 +-
 src/net/net_test.go                                |  403 +-
 src/net/net_windows_test.go                        |   49 +-
 src/net/netgo_unix_test.go                         |    4 +-
 src/net/packetconn_test.go                         |  119 +-
 src/net/parse.go                                   |  207 +-
 src/net/parse_test.go                              |   36 +-
 src/net/pipe.go                                    |    6 +-
 src/net/pipe_test.go                               |   25 +-
 src/net/port.go                                    |    2 +-
 src/net/port_test.go                               |   24 +-
 src/net/port_unix.go                               |    2 +-
 src/net/protoconn_test.go                          |  178 +-
 src/net/rpc/client_test.go                         |    2 +-
 src/net/rpc/server.go                              |    3 +-
 src/net/sendfile_dragonfly.go                      |    7 +-
 src/net/sendfile_freebsd.go                        |    7 +-
 src/net/sendfile_linux.go                          |    7 +-
 src/net/sendfile_stub.go                           |    2 +-
 src/net/sendfile_windows.go                        |    2 +-
 src/net/server_test.go                             |  661 +--
 src/net/singleflight.go                            |  109 +
 src/net/smtp/example_test.go                       |   24 +-
 src/net/smtp/smtp.go                               |   35 +-
 src/net/smtp/smtp_test.go                          |   44 -
 src/net/sock_cloexec.go                            |   39 +-
 src/net/sock_posix.go                              |   10 +-
 src/net/sock_windows.go                            |   14 +-
 src/net/sockopt_bsd.go                             |    2 +-
 src/net/sys_cloexec.go                             |   21 +-
 src/net/tcp_test.go                                |  187 +-
 src/net/tcpsock.go                                 |   13 +-
 src/net/tcpsock_plan9.go                           |   61 +-
 src/net/tcpsock_posix.go                           |   99 +-
 src/net/tcpsockopt_plan9.go                        |    3 +-
 src/net/tcpsockopt_unix.go                         |    2 +-
 src/net/tcpsockopt_windows.go                      |    2 +-
 src/net/testdata/hosts_singleline                  |    1 +
 src/net/textproto/reader.go                        |   51 +-
 src/net/textproto/reader_test.go                   |   20 +-
 src/net/timeout_test.go                            | 1237 ++---
 src/net/udp_test.go                                |  330 +-
 src/net/udpsock.go                                 |   13 +-
 src/net/udpsock_plan9.go                           |   52 +-
 src/net/udpsock_posix.go                           |  103 +-
 src/net/unicast_posix_test.go                      |  469 ++
 src/net/unix_test.go                               |  264 +-
 src/net/unixsock.go                                |    6 +-
 src/net/unixsock_plan9.go                          |   38 +-
 src/net/unixsock_posix.go                          |  108 +-
 src/net/url/example_test.go                        |   31 +-
 src/net/url/url.go                                 |  200 +-
 src/net/url/url_test.go                            |  286 +-
 src/net/z_last_test.go                             |   99 +
 src/os/env.go                                      |   13 +-
 src/os/env_test.go                                 |   17 -
 src/os/error_windows_test.go                       |   47 +
 src/os/exec.go                                     |    4 +-
 src/os/exec/exec.go                                |   20 +-
 src/os/exec/exec_test.go                           |  123 +-
 src/os/exec/lp_windows_test.go                     |    2 +-
 src/os/exec_posix.go                               |   31 +-
 src/os/exec_windows.go                             |   18 +-
 src/os/file.go                                     |   18 +-
 src/os/file_plan9.go                               |    8 +-
 src/os/file_posix.go                               |   10 +-
 src/os/file_unix.go                                |   34 +-
 src/os/file_windows.go                             |   38 +-
 src/os/os_test.go                                  |  399 +-
 src/os/os_unix_test.go                             |  114 +-
 src/os/os_windows_test.go                          |   59 +-
 src/os/path_plan9.go                               |    2 +-
 src/os/path_test.go                                |   16 +-
 src/os/path_unix.go                                |    2 +-
 src/os/path_windows.go                             |    2 +-
 src/os/proc.go                                     |   14 +-
 src/os/signal/sig.s                                |   11 +-
 src/os/signal/signal.go                            |   59 +-
 src/os/signal/signal_stub.go                       |   17 +
 src/os/signal/signal_test.go                       |   66 -
 src/os/signal/signal_unix.go                       |    5 -
 src/os/stat_plan9.go                               |   40 +-
 src/os/stat_windows.go                             |   15 +-
 src/os/str.go                                      |   25 +-
 src/os/sys_windows.go                              |   28 +-
 src/os/types.go                                    |    2 +-
 src/os/user/lookup_unix.go                         |   14 +-
 src/path/filepath/example_unix_test.go             |   28 -
 src/path/filepath/match.go                         |    4 +-
 src/path/filepath/path.go                          |   28 +-
 src/path/filepath/path_plan9.go                    |   12 +-
 src/path/filepath/path_test.go                     |   92 +-
 src/path/filepath/path_unix.go                     |   12 +-
 src/path/filepath/path_windows.go                  |   39 +-
 src/path/filepath/symlink_windows.go               |   27 +-
 src/path/match.go                                  |    2 +-
 src/path/path.go                                   |    4 +-
 src/race.bash                                      |   13 +-
 src/race.bat                                       |   17 +-
 src/reflect/all_test.go                            |  669 +--
 src/reflect/example_test.go                        |   15 -
 src/reflect/export_test.go                         |   50 +-
 src/reflect/makefunc.go                            |    8 +-
 src/reflect/type.go                                |  762 +--
 src/reflect/value.go                               |  200 +-
 src/regexp/all_test.go                             |   11 -
 src/regexp/exec.go                                 |   30 +-
 src/regexp/exec_test.go                            |   24 +-
 src/regexp/regexp.go                               |    6 +-
 src/regexp/syntax/prog.go                          |    4 +-
 src/regexp/testdata/README                         |    3 +-
 src/run.bash                                       |  233 +-
 src/run.bat                                        |  105 +-
 src/run.rc                                         |   50 +-
 src/runtime/alg.go                                 |  213 +-
 src/runtime/arch_386.h                             |   17 +
 src/runtime/arch_amd64.h                           |   25 +
 src/runtime/arch_amd64p32.h                        |   17 +
 src/runtime/arch_arm.h                             |   17 +
 src/runtime/asm.s                                  |    5 -
 src/runtime/asm_386.s                              | 1458 ++++--
 src/runtime/asm_amd64.s                            | 1631 ++++---
 src/runtime/asm_amd64p32.s                         |  314 +-
 src/runtime/asm_arm.s                              |  850 ++--
 src/runtime/atomic.go                              |   51 +
 src/runtime/atomic_386.c                           |   46 +
 src/runtime/atomic_amd64x.c                        |   29 +
 src/runtime/atomic_arm.go                          |   40 +-
 src/runtime/cgo/asm_arm.s                          |    8 +-
 src/runtime/cgo/callbacks.c                        |   83 +
 src/runtime/cgo/cgo.go                             |    6 +-
 src/runtime/cgo/dragonfly.c                        |   19 +
 src/runtime/cgo/freebsd.c                          |   19 +
 src/runtime/cgo/gcc_android_arm.c                  |    4 +-
 src/runtime/cgo/gcc_arm.S                          |    4 -
 src/runtime/cgo/gcc_dragonfly_386.c                |   70 +
 src/runtime/cgo/gcc_setenv.c                       |    2 +-
 src/runtime/cgo/iscgo.c                            |   15 +
 src/runtime/cgo/libcgo.h                           |   21 -
 src/runtime/cgo/netbsd.c                           |   19 +
 src/runtime/cgo/openbsd.c                          |   27 +
 src/runtime/cgo/setenv.c                           |   13 +
 src/runtime/cgocall.go                             |   91 +-
 src/runtime/cgocall.h                              |   13 +
 src/runtime/cgocallback.go                         |   29 +-
 src/runtime/chan.go                                |  130 +-
 src/runtime/chan.h                                 |   68 +
 src/runtime/chan_test.go                           |  104 +-
 src/runtime/compiler.go                            |    2 +-
 src/runtime/complex.go                             |   39 +-
 src/runtime/cpuprof.go                             |   53 +-
 src/runtime/crash_cgo_test.go                      |  237 +-
 src/runtime/crash_test.go                          |  104 +-
 src/runtime/debug.go                               |   27 +-
 src/runtime/debug/garbage.go                       |    2 +-
 src/runtime/debug/garbage_test.go                  |    4 -
 src/runtime/debug/heapdump_test.go                 |   36 -
 src/runtime/debug/stack.go                         |    2 +-
 src/runtime/debug/stubs.go                         |    1 +
 src/runtime/debug/stubs.s                          |    9 -
 src/runtime/defs.c                                 |   15 +
 src/runtime/defs1_linux.go                         |    6 +-
 src/runtime/defs_android_arm.h                     |    3 +
 src/runtime/defs_darwin_386.h                      |  392 ++
 src/runtime/defs_darwin_amd64.h                    |  395 ++
 src/runtime/defs_dragonfly.go                      |    1 +
 src/runtime/defs_dragonfly_386.h                   |  198 +
 src/runtime/defs_dragonfly_amd64.h                 |  208 +
 src/runtime/defs_freebsd_386.h                     |  213 +
 src/runtime/defs_freebsd_amd64.h                   |  224 +
 src/runtime/defs_freebsd_arm.h                     |  186 +
 src/runtime/defs_linux.go                          |   11 +-
 src/runtime/defs_linux_386.h                       |  211 +
 src/runtime/defs_linux_amd64.h                     |  254 +
 src/runtime/defs_linux_arm.h                       |  168 +
 src/runtime/defs_nacl_386.h                        |   63 +
 src/runtime/defs_nacl_amd64p32.h                   |   90 +
 src/runtime/defs_nacl_arm.h                        |   70 +
 src/runtime/defs_netbsd_386.h                      |  182 +
 src/runtime/defs_netbsd_amd64.h                    |  194 +
 src/runtime/defs_netbsd_arm.h                      |  184 +
 src/runtime/defs_openbsd_386.h                     |  168 +
 src/runtime/defs_openbsd_amd64.h                   |  179 +
 src/runtime/defs_plan9_386.h                       |   26 +
 src/runtime/defs_plan9_amd64.h                     |   34 +
 src/runtime/defs_solaris_amd64.h                   |  254 +
 src/runtime/defs_windows.go                        |    1 +
 src/runtime/defs_windows_386.h                     |  116 +
 src/runtime/defs_windows_amd64.h                   |  131 +
 src/runtime/env_plan9.go                           |   16 +-
 src/runtime/env_posix.go                           |   23 +-
 src/runtime/error.go                               |   23 +-
 src/runtime/export_test.go                         |  165 +-
 src/runtime/extern.go                              |   68 +-
 src/runtime/float.c                                |   10 +
 src/runtime/funcdata.h                             |   10 +-
 src/runtime/futex_test.go                          |    4 +-
 src/runtime/gc_test.go                             |  251 +-
 src/runtime/gcinfo_test.go                         |  153 +-
 src/runtime/hash_test.go                           |    9 +
 src/runtime/hashmap.go                             |  292 +-
 src/runtime/hashmap_fast.go                        |   12 +-
 src/runtime/heapdump.c                             |  864 ++++
 src/runtime/iface.go                               |  244 +-
 src/runtime/iface_test.go                          |  125 -
 src/runtime/lfstack.c                              |   87 +
 src/runtime/lfstack_test.go                        |    8 +-
 src/runtime/lock_futex.go                          |   27 +-
 src/runtime/lock_sema.go                           |   36 +-
 src/runtime/malloc.c                               |  396 ++
 src/runtime/malloc.go                              | 1273 +++--
 src/runtime/malloc.h                               |  621 +++
 src/runtime/malloc_test.go                         |   38 +-
 src/runtime/map_test.go                            |   65 -
 src/runtime/mapspeed_test.go                       |   28 -
 src/runtime/mcache.c                               |  115 +
 src/runtime/mcentral.c                             |  214 +
 src/runtime/mem.go                                 |  108 +
 src/runtime/mem_darwin.c                           |   82 +
 src/runtime/mem_dragonfly.c                        |  105 +
 src/runtime/mem_freebsd.c                          |  100 +
 src/runtime/mem_linux.c                            |  162 +
 src/runtime/mem_nacl.c                             |  120 +
 src/runtime/mem_netbsd.c                           |  100 +
 src/runtime/mem_openbsd.c                          |  100 +
 src/runtime/mem_plan9.c                            |  121 +
 src/runtime/mem_solaris.c                          |  101 +
 src/runtime/mem_windows.c                          |  132 +
 src/runtime/memclr_386.s                           |   46 +-
 src/runtime/memclr_amd64.s                         |   44 +-
 src/runtime/memclr_arm.s                           |   40 +-
 src/runtime/memclr_plan9_386.s                     |   24 +-
 src/runtime/memmove_arm.s                          |  252 +-
 src/runtime/memmove_test.go                        |   32 -
 src/runtime/mfinal_test.go                         |    3 +
 src/runtime/mfixalloc.c                            |   64 +
 src/runtime/mgc0.c                                 | 2013 ++++++++
 src/runtime/mgc0.go                                |  152 +
 src/runtime/mgc0.h                                 |   78 +
 src/runtime/mheap.c                                |  889 ++++
 src/runtime/mprof.go                               |   57 +-
 src/runtime/msize.c                                |  184 +
 src/runtime/netpoll.go                             |  139 +-
 src/runtime/netpoll_epoll.go                       |   16 +-
 src/runtime/netpoll_kqueue.go                      |   15 +-
 src/runtime/netpoll_solaris.c                      |  264 +
 src/runtime/netpoll_stub.c                         |   18 +
 src/runtime/netpoll_windows.c                      |  163 +
 src/runtime/noasm_arm.go                           |   54 +
 src/runtime/norace_test.go                         |    4 +-
 src/runtime/os_android.c                           |   16 +
 src/runtime/os_android.h                           |    1 +
 src/runtime/os_darwin.c                            |  567 +++
 src/runtime/os_darwin.go                           |   31 +-
 src/runtime/os_darwin.h                            |   43 +
 src/runtime/os_dragonfly.c                         |  312 ++
 src/runtime/os_dragonfly.go                        |   38 +-
 src/runtime/os_dragonfly.h                         |   30 +
 src/runtime/os_freebsd.c                           |  320 ++
 src/runtime/os_freebsd.go                          |   33 +-
 src/runtime/os_freebsd.h                           |   29 +
 src/runtime/os_freebsd_arm.c                       |   24 +
 src/runtime/os_linux.c                             |  342 ++
 src/runtime/os_linux.go                            |   28 +-
 src/runtime/os_linux.h                             |   41 +
 src/runtime/os_linux_386.c                         |   38 +
 src/runtime/os_linux_arm.c                         |   80 +
 src/runtime/os_nacl.c                              |  312 ++
 src/runtime/os_nacl.go                             |   38 +-
 src/runtime/os_nacl.h                              |  162 +
 src/runtime/os_nacl_arm.c                          |   24 +
 src/runtime/os_netbsd.c                            |  368 ++
 src/runtime/os_netbsd.go                           |   37 +-
 src/runtime/os_netbsd.h                            |   31 +
 src/runtime/os_netbsd_386.c                        |   17 +
 src/runtime/os_netbsd_amd64.c                      |   18 +
 src/runtime/os_netbsd_arm.c                        |   34 +
 src/runtime/os_openbsd.c                           |  309 ++
 src/runtime/os_openbsd.go                          |   34 +-
 src/runtime/os_openbsd.h                           |   26 +
 src/runtime/os_plan9.c                             |  362 ++
 src/runtime/os_plan9.go                            |   43 +-
 src/runtime/os_plan9.h                             |   93 +
 src/runtime/os_plan9_386.c                         |  150 +
 src/runtime/os_plan9_amd64.c                       |  158 +
 src/runtime/os_solaris.c                           |  557 +++
 src/runtime/os_solaris.go                          |   27 +-
 src/runtime/os_solaris.h                           |   55 +
 src/runtime/os_windows.c                           |  636 +++
 src/runtime/os_windows.go                          |   58 +-
 src/runtime/os_windows.h                           |   42 +
 src/runtime/os_windows_386.c                       |  128 +
 src/runtime/os_windows_386.go                      |   11 +
 src/runtime/os_windows_amd64.c                     |  150 +
 src/runtime/os_windows_amd64.go                    |   11 +
 src/runtime/panic.c                                |  200 +
 src/runtime/panic.go                               |  184 +-
 src/runtime/parfor.c                               |  226 +
 src/runtime/parfor_test.go                         |   21 +-
 src/runtime/pprof/pprof.go                         |   65 +-
 src/runtime/pprof/pprof_test.go                    |   54 +-
 src/runtime/print1.go                              |  146 +-
 src/runtime/proc.c                                 | 3521 ++++++++++++++
 src/runtime/proc.go                                |  195 +-
 src/runtime/proc_test.go                           |  133 +-
 src/runtime/race.c                                 |  347 ++
 src/runtime/race.go                                |   47 +-
 src/runtime/race.h                                 |   34 +
 src/runtime/race/README                            |    2 +-
 src/runtime/race/doc.go                            |    2 +-
 src/runtime/race/output_test.go                    |   36 +-
 src/runtime/race/race_darwin_amd64.syso            |  Bin 314000 -> 278328 bytes
 src/runtime/race/race_freebsd_amd64.syso           |  Bin 316816 -> 294224 bytes
 src/runtime/race/race_linux_amd64.syso             |  Bin 330232 -> 298064 bytes
 src/runtime/race/race_test.go                      |   16 +-
 src/runtime/race/race_windows_amd64.syso           |  Bin 331489 -> 292311 bytes
 src/runtime/race/testdata/io_test.go               |    2 +-
 src/runtime/race/testdata/mop_test.go              |  110 -
 src/runtime/race/testdata/rwmutex_test.go          |   22 +-
 src/runtime/race/testdata/select_test.go           |    2 +-
 src/runtime/race/testdata/slice_test.go            |  107 -
 src/runtime/race/testdata/sync_test.go             |   74 +-
 src/runtime/race0.go                               |   38 +-
 src/runtime/race_amd64.s                           |   40 +-
 src/runtime/rdebug.go                              |   18 +
 src/runtime/rt0_android_arm.s                      |   24 -
 src/runtime/rt0_darwin_amd64.s                     |   34 -
 src/runtime/rt0_dragonfly_386.s                    |   16 +
 src/runtime/rt0_freebsd_arm.s                      |    6 +-
 src/runtime/rt0_linux_386.s                        |   56 +-
 src/runtime/rt0_linux_amd64.s                      |   49 -
 src/runtime/rt0_linux_arm.s                        |   57 +-
 src/runtime/rt0_netbsd_arm.s                       |    4 +-
 src/runtime/rt0_windows_386.s                      |    4 +-
 src/runtime/rt0_windows_amd64.s                    |    3 +-
 src/runtime/rune.go                                |    2 +-
 src/runtime/runtime-gdb.py                         |   58 +-
 src/runtime/runtime.c                              |  399 ++
 src/runtime/runtime.go                             |   26 +-
 src/runtime/runtime.h                              | 1132 +++++
 src/runtime/runtime_test.go                        |  160 +-
 src/runtime/runtime_unix_test.go                   |    2 +-
 src/runtime/select.go                              |  221 +-
 src/runtime/sema.go                                |   40 +-
 src/runtime/signal.c                               |   25 +
 src/runtime/signal_386.c                           |  122 +
 src/runtime/signal_amd64x.c                        |  156 +
 src/runtime/signal_android_386.h                   |    1 +
 src/runtime/signal_android_arm.h                   |    1 +
 src/runtime/signal_arm.c                           |  121 +
 src/runtime/signal_darwin_386.h                    |   23 +
 src/runtime/signal_darwin_amd64.h                  |   31 +
 src/runtime/signal_dragonfly_386.h                 |   23 +
 src/runtime/signal_dragonfly_amd64.h               |   31 +
 src/runtime/signal_freebsd_386.h                   |   23 +
 src/runtime/signal_freebsd_amd64.h                 |   31 +
 src/runtime/signal_freebsd_arm.h                   |   28 +
 src/runtime/signal_linux_386.h                     |   24 +
 src/runtime/signal_linux_amd64.h                   |   32 +
 src/runtime/signal_linux_arm.h                     |   28 +
 src/runtime/signal_nacl_386.h                      |   23 +
 src/runtime/signal_nacl_amd64p32.h                 |   31 +
 src/runtime/signal_nacl_arm.h                      |   28 +
 src/runtime/signal_netbsd_386.h                    |   23 +
 src/runtime/signal_netbsd_amd64.h                  |   31 +
 src/runtime/signal_netbsd_arm.h                    |   30 +
 src/runtime/signal_openbsd_386.h                   |   23 +
 src/runtime/signal_openbsd_amd64.h                 |   31 +
 src/runtime/signal_solaris_amd64.h                 |   31 +
 src/runtime/signal_unix.c                          |  119 +
 src/runtime/signal_unix.go                         |   39 +-
 src/runtime/signal_unix.h                          |   14 +
 src/runtime/signals_android.h                      |    1 +
 src/runtime/signals_darwin.h                       |   53 +
 src/runtime/signals_dragonfly.h                    |   54 +
 src/runtime/signals_freebsd.h                      |   54 +
 src/runtime/signals_linux.h                        |   86 +
 src/runtime/signals_nacl.h                         |   53 +
 src/runtime/signals_netbsd.h                       |   54 +
 src/runtime/signals_openbsd.h                      |   54 +
 src/runtime/signals_plan9.h                        |   63 +
 src/runtime/signals_solaris.h                      |   97 +
 src/runtime/signals_windows.h                      |    3 +
 src/runtime/sigpanic_unix.go                       |   25 +-
 src/runtime/sigqueue.go                            |   50 +-
 src/runtime/slice.go                               |   58 +-
 src/runtime/softfloat64.go                         |   15 +-
 src/runtime/softfloat64_test.go                    |    2 +-
 src/runtime/softfloat_arm.c                        |  687 +++
 src/runtime/sqrt.go                                |   63 +-
 src/runtime/stack.c                                |  892 ++++
 src/runtime/stack.go                               |   13 +
 src/runtime/stack.h                                |  118 +
 src/runtime/stack_test.go                          |   54 +-
 src/runtime/string.c                               |  226 +
 src/runtime/string.go                              |  164 +-
 src/runtime/string_test.go                         |   77 -
 src/runtime/stubs.go                               |  276 +-
 src/runtime/symtab.go                              |  273 +-
 src/runtime/symtab_test.go                         |  105 -
 src/runtime/sys_arm.c                              |   35 +
 src/runtime/sys_darwin_386.s                       |   61 +-
 src/runtime/sys_darwin_amd64.s                     |  133 +-
 src/runtime/sys_dragonfly_386.s                    |  381 ++
 src/runtime/sys_dragonfly_amd64.s                  |   40 +-
 src/runtime/sys_freebsd_386.s                      |   38 +-
 src/runtime/sys_freebsd_amd64.s                    |   63 +-
 src/runtime/sys_freebsd_arm.s                      |  139 +-
 src/runtime/sys_linux_386.s                        |  105 +-
 src/runtime/sys_linux_amd64.s                      |  102 +-
 src/runtime/sys_linux_arm.s                        |  275 +-
 src/runtime/sys_nacl_386.s                         |   20 +-
 src/runtime/sys_nacl_amd64p32.s                    |   17 +-
 src/runtime/sys_nacl_arm.s                         |   19 +-
 src/runtime/sys_netbsd_386.s                       |   28 +-
 src/runtime/sys_netbsd_amd64.s                     |   32 +-
 src/runtime/sys_netbsd_arm.s                       |  140 +-
 src/runtime/sys_openbsd_386.s                      |   32 +-
 src/runtime/sys_openbsd_amd64.s                    |   30 +-
 src/runtime/sys_plan9_386.s                        |    5 +-
 src/runtime/sys_plan9_amd64.s                      |    5 +-
 src/runtime/sys_solaris_amd64.s                    |   27 +-
 src/runtime/sys_windows_386.s                      |   45 +-
 src/runtime/sys_windows_amd64.s                    |   43 +-
 src/runtime/sys_x86.c                              |   57 +
 src/runtime/syscall_nacl.h                         |   15 +-
 src/runtime/syscall_solaris.c                      |   23 +
 src/runtime/syscall_solaris.go                     |   80 +-
 src/runtime/syscall_windows.go                     |   78 +-
 src/runtime/syscall_windows_test.go                |  125 +-
 src/runtime/thunk.s                                |  183 +
 src/runtime/thunk_solaris_amd64.s                  |   88 +
 src/runtime/thunk_windows.s                        |   30 +
 src/runtime/time.go                                |   26 +-
 src/runtime/tls_arm.s                              |   52 +-
 src/runtime/traceback.go                           |  210 +-
 src/runtime/type.h                                 |  113 +
 src/runtime/typekind.h                             |   38 +
 src/runtime/vdso_linux_amd64.c                     |  371 ++
 src/runtime/vlop_arm.s                             |  254 +-
 src/runtime/vlop_arm_test.go                       |   16 +-
 src/runtime/vlrt.c                                 |  914 ++++
 src/sort/sort.go                                   |  140 +-
 src/strconv/atof.go                                |    2 +
 src/strconv/atoi.go                                |   40 +-
 src/strconv/atoi_test.go                           |   83 +-
 src/strconv/decimal.go                             |  117 +-
 src/strconv/extfloat.go                            |    2 +-
 src/strconv/ftoa.go                                |  108 +-
 src/strconv/ftoa_test.go                           |    1 -
 src/strconv/isprint.go                             |   89 +-
 src/strconv/itoa.go                                |   58 +-
 src/strconv/itoa_test.go                           |    1 -
 src/strconv/quote_example_test.go                  |   35 +
 src/strings/reader.go                              |    6 -
 src/strings/reader_test.go                         |   13 -
 src/strings/strings.go                             |   32 +-
 src/strings/strings_test.go                        |   46 -
 src/sudo.bash                                      |   41 +
 src/sync/atomic/asm_386.s                          |    9 +
 src/sync/atomic/asm_amd64.s                        |   14 +-
 src/sync/atomic/asm_amd64p32.s                     |   14 +-
 src/sync/atomic/asm_arm.s                          |   28 -
 src/sync/atomic/asm_freebsd_arm.s                  |    9 +
 src/sync/atomic/asm_linux_arm.s                    |   27 +-
 src/sync/atomic/asm_nacl_arm.s                     |    9 +
 src/sync/atomic/asm_netbsd_arm.s                   |    9 +
 src/sync/atomic/atomic_test.go                     |   71 +-
 src/sync/export_test.go                            |    2 -
 src/sync/mutex.go                                  |   17 -
 src/sync/mutex_test.go                             |   55 -
 src/sync/runtime.go                                |    7 -
 src/sync/waitgroup.go                              |  134 +-
 src/sync/waitgroup_test.go                         |  123 -
 src/syscall/asm_darwin_386.s                       |   93 +-
 src/syscall/asm_darwin_amd64.s                     |  135 +-
 src/syscall/asm_dragonfly_386.s                    |  140 +
 src/syscall/asm_freebsd_amd64.s                    |    5 +
 src/syscall/asm_freebsd_arm.s                      |  112 +-
 src/syscall/asm_linux_386.s                        |  143 +-
 src/syscall/asm_linux_amd64.s                      |  105 +-
 src/syscall/asm_linux_arm.s                        |  112 +-
 src/syscall/asm_nacl_386.s                         |    3 +-
 src/syscall/asm_nacl_amd64p32.s                    |    2 +-
 src/syscall/asm_nacl_arm.s                         |    2 +-
 src/syscall/asm_netbsd_arm.s                       |  106 +-
 src/syscall/asm_solaris_amd64.s                    |    3 -
 src/syscall/creds_test.go                          |    8 +-
 src/syscall/dll_windows.go                         |    2 +-
 src/syscall/env_plan9.go                           |    6 +-
 src/syscall/env_windows.go                         |   20 +-
 src/syscall/exec_bsd.go                            |   34 +-
 src/syscall/exec_linux.go                          |  115 +-
 src/syscall/exec_plan9.go                          |   20 +-
 src/syscall/exec_solaris.go                        |   37 +-
 src/syscall/exec_unix.go                           |   10 +-
 src/syscall/exec_windows.go                        |   19 +-
 src/syscall/fs_nacl.go                             |   25 +-
 src/syscall/mkall.sh                               |   73 +-
 src/syscall/mkall_windows.bat                      |   15 +
 src/syscall/mkerrors.sh                            |   11 -
 src/syscall/mksyscall.pl                           |    2 +-
 src/syscall/mksyscall_solaris.pl                   |   30 +-
 src/syscall/mksyscall_windows.go                   |   43 +-
 src/syscall/mksysnum_linux.pl                      |   17 +-
 src/syscall/route_bsd.go                           |  313 +-
 src/syscall/route_darwin.go                        |   46 +-
 src/syscall/route_dragonfly.go                     |   50 +-
 src/syscall/route_freebsd.go                       |   70 +-
 src/syscall/route_freebsd_32bit.go                 |   13 +-
 src/syscall/route_freebsd_64bit.go                 |    7 +-
 src/syscall/route_netbsd.go                        |    6 +-
 src/syscall/route_openbsd.go                       |    6 +-
 src/syscall/security_windows.go                    |   98 +-
 src/syscall/so_solaris.go                          |  262 +
 src/syscall/syscall.go                             |   14 +-
 src/syscall/syscall_bsd.go                         |   35 +-
 src/syscall/syscall_darwin.go                      |    4 +-
 src/syscall/syscall_darwin_amd64.go                |    2 +-
 src/syscall/syscall_dragonfly.go                   |    6 +-
 src/syscall/syscall_dragonfly_386.go               |   58 +
 src/syscall/syscall_freebsd.go                     |    4 +-
 src/syscall/syscall_linux.go                       |  101 +-
 src/syscall/syscall_linux_386.go                   |   31 +-
 src/syscall/syscall_linux_amd64.go                 |   35 +-
 src/syscall/syscall_linux_arm.go                   |   29 +-
 src/syscall/syscall_nacl.go                        |    1 -
 src/syscall/syscall_netbsd.go                      |    4 +-
 src/syscall/syscall_openbsd.go                     |    4 +-
 src/syscall/syscall_plan9.go                       |   67 +-
 src/syscall/syscall_solaris.go                     |   11 +-
 src/syscall/syscall_solaris_amd64.go               |    5 +
 src/syscall/syscall_unix.go                        |   24 -
 src/syscall/syscall_unix_test.go                   |   66 +-
 src/syscall/syscall_windows.go                     |   50 +-
 src/syscall/tables_nacl.go                         |   39 +-
 src/syscall/types_linux.go                         |  116 +-
 src/syscall/types_plan9.c                          |  115 +
 src/syscall/zerrors_darwin_386.go                  |    2 -
 src/syscall/zerrors_darwin_amd64.go                |    2 -
 src/syscall/zerrors_dragonfly_386.go               | 1526 ++++++
 src/syscall/zerrors_dragonfly_amd64.go             |    2 -
 src/syscall/zerrors_freebsd_386.go                 |    2 -
 src/syscall/zerrors_freebsd_amd64.go               |    2 -
 src/syscall/zerrors_freebsd_arm.go                 |    2 -
 src/syscall/zerrors_linux_386.go                   |    2 -
 src/syscall/zerrors_linux_amd64.go                 |    2 -
 src/syscall/zerrors_linux_arm.go                   |    2 -
 src/syscall/zerrors_netbsd_386.go                  |    2 -
 src/syscall/zerrors_netbsd_amd64.go                |    2 -
 src/syscall/zerrors_netbsd_arm.go                  |    2 -
 src/syscall/zerrors_openbsd_386.go                 |    2 -
 src/syscall/zerrors_openbsd_amd64.go               |    2 -
 src/syscall/zerrors_plan9_386.go                   |   48 +
 src/syscall/zerrors_plan9_amd64.go                 |   48 +
 src/syscall/zerrors_solaris_amd64.go               |    2 -
 src/syscall/zsyscall_darwin_386.go                 |  212 +-
 src/syscall/zsyscall_darwin_amd64.go               |  212 +-
 src/syscall/zsyscall_dragonfly_386.go              | 1317 +++++
 src/syscall/zsyscall_dragonfly_amd64.go            |  198 +-
 src/syscall/zsyscall_freebsd_386.go                |  200 +-
 src/syscall/zsyscall_freebsd_amd64.go              |  200 +-
 src/syscall/zsyscall_freebsd_arm.go                |  200 +-
 src/syscall/zsyscall_linux_386.go                  |  572 ++-
 src/syscall/zsyscall_linux_amd64.go                |  608 ++-
 src/syscall/zsyscall_linux_arm.go                  |  590 ++-
 src/syscall/zsyscall_nacl_386.go                   |   28 +-
 src/syscall/zsyscall_nacl_amd64p32.go              |   28 +-
 src/syscall/zsyscall_nacl_arm.go                   |   28 +-
 src/syscall/zsyscall_netbsd_386.go                 |  190 +-
 src/syscall/zsyscall_netbsd_amd64.go               |  190 +-
 src/syscall/zsyscall_netbsd_arm.go                 |  190 +-
 src/syscall/zsyscall_openbsd_386.go                |  196 +-
 src/syscall/zsyscall_openbsd_amd64.go              |  196 +-
 src/syscall/zsyscall_plan9_386.go                  |  160 +-
 src/syscall/zsyscall_plan9_amd64.go                |  160 +-
 src/syscall/zsyscall_solaris_amd64.go              |  645 +--
 src/syscall/zsyscall_windows.go                    |    7 +-
 src/syscall/zsysnum_darwin_386.go                  |    2 -
 src/syscall/zsysnum_darwin_amd64.go                |    2 -
 src/syscall/zsysnum_dragonfly_386.go               |  302 ++
 src/syscall/zsysnum_dragonfly_amd64.go             |    2 -
 src/syscall/zsysnum_freebsd_386.go                 |    2 -
 src/syscall/zsysnum_freebsd_amd64.go               |    2 -
 src/syscall/zsysnum_freebsd_arm.go                 |    2 -
 src/syscall/zsysnum_linux_386.go                   |    2 -
 src/syscall/zsysnum_linux_amd64.go                 |    2 -
 src/syscall/zsysnum_linux_arm.go                   |    2 -
 src/syscall/zsysnum_netbsd_386.go                  |    2 -
 src/syscall/zsysnum_netbsd_amd64.go                |    2 -
 src/syscall/zsysnum_netbsd_arm.go                  |    2 -
 src/syscall/zsysnum_openbsd_386.go                 |    2 -
 src/syscall/zsysnum_openbsd_amd64.go               |    2 -
 src/syscall/zsysnum_plan9_386.go                   |   49 +
 src/syscall/zsysnum_plan9_amd64.go                 |   49 +
 src/syscall/zsysnum_solaris_amd64.go               |    2 -
 src/syscall/ztypes_darwin_386.go                   |    2 -
 src/syscall/ztypes_darwin_amd64.go                 |    2 -
 src/syscall/ztypes_dragonfly_386.go                |  435 ++
 src/syscall/ztypes_dragonfly_amd64.go              |    2 -
 src/syscall/ztypes_freebsd_386.go                  |    2 -
 src/syscall/ztypes_freebsd_amd64.go                |    2 -
 src/syscall/ztypes_freebsd_arm.go                  |    2 -
 src/syscall/ztypes_linux_386.go                    |    6 +-
 src/syscall/ztypes_linux_amd64.go                  |    6 +-
 src/syscall/ztypes_linux_arm.go                    |    6 +-
 src/syscall/ztypes_netbsd_386.go                   |    2 -
 src/syscall/ztypes_netbsd_amd64.go                 |    2 -
 src/syscall/ztypes_netbsd_arm.go                   |    2 -
 src/syscall/ztypes_openbsd_386.go                  |    2 -
 src/syscall/ztypes_openbsd_amd64.go                |    2 -
 src/syscall/ztypes_plan9_386.go                    |   75 +
 src/syscall/ztypes_plan9_amd64.go                  |   75 +
 src/syscall/ztypes_solaris_amd64.go                |    2 -
 src/syscall/ztypes_windows.go                      |   25 +-
 src/testing/benchmark.go                           |   34 +-
 src/testing/example.go                             |    6 +-
 src/testing/iotest/logger.go                       |    2 +-
 src/testing/quick/quick.go                         |   26 +-
 src/testing/quick/quick_test.go                    |   47 +-
 src/testing/testing.go                             |   58 +-
 src/text/scanner/scanner.go                        |   23 +-
 src/text/scanner/scanner_test.go                   |   49 -
 src/text/template/doc.go                           |    4 +-
 src/text/template/exec.go                          |   77 +-
 src/text/template/exec_test.go                     |  101 +-
 src/text/template/funcs.go                         |    4 +-
 src/text/template/helper.go                        |   11 +-
 src/text/template/multi_test.go                    |   73 -
 src/text/template/parse/lex.go                     |   13 +-
 src/text/template/parse/lex_test.go                |   57 +-
 src/text/template/parse/node.go                    |   15 +-
 src/text/template/parse/parse.go                   |   35 +-
 src/text/template/parse/parse_test.go              |   31 +-
 src/text/template/template.go                      |   84 +-
 src/time/example_test.go                           |  124 +-
 src/time/export_windows_test.go                    |    4 -
 src/time/format.go                                 |  225 +-
 src/time/sleep_test.go                             |   41 +-
 src/time/sys_unix.go                               |    2 -
 src/time/tick.go                                   |    4 +-
 src/time/time.go                                   |    2 -
 src/time/time_test.go                              |   25 +-
 src/time/zoneinfo_plan9.go                         |   10 +-
 src/time/zoneinfo_unix.go                          |    8 +-
 src/time/zoneinfo_windows.go                       |   63 +-
 src/time/zoneinfo_windows_test.go                  |   25 -
 src/unicode/graphic.go                             |    2 +-
 src/unicode/letter_test.go                         |   14 -
 src/unicode/maketables.go                          |    7 +-
 src/unicode/script_test.go                         |   10 +-
 src/unicode/tables.go                              |  524 +-
 src/unicode/utf16/utf16.go                         |    2 +-
 src/unsafe/unsafe.go                               |   22 +-
 test/bench/shootout/fasta-1000.out                 |  171 +
 test/bench/shootout/timing.sh                      |   68 +-
 test/bugs/bug395.go                                |    7 +-
 test/chan/select5.go                               |    2 +-
 test/cmp.go                                        |    2 +-
 test/cmplxdivide.c                                 |   13 +-
 test/cmplxdivide.go                                |    1 -
 test/complit1.go                                   |   14 -
 test/const4.go                                     |    2 +-
 test/const5.go                                     |    2 +-
 test/convlit.go                                    |    7 -
 test/errchk                                        |    2 +-
 test/escape2.go                                    | 1048 ++--
 test/escape2n.go                                   | 1048 ++--
 test/escape4.go                                    |    8 +-
 test/escape5.go                                    |   10 +-
 test/fixedbugs/bug121.go                           |    1 +
 test/fixedbugs/bug214.go                           |    2 +-
 test/fixedbugs/bug215.go                           |    2 +-
 test/fixedbugs/bug216.go                           |    2 +-
 test/fixedbugs/bug217.go                           |    2 +-
 test/fixedbugs/bug218.go                           |    2 +-
 test/fixedbugs/bug221.go                           |    2 +-
 test/fixedbugs/bug248.go                           |   58 +-
 test/fixedbugs/bug264.go                           |    2 +-
 test/fixedbugs/bug265.go                           |    2 +-
 test/fixedbugs/bug269.go                           |    2 +-
 test/fixedbugs/bug271.go                           |    2 +-
 test/fixedbugs/bug272.go                           |    2 +-
 test/fixedbugs/bug273.go                           |    2 +-
 test/fixedbugs/bug274.go                           |    2 +-
 test/fixedbugs/bug279.go                           |    2 +-
 test/fixedbugs/bug280.go                           |    2 +-
 test/fixedbugs/bug281.go                           |    2 +-
 test/fixedbugs/bug283.go                           |    2 +-
 test/fixedbugs/bug285.go                           |    2 +-
 test/fixedbugs/bug290.go                           |    2 +-
 test/fixedbugs/bug291.go                           |    2 +-
 test/fixedbugs/bug292.go                           |    2 +-
 test/fixedbugs/bug293.go                           |    2 +-
 test/fixedbugs/bug294.go                           |    2 +-
 test/fixedbugs/bug301.go                           |    2 +-
 test/fixedbugs/bug302.dir/main.go                  |    4 +-
 test/fixedbugs/bug302.go                           |   32 +-
 test/fixedbugs/bug345.go                           |   45 +-
 test/fixedbugs/bug346.go                           |   27 +-
 test/fixedbugs/bug369.go                           |   70 +-
 test/fixedbugs/bug425.go                           |    2 +-
 test/fixedbugs/bug427.go                           |    2 +-
 test/fixedbugs/bug429.go                           |    6 +-
 test/fixedbugs/bug435.go                           |    2 +-
 test/fixedbugs/issue3924.go                        |   13 +
 test/fixedbugs/issue6889.go                        |   10 +-
 test/fixedbugs/issue6964.go                        |    2 +-
 test/fixedbugs/issue9110.go                        |    1 -
 test/fixedbugs/issue9321.go                        |    6 +-
 test/func6.go                                      |    2 +-
 test/func7.go                                      |    2 +-
 test/gc2.go                                        |    3 +-
 test/golden.out                                    |   24 +
 test/index.go                                      |    2 +-
 test/init1.go                                      |   26 +-
 test/interface/embed2.go                           |   23 +-
 test/linkx.go                                      |    9 +-
 test/linkx_run.go                                  |   45 +-
 test/live.go                                       |  203 +-
 test/live2.go                                      |   10 +-
 test/nilcheck.go                                   |    5 -
 test/nilptr3.go                                    |    3 -
 test/nosplit.go                                    |   51 +-
 test/run                                           |  138 +
 test/run.go                                        |  185 +-
 test/sinit.go                                      |    5 -
 test/sinit_run.go                                  |   11 +-
 test/testlib                                       |  170 +
 1768 files changed, 259841 insertions(+), 51344 deletions(-)

diff --git a/.hgignore b/.hgignore
new file mode 100644
index 0000000..0071161
--- /dev/null
+++ b/.hgignore
@@ -0,0 +1,58 @@
+syntax:glob
+.DS_Store
+.git
+.gitignore
+*.[568ao]
+*.a[568o]
+*.so
+*.pyc
+._*
+.nfs.*
+[568a].out
+*~
+*.orig
+*.rej
+*.exe
+.*.swp
+core
+*.cgo*.go
+*.cgo*.c
+_cgo_*
+_obj
+_test
+_testmain.go
+build.out
+test.out
+doc/articles/wiki/*.bin
+include/plan9/libc_plan9.h
+misc/cgo/life/run.out
+misc/cgo/stdio/run.out
+misc/cgo/testso/main
+misc/dashboard/builder/builder
+src/cmd/?a/y.output
+src/liblink/anames?.c
+src/cmd/cc/y.output
+src/cmd/cgo/zdefaultcc.go
+src/cmd/dist/dist.dSYM
+src/cmd/gc/mkbuiltin1
+src/cmd/gc/opnames.h
+src/cmd/gc/y.output
+src/cmd/go/zdefaultcc.go
+src/go/doc/headscan
+src/runtime/mkversion
+src/runtime/z*
+src/unicode/maketables
+src/*.*/
+test/pass.out
+test/run.out
+test/times.out
+test/garbage/*.out
+goinstall.log
+last-change
+VERSION.cache
+
+syntax:regexp
+^bin/
+^pkg/
+^src/cmd/(.*)/6?\1$
+^.*/core.[0-9]*$
diff --git a/.hgtags b/.hgtags
new file mode 100644
index 0000000..edd2163
--- /dev/null
+++ b/.hgtags
@@ -0,0 +1,138 @@
+1f0a01c93d305f1ab636c68b67346659c5b957f7 weekly.2009-11-06
+64e703cb307da550861fe740ff70a482a2c14819 weekly.2009-11-10
+b51fd2d6c16034480f26c96ba32a11c598e4638e weekly.2009-11-10.1
+cb140bac9ab0fd9f734ee443cea9ebadc9c99737 weekly.2009-11-12
+d1b75410b793309532352a6fb6b44453f052f3f4 weekly.2009-11-17
+e205103b02e7393d4719df5faac2dac808234d3f weekly.2009-12-07
+3a47d2e3882bb12129de05382a2c131bb0c00964 weekly.2009-12-09
+a6fcf4303b0a92cce4011556b1c96044252d93af weekly.2009-12-22
+3887d4d81bca78b63d620985d93f1cc06c063871 weekly.2010-01-05
+40dd722155f6d0c83fa572c1a5abf7c6ff35049f weekly.2010-01-13
+0a2770db06efe92b08b5c6f30e14b7e8db012538 weekly.2010-01-27
+db4262ce882d8445764312d41547ee8f11a7f7a9 weekly.2010-02-04
+53fec18b83e2b93baafba4733b59bb86b8c1988e weekly.2010-02-17
+4a0661b86e50eae734dbe43ed1312c4a0304676b weekly.2010-02-23
+a215d03e7ee1013b2abe3f1e2c84457ec51c68e4 weekly.2010-03-04
+194d473264c1a015803d07bed200e0c312aca43e weekly.2010-03-15
+9482fde11a02ffd57ba0561dc8a4ac338061a3ae weekly.2010-03-22
+57380d620ee6b65eb88da1c52784b62c94d7e72e weekly.2010-03-30
+f98f784927abc56a61501eba0cf225966f2b0142 weekly.2010-04-13
+6cc6c0d85fc3234fc0a5ec0a8777aa9d59d05ae8 weekly.2010-04-27
+17ded5ad443b41ac05924864798f1bd8750da344 weekly.2010-05-04
+a85ad0a640154b5d33626ad8ea15ed17e3828178 weekly.2010-05-27
+f776656df34c009f2aad142bf7b34a778404acd1 weekly.2010-06-09
+113ec27f29f18825444f6f8a3cdc156c1df28e87 weekly.2010-06-21
+b761e0299e9bf66298778cf170b0f64216e3cf7d weekly.2010-07-01
+5992bf56aa72efcea87d8dff14985fc8fcc68575 weekly.2010-07-14
+db904d88dc0ebf6ee5b55e44088915695c1223ee weekly.2010-07-29
+8884f7b4c7750481ed246c249db47b61fe752c56 weekly.2010-08-04
+07d3a97302be88af68acff34c8a089589da21d18 weekly.2010-08-11
+18926649cda7498b8aa539b3a611abcff548f09f weekly.2010-08-25
+92fcf05736e8565a485adc52da1894270e06ed09 weekly.2010-09-06
+9329773e204fed50ec686ee78cc715b624bf1b1d weekly.2010-09-15
+1eec33c03bceef5d7607ea4636185f7bf773e0e4 weekly.2010-09-22
+c2b8c9f13fb8ad2b56920d9da2928c5314ebf725 weekly.2010-09-29
+7c2e97710bf49cdbe388260958a6674afefb6c0f weekly.2010-10-13
+ca4f9687cec0b9c4732afd57b8c2786c7fe242de weekly.2010-10-13.1
+79997f0e5823ee9d13a34ca9971a9d8811df1c4a weekly.2010-10-20
+4d5b0816392116d3a3452bb275b6dab6c6456278 weekly.2010-10-27
+c627e23260c7ddf4a1fcda6ef3197c98fa22551d weekly.2010-11-02
+a7800e20064a39585aa3ee339c2b7454ae1ce6d5 weekly.2010-11-10
+c5287468fcff0f8a7bb9ffaece2a4863e7e5d83e weekly.2010-11-23
+f7e692dc29b02fba8e5d59b967880a347b53607c weekly.2010-12-02
+56e39c466cc1c49b587eb56dc2166d61151637df weekly.2010-12-08
+26f4898dc1ca18bb77f9968aca23773637e34f0d weekly.2010-12-15
+61b2c52b0d2246430395f2869d7b34e565333cf5 weekly.2010-12-15.1
+51c777dbccb9f537ebffb99244f521c05bf65df6 weekly.2010-12-22
+8eeee945e358f19405e81792db0e16a1cad14bc0 weekly.2011-01-06
+514c7ba501a1dd74d69ea2d0a2b4116802ada2b5 weekly.2011-01-12
+72f9cb714f08b98c6a65ab2f2256fad6bb16967a weekly.2011-01-19
+d8ba80011a986470a54e5262ec125105aa4adc34 weekly.2011-01-20
+5b98b59dd37292e36afb24babb2d22758928e13d weekly.2011-02-01
+867d37fb41a4d96ab7a6202fd6ad54c345494051 weekly.2011-02-01.1
+b2be017f91348d5f8cbaf42f77a99fc905044b59 weekly.2011-02-15
+322350d6fdbf11d9c404d6fc766349d824031339 weekly.2011-02-24
+21848430d60167817ca965c813a2118068ca660f weekly.2011-03-07
+c5c62aeb6267e124cf05f9622e28dbd0dc6b971d weekly.2011-03-07.1
+c5c62aeb6267e124cf05f9622e28dbd0dc6b971d release.r56
+3b4e9c85b643a35860805718323b05186dd7f235 weekly.2011-03-15
+b84e614e25161f626a6102813c41a80a15e3a625 weekly.2011-03-28
+cd89452cfea3d125aaf75a1ec8004e2f6a868d38 weekly.2011-04-04
+d6903b7fbff40c13ee7ea3177c0ae54c7f89d2e6 weekly.2011-04-13
+2f0fa51fa2da6ab50fcebba526326153da8ed999 weekly.2011-04-27
+8493bb64e5592bd20c0e60e78e7f8052c1276fcf release.r57
+95d2ce135523c96c4cea049af94ce76dd8c7d981 release.r57.1
+c98449d685d2b6aa1df9bfd2e1cce9307efb6e00 weekly.2011-05-22
+3418f22c39eb8299053ae681199ee90f8cd29c6d weekly.2011-06-02
+c81944152e973a917797679055b8fcdc70fbc802 weekly.2011-06-09
+9d7967223815ef6415ff01aa0fe6ad38cdbc7810 release.r57.2
+dac76f0b1a18a5de5b54a1dc0b231aceaf1c8583 weekly.2011-06-16
+541c445d6c1353fbfa39df7dc4b0eb27558d1fc1 weekly.2011-06-23
+1b38d90eebcddefabb3901c5bb63c7e2b04a6ec5 release.r58
+16bfa562ba767aefd82e598da8b15ee4729e23b0 weekly.2011-07-07
+d292bc7886682d35bb391bf572be28656baee12d release.r58.1
+3c21f37b25a3f7a1726265c5339c8a7b0b329336 weekly.2011-07-19
+bb28251f6da4aca85658582c370c7df89d34efd4 weekly.2011-07-29
+d5785050f61d973fc36775f7bd2e26689529cb3e release.r59
+c17ce5ec06b4bd5cf6e7ff2ceb0a60c2e40e0b17 weekly.2011-08-10
+6eb2b9dbe489acb57a2bfc1de31ec2239ed94326 weekly.2011-08-17
+c934f6f5fe8b30b4b3210ee3f13669e6e4670c32 weekly.2011-09-01
+c77997547d546c36c7b969586a36de7ceda74e33 weekly.2011-09-07
+b0819469a6df6029a27192fe7b19a73d97404c63 release.r60
+8a09ce0cefc64deab4e6d1ed59a08a53e879bbee weekly.2011-09-16
+fd30c132d1bdeb79f8f111cb721fb1c78b767b27 release.r60.1
+d7322ae4d055a4cf3efaf842d0717a41acd85bac weekly.2011-09-21
+32a5db19629897641b2d488de4d1b998942ef80e release.r60.2
+3bdabf483805fbf0c7ef013fd09bfd6062b9d3f2 weekly.2011-10-06
+c1702f36df0397c19fc333571a771666029aa37e release.r60.3
+acaddf1cea75c059d19b20dbef35b20fb3f38954 release.r58.2
+6d7136d74b656ba6e1194853a9486375005227ef weekly.2011-10-18
+941b8015061a0f6480954821dd589c60dfe35ed1 weekly.2011-10-25
+7c1f789e6efd153951e85e3f28722fc69efc2af2 weekly.2011-10-26
+e69e528f2afc25a8334cfb9359fa4fcdf2a934b6 weekly.2011-11-01
+780c85032b174c9d4b42adf75d82bc85af7d78d1 weekly.2011-11-02
+f4397ad6e87c7ce5feac9b01686f1ebd6cbaac4e weekly.2011-11-08
+2f4482b89a6b5956828872137b6b96636cd904d3 weekly.2011-11-09
+b4a91b6933748db1a7150c06a1b55ad506e52906 weekly.2011-11-18
+80db2da6495a20ddff8305c236825811db8c8665 weekly.2011-12-01
+0beb796b4ef8747af601ed5ea6766d5b1340086b weekly.2011-12-02
+0c39eee85b0d1606b79c8ebcdeb3b67ed5849e39 weekly.2011-12-06
+82fdc445f2ff2c85043446eb84a19cc999dfcb95 weekly.2011-12-14
+4a82689277582a2a60f006e3f158985f2f8d1da3 weekly.2011-12-22
+354b17404643c0f1a710bdc48927dff02f203ae3 weekly.2012-01-15
+9f2be4fbbf690b9562c6e98b91daa0003f0913c7 weekly.2012-01-20
+1107a7d3cb075836387adfab5ce56d1b3e56637d weekly.2012-01-27
+52ba9506bd993663a0a033c2bd68699e25d061ab weekly.2012-02-07
+43cf9b39b6477d3144b0353ee91096e55db6107f weekly.2012-02-14
+96bd78e7d35e892113bdfa1bdc392d3a5f2e644b weekly.2012-02-22
+f4470a54e6dbcdd52d8d404e12e4754adcd2c948 weekly.2012-03-04
+3cdba7b0650c6c906ef3e782654f61701abd7dd2 weekly.2012-03-13
+bce220d0377405146527ab9478867cbc572a6886 weekly.2012-03-22
+dc5e410f0b4c32ab11dc992593a2bcf5f607381b weekly.2012-03-27
+dc5e410f0b4c32ab11dc992593a2bcf5f607381b weekly
+920e9d1ffd1f46665dd152aa9cf3c0f17d68dd88 go1
+2ccfd4b451d319941bfe3e08037e1462d3c15093 go1.0.1
+5e806355a9e1491aaab53d3612fed4c550b130c0 go1.0.2
+2d8bc3c94ecb3ec8f70556d5fd237788903c7281 go1.0.3
+35da6063e57f8cefc82ba1ea542c4d9393ea9dfd go1.1rc2
+5a15f0dae37931da46f0356cf4cffe775a061c12 go1.1rc3
+e570c2daeaca10663d36d6dee7f8d1d76e8f7b92 go1.1
+a7bd9a33067b3537351276e0178a045748ad046a go1.1.1
+414057ac1f1fc850957088e4c5e95cdbccd2d594 go1.1.2
+45475ec7eab1c588fc4210b34d5901b15ca1e479 go1.2rc2
+7422495a6bf9d5e84828ee466406293be84f565a go1.2rc3
+94af58f9fd71feda5c316d791ed11aaf015f9e82 go1.2rc4
+b3d5a20b070a92da2458c5788694d1359b353f4a go1.2rc5
+87dea3f5ebe7510998c84dbeeec89382b7d42f9c go1.2
+0ddbdc3c7ce27e66508fe58ab81ff29324786026 go1.2.1
+9c4fdd8369ca4483fbed1cb8e67f02643ca10f79 go1.2.2
+f8b50ad4cac4d4c4ecf48324b4f512f65e82cc1c go1.3beta1
+9e1652c32289c164126b6171f024afad5665fc9e go1.3beta2
+9d5451df4e53acc58a848005b7ec3a24c4b6050c go1.3rc1
+3f66a43d5180052e2e1e38d979d1aa5ad05b21f9 go1.3rc2
+9895f9e36435468d503eaa74ee217f28d5e28dd4 go1.3
+073fc578434bf3e1e22749b559d273c8da728ebb go1.3.1
+85518b1d6f8d6e16133b9ed2c9db6807522d37de go1.3.2
+f44017549ff9c3cc5eef74ebe7276cd0dfc066b6 go1.3.3
+f44017549ff9c3cc5eef74ebe7276cd0dfc066b6 release
+1fdfd7dfaedb1b7702141617e621ab7328a236a1 go1.4beta1
diff --git a/AUTHORS b/AUTHORS
index 6520630..46fd9fd 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -8,15 +8,12 @@
 
 # Please keep the list sorted.
 
-A Medium Corporation
-Aamir Khan <syst3m.w0rm at gmail.com>
 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>
 Ahmed Waheed Moanes <oneofone at gmail.com>
-Ainar Garipov <gugl.zadolbal at gmail.com>
 Akshat Kumar <seed at mail.nanosouffle.net>
 Alan Shreve <alan at inconshreveable.com>
 Albert Strasheim <fullung at gmail.com>
@@ -26,29 +23,21 @@ 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>
-Alex Plugaru <alex at plugaru.org> <alexandru.plugaru at gmail.com>
-Alex Schroeder <alex at gnu.org>
-Alex Sergeyev <abc at alexsergeyev.com>
 Alexander Larsson <alexander.larsson at gmail.com>
-Alexander Morozov <lk4d4math 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>
-Alexander Zolotov <goldifit at gmail.com>
-Alexandre Cesaro <alexandre.cesaro 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 Korzhevskii <a.korzhevskiy at gmail.com>
 Andrei Vieru <euvieru at gmail.com>
 Andrew Balholm <andybalholm at gmail.com>
 Andrew Bonventre <andybons at chromium.org>
 Andrew Bursavich <abursavich at gmail.com>
-Andrew Ekstedt <andrew.ekstedt at gmail.com>
 Andrew Harding <andrew at spacemonkey.com>
 Andrew Lutomirski <andy at luto.us>
 Andrew Pritchard <awpritchard at gmail.com>
@@ -56,12 +45,9 @@ 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>
-Andrew Williams <williams.andrew at gmail.com>
 Andrey Mirtchovski <mirtchovski at gmail.com>
-Andrey Petrov <andrey.petrov at shazow.net>
 Andriy Lytvynov <lytvynov.a.v at gmail.com>
 Andy Davis <andy at bigandian.com>
-Andy Maloney <asmaloney at gmail.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>
@@ -70,16 +56,12 @@ 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>
-Areski Belaid <areski at gmail.com>
 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>
 Aulus Egnatius Varialus <varialus at gmail.com>
-awaw fumin <awawfumin at gmail.com>
-Aymerick Jéhanne <aymerick at jehanne.org>
-Ben Burkert <ben at benburkert.com>
 Ben Olive <sionide21 at gmail.com>
 Benjamin Black <b at b3k.us>
 Benny Siegert <bsiegert at gmail.com>
@@ -88,22 +70,17 @@ 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 Gentry <blakesgentry at gmail.com>
 Blake Mizerany <blake.mizerany at gmail.com>
 Bobby Powers <bobbypowers at gmail.com>
 Brendan Daniel Tracey <tracey.brendan at gmail.com>
-Brett Cannon <bcannon at gmail.com>
 Brian Dellisanti <briandellisanti at gmail.com>
 Brian G. Merrell <bgmerrell at gmail.com>
-Brian Gitonga Marete <marete at toshnix.com> <bgmarete at gmail.com>
+Brian Gitonga Marete <marete at toshnix.com>
 Brian Ketelsen <bketelsen at gmail.com>
-Brian Smith <ohohvi at gmail.com>
-Bryan Ford <brynosaurus 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>
-Carlos Cirello <uldericofilho at gmail.com>
 Case Nelson <case.nelson at gmail.com>
 Casey Marshall <casey.marshall at gmail.com>
 Cezar Sá Espinola <cezarsa at gmail.com>
@@ -114,7 +91,6 @@ Chris Dollin <ehog.hedge at gmail.com>
 Chris Farmiloe <chrisfarms at gmail.com>
 Chris Howey <howeyc at gmail.com>
 Chris Jones <chris at cjones.org>
-Chris Kastorff <encryptio at gmail.com>
 Chris Lennert <calennert at gmail.com>
 Chris McGee <sirnewton_01 at yahoo.ca> <newton688 at gmail.com>
 Christian Himpel <chressie at googlemail.com>
@@ -122,13 +98,10 @@ 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 Guiney <chris at guiney.net>
 Christopher Nielsen <m4dh4tt3r at gmail.com>
 Christopher Redden <christopher.redden at gmail.com>
 Christopher Wedgwood <cw at f00f.org>
 Clement Skau <clementskau at gmail.com>
-CloudFlare Inc.
-Colin Kennedy <moshen.colin at gmail.com>
 Conrad Meyer <cemeyer at cs.washington.edu>
 Corey Thomasson <cthom.lists at gmail.com>
 Cristian Staretu <unclejacksons at gmail.com>
@@ -152,26 +125,21 @@ David Jakob Fritz <david.jakob.fritz at gmail.com>
 David Leon Gil <coruus at gmail.com>
 David Thomas <davidthomas426 at gmail.com>
 David Titarenco <david.titarenco at gmail.com>
-Davies Liu <davies.liu at gmail.com>
 Dean Prichard <dean.prichard at gmail.com>
 Denis Brandolini <denis.brandolini at gmail.com>
-Derek Buitenhuis <derek.buitenhuis at gmail.com>
 Derek Parker <parkerderek86 at gmail.com>
 Devon H. O'Dell <devon.odell at gmail.com>
 Dhiru Kholia <dhiru.kholia at gmail.com>
-Didier Spezia <didier.06 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>
-Dmitry Savintsev <dsavints at gmail.com>
 Dominik Honnef <dominik.honnef at gmail.com>
 Donovan Hide <donovanhide at gmail.com>
 Dropbox, Inc.
 Duncan Holm <mail at frou.org>
 Dustin Sallings <dsallings at gmail.com>
 Dustin Shields-Cloues <dcloues at gmail.com>
-Dvir Volk <dvir at everything.me> <dvirsky at gmail.com>
 Eden Li <eden.li at gmail.com>
 Egon Elbre <egonelbre at gmail.com>
 Ehren Kret <ehren.kret at gmail.com>
@@ -182,11 +150,9 @@ Eoghan Sherry <ejsherry at gmail.com>
 Eric Clark <zerohp at gmail.com>
 Eric Milliken <emilliken at gmail.com>
 Eric Roshan-Eisner <eric.d.eisner at gmail.com>
-Erik Aigner <aigner.erik 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 Phoenix <evan at phx.io>
 Evan Shaw <chickencha at gmail.com>
 Ewan Chou <coocood at gmail.com>
 Fabrizio Milo <mistobaan at gmail.com>
@@ -198,7 +164,6 @@ 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>
-Florin Patan <florinpatan at gmail.com>
 Francisco Souza <franciscossouza at gmail.com>
 Frederick Kelly Mayle III <frederickmayle at gmail.com>
 Fredrik Enestad <fredrik.enestad at soundtrackyourbrand.com>
@@ -206,44 +171,29 @@ Frithjof Schulze <schulze at math.uni-hannover.de> <sfrithjof at gmail.com>
 Gabriel Aszalos <gabriel.aszalos at gmail.com>
 Gary Burd <gary at beagledreams.com>
 Gautham Thambidorai <gautham.dorai at gmail.com>
-Geert-Johan Riemer <gjr19912 at gmail.com>
 Georg Reinke <guelfey at gmail.com>
-George Shammas <george at shamm.as> <georgyo at gmail.com>
 Gerasimos Dimitriadis <gedimitr at gmail.com>
 Gideon Jan-Wessel Redelinghuys <gjredelinghuys at gmail.com>
 Giles Lean <giles.lean at pobox.com>
-Giulio Iotti <dullgiulio at gmail.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>
-Guobiao Mei <meiguobiao at gmail.com>
 Gustav Paul <gustav.paul at gmail.com>
 Gustavo Niemeyer <gustavo at niemeyer.net>
 Gwenael Treguier <gwenn.kahz at gmail.com>
-Hajime Hoshi <hajimehoshi at gmail.com>
-Hari haran <hariharan.uno at gmail.com>
-Hariharan Srinath <srinathh at gmail.com>
 Harley Laue <losinggeneration at gmail.com>
-Håvard Haugen <havard.haugen at gmail.com>
 Hector Chu <hectorchu at gmail.com>
 Hector Martin Cantero <hector at marcansoft.com>
 Henning Schmiedehausen <henning at schmiedehausen.org>
 Henrik Edwards <henrik.edwards at gmail.com>
 Herbert Georg Fischer <herbert.fischer at gmail.com>
 Hong Ruiqi <hongruiqi at gmail.com>
-IBM
 Icarus Sparry <golang at icarus.freeuk.com>
-Igneous Systems, Inc.
-Igor Dolzhikov <bluesriverz at gmail.com>
-INADA Naoki <songofacandy at gmail.com>
-Ingo Krabbe <ikrabbe.ask at gmail.com>
 Ingo Oeser <nightlyone at googlemail.com>
 Isaac Wagner <ibw at isaacwagner.me>
-Ivan Ukhov <ivan.ukhov at gmail.com>
-Jae Kwon <jae at tendermint.com>
 Jakob Borg <jakob at nym.se>
 Jakub Ryszard Czarnowicz <j.czarnowicz at gmail.com>
 James David Chalfant <james.chalfant at gmail.com>
@@ -272,18 +222,14 @@ Jeremy Jackins <jeremyjackins at gmail.com>
 Jim McGrath <jimmc2 at gmail.com>
 Jimmy Zelinskie <jimmyzelinskie at gmail.com>
 Jingcheng Zhang <diogin at gmail.com>
-Jiong Du <londevil at gmail.com>
 Joakim Sernbrant <serbaut at gmail.com>
-Joe Harrison <joehazzers at gmail.com>
 Joe Poirier <jdpoirier at gmail.com>
 Joe Shaw <joe at joeshaw.org>
-Joe Tsai <joetsai at digital-static.net>
 Joel Stemmer <stemmertech 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 Potocny <johnp at vividcortex.com>
 John Shahid <jvshahid at gmail.com>
 John Tuley <john at tuley.org>
 Jonathan Gold <jgold.bg at gmail.com>
@@ -301,11 +247,8 @@ JT Olds <jtolds at xnet5.com>
 Jukka-Pekka Kekkonen <karatepekka at gmail.com>
 Julian Phillips <julian at quantumfyre.co.uk>
 Julien Schmidt <google at julienschmidt.com>
-Justin Nuß <nuss.justin at gmail.com>
 Kai Backman <kaib at golang.org>
 Kamil Kisiel <kamil at kamilkisiel.net> <kamil.kisiel at gmail.com>
-Kang Hu <hukangustc at gmail.com>
-Kato Kazuyoshi <kato.kazuyoshi at gmail.com>
 Katrina Owen <katrina.owen at gmail.com>
 Kei Son <hey.calmdown at gmail.com>
 Keith Rarick <kr at xph.us>
@@ -314,16 +257,12 @@ 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>
-Konstantin Shaposhnikov <k.shaposhnikov at gmail.com>
 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>
-Larz Conwell <larzconwell at gmail.com>
-Lee Packham <lpackham at gmail.com>
 Linaro Limited
-Lloyd Dewolf <foolswisdom at gmail.com>
 Lorenzo Stoakes <lstoakes at gmail.com>
 Luca Greco <luca.greco at alcacoop.it>
 Lucio De Re <lucio.dere at gmail.com>
@@ -333,7 +272,6 @@ Luke Curley <qpingu at gmail.com>
 Manuel Mendez <mmendez534 at gmail.com>
 Marc Weistroff <marc at weistroff.net>
 Marco Hennings <marco.hennings at freiheit.com>
-Mark Bucciarelli <mkbucc at gmail.com>
 Mark Theunissen <mark.theunissen at gmail.com>
 Marko Juhani Silokunnas <marko.silokunnas at gmail.com>
 Marko Tiikkaja <marko at joh.to>
@@ -341,41 +279,29 @@ Markover Inc. DBA Poptip
 Markus Duft <markus.duft at salomon.at>
 Markus Sonderegger <marraison at gmail.com>
 Markus Zimmermann <zimmski at gmail.com>
-Martin Möhrmann <martisch at uos.de>
 Martin Neubauer <m.ne at gmx.net>
 Martin Olsson <martin at minimum.se>
 Mateusz Czapliński <czapkofan at gmail.com>
-Mathias Beke <git at denbeke.be>
 Mathieu Lonjaret <mathieu.lonjaret at gmail.com>
 Mats Lidell <mats.lidell at cag.se>
 Matt Aimonetti <mattaimonetti at gmail.com>
-Matt Bostock <matt at mattbostock.com>
 Matt Jibson <matt.jibson at gmail.com>
 Matt Joiner <anacrolix at gmail.com>
-Matt Layher <mdlayher at gmail.com>
 Matt Reiferson <mreiferson at gmail.com>
-Matt T. Proud <matt.proud at gmail.com>
-Matt Williams <gh at mattyw.net>
-Matthew Brennan <matty.brennan at gmail.com>
 Matthew Cottingham <mattcottingham at gmail.com>
-Matthew Holt <Matthew.Holt+git at gmail.com>
 Matthew Horsnell <matthew.horsnell at gmail.com>
 Maxim Khitrov <max at mxcrypt.com>
-Meir Fischer <meirfischer at gmail.com>
 Micah Stetson <micah.stetson at gmail.com>
 Michael Chaten <mchaten at gmail.com>
 Michael Elkins <michael.elkins at gmail.com>
 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 Käufl <golang at c.michael-kaeufl.de>
 Michael Lewis <mikelikespie at gmail.com>
 Michael MacInnis <Michael.P.MacInnis at gmail.com>
 Michael Pearson <mipearson at gmail.com>
-Michael Schaller <michael at 5challer.de>
 Michael Stapelberg <michael at stapelberg.de>
 Michael Teichgräber <mteichgraeber at gmx.de>
-Michael Vetter <g.bluehut at gmail.com>
 Michał Derkacz <ziutek at lnet.pl>
 Miek Gieben <miek at miek.nl>
 Mihai Borobocea <MihaiBorobocea at gmail.com>
@@ -393,8 +319,6 @@ Môshe van der Sterre <moshevds at gmail.com>
 Nan Deng <monnand at gmail.com>
 Nathan John Youngman <nj at nathany.com>
 Nathan P Finch <nate.finch at gmail.com>
-Nathan Youngman <git at nathany.com>
-Nevins Bartolomeo <nevins.bartolomeo at gmail.com>
 ngmoco, LLC
 Nicholas Katsaros <nick at nickkatsaros.com>
 Nicholas Presta <nick at nickpresta.ca> <nick1presta at gmail.com>
@@ -403,7 +327,6 @@ 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>
-Nicolas S. Dade <nic.dade at gmail.com>
 Nigel Kerr <nigel.kerr at gmail.com>
 Noah Campbell <noahcampbell at gmail.com>
 Oling Cat <olingcat at gmail.com>
@@ -412,9 +335,7 @@ Olivier Antoine <olivier.antoine at gmail.com>
 Olivier Duperray <duperray.olivier at gmail.com>
 Olivier Saingre <osaingre at gmail.com>
 Padraig Kitterick <padraigkitterick at gmail.com>
-Palm Stone Games
 Paolo Giarrusso <p.giarrusso at gmail.com>
-Paolo Martini <mrtnpaolo at gmail.com>
 Pascal S. de Kloe <pascal at quies.net>
 Patrick Crosby <patrick at stathat.com>
 Patrick Gavlin <pgavlin at gmail.com>
@@ -426,7 +347,6 @@ 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 Smith <paulsmith at pobox.com> <paulsmith at gmail.com>
 Paul van Brouwershaven <paul at vanbrouwershaven.com>
 Pavel Zinovkin <pavel.zinovkin at gmail.com>
 Percy Wegmann <ox.to.a.cart at gmail.com>
@@ -434,11 +354,9 @@ 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 Moody <pmoody at uber.com>
 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 Waldschmidt <peter at waldschmidt.com>
 Peter Waller <peter.waller at gmail.com>
 Peter Williams <pwil3058 at gmail.com>
 Philip K. Warren <pkwarren at gmail.com>
@@ -446,12 +364,9 @@ 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>
-Quoc-Viet Nguyen <afelion at gmail.com>
 Raif S. Naffah <go at naffah-raif.name>
-Rajat Goel <rajat.goel2010 at gmail.com>
 Red Hat, Inc.
 Rémy Oudompheng <oudomphe at phare.normalesup.org>
-Richard Barnes <rlb at ipv.sx>
 Richard Crowley <r at rcrowley.org>
 Richard Eric Gavaletz <gavaletz at gmail.com>
 Richard Musiol <mail at richard-musiol.de>
@@ -472,11 +387,9 @@ 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 Seys <ryan at ryanseys.com>
 Ryan Slade <ryanslade at gmail.com>
 S.Çağlar Onur <caglar at 10ur.org>
 Sanjay Menakuru <balasanjay at gmail.com>
-Scott Barron <scott.barron at github.com>
 Scott Ferguson <scottwferg at gmail.com>
 Scott Lawrence <bytbox at gmail.com>
 Sebastien Binet	<seb.binet at gmail.com>
@@ -488,26 +401,21 @@ Shane Hansen <shanemhansen at gmail.com>
 Shawn Smith <shawn.p.smith at gmail.com>
 Shenghou Ma <minux.ma at gmail.com>
 Shivakumar GN <shivakumar.gn at gmail.com>
-Silvan Jegen <s.jegen at gmail.com>
 Simon Whitehead <chemnova at gmail.com>
 Sokolov Yura <funny.falcon at gmail.com>
 Spring Mc <heresy.mc at gmail.com>
 StalkR <stalkr at stalkr.net>
-Stan Schwertly <stan at schwertly.com>
 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>
-Steve Streeting <steve at stevestreeting.com>
 Steven Elliot Harris <seharris at gmail.com>
 Steven Hartland <steven.hartland at multiplay.co.uk>
-Stripe, Inc.
 Sven Almgren <sven at tras.se>
 Szabolcs Nagy <nsz at port70.net>
 Tad Glines <tad.glines at gmail.com>
 Taj Khattra <taj.khattra at gmail.com>
-Tamir Duberstein <tamird at gmail.com>
 Tarmigan Casebolt <tarmigan at gmail.com>
 Taru Karttunen <taruti at taruti.net>
 Tetsuo Kiso <tetsuokiso9 at gmail.com>
@@ -517,10 +425,7 @@ Thomas Kappler <tkappler at gmail.com>
 Timo Savola <timo.savola at gmail.com>
 Timo Truyts <alkaloid.btx at gmail.com>
 Tobias Columbus <tobias.columbus at gmail.com>
-Todd Neal <todd at tneal.org>
-Tom Heng <zhm20070928 at gmail.com>
 Tom Linford <tomlinford at gmail.com>
-Tommy Schaefer <tommy.schaefer at teecom.com>
 Tor Andersson <tor.andersson at gmail.com>
 Travis Cline <travis.cline at gmail.com>
 Tudor Golubenco <tudor.g at gmail.com>
@@ -531,7 +436,6 @@ Ulf Holm Nielsen <doktor at dyregod.dk>
 Uriel Mangado <uriel at berlinblue.org>
 Vadim Vygonets <unixdj at gmail.com>
 Vincent Ambo <tazjin at googlemail.com>
-Vincent Batts <vbatts at hashbangbash.com> <vbatts at gmail.com>
 Vincent Vanackere <vincent.vanackere at gmail.com>
 Vinu Rajashekhar <vinutheraj at gmail.com>
 Vladimir Nikishenko <vova616 at gmail.com>
@@ -544,7 +448,6 @@ Xia Bin <snyh at snyh.org>
 Xing Xing <mikespook at gmail.com>
 Yasuhiro Matsumoto <mattn.jp at gmail.com>
 Yissakhar Z. Beck <yissakhar.beck at gmail.com>
-Yo-An Lin <yoanlin93 at gmail.com>
 Yongjian Xu <i3dmaster at gmail.com>
 Yoshiyuki Kanno <nekotaroh at gmail.com> <yoshiyuki.kanno at stoic.co.jp>
 Yusuke Kagiwada <block.rxckin.beats at gmail.com>
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
index d974f36..b5e709e 100644
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -31,9 +31,7 @@
 
 # Please keep the list sorted.
 
-Aamir Khan <syst3m.w0rm at gmail.com>
 Aaron France <aaron.l.france at gmail.com>
-Aaron Jacobs <jacobsa at google.com>
 Aaron Kemp <kemp.aaron at gmail.com>
 Abhinav Gupta <abhinav.g90 at gmail.com>
 Adam Langley <agl at golang.org>
@@ -41,7 +39,6 @@ Adrian Nos <nos.adrian at gmail.com>
 Adrian O'Grady <elpollouk at gmail.com>
 Adrien Bustany <adrien-xx-google at bustany.org>
 Ahmed Waheed Moanes <oneofone at gmail.com>
-Ainar Garipov <gugl.zadolbal at gmail.com>
 Akshat Kumar <seed at mail.nanosouffle.net>
 Alan Donovan <adonovan at google.com>
 Alan Shreve <alan at inconshreveable.com>
@@ -53,17 +50,11 @@ 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>
-Alex Plugaru <alex at plugaru.org> <alexandru.plugaru at gmail.com>
-Alex Schroeder <alex at gnu.org>
-Alex Sergeyev <abc at alexsergeyev.com>
 Alexander Larsson <alexander.larsson at gmail.com>
-Alexander Morozov <lk4d4math 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>
-Alexander Zolotov <goldifit at gmail.com>
-Alexandre Cesaro <alexandre.cesaro at gmail.com>
 Alexandre Normand <alexandre.normand at gmail.com>
 Alexandru Moșoi <brtzsnr at gmail.com>
 Alexei Sholik <alcosholik at gmail.com>
@@ -74,28 +65,22 @@ Amir Mohammad Saied <amir at gluegadget.com>
 Amrut Joshi <amrut.joshi at gmail.com>
 Andrea Spadaccini <spadaccio at google.com>
 Andreas Jellinghaus <andreas at ionisiert.de> <anj at google.com>
-Andrei Korzhevskii <a.korzhevskiy at gmail.com>
 Andrei Vieru <euvieru at gmail.com>
 Andres Erbsen <andreser at google.com>
 Andrew Balholm <andybalholm at gmail.com>
 Andrew Bonventre <andybons at chromium.org>
 Andrew Bursavich <abursavich at gmail.com>
-Andrew Ekstedt <andrew.ekstedt at gmail.com>
 Andrew Gerrand <adg at golang.org>
 Andrew Harding <andrew at spacemonkey.com>
 Andrew Lutomirski <andy at luto.us>
-Andrew Pilloud <andrewpilloud at igneoussystems.com>
 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>
-Andrew Williams <williams.andrew at gmail.com>
 Andrey Mirtchovski <mirtchovski at gmail.com>
-Andrey Petrov <andrey.petrov at shazow.net>
 Andriy Lytvynov <lytvynov.a.v at gmail.com>
 Andy Davis <andy at bigandian.com>
-Andy Maloney <asmaloney at gmail.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>
@@ -104,7 +89,6 @@ 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>
-Areski Belaid <areski at gmail.com>
 Arnaud Ysmal <arnaud.ysmal at gmail.com>
 Arne Hormann <arnehormann at gmail.com>
 Aron Nopanen <aron.nopanen at gmail.com>
@@ -113,10 +97,7 @@ Asim Shankar <asimshankar at gmail.com>
 Ato Araki <ato.araki at gmail.com>
 Aulus Egnatius Varialus <varialus at gmail.com>
 Austin Clements <austin at google.com> <aclements at csail.mit.edu>
-awaw fumin <awawfumin at gmail.com>
-Aymerick Jéhanne <aymerick at jehanne.org>
 Balazs Lecz <leczb at google.com>
-Ben Burkert <ben at benburkert.com>
 Ben Eitzen <eitzenb at golang.org>
 Ben Fried <ben.fried at gmail.com>
 Ben Lynn <benlynn at gmail.com>
@@ -130,31 +111,24 @@ 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 Gentry <blakesgentry 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>
-Brandon Gilmore <varz at google.com>
 Brendan Daniel Tracey <tracey.brendan at gmail.com>
 Brendan O'Dea <bod at golang.org>
-Brett Cannon <bcannon at gmail.com>
 Brian Dellisanti <briandellisanti at gmail.com>
 Brian G. Merrell <bgmerrell at gmail.com>
-Brian Gitonga Marete <marete at toshnix.com> <bgmarete at gmail.com>
+Brian Gitonga Marete <marete at toshnix.com>
 Brian Ketelsen <bketelsen at gmail.com>
 Brian Slesinsky <skybrian at google.com>
-Brian Smith <ohohvi at gmail.com>
-Bryan Ford <brynosaurus at gmail.com>
-Burcu Dogan <jbd at google.com> <burcujdogan at gmail.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 Jackson <carl at stripe.com>
 Carl Mastrangelo <notcarl at google.com>
 Carl Shapiro <cshapiro at google.com> <cshapiro at golang.org>
 Carlos Castillo <cookieo9 at gmail.com>
-Carlos Cirello <uldericofilho at gmail.com>
 Cary Hull <chull at google.com>
 Case Nelson <case.nelson at gmail.com>
 Casey Marshall <casey.marshall at gmail.com>
@@ -163,13 +137,11 @@ 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>
-Chris Broadfoot <cbro at golang.org>
 Chris Dollin <ehog.hedge at gmail.com>
 Chris Farmiloe <chrisfarms at gmail.com>
 Chris Howey <howeyc at gmail.com>
 Chris Hundt <hundt at google.com>
 Chris Jones <chris at cjones.org> <chris.jones.yar at gmail.com>
-Chris Kastorff <encryptio at gmail.com>
 Chris Lennert <calennert at gmail.com>
 Chris Manghane <cmang at golang.org>
 Chris McGee <sirnewton_01 at yahoo.ca> <newton688 at gmail.com>
@@ -178,14 +150,12 @@ 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 Guiney <chris at guiney.net>
 Christopher Nielsen <m4dh4tt3r at gmail.com>
 Christopher Redden <christopher.redden at gmail.com>
 Christopher Swenson <cswenson at google.com>
 Christopher Wedgwood <cw at f00f.org>
 Clement Skau <clementskau at gmail.com>
 Colby Ranger <cranger at google.com>
-Colin Kennedy <moshen.colin at gmail.com>
 Conrad Meyer <cemeyer at cs.washington.edu>
 Corey Thomasson <cthom.lists at gmail.com>
 Cosmos Nicolaou <cnicolaou at google.com>
@@ -194,7 +164,6 @@ Damian Gryski <dgryski at gmail.com>
 Damien Neil <dneil at google.com>
 Dan Callahan <dan.callahan at gmail.com>
 Dan Peterson <dpiddy at gmail.com>
-Dan Pupius <dan at medium.com>
 Dan Sinclair <dan.sinclair at gmail.com>
 Daniel Fleischman <danielfleischman at gmail.com>
 Daniel Krech <eikeon at eikeon.com>
@@ -211,7 +180,6 @@ David Anderson <danderson at google.com>
 David Barnett <dbarnett at google.com>
 David Bürgin <676c7473 at gmail.com>
 David Calavera <david.calavera at gmail.com>
-David Chase <drchase at google.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>
@@ -224,29 +192,23 @@ 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>
-Davies Liu <davies.liu at gmail.com>
 Dean Prichard <dean.prichard at gmail.com>
 Denis Brandolini <denis.brandolini at gmail.com>
-Derek Buitenhuis <derek.buitenhuis at gmail.com>
 Derek Parker <parkerderek86 at gmail.com>
 Devon H. O'Dell <devon.odell at gmail.com>
 Dhiru Kholia <dhiru.kholia at gmail.com>
-Didier Spezia <didier.06 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>
-Dmitry Savintsev <dsavints at gmail.com>
 Dominik Honnef <dominik.honnef at gmail.com>
-Dominik Vogt <vogt at linux.vnet.ibm.com>
 Donovan Hide <donovanhide at gmail.com>
 Drew Hintz <adhintz at google.com>
 Duncan Holm <mail at frou.org>
 Dustin Long <dustmop at gmail.com>
 Dustin Sallings <dsallings at gmail.com>
 Dustin Shields-Cloues <dcloues at gmail.com>
-Dvir Volk <dvir at everything.me> <dvirsky at gmail.com>
 Eden Li <eden.li at gmail.com>
 Egon Elbre <egonelbre at gmail.com>
 Ehren Kret <ehren.kret at gmail.com>
@@ -257,13 +219,11 @@ Eoghan Sherry <ejsherry at gmail.com>
 Eric Clark <zerohp at gmail.com>
 Eric Milliken <emilliken at gmail.com>
 Eric Roshan-Eisner <eric.d.eisner at gmail.com>
-Erik Aigner <aigner.erik 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 Kroske <evankroske at google.com>
 Evan Martin <evan.martin at gmail.com>
-Evan Phoenix <evan at phx.io>
 Evan Shaw <chickencha at gmail.com>
 Ewan Chou <coocood at gmail.com>
 Fabrizio Milo <mistobaan at gmail.com>
@@ -274,7 +234,6 @@ 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>
-Florin Patan <florinpatan at gmail.com>
 Folke Behrens <folke at google.com>
 Francesc Campoy <campoy at golang.org>
 Francisco Souza <franciscossouza at gmail.com>
@@ -286,30 +245,23 @@ Gaal Yahas <gaal at google.com>
 Gabriel Aszalos <gabriel.aszalos at gmail.com>
 Gary Burd <gary at beagledreams.com> <gary.burd at gmail.com>
 Gautham Thambidorai <gautham.dorai at gmail.com>
-Geert-Johan Riemer <gjr19912 at gmail.com>
 Georg Reinke <guelfey at gmail.com>
-George Shammas <george at shamm.as> <georgyo at gmail.com>
 Gerasimos Dimitriadis <gedimitr at gmail.com>
 Gideon Jan-Wessel Redelinghuys <gjredelinghuys at gmail.com>
 Giles Lean <giles.lean at pobox.com>
-Giulio Iotti <dullgiulio at gmail.com>
 Glenn Lewis <gmlewis at google.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>
-Guobiao Mei <meiguobiao at gmail.com>
 Gustav Paul <gustav.paul at gmail.com>
 Gustavo Franco <gustavorfranco at gmail.com>
 Gustavo Niemeyer <gustavo at niemeyer.net> <n13m3y3r at gmail.com>
 Gwenael Treguier <gwenn.kahz at gmail.com>
-Hajime Hoshi <hajimehoshi at gmail.com>
+Hana Kim <hyangah at gmail.com>
 Han-Wen Nienhuys <hanwen at google.com>
-Hari haran <hariharan.uno at gmail.com>
-Hariharan Srinath <srinathh at gmail.com>
 Harley Laue <losinggeneration at gmail.com>
-Håvard Haugen <havard.haugen at gmail.com>
 Hector Chu <hectorchu at gmail.com>
 Hector Martin Cantero <hector at marcansoft.com>
 Henning Schmiedehausen <henning at schmiedehausen.org>
@@ -317,19 +269,12 @@ 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>
-Hyang-Ah Hana Kim <hakim at google.com> <hyangah at gmail.com>
 Ian Lance Taylor <iant at golang.org>
 Icarus Sparry <golang at icarus.freeuk.com>
-Igor Dolzhikov <bluesriverz at gmail.com>
-INADA Naoki <songofacandy at gmail.com>
-Ingo Krabbe <ikrabbe.ask at gmail.com>
 Ingo Oeser <nightlyone at googlemail.com> <nightlyone at gmail.com>
 Isaac Wagner <ibw at isaacwagner.me>
 Ivan Krasin <krasin at golang.org>
-Ivan Ukhov <ivan.ukhov at gmail.com>
 Jacob Baskin <jbaskin at google.com>
-Jacob H. Haven <jacob at cloudflare.com>
-Jae Kwon <jae at tendermint.com>
 Jakob Borg <jakob at nym.se>
 Jakub Ryszard Czarnowicz <j.czarnowicz at gmail.com>
 James Aguilar <jaguilar at google.com>
@@ -346,7 +291,6 @@ Jamie Gennis <jgennis at google.com> <jgennis at gmail.com>
 Jamie Turner <jamwt at dropbox.com>
 Jamie Wilkinson <jaq at spacepants.org>
 Jan H. Hosang <jan.hosang at gmail.com>
-Jan Kratochvil <jan.kratochvil at redhat.com>
 Jan Mercl <0xjnml at gmail.com>
 Jan Mercl <befelemepeseveze at gmail.com>
 Jan Newmarch <jan.newmarch at gmail.com>
@@ -369,12 +313,9 @@ Jeremy Schlatter <jeremy.schlatter at gmail.com>
 Jim McGrath <jimmc2 at gmail.com>
 Jimmy Zelinskie <jimmyzelinskie at gmail.com>
 Jingcheng Zhang <diogin at gmail.com>
-Jiong Du <londevil at gmail.com>
 Joakim Sernbrant <serbaut at gmail.com>
-Joe Harrison <joehazzers at gmail.com>
 Joe Poirier <jdpoirier at gmail.com>
 Joe Shaw <joe at joeshaw.org>
-Joe Tsai <joetsai at digital-static.net>
 Joel Sing <jsing at google.com>
 Joel Stemmer <stemmertech at gmail.com>
 Johan Euphrosine <proppy at google.com>
@@ -382,11 +323,9 @@ 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 Dethridge <jcd at golang.org>
 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 Potocny <johnp at vividcortex.com>
 John Shahid <jvshahid at gmail.com>
 John Tuley <john at tuley.org>
 Jonathan Allie <jonallie at google.com>
@@ -413,11 +352,8 @@ JT Olds <jtolds at xnet5.com>
 Jukka-Pekka Kekkonen <karatepekka at gmail.com>
 Julian Phillips <julian at quantumfyre.co.uk>
 Julien Schmidt <google at julienschmidt.com>
-Justin Nuß <nuss.justin at gmail.com>
 Kai Backman <kaib at golang.org>
 Kamil Kisiel <kamil at kamilkisiel.net> <kamil.kisiel at gmail.com>
-Kang Hu <hukangustc at gmail.com>
-Kato Kazuyoshi <kato.kazuyoshi at gmail.com>
 Katrina Owen <katrina.owen at gmail.com>
 Kay Zhu <kayzhu at google.com>
 Kei Son <hey.calmdown at gmail.com>
@@ -431,16 +367,12 @@ Ken Thompson <ken at golang.org>
 Kevin Ballard <kevin at sb.org>
 Kevin Klues <klueska at gmail.com> <klueska at google.com>
 Kirklin McDonald <kirklin.mcdonald at gmail.com>
-Konstantin Shaposhnikov <k.shaposhnikov 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>
 Larry Hosken <lahosken at golang.org>
-Larz Conwell <larzconwell at gmail.com>
-Lee Packham <lpackham at gmail.com>
-Lloyd Dewolf <foolswisdom at gmail.com>
 Lorenzo Stoakes <lstoakes at gmail.com>
 Louis Kruger <louisk at google.com>
 Luca Greco <luca.greco at alcacoop.it>
@@ -448,17 +380,13 @@ 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>
-Luna Duclos <luna.duclos at palmstonegames.com>
 Luuk van Dijk <lvd at golang.org> <lvd at google.com>
-Lynn Boger <laboger at linux.vnet.ibm.com>
 Manoj Dayaram <platform-dev at moovweb.com> <manoj.dayaram at moovweb.com>
 Manu Garg <manugarg at google.com>
 Manuel Mendez <mmendez534 at gmail.com>
 Marc Weistroff <marc at weistroff.net>
 Marcel van Lohuizen <mpvl at golang.org>
 Marco Hennings <marco.hennings at freiheit.com>
-Marius Nuennerich <mnu at google.com>
-Mark Bucciarelli <mkbucc at gmail.com>
 Mark Theunissen <mark.theunissen at gmail.com>
 Mark Zavislak <zavislak at google.com>
 Marko Juhani Silokunnas <marko.silokunnas at gmail.com>
@@ -467,32 +395,23 @@ 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 Möhrmann <martisch at uos.de>
 Martin Neubauer <m.ne at gmx.net>
 Martin Olsson <martin at minimum.se>
 Mateusz Czapliński <czapkofan at gmail.com>
-Mathias Beke <git at denbeke.be>
 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 Bostock <matt at mattbostock.com>
 Matt Brown <mdbrown at google.com>
 Matt Jibson <matt.jibson at gmail.com>
 Matt Joiner <anacrolix at gmail.com>
 Matt Jones <mrjones at google.com>
-Matt Layher <mdlayher at gmail.com>
 Matt Reiferson <mreiferson at gmail.com>
-Matt T. Proud <matt.proud at gmail.com>
-Matt Williams <gh at mattyw.net> <mattyjwilliams at gmail.com>
-Matthew Brennan <matty.brennan at gmail.com>
 Matthew Cottingham <mattcottingham at gmail.com>
 Matthew Dempsky <mdempsky at google.com>
-Matthew Holt <Matthew.Holt+git at gmail.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>
-Meir Fischer <meirfischer at gmail.com>
 Micah Stetson <micah.stetson at gmail.com>
 Michael Chaten <mchaten at gmail.com>
 Michael Elkins <michael.elkins at gmail.com>
@@ -500,23 +419,17 @@ 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 Käufl <golang at c.michael-kaeufl.de>
 Michael Kelly <mjk at google.com>
 Michael Lewis <mikelikespie at gmail.com>
 Michael MacInnis <Michael.P.MacInnis at gmail.com>
 Michael Matloob <matloob at google.com>
-Michael McGreevy <mcgreevy at golang.org>
 Michael Pearson <mipearson at gmail.com>
 Michael Piatek <piatek at google.com>
-Michael Schaller <michael at 5challer.de>
 Michael Shields <mshields at google.com>
 Michael Stapelberg <michael at stapelberg.de> <mstplbrg at googlemail.com>
 Michael T. Jones <mtj at google.com> <michael.jones at gmail.com>
 Michael Teichgräber <mteichgraeber at gmx.de> <mt4swm at googlemail.com>
-Michael Vetter <g.bluehut at gmail.com>
-Michal Cierniak <cierniak at google.com>
 Michał Derkacz <ziutek at lnet.pl>
-Michalis Kargakis <michaliskargakis at gmail.com>
 Miek Gieben <miek at miek.nl> <remigius.gieben at gmail.com>
 Mihai Borobocea <MihaiBorobocea at gmail.com>
 Mikael Tillenius <mikti42 at gmail.com>
@@ -535,8 +448,6 @@ Mrunal Patel <mrunalp at gmail.com>
 Nan Deng <monnand at gmail.com>
 Nathan John Youngman <nj at nathany.com>
 Nathan P Finch <nate.finch at gmail.com>
-Nathan Youngman <git at nathany.com>
-Nevins Bartolomeo <nevins.bartolomeo at gmail.com>
 Nicholas Katsaros <nick at nickkatsaros.com>
 Nicholas Presta <nick at nickpresta.ca> <nick1presta at gmail.com>
 Nicholas Sullivan <nicholas.sullivan at gmail.com>
@@ -545,7 +456,6 @@ Nick Cooper <nmvc at google.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>
-Nicolas S. Dade <nic.dade at gmail.com>
 Nigel Kerr <nigel.kerr at gmail.com>
 Nigel Tao <nigeltao at golang.org>
 Noah Campbell <noahcampbell at gmail.com>
@@ -556,7 +466,6 @@ Olivier Duperray <duperray.olivier at gmail.com>
 Olivier Saingre <osaingre at gmail.com>
 Padraig Kitterick <padraigkitterick at gmail.com>
 Paolo Giarrusso <p.giarrusso at gmail.com>
-Paolo Martini <mrtnpaolo at gmail.com>
 Pascal S. de Kloe <pascal at quies.net>
 Patrick Crosby <patrick at stathat.com>
 Patrick Gavlin <pgavlin at gmail.com>
@@ -570,10 +479,8 @@ 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 Marks <pmarks at google.com>
 Paul Nasrat <pnasrat at google.com>
 Paul Sbarra <Sbarra.Paul at gmail.com>
-Paul Smith <paulsmith at pobox.com> <paulsmith at gmail.com>
 Paul van Brouwershaven <paul at vanbrouwershaven.com>
 Pavel Zinovkin <pavel.zinovkin at gmail.com>
 Pawel Szczur <filemon at google.com>
@@ -584,12 +491,10 @@ 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 Moody <pmoody at uber.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 Waldschmidt <peter at waldschmidt.com>
 Peter Waller <peter.waller at gmail.com>
 Peter Weinberger <pjw at golang.org>
 Peter Williams <pwil3058 at gmail.com>
@@ -599,14 +504,10 @@ 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>
-Quoc-Viet Nguyen <afelion at gmail.com>
-Rahul Chaudhry <rahulchaudhry at chromium.org>
 Raif S. Naffah <go at naffah-raif.name>
-Rajat Goel <rajat.goel2010 at gmail.com>
 Raph Levien <raph at google.com>
 Raul Silvera <rsilvera at google.com>
 Rémy Oudompheng <oudomphe at phare.normalesup.org> <remyoudompheng at gmail.com>
-Richard Barnes <rlb at ipv.sx>
 Richard Crowley <r at rcrowley.org>
 Richard Eric Gavaletz <gavaletz at gmail.com>
 Richard Musiol <mail at richard-musiol.de> <neelance at gmail.com>
@@ -629,25 +530,22 @@ Roger Pau Monné <royger at gmail.com>
 Roger Peppe <rogpeppe at gmail.com>
 Ron Hashimoto <mail at h2so5.net>
 Ron Minnich <rminnich at gmail.com>
-Ross Light <light at google.com> <rlight2 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 Brown <ribrdb at google.com>
 Ryan Hitchman <hitchmanr at gmail.com>
-Ryan Seys <ryan at ryanseys.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 Barron <scott.barron at github.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>
+Sebastien Binet	<seb.binet at gmail.com>
 Sébastien Paolacci <sebastien.paolacci at gmail.com>
 Sergei Skorobogatov <skorobo at rambler.ru>
 Sergey 'SnakE' Gromov <snake.scaly at gmail.com>
@@ -657,20 +555,16 @@ Shawn Ledbetter <sledbetter at google.com>
 Shawn Smith <shawn.p.smith at gmail.com>
 Shenghou Ma <minux at golang.org> <minux.ma at gmail.com>
 Shivakumar GN <shivakumar.gn at gmail.com>
-Silvan Jegen <s.jegen at gmail.com>
 Simon Whitehead <chemnova at gmail.com>
 Sokolov Yura <funny.falcon at gmail.com>
 Spring Mc <heresy.mc at gmail.com>
-Srdjan Petrovic <spetrovic at google.com>
 StalkR <stalkr at stalkr.net>
-Stan Schwertly <stan at schwertly.com>
 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>
 Stephen McQuay <stephen at mcquay.me>
 Stephen Weinberg <stephen at q5comm.com>
 Steve McCoy <mccoyst at gmail.com>
-Steve Streeting <steve at stevestreeting.com>
 Steven Elliot Harris <seharris at gmail.com>
 Steven Hartland <steven.hartland at multiplay.co.uk>
 Sugu Sougoumarane <ssougou at gmail.com>
@@ -678,7 +572,6 @@ Sven Almgren <sven at tras.se>
 Szabolcs Nagy <nsz at port70.net>
 Tad Glines <tad.glines at gmail.com>
 Taj Khattra <taj.khattra at gmail.com>
-Tamir Duberstein <tamird at gmail.com>
 Tarmigan Casebolt <tarmigan at gmail.com>
 Taru Karttunen <taruti at taruti.net>
 Tetsuo Kiso <tetsuokiso9 at gmail.com>
@@ -689,12 +582,9 @@ Thomas Kappler <tkappler at gmail.com>
 Timo Savola <timo.savola at gmail.com>
 Timo Truyts <alkaloid.btx at gmail.com>
 Tobias Columbus <tobias.columbus at gmail.com> <tobias.columbus at googlemail.com>
-Todd Neal <todd at tneal.org>
 Todd Wang <toddwang at gmail.com>
-Tom Heng <zhm20070928 at gmail.com>
 Tom Linford <tomlinford at gmail.com>
 Tom Szymanski <tgs at google.com>
-Tommy Schaefer <tommy.schaefer at teecom.com>
 Tor Andersson <tor.andersson at gmail.com>
 Travis Cline <travis.cline at gmail.com>
 Trevor Strohman <trevor.strohman at gmail.com>
@@ -707,11 +597,9 @@ Uriel Mangado <uriel at berlinblue.org>
 Vadim Vygonets <unixdj at gmail.com>
 Vega Garcia Luis Alfonso <vegacom at gmail.com>
 Vincent Ambo <tazjin at googlemail.com>
-Vincent Batts <vbatts at hashbangbash.com> <vbatts at gmail.com>
 Vincent Vanackere <vincent.vanackere at gmail.com>
 Vinu Rajashekhar <vinutheraj at gmail.com>
 Vish Subramanian <vish at google.com>
-Vlad Krasnov <vlad at cloudflare.com>
 Vladimir Nikishenko <vova616 at gmail.com>
 Volker Dobler <dr.volker.dobler at gmail.com>
 Wei Guangjing <vcc.163 at gmail.com>
@@ -725,7 +613,6 @@ 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>
-Yo-An Lin <yoanlin93 at gmail.com>
 Yongjian Xu <i3dmaster at gmail.com>
 Yoshiyuki Kanno <nekotaroh at gmail.com> <yoshiyuki.kanno at stoic.co.jp>
 Yusuke Kagiwada <block.rxckin.beats at gmail.com>
diff --git a/README b/README
new file mode 100644
index 0000000..a557fe9
--- /dev/null
+++ b/README
@@ -0,0 +1,32 @@
+This is the source code repository for the Go programming language.  
+
+For documentation about how to install and use Go,
+visit http://golang.org/ or load doc/install-source.html
+in your web browser.
+
+After installing Go, you can view a nicely formatted
+doc/install-source.html by running godoc --http=:6060
+and then visiting http://localhost:6060/doc/install/source.
+
+Unless otherwise noted, the Go source files are distributed
+under the BSD-style license found in the LICENSE file.
+
+--
+
+Binary Distribution Notes
+
+If you have just untarred a binary Go distribution, you need to set
+the environment variable $GOROOT to the full path of the go
+directory (the one containing this README).  You can omit the
+variable if you unpack it into /usr/local/go, or if you rebuild
+from sources by running all.bash (see doc/install.html).
+You should also add the Go binary directory $GOROOT/bin
+to your shell's path.
+
+For example, if you extracted the tar file into $HOME/go, you might
+put the following in your .profile:
+
+    export GOROOT=$HOME/go
+    export PATH=$PATH:$GOROOT/bin
+
+See doc/install.html for more details.
diff --git a/VERSION b/VERSION
index 661b4f9..bcab27e 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-go1.5
\ No newline at end of file
+go1.4.2
\ No newline at end of file
diff --git a/api/except.txt b/api/except.txt
index 59ef942..6e40e18 100644
--- a/api/except.txt
+++ b/api/except.txt
@@ -328,4 +328,3 @@ 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
 pkg unicode, const Version = "6.3.0"
-pkg unicode, const Version = "7.0.0"
diff --git a/api/next.txt b/api/next.txt
index e69de29..e8570a6 100644
--- a/api/next.txt
+++ b/api/next.txt
@@ -0,0 +1,141 @@
+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
+pkg unicode, const Version = "7.0.0"
+pkg unicode, var Bassa_Vah *RangeTable
+pkg unicode, var Caucasian_Albanian *RangeTable
+pkg unicode, var Duployan *RangeTable
+pkg unicode, var Elbasan *RangeTable
+pkg unicode, var Grantha *RangeTable
+pkg unicode, var Khojki *RangeTable
+pkg unicode, var Khudawadi *RangeTable
+pkg unicode, var Linear_A *RangeTable
+pkg unicode, var Mahajani *RangeTable
+pkg unicode, var Manichaean *RangeTable
+pkg unicode, var Mende_Kikakui *RangeTable
+pkg unicode, var Modi *RangeTable
+pkg unicode, var Mro *RangeTable
+pkg unicode, var Nabataean *RangeTable
+pkg unicode, var Old_North_Arabian *RangeTable
+pkg unicode, var Old_Permic *RangeTable
+pkg unicode, var Pahawh_Hmong *RangeTable
+pkg unicode, var Palmyrene *RangeTable
+pkg unicode, var Pau_Cin_Hau *RangeTable
+pkg unicode, var Psalter_Pahlavi *RangeTable
+pkg unicode, var Siddham *RangeTable
+pkg unicode, var Tirhuta *RangeTable
+pkg unicode, var Warang_Citi *RangeTable
diff --git a/debian/changelog b/debian/changelog
index 587f8d2..fa10914 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,18 +1,3 @@
-golang (2:1.5-1) UNRELEASED; urgency=low
-
-  * Update to 1.5 upstream release (Closes: #796150).
-    - Compiler and runtime written entirely in Go.
-    - Concurrent garbage collector.
-    - GOMAXPROCS=runtime.NumCPU() by default.
-    - "internal" packages for all, not just core.
-    - Experimental "vendoring" support.
-    - Cross-compilation no longer requires a complete rebuild of the stdlib in
-      GOROOT, and thus the golang-go-GOHOST-GOARCH packages are removed.
-    - Fixes for CVE-2015-5739, CVE-2015-5740, CVE-2015-5741 (Closes: #795106).
-  * Sync debian/copyright with the Ubuntu delta. (thanks doko!)
-
- -- Tianon Gravi <tianon at debian.org>  Wed, 22 Jul 2015 21:55:56 -0700
-
 golang (2:1.4.2-3) unstable; urgency=medium
 
   * Add missing "prerm" for our new alternatives (thanks piuparts).
diff --git a/debian/control b/debian/control
index fa5cafc..dfde545 100644
--- a/debian/control
+++ b/debian/control
@@ -1,74 +1,71 @@
+# DO NOT EDIT THIS FILE. EDIT debian/control.* instead!
 Source: golang
 Section: devel
 Priority: optional
 Maintainer: Go Compiler Team <pkg-golang-devel at lists.alioth.debian.org>
 Uploaders: Michael Stapelberg <stapelberg at debian.org>,
            Paul Tagliamonte <paultag at debian.org>,
-           Tianon Gravi <tianon at debian.org>
-Vcs-Browser: https://anonscm.debian.org/cgit/pkg-golang/golang.git
+           Tianon Gravi <admwiggin at gmail.com>
+Vcs-Browser: http://anonscm.debian.org/gitweb/?p=pkg-golang/golang.git
 Vcs-Git: git://anonscm.debian.org/pkg-golang/golang.git
-Build-Depends: debhelper (>= 7.4.10), bison, ed, mawk | awk, perl, netbase,
-               golang-go (>= 2:1.4.2-2~) | gccgo-5
+Build-Depends: debhelper (>= 7.4.10), bison, ed, mawk | awk, perl, netbase
 Build-Depends-Indep: po-debconf
 Standards-Version: 3.9.6
-Homepage: https://golang.org
+Homepage: http://golang.org/
 
 Package: golang-go
-Architecture: amd64 arm64 armel armhf i386 ppc64 ppc64el
+Architecture: i386 amd64 armel armhf
 Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends},
-         golang-src (>= ${source:Version})
-Replaces: golang-go-darwin-386,
-          golang-go-darwin-amd64,
-          golang-go-freebsd-386,
-          golang-go-freebsd-amd64,
-          golang-go-freebsd-arm,
-          golang-go-linux-386,
-          golang-go-linux-amd64,
-          golang-go-linux-arm,
-          golang-go-netbsd-386,
-          golang-go-netbsd-amd64,
-          golang-go-windows-386,
-          golang-go-windows-amd64
+	 golang-src (>= ${source:Version}),
+	 golang-go-linux-${go:Hostarch} (= ${source:Version})
+Replaces: golang-weekly-go, golang-weekly-tools, golang-tools
+Conflicts: golang-weekly-go, golang-weekly-tools, golang-tools
+Provides: go-compiler, golang-weekly-go, golang-weekly-tools, golang-tools
 Suggests: bzr, git, golang-go.tools, mercurial, subversion
-Description: Go programming language compiler, linker, compiled stdlib
- The Go programming language is an open source project to make programmers more
- productive. Go is expressive, concise, clean, and efficient. Its concurrency
- mechanisms make it easy to write programs that get the most out of multicore
- and networked machines, while its novel type system enables flexible and
- modular program construction. Go compiles quickly to machine code yet has the
- convenience of garbage collection and the power of run-time reflection. It's a
- fast, statically typed, compiled language that feels like a dynamically typed,
- interpreted language.
- .
- This package provides an assembler, compiler, linker, and compiled libraries
- for the Go programming language.
- .
- Go supports cross-compilation, but as of Go 1.5, it is no longer necessary to
- pre-compile the standard library inside GOROOT for cross-compilation to work.
+Description: Go programming language compiler
+ The Go programming language is an open source project to make
+ programmers more productive. Go is expressive, concise, clean, and
+ efficient. Its concurrency mechanisms make it easy to write programs
+ that get the most out of multicore and networked machines, while its
+ novel type system enables flexible and modular program construction.
+ Go compiles quickly to machine code yet has the convenience of
+ garbage collection and the power of run-time reflection. It's a
+ fast, statically typed, compiled language that feels like a
+ dynamically typed, interpreted language.
+ .
+ This package provides an assembler, a compiler, and a linker for the
+ Go programming language. This is Google's implementation of the Go
+ tool chain.
 
 Package: golang-src
-Replaces: golang-go (<< 2:1-3~)
+Replaces: golang-weekly-src, golang-go (<< 2:1-3~)
+Conflicts: golang-weekly-src
+Provides: golang-weekly-src
 Breaks: golang-go (<< 2:1-3~)
-Architecture: amd64 arm64 armel armhf i386 ppc64 ppc64el
+Architecture: i386 amd64 armel armhf
 Depends: ${shlibs:Depends}, ${misc:Depends}
-Description: Go programming language - source files
- The Go programming language is an open source project to make programmers more
- productive. Go is expressive, concise, clean, and efficient. Its concurrency
- mechanisms make it easy to write programs that get the most out of multicore
- and networked machines, while its novel type system enables flexible and
- modular program construction. Go compiles quickly to machine code yet has the
- convenience of garbage collection and the power of run-time reflection. It's a
- fast, statically typed, compiled language that feels like a dynamically typed,
- interpreted language.
- .
- This package provides the Go programming language source files needed for
- cross-compilation.
+Description: Go programming language compiler - source files
+ The Go programming language is an open source project to make
+ programmers more productive. Go is expressive, concise, clean, and
+ efficient. Its concurrency mechanisms make it easy to write programs
+ that get the most out of multicore and networked machines, while its
+ novel type system enables flexible and modular program construction.
+ Go compiles quickly to machine code yet has the convenience of
+ garbage collection and the power of run-time reflection. It's a
+ fast, statically typed, compiled language that feels like a
+ dynamically typed, interpreted language.
+ .
+ This package provides the Go programming language source files needed
+ for godoc and goinstall.
 
 Package: golang-doc
+Replaces: golang-weekly-doc
+Conflicts: golang-weekly-doc
+Provides: golang-weekly-doc
 Depends: ${misc:Depends}, golang-go
 Architecture: all
 Section: doc
-Description: Go programming language - documentation
+Description: Go programming language compiler - documentation
  The Go programming language is an open source project to make
  programmers more productive. Go is expressive, concise, clean, and
  efficient. Its concurrency mechanisms make it easy to write programs
@@ -84,6 +81,9 @@ Description: Go programming language - documentation
  --http=:6060", and then visiting http://localhost:6060/doc/install.html.
 
 Package: golang
+Replaces: golang-weekly
+Conflicts: golang-weekly
+Provides: golang-weekly
 Depends: ${misc:Depends},
 	 golang-go (>= ${source:Version}),
 	 golang-src (>= ${source:Version}),
@@ -102,3 +102,219 @@ Description: Go programming language compiler - metapackage
  .
  This package is a metapackage that, when installed, guarantees
  that (most of) a full Go development environment is installed.
+
+Package: golang-go-linux-amd64
+Architecture: i386 amd64 armel armhf
+Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends}
+Breaks: golang-go (<< 2:1.1-2)
+Replaces: golang-go (<< 2:1.1-2)
+Description: Go standard library compiled for linux_amd64
+ This package contains the Go standard library,
+ compiled for linux_amd64.
+ .
+ This package is just one of a number of packages, each providing the Go
+ standard library for a specific operating system/architecture combination.
+ Go supports cross-compilation, so each of these packages is useful on any
+ architecture.
+ .
+ The files contained in this package are independent of the host architecture,
+ that is, you can use golang-go-linux-amd64 to generate a binary for
+ linux_amd64, even though you are executing the Go compiler on linux_386.
+
+Package: golang-go-linux-arm
+Architecture: i386 amd64 armel armhf
+Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends}
+Breaks: golang-go (<< 2:1.1-2)
+Replaces: golang-go (<< 2:1.1-2)
+Description: Go standard library compiled for linux_arm
+ This package contains the Go standard library,
+ compiled for linux_arm.
+ .
+ This package is just one of a number of packages, each providing the Go
+ standard library for a specific operating system/architecture combination.
+ Go supports cross-compilation, so each of these packages is useful on any
+ architecture.
+ .
+ The files contained in this package are independent of the host architecture,
+ that is, you can use golang-go-linux-amd64 to generate a binary for
+ linux_amd64, even though you are executing the Go compiler on linux_386.
+
+Package: golang-go-linux-386
+Architecture: i386 amd64 armel armhf
+Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends}
+Breaks: golang-go (<< 2:1.1-2)
+Replaces: golang-go (<< 2:1.1-2)
+Description: Go standard library compiled for linux_386
+ This package contains the Go standard library,
+ compiled for linux_386.
+ .
+ This package is just one of a number of packages, each providing the Go
+ standard library for a specific operating system/architecture combination.
+ Go supports cross-compilation, so each of these packages is useful on any
+ architecture.
+ .
+ The files contained in this package are independent of the host architecture,
+ that is, you can use golang-go-linux-amd64 to generate a binary for
+ linux_amd64, even though you are executing the Go compiler on linux_386.
+
+Package: golang-go-freebsd-amd64
+Architecture: all
+Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends}
+Breaks: golang-go (<< 2:1.1-2)
+Replaces: golang-go (<< 2:1.1-2)
+Description: Go standard library compiled for freebsd_amd64
+ This package contains the Go standard library,
+ compiled for freebsd_amd64.
+ .
+ This package is just one of a number of packages, each providing the Go
+ standard library for a specific operating system/architecture combination.
+ Go supports cross-compilation, so each of these packages is useful on any
+ architecture.
+ .
+ The files contained in this package are independent of the host architecture,
+ that is, you can use golang-go-linux-amd64 to generate a binary for
+ linux_amd64, even though you are executing the Go compiler on linux_386.
+
+Package: golang-go-freebsd-arm
+Architecture: all
+Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends}
+Breaks: golang-go (<< 2:1.1-2)
+Replaces: golang-go (<< 2:1.1-2)
+Description: Go standard library compiled for freebsd_arm
+ This package contains the Go standard library,
+ compiled for freebsd_arm.
+ .
+ This package is just one of a number of packages, each providing the Go
+ standard library for a specific operating system/architecture combination.
+ Go supports cross-compilation, so each of these packages is useful on any
+ architecture.
+ .
+ The files contained in this package are independent of the host architecture,
+ that is, you can use golang-go-linux-amd64 to generate a binary for
+ linux_amd64, even though you are executing the Go compiler on linux_386.
+
+Package: golang-go-freebsd-386
+Architecture: all
+Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends}
+Breaks: golang-go (<< 2:1.1-2)
+Replaces: golang-go (<< 2:1.1-2)
+Description: Go standard library compiled for freebsd_386
+ This package contains the Go standard library,
+ compiled for freebsd_386.
+ .
+ This package is just one of a number of packages, each providing the Go
+ standard library for a specific operating system/architecture combination.
+ Go supports cross-compilation, so each of these packages is useful on any
+ architecture.
+ .
+ The files contained in this package are independent of the host architecture,
+ that is, you can use golang-go-linux-amd64 to generate a binary for
+ linux_amd64, even though you are executing the Go compiler on linux_386.
+
+Package: golang-go-windows-amd64
+Architecture: all
+Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends}
+Breaks: golang-go (<< 2:1.1-2)
+Replaces: golang-go (<< 2:1.1-2)
+Description: Go standard library compiled for windows_amd64
+ This package contains the Go standard library,
+ compiled for windows_amd64.
+ .
+ This package is just one of a number of packages, each providing the Go
+ standard library for a specific operating system/architecture combination.
+ Go supports cross-compilation, so each of these packages is useful on any
+ architecture.
+ .
+ The files contained in this package are independent of the host architecture,
+ that is, you can use golang-go-linux-amd64 to generate a binary for
+ linux_amd64, even though you are executing the Go compiler on linux_386.
+
+Package: golang-go-windows-386
+Architecture: all
+Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends}
+Breaks: golang-go (<< 2:1.1-2)
+Replaces: golang-go (<< 2:1.1-2)
+Description: Go standard library compiled for windows_386
+ This package contains the Go standard library,
+ compiled for windows_386.
+ .
+ This package is just one of a number of packages, each providing the Go
+ standard library for a specific operating system/architecture combination.
+ Go supports cross-compilation, so each of these packages is useful on any
+ architecture.
+ .
+ The files contained in this package are independent of the host architecture,
+ that is, you can use golang-go-linux-amd64 to generate a binary for
+ linux_amd64, even though you are executing the Go compiler on linux_386.
+
+Package: golang-go-darwin-amd64
+Architecture: all
+Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends}
+Breaks: golang-go (<< 2:1.1-2)
+Replaces: golang-go (<< 2:1.1-2)
+Description: Go standard library compiled for darwin_amd64
+ This package contains the Go standard library,
+ compiled for darwin_amd64.
+ .
+ This package is just one of a number of packages, each providing the Go
+ standard library for a specific operating system/architecture combination.
+ Go supports cross-compilation, so each of these packages is useful on any
+ architecture.
+ .
+ The files contained in this package are independent of the host architecture,
+ that is, you can use golang-go-linux-amd64 to generate a binary for
+ linux_amd64, even though you are executing the Go compiler on linux_386.
+
+Package: golang-go-darwin-386
+Architecture: all
+Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends}
+Breaks: golang-go (<< 2:1.1-2)
+Replaces: golang-go (<< 2:1.1-2)
+Description: Go standard library compiled for darwin_386
+ This package contains the Go standard library,
+ compiled for darwin_386.
+ .
+ This package is just one of a number of packages, each providing the Go
+ standard library for a specific operating system/architecture combination.
+ Go supports cross-compilation, so each of these packages is useful on any
+ architecture.
+ .
+ The files contained in this package are independent of the host architecture,
+ that is, you can use golang-go-linux-amd64 to generate a binary for
+ linux_amd64, even though you are executing the Go compiler on linux_386.
+
+Package: golang-go-netbsd-amd64
+Architecture: all
+Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends}
+Breaks: golang-go (<< 2:1.1-2)
+Replaces: golang-go (<< 2:1.1-2)
+Description: Go standard library compiled for netbsd_amd64
+ This package contains the Go standard library,
+ compiled for netbsd_amd64.
+ .
+ This package is just one of a number of packages, each providing the Go
+ standard library for a specific operating system/architecture combination.
+ Go supports cross-compilation, so each of these packages is useful on any
+ architecture.
+ .
+ The files contained in this package are independent of the host architecture,
+ that is, you can use golang-go-linux-amd64 to generate a binary for
+ linux_amd64, even though you are executing the Go compiler on linux_386.
+
+Package: golang-go-netbsd-386
+Architecture: all
+Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends}
+Breaks: golang-go (<< 2:1.1-2)
+Replaces: golang-go (<< 2:1.1-2)
+Description: Go standard library compiled for netbsd_386
+ This package contains the Go standard library,
+ compiled for netbsd_386.
+ .
+ This package is just one of a number of packages, each providing the Go
+ standard library for a specific operating system/architecture combination.
+ Go supports cross-compilation, so each of these packages is useful on any
+ architecture.
+ .
+ The files contained in this package are independent of the host architecture,
+ that is, you can use golang-go-linux-amd64 to generate a binary for
+ linux_amd64, even though you are executing the Go compiler on linux_386.
diff --git a/debian/control.base b/debian/control.base
new file mode 100644
index 0000000..94e2823
--- /dev/null
+++ b/debian/control.base
@@ -0,0 +1,103 @@
+Source: golang
+Section: devel
+Priority: optional
+Maintainer: Go Compiler Team <pkg-golang-devel at lists.alioth.debian.org>
+Uploaders: Michael Stapelberg <stapelberg at debian.org>,
+           Paul Tagliamonte <paultag at debian.org>,
+           Tianon Gravi <admwiggin at gmail.com>
+Vcs-Browser: http://anonscm.debian.org/gitweb/?p=pkg-golang/golang.git
+Vcs-Git: git://anonscm.debian.org/pkg-golang/golang.git
+Build-Depends: debhelper (>= 7.4.10), bison, ed, mawk | awk, perl, netbase
+Build-Depends-Indep: po-debconf
+Standards-Version: 3.9.6
+Homepage: http://golang.org/
+
+Package: golang-go
+Architecture: i386 amd64 armel armhf
+Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends},
+	 golang-src (>= ${source:Version}),
+	 golang-go-linux-${go:Hostarch} (= ${source:Version})
+Replaces: golang-weekly-go, golang-weekly-tools, golang-tools
+Conflicts: golang-weekly-go, golang-weekly-tools, golang-tools
+Provides: go-compiler, golang-weekly-go, golang-weekly-tools, golang-tools
+Suggests: bzr, git, golang-go.tools, mercurial, subversion
+Description: Go programming language compiler
+ The Go programming language is an open source project to make
+ programmers more productive. Go is expressive, concise, clean, and
+ efficient. Its concurrency mechanisms make it easy to write programs
+ that get the most out of multicore and networked machines, while its
+ novel type system enables flexible and modular program construction.
+ Go compiles quickly to machine code yet has the convenience of
+ garbage collection and the power of run-time reflection. It's a
+ fast, statically typed, compiled language that feels like a
+ dynamically typed, interpreted language.
+ .
+ This package provides an assembler, a compiler, and a linker for the
+ Go programming language. This is Google's implementation of the Go
+ tool chain.
+
+Package: golang-src
+Replaces: golang-weekly-src, golang-go (<< 2:1-3~)
+Conflicts: golang-weekly-src
+Provides: golang-weekly-src
+Breaks: golang-go (<< 2:1-3~)
+Architecture: i386 amd64 armel armhf
+Depends: ${shlibs:Depends}, ${misc:Depends}
+Description: Go programming language compiler - source files
+ The Go programming language is an open source project to make
+ programmers more productive. Go is expressive, concise, clean, and
+ efficient. Its concurrency mechanisms make it easy to write programs
+ that get the most out of multicore and networked machines, while its
+ novel type system enables flexible and modular program construction.
+ Go compiles quickly to machine code yet has the convenience of
+ garbage collection and the power of run-time reflection. It's a
+ fast, statically typed, compiled language that feels like a
+ dynamically typed, interpreted language.
+ .
+ This package provides the Go programming language source files needed
+ for godoc and goinstall.
+
+Package: golang-doc
+Replaces: golang-weekly-doc
+Conflicts: golang-weekly-doc
+Provides: golang-weekly-doc
+Depends: ${misc:Depends}, golang-go
+Architecture: all
+Section: doc
+Description: Go programming language compiler - documentation
+ The Go programming language is an open source project to make
+ programmers more productive. Go is expressive, concise, clean, and
+ efficient. Its concurrency mechanisms make it easy to write programs
+ that get the most out of multicore and networked machines, while its
+ novel type system enables flexible and modular program construction.
+ Go compiles quickly to machine code yet has the convenience of
+ garbage collection and the power of run-time reflection. It's a fast,
+ statically typed, compiled language that feels like a dynamically
+ typed, interpreted language.
+ .
+ This package provides the documentation for the Go programming
+ language. You can view the formatted documentation by running "godoc
+ --http=:6060", and then visiting http://localhost:6060/doc/install.html.
+
+Package: golang
+Replaces: golang-weekly
+Conflicts: golang-weekly
+Provides: golang-weekly
+Depends: ${misc:Depends},
+	 golang-go (>= ${source:Version}),
+	 golang-src (>= ${source:Version}),
+	 golang-doc (>= ${source:Version})
+Architecture: all
+Description: Go programming language compiler - metapackage
+ The Go programming language is an open source project to make
+ programmers more productive. Go is expressive, concise, clean, and
+ efficient. Its concurrency mechanisms make it easy to write programs
+ that get the most out of multicore and networked machines, while its
+ novel type system enables flexible and modular program construction.
+ Go compiles quickly to machine code yet has the convenience of
+ garbage collection and the power of run-time reflection. It's a
+ fast, statically typed, compiled language that feels like a
+ dynamically typed, interpreted language.
+ .
+ This package is a metapackage that, when installed, guarantees
+ that (most of) a full Go development environment is installed.
diff --git a/debian/control.cross b/debian/control.cross
new file mode 100644
index 0000000..592b4f9
--- /dev/null
+++ b/debian/control.cross
@@ -0,0 +1,18 @@
+
+Package: golang-go- at OS@- at ARCH@
+Architecture: @BUILDARCHS@
+Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends}
+Breaks: golang-go (<< 2:1.1-2)
+Replaces: golang-go (<< 2:1.1-2)
+Description: Go standard library compiled for @OS at _@ARCH@
+ This package contains the Go standard library,
+ compiled for @OS at _@ARCH at .
+ .
+ This package is just one of a number of packages, each providing the Go
+ standard library for a specific operating system/architecture combination.
+ Go supports cross-compilation, so each of these packages is useful on any
+ architecture.
+ .
+ The files contained in this package are independent of the host architecture,
+ that is, you can use golang-go-linux-amd64 to generate a binary for
+ linux_amd64, even though you are executing the Go compiler on linux_386.
diff --git a/debian/copyright b/debian/copyright
index 5a0faeb..ae2e96f 100644
--- a/debian/copyright
+++ b/debian/copyright
@@ -1,54 +1,23 @@
-Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
-Upstream-Name: golang
-Source: https://github.com/golang/go
+Source: https://go.googlecode.com/hg/
 
 Files: *
 Copyright: © 2009, 2010, The Go Authors.  All rights reserved.
 License: Go
 
-Files: include/*
- src/lib9/*
- src/libbio/*
- src/runtime/386/*
- src/libmach/*
- src/runtime/arm/vlop.s
- src/runtime/arm/vlrt.c
- src/runtime/arm/memset.s
- src/runtime/arm/memmove.s
- src/runtime/amd64/memmove.s
- src/runtime/amd64/memmove.s
- src/math/fltasm_amd64.s
- src/cmd/6c/txt.c
- src/cmd/gopack/ar.c
- src/cmd/ld/lib.[ch]
- src/cmd/6a/a.[yh]
- src/cmd/6a/lex.c
- src/cmd/5g/gobj.c
- src/cmd/5g/list.c
- src/cmd/5g/gsubr.c
- src/cmd/5g/opt.h
- src/cmd/8c/*
- src/cmd/goyacc/goyacc.go
- src/cmd/5l/*
- src/cmd/6g/reg.c
- src/cmd/6g/gobj.c
- src/cmd/6g/peep.c
- src/cmd/6g/list.c
- src/cmd/6g/gsubr.c
- src/cmd/6g/opt.c
- src/cmd/8l/*
- src/cmd/nm/nm.c
- src/cmd/gc/bits.c
- src/cmd/cc/*
- src/cmd/5a/*
- src/cmd/8g/reg.c
- src/cmd/8g/gobj.c
- src/cmd/8g/peep.c
- src/cmd/8g/list.c
- src/cmd/8g/gsubr.c
- src/cmd/8g/opt.h
- src/cmd/5c/*
- src/cmd/6l/*
+Files: include/*, src/lib9/*, src/libbio/*, src/pkg/runtime/386/*,
+ src/libmach/*, src/pkg/runtime/arm/vlop.s, src/pkg/runtime/arm/vlrt.c,
+ src/pkg/runtime/arm/memset.s, src/pkg/runtime/arm/memmove.s,
+ src/pkg/runtime/amd64/memmove.s, src/pkg/runtime/amd64/memmove.s,
+ src/pkg/math/fltasm_amd64.s, src/cmd/6c/txt.c, src/cmd/gopack/ar.c,
+ src/cmd/ld/lib.[ch], src/cmd/6a/a.[yh], src/cmd/6a/lex.c,
+ src/cmd/5g/gobj.c, src/cmd/5g/list.c, src/cmd/5g/gsubr.c,
+ src/cmd/5g/opt.h, src/cmd/8c/*, src/cmd/goyacc/goyacc.go,
+ src/cmd/5l/*, src/cmd/6g/reg.c, src/cmd/6g/gobj.c,
+ src/cmd/6g/peep.c, src/cmd/6g/list.c, src/cmd/6g/gsubr.c,
+ src/cmd/6g/opt.c, src/cmd/8l/*, src/cmd/nm/nm.c,
+ src/cmd/gc/bits.c, src/cmd/cc/*, src/cmd/5a/*, src/cmd/8g/reg.c,
+ src/cmd/8g/gobj.c, src/cmd/8g/peep.c, src/cmd/8g/list.c,
+ src/cmd/8g/gsubr.c, src/cmd/8g/opt.h, src/cmd/5c/*, src/cmd/6l/*,
  src/cmd/8a/*
 Origin: Plan 9 from User Space include/, src/lib9/, src/libmach/
         Inferno utils/include/, utils/libmach/, utils/6c/, utils/iar/,
@@ -65,42 +34,22 @@ Copyright: © 1994-1999 Lucent Technologies Inc.  All rights reserved.
            Portions © 2009 The Go Authors.  All rights reserved.
 License: X11
 
-Files: src/lib9/goos.c
- src/lib9/win32.c
- src/lib9/Makefile
- src/runtime/386/asm.s
- src/runtime/386/closure.c
- src/runtime/arm/asm.s
- src/runtime/arm/closure.c
- src/runtime/arm/cas5.s
- src/libmach/fakeobj.c
- src/libmach/macho.h
- src/cmd/6c/doc.go
- src/cmd/6c/Makefile
- src/cmd/8c/doc.go
- src/cmd/8c/Makefile
- src/cmd/5l/doc.go
- src/cmd/5l/softfloat.c
- src/cmd/5l/Makefile
- src/cmd/8l/doc.go
- src/cmd/8l/Makefile
- src/cmd/cc/doc.go
- src/cmd/cc/Makefile
- src/cmd/5a/doc.go
- src/cmd/5a/Makefile
- src/cmd/5c/doc.go
- src/cmd/5c/Makefile
- src/cmd/6l/doc.go
- src/cmd/6l/Makefile
- src/cmd/8a/doc.go
- src/cmd/8a/Makefile
+Files: src/lib9/goos.c, src/lib9/win32.c, src/lib9/Makefile,
+ src/pkg/runtime/386/asm.s, src/pkg/runtime/386/closure.c,
+ src/pkg/runtime/arm/asm.s, src/pkg/runtime/arm/closure.c,
+ src/pkg/runtime/arm/cas5.s, src/libmach/fakeobj.c,
+ src/libmach/macho.h, src/cmd/6c/doc.go, src/cmd/6c/Makefile,
+ src/cmd/8c/doc.go, src/cmd/8c/Makefile, src/cmd/5l/doc.go,
+ src/cmd/5l/softfloat.c, src/cmd/5l/Makefile, src/cmd/8l/doc.go,
+ src/cmd/8l/Makefile, src/cmd/cc/doc.go, src/cmd/cc/Makefile,
+ src/cmd/5a/doc.go, src/cmd/5a/Makefile, src/cmd/5c/doc.go,
+ src/cmd/5c/Makefile, src/cmd/6l/doc.go, src/cmd/6l/Makefile,
+ src/cmd/8a/doc.go, src/cmd/8a/Makefile
 Copyright: © 2009, 2010, The Go Authors.  All rights reserved.
 License: Go
 
-Files: include/fmt.h
- src/lib9/utf/*
- src/lib9/fmt/*
- src/runtime/rune.c
+Files: include/fmt.h, src/lib9/utf/*, src/lib9/fmt/*,
+ src/pkg/runtime/rune.c
 Copyright: © 1998-2002 by Lucent Technologies.
            Portions © 2004 Google Inc.
            Portions © 2009 The Go Authors.  All rights reserved.
@@ -142,39 +91,36 @@ Notes:
  It's convenient to have a copy here because we need just the one
  Perl script, not all the C++ libraries that surround it.
 
-Files: src/runtime/tiny/bootblock
+Files: src/pkg/runtime/tiny/bootblock
 Origin: Xv6 rev3
 Copyright: © 2006-2009 Frans Kaashoek, Robert Morris, Russ Cox,
                        Massachusetts Institute of Technology
 License: X11
 
-Files: src/debug/dwarf/testdata/typedef.macho
- src/debug/dwarf/testdata/typedef.elf
-Source: src/debug/dwarf/testdata/typedef.c
+Files: src/pkg/debug/dwarf/testdata/typedef.macho,
+ src/pkg/debug/dwarf/testdata/typedef.elf
+Source: src/pkg/debug/dwarf/testdata/typedef.c
 Copyright: © 2009, The Go Authors.  All rights reserved.
 License: Go
 
-Files: src/debug/macho/testdata/gcc-amd64-darwin-exec-debug
- src/debug/macho/testdata/gcc-386-darwin-exec
- src/debug/macho/testdata/gcc-amd64-darwin-exec
- src/debug/elf/testdata/go-relocation-test-gcc424-x86-64.o
- src/debug/elf/testdata/gcc-amd64-linux-exec
- src/debug/elf/testdata/go-relocation-test-gcc441-x86.o
- src/debug/elf/testdata/gcc-386-freebsd-exec
- src/debug/elf/testdata/go-relocation-test-gcc441-x86-64.o
-Source: src/debug/elf/testdata/hello.c
-Copyright: © 2009, 2010, The Go Authors.  All rights reserved.
-License: Go
+Files: src/pkg/debug/macho/testdata/gcc-amd64-darwin-exec-debug,
+ src/pkg/debug/macho/testdata/gcc-386-darwin-exec,
+ src/pkg/debug/macho/testdata/gcc-amd64-darwin-exec,
+ src/pkg/debug/elf/testdata/go-relocation-test-gcc424-x86-64.o,
+ src/pkg/debug/elf/testdata/gcc-amd64-linux-exec,
+ src/pkg/debug/elf/testdata/go-relocation-test-gcc441-x86.o,
+ src/pkg/debug/elf/testdata/gcc-386-freebsd-exec,
+ src/pkg/debug/elf/testdata/go-relocation-test-gcc441-x86-64.o
+Source: ?
 
-Files: src/debug/elf/elf.go
- src/cmd/ld/elf.h
+Files: src/pkg/debug/elf/elf.go, src/cmd/ld/elf.h
 Origin: FreeBSD src/sys/sys/elf{32,64,_common}.h, src/sys/*/include/elf.h
 Copyright: © 1996-1998 John D. Polstra.  All rights reserved.
            © 2001 David E. O'Brien
            Portions © 2009 The Go Authors.  All rights reserved.
 License: FreeBSD
 
-Files: src/math/log1p.go
+Files: src/pkg/math/log1p.go
 Origin: Translated and simplified from FreeBSD /usr/src/lib/msun/src/s_log1p.c
 Copyright: © 2010 The Go Authors. All rights reserved.
            Based on code © 1993 by Sun Microsystems, Inc. All rights reserved.
@@ -192,21 +138,20 @@ License: Go
  software is freely granted, provided that this notice
  is preserved.
 
-Files: src/image/jpeg/idct.go
+Files: src/pkg/image/jpeg/idct.go
 Origin: Translated from idct.c in the MPEG-2 (ISO/IEC 13818-4)
          technical report video software verifier (mpeg2decode)
          version 960109
 Copyright: © 1996, MPEG Software Simulation Group. All Rights Reserved.
 License: MPEG
 
-Files: src/exp/spacewar/pdp1.go
- src/exp/spacewar/spacewar.go
+Files: src/pkg/exp/spacewar/pdp1.go, src/pkg/exp/spacewar/spacewar.go
 Origin: Translated from the Java emulator pdp1.java in Spacewar!
 Copyright: © 1996 Barry Silverman, Brian Silverman, Vadim Gerasimov.
            Portions © 2009 The Go Authors.
 License: Spacewar!
 
-Files: src/exp/spacewar/code.go
+Files: src/pkg/exp/spacewar/code.go
 Origin: The original Spacewar!
 Copyright: See license
 License: PD
@@ -239,8 +184,7 @@ License: PD
       Brian Silverman
       Vadim Gerasimov
 
-Files: src/exp/4s/xs.go
- src/exp/4s/data.go
+Files: src/pkg/exp/4s/xs.go, src/pkg/exp/4s/data.go
 Origin: Derived from Plan 9's /sys/src/games/xs.c
 Copyright: © 2003, Lucent Technologies Inc. and others. All Rights Reserved.
            Portions © 2009 The Go Authors.  All Rights Reserved.
@@ -257,12 +201,12 @@ Copyright: © 2003, Lucent Technologies Inc. and others. All Rights Reserved.
            Portions © 2009 The Go Authors.  All Rights Reserved.
 License: Plan9
 
-Files: src/html/testdata/webkit/*
+Files: src/pkg/html/testdata/webkit/*
 Origin: WebKit LayoutTests/html5lib/resources/
 Copyright: © 2009, Apple Inc. All rights reserved.
 License: WebKit
 
-Files: src/image/png/testdata/pngsuite/*
+Files: src/pkg/image/png/testdata/pngsuite/*
 Origin: libpng 1.2.40, contrib/pngsuite/*
 Copyright: © Willem van Schaik, 1999
 License: noderivs
@@ -286,13 +230,11 @@ Authors: contributed by The Go Authors.
                               modified by Michael Mellor)
 License: Shootout
 
-Files: test/garbage/tree.go
- test/bench/*
+Files: test/garbage/tree.go, test/bench/*
 Copyright: Brent Fulgham
 License: Shootout
 
-Files: favicon.ico
- doc/gopher/*
+Files: favicon.ico, doc/gopher/*
 Author: Renée French
 License: CC-BY-3.0
  The mascot and logo were designed by
@@ -311,18 +253,10 @@ License: CC-BY-3.0
  Except as noted, this content is licensed under Creative Commons
  Attribution 3.0
 
-Files: doc/htmlgen.go
- doc/makehtml
- doc/popups.js
- doc/style.css
- doc/Makefile
- doc/codelab/wiki/Makefile
- doc/prog.sh
- doc/progs/*
- doc/codewalk/codewalk.css
- doc/codewalk/codewalk.js
- doc/codewalk/urlpoll.go
- doc/talks/io2010/*.go
+Files: doc/htmlgen.go, doc/makehtml, doc/popups.js, doc/style.css,
+ doc/Makefile, doc/codelab/wiki/Makefile, doc/prog.sh, doc/progs/*,
+ doc/codewalk/codewalk.css, doc/codewalk/codewalk.js,
+ doc/codewalk/urlpoll.go, doc/talks/io2010/*.go
 Copyright: © 2009, 2010, The Go Authors.  All rights reserved.
 License: Go
 
@@ -338,10 +272,8 @@ License: W3C
 
 Files: debian/*
 Copyright: 2010 Ivan Wong <ivanwyc at gmail.com>
-           2010 Ondřej Surý <ondrej at debian.org>
-           2012 Michael Stapelberg <stapelberg at debian.org>
-           2014 Canonical Ltd
-           2014 Tianon Gravi <tianon at debian.org>
+           2010-2013 Ondřej Surý <ondrej at debian.org>
+           2013 Michael Stapelberg <stapelberg at debian.org>
 License: Go
 
 License: Go
diff --git a/debian/docs b/debian/docs
index 4ad6ffb..9975f39 100644
--- a/debian/docs
+++ b/debian/docs
@@ -1,3 +1,3 @@
+README
 AUTHORS
 CONTRIBUTORS
-README.md
diff --git a/debian/golang-doc.links b/debian/golang-doc.links
index fbd3d65..68cc210 100644
--- a/debian/golang-doc.links
+++ b/debian/golang-doc.links
@@ -1,2 +1,2 @@
-usr/share/doc/golang-doc/favicon.ico /usr/lib/go/favicon.ico
 usr/share/doc/golang-doc/html /usr/lib/go/doc
+usr/share/doc/golang-doc/favicon.ico /usr/lib/go/favicon.ico
diff --git a/debian/golang-go.install b/debian/golang-go.install
index c79c8b1..c819e34 100644
--- a/debian/golang-go.install
+++ b/debian/golang-go.install
@@ -1,7 +1,5 @@
-VERSION /usr/lib/go/
 bin/go /usr/lib/go/bin/
 bin/gofmt /usr/lib/go/bin/
-pkg/*_* /usr/lib/go/pkg/
-pkg/include /usr/share/go/pkg/
 pkg/obj /usr/lib/go/pkg/
 pkg/tool /usr/lib/go/pkg/
+VERSION /usr/lib/go/
diff --git a/debian/golang-go.links b/debian/golang-go.links
index 8865815..8a3bad6 100644
--- a/debian/golang-go.links
+++ b/debian/golang-go.links
@@ -1,3 +1,3 @@
-usr/share/go/pkg/include /usr/lib/go/pkg/include
 usr/share/go/src /usr/lib/go/src
 usr/share/go/test /usr/lib/go/test
+usr/share/go/include /usr/lib/go/include
diff --git a/debian/golang-go.postinst b/debian/golang-go.postinst
index ca3f089..6a6081e 100644
--- a/debian/golang-go.postinst
+++ b/debian/golang-go.postinst
@@ -22,15 +22,8 @@ case "$1" in
 	# Very ugly hack to set timestamps same as /usr/lib/go/bin/go
 	find /usr/lib/go/pkg -exec touch -r /usr/lib/go/bin/go {} \;
 	# Setup alternatives
-	# Priority: base of 100 + go version; 1.4.2 = 100 + 42; 1.5 = 100 + 50
-	go=$(/usr/lib/go/bin/go version | awk '{
-		gsub(/^go1|[.]/, "", $3);
-		gsub(/([^0-9.]+.*)$/, "", $3);
-		if ($3 ~ /^[0-9]$/) {
-			$3 = $3 "0";
-		};
-		print $3;
-	}')
+	# Priority: base of 100 + go version; 1.4.2 = 100 + 42)
+	go=$(/usr/lib/go/bin/go version | awk '{ gsub(/^go1|[.]/, "", $3); print $3 }')
 	priority=$(( 100 + $go ))
 	update-alternatives \
 		--install /usr/bin/go go /usr/lib/go/bin/go $priority \
diff --git a/debian/golang-src.install b/debian/golang-src.install
index f034ba5..f245da9 100644
--- a/debian/golang-src.install
+++ b/debian/golang-src.install
@@ -1,2 +1,3 @@
 src /usr/share/go/
 test /usr/share/go/
+include /usr/share/go/
diff --git a/debian/rules b/debian/rules
index 31b1b8f..b2545c2 100755
--- a/debian/rules
+++ b/debian/rules
@@ -2,15 +2,28 @@
 # This file is in the public domain.
 # You may freely use, modify, distribute, and relicense it.
 
+PACKAGE = golang
+
 libexecdir := /usr/lib/go
 datadir := /usr/share/go
 bindir := /bin
 
+# We loop over supported operating systems and architectures multiple times,
+# so these two variables contain a centralized version of that code.
+# The variables $$os and $$arch can be used inside such a loop.
+FOR_GO_ARCH := for os in $$(echo linux freebsd windows darwin netbsd); do \
+	archs="amd64 386"; \
+	[ "$$os" = "linux" ] || [ "$$os" = "freebsd" ] && archs="amd64 arm 386"; \
+	for arch in $$(echo $$archs); do
+FOR_GO_ARCH_END := done; done
+
 build-arch build-indep build clean install binary-arch binary-indep binary: debian/control
 	+dh --parallel $(opt_no_act) $@
 
 override_dh_auto_clean:
 	rm -rf bin pkg
+	# golang-go-$os-$arch.install files are auto-generated in override_dh_install
+	rm -f debian/golang-go-*.install
 	rm -f debian/*+
 	rm -f debian/build.stamp
 	rm -f test/pass.out test/run.out test/times.out
@@ -27,24 +40,50 @@ else
 endif
 
 override_dh_compress:
-	dh_compress -Xusr/share/doc/golang-doc/html -Xusr/share/doc/golang-doc/godoc
+	dh_compress -Xusr/share/doc/$(PACKAGE)-doc/html -Xusr/share/doc/$(PACKAGE)-doc/godoc
+
+# Generates debian/control from debian/control.base and debian/control.cross.
+# In the latter, @OS@ and @ARCH@ are replaced with every supported combination
+# of operating system and architecture (e.g. linux_amd64, linux_386, …).
+gencontrol:
+	echo "# DO NOT EDIT THIS FILE. EDIT debian/control.* instead!" > debian/control.tmp
+	cat debian/control.base >> debian/control.tmp
+	${FOR_GO_ARCH} \
+		BUILDARCHS=all; \
+		[ "$$os" = "linux" ] && BUILDARCHS="i386 amd64 armel armhf"; \
+		sed -e "s, at OS@,$$os,g; s, at ARCH@,$$arch,g; s, at BUILDARCHS@,$$BUILDARCHS,g" debian/control.cross >> debian/control.tmp; \
+	${FOR_GO_ARCH_END}
+	mv debian/control.tmp debian/control
 
 override_dh_install:
+	-${FOR_GO_ARCH} \
+		echo "pkg/$${os}_$${arch} /usr/lib/go/pkg/" > debian/golang-go-$$os-$$arch.install; \
+		[ "$$arch" = "amd64" ] && [ "$$os" = "linux" ] && echo "pkg/linux_amd64_race /usr/lib/go/pkg" >> debian/golang-go-$$os-$$arch.install; \
+		echo "golang-go-$$os-$$arch: arch-independent-package-contains-binary-or-object" > debian/golang-go-$$os-$$arch.lintian-overrides; \
+	${FOR_GO_ARCH_END}
 	# Install the native runtime/cgo.a to the golang-go package.
 	# runtime/cgo is only built for the native architecture, but the
 	# golang-go-OS-ARCH packages are built on one particular buildd, which
 	# might either be i386 or amd64.
 	echo "listing of $$(pwd):"; ls -hlR .
 	echo "listing of GOBIN: ($(GOBIN))"; ls -hlR $(GOBIN)
-	for file in pkg/*/runtime/cgo.a; do \
-		mkdir -p $(CURDIR)/debian/golang-go/usr/lib/go/$$(dirname $$file); \
-		mv $$file $(CURDIR)/debian/golang-go/usr/lib/go/$$file; \
+	for file in $$(cd pkg/ && ls */runtime/cgo.a); do \
+		mkdir -p $(CURDIR)/debian/golang-go/usr/lib/go/pkg/$$(dirname $$file); \
+		mv pkg/$$file $(CURDIR)/debian/golang-go/usr/lib/go/pkg/$$file; \
 	done
 	dh_install --fail-missing
+	# Remove .syso files of the race detector; it is not used yet and the files are arch-dependent.
+	find $(CURDIR)/debian/golang-src/usr/share/go/src/runtime/race -type f -name '*.syso' -delete
 	# Remove Plan9 rc(1) scripts
 	find $(CURDIR)/debian/golang-src/usr/share/go/src -type f -name "*.rc" -delete
 	# Remove empty /usr/share/go/src from golang-go, it is provided by golang-src
 	find $(CURDIR)/debian/golang-go/usr/share/go/src -type d -delete
+	# Subsequently, /usr/share/go is empty, too, so remove
+	find $(CURDIR)/debian/golang-go/usr/share/go -type d -delete
+	# For some reason, Go cross-compiles a handful of tools: {yacc,fix,api,vet,cgo}.
+	# Delete those, as they cannot be ran anyway.
+	# This is tracked upstream at https://code.google.com/p/go/issues/detail?id=5667
+	(cd $(CURDIR)/debian/golang-go/usr/lib/go/pkg/tool && find . -depth -path "./$(GOHOSTOS)_$(GOHOSTARCH)*" -prune -o -delete)
 	# Touch built and installed files and directories to have same timestamp
 	touch $(CURDIR)/debian/golang-go/usr/lib/go/pkg
 	find $(CURDIR)/debian/golang-go/usr/lib/go/pkg -exec touch -r $(CURDIR)/debian/golang-go/usr/lib/go/pkg {} \;
@@ -53,6 +92,10 @@ override_dh_strip:
 	# strip disabled as golang upstream doesn't support it and it makes go
 	# crash. See http://bugs.debian.org/717172
 
+override_dh_prep:
+	dh_prep
+	echo 'go:Hostarch=$(GOHOSTARCH)' >> debian/golang-go.substvars
+
 override_dh_builddeb:
 	dh_builddeb -- -Zxz
 
@@ -60,10 +103,23 @@ override_dh_shlibdeps:
 	dh_shlibdeps -Xtestdata -Xtest
 
 debian/build.stamp:
-	[ -f VERSION ] || echo "debian snapshot +$$(dpkg-parsechangelog -SVersion)" > VERSION
 	rm -f debian/build.stamp
 	mkdir -p $(GOBIN)
-	export GOROOT_BOOTSTRAP=$$(env -i go env GOROOT) && cd src && bash ./make.bash --no-banner
+	# Build native tools first, then bootstrap all other GOOS/GOARCH combinations.
+	cd src && bash ./make.bash --no-banner
+	# For the race detector to work (go test -race), we need to install the
+	# std library with the race detector enabled. This will result in
+	# having an additional “architecture” directory, e.g. linux_amd64_race.
+	#
+	# The race detector currently only works on linux/amd64. The check within
+	# the following loop works precisely the same way src/race.bash does.
+	-${FOR_GO_ARCH} \
+		export GOARCH=$$arch; \
+		export GOOS=$$os; \
+		cd src && bash ./make.bash --no-clean; \
+		[ "$$arch" = "amd64" ] && [ "$$os" = "linux" ] && $(GOBIN)/go install -race std; \
+		cd ..; \
+	${FOR_GO_ARCH_END}
 	>debian/build.stamp
 
 opt_no_act =
diff --git a/debian/source/lintian-overrides b/debian/source/lintian-overrides
index c078098..eaa4578 100644
--- a/debian/source/lintian-overrides
+++ b/debian/source/lintian-overrides
@@ -1,10 +1,10 @@
-golang source: source-contains-prebuilt-binary src/debug/dwarf/testdata/typedef.elf
-golang source: source-contains-prebuilt-binary src/debug/elf/testdata/gcc-amd64-linux-exec
-golang source: source-contains-prebuilt-binary src/debug/elf/testdata/go-relocation-test-gcc441-x86.obj
-golang source: source-contains-prebuilt-binary src/debug/elf/testdata/gcc-386-freebsd-exec
-golang source: source-contains-prebuilt-binary src/debug/elf/testdata/gcc-amd64-openbsd-debug-with-rela.obj
-golang source: source-contains-prebuilt-windows-binary src/debug/pe/testdata/gcc-386-mingw-exec
-golang source: source-contains-prebuilt-binary src/debug/elf/testdata/go-relocation-test-gcc424-x86-64.obj
-golang source: source-contains-prebuilt-binary src/debug/elf/testdata/go-relocation-test-gcc441-x86-64.obj
-golang source: source-contains-prebuilt-windows-binary src/debug/pe/testdata/gcc-386-mingw-obj
-golang source: source-contains-prebuilt-binary src/runtime/race/race_linux_amd64.syso
+golang source: source-contains-prebuilt-binary src/pkg/debug/dwarf/testdata/typedef.elf
+golang source: source-contains-prebuilt-binary src/pkg/debug/elf/testdata/gcc-amd64-linux-exec
+golang source: source-contains-prebuilt-binary src/pkg/debug/elf/testdata/go-relocation-test-gcc441-x86.obj
+golang source: source-contains-prebuilt-binary src/pkg/debug/elf/testdata/gcc-386-freebsd-exec
+golang source: source-contains-prebuilt-binary src/pkg/debug/elf/testdata/gcc-amd64-openbsd-debug-with-rela.obj
+golang source: source-contains-prebuilt-windows-binary src/pkg/debug/pe/testdata/gcc-386-mingw-exec
+golang source: source-contains-prebuilt-binary src/pkg/debug/elf/testdata/go-relocation-test-gcc424-x86-64.obj
+golang source: source-contains-prebuilt-binary src/pkg/debug/elf/testdata/go-relocation-test-gcc441-x86-64.obj
+golang source: source-contains-prebuilt-windows-binary src/pkg/debug/pe/testdata/gcc-386-mingw-obj
+golang source: source-contains-prebuilt-binary src/pkg/runtime/race/race_linux_amd64.syso
diff --git a/doc/articles/go_command.html b/doc/articles/go_command.html
index cc1d86a..2978628 100644
--- a/doc/articles/go_command.html
+++ b/doc/articles/go_command.html
@@ -250,16 +250,11 @@ projects at once within a single <code>$GOPATH</code> root directory.</p>
 <h2>Limitations</h2>
 
 <p>As mentioned above, the go command is not a general-purpose build
-tool.
-In particular, it does not have any facility for generating Go
-source files <em>during</em> a build, although it does provide
-<a href="/cmd/go/#hdr-Generate_Go_files_by_processing_source"><code>go</code>
-<code>generate</code></a>,
-which can automate the creation of Go files <em>before</em>
-the build, such as by running <code>yacc</code>.
-For more advanced build setups, you may need to write a
+tool. In particular, it does not have any facility for generating Go
+source files during a build.  Instead, if you want to use a tool like
+yacc or the protocol buffer compiler, you will need to write a
 makefile (or a configuration file for the build tool of your choice)
-to run whatever tool creates the Go files and then check those generated source files
+to generate the Go files and then check those generated source files
 into your repository. This is more work for you, the package author,
 but it is significantly less work for your users, who can use
 "<code>go get</code>" without needing to obtain and build
diff --git a/doc/articles/wiki/final.go b/doc/articles/wiki/final.go
index 139a323..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,9 +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/test.bash b/doc/articles/wiki/test.bash
index 8bbb734..2997f16 100755
--- a/doc/articles/wiki/test.bash
+++ b/doc/articles/wiki/test.bash
@@ -4,20 +4,14 @@
 # license that can be found in the LICENSE file.
 
 set -e
-
-if ! which patch > /dev/null; then
-	echo "Skipping test; patch command not found."
-	exit 0
-fi
-
 wiki_pid=
 cleanup() {
 	kill $wiki_pid
-	rm -f test_*.out Test.txt final-test.go final-test.bin final-test-port.txt 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-test.bin a.out
+rm -f get.bin final.bin a.out
 
 # If called with -all, check that all code snippets compile.
 if [ "$1" == "-all" ]; then
@@ -27,14 +21,12 @@ if [ "$1" == "-all" ]; then
 fi
 
 go build -o get.bin get.go
-cp final.go final-test.go
-patch final-test.go final-test.patch > /dev/null
-go build -o final-test.bin final-test.go
-./final-test.bin &
+go build -o final.bin final.go
+(./final.bin --addr) &
 wiki_pid=$!
 
 l=0
-while [ ! -f ./final-test-port.txt ]
+while [ ! -f ./final-port.txt ]
 do
 	l=$(($l+1))
 	if [ "$l" -gt 5 ]
@@ -46,7 +38,7 @@ do
 	sleep 1
 done
 
-addr=$(cat final-test-port.txt)
+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 --git a/doc/asm.html b/doc/asm.html
index c992e14..771c493 100644
--- a/doc/asm.html
+++ b/doc/asm.html
@@ -6,16 +6,16 @@
 <h2 id="introduction">A Quick Guide to Go's Assembler</h2>
 
 <p>
-This document is a quick outline of the unusual form of assembly language used by the <code>gc</code> Go compiler.
+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.).
 The document is not comprehensive.
 </p>
 
 <p>
-The assembler is based on the input style of the Plan 9 assemblers, which is documented in detail
-<a href="http://plan9.bell-labs.com/sys/doc/asm.html">elsewhere</a>.
+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.
-The current document provides a summary of the syntax and the differences with
-what is explained in that document, and
+This document provides a summary of the syntax and
 describes the peculiarities that apply when writing assembly code to interact with Go.
 </p>
 
@@ -25,12 +25,10 @@ Some of the details map precisely to the machine, but some do not.
 This is because the compiler suite (see
 <a href="http://plan9.bell-labs.com/sys/doc/compiler.html">this description</a>)
 needs no assembler pass in the usual pipeline.
-Instead, the compiler operates on a kind of semi-abstract instruction set,
-and instruction selection occurs partly after code generation.
-The assembler works on the semi-abstract form, so
-when you see an instruction like <code>MOV</code>
-what the tool chain actually generates for that operation might
-not be a move instruction at all, perhaps a clear or load.
+Instead, the compiler emits a kind of incompletely defined instruction set, in binary form, which the linker
+then completes.
+In particular, the linker does instruction selection, so when you see an instruction like <code>MOV</code>
+what the linker actually generates for that operation might not be a move instruction at all, perhaps a clear or load.
 Or it might correspond exactly to the machine instruction with that name.
 In general, machine-specific operations tend to appear as themselves, while more general concepts like
 memory move and subroutine call and return are more abstract.
@@ -38,15 +36,13 @@ The details vary with architecture, and we apologize for the imprecision; the si
 </p>
 
 <p>
-The assembler program is a way to parse a description of that
-semi-abstract instruction set and turn it into instructions to be
-input to the linker.
+The assembler program is a way to generate that intermediate, incompletely defined instruction sequence
+as input for the linker.
 If you want to see what the instructions look like in assembly for a given architecture, say amd64, there
 are many examples in the sources of the standard library, in packages such as
 <a href="/pkg/runtime/"><code>runtime</code></a> and
 <a href="/pkg/math/big/"><code>math/big</code></a>.
-You can also examine what the compiler emits as assembly code
-(the actual output may differ from what you see here):
+You can also examine what the compiler emits as assembly code:
 </p>
 
 <pre>
@@ -56,7 +52,7 @@ package main
 func main() {
 	println(3)
 }
-$ GOOS=linux GOARCH=amd64 go tool compile -S x.go        # or: go build -gcflags -S x.go
+$ go tool 6g -S x.go        # or: go build -gcflags -S x.go
 
 --- prog list "main" ---
 0000 (x.go:3) TEXT    main+0(SB),$8-0
@@ -110,73 +106,20 @@ codeblk [0x2000,0x1d059) at offset 0x1000
 
 -->
 
-<h3 id="constants">Constants</h3>
-
-<p>
-Although the assembler takes its guidance from the Plan 9 assemblers,
-it is a distinct program, so there are some differences.
-One is in constant evaluation.
-Constant expressions in the assembler are parsed using Go's operator
-precedence, not the C-like precedence of the original.
-Thus <code>3&1<<2</code> is 4, not 0—it parses as <code>(3&1)<<2</code>
-not <code>3&(1<<2)</code>.
-Also, constants are always evaluated as 64-bit unsigned integers.
-Thus <code>-2</code> is not the integer value minus two,
-but the unsigned 64-bit integer with the same bit pattern.
-The distinction rarely matters but
-to avoid ambiguity, division or right shift where the right operand's
-high bit is set is rejected.
-</p>
-
 <h3 id="symbols">Symbols</h3>
 
 <p>
-Some symbols, such as <code>R1</code> or <code>LR</code>,
-are predefined and refer to registers.
-The exact set depends on the architecture.
-</p>
-
-<p>
-There are four predeclared symbols that refer to pseudo-registers.
-These are not real registers, but rather virtual registers maintained by
-the tool chain, such as a frame pointer.
-The set of pseudo-registers is the same for all architectures:
-</p>
-
-<ul>
-
-<li>
-<code>FP</code>: Frame pointer: arguments and locals.
-</li>
-
-<li>
-<code>PC</code>: Program counter:
-jumps and branches.
-</li>
-
-<li>
-<code>SB</code>: Static base pointer: global symbols.
-</li>
-
-<li>
-<code>SP</code>: Stack pointer: top of stack.
-</li>
-
-</ul>
-
-<p>
-All user-defined symbols are written as offsets to the pseudo-registers
-<code>FP</code> (arguments and locals) and <code>SB</code> (globals).
+Some symbols, such as <code>PC</code>, <code>R0</code> and <code>SP</code>, are predeclared and refer to registers.
+There are two other predeclared symbols, <code>SB</code> (static base) and <code>FP</code> (frame pointer).
+All user-defined symbols other than jump labels are written as offsets to these pseudo-registers.
 </p>
 
 <p>
 The <code>SB</code> pseudo-register can be thought of as the origin of memory, so the symbol <code>foo(SB)</code>
 is the name <code>foo</code> as an address in memory.
 This form is used to name global functions and data.
-Adding <code><></code> to the name, as in <span style="white-space: nowrap"><code>foo<>(SB)</code></span>, makes the name
+Adding <code><></code> to the name, as in <code>foo<>(SB)</code>, makes the name
 visible only in the current source file, like a top-level <code>static</code> declaration in a C file.
-Adding an offset to the name refers to that offset from the symbol's address, so
-<code>a+4(SB)</code> is four bytes past the start of <code>foo</code>.
 </p>
 
 <p>
@@ -185,19 +128,9 @@ used to refer to function arguments.
 The compilers maintain a virtual frame pointer and refer to the arguments on the stack as offsets from that pseudo-register.
 Thus <code>0(FP)</code> is the first argument to the function,
 <code>8(FP)</code> is the second (on a 64-bit machine), and so on.
-However, when referring to a function argument this way, it is necessary to place a name
+When referring to a function argument this way, it is conventional to place the name
 at the beginning, as in <code>first_arg+0(FP)</code> and <code>second_arg+8(FP)</code>.
-(The meaning of the offset—offset from the frame pointer—distinct
-from its use with <code>SB</code>, where it is an offset from the symbol.)
-The assembler enforces this convention, rejecting plain <code>0(FP)</code> and <code>8(FP)</code>.
-The actual name is semantically irrelevant but should be used to document
-the argument's name.
-It is worth stressing that <code>FP</code> is always a
-pseudo-register, not a hardware
-register, even on architectures with a hardware frame pointer.
-</p>
-
-<p>
+Some of the assemblers enforce this convention, rejecting plain <code>0(FP)</code> and <code>8(FP)</code>.
 For assembly functions with Go prototypes, <code>go</code> <code>vet</code> will check that the argument names
 and offsets match.
 On 32-bit systems, the low and high 32 bits of a 64-bit value are distinguished by adding
@@ -212,54 +145,14 @@ prepared for function calls.
 It points to the top of the local stack frame, so references should use negative offsets
 in the range [−framesize, 0):
 <code>x-8(SP)</code>, <code>y-4(SP)</code>, and so on.
-</p>
-
-<p>
-On architectures with a hardware register named <code>SP</code>,
-the name prefix distinguishes
-references to the virtual stack pointer from references to the architectural
-<code>SP</code> register.
-That is, <code>x-8(SP)</code> and <code>-8(SP)</code>
-are different memory locations:
-the first refers to the virtual stack pointer pseudo-register,
-while the second refers to the
+On architectures with a real register named <code>SP</code>, the name prefix distinguishes
+references to the virtual stack pointer from references to the architectural <code>SP</code> register.
+That is, <code>x-8(SP)</code> and <code>-8(SP)</code> are different memory locations:
+the first refers to the virtual stack pointer pseudo-register, while the second refers to the
 hardware's <code>SP</code> register.
 </p>
 
 <p>
-On machines where <code>SP</code> and <code>PC</code> are
-traditionally aliases for a physical, numbered register,
-in the Go assembler the names <code>SP</code> and <code>PC</code>
-are still treated specially;
-for instance, references to <code>SP</code> require a symbol,
-much like <code>FP</code>.
-To access the actual hardware register use the true <code>R</code> name.
-For example, on the ARM architecture the hardware
-<code>SP</code> and <code>PC</code> are accessible as
-<code>R13</code> and <code>R15</code>.
-</p>
-
-<p>
-Branches and direct jumps are always written as offsets to the PC, or as
-jumps to labels:
-</p>
-
-<pre>
-label:
-	MOVW $0, R1
-	JMP label
-</pre>
-
-<p>
-Each label is visible only within the function in which it is defined.
-It is therefore permitted for multiple functions in a file to define
-and use the same label names.
-Direct jumps and call instructions can target text symbols,
-such as <code>name(SB)</code>, but not offsets from symbols,
-such as <code>name+4(SB)</code>.
-</p>
-
-<p>
 Instructions, registers, and assembler directives are always in UPPER CASE to remind you
 that assembly programming is a fraught endeavor.
 (Exception: the <code>g</code> register renaming on ARM.)
@@ -419,17 +312,11 @@ This data contains no pointers and therefore does not need to be
 scanned by the garbage collector.
 </li>
 <li>
-<code>WRAPPER</code> = 32
+<code>WRAPPER</code>  = 32
 <br>
 (For <code>TEXT</code> items.)
 This is a wrapper function and should not count as disabling <code>recover</code>.
 </li>
-<li>
-<code>NEEDCTXT</code> = 64
-<br>
-(For <code>TEXT</code> items.)
-This function is a closure so it uses its incoming context register.
-</li>
 </ul>
 
 <h3 id="runtime">Runtime Coordination</h3>
@@ -463,11 +350,7 @@ live pointers in its arguments, results, and local stack frame.
 For an assembly function with no pointer results and
 either no local stack frame or no function calls,
 the only requirement is to define a Go prototype for the function
-in a Go source file in the same package. The name of the assembly
-function must not contain the package name component (for example,
-function <code>Syscall</code> in package <code>syscall</code> should
-use the name <code>·Syscall</code> instead of the equivalent name
-<code>syscall·Syscall</code> in its <code>TEXT</code> directive).
+in a Go source file in the same package.
 For more complex situations, explicit annotation is needed.
 These annotations use pseudo-instructions defined in the standard
 <code>#include</code> file <code>funcdata.h</code>.
@@ -514,61 +397,42 @@ even pointers to stack data must not be kept in local variables.
 
 <p>
 It is impractical to list all the instructions and other details for each machine.
-To see what instructions are defined for a given machine, say ARM,
-look in the source for the <code>obj</code> support library for
-that architecture, located in the directory <code>src/cmd/internal/obj/arm</code>.
-In that directory is a file <code>a.out.go</code>; it contains
-a long list of constants starting with <code>A</code>, like this:
+To see what instructions are defined for a given machine, say 32-bit Intel x86,
+look in the top-level header file for the corresponding linker, in this case <code>8l</code>.
+That is, the file <code>$GOROOT/src/cmd/8l/8.out.h</code> contains a C enumeration, called <code>as</code>,
+of the instructions and their spellings as known to the assembler and linker for that architecture.
+In that file you'll find a declaration that begins
 </p>
 
 <pre>
-const (
-	AAND = obj.ABaseARM + obj.A_ARCHSPECIFIC + iota
-	AEOR
-	ASUB
-	ARSB
-	AADD
+enum	as
+{
+	AXXX,
+	AAAA,
+	AAAD,
+	AAAM,
+	AAAS,
+	AADCB,
 	...
 </pre>
 
 <p>
-This is the list of instructions and their spellings as known to the assembler and linker for that architecture.
-Each instruction begins with an initial capital <code>A</code> in this list, so <code>AAND</code>
-represents the bitwise and instruction,
-<code>AND</code> (without the leading <code>A</code>),
-and is written in assembly source as <code>AND</code>.
-The enumeration is mostly in alphabetical order.
-(The architecture-independent <code>AXXX</code>, defined in the
-<code>cmd/internal/obj</code> package,
-represents an invalid instruction).
-The sequence of the <code>A</code> names has nothing to do with the actual
-encoding of the machine instructions.
-The <code>cmd/internal/obj</code> package takes care of that detail.
-</p>
-
-<p>
-The instructions for both the 386 and AMD64 architectures are listed in
-<code>cmd/internal/obj/x86/a.out.go</code>.
-</p>
-
-<p>
-The architectures share syntax for common addressing modes such as
-<code>(R1)</code> (register indirect),
-<code>4(R1)</code> (register indirect with offset), and
-<code>$foo(SB)</code> (absolute address).
-The assembler also supports some (not necessarily all) addressing modes
-specific to each architecture.
-The sections below list these.
+Each instruction begins with a  initial capital <code>A</code> in this list, so <code>AADCB</code>
+represents the <code>ADCB</code> (add carry byte) instruction.
+The enumeration is in alphabetical order, plus some late additions (<code>AXXX</code> occupies
+the zero slot as an invalid instruction).
+The sequence has nothing to do with the actual encoding of the machine instructions.
+Again, the linker takes care of that detail.
 </p>
 
 <p>
 One detail evident in the examples from the previous sections is that data in the instructions flows from left to right:
 <code>MOVQ</code> <code>$0,</code> <code>CX</code> clears <code>CX</code>.
-This rule applies even on architectures where the conventional notation uses the opposite direction.
+This convention applies even on architectures where the usual mode is the opposite direction.
 </p>
 
 <p>
-Here follow some descriptions of key Go-specific details for the supported architectures.
+Here follows some descriptions of key Go-specific details for the supported architectures.
 </p>
 
 <h3 id="x86">32-bit Intel 386</h3>
@@ -577,11 +441,11 @@ Here follow some descriptions of key Go-specific details for the supported archi
 The runtime pointer to the <code>g</code> structure is maintained
 through the value of an otherwise unused (as far as Go is concerned) register in the MMU.
 A OS-dependent macro <code>get_tls</code> is defined for the assembler if the source includes
-a special header, <code>go_asm.h</code>:
+an architecture-dependent header file, like this:
 </p>
 
 <pre>
-#include "go_asm.h"
+#include "zasm_GOOS_GOARCH.h"
 </pre>
 
 <p>
@@ -594,39 +458,21 @@ The sequence to load <code>g</code> and <code>m</code> using <code>CX</code> loo
 <pre>
 get_tls(CX)
 MOVL	g(CX), AX     // Move g into AX.
-MOVL	g_m(AX), BX   // Move g.m into BX.
+MOVL	g_m(AX), BX   // Move g->m into BX.
 </pre>
 
-<p>
-Addressing modes:
-</p>
-
-<ul>
-
-<li>
-<code>(DI)(BX*2)</code>: The location at address <code>DI</code> plus <code>BX*2</code>.
-</li>
-
-<li>
-<code>64(DI)(BX*2)</code>: The location at address <code>DI</code> plus <code>BX*2</code> plus 64.
-These modes accept only 1, 2, 4, and 8 as scale factors.
-</li>
-
-</ul>
-
 <h3 id="amd64">64-bit Intel 386 (a.k.a. amd64)</h3>
 
 <p>
-The two architectures behave largely the same at the assembler level.
-Assembly code to access the <code>m</code> and <code>g</code>
-pointers on the 64-bit version is the same as on the 32-bit 386,
-except it uses <code>MOVQ</code> rather than <code>MOVL</code>:
+The assembly code to access the <code>m</code> and <code>g</code>
+pointers is the same as on the 386, except it uses <code>MOVQ</code> rather than
+<code>MOVL</code>:
 </p>
 
 <pre>
 get_tls(CX)
 MOVQ	g(CX), AX     // Move g into AX.
-MOVQ	g_m(AX), BX   // Move g.m into BX.
+MOVQ	g_m(AX), BX   // Move g->m into BX.
 </pre>
 
 <h3 id="arm">ARM</h3>
@@ -663,107 +509,6 @@ The name <code>SP</code> always refers to the virtual stack pointer described ea
 For the hardware register, use <code>R13</code>.
 </p>
 
-<p>
-Condition code syntax is to append a period and the one- or two-letter code to the instruction,
-as in <code>MOVW.EQ</code>.
-Multiple codes may be appended: <code>MOVM.IA.W</code>.
-The order of the code modifiers is irrelevant.
-</p>
-
-<p>
-Addressing modes:
-</p>
-
-<ul>
-
-<li>
-<code>R0->16</code>
-<br>
-<code>R0>>16</code>
-<br>
-<code>R0<<16</code>
-<br>
-<code>R0@>16</code>:
-For <code><<</code>, left shift <code>R0</code> by 16 bits.
-The other codes are <code>-></code> (arithmetic right shift),
-<code>>></code> (logical right shift), and
-<code>@></code> (rotate right).
-</li>
-
-<li>
-<code>R0->R1</code>
-<br>
-<code>R0>>R1</code>
-<br>
-<code>R0<<R1</code>
-<br>
-<code>R0@>R1</code>:
-For <code><<</code>, left shift <code>R0</code> by the count in <code>R1</code>.
-The other codes are <code>-></code> (arithmetic right shift),
-<code>>></code> (logical right shift), and
-<code>@></code> (rotate right).
-
-</li>
-
-<li>
-<code>[R0,g,R12-R15]</code>: For multi-register instructions, the set comprising
-<code>R0</code>, <code>g</code>, and <code>R12</code> through <code>R15</code> inclusive.
-</li>
-
-<li>
-<code>(R5, R6)</code>: Destination register pair.
-</li>
-
-</ul>
-
-<h3 id="arm64">ARM64</h3>
-
-<p>
-The ARM64 port is in an experimental state.
-</p>
-
-<p>
-Instruction modifiers are appended to the instruction following a period.
-The only modifiers are <code>P</code> (postincrement) and <code>W</code>
-(preincrement):
-<code>MOVW.P</code>, <code>MOVW.W</code>
-</p>
-
-<p>
-Addressing modes:
-</p>
-
-<ul>
-
-<li>
-<code>(R5, R6)</code>: Register pair for <code>LDP</code>/<code>STP</code>.
-</li>
-
-</ul>
-
-<h3 id="ppc64">64-bit PowerPC, a.k.a. ppc64</h3>
-
-<p>
-The 64-bit PowerPC port is in an experimental state.
-</p>
-
-<p>
-Addressing modes:
-</p>
-
-<ul>
-
-<li>
-<code>(R5)(R6*1)</code>: The location at <code>R5</code> plus <code>R6</code>. It is a scaled
-mode as on the x86, but the only scale allowed is <code>1</code>.
-</li>
-
-<li>
-<code>(R5+R6)</code>: Alias for (R5)(R6*1)
-</li>
-
-</ul>
-
 <h3 id="unsupported_opcodes">Unsupported opcodes</h3>
 
 <p>
@@ -782,17 +527,11 @@ Here's how the 386 runtime defines the 64-bit atomic load function.
 // uint64 atomicload64(uint64 volatile* addr);
 // so actually
 // void atomicload64(uint64 *res, uint64 volatile *addr);
-TEXT runtime·atomicload64(SB), NOSPLIT, $0-12
+TEXT runtime·atomicload64(SB), NOSPLIT, $0-8
 	MOVL	ptr+0(FP), AX
-	TESTL	$7, AX
-	JZ	2(PC)
-	MOVL	0, AX // crash with nil ptr deref
 	LEAL	ret_lo+4(FP), BX
-	// MOVQ (%EAX), %MM0
-	BYTE $0x0f; BYTE $0x6f; BYTE $0x00
-	// MOVQ %MM0, 0(%EBX)
-	BYTE $0x0f; BYTE $0x7f; BYTE $0x03
-	// EMMS
-	BYTE $0x0F; BYTE $0x77
+	BYTE $0x0f; BYTE $0x6f; BYTE $0x00	// MOVQ (%EAX), %MM0
+	BYTE $0x0f; BYTE $0x7f; BYTE $0x03	// MOVQ %MM0, 0(%EBX)
+	BYTE $0x0F; BYTE $0x77			// EMMS
 	RET
 </pre>
diff --git a/doc/code.html b/doc/code.html
index 8cbfba0..a4638f9 100644
--- a/doc/code.html
+++ b/doc/code.html
@@ -108,14 +108,13 @@ when developing Go code.
 <p>
 To get started, create a workspace directory and set <code>GOPATH</code>
 accordingly. Your workspace can be located wherever you like, but we'll use
-<code>$HOME/work</code> in this document. Note that this must <b>not</b> be the
+<code>$HOME/go</code> in this document. Note that this must <b>not</b> be the
 same path as your Go installation.
-(Another common setup is to set <code>GOPATH=$HOME</code>.)
 </p>
 
 <pre>
-$ <b>mkdir $HOME/work</b>
-$ <b>export GOPATH=$HOME/work</b>
+$ <b>mkdir $HOME/go</b>
+$ <b>export GOPATH=$HOME/go</b>
 </pre>
 
 <p>
@@ -127,11 +126,6 @@ to your <code>PATH</code>:
 $ <b>export PATH=$PATH:$GOPATH/bin</b>
 </pre>
 
-<p>
-To learn more about setting up the <code>GOPATH</code> environment variable,
-please see
-<a href="/cmd/go/#hdr-GOPATH_environment_variable"><code>go help gopath</code></a>
-</p>
 
 <h3 id="PackagePaths">Package paths</h3>
 
@@ -224,7 +218,7 @@ This command builds the <code>hello</code> command, producing an executable
 binary. It then installs that binary to the workspace's <code>bin</code>
 directory as <code>hello</code> (or, under Windows, <code>hello.exe</code>).
 In our example, that will be <code>$GOPATH/bin/hello</code>, which is
-<code>$HOME/work/bin/hello</code>.
+<code>$HOME/go/bin/hello</code>.
 </p>
 
 <p>
@@ -260,7 +254,7 @@ optional: you do not need to use source control to write Go code.
 <pre>
 $ <b>cd $GOPATH/src/github.com/user/hello</b>
 $ <b>git init</b>
-Initialized empty Git repository in /home/user/work/src/github.com/user/hello/.git/
+Initialized empty Git repository in /home/user/go/src/github.com/user/hello/.git/
 $ <b>git add hello.go</b>
 $ <b>git commit -m "initial commit"</b>
 [master (root-commit) 0b4507d] initial commit
diff --git a/doc/contrib.html b/doc/contrib.html
index 4839035..93a609f 100644
--- a/doc/contrib.html
+++ b/doc/contrib.html
@@ -34,7 +34,6 @@ We encourage all Go users to subscribe to
 <p>A <a href="/doc/devel/release.html">summary</a> of the changes between Go releases. Notes for the major releases:</p>
 
 <ul>
-	<li><a href="/doc/go1.5">Go 1.5</a> <small>(August 2015)</small></li>
 	<li><a href="/doc/go1.4">Go 1.4</a> <small>(December 2014)</small></li>
 	<li><a href="/doc/go1.3">Go 1.3</a> <small>(June 2014)</small></li>
 	<li><a href="/doc/go1.2">Go 1.2</a> <small>(December 2013)</small></li>
@@ -92,10 +91,6 @@ a new one.)
 We pride ourselves on being meticulous; no issue is too small.
 </p>
 
-<p>
-Sensitive security-related issues should be reported to <a href="mailto:security at golang.org">security at golang.org</a>.
-</p>
-
 <h3><a href="/doc/contribute.html">Contributing code</a></h3>
 
 <p>
diff --git a/doc/contribute.html b/doc/contribute.html
index 45ed8f1..63d4774 100644
--- a/doc/contribute.html
+++ b/doc/contribute.html
@@ -20,32 +20,23 @@ see <a href="gccgo_contribute.html">Contributing to gccgo</a>.)
 
 <p>
 The project welcomes submissions but please let everyone know what
-you're working on if you want to change or add to the Go repositories.
+you're working on if you want it to become part of the main repository.
 </p>
 
 <p>
-Before undertaking to write something new for the Go project,
-please <a href="https://golang.org/issue/new">file an issue</a>
-(or claim an <a href="https://golang.org/issues">existing issue</a>).
-Significant changes must go through the
-<a href="https://golang.org/s/proposal-process">change proposal process</a>
-before they can be accepted.
+Before undertaking to write something new for the Go project, send
+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
+and tools.  It also guarantees that the design is sound before code
+is written; the code review tool is not the place for high-level
+discussions.
 </p>
 
 <p>
-This process 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 and tools.
-It also checks that the design is sound before code is written;
-the code review tool is not the place for high-level discussions.
-</p>
-
-<p>
-When planning work, please note that the Go project follows a
-<a href="https://golang.org/wiki/Go-Release-Cycle">six-month
-development cycle</a>. The latter half of each cycle is a three-month
-feature freeze during which only bug fixes and doc updates are accepted.
-New work cannot be submitted during a feature freeze.
+In short, send mail before you code.
+And don't start the discussion by mailing a change list!
 </p>
 
 <h2 id="Testing">Testing redux</h2>
@@ -73,8 +64,10 @@ After running for a while, the command should print
 <h2 id="Code_review">Code review</h2>
 
 <p>
-Changes to Go must be reviewed before they are accepted,
+Changes to Go must be reviewed before they are submitted,
 no matter who makes the change.
+(In exceptional cases, such as fixing a build, the review can
+follow shortly after submitting.)
 A custom git command called <code>git-codereview</code>,
 discussed below, helps manage the code review process through a Google-hosted
 <a href="https://go-review.googlesource.com/">instance</a> of the code review
@@ -84,89 +77,52 @@ system called <a href="https://code.google.com/p/gerrit/">Gerrit</a>.
 <h3>Set up authentication for code review</h3>
 
 <p>
-Gerrit uses Google Accounts for authentication. If you don't have
-a Google Account, you can create an account which
-<a href="https://www.google.com/accounts/NewAccount">includes
-a new Gmail email account</a> or create an account associated
-<a href="https://accounts.google.com/SignUpWithoutGmail">with your existing
-email address</a>.
+The Git code hosting server and Gerrit code review server both use a Google
+Account to authenticate. You therefore need a Google Account to proceed.
+(If you can use the account to
+<a href="https://www.google.com/accounts/Login">sign in at google.com</a>,
+you can use it to sign in to the code review server.)
+The email address you use with the code review system
+will be recorded in the <a href="https://go.googlesource.com/go">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.
 </p>
 
 <p>
-The email address associated with the Google Account you use will be recorded in
-the <a href="https://go.googlesource.com/go/+log/">change log</a>
-and in the <a href="/CONTRIBUTORS">contributors file</a>.
+Visit the site <a href="https://go.googlesource.com">go.googlesource.com</a>
+and log in using your Google Account.
+Click on the "Generate Password" link that appears at the top of the page.
 </p>
 
 <p>
-To set up your account in Gerrit, visit
-<a href="https://go.googlesource.com">go.googlesource.com</a>
-and click on "Generate Password" in the page's top right menu bar.
+Click the radio button that says "Only <code>go.googlesource.com</code>"
+to use this authentication token only for the Go project.
 </p>
 
 <p>
-You will be redirected to accounts.google.com to sign in.
+Further down the page is a box containing commands to install
+the authentication cookie in file called <code>.gitcookies</code> in your home
+directory.
+Copy the text for the commands into a Unix shell window to execute it.
+That will install the authentication token.
 </p>
 
 <p>
-Once signed in, you are returned back to go.googlesource.com to "Configure Git".
-Follow the instructions on the page.
 (If you are on a Windows computer, you should instead follow the instructions
 in the yellow box to run the command.)
 </p>
 
-<p>
-Your secret authentication token is now in a <code>.gitcookie</code> file
-and Git is configured to use this file.
-</p>
-
 <h3>Register with Gerrit</h3>
 
 <p>
-Now that you have your authentication token,
-you need to register your account with Gerrit.
-To do this, visit
-<a href="https://go-review.googlesource.com/login/">
-go-review.googlesource.com/login/</a>. You will immediately be redirected
-to Google Accounts. Sign in using the same Google Account you used above.
+Now that you have a Google account and the authentication token,
+you need to register your account with Gerrit, the code review system.
+To do this, visit <a href="https://golang.org/cl">golang.org/cl</a>
+and log in using the same Google Account you used above.
 That is all that is required.
 </p>
 
-<h3>Contributor License Agreement</h3>
-
-<p>Gerrit serves as the gatekeeper and uses your e-mail address as the key.
-To send your first change to the Go project from a given address,
-you must 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="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="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.)
-</li>
-</ul>
-
-<p>
-You can use the links above to create and sign the contributor license agreement
-or you can show your current agreements and create new ones through the Gerrit
-interface.  <a href="https://go-review.googlesource.com/login/">Log into Gerrit</a>,
-click your name in the upper-right, choose "Settings", then select "Agreements"
-from the topics on the left. If you do not have a signed agreement listed here,
-you can create one by clicking "New Contributor Agreement" and following the steps.
-</p>
-
-<p>
-This rigmarole only needs to be done for your first submission for each email address.
-</p>
-
 <h3>Install the git-codereview command</h3>
 
 <p>
@@ -174,7 +130,7 @@ Now install the <code>git-codereview</code> command by running,
 </p>
 
 <pre>
-$ go get -u golang.org/x/review/git-codereview
+go get -u golang.org/x/review/git-codereview
 </pre>
 
 <p>
@@ -430,8 +386,7 @@ Unless explicitly told otherwise, such as in the discussion leading
 up to sending in the change list, it's better not to specify a reviewer.
 All changes are automatically CC'ed to the
 <a href="https://groups.google.com/group/golang-codereviews">golang-codereviews at googlegroups.com</a>
-mailing list. If this is your first ever change, there may be a moderation
-delay before it appears on the mailing list, to prevent spam.
+mailing list.
 </p>
 
 <p>
@@ -527,7 +482,7 @@ $ git sync
 Failed to merge in the changes.
 Patch failed at 0023 math: improved Sin, Cos and Tan precision for very large arguments
 The copy of the patch that failed is found in:
-   /home/you/repo/.git/rebase-apply/patch
+   /home/you/repo/.git/rebase-apply/patch
 
 When you have resolved this problem, run "git rebase --continue".
 If you prefer to skip this patch, run "git rebase --skip" instead.
@@ -550,15 +505,15 @@ The output will look something like this:
 <pre>
 rebase in progress; onto a24c3eb
 You are currently rebasing branch 'mcgillicutty' on 'a24c3eb'.
-  (fix conflicts and then run "git rebase --continue")
-  (use "git rebase --skip" to skip this patch)
-  (use "git rebase --abort" to check out the original branch)
+  (fix conflicts and then run "git rebase --continue")
+  (use "git rebase --skip" to skip this patch)
+  (use "git rebase --abort" to check out the original branch)
 
 Unmerged paths:
-  (use "git reset HEAD <file>..." to unstage)
-  (use "git add <file>..." to mark resolution)
+  (use "git reset HEAD <file>..." to unstage)
+  (use "git add <file>..." to mark resolution)
 
-	<i>both modified: sin.go</i>
+	<i>both modified:   sin.go</i>
 </pre>
 
 <p>
@@ -575,9 +530,9 @@ might turn up:
 <pre>
 	arg = scale(arg)
 <<<<<<< HEAD
-	if arg < 1e9 {
+	if arg > 1e9 {
 =======
-	if arg &lh; 1e10 {
+	if arg > 1e10 {
 >>>>>>> mcgillicutty
 		largeReduce(arg)
 </pre>
@@ -591,7 +546,7 @@ to remove the markers and leave the correct code:
 
 <pre>
 	arg = scale(arg)
-	if arg < 1e10 {
+	if arg > 1e10 {
 		largeReduce(arg)
 </pre>
 
@@ -622,7 +577,7 @@ It should look something like this:
 </p>
 
 <pre>
-$ git fetch https://go.googlesource.com/review refs/changes/21/1221/1 && git checkout FETCH_HEAD
+$ git fetch https://go.googlesource.com/review refs/changes/21/1221/1 && git checkout FETCH_HEAD
 </pre>
 
 <p>
@@ -669,7 +624,30 @@ and perhaps the <a href="/AUTHORS"><code>AUTHORS</code></a> file.
 defines who the Go contributors—the people—are;
 the <a href="/AUTHORS"><code>AUTHORS</code></a> file defines
 who “The Go Authors”—the copyright holders—are.
-These files will be periodically updated based on the commit logs.
+The Go developers at Google will update these files when submitting
+your first change.
+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="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="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.)
+</li>
+</ul>
+
+<p>
+This rigmarole needs to be done only for your first submission.
+</p>
 
 <p>Code that you contribute should use the standard copyright header:</p>
 
diff --git a/doc/devel/release.html b/doc/devel/release.html
index 7d72c8d..5a1a747 100644
--- a/doc/devel/release.html
+++ b/doc/devel/release.html
@@ -8,17 +8,10 @@ The <a href="//golang.org/change">change log</a> has the full details.</p>
 <p>To update to a specific release, use:</p>
 
 <pre>
-git pull
-git checkout <i>release-branch</i>
+hg pull
+hg update <i>tag</i>
 </pre>
 
-<h2 id="go1.5">go1.5 (released 2015/08/19)</h2>
-
-<p>
-Go 1.5 is a major release of Go.
-Read the <a href="/doc/go1.5">Go 1.5 Release Notes</a> for more information.
-</p>
-
 <h2 id="go1.4">go1.4 (released 2014/12/10)</h2>
 
 <p>
@@ -152,10 +145,449 @@ go1.0.3 (released 2012/09/21) includes minor code and documentation fixes.
 See the <a href="//code.google.com/p/go/source/list?name=release-branch.go1">go1 release branch history</a> for the complete list of changes.
 </p>
 
-<h2 id="pre.go1">Older releases</h2>
+<h2 id="r60">r60 (released 2011/09/07)</h2>
+
+<p>
+The r60 release corresponds to 
+<code><a href="weekly.html#2011-08-17">weekly.2011-08-17</a></code>.
+This section highlights the most significant changes in this release.
+For a more detailed summary, see the
+<a href="weekly.html#2011-08-17">weekly release notes</a>.
+For complete information, see the
+<a href="//code.google.com/p/go/source/list?r=release-branch.r60">Mercurial change list</a>.
+</p>
+
+<h3 id="r60.lang">Language</h3>
+
+<p>
+An "else" block is now required to have braces except if the body of the "else"
+is another "if". Since gofmt always puts those braces in anyway,
+gofmt-formatted programs will not be affected.
+To fix other programs, run gofmt.
+</p>
+
+<h3 id="r60.pkg">Packages</h3>
+
+<p>
+<a href="/pkg/http/">Package http</a>'s URL parsing and query escaping code
+(such as <code>ParseURL</code> and <code>URLEscape</code>) has been moved to
+the new <a href="/pkg/url/">url package</a>, with several simplifications to
+the names. Client code can be updated automatically with gofix.
+</p>
+
+<p>
+<a href="/pkg/image/">Package image</a> has had significant changes made to the
+<code>Pix</code> field of struct types such as
+<a href="/pkg/image/#RGBA">image.RGBA</a> and
+<a href="/pkg/image/#NRGBA">image.NRGBA</a>.
+The <a href="/pkg/image/#Image">image.Image</a> interface type has not changed,
+though, and you should not need to change your code if you don't explicitly
+refer to <code>Pix</code> fields. For example, if you decode a number of images
+using the <a href="/pkg/image/jpeg/">image/jpeg</a> package, compose them using
+<a href="/pkg/image/draw/">image/draw</a>, and then encode the result using
+<a href="/pkg/img/png">image/png</a>, then your code should still work as
+before.
+If your code <i>does</i> refer to <code>Pix</code> fields see the 
+<a href="/doc/devel/weekly.html#2011-07-19">weekly.2011-07-19</a>
+snapshot notes for how to update your code.
+</p>
+
+<p>
+<a href="/pkg/template/">Package template</a> has been replaced with a new
+templating package (formerly <code>exp/template</code>). The original template
+package is still available as <a href="/pkg/old/template/">old/template</a>.
+The <code>old/template</code> package is deprecated and will be removed.
+The Go tree has been updated to use the new template package. We encourage
+users of the old template package to switch to the new one. Code that uses
+<code>template</code> or <code>exp/template</code> will need to change its
+import lines to <code>"old/template"</code> or <code>"template"</code>,
+respectively.
+</p>
+
+<h3 id="r60.cmd">Tools</h3>
+
+<p>
+<a href="/cmd/goinstall/">Goinstall</a> now uses a new tag selection scheme.
+When downloading or updating, goinstall looks for a tag or branch with the
+<code>"go."</code> prefix that corresponds to the local Go version. For Go
+<code>release.r58</code> it looks for <code>go.r58</code>. For
+<code>weekly.2011-06-03</code> it looks for <code>go.weekly.2011-06-03</code>.
+If the specific <code>go.X</code> tag or branch is not found, it chooses the
+closest earlier version. If an appropriate tag or branch is found, goinstall
+uses that version of the code. Otherwise it uses the default version selected
+by the version control system. Library authors are encouraged to use the
+appropriate tag or branch names in their repositories to make their libraries
+more accessible.
+</p>
+
+<h3 id="r60.minor">Minor revisions</h3>
+
+<p>
+r60.1 includes a 
+<a href="//golang.org/change/1824581bf62d">linker
+fix</a>, a pair of
+<a href="//golang.org/change/9ef4429c2c64">goplay</a>
+<a href="//golang.org/change/d42ed8c3098e">fixes</a>,
+and a <code>json</code> package
+<a href="//golang.org/change/d5e97874fe84">fix</a> and
+a new
+<a href="//golang.org/change/4f0e6269213f">struct tag
+option</a>.
+</p>
+
+<p>
+r60.2
+<a href="//golang.org/change/ff19536042ac">fixes</a>
+a memory leak involving maps.
+</p>
+
+<p>
+r60.3 fixes a
+<a href="//golang.org/change/01fa62f5e4e5">reflect bug</a>.
+</p>
+
+<h2 id="r59">r59 (released 2011/08/01)</h2>
+
+<p>
+The r59 release corresponds to 
+<code><a href="weekly.html#2011-07-07">weekly.2011-07-07</a></code>.
+This section highlights the most significant changes in this release.
+For a more detailed summary, see the
+<a href="weekly.html#2011-07-07">weekly release notes</a>.
+For complete information, see the
+<a href="//code.google.com/p/go/source/list?r=release-branch.r59">Mercurial change list</a>.
+</p>
+
+<h3 id="r59.lang">Language</h3>
+
+<p>
+This release includes a language change that restricts the use of
+<code>goto</code>.  In essence, a <code>goto</code> statement outside a block
+cannot jump to a label inside that block. Your code may require changes if it
+uses <code>goto</code>.
+See <a href="//golang.org/change/dc6d3cf9279d">this
+changeset</a> for how the new rule affected the Go tree.
+</p>
+
+<h3 id="r59.pkg">Packages</h3>
+
+<p>
+As usual, <a href="/cmd/gofix/">gofix</a> will handle the bulk of the rewrites
+necessary for these changes to package APIs.
+</p>
+
+<p>
+<a href="/pkg/http">Package http</a> has a new
+<a href="/pkg/http/#FileSystem">FileSystem</a> interface that provides access
+to files. The <a href="/pkg/http/#FileServer">FileServer</a> helper now takes a
+<code>FileSystem</code> argument instead of an explicit file system root. By
+implementing your own <code>FileSystem</code> you can use the
+<code>FileServer</code> to serve arbitrary data.
+</p>
+
+<p>
+<a href="/pkg/os/">Package os</a>'s <code>ErrorString</code> type has been
+hidden. Most uses of <code>os.ErrorString</code> can be replaced with
+<a href="/pkg/os/#NewError">os.NewError</a>.
+</p>
+
+<p>
+<a href="/pkg/reflect/">Package reflect</a> supports a new struct tag scheme
+that enables sharing of struct tags between multiple packages.
+In this scheme, the tags must be of the form:
+</p>
+<pre>
+	`key:"value" key2:"value2"`
+</pre>
+<p>
+The <a href="/pkg/reflect/#StructField">StructField</a> type's Tag field now
+has type <a href="/pkg/reflect/#StructTag">StructTag</a>, which has a
+<code>Get</code> method. Clients of <a href="/pkg/json">json</a> and
+<a href="/pkg/xml">xml</a> will need to be updated. Code that says
+</p>
+<pre>
+	type T struct {
+		X int "name"
+	}
+</pre>
+<p>
+should become
+</p>
+<pre>
+	type T struct {
+		X int `json:"name"`  // or `xml:"name"`
+	}
+</pre>
+<p>
+Use <a href="/cmd/govet/">govet</a> to identify struct tags that need to be
+changed to use the new syntax.
+</p>
+
+<p>
+<a href="/pkg/sort/">Package sort</a>'s <code>IntArray</code> type has been
+renamed to <a href="/pkg/sort/#IntSlice">IntSlice</a>, and similarly for
+<a href="/pkg/sort/#Float64Slice">Float64Slice</a> and
+<a href="/pkg/sort/#StringSlice">StringSlice</a>.
+</p>
+
+<p>
+<a href="/pkg/strings/">Package strings</a>'s <code>Split</code> function has
+itself been split into <a href="/pkg/strings/#Split">Split</a> and
+<a href="/pkg/strings/#SplitN">SplitN</a>.
+<code>SplitN</code> is the same as the old <code>Split</code>.
+The new <code>Split</code> is equivalent to <code>SplitN</code> with a final
+argument of -1.
+</p>
+
+<a href="/pkg/image/draw/">Package image/draw</a>'s
+<a href="/pkg/image/draw/#Draw">Draw</a> function now takes an additional
+argument, a compositing operator.
+If in doubt, use <a href="/pkg/image/draw/#Op">draw.Over</a>.
+</p>
+
+<h3 id="r59.cmd">Tools</h3>
+
+<p>
+<a href="/cmd/goinstall/">Goinstall</a> now installs packages and commands from
+arbitrary remote repositories (not just Google Code, Github, and so on).
+See the <a href="/cmd/goinstall/">goinstall documentation</a> for details.
+</p>
+
+<h2 id="r58">r58 (released 2011/06/29)</h2>
 
 <p>
-See the <a href="pre_go1.html">Pre-Go 1 Release History</a> page for notes
-on earlier releases.
+The r58 release corresponds to 
+<code><a href="weekly.html#2011-06-09">weekly.2011-06-09</a></code>
+with additional bug fixes.
+This section highlights the most significant changes in this release.
+For a more detailed summary, see the
+<a href="weekly.html#2011-06-09">weekly release notes</a>.
+For complete information, see the
+<a href="//code.google.com/p/go/source/list?r=release-branch.r58">Mercurial change list</a>.
 </p>
 
+<h3 id="r58.lang">Language</h3>
+
+<p>
+This release fixes a <a href="//golang.org/change/b720749486e1">use of uninitialized memory in programs that misuse <code>goto</code></a>.
+</p>
+
+<h3 id="r58.pkg">Packages</h3>
+
+<p>
+As usual, <a href="/cmd/gofix/">gofix</a> will handle the bulk of the rewrites
+necessary for these changes to package APIs.
+</p>
+
+<p>
+<a href="/pkg/http/">Package http</a> drops the <code>finalURL</code> return
+value from the <a href="/pkg/http/#Client.Get">Client.Get</a> method. The value
+is now available via the new <code>Request</code> field on <a
+href="/pkg/http/#Response">http.Response</a>.
+Most instances of the type map[string][]string in have been
+replaced with the new <a href="/pkg/http/#Values">Values</a> type.
+</p>
+
+<p>
+<a href="/pkg/exec/">Package exec</a> has been redesigned with a more
+convenient and succinct API.
+</p>
+
+<p>
+<a href="/pkg/strconv/">Package strconv</a>'s <a href="/pkg/strconv/#Quote">Quote</a>
+function now escapes only those Unicode code points not classified as printable
+by <a href="/pkg/unicode/#IsPrint">unicode.IsPrint</a>.
+Previously Quote would escape all non-ASCII characters.
+This also affects the <a href="/pkg/fmt/">fmt</a> package's <code>"%q"</code>
+formatting directive. The previous quoting behavior is still available via
+strconv's new <a href="/pkg/strconv/#QuoteToASCII">QuoteToASCII</a> function.   
+</p>
+
+<p>
+<a href="/pkg/os/signal/">Package os/signal</a>'s
+<a href="/pkg/os/#Signal">Signal</a> and 
+<a href="/pkg/os/#UnixSignal">UnixSignal</a> types have been moved to the
+<a href="/pkg/os/">os</a> package.
+</p>
+
+<p>
+<a href="/pkg/image/draw/">Package image/draw</a> is the new name for
+<code>exp/draw</code>. The GUI-related code from <code>exp/draw</code> is now
+located in the <a href="/pkg/exp/gui/">exp/gui</a> package.
+</p>
+
+<h3 id="r58.cmd">Tools</h3>
+
+<p>
+<a href="/cmd/goinstall/">Goinstall</a> now observes the GOPATH environment
+variable to build and install your own code and external libraries outside of
+the Go tree (and avoid writing Makefiles).
+</p>
+
+
+<h3 id="r58.minor">Minor revisions</h3>
+
+<p>r58.1 adds 
+<a href="//golang.org/change/293c25943586">build</a> and
+<a href="//golang.org/change/bf17e96b6582">runtime</a>
+changes to make Go run on OS X 10.7 Lion.
+</p>
+
+<h2 id="r57">r57 (released 2011/05/03)</h2>
+
+<p>
+The r57 release corresponds to 
+<code><a href="weekly.html#2011-04-27">weekly.2011-04-27</a></code>
+with additional bug fixes.
+This section highlights the most significant changes in this release.
+For a more detailed summary, see the
+<a href="weekly.html#2011-04-27">weekly release notes</a>.
+For complete information, see the
+<a href="//code.google.com/p/go/source/list?r=release-branch.r57">Mercurial change list</a>.
+</p>
+
+<p>The new <a href="/cmd/gofix">gofix</a> tool finds Go programs that use old APIs and rewrites them to use
+newer ones.  After you update to a new Go release, gofix helps make the
+necessary changes to your programs. Gofix will handle the http, os, and syscall
+package changes described below, and we will update the program to keep up with
+future changes to the libraries. 
+Gofix can’t
+handle all situations perfectly, so read and test the changes it makes before
+committing them.
+See <a href="//blog.golang.org/2011/04/introducing-gofix.html">the gofix blog post</a> for more
+information.</p>
+
+<h3 id="r57.lang">Language</h3>
+
+<p>
+<a href="/doc/go_spec.html#Receive_operator">Multiple assignment syntax</a> replaces the <code>closed</code> function.
+The syntax for channel
+receives allows an optional second assigned value, a boolean value
+indicating whether the channel is closed. This code:
+</p>
+
+<pre>
+	v := <-ch
+	if closed(ch) {
+		// channel is closed
+	}
+</pre>
+
+<p>should now be written as:</p>
+
+<pre>
+	v, ok := <-ch
+	if !ok {
+		// channel is closed
+	}
+</pre>
+
+<p><a href="/doc/go_spec.html#Label_scopes">Unused labels are now illegal</a>, just as unused local variables are.</p>
+
+<h3 id="r57.pkg">Packages</h3>
+
+<p>
+<a href="/pkg/gob/">Package gob</a> will now encode and decode values of types that implement the
+<a href="/pkg/gob/#GobEncoder">GobEncoder</a> and
+<a href="/pkg/gob/#GobDecoder">GobDecoder</a> interfaces. This allows types with unexported
+fields to transmit self-consistent descriptions; examples include 
+<a href="/pkg/big/#Int.GobDecode">big.Int</a> and <a href="/pkg/big/#Rat.GobDecode">big.Rat</a>.
+</p>
+
+<p>
+<a href="/pkg/http/">Package http</a> has been redesigned.
+For clients, there are new
+<a href="/pkg/http/#Client">Client</a> and <a href="/pkg/http/#Transport">Transport</a>
+abstractions that give more control over HTTP details such as headers sent
+and redirections followed.  These abstractions make it easy to implement
+custom clients that add functionality such as <a href="//code.google.com/p/goauth2/source/browse/oauth/oauth.go">OAuth2</a>.
+For servers, <a href="/pkg/http/#ResponseWriter">ResponseWriter</a>
+has dropped its non-essential methods.
+The Hijack and Flush methods are no longer required;
+code can test for them by checking whether a specific value implements
+<a href="/pkg/http/#Hijacker">Hijacker</a> or <a href="/pkg/http/#Flusher">Flusher</a>.
+The RemoteAddr and UsingTLS methods are replaced by <a href="/pkg/http/#Request">Request</a>'s
+RemoteAddr and TLS fields.
+The SetHeader method is replaced by a Header method;
+its result, of type <a href="/pkg/http/#Header">Header</a>,
+implements Set and other methods.
+</p>
+
+<p>
+<a href="/pkg/net/">Package net</a>
+drops the <code>laddr</code> argument from <a href="/pkg/net/#Conn.Dial">Dial</a>
+and drops the <code>cname</code> return value
+from <a href="/pkg/net/#LookupHost">LookupHost</a>.
+The implementation now uses <a href="/cmd/cgo/">cgo</a> to implement
+network name lookups using the C library getaddrinfo(3)
+function when possible.  This ensures that Go and C programs
+resolve names the same way and also avoids the OS X 
+application-level firewall.
+</p>
+
+<p>
+<a href="/pkg/os/">Package os</a>
+introduces simplified <a href="/pkg/os/#File.Open">Open</a>
+and <a href="/pkg/os/#File.Create">Create</a> functions.
+The original Open is now available as <a href="/pkg/os/#File.OpenFile">OpenFile</a>.
+The final three arguments to <a href="/pkg/os/#Process.StartProcess">StartProcess</a>
+have been replaced by a pointer to a <a href="/pkg/os/#ProcAttr">ProcAttr</a>.
+</p>
+
+<p>
+<a href="/pkg/reflect/">Package reflect</a> has been redesigned.
+<a href="/pkg/reflect/#Type">Type</a> is now an interface that implements
+all the possible type methods.
+Instead of a type switch on a Type <code>t</code>, switch on <code>t.Kind()</code>.
+<a href="/pkg/reflect/#Value">Value</a> is now a struct value that
+implements all the possible value methods.
+Instead of a type switch on a Value <code>v</code>, switch on <code>v.Kind()</code>.
+Typeof and NewValue are now called <a href="/pkg/reflect/#Type.TypeOf">TypeOf</a> and <a href="/pkg/reflect/#Value.ValueOf">ValueOf</a>
+To create a writable Value, use <code>New(t).Elem()</code> instead of <code>Zero(t)</code>.
+See <a href="//golang.org/change/843855f3c026">the change description</a>
+for the full details.
+The new API allows a more efficient implementation of Value
+that avoids many of the allocations required by the previous API.
+</p>
+
+<p>
+Remember that gofix will handle the bulk of the rewrites
+necessary for these changes to package APIs.
+</p>
+
+<h3 id="r57.cmd">Tools</h3>
+
+<p><a href="/cmd/gofix/">Gofix</a>, a new command, is described above.</p>
+
+<p>
+<a href="/cmd/gotest/">Gotest</a> is now a Go program instead of a shell script.
+The new <code>-test.short</code> flag in combination with package testing's Short function
+allows you to write tests that can be run in normal or “short” mode;
+all.bash runs tests in short mode to reduce installation time.
+The Makefiles know about the flag: use <code>make testshort</code>.
+</p>
+
+<p>
+The run-time support now implements CPU and memory profiling.
+Gotest's new 
+<a href="/cmd/gotest/"><code>-test.cpuprofile</code> and
+<code>-test.memprofile</code> flags</a> make it easy to
+profile tests.
+To add profiling to your web server, see the <a href="/pkg/http/pprof/">http/pprof</a>
+documentation.
+For other uses, see the <a href="/pkg/runtime/pprof/">runtime/pprof</a> documentation.
+</p>
+
+<h3 id="r57.minor">Minor revisions</h3>
+
+<p>r57.1 fixes a <a href="//golang.org/change/ff2bc62726e7145eb2ecc1e0f076998e4a8f86f0">nil pointer dereference in http.FormFile</a>.</p>
+<p>r57.2 fixes a <a href="//golang.org/change/063b0ff67d8277df03c956208abc068076818dae">use of uninitialized memory in programs that misuse <code>goto</code></a>.</p>
+
+<h2 id="r56">r56 (released 2011/03/16)</h2>
+
+<p>
+The r56 release was the first stable release and corresponds to
+<code><a href="weekly.html#2011-03-07">weekly.2011-03-07.1</a></code>.
+The numbering starts at 56 because before this release,
+what we now consider weekly snapshots were called releases.
+</p>
diff --git a/doc/devel/weekly.html b/doc/devel/weekly.html
index 143727f..5a9c51e 100644
--- a/doc/devel/weekly.html
+++ b/doc/devel/weekly.html
@@ -5971,7 +5971,7 @@ You can now check build status on various platforms at the Go Dashboard:
 * runtime: add SetFinalizer
 * time: Sleep through interruptions (thanks Chris Wedgwood)
 	add RFC822 formats
-	experimental implementation of Ticker using two goroutines for all tickers
+	experimental implemenation of Ticker using two goroutines for all tickers
 * xml: allow underscores in XML element names (thanks Michael Hoisie)
 	allow any scalar type in xml.Unmarshal
 </pre>
diff --git a/doc/effective_go.html b/doc/effective_go.html
index 5a522f6..4dd1a3e 100644
--- a/doc/effective_go.html
+++ b/doc/effective_go.html
@@ -866,7 +866,7 @@ var t interface{}
 t = functionOfSomeType()
 switch t := t.(type) {
 default:
-    fmt.Printf("unexpected type %T\n", t)     // %T prints whatever type t has
+    fmt.Printf("unexpected type %T", t)       // %T prints whatever type t has
 case bool:
     fmt.Printf("boolean %t\n", t)             // t has type bool
 case int:
@@ -1382,7 +1382,7 @@ limit of how much data to read.  Here is the signature of the
 <code>os</code>:
 </p>
 <pre>
-func (f *File) Read(buf []byte) (n int, err error)
+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
@@ -1421,7 +1421,7 @@ resulting slice is returned.  The function uses the fact that
 <code>nil</code> slice, and return 0.
 </p>
 <pre>
-func Append(slice, data []byte) []byte {
+func Append(slice, data[]byte) []byte {
     l := len(slice)
     if l + len(data) > cap(slice) {  // reallocate
         // Allocate double what's needed, for future growth.
@@ -3054,7 +3054,7 @@ req := req
 </pre>
 
 <p>
-but it's legal and idiomatic in Go to do this.
+but it's a legal and idiomatic in Go to do this.
 You get a fresh version of the variable with the same name, deliberately
 shadowing the loop variable locally but unique to each goroutine.
 </p>
@@ -3172,44 +3172,40 @@ count the completion signals by draining the channel after
 launching all the goroutines.
 </p>
 <pre>
-const numCPU = 4 // number of CPU cores
+const NCPU = 4  // number of CPU cores
 
 func (v Vector) DoAll(u Vector) {
-    c := make(chan int, numCPU)  // Buffering optional but sensible.
-    for i := 0; i < numCPU; i++ {
-        go v.DoSome(i*len(v)/numCPU, (i+1)*len(v)/numCPU, u, c)
+    c := make(chan int, NCPU)  // Buffering optional but sensible.
+    for i := 0; i < NCPU; i++ {
+        go v.DoSome(i*len(v)/NCPU, (i+1)*len(v)/NCPU, u, c)
     }
     // Drain the channel.
-    for i := 0; i < numCPU; i++ {
+    for i := 0; i < NCPU; i++ {
         <-c    // wait for one task to complete
     }
     // All done.
 }
+
 </pre>
+
 <p>
-Rather than create a constant value for numCPU, we can ask the runtime what
-value is appropriate.
-The function <code><a href="/pkg/runtime#NumCPU">runtime.NumCPU</a></code>
-returns the number of hardware CPU cores in the machine, so we could write
-</p>
-<pre>
-var numCPU = runtime.NumCPU()
-</pre>
-<p>
-There is also a function
-<code><a href="/pkg/runtime#GOMAXPROCS">runtime.GOMAXPROCS</a></code>,
-which reports (or sets)
-the user-specified number of cores that a Go program can have running
-simultaneously.
-It defaults to the value of <code>runtime.NumCPU</code> but can be
-overridden by setting the similarly named shell environment variable
-or by calling the function with a positive number.  Calling it with
-zero just queries the value.
-Therefore if we want to honor the user's resource request, we should write
+The current implementation of the Go runtime
+will not parallelize this code by default.
+It dedicates only a single core to user-level processing.  An
+arbitrary number of goroutines can be blocked in system calls, but
+by default only one can be executing user-level code at any time.
+It should be smarter and one day it will be smarter, but until it
+is if you want CPU parallelism you must tell the run-time
+how many goroutines you want executing code simultaneously.  There
+are two related ways to do this.  Either run your job with environment
+variable <code>GOMAXPROCS</code> set to the number of cores to use
+or import the <code>runtime</code> package and call
+<code>runtime.GOMAXPROCS(NCPU)</code>.
+A helpful value might be <code>runtime.NumCPU()</code>, which reports the number
+of logical CPUs on the local machine.
+Again, this requirement is expected to be retired as the scheduling and run-time improve.
 </p>
-<pre>
-var numCPU = runtime.GOMAXPROCS(0)
-</pre>
+
 <p>
 Be sure not to confuse the ideas of concurrency—structuring a program
 as independently executing components—and parallelism—executing
diff --git a/doc/gccgo_contribute.html b/doc/gccgo_contribute.html
index dd1327a..db7d1ab 100644
--- a/doc/gccgo_contribute.html
+++ b/doc/gccgo_contribute.html
@@ -30,9 +30,7 @@ contribution rules</a>.
 
 <p>
 The master sources for the gccgo frontend may be found at
-<a href="http://go.googlesource.com/gofrontend">http://go.googlesource.com/gofrontend</a>.
-They are mirrored
-at <a href="http://github.com/golang/gofrontend">http://github.com/golang/gofrontend</a>.
+<a href="//code.google.com/p/gofrontend">http://code.google.com/p/gofrontend</a>.
 The master sources are not buildable by themselves, but only in
 conjunction with GCC (in the future, other compilers may be
 supported).  Changes made to the gccgo frontend are also applied to
@@ -42,7 +40,7 @@ is mirrored to the <code>gcc/go/gofrontend</code> directory in the GCC
 repository, and the <code>gofrontend</code> <code>libgo</code>
 directory is mirrored to the GCC <code>libgo</code> directory.  In
 addition, the <code>test</code> directory
-from <a href="//go.googlesource.com/go">the main Go repository</a>
+from <a href="//code.google.com/p/go">the main Go repository</a>
 is mirrored to the <code>gcc/testsuite/go.test/test</code> directory
 in the GCC repository.
 </p>
@@ -55,17 +53,19 @@ them.
 </p>
 
 <p>
-The gccgo frontend is written in C++.
-It follows the GNU and GCC coding standards for C++.
-In writing code for the frontend, follow the formatting of the
-surrounding code.
-Almost all GCC-specific code is not in the frontend proper and is
-instead in the GCC sources in the <code>gcc/go</code> directory.
+The gccgo frontend is written in C++.  It follows the GNU coding
+standards to the extent that they apply to C++.  In writing code for
+the frontend, follow the formatting of the surrounding code.  Although
+the frontend is currently tied to the rest of the GCC codebase, we
+plan to make it more independent.  Eventually all GCC-specific code
+will migrate out of the frontend proper and into GCC proper.  In the
+GCC sources this will generally mean moving code
+from <code>gcc/go/gofrontend</code> to <code>gcc/go</code>.
 </p>
 
 <p>
 The run-time library for gccgo is mostly the same as the library
-in <a href="//go.googlesource.com/go">the main Go repository</a>.
+in <a href="//code.google.com/p/go">the main Go repository</a>.
 The library code in the Go repository is periodically merged into
 the <code>libgo/go</code> directory of the <code>gofrontend</code> and
 then the GCC repositories, using the shell
@@ -105,7 +105,7 @@ or <code>gcc/testsuite/go.dg</code> directories in the GCC repository.
 <p>
 Changes to the Go frontend should follow the same process as for the
 main Go repository, only for the <code>gofrontend</code> project and
-the <code>gofrontend-dev at googlegroups.com</code> mailing list 
+the<code>gofrontend-dev at googlegroups.com</code> mailing list 
 rather than the <code>go</code> project and the
 <code>golang-dev at googlegroups.com</code> mailing list.  Those changes
 will then be merged into the GCC sources.
diff --git a/doc/gccgo_install.html b/doc/gccgo_install.html
index ef27fd1..acb315a 100644
--- a/doc/gccgo_install.html
+++ b/doc/gccgo_install.html
@@ -46,12 +46,6 @@ identical to Go 1.1.  The GCC 4.8.2 release includes a complete Go
 The GCC 4.9 releases include a complete Go 1.2 implementation.
 </p>
 
-<p>
-The GCC 5 releases include a complete implementation of the Go 1.4
-user libraries.  The Go 1.4 runtime is not fully merged, but that
-should not be visible to Go programs.
-</p>
-
 <h2 id="Source_code">Source code</h2>
 
 <p>
@@ -180,10 +174,13 @@ export LIBRARY_PATH C_INCLUDE_PATH CPLUS_INCLUDE_PATH
 <h2 id="Using_gccgo">Using gccgo</h2>
 
 <p>
-The gccgo compiler works like other gcc frontends.  As of GCC 5 the gccgo
-installation also includes a version of the <code>go</code> command,
-which may be used to build Go programs as described at
-<a href="https://golang.org/cmd/go">https://golang.org/cmd/go</a>.
+The gccgo compiler works like other gcc frontends.  The gccgo
+installation does not currently include a version of
+the <code>go</code> command.  However if you have the <code>go</code>
+command from an installation of the <code>gc</code> compiler, you can
+use it with gccgo by passing the option <code>-compiler gccgo</code>
+to <code>go build</code> or <code>go install</code> or <code>go
+test</code>.
 </p>
 
 <p>
@@ -235,14 +232,13 @@ name the directory where <code>libgo.so</code> is found.
 
 <li>
 <p>
-Passing a <code>-Wl,-R</code> option when you link (replace lib with
-lib64 if appropriate for your system):
+Passing a <code>-Wl,-R</code> option when you link:
 </p>
 
 <pre>
-go build -gccgoflags -Wl,-R,${prefix}/lib/gcc/MACHINE/VERSION
-[or]
 gccgo -o file file.o -Wl,-R,${prefix}/lib/gcc/MACHINE/VERSION
+[or]
+gccgo -o file file.o -Wl,-R,${prefix}/lib64/gcc/MACHINE/VERSION
 </pre>
 </li>
 
@@ -270,33 +266,27 @@ and <code>-g</code> options.
 </p>
 
 <p>
-The <code>-fgo-pkgpath=PKGPATH</code> option may be used to set a
-unique prefix for the package being compiled.
-This option is automatically used by the go command, but you may want
-to use it if you invoke gccgo directly.
-This option is intended for use with large
-programs that contain many packages, in order to allow multiple
-packages to use the same identifier as the package name.
-The <code>PKGPATH</code> may be any string; a good choice for the
-string is the path used to import the package.
+The <code>-fgo-prefix=PREFIX</code> option may be used to set a unique
+prefix for the package being compiled.  This option is intended for
+use with large programs that contain many packages, in order to allow
+multiple packages to use the same identifier as the package name.
+The <code>PREFIX</code> may be any string; a good choice for the
+string is the directory where the package will be installed.
 </p>
 
 <p>
 The <code>-I</code> and <code>-L</code> options, which are synonyms
 for the compiler, may be used to set the search path for finding
 imports.
-These options are not needed if you build with the go command.
 </p>
 
 <h2 id="Imports">Imports</h2>
 
 <p>
 When you compile a file that exports something, the export
-information will be stored directly in the object file.
-If you build with gccgo directly, rather than with the go command,
-then when you import a package, you must tell gccgo how to find the
-file.
-</p>
+information will be stored directly in the object file.  When
+you import a package, you must tell gccgo how to
+find the file.
 
 <p>
 When you import the package <var>FILE</var> with gccgo,
@@ -329,10 +319,9 @@ gccgo.  Both options take directories to search. The
 </p>
 
 <p>
-The gccgo compiler does not currently (2015-06-15) record
+The gccgo compiler does not currently (2013-06-20) record
 the file name of imported packages in the object file. You must
 arrange for the imported data to be linked into the program.
-Again, this is not necessary when building with the go command.
 </p>
 
 <pre>
diff --git a/doc/go1.1.html b/doc/go1.1.html
index f059fd7..825867f 100644
--- a/doc/go1.1.html
+++ b/doc/go1.1.html
@@ -160,7 +160,7 @@ The GCC release schedule does not coincide with the Go release schedule, so some
 The 4.8.0 version of GCC shipped in March, 2013 and includes a nearly-Go 1.1 version of <code>gccgo</code>.
 Its library is a little behind the release, but the biggest difference is that method values are not implemented.
 Sometime around July 2013, we expect 4.8.2 of GCC to ship with a <code>gccgo</code>
-providing a complete Go 1.1 implementation.
+providing a complete Go 1.1 implementaiton.
 </p>
 
 <h3 id="gc_flag">Command-line flag parsing</h3>
diff --git a/doc/go1.4.html b/doc/go1.4.html
index ca44d56..b4f9619 100644
--- a/doc/go1.4.html
+++ b/doc/go1.4.html
@@ -677,7 +677,7 @@ now supports ALPN as defined in <a href="http://tools.ietf.org/html/rfc7301">RFC
 The <a href="/pkg/crypto/tls/"><code>crypto/tls</code></a> package
 now supports programmatic selection of server certificates
 through the new <a href="/pkg/crypto/tls/#Config.CertificateForName"><code>CertificateForName</code></a> function
-of the <a href="/pkg/crypto/tls/#Config"><code>Config</code></a> struct.
+of the <a href="/pkg/crypo/tls/#Config"><code>Config</code></a> struct.
 </li>
 
 <li>
diff --git a/doc/go1compat.html b/doc/go1compat.html
index 607d354..d800dec 100644
--- a/doc/go1compat.html
+++ b/doc/go1compat.html
@@ -96,18 +96,6 @@ in a separate package should use the keyed notation.
 </li>
 
 <li>
-Methods. As with struct fields, it may be necessary to add methods
-to types.
-Under some circumstances, such as when the type is embedded in
-a struct along with another type,
-the addition of the new method may break
-the struct by creating a conflict with an existing method of the other
-embedded type.
-We cannot protect against this rare case and do not guarantee compatibility
-should it arise.
-</li>
-
-<li>
 Dot imports. If a program imports a standard package
 using <code>import . "path"</code>, additional names defined in the
 imported package in future releases may conflict with other names
diff --git a/doc/go_faq.html b/doc/go_faq.html
index 33636fc..6b77f1c 100644
--- a/doc/go_faq.html
+++ b/doc/go_faq.html
@@ -92,6 +92,13 @@ portability and the addition of new functionality such as improved support for i
 There may well be a Go 2 one day, but not for a few years and it will be influenced by what we learn using Go 1 as it is today.
 </p>
 
+<h3 id="What_is_the_origin_of_the_name">
+What is the origin of the name?</h3>
+
+<p>
+“Ogle” would be a good name for a Go debugger.
+</p>
+
 <h3 id="Whats_the_origin_of_the_mascot">
 What's the origin of the mascot?</h3>
 
@@ -100,8 +107,7 @@ The mascot and logo were designed by
 <a href="http://reneefrench.blogspot.com">Renée French</a>, who also designed
 <a href="http://plan9.bell-labs.com/plan9/glenda.html">Glenda</a>,
 the Plan 9 bunny.
-The <a href="https://blog.golang.org/gopher">gopher</a>
-is derived from one she used for an <a href="http://wfmu.org/">WFMU</a>
+The gopher is derived from one she used for an <a href="http://wfmu.org/">WFMU</a>
 T-shirt design some years ago.
 The logo and mascot are covered by the
 <a href="http://creativecommons.org/licenses/by/3.0/">Creative Commons Attribution 3.0</a>
@@ -147,7 +153,7 @@ Go is an attempt to combine the ease of programming of an interpreted,
 dynamically typed
 language with the efficiency and safety of a statically typed, compiled language.
 It also aims to be modern, with support for networked and multicore
-computing.  Finally, working with Go is intended to be <i>fast</i>: it should take
+computing.  Finally, it is intended to be <i>fast</i>: it should take
 at most a few seconds to build a large executable on a single computer.
 To meet these goals required addressing a number of
 linguistic issues: an expressive but lightweight type system;
@@ -222,7 +228,7 @@ document server running in a production configuration on
 </p>
 
 <p>
-Other examples include the <a href="//github.com/youtube/vitess/">Vitess</a>
+Other examples include the <a href="//code.google.com/p/vitess/">Vitess</a>
 system for large-scale SQL installations and Google's download server, <code>dl.google.com</code>,
 which delivers Chrome binaries and other large installables such as <code>apt-get</code>
 packages.
@@ -233,7 +239,7 @@ Do Go programs link with C/C++ programs?</h3>
 
 <p>
 There are two Go compiler implementations, <code>gc</code>
-and <code>gccgo</code>.
+(the <code>6g</code> program and friends) and <code>gccgo</code>.
 <code>Gc</code> uses a different calling convention and linker and can
 therefore only be linked with C programs using the same convention.
 There is such a C compiler but no C++ compiler.
@@ -254,7 +260,7 @@ Does Go support Google's protocol buffers?</h3>
 <p>
 A separate open source project provides the necessary compiler plugin and library.
 It is available at
-<a href="//github.com/golang/protobuf">github.com/golang/protobuf/</a>
+<a href="//code.google.com/p/goprotobuf/">code.google.com/p/goprotobuf/</a>
 </p>
 
 
@@ -502,7 +508,7 @@ They are not restricted to structs (classes).
 </p>
 
 <p>
-Also, the lack of a type hierarchy makes “objects” in Go feel much more
+Also, the lack of type hierarchy makes “objects” in Go feel much more
 lightweight than in languages such as C++ or Java.
 </p>
 
@@ -602,19 +608,17 @@ How can I guarantee my type satisfies an interface?</h3>
 
 <p>
 You can ask the compiler to check that the type <code>T</code> implements the
-interface <code>I</code> by attempting an assignment using the zero value for
-<code>T</code> or pointer to <code>T</code>, as appropriate:
+interface <code>I</code> by attempting an assignment:
 </p>
 
 <pre>
 type T struct{}
-var _ I = T{}       // Verify that T implements I.
-var _ I = (*T)(nil) // Verify that *T implements I.
+var _ I = T{}   // Verify that T implements I.
 </pre>
 
 <p>
-If <code>T</code> (or <code>*T</code>, accordingly) doesn't implement
-<code>I</code>, the mistake will be caught at compile time.
+If <code>T</code> doesn't implement <code>I</code>, the mistake will be caught
+at compile time.
 </p>
 
 <p>
@@ -722,7 +726,7 @@ interface satisfaction very easy to state: are the function's names
 and signatures exactly those of the interface?
 Go's rule is also easy to implement efficiently.
 We feel these benefits offset the lack of
-automatic type promotion. Should Go one day adopt some form of polymorphic
+automatic type promotion. Should Go one day adopt some form of generic
 typing, we expect there would be a way to express the idea of these
 examples and also have them be statically checked.
 </p>
@@ -761,7 +765,7 @@ schematically, (<code>int</code>, <code>3</code>).
 An interface value is <code>nil</code> only if the inner value and type are both unset,
 (<code>nil</code>, <code>nil</code>).
 In particular, a <code>nil</code> interface will always hold a <code>nil</code> type.
-If we store a <code>nil</code> pointer of type <code>*int</code> inside
+If we store a pointer of type <code>*int</code> inside
 an interface value, the inner type will be <code>*int</code> regardless of the value of the pointer:
 (<code>*int</code>, <code>nil</code>).
 Such an interface value will therefore be non-<code>nil</code>
@@ -769,7 +773,7 @@ Such an interface value will therefore be non-<code>nil</code>
 </p>
 
 <p>
-This situation can be confusing, and arises when a <code>nil</code> value is
+This situation can be confusing, and often arises when a <code>nil</code> value is
 stored inside an interface value such as an <code>error</code> return:
 </p>
 
@@ -886,7 +890,7 @@ encourages you to be explicit.
 </p>
 
 <p>
-A blog post titled <a href="https://blog.golang.org/constants">Constants</a>
+A blog post, title <a href="http://blog.golang.org/constants">Constants</a>,
 explores this topic in more detail.
 </p>
 
@@ -946,19 +950,6 @@ In fact, <code>godoc</code> implements the full site at
 <a href="/">golang.org/</a>.
 </p>
 
-<p>
-A <code>godoc</code> instance may be configured to provide rich,
-interactive static analyses of symbols in the programs it displays; details are
-listed <a href="https://golang.org/lib/godoc/analysis/help.html">here</a>.
-</p>
-
-<p>
-For access to documentation from the command line, the
-<a href="https://golang.org/pkg/cmd/go/">go</a> tool has a
-<a href="https://golang.org/pkg/cmd/go/#hdr-Show_documentation_for_package_or_symbol">doc</a>
-subcommand that provides a textual interface to the same information.
-</p>
-
 <h3 id="Is_there_a_Go_programming_style_guide">
 Is there a Go programming style guide?</h3>
 
@@ -1055,17 +1046,7 @@ unexpected ways, the simplest solution is to copy it to your local repository.
 (This is the approach Google takes internally.)
 Store the copy under a new import path that identifies it as a local copy.
 For example, you might copy "original.com/pkg" to "you.com/external/original.com/pkg".
-The <a href="https://godoc.org/golang.org/x/tools/cmd/gomvpkg">gomvpkg</a>
-program is one tool to help automate this process.
-</p>
-
-<p>
-The Go 1.5 release includes an experimental facility to the
-<a href="https://golang.org/cmd/go">go</a> command
-that makes it easier to manage external dependencies by "vendoring"
-them into a special directory near the package that depends upon them.
-See the <a href="https://golang.org/s/go15vendor">design
-document</a> for details.
+Keith Rarick's <a href="https://github.com/kr/goven">goven</a> is one tool to help automate this process.
 </p>
 
 <h2 id="Pointers">Pointers and Allocation</h2>
@@ -1080,8 +1061,7 @@ thing being passed, as if there were an assignment statement assigning the
 value to the parameter.  For instance, passing an <code>int</code> value
 to a function makes a copy of the <code>int</code>, and passing a pointer
 value makes a copy of the pointer, but not the data it points to.
-(See a <a href="/doc/faq#methods_on_values_or_pointers">later
-section</a> for a discussion of how this affects method receivers.)
+(See the next section for a discussion of how this affects method receivers.)
 </p>
 
 <p>
@@ -1310,20 +1290,14 @@ See the <a href="/doc/codewalk/sharemem/">Share Memory By Communicating</a> code
 Why doesn't my multi-goroutine program use multiple CPUs?</h3>
 
 <p>
-The number of CPUs available simultaneously to executing goroutines is
-controlled by the <code>GOMAXPROCS</code> shell environment variable.
-In earlier releases of Go, the default value was 1, but as of Go 1.5 the default
-value is the number of cores available.
-Therefore programs compiled after 1.5 should demonstrate parallel execution
-of multiple goroutines.
-To change the behavior, set the environment variable or use the similarly-named
-<a href="/pkg/runtime/#GOMAXPROCS">function</a>
-of the runtime package to configure the
-run-time support to utilize a different number of threads.
+You must set the <code>GOMAXPROCS</code> shell environment variable
+or use the similarly-named <a href="/pkg/runtime/#GOMAXPROCS"><code>function</code></a>
+of the runtime package to allow the
+run-time support to utilize more than one OS thread.
 </p>
 
 <p>
-Programs that perform parallel computation might benefit from a further increase in
+Programs that perform parallel computation should benefit from an increase in
 <code>GOMAXPROCS</code>.
 However, be aware that
 <a href="//blog.golang.org/2013/01/concurrency-is-not-parallelism.html">concurrency
@@ -1345,7 +1319,7 @@ intrinsically parallel.
 <p>
 In practical terms, programs that spend more time
 communicating on channels than doing computation
-may experience performance degradation when using
+will experience performance degradation when using
 multiple OS threads.
 This is because sending data between threads involves switching
 contexts, which has significant cost.
@@ -1356,11 +1330,9 @@ to speed it up.
 </p>
 
 <p>
-Go's goroutine scheduler is not as good as it needs to be, although it
-has improved in recent releases.
-In the future, it may better optimize its use of OS threads.
-For now, if there are performance issues,
-setting <code>GOMAXPROCS</code> on a per-application basis may help.
+Go's goroutine scheduler is not as good as it needs to be. In the future, it
+should recognize such cases and optimize its use of OS threads. For now,
+<code>GOMAXPROCS</code> should be set on a per-application basis.
 </p>
 
 <p>
@@ -1395,10 +1367,7 @@ there is no useful way for a method call to obtain a pointer.
 Even in cases where the compiler could take the address of a value
 to pass to the method, if the method modifies the value the changes
 will be lost in the caller.
-As an example, if the <code>Write</code> method of
-<a href="/pkg/bytes/#Buffer"><code>bytes.Buffer</code></a>
-used a value receiver rather than a pointer,
-this code:
+As a common example, this code:
 </p>
 
 <pre>
@@ -1492,7 +1461,7 @@ seem odd but works fine in Go:
 Does Go have the <code>?:</code> operator?</h3>
 
 <p>
-There is no ternary testing operation in Go. You may use the following to achieve the same
+There is no ternary form in Go. You may use the following to achieve the same
 result:
 </p>
 
@@ -1584,51 +1553,6 @@ test cases. The standard Go library is full of illustrative examples, such as in
 <a href="/src/fmt/fmt_test.go">the formatting tests for the <code>fmt</code> package</a>.
 </p>
 
-<h3 id="x_in_std">
-Why isn't <i>X</i> in the standard library?</h3>
-
-<p>
-The standard library's purpose is to support the runtime, connect to
-the operating system, and provide key functionality that many Go
-programs require, such as formatted I/O and networking.
-It also contains elements important for web programming, including
-cryptography and support for standards like HTTP, JSON, and XML.
-</p>
-
-<p>
-There is no clear criterion that defines what is included because for
-a long time, this was the <i>only</i> Go library.
-There are criteria that define what gets added today, however.
-</p>
-
-<p>
-New additions to the standard library are rare and the bar for
-inclusion is high.
-Code included in the standard library bears a large ongoing maintenance cost
-(often borne by those other than the original author),
-is subject to the <a href="/doc/go1compat.html">Go 1 compatibility promise</a>
-(blocking fixes to any flaws in the API),
-and is subject to the Go
-<a href="https://golang.org/s/releasesched">release schedule</a>,
-preventing bug fixes from being available to users quickly.
-</p>
-
-<p>
-Most new code should live outside of the standard library and be accessible
-via the <a href="/cmd/go/"><code>go</code> tool</a>'s
-<code>go get</code> command.
-Such code can have its own maintainers, release cycle,
-and compatibility guarantees.
-Users can find packages and read their documentation at
-<a href="https://godoc.org/">godoc.org</a>.
-</p>
-
-<p>
-Although there are pieces in the standard library that don't really belong,
-such as <code>log/syslog</code>, we continue to maintain everything in the
-library because of the Go 1 compatibility promise.
-But we encourage most new code to live elsewhere.
-</p>
 
 <h2 id="Implementation">Implementation</h2>
 
@@ -1637,10 +1561,11 @@ What compiler technology is used to build the compilers?</h3>
 
 <p>
 <code>Gccgo</code> has a front end written in C++, with a recursive descent parser coupled to the
-standard GCC back end. <code>Gc</code> is written in Go using
-<code>yacc</code>/<code>bison</code> for the parser
-and uses a custom loader, also written in Go but
-based on the Plan 9 loader, to generate ELF/Mach-O/PE binaries.
+standard GCC back end. <code>Gc</code> is written in C using
+<code>yacc</code>/<code>bison</code> for the parser.
+Although it's a new program, it fits in the Plan 9 C compiler suite
+(<a href="http://plan9.bell-labs.com/sys/doc/compiler.html">http://plan9.bell-labs.com/sys/doc/compiler.html</a>)
+and uses a variant of the Plan 9 loader to generate ELF/Mach-O/PE binaries.
 </p>
 
 <p>
@@ -1649,26 +1574,24 @@ slow to meet our performance goals.
 </p>
 
 <p>
-The original <code>gc</code>, the Go compiler, was written in C
-because of the difficulties of bootstrapping—you'd need a Go compiler to
-set up a Go environment.
-But things have advanced and as of Go 1.5 the compiler is written in Go.
-It was converted from C to Go using automatic translation tools, as
-described in <a href="/s/go13compiler">this design document</a>
-and <a href="https://talks.golang.org/2015/gogo.slide#1">a recent talk</a>.
-Thus the compiler is now "self-hosting", which means we must face
-the bootstrapping problem.
-The solution, naturally, is to have a working Go installation already,
-just as one normally has a working C installation in place.
-The story of how to bring up a new Go installation from source
-is described <a href="/s/go15bootstrap">separately</a>.
+We also considered writing <code>gc</code>, the original Go compiler, in Go itself but
+elected not to do so because of the difficulties of bootstrapping and
+especially of open source distribution—you'd need a Go compiler to
+set up a Go environment. <code>Gccgo</code>, which came later, makes it possible to
+consider writing a compiler in Go.
+A plan to do that by machine translation of the existing compiler is under development.
+<a href="http://golang.org/s/go13compiler">A separate document</a>
+explains the reason for this approach.
 </p>
 
 <p>
-Go is a fine language in which to implement a Go compiler.
-Although <code>gc</code> does not use them (yet?), a native lexer and
-parser are available in the <a href="/pkg/go/"><code>go</code></a> package
-and there is also a <a href="/pkg/go/types">type checker</a>.
+That plan aside,
+Go is a
+fine language in which to implement a self-hosting compiler: a native lexer and
+parser are already available in the <a href="/pkg/go/"><code>go</code></a> package
+and a separate type checking
+<a href="http://godoc.org/golang.org/x/tools/go/types">package</a>
+has also been written.
 </p>
 
 <h3 id="How_is_the_run_time_support_implemented">
@@ -1676,11 +1599,15 @@ How is the run-time support implemented?</h3>
 
 <p>
 Again due to bootstrapping issues, the run-time code was originally written mostly in C (with a
-tiny bit of assembler) but it has since been translated to Go
-(except for some assembler bits).
+tiny bit of assembler) although much of it has been translated to Go since then
+and one day all of it might be (except for the assembler bits).
 <code>Gccgo</code>'s run-time support uses <code>glibc</code>.
-The <code>gccgo</code> compiler implements goroutines using
-a technique called segmented stacks,
+<code>Gc</code> uses a custom C library to keep the footprint under
+control; it is
+compiled with a version of the Plan 9 C compiler that supports
+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>
 
@@ -1688,8 +1615,8 @@ supported by recent modifications to the gold linker.
 Why is my trivial program such a large binary?</h3>
 
 <p>
-The linker in the <code>gc</code> tool chain
-creates statically-linked binaries by default.  All Go binaries therefore include the Go
+The linkers in the gc tool chain (<code>5l</code>, <code>6l</code>, and <code>8l</code>)
+do static linking.  All Go binaries therefore include the Go
 run-time, along with the run-time type information necessary to support dynamic
 type checks, reflection, and even panic-time stack traces.
 </p>
@@ -1699,7 +1626,7 @@ A simple C "hello, world" program compiled and linked statically using gcc
 on Linux is around 750 kB,
 including an implementation of <code>printf</code>.
 An equivalent Go program using <code>fmt.Printf</code>
-is around 2.3 MB, but
+is around 1.9 MB, but
 that includes more powerful run-time support and type information.
 </p>
 
@@ -1958,12 +1885,8 @@ simpler because they don't need to specify how memory is managed across them.
 </p>
 
 <p>
-The current implementation is a parallel mark-and-sweep collector.
-Recent improvements, documented in
-<a href="/s/go14gc">this design document</a>,
-have introduced bounded pause times and improved the
-parallelism.
-Future versions might attempt new approaches.
+The current implementation is a parallel mark-and-sweep
+collector but a future version might take a different approach.
 </p>
 
 <p>
diff --git a/doc/go_mem.html b/doc/go_mem.html
index 143f3b2..5dd48ff 100644
--- a/doc/go_mem.html
+++ b/doc/go_mem.html
@@ -322,11 +322,11 @@ var limit = make(chan int, 3)
 
 func main() {
 	for _, w := range work {
-		go func(w func()) {
-			limit <- 1
+		go func() {
+			limit <- 1
 			w()
-			<-limit
-		}(w)
+			<-limit
+		}()
 	}
 	select{}
 }
diff --git a/doc/go_spec.html b/doc/go_spec.html
index 22f9701..ca0deb5 100644
--- a/doc/go_spec.html
+++ b/doc/go_spec.html
@@ -1,9 +1,24 @@
 <!--{
 	"Title": "The Go Programming Language Specification",
-	"Subtitle": "Version of August 5, 2015",
+	"Subtitle": "Version of November 11, 2014",
 	"Path": "/ref/spec"
 }-->
 
+<!--
+TODO
+[ ] need language about function/method calls and parameter passing rules
+[ ] last paragraph of #Assignments (constant promotion) should be elsewhere
+    and mention assignment to empty interface.
+[ ] need to say something about "scope" of selectors?
+[ ] clarify what a field name is in struct declarations
+    (struct{T} vs struct {T T} vs struct {t T})
+[ ] need explicit language about the result type of operations
+[ ] should probably write something about evaluation order of statements even
+	though obvious
+[ ] in Selectors section, clarify what receiver value is passed in method invocations
+-->
+
+
 <h2 id="Introduction">Introduction</h2>
 
 <p>
@@ -129,27 +144,27 @@ hex_digit     = "0" … "9" | "A" … "F" | "a" … "f" .
 <h3 id="Comments">Comments</h3>
 
 <p>
-Comments serve as program documentation. There are two forms:
+There are two forms of comments:
 </p>
 
 <ol>
 <li>
 <i>Line comments</i> start with the character sequence <code>//</code>
-and stop at the end of the line.
+and stop at the end of the line. A line comment acts like a newline.
 </li>
 <li>
 <i>General comments</i> start with the character sequence <code>/*</code>
-and stop with the first subsequent character sequence <code>*/</code>.
+and continue through the character sequence <code>*/</code>. A general
+comment containing one or more newlines acts like a newline, otherwise it acts
+like a space.
 </li>
 </ol>
 
 <p>
-A comment cannot start inside a <a href="#Rune_literals">rune</a> or
-<a href="#String_literals">string literal</a>, or inside a comment.
-A general comment containing no newlines acts like a space.
-Any other comment acts like a newline.
+Comments do not nest.
 </p>
 
+
 <h3 id="Tokens">Tokens</h3>
 
 <p>
@@ -176,8 +191,11 @@ using the following two rules:
 
 <ol>
 <li>
+<p>
 When the input is broken into tokens, a semicolon is automatically inserted
-into the token stream immediately after a line's final token if that token is
+into the token stream at the end of a non-blank line if the line's final
+token is
+</p>
 <ul>
 	<li>an
 	    <a href="#Identifiers">identifier</a>
@@ -354,10 +372,9 @@ imaginary_lit = (decimals | float_lit) "i" .
 <p>
 A rune literal represents a <a href="#Constants">rune constant</a>,
 an integer value identifying a Unicode code point.
-A rune literal is expressed as one or more characters enclosed in single quotes,
-as in <code>'x'</code> or <code>'\n'</code>.
-Within the quotes, any character may appear except newline and unescaped single
-quote. A single quoted character represents the Unicode value
+A rune literal is expressed as one or more characters enclosed in single quotes.
+Within the quotes, any character may appear except single
+quote and newline. A single quoted character represents the Unicode value
 of the character itself,
 while multi-character sequences beginning with a backslash encode
 values in various formats.
@@ -431,7 +448,6 @@ escaped_char     = `\` ( "a" | "b" | "f" | "n" | "r" | "t" | "v" | `\` | "'" | `
 '\xff'
 '\u12e4'
 '\U00101234'
-'\''         // rune literal containing single quote character
 'aa'         // illegal: too many characters
 '\xa'        // illegal: too few hexadecimal digits
 '\0'         // illegal: too few octal digits
@@ -448,8 +464,8 @@ obtained from concatenating a sequence of characters. There are two forms:
 raw string literals and interpreted string literals.
 </p>
 <p>
-Raw string literals are character sequences between back quotes, as in
-<code>`foo`</code>.  Within the quotes, any character may appear except
+Raw string literals are character sequences between back quotes
+<code>``</code>.  Within the quotes, any character is legal except
 back quote. The value of a raw string literal is the
 string composed of the uninterpreted (implicitly UTF-8-encoded) characters
 between the quotes;
@@ -460,9 +476,8 @@ are discarded from the raw string value.
 </p>
 <p>
 Interpreted string literals are character sequences between double
-quotes, as in <code>"bar"</code>.
-Within the quotes, any character may appear except newline and unescaped double quote.
-The text between the quotes forms the
+quotes <code>""</code>. The text between the quotes,
+which may not contain newlines, forms the
 value of the literal, with backslash escapes interpreted as they
 are in <a href="#Rune_literals">rune literals</a> (except that <code>\'</code> is illegal and
 <code>\"</code> is legal), with the same restrictions.
@@ -484,17 +499,17 @@ interpreted_string_lit = `"` { unicode_value | byte_value } `"` .
 </pre>
 
 <pre>
-`abc`                // same as "abc"
+`abc`  // same as "abc"
 `\n
-\n`                  // same as "\\n\n\\n"
+\n`    // same as "\\n\n\\n"
 "\n"
-"\""                 // same as `"`
+""
 "Hello, world!\n"
 "日本語"
 "\u65e5本\U00008a9e"
 "\xff\u00FF"
-"\uD800"             // illegal: surrogate half
-"\U00110000"         // illegal: invalid Unicode code point
+"\uD800"       // illegal: surrogate half
+"\U00110000"   // illegal: invalid Unicode code point
 </pre>
 
 <p>
@@ -662,7 +677,7 @@ acts like a variable.
 </p>
 
 <p>
-The <i>static type</i> (or just <i>type</i>) of a variable is the
+The <i>static type</i> (or just <i>type</i>) of a variable is the	
 type given in its declaration, the type provided in the
 <code>new</code> call or composite literal, or the type of
 an element of a structured variable.
@@ -672,8 +687,8 @@ which is the concrete type of the value assigned to the variable at run time
 which has no type).
 The dynamic type may vary during execution but values stored in interface
 variables are always <a href="#Assignability">assignable</a>
-to the static type of the variable.
-</p>
+to the static type of the variable.	
+</p>	
 
 <pre>
 var x interface{}  // x is nil and has static type interface{}
@@ -1918,7 +1933,7 @@ const (
 )
 
 func (tz TimeZone) String() string {
-	return fmt.Sprintf("GMT%+dh", tz)
+	return fmt.Sprintf("GMT+%dh", tz)
 }
 </pre>
 
@@ -1966,7 +1981,7 @@ with no explicit type.
 </p>
 
 <pre>
-var d = math.Sin(0.5)  // d is float64
+var d = math.Sin(0.5)  // d is int64
 var i = 42             // i is int
 var t, ok = x.(T)      // t is T, ok is bool
 var n = nil            // illegal
@@ -2006,12 +2021,12 @@ _, y, _ := coord(p)  // coord() returns three values; only interested in y coord
 </pre>
 
 <p>
-Unlike regular variable declarations, a short variable declaration may <i>redeclare</i>
-variables provided they were originally declared earlier in the same block
-(or the parameter lists if the block is the function body) with the same type, 
-and at least one of the non-<a href="#Blank_identifier">blank</a> variables is new.
-As a consequence, redeclaration can only appear in a multi-variable short declaration.
-Redeclaration does not introduce a new variable; it just assigns a new value to the original.
+Unlike regular variable declarations, a short variable declaration may redeclare variables provided they
+were originally declared earlier in the same block with the same type, and at
+least one of the non-<a href="#Blank_identifier">blank</a> variables is new.  As a consequence, redeclaration
+can only appear in a multi-variable short declaration.
+Redeclaration does not introduce a new
+variable; it just assigns a new value to the original.
 </p>
 
 <pre>
@@ -2050,13 +2065,13 @@ a <a href="#Terminating_statements">terminating statement</a>.
 </p>
 
 <pre>
-func IndexRune(s string, r rune) int {
-	for i, c := range s {
-		if c == r {
-			return i
+func findMarker(c <-chan int) int {
+	for i := range c {
+		if x := <-c; isMarker(x) {
+			return x
 		}
 	}
-	// invalid: missing return statement
+	// invalid: missing return statement.
 }
 </pre>
 
@@ -2090,15 +2105,14 @@ Receiver     = Parameters .
 </pre>
 
 <p>
-The receiver is specified via an extra parameter section preceding the method
+The receiver is specified via an extra parameter section preceeding the method
 name. That parameter section must declare a single parameter, the receiver.
 Its type must be of the form <code>T</code> or <code>*T</code> (possibly using
 parentheses) where <code>T</code> is a type name. The type denoted by <code>T</code> is called
 the receiver <i>base type</i>; it must not be a pointer or interface type and
 it must be declared in the same package as the method.
 The method is said to be <i>bound</i> to the base type and the method name
-is visible only within <a href="#Selectors">selectors</a> for type <code>T</code>
-or <code>*T</code>.
+is visible only within selectors for that type.
 </p>
 
 <p>
@@ -2222,8 +2236,9 @@ LiteralType   = StructType | ArrayType | "[" "..." "]" ElementType |
 LiteralValue  = "{" [ ElementList [ "," ] ] "}" .
 ElementList   = Element { "," Element } .
 Element       = [ Key ":" ] Value .
-Key           = FieldName | Expression | LiteralValue .
+Key           = FieldName | ElementIndex .
 FieldName     = identifier .
+ElementIndex  = Expression .
 Value         = Expression | LiteralValue .
 </pre>
 
@@ -2342,21 +2357,17 @@ tmp[0 : n]
 
 <p>
 Within a composite literal of array, slice, or map type <code>T</code>,
-elements or map keys that are themselves composite literals may elide the respective
-literal type if it is identical to the element or key type of <code>T</code>.
-Similarly, elements or keys that are addresses of composite literals may elide
-the <code>&T</code> when the element or key type is <code>*T</code>.
+elements that are themselves composite literals may elide the respective
+literal type if it is identical to the element type of <code>T</code>.
+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}}
-[][]Point{{{0, 1}, {1, 2}}}         // same as [][]Point{[]Point{Point{0, 1}, Point{1, 2}}}
-map[string]Point{"orig": {0, 0}}    // same as map[string]Point{"orig": Point{0, 0}}
-
-[...]*Point{{1.5, -3.5}, {0, 0}}    // same as [...]*Point{&Point{1.5, -3.5}, &Point{0, 0}}
+[...]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}}
 
-map[Point]string{{0, 0}: "orig"}    // same as map[Point]string{Point{0, 0}: "orig"}
+[...]*Point{{1.5, -3.5}, {0, 0}}  // same as [...]*Point{&Point{1.5, -3.5}, &Point{0, 0}}
 </pre>
 
 <p>
@@ -2591,7 +2602,7 @@ one may write:
 <pre>
 t.z          // t.z
 t.y          // t.T1.y
-t.x          // (*t.T0).x
+t.x          // (*t.TO).x
 
 p.z          // (*p).z
 p.y          // (*p).T1.y
@@ -2599,10 +2610,9 @@ p.x          // (*(*p).T0).x
 
 q.x          // (*(*q).T0).x        (*q).x is a valid field selector
 
-p.M0()       // ((*p).T0).M0()      M0 expects *T0 receiver
-p.M1()       // ((*p).T1).M1()      M1 expects T1 receiver
 p.M2()       // p.M2()              M2 expects *T2 receiver
-t.M2()       // (&t).M2()           M2 expects *T2 receiver, see section on Calls
+p.M1()       // ((*p).T1).M1()      M1 expects T1 receiver
+p.M0()       // ((&(*p).T0)).M0()   M0 expects *T0 receiver, see section on Calls
 </pre>
 
 <p>
@@ -3292,7 +3302,7 @@ Operators combine operands into expressions.
 </p>
 
 <pre class="ebnf">
-Expression = UnaryExpr | Expression binary_op Expression .
+Expression = UnaryExpr | Expression binary_op UnaryExpr .
 UnaryExpr  = PrimaryExpr | unary_op UnaryExpr .
 
 binary_op  = "||" | "&&" | rel_op | add_op | mul_op .
@@ -3321,7 +3331,7 @@ to the type of the other operand.
 The right operand in a shift expression must have unsigned integer type
 or be an untyped constant that can be converted to unsigned integer type.
 If the left operand of a non-constant shift expression is an untyped constant,
-it is first converted to the type it would assume if the shift expression were
+the type of the constant is what it would be if the shift expression were
 replaced by its left operand alone.
 </p>
 
@@ -3341,8 +3351,7 @@ var v float32 = 1<<s   // illegal: 1 has type float32, cannot shift
 var w int64 = 1.0<<33  // 1.0<<33 is a constant shift expression
 </pre>
 
-
-<h4 id="Operator_precedence">Operator precedence</h4>
+<h3 id="Operator_precedence">Operator precedence</h3>
 <p>
 Unary operators have the highest precedence.
 As the  <code>++</code> and <code>--</code> operators form
@@ -3384,9 +3393,9 @@ x == y+1 && <-chanPtr > 0
 <p>
 Arithmetic operators apply to numeric values and yield a result of the same
 type as the first operand. The four standard arithmetic operators (<code>+</code>,
-<code>-</code>, <code>*</code>, <code>/</code>) apply to integer,
-floating-point, and complex types; <code>+</code> also applies to strings.
-The bitwise logical and shift operators apply to integers only.
+<code>-</code>,  <code>*</code>, <code>/</code>) apply to integer,
+floating-point, and complex types; <code>+</code> also applies
+to strings. All other arithmetic operators apply to integers only.
 </p>
 
 <pre class="grammar">
@@ -3405,10 +3414,20 @@ The bitwise logical and shift operators apply to integers only.
 >>   right shift            integer >> unsigned integer
 </pre>
 
+<p>
+Strings can be concatenated using the <code>+</code> operator
+or the <code>+=</code> assignment operator:
+</p>
 
-<h4 id="Integer_operators">Integer operators</h4>
+<pre>
+s := "hi" + string(c)
+s += " and good bye"
+</pre>
 
 <p>
+String addition creates a new string by concatenating the operands.
+</p>
+<p>
 For two integer values <code>x</code> and <code>y</code>, the integer quotient
 <code>q = x / y</code> and remainder <code>r = x % y</code> satisfy the following
 relationships:
@@ -3484,8 +3503,16 @@ follows:
                                       and  m = -1 for signed x
 </pre>
 
+<p>
+For floating-point and complex numbers,
+<code>+x</code> is the same as <code>x</code>,
+while <code>-x</code> is the negation of <code>x</code>.
+The result of a floating-point or complex division by zero is not specified beyond the
+IEEE-754 standard; whether a <a href="#Run_time_panics">run-time panic</a>
+occurs is implementation-specific.
+</p>
 
-<h4 id="Integer_overflow">Integer overflow</h4>
+<h3 id="Integer_overflow">Integer overflow</h3>
 
 <p>
 For unsigned integer values, the operations <code>+</code>,
@@ -3506,35 +3533,6 @@ not occur. For instance, it may not assume that <code>x < x + 1</code> is alw
 </p>
 
 
-<h4 id="Floating_point_operators">Floating-point operators</h4>
-
-<p>
-For floating-point and complex numbers,
-<code>+x</code> is the same as <code>x</code>,
-while <code>-x</code> is the negation of <code>x</code>.
-The result of a floating-point or complex division by zero is not specified beyond the
-IEEE-754 standard; whether a <a href="#Run_time_panics">run-time panic</a>
-occurs is implementation-specific.
-</p>
-
-
-<h4 id="String_concatenation">String concatenation</h4>
-
-<p>
-Strings can be concatenated using the <code>+</code> operator
-or the <code>+=</code> assignment operator:
-</p>
-
-<pre>
-s := "hi" + string(c)
-s += " and good bye"
-</pre>
-
-<p>
-String addition creates a new string by concatenating the operands.
-</p>
-
-
 <h3 id="Comparison_operators">Comparison operators</h3>
 
 <p>
@@ -4097,7 +4095,7 @@ the implementation restriction in the section
 on <a href="#Constants">constants</a>.  This rounding may cause a
 floating-point constant expression to be invalid in an integer
 context, even if it would be integral when calculated using infinite
-precision, and vice versa.
+precision.
 </p>
 
 
@@ -4402,7 +4400,7 @@ a[i] = 23
 An <i>assignment operation</i> <code>x</code> <i>op</i><code>=</code>
 <code>y</code> where <i>op</i> is a binary arithmetic operation is equivalent
 to <code>x</code> <code>=</code> <code>x</code> <i>op</i>
-<code>(y)</code> but evaluates <code>x</code>
+<code>y</code> but evaluates <code>x</code>
 only once.  The <i>op</i><code>=</code> construct is a single token.
 In assignment operations, both the left- and right-hand expression lists
 must contain exactly one single-valued expression, and the left-hand
@@ -4564,7 +4562,6 @@ In an expression switch, the cases contain expressions that are compared
 against the value of the switch expression.
 In a type switch, the cases contain types that are compared against the
 type of a specially annotated switch expression.
-The switch expression is evaluated exactly once in a switch statement.
 </p>
 
 <h4 id="Expression_switches">Expression switches</h4>
@@ -4592,27 +4589,6 @@ ExprSwitchCase = "case" ExpressionList | "default" .
 </pre>
 
 <p>
-If the switch expression evaluates to an untyped constant, it is first
-<a href="#Conversions">converted</a> to its <a href="#Constants">default type</a>;
-if it is an untyped boolean value, it is first converted to type <code>bool</code>.
-The predeclared untyped value <code>nil</code> cannot be used as a switch expression.
-</p>
-
-<p>
-If a case expression is untyped, it is first <a href="#Conversions">converted</a>
-to the type of the switch expression.
-For each (possibly converted) case expression <code>x</code> and the value <code>t</code>
-of the switch expression, <code>x == t</code> must be a valid <a href="#Comparison_operators">comparison</a>.
-</p>
-
-<p>
-In other words, the switch expression is treated as if it were used to declare and
-initialize a temporary variable <code>t</code> without explicit type; it is that
-value of <code>t</code> against which each case expression <code>x</code> is tested
-for equality.
-</p>
-
-<p>
 In a case or default clause, the last non-empty statement
 may be a (possibly <a href="#Labeled_statements">labeled</a>)
 <a href="#Fallthrough_statements">"fallthrough" statement</a> to
@@ -4624,7 +4600,7 @@ but the last clause of an expression switch.
 </p>
 
 <p>
-The switch expression may be preceded by a simple statement, which
+The expression may be preceded by a simple statement, which
 executes before the expression is evaluated.
 </p>
 
@@ -4647,13 +4623,6 @@ case x == 4: f3()
 }
 </pre>
 
-<p>
-Implementation restriction: A compiler may disallow multiple case
-expressions evaluating to the same constant.
-For instance, the current compilers disallow duplicate integer,
-floating point, or string constants in case expressions.
-</p>
-
 <h4 id="Type_switches">Type switches</h4>
 
 <p>
@@ -5486,7 +5455,7 @@ const (
 	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(z) is a (non-constant) function call
+	c5 = len([10]float64{imag(z)})   // invalid: imag(x) is a (non-constant) function call
 )
 var z complex128
 </pre>
@@ -5610,7 +5579,7 @@ s3 := append(s2, s0...)            // append a slice              s3 == []int{0,
 s4 := append(s3[3:6], s3[2:]...)   // append overlapping slice    s4 == []int{3, 5, 7, 2, 3, 5, 7, 0, 0}
 
 var t []interface{}
-t = append(t, 42, 3.1415, "foo")   //                             t == []interface{}{42, 3.1415, "foo"}
+t = append(t, 42, 3.1415, "foo")                                  t == []interface{}{42, 3.1415, "foo"}
 
 var b []byte
 b = append(b, "bar"...)            // append string contents      b == []byte{'b', 'a', 'r' }
@@ -5688,28 +5657,11 @@ The type of the arguments and return value correspond.
 For <code>complex</code>, the two arguments must be of the same
 floating-point type and the return type is the complex type
 with the corresponding floating-point constituents:
-<code>complex64</code> for <code>float32</code> arguments, and
-<code>complex128</code> for <code>float64</code> arguments.
-If one of the arguments evaluates to an untyped constant, it is first
-<a href="#Conversions">converted</a> to the type of the other argument.
-If both arguments evaluate to untyped constants, they must be non-complex
-numbers or their imaginary parts must be zero, and the return value of
-the function is an untyped complex constant.
-</p>
-
-<p>
-For <code>real</code> and <code>imag</code>, the argument must be
-of complex type, and the return type is the corresponding floating-point
-type: <code>float32</code> for a <code>complex64</code> argument, and
-<code>float64</code> for a <code>complex128</code> argument.
-If the argument evaluates to an untyped constant, it must be a number,
-and the return value of the function is an untyped floating-point constant.
-</p>
-
-<p>
-The <code>real</code> and <code>imag</code> functions together form the inverse of
-<code>complex</code>, so for a value <code>z</code> of a complex type <code>Z</code>,
-<code>z == Z(complex(real(z), imag(z)))</code>.
+<code>complex64</code> for <code>float32</code>,
+<code>complex128</code> for <code>float64</code>.
+The <code>real</code> and <code>imag</code> functions
+together form the inverse, so for a complex value <code>z</code>,
+<code>z</code> <code>==</code> <code>complex(real(z),</code> <code>imag(z))</code>.
 </p>
 
 <p>
@@ -5719,15 +5671,11 @@ value is a constant.
 
 <pre>
 var a = complex(2, -2)             // complex128
-const b = complex(1.0, -1.4)       // untyped complex constant 1 - 1.4i
+var b = complex(1.0, -1.4)         // complex128
 x := float32(math.Cos(math.Pi/2))  // float32
 var c64 = complex(5, -x)           // complex64
-const s uint = complex(1, 0)       // untyped complex constant 1 + 0i can be converted to uint
-_ = complex(1, 2<<s)               // illegal: 2 has floating-point type, cannot shift
+var im = imag(b)                   // float64
 var rl = real(c64)                 // float32
-var im = imag(a)                   // float64
-const c = imag(b)                  // untyped constant -1.4
-_ = imag(3 << s)                   // illegal: 3 has complex type, cannot shift
 </pre>
 
 <h3 id="Handling_panics">Handling panics</h3>
diff --git a/doc/gopher/README b/doc/gopher/README
index d4ca8a1..936a24c 100644
--- a/doc/gopher/README
+++ b/doc/gopher/README
@@ -1,3 +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: https://blog.golang.org/gopher
+Read this article for more details: http://blog.golang.org/gopher
diff --git a/doc/install-source.html b/doc/install-source.html
index e71fff7..7daf360 100644
--- a/doc/install-source.html
+++ b/doc/install-source.html
@@ -26,21 +26,21 @@ packages, though, read on.
 <p>
 There are two official Go compiler tool chains.
 This document focuses on the <code>gc</code> Go
-compiler and tools.
+compiler and tools (<code>6g</code>, <code>8g</code> etc.).
 For information on how to work on <code>gccgo</code>, a more traditional
 compiler using the GCC back end, see
 <a href="/doc/install/gccgo">Setting up and using gccgo</a>.
 </p>
 
 <p>
-The Go compilers support five instruction sets.
+The Go compilers support three instruction sets.
 There are important differences in the quality of the compilers for the different
 architectures.
 </p>
 
 <dl>
 <dt>
-	<code>amd64</code> (also known as <code>x86-64</code>)
+	<code>amd64</code> (a.k.a. <code>x86-64</code>); <code>6g,6l,6c,6a</code>
 </dt>
 <dd>
 	A mature implementation. The compiler has an effective
@@ -48,28 +48,16 @@ architectures.
 	<code>gccgo</code> can do noticeably better sometimes).
 </dd>
 <dt>
-	<code>386</code> (<code>x86</code> or <code>x86-32</code>)
+	<code>386</code> (a.k.a. <code>x86</code> or <code>x86-32</code>); <code>8g,8l,8c,8a</code>
 </dt>
 <dd>
 	Comparable to the <code>amd64</code> port.
 </dd>
 <dt>
-	<code>arm</code> (<code>ARM</code>)
+	<code>arm</code> (a.k.a. <code>ARM</code>); <code>5g,5l,5c,5a</code>
 </dt>
 <dd>
-	Supports Linux, FreeBSD, NetBSD and Darwin binaries. Less widely used than the other ports.
-</dd>
-<dt>
-	<code>arm64</code> (<code>AArch64</code>)
-</dt>
-<dd>
-	Supports Linux and Darwin binaries. New in 1.5 and not as well excercised as other ports.
-</dd>
-<dt>
-	<code>ppc64, ppc64le</code> (64-bit PowerPC big- and little-endian)
-</dt>
-<dd>
-	Supports Linux binaries. New in 1.5 and not as well excercised as other ports.
+	Supports Linux, FreeBSD and NetBSD binaries. Less widely used than the other ports.
 </dd>
 </dl>
 
@@ -89,60 +77,14 @@ The full set of supported combinations is listed in the discussion of
 
 </div>
 
-<h2 id="go14">Install Go compiler binaries</h2>
-
-<p>
-The Go tool chain is written in Go. To build it, you need a Go compiler installed.
-The scripts that do the initial build of the tools look for an existing Go tool
-chain in <code>$HOME/go1.4</code>.
-(This path may be overridden by setting the <code>GOROOT_BOOTSTRAP</code>
-environment variable.)
-</p>
-
-<p>
-Build the tools with Go version 1.4 or a point release (1.4.1, 1.4.2 etc.).
-Go 1.4 binaries can be found at <a href="/dl/">the downloads page</a>.
-</p>
-
-<p>
-Download the zip or tarball of Go 1.4 for your platform and extract it to
-<code>$HOME/go1.4</code> (or your nominated <code>GOROOT_BOOTSTRAP</code>
-location).
-</p>
+<h2 id="ctools">Install C tools, if needed</h2>
 
 <p>
-If you want to install Go 1.5 on a system that is not supported by Go 1.4 (such
-as <code>linux/ppc64</code>) you can either use
-<a href="/src/bootstrap.bash">bootstrap.bash</a> on a system that can bootstrap Go
-1.5 normally, or bootstrap with gccgo 5.
+The Go tool chain is written in C. To build it, you need a C compiler installed. 
+Please refer to the <a href="//golang.org/wiki/InstallFromSource#install-c-tools">InstallFromSource</a>
+page on the Go community Wiki for operating system specific instructions.
 </p>
 
-<p>
-When run as (for example)
-</p>
-
-<pre>
-$ GOOS=linux GOARCH=ppc64 ./bootstrap.bash
-</pre>
-
-<p>
-<code>bootstrap.bash</code> cross-compiles a toolchain for that <code>GOOS/GOARCH</code>
-combination, leaving the resulting tree in <code>../../go-${GOOS}-${GOARCH}-bootstrap</code>.
-That tree can be copied to a machine of the given target type
-and used as <code>GOROOT_BOOTSTRAP</code> to bootstrap a local build.
-</p>
-
-<p>
-To use gccgo, you need to arrange for <code>$GOROOT_BOOSTRAP/bin/go</code> to be
-the go tool that comes as part of gccgo 5. For example on Ubuntu Vivid:
-</p>
-
-<pre>
-$ sudo apt-get install gccgo-5
-$ sudo update-alternatives --set go /usr/bin/go-5
-$ GOROOT_BOOTSTRAP=/usr ./make.bash
-</pre>
-
 <h2 id="git">Install Git, if needed</h2>
 
 <p>
@@ -167,7 +109,7 @@ Then clone the repository and check out the latest release tag:</p>
 <pre>
 $ git clone https://go.googlesource.com/go
 $ cd go
-$ git checkout go1.5
+$ git checkout go1.4.1
 </pre>
 
 <h2 id="head">(Optional) Switch to the master branch</h2>
@@ -189,7 +131,7 @@ To build the Go distribution, run
 </p>
 
 <pre>
-$ cd src
+$ cd go/src
 $ ./all.bash
 </pre>
 
@@ -346,7 +288,7 @@ New releases are announced on the
 <a href="//groups.google.com/group/golang-announce">golang-announce</a>
 mailing list.
 Each announcement mentions the latest release tag, for instance,
-<code>go1.5</code>.
+<code>go1.4</code>.
 </p>
 
 <p>
@@ -399,13 +341,12 @@ These default to the values of <code>$GOHOSTOS</code> and
 
 <p>
 Choices for <code>$GOOS</code> are
-<code>darwin</code> (Mac OS X 10.7 and above and iOS), <code>dragonfly</code>, <code>freebsd</code>,
-<code>linux</code>, <code>netbsd</code>, <code>openbsd</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>, <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), <code>arm</code> (32-bit ARM), <code>arm64</code> (64-bit ARM),
-<code>ppc64le</code> (PowerPC 64-bit, little-endian), and <code>ppc64</code> (PowerPC 64-bit, big-endian).
+<code>386</code> (32-bit x86), and <code>arm</code> (32-bit ARM).
 The valid combinations of <code>$GOOS</code> and <code>$GOARCH</code> are:
 <table cellpadding="0">
 <tr>
@@ -418,10 +359,7 @@ 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>darwin</code></td> <td><code>arm</code></td>
-</tr>
-<tr>
-<td></td><td><code>darwin</code></td> <td><code>arm64</code></td>
+<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>
@@ -445,15 +383,6 @@ The valid combinations of <code>$GOOS</code> and <code>$GOARCH</code> are:
 <td></td><td><code>linux</code></td> <td><code>arm</code></td>
 </tr>
 <tr>
-<td></td><td><code>linux</code></td> <td><code>arm64</code></td>
-</tr>
-<tr>
-<td></td><td><code>linux</code></td> <td><code>ppc64</code></td>
-</tr>
-<tr>
-<td></td><td><code>linux</code></td> <td><code>ppc64le</code></td>
-</tr>
-<tr>
 <td></td><td><code>netbsd</code></td> <td><code>386</code></td>
 </tr>
 <tr>
@@ -469,9 +398,6 @@ The valid combinations of <code>$GOOS</code> and <code>$GOARCH</code> are:
 <td></td><td><code>openbsd</code></td> <td><code>amd64</code></td>
 </tr>
 <tr>
-<td></td><td><code>openbsd</code></td> <td><code>arm</code></td>
-</tr>
-<tr>
 <td></td><td><code>plan9</code></td> <td><code>386</code></td>
 </tr>
 <tr>
@@ -487,7 +413,6 @@ The valid combinations of <code>$GOOS</code> and <code>$GOARCH</code> are:
 <td></td><td><code>windows</code></td> <td><code>amd64</code></td>
 </tr>
 </table>
-<br>
 
 <li><code>$GOHOSTOS</code> and <code>$GOHOSTARCH</code>
 <p>
@@ -517,7 +442,7 @@ installs all commands there.
 <li><code>$GO386</code> (for <code>386</code> only, default is auto-detected
 if built on either <code>386</code> or <code>amd64</code>, <code>387</code> otherwise)
 <p>
-This controls the code generated by gc to use either the 387 floating-point unit
+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
 floating point computations.
 </p>
diff --git a/doc/install.html b/doc/install.html
index e9f0f0d..9561fdd 100644
--- a/doc/install.html
+++ b/doc/install.html
@@ -3,12 +3,10 @@
 	"Path":  "/doc/install"
 }-->
 
-<div class="hideFromDownload">
-
 <h2 id="download">Download the Go distribution</h2>
 
 <p>
-<a href="https://golang.org/dl/" id="start" class="download">
+<a href="https://golang.org/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>
@@ -16,10 +14,9 @@
 
 <p>
 <a href="https://golang.org/dl/" target="_blank">Official binary
-distributions</a> are available for the FreeBSD (release 8-STABLE and above),
-Linux, Mac OS X (10.7 and above), and Windows operating systems and
-the 32-bit (<code>386</code>) and 64-bit (<code>amd64</code>) x86 processor
-architectures.
+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>
 
 <p>
@@ -33,11 +30,11 @@ system and architecture, try
 <h2 id="requirements">System requirements</h2>
 
 <p>
-Go binary distributions are available for these supported operating systems and architectures.
-Please ensure your system meets these requirements before proceeding.
-If your OS or architecture is not on the list, you may be able to
-<a href="/doc/install/source">install from source</a> or
-<a href="/doc/install/gccgo">use gccgo instead</a>.
+The <code>gc</code> compiler supports the following operating systems and
+architectures. Please ensure your system meets these requirements before
+proceeding. If your OS or architecture is not on the list, it's possible that
+<code>gccgo</code> might support your setup; see
+<a href="/doc/install/gccgo">Setting up and using gccgo</a> for details.
 </p>
 
 <table class="codetable" frame="border" summary="requirements">
@@ -47,9 +44,9 @@ If your OS or architecture is not on the list, you may be able to
 <th align="center">Notes</th>
 </tr>
 <tr><td colspan="3"><hr></td></tr>
-<tr><td>FreeBSD 8-STABLE or later</td> <td>amd64</td> <td>Debian GNU/kFreeBSD not supported</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; install from source for ARM</td></tr>
-<tr><td>Mac OS X 10.7 or later</td> <td>amd64</td> <td>use the clang or gcc<sup>†</sup> that comes with Xcode<sup>‡</sup></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 XP or later</td> <td>amd64, 386</td> <td>use MinGW gcc<sup>†</sup>. No need for cygwin or msys.</td></tr>
 </table>
 
@@ -62,8 +59,6 @@ installed Xcode 4.3+, you can install it from the Components tab of the
 Downloads preferences panel.
 </p>
 
-</div><!-- hideFromDownload -->
-
 
 <h2 id="install">Install the Go tools</h2>
 
@@ -72,8 +67,6 @@ If you are upgrading from an older version of Go you must
 first <a href="#uninstall">remove the existing version</a>.
 </p>
 
-<div id="tarballInstructions">
-
 <h3 id="tarball">Linux, Mac OS X, and FreeBSD tarballs</h3>
 
 <p>
@@ -83,10 +76,10 @@ and extract it into <code>/usr/local</code>, creating a Go tree in
 </p>
 
 <pre>
-tar -C /usr/local -xzf <span class="downloadFilename">go$VERSION.$OS-$ARCH.tar.gz</span>
+tar -C /usr/local -xzf go$VERSION.$OS-$ARCH.tar.gz
 </pre>
 
-<p class="hideFromDownload">
+<p>
 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>.
@@ -131,10 +124,6 @@ export PATH=$PATH:$GOROOT/bin
 location.
 </p>
 
-</div><!-- tarballInstructions -->
-
-<div id="darwinPackageInstructions">
-
 <h3 id="osx">Mac OS X package installer</h3>
 
 <p>
@@ -149,21 +138,15 @@ The package should put the <code>/usr/local/go/bin</code> directory in your
 Terminal sessions for the change to take effect.
 </p>
 
-</div><!-- darwinPackageInstructions -->
-
-<div id="windowsInstructions">
-
 <h3 id="windows">Windows</h3>
 
-<p class="hideFromDownload">
+<p>
 The Go project provides two installation options for Windows users
 (besides <a href="/doc/install/source">installing from source</a>):
 a zip archive that requires you to set some environment variables and an
 MSI installer that configures your installation automatically.
 </p>
 
-<div id="windowsInstallerInstructions">
-
 <h4 id="windows_msi">MSI installer</h4>
 
 <p>
@@ -178,10 +161,6 @@ The installer should put the <code>c:\Go\bin</code> directory in your
 command prompts for the change to take effect.
 </p>
 
-</div><!-- windowsInstallerInstructions -->
-
-<div id="windowsZipInstructions">
-
 <h4 id="windows_zip">Zip archive</h4>
 
 <p>
@@ -197,8 +176,6 @@ you must set the <code>GOROOT</code> environment variable to your chosen path.
 Add the <code>bin</code> subdirectory of your Go root (for example, <code>c:\Go\bin</code>) to your <code>PATH</code> environment variable.
 </p>
 
-</div><!-- windowsZipInstructions -->
-
 <h4 id="windows_env">Setting environment variables under Windows</h4>
 
 <p>
@@ -208,38 +185,15 @@ versions of Windows provide this control panel through the "Advanced System
 Settings" option inside the "System" control panel.
 </p>
 
-</div><!-- windowsInstructions -->
-
 
 <h2 id="testing">Test your installation</h2>
 
 <p>
-Check that Go is installed correctly by setting up a workspace
-and building a simple program, as follows.
-</p>
-
-<p>
-Create a directory to contain your <a href="code.html#Workspaces">workspace</a>,
-<code>$HOME/work</code> for example, and set the <code>GOPATH</code> environment
-variable to point to that location.
-</p>
-
-<pre>
-$ <b>export GOPATH=$HOME/work</b>
-</pre>
-
-<p>
-You should put the above command in your shell startup script
-(<code>$HOME/.profile</code> for example) or, if you use Windows,
-follow the <a href="#windows_env">instructions above</a> to set the
-<code>GOPATH</code> environment variable on your system.
+Check that Go is installed correctly by building a simple program, as follows.
 </p>
 
 <p>
-Next, make the directories <code>src/github.com/user/hello</code> inside your
-workspace (if you use GitHub, substitute your user name for <code>user</code>),
-and inside the <code>hello</code> directory create a file named <code>hello.go</code>
-with the following contents:
+Create a file named <code>hello.go</code> and put the following program in it:
 </p>
 
 <pre>
@@ -253,32 +207,29 @@ func main() {
 </pre>
 
 <p>
-Then compile it with the <code>go</code> tool:
+Then run it with the <code>go</code> tool:
 </p>
 
 <pre>
-$ <b>go install github.com/user/hello</b>
+$ go run hello.go
+hello, world
 </pre>
 
 <p>
-The above command will put an executable command named <code>hello</code> 
-(or <code>hello.exe</code>) inside the <code>bin</code> directory of your workspace.
-Execute the command to see the greeting:
+If you see the "hello, world" message then your Go installation is working.
 </p>
 
-<pre>
-$ <b>$GOPATH/bin/hello</b>
-hello, world
-</pre>
+
+<h2 id="gopath">Set up your work environment</h2>
 
 <p>
-If you see the "hello, world" message then your Go installation is working.
+You're almost done.
+You just need to set up your environment.
 </p>
 
 <p>
-Before rushing off to write Go code please read the
-<a href="/doc/code.html">How to Write Go Code</a> document,
-which describes some essential concepts about using the Go tools.
+Read the <a href="/doc/code.html">How to Write Go Code</a> document,
+which provides <b>essential setup instructions</b> for using the Go tools.
 </p>
 
 
diff --git a/doc/logo-153x55.png b/doc/logo-153x55.png
new file mode 100644
index 0000000..8ec22aa
Binary files /dev/null and b/doc/logo-153x55.png differ
diff --git a/doc/play/peano.go b/doc/play/peano.go
index 214fe1b..c1ee5ad 100644
--- a/doc/play/peano.go
+++ b/doc/play/peano.go
@@ -3,9 +3,9 @@
 // (the nodes are the data).
 // http://en.wikipedia.org/wiki/Peano_axioms
 
-// This program demonstrates that Go's automatic
-// stack management can handle heavily recursive
-// computations.
+// This program demonstrates the power of Go's
+// segmented stacks when doing massively
+// recursive computations.
 
 package main
 
diff --git a/doc/progs/cgo1.go b/doc/progs/cgo1.go
index d559e13..805fe3c 100644
--- a/doc/progs/cgo1.go
+++ b/doc/progs/cgo1.go
@@ -1,7 +1,8 @@
+// skip
+
 // 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 rand
 
 /*
diff --git a/doc/progs/cgo2.go b/doc/progs/cgo2.go
index da07aa4..b9e9f7d 100644
--- a/doc/progs/cgo2.go
+++ b/doc/progs/cgo2.go
@@ -1,7 +1,8 @@
+// skip
+
 // 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 rand2
 
 /*
diff --git a/doc/progs/cgo3.go b/doc/progs/cgo3.go
index d5cedf4..c4f4791 100644
--- a/doc/progs/cgo3.go
+++ b/doc/progs/cgo3.go
@@ -1,7 +1,8 @@
+// skip
+
 // 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 print
 
 // #include <stdio.h>
diff --git a/doc/progs/cgo4.go b/doc/progs/cgo4.go
index dbb07e8..30b8935 100644
--- a/doc/progs/cgo4.go
+++ b/doc/progs/cgo4.go
@@ -1,7 +1,8 @@
+// skip
+
 // 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 print
 
 // #include <stdio.h>
diff --git a/doc/progs/defer.go b/doc/progs/defer.go
index 2e11020..006a474 100644
--- a/doc/progs/defer.go
+++ b/doc/progs/defer.go
@@ -1,3 +1,5 @@
+// cmpout
+
 // 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.
diff --git a/doc/progs/defer.out b/doc/progs/defer.out
new file mode 100644
index 0000000..0cdf53a
--- /dev/null
+++ b/doc/progs/defer.out
@@ -0,0 +1,3 @@
+0
+3210
+2
diff --git a/doc/progs/defer2.go b/doc/progs/defer2.go
index cad66b0..ff7eaf9 100644
--- a/doc/progs/defer2.go
+++ b/doc/progs/defer2.go
@@ -1,3 +1,5 @@
+// cmpout
+
 // 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.
diff --git a/doc/progs/defer2.out b/doc/progs/defer2.out
new file mode 100644
index 0000000..6110685
--- /dev/null
+++ b/doc/progs/defer2.out
@@ -0,0 +1,12 @@
+Calling g.
+Printing in g 0
+Printing in g 1
+Printing in g 2
+Printing in g 3
+Panicking!
+Defer in g 3
+Defer in g 2
+Defer in g 1
+Defer in g 0
+Recovered in f 4
+Returned normally from f.
diff --git a/doc/progs/eff_bytesize.go b/doc/progs/eff_bytesize.go
index b459611..a0c3d50 100644
--- a/doc/progs/eff_bytesize.go
+++ b/doc/progs/eff_bytesize.go
@@ -1,3 +1,5 @@
+// cmpout
+
 // 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.
diff --git a/doc/progs/eff_bytesize.out b/doc/progs/eff_bytesize.out
new file mode 100644
index 0000000..df763f3
--- /dev/null
+++ b/doc/progs/eff_bytesize.out
@@ -0,0 +1 @@
+1.00YB 9.09TB
diff --git a/doc/progs/eff_qr.go b/doc/progs/eff_qr.go
index 89de459..861131d 100644
--- a/doc/progs/eff_qr.go
+++ b/doc/progs/eff_qr.go
@@ -1,3 +1,5 @@
+// compile
+
 // 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.
diff --git a/doc/progs/eff_sequence.go b/doc/progs/eff_sequence.go
index 11c885a..c9b18ba 100644
--- a/doc/progs/eff_sequence.go
+++ b/doc/progs/eff_sequence.go
@@ -1,3 +1,5 @@
+// cmpout
+
 // 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.
diff --git a/doc/progs/eff_sequence.out b/doc/progs/eff_sequence.out
new file mode 100644
index 0000000..fd01a7d
--- /dev/null
+++ b/doc/progs/eff_sequence.out
@@ -0,0 +1 @@
+[-1 2 6 16 44]
diff --git a/doc/progs/eff_unused1.go b/doc/progs/eff_unused1.go
index 285d55e..f990a19 100644
--- a/doc/progs/eff_unused1.go
+++ b/doc/progs/eff_unused1.go
@@ -1,3 +1,5 @@
+// skip
+
 package main
 
 import (
diff --git a/doc/progs/eff_unused2.go b/doc/progs/eff_unused2.go
index 92eb74e..3e6e041 100644
--- a/doc/progs/eff_unused2.go
+++ b/doc/progs/eff_unused2.go
@@ -1,3 +1,5 @@
+// compile
+
 package main
 
 import (
diff --git a/doc/progs/error.go b/doc/progs/error.go
index e776cdb..57854c5 100644
--- a/doc/progs/error.go
+++ b/doc/progs/error.go
@@ -1,3 +1,5 @@
+// compile
+
 // 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.
diff --git a/doc/progs/error2.go b/doc/progs/error2.go
index 2b0e0c3..aad1dc8 100644
--- a/doc/progs/error2.go
+++ b/doc/progs/error2.go
@@ -1,3 +1,5 @@
+// compile
+
 // 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.
diff --git a/doc/progs/error3.go b/doc/progs/error3.go
index e4e57e0..9f1b300 100644
--- a/doc/progs/error3.go
+++ b/doc/progs/error3.go
@@ -1,3 +1,5 @@
+// compile
+
 // 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.
diff --git a/doc/progs/error4.go b/doc/progs/error4.go
index 8b2f304..d40fc6e 100644
--- a/doc/progs/error4.go
+++ b/doc/progs/error4.go
@@ -1,3 +1,5 @@
+// compile
+
 // 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.
diff --git a/doc/progs/go1.go b/doc/progs/go1.go
index 50fd934..a4dc64d 100644
--- a/doc/progs/go1.go
+++ b/doc/progs/go1.go
@@ -1,3 +1,6 @@
+// compile
+// this file will output a list of filenames in cwd, not suitable for cmpout
+
 // 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.
diff --git a/doc/progs/gobs1.go b/doc/progs/gobs1.go
index 7077ca1..d95f765 100644
--- a/doc/progs/gobs1.go
+++ b/doc/progs/gobs1.go
@@ -1,3 +1,5 @@
+// compile
+
 // 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.
diff --git a/doc/progs/gobs2.go b/doc/progs/gobs2.go
index 85bb41c..acd1838 100644
--- a/doc/progs/gobs2.go
+++ b/doc/progs/gobs2.go
@@ -1,3 +1,5 @@
+// compile
+
 // 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.
diff --git a/doc/progs/image_draw.go b/doc/progs/image_draw.go
index bb73c8a..0a1f7ac 100644
--- a/doc/progs/image_draw.go
+++ b/doc/progs/image_draw.go
@@ -1,3 +1,5 @@
+// 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.
diff --git a/doc/progs/image_package1.go b/doc/progs/image_package1.go
index c4c401e..d331834 100644
--- a/doc/progs/image_package1.go
+++ b/doc/progs/image_package1.go
@@ -1,3 +1,5 @@
+// cmpout
+
 // 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.
diff --git a/doc/progs/image_package1.out b/doc/progs/image_package1.out
new file mode 100644
index 0000000..809b31b
--- /dev/null
+++ b/doc/progs/image_package1.out
@@ -0,0 +1 @@
+X is 2 Y is 1
diff --git a/doc/progs/image_package2.go b/doc/progs/image_package2.go
index fcb5d9f..e5b78b4 100644
--- a/doc/progs/image_package2.go
+++ b/doc/progs/image_package2.go
@@ -1,3 +1,5 @@
+// cmpout
+
 // 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.
diff --git a/doc/progs/image_package2.out b/doc/progs/image_package2.out
new file mode 100644
index 0000000..616d307
--- /dev/null
+++ b/doc/progs/image_package2.out
@@ -0,0 +1 @@
+3 4 false
diff --git a/doc/progs/image_package3.go b/doc/progs/image_package3.go
index 13d0f08..95d72a0 100644
--- a/doc/progs/image_package3.go
+++ b/doc/progs/image_package3.go
@@ -1,3 +1,5 @@
+// cmpout
+
 // 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.
diff --git a/doc/progs/image_package3.out b/doc/progs/image_package3.out
new file mode 100644
index 0000000..3fe35de
--- /dev/null
+++ b/doc/progs/image_package3.out
@@ -0,0 +1 @@
+3 4 true
diff --git a/doc/progs/image_package4.go b/doc/progs/image_package4.go
index c46fddf..ec0e461 100644
--- a/doc/progs/image_package4.go
+++ b/doc/progs/image_package4.go
@@ -1,3 +1,5 @@
+// cmpout
+
 // 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.
diff --git a/doc/progs/image_package4.out b/doc/progs/image_package4.out
new file mode 100644
index 0000000..cb1b777
--- /dev/null
+++ b/doc/progs/image_package4.out
@@ -0,0 +1 @@
+image.Point{X:2, Y:1}
diff --git a/doc/progs/image_package5.go b/doc/progs/image_package5.go
index 0bb5c76..b9e27d6 100644
--- a/doc/progs/image_package5.go
+++ b/doc/progs/image_package5.go
@@ -1,3 +1,5 @@
+// cmpout
+
 // 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.
diff --git a/doc/progs/image_package5.out b/doc/progs/image_package5.out
new file mode 100644
index 0000000..2da80c1
--- /dev/null
+++ b/doc/progs/image_package5.out
@@ -0,0 +1 @@
+{255 0 0 255}
diff --git a/doc/progs/image_package6.go b/doc/progs/image_package6.go
index 62eeecd..5e6eefa 100644
--- a/doc/progs/image_package6.go
+++ b/doc/progs/image_package6.go
@@ -1,3 +1,5 @@
+// cmpout
+
 // 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.
diff --git a/doc/progs/image_package6.out b/doc/progs/image_package6.out
new file mode 100644
index 0000000..fcd13c0
--- /dev/null
+++ b/doc/progs/image_package6.out
@@ -0,0 +1,2 @@
+8 4
+true
diff --git a/doc/progs/interface.go b/doc/progs/interface.go
index c2925d5..6972b72 100644
--- a/doc/progs/interface.go
+++ b/doc/progs/interface.go
@@ -1,3 +1,5 @@
+// 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.
diff --git a/doc/progs/interface2.go b/doc/progs/interface2.go
index a541d94..85e7d51 100644
--- a/doc/progs/interface2.go
+++ b/doc/progs/interface2.go
@@ -1,3 +1,5 @@
+// cmpout
+
 // 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.
diff --git a/doc/progs/interface2.out b/doc/progs/interface2.out
new file mode 100644
index 0000000..085bd01
--- /dev/null
+++ b/doc/progs/interface2.out
@@ -0,0 +1 @@
+type: float64
diff --git a/doc/progs/json1.go b/doc/progs/json1.go
index 9e10f47..887d7d1 100644
--- a/doc/progs/json1.go
+++ b/doc/progs/json1.go
@@ -1,3 +1,5 @@
+// run
+
 // 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.
diff --git a/doc/progs/json2.go b/doc/progs/json2.go
index 6089ae6..f358fea 100644
--- a/doc/progs/json2.go
+++ b/doc/progs/json2.go
@@ -1,3 +1,5 @@
+// cmpout
+
 // 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.
diff --git a/doc/progs/json2.out b/doc/progs/json2.out
new file mode 100644
index 0000000..8f2dea5
--- /dev/null
+++ b/doc/progs/json2.out
@@ -0,0 +1,2 @@
+the circle's area 24.227111172875365
+the reciprocal of i is 0.3601008282319049
diff --git a/doc/progs/json3.go b/doc/progs/json3.go
index a04fdfa..41eb373 100644
--- a/doc/progs/json3.go
+++ b/doc/progs/json3.go
@@ -1,3 +1,5 @@
+// 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.
diff --git a/doc/progs/json4.go b/doc/progs/json4.go
index 4926302..ee38f31 100644
--- a/doc/progs/json4.go
+++ b/doc/progs/json4.go
@@ -1,3 +1,5 @@
+// run
+
 // 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.
diff --git a/doc/progs/json5.go b/doc/progs/json5.go
index 6d7a4ca..9ab972d 100644
--- a/doc/progs/json5.go
+++ b/doc/progs/json5.go
@@ -1,3 +1,5 @@
+// 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.
diff --git a/doc/progs/run b/doc/progs/run
new file mode 100755
index 0000000..6e680b8
--- /dev/null
+++ b/doc/progs/run
@@ -0,0 +1,125 @@
+#!/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.
+
+set -e
+
+goos=$(go env GOOS)
+
+defer_panic_recover="
+	defer
+	defer2
+"
+
+effective_go="
+	eff_bytesize
+	eff_qr
+	eff_sequence
+	eff_unused2
+"
+
+error_handling="
+	error
+	error2
+	error3
+	error4
+"
+
+law_of_reflection="
+	interface
+	interface2
+"
+
+c_go_cgo="
+	cgo1
+	cgo2
+	cgo3
+	cgo4
+"
+# cgo1 and cgo2 don't run on freebsd, srandom has a different signature
+if [ "$goos" == "freebsd" ]; then
+	c_go_cgo="cgo3 cgo4"
+fi
+# cgo1 and cgo2 don't run on netbsd, srandom has a different signature
+# cgo3 and cgo4 don't run on netbsd, since cgo cannot handle stdout correctly
+if [ "$goos" == "netbsd" ]; then
+	c_go_cgo=""
+fi
+# cgo3 and cgo4 don't run on openbsd, since cgo cannot handle stdout correctly
+if [ "$goos" == "openbsd" ]; then
+	c_go_cgo="cgo1 cgo2"
+fi
+if [ "$CGO_ENABLED" != 1 ]; then
+	c_go_cgo=""
+fi
+
+timeout="
+	timeout1
+	timeout2
+"
+
+gobs="
+	gobs1
+	gobs2
+"
+
+json="
+	json1
+	json2
+	json3
+	json4
+	json5
+"
+
+image_package="
+	image_package1
+	image_package2
+	image_package3
+	image_package4
+	image_package5
+	image_package6
+"
+
+all=$(echo $defer_panic_recover $effective_go $error_handling $law_of_reflection $c_go_cgo $timeout $gobs $json $image_package slices go1)
+
+for i in $all; do
+	go build $i.go
+done
+
+# Write to temporary file to avoid mingw bash bug.
+TMPFILE="${TMPDIR:-/tmp}/gotest3.$USER"
+
+function testit {
+	./$1 >"$TMPFILE" 2>&1 || true
+	x=$(echo $(cat "$TMPFILE")) # extra echo canonicalizes
+	if ! echo "$x" | grep "$2" > /dev/null
+	then
+		echo $1 failed: '"'$x'"' is not '"'$2'"'
+	fi
+}
+
+
+testit defer '^0 3210 2$'
+testit defer2 '^Calling g. Printing in g 0 Printing in g 1 Printing in g 2 Printing in g 3 Panicking! Defer in g 3 Defer in g 2 Defer in g 1 Defer in g 0 Recovered in f 4 Returned normally from f.$'
+
+testit eff_bytesize '^1.00YB 9.09TB$'
+testit eff_sequence '^\[-1 2 6 16 44\]$'
+
+testit go1 '^Christmas is a holiday: true Sleeping for 0.123s.*go1.go already exists$'
+
+testit interface2 "^type: float64$"
+
+testit json1 "^$"
+testit json2 "the reciprocal of i is"
+testit json3 "Age is int 6"
+testit json4 "^$"
+
+testit image_package1 "^X is 2 Y is 1$"
+testit image_package2 "^3 4 false$"
+testit image_package3 "^3 4 true$"
+testit image_package4 "^image.Point{X:2, Y:1}$"
+testit image_package5 "^{255 0 0 255}$"
+testit image_package6 "^8 4 true$"
+
+rm -f $all "$TMPFILE"
diff --git a/doc/progs/slices.go b/doc/progs/slices.go
index 967a3e7..f9af5fe 100644
--- a/doc/progs/slices.go
+++ b/doc/progs/slices.go
@@ -1,3 +1,5 @@
+// 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.
diff --git a/doc/progs/timeout1.go b/doc/progs/timeout1.go
index 353ba69..fbc39ca 100644
--- a/doc/progs/timeout1.go
+++ b/doc/progs/timeout1.go
@@ -1,7 +1,8 @@
+// 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.
-
 package timeout
 
 import (
diff --git a/doc/progs/timeout2.go b/doc/progs/timeout2.go
index b0d34ea..a12bc2a 100644
--- a/doc/progs/timeout2.go
+++ b/doc/progs/timeout2.go
@@ -1,7 +1,8 @@
+// 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.
-
 package query
 
 type Conn string
diff --git a/doc/progs/update.bash b/doc/progs/update.bash
new file mode 100755
index 0000000..d4ecfbe
--- /dev/null
+++ b/doc/progs/update.bash
@@ -0,0 +1,15 @@
+#!/usr/bin/env bash
+# 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.
+
+set -e
+
+rm -f *.out *.rej *.orig [568].out
+
+for i in *.go; do
+	if grep -q '^// cmpout$' $i; then
+		echo $i
+		go run $i &> ${i/.go/.out}
+	fi
+done
diff --git a/doc/root.html b/doc/root.html
index 1217368..3c6de2e 100644
--- a/doc/root.html
+++ b/doc/root.html
@@ -53,7 +53,7 @@ simple, reliable, and efficient software.
 
 <div id="gopher"></div>
 
-<a href="https://golang.org/dl/" id="start">
+<a href="/doc/install" id="start">
 <span class="big">Download Go</span>
 <span class="desc">
 Binary distributions available for<br>
diff --git a/doc/sieve.gif b/doc/sieve.gif
new file mode 100644
index 0000000..8018ae2
Binary files /dev/null and b/doc/sieve.gif differ
diff --git a/include/README b/include/README
new file mode 100644
index 0000000..b8fb523
--- /dev/null
+++ b/include/README
@@ -0,0 +1,6 @@
+The header files under this directory are strictly internal to the gc
+toolchain, so please don't copy them to the system include file
+directory (/usr/include, /usr/local/include, etc.)
+
+Also note that they must be kept as is in $GOROOT/include, or cmd/dist
+will malfunction.
diff --git a/include/ar.h b/include/ar.h
new file mode 100644
index 0000000..d5636b3
--- /dev/null
+++ b/include/ar.h
@@ -0,0 +1,47 @@
+// Inferno utils/include/ar.h
+// http://code.google.com/p/inferno-os/source/browse/utils/include/ar.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.
+
+#define	ARMAG	"!<arch>\n"
+#define	SARMAG	8
+
+#define	ARFMAG	"`\n"
+#define	SARNAME	16
+
+struct	ar_hdr
+{
+	char	name[SARNAME];
+	char	date[12];
+	char	uid[6];
+	char	gid[6];
+	char	mode[8];
+	char	size[10];
+	char	fmag[2];
+};
+#define	SAR_HDR	(SARNAME+44)
diff --git a/include/bio.h b/include/bio.h
new file mode 100644
index 0000000..982b881
--- /dev/null
+++ b/include/bio.h
@@ -0,0 +1,144 @@
+/*
+http://code.google.com/p/inferno-os/source/browse/include/bio.h
+
+	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+	Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).  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.
+*/
+
+#ifndef _BIO_H_
+#define _BIO_H_ 1
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#ifdef AUTOLIB
+AUTOLIB(bio)
+#endif
+
+typedef	struct	Biobuf	Biobuf;
+
+enum
+{
+	Bsize		= 8*1024,
+	Bungetsize	= 4,		/* space for ungetc */
+	Bmagic		= 0x314159,
+	Beof		= -1,
+	Bbad		= -2,
+
+	Binactive	= 0,		/* states */
+	Bractive,
+	Bwactive,
+	Bracteof,
+
+	Bend
+};
+
+struct	Biobuf
+{
+	int	icount;		/* neg num of bytes at eob */
+	int	ocount;		/* num of bytes at bob */
+	int	rdline;		/* num of bytes after rdline */
+	int	runesize;	/* num of bytes of last getrune */
+	int	state;		/* r/w/inactive */
+	int	fid;		/* open file */
+	int	flag;		/* magic if malloc'ed */
+	vlong	offset;		/* offset of buffer in file */
+	int	bsize;		/* size of buffer */
+	unsigned char*	bbuf;		/* pointer to beginning of buffer */
+	unsigned char*	ebuf;		/* pointer to end of buffer */
+	unsigned char*	gbuf;		/* pointer to good data in buf */
+	unsigned char	b[Bungetsize+Bsize];
+};
+
+/*
+ * These macros get 1-, 2-, and 4-byte integer values by reading the
+ * next few bytes in little-endian order.
+ */
+#define	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)\
+	(int)((bp)->icount<=-4?((bp)->icount+=4,((bp)->ebuf[(bp)->icount-4])|((bp)->ebuf[(bp)->icount-3]<<8)|((bp)->ebuf[(bp)->icount-2]<<16)|((uint32)(bp)->ebuf[(bp)->icount-1]<<24)):Bgetle4((bp)))
+
+/*
+ * These macros put 1-, 2-, and 4-byte integer values by writing the
+ * next few bytes in little-endian order.
+ */
+#define	BPUTC(bp,c)\
+	((bp)->ocount?(bp)->ebuf[(bp)->ocount++]=(unsigned char)(c),0:Bputc((bp),(c)))
+#define	BPUTLE2(bp,c)\
+	((bp)->ocount<=-2?(bp)->ocount+=2,(bp)->ebuf[(bp)->ocount-2]=(unsigned char)(c),(bp)->ebuf[(bp)->ocount-1]=(unsigned char)(c>>8),0:Bputle2((bp),(c)))
+#define	BPUTLE4(bp,c)\
+	((bp)->ocount<=-4?(bp)->ocount+=4,(bp)->ebuf[(bp)->ocount-4]=(unsigned char)(c),(bp)->ebuf[(bp)->ocount-3]=(unsigned char)(c>>8),(bp)->ebuf[(bp)->ocount-2]=(unsigned char)(c>>16),(bp)->ebuf[(bp)->ocount-1]=(unsigned char)(c>>24),0:Bputle4((bp),(c)))
+
+#define	BOFFSET(bp)\
+	(((bp)->state==Bractive)?\
+		(bp)->offset + (bp)->icount:\
+	(((bp)->state==Bwactive)?\
+		(bp)->offset + ((bp)->bsize + (bp)->ocount):\
+		-1))
+#define	BLINELEN(bp)\
+	(bp)->rdline
+#define	BFILDES(bp)\
+	(bp)->fid
+
+int	Bbuffered(Biobuf*);
+Biobuf*	Bfdopen(int, int);
+int	Bfildes(Biobuf*);
+int	Bflush(Biobuf*);
+int	Bgetc(Biobuf*);
+int	Bgetle2(Biobuf*);
+int	Bgetle4(Biobuf*);
+int	Bgetd(Biobuf*, double*);
+long	Bgetrune(Biobuf*);
+int	Binit(Biobuf*, int, int);
+int	Binits(Biobuf*, int, int, unsigned char*, int);
+int	Blinelen(Biobuf*);
+vlong	Boffset(Biobuf*);
+Biobuf*	Bopen(char*, int);
+int	Bprint(Biobuf*, char*, ...);
+int	Bputc(Biobuf*, int);
+int	Bputle2(Biobuf*, int);
+int	Bputle4(Biobuf*, int);
+int	Bputrune(Biobuf*, long);
+void*	Brdline(Biobuf*, int);
+char*	Brdstr(Biobuf*, int, int);
+long	Bread(Biobuf*, void*, long);
+vlong	Bseek(Biobuf*, vlong, int);
+int	Bterm(Biobuf*);
+int	Bungetc(Biobuf*);
+int	Bungetrune(Biobuf*);
+long	Bwrite(Biobuf*, void*, long);
+int	Bvprint(Biobuf*, char*, va_list);
+/*c2go
+int	BGETC(Biobuf*);
+int	BGETLE2(Biobuf*);
+int	BGETLE4(Biobuf*);
+int	BPUTC(Biobuf*, int);
+int	BPUTLE2(Biobuf*, int);
+int	BPUTLE4(Biobuf*, int);
+*/
+
+#if defined(__cplusplus)
+}
+#endif
+#endif
diff --git a/include/fmt.h b/include/fmt.h
new file mode 100644
index 0000000..2280f25
--- /dev/null
+++ b/include/fmt.h
@@ -0,0 +1,116 @@
+#ifndef _FMT_H_
+#define _FMT_H_ 1
+#if defined(__cplusplus)
+extern "C" {
+#endif
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * 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 MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+#include <stdarg.h>
+#include <utf.h>
+
+typedef struct Fmt	Fmt;
+struct Fmt{
+	unsigned char	runes;		/* output buffer is runes or chars? */
+	void	*start;			/* of buffer */
+	void	*to;			/* current place in the buffer */
+	void	*stop;			/* end of the buffer; overwritten if flush fails */
+	int	(*flush)(Fmt *);	/* called when to == stop */
+	void	*farg;			/* to make flush a closure */
+	int	nfmt;			/* num chars formatted so far */
+	va_list	args;			/* args passed to dofmt */
+	Rune	r;			/* % format Rune */
+	int	width;
+	int	prec;
+	unsigned long	flags;
+	char	*decimal;	/* decimal point; cannot be "" */
+
+	/* For %'d */
+	char *thousands;	/* separator for thousands */
+
+	/*
+	 * Each char is an integer indicating #digits before next separator. Values:
+	 *	\xFF: no more grouping (or \x7F; defined to be CHAR_MAX in POSIX)
+	 *	\x00: repeat previous indefinitely
+	 *	\x**: count that many
+	 */
+	char	*grouping;		/* descriptor of separator placement */
+};
+
+enum{
+	FmtWidth	= 1,
+	FmtLeft		= FmtWidth << 1,
+	FmtPrec		= FmtLeft << 1,
+	FmtSharp	= FmtPrec << 1,
+	FmtSpace	= FmtSharp << 1,
+	FmtSign		= FmtSpace << 1,
+	FmtApost		= FmtSign << 1,
+	FmtZero		= FmtApost << 1,
+	FmtUnsigned	= FmtZero << 1,
+	FmtShort	= FmtUnsigned << 1,
+	FmtLong		= FmtShort << 1,
+	FmtVLong	= FmtLong << 1,
+	FmtComma	= FmtVLong << 1,
+	FmtByte		= FmtComma << 1,
+	FmtLDouble	= FmtByte << 1,
+
+	FmtFlag		= FmtLDouble << 1
+};
+
+extern	int	(*fmtdoquote)(int);
+
+/* Edit .+1,/^$/ | cfn $PLAN9/src/lib9/fmt/?*.c | grep -v static |grep -v __ */
+int		dofmt(Fmt *f, char *fmt);
+int		dorfmt(Fmt *f, const Rune *fmt);
+double		fmtcharstod(int(*f)(void*), void *vp);
+int		fmtfdflush(Fmt *f);
+int		fmtfdinit(Fmt *f, int fd, char *buf, int size);
+int		fmtinstall(int c, int (*f)(Fmt*));
+int		fmtnullinit(Fmt*);
+void		fmtlocaleinit(Fmt*, char*, char*, char*);
+int		fmtprint(Fmt *f, char *fmt, ...);
+int		fmtrune(Fmt *f, int r);
+int		fmtrunestrcpy(Fmt *f, Rune *s);
+int		fmtstrcpy(Fmt *f, char *s);
+char*		fmtstrflush(Fmt *f);
+int		fmtstrinit(Fmt *f);
+double		fmtstrtod(const char *as, char **aas);
+int		fmtvprint(Fmt *f, char *fmt, va_list args);
+int		fprint(int fd, char *fmt, ...);
+int		print(char *fmt, ...);
+void		quotefmtinstall(void);
+int		quoterunestrfmt(Fmt *f);
+int		quotestrfmt(Fmt *f);
+Rune*		runefmtstrflush(Fmt *f);
+int		runefmtstrinit(Fmt *f);
+Rune*		runeseprint(Rune *buf, Rune *e, char *fmt, ...);
+Rune*		runesmprint(char *fmt, ...);
+int		runesnprint(Rune *buf, int len, char *fmt, ...);
+int		runesprint(Rune *buf, char *fmt, ...);
+Rune*		runevseprint(Rune *buf, Rune *e, char *fmt, va_list args);
+Rune*		runevsmprint(char *fmt, va_list args);
+int		runevsnprint(Rune *buf, int len, char *fmt, va_list args);
+char*		seprint(char *buf, char *e, char *fmt, ...);
+char*		smprint(char *fmt, ...);
+int		snprint(char *buf, int len, char *fmt, ...);
+int		sprint(char *buf, char *fmt, ...);
+int		vfprint(int fd, char *fmt, va_list args);
+char*		vseprint(char *buf, char *e, char *fmt, va_list args);
+char*		vsmprint(char *fmt, va_list args);
+int		vsnprint(char *buf, int len, char *fmt, va_list args);
+
+#if defined(__cplusplus)
+}
+#endif
+#endif
diff --git a/include/libc.h b/include/libc.h
new file mode 100644
index 0000000..e10dde3
--- /dev/null
+++ b/include/libc.h
@@ -0,0 +1,405 @@
+/*
+Derived from Inferno include/kern.h and
+Plan 9 from User Space include/libc.h
+
+http://code.google.com/p/inferno-os/source/browse/include/kern.h
+http://code.swtch.com/plan9port/src/tip/include/libc.h
+
+	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 © 2001-2007 Russ Cox.  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.
+*/
+
+/*
+ * Lib9 is miscellany from the Plan 9 C library that doesn't
+ * fit into libutf or into libfmt, but is still missing from traditional
+ * Unix C libraries.
+ */
+#ifndef _LIBC_H_
+#define _LIBC_H_ 1
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#include <utf.h>
+#include <fmt.h>
+
+/*
+ * Begin trimmed down usual libc.h
+ */
+
+#ifndef nil
+#define	nil	((void*)0)
+#endif
+#define	nelem(x)	(sizeof(x)/sizeof((x)[0]))
+
+#ifndef offsetof
+#define offsetof(s, m)	(ulong)(&(((s*)0)->m))
+#endif
+
+extern	char*	strecpy(char*, char*, char*);
+extern  int tokenize(char*, char**, int);
+
+extern  double  p9cputime(void);
+#ifndef NOPLAN9DEFINES
+#define cputime     p9cputime
+#endif
+/*
+ * one-of-a-kind
+ */
+enum
+{
+	PNPROC		= 1,
+	PNGROUP		= 2
+};
+int isInf(double, int);
+
+extern	int	p9atoi(char*);
+extern	long	p9atol(char*);
+extern	vlong	p9atoll(char*);
+extern	double	fmtcharstod(int(*)(void*), void*);
+extern	char*	cleanname(char*);
+extern	int	exitcode(char*);
+extern	void	exits(char*);
+extern	double	frexp(double, int*);
+extern	char*	p9getenv(char*);
+extern	int	p9putenv(char*, char*);
+extern	int	getfields(char*, char**, int, int, char*);
+extern	int	gettokens(char *, char **, int, char *);
+extern	char*	p9getwd(char*, int);
+extern	void	p9longjmp(p9jmp_buf, int);
+extern	void	p9notejmp(void*, p9jmp_buf, int);
+extern	void	perror(const char*);
+extern	int	postnote(int, int, char *);
+extern	double	p9pow10(int);
+extern	char*	p9ctime(long);
+#define p9setjmp(b)	sigsetjmp((void*)(b), 1)
+
+extern	void	sysfatal(char*, ...);
+
+#ifndef NOPLAN9DEFINES
+#define atoi		p9atoi
+#define atol		p9atol
+#define atoll		p9atoll
+#define getenv		p9getenv
+#define	getwd		p9getwd
+#define	longjmp		p9longjmp
+#undef  setjmp
+#define setjmp		p9setjmp
+#define putenv		p9putenv
+#define notejmp		p9notejmp
+#define jmp_buf		p9jmp_buf
+#define pow10		p9pow10
+#undef  strtod
+#define strtod		fmtstrtod
+#define charstod	fmtcharstod
+#define ctime	p9ctime
+#endif
+
+/*
+ * system calls
+ *
+ */
+#define	STATMAX	65535U	/* max length of machine-independent stat structure */
+#define	DIRMAX	(sizeof(Dir)+STATMAX)	/* max length of Dir structure */
+#define	ERRMAX	128	/* max length of error string */
+
+#define	MORDER	0x0003	/* mask for bits defining order of mounting */
+#define	MREPL	0x0000	/* mount replaces object */
+#define	MBEFORE	0x0001	/* mount goes before others in union directory */
+#define	MAFTER	0x0002	/* mount goes after others in union directory */
+#define	MCREATE	0x0004	/* permit creation in mounted directory */
+#define	MCACHE	0x0010	/* cache some data */
+#define	MMASK	0x0017	/* all bits on */
+
+#define	OREAD	0	/* open for read */
+#define	OWRITE	1	/* write */
+#define	ORDWR	2	/* read and write */
+#define	OEXEC	3	/* execute, == read but check execute permission */
+#define	OTRUNC	16	/* or'ed in (except for exec), truncate file first */
+#define	ORCLOSE	64	/* or'ed in, remove on close */
+#define	ODIRECT	128	/* or'ed in, direct access */
+#define	OEXCL	0x1000	/* or'ed in, exclusive use (create only) */
+#define	OAPPEND	0x4000	/* or'ed in, append only */
+
+#define	AEXIST	0	/* accessible: exists */
+#define	AEXEC	1	/* execute access */
+#define	AWRITE	2	/* write access */
+#define	AREAD	4	/* read access */
+
+/* Segattch */
+#define	SG_RONLY	0040	/* read only */
+#define	SG_CEXEC	0100	/* detach on exec */
+
+#define	NCONT	0	/* continue after note */
+#define	NDFLT	1	/* terminate after note */
+#define	NSAVE	2	/* clear note but hold state */
+#define	NRSTR	3	/* restore saved state */
+
+/* bits in Qid.type */
+#define QTDIR		0x80		/* type bit for directories */
+#define QTAPPEND	0x40		/* type bit for append only files */
+#define QTEXCL		0x20		/* type bit for exclusive use files */
+#define QTMOUNT		0x10		/* type bit for mounted channel */
+#define QTAUTH		0x08		/* type bit for authentication file */
+#define QTTMP		0x04		/* type bit for non-backed-up file */
+#define QTSYMLINK	0x02		/* type bit for symbolic link */
+#define QTFILE		0x00		/* type bits for plain file */
+
+/* bits in Dir.mode */
+#define DMDIR		0x80000000	/* mode bit for directories */
+#define DMAPPEND	0x40000000	/* mode bit for append only files */
+#define DMEXCL		0x20000000	/* mode bit for exclusive use files */
+#define DMMOUNT		0x10000000	/* mode bit for mounted channel */
+#define DMAUTH		0x08000000	/* mode bit for authentication file */
+#define DMTMP		0x04000000	/* mode bit for non-backed-up file */
+#define DMSYMLINK	0x02000000	/* mode bit for symbolic link (Unix, 9P2000.u) */
+#define DMDEVICE	0x00800000	/* mode bit for device file (Unix, 9P2000.u) */
+#define DMNAMEDPIPE	0x00200000	/* mode bit for named pipe (Unix, 9P2000.u) */
+#define DMSOCKET	0x00100000	/* mode bit for socket (Unix, 9P2000.u) */
+#define DMSETUID	0x00080000	/* mode bit for setuid (Unix, 9P2000.u) */
+#define DMSETGID	0x00040000	/* mode bit for setgid (Unix, 9P2000.u) */
+
+#define DMREAD		0x4		/* mode bit for read permission */
+#define DMWRITE		0x2		/* mode bit for write permission */
+#define DMEXEC		0x1		/* mode bit for execute permission */
+
+#ifdef RFMEM	/* FreeBSD, OpenBSD, NetBSD */
+#undef RFFDG
+#undef RFNOTEG
+#undef RFPROC
+#undef RFMEM
+#undef RFNOWAIT
+#undef RFCFDG
+#undef RFNAMEG
+#undef RFENVG
+#undef RFCENVG
+#undef RFCFDG
+#undef RFCNAMEG
+#endif
+
+enum
+{
+	RFNAMEG		= (1<<0),
+	RFENVG		= (1<<1),
+	RFFDG		= (1<<2),
+	RFNOTEG		= (1<<3),
+	RFPROC		= (1<<4),
+	RFMEM		= (1<<5),
+	RFNOWAIT	= (1<<6),
+	RFCNAMEG	= (1<<10),
+	RFCENVG		= (1<<11),
+	RFCFDG		= (1<<12)
+/*	RFREND		= (1<<13), */
+/*	RFNOMNT		= (1<<14) */
+};
+
+typedef
+struct Qid
+{
+	uvlong	path;
+	ulong	vers;
+	uchar	type;
+} Qid;
+
+typedef
+struct Dir {
+	/* system-modified data */
+	ushort	type;	/* server type */
+	uint	dev;	/* server subtype */
+	/* file data */
+	Qid	qid;	/* unique id from server */
+	ulong	mode;	/* permissions */
+	ulong	atime;	/* last read time */
+	ulong	mtime;	/* last write time */
+	vlong	length;	/* file length */
+	char	*name;	/* last element of path */
+	char	*uid;	/* owner name */
+	char	*gid;	/* group name */
+	char	*muid;	/* last modifier name */
+
+	/* 9P2000.u extensions */
+	uint	uidnum;		/* numeric uid */
+	uint	gidnum;		/* numeric gid */
+	uint	muidnum;	/* numeric muid */
+	char	*ext;		/* extended info */
+} Dir;
+
+typedef
+struct Waitmsg
+{
+	int pid;	/* of loved one */
+	ulong time[3];	/* of loved one & descendants */
+	char	*msg;
+} Waitmsg;
+
+extern	void	_exits(char*);
+
+extern	void	abort(void);
+extern	long	p9alarm(ulong);
+extern	int	await(char*, int);
+extern	int	awaitfor(int, char*, int);
+extern	int	awaitnohang(char*, int);
+extern	int	p9chdir(char*);
+extern	int	close(int);
+extern	int	p9create(char*, int, ulong);
+extern	int	p9dup(int, int);
+extern	int	errstr(char*, uint);
+extern	int	p9exec(char*, char*[]);
+extern	int	p9execl(char*, ...);
+extern	int	p9rfork(int);
+extern	int	noted(int);
+extern	int	notify(void(*)(void*, char*));
+extern	int	noteenable(char*);
+extern	int	notedisable(char*);
+extern	int	notifyon(char*);
+extern	int	notifyoff(char*);
+extern	int	p9open(char*, int);
+extern	int	fd2path(int, char*, int);
+extern	long	readn(int, void*, long);
+extern	int	remove(const char*);
+extern	vlong	p9seek(int, vlong, int);
+extern	int	p9sleep(long);
+extern	Waitmsg*	p9wait(void);
+extern	Waitmsg*	p9waitfor(int);
+extern	Waitmsg*	waitnohang(void);
+extern	int	p9waitpid(void);
+extern	ulong	rendezvous(ulong, ulong);
+
+extern	char*	getgoos(void);
+extern	char*	getgoarch(void);
+extern	char*	getgoroot(void);
+extern	char*	getgoversion(void);
+extern	char*	getgoarm(void);
+extern	char*	getgo386(void);
+extern	char*	getgoextlinkenabled(void);
+
+extern	char*	mktempdir(void);
+extern	void	removeall(char*);
+extern	int	runcmd(char**);
+
+extern	void	flagcount(char*, char*, int*);
+extern	void	flagint32(char*, char*, int32*);
+extern	void	flagint64(char*, char*, int64*);
+extern	void	flagstr(char*, char*, char**);
+extern	void	flagparse(int*, char***, void (*usage)(void));
+extern	void	flagfn0(char*, char*, void(*fn)(void));
+extern	void	flagfn1(char*, char*, void(*fn)(char*));
+extern	void	flagfn2(char*, char*, void(*fn)(char*, char*));
+extern	void	flagprint(int);
+
+#ifdef _WIN32
+
+#if !defined(_WIN64) && !defined(__MINGW64_VERSION_MAJOR)
+struct timespec {
+	int tv_sec;
+	long tv_nsec;
+};
+#define execv(prog, argv) execv(prog, (const char* const*)(argv))
+#define execvp(prog, argv) execvp(prog, (const char**)(argv))
+#endif
+
+extern int nanosleep(const struct timespec *rqtp, struct timespec *rmtp);
+extern int fork(void);
+extern int pread(int fd, void *buf, int n, int off);
+extern int pwrite(int fd, void *buf, int n, int off);
+#undef  getwd
+#define getwd(s, ns) getcwd(s, ns)
+#undef  lseek
+#define lseek(fd, n, base) _lseeki64(fd, n, base)
+#define mkdir(path, perm) mkdir(path)
+#define pipe(fd) _pipe(fd, 512, O_BINARY)
+#else
+#define O_BINARY 0
+#endif
+
+#ifndef NOPLAN9DEFINES
+#define alarm		p9alarm
+#define	dup		p9dup
+#define	exec		p9exec
+#define	execl	p9execl
+#define	seek		p9seek
+#define sleep		p9sleep
+#define wait		p9wait
+#define waitpid		p9waitpid
+#define rfork		p9rfork
+#define create		p9create
+#undef open
+#define open		p9open
+#define	waitfor		p9waitfor
+#endif
+
+extern	Dir*	dirstat(char*);
+extern	Dir*	dirfstat(int);
+extern	int	dirwstat(char*, Dir*);
+extern	int	dirfwstat(int, Dir*);
+extern	void	nulldir(Dir*);
+extern	long	dirreadall(int, Dir**);
+extern	void	rerrstr(char*, uint);
+extern	char*	sysname(void);
+extern	void	werrstr(char*, ...);
+extern	char*	getns(void);
+extern	char*	get9root(void);
+extern	char*	unsharp(char*);
+
+/* external names that we don't want to step on */
+#ifndef NOPLAN9DEFINES
+#define main	p9main
+#endif
+
+/* compiler directives on plan 9 */
+#define	SET(x)	((x)=0)
+#define	USED(x)	if(x){}else{}
+#ifdef __GNUC__
+#	if __GNUC__ >= 3
+#		undef USED
+#		define USED(x) ((void)(x))
+#	endif
+#endif
+
+/* command line */
+extern char	*argv0;
+extern void __fixargv0(void);
+#define	ARGBEGIN	for((void)(argv0?0:(argv0=(__fixargv0(),*argv))),argv++,argc--;\
+			    argv[0] && argv[0][0]=='-' && argv[0][1];\
+			    argc--, argv++) {\
+				char *_args, *_argt;\
+				Rune _argc;\
+				_args = &argv[0][1];\
+				if(_args[0]=='-' && _args[1]==0){\
+					argc--; argv++; break;\
+				}\
+				_argc = 0;\
+				while(*_args && (_args += chartorune(&_argc, _args)))\
+				switch(_argc)
+#define	ARGEND		SET(_argt);USED(_argt);USED(_argc);USED(_args);}USED(argv);USED(argc);
+#define	ARGF()		(_argt=_args, _args="",\
+				(*_argt? _argt: argv[1]? (argc--, *++argv): 0))
+#define	EARGF(x)	(_argt=_args, _args="",\
+				(*_argt? _argt: argv[1]? (argc--, *++argv): ((x), abort(), (char*)0)))
+
+#define	ARGC()		_argc
+
+#if defined(__cplusplus)
+}
+#endif
+#endif	/* _LIB9_H_ */
diff --git a/include/link.h b/include/link.h
new file mode 100644
index 0000000..05e117c
--- /dev/null
+++ b/include/link.h
@@ -0,0 +1,631 @@
+// 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
+	uchar	ft;	/* 6l, 8l oclass cache */
+	uchar	tt;	// 6l, 8l
+	uint16	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 */
+	
+	/*c2go uchar TEXTFLAG; */
+};
+
+// 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	cfunc;
+	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;
+	int	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,
+	SWINDOWS,
+	SNOPTRDATA,
+	SINITARR,
+	SDATA,
+	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;
+	int32	enforce_data_order;	// for use by assembler
+
+	// 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[2];
+	LSym*	tlsg;
+	LSym*	plan9privates;
+	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];
+	int64	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;
+};
+
+enum {
+	LittleEndian = 0x04030201,
+	BigEndian = 0x01020304,
+};
+
+// LinkArch is the definition of a single architecture.
+struct LinkArch
+{
+	char*	name; // "arm", "amd64", and so on
+	int	thechar;	// '5', '6', and so on
+	int32	endian; // LittleEndian or BigEndian
+
+	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	D_OREG;
+
+	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);
+void	savedata1(Link *ctxt, LSym *s, Prog *p, char *pn, int enforce_order);
+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(LinkArch*);
+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	char*	cnames5[];
+
+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
+#pragma varargck	type	"^"	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/plan9/386/u.h b/include/plan9/386/u.h
new file mode 100644
index 0000000..1c4076b
--- /dev/null
+++ b/include/plan9/386/u.h
@@ -0,0 +1,17 @@
+// 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/u.h"
+
+typedef	char	int8;
+typedef	uchar	uint8;
+typedef	short	int16;
+typedef	ushort	uint16;
+typedef	int	int32;
+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
new file mode 100644
index 0000000..c2d4999
--- /dev/null
+++ b/include/plan9/amd64/u.h
@@ -0,0 +1,17 @@
+// 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/u.h"
+
+typedef	char	int8;
+typedef	uchar	uint8;
+typedef	short	int16;
+typedef	ushort	uint16;
+typedef	int	int32;
+typedef	uint	uint32;
+typedef	vlong	int64;
+typedef	uvlong	uint64;
+typedef	vlong	intptr;
+typedef	float	float32;
+typedef	double	float64;
diff --git a/include/plan9/arm/u.h b/include/plan9/arm/u.h
new file mode 100644
index 0000000..19249aa
--- /dev/null
+++ b/include/plan9/arm/u.h
@@ -0,0 +1,15 @@
+// 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/u.h"
+
+typedef	char	int8;
+typedef	uchar	uint8;
+typedef	short	int16;
+typedef	ushort	uint16;
+typedef	int	int32;
+typedef	uint	uint32;
+typedef	vlong	int64;
+typedef	uvlong	uint64;
+typedef	int	intptr;
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
new file mode 100644
index 0000000..773edee
--- /dev/null
+++ b/include/plan9/libc.h
@@ -0,0 +1,33 @@
+// 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 "/sys/include/ctype.h"
+#include "fmt.h"
+#include "utf.h"
+#include "libc_plan9.h"
+
+char*	getgoos(void);
+char*	getgoarch(void);
+char*	getgoroot(void);
+char*	getgoversion(void);
+char*	getgoarm(void);
+char*	getgo386(void);
+char*	getgoextlinkenabled(void);
+
+void	flagcount(char*, char*, int*);
+void	flagint32(char*, char*, int32*);
+void	flagint64(char*, char*, int64*);
+void	flagstr(char*, char*, char**);
+void	flagparse(int*, char***, void (*usage)(void));
+void	flagfn0(char*, char*, void(*fn)(void));
+void	flagfn1(char*, char*, void(*fn)(char*));
+void	flagfn2(char*, char*, void(*fn)(char*, char*));
+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/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/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
new file mode 100644
index 0000000..489b2a3
--- /dev/null
+++ b/include/u.h
@@ -0,0 +1,233 @@
+/*
+Plan 9 from User Space include/u.h
+http://code.swtch.com/plan9port/src/tip/include/u.h
+
+Copyright 2001-2007 Russ Cox.  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.
+*/
+
+#ifndef _U_H_
+#define _U_H_ 1
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#define __BSD_VISIBLE 1 /* FreeBSD 5.x */
+#if defined(__sun__)
+#	define __EXTENSIONS__ 1 /* SunOS */
+#	if defined(__SunOS5_6__) || defined(__SunOS5_7__) || defined(__SunOS5_8__)
+		/* NOT USING #define __MAKECONTEXT_V2_SOURCE 1 / * SunOS */
+#	else
+#		define __MAKECONTEXT_V2_SOURCE 1
+#	endif
+#endif
+#define _BSD_SOURCE 1
+#define _NETBSD_SOURCE 1	/* NetBSD */
+#define _DEFAULT_SOURCE 1	/* glibc > 2.19 */
+#define _SVID_SOURCE 1
+#if !defined(__APPLE__) && !defined(__OpenBSD__)
+#	define _XOPEN_SOURCE 1000
+#	define _XOPEN_SOURCE_EXTENDED 1
+#endif
+#if defined(__FreeBSD__)
+#	include <sys/cdefs.h>
+	/* for strtoll */
+#	undef __ISO_C_VISIBLE
+#	define __ISO_C_VISIBLE 1999
+#	undef __LONG_LONG_SUPPORTED
+#	define __LONG_LONG_SUPPORTED
+#endif
+#define _LARGEFILE64_SOURCE 1
+#define _FILE_OFFSET_BITS 64
+
+#include <inttypes.h>
+
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <setjmp.h>
+#include <stddef.h>
+#include <math.h>
+#include <ctype.h>	/* for tolower */
+#include <signal.h>
+#include <time.h>
+
+/*
+ * OS-specific crap
+ */
+#define _NEEDUCHAR 1
+#define _NEEDUSHORT 1
+#define _NEEDUINT 1
+#define _NEEDULONG 1
+
+#ifdef _WIN32
+typedef jmp_buf sigjmp_buf;
+#endif
+typedef long p9jmp_buf[sizeof(sigjmp_buf)/sizeof(long)];
+
+#if defined(__linux__)
+#	include <sys/types.h>
+#	if defined(__Linux26__)
+#		include <pthread.h>
+#		define PLAN9PORT_USING_PTHREADS 1
+#	endif
+#	if defined(__USE_MISC)
+#		undef _NEEDUSHORT
+#		undef _NEEDUINT
+#		undef _NEEDULONG
+#	endif
+#elif defined(__sun__)
+#	include <sys/types.h>
+#	include <pthread.h>
+#	define PLAN9PORT_USING_PTHREADS 1
+#	undef _NEEDUSHORT
+#	undef _NEEDUINT
+#	undef _NEEDULONG
+#	define nil 0	/* no cast to void* */
+#elif defined(__FreeBSD__)
+#	include <sys/types.h>
+#	include <osreldate.h>
+#	if __FreeBSD_version >= 500000
+#		define PLAN9PORT_USING_PTHREADS 1
+#		include <pthread.h>
+#	endif
+#	if !defined(_POSIX_SOURCE)
+#		undef _NEEDUSHORT
+#		undef _NEEDUINT
+#	endif
+#elif defined(__APPLE__)
+#	include <sys/types.h>
+#	include <pthread.h>
+#	define PLAN9PORT_USING_PTHREADS 1
+#	if __GNUC__ < 4
+#		undef _NEEDUSHORT
+#		undef _NEEDUINT
+#	endif
+#	undef _ANSI_SOURCE
+#	undef _POSIX_C_SOURCE
+#	undef _XOPEN_SOURCE
+#	if !defined(NSIG)
+#		define NSIG 32
+#	endif
+#	define _NEEDLL 1
+#elif defined(__NetBSD__)
+#	include <sched.h>
+#	include <sys/types.h>
+#	undef _NEEDUSHORT
+#	undef _NEEDUINT
+#	undef _NEEDULONG
+#elif defined(__OpenBSD__)
+#	include <sys/types.h>
+#	undef _NEEDUSHORT
+#	undef _NEEDUINT
+#	undef _NEEDULONG
+#elif defined(_WIN32)
+#else
+	/* No idea what system this is -- try some defaults */
+#	include <pthread.h>
+#	define PLAN9PORT_USING_PTHREADS 1
+#endif
+
+#ifndef O_DIRECT
+#define O_DIRECT 0
+#endif
+
+typedef signed char schar;
+
+#ifdef _NEEDUCHAR
+	typedef unsigned char uchar;
+#endif
+#ifdef _NEEDUSHORT
+	typedef unsigned short ushort;
+#endif
+#ifdef _NEEDUINT
+	typedef unsigned int uint;
+#endif
+#ifdef _NEEDULONG
+	typedef unsigned long ulong;
+#endif
+typedef unsigned long long uvlong;
+typedef long long vlong;
+
+typedef uint64_t u64int;
+typedef int64_t s64int;
+typedef uint8_t u8int;
+typedef int8_t s8int;
+typedef uint16_t u16int;
+typedef int16_t s16int;
+typedef uintptr_t uintptr;
+typedef intptr_t intptr;
+typedef uint32_t u32int;
+typedef int32_t s32int;
+
+typedef s8int int8;
+typedef u8int uint8;
+typedef s16int int16;
+typedef u16int uint16;
+typedef s32int int32;
+typedef u32int uint32;
+typedef s64int int64;
+typedef u64int uint64;
+
+typedef float float32;
+typedef double float64;
+
+#undef _NEEDUCHAR
+#undef _NEEDUSHORT
+#undef _NEEDUINT
+#undef _NEEDULONG
+
+#define getcallerpc(x)	__builtin_return_address(0)
+
+#ifndef SIGBUS
+#define SIGBUS SIGSEGV /* close enough */
+#endif
+
+/*
+ * Funny-named symbols to tip off 9l to autolink.
+ */
+#define AUTOLIB(x)	static int __p9l_autolib_ ## x = 1;
+#define AUTOFRAMEWORK(x) static int __p9l_autoframework_ ## x = 1;
+
+/*
+ * Gcc is too smart for its own good.
+ */
+#if defined(__GNUC__)
+#	undef strcmp	/* causes way too many warnings */
+#	if __GNUC__ >= 4 || (__GNUC__==3 && !defined(__APPLE_CC__) && !defined(_WIN32))
+#		undef AUTOLIB
+#		define AUTOLIB(x) int __p9l_autolib_ ## x __attribute__ ((weak));
+#		undef AUTOFRAMEWORK
+#		define AUTOFRAMEWORK(x) int __p9l_autoframework_ ## x __attribute__ ((weak));
+#	else
+#		undef AUTOLIB
+#		define AUTOLIB(x) static int __p9l_autolib_ ## x __attribute__ ((unused));
+#		undef AUTOFRAMEWORK
+#		define AUTOFRAMEWORK(x) static int __p9l_autoframework_ ## x __attribute__ ((unused));
+#	endif
+#endif
+
+#if defined(__cplusplus)
+}
+#endif
+#endif
diff --git a/include/utf.h b/include/utf.h
new file mode 100644
index 0000000..be1c46e
--- /dev/null
+++ b/include/utf.h
@@ -0,0 +1 @@
+#include "../src/lib9/utf/utf.h"
diff --git a/lib/time/update.bash b/lib/time/update.bash
index 3ef1df5..caa8450 100755
--- a/lib/time/update.bash
+++ b/lib/time/update.bash
@@ -7,8 +7,8 @@
 # downloaded from the ICANN/IANA distribution.
 
 # Versions to use.
-CODE=2015e
-DATA=2015e
+CODE=2014j
+DATA=2014j
 
 set -e
 rm -rf work
diff --git a/lib/time/zoneinfo.zip b/lib/time/zoneinfo.zip
index 73c30b4..425d7c9 100644
Binary files a/lib/time/zoneinfo.zip and b/lib/time/zoneinfo.zip differ
diff --git a/misc/android/README b/misc/android/README
index 7b17d87..5f24faf 100644
--- a/misc/android/README
+++ b/misc/android/README
@@ -2,9 +2,9 @@ Android
 =======
 
 For details on developing Go for Android, see the documentation in the
-mobile subrepository:
+go.mobile subrepository:
 
-	https://github.com/golang/mobile
+	https://code.google.com/p/go/source/browse/README?repo=mobile
 
 To run the standard library tests, see androidtest.bash. Run it as
 
diff --git a/misc/android/go_android_exec.go b/misc/android/go_android_exec.go
index a67e990..e32a805 100644
--- a/misc/android/go_android_exec.go
+++ b/misc/android/go_android_exec.go
@@ -9,7 +9,6 @@ package main
 import (
 	"bytes"
 	"fmt"
-	"go/build"
 	"io"
 	"log"
 	"os"
@@ -33,36 +32,33 @@ func run(args ...string) string {
 	return buf.String()
 }
 
-const (
-	// Directory structure on the target device androidtest.bash assumes.
-	deviceGoroot = "/data/local/tmp/goroot"
-	deviceGopath = "/data/local/tmp/gopath"
-)
-
 func main() {
 	log.SetFlags(0)
 	log.SetPrefix("go_android_exec: ")
 
-	// Prepare a temporary directory that will be cleaned up at the end.
-	deviceGotmp := fmt.Sprintf("/data/local/tmp/%s-%d",
-		filepath.Base(os.Args[1]), os.Getpid())
-	run("shell", "mkdir", "-p", deviceGotmp)
-
-	// Determine the package by examining the current working
+	// Determine thepackage by examining the current working
 	// directory, which will look something like
-	// "$GOROOT/src/mime/multipart" or "$GOPATH/src/golang.org/x/mobile".
-	// We extract everything after the $GOROOT or $GOPATH to run on the
-	// same relative directory on the target device.
-	subdir, inGoRoot := subdir()
-	deviceCwd := filepath.Join(deviceGoroot, subdir)
-	if !inGoRoot {
-		deviceCwd = filepath.Join(deviceGopath, subdir)
+	// "$GOROOT/src/mime/multipart". We extract everything
+	// after the $GOROOT to run on the same relative directory
+	// on the target device.
+	//
+	// TODO(crawshaw): Pick useful subdir when we are not
+	// inside a GOROOT, e.g. we are in a GOPATH.
+	cwd, err := os.Getwd()
+	if err != nil {
+		log.Fatal(err)
 	}
+	subdir, err := filepath.Rel(runtime.GOROOT(), cwd)
+	if err != nil {
+		log.Fatal(err)
+	}
+	subdir = filepath.ToSlash(subdir)
 
 	// Binary names can conflict.
 	// E.g. template.test from the {html,text}/template packages.
 	binName := filepath.Base(os.Args[1])
-	deviceBin := fmt.Sprintf("%s/%s-%d", deviceGotmp, binName, os.Getpid())
+	deviceGoroot := "/data/local/tmp/goroot"
+	deviceBin := fmt.Sprintf("%s/%s-%d", deviceGoroot, binName, os.Getpid())
 
 	// The push of the binary happens in parallel with other tests.
 	// Unfortunately, a simultaneous call to adb shell hold open
@@ -75,22 +71,19 @@ func main() {
 
 	// The adb shell command will return an exit code of 0 regardless
 	// of the command run. E.g.
-	//      $ adb shell false
-	//      $ echo $?
-	//      0
+	//	$ adb shell false
+	//	$ echo $?
+	//	0
 	// https://code.google.com/p/android/issues/detail?id=3254
 	// So we append the exitcode to the output and parse it from there.
 	const exitstr = "exitcode="
-	cmd := `export TMPDIR="` + deviceGotmp + `"` +
+	cmd := `export TMPDIR="/data/local/tmp"` +
 		`; export GOROOT="` + deviceGoroot + `"` +
-		`; export GOPATH="` + deviceGopath + `"` +
-		`; cd "` + deviceCwd + `"` +
+		`; cd "$GOROOT/` + subdir + `"` +
 		"; '" + deviceBin + "' " + strings.Join(os.Args[2:], " ") +
 		"; echo -n " + exitstr + "$?"
 	output := run("shell", cmd)
-
-	run("shell", "rm", "-rf", deviceGotmp) // Clean up.
-
+	run("shell", "rm '"+deviceBin+"'") // cleanup
 	output = output[strings.LastIndex(output, "\n")+1:]
 	if !strings.HasPrefix(output, exitstr) {
 		log.Fatalf("no exit code: %q", output)
@@ -101,32 +94,3 @@ func main() {
 	}
 	os.Exit(code)
 }
-
-// subdir determines the package based on the current working directory,
-// and returns the path to the package source relative to $GOROOT (or $GOPATH).
-func subdir() (pkgpath string, underGoRoot bool) {
-	cwd, err := os.Getwd()
-	if err != nil {
-		log.Fatal(err)
-	}
-	if root := runtime.GOROOT(); strings.HasPrefix(cwd, root) {
-		subdir, err := filepath.Rel(root, cwd)
-		if err != nil {
-			log.Fatal(err)
-		}
-		return subdir, true
-	}
-
-	for _, p := range filepath.SplitList(build.Default.GOPATH) {
-		if !strings.HasPrefix(cwd, p) {
-			continue
-		}
-		subdir, err := filepath.Rel(p, cwd)
-		if err == nil {
-			return subdir, false
-		}
-	}
-	log.Fatalf("the current path %q is not in either GOROOT(%q) or GOPATH(%q)",
-		cwd, runtime.GOROOT(), build.Default.GOPATH)
-	return "", false
-}
diff --git a/misc/cgo/errors/test.bash b/misc/cgo/errors/test.bash
index c880ad6..c962643 100755
--- a/misc/cgo/errors/test.bash
+++ b/misc/cgo/errors/test.bash
@@ -1,5 +1,3 @@
-#!/usr/bin/env 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.
diff --git a/misc/cgo/gmp/gmp.go b/misc/cgo/gmp/gmp.go
index d39bfe6..7b7a9b3 100644
--- a/misc/cgo/gmp/gmp.go
+++ b/misc/cgo/gmp/gmp.go
@@ -8,7 +8,7 @@ multiprecision library gmp's integer type mpz_t wrapped to look like
 the Go package big's integer type Int.
 
 This is a syntactically valid Go program—it can be parsed with the Go
-parser and processed by godoc—but it is not compiled directly by gc.
+parser and processed by godoc—but it is not compiled directly by 6g.
 Instead, a separate tool, cgo, processes it to produce three output
 files.  The first two, 6g.go and 6c.c, are a Go source file for 6g and
 a C source file for 6c; both compile as part of the named package
diff --git a/misc/cgo/test/backdoor/backdoor.go b/misc/cgo/test/backdoor/backdoor.go
new file mode 100644
index 0000000..3a97349
--- /dev/null
+++ b/misc/cgo/test/backdoor/backdoor.go
@@ -0,0 +1,7 @@
+// 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 backdoor
+
+func LockedOSThread() bool // in thunk.s
diff --git a/misc/cgo/test/backdoor/runtime_gccgo.c b/misc/cgo/test/backdoor/runtime_gccgo.c
new file mode 100644
index 0000000..218b2c3
--- /dev/null
+++ b/misc/cgo/test/backdoor/runtime_gccgo.c
@@ -0,0 +1,18 @@
+// 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.
+
+// Expose some runtime functions for testing.
+// This is the gccgo version of runtime.c.
+
+// +build gccgo
+
+_Bool runtime_lockedOSThread(void);
+
+_Bool LockedOSThread(void) asm(GOPKGPATH ".LockedOSThread");
+
+_Bool
+LockedOSThread(void)
+{
+	return runtime_lockedOSThread();
+}
diff --git a/misc/cgo/test/backdoor/thunk.s b/misc/cgo/test/backdoor/thunk.s
new file mode 100644
index 0000000..ae735c8
--- /dev/null
+++ b/misc/cgo/test/backdoor/thunk.s
@@ -0,0 +1,16 @@
+// 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.
+
+// Assembly to get into package runtime without using exported symbols.
+
+// +build amd64 amd64p32 arm 386
+
+#include "textflag.h"
+
+#ifdef GOARCH_arm
+#define JMP B
+#endif
+
+TEXT ·LockedOSThread(SB),NOSPLIT,$0-0
+	JMP	runtime·lockedOSThread(SB)
diff --git a/misc/cgo/test/callback.go b/misc/cgo/test/callback.go
index bff770f..44167e6 100644
--- a/misc/cgo/test/callback.go
+++ b/misc/cgo/test/callback.go
@@ -9,6 +9,7 @@ void callback(void *f);
 void callGoFoo(void);
 void callGoStackCheck(void);
 void callPanic(void);
+void callCgoAllocate(void);
 int callGoReturnVal(void);
 int returnAfterGrow(void);
 int returnAfterGrowFromGo(void);
@@ -21,6 +22,8 @@ import (
 	"strings"
 	"testing"
 	"unsafe"
+
+	"./backdoor"
 )
 
 // nestedCall calls into C, back into Go, and finally to f.
@@ -47,6 +50,8 @@ func testCallbackGC(t *testing.T) {
 	nestedCall(runtime.GC)
 }
 
+var lockedOSThread = backdoor.LockedOSThread
+
 func testCallbackPanic(t *testing.T) {
 	// Make sure panic during callback unwinds properly.
 	if lockedOSThread() {
@@ -156,8 +161,9 @@ func testCallbackCallers(t *testing.T) {
 		"runtime.cgocallbackg1",
 		"runtime.cgocallbackg",
 		"runtime.cgocallback_gofunc",
-		"runtime.asmcgocall",
-		"runtime.cgocall",
+		"asmcgocall",
+		"runtime.asmcgocall_errno",
+		"runtime.cgocall_errno",
 		"test._Cfunc_callback",
 		"test.nestedCall",
 		"test.testCallbackCallers",
@@ -165,9 +171,6 @@ func testCallbackCallers(t *testing.T) {
 		"testing.tRunner",
 		"runtime.goexit",
 	}
-	if unsafe.Sizeof((*byte)(nil)) == 8 {
-		name[1] = "runtime.call32"
-	}
 	nestedCall(func() {
 		n = runtime.Callers(2, pc)
 	})
@@ -208,6 +211,10 @@ func testPanicFromC(t *testing.T) {
 	C.callPanic()
 }
 
+func testAllocateFromC(t *testing.T) {
+	C.callCgoAllocate() // crashes or exits on failure
+}
+
 // Test that C code can return a value if it calls a Go function that
 // causes a stack copy.
 func testReturnAfterGrow(t *testing.T) {
diff --git a/misc/cgo/test/callback_c_gc.c b/misc/cgo/test/callback_c_gc.c
index c6ea3c5..28a62c6 100644
--- a/misc/cgo/test/callback_c_gc.c
+++ b/misc/cgo/test/callback_c_gc.c
@@ -23,3 +23,58 @@ callPanic(void)
 	crosscall2(_cgo_panic, &a, sizeof a);
 	*(int*)1 = 1;
 }
+
+/* Test calling cgo_allocate from C. This is what SWIG does. */
+
+typedef struct List List;
+struct List
+{
+	List *next;
+	int x;
+};
+
+void
+callCgoAllocate(void)
+{
+	int i;
+	struct { size_t n; void *ret; } a;
+	List *l, *head, **tail;
+
+	// Make sure this doesn't crash.
+	// And make sure it returns non-nil.
+	a.n = 0;
+	a.ret = 0;
+	crosscall2(_cgo_allocate, &a, sizeof a);
+	if(a.ret == 0) {
+		fprintf(stderr, "callCgoAllocate: alloc 0 returned nil\n");
+		exit(2);
+	}
+	
+	head = 0;
+	tail = &head;
+	for(i=0; i<100; i++) {
+		a.n = sizeof *l;
+		crosscall2(_cgo_allocate, &a, sizeof a);
+		l = a.ret;
+		l->x = i;
+		l->next = 0;
+		*tail = l;
+		tail = &l->next;
+	}
+	
+	gc();
+	
+	l = head;
+	for(i=0; i<100; i++) {
+		if(l->x != i) {
+			fprintf(stderr, "callCgoAllocate: lost memory\n");
+			exit(2);
+		}
+		l = l->next;
+	}
+	if(l != 0) {
+		fprintf(stderr, "callCgoAllocate: lost memory\n");
+		exit(2);
+	}
+}
+
diff --git a/misc/cgo/test/callback_c_gccgo.c b/misc/cgo/test/callback_c_gccgo.c
index ff5dbbb..d367b7b 100644
--- a/misc/cgo/test/callback_c_gccgo.c
+++ b/misc/cgo/test/callback_c_gccgo.c
@@ -19,3 +19,52 @@ callPanic(void)
 {
 	_cgo_panic("panic from C");
 }
+
+/* Test calling cgo_allocate from C. This is what SWIG does. */
+
+typedef struct List List;
+struct List
+{
+	List *next;
+	int x;
+};
+
+void
+callCgoAllocate(void)
+{
+	int i;
+	List *l, *head, **tail;
+	
+	// Make sure this doesn't crash.
+	// And make sure it returns non-nil.
+	if(_cgo_allocate(0) == 0) {
+		fprintf(stderr, "callCgoAllocate: alloc 0 returned nil\n");
+		exit(2);
+	}
+
+	head = 0;
+	tail = &head;
+	for(i=0; i<100; i++) {
+		l = _cgo_allocate(sizeof *l);
+		l->x = i;
+		l->next = 0;
+		*tail = l;
+		tail = &l->next;
+	}
+	
+	gc();
+	
+	l = head;
+	for(i=0; i<100; i++) {
+		if(l->x != i) {
+			fprintf(stderr, "callCgoAllocate: lost memory\n");
+			exit(2);
+		}
+		l = l->next;
+	}
+	if(l != 0) {
+		fprintf(stderr, "callCgoAllocate: lost memory\n");
+		exit(2);
+	}
+}
+
diff --git a/misc/cgo/test/cflags.go b/misc/cgo/test/cflags.go
index 6571fe0..24caab4 100644
--- a/misc/cgo/test/cflags.go
+++ b/misc/cgo/test/cflags.go
@@ -4,7 +4,7 @@
 
 // Test that the #cgo CFLAGS directive works,
 // with and without platform filters.
-// See https://golang.org/issue/5224 for details.
+// See http://code.google.com/p/go/issues/detail?id=5224 for details.
 package cgotest
 
 /*
diff --git a/misc/cgo/test/cgo_linux_test.go b/misc/cgo/test/cgo_linux_test.go
index 3cc2af5..4fe0db1 100644
--- a/misc/cgo/test/cgo_linux_test.go
+++ b/misc/cgo/test/cgo_linux_test.go
@@ -6,8 +6,6 @@ package cgotest
 
 import "testing"
 
-func TestSetgid(t *testing.T)      { testSetgid(t) }
-func Test6997(t *testing.T)        { test6997(t) }
-func TestBuildID(t *testing.T)     { testBuildID(t) }
-func Test9400(t *testing.T)        { test9400(t) }
-func TestSigProcMask(t *testing.T) { testSigProcMask(t) }
+func TestSetgid(t *testing.T)  { testSetgid(t) }
+func Test6997(t *testing.T)    { test6997(t) }
+func TestBuildID(t *testing.T) { testBuildID(t) }
diff --git a/misc/cgo/test/cgo_test.go b/misc/cgo/test/cgo_test.go
index 9af31e8..fbdfac8 100644
--- a/misc/cgo/test/cgo_test.go
+++ b/misc/cgo/test/cgo_test.go
@@ -23,6 +23,7 @@ func TestCallbackPanic(t *testing.T)         { testCallbackPanic(t) }
 func TestCallbackPanicLoop(t *testing.T)     { testCallbackPanicLoop(t) }
 func TestCallbackPanicLocked(t *testing.T)   { testCallbackPanicLocked(t) }
 func TestPanicFromC(t *testing.T)            { testPanicFromC(t) }
+func TestAllocateFromC(t *testing.T)         { testAllocateFromC(t) }
 func TestZeroArgCallback(t *testing.T)       { testZeroArgCallback(t) }
 func TestBlocking(t *testing.T)              { testBlocking(t) }
 func Test1328(t *testing.T)                  { test1328(t) }
@@ -62,8 +63,5 @@ func Test8811(t *testing.T)                  { test8811(t) }
 func TestReturnAfterGrow(t *testing.T)       { testReturnAfterGrow(t) }
 func TestReturnAfterGrowFromGo(t *testing.T) { testReturnAfterGrowFromGo(t) }
 func Test9026(t *testing.T)                  { test9026(t) }
-func Test9557(t *testing.T)                  { test9557(t) }
-func Test10303(t *testing.T)                 { test10303(t, 10) }
-func Test11925(t *testing.T)                 { test11925(t) }
 
 func BenchmarkCgoCall(b *testing.B) { benchCgoCall(b) }
diff --git a/misc/cgo/test/cthread_unix.c b/misc/cgo/test/cthread_unix.c
index d29f2fc..3f39c15 100644
--- a/misc/cgo/test/cthread_unix.c
+++ b/misc/cgo/test/cthread_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 solaris
+// +build darwin dragonfly freebsd linux netbsd openbsd
 
 #include <pthread.h>
 #include "_cgo_export.h"
diff --git a/misc/cgo/test/issue3261.go b/misc/cgo/test/issue3261.go
index 32cb06b..0411be8 100644
--- a/misc/cgo/test/issue3261.go
+++ b/misc/cgo/test/issue3261.go
@@ -13,12 +13,6 @@ int vabs(int x) {
 	puts("testLibgcc is disabled on ARM because 5l cannot handle thumb library.");
 	return (x < 0) ? -x : x;
 }
-#elif defined(__arm64__) && defined(__clang__)
-#include <stdio.h>
-int vabs(int x) {
-	puts("testLibgcc is disabled on ARM64 with clang due to lack of libgcc.");
-	return (x < 0) ? -x : x;
-}
 #else
 int __absvsi2(int); // dummy prototype for libgcc function
 // we shouldn't name the function abs, as gcc might use
diff --git a/misc/cgo/test/issue3945.go b/misc/cgo/test/issue3945.go
index 7e6863f..331cd0b 100644
--- a/misc/cgo/test/issue3945.go
+++ b/misc/cgo/test/issue3945.go
@@ -5,7 +5,7 @@
 package cgotest
 
 // Test that cgo reserves enough stack space during cgo call.
-// See https://golang.org/issue/3945 for details.
+// See http://golang.org/issue/3945 for details.
 
 // #include <stdio.h>
 //
diff --git a/misc/cgo/test/issue6997_linux.go b/misc/cgo/test/issue6997_linux.go
index 07fd58e..5455f0c 100644
--- a/misc/cgo/test/issue6997_linux.go
+++ b/misc/cgo/test/issue6997_linux.go
@@ -4,7 +4,7 @@
 
 // Test that pthread_cancel works as expected
 // (NPTL uses SIGRTMIN to implement thread cancellation)
-// See https://golang.org/issue/6997
+// See http://golang.org/issue/6997
 package cgotest
 
 /*
diff --git a/misc/cgo/test/issue7234_test.go b/misc/cgo/test/issue7234_test.go
index a020b6a..713dade 100644
--- a/misc/cgo/test/issue7234_test.go
+++ b/misc/cgo/test/issue7234_test.go
@@ -7,14 +7,14 @@ package cgotest
 import "testing"
 
 // This test actually doesn't have anything to do with cgo.  It is a
-// test of https://golang.org/issue/7234, a compiler/linker bug in
+// 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 Test7234(t *testing.T) {
+func TestIssue7234(t *testing.T) {
 	if v7234[0] != "runtime/cgo" {
 		t.Errorf("bad string constant %q", v7234[0])
 	}
diff --git a/misc/cgo/test/issue7978.go b/misc/cgo/test/issue7978.go
index 094ccc1..5feed07 100644
--- a/misc/cgo/test/issue7978.go
+++ b/misc/cgo/test/issue7978.go
@@ -12,23 +12,9 @@ package cgotest
 
 void issue7978cb(void);
 
-#if defined(__APPLE__) && defined(__arm__)
-// on Darwin/ARM, libSystem doesn't provide implementation of the __sync_fetch_and_add
-// primitive, and although gcc supports it, it doesn't inline its definition.
-// Clang could inline its definition, so we require clang on Darwin/ARM.
-#if defined(__clang__)
-#define HAS_SYNC_FETCH_AND_ADD 1
-#else
-#define HAS_SYNC_FETCH_AND_ADD 0
-#endif
-#else
-#define HAS_SYNC_FETCH_AND_ADD 1
-#endif
-
 // use ugly atomic variable sync since that doesn't require calling back into
 // Go code or OS dependencies
 static void issue7978c(uint32_t *sync) {
-#if HAS_SYNC_FETCH_AND_ADD
 	while(__sync_fetch_and_add(sync, 0) != 0)
 		;
 	__sync_fetch_and_add(sync, 1);
@@ -38,7 +24,6 @@ static void issue7978c(uint32_t *sync) {
 	__sync_fetch_and_add(sync, 1);
 	while(__sync_fetch_and_add(sync, 0) != 6)
 		;
-#endif
 }
 */
 import "C"
@@ -97,12 +82,6 @@ func issue7978go() {
 }
 
 func test7978(t *testing.T) {
-	if runtime.Compiler == "gccgo" {
-		t.Skip("gccgo can not do stack traces of C code")
-	}
-	if C.HAS_SYNC_FETCH_AND_ADD == 0 {
-		t.Skip("clang required for __sync_fetch_and_add support on darwin/arm")
-	}
 	if os.Getenv("GOTRACEBACK") != "2" {
 		t.Fatalf("GOTRACEBACK must be 2")
 	}
@@ -110,13 +89,13 @@ func test7978(t *testing.T) {
 	go issue7978go()
 	// test in c code, before callback
 	issue7978wait(0, 1)
-	issue7978check(t, "runtime.cgocall(", "", 1)
+	issue7978check(t, "runtime.cgocall_errno(", "", 1)
 	// test in go code, during callback
 	issue7978wait(2, 3)
 	issue7978check(t, "test.issue7978cb(", "test.issue7978go", 3)
 	// test in c code, after callback
 	issue7978wait(4, 5)
-	issue7978check(t, "runtime.cgocall(", "runtime.cgocallback", 1)
+	issue7978check(t, "runtime.cgocall_errno(", "runtime.cgocallback", 1)
 	// test in go code, after return from cgo
 	issue7978wait(6, 7)
 	issue7978check(t, "test.issue7978go(", "", 3)
diff --git a/misc/cgo/test/issue8428.go b/misc/cgo/test/issue8428.go
index 16fa7cc..a3dc575 100644
--- a/misc/cgo/test/issue8428.go
+++ b/misc/cgo/test/issue8428.go
@@ -20,7 +20,6 @@ struct issue8428two {
 	void *p;
 	char b;
 	char rest[0];
-	char pad;
 };
 
 struct issue8428three {
@@ -35,10 +34,8 @@ import "C"
 import "unsafe"
 
 var _ = C.struct_issue8428one{
-	b: C.char(0),
-	// The trailing rest field is not available in cgo.
-	// See issue 11925.
-	// rest: [0]C.char{},
+	b:    C.char(0),
+	rest: [0]C.char{},
 }
 
 var _ = C.struct_issue8428two{
diff --git a/misc/cgo/test/setgid_linux.go b/misc/cgo/test/setgid_linux.go
index 197f01f..829afce 100644
--- a/misc/cgo/test/setgid_linux.go
+++ b/misc/cgo/test/setgid_linux.go
@@ -3,7 +3,7 @@
 // license that can be found in the LICENSE file.
 
 // Test that setgid does not hang on GNU/Linux.
-// See https://golang.org/issue/3871 for details.
+// See http://code.google.com/p/go/issues/detail?id=3871 for details.
 
 package cgotest
 
diff --git a/misc/cgo/testcdefs/cdefstest.c b/misc/cgo/testcdefs/cdefstest.c
new file mode 100644
index 0000000..ce670e7
--- /dev/null
+++ b/misc/cgo/testcdefs/cdefstest.c
@@ -0,0 +1,9 @@
+// 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 "cdefstest.h"
+
+struct CdefsTest test;
+struct PackedTest packed;
diff --git a/misc/cgo/testcdefs/cdefstest.go b/misc/cgo/testcdefs/cdefstest.go
new file mode 100644
index 0000000..5e613c7
--- /dev/null
+++ b/misc/cgo/testcdefs/cdefstest.go
@@ -0,0 +1,60 @@
+// 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
+
+package cgotest
+
+/*
+// This file tests a bug found in the cgo -cdefs tool that incorrectly
+// translated Go pointer arrays generated by the cgo godefs tool back into C
+// pointer arrays.
+//
+// The comments below show how the type is translated from gcc-style C into Go
+// and back into C for both the buggy version and the correct version
+
+struct cdefsTest {
+	// This was already being handled correctly
+	// Correct: -> Array [20]int8 -> int8 array[20]
+	char array1[20];
+
+	// Buggy:   -> Array [20][20]int8 -> [20]int8 array[20]
+	// Correct: -> Array [20][20]int8 -> int8 array[20][20]
+	char array2[20][20];
+
+	// Buggy:   -> Array [20]*int8 -> *int8 array[20]
+	// Correct: -> Array [20]*int8 -> int8 *array[20]
+	char *array3[20];
+
+	// Buggy:   -> Array [20][20]*int8 -> [20]*int8 array[20]
+	// Correct: -> Array [20]**int8 -> int8 *array[20][20]
+	char *array4[20][20];
+
+	// Buggy:   -> Array [20][20]**int8 -> [20]**int8 array[20]
+	// Correct: -> Array [20][20]**int8 -> int8 **array[20][20]
+	char **array5[20][20];
+};
+
+// Test that packed structures can be translated to C correctly too.
+// See issue 8477.
+
+struct packedTest {
+	char first;
+	int second;
+	long long third;
+} __attribute__((packed));
+
+// Test that conflicting type definitions don't cause problems with cgo.
+// See issue 8477.
+
+typedef struct timespec {
+	double bogus;
+} pid_t;
+
+*/
+import "C"
+
+type CdefsTest C.struct_cdefsTest
+
+//type PackedTest C.struct_packedTest
diff --git a/misc/cgo/testcdefs/main.c b/misc/cgo/testcdefs/main.c
new file mode 100644
index 0000000..594a431
--- /dev/null
+++ b/misc/cgo/testcdefs/main.c
@@ -0,0 +1,76 @@
+// 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 "cdefstest.h"
+
+void runtime·printf(int8*, ...);
+
+// From cdefstest.go.
+typedef struct CdefsOrig CdefsOrig;
+struct CdefsOrig {
+	int8 array1[20];
+	int8 array2[20][20];
+	int8 *array3[20];
+	int8 *array4[20][20];
+	int8 **array5[20][20];
+};
+
+// Packed structs are no longer supported for -cdefs.
+/*
+typedef struct PackedOrig PackedOrig;
+#pragma pack on
+struct PackedOrig {
+	int8 first;
+	int32 second;
+	int64 third;
+};
+#pragma pack off
+*/
+
+void
+main·test(int32 ret)
+{
+	CdefsOrig o;
+	CdefsTest t;
+	// PackedOrig po;
+	// PackedTest pt;
+	
+	ret = 0;
+	if(sizeof(t.array1) != sizeof(o.array1) || offsetof(CdefsTest, array1[0]) != offsetof(CdefsOrig, array1[0])) {
+		runtime·printf("array1: size, offset = %d, %d, want %d, %d\n", sizeof(t.array1), offsetof(CdefsTest, array1[0]), sizeof(o.array1), offsetof(CdefsOrig, array1[0]));
+		ret = 1;
+	}
+	if(sizeof(t.array2) != sizeof(o.array2) || offsetof(CdefsTest, array2[0][0]) != offsetof(CdefsOrig, array2[0][0])) {
+		runtime·printf("array2: size, offset = %d, %d, want %d, %d\n", sizeof(t.array2), offsetof(CdefsTest, array2[0][0]), sizeof(o.array2), offsetof(CdefsOrig, array2[0][0]));
+		ret = 1;
+	}
+	if(sizeof(t.array3) != sizeof(o.array3) || offsetof(CdefsTest, array3[0]) != offsetof(CdefsOrig, array3[0])) {
+		runtime·printf("array3: size, offset = %d, %d, want %d, %d\n", sizeof(t.array3), offsetof(CdefsTest, array3[0]), sizeof(o.array3), offsetof(CdefsOrig, array3[0]));
+		ret = 1;
+	}
+	if(sizeof(t.array4) != sizeof(o.array4) || offsetof(CdefsTest, array4[0][0]) != offsetof(CdefsOrig, array4[0][0])) {
+		runtime·printf("array4: size, offset = %d, %d, want %d, %d\n", sizeof(t.array4), offsetof(CdefsTest, array4[0][0]), sizeof(o.array4), offsetof(CdefsOrig, array4[0][0]));
+		ret = 1;
+	}
+	if(sizeof(t.array5) != sizeof(o.array5) || offsetof(CdefsTest, array5[0][0]) != offsetof(CdefsOrig, array5[0][0])) {
+		runtime·printf("array5: size, offset = %d, %d, want %d, %d\n", sizeof(t.array5), offsetof(CdefsTest, array5[0][0]), sizeof(o.array5), offsetof(CdefsOrig, array5[0][0]));
+		ret = 1;
+	}
+/*
+	if(sizeof(pt.first) != sizeof(po.first) || offsetof(PackedTest, first) != offsetof(PackedOrig, first)) {
+		runtime·printf("first: size, offset = %d, %d, want %d, %d\n", sizeof(pt.first), offsetof(PackedTest, first), sizeof(po.first), offsetof(PackedOrig, first));
+		ret = 1;
+	}
+	if(sizeof(pt.second) != sizeof(po.second) || offsetof(PackedTest, second) != offsetof(PackedOrig, second)) {
+		runtime·printf("second: size, offset = %d, %d, want %d, %d\n", sizeof(pt.second), offsetof(PackedTest, second), sizeof(po.second), offsetof(PackedOrig, second));
+		ret = 1;
+	}
+	if(sizeof(pt.third) != sizeof(po.third) || offsetof(PackedTest, third) != offsetof(PackedOrig, third)) {
+		runtime·printf("third: size, offset = %d, %d, want %d, %d\n", sizeof(pt.third), offsetof(PackedTest, third), sizeof(po.third), offsetof(PackedOrig, third));
+		ret = 1;
+	}
+*/
+	FLUSH(&ret); // flush return value
+}
diff --git a/misc/cgo/testcdefs/main.go b/misc/cgo/testcdefs/main.go
new file mode 100644
index 0000000..9231741
--- /dev/null
+++ b/misc/cgo/testcdefs/main.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 main
+
+import "os"
+
+func test() int32 // in main.c
+
+func main() {
+	os.Exit(int(test()))
+}
diff --git a/misc/cgo/testcdefs/test.bash b/misc/cgo/testcdefs/test.bash
new file mode 100755
index 0000000..01621a4
--- /dev/null
+++ b/misc/cgo/testcdefs/test.bash
@@ -0,0 +1,16 @@
+# 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.
+
+# Just add issue file prefixes to this list if more issues come up
+FILE_PREFIXES="cdefstest"
+
+for FP in $FILE_PREFIXES
+do 
+  go tool cgo -cdefs ${FP}.go > ${FP}.h
+done
+
+go build . && ./testcdefs
+EXIT=$?
+rm -rf _obj testcdefs *.h
+exit $EXIT
diff --git a/misc/cgo/testgodefs/test.bash b/misc/cgo/testgodefs/test.bash
index 14235c0..5281b10 100755
--- a/misc/cgo/testgodefs/test.bash
+++ b/misc/cgo/testgodefs/test.bash
@@ -1,5 +1,3 @@
-#!/usr/bin/env 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.
diff --git a/misc/cgo/testso/cgoso.go b/misc/cgo/testso/cgoso.go
index 29814fa..ba62183 100644
--- a/misc/cgo/testso/cgoso.go
+++ b/misc/cgo/testso/cgoso.go
@@ -11,7 +11,6 @@ package cgosotest
 #cgo dragonfly LDFLAGS: -L. -l cgosotest
 #cgo freebsd LDFLAGS: -L. -l cgosotest
 #cgo openbsd LDFLAGS: -L. -l cgosotest
-#cgo solaris LDFLAGS: -L. -lcgosotest
 #cgo netbsd LDFLAGS: -L. libcgosotest.so
 #cgo darwin LDFLAGS: -L. libcgosotest.dylib
 #cgo windows LDFLAGS: -L. libcgosotest.dll
diff --git a/misc/cgo/testso/cgoso_unix.go b/misc/cgo/testso/cgoso_unix.go
index 49cdeaa..7d5444c 100644
--- a/misc/cgo/testso/cgoso_unix.go
+++ b/misc/cgo/testso/cgoso_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 solaris
+// +build dragonfly freebsd linux netbsd
 
 package cgosotest
 
diff --git a/misc/cgo/testso/test.bash b/misc/cgo/testso/test.bash
new file mode 100755
index 0000000..f4061c6
--- /dev/null
+++ b/misc/cgo/testso/test.bash
@@ -0,0 +1,22 @@
+#!/usr/bin/env bash
+# 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.
+
+set -e
+
+args=
+dyld_envvar=LD_LIBRARY_PATH
+ext=so
+if [ "$(uname)" == "Darwin" ]; then
+	args="-undefined suppress -flat_namespace"
+	dyld_envvar=DYLD_LIBRARY_PATH
+	ext=dylib
+fi
+
+dylib=libcgosotest.$ext
+$(go env CC) $(go env GOGCCFLAGS) -shared $args -o $dylib cgoso_c.c
+go build main.go
+
+eval "$dyld_envvar"=. ./main
+rm -rf $dylib main *.dSYM
diff --git a/misc/cgo/testso/test.bat b/misc/cgo/testso/test.bat
new file mode 100644
index 0000000..b8cc384
--- /dev/null
+++ b/misc/cgo/testso/test.bat
@@ -0,0 +1,18 @@
+:: 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
+
+gcc -c cgoso_c.c
+gcc -shared -o libcgosotest.dll cgoso_c.o
+if not exist libcgosotest.dll goto fail
+go build main.go
+if not exist main.exe goto fail
+main.exe
+goto :end
+
+:fail
+set FAIL=1
+:end
+del /F cgoso_c.o libcgosotest.dll main.exe 2>NUL
diff --git a/misc/chrome/gophertool/gopher.js b/misc/chrome/gophertool/gopher.js
index 09edb29..3238f0f 100644
--- a/misc/chrome/gophertool/gopher.js
+++ b/misc/chrome/gophertool/gopher.js
@@ -3,8 +3,7 @@
 // license that can be found in the LICENSE file.
 
 var numericRE = /^\d+$/;
-var commitRE = /^(?:\d+:)?([0-9a-f]{6,40})$/; // e.g "8486:ab29d2698a47" or "ab29d2698a47"
-var gerritChangeIdRE = /^I[0-9a-f]{4,40}$/; // e.g. Id69c00d908d18151486007ec03da5495b34b05f5
+var commitRE = /^(?:\d+:)?([0-9a-f]{6,20})$/; // e.g "8486:ab29d2698a47" or "ab29d2698a47"
 var pkgRE = /^[a-z0-9_\/]+$/;
 
 function urlForInput(t) {
@@ -14,27 +13,21 @@ function urlForInput(t) {
 
     if (numericRE.test(t)) {
         if (t < 150000) {
-            // We could use the golang.org/cl/ handler here, but
-            // avoid some redirect latency and go right there, since
-            // one is easy. (no server-side mapping)
-            return "https://github.com/golang/go/issues/" + t;
+            return "http://code.google.com/p/go/issues/detail?id=" + t;
         }
-        return "https://golang.org/cl/" + t;
-    }
-
-    if (gerritChangeIdRE.test(t)) {
-        return "https://golang.org/cl/" + t;
+        return "http://codereview.appspot.com/" + t + "/";
     }
 
     var match = commitRE.exec(t);
     if (match) {
-        return "https://golang.org/change/" + match[1];
+        return "http://code.google.com/p/go/source/detail?r=" + match[1];
     }
 
     if (pkgRE.test(t)) {
         // TODO: make this smarter, using a list of packages + substring matches.
         // Get the list from godoc itself in JSON format?
-        return "https://golang.org/pkg/" + t;
+        // TODO: prefer localhost:6060 to golang.org if localhost:6060 is responding. 
+        return "http://golang.org/pkg/" + t;
     }
 
     return null;
diff --git a/misc/chrome/gophertool/popup.html b/misc/chrome/gophertool/popup.html
index 9740406..8bb7795 100644
--- a/misc/chrome/gophertool/popup.html
+++ b/misc/chrome/gophertool/popup.html
@@ -9,13 +9,11 @@
 <script src="popup.js"></script>
 </head>
 <body style='margin: 0.5em; font-family: sans;'>
-<small><a href="#" url="https://golang.org/issue">issue</a>,
-<a href="#" url="https://golang.org/cl">codereview</a>,
-<a href="#" url="https://golang.org/change">commit</a>, or
-<a href="#" url="https://golang.org/pkg/">pkg</a> id/name:</small>
+<small><a href="#" url="http://code.google.com/p/go/issues/list">issue</a>,
+<a href="#" url="http://codereview.appspot.com/">codereview</a>,
+<a href="#" url="http://code.google.com/p/go/source/list">commit</a>, or
+<a href="#" url="http://golang.org/pkg/">pkg</a> id/name:</small>
 <form style='margin: 0' id='navform'><nobr><input id="inputbox" size=10 tabindex=1 /><input type="submit" value="go" /></nobr></form>
-<small>Also: <a href="#" url="https://build.golang.org">buildbots</a>
-<a href="#" url="https://github.com/golang/go">Github</a>
-</small>
+<small>Also: <a href="#" url="http://build.golang.org">buildbots</a></small>
 </body>
 </html>
diff --git a/misc/dashboard/codereview/app.yaml b/misc/dashboard/codereview/app.yaml
new file mode 100644
index 0000000..372eca5
--- /dev/null
+++ b/misc/dashboard/codereview/app.yaml
@@ -0,0 +1,24 @@
+application: gocodereview
+version: 1
+runtime: go
+api_version: go1
+
+inbound_services:
+- mail
+
+handlers:
+- url: /static/(.*)
+  static_files: static/\1
+  upload: static/.*
+- url: /_ah/mail/.*
+  script: _go_app
+  login: admin
+- url: /_ah/queue/go/delay
+  script: _go_app
+  login: admin
+- url: /(gc|update-cl)
+  script: _go_app
+  login: admin
+- url: /.*
+  script: _go_app
+  login: required
diff --git a/misc/dashboard/codereview/cron.yaml b/misc/dashboard/codereview/cron.yaml
new file mode 100644
index 0000000..3d33d32
--- /dev/null
+++ b/misc/dashboard/codereview/cron.yaml
@@ -0,0 +1,4 @@
+cron:
+- description: GC
+  url: /gc
+  schedule: every 6 hours
diff --git a/misc/dashboard/codereview/dashboard/cl.go b/misc/dashboard/codereview/dashboard/cl.go
new file mode 100644
index 0000000..0ef3303
--- /dev/null
+++ b/misc/dashboard/codereview/dashboard/cl.go
@@ -0,0 +1,493 @@
+// 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 dashboard
+
+// This file handles operations on the CL entity kind.
+
+import (
+	"bytes"
+	"encoding/json"
+	"fmt"
+	"html/template"
+	"io"
+	"io/ioutil"
+	"net/http"
+	"net/url"
+	"regexp"
+	"sort"
+	"strings"
+	"time"
+
+	"appengine"
+	"appengine/datastore"
+	"appengine/taskqueue"
+	"appengine/urlfetch"
+	"appengine/user"
+)
+
+func init() {
+	http.HandleFunc("/assign", handleAssign)
+	http.HandleFunc("/update-cl", handleUpdateCL)
+}
+
+const codereviewBase = "http://codereview.appspot.com"
+const gobotBase = "http://research.swtch.com/gobot_codereview"
+
+var clRegexp = regexp.MustCompile(`\d+`)
+
+// CL represents a code review.
+type CL struct {
+	Number string // e.g. "5903061"
+	Closed bool
+	Owner  string // email address
+
+	Created, Modified time.Time
+
+	Description  []byte `datastore:",noindex"`
+	FirstLine    string `datastore:",noindex"`
+	LGTMs        []string
+	NotLGTMs     []string
+	LastUpdateBy string // author of most recent review message
+	LastUpdate   string `datastore:",noindex"` // first line of most recent review message
+
+	// Mail information.
+	Subject       string   `datastore:",noindex"`
+	Recipients    []string `datastore:",noindex"`
+	LastMessageID string   `datastore:",noindex"`
+
+	// These are person IDs (e.g. "rsc"); they may be empty
+	Author   string
+	Reviewer string
+}
+
+// Reviewed reports whether the reviewer has replied to the CL.
+// The heuristic is that the CL has been replied to if it is LGTMed
+// or if the last CL message was from the reviewer.
+func (cl *CL) Reviewed() bool {
+	if cl.LastUpdateBy == cl.Reviewer {
+		return true
+	}
+	if person := emailToPerson[cl.LastUpdateBy]; person != "" && person == cl.Reviewer {
+		return true
+	}
+	for _, who := range cl.LGTMs {
+		if who == cl.Reviewer {
+			return true
+		}
+	}
+	return false
+}
+
+// DisplayOwner returns the CL's owner, either as their email address
+// or the person ID if it's a reviewer. It is for display only.
+func (cl *CL) DisplayOwner() string {
+	if p, ok := emailToPerson[cl.Owner]; ok {
+		return p
+	}
+	return cl.Owner
+}
+
+func (cl *CL) FirstLineHTML() template.HTML {
+	s := template.HTMLEscapeString(cl.FirstLine)
+	// Embolden the package name.
+	if i := strings.Index(s, ":"); i >= 0 {
+		s = "<b>" + s[:i] + "</b>" + s[i:]
+	}
+	return template.HTML(s)
+}
+
+func formatEmails(e []string) template.HTML {
+	x := make([]string, len(e))
+	for i, s := range e {
+		s = template.HTMLEscapeString(s)
+		if !strings.Contains(s, "@") {
+			s = "<b>" + s + "</b>"
+		}
+		s = `<span class="email">` + s + "</span>"
+		x[i] = s
+	}
+	return template.HTML(strings.Join(x, ", "))
+}
+
+func (cl *CL) LGTMHTML() template.HTML {
+	return formatEmails(cl.LGTMs)
+}
+
+func (cl *CL) NotLGTMHTML() template.HTML {
+	return formatEmails(cl.NotLGTMs)
+}
+
+func (cl *CL) ModifiedAgo() string {
+	// Just the first non-zero unit.
+	units := [...]struct {
+		suffix string
+		unit   time.Duration
+	}{
+		{"d", 24 * time.Hour},
+		{"h", time.Hour},
+		{"m", time.Minute},
+		{"s", time.Second},
+	}
+	d := time.Now().Sub(cl.Modified)
+	for _, u := range units {
+		if d > u.unit {
+			return fmt.Sprintf("%d%s", d/u.unit, u.suffix)
+		}
+	}
+	return "just now"
+}
+
+func handleAssign(w http.ResponseWriter, r *http.Request) {
+	c := appengine.NewContext(r)
+
+	if r.Method != "POST" {
+		http.Error(w, "Bad method "+r.Method, 400)
+		return
+	}
+
+	u := user.Current(c)
+	person, ok := emailToPerson[u.Email]
+	if !ok {
+		http.Error(w, "Not allowed", http.StatusUnauthorized)
+		return
+	}
+
+	n, rev := r.FormValue("cl"), r.FormValue("r")
+	if !clRegexp.MatchString(n) {
+		c.Errorf("Bad CL %q", n)
+		http.Error(w, "Bad CL", 400)
+		return
+	}
+	if _, ok := preferredEmail[rev]; !ok && rev != "" {
+		c.Errorf("Unknown reviewer %q", rev)
+		http.Error(w, "Unknown reviewer", 400)
+		return
+	}
+
+	key := datastore.NewKey(c, "CL", n, 0, nil)
+
+	if rev != "" {
+		// Make sure the reviewer is listed in Rietveld as a reviewer.
+		url := codereviewBase + "/" + n + "/fields"
+		resp, err := urlfetch.Client(c).Get(url + "?field=reviewers")
+		if err != nil {
+			c.Errorf("Retrieving CL reviewer list failed: %v", err)
+			http.Error(w, err.Error(), 500)
+			return
+		}
+		defer resp.Body.Close()
+		body, err := ioutil.ReadAll(resp.Body)
+		if err != nil {
+			c.Errorf("Failed reading body: %v", err)
+			http.Error(w, err.Error(), 500)
+			return
+		}
+		if resp.StatusCode != 200 {
+			c.Errorf("Retrieving CL reviewer list failed: got HTTP response %d\nBody: %s", resp.StatusCode, body)
+			http.Error(w, "Failed contacting Rietveld", 500)
+			return
+		}
+
+		var apiResp struct {
+			Reviewers []string `json:"reviewers"`
+		}
+		if err := json.Unmarshal(body, &apiResp); err != nil {
+			// probably can't be retried
+			msg := fmt.Sprintf("Malformed JSON from %v: %v", url, err)
+			c.Errorf("%s", msg)
+			http.Error(w, msg, 500)
+			return
+		}
+		found := false
+		for _, r := range apiResp.Reviewers {
+			if emailToPerson[r] == rev {
+				found = true
+				break
+			}
+		}
+		if !found {
+			c.Infof("Adding %v as a reviewer of CL %v", rev, n)
+
+			url := fmt.Sprintf("%s?cl=%s&r=%s&obo=%s", gobotBase, n, rev, person)
+			resp, err := urlfetch.Client(c).Get(url)
+			if err != nil {
+				c.Errorf("Gobot GET failed: %v", err)
+				http.Error(w, err.Error(), 500)
+				return
+			}
+			defer resp.Body.Close()
+			body, err := ioutil.ReadAll(resp.Body)
+			if err != nil {
+				c.Errorf("Failed reading Gobot body: %v", err)
+				http.Error(w, err.Error(), 500)
+				return
+			}
+			if resp.StatusCode != 200 {
+				c.Errorf("Gobot GET failed: got HTTP response %d\nBody: %s", resp.StatusCode, body)
+				http.Error(w, "Failed contacting Gobot", 500)
+				return
+			}
+
+			c.Infof("Gobot said %q", resp.Status)
+		}
+	}
+
+	// Update our own record.
+	err := datastore.RunInTransaction(c, func(c appengine.Context) error {
+		cl := new(CL)
+		err := datastore.Get(c, key, cl)
+		if err != nil {
+			return err
+		}
+		cl.Reviewer = rev
+		_, err = datastore.Put(c, key, cl)
+		return err
+	}, nil)
+	if err != nil {
+		msg := fmt.Sprintf("Assignment failed: %v", err)
+		c.Errorf("%s", msg)
+		http.Error(w, msg, 500)
+		return
+	}
+	c.Infof("Assigned CL %v to %v", n, rev)
+}
+
+func UpdateCLLater(c appengine.Context, n string, delay time.Duration) {
+	t := taskqueue.NewPOSTTask("/update-cl", url.Values{
+		"cl": []string{n},
+	})
+	t.Delay = delay
+	if _, err := taskqueue.Add(c, t, "update-cl"); err != nil {
+		c.Errorf("Failed adding task: %v", err)
+	}
+}
+
+func handleUpdateCL(w http.ResponseWriter, r *http.Request) {
+	c := appengine.NewContext(r)
+
+	n := r.FormValue("cl")
+	if !clRegexp.MatchString(n) {
+		c.Errorf("Bad CL %q", n)
+		http.Error(w, "Bad CL", 400)
+		return
+	}
+
+	if err := updateCL(c, n); err != nil {
+		c.Errorf("Failed updating CL %v: %v", n, err)
+		http.Error(w, "Failed update", 500)
+		return
+	}
+
+	io.WriteString(w, "OK")
+}
+
+// apiMessage describes the JSON sent back by Rietveld in the CL messages list.
+type apiMessage struct {
+	Date       string   `json:"date"`
+	Text       string   `json:"text"`
+	Sender     string   `json:"sender"`
+	Recipients []string `json:"recipients"`
+	Approval   bool     `json:"approval"`
+}
+
+// byDate implements sort.Interface to order the messages by date, earliest first.
+// The dates are sent in RFC 3339 format, so string comparison matches time value comparison.
+type byDate []*apiMessage
+
+func (x byDate) Len() int           { return len(x) }
+func (x byDate) Swap(i, j int)      { x[i], x[j] = x[j], x[i] }
+func (x byDate) Less(i, j int) bool { return x[i].Date < x[j].Date }
+
+// updateCL updates a single CL. If a retryable failure occurs, an error is returned.
+func updateCL(c appengine.Context, n string) error {
+	c.Debugf("Updating CL %v", n)
+	key := datastore.NewKey(c, "CL", n, 0, nil)
+
+	url := codereviewBase + "/api/" + n + "?messages=true"
+	resp, err := urlfetch.Client(c).Get(url)
+	if err != nil {
+		return err
+	}
+	defer resp.Body.Close()
+
+	raw, err := ioutil.ReadAll(resp.Body)
+	if err != nil {
+		return fmt.Errorf("Failed reading HTTP body: %v", err)
+	}
+
+	// Special case for abandoned CLs.
+	if resp.StatusCode == 404 && bytes.Contains(raw, []byte("No issue exists with that id")) {
+		// Don't bother checking for errors. The CL might never have been saved, for instance.
+		datastore.Delete(c, key)
+		c.Infof("Deleted abandoned CL %v", n)
+		return nil
+	}
+
+	if resp.StatusCode != 200 {
+		return fmt.Errorf("Update: got HTTP response %d", resp.StatusCode)
+	}
+
+	var apiResp struct {
+		Description string        `json:"description"`
+		Reviewers   []string      `json:"reviewers"`
+		Created     string        `json:"created"`
+		OwnerEmail  string        `json:"owner_email"`
+		Modified    string        `json:"modified"`
+		Closed      bool          `json:"closed"`
+		Subject     string        `json:"subject"`
+		Messages    []*apiMessage `json:"messages"`
+	}
+	if err := json.Unmarshal(raw, &apiResp); err != nil {
+		// probably can't be retried
+		c.Errorf("Malformed JSON from %v: %v", url, err)
+		return nil
+	}
+	//c.Infof("RAW: %+v", apiResp)
+	sort.Sort(byDate(apiResp.Messages))
+
+	cl := &CL{
+		Number:      n,
+		Closed:      apiResp.Closed,
+		Owner:       apiResp.OwnerEmail,
+		Description: []byte(apiResp.Description),
+		FirstLine:   apiResp.Description,
+		Subject:     apiResp.Subject,
+		Author:      emailToPerson[apiResp.OwnerEmail],
+	}
+	cl.Created, err = time.Parse("2006-01-02 15:04:05.000000", apiResp.Created)
+	if err != nil {
+		c.Errorf("Bad creation time %q: %v", apiResp.Created, err)
+	}
+	cl.Modified, err = time.Parse("2006-01-02 15:04:05.000000", apiResp.Modified)
+	if err != nil {
+		c.Errorf("Bad modification time %q: %v", apiResp.Modified, err)
+	}
+	if i := strings.Index(cl.FirstLine, "\n"); i >= 0 {
+		cl.FirstLine = cl.FirstLine[:i]
+	}
+	// Treat zero reviewers as a signal that the CL is completed.
+	// This could be after the CL has been submitted, but before the CL author has synced,
+	// but it could also be a CL manually edited to remove reviewers.
+	if len(apiResp.Reviewers) == 0 {
+		cl.Closed = true
+	}
+
+	lgtm := make(map[string]bool)
+	notLGTM := make(map[string]bool)
+	rcpt := make(map[string]bool)
+	for _, msg := range apiResp.Messages {
+		s, rev := msg.Sender, false
+		if p, ok := emailToPerson[s]; ok {
+			s, rev = p, true
+		}
+
+		line := firstLine(msg.Text)
+		if line != "" {
+			cl.LastUpdateBy = msg.Sender
+			cl.LastUpdate = line
+		}
+
+		// CLs submitted by someone other than the CL owner do not immediately
+		// transition to "closed". Let's simulate the intention by treating
+		// messages starting with "*** Submitted as " from a reviewer as a
+		// signal that the CL is now closed.
+		if rev && strings.HasPrefix(msg.Text, "*** Submitted as ") {
+			cl.Closed = true
+		}
+
+		if msg.Approval {
+			lgtm[s] = true
+			delete(notLGTM, s) // "LGTM" overrules previous "NOT LGTM"
+		}
+		if strings.Contains(line, "NOT LGTM") {
+			notLGTM[s] = true
+			delete(lgtm, s) // "NOT LGTM" overrules previous "LGTM"
+		}
+
+		for _, r := range msg.Recipients {
+			rcpt[r] = true
+		}
+	}
+	for l := range lgtm {
+		cl.LGTMs = append(cl.LGTMs, l)
+	}
+	for l := range notLGTM {
+		cl.NotLGTMs = append(cl.NotLGTMs, l)
+	}
+	for r := range rcpt {
+		cl.Recipients = append(cl.Recipients, r)
+	}
+	sort.Strings(cl.LGTMs)
+	sort.Strings(cl.NotLGTMs)
+	sort.Strings(cl.Recipients)
+
+	err = datastore.RunInTransaction(c, func(c appengine.Context) error {
+		ocl := new(CL)
+		err := datastore.Get(c, key, ocl)
+		if err != nil && err != datastore.ErrNoSuchEntity {
+			return err
+		} else if err == nil {
+			// LastMessageID and Reviewer need preserving.
+			cl.LastMessageID = ocl.LastMessageID
+			cl.Reviewer = ocl.Reviewer
+		}
+		_, err = datastore.Put(c, key, cl)
+		return err
+	}, nil)
+	if err != nil {
+		return err
+	}
+	c.Infof("Updated CL %v", n)
+	return nil
+}
+
+// trailingSpaceRE matches trailing spaces.
+var trailingSpaceRE = regexp.MustCompile(`(?m)[ \t\r]+$`)
+
+// removeRE is the list of patterns to skip over at the beginning of a
+// message when looking for message text.
+var removeRE = regexp.MustCompile(`(?m-s)\A(` +
+	// Skip leading "Hello so-and-so," generated by codereview plugin.
+	`(Hello(.|\n)*?\n\n)` +
+
+	// Skip quoted text.
+	`|((On.*|.* writes|.* wrote):\n)` +
+	`|((>.*\n)+)` +
+
+	// Skip lines with no letters.
+	`|(([^A-Za-z]*\n)+)` +
+
+	// Skip links to comments and file info.
+	`|(http://codereview.*\n([^ ]+:[0-9]+:.*\n)?)` +
+	`|(File .*:\n)` +
+
+	`)`,
+)
+
+// firstLine returns the first interesting line of the message text.
+func firstLine(text string) string {
+	// Cut trailing spaces.
+	text = trailingSpaceRE.ReplaceAllString(text, "")
+
+	// Skip uninteresting lines.
+	for {
+		text = strings.TrimSpace(text)
+		m := removeRE.FindStringIndex(text)
+		if m == nil || m[0] != 0 {
+			break
+		}
+		text = text[m[1]:]
+	}
+
+	// Chop line at newline or else at 74 bytes.
+	i := strings.Index(text, "\n")
+	if i >= 0 {
+		text = text[:i]
+	}
+	if len(text) > 74 {
+		text = text[:70] + "..."
+	}
+	return text
+}
diff --git a/misc/dashboard/codereview/dashboard/front.go b/misc/dashboard/codereview/dashboard/front.go
new file mode 100644
index 0000000..ea9fe0d
--- /dev/null
+++ b/misc/dashboard/codereview/dashboard/front.go
@@ -0,0 +1,299 @@
+// 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 dashboard
+
+// This file handles the front page.
+
+import (
+	"bytes"
+	"html/template"
+	"io"
+	"net/http"
+	"strings"
+	"sync"
+	"time"
+
+	"appengine"
+	"appengine/datastore"
+	"appengine/user"
+)
+
+func init() {
+	http.HandleFunc("/", handleFront)
+	http.HandleFunc("/favicon.ico", http.NotFound)
+}
+
+// maximum number of active CLs to show in person-specific tables.
+const maxCLs = 100
+
+func handleFront(w http.ResponseWriter, r *http.Request) {
+	c := appengine.NewContext(r)
+
+	data := &frontPageData{
+		Reviewers: personList,
+		User:      user.Current(c).Email,
+		IsAdmin:   user.IsAdmin(c),
+	}
+	var currentPerson string
+	u := data.User
+	you := "you"
+	if e := r.FormValue("user"); e != "" {
+		u = e
+		you = e
+	}
+	currentPerson, data.UserIsReviewer = emailToPerson[u]
+	if !data.UserIsReviewer {
+		currentPerson = u
+	}
+
+	var wg sync.WaitGroup
+	errc := make(chan error, 10)
+	activeCLs := datastore.NewQuery("CL").
+		Filter("Closed =", false).
+		Order("-Modified")
+
+	tableFetch := func(index int, f func(tbl *clTable) error) {
+		wg.Add(1)
+		go func() {
+			defer wg.Done()
+			start := time.Now()
+			if err := f(&data.Tables[index]); err != nil {
+				errc <- err
+			}
+			data.Timing[index] = time.Now().Sub(start)
+		}()
+	}
+
+	data.Tables[0].Title = "CLs assigned to " + you + " for review"
+	if data.UserIsReviewer {
+		tableFetch(0, func(tbl *clTable) error {
+			q := activeCLs.Filter("Reviewer =", currentPerson).Limit(maxCLs)
+			tbl.Assignable = true
+			_, err := q.GetAll(c, &tbl.CLs)
+			return err
+		})
+	}
+
+	tableFetch(1, func(tbl *clTable) error {
+		q := activeCLs
+		if data.UserIsReviewer {
+			q = q.Filter("Author =", currentPerson)
+		} else {
+			q = q.Filter("Owner =", currentPerson)
+		}
+		q = q.Limit(maxCLs)
+		tbl.Title = "CLs sent by " + you
+		tbl.Assignable = true
+		_, err := q.GetAll(c, &tbl.CLs)
+		return err
+	})
+
+	tableFetch(2, func(tbl *clTable) error {
+		q := activeCLs.Limit(50)
+		tbl.Title = "Other active CLs"
+		tbl.Assignable = true
+		if _, err := q.GetAll(c, &tbl.CLs); err != nil {
+			return err
+		}
+		// filter
+		for i := len(tbl.CLs) - 1; i >= 0; i-- {
+			cl := tbl.CLs[i]
+			if cl.Owner == currentPerson || cl.Author == currentPerson || cl.Reviewer == currentPerson {
+				// Preserve order.
+				copy(tbl.CLs[i:], tbl.CLs[i+1:])
+				tbl.CLs = tbl.CLs[:len(tbl.CLs)-1]
+			}
+		}
+		return nil
+	})
+
+	tableFetch(3, func(tbl *clTable) error {
+		q := datastore.NewQuery("CL").
+			Filter("Closed =", true).
+			Order("-Modified").
+			Limit(10)
+		tbl.Title = "Recently closed CLs"
+		tbl.Assignable = false
+		_, err := q.GetAll(c, &tbl.CLs)
+		return err
+	})
+
+	// Not really a table fetch.
+	tableFetch(0, func(_ *clTable) error {
+		var err error
+		data.LogoutURL, err = user.LogoutURL(c, "/")
+		return err
+	})
+
+	wg.Wait()
+
+	select {
+	case err := <-errc:
+		c.Errorf("%v", err)
+		http.Error(w, err.Error(), http.StatusInternalServerError)
+		return
+	default:
+	}
+
+	var b bytes.Buffer
+	if err := frontPage.ExecuteTemplate(&b, "front", &data); err != nil {
+		http.Error(w, err.Error(), http.StatusInternalServerError)
+		return
+	}
+
+	io.Copy(w, &b)
+}
+
+type frontPageData struct {
+	Tables [4]clTable
+	Timing [4]time.Duration
+
+	Reviewers      []string
+	UserIsReviewer bool
+
+	User, LogoutURL string // actual logged in user
+	IsAdmin         bool
+}
+
+type clTable struct {
+	Title      string
+	Assignable bool
+	CLs        []*CL
+}
+
+var frontPage = template.Must(template.New("front").Funcs(template.FuncMap{
+	"selected": func(a, b string) string {
+		if a == b {
+			return "selected"
+		}
+		return ""
+	},
+	"shortemail": func(s string) string {
+		if i := strings.Index(s, "@"); i >= 0 {
+			s = s[:i]
+		}
+		return s
+	},
+}).Parse(`
+<!doctype html>
+<html>
+  <head>
+    <title>Go code reviews</title>
+    <link rel="icon" type="image/png" href="/static/icon.png" />
+    <style type="text/css">
+      body {
+        font-family: Helvetica, sans-serif;
+      }
+      img#gopherstamp {
+        float: right;
+	height: auto;
+	width: 250px;
+      }
+      h1, h2, h3 {
+        color: #777;
+	margin-bottom: 0;
+      }
+      table {
+        border-spacing: 0;
+      }
+      td {
+        vertical-align: top;
+        padding: 2px 5px;
+      }
+      tr.unreplied td.email {
+        border-left: 2px solid blue;
+      }
+      tr.pending td {
+        background: #fc8;
+      }
+      tr.failed td {
+        background: #f88;
+      }
+      tr.saved td {
+        background: #8f8;
+      }
+      .cls {
+        margin-top: 0;
+      }
+      a {
+        color: blue;
+	text-decoration: none;  /* no link underline */
+      }
+      address {
+        font-size: 10px;
+	text-align: right;
+      }
+      .email {
+        font-family: monospace;
+      }
+    </style>
+    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
+  </head>
+  <body>
+
+<img id="gopherstamp" src="/static/gopherstamp.jpg" />
+<h1>Go code reviews</h1>
+
+<table class="cls">
+{{range $i, $tbl := .Tables}}
+<tr><td colspan="5"><h3>{{$tbl.Title}}</h3></td></tr>
+{{if .CLs}}
+{{range $cl := .CLs}}
+  <tr id="cl-{{$cl.Number}}" class="{{if not $i}}{{if not .Reviewed}}unreplied{{end}}{{end}}">
+    <td class="email">{{$cl.DisplayOwner}}</td>
+    <td>
+    {{if $tbl.Assignable}}
+    <select id="cl-rev-{{$cl.Number}}" {{if not $.UserIsReviewer}}disabled{{end}}>
+      <option></option>
+      {{range $.Reviewers}}
+      <option {{selected . $cl.Reviewer}}>{{.}}</option>
+      {{end}}
+    </select>
+    <script type="text/javascript">
+    $(function() {
+      $('#cl-rev-{{$cl.Number}}').change(function() {
+        var r = $(this).val();
+        var row = $('tr#cl-{{$cl.Number}}');
+        row.addClass('pending');
+        $.post('/assign', {
+          'cl': '{{$cl.Number}}',
+          'r': r
+        }).success(function() {
+          row.removeClass('pending');
+          row.addClass('saved');
+        }).error(function() {
+          row.removeClass('pending');
+          row.addClass('failed');
+        });
+      });
+    });
+    </script>
+    {{end}}
+    </td>
+    <td>
+      <a href="http://codereview.appspot.com/{{.Number}}/" title="{{ printf "%s" .Description}}">{{.Number}}: {{.FirstLineHTML}}</a>
+      {{if and .LGTMs $tbl.Assignable}}<br /><span style="font-size: smaller;">LGTMs: {{.LGTMHTML}}</span>{{end}}
+      {{if and .NotLGTMs $tbl.Assignable}}<br /><span style="font-size: smaller; color: #f74545;">NOT LGTMs: {{.NotLGTMHTML}}</span>{{end}}
+      {{if .LastUpdateBy}}<br /><span style="font-size: smaller; color: #777777;">(<span title="{{.LastUpdateBy}}">{{.LastUpdateBy | shortemail}}</span>) {{.LastUpdate}}</span>{{end}}
+    </td>
+    <td title="Last modified">{{.ModifiedAgo}}</td>
+    <td>{{if $.IsAdmin}}<a href="/update-cl?cl={{.Number}}" title="Update this CL">&#x27f3;</a>{{end}}</td>
+  </tr>
+{{end}}
+{{else}}
+<tr><td colspan="5"><em>none</em></td></tr>
+{{end}}
+{{end}}
+</table>
+
+<hr />
+<address>
+You are <span class="email">{{.User}}</span> · <a href="{{.LogoutURL}}">logout</a><br />
+datastore timing: {{range .Timing}} {{.}}{{end}}
+</address>
+
+  </body>
+</html>
+`))
diff --git a/misc/dashboard/codereview/dashboard/gc.go b/misc/dashboard/codereview/dashboard/gc.go
new file mode 100644
index 0000000..a80b375
--- /dev/null
+++ b/misc/dashboard/codereview/dashboard/gc.go
@@ -0,0 +1,47 @@
+// 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 dashboard
+
+// This file handles garbage collection of old CLs.
+
+import (
+	"net/http"
+	"time"
+
+	"appengine"
+	"appengine/datastore"
+)
+
+func init() {
+	http.HandleFunc("/gc", handleGC)
+}
+
+func handleGC(w http.ResponseWriter, r *http.Request) {
+	c := appengine.NewContext(r)
+
+	// Delete closed CLs that haven't been modified in 168 hours (7 days).
+	cutoff := time.Now().Add(-168 * time.Hour)
+	q := datastore.NewQuery("CL").
+		Filter("Closed =", true).
+		Filter("Modified <", cutoff).
+		Limit(100).
+		KeysOnly()
+	keys, err := q.GetAll(c, nil)
+	if err != nil {
+		c.Errorf("GetAll failed for old CLs: %v", err)
+		http.Error(w, err.Error(), http.StatusInternalServerError)
+		return
+	}
+	if len(keys) == 0 {
+		return
+	}
+
+	if err := datastore.DeleteMulti(c, keys); err != nil {
+		c.Errorf("DeleteMulti failed for old CLs: %v", err)
+		http.Error(w, err.Error(), http.StatusInternalServerError)
+		return
+	}
+	c.Infof("Deleted %d old CLs", len(keys))
+}
diff --git a/misc/dashboard/codereview/dashboard/mail.go b/misc/dashboard/codereview/dashboard/mail.go
new file mode 100644
index 0000000..838d082
--- /dev/null
+++ b/misc/dashboard/codereview/dashboard/mail.go
@@ -0,0 +1,68 @@
+// 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 dashboard
+
+// This file handles receiving mail.
+
+import (
+	"net/http"
+	"net/mail"
+	"regexp"
+	"time"
+
+	"appengine"
+	"appengine/datastore"
+)
+
+func init() {
+	http.HandleFunc("/_ah/mail/", handleMail)
+}
+
+var subjectRegexp = regexp.MustCompile(`.*code review (\d+):.*`)
+
+func handleMail(w http.ResponseWriter, r *http.Request) {
+	c := appengine.NewContext(r)
+
+	defer r.Body.Close()
+	msg, err := mail.ReadMessage(r.Body)
+	if err != nil {
+		c.Errorf("mail.ReadMessage: %v", err)
+		return
+	}
+
+	subj := msg.Header.Get("Subject")
+	m := subjectRegexp.FindStringSubmatch(subj)
+	if len(m) != 2 {
+		c.Debugf("Subject %q did not match /%v/", subj, subjectRegexp)
+		return
+	}
+
+	c.Infof("Found issue %q", m[1])
+
+	// Track the MessageID.
+	key := datastore.NewKey(c, "CL", m[1], 0, nil)
+	err = datastore.RunInTransaction(c, func(c appengine.Context) error {
+		cl := new(CL)
+		err := datastore.Get(c, key, cl)
+		if err != nil && err != datastore.ErrNoSuchEntity {
+			return err
+		}
+		if err == datastore.ErrNoSuchEntity {
+			// Must set sentinel values for time.Time fields
+			// if this is a new entity.
+			cl.Created = time.Unix(0, 0)
+			cl.Modified = time.Unix(0, 0)
+		}
+		cl.LastMessageID = msg.Header.Get("Message-ID")
+		_, err = datastore.Put(c, key, cl)
+		return err
+	}, nil)
+	if err != nil {
+		c.Errorf("datastore transaction failed: %v", err)
+	}
+
+	// Update the CL after a delay to give Rietveld a chance to catch up.
+	UpdateCLLater(c, m[1], 10*time.Second)
+}
diff --git a/misc/dashboard/codereview/dashboard/people.go b/misc/dashboard/codereview/dashboard/people.go
new file mode 100644
index 0000000..7bab253
--- /dev/null
+++ b/misc/dashboard/codereview/dashboard/people.go
@@ -0,0 +1,65 @@
+// 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 dashboard
+
+// This file handles identities of people.
+
+import (
+	"sort"
+)
+
+var (
+	emailToPerson  = make(map[string]string) // email => person
+	preferredEmail = make(map[string]string) // person => email
+	personList     []string
+)
+
+func init() {
+	// People we assume have golang.org and google.com accounts,
+	// and prefer to use their golang.org address for code review.
+	gophers := [...]string{
+		"adg",
+		"agl",
+		"bradfitz",
+		"campoy",
+		"cshapiro",
+		"dsymonds",
+		"gri",
+		"iant",
+		"khr",
+		"mpvl",
+		"nigeltao",
+		"r",
+		"rsc",
+		"sameer",
+	}
+	for _, p := range gophers {
+		personList = append(personList, p)
+		emailToPerson[p+"@golang.org"] = p
+		emailToPerson[p+"@google.com"] = p
+		preferredEmail[p] = p + "@golang.org"
+	}
+	// Other people.
+	others := map[string]string{
+		"adonovan": "adonovan at google.com",
+		"brainman": "alex.brainman at gmail.com",
+		"ality":    "ality at pbrane.org",
+		"dfc":      "dave at cheney.net",
+		"dvyukov":  "dvyukov at google.com",
+		"gustavo":  "gustavo at niemeyer.net",
+		"jsing":    "jsing at google.com",
+		"mikio":    "mikioh.mikioh at gmail.com",
+		"minux":    "minux.ma at gmail.com",
+		"remy":     "remyoudompheng at gmail.com",
+		"rminnich": "rminnich at gmail.com",
+	}
+	for p, e := range others {
+		personList = append(personList, p)
+		emailToPerson[e] = p
+		preferredEmail[p] = e
+	}
+
+	sort.Strings(personList)
+}
diff --git a/misc/dashboard/codereview/index.yaml b/misc/dashboard/codereview/index.yaml
new file mode 100644
index 0000000..a87073c
--- /dev/null
+++ b/misc/dashboard/codereview/index.yaml
@@ -0,0 +1,25 @@
+indexes:
+
+- kind: CL
+  properties:
+  - name: Author
+  - name: Modified
+    direction: desc
+
+- kind: CL
+  properties:
+  - name: Owner
+  - name: Modified
+    direction: desc
+
+- kind: CL
+  properties:
+  - name: Closed
+  - name: Modified
+    direction: desc
+
+- kind: CL
+  properties:
+  - name: Reviewer
+  - name: Modified
+    direction: desc
diff --git a/misc/dashboard/codereview/queue.yaml b/misc/dashboard/codereview/queue.yaml
new file mode 100644
index 0000000..1a35fac
--- /dev/null
+++ b/misc/dashboard/codereview/queue.yaml
@@ -0,0 +1,4 @@
+queue:
+- name: update-cl
+  rate: 12/m
+  bucket_size: 1
diff --git a/misc/dashboard/codereview/static/gopherstamp.jpg b/misc/dashboard/codereview/static/gopherstamp.jpg
new file mode 100644
index 0000000..b17f3c8
Binary files /dev/null and b/misc/dashboard/codereview/static/gopherstamp.jpg differ
diff --git a/misc/dashboard/codereview/static/icon.png b/misc/dashboard/codereview/static/icon.png
new file mode 100644
index 0000000..c929ac8
Binary files /dev/null and b/misc/dashboard/codereview/static/icon.png differ
diff --git a/misc/editors b/misc/editors
index 3a0f73f..850ec34 100644
--- a/misc/editors
+++ b/misc/editors
@@ -1,5 +1,5 @@
 For information about plugins and other support for Go in editors and shells,
 see this page on the Go Wiki:
 
-https://golang.org/wiki/IDEsAndTextEditorPlugins
+https://code.google.com/p/go-wiki/wiki/IDEsAndTextEditorPlugins
 
diff --git a/misc/makerelease/darwin/Distribution b/misc/makerelease/darwin/Distribution
new file mode 100644
index 0000000..8b764b6
--- /dev/null
+++ b/misc/makerelease/darwin/Distribution
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8" standalone="no"?>
+<installer-script minSpecVersion="1.000000">
+    <title>Go</title>
+    <background mime-type="image/png" file="bg.png"/>
+    <options customize="never" allow-external-scripts="no"/>
+    <domains enable_localSystem="true" />
+    <installation-check script="installCheck();"/>
+    <script>
+function installCheck() {
+    if(!(system.compareVersions(system.version.ProductVersion, '10.6.0') >= 0)) {
+        my.result.title = 'Unable to install';
+        my.result.message = 'Go requires Mac OS X 10.6 or later.';
+        my.result.type = 'Fatal';
+        return false;
+    }
+    if(system.files.fileExistsAtPath('/usr/local/go/bin/go')) {
+	    my.result.title = 'Previous Installation Detected';
+	    my.result.message = 'A previous installation of Go exists at /usr/local/go. This installer will remove the previous installation prior to installing. Please back up any data before proceeding.';
+	    my.result.type = 'Warning';
+	    return false;
+	}
+    return true;    
+}
+    </script>
+    <choices-outline>
+        <line choice="com.googlecode.go.choice"/>
+    </choices-outline>
+    <choice id="com.googlecode.go.choice" title="Go">
+        <pkg-ref id="com.googlecode.go.pkg"/>
+    </choice>
+    <pkg-ref id="com.googlecode.go.pkg" auth="Root">com.googlecode.go.pkg</pkg-ref>
+</installer-script>
diff --git a/misc/makerelease/darwin/Resources/bg.png b/misc/makerelease/darwin/Resources/bg.png
new file mode 100644
index 0000000..c3d8ea9
Binary files /dev/null and b/misc/makerelease/darwin/Resources/bg.png differ
diff --git a/misc/makerelease/darwin/etc/paths.d/go b/misc/makerelease/darwin/etc/paths.d/go
new file mode 100644
index 0000000..532e5f9
--- /dev/null
+++ b/misc/makerelease/darwin/etc/paths.d/go
@@ -0,0 +1 @@
+/usr/local/go/bin
diff --git a/misc/makerelease/darwin/scripts/postinstall b/misc/makerelease/darwin/scripts/postinstall
new file mode 100755
index 0000000..13f5bff
--- /dev/null
+++ b/misc/makerelease/darwin/scripts/postinstall
@@ -0,0 +1,10 @@
+#!/bin/bash
+
+GOROOT=/usr/local/go
+
+echo "Fixing permissions"
+cd $GOROOT
+find . -exec chmod ugo+r \{\} \;
+find bin -exec chmod ugo+rx \{\} \;
+find . -type d -exec chmod ugo+rx \{\} \;
+chmod o-w .
diff --git a/misc/makerelease/darwin/scripts/preinstall b/misc/makerelease/darwin/scripts/preinstall
new file mode 100755
index 0000000..4cdaaa4
--- /dev/null
+++ b/misc/makerelease/darwin/scripts/preinstall
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+GOROOT=/usr/local/go
+
+echo "Removing previous installation"
+if [ -d $GOROOT ]; then
+	rm -r $GOROOT
+fi
diff --git a/misc/makerelease/makerelease.go b/misc/makerelease/makerelease.go
new file mode 100644
index 0000000..3b511b1
--- /dev/null
+++ b/misc/makerelease/makerelease.go
@@ -0,0 +1,1075 @@
+// 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"
+	"errors"
+	"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"
+	storage "code.google.com/p/google-api-go-client/storage/v1"
+)
+
+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       = "golang.org/x/blog"
+	toolPath       = "golang.org/x/tools"
+	tourPath       = "code.google.com/p/go-tour"
+	defaultToolTag = "release-branch.go1.4"
+	defaultTourTag = "release-branch.go1.4"
+)
+
+// 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{
+	"golang.org/x/tools/cmd/cover",
+	"golang.org/x/tools/cmd/godoc",
+	"golang.org/x/tools/cmd/vet",
+}
+
+var preBuildCleanFiles = []string{
+	"lib/codereview",
+	"misc/dashboard/godashboard",
+	"src/cmd/cov",
+	"src/cmd/prof",
+	"src/exp",
+	"src/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)
+		}
+	}
+	ok := true
+	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)
+			ok = false
+		}
+	}
+	if !ok {
+		os.Exit(1)
+	}
+}
+
+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",
+			"-dGoVersion="+version,
+			"-dWixGoVersion="+wixVersion(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
+}
+
+var versionRe = regexp.MustCompile(`^go([0-9]+(\.[0-9]+)*)`)
+
+// The Microsoft installer requires version format major.minor.build
+// (http://msdn.microsoft.com/en-us/library/aa370859%28v=vs.85%29.aspx).
+// Where the major and minor field has a maximum value of 255 and build 65535.
+// The offical Go version format is goMAJOR.MINOR.PATCH at $GOROOT/VERSION.
+// It's based on the Mercurial tag. Remove prefix and suffix to make the
+// installer happy.
+func wixVersion(v string) string {
+	m := versionRe.FindStringSubmatch(v)
+	if m == nil {
+		return "0.0.0"
+	}
+	return m[1]
+}
+
+// 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 {
+	dest := filepath.Join(b.gopath, "src", filepath.FromSlash(repoPath))
+
+	if strings.HasPrefix(repoPath, "golang.org/x/") {
+		// For sub-repos, fetch the old Mercurial repo; bypass "go get".
+		// DO NOT import this special case into the git tree.
+
+		if err := os.MkdirAll(filepath.Dir(dest), 0755); err != nil {
+			return err
+		}
+		repo := strings.Replace(repoPath, "golang.org/x/", "https://code.google.com/p/go.", 1)
+		if _, err := b.run(b.gopath, "hg", "clone", repo, dest); err != nil {
+			return err
+		}
+	} else {
+		// 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.
+	var err error
+	switch {
+	case exists(filepath.Join(dest, ".git")):
+		_, err = b.run(dest, "git", "checkout", revision)
+	case exists(filepath.Join(dest, ".hg")):
+		_, err = b.run(dest, "hg", "update", revision)
+	default:
+		err = errors.New("unknown version control system")
+	}
+	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-NtF3iqIQz",
+		Scope:        storage.DevstorageRead_writeScope,
+		AuthURL:      "https://accounts.google.com/o/oauth2/auth",
+		TokenURL:     "https://accounts.google.com/o/oauth2/token",
+		TokenCache:   oauth.CacheFile(*tokenCache),
+		RedirectURL:  "oob",
+	}
+	transport := &oauth.Transport{Config: config}
+	if token, err := config.TokenCache.Token(); err != nil {
+		url := transport.Config.AuthCodeURL("")
+		fmt.Println("Visit the following URL, obtain an authentication" +
+			"code, and enter it below.")
+		fmt.Println(url)
+		fmt.Print("Enter authentication code: ")
+		code := ""
+		if _, err := fmt.Scan(&code); err != nil {
+			return err
+		}
+		if _, err := transport.Exchange(code); err != nil {
+			return err
+		}
+	} else {
+		transport.Token = token
+	}
+	oauthClient = transport.Client()
+	return nil
+}
+
+func (b *Build) clean(files []string) error {
+	for _, name := range files {
+		err := os.RemoveAll(filepath.Join(b.root, name))
+		if err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+func exists(path string) bool {
+	_, err := os.Stat(path)
+	return err == nil
+}
+
+func readCredentials() error {
+	name := os.Getenv("HOME")
+	if runtime.GOOS == "windows" {
+		name = os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH")
+	}
+	name = filepath.Join(name, ".gobuildkey")
+	f, err := os.Open(name)
+	if err != nil {
+		return err
+	}
+	defer f.Close()
+	s := bufio.NewScanner(f)
+	if s.Scan() {
+		builderKey = s.Text()
+	}
+	return s.Err()
+}
+
+func cp(dst, src string) error {
+	sf, err := os.Open(src)
+	if err != nil {
+		return err
+	}
+	defer sf.Close()
+	fi, err := sf.Stat()
+	if err != nil {
+		return err
+	}
+	df, err := os.Create(dst)
+	if err != nil {
+		return err
+	}
+	defer df.Close()
+	// Windows doesn't currently implement Fchmod
+	if runtime.GOOS != "windows" {
+		if err := df.Chmod(fi.Mode()); err != nil {
+			return err
+		}
+	}
+	_, err = io.Copy(df, sf)
+	return err
+}
+
+func cpDir(dst, src string) error {
+	walk := func(srcPath string, info os.FileInfo, err error) error {
+		if err != nil {
+			return err
+		}
+		dstPath := filepath.Join(dst, srcPath[len(src):])
+		if info.IsDir() {
+			return os.MkdirAll(dstPath, 0755)
+		}
+		return cp(dstPath, srcPath)
+	}
+	return filepath.Walk(src, walk)
+}
+
+func cpAllDir(dst, basePath string, dirs ...string) error {
+	for _, dir := range dirs {
+		if err := cpDir(filepath.Join(dst, dir), filepath.Join(basePath, dir)); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+func makeTar(targ, workdir string) error {
+	f, err := os.Create(targ)
+	if err != nil {
+		return err
+	}
+	zout := gzip.NewWriter(f)
+	tw := tar.NewWriter(zout)
+
+	err = filepath.Walk(workdir, func(path string, fi os.FileInfo, err error) error {
+		if !strings.HasPrefix(path, workdir) {
+			log.Panicf("walked filename %q doesn't begin with workdir %q", path, workdir)
+		}
+		name := path[len(workdir):]
+
+		// Chop of any leading / from filename, leftover from removing workdir.
+		if strings.HasPrefix(name, "/") {
+			name = name[1:]
+		}
+		// Don't include things outside of the go subdirectory (for instance,
+		// the zip file that we're currently writing here.)
+		if !strings.HasPrefix(name, "go/") {
+			return nil
+		}
+		if *verbose {
+			log.Printf("adding to tar: %s", name)
+		}
+		target, _ := os.Readlink(path)
+		hdr, err := tar.FileInfoHeader(fi, target)
+		if err != nil {
+			return err
+		}
+		hdr.Name = name
+		hdr.Uname = "root"
+		hdr.Gname = "root"
+		hdr.Uid = 0
+		hdr.Gid = 0
+
+		// Force permissions to 0755 for executables, 0644 for everything else.
+		if fi.Mode().Perm()&0111 != 0 {
+			hdr.Mode = hdr.Mode&^0777 | 0755
+		} else {
+			hdr.Mode = hdr.Mode&^0777 | 0644
+		}
+
+		err = tw.WriteHeader(hdr)
+		if err != nil {
+			return fmt.Errorf("Error writing file %q: %v", name, err)
+		}
+		if fi.IsDir() {
+			return nil
+		}
+		r, err := os.Open(path)
+		if err != nil {
+			return err
+		}
+		defer r.Close()
+		_, err = io.Copy(tw, r)
+		return err
+	})
+	if err != nil {
+		return err
+	}
+	if err := tw.Close(); err != nil {
+		return err
+	}
+	if err := zout.Close(); err != nil {
+		return err
+	}
+	return f.Close()
+}
+
+func makeZip(targ, workdir string) error {
+	f, err := os.Create(targ)
+	if err != nil {
+		return err
+	}
+	zw := zip.NewWriter(f)
+
+	err = filepath.Walk(workdir, func(path string, fi os.FileInfo, err error) error {
+		if !strings.HasPrefix(path, workdir) {
+			log.Panicf("walked filename %q doesn't begin with workdir %q", path, workdir)
+		}
+		name := path[len(workdir):]
+
+		// Convert to Unix-style named paths, as that's the
+		// type of zip file that archive/zip creates.
+		name = strings.Replace(name, "\\", "/", -1)
+		// Chop of any leading / from filename, leftover from removing workdir.
+		if strings.HasPrefix(name, "/") {
+			name = name[1:]
+		}
+		// Don't include things outside of the go subdirectory (for instance,
+		// the zip file that we're currently writing here.)
+		if !strings.HasPrefix(name, "go/") {
+			return nil
+		}
+		if *verbose {
+			log.Printf("adding to zip: %s", name)
+		}
+		fh, err := zip.FileInfoHeader(fi)
+		if err != nil {
+			return err
+		}
+		fh.Name = name
+		fh.Method = zip.Deflate
+		if fi.IsDir() {
+			fh.Name += "/"        // append trailing slash
+			fh.Method = zip.Store // no need to deflate 0 byte files
+		}
+		w, err := zw.CreateHeader(fh)
+		if err != nil {
+			return err
+		}
+		if fi.IsDir() {
+			return nil
+		}
+		r, err := os.Open(path)
+		if err != nil {
+			return err
+		}
+		defer r.Close()
+		_, err = io.Copy(w, r)
+		return err
+	})
+	if err != nil {
+		return err
+	}
+	if err := zw.Close(); err != nil {
+		return err
+	}
+	return f.Close()
+}
+
+type tool struct {
+	name       string
+	commonDirs []string
+}
+
+var wixTool = tool{
+	"http://wix.sourceforge.net/, version 3.5",
+	[]string{`C:\Program Files\Windows Installer XML v3.5\bin`,
+		`C:\Program Files (x86)\Windows Installer XML v3.5\bin`},
+}
+
+var hgTool = tool{
+	"http://mercurial.selenic.com/wiki/WindowsInstall",
+	[]string{`C:\Program Files\Mercurial`,
+		`C:\Program Files (x86)\Mercurial`,
+	},
+}
+
+var gccTool = tool{
+	"Mingw gcc; http://sourceforge.net/projects/mingw/files/Installer/mingw-get-inst/",
+	[]string{`C:\Mingw\bin`},
+}
+
+var windowsDeps = map[string]tool{
+	"gcc":    gccTool,
+	"heat":   wixTool,
+	"candle": wixTool,
+	"light":  wixTool,
+	"cmd":    {"Windows cmd.exe", nil},
+	"hg":     hgTool,
+}
+
+func checkWindowsDeps() {
+	for prog, help := range windowsDeps {
+		absPath, err := lookPath(prog)
+		if err != nil {
+			log.Fatalf("Failed to find necessary binary %q in path or common locations; %s", prog, help)
+		}
+		if *verbose {
+			log.Printf("found windows dep %s at %s", prog, absPath)
+		}
+	}
+}
+
+func lookPath(prog string) (absPath string, err error) {
+	absPath, err = exec.LookPath(prog)
+	if err == nil {
+		return
+	}
+	t, ok := windowsDeps[prog]
+	if !ok {
+		return
+	}
+	for _, dir := range t.commonDirs {
+		for _, ext := range []string{"exe", "bat"} {
+			absPath = filepath.Join(dir, prog+"."+ext)
+			if _, err1 := os.Stat(absPath); err1 == nil {
+				err = nil
+				os.Setenv("PATH", os.Getenv("PATH")+";"+dir)
+				return
+			}
+		}
+	}
+	return
+}
diff --git a/misc/makerelease/windows/LICENSE.rtf b/misc/makerelease/windows/LICENSE.rtf
new file mode 100644
index 0000000..b2b0be6
Binary files /dev/null and b/misc/makerelease/windows/LICENSE.rtf differ
diff --git a/misc/makerelease/windows/README.txt b/misc/makerelease/windows/README.txt
new file mode 100644
index 0000000..0cf828b
--- /dev/null
+++ b/misc/makerelease/windows/README.txt
@@ -0,0 +1,25 @@
+
+Windows build dependencies
+
+- Mercurial (hg): http://mercurial.selenic.com/
+- MinGW: http://www.mingw.org/
+- Windows Installer XML (WiX) toolset: http://wix.sourceforge.net/
+
+Packaging
+
+The dependencies must be in/added to the system's search PATH. 
+
+Run bindist as normal, eg:
+	bindist windows-386
+
+TODO
+
+- Documentation server shortcut checkbox option
+
+Misc
+
+WiX box sizes:
+ - banner size: 493x58
+ - left side of dialog: 164x312
+ - full dialog size: 493x312
+
diff --git a/misc/makerelease/windows/images/Banner.jpg b/misc/makerelease/windows/images/Banner.jpg
new file mode 100644
index 0000000..ce65f63
Binary files /dev/null and b/misc/makerelease/windows/images/Banner.jpg differ
diff --git a/misc/makerelease/windows/images/Dialog.jpg b/misc/makerelease/windows/images/Dialog.jpg
new file mode 100644
index 0000000..1f0ec0a
Binary files /dev/null and b/misc/makerelease/windows/images/Dialog.jpg differ
diff --git a/misc/makerelease/windows/images/DialogLeft.jpg b/misc/makerelease/windows/images/DialogLeft.jpg
new file mode 100644
index 0000000..73bab89
Binary files /dev/null and b/misc/makerelease/windows/images/DialogLeft.jpg differ
diff --git a/misc/makerelease/windows/images/gopher.ico b/misc/makerelease/windows/images/gopher.ico
new file mode 100644
index 0000000..2e861eb
Binary files /dev/null and b/misc/makerelease/windows/images/gopher.ico differ
diff --git a/misc/makerelease/windows/installer.wxs b/misc/makerelease/windows/installer.wxs
new file mode 100644
index 0000000..01178e2
--- /dev/null
+++ b/misc/makerelease/windows/installer.wxs
@@ -0,0 +1,163 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
+<!--
+# 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.
+-->
+
+<?if $(var.Arch) = 386 ?>
+  <?define ProdId = {FF5B30B2-08C2-11E1-85A2-6ACA4824019B} ?>
+  <?define UpgradeCode = {1C3114EA-08C3-11E1-9095-7FCA4824019B} ?>
+  <?define SysFolder=SystemFolder ?>
+<?else?>
+  <?define ProdId = {716c3eaa-9302-48d2-8e5e-5cfec5da2fab} ?>
+  <?define UpgradeCode = {22ea7650-4ac6-4001-bf29-f4b8775db1c0} ?>
+  <?define SysFolder=System64Folder ?>
+<?endif?>
+
+<Product
+    Id="FF5B30B2-08C2-11E1-85A2-6ACA4824019B"
+    Name="Go Programming Language $(var.Arch) $(var.GoVersion)"
+    Language="1033"
+    Codepage="1252"
+    Version="$(var.WixGoVersion)"
+    Manufacturer="http://golang.org"
+    UpgradeCode="$(var.UpgradeCode)" >
+
+<Package
+    Id='*' 
+    Keywords='Installer'
+    Description="The Go Programming Language Installer"
+    Comments="The Go programming language is an open source project to make programmers more productive."
+    InstallerVersion="300"
+    Compressed="yes"
+    InstallScope="perMachine"
+    SummaryCodepage="1252"
+    Languages="1033" />
+    <!--    Platform="x86 or x64" -->
+
+<Property Id="ARPCOMMENTS" Value="The Go programming language is a fast, statically typed, compiled language that feels like a dynamically typed, interpreted language." />
+<Property Id="ARPCONTACT" Value="golang-nuts at googlegroups.com" />
+<Property Id="ARPHELPLINK" Value="https://golang.org/help/" />
+<Property Id="ARPREADME" Value="https://golang.org" />
+<Property Id="ARPURLINFOABOUT" Value="https://golang.org" />
+<Property Id="LicenseAccepted">1</Property>
+<Icon Id="gopher.ico" SourceFile="images\gopher.ico"/>
+<Property Id="ARPPRODUCTICON" Value="gopher.ico" />
+<Media Id='1' Cabinet="go.cab" EmbedCab="yes" CompressionLevel="high" />
+<Condition Message="Windows 2000 or greater required."> VersionNT >= 500</Condition>
+<MajorUpgrade AllowDowngrades="yes" />
+<SetDirectory Id="INSTALLDIRROOT" Value="[%SYSTEMDRIVE]"/>
+
+<CustomAction
+    Id="SetApplicationRootDirectory"
+    Property="ARPINSTALLLOCATION"
+    Value="[INSTALLDIR]" />
+
+<!-- Define the directory structure and environment variables -->
+<Directory Id="TARGETDIR" Name="SourceDir">
+  <Directory Id="INSTALLDIRROOT">
+    <Directory Id="INSTALLDIR" Name="Go"/>
+  </Directory>
+  <Directory Id="ProgramMenuFolder">
+    <Directory Id="GoProgramShortcutsDir" Name="Go Programming Language"/>
+  </Directory>
+  <Directory Id="EnvironmentEntries">
+    <Directory Id="GoEnvironmentEntries" Name="Go Programming Language"/>
+  </Directory>
+</Directory>
+
+<!-- Programs Menu Shortcuts -->
+<DirectoryRef Id="GoProgramShortcutsDir">
+  <Component Id="Component_GoProgramShortCuts" Guid="{f5fbfb5e-6c5c-423b-9298-21b0e3c98f4b}">
+    <Shortcut
+        Id="GoDocServerStartMenuShortcut"
+        Name="GoDocServer"
+        Description="Starts the Go documentation server (http://localhost:6060)"
+        Show="minimized"
+        Arguments='/c start "Godoc Server http://localhost:6060" "[INSTALLDIR]bin\godoc.exe" -http=localhost:6060 -goroot="[INSTALLDIR]." && start http://localhost:6060'
+        Icon="gopher.ico"
+        Target="[%ComSpec]" />
+    <Shortcut
+        Id="UninstallShortcut"
+        Name="Uninstall Go"
+        Description="Uninstalls Go and all of its components"
+        Target="[$(var.SysFolder)]msiexec.exe"
+        Arguments="/x [ProductCode]" />
+    <RemoveFolder
+        Id="GoProgramShortcutsDir"
+        On="uninstall" />
+    <RegistryValue
+        Root="HKCU"
+        Key="Software\GoProgrammingLanguage"
+        Name="ShortCuts"
+        Type="integer" 
+        Value="1"
+        KeyPath="yes" /> 
+  </Component>
+</DirectoryRef>
+
+<!-- Registry & Environment Settings -->
+<DirectoryRef Id="GoEnvironmentEntries">
+  <Component Id="Component_GoEnvironment" Guid="{3ec7a4d5-eb08-4de7-9312-2df392c45993}">
+    <RegistryKey 
+        Root="HKCU"
+        Key="Software\GoProgrammingLanguage"
+        Action="create" >
+            <RegistryValue
+                Name="installed"
+                Type="integer"
+                Value="1"
+                KeyPath="yes" />
+            <RegistryValue
+                Name="installLocation"
+                Type="string"
+                Value="[INSTALLDIR]" />
+    </RegistryKey>
+    <Environment
+        Id="GoPathEntry"
+        Action="set"
+        Part="last"
+        Name="PATH"
+        Permanent="no"
+        System="yes"
+        Value="[INSTALLDIR]bin" />
+    <Environment
+        Id="GoRoot"
+        Action="set"
+        Part="all"
+        Name="GOROOT"
+        Permanent="no"
+        System="yes"
+        Value="[INSTALLDIR]" />
+    <RemoveFolder
+        Id="GoEnvironmentEntries"
+        On="uninstall" />
+  </Component>
+</DirectoryRef>
+
+<!-- Install the files -->
+<Feature
+    Id="GoTools"
+    Title="Go"
+    Level="1">
+      <ComponentRef Id="Component_GoEnvironment" />
+      <ComponentGroupRef Id="AppFiles" />
+      <ComponentRef Id="Component_GoProgramShortCuts" />
+</Feature>
+
+<!-- Update the environment -->
+<InstallExecuteSequence>
+    <Custom Action="SetApplicationRootDirectory" Before="InstallFinalize" />
+</InstallExecuteSequence>
+
+<!-- Include the user interface -->
+<WixVariable Id="WixUILicenseRtf" Value="LICENSE.rtf" />
+<WixVariable Id="WixUIBannerBmp" Value="images\Banner.jpg" />
+<WixVariable Id="WixUIDialogBmp" Value="images\Dialog.jpg" />
+<Property Id="WIXUI_INSTALLDIR" Value="INSTALLDIR" />
+<UIRef Id="WixUI_InstallDir" />
+
+</Product>
+</Wix>
diff --git a/misc/nacl/README b/misc/nacl/README
index 99b94dc..72d0e08 100644
--- a/misc/nacl/README
+++ b/misc/nacl/README
@@ -8,10 +8,10 @@ Go 1.3 supports three 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.
+   limited to a 4gb window. 
  * nacl/arm which is 32-bit ARMv7A architecture with 1GB address space.
 
-For background it is recommended that you read https://golang.org/s/go13nacl.
+For background it is recommended that you read http://golang.org/s/go13nacl.
 
 Prerequisites
 -------------
@@ -37,20 +37,21 @@ sdk. These are released every 6-8 weeks, in line with Chrome releases.
 	% cd /opt/nacl_sdk
 	% ./naclsdk update
 
-At this time pepper_40 is the stable version. The NaCl port needs at least pepper_39
-to work. If naclsdk downloads a later version, please adjust accordingly.
+At this time pepper_34 is the stable version. If naclsdk downloads a later
+version, please adjust accordingly. As of June 2014, only the canary sdk
+provides support for nacl/arm.
 
 The cmd/go helper scripts expect that the loaders sel_ldr_{x86_{32,64},arm} and
 nacl_helper_bootstrap_arm 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_39/tools/sel_ldr_x86_32 $GOPATH/bin/sel_ldr_x86_32
-	% ln -nfs /opt/nacl_sdk/pepper_39/tools/sel_ldr_x86_64 $GOPATH/bin/sel_ldr_x86_64
-	% ln -nfs /opt/nacl_sdk/pepper_39/tools/sel_ldr_arm $GOPATH/bin/sel_ldr_arm
+	% ln -nfs /opt/nacl_sdk/pepper_34/tools/sel_ldr_x86_32 $GOPATH/bin/sel_ldr_x86_32
+	% ln -nfs /opt/nacl_sdk/pepper_34/tools/sel_ldr_x86_64 $GOPATH/bin/sel_ldr_x86_64
+	% ln -nfs /opt/nacl_sdk/pepper_canary/tools/sel_ldr_arm $GOPATH/bin/sel_ldr_arm
 
 Additionally, for NaCl/ARM only:
 
-	% ln -nfs /opt/nacl_sdk/pepper_39/tools/nacl_helper_bootstrap_arm $GOPATH/bin/nacl_helper_bootstrap_arm
+	% ln -nfs /opt/nacl_sdk/pepper_canary/tools/nacl_helper_bootstrap_arm $GOPATH/bin/nacl_helper_bootstrap_arm 
 
 Support scripts
 ---------------
@@ -109,7 +110,7 @@ Then, run the program as:
 
 The -g flag instructs the loader to stop at startup. Then, in another console:
 
-	% /opt/nacl_sdk/pepper_39/toolchain/linux_x86_glibc/bin/x86_64-nacl-gdb
+	% /opt/nacl_sdk/pepper_34/toolchain/linux_x86_glibc/bin/x86_64-nacl-gdb
 	% nacl-manifest mybin.manifest
 	% target remote :4014
 
@@ -117,5 +118,5 @@ If you see that the program is stopped in _rt0_amd64p32_nacl, then symbols are
 loaded successfully and you can type 'c' to start the program.
 Next time you can automate it as:
 
-	% /opt/nacl_sdk/pepper_39/toolchain/linux_x86_glibc/bin/x86_64-nacl-gdb \
+	% /opt/nacl_sdk/pepper_34/toolchain/linux_x86_glibc/bin/x86_64-nacl-gdb \
 		-ex 'nacl-manifest mybin.manifest' -ex 'target remote :4014'
diff --git a/misc/nacl/testzip.proto b/misc/nacl/testzip.proto
index bc382d5..07d4a1d 100644
--- a/misc/nacl/testzip.proto
+++ b/misc/nacl/testzip.proto
@@ -10,32 +10,9 @@ usr	src=../misc/nacl/testdata
 go	src=..
 	src
 		cmd
-			api
-				testdata
-					+
-			asm
-				internal
-					asm
-						testdata
-							+
-			doc
-				main.go
-				pkg.go
-				doc_test.go
-				testdata
-					+
 			internal
 				objfile
 					objfile.go
-				rsc.io
-					arm
-						armasm
-							testdata
-								+
-					x86
-						x86asm
-							testdata
-								+
 			gofmt
 				gofmt.go
 				gofmt_test.go
diff --git a/misc/swig/callback/callback_test.go b/misc/swig/callback/callback_test.go
index dbbbab5..cf008fb 100644
--- a/misc/swig/callback/callback_test.go
+++ b/misc/swig/callback/callback_test.go
@@ -2,15 +2,16 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package callback
+package callback_test
 
 import (
+	"../callback"
 	"testing"
 )
 
 func TestCall(t *testing.T) {
-	c := NewCaller()
-	cb := NewCallback()
+	c := callback.NewCaller()
+	cb := callback.NewCallback()
 
 	c.SetCallback(cb)
 	s := c.Call()
@@ -21,13 +22,13 @@ func TestCall(t *testing.T) {
 }
 
 func TestCallback(t *testing.T) {
-	c := NewCaller()
-	cb := NewDirectorCallback(&GoCallback{})
+	c := callback.NewCaller()
+	cb := callback.NewDirectorCallback(&callback.GoCallback{})
 	c.SetCallback(cb)
 	s := c.Call()
 	if s != "GoCallback.Run" {
 		t.Errorf("unexpected string from Call with callback: %q", s)
 	}
 	c.DelCallback()
-	DeleteDirectorCallback(cb)
+	callback.DeleteDirectorCallback(cb)
 }
diff --git a/misc/swig/stdio/file_test.go b/misc/swig/stdio/file_test.go
index 38d0746..6478a7c 100644
--- a/misc/swig/stdio/file_test.go
+++ b/misc/swig/stdio/file_test.go
@@ -10,7 +10,7 @@ import "testing"
 // as expected.
 func TestRead(t *testing.T) {
 	f := Fopen("file_test.go", "r")
-	if f.Swigcptr() == 0 {
+	if f == nil {
 		t.Fatal("fopen failed")
 	}
 	if Fgetc(f) != '/' || Fgetc(f) != '/' || Fgetc(f) != ' ' || Fgetc(f) != 'C' {
diff --git a/src/androidtest.bash b/src/androidtest.bash
index 0010738..504d276 100755
--- a/src/androidtest.bash
+++ b/src/androidtest.bash
@@ -11,7 +11,7 @@ set -e
 ulimit -c 0 # no core files
 
 if [ ! -f make.bash ]; then
-	echo 'androidtest.bash must be run from $GOROOT/src' 1>&2
+	echo 'nacl.bash must be run from $GOROOT/src' 1>&2
 	exit 1
 fi
 
@@ -24,53 +24,32 @@ if [ "$GOOS" != "android" ]; then
 fi
 
 export CGO_ENABLED=1
-unset GOBIN
 
-# Do the build first, so we can build go_android_exec and cleaner.
+# Run the build for the host bootstrap, so we can build go_android_exec.
 # Also lets us fail early before the (slow) adb push if the build is broken.
-. ./make.bash --no-banner
+./make.bash
 export GOROOT=$(dirname $(pwd))
 export PATH=$GOROOT/bin:$PATH
 GOOS=$GOHOSTOS GOARCH=$GOHOSTARCH go build \
 	-o ../bin/go_android_${GOARCH}_exec \
 	../misc/android/go_android_exec.go
 
-export ANDROID_TEST_DIR=/tmp/androidtest-$$
-
-function cleanup() {
-	rm -rf ${ANDROID_TEST_DIR}
-}
-trap cleanup EXIT
-
 # Push GOROOT to target device.
 #
 # The adb sync command will sync either the /system or /data
 # directories of an android device from a similar directory
-# on the host. We copy the files required for running tests under
-# /data/local/tmp/goroot. The adb sync command does not follow
-# symlinks so we have to copy.
-export ANDROID_PRODUCT_OUT="${ANDROID_TEST_DIR}/out"
+# on the host. So we fake one with symlinks to push the GOROOT
+# into a subdirectory of /data.
+export ANDROID_PRODUCT_OUT=/tmp/androidtest-$$
 FAKE_GOROOT=$ANDROID_PRODUCT_OUT/data/local/tmp/goroot
 mkdir -p $FAKE_GOROOT
-mkdir -p $FAKE_GOROOT/pkg
-cp -a "${GOROOT}/src" "${FAKE_GOROOT}/"
-cp -a "${GOROOT}/test" "${FAKE_GOROOT}/"
-cp -a "${GOROOT}/lib" "${FAKE_GOROOT}/"
-cp -a "${GOROOT}/pkg/android_$GOARCH" "${FAKE_GOROOT}/pkg/"
+ln -s $GOROOT/src $FAKE_GOROOT/src
+ln -s $GOROOT/test $FAKE_GOROOT/test
+ln -s $GOROOT/lib $FAKE_GOROOT/lib
 echo '# Syncing test files to android device'
-adb shell mkdir -p /data/local/tmp/goroot
 time adb sync data &> /dev/null
-
-export CLEANER=${ANDROID_TEST_DIR}/androidcleaner-$$
-cp ../misc/android/cleaner.go $CLEANER.go
-echo 'var files = `' >> $CLEANER.go
-(cd $ANDROID_PRODUCT_OUT/data/local/tmp/goroot; find . >> $CLEANER.go)
-echo '`' >> $CLEANER.go
-go build -o $CLEANER $CLEANER.go
-adb push $CLEANER /data/local/tmp/cleaner
-adb shell /data/local/tmp/cleaner
-
 echo ''
+rm -rf "$ANDROID_PRODUCT_OUT"
 
-# Run standard tests.
-bash run.bash --no-rebuild
+# Run standard build and tests.
+./all.bash --no-clean
diff --git a/src/archive/tar/common.go b/src/archive/tar/common.go
index c31df06..e363aa7 100644
--- a/src/archive/tar/common.go
+++ b/src/archive/tar/common.go
@@ -139,8 +139,8 @@ func (fi headerFileInfo) Mode() (mode os.FileMode) {
 	}
 
 	switch fi.h.Typeflag {
-	case TypeSymlink:
-		// symbolic link
+	case TypeLink, TypeSymlink:
+		// hard link, symbolic link
 		mode |= os.ModeSymlink
 	case TypeChar:
 		// character device node
@@ -249,30 +249,6 @@ func FileInfoHeader(fi os.FileInfo, link string) (*Header, error) {
 	if fm&os.ModeSticky != 0 {
 		h.Mode |= c_ISVTX
 	}
-	// If possible, populate additional fields from OS-specific
-	// FileInfo fields.
-	if sys, ok := fi.Sys().(*Header); ok {
-		// This FileInfo came from a Header (not the OS). Use the
-		// original Header to populate all remaining fields.
-		h.Uid = sys.Uid
-		h.Gid = sys.Gid
-		h.Uname = sys.Uname
-		h.Gname = sys.Gname
-		h.AccessTime = sys.AccessTime
-		h.ChangeTime = sys.ChangeTime
-		if sys.Xattrs != nil {
-			h.Xattrs = make(map[string]string)
-			for k, v := range sys.Xattrs {
-				h.Xattrs[k] = v
-			}
-		}
-		if sys.Typeflag == TypeLink {
-			// hard link
-			h.Typeflag = TypeLink
-			h.Size = 0
-			h.Linkname = sys.Linkname
-		}
-	}
 	if sysStat != nil {
 		return h, sysStat(fi, h)
 	}
diff --git a/src/archive/tar/example_test.go b/src/archive/tar/example_test.go
index 2317f44..351eaa0 100644
--- a/src/archive/tar/example_test.go
+++ b/src/archive/tar/example_test.go
@@ -31,7 +31,6 @@ func Example() {
 	for _, file := range files {
 		hdr := &tar.Header{
 			Name: file.Name,
-			Mode: 0600,
 			Size: int64(len(file.Body)),
 		}
 		if err := tw.WriteHeader(hdr); err != nil {
diff --git a/src/archive/tar/reader.go b/src/archive/tar/reader.go
index 67daca2..a27559d 100644
--- a/src/archive/tar/reader.go
+++ b/src/archive/tar/reader.go
@@ -85,8 +85,6 @@ const (
 func NewReader(r io.Reader) *Reader { return &Reader{r: r} }
 
 // Next advances to the next entry in the tar archive.
-//
-// io.EOF is returned at the end of the input.
 func (tr *Reader) Next() (*Header, error) {
 	var hdr *Header
 	if tr.err == nil {
@@ -110,13 +108,7 @@ func (tr *Reader) Next() (*Header, error) {
 		// We actually read the whole file,
 		// but this skips alignment padding
 		tr.skipUnread()
-		if tr.err != nil {
-			return nil, tr.err
-		}
 		hdr = tr.readHeader()
-		if hdr == nil {
-			return nil, tr.err
-		}
 		mergePAX(hdr, headers)
 
 		// Check for a PAX format sparse file
@@ -339,7 +331,7 @@ func parsePAX(r io.Reader) (map[string]string, error) {
 		}
 		// Parse the first token as a decimal integer.
 		n, err := strconv.ParseInt(string(buf[:sp]), 10, 0)
-		if err != nil || n < 5 || int64(len(buf)) < n {
+		if err != nil {
 			return nil, ErrHeader
 		}
 		// Extract everything between the decimal and the n -1 on the
@@ -469,10 +461,6 @@ func (tr *Reader) readHeader() *Header {
 	hdr.Uid = int(tr.octal(s.next(8)))
 	hdr.Gid = int(tr.octal(s.next(8)))
 	hdr.Size = tr.octal(s.next(12))
-	if hdr.Size < 0 {
-		tr.err = ErrHeader
-		return nil
-	}
 	hdr.ModTime = time.Unix(tr.octal(s.next(12)), 0)
 	s.next(8) // chksum
 	hdr.Typeflag = s.next(1)[0]
@@ -797,9 +785,6 @@ func (sfr *sparseFileReader) Read(b []byte) (n int, err error) {
 		// Otherwise, we're at the end of the file
 		return 0, io.EOF
 	}
-	if sfr.tot < sfr.sp[0].offset {
-		return 0, io.ErrUnexpectedEOF
-	}
 	if sfr.pos < sfr.sp[0].offset {
 		// We're in a hole
 		n = sfr.readHole(b, sfr.sp[0].offset)
diff --git a/src/archive/tar/reader_test.go b/src/archive/tar/reader_test.go
index da01f26..9601ffe 100644
--- a/src/archive/tar/reader_test.go
+++ b/src/archive/tar/reader_test.go
@@ -462,14 +462,9 @@ func TestParsePAXHeader(t *testing.T) {
 			t.Error("Buffer wasn't consumed")
 		}
 	}
-	badHeaderTests := [][]byte{
-		[]byte("3 somelongkey=\n"),
-		[]byte("50 tooshort=\n"),
-	}
-	for _, test := range badHeaderTests {
-		if _, err := parsePAX(bytes.NewReader(test)); err != ErrHeader {
-			t.Fatal("Unexpected success when parsing bad header")
-		}
+	badHeader := bytes.NewReader([]byte("3 somelongkey="))
+	if _, err := parsePAX(badHeader); err != ErrHeader {
+		t.Fatal("Unexpected success when parsing bad header")
 	}
 }
 
@@ -746,53 +741,3 @@ func TestUninitializedRead(t *testing.T) {
 	}
 
 }
-
-// Negative header size should not cause panic.
-// Issues 10959 and 10960.
-func TestNegativeHdrSize(t *testing.T) {
-	f, err := os.Open("testdata/neg-size.tar")
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer f.Close()
-	r := NewReader(f)
-	_, err = r.Next()
-	if err != ErrHeader {
-		t.Error("want ErrHeader, got", err)
-	}
-	io.Copy(ioutil.Discard, r)
-}
-
-// This used to hang in (*sparseFileReader).readHole due to missing
-// verification of sparse offsets against file size.
-func TestIssue10968(t *testing.T) {
-	f, err := os.Open("testdata/issue10968.tar")
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer f.Close()
-	r := NewReader(f)
-	_, err = r.Next()
-	if err != nil {
-		t.Fatal(err)
-	}
-	_, err = io.Copy(ioutil.Discard, r)
-	if err != io.ErrUnexpectedEOF {
-		t.Fatalf("expected %q, got %q", io.ErrUnexpectedEOF, err)
-	}
-}
-
-// Do not panic if there are errors in header blocks after the pax header.
-// Issue 11169
-func TestIssue11169(t *testing.T) {
-	f, err := os.Open("testdata/issue11169.tar")
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer f.Close()
-	r := NewReader(f)
-	_, err = r.Next()
-	if err == nil {
-		t.Fatal("Unexpected success")
-	}
-}
diff --git a/src/archive/tar/tar_test.go b/src/archive/tar/tar_test.go
index d63c072..ed333f3 100644
--- a/src/archive/tar/tar_test.go
+++ b/src/archive/tar/tar_test.go
@@ -147,6 +147,17 @@ func TestHeaderRoundTrip(t *testing.T) {
 			},
 			fm: 0644,
 		},
+		// hard link.
+		{
+			h: &Header{
+				Name:     "hard.txt",
+				Mode:     0644 | c_ISLNK,
+				Size:     0,
+				ModTime:  time.Unix(1360600916, 0),
+				Typeflag: TypeLink,
+			},
+			fm: 0644 | os.ModeSymlink,
+		},
 		// symbolic link.
 		{
 			h: &Header{
@@ -235,33 +246,6 @@ func TestHeaderRoundTrip(t *testing.T) {
 			},
 			fm: 0600 | os.ModeSticky,
 		},
-		// hard link.
-		{
-			h: &Header{
-				Name:     "hard.txt",
-				Mode:     0644 | c_ISREG,
-				Size:     0,
-				Linkname: "file.txt",
-				ModTime:  time.Unix(1360600916, 0),
-				Typeflag: TypeLink,
-			},
-			fm: 0644,
-		},
-		// More information.
-		{
-			h: &Header{
-				Name:     "info.txt",
-				Mode:     0600 | c_ISREG,
-				Size:     0,
-				Uid:      1000,
-				Gid:      1000,
-				ModTime:  time.Unix(1360602540, 0),
-				Uname:    "slartibartfast",
-				Gname:    "users",
-				Typeflag: TypeReg,
-			},
-			fm: 0600,
-		},
 	}
 
 	for i, g := range golden {
@@ -284,37 +268,12 @@ func TestHeaderRoundTrip(t *testing.T) {
 		if got, want := h2.Size, g.h.Size; got != want {
 			t.Errorf("i=%d: Size: got %v, want %v", i, got, want)
 		}
-		if got, want := h2.Uid, g.h.Uid; got != want {
-			t.Errorf("i=%d: Uid: got %d, want %d", i, got, want)
-		}
-		if got, want := h2.Gid, g.h.Gid; got != want {
-			t.Errorf("i=%d: Gid: got %d, want %d", i, got, want)
-		}
-		if got, want := h2.Uname, g.h.Uname; got != want {
-			t.Errorf("i=%d: Uname: got %q, want %q", i, got, want)
-		}
-		if got, want := h2.Gname, g.h.Gname; got != want {
-			t.Errorf("i=%d: Gname: got %q, want %q", i, got, want)
-		}
-		if got, want := h2.Linkname, g.h.Linkname; got != want {
-			t.Errorf("i=%d: Linkname: got %v, want %v", i, got, want)
-		}
-		if got, want := h2.Typeflag, g.h.Typeflag; got != want {
-			t.Logf("%#v %#v", g.h, fi.Sys())
-			t.Errorf("i=%d: Typeflag: got %q, want %q", i, got, want)
-		}
 		if got, want := h2.Mode, g.h.Mode; got != want {
 			t.Errorf("i=%d: Mode: got %o, want %o", i, got, want)
 		}
 		if got, want := fi.Mode(), g.fm; got != want {
 			t.Errorf("i=%d: fi.Mode: got %o, want %o", i, got, want)
 		}
-		if got, want := h2.AccessTime, g.h.AccessTime; got != want {
-			t.Errorf("i=%d: AccessTime: got %v, want %v", i, got, want)
-		}
-		if got, want := h2.ChangeTime, g.h.ChangeTime; got != want {
-			t.Errorf("i=%d: ChangeTime: got %v, want %v", i, got, want)
-		}
 		if got, want := h2.ModTime, g.h.ModTime; got != want {
 			t.Errorf("i=%d: ModTime: got %v, want %v", i, got, want)
 		}
diff --git a/src/archive/tar/writer.go b/src/archive/tar/writer.go
index 9dbc01a..dafb2ca 100644
--- a/src/archive/tar/writer.go
+++ b/src/archive/tar/writer.go
@@ -355,7 +355,7 @@ func paxHeader(msg string) string {
 // hdr.Size bytes are written after WriteHeader.
 func (tw *Writer) Write(b []byte) (n int, err error) {
 	if tw.closed {
-		err = ErrWriteAfterClose
+		err = ErrWriteTooLong
 		return
 	}
 	overwrite := false
diff --git a/src/archive/tar/writer_test.go b/src/archive/tar/writer_test.go
index fe46a67..5e42e32 100644
--- a/src/archive/tar/writer_test.go
+++ b/src/archive/tar/writer_test.go
@@ -147,44 +147,6 @@ var writerTests = []*writerTest{
 			},
 		},
 	},
-	// This file was produced using gnu tar 1.26
-	// echo "Slartibartfast" > file.txt
-	// ln file.txt hard.txt
-	// tar -b 1 --format=ustar -c -f hardlink.tar file.txt hard.txt
-	{
-		file: "testdata/hardlink.tar",
-		entries: []*writerTestEntry{
-			{
-				header: &Header{
-					Name:     "file.txt",
-					Mode:     0644,
-					Uid:      1000,
-					Gid:      100,
-					Size:     15,
-					ModTime:  time.Unix(1425484303, 0),
-					Typeflag: '0',
-					Uname:    "vbatts",
-					Gname:    "users",
-				},
-				contents: "Slartibartfast\n",
-			},
-			{
-				header: &Header{
-					Name:     "hard.txt",
-					Mode:     0644,
-					Uid:      1000,
-					Gid:      100,
-					Size:     0,
-					ModTime:  time.Unix(1425484303, 0),
-					Typeflag: '1',
-					Linkname: "file.txt",
-					Uname:    "vbatts",
-					Gname:    "users",
-				},
-				// no contents
-			},
-		},
-	},
 }
 
 // Render byte array in a two-character hexadecimal string, spaced for easy visual inspection.
@@ -527,20 +489,3 @@ func TestValidTypeflagWithPAXHeader(t *testing.T) {
 		}
 	}
 }
-
-func TestWriteAfterClose(t *testing.T) {
-	var buffer bytes.Buffer
-	tw := NewWriter(&buffer)
-
-	hdr := &Header{
-		Name: "small.txt",
-		Size: 5,
-	}
-	if err := tw.WriteHeader(hdr); err != nil {
-		t.Fatalf("Failed to write header: %s", err)
-	}
-	tw.Close()
-	if _, err := tw.Write([]byte("Kilts")); err != ErrWriteAfterClose {
-		t.Fatalf("Write: got %v; want ErrWriteAfterClose", err)
-	}
-}
diff --git a/src/archive/zip/reader.go b/src/archive/zip/reader.go
index 519748b..8136b84 100644
--- a/src/archive/zip/reader.go
+++ b/src/archive/zip/reader.go
@@ -8,7 +8,6 @@ import (
 	"bufio"
 	"encoding/binary"
 	"errors"
-	"fmt"
 	"hash"
 	"hash/crc32"
 	"io"
@@ -78,9 +77,6 @@ func (z *Reader) init(r io.ReaderAt, size int64) error {
 	if err != nil {
 		return err
 	}
-	if end.directoryRecords > uint64(size)/fileHeaderLen {
-		return fmt.Errorf("archive/zip: TOC declares impossible %d files in %d byte zip", end.directoryRecords, size)
-	}
 	z.r = r
 	z.File = make([]*File, 0, end.directoryRecords)
 	z.Comment = end.comment
@@ -150,22 +146,16 @@ func (f *File) Open() (rc io.ReadCloser, err error) {
 	if f.hasDataDescriptor() {
 		desr = io.NewSectionReader(f.zipr, f.headerOffset+bodyOffset+size, dataDescriptorLen)
 	}
-	rc = &checksumReader{
-		rc:   rc,
-		hash: crc32.NewIEEE(),
-		f:    f,
-		desr: desr,
-	}
+	rc = &checksumReader{rc, crc32.NewIEEE(), f, desr, nil}
 	return
 }
 
 type checksumReader struct {
-	rc    io.ReadCloser
-	hash  hash.Hash32
-	nread uint64 // number of bytes read so far
-	f     *File
-	desr  io.Reader // if non-nil, where to read the data descriptor
-	err   error     // sticky error
+	rc   io.ReadCloser
+	hash hash.Hash32
+	f    *File
+	desr io.Reader // if non-nil, where to read the data descriptor
+	err  error     // sticky error
 }
 
 func (r *checksumReader) Read(b []byte) (n int, err error) {
@@ -174,21 +164,13 @@ func (r *checksumReader) Read(b []byte) (n int, err error) {
 	}
 	n, err = r.rc.Read(b)
 	r.hash.Write(b[:n])
-	r.nread += uint64(n)
 	if err == nil {
 		return
 	}
 	if err == io.EOF {
-		if r.nread != r.f.UncompressedSize64 {
-			return 0, io.ErrUnexpectedEOF
-		}
 		if r.desr != nil {
 			if err1 := readDataDescriptor(r.desr, r.f); err1 != nil {
-				if err1 == io.EOF {
-					err = io.ErrUnexpectedEOF
-				} else {
-					err = err1
-				}
+				err = err1
 			} else if r.hash.Sum32() != r.f.CRC32 {
 				err = ErrChecksum
 			}
diff --git a/src/archive/zip/reader_test.go b/src/archive/zip/reader_test.go
index 547dd39..29d0652 100644
--- a/src/archive/zip/reader_test.go
+++ b/src/archive/zip/reader_test.go
@@ -531,77 +531,3 @@ func TestIssue8186(t *testing.T) {
 		}
 	}
 }
-
-// Verify we return ErrUnexpectedEOF when length is short.
-func TestIssue10957(t *testing.T) {
-	data := []byte("PK\x03\x040000000PK\x01\x0200000" +
-		"0000000000000000000\x00" +
-		"\x00\x00\x00\x00\x00000000000000PK\x01" +
-		"\x020000000000000000000" +
-		"00000\v\x00\x00\x00\x00\x00000000000" +
-		"00000000000000PK\x01\x0200" +
-		"00000000000000000000" +
-		"00\v\x00\x00\x00\x00\x00000000000000" +
-		"00000000000PK\x01\x020000<" +
-		"0\x00\x0000000000000000\v\x00\v" +
-		"\x00\x00\x00\x00\x0000000000\x00\x00\x00\x00000" +
-		"00000000PK\x01\x0200000000" +
-		"0000000000000000\v\x00\x00\x00" +
-		"\x00\x0000PK\x05\x06000000\x05\x000000" +
-		"\v\x00\x00\x00\x00\x00")
-	z, err := NewReader(bytes.NewReader(data), int64(len(data)))
-	if err != nil {
-		t.Fatal(err)
-	}
-	for i, f := range z.File {
-		r, err := f.Open()
-		if err != nil {
-			continue
-		}
-		if f.UncompressedSize64 < 1e6 {
-			n, err := io.Copy(ioutil.Discard, r)
-			if i == 3 && err != io.ErrUnexpectedEOF {
-				t.Errorf("File[3] error = %v; want io.ErrUnexpectedEOF", err)
-			}
-			if err == nil && uint64(n) != f.UncompressedSize64 {
-				t.Errorf("file %d: bad size: copied=%d; want=%d", i, n, f.UncompressedSize64)
-			}
-		}
-		r.Close()
-	}
-}
-
-// Verify the number of files is sane.
-func TestIssue10956(t *testing.T) {
-	data := []byte("PK\x06\x06PK\x06\a0000\x00\x00\x00\x00\x00\x00\x00\x00" +
-		"0000PK\x05\x06000000000000" +
-		"0000\v\x00000\x00\x00\x00\x00\x00\x00\x000")
-	_, err := NewReader(bytes.NewReader(data), int64(len(data)))
-	const want = "TOC declares impossible 3472328296227680304 files in 57 byte"
-	if err == nil && !strings.Contains(err.Error(), want) {
-		t.Errorf("error = %v; want %q", err, want)
-	}
-}
-
-// Verify we return ErrUnexpectedEOF when reading truncated data descriptor.
-func TestIssue11146(t *testing.T) {
-	data := []byte("PK\x03\x040000000000000000" +
-		"000000\x01\x00\x00\x000\x01\x00\x00\xff\xff0000" +
-		"0000000000000000PK\x01\x02" +
-		"0000\b0\b\x00000000000000" +
-		"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x000000PK\x05\x06\x00\x00" +
-		"\x00\x0000\x01\x0000008\x00\x00\x00\x00\x00")
-	z, err := NewReader(bytes.NewReader(data), int64(len(data)))
-	if err != nil {
-		t.Fatal(err)
-	}
-	r, err := z.File[0].Open()
-	if err != nil {
-		t.Fatal(err)
-	}
-	_, err = ioutil.ReadAll(r)
-	if err != io.ErrUnexpectedEOF {
-		t.Errorf("File[0] error = %v; want io.ErrUnexpectedEOF", err)
-	}
-	r.Close()
-}
diff --git a/src/archive/zip/struct.go b/src/archive/zip/struct.go
index 137d049..cb28e83 100644
--- a/src/archive/zip/struct.go
+++ b/src/archive/zip/struct.go
@@ -81,8 +81,8 @@ type FileHeader struct {
 	ModifiedTime       uint16 // MS-DOS time
 	ModifiedDate       uint16 // MS-DOS date
 	CRC32              uint32
-	CompressedSize     uint32 // Deprecated: Use CompressedSize64 instead.
-	UncompressedSize   uint32 // Deprecated: Use UncompressedSize64 instead.
+	CompressedSize     uint32 // deprecated; use CompressedSize64
+	UncompressedSize   uint32 // deprecated; use UncompressedSize64
 	CompressedSize64   uint64
 	UncompressedSize64 uint64
 	Extra              []byte
@@ -233,7 +233,7 @@ func (h *FileHeader) SetMode(mode os.FileMode) {
 	}
 }
 
-// isZip64 reports whether the file size exceeds the 32 bit limit
+// isZip64 returns true if the file size exceeds the 32 bit limit
 func (fh *FileHeader) isZip64() bool {
 	return fh.CompressedSize64 > uint32max || fh.UncompressedSize64 > uint32max
 }
diff --git a/src/archive/zip/testdata/readme.notzip b/src/archive/zip/testdata/readme.notzip
index 8173727..06668c4 100644
Binary files a/src/archive/zip/testdata/readme.notzip and b/src/archive/zip/testdata/readme.notzip differ
diff --git a/src/archive/zip/testdata/readme.zip b/src/archive/zip/testdata/readme.zip
index 5642a67..db3bb90 100644
Binary files a/src/archive/zip/testdata/readme.zip and b/src/archive/zip/testdata/readme.zip differ
diff --git a/src/archive/zip/writer.go b/src/archive/zip/writer.go
index 3be2b5f..170beec 100644
--- a/src/archive/zip/writer.go
+++ b/src/archive/zip/writer.go
@@ -34,17 +34,6 @@ func NewWriter(w io.Writer) *Writer {
 	return &Writer{cw: &countWriter{w: bufio.NewWriter(w)}}
 }
 
-// SetOffset sets the offset of the beginning of the zip data within the
-// underlying writer. It should be used when the zip data is appended to an
-// existing file, such as a binary executable.
-// It must be called before any data is written.
-func (w *Writer) SetOffset(n int64) {
-	if w.cw.count != 0 {
-		panic("zip: SetOffset called after data was written")
-	}
-	w.cw.count = n
-}
-
 // Flush flushes any buffered data to the underlying writer.
 // Calling Flush is not normally necessary; calling Close is sufficient.
 func (w *Writer) Flush() error {
@@ -133,15 +122,15 @@ func (w *Writer) Close() error {
 
 		// zip64 end of central directory record
 		b.uint32(directory64EndSignature)
-		b.uint64(directory64EndLen - 12) // length minus signature (uint32) and length fields (uint64)
-		b.uint16(zipVersion45)           // version made by
-		b.uint16(zipVersion45)           // version needed to extract
-		b.uint32(0)                      // number of this disk
-		b.uint32(0)                      // number of the disk with the start of the central directory
-		b.uint64(records)                // total number of entries in the central directory on this disk
-		b.uint64(records)                // total number of entries in the central directory
-		b.uint64(size)                   // size of the central directory
-		b.uint64(offset)                 // offset of start of central directory with respect to the starting disk number
+		b.uint64(directory64EndLen)
+		b.uint16(zipVersion45) // version made by
+		b.uint16(zipVersion45) // version needed to extract
+		b.uint32(0)            // number of this disk
+		b.uint32(0)            // number of the disk with the start of the central directory
+		b.uint64(records)      // total number of entries in the central directory on this disk
+		b.uint64(records)      // total number of entries in the central directory
+		b.uint64(size)         // size of the central directory
+		b.uint64(offset)       // offset of start of central directory with respect to the starting disk number
 
 		// zip64 end of central directory locator
 		b.uint32(directory64LocSignature)
@@ -195,20 +184,14 @@ func (w *Writer) Create(name string) (io.Writer, error) {
 // CreateHeader adds a file to the zip file using the provided FileHeader
 // for the file metadata.
 // It returns a Writer to which the file contents should be written.
-//
 // The file's contents must be written to the io.Writer before the next
-// call to Create, CreateHeader, or Close. The provided FileHeader fh
-// must not be modified after a call to CreateHeader.
+// call to Create, CreateHeader, or Close.
 func (w *Writer) CreateHeader(fh *FileHeader) (io.Writer, error) {
 	if w.last != nil && !w.last.closed {
 		if err := w.last.close(); err != nil {
 			return nil, err
 		}
 	}
-	if len(w.dir) > 0 && w.dir[len(w.dir)-1].FileHeader == fh {
-		// See https://golang.org/issue/11144 confusion.
-		return nil, errors.New("archive/zip: invalid duplicate FileHeader")
-	}
 
 	fh.Flags |= 0x8 // we will write a data descriptor
 
diff --git a/src/archive/zip/writer_test.go b/src/archive/zip/writer_test.go
index 01b63f2..184a7d9 100644
--- a/src/archive/zip/writer_test.go
+++ b/src/archive/zip/writer_test.go
@@ -87,41 +87,6 @@ func TestWriter(t *testing.T) {
 	}
 }
 
-func TestWriterOffset(t *testing.T) {
-	largeData := make([]byte, 1<<17)
-	for i := range largeData {
-		largeData[i] = byte(rand.Int())
-	}
-	writeTests[1].Data = largeData
-	defer func() {
-		writeTests[1].Data = nil
-	}()
-
-	// write a zip file
-	buf := new(bytes.Buffer)
-	existingData := []byte{1, 2, 3, 1, 2, 3, 1, 2, 3}
-	n, _ := buf.Write(existingData)
-	w := NewWriter(buf)
-	w.SetOffset(int64(n))
-
-	for _, wt := range writeTests {
-		testCreate(t, w, &wt)
-	}
-
-	if err := w.Close(); err != nil {
-		t.Fatal(err)
-	}
-
-	// read it back
-	r, err := NewReader(bytes.NewReader(buf.Bytes()), int64(buf.Len()))
-	if err != nil {
-		t.Fatal(err)
-	}
-	for i, wt := range writeTests {
-		testReadFile(t, r.File[i], &wt)
-	}
-}
-
 func TestWriterFlush(t *testing.T) {
 	var buf bytes.Buffer
 	w := NewWriter(struct{ io.Writer }{&buf})
diff --git a/src/archive/zip/zip_test.go b/src/archive/zip/zip_test.go
index f00ff47..32a16a7 100644
--- a/src/archive/zip/zip_test.go
+++ b/src/archive/zip/zip_test.go
@@ -229,11 +229,10 @@ func TestZip64(t *testing.T) {
 		t.Skip("slow test; skipping")
 	}
 	const size = 1 << 32 // before the "END\n" part
-	buf := testZip64(t, size)
-	testZip64DirectoryRecordLength(buf, t)
+	testZip64(t, size)
 }
 
-func testZip64(t testing.TB, size int64) *rleBuffer {
+func testZip64(t testing.TB, size int64) {
 	const chunkSize = 1024
 	chunks := int(size / chunkSize)
 	// write 2^32 bytes plus "END\n" to a zip file
@@ -303,37 +302,6 @@ func testZip64(t testing.TB, size int64) *rleBuffer {
 	if got, want := f0.UncompressedSize64, uint64(size)+uint64(len(end)); got != want {
 		t.Errorf("UncompressedSize64 %d, want %d", got, want)
 	}
-
-	return buf
-}
-
-// Issue 9857
-func testZip64DirectoryRecordLength(buf *rleBuffer, t *testing.T) {
-	d := make([]byte, 1024)
-	if _, err := buf.ReadAt(d, buf.Size()-int64(len(d))); err != nil {
-		t.Fatal("read:", err)
-	}
-
-	sigOff := findSignatureInBlock(d)
-	dirOff, err := findDirectory64End(buf, buf.Size()-int64(len(d))+int64(sigOff))
-	if err != nil {
-		t.Fatal("findDirectory64End:", err)
-	}
-
-	d = make([]byte, directory64EndLen)
-	if _, err := buf.ReadAt(d, dirOff); err != nil {
-		t.Fatal("read:", err)
-	}
-
-	b := readBuf(d)
-	if sig := b.uint32(); sig != directory64EndSignature {
-		t.Fatalf("Expected directory64EndSignature (%d), got %d", directory64EndSignature, sig)
-	}
-
-	size := b.uint64()
-	if size != directory64EndLen-12 {
-		t.Fatalf("Expected length of %d, got %d", directory64EndLen-12, size)
-	}
 }
 
 func testInvalidHeader(h *FileHeader, t *testing.T) {
diff --git a/src/bufio/bufio.go b/src/bufio/bufio.go
index 3bbb933..d3c68fe 100644
--- a/src/bufio/bufio.go
+++ b/src/bufio/bufio.go
@@ -144,39 +144,6 @@ func (b *Reader) Peek(n int) ([]byte, error) {
 	return b.buf[b.r : b.r+n], err
 }
 
-// Discard skips the next n bytes, returning the number of bytes discarded.
-//
-// If Discard skips fewer than n bytes, it also returns an error.
-// If 0 <= n <= b.Buffered(), Discard is guaranteed to succeed without
-// reading from the underlying io.Reader.
-func (b *Reader) Discard(n int) (discarded int, err error) {
-	if n < 0 {
-		return 0, ErrNegativeCount
-	}
-	if n == 0 {
-		return
-	}
-	remain := n
-	for {
-		skip := b.Buffered()
-		if skip == 0 {
-			b.fill()
-			skip = b.Buffered()
-		}
-		if skip > remain {
-			skip = remain
-		}
-		b.r += skip
-		remain -= skip
-		if remain == 0 {
-			return n, nil
-		}
-		if b.err != nil {
-			return n - remain, b.readErr()
-		}
-	}
-}
-
 // Read reads data into p.
 // It returns the number of bytes read into p.
 // It calls Read at most once on the underlying Reader,
@@ -400,6 +367,7 @@ func (b *Reader) ReadBytes(delim byte) (line []byte, err error) {
 	// accumulating full buffers.
 	var frag []byte
 	var full [][]byte
+	err = nil
 
 	for {
 		var e error
diff --git a/src/bufio/bufio_test.go b/src/bufio/bufio_test.go
index 666c44e..550dac9 100644
--- a/src/bufio/bufio_test.go
+++ b/src/bufio/bufio_test.go
@@ -1268,135 +1268,6 @@ func TestWriterReset(t *testing.T) {
 	}
 }
 
-func TestReaderDiscard(t *testing.T) {
-	tests := []struct {
-		name     string
-		r        io.Reader
-		bufSize  int // 0 means 16
-		peekSize int
-
-		n int // input to Discard
-
-		want    int   // from Discard
-		wantErr error // from Discard
-
-		wantBuffered int
-	}{
-		{
-			name:         "normal case",
-			r:            strings.NewReader("abcdefghijklmnopqrstuvwxyz"),
-			peekSize:     16,
-			n:            6,
-			want:         6,
-			wantBuffered: 10,
-		},
-		{
-			name:         "discard causing read",
-			r:            strings.NewReader("abcdefghijklmnopqrstuvwxyz"),
-			n:            6,
-			want:         6,
-			wantBuffered: 10,
-		},
-		{
-			name:         "discard all without peek",
-			r:            strings.NewReader("abcdefghijklmnopqrstuvwxyz"),
-			n:            26,
-			want:         26,
-			wantBuffered: 0,
-		},
-		{
-			name:         "discard more than end",
-			r:            strings.NewReader("abcdefghijklmnopqrstuvwxyz"),
-			n:            27,
-			want:         26,
-			wantErr:      io.EOF,
-			wantBuffered: 0,
-		},
-		// Any error from filling shouldn't show up until we
-		// get past the valid bytes. Here we return we return 5 valid bytes at the same time
-		// as an error, but test that we don't see the error from Discard.
-		{
-			name: "fill error, discard less",
-			r: newScriptedReader(func(p []byte) (n int, err error) {
-				if len(p) < 5 {
-					panic("unexpected small read")
-				}
-				return 5, errors.New("5-then-error")
-			}),
-			n:            4,
-			want:         4,
-			wantErr:      nil,
-			wantBuffered: 1,
-		},
-		{
-			name: "fill error, discard equal",
-			r: newScriptedReader(func(p []byte) (n int, err error) {
-				if len(p) < 5 {
-					panic("unexpected small read")
-				}
-				return 5, errors.New("5-then-error")
-			}),
-			n:            5,
-			want:         5,
-			wantErr:      nil,
-			wantBuffered: 0,
-		},
-		{
-			name: "fill error, discard more",
-			r: newScriptedReader(func(p []byte) (n int, err error) {
-				if len(p) < 5 {
-					panic("unexpected small read")
-				}
-				return 5, errors.New("5-then-error")
-			}),
-			n:            6,
-			want:         5,
-			wantErr:      errors.New("5-then-error"),
-			wantBuffered: 0,
-		},
-		// Discard of 0 shouldn't cause a read:
-		{
-			name:         "discard zero",
-			r:            newScriptedReader(), // will panic on Read
-			n:            0,
-			want:         0,
-			wantErr:      nil,
-			wantBuffered: 0,
-		},
-		{
-			name:         "discard negative",
-			r:            newScriptedReader(), // will panic on Read
-			n:            -1,
-			want:         0,
-			wantErr:      ErrNegativeCount,
-			wantBuffered: 0,
-		},
-	}
-	for _, tt := range tests {
-		br := NewReaderSize(tt.r, tt.bufSize)
-		if tt.peekSize > 0 {
-			peekBuf, err := br.Peek(tt.peekSize)
-			if err != nil {
-				t.Errorf("%s: Peek(%d): %v", tt.name, tt.peekSize, err)
-				continue
-			}
-			if len(peekBuf) != tt.peekSize {
-				t.Errorf("%s: len(Peek(%d)) = %v; want %v", tt.name, tt.peekSize, len(peekBuf), tt.peekSize)
-				continue
-			}
-		}
-		discarded, err := br.Discard(tt.n)
-		if ge, we := fmt.Sprint(err), fmt.Sprint(tt.wantErr); discarded != tt.want || ge != we {
-			t.Errorf("%s: Discard(%d) = (%v, %v); want (%v, %v)", tt.name, tt.n, discarded, ge, tt.want, we)
-			continue
-		}
-		if bn := br.Buffered(); bn != tt.wantBuffered {
-			t.Errorf("%s: after Discard, Buffered = %d; want %d", tt.name, bn, tt.wantBuffered)
-		}
-	}
-
-}
-
 // An onlyReader only implements io.Reader, no matter what other methods the underlying implementation may have.
 type onlyReader struct {
 	io.Reader
@@ -1407,23 +1278,6 @@ type onlyWriter struct {
 	io.Writer
 }
 
-// A scriptedReader is an io.Reader that executes its steps sequentially.
-type scriptedReader []func(p []byte) (n int, err error)
-
-func (sr *scriptedReader) Read(p []byte) (n int, err error) {
-	if len(*sr) == 0 {
-		panic("too many Read calls on scripted Reader. No steps remain.")
-	}
-	step := (*sr)[0]
-	*sr = (*sr)[1:]
-	return step(p)
-}
-
-func newScriptedReader(steps ...func(p []byte) (n int, err error)) io.Reader {
-	sr := scriptedReader(steps)
-	return &sr
-}
-
 func BenchmarkReaderCopyOptimal(b *testing.B) {
 	// Optimal case is where the underlying reader implements io.WriterTo
 	srcBuf := bytes.NewBuffer(make([]byte, 8192))
diff --git a/src/bufio/scan.go b/src/bufio/scan.go
index 7a349fa..364d159 100644
--- a/src/bufio/scan.go
+++ b/src/bufio/scan.go
@@ -109,7 +109,7 @@ func (s *Scanner) Text() string {
 // After Scan returns false, the Err method will return any error that
 // occurred during scanning, except that if it was io.EOF, Err
 // will return nil.
-// Scan panics if the split function returns 100 empty tokens without
+// Split panics if the split function returns 100 empty tokens without
 // advancing the input. This is a common error mode for scanners.
 func (s *Scanner) Scan() bool {
 	// Loop until we have a token.
diff --git a/src/builtin/builtin.go b/src/builtin/builtin.go
index d63ad22..51550a4 100644
--- a/src/builtin/builtin.go
+++ b/src/builtin/builtin.go
@@ -236,14 +236,14 @@ func panic(v interface{})
 // panicking.
 func recover() interface{}
 
-// The print built-in function formats its arguments in an
-// implementation-specific way and writes the result to standard error.
+// The print built-in function formats its arguments in an implementation-
+// specific way and writes the result to standard error.
 // Print is useful for bootstrapping and debugging; it is not guaranteed
 // to stay in the language.
 func print(args ...Type)
 
-// The println built-in function formats its arguments in an
-// implementation-specific way and writes the result to standard error.
+// The println built-in function formats its arguments in an implementation-
+// specific way and writes the result to standard error.
 // Spaces are always added between arguments and a newline is appended.
 // Println is useful for bootstrapping and debugging; it is not guaranteed
 // to stay in the language.
diff --git a/src/bytes/buffer.go b/src/bytes/buffer.go
index 4db9386..46ca1d5 100644
--- a/src/bytes/buffer.go
+++ b/src/bytes/buffer.go
@@ -56,10 +56,6 @@ func (b *Buffer) String() string {
 // b.Len() == len(b.Bytes()).
 func (b *Buffer) Len() int { return len(b.buf) - b.off }
 
-// Cap returns the capacity of the buffer's underlying byte slice, that is, the
-// total space allocated for the buffer's data.
-func (b *Buffer) Cap() int { return cap(b.buf) }
-
 // Truncate discards all but the first n unread bytes from the buffer.
 // It panics if n is negative or greater than the length of the buffer.
 func (b *Buffer) Truncate(n int) {
diff --git a/src/bytes/buffer_test.go b/src/bytes/buffer_test.go
index 7de17ae..75145b0 100644
--- a/src/bytes/buffer_test.go
+++ b/src/bytes/buffer_test.go
@@ -231,23 +231,6 @@ func TestMixedReadsAndWrites(t *testing.T) {
 	empty(t, "TestMixedReadsAndWrites (2)", &buf, s, make([]byte, buf.Len()))
 }
 
-func TestCapWithPreallocatedSlice(t *testing.T) {
-	buf := NewBuffer(make([]byte, 10))
-	n := buf.Cap()
-	if n != 10 {
-		t.Errorf("expected 10, got %d", n)
-	}
-}
-
-func TestCapWithSliceAndWrittenData(t *testing.T) {
-	buf := NewBuffer(make([]byte, 0, 10))
-	buf.Write([]byte("test"))
-	n := buf.Cap()
-	if n != 10 {
-		t.Errorf("expected 10, got %d", n)
-	}
-}
-
 func TestNil(t *testing.T) {
 	var b *Buffer
 	if b.String() != "<nil>" {
diff --git a/src/bytes/bytes.go b/src/bytes/bytes.go
index b868240..7634707 100644
--- a/src/bytes/bytes.go
+++ b/src/bytes/bytes.go
@@ -23,7 +23,7 @@ func equalPortable(a, b []byte) bool {
 	return true
 }
 
-// explode splits s into a slice of UTF-8 sequences, one per Unicode code point (still slices of bytes),
+// explode splits s into a slice of UTF-8 sequences, one per Unicode character (still slices of bytes),
 // up to a maximum of n byte slices. Invalid UTF-8 sequences are chopped into individual bytes.
 func explode(s []byte, n int) [][]byte {
 	if n <= 0 {
@@ -47,7 +47,6 @@ func explode(s []byte, n int) [][]byte {
 }
 
 // Count counts the number of non-overlapping instances of sep in s.
-// If sep is an empty slice, Count returns 1 + the number of Unicode code points in s.
 func Count(s, sep []byte) int {
 	n := len(sep)
 	if n == 0 {
@@ -138,16 +137,6 @@ func LastIndex(s, sep []byte) int {
 	return -1
 }
 
-// LastIndexByte returns the index of the last instance of c in s, or -1 if c is not present in s.
-func LastIndexByte(s []byte, c byte) int {
-	for i := len(s) - 1; i >= 0; i-- {
-		if s[i] == c {
-			return i
-		}
-	}
-	return -1
-}
-
 // IndexRune interprets s as a sequence of UTF-8-encoded Unicode code points.
 // It returns the byte index of the first occurrence in s of the given rune.
 // It returns -1 if rune is not present in s.
@@ -453,7 +442,7 @@ func isSeparator(r rune) bool {
 // Title returns a copy of s with all Unicode letters that begin words
 // mapped to their title case.
 //
-// BUG(rsc): The rule Title uses for word boundaries does not handle Unicode punctuation properly.
+// BUG: The rule Title uses for word boundaries does not handle Unicode punctuation properly.
 func Title(s []byte) []byte {
 	// Use a closure here to remember state.
 	// Hackish but effective. Depends on Map scanning in order and calling
diff --git a/src/bytes/bytes_decl.go b/src/bytes/bytes_decl.go
index b453f21..617d748 100644
--- a/src/bytes/bytes_decl.go
+++ b/src/bytes/bytes_decl.go
@@ -21,4 +21,4 @@ func Equal(a, b []byte) bool // ../runtime/asm_$GOARCH.s
 // Compare returns an integer comparing two byte slices lexicographically.
 // The result will be 0 if a==b, -1 if a < b, and +1 if a > b.
 // A nil argument is equivalent to an empty slice.
-func Compare(a, b []byte) int // ../runtime/noasm.go or ../runtime/asm_{386,amd64}.s
+func Compare(a, b []byte) int // ../runtime/noasm_arm.goc or ../runtime/asm_{386,amd64}.s
diff --git a/src/bytes/bytes_test.go b/src/bytes/bytes_test.go
index 6245e48..980c41d 100644
--- a/src/bytes/bytes_test.go
+++ b/src/bytes/bytes_test.go
@@ -265,23 +265,6 @@ func TestIndexByte(t *testing.T) {
 	}
 }
 
-func TestLastIndexByte(t *testing.T) {
-	testCases := []BinOpTest{
-		{"", "q", -1},
-		{"abcdef", "q", -1},
-		{"abcdefabcdef", "a", len("abcdef")},      // something in the middle
-		{"abcdefabcdef", "f", len("abcdefabcde")}, // last byte
-		{"zabcdefabcdef", "z", 0},                 // first byte
-		{"a☺b☻c☹d", "b", len("a☺")},               // non-ascii
-	}
-	for _, test := range testCases {
-		actual := LastIndexByte([]byte(test.a), test.b[0])
-		if actual != test.i {
-			t.Errorf("LastIndexByte(%q,%c) = %v; want %v", test.a, test.b[0], actual, test.i)
-		}
-	}
-}
-
 // test a larger buffer with different sizes and alignments
 func TestIndexByteBig(t *testing.T) {
 	var n = 1024
diff --git a/src/bytes/compare_test.go b/src/bytes/compare_test.go
index f2d81d5..6352237 100644
--- a/src/bytes/compare_test.go
+++ b/src/bytes/compare_test.go
@@ -17,8 +17,6 @@ var compareTests = []struct {
 	{[]byte("a"), []byte(""), 1},
 	{[]byte(""), []byte("a"), -1},
 	{[]byte("abc"), []byte("abc"), 0},
-	{[]byte("abd"), []byte("abc"), 1},
-	{[]byte("abc"), []byte("abd"), -1},
 	{[]byte("ab"), []byte("abc"), -1},
 	{[]byte("abc"), []byte("ab"), 1},
 	{[]byte("x"), []byte("ab"), 1},
@@ -29,7 +27,6 @@ var compareTests = []struct {
 	{[]byte("abcdefgh"), []byte("abcdefgh"), 0},
 	{[]byte("abcdefghi"), []byte("abcdefghi"), 0},
 	{[]byte("abcdefghi"), []byte("abcdefghj"), -1},
-	{[]byte("abcdefghj"), []byte("abcdefghi"), 1},
 	// nil tests
 	{nil, nil, 0},
 	{[]byte(""), nil, 0},
diff --git a/src/bytes/export_test.go b/src/bytes/export_test.go
index f61523e..3b915d5 100644
--- a/src/bytes/export_test.go
+++ b/src/bytes/export_test.go
@@ -7,3 +7,7 @@ package bytes
 // Export func for testing
 var IndexBytePortable = indexBytePortable
 var EqualPortable = equalPortable
+
+func (b *Buffer) Cap() int {
+	return cap(b.buf)
+}
diff --git a/src/bytes/reader.go b/src/bytes/reader.go
index b89d154..d2d40fa 100644
--- a/src/bytes/reader.go
+++ b/src/bytes/reader.go
@@ -29,12 +29,6 @@ func (r *Reader) Len() int {
 	return int(int64(len(r.s)) - r.i)
 }
 
-// Size returns the original length of the underlying byte slice.
-// Size is the number of bytes available for reading via ReadAt.
-// The returned value is always the same and is not affected by calls
-// to any other method.
-func (r *Reader) Size() int64 { return int64(len(r.s)) }
-
 func (r *Reader) Read(b []byte) (n int, err error) {
 	if len(b) == 0 {
 		return 0, nil
diff --git a/src/bytes/reader_test.go b/src/bytes/reader_test.go
index b929a28..d3dce53 100644
--- a/src/bytes/reader_test.go
+++ b/src/bytes/reader_test.go
@@ -244,15 +244,3 @@ func TestReaderCopyNothing(t *testing.T) {
 		t.Errorf("behavior differs: with = %#v; without: %#v", with, withOut)
 	}
 }
-
-// tests that Len is affected by reads, but Size is not.
-func TestReaderLenSize(t *testing.T) {
-	r := NewReader([]byte("abc"))
-	io.CopyN(ioutil.Discard, r, 1)
-	if r.Len() != 2 {
-		t.Errorf("Len = %d; want 2", r.Len())
-	}
-	if r.Size() != 3 {
-		t.Errorf("Size = %d; want 3", r.Size())
-	}
-}
diff --git a/src/clean.bash b/src/clean.bash
index 39fe36d..f362602 100755
--- a/src/clean.bash
+++ b/src/clean.bash
@@ -5,18 +5,12 @@
 
 set -e
 
-if [ ! -f run.bash ]; then
-	echo 'clean.bash must be run from $GOROOT/src' 1>&2
-	exit 1
-fi
-export GOROOT="$(cd .. && pwd)"
+eval $(go tool dist env)
 
-gobin="${GOBIN:-../bin}"
-if ! "$gobin"/go help >/dev/null 2>&1; then
-	echo 'cannot find go command; nothing to clean' >&2
+if [ ! -x $GOTOOLDIR/dist ]; then
+	echo 'cannot find $GOTOOLDIR/dist; nothing to clean' >&2
 	exit 1
 fi
 
-"$gobin/go" clean -i std
-"$gobin/go" tool dist clean
-"$gobin/go" clean -i cmd
+"$GOBIN/go" clean -i std
+$GOTOOLDIR/dist clean
diff --git a/src/clean.bat b/src/clean.bat
index 3cc6a68..dcf54ea 100644
--- a/src/clean.bat
+++ b/src/clean.bat
@@ -7,7 +7,7 @@ setlocal
 
 set GOBUILDFAIL=0
 
-go tool dist env -w -p >env.bat
+go tool dist env -wp >env.bat
 if errorlevel 1 goto fail
 call env.bat
 del env.bat
@@ -19,8 +19,7 @@ goto fail
 :distok
 
 "%GOBIN%\go" clean -i std
-"%GOBIN%\go" tool dist clean
-"%GOBIN%\go" clean -i cmd
+%GOTOOLDIR%\dist clean
 
 goto end
 
diff --git a/src/clean.rc b/src/clean.rc
index 23bbd60..41cab61 100755
--- a/src/clean.rc
+++ b/src/clean.rc
@@ -11,5 +11,4 @@ if(! test -x $GOTOOLDIR/dist){
 }
 
 $GOBIN/go clean -i std
-$GOBIN/go tool dist clean
-$GOBIN/go clean -i cmd
+$GOTOOLDIR/dist clean
diff --git a/src/cmd/5a/Makefile b/src/cmd/5a/Makefile
new file mode 100644
index 0000000..27290dd
--- /dev/null
+++ b/src/cmd/5a/Makefile
@@ -0,0 +1,10 @@
+# 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
+
+install: y.tab.h
+
+y.tab.h: a.y
+	LANG=C LANGUAGE=en_US.UTF8 bison -d -v -y a.y
diff --git a/src/cmd/5a/a.h b/src/cmd/5a/a.h
new file mode 100644
index 0000000..bb60fe7
--- /dev/null
+++ b/src/cmd/5a/a.h
@@ -0,0 +1,169 @@
+// Inferno utils/5a/a.h
+// http://code.google.com/p/inferno-os/source/browse/utils/5a/a.h
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.	All rights reserved.
+//	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 <bio.h>
+#include <link.h>
+#include "../5l/5.out.h"
+
+#ifndef	EXTERN
+#define	EXTERN	extern
+#endif
+
+#undef	getc
+#undef	ungetc
+#undef	BUFSIZ
+
+#define	getc	ccgetc
+#define	ungetc	ccungetc
+
+typedef	struct	Sym	Sym;
+typedef	struct	Io	Io;
+
+#define	MAXALIGN	7
+#define	FPCHIP		1
+#define	NSYMB		8192
+#define	BUFSIZ		8192
+#define	HISTSZ		20
+#ifndef	EOF
+#define	EOF		(-1)
+#endif
+#define	IGN		(-2)
+#define	GETC()		((--fi.c < 0)? filbuf(): *fi.p++ & 0xff)
+#define	NHASH		503
+#define	STRINGSZ	200
+#define	NMACRO		10
+
+struct	Sym
+{
+	Sym*	link;
+	char*	macro;
+	int32	value;
+	ushort	type;
+	char	*name;
+	char	sym;
+};
+#define	S	((Sym*)0)
+
+EXTERN	struct
+{
+	char*	p;
+	int	c;
+} fi;
+
+struct	Io
+{
+	Io*	link;
+	char	b[BUFSIZ];
+	char*	p;
+	short	c;
+	short	f;
+};
+#define	I	((Io*)0)
+
+enum
+{
+	CLAST,
+	CMACARG,
+	CMACRO,
+	CPREPROC,
+
+	Always	= 14,
+};
+
+EXTERN	int	debug[256];
+EXTERN	Sym*	hash[NHASH];
+EXTERN	char**	Dlist;
+EXTERN	int	nDlist;
+EXTERN	int	newflag;
+EXTERN	char*	hunk;
+EXTERN	char**	include;
+EXTERN	Io*	iofree;
+EXTERN	Io*	ionext;
+EXTERN	Io*	iostack;
+EXTERN	int32	lineno;
+EXTERN	int	nerrors;
+EXTERN	int32	nhunk;
+EXTERN	int	ninclude;
+EXTERN	int32	nsymb;
+EXTERN	Addr	nullgen;
+EXTERN	char*	outfile;
+EXTERN	int	pass;
+EXTERN	int32	pc;
+EXTERN	int	peekc;
+EXTERN	int32	stmtline;
+EXTERN	int	sym;
+EXTERN	char*	symb;
+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);
+void	ensuresymb(int32);
+void	errorexit(void);
+void	pushio(void);
+void	newio(void);
+void	newfile(char*, int);
+Sym*	slookup(char*);
+Sym*	lookup(void);
+void	syminit(Sym*);
+int32	yylex(void);
+int	getc(void);
+int	getnsc(void);
+void	unget(int);
+int	escchar(int);
+void	cinit(void);
+void	pinit(char*);
+void	cclean(void);
+int	isreg(Addr*);
+void	outcode(int, int, Addr*, int, Addr*);
+int	filbuf(void);
+Sym*	getsym(void);
+void	domacro(void);
+void	macund(void);
+void	macdef(void);
+void	macexpand(Sym*, char*);
+void	macinc(void);
+void	maclin(void);
+void	macprag(void);
+void	macif(int);
+void	macend(void);
+void	dodefine(char*);
+void	prfile(int32);
+void	linehist(char*, int);
+void	gethunk(void);
+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
new file mode 100644
index 0000000..ad64760
--- /dev/null
+++ b/src/cmd/5a/a.y
@@ -0,0 +1,747 @@
+// Inferno utils/5a/a.y
+// http://code.google.com/p/inferno-os/source/browse/utils/5a/a.y
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.	All rights reserved.
+//	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 <stdio.h>	/* if we don't, bison will, and a.h re-#defines getc */
+#include <libc.h>
+#include "a.h"
+#include "../../runtime/funcdata.h"
+%}
+%union
+{
+	Sym	*sym;
+	int32	lval;
+	double	dval;
+	char	sval[8];
+	Addr	addr;
+}
+%left	'|'
+%left	'^'
+%left	'&'
+%left	'<' '>'
+%left	'+' '-'
+%left	'*' '/' '%'
+%token	<lval>	LTYPE1 LTYPE2 LTYPE3 LTYPE4 LTYPE5
+%token	<lval>	LTYPE6 LTYPE7 LTYPE8 LTYPE9 LTYPEA
+%token	<lval>	LTYPEB LTYPEC LTYPED LTYPEE
+%token	<lval>	LTYPEG LTYPEH LTYPEI LTYPEJ LTYPEK
+%token	<lval>	LTYPEL LTYPEM LTYPEN LTYPEBX LTYPEPLD
+%token	<lval>	LCONST LSP LSB LFP LPC
+%token	<lval>	LTYPEX LTYPEPC LTYPEF LR LREG LF LFREG LC LCREG LPSR LFCR
+%token	<lval>	LCOND LS LAT
+%token	<dval>	LFCONST
+%token	<sval>	LSCONST
+%token	<sym>	LNAME LLAB LVAR
+%type	<lval>	con expr oexpr pointer offset sreg spreg creg
+%type	<lval>	rcon cond reglist
+%type	<addr>	gen rel reg regreg freg shift fcon frcon
+%type	<addr>	imm ximm name oreg ireg nireg ioreg imsr
+%%
+prog:
+|	prog
+	{
+		stmtline = lineno;
+	}
+	line
+
+line:
+	LLAB ':'
+	{
+		if($1->value != pc)
+			yyerror("redeclaration of %s", $1->name);
+		$1->value = pc;
+	}
+	line
+|	LNAME ':'
+	{
+		$1->type = LLAB;
+		$1->value = pc;
+	}
+	line
+|	LNAME '=' expr ';'
+	{
+		$1->type = LVAR;
+		$1->value = $3;
+	}
+|	LVAR '=' expr ';'
+	{
+		if($1->value != $3)
+			yyerror("redeclaration of %s", $1->name);
+		$1->value = $3;
+	}
+|	';'
+|	inst ';'
+|	error ';'
+
+inst:
+/*
+ * ADD
+ */
+	LTYPE1 cond imsr ',' spreg ',' reg
+	{
+		outcode($1, $2, &$3, $5, &$7);
+	}
+|	LTYPE1 cond imsr ',' spreg ','
+	{
+		outcode($1, $2, &$3, $5, &nullgen);
+	}
+|	LTYPE1 cond imsr ',' reg
+	{
+		outcode($1, $2, &$3, NREG, &$5);
+	}
+/*
+ * MVN
+ */
+|	LTYPE2 cond imsr ',' reg
+	{
+		outcode($1, $2, &$3, NREG, &$5);
+	}
+/*
+ * MOVW
+ */
+|	LTYPE3 cond gen ',' gen
+	{
+		outcode($1, $2, &$3, NREG, &$5);
+	}
+/*
+ * B/BL
+ */
+|	LTYPE4 cond comma rel
+	{
+		outcode($1, $2, &nullgen, NREG, &$4);
+	}
+|	LTYPE4 cond comma nireg
+	{
+		outcode($1, $2, &nullgen, NREG, &$4);
+	}
+/*
+ * BX
+ */
+|	LTYPEBX comma ireg
+	{
+		outcode($1, Always, &nullgen, NREG, &$3);
+	}
+/*
+ * BEQ
+ */
+|	LTYPE5 comma rel
+	{
+		outcode($1, Always, &nullgen, NREG, &$3);
+	}
+/*
+ * SWI
+ */
+|	LTYPE6 cond comma gen
+	{
+		outcode($1, $2, &nullgen, NREG, &$4);
+	}
+/*
+ * CMP
+ */
+|	LTYPE7 cond imsr ',' spreg comma
+	{
+		outcode($1, $2, &$3, $5, &nullgen);
+	}
+/*
+ * MOVM
+ */
+|	LTYPE8 cond ioreg ',' '[' reglist ']'
+	{
+		Addr g;
+
+		g = nullgen;
+		g.type = D_CONST;
+		g.offset = $6;
+		outcode($1, $2, &$3, NREG, &g);
+	}
+|	LTYPE8 cond '[' reglist ']' ',' ioreg
+	{
+		Addr g;
+
+		g = nullgen;
+		g.type = D_CONST;
+		g.offset = $4;
+		outcode($1, $2, &g, NREG, &$7);
+	}
+/*
+ * SWAP
+ */
+|	LTYPE9 cond reg ',' ireg ',' reg
+	{
+		outcode($1, $2, &$5, $3.reg, &$7);
+	}
+|	LTYPE9 cond reg ',' ireg comma
+	{
+		outcode($1, $2, &$5, $3.reg, &$3);
+	}
+|	LTYPE9 cond comma ireg ',' reg
+	{
+		outcode($1, $2, &$4, $6.reg, &$6);
+	}
+/*
+ * RET
+ */
+|	LTYPEA cond comma
+	{
+		outcode($1, $2, &nullgen, NREG, &nullgen);
+	}
+/*
+ * TEXT/GLOBL
+ */
+|	LTYPEB name ',' imm
+	{
+		$4.type = D_CONST2;
+		$4.offset2 = ArgsSizeUnknown;
+		outcode($1, Always, &$2, 0, &$4);
+	}
+|	LTYPEB name ',' con ',' imm
+	{
+		$6.type = D_CONST2;
+		$6.offset2 = ArgsSizeUnknown;
+		outcode($1, Always, &$2, $4, &$6);
+	}
+|	LTYPEB name ',' con ',' imm '-' con
+	{
+		$6.type = D_CONST2;
+		$6.offset2 = $8;
+		outcode($1, Always, &$2, $4, &$6);
+	}
+/*
+ * DATA
+ */
+|	LTYPEC name '/' con ',' ximm
+	{
+		outcode($1, Always, &$2, $4, &$6);
+	}
+/*
+ * CASE
+ */
+|	LTYPED cond reg comma
+	{
+		outcode($1, $2, &$3, NREG, &nullgen);
+	}
+/*
+ * word
+ */
+|	LTYPEH comma ximm
+	{
+		outcode($1, Always, &nullgen, NREG, &$3);
+	}
+/*
+ * floating-point coprocessor
+ */
+|	LTYPEI cond freg ',' freg
+	{
+		outcode($1, $2, &$3, NREG, &$5);
+	}
+|	LTYPEK cond frcon ',' freg
+	{
+		outcode($1, $2, &$3, NREG, &$5);
+	}
+|	LTYPEK cond frcon ',' LFREG ',' freg
+	{
+		outcode($1, $2, &$3, $5, &$7);
+	}
+|	LTYPEL cond freg ',' freg comma
+	{
+		outcode($1, $2, &$3, $5.reg, &nullgen);
+	}
+/*
+ * MCR MRC
+ */
+|	LTYPEJ cond con ',' expr ',' spreg ',' creg ',' creg oexpr
+	{
+		Addr g;
+
+		g = nullgen;
+		g.type = D_CONST;
+		g.offset =
+			(0xe << 24) |		/* opcode */
+			($1 << 20) |		/* MCR/MRC */
+			($2 << 28) |		/* scond */
+			(($3 & 15) << 8) |	/* coprocessor number */
+			(($5 & 7) << 21) |	/* coprocessor operation */
+			(($7 & 15) << 12) |	/* arm register */
+			(($9 & 15) << 16) |	/* Crn */
+			(($11 & 15) << 0) |	/* Crm */
+			(($12 & 7) << 5) |	/* coprocessor information */
+			(1<<4);			/* must be set */
+		outcode(AMRC, Always, &nullgen, NREG, &g);
+	}
+/*
+ * MULL r1,r2,(hi,lo)
+ */
+|	LTYPEM cond reg ',' reg ',' regreg
+	{
+		outcode($1, $2, &$3, $5.reg, &$7);
+	}
+/*
+ * MULA r1,r2,r3,r4: (r1*r2+r3) & 0xffffffff -> r4
+ * MULAW{T,B} r1,r2,r3,r4
+ */
+|	LTYPEN cond reg ',' reg ',' reg ',' spreg
+	{
+		$7.type = D_REGREG2;
+		$7.offset = $9;
+		outcode($1, $2, &$3, $5.reg, &$7);
+	}
+/*
+ * PLD
+ */
+|	LTYPEPLD oreg
+	{
+		outcode($1, Always, &$2, NREG, &nullgen);
+	}
+/*
+ * PCDATA
+ */
+|	LTYPEPC gen ',' gen
+	{
+		if($2.type != D_CONST || $4.type != D_CONST)
+			yyerror("arguments to PCDATA must be integer constants");
+		outcode($1, Always, &$2, NREG, &$4);
+	}
+/*
+ * FUNCDATA
+ */
+|	LTYPEF gen ',' gen
+	{
+		if($2.type != D_CONST)
+			yyerror("index for FUNCDATA must be integer constant");
+		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);
+	}
+/*
+ * END
+ */
+|	LTYPEE comma
+	{
+		outcode($1, Always, &nullgen, NREG, &nullgen);
+	}
+
+cond:
+	{
+		$$ = Always;
+	}
+|	cond LCOND
+	{
+		$$ = ($1 & ~C_SCOND) | $2;
+	}
+|	cond LS
+	{
+		$$ = $1 | $2;
+	}
+
+comma:
+|	',' comma
+
+rel:
+	con '(' LPC ')'
+	{
+		$$ = nullgen;
+		$$.type = D_BRANCH;
+		$$.offset = $1 + pc;
+	}
+|	LNAME offset
+	{
+		$$ = nullgen;
+		if(pass == 2)
+			yyerror("undefined label: %s", $1->name);
+		$$.type = D_BRANCH;
+		$$.offset = $2;
+	}
+|	LLAB offset
+	{
+		$$ = nullgen;
+		$$.type = D_BRANCH;
+		$$.offset = $1->value + $2;
+	}
+
+ximm:	'$' con
+	{
+		$$ = nullgen;
+		$$.type = D_CONST;
+		$$.offset = $2;
+	}
+|	'$' oreg
+	{
+		$$ = $2;
+		$$.type = D_CONST;
+	}
+|	'$' '*' '$' oreg
+	{
+		$$ = $4;
+		$$.type = D_OCONST;
+	}
+|	'$' LSCONST
+	{
+		$$ = nullgen;
+		$$.type = D_SCONST;
+		memcpy($$.u.sval, $2, sizeof($$.u.sval));
+	}
+|	fcon
+
+fcon:
+	'$' LFCONST
+	{
+		$$ = nullgen;
+		$$.type = D_FCONST;
+		$$.u.dval = $2;
+	}
+|	'$' '-' LFCONST
+	{
+		$$ = nullgen;
+		$$.type = D_FCONST;
+		$$.u.dval = -$3;
+	}
+
+reglist:
+	spreg
+	{
+		$$ = 1 << $1;
+	}
+|	spreg '-' spreg
+	{
+		int i;
+		$$=0;
+		for(i=$1; i<=$3; i++)
+			$$ |= 1<<i;
+		for(i=$3; i<=$1; i++)
+			$$ |= 1<<i;
+	}
+|	spreg comma reglist
+	{
+		$$ = (1<<$1) | $3;
+	}
+
+gen:
+	reg
+|	ximm
+|	shift
+|	shift '(' spreg ')'
+	{
+		$$ = $1;
+		$$.reg = $3;
+	}
+|	LPSR
+	{
+		$$ = nullgen;
+		$$.type = D_PSR;
+		$$.reg = $1;
+	}
+|	LFCR
+	{
+		$$ = nullgen;
+		$$.type = D_FPCR;
+		$$.reg = $1;
+	}
+|	con
+	{
+		$$ = nullgen;
+		$$.type = D_OREG;
+		$$.offset = $1;
+	}
+|	oreg
+|	freg
+
+nireg:
+	ireg
+|	name
+	{
+		$$ = $1;
+		if($1.name != D_EXTERN && $1.name != D_STATIC) {
+		}
+	}
+
+ireg:
+	'(' spreg ')'
+	{
+		$$ = nullgen;
+		$$.type = D_OREG;
+		$$.reg = $2;
+		$$.offset = 0;
+	}
+
+ioreg:
+	ireg
+|	con '(' sreg ')'
+	{
+		$$ = nullgen;
+		$$.type = D_OREG;
+		$$.reg = $3;
+		$$.offset = $1;
+	}
+
+oreg:
+	name
+|	name '(' sreg ')'
+	{
+		$$ = $1;
+		$$.type = D_OREG;
+		$$.reg = $3;
+	}
+|	ioreg
+
+imsr:
+	reg
+|	imm
+|	shift
+
+imm:	'$' con
+	{
+		$$ = nullgen;
+		$$.type = D_CONST;
+		$$.offset = $2;
+	}
+
+reg:
+	spreg
+	{
+		$$ = nullgen;
+		$$.type = D_REG;
+		$$.reg = $1;
+	}
+
+regreg:
+	'(' spreg ',' spreg ')'
+	{
+		$$ = nullgen;
+		$$.type = D_REGREG;
+		$$.reg = $2;
+		$$.offset = $4;
+	}
+
+shift:
+	spreg '<' '<' rcon
+	{
+		$$ = nullgen;
+		$$.type = D_SHIFT;
+		$$.offset = $1 | $4 | (0 << 5);
+	}
+|	spreg '>' '>' rcon
+	{
+		$$ = nullgen;
+		$$.type = D_SHIFT;
+		$$.offset = $1 | $4 | (1 << 5);
+	}
+|	spreg '-' '>' rcon
+	{
+		$$ = nullgen;
+		$$.type = D_SHIFT;
+		$$.offset = $1 | $4 | (2 << 5);
+	}
+|	spreg LAT '>' rcon
+	{
+		$$ = nullgen;
+		$$.type = D_SHIFT;
+		$$.offset = $1 | $4 | (3 << 5);
+	}
+
+rcon:
+	spreg
+	{
+		if($$ < 0 || $$ >= 16)
+			print("register value out of range\n");
+		$$ = (($1&15) << 8) | (1 << 4);
+	}
+|	con
+	{
+		if($$ < 0 || $$ >= 32)
+			print("shift value out of range\n");
+		$$ = ($1&31) << 7;
+	}
+
+sreg:
+	LREG
+|	LPC
+	{
+		$$ = REGPC;
+	}
+|	LR '(' expr ')'
+	{
+		if($3 < 0 || $3 >= NREG)
+			print("register value out of range\n");
+		$$ = $3;
+	}
+
+spreg:
+	sreg
+|	LSP
+	{
+		$$ = REGSP;
+	}
+
+creg:
+	LCREG
+|	LC '(' expr ')'
+	{
+		if($3 < 0 || $3 >= NREG)
+			print("register value out of range\n");
+		$$ = $3;
+	}
+
+frcon:
+	freg
+|	fcon
+
+freg:
+	LFREG
+	{
+		$$ = nullgen;
+		$$.type = D_FREG;
+		$$.reg = $1;
+	}
+|	LF '(' con ')'
+	{
+		$$ = nullgen;
+		$$.type = D_FREG;
+		$$.reg = $3;
+	}
+
+name:
+	con '(' pointer ')'
+	{
+		$$ = nullgen;
+		$$.type = D_OREG;
+		$$.name = $3;
+		$$.sym = nil;
+		$$.offset = $1;
+	}
+|	LNAME offset '(' pointer ')'
+	{
+		$$ = nullgen;
+		$$.type = D_OREG;
+		$$.name = $4;
+		$$.sym = linklookup(ctxt, $1->name, 0);
+		$$.offset = $2;
+	}
+|	LNAME '<' '>' offset '(' LSB ')'
+	{
+		$$ = nullgen;
+		$$.type = D_OREG;
+		$$.name = D_STATIC;
+		$$.sym = linklookup(ctxt, $1->name, 1);
+		$$.offset = $4;
+	}
+
+offset:
+	{
+		$$ = 0;
+	}
+|	'+' con
+	{
+		$$ = $2;
+	}
+|	'-' con
+	{
+		$$ = -$2;
+	}
+
+pointer:
+	LSB
+|	LSP
+|	LFP
+
+con:
+	LCONST
+|	LVAR
+	{
+		$$ = $1->value;
+	}
+|	'-' con
+	{
+		$$ = -$2;
+	}
+|	'+' con
+	{
+		$$ = $2;
+	}
+|	'~' con
+	{
+		$$ = ~$2;
+	}
+|	'(' expr ')'
+	{
+		$$ = $2;
+	}
+
+oexpr:
+	{
+		$$ = 0;
+	}
+|	',' expr
+	{
+		$$ = $2;
+	}
+
+expr:
+	con
+|	expr '+' expr
+	{
+		$$ = $1 + $3;
+	}
+|	expr '-' expr
+	{
+		$$ = $1 - $3;
+	}
+|	expr '*' expr
+	{
+		$$ = $1 * $3;
+	}
+|	expr '/' expr
+	{
+		$$ = $1 / $3;
+	}
+|	expr '%' expr
+	{
+		$$ = $1 % $3;
+	}
+|	expr '<' '<' expr
+	{
+		$$ = $1 << $4;
+	}
+|	expr '>' '>' expr
+	{
+		$$ = $1 >> $4;
+	}
+|	expr '&' expr
+	{
+		$$ = $1 & $3;
+	}
+|	expr '^' expr
+	{
+		$$ = $1 ^ $3;
+	}
+|	expr '|' expr
+	{
+		$$ = $1 | $3;
+	}
diff --git a/src/cmd/5a/doc.go b/src/cmd/5a/doc.go
new file mode 100644
index 0000000..3e9e78f
--- /dev/null
+++ b/src/cmd/5a/doc.go
@@ -0,0 +1,20 @@
+// 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
+
+/*
+
+5a is a version of the Plan 9 assembler.  The original is documented at
+
+	http://plan9.bell-labs.com/magic/man2html/1/8a
+
+Go-specific considerations are documented at
+
+	http://golang.org/doc/asm
+
+Its target architecture is the ARM, referred to by these tools as arm.
+
+*/
+package main
diff --git a/src/cmd/5a/lex.c b/src/cmd/5a/lex.c
new file mode 100644
index 0000000..9c69709
--- /dev/null
+++ b/src/cmd/5a/lex.c
@@ -0,0 +1,538 @@
+// Inferno utils/5a/lex.c
+// http://code.google.com/p/inferno-os/source/browse/utils/5a/lex.c
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.	All rights reserved.
+//	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.
+
+#define	EXTERN
+#include <u.h>
+#include <libc.h>
+#include "a.h"
+#include "y.tab.h"
+
+enum
+{
+	Plan9	= 1<<0,
+	Unix	= 1<<1,
+	Windows	= 1<<2,
+};
+
+int
+systemtype(int sys)
+{
+#ifdef _WIN32
+	return sys&Windows;
+#else
+	return sys&Plan9;
+#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;
+
+	thechar = '5';
+	thestring = "arm";
+
+	ctxt = linknew(&linkarm);
+	ctxt->diag = yyerror;
+	ctxt->bso = &bstdout;
+	ctxt->enforce_data_order = 1;
+	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(".");
+	
+	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);
+}
+
+int
+assemble(char *file)
+{
+	char *ofile, *p;
+	int i, of;
+
+	ofile = alloc(strlen(file)+3); // +3 for .x\0 (x=thechar)
+	strcpy(ofile, file);
+	p = utfrrune(ofile, '/');
+	if(p) {
+		include[0] = ofile;
+		*p++ = 0;
+	} else
+		p = ofile;
+	if(outfile == 0) {
+		outfile = p;
+		if(outfile){
+			p = utfrrune(outfile, '.');
+			if(p)
+				if(p[1] == 's' && p[2] == 0)
+					p[0] = 0;
+			p = utfrune(outfile, 0);
+			p[0] = '.';
+			p[1] = thechar;
+			p[2] = 0;
+		} else
+			outfile = "/dev/null";
+	}
+
+	of = create(outfile, OWRITE, 0664);
+	if(of < 0) {
+		yyerror("%ca: cannot create %s", thechar, outfile);
+		errorexit();
+	}
+	Binit(&obuf, of, OWRITE);
+	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();
+		if(nerrors)
+			return nerrors;
+	}
+
+	writeobj(ctxt, &obuf);
+	Bflush(&obuf);
+	return 0;
+}
+
+struct
+{
+	char	*name;
+	ushort	type;
+	ushort	value;
+} itab[] =
+{
+	"SP",		LSP,	D_AUTO,
+	"SB",		LSB,	D_EXTERN,
+	"FP",		LFP,	D_PARAM,
+	"PC",		LPC,	D_BRANCH,
+
+	"R",		LR,	0,
+	"R0",		LREG,	0,
+	"R1",		LREG,	1,
+	"R2",		LREG,	2,
+	"R3",		LREG,	3,
+	"R4",		LREG,	4,
+	"R5",		LREG,	5,
+	"R6",		LREG,	6,
+	"R7",		LREG,	7,
+	"R8",		LREG,	8,
+	"R9",		LREG,	9,
+	"g",		LREG,	10, // avoid unintentionally clobber g using R10
+	"R11",		LREG,	11,
+	"R12",		LREG,	12,
+	"R13",		LREG,	13,
+	"R14",		LREG,	14,
+	"R15",		LREG,	15,
+
+	"F",		LF,	0,
+
+	"F0",		LFREG,	0,
+	"F1",		LFREG,	1,
+	"F2",		LFREG,	2,
+	"F3",		LFREG,	3,
+	"F4",		LFREG,	4,
+	"F5",		LFREG,	5,
+	"F6",		LFREG,	6,
+	"F7",		LFREG,	7,
+	"F8",		LFREG,	8,
+	"F9",		LFREG,	9,
+	"F10",		LFREG,	10,
+	"F11",		LFREG,	11,
+	"F12",		LFREG,	12,
+	"F13",		LFREG,	13,
+	"F14",		LFREG,	14,
+	"F15",		LFREG,	15,
+
+	"C",		LC,	0,
+
+	"C0",		LCREG,	0,
+	"C1",		LCREG,	1,
+	"C2",		LCREG,	2,
+	"C3",		LCREG,	3,
+	"C4",		LCREG,	4,
+	"C5",		LCREG,	5,
+	"C6",		LCREG,	6,
+	"C7",		LCREG,	7,
+	"C8",		LCREG,	8,
+	"C9",		LCREG,	9,
+	"C10",		LCREG,	10,
+	"C11",		LCREG,	11,
+	"C12",		LCREG,	12,
+	"C13",		LCREG,	13,
+	"C14",		LCREG,	14,
+	"C15",		LCREG,	15,
+
+	"CPSR",		LPSR,	0,
+	"SPSR",		LPSR,	1,
+
+	"FPSR",		LFCR,	0,
+	"FPCR",		LFCR,	1,
+
+	".EQ",		LCOND,	0,
+	".NE",		LCOND,	1,
+	".CS",		LCOND,	2,
+	".HS",		LCOND,	2,
+	".CC",		LCOND,	3,
+	".LO",		LCOND,	3,
+	".MI",		LCOND,	4,
+	".PL",		LCOND,	5,
+	".VS",		LCOND,	6,
+	".VC",		LCOND,	7,
+	".HI",		LCOND,	8,
+	".LS",		LCOND,	9,
+	".GE",		LCOND,	10,
+	".LT",		LCOND,	11,
+	".GT",		LCOND,	12,
+	".LE",		LCOND,	13,
+	".AL",		LCOND,	Always,
+
+	".U",		LS,	C_UBIT,
+	".S",		LS,	C_SBIT,
+	".W",		LS,	C_WBIT,
+	".P",		LS,	C_PBIT,
+	".PW",		LS,	C_WBIT|C_PBIT,
+	".WP",		LS,	C_WBIT|C_PBIT,
+
+	".F",		LS,	C_FBIT,
+
+	".IBW",		LS,	C_WBIT|C_PBIT|C_UBIT,
+	".IAW",		LS,	C_WBIT|C_UBIT,
+	".DBW",		LS,	C_WBIT|C_PBIT,
+	".DAW",		LS,	C_WBIT,
+	".IB",		LS,	C_PBIT|C_UBIT,
+	".IA",		LS,	C_UBIT,
+	".DB",		LS,	C_PBIT,
+	".DA",		LS,	0,
+
+	"@",		LAT,	0,
+
+	"AND",		LTYPE1,	AAND,
+	"EOR",		LTYPE1,	AEOR,
+	"SUB",		LTYPE1,	ASUB,
+	"RSB",		LTYPE1,	ARSB,
+	"ADD",		LTYPE1,	AADD,
+	"ADC",		LTYPE1,	AADC,
+	"SBC",		LTYPE1,	ASBC,
+	"RSC",		LTYPE1,	ARSC,
+	"ORR",		LTYPE1,	AORR,
+	"BIC",		LTYPE1,	ABIC,
+
+	"SLL",		LTYPE1,	ASLL,
+	"SRL",		LTYPE1,	ASRL,
+	"SRA",		LTYPE1,	ASRA,
+
+	"MUL",		LTYPE1, AMUL,
+	"MULA",		LTYPEN, AMULA,
+	"DIV",		LTYPE1,	ADIV,
+	"MOD",		LTYPE1,	AMOD,
+
+	"MULL",		LTYPEM, AMULL,
+	"MULAL",	LTYPEM, AMULAL,
+	"MULLU",	LTYPEM, AMULLU,
+	"MULALU",	LTYPEM, AMULALU,
+
+	"MVN",		LTYPE2, AMVN,	/* op2 ignored */
+
+	"MOVB",		LTYPE3, AMOVB,
+	"MOVBU",	LTYPE3, AMOVBU,
+	"MOVH",		LTYPE3, AMOVH,
+	"MOVHU",	LTYPE3, AMOVHU,
+	"MOVW",		LTYPE3, AMOVW,
+
+	"MOVD",		LTYPE3, AMOVD,
+	"MOVDF",		LTYPE3, AMOVDF,
+	"MOVDW",	LTYPE3, AMOVDW,
+	"MOVF",		LTYPE3, AMOVF,
+	"MOVFD",		LTYPE3, AMOVFD,
+	"MOVFW",		LTYPE3, AMOVFW,
+	"MOVWD",	LTYPE3, AMOVWD,
+	"MOVWF",		LTYPE3, AMOVWF,
+
+	"LDREX",		LTYPE3, ALDREX,
+	"LDREXD",		LTYPE3, ALDREXD,
+	"STREX",		LTYPE9, ASTREX,
+	"STREXD",		LTYPE9, ASTREXD,
+
+/*
+	"NEGF",		LTYPEI, ANEGF,
+	"NEGD",		LTYPEI, ANEGD,
+	"SQTF",		LTYPEI,	ASQTF,
+	"SQTD",		LTYPEI,	ASQTD,
+	"RNDF",		LTYPEI,	ARNDF,
+	"RNDD",		LTYPEI,	ARNDD,
+	"URDF",		LTYPEI,	AURDF,
+	"URDD",		LTYPEI,	AURDD,
+	"NRMF",		LTYPEI,	ANRMF,
+	"NRMD",		LTYPEI,	ANRMD,
+*/
+
+	"ABSF",		LTYPEI, AABSF,
+	"ABSD",		LTYPEI, AABSD,
+	"SQRTF",	LTYPEI, ASQRTF,
+	"SQRTD",	LTYPEI, ASQRTD,
+	"CMPF",		LTYPEL, ACMPF,
+	"CMPD",		LTYPEL, ACMPD,
+	"ADDF",		LTYPEK,	AADDF,
+	"ADDD",		LTYPEK,	AADDD,
+	"SUBF",		LTYPEK,	ASUBF,
+	"SUBD",		LTYPEK,	ASUBD,
+	"MULF",		LTYPEK,	AMULF,
+	"MULD",		LTYPEK,	AMULD,
+	"DIVF",		LTYPEK,	ADIVF,
+	"DIVD",		LTYPEK,	ADIVD,
+
+	"B",		LTYPE4, AB,
+	"BL",		LTYPE4, ABL,
+	"BX",		LTYPEBX,	ABX,
+
+	"BEQ",		LTYPE5,	ABEQ,
+	"BNE",		LTYPE5,	ABNE,
+	"BCS",		LTYPE5,	ABCS,
+	"BHS",		LTYPE5,	ABHS,
+	"BCC",		LTYPE5,	ABCC,
+	"BLO",		LTYPE5,	ABLO,
+	"BMI",		LTYPE5,	ABMI,
+	"BPL",		LTYPE5,	ABPL,
+	"BVS",		LTYPE5,	ABVS,
+	"BVC",		LTYPE5,	ABVC,
+	"BHI",		LTYPE5,	ABHI,
+	"BLS",		LTYPE5,	ABLS,
+	"BGE",		LTYPE5,	ABGE,
+	"BLT",		LTYPE5,	ABLT,
+	"BGT",		LTYPE5,	ABGT,
+	"BLE",		LTYPE5,	ABLE,
+	"BCASE",	LTYPE5,	ABCASE,
+
+	"SWI",		LTYPE6, ASWI,
+
+	"CMP",		LTYPE7,	ACMP,
+	"TST",		LTYPE7,	ATST,
+	"TEQ",		LTYPE7,	ATEQ,
+	"CMN",		LTYPE7,	ACMN,
+
+	"MOVM",		LTYPE8, AMOVM,
+
+	"SWPBU",	LTYPE9, ASWPBU,
+	"SWPW",		LTYPE9, ASWPW,
+
+	"RET",		LTYPEA, ARET,
+	"RFE",		LTYPEA, ARFE,
+
+	"TEXT",		LTYPEB, ATEXT,
+	"GLOBL",	LTYPEB, AGLOBL,
+	"DATA",		LTYPEC, ADATA,
+	"CASE",		LTYPED, ACASE,
+	"END",		LTYPEE, AEND,
+	"WORD",		LTYPEH, AWORD,
+	"NOP",		LTYPEI, ANOP,
+
+	"MCR",		LTYPEJ, 0,
+	"MRC",		LTYPEJ, 1,
+
+	"PLD",		LTYPEPLD, APLD,
+	"UNDEF",	LTYPEE,	AUNDEF,
+	"CLZ",		LTYPE2, ACLZ,
+
+	"MULWT",	LTYPE1, AMULWT,
+	"MULWB",	LTYPE1, AMULWB,
+	"MULAWT",	LTYPEN, AMULAWT,
+	"MULAWB",	LTYPEN, AMULAWB,
+
+	"USEFIELD",	LTYPEN, AUSEFIELD,
+	"PCDATA",	LTYPEPC,	APCDATA,
+	"FUNCDATA",	LTYPEF,	AFUNCDATA,
+
+	0
+};
+
+void
+cinit(void)
+{
+	Sym *s;
+	int i;
+
+	nullgen.type = D_NONE;
+	nullgen.name = D_NONE;
+	nullgen.reg = NREG;
+
+	nerrors = 0;
+	iostack = I;
+	iofree = I;
+	peekc = IGN;
+	nhunk = 0;
+	for(i=0; i<NHASH; i++)
+		hash[i] = S;
+	for(i=0; itab[i].name; i++) {
+		s = slookup(itab[i].name);
+		s->type = itab[i].type;
+		s->value = itab[i].value;
+	}
+}
+
+void
+syminit(Sym *s)
+{
+
+	s->type = LNAME;
+	s->value = 0;
+}
+
+int
+isreg(Addr *g)
+{
+
+	USED(g);
+	return 1;
+}
+
+void
+cclean(void)
+{
+	outcode(AEND, Always, &nullgen, NREG, &nullgen);
+}
+
+static int bcode[] =
+{
+	ABEQ,
+	ABNE,
+	ABCS,
+	ABCC,
+	ABMI,
+	ABPL,
+	ABVS,
+	ABVC,
+	ABHI,
+	ABLS,
+	ABGE,
+	ABLT,
+	ABGT,
+	ABLE,
+	AB,
+	ANOP,
+};
+
+static Prog *lastpc;
+
+void
+outcode(int a, int scond, Addr *g1, int reg, Addr *g2)
+{
+	Prog *p;
+	Plist *pl;
+
+	/* hack to make B.NE etc. work: turn it into the corresponding conditional */
+	if(a == AB){
+		a = bcode[scond&0xf];
+		scond = (scond & ~0xf) | Always;
+	}
+
+	if(pass == 1)
+		goto out;
+	
+	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++;
+}
+
+#include "../cc/lexbody"
+#include "../cc/macbody"
diff --git a/src/cmd/5a/y.tab.c b/src/cmd/5a/y.tab.c
new file mode 100644
index 0000000..a6251b8
--- /dev/null
+++ b/src/cmd/5a/y.tab.c
@@ -0,0 +1,2936 @@
+/* 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-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
+   the Free Software Foundation, either version 3 of the License, 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/>.  */
+
+/* As a special exception, you may create a larger work that contains
+   part or all of the Bison parser skeleton and distribute that work
+   under terms of your choice, so long as that work isn't itself a
+   parser generator using the skeleton or a modified version thereof
+   as a parser skeleton.  Alternatively, if you modify or redistribute
+   the parser skeleton itself, you may (at your option) remove this
+   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.  */
+
+/* C LALR(1) parser skeleton written by Richard Stallman, by
+   simplifying the original so-called "semantic" parser.  */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+   infringing on user name space.  This should be done even for local
+   variables, as they might otherwise be expanded by user macros.
+   There are some unavoidable exceptions within include files to
+   define necessary library symbols; they are noted "INFRINGES ON
+   USER NAME SPACE" below.  */
+
+/* Identify Bison output.  */
+#define YYBISON 1
+
+/* Bison version.  */
+#define YYBISON_VERSION "2.7.12-4996"
+
+/* Skeleton name.  */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers.  */
+#define YYPURE 0
+
+/* Push parsers.  */
+#define YYPUSH 0
+
+/* Pull parsers.  */
+#define YYPULL 1
+
+
+
+
+/* Copy the first part of user declarations.  */
+/* Line 371 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 "../../runtime/funcdata.h"
+
+/* Line 371 of yacc.c  */
+#line 76 "y.tab.c"
+
+# 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
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+/* 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
+# define YYTOKENTYPE
+   /* Put the tokens into the symbol table, so that GDB and other debuggers
+      know about them.  */
+   enum yytokentype {
+     LTYPE1 = 258,
+     LTYPE2 = 259,
+     LTYPE3 = 260,
+     LTYPE4 = 261,
+     LTYPE5 = 262,
+     LTYPE6 = 263,
+     LTYPE7 = 264,
+     LTYPE8 = 265,
+     LTYPE9 = 266,
+     LTYPEA = 267,
+     LTYPEB = 268,
+     LTYPEC = 269,
+     LTYPED = 270,
+     LTYPEE = 271,
+     LTYPEG = 272,
+     LTYPEH = 273,
+     LTYPEI = 274,
+     LTYPEJ = 275,
+     LTYPEK = 276,
+     LTYPEL = 277,
+     LTYPEM = 278,
+     LTYPEN = 279,
+     LTYPEBX = 280,
+     LTYPEPLD = 281,
+     LCONST = 282,
+     LSP = 283,
+     LSB = 284,
+     LFP = 285,
+     LPC = 286,
+     LTYPEX = 287,
+     LTYPEPC = 288,
+     LTYPEF = 289,
+     LR = 290,
+     LREG = 291,
+     LF = 292,
+     LFREG = 293,
+     LC = 294,
+     LCREG = 295,
+     LPSR = 296,
+     LFCR = 297,
+     LCOND = 298,
+     LS = 299,
+     LAT = 300,
+     LFCONST = 301,
+     LSCONST = 302,
+     LNAME = 303,
+     LLAB = 304,
+     LVAR = 305
+   };
+#endif
+/* Tokens.  */
+#define LTYPE1 258
+#define LTYPE2 259
+#define LTYPE3 260
+#define LTYPE4 261
+#define LTYPE5 262
+#define LTYPE6 263
+#define LTYPE7 264
+#define LTYPE8 265
+#define LTYPE9 266
+#define LTYPEA 267
+#define LTYPEB 268
+#define LTYPEC 269
+#define LTYPED 270
+#define LTYPEE 271
+#define LTYPEG 272
+#define LTYPEH 273
+#define LTYPEI 274
+#define LTYPEJ 275
+#define LTYPEK 276
+#define LTYPEL 277
+#define LTYPEM 278
+#define LTYPEN 279
+#define LTYPEBX 280
+#define LTYPEPLD 281
+#define LCONST 282
+#define LSP 283
+#define LSB 284
+#define LFP 285
+#define LPC 286
+#define LTYPEX 287
+#define LTYPEPC 288
+#define LTYPEF 289
+#define LR 290
+#define LREG 291
+#define LF 292
+#define LFREG 293
+#define LC 294
+#define LCREG 295
+#define LPSR 296
+#define LFCR 297
+#define LCOND 298
+#define LS 299
+#define LAT 300
+#define LFCONST 301
+#define LSCONST 302
+#define LNAME 303
+#define LLAB 304
+#define LVAR 305
+
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+{
+/* Line 387 of yacc.c  */
+#line 39 "a.y"
+
+	Sym	*sym;
+	int32	lval;
+	double	dval;
+	char	sval[8];
+	Addr	addr;
+
+
+/* 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;
+
+#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 390 of yacc.c  */
+#line 256 "y.tab.c"
+
+#ifdef short
+# undef short
+#endif
+
+#ifdef YYTYPE_UINT8
+typedef YYTYPE_UINT8 yytype_uint8;
+#else
+typedef unsigned char yytype_uint8;
+#endif
+
+#ifdef YYTYPE_INT8
+typedef YYTYPE_INT8 yytype_int8;
+#elif (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+typedef signed char yytype_int8;
+#else
+typedef short int yytype_int8;
+#endif
+
+#ifdef YYTYPE_UINT16
+typedef YYTYPE_UINT16 yytype_uint16;
+#else
+typedef unsigned short int yytype_uint16;
+#endif
+
+#ifdef YYTYPE_INT16
+typedef YYTYPE_INT16 yytype_int16;
+#else
+typedef short int yytype_int16;
+#endif
+
+#ifndef YYSIZE_T
+# ifdef __SIZE_TYPE__
+#  define YYSIZE_T __SIZE_TYPE__
+# elif defined size_t
+#  define YYSIZE_T size_t
+# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+#  include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+#  define YYSIZE_T size_t
+# else
+#  define YYSIZE_T unsigned int
+# endif
+#endif
+
+#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
+
+#ifndef YY_
+# if defined YYENABLE_NLS && YYENABLE_NLS
+#  if ENABLE_NLS
+#   include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+#   define YY_(Msgid) dgettext ("bison-runtime", Msgid)
+#  endif
+# endif
+# ifndef YY_
+#  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))
+#else
+# define YYUSE(E) /* empty */
+#endif
+
+
+/* Identity function, used to suppress warnings about constant conditions.  */
+#ifndef lint
+# define YYID(N) (N)
+#else
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static int
+YYID (int yyi)
+#else
+static int
+YYID (yyi)
+    int yyi;
+#endif
+{
+  return yyi;
+}
+#endif
+
+#if ! defined yyoverflow || YYERROR_VERBOSE
+
+/* The parser invokes alloca or malloc; define the necessary symbols.  */
+
+# ifdef YYSTACK_USE_ALLOCA
+#  if YYSTACK_USE_ALLOCA
+#   ifdef __GNUC__
+#    define YYSTACK_ALLOC __builtin_alloca
+#   elif defined __BUILTIN_VA_ARG_INCR
+#    include <alloca.h> /* INFRINGES ON USER NAME SPACE */
+#   elif defined _AIX
+#    define YYSTACK_ALLOC __alloca
+#   elif defined _MSC_VER
+#    include <malloc.h> /* INFRINGES ON USER NAME SPACE */
+#    define alloca _alloca
+#   else
+#    define YYSTACK_ALLOC alloca
+#    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
+#    endif
+#   endif
+#  endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+   /* Pacify GCC's `empty if-body' warning.  */
+#  define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
+#  ifndef YYSTACK_ALLOC_MAXIMUM
+    /* The OS might guarantee only one guard page at the bottom of the stack,
+       and a page size can be as small as 4096 bytes.  So we cannot safely
+       invoke alloca (N) if N exceeds 4096.  Use a slightly smaller number
+       to allow for a few compiler-allocated temporary stack slots.  */
+#   define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
+#  endif
+# else
+#  define YYSTACK_ALLOC YYMALLOC
+#  define YYSTACK_FREE YYFREE
+#  ifndef YYSTACK_ALLOC_MAXIMUM
+#   define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
+#  endif
+#  if (defined __cplusplus && ! defined EXIT_SUCCESS \
+       && ! ((defined YYMALLOC || defined malloc) \
+	     && (defined YYFREE || defined free)))
+#   include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+#   ifndef EXIT_SUCCESS
+#    define EXIT_SUCCESS 0
+#   endif
+#  endif
+#  ifndef YYMALLOC
+#   define YYMALLOC malloc
+#   if ! defined malloc && ! defined EXIT_SUCCESS && (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__ \
+     || defined __cplusplus || defined _MSC_VER)
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+#   endif
+#  endif
+# endif
+#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
+
+
+#if (! defined yyoverflow \
+     && (! defined __cplusplus \
+	 || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member.  */
+union yyalloc
+{
+  yytype_int16 yyss_alloc;
+  YYSTYPE yyvs_alloc;
+};
+
+/* The size of the maximum gap between one aligned stack and the next.  */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+   N elements.  */
+# define YYSTACK_BYTES(N) \
+     ((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 SRC to DST.  The source and destination do
+   not overlap.  */
+# ifndef YYCOPY
+#  if defined __GNUC__ && 1 < __GNUC__
+#   define YYCOPY(Dst, Src, Count) \
+      __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src)))
+#  else
+#   define YYCOPY(Dst, Src, Count)              \
+      do                                        \
+        {                                       \
+          YYSIZE_T yyi;                         \
+          for (yyi = 0; yyi < (Count); yyi++)   \
+            (Dst)[yyi] = (Src)[yyi];            \
+        }                                       \
+      while (YYID (0))
+#  endif
+# endif
+#endif /* !YYCOPY_NEEDED */
+
+/* YYFINAL -- State number of the termination state.  */
+#define YYFINAL  2
+/* YYLAST -- Last index in YYTABLE.  */
+#define YYLAST   609
+
+/* YYNTOKENS -- Number of terminals.  */
+#define YYNTOKENS  71
+/* YYNNTS -- Number of nonterminals.  */
+#define YYNNTS  35
+/* YYNRULES -- Number of rules.  */
+#define YYNRULES  133
+/* YYNRULES -- Number of states.  */
+#define YYNSTATES  339
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX.  */
+#define YYUNDEFTOK  2
+#define YYMAXUTOK   305
+
+#define YYTRANSLATE(YYX)						\
+  ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX.  */
+static const yytype_uint8 yytranslate[] =
+{
+       0,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,    69,    12,     5,     2,
+      67,    68,    10,     8,    64,     9,     2,    11,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,    61,    63,
+       6,    62,     7,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,    65,     2,    66,     4,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     3,     2,    70,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     1,     2,    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
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+   YYRHS.  */
+static const yytype_uint16 yyprhs[] =
+{
+       0,     0,     3,     4,     5,     9,    10,    15,    16,    21,
+      26,    31,    33,    36,    39,    47,    54,    60,    66,    72,
+      77,    82,    86,    90,    95,   102,   110,   118,   126,   133,
+     140,   144,   149,   156,   165,   172,   177,   181,   187,   193,
+     201,   208,   221,   229,   239,   242,   247,   252,   255,   256,
+     259,   262,   263,   266,   271,   274,   277,   280,   283,   288,
+     291,   293,   296,   300,   302,   306,   310,   312,   314,   316,
+     321,   323,   325,   327,   329,   331,   333,   335,   339,   341,
+     346,   348,   353,   355,   357,   359,   361,   364,   366,   372,
+     377,   382,   387,   392,   394,   396,   398,   400,   405,   407,
+     409,   411,   416,   418,   420,   422,   427,   432,   438,   446,
+     447,   450,   453,   455,   457,   459,   461,   463,   466,   469,
+     472,   476,   477,   480,   482,   486,   490,   494,   498,   502,
+     507,   512,   516,   520
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS.  */
+static const yytype_int8 yyrhs[] =
+{
+      72,     0,    -1,    -1,    -1,    72,    73,    74,    -1,    -1,
+      59,    61,    75,    74,    -1,    -1,    58,    61,    76,    74,
+      -1,    58,    62,   105,    63,    -1,    60,    62,   105,    63,
+      -1,    63,    -1,    77,    63,    -1,     1,    63,    -1,    13,
+      78,    89,    64,    96,    64,    91,    -1,    13,    78,    89,
+      64,    96,    64,    -1,    13,    78,    89,    64,    91,    -1,
+      14,    78,    89,    64,    91,    -1,    15,    78,    84,    64,
+      84,    -1,    16,    78,    79,    80,    -1,    16,    78,    79,
+      85,    -1,    35,    79,    86,    -1,    17,    79,    80,    -1,
+      18,    78,    79,    84,    -1,    19,    78,    89,    64,    96,
+      79,    -1,    20,    78,    87,    64,    65,    83,    66,    -1,
+      20,    78,    65,    83,    66,    64,    87,    -1,    21,    78,
+      91,    64,    86,    64,    91,    -1,    21,    78,    91,    64,
+      86,    79,    -1,    21,    78,    79,    86,    64,    91,    -1,
+      22,    78,    79,    -1,    23,   100,    64,    90,    -1,    23,
+     100,    64,   103,    64,    90,    -1,    23,   100,    64,   103,
+      64,    90,     9,   103,    -1,    24,   100,    11,   103,    64,
+      81,    -1,    25,    78,    91,    79,    -1,    28,    79,    81,
+      -1,    29,    78,    99,    64,    99,    -1,    31,    78,    98,
+      64,    99,    -1,    31,    78,    98,    64,    48,    64,    99,
+      -1,    32,    78,    99,    64,    99,    79,    -1,    30,    78,
+     103,    64,   105,    64,    96,    64,    97,    64,    97,   104,
+      -1,    33,    78,    91,    64,    91,    64,    92,    -1,    34,
+      78,    91,    64,    91,    64,    91,    64,    96,    -1,    36,
+      88,    -1,    43,    84,    64,    84,    -1,    44,    84,    64,
+      84,    -1,    26,    79,    -1,    -1,    78,    53,    -1,    78,
+      54,    -1,    -1,    64,    79,    -1,   103,    67,    41,    68,
+      -1,    58,   101,    -1,    59,   101,    -1,    69,   103,    -1,
+      69,    88,    -1,    69,    10,    69,    88,    -1,    69,    57,
+      -1,    82,    -1,    69,    56,    -1,    69,     9,    56,    -1,
+      96,    -1,    96,     9,    96,    -1,    96,    79,    83,    -1,
+      91,    -1,    81,    -1,    93,    -1,    93,    67,    96,    68,
+      -1,    51,    -1,    52,    -1,   103,    -1,    88,    -1,    99,
+      -1,    86,    -1,   100,    -1,    67,    96,    68,    -1,    86,
+      -1,   103,    67,    95,    68,    -1,   100,    -1,   100,    67,
+      95,    68,    -1,    87,    -1,    91,    -1,    90,    -1,    93,
+      -1,    69,   103,    -1,    96,    -1,    67,    96,    64,    96,
+      68,    -1,    96,     6,     6,    94,    -1,    96,     7,     7,
+      94,    -1,    96,     9,     7,    94,    -1,    96,    55,     7,
+      94,    -1,    96,    -1,   103,    -1,    46,    -1,    41,    -1,
+      45,    67,   105,    68,    -1,    95,    -1,    38,    -1,    50,
+      -1,    49,    67,   105,    68,    -1,    99,    -1,    82,    -1,
+      48,    -1,    47,    67,   103,    68,    -1,   103,    67,   102,
+      68,    -1,    58,   101,    67,   102,    68,    -1,    58,     6,
+       7,   101,    67,    39,    68,    -1,    -1,     8,   103,    -1,
+       9,   103,    -1,    39,    -1,    38,    -1,    40,    -1,    37,
+      -1,    60,    -1,     9,   103,    -1,     8,   103,    -1,    70,
+     103,    -1,    67,   105,    68,    -1,    -1,    64,   105,    -1,
+     103,    -1,   105,     8,   105,    -1,   105,     9,   105,    -1,
+     105,    10,   105,    -1,   105,    11,   105,    -1,   105,    12,
+     105,    -1,   105,     6,     6,   105,    -1,   105,     7,     7,
+     105,    -1,   105,     5,   105,    -1,   105,     4,   105,    -1,
+     105,     3,   105,    -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
+static const yytype_uint16 yyrline[] =
+{
+       0,    68,    68,    70,    69,    77,    76,    84,    83,    89,
+      94,   100,   101,   102,   108,   112,   116,   123,   130,   137,
+     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,   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 || 0
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+   First, the terminals, then, starting at YYNTOKENS, nonterminals.  */
+static const char *const yytname[] =
+{
+  "$end", "error", "$undefined", "'|'", "'^'", "'&'", "'<'", "'>'", "'+'",
+  "'-'", "'*'", "'/'", "'%'", "LTYPE1", "LTYPE2", "LTYPE3", "LTYPE4",
+  "LTYPE5", "LTYPE6", "LTYPE7", "LTYPE8", "LTYPE9", "LTYPEA", "LTYPEB",
+  "LTYPEC", "LTYPED", "LTYPEE", "LTYPEG", "LTYPEH", "LTYPEI", "LTYPEJ",
+  "LTYPEK", "LTYPEL", "LTYPEM", "LTYPEN", "LTYPEBX", "LTYPEPLD", "LCONST",
+  "LSP", "LSB", "LFP", "LPC", "LTYPEX", "LTYPEPC", "LTYPEF", "LR", "LREG",
+  "LF", "LFREG", "LC", "LCREG", "LPSR", "LFCR", "LCOND", "LS", "LAT",
+  "LFCONST", "LSCONST", "LNAME", "LLAB", "LVAR", "':'", "'='", "';'",
+  "','", "'['", "']'", "'('", "')'", "'$'", "'~'", "$accept", "prog",
+  "$@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", YY_NULL
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+   token YYLEX-NUM.  */
+static const yytype_uint16 yytoknum[] =
+{
+       0,   256,   257,   124,    94,    38,    60,    62,    43,    45,
+      42,    47,    37,   258,   259,   260,   261,   262,   263,   264,
+     265,   266,   267,   268,   269,   270,   271,   272,   273,   274,
+     275,   276,   277,   278,   279,   280,   281,   282,   283,   284,
+     285,   286,   287,   288,   289,   290,   291,   292,   293,   294,
+     295,   296,   297,   298,   299,   300,   301,   302,   303,   304,
+     305,    58,    61,    59,    44,    91,    93,    40,    41,    36,
+     126
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
+static const yytype_uint8 yyr1[] =
+{
+       0,    71,    72,    73,    72,    75,    74,    76,    74,    74,
+      74,    74,    74,    74,    77,    77,    77,    77,    77,    77,
+      77,    77,    77,    77,    77,    77,    77,    77,    77,    77,
+      77,    77,    77,    77,    77,    77,    77,    77,    77,    77,
+      77,    77,    77,    77,    77,    77,    77,    77,    78,    78,
+      78,    79,    79,    80,    80,    80,    81,    81,    81,    81,
+      81,    82,    82,    83,    83,    83,    84,    84,    84,    84,
+      84,    84,    84,    84,    84,    85,    85,    86,    87,    87,
+      88,    88,    88,    89,    89,    89,    90,    91,    92,    93,
+      93,    93,    93,    94,    94,    95,    95,    95,    96,    96,
+      97,    97,    98,    98,    99,    99,   100,   100,   100,   101,
+     101,   101,   102,   102,   102,   103,   103,   103,   103,   103,
+     103,   104,   104,   105,   105,   105,   105,   105,   105,   105,
+     105,   105,   105,   105
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN.  */
+static const yytype_uint8 yyr2[] =
+{
+       0,     2,     0,     0,     3,     0,     4,     0,     4,     4,
+       4,     1,     2,     2,     7,     6,     5,     5,     5,     4,
+       4,     3,     3,     4,     6,     7,     7,     7,     6,     6,
+       3,     4,     6,     8,     6,     4,     3,     5,     5,     7,
+       6,    12,     7,     9,     2,     4,     4,     2,     0,     2,
+       2,     0,     2,     4,     2,     2,     2,     2,     4,     2,
+       1,     2,     3,     1,     3,     3,     1,     1,     1,     4,
+       1,     1,     1,     1,     1,     1,     1,     3,     1,     4,
+       1,     4,     1,     1,     1,     1,     2,     1,     5,     4,
+       4,     4,     4,     1,     1,     1,     1,     4,     1,     1,
+       1,     4,     1,     1,     1,     4,     4,     5,     7,     0,
+       2,     2,     1,     1,     1,     1,     1,     2,     2,     2,
+       3,     0,     2,     1,     3,     3,     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
+   means the default is an error.  */
+static const yytype_uint8 yydefact[] =
+{
+       2,     3,     1,     0,     0,    48,    48,    48,    48,    51,
+      48,    48,    48,    48,    48,     0,     0,    48,    51,    51,
+      48,    48,    48,    48,    48,    48,    51,     0,     0,     0,
+       0,     0,     0,    11,     4,     0,    13,     0,     0,     0,
+      51,    51,     0,    51,     0,     0,    51,    51,     0,     0,
+     115,   109,   116,     0,     0,     0,     0,     0,     0,    47,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,    78,
+      82,    44,    80,     0,    99,    96,     0,    95,     0,   104,
+      70,    71,     0,    67,    60,     0,    73,    66,    68,    98,
+      87,    74,    72,     0,     7,     0,     5,     0,    12,    49,
+      50,     0,     0,    84,    83,    85,     0,     0,     0,    52,
+     109,   109,    22,     0,     0,     0,     0,     0,     0,     0,
+       0,    87,    30,   118,   117,     0,     0,     0,     0,   123,
+       0,   119,     0,     0,     0,    51,    36,     0,     0,     0,
+     103,     0,   102,     0,     0,     0,     0,    21,     0,     0,
+       0,     0,     0,     0,     0,    61,    59,    57,    56,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+      86,     0,     0,     0,   109,    19,    20,    75,    76,     0,
+      54,    55,     0,    23,     0,     0,    51,     0,     0,     0,
+       0,   109,   110,   111,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,   120,    31,     0,   113,   112,
+     114,     0,     0,    35,     0,     0,     0,     0,     0,     0,
+       0,    77,     0,     0,     0,     0,    62,     0,    45,     0,
+       0,     0,     0,     0,    46,     8,     9,     6,    10,    16,
+      87,    17,    18,    54,     0,     0,    51,     0,     0,     0,
+       0,     0,    51,     0,     0,   133,   132,   131,     0,     0,
+     124,   125,   126,   127,   128,     0,   106,     0,    37,     0,
+     104,    38,    51,     0,     0,    81,    79,    97,   105,    58,
+      69,    89,    93,    94,    90,    91,    92,    15,    53,    24,
+       0,    64,    65,     0,    29,    51,    28,     0,   107,   129,
+     130,    32,    34,     0,     0,    40,     0,     0,    14,    26,
+      25,    27,     0,     0,     0,    39,     0,    42,     0,   108,
+      33,     0,     0,     0,     0,   100,     0,     0,    43,     0,
+       0,     0,     0,   121,    88,   101,     0,    41,   122
+};
+
+/* YYDEFGOTO[NTERM-NUM].  */
+static const yytype_int16 yydefgoto[] =
+{
+      -1,     1,     3,    34,   168,   166,    35,    37,   109,   112,
+      83,    84,   185,    85,   176,    69,    70,    86,   102,   103,
+      87,   317,    88,   281,    89,   121,   326,   141,    91,    72,
+     128,   211,   129,   337,   130
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+   STATE-NUM.  */
+#define YYPACT_NINF -128
+static const yytype_int16 yypact[] =
+{
+    -128,     4,  -128,   315,   -35,  -128,  -128,  -128,  -128,   -10,
+    -128,  -128,  -128,  -128,  -128,    44,    44,  -128,   -10,   -10,
+    -128,  -128,  -128,  -128,  -128,  -128,   -10,   416,   371,   371,
+     -49,     9,    32,  -128,  -128,    38,  -128,   487,   487,   344,
+      69,   -10,   391,    69,   487,   209,   489,    69,   317,   317,
+    -128,    49,  -128,   317,   317,    42,    48,   106,    67,  -128,
+      61,   191,    25,    93,   191,    67,    67,    68,   170,  -128,
+    -128,  -128,    72,    84,  -128,  -128,    86,  -128,   109,  -128,
+    -128,  -128,   233,  -128,  -128,    80,  -128,  -128,   115,  -128,
+     426,  -128,    84,   120,  -128,   317,  -128,   317,  -128,  -128,
+    -128,   317,   137,  -128,  -128,  -128,   148,   155,   397,  -128,
+      74,    74,  -128,   164,   371,   204,   240,   207,   206,    68,
+     223,  -128,  -128,  -128,  -128,   270,   317,   317,   227,  -128,
+     183,  -128,    90,   160,   317,   -10,  -128,   234,   237,    16,
+    -128,   254,  -128,   255,   256,   257,   240,  -128,   212,   168,
+     548,   317,   317,   428,   258,  -128,  -128,  -128,    84,   371,
+     240,   318,   316,   335,   348,   371,   315,   502,   315,   512,
+    -128,   240,   240,   371,    49,  -128,  -128,  -128,  -128,   289,
+    -128,  -128,   330,  -128,   240,   291,    11,   307,   168,   312,
+      68,    74,  -128,  -128,   160,   317,   317,   317,   377,   379,
+     317,   317,   317,   317,   317,  -128,  -128,   324,  -128,  -128,
+    -128,   325,   337,  -128,    77,   317,   338,   126,    77,   240,
+     240,  -128,   339,   342,   249,   347,  -128,   416,  -128,   352,
+     170,   170,   170,   170,  -128,  -128,  -128,  -128,  -128,  -128,
+     362,  -128,  -128,   227,    -2,   359,   -10,   366,   240,   240,
+     240,   240,   375,   336,   384,   562,   590,   597,   317,   317,
+     213,   213,  -128,  -128,  -128,   385,  -128,    61,  -128,   357,
+     395,  -128,   -10,   396,   398,  -128,  -128,  -128,  -128,  -128,
+    -128,  -128,  -128,  -128,  -128,  -128,  -128,   240,  -128,  -128,
+     434,  -128,  -128,   400,  -128,   432,  -128,   424,  -128,   436,
+     436,   459,  -128,   240,    77,  -128,   402,   240,  -128,  -128,
+    -128,  -128,   404,   317,   411,  -128,   240,  -128,   415,  -128,
+    -128,   216,   418,   240,   413,  -128,   421,   240,  -128,   317,
+     216,   419,   302,   425,  -128,  -128,   317,  -128,   573
+};
+
+/* YYPGOTO[NTERM-NUM].  */
+static const yytype_int16 yypgoto[] =
+{
+    -128,  -128,  -128,   -77,  -128,  -128,  -128,   538,    50,   382,
+     -57,   429,    33,    -7,  -128,   -48,   -43,   -21,    36,  -127,
+     -23,  -128,    29,    17,  -101,   -28,   161,  -128,   -37,    -8,
+     -65,   299,     2,  -128,   -32
+};
+
+/* 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.  */
+#define YYTABLE_NINF -64
+static const yytype_int16 yytable[] =
+{
+      90,    90,   117,   136,     2,   206,    71,    55,    57,    90,
+      90,    90,    94,    95,   104,   104,    90,    56,    56,   147,
+     248,   104,    93,   120,   137,   216,   142,   143,    36,    73,
+      92,    92,   107,    48,    49,   135,   208,   209,   210,   245,
+     148,    92,   144,   145,   113,   180,   181,   118,   222,   223,
+     123,   124,    48,    49,    41,   125,   131,   126,   127,    42,
+     177,   157,    50,   167,   138,   169,   105,   105,    59,    60,
+      96,   189,   155,   105,   106,    41,    67,   -63,    99,   100,
+     115,    50,   126,   127,   158,    52,    90,   223,   186,   235,
+     108,   237,    53,   114,    97,    54,   119,   122,    48,    49,
+     178,    98,    51,   170,    52,    74,   132,   183,    75,   243,
+     179,    53,    76,    77,    54,   133,    92,   134,   148,   224,
+      99,   100,    99,   100,    78,    79,   253,    50,   192,   193,
+      82,    90,   229,    41,   207,   146,   212,    90,   301,   149,
+      78,    79,   252,   240,   159,    90,    99,   100,   239,   241,
+      52,   150,   228,   151,   225,   124,   246,    53,   234,   101,
+      54,    92,   139,   255,   256,   257,   242,    92,   260,   261,
+     262,   263,   264,    78,   270,    92,   152,   268,    48,    49,
+     271,   272,   160,   269,   165,   213,   195,   196,   197,   198,
+     199,   200,   201,   202,   203,   204,   273,   274,   208,   209,
+     210,   171,   282,   282,   282,   282,   279,    50,    74,    75,
+     302,    75,   172,    76,    77,    76,    77,    48,    49,   173,
+     291,   186,   186,   202,   203,   204,   299,   300,   294,    73,
+      52,   182,   283,   283,   283,   283,   249,    53,    78,    79,
+      54,    48,   153,   154,    99,   100,    50,   309,   284,   285,
+     286,   205,   195,   196,   197,   198,   199,   200,   201,   202,
+     203,   204,    99,   100,   308,   324,   325,   315,   184,    52,
+      50,   187,   311,   188,   116,   314,    68,   191,    74,    54,
+     221,    75,   292,   293,   318,    76,    77,   190,   322,   155,
+     156,    51,   118,    52,   194,   328,   289,   332,   214,   331,
+      68,   215,   296,    54,   338,   195,   196,   197,   198,   199,
+     200,   201,   202,   203,   204,   320,     4,   277,   217,   218,
+     219,   220,   305,   231,   230,    48,    49,   227,     5,     6,
+       7,     8,     9,    10,    11,    12,    13,    14,    15,    16,
+      17,    18,   232,    19,    20,    21,    22,    23,    24,    25,
+      26,    27,    48,    49,    50,   233,   244,   247,    28,    29,
+     195,   196,   197,   198,   199,   200,   201,   202,   203,   204,
+     335,   245,   250,    30,    31,    32,   251,    52,    33,    48,
+      49,    50,    74,   258,    53,    75,   259,    54,   265,    76,
+      77,    78,    79,   266,   226,    80,    81,    99,   100,    48,
+      49,   267,    51,   297,    52,    48,    49,   275,    50,    74,
+     276,    68,    75,    82,    54,   278,    76,    77,    78,    79,
+     280,   303,    80,    81,    48,    49,   287,   288,    50,    51,
+     290,    52,   161,   162,    50,   163,    48,    49,    68,   295,
+      82,    54,    48,    49,   200,   201,   202,   203,   204,   110,
+     111,    52,   298,    50,   101,   174,   111,    52,    53,   304,
+     306,    54,   307,   312,    68,    50,   310,    54,   313,   316,
+      74,    50,   319,    75,    51,   321,    52,    76,    77,   323,
+     329,   164,   327,    68,   226,   330,    54,   334,    52,   336,
+     175,   333,   140,   254,    52,    53,    41,     0,    54,     0,
+       0,    68,     0,     0,    54,   195,   196,   197,   198,   199,
+     200,   201,   202,   203,   204,   195,   196,   197,   198,   199,
+     200,   201,   202,   203,   204,    74,     0,    74,    75,     0,
+      75,     0,    76,    77,    76,    77,     0,     0,     0,     0,
+      99,   100,    99,   100,    38,    39,    40,     0,    43,    44,
+      45,    46,    47,    41,     0,    58,   101,     0,    61,    62,
+      63,    64,    65,    66,     0,   236,   196,   197,   198,   199,
+     200,   201,   202,   203,   204,   238,   195,   196,   197,   198,
+     199,   200,   201,   202,   203,   204,   208,   209,   210,    75,
+       0,     0,     0,    76,    77,   197,   198,   199,   200,   201,
+     202,   203,   204,   198,   199,   200,   201,   202,   203,   204
+};
+
+#define yypact_value_is_default(Yystate) \
+  (!!((Yystate) == (-128)))
+
+#define yytable_value_is_error(Yytable_value) \
+  YYID (0)
+
+static const yytype_int16 yycheck[] =
+{
+      28,    29,    45,    60,     0,   132,    27,    15,    16,    37,
+      38,    39,    61,    62,    37,    38,    44,    15,    16,    67,
+       9,    44,    29,    46,    61,     9,    63,    64,    63,    27,
+      28,    29,    39,     8,     9,    58,    38,    39,    40,    41,
+      68,    39,    65,    66,    42,   110,   111,    45,   149,   150,
+      48,    49,     8,     9,    64,     6,    54,     8,     9,     9,
+     108,    82,    37,    95,    62,    97,    37,    38,    18,    19,
+      61,   119,    56,    44,    38,    64,    26,    66,    53,    54,
+      44,    37,     8,     9,    82,    60,   114,   188,   116,   166,
+      40,   168,    67,    43,    62,    70,    46,    47,     8,     9,
+     108,    63,    58,   101,    60,    38,    64,   114,    41,   174,
+     108,    67,    45,    46,    70,    67,   114,    11,   146,   151,
+      53,    54,    53,    54,    47,    48,   191,    37,   126,   127,
+      69,   159,   160,    64,   132,    67,   134,   165,   265,    67,
+      47,    48,   190,   171,    64,   173,    53,    54,   171,   172,
+      60,    67,   159,    67,   152,   153,   184,    67,   165,    69,
+      70,   159,    69,   195,   196,   197,   173,   165,   200,   201,
+     202,   203,   204,    47,    48,   173,    67,   214,     8,     9,
+     217,   218,    67,   215,    64,   135,     3,     4,     5,     6,
+       7,     8,     9,    10,    11,    12,   219,   220,    38,    39,
+      40,    64,   230,   231,   232,   233,   227,    37,    38,    41,
+     267,    41,    64,    45,    46,    45,    46,     8,     9,    64,
+     248,   249,   250,    10,    11,    12,   258,   259,   251,   227,
+      60,    67,   230,   231,   232,   233,   186,    67,    47,    48,
+      70,     8,     9,    10,    53,    54,    37,   290,   231,   232,
+     233,    68,     3,     4,     5,     6,     7,     8,     9,    10,
+      11,    12,    53,    54,   287,    49,    50,   304,    64,    60,
+      37,    64,   295,    67,    65,   303,    67,     7,    38,    70,
+      68,    41,   249,   250,   307,    45,    46,    64,   316,    56,
+      57,    58,   290,    60,    67,   323,   246,   329,    64,   327,
+      67,    64,   252,    70,   336,     3,     4,     5,     6,     7,
+       8,     9,    10,    11,    12,   313,     1,    68,    64,    64,
+      64,    64,   272,     7,     6,     8,     9,    69,    13,    14,
+      15,    16,    17,    18,    19,    20,    21,    22,    23,    24,
+      25,    26,     7,    28,    29,    30,    31,    32,    33,    34,
+      35,    36,     8,     9,    37,     7,    67,    66,    43,    44,
+       3,     4,     5,     6,     7,     8,     9,    10,    11,    12,
+      68,    41,    65,    58,    59,    60,    64,    60,    63,     8,
+       9,    37,    38,     6,    67,    41,     7,    70,    64,    45,
+      46,    47,    48,    68,    56,    51,    52,    53,    54,     8,
+       9,    64,    58,    67,    60,     8,     9,    68,    37,    38,
+      68,    67,    41,    69,    70,    68,    45,    46,    47,    48,
+      68,    64,    51,    52,     8,     9,    64,    68,    37,    58,
+      64,    60,     6,     7,    37,     9,     8,     9,    67,    64,
+      69,    70,     8,     9,     8,     9,    10,    11,    12,    58,
+      59,    60,    68,    37,    69,    58,    59,    60,    67,    64,
+      64,    70,    64,    39,    67,    37,    66,    70,     9,    67,
+      38,    37,    68,    41,    58,    64,    60,    45,    46,    64,
+      67,    55,    64,    67,    56,    64,    70,    68,    60,    64,
+     108,   330,    63,   194,    60,    67,    64,    -1,    70,    -1,
+      -1,    67,    -1,    -1,    70,     3,     4,     5,     6,     7,
+       8,     9,    10,    11,    12,     3,     4,     5,     6,     7,
+       8,     9,    10,    11,    12,    38,    -1,    38,    41,    -1,
+      41,    -1,    45,    46,    45,    46,    -1,    -1,    -1,    -1,
+      53,    54,    53,    54,     6,     7,     8,    -1,    10,    11,
+      12,    13,    14,    64,    -1,    17,    69,    -1,    20,    21,
+      22,    23,    24,    25,    -1,    63,     4,     5,     6,     7,
+       8,     9,    10,    11,    12,    63,     3,     4,     5,     6,
+       7,     8,     9,    10,    11,    12,    38,    39,    40,    41,
+      -1,    -1,    -1,    45,    46,     5,     6,     7,     8,     9,
+      10,    11,    12,     6,     7,     8,     9,    10,    11,    12
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+   symbol of state STATE-NUM.  */
+static const yytype_uint8 yystos[] =
+{
+       0,    72,     0,    73,     1,    13,    14,    15,    16,    17,
+      18,    19,    20,    21,    22,    23,    24,    25,    26,    28,
+      29,    30,    31,    32,    33,    34,    35,    36,    43,    44,
+      58,    59,    60,    63,    74,    77,    63,    78,    78,    78,
+      78,    64,    79,    78,    78,    78,    78,    78,     8,     9,
+      37,    58,    60,    67,    70,   100,   103,   100,    78,    79,
+      79,    78,    78,    78,    78,    78,    78,    79,    67,    86,
+      87,    88,   100,   103,    38,    41,    45,    46,    47,    48,
+      51,    52,    69,    81,    82,    84,    88,    91,    93,    95,
+      96,    99,   103,    84,    61,    62,    61,    62,    63,    53,
+      54,    69,    89,    90,    91,    93,    89,    84,    79,    79,
+      58,    59,    80,   103,    79,    89,    65,    87,   103,    79,
+      91,    96,    79,   103,   103,     6,     8,     9,   101,   103,
+     105,   103,    64,    67,    11,    91,    81,    99,   103,    69,
+      82,    98,    99,    99,    91,    91,    67,    86,    96,    67,
+      67,    67,    67,     9,    10,    56,    57,    88,   103,    64,
+      67,     6,     7,     9,    55,    64,    76,   105,    75,   105,
+     103,    64,    64,    64,    58,    80,    85,    86,   100,   103,
+     101,   101,    67,    84,    64,    83,    96,    64,    67,    86,
+      64,     7,   103,   103,    67,     3,     4,     5,     6,     7,
+       8,     9,    10,    11,    12,    68,    90,   103,    38,    39,
+      40,   102,   103,    79,    64,    64,     9,    64,    64,    64,
+      64,    68,    95,    95,   105,   103,    56,    69,    84,    96,
+       6,     7,     7,     7,    84,    74,    63,    74,    63,    91,
+      96,    91,    84,   101,    67,    41,    96,    66,     9,    79,
+      65,    64,    86,   101,   102,   105,   105,   105,     6,     7,
+     105,   105,   105,   105,   105,    64,    68,    64,    99,   105,
+      48,    99,    99,    91,    91,    68,    68,    68,    68,    88,
+      68,    94,    96,   103,    94,    94,    94,    64,    68,    79,
+      64,    96,    83,    83,    91,    64,    79,    67,    68,   105,
+     105,    90,    81,    64,    64,    79,    64,    64,    91,    87,
+      66,    91,    39,     9,    96,    99,    67,    92,    91,    68,
+     103,    64,    96,    64,    49,    50,    97,    64,    96,    67,
+      64,    96,   105,    97,    68,    68,    64,   104,   105
+};
+
+#define yyerrok		(yyerrstatus = 0)
+#define yyclearin	(yychar = YYEMPTY)
+#define YYEMPTY		(-2)
+#define YYEOF		0
+
+#define YYACCEPT	goto yyacceptlab
+#define YYABORT		goto yyabortlab
+#define YYERROR		goto yyerrorlab
+
+
+/* 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.  */
+
+#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)
+
+#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
+
+
+/* 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
+# define YYLEX yylex ()
+#endif
+
+/* Enable debugging if requested.  */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+#  include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+#  define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args)			\
+do {						\
+  if (yydebug)					\
+    YYFPRINTF Args;				\
+} while (YYID (0))
+
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)			  \
+do {									  \
+  if (yydebug)								  \
+    {									  \
+      YYFPRINTF (stderr, "%s ", Title);					  \
+      yy_symbol_print (stderr,						  \
+		  Type, Value); \
+      YYFPRINTF (stderr, "\n");						  \
+    }									  \
+} while (YYID (0))
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT.  |
+`--------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_value_print (yyoutput, yytype, yyvaluep)
+    FILE *yyoutput;
+    int yytype;
+    YYSTYPE const * const yyvaluep;
+#endif
+{
+  FILE *yyo = yyoutput;
+  YYUSE (yyo);
+  if (!yyvaluep)
+    return;
+# ifdef YYPRINT
+  if (yytype < YYNTOKENS)
+    YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# else
+  YYUSE (yyoutput);
+# endif
+  YYUSE (yytype);
+}
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT.  |
+`--------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_print (yyoutput, yytype, yyvaluep)
+    FILE *yyoutput;
+    int yytype;
+    YYSTYPE const * const yyvaluep;
+#endif
+{
+  if (yytype < YYNTOKENS)
+    YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+  else
+    YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+  yy_symbol_value_print (yyoutput, yytype, yyvaluep);
+  YYFPRINTF (yyoutput, ")");
+}
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included).                                                   |
+`------------------------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop)
+#else
+static void
+yy_stack_print (yybottom, yytop)
+    yytype_int16 *yybottom;
+    yytype_int16 *yytop;
+#endif
+{
+  YYFPRINTF (stderr, "Stack now");
+  for (; yybottom <= yytop; yybottom++)
+    {
+      int yybot = *yybottom;
+      YYFPRINTF (stderr, " %d", yybot);
+    }
+  YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top)				\
+do {								\
+  if (yydebug)							\
+    yy_stack_print ((Bottom), (Top));				\
+} while (YYID (0))
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced.  |
+`------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_reduce_print (YYSTYPE *yyvsp, int yyrule)
+#else
+static void
+yy_reduce_print (yyvsp, yyrule)
+    YYSTYPE *yyvsp;
+    int yyrule;
+#endif
+{
+  int yynrhs = yyr2[yyrule];
+  int yyi;
+  unsigned long int yylno = yyrline[yyrule];
+  YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
+	     yyrule - 1, yylno);
+  /* The symbols being reduced.  */
+  for (yyi = 0; yyi < yynrhs; yyi++)
+    {
+      YYFPRINTF (stderr, "   $%d = ", yyi + 1);
+      yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
+		       &(yyvsp[(yyi + 1) - (yynrhs)])
+		       		       );
+      YYFPRINTF (stderr, "\n");
+    }
+}
+
+# define YY_REDUCE_PRINT(Rule)		\
+do {					\
+  if (yydebug)				\
+    yy_reduce_print (yyvsp, Rule); \
+} while (YYID (0))
+
+/* Nonzero means print parse trace.  It is left uninitialized so that
+   multiple parsers can coexist.  */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks.  */
+#ifndef	YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+   if the built-in stack extension method is used).
+
+   Do not make this value too large; the results are undefined if
+   YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+   evaluated with infinite-precision integer arithmetic.  */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+#  if defined __GLIBC__ && defined _STRING_H
+#   define yystrlen strlen
+#  else
+/* Return the length of YYSTR.  */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static YYSIZE_T
+yystrlen (const char *yystr)
+#else
+static YYSIZE_T
+yystrlen (yystr)
+    const char *yystr;
+#endif
+{
+  YYSIZE_T yylen;
+  for (yylen = 0; yystr[yylen]; yylen++)
+    continue;
+  return yylen;
+}
+#  endif
+# endif
+
+# ifndef yystpcpy
+#  if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
+#   define yystpcpy stpcpy
+#  else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+   YYDEST.  */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static char *
+yystpcpy (char *yydest, const char *yysrc)
+#else
+static char *
+yystpcpy (yydest, yysrc)
+    char *yydest;
+    const char *yysrc;
+#endif
+{
+  char *yyd = yydest;
+  const char *yys = yysrc;
+
+  while ((*yyd++ = *yys++) != '\0')
+    continue;
+
+  return yyd - 1;
+}
+#  endif
+# endif
+
+# ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+   quotes and backslashes, so that it's suitable for yyerror.  The
+   heuristic is that double-quoting is unnecessary unless the string
+   contains an apostrophe, a comma, or backslash (other than
+   backslash-backslash).  YYSTR is taken from yytname.  If YYRES is
+   null, do not copy; instead, return the length of what the result
+   would have been.  */
+static YYSIZE_T
+yytnamerr (char *yyres, const char *yystr)
+{
+  if (*yystr == '"')
+    {
+      YYSIZE_T yyn = 0;
+      char const *yyp = yystr;
+
+      for (;;)
+	switch (*++yyp)
+	  {
+	  case '\'':
+	  case ',':
+	    goto do_not_strip_quotes;
+
+	  case '\\':
+	    if (*++yyp != '\\')
+	      goto do_not_strip_quotes;
+	    /* Fall through.  */
+	  default:
+	    if (yyres)
+	      yyres[yyn] = *yyp;
+	    yyn++;
+	    break;
+
+	  case '"':
+	    if (yyres)
+	      yyres[yyn] = '\0';
+	    return yyn;
+	  }
+    do_not_strip_quotes: ;
+    }
+
+  if (! yyres)
+    return yystrlen (yystr);
+
+  return yystpcpy (yyres, yystr) - yyres;
+}
+# 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)
+{
+  YYSIZE_T yysize0 = yytnamerr (YY_NULL, yytname[yytoken]);
+  YYSIZE_T yysize = yysize0;
+  enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+  /* Internationalized format string. */
+  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
+     "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];
+                {
+                  YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULL, yytname[yyx]);
+                  if (! (yysize <= yysize1
+                         && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
+                    return 2;
+                  yysize = yysize1;
+                }
+              }
+        }
+    }
+
+  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_
+    }
+
+  {
+    YYSIZE_T yysize1 = yysize + yystrlen (yyformat);
+    if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
+      return 2;
+    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;
+    }
+
+  /* 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;
+}
+#endif /* YYERROR_VERBOSE */
+
+/*-----------------------------------------------.
+| Release the memory associated to this symbol.  |
+`-----------------------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yydestruct (yymsg, yytype, yyvaluep)
+    const char *yymsg;
+    int yytype;
+    YYSTYPE *yyvaluep;
+#endif
+{
+  YYUSE (yyvaluep);
+
+  if (!yymsg)
+    yymsg = "Deleting";
+  YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
+  YYUSE (yytype);
+}
+
+
+
+
+/* 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 YY_INITIAL_VALUE(yyval_default);
+
+/* Number of syntax errors so far.  */
+int yynerrs;
+
+
+/*----------.
+| yyparse.  |
+`----------*/
+
+#ifdef YYPARSE_PARAM
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void *YYPARSE_PARAM)
+#else
+int
+yyparse (YYPARSE_PARAM)
+    void *YYPARSE_PARAM;
+#endif
+#else /* ! YYPARSE_PARAM */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void)
+#else
+int
+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 through 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 = 0;
+  /* The variables used to return semantic value and location from the
+     action routines.  */
+  YYSTYPE yyval;
+
+#if YYERROR_VERBOSE
+  /* Buffer for error messages, and its allocated size.  */
+  char yymsgbuf[128];
+  char *yymsg = yymsgbuf;
+  YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
+#endif
+
+#define YYPOPSTACK(N)   (yyvsp -= (N), yyssp -= (N))
+
+  /* The number of symbols on the RHS of the reduced rule.
+     Keep to zero when no symbol should be popped.  */
+  int yylen = 0;
+
+  yyssp = yyss = yyssa;
+  yyvsp = yyvs = yyvsa;
+  yystacksize = YYINITDEPTH;
+
+  YYDPRINTF ((stderr, "Starting parse\n"));
+
+  yystate = 0;
+  yyerrstatus = 0;
+  yynerrs = 0;
+  yychar = YYEMPTY; /* Cause a token to be read.  */
+  goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate.  |
+`------------------------------------------------------------*/
+ yynewstate:
+  /* In all cases, when you get here, the value and location stacks
+     have just been pushed.  So pushing a state here evens the stacks.  */
+  yyssp++;
+
+ yysetstate:
+  *yyssp = yystate;
+
+  if (yyss + yystacksize - 1 <= yyssp)
+    {
+      /* Get the current used size of the three stacks, in elements.  */
+      YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+      {
+	/* Give user a chance to reallocate the stack.  Use copies of
+	   these so that the &'s don't force the real ones into
+	   memory.  */
+	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
+	   be undefined if yyoverflow is a macro.  */
+	yyoverflow (YY_("memory exhausted"),
+		    &yyss1, yysize * sizeof (*yyssp),
+		    &yyvs1, yysize * sizeof (*yyvsp),
+		    &yystacksize);
+
+	yyss = yyss1;
+	yyvs = yyvs1;
+      }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+      goto yyexhaustedlab;
+# else
+      /* Extend the stack our own way.  */
+      if (YYMAXDEPTH <= yystacksize)
+	goto yyexhaustedlab;
+      yystacksize *= 2;
+      if (YYMAXDEPTH < yystacksize)
+	yystacksize = YYMAXDEPTH;
+
+      {
+	yytype_int16 *yyss1 = yyss;
+	union yyalloc *yyptr =
+	  (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+	if (! yyptr)
+	  goto yyexhaustedlab;
+	YYSTACK_RELOCATE (yyss_alloc, yyss);
+	YYSTACK_RELOCATE (yyvs_alloc, yyvs);
+#  undef YYSTACK_RELOCATE
+	if (yyss1 != yyssa)
+	  YYSTACK_FREE (yyss1);
+      }
+# endif
+#endif /* no yyoverflow */
+
+      yyssp = yyss + yysize - 1;
+      yyvsp = yyvs + yysize - 1;
+
+      YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+		  (unsigned long int) yystacksize));
+
+      if (yyss + yystacksize - 1 <= yyssp)
+	YYABORT;
+    }
+
+  YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+  if (yystate == YYFINAL)
+    YYACCEPT;
+
+  goto yybackup;
+
+/*-----------.
+| yybackup.  |
+`-----------*/
+yybackup:
+
+  /* Do appropriate processing given the current state.  Read a
+     lookahead token if we need one and don't already have one.  */
+
+  /* First try to decide what to do without reference to lookahead token.  */
+  yyn = yypact[yystate];
+  if (yypact_value_is_default (yyn))
+    goto yydefault;
+
+  /* Not known => get a lookahead token if don't already have one.  */
+
+  /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol.  */
+  if (yychar == YYEMPTY)
+    {
+      YYDPRINTF ((stderr, "Reading a token: "));
+      yychar = YYLEX;
+    }
+
+  if (yychar <= YYEOF)
+    {
+      yychar = yytoken = YYEOF;
+      YYDPRINTF ((stderr, "Now at end of input.\n"));
+    }
+  else
+    {
+      yytoken = YYTRANSLATE (yychar);
+      YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
+    }
+
+  /* If the proper action on seeing token YYTOKEN is to reduce or to
+     detect an error, take that action.  */
+  yyn += yytoken;
+  if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+    goto yydefault;
+  yyn = yytable[yyn];
+  if (yyn <= 0)
+    {
+      if (yytable_value_is_error (yyn))
+        goto yyerrlab;
+      yyn = -yyn;
+      goto yyreduce;
+    }
+
+  /* Count tokens shifted since error; after three, turn off error
+     status.  */
+  if (yyerrstatus)
+    yyerrstatus--;
+
+  /* Shift the lookahead token.  */
+  YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+
+  /* Discard the shifted token.  */
+  yychar = YYEMPTY;
+
+  yystate = yyn;
+  YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+  *++yyvsp = yylval;
+  YY_IGNORE_MAYBE_UNINITIALIZED_END
+
+  goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state.  |
+`-----------------------------------------------------------*/
+yydefault:
+  yyn = yydefact[yystate];
+  if (yyn == 0)
+    goto yyerrlab;
+  goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction.  |
+`-----------------------------*/
+yyreduce:
+  /* yyn is the number of a rule to reduce with.  */
+  yylen = yyr2[yyn];
+
+  /* If YYLEN is nonzero, implement the default value of the action:
+     `$$ = $1'.
+
+     Otherwise, the following line sets YYVAL to garbage.
+     This behavior is undocumented and Bison
+     users should not rely upon it.  Assigning to YYVAL
+     unconditionally makes the parser a bit smaller, and it avoids a
+     GCC warning that YYVAL may be used uninitialized.  */
+  yyval = yyvsp[1-yylen];
+
+
+  YY_REDUCE_PRINT (yyn);
+  switch (yyn)
+    {
+        case 3:
+/* Line 1787 of yacc.c  */
+#line 70 "a.y"
+    {
+		stmtline = lineno;
+	}
+    break;
+
+  case 5:
+/* Line 1787 of yacc.c  */
+#line 77 "a.y"
+    {
+		if((yyvsp[(1) - (2)].sym)->value != pc)
+			yyerror("redeclaration of %s", (yyvsp[(1) - (2)].sym)->name);
+		(yyvsp[(1) - (2)].sym)->value = pc;
+	}
+    break;
+
+  case 7:
+/* Line 1787 of yacc.c  */
+#line 84 "a.y"
+    {
+		(yyvsp[(1) - (2)].sym)->type = LLAB;
+		(yyvsp[(1) - (2)].sym)->value = pc;
+	}
+    break;
+
+  case 9:
+/* Line 1787 of yacc.c  */
+#line 90 "a.y"
+    {
+		(yyvsp[(1) - (4)].sym)->type = LVAR;
+		(yyvsp[(1) - (4)].sym)->value = (yyvsp[(3) - (4)].lval);
+	}
+    break;
+
+  case 10:
+/* Line 1787 of yacc.c  */
+#line 95 "a.y"
+    {
+		if((yyvsp[(1) - (4)].sym)->value != (yyvsp[(3) - (4)].lval))
+			yyerror("redeclaration of %s", (yyvsp[(1) - (4)].sym)->name);
+		(yyvsp[(1) - (4)].sym)->value = (yyvsp[(3) - (4)].lval);
+	}
+    break;
+
+  case 14:
+/* Line 1787 of yacc.c  */
+#line 109 "a.y"
+    {
+		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 1787 of yacc.c  */
+#line 113 "a.y"
+    {
+		outcode((yyvsp[(1) - (6)].lval), (yyvsp[(2) - (6)].lval), &(yyvsp[(3) - (6)].addr), (yyvsp[(5) - (6)].lval), &nullgen);
+	}
+    break;
+
+  case 16:
+/* Line 1787 of yacc.c  */
+#line 117 "a.y"
+    {
+		outcode((yyvsp[(1) - (5)].lval), (yyvsp[(2) - (5)].lval), &(yyvsp[(3) - (5)].addr), NREG, &(yyvsp[(5) - (5)].addr));
+	}
+    break;
+
+  case 17:
+/* Line 1787 of yacc.c  */
+#line 124 "a.y"
+    {
+		outcode((yyvsp[(1) - (5)].lval), (yyvsp[(2) - (5)].lval), &(yyvsp[(3) - (5)].addr), NREG, &(yyvsp[(5) - (5)].addr));
+	}
+    break;
+
+  case 18:
+/* Line 1787 of yacc.c  */
+#line 131 "a.y"
+    {
+		outcode((yyvsp[(1) - (5)].lval), (yyvsp[(2) - (5)].lval), &(yyvsp[(3) - (5)].addr), NREG, &(yyvsp[(5) - (5)].addr));
+	}
+    break;
+
+  case 19:
+/* Line 1787 of yacc.c  */
+#line 138 "a.y"
+    {
+		outcode((yyvsp[(1) - (4)].lval), (yyvsp[(2) - (4)].lval), &nullgen, NREG, &(yyvsp[(4) - (4)].addr));
+	}
+    break;
+
+  case 20:
+/* Line 1787 of yacc.c  */
+#line 142 "a.y"
+    {
+		outcode((yyvsp[(1) - (4)].lval), (yyvsp[(2) - (4)].lval), &nullgen, NREG, &(yyvsp[(4) - (4)].addr));
+	}
+    break;
+
+  case 21:
+/* Line 1787 of yacc.c  */
+#line 149 "a.y"
+    {
+		outcode((yyvsp[(1) - (3)].lval), Always, &nullgen, NREG, &(yyvsp[(3) - (3)].addr));
+	}
+    break;
+
+  case 22:
+/* Line 1787 of yacc.c  */
+#line 156 "a.y"
+    {
+		outcode((yyvsp[(1) - (3)].lval), Always, &nullgen, NREG, &(yyvsp[(3) - (3)].addr));
+	}
+    break;
+
+  case 23:
+/* Line 1787 of yacc.c  */
+#line 163 "a.y"
+    {
+		outcode((yyvsp[(1) - (4)].lval), (yyvsp[(2) - (4)].lval), &nullgen, NREG, &(yyvsp[(4) - (4)].addr));
+	}
+    break;
+
+  case 24:
+/* Line 1787 of yacc.c  */
+#line 170 "a.y"
+    {
+		outcode((yyvsp[(1) - (6)].lval), (yyvsp[(2) - (6)].lval), &(yyvsp[(3) - (6)].addr), (yyvsp[(5) - (6)].lval), &nullgen);
+	}
+    break;
+
+  case 25:
+/* Line 1787 of yacc.c  */
+#line 177 "a.y"
+    {
+		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)].addr), NREG, &g);
+	}
+    break;
+
+  case 26:
+/* Line 1787 of yacc.c  */
+#line 186 "a.y"
+    {
+		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)].addr));
+	}
+    break;
+
+  case 27:
+/* Line 1787 of yacc.c  */
+#line 198 "a.y"
+    {
+		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 1787 of yacc.c  */
+#line 202 "a.y"
+    {
+		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 1787 of yacc.c  */
+#line 206 "a.y"
+    {
+		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 1787 of yacc.c  */
+#line 213 "a.y"
+    {
+		outcode((yyvsp[(1) - (3)].lval), (yyvsp[(2) - (3)].lval), &nullgen, NREG, &nullgen);
+	}
+    break;
+
+  case 31:
+/* Line 1787 of yacc.c  */
+#line 220 "a.y"
+    {
+		(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 1787 of yacc.c  */
+#line 226 "a.y"
+    {
+		(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 1787 of yacc.c  */
+#line 232 "a.y"
+    {
+		(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 1787 of yacc.c  */
+#line 241 "a.y"
+    {
+		outcode((yyvsp[(1) - (6)].lval), Always, &(yyvsp[(2) - (6)].addr), (yyvsp[(4) - (6)].lval), &(yyvsp[(6) - (6)].addr));
+	}
+    break;
+
+  case 35:
+/* Line 1787 of yacc.c  */
+#line 248 "a.y"
+    {
+		outcode((yyvsp[(1) - (4)].lval), (yyvsp[(2) - (4)].lval), &(yyvsp[(3) - (4)].addr), NREG, &nullgen);
+	}
+    break;
+
+  case 36:
+/* Line 1787 of yacc.c  */
+#line 255 "a.y"
+    {
+		outcode((yyvsp[(1) - (3)].lval), Always, &nullgen, NREG, &(yyvsp[(3) - (3)].addr));
+	}
+    break;
+
+  case 37:
+/* Line 1787 of yacc.c  */
+#line 262 "a.y"
+    {
+		outcode((yyvsp[(1) - (5)].lval), (yyvsp[(2) - (5)].lval), &(yyvsp[(3) - (5)].addr), NREG, &(yyvsp[(5) - (5)].addr));
+	}
+    break;
+
+  case 38:
+/* Line 1787 of yacc.c  */
+#line 266 "a.y"
+    {
+		outcode((yyvsp[(1) - (5)].lval), (yyvsp[(2) - (5)].lval), &(yyvsp[(3) - (5)].addr), NREG, &(yyvsp[(5) - (5)].addr));
+	}
+    break;
+
+  case 39:
+/* Line 1787 of yacc.c  */
+#line 270 "a.y"
+    {
+		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 1787 of yacc.c  */
+#line 274 "a.y"
+    {
+		outcode((yyvsp[(1) - (6)].lval), (yyvsp[(2) - (6)].lval), &(yyvsp[(3) - (6)].addr), (yyvsp[(5) - (6)].addr).reg, &nullgen);
+	}
+    break;
+
+  case 41:
+/* Line 1787 of yacc.c  */
+#line 281 "a.y"
+    {
+		Addr g;
+
+		g = nullgen;
+		g.type = D_CONST;
+		g.offset =
+			(0xe << 24) |		/* opcode */
+			((yyvsp[(1) - (12)].lval) << 20) |		/* MCR/MRC */
+			((yyvsp[(2) - (12)].lval) << 28) |		/* scond */
+			(((yyvsp[(3) - (12)].lval) & 15) << 8) |	/* coprocessor number */
+			(((yyvsp[(5) - (12)].lval) & 7) << 21) |	/* coprocessor operation */
+			(((yyvsp[(7) - (12)].lval) & 15) << 12) |	/* arm register */
+			(((yyvsp[(9) - (12)].lval) & 15) << 16) |	/* Crn */
+			(((yyvsp[(11) - (12)].lval) & 15) << 0) |	/* Crm */
+			(((yyvsp[(12) - (12)].lval) & 7) << 5) |	/* coprocessor information */
+			(1<<4);			/* must be set */
+		outcode(AMRC, Always, &nullgen, NREG, &g);
+	}
+    break;
+
+  case 42:
+/* Line 1787 of yacc.c  */
+#line 303 "a.y"
+    {
+		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 1787 of yacc.c  */
+#line 311 "a.y"
+    {
+		(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 1787 of yacc.c  */
+#line 320 "a.y"
+    {
+		outcode((yyvsp[(1) - (2)].lval), Always, &(yyvsp[(2) - (2)].addr), NREG, &nullgen);
+	}
+    break;
+
+  case 45:
+/* Line 1787 of yacc.c  */
+#line 327 "a.y"
+    {
+		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)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+	}
+    break;
+
+  case 46:
+/* Line 1787 of yacc.c  */
+#line 336 "a.y"
+    {
+		if((yyvsp[(2) - (4)].addr).type != D_CONST)
+			yyerror("index for FUNCDATA must be integer constant");
+		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)].addr), NREG, &(yyvsp[(4) - (4)].addr));
+	}
+    break;
+
+  case 47:
+/* Line 1787 of yacc.c  */
+#line 347 "a.y"
+    {
+		outcode((yyvsp[(1) - (2)].lval), Always, &nullgen, NREG, &nullgen);
+	}
+    break;
+
+  case 48:
+/* Line 1787 of yacc.c  */
+#line 352 "a.y"
+    {
+		(yyval.lval) = Always;
+	}
+    break;
+
+  case 49:
+/* Line 1787 of yacc.c  */
+#line 356 "a.y"
+    {
+		(yyval.lval) = ((yyvsp[(1) - (2)].lval) & ~C_SCOND) | (yyvsp[(2) - (2)].lval);
+	}
+    break;
+
+  case 50:
+/* Line 1787 of yacc.c  */
+#line 360 "a.y"
+    {
+		(yyval.lval) = (yyvsp[(1) - (2)].lval) | (yyvsp[(2) - (2)].lval);
+	}
+    break;
+
+  case 53:
+/* Line 1787 of yacc.c  */
+#line 369 "a.y"
+    {
+		(yyval.addr) = nullgen;
+		(yyval.addr).type = D_BRANCH;
+		(yyval.addr).offset = (yyvsp[(1) - (4)].lval) + pc;
+	}
+    break;
+
+  case 54:
+/* Line 1787 of yacc.c  */
+#line 375 "a.y"
+    {
+		(yyval.addr) = nullgen;
+		if(pass == 2)
+			yyerror("undefined label: %s", (yyvsp[(1) - (2)].sym)->name);
+		(yyval.addr).type = D_BRANCH;
+		(yyval.addr).offset = (yyvsp[(2) - (2)].lval);
+	}
+    break;
+
+  case 55:
+/* Line 1787 of yacc.c  */
+#line 383 "a.y"
+    {
+		(yyval.addr) = nullgen;
+		(yyval.addr).type = D_BRANCH;
+		(yyval.addr).offset = (yyvsp[(1) - (2)].sym)->value + (yyvsp[(2) - (2)].lval);
+	}
+    break;
+
+  case 56:
+/* Line 1787 of yacc.c  */
+#line 390 "a.y"
+    {
+		(yyval.addr) = nullgen;
+		(yyval.addr).type = D_CONST;
+		(yyval.addr).offset = (yyvsp[(2) - (2)].lval);
+	}
+    break;
+
+  case 57:
+/* Line 1787 of yacc.c  */
+#line 396 "a.y"
+    {
+		(yyval.addr) = (yyvsp[(2) - (2)].addr);
+		(yyval.addr).type = D_CONST;
+	}
+    break;
+
+  case 58:
+/* Line 1787 of yacc.c  */
+#line 401 "a.y"
+    {
+		(yyval.addr) = (yyvsp[(4) - (4)].addr);
+		(yyval.addr).type = D_OCONST;
+	}
+    break;
+
+  case 59:
+/* Line 1787 of yacc.c  */
+#line 406 "a.y"
+    {
+		(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 1787 of yacc.c  */
+#line 415 "a.y"
+    {
+		(yyval.addr) = nullgen;
+		(yyval.addr).type = D_FCONST;
+		(yyval.addr).u.dval = (yyvsp[(2) - (2)].dval);
+	}
+    break;
+
+  case 62:
+/* Line 1787 of yacc.c  */
+#line 421 "a.y"
+    {
+		(yyval.addr) = nullgen;
+		(yyval.addr).type = D_FCONST;
+		(yyval.addr).u.dval = -(yyvsp[(3) - (3)].dval);
+	}
+    break;
+
+  case 63:
+/* Line 1787 of yacc.c  */
+#line 429 "a.y"
+    {
+		(yyval.lval) = 1 << (yyvsp[(1) - (1)].lval);
+	}
+    break;
+
+  case 64:
+/* Line 1787 of yacc.c  */
+#line 433 "a.y"
+    {
+		int i;
+		(yyval.lval)=0;
+		for(i=(yyvsp[(1) - (3)].lval); i<=(yyvsp[(3) - (3)].lval); i++)
+			(yyval.lval) |= 1<<i;
+		for(i=(yyvsp[(3) - (3)].lval); i<=(yyvsp[(1) - (3)].lval); i++)
+			(yyval.lval) |= 1<<i;
+	}
+    break;
+
+  case 65:
+/* Line 1787 of yacc.c  */
+#line 442 "a.y"
+    {
+		(yyval.lval) = (1<<(yyvsp[(1) - (3)].lval)) | (yyvsp[(3) - (3)].lval);
+	}
+    break;
+
+  case 69:
+/* Line 1787 of yacc.c  */
+#line 451 "a.y"
+    {
+		(yyval.addr) = (yyvsp[(1) - (4)].addr);
+		(yyval.addr).reg = (yyvsp[(3) - (4)].lval);
+	}
+    break;
+
+  case 70:
+/* Line 1787 of yacc.c  */
+#line 456 "a.y"
+    {
+		(yyval.addr) = nullgen;
+		(yyval.addr).type = D_PSR;
+		(yyval.addr).reg = (yyvsp[(1) - (1)].lval);
+	}
+    break;
+
+  case 71:
+/* Line 1787 of yacc.c  */
+#line 462 "a.y"
+    {
+		(yyval.addr) = nullgen;
+		(yyval.addr).type = D_FPCR;
+		(yyval.addr).reg = (yyvsp[(1) - (1)].lval);
+	}
+    break;
+
+  case 72:
+/* Line 1787 of yacc.c  */
+#line 468 "a.y"
+    {
+		(yyval.addr) = nullgen;
+		(yyval.addr).type = D_OREG;
+		(yyval.addr).offset = (yyvsp[(1) - (1)].lval);
+	}
+    break;
+
+  case 76:
+/* Line 1787 of yacc.c  */
+#line 479 "a.y"
+    {
+		(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 1787 of yacc.c  */
+#line 487 "a.y"
+    {
+		(yyval.addr) = nullgen;
+		(yyval.addr).type = D_OREG;
+		(yyval.addr).reg = (yyvsp[(2) - (3)].lval);
+		(yyval.addr).offset = 0;
+	}
+    break;
+
+  case 79:
+/* Line 1787 of yacc.c  */
+#line 497 "a.y"
+    {
+		(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 1787 of yacc.c  */
+#line 507 "a.y"
+    {
+		(yyval.addr) = (yyvsp[(1) - (4)].addr);
+		(yyval.addr).type = D_OREG;
+		(yyval.addr).reg = (yyvsp[(3) - (4)].lval);
+	}
+    break;
+
+  case 86:
+/* Line 1787 of yacc.c  */
+#line 520 "a.y"
+    {
+		(yyval.addr) = nullgen;
+		(yyval.addr).type = D_CONST;
+		(yyval.addr).offset = (yyvsp[(2) - (2)].lval);
+	}
+    break;
+
+  case 87:
+/* Line 1787 of yacc.c  */
+#line 528 "a.y"
+    {
+		(yyval.addr) = nullgen;
+		(yyval.addr).type = D_REG;
+		(yyval.addr).reg = (yyvsp[(1) - (1)].lval);
+	}
+    break;
+
+  case 88:
+/* Line 1787 of yacc.c  */
+#line 536 "a.y"
+    {
+		(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 1787 of yacc.c  */
+#line 545 "a.y"
+    {
+		(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 1787 of yacc.c  */
+#line 551 "a.y"
+    {
+		(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 1787 of yacc.c  */
+#line 557 "a.y"
+    {
+		(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 1787 of yacc.c  */
+#line 563 "a.y"
+    {
+		(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 1787 of yacc.c  */
+#line 571 "a.y"
+    {
+		if((yyval.lval) < 0 || (yyval.lval) >= 16)
+			print("register value out of range\n");
+		(yyval.lval) = (((yyvsp[(1) - (1)].lval)&15) << 8) | (1 << 4);
+	}
+    break;
+
+  case 94:
+/* Line 1787 of yacc.c  */
+#line 577 "a.y"
+    {
+		if((yyval.lval) < 0 || (yyval.lval) >= 32)
+			print("shift value out of range\n");
+		(yyval.lval) = ((yyvsp[(1) - (1)].lval)&31) << 7;
+	}
+    break;
+
+  case 96:
+/* Line 1787 of yacc.c  */
+#line 586 "a.y"
+    {
+		(yyval.lval) = REGPC;
+	}
+    break;
+
+  case 97:
+/* 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");
+		(yyval.lval) = (yyvsp[(3) - (4)].lval);
+	}
+    break;
+
+  case 99:
+/* Line 1787 of yacc.c  */
+#line 599 "a.y"
+    {
+		(yyval.lval) = REGSP;
+	}
+    break;
+
+  case 101:
+/* 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");
+		(yyval.lval) = (yyvsp[(3) - (4)].lval);
+	}
+    break;
+
+  case 104:
+/* Line 1787 of yacc.c  */
+#line 618 "a.y"
+    {
+		(yyval.addr) = nullgen;
+		(yyval.addr).type = D_FREG;
+		(yyval.addr).reg = (yyvsp[(1) - (1)].lval);
+	}
+    break;
+
+  case 105:
+/* Line 1787 of yacc.c  */
+#line 624 "a.y"
+    {
+		(yyval.addr) = nullgen;
+		(yyval.addr).type = D_FREG;
+		(yyval.addr).reg = (yyvsp[(3) - (4)].lval);
+	}
+    break;
+
+  case 106:
+/* Line 1787 of yacc.c  */
+#line 632 "a.y"
+    {
+		(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 1787 of yacc.c  */
+#line 640 "a.y"
+    {
+		(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 1787 of yacc.c  */
+#line 648 "a.y"
+    {
+		(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 1787 of yacc.c  */
+#line 657 "a.y"
+    {
+		(yyval.lval) = 0;
+	}
+    break;
+
+  case 110:
+/* Line 1787 of yacc.c  */
+#line 661 "a.y"
+    {
+		(yyval.lval) = (yyvsp[(2) - (2)].lval);
+	}
+    break;
+
+  case 111:
+/* Line 1787 of yacc.c  */
+#line 665 "a.y"
+    {
+		(yyval.lval) = -(yyvsp[(2) - (2)].lval);
+	}
+    break;
+
+  case 116:
+/* Line 1787 of yacc.c  */
+#line 677 "a.y"
+    {
+		(yyval.lval) = (yyvsp[(1) - (1)].sym)->value;
+	}
+    break;
+
+  case 117:
+/* Line 1787 of yacc.c  */
+#line 681 "a.y"
+    {
+		(yyval.lval) = -(yyvsp[(2) - (2)].lval);
+	}
+    break;
+
+  case 118:
+/* Line 1787 of yacc.c  */
+#line 685 "a.y"
+    {
+		(yyval.lval) = (yyvsp[(2) - (2)].lval);
+	}
+    break;
+
+  case 119:
+/* Line 1787 of yacc.c  */
+#line 689 "a.y"
+    {
+		(yyval.lval) = ~(yyvsp[(2) - (2)].lval);
+	}
+    break;
+
+  case 120:
+/* Line 1787 of yacc.c  */
+#line 693 "a.y"
+    {
+		(yyval.lval) = (yyvsp[(2) - (3)].lval);
+	}
+    break;
+
+  case 121:
+/* Line 1787 of yacc.c  */
+#line 698 "a.y"
+    {
+		(yyval.lval) = 0;
+	}
+    break;
+
+  case 122:
+/* Line 1787 of yacc.c  */
+#line 702 "a.y"
+    {
+		(yyval.lval) = (yyvsp[(2) - (2)].lval);
+	}
+    break;
+
+  case 124:
+/* Line 1787 of yacc.c  */
+#line 709 "a.y"
+    {
+		(yyval.lval) = (yyvsp[(1) - (3)].lval) + (yyvsp[(3) - (3)].lval);
+	}
+    break;
+
+  case 125:
+/* Line 1787 of yacc.c  */
+#line 713 "a.y"
+    {
+		(yyval.lval) = (yyvsp[(1) - (3)].lval) - (yyvsp[(3) - (3)].lval);
+	}
+    break;
+
+  case 126:
+/* Line 1787 of yacc.c  */
+#line 717 "a.y"
+    {
+		(yyval.lval) = (yyvsp[(1) - (3)].lval) * (yyvsp[(3) - (3)].lval);
+	}
+    break;
+
+  case 127:
+/* Line 1787 of yacc.c  */
+#line 721 "a.y"
+    {
+		(yyval.lval) = (yyvsp[(1) - (3)].lval) / (yyvsp[(3) - (3)].lval);
+	}
+    break;
+
+  case 128:
+/* Line 1787 of yacc.c  */
+#line 725 "a.y"
+    {
+		(yyval.lval) = (yyvsp[(1) - (3)].lval) % (yyvsp[(3) - (3)].lval);
+	}
+    break;
+
+  case 129:
+/* Line 1787 of yacc.c  */
+#line 729 "a.y"
+    {
+		(yyval.lval) = (yyvsp[(1) - (4)].lval) << (yyvsp[(4) - (4)].lval);
+	}
+    break;
+
+  case 130:
+/* Line 1787 of yacc.c  */
+#line 733 "a.y"
+    {
+		(yyval.lval) = (yyvsp[(1) - (4)].lval) >> (yyvsp[(4) - (4)].lval);
+	}
+    break;
+
+  case 131:
+/* Line 1787 of yacc.c  */
+#line 737 "a.y"
+    {
+		(yyval.lval) = (yyvsp[(1) - (3)].lval) & (yyvsp[(3) - (3)].lval);
+	}
+    break;
+
+  case 132:
+/* Line 1787 of yacc.c  */
+#line 741 "a.y"
+    {
+		(yyval.lval) = (yyvsp[(1) - (3)].lval) ^ (yyvsp[(3) - (3)].lval);
+	}
+    break;
+
+  case 133:
+/* Line 1787 of yacc.c  */
+#line 745 "a.y"
+    {
+		(yyval.lval) = (yyvsp[(1) - (3)].lval) | (yyvsp[(3) - (3)].lval);
+	}
+    break;
+
+
+/* Line 1787 of yacc.c  */
+#line 2707 "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);
+  yylen = 0;
+  YY_STACK_PRINT (yyss, yyssp);
+
+  *++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.  */
+
+  yyn = yyr1[yyn];
+
+  yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+  if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+    yystate = yytable[yystate];
+  else
+    yystate = yydefgoto[yyn - YYNTOKENS];
+
+  goto yynewstate;
+
+
+/*------------------------------------.
+| 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)
+    {
+      ++yynerrs;
+#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;
+      }
+# undef YYSYNTAX_ERROR
+#endif
+    }
+
+
+
+  if (yyerrstatus == 3)
+    {
+      /* If just tried and failed to reuse lookahead token after an
+	 error, discard it.  */
+
+      if (yychar <= YYEOF)
+	{
+	  /* Return failure if at end of input.  */
+	  if (yychar == YYEOF)
+	    YYABORT;
+	}
+      else
+	{
+	  yydestruct ("Error: discarding",
+		      yytoken, &yylval);
+	  yychar = YYEMPTY;
+	}
+    }
+
+  /* Else will try to reuse lookahead token after shifting the error
+     token.  */
+  goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR.  |
+`---------------------------------------------------*/
+yyerrorlab:
+
+  /* Pacify compilers like GCC when the user code never invokes
+     YYERROR and the label yyerrorlab therefore never appears in user
+     code.  */
+  if (/*CONSTCOND*/ 0)
+     goto yyerrorlab;
+
+  /* Do not reclaim the symbols of the rule which action triggered
+     this YYERROR.  */
+  YYPOPSTACK (yylen);
+  yylen = 0;
+  YY_STACK_PRINT (yyss, yyssp);
+  yystate = *yyssp;
+  goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR.  |
+`-------------------------------------------------------------*/
+yyerrlab1:
+  yyerrstatus = 3;	/* Each real token shifted decrements this.  */
+
+  for (;;)
+    {
+      yyn = yypact[yystate];
+      if (!yypact_value_is_default (yyn))
+	{
+	  yyn += YYTERROR;
+	  if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+	    {
+	      yyn = yytable[yyn];
+	      if (0 < yyn)
+		break;
+	    }
+	}
+
+      /* Pop the current state because it cannot handle the error token.  */
+      if (yyssp == yyss)
+	YYABORT;
+
+
+      yydestruct ("Error: popping",
+		  yystos[yystate], yyvsp);
+      YYPOPSTACK (1);
+      yystate = *yyssp;
+      YY_STACK_PRINT (yyss, yyssp);
+    }
+
+  YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+  *++yyvsp = yylval;
+  YY_IGNORE_MAYBE_UNINITIALIZED_END
+
+
+  /* Shift the error token.  */
+  YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+
+  yystate = yyn;
+  goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here.  |
+`-------------------------------------*/
+yyacceptlab:
+  yyresult = 0;
+  goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here.  |
+`-----------------------------------*/
+yyabortlab:
+  yyresult = 1;
+  goto yyreturn;
+
+#if !defined yyoverflow || YYERROR_VERBOSE
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here.  |
+`-------------------------------------------------*/
+yyexhaustedlab:
+  yyerror (YY_("memory exhausted"));
+  yyresult = 2;
+  /* Fall through.  */
+#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);
+    }
+  /* Do not reclaim the symbols of the rule which action triggered
+     this YYABORT or YYACCEPT.  */
+  YYPOPSTACK (yylen);
+  YY_STACK_PRINT (yyss, yyssp);
+  while (yyssp != yyss)
+    {
+      yydestruct ("Cleanup: popping",
+		  yystos[*yyssp], yyvsp);
+      YYPOPSTACK (1);
+    }
+#ifndef yyoverflow
+  if (yyss != yyssa)
+    YYSTACK_FREE (yyss);
+#endif
+#if YYERROR_VERBOSE
+  if (yymsg != yymsgbuf)
+    YYSTACK_FREE (yymsg);
+#endif
+  /* Make sure YYID is used.  */
+  return YYID (yyresult);
+}
+
+
diff --git a/src/cmd/5a/y.tab.h b/src/cmd/5a/y.tab.h
new file mode 100644
index 0000000..f11fb85
--- /dev/null
+++ b/src/cmd/5a/y.tab.h
@@ -0,0 +1,188 @@
+/* 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-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
+   the Free Software Foundation, either version 3 of the License, 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/>.  */
+
+/* As a special exception, you may create a larger work that contains
+   part or all of the Bison parser skeleton and distribute that work
+   under terms of your choice, so long as that work isn't itself a
+   parser generator using the skeleton or a modified version thereof
+   as a parser skeleton.  Alternatively, if you modify or redistribute
+   the parser skeleton itself, you may (at your option) remove this
+   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.  */
+
+#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
+# define YYTOKENTYPE
+   /* Put the tokens into the symbol table, so that GDB and other debuggers
+      know about them.  */
+   enum yytokentype {
+     LTYPE1 = 258,
+     LTYPE2 = 259,
+     LTYPE3 = 260,
+     LTYPE4 = 261,
+     LTYPE5 = 262,
+     LTYPE6 = 263,
+     LTYPE7 = 264,
+     LTYPE8 = 265,
+     LTYPE9 = 266,
+     LTYPEA = 267,
+     LTYPEB = 268,
+     LTYPEC = 269,
+     LTYPED = 270,
+     LTYPEE = 271,
+     LTYPEG = 272,
+     LTYPEH = 273,
+     LTYPEI = 274,
+     LTYPEJ = 275,
+     LTYPEK = 276,
+     LTYPEL = 277,
+     LTYPEM = 278,
+     LTYPEN = 279,
+     LTYPEBX = 280,
+     LTYPEPLD = 281,
+     LCONST = 282,
+     LSP = 283,
+     LSB = 284,
+     LFP = 285,
+     LPC = 286,
+     LTYPEX = 287,
+     LTYPEPC = 288,
+     LTYPEF = 289,
+     LR = 290,
+     LREG = 291,
+     LF = 292,
+     LFREG = 293,
+     LC = 294,
+     LCREG = 295,
+     LPSR = 296,
+     LFCR = 297,
+     LCOND = 298,
+     LS = 299,
+     LAT = 300,
+     LFCONST = 301,
+     LSCONST = 302,
+     LNAME = 303,
+     LLAB = 304,
+     LVAR = 305
+   };
+#endif
+/* Tokens.  */
+#define LTYPE1 258
+#define LTYPE2 259
+#define LTYPE3 260
+#define LTYPE4 261
+#define LTYPE5 262
+#define LTYPE6 263
+#define LTYPE7 264
+#define LTYPE8 265
+#define LTYPE9 266
+#define LTYPEA 267
+#define LTYPEB 268
+#define LTYPEC 269
+#define LTYPED 270
+#define LTYPEE 271
+#define LTYPEG 272
+#define LTYPEH 273
+#define LTYPEI 274
+#define LTYPEJ 275
+#define LTYPEK 276
+#define LTYPEL 277
+#define LTYPEM 278
+#define LTYPEN 279
+#define LTYPEBX 280
+#define LTYPEPLD 281
+#define LCONST 282
+#define LSP 283
+#define LSB 284
+#define LFP 285
+#define LPC 286
+#define LTYPEX 287
+#define LTYPEPC 288
+#define LTYPEF 289
+#define LR 290
+#define LREG 291
+#define LF 292
+#define LFREG 293
+#define LC 294
+#define LCREG 295
+#define LPSR 296
+#define LFCR 297
+#define LCOND 298
+#define LS 299
+#define LAT 300
+#define LFCONST 301
+#define LSCONST 302
+#define LNAME 303
+#define LLAB 304
+#define LVAR 305
+
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+{
+/* Line 2053 of yacc.c  */
+#line 39 "a.y"
+
+	Sym	*sym;
+	int32	lval;
+	double	dval;
+	char	sval[8];
+	Addr	addr;
+
+
+/* Line 2053 of yacc.c  */
+#line 166 "y.tab.h"
+} YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+#endif
+
+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/Makefile b/src/cmd/5c/Makefile
new file mode 100644
index 0000000..3f528d7
--- /dev/null
+++ b/src/cmd/5c/Makefile
@@ -0,0 +1,5 @@
+# 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/5c/cgen.c b/src/cmd/5c/cgen.c
new file mode 100644
index 0000000..5a049ae
--- /dev/null
+++ b/src/cmd/5c/cgen.c
@@ -0,0 +1,1213 @@
+// Inferno utils/5c/cgen.c
+// http://code.google.com/p/inferno-os/source/browse/utils/5c/cgen.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 "gc.h"
+#include "../../runtime/funcdata.h"
+
+void
+_cgen(Node *n, Node *nn, int inrel)
+{
+	Node *l, *r;
+	Prog *p1;
+	Node nod, nod1, nod2, nod3, nod4;
+	int o, t;
+	int32 v, curs;
+
+	if(debug['g']) {
+		prtree(nn, "cgen lhs");
+		prtree(n, "cgen");
+	}
+	if(n == Z || n->type == T)
+		return;
+	if(typesuv[n->type->etype] && (n->op != OFUNC || nn != Z)) {
+		sugen(n, nn, n->type->width);
+		return;
+	}
+	l = n->left;
+	r = n->right;
+	o = n->op;
+	if(n->addable >= INDEXED) {
+		if(nn == Z) {
+			switch(o) {
+			default:
+				nullwarn(Z, Z);
+				break;
+			case OINDEX:
+				nullwarn(l, r);
+				break;
+			}
+			return;
+		}
+		gmove(n, nn);
+		return;
+	}
+	curs = cursafe;
+
+	if(n->complex >= FNX)
+	if(l->complex >= FNX)
+	if(r != Z && r->complex >= FNX)
+	switch(o) {
+	default:
+		regret(&nod, r, 0, 0);
+		cgen(r, &nod);
+
+		regsalloc(&nod1, r);
+		gopcode(OAS, &nod, Z, &nod1);
+
+		regfree(&nod);
+		nod = *n;
+		nod.right = &nod1;
+		cgen(&nod, nn);
+		return;
+
+	case OFUNC:
+	case OCOMMA:
+	case OANDAND:
+	case OOROR:
+	case OCOND:
+	case ODOT:
+		break;
+	}
+
+	switch(o) {
+	default:
+		diag(n, "unknown op in cgen: %O", o);
+		break;
+
+	case OAS:
+		if(l->op == OBIT)
+			goto bitas;
+		if(l->addable >= INDEXED && l->complex < FNX) {
+			if(nn != Z || r->addable < INDEXED) {
+				if(r->complex >= FNX && nn == Z)
+					regret(&nod, r, 0, 0);
+				else
+					regalloc(&nod, r, nn);
+				cgen(r, &nod);
+				gmove(&nod, l);
+				if(nn != Z)
+					gmove(&nod, nn);
+				regfree(&nod);
+			} else
+				gmove(r, l);
+			break;
+		}
+		if(l->complex >= r->complex) {
+			reglcgen(&nod1, l, Z);
+			if(r->addable >= INDEXED) {
+				gmove(r, &nod1);
+				if(nn != Z)
+					gmove(r, nn);
+				regfree(&nod1);
+				break;
+			}
+			regalloc(&nod, r, nn);
+			cgen(r, &nod);
+		} else {
+			regalloc(&nod, r, nn);
+			cgen(r, &nod);
+			reglcgen(&nod1, l, Z);
+		}
+		gmove(&nod, &nod1);
+		regfree(&nod);
+		regfree(&nod1);
+		break;
+
+	bitas:
+		n = l->left;
+		regalloc(&nod, r, nn);
+		if(l->complex >= r->complex) {
+			reglcgen(&nod1, n, Z);
+			cgen(r, &nod);
+		} else {
+			cgen(r, &nod);
+			reglcgen(&nod1, n, Z);
+		}
+		regalloc(&nod2, n, Z);
+		gopcode(OAS, &nod1, Z, &nod2);
+		bitstore(l, &nod, &nod1, &nod2, nn);
+		break;
+
+	case OBIT:
+		if(nn == Z) {
+			nullwarn(l, Z);
+			break;
+		}
+		bitload(n, &nod, Z, Z, nn);
+		gopcode(OAS, &nod, Z, nn);
+		regfree(&nod);
+		break;
+
+	case ODIV:
+	case OMOD:
+		if(nn != Z)
+		if((t = vlog(r)) >= 0) {
+			/* signed div/mod by constant power of 2 */
+			cgen(l, nn);
+			gopcode(OGE, nodconst(0), nn, Z);
+			p1 = p;
+			if(o == ODIV) {
+				gopcode(OADD, nodconst((1<<t)-1), Z, nn);
+				patch(p1, pc);
+				gopcode(OASHR, nodconst(t), Z, nn);
+			} else {
+				gopcode(OSUB, nn, nodconst(0), nn);
+				gopcode(OAND, nodconst((1<<t)-1), Z, nn);
+				gopcode(OSUB, nn, nodconst(0), nn);
+				gbranch(OGOTO);
+				patch(p1, pc);
+				p1 = p;
+				gopcode(OAND, nodconst((1<<t)-1), Z, nn);
+				patch(p1, pc);
+			}
+			break;
+		}
+		goto muldiv;
+
+	case OSUB:
+		if(nn != Z)
+		if(l->op == OCONST)
+		if(!typefd[n->type->etype]) {
+			cgen(r, nn);
+			gopcode(o, Z, l, nn);
+			break;
+		}
+	case OADD:
+	case OAND:
+	case OOR:
+	case OXOR:
+	case OLSHR:
+	case OASHL:
+	case OASHR:
+		/*
+		 * immediate operands
+		 */
+		if(nn != Z)
+		if(r->op == OCONST)
+		if(!typefd[n->type->etype]) {
+			cgen(l, nn);
+			if(r->vconst == 0)
+			if(o != OAND)
+				break;
+			if(nn != Z)
+				gopcode(o, r, Z, nn);
+			break;
+		}
+
+	case OLMUL:
+	case OLDIV:
+	case OLMOD:
+	case OMUL:
+	muldiv:
+		if(nn == Z) {
+			nullwarn(l, r);
+			break;
+		}
+		if(o == OMUL || o == OLMUL) {
+			if(mulcon(n, nn))
+				break;
+		}
+		if(l->complex >= r->complex) {
+			regalloc(&nod, l, nn);
+			cgen(l, &nod);
+			regalloc(&nod1, r, Z);
+			cgen(r, &nod1);
+			gopcode(o, &nod1, Z, &nod);
+		} else {
+			regalloc(&nod, r, nn);
+			cgen(r, &nod);
+			regalloc(&nod1, l, Z);
+			cgen(l, &nod1);
+			gopcode(o, &nod, &nod1, &nod);
+		}
+		gopcode(OAS, &nod, Z, nn);
+		regfree(&nod);
+		regfree(&nod1);
+		break;
+
+	case OASLSHR:
+	case OASASHL:
+	case OASASHR:
+	case OASAND:
+	case OASADD:
+	case OASSUB:
+	case OASXOR:
+	case OASOR:
+		if(l->op == OBIT)
+			goto asbitop;
+		if(r->op == OCONST)
+		if(!typefd[r->type->etype])
+		if(!typefd[n->type->etype]) {
+			if(l->addable < INDEXED)
+				reglcgen(&nod2, l, Z);
+			else
+				nod2 = *l;
+			regalloc(&nod, r, nn);
+			gopcode(OAS, &nod2, Z, &nod);
+			gopcode(o, r, Z, &nod);
+			gopcode(OAS, &nod, Z, &nod2);
+
+			regfree(&nod);
+			if(l->addable < INDEXED)
+				regfree(&nod2);
+			break;
+		}
+
+	case OASLMUL:
+	case OASLDIV:
+	case OASLMOD:
+	case OASMUL:
+	case OASDIV:
+	case OASMOD:
+		if(l->op == OBIT)
+			goto asbitop;
+		if(l->complex >= r->complex) {
+			if(l->addable < INDEXED)
+				reglcgen(&nod2, l, Z);
+			else
+				nod2 = *l;
+			regalloc(&nod1, r, Z);
+			cgen(r, &nod1);
+		} else {
+			regalloc(&nod1, r, Z);
+			cgen(r, &nod1);
+			if(l->addable < INDEXED)
+				reglcgen(&nod2, l, Z);
+			else
+				nod2 = *l;
+		}
+
+		regalloc(&nod, n, nn);
+		gmove(&nod2, &nod);
+		gopcode(o, &nod1, Z, &nod);
+		gmove(&nod, &nod2);
+		if(nn != Z)
+			gopcode(OAS, &nod, Z, nn);
+		regfree(&nod);
+		regfree(&nod1);
+		if(l->addable < INDEXED)
+			regfree(&nod2);
+		break;
+
+	asbitop:
+		regalloc(&nod4, n, nn);
+		if(l->complex >= r->complex) {
+			bitload(l, &nod, &nod1, &nod2, &nod4);
+			regalloc(&nod3, r, Z);
+			cgen(r, &nod3);
+		} else {
+			regalloc(&nod3, r, Z);
+			cgen(r, &nod3);
+			bitload(l, &nod, &nod1, &nod2, &nod4);
+		}
+		gmove(&nod, &nod4);
+		gopcode(o, &nod3, Z, &nod4);
+		regfree(&nod3);
+		gmove(&nod4, &nod);
+		regfree(&nod4);
+		bitstore(l, &nod, &nod1, &nod2, nn);
+		break;
+
+	case OADDR:
+		if(nn == Z) {
+			nullwarn(l, Z);
+			break;
+		}
+		lcgen(l, nn);
+		break;
+
+	case OFUNC:
+		if(l->complex >= FNX) {
+			if(l->op != OIND)
+				diag(n, "bad function call");
+
+			regret(&nod, l->left, 0, 0);
+			cgen(l->left, &nod);
+			regsalloc(&nod1, l->left);
+			gopcode(OAS, &nod, Z, &nod1);
+			regfree(&nod);
+
+			nod = *n;
+			nod.left = &nod2;
+			nod2 = *l;
+			nod2.left = &nod1;
+			nod2.complex = 1;
+			cgen(&nod, nn);
+
+			return;
+		}
+		if(REGARG >= 0)
+			o = reg[REGARG];
+		gargs(r, &nod, &nod1);
+		if(l->addable < INDEXED) {
+			reglcgen(&nod, l, Z);
+			gopcode(OFUNC, Z, Z, &nod);
+			regfree(&nod);
+		} else
+			gopcode(OFUNC, Z, Z, l);
+		if(REGARG >= 0)
+			if(o != reg[REGARG])
+				reg[REGARG]--;
+		regret(&nod, n, l->type, 1);
+		if(nn != Z)
+			gmove(&nod, nn);
+		if(nod.op == OREGISTER)
+			regfree(&nod);
+		break;
+
+	case OIND:
+		if(nn == Z) {
+			nullwarn(l, Z);
+			break;
+		}
+		regialloc(&nod, n, nn);
+		r = l;
+		while(r->op == OADD)
+			r = r->right;
+		if(sconst(r) && (v = r->vconst+nod.xoffset) > -4096 && v < 4096) {
+			v = r->vconst;
+			r->vconst = 0;
+			cgen(l, &nod);
+			nod.xoffset += v;
+			r->vconst = v;
+		} else
+			cgen(l, &nod);
+		regind(&nod, n);
+		gopcode(OAS, &nod, Z, nn);
+		regfree(&nod);
+		break;
+
+	case OEQ:
+	case ONE:
+	case OLE:
+	case OLT:
+	case OGE:
+	case OGT:
+	case OLO:
+	case OLS:
+	case OHI:
+	case OHS:
+		if(nn == Z) {
+			nullwarn(l, r);
+			break;
+		}
+		boolgen(n, 1, nn);
+		break;
+
+	case OANDAND:
+	case OOROR:
+		boolgen(n, 1, nn);
+		if(nn == Z)
+			patch(p, pc);
+		break;
+
+	case ONOT:
+		if(nn == Z) {
+			nullwarn(l, Z);
+			break;
+		}
+		boolgen(n, 1, nn);
+		break;
+
+	case OCOMMA:
+		cgen(l, Z);
+		cgen(r, nn);
+		break;
+
+	case OCAST:
+		if(nn == Z) {
+			nullwarn(l, Z);
+			break;
+		}
+		/*
+		 * convert from types l->n->nn
+		 */
+		if(nocast(l->type, n->type)) {
+			if(nocast(n->type, nn->type)) {
+				cgen(l, nn);
+				break;
+			}
+		}
+		regalloc(&nod, l, nn);
+		cgen(l, &nod);
+		regalloc(&nod1, n, &nod);
+		if(inrel)
+			gmover(&nod, &nod1);
+		else
+			gopcode(OAS, &nod, Z, &nod1);
+		gopcode(OAS, &nod1, Z, nn);
+		regfree(&nod1);
+		regfree(&nod);
+		break;
+
+	case ODOT:
+		sugen(l, nodrat, l->type->width);
+		if(nn != Z) {
+			warn(n, "non-interruptable temporary");
+			nod = *nodrat;
+			if(!r || r->op != OCONST) {
+				diag(n, "DOT and no offset");
+				break;
+			}
+			nod.xoffset += (int32)r->vconst;
+			nod.type = n->type;
+			cgen(&nod, nn);
+		}
+		break;
+
+	case OCOND:
+		bcgen(l, 1);
+		p1 = p;
+		cgen(r->left, nn);
+		gbranch(OGOTO);
+		patch(p1, pc);
+		p1 = p;
+		cgen(r->right, nn);
+		patch(p1, pc);
+		break;
+
+	case OPOSTINC:
+	case OPOSTDEC:
+		v = 1;
+		if(l->type->etype == TIND)
+			v = l->type->link->width;
+		if(o == OPOSTDEC)
+			v = -v;
+		if(l->op == OBIT)
+			goto bitinc;
+		if(nn == Z)
+			goto pre;
+
+		if(l->addable < INDEXED)
+			reglcgen(&nod2, l, Z);
+		else
+			nod2 = *l;
+
+		regalloc(&nod, l, nn);
+		gopcode(OAS, &nod2, Z, &nod);
+		regalloc(&nod1, l, Z);
+		if(typefd[l->type->etype]) {
+			regalloc(&nod3, l, Z);
+			if(v < 0) {
+				gopcode(OAS, nodfconst(-v), Z, &nod3);
+				gopcode(OSUB, &nod3, &nod, &nod1);
+			} else {
+				gopcode(OAS, nodfconst(v), Z, &nod3);
+				gopcode(OADD, &nod3, &nod, &nod1);
+			}
+			regfree(&nod3);
+		} else
+			gopcode(OADD, nodconst(v), &nod, &nod1);
+		gopcode(OAS, &nod1, Z, &nod2);
+
+		regfree(&nod);
+		regfree(&nod1);
+		if(l->addable < INDEXED)
+			regfree(&nod2);
+		break;
+
+	case OPREINC:
+	case OPREDEC:
+		v = 1;
+		if(l->type->etype == TIND)
+			v = l->type->link->width;
+		if(o == OPREDEC)
+			v = -v;
+		if(l->op == OBIT)
+			goto bitinc;
+
+	pre:
+		if(l->addable < INDEXED)
+			reglcgen(&nod2, l, Z);
+		else
+			nod2 = *l;
+
+		regalloc(&nod, l, nn);
+		gopcode(OAS, &nod2, Z, &nod);
+		if(typefd[l->type->etype]) {
+			regalloc(&nod3, l, Z);
+			if(v < 0) {
+				gopcode(OAS, nodfconst(-v), Z, &nod3);
+				gopcode(OSUB, &nod3, Z, &nod);
+			} else {
+				gopcode(OAS, nodfconst(v), Z, &nod3);
+				gopcode(OADD, &nod3, Z, &nod);
+			}
+			regfree(&nod3);
+		} else
+			gopcode(OADD, nodconst(v), Z, &nod);
+		gopcode(OAS, &nod, Z, &nod2);
+
+		regfree(&nod);
+		if(l->addable < INDEXED)
+			regfree(&nod2);
+		break;
+
+	bitinc:
+		if(nn != Z && (o == OPOSTINC || o == OPOSTDEC)) {
+			bitload(l, &nod, &nod1, &nod2, Z);
+			gopcode(OAS, &nod, Z, nn);
+			gopcode(OADD, nodconst(v), Z, &nod);
+			bitstore(l, &nod, &nod1, &nod2, Z);
+			break;
+		}
+		bitload(l, &nod, &nod1, &nod2, nn);
+		gopcode(OADD, nodconst(v), Z, &nod);
+		bitstore(l, &nod, &nod1, &nod2, nn);
+		break;
+	}
+	cursafe = curs;
+	return;
+}
+
+void
+cgen(Node *n, Node *nn)
+{
+	_cgen(n, nn, 0);
+}
+
+void
+cgenrel(Node *n, Node *nn)
+{
+	_cgen(n, nn, 1);
+}
+
+void
+reglcgen(Node *t, Node *n, Node *nn)
+{
+	Node *r;
+	int32 v;
+
+	regialloc(t, n, nn);
+	if(n->op == OIND) {
+		r = n->left;
+		while(r->op == OADD)
+			r = r->right;
+		if(sconst(r) && (v = r->vconst+t->xoffset) > -4096 && v < 4096) {
+			v = r->vconst;
+			r->vconst = 0;
+			lcgen(n, t);
+			t->xoffset += v;
+			r->vconst = v;
+			regind(t, n);
+			return;
+		}
+	} else if(n->op == OINDREG) {
+		if((v = n->xoffset) > -4096 && v < 4096) {
+			n->op = OREGISTER;
+			cgen(n, t);
+			t->xoffset += v;
+			n->op = OINDREG;
+			regind(t, n);
+			return;
+		}
+	}
+	lcgen(n, t);
+	regind(t, n);
+}
+
+void
+reglpcgen(Node *n, Node *nn, int f)
+{
+	Type *t;
+
+	t = nn->type;
+	nn->type = types[TLONG];
+	if(f)
+		reglcgen(n, nn, Z);
+	else {
+		regialloc(n, nn, Z);
+		lcgen(nn, n);
+		regind(n, nn);
+	}
+	nn->type = t;
+}
+
+void
+lcgen(Node *n, Node *nn)
+{
+	Prog *p1;
+	Node nod;
+
+	if(debug['g']) {
+		prtree(nn, "lcgen lhs");
+		prtree(n, "lcgen");
+	}
+	if(n == Z || n->type == T)
+		return;
+	if(nn == Z) {
+		nn = &nod;
+		regalloc(&nod, n, Z);
+	}
+	switch(n->op) {
+	default:
+		if(n->addable < INDEXED) {
+			diag(n, "unknown op in lcgen: %O", n->op);
+			break;
+		}
+		nod = *n;
+		nod.op = OADDR;
+		nod.left = n;
+		nod.right = Z;
+		nod.type = types[TIND];
+		gopcode(OAS, &nod, Z, nn);
+		break;
+
+	case OCOMMA:
+		cgen(n->left, n->left);
+		lcgen(n->right, nn);
+		break;
+
+	case OIND:
+		cgen(n->left, nn);
+		break;
+
+	case OCOND:
+		bcgen(n->left, 1);
+		p1 = p;
+		lcgen(n->right->left, nn);
+		gbranch(OGOTO);
+		patch(p1, pc);
+		p1 = p;
+		lcgen(n->right->right, nn);
+		patch(p1, pc);
+		break;
+	}
+}
+
+void
+bcgen(Node *n, int true)
+{
+
+	if(n->type == T)
+		gbranch(OGOTO);
+	else
+		boolgen(n, true, Z);
+}
+
+void
+boolgen(Node *n, int true, Node *nn)
+{
+	int o;
+	Prog *p1, *p2;
+	Node *l, *r, nod, nod1;
+	int32 curs;
+
+	if(debug['g']) {
+		prtree(nn, "boolgen lhs");
+		prtree(n, "boolgen");
+	}
+	curs = cursafe;
+	l = n->left;
+	r = n->right;
+	switch(n->op) {
+
+	default:
+		regalloc(&nod, n, nn);
+		cgen(n, &nod);
+		o = ONE;
+		if(true)
+			o = comrel[relindex(o)];
+		if(typefd[n->type->etype]) {
+			gopcode(o, nodfconst(0), &nod, Z);
+		} else
+			gopcode(o, nodconst(0), &nod, Z);
+		regfree(&nod);
+		goto com;
+
+	case OCONST:
+		o = vconst(n);
+		if(!true)
+			o = !o;
+		gbranch(OGOTO);
+		if(o) {
+			p1 = p;
+			gbranch(OGOTO);
+			patch(p1, pc);
+		}
+		goto com;
+
+	case OCOMMA:
+		cgen(l, Z);
+		boolgen(r, true, nn);
+		break;
+
+	case ONOT:
+		boolgen(l, !true, nn);
+		break;
+
+	case OCOND:
+		bcgen(l, 1);
+		p1 = p;
+		bcgen(r->left, true);
+		p2 = p;
+		gbranch(OGOTO);
+		patch(p1, pc);
+		p1 = p;
+		bcgen(r->right, !true);
+		patch(p2, pc);
+		p2 = p;
+		gbranch(OGOTO);
+		patch(p1, pc);
+		patch(p2, pc);
+		goto com;
+
+	case OANDAND:
+		if(!true)
+			goto caseor;
+
+	caseand:
+		bcgen(l, true);
+		p1 = p;
+		bcgen(r, !true);
+		p2 = p;
+		patch(p1, pc);
+		gbranch(OGOTO);
+		patch(p2, pc);
+		goto com;
+
+	case OOROR:
+		if(!true)
+			goto caseand;
+
+	caseor:
+		bcgen(l, !true);
+		p1 = p;
+		bcgen(r, !true);
+		p2 = p;
+		gbranch(OGOTO);
+		patch(p1, pc);
+		patch(p2, pc);
+		goto com;
+
+	case OEQ:
+	case ONE:
+	case OLE:
+	case OLT:
+	case OGE:
+	case OGT:
+	case OHI:
+	case OHS:
+	case OLO:
+	case OLS:
+		o = n->op;
+		if(true)
+			o = comrel[relindex(o)];
+		if(l->complex >= FNX && r->complex >= FNX) {
+			regret(&nod, r, 0, 0);
+			cgenrel(r, &nod);
+			regsalloc(&nod1, r);
+			gopcode(OAS, &nod, Z, &nod1);
+			regfree(&nod);
+			nod = *n;
+			nod.right = &nod1;
+			boolgen(&nod, true, nn);
+			break;
+		}
+		if(sconst(l)) {
+			regalloc(&nod, r, nn);
+			cgenrel(r, &nod);
+			o = invrel[relindex(o)];
+			gopcode(o, l, &nod, Z);
+			regfree(&nod);
+			goto com;
+		}
+		if(sconst(r)) {
+			regalloc(&nod, l, nn);
+			cgenrel(l, &nod);
+			gopcode(o, r, &nod, Z);
+			regfree(&nod);
+			goto com;
+		}
+		if(l->complex >= r->complex) {
+			regalloc(&nod1, l, nn);
+			cgenrel(l, &nod1);
+			regalloc(&nod, r, Z);
+			cgenrel(r, &nod);
+		} else {
+			regalloc(&nod, r, nn);
+			cgenrel(r, &nod);
+			regalloc(&nod1, l, Z);
+			cgenrel(l, &nod1);
+		}
+		gopcode(o, &nod, &nod1, Z);
+		regfree(&nod);
+		regfree(&nod1);
+
+	com:
+		if(nn != Z) {
+			p1 = p;
+			gopcode(OAS, nodconst(1), Z, nn);
+			gbranch(OGOTO);
+			p2 = p;
+			patch(p1, pc);
+			gopcode(OAS, nodconst(0), Z, nn);
+			patch(p2, pc);
+		}
+		break;
+	}
+	cursafe = curs;
+}
+
+void
+sugen(Node *n, Node *nn, int32 w)
+{
+	Prog *p1;
+	Node nod0, nod1, nod2, nod3, nod4, *l, *r;
+	Type *t;
+	int32 pc1;
+	int i, m, c;
+
+	if(n == Z || n->type == T)
+		return;
+	if(debug['g']) {
+		prtree(nn, "sugen lhs");
+		prtree(n, "sugen");
+	}
+	if(nn == nodrat)
+		if(w > nrathole)
+			nrathole = w;
+	switch(n->op) {
+	case OIND:
+		if(nn == Z) {
+			nullwarn(n->left, Z);
+			break;
+		}
+
+	default:
+		goto copy;
+
+	case OCONST:
+		if(n->type && typev[n->type->etype]) {
+			if(nn == Z) {
+				nullwarn(n->left, Z);
+				break;
+			}
+
+			t = nn->type;
+			nn->type = types[TLONG];
+			reglcgen(&nod1, nn, Z);
+			nn->type = t;
+
+			if(isbigendian)
+				gopcode(OAS, nod32const(n->vconst>>32), Z, &nod1);
+			else
+				gopcode(OAS, nod32const(n->vconst), Z, &nod1);
+			nod1.xoffset += SZ_LONG;
+			if(isbigendian)
+				gopcode(OAS, nod32const(n->vconst), Z, &nod1);
+			else
+				gopcode(OAS, nod32const(n->vconst>>32), Z, &nod1);
+
+			regfree(&nod1);
+			break;
+		}
+		goto copy;
+
+	case ODOT:
+		l = n->left;
+		sugen(l, nodrat, l->type->width);
+		if(nn != Z) {
+			warn(n, "non-interruptable temporary");
+			nod1 = *nodrat;
+			r = n->right;
+			if(!r || r->op != OCONST) {
+				diag(n, "DOT and no offset");
+				break;
+			}
+			nod1.xoffset += (int32)r->vconst;
+			nod1.type = n->type;
+			sugen(&nod1, nn, w);
+		}
+		break;
+
+	case OSTRUCT:
+		/*
+		 * rewrite so lhs has no side effect.
+		 */
+		if(nn != Z && side(nn)) {
+			nod1 = *n;
+			nod1.type = typ(TIND, n->type);
+			regret(&nod2, &nod1, 0, 0);
+			lcgen(nn, &nod2);
+			regsalloc(&nod0, &nod1);
+			gopcode(OAS, &nod2, Z, &nod0);
+			regfree(&nod2);
+
+			nod1 = *n;
+			nod1.op = OIND;
+			nod1.left = &nod0;
+			nod1.right = Z;
+			nod1.complex = 1;
+
+			sugen(n, &nod1, w);
+			return;
+		}
+
+		r = n->left;
+		for(t = n->type->link; t != T; t = t->down) {
+			l = r;
+			if(r->op == OLIST) {
+				l = r->left;
+				r = r->right;
+			}
+			if(nn == Z) {
+				cgen(l, nn);
+				continue;
+			}
+			/*
+			 * hand craft *(&nn + o) = l
+			 */
+			nod0 = znode;
+			nod0.op = OAS;
+			nod0.type = t;
+			nod0.left = &nod1;
+			nod0.right = l;
+
+			nod1 = znode;
+			nod1.op = OIND;
+			nod1.type = t;
+			nod1.left = &nod2;
+
+			nod2 = znode;
+			nod2.op = OADD;
+			nod2.type = typ(TIND, t);
+			nod2.left = &nod3;
+			nod2.right = &nod4;
+
+			nod3 = znode;
+			nod3.op = OADDR;
+			nod3.type = nod2.type;
+			nod3.left = nn;
+
+			nod4 = znode;
+			nod4.op = OCONST;
+			nod4.type = nod2.type;
+			nod4.vconst = t->offset;
+
+			ccom(&nod0);
+			acom(&nod0);
+			xcom(&nod0);
+			nod0.addable = 0;
+
+			cgen(&nod0, Z);
+		}
+		break;
+
+	case OAS:
+		if(nn == Z) {
+			if(n->addable < INDEXED)
+				sugen(n->right, n->left, w);
+			break;
+		}
+		sugen(n->right, nodrat, w);
+		warn(n, "non-interruptable temporary");
+		sugen(nodrat, n->left, w);
+		sugen(nodrat, nn, w);
+		break;
+
+	case OFUNC:
+		if(!hasdotdotdot(n->left->type)) {
+			cgen(n, Z);
+			if(nn != Z) {
+				curarg -= n->type->width;
+				regret(&nod1, n, n->left->type, 1);
+				if(nn->complex >= FNX) {
+					regsalloc(&nod2, n);
+					cgen(&nod1, &nod2);
+					nod1 = nod2;
+				}
+				cgen(&nod1, nn);
+			}
+			break;
+		}
+		if(nn == Z) {
+			sugen(n, nodrat, w);
+			break;
+		}
+		if(nn->op != OIND) {
+			nn = new1(OADDR, nn, Z);
+			nn->type = types[TIND];
+			nn->addable = 0;
+		} else
+			nn = nn->left;
+		n = new(OFUNC, n->left, new(OLIST, nn, n->right));
+		n->type = types[TVOID];
+		n->left->type = types[TVOID];
+		cgen(n, Z);
+		break;
+
+	case OCOND:
+		bcgen(n->left, 1);
+		p1 = p;
+		sugen(n->right->left, nn, w);
+		gbranch(OGOTO);
+		patch(p1, pc);
+		p1 = p;
+		sugen(n->right->right, nn, w);
+		patch(p1, pc);
+		break;
+
+	case OCOMMA:
+		cgen(n->left, Z);
+		sugen(n->right, nn, w);
+		break;
+	}
+	return;
+
+copy:
+	if(nn == Z)
+		return;
+	if(n->complex >= FNX && nn->complex >= FNX) {
+		t = nn->type;
+		nn->type = types[TLONG];
+		regialloc(&nod1, nn, Z);
+		lcgen(nn, &nod1);
+		regsalloc(&nod2, nn);
+		nn->type = t;
+
+		gopcode(OAS, &nod1, Z, &nod2);
+		regfree(&nod1);
+
+		nod2.type = typ(TIND, t);
+
+		nod1 = nod2;
+		nod1.op = OIND;
+		nod1.left = &nod2;
+		nod1.right = Z;
+		nod1.complex = 1;
+		nod1.type = t;
+
+		sugen(n, &nod1, w);
+		return;
+	}
+
+	w /= SZ_LONG;
+	if(w <= 2) {
+		if(n->complex > nn->complex) {
+			reglpcgen(&nod1, n, 1);
+			reglpcgen(&nod2, nn, 1);
+		} else {
+			reglpcgen(&nod2, nn, 1);
+			reglpcgen(&nod1, n, 1);
+		}
+		regalloc(&nod3, &regnode, Z);
+		regalloc(&nod4, &regnode, Z);
+		nod0 = *nodconst((1<<nod3.reg)|(1<<nod4.reg));
+		if(w == 2 && nod1.xoffset == 0)
+			gmovm(&nod1, &nod0, 0);
+		else {
+			gmove(&nod1, &nod3);
+			if(w == 2) {
+				nod1.xoffset += SZ_LONG;
+				gmove(&nod1, &nod4);
+			}
+		}
+		if(w == 2 && nod2.xoffset == 0)
+			gmovm(&nod0, &nod2, 0);
+		else {
+			gmove(&nod3, &nod2);
+			if(w == 2) {
+				nod2.xoffset += SZ_LONG;
+				gmove(&nod4, &nod2);
+			}
+		}
+		regfree(&nod1);
+		regfree(&nod2);
+		regfree(&nod3);
+		regfree(&nod4);
+		return;
+	}
+
+	if(n->complex > nn->complex) {
+		reglpcgen(&nod1, n, 0);
+		reglpcgen(&nod2, nn, 0);
+	} else {
+		reglpcgen(&nod2, nn, 0);
+		reglpcgen(&nod1, n, 0);
+	}
+
+	m = 0;
+	for(c = 0; c < w && c < 4; c++) {
+		i = tmpreg();
+		if (i == 0)
+			break;
+		reg[i]++;
+		m |= 1<<i;
+	}
+	nod4 = *(nodconst(m));
+	if(w < 3*c) {
+		for (; w>c; w-=c) {
+			gmovm(&nod1, &nod4, 1);
+			gmovm(&nod4, &nod2, 1);
+		}
+		goto out;
+	}
+
+	regalloc(&nod3, &regnode, Z);
+	gopcode(OAS, nodconst(w/c), Z, &nod3);
+	w %= c;
+
+	pc1 = pc;
+	gmovm(&nod1, &nod4, 1);
+	gmovm(&nod4, &nod2, 1);
+
+	gopcode(OSUB, nodconst(1), Z, &nod3);
+	gopcode(OEQ, nodconst(0), &nod3, Z);
+	p->as = ABGT;
+	patch(p, pc1);
+	regfree(&nod3);
+
+out:
+	if (w) {
+		i = 0;
+		while (c>w) {
+			while ((m&(1<<i)) == 0)
+				i++;
+			m &= ~(1<<i);
+			reg[i] = 0;
+			c--;
+			i++;
+		}
+		nod4.vconst = m;
+		gmovm(&nod1, &nod4, 0);
+		gmovm(&nod4, &nod2, 0);
+	}
+	i = 0;
+	do {
+		while ((m&(1<<i)) == 0)
+			i++;
+		reg[i] = 0;
+		c--;
+		i++;
+	} while (c>0);
+	regfree(&nod1);
+	regfree(&nod2);
+}
diff --git a/src/cmd/5c/doc.go b/src/cmd/5c/doc.go
new file mode 100644
index 0000000..7291d45
--- /dev/null
+++ b/src/cmd/5c/doc.go
@@ -0,0 +1,16 @@
+// 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
+
+/*
+
+5c is a version of the Plan 9 C compiler.  The original is documented at
+
+	http://plan9.bell-labs.com/magic/man2html/1/8c
+
+Its target architecture is the ARM, referred to by these tools as arm.
+
+*/
+package main
diff --git a/src/cmd/5c/gc.h b/src/cmd/5c/gc.h
new file mode 100644
index 0000000..7417b7d
--- /dev/null
+++ b/src/cmd/5c/gc.h
@@ -0,0 +1,333 @@
+// Inferno utils/5c/gc.h
+// http://code.google.com/p/inferno-os/source/browse/utils/5c/gc.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.
+
+#include	<u.h>
+#include	"../cc/cc.h"
+#include	"../5l/5.out.h"
+
+/*
+ * 5c/arm
+ * Arm 7500
+ */
+#define	SZ_CHAR		1
+#define	SZ_SHORT	2
+#define	SZ_INT		4
+#define	SZ_LONG		4
+#define	SZ_IND		4
+#define	SZ_FLOAT	4
+#define	SZ_VLONG	8
+#define	SZ_DOUBLE	8
+#define	FNX		100
+
+typedef	struct	Case	Case;
+typedef	struct	C1	C1;
+typedef	struct	Multab	Multab;
+typedef	struct	Hintab	Hintab;
+typedef	struct	Reg	Reg;
+typedef	struct	Rgn	Rgn;
+
+
+#define	R0ISZERO	0
+
+#define	A	((Addr*)0)
+
+#define	INDEXED	9
+#define	P	((Prog*)0)
+
+struct	Case
+{
+	Case*	link;
+	int32	val;
+	int32	label;
+	char	def;
+	char	isv;
+};
+#define	C	((Case*)0)
+
+struct	C1
+{
+	int32	val;
+	int32	label;
+};
+
+struct	Multab
+{
+	int32	val;
+	char	code[20];
+};
+
+struct	Hintab
+{
+	ushort	val;
+	char	hint[10];
+};
+
+struct	Reg
+{
+	int32	pc;
+	int32	rpo;		/* reverse post ordering */
+
+	Bits	set;
+	Bits	use1;
+	Bits	use2;
+
+	Bits	refbehind;
+	Bits	refahead;
+	Bits	calbehind;
+	Bits	calahead;
+	Bits	regdiff;
+	Bits	act;
+
+	int32	regu;
+	int32	loop;		/* could be shorter */
+
+
+	Reg*	log5;
+	int32	active;
+
+	Reg*	p1;
+	Reg*	p2;
+	Reg*	p2link;
+	Reg*	s1;
+	Reg*	s2;
+	Reg*	link;
+	Prog*	prog;
+};
+#define	R	((Reg*)0)
+
+#define	NRGN	600
+struct	Rgn
+{
+	Reg*	enter;
+	short	cost;
+	short	varno;
+	short	regno;
+};
+
+EXTERN	int32	breakpc;
+EXTERN	int32	nbreak;
+EXTERN	Case*	cases;
+EXTERN	Node	constnode;
+EXTERN	Node	fconstnode;
+EXTERN	int32	continpc;
+EXTERN	int32	curarg;
+EXTERN	int32	cursafe;
+EXTERN	int32	isbigendian;
+EXTERN	Prog*	lastp;
+EXTERN	int32	maxargsafe;
+EXTERN	int	mnstring;
+EXTERN	Multab	multab[20];
+extern	int	hintabsize;
+EXTERN	Node*	nodrat;
+EXTERN	Node*	nodret;
+EXTERN	Node*	nodsafe;
+EXTERN	int32	nrathole;
+EXTERN	int32	nstring;
+EXTERN	Prog*	p;
+EXTERN	int32	pc;
+EXTERN	Node	regnode;
+EXTERN	char	string[NSNAME];
+EXTERN	Sym*	symrathole;
+EXTERN	Node	znode;
+EXTERN	Prog	zprog;
+EXTERN	char	reg[NREG+NFREG];
+EXTERN	int32	exregoffset;
+EXTERN	int32	exfregoffset;
+EXTERN	int	suppress;
+
+#define	BLOAD(r)	band(bnot(r->refbehind), r->refahead)
+#define	BSTORE(r)	band(bnot(r->calbehind), r->calahead)
+#define	LOAD(r)		(~r->refbehind.b[z] & r->refahead.b[z])
+#define	STORE(r)	(~r->calbehind.b[z] & r->calahead.b[z])
+
+#define	bset(a,n)	((a).b[(n)/32]&(1L<<(n)%32))
+
+#define	CLOAD	4
+#define	CREF	5
+#define	CINF	1000
+#define	LOOP	3
+
+EXTERN	Rgn	region[NRGN];
+EXTERN	Rgn*	rgp;
+EXTERN	int	nregion;
+EXTERN	int	nvar;
+
+EXTERN	Bits	externs;
+EXTERN	Bits	params;
+EXTERN	Bits	consts;
+EXTERN	Bits	addrs;
+
+EXTERN	int32	regbits;
+EXTERN	int32	exregbits;
+
+EXTERN	int	change;
+
+EXTERN	Reg*	firstr;
+EXTERN	Reg*	lastr;
+EXTERN	Reg	zreg;
+EXTERN	Reg*	freer;
+EXTERN	int32*	idom;
+EXTERN	Reg**	rpo2r;
+EXTERN	int32	maxnr;
+
+extern	char*	anames[];
+extern	Hintab	hintab[];
+
+/*
+ * sgen.c
+ */
+void	codgen(Node*, Node*);
+void	gen(Node*);
+void	noretval(int);
+void	usedset(Node*, int);
+void	xcom(Node*);
+int	bcomplex(Node*, Node*);
+Prog*	gtext(Sym*, int32);
+vlong	argsize(int);
+
+/*
+ * cgen.c
+ */
+void	cgen(Node*, Node*);
+void	reglcgen(Node*, Node*, Node*);
+void	lcgen(Node*, Node*);
+void	bcgen(Node*, int);
+void	boolgen(Node*, int, Node*);
+void	sugen(Node*, Node*, int32);
+void	layout(Node*, Node*, int, int, Node*);
+void	cgenrel(Node*, Node*);
+
+/*
+ * txt.c
+ */
+void	ginit(void);
+void	gclean(void);
+void	nextpc(void);
+void	gargs(Node*, Node*, Node*);
+void	garg1(Node*, Node*, Node*, int, Node**);
+Node*	nodconst(int32);
+Node*	nod32const(vlong);
+Node*	nodfconst(double);
+void	nodreg(Node*, Node*, int);
+void	regret(Node*, Node*, Type*, int);
+int	tmpreg(void);
+void	regalloc(Node*, Node*, Node*);
+void	regfree(Node*);
+void	regialloc(Node*, Node*, Node*);
+void	regsalloc(Node*, Node*);
+void	regaalloc1(Node*, Node*);
+void	regaalloc(Node*, Node*);
+void	regind(Node*, Node*);
+void	gprep(Node*, Node*);
+void	raddr(Node*, Prog*);
+void	naddr(Node*, Addr*);
+void	gmovm(Node*, Node*, int);
+void	gmove(Node*, Node*);
+void	gmover(Node*, Node*);
+void	gins(int a, Node*, Node*);
+void	gopcode(int, Node*, Node*, Node*);
+int	samaddr(Node*, Node*);
+void	gbranch(int);
+void	patch(Prog*, int32);
+int	sconst(Node*);
+int	sval(int32);
+void	gpseudo(int, Sym*, Node*);
+void	gprefetch(Node*);
+void	gpcdata(int, int);
+
+/*
+ * swt.c
+ */
+int	swcmp(const void*, const void*);
+void	doswit(Node*);
+void	swit1(C1*, int, int32, Node*);
+void	swit2(C1*, int, int32, Node*);
+void	newcase(void);
+void	bitload(Node*, Node*, Node*, Node*, Node*);
+void	bitstore(Node*, Node*, Node*, Node*, Node*);
+int	mulcon(Node*, Node*);
+Multab*	mulcon0(int32);
+void	nullwarn(Node*, Node*);
+void	outcode(void);
+
+/*
+ * list
+ */
+void	listinit(void);
+
+/*
+ * reg.c
+ */
+Reg*	rega(void);
+int	rcmp(const void*, const void*);
+void	regopt(Prog*);
+void	addmove(Reg*, int, int, int);
+Bits	mkvar(Addr*, int);
+void	prop(Reg*, Bits, Bits);
+void	loopit(Reg*, int32);
+void	synch(Reg*, Bits);
+uint32	allreg(uint32, Rgn*);
+void	paint1(Reg*, int);
+uint32	paint2(Reg*, int);
+void	paint3(Reg*, int, int32, int);
+void	addreg(Addr*, int);
+
+/*
+ * peep.c
+ */
+void	peep(void);
+void	excise(Reg*);
+Reg*	uniqp(Reg*);
+Reg*	uniqs(Reg*);
+int	regtyp(Addr*);
+int	regzer(Addr*);
+int	anyvar(Addr*);
+int	subprop(Reg*);
+int	copyprop(Reg*);
+int	shiftprop(Reg*);
+void	constprop(Addr*, Addr*, Reg*);
+int	copy1(Addr*, Addr*, Reg*, int);
+int	copyu(Prog*, Addr*, Addr*);
+
+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);
+int	BtoR(int32);
+int	BtoF(int32);
+
+void	predicate(void);
+int	isbranch(Prog *);
+int	predicable(Prog *p);
+int	modifiescpsr(Prog *p);
diff --git a/src/cmd/5c/list.c b/src/cmd/5c/list.c
new file mode 100644
index 0000000..98da424
--- /dev/null
+++ b/src/cmd/5c/list.c
@@ -0,0 +1,39 @@
+// 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.
+
+
+#define	EXTERN
+#include "gc.h"
+
+void
+listinit(void)
+{
+	listinit5();
+}
diff --git a/src/cmd/5c/mul.c b/src/cmd/5c/mul.c
new file mode 100644
index 0000000..ff50c48
--- /dev/null
+++ b/src/cmd/5c/mul.c
@@ -0,0 +1,640 @@
+// Inferno utils/5c/mul.c
+// http://code.google.com/p/inferno-os/source/browse/utils/5c/mul.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 "gc.h"
+
+/*
+ * code sequences for multiply by constant.
+ * [a-l][0-3]
+ *	lsl	$(A-'a'),r0,r1
+ * [+][0-7]
+ *	add	r0,r1,r2
+ * [-][0-7]
+ *	sub	r0,r1,r2
+ */
+
+static  int	maxmulops = 3;	/* max # of ops to replace mul with */
+static	int	multabp;
+static	int32	mulval;
+static	char*	mulcp;
+static	int32	valmax;
+static	int	shmax;
+
+static int	docode(char *hp, char *cp, int r0, int r1);
+static int	gen1(int len);
+static int	gen2(int len, int32 r1);
+static int	gen3(int len, int32 r0, int32 r1, int flag);
+enum
+{
+	SR1	= 1<<0,		/* r1 has been shifted */
+	SR0	= 1<<1,		/* r0 has been shifted */
+	UR1	= 1<<2,		/* r1 has not been used */
+	UR0	= 1<<3,		/* r0 has not been used */
+};
+
+Multab*
+mulcon0(int32 v)
+{
+	int a1, a2, g;
+	Multab *m, *m1;
+	char hint[10];
+
+	if(v < 0)
+		v = -v;
+
+	/*
+	 * look in cache
+	 */
+	m = multab;
+	for(g=0; g<nelem(multab); g++) {
+		if(m->val == v) {
+			if(m->code[0] == 0)
+				return 0;
+			return m;
+		}
+		m++;
+	}
+
+	/*
+	 * select a spot in cache to overwrite
+	 */
+	multabp++;
+	if(multabp < 0 || multabp >= nelem(multab))
+		multabp = 0;
+	m = multab+multabp;
+	m->val = v;
+	mulval = v;
+
+	/*
+	 * look in execption hint table
+	 */
+	a1 = 0;
+	a2 = hintabsize;
+	for(;;) {
+		if(a1 >= a2)
+			goto no;
+		g = (a2 + a1)/2;
+		if(v < hintab[g].val) {
+			a2 = g;
+			continue;
+		}
+		if(v > hintab[g].val) {
+			a1 = g+1;
+			continue;
+		}
+		break;
+	}
+
+	if(docode(hintab[g].hint, m->code, 1, 0))
+		return m;
+	print("multiply table failure %d\n", v);
+	m->code[0] = 0;
+	return 0;
+
+no:
+	/*
+	 * try to search
+	 */
+	hint[0] = 0;
+	for(g=1; g<=maxmulops; g++) {
+		if(g >= maxmulops && v >= 65535)
+			break;
+		mulcp = hint+g;
+		*mulcp = 0;
+		if(gen1(g)) {
+			if(docode(hint, m->code, 1, 0))
+				return m;
+			print("multiply table failure %d\n", v);
+			break;
+		}
+	}
+
+	/*
+	 * try a recur followed by a shift
+	 */
+	g = 0;
+	while(!(v & 1)) {
+		g++;
+		v >>= 1;
+	}
+	if(g) {
+		m1 = mulcon0(v);
+		if(m1) {
+			strcpy(m->code, m1->code);
+			sprint(strchr(m->code, 0), "%c0", g+'a');
+			return m;
+		}
+	}
+	m->code[0] = 0;
+	return 0;
+}
+
+static int
+docode(char *hp, char *cp, int r0, int r1)
+{
+	int c, i;
+
+	c = *hp++;
+	*cp = c;
+	cp += 2;
+	switch(c) {
+	default:
+		c -= 'a';
+		if(c < 1 || c >= 30)
+			break;
+		for(i=0; i<4; i++) {
+			switch(i) {
+			case 0:
+				if(docode(hp, cp, r0<<c, r1))
+					goto out;
+				break;
+			case 1:
+				if(docode(hp, cp, r1<<c, r1))
+					goto out;
+				break;
+			case 2:
+				if(docode(hp, cp, r0, r0<<c))
+					goto out;
+				break;
+			case 3:
+				if(docode(hp, cp, r0, r1<<c))
+					goto out;
+				break;
+			}
+		}
+		break;
+
+	case '+':
+		for(i=0; i<8; i++) {
+			cp[-1] = i+'0';
+			switch(i) {
+			case 1:
+				if(docode(hp, cp, r0+r1, r1))
+					goto out;
+				break;
+			case 5:
+				if(docode(hp, cp, r0, r0+r1))
+					goto out;
+				break;
+			}
+		}
+		break;
+
+	case '-':
+		for(i=0; i<8; i++) {
+			cp[-1] = i+'0';
+			switch(i) {
+			case 1:
+				if(docode(hp, cp, r0-r1, r1))
+					goto out;
+				break;
+			case 2:
+				if(docode(hp, cp, r1-r0, r1))
+					goto out;
+				break;
+			case 5:
+				if(docode(hp, cp, r0, r0-r1))
+					goto out;
+				break;
+			case 6:
+				if(docode(hp, cp, r0, r1-r0))
+					goto out;
+				break;
+			}
+		}
+		break;
+
+	case 0:
+		if(r0 == mulval)
+			return 1;
+	}
+	return 0;
+
+out:
+	cp[-1] = i+'0';
+	return 1;
+}
+
+static int
+gen1(int len)
+{
+	int i;
+
+	for(shmax=1; shmax<30; shmax++) {
+		valmax = 1<<shmax;
+		if(valmax >= mulval)
+			break;
+	}
+	if(mulval == 1)
+		return 1;
+
+	len--;
+	for(i=1; i<=shmax; i++)
+		if(gen2(len, 1<<i)) {
+			*--mulcp = 'a'+i;
+			return 1;
+		}
+	return 0;
+}
+
+static int
+gen2(int len, int32 r1)
+{
+	int i;
+
+	if(len <= 0) {
+		if(r1 == mulval)
+			return 1;
+		return 0;
+	}
+
+	len--;
+	if(len == 0)
+		goto calcr0;
+
+	if(gen3(len, r1, r1+1, UR1)) {
+		i = '+';
+		goto out;
+	}
+	if(gen3(len, r1-1, r1, UR0)) {
+		i = '-';
+		goto out;
+	}
+	if(gen3(len, 1, r1+1, UR1)) {
+		i = '+';
+		goto out;
+	}
+	if(gen3(len, 1, r1-1, UR1)) {
+		i = '-';
+		goto out;
+	}
+
+	return 0;
+
+calcr0:
+	if(mulval == r1+1) {
+		i = '+';
+		goto out;
+	}
+	if(mulval == r1-1) {
+		i = '-';
+		goto out;
+	}
+	return 0;
+
+out:
+	*--mulcp = i;
+	return 1;
+}
+
+static int
+gen3(int len, int32 r0, int32 r1, int flag)
+{
+	int i, f1, f2;
+	int32 x;
+
+	if(r0 <= 0 ||
+	   r0 >= r1 ||
+	   r1 > valmax)
+		return 0;
+
+	len--;
+	if(len == 0)
+		goto calcr0;
+
+	if(!(flag & UR1)) {
+		f1 = UR1|SR1;
+		for(i=1; i<=shmax; i++) {
+			x = r0<<i;
+			if(x > valmax)
+				break;
+			if(gen3(len, r0, x, f1)) {
+				i += 'a';
+				goto out;
+			}
+		}
+	}
+
+	if(!(flag & UR0)) {
+		f1 = UR1|SR1;
+		for(i=1; i<=shmax; i++) {
+			x = r1<<i;
+			if(x > valmax)
+				break;
+			if(gen3(len, r1, x, f1)) {
+				i += 'a';
+				goto out;
+			}
+		}
+	}
+
+	if(!(flag & SR1)) {
+		f1 = UR1|SR1|(flag&UR0);
+		for(i=1; i<=shmax; i++) {
+			x = r1<<i;
+			if(x > valmax)
+				break;
+			if(gen3(len, r0, x, f1)) {
+				i += 'a';
+				goto out;
+			}
+		}
+	}
+
+	if(!(flag & SR0)) {
+		f1 = UR0|SR0|(flag&(SR1|UR1));
+
+		f2 = UR1|SR1;
+		if(flag & UR1)
+			f2 |= UR0;
+		if(flag & SR1)
+			f2 |= SR0;
+
+		for(i=1; i<=shmax; i++) {
+			x = r0<<i;
+			if(x > valmax)
+				break;
+			if(x > r1) {
+				if(gen3(len, r1, x, f2)) {
+					i += 'a';
+					goto out;
+				}
+			} else
+				if(gen3(len, x, r1, f1)) {
+					i += 'a';
+					goto out;
+				}
+		}
+	}
+
+	x = r1+r0;
+	if(gen3(len, r0, x, UR1)) {
+		i = '+';
+		goto out;
+	}
+
+	if(gen3(len, r1, x, UR1)) {
+		i = '+';
+		goto out;
+	}
+
+	x = r1-r0;
+	if(gen3(len, x, r1, UR0)) {
+		i = '-';
+		goto out;
+	}
+
+	if(x > r0) {
+		if(gen3(len, r0, x, UR1)) {
+			i = '-';
+			goto out;
+		}
+	} else
+		if(gen3(len, x, r0, UR0)) {
+			i = '-';
+			goto out;
+		}
+
+	return 0;
+
+calcr0:
+	f1 = flag & (UR0|UR1);
+	if(f1 == UR1) {
+		for(i=1; i<=shmax; i++) {
+			x = r1<<i;
+			if(x >= mulval) {
+				if(x == mulval) {
+					i += 'a';
+					goto out;
+				}
+				break;
+			}
+		}
+	}
+
+	if(mulval == r1+r0) {
+		i = '+';
+		goto out;
+	}
+	if(mulval == r1-r0) {
+		i = '-';
+		goto out;
+	}
+
+	return 0;
+
+out:
+	*--mulcp = i;
+	return 1;
+}
+
+/*
+ * hint table has numbers that
+ * the search algorithm fails on.
+ * <1000:
+ *	all numbers
+ * <5000:
+ * 	÷ by 5
+ * <10000:
+ * 	÷ by 50
+ * <65536:
+ * 	÷ by 250
+ */
+Hintab	hintab[] =
+{
+	683,	"b++d+e+",
+	687,	"b+e++e-",
+	691,	"b++d+e+",
+	731,	"b++d+e+",
+	811,	"b++d+i+",
+	821,	"b++e+e+",
+	843,	"b+d++e+",
+	851,	"b+f-+e-",
+	853,	"b++e+e+",
+	877,	"c++++g-",
+	933,	"b+c++g-",
+	981,	"c-+e-d+",
+	1375,	"b+c+b+h-",
+	1675,	"d+b++h+",
+	2425,	"c++f-e+",
+	2675,	"c+d++f-",
+	2750,	"b+d-b+h-",
+	2775,	"c-+g-e-",
+	3125,	"b++e+g+",
+	3275,	"b+c+g+e+",
+	3350,	"c++++i+",
+	3475,	"c-+e-f-",
+	3525,	"c-+d+g-",
+	3625,	"c-+e-j+",
+	3675,	"b+d+d+e+",
+	3725,	"b+d-+h+",
+	3925,	"b+d+f-d-",
+	4275,	"b+g++e+",
+	4325,	"b+h-+d+",
+	4425,	"b+b+g-j-",
+	4525,	"b+d-d+f+",
+	4675,	"c++d-g+",
+	4775,	"b+d+b+g-",
+	4825,	"c+c-+i-",
+	4850,	"c++++i-",
+	4925,	"b++e-g-",
+	4975,	"c+f++e-",
+	5500,	"b+g-c+d+",
+	6700,	"d+b++i+",
+	9700,	"d++++j-",
+	11000,	"b+f-c-h-",
+	11750,	"b+d+g+j-",
+	12500,	"b+c+e-k+",
+	13250,	"b+d+e-f+",
+	13750,	"b+h-c-d+",
+	14250,	"b+g-c+e-",
+	14500,	"c+f+j-d-",
+	14750,	"d-g--f+",
+	16750,	"b+e-d-n+",
+	17750,	"c+h-b+e+",
+	18250,	"d+b+h-d+",
+	18750,	"b+g-++f+",
+	19250,	"b+e+b+h+",
+	19750,	"b++h--f-",
+	20250,	"b+e-l-c+",
+	20750,	"c++bi+e-",
+	21250,	"b+i+l+c+",
+	22000,	"b+e+d-g-",
+	22250,	"b+d-h+k-",
+	22750,	"b+d-e-g+",
+	23250,	"b+c+h+e-",
+	23500,	"b+g-c-g-",
+	23750,	"b+g-b+h-",
+	24250,	"c++g+m-",
+	24750,	"b+e+e+j-",
+	25000,	"b++dh+g+",
+	25250,	"b+e+d-g-",
+	25750,	"b+e+b+j+",
+	26250,	"b+h+c+e+",
+	26500,	"b+h+c+g+",
+	26750,	"b+d+e+g-",
+	27250,	"b+e+e+f+",
+	27500,	"c-i-c-d+",
+	27750,	"b+bd++j+",
+	28250,	"d-d-++i-",
+	28500,	"c+c-h-e-",
+	29000,	"b+g-d-f+",
+	29500,	"c+h+++e-",
+	29750,	"b+g+f-c+",
+	30250,	"b+f-g-c+",
+	33500,	"c-f-d-n+",
+	33750,	"b+d-b+j-",
+	34250,	"c+e+++i+",
+	35250,	"e+b+d+k+",
+	35500,	"c+e+d-g-",
+	35750,	"c+i-++e+",
+	36250,	"b+bh-d+e+",
+	36500,	"c+c-h-e-",
+	36750,	"d+e--i+",
+	37250,	"b+g+g+b+",
+	37500,	"b+h-b+f+",
+	37750,	"c+be++j-",
+	38500,	"b+e+b+i+",
+	38750,	"d+i-b+d+",
+	39250,	"b+g-l-+d+",
+	39500,	"b+g-c+g-",
+	39750,	"b+bh-c+f-",
+	40250,	"b+bf+d+g-",
+	40500,	"b+g-c+g+",
+	40750,	"c+b+i-e+",
+	41250,	"d++bf+h+",
+	41500,	"b+j+c+d-",
+	41750,	"c+f+b+h-",
+	42500,	"c+h++g+",
+	42750,	"b+g+d-f-",
+	43250,	"b+l-e+d-",
+	43750,	"c+bd+h+f-",
+	44000,	"b+f+g-d-",
+	44250,	"b+d-g--f+",
+	44500,	"c+e+c+h+",
+	44750,	"b+e+d-h-",
+	45250,	"b++g+j-g+",
+	45500,	"c+d+e-g+",
+	45750,	"b+d-h-e-",
+	46250,	"c+bd++j+",
+	46500,	"b+d-c-j-",
+	46750,	"e-e-b+g-",
+	47000,	"b+c+d-j-",
+	47250,	"b+e+e-g-",
+	47500,	"b+g-c-h-",
+	47750,	"b+f-c+h-",
+	48250,	"d--h+n-",
+	48500,	"b+c-g+m-",
+	48750,	"b+e+e-g+",
+	49500,	"c-f+e+j-",
+	49750,	"c+c+g++f-",
+	50000,	"b+e+e+k+",
+	50250,	"b++i++g+",
+	50500,	"c+g+f-i+",
+	50750,	"b+e+d+k-",
+	51500,	"b+i+c-f+",
+	51750,	"b+bd+g-e-",
+	52250,	"b+d+g-j+",
+	52500,	"c+c+f+g+",
+	52750,	"b+c+e+i+",
+	53000,	"b+i+c+g+",
+	53500,	"c+g+g-n+",
+	53750,	"b+j+d-c+",
+	54250,	"b+d-g-j-",
+	54500,	"c-f+e+f+",
+	54750,	"b+f-+c+g+",
+	55000,	"b+g-d-g-",
+	55250,	"b+e+e+g+",
+	55500,	"b+cd++j+",
+	55750,	"b+bh-d-f-",
+	56250,	"c+d-b+j-",
+	56500,	"c+d+c+i+",
+	56750,	"b+e+d++h-",
+	57000,	"b+d+g-f+",
+	57250,	"b+f-m+d-",
+	57750,	"b+i+c+e-",
+	58000,	"b+e+d+h+",
+	58250,	"c+b+g+g+",
+	58750,	"d-e-j--e+",
+	59000,	"d-i-+e+",
+	59250,	"e--h-m+",
+	59500,	"c+c-h+f-",
+	59750,	"b+bh-e+i-",
+	60250,	"b+bh-e-e-",
+	60500,	"c+c-g-g-",
+	60750,	"b+e-l-e-",
+	61250,	"b+g-g-c+",
+	61750,	"b+g-c+g+",
+	62250,	"f--+c-i-",
+	62750,	"e+f--+g+",
+	64750,	"b+f+d+p-",
+};
+int	hintabsize	= nelem(hintab);
diff --git a/src/cmd/5c/peep.c b/src/cmd/5c/peep.c
new file mode 100644
index 0000000..1de56b5
--- /dev/null
+++ b/src/cmd/5c/peep.c
@@ -0,0 +1,1478 @@
+// Inferno utils/5c/peep.c
+// http://code.google.com/p/inferno-os/source/browse/utils/5c/peep.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 "gc.h"
+
+int xtramodes(Reg*, Addr*);
+
+void
+peep(void)
+{
+	Reg *r, *r1, *r2;
+	Prog *p, *p1;
+	int t;
+/*
+ * complete R structure
+ */
+	t = 0;
+	for(r=firstr; r!=R; r=r1) {
+		r1 = r->link;
+		if(r1 == R)
+			break;
+		p = r->prog->link;
+		while(p != r1->prog)
+		switch(p->as) {
+		default:
+			r2 = rega();
+			r->link = r2;
+			r2->link = r1;
+
+			r2->prog = p;
+			r2->p1 = r;
+			r->s1 = r2;
+			r2->s1 = r1;
+			r1->p1 = r2;
+
+			r = r2;
+			t++;
+
+		case ADATA:
+		case AGLOBL:
+		case ANAME:
+		case ASIGNAME:
+			p = p->link;
+		}
+	}
+
+loop1:
+	t = 0;
+	for(r=firstr; r!=R; r=r->link) {
+		p = r->prog;
+		if(p->as == ASLL || p->as == ASRL || p->as == ASRA) {
+			/*
+			 * elide shift into D_SHIFT operand of subsequent instruction
+			 */
+			if(shiftprop(r)) {
+				excise(r);
+				t++;
+			}
+		}
+		if(p->as == AMOVW || p->as == AMOVF || p->as == AMOVD)
+		if(regtyp(&p->to)) {
+			if(p->from.type == D_CONST)
+				constprop(&p->from, &p->to, r->s1);
+			else if(regtyp(&p->from))
+			if(p->from.type == p->to.type) {
+				if(copyprop(r)) {
+					excise(r);
+					t++;
+				} else
+				if(subprop(r) && copyprop(r)) {
+					excise(r);
+					t++;
+				}
+			}
+		}
+	}
+	if(t)
+		goto loop1;
+	/*
+	 * look for MOVB x,R; MOVB R,R
+	 */
+	for(r=firstr; r!=R; r=r->link) {
+		p = r->prog;
+		switch(p->as) {
+		default:
+			continue;
+		case AEOR:
+			/*
+			 * EOR -1,x,y => MVN x,y
+			 */
+			if(p->from.type == D_CONST && p->from.offset == -1) {
+				p->as = AMVN;
+				p->from.type = D_REG;
+				if(p->reg != NREG)
+					p->from.reg = p->reg;
+				else
+					p->from.reg = p->to.reg;
+				p->reg = NREG;
+			}
+			continue;
+		case AMOVH:
+		case AMOVHS:
+		case AMOVHU:
+		case AMOVB:
+		case AMOVBS:
+		case AMOVBU:
+			if(p->to.type != D_REG)
+				continue;
+			break;
+		}
+		r1 = r->link;
+		if(r1 == R)
+			continue;
+		p1 = r1->prog;
+		if(p1->as != p->as)
+			continue;
+		if(p1->from.type != D_REG || p1->from.reg != p->to.reg)
+			continue;
+		if(p1->to.type != D_REG || p1->to.reg != p->to.reg)
+			continue;
+		excise(r1);
+	}
+
+	for(r=firstr; r!=R; r=r->link) {
+		p = r->prog;
+		switch(p->as) {
+		case AMOVW:
+		case AMOVB:
+		case AMOVBS:
+		case AMOVBU:
+			if(p->from.type == D_OREG && p->from.offset == 0)
+				xtramodes(r, &p->from);
+			else if(p->to.type == D_OREG && p->to.offset == 0)
+				xtramodes(r, &p->to);
+			else
+				continue;
+			break;
+		case ACMP:
+			/*
+			 * elide CMP $0,x if calculation of x can set condition codes
+			 */
+			if(p->from.type != D_CONST || p->from.offset != 0)
+				continue;
+			r2 = r->s1;
+			if(r2 == R)
+				continue;
+			t = r2->prog->as;
+			switch(t) {
+			default:
+				continue;
+			case ABEQ:
+			case ABNE:
+			case ABMI:
+			case ABPL:
+				break;
+			case ABGE:
+				t = ABPL;
+				break;
+			case ABLT:
+				t = ABMI;
+				break;
+			case ABHI:
+				t = ABNE;
+				break;
+			case ABLS:
+				t = ABEQ;
+				break;
+			}
+			r1 = r;
+			do
+				r1 = uniqp(r1);
+			while (r1 != R && r1->prog->as == ANOP);
+			if(r1 == R)
+				continue;
+			p1 = r1->prog;
+			if(p1->to.type != D_REG)
+				continue;
+			if(p1->to.reg != p->reg)
+			if(!(p1->as == AMOVW && p1->from.type == D_REG && p1->from.reg == p->reg))
+				continue;
+			switch(p1->as) {
+			default:
+				continue;
+			case AMOVW:
+				if(p1->from.type != D_REG)
+					continue;
+			case AAND:
+			case AEOR:
+			case AORR:
+			case ABIC:
+			case AMVN:
+			case ASUB:
+			case ARSB:
+			case AADD:
+			case AADC:
+			case ASBC:
+			case ARSC:
+				break;
+			}
+			p1->scond |= C_SBIT;
+			r2->prog->as = t;
+			excise(r);
+			continue;
+		}
+	}
+
+	predicate();
+}
+
+void
+excise(Reg *r)
+{
+	Prog *p;
+
+	p = r->prog;
+	p->as = ANOP;
+	p->scond = zprog.scond;
+	p->from = zprog.from;
+	p->to = zprog.to;
+	p->reg = zprog.reg; /**/
+}
+
+Reg*
+uniqp(Reg *r)
+{
+	Reg *r1;
+
+	r1 = r->p1;
+	if(r1 == R) {
+		r1 = r->p2;
+		if(r1 == R || r1->p2link != R)
+			return R;
+	} else
+		if(r->p2 != R)
+			return R;
+	return r1;
+}
+
+Reg*
+uniqs(Reg *r)
+{
+	Reg *r1;
+
+	r1 = r->s1;
+	if(r1 == R) {
+		r1 = r->s2;
+		if(r1 == R)
+			return R;
+	} else
+		if(r->s2 != R)
+			return R;
+	return r1;
+}
+
+int
+regtyp(Addr *a)
+{
+
+	if(a->type == D_REG)
+		return 1;
+	if(a->type == D_FREG)
+		return 1;
+	return 0;
+}
+
+/*
+ * the idea is to substitute
+ * one register for another
+ * from one MOV to another
+ *	MOV	a, R0
+ *	ADD	b, R0	/ no use of R1
+ *	MOV	R0, R1
+ * would be converted to
+ *	MOV	a, R1
+ *	ADD	b, R1
+ *	MOV	R1, R0
+ * hopefully, then the former or latter MOV
+ * will be eliminated by copy propagation.
+ */
+int
+subprop(Reg *r0)
+{
+	Prog *p;
+	Addr *v1, *v2;
+	Reg *r;
+	int t;
+
+	p = r0->prog;
+	v1 = &p->from;
+	if(!regtyp(v1))
+		return 0;
+	v2 = &p->to;
+	if(!regtyp(v2))
+		return 0;
+	for(r=uniqp(r0); r!=R; r=uniqp(r)) {
+		if(uniqs(r) == R)
+			break;
+		p = r->prog;
+		switch(p->as) {
+		case ABL:
+			return 0;
+
+		case ACMP:
+		case ACMN:
+		case AADD:
+		case ASUB:
+		case ARSB:
+		case ASLL:
+		case ASRL:
+		case ASRA:
+		case AORR:
+		case AAND:
+		case AEOR:
+		case AMUL:
+		case ADIV:
+		case ADIVU:
+
+		case ACMPF:
+		case ACMPD:
+		case AADDD:
+		case AADDF:
+		case ASUBD:
+		case ASUBF:
+		case AMULD:
+		case AMULF:
+		case ADIVD:
+		case ADIVF:
+			if(p->to.type == v1->type)
+			if(p->to.reg == v1->reg) {
+				if(p->reg == NREG)
+					p->reg = p->to.reg;
+				goto gotit;
+			}
+			break;
+
+		case AMOVF:
+		case AMOVD:
+		case AMOVW:
+			if(p->to.type == v1->type)
+			if(p->to.reg == v1->reg)
+				goto gotit;
+			break;
+
+		case AMOVM:
+			t = 1<<v2->reg;
+			if((p->from.type == D_CONST && (p->from.offset&t)) ||
+			   (p->to.type == D_CONST && (p->to.offset&t)))
+				return 0;
+			break;
+		}
+		if(copyau(&p->from, v2) ||
+		   copyau1(p, v2) ||
+		   copyau(&p->to, v2))
+			break;
+		if(copysub(&p->from, v1, v2, 0) ||
+		   copysub1(p, v1, v2, 0) ||
+		   copysub(&p->to, v1, v2, 0))
+			break;
+	}
+	return 0;
+
+gotit:
+	copysub(&p->to, v1, v2, 1);
+	if(debug['P']) {
+		print("gotit: %D->%D\n%P", v1, v2, r->prog);
+		if(p->from.type == v2->type)
+			print(" excise");
+		print("\n");
+	}
+	for(r=uniqs(r); r!=r0; r=uniqs(r)) {
+		p = r->prog;
+		copysub(&p->from, v1, v2, 1);
+		copysub1(p, v1, v2, 1);
+		copysub(&p->to, v1, v2, 1);
+		if(debug['P'])
+			print("%P\n", r->prog);
+	}
+	t = v1->reg;
+	v1->reg = v2->reg;
+	v2->reg = t;
+	if(debug['P'])
+		print("%P last\n", r->prog);
+	return 1;
+}
+
+/*
+ * The idea is to remove redundant copies.
+ *	v1->v2	F=0
+ *	(use v2	s/v2/v1/)*
+ *	set v1	F=1
+ *	use v2	return fail
+ *	-----------------
+ *	v1->v2	F=0
+ *	(use v2	s/v2/v1/)*
+ *	set v1	F=1
+ *	set v2	return success
+ */
+int
+copyprop(Reg *r0)
+{
+	Prog *p;
+	Addr *v1, *v2;
+	Reg *r;
+
+	p = r0->prog;
+	v1 = &p->from;
+	v2 = &p->to;
+	if(copyas(v1, v2))
+		return 1;
+	for(r=firstr; r!=R; r=r->link)
+		r->active = 0;
+	return copy1(v1, v2, r0->s1, 0);
+}
+
+int
+copy1(Addr *v1, Addr *v2, Reg *r, int f)
+{
+	int t;
+	Prog *p;
+
+	if(r->active) {
+		if(debug['P'])
+			print("act set; return 1\n");
+		return 1;
+	}
+	r->active = 1;
+	if(debug['P'])
+		print("copy %D->%D f=%d\n", v1, v2, f);
+	for(; r != R; r = r->s1) {
+		p = r->prog;
+		if(debug['P'])
+			print("%P", p);
+		if(!f && uniqp(r) == R) {
+			f = 1;
+			if(debug['P'])
+				print("; merge; f=%d", f);
+		}
+		t = copyu(p, v2, A);
+		switch(t) {
+		case 2:	/* rar, can't split */
+			if(debug['P'])
+				print("; %Drar; return 0\n", v2);
+			return 0;
+
+		case 3:	/* set */
+			if(debug['P'])
+				print("; %Dset; return 1\n", v2);
+			return 1;
+
+		case 1:	/* used, substitute */
+		case 4:	/* use and set */
+			if(f) {
+				if(!debug['P'])
+					return 0;
+				if(t == 4)
+					print("; %Dused+set and f=%d; return 0\n", v2, f);
+				else
+					print("; %Dused and f=%d; return 0\n", v2, f);
+				return 0;
+			}
+			if(copyu(p, v2, v1)) {
+				if(debug['P'])
+					print("; sub fail; return 0\n");
+				return 0;
+			}
+			if(debug['P'])
+				print("; sub%D/%D", v2, v1);
+			if(t == 4) {
+				if(debug['P'])
+					print("; %Dused+set; return 1\n", v2);
+				return 1;
+			}
+			break;
+		}
+		if(!f) {
+			t = copyu(p, v1, A);
+			if(!f && (t == 2 || t == 3 || t == 4)) {
+				f = 1;
+				if(debug['P'])
+					print("; %Dset and !f; f=%d", v1, f);
+			}
+		}
+		if(debug['P'])
+			print("\n");
+		if(r->s2)
+			if(!copy1(v1, v2, r->s2, f))
+				return 0;
+	}
+	return 1;
+}
+
+/*
+ * The idea is to remove redundant constants.
+ *	$c1->v1
+ *	($c1->v2 s/$c1/v1)*
+ *	set v1  return
+ * The v1->v2 should be eliminated by copy propagation.
+ */
+void
+constprop(Addr *c1, Addr *v1, Reg *r)
+{
+	Prog *p;
+
+	if(debug['C'])
+		print("constprop %D->%D\n", c1, v1);
+	for(; r != R; r = r->s1) {
+		p = r->prog;
+		if(debug['C'])
+			print("%P", p);
+		if(uniqp(r) == R) {
+			if(debug['C'])
+				print("; merge; return\n");
+			return;
+		}
+		if(p->as == AMOVW && copyas(&p->from, c1)) {
+				if(debug['C'])
+					print("; sub%D/%D", &p->from, v1);
+				p->from = *v1;
+		} else if(copyu(p, v1, A) > 1) {
+			if(debug['C'])
+				print("; %Dset; return\n", v1);
+			return;
+		}
+		if(debug['C'])
+			print("\n");
+		if(r->s2)
+			constprop(c1, v1, r->s2);
+	}
+}
+
+/*
+ * ASLL x,y,w
+ * .. (not use w, not set x y w)
+ * AXXX w,a,b (a != w)
+ * .. (not use w)
+ * (set w)
+ * ----------- changed to
+ * ..
+ * AXXX (x<<y),a,b
+ * ..
+ */
+#define FAIL(msg) { if(debug['H']) print("\t%s; FAILURE\n", msg); return 0; }
+int
+shiftprop(Reg *r)
+{
+	Reg *r1;
+	Prog *p, *p1, *p2;
+	int n, o;
+	Addr a;
+
+	p = r->prog;
+	if(p->to.type != D_REG)
+		FAIL("BOTCH: result not reg");
+	n = p->to.reg;
+	a = zprog.from;
+	if(p->reg != NREG && p->reg != p->to.reg) {
+		a.type = D_REG;
+		a.reg = p->reg;
+	}
+	if(debug['H'])
+		print("shiftprop\n%P", p);
+	r1 = r;
+	for(;;) {
+		/* find first use of shift result; abort if shift operands or result are changed */
+		r1 = uniqs(r1);
+		if(r1 == R)
+			FAIL("branch");
+		if(uniqp(r1) == R)
+			FAIL("merge");
+		p1 = r1->prog;
+		if(debug['H'])
+			print("\n%P", p1);
+		switch(copyu(p1, &p->to, A)) {
+		case 0:	/* not used or set */
+			if((p->from.type == D_REG && copyu(p1, &p->from, A) > 1) ||
+			   (a.type == D_REG && copyu(p1, &a, A) > 1))
+				FAIL("args modified");
+			continue;
+		case 3:	/* set, not used */
+			FAIL("BOTCH: noref");
+		}
+		break;
+	}
+	/* check whether substitution can be done */
+	switch(p1->as) {
+	default:
+		FAIL("non-dpi");
+	case AAND:
+	case AEOR:
+	case AADD:
+	case AADC:
+	case AORR:
+	case ASUB:
+	case ARSB:
+	case ASBC:
+	case ARSC:
+		if(p1->reg == n || (p1->reg == NREG && p1->to.type == D_REG && p1->to.reg == n)) {
+			if(p1->from.type != D_REG)
+				FAIL("can't swap");
+			p1->reg = p1->from.reg;
+			p1->from.reg = n;
+			switch(p1->as) {
+			case ASUB:
+				p1->as = ARSB;
+				break;
+			case ARSB:
+				p1->as = ASUB;
+				break;
+			case ASBC:
+				p1->as = ARSC;
+				break;
+			case ARSC:
+				p1->as = ASBC;
+				break;
+			}
+			if(debug['H'])
+				print("\t=>%P", p1);
+		}
+	case ABIC:
+	case ACMP:
+	case ACMN:
+		if(p1->reg == n)
+			FAIL("can't swap");
+		if(p1->reg == NREG && p1->to.reg == n)
+			FAIL("shift result used twice");
+	case AMVN:
+		if(p1->from.type == D_SHIFT)
+			FAIL("shift result used in shift");
+		if(p1->from.type != D_REG || p1->from.reg != n)
+			FAIL("BOTCH: where is it used?");
+		break;
+	}
+	/* check whether shift result is used subsequently */
+	p2 = p1;
+	if(p1->to.reg != n)
+	for (;;) {
+		r1 = uniqs(r1);
+		if(r1 == R)
+			FAIL("inconclusive");
+		p1 = r1->prog;
+		if(debug['H'])
+			print("\n%P", p1);
+		switch(copyu(p1, &p->to, A)) {
+		case 0:	/* not used or set */
+			continue;
+		case 3: /* set, not used */
+			break;
+		default:/* used */
+			FAIL("reused");
+		}
+		break;
+	}
+	/* make the substitution */
+	p2->from.type = D_SHIFT;
+	p2->from.reg = NREG;
+	o = p->reg;
+	if(o == NREG)
+		o = p->to.reg;
+	switch(p->from.type){
+	case D_CONST:
+		o |= (p->from.offset&0x1f)<<7;
+		break;
+	case D_REG:
+		o |= (1<<4) | (p->from.reg<<8);
+		break;
+	}
+	switch(p->as){
+	case ASLL:
+		o |= 0<<5;
+		break;
+	case ASRL:
+		o |= 1<<5;
+		break;
+	case ASRA:
+		o |= 2<<5;
+		break;
+	}
+	p2->from.offset = o;
+	if(debug['H'])
+		print("\t=>%P\tSUCCEED\n", p2);
+	return 1;
+}
+
+Reg*
+findpre(Reg *r, Addr *v)
+{
+	Reg *r1;
+
+	for(r1=uniqp(r); r1!=R; r=r1,r1=uniqp(r)) {
+		if(uniqs(r1) != r)
+			return R;
+		switch(copyu(r1->prog, v, A)) {
+		case 1: /* used */
+		case 2: /* read-alter-rewrite */
+			return R;
+		case 3: /* set */
+		case 4: /* set and used */
+			return r1;
+		}
+	}
+	return R;
+}
+
+Reg*
+findinc(Reg *r, Reg *r2, Addr *v)
+{
+	Reg *r1;
+	Prog *p;
+
+
+	for(r1=uniqs(r); r1!=R && r1!=r2; r=r1,r1=uniqs(r)) {
+		if(uniqp(r1) != r)
+			return R;
+		switch(copyu(r1->prog, v, A)) {
+		case 0: /* not touched */
+			continue;
+		case 4: /* set and used */
+			p = r1->prog;
+			if(p->as == AADD)
+			if(p->from.type == D_CONST)
+			if(p->from.offset > -4096 && p->from.offset < 4096)
+				return r1;
+		default:
+			return R;
+		}
+	}
+	return R;
+}
+
+int
+nochange(Reg *r, Reg *r2, Prog *p)
+{
+	Addr a[3];
+	int i, n;
+
+	if(r == r2)
+		return 1;
+	n = 0;
+	if(p->reg != NREG && p->reg != p->to.reg) {
+		a[n].type = D_REG;
+		a[n++].reg = p->reg;
+	}
+	switch(p->from.type) {
+	case D_SHIFT:
+		a[n].type = D_REG;
+		a[n++].reg = p->from.offset&0xf;
+	case D_REG:
+		a[n].type = D_REG;
+		a[n++].reg = p->from.reg;
+	}
+	if(n == 0)
+		return 1;
+	for(; r!=R && r!=r2; r=uniqs(r)) {
+		p = r->prog;
+		for(i=0; i<n; i++)
+			if(copyu(p, &a[i], A) > 1)
+				return 0;
+	}
+	return 1;
+}
+
+int
+findu1(Reg *r, Addr *v)
+{
+	for(; r != R; r = r->s1) {
+		if(r->active)
+			return 0;
+		r->active = 1;
+		switch(copyu(r->prog, v, A)) {
+		case 1: /* used */
+		case 2: /* read-alter-rewrite */
+		case 4: /* set and used */
+			return 1;
+		case 3: /* set */
+			return 0;
+		}
+		if(r->s2)
+			if (findu1(r->s2, v))
+				return 1;
+	}
+	return 0;
+}
+
+int
+finduse(Reg *r, Addr *v)
+{
+	Reg *r1;
+
+	for(r1=firstr; r1!=R; r1=r1->link)
+		r1->active = 0;
+	return findu1(r, v);
+}
+
+int
+xtramodes(Reg *r, Addr *a)
+{
+	Reg *r1, *r2, *r3;
+	Prog *p, *p1;
+	Addr v;
+
+	p = r->prog;
+	if((p->as == AMOVB || p->as == AMOVBS) && p->from.type == D_OREG)	/* byte load */
+		return 0;
+	v = *a;
+	v.type = D_REG;
+	r1 = findpre(r, &v);
+	if(r1 != R) {
+		p1 = r1->prog;
+		if(p1->to.type == D_REG && p1->to.reg == v.reg)
+		switch(p1->as) {
+		case AADD:
+			if(p1->from.type == D_REG ||
+			   (p1->from.type == D_SHIFT && (p1->from.offset&(1<<4)) == 0 &&
+			    ((p->as != AMOVB && p->as != AMOVBS) || (a == &p->from && (p1->from.offset&~0xf) == 0))) ||
+			   (p1->from.type == D_CONST &&
+			    p1->from.offset > -4096 && p1->from.offset < 4096))
+			if(nochange(uniqs(r1), r, p1)) {
+				if(a != &p->from || v.reg != p->to.reg)
+				if (finduse(r->s1, &v)) {
+					if(p1->reg == NREG || p1->reg == v.reg)
+						/* pre-indexing */
+						p->scond |= C_WBIT;
+					else return 0;
+				}
+				switch (p1->from.type) {
+				case D_REG:
+					/* register offset */
+					if(nacl)
+						return 0;
+					a->type = D_SHIFT;
+					a->offset = p1->from.reg;
+					break;
+				case D_SHIFT:
+					/* scaled register offset */
+					if(nacl)
+						return 0;
+					a->type = D_SHIFT;
+				case D_CONST:
+					/* immediate offset */
+					a->offset = p1->from.offset;
+					break;
+				}
+				if(p1->reg != NREG)
+					a->reg = p1->reg;
+				excise(r1);
+				return 1;
+			}
+			break;
+		case AMOVW:
+			if(p1->from.type == D_REG)
+			if((r2 = findinc(r1, r, &p1->from)) != R) {
+			for(r3=uniqs(r2); r3->prog->as==ANOP; r3=uniqs(r3))
+				;
+			if(r3 == r) {
+				/* post-indexing */
+				p1 = r2->prog;
+				a->reg = p1->to.reg;
+				a->offset = p1->from.offset;
+				p->scond |= C_PBIT;
+				if(!finduse(r, &r1->prog->to))
+					excise(r1);
+				excise(r2);
+				return 1;
+			}
+			}
+			break;
+		}
+	}
+	if(a != &p->from || a->reg != p->to.reg)
+	if((r1 = findinc(r, R, &v)) != R) {
+		/* post-indexing */
+		p1 = r1->prog;
+		a->offset = p1->from.offset;
+		p->scond |= C_PBIT;
+		excise(r1);
+		return 1;
+	}
+	return 0;
+}
+
+/*
+ * return
+ * 1 if v only used (and substitute),
+ * 2 if read-alter-rewrite
+ * 3 if set
+ * 4 if set and used
+ * 0 otherwise (not touched)
+ */
+int
+copyu(Prog *p, Addr *v, Addr *s)
+{
+
+	switch(p->as) {
+
+	default:
+		if(debug['P'])
+			print(" (?)");
+		return 2;
+
+	case AMOVM:
+		if(v->type != D_REG)
+			return 0;
+		if(p->from.type == D_CONST) {	/* read reglist, read/rar */
+			if(s != A) {
+				if(p->from.offset&(1<<v->reg))
+					return 1;
+				if(copysub(&p->to, v, s, 1))
+					return 1;
+				return 0;
+			}
+			if(copyau(&p->to, v)) {
+				if(p->scond&C_WBIT)
+					return 2;
+				return 1;
+			}
+			if(p->from.offset&(1<<v->reg))
+				return 1;
+		} else {			/* read/rar, write reglist */
+			if(s != A) {
+				if(p->to.offset&(1<<v->reg))
+					return 1;
+				if(copysub(&p->from, v, s, 1))
+					return 1;
+				return 0;
+			}
+			if(copyau(&p->from, v)) {
+				if(p->scond&C_WBIT)
+					return 2;
+				if(p->to.offset&(1<<v->reg))
+					return 4;
+				return 1;
+			}
+			if(p->to.offset&(1<<v->reg))
+				return 3;
+		}
+		return 0;
+
+	case ANOP:	/* read, write */
+	case AMOVW:
+	case AMOVF:
+	case AMOVD:
+	case AMOVH:
+	case AMOVHS:
+	case AMOVHU:
+	case AMOVB:
+	case AMOVBS:
+	case AMOVBU:
+	case AMOVDW:
+	case AMOVWD:
+	case AMOVFD:
+	case AMOVDF:
+		if(p->scond&(C_WBIT|C_PBIT))
+		if(v->type == D_REG) {
+			if(p->from.type == D_OREG || p->from.type == D_SHIFT) {
+				if(p->from.reg == v->reg)
+					return 2;
+			} else {
+		  		if(p->to.reg == v->reg)
+				return 2;
+			}
+		}
+		if(s != A) {
+			if(copysub(&p->from, v, s, 1))
+				return 1;
+			if(!copyas(&p->to, v))
+				if(copysub(&p->to, v, s, 1))
+					return 1;
+			return 0;
+		}
+		if(copyas(&p->to, v)) {
+			if(copyau(&p->from, v))
+				return 4;
+			return 3;
+		}
+		if(copyau(&p->from, v))
+			return 1;
+		if(copyau(&p->to, v))
+			return 1;
+		return 0;
+
+
+	case AADD:	/* read, read, write */
+	case ASUB:
+	case ARSB:
+	case ASLL:
+	case ASRL:
+	case ASRA:
+	case AORR:
+	case AAND:
+	case AEOR:
+	case AMUL:
+	case ADIV:
+	case ADIVU:
+	case AADDF:
+	case AADDD:
+	case ASUBF:
+	case ASUBD:
+	case AMULF:
+	case AMULD:
+	case ADIVF:
+	case ADIVD:
+
+	case ACMPF:
+	case ACMPD:
+	case ACMP:
+	case ACMN:
+	case ACASE:
+		if(s != A) {
+			if(copysub(&p->from, v, s, 1))
+				return 1;
+			if(copysub1(p, v, s, 1))
+				return 1;
+			if(!copyas(&p->to, v))
+				if(copysub(&p->to, v, s, 1))
+					return 1;
+			return 0;
+		}
+		if(copyas(&p->to, v)) {
+			if(p->reg == NREG)
+				p->reg = p->to.reg;
+			if(copyau(&p->from, v))
+				return 4;
+			if(copyau1(p, v))
+				return 4;
+			return 3;
+		}
+		if(copyau(&p->from, v))
+			return 1;
+		if(copyau1(p, v))
+			return 1;
+		if(copyau(&p->to, v))
+			return 1;
+		return 0;
+
+	case ABEQ:	/* read, read */
+	case ABNE:
+	case ABCS:
+	case ABHS:
+	case ABCC:
+	case ABLO:
+	case ABMI:
+	case ABPL:
+	case ABVS:
+	case ABVC:
+	case ABHI:
+	case ABLS:
+	case ABGE:
+	case ABLT:
+	case ABGT:
+	case ABLE:
+	case APLD:
+		if(s != A) {
+			if(copysub(&p->from, v, s, 1))
+				return 1;
+			return copysub1(p, v, s, 1);
+		}
+		if(copyau(&p->from, v))
+			return 1;
+		if(copyau1(p, v))
+			return 1;
+		return 0;
+
+	case AB:	/* funny */
+		if(s != A) {
+			if(copysub(&p->to, v, s, 1))
+				return 1;
+			return 0;
+		}
+		if(copyau(&p->to, v))
+			return 1;
+		return 0;
+
+	case ARET:	/* funny */
+		if(v->type == D_REG)
+		if(v->reg == REGRET)
+			return 2;
+		if(v->type == D_FREG)
+		if(v->reg == FREGRET)
+			return 2;
+
+	case ABL:	/* funny */
+		if(v->type == D_REG) {
+			if(v->reg <= REGEXT && v->reg > exregoffset)
+				return 2;
+			if(v->reg == REGARG)
+				return 2;
+		}
+		if(v->type == D_FREG)
+			if(v->reg <= FREGEXT && v->reg > exfregoffset)
+				return 2;
+
+		if(s != A) {
+			if(copysub(&p->to, v, s, 1))
+				return 1;
+			return 0;
+		}
+		if(copyau(&p->to, v))
+			return 4;
+		return 3;
+
+	case ATEXT:	/* funny */
+		if(v->type == D_REG)
+			if(v->reg == REGARG)
+				return 3;
+		return 0;
+	}
+}
+
+int
+a2type(Prog *p)
+{
+
+	switch(p->as) {
+
+	case ACMP:
+	case ACMN:
+
+	case AADD:
+	case ASUB:
+	case ARSB:
+	case ASLL:
+	case ASRL:
+	case ASRA:
+	case AORR:
+	case AAND:
+	case AEOR:
+	case AMUL:
+	case ADIV:
+	case ADIVU:
+		return D_REG;
+
+	case ACMPF:
+	case ACMPD:
+
+	case AADDF:
+	case AADDD:
+	case ASUBF:
+	case ASUBD:
+	case AMULF:
+	case AMULD:
+	case ADIVF:
+	case ADIVD:
+		return D_FREG;
+	}
+	return D_NONE;
+}
+
+/*
+ * direct reference,
+ * could be set/use depending on
+ * semantics
+ */
+int
+copyas(Addr *a, Addr *v)
+{
+
+	if(regtyp(v)) {
+		if(a->type == v->type)
+		if(a->reg == v->reg)
+			return 1;
+	} else if(v->type == D_CONST) {		/* for constprop */
+		if(a->type == v->type)
+		if(a->name == v->name)
+		if(a->sym == v->sym)
+		if(a->reg == v->reg)
+		if(a->offset == v->offset)
+			return 1;
+	}
+	return 0;
+}
+
+/*
+ * either direct or indirect
+ */
+int
+copyau(Addr *a, Addr *v)
+{
+
+	if(copyas(a, v))
+		return 1;
+	if(v->type == D_REG) {
+		if(a->type == D_OREG) {
+			if(v->reg == a->reg)
+				return 1;
+		} else if(a->type == D_SHIFT) {
+			if((a->offset&0xf) == v->reg)
+				return 1;
+			if((a->offset&(1<<4)) && (a->offset>>8) == v->reg)
+				return 1;
+		}
+	}
+	return 0;
+}
+
+int
+copyau1(Prog *p, Addr *v)
+{
+
+	if(regtyp(v)) {
+		if(a2type(p) == v->type)
+		if(p->reg == v->reg) {
+			if(a2type(p) != v->type)
+				print("botch a2type %P\n", p);
+			return 1;
+		}
+	}
+	return 0;
+}
+
+/*
+ * substitute s for v in a
+ * return failure to substitute
+ */
+int
+copysub(Addr *a, Addr *v, Addr *s, int f)
+{
+
+	if(f)
+	if(copyau(a, v)) {
+		if(a->type == D_SHIFT) {
+			if((a->offset&0xf) == v->reg)
+				a->offset = (a->offset&~0xf)|s->reg;
+			if((a->offset&(1<<4)) && (a->offset>>8) == v->reg)
+				a->offset = (a->offset&~(0xf<<8))|(s->reg<<8);
+		} else
+			a->reg = s->reg;
+	}
+	return 0;
+}
+
+int
+copysub1(Prog *p1, Addr *v, Addr *s, int f)
+{
+
+	if(f)
+	if(copyau1(p1, v))
+		p1->reg = s->reg;
+	return 0;
+}
+
+struct {
+	int opcode;
+	int notopcode;
+	int scond;
+	int notscond;
+} predinfo[]  = {
+	{ ABEQ,	ABNE,	0x0,	0x1, },
+	{ ABNE,	ABEQ,	0x1,	0x0, },
+	{ ABCS,	ABCC,	0x2,	0x3, },
+	{ ABHS,	ABLO,	0x2,	0x3, },
+	{ ABCC,	ABCS,	0x3,	0x2, },
+	{ ABLO,	ABHS,	0x3,	0x2, },
+	{ ABMI,	ABPL,	0x4,	0x5, },
+	{ ABPL,	ABMI,	0x5,	0x4, },
+	{ ABVS,	ABVC,	0x6,	0x7, },
+	{ ABVC,	ABVS,	0x7,	0x6, },
+	{ ABHI,	ABLS,	0x8,	0x9, },
+	{ ABLS,	ABHI,	0x9,	0x8, },
+	{ ABGE,	ABLT,	0xA,	0xB, },
+	{ ABLT,	ABGE,	0xB,	0xA, },
+	{ ABGT,	ABLE,	0xC,	0xD, },
+	{ ABLE,	ABGT,	0xD,	0xC, },
+};
+
+typedef struct {
+	Reg *start;
+	Reg *last;
+	Reg *end;
+	int len;
+} Joininfo;
+
+enum {
+	Join,
+	Split,
+	End,
+	Branch,
+	Setcond,
+	Toolong
+};
+
+enum {
+	Falsecond,
+	Truecond,
+	Delbranch,
+	Keepbranch
+};
+
+int
+isbranch(Prog *p)
+{
+	return (ABEQ <= p->as) && (p->as <= ABLE);
+}
+
+int
+predicable(Prog *p)
+{
+	if (isbranch(p)
+		|| p->as == ANOP
+		|| p->as == AXXX
+		|| p->as == ADATA
+		|| p->as == AGLOBL
+		|| p->as == AGOK
+		|| p->as == AHISTORY
+		|| p->as == ANAME
+		|| p->as == ASIGNAME
+		|| p->as == ATEXT
+		|| p->as == AWORD
+		|| p->as == ABCASE
+		|| p->as == ACASE)
+		return 0;
+	return 1;
+}
+
+/*
+ * Depends on an analysis of the encodings performed by 5l.
+ * These seem to be all of the opcodes that lead to the "S" bit
+ * being set in the instruction encodings.
+ *
+ * C_SBIT may also have been set explicitly in p->scond.
+ */
+int
+modifiescpsr(Prog *p)
+{
+	return (p->scond&C_SBIT)
+		|| p->as == ATST
+		|| p->as == ATEQ
+		|| p->as == ACMN
+		|| p->as == ACMP
+		|| p->as == AMULU
+		|| p->as == ADIVU
+		|| p->as == AMUL
+		|| p->as == ADIV
+		|| p->as == AMOD
+		|| p->as == AMODU
+		|| p->as == ABL;
+}
+
+/*
+ * Find the maximal chain of instructions starting with r which could
+ * be executed conditionally
+ */
+int
+joinsplit(Reg *r, Joininfo *j)
+{
+	j->start = r;
+	j->last = r;
+	j->len = 0;
+	do {
+		if (r->p2 && (r->p1 || r->p2->p2link)) {
+			j->end = r;
+			return Join;
+		}
+		if (r->s1 && r->s2) {
+			j->end = r;
+			return Split;
+		}
+		j->last = r;
+		if (r->prog->as != ANOP)
+			j->len++;
+		if (!r->s1 && !r->s2) {
+			j->end = r->link;
+			return End;
+		}
+		if (r->s2) {
+			j->end = r->s2;
+			return Branch;
+		}
+		if (modifiescpsr(r->prog)) {
+			j->end = r->s1;
+			return Setcond;
+		}
+		r = r->s1;
+	} while (j->len < 4);
+	j->end = r;
+	return Toolong;
+}
+
+Reg *
+successor(Reg *r)
+{
+	if (r->s1)
+		return r->s1;
+	else
+		return r->s2;
+}
+
+void
+applypred(Reg *rstart, Joininfo *j, int cond, int branch)
+{
+	int pred;
+	Reg *r;
+
+	if(j->len == 0)
+		return;
+	if (cond == Truecond)
+		pred = predinfo[rstart->prog->as - ABEQ].scond;
+	else
+		pred = predinfo[rstart->prog->as - ABEQ].notscond;
+
+	for (r = j->start; ; r = successor(r)) {
+		if (r->prog->as == AB) {
+			if (r != j->last || branch == Delbranch)
+				excise(r);
+			else {
+			  if (cond == Truecond)
+				r->prog->as = predinfo[rstart->prog->as - ABEQ].opcode;
+			  else
+				r->prog->as = predinfo[rstart->prog->as - ABEQ].notopcode;
+			}
+		}
+		else if (predicable(r->prog))
+			r->prog->scond = (r->prog->scond&~C_SCOND)|pred;
+		if (r->s1 != r->link) {
+			r->s1 = r->link;
+			r->link->p1 = r;
+		}
+		if (r == j->last)
+			break;
+	}
+}
+
+void
+predicate(void)
+{
+	Reg *r;
+	int t1, t2;
+	Joininfo j1, j2;
+
+	for(r=firstr; r!=R; r=r->link) {
+		if (isbranch(r->prog)) {
+			t1 = joinsplit(r->s1, &j1);
+			t2 = joinsplit(r->s2, &j2);
+			if(j1.last->link != j2.start)
+				continue;
+			if(j1.end == j2.end)
+			if((t1 == Branch && (t2 == Join || t2 == Setcond)) ||
+			   (t2 == Join && (t1 == Join || t1 == Setcond))) {
+				applypred(r, &j1, Falsecond, Delbranch);
+				applypred(r, &j2, Truecond, Delbranch);
+				excise(r);
+				continue;
+			}
+			if(t1 == End || t1 == Branch) {
+				applypred(r, &j1, Falsecond, Keepbranch);
+				excise(r);
+				continue;
+			}
+		}
+	}
+}
diff --git a/src/cmd/5c/reg.c b/src/cmd/5c/reg.c
new file mode 100644
index 0000000..9024d5f
--- /dev/null
+++ b/src/cmd/5c/reg.c
@@ -0,0 +1,1210 @@
+// Inferno utils/5c/reg.c
+// http://code.google.com/p/inferno-os/source/browse/utils/5c/reg.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 "gc.h"
+
+void	addsplits(void);
+
+Reg*
+rega(void)
+{
+	Reg *r;
+
+	r = freer;
+	if(r == R) {
+		r = alloc(sizeof(*r));
+	} else
+		freer = r->link;
+
+	*r = zreg;
+	return r;
+}
+
+int
+rcmp(const void *a1, const void *a2)
+{
+	Rgn *p1, *p2;
+	int c1, c2;
+
+	p1 = (Rgn*)a1;
+	p2 = (Rgn*)a2;
+	c1 = p2->cost;
+	c2 = p1->cost;
+	if(c1 -= c2)
+		return c1;
+	return p2->varno - p1->varno;
+}
+
+void
+regopt(Prog *p)
+{
+	Reg *r, *r1, *r2;
+	Prog *p1;
+	int i, z;
+	int32 initpc, val, npc;
+	uint32 vreg;
+	Bits bit;
+	struct
+	{
+		int32	m;
+		int32	c;
+		Reg*	p;
+	} log5[6], *lp;
+
+	firstr = R;
+	lastr = R;
+	nvar = 0;
+	regbits = 0;
+	for(z=0; z<BITS; z++) {
+		externs.b[z] = 0;
+		params.b[z] = 0;
+		consts.b[z] = 0;
+		addrs.b[z] = 0;
+	}
+
+	/*
+	 * pass 1
+	 * build aux data structure
+	 * allocate pcs
+	 * find use and set of variables
+	 */
+	val = 5L * 5L * 5L * 5L * 5L;
+	lp = log5;
+	for(i=0; i<5; i++) {
+		lp->m = val;
+		lp->c = 0;
+		lp->p = R;
+		val /= 5L;
+		lp++;
+	}
+	val = 0;
+	for(; p != P; p = p->link) {
+		switch(p->as) {
+		case ADATA:
+		case AGLOBL:
+		case ANAME:
+		case ASIGNAME:
+		case AFUNCDATA:
+			continue;
+		}
+		r = rega();
+		if(firstr == R) {
+			firstr = r;
+			lastr = r;
+		} else {
+			lastr->link = r;
+			r->p1 = lastr;
+			lastr->s1 = r;
+			lastr = r;
+		}
+		r->prog = p;
+		r->pc = val;
+		val++;
+
+		lp = log5;
+		for(i=0; i<5; i++) {
+			lp->c--;
+			if(lp->c <= 0) {
+				lp->c = lp->m;
+				if(lp->p != R)
+					lp->p->log5 = r;
+				lp->p = r;
+				(lp+1)->c = 0;
+				break;
+			}
+			lp++;
+		}
+
+		r1 = r->p1;
+		if(r1 != R)
+		switch(r1->prog->as) {
+		case ARET:
+		case AB:
+		case ARFE:
+			r->p1 = R;
+			r1->s1 = R;
+		}
+
+		/*
+		 * left side always read
+		 */
+		bit = mkvar(&p->from, p->as==AMOVW);
+		for(z=0; z<BITS; z++)
+			r->use1.b[z] |= bit.b[z];
+
+		/*
+		 * right side depends on opcode
+		 */
+		bit = mkvar(&p->to, 0);
+		if(bany(&bit))
+		switch(p->as) {
+		default:
+			diag(Z, "reg: unknown asop: %A", p->as);
+			break;
+
+		/*
+		 * right side write
+		 */
+		case ANOP:
+		case AMOVB:
+		case AMOVBS:
+		case AMOVBU:
+		case AMOVH:
+		case AMOVHS:
+		case AMOVHU:
+		case AMOVW:
+		case AMOVF:
+		case AMOVD:
+			for(z=0; z<BITS; z++)
+				r->set.b[z] |= bit.b[z];
+			break;
+
+		/*
+		 * right side read
+		 */
+		case APLD:
+			for(z=0; z<BITS; z++)
+				r->use2.b[z] |= bit.b[z];
+			break;
+
+		/*
+		 * funny
+		 */
+		case ABL:
+			for(z=0; z<BITS; z++)
+				addrs.b[z] |= bit.b[z];
+			break;
+		}
+
+		/* the mod/div runtime routines smash R12 */
+		switch(p->as) {
+		case AMOD:
+		case AMODU:
+		case ADIV:
+		case ADIVU:
+			regbits |= RtoB(12);
+			break;
+		}
+
+		if(p->as == AMOVM) {
+			if(p->from.type == D_CONST)
+				z = p->from.offset;
+			else
+				z = p->to.offset;
+			for(i=0; z; i++) {
+				if(z&1)
+					regbits |= RtoB(i);
+				z >>= 1;
+			}
+		}
+	}
+	if(firstr == R)
+		return;
+	initpc = pc - val;
+	npc = val;
+
+	/*
+	 * pass 2
+	 * turn branch references to pointers
+	 * build back pointers
+	 */
+	for(r = firstr; r != R; r = r->link) {
+		p = r->prog;
+		if(p->to.type == D_BRANCH) {
+			val = p->to.offset - initpc;
+			r1 = firstr;
+			while(r1 != R) {
+				r2 = r1->log5;
+				if(r2 != R && val >= r2->pc) {
+					r1 = r2;
+					continue;
+				}
+				if(r1->pc == val)
+					break;
+				r1 = r1->link;
+			}
+			if(r1 == R) {
+				nearln = p->lineno;
+				diag(Z, "ref not found\n%P", p);
+				continue;
+			}
+			if(r1 == r) {
+				nearln = p->lineno;
+				diag(Z, "ref to self\n%P", p);
+				continue;
+			}
+			r->s2 = r1;
+			r->p2link = r1->p2;
+			r1->p2 = r;
+		}
+	}
+	if(debug['R']) {
+		p = firstr->prog;
+		print("\n%L %D\n", p->lineno, &p->from);
+	}
+
+	/*
+	 * pass 2.5
+	 * find looping structure
+	 */
+	for(r = firstr; r != R; r = r->link)
+		r->active = 0;
+	change = 0;
+	loopit(firstr, npc);
+
+	/*
+	 * pass 3
+	 * iterate propagating usage
+	 * 	back until flow graph is complete
+	 */
+loop1:
+	change = 0;
+	for(r = firstr; r != R; r = r->link)
+		r->active = 0;
+	for(r = firstr; r != R; r = r->link)
+		if(r->prog->as == ARET)
+			prop(r, zbits, zbits);
+loop11:
+	/* pick up unreachable code */
+	i = 0;
+	for(r = firstr; r != R; r = r1) {
+		r1 = r->link;
+		if(r1 && r1->active && !r->active) {
+			prop(r, zbits, zbits);
+			i = 1;
+		}
+	}
+	if(i)
+		goto loop11;
+	if(change)
+		goto loop1;
+
+
+	/*
+	 * pass 4
+	 * iterate propagating register/variable synchrony
+	 * 	forward until graph is complete
+	 */
+loop2:
+	change = 0;
+	for(r = firstr; r != R; r = r->link)
+		r->active = 0;
+	synch(firstr, zbits);
+	if(change)
+		goto loop2;
+
+	addsplits();
+
+	if(debug['R'] && debug['v']) {
+		print("\nprop structure:\n");
+		for(r = firstr; r != R; r = r->link) {
+			print("%d:%P", r->loop, r->prog);
+			for(z=0; z<BITS; z++)
+				bit.b[z] = r->set.b[z] |
+					r->refahead.b[z] | r->calahead.b[z] |
+					r->refbehind.b[z] | r->calbehind.b[z] |
+					r->use1.b[z] | r->use2.b[z];
+			if(bany(&bit)) {
+				print("\t");
+				if(bany(&r->use1))
+					print(" u1=%B", r->use1);
+				if(bany(&r->use2))
+					print(" u2=%B", r->use2);
+				if(bany(&r->set))
+					print(" st=%B", r->set);
+				if(bany(&r->refahead))
+					print(" ra=%B", r->refahead);
+				if(bany(&r->calahead))
+					print(" ca=%B", r->calahead);
+				if(bany(&r->refbehind))
+					print(" rb=%B", r->refbehind);
+				if(bany(&r->calbehind))
+					print(" cb=%B", r->calbehind);
+			}
+			print("\n");
+		}
+	}
+
+	/*
+	 * pass 5
+	 * isolate regions
+	 * calculate costs (paint1)
+	 */
+	r = firstr;
+	if(r) {
+		for(z=0; z<BITS; z++)
+			bit.b[z] = (r->refahead.b[z] | r->calahead.b[z]) &
+			  ~(externs.b[z] | params.b[z] | addrs.b[z] | consts.b[z]);
+		if(bany(&bit)) {
+			nearln = r->prog->lineno;
+			warn(Z, "used and not set: %B", bit);
+			if(debug['R'] && !debug['w'])
+				print("used and not set: %B\n", bit);
+		}
+	}
+
+	for(r = firstr; r != R; r = r->link)
+		r->act = zbits;
+	rgp = region;
+	nregion = 0;
+	for(r = firstr; r != R; r = r->link) {
+		for(z=0; z<BITS; z++)
+			bit.b[z] = r->set.b[z] &
+			  ~(r->refahead.b[z] | r->calahead.b[z] | addrs.b[z]);
+		if(bany(&bit)) {
+			nearln = r->prog->lineno;
+			warn(Z, "set and not used: %B", bit);
+			if(debug['R'])
+				print("set and not used: %B\n", bit);
+			excise(r);
+		}
+		for(z=0; z<BITS; z++)
+			bit.b[z] = LOAD(r) & ~(r->act.b[z] | addrs.b[z]);
+		while(bany(&bit)) {
+			i = bnum(bit);
+			rgp->enter = r;
+			rgp->varno = i;
+			change = 0;
+			if(debug['R'] && debug['v'])
+				print("\n");
+			paint1(r, i);
+			bit.b[i/32] &= ~(1L<<(i%32));
+			if(change <= 0) {
+				if(debug['R'])
+					print("%L $%d: %B\n",
+						r->prog->lineno, change, blsh(i));
+				continue;
+			}
+			rgp->cost = change;
+			nregion++;
+			if(nregion >= NRGN) {
+				fatal(Z, "too many regions");
+				goto brk;
+			}
+			rgp++;
+		}
+	}
+brk:
+	qsort(region, nregion, sizeof(region[0]), rcmp);
+
+	/*
+	 * pass 6
+	 * determine used registers (paint2)
+	 * replace code (paint3)
+	 */
+	rgp = region;
+	for(i=0; i<nregion; i++) {
+		bit = blsh(rgp->varno);
+		vreg = paint2(rgp->enter, rgp->varno);
+		vreg = allreg(vreg, rgp);
+		if(debug['R']) {
+			if(rgp->regno >= NREG)
+				print("%L $%d F%d: %B\n",
+					rgp->enter->prog->lineno,
+					rgp->cost,
+					rgp->regno-NREG,
+					bit);
+			else
+				print("%L $%d R%d: %B\n",
+					rgp->enter->prog->lineno,
+					rgp->cost,
+					rgp->regno,
+					bit);
+		}
+		if(rgp->regno != 0)
+			paint3(rgp->enter, rgp->varno, vreg, rgp->regno);
+		rgp++;
+	}
+	/*
+	 * pass 7
+	 * peep-hole on basic block
+	 */
+	if(!debug['R'] || debug['P'])
+		peep();
+
+	/*
+	 * pass 8
+	 * recalculate pc
+	 */
+	val = initpc;
+	for(r = firstr; r != R; r = r1) {
+		r->pc = val;
+		p = r->prog;
+		p1 = P;
+		r1 = r->link;
+		if(r1 != R)
+			p1 = r1->prog;
+		for(; p != p1; p = p->link) {
+			switch(p->as) {
+			default:
+				val++;
+				break;
+
+			case ANOP:
+			case ADATA:
+			case AGLOBL:
+			case ANAME:
+			case ASIGNAME:
+			case AFUNCDATA:
+				break;
+			}
+		}
+	}
+	pc = val;
+
+	/*
+	 * fix up branches
+	 */
+	if(debug['R'])
+		if(bany(&addrs))
+			print("addrs: %B\n", addrs);
+
+	r1 = 0; /* set */
+	for(r = firstr; r != R; r = r->link) {
+		p = r->prog;
+		if(p->to.type == D_BRANCH) {
+			p->to.offset = r->s2->pc;
+			p->to.u.branch = r->s2->prog;
+		}
+		r1 = r;
+	}
+
+	/*
+	 * last pass
+	 * eliminate nops
+	 * free aux structures
+	 */
+	for(p = firstr->prog; p != P; p = p->link){
+		while(p->link && p->link->as == ANOP)
+			p->link = p->link->link;
+	}
+	if(r1 != R) {
+		r1->link = freer;
+		freer = firstr;
+	}
+}
+
+void
+addsplits(void)
+{
+	Reg *r, *r1;
+	int z, i;
+	Bits bit;
+
+	for(r = firstr; r != R; r = r->link) {
+		if(r->loop > 1)
+			continue;
+		if(r->prog->as == ABL)
+			continue;
+		for(r1 = r->p2; r1 != R; r1 = r1->p2link) {
+			if(r1->loop <= 1)
+				continue;
+			for(z=0; z<BITS; z++)
+				bit.b[z] = r1->calbehind.b[z] &
+					(r->refahead.b[z] | r->use1.b[z] | r->use2.b[z]) &
+					~(r->calahead.b[z] & addrs.b[z]);
+			while(bany(&bit)) {
+				i = bnum(bit);
+				bit.b[i/32] &= ~(1L << (i%32));
+			}
+		}
+	}
+}
+
+/*
+ * add mov b,rn
+ * just after r
+ */
+void
+addmove(Reg *r, int bn, int rn, int f)
+{
+	Prog *p, *p1;
+	Addr *a;
+	Var *v;
+
+	p1 = alloc(sizeof(*p1));
+	*p1 = zprog;
+	p = r->prog;
+
+	p1->link = p->link;
+	p->link = p1;
+	p1->lineno = p->lineno;
+
+	v = var + bn;
+
+	a = &p1->to;
+	a->sym = v->sym;
+	a->name = v->name;
+	a->offset = v->offset;
+	a->etype = v->etype;
+	a->type = D_OREG;
+	if(a->etype == TARRAY || a->sym == nil)
+		a->type = D_CONST;
+
+	p1->as = AMOVW;
+	if(v->etype == TCHAR || v->etype == TUCHAR)
+		p1->as = AMOVBS;
+	if(v->etype == TSHORT || v->etype == TUSHORT)
+		p1->as = AMOVHS;
+	if(v->etype == TFLOAT)
+		p1->as = AMOVF;
+	if(v->etype == TDOUBLE)
+		p1->as = AMOVD;
+
+	p1->from.type = D_REG;
+	p1->from.reg = rn;
+	if(rn >= NREG) {
+		p1->from.type = D_FREG;
+		p1->from.reg = rn-NREG;
+	}
+	if(!f) {
+		p1->from = *a;
+		*a = zprog.from;
+		a->type = D_REG;
+		a->reg = rn;
+		if(rn >= NREG) {
+			a->type = D_FREG;
+			a->reg = rn-NREG;
+		}
+		if(v->etype == TUCHAR)
+			p1->as = AMOVBU;
+		if(v->etype == TUSHORT)
+			p1->as = AMOVHU;
+	}
+	if(debug['R'])
+		print("%P\t.a%P\n", p, p1);
+}
+
+Bits
+mkvar(Addr *a, int docon)
+{
+	Var *v;
+	int i, t, n, et, z;
+	int32 o;
+	Bits bit;
+	LSym *s;
+
+	t = a->type;
+	if(t == D_REG && a->reg != NREG)
+		regbits |= RtoB(a->reg);
+	if(t == D_FREG && a->reg != NREG)
+		regbits |= FtoB(a->reg);
+	s = a->sym;
+	o = a->offset;
+	et = a->etype;
+	if(s == nil) {
+		if(t != D_CONST || !docon || a->reg != NREG)
+			goto none;
+		et = TLONG;
+	}
+	if(t == D_CONST) {
+		if(s == nil && sval(o))
+			goto none;
+	}
+
+	n = a->name;
+	v = var;
+	for(i=0; i<nvar; i++) {
+		if(s == v->sym)
+		if(n == v->name)
+		if(o == v->offset)
+			goto out;
+		v++;
+	}
+	if(s)
+		if(s->name[0] == '.')
+			goto none;
+	if(nvar >= NVAR)
+		fatal(Z, "variable not optimized: %s", s->name);
+	i = nvar;
+	nvar++;
+	v = &var[i];
+	v->sym = s;
+	v->offset = o;
+	v->etype = et;
+	v->name = n;
+	if(debug['R'])
+		print("bit=%2d et=%2d %D\n", i, et, a);
+out:
+	bit = blsh(i);
+	if(n == D_EXTERN || n == D_STATIC)
+		for(z=0; z<BITS; z++)
+			externs.b[z] |= bit.b[z];
+	if(n == D_PARAM)
+		for(z=0; z<BITS; z++)
+			params.b[z] |= bit.b[z];
+	if(v->etype != et || !typechlpfd[et])	/* funny punning */
+		for(z=0; z<BITS; z++)
+			addrs.b[z] |= bit.b[z];
+	if(t == D_CONST) {
+		if(s == nil) {
+			for(z=0; z<BITS; z++)
+				consts.b[z] |= bit.b[z];
+			return bit;
+		}
+		if(et != TARRAY)
+			for(z=0; z<BITS; z++)
+				addrs.b[z] |= bit.b[z];
+		for(z=0; z<BITS; z++)
+			params.b[z] |= bit.b[z];
+		return bit;
+	}
+	if(t == D_OREG)
+		return bit;
+
+none:
+	return zbits;
+}
+
+void
+prop(Reg *r, Bits ref, Bits cal)
+{
+	Reg *r1, *r2;
+	int z;
+
+	for(r1 = r; r1 != R; r1 = r1->p1) {
+		for(z=0; z<BITS; z++) {
+			ref.b[z] |= r1->refahead.b[z];
+			if(ref.b[z] != r1->refahead.b[z]) {
+				r1->refahead.b[z] = ref.b[z];
+				change++;
+			}
+			cal.b[z] |= r1->calahead.b[z];
+			if(cal.b[z] != r1->calahead.b[z]) {
+				r1->calahead.b[z] = cal.b[z];
+				change++;
+			}
+		}
+		switch(r1->prog->as) {
+		case ABL:
+			for(z=0; z<BITS; z++) {
+				cal.b[z] |= ref.b[z] | externs.b[z];
+				ref.b[z] = 0;
+			}
+			break;
+
+		case ATEXT:
+			for(z=0; z<BITS; z++) {
+				cal.b[z] = 0;
+				ref.b[z] = 0;
+			}
+			break;
+
+		case ARET:
+			for(z=0; z<BITS; z++) {
+				cal.b[z] = externs.b[z];
+				ref.b[z] = 0;
+			}
+		}
+		for(z=0; z<BITS; z++) {
+			ref.b[z] = (ref.b[z] & ~r1->set.b[z]) |
+				r1->use1.b[z] | r1->use2.b[z];
+			cal.b[z] &= ~(r1->set.b[z] | r1->use1.b[z] | r1->use2.b[z]);
+			r1->refbehind.b[z] = ref.b[z];
+			r1->calbehind.b[z] = cal.b[z];
+		}
+		if(r1->active)
+			break;
+		r1->active = 1;
+	}
+	for(; r != r1; r = r->p1)
+		for(r2 = r->p2; r2 != R; r2 = r2->p2link)
+			prop(r2, r->refbehind, r->calbehind);
+}
+
+/*
+ * find looping structure
+ *
+ * 1) find reverse postordering
+ * 2) find approximate dominators,
+ *	the actual dominators if the flow graph is reducible
+ *	otherwise, dominators plus some other non-dominators.
+ *	See Matthew S. Hecht and Jeffrey D. Ullman,
+ *	"Analysis of a Simple Algorithm for Global Data Flow Problems",
+ *	Conf.  Record of ACM Symp. on Principles of Prog. Langs, Boston, Massachusetts,
+ *	Oct. 1-3, 1973, pp.  207-217.
+ * 3) find all nodes with a predecessor dominated by the current node.
+ *	such a node is a loop head.
+ *	recursively, all preds with a greater rpo number are in the loop
+ */
+int32
+postorder(Reg *r, Reg **rpo2r, int32 n)
+{
+	Reg *r1;
+
+	r->rpo = 1;
+	r1 = r->s1;
+	if(r1 && !r1->rpo)
+		n = postorder(r1, rpo2r, n);
+	r1 = r->s2;
+	if(r1 && !r1->rpo)
+		n = postorder(r1, rpo2r, n);
+	rpo2r[n] = r;
+	n++;
+	return n;
+}
+
+int32
+rpolca(int32 *idom, int32 rpo1, int32 rpo2)
+{
+	int32 t;
+
+	if(rpo1 == -1)
+		return rpo2;
+	while(rpo1 != rpo2){
+		if(rpo1 > rpo2){
+			t = rpo2;
+			rpo2 = rpo1;
+			rpo1 = t;
+		}
+		while(rpo1 < rpo2){
+			t = idom[rpo2];
+			if(t >= rpo2)
+				fatal(Z, "bad idom");
+			rpo2 = t;
+		}
+	}
+	return rpo1;
+}
+
+int
+doms(int32 *idom, int32 r, int32 s)
+{
+	while(s > r)
+		s = idom[s];
+	return s == r;
+}
+
+int
+loophead(int32 *idom, Reg *r)
+{
+	int32 src;
+
+	src = r->rpo;
+	if(r->p1 != R && doms(idom, src, r->p1->rpo))
+		return 1;
+	for(r = r->p2; r != R; r = r->p2link)
+		if(doms(idom, src, r->rpo))
+			return 1;
+	return 0;
+}
+
+void
+loopmark(Reg **rpo2r, int32 head, Reg *r)
+{
+	if(r->rpo < head || r->active == head)
+		return;
+	r->active = head;
+	r->loop += LOOP;
+	if(r->p1 != R)
+		loopmark(rpo2r, head, r->p1);
+	for(r = r->p2; r != R; r = r->p2link)
+		loopmark(rpo2r, head, r);
+}
+
+void
+loopit(Reg *r, int32 nr)
+{
+	Reg *r1;
+	int32 i, d, me;
+
+	if(nr > maxnr) {
+		rpo2r = alloc(nr * sizeof(Reg*));
+		idom = alloc(nr * sizeof(int32));
+		maxnr = nr;
+	}
+	d = postorder(r, rpo2r, 0);
+	if(d > nr)
+		fatal(Z, "too many reg nodes");
+	nr = d;
+	for(i = 0; i < nr / 2; i++){
+		r1 = rpo2r[i];
+		rpo2r[i] = rpo2r[nr - 1 - i];
+		rpo2r[nr - 1 - i] = r1;
+	}
+	for(i = 0; i < nr; i++)
+		rpo2r[i]->rpo = i;
+
+	idom[0] = 0;
+	for(i = 0; i < nr; i++){
+		r1 = rpo2r[i];
+		me = r1->rpo;
+		d = -1;
+		if(r1->p1 != R && r1->p1->rpo < me)
+			d = r1->p1->rpo;
+		for(r1 = r1->p2; r1 != nil; r1 = r1->p2link)
+			if(r1->rpo < me)
+				d = rpolca(idom, d, r1->rpo);
+		idom[i] = d;
+	}
+
+	for(i = 0; i < nr; i++){
+		r1 = rpo2r[i];
+		r1->loop++;
+		if(r1->p2 != R && loophead(idom, r1))
+			loopmark(rpo2r, i, r1);
+	}
+}
+
+void
+synch(Reg *r, Bits dif)
+{
+	Reg *r1;
+	int z;
+
+	for(r1 = r; r1 != R; r1 = r1->s1) {
+		for(z=0; z<BITS; z++) {
+			dif.b[z] = (dif.b[z] &
+				~(~r1->refbehind.b[z] & r1->refahead.b[z])) |
+					r1->set.b[z] | r1->regdiff.b[z];
+			if(dif.b[z] != r1->regdiff.b[z]) {
+				r1->regdiff.b[z] = dif.b[z];
+				change++;
+			}
+		}
+		if(r1->active)
+			break;
+		r1->active = 1;
+		for(z=0; z<BITS; z++)
+			dif.b[z] &= ~(~r1->calbehind.b[z] & r1->calahead.b[z]);
+		if(r1->s2 != R)
+			synch(r1->s2, dif);
+	}
+}
+
+uint32
+allreg(uint32 b, Rgn *r)
+{
+	Var *v;
+	int i;
+
+	v = var + r->varno;
+	r->regno = 0;
+	switch(v->etype) {
+
+	default:
+		diag(Z, "unknown etype %d/%d", bitno(b), v->etype);
+		break;
+
+	case TCHAR:
+	case TUCHAR:
+	case TSHORT:
+	case TUSHORT:
+	case TINT:
+	case TUINT:
+	case TLONG:
+	case TULONG:
+	case TIND:
+	case TARRAY:
+		i = BtoR(~b);
+		if(i && r->cost >= 0) {
+			r->regno = i;
+			return RtoB(i);
+		}
+		break;
+
+	case TVLONG:
+	case TDOUBLE:
+	case TFLOAT:
+		i = BtoF(~b);
+		if(i && r->cost >= 0) {
+			r->regno = i+NREG;
+			return FtoB(i);
+		}
+		break;
+	}
+	return 0;
+}
+
+void
+paint1(Reg *r, int bn)
+{
+	Reg *r1;
+	Prog *p;
+	int z;
+	uint32 bb;
+
+	z = bn/32;
+	bb = 1L<<(bn%32);
+	if(r->act.b[z] & bb)
+		return;
+	for(;;) {
+		if(!(r->refbehind.b[z] & bb))
+			break;
+		r1 = r->p1;
+		if(r1 == R)
+			break;
+		if(!(r1->refahead.b[z] & bb))
+			break;
+		if(r1->act.b[z] & bb)
+			break;
+		r = r1;
+	}
+
+	if(LOAD(r) & ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z])) & bb) {
+		change -= CLOAD * r->loop;
+		if(debug['R'] && debug['v'])
+			print("%d%P\td %B $%d\n", r->loop,
+				r->prog, blsh(bn), change);
+	}
+	for(;;) {
+		r->act.b[z] |= bb;
+		p = r->prog;
+
+		if(r->use1.b[z] & bb) {
+			change += CREF * r->loop;
+			if(debug['R'] && debug['v'])
+				print("%d%P\tu1 %B $%d\n", r->loop,
+					p, blsh(bn), change);
+		}
+
+		if((r->use2.b[z]|r->set.b[z]) & bb) {
+			change += CREF * r->loop;
+			if(debug['R'] && debug['v'])
+				print("%d%P\tu2 %B $%d\n", r->loop,
+					p, blsh(bn), change);
+		}
+
+		if(STORE(r) & r->regdiff.b[z] & bb) {
+			change -= CLOAD * r->loop;
+			if(debug['R'] && debug['v'])
+				print("%d%P\tst %B $%d\n", r->loop,
+					p, blsh(bn), change);
+		}
+
+		if(r->refbehind.b[z] & bb)
+			for(r1 = r->p2; r1 != R; r1 = r1->p2link)
+				if(r1->refahead.b[z] & bb)
+					paint1(r1, bn);
+
+		if(!(r->refahead.b[z] & bb))
+			break;
+		r1 = r->s2;
+		if(r1 != R)
+			if(r1->refbehind.b[z] & bb)
+				paint1(r1, bn);
+		r = r->s1;
+		if(r == R)
+			break;
+		if(r->act.b[z] & bb)
+			break;
+		if(!(r->refbehind.b[z] & bb))
+			break;
+	}
+}
+
+uint32
+paint2(Reg *r, int bn)
+{
+	Reg *r1;
+	int z;
+	uint32 bb, vreg;
+
+	z = bn/32;
+	bb = 1L << (bn%32);
+	vreg = regbits;
+	if(!(r->act.b[z] & bb))
+		return vreg;
+	for(;;) {
+		if(!(r->refbehind.b[z] & bb))
+			break;
+		r1 = r->p1;
+		if(r1 == R)
+			break;
+		if(!(r1->refahead.b[z] & bb))
+			break;
+		if(!(r1->act.b[z] & bb))
+			break;
+		r = r1;
+	}
+	for(;;) {
+		r->act.b[z] &= ~bb;
+
+		vreg |= r->regu;
+
+		if(r->refbehind.b[z] & bb)
+			for(r1 = r->p2; r1 != R; r1 = r1->p2link)
+				if(r1->refahead.b[z] & bb)
+					vreg |= paint2(r1, bn);
+
+		if(!(r->refahead.b[z] & bb))
+			break;
+		r1 = r->s2;
+		if(r1 != R)
+			if(r1->refbehind.b[z] & bb)
+				vreg |= paint2(r1, bn);
+		r = r->s1;
+		if(r == R)
+			break;
+		if(!(r->act.b[z] & bb))
+			break;
+		if(!(r->refbehind.b[z] & bb))
+			break;
+	}
+	return vreg;
+}
+
+void
+paint3(Reg *r, int bn, int32 rb, int rn)
+{
+	Reg *r1;
+	Prog *p;
+	int z;
+	uint32 bb;
+
+	z = bn/32;
+	bb = 1L << (bn%32);
+	if(r->act.b[z] & bb)
+		return;
+	for(;;) {
+		if(!(r->refbehind.b[z] & bb))
+			break;
+		r1 = r->p1;
+		if(r1 == R)
+			break;
+		if(!(r1->refahead.b[z] & bb))
+			break;
+		if(r1->act.b[z] & bb)
+			break;
+		r = r1;
+	}
+
+	if(LOAD(r) & ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z])) & bb)
+		addmove(r, bn, rn, 0);
+	for(;;) {
+		r->act.b[z] |= bb;
+		p = r->prog;
+
+		if(r->use1.b[z] & bb) {
+			if(debug['R'])
+				print("%P", p);
+			addreg(&p->from, rn);
+			if(debug['R'])
+				print("\t.c%P\n", p);
+		}
+		if((r->use2.b[z]|r->set.b[z]) & bb) {
+			if(debug['R'])
+				print("%P", p);
+			addreg(&p->to, rn);
+			if(debug['R'])
+				print("\t.c%P\n", p);
+		}
+
+		if(STORE(r) & r->regdiff.b[z] & bb)
+			addmove(r, bn, rn, 1);
+		r->regu |= rb;
+
+		if(r->refbehind.b[z] & bb)
+			for(r1 = r->p2; r1 != R; r1 = r1->p2link)
+				if(r1->refahead.b[z] & bb)
+					paint3(r1, bn, rb, rn);
+
+		if(!(r->refahead.b[z] & bb))
+			break;
+		r1 = r->s2;
+		if(r1 != R)
+			if(r1->refbehind.b[z] & bb)
+				paint3(r1, bn, rb, rn);
+		r = r->s1;
+		if(r == R)
+			break;
+		if(r->act.b[z] & bb)
+			break;
+		if(!(r->refbehind.b[z] & bb))
+			break;
+	}
+}
+
+void
+addreg(Addr *a, int rn)
+{
+
+	a->sym = 0;
+	a->name = D_NONE;
+	a->type = D_REG;
+	a->reg = rn;
+	if(rn >= NREG) {
+		a->type = D_FREG;
+		a->reg = rn-NREG;
+	}
+}
+
+/*
+ *	bit	reg
+ *	0	R0
+ *	1	R1
+ *	...	...
+ *	10	R10
+ *	12  R12
+ */
+int32
+RtoB(int r)
+{
+
+	if(r < 2 || (r >= REGTMP-2 && r != 12))	// excluded R9 and R10 for m and g, but not R12
+		return 0;
+	return 1L << r;
+}
+
+int
+BtoR(int32 b)
+{
+	b &= 0x11fcL;	// excluded R9 and R10 for m and g, but not R12
+	if(b == 0)
+		return 0;
+	return bitno(b);
+}
+
+/*
+ *	bit	reg
+ *	18	F2
+ *	19	F3
+ *	...	...
+ *	31	F15
+ */
+int32
+FtoB(int f)
+{
+
+	if(f < 2 || f > NFREG-1)
+		return 0;
+	return 1L << (f + 16);
+}
+
+int
+BtoF(int32 b)
+{
+
+	b &= 0xfffc0000L;
+	if(b == 0)
+		return 0;
+	return bitno(b) - 16;
+}
diff --git a/src/cmd/5c/sgen.c b/src/cmd/5c/sgen.c
new file mode 100644
index 0000000..a36612c
--- /dev/null
+++ b/src/cmd/5c/sgen.c
@@ -0,0 +1,265 @@
+// Inferno utils/5c/sgen.c
+// http://code.google.com/p/inferno-os/source/browse/utils/5c/sgen.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 "gc.h"
+
+Prog*
+gtext(Sym *s, int32 stkoff)
+{
+	int32 a;
+
+	a = argsize(1);
+	if((textflag & NOSPLIT) != 0 && stkoff >= 128)
+		yyerror("stack frame too large for NOSPLIT function");
+
+	gpseudo(ATEXT, s, nodconst(stkoff));
+	p->to.type = D_CONST2;
+	p->to.offset2 = a;
+	return p;
+}
+
+void
+noretval(int n)
+{
+
+	if(n & 1) {
+		gins(ANOP, Z, Z);
+		p->to.type = D_REG;
+		p->to.reg = REGRET;
+	}
+	if(n & 2) {
+		gins(ANOP, Z, Z);
+		p->to.type = D_FREG;
+		p->to.reg = FREGRET;
+	}
+}
+
+/*
+ *	calculate addressability as follows
+ *		CONST ==> 20		$value
+ *		NAME ==> 10		name
+ *		REGISTER ==> 11		register
+ *		INDREG ==> 12		*[(reg)+offset]
+ *		&10 ==> 2		$name
+ *		ADD(2, 20) ==> 2	$name+offset
+ *		ADD(3, 20) ==> 3	$(reg)+offset
+ *		&12 ==> 3		$(reg)+offset
+ *		*11 ==> 11		??
+ *		*2 ==> 10		name
+ *		*3 ==> 12		*(reg)+offset
+ *	calculate complexity (number of registers)
+ */
+void
+xcom(Node *n)
+{
+	Node *l, *r;
+	int t;
+
+	if(n == Z)
+		return;
+	l = n->left;
+	r = n->right;
+	n->addable = 0;
+	n->complex = 0;
+	switch(n->op) {
+	case OCONST:
+		n->addable = 20;
+		return;
+
+	case OREGISTER:
+		n->addable = 11;
+		return;
+
+	case OINDREG:
+		n->addable = 12;
+		return;
+
+	case ONAME:
+		n->addable = 10;
+		return;
+
+	case OADDR:
+		xcom(l);
+		if(l->addable == 10)
+			n->addable = 2;
+		if(l->addable == 12)
+			n->addable = 3;
+		break;
+
+	case OIND:
+		xcom(l);
+		if(l->addable == 11)
+			n->addable = 12;
+		if(l->addable == 3)
+			n->addable = 12;
+		if(l->addable == 2)
+			n->addable = 10;
+		break;
+
+	case OADD:
+		xcom(l);
+		xcom(r);
+		if(l->addable == 20) {
+			if(r->addable == 2)
+				n->addable = 2;
+			if(r->addable == 3)
+				n->addable = 3;
+		}
+		if(r->addable == 20) {
+			if(l->addable == 2)
+				n->addable = 2;
+			if(l->addable == 3)
+				n->addable = 3;
+		}
+		break;
+
+	case OASLMUL:
+	case OASMUL:
+		xcom(l);
+		xcom(r);
+		t = vlog(r);
+		if(t >= 0) {
+			n->op = OASASHL;
+			r->vconst = t;
+			r->type = types[TINT];
+		}
+		break;
+
+	case OMUL:
+	case OLMUL:
+		xcom(l);
+		xcom(r);
+		t = vlog(r);
+		if(t >= 0) {
+			n->op = OASHL;
+			r->vconst = t;
+			r->type = types[TINT];
+		}
+		t = vlog(l);
+		if(t >= 0) {
+			n->op = OASHL;
+			n->left = r;
+			n->right = l;
+			r = l;
+			l = n->left;
+			r->vconst = t;
+			r->type = types[TINT];
+		}
+		break;
+
+	case OASLDIV:
+		xcom(l);
+		xcom(r);
+		t = vlog(r);
+		if(t >= 0) {
+			n->op = OASLSHR;
+			r->vconst = t;
+			r->type = types[TINT];
+		}
+		break;
+
+	case OLDIV:
+		xcom(l);
+		xcom(r);
+		t = vlog(r);
+		if(t >= 0) {
+			n->op = OLSHR;
+			r->vconst = t;
+			r->type = types[TINT];
+		}
+		break;
+
+	case OASLMOD:
+		xcom(l);
+		xcom(r);
+		t = vlog(r);
+		if(t >= 0) {
+			n->op = OASAND;
+			r->vconst--;
+		}
+		break;
+
+	case OLMOD:
+		xcom(l);
+		xcom(r);
+		t = vlog(r);
+		if(t >= 0) {
+			n->op = OAND;
+			r->vconst--;
+		}
+		break;
+
+	default:
+		if(l != Z)
+			xcom(l);
+		if(r != Z)
+			xcom(r);
+		break;
+	}
+	if(n->addable >= 10)
+		return;
+
+	if(l != Z)
+		n->complex = l->complex;
+	if(r != Z) {
+		if(r->complex == n->complex)
+			n->complex = r->complex+1;
+		else
+		if(r->complex > n->complex)
+			n->complex = r->complex;
+	}
+	if(n->complex == 0)
+		n->complex++;
+
+	if(com64(n))
+		return;
+
+	switch(n->op) {
+	case OFUNC:
+		n->complex = FNX;
+		break;
+
+	case OADD:
+	case OXOR:
+	case OAND:
+	case OOR:
+	case OEQ:
+	case ONE:
+		/*
+		 * immediate operators, make const on right
+		 */
+		if(l->op == OCONST) {
+			n->left = r;
+			n->right = l;
+		}
+		break;
+	}
+}
diff --git a/src/cmd/5c/swt.c b/src/cmd/5c/swt.c
new file mode 100644
index 0000000..f39963b
--- /dev/null
+++ b/src/cmd/5c/swt.c
@@ -0,0 +1,461 @@
+// 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 "gc.h"
+
+void
+swit1(C1 *q, int nc, int32 def, Node *n)
+{
+	Node nreg;
+
+	if(typev[n->type->etype]) {
+		regsalloc(&nreg, n);
+		nreg.type = types[TVLONG];
+		cgen(n, &nreg);
+		swit2(q, nc, def, &nreg);
+		return;
+	}
+
+	regalloc(&nreg, n, Z);
+	nreg.type = types[TLONG];
+	cgen(n, &nreg);
+	swit2(q, nc, def, &nreg);
+	regfree(&nreg);
+}
+
+void
+swit2(C1 *q, int nc, int32 def, Node *n)
+{
+	C1 *r;
+	int i;
+	int32 v;
+	Prog *sp;
+
+	if(nc >= 3) {
+		i = (q+nc-1)->val - (q+0)->val;
+		if(!nacl && i > 0 && i < nc*2)
+			goto direct;
+	}
+	if(nc < 5) {
+		for(i=0; i<nc; i++) {
+			if(debug['W'])
+				print("case = %.8ux\n", q->val);
+			gopcode(OEQ, nodconst(q->val), n, Z);
+			patch(p, q->label);
+			q++;
+		}
+		gbranch(OGOTO);
+		patch(p, def);
+		return;
+	}
+
+	i = nc / 2;
+	r = q+i;
+	if(debug['W'])
+		print("case > %.8ux\n", r->val);
+	gopcode(OGT, nodconst(r->val), n, Z);
+	sp = p;
+	gopcode(OEQ, nodconst(r->val), n, Z);	/* just gen the B.EQ */
+	patch(p, r->label);
+	swit2(q, i, def, n);
+
+	if(debug['W'])
+		print("case < %.8ux\n", r->val);
+	patch(sp, pc);
+	swit2(r+1, nc-i-1, def, n);
+	return;
+
+direct:
+	v = q->val;
+	if(v != 0)
+		gopcode(OSUB, nodconst(v), Z, n);
+	gopcode(OCASE, nodconst((q+nc-1)->val - v), n, Z);
+	patch(p, def);
+	for(i=0; i<nc; i++) {
+		if(debug['W'])
+			print("case = %.8ux\n", q->val);
+		while(q->val != v) {
+			nextpc();
+			p->as = ABCASE;
+			patch(p, def);
+			v++;
+		}
+		nextpc();
+		p->as = ABCASE;
+		patch(p, q->label);
+		q++;
+		v++;
+	}
+	gbranch(OGOTO);		/* so that regopt() won't be confused */
+	patch(p, def);
+}
+
+void
+bitload(Node *b, Node *n1, Node *n2, Node *n3, Node *nn)
+{
+	int sh;
+	int32 v;
+	Node *l;
+
+	/*
+	 * n1 gets adjusted/masked value
+	 * n2 gets address of cell
+	 * n3 gets contents of cell
+	 */
+	l = b->left;
+	if(n2 != Z) {
+		regalloc(n1, l, nn);
+		reglcgen(n2, l, Z);
+		regalloc(n3, l, Z);
+		gopcode(OAS, n2, Z, n3);
+		gopcode(OAS, n3, Z, n1);
+	} else {
+		regalloc(n1, l, nn);
+		cgen(l, n1);
+	}
+	if(b->type->shift == 0 && typeu[b->type->etype]) {
+		v = ~0 + (1L << b->type->nbits);
+		gopcode(OAND, nodconst(v), Z, n1);
+	} else {
+		sh = 32 - b->type->shift - b->type->nbits;
+		if(sh > 0)
+			gopcode(OASHL, nodconst(sh), Z, n1);
+		sh += b->type->shift;
+		if(sh > 0)
+			if(typeu[b->type->etype])
+				gopcode(OLSHR, nodconst(sh), Z, n1);
+			else
+				gopcode(OASHR, nodconst(sh), Z, n1);
+	}
+}
+
+void
+bitstore(Node *b, Node *n1, Node *n2, Node *n3, Node *nn)
+{
+	int32 v;
+	Node nod, *l;
+	int sh;
+
+	/*
+	 * n1 has adjusted/masked value
+	 * n2 has address of cell
+	 * n3 has contents of cell
+	 */
+	l = b->left;
+	regalloc(&nod, l, Z);
+	v = ~0 + (1L << b->type->nbits);
+	gopcode(OAND, nodconst(v), Z, n1);
+	gopcode(OAS, n1, Z, &nod);
+	if(nn != Z)
+		gopcode(OAS, n1, Z, nn);
+	sh = b->type->shift;
+	if(sh > 0)
+		gopcode(OASHL, nodconst(sh), Z, &nod);
+	v <<= sh;
+	gopcode(OAND, nodconst(~v), Z, n3);
+	gopcode(OOR, n3, Z, &nod);
+	gopcode(OAS, &nod, Z, n2);
+
+	regfree(&nod);
+	regfree(n1);
+	regfree(n2);
+	regfree(n3);
+}
+
+int32
+outstring(char *s, int32 n)
+{
+	int32 r;
+
+	if(suppress)
+		return nstring;
+	r = nstring;
+	while(n) {
+		string[mnstring] = *s++;
+		mnstring++;
+		nstring++;
+		if(mnstring >= NSNAME) {
+			gpseudo(ADATA, symstring, nodconst(0L));
+			p->from.offset += nstring - NSNAME;
+			p->reg = NSNAME;
+			p->to.type = D_SCONST;
+			memmove(p->to.u.sval, string, NSNAME);
+			mnstring = 0;
+		}
+		n--;
+	}
+	return r;
+}
+
+int
+mulcon(Node *n, Node *nn)
+{
+	Node *l, *r, nod1, nod2;
+	Multab *m;
+	int32 v, vs;
+	int o;
+	char code[sizeof(m->code)+2], *p;
+
+	if(typefd[n->type->etype])
+		return 0;
+	l = n->left;
+	r = n->right;
+	if(l->op == OCONST) {
+		l = r;
+		r = n->left;
+	}
+	if(r->op != OCONST)
+		return 0;
+	v = convvtox(r->vconst, n->type->etype);
+	if(v != r->vconst) {
+		if(debug['M'])
+			print("%L multiply conv: %lld\n", n->lineno, r->vconst);
+		return 0;
+	}
+	m = mulcon0(v);
+	if(!m) {
+		if(debug['M'])
+			print("%L multiply table: %lld\n", n->lineno, r->vconst);
+		return 0;
+	}
+	if(debug['M'] && debug['v'])
+		print("%L multiply: %d\n", n->lineno, v);
+
+	memmove(code, m->code, sizeof(m->code));
+	code[sizeof(m->code)] = 0;
+
+	p = code;
+	if(p[1] == 'i')
+		p += 2;
+	regalloc(&nod1, n, nn);
+	cgen(l, &nod1);
+	vs = v;
+	regalloc(&nod2, n, Z);
+
+loop:
+	switch(*p) {
+	case 0:
+		regfree(&nod2);
+		if(vs < 0) {
+			gopcode(OAS, &nod1, Z, &nod1);
+			gopcode(OSUB, &nod1, nodconst(0), nn);
+		} else
+			gopcode(OAS, &nod1, Z, nn);
+		regfree(&nod1);
+		return 1;
+	case '+':
+		o = OADD;
+		goto addsub;
+	case '-':
+		o = OSUB;
+	addsub:	/* number is r,n,l */
+		v = p[1] - '0';
+		r = &nod1;
+		if(v&4)
+			r = &nod2;
+		n = &nod1;
+		if(v&2)
+			n = &nod2;
+		l = &nod1;
+		if(v&1)
+			l = &nod2;
+		gopcode(o, l, n, r);
+		break;
+	default: /* op is shiftcount, number is r,l */
+		v = p[1] - '0';
+		r = &nod1;
+		if(v&2)
+			r = &nod2;
+		l = &nod1;
+		if(v&1)
+			l = &nod2;
+		v = *p - 'a';
+		if(v < 0 || v >= 32) {
+			diag(n, "mulcon unknown op: %c%c", p[0], p[1]);
+			break;
+		}
+		gopcode(OASHL, nodconst(v), l, r);
+		break;
+	}
+	p += 2;
+	goto loop;
+}
+
+void
+sextern(Sym *s, Node *a, int32 o, int32 w)
+{
+	int32 e, lw;
+
+	for(e=0; e<w; e+=NSNAME) {
+		lw = NSNAME;
+		if(w-e < lw)
+			lw = w-e;
+		gpseudo(ADATA, s, nodconst(0));
+		p->from.offset += o+e;
+		p->reg = lw;
+		p->to.type = D_SCONST;
+		memmove(p->to.u.sval, a->cstring+e, lw);
+	}
+}
+
+void
+gextern(Sym *s, Node *a, int32 o, int32 w)
+{
+
+	if(a->op == OCONST && typev[a->type->etype]) {
+		if(isbigendian)
+			gpseudo(ADATA, s, nod32const(a->vconst>>32));
+		else
+			gpseudo(ADATA, s, nod32const(a->vconst));
+		p->from.offset += o;
+		p->reg = 4;
+		if(isbigendian)
+			gpseudo(ADATA, s, nod32const(a->vconst));
+		else
+			gpseudo(ADATA, s, nod32const(a->vconst>>32));
+		p->from.offset += o + 4;
+		p->reg = 4;
+		return;
+	}
+	gpseudo(ADATA, s, a);
+	p->from.offset += o;
+	p->reg = w;
+	if(p->to.type == D_OREG)
+		p->to.type = D_CONST;
+}
+
+void
+outcode(void)
+{
+	Bprint(&outbuf, "go object %s %s %s\n", getgoos(), getgoarch(), getgoversion());
+	if(pragcgobuf.to > pragcgobuf.start) {
+		Bprint(&outbuf, "\n");
+		Bprint(&outbuf, "$$  // exports\n\n");
+		Bprint(&outbuf, "$$  // local types\n\n");
+		Bprint(&outbuf, "$$  // cgo\n");
+		Bprint(&outbuf, "%s", fmtstrflush(&pragcgobuf));
+		Bprint(&outbuf, "\n$$\n\n");
+	}
+	Bprint(&outbuf, "!\n");
+
+	writeobj(ctxt, &outbuf);
+	lastp = P;
+}
+
+int32
+align(int32 i, Type *t, int op, int32 *maxalign)
+{
+	int32 o;
+	Type *v;
+	int w, packw;
+
+	o = i;
+	w = 1;
+	packw = 0;
+	switch(op) {
+	default:
+		diag(Z, "unknown align opcode %d", op);
+		break;
+
+	case Asu2:	/* padding at end of a struct */
+		w = *maxalign;
+		if(w < 1)
+			w = 1;
+		if(packflg)
+			packw = packflg;
+		break;
+
+	case Ael1:	/* initial align of struct element */
+		for(v=t; v->etype==TARRAY; v=v->link)
+			;
+		if(v->etype == TSTRUCT || v->etype == TUNION)
+			w = v->align;
+		else {
+			w = ewidth[v->etype];
+			if(w == 8)
+				w = 4;
+		}
+		if(w < 1 || w > SZ_LONG)
+			fatal(Z, "align");
+		if(packflg) 
+			packw = packflg;
+		break;
+
+	case Ael2:	/* width of a struct element */
+		o += t->width;
+		break;
+
+	case Aarg0:	/* initial passbyptr argument in arg list */
+		if(typesuv[t->etype]) {
+			o = align(o, types[TIND], Aarg1, nil);
+			o = align(o, types[TIND], Aarg2, nil);
+		}
+		break;
+
+	case Aarg1:	/* initial align of parameter */
+		w = ewidth[t->etype];
+		if(w <= 0 || w >= SZ_LONG) {
+			w = SZ_LONG;
+			break;
+		}
+		w = 1;		/* little endian no adjustment */
+		break;
+
+	case Aarg2:	/* width of a parameter */
+		o += t->width;
+		w = t->width;
+		if(w > SZ_LONG)
+			w = SZ_LONG;
+		break;
+
+	case Aaut3:	/* total align of automatic */
+		o = align(o, t, Ael2, nil);
+		o = align(o, t, Ael1, nil);
+		w = SZ_LONG;	/* because of a pun in cc/dcl.c:contig() */
+		break;
+	}
+	if(packw != 0 && xround(o, w) != xround(o, packw))
+		diag(Z, "#pragma pack changes offset of %T", t);
+	o = xround(o, w);
+	if(maxalign != nil && *maxalign < w)
+		*maxalign = w;
+	if(debug['A'])
+		print("align %s %d %T = %d\n", bnames[op], i, t, o);
+	return o;
+}
+
+int32
+maxround(int32 max, int32 v)
+{
+	v = xround(v, SZ_LONG);
+	if(v > max)
+		return v;
+	return max;
+}
diff --git a/src/cmd/5c/txt.c b/src/cmd/5c/txt.c
new file mode 100644
index 0000000..af40220
--- /dev/null
+++ b/src/cmd/5c/txt.c
@@ -0,0 +1,1361 @@
+// Inferno utils/5c/txt.c
+// http://code.google.com/p/inferno-os/source/browse/utils/5c/txt.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 "gc.h"
+
+
+int thechar = '5';
+char *thestring = "arm";
+
+LinkArch	*thelinkarch = &linkarm;
+
+void
+linkarchinit(void)
+{
+}
+
+void
+ginit(void)
+{
+	Type *t;
+
+	exregoffset = REGEXT;
+	exfregoffset = FREGEXT;
+	listinit();
+	nstring = 0;
+	mnstring = 0;
+	nrathole = 0;
+	pc = 0;
+	breakpc = -1;
+	continpc = -1;
+	cases = C;
+	lastp = P;
+	tfield = types[TLONG];
+
+	zprog.link = P;
+	zprog.as = AGOK;
+	zprog.reg = NREG;
+	zprog.from.type = D_NONE;
+	zprog.from.name = D_NONE;
+	zprog.from.reg = NREG;
+	zprog.to = zprog.from;
+	zprog.scond = 0xE;
+
+	regnode.op = OREGISTER;
+	regnode.class = CEXREG;
+	regnode.reg = REGTMP;
+	regnode.complex = 0;
+	regnode.addable = 11;
+	regnode.type = types[TLONG];
+
+	constnode.op = OCONST;
+	constnode.class = CXXX;
+	constnode.complex = 0;
+	constnode.addable = 20;
+	constnode.type = types[TLONG];
+
+	fconstnode.op = OCONST;
+	fconstnode.class = CXXX;
+	fconstnode.complex = 0;
+	fconstnode.addable = 20;
+	fconstnode.type = types[TDOUBLE];
+
+	nodsafe = new(ONAME, Z, Z);
+	nodsafe->sym = slookup(".safe");
+	nodsafe->type = types[TINT];
+	nodsafe->etype = types[TINT]->etype;
+	nodsafe->class = CAUTO;
+	complex(nodsafe);
+
+	t = typ(TARRAY, types[TCHAR]);
+	symrathole = slookup(".rathole");
+	symrathole->class = CGLOBL;
+	symrathole->type = t;
+
+	nodrat = new(ONAME, Z, Z);
+	nodrat->sym = symrathole;
+	nodrat->type = types[TIND];
+	nodrat->etype = TVOID;
+	nodrat->class = CGLOBL;
+	complex(nodrat);
+	nodrat->type = t;
+
+	nodret = new(ONAME, Z, Z);
+	nodret->sym = slookup(".ret");
+	nodret->type = types[TIND];
+	nodret->etype = TIND;
+	nodret->class = CPARAM;
+	nodret = new(OIND, nodret, Z);
+	complex(nodret);
+
+	com64init();
+
+	memset(reg, 0, sizeof(reg));
+}
+
+void
+gclean(void)
+{
+	int i;
+	Sym *s;
+
+	for(i=0; i<NREG; i++)
+		if(reg[i])
+			diag(Z, "reg %d left allocated", i);
+	for(i=NREG; i<NREG+NFREG; i++)
+		if(reg[i])
+			diag(Z, "freg %d left allocated", i-NREG);
+	while(mnstring)
+		outstring("", 1L);
+	symstring->type->width = nstring;
+	symrathole->type->width = nrathole;
+	for(i=0; i<NHASH; i++)
+	for(s = hash[i]; s != S; s = s->link) {
+		if(s->type == T)
+			continue;
+		if(s->type->width == 0)
+			continue;
+		if(s->class != CGLOBL && s->class != CSTATIC)
+			continue;
+		if(s->type == types[TENUM])
+			continue;
+		gpseudo(AGLOBL, s, nodconst(s->type->width));
+	}
+	nextpc();
+	p->as = AEND;
+	outcode();
+}
+
+void
+nextpc(void)
+{
+	Plist *pl;
+
+	p = alloc(sizeof(*p));
+	*p = zprog;
+	p->lineno = nearln;
+	pc++;
+	if(lastp == nil) {
+		pl = linknewplist(ctxt);
+		pl->firstpc = p;
+	} else
+		lastp->link = p;
+	lastp = p;
+}
+
+void
+gargs(Node *n, Node *tn1, Node *tn2)
+{
+	int32 regs;
+	Node fnxargs[20], *fnxp;
+
+	regs = cursafe;
+
+	fnxp = fnxargs;
+	garg1(n, tn1, tn2, 0, &fnxp);	/* compile fns to temps */
+
+	curarg = 0;
+	fnxp = fnxargs;
+	garg1(n, tn1, tn2, 1, &fnxp);	/* compile normal args and temps */
+
+	cursafe = regs;
+}
+
+void
+garg1(Node *n, Node *tn1, Node *tn2, int f, Node **fnxp)
+{
+	Node nod;
+
+	if(n == Z)
+		return;
+	if(n->op == OLIST) {
+		garg1(n->left, tn1, tn2, f, fnxp);
+		garg1(n->right, tn1, tn2, f, fnxp);
+		return;
+	}
+	if(f == 0) {
+		if(n->complex >= FNX) {
+			regsalloc(*fnxp, n);
+			nod = znode;
+			nod.op = OAS;
+			nod.left = *fnxp;
+			nod.right = n;
+			nod.type = n->type;
+			cgen(&nod, Z);
+			(*fnxp)++;
+		}
+		return;
+	}
+	if(typesuv[n->type->etype]) {
+		regaalloc(tn2, n);
+		if(n->complex >= FNX) {
+			sugen(*fnxp, tn2, n->type->width);
+			(*fnxp)++;
+		} else
+			sugen(n, tn2, n->type->width);
+		return;
+	}
+	if(REGARG >= 0 && curarg == 0 && typechlp[n->type->etype]) {
+		regaalloc1(tn1, n);
+		if(n->complex >= FNX) {
+			cgen(*fnxp, tn1);
+			(*fnxp)++;
+		} else
+			cgen(n, tn1);
+		return;
+	}
+	regalloc(tn1, n, Z);
+	if(n->complex >= FNX) {
+		cgen(*fnxp, tn1);
+		(*fnxp)++;
+	} else
+		cgen(n, tn1);
+	regaalloc(tn2, n);
+	gopcode(OAS, tn1, Z, tn2);
+	regfree(tn1);
+}
+
+Node*
+nodconst(int32 v)
+{
+	constnode.vconst = v;
+	return &constnode;
+}
+
+Node*
+nod32const(vlong v)
+{
+	constnode.vconst = v & MASK(32);
+	return &constnode;
+}
+
+Node*
+nodfconst(double d)
+{
+	fconstnode.fconst = d;
+	return &fconstnode;
+}
+
+void
+nodreg(Node *n, Node *nn, int reg)
+{
+	*n = regnode;
+	n->reg = reg;
+	n->type = nn->type;
+	n->lineno = nn->lineno;
+}
+
+void
+regret(Node *n, Node *nn, Type *t, int mode)
+{
+	int r;
+
+	if(mode == 0 || hasdotdotdot(t) || nn->type->width == 0) {
+		r = REGRET;
+		if(typefd[nn->type->etype])
+			r = FREGRET+NREG;
+		nodreg(n, nn, r);
+		reg[r]++;
+		return;
+	}
+	
+	if(mode == 1) {
+		// fetch returned value after call.
+		// already called gargs, so curarg is set.
+		curarg = (curarg+3) & ~3;
+		regaalloc(n, nn);
+		return;
+	}
+	
+	if(mode == 2) {
+		// store value to be returned.
+		// must compute arg offset.
+		if(t->etype != TFUNC)
+			fatal(Z, "bad regret func %T", t);
+		*n = *nn;
+		n->op = ONAME;
+		n->class = CPARAM;
+		n->sym = slookup(".ret");
+		n->complex = nodret->complex;
+		n->xoffset = argsize(0);
+		n->addable = 20;
+		return;
+	}
+	
+	fatal(Z, "bad regret");
+}
+
+int
+tmpreg(void)
+{
+	int i;
+
+	for(i=REGRET+1; i<NREG; i++)
+		if(reg[i] == 0)
+			return i;
+	diag(Z, "out of fixed registers");
+	return 0;
+}
+
+void
+regalloc(Node *n, Node *tn, Node *o)
+{
+	int i;
+
+	switch(tn->type->etype) {
+	case TCHAR:
+	case TUCHAR:
+	case TSHORT:
+	case TUSHORT:
+	case TINT:
+	case TUINT:
+	case TLONG:
+	case TULONG:
+	case TIND:
+		if(o != Z && o->op == OREGISTER) {
+			i = o->reg;
+			if(i >= 0 && i < NREG)
+				goto out;
+		}
+		for(i=REGRET+1; i<=REGEXT-2; i++)
+			if(reg[i] == 0)
+				goto out;
+		diag(tn, "out of fixed registers");
+		goto err;
+
+	case TFLOAT:
+	case TDOUBLE:
+	case TVLONG:
+		if(o != Z && o->op == OREGISTER) {
+			i = o->reg;
+			if(i >= NREG && i < NREG+NFREG)
+				goto out;
+		}
+		for(i=NREG; i<NREG+NFREG; i++)
+			if(reg[i] == 0)
+				goto out;
+		diag(tn, "out of float registers");
+		goto err;
+	}
+	diag(tn, "unknown type in regalloc: %T", tn->type);
+err:
+	nodreg(n, tn, 0);
+	return;
+out:
+	reg[i]++;
+	nodreg(n, tn, i);
+}
+
+void
+regialloc(Node *n, Node *tn, Node *o)
+{
+	Node nod;
+
+	nod = *tn;
+	nod.type = types[TIND];
+	regalloc(n, &nod, o);
+}
+
+void
+regfree(Node *n)
+{
+	int i;
+
+	i = 0;
+	if(n->op != OREGISTER && n->op != OINDREG)
+		goto err;
+	i = n->reg;
+	if(i < 0 || i >= nelem(reg))
+		goto err;
+	if(reg[i] <= 0)
+		goto err;
+	reg[i]--;
+	return;
+err:
+	diag(n, "error in regfree: %d", i);
+}
+
+void
+regsalloc(Node *n, Node *nn)
+{
+	cursafe = align(cursafe, nn->type, Aaut3, nil);
+	maxargsafe = maxround(maxargsafe, cursafe+curarg);
+	*n = *nodsafe;
+	n->xoffset = -(stkoff + cursafe);
+	n->type = nn->type;
+	n->etype = nn->type->etype;
+	n->lineno = nn->lineno;
+}
+
+void
+regaalloc1(Node *n, Node *nn)
+{
+	if(REGARG < 0) {
+		fatal(n, "regaalloc1 and REGARG<0");
+		return;
+	}
+	nodreg(n, nn, REGARG);
+	reg[REGARG]++;
+	curarg = align(curarg, nn->type, Aarg1, nil);
+	curarg = align(curarg, nn->type, Aarg2, nil);
+	maxargsafe = maxround(maxargsafe, cursafe+curarg);
+}
+
+void
+regaalloc(Node *n, Node *nn)
+{
+	curarg = align(curarg, nn->type, Aarg1, nil);
+	*n = *nn;
+	n->op = OINDREG;
+	n->reg = REGSP;
+	n->xoffset = curarg + SZ_LONG;
+	n->complex = 0;
+	n->addable = 20;
+	curarg = align(curarg, nn->type, Aarg2, nil);
+	maxargsafe = maxround(maxargsafe, cursafe+curarg);
+}
+
+void
+regind(Node *n, Node *nn)
+{
+
+	if(n->op != OREGISTER) {
+		diag(n, "regind not OREGISTER");
+		return;
+	}
+	n->op = OINDREG;
+	n->type = nn->type;
+}
+
+void
+raddr(Node *n, Prog *p)
+{
+	Addr a;
+
+	naddr(n, &a);
+	if(R0ISZERO && a.type == D_CONST && a.offset == 0) {
+		a.type = D_REG;
+		a.reg = 0;
+	}
+	if(a.type != D_REG && a.type != D_FREG) {
+		if(n)
+			diag(n, "bad in raddr: %O", n->op);
+		else
+			diag(n, "bad in raddr: <null>");
+		p->reg = NREG;
+	} else
+		p->reg = a.reg;
+}
+
+void
+naddr(Node *n, Addr *a)
+{
+	int32 v;
+
+	a->type = D_NONE;
+	if(n == Z)
+		return;
+	switch(n->op) {
+	default:
+	bad:
+		diag(n, "bad in naddr: %O", n->op);
+		break;
+
+	case OREGISTER:
+		a->type = D_REG;
+		a->sym = nil;
+		a->reg = n->reg;
+		if(a->reg >= NREG) {
+			a->type = D_FREG;
+			a->reg -= NREG;
+		}
+		break;
+
+	case OIND:
+		naddr(n->left, a);
+		if(a->type == D_REG) {
+			a->type = D_OREG;
+			break;
+		}
+		if(a->type == D_CONST) {
+			a->type = D_OREG;
+			break;
+		}
+		goto bad;
+
+	case OINDREG:
+		a->type = D_OREG;
+		a->sym = nil;
+		a->offset = n->xoffset;
+		a->reg = n->reg;
+		break;
+
+	case ONAME:
+		a->etype = n->etype;
+		a->type = D_OREG;
+		a->name = D_STATIC;
+		a->sym = linksym(n->sym);
+		a->offset = n->xoffset;
+		if(n->class == CSTATIC)
+			break;
+		if(n->class == CEXTERN || n->class == CGLOBL) {
+			a->name = D_EXTERN;
+			break;
+		}
+		if(n->class == CAUTO) {
+			a->name = D_AUTO;
+			break;
+		}
+		if(n->class == CPARAM) {
+			a->name = D_PARAM;
+			break;
+		}
+		goto bad;
+
+	case OCONST:
+		a->sym = nil;
+		a->reg = NREG;
+		if(typefd[n->type->etype]) {
+			a->type = D_FCONST;
+			a->u.dval = n->fconst;
+		} else {
+			a->type = D_CONST;
+			a->offset = n->vconst;
+		}
+		break;
+
+	case OADDR:
+		naddr(n->left, a);
+		if(a->type == D_OREG) {
+			a->type = D_CONST;
+			break;
+		}
+		goto bad;
+
+	case OADD:
+		if(n->left->op == OCONST) {
+			naddr(n->left, a);
+			v = a->offset;
+			naddr(n->right, a);
+		} else {
+			naddr(n->right, a);
+			v = a->offset;
+			naddr(n->left, a);
+		}
+		a->offset += v;
+		break;
+
+	}
+}
+
+void
+fop(int as, int f1, int f2, Node *t)
+{
+	Node nod1, nod2, nod3;
+
+	nodreg(&nod1, t, NREG+f1);
+	nodreg(&nod2, t, NREG+f2);
+	regalloc(&nod3, t, t);
+	gopcode(as, &nod1, &nod2, &nod3);
+	gmove(&nod3, t);
+	regfree(&nod3);
+}
+
+void
+gmovm(Node *f, Node *t, int w)
+{
+	gins(AMOVM, f, t);
+	p->scond |= C_UBIT;
+	if(w)
+		p->scond |= C_WBIT;
+}
+
+void
+gmove(Node *f, Node *t)
+{
+	int ft, tt, a;
+	Node nod, nod1;
+	Prog *p1;
+
+	ft = f->type->etype;
+	tt = t->type->etype;
+
+	if(ft == TDOUBLE && f->op == OCONST) {
+	}
+	if(ft == TFLOAT && f->op == OCONST) {
+	}
+
+	/*
+	 * a load --
+	 * put it into a register then
+	 * worry what to do with it.
+	 */
+	if(f->op == ONAME || f->op == OINDREG || f->op == OIND) {
+		switch(ft) {
+		default:
+			a = AMOVW;
+			break;
+		case TFLOAT:
+			a = AMOVF;
+			break;
+		case TDOUBLE:
+			a = AMOVD;
+			break;
+		case TCHAR:
+			a = AMOVBS;
+			break;
+		case TUCHAR:
+			a = AMOVBU;
+			break;
+		case TSHORT:
+			a = AMOVHS;
+			break;
+		case TUSHORT:
+			a = AMOVHU;
+			break;
+		}
+		if(typechlp[ft] && typeilp[tt])
+			regalloc(&nod, t, t);
+		else
+			regalloc(&nod, f, t);
+		gins(a, f, &nod);
+		gmove(&nod, t);
+		regfree(&nod);
+		return;
+	}
+
+	/*
+	 * a store --
+	 * put it into a register then
+	 * store it.
+	 */
+	if(t->op == ONAME || t->op == OINDREG || t->op == OIND) {
+		switch(tt) {
+		default:
+			a = AMOVW;
+			break;
+		case TUCHAR:
+			a = AMOVBU;
+			break;
+		case TCHAR:
+			a = AMOVBS;
+			break;
+		case TUSHORT:
+			a = AMOVHU;
+			break;
+		case TSHORT:
+			a = AMOVHS;
+			break;
+		case TFLOAT:
+			a = AMOVF;
+			break;
+		case TVLONG:
+		case TDOUBLE:
+			a = AMOVD;
+			break;
+		}
+		if(ft == tt)
+			regalloc(&nod, t, f);
+		else
+			regalloc(&nod, t, Z);
+		gmove(f, &nod);
+		gins(a, &nod, t);
+		regfree(&nod);
+		return;
+	}
+
+	/*
+	 * type x type cross table
+	 */
+	a = AGOK;
+	switch(ft) {
+	case TDOUBLE:
+	case TVLONG:
+	case TFLOAT:
+		switch(tt) {
+		case TDOUBLE:
+		case TVLONG:
+			a = AMOVD;
+			if(ft == TFLOAT)
+				a = AMOVFD;
+			break;
+		case TFLOAT:
+			a = AMOVDF;
+			if(ft == TFLOAT)
+				a = AMOVF;
+			break;
+		case TINT:
+		case TUINT:
+		case TLONG:
+		case TULONG:
+		case TIND:
+			a = AMOVDW;
+			if(ft == TFLOAT)
+				a = AMOVFW;
+			break;
+		case TSHORT:
+		case TUSHORT:
+		case TCHAR:
+		case TUCHAR:
+			a = AMOVDW;
+			if(ft == TFLOAT)
+				a = AMOVFW;
+			break;
+		}
+		break;
+	case TUINT:
+	case TULONG:
+		if(tt == TFLOAT || tt == TDOUBLE) {
+			// ugly and probably longer than necessary,
+			// but vfp has a single instruction for this,
+			// so hopefully it won't last long.
+			//
+			//	tmp = f
+			//	tmp1 = tmp & 0x80000000
+			//	tmp ^= tmp1
+			//	t = float(int32(tmp))
+			//	if(tmp1)
+			//		t += 2147483648.
+			//
+			regalloc(&nod, f, Z);
+			regalloc(&nod1, f, Z);
+			gins(AMOVW, f, &nod);
+			gins(AMOVW, &nod, &nod1);
+			gins(AAND, nodconst(0x80000000), &nod1);
+			gins(AEOR, &nod1, &nod);
+			if(tt == TFLOAT)
+				gins(AMOVWF, &nod, t);
+			else
+				gins(AMOVWD, &nod, t);
+			gins(ACMP, nodconst(0), Z);
+			raddr(&nod1, p);
+			gins(ABEQ, Z, Z);
+			regfree(&nod);
+			regfree(&nod1);
+			p1 = p;
+			regalloc(&nod, t, Z);
+			gins(AMOVF, nodfconst(2147483648.), &nod);
+			gins(AADDF, &nod, t);
+			regfree(&nod);
+			patch(p1, pc);
+			return;
+		}
+		// fall through
+	
+	case TINT:
+	case TLONG:
+	case TIND:
+		switch(tt) {
+		case TDOUBLE:
+			gins(AMOVWD, f, t);
+			return;
+		case TFLOAT:
+			gins(AMOVWF, f, t);
+			return;
+		case TINT:
+		case TUINT:
+		case TLONG:
+		case TULONG:
+		case TIND:
+		case TSHORT:
+		case TUSHORT:
+		case TCHAR:
+		case TUCHAR:
+			a = AMOVW;
+			break;
+		}
+		break;
+	case TSHORT:
+		switch(tt) {
+		case TDOUBLE:
+			regalloc(&nod, f, Z);
+			gins(AMOVHS, f, &nod);
+			gins(AMOVWD, &nod, t);
+			regfree(&nod);
+			return;
+		case TFLOAT:
+			regalloc(&nod, f, Z);
+			gins(AMOVHS, f, &nod);
+			gins(AMOVWF, &nod, t);
+			regfree(&nod);
+			return;
+		case TUINT:
+		case TINT:
+		case TULONG:
+		case TLONG:
+		case TIND:
+			a = AMOVHS;
+			break;
+		case TSHORT:
+		case TUSHORT:
+		case TCHAR:
+		case TUCHAR:
+			a = AMOVW;
+			break;
+		}
+		break;
+	case TUSHORT:
+		switch(tt) {
+		case TDOUBLE:
+			regalloc(&nod, f, Z);
+			gins(AMOVHU, f, &nod);
+			gins(AMOVWD, &nod, t);
+			regfree(&nod);
+			return;
+		case TFLOAT:
+			regalloc(&nod, f, Z);
+			gins(AMOVHU, f, &nod);
+			gins(AMOVWF, &nod, t);
+			regfree(&nod);
+			return;
+		case TINT:
+		case TUINT:
+		case TLONG:
+		case TULONG:
+		case TIND:
+			a = AMOVHU;
+			break;
+		case TSHORT:
+		case TUSHORT:
+		case TCHAR:
+		case TUCHAR:
+			a = AMOVW;
+			break;
+		}
+		break;
+	case TCHAR:
+		switch(tt) {
+		case TDOUBLE:
+			regalloc(&nod, f, Z);
+			gins(AMOVBS, f, &nod);
+			gins(AMOVWD, &nod, t);
+			regfree(&nod);
+			return;
+		case TFLOAT:
+			regalloc(&nod, f, Z);
+			gins(AMOVBS, f, &nod);
+			gins(AMOVWF, &nod, t);
+			regfree(&nod);
+			return;
+		case TINT:
+		case TUINT:
+		case TLONG:
+		case TULONG:
+		case TIND:
+		case TSHORT:
+		case TUSHORT:
+			a = AMOVBS;
+			break;
+		case TCHAR:
+		case TUCHAR:
+			a = AMOVW;
+			break;
+		}
+		break;
+	case TUCHAR:
+		switch(tt) {
+		case TDOUBLE:
+			regalloc(&nod, f, Z);
+			gins(AMOVBU, f, &nod);
+			gins(AMOVWD, &nod, t);
+			regfree(&nod);
+			return;
+		case TFLOAT:
+			regalloc(&nod, f, Z);
+			gins(AMOVBU, f, &nod);
+			gins(AMOVWF, &nod, t);
+			regfree(&nod);
+			return;
+		case TINT:
+		case TUINT:
+		case TLONG:
+		case TULONG:
+		case TIND:
+		case TSHORT:
+		case TUSHORT:
+			a = AMOVBU;
+			break;
+		case TCHAR:
+		case TUCHAR:
+			a = AMOVW;
+			break;
+		}
+		break;
+	}
+	if(a == AGOK)
+		diag(Z, "bad opcode in gmove %T -> %T", f->type, t->type);
+	if(a == AMOVW || a == AMOVF || a == AMOVD)
+	if(samaddr(f, t))
+		return;
+	gins(a, f, t);
+}
+
+void
+gmover(Node *f, Node *t)
+{
+	int ft, tt, a;
+
+	ft = f->type->etype;
+	tt = t->type->etype;
+	a = AGOK;
+	if(typechlp[ft] && typechlp[tt] && ewidth[ft] >= ewidth[tt]){
+		switch(tt){
+		case TSHORT:
+			a = AMOVHS;
+			break;
+		case TUSHORT:
+			a = AMOVHU;
+			break;
+		case TCHAR:
+			a = AMOVBS;
+			break;
+		case TUCHAR:
+			a = AMOVBU;
+			break;
+		}
+	}
+	if(a == AGOK)
+		gmove(f, t);
+	else
+		gins(a, f, t);
+}
+
+void
+gins(int a, Node *f, Node *t)
+{
+
+	nextpc();
+	p->as = a;
+	if(f != Z)
+		naddr(f, &p->from);
+	if(t != Z)
+		naddr(t, &p->to);
+	if(debug['g'])
+		print("%P\n", p);
+}
+
+void
+gopcode(int o, Node *f1, Node *f2, Node *t)
+{
+	int a, et;
+	Addr ta;
+
+	et = TLONG;
+	if(f1 != Z && f1->type != T)
+		et = f1->type->etype;
+	a = AGOK;
+	switch(o) {
+	case OAS:
+		gmove(f1, t);
+		return;
+
+	case OASADD:
+	case OADD:
+		a = AADD;
+		if(et == TFLOAT)
+			a = AADDF;
+		else
+		if(et == TDOUBLE || et == TVLONG)
+			a = AADDD;
+		break;
+
+	case OASSUB:
+	case OSUB:
+		if(f2 && f2->op == OCONST) {
+			Node *t = f1;
+			f1 = f2;
+			f2 = t;
+			a = ARSB;
+		} else
+			a = ASUB;
+		if(et == TFLOAT)
+			a = ASUBF;
+		else
+		if(et == TDOUBLE || et == TVLONG)
+			a = ASUBD;
+		break;
+
+	case OASOR:
+	case OOR:
+		a = AORR;
+		break;
+
+	case OASAND:
+	case OAND:
+		a = AAND;
+		break;
+
+	case OASXOR:
+	case OXOR:
+		a = AEOR;
+		break;
+
+	case OASLSHR:
+	case OLSHR:
+		a = ASRL;
+		break;
+
+	case OASASHR:
+	case OASHR:
+		a = ASRA;
+		break;
+
+	case OASASHL:
+	case OASHL:
+		a = ASLL;
+		break;
+
+	case OFUNC:
+		a = ABL;
+		break;
+
+	case OASMUL:
+	case OMUL:
+		a = AMUL;
+		if(et == TFLOAT)
+			a = AMULF;
+		else
+		if(et == TDOUBLE || et == TVLONG)
+			a = AMULD;
+		break;
+
+	case OASDIV:
+	case ODIV:
+		a = ADIV;
+		if(et == TFLOAT)
+			a = ADIVF;
+		else
+		if(et == TDOUBLE || et == TVLONG)
+			a = ADIVD;
+		break;
+
+	case OASMOD:
+	case OMOD:
+		a = AMOD;
+		break;
+
+	case OASLMUL:
+	case OLMUL:
+		a = AMULU;
+		break;
+
+	case OASLMOD:
+	case OLMOD:
+		a = AMODU;
+		break;
+
+	case OASLDIV:
+	case OLDIV:
+		a = ADIVU;
+		break;
+
+	case OCASE:
+	case OEQ:
+	case ONE:
+	case OLT:
+	case OLE:
+	case OGE:
+	case OGT:
+	case OLO:
+	case OLS:
+	case OHS:
+	case OHI:
+		a = ACMP;
+		if(et == TFLOAT)
+			a = ACMPF;
+		else
+		if(et == TDOUBLE || et == TVLONG)
+			a = ACMPD;
+		nextpc();
+		p->as = a;
+		naddr(f1, &p->from);
+		if(a == ACMP && f1->op == OCONST && p->from.offset < 0) {
+			p->as = ACMN;
+			p->from.offset = -p->from.offset;
+		}
+		raddr(f2, p);
+		switch(o) {
+		case OEQ:
+			a = ABEQ;
+			break;
+		case ONE:
+			a = ABNE;
+			break;
+		case OLT:
+			a = ABLT;
+			break;
+		case OLE:
+			a = ABLE;
+			break;
+		case OGE:
+			a = ABGE;
+			break;
+		case OGT:
+			a = ABGT;
+			break;
+		case OLO:
+			a = ABLO;
+			break;
+		case OLS:
+			a = ABLS;
+			break;
+		case OHS:
+			a = ABHS;
+			break;
+		case OHI:
+			a = ABHI;
+			break;
+		case OCASE:
+			nextpc();
+			p->as = ACASE;
+			p->scond = 0x9;
+			naddr(f2, &p->from);
+			a = ABHI;
+			break;
+		}
+		f1 = Z;
+		f2 = Z;
+		break;
+	}
+	if(a == AGOK)
+		diag(Z, "bad in gopcode %O", o);
+	nextpc();
+	p->as = a;
+	if(f1 != Z)
+		naddr(f1, &p->from);
+	if(f2 != Z) {
+		naddr(f2, &ta);
+		p->reg = ta.reg;
+	}
+	if(t != Z)
+		naddr(t, &p->to);
+	if(debug['g'])
+		print("%P\n", p);
+}
+
+int
+samaddr(Node *f, Node *t)
+{
+
+	if(f->op != t->op)
+		return 0;
+	switch(f->op) {
+
+	case OREGISTER:
+		if(f->reg != t->reg)
+			break;
+		return 1;
+	}
+	return 0;
+}
+
+void
+gbranch(int o)
+{
+	int a;
+
+	a = AGOK;
+	switch(o) {
+	case ORETURN:
+		a = ARET;
+		break;
+	case OGOTO:
+		a = AB;
+		break;
+	}
+	nextpc();
+	if(a == AGOK) {
+		diag(Z, "bad in gbranch %O",  o);
+		nextpc();
+	}
+	p->as = a;
+}
+
+void
+patch(Prog *op, int32 pc)
+{
+
+	op->to.offset = pc;
+	op->to.type = D_BRANCH;
+}
+
+void
+gpseudo(int a, Sym *s, Node *n)
+{
+	nextpc();
+	p->as = a;
+	p->from.type = D_OREG;
+	p->from.sym = linksym(s);
+	p->from.name = D_EXTERN;
+
+	switch(a) {
+	case ATEXT:
+		p->reg = textflag;
+		textflag = 0;
+		break;
+	case AGLOBL:
+		p->reg = s->dataflag;
+		break;
+	}
+
+	if(s->class == CSTATIC)
+		p->from.name = D_STATIC;
+	naddr(n, &p->to);
+	if(a == ADATA || a == AGLOBL)
+		pc--;
+}
+
+void
+gpcdata(int index, int value)
+{
+	Node n1;
+	
+	n1 = *nodconst(index);
+	gins(APCDATA, &n1, nodconst(value));
+}
+
+void
+gprefetch(Node *n)
+{
+	Node n1;
+
+	regalloc(&n1, n, Z);
+	gmove(n, &n1);
+	n1.op = OINDREG;
+	gins(APLD, &n1, Z);
+	regfree(&n1);
+}
+
+int
+sconst(Node *n)
+{
+	vlong vv;
+
+	if(n->op == OCONST) {
+		if(!typefd[n->type->etype]) {
+			vv = n->vconst;
+			if(vv >= (vlong)(-32766) && vv < (vlong)32766)
+				return 1;
+			/*
+			 * should be specialised for constant values which will
+			 * fit in different instructionsl; for now, let 5l
+			 * sort it out
+			 */
+			return 1;
+		}
+	}
+	return 0;
+}
+
+int
+sval(int32 v)
+{
+	int i;
+
+	for(i=0; i<16; i++) {
+		if((v & ~0xff) == 0)
+			return 1;
+		if((~v & ~0xff) == 0)
+			return 1;
+		v = (v<<2) | ((uint32)v>>30);
+	}
+	return 0;
+}
+
+int32
+exreg(Type *t)
+{
+	int32 o;
+
+	if(typechlp[t->etype]) {
+		if(exregoffset <= REGEXT-4)
+			return 0;
+		o = exregoffset;
+		exregoffset--;
+		return o;
+	}
+	if(typefd[t->etype]) {
+		if(exfregoffset <= NFREG-1)
+			return 0;
+		o = exfregoffset + NREG;
+		exfregoffset--;
+		return o;
+	}
+	return 0;
+}
+
+schar	ewidth[NTYPE] =
+{
+	-1,		/* [TXXX] */
+	SZ_CHAR,	/* [TCHAR] */
+	SZ_CHAR,	/* [TUCHAR] */
+	SZ_SHORT,	/* [TSHORT] */
+	SZ_SHORT,	/* [TUSHORT] */
+	SZ_INT,		/* [TINT] */
+	SZ_INT,		/* [TUINT] */
+	SZ_LONG,	/* [TLONG] */
+	SZ_LONG,	/* [TULONG] */
+	SZ_VLONG,	/* [TVLONG] */
+	SZ_VLONG,	/* [TUVLONG] */
+	SZ_FLOAT,	/* [TFLOAT] */
+	SZ_DOUBLE,	/* [TDOUBLE] */
+	SZ_IND,		/* [TIND] */
+	0,		/* [TFUNC] */
+	-1,		/* [TARRAY] */
+	0,		/* [TVOID] */
+	-1,		/* [TSTRUCT] */
+	-1,		/* [TUNION] */
+	SZ_INT,		/* [TENUM] */
+};
+
+int32	ncast[NTYPE] =
+{
+	0,				/* [TXXX] */
+	BCHAR|BUCHAR,			/* [TCHAR] */
+	BCHAR|BUCHAR,			/* [TUCHAR] */
+	BSHORT|BUSHORT,			/* [TSHORT] */
+	BSHORT|BUSHORT,			/* [TUSHORT] */
+	BINT|BUINT|BLONG|BULONG|BIND,	/* [TINT] */
+	BINT|BUINT|BLONG|BULONG|BIND,	/* [TUINT] */
+	BINT|BUINT|BLONG|BULONG|BIND,	/* [TLONG] */
+	BINT|BUINT|BLONG|BULONG|BIND,	/* [TULONG] */
+	BVLONG|BUVLONG,			/* [TVLONG] */
+	BVLONG|BUVLONG,			/* [TUVLONG] */
+	BFLOAT,				/* [TFLOAT] */
+	BDOUBLE,			/* [TDOUBLE] */
+	BLONG|BULONG|BIND,		/* [TIND] */
+	0,				/* [TFUNC] */
+	0,				/* [TARRAY] */
+	0,				/* [TVOID] */
+	BSTRUCT,			/* [TSTRUCT] */
+	BUNION,				/* [TUNION] */
+	0,				/* [TENUM] */
+};
diff --git a/src/cmd/5g/Makefile b/src/cmd/5g/Makefile
new file mode 100644
index 0000000..3f528d7
--- /dev/null
+++ b/src/cmd/5g/Makefile
@@ -0,0 +1,5 @@
+# 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/5g/cgen.c b/src/cmd/5g/cgen.c
new file mode 100644
index 0000000..87c64f6
--- /dev/null
+++ b/src/cmd/5g/cgen.c
@@ -0,0 +1,1846 @@
+// 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 "gg.h"
+
+/*
+ * generate:
+ *	res = n;
+ * simplifies and calls gmove.
+ */
+void
+cgen(Node *n, Node *res)
+{
+	Node *nl, *nr, *r;
+	Node n1, n2, f0, f1;
+	int a, w, rg;
+	Prog *p1, *p2, *p3;
+	Addr addr;
+
+	if(debug['g']) {
+		dump("\ncgen-n", n);
+		dump("cgen-res", res);
+	}
+	if(n == N || n->type == T)
+		goto ret;
+
+	if(res == N || res->type == T)
+		fatal("cgen: res nil");
+
+	switch(n->op) {
+	case OSLICE:
+	case OSLICEARR:
+	case OSLICESTR:
+	case OSLICE3:
+	case OSLICE3ARR:
+		if (res->op != ONAME || !res->addable) {
+			tempname(&n1, n->type);
+			cgen_slice(n, &n1);
+			cgen(&n1, res);
+		} else
+			cgen_slice(n, res);
+		return;
+	case OEFACE:
+		if (res->op != ONAME || !res->addable) {
+			tempname(&n1, n->type);
+			cgen_eface(n, &n1);
+			cgen(&n1, res);
+		} else
+			cgen_eface(n, res);
+		return;
+	}
+
+	while(n->op == OCONVNOP)
+		n = n->left;
+
+	if(n->ullman >= UINF) {
+		if(n->op == OINDREG)
+			fatal("cgen: this is going to misscompile");
+		if(res->ullman >= UINF) {
+			tempname(&n1, n->type);
+			cgen(n, &n1);
+			cgen(&n1, res);
+			goto ret;
+		}
+	}
+
+	if(isfat(n->type)) {
+		if(n->type->width < 0)
+			fatal("forgot to compute width for %T", n->type);
+		sgen(n, res, n->type->width);
+		goto ret;
+	}
+
+
+	// update addressability for string, slice
+	// can't do in walk because n->left->addable
+	// changes if n->left is an escaping local variable.
+	switch(n->op) {
+	case OSPTR:
+	case OLEN:
+		if(isslice(n->left->type) || istype(n->left->type, TSTRING))
+			n->addable = n->left->addable;
+		break;
+	case OCAP:
+		if(isslice(n->left->type))
+			n->addable = n->left->addable;
+		break;
+	case OITAB:
+		n->addable = n->left->addable;
+		break;
+	}
+
+	// if both are addressable, move
+	if(n->addable && res->addable) {
+		if(is64(n->type) || is64(res->type) ||
+		   n->op == OREGISTER || res->op == OREGISTER ||
+		   iscomplex[n->type->etype] || iscomplex[res->type->etype]) {
+			gmove(n, res);
+		} else {
+			regalloc(&n1, n->type, N);
+			gmove(n, &n1);
+			cgen(&n1, res);
+			regfree(&n1);
+		}
+		goto ret;
+	}
+
+	// if both are not addressable, use a temporary.
+	if(!n->addable && !res->addable) {
+		// could use regalloc here sometimes,
+		// but have to check for ullman >= UINF.
+		tempname(&n1, n->type);
+		cgen(n, &n1);
+		cgen(&n1, res);
+		return;
+	}
+
+	// if result is not addressable directly but n is,
+	// compute its address and then store via the address.
+	if(!res->addable) {
+		igen(res, &n1, N);
+		cgen(n, &n1);
+		regfree(&n1);
+		return;
+	}
+
+	if(complexop(n, res)) {
+		complexgen(n, res);
+		return;
+	}
+
+	// if n is sudoaddable generate addr and move
+	if (!is64(n->type) && !is64(res->type) && !iscomplex[n->type->etype] && !iscomplex[res->type->etype]) {
+		a = optoas(OAS, n->type);
+		if(sudoaddable(a, n, &addr, &w)) {
+			if (res->op != OREGISTER) {
+				regalloc(&n2, res->type, N);
+				p1 = gins(a, N, &n2);
+				p1->from = addr;
+				if(debug['g'])
+					print("%P [ignore previous line]\n", p1);
+				gmove(&n2, res);
+				regfree(&n2);
+			} else {
+				p1 = gins(a, N, res);
+				p1->from = addr;
+				if(debug['g'])
+					print("%P [ignore previous line]\n", p1);
+			}
+			sudoclean();
+			goto ret;
+		}
+	}
+
+	// otherwise, the result is addressable but n is not.
+	// let's do some computation.
+
+	nl = n->left;
+	nr = n->right;
+
+	if(nl != N && nl->ullman >= UINF)
+	if(nr != N && nr->ullman >= UINF) {
+		tempname(&n1, nl->type);
+		cgen(nl, &n1);
+		n2 = *n;
+		n2.left = &n1;
+		cgen(&n2, res);
+		goto ret;
+	}
+
+	// 64-bit ops are hard on 32-bit machine.
+	if(is64(n->type) || is64(res->type) || n->left != N && is64(n->left->type)) {
+		switch(n->op) {
+		// math goes to cgen64.
+		case OMINUS:
+		case OCOM:
+		case OADD:
+		case OSUB:
+		case OMUL:
+		case OLROT:
+		case OLSH:
+		case ORSH:
+		case OAND:
+		case OOR:
+		case OXOR:
+			cgen64(n, res);
+			return;
+		}
+	}
+
+	if(nl != N && isfloat[n->type->etype] && isfloat[nl->type->etype])
+		goto flt;
+	switch(n->op) {
+	default:
+		dump("cgen", n);
+		fatal("cgen: unknown op %+hN", n);
+		break;
+
+	case OREAL:
+	case OIMAG:
+	case OCOMPLEX:
+		fatal("unexpected complex");
+		break;
+
+	// these call bgen to get a bool value
+	case OOROR:
+	case OANDAND:
+	case OEQ:
+	case ONE:
+	case OLT:
+	case OLE:
+	case OGE:
+	case OGT:
+	case ONOT:
+		p1 = gbranch(AB, T, 0);
+		p2 = pc;
+		gmove(nodbool(1), res);
+		p3 = gbranch(AB, T, 0);
+		patch(p1, pc);
+		bgen(n, 1, 0, p2);
+		gmove(nodbool(0), res);
+		patch(p3, pc);
+		goto ret;
+
+	case OPLUS:
+		cgen(nl, res);
+		goto ret;
+
+	// unary
+	case OCOM:
+		a = optoas(OXOR, nl->type);
+		regalloc(&n1, nl->type, N);
+		cgen(nl, &n1);
+		nodconst(&n2, nl->type, -1);
+		gins(a, &n2, &n1);
+		goto norm;
+
+	case OMINUS:
+		regalloc(&n1, nl->type, N);
+		cgen(nl, &n1);
+		nodconst(&n2, nl->type, 0);
+		gins(optoas(OMINUS, nl->type), &n2, &n1);
+		goto norm;
+
+	// symmetric binary
+	case OAND:
+	case OOR:
+	case OXOR:
+	case OADD:
+	case OMUL:
+		a = optoas(n->op, nl->type);
+		goto sbop;
+
+	// asymmetric binary
+	case OSUB:
+		a = optoas(n->op, nl->type);
+		goto abop;
+
+	case OHMUL:
+		cgen_hmul(nl, nr, res);
+		break;
+
+	case OLROT:
+	case OLSH:
+	case ORSH:
+		cgen_shift(n->op, n->bounded, nl, nr, res);
+		break;
+
+	case OCONV:
+		if(eqtype(n->type, nl->type) || noconv(n->type, nl->type)) {
+			cgen(nl, res);
+			break;
+		}
+		if(nl->addable && !is64(nl->type)) {
+			regalloc(&n1, nl->type, res);
+			gmove(nl, &n1);
+		} else {
+			if(n->type->width > widthptr || is64(nl->type) || isfloat[nl->type->etype])
+				tempname(&n1, nl->type);
+			else
+				regalloc(&n1, nl->type, res);
+			cgen(nl, &n1);
+		}
+		if(n->type->width > widthptr || is64(n->type) || isfloat[n->type->etype])
+			tempname(&n2, n->type);
+		else
+			regalloc(&n2, n->type, N);
+		gmove(&n1, &n2);
+		gmove(&n2, res);
+		if(n1.op == OREGISTER)
+			regfree(&n1);
+		if(n2.op == OREGISTER)
+			regfree(&n2);
+		break;
+
+	case ODOT:
+	case ODOTPTR:
+	case OINDEX:
+	case OIND:
+	case ONAME:	// PHEAP or PPARAMREF var
+		igen(n, &n1, res);
+		gmove(&n1, res);
+		regfree(&n1);
+		break;
+
+	case OITAB:
+		// interface table is first word of interface value
+		igen(nl, &n1, res);
+		n1.type = n->type;
+		gmove(&n1, res);
+		regfree(&n1);
+		break;
+
+	case OSPTR:
+		// pointer is the first word of string or slice.
+		if(isconst(nl, CTSTR)) {
+			regalloc(&n1, types[tptr], res);
+			p1 = gins(AMOVW, N, &n1);
+			datastring(nl->val.u.sval->s, nl->val.u.sval->len, &p1->from);
+			gmove(&n1, res);
+			regfree(&n1);
+			break;
+		}
+		igen(nl, &n1, res);
+		n1.type = n->type;
+		gmove(&n1, res);
+		regfree(&n1);
+		break;
+
+	case OLEN:
+		if(istype(nl->type, TMAP) || istype(nl->type, TCHAN)) {
+			// map has len in the first 32-bit word.
+			// a zero pointer means zero length
+			regalloc(&n1, types[tptr], res);
+			cgen(nl, &n1);
+
+			nodconst(&n2, types[tptr], 0);
+			gcmp(optoas(OCMP, types[tptr]), &n1, &n2);
+			p1 = gbranch(optoas(OEQ, types[tptr]), T, -1);
+
+			n2 = n1;
+			n2.op = OINDREG;
+			n2.type = types[TINT32];
+			gmove(&n2, &n1);
+
+			patch(p1, pc);
+
+			gmove(&n1, res);
+			regfree(&n1);
+			break;
+		}
+		if(istype(nl->type, TSTRING) || isslice(nl->type)) {
+			// both slice and string have len one pointer into the struct.
+			igen(nl, &n1, res);
+			n1.type = types[TUINT32];
+			n1.xoffset += Array_nel;
+			gmove(&n1, res);
+			regfree(&n1);
+			break;
+		}
+		fatal("cgen: OLEN: unknown type %lT", nl->type);
+		break;
+
+	case OCAP:
+		if(istype(nl->type, TCHAN)) {
+			// chan has cap in the second 32-bit word.
+			// a zero pointer means zero length
+			regalloc(&n1, types[tptr], res);
+			cgen(nl, &n1);
+
+			nodconst(&n2, types[tptr], 0);
+			gcmp(optoas(OCMP, types[tptr]), &n1, &n2);
+			p1 = gbranch(optoas(OEQ, types[tptr]), T, -1);
+
+			n2 = n1;
+			n2.op = OINDREG;
+			n2.xoffset = 4;
+			n2.type = types[TINT32];
+			gmove(&n2, &n1);
+
+			patch(p1, pc);
+
+			gmove(&n1, res);
+			regfree(&n1);
+			break;
+		}
+		if(isslice(nl->type)) {
+			igen(nl, &n1, res);
+			n1.type = types[TUINT32];
+			n1.xoffset += Array_cap;
+			gmove(&n1, res);
+			regfree(&n1);
+			break;
+		}
+		fatal("cgen: OCAP: unknown type %lT", nl->type);
+		break;
+
+	case OADDR:
+		agen(nl, res);
+		break;
+
+	case OCALLMETH:
+	case OCALLFUNC:
+		// Release res so that it is available for cgen_call.
+		// Pick it up again after the call.
+		rg = -1;
+		if(n->ullman >= UINF) {
+			if(res != N && (res->op == OREGISTER || res->op == OINDREG)) {
+				rg = res->val.u.reg;
+				reg[rg]--;
+			}
+		}
+		if(n->op == OCALLMETH)
+			cgen_callmeth(n, 0);
+		else
+			cgen_call(n, 0);
+		if(rg >= 0)
+			reg[rg]++;
+		cgen_callret(n, res);
+		break;
+
+	case OCALLINTER:
+		cgen_callinter(n, res, 0);
+		cgen_callret(n, res);
+		break;
+
+	case OMOD:
+	case ODIV:
+		a = optoas(n->op, nl->type);
+		goto abop;
+	}
+	goto ret;
+
+sbop:	// symmetric binary
+	if(nl->ullman < nr->ullman) {
+		r = nl;
+		nl = nr;
+		nr = r;
+	}
+
+abop:	// asymmetric binary
+	// TODO(kaib): use fewer registers here.
+	if(nl->ullman >= nr->ullman) {
+		regalloc(&n1, nl->type, res);
+		cgen(nl, &n1);
+		switch(n->op) {
+		case OADD:
+		case OSUB:
+		case OAND:
+		case OOR:
+		case OXOR:
+			if(smallintconst(nr)) {
+				n2 = *nr;
+				break;
+			}
+		default:
+			regalloc(&n2, nr->type, N);
+			cgen(nr, &n2);
+		}
+	} else {
+		switch(n->op) {
+		case OADD:
+		case OSUB:
+		case OAND:
+		case OOR:
+		case OXOR:
+			if(smallintconst(nr)) {
+				n2 = *nr;
+				break;
+			}
+		default:
+			regalloc(&n2, nr->type, res);
+			cgen(nr, &n2);
+		}
+		regalloc(&n1, nl->type, N);
+		cgen(nl, &n1);
+	}
+	gins(a, &n2, &n1);
+norm:
+	// Normalize result for types smaller than word.
+	if(n->type->width < widthptr) {
+		switch(n->op) {
+		case OADD:
+		case OSUB:
+		case OMUL:
+		case OCOM:
+		case OMINUS:
+			gins(optoas(OAS, n->type), &n1, &n1);
+			break;
+		}
+	}
+	gmove(&n1, res);
+	regfree(&n1);
+	if(n2.op != OLITERAL)
+		regfree(&n2);
+	goto ret;
+
+flt:	// floating-point.
+	regalloc(&f0, nl->type, res);
+	if(nr != N)
+		goto flt2;
+
+	if(n->op == OMINUS) {
+		nr = nodintconst(-1);
+		convlit(&nr, n->type);
+		n->op = OMUL;
+		goto flt2;
+	}
+
+	// unary
+	cgen(nl, &f0);
+	if(n->op != OCONV && n->op != OPLUS)
+		gins(optoas(n->op, n->type), &f0, &f0);
+	gmove(&f0, res);
+	regfree(&f0);
+	goto ret;
+
+flt2:	// binary
+	if(nl->ullman >= nr->ullman) {
+		cgen(nl, &f0);
+		regalloc(&f1, n->type, N);
+		gmove(&f0, &f1);
+		cgen(nr, &f0);
+		gins(optoas(n->op, n->type), &f0, &f1);
+	} else {
+		cgen(nr, &f0);
+		regalloc(&f1, n->type, N);
+		cgen(nl, &f1);
+		gins(optoas(n->op, n->type), &f0, &f1);
+	}
+	gmove(&f1, res);
+	regfree(&f0);
+	regfree(&f1);
+	goto ret;
+
+ret:
+	;
+}
+
+/*
+ * generate array index into res.
+ * n might be any size; res is 32-bit.
+ * returns Prog* to patch to panic call.
+ */
+Prog*
+cgenindex(Node *n, Node *res, int bounded)
+{
+	Node tmp, lo, hi, zero, n1, n2;
+
+	if(!is64(n->type)) {
+		cgen(n, res);
+		return nil;
+	}
+
+	tempname(&tmp, types[TINT64]);
+	cgen(n, &tmp);
+	split64(&tmp, &lo, &hi);
+	gmove(&lo, res);
+	if(bounded) {
+		splitclean();
+		return nil;
+	}
+	regalloc(&n1, types[TINT32], N);
+	regalloc(&n2, types[TINT32], N);
+	nodconst(&zero, types[TINT32], 0);
+	gmove(&hi, &n1);
+	gmove(&zero, &n2);
+	gcmp(ACMP, &n1, &n2);
+	regfree(&n2);
+	regfree(&n1);
+	splitclean();
+	return gbranch(ABNE, T, -1);
+}
+
+/*
+ * generate:
+ *	res = &n;
+ * The generated code checks that the result is not nil.
+ */
+void
+agen(Node *n, Node *res)
+{
+	Node *nl;
+	Node n1, n2, n3;
+	int r;
+
+	if(debug['g']) {
+		dump("\nagen-res", res);
+		dump("agen-r", n);
+	}
+	if(n == N || n->type == T || res == N || res->type == T)
+		fatal("agen");
+
+	while(n->op == OCONVNOP)
+		n = n->left;
+
+	if(isconst(n, CTNIL) && n->type->width > widthptr) {
+		// Use of a nil interface or nil slice.
+		// Create a temporary we can take the address of and read.
+		// 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);
+		gmove(&n2, res);
+		regfree(&n2);
+		goto ret;
+	}
+		
+
+	if(n->addable) {
+		memset(&n1, 0, sizeof n1);
+		n1.op = OADDR;
+		n1.left = n;
+		regalloc(&n2, types[tptr], res);
+		gins(AMOVW, &n1, &n2);
+		gmove(&n2, res);
+		regfree(&n2);
+		goto ret;
+	}
+
+	nl = n->left;
+
+	switch(n->op) {
+	default:
+		fatal("agen: unknown op %+hN", n);
+		break;
+
+	case OCALLMETH:
+	case OCALLFUNC:
+		// Release res so that it is available for cgen_call.
+		// Pick it up again after the call.
+		r = -1;
+		if(n->ullman >= UINF) {
+			if(res->op == OREGISTER || res->op == OINDREG) {
+				r = res->val.u.reg;
+				reg[r]--;
+			}
+		}
+		if(n->op == OCALLMETH)
+			cgen_callmeth(n, 0);
+		else
+			cgen_call(n, 0);
+		if(r >= 0)
+			reg[r]++;
+		cgen_aret(n, res);
+		break;
+
+	case OCALLINTER:
+		cgen_callinter(n, res, 0);
+		cgen_aret(n, res);
+		break;
+
+	case OSLICE:
+	case OSLICEARR:
+	case OSLICESTR:
+	case OSLICE3:
+	case OSLICE3ARR:
+		tempname(&n1, n->type);
+		cgen_slice(n, &n1);
+		agen(&n1, res);
+		break;
+
+	case OEFACE:
+		tempname(&n1, n->type);
+		cgen_eface(n, &n1);
+		agen(&n1, res);
+		break;
+
+	case OINDEX:
+		agenr(n, &n1, res);
+		gmove(&n1, res);
+		regfree(&n1);
+		break;
+
+	case ONAME:
+		// should only get here with names in this func.
+		if(n->funcdepth > 0 && n->funcdepth != funcdepth) {
+			dump("bad agen", n);
+			fatal("agen: bad ONAME funcdepth %d != %d",
+				n->funcdepth, funcdepth);
+		}
+
+		// should only get here for heap vars or paramref
+		if(!(n->class & PHEAP) && n->class != PPARAMREF) {
+			dump("bad agen", n);
+			fatal("agen: bad ONAME class %#x", n->class);
+		}
+		cgen(n->heapaddr, res);
+		if(n->xoffset != 0) {
+			nodconst(&n1, types[TINT32], n->xoffset);
+			regalloc(&n2, n1.type, N);
+			regalloc(&n3, types[TINT32], N);
+			gmove(&n1, &n2);
+			gmove(res, &n3);
+			gins(optoas(OADD, types[tptr]), &n2, &n3);
+			gmove(&n3, res);
+			regfree(&n2);
+			regfree(&n3);
+		}
+		break;
+
+	case OIND:
+		cgen(nl, res);
+		cgen_checknil(res);
+		break;
+
+	case ODOT:
+		agen(nl, res);
+		if(n->xoffset != 0) {
+			nodconst(&n1, types[TINT32], n->xoffset);
+			regalloc(&n2, n1.type, N);
+			regalloc(&n3, types[TINT32], N);
+			gmove(&n1, &n2);
+			gmove(res, &n3);
+			gins(optoas(OADD, types[tptr]), &n2, &n3);
+			gmove(&n3, res);
+			regfree(&n2);
+			regfree(&n3);
+		}
+		break;
+
+	case ODOTPTR:
+		cgen(nl, res);
+		cgen_checknil(res);
+		if(n->xoffset != 0) {
+			nodconst(&n1, types[TINT32], n->xoffset);
+			regalloc(&n2, n1.type, N);
+			regalloc(&n3, types[tptr], N);
+			gmove(&n1, &n2);
+			gmove(res, &n3);
+			gins(optoas(OADD, types[tptr]), &n2, &n3);
+			gmove(&n3, res);
+			regfree(&n2);
+			regfree(&n3);
+		}
+		break;
+	}
+
+ret:
+	;
+}
+
+/*
+ * generate:
+ *	newreg = &n;
+ *	res = newreg
+ *
+ * on exit, a has been changed to be *newreg.
+ * caller must regfree(a).
+ * The generated code checks that the result is not *nil.
+ */
+void
+igen(Node *n, Node *a, Node *res)
+{
+	Node n1;
+	int r;
+
+	if(debug['g']) {
+		dump("\nigen-n", n);
+	}
+	switch(n->op) {
+	case ONAME:
+		if((n->class&PHEAP) || n->class == PPARAMREF)
+			break;
+		*a = *n;
+		return;
+
+	case OINDREG:
+		// Increase the refcount of the register so that igen's caller
+		// has to call regfree.
+		if(n->val.u.reg != REGSP)
+			reg[n->val.u.reg]++;
+		*a = *n;
+		return;
+
+	case ODOT:
+		igen(n->left, a, res);
+		a->xoffset += n->xoffset;
+		a->type = n->type;
+		return;
+
+	case ODOTPTR:
+		if(n->left->addable
+			|| n->left->op == OCALLFUNC
+			|| n->left->op == OCALLMETH
+			|| n->left->op == OCALLINTER) {
+			// igen-able nodes.
+			igen(n->left, &n1, res);
+			regalloc(a, types[tptr], &n1);
+			gmove(&n1, a);
+			regfree(&n1);
+		} else {
+			regalloc(a, types[tptr], res);
+			cgen(n->left, a);
+		}
+		cgen_checknil(a);
+		a->op = OINDREG;
+		a->xoffset = n->xoffset;
+		a->type = n->type;
+		return;
+
+	case OCALLMETH:
+	case OCALLFUNC:
+	case OCALLINTER:
+		// Release res so that it is available for cgen_call.
+		// Pick it up again after the call.
+		r = -1;
+		if(n->ullman >= UINF) {
+			if(res != N && (res->op == OREGISTER || res->op == OINDREG)) {
+				r = res->val.u.reg;
+				reg[r]--;
+			}
+		}
+		switch(n->op) {
+		case OCALLMETH:
+			cgen_callmeth(n, 0);
+			break;
+		case OCALLFUNC:
+			cgen_call(n, 0);
+			break;
+		case OCALLINTER:
+			cgen_callinter(n, N, 0);
+			break;
+		}
+		if(r >= 0)
+			reg[r]++;
+		regalloc(a, types[tptr], res);
+		cgen_aret(n, a);
+		a->op = OINDREG;
+		a->type = n->type;
+		return;
+	}
+
+	agenr(n, a, res);
+	a->op = OINDREG;
+	a->type = n->type;
+}
+
+/*
+ * allocate a register in res and generate
+ *  newreg = &n
+ * The caller must call regfree(a).
+ */
+void
+cgenr(Node *n, Node *a, Node *res)
+{
+	Node n1;
+
+	if(debug['g'])
+		dump("cgenr-n", n);
+
+	if(isfat(n->type))
+		fatal("cgenr on fat node");
+
+	if(n->addable) {
+		regalloc(a, types[tptr], res);
+		gmove(n, a);
+		return;
+	}
+
+	switch(n->op) {
+	case ONAME:
+	case ODOT:
+	case ODOTPTR:
+	case OINDEX:
+	case OCALLFUNC:
+	case OCALLMETH:
+	case OCALLINTER:
+		igen(n, &n1, res);
+		regalloc(a, types[tptr], &n1);
+		gmove(&n1, a);
+		regfree(&n1);
+		break;
+	default:
+		regalloc(a, n->type, res);
+		cgen(n, a);
+		break;
+	}
+}
+
+/*
+ * generate:
+ *	newreg = &n;
+ *
+ * caller must regfree(a).
+ * The generated code checks that the result is not nil.
+ */
+void
+agenr(Node *n, Node *a, Node *res)
+{
+	Node *nl, *nr;
+	Node n1, n2, n3, n4, tmp;
+	Prog *p1, *p2;
+	uint32 w;
+	uint64 v;
+	int bounded;
+
+	if(debug['g'])
+		dump("agenr-n", n);
+
+	nl = n->left;
+	nr = n->right;
+
+	switch(n->op) {
+	case ODOT:
+	case ODOTPTR:
+	case OCALLFUNC:
+	case OCALLMETH:
+	case OCALLINTER:
+		igen(n, &n1, res);
+		regalloc(a, types[tptr], &n1);
+		agen(&n1, a);
+		regfree(&n1);
+		break;
+
+	case OIND:
+		cgenr(n->left, a, res);
+		cgen_checknil(a);
+		break;
+
+	case OINDEX:
+		p2 = nil;  // to be patched to panicindex.
+		w = n->type->width;
+		bounded = debug['B'] || n->bounded;
+		if(nr->addable) {
+			if(!isconst(nr, CTINT))
+				tempname(&tmp, types[TINT32]);
+			if(!isconst(nl, CTSTR))
+				agenr(nl, &n3, res);
+			if(!isconst(nr, CTINT)) {
+				p2 = cgenindex(nr, &tmp, bounded);
+				regalloc(&n1, tmp.type, N);
+				gmove(&tmp, &n1);
+			}
+		} else
+		if(nl->addable) {
+			if(!isconst(nr, CTINT)) {
+				tempname(&tmp, types[TINT32]);
+				p2 = cgenindex(nr, &tmp, bounded);
+				regalloc(&n1, tmp.type, N);
+				gmove(&tmp, &n1);
+			}
+			if(!isconst(nl, CTSTR)) {
+				agenr(nl, &n3, res);
+			}
+		} else {
+			tempname(&tmp, types[TINT32]);
+			p2 = cgenindex(nr, &tmp, bounded);
+			nr = &tmp;
+			if(!isconst(nl, CTSTR))
+				agenr(nl, &n3, res);
+			regalloc(&n1, tmp.type, N);
+			gins(optoas(OAS, tmp.type), &tmp, &n1);
+		}
+
+		// &a is in &n3 (allocated in res)
+		// i is in &n1 (if not constant)
+		// w is width
+
+		// constant index
+		if(isconst(nr, CTINT)) {
+			if(isconst(nl, CTSTR))
+				fatal("constant string constant index");
+			v = mpgetfix(nr->val.u.xval);
+			if(isslice(nl->type) || nl->type->etype == TSTRING) {
+				if(!debug['B'] && !n->bounded) {
+					n1 = n3;
+					n1.op = OINDREG;
+					n1.type = types[tptr];
+					n1.xoffset = Array_nel;
+					regalloc(&n4, n1.type, N);
+					gmove(&n1, &n4);
+					nodconst(&n2, types[TUINT32], v);
+					gcmp(optoas(OCMP, types[TUINT32]), &n4, &n2);
+					regfree(&n4);
+					p1 = gbranch(optoas(OGT, types[TUINT32]), T, +1);
+					ginscall(panicindex, 0);
+					patch(p1, pc);
+				}
+
+				n1 = n3;
+				n1.op = OINDREG;
+				n1.type = types[tptr];
+				n1.xoffset = Array_array;
+				gmove(&n1, &n3);
+			}
+
+			nodconst(&n2, types[tptr], v*w);
+			gins(optoas(OADD, types[tptr]), &n2, &n3);
+			*a = n3;
+			break;
+		}
+
+		regalloc(&n2, types[TINT32], &n1);			// i
+		gmove(&n1, &n2);
+		regfree(&n1);
+
+		if(!debug['B'] && !n->bounded) {
+			// check bounds
+			if(isconst(nl, CTSTR)) {
+				nodconst(&n4, types[TUINT32], nl->val.u.sval->len);
+			} else if(isslice(nl->type) || nl->type->etype == TSTRING) {
+				n1 = n3;
+				n1.op = OINDREG;
+				n1.type = types[tptr];
+				n1.xoffset = Array_nel;
+				regalloc(&n4, types[TUINT32], N);
+				gmove(&n1, &n4);
+			} else {
+				nodconst(&n4, types[TUINT32], nl->type->bound);
+			}
+			gcmp(optoas(OCMP, types[TUINT32]), &n2, &n4);
+			if(n4.op == OREGISTER)
+				regfree(&n4);
+			p1 = gbranch(optoas(OLT, types[TUINT32]), T, +1);
+			if(p2)
+				patch(p2, pc);
+			ginscall(panicindex, 0);
+			patch(p1, pc);
+		}
+		
+		if(isconst(nl, CTSTR)) {
+			regalloc(&n3, types[tptr], res);
+			p1 = gins(AMOVW, N, &n3);
+			datastring(nl->val.u.sval->s, nl->val.u.sval->len, &p1->from);
+			p1->from.type = D_CONST;
+		} else
+		if(isslice(nl->type) || nl->type->etype == TSTRING) {
+			n1 = n3;
+			n1.op = OINDREG;
+			n1.type = types[tptr];
+			n1.xoffset = Array_array;
+			gmove(&n1, &n3);
+		}
+
+		if(w == 0) {
+			// nothing to do
+		} else if(w == 1 || w == 2 || w == 4 || w == 8) {
+			memset(&n4, 0, sizeof n4);
+			n4.op = OADDR;
+			n4.left = &n2;
+			cgen(&n4, &n3);
+			if (w == 1)
+				gins(AADD, &n2, &n3);
+			else if(w == 2)
+				gshift(AADD, &n2, SHIFT_LL, 1, &n3);
+			else if(w == 4)
+				gshift(AADD, &n2, SHIFT_LL, 2, &n3);
+			else if(w == 8)
+				gshift(AADD, &n2, SHIFT_LL, 3, &n3);
+		} else {
+			regalloc(&n4, types[TUINT32], N);
+			nodconst(&n1, types[TUINT32], w);
+			gmove(&n1, &n4);
+			gins(optoas(OMUL, types[TUINT32]), &n4, &n2);
+			gins(optoas(OADD, types[tptr]), &n2, &n3);
+			regfree(&n4);
+		}
+
+		*a = n3;
+		regfree(&n2);
+		break;
+
+	default:
+		regalloc(a, types[tptr], res);
+		agen(n, a);
+		break;
+	}
+}
+
+void
+gencmp0(Node *n, Type *t, int o, int likely, Prog *to)
+{
+	Node n1, n2, n3;
+	int a;
+
+	regalloc(&n1, t, N);
+	cgen(n, &n1);
+	a = optoas(OCMP, t);
+	if(a != ACMP) {
+		nodconst(&n2, t, 0);
+		regalloc(&n3, t, N);
+		gmove(&n2, &n3);
+		gcmp(a, &n1, &n3);
+		regfree(&n3);
+	} else
+		gins(ATST, &n1, N);
+	a = optoas(o, t);
+	patch(gbranch(a, t, likely), to);
+	regfree(&n1);
+}
+
+/*
+ * generate:
+ *	if(n == true) goto to;
+ */
+void
+bgen(Node *n, int true, int likely, Prog *to)
+{
+	int et, a;
+	Node *nl, *nr, *r;
+	Node n1, n2, n3, tmp;
+	NodeList *ll;
+	Prog *p1, *p2;
+
+	if(debug['g']) {
+		dump("\nbgen", n);
+	}
+
+	if(n == N)
+		n = nodbool(1);
+
+	if(n->ninit != nil)
+		genlist(n->ninit);
+
+	if(n->type == T) {
+		convlit(&n, types[TBOOL]);
+		if(n->type == T)
+			goto ret;
+	}
+
+	et = n->type->etype;
+	if(et != TBOOL) {
+		yyerror("cgen: bad type %T for %O", n->type, n->op);
+		patch(gins(AEND, N, N), to);
+		goto ret;
+	}
+	nr = N;
+
+	switch(n->op) {
+	default:
+		a = ONE;
+		if(!true)
+			a = OEQ;
+		gencmp0(n, n->type, a, likely, to);
+		goto ret;
+
+	case OLITERAL:
+		// need to ask if it is bool?
+		if(!true == !n->val.u.bval)
+			patch(gbranch(AB, T, 0), to);
+		goto ret;
+
+	case OANDAND:
+		if(!true)
+			goto caseor;
+
+	caseand:
+		p1 = gbranch(AB, T, 0);
+		p2 = gbranch(AB, T, 0);
+		patch(p1, pc);
+		bgen(n->left, !true, -likely, p2);
+		bgen(n->right, !true, -likely, p2);
+		p1 = gbranch(AB, T, 0);
+		patch(p1, to);
+		patch(p2, pc);
+		goto ret;
+
+	case OOROR:
+		if(!true)
+			goto caseand;
+
+	caseor:
+		bgen(n->left, true, likely, to);
+		bgen(n->right, true, likely, to);
+		goto ret;
+
+	case OEQ:
+	case ONE:
+	case OLT:
+	case OGT:
+	case OLE:
+	case OGE:
+		nr = n->right;
+		if(nr == N || nr->type == T)
+			goto ret;
+
+	case ONOT:	// unary
+		nl = n->left;
+		if(nl == N || nl->type == T)
+			goto ret;
+	}
+
+	switch(n->op) {
+
+	case ONOT:
+		bgen(nl, !true, likely, to);
+		goto ret;
+
+	case OEQ:
+	case ONE:
+	case OLT:
+	case OGT:
+	case OLE:
+	case OGE:
+		a = n->op;
+		if(!true) {
+			if(isfloat[nl->type->etype]) {
+				// brcom is not valid on floats when NaN is involved.
+				p1 = gbranch(AB, T, 0);
+				p2 = gbranch(AB, T, 0);
+				patch(p1, pc);
+				ll = n->ninit;
+				n->ninit = nil;
+				bgen(n, 1, -likely, p2);
+				n->ninit = ll;
+				patch(gbranch(AB, T, 0), to);
+				patch(p2, pc);
+				goto ret;
+			}				
+			a = brcom(a);
+			true = !true;
+		}
+
+		// make simplest on right
+		if(nl->op == OLITERAL || (nl->ullman < UINF && nl->ullman < nr->ullman)) {
+			a = brrev(a);
+			r = nl;
+			nl = nr;
+			nr = r;
+		}
+
+		if(isslice(nl->type)) {
+			// only valid to cmp darray to literal nil
+			if((a != OEQ && a != ONE) || nr->op != OLITERAL) {
+				yyerror("illegal array comparison");
+				break;
+			}
+
+			igen(nl, &n1, N);
+			n1.xoffset += Array_array;
+			n1.type = types[tptr];
+			gencmp0(&n1, types[tptr], a, likely, to);
+			regfree(&n1);
+			break;
+		}
+
+		if(isinter(nl->type)) {
+			// front end shold only leave cmp to literal nil
+			if((a != OEQ && a != ONE) || nr->op != OLITERAL) {
+				yyerror("illegal interface comparison");
+				break;
+			}
+
+			igen(nl, &n1, N);
+			n1.type = types[tptr];
+			n1.xoffset += 0;
+			gencmp0(&n1, types[tptr], a, likely, to);
+			regfree(&n1);
+			break;
+		}
+
+		if(iscomplex[nl->type->etype]) {
+			complexbool(a, nl, nr, true, likely, to);
+			break;
+		}
+
+		if(is64(nr->type)) {
+			if(!nl->addable) {
+				tempname(&n1, nl->type);
+				cgen(nl, &n1);
+				nl = &n1;
+			}
+			if(!nr->addable) {
+				tempname(&n2, nr->type);
+				cgen(nr, &n2);
+				nr = &n2;
+			}
+			cmp64(nl, nr, a, likely, to);
+			break;
+		}
+
+		if(nr->op == OLITERAL) {
+			if(isconst(nr, CTINT) &&  mpgetfix(nr->val.u.xval) == 0) {
+				gencmp0(nl, nl->type, a, likely, to);
+				break;
+			}
+			if(nr->val.ctype == CTNIL) {
+				gencmp0(nl, nl->type, a, likely, to);
+				break;
+			}
+		}
+
+		a = optoas(a, nr->type);
+
+		if(nr->ullman >= UINF) {
+			regalloc(&n1, nl->type, N);
+			cgen(nl, &n1);
+
+			tempname(&tmp, nl->type);
+			gmove(&n1, &tmp);
+			regfree(&n1);
+
+			regalloc(&n2, nr->type, N);
+			cgen(nr, &n2);
+
+			regalloc(&n1, nl->type, N);
+			cgen(&tmp, &n1);
+
+			gcmp(optoas(OCMP, nr->type), &n1, &n2);
+			patch(gbranch(a, nr->type, likely), to);
+
+			regfree(&n1);
+			regfree(&n2);
+			break;
+		}
+
+		tempname(&n3, nl->type);
+		cgen(nl, &n3);
+
+		tempname(&tmp, nr->type);
+		cgen(nr, &tmp);
+
+		regalloc(&n1, nl->type, N);
+		gmove(&n3, &n1);
+
+		regalloc(&n2, nr->type, N);
+		gmove(&tmp, &n2);
+
+		gcmp(optoas(OCMP, nr->type), &n1, &n2);
+		if(isfloat[nl->type->etype]) {
+			if(n->op == ONE) {
+				p1 = gbranch(ABVS, nr->type, likely);
+				patch(gbranch(a, nr->type, likely), to);
+				patch(p1, to);
+			} else {
+				p1 = gbranch(ABVS, nr->type, -likely);
+				patch(gbranch(a, nr->type, likely), to);
+				patch(p1, pc);
+			}
+		} else {
+			patch(gbranch(a, nr->type, likely), to);
+		}
+		regfree(&n1);
+		regfree(&n2);
+		break;
+	}
+	goto ret;
+
+ret:
+	;
+}
+
+/*
+ * n is on stack, either local variable
+ * or return value from function call.
+ * return n's offset from SP.
+ */
+int32
+stkof(Node *n)
+{
+	Type *t;
+	Iter flist;
+	int32 off;
+
+	switch(n->op) {
+	case OINDREG:
+		return n->xoffset;
+
+	case ODOT:
+		t = n->left->type;
+		if(isptr[t->etype])
+			break;
+		off = stkof(n->left);
+		if(off == -1000 || off == 1000)
+			return off;
+		return off + n->xoffset;
+
+	case OINDEX:
+		t = n->left->type;
+		if(!isfixedarray(t))
+			break;
+		off = stkof(n->left);
+		if(off == -1000 || off == 1000)
+			return off;
+		if(isconst(n->right, CTINT))
+			return off + t->type->width * mpgetfix(n->right->val.u.xval);
+		return 1000;
+		
+	case OCALLMETH:
+	case OCALLINTER:
+	case OCALLFUNC:
+		t = n->left->type;
+		if(isptr[t->etype])
+			t = t->type;
+
+		t = structfirst(&flist, getoutarg(t));
+		if(t != T)
+			return t->width + 4;	// correct for LR
+		break;
+	}
+
+	// botch - probably failing to recognize address
+	// arithmetic on the above. eg INDEX and DOT
+	return -1000;
+}
+
+/*
+ * block copy:
+ *	memmove(&res, &n, w);
+ * NB: character copy assumed little endian architecture
+ */
+void
+sgen(Node *n, Node *res, int64 w)
+{
+	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);
+		dump("r", n);
+		dump("res", res);
+	}
+
+	if(n->ullman >= UINF && res->ullman >= UINF)
+		fatal("sgen UINF");
+
+	if(w < 0 || (int32)w != w)
+		fatal("sgen copy %lld", w);
+
+	if(n->type == T)
+		fatal("sgen: missing type");
+
+	if(w == 0) {
+		// evaluate side effects only.
+		regalloc(&dst, types[tptr], N);
+		agen(res, &dst);
+		agen(n, &dst);
+		regfree(&dst);
+		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;
+	
+	// determine alignment.
+	// want to avoid unaligned access, so have to use
+	// smaller operations for less aligned types.
+	// for example moving [4]byte must use 4 MOVB not 1 MOVW.
+	align = n->type->align;
+	switch(align) {
+	default:
+		fatal("sgen: invalid alignment %d for %T", align, n->type);
+	case 1:
+		op = AMOVB;
+		break;
+	case 2:
+		op = AMOVH;
+		break;
+	case 4:
+		op = AMOVW;
+		break;
+	}
+	if(w%align)
+		fatal("sgen: unaligned size %lld (align=%d) for %T", w, align, n->type);
+	c = w / align;
+
+	// offset on the stack
+	osrc = stkof(n);
+	odst = stkof(res);
+	if(osrc != -1000 && odst != -1000 && (osrc == 1000 || odst == 1000)) {
+		// osrc and odst both on stack, and at least one is in
+		// an unknown position.  Could generate code to test
+		// for forward/backward copy, but instead just copy
+		// to a temporary location first.
+		tempname(&tmp, n->type);
+		sgen(n, &tmp, w);
+		sgen(&tmp, res, w);
+		return;
+	}
+	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 && !nacl && 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 ../../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);
+	}
+
+	regalloc(&tmp, types[TUINT32], N);
+
+	// set up end marker
+	memset(&nend, 0, sizeof nend);
+	if(c >= 4) {
+		regalloc(&nend, types[TUINT32], N);
+
+		p = gins(AMOVW, &src, &nend);
+		p->from.type = D_CONST;
+		if(dir < 0)
+			p->from.offset = dir;
+		else
+			p->from.offset = w;
+	}
+
+	// move src and dest to the end of block if necessary
+	if(dir < 0) {
+		p = gins(AMOVW, &src, &src);
+		p->from.type = D_CONST;
+		p->from.offset = w + dir;
+
+		p = gins(AMOVW, &dst, &dst);
+		p->from.type = D_CONST;
+		p->from.offset = w + dir;
+	}
+	
+	// move
+	if(c >= 4) {
+		p = gins(op, &src, &tmp);
+		p->from.type = D_OREG;
+		p->from.offset = dir;
+		p->scond |= C_PBIT;
+		ploop = p;
+
+		p = gins(op, &tmp, &dst);
+		p->to.type = D_OREG;
+		p->to.offset = dir;
+		p->scond |= C_PBIT;
+
+		p = gins(ACMP, &src, N);
+		raddr(&nend, p);
+
+		patch(gbranch(ABNE, T, 0), ploop);
+ 		regfree(&nend);
+	} else {
+		while(c-- > 0) {
+			p = gins(op, &src, &tmp);
+			p->from.type = D_OREG;
+			p->from.offset = dir;
+			p->scond |= C_PBIT;
+	
+			p = gins(op, &tmp, &dst);
+			p->to.type = D_OREG;
+			p->to.offset = dir;
+			p->scond |= C_PBIT;
+		}
+	}
+
+	regfree(&dst);
+	regfree(&src);
+	regfree(&tmp);
+}
+
+static int
+cadable(Node *n)
+{
+	if(!n->addable) {
+		// dont know how it happens,
+		// but it does
+		return 0;
+	}
+
+	switch(n->op) {
+	case ONAME:
+		return 1;
+	}
+	return 0;
+}
+
+/*
+ * copy a composite value by moving its individual components.
+ * Slices, strings and interfaces are supported.
+ * nr is N when assigning a zero value.
+ * return 1 if can do, 0 if cant.
+ */
+int
+componentgen(Node *nr, Node *nl)
+{
+	Node nodl, nodr, tmp;
+	Type *t;
+	int freel, freer;
+	vlong fldcount;
+	vlong loffset, roffset;
+
+	freel = 0;
+	freer = 0;
+
+	switch(nl->type->etype) {
+	default:
+		goto no;
+
+	case TARRAY:
+		t = nl->type;
+
+		// Slices are ok.
+		if(isslice(t))
+			break;
+		// Small arrays are ok.
+		if(t->bound > 0 && t->bound <= 3 && !isfat(t->type))
+			break;
+
+		goto no;
+
+	case TSTRUCT:
+		// Small structs with non-fat types are ok.
+		// Zero-sized structs are treated separately elsewhere.
+		fldcount = 0;
+		for(t=nl->type->type; t; t=t->down) {
+			if(isfat(t->type))
+				goto no;
+			if(t->etype != TFIELD)
+				fatal("componentgen: not a TFIELD: %lT", t);
+			fldcount++;
+		}
+		if(fldcount == 0 || fldcount > 4)
+			goto no;
+
+		break;
+
+	case TSTRING:
+	case TINTER:
+		break;
+	}
+
+	nodl = *nl;
+	if(!cadable(nl)) {
+		if(nr == N || !cadable(nr))
+			goto no;
+		igen(nl, &nodl, N);
+		freel = 1;
+	}
+
+	if(nr != N) {
+		nodr = *nr;
+		if(!cadable(nr)) {
+			igen(nr, &nodr, N);
+			freer = 1;
+		}
+	} else {
+		// When zeroing, prepare a register containing zero.
+		nodconst(&tmp, nl->type, 0);
+		regalloc(&nodr, types[TUINT], N);
+		gmove(&tmp, &nodr);
+		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;
+			nodr.type = nodl.type;
+			for(fldcount=0; fldcount < t->bound; fldcount++) {
+				if(nr == N)
+					clearslim(&nodl);
+				else
+					gmove(&nodr, &nodl);
+				nodl.xoffset += t->type->width;
+				nodr.xoffset += t->type->width;
+			}
+			goto yes;
+		}
+
+		// componentgen for slices.
+		nodl.xoffset += Array_array;
+		nodl.type = ptrto(nl->type->type);
+
+		if(nr != N) {
+			nodr.xoffset += Array_array;
+			nodr.type = nodl.type;
+		}
+		gmove(&nodr, &nodl);
+
+		nodl.xoffset += Array_nel-Array_array;
+		nodl.type = types[simtype[TUINT]];
+
+		if(nr != N) {
+			nodr.xoffset += Array_nel-Array_array;
+			nodr.type = nodl.type;
+		}
+		gmove(&nodr, &nodl);
+
+		nodl.xoffset += Array_cap-Array_nel;
+		nodl.type = types[simtype[TUINT]];
+
+		if(nr != N) {
+			nodr.xoffset += Array_cap-Array_nel;
+			nodr.type = nodl.type;
+		}
+		gmove(&nodr, &nodl);
+
+		goto yes;
+
+	case TSTRING:
+		if(nl->op == ONAME)
+			gvardef(nl);
+		nodl.xoffset += Array_array;
+		nodl.type = ptrto(types[TUINT8]);
+
+		if(nr != N) {
+			nodr.xoffset += Array_array;
+			nodr.type = nodl.type;
+		}
+		gmove(&nodr, &nodl);
+
+		nodl.xoffset += Array_nel-Array_array;
+		nodl.type = types[simtype[TUINT]];
+
+		if(nr != N) {
+			nodr.xoffset += Array_nel-Array_array;
+			nodr.type = nodl.type;
+		}
+		gmove(&nodr, &nodl);
+
+		goto yes;
+
+	case TINTER:
+		if(nl->op == ONAME)
+			gvardef(nl);
+		nodl.xoffset += Array_array;
+		nodl.type = ptrto(types[TUINT8]);
+
+		if(nr != N) {
+			nodr.xoffset += Array_array;
+			nodr.type = nodl.type;
+		}
+		gmove(&nodr, &nodl);
+
+		nodl.xoffset += Array_nel-Array_array;
+		nodl.type = ptrto(types[TUINT8]);
+
+		if(nr != N) {
+			nodr.xoffset += Array_nel-Array_array;
+			nodr.type = nodl.type;
+		}
+		gmove(&nodr, &nodl);
+
+		goto yes;
+
+	case TSTRUCT:
+		if(nl->op == ONAME)
+			gvardef(nl);
+		loffset = nodl.xoffset;
+		roffset = nodr.xoffset;
+		// funarg structs may not begin at offset zero.
+		if(nl->type->etype == TSTRUCT && nl->type->funarg && nl->type->type)
+			loffset -= nl->type->type->width;
+		if(nr != N && nr->type->etype == TSTRUCT && nr->type->funarg && nr->type->type)
+			roffset -= nr->type->type->width;
+
+		for(t=nl->type->type; t; t=t->down) {
+			nodl.xoffset = loffset + t->width;
+			nodl.type = t->type;
+
+			if(nr == N)
+				clearslim(&nodl);
+			else {
+				nodr.xoffset = roffset + t->width;
+				nodr.type = nodl.type;
+				gmove(&nodr, &nodl);
+			}
+		}
+		goto yes;
+	}
+
+no:
+	if(freer)
+		regfree(&nodr);
+	if(freel)
+		regfree(&nodl);
+	return 0;
+
+yes:
+	if(freer)
+		regfree(&nodr);
+	if(freel)
+		regfree(&nodl);
+	return 1;
+}
diff --git a/src/cmd/5g/cgen64.c b/src/cmd/5g/cgen64.c
new file mode 100644
index 0000000..ef11e2a
--- /dev/null
+++ b/src/cmd/5g/cgen64.c
@@ -0,0 +1,760 @@
+// 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 "gg.h"
+
+/*
+ * attempt to generate 64-bit
+ *	res = n
+ * return 1 on success, 0 if op not handled.
+ */
+void
+cgen64(Node *n, Node *res)
+{
+	Node t1, t2, *l, *r;
+	Node lo1, lo2, hi1, hi2;
+	Node al, ah, bl, bh, cl, ch, s, n1, creg;
+	Prog *p1, *p2, *p3, *p4, *p5, *p6;
+
+	uint64 v;
+
+	if(res->op != OINDREG && res->op != ONAME) {
+		dump("n", n);
+		dump("res", res);
+		fatal("cgen64 %O of %O", n->op, res->op);
+	}
+
+	l = n->left;
+	if(!l->addable) {
+		tempname(&t1, l->type);
+		cgen(l, &t1);
+		l = &t1;
+	}
+
+	split64(l, &lo1, &hi1);
+	switch(n->op) {
+	default:
+		fatal("cgen64 %O", n->op);
+
+	case OMINUS:
+		split64(res, &lo2, &hi2);
+
+		regalloc(&t1, lo1.type, N);
+		regalloc(&al, lo1.type, N);
+		regalloc(&ah, hi1.type, N);
+
+		gins(AMOVW, &lo1, &al);
+		gins(AMOVW, &hi1, &ah);
+
+		gmove(ncon(0), &t1);
+		p1 = gins(ASUB, &al, &t1);
+		p1->scond |= C_SBIT;
+		gins(AMOVW, &t1, &lo2);
+
+		gmove(ncon(0), &t1);
+		gins(ASBC, &ah, &t1);
+		gins(AMOVW, &t1, &hi2);
+
+		regfree(&t1);
+		regfree(&al);
+		regfree(&ah);
+		splitclean();
+		splitclean();
+		return;
+
+	case OCOM:
+		regalloc(&t1, lo1.type, N);
+		gmove(ncon(-1), &t1);
+
+		split64(res, &lo2, &hi2);
+		regalloc(&n1, lo1.type, N);
+
+		gins(AMOVW, &lo1, &n1);
+		gins(AEOR, &t1, &n1);
+		gins(AMOVW, &n1, &lo2);
+
+		gins(AMOVW, &hi1, &n1);
+		gins(AEOR, &t1, &n1);
+		gins(AMOVW, &n1, &hi2);
+
+		regfree(&t1);
+		regfree(&n1);
+		splitclean();
+		splitclean();
+		return;
+
+	case OADD:
+	case OSUB:
+	case OMUL:
+	case OLSH:
+	case ORSH:
+	case OAND:
+	case OOR:
+	case OXOR:
+	case OLROT:
+		// binary operators.
+		// common setup below.
+		break;
+	}
+
+	// setup for binary operators
+	r = n->right;
+	if(r != N && !r->addable) {
+		tempname(&t2, r->type);
+		cgen(r, &t2);
+		r = &t2;
+	}
+	if(is64(r->type))
+		split64(r, &lo2, &hi2);
+
+	regalloc(&al, lo1.type, N);
+	regalloc(&ah, hi1.type, N);
+
+	// Do op.  Leave result in ah:al.
+	switch(n->op) {
+	default:
+		fatal("cgen64: not implemented: %N\n", n);
+
+	case OADD:
+		// TODO: Constants
+		regalloc(&bl, types[TPTR32], N);
+		regalloc(&bh, types[TPTR32], N);
+		gins(AMOVW, &hi1, &ah);
+		gins(AMOVW, &lo1, &al);
+		gins(AMOVW, &hi2, &bh);
+		gins(AMOVW, &lo2, &bl);
+		p1 = gins(AADD, &bl, &al);
+		p1->scond |= C_SBIT;
+		gins(AADC, &bh, &ah);
+		regfree(&bl);
+		regfree(&bh);
+		break;
+
+	case OSUB:
+		// TODO: Constants.
+		regalloc(&bl, types[TPTR32], N);
+		regalloc(&bh, types[TPTR32], N);
+		gins(AMOVW, &lo1, &al);
+		gins(AMOVW, &hi1, &ah);
+		gins(AMOVW, &lo2, &bl);
+		gins(AMOVW, &hi2, &bh);
+		p1 = gins(ASUB, &bl, &al);
+		p1->scond |= C_SBIT;
+		gins(ASBC, &bh, &ah);
+		regfree(&bl);
+		regfree(&bh);
+		break;
+
+	case OMUL:
+		// TODO(kaib): this can be done with 4 regs and does not need 6
+		regalloc(&bl, types[TPTR32], N);
+		regalloc(&bh, types[TPTR32], N);
+		regalloc(&cl, types[TPTR32], N);
+		regalloc(&ch, types[TPTR32], N);
+
+		// load args into bh:bl and bh:bl.
+		gins(AMOVW, &hi1, &bh);
+		gins(AMOVW, &lo1, &bl);
+		gins(AMOVW, &hi2, &ch);
+		gins(AMOVW, &lo2, &cl);
+
+		// bl * cl -> ah al
+		p1 = gins(AMULLU, N, N);
+		p1->from.type = D_REG;
+		p1->from.reg = bl.val.u.reg;
+		p1->reg = cl.val.u.reg;
+		p1->to.type = D_REGREG;
+		p1->to.reg = ah.val.u.reg;
+		p1->to.offset = al.val.u.reg;
+//print("%P\n", p1);
+
+		// bl * ch + ah -> ah
+		p1 = gins(AMULA, N, N);
+		p1->from.type = D_REG;
+		p1->from.reg = bl.val.u.reg;
+		p1->reg = ch.val.u.reg;
+		p1->to.type = D_REGREG2;
+		p1->to.reg = ah.val.u.reg;
+		p1->to.offset = ah.val.u.reg;
+//print("%P\n", p1);
+
+		// bh * cl + ah -> ah
+		p1 = gins(AMULA, N, N);
+		p1->from.type = D_REG;
+		p1->from.reg = bh.val.u.reg;
+		p1->reg = cl.val.u.reg;
+		p1->to.type = D_REGREG2;
+		p1->to.reg = ah.val.u.reg;
+		p1->to.offset = ah.val.u.reg;
+//print("%P\n", p1);
+
+		regfree(&bh);
+		regfree(&bl);
+		regfree(&ch);
+		regfree(&cl);
+
+		break;
+
+	case OLROT:
+		// We only rotate by a constant c in [0,64).
+		// if c >= 32:
+		//	lo, hi = hi, lo
+		//	c -= 32
+		// if c == 0:
+		//	no-op
+		// else:
+		//	t = hi
+		//	shld hi:lo, c
+		//	shld lo:t, c
+		v = mpgetfix(r->val.u.xval);
+		regalloc(&bl, lo1.type, N);
+		regalloc(&bh, hi1.type, N);
+		if(v >= 32) {
+			// reverse during load to do the first 32 bits of rotate
+			v -= 32;
+			gins(AMOVW, &hi1, &bl);
+			gins(AMOVW, &lo1, &bh);
+		} else {
+			gins(AMOVW, &hi1, &bh);
+			gins(AMOVW, &lo1, &bl);
+		}
+		if(v == 0) {
+			gins(AMOVW, &bh, &ah);
+			gins(AMOVW, &bl, &al);
+		} else {
+			// rotate by 1 <= v <= 31
+			//	MOVW	bl<<v, al
+			//	MOVW	bh<<v, ah
+			//	OR		bl>>(32-v), ah
+			//	OR		bh>>(32-v), al
+			gshift(AMOVW, &bl, SHIFT_LL, v, &al);
+			gshift(AMOVW, &bh, SHIFT_LL, v, &ah);
+			gshift(AORR, &bl, SHIFT_LR, 32-v, &ah);
+			gshift(AORR, &bh, SHIFT_LR, 32-v, &al);
+		}
+		regfree(&bl);
+		regfree(&bh);
+		break;
+
+	case OLSH:
+		regalloc(&bl, lo1.type, N);
+		regalloc(&bh, hi1.type, N);
+		gins(AMOVW, &hi1, &bh);
+		gins(AMOVW, &lo1, &bl);
+
+		if(r->op == OLITERAL) {
+			v = mpgetfix(r->val.u.xval);
+			if(v >= 64) {
+				// TODO(kaib): replace with gins(AMOVW, nodintconst(0), &al)
+				// here and below (verify it optimizes to EOR)
+				gins(AEOR, &al, &al);
+				gins(AEOR, &ah, &ah);
+			} else
+			if(v > 32) {
+				gins(AEOR, &al, &al);
+				//	MOVW	bl<<(v-32), ah
+				gshift(AMOVW, &bl, SHIFT_LL, (v-32), &ah);
+			} else
+			if(v == 32) {
+				gins(AEOR, &al, &al);
+				gins(AMOVW, &bl, &ah);
+			} else
+			if(v > 0) {
+				//	MOVW	bl<<v, al
+				gshift(AMOVW, &bl, SHIFT_LL, v, &al);
+
+				//	MOVW	bh<<v, ah
+				gshift(AMOVW, &bh, SHIFT_LL, v, &ah);
+
+				//	OR		bl>>(32-v), ah
+				gshift(AORR, &bl, SHIFT_LR, 32-v, &ah);
+			} else {
+				gins(AMOVW, &bl, &al);
+				gins(AMOVW, &bh, &ah);
+			}
+			goto olsh_break;
+		}
+
+		regalloc(&s, types[TUINT32], N);
+		regalloc(&creg, types[TUINT32], N);
+		if (is64(r->type)) {
+			// shift is >= 1<<32
+			split64(r, &cl, &ch);
+			gmove(&ch, &s);
+			gins(ATST, &s, N);
+			p6 = gbranch(ABNE, T, 0);
+			gmove(&cl, &s);
+			splitclean();
+		} else {
+			gmove(r, &s);
+			p6 = P;
+		}
+		gins(ATST, &s, N);
+
+		// shift == 0
+		p1 = gins(AMOVW, &bl, &al);
+		p1->scond = C_SCOND_EQ;
+		p1 = gins(AMOVW, &bh, &ah);
+		p1->scond = C_SCOND_EQ;
+		p2 = gbranch(ABEQ, T, 0);
+
+		// shift is < 32
+		nodconst(&n1, types[TUINT32], 32);
+		gmove(&n1, &creg);
+		gcmp(ACMP, &s, &creg);
+
+		//	MOVW.LO		bl<<s, al
+		p1 = gregshift(AMOVW, &bl, SHIFT_LL, &s, &al);
+		p1->scond = C_SCOND_LO;
+
+		//	MOVW.LO		bh<<s, ah
+		p1 = gregshift(AMOVW, &bh, SHIFT_LL, &s, &ah);
+		p1->scond = C_SCOND_LO;
+
+		//	SUB.LO		s, creg
+		p1 = gins(ASUB, &s, &creg);
+		p1->scond = C_SCOND_LO;
+
+		//	OR.LO		bl>>creg, ah
+		p1 = gregshift(AORR, &bl, SHIFT_LR, &creg, &ah);
+		p1->scond = C_SCOND_LO;
+
+		//	BLO	end
+		p3 = gbranch(ABLO, T, 0);
+
+		// shift == 32
+		p1 = gins(AEOR, &al, &al);
+		p1->scond = C_SCOND_EQ;
+		p1 = gins(AMOVW, &bl, &ah);
+		p1->scond = C_SCOND_EQ;
+		p4 = gbranch(ABEQ, T, 0);
+
+		// shift is < 64
+		nodconst(&n1, types[TUINT32], 64);
+		gmove(&n1, &creg);
+		gcmp(ACMP, &s, &creg);
+
+		//	EOR.LO	al, al
+		p1 = gins(AEOR, &al, &al);
+		p1->scond = C_SCOND_LO;
+
+		//	MOVW.LO		creg>>1, creg
+		p1 = gshift(AMOVW, &creg, SHIFT_LR, 1, &creg);
+		p1->scond = C_SCOND_LO;
+
+		//	SUB.LO		creg, s
+		p1 = gins(ASUB, &creg, &s);
+		p1->scond = C_SCOND_LO;
+
+		//	MOVW	bl<<s, ah
+		p1 = gregshift(AMOVW, &bl, SHIFT_LL, &s, &ah);
+		p1->scond = C_SCOND_LO;
+
+		p5 = gbranch(ABLO, T, 0);
+
+		// shift >= 64
+		if (p6 != P) patch(p6, pc);
+		gins(AEOR, &al, &al);
+		gins(AEOR, &ah, &ah);
+
+		patch(p2, pc);
+		patch(p3, pc);
+		patch(p4, pc);
+		patch(p5, pc);
+		regfree(&s);
+		regfree(&creg);
+
+olsh_break:
+		regfree(&bl);
+		regfree(&bh);
+		break;
+
+
+	case ORSH:
+		regalloc(&bl, lo1.type, N);
+		regalloc(&bh, hi1.type, N);
+		gins(AMOVW, &hi1, &bh);
+		gins(AMOVW, &lo1, &bl);
+
+		if(r->op == OLITERAL) {
+			v = mpgetfix(r->val.u.xval);
+			if(v >= 64) {
+				if(bh.type->etype == TINT32) {
+					//	MOVW	bh->31, al
+					gshift(AMOVW, &bh, SHIFT_AR, 31, &al);
+
+					//	MOVW	bh->31, ah
+					gshift(AMOVW, &bh, SHIFT_AR, 31, &ah);
+				} else {
+					gins(AEOR, &al, &al);
+					gins(AEOR, &ah, &ah);
+				}
+			} else
+			if(v > 32) {
+				if(bh.type->etype == TINT32) {
+					//	MOVW	bh->(v-32), al
+					gshift(AMOVW, &bh, SHIFT_AR, v-32, &al);
+
+					//	MOVW	bh->31, ah
+					gshift(AMOVW, &bh, SHIFT_AR, 31, &ah);
+				} else {
+					//	MOVW	bh>>(v-32), al
+					gshift(AMOVW, &bh, SHIFT_LR, v-32, &al);
+					gins(AEOR, &ah, &ah);
+				}
+			} else
+			if(v == 32) {
+				gins(AMOVW, &bh, &al);
+				if(bh.type->etype == TINT32) {
+					//	MOVW	bh->31, ah
+					gshift(AMOVW, &bh, SHIFT_AR, 31, &ah);
+				} else {
+					gins(AEOR, &ah, &ah);
+				}
+			} else
+			if( v > 0) {
+				//	MOVW	bl>>v, al
+				gshift(AMOVW, &bl, SHIFT_LR, v, &al);
+	
+				//	OR		bh<<(32-v), al
+				gshift(AORR, &bh, SHIFT_LL, 32-v, &al);
+
+				if(bh.type->etype == TINT32) {
+					//	MOVW	bh->v, ah
+					gshift(AMOVW, &bh, SHIFT_AR, v, &ah);
+				} else {
+					//	MOVW	bh>>v, ah
+					gshift(AMOVW, &bh, SHIFT_LR, v, &ah);
+				}
+			} else {
+				gins(AMOVW, &bl, &al);
+				gins(AMOVW, &bh, &ah);
+			}
+			goto orsh_break;
+		}
+
+		regalloc(&s, types[TUINT32], N);
+		regalloc(&creg, types[TUINT32], N);
+		if(is64(r->type)) {
+			// shift is >= 1<<32
+			split64(r, &cl, &ch);
+			gmove(&ch, &s);
+			gins(ATST, &s, N);
+			if(bh.type->etype == TINT32)
+				p1 = gshift(AMOVW, &bh, SHIFT_AR, 31, &ah);
+			else
+				p1 = gins(AEOR, &ah, &ah);
+			p1->scond = C_SCOND_NE;
+			p6 = gbranch(ABNE, T, 0);
+			gmove(&cl, &s);
+			splitclean();
+		} else {
+			gmove(r, &s);
+			p6 = P;
+		}
+		gins(ATST, &s, N);
+
+		// shift == 0
+		p1 = gins(AMOVW, &bl, &al);
+		p1->scond = C_SCOND_EQ;
+		p1 = gins(AMOVW, &bh, &ah);
+		p1->scond = C_SCOND_EQ;
+		p2 = gbranch(ABEQ, T, 0);
+
+		// check if shift is < 32
+		nodconst(&n1, types[TUINT32], 32);
+		gmove(&n1, &creg);
+		gcmp(ACMP, &s, &creg);
+
+		//	MOVW.LO		bl>>s, al
+		p1 = gregshift(AMOVW, &bl, SHIFT_LR, &s, &al);
+		p1->scond = C_SCOND_LO;
+
+		//	SUB.LO		s,creg
+		p1 = gins(ASUB, &s, &creg);
+		p1->scond = C_SCOND_LO;
+
+		//	OR.LO		bh<<(32-s), al
+		p1 = gregshift(AORR, &bh, SHIFT_LL, &creg, &al);
+		p1->scond = C_SCOND_LO;
+
+		if(bh.type->etype == TINT32) {
+			//	MOVW	bh->s, ah
+			p1 = gregshift(AMOVW, &bh, SHIFT_AR, &s, &ah);
+		} else {
+			//	MOVW	bh>>s, ah
+			p1 = gregshift(AMOVW, &bh, SHIFT_LR, &s, &ah);
+		}
+		p1->scond = C_SCOND_LO;
+
+		//	BLO	end
+		p3 = gbranch(ABLO, T, 0);
+
+		// shift == 32
+		p1 = gins(AMOVW, &bh, &al);
+		p1->scond = C_SCOND_EQ;
+		if(bh.type->etype == TINT32)
+			gshift(AMOVW, &bh, SHIFT_AR, 31, &ah);
+		else
+			gins(AEOR, &ah, &ah);
+		p4 = gbranch(ABEQ, T, 0);
+
+		// check if shift is < 64
+		nodconst(&n1, types[TUINT32], 64);
+		gmove(&n1, &creg);
+		gcmp(ACMP, &s, &creg);
+
+		//	MOVW.LO		creg>>1, creg
+		p1 = gshift(AMOVW, &creg, SHIFT_LR, 1, &creg);
+		p1->scond = C_SCOND_LO;
+
+		//	SUB.LO		creg, s
+		p1 = gins(ASUB, &creg, &s);
+		p1->scond = C_SCOND_LO;
+
+		if(bh.type->etype == TINT32) {
+			//	MOVW	bh->(s-32), al
+			p1 = gregshift(AMOVW, &bh, SHIFT_AR, &s, &al);
+			p1->scond = C_SCOND_LO;
+		} else {
+			//	MOVW	bh>>(v-32), al
+			p1 = gregshift(AMOVW, &bh, SHIFT_LR, &s, &al);
+			p1->scond = C_SCOND_LO;
+		}
+
+		//	BLO	end
+		p5 = gbranch(ABLO, T, 0);
+
+		// s >= 64
+		if(p6 != P)
+			patch(p6, pc);
+		if(bh.type->etype == TINT32) {
+			//	MOVW	bh->31, al
+			gshift(AMOVW, &bh, SHIFT_AR, 31, &al);
+		} else {
+			gins(AEOR, &al, &al);
+		}
+
+		patch(p2, pc);
+		patch(p3, pc);
+		patch(p4, pc);
+		patch(p5, pc);
+		regfree(&s);
+		regfree(&creg);
+
+
+orsh_break:
+		regfree(&bl);
+		regfree(&bh);
+		break;
+
+	case OXOR:
+	case OAND:
+	case OOR:
+		// TODO(kaib): literal optimizations
+		// make constant the right side (it usually is anyway).
+//		if(lo1.op == OLITERAL) {
+//			nswap(&lo1, &lo2);
+//			nswap(&hi1, &hi2);
+//		}
+//		if(lo2.op == OLITERAL) {
+//			// special cases for constants.
+//			lv = mpgetfix(lo2.val.u.xval);
+//			hv = mpgetfix(hi2.val.u.xval);
+//			splitclean();	// right side
+//			split64(res, &lo2, &hi2);
+//			switch(n->op) {
+//			case OXOR:
+//				gmove(&lo1, &lo2);
+//				gmove(&hi1, &hi2);
+//				switch(lv) {
+//				case 0:
+//					break;
+//				case 0xffffffffu:
+//					gins(ANOTL, N, &lo2);
+//					break;
+//				default:
+//					gins(AXORL, ncon(lv), &lo2);
+//					break;
+//				}
+//				switch(hv) {
+//				case 0:
+//					break;
+//				case 0xffffffffu:
+//					gins(ANOTL, N, &hi2);
+//					break;
+//				default:
+//					gins(AXORL, ncon(hv), &hi2);
+//					break;
+//				}
+//				break;
+
+//			case OAND:
+//				switch(lv) {
+//				case 0:
+//					gins(AMOVL, ncon(0), &lo2);
+//					break;
+//				default:
+//					gmove(&lo1, &lo2);
+//					if(lv != 0xffffffffu)
+//						gins(AANDL, ncon(lv), &lo2);
+//					break;
+//				}
+//				switch(hv) {
+//				case 0:
+//					gins(AMOVL, ncon(0), &hi2);
+//					break;
+//				default:
+//					gmove(&hi1, &hi2);
+//					if(hv != 0xffffffffu)
+//						gins(AANDL, ncon(hv), &hi2);
+//					break;
+//				}
+//				break;
+
+//			case OOR:
+//				switch(lv) {
+//				case 0:
+//					gmove(&lo1, &lo2);
+//					break;
+//				case 0xffffffffu:
+//					gins(AMOVL, ncon(0xffffffffu), &lo2);
+//					break;
+//				default:
+//					gmove(&lo1, &lo2);
+//					gins(AORL, ncon(lv), &lo2);
+//					break;
+//				}
+//				switch(hv) {
+//				case 0:
+//					gmove(&hi1, &hi2);
+//					break;
+//				case 0xffffffffu:
+//					gins(AMOVL, ncon(0xffffffffu), &hi2);
+//					break;
+//				default:
+//					gmove(&hi1, &hi2);
+//					gins(AORL, ncon(hv), &hi2);
+//					break;
+//				}
+//				break;
+//			}
+//			splitclean();
+//			splitclean();
+//			goto out;
+//		}
+		regalloc(&n1, lo1.type, N);
+		gins(AMOVW, &lo1, &al);
+		gins(AMOVW, &hi1, &ah);
+		gins(AMOVW, &lo2, &n1);
+		gins(optoas(n->op, lo1.type), &n1, &al);
+		gins(AMOVW, &hi2, &n1);
+		gins(optoas(n->op, lo1.type), &n1, &ah);
+		regfree(&n1);
+		break;
+	}
+	if(is64(r->type))
+		splitclean();
+	splitclean();
+
+	split64(res, &lo1, &hi1);
+	gins(AMOVW, &al, &lo1);
+	gins(AMOVW, &ah, &hi1);
+	splitclean();
+
+//out:
+	regfree(&al);
+	regfree(&ah);
+}
+
+/*
+ * generate comparison of nl, nr, both 64-bit.
+ * nl is memory; nr is constant or memory.
+ */
+void
+cmp64(Node *nl, Node *nr, int op, int likely, Prog *to)
+{
+	Node lo1, hi1, lo2, hi2, r1, r2;
+	Prog *br;
+	Type *t;
+
+	split64(nl, &lo1, &hi1);
+	split64(nr, &lo2, &hi2);
+
+	// compare most significant word;
+	// if they differ, we're done.
+	t = hi1.type;
+	regalloc(&r1, types[TINT32], N);
+	regalloc(&r2, types[TINT32], N);
+	gins(AMOVW, &hi1, &r1);
+	gins(AMOVW, &hi2, &r2);
+	gcmp(ACMP, &r1, &r2);
+	regfree(&r1);
+	regfree(&r2);
+
+	br = P;
+	switch(op) {
+	default:
+		fatal("cmp64 %O %T", op, t);
+	case OEQ:
+		// cmp hi
+		// bne L
+		// cmp lo
+		// beq to
+		// L:
+		br = gbranch(ABNE, T, -likely);
+		break;
+	case ONE:
+		// cmp hi
+		// bne to
+		// cmp lo
+		// bne to
+		patch(gbranch(ABNE, T, likely), to);
+		break;
+	case OGE:
+	case OGT:
+		// cmp hi
+		// bgt to
+		// blt L
+		// cmp lo
+		// bge to (or bgt to)
+		// L:
+		patch(gbranch(optoas(OGT, t), T, likely), to);
+		br = gbranch(optoas(OLT, t), T, -likely);
+		break;
+	case OLE:
+	case OLT:
+		// cmp hi
+		// blt to
+		// bgt L
+		// cmp lo
+		// ble to (or jlt to)
+		// L:
+		patch(gbranch(optoas(OLT, t), T, likely), to);
+		br = gbranch(optoas(OGT, t), T, -likely);
+		break;
+	}
+
+	// compare least significant word
+	t = lo1.type;
+	regalloc(&r1, types[TINT32], N);
+	regalloc(&r2, types[TINT32], N);
+	gins(AMOVW, &lo1, &r1);
+	gins(AMOVW, &lo2, &r2);
+	gcmp(ACMP, &r1, &r2);
+	regfree(&r1);
+	regfree(&r2);
+
+	// jump again
+	patch(gbranch(optoas(op, t), T, likely), to);
+
+	// point first branch down here if appropriate
+	if(br != P)
+		patch(br, pc);
+
+	splitclean();
+	splitclean();
+}
diff --git a/src/cmd/5g/doc.go b/src/cmd/5g/doc.go
new file mode 100644
index 0000000..aebdcab
--- /dev/null
+++ b/src/cmd/5g/doc.go
@@ -0,0 +1,15 @@
+// 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
+
+/*
+
+5g is the version of the gc compiler for the ARM.
+The $GOARCH for these tools is arm.
+
+It reads .go files and outputs .5 files. The flags are documented in ../gc/doc.go.
+
+*/
+package main
diff --git a/src/cmd/5g/galign.c b/src/cmd/5g/galign.c
new file mode 100644
index 0000000..b4c45da
--- /dev/null
+++ b/src/cmd/5g/galign.c
@@ -0,0 +1,49 @@
+// 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 "gg.h"
+
+int	thechar	= '5';
+char*	thestring	= "arm";
+LinkArch*	thelinkarch = &linkarm;
+
+void
+linkarchinit(void)
+{
+}
+
+vlong MAXWIDTH = (1LL<<32) - 1;
+
+/*
+ * go declares several platform-specific type aliases:
+ * int, uint, float, and uintptr
+ */
+Typedef	typedefs[] =
+{
+	{"int",		TINT,		TINT32},
+	{"uint",		TUINT,		TUINT32},
+	{"uintptr",	TUINTPTR,	TUINT32},
+	{0}
+};
+
+void
+betypeinit(void)
+{
+	widthptr = 4;
+	widthint = 4;
+	widthreg = 4;
+
+	zprog.link = P;
+	zprog.as = AGOK;
+	zprog.scond = C_SCOND_NONE;
+	zprog.reg = NREG;
+	zprog.from.type = D_NONE;
+	zprog.from.name = D_NONE;
+	zprog.from.reg = NREG;
+	zprog.to = zprog.from;
+
+	listinit5();
+}
diff --git a/src/cmd/5g/gg.h b/src/cmd/5g/gg.h
new file mode 100644
index 0000000..00914bf
--- /dev/null
+++ b/src/cmd/5g/gg.h
@@ -0,0 +1,123 @@
+// 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.
+
+#ifndef	EXTERN
+#define	EXTERN	extern
+#endif
+
+#include "../gc/go.h"
+#include "../5l/5.out.h"
+
+#define TEXTFLAG reg
+
+enum
+{
+	REGALLOC_R0 = 0,
+	REGALLOC_RMAX = REGEXT,
+	REGALLOC_F0 = NREG,
+	REGALLOC_FMAX = REGALLOC_F0 + FREGEXT,
+};
+
+EXTERN	int32	dynloc;
+EXTERN	uchar	reg[REGALLOC_FMAX+1];
+EXTERN	int32	pcloc;		// instruction counter
+EXTERN	Strlit	emptystring;
+EXTERN	Prog	zprog;
+EXTERN	Node*	newproc;
+EXTERN	Node*	deferproc;
+EXTERN	Node*	deferreturn;
+EXTERN	Node*	panicindex;
+EXTERN	Node*	panicslice;
+EXTERN	Node*	throwreturn;
+extern	long	unmappedzero;
+
+/*
+ * gen.c
+ */
+void	compile(Node*);
+void	gen(Node*);
+Node*	lookdot(Node*, Node*, int);
+void	cgen_as(Node*, Node*);
+void	cgen_callmeth(Node*, int);
+void	cgen_callinter(Node*, Node*, int);
+void	cgen_proc(Node*, int);
+void	cgen_callret(Node*, Node*);
+void	cgen_dcl(Node*);
+int	needconvert(Type*, Type*);
+void	genconv(Type*, Type*);
+void	allocparams(void);
+void	checklabels(void);
+void	ginscall(Node*, int);
+
+/*
+ * cgen
+ */
+void	agen(Node*, Node*);
+Prog* cgenindex(Node *, Node *, int);
+void	igen(Node*, Node*, Node*);
+void agenr(Node *n, Node *a, Node *res);
+vlong	fieldoffset(Type*, Node*);
+void	sgen(Node*, Node*, int64);
+void	gmove(Node*, Node*);
+Prog*	gins(int, Node*, Node*);
+int	samaddr(Node*, Node*);
+void	raddr(Node *n, Prog *p);
+Prog*	gcmp(int, Node*, Node*);
+Prog*	gshift(int as, Node *lhs, int32 stype, int32 sval, Node *rhs);
+Prog *	gregshift(int as, Node *lhs, int32 stype, Node *reg, Node *rhs);
+void	naddr(Node*, Addr*, int);
+void	cgen_aret(Node*, Node*);
+void	cgen_hmul(Node*, Node*, Node*);
+void	cgen_shift(int, int, Node*, Node*, Node*);
+int	componentgen(Node*, Node*);
+
+/*
+ * cgen64.c
+ */
+void	cmp64(Node*, Node*, int, int, Prog*);
+void	cgen64(Node*, Node*);
+
+/*
+ * gsubr.c
+ */
+void	clearp(Prog*);
+Prog*	gbranch(int, Type*, int);
+Prog*	prog(int);
+void	gconv(int, int);
+int	conv2pt(Type*);
+vlong	convvtox(vlong, int);
+void	fnparam(Type*, int, int);
+Prog*	gop(int, Node*, Node*, Node*);
+int	optoas(int, Type*);
+void	ginit(void);
+void	gclean(void);
+void	regalloc(Node*, Type*, Node*);
+void	regfree(Node*);
+Node*	nodarg(Type*, int);
+void	nodreg(Node*, Type*, int);
+void	nodindreg(Node*, Type*, int);
+void	buildtxt(void);
+Plist*	newplist(void);
+int	isfat(Type*);
+int	dotaddable(Node*, Node*);
+void	sudoclean(void);
+int	sudoaddable(int, Node*, Addr*, int*);
+void	afunclit(Addr*, Node*);
+void	datagostring(Strlit*, Addr*);
+void	split64(Node*, Node*, Node*);
+void	splitclean(void);
+Node*	ncon(uint32 i);
+void	gtrack(Sym*);
+
+/*
+ * obj.c
+ */
+void	datastring(char*, int, Addr*);
+
+/*
+ * list.c
+ */
+void	listinit(void);
+
+void	zaddr(Biobuf*, Addr*, int, int);
diff --git a/src/cmd/5g/ggen.c b/src/cmd/5g/ggen.c
new file mode 100644
index 0000000..53cddb7
--- /dev/null
+++ b/src/cmd/5g/ggen.c
@@ -0,0 +1,956 @@
+// 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.
+
+#undef	EXTERN
+#define	EXTERN
+#include <u.h>
+#include <libc.h>
+#include "gg.h"
+#include "opt.h"
+
+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)
+{
+	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
+	frame = rnd(stksize+maxarg, widthptr);
+	ptxt->to.offset = frame;
+	
+	// insert code to contain ambiguously live variables
+	// so that garbage collector only sees initialized values
+	// when it looks for pointers.
+	p = ptxt;
+	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(!nacl && (cnt <= 128*widthptr)) {
+		p = appendpp(p, AADD, D_CONST, NREG, 4+frame+lo, D_REG, 1, 0);
+		p->reg = REGSP;
+		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 = appendpp(p, AMOVW, D_REG, 0, 0, D_OREG, 1, 4);
+		p->scond |= C_PBIT;
+		p = appendpp(p, ACMP, D_REG, 1, 0, D_NONE, 0, 0);
+		p->reg = 2;
+		p = appendpp(p, ABNE, D_NONE, NREG, 0, D_BRANCH, NREG, 0);
+		patch(p, p1);
+	}
+	return p;
+}
+
+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.
+void
+markautoused(Prog* p)
+{
+	for (; p; p = p->link) {
+		if (p->as == ATYPE || p->as == AVARDEF || p->as == AVARKILL)
+			continue;
+
+		if (p->from.node)
+			p->from.node->used = 1;
+
+		if (p->to.node)
+			p->to.node->used = 1;
+	}
+}
+
+// Fixup instructions after allocauto (formerly compactframe) has moved all autos around.
+void
+fixautoused(Prog* p)
+{
+	Prog **lp;
+
+	for (lp=&p; (p=*lp) != P; ) {
+		if (p->as == ATYPE && p->from.node && p->from.name == D_AUTO && !p->from.node->used) {
+			*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;
+
+		if (p->to.name == D_AUTO && p->to.node)
+			p->to.offset += p->to.node->stkdelta;
+
+		lp = &p->link;
+	}
+}
+
+/*
+ * generate:
+ *	call f
+ *	proc=-1	normal call but no return
+ *	proc=0	normal call
+ *	proc=1	goroutine run in new proc
+ *	proc=2	defer call save away stack
+  *	proc=3	normal call to C pointer (not Go func value)
+ */
+void
+ginscall(Node *f, int proc)
+{
+	Prog *p;
+	Node n1, r, r1, con;
+
+	if(f->type != T)
+		setmaxarg(f->type);
+
+	switch(proc) {
+	default:
+		fatal("ginscall: bad proc %d", proc);
+		break;
+
+	case 0:	// normal call
+	case -1:	// normal call but no return
+		if(f->op == ONAME && f->class == PFUNC) {
+			if(f == deferreturn) {
+				// Deferred calls will appear to be returning to
+				// the BL deferreturn(SB) that we are about to emit.
+				// However, the stack trace code will show the line
+				// of the instruction before that return PC. 
+				// To avoid that instruction being an unrelated instruction,
+				// insert a NOP so that we will have the right line number.
+				// ARM NOP 0x00000000 is really AND.EQ R0, R0, R0.
+				// Use the latter form because the NOP pseudo-instruction
+				// would be removed by the linker.
+				nodreg(&r, types[TINT], 0);
+				p = gins(AAND, &r, &r);
+				p->scond = C_SCOND_EQ;
+			}
+			p = gins(ABL, N, f);
+			afunclit(&p->to, f);
+			if(proc == -1 || noreturn(p))
+				gins(AUNDEF, N, N);
+			break;
+		}
+		nodreg(&r, types[tptr], 7);
+		nodreg(&r1, types[tptr], 1);
+		gmove(f, &r);
+		r.op = OINDREG;
+		gmove(&r, &r1);
+		r.op = OREGISTER;
+		r1.op = OINDREG;
+		gins(ABL, &r, &r1);
+		break;
+
+	case 3:	// normal call of c function pointer
+		gins(ABL, N, f);
+		break;
+
+	case 1:	// call in new proc (go)
+	case 2:	// deferred call (defer)
+		regalloc(&r, types[tptr], N);
+		p = gins(AMOVW, N, &r);
+		p->from.type = D_OREG;
+		p->from.reg = REGSP;
+		
+		p = gins(AMOVW, &r, N);
+		p->to.type = D_OREG;
+		p->to.reg = REGSP;
+		p->to.offset = -12;
+		p->scond |= C_WBIT;
+
+		memset(&n1, 0, sizeof n1);
+		n1.op = OADDR;
+		n1.left = f;
+		gins(AMOVW, &n1, &r);
+
+		p = gins(AMOVW, &r, N);
+		p->to.type = D_OREG;
+		p->to.reg = REGSP;
+		p->to.offset = 8;
+
+		nodconst(&con, types[TINT32], argsize(f->type));
+		gins(AMOVW, &con, &r);
+		p = gins(AMOVW, &r, N);
+		p->to.type = D_OREG;
+		p->to.reg = REGSP;
+		p->to.offset = 4;
+		regfree(&r);
+
+		if(proc == 1)
+			ginscall(newproc, 0);
+		else
+			ginscall(deferproc, 0);
+
+		nodreg(&r, types[tptr], 1);
+		p = gins(AMOVW, N, N);
+		p->from.type = D_CONST;
+		p->from.reg = REGSP;
+		p->from.offset = 12;
+		p->to.reg = REGSP;
+		p->to.type = D_REG;
+
+		if(proc == 2) {
+			nodconst(&con, types[TINT32], 0);
+			p = gins(ACMP, &con, N);
+			p->reg = 0;
+			p = gbranch(ABEQ, T, +1);
+			cgen_ret(N);
+			patch(p, pc);
+		}
+		break;
+	}
+}
+
+/*
+ * n is call to interface method.
+ * generate res = n.
+ */
+void
+cgen_callinter(Node *n, Node *res, int proc)
+{
+	int r;
+	Node *i, *f;
+	Node tmpi, nodo, nodr, nodsp;
+	Prog *p;
+
+	i = n->left;
+	if(i->op != ODOTINTER)
+		fatal("cgen_callinter: not ODOTINTER %O", i->op);
+
+	f = i->right;		// field
+	if(f->op != ONAME)
+		fatal("cgen_callinter: not ONAME %O", f->op);
+
+	i = i->left;		// interface
+
+	// Release res register during genlist and cgen,
+	// which might have their own function calls.
+	r = -1;
+	if(res != N && (res->op == OREGISTER || res->op == OINDREG)) {
+		r = res->val.u.reg;
+		reg[r]--;
+	}
+
+	if(!i->addable) {
+		tempname(&tmpi, i->type);
+		cgen(i, &tmpi);
+		i = &tmpi;
+	}
+
+	genlist(n->list);			// args
+	if(r >= 0)
+		reg[r]++;
+
+	regalloc(&nodr, types[tptr], res);
+	regalloc(&nodo, types[tptr], &nodr);
+	nodo.op = OINDREG;
+
+	agen(i, &nodr);		// REG = &inter
+
+	nodindreg(&nodsp, types[tptr], REGSP);
+	nodsp.xoffset = 4;
+	nodo.xoffset += widthptr;
+	cgen(&nodo, &nodsp);	// 4(SP) = 4(REG) -- i.data
+
+	nodo.xoffset -= widthptr;
+	cgen(&nodo, &nodr);	// REG = 0(REG) -- i.tab
+	cgen_checknil(&nodr); // in case offset is huge
+
+	nodo.xoffset = n->left->xoffset + 3*widthptr + 8;
+	
+	if(proc == 0) {
+		// plain call: use direct c function pointer - more efficient
+		cgen(&nodo, &nodr);	// REG = 20+offset(REG) -- i.tab->fun[f]
+		nodr.op = OINDREG;
+		proc = 3;
+	} else {
+		// go/defer. generate go func value.
+		p = gins(AMOVW, &nodo, &nodr);
+		p->from.type = D_CONST;	// REG = &(20+offset(REG)) -- i.tab->fun[f]
+	}
+
+	nodr.type = n->left->type;
+	ginscall(&nodr, proc);
+
+	regfree(&nodr);
+	regfree(&nodo);
+}
+
+/*
+ * generate function call;
+ *	proc=0	normal call
+ *	proc=1	goroutine run in new proc
+ *	proc=2	defer call save away stack
+ */
+void
+cgen_call(Node *n, int proc)
+{
+	Type *t;
+	Node nod, afun;
+
+	if(n == N)
+		return;
+
+	if(n->left->ullman >= UINF) {
+		// if name involves a fn call
+		// precompute the address of the fn
+		tempname(&afun, types[tptr]);
+		cgen(n->left, &afun);
+	}
+
+	genlist(n->list);		// assign the args
+	t = n->left->type;
+
+	// call tempname pointer
+	if(n->left->ullman >= UINF) {
+		regalloc(&nod, types[tptr], N);
+		cgen_as(&nod, &afun);
+		nod.type = t;
+		ginscall(&nod, proc);
+		regfree(&nod);
+		goto ret;
+	}
+
+	// call pointer
+	if(n->left->op != ONAME || n->left->class != PFUNC) {
+		regalloc(&nod, types[tptr], N);
+		cgen_as(&nod, n->left);
+		nod.type = t;
+		ginscall(&nod, proc);
+		regfree(&nod);
+		goto ret;
+	}
+
+	// call direct
+	n->left->method = 1;
+	ginscall(n->left, proc);
+
+
+ret:
+	;
+}
+
+/*
+ * call to n has already been generated.
+ * generate:
+ *	res = return value from call.
+ */
+void
+cgen_callret(Node *n, Node *res)
+{
+	Node nod;
+	Type *fp, *t;
+	Iter flist;
+
+	t = n->left->type;
+	if(t->etype == TPTR32 || t->etype == TPTR64)
+		t = t->type;
+
+	fp = structfirst(&flist, getoutarg(t));
+	if(fp == T)
+		fatal("cgen_callret: nil");
+
+	memset(&nod, 0, sizeof(nod));
+	nod.op = OINDREG;
+	nod.val.u.reg = REGSP;
+	nod.addable = 1;
+
+	nod.xoffset = fp->width + 4; // +4: saved lr at 0(SP)
+	nod.type = fp->type;
+	cgen_as(res, &nod);
+}
+
+/*
+ * call to n has already been generated.
+ * generate:
+ *	res = &return value from call.
+ */
+void
+cgen_aret(Node *n, Node *res)
+{
+	Node nod1, nod2;
+	Type *fp, *t;
+	Iter flist;
+
+	t = n->left->type;
+	if(isptr[t->etype])
+		t = t->type;
+
+	fp = structfirst(&flist, getoutarg(t));
+	if(fp == T)
+		fatal("cgen_aret: nil");
+
+	memset(&nod1, 0, sizeof(nod1));
+	nod1.op = OINDREG;
+	nod1.val.u.reg = REGSP;
+	nod1.addable = 1;
+
+	nod1.xoffset = fp->width + 4; // +4: saved lr at 0(SP)
+	nod1.type = fp->type;
+
+	if(res->op != OREGISTER) {
+		regalloc(&nod2, types[tptr], res);
+		agen(&nod1, &nod2);
+		gins(AMOVW, &nod2, res);
+		regfree(&nod2);
+	} else
+		agen(&nod1, res);
+}
+
+/*
+ * generate return.
+ * n->left is assignments to return values.
+ */
+void
+cgen_ret(Node *n)
+{
+	Prog *p;
+
+	if(n != N)
+		genlist(n->list);		// copy out args
+	if(hasdefer)
+		ginscall(deferreturn, 0);
+	genlist(curfn->exit);
+	p = gins(ARET, N, N);
+	if(n != N && n->op == ORETJMP) {
+		p->to.name = D_EXTERN;
+		p->to.type = D_CONST;
+		p->to.sym = linksym(n->left->sym);
+	}
+}
+
+/*
+ * generate += *= etc.
+ */
+void
+cgen_asop(Node *n)
+{
+	Node n1, n2, n3, n4;
+	Node *nl, *nr;
+	Prog *p1;
+	Addr addr;
+	int a, w;
+
+	nl = n->left;
+	nr = n->right;
+
+	if(nr->ullman >= UINF && nl->ullman >= UINF) {
+		tempname(&n1, nr->type);
+		cgen(nr, &n1);
+		n2 = *n;
+		n2.right = &n1;
+		cgen_asop(&n2);
+		goto ret;
+	}
+
+	if(!isint[nl->type->etype])
+		goto hard;
+	if(!isint[nr->type->etype])
+		goto hard;
+	if(is64(nl->type) || is64(nr->type))
+		goto hard64;
+
+	switch(n->etype) {
+	case OADD:
+	case OSUB:
+	case OXOR:
+	case OAND:
+	case OOR:
+		a = optoas(n->etype, nl->type);
+		if(nl->addable) {
+			if(smallintconst(nr))
+				n3 = *nr;
+			else {
+				regalloc(&n3, nr->type, N);
+				cgen(nr, &n3);
+			}
+			regalloc(&n2, nl->type, N);
+			cgen(nl, &n2);
+			gins(a, &n3, &n2);
+			cgen(&n2, nl);
+			regfree(&n2);
+			if(n3.op != OLITERAL)
+				regfree(&n3);
+			goto ret;
+		}
+		if(nr->ullman < UINF)
+		if(sudoaddable(a, nl, &addr, &w)) {
+			w = optoas(OAS, nl->type);
+			regalloc(&n2, nl->type, N);
+			p1 = gins(w, N, &n2);
+			p1->from = addr;
+			regalloc(&n3, nr->type, N);
+			cgen(nr, &n3);
+			gins(a, &n3, &n2);
+			p1 = gins(w, &n2, N);
+			p1->to = addr;
+			regfree(&n2);
+			regfree(&n3);
+			sudoclean();
+			goto ret;
+		}
+	}
+
+hard:
+	n2.op = 0;
+	n1.op = 0;
+	if(nr->op == OLITERAL) {
+		// don't allocate a register for literals.
+	} else if(nr->ullman >= nl->ullman || nl->addable) {
+		regalloc(&n2, nr->type, N);
+		cgen(nr, &n2);
+		nr = &n2;
+	} else {
+		tempname(&n2, nr->type);
+		cgen(nr, &n2);
+		nr = &n2;
+	}
+	if(!nl->addable) {
+		igen(nl, &n1, N);
+		nl = &n1;
+	}
+
+	n3 = *n;
+	n3.left = nl;
+	n3.right = nr;
+	n3.op = n->etype;
+
+	regalloc(&n4, nl->type, N);
+	cgen(&n3, &n4);
+	gmove(&n4, nl);
+
+	if(n1.op)
+		regfree(&n1);
+	if(n2.op == OREGISTER)
+		regfree(&n2);
+	regfree(&n4);
+	goto ret;
+
+hard64:
+	if(nr->ullman > nl->ullman) {
+		tempname(&n2, nr->type);
+		cgen(nr, &n2);
+		igen(nl, &n1, N);
+	} else {
+		igen(nl, &n1, N);
+		tempname(&n2, nr->type);
+		cgen(nr, &n2);
+	}
+
+	n3 = *n;
+	n3.left = &n1;
+	n3.right = &n2;
+	n3.op = n->etype;
+
+	cgen(&n3, &n1);
+
+ret:
+	;
+}
+
+int
+samereg(Node *a, Node *b)
+{
+	if(a->op != OREGISTER)
+		return 0;
+	if(b->op != OREGISTER)
+		return 0;
+	if(a->val.u.reg != b->val.u.reg)
+		return 0;
+	return 1;
+}
+
+/*
+ * generate high multiply
+ *  res = (nl * nr) >> wordsize
+ */
+void
+cgen_hmul(Node *nl, Node *nr, Node *res)
+{
+	int w;
+	Node n1, n2, *tmp;
+	Type *t;
+	Prog *p;
+
+	if(nl->ullman < nr->ullman) {
+		tmp = nl;
+		nl = nr;
+		nr = tmp;
+	}
+	t = nl->type;
+	w = t->width * 8;
+	regalloc(&n1, t, res);
+	cgen(nl, &n1);
+	regalloc(&n2, t, N);
+	cgen(nr, &n2);
+	switch(simtype[t->etype]) {
+	case TINT8:
+	case TINT16:
+		gins(optoas(OMUL, t), &n2, &n1);
+		gshift(AMOVW, &n1, SHIFT_AR, w, &n1);
+		break;
+	case TUINT8:
+	case TUINT16:
+		gins(optoas(OMUL, t), &n2, &n1);
+		gshift(AMOVW, &n1, SHIFT_LR, w, &n1);
+		break;
+	case TINT32:
+	case TUINT32:
+		// perform a long multiplication.
+		if(issigned[t->etype])
+			p = gins(AMULL, &n2, N);
+		else
+			p = gins(AMULLU, &n2, N);
+		// n2 * n1 -> (n1 n2)
+		p->reg = n1.val.u.reg;
+		p->to.type = D_REGREG;
+		p->to.reg = n1.val.u.reg;
+		p->to.offset = n2.val.u.reg;
+		break;
+	default:
+		fatal("cgen_hmul %T", t);
+		break;
+	}
+	cgen(&n1, res);
+	regfree(&n1);
+	regfree(&n2);
+}
+
+/*
+ * generate shift according to op, one of:
+ *	res = nl << nr
+ *	res = nl >> nr
+ */
+void
+cgen_shift(int op, int bounded, Node *nl, Node *nr, Node *res)
+{
+	Node n1, n2, n3, nt, t, lo, hi;
+	int w, v;
+	Prog *p1, *p2, *p3;
+	Type *tr;
+	uvlong sc;
+
+	USED(bounded);
+	if(nl->type->width > 4)
+		fatal("cgen_shift %T", nl->type);
+
+	w = nl->type->width * 8;
+
+	if(op == OLROT) {
+		v = mpgetfix(nr->val.u.xval);
+		regalloc(&n1, nl->type, res);
+		if(w == 32) {
+			cgen(nl, &n1);
+			gshift(AMOVW, &n1, SHIFT_RR, w-v, &n1);
+		} else {
+			regalloc(&n2, nl->type, N);
+			cgen(nl, &n2);
+			gshift(AMOVW, &n2, SHIFT_LL, v, &n1);
+			gshift(AORR, &n2, SHIFT_LR, w-v, &n1);
+			regfree(&n2);
+			// Ensure sign/zero-extended result.
+			gins(optoas(OAS, nl->type), &n1, &n1);
+		}
+		gmove(&n1, res);
+		regfree(&n1);
+		return;
+	}
+
+	if(nr->op == OLITERAL) {
+		regalloc(&n1, nl->type, res);
+		cgen(nl, &n1);
+		sc = mpgetfix(nr->val.u.xval);
+		if(sc == 0) {
+			// nothing to do
+		} else if(sc >= nl->type->width*8) {
+			if(op == ORSH && issigned[nl->type->etype])
+				gshift(AMOVW, &n1, SHIFT_AR, w, &n1);
+			else
+				gins(AEOR, &n1, &n1);
+		} else {
+			if(op == ORSH && issigned[nl->type->etype])
+				gshift(AMOVW, &n1, SHIFT_AR, sc, &n1);
+			else if(op == ORSH)
+				gshift(AMOVW, &n1, SHIFT_LR, sc, &n1);
+			else // OLSH
+				gshift(AMOVW, &n1, SHIFT_LL, sc, &n1);
+		}
+		if(w < 32 && op == OLSH)
+			gins(optoas(OAS, nl->type), &n1, &n1);
+		gmove(&n1, res);
+		regfree(&n1);
+		return;
+	}
+
+	tr = nr->type;
+	if(tr->width > 4) {
+		tempname(&nt, nr->type);
+		if(nl->ullman >= nr->ullman) {
+			regalloc(&n2, nl->type, res);
+			cgen(nl, &n2);
+			cgen(nr, &nt);
+			n1 = nt;
+		} else {
+			cgen(nr, &nt);
+			regalloc(&n2, nl->type, res);
+			cgen(nl, &n2);
+		}
+		split64(&nt, &lo, &hi);
+		regalloc(&n1, types[TUINT32], N);
+		regalloc(&n3, types[TUINT32], N);
+		gmove(&lo, &n1);
+		gmove(&hi, &n3);
+		splitclean();
+		gins(ATST, &n3, N);
+		nodconst(&t, types[TUINT32], w);
+		p1 = gins(AMOVW, &t, &n1);
+		p1->scond = C_SCOND_NE;
+		tr = types[TUINT32];
+		regfree(&n3);
+	} else {
+		if(nl->ullman >= nr->ullman) {
+			regalloc(&n2, nl->type, res);
+			cgen(nl, &n2);
+			regalloc(&n1, nr->type, N);
+			cgen(nr, &n1);
+		} else {
+			regalloc(&n1, nr->type, N);
+			cgen(nr, &n1);
+			regalloc(&n2, nl->type, res);
+			cgen(nl, &n2);
+		}
+	}
+
+	// test for shift being 0
+	gins(ATST, &n1, N);
+	p3 = gbranch(ABEQ, T, -1);
+
+	// test and fix up large shifts
+	// TODO: if(!bounded), don't emit some of this.
+	regalloc(&n3, tr, N);
+	nodconst(&t, types[TUINT32], w);
+	gmove(&t, &n3);
+	gcmp(ACMP, &n1, &n3);
+	if(op == ORSH) {
+		if(issigned[nl->type->etype]) {
+			p1 = gshift(AMOVW, &n2, SHIFT_AR, w-1, &n2);
+			p2 = gregshift(AMOVW, &n2, SHIFT_AR, &n1, &n2);
+		} else {
+			p1 = gins(AEOR, &n2, &n2);
+			p2 = gregshift(AMOVW, &n2, SHIFT_LR, &n1, &n2);
+		}
+		p1->scond = C_SCOND_HS;
+		p2->scond = C_SCOND_LO;
+	} else {
+		p1 = gins(AEOR, &n2, &n2);
+		p2 = gregshift(AMOVW, &n2, SHIFT_LL, &n1, &n2);
+		p1->scond = C_SCOND_HS;
+		p2->scond = C_SCOND_LO;
+	}
+	regfree(&n3);
+
+	patch(p3, pc);
+	// Left-shift of smaller word must be sign/zero-extended.
+	if(w < 32 && op == OLSH)
+		gins(optoas(OAS, nl->type), &n2, &n2);
+	gmove(&n2, res);
+
+	regfree(&n1);
+	regfree(&n2);
+}
+
+void
+clearfat(Node *nl)
+{
+	uint32 w, c, q;
+	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))
+		return;
+
+	c = w % 4;	// bytes
+	q = w / 4;	// quads
+
+	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], &r0);
+	cgen(&nc, &nz);
+
+	if(q > 128) {
+		regalloc(&end, types[tptr], N);
+		p = gins(AMOVW, &dst, &end);
+		p->from.type = D_CONST;
+		p->from.offset = q*4;
+
+		p = gins(AMOVW, &nz, &dst);
+		p->to.type = D_OREG;
+		p->to.offset = 4;
+		p->scond |= C_PBIT;
+		pl = p;
+
+		p = gins(ACMP, &dst, N);
+		raddr(&end, p);
+		patch(gbranch(ABNE, T, 0), pl);
+
+		regfree(&end);
+	} else if(q >= 4 && !nacl) {
+		f = sysfunc("duffzero");
+		p = gins(ADUFFZERO, N, f);
+		afunclit(&p->to, f);
+		// 4 and 128 = magic constants: see ../../runtime/asm_arm.s
+		p->to.offset = 4*(128-q);
+	} else
+	while(q > 0) {
+		p = gins(AMOVW, &nz, &dst);
+		p->to.type = D_OREG;
+		p->to.offset = 4;
+ 		p->scond |= C_PBIT;
+//print("1. %P\n", p);
+		q--;
+	}
+
+	while(c > 0) {
+		p = gins(AMOVB, &nz, &dst);
+		p->to.type = D_OREG;
+		p->to.offset = 1;
+ 		p->scond |= C_PBIT;
+//print("2. %P\n", p);
+		c--;
+	}
+	regfree(&dst);
+	regfree(&nz);
+}
+
+// Called after regopt and peep have run.
+// Expand CHECKNIL pseudo-op into actual nil pointer check.
+void
+expandchecks(Prog *firstp)
+{
+	int reg;
+	Prog *p, *p1;
+
+	for(p = firstp; p != P; p = p->link) {
+		if(p->as != ACHECKNIL)
+			continue;
+		if(debug_checknil && p->lineno > 1) // p->lineno==1 in generated wrappers
+			warnl(p->lineno, "generated nil check");
+		if(p->from.type != D_REG)
+			fatal("invalid nil check %P", p);
+		reg = p->from.reg;
+		// check is
+		//	CMP arg, $0
+		//	MOV.EQ arg, 0(arg)
+		p1 = mal(sizeof *p1);
+		clearp(p1);
+		p1->link = p->link;
+		p->link = p1;
+		p1->lineno = p->lineno;
+		p1->pc = 9999;
+		p1->as = AMOVW;
+		p1->from.type = D_REG;
+		p1->from.reg = reg;
+		p1->to.type = D_OREG;
+		p1->to.reg = reg;
+		p1->to.offset = 0;
+		p1->scond = C_SCOND_EQ;
+		p->as = ACMP;
+		p->from.type = D_CONST;
+		p->from.reg = NREG;
+		p->from.offset = 0;
+		p->reg = reg;
+	}
+}
diff --git a/src/cmd/5g/gobj.c b/src/cmd/5g/gobj.c
new file mode 100644
index 0000000..5e98887
--- /dev/null
+++ b/src/cmd/5g/gobj.c
@@ -0,0 +1,252 @@
+// 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 "gg.h"
+
+int
+dsname(Sym *sym, int off, char *t, int n)
+{
+	Prog *p;
+
+	p = gins(ADATA, N, N);
+	p->from.type = D_OREG;
+	p->from.name = D_EXTERN;
+	p->from.etype = TINT32;
+	p->from.offset = off;
+	p->from.reg = NREG;
+	p->from.sym = linksym(sym);
+	
+	p->reg = n;
+	
+	p->to.type = D_SCONST;
+	p->to.name = D_NONE;
+	p->to.reg = NREG;
+	p->to.offset = 0;
+	memmove(p->to.u.sval, t, n);
+	return off + n;
+}
+
+/*
+ * make a refer to the data s, s+len
+ * emitting DATA if needed.
+ */
+void
+datastring(char *s, int len, Addr *a)
+{
+	Sym *sym;
+	
+	sym = stringsym(s, len);
+	a->type = D_OREG;
+	a->name = D_EXTERN;
+	a->etype = TINT32;
+	a->offset = widthptr+4;  // skip header
+	a->reg = NREG;
+	a->sym = linksym(sym);
+	a->node = sym->def;
+}
+
+/*
+ * make a refer to the string sval,
+ * emitting DATA if needed.
+ */
+void
+datagostring(Strlit *sval, Addr *a)
+{
+	Sym *sym;
+	
+	sym = stringsym(sval->s, sval->len);
+	a->type = D_OREG;
+	a->name = D_EXTERN;
+	a->etype = TINT32;
+	a->offset = 0;  // header
+	a->reg = NREG;
+	a->sym = linksym(sym);
+	a->node = sym->def;
+}
+
+void
+gdata(Node *nam, Node *nr, int wid)
+{
+	Prog *p;
+	vlong v;
+
+	if(nr->op == OLITERAL) {
+		switch(nr->val.ctype) {
+		case CTCPLX:
+			gdatacomplex(nam, nr->val.u.cval);
+			return;
+		case CTSTR:
+			gdatastring(nam, nr->val.u.sval);
+			return;
+		}
+	}
+
+	if(wid == 8 && is64(nr->type)) {
+		v = mpgetfix(nr->val.u.xval);
+		p = gins(ADATA, nam, nodintconst(v));
+		p->reg = 4;
+		p = gins(ADATA, nam, nodintconst(v>>32));
+		p->reg = 4;
+		p->from.offset += 4;
+		return;
+	}
+	p = gins(ADATA, nam, nr);
+	p->reg = wid;
+}
+
+void
+gdatacomplex(Node *nam, Mpcplx *cval)
+{
+	Prog *p;
+	int w;
+
+	w = cplxsubtype(nam->type->etype);
+	w = types[w]->width;
+
+	p = gins(ADATA, nam, N);
+	p->reg = w;
+	p->to.type = D_FCONST;
+	p->to.u.dval = mpgetflt(&cval->real);
+
+	p = gins(ADATA, nam, N);
+	p->reg = w;
+	p->from.offset += w;
+	p->to.type = D_FCONST;
+	p->to.u.dval = mpgetflt(&cval->imag);
+}
+
+void
+gdatastring(Node *nam, Strlit *sval)
+{
+	Prog *p;
+	Node nod1;
+
+	p = gins(ADATA, nam, N);
+	datastring(sval->s, sval->len, &p->to);
+	p->reg = types[tptr]->width;
+	p->to.type = D_CONST;
+	p->to.etype = TINT32;
+//print("%P\n", p);
+
+	nodconst(&nod1, types[TINT32], sval->len);
+	p = gins(ADATA, nam, &nod1);
+	p->reg = types[TINT32]->width;
+	p->from.offset += types[tptr]->width;
+}
+
+int
+dstringptr(Sym *s, int off, char *str)
+{
+	Prog *p;
+
+	off = rnd(off, widthptr);
+	p = gins(ADATA, N, N);
+	p->from.type = D_OREG;
+	p->from.name = D_EXTERN;
+	p->from.sym = linksym(s);
+	p->from.offset = off;
+	p->reg = widthptr;
+
+	datastring(str, strlen(str)+1, &p->to);
+	p->to.type = D_CONST;
+	p->to.etype = TINT32;
+	off += widthptr;
+
+	return off;
+}
+
+int
+dgostrlitptr(Sym *s, int off, Strlit *lit)
+{
+	Prog *p;
+
+	if(lit == nil)
+		return duintptr(s, off, 0);
+
+	off = rnd(off, widthptr);
+	p = gins(ADATA, N, N);
+	p->from.type = D_OREG;
+	p->from.name = D_EXTERN;
+	p->from.sym = linksym(s);
+	p->from.offset = off;
+	p->reg = widthptr;
+	datagostring(lit, &p->to);
+	p->to.type = D_CONST;
+	p->to.etype = TINT32;
+	off += widthptr;
+
+	return off;
+}
+
+int
+dgostringptr(Sym *s, int off, char *str)
+{
+	int n;
+	Strlit *lit;
+
+	if(str == nil)
+		return duintptr(s, off, 0);
+
+	n = strlen(str);
+	lit = mal(sizeof *lit + n);
+	strcpy(lit->s, str);
+	lit->len = n;
+	return dgostrlitptr(s, off, lit);
+}
+
+int
+dsymptr(Sym *s, int off, Sym *x, int xoff)
+{
+	Prog *p;
+
+	off = rnd(off, widthptr);
+
+	p = gins(ADATA, N, N);
+	p->from.type = D_OREG;
+	p->from.name = D_EXTERN;
+	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 = linksym(x);
+	p->to.offset = xoff;
+	off += widthptr;
+
+	return off;
+}
+
+void
+nopout(Prog *p)
+{
+	p->as = ANOP;
+}
diff --git a/src/cmd/5g/gsubr.c b/src/cmd/5g/gsubr.c
new file mode 100644
index 0000000..06e274e
--- /dev/null
+++ b/src/cmd/5g/gsubr.c
@@ -0,0 +1,2082 @@
+// Derived from Inferno utils/5c/txt.c
+// http://code.google.com/p/inferno-os/source/browse/utils/5c/txt.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"
+#include "../../runtime/funcdata.h"
+
+// TODO(rsc): Can make this bigger if we move
+// the text segment up higher in 5l for all GOOS.
+// At the same time, can raise StackBig in ../../runtime/stack.h.
+long unmappedzero = 4096;
+
+void
+clearp(Prog *p)
+{
+	p->as = AEND;
+	p->reg = NREG;
+	p->scond = C_SCOND_NONE;
+	p->from.type = D_NONE;
+	p->from.name = D_NONE;
+	p->from.reg = NREG;
+	p->to.type = D_NONE;
+	p->to.name = D_NONE;
+	p->to.reg = NREG;
+	p->pc = pcloc;
+	pcloc++;
+}
+
+static int ddumped;
+static Prog *dfirst;
+static Prog *dpc;
+
+/*
+ * generate and return proc with p->as = as,
+ * linked into program.  pc is next instruction.
+ */
+Prog*
+prog(int as)
+{
+	Prog *p;
+
+	if(as == ADATA || as == AGLOBL) {
+		if(ddumped)
+			fatal("already dumped data");
+		if(dpc == nil) {
+			dpc = mal(sizeof(*dpc));
+			dfirst = dpc;
+		}
+		p = dpc;
+		dpc = mal(sizeof(*dpc));
+		p->link = dpc;
+		p->reg = 0;  // used for flags
+	} else {
+		p = pc;
+		pc = mal(sizeof(*pc));
+		clearp(pc);
+		p->link = pc;
+	}
+
+	if(lineno == 0) {
+		if(debug['K'])
+			warn("prog: line 0");
+	}
+
+	p->as = as;
+	p->lineno = lineno;
+	return p;
+}
+
+void
+dumpdata(void)
+{
+	ddumped = 1;
+	if(dfirst == nil)
+		return;
+	newplist();
+	*pc = *dfirst;
+	pc = dpc;
+	clearp(pc);
+}
+
+/*
+ * generate a branch.
+ * t is ignored.
+ * likely values are for branch prediction:
+ *	-1 unlikely
+ *	0 no opinion
+ *	+1 likely
+ */
+Prog*
+gbranch(int as, Type *t, int likely)
+{
+	Prog *p;
+
+	USED(t);
+	USED(likely);  // TODO: record this for linker
+
+	p = prog(as);
+	p->to.type = D_BRANCH;
+	p->to.u.branch = P;
+	return p;
+}
+
+/*
+ * patch previous branch to jump to to.
+ */
+void
+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->pc;
+}
+
+Prog*
+unpatch(Prog *p)
+{
+	Prog *q;
+
+	if(p->to.type != D_BRANCH)
+		fatal("unpatch: not a branch");
+	q = p->to.u.branch;
+	p->to.u.branch = P;
+	p->to.offset = 0;
+	return q;
+}
+
+/*
+ * start a new Prog list.
+ */
+Plist*
+newplist(void)
+{
+	Plist *pl;
+
+	pl = linknewplist(ctxt);
+
+	pc = mal(sizeof(*pc));
+	clearp(pc);
+	pl->firstpc = pc;
+
+	return pl;
+}
+
+void
+gused(Node *n)
+{
+	gins(ANOP, n, N);	// used
+}
+
+Prog*
+gjmp(Prog *to)
+{
+	Prog *p;
+
+	p = gbranch(AB, T, 0);
+	if(to != P)
+		patch(p, to);
+	return p;
+}
+
+void
+ggloblnod(Node *nam)
+{
+	Prog *p;
+
+	p = gins(AGLOBL, nam, N);
+	p->lineno = nam->lineno;
+	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)
+		p->reg = RODATA;
+	if(nam->type != T && !haspointers(nam->type))
+		p->reg |= NOPTR;
+}
+
+void
+ggloblsym(Sym *s, int32 width, int8 flags)
+{
+	Prog *p;
+
+	p = gins(AGLOBL, N, N);
+	p->from.type = D_OREG;
+	p->from.name = D_EXTERN;
+	p->from.sym = linksym(s);
+	p->to.type = D_CONST;
+	p->to.name = D_NONE;
+	p->to.offset = width;
+	p->reg = flags;
+}
+
+void
+gtrack(Sym *s)
+{
+	Prog *p;
+	
+	p = gins(AUSEFIELD, N, N);
+	p->from.type = D_OREG;
+	p->from.name = D_EXTERN;
+	p->from.sym = linksym(s);
+}
+
+int
+isfat(Type *t)
+{
+	if(t != T)
+	switch(t->etype) {
+	case TSTRUCT:
+	case TARRAY:
+	case TSTRING:
+	case TINTER:	// maybe remove later
+		return 1;
+	}
+	return 0;
+}
+
+/*
+ * naddr of func generates code for address of func.
+ * if using opcode that can take address implicitly,
+ * call afunclit to fix up the argument.
+ * also fix up direct register references to be D_OREG.
+ */
+void
+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 = linksym(n->sym);
+	}
+}
+
+static	int	resvd[] =
+{
+	9,     // reserved for m
+	10,    // reserved for g
+	REGSP, // reserved for SP
+};
+
+void
+ginit(void)
+{
+	int i;
+
+	for(i=0; i<nelem(reg); i++)
+		reg[i] = 0;
+	for(i=0; i<nelem(resvd); i++)
+		reg[resvd[i]]++;
+}
+
+void
+gclean(void)
+{
+	int i;
+
+	for(i=0; i<nelem(resvd); i++)
+		reg[resvd[i]]--;
+
+	for(i=0; i<nelem(reg); i++)
+		if(reg[i])
+			yyerror("reg %R left allocated\n", i);
+}
+
+int32
+anyregalloc(void)
+{
+	int i, j;
+
+	for(i=0; i<nelem(reg); i++) {
+		if(reg[i] == 0)
+			goto ok;
+		for(j=0; j<nelem(resvd); j++)
+			if(resvd[j] == i)
+				goto ok;
+		return 1;
+	ok:;
+	}
+	return 0;
+}
+
+uintptr regpc[REGALLOC_FMAX+1];
+
+/*
+ * allocate register of type t, leave in n.
+ * if o != N, o is desired fixed register.
+ * caller must regfree(n).
+ */
+void
+regalloc(Node *n, Type *t, Node *o)
+{
+	int i, et, fixfree, floatfree;
+
+	if(0 && debug['r']) {
+		fixfree = 0;
+		for(i=REGALLOC_R0; i<=REGALLOC_RMAX; i++)
+			if(reg[i] == 0)
+				fixfree++;
+		floatfree = 0;
+		for(i=REGALLOC_F0; i<=REGALLOC_FMAX; i++)
+			if(reg[i] == 0)
+				floatfree++;
+		print("regalloc fix %d float %d\n", fixfree, floatfree);
+	}
+
+	if(t == T)
+		fatal("regalloc: t nil");
+	et = simtype[t->etype];
+	if(is64(t))
+		fatal("regalloc: 64 bit type %T");
+
+	switch(et) {
+	case TINT8:
+	case TUINT8:
+	case TINT16:
+	case TUINT16:
+	case TINT32:
+	case TUINT32:
+	case TPTR32:
+	case TBOOL:
+		if(o != N && o->op == OREGISTER) {
+			i = o->val.u.reg;
+			if(i >= REGALLOC_R0 && i <= REGALLOC_RMAX)
+				goto out;
+		}
+		for(i=REGALLOC_R0; i<=REGALLOC_RMAX; i++)
+			if(reg[i] == 0) {
+				regpc[i] = (uintptr)getcallerpc(&n);
+				goto out;
+			}
+		print("registers allocated at\n");
+		for(i=REGALLOC_R0; i<=REGALLOC_RMAX; i++)
+			print("%d %p\n", i, regpc[i]);
+		fatal("out of fixed registers");
+		goto err;
+
+	case TFLOAT32:
+	case TFLOAT64:
+		if(o != N && o->op == OREGISTER) {
+			i = o->val.u.reg;
+			if(i >= REGALLOC_F0 && i <= REGALLOC_FMAX)
+				goto out;
+		}
+		for(i=REGALLOC_F0; i<=REGALLOC_FMAX; i++)
+			if(reg[i] == 0)
+				goto out;
+		fatal("out of floating point registers");
+		goto err;
+
+	case TCOMPLEX64:
+	case TCOMPLEX128:
+		tempname(n, t);
+		return;
+	}
+	yyerror("regalloc: unknown type %T", t);
+
+err:
+	nodreg(n, t, 0);
+	return;
+
+out:
+	reg[i]++;
+	nodreg(n, t, i);
+}
+
+void
+regfree(Node *n)
+{
+	int i, fixfree, floatfree;
+
+	if(0 && debug['r']) {
+		fixfree = 0;
+		for(i=REGALLOC_R0; i<=REGALLOC_RMAX; i++)
+			if(reg[i] == 0)
+				fixfree++;
+		floatfree = 0;
+		for(i=REGALLOC_F0; i<=REGALLOC_FMAX; i++)
+			if(reg[i] == 0)
+				floatfree++;
+		print("regalloc fix %d float %d\n", fixfree, floatfree);
+	}
+
+	if(n->op == ONAME)
+		return;
+	if(n->op != OREGISTER && n->op != OINDREG)
+		fatal("regfree: not a register");
+	i = n->val.u.reg;
+	if(i == REGSP)
+		return;
+	if(i < 0 || i >= nelem(reg) || i >= nelem(regpc))
+		fatal("regfree: reg out of range");
+	if(reg[i] <= 0)
+		fatal("regfree: reg %R not allocated", i);
+	reg[i]--;
+	if(reg[i] == 0)
+		regpc[i] = 0;
+}
+
+/*
+ * initialize n to be register r of type t.
+ */
+void
+nodreg(Node *n, Type *t, int r)
+{
+	if(t == T)
+		fatal("nodreg: t nil");
+
+	memset(n, 0, sizeof(*n));
+	n->op = OREGISTER;
+	n->addable = 1;
+	ullmancalc(n);
+	n->val.u.reg = r;
+	n->type = t;
+}
+
+/*
+ * initialize n to be indirect of register r; n is type t.
+ */
+void
+nodindreg(Node *n, Type *t, int r)
+{
+	nodreg(n, t, r);
+	n->op = OINDREG;
+}
+
+Node*
+nodarg(Type *t, int fp)
+{
+	Node *n;
+	NodeList *l;
+	Type *first;
+	Iter savet;
+
+	// entire argument struct, not just one arg
+	if(t->etype == TSTRUCT && t->funarg) {
+		n = nod(ONAME, N, N);
+		n->sym = lookup(".args");
+		n->type = t;
+		first = structfirst(&savet, &t);
+		if(first == nil)
+			fatal("nodarg: bad struct");
+		if(first->width == BADWIDTH)
+			fatal("nodarg: offset not computed for %T", t);
+		n->xoffset = first->width;
+		n->addable = 1;
+		goto 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;
+	if(t->width == BADWIDTH)
+		fatal("nodarg: offset not computed for %T", t);
+	n->xoffset = t->width;
+	n->addable = 1;
+	n->orig = t->nname;
+
+fp:
+	// Rewrite argument named _ to __,
+	// or else the assignment to _ will be
+	// discarded during code generation.
+	if(isblank(n))
+		n->sym = lookup("__");
+
+	switch(fp) {
+	default:
+		fatal("nodarg %T %d", t, fp);
+
+	case 0:		// output arg for calling another function
+		n->op = OINDREG;
+		n->val.u.reg = REGSP;
+		n->xoffset += 4;
+		break;
+
+	case 1:		// input arg to current function
+		n->class = PPARAM;
+		break;
+	}
+	n->typecheck = 1;
+	return n;
+}
+
+/*
+ * return constant i node.
+ * overwritten by next call, but useful in calls to gins.
+ */
+Node*
+ncon(uint32 i)
+{
+	static Node n;
+
+	if(n.type == T)
+		nodconst(&n, types[TUINT32], 0);
+	mpmovecfix(n.val.u.xval, i);
+	return &n;
+}
+
+/*
+ * Is this node a memory operand?
+ */
+int
+ismem(Node *n)
+{
+	switch(n->op) {
+	case OINDREG:
+	case ONAME:
+	case OPARAM:
+	case OCLOSUREVAR:
+		return 1;
+	}
+	return 0;
+}
+
+Node sclean[10];
+int nsclean;
+
+/*
+ * n is a 64-bit value.  fill in lo and hi to refer to its 32-bit halves.
+ */
+void
+split64(Node *n, Node *lo, Node *hi)
+{
+	Node n1;
+	int64 i;
+
+	if(!is64(n->type))
+		fatal("split64 %T", n->type);
+
+	if(nsclean >= nelem(sclean))
+		fatal("split64 clean");
+	sclean[nsclean].op = OEMPTY;
+	nsclean++;
+	switch(n->op) {
+	default:
+		if(!dotaddable(n, &n1)) {
+			igen(n, &n1, N);
+			sclean[nsclean-1] = n1;
+		}
+		n = &n1;
+		goto common;
+	case ONAME:
+		if(n->class == PPARAMREF) {
+			cgen(n->heapaddr, &n1);
+			sclean[nsclean-1] = n1;
+			// fall through.
+			n = &n1;
+		}
+		goto common;
+	case OINDREG:
+	common:
+		*lo = *n;
+		*hi = *n;
+		lo->type = types[TUINT32];
+		if(n->type->etype == TINT64)
+			hi->type = types[TINT32];
+		else
+			hi->type = types[TUINT32];
+		hi->xoffset += 4;
+		break;
+
+	case OLITERAL:
+		convconst(&n1, n->type, &n->val);
+		i = mpgetfix(n1.val.u.xval);
+		nodconst(lo, types[TUINT32], (uint32)i);
+		i >>= 32;
+		if(n->type->etype == TINT64)
+			nodconst(hi, types[TINT32], (int32)i);
+		else
+			nodconst(hi, types[TUINT32], (uint32)i);
+		break;
+	}
+}
+
+void
+splitclean(void)
+{
+	if(nsclean <= 0)
+		fatal("splitclean");
+	nsclean--;
+	if(sclean[nsclean].op != OEMPTY)
+		regfree(&sclean[nsclean]);
+}
+
+#define	CASE(a,b)	(((a)<<16)|((b)<<0))
+/*c2go int CASE(int, int); */
+
+void
+gmove(Node *f, Node *t)
+{
+	int a, ft, tt, fa, ta;
+	Type *cvt;
+	Node r1, r2, flo, fhi, tlo, thi, con;
+	Prog *p1;
+
+	if(debug['M'])
+		print("gmove %N -> %N\n", f, t);
+
+	ft = simsimtype(f->type);
+	tt = simsimtype(t->type);
+	cvt = t->type;
+
+	if(iscomplex[ft] || iscomplex[tt]) {
+		complexmove(f, t);
+		return;
+	}
+
+	// cannot have two memory operands;
+	// except 64-bit, which always copies via registers anyway.
+	if(!is64(f->type) && !is64(t->type) && ismem(f) && ismem(t))
+		goto hard;
+
+	// convert constant to desired type
+	if(f->op == OLITERAL) {
+		switch(tt) {
+		default:
+			convconst(&con, t->type, &f->val);
+			break;
+
+		case TINT16:
+		case TINT8:
+			convconst(&con, types[TINT32], &f->val);
+			regalloc(&r1, con.type, t);
+			gins(AMOVW, &con, &r1);
+			gmove(&r1, t);
+			regfree(&r1);
+			return;
+
+		case TUINT16:
+		case TUINT8:
+			convconst(&con, types[TUINT32], &f->val);
+			regalloc(&r1, con.type, t);
+			gins(AMOVW, &con, &r1);
+			gmove(&r1, t);
+			regfree(&r1);
+			return;
+		}
+
+		f = &con;
+		ft = simsimtype(con.type);
+
+		// constants can't move directly to memory
+		if(ismem(t) && !is64(t->type)) goto hard;
+	}
+
+	// value -> value copy, only one memory operand.
+	// figure out the instruction to use.
+	// break out of switch for one-instruction gins.
+	// goto rdst for "destination must be register".
+	// goto hard for "convert to cvt type first".
+	// otherwise handle and return.
+
+	switch(CASE(ft, tt)) {
+	default:
+		goto fatal;
+
+	/*
+	 * integer copy and truncate
+	 */
+	case CASE(TINT8, TINT8):	// same size
+		if(!ismem(f)) {
+			a = AMOVB;
+			break;
+		}
+	case CASE(TUINT8, TINT8):
+	case CASE(TINT16, TINT8):	// truncate
+	case CASE(TUINT16, TINT8):
+	case CASE(TINT32, TINT8):
+	case CASE(TUINT32, TINT8):
+		a = AMOVBS;
+		break;
+
+	case CASE(TUINT8, TUINT8):
+		if(!ismem(f)) {
+			a = AMOVB;
+			break;
+		}
+	case CASE(TINT8, TUINT8):
+	case CASE(TINT16, TUINT8):
+	case CASE(TUINT16, TUINT8):
+	case CASE(TINT32, TUINT8):
+	case CASE(TUINT32, TUINT8):
+		a = AMOVBU;
+		break;
+
+	case CASE(TINT64, TINT8):	// truncate low word
+	case CASE(TUINT64, TINT8):
+		a = AMOVBS;
+		goto trunc64;
+
+	case CASE(TINT64, TUINT8):
+	case CASE(TUINT64, TUINT8):
+		a = AMOVBU;
+		goto trunc64;
+
+	case CASE(TINT16, TINT16):	// same size
+		if(!ismem(f)) {
+			a = AMOVH;
+			break;
+		}
+	case CASE(TUINT16, TINT16):
+	case CASE(TINT32, TINT16):	// truncate
+	case CASE(TUINT32, TINT16):
+		a = AMOVHS;
+		break;
+
+	case CASE(TUINT16, TUINT16):
+		if(!ismem(f)) {
+			a = AMOVH;
+			break;
+		}
+	case CASE(TINT16, TUINT16):
+	case CASE(TINT32, TUINT16):
+	case CASE(TUINT32, TUINT16):
+		a = AMOVHU;
+		break;
+
+	case CASE(TINT64, TINT16):	// truncate low word
+	case CASE(TUINT64, TINT16):
+		a = AMOVHS;
+		goto trunc64;
+
+	case CASE(TINT64, TUINT16):
+	case CASE(TUINT64, TUINT16):
+		a = AMOVHU;
+		goto trunc64;
+
+	case CASE(TINT32, TINT32):	// same size
+	case CASE(TINT32, TUINT32):
+	case CASE(TUINT32, TINT32):
+	case CASE(TUINT32, TUINT32):
+		a = AMOVW;
+		break;
+
+	case CASE(TINT64, TINT32):	// truncate
+	case CASE(TUINT64, TINT32):
+	case CASE(TINT64, TUINT32):
+	case CASE(TUINT64, TUINT32):
+		split64(f, &flo, &fhi);
+		regalloc(&r1, t->type, N);
+		gins(AMOVW, &flo, &r1);
+		gins(AMOVW, &r1, t);
+		regfree(&r1);
+		splitclean();
+		return;
+
+	case CASE(TINT64, TINT64):	// same size
+	case CASE(TINT64, TUINT64):
+	case CASE(TUINT64, TINT64):
+	case CASE(TUINT64, TUINT64):
+		split64(f, &flo, &fhi);
+		split64(t, &tlo, &thi);
+		regalloc(&r1, flo.type, N);
+		regalloc(&r2, fhi.type, N);
+		gins(AMOVW, &flo, &r1);
+		gins(AMOVW, &fhi, &r2);
+		gins(AMOVW, &r1, &tlo);
+		gins(AMOVW, &r2, &thi);
+		regfree(&r1);
+		regfree(&r2);
+		splitclean();
+		splitclean();
+		return;
+
+	/*
+	 * integer up-conversions
+	 */
+	case CASE(TINT8, TINT16):	// sign extend int8
+	case CASE(TINT8, TUINT16):
+	case CASE(TINT8, TINT32):
+	case CASE(TINT8, TUINT32):
+		a = AMOVBS;
+		goto rdst;
+	case CASE(TINT8, TINT64):	// convert via int32
+	case CASE(TINT8, TUINT64):
+		cvt = types[TINT32];
+		goto hard;
+
+	case CASE(TUINT8, TINT16):	// zero extend uint8
+	case CASE(TUINT8, TUINT16):
+	case CASE(TUINT8, TINT32):
+	case CASE(TUINT8, TUINT32):
+		a = AMOVBU;
+		goto rdst;
+	case CASE(TUINT8, TINT64):	// convert via uint32
+	case CASE(TUINT8, TUINT64):
+		cvt = types[TUINT32];
+		goto hard;
+
+	case CASE(TINT16, TINT32):	// sign extend int16
+	case CASE(TINT16, TUINT32):
+		a = AMOVHS;
+		goto rdst;
+	case CASE(TINT16, TINT64):	// convert via int32
+	case CASE(TINT16, TUINT64):
+		cvt = types[TINT32];
+		goto hard;
+
+	case CASE(TUINT16, TINT32):	// zero extend uint16
+	case CASE(TUINT16, TUINT32):
+		a = AMOVHU;
+		goto rdst;
+	case CASE(TUINT16, TINT64):	// convert via uint32
+	case CASE(TUINT16, TUINT64):
+		cvt = types[TUINT32];
+		goto hard;
+
+	case CASE(TINT32, TINT64):	// sign extend int32
+	case CASE(TINT32, TUINT64):
+		split64(t, &tlo, &thi);
+		regalloc(&r1, tlo.type, N);
+		regalloc(&r2, thi.type, N);
+		gmove(f, &r1);
+		p1 = gins(AMOVW, &r1, &r2);
+		p1->from.type = D_SHIFT;
+		p1->from.offset = 2 << 5 | 31 << 7 | r1.val.u.reg; // r1->31
+		p1->from.reg = NREG;
+//print("gmove: %P\n", p1);
+		gins(AMOVW, &r1, &tlo);
+		gins(AMOVW, &r2, &thi);
+		regfree(&r1);
+		regfree(&r2);
+		splitclean();
+		return;
+
+	case CASE(TUINT32, TINT64):	// zero extend uint32
+	case CASE(TUINT32, TUINT64):
+		split64(t, &tlo, &thi);
+		gmove(f, &tlo);
+		regalloc(&r1, thi.type, N);
+		gins(AMOVW, ncon(0), &r1);
+		gins(AMOVW, &r1, &thi);
+		regfree(&r1);
+		splitclean();
+		return;
+
+	/*
+	* float to integer
+	*/
+	case CASE(TFLOAT32, TINT8):
+	case CASE(TFLOAT32, TUINT8):
+	case CASE(TFLOAT32, TINT16):
+	case CASE(TFLOAT32, TUINT16):
+	case CASE(TFLOAT32, TINT32):
+	case CASE(TFLOAT32, TUINT32):
+//	case CASE(TFLOAT32, TUINT64):
+
+	case CASE(TFLOAT64, TINT8):
+	case CASE(TFLOAT64, TUINT8):
+	case CASE(TFLOAT64, TINT16):
+	case CASE(TFLOAT64, TUINT16):
+	case CASE(TFLOAT64, TINT32):
+	case CASE(TFLOAT64, TUINT32):
+//	case CASE(TFLOAT64, TUINT64):
+		fa = AMOVF;
+		a = AMOVFW;
+		if(ft == TFLOAT64) {
+			fa = AMOVD;
+			a = AMOVDW;
+		}
+		ta = AMOVW;
+		switch(tt) {
+		case TINT8:
+			ta = AMOVBS;
+			break;
+		case TUINT8:
+			ta = AMOVBU;
+			break;
+		case TINT16:
+			ta = AMOVHS;
+			break;
+		case TUINT16:
+			ta = AMOVHU;
+			break;
+		}
+
+		regalloc(&r1, types[ft], f);
+		regalloc(&r2, types[tt], t);
+		gins(fa, f, &r1);	// load to fpu
+		p1 = gins(a, &r1, &r1);	// convert to w
+		switch(tt) {
+		case TUINT8:
+		case TUINT16:
+		case TUINT32:
+			p1->scond |= C_UBIT;
+		}
+		gins(AMOVW, &r1, &r2);	// copy to cpu
+		gins(ta, &r2, t);	// store
+		regfree(&r1);
+		regfree(&r2);
+		return;
+
+	/*
+	 * integer to float
+	 */
+	case CASE(TINT8, TFLOAT32):
+	case CASE(TUINT8, TFLOAT32):
+	case CASE(TINT16, TFLOAT32):
+	case CASE(TUINT16, TFLOAT32):
+	case CASE(TINT32, TFLOAT32):
+	case CASE(TUINT32, TFLOAT32):
+	case CASE(TINT8, TFLOAT64):
+	case CASE(TUINT8, TFLOAT64):
+	case CASE(TINT16, TFLOAT64):
+	case CASE(TUINT16, TFLOAT64):
+	case CASE(TINT32, TFLOAT64):
+	case CASE(TUINT32, TFLOAT64):
+		fa = AMOVW;
+		switch(ft) {
+		case TINT8:
+			fa = AMOVBS;
+			break;
+		case TUINT8:
+			fa = AMOVBU;
+			break;
+		case TINT16:
+			fa = AMOVHS;
+			break;
+		case TUINT16:
+			fa = AMOVHU;
+			break;
+		}
+		a = AMOVWF;
+		ta = AMOVF;
+		if(tt == TFLOAT64) {
+			a = AMOVWD;
+			ta = AMOVD;
+		}
+		regalloc(&r1, types[ft], f);
+		regalloc(&r2, types[tt], t);
+		gins(fa, f, &r1);	// load to cpu
+		gins(AMOVW, &r1, &r2);	// copy to fpu
+		p1 = gins(a, &r2, &r2);	// convert
+		switch(ft) {
+		case TUINT8:
+		case TUINT16:
+		case TUINT32:
+			p1->scond |= C_UBIT;
+		}
+		gins(ta, &r2, t);	// store
+		regfree(&r1);
+		regfree(&r2);
+		return;
+
+	case CASE(TUINT64, TFLOAT32):
+	case CASE(TUINT64, TFLOAT64):
+		fatal("gmove UINT64, TFLOAT not implemented");
+		return;
+
+
+	/*
+	 * float to float
+	 */
+	case CASE(TFLOAT32, TFLOAT32):
+		a = AMOVF;
+		break;
+
+	case CASE(TFLOAT64, TFLOAT64):
+		a = AMOVD;
+		break;
+
+	case CASE(TFLOAT32, TFLOAT64):
+		regalloc(&r1, types[TFLOAT64], t);
+		gins(AMOVF, f, &r1);
+		gins(AMOVFD, &r1, &r1);
+		gins(AMOVD, &r1, t);
+		regfree(&r1);
+		return;
+
+	case CASE(TFLOAT64, TFLOAT32):
+		regalloc(&r1, types[TFLOAT64], t);
+		gins(AMOVD, f, &r1);
+		gins(AMOVDF, &r1, &r1);
+		gins(AMOVF, &r1, t);
+		regfree(&r1);
+		return;
+	}
+
+	gins(a, f, t);
+	return;
+
+rdst:
+	// TODO(kaib): we almost always require a register dest anyway, this can probably be
+	// removed.
+	// requires register destination
+	regalloc(&r1, t->type, t);
+	gins(a, f, &r1);
+	gmove(&r1, t);
+	regfree(&r1);
+	return;
+
+hard:
+	// requires register intermediate
+	regalloc(&r1, cvt, t);
+	gmove(f, &r1);
+	gmove(&r1, t);
+	regfree(&r1);
+	return;
+
+trunc64:
+	// truncate 64 bit integer
+	split64(f, &flo, &fhi);
+	regalloc(&r1, t->type, N);
+	gins(a, &flo, &r1);
+	gins(a, &r1, t);
+	regfree(&r1);
+	splitclean();
+	return;
+
+fatal:
+	// should not happen
+	fatal("gmove %N -> %N", f, t);
+}
+
+int
+samaddr(Node *f, Node *t)
+{
+
+	if(f->op != t->op)
+		return 0;
+
+	switch(f->op) {
+	case OREGISTER:
+		if(f->val.u.reg != t->val.u.reg)
+			break;
+		return 1;
+	}
+	return 0;
+}
+
+/*
+ * generate one instruction:
+ *	as f, t
+ */
+Prog*
+gins(int as, Node *f, Node *t)
+{
+//	Node nod;
+//	int32 v;
+	Prog *p;
+	Addr af, at;
+
+	if(f != N && f->op == OINDEX) {
+		fatal("gins OINDEX not implemented");
+//		regalloc(&nod, &regnode, Z);
+//		v = constnode.vconst;
+//		cgen(f->right, &nod);
+//		constnode.vconst = v;
+//		idx.reg = nod.reg;
+//		regfree(&nod);
+	}
+	if(t != N && t->op == OINDEX) {
+		fatal("gins OINDEX not implemented");
+//		regalloc(&nod, &regnode, Z);
+//		v = constnode.vconst;
+//		cgen(t->right, &nod);
+//		constnode.vconst = v;
+//		idx.reg = nod.reg;
+//		regfree(&nod);
+	}
+
+	memset(&af, 0, sizeof af);
+	memset(&at, 0, sizeof at);
+	if(f != N)
+		naddr(f, &af, 1);
+	if(t != N)
+		naddr(t, &at, 1);
+	p = prog(as);
+	if(f != N)
+		p->from = af;
+	if(t != N)
+		p->to = at;
+	if(debug['g'])
+		print("%P\n", p);
+	return p;
+}
+
+/*
+ * insert n into reg slot of p
+ */
+void
+raddr(Node *n, Prog *p)
+{
+	Addr a;
+
+	naddr(n, &a, 1);
+	if(a.type != D_REG && a.type != D_FREG) {
+		if(n)
+			fatal("bad in raddr: %O", n->op);
+		else
+			fatal("bad in raddr: <null>");
+		p->reg = NREG;
+	} else
+		p->reg = a.reg;
+}
+
+/* generate a comparison
+TODO(kaib): one of the args can actually be a small constant. relax the constraint and fix call sites.
+ */
+Prog*
+gcmp(int as, Node *lhs, Node *rhs)
+{
+	Prog *p;
+
+	if(lhs->op != OREGISTER)
+		fatal("bad operands to gcmp: %O %O", lhs->op, rhs->op);
+
+	p = gins(as, rhs, N);
+	raddr(lhs, p);
+	return p;
+}
+
+/* generate a constant shift
+ * arm encodes a shift by 32 as 0, thus asking for 0 shift is illegal.
+*/
+Prog*
+gshift(int as, Node *lhs, int32 stype, int32 sval, Node *rhs)
+{
+	Prog *p;
+
+	if(sval <= 0 || sval > 32)
+		fatal("bad shift value: %d", sval);
+
+	sval = sval&0x1f;
+
+	p = gins(as, N, rhs);
+	p->from.type = D_SHIFT;
+	p->from.offset = stype | sval<<7 | lhs->val.u.reg;
+	return p;
+}
+
+/* generate a register shift
+*/
+Prog *
+gregshift(int as, Node *lhs, int32 stype, Node *reg, Node *rhs)
+{
+	Prog *p;
+	p = gins(as, N, rhs);
+	p->from.type = D_SHIFT;
+	p->from.offset = stype | reg->val.u.reg << 8 | 1<<4 | lhs->val.u.reg;
+	return p;
+}
+
+/*
+ * generate code to compute n;
+ * make a refer to result.
+ */
+void
+naddr(Node *n, Addr *a, int canemitcode)
+{
+	Sym *s;
+
+	a->type = D_NONE;
+	a->name = D_NONE;
+	a->reg = NREG;
+	a->gotype = nil;
+	a->node = N;
+	a->etype = 0;
+	if(n == N)
+		return;
+
+	if(n->type != T && n->type->etype != TIDEAL) {
+		dowidth(n->type);
+		a->width = n->type->width;
+	}
+
+	switch(n->op) {
+	default:
+		fatal("naddr: bad %O %D", n->op, a);
+		break;
+
+	case OREGISTER:
+		if(n->val.u.reg <= REGALLOC_RMAX) {
+			a->type = D_REG;
+			a->reg = n->val.u.reg;
+		} else {
+			a->type = D_FREG;
+			a->reg = n->val.u.reg - REGALLOC_F0;
+		}
+		a->sym = nil;
+		break;
+
+	case OINDEX:
+	case OIND:
+		fatal("naddr: OINDEX");
+//		naddr(n->left, a);
+//		if(a->type >= D_AX && a->type <= D_DI)
+//			a->type += D_INDIR;
+//		else
+//		if(a->type == D_CONST)
+//			a->type = D_NONE+D_INDIR;
+//		else
+//		if(a->type == D_ADDR) {
+//			a->type = a->index;
+//			a->index = D_NONE;
+//		} else
+//			goto bad;
+//		if(n->op == OINDEX) {
+//			a->index = idx.reg;
+//			a->scale = n->scale;
+//		}
+//		break;
+
+	case OINDREG:
+		a->type = D_OREG;
+		a->reg = n->val.u.reg;
+		a->sym = linksym(n->sym);
+		a->offset = n->xoffset;
+		break;
+
+	case OPARAM:
+		// n->left is PHEAP ONAME for stack parameter.
+		// compute address of actual parameter on stack.
+		a->etype = simtype[n->left->type->etype];
+		a->width = n->left->type->width;
+		a->offset = n->xoffset;
+		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 = nil;
+		break;		
+
+	case OCFUNC:
+		naddr(n->left, a, canemitcode);
+		a->sym = linksym(n->left->sym);
+		break;
+
+	case ONAME:
+		a->etype = 0;
+		a->width = 0;
+		a->reg = NREG;
+		if(n->type != T) {
+			a->etype = simtype[n->type->etype];
+			a->width = n->type->width;
+		}
+		a->offset = n->xoffset;
+		s = n->sym;
+		a->node = n->orig;
+		//if(a->node >= (Node*)&n)
+		//	fatal("stack node");
+		if(s == S)
+			s = lookup(".noname");
+		if(n->method) {
+			if(n->type != T)
+			if(n->type->sym != S)
+			if(n->type->sym->pkg != nil)
+				s = pkglookup(s->name, n->type->sym->pkg);
+		}
+
+		a->type = D_OREG;
+		switch(n->class) {
+		default:
+			fatal("naddr: ONAME class %S %d\n", n->sym, n->class);
+		case PEXTERN:
+			a->name = D_EXTERN;
+			break;
+		case PAUTO:
+			a->name = D_AUTO;
+			break;
+		case PPARAM:
+		case PPARAMOUT:
+			a->name = D_PARAM;
+			break;
+		case PFUNC:
+			a->name = D_EXTERN;
+			a->type = D_CONST;
+			s = funcsym(s);
+			break;
+		}
+		a->sym = linksym(s);
+		break;
+
+	case OLITERAL:
+		switch(n->val.ctype) {
+		default:
+			fatal("naddr: const %lT", n->type);
+			break;
+		case CTFLT:
+			a->type = D_FCONST;
+			a->u.dval = mpgetflt(n->val.u.fval);
+			break;
+		case CTINT:
+		case CTRUNE:
+			a->sym = nil;
+			a->type = D_CONST;
+			a->offset = mpgetfix(n->val.u.xval);
+			break;
+		case CTSTR:
+			datagostring(n->val.u.sval, a);
+			break;
+		case CTBOOL:
+			a->sym = nil;
+			a->type = D_CONST;
+			a->offset = n->val.u.bval;
+			break;
+		case CTNIL:
+			a->sym = nil;
+			a->type = D_CONST;
+			a->offset = 0;
+			break;
+		}
+		break;
+
+	case OITAB:
+		// itable of interface value
+		naddr(n->left, a, canemitcode);
+		a->etype = TINT32;
+		if(a->type == D_CONST && a->offset == 0)
+			break;	// len(nil)
+		break;
+
+	case OSPTR:
+		// pointer in a string or slice
+		naddr(n->left, a, canemitcode);
+		if(a->type == D_CONST && a->offset == 0)
+			break;	// ptr(nil)
+		a->etype = simtype[tptr];
+		a->offset += Array_array;
+		a->width = widthptr;
+		break;
+
+	case OLEN:
+		// len of string or slice
+		naddr(n->left, a, canemitcode);
+		a->etype = TINT32;
+		if(a->type == D_CONST && a->offset == 0)
+			break;	// len(nil)
+		a->offset += Array_nel;
+		break;
+
+	case OCAP:
+		// cap of string or slice
+		naddr(n->left, a, canemitcode);
+		a->etype = TINT32;
+		if(a->type == D_CONST && a->offset == 0)
+			break;	// cap(nil)
+		a->offset += Array_cap;
+		break;
+
+	case OADDR:
+		naddr(n->left, a, canemitcode);
+		a->etype = tptr;
+		switch(a->type) {
+		case D_OREG:
+			a->type = D_CONST;
+			break;
+
+		case D_REG:
+		case D_CONST:
+			break;
+		
+		default:
+			fatal("naddr: OADDR %d\n", a->type);
+		}
+	}
+	
+	if(a->width < 0)
+		fatal("naddr: bad width for %N -> %D", n, a);
+}
+
+/*
+ * return Axxx for Oxxx on type t.
+ */
+int
+optoas(int op, Type *t)
+{
+	int a;
+
+	if(t == T)
+		fatal("optoas: t is nil");
+
+	a = AGOK;
+	switch(CASE(op, simtype[t->etype])) {
+	default:
+		fatal("optoas: no entry %O-%T etype %T simtype %T", op, t, types[t->etype], types[simtype[t->etype]]);
+		break;
+
+/*	case CASE(OADDR, TPTR32):
+		a = ALEAL;
+		break;
+
+	case CASE(OADDR, TPTR64):
+		a = ALEAQ;
+		break;
+*/
+	// TODO(kaib): make sure the conditional branches work on all edge cases
+	case CASE(OEQ, TBOOL):
+	case CASE(OEQ, TINT8):
+	case CASE(OEQ, TUINT8):
+	case CASE(OEQ, TINT16):
+	case CASE(OEQ, TUINT16):
+	case CASE(OEQ, TINT32):
+	case CASE(OEQ, TUINT32):
+	case CASE(OEQ, TINT64):
+	case CASE(OEQ, TUINT64):
+	case CASE(OEQ, TPTR32):
+	case CASE(OEQ, TPTR64):
+	case CASE(OEQ, TFLOAT32):
+	case CASE(OEQ, TFLOAT64):
+		a = ABEQ;
+		break;
+
+	case CASE(ONE, TBOOL):
+	case CASE(ONE, TINT8):
+	case CASE(ONE, TUINT8):
+	case CASE(ONE, TINT16):
+	case CASE(ONE, TUINT16):
+	case CASE(ONE, TINT32):
+	case CASE(ONE, TUINT32):
+	case CASE(ONE, TINT64):
+	case CASE(ONE, TUINT64):
+	case CASE(ONE, TPTR32):
+	case CASE(ONE, TPTR64):
+	case CASE(ONE, TFLOAT32):
+	case CASE(ONE, TFLOAT64):
+		a = ABNE;
+		break;
+
+	case CASE(OLT, TINT8):
+	case CASE(OLT, TINT16):
+	case CASE(OLT, TINT32):
+	case CASE(OLT, TINT64):
+	case CASE(OLT, TFLOAT32):
+	case CASE(OLT, TFLOAT64):
+		a = ABLT;
+		break;
+
+	case CASE(OLT, TUINT8):
+	case CASE(OLT, TUINT16):
+	case CASE(OLT, TUINT32):
+	case CASE(OLT, TUINT64):
+		a = ABLO;
+		break;
+
+	case CASE(OLE, TINT8):
+	case CASE(OLE, TINT16):
+	case CASE(OLE, TINT32):
+	case CASE(OLE, TINT64):
+	case CASE(OLE, TFLOAT32):
+	case CASE(OLE, TFLOAT64):
+		a = ABLE;
+		break;
+
+	case CASE(OLE, TUINT8):
+	case CASE(OLE, TUINT16):
+	case CASE(OLE, TUINT32):
+	case CASE(OLE, TUINT64):
+		a = ABLS;
+		break;
+
+	case CASE(OGT, TINT8):
+	case CASE(OGT, TINT16):
+	case CASE(OGT, TINT32):
+	case CASE(OGT, TINT64):
+	case CASE(OGT, TFLOAT32):
+	case CASE(OGT, TFLOAT64):
+		a = ABGT;
+		break;
+
+	case CASE(OGT, TUINT8):
+	case CASE(OGT, TUINT16):
+	case CASE(OGT, TUINT32):
+	case CASE(OGT, TUINT64):
+		a = ABHI;
+		break;
+
+	case CASE(OGE, TINT8):
+	case CASE(OGE, TINT16):
+	case CASE(OGE, TINT32):
+	case CASE(OGE, TINT64):
+	case CASE(OGE, TFLOAT32):
+	case CASE(OGE, TFLOAT64):
+		a = ABGE;
+		break;
+
+	case CASE(OGE, TUINT8):
+	case CASE(OGE, TUINT16):
+	case CASE(OGE, TUINT32):
+	case CASE(OGE, TUINT64):
+		a = ABHS;
+		break;
+
+	case CASE(OCMP, TBOOL):
+	case CASE(OCMP, TINT8):
+	case CASE(OCMP, TUINT8):
+	case CASE(OCMP, TINT16):
+	case CASE(OCMP, TUINT16):
+	case CASE(OCMP, TINT32):
+	case CASE(OCMP, TUINT32):
+	case CASE(OCMP, TPTR32):
+		a = ACMP;
+		break;
+
+	case CASE(OCMP, TFLOAT32):
+		a = ACMPF;
+		break;
+
+	case CASE(OCMP, TFLOAT64):
+		a = ACMPD;
+		break;
+
+	case CASE(OAS, TBOOL):
+		a = AMOVB;
+		break;
+
+	case CASE(OAS, TINT8):
+		a = AMOVBS;
+		break;
+
+	case CASE(OAS, TUINT8):
+		a = AMOVBU;
+		break;
+
+	case CASE(OAS, TINT16):
+		a = AMOVHS;
+		break;
+
+	case CASE(OAS, TUINT16):
+		a = AMOVHU;
+		break;
+
+	case CASE(OAS, TINT32):
+	case CASE(OAS, TUINT32):
+	case CASE(OAS, TPTR32):
+		a = AMOVW;
+		break;
+
+	case CASE(OAS, TFLOAT32):
+		a = AMOVF;
+		break;
+
+	case CASE(OAS, TFLOAT64):
+		a = AMOVD;
+		break;
+
+	case CASE(OADD, TINT8):
+	case CASE(OADD, TUINT8):
+	case CASE(OADD, TINT16):
+	case CASE(OADD, TUINT16):
+	case CASE(OADD, TINT32):
+	case CASE(OADD, TUINT32):
+	case CASE(OADD, TPTR32):
+		a = AADD;
+		break;
+
+	case CASE(OADD, TFLOAT32):
+		a = AADDF;
+		break;
+
+	case CASE(OADD, TFLOAT64):
+		a = AADDD;
+		break;
+
+	case CASE(OSUB, TINT8):
+	case CASE(OSUB, TUINT8):
+	case CASE(OSUB, TINT16):
+	case CASE(OSUB, TUINT16):
+	case CASE(OSUB, TINT32):
+	case CASE(OSUB, TUINT32):
+	case CASE(OSUB, TPTR32):
+		a = ASUB;
+		break;
+
+	case CASE(OSUB, TFLOAT32):
+		a = ASUBF;
+		break;
+
+	case CASE(OSUB, TFLOAT64):
+		a = ASUBD;
+		break;
+
+	case CASE(OMINUS, TINT8):
+	case CASE(OMINUS, TUINT8):
+	case CASE(OMINUS, TINT16):
+	case CASE(OMINUS, TUINT16):
+	case CASE(OMINUS, TINT32):
+	case CASE(OMINUS, TUINT32):
+	case CASE(OMINUS, TPTR32):
+		a = ARSB;
+		break;
+
+	case CASE(OAND, TINT8):
+	case CASE(OAND, TUINT8):
+	case CASE(OAND, TINT16):
+	case CASE(OAND, TUINT16):
+	case CASE(OAND, TINT32):
+	case CASE(OAND, TUINT32):
+	case CASE(OAND, TPTR32):
+		a = AAND;
+		break;
+
+	case CASE(OOR, TINT8):
+	case CASE(OOR, TUINT8):
+	case CASE(OOR, TINT16):
+	case CASE(OOR, TUINT16):
+	case CASE(OOR, TINT32):
+	case CASE(OOR, TUINT32):
+	case CASE(OOR, TPTR32):
+		a = AORR;
+		break;
+
+	case CASE(OXOR, TINT8):
+	case CASE(OXOR, TUINT8):
+	case CASE(OXOR, TINT16):
+	case CASE(OXOR, TUINT16):
+	case CASE(OXOR, TINT32):
+	case CASE(OXOR, TUINT32):
+	case CASE(OXOR, TPTR32):
+		a = AEOR;
+		break;
+
+	case CASE(OLSH, TINT8):
+	case CASE(OLSH, TUINT8):
+	case CASE(OLSH, TINT16):
+	case CASE(OLSH, TUINT16):
+	case CASE(OLSH, TINT32):
+	case CASE(OLSH, TUINT32):
+	case CASE(OLSH, TPTR32):
+		a = ASLL;
+		break;
+
+	case CASE(ORSH, TUINT8):
+	case CASE(ORSH, TUINT16):
+	case CASE(ORSH, TUINT32):
+	case CASE(ORSH, TPTR32):
+		a = ASRL;
+		break;
+
+	case CASE(ORSH, TINT8):
+	case CASE(ORSH, TINT16):
+	case CASE(ORSH, TINT32):
+		a = ASRA;
+		break;
+
+	case CASE(OMUL, TUINT8):
+	case CASE(OMUL, TUINT16):
+	case CASE(OMUL, TUINT32):
+	case CASE(OMUL, TPTR32):
+		a = AMULU;
+		break;
+
+	case CASE(OMUL, TINT8):
+	case CASE(OMUL, TINT16):
+	case CASE(OMUL, TINT32):
+		a = AMUL;
+		break;
+
+	case CASE(OMUL, TFLOAT32):
+		a = AMULF;
+		break;
+
+	case CASE(OMUL, TFLOAT64):
+		a = AMULD;
+		break;
+
+	case CASE(ODIV, TUINT8):
+	case CASE(ODIV, TUINT16):
+	case CASE(ODIV, TUINT32):
+	case CASE(ODIV, TPTR32):
+		a = ADIVU;
+		break;
+
+	case CASE(ODIV, TINT8):
+	case CASE(ODIV, TINT16):
+	case CASE(ODIV, TINT32):
+		a = ADIV;
+		break;
+
+	case CASE(OMOD, TUINT8):
+	case CASE(OMOD, TUINT16):
+	case CASE(OMOD, TUINT32):
+	case CASE(OMOD, TPTR32):
+		a = AMODU;
+		break;
+
+	case CASE(OMOD, TINT8):
+	case CASE(OMOD, TINT16):
+	case CASE(OMOD, TINT32):
+		a = AMOD;
+		break;
+
+//	case CASE(OEXTEND, TINT16):
+//		a = ACWD;
+//		break;
+
+//	case CASE(OEXTEND, TINT32):
+//		a = ACDQ;
+//		break;
+
+//	case CASE(OEXTEND, TINT64):
+//		a = ACQO;
+//		break;
+
+	case CASE(ODIV, TFLOAT32):
+		a = ADIVF;
+		break;
+
+	case CASE(ODIV, TFLOAT64):
+		a = ADIVD;
+		break;
+
+	}
+	return a;
+}
+
+enum
+{
+	ODynam	= 1<<0,
+	OPtrto	= 1<<1,
+};
+
+static	Node	clean[20];
+static	int	cleani = 0;
+
+void
+sudoclean(void)
+{
+	if(clean[cleani-1].op != OEMPTY)
+		regfree(&clean[cleani-1]);
+	if(clean[cleani-2].op != OEMPTY)
+		regfree(&clean[cleani-2]);
+	cleani -= 2;
+}
+
+int
+dotaddable(Node *n, Node *n1)
+{
+	int o;
+	int64 oary[10];
+	Node *nn;
+
+	if(n->op != ODOT)
+		return 0;
+
+	o = dotoffset(n, oary, &nn);
+	if(nn != N && nn->addable && o == 1 && oary[0] >= 0) {
+		*n1 = *nn;
+		n1->type = n->type;
+		n1->xoffset += oary[0];
+		return 1;
+	}
+	return 0;
+}
+
+/*
+ * generate code to compute address of n,
+ * a reference to a (perhaps nested) field inside
+ * an array or struct.
+ * return 0 on failure, 1 on success.
+ * on success, leaves usable address in a.
+ *
+ * caller is responsible for calling sudoclean
+ * after successful sudoaddable,
+ * to release the register used for a.
+ */
+int
+sudoaddable(int as, Node *n, Addr *a, int *w)
+{
+	int o, i;
+	int64 oary[10];
+	int64 v;
+	Node n1, n2, n3, n4, *nn, *l, *r;
+	Node *reg, *reg1;
+	Prog *p1, *p2;
+	Type *t;
+
+	if(n->type == T)
+		return 0;
+
+	switch(n->op) {
+	case OLITERAL:
+		if(!isconst(n, CTINT))
+			break;
+		v = mpgetfix(n->val.u.xval);
+		if(v >= 32000 || v <= -32000)
+			break;
+		goto lit;
+
+	case ODOT:
+	case ODOTPTR:
+		cleani += 2;
+		reg = &clean[cleani-1];
+		reg1 = &clean[cleani-2];
+		reg->op = OEMPTY;
+		reg1->op = OEMPTY;
+		goto odot;
+
+	case OINDEX:
+		return 0;
+		// disabled: OINDEX case is now covered by agenr
+		// for a more suitable register allocation pattern.
+		if(n->left->type->etype == TSTRING)
+			return 0;
+		cleani += 2;
+		reg = &clean[cleani-1];
+		reg1 = &clean[cleani-2];
+		reg->op = OEMPTY;
+		reg1->op = OEMPTY;
+		goto oindex;
+	}
+	return 0;
+
+lit:
+	switch(as) {
+	default:
+		return 0;
+	case AADD: case ASUB: case AAND: case AORR: case AEOR:
+	case AMOVB: case AMOVBS: case AMOVBU:
+	case AMOVH: case AMOVHS: case AMOVHU:
+	case AMOVW:
+		break;
+	}
+
+	cleani += 2;
+	reg = &clean[cleani-1];
+	reg1 = &clean[cleani-2];
+	reg->op = OEMPTY;
+	reg1->op = OEMPTY;
+	naddr(n, a, 1);
+	goto yes;
+
+odot:
+	o = dotoffset(n, oary, &nn);
+	if(nn == N)
+		goto no;
+
+	if(nn->addable && o == 1 && oary[0] >= 0) {
+		// directly addressable set of DOTs
+		n1 = *nn;
+		n1.type = n->type;
+		n1.xoffset += oary[0];
+		naddr(&n1, a, 1);
+		goto yes;
+	}
+
+	regalloc(reg, types[tptr], N);
+	n1 = *reg;
+	n1.op = OINDREG;
+	if(oary[0] >= 0) {
+		agen(nn, reg);
+		n1.xoffset = oary[0];
+	} else {
+		cgen(nn, reg);
+		cgen_checknil(reg);
+		n1.xoffset = -(oary[0]+1);
+	}
+
+	for(i=1; i<o; i++) {
+		if(oary[i] >= 0)
+			fatal("can't happen");
+		gins(AMOVW, &n1, reg);
+		cgen_checknil(reg);
+		n1.xoffset = -(oary[i]+1);
+	}
+
+	a->type = D_NONE;
+	a->name = D_NONE;
+	n1.type = n->type;
+	naddr(&n1, a, 1);
+	goto yes;
+
+oindex:
+	l = n->left;
+	r = n->right;
+	if(l->ullman >= UINF && r->ullman >= UINF)
+		goto no;
+
+	// set o to type of array
+	o = 0;
+	if(isptr[l->type->etype]) {
+		o += OPtrto;
+		if(l->type->type->etype != TARRAY)
+			fatal("not ptr ary");
+		if(l->type->type->bound < 0)
+			o += ODynam;
+	} else {
+		if(l->type->etype != TARRAY)
+			fatal("not ary");
+		if(l->type->bound < 0)
+			o += ODynam;
+	}
+
+	*w = n->type->width;
+	if(isconst(r, CTINT))
+		goto oindex_const;
+
+	switch(*w) {
+	default:
+		goto no;
+	case 1:
+	case 2:
+	case 4:
+	case 8:
+		break;
+	}
+
+	// load the array (reg)
+	if(l->ullman > r->ullman) {
+		regalloc(reg, types[tptr], N);
+		if(o & OPtrto) {
+			cgen(l, reg);
+			cgen_checknil(reg);
+		} else
+			agen(l, reg);
+	}
+
+	// load the index (reg1)
+	t = types[TUINT32];
+	if(issigned[r->type->etype])
+		t = types[TINT32];
+	regalloc(reg1, t, N);
+	regalloc(&n3, types[TINT32], reg1);
+	p2 = cgenindex(r, &n3, debug['B'] || n->bounded);
+	gmove(&n3, reg1);
+	regfree(&n3);
+
+	// load the array (reg)
+	if(l->ullman <= r->ullman) {
+		regalloc(reg, types[tptr], N);
+		if(o & OPtrto) {
+			cgen(l, reg);
+			cgen_checknil(reg);
+		} else
+			agen(l, reg);
+	}
+
+	// check bounds
+	if(!debug['B']) {
+		if(o & ODynam) {
+			n2 = *reg;
+			n2.op = OINDREG;
+			n2.type = types[tptr];
+			n2.xoffset = Array_nel;
+		} else {
+			if(o & OPtrto)
+				nodconst(&n2, types[TUINT32], l->type->type->bound);
+			else
+				nodconst(&n2, types[TUINT32], l->type->bound);
+		}
+		regalloc(&n3, n2.type, N);
+		cgen(&n2, &n3);
+		gcmp(optoas(OCMP, types[TUINT32]), reg1, &n3);
+		regfree(&n3);
+		p1 = gbranch(optoas(OLT, types[TUINT32]), T, +1);
+		if(p2)
+			patch(p2, pc);
+		ginscall(panicindex, 0);
+		patch(p1, pc);
+	}
+
+	if(o & ODynam) {
+		n2 = *reg;
+		n2.op = OINDREG;
+		n2.type = types[tptr];
+		n2.xoffset = Array_array;
+		gmove(&n2, reg);
+	}
+
+	switch(*w) {
+	case 1:
+		gins(AADD, reg1, reg);
+		break;
+	case 2:
+		gshift(AADD, reg1, SHIFT_LL, 1, reg);
+		break;
+	case 4:
+		gshift(AADD, reg1, SHIFT_LL, 2, reg);
+		break;
+	case 8:
+		gshift(AADD, reg1, SHIFT_LL, 3, reg);
+		break;
+	}
+
+	naddr(reg1, a, 1);
+	a->type = D_OREG;
+	a->reg = reg->val.u.reg;
+	a->offset = 0;
+	goto yes;
+
+oindex_const:
+	// index is constant
+	// can check statically and
+	// can multiply by width statically
+
+	regalloc(reg, types[tptr], N);
+	if(o & OPtrto) {
+		cgen(l, reg);
+		cgen_checknil(reg);
+	} else
+		agen(l, reg);
+
+	v = mpgetfix(r->val.u.xval);
+	if(o & ODynam) {
+		if(!debug['B'] && !n->bounded) {
+			n1 = *reg;
+			n1.op = OINDREG;
+			n1.type = types[tptr];
+			n1.xoffset = Array_nel;
+			nodconst(&n2, types[TUINT32], v);
+			regalloc(&n3, types[TUINT32], N);
+			cgen(&n2, &n3);
+			regalloc(&n4, n1.type, N);
+			cgen(&n1, &n4);
+			gcmp(optoas(OCMP, types[TUINT32]), &n4, &n3);
+			regfree(&n4);
+			regfree(&n3);
+			p1 = gbranch(optoas(OGT, types[TUINT32]), T, +1);
+			ginscall(panicindex, 0);
+			patch(p1, pc);
+		}
+
+		n1 = *reg;
+		n1.op = OINDREG;
+		n1.type = types[tptr];
+		n1.xoffset = Array_array;
+		gmove(&n1, reg);
+	}
+
+	n2 = *reg;
+	n2.op = OINDREG;
+	n2.xoffset = v * (*w);
+	a->type = D_NONE;
+	a->name = D_NONE;
+	naddr(&n2, a, 1);
+	goto yes;
+
+yes:
+	return 1;
+
+no:
+	sudoclean();
+	return 0;
+}
diff --git a/src/cmd/5g/opt.h b/src/cmd/5g/opt.h
new file mode 100644
index 0000000..1946c1d
--- /dev/null
+++ b/src/cmd/5g/opt.h
@@ -0,0 +1,221 @@
+// Inferno utils/5c/gc.h
+// http://code.google.com/p/inferno-os/source/browse/utils/5c/gc.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.
+
+#include	"../gc/popt.h"
+
+#define	Z	N
+#define	Adr	Addr
+
+#define	D_HI	D_NONE
+#define	D_LO	D_NONE
+
+#define	BLOAD(r)	band(bnot(r->refbehind), r->refahead)
+#define	BSTORE(r)	band(bnot(r->calbehind), r->calahead)
+#define	LOAD(r)		(~r->refbehind.b[z] & r->refahead.b[z])
+#define	STORE(r)	(~r->calbehind.b[z] & r->calahead.b[z])
+
+#define	CLOAD	5
+#define	CREF	5
+#define	CINF	1000
+#define	LOOP	3
+
+typedef	struct	Reg	Reg;
+typedef	struct	Rgn	Rgn;
+
+/*c2go
+extern Node *Z;
+enum
+{
+	D_HI = D_NONE,
+	D_LO = D_NONE,
+	CLOAD = 5,
+	CREF = 5,
+	CINF = 1000,
+	LOOP = 3,
+};
+
+uint32 BLOAD(Reg*);
+uint32 BSTORE(Reg*);
+uint32 LOAD(Reg*);
+uint32 STORE(Reg*);
+*/
+
+// A Reg is a wrapper around a single Prog (one instruction) that holds
+// register optimization information while the optimizer runs.
+// r->prog is the instruction.
+// r->prog->opt points back to r.
+struct	Reg
+{
+	Flow	f;
+
+	Bits	set;  		// variables written by this instruction.
+	Bits	use1; 		// variables read by prog->from.
+	Bits	use2; 		// variables read by prog->to.
+
+	Bits	refbehind;
+	Bits	refahead;
+	Bits	calbehind;
+	Bits	calahead;
+	Bits	regdiff;
+	Bits	act;
+
+	int32	regu;		// register used bitmap
+};
+#define	R	((Reg*)0)
+/*c2go extern Reg *R; */
+
+#define	NRGN	600
+/*c2go enum { NRGN = 600 }; */
+struct	Rgn
+{
+	Reg*	enter;
+	short	cost;
+	short	varno;
+	short	regno;
+};
+
+EXTERN	int32	exregoffset;		// not set
+EXTERN	int32	exfregoffset;		// not set
+EXTERN	Reg	zreg;
+EXTERN	Reg*	freer;
+EXTERN	Reg**	rpo2r;
+EXTERN	Rgn	region[NRGN];
+EXTERN	Rgn*	rgp;
+EXTERN	int	nregion;
+EXTERN	int	nvar;
+EXTERN	int32	regbits;
+EXTERN	int32	exregbits;
+EXTERN	Bits	externs;
+EXTERN	Bits	params;
+EXTERN	Bits	consts;
+EXTERN	Bits	addrs;
+EXTERN	Bits	ivar;
+EXTERN	Bits	ovar;
+EXTERN	int	change;
+EXTERN	int32	maxnr;
+EXTERN	int32*	idom;
+
+EXTERN	struct
+{
+	int32	ncvtreg;
+	int32	nspill;
+	int32	nreload;
+	int32	ndelmov;
+	int32	nvar;
+	int32	naddr;
+} ostats;
+
+/*
+ * reg.c
+ */
+Reg*	rega(void);
+int	rcmp(const void*, const void*);
+void	regopt(Prog*);
+void	addmove(Reg*, int, int, int);
+Bits	mkvar(Reg *r, Adr *a);
+void	prop(Reg*, Bits, Bits);
+void	synch(Reg*, Bits);
+uint32	allreg(uint32, Rgn*);
+void	paint1(Reg*, int);
+uint32	paint2(Reg*, int);
+void	paint3(Reg*, int, int32, int);
+void	addreg(Adr*, int);
+void	dumpit(char *str, Flow *r0, int);
+
+/*
+ * peep.c
+ */
+void	peep(Prog*);
+void	excise(Flow*);
+int	copyu(Prog*, Adr*, Adr*);
+
+int32	RtoB(int);
+int32	FtoB(int);
+int	BtoR(int32);
+int	BtoF(int32);
+
+/*
+ * prog.c
+ */
+typedef struct ProgInfo ProgInfo;
+struct ProgInfo
+{
+	uint32 flags; // the bits below
+};
+
+enum
+{
+	// Pseudo-op, like TEXT, GLOBL, TYPE, PCDATA, FUNCDATA.
+	Pseudo = 1<<1,
+	
+	// There's nothing to say about the instruction,
+	// but it's still okay to see.
+	OK = 1<<2,
+
+	// Size of right-side write, or right-side read if no write.
+	SizeB = 1<<3,
+	SizeW = 1<<4,
+	SizeL = 1<<5,
+	SizeQ = 1<<6,
+	SizeF = 1<<7, // float aka float32
+	SizeD = 1<<8, // double aka float64
+
+	// Left side: address taken, read, write.
+	LeftAddr = 1<<9,
+	LeftRead = 1<<10,
+	LeftWrite = 1<<11,
+	
+	// Register in middle; never written.
+	RegRead = 1<<12,
+	CanRegRead = 1<<13,
+	
+	// Right side: address taken, read, write.
+	RightAddr = 1<<14,
+	RightRead = 1<<15,
+	RightWrite = 1<<16,
+
+	// Instruction kinds
+	Move = 1<<17, // straight move
+	Conv = 1<<18, // size conversion
+	Cjmp = 1<<19, // conditional jump
+	Break = 1<<20, // breaks control flow (no fallthrough)
+	Call = 1<<21, // function call
+	Jump = 1<<22, // jump
+	Skip = 1<<23, // data instruction
+};
+
+void proginfo(ProgInfo*, Prog*);
+
+// To allow use of AJMP and ACALL in ../gc/popt.c.
+enum
+{
+	AJMP = AB,
+	ACALL = ABL,
+};
diff --git a/src/cmd/5g/peep.c b/src/cmd/5g/peep.c
new file mode 100644
index 0000000..639f4c5
--- /dev/null
+++ b/src/cmd/5g/peep.c
@@ -0,0 +1,1629 @@
+// Inferno utils/5c/peep.c
+// http://code.google.com/p/inferno-os/source/browse/utils/5c/peep.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"
+#include "opt.h"
+
+static int	xtramodes(Graph*, Flow*, Adr*);
+static int	shortprop(Flow *r);
+static int	subprop(Flow*);
+static int	copyprop(Graph*, Flow*);
+static int	copy1(Adr*, Adr*, Flow*, int);
+static int	copyas(Adr*, Adr*);
+static int	copyau(Adr*, Adr*);
+static int	copysub(Adr*, Adr*, Adr*, int);
+static int	copysub1(Prog*, Adr*, Adr*, int);
+static Flow*	findpre(Flow *r, Adr *v);
+static int	copyau1(Prog *p, Adr *v);
+static int	isdconst(Addr *a);
+
+static uint32	gactive;
+
+// UNUSED
+int	shiftprop(Flow *r);
+void	constprop(Adr *c1, Adr *v1, Flow *r);
+void	predicate(Graph*);
+
+void
+peep(Prog *firstp)
+{
+	Flow *r;
+	Graph *g;
+	Prog *p;
+	int t;
+
+	g = flowstart(firstp, sizeof(Flow));
+	if(g == nil)
+		return;
+	gactive = 0;
+
+loop1:
+	if(debug['P'] && debug['v'])
+		dumpit("loop1", g->start, 0);
+
+	t = 0;
+	for(r=g->start; r!=nil; r=r->link) {
+		p = r->prog;
+		switch(p->as) {
+		case ASLL:
+		case ASRL:
+		case ASRA:
+			/*
+			 * elide shift into D_SHIFT operand of subsequent instruction
+			 */
+//			if(shiftprop(r)) {
+//				excise(r);
+//				t++;
+//				break;
+//			}
+			break;
+
+		case AMOVB:
+		case AMOVH:
+		case AMOVW:
+		case AMOVF:
+		case AMOVD:
+			if(regtyp(&p->from))
+			if(p->from.type == p->to.type)
+			if(p->scond == C_SCOND_NONE) {
+				if(copyprop(g, r)) {
+					excise(r);
+					t++;
+					break;
+				}
+				if(subprop(r) && copyprop(g, r)) {
+					excise(r);
+					t++;
+					break;
+				}
+			}
+			break;
+
+		case AMOVHS:
+		case AMOVHU:
+		case AMOVBS:
+		case AMOVBU:
+			if(p->from.type == D_REG) {
+				if(shortprop(r))
+					t++;
+			}
+			break;
+
+#ifdef NOTDEF
+			if(p->scond == C_SCOND_NONE)
+			if(regtyp(&p->to))
+			if(isdconst(&p->from)) {
+				constprop(&p->from, &p->to, r->s1);
+			}
+			break;
+#endif
+		}
+	}
+	if(t)
+		goto loop1;
+
+	for(r=g->start; r!=nil; r=r->link) {
+		p = r->prog;
+		switch(p->as) {
+		case AEOR:
+			/*
+			 * EOR -1,x,y => MVN x,y
+			 */
+			if(isdconst(&p->from) && p->from.offset == -1) {
+				p->as = AMVN;
+				p->from.type = D_REG;
+				if(p->reg != NREG)
+					p->from.reg = p->reg;
+				else
+					p->from.reg = p->to.reg;
+				p->reg = NREG;
+			}
+			break;
+		}
+	}
+
+	for(r=g->start; r!=nil; r=r->link) {
+		p = r->prog;
+		switch(p->as) {
+		case AMOVW:
+		case AMOVB:
+		case AMOVBS:
+		case AMOVBU:
+			if(p->from.type == D_OREG && p->from.offset == 0)
+				xtramodes(g, r, &p->from);
+			else
+			if(p->to.type == D_OREG && p->to.offset == 0)
+				xtramodes(g, r, &p->to);
+			else
+				continue;
+			break;
+//		case ACMP:
+//			/*
+//			 * elide CMP $0,x if calculation of x can set condition codes
+//			 */
+//			if(isdconst(&p->from) || p->from.offset != 0)
+//				continue;
+//			r2 = r->s1;
+//			if(r2 == nil)
+//				continue;
+//			t = r2->prog->as;
+//			switch(t) {
+//			default:
+//				continue;
+//			case ABEQ:
+//			case ABNE:
+//			case ABMI:
+//			case ABPL:
+//				break;
+//			case ABGE:
+//				t = ABPL;
+//				break;
+//			case ABLT:
+//				t = ABMI;
+//				break;
+//			case ABHI:
+//				t = ABNE;
+//				break;
+//			case ABLS:
+//				t = ABEQ;
+//				break;
+//			}
+//			r1 = r;
+//			do
+//				r1 = uniqp(r1);
+//			while (r1 != nil && r1->prog->as == ANOP);
+//			if(r1 == nil)
+//				continue;
+//			p1 = r1->prog;
+//			if(p1->to.type != D_REG)
+//				continue;
+//			if(p1->to.reg != p->reg)
+//			if(!(p1->as == AMOVW && p1->from.type == D_REG && p1->from.reg == p->reg))
+//				continue;
+//
+//			switch(p1->as) {
+//			default:
+//				continue;
+//			case AMOVW:
+//				if(p1->from.type != D_REG)
+//					continue;
+//			case AAND:
+//			case AEOR:
+//			case AORR:
+//			case ABIC:
+//			case AMVN:
+//			case ASUB:
+//			case ARSB:
+//			case AADD:
+//			case AADC:
+//			case ASBC:
+//			case ARSC:
+//				break;
+//			}
+//			p1->scond |= C_SBIT;
+//			r2->prog->as = t;
+//			excise(r);
+//			continue;
+		}
+	}
+
+//	predicate(g);
+
+	flowend(g);
+}
+
+int
+regtyp(Adr *a)
+{
+
+	if(a->type == D_REG)
+		return 1;
+	if(a->type == D_FREG)
+		return 1;
+	return 0;
+}
+
+/*
+ * the idea is to substitute
+ * one register for another
+ * from one MOV to another
+ *	MOV	a, R0
+ *	ADD	b, R0	/ no use of R1
+ *	MOV	R0, R1
+ * would be converted to
+ *	MOV	a, R1
+ *	ADD	b, R1
+ *	MOV	R1, R0
+ * hopefully, then the former or latter MOV
+ * will be eliminated by copy propagation.
+ */
+static int
+subprop(Flow *r0)
+{
+	Prog *p;
+	Adr *v1, *v2;
+	Flow *r;
+	int t;
+	ProgInfo info;
+
+	p = r0->prog;
+	v1 = &p->from;
+	if(!regtyp(v1))
+		return 0;
+	v2 = &p->to;
+	if(!regtyp(v2))
+		return 0;
+	for(r=uniqp(r0); r!=nil; r=uniqp(r)) {
+		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;
+
+		if((info.flags & CanRegRead) && p->to.type == D_REG) {
+			info.flags |= RegRead;
+			info.flags &= ~(CanRegRead | RightRead);
+			p->reg = p->to.reg;
+		}
+
+		switch(p->as) {
+		case AMULLU:
+		case AMULA:
+		case AMVN:
+			return 0;
+		}
+		
+		if((info.flags & (RightRead|RightWrite)) == RightWrite) {
+			if(p->to.type == v1->type)
+			if(p->to.reg == v1->reg)
+			if(p->scond == C_SCOND_NONE)
+				goto gotit;
+		}
+
+		if(copyau(&p->from, v2) ||
+		   copyau1(p, v2) ||
+		   copyau(&p->to, v2))
+			break;
+		if(copysub(&p->from, v1, v2, 0) ||
+		   copysub1(p, v1, v2, 0) ||
+		   copysub(&p->to, v1, v2, 0))
+			break;
+	}
+	return 0;
+
+gotit:
+	copysub(&p->to, v1, v2, 1);
+	if(debug['P']) {
+		print("gotit: %D->%D\n%P", v1, v2, r->prog);
+		if(p->from.type == v2->type)
+			print(" excise");
+		print("\n");
+	}
+	for(r=uniqs(r); r!=r0; r=uniqs(r)) {
+		p = r->prog;
+		copysub(&p->from, v1, v2, 1);
+		copysub1(p, v1, v2, 1);
+		copysub(&p->to, v1, v2, 1);
+		if(debug['P'])
+			print("%P\n", r->prog);
+	}
+	t = v1->reg;
+	v1->reg = v2->reg;
+	v2->reg = t;
+	if(debug['P'])
+		print("%P last\n", r->prog);
+	return 1;
+}
+
+/*
+ * The idea is to remove redundant copies.
+ *	v1->v2	F=0
+ *	(use v2	s/v2/v1/)*
+ *	set v1	F=1
+ *	use v2	return fail
+ *	-----------------
+ *	v1->v2	F=0
+ *	(use v2	s/v2/v1/)*
+ *	set v1	F=1
+ *	set v2	return success
+ */
+static int
+copyprop(Graph *g, Flow *r0)
+{
+	Prog *p;
+	Adr *v1, *v2;
+
+	USED(g);
+	p = r0->prog;
+	v1 = &p->from;
+	v2 = &p->to;
+	if(copyas(v1, v2))
+		return 1;
+	gactive++;
+	return copy1(v1, v2, r0->s1, 0);
+}
+
+static int
+copy1(Adr *v1, Adr *v2, Flow *r, int f)
+{
+	int t;
+	Prog *p;
+
+	if(r->active == gactive) {
+		if(debug['P'])
+			print("act set; return 1\n");
+		return 1;
+	}
+	r->active = gactive;
+	if(debug['P'])
+		print("copy %D->%D f=%d\n", v1, v2, f);
+	for(; r != nil; r = r->s1) {
+		p = r->prog;
+		if(debug['P'])
+			print("%P", p);
+		if(!f && uniqp(r) == nil) {
+			f = 1;
+			if(debug['P'])
+				print("; merge; f=%d", f);
+		}
+		t = copyu(p, v2, nil);
+		switch(t) {
+		case 2:	/* rar, can't split */
+			if(debug['P'])
+				print("; %Drar; return 0\n", v2);
+			return 0;
+
+		case 3:	/* set */
+			if(debug['P'])
+				print("; %Dset; return 1\n", v2);
+			return 1;
+
+		case 1:	/* used, substitute */
+		case 4:	/* use and set */
+			if(f) {
+				if(!debug['P'])
+					return 0;
+				if(t == 4)
+					print("; %Dused+set and f=%d; return 0\n", v2, f);
+				else
+					print("; %Dused and f=%d; return 0\n", v2, f);
+				return 0;
+			}
+			if(copyu(p, v2, v1)) {
+				if(debug['P'])
+					print("; sub fail; return 0\n");
+				return 0;
+			}
+			if(debug['P'])
+				print("; sub%D/%D", v2, v1);
+			if(t == 4) {
+				if(debug['P'])
+					print("; %Dused+set; return 1\n", v2);
+				return 1;
+			}
+			break;
+		}
+		if(!f) {
+			t = copyu(p, v1, nil);
+			if(!f && (t == 2 || t == 3 || t == 4)) {
+				f = 1;
+				if(debug['P'])
+					print("; %Dset and !f; f=%d", v1, f);
+			}
+		}
+		if(debug['P'])
+			print("\n");
+		if(r->s2)
+			if(!copy1(v1, v2, r->s2, f))
+				return 0;
+	}
+	return 1;
+}
+
+// UNUSED
+/*
+ * The idea is to remove redundant constants.
+ *	$c1->v1
+ *	($c1->v2 s/$c1/v1)*
+ *	set v1  return
+ * The v1->v2 should be eliminated by copy propagation.
+ */
+void
+constprop(Adr *c1, Adr *v1, Flow *r)
+{
+	Prog *p;
+
+	if(debug['P'])
+		print("constprop %D->%D\n", c1, v1);
+	for(; r != nil; r = r->s1) {
+		p = r->prog;
+		if(debug['P'])
+			print("%P", p);
+		if(uniqp(r) == nil) {
+			if(debug['P'])
+				print("; merge; return\n");
+			return;
+		}
+		if(p->as == AMOVW && copyas(&p->from, c1)) {
+				if(debug['P'])
+					print("; sub%D/%D", &p->from, v1);
+				p->from = *v1;
+		} else if(copyu(p, v1, nil) > 1) {
+			if(debug['P'])
+				print("; %Dset; return\n", v1);
+			return;
+		}
+		if(debug['P'])
+			print("\n");
+		if(r->s2)
+			constprop(c1, v1, r->s2);
+	}
+}
+
+/*
+ * shortprop eliminates redundant zero/sign extensions.
+ *
+ *   MOVBS x, R
+ *   <no use R>
+ *   MOVBS R, R'
+ *
+ * changed to
+ *
+ *   MOVBS x, R
+ *   ...
+ *   MOVB  R, R' (compiled to mov)
+ *
+ * MOVBS above can be a MOVBS, MOVBU, MOVHS or MOVHU.
+ */
+static int
+shortprop(Flow *r)
+{
+	Prog *p, *p1;
+	Flow *r1;
+
+	p = r->prog;
+	r1 = findpre(r, &p->from);
+	if(r1 == nil)
+		return 0;
+
+	p1 = r1->prog;
+	if(p1->as == p->as) {
+		// Two consecutive extensions.
+		goto gotit;
+	}
+
+	if(p1->as == AMOVW && isdconst(&p1->from)
+	   && p1->from.offset >= 0 && p1->from.offset < 128) {
+		// Loaded an immediate.
+		goto gotit;
+	}
+
+	return 0;
+
+gotit:
+	if(debug['P'])
+		print("shortprop\n%P\n%P", p1, p);
+	switch(p->as) {
+	case AMOVBS:
+	case AMOVBU:
+		p->as = AMOVB;
+		break;
+	case AMOVHS:
+	case AMOVHU:
+		p->as = AMOVH;
+		break;
+	}
+	if(debug['P'])
+		print(" => %A\n", p->as);
+	return 1;
+}
+
+// UNUSED
+/*
+ * ASLL x,y,w
+ * .. (not use w, not set x y w)
+ * AXXX w,a,b (a != w)
+ * .. (not use w)
+ * (set w)
+ * ----------- changed to
+ * ..
+ * AXXX (x<<y),a,b
+ * ..
+ */
+#define FAIL(msg) { if(debug['P']) print("\t%s; FAILURE\n", msg); return 0; }
+/*c2go void FAIL(char*); */
+
+int
+shiftprop(Flow *r)
+{
+	Flow *r1;
+	Prog *p, *p1, *p2;
+	int n, o;
+	Adr a;
+
+	p = r->prog;
+	if(p->to.type != D_REG)
+		FAIL("BOTCH: result not reg");
+	n = p->to.reg;
+	a = zprog.from;
+	if(p->reg != NREG && p->reg != p->to.reg) {
+		a.type = D_REG;
+		a.reg = p->reg;
+	}
+	if(debug['P'])
+		print("shiftprop\n%P", p);
+	r1 = r;
+	for(;;) {
+		/* find first use of shift result; abort if shift operands or result are changed */
+		r1 = uniqs(r1);
+		if(r1 == nil)
+			FAIL("branch");
+		if(uniqp(r1) == nil)
+			FAIL("merge");
+		p1 = r1->prog;
+		if(debug['P'])
+			print("\n%P", p1);
+		switch(copyu(p1, &p->to, nil)) {
+		case 0:	/* not used or set */
+			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 */
+			FAIL("BOTCH: noref");
+		}
+		break;
+	}
+	/* check whether substitution can be done */
+	switch(p1->as) {
+	default:
+		FAIL("non-dpi");
+	case AAND:
+	case AEOR:
+	case AADD:
+	case AADC:
+	case AORR:
+	case ASUB:
+	case ASBC:
+	case ARSB:
+	case ARSC:
+		if(p1->reg == n || (p1->reg == NREG && p1->to.type == D_REG && p1->to.reg == n)) {
+			if(p1->from.type != D_REG)
+				FAIL("can't swap");
+			p1->reg = p1->from.reg;
+			p1->from.reg = n;
+			switch(p1->as) {
+			case ASUB:
+				p1->as = ARSB;
+				break;
+			case ARSB:
+				p1->as = ASUB;
+				break;
+			case ASBC:
+				p1->as = ARSC;
+				break;
+			case ARSC:
+				p1->as = ASBC;
+				break;
+			}
+			if(debug['P'])
+				print("\t=>%P", p1);
+		}
+	case ABIC:
+	case ATST:
+	case ACMP:
+	case ACMN:
+		if(p1->reg == n)
+			FAIL("can't swap");
+		if(p1->reg == NREG && p1->to.reg == n)
+			FAIL("shift result used twice");
+//	case AMVN:
+		if(p1->from.type == D_SHIFT)
+			FAIL("shift result used in shift");
+		if(p1->from.type != D_REG || p1->from.reg != n)
+			FAIL("BOTCH: where is it used?");
+		break;
+	}
+	/* check whether shift result is used subsequently */
+	p2 = p1;
+	if(p1->to.reg != n)
+	for (;;) {
+		r1 = uniqs(r1);
+		if(r1 == nil)
+			FAIL("inconclusive");
+		p1 = r1->prog;
+		if(debug['P'])
+			print("\n%P", p1);
+		switch(copyu(p1, &p->to, nil)) {
+		case 0:	/* not used or set */
+			continue;
+		case 3: /* set, not used */
+			break;
+		default:/* used */
+			FAIL("reused");
+		}
+		break;
+	}
+
+	/* make the substitution */
+	p2->from.type = D_SHIFT;
+	p2->from.reg = NREG;
+	o = p->reg;
+	if(o == NREG)
+		o = p->to.reg;
+
+	switch(p->from.type){
+	case D_CONST:
+		o |= (p->from.offset&0x1f)<<7;
+		break;
+	case D_REG:
+		o |= (1<<4) | (p->from.reg<<8);
+		break;
+	}
+	switch(p->as){
+	case ASLL:
+		o |= 0<<5;
+		break;
+	case ASRL:
+		o |= 1<<5;
+		break;
+	case ASRA:
+		o |= 2<<5;
+		break;
+	}
+	p2->from.offset = o;
+	if(debug['P'])
+		print("\t=>%P\tSUCCEED\n", p2);
+	return 1;
+}
+
+/*
+ * findpre returns the last instruction mentioning v
+ * before r. It must be a set, and there must be
+ * a unique path from that instruction to r.
+ */
+static Flow*
+findpre(Flow *r, Adr *v)
+{
+	Flow *r1;
+
+	for(r1=uniqp(r); r1!=nil; r=r1,r1=uniqp(r)) {
+		if(uniqs(r1) != r)
+			return nil;
+		switch(copyu(r1->prog, v, nil)) {
+		case 1: /* used */
+		case 2: /* read-alter-rewrite */
+			return nil;
+		case 3: /* set */
+		case 4: /* set and used */
+			return r1;
+		}
+	}
+	return nil;
+}
+
+/*
+ * findinc finds ADD instructions with a constant
+ * argument which falls within the immed_12 range.
+ */
+static Flow*
+findinc(Flow *r, Flow *r2, Adr *v)
+{
+	Flow *r1;
+	Prog *p;
+
+
+	for(r1=uniqs(r); r1!=nil && r1!=r2; r=r1,r1=uniqs(r)) {
+		if(uniqp(r1) != r)
+			return nil;
+		switch(copyu(r1->prog, v, nil)) {
+		case 0: /* not touched */
+			continue;
+		case 4: /* set and used */
+			p = r1->prog;
+			if(p->as == AADD)
+			if(isdconst(&p->from))
+			if(p->from.offset > -4096 && p->from.offset < 4096)
+				return r1;
+		default:
+			return nil;
+		}
+	}
+	return nil;
+}
+
+static int
+nochange(Flow *r, Flow *r2, Prog *p)
+{
+	Adr a[3];
+	int i, n;
+
+	if(r == r2)
+		return 1;
+	n = 0;
+	if(p->reg != NREG && p->reg != p->to.reg) {
+		a[n].type = D_REG;
+		a[n++].reg = p->reg;
+	}
+	switch(p->from.type) {
+	case D_SHIFT:
+		a[n].type = D_REG;
+		a[n++].reg = p->from.offset&0xf;
+	case D_REG:
+		a[n].type = D_REG;
+		a[n++].reg = p->from.reg;
+	}
+	if(n == 0)
+		return 1;
+	for(; r!=nil && r!=r2; r=uniqs(r)) {
+		p = r->prog;
+		for(i=0; i<n; i++)
+			if(copyu(p, &a[i], nil) > 1)
+				return 0;
+	}
+	return 1;
+}
+
+static int
+findu1(Flow *r, Adr *v)
+{
+	for(; r != nil; r = r->s1) {
+		if(r->active)
+			return 0;
+		r->active = 1;
+		switch(copyu(r->prog, v, nil)) {
+		case 1: /* used */
+		case 2: /* read-alter-rewrite */
+		case 4: /* set and used */
+			return 1;
+		case 3: /* set */
+			return 0;
+		}
+		if(r->s2)
+			if (findu1(r->s2, v))
+				return 1;
+	}
+	return 0;
+}
+
+static int
+finduse(Graph *g, Flow *r, Adr *v)
+{
+	Flow *r1;
+
+	for(r1=g->start; r1!=nil; r1=r1->link)
+		r1->active = 0;
+	return findu1(r, v);
+}
+
+/*
+ * xtramodes enables the ARM post increment and
+ * shift offset addressing modes to transform
+ *   MOVW   0(R3),R1
+ *   ADD    $4,R3,R3
+ * into
+ *   MOVW.P 4(R3),R1
+ * and 
+ *   ADD    R0,R1
+ *   MOVBU  0(R1),R0
+ * into 
+ *   MOVBU  R0<<0(R1),R0
+ */
+static int
+xtramodes(Graph *g, Flow *r, Adr *a)
+{
+	Flow *r1, *r2, *r3;
+	Prog *p, *p1;
+	Adr v;
+
+	p = r->prog;
+	v = *a;
+	v.type = D_REG;
+	r1 = findpre(r, &v);
+	if(r1 != nil) {
+		p1 = r1->prog;
+		if(p1->to.type == D_REG && p1->to.reg == v.reg)
+		switch(p1->as) {
+		case AADD:
+			if(p1->scond & C_SBIT)
+				// avoid altering ADD.S/ADC sequences.
+				break;
+			if(p1->from.type == D_REG ||
+			   (p1->from.type == D_SHIFT && (p1->from.offset&(1<<4)) == 0 &&
+			    ((p->as != AMOVB && p->as != AMOVBS) || (a == &p->from && (p1->from.offset&~0xf) == 0))) ||
+			   (p1->from.type == D_CONST &&
+			    p1->from.offset > -4096 && p1->from.offset < 4096))
+			if(nochange(uniqs(r1), r, p1)) {
+				if(a != &p->from || v.reg != p->to.reg)
+				if (finduse(g, r->s1, &v)) {
+					if(p1->reg == NREG || p1->reg == v.reg)
+						/* pre-indexing */
+						p->scond |= C_WBIT;
+					else return 0;
+				}
+				switch (p1->from.type) {
+				case D_REG:
+					/* register offset */
+					if(nacl)
+						return 0;
+					a->type = D_SHIFT;
+					a->offset = p1->from.reg;
+					break;
+				case D_SHIFT:
+					/* scaled register offset */
+					if(nacl)
+						return 0;
+					a->type = D_SHIFT;
+				case D_CONST:
+					/* immediate offset */
+					a->offset = p1->from.offset;
+					break;
+				}
+				if(p1->reg != NREG)
+					a->reg = p1->reg;
+				excise(r1);
+				return 1;
+			}
+			break;
+		case AMOVW:
+			if(p1->from.type == D_REG)
+			if((r2 = findinc(r1, r, &p1->from)) != nil) {
+			for(r3=uniqs(r2); r3->prog->as==ANOP; r3=uniqs(r3))
+				;
+			if(r3 == r) {
+				/* post-indexing */
+				p1 = r2->prog;
+				a->reg = p1->to.reg;
+				a->offset = p1->from.offset;
+				p->scond |= C_PBIT;
+				if(!finduse(g, r, &r1->prog->to))
+					excise(r1);
+				excise(r2);
+				return 1;
+			}
+			}
+			break;
+		}
+	}
+	if(a != &p->from || a->reg != p->to.reg)
+	if((r1 = findinc(r, nil, &v)) != nil) {
+		/* post-indexing */
+		p1 = r1->prog;
+		a->offset = p1->from.offset;
+		p->scond |= C_PBIT;
+		excise(r1);
+		return 1;
+	}
+	return 0;
+}
+
+/*
+ * return
+ * 1 if v only used (and substitute),
+ * 2 if read-alter-rewrite
+ * 3 if set
+ * 4 if set and used
+ * 0 otherwise (not touched)
+ */
+int
+copyu(Prog *p, Adr *v, Adr *s)
+{
+	switch(p->as) {
+
+	default:
+		print("copyu: can't find %A\n", p->as);
+		return 2;
+
+	case AMOVM:
+		if(v->type != D_REG)
+			return 0;
+		if(p->from.type == D_CONST) {	/* read reglist, read/rar */
+			if(s != nil) {
+				if(p->from.offset&(1<<v->reg))
+					return 1;
+				if(copysub(&p->to, v, s, 1))
+					return 1;
+				return 0;
+			}
+			if(copyau(&p->to, v)) {
+				if(p->scond&C_WBIT)
+					return 2;
+				return 1;
+			}
+			if(p->from.offset&(1<<v->reg))
+				return 1;
+		} else {			/* read/rar, write reglist */
+			if(s != nil) {
+				if(p->to.offset&(1<<v->reg))
+					return 1;
+				if(copysub(&p->from, v, s, 1))
+					return 1;
+				return 0;
+			}
+			if(copyau(&p->from, v)) {
+				if(p->scond&C_WBIT)
+					return 2;
+				if(p->to.offset&(1<<v->reg))
+					return 4;
+				return 1;
+			}
+			if(p->to.offset&(1<<v->reg))
+				return 3;
+		}
+		return 0;
+
+	case ANOP:	/* read,, write */
+	case AMOVW:
+	case AMOVF:
+	case AMOVD:
+	case AMOVH:
+	case AMOVHS:
+	case AMOVHU:
+	case AMOVB:
+	case AMOVBS:
+	case AMOVBU:
+	case AMOVFW:
+	case AMOVWF:
+	case AMOVDW:
+	case AMOVWD:
+	case AMOVFD:
+	case AMOVDF:
+		if(p->scond&(C_WBIT|C_PBIT))
+		if(v->type == D_REG) {
+			if(p->from.type == D_OREG || p->from.type == D_SHIFT) {
+				if(p->from.reg == v->reg)
+					return 2;
+			} else {
+		  		if(p->to.reg == v->reg)
+					return 2;
+			}
+		}
+		if(s != nil) {
+			if(copysub(&p->from, v, s, 1))
+				return 1;
+			if(!copyas(&p->to, v))
+				if(copysub(&p->to, v, s, 1))
+					return 1;
+			return 0;
+		}
+		if(copyas(&p->to, v)) {
+			if(p->scond != C_SCOND_NONE)
+				return 2;
+			if(copyau(&p->from, v))
+				return 4;
+			return 3;
+		}
+		if(copyau(&p->from, v))
+			return 1;
+		if(copyau(&p->to, v))
+			return 1;
+		return 0;
+
+	case AMULLU:	/* read, read, write, write */
+	case AMULL:
+	case AMULA:
+	case AMVN:
+		return 2;
+
+	case AADD:	/* read, read, write */
+	case AADC:
+	case ASUB:
+	case ASBC:
+	case ARSB:
+	case ASLL:
+	case ASRL:
+	case ASRA:
+	case AORR:
+	case AAND:
+	case AEOR:
+	case AMUL:
+	case AMULU:
+	case ADIV:
+	case ADIVU:
+	case AMOD:
+	case AMODU:
+	case AADDF:
+	case AADDD:
+	case ASUBF:
+	case ASUBD:
+	case AMULF:
+	case AMULD:
+	case ADIVF:
+	case ADIVD:
+
+	case ACHECKNIL: /* read */
+	case ACMPF:	/* read, read, */
+	case ACMPD:
+	case ACMP:
+	case ACMN:
+	case ACASE:
+	case ATST:	/* read,, */
+		if(s != nil) {
+			if(copysub(&p->from, v, s, 1))
+				return 1;
+			if(copysub1(p, v, s, 1))
+				return 1;
+			if(!copyas(&p->to, v))
+				if(copysub(&p->to, v, s, 1))
+					return 1;
+			return 0;
+		}
+		if(copyas(&p->to, v)) {
+			if(p->scond != C_SCOND_NONE)
+				return 2;
+			if(p->reg == NREG)
+				p->reg = p->to.reg;
+			if(copyau(&p->from, v))
+				return 4;
+			if(copyau1(p, v))
+				return 4;
+			return 3;
+		}
+		if(copyau(&p->from, v))
+			return 1;
+		if(copyau1(p, v))
+			return 1;
+		if(copyau(&p->to, v))
+			return 1;
+		return 0;
+
+	case ABEQ:	/* read, read */
+	case ABNE:
+	case ABCS:
+	case ABHS:
+	case ABCC:
+	case ABLO:
+	case ABMI:
+	case ABPL:
+	case ABVS:
+	case ABVC:
+	case ABHI:
+	case ABLS:
+	case ABGE:
+	case ABLT:
+	case ABGT:
+	case ABLE:
+		if(s != nil) {
+			if(copysub(&p->from, v, s, 1))
+				return 1;
+			return copysub1(p, v, s, 1);
+		}
+		if(copyau(&p->from, v))
+			return 1;
+		if(copyau1(p, v))
+			return 1;
+		return 0;
+
+	case AB:	/* funny */
+		if(s != nil) {
+			if(copysub(&p->to, v, s, 1))
+				return 1;
+			return 0;
+		}
+		if(copyau(&p->to, v))
+			return 1;
+		return 0;
+
+	case ARET:	/* funny */
+		if(s != nil)
+			return 1;
+		return 3;
+
+	case ABL:	/* funny */
+		if(v->type == D_REG) {
+			if(v->reg <= REGEXT && v->reg > exregoffset)
+				return 2;
+			if(v->reg == REGARG)
+				return 2;
+		}
+		if(v->type == D_FREG)
+			if(v->reg <= FREGEXT && v->reg > exfregoffset)
+				return 2;
+		if(p->from.type == D_REG && v->type == D_REG && p->from.reg == v->reg)
+			return 2;
+
+		if(s != nil) {
+			if(copysub(&p->to, v, s, 1))
+				return 1;
+			return 0;
+		}
+		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 == REGARG)
+				return 3;
+		return 0;
+
+	case APCDATA:
+	case AFUNCDATA:
+	case AVARDEF:
+	case AVARKILL:
+		return 0;
+	}
+}
+
+/*
+ * direct reference,
+ * could be set/use depending on
+ * semantics
+ */
+static int
+copyas(Adr *a, Adr *v)
+{
+
+	if(regtyp(v)) {
+		if(a->type == v->type)
+		if(a->reg == v->reg)
+			return 1;
+	} else
+	if(v->type == D_CONST) {		/* for constprop */
+		if(a->type == v->type)
+		if(a->name == v->name)
+		if(a->sym == v->sym)
+		if(a->reg == v->reg)
+		if(a->offset == v->offset)
+			return 1;
+	}
+	return 0;
+}
+
+int
+sameaddr(Adr *a, Adr *v)
+{
+	if(a->type != v->type)
+		return 0;
+	if(regtyp(v) && a->reg == v->reg)
+		return 1;
+	if(v->type == D_AUTO || v->type == D_PARAM) {
+		if(v->offset == a->offset)
+			return 1;
+	}
+	return 0;
+}
+
+/*
+ * either direct or indirect
+ */
+static int
+copyau(Adr *a, Adr *v)
+{
+
+	if(copyas(a, v))
+		return 1;
+	if(v->type == D_REG) {
+		if(a->type == D_CONST && a->reg != NREG) {
+			if(a->reg == v->reg)
+				return 1;
+		} else
+		if(a->type == D_OREG) {
+			if(a->reg == v->reg)
+				return 1;
+		} else
+		if(a->type == D_REGREG || a->type == D_REGREG2) {
+			if(a->reg == v->reg)
+				return 1;
+			if(a->offset == v->reg)
+				return 1;
+		} else
+		if(a->type == D_SHIFT) {
+			if((a->offset&0xf) == v->reg)
+				return 1;
+			if((a->offset&(1<<4)) && (a->offset>>8) == v->reg)
+				return 1;
+		}
+	}
+	return 0;
+}
+
+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)
+ */
+static int
+copyau1(Prog *p, Adr *v)
+{
+	if(v->type == D_REG && v->reg == NREG)
+		return 0;
+	return p->reg == v->reg && a2type(p) == v->type;
+}
+
+/*
+ * substitute s for v in a
+ * return failure to substitute
+ */
+static int
+copysub(Adr *a, Adr *v, Adr *s, int f)
+{
+
+	if(f)
+	if(copyau(a, v)) {
+		if(a->type == D_SHIFT) {
+			if((a->offset&0xf) == v->reg)
+				a->offset = (a->offset&~0xf)|s->reg;
+			if((a->offset&(1<<4)) && (a->offset>>8) == v->reg)
+				a->offset = (a->offset&~(0xf<<8))|(s->reg<<8);
+		} else
+		if(a->type == D_REGREG || a->type == D_REGREG2) {
+			if(a->offset == v->reg)
+				a->offset = s->reg;
+			if(a->reg == v->reg)
+				a->reg = s->reg;
+		} else
+			a->reg = s->reg;
+	}
+	return 0;
+}
+
+static int
+copysub1(Prog *p1, Adr *v, Adr *s, int f)
+{
+
+	if(f)
+	if(copyau1(p1, v))
+		p1->reg = s->reg;
+	return 0;
+}
+
+struct {
+	int opcode;
+	int notopcode;
+	int scond;
+	int notscond;
+} predinfo[]  = {
+	{ ABEQ,	ABNE,	0x0,	0x1, },
+	{ ABNE,	ABEQ,	0x1,	0x0, },
+	{ ABCS,	ABCC,	0x2,	0x3, },
+	{ ABHS,	ABLO,	0x2,	0x3, },
+	{ ABCC,	ABCS,	0x3,	0x2, },
+	{ ABLO,	ABHS,	0x3,	0x2, },
+	{ ABMI,	ABPL,	0x4,	0x5, },
+	{ ABPL,	ABMI,	0x5,	0x4, },
+	{ ABVS,	ABVC,	0x6,	0x7, },
+	{ ABVC,	ABVS,	0x7,	0x6, },
+	{ ABHI,	ABLS,	0x8,	0x9, },
+	{ ABLS,	ABHI,	0x9,	0x8, },
+	{ ABGE,	ABLT,	0xA,	0xB, },
+	{ ABLT,	ABGE,	0xB,	0xA, },
+	{ ABGT,	ABLE,	0xC,	0xD, },
+	{ ABLE,	ABGT,	0xD,	0xC, },
+};
+
+typedef struct {
+	Flow *start;
+	Flow *last;
+	Flow *end;
+	int len;
+} Joininfo;
+
+enum {
+	Join,
+	Split,
+	End,
+	Branch,
+	Setcond,
+	Toolong
+};
+
+enum {
+	Falsecond,
+	Truecond,
+	Delbranch,
+	Keepbranch
+};
+
+static int
+isbranch(Prog *p)
+{
+	return (ABEQ <= p->as) && (p->as <= ABLE);
+}
+
+static int
+predicable(Prog *p)
+{
+	switch(p->as) {
+	case ANOP:
+	case AXXX:
+	case ADATA:
+	case AGLOBL:
+	case AGOK:
+	case AHISTORY:
+	case ANAME:
+	case ASIGNAME:
+	case ATEXT:
+	case AWORD:
+	case ABCASE:
+	case ACASE:
+		return 0;
+	}
+	if(isbranch(p))
+		return 0;
+	return 1;
+}
+
+/*
+ * Depends on an analysis of the encodings performed by 5l.
+ * These seem to be all of the opcodes that lead to the "S" bit
+ * being set in the instruction encodings.
+ *
+ * C_SBIT may also have been set explicitly in p->scond.
+ */
+static int
+modifiescpsr(Prog *p)
+{
+	switch(p->as) {
+	case AMULLU:
+	case AMULA:
+	case AMULU:
+	case ADIVU:
+
+	case ATEQ:
+	case ACMN:
+	case ATST:
+	case ACMP:
+	case AMUL:
+	case ADIV:
+	case AMOD:
+	case AMODU:
+	case ABL:
+		return 1;
+	}
+	if(p->scond & C_SBIT)
+		return 1;
+	return 0;
+}
+
+/*
+ * Find the maximal chain of instructions starting with r which could
+ * be executed conditionally
+ */
+static int
+joinsplit(Flow *r, Joininfo *j)
+{
+	j->start = r;
+	j->last = r;
+	j->len = 0;
+	do {
+		if (r->p2 && (r->p1 || r->p2->p2link)) {
+			j->end = r;
+			return Join;
+		}
+		if (r->s1 && r->s2) {
+			j->end = r;
+			return Split;
+		}
+		j->last = r;
+		if (r->prog->as != ANOP)
+			j->len++;
+		if (!r->s1 && !r->s2) {
+			j->end = r->link;
+			return End;
+		}
+		if (r->s2) {
+			j->end = r->s2;
+			return Branch;
+		}
+		if (modifiescpsr(r->prog)) {
+			j->end = r->s1;
+			return Setcond;
+		}
+		r = r->s1;
+	} while (j->len < 4);
+	j->end = r;
+	return Toolong;
+}
+
+static Flow*
+successor(Flow *r)
+{
+	if(r->s1)
+		return r->s1;
+	else
+		return r->s2;
+}
+
+static void
+applypred(Flow *rstart, Joininfo *j, int cond, int branch)
+{
+	int pred;
+	Flow *r;
+
+	if(j->len == 0)
+		return;
+	if(cond == Truecond)
+		pred = predinfo[rstart->prog->as - ABEQ].scond;
+	else
+		pred = predinfo[rstart->prog->as - ABEQ].notscond;
+
+	for(r = j->start;; r = successor(r)) {
+		if(r->prog->as == AB) {
+			if(r != j->last || branch == Delbranch)
+				excise(r);
+			else {
+				if(cond == Truecond)
+					r->prog->as = predinfo[rstart->prog->as - ABEQ].opcode;
+				else
+					r->prog->as = predinfo[rstart->prog->as - ABEQ].notopcode;
+			}
+		}
+		else
+		if(predicable(r->prog))
+			r->prog->scond = (r->prog->scond&~C_SCOND)|pred;
+		if(r->s1 != r->link) {
+			r->s1 = r->link;
+			r->link->p1 = r;
+		}
+		if(r == j->last)
+			break;
+	}
+}
+
+void
+predicate(Graph *g)
+{
+	Flow *r;
+	int t1, t2;
+	Joininfo j1, j2;
+
+	for(r=g->start; r!=nil; r=r->link) {
+		if (isbranch(r->prog)) {
+			t1 = joinsplit(r->s1, &j1);
+			t2 = joinsplit(r->s2, &j2);
+			if(j1.last->link != j2.start)
+				continue;
+			if(j1.end == j2.end)
+			if((t1 == Branch && (t2 == Join || t2 == Setcond)) ||
+			   (t2 == Join && (t1 == Join || t1 == Setcond))) {
+				applypred(r, &j1, Falsecond, Delbranch);
+				applypred(r, &j2, Truecond, Delbranch);
+				excise(r);
+				continue;
+			}
+			if(t1 == End || t1 == Branch) {
+				applypred(r, &j1, Falsecond, Keepbranch);
+				excise(r);
+				continue;
+			}
+		}
+	}
+}
+
+static int
+isdconst(Addr *a)
+{
+	if(a->type == D_CONST && a->reg == NREG)
+		return 1;
+	return 0;
+}
+
+int
+stackaddr(Addr *a)
+{
+	return regtyp(a) && a->reg == REGSP;
+}
+
+int
+smallindir(Addr *a, Addr *reg)
+{
+	return reg->type == D_REG && a->type == D_OREG &&
+		a->reg == reg->reg &&
+		0 <= a->offset && a->offset < 4096;
+}
diff --git a/src/cmd/5g/prog.c b/src/cmd/5g/prog.c
new file mode 100644
index 0000000..797bc07
--- /dev/null
+++ b/src/cmd/5g/prog.c
@@ -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.
+
+#include <u.h>
+#include <libc.h>
+#include "gg.h"
+#include "opt.h"
+
+enum
+{
+	RightRdwr = RightRead | RightWrite,
+};
+
+// This table gives the basic information about instruction
+// generated by the compiler and processed in the optimizer.
+// See opt.h for bit definitions.
+//
+// Instructions not generated need not be listed.
+// As an exception to that rule, we typically write down all the
+// size variants of an operation even if we just use a subset.
+//
+// The table is formatted for 8-space tabs.
+static ProgInfo progtable[ALAST] = {
+	[ATYPE]=	{Pseudo | Skip},
+	[ATEXT]=	{Pseudo},
+	[AFUNCDATA]=	{Pseudo},
+	[APCDATA]=	{Pseudo},
+	[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.
+	[ANOP]=		{LeftRead | RightWrite},
+	
+	// Integer.
+	[AADC]=		{SizeL | LeftRead | RegRead | RightWrite},
+	[AADD]=		{SizeL | LeftRead | RegRead | RightWrite},
+	[AAND]=		{SizeL | LeftRead | RegRead | RightWrite},
+	[ABIC]=		{SizeL | LeftRead | RegRead | RightWrite},
+	[ACMN]=		{SizeL | LeftRead | RightRead},
+	[ACMP]=		{SizeL | LeftRead | RightRead},
+	[ADIVU]=	{SizeL | LeftRead | RegRead | RightWrite},
+	[ADIV]=		{SizeL | LeftRead | RegRead | RightWrite},
+	[AEOR]=		{SizeL | LeftRead | RegRead | RightWrite},
+	[AMODU]=	{SizeL | LeftRead | RegRead | RightWrite},
+	[AMOD]=		{SizeL | LeftRead | RegRead | RightWrite},
+	[AMULALU]=	{SizeL | LeftRead | RegRead | RightRdwr},
+	[AMULAL]=	{SizeL | LeftRead | RegRead | RightRdwr},
+	[AMULA]=	{SizeL | LeftRead | RegRead | RightRdwr},
+	[AMULU]=	{SizeL | LeftRead | RegRead | RightWrite},
+	[AMUL]=		{SizeL | LeftRead | RegRead | RightWrite},
+	[AMULL]=	{SizeL | LeftRead | RegRead | RightWrite},
+	[AMULLU]=	{SizeL | LeftRead | RegRead | RightWrite},
+	[AMVN]=		{SizeL | LeftRead | RightWrite},
+	[AORR]=		{SizeL | LeftRead | RegRead | RightWrite},
+	[ARSB]=		{SizeL | LeftRead | RegRead | RightWrite},
+	[ARSC]=		{SizeL | LeftRead | RegRead | RightWrite},
+	[ASBC]=		{SizeL | LeftRead | RegRead | RightWrite},
+	[ASLL]=		{SizeL | LeftRead | RegRead | RightWrite},
+	[ASRA]=		{SizeL | LeftRead | RegRead | RightWrite},
+	[ASRL]=		{SizeL | LeftRead | RegRead | RightWrite},
+	[ASUB]=		{SizeL | LeftRead | RegRead | RightWrite},
+	[ATEQ]=		{SizeL | LeftRead | RightRead},
+	[ATST]=		{SizeL | LeftRead | RightRead},
+
+	// Floating point.
+	[AADDD]=	{SizeD | LeftRead | RightRdwr},
+	[AADDF]=	{SizeF | LeftRead | RightRdwr},
+	[ACMPD]=	{SizeD | LeftRead | RightRead},
+	[ACMPF]=	{SizeF | LeftRead | RightRead},
+	[ADIVD]=	{SizeD | LeftRead | RightRdwr},
+	[ADIVF]=	{SizeF | LeftRead | RightRdwr},
+	[AMULD]=	{SizeD | LeftRead | RightRdwr},
+	[AMULF]=	{SizeF | LeftRead | RightRdwr},
+	[ASUBD]=	{SizeD | LeftRead | RightRdwr},
+	[ASUBF]=	{SizeF | LeftRead | RightRdwr},
+
+	// Conversions.
+	[AMOVWD]=		{SizeD | LeftRead | RightWrite | Conv},
+	[AMOVWF]=		{SizeF | LeftRead | RightWrite | Conv},
+	[AMOVDF]=		{SizeF | LeftRead | RightWrite | Conv},
+	[AMOVDW]=		{SizeL | LeftRead | RightWrite | Conv},
+	[AMOVFD]=		{SizeD | LeftRead | RightWrite | Conv},
+	[AMOVFW]=		{SizeL | LeftRead | RightWrite | Conv},
+
+	// Moves.
+	[AMOVB]=		{SizeB | LeftRead | RightWrite | Move},
+	[AMOVD]=		{SizeD | LeftRead | RightWrite | Move},
+	[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.
+	[AMOVBS]=		{SizeB | LeftRead | RightWrite | Conv},
+	[AMOVBU]=		{SizeB | LeftRead | RightWrite | Conv},
+	[AMOVHS]=		{SizeW | LeftRead | RightWrite | Conv},
+	[AMOVHU]=		{SizeW | LeftRead | RightWrite | Conv},
+	
+	// Jumps.
+	[AB]=		{Jump | Break},
+	[ABL]=		{Call},
+	[ABEQ]=		{Cjmp},
+	[ABNE]=		{Cjmp},
+	[ABCS]=		{Cjmp},
+	[ABHS]=		{Cjmp},
+	[ABCC]=		{Cjmp},
+	[ABLO]=		{Cjmp},
+	[ABMI]=		{Cjmp},
+	[ABPL]=		{Cjmp},
+	[ABVS]=		{Cjmp},
+	[ABVC]=		{Cjmp},
+	[ABHI]=		{Cjmp},
+	[ABLS]=		{Cjmp},
+	[ABGE]=		{Cjmp},
+	[ABLT]=		{Cjmp},
+	[ABGT]=		{Cjmp},
+	[ABLE]=		{Cjmp},
+	[ARET]=		{Break},
+};
+
+void
+proginfo(ProgInfo *info, Prog *p)
+{
+	*info = progtable[p->as];
+	if(info->flags == 0)
+		fatal("unknown instruction %P", p);
+
+	if(p->from.type == D_CONST && p->from.sym != nil && (info->flags & LeftRead)) {
+		info->flags &= ~LeftRead;
+		info->flags |= LeftAddr;
+	}
+
+	if((info->flags & RegRead) && p->reg == NREG) {
+		info->flags &= ~RegRead;
+		info->flags |= CanRegRead | RightRead;
+	}
+	
+	if(((p->scond & C_SCOND) != C_SCOND_NONE) && (info->flags & RightWrite))
+		info->flags |= RightRead;
+}
diff --git a/src/cmd/5g/reg.c b/src/cmd/5g/reg.c
new file mode 100644
index 0000000..b78c268
--- /dev/null
+++ b/src/cmd/5g/reg.c
@@ -0,0 +1,1453 @@
+// Inferno utils/5c/reg.c
+// http://code.google.com/p/inferno-os/source/browse/utils/5c/reg.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"
+#include "opt.h"
+
+#define	NREGVAR	32
+#define	REGBITS	((uint32)0xffffffff)
+/*c2go enum {
+	NREGVAR = 32,
+	REGBITS = 0xffffffff,
+};
+*/
+
+	void	addsplits(void);
+static	Reg*	firstr;
+static	int	first	= 1;
+
+int
+rcmp(const void *a1, const void *a2)
+{
+	Rgn *p1, *p2;
+	int c1, c2;
+
+	p1 = (Rgn*)a1;
+	p2 = (Rgn*)a2;
+	c1 = p2->cost;
+	c2 = p1->cost;
+	if(c1 -= c2)
+		return c1;
+	return p2->varno - p1->varno;
+}
+
+void
+excise(Flow *r)
+{
+	Prog *p;
+
+	p = r->prog;
+	p->as = ANOP;
+	p->scond = zprog.scond;
+	p->from = zprog.from;
+	p->to = zprog.to;
+	p->reg = zprog.reg;
+}
+
+static void
+setaddrs(Bits bit)
+{
+	int i, n;
+	Var *v;
+	Node *node;
+
+	while(bany(&bit)) {
+		// convert each bit to a variable
+		i = bnum(bit);
+		node = var[i].node;
+		n = var[i].name;
+		bit.b[i/32] &= ~(1L<<(i%32));
+
+		// disable all pieces of that variable
+		for(i=0; i<nvar; i++) {
+			v = var+i;
+			if(v->node == node && v->name == n)
+				v->addr = 2;
+		}
+	}
+}
+
+static char* regname[] = {
+	".R0",
+	".R1",
+	".R2",
+	".R3",
+	".R4",
+	".R5",
+	".R6",
+	".R7",
+	".R8",
+	".R9",
+	".R10",
+	".R11",
+	".R12",
+	".R13",
+	".R14",
+	".R15",
+	".F0",
+	".F1",
+	".F2",
+	".F3",
+	".F4",
+	".F5",
+	".F6",
+	".F7",
+	".F8",
+	".F9",
+	".F10",
+	".F11",
+	".F12",
+	".F13",
+	".F14",
+	".F15",
+};
+
+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, active;
+	uint32 vreg;
+	Bits bit;
+	ProgInfo info;
+
+	if(first) {
+		fmtinstall('Q', Qconv);
+		first = 0;
+	}
+
+	mergetemp(firstp);
+
+	/*
+	 * control flow is more complicated in generated go code
+	 * than in generated c code.  define pseudo-variables for
+	 * registers, so we have complete register usage information.
+	 */
+	nvar = NREGVAR;
+	memset(var, 0, NREGVAR*sizeof var[0]);
+	for(i=0; i<NREGVAR; i++) {
+		if(regnodes[i] == N)
+			regnodes[i] = newname(lookup(regname[i]));
+		var[i].node = regnodes[i];
+	}
+
+	regbits = RtoB(REGSP)|RtoB(REGLINK)|RtoB(REGPC);
+	for(z=0; z<BITS; z++) {
+		externs.b[z] = 0;
+		params.b[z] = 0;
+		consts.b[z] = 0;
+		addrs.b[z] = 0;
+		ivar.b[z] = 0;
+		ovar.b[z] = 0;
+	}
+
+	/*
+	 * pass 1
+	 * build aux data structure
+	 * allocate pcs
+	 * find use and set of variables
+	 */
+	g = flowstart(firstp, sizeof(Reg));
+	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.
+		if(p->as == ABL && p->to.name == D_EXTERN)
+			continue;
+
+		bit = mkvar(r, &p->from);
+		if(info.flags & LeftRead)
+			for(z=0; z<BITS; z++)
+				r->use1.b[z] |= bit.b[z];
+		if(info.flags & LeftAddr)
+			setaddrs(bit);
+
+		if(info.flags & RegRead) {	
+			if(p->from.type != D_FREG)
+				r->use1.b[0] |= RtoB(p->reg);
+			else
+				r->use1.b[0] |= FtoB(p->reg);
+		}
+
+		if(info.flags & (RightAddr | RightRead | RightWrite)) {
+			bit = mkvar(r, &p->to);
+			if(info.flags & RightAddr)
+				setaddrs(bit);
+			if(info.flags & RightRead)
+				for(z=0; z<BITS; z++)
+					r->use2.b[z] |= bit.b[z];
+			if(info.flags & RightWrite)
+				for(z=0; z<BITS; z++)
+					r->set.b[z] |= bit.b[z];
+		}
+
+		/* the mod/div runtime routines smash R12 */
+		if(p->as == ADIV || p->as == ADIVU || p->as == AMOD || p->as == AMODU)
+			r->set.b[0] |= RtoB(12);
+	}
+	if(firstr == R)
+		return;
+
+	for(i=0; i<nvar; i++) {
+		Var *v = var+i;
+		if(v->addr) {
+			bit = blsh(i);
+			for(z=0; z<BITS; z++)
+				addrs.b[z] |= bit.b[z];
+		}
+
+		if(debug['R'] && debug['v'])
+			print("bit=%2d addr=%d et=%-6E w=%-2d s=%N + %lld\n",
+				i, v->addr, v->etype, v->width, v->node, v->offset);
+	}
+
+	if(debug['R'] && debug['v'])
+		dumpit("pass1", &firstr->f, 1);
+
+	/*
+	 * pass 2
+	 * find looping structure
+	 */
+	flowrpo(g);
+
+	if(debug['R'] && debug['v'])
+		dumpit("pass2", &firstr->f, 1);
+
+	/*
+	 * pass 2.5
+	 * iterate propagating fat vardef covering forward
+	 * r->act records vars with a VARDEF since the last CALL.
+	 * (r->act will be reused in pass 5 for something else,
+	 * but we'll be done with it by then.)
+	 */
+	active = 0;
+	for(r = firstr; r != R; r = (Reg*)r->f.link) {
+		r->f.active = 0;
+		r->act = zbits;
+	}
+	for(r = firstr; r != R; r = (Reg*)r->f.link) {
+		p = r->f.prog;
+		if(p->as == AVARDEF && isfat(p->to.node->type) && p->to.node->opt != nil) {
+			active++;
+			walkvardef(p->to.node, r, active);
+		}
+	}
+
+	/*
+	 * pass 3
+	 * iterate propagating usage
+	 * 	back until flow graph is complete
+	 */
+loop1:
+	change = 0;
+	for(r = firstr; r != R; r = (Reg*)r->f.link)
+		r->f.active = 0;
+	for(r = firstr; r != R; r = (Reg*)r->f.link)
+		if(r->f.prog->as == ARET)
+			prop(r, zbits, zbits);
+loop11:
+	/* pick up unreachable code */
+	i = 0;
+	for(r = firstr; r != R; r = r1) {
+		r1 = (Reg*)r->f.link;
+		if(r1 && r1->f.active && !r->f.active) {
+			prop(r, zbits, zbits);
+			i = 1;
+		}
+	}
+	if(i)
+		goto loop11;
+	if(change)
+		goto loop1;
+
+	if(debug['R'] && debug['v'])
+		dumpit("pass3", &firstr->f, 1);
+
+
+	/*
+	 * pass 4
+	 * iterate propagating register/variable synchrony
+	 * 	forward until graph is complete
+	 */
+loop2:
+	change = 0;
+	for(r = firstr; r != R; r = (Reg*)r->f.link)
+		r->f.active = 0;
+	synch(firstr, zbits);
+	if(change)
+		goto loop2;
+
+	addsplits();
+
+	if(debug['R'] && debug['v'])
+		dumpit("pass4", &firstr->f, 1);
+
+	if(debug['R'] > 1) {
+		print("\nprop structure:\n");
+		for(r = firstr; r != R; r = (Reg*)r->f.link) {
+			print("%d:%P", r->f.loop, r->f.prog);
+			for(z=0; z<BITS; z++) {
+				bit.b[z] = r->set.b[z] |
+					r->refahead.b[z] | r->calahead.b[z] |
+					r->refbehind.b[z] | r->calbehind.b[z] |
+					r->use1.b[z] | r->use2.b[z];
+				bit.b[z] &= ~addrs.b[z];
+			}
+
+			if(bany(&bit)) {
+				print("\t");
+				if(bany(&r->use1))
+					print(" u1=%Q", r->use1);
+				if(bany(&r->use2))
+					print(" u2=%Q", r->use2);
+				if(bany(&r->set))
+					print(" st=%Q", r->set);
+				if(bany(&r->refahead))
+					print(" ra=%Q", r->refahead);
+				if(bany(&r->calahead))
+					print(" ca=%Q", r->calahead);
+				if(bany(&r->refbehind))
+					print(" rb=%Q", r->refbehind);
+				if(bany(&r->calbehind))
+					print(" cb=%Q", r->calbehind);
+			}
+			print("\n");
+		}
+	}
+
+	/*
+	 * pass 4.5
+	 * move register pseudo-variables into regu.
+	 */
+	for(r = firstr; r != R; r = (Reg*)r->f.link) {
+		r->regu = (r->refbehind.b[0] | r->set.b[0]) & REGBITS;
+
+		r->set.b[0] &= ~REGBITS;
+		r->use1.b[0] &= ~REGBITS;
+		r->use2.b[0] &= ~REGBITS;
+		r->refbehind.b[0] &= ~REGBITS;
+		r->refahead.b[0] &= ~REGBITS;
+		r->calbehind.b[0] &= ~REGBITS;
+		r->calahead.b[0] &= ~REGBITS;
+		r->regdiff.b[0] &= ~REGBITS;
+		r->act.b[0] &= ~REGBITS;
+	}
+
+	if(debug['R'] && debug['v'])
+		dumpit("pass4.5", &firstr->f, 1);
+
+	/*
+	 * pass 5
+	 * isolate regions
+	 * calculate costs (paint1)
+	 */
+	r = firstr;
+	if(r) {
+		for(z=0; z<BITS; z++)
+			bit.b[z] = (r->refahead.b[z] | r->calahead.b[z]) &
+			  ~(externs.b[z] | params.b[z] | addrs.b[z] | consts.b[z]);
+		if(bany(&bit) & !r->f.refset) {
+			// should never happen - all variables are preset
+			if(debug['w'])
+				print("%L: used and not set: %Q\n", r->f.prog->lineno, bit);
+			r->f.refset = 1;
+		}
+	}
+
+	for(r = firstr; r != R; r = (Reg*)r->f.link)
+		r->act = zbits;
+	rgp = region;
+	nregion = 0;
+	for(r = firstr; r != R; r = (Reg*)r->f.link) {
+		for(z=0; z<BITS; z++)
+			bit.b[z] = r->set.b[z] &
+			  ~(r->refahead.b[z] | r->calahead.b[z] | addrs.b[z]);
+		if(bany(&bit) && !r->f.refset) {
+			if(debug['w'])
+				print("%L: set and not used: %Q\n", r->f.prog->lineno, bit);
+			r->f.refset = 1;
+			excise(&r->f);
+		}
+		for(z=0; z<BITS; z++)
+			bit.b[z] = LOAD(r) & ~(r->act.b[z] | addrs.b[z]);
+		while(bany(&bit)) {
+			i = bnum(bit);
+			rgp->enter = r;
+			rgp->varno = i;
+			change = 0;
+			if(debug['R'] > 1)
+				print("\n");
+			paint1(r, i);
+			bit.b[i/32] &= ~(1L<<(i%32));
+			if(change <= 0) {
+				if(debug['R'])
+					print("%L $%d: %Q\n",
+						r->f.prog->lineno, change, blsh(i));
+				continue;
+			}
+			rgp->cost = change;
+			nregion++;
+			if(nregion >= NRGN) {
+				if(debug['R'] > 1)
+					print("too many regions\n");
+				goto brk;
+			}
+			rgp++;
+		}
+	}
+brk:
+	qsort(region, nregion, sizeof(region[0]), rcmp);
+
+	if(debug['R'] && debug['v'])
+		dumpit("pass5", &firstr->f, 1);
+
+	/*
+	 * pass 6
+	 * determine used registers (paint2)
+	 * replace code (paint3)
+	 */
+	rgp = region;
+	for(i=0; i<nregion; i++) {
+		bit = blsh(rgp->varno);
+		vreg = paint2(rgp->enter, rgp->varno);
+		vreg = allreg(vreg, rgp);
+		if(debug['R']) {
+			if(rgp->regno >= NREG)
+				print("%L $%d F%d: %Q\n",
+					rgp->enter->f.prog->lineno,
+					rgp->cost,
+					rgp->regno-NREG,
+					bit);
+			else
+				print("%L $%d R%d: %Q\n",
+					rgp->enter->f.prog->lineno,
+					rgp->cost,
+					rgp->regno,
+					bit);
+		}
+		if(rgp->regno != 0)
+			paint3(rgp->enter, rgp->varno, vreg, rgp->regno);
+		rgp++;
+	}
+
+	if(debug['R'] && debug['v'])
+		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
+	 */
+	if(!debug['R'] || debug['P']) {
+		peep(firstp);
+	}
+
+	if(debug['R'] && debug['v'])
+		dumpit("pass7", &firstr->f, 1);
+
+	/*
+	 * last pass
+	 * eliminate nops
+	 * free aux structures
+	 * adjust the stack pointer
+	 *	MOVW.W 	R1,-12(R13)			<<- start
+	 *	MOVW   	R0,R1
+	 *	MOVW   	R1,8(R13)
+	 *	MOVW   	$0,R1
+	 *	MOVW   	R1,4(R13)
+	 *	BL     	,runtime.newproc+0(SB)
+	 *	MOVW   	&ft+-32(SP),R7			<<- adjust
+	 *	MOVW   	&j+-40(SP),R6			<<- adjust
+	 *	MOVW   	autotmp_0003+-24(SP),R5		<<- adjust
+	 *	MOVW   	$12(R13),R13			<<- finish
+	 */
+	vreg = 0;
+	for(p = firstp; p != P; p = p->link) {
+		while(p->link != P && p->link->as == ANOP)
+			p->link = p->link->link;
+		if(p->to.type == D_BRANCH)
+			while(p->to.u.branch != P && p->to.u.branch->as == ANOP)
+				p->to.u.branch = p->to.u.branch->link;
+		if(p->as == AMOVW && p->to.reg == 13) {
+			if(p->scond & C_WBIT) {
+				vreg = -p->to.offset;		// in adjust region
+//				print("%P adjusting %d\n", p, vreg);
+				continue;
+			}
+			if(p->from.type == D_CONST && p->to.type == D_REG) {
+				if(p->from.offset != vreg)
+					print("in and out different\n");
+//				print("%P finish %d\n", p, vreg);
+				vreg = 0;	// done adjust region
+				continue;
+			}
+
+//			print("%P %d %d from type\n", p, p->from.type, D_CONST);
+//			print("%P %d %d to type\n\n", p, p->to.type, D_REG);
+		}
+
+		if(p->as == AMOVW && vreg != 0) {
+			if(p->from.sym != 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 != 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);
+			}
+		}
+	}
+}
+
+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
+addsplits(void)
+{
+	Reg *r, *r1;
+	int z, i;
+	Bits bit;
+
+	for(r = firstr; r != R; r = (Reg*)r->f.link) {
+		if(r->f.loop > 1)
+			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;
+			for(z=0; z<BITS; z++)
+				bit.b[z] = r1->calbehind.b[z] &
+					(r->refahead.b[z] | r->use1.b[z] | r->use2.b[z]) &
+					~(r->calahead.b[z] & addrs.b[z]);
+			while(bany(&bit)) {
+				i = bnum(bit);
+				bit.b[i/32] &= ~(1L << (i%32));
+			}
+		}
+	}
+}
+
+/*
+ * add mov b,rn
+ * just after r
+ */
+void
+addmove(Reg *r, int bn, int rn, int f)
+{
+	Prog *p, *p1, *p2;
+	Adr *a;
+	Var *v;
+
+	p1 = mal(sizeof(*p1));
+	*p1 = zprog;
+	p = r->f.prog;
+	
+	// If there's a stack fixup coming (after BL newproc or BL deferproc),
+	// delay the load until after the fixup.
+	p2 = p->link;
+	if(p2 && p2->as == AMOVW && p2->from.type == D_CONST && p2->from.reg == REGSP && p2->to.reg == REGSP && p2->to.type == D_REG)
+		p = p2;
+
+	p1->link = p->link;
+	p->link = p1;
+	p1->lineno = p->lineno;
+
+	v = var + bn;
+
+	a = &p1->to;
+	a->name = v->name;
+	a->node = v->node;
+	a->sym = linksym(v->node->sym);
+	a->offset = v->offset;
+	a->etype = v->etype;
+	a->type = D_OREG;
+	if(a->etype == TARRAY || a->sym == nil)
+		a->type = D_CONST;
+
+	if(v->addr)
+		fatal("addmove: shouldn't be doing this %A\n", a);
+
+	switch(v->etype) {
+	default:
+		print("What is this %E\n", v->etype);
+
+	case TINT8:
+		p1->as = AMOVBS;
+		break;
+	case TBOOL:
+	case TUINT8:
+//print("movbu %E %d %S\n", v->etype, bn, v->sym);
+		p1->as = AMOVBU;
+		break;
+	case TINT16:
+		p1->as = AMOVHS;
+		break;
+	case TUINT16:
+		p1->as = AMOVHU;
+		break;
+	case TINT32:
+	case TUINT32:
+	case TPTR32:
+		p1->as = AMOVW;
+		break;
+	case TFLOAT32:
+		p1->as = AMOVF;
+		break;
+	case TFLOAT64:
+		p1->as = AMOVD;
+		break;
+	}
+
+	p1->from.type = D_REG;
+	p1->from.reg = rn;
+	if(rn >= NREG) {
+		p1->from.type = D_FREG;
+		p1->from.reg = rn-NREG;
+	}
+	if(!f) {
+		p1->from = *a;
+		*a = zprog.from;
+		a->type = D_REG;
+		a->reg = rn;
+		if(rn >= NREG) {
+			a->type = D_FREG;
+			a->reg = rn-NREG;
+		}
+		if(v->etype == TUINT8 || v->etype == TBOOL)
+			p1->as = AMOVBU;
+		if(v->etype == TUINT16)
+			p1->as = AMOVHU;
+	}
+	if(debug['R'])
+		print("%P\t.a%P\n", p, p1);
+}
+
+static int
+overlap(int32 o1, int w1, int32 o2, int w2)
+{
+	int32 t1, t2;
+
+	t1 = o1+w1;
+	t2 = o2+w2;
+
+	if(!(t1 > o2 && t2 > o1))
+		return 0;
+
+	return 1;
+}
+
+Bits
+mkvar(Reg *r, Adr *a)
+{
+	Var *v;
+	int i, t, n, et, z, w, flag;
+	int32 o;
+	Bits bit;
+	Node *node;
+
+	// mark registers used
+	t = a->type;
+
+	flag = 0;
+	switch(t) {
+	default:
+		print("type %d %d %D\n", t, a->name, a);
+		goto none;
+
+	case D_NONE:
+	case D_FCONST:
+	case D_BRANCH:
+		break;
+
+
+	case D_REGREG:
+	case D_REGREG2:
+		bit = zbits;
+		if(a->offset != NREG)
+			bit.b[0] |= RtoB(a->offset);
+		if(a->reg != NREG)
+			bit.b[0] |= RtoB(a->reg);
+		return bit;
+
+	case D_CONST:
+	case D_REG:
+	case D_SHIFT:
+		if(a->reg != NREG) {
+			bit = zbits;
+			bit.b[0] = RtoB(a->reg);
+			return bit;
+		}
+		break;
+
+	case D_OREG:
+		if(a->reg != NREG) {
+			if(a == &r->f.prog->from)
+				r->use1.b[0] |= RtoB(a->reg);
+			else
+				r->use2.b[0] |= RtoB(a->reg);
+			if(r->f.prog->scond & (C_PBIT|C_WBIT))
+				r->set.b[0] |= RtoB(a->reg);
+		}
+		break;
+
+	case D_FREG:
+		if(a->reg != NREG) {
+			bit = zbits;
+			bit.b[0] = FtoB(a->reg);
+			return bit;
+		}
+		break;
+	}
+
+	switch(a->name) {
+	default:
+		goto none;
+
+	case D_EXTERN:
+	case D_STATIC:
+	case D_AUTO:
+	case D_PARAM:
+		n = a->name;
+		break;
+	}
+
+	node = a->node;
+	if(node == N || node->op != ONAME || node->orig == N)
+		goto none;
+	node = node->orig;
+	if(node->orig != node)
+		fatal("%D: bad node", a);
+	if(node->sym == S || node->sym->name[0] == '.')
+		goto none;
+	et = a->etype;
+	o = a->offset;
+	w = a->width;
+	if(w < 0)
+		fatal("bad width %d for %D", w, a);
+
+	for(i=0; i<nvar; i++) {
+		v = var+i;
+		if(v->node == node && v->name == n) {
+			if(v->offset == o)
+			if(v->etype == et)
+			if(v->width == w)
+				if(!flag)
+					return blsh(i);
+
+			// if they overlap, disable both
+			if(overlap(v->offset, v->width, o, w)) {
+				v->addr = 1;
+				flag = 1;
+			}
+		}
+	}
+
+	switch(et) {
+	case 0:
+	case TFUNC:
+		goto none;
+	}
+
+	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;
+	}
+
+	i = nvar;
+	nvar++;
+//print("var %d %E %D %S\n", i, et, a, s);
+	v = var+i;
+	v->offset = o;
+	v->name = n;
+	v->etype = et;
+	v->width = w;
+	v->addr = flag;		// funny punning
+	v->node = node;
+	
+	// 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++)
+			externs.b[z] |= bit.b[z];
+	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);
+
+	return bit;
+
+none:
+	return zbits;
+}
+
+void
+prop(Reg *r, Bits ref, Bits cal)
+{
+	Reg *r1, *r2;
+	int z, i, j;
+	Var *v, *v1;
+
+	for(r1 = r; r1 != R; r1 = (Reg*)r1->f.p1) {
+		for(z=0; z<BITS; z++) {
+			ref.b[z] |= r1->refahead.b[z];
+			if(ref.b[z] != r1->refahead.b[z]) {
+				r1->refahead.b[z] = ref.b[z];
+				change++;
+			}
+			cal.b[z] |= r1->calahead.b[z];
+			if(cal.b[z] != r1->calahead.b[z]) {
+				r1->calahead.b[z] = cal.b[z];
+				change++;
+			}
+		}
+		switch(r1->f.prog->as) {
+		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] | 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:
+			for(z=0; z<BITS; z++) {
+				cal.b[z] = 0;
+				ref.b[z] = 0;
+			}
+			break;
+
+		case ARET:
+			for(z=0; z<BITS; z++) {
+				cal.b[z] = externs.b[z] | ovar.b[z];
+				ref.b[z] = 0;
+			}
+			break;
+		}
+		for(z=0; z<BITS; z++) {
+			ref.b[z] = (ref.b[z] & ~r1->set.b[z]) |
+				r1->use1.b[z] | r1->use2.b[z];
+			cal.b[z] &= ~(r1->set.b[z] | r1->use1.b[z] | r1->use2.b[z]);
+			r1->refbehind.b[z] = ref.b[z];
+			r1->calbehind.b[z] = cal.b[z];
+		}
+		if(r1->f.active)
+			break;
+		r1->f.active = 1;
+	}
+	for(; r != r1; r = (Reg*)r->f.p1)
+		for(r2 = (Reg*)r->f.p2; r2 != R; r2 = (Reg*)r2->f.p2link)
+			prop(r2, r->refbehind, r->calbehind);
+}
+
+void
+synch(Reg *r, Bits dif)
+{
+	Reg *r1;
+	int z;
+
+	for(r1 = r; r1 != R; r1 = (Reg*)r1->f.s1) {
+		for(z=0; z<BITS; z++) {
+			dif.b[z] = (dif.b[z] &
+				~(~r1->refbehind.b[z] & r1->refahead.b[z])) |
+					r1->set.b[z] | r1->regdiff.b[z];
+			if(dif.b[z] != r1->regdiff.b[z]) {
+				r1->regdiff.b[z] = dif.b[z];
+				change++;
+			}
+		}
+		if(r1->f.active)
+			break;
+		r1->f.active = 1;
+		for(z=0; z<BITS; z++)
+			dif.b[z] &= ~(~r1->calbehind.b[z] & r1->calahead.b[z]);
+		if(r1->f.s2 != nil)
+			synch((Reg*)r1->f.s2, dif);
+	}
+}
+
+uint32
+allreg(uint32 b, Rgn *r)
+{
+	Var *v;
+	int i;
+
+	v = var + r->varno;
+	r->regno = 0;
+	switch(v->etype) {
+
+	default:
+		fatal("unknown etype %d/%E", bitno(b), v->etype);
+		break;
+
+	case TINT8:
+	case TUINT8:
+	case TINT16:
+	case TUINT16:
+	case TINT32:
+	case TUINT32:
+	case TINT:
+	case TUINT:
+	case TUINTPTR:
+	case TBOOL:
+	case TPTR32:
+		i = BtoR(~b);
+		if(i && r->cost >= 0) {
+			r->regno = i;
+			return RtoB(i);
+		}
+		break;
+
+	case TFLOAT32:
+	case TFLOAT64:
+		i = BtoF(~b);
+		if(i && r->cost >= 0) {
+			r->regno = i+NREG;
+			return FtoB(i);
+		}
+		break;
+
+	case TINT64:
+	case TUINT64:
+	case TPTR64:
+	case TINTER:
+	case TSTRUCT:
+	case TARRAY:
+		break;
+	}
+	return 0;
+}
+
+void
+paint1(Reg *r, int bn)
+{
+	Reg *r1;
+	Prog *p;
+	int z;
+	uint32 bb;
+
+	z = bn/32;
+	bb = 1L<<(bn%32);
+	if(r->act.b[z] & bb)
+		return;
+	for(;;) {
+		if(!(r->refbehind.b[z] & bb))
+			break;
+		r1 = (Reg*)r->f.p1;
+		if(r1 == R)
+			break;
+		if(!(r1->refahead.b[z] & bb))
+			break;
+		if(r1->act.b[z] & bb)
+			break;
+		r = r1;
+	}
+
+	if(LOAD(r) & ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z])) & bb) {
+		change -= CLOAD * r->f.loop;
+		if(debug['R'] > 1)
+			print("%d%P\td %Q $%d\n", r->f.loop,
+				r->f.prog, blsh(bn), change);
+	}
+	for(;;) {
+		r->act.b[z] |= bb;
+		p = r->f.prog;
+
+
+		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) {
+			change -= CLOAD * r->f.loop;
+			if(debug['R'] > 1)
+				print("%d%P\tst %Q $%d\n", r->f.loop,
+					p, blsh(bn), change);
+		}
+
+		if(r->refbehind.b[z] & bb)
+			for(r1 = (Reg*)r->f.p2; r1 != R; r1 = (Reg*)r1->f.p2link)
+				if(r1->refahead.b[z] & bb)
+					paint1(r1, bn);
+
+		if(!(r->refahead.b[z] & bb))
+			break;
+		r1 = (Reg*)r->f.s2;
+		if(r1 != R)
+			if(r1->refbehind.b[z] & bb)
+				paint1(r1, bn);
+		r = (Reg*)r->f.s1;
+		if(r == R)
+			break;
+		if(r->act.b[z] & bb)
+			break;
+		if(!(r->refbehind.b[z] & bb))
+			break;
+	}
+}
+
+uint32
+paint2(Reg *r, int bn)
+{
+	Reg *r1;
+	int z;
+	uint32 bb, vreg;
+
+	z = bn/32;
+	bb = 1L << (bn%32);
+	vreg = regbits;
+	if(!(r->act.b[z] & bb))
+		return vreg;
+	for(;;) {
+		if(!(r->refbehind.b[z] & bb))
+			break;
+		r1 = (Reg*)r->f.p1;
+		if(r1 == R)
+			break;
+		if(!(r1->refahead.b[z] & bb))
+			break;
+		if(!(r1->act.b[z] & bb))
+			break;
+		r = r1;
+	}
+	for(;;) {
+		r->act.b[z] &= ~bb;
+
+		vreg |= r->regu;
+
+		if(r->refbehind.b[z] & bb)
+			for(r1 = (Reg*)r->f.p2; r1 != R; r1 = (Reg*)r1->f.p2link)
+				if(r1->refahead.b[z] & bb)
+					vreg |= paint2(r1, bn);
+
+		if(!(r->refahead.b[z] & bb))
+			break;
+		r1 = (Reg*)r->f.s2;
+		if(r1 != R)
+			if(r1->refbehind.b[z] & bb)
+				vreg |= paint2(r1, bn);
+		r = (Reg*)r->f.s1;
+		if(r == R)
+			break;
+		if(!(r->act.b[z] & bb))
+			break;
+		if(!(r->refbehind.b[z] & bb))
+			break;
+	}
+	return vreg;
+}
+
+void
+paint3(Reg *r, int bn, int32 rb, int rn)
+{
+	Reg *r1;
+	Prog *p;
+	int z;
+	uint32 bb;
+
+	z = bn/32;
+	bb = 1L << (bn%32);
+	if(r->act.b[z] & bb)
+		return;
+	for(;;) {
+		if(!(r->refbehind.b[z] & bb))
+			break;
+		r1 = (Reg*)r->f.p1;
+		if(r1 == R)
+			break;
+		if(!(r1->refahead.b[z] & bb))
+			break;
+		if(r1->act.b[z] & bb)
+			break;
+		r = r1;
+	}
+
+	if(LOAD(r) & ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z])) & bb)
+		addmove(r, bn, rn, 0);
+
+	for(;;) {
+		r->act.b[z] |= bb;
+		p = r->f.prog;
+
+		if(r->use1.b[z] & bb) {
+			if(debug['R'])
+				print("%P", p);
+			addreg(&p->from, rn);
+			if(debug['R'])
+				print("\t.c%P\n", p);
+		}
+		if((r->use2.b[z]|r->set.b[z]) & bb) {
+			if(debug['R'])
+				print("%P", p);
+			addreg(&p->to, rn);
+			if(debug['R'])
+				print("\t.c%P\n", p);
+		}
+
+		if(STORE(r) & r->regdiff.b[z] & bb)
+			addmove(r, bn, rn, 1);
+		r->regu |= rb;
+
+		if(r->refbehind.b[z] & bb)
+			for(r1 = (Reg*)r->f.p2; r1 != R; r1 = (Reg*)r1->f.p2link)
+				if(r1->refahead.b[z] & bb)
+					paint3(r1, bn, rb, rn);
+
+		if(!(r->refahead.b[z] & bb))
+			break;
+		r1 = (Reg*)r->f.s2;
+		if(r1 != R)
+			if(r1->refbehind.b[z] & bb)
+				paint3(r1, bn, rb, rn);
+		r = (Reg*)r->f.s1;
+		if(r == R)
+			break;
+		if(r->act.b[z] & bb)
+			break;
+		if(!(r->refbehind.b[z] & bb))
+			break;
+	}
+}
+
+void
+addreg(Adr *a, int rn)
+{
+	a->sym = nil;
+	a->node = nil;
+	a->name = D_NONE;
+	a->type = D_REG;
+	a->reg = rn;
+	if(rn >= NREG) {
+		a->type = D_FREG;
+		a->reg = rn-NREG;
+	}
+}
+
+/*
+ *	bit	reg
+ *	0	R0
+ *	1	R1
+ *	...	...
+ *	10	R10
+ *	12  R12
+ */
+int32
+RtoB(int r)
+{
+	if(r >= REGTMP-2 && r != 12)	// excluded R9 and R10 for m and g, but not R12
+		return 0;
+	return 1L << r;
+}
+
+int
+BtoR(int32 b)
+{
+	b &= 0x11fcL;	// excluded R9 and R10 for m and g, but not R12
+	if(b == 0)
+		return 0;
+	return bitno(b);
+}
+
+/*
+ *	bit	reg
+ *	18	F2
+ *	19	F3
+ *	...	...
+ *	31	F15
+ */
+int32
+FtoB(int f)
+{
+
+	if(f < 2 || f > NFREG-1)
+		return 0;
+	return 1L << (f + 16);
+}
+
+int
+BtoF(int32 b)
+{
+
+	b &= 0xfffc0000L;
+	if(b == 0)
+		return 0;
+	return bitno(b) - 16;
+}
+
+void
+dumpone(Flow *f, int isreg)
+{
+	int z;
+	Bits bit;
+	Reg *r;
+
+	print("%d:%P", f->loop, f->prog);
+	if(isreg) {
+		r = (Reg*)f;
+		for(z=0; z<BITS; z++)
+			bit.b[z] =
+				r->set.b[z] |
+				r->use1.b[z] |
+				r->use2.b[z] |
+				r->refbehind.b[z] |
+				r->refahead.b[z] |
+				r->calbehind.b[z] |
+				r->calahead.b[z] |
+				r->regdiff.b[z] |
+				r->act.b[z] |
+					0;
+		if(bany(&bit)) {
+			print("\t");
+			if(bany(&r->set))
+				print(" s:%Q", r->set);
+			if(bany(&r->use1))
+				print(" u1:%Q", r->use1);
+			if(bany(&r->use2))
+				print(" u2:%Q", r->use2);
+			if(bany(&r->refbehind))
+				print(" rb:%Q ", r->refbehind);
+			if(bany(&r->refahead))
+				print(" ra:%Q ", r->refahead);
+			if(bany(&r->calbehind))
+				print(" cb:%Q ", r->calbehind);
+			if(bany(&r->calahead))
+				print(" ca:%Q ", r->calahead);
+			if(bany(&r->regdiff))
+				print(" d:%Q ", r->regdiff);
+			if(bany(&r->act))
+				print(" a:%Q ", r->act);
+		}
+	}
+	print("\n");
+}
+
+void
+dumpit(char *str, Flow *r0, int isreg)
+{
+	Flow *r, *r1;
+
+	print("\n%s\n", str);
+	for(r = r0; r != nil; r = r->link) {
+		dumpone(r, isreg);
+		r1 = r->p2;
+		if(r1 != nil) {
+			print("	pred:");
+			for(; r1 != nil; r1 = r1->p2link)
+				print(" %.4ud", (int)r1->prog->pc);
+			if(r->p1 != nil)
+				print(" (and %.4ud)", (int)r->p1->prog->pc);
+			else
+				print(" (only)");
+			print("\n");
+		}
+//		r1 = r->s1;
+//		if(r1 != nil) {
+//			print("	succ:");
+//			for(; r1 != R; r1 = r1->s1)
+//				print(" %.4ud", (int)r1->prog->pc);
+//			print("\n");
+//		}
+	}
+}
diff --git a/src/cmd/5l/5.out.h b/src/cmd/5l/5.out.h
new file mode 100644
index 0000000..7b16ac4
--- /dev/null
+++ b/src/cmd/5l/5.out.h
@@ -0,0 +1,347 @@
+// Inferno utils/5c/5.out.h
+// http://code.google.com/p/inferno-os/source/browse/utils/5c/5.out.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.
+
+enum
+{
+	NSNAME = 8,
+	NSYM = 50,
+	NREG = 16,
+};
+#include "../ld/textflag.h"
+
+/* -1 disables use of REGARG */
+#define	REGARG		-1
+/*c2go enum { REGARG = -1 }; */
+
+enum
+{
+	REGRET = 0,
+	/* compiler allocates R1 up as temps */
+	/* compiler allocates register variables R3 up */
+	/* compiler allocates external registers R10 down */
+	REGEXT = 10,
+	/* these two registers are declared in runtime.h */
+	REGG = REGEXT-0,
+	REGM = REGEXT-1,
+
+	REGTMP = 11,
+	REGSP = 13,
+	REGLINK = 14,
+	REGPC = 15,
+	
+	NFREG = 16,
+	FREGRET = 0,
+	FREGEXT = 7,
+	FREGTMP = 15,
+};
+/* compiler allocates register variables F0 up */
+/* compiler allocates external registers F7 down */
+
+enum
+{
+	C_NONE,
+	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,
+
+	C_NCLASS,	/* must be the last */
+};
+
+enum
+{
+	AXXX,
+
+	AAND,
+	AEOR,
+	ASUB,
+	ARSB,
+	AADD,
+	AADC,
+	ASBC,
+	ARSC,
+	ATST,
+	ATEQ,
+	ACMP,
+	ACMN,
+	AORR,
+	ABIC,
+
+	AMVN,
+
+	AB,
+	ABL,
+
+/*
+ * Do not reorder or fragment the conditional branch
+ * opcodes, or the predication code will break
+ */
+	ABEQ,
+	ABNE,
+	ABCS,
+	ABHS,
+	ABCC,
+	ABLO,
+	ABMI,
+	ABPL,
+	ABVS,
+	ABVC,
+	ABHI,
+	ABLS,
+	ABGE,
+	ABLT,
+	ABGT,
+	ABLE,
+
+	AMOVWD,
+	AMOVWF,
+	AMOVDW,
+	AMOVFW,
+	AMOVFD,
+	AMOVDF,
+	AMOVF,
+	AMOVD,
+
+	ACMPF,
+	ACMPD,
+	AADDF,
+	AADDD,
+	ASUBF,
+	ASUBD,
+	AMULF,
+	AMULD,
+	ADIVF,
+	ADIVD,
+	ASQRTF,
+	ASQRTD,
+	AABSF,
+	AABSD,
+
+	ASRL,
+	ASRA,
+	ASLL,
+	AMULU,
+	ADIVU,
+	AMUL,
+	ADIV,
+	AMOD,
+	AMODU,
+
+	AMOVB,
+	AMOVBS,
+	AMOVBU,
+	AMOVH,
+	AMOVHS,
+	AMOVHU,
+	AMOVW,
+	AMOVM,
+	ASWPBU,
+	ASWPW,
+
+	ANOP,
+	ARFE,
+	ASWI,
+	AMULA,
+
+	ADATA,
+	AGLOBL,
+	AGOK,
+	AHISTORY,
+	ANAME,
+	ARET,
+	ATEXT,
+	AWORD,
+	ADYNT_,
+	AINIT_,
+	ABCASE,
+	ACASE,
+
+	AEND,
+
+	AMULL,
+	AMULAL,
+	AMULLU,
+	AMULALU,
+
+	ABX,
+	ABXRET,
+	ADWORD,
+
+	ASIGNAME,
+
+	ALDREX,
+	ASTREX,
+	
+	ALDREXD,
+	ASTREXD,
+
+	APLD,
+
+	AUNDEF,
+
+	ACLZ,
+
+	AMULWT,
+	AMULWB,
+	AMULAWT,
+	AMULAWB,
+	
+	AUSEFIELD,
+	ATYPE,
+	AFUNCDATA,
+	APCDATA,
+	ACHECKNIL,
+	AVARDEF,
+	AVARKILL,
+	ADUFFCOPY,
+	ADUFFZERO,
+	ADATABUNDLE,
+	ADATABUNDLEEND,
+
+	AMRC, // MRC/MCR
+
+	ALAST,
+};
+
+/* scond byte */
+enum
+{
+	C_SCOND = (1<<4)-1,
+	C_SBIT = 1<<4,
+	C_PBIT = 1<<5,
+	C_WBIT = 1<<6,
+	C_FBIT = 1<<7,	/* psr flags-only */
+	C_UBIT = 1<<7,	/* up bit, unsigned bit */
+
+	C_SCOND_EQ = 0,
+	C_SCOND_NE = 1,
+	C_SCOND_HS = 2,
+	C_SCOND_LO = 3,
+	C_SCOND_MI = 4,
+	C_SCOND_PL = 5,
+	C_SCOND_VS = 6,
+	C_SCOND_VC = 7,
+	C_SCOND_HI = 8,
+	C_SCOND_LS = 9,
+	C_SCOND_GE = 10,
+	C_SCOND_LT = 11,
+	C_SCOND_GT = 12,
+	C_SCOND_LE = 13,
+	C_SCOND_NONE = 14,
+	C_SCOND_NV = 15,
+
+	/* D_SHIFT type */
+	SHIFT_LL = 0<<5,
+	SHIFT_LR = 1<<5,
+	SHIFT_AR = 2<<5,
+	SHIFT_RR = 3<<5,
+};
+
+enum
+{
+/* type/name */
+	D_GOK = 0,
+	D_NONE = 1,
+
+/* type */
+	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 */
+	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"
+/*c2go extern char SYMDEF[]; */
diff --git a/src/cmd/5l/Makefile b/src/cmd/5l/Makefile
new file mode 100644
index 0000000..3f528d7
--- /dev/null
+++ b/src/cmd/5l/Makefile
@@ -0,0 +1,5 @@
+# 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/5l/asm.c b/src/cmd/5l/asm.c
new file mode 100644
index 0000000..9c1c04e
--- /dev/null
+++ b/src/cmd/5l/asm.c
@@ -0,0 +1,692 @@
+// Inferno utils/5l/asm.c
+// http://code.google.com/p/inferno-os/source/browse/utils/5l/asm.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.
+
+// Writing object files.
+
+#include	"l.h"
+#include	"../ld/lib.h"
+#include	"../ld/elf.h"
+#include	"../ld/dwarf.h"
+
+
+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";
+char solarisdynld[] = "XXX";
+
+static int
+needlib(char *name)
+{
+	char *p;
+	LSym *s;
+
+	if(*name == '\0')
+		return 0;
+
+	/* reuse hash code in symbol table */
+	p = smprint(".dynlib.%s", name);
+	s = linklookup(ctxt, p, 0);
+	free(p);
+	if(s->type == 0) {
+		s->type = 100;	// avoid SDATA, etc.
+		return 1;
+	}
+	return 0;
+}
+
+int	nelfsym = 1;
+
+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
+static int32
+braddoff(int32 a, int32 b)
+{
+	return (((uint32)a) & 0xff000000U) | (0x00ffffffU & (uint32)(a + b));
+}
+
+void
+adddynrela(LSym *rel, LSym *s, Reloc *r)
+{
+	addaddrplus(ctxt, rel, s, r->off);
+	adduint32(ctxt, rel, R_ARM_RELATIVE);
+}
+
+void
+adddynrel(LSym *s, Reloc *r)
+{
+	LSym *targ, *rel;
+
+	targ = r->sym;
+	ctxt->cursym = s;
+
+	switch(r->type) {
+	default:
+		if(r->type >= 256) {
+			diag("unexpected relocation type %d", r->type);
+			return;
+		}
+		break;
+
+	// Handle relocations found in ELF object files.
+	case 256 + R_ARM_PLT32:
+		r->type = R_CALLARM;
+		if(targ->type == SDYNIMPORT) {
+			addpltsym(ctxt, targ);
+			r->sym = linklookup(ctxt, ".plt", 0);
+			r->add = braddoff(r->add, targ->plt / 4);
+		}
+		return;
+
+	case 256 + R_ARM_THM_PC22: // R_ARM_THM_CALL
+		diag("R_ARM_THM_CALL, are you using -marm?");
+		errorexit();
+		return;
+
+	case 256 + R_ARM_GOT32: // R_ARM_GOT_BREL
+		if(targ->type != SDYNIMPORT) {
+			addgotsyminternal(ctxt, targ);
+		} else {
+			addgotsym(ctxt, targ);
+		}
+		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(ctxt, targ);
+		} else {
+			addgotsym(ctxt, targ);
+		}
+		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 = R_GOTOFF;
+		return;
+
+	case 256 + R_ARM_GOTPC: // R_ARM_BASE_PREL
+		r->type = R_PCREL;
+		r->sym = linklookup(ctxt, ".got", 0);
+		r->add += 4;
+		return;
+
+	case 256 + R_ARM_CALL:
+		r->type = R_CALLARM;
+		if(targ->type == SDYNIMPORT) {
+			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 = 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 = R_ADDR;
+		return;
+
+	case 256 + R_ARM_V4BX:
+		// we can just ignore this, because we are targeting ARM V5+ anyway
+		if(r->sym) {
+			// R_ARM_V4BX is ABS relocation, so this symbol is a dummy symbol, ignore it
+			r->sym->type = 0;
+		}
+		r->sym = S;
+		return;
+
+	case 256 + R_ARM_PC24:
+	case 256 + R_ARM_JUMP24:
+		r->type = R_CALLARM;
+		if(targ->type == SDYNIMPORT) {
+			addpltsym(ctxt, targ);
+			r->sym = linklookup(ctxt, ".plt", 0);
+			r->add = braddoff(r->add, targ->plt / 4);
+		}
+		return;
+	}
+	
+	// Handle references to ELF symbols from our own object files.
+	if(targ->type != SDYNIMPORT)
+		return;
+
+	switch(r->type) {
+	case R_CALLARM:
+		addpltsym(ctxt, targ);
+		r->sym = linklookup(ctxt, ".plt", 0);
+		r->add = targ->plt;
+		return;
+	
+	case R_ADDR:
+		if(s->type != SDATA)
+			break;
+		if(iself) {
+			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;
+	}
+
+	ctxt->cursym = s;
+	diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ->name, r->type, targ->type);
+}
+
+int
+elfreloc1(Reloc *r, vlong sectoff)
+{
+	int32 elfsym;
+	
+	LPUT(sectoff);
+
+	elfsym = r->xsym->elfsym;
+	switch(r->type) {
+	default:
+		return -1;
+
+	case R_ADDR:
+		if(r->siz == 4)
+			LPUT(R_ARM_ABS32 | elfsym<<8);
+		else
+			return -1;
+		break;
+
+	case R_PCREL:
+		if(r->siz == 4)
+			LPUT(R_ARM_REL32 | elfsym<<8);
+		else
+			return -1;
+		break;
+
+	case R_CALLARM:
+		if(r->siz == 4) {
+			if((r->add & 0xff000000) == 0xeb000000) // BL
+				LPUT(R_ARM_CALL | elfsym<<8);
+			else
+				LPUT(R_ARM_JUMP24 | elfsym<<8);
+		} else
+			return -1;
+		break;
+
+	case R_TLS:
+		if(r->siz == 4) {
+			if(flag_shared)
+				LPUT(R_ARM_TLS_IE32 | elfsym<<8);
+			else
+				LPUT(R_ARM_TLS_LE32 | elfsym<<8);
+		} else
+			return -1;
+		break;
+	}
+
+	return 0;
+}
+
+void
+elfsetupplt(void)
+{
+	LSym *plt, *got;
+	
+	plt = linklookup(ctxt, ".plt", 0);
+	got = linklookup(ctxt, ".got.plt", 0);
+	if(plt->size == 0) {
+		// str lr, [sp, #-4]!
+		adduint32(ctxt, plt, 0xe52de004);
+		// ldr lr, [pc, #4]
+		adduint32(ctxt, plt, 0xe59fe004);
+		// add lr, pc, lr
+		adduint32(ctxt, plt, 0xe08fe00e);
+		// ldr pc, [lr, #8]!
+		adduint32(ctxt, plt, 0xe5bef008);
+		// .word &GLOBAL_OFFSET_TABLE[0] - .
+		addpcrelplus(ctxt, plt, got, 4);
+
+		// the first .plt entry requires 3 .plt.got entries
+		adduint32(ctxt, got, 0);
+		adduint32(ctxt, got, 0);
+		adduint32(ctxt, got, 0);
+	}
+}
+
+int
+machoreloc1(Reloc *r, vlong sectoff)
+{
+	USED(r);
+	USED(sectoff);
+
+	return -1;
+}
+
+
+int
+archreloc(Reloc *r, LSym *s, vlong *val)
+{
+	LSym *rs;
+
+	if(linkmode == LinkExternal) {
+		switch(r->type) {
+		case R_CALLARM:
+			r->done = 0;
+
+			// set up addend for eventual relocation via outer symbol.
+			rs = r->sym;
+			r->xadd = r->add;
+			if(r->xadd & 0x800000)
+				r->xadd |= ~0xffffff;
+			r->xadd *= 4;
+			while(rs->outer != nil) {
+				r->xadd += symaddr(rs) - symaddr(rs->outer);
+				rs = rs->outer;
+			}
+
+			if(rs->type != SHOSTOBJ && rs->sect == nil)
+				diag("missing section for %s", rs->name);
+			r->xsym = rs;
+
+			*val = braddoff((0xff000000U & (uint32)r->add), 
+							(0xffffff & (uint32)(r->xadd / 4)));
+			return 0;
+		}
+		return -1;
+	}
+	switch(r->type) {
+	case R_CONST:
+		*val = r->add;
+		return 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 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(linklookup(ctxt, ".plt", 0)) + r->off) + r->add) >> 20));
+		return 0;
+	case R_PLT1: // add ip, ip, #0xYY000
+		*val = 0xe28cca00U +
+			(0xff & ((uint32)(symaddr(r->sym) - (symaddr(linklookup(ctxt, ".plt", 0)) + r->off) + r->add + 4) >> 12));
+		return 0;
+	case R_PLT2: // ldr pc, [ip, #0xZZZ]!
+		*val = 0xe5bcf000U +
+			(0xfff & (uint32)(symaddr(r->sym) - (symaddr(linklookup(ctxt, ".plt", 0)) + r->off) + r->add + 8));
+		return 0;
+	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)));
+		return 0;
+	}
+	return -1;
+}
+
+static Reloc *
+addpltreloc(Link *ctxt, LSym *plt, LSym *got, LSym *sym, int typ)
+{
+	Reloc *r;
+
+	r = addrel(plt);
+	r->sym = got;
+	r->off = plt->size;
+	r->siz = 4;
+	r->type = typ;
+	r->add = sym->got - 8;
+
+	plt->reachable = 1;
+	plt->size += 4;
+	symgrow(ctxt, plt, plt->size);
+
+	return r;
+}
+
+static void
+addpltsym(Link *ctxt, LSym *s)
+{
+	LSym *plt, *got, *rel;
+	
+	if(s->plt >= 0)
+		return;
+
+	adddynsym(ctxt, s);
+	
+	if(iself) {
+		plt = linklookup(ctxt, ".plt", 0);
+		got = linklookup(ctxt, ".got.plt", 0);
+		rel = linklookup(ctxt, ".rel.plt", 0);
+		if(plt->size == 0)
+			elfsetupplt();
+		
+		// .got entry
+		s->got = got->size;
+		// 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(ctxt, got, plt, 0);
+
+		// .plt entry, this depends on the .got entry
+		s->plt = plt->size;
+		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(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(Link *ctxt, LSym *s)
+{
+	LSym *got;
+	
+	if(s->got >= 0)
+		return;
+
+	got = linklookup(ctxt, ".got", 0);
+	s->got = got->size;
+
+	addaddrplus(ctxt, got, s, 0);
+
+	if(iself) {
+		;
+	} else {
+		diag("addgotsyminternal: unsupported binary format");
+	}
+}
+
+static void
+addgotsym(Link *ctxt, LSym *s)
+{
+	LSym *got, *rel;
+	
+	if(s->got >= 0)
+		return;
+	
+	adddynsym(ctxt, s);
+	got = linklookup(ctxt, ".got", 0);
+	s->got = got->size;
+	adduint32(ctxt, got, 0);
+	
+	if(iself) {
+		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(Link *ctxt, LSym *s)
+{
+	LSym *d;
+	int t;
+	char *name;
+
+	if(s->dynid >= 0)
+		return;
+
+	if(iself) {
+		s->dynid = nelfsym++;
+
+		d = linklookup(ctxt, ".dynsym", 0);
+
+		/* name */
+		name = s->extname;
+		adduint32(ctxt, d, addstring(linklookup(ctxt, ".dynstr", 0), name));
+
+		/* value */
+		if(s->type == SDYNIMPORT)
+			adduint32(ctxt, d, 0);
+		else
+			addaddr(ctxt, d, s);
+
+		/* size */
+		adduint32(ctxt, d, 0);
+
+		/* type */
+		t = STB_GLOBAL << 4;
+		if((s->cgoexport & CgoExportDynamic) && (s->type&SMASK) == STEXT)
+			t |= STT_FUNC;
+		else
+			t |= STT_OBJECT;
+		adduint8(ctxt, d, t);
+		adduint8(ctxt, d, 0);
+
+		/* shndx */
+		if(s->type == SDYNIMPORT)
+			adduint16(ctxt, d, SHN_UNDEF);
+		else {
+			switch(s->type) {
+			default:
+			case STEXT:
+				t = 11;
+				break;
+			case SRODATA:
+				t = 12;
+				break;
+			case SDATA:
+				t = 13;
+				break;
+			case SBSS:
+				t = 14;
+				break;
+			}
+			adduint16(ctxt, d, t);
+		}
+	} else {
+		diag("adddynsym: unsupported binary format");
+	}
+}
+
+void
+adddynlib(char *lib)
+{
+	LSym *s;
+	
+	if(!needlib(lib))
+		return;
+	
+	if(iself) {
+		s = linklookup(ctxt, ".dynstr", 0);
+		if(s->size == 0)
+			addstring(s, "");
+		elfwritedynent(linklookup(ctxt, ".dynamic", 0), DT_NEEDED, addstring(s, lib));
+	} else {
+		diag("adddynlib: unsupported binary format");
+	}
+}
+
+void
+asmb(void)
+{
+	uint32 symo;
+	Section *sect;
+	LSym *sym;
+	int i;
+
+	if(debug['v'])
+		Bprint(&bso, "%5.2f asmb\n", cputime());
+	Bflush(&bso);
+
+	if(iself)
+		asmbelfsetup();
+
+	sect = segtext.sect;
+	cseek(sect->vaddr - segtext.vaddr + segtext.fileoff);
+	codeblk(sect->vaddr, sect->len);
+	for(sect = sect->next; sect != nil; sect = sect->next) {
+		cseek(sect->vaddr - segtext.vaddr + segtext.fileoff);
+		datblk(sect->vaddr, sect->len);
+	}
+
+	if(segrodata.filelen > 0) {
+		if(debug['v'])
+			Bprint(&bso, "%5.2f rodatblk\n", cputime());
+		Bflush(&bso);
+
+		cseek(segrodata.fileoff);
+		datblk(segrodata.vaddr, segrodata.filelen);
+	}
+
+	if(debug['v'])
+		Bprint(&bso, "%5.2f datblk\n", cputime());
+	Bflush(&bso);
+
+	cseek(segdata.fileoff);
+	datblk(segdata.vaddr, segdata.filelen);
+
+	/* output symbol table */
+	symsize = 0;
+	lcsize = 0;
+	symo = 0;
+	if(!debug['s']) {
+		// TODO: rationalize
+		if(debug['v'])
+			Bprint(&bso, "%5.2f sym\n", cputime());
+		Bflush(&bso);
+		switch(HEADTYPE) {
+		default:
+			if(iself)
+				goto ElfSym;
+		case Hplan9:
+			symo = segdata.fileoff+segdata.filelen;
+			break;
+		ElfSym:
+			symo = segdata.fileoff+segdata.filelen;
+			symo = rnd(symo, INITRND);
+			break;
+		}
+		cseek(symo);
+		switch(HEADTYPE) {
+		default:
+			if(iself) {
+				if(debug['v'])
+					Bprint(&bso, "%5.2f elfsym\n", cputime());
+				asmelfsym();
+				cflush();
+				cwrite(elfstrdat, elfstrsize);
+	
+				if(debug['v'])
+					Bprint(&bso, "%5.2f dwarf\n", cputime());
+				dwarfemitdebugsections();
+				
+				if(linkmode == LinkExternal)
+					elfemitreloc();
+			}
+			break;
+		case Hplan9:
+			asmplan9sym();
+			cflush();
+
+			sym = linklookup(ctxt, "pclntab", 0);
+			if(sym != nil) {
+				lcsize = sym->np;
+				for(i=0; i < lcsize; i++)
+					cput(sym->p[i]);
+
+				cflush();
+			}
+			break;
+		}
+	}
+
+	ctxt->cursym = nil;
+	if(debug['v'])
+		Bprint(&bso, "%5.2f header\n", cputime());
+	Bflush(&bso);
+	cseek(0L);
+	switch(HEADTYPE) {
+	default:
+	case Hplan9:	/* plan 9 */
+		LPUT(0x647);			/* magic */
+		LPUT(segtext.filelen);			/* sizes */
+		LPUT(segdata.filelen);
+		LPUT(segdata.len - segdata.filelen);
+		LPUT(symsize);			/* nsyms */
+		LPUT(entryvalue());		/* va of entry */
+		LPUT(0L);
+		LPUT(lcsize);
+		break;
+	case Hlinux:
+	case Hfreebsd:
+	case Hnetbsd:
+	case Hopenbsd:
+	case Hnacl:
+		asmbelf(symo);
+		break;
+	}
+	cflush();
+	if(debug['c']){
+		print("textsize=%ulld\n", segtext.filelen);
+		print("datsize=%ulld\n", segdata.filelen);
+		print("bsssize=%ulld\n", segdata.len - segdata.filelen);
+		print("symsize=%d\n", symsize);
+		print("lcsize=%d\n", lcsize);
+		print("total=%lld\n", segtext.filelen+segdata.len+symsize+lcsize);
+	}
+}
+
+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;
+}
diff --git a/src/cmd/5l/doc.go b/src/cmd/5l/doc.go
new file mode 100644
index 0000000..a054a22
--- /dev/null
+++ b/src/cmd/5l/doc.go
@@ -0,0 +1,15 @@
+// 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
+
+/*
+
+5l is the linker for the ARM.
+The $GOARCH for these tools is arm.
+
+The flags are documented in ../ld/doc.go.
+
+*/
+package main
diff --git a/src/cmd/5l/l.h b/src/cmd/5l/l.h
new file mode 100644
index 0000000..c881a54
--- /dev/null
+++ b/src/cmd/5l/l.h
@@ -0,0 +1,103 @@
+// Inferno utils/5l/l.h
+// http://code.google.com/p/inferno-os/source/browse/utils/5l/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.
+
+#include	<u.h>
+#include	<libc.h>
+#include	<bio.h>
+#include	<link.h>
+#include	"5.out.h"
+
+enum
+{
+	thechar = '5',
+	PtrSize = 4,
+	IntSize = 4,
+	RegSize = 4,
+	MaxAlign = 8,	// max data alignment
+	FuncAlign = 4  // single-instruction alignment
+};
+
+#ifndef	EXTERN
+#define	EXTERN	extern
+#endif
+
+#define	P		((Prog*)0)
+#define	S		((LSym*)0)
+
+enum
+{
+/* mark flags */
+	FOLL		= 1<<0,
+	LABEL		= 1<<1,
+	LEAF		= 1<<2,
+
+	MINLC	= 4,
+};
+
+EXTERN	int32	autosize;
+EXTERN	LSym*	datap;
+EXTERN	int	debug[128];
+EXTERN	char*	noname;
+EXTERN	Prog*	lastp;
+EXTERN	int32	lcsize;
+EXTERN	char	literal[32];
+EXTERN	int	nerrors;
+EXTERN	int32	instoffset;
+EXTERN	char*	rpath;
+EXTERN	uint32	stroffset;
+EXTERN	int32	symsize;
+EXTERN	int	armsize;
+
+#pragma	varargck	type	"I"	uint32*
+
+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);
+int	elfreloc1(Reloc *r, vlong sectoff);
+void	elfsetupplt(void);
+void	listinit(void);
+int	machoreloc1(Reloc *r, vlong sectoff);
+void	main(int argc, char *argv[]);
+int32	rnd(int32 v, int32 r);
+
+/* Native is little-endian */
+#define	LPUT(a)	lputl(a)
+#define	WPUT(a)	wputl(a)
+#define	VPUT(a)	abort()
+
+/* Used by ../ld/dwarf.c */
+enum
+{
+	DWARFREGSP = 13
+};
diff --git a/src/cmd/5l/list.c b/src/cmd/5l/list.c
new file mode 100644
index 0000000..875fc3e
--- /dev/null
+++ b/src/cmd/5l/list.c
@@ -0,0 +1,70 @@
+// Inferno utils/5l/list.h
+// http://code.google.com/p/inferno-os/source/browse/utils/5l/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.
+
+// Printing.
+
+#include "l.h"
+#include "../ld/lib.h"
+
+void
+listinit(void)
+{
+	listinit5();
+	fmtinstall('I', Iconv);
+}
+
+int
+Iconv(Fmt *fp)
+{
+	int i, n;
+	uint32 *p;
+	char *s;
+	Fmt fmt;
+	
+	n = fp->prec;
+	fp->prec = 0;
+	if(!(fp->flags&FmtPrec) || n < 0)
+		return fmtstrcpy(fp, "%I");
+	fp->flags &= ~FmtPrec;
+	p = va_arg(fp->args, uint32*);
+
+	// format into temporary buffer and
+	// call fmtstrcpy to handle padding.
+	fmtstrinit(&fmt);
+	for(i=0; i<n/4; i++) {
+		if(i > 0)
+			fmtprint(&fmt, " ");
+		fmtprint(&fmt, "%.8ux", *p++);
+	}
+	s = fmtstrflush(&fmt);
+	fmtstrcpy(fp, s);
+	free(s);
+	return 0;
+}
diff --git a/src/cmd/5l/obj.c b/src/cmd/5l/obj.c
new file mode 100644
index 0000000..c6f60ee
--- /dev/null
+++ b/src/cmd/5l/obj.c
@@ -0,0 +1,116 @@
+// 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.
+
+// Reading object files.
+
+#include	"l.h"
+#include	"../ld/lib.h"
+#include	"../ld/elf.h"
+#include	"../ld/dwarf.h"
+#include	<ar.h>
+
+char *thestring = "arm";
+LinkArch *thelinkarch = &linkarm;
+
+void
+linkarchinit(void)
+{
+}
+
+void
+archinit(void)
+{
+	LSym *s;
+
+	// getgoextlinkenabled is based on GO_EXTLINK_ENABLED when
+	// Go was built; see ../../make.bash.
+	if(linkmode == LinkAuto && strcmp(getgoextlinkenabled(), "0") == 0)
+		linkmode = LinkInternal;
+
+	switch(HEADTYPE) {
+	default:
+		if(linkmode == LinkAuto)
+			linkmode = LinkInternal;
+		if(linkmode == LinkExternal && strcmp(getgoextlinkenabled(), "1") != 0)
+			sysfatal("cannot use -linkmode=external with -H %s", headstr(HEADTYPE));
+		break;
+	case Hlinux:
+	case Hfreebsd:
+	case Hnacl:
+		break;
+	}
+
+	switch(HEADTYPE) {
+	default:
+		diag("unknown -H option");
+		errorexit();
+	case Hplan9:	/* plan 9 */
+		HEADR = 32L;
+		if(INITTEXT == -1)
+			INITTEXT = 4128;
+		if(INITDAT == -1)
+			INITDAT = 0;
+		if(INITRND == -1)
+			INITRND = 4096;
+		break;
+	case Hlinux:	/* arm elf */
+	case Hfreebsd:
+	case Hnetbsd:
+		debug['d'] = 0;	// with dynamic linking
+		elfinit();
+		HEADR = ELFRESERVE;
+		if(INITTEXT == -1)
+			INITTEXT = 0x10000 + HEADR;
+		if(INITDAT == -1)
+			INITDAT = 0;
+		if(INITRND == -1)
+			INITRND = 4096;
+		break;
+	case Hnacl:
+		elfinit();
+		HEADR = 0x10000;
+		funcalign = 16;
+		if(INITTEXT == -1)
+			INITTEXT = 0x20000;
+		if(INITDAT == -1)
+			INITDAT = 0;
+		if(INITRND == -1)
+			INITRND = 0x10000;
+		break;
+	}
+	if(INITDAT != 0 && INITRND != 0)
+		print("warning: -D0x%ux is ignored because of -R0x%ux\n",
+			INITDAT, INITRND);
+
+	// embed goarm to runtime.goarm
+	s = linklookup(ctxt, "runtime.goarm", 0);
+	s->type = SRODATA;
+	adduint8(ctxt, s, ctxt->goarm);
+}
diff --git a/src/cmd/6a/Makefile b/src/cmd/6a/Makefile
new file mode 100644
index 0000000..27290dd
--- /dev/null
+++ b/src/cmd/6a/Makefile
@@ -0,0 +1,10 @@
+# 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
+
+install: y.tab.h
+
+y.tab.h: a.y
+	LANG=C LANGUAGE=en_US.UTF8 bison -d -v -y a.y
diff --git a/src/cmd/6a/a.h b/src/cmd/6a/a.h
new file mode 100644
index 0000000..b3fb0bb
--- /dev/null
+++ b/src/cmd/6a/a.h
@@ -0,0 +1,184 @@
+// Inferno utils/6a/a.h
+// http://code.google.com/p/inferno-os/source/browse/utils/6a/a.h
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.	All rights reserved.
+//	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 <bio.h>
+#include <link.h>
+#include "../6l/6.out.h"
+
+#ifndef	EXTERN
+#define	EXTERN	extern
+#endif
+
+#undef	getc
+#undef	ungetc
+#undef	BUFSIZ
+
+#define	getc	ccgetc
+#define	ungetc	ccungetc
+
+typedef	struct	Sym	Sym;
+typedef	struct	Ref	Ref;
+typedef	struct	Io	Io;
+typedef	struct	Addr2	Addr2;
+
+#define	MAXALIGN	7
+#define	FPCHIP		1
+#define	NSYMB		500
+#define	BUFSIZ		8192
+#define	HISTSZ		20
+#ifndef	EOF
+#define	EOF		(-1)
+#endif
+#define	IGN		(-2)
+#define	GETC()		((--fi.c < 0)? filbuf(): *fi.p++ & 0xff)
+#define	NHASH		503
+#define	STRINGSZ	200
+#define	NMACRO		10
+
+struct	Sym
+{
+	Sym*	link;
+	Ref*	ref;
+	char*	macro;
+	vlong	value;
+	ushort	type;
+	char	*name;
+	char	sym;
+};
+#define	S	((Sym*)0)
+
+struct	Ref
+{
+	int	class;
+};
+
+EXTERN struct
+{
+	char*	p;
+	int	c;
+} fi;
+
+struct	Io
+{
+	Io*	link;
+	char	b[BUFSIZ];
+	char*	p;
+	short	c;
+	short	f;
+};
+#define	I	((Io*)0)
+
+struct	Addr2
+{
+	Addr	from;
+	Addr	to;
+};
+
+enum
+{
+	CLAST,
+	CMACARG,
+	CMACRO,
+	CPREPROC,
+};
+
+EXTERN	int	debug[256];
+EXTERN	Sym*	hash[NHASH];
+EXTERN	char**	Dlist;
+EXTERN	int	nDlist;
+EXTERN	int	newflag;
+EXTERN	char*	hunk;
+EXTERN	char**	include;
+EXTERN	Io*	iofree;
+EXTERN	Io*	ionext;
+EXTERN	Io*	iostack;
+EXTERN	int32	lineno;
+EXTERN	int	nerrors;
+EXTERN	int32	nhunk;
+EXTERN	int	ninclude;
+EXTERN	int32	nsymb;
+EXTERN	Addr	nullgen;
+EXTERN	char*	outfile;
+EXTERN	int	pass;
+EXTERN	int32	pc;
+EXTERN	int	peekc;
+EXTERN	int32	stmtline;
+EXTERN	int	sym;
+EXTERN	char*	symb;
+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);
+void	ensuresymb(int32);
+void	errorexit(void);
+void	pushio(void);
+void	newio(void);
+void	newfile(char*, int);
+Sym*	slookup(char*);
+Sym*	lookup(void);
+void	syminit(Sym*);
+int32	yylex(void);
+int	getc(void);
+int	getnsc(void);
+void	unget(int);
+int	escchar(int);
+void	cinit(void);
+void	checkscale(int);
+void	pinit(char*);
+void	cclean(void);
+int	isreg(Addr*);
+void	outcode(int, Addr2*);
+void	outhist(void);
+void	zaddr(Addr*, int);
+void	zname(char*, int, int);
+int	filbuf(void);
+Sym*	getsym(void);
+void	domacro(void);
+void	macund(void);
+void	macdef(void);
+void	macexpand(Sym*, char*);
+void	macinc(void);
+void	macprag(void);
+void	maclin(void);
+void	macif(int);
+void	macend(void);
+void	dodefine(char*);
+void	prfile(int32);
+void	linehist(char*, int);
+void	gethunk(void);
+void	yyerror(char*, ...);
+int	yyparse(void);
+void	setinclude(char*);
+int	assemble(char*);
diff --git a/src/cmd/6a/a.y b/src/cmd/6a/a.y
new file mode 100644
index 0000000..1089d40
--- /dev/null
+++ b/src/cmd/6a/a.y
@@ -0,0 +1,691 @@
+// Inferno utils/6a/a.y
+// http://code.google.com/p/inferno-os/source/browse/utils/6a/a.y
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.	All rights reserved.
+//	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 <stdio.h>	/* if we don't, bison will, and a.h re-#defines getc */
+#include <libc.h>
+#include "a.h"
+#include "../../runtime/funcdata.h"
+%}
+%union	{
+	Sym	*sym;
+	vlong	lval;
+	double	dval;
+	char	sval[8];
+	Addr	addr;
+	Addr2	addr2;
+}
+%left	'|'
+%left	'^'
+%left	'&'
+%left	'<' '>'
+%left	'+' '-'
+%left	'*' '/' '%'
+%token	<lval>	LTYPE0 LTYPE1 LTYPE2 LTYPE3 LTYPE4
+%token	<lval>	LTYPEC LTYPED LTYPEN LTYPER LTYPET LTYPEG LTYPEPC
+%token	<lval>	LTYPES LTYPEM LTYPEI LTYPEXC LTYPEX LTYPERT LTYPEF
+%token	<lval>	LCONST LFP LPC LSB
+%token	<lval>	LBREG LLREG LSREG LFREG LMREG LXREG
+%token	<dval>	LFCONST
+%token	<sval>	LSCONST LSP
+%token	<sym>	LNAME LLAB LVAR
+%type	<lval>	con con2 expr pointer offset
+%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 
+	{
+		stmtline = lineno;
+	}
+	line
+
+line:
+	LLAB ':'
+	{
+		if($1->value != pc)
+			yyerror("redeclaration of %s", $1->name);
+		$1->value = pc;
+	}
+	line
+|	LNAME ':'
+	{
+		$1->type = LLAB;
+		$1->value = pc;
+	}
+	line
+|	';'
+|	inst ';'
+|	error ';'
+
+inst:
+	LNAME '=' expr
+	{
+		$1->type = LVAR;
+		$1->value = $3;
+	}
+|	LVAR '=' expr
+	{
+		if($1->value != $3)
+			yyerror("redeclaration of %s", $1->name);
+		$1->value = $3;
+	}
+|	LTYPE0 nonnon	{ outcode($1, &$2); }
+|	LTYPE1 nonrem	{ outcode($1, &$2); }
+|	LTYPE2 rimnon	{ outcode($1, &$2); }
+|	LTYPE3 rimrem	{ outcode($1, &$2); }
+|	LTYPE4 remrim	{ outcode($1, &$2); }
+|	LTYPER nonrel	{ outcode($1, &$2); }
+|	LTYPED spec1	{ outcode($1, &$2); }
+|	LTYPET spec2	{ outcode($1, &$2); }
+|	LTYPEC spec3	{ outcode($1, &$2); }
+|	LTYPEN spec4	{ outcode($1, &$2); }
+|	LTYPES spec5	{ outcode($1, &$2); }
+|	LTYPEM spec6	{ outcode($1, &$2); }
+|	LTYPEI spec7	{ outcode($1, &$2); }
+|	LTYPEXC spec8	{ outcode($1, &$2); }
+|	LTYPEX spec9	{ outcode($1, &$2); }
+|	LTYPERT spec10	{ outcode($1, &$2); }
+|	LTYPEG spec11	{ outcode($1, &$2); }
+|	LTYPEPC spec12	{ outcode($1, &$2); }
+|	LTYPEF spec13	{ outcode($1, &$2); }
+
+nonnon:
+	{
+		$$.from = nullgen;
+		$$.to = nullgen;
+	}
+|	','
+	{
+		$$.from = nullgen;
+		$$.to = nullgen;
+	}
+
+rimrem:
+	rim ',' rem
+	{
+		$$.from = $1;
+		$$.to = $3;
+	}
+
+remrim:
+	rem ',' rim
+	{
+		$$.from = $1;
+		$$.to = $3;
+	}
+
+rimnon:
+	rim ','
+	{
+		$$.from = $1;
+		$$.to = nullgen;
+	}
+|	rim
+	{
+		$$.from = $1;
+		$$.to = nullgen;
+	}
+
+nonrem:
+	',' rem
+	{
+		$$.from = nullgen;
+		$$.to = $2;
+	}
+|	rem
+	{
+		$$.from = nullgen;
+		$$.to = $1;
+	}
+
+nonrel:
+	',' rel
+	{
+		$$.from = nullgen;
+		$$.to = $2;
+	}
+|	rel
+	{
+		$$.from = nullgen;
+		$$.to = $1;
+	}
+|	imm ',' rel
+	{
+		$$.from = $1;
+		$$.to = $3;
+	}
+
+spec1:	/* DATA */
+	nam '/' con ',' imm
+	{
+		$$.from = $1;
+		$$.from.scale = $3;
+		$$.to = $5;
+	}
+
+spec2:	/* TEXT */
+	mem ',' imm2
+	{
+		$$.from = $1;
+		$$.to = $3;
+	}
+|	mem ',' con ',' imm2
+	{
+		$$.from = $1;
+		$$.from.scale = $3;
+		$$.to = $5;
+	}
+
+spec3:	/* JMP/CALL */
+	',' rom
+	{
+		$$.from = nullgen;
+		$$.to = $2;
+	}
+|	rom
+	{
+		$$.from = nullgen;
+		$$.to = $1;
+	}
+
+spec4:	/* NOP */
+	nonnon
+|	nonrem
+
+spec5:	/* SHL/SHR */
+	rim ',' rem
+	{
+		$$.from = $1;
+		$$.to = $3;
+	}
+|	rim ',' rem ':' LLREG
+	{
+		$$.from = $1;
+		$$.to = $3;
+		if($$.from.index != D_NONE)
+			yyerror("dp shift with lhs index");
+		$$.from.index = $5;
+	}
+
+spec6:	/* MOVW/MOVL */
+	rim ',' rem
+	{
+		$$.from = $1;
+		$$.to = $3;
+	}
+|	rim ',' rem ':' LSREG
+	{
+		$$.from = $1;
+		$$.to = $3;
+		if($$.to.index != D_NONE)
+			yyerror("dp move with lhs index");
+		$$.to.index = $5;
+	}
+
+spec7:
+	rim ','
+	{
+		$$.from = $1;
+		$$.to = nullgen;
+	}
+|	rim
+	{
+		$$.from = $1;
+		$$.to = nullgen;
+	}
+|	rim ',' rem
+	{
+		$$.from = $1;
+		$$.to = $3;
+	}
+
+spec8:	/* CMPPS/CMPPD */
+	reg ',' rem ',' con
+	{
+		$$.from = $1;
+		$$.to = $3;
+		$$.to.offset = $5;
+	}
+
+spec9:	/* shufl */
+	imm ',' rem ',' reg
+	{
+		$$.from = $3;
+		$$.to = $5;
+		if($1.type != D_CONST)
+			yyerror("illegal constant");
+		$$.to.offset = $1.offset;
+	}
+
+spec10:	/* RET/RETF */
+	{
+		$$.from = nullgen;
+		$$.to = nullgen;
+	}
+|	imm
+	{
+		$$.from = $1;
+		$$.to = nullgen;
+	}
+
+spec11:	/* GLOBL */
+	mem ',' imm
+	{
+		$$.from = $1;
+		$$.to = $3;
+	}
+|	mem ',' con ',' imm
+	{
+		$$.from = $1;
+		$$.from.scale = $3;
+		$$.to = $5;
+	}
+
+spec12:	/* PCDATA */
+	rim ',' rim
+	{
+		if($1.type != D_CONST || $3.type != D_CONST)
+			yyerror("arguments to PCDATA must be integer constants");
+		$$.from = $1;
+		$$.to = $3;
+	}
+
+spec13:	/* FUNCDATA */
+	rim ',' rim
+	{
+		if($1.type != D_CONST)
+			yyerror("index for FUNCDATA must be integer constant");
+		if($3.type != D_EXTERN && $3.type != D_STATIC)
+			yyerror("value for FUNCDATA must be symbol reference");
+		$$.from = $1;
+		$$.to = $3;
+	}
+
+rem:
+	reg
+|	mem
+
+rom:
+	rel
+|	nmem
+|	'*' reg
+	{
+		$$ = $2;
+	}
+|	'*' omem
+	{
+		$$ = $2;
+	}
+|	reg
+|	omem
+
+rim:
+	rem
+|	imm
+
+rel:
+	con '(' LPC ')'
+	{
+		$$ = nullgen;
+		$$.type = D_BRANCH;
+		$$.offset = $1 + pc;
+	}
+|	LNAME offset
+	{
+		$$ = nullgen;
+		if(pass == 2)
+			yyerror("undefined label: %s", $1->name);
+		$$.type = D_BRANCH;
+		$$.offset = $2;
+	}
+|	LLAB offset
+	{
+		$$ = nullgen;
+		$$.type = D_BRANCH;
+		$$.offset = $1->value + $2;
+	}
+
+reg:
+	LBREG
+	{
+		$$ = nullgen;
+		$$.type = $1;
+	}
+|	LFREG
+	{
+		$$ = nullgen;
+		$$.type = $1;
+	}
+|	LLREG
+	{
+		$$ = nullgen;
+		$$.type = $1;
+	}
+|	LMREG
+	{
+		$$ = nullgen;
+		$$.type = $1;
+	}
+|	LSP
+	{
+		$$ = nullgen;
+		$$.type = D_SP;
+	}
+|	LSREG
+	{
+		$$ = nullgen;
+		$$.type = $1;
+	}
+|	LXREG
+	{
+		$$ = nullgen;
+		$$.type = $1;
+	}
+imm2:
+	'$' con2
+	{
+		$$ = nullgen;
+		$$.type = D_CONST;
+		$$.offset = $2;
+	}
+
+imm:
+	'$' con
+	{
+		$$ = nullgen;
+		$$.type = D_CONST;
+		$$.offset = $2;
+	}
+|	'$' nam
+	{
+		$$ = $2;
+		$$.index = $2.type;
+		$$.type = D_ADDR;
+		/*
+		if($2.type == D_AUTO || $2.type == D_PARAM)
+			yyerror("constant cannot be automatic: %s",
+				$2.sym->name);
+		 */
+	}
+|	'$' LSCONST
+	{
+		$$ = nullgen;
+		$$.type = D_SCONST;
+		memcpy($$.u.sval, $2, sizeof($$.u.sval));
+	}
+|	'$' LFCONST
+	{
+		$$ = nullgen;
+		$$.type = D_FCONST;
+		$$.u.dval = $2;
+	}
+|	'$' '(' LFCONST ')'
+	{
+		$$ = nullgen;
+		$$.type = D_FCONST;
+		$$.u.dval = $3;
+	}
+|	'$' '(' '-' LFCONST ')'
+	{
+		$$ = nullgen;
+		$$.type = D_FCONST;
+		$$.u.dval = -$4;
+	}
+|	'$' '-' LFCONST
+	{
+		$$ = nullgen;
+		$$.type = D_FCONST;
+		$$.u.dval = -$3;
+	}
+
+mem:
+	omem
+|	nmem
+
+omem:
+	con
+	{
+		$$ = nullgen;
+		$$.type = D_INDIR+D_NONE;
+		$$.offset = $1;
+	}
+|	con '(' LLREG ')'
+	{
+		$$ = nullgen;
+		$$.type = D_INDIR+$3;
+		$$.offset = $1;
+	}
+|	con '(' LSP ')'
+	{
+		$$ = nullgen;
+		$$.type = D_INDIR+D_SP;
+		$$.offset = $1;
+	}
+|	con '(' LSREG ')'
+	{
+		$$ = nullgen;
+		$$.type = D_INDIR+$3;
+		$$.offset = $1;
+	}
+|	con '(' LLREG '*' con ')'
+	{
+		$$ = nullgen;
+		$$.type = D_INDIR+D_NONE;
+		$$.offset = $1;
+		$$.index = $3;
+		$$.scale = $5;
+		checkscale($$.scale);
+	}
+|	con '(' LLREG ')' '(' LLREG '*' con ')'
+	{
+		$$ = nullgen;
+		$$.type = D_INDIR+$3;
+		$$.offset = $1;
+		$$.index = $6;
+		$$.scale = $8;
+		checkscale($$.scale);
+	}
+|	con '(' LLREG ')' '(' LSREG '*' con ')'
+	{
+		$$ = nullgen;
+		$$.type = D_INDIR+$3;
+		$$.offset = $1;
+		$$.index = $6;
+		$$.scale = $8;
+		checkscale($$.scale);
+	}
+|	'(' LLREG ')'
+	{
+		$$ = nullgen;
+		$$.type = D_INDIR+$2;
+	}
+|	'(' LSP ')'
+	{
+		$$ = nullgen;
+		$$.type = D_INDIR+D_SP;
+	}
+|	'(' LLREG '*' con ')'
+	{
+		$$ = nullgen;
+		$$.type = D_INDIR+D_NONE;
+		$$.index = $2;
+		$$.scale = $4;
+		checkscale($$.scale);
+	}
+|	'(' LLREG ')' '(' LLREG '*' con ')'
+	{
+		$$ = nullgen;
+		$$.type = D_INDIR+$2;
+		$$.index = $5;
+		$$.scale = $7;
+		checkscale($$.scale);
+	}
+
+nmem:
+	nam
+	{
+		$$ = $1;
+	}
+|	nam '(' LLREG '*' con ')'
+	{
+		$$ = $1;
+		$$.index = $3;
+		$$.scale = $5;
+		checkscale($$.scale);
+	}
+
+nam:
+	LNAME offset '(' pointer ')'
+	{
+		$$ = nullgen;
+		$$.type = $4;
+		$$.sym = linklookup(ctxt, $1->name, 0);
+		$$.offset = $2;
+	}
+|	LNAME '<' '>' offset '(' LSB ')'
+	{
+		$$ = nullgen;
+		$$.type = D_STATIC;
+		$$.sym = linklookup(ctxt, $1->name, 1);
+		$$.offset = $4;
+	}
+
+offset:
+	{
+		$$ = 0;
+	}
+|	'+' con
+	{
+		$$ = $2;
+	}
+|	'-' con
+	{
+		$$ = -$2;
+	}
+
+pointer:
+	LSB
+|	LSP
+	{
+		$$ = D_AUTO;
+	}
+|	LFP
+
+con:
+	LCONST
+|	LVAR
+	{
+		$$ = $1->value;
+	}
+|	'-' con
+	{
+		$$ = -$2;
+	}
+|	'+' con
+	{
+		$$ = $2;
+	}
+|	'~' con
+	{
+		$$ = ~$2;
+	}
+|	'(' expr ')'
+	{
+		$$ = $2;
+	}
+
+con2:
+	LCONST
+	{
+		$$ = ($1 & 0xffffffffLL) +
+			((vlong)ArgsSizeUnknown << 32);
+	}
+|	'-' LCONST
+	{
+		$$ = (-$2 & 0xffffffffLL) +
+			((vlong)ArgsSizeUnknown << 32);
+	}
+|	LCONST '-' LCONST
+	{
+		$$ = ($1 & 0xffffffffLL) +
+			(($3 & 0xffffLL) << 32);
+	}
+|	'-' LCONST '-' LCONST
+	{
+		$$ = (-$2 & 0xffffffffLL) +
+			(($4 & 0xffffLL) << 32);
+	}
+
+expr:
+	con
+|	expr '+' expr
+	{
+		$$ = $1 + $3;
+	}
+|	expr '-' expr
+	{
+		$$ = $1 - $3;
+	}
+|	expr '*' expr
+	{
+		$$ = $1 * $3;
+	}
+|	expr '/' expr
+	{
+		$$ = $1 / $3;
+	}
+|	expr '%' expr
+	{
+		$$ = $1 % $3;
+	}
+|	expr '<' '<' expr
+	{
+		$$ = $1 << $4;
+	}
+|	expr '>' '>' expr
+	{
+		$$ = $1 >> $4;
+	}
+|	expr '&' expr
+	{
+		$$ = $1 & $3;
+	}
+|	expr '^' expr
+	{
+		$$ = $1 ^ $3;
+	}
+|	expr '|' expr
+	{
+		$$ = $1 | $3;
+	}
diff --git a/src/cmd/6a/doc.go b/src/cmd/6a/doc.go
new file mode 100644
index 0000000..9f14cc0
--- /dev/null
+++ b/src/cmd/6a/doc.go
@@ -0,0 +1,20 @@
+// 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
+
+/*
+
+6a is a version of the Plan 9 assembler.  The original is documented at
+
+	http://plan9.bell-labs.com/magic/man2html/1/8a
+
+Go-specific considerations are documented at
+
+	http://golang.org/doc/asm
+
+Its target architecture is the x86-64, referred to by these tools as amd64.
+
+*/
+package main
diff --git a/src/cmd/6a/lex.c b/src/cmd/6a/lex.c
new file mode 100644
index 0000000..8973d69
--- /dev/null
+++ b/src/cmd/6a/lex.c
@@ -0,0 +1,1136 @@
+// Inferno utils/6a/lex.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6a/lex.c
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.	All rights reserved.
+//	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.
+
+#define	EXTERN
+#include <u.h>
+#include <libc.h>
+#include "a.h"
+#include "y.tab.h"
+
+enum
+{
+	Plan9	= 1<<0,
+	Unix	= 1<<1,
+	Windows	= 1<<2,
+};
+
+int
+systemtype(int sys)
+{
+#ifdef _WIN32
+	return sys&Windows;
+#else
+	return sys&Plan9;
+#endif
+}
+
+int
+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;
+
+	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;
+	ctxt->enforce_data_order = 1;
+	Binit(&bstdout, 1, OWRITE);
+	listinit6();
+	fmtinstall('L', Lconv);
+
+	ensuresymb(NSYMB);
+	memset(debug, 0, sizeof(debug));
+	cinit();
+	outfile = 0;
+	setinclude(".");
+	
+	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);
+}
+
+int
+assemble(char *file)
+{
+	char *ofile, *p;
+	int i, of;
+
+	ofile = alloc(strlen(file)+3); // +3 for .x\0 (x=thechar)
+	strcpy(ofile, file);
+	p = utfrrune(ofile, pathchar());
+	if(p) {
+		include[0] = ofile;
+		*p++ = 0;
+	} else
+		p = ofile;
+	if(outfile == 0) {
+		outfile = p;
+		if(outfile){
+			p = utfrrune(outfile, '.');
+			if(p)
+				if(p[1] == 's' && p[2] == 0)
+					p[0] = 0;
+			p = utfrune(outfile, 0);
+			p[0] = '.';
+			p[1] = thechar;
+			p[2] = 0;
+		} else
+			outfile = "/dev/null";
+	}
+
+	of = create(outfile, OWRITE, 0664);
+	if(of < 0) {
+		yyerror("%ca: cannot create %s", thechar, outfile);
+		errorexit();
+	}
+	Binit(&obuf, of, OWRITE);
+	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();
+		if(nerrors)
+			return nerrors;
+	}
+
+	writeobj(ctxt, &obuf);
+	Bflush(&obuf);
+	return 0;
+}
+
+struct
+{
+	char	*name;
+	/*
+	 * type is the lexical type to return.  It dictates what kind of
+	 * operands 6a allows to follow it (in a.y) as the possible operand
+	 * types are handled by a grammar.  How do you know which LTYPE?
+	 * Either read a.y or think of an instruction that has the same
+	 * possible operands and look up what it takes.
+	 */
+	ushort	type;
+	ushort	value;
+} itab[] =
+{
+	"SP",		LSP,	D_AUTO,
+	"SB",		LSB,	D_EXTERN,
+	"FP",		LFP,	D_PARAM,
+	"PC",		LPC,	D_BRANCH,
+
+	"AL",		LBREG,	D_AL,
+	"CL",		LBREG,	D_CL,
+	"DL",		LBREG,	D_DL,
+	"BL",		LBREG,	D_BL,
+/*	"SPB",		LBREG,	D_SPB,	*/
+	"SIB",		LBREG,	D_SIB,
+	"DIB",		LBREG,	D_DIB,
+	"BPB",		LBREG,	D_BPB,
+	"R8B",		LBREG,	D_R8B,
+	"R9B",		LBREG,	D_R9B,
+	"R10B",		LBREG,	D_R10B,
+	"R11B",		LBREG,	D_R11B,
+	"R12B",		LBREG,	D_R12B,
+	"R13B",		LBREG,	D_R13B,
+	"R14B",		LBREG,	D_R14B,
+	"R15B",		LBREG,	D_R15B,
+
+	"AH",		LBREG,	D_AH,
+	"CH",		LBREG,	D_CH,
+	"DH",		LBREG,	D_DH,
+	"BH",		LBREG,	D_BH,
+
+	"AX",		LLREG,	D_AX,
+	"CX",		LLREG,	D_CX,
+	"DX",		LLREG,	D_DX,
+	"BX",		LLREG,	D_BX,
+/*	"SP",		LLREG,	D_SP,	*/
+	"BP",		LLREG,	D_BP,
+	"SI",		LLREG,	D_SI,
+	"DI",		LLREG,	D_DI,
+	"R8",		LLREG,	D_R8,
+	"R9",		LLREG,	D_R9,
+	"R10",		LLREG,	D_R10,
+	"R11",		LLREG,	D_R11,
+	"R12",		LLREG,	D_R12,
+	"R13",		LLREG,	D_R13,
+	"R14",		LLREG,	D_R14,
+	"R15",		LLREG,	D_R15,
+
+	"RARG",		LLREG,	REGARG,
+
+	"F0",		LFREG,	D_F0+0,
+	"F1",		LFREG,	D_F0+1,
+	"F2",		LFREG,	D_F0+2,
+	"F3",		LFREG,	D_F0+3,
+	"F4",		LFREG,	D_F0+4,
+	"F5",		LFREG,	D_F0+5,
+	"F6",		LFREG,	D_F0+6,
+	"F7",		LFREG,	D_F0+7,
+
+	"M0",		LMREG,	D_M0+0,
+	"M1",		LMREG,	D_M0+1,
+	"M2",		LMREG,	D_M0+2,
+	"M3",		LMREG,	D_M0+3,
+	"M4",		LMREG,	D_M0+4,
+	"M5",		LMREG,	D_M0+5,
+	"M6",		LMREG,	D_M0+6,
+	"M7",		LMREG,	D_M0+7,
+
+	"X0",		LXREG,	D_X0+0,
+	"X1",		LXREG,	D_X0+1,
+	"X2",		LXREG,	D_X0+2,
+	"X3",		LXREG,	D_X0+3,
+	"X4",		LXREG,	D_X0+4,
+	"X5",		LXREG,	D_X0+5,
+	"X6",		LXREG,	D_X0+6,
+	"X7",		LXREG,	D_X0+7,
+	"X8",		LXREG,	D_X0+8,
+	"X9",		LXREG,	D_X0+9,
+	"X10",		LXREG,	D_X0+10,
+	"X11",		LXREG,	D_X0+11,
+	"X12",		LXREG,	D_X0+12,
+	"X13",		LXREG,	D_X0+13,
+	"X14",		LXREG,	D_X0+14,
+	"X15",		LXREG,	D_X0+15,
+
+	"CS",		LSREG,	D_CS,
+	"SS",		LSREG,	D_SS,
+	"DS",		LSREG,	D_DS,
+	"ES",		LSREG,	D_ES,
+	"FS",		LSREG,	D_FS,
+	"GS",		LSREG,	D_GS,
+
+	"GDTR",		LBREG,	D_GDTR,
+	"IDTR",		LBREG,	D_IDTR,
+	"LDTR",		LBREG,	D_LDTR,
+	"MSW",		LBREG,	D_MSW,
+	"TASK",		LBREG,	D_TASK,
+
+	"CR0",		LBREG,	D_CR+0,
+	"CR1",		LBREG,	D_CR+1,
+	"CR2",		LBREG,	D_CR+2,
+	"CR3",		LBREG,	D_CR+3,
+	"CR4",		LBREG,	D_CR+4,
+	"CR5",		LBREG,	D_CR+5,
+	"CR6",		LBREG,	D_CR+6,
+	"CR7",		LBREG,	D_CR+7,
+	"CR8",		LBREG,	D_CR+8,
+	"CR9",		LBREG,	D_CR+9,
+	"CR10",		LBREG,	D_CR+10,
+	"CR11",		LBREG,	D_CR+11,
+	"CR12",		LBREG,	D_CR+12,
+	"CR13",		LBREG,	D_CR+13,
+	"CR14",		LBREG,	D_CR+14,
+	"CR15",		LBREG,	D_CR+15,
+
+	"DR0",		LBREG,	D_DR+0,
+	"DR1",		LBREG,	D_DR+1,
+	"DR2",		LBREG,	D_DR+2,
+	"DR3",		LBREG,	D_DR+3,
+	"DR4",		LBREG,	D_DR+4,
+	"DR5",		LBREG,	D_DR+5,
+	"DR6",		LBREG,	D_DR+6,
+	"DR7",		LBREG,	D_DR+7,
+
+	"TR0",		LBREG,	D_TR+0,
+	"TR1",		LBREG,	D_TR+1,
+	"TR2",		LBREG,	D_TR+2,
+	"TR3",		LBREG,	D_TR+3,
+	"TR4",		LBREG,	D_TR+4,
+	"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,
+	"AAM",		LTYPE0,	AAAM,
+	"AAS",		LTYPE0,	AAAS,
+	"ADCB",		LTYPE3,	AADCB,
+	"ADCL",		LTYPE3,	AADCL,
+	"ADCQ",		LTYPE3,	AADCQ,
+	"ADCW",		LTYPE3,	AADCW,
+	"ADDB",		LTYPE3,	AADDB,
+	"ADDL",		LTYPE3,	AADDL,
+	"ADDQ",		LTYPE3,	AADDQ,
+	"ADDW",		LTYPE3,	AADDW,
+	"ADJSP",	LTYPE2,	AADJSP,
+	"ANDB",		LTYPE3,	AANDB,
+	"ANDL",		LTYPE3,	AANDL,
+	"ANDQ",		LTYPE3,	AANDQ,
+	"ANDW",		LTYPE3,	AANDW,
+	"ARPL",		LTYPE3,	AARPL,
+	"BOUNDL",	LTYPE3,	ABOUNDL,
+	"BOUNDW",	LTYPE3,	ABOUNDW,
+	"BSFL",		LTYPE3,	ABSFL,
+	"BSFQ",		LTYPE3,	ABSFQ,
+	"BSFW",		LTYPE3,	ABSFW,
+	"BSRL",		LTYPE3,	ABSRL,
+	"BSRQ",		LTYPE3,	ABSRQ,
+	"BSRW",		LTYPE3,	ABSRW,
+	"BSWAPL",	LTYPE1,	ABSWAPL,
+	"BSWAPQ",	LTYPE1,	ABSWAPQ,
+	"BTCL",		LTYPE3,	ABTCL,
+	"BTCQ",		LTYPE3,	ABTCQ,
+	"BTCW",		LTYPE3,	ABTCW,
+	"BTL",		LTYPE3,	ABTL,
+	"BTQ",		LTYPE3,	ABTQ,
+	"BTRL",		LTYPE3,	ABTRL,
+	"BTRQ",		LTYPE3,	ABTRQ,
+	"BTRW",		LTYPE3,	ABTRW,
+	"BTSL",		LTYPE3,	ABTSL,
+	"BTSQ",		LTYPE3,	ABTSQ,
+	"BTSW",		LTYPE3,	ABTSW,
+	"BTW",		LTYPE3,	ABTW,
+	"BYTE",		LTYPE2,	ABYTE,
+	"CALL",		LTYPEC,	ACALL,
+	"CLC",		LTYPE0,	ACLC,
+	"CLD",		LTYPE0,	ACLD,
+	"CLI",		LTYPE0,	ACLI,
+	"CLTS",		LTYPE0,	ACLTS,
+	"CMC",		LTYPE0,	ACMC,
+	"CMPB",		LTYPE4,	ACMPB,
+	"CMPL",		LTYPE4,	ACMPL,
+	"CMPQ",		LTYPE4,	ACMPQ,
+	"CMPW",		LTYPE4,	ACMPW,
+	"CMPSB",	LTYPE0,	ACMPSB,
+	"CMPSL",	LTYPE0,	ACMPSL,
+	"CMPSQ",	LTYPE0,	ACMPSQ,
+	"CMPSW",	LTYPE0,	ACMPSW,
+	"CMPXCHG8B",	LTYPE1,	ACMPXCHG8B,
+	"CMPXCHGB",	LTYPE3,	ACMPXCHGB,	/* LTYPE3? */
+	"CMPXCHGL",	LTYPE3,	ACMPXCHGL,
+	"CMPXCHGQ",	LTYPE3,	ACMPXCHGQ,
+	"CMPXCHGW",	LTYPE3,	ACMPXCHGW,
+	"CPUID",	LTYPE0,	ACPUID,
+	"DAA",		LTYPE0,	ADAA,
+	"DAS",		LTYPE0,	ADAS,
+	"DATA",		LTYPED,	ADATA,
+	"DECB",		LTYPE1,	ADECB,
+	"DECL",		LTYPE1,	ADECL,
+	"DECQ",		LTYPE1,	ADECQ,
+	"DECW",		LTYPE1,	ADECW,
+	"DIVB",		LTYPE2,	ADIVB,
+	"DIVL",		LTYPE2,	ADIVL,
+	"DIVQ",		LTYPE2,	ADIVQ,
+	"DIVW",		LTYPE2,	ADIVW,
+	"EMMS",		LTYPE0,	AEMMS,
+	"END",		LTYPE0,	AEND,
+	"ENTER",	LTYPE2,	AENTER,
+	"GLOBL",	LTYPEG,	AGLOBL,
+	"HLT",		LTYPE0,	AHLT,
+	"IDIVB",	LTYPE2,	AIDIVB,
+	"IDIVL",	LTYPE2,	AIDIVL,
+	"IDIVQ",	LTYPE2,	AIDIVQ,
+	"IDIVW",	LTYPE2,	AIDIVW,
+	"IMULB",	LTYPEI,	AIMULB,
+	"IMULL",	LTYPEI,	AIMULL,
+	"IMULQ",	LTYPEI,	AIMULQ,
+	"IMUL3Q",	LTYPEX,	AIMUL3Q,
+	"IMULW",	LTYPEI,	AIMULW,
+	"INB",		LTYPE0,	AINB,
+	"INL",		LTYPE0,	AINL,
+	"INW",		LTYPE0,	AINW,
+	"INCB",		LTYPE1,	AINCB,
+	"INCL",		LTYPE1,	AINCL,
+	"INCQ",		LTYPE1,	AINCQ,
+	"INCW",		LTYPE1,	AINCW,
+	"INSB",		LTYPE0,	AINSB,
+	"INSL",		LTYPE0,	AINSL,
+	"INSW",		LTYPE0,	AINSW,
+	"INT",		LTYPE2,	AINT,
+	"INTO",		LTYPE0,	AINTO,
+	"INVD",		LTYPE0,	AINVD,
+	"INVLPG",	LTYPE2,	AINVLPG,
+	"IRETL",	LTYPE0,	AIRETL,
+	"IRETQ",	LTYPE0,	AIRETQ,
+	"IRETW",	LTYPE0,	AIRETW,
+
+	"JOS",		LTYPER,	AJOS,	/* overflow set (OF = 1) */
+	"JO",		LTYPER,	AJOS,	/* alternate */
+	"JOC",		LTYPER,	AJOC,	/* overflow clear (OF = 0) */
+	"JNO",		LTYPER,	AJOC,	/* alternate */
+	"JCS",		LTYPER,	AJCS,	/* carry set (CF = 1) */
+	"JB",		LTYPER,	AJCS,	/* alternate */
+	"JC",		LTYPER,	AJCS,	/* alternate */
+	"JNAE",		LTYPER,	AJCS,	/* alternate */
+	"JLO",		LTYPER,	AJCS,	/* alternate */
+	"JCC",		LTYPER,	AJCC,	/* carry clear (CF = 0) */
+	"JAE",		LTYPER,	AJCC,	/* alternate */
+	"JNB",		LTYPER,	AJCC,	/* alternate */
+	"JNC",		LTYPER,	AJCC,	/* alternate */
+	"JHS",		LTYPER,	AJCC,	/* alternate */
+	"JEQ",		LTYPER,	AJEQ,	/* equal (ZF = 1) */
+	"JE",		LTYPER,	AJEQ,	/* alternate */
+	"JZ",		LTYPER,	AJEQ,	/* alternate */
+	"JNE",		LTYPER,	AJNE,	/* not equal (ZF = 0) */
+	"JNZ",		LTYPER,	AJNE,	/* alternate */
+	"JLS",		LTYPER,	AJLS,	/* lower or same (unsigned) (CF = 1 || ZF = 1) */
+	"JBE",		LTYPER,	AJLS,	/* alternate */
+	"JNA",		LTYPER,	AJLS,	/* alternate */
+	"JHI",		LTYPER,	AJHI,	/* higher (unsigned) (CF = 0 && ZF = 0) */
+	"JA",		LTYPER,	AJHI,	/* alternate */
+	"JNBE",		LTYPER,	AJHI,	/* alternate */
+	"JMI",		LTYPER,	AJMI,	/* negative (minus) (SF = 1) */
+	"JS",		LTYPER,	AJMI,	/* alternate */
+	"JPL",		LTYPER,	AJPL,	/* non-negative (plus) (SF = 0) */
+	"JNS",		LTYPER,	AJPL,	/* alternate */
+	"JPS",		LTYPER,	AJPS,	/* parity set (PF = 1) */
+	"JP",		LTYPER,	AJPS,	/* alternate */
+	"JPE",		LTYPER,	AJPS,	/* alternate */
+	"JPC",		LTYPER,	AJPC,	/* parity clear (PF = 0) */
+	"JNP",		LTYPER,	AJPC,	/* alternate */
+	"JPO",		LTYPER,	AJPC,	/* alternate */
+	"JLT",		LTYPER,	AJLT,	/* less than (signed) (SF != OF) */
+	"JL",		LTYPER,	AJLT,	/* alternate */
+	"JNGE",		LTYPER,	AJLT,	/* alternate */
+	"JGE",		LTYPER,	AJGE,	/* greater than or equal (signed) (SF = OF) */
+	"JNL",		LTYPER,	AJGE,	/* alternate */
+	"JLE",		LTYPER,	AJLE,	/* less than or equal (signed) (ZF = 1 || SF != OF) */
+	"JNG",		LTYPER,	AJLE,	/* alternate */
+	"JGT",		LTYPER,	AJGT,	/* greater than (signed) (ZF = 0 && SF = OF) */
+	"JG",		LTYPER,	AJGT,	/* alternate */
+	"JNLE",		LTYPER,	AJGT,	/* alternate */
+	"JCXZL",	LTYPER,	AJCXZL,
+	"JCXZQ",	LTYPER,	AJCXZQ,
+	"JMP",		LTYPEC,	AJMP,
+	"LAHF",		LTYPE0,	ALAHF,
+	"LARL",		LTYPE3,	ALARL,
+	"LARW",		LTYPE3,	ALARW,
+	"LEAL",		LTYPE3,	ALEAL,
+	"LEAQ",		LTYPE3,	ALEAQ,
+	"LEAW",		LTYPE3,	ALEAW,
+	"LEAVEL",	LTYPE0,	ALEAVEL,
+	"LEAVEQ",	LTYPE0,	ALEAVEQ,
+	"LEAVEW",	LTYPE0,	ALEAVEW,
+	"LFENCE",	LTYPE0,	ALFENCE,
+	"LOCK",		LTYPE0,	ALOCK,
+	"LODSB",	LTYPE0,	ALODSB,
+	"LODSL",	LTYPE0,	ALODSL,
+	"LODSQ",	LTYPE0,	ALODSQ,
+	"LODSW",	LTYPE0,	ALODSW,
+	"LONG",		LTYPE2,	ALONG,
+	"LOOP",		LTYPER,	ALOOP,
+	"LOOPEQ",	LTYPER,	ALOOPEQ,
+	"LOOPNE",	LTYPER,	ALOOPNE,
+	"LSLL",		LTYPE3,	ALSLL,
+	"LSLW",		LTYPE3,	ALSLW,
+	"MFENCE",	LTYPE0,	AMFENCE,
+	"MODE",		LTYPE2,	AMODE,
+	"MOVB",		LTYPE3,	AMOVB,
+	"MOVL",		LTYPEM,	AMOVL,
+	"MOVQ",		LTYPEM,	AMOVQ,
+	"MOVW",		LTYPEM,	AMOVW,
+	"MOVBLSX",	LTYPE3, AMOVBLSX,
+	"MOVBLZX",	LTYPE3, AMOVBLZX,
+	"MOVBQSX",	LTYPE3,	AMOVBQSX,
+	"MOVBQZX",	LTYPE3,	AMOVBQZX,
+	"MOVBWSX",	LTYPE3, AMOVBWSX,
+	"MOVBWZX",	LTYPE3, AMOVBWZX,
+	"MOVLQSX",	LTYPE3, AMOVLQSX,
+	"MOVLQZX",	LTYPE3, AMOVLQZX,
+	"MOVNTIL",	LTYPE3,	AMOVNTIL,
+	"MOVNTIQ",	LTYPE3,	AMOVNTIQ,
+	"MOVQL",	LTYPE3, AMOVQL,
+	"MOVWLSX",	LTYPE3, AMOVWLSX,
+	"MOVWLZX",	LTYPE3, AMOVWLZX,
+	"MOVWQSX",	LTYPE3,	AMOVWQSX,
+	"MOVWQZX",	LTYPE3,	AMOVWQZX,
+	"MOVSB",	LTYPE0,	AMOVSB,
+	"MOVSL",	LTYPE0,	AMOVSL,
+	"MOVSQ",	LTYPE0,	AMOVSQ,
+	"MOVSW",	LTYPE0,	AMOVSW,
+	"MULB",		LTYPE2,	AMULB,
+	"MULL",		LTYPE2,	AMULL,
+	"MULQ",		LTYPE2,	AMULQ,
+	"MULW",		LTYPE2,	AMULW,
+	"NEGB",		LTYPE1,	ANEGB,
+	"NEGL",		LTYPE1,	ANEGL,
+	"NEGQ",		LTYPE1,	ANEGQ,
+	"NEGW",		LTYPE1,	ANEGW,
+	"NOP",		LTYPEN,	ANOP,
+	"NOTB",		LTYPE1,	ANOTB,
+	"NOTL",		LTYPE1,	ANOTL,
+	"NOTQ",		LTYPE1,	ANOTQ,
+	"NOTW",		LTYPE1,	ANOTW,
+	"ORB",		LTYPE3,	AORB,
+	"ORL",		LTYPE3,	AORL,
+	"ORQ",		LTYPE3,	AORQ,
+	"ORW",		LTYPE3,	AORW,
+	"OUTB",		LTYPE0,	AOUTB,
+	"OUTL",		LTYPE0,	AOUTL,
+	"OUTW",		LTYPE0,	AOUTW,
+	"OUTSB",	LTYPE0,	AOUTSB,
+	"OUTSL",	LTYPE0,	AOUTSL,
+	"OUTSW",	LTYPE0,	AOUTSW,
+	"PAUSE",	LTYPEN,	APAUSE,
+	"POPAL",	LTYPE0,	APOPAL,
+	"POPAW",	LTYPE0,	APOPAW,
+	"POPFL",	LTYPE0,	APOPFL,
+	"POPFQ",	LTYPE0,	APOPFQ,
+	"POPFW",	LTYPE0,	APOPFW,
+	"POPL",		LTYPE1,	APOPL,
+	"POPQ",		LTYPE1,	APOPQ,
+	"POPW",		LTYPE1,	APOPW,
+	"PUSHAL",	LTYPE0,	APUSHAL,
+	"PUSHAW",	LTYPE0,	APUSHAW,
+	"PUSHFL",	LTYPE0,	APUSHFL,
+	"PUSHFQ",	LTYPE0,	APUSHFQ,
+	"PUSHFW",	LTYPE0,	APUSHFW,
+	"PUSHL",	LTYPE2,	APUSHL,
+	"PUSHQ",	LTYPE2,	APUSHQ,
+	"PUSHW",	LTYPE2,	APUSHW,
+	"RCLB",		LTYPE3,	ARCLB,
+	"RCLL",		LTYPE3,	ARCLL,
+	"RCLQ",		LTYPE3,	ARCLQ,
+	"RCLW",		LTYPE3,	ARCLW,
+	"RCRB",		LTYPE3,	ARCRB,
+	"RCRL",		LTYPE3,	ARCRL,
+	"RCRQ",		LTYPE3,	ARCRQ,
+	"RCRW",		LTYPE3,	ARCRW,
+	"RDMSR",	LTYPE0,	ARDMSR,
+	"RDPMC",	LTYPE0,	ARDPMC,
+	"RDTSC",	LTYPE0,	ARDTSC,
+	"REP",		LTYPE0,	AREP,
+	"REPN",		LTYPE0,	AREPN,
+	"RET",		LTYPE0,	ARET,
+	"RETFL",	LTYPERT,ARETFL,
+	"RETFW",	LTYPERT,ARETFW,
+	"RETFQ",	LTYPERT,ARETFQ,
+	"ROLB",		LTYPE3,	AROLB,
+	"ROLL",		LTYPE3,	AROLL,
+	"ROLQ",		LTYPE3,	AROLQ,
+	"ROLW",		LTYPE3,	AROLW,
+	"RORB",		LTYPE3,	ARORB,
+	"RORL",		LTYPE3,	ARORL,
+	"RORQ",		LTYPE3,	ARORQ,
+	"RORW",		LTYPE3,	ARORW,
+	"RSM",		LTYPE0,	ARSM,
+	"SAHF",		LTYPE0,	ASAHF,
+	"SALB",		LTYPE3,	ASALB,
+	"SALL",		LTYPE3,	ASALL,
+	"SALQ",		LTYPE3,	ASALQ,
+	"SALW",		LTYPE3,	ASALW,
+	"SARB",		LTYPE3,	ASARB,
+	"SARL",		LTYPE3,	ASARL,
+	"SARQ",		LTYPE3,	ASARQ,
+	"SARW",		LTYPE3,	ASARW,
+	"SBBB",		LTYPE3,	ASBBB,
+	"SBBL",		LTYPE3,	ASBBL,
+	"SBBQ",		LTYPE3,	ASBBQ,
+	"SBBW",		LTYPE3,	ASBBW,
+	"SCASB",	LTYPE0,	ASCASB,
+	"SCASL",	LTYPE0,	ASCASL,
+	"SCASQ",	LTYPE0,	ASCASQ,
+	"SCASW",	LTYPE0,	ASCASW,
+	"SETCC",	LTYPE1,	ASETCC,	/* see JCC etc above for condition codes */
+	"SETCS",	LTYPE1,	ASETCS,
+	"SETEQ",	LTYPE1,	ASETEQ,
+	"SETGE",	LTYPE1,	ASETGE,
+	"SETGT",	LTYPE1,	ASETGT,
+	"SETHI",	LTYPE1,	ASETHI,
+	"SETLE",	LTYPE1,	ASETLE,
+	"SETLS",	LTYPE1,	ASETLS,
+	"SETLT",	LTYPE1,	ASETLT,
+	"SETMI",	LTYPE1,	ASETMI,
+	"SETNE",	LTYPE1,	ASETNE,
+	"SETOC",	LTYPE1,	ASETOC,
+	"SETOS",	LTYPE1,	ASETOS,
+	"SETPC",	LTYPE1,	ASETPC,
+	"SETPL",	LTYPE1,	ASETPL,
+	"SETPS",	LTYPE1,	ASETPS,
+	"SFENCE",	LTYPE0,	ASFENCE,
+	"CDQ",		LTYPE0,	ACDQ,
+	"CWD",		LTYPE0,	ACWD,
+	"CQO",		LTYPE0,	ACQO,
+	"SHLB",		LTYPE3,	ASHLB,
+	"SHLL",		LTYPES,	ASHLL,
+	"SHLQ",		LTYPES,	ASHLQ,
+	"SHLW",		LTYPES,	ASHLW,
+	"SHRB",		LTYPE3,	ASHRB,
+	"SHRL",		LTYPES,	ASHRL,
+	"SHRQ",		LTYPES,	ASHRQ,
+	"SHRW",		LTYPES,	ASHRW,
+	"STC",		LTYPE0,	ASTC,
+	"STD",		LTYPE0,	ASTD,
+	"STI",		LTYPE0,	ASTI,
+	"STOSB",	LTYPE0,	ASTOSB,
+	"STOSL",	LTYPE0,	ASTOSL,
+	"STOSQ",	LTYPE0,	ASTOSQ,
+	"STOSW",	LTYPE0,	ASTOSW,
+	"SUBB",		LTYPE3,	ASUBB,
+	"SUBL",		LTYPE3,	ASUBL,
+	"SUBQ",		LTYPE3,	ASUBQ,
+	"SUBW",		LTYPE3,	ASUBW,
+	"SYSCALL",	LTYPE0,	ASYSCALL,
+	"SYSRET",	LTYPE0,	ASYSRET,
+	"SWAPGS",	LTYPE0,	ASWAPGS,
+	"TESTB",	LTYPE3,	ATESTB,
+	"TESTL",	LTYPE3,	ATESTL,
+	"TESTQ",	LTYPE3,	ATESTQ,
+	"TESTW",	LTYPE3,	ATESTW,
+	"TEXT",		LTYPET,	ATEXT,
+	"VERR",		LTYPE2,	AVERR,
+	"VERW",		LTYPE2,	AVERW,
+	"QUAD",		LTYPE2,	AQUAD,
+	"WAIT",		LTYPE0,	AWAIT,
+	"WBINVD",	LTYPE0,	AWBINVD,
+	"WRMSR",	LTYPE0,	AWRMSR,
+	"WORD",		LTYPE2,	AWORD,
+	"XADDB",	LTYPE3,	AXADDB,
+	"XADDL",	LTYPE3,	AXADDL,
+	"XADDQ",	LTYPE3,	AXADDQ,
+	"XADDW",	LTYPE3,	AXADDW,
+	"XCHGB",	LTYPE3,	AXCHGB,
+	"XCHGL",	LTYPE3,	AXCHGL,
+	"XCHGQ",	LTYPE3,	AXCHGQ,
+	"XCHGW",	LTYPE3,	AXCHGW,
+	"XLAT",		LTYPE2,	AXLAT,
+	"XORB",		LTYPE3,	AXORB,
+	"XORL",		LTYPE3,	AXORL,
+	"XORQ",		LTYPE3,	AXORQ,
+	"XORW",		LTYPE3,	AXORW,
+
+	"CMOVLCC",	LTYPE3,	ACMOVLCC,
+	"CMOVLCS",	LTYPE3,	ACMOVLCS,
+	"CMOVLEQ",	LTYPE3,	ACMOVLEQ,
+	"CMOVLGE",	LTYPE3,	ACMOVLGE,
+	"CMOVLGT",	LTYPE3,	ACMOVLGT,
+	"CMOVLHI",	LTYPE3,	ACMOVLHI,
+	"CMOVLLE",	LTYPE3,	ACMOVLLE,
+	"CMOVLLS",	LTYPE3,	ACMOVLLS,
+	"CMOVLLT",	LTYPE3,	ACMOVLLT,
+	"CMOVLMI",	LTYPE3,	ACMOVLMI,
+	"CMOVLNE",	LTYPE3,	ACMOVLNE,
+	"CMOVLOC",	LTYPE3,	ACMOVLOC,
+	"CMOVLOS",	LTYPE3,	ACMOVLOS,
+	"CMOVLPC",	LTYPE3,	ACMOVLPC,
+	"CMOVLPL",	LTYPE3,	ACMOVLPL,
+	"CMOVLPS",	LTYPE3,	ACMOVLPS,
+	"CMOVQCC",	LTYPE3,	ACMOVQCC,
+	"CMOVQCS",	LTYPE3,	ACMOVQCS,
+	"CMOVQEQ",	LTYPE3,	ACMOVQEQ,
+	"CMOVQGE",	LTYPE3,	ACMOVQGE,
+	"CMOVQGT",	LTYPE3,	ACMOVQGT,
+	"CMOVQHI",	LTYPE3,	ACMOVQHI,
+	"CMOVQLE",	LTYPE3,	ACMOVQLE,
+	"CMOVQLS",	LTYPE3,	ACMOVQLS,
+	"CMOVQLT",	LTYPE3,	ACMOVQLT,
+	"CMOVQMI",	LTYPE3,	ACMOVQMI,
+	"CMOVQNE",	LTYPE3,	ACMOVQNE,
+	"CMOVQOC",	LTYPE3,	ACMOVQOC,
+	"CMOVQOS",	LTYPE3,	ACMOVQOS,
+	"CMOVQPC",	LTYPE3,	ACMOVQPC,
+	"CMOVQPL",	LTYPE3,	ACMOVQPL,
+	"CMOVQPS",	LTYPE3,	ACMOVQPS,
+	"CMOVWCC",	LTYPE3,	ACMOVWCC,
+	"CMOVWCS",	LTYPE3,	ACMOVWCS,
+	"CMOVWEQ",	LTYPE3,	ACMOVWEQ,
+	"CMOVWGE",	LTYPE3,	ACMOVWGE,
+	"CMOVWGT",	LTYPE3,	ACMOVWGT,
+	"CMOVWHI",	LTYPE3,	ACMOVWHI,
+	"CMOVWLE",	LTYPE3,	ACMOVWLE,
+	"CMOVWLS",	LTYPE3,	ACMOVWLS,
+	"CMOVWLT",	LTYPE3,	ACMOVWLT,
+	"CMOVWMI",	LTYPE3,	ACMOVWMI,
+	"CMOVWNE",	LTYPE3,	ACMOVWNE,
+	"CMOVWOC",	LTYPE3,	ACMOVWOC,
+	"CMOVWOS",	LTYPE3,	ACMOVWOS,
+	"CMOVWPC",	LTYPE3,	ACMOVWPC,
+	"CMOVWPL",	LTYPE3,	ACMOVWPL,
+	"CMOVWPS",	LTYPE3,	ACMOVWPS,
+
+	"FMOVB",	LTYPE3, AFMOVB,
+	"FMOVBP",	LTYPE3, AFMOVBP,
+	"FMOVD",	LTYPE3, AFMOVD,
+	"FMOVDP",	LTYPE3, AFMOVDP,
+	"FMOVF",	LTYPE3, AFMOVF,
+	"FMOVFP",	LTYPE3, AFMOVFP,
+	"FMOVL",	LTYPE3, AFMOVL,
+	"FMOVLP",	LTYPE3, AFMOVLP,
+	"FMOVV",	LTYPE3, AFMOVV,
+	"FMOVVP",	LTYPE3, AFMOVVP,
+	"FMOVW",	LTYPE3, AFMOVW,
+	"FMOVWP",	LTYPE3, AFMOVWP,
+	"FMOVX",	LTYPE3, AFMOVX,
+	"FMOVXP",	LTYPE3, AFMOVXP,
+	"FCOMB",	LTYPE3, AFCOMB,
+	"FCOMBP",	LTYPE3, AFCOMBP,
+	"FCOMD",	LTYPE3, AFCOMD,
+	"FCOMDP",	LTYPE3, AFCOMDP,
+	"FCOMDPP",	LTYPE3, AFCOMDPP,
+	"FCOMF",	LTYPE3, AFCOMF,
+	"FCOMFP",	LTYPE3, AFCOMFP,
+	"FCOML",	LTYPE3, AFCOML,
+	"FCOMLP",	LTYPE3, AFCOMLP,
+	"FCOMW",	LTYPE3, AFCOMW,
+	"FCOMWP",	LTYPE3, AFCOMWP,
+	"FUCOM",	LTYPE3, AFUCOM,
+	"FUCOMP",	LTYPE3, AFUCOMP,
+	"FUCOMPP",	LTYPE3, AFUCOMPP,
+	"FADDW",	LTYPE3, AFADDW,
+	"FADDL",	LTYPE3, AFADDL,
+	"FADDF",	LTYPE3, AFADDF,
+	"FADDD",	LTYPE3, AFADDD,
+	"FADDDP",	LTYPE3, AFADDDP,
+	"FSUBDP",	LTYPE3, AFSUBDP,
+	"FSUBW",	LTYPE3, AFSUBW,
+	"FSUBL",	LTYPE3, AFSUBL,
+	"FSUBF",	LTYPE3, AFSUBF,
+	"FSUBD",	LTYPE3, AFSUBD,
+	"FSUBRDP",	LTYPE3, AFSUBRDP,
+	"FSUBRW",	LTYPE3, AFSUBRW,
+	"FSUBRL",	LTYPE3, AFSUBRL,
+	"FSUBRF",	LTYPE3, AFSUBRF,
+	"FSUBRD",	LTYPE3, AFSUBRD,
+	"FMULDP",	LTYPE3, AFMULDP,
+	"FMULW",	LTYPE3, AFMULW,
+	"FMULL",	LTYPE3, AFMULL,
+	"FMULF",	LTYPE3, AFMULF,
+	"FMULD",	LTYPE3, AFMULD,
+	"FDIVDP",	LTYPE3, AFDIVDP,
+	"FDIVW",	LTYPE3, AFDIVW,
+	"FDIVL",	LTYPE3, AFDIVL,
+	"FDIVF",	LTYPE3, AFDIVF,
+	"FDIVD",	LTYPE3, AFDIVD,
+	"FDIVRDP",	LTYPE3, AFDIVRDP,
+	"FDIVRW",	LTYPE3, AFDIVRW,
+	"FDIVRL",	LTYPE3, AFDIVRL,
+	"FDIVRF",	LTYPE3, AFDIVRF,
+	"FDIVRD",	LTYPE3, AFDIVRD,
+	"FXCHD",	LTYPE3, AFXCHD,
+	"FFREE",	LTYPE1, AFFREE,
+	"FLDCW",	LTYPE2, AFLDCW,
+	"FLDENV",	LTYPE1, AFLDENV,
+	"FRSTOR",	LTYPE2, AFRSTOR,
+	"FSAVE",	LTYPE1, AFSAVE,
+	"FSTCW",	LTYPE1, AFSTCW,
+	"FSTENV",	LTYPE1, AFSTENV,
+	"FSTSW",	LTYPE1, AFSTSW,
+	"F2XM1",	LTYPE0, AF2XM1,
+	"FABS",		LTYPE0, AFABS,
+	"FCHS",		LTYPE0, AFCHS,
+	"FCLEX",	LTYPE0, AFCLEX,
+	"FCOS",		LTYPE0, AFCOS,
+	"FDECSTP",	LTYPE0, AFDECSTP,
+	"FINCSTP",	LTYPE0, AFINCSTP,
+	"FINIT",	LTYPE0, AFINIT,
+	"FLD1",		LTYPE0, AFLD1,
+	"FLDL2E",	LTYPE0, AFLDL2E,
+	"FLDL2T",	LTYPE0, AFLDL2T,
+	"FLDLG2",	LTYPE0, AFLDLG2,
+	"FLDLN2",	LTYPE0, AFLDLN2,
+	"FLDPI",	LTYPE0, AFLDPI,
+	"FLDZ",		LTYPE0, AFLDZ,
+	"FNOP",		LTYPE0, AFNOP,
+	"FPATAN",	LTYPE0, AFPATAN,
+	"FPREM",	LTYPE0, AFPREM,
+	"FPREM1",	LTYPE0, AFPREM1,
+	"FPTAN",	LTYPE0, AFPTAN,
+	"FRNDINT",	LTYPE0, AFRNDINT,
+	"FSCALE",	LTYPE0, AFSCALE,
+	"FSIN",		LTYPE0, AFSIN,
+	"FSINCOS",	LTYPE0, AFSINCOS,
+	"FSQRT",	LTYPE0, AFSQRT,
+	"FTST",		LTYPE0, AFTST,
+	"FXAM",		LTYPE0, AFXAM,
+	"FXTRACT",	LTYPE0, AFXTRACT,
+	"FYL2X",	LTYPE0, AFYL2X,
+	"FYL2XP1",	LTYPE0, AFYL2XP1,
+
+	"ADDPD",	LTYPE3,	AADDPD,
+	"ADDPS",	LTYPE3,	AADDPS,
+	"ADDSD",	LTYPE3,	AADDSD,
+	"ADDSS",	LTYPE3,	AADDSS,
+	"ANDNPD",	LTYPE3,	AANDNPD,
+	"ANDNPS",	LTYPE3,	AANDNPS,
+	"ANDPD",	LTYPE3,	AANDPD,
+	"ANDPS",	LTYPE3,	AANDPS,
+	"CMPPD",	LTYPEXC,ACMPPD,
+	"CMPPS",	LTYPEXC,ACMPPS,
+	"CMPSD",	LTYPEXC,ACMPSD,
+	"CMPSS",	LTYPEXC,ACMPSS,
+	"COMISD",	LTYPE3,	ACOMISD,
+	"COMISS",	LTYPE3,	ACOMISS,
+	"CVTPL2PD",	LTYPE3,	ACVTPL2PD,
+	"CVTPL2PS",	LTYPE3,	ACVTPL2PS,
+	"CVTPD2PL",	LTYPE3,	ACVTPD2PL,
+	"CVTPD2PS",	LTYPE3,	ACVTPD2PS,
+	"CVTPS2PL",	LTYPE3,	ACVTPS2PL,
+	"PF2IW",	LTYPE3,	APF2IW,
+	"PF2IL",	LTYPE3,	APF2IL,
+	"PF2ID",	LTYPE3,	APF2IL,	/* syn */
+	"PI2FL",	LTYPE3,	API2FL,
+	"PI2FD",	LTYPE3,	API2FL,	/* syn */
+	"PI2FW",	LTYPE3,	API2FW,
+	"CVTPS2PD",	LTYPE3,	ACVTPS2PD,
+	"CVTSD2SL",	LTYPE3,	ACVTSD2SL,
+	"CVTSD2SQ",	LTYPE3,	ACVTSD2SQ,
+	"CVTSD2SS",	LTYPE3,	ACVTSD2SS,
+	"CVTSL2SD",	LTYPE3,	ACVTSL2SD,
+	"CVTSQ2SD",	LTYPE3,	ACVTSQ2SD,
+	"CVTSL2SS",	LTYPE3,	ACVTSL2SS,
+	"CVTSQ2SS",	LTYPE3,	ACVTSQ2SS,
+	"CVTSS2SD",	LTYPE3,	ACVTSS2SD,
+	"CVTSS2SL",	LTYPE3,	ACVTSS2SL,
+	"CVTSS2SQ",	LTYPE3,	ACVTSS2SQ,
+	"CVTTPD2PL",	LTYPE3,	ACVTTPD2PL,
+	"CVTTPS2PL",	LTYPE3,	ACVTTPS2PL,
+	"CVTTSD2SL",	LTYPE3,	ACVTTSD2SL,
+	"CVTTSD2SQ",	LTYPE3,	ACVTTSD2SQ,
+	"CVTTSS2SL",	LTYPE3,	ACVTTSS2SL,
+	"CVTTSS2SQ",	LTYPE3,	ACVTTSS2SQ,
+	"DIVPD",	LTYPE3,	ADIVPD,
+	"DIVPS",	LTYPE3,	ADIVPS,
+	"DIVSD",	LTYPE3,	ADIVSD,
+	"DIVSS",	LTYPE3,	ADIVSS,
+	"FXRSTOR",	LTYPE2,	AFXRSTOR,
+	"FXRSTOR64",	LTYPE2,	AFXRSTOR64,
+	"FXSAVE",	LTYPE1,	AFXSAVE,
+	"FXSAVE64",	LTYPE1,	AFXSAVE64,
+	"LDMXCSR",	LTYPE2,	ALDMXCSR,
+	"MASKMOVOU",	LTYPE3,	AMASKMOVOU,
+	"MASKMOVDQU",	LTYPE3,	AMASKMOVOU,	/* syn */
+	"MASKMOVQ",	LTYPE3,	AMASKMOVQ,
+	"MAXPD",	LTYPE3,	AMAXPD,
+	"MAXPS",	LTYPE3,	AMAXPS,
+	"MAXSD",	LTYPE3,	AMAXSD,
+	"MAXSS",	LTYPE3,	AMAXSS,
+	"MINPD",	LTYPE3,	AMINPD,
+	"MINPS",	LTYPE3,	AMINPS,
+	"MINSD",	LTYPE3,	AMINSD,
+	"MINSS",	LTYPE3,	AMINSS,
+	"MOVAPD",	LTYPE3,	AMOVAPD,
+	"MOVAPS",	LTYPE3,	AMOVAPS,
+	"MOVD",		LTYPE3,	AMOVQ,	/* syn */
+	"MOVDQ2Q",	LTYPE3,	AMOVQ,	/* syn */
+	"MOVO",		LTYPE3,	AMOVO,
+	"MOVOA",	LTYPE3,	AMOVO,	/* syn */
+	"MOVOU",	LTYPE3,	AMOVOU,
+	"MOVHLPS",	LTYPE3,	AMOVHLPS,
+	"MOVHPD",	LTYPE3,	AMOVHPD,
+	"MOVHPS",	LTYPE3,	AMOVHPS,
+	"MOVLHPS",	LTYPE3,	AMOVLHPS,
+	"MOVLPD",	LTYPE3,	AMOVLPD,
+	"MOVLPS",	LTYPE3,	AMOVLPS,
+	"MOVMSKPD",	LTYPE3,	AMOVMSKPD,
+	"MOVMSKPS",	LTYPE3,	AMOVMSKPS,
+	"MOVNTO",	LTYPE3,	AMOVNTO,
+	"MOVNTDQ",	LTYPE3,	AMOVNTO,	/* syn */
+	"MOVNTPD",	LTYPE3,	AMOVNTPD,
+	"MOVNTPS",	LTYPE3,	AMOVNTPS,
+	"MOVNTQ",	LTYPE3,	AMOVNTQ,
+	"MOVQOZX",	LTYPE3,	AMOVQOZX,
+	"MOVSD",	LTYPE3,	AMOVSD,
+	"MOVSS",	LTYPE3,	AMOVSS,
+	"MOVUPD",	LTYPE3,	AMOVUPD,
+	"MOVUPS",	LTYPE3,	AMOVUPS,
+	"MULPD",	LTYPE3,	AMULPD,
+	"MULPS",	LTYPE3,	AMULPS,
+	"MULSD",	LTYPE3,	AMULSD,
+	"MULSS",	LTYPE3,	AMULSS,
+	"ORPD",		LTYPE3,	AORPD,
+	"ORPS",		LTYPE3,	AORPS,
+	"PACKSSLW",	LTYPE3,	APACKSSLW,
+	"PACKSSWB",	LTYPE3,	APACKSSWB,
+	"PACKUSWB",	LTYPE3,	APACKUSWB,
+	"PADDB",	LTYPE3,	APADDB,
+	"PADDL",	LTYPE3,	APADDL,
+	"PADDQ",	LTYPE3,	APADDQ,
+	"PADDSB",	LTYPE3,	APADDSB,
+	"PADDSW",	LTYPE3,	APADDSW,
+	"PADDUSB",	LTYPE3,	APADDUSB,
+	"PADDUSW",	LTYPE3,	APADDUSW,
+	"PADDW",	LTYPE3,	APADDW,
+	"PAND",		LTYPE3, APAND,
+	"PANDB",	LTYPE3,	APANDB,
+	"PANDL",	LTYPE3,	APANDL,
+	"PANDSB",	LTYPE3,	APANDSB,
+	"PANDSW",	LTYPE3,	APANDSW,
+	"PANDUSB",	LTYPE3,	APANDUSB,
+	"PANDUSW",	LTYPE3,	APANDUSW,
+	"PANDW",	LTYPE3,	APANDW,
+	"PANDN",	LTYPE3, APANDN,
+	"PAVGB",	LTYPE3,	APAVGB,
+	"PAVGW",	LTYPE3,	APAVGW,
+	"PCMPEQB",	LTYPE3,	APCMPEQB,
+	"PCMPEQL",	LTYPE3,	APCMPEQL,
+	"PCMPEQW",	LTYPE3,	APCMPEQW,
+	"PCMPGTB",	LTYPE3,	APCMPGTB,
+	"PCMPGTL",	LTYPE3,	APCMPGTL,	
+	"PCMPGTW",	LTYPE3,	APCMPGTW,
+	"PEXTRW",	LTYPEX,	APEXTRW,
+	"PINSRW",	LTYPEX,	APINSRW,
+	"PINSRD",	LTYPEX,	APINSRD,
+	"PINSRQ",	LTYPEX,	APINSRQ,
+	"PMADDWL",	LTYPE3,	APMADDWL,
+	"PMAXSW",	LTYPE3,	APMAXSW,
+	"PMAXUB",	LTYPE3,	APMAXUB,
+	"PMINSW",	LTYPE3,	APMINSW,
+	"PMINUB",	LTYPE3,	APMINUB,
+	"PMOVMSKB",	LTYPE3,	APMOVMSKB,
+	"PMULHRW",	LTYPE3,	APMULHRW,
+	"PMULHUW",	LTYPE3,	APMULHUW,
+	"PMULHW",	LTYPE3,	APMULHW,
+	"PMULLW",	LTYPE3,	APMULLW,
+	"PMULULQ",	LTYPE3,	APMULULQ,
+	"POR",		LTYPE3,	APOR,
+	"PSADBW",	LTYPE3,	APSADBW,
+	"PSHUFHW",	LTYPEX,	APSHUFHW,
+	"PSHUFL",	LTYPEX,	APSHUFL,
+	"PSHUFLW",	LTYPEX,	APSHUFLW,
+	"PSHUFW",	LTYPEX, APSHUFW,
+	"PSHUFB",	LTYPEM, APSHUFB,
+	"PSLLO",	LTYPE3,	APSLLO,
+	"PSLLDQ",	LTYPE3,	APSLLO,	/* syn */
+	"PSLLL",	LTYPE3,	APSLLL,
+	"PSLLQ",	LTYPE3,	APSLLQ,
+	"PSLLW",	LTYPE3,	APSLLW,
+	"PSRAL",	LTYPE3,	APSRAL,
+	"PSRAW",	LTYPE3,	APSRAW,
+	"PSRLO",	LTYPE3,	APSRLO,
+	"PSRLDQ",	LTYPE3,	APSRLO,	/* syn */
+	"PSRLL",	LTYPE3,	APSRLL,
+	"PSRLQ",	LTYPE3,	APSRLQ,
+	"PSRLW",	LTYPE3,	APSRLW,
+	"PSUBB",	LTYPE3,	APSUBB,
+	"PSUBL",	LTYPE3,	APSUBL,
+	"PSUBQ",	LTYPE3,	APSUBQ,
+	"PSUBSB",	LTYPE3,	APSUBSB,
+	"PSUBSW",	LTYPE3,	APSUBSW,
+	"PSUBUSB",	LTYPE3,	APSUBUSB,
+	"PSUBUSW",	LTYPE3,	APSUBUSW,
+	"PSUBW",	LTYPE3,	APSUBW,
+	"PUNPCKHBW",	LTYPE3,	APUNPCKHBW,
+	"PUNPCKHLQ",	LTYPE3,	APUNPCKHLQ,
+	"PUNPCKHQDQ",	LTYPE3,	APUNPCKHQDQ,
+	"PUNPCKHWL",	LTYPE3,	APUNPCKHWL,
+	"PUNPCKLBW",	LTYPE3,	APUNPCKLBW,
+	"PUNPCKLLQ",	LTYPE3,	APUNPCKLLQ,
+	"PUNPCKLQDQ",	LTYPE3,	APUNPCKLQDQ,
+	"PUNPCKLWL",	LTYPE3,	APUNPCKLWL,
+	"PXOR",		LTYPE3,	APXOR,
+	"RCPPS",	LTYPE3,	ARCPPS,
+	"RCPSS",	LTYPE3,	ARCPSS,
+	"RSQRTPS",	LTYPE3,	ARSQRTPS,
+	"RSQRTSS",	LTYPE3,	ARSQRTSS,
+	"SHUFPD",	LTYPEX,	ASHUFPD,
+	"SHUFPS",	LTYPEX,	ASHUFPS,
+	"SQRTPD",	LTYPE3,	ASQRTPD,
+	"SQRTPS",	LTYPE3,	ASQRTPS,
+	"SQRTSD",	LTYPE3,	ASQRTSD,
+	"SQRTSS",	LTYPE3,	ASQRTSS,
+	"STMXCSR",	LTYPE1,	ASTMXCSR,
+	"SUBPD",	LTYPE3,	ASUBPD,
+	"SUBPS",	LTYPE3,	ASUBPS,
+	"SUBSD",	LTYPE3,	ASUBSD,
+	"SUBSS",	LTYPE3,	ASUBSS,
+	"UCOMISD",	LTYPE3,	AUCOMISD,
+	"UCOMISS",	LTYPE3,	AUCOMISS,
+	"UNPCKHPD",	LTYPE3,	AUNPCKHPD,
+	"UNPCKHPS",	LTYPE3,	AUNPCKHPS,
+	"UNPCKLPD",	LTYPE3,	AUNPCKLPD,
+	"UNPCKLPS",	LTYPE3,	AUNPCKLPS,
+	"XORPD",	LTYPE3,	AXORPD,
+	"XORPS",	LTYPE3,	AXORPS,
+	"CRC32B",	LTYPE4, ACRC32B,
+	"CRC32Q",	LTYPE4, ACRC32Q,
+	"PREFETCHT0",		LTYPE2,	APREFETCHT0,
+	"PREFETCHT1",		LTYPE2,	APREFETCHT1,
+	"PREFETCHT2",		LTYPE2,	APREFETCHT2,
+	"PREFETCHNTA",		LTYPE2,	APREFETCHNTA,
+	"UNDEF",	LTYPE0,	AUNDEF,
+	"AESENC",	LTYPE3,	AAESENC,
+	"AESENCLAST",	LTYPE3, AAESENCLAST,
+	"AESDEC",	LTYPE3, AAESDEC,
+	"AESDECLAST",	LTYPE3, AAESDECLAST,
+	"AESIMC",	LTYPE3, AAESIMC,
+	"AESKEYGENASSIST", LTYPEX, AAESKEYGENASSIST,
+	"PSHUFD",	LTYPEX, APSHUFD,
+	"USEFIELD",	LTYPEN, AUSEFIELD,
+	"PCLMULQDQ",	LTYPEX, APCLMULQDQ,
+	"PCDATA",	LTYPEPC,	APCDATA,
+	"FUNCDATA",	LTYPEF,	AFUNCDATA,
+	0
+};
+
+void
+cinit(void)
+{
+	Sym *s;
+	int i;
+
+	nullgen.type = D_NONE;
+	nullgen.index = D_NONE;
+
+	nerrors = 0;
+	iostack = I;
+	iofree = I;
+	peekc = IGN;
+	nhunk = 0;
+	for(i=0; i<NHASH; i++)
+		hash[i] = S;
+	for(i=0; itab[i].name; i++) {
+		s = slookup(itab[i].name);
+		if(s->type != LNAME)
+			yyerror("double initialization %s", itab[i].name);
+		s->type = itab[i].type;
+		s->value = itab[i].value;
+	}
+}
+
+void
+checkscale(int scale)
+{
+
+	switch(scale) {
+	case 1:
+	case 2:
+	case 4:
+	case 8:
+		return;
+	}
+	yyerror("scale must be 1248: %d", scale);
+}
+
+void
+syminit(Sym *s)
+{
+
+	s->type = LNAME;
+	s->value = 0;
+}
+
+void
+cclean(void)
+{
+	Addr2 g2;
+
+	g2.from = nullgen;
+	g2.to = nullgen;
+	outcode(AEND, &g2);
+}
+
+static Prog *lastpc;
+
+void
+outcode(int a, Addr2 *g2)
+{
+	Prog *p;
+	Plist *pl;
+	
+	if(pass == 1)
+		goto out;
+
+	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++;
+}
+
+#include "../cc/lexbody"
+#include "../cc/macbody"
diff --git a/src/cmd/6a/y.tab.c b/src/cmd/6a/y.tab.c
new file mode 100644
index 0000000..b69fd95
--- /dev/null
+++ b/src/cmd/6a/y.tab.c
@@ -0,0 +1,2801 @@
+/* A Bison parser, made by GNU Bison 2.3.  */
+
+/* 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 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, 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
+   under terms of your choice, so long as that work isn't itself a
+   parser generator using the skeleton or a modified version thereof
+   as a parser skeleton.  Alternatively, if you modify or redistribute
+   the parser skeleton itself, you may (at your option) remove this
+   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.  */
+
+/* C LALR(1) parser skeleton written by Richard Stallman, by
+   simplifying the original so-called "semantic" parser.  */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+   infringing on user name space.  This should be done even for local
+   variables, as they might otherwise be expanded by user macros.
+   There are some unavoidable exceptions within include files to
+   define necessary library symbols; they are noted "INFRINGES ON
+   USER NAME SPACE" below.  */
+
+/* Identify Bison output.  */
+#define YYBISON 1
+
+/* Bison version.  */
+#define YYBISON_VERSION "2.3"
+
+/* Skeleton name.  */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers.  */
+#define YYPURE 0
+
+/* Using locations.  */
+#define YYLSP_NEEDED 0
+
+
+
+/* Tokens.  */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+   /* Put the tokens into the symbol table, so that GDB and other debuggers
+      know about them.  */
+   enum yytokentype {
+     LTYPE0 = 258,
+     LTYPE1 = 259,
+     LTYPE2 = 260,
+     LTYPE3 = 261,
+     LTYPE4 = 262,
+     LTYPEC = 263,
+     LTYPED = 264,
+     LTYPEN = 265,
+     LTYPER = 266,
+     LTYPET = 267,
+     LTYPEG = 268,
+     LTYPEPC = 269,
+     LTYPES = 270,
+     LTYPEM = 271,
+     LTYPEI = 272,
+     LTYPEXC = 273,
+     LTYPEX = 274,
+     LTYPERT = 275,
+     LTYPEF = 276,
+     LCONST = 277,
+     LFP = 278,
+     LPC = 279,
+     LSB = 280,
+     LBREG = 281,
+     LLREG = 282,
+     LSREG = 283,
+     LFREG = 284,
+     LMREG = 285,
+     LXREG = 286,
+     LFCONST = 287,
+     LSCONST = 288,
+     LSP = 289,
+     LNAME = 290,
+     LLAB = 291,
+     LVAR = 292
+   };
+#endif
+/* Tokens.  */
+#define LTYPE0 258
+#define LTYPE1 259
+#define LTYPE2 260
+#define LTYPE3 261
+#define LTYPE4 262
+#define LTYPEC 263
+#define LTYPED 264
+#define LTYPEN 265
+#define LTYPER 266
+#define LTYPET 267
+#define LTYPEG 268
+#define LTYPEPC 269
+#define LTYPES 270
+#define LTYPEM 271
+#define LTYPEI 272
+#define LTYPEXC 273
+#define LTYPEX 274
+#define LTYPERT 275
+#define LTYPEF 276
+#define LCONST 277
+#define LFP 278
+#define LPC 279
+#define LSB 280
+#define LBREG 281
+#define LLREG 282
+#define LSREG 283
+#define LFREG 284
+#define LMREG 285
+#define LXREG 286
+#define LFCONST 287
+#define LSCONST 288
+#define LSP 289
+#define LNAME 290
+#define LLAB 291
+#define LVAR 292
+
+
+
+
+/* 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 "../../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 38 "a.y"
+{
+	Sym	*sym;
+	vlong	lval;
+	double	dval;
+	char	sval[8];
+	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 216 of yacc.c.  */
+#line 200 "y.tab.c"
+
+#ifdef short
+# undef short
+#endif
+
+#ifdef YYTYPE_UINT8
+typedef YYTYPE_UINT8 yytype_uint8;
+#else
+typedef unsigned char yytype_uint8;
+#endif
+
+#ifdef YYTYPE_INT8
+typedef YYTYPE_INT8 yytype_int8;
+#elif (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+typedef signed char yytype_int8;
+#else
+typedef short int yytype_int8;
+#endif
+
+#ifdef YYTYPE_UINT16
+typedef YYTYPE_UINT16 yytype_uint16;
+#else
+typedef unsigned short int yytype_uint16;
+#endif
+
+#ifdef YYTYPE_INT16
+typedef YYTYPE_INT16 yytype_int16;
+#else
+typedef short int yytype_int16;
+#endif
+
+#ifndef YYSIZE_T
+# ifdef __SIZE_TYPE__
+#  define YYSIZE_T __SIZE_TYPE__
+# elif defined size_t
+#  define YYSIZE_T size_t
+# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+#  include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+#  define YYSIZE_T size_t
+# else
+#  define YYSIZE_T unsigned int
+# endif
+#endif
+
+#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
+
+#ifndef YY_
+# if defined YYENABLE_NLS && YYENABLE_NLS
+#  if ENABLE_NLS
+#   include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+#   define YY_(msgid) dgettext ("bison-runtime", msgid)
+#  endif
+# endif
+# ifndef YY_
+#  define YY_(msgid) msgid
+# endif
+#endif
+
+/* Suppress unused-variable warnings by "using" E.  */
+#if ! defined lint || defined __GNUC__
+# define YYUSE(e) ((void) (e))
+#else
+# define YYUSE(e) /* empty */
+#endif
+
+/* Identity function, used to suppress warnings about constant conditions.  */
+#ifndef lint
+# define YYID(n) (n)
+#else
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static int
+YYID (int i)
+#else
+static int
+YYID (i)
+    int i;
+#endif
+{
+  return i;
+}
+#endif
+
+#if ! defined yyoverflow || YYERROR_VERBOSE
+
+/* The parser invokes alloca or malloc; define the necessary symbols.  */
+
+# ifdef YYSTACK_USE_ALLOCA
+#  if YYSTACK_USE_ALLOCA
+#   ifdef __GNUC__
+#    define YYSTACK_ALLOC __builtin_alloca
+#   elif defined __BUILTIN_VA_ARG_INCR
+#    include <alloca.h> /* INFRINGES ON USER NAME SPACE */
+#   elif defined _AIX
+#    define YYSTACK_ALLOC __alloca
+#   elif defined _MSC_VER
+#    include <malloc.h> /* INFRINGES ON USER NAME SPACE */
+#    define alloca _alloca
+#   else
+#    define YYSTACK_ALLOC alloca
+#    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 _STDLIB_H
+#      define _STDLIB_H 1
+#     endif
+#    endif
+#   endif
+#  endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+   /* Pacify GCC's `empty if-body' warning.  */
+#  define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
+#  ifndef YYSTACK_ALLOC_MAXIMUM
+    /* The OS might guarantee only one guard page at the bottom of the stack,
+       and a page size can be as small as 4096 bytes.  So we cannot safely
+       invoke alloca (N) if N exceeds 4096.  Use a slightly smaller number
+       to allow for a few compiler-allocated temporary stack slots.  */
+#   define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
+#  endif
+# else
+#  define YYSTACK_ALLOC YYMALLOC
+#  define YYSTACK_FREE YYFREE
+#  ifndef YYSTACK_ALLOC_MAXIMUM
+#   define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
+#  endif
+#  if (defined __cplusplus && ! defined _STDLIB_H \
+       && ! ((defined YYMALLOC || defined malloc) \
+	     && (defined YYFREE || defined free)))
+#   include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+#   ifndef _STDLIB_H
+#    define _STDLIB_H 1
+#   endif
+#  endif
+#  ifndef YYMALLOC
+#   define YYMALLOC malloc
+#   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 _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+#   endif
+#  endif
+# endif
+#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
+
+
+#if (! defined yyoverflow \
+     && (! defined __cplusplus \
+	 || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member.  */
+union yyalloc
+{
+  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)
+
+/* The size of an array large to enough to hold all stacks, each with
+   N elements.  */
+# define YYSTACK_BYTES(N) \
+     ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
+      + YYSTACK_GAP_MAXIMUM)
+
+/* Copy COUNT objects from FROM to TO.  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)))
+#  else
+#   define YYCOPY(To, From, Count)		\
+      do					\
+	{					\
+	  YYSIZE_T yyi;				\
+	  for (yyi = 0; yyi < (Count); yyi++)	\
+	    (To)[yyi] = (From)[yyi];		\
+	}					\
+      while (YYID (0))
+#  endif
+# endif
+
+/* 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
+/* YYLAST -- Last index in YYTABLE.  */
+#define YYLAST   560
+
+/* YYNTOKENS -- Number of terminals.  */
+#define YYNTOKENS  56
+/* YYNNTS -- Number of nonterminals.  */
+#define YYNNTS  42
+/* YYNRULES -- Number of rules.  */
+#define YYNRULES  137
+/* YYNRULES -- Number of states.  */
+#define YYNSTATES  277
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX.  */
+#define YYUNDEFTOK  2
+#define YYMAXUTOK   292
+
+#define YYTRANSLATE(YYX)						\
+  ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX.  */
+static const yytype_uint8 yytranslate[] =
+{
+       0,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,    54,    12,     5,     2,
+      52,    53,    10,     8,    51,     9,     2,    11,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,    48,    49,
+       6,    50,     7,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     4,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     3,     2,    55,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     1,     2,    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
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+   YYRHS.  */
+static const yytype_uint16 yyprhs[] =
+{
+       0,     0,     3,     4,     5,     9,    10,    15,    16,    21,
+      23,    26,    29,    33,    37,    40,    43,    46,    49,    52,
+      55,    58,    61,    64,    67,    70,    73,    76,    79,    82,
+      85,    88,    91,    94,    95,    97,   101,   105,   108,   110,
+     113,   115,   118,   120,   124,   130,   134,   140,   143,   145,
+     147,   149,   153,   159,   163,   169,   172,   174,   178,   184,
+     190,   191,   193,   197,   203,   207,   211,   213,   215,   217,
+     219,   222,   225,   227,   229,   231,   233,   238,   241,   244,
+     246,   248,   250,   252,   254,   256,   258,   261,   264,   267,
+     270,   273,   278,   284,   288,   290,   292,   294,   299,   304,
+     309,   316,   326,   336,   340,   344,   350,   359,   361,   368,
+     374,   382,   383,   386,   389,   391,   393,   395,   397,   399,
+     402,   405,   408,   412,   414,   417,   421,   426,   428,   432,
+     436,   440,   444,   448,   453,   458,   462,   466
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS.  */
+static const yytype_int8 yyrhs[] =
+{
+      57,     0,    -1,    -1,    -1,    57,    58,    59,    -1,    -1,
+      46,    48,    60,    59,    -1,    -1,    45,    48,    61,    59,
+      -1,    49,    -1,    62,    49,    -1,     1,    49,    -1,    45,
+      50,    97,    -1,    47,    50,    97,    -1,    13,    63,    -1,
+      14,    67,    -1,    15,    66,    -1,    16,    64,    -1,    17,
+      65,    -1,    21,    68,    -1,    19,    69,    -1,    22,    70,
+      -1,    18,    71,    -1,    20,    72,    -1,    25,    73,    -1,
+      26,    74,    -1,    27,    75,    -1,    28,    76,    -1,    29,
+      77,    -1,    30,    78,    -1,    23,    79,    -1,    24,    80,
+      -1,    31,    81,    -1,    -1,    51,    -1,    84,    51,    82,
+      -1,    82,    51,    84,    -1,    84,    51,    -1,    84,    -1,
+      51,    82,    -1,    82,    -1,    51,    85,    -1,    85,    -1,
+      88,    51,    85,    -1,    92,    11,    95,    51,    88,    -1,
+      89,    51,    87,    -1,    89,    51,    95,    51,    87,    -1,
+      51,    83,    -1,    83,    -1,    63,    -1,    67,    -1,    84,
+      51,    82,    -1,    84,    51,    82,    48,    37,    -1,    84,
+      51,    82,    -1,    84,    51,    82,    48,    38,    -1,    84,
+      51,    -1,    84,    -1,    84,    51,    82,    -1,    86,    51,
+      82,    51,    95,    -1,    88,    51,    82,    51,    86,    -1,
+      -1,    88,    -1,    89,    51,    88,    -1,    89,    51,    95,
+      51,    88,    -1,    84,    51,    84,    -1,    84,    51,    84,
+      -1,    86,    -1,    89,    -1,    85,    -1,    91,    -1,    10,
+      86,    -1,    10,    90,    -1,    86,    -1,    90,    -1,    82,
+      -1,    88,    -1,    95,    52,    34,    53,    -1,    45,    93,
+      -1,    46,    93,    -1,    36,    -1,    39,    -1,    37,    -1,
+      40,    -1,    44,    -1,    38,    -1,    41,    -1,    54,    96,
+      -1,    54,    95,    -1,    54,    92,    -1,    54,    43,    -1,
+      54,    42,    -1,    54,    52,    42,    53,    -1,    54,    52,
+       9,    42,    53,    -1,    54,     9,    42,    -1,    90,    -1,
+      91,    -1,    95,    -1,    95,    52,    37,    53,    -1,    95,
+      52,    44,    53,    -1,    95,    52,    38,    53,    -1,    95,
+      52,    37,    10,    95,    53,    -1,    95,    52,    37,    53,
+      52,    37,    10,    95,    53,    -1,    95,    52,    37,    53,
+      52,    38,    10,    95,    53,    -1,    52,    37,    53,    -1,
+      52,    44,    53,    -1,    52,    37,    10,    95,    53,    -1,
+      52,    37,    53,    52,    37,    10,    95,    53,    -1,    92,
+      -1,    92,    52,    37,    10,    95,    53,    -1,    45,    93,
+      52,    94,    53,    -1,    45,     6,     7,    93,    52,    35,
+      53,    -1,    -1,     8,    95,    -1,     9,    95,    -1,    35,
+      -1,    44,    -1,    33,    -1,    32,    -1,    47,    -1,     9,
+      95,    -1,     8,    95,    -1,    55,    95,    -1,    52,    97,
+      53,    -1,    32,    -1,     9,    32,    -1,    32,     9,    32,
+      -1,     9,    32,     9,    32,    -1,    95,    -1,    97,     8,
+      97,    -1,    97,     9,    97,    -1,    97,    10,    97,    -1,
+      97,    11,    97,    -1,    97,    12,    97,    -1,    97,     6,
+       6,    97,    -1,    97,     7,     7,    97,    -1,    97,     5,
+      97,    -1,    97,     4,    97,    -1,    97,     3,    97,    -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
+static const yytype_uint16 yyrline[] =
+{
+       0,    66,    66,    68,    67,    75,    74,    82,    81,    87,
+      88,    89,    92,    97,   103,   104,   105,   106,   107,   108,
+     109,   110,   111,   112,   113,   114,   115,   116,   117,   118,
+     119,   120,   121,   124,   128,   135,   142,   149,   154,   161,
+     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,   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
+
+#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+   First, the terminals, then, starting at YYNTOKENS, nonterminals.  */
+static const char *const yytname[] =
+{
+  "$end", "error", "$undefined", "'|'", "'^'", "'&'", "'<'", "'>'", "'+'",
+  "'-'", "'*'", "'/'", "'%'", "LTYPE0", "LTYPE1", "LTYPE2", "LTYPE3",
+  "LTYPE4", "LTYPEC", "LTYPED", "LTYPEN", "LTYPER", "LTYPET", "LTYPEG",
+  "LTYPEPC", "LTYPES", "LTYPEM", "LTYPEI", "LTYPEXC", "LTYPEX", "LTYPERT",
+  "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
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+   token YYLEX-NUM.  */
+static const yytype_uint16 yytoknum[] =
+{
+       0,   256,   257,   124,    94,    38,    60,    62,    43,    45,
+      42,    47,    37,   258,   259,   260,   261,   262,   263,   264,
+     265,   266,   267,   268,   269,   270,   271,   272,   273,   274,
+     275,   276,   277,   278,   279,   280,   281,   282,   283,   284,
+     285,   286,   287,   288,   289,   290,   291,   292,    58,    59,
+      61,    44,    40,    41,    36,   126
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
+static const yytype_uint8 yyr1[] =
+{
+       0,    56,    57,    58,    57,    60,    59,    61,    59,    59,
+      59,    59,    62,    62,    62,    62,    62,    62,    62,    62,
+      62,    62,    62,    62,    62,    62,    62,    62,    62,    62,
+      62,    62,    62,    63,    63,    64,    65,    66,    66,    67,
+      67,    68,    68,    68,    69,    70,    70,    71,    71,    72,
+      72,    73,    73,    74,    74,    75,    75,    75,    76,    77,
+      78,    78,    79,    79,    80,    81,    82,    82,    83,    83,
+      83,    83,    83,    83,    84,    84,    85,    85,    85,    86,
+      86,    86,    86,    86,    86,    86,    87,    88,    88,    88,
+      88,    88,    88,    88,    89,    89,    90,    90,    90,    90,
+      90,    90,    90,    90,    90,    90,    90,    91,    91,    92,
+      92,    93,    93,    93,    94,    94,    94,    95,    95,    95,
+      95,    95,    95,    96,    96,    96,    96,    97,    97,    97,
+      97,    97,    97,    97,    97,    97,    97,    97
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN.  */
+static const yytype_uint8 yyr2[] =
+{
+       0,     2,     0,     0,     3,     0,     4,     0,     4,     1,
+       2,     2,     3,     3,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     0,     1,     3,     3,     2,     1,     2,
+       1,     2,     1,     3,     5,     3,     5,     2,     1,     1,
+       1,     3,     5,     3,     5,     2,     1,     3,     5,     5,
+       0,     1,     3,     5,     3,     3,     1,     1,     1,     1,
+       2,     2,     1,     1,     1,     1,     4,     2,     2,     1,
+       1,     1,     1,     1,     1,     1,     2,     2,     2,     2,
+       2,     4,     5,     3,     1,     1,     1,     4,     4,     4,
+       6,     9,     9,     3,     3,     5,     8,     1,     6,     5,
+       7,     0,     2,     2,     1,     1,     1,     1,     1,     2,
+       2,     2,     3,     1,     2,     3,     4,     1,     3,     3,
+       3,     3,     3,     4,     4,     3,     3,     3
+};
+
+/* 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[] =
+{
+       2,     3,     1,     0,     0,    33,     0,     0,     0,     0,
+       0,     0,    33,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,    60,     0,     0,     0,     0,     9,     4,     0,
+      11,    34,    14,     0,     0,   117,    79,    81,    84,    80,
+      82,    85,    83,   111,   118,     0,     0,     0,    15,    40,
+      66,    67,    94,    95,   107,    96,     0,    16,    74,    38,
+      75,    17,     0,    18,     0,     0,   111,   111,     0,    22,
+      48,    68,    72,    73,    69,    96,    20,     0,    34,    49,
+      50,    23,   111,     0,     0,    19,    42,     0,     0,    21,
+       0,    30,     0,    31,     0,    24,     0,    25,     0,    26,
+      56,    27,     0,    28,     0,    29,    61,    32,     0,     7,
+       0,     5,     0,    10,   120,   119,     0,     0,     0,     0,
+      39,     0,     0,   127,     0,   121,     0,     0,     0,    90,
+      89,     0,    88,    87,    37,     0,     0,    70,    71,    77,
+      78,    47,     0,     0,    77,    41,     0,     0,     0,     0,
+       0,     0,     0,    55,     0,     0,     0,     0,    12,     0,
+      13,   111,   112,   113,     0,     0,   103,   104,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,   122,     0,
+       0,     0,     0,    93,     0,     0,    35,    36,     0,     0,
+      43,     0,    45,     0,    62,     0,    64,    51,    53,    57,
+       0,     0,    65,     8,     6,     0,   116,   114,   115,     0,
+       0,     0,   137,   136,   135,     0,     0,   128,   129,   130,
+     131,   132,     0,     0,    97,    99,    98,     0,    91,    76,
+       0,     0,   123,    86,     0,     0,     0,     0,     0,     0,
+       0,   109,   105,     0,   133,   134,     0,     0,     0,    92,
+      44,   124,     0,    46,    63,    52,    54,    58,    59,     0,
+       0,   108,   100,     0,     0,     0,   125,   110,     0,     0,
+       0,   126,   106,     0,     0,   101,   102
+};
+
+/* YYDEFGOTO[NTERM-NUM].  */
+static const yytype_int16 yydefgoto[] =
+{
+      -1,     1,     3,    28,   159,   157,    29,    32,    61,    63,
+      57,    48,    85,    76,    89,    69,    81,    95,    97,    99,
+     101,   103,   105,    91,    93,   107,    58,    70,    59,    71,
+      50,   192,    60,    51,    52,    53,    54,   119,   209,    55,
+     233,   124
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+   STATE-NUM.  */
+#define YYPACT_NINF -94
+static const yytype_int16 yypact[] =
+{
+     -94,    15,   -94,   218,   -28,   -25,   264,   285,   285,   340,
+     163,     2,   319,    97,   415,   415,   285,   285,   285,   285,
+     306,   -24,   -24,   285,   -17,   -14,     4,   -94,   -94,    48,
+     -94,   -94,   -94,   481,   481,   -94,   -94,   -94,   -94,   -94,
+     -94,   -94,   -94,    19,   -94,   340,   399,   481,   -94,   -94,
+     -94,   -94,   -94,   -94,    46,    47,   385,   -94,   -94,    52,
+     -94,   -94,    59,   -94,    60,   374,    19,    56,   243,   -94,
+     -94,   -94,   -94,   -94,   -94,    63,   -94,   106,   340,   -94,
+     -94,   -94,    56,   138,   481,   -94,   -94,    69,    72,   -94,
+      74,   -94,    76,   -94,    77,   -94,    79,   -94,    80,   -94,
+      81,   -94,    83,   -94,    89,   -94,   -94,   -94,    94,   -94,
+     481,   -94,   481,   -94,   -94,   -94,   119,   481,   481,    98,
+     -94,    -1,   100,   -94,    84,   -94,   117,    23,   426,   -94,
+     -94,   433,   -94,   -94,   -94,   340,   285,   -94,   -94,    98,
+     -94,   -94,    75,   481,   -94,   -94,   138,   122,   440,   444,
+     285,   340,   340,   340,   340,   340,   285,   218,   393,   218,
+     393,    56,   -94,   -94,   -15,   481,   105,   -94,   481,   481,
+     481,   156,   162,   481,   481,   481,   481,   481,   -94,   165,
+       0,   123,   133,   -94,   474,   134,   -94,   -94,   136,   140,
+     -94,     7,   -94,   141,   -94,   143,   -94,   148,   149,   -94,
+     147,   160,   -94,   -94,   -94,   164,   -94,   -94,   -94,   167,
+     168,   180,   533,   541,   548,   481,   481,    58,    58,   -94,
+     -94,   -94,   481,   481,   171,   -94,   -94,   172,   -94,   -94,
+     -24,   192,   217,   -94,   175,   -24,   219,   216,   481,   306,
+     220,   -94,   -94,   247,    33,    33,   205,   208,    41,   -94,
+     -94,   253,   234,   -94,   -94,   -94,   -94,   -94,   -94,   215,
+     481,   -94,   -94,   259,   260,   239,   -94,   -94,   221,   481,
+     481,   -94,   -94,   223,   224,   -94,   -94
+};
+
+/* YYPGOTO[NTERM-NUM].  */
+static const yytype_int16 yypgoto[] =
+{
+     -94,   -94,   -94,   -43,   -94,   -94,   -94,   266,   -94,   -94,
+     -94,   273,   -94,   -94,   -94,   -94,   -94,   -94,   -94,   -94,
+     -94,   -94,   -94,   -94,   -94,   -94,    26,   229,    32,   -11,
+      -9,    57,    -8,    71,    -2,    -6,     1,   -60,   -94,   -10,
+     -94,   -93
+};
+
+/* 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 zero, do what YYDEFACT says.
+   If YYTABLE_NINF, syntax error.  */
+#define YYTABLE_NINF -1
+static const yytype_uint16 yytable[] =
+{
+      75,    72,    86,    88,    74,    87,   139,   140,    73,   165,
+     223,   102,    77,   104,   106,     2,   231,   158,   206,   160,
+     207,    30,   144,   114,   115,   116,    31,   117,   118,   208,
+      56,   109,    49,   110,   111,    64,   123,   125,    49,   232,
+      62,   173,   174,   175,   176,   177,   133,    43,    94,    96,
+      98,   100,   166,   224,   112,   108,   137,   132,    75,    72,
+     180,   181,    74,   138,   117,   118,    73,   182,   175,   176,
+     177,   120,   145,    88,   123,   212,   213,   214,   263,   264,
+     217,   218,   219,   220,   221,    90,    92,   168,   169,   170,
+     171,   172,   173,   174,   175,   176,   177,   113,   126,   127,
+     123,   205,   123,   134,   120,    33,    34,   162,   163,   188,
+     135,   136,   180,   181,   203,   142,   204,   143,   115,   182,
+     146,   123,   244,   245,   147,   148,   161,   149,   150,    35,
+     151,   152,   153,   189,   154,   190,    88,   178,   193,   195,
+     155,   194,    82,    67,    44,   156,    33,    34,    83,    84,
+     164,    56,    47,   167,   179,   210,   188,   211,   123,   123,
+     123,   186,   215,   123,   123,   123,   123,   123,   187,   216,
+      35,    33,    34,    65,   115,   222,   225,   197,   198,   199,
+     200,   201,   196,    82,    67,    44,   226,   228,   202,   229,
+      84,   230,   234,    47,   235,    35,   236,   237,   238,    36,
+      37,    38,    39,    40,    41,   123,   123,    42,    66,    67,
+      44,   239,   246,   247,    68,    46,   240,   243,    47,     4,
+     241,   242,   250,   248,   251,   249,   252,   254,   257,   191,
+     258,     5,     6,     7,     8,     9,    10,    11,    12,    13,
+      14,    15,    16,    17,    18,    19,    20,    21,    22,    23,
+     268,    33,    34,    65,   256,   259,   255,   260,   261,   273,
+     274,   262,   265,    24,    25,    26,   266,    27,   267,   269,
+     270,   271,    33,    34,   272,    35,   275,   276,    79,    36,
+      37,    38,    39,    40,    41,    80,     0,    42,    66,    67,
+      44,   253,     0,    33,    34,    46,    35,   141,    47,     0,
+      36,    37,    38,    39,    40,    41,     0,     0,    42,    43,
+       0,    44,     0,     0,     0,    45,    46,    35,     0,    47,
+       0,    36,    37,    38,    39,    40,    41,    33,    34,    42,
+      43,     0,    44,     0,     0,     0,     0,    46,     0,    56,
+      47,     0,    36,    37,    38,    39,    40,    41,    33,    34,
+      42,    35,     0,     0,     0,    36,    37,    38,    39,    40,
+      41,     0,     0,    42,    43,     0,    44,     0,     0,     0,
+      78,    46,    35,     0,    47,     0,    36,    37,    38,    39,
+      40,    41,    33,    34,    42,    43,     0,    44,     0,     0,
+       0,     0,    46,    33,   128,    47,   168,   169,   170,   171,
+     172,   173,   174,   175,   176,   177,    35,    33,    34,     0,
+      36,    37,    38,    39,    40,    41,     0,    35,    42,     0,
+       0,    44,     0,    33,    34,     0,    46,   129,   130,    47,
+      43,    35,    44,     0,    33,    34,   121,   131,     0,     0,
+      47,    33,   184,   122,     0,     0,    44,    35,    33,    34,
+       0,    84,    33,    34,    47,     0,     0,     0,    35,     0,
+      43,     0,    44,     0,     0,    35,     0,    46,   183,     0,
+      47,     0,    35,    44,     0,   185,    35,     0,    84,     0,
+      44,    47,    33,    34,     0,    84,     0,    44,    47,    33,
+      34,    44,    84,     0,   191,    47,    84,     0,    56,    47,
+       0,     0,     0,     0,     0,     0,    35,     0,     0,     0,
+       0,     0,     0,    35,     0,     0,   227,     0,     0,     0,
+       0,    44,     0,     0,     0,     0,    84,     0,    44,    47,
+       0,     0,     0,    84,     0,     0,    47,   169,   170,   171,
+     172,   173,   174,   175,   176,   177,   170,   171,   172,   173,
+     174,   175,   176,   177,   171,   172,   173,   174,   175,   176,
+     177
+};
+
+static const yytype_int16 yycheck[] =
+{
+      10,    10,    13,    13,    10,    13,    66,    67,    10,    10,
+      10,    20,    11,    21,    22,     0,     9,   110,    33,   112,
+      35,    49,    82,    33,    34,     6,    51,     8,     9,    44,
+      54,    48,     6,    50,    48,     9,    46,    47,    12,    32,
+       8,     8,     9,    10,    11,    12,    56,    45,    16,    17,
+      18,    19,    53,    53,    50,    23,    65,    56,    68,    68,
+      37,    38,    68,    65,     8,     9,    68,    44,    10,    11,
+      12,    45,    83,    83,    84,   168,   169,   170,    37,    38,
+     173,   174,   175,   176,   177,    14,    15,     3,     4,     5,
+       6,     7,     8,     9,    10,    11,    12,    49,    52,    52,
+     110,   161,   112,    51,    78,     8,     9,   117,   118,    34,
+      51,    51,    37,    38,   157,    52,   159,    11,   128,    44,
+      51,   131,   215,   216,    52,    51,     7,    51,    51,    32,
+      51,    51,    51,   143,    51,   146,   146,    53,   148,   149,
+      51,   149,    45,    46,    47,    51,     8,     9,    51,    52,
+      52,    54,    55,    53,    37,   165,    34,    52,   168,   169,
+     170,   135,     6,   173,   174,   175,   176,   177,   136,     7,
+      32,     8,     9,    10,   184,    10,    53,   151,   152,   153,
+     154,   155,   150,    45,    46,    47,    53,    53,   156,    53,
+      52,    51,    51,    55,    51,    32,    48,    48,    51,    36,
+      37,    38,    39,    40,    41,   215,   216,    44,    45,    46,
+      47,    51,   222,   223,    51,    52,    52,    37,    55,     1,
+      53,    53,   230,    52,    32,    53,     9,   235,   238,    54,
+     239,    13,    14,    15,    16,    17,    18,    19,    20,    21,
+      22,    23,    24,    25,    26,    27,    28,    29,    30,    31,
+     260,     8,     9,    10,    38,    35,    37,    10,    53,   269,
+     270,    53,     9,    45,    46,    47,    32,    49,    53,    10,
+      10,    32,     8,     9,    53,    32,    53,    53,    12,    36,
+      37,    38,    39,    40,    41,    12,    -1,    44,    45,    46,
+      47,   234,    -1,     8,     9,    52,    32,    68,    55,    -1,
+      36,    37,    38,    39,    40,    41,    -1,    -1,    44,    45,
+      -1,    47,    -1,    -1,    -1,    51,    52,    32,    -1,    55,
+      -1,    36,    37,    38,    39,    40,    41,     8,     9,    44,
+      45,    -1,    47,    -1,    -1,    -1,    -1,    52,    -1,    54,
+      55,    -1,    36,    37,    38,    39,    40,    41,     8,     9,
+      44,    32,    -1,    -1,    -1,    36,    37,    38,    39,    40,
+      41,    -1,    -1,    44,    45,    -1,    47,    -1,    -1,    -1,
+      51,    52,    32,    -1,    55,    -1,    36,    37,    38,    39,
+      40,    41,     8,     9,    44,    45,    -1,    47,    -1,    -1,
+      -1,    -1,    52,     8,     9,    55,     3,     4,     5,     6,
+       7,     8,     9,    10,    11,    12,    32,     8,     9,    -1,
+      36,    37,    38,    39,    40,    41,    -1,    32,    44,    -1,
+      -1,    47,    -1,     8,     9,    -1,    52,    42,    43,    55,
+      45,    32,    47,    -1,     8,     9,    37,    52,    -1,    -1,
+      55,     8,     9,    44,    -1,    -1,    47,    32,     8,     9,
+      -1,    52,     8,     9,    55,    -1,    -1,    -1,    32,    -1,
+      45,    -1,    47,    -1,    -1,    32,    -1,    52,    42,    -1,
+      55,    -1,    32,    47,    -1,    42,    32,    -1,    52,    -1,
+      47,    55,     8,     9,    -1,    52,    -1,    47,    55,     8,
+       9,    47,    52,    -1,    54,    55,    52,    -1,    54,    55,
+      -1,    -1,    -1,    -1,    -1,    -1,    32,    -1,    -1,    -1,
+      -1,    -1,    -1,    32,    -1,    -1,    42,    -1,    -1,    -1,
+      -1,    47,    -1,    -1,    -1,    -1,    52,    -1,    47,    55,
+      -1,    -1,    -1,    52,    -1,    -1,    55,     4,     5,     6,
+       7,     8,     9,    10,    11,    12,     5,     6,     7,     8,
+       9,    10,    11,    12,     6,     7,     8,     9,    10,    11,
+      12
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+   symbol of state STATE-NUM.  */
+static const yytype_uint8 yystos[] =
+{
+       0,    57,     0,    58,     1,    13,    14,    15,    16,    17,
+      18,    19,    20,    21,    22,    23,    24,    25,    26,    27,
+      28,    29,    30,    31,    45,    46,    47,    49,    59,    62,
+      49,    51,    63,     8,     9,    32,    36,    37,    38,    39,
+      40,    41,    44,    45,    47,    51,    52,    55,    67,    82,
+      86,    89,    90,    91,    92,    95,    54,    66,    82,    84,
+      88,    64,    84,    65,    82,    10,    45,    46,    51,    71,
+      83,    85,    86,    90,    91,    95,    69,    92,    51,    63,
+      67,    72,    45,    51,    52,    68,    85,    88,    95,    70,
+      89,    79,    89,    80,    84,    73,    84,    74,    84,    75,
+      84,    76,    86,    77,    88,    78,    88,    81,    84,    48,
+      50,    48,    50,    49,    95,    95,     6,     8,     9,    93,
+      82,    37,    44,    95,    97,    95,    52,    52,     9,    42,
+      43,    52,    92,    95,    51,    51,    51,    86,    90,    93,
+      93,    83,    52,    11,    93,    85,    51,    52,    51,    51,
+      51,    51,    51,    51,    51,    51,    51,    61,    97,    60,
+      97,     7,    95,    95,    52,    10,    53,    53,     3,     4,
+       5,     6,     7,     8,     9,    10,    11,    12,    53,    37,
+      37,    38,    44,    42,     9,    42,    82,    84,    34,    95,
+      85,    54,    87,    95,    88,    95,    84,    82,    82,    82,
+      82,    82,    84,    59,    59,    93,    33,    35,    44,    94,
+      95,    52,    97,    97,    97,     6,     7,    97,    97,    97,
+      97,    97,    10,    10,    53,    53,    53,    42,    53,    53,
+      51,     9,    32,    96,    51,    51,    48,    48,    51,    51,
+      52,    53,    53,    37,    97,    97,    95,    95,    52,    53,
+      88,    32,     9,    87,    88,    37,    38,    95,    86,    35,
+      10,    53,    53,    37,    38,     9,    32,    53,    95,    10,
+      10,    32,    53,    95,    95,    53,    53
+};
+
+#define yyerrok		(yyerrstatus = 0)
+#define yyclearin	(yychar = YYEMPTY)
+#define YYEMPTY		(-2)
+#define YYEOF		0
+
+#define YYACCEPT	goto yyacceptlab
+#define YYABORT		goto yyabortlab
+#define YYERROR		goto yyerrorlab
+
+
+/* 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.  */
+
+#define YYFAIL		goto yyerrlab
+
+#define YYRECOVERING()  (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value)					\
+do								\
+  if (yychar == YYEMPTY && yylen == 1)				\
+    {								\
+      yychar = (Token);						\
+      yylval = (Value);						\
+      yytoken = YYTRANSLATE (yychar);				\
+      YYPOPSTACK (1);						\
+      goto yybackup;						\
+    }								\
+  else								\
+    {								\
+      yyerror (YY_("syntax error: cannot back up")); \
+      YYERROR;							\
+    }								\
+while (YYID (0))
+
+
+#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
+
+
+/* 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
+# 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
+
+
+/* YYLEX -- calling `yylex' with the right arguments.  */
+
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (YYLEX_PARAM)
+#else
+# define YYLEX yylex ()
+#endif
+
+/* Enable debugging if requested.  */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+#  include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+#  define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args)			\
+do {						\
+  if (yydebug)					\
+    YYFPRINTF Args;				\
+} while (YYID (0))
+
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)			  \
+do {									  \
+  if (yydebug)								  \
+    {									  \
+      YYFPRINTF (stderr, "%s ", Title);					  \
+      yy_symbol_print (stderr,						  \
+		  Type, Value); \
+      YYFPRINTF (stderr, "\n");						  \
+    }									  \
+} while (YYID (0))
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT.  |
+`--------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_value_print (yyoutput, yytype, yyvaluep)
+    FILE *yyoutput;
+    int yytype;
+    YYSTYPE const * const yyvaluep;
+#endif
+{
+  if (!yyvaluep)
+    return;
+# ifdef YYPRINT
+  if (yytype < YYNTOKENS)
+    YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# else
+  YYUSE (yyoutput);
+# endif
+  switch (yytype)
+    {
+      default:
+	break;
+    }
+}
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT.  |
+`--------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_print (yyoutput, yytype, yyvaluep)
+    FILE *yyoutput;
+    int yytype;
+    YYSTYPE const * const yyvaluep;
+#endif
+{
+  if (yytype < YYNTOKENS)
+    YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+  else
+    YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+  yy_symbol_value_print (yyoutput, yytype, yyvaluep);
+  YYFPRINTF (yyoutput, ")");
+}
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included).                                                   |
+`------------------------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_stack_print (yytype_int16 *bottom, yytype_int16 *top)
+#else
+static void
+yy_stack_print (bottom, top)
+    yytype_int16 *bottom;
+    yytype_int16 *top;
+#endif
+{
+  YYFPRINTF (stderr, "Stack now");
+  for (; bottom <= top; ++bottom)
+    YYFPRINTF (stderr, " %d", *bottom);
+  YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top)				\
+do {								\
+  if (yydebug)							\
+    yy_stack_print ((Bottom), (Top));				\
+} while (YYID (0))
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced.  |
+`------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_reduce_print (YYSTYPE *yyvsp, int yyrule)
+#else
+static void
+yy_reduce_print (yyvsp, yyrule)
+    YYSTYPE *yyvsp;
+    int yyrule;
+#endif
+{
+  int yynrhs = yyr2[yyrule];
+  int yyi;
+  unsigned long int yylno = yyrline[yyrule];
+  YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
+	     yyrule - 1, yylno);
+  /* The symbols being reduced.  */
+  for (yyi = 0; yyi < yynrhs; yyi++)
+    {
+      fprintf (stderr, "   $%d = ", yyi + 1);
+      yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
+		       &(yyvsp[(yyi + 1) - (yynrhs)])
+		       		       );
+      fprintf (stderr, "\n");
+    }
+}
+
+# define YY_REDUCE_PRINT(Rule)		\
+do {					\
+  if (yydebug)				\
+    yy_reduce_print (yyvsp, Rule); \
+} while (YYID (0))
+
+/* Nonzero means print parse trace.  It is left uninitialized so that
+   multiple parsers can coexist.  */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks.  */
+#ifndef	YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+   if the built-in stack extension method is used).
+
+   Do not make this value too large; the results are undefined if
+   YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+   evaluated with infinite-precision integer arithmetic.  */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+

+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+#  if defined __GLIBC__ && defined _STRING_H
+#   define yystrlen strlen
+#  else
+/* Return the length of YYSTR.  */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static YYSIZE_T
+yystrlen (const char *yystr)
+#else
+static YYSIZE_T
+yystrlen (yystr)
+    const char *yystr;
+#endif
+{
+  YYSIZE_T yylen;
+  for (yylen = 0; yystr[yylen]; yylen++)
+    continue;
+  return yylen;
+}
+#  endif
+# endif
+
+# ifndef yystpcpy
+#  if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
+#   define yystpcpy stpcpy
+#  else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+   YYDEST.  */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static char *
+yystpcpy (char *yydest, const char *yysrc)
+#else
+static char *
+yystpcpy (yydest, yysrc)
+    char *yydest;
+    const char *yysrc;
+#endif
+{
+  char *yyd = yydest;
+  const char *yys = yysrc;
+
+  while ((*yyd++ = *yys++) != '\0')
+    continue;
+
+  return yyd - 1;
+}
+#  endif
+# endif
+
+# ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+   quotes and backslashes, so that it's suitable for yyerror.  The
+   heuristic is that double-quoting is unnecessary unless the string
+   contains an apostrophe, a comma, or backslash (other than
+   backslash-backslash).  YYSTR is taken from yytname.  If YYRES is
+   null, do not copy; instead, return the length of what the result
+   would have been.  */
+static YYSIZE_T
+yytnamerr (char *yyres, const char *yystr)
+{
+  if (*yystr == '"')
+    {
+      YYSIZE_T yyn = 0;
+      char const *yyp = yystr;
+
+      for (;;)
+	switch (*++yyp)
+	  {
+	  case '\'':
+	  case ',':
+	    goto do_not_strip_quotes;
+
+	  case '\\':
+	    if (*++yyp != '\\')
+	      goto do_not_strip_quotes;
+	    /* Fall through.  */
+	  default:
+	    if (yyres)
+	      yyres[yyn] = *yyp;
+	    yyn++;
+	    break;
+
+	  case '"':
+	    if (yyres)
+	      yyres[yyn] = '\0';
+	    return yyn;
+	  }
+    do_not_strip_quotes: ;
+    }
+
+  if (! yyres)
+    return yystrlen (yystr);
+
+  return yystpcpy (yyres, yystr) - yyres;
+}
+# endif
+
+/* 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)
+{
+  int yyn = yypact[yystate];
+
+  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;
+	  }
+
+      yyf = YY_(yyformat);
+      yysize1 = yysize + yystrlen (yyf);
+      yysize_overflow |= (yysize1 < yysize);
+      yysize = yysize1;
+
+      if (yysize_overflow)
+	return YYSIZE_MAXIMUM;
+
+      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.  |
+`-----------------------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yydestruct (yymsg, yytype, yyvaluep)
+    const char *yymsg;
+    int yytype;
+    YYSTYPE *yyvaluep;
+#endif
+{
+  YYUSE (yyvaluep);
+
+  if (!yymsg)
+    yymsg = "Deleting";
+  YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
+  switch (yytype)
+    {
+
+      default:
+	break;
+    }
+}
+

+
+/* 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 look-ahead symbol.  */
+int yychar;
+
+/* The semantic value of the look-ahead symbol.  */
+YYSTYPE yylval;
+
+/* Number of syntax errors so far.  */
+int yynerrs;
+
+
+
+/*----------.
+| yyparse.  |
+`----------*/
+
+#ifdef YYPARSE_PARAM
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void *YYPARSE_PARAM)
+#else
+int
+yyparse (YYPARSE_PARAM)
+    void *YYPARSE_PARAM;
+#endif
+#else /* ! YYPARSE_PARAM */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void)
+#else
+int
+yyparse ()
+
+#endif
+#endif
+{
+  
+  int yystate;
+  int yyn;
+  int yyresult;
+  /* 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];
+  char *yymsg = yymsgbuf;
+  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;
+
+  YYDPRINTF ((stderr, "Starting parse\n"));
+
+  yystate = 0;
+  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;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate.  |
+`------------------------------------------------------------*/
+ yynewstate:
+  /* In all cases, when you get here, the value and location stacks
+     have just been pushed.  So pushing a state here evens the stacks.  */
+  yyssp++;
+
+ yysetstate:
+  *yyssp = yystate;
+
+  if (yyss + yystacksize - 1 <= yyssp)
+    {
+      /* Get the current used size of the three stacks, in elements.  */
+      YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+      {
+	/* Give user a chance to reallocate the stack.  Use copies of
+	   these so that the &'s don't force the real ones into
+	   memory.  */
+	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
+	   be undefined if yyoverflow is a macro.  */
+	yyoverflow (YY_("memory exhausted"),
+		    &yyss1, yysize * sizeof (*yyssp),
+		    &yyvs1, yysize * sizeof (*yyvsp),
+
+		    &yystacksize);
+
+	yyss = yyss1;
+	yyvs = yyvs1;
+      }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+      goto yyexhaustedlab;
+# else
+      /* Extend the stack our own way.  */
+      if (YYMAXDEPTH <= yystacksize)
+	goto yyexhaustedlab;
+      yystacksize *= 2;
+      if (YYMAXDEPTH < yystacksize)
+	yystacksize = YYMAXDEPTH;
+
+      {
+	yytype_int16 *yyss1 = yyss;
+	union yyalloc *yyptr =
+	  (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+	if (! yyptr)
+	  goto yyexhaustedlab;
+	YYSTACK_RELOCATE (yyss);
+	YYSTACK_RELOCATE (yyvs);
+
+#  undef YYSTACK_RELOCATE
+	if (yyss1 != yyssa)
+	  YYSTACK_FREE (yyss1);
+      }
+# endif
+#endif /* no yyoverflow */
+
+      yyssp = yyss + yysize - 1;
+      yyvsp = yyvs + yysize - 1;
+
+
+      YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+		  (unsigned long int) yystacksize));
+
+      if (yyss + yystacksize - 1 <= yyssp)
+	YYABORT;
+    }
+
+  YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+  goto yybackup;
+
+/*-----------.
+| yybackup.  |
+`-----------*/
+yybackup:
+
+  /* Do appropriate processing given the current state.  Read a
+     look-ahead token if we need one and don't already have one.  */
+
+  /* First try to decide what to do without reference to look-ahead token.  */
+  yyn = yypact[yystate];
+  if (yyn == YYPACT_NINF)
+    goto yydefault;
+
+  /* Not known => get a look-ahead token if don't already have one.  */
+
+  /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol.  */
+  if (yychar == YYEMPTY)
+    {
+      YYDPRINTF ((stderr, "Reading a token: "));
+      yychar = YYLEX;
+    }
+
+  if (yychar <= YYEOF)
+    {
+      yychar = yytoken = YYEOF;
+      YYDPRINTF ((stderr, "Now at end of input.\n"));
+    }
+  else
+    {
+      yytoken = YYTRANSLATE (yychar);
+      YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
+    }
+
+  /* If the proper action on seeing token YYTOKEN is to reduce or to
+     detect an error, take that action.  */
+  yyn += yytoken;
+  if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+    goto yydefault;
+  yyn = yytable[yyn];
+  if (yyn <= 0)
+    {
+      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 look-ahead token.  */
+  YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+
+  /* Discard the shifted token unless it is eof.  */
+  if (yychar != YYEOF)
+    yychar = YYEMPTY;
+
+  yystate = yyn;
+  *++yyvsp = yylval;
+
+  goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state.  |
+`-----------------------------------------------------------*/
+yydefault:
+  yyn = yydefact[yystate];
+  if (yyn == 0)
+    goto yyerrlab;
+  goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction.  |
+`-----------------------------*/
+yyreduce:
+  /* yyn is the number of a rule to reduce with.  */
+  yylen = yyr2[yyn];
+
+  /* If YYLEN is nonzero, implement the default value of the action:
+     `$$ = $1'.
+
+     Otherwise, the following line sets YYVAL to garbage.
+     This behavior is undocumented and Bison
+     users should not rely upon it.  Assigning to YYVAL
+     unconditionally makes the parser a bit smaller, and it avoids a
+     GCC warning that YYVAL may be used uninitialized.  */
+  yyval = yyvsp[1-yylen];
+
+
+  YY_REDUCE_PRINT (yyn);
+  switch (yyn)
+    {
+        case 3:
+#line 68 "a.y"
+    {
+		stmtline = lineno;
+	}
+    break;
+
+  case 5:
+#line 75 "a.y"
+    {
+		if((yyvsp[(1) - (2)].sym)->value != pc)
+			yyerror("redeclaration of %s", (yyvsp[(1) - (2)].sym)->name);
+		(yyvsp[(1) - (2)].sym)->value = pc;
+	}
+    break;
+
+  case 7:
+#line 82 "a.y"
+    {
+		(yyvsp[(1) - (2)].sym)->type = LLAB;
+		(yyvsp[(1) - (2)].sym)->value = pc;
+	}
+    break;
+
+  case 12:
+#line 93 "a.y"
+    {
+		(yyvsp[(1) - (3)].sym)->type = LVAR;
+		(yyvsp[(1) - (3)].sym)->value = (yyvsp[(3) - (3)].lval);
+	}
+    break;
+
+  case 13:
+#line 98 "a.y"
+    {
+		if((yyvsp[(1) - (3)].sym)->value != (yyvsp[(3) - (3)].lval))
+			yyerror("redeclaration of %s", (yyvsp[(1) - (3)].sym)->name);
+		(yyvsp[(1) - (3)].sym)->value = (yyvsp[(3) - (3)].lval);
+	}
+    break;
+
+  case 14:
+#line 103 "a.y"
+    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
+    break;
+
+  case 15:
+#line 104 "a.y"
+    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
+    break;
+
+  case 16:
+#line 105 "a.y"
+    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
+    break;
+
+  case 17:
+#line 106 "a.y"
+    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
+    break;
+
+  case 18:
+#line 107 "a.y"
+    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
+    break;
+
+  case 19:
+#line 108 "a.y"
+    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
+    break;
+
+  case 20:
+#line 109 "a.y"
+    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
+    break;
+
+  case 21:
+#line 110 "a.y"
+    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
+    break;
+
+  case 22:
+#line 111 "a.y"
+    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
+    break;
+
+  case 23:
+#line 112 "a.y"
+    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
+    break;
+
+  case 24:
+#line 113 "a.y"
+    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
+    break;
+
+  case 25:
+#line 114 "a.y"
+    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
+    break;
+
+  case 26:
+#line 115 "a.y"
+    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
+    break;
+
+  case 27:
+#line 116 "a.y"
+    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
+    break;
+
+  case 28:
+#line 117 "a.y"
+    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
+    break;
+
+  case 29:
+#line 118 "a.y"
+    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
+    break;
+
+  case 30:
+#line 119 "a.y"
+    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
+    break;
+
+  case 31:
+#line 120 "a.y"
+    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
+    break;
+
+  case 32:
+#line 121 "a.y"
+    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
+    break;
+
+  case 33:
+#line 124 "a.y"
+    {
+		(yyval.addr2).from = nullgen;
+		(yyval.addr2).to = nullgen;
+	}
+    break;
+
+  case 34:
+#line 129 "a.y"
+    {
+		(yyval.addr2).from = nullgen;
+		(yyval.addr2).to = nullgen;
+	}
+    break;
+
+  case 35:
+#line 136 "a.y"
+    {
+		(yyval.addr2).from = (yyvsp[(1) - (3)].addr);
+		(yyval.addr2).to = (yyvsp[(3) - (3)].addr);
+	}
+    break;
+
+  case 36:
+#line 143 "a.y"
+    {
+		(yyval.addr2).from = (yyvsp[(1) - (3)].addr);
+		(yyval.addr2).to = (yyvsp[(3) - (3)].addr);
+	}
+    break;
+
+  case 37:
+#line 150 "a.y"
+    {
+		(yyval.addr2).from = (yyvsp[(1) - (2)].addr);
+		(yyval.addr2).to = nullgen;
+	}
+    break;
+
+  case 38:
+#line 155 "a.y"
+    {
+		(yyval.addr2).from = (yyvsp[(1) - (1)].addr);
+		(yyval.addr2).to = nullgen;
+	}
+    break;
+
+  case 39:
+#line 162 "a.y"
+    {
+		(yyval.addr2).from = nullgen;
+		(yyval.addr2).to = (yyvsp[(2) - (2)].addr);
+	}
+    break;
+
+  case 40:
+#line 167 "a.y"
+    {
+		(yyval.addr2).from = nullgen;
+		(yyval.addr2).to = (yyvsp[(1) - (1)].addr);
+	}
+    break;
+
+  case 41:
+#line 174 "a.y"
+    {
+		(yyval.addr2).from = nullgen;
+		(yyval.addr2).to = (yyvsp[(2) - (2)].addr);
+	}
+    break;
+
+  case 42:
+#line 179 "a.y"
+    {
+		(yyval.addr2).from = nullgen;
+		(yyval.addr2).to = (yyvsp[(1) - (1)].addr);
+	}
+    break;
+
+  case 43:
+#line 184 "a.y"
+    {
+		(yyval.addr2).from = (yyvsp[(1) - (3)].addr);
+		(yyval.addr2).to = (yyvsp[(3) - (3)].addr);
+	}
+    break;
+
+  case 44:
+#line 191 "a.y"
+    {
+		(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 199 "a.y"
+    {
+		(yyval.addr2).from = (yyvsp[(1) - (3)].addr);
+		(yyval.addr2).to = (yyvsp[(3) - (3)].addr);
+	}
+    break;
+
+  case 46:
+#line 204 "a.y"
+    {
+		(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 212 "a.y"
+    {
+		(yyval.addr2).from = nullgen;
+		(yyval.addr2).to = (yyvsp[(2) - (2)].addr);
+	}
+    break;
+
+  case 48:
+#line 217 "a.y"
+    {
+		(yyval.addr2).from = nullgen;
+		(yyval.addr2).to = (yyvsp[(1) - (1)].addr);
+	}
+    break;
+
+  case 51:
+#line 228 "a.y"
+    {
+		(yyval.addr2).from = (yyvsp[(1) - (3)].addr);
+		(yyval.addr2).to = (yyvsp[(3) - (3)].addr);
+	}
+    break;
+
+  case 52:
+#line 233 "a.y"
+    {
+		(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.addr2).from.index = (yyvsp[(5) - (5)].lval);
+	}
+    break;
+
+  case 53:
+#line 243 "a.y"
+    {
+		(yyval.addr2).from = (yyvsp[(1) - (3)].addr);
+		(yyval.addr2).to = (yyvsp[(3) - (3)].addr);
+	}
+    break;
+
+  case 54:
+#line 248 "a.y"
+    {
+		(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.addr2).to.index = (yyvsp[(5) - (5)].lval);
+	}
+    break;
+
+  case 55:
+#line 258 "a.y"
+    {
+		(yyval.addr2).from = (yyvsp[(1) - (2)].addr);
+		(yyval.addr2).to = nullgen;
+	}
+    break;
+
+  case 56:
+#line 263 "a.y"
+    {
+		(yyval.addr2).from = (yyvsp[(1) - (1)].addr);
+		(yyval.addr2).to = nullgen;
+	}
+    break;
+
+  case 57:
+#line 268 "a.y"
+    {
+		(yyval.addr2).from = (yyvsp[(1) - (3)].addr);
+		(yyval.addr2).to = (yyvsp[(3) - (3)].addr);
+	}
+    break;
+
+  case 58:
+#line 275 "a.y"
+    {
+		(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 283 "a.y"
+    {
+		(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.addr2).to.offset = (yyvsp[(1) - (5)].addr).offset;
+	}
+    break;
+
+  case 60:
+#line 292 "a.y"
+    {
+		(yyval.addr2).from = nullgen;
+		(yyval.addr2).to = nullgen;
+	}
+    break;
+
+  case 61:
+#line 297 "a.y"
+    {
+		(yyval.addr2).from = (yyvsp[(1) - (1)].addr);
+		(yyval.addr2).to = nullgen;
+	}
+    break;
+
+  case 62:
+#line 304 "a.y"
+    {
+		(yyval.addr2).from = (yyvsp[(1) - (3)].addr);
+		(yyval.addr2).to = (yyvsp[(3) - (3)].addr);
+	}
+    break;
+
+  case 63:
+#line 309 "a.y"
+    {
+		(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 317 "a.y"
+    {
+		if((yyvsp[(1) - (3)].addr).type != D_CONST || (yyvsp[(3) - (3)].addr).type != D_CONST)
+			yyerror("arguments to PCDATA must be integer constants");
+		(yyval.addr2).from = (yyvsp[(1) - (3)].addr);
+		(yyval.addr2).to = (yyvsp[(3) - (3)].addr);
+	}
+    break;
+
+  case 65:
+#line 326 "a.y"
+    {
+		if((yyvsp[(1) - (3)].addr).type != D_CONST)
+			yyerror("index for FUNCDATA must be integer constant");
+		if((yyvsp[(3) - (3)].addr).type != D_EXTERN && (yyvsp[(3) - (3)].addr).type != D_STATIC)
+			yyerror("value for FUNCDATA must be symbol reference");
+		(yyval.addr2).from = (yyvsp[(1) - (3)].addr);
+		(yyval.addr2).to = (yyvsp[(3) - (3)].addr);
+	}
+    break;
+
+  case 70:
+#line 343 "a.y"
+    {
+		(yyval.addr) = (yyvsp[(2) - (2)].addr);
+	}
+    break;
+
+  case 71:
+#line 347 "a.y"
+    {
+		(yyval.addr) = (yyvsp[(2) - (2)].addr);
+	}
+    break;
+
+  case 76:
+#line 359 "a.y"
+    {
+		(yyval.addr) = nullgen;
+		(yyval.addr).type = D_BRANCH;
+		(yyval.addr).offset = (yyvsp[(1) - (4)].lval) + pc;
+	}
+    break;
+
+  case 77:
+#line 365 "a.y"
+    {
+		(yyval.addr) = nullgen;
+		if(pass == 2)
+			yyerror("undefined label: %s", (yyvsp[(1) - (2)].sym)->name);
+		(yyval.addr).type = D_BRANCH;
+		(yyval.addr).offset = (yyvsp[(2) - (2)].lval);
+	}
+    break;
+
+  case 78:
+#line 373 "a.y"
+    {
+		(yyval.addr) = nullgen;
+		(yyval.addr).type = D_BRANCH;
+		(yyval.addr).offset = (yyvsp[(1) - (2)].sym)->value + (yyvsp[(2) - (2)].lval);
+	}
+    break;
+
+  case 79:
+#line 381 "a.y"
+    {
+		(yyval.addr) = nullgen;
+		(yyval.addr).type = (yyvsp[(1) - (1)].lval);
+	}
+    break;
+
+  case 80:
+#line 386 "a.y"
+    {
+		(yyval.addr) = nullgen;
+		(yyval.addr).type = (yyvsp[(1) - (1)].lval);
+	}
+    break;
+
+  case 81:
+#line 391 "a.y"
+    {
+		(yyval.addr) = nullgen;
+		(yyval.addr).type = (yyvsp[(1) - (1)].lval);
+	}
+    break;
+
+  case 82:
+#line 396 "a.y"
+    {
+		(yyval.addr) = nullgen;
+		(yyval.addr).type = (yyvsp[(1) - (1)].lval);
+	}
+    break;
+
+  case 83:
+#line 401 "a.y"
+    {
+		(yyval.addr) = nullgen;
+		(yyval.addr).type = D_SP;
+	}
+    break;
+
+  case 84:
+#line 406 "a.y"
+    {
+		(yyval.addr) = nullgen;
+		(yyval.addr).type = (yyvsp[(1) - (1)].lval);
+	}
+    break;
+
+  case 85:
+#line 411 "a.y"
+    {
+		(yyval.addr) = nullgen;
+		(yyval.addr).type = (yyvsp[(1) - (1)].lval);
+	}
+    break;
+
+  case 86:
+#line 417 "a.y"
+    {
+		(yyval.addr) = nullgen;
+		(yyval.addr).type = D_CONST;
+		(yyval.addr).offset = (yyvsp[(2) - (2)].lval);
+	}
+    break;
+
+  case 87:
+#line 425 "a.y"
+    {
+		(yyval.addr) = nullgen;
+		(yyval.addr).type = D_CONST;
+		(yyval.addr).offset = (yyvsp[(2) - (2)].lval);
+	}
+    break;
+
+  case 88:
+#line 431 "a.y"
+    {
+		(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",
+				$2.sym->name);
+		 */
+	}
+    break;
+
+  case 89:
+#line 442 "a.y"
+    {
+		(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 448 "a.y"
+    {
+		(yyval.addr) = nullgen;
+		(yyval.addr).type = D_FCONST;
+		(yyval.addr).u.dval = (yyvsp[(2) - (2)].dval);
+	}
+    break;
+
+  case 91:
+#line 454 "a.y"
+    {
+		(yyval.addr) = nullgen;
+		(yyval.addr).type = D_FCONST;
+		(yyval.addr).u.dval = (yyvsp[(3) - (4)].dval);
+	}
+    break;
+
+  case 92:
+#line 460 "a.y"
+    {
+		(yyval.addr) = nullgen;
+		(yyval.addr).type = D_FCONST;
+		(yyval.addr).u.dval = -(yyvsp[(4) - (5)].dval);
+	}
+    break;
+
+  case 93:
+#line 466 "a.y"
+    {
+		(yyval.addr) = nullgen;
+		(yyval.addr).type = D_FCONST;
+		(yyval.addr).u.dval = -(yyvsp[(3) - (3)].dval);
+	}
+    break;
+
+  case 96:
+#line 478 "a.y"
+    {
+		(yyval.addr) = nullgen;
+		(yyval.addr).type = D_INDIR+D_NONE;
+		(yyval.addr).offset = (yyvsp[(1) - (1)].lval);
+	}
+    break;
+
+  case 97:
+#line 484 "a.y"
+    {
+		(yyval.addr) = nullgen;
+		(yyval.addr).type = D_INDIR+(yyvsp[(3) - (4)].lval);
+		(yyval.addr).offset = (yyvsp[(1) - (4)].lval);
+	}
+    break;
+
+  case 98:
+#line 490 "a.y"
+    {
+		(yyval.addr) = nullgen;
+		(yyval.addr).type = D_INDIR+D_SP;
+		(yyval.addr).offset = (yyvsp[(1) - (4)].lval);
+	}
+    break;
+
+  case 99:
+#line 496 "a.y"
+    {
+		(yyval.addr) = nullgen;
+		(yyval.addr).type = D_INDIR+(yyvsp[(3) - (4)].lval);
+		(yyval.addr).offset = (yyvsp[(1) - (4)].lval);
+	}
+    break;
+
+  case 100:
+#line 502 "a.y"
+    {
+		(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 511 "a.y"
+    {
+		(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 520 "a.y"
+    {
+		(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 529 "a.y"
+    {
+		(yyval.addr) = nullgen;
+		(yyval.addr).type = D_INDIR+(yyvsp[(2) - (3)].lval);
+	}
+    break;
+
+  case 104:
+#line 534 "a.y"
+    {
+		(yyval.addr) = nullgen;
+		(yyval.addr).type = D_INDIR+D_SP;
+	}
+    break;
+
+  case 105:
+#line 539 "a.y"
+    {
+		(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 547 "a.y"
+    {
+		(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 557 "a.y"
+    {
+		(yyval.addr) = (yyvsp[(1) - (1)].addr);
+	}
+    break;
+
+  case 108:
+#line 561 "a.y"
+    {
+		(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 570 "a.y"
+    {
+		(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 577 "a.y"
+    {
+		(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 585 "a.y"
+    {
+		(yyval.lval) = 0;
+	}
+    break;
+
+  case 112:
+#line 589 "a.y"
+    {
+		(yyval.lval) = (yyvsp[(2) - (2)].lval);
+	}
+    break;
+
+  case 113:
+#line 593 "a.y"
+    {
+		(yyval.lval) = -(yyvsp[(2) - (2)].lval);
+	}
+    break;
+
+  case 115:
+#line 600 "a.y"
+    {
+		(yyval.lval) = D_AUTO;
+	}
+    break;
+
+  case 118:
+#line 608 "a.y"
+    {
+		(yyval.lval) = (yyvsp[(1) - (1)].sym)->value;
+	}
+    break;
+
+  case 119:
+#line 612 "a.y"
+    {
+		(yyval.lval) = -(yyvsp[(2) - (2)].lval);
+	}
+    break;
+
+  case 120:
+#line 616 "a.y"
+    {
+		(yyval.lval) = (yyvsp[(2) - (2)].lval);
+	}
+    break;
+
+  case 121:
+#line 620 "a.y"
+    {
+		(yyval.lval) = ~(yyvsp[(2) - (2)].lval);
+	}
+    break;
+
+  case 122:
+#line 624 "a.y"
+    {
+		(yyval.lval) = (yyvsp[(2) - (3)].lval);
+	}
+    break;
+
+  case 123:
+#line 630 "a.y"
+    {
+		(yyval.lval) = ((yyvsp[(1) - (1)].lval) & 0xffffffffLL) +
+			((vlong)ArgsSizeUnknown << 32);
+	}
+    break;
+
+  case 124:
+#line 635 "a.y"
+    {
+		(yyval.lval) = (-(yyvsp[(2) - (2)].lval) & 0xffffffffLL) +
+			((vlong)ArgsSizeUnknown << 32);
+	}
+    break;
+
+  case 125:
+#line 640 "a.y"
+    {
+		(yyval.lval) = ((yyvsp[(1) - (3)].lval) & 0xffffffffLL) +
+			(((yyvsp[(3) - (3)].lval) & 0xffffLL) << 32);
+	}
+    break;
+
+  case 126:
+#line 645 "a.y"
+    {
+		(yyval.lval) = (-(yyvsp[(2) - (4)].lval) & 0xffffffffLL) +
+			(((yyvsp[(4) - (4)].lval) & 0xffffLL) << 32);
+	}
+    break;
+
+  case 128:
+#line 653 "a.y"
+    {
+		(yyval.lval) = (yyvsp[(1) - (3)].lval) + (yyvsp[(3) - (3)].lval);
+	}
+    break;
+
+  case 129:
+#line 657 "a.y"
+    {
+		(yyval.lval) = (yyvsp[(1) - (3)].lval) - (yyvsp[(3) - (3)].lval);
+	}
+    break;
+
+  case 130:
+#line 661 "a.y"
+    {
+		(yyval.lval) = (yyvsp[(1) - (3)].lval) * (yyvsp[(3) - (3)].lval);
+	}
+    break;
+
+  case 131:
+#line 665 "a.y"
+    {
+		(yyval.lval) = (yyvsp[(1) - (3)].lval) / (yyvsp[(3) - (3)].lval);
+	}
+    break;
+
+  case 132:
+#line 669 "a.y"
+    {
+		(yyval.lval) = (yyvsp[(1) - (3)].lval) % (yyvsp[(3) - (3)].lval);
+	}
+    break;
+
+  case 133:
+#line 673 "a.y"
+    {
+		(yyval.lval) = (yyvsp[(1) - (4)].lval) << (yyvsp[(4) - (4)].lval);
+	}
+    break;
+
+  case 134:
+#line 677 "a.y"
+    {
+		(yyval.lval) = (yyvsp[(1) - (4)].lval) >> (yyvsp[(4) - (4)].lval);
+	}
+    break;
+
+  case 135:
+#line 681 "a.y"
+    {
+		(yyval.lval) = (yyvsp[(1) - (3)].lval) & (yyvsp[(3) - (3)].lval);
+	}
+    break;
+
+  case 136:
+#line 685 "a.y"
+    {
+		(yyval.lval) = (yyvsp[(1) - (3)].lval) ^ (yyvsp[(3) - (3)].lval);
+	}
+    break;
+
+  case 137:
+#line 689 "a.y"
+    {
+		(yyval.lval) = (yyvsp[(1) - (3)].lval) | (yyvsp[(3) - (3)].lval);
+	}
+    break;
+
+
+/* Line 1267 of yacc.c.  */
+#line 2588 "y.tab.c"
+      default: break;
+    }
+  YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
+
+  YYPOPSTACK (yylen);
+  yylen = 0;
+  YY_STACK_PRINT (yyss, yyssp);
+
+  *++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.  */
+
+  yyn = yyr1[yyn];
+
+  yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+  if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+    yystate = yytable[yystate];
+  else
+    yystate = yydefgoto[yyn - YYNTOKENS];
+
+  goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+  /* If not already recovering from an error, report this error.  */
+  if (!yyerrstatus)
+    {
+      ++yynerrs;
+#if ! YYERROR_VERBOSE
+      yyerror (YY_("syntax error"));
+#else
+      {
+	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;
+	  }
+      }
+#endif
+    }
+
+
+
+  if (yyerrstatus == 3)
+    {
+      /* If just tried and failed to reuse look-ahead token after an
+	 error, discard it.  */
+
+      if (yychar <= YYEOF)
+	{
+	  /* Return failure if at end of input.  */
+	  if (yychar == YYEOF)
+	    YYABORT;
+	}
+      else
+	{
+	  yydestruct ("Error: discarding",
+		      yytoken, &yylval);
+	  yychar = YYEMPTY;
+	}
+    }
+
+  /* Else will try to reuse look-ahead token after shifting the error
+     token.  */
+  goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR.  |
+`---------------------------------------------------*/
+yyerrorlab:
+
+  /* Pacify compilers like GCC when the user code never invokes
+     YYERROR and the label yyerrorlab therefore never appears in user
+     code.  */
+  if (/*CONSTCOND*/ 0)
+     goto yyerrorlab;
+
+  /* Do not reclaim the symbols of the rule which action triggered
+     this YYERROR.  */
+  YYPOPSTACK (yylen);
+  yylen = 0;
+  YY_STACK_PRINT (yyss, yyssp);
+  yystate = *yyssp;
+  goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR.  |
+`-------------------------------------------------------------*/
+yyerrlab1:
+  yyerrstatus = 3;	/* Each real token shifted decrements this.  */
+
+  for (;;)
+    {
+      yyn = yypact[yystate];
+      if (yyn != YYPACT_NINF)
+	{
+	  yyn += YYTERROR;
+	  if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+	    {
+	      yyn = yytable[yyn];
+	      if (0 < yyn)
+		break;
+	    }
+	}
+
+      /* Pop the current state because it cannot handle the error token.  */
+      if (yyssp == yyss)
+	YYABORT;
+
+
+      yydestruct ("Error: popping",
+		  yystos[yystate], yyvsp);
+      YYPOPSTACK (1);
+      yystate = *yyssp;
+      YY_STACK_PRINT (yyss, yyssp);
+    }
+
+  if (yyn == YYFINAL)
+    YYACCEPT;
+
+  *++yyvsp = yylval;
+
+
+  /* Shift the error token.  */
+  YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+
+  yystate = yyn;
+  goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here.  |
+`-------------------------------------*/
+yyacceptlab:
+  yyresult = 0;
+  goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here.  |
+`-----------------------------------*/
+yyabortlab:
+  yyresult = 1;
+  goto yyreturn;
+
+#ifndef yyoverflow
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here.  |
+`-------------------------------------------------*/
+yyexhaustedlab:
+  yyerror (YY_("memory exhausted"));
+  yyresult = 2;
+  /* Fall through.  */
+#endif
+
+yyreturn:
+  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);
+  YY_STACK_PRINT (yyss, yyssp);
+  while (yyssp != yyss)
+    {
+      yydestruct ("Cleanup: popping",
+		  yystos[*yyssp], yyvsp);
+      YYPOPSTACK (1);
+    }
+#ifndef yyoverflow
+  if (yyss != yyssa)
+    YYSTACK_FREE (yyss);
+#endif
+#if YYERROR_VERBOSE
+  if (yymsg != yymsgbuf)
+    YYSTACK_FREE (yymsg);
+#endif
+  /* Make sure YYID is used.  */
+  return YYID (yyresult);
+}
+
+
+
diff --git a/src/cmd/6a/y.tab.h b/src/cmd/6a/y.tab.h
new file mode 100644
index 0000000..e0eb5e1
--- /dev/null
+++ b/src/cmd/6a/y.tab.h
@@ -0,0 +1,139 @@
+/* A Bison parser, made by GNU Bison 2.3.  */
+
+/* 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 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, 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
+   under terms of your choice, so long as that work isn't itself a
+   parser generator using the skeleton or a modified version thereof
+   as a parser skeleton.  Alternatively, if you modify or redistribute
+   the parser skeleton itself, you may (at your option) remove this
+   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
+   /* Put the tokens into the symbol table, so that GDB and other debuggers
+      know about them.  */
+   enum yytokentype {
+     LTYPE0 = 258,
+     LTYPE1 = 259,
+     LTYPE2 = 260,
+     LTYPE3 = 261,
+     LTYPE4 = 262,
+     LTYPEC = 263,
+     LTYPED = 264,
+     LTYPEN = 265,
+     LTYPER = 266,
+     LTYPET = 267,
+     LTYPEG = 268,
+     LTYPEPC = 269,
+     LTYPES = 270,
+     LTYPEM = 271,
+     LTYPEI = 272,
+     LTYPEXC = 273,
+     LTYPEX = 274,
+     LTYPERT = 275,
+     LTYPEF = 276,
+     LCONST = 277,
+     LFP = 278,
+     LPC = 279,
+     LSB = 280,
+     LBREG = 281,
+     LLREG = 282,
+     LSREG = 283,
+     LFREG = 284,
+     LMREG = 285,
+     LXREG = 286,
+     LFCONST = 287,
+     LSCONST = 288,
+     LSP = 289,
+     LNAME = 290,
+     LLAB = 291,
+     LVAR = 292
+   };
+#endif
+/* Tokens.  */
+#define LTYPE0 258
+#define LTYPE1 259
+#define LTYPE2 260
+#define LTYPE3 261
+#define LTYPE4 262
+#define LTYPEC 263
+#define LTYPED 264
+#define LTYPEN 265
+#define LTYPER 266
+#define LTYPET 267
+#define LTYPEG 268
+#define LTYPEPC 269
+#define LTYPES 270
+#define LTYPEM 271
+#define LTYPEI 272
+#define LTYPEXC 273
+#define LTYPEX 274
+#define LTYPERT 275
+#define LTYPEF 276
+#define LCONST 277
+#define LFP 278
+#define LPC 279
+#define LSB 280
+#define LBREG 281
+#define LLREG 282
+#define LSREG 283
+#define LFREG 284
+#define LMREG 285
+#define LXREG 286
+#define LFCONST 287
+#define LSCONST 288
+#define LSP 289
+#define LNAME 290
+#define LLAB 291
+#define LVAR 292
+
+
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+#line 38 "a.y"
+{
+	Sym	*sym;
+	vlong	lval;
+	double	dval;
+	char	sval[8];
+	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/Makefile b/src/cmd/6c/Makefile
new file mode 100644
index 0000000..3f528d7
--- /dev/null
+++ b/src/cmd/6c/Makefile
@@ -0,0 +1,5 @@
+# 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/6c/cgen.c b/src/cmd/6c/cgen.c
new file mode 100644
index 0000000..68dd7bb
--- /dev/null
+++ b/src/cmd/6c/cgen.c
@@ -0,0 +1,2046 @@
+// Inferno utils/6c/cgen.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/cgen.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 "gc.h"
+#include "../../runtime/funcdata.h"
+
+/* ,x/^(print|prtree)\(/i/\/\/ */
+int castup(Type*, Type*);
+int vaddr(Node *n, int a);
+
+void
+cgen(Node *n, Node *nn)
+{
+	Node *l, *r, *t;
+	Prog *p1;
+	Node nod, nod1, nod2, nod3, nod4;
+	int o, hardleft;
+	int32 v, curs;
+	vlong c;
+
+	if(debug['g']) {
+		prtree(nn, "cgen lhs");
+		prtree(n, "cgen");
+	}
+	if(n == Z || n->type == T)
+		return;
+	if(typesu[n->type->etype] && (n->op != OFUNC || nn != Z)) {
+		sugen(n, nn, n->type->width);
+		return;
+	}
+	l = n->left;
+	r = n->right;
+	o = n->op;
+	
+	if(n->op == OEXREG || (nn != Z && nn->op == OEXREG)) {
+		gmove(n, nn);
+		return;
+	}
+
+	if(n->addable >= INDEXED) {
+		if(nn == Z) {
+			switch(o) {
+			default:
+				nullwarn(Z, Z);
+				break;
+			case OINDEX:
+				nullwarn(l, r);
+				break;
+			}
+			return;
+		}
+		gmove(n, nn);
+		return;
+	}
+	curs = cursafe;
+
+	if(l->complex >= FNX)
+	if(r != Z && r->complex >= FNX)
+	switch(o) {
+	default:
+		if(cond(o) && typesu[l->type->etype])
+			break;
+
+		regret(&nod, r, 0, 0);
+		cgen(r, &nod);
+
+		regsalloc(&nod1, r);
+		gmove(&nod, &nod1);
+
+		regfree(&nod);
+		nod = *n;
+		nod.right = &nod1;
+
+		cgen(&nod, nn);
+		return;
+
+	case OFUNC:
+	case OCOMMA:
+	case OANDAND:
+	case OOROR:
+	case OCOND:
+	case ODOT:
+		break;
+	}
+
+	hardleft = l->addable < INDEXED || l->complex >= FNX;
+	switch(o) {
+	default:
+		diag(n, "unknown op in cgen: %O", o);
+		break;
+
+	case ONEG:
+	case OCOM:
+		if(nn == Z) {
+			nullwarn(l, Z);
+			break;
+		}
+		regalloc(&nod, l, nn);
+		cgen(l, &nod);
+		gopcode(o, n->type, Z, &nod);
+		gmove(&nod, nn);
+		regfree(&nod);
+		break;
+
+	case OAS:
+		if(l->op == OBIT)
+			goto bitas;
+		if(!hardleft) {
+			if(nn != Z || r->addable < INDEXED || hardconst(r)) {
+				if(r->complex >= FNX && nn == Z)
+					regret(&nod, r, 0, 0);
+				else
+					regalloc(&nod, r, nn);
+				cgen(r, &nod);
+				gmove(&nod, l);
+				if(nn != Z)
+					gmove(&nod, nn);
+				regfree(&nod);
+			} else
+				gmove(r, l);
+			break;
+		}
+		if(l->complex >= r->complex) {
+			if(l->op == OINDEX && immconst(r)) {
+				gmove(r, l);
+				break;
+			}
+			reglcgen(&nod1, l, Z);
+			if(r->addable >= INDEXED && !hardconst(r)) {
+				gmove(r, &nod1);
+				if(nn != Z)
+					gmove(r, nn);
+				regfree(&nod1);
+				break;
+			}
+			regalloc(&nod, r, nn);
+			cgen(r, &nod);
+		} else {
+			regalloc(&nod, r, nn);
+			cgen(r, &nod);
+			reglcgen(&nod1, l, Z);
+		}
+		gmove(&nod, &nod1);
+		regfree(&nod);
+		regfree(&nod1);
+		break;
+
+	bitas:
+		n = l->left;
+		regalloc(&nod, r, nn);
+		if(l->complex >= r->complex) {
+			reglcgen(&nod1, n, Z);
+			cgen(r, &nod);
+		} else {
+			cgen(r, &nod);
+			reglcgen(&nod1, n, Z);
+		}
+		regalloc(&nod2, n, Z);
+		gmove(&nod1, &nod2);
+		bitstore(l, &nod, &nod1, &nod2, nn);
+		break;
+
+	case OBIT:
+		if(nn == Z) {
+			nullwarn(l, Z);
+			break;
+		}
+		bitload(n, &nod, Z, Z, nn);
+		gmove(&nod, nn);
+		regfree(&nod);
+		break;
+
+	case OLSHR:
+	case OASHL:
+	case OASHR:
+		if(nn == Z) {
+			nullwarn(l, r);
+			break;
+		}
+		if(r->op == OCONST) {
+			if(r->vconst == 0) {
+				cgen(l, nn);
+				break;
+			}
+			regalloc(&nod, l, nn);
+			cgen(l, &nod);
+			if(o == OASHL && r->vconst == 1)
+				gopcode(OADD, n->type, &nod, &nod);
+			else
+				gopcode(o, n->type, r, &nod);
+			gmove(&nod, nn);
+			regfree(&nod);
+			break;
+		}
+
+		/*
+		 * get nod to be D_CX
+		 */
+		if(nodreg(&nod, nn, D_CX)) {
+			regsalloc(&nod1, n);
+			gmove(&nod, &nod1);
+			cgen(n, &nod);		/* probably a bug */
+			gmove(&nod, nn);
+			gmove(&nod1, &nod);
+			break;
+		}
+		reg[D_CX]++;
+		if(nn->op == OREGISTER && nn->reg == D_CX)
+			regalloc(&nod1, l, Z);
+		else
+			regalloc(&nod1, l, nn);
+		if(r->complex >= l->complex) {
+			cgen(r, &nod);
+			cgen(l, &nod1);
+		} else {
+			cgen(l, &nod1);
+			cgen(r, &nod);
+		}
+		gopcode(o, n->type, &nod, &nod1);
+		gmove(&nod1, nn);
+		regfree(&nod);
+		regfree(&nod1);
+		break;
+
+	case OADD:
+	case OSUB:
+	case OOR:
+	case OXOR:
+	case OAND:
+		if(nn == Z) {
+			nullwarn(l, r);
+			break;
+		}
+		if(typefd[n->type->etype])
+			goto fop;
+		if(r->op == OCONST) {
+			if(r->vconst == 0 && o != OAND) {
+				cgen(l, nn);
+				break;
+			}
+		}
+		if(n->op == OOR && l->op == OASHL && r->op == OLSHR
+		&& l->right->op == OCONST && r->right->op == OCONST
+		&& l->left->op == ONAME && r->left->op == ONAME
+		&& l->left->sym == r->left->sym
+		&& l->right->vconst + r->right->vconst == 8 * l->left->type->width) {
+			regalloc(&nod, l->left, nn);
+			cgen(l->left, &nod);
+			gopcode(OROTL, n->type, l->right, &nod);
+			gmove(&nod, nn);
+			regfree(&nod);
+			break;
+		}
+		if(n->op == OADD && l->op == OASHL && l->right->op == OCONST
+		&& (r->op != OCONST || r->vconst < -128 || r->vconst > 127)) {
+			c = l->right->vconst;
+			if(c > 0 && c <= 3) {
+				if(l->left->complex >= r->complex) {
+					regalloc(&nod, l->left, nn);
+					cgen(l->left, &nod);
+					if(r->addable < INDEXED) {
+						regalloc(&nod1, r, Z);
+						cgen(r, &nod1);
+						genmuladd(&nod, &nod, 1 << c, &nod1);
+						regfree(&nod1);
+					}
+					else
+						genmuladd(&nod, &nod, 1 << c, r);
+				}
+				else {
+					regalloc(&nod, r, nn);
+					cgen(r, &nod);
+					regalloc(&nod1, l->left, Z);
+					cgen(l->left, &nod1);
+					genmuladd(&nod, &nod1, 1 << c, &nod);
+					regfree(&nod1);
+				}
+				gmove(&nod, nn);
+				regfree(&nod);
+				break;
+			}
+		}
+		if(r->addable >= INDEXED && !hardconst(r)) {
+			regalloc(&nod, l, nn);
+			cgen(l, &nod);
+			gopcode(o, n->type, r, &nod);
+			gmove(&nod, nn);
+			regfree(&nod);
+			break;
+		}
+		if(l->complex >= r->complex) {
+			regalloc(&nod, l, nn);
+			cgen(l, &nod);
+			regalloc(&nod1, r, Z);
+			cgen(r, &nod1);
+			gopcode(o, n->type, &nod1, &nod);
+		} else {
+			regalloc(&nod1, r, nn);
+			cgen(r, &nod1);
+			regalloc(&nod, l, Z);
+			cgen(l, &nod);
+			gopcode(o, n->type, &nod1, &nod);
+		}
+		gmove(&nod, nn);
+		regfree(&nod);
+		regfree(&nod1);
+		break;
+
+	case OLMOD:
+	case OMOD:
+	case OLMUL:
+	case OLDIV:
+	case OMUL:
+	case ODIV:
+		if(nn == Z) {
+			nullwarn(l, r);
+			break;
+		}
+		if(typefd[n->type->etype])
+			goto fop;
+		if(r->op == OCONST && typechl[n->type->etype]) {	/* TO DO */
+			SET(v);
+			switch(o) {
+			case ODIV:
+			case OMOD:
+				c = r->vconst;
+				if(c < 0)
+					c = -c;
+				v = xlog2(c);
+				if(v < 0)
+					break;
+				/* fall thru */
+			case OMUL:
+			case OLMUL:
+				regalloc(&nod, l, nn);
+				cgen(l, &nod);
+				switch(o) {
+				case OMUL:
+				case OLMUL:
+					mulgen(n->type, r, &nod);
+					break;
+				case ODIV:
+					sdiv2(r->vconst, v, l, &nod);
+					break;
+				case OMOD:
+					smod2(r->vconst, v, l, &nod);
+					break;
+				}
+				gmove(&nod, nn);
+				regfree(&nod);
+				goto done;
+			case OLDIV:
+				c = r->vconst;
+				if((c & 0x80000000) == 0)
+					break;
+				regalloc(&nod1, l, Z);
+				cgen(l, &nod1);
+				regalloc(&nod, l, nn);
+				zeroregm(&nod);
+				gins(ACMPL, &nod1, nodconst(c));
+				gins(ASBBL, nodconst(-1), &nod);
+				regfree(&nod1);
+				gmove(&nod, nn);
+				regfree(&nod);
+				goto done;
+			}
+		}
+
+		if(o == OMUL || o == OLMUL) {
+			if(l->addable >= INDEXED) {
+				t = l;
+				l = r;
+				r = t;
+			}
+			reg[D_DX]++; // for gopcode case OMUL
+			regalloc(&nod, l, nn);
+			cgen(l, &nod);
+			if(r->addable < INDEXED || hardconst(r)) {
+				regalloc(&nod1, r, Z);
+				cgen(r, &nod1);
+				gopcode(OMUL, n->type, &nod1, &nod);
+				regfree(&nod1);
+			}else
+				gopcode(OMUL, n->type, r, &nod);	/* addressible */
+			gmove(&nod, nn);
+			regfree(&nod);
+			reg[D_DX]--;
+			break;
+		}
+
+		/*
+		 * get nod to be D_AX
+		 * get nod1 to be D_DX
+		 */
+		if(nodreg(&nod, nn, D_AX)) {
+			regsalloc(&nod2, n);
+			gmove(&nod, &nod2);
+			v = reg[D_AX];
+			reg[D_AX] = 0;
+
+			if(isreg(l, D_AX)) {
+				nod3 = *n;
+				nod3.left = &nod2;
+				cgen(&nod3, nn);
+			} else
+			if(isreg(r, D_AX)) {
+				nod3 = *n;
+				nod3.right = &nod2;
+				cgen(&nod3, nn);
+			} else
+				cgen(n, nn);
+
+			gmove(&nod2, &nod);
+			reg[D_AX] = v;
+			break;
+		}
+		if(nodreg(&nod1, nn, D_DX)) {
+			regsalloc(&nod2, n);
+			gmove(&nod1, &nod2);
+			v = reg[D_DX];
+			reg[D_DX] = 0;
+
+			if(isreg(l, D_DX)) {
+				nod3 = *n;
+				nod3.left = &nod2;
+				cgen(&nod3, nn);
+			} else
+			if(isreg(r, D_DX)) {
+				nod3 = *n;
+				nod3.right = &nod2;
+				cgen(&nod3, nn);
+			} else
+				cgen(n, nn);
+
+			gmove(&nod2, &nod1);
+			reg[D_DX] = v;
+			break;
+		}
+		reg[D_AX]++;
+
+		if(r->op == OCONST && (o == ODIV || o == OLDIV) && immconst(r) && typechl[r->type->etype]) {
+			reg[D_DX]++;
+			if(l->addable < INDEXED) {
+				regalloc(&nod2, l, Z);
+				cgen(l, &nod2);
+				l = &nod2;
+			}
+			if(o == ODIV)
+				sdivgen(l, r, &nod, &nod1);
+			else
+				udivgen(l, r, &nod, &nod1);
+			gmove(&nod1, nn);
+			if(l == &nod2)
+				regfree(l);
+			goto freeaxdx;
+		}
+
+		if(l->complex >= r->complex) {
+			cgen(l, &nod);
+			reg[D_DX]++;
+			if(o == ODIV || o == OMOD)
+				gins(typechl[l->type->etype]? ACDQ: ACQO, Z, Z);
+			if(o == OLDIV || o == OLMOD)
+				zeroregm(&nod1);
+			if(r->addable < INDEXED || r->op == OCONST) {
+				regsalloc(&nod3, r);
+				cgen(r, &nod3);
+				gopcode(o, n->type, &nod3, Z);
+			} else
+				gopcode(o, n->type, r, Z);
+		} else {
+			regsalloc(&nod3, r);
+			cgen(r, &nod3);
+			cgen(l, &nod);
+			reg[D_DX]++;
+			if(o == ODIV || o == OMOD)
+				gins(typechl[l->type->etype]? ACDQ: ACQO, Z, Z);
+			if(o == OLDIV || o == OLMOD)
+				zeroregm(&nod1);
+			gopcode(o, n->type, &nod3, Z);
+		}
+		if(o == OMOD || o == OLMOD)
+			gmove(&nod1, nn);
+		else
+			gmove(&nod, nn);
+	freeaxdx:
+		regfree(&nod);
+		regfree(&nod1);
+		break;
+
+	case OASLSHR:
+	case OASASHL:
+	case OASASHR:
+		if(r->op == OCONST)
+			goto asand;
+		if(l->op == OBIT)
+			goto asbitop;
+		if(typefd[n->type->etype])
+			goto asand;	/* can this happen? */
+
+		/*
+		 * get nod to be D_CX
+		 */
+		if(nodreg(&nod, nn, D_CX)) {
+			regsalloc(&nod1, n);
+			gmove(&nod, &nod1);
+			cgen(n, &nod);
+			if(nn != Z)
+				gmove(&nod, nn);
+			gmove(&nod1, &nod);
+			break;
+		}
+		reg[D_CX]++;
+
+		if(r->complex >= l->complex) {
+			cgen(r, &nod);
+			if(hardleft)
+				reglcgen(&nod1, l, Z);
+			else
+				nod1 = *l;
+		} else {
+			if(hardleft)
+				reglcgen(&nod1, l, Z);
+			else
+				nod1 = *l;
+			cgen(r, &nod);
+		}
+
+		gopcode(o, l->type, &nod, &nod1);
+		regfree(&nod);
+		if(nn != Z)
+			gmove(&nod1, nn);
+		if(hardleft)
+			regfree(&nod1);
+		break;
+
+	case OASAND:
+	case OASADD:
+	case OASSUB:
+	case OASXOR:
+	case OASOR:
+	asand:
+		if(l->op == OBIT)
+			goto asbitop;
+		if(typefd[l->type->etype] || typefd[r->type->etype])
+			goto asfop;
+		if(l->complex >= r->complex) {
+			if(hardleft)
+				reglcgen(&nod, l, Z);
+			else
+				nod = *l;
+			if(!immconst(r)) {
+				regalloc(&nod1, r, nn);
+				cgen(r, &nod1);
+				gopcode(o, l->type, &nod1, &nod);
+				regfree(&nod1);
+			} else
+				gopcode(o, l->type, r, &nod);
+		} else {
+			regalloc(&nod1, r, nn);
+			cgen(r, &nod1);
+			if(hardleft)
+				reglcgen(&nod, l, Z);
+			else
+				nod = *l;
+			gopcode(o, l->type, &nod1, &nod);
+			regfree(&nod1);
+		}
+		if(nn != Z)
+			gmove(&nod, nn);
+		if(hardleft)
+			regfree(&nod);
+		break;
+
+	asfop:
+		if(l->complex >= r->complex) {
+			if(hardleft)
+				reglcgen(&nod, l, Z);
+			else
+				nod = *l;
+			if(r->addable < INDEXED){
+				regalloc(&nod1, r, nn);
+				cgen(r, &nod1);
+			}else
+				nod1 = *r;
+			regalloc(&nod2, r, Z);
+			gmove(&nod, &nod2);
+			gopcode(o, r->type, &nod1, &nod2);
+			gmove(&nod2, &nod);
+			regfree(&nod2);
+			if(r->addable < INDEXED)
+				regfree(&nod1);
+		} else {
+			regalloc(&nod1, r, nn);
+			cgen(r, &nod1);
+			if(hardleft)
+				reglcgen(&nod, l, Z);
+			else
+				nod = *l;
+			if(o != OASMUL && o != OASADD) {
+				regalloc(&nod2, r, Z);
+				gmove(&nod, &nod2);
+				gopcode(o, r->type, &nod1, &nod2);
+				regfree(&nod1);
+				gmove(&nod2, &nod);
+				regfree(&nod2);
+			} else {
+				gopcode(o, r->type, &nod, &nod1);
+				gmove(&nod1, &nod);
+				regfree(&nod1);
+			}
+		}
+		if(nn != Z)
+			gmove(&nod, nn);
+		if(hardleft)
+			regfree(&nod);
+		break;
+
+	case OASLMUL:
+	case OASLDIV:
+	case OASLMOD:
+	case OASMUL:
+	case OASDIV:
+	case OASMOD:
+		if(l->op == OBIT)
+			goto asbitop;
+		if(typefd[n->type->etype] || typefd[r->type->etype])
+			goto asfop;
+		if(r->op == OCONST && typechl[n->type->etype]) {
+			SET(v);
+			switch(o) {
+			case OASDIV:
+			case OASMOD:
+				c = r->vconst;
+				if(c < 0)
+					c = -c;
+				v = xlog2(c);
+				if(v < 0)
+					break;
+				/* fall thru */
+			case OASMUL:
+			case OASLMUL:
+				if(hardleft)
+					reglcgen(&nod2, l, Z);
+				else
+					nod2 = *l;
+				regalloc(&nod, l, nn);
+				cgen(&nod2, &nod);
+				switch(o) {
+				case OASMUL:
+				case OASLMUL:
+					mulgen(n->type, r, &nod);
+					break;
+				case OASDIV:
+					sdiv2(r->vconst, v, l, &nod);
+					break;
+				case OASMOD:
+					smod2(r->vconst, v, l, &nod);
+					break;
+				}
+			havev:
+				gmove(&nod, &nod2);
+				if(nn != Z)
+					gmove(&nod, nn);
+				if(hardleft)
+					regfree(&nod2);
+				regfree(&nod);
+				goto done;
+			case OASLDIV:
+				c = r->vconst;
+				if((c & 0x80000000) == 0)
+					break;
+				if(hardleft)
+					reglcgen(&nod2, l, Z);
+				else
+					nod2 = *l;
+				regalloc(&nod1, l, nn);
+				cgen(&nod2, &nod1);
+				regalloc(&nod, l, nn);
+				zeroregm(&nod);
+				gins(ACMPL, &nod1, nodconst(c));
+				gins(ASBBL, nodconst(-1), &nod);
+				regfree(&nod1);
+				goto havev;
+			}
+		}
+
+		if(o == OASMUL) {
+			/* should favour AX */
+			regalloc(&nod, l, nn);
+			if(r->complex >= FNX) {
+				regalloc(&nod1, r, Z);
+				cgen(r, &nod1);
+				r = &nod1;
+			}
+			if(hardleft)
+				reglcgen(&nod2, l, Z);
+			else
+				nod2 = *l;
+			cgen(&nod2, &nod);
+			if(r->addable < INDEXED || hardconst(r)) {
+				if(r->complex < FNX) {
+					regalloc(&nod1, r, Z);
+					cgen(r, &nod1);
+				}
+				gopcode(OASMUL, n->type, &nod1, &nod);
+				regfree(&nod1);
+			}
+			else
+				gopcode(OASMUL, n->type, r, &nod);
+			if(r == &nod1)
+				regfree(r);
+			gmove(&nod, &nod2);
+			if(nn != Z)
+				gmove(&nod, nn);
+			regfree(&nod);
+			if(hardleft)
+				regfree(&nod2);
+			break;
+		}
+
+		/*
+		 * get nod to be D_AX
+		 * get nod1 to be D_DX
+		 */
+		if(nodreg(&nod, nn, D_AX)) {
+			regsalloc(&nod2, n);
+			gmove(&nod, &nod2);
+			v = reg[D_AX];
+			reg[D_AX] = 0;
+
+			if(isreg(l, D_AX)) {
+				nod3 = *n;
+				nod3.left = &nod2;
+				cgen(&nod3, nn);
+			} else
+			if(isreg(r, D_AX)) {
+				nod3 = *n;
+				nod3.right = &nod2;
+				cgen(&nod3, nn);
+			} else
+				cgen(n, nn);
+
+			gmove(&nod2, &nod);
+			reg[D_AX] = v;
+			break;
+		}
+		if(nodreg(&nod1, nn, D_DX)) {
+			regsalloc(&nod2, n);
+			gmove(&nod1, &nod2);
+			v = reg[D_DX];
+			reg[D_DX] = 0;
+
+			if(isreg(l, D_DX)) {
+				nod3 = *n;
+				nod3.left = &nod2;
+				cgen(&nod3, nn);
+			} else
+			if(isreg(r, D_DX)) {
+				nod3 = *n;
+				nod3.right = &nod2;
+				cgen(&nod3, nn);
+			} else
+				cgen(n, nn);
+
+			gmove(&nod2, &nod1);
+			reg[D_DX] = v;
+			break;
+		}
+		reg[D_AX]++;
+		reg[D_DX]++;
+
+		if(l->complex >= r->complex) {
+			if(hardleft)
+				reglcgen(&nod2, l, Z);
+			else
+				nod2 = *l;
+			cgen(&nod2, &nod);
+			if(r->op == OCONST && typechl[r->type->etype]) {
+				switch(o) {
+				case OASDIV:
+					sdivgen(&nod2, r, &nod, &nod1);
+					goto divdone;
+				case OASLDIV:
+					udivgen(&nod2, r, &nod, &nod1);
+				divdone:
+					gmove(&nod1, &nod2);
+					if(nn != Z)
+						gmove(&nod1, nn);
+					goto freelxaxdx;
+				}
+			}
+			if(o == OASDIV || o == OASMOD)
+				gins(typechl[l->type->etype]? ACDQ: ACQO, Z, Z);
+			if(o == OASLDIV || o == OASLMOD)
+				zeroregm(&nod1);
+			if(r->addable < INDEXED || r->op == OCONST ||
+			   !typeil[r->type->etype]) {
+				regalloc(&nod3, r, Z);
+				cgen(r, &nod3);
+				gopcode(o, l->type, &nod3, Z);
+				regfree(&nod3);
+			} else
+				gopcode(o, n->type, r, Z);
+		} else {
+			regalloc(&nod3, r, Z);
+			cgen(r, &nod3);
+			if(hardleft)
+				reglcgen(&nod2, l, Z);
+			else
+				nod2 = *l;
+			cgen(&nod2, &nod);
+			if(o == OASDIV || o == OASMOD)
+				gins(typechl[l->type->etype]? ACDQ: ACQO, Z, Z);
+			if(o == OASLDIV || o == OASLMOD)
+				zeroregm(&nod1);
+			gopcode(o, l->type, &nod3, Z);
+			regfree(&nod3);
+		}
+		if(o == OASMOD || o == OASLMOD) {
+			gmove(&nod1, &nod2);
+			if(nn != Z)
+				gmove(&nod1, nn);
+		} else {
+			gmove(&nod, &nod2);
+			if(nn != Z)
+				gmove(&nod, nn);
+		}
+	freelxaxdx:
+		if(hardleft)
+			regfree(&nod2);
+		regfree(&nod);
+		regfree(&nod1);
+		break;
+
+	fop:
+		if(l->complex >= r->complex) {
+			regalloc(&nod, l, nn);
+			cgen(l, &nod);
+			if(r->addable < INDEXED) {
+				regalloc(&nod1, r, Z);
+				cgen(r, &nod1);
+				gopcode(o, n->type, &nod1, &nod);
+				regfree(&nod1);
+			} else
+				gopcode(o, n->type, r, &nod);
+		} else {
+			/* TO DO: could do better with r->addable >= INDEXED */
+			regalloc(&nod1, r, Z);
+			cgen(r, &nod1);
+			regalloc(&nod, l, nn);
+			cgen(l, &nod);
+			gopcode(o, n->type, &nod1, &nod);
+			regfree(&nod1);
+		}
+		gmove(&nod, nn);
+		regfree(&nod);
+		break;
+
+	asbitop:
+		regalloc(&nod4, n, nn);
+		if(l->complex >= r->complex) {
+			bitload(l, &nod, &nod1, &nod2, &nod4);
+			regalloc(&nod3, r, Z);
+			cgen(r, &nod3);
+		} else {
+			regalloc(&nod3, r, Z);
+			cgen(r, &nod3);
+			bitload(l, &nod, &nod1, &nod2, &nod4);
+		}
+		gmove(&nod, &nod4);
+
+		{	/* TO DO: check floating point source */
+			Node onod;
+
+			/* incredible grot ... */
+			onod = nod3;
+			onod.op = o;
+			onod.complex = 2;
+			onod.addable = 0;
+			onod.type = tfield;
+			onod.left = &nod4;
+			onod.right = &nod3;
+			cgen(&onod, Z);
+		}
+		regfree(&nod3);
+		gmove(&nod4, &nod);
+		regfree(&nod4);
+		bitstore(l, &nod, &nod1, &nod2, nn);
+		break;
+
+	case OADDR:
+		if(nn == Z) {
+			nullwarn(l, Z);
+			break;
+		}
+		lcgen(l, nn);
+		break;
+
+	case OFUNC:
+		if(l->complex >= FNX) {
+			if(l->op != OIND)
+				diag(n, "bad function call");
+
+			regret(&nod, l->left, 0, 0);
+			cgen(l->left, &nod);
+			regsalloc(&nod1, l->left);
+			gmove(&nod, &nod1);
+			regfree(&nod);
+
+			nod = *n;
+			nod.left = &nod2;
+			nod2 = *l;
+			nod2.left = &nod1;
+			nod2.complex = 1;
+			cgen(&nod, nn);
+
+			return;
+		}
+		gargs(r, &nod, &nod1);
+		if(l->addable < INDEXED) {
+			reglcgen(&nod, l, nn);
+			nod.op = OREGISTER;
+			gopcode(OFUNC, n->type, Z, &nod);
+			regfree(&nod);
+		} else
+			gopcode(OFUNC, n->type, Z, l);
+		if(REGARG >= 0 && reg[REGARG])
+			reg[REGARG]--;
+		regret(&nod, n, l->type, 1); // update maxarg if nothing else
+		if(nn != Z)
+			gmove(&nod, nn);
+		if(nod.op == OREGISTER)
+			regfree(&nod);
+		break;
+
+	case OIND:
+		if(nn == Z) {
+			nullwarn(l, Z);
+			break;
+		}
+		regialloc(&nod, n, nn);
+		r = l;
+		while(r->op == OADD)
+			r = r->right;
+		if(sconst(r)) {
+			v = r->vconst;
+			r->vconst = 0;
+			cgen(l, &nod);
+			nod.xoffset += v;
+			r->vconst = v;
+		} else
+			cgen(l, &nod);
+		regind(&nod, n);
+		gmove(&nod, nn);
+		regfree(&nod);
+		break;
+
+	case OEQ:
+	case ONE:
+	case OLE:
+	case OLT:
+	case OGE:
+	case OGT:
+	case OLO:
+	case OLS:
+	case OHI:
+	case OHS:
+		if(nn == Z) {
+			nullwarn(l, r);
+			break;
+		}
+		boolgen(n, 1, nn);
+		break;
+
+	case OANDAND:
+	case OOROR:
+		boolgen(n, 1, nn);
+		if(nn == Z)
+			patch(p, pc);
+		break;
+
+	case ONOT:
+		if(nn == Z) {
+			nullwarn(l, Z);
+			break;
+		}
+		boolgen(n, 1, nn);
+		break;
+
+	case OCOMMA:
+		cgen(l, Z);
+		cgen(r, nn);
+		break;
+
+	case OCAST:
+		if(nn == Z) {
+			nullwarn(l, Z);
+			break;
+		}
+		/*
+		 * convert from types l->n->nn
+		 */
+		if(nocast(l->type, n->type) && nocast(n->type, nn->type)) {
+			/* both null, gen l->nn */
+			cgen(l, nn);
+			break;
+		}
+		if(ewidth[n->type->etype] < ewidth[l->type->etype]){
+			if(l->type->etype == TIND && typechlp[n->type->etype])
+				warn(n, "conversion of pointer to shorter integer");
+		}else if(0){
+			if(nocast(n->type, nn->type) || castup(n->type, nn->type)){
+				if(typefd[l->type->etype] != typefd[nn->type->etype])
+					regalloc(&nod, l, nn);
+				else
+					regalloc(&nod, nn, nn);
+				cgen(l, &nod);
+				gmove(&nod, nn);
+				regfree(&nod);
+				break;
+			}
+		}
+		regalloc(&nod, l, nn);
+		cgen(l, &nod);
+		regalloc(&nod1, n, &nod);
+		gmove(&nod, &nod1);
+		gmove(&nod1, nn);
+		regfree(&nod1);
+		regfree(&nod);
+		break;
+
+	case ODOT:
+		sugen(l, nodrat, l->type->width);
+		if(nn == Z)
+			break;
+		warn(n, "non-interruptable temporary");
+		nod = *nodrat;
+		if(!r || r->op != OCONST) {
+			diag(n, "DOT and no offset");
+			break;
+		}
+		nod.xoffset += (int32)r->vconst;
+		nod.type = n->type;
+		cgen(&nod, nn);
+		break;
+
+	case OCOND:
+		bcgen(l, 1);
+		p1 = p;
+		cgen(r->left, nn);
+		gbranch(OGOTO);
+		patch(p1, pc);
+		p1 = p;
+		cgen(r->right, nn);
+		patch(p1, pc);
+		break;
+
+	case OPOSTINC:
+	case OPOSTDEC:
+		v = 1;
+		if(l->type->etype == TIND)
+			v = l->type->link->width;
+		if(o == OPOSTDEC)
+			v = -v;
+		if(l->op == OBIT)
+			goto bitinc;
+		if(nn == Z)
+			goto pre;
+
+		if(hardleft)
+			reglcgen(&nod, l, Z);
+		else
+			nod = *l;
+
+		gmove(&nod, nn);
+		if(typefd[n->type->etype]) {
+			regalloc(&nod1, l, Z);
+			gmove(&nod, &nod1);
+			if(v < 0)
+				gopcode(OSUB, n->type, nodfconst(-v), &nod1);
+			else
+				gopcode(OADD, n->type, nodfconst(v), &nod1);
+			gmove(&nod1, &nod);
+			regfree(&nod1);
+		} else
+			gopcode(OADD, n->type, nodconst(v), &nod);
+		if(hardleft)
+			regfree(&nod);
+		break;
+
+	case OPREINC:
+	case OPREDEC:
+		v = 1;
+		if(l->type->etype == TIND)
+			v = l->type->link->width;
+		if(o == OPREDEC)
+			v = -v;
+		if(l->op == OBIT)
+			goto bitinc;
+
+	pre:
+		if(hardleft)
+			reglcgen(&nod, l, Z);
+		else
+			nod = *l;
+		if(typefd[n->type->etype]) {
+			regalloc(&nod1, l, Z);
+			gmove(&nod, &nod1);
+			if(v < 0)
+				gopcode(OSUB, n->type, nodfconst(-v), &nod1);
+			else
+				gopcode(OADD, n->type, nodfconst(v), &nod1);
+			gmove(&nod1, &nod);
+			regfree(&nod1);
+		} else
+			gopcode(OADD, n->type, nodconst(v), &nod);
+		if(nn != Z)
+			gmove(&nod, nn);
+		if(hardleft)
+			regfree(&nod);
+		break;
+
+	bitinc:
+		if(nn != Z && (o == OPOSTINC || o == OPOSTDEC)) {
+			bitload(l, &nod, &nod1, &nod2, Z);
+			gmove(&nod, nn);
+			gopcode(OADD, tfield, nodconst(v), &nod);
+			bitstore(l, &nod, &nod1, &nod2, Z);
+			break;
+		}
+		bitload(l, &nod, &nod1, &nod2, nn);
+		gopcode(OADD, tfield, nodconst(v), &nod);
+		bitstore(l, &nod, &nod1, &nod2, nn);
+		break;
+	}
+done:
+	cursafe = curs;
+}
+
+void
+reglcgen(Node *t, Node *n, Node *nn)
+{
+	Node *r;
+	int32 v;
+
+	regialloc(t, n, nn);
+	if(n->op == OIND) {
+		r = n->left;
+		while(r->op == OADD)
+			r = r->right;
+		if(sconst(r)) {
+			v = r->vconst;
+			r->vconst = 0;
+			lcgen(n, t);
+			t->xoffset += v;
+			r->vconst = v;
+			regind(t, n);
+			return;
+		}
+	}
+	lcgen(n, t);
+	regind(t, n);
+}
+
+void
+lcgen(Node *n, Node *nn)
+{
+	Prog *p1;
+	Node nod;
+
+	if(debug['g']) {
+		prtree(nn, "lcgen lhs");
+		prtree(n, "lcgen");
+	}
+	if(n == Z || n->type == T)
+		return;
+	if(nn == Z) {
+		nn = &nod;
+		regalloc(&nod, n, Z);
+	}
+	switch(n->op) {
+	default:
+		if(n->addable < INDEXED) {
+			diag(n, "unknown op in lcgen: %O", n->op);
+			break;
+		}
+		gopcode(OADDR, n->type, n, nn);
+		break;
+
+	case OCOMMA:
+		cgen(n->left, n->left);
+		lcgen(n->right, nn);
+		break;
+
+	case OIND:
+		cgen(n->left, nn);
+		break;
+
+	case OCOND:
+		bcgen(n->left, 1);
+		p1 = p;
+		lcgen(n->right->left, nn);
+		gbranch(OGOTO);
+		patch(p1, pc);
+		p1 = p;
+		lcgen(n->right->right, nn);
+		patch(p1, pc);
+		break;
+	}
+}
+
+void
+bcgen(Node *n, int true)
+{
+
+	if(n->type == T)
+		gbranch(OGOTO);
+	else
+		boolgen(n, true, Z);
+}
+
+void
+boolgen(Node *n, int true, Node *nn)
+{
+	int o;
+	Prog *p1, *p2, *p3;
+	Node *l, *r, nod, nod1;
+	int32 curs;
+
+	if(debug['g']) {
+		print("boolgen %d\n", true);
+		prtree(nn, "boolgen lhs");
+		prtree(n, "boolgen");
+	}
+	curs = cursafe;
+	l = n->left;
+	r = n->right;
+	switch(n->op) {
+
+	default:
+		o = ONE;
+		if(true)
+			o = OEQ;
+		/* bad, 13 is address of external that becomes constant */
+		if(n->addable >= INDEXED && n->addable != 13) {
+			if(typefd[n->type->etype]) {
+				regalloc(&nod1, n, Z);
+				gmove(nodfconst(0.0), &nod1);	/* TO DO: FREGZERO */
+				gopcode(o, n->type, n, &nod1);
+				regfree(&nod1);
+			} else
+				gopcode(o, n->type, n, nodconst(0));
+			goto com;
+		}
+		regalloc(&nod, n, nn);
+		cgen(n, &nod);
+		if(typefd[n->type->etype]) {
+			regalloc(&nod1, n, Z);
+			gmove(nodfconst(0.0), &nod1);	/* TO DO: FREGZERO */
+			gopcode(o, n->type, &nod, &nod1);
+			regfree(&nod1);
+		} else
+			gopcode(o, n->type, &nod, nodconst(0));
+		regfree(&nod);
+		goto com;
+
+	case OCONST:
+		o = vconst(n);
+		if(!true)
+			o = !o;
+		gbranch(OGOTO);
+		if(o) {
+			p1 = p;
+			gbranch(OGOTO);
+			patch(p1, pc);
+		}
+		goto com;
+
+	case OCOMMA:
+		cgen(l, Z);
+		boolgen(r, true, nn);
+		break;
+
+	case ONOT:
+		boolgen(l, !true, nn);
+		break;
+
+	case OCOND:
+		bcgen(l, 1);
+		p1 = p;
+		bcgen(r->left, true);
+		p2 = p;
+		gbranch(OGOTO);
+		patch(p1, pc);
+		p1 = p;
+		bcgen(r->right, !true);
+		patch(p2, pc);
+		p2 = p;
+		gbranch(OGOTO);
+		patch(p1, pc);
+		patch(p2, pc);
+		goto com;
+
+	case OANDAND:
+		if(!true)
+			goto caseor;
+
+	caseand:
+		bcgen(l, true);
+		p1 = p;
+		bcgen(r, !true);
+		p2 = p;
+		patch(p1, pc);
+		gbranch(OGOTO);
+		patch(p2, pc);
+		goto com;
+
+	case OOROR:
+		if(!true)
+			goto caseand;
+
+	caseor:
+		bcgen(l, !true);
+		p1 = p;
+		bcgen(r, !true);
+		p2 = p;
+		gbranch(OGOTO);
+		patch(p1, pc);
+		patch(p2, pc);
+		goto com;
+
+	case OEQ:
+	case ONE:
+	case OLE:
+	case OLT:
+	case OGE:
+	case OGT:
+	case OHI:
+	case OHS:
+	case OLO:
+	case OLS:
+		o = n->op;
+		if(true && typefd[l->type->etype] && (o == OEQ || o == ONE)) {
+			// Cannot rewrite !(l == r) into l != r with float64; it breaks NaNs.
+			// Jump around instead.
+			boolgen(n, 0, Z);
+			p1 = p;
+			gbranch(OGOTO);
+			patch(p1, pc);
+			goto com;
+		}
+		if(true)
+			o = comrel[relindex(o)];
+		if(l->complex >= FNX && r->complex >= FNX) {
+			regret(&nod, r, 0, 0);
+			cgen(r, &nod);
+			regsalloc(&nod1, r);
+			gmove(&nod, &nod1);
+			regfree(&nod);
+			nod = *n;
+			nod.right = &nod1;
+			boolgen(&nod, true, nn);
+			break;
+		}
+		if(immconst(l)) {
+			// NOTE: Reversing the comparison here is wrong
+			// for floating point ordering comparisons involving NaN,
+			// but we don't have any of those yet so we don't
+			// bother worrying about it.
+			o = invrel[relindex(o)];
+			/* bad, 13 is address of external that becomes constant */
+			if(r->addable < INDEXED || r->addable == 13) {
+				regalloc(&nod, r, nn);
+				cgen(r, &nod);
+				gopcode(o, l->type, &nod, l);
+				regfree(&nod);
+			} else
+				gopcode(o, l->type, r, l);
+			goto com;
+		}
+		if(typefd[l->type->etype])
+			o = invrel[relindex(logrel[relindex(o)])];
+		if(l->complex >= r->complex) {
+			regalloc(&nod, l, nn);
+			cgen(l, &nod);
+			if(r->addable < INDEXED || hardconst(r) || typefd[l->type->etype]) {
+				regalloc(&nod1, r, Z);
+				cgen(r, &nod1);
+				gopcode(o, l->type, &nod, &nod1);
+				regfree(&nod1);
+			} else {
+				gopcode(o, l->type, &nod, r);
+			}
+			regfree(&nod);
+			goto fixfloat;
+		}
+		regalloc(&nod, r, nn);
+		cgen(r, &nod);
+		if(l->addable < INDEXED || l->addable == 13 || hardconst(l)) {
+			regalloc(&nod1, l, Z);
+			cgen(l, &nod1);
+			if(typechl[l->type->etype] && ewidth[l->type->etype] <= ewidth[TINT])
+				gopcode(o, types[TINT], &nod1, &nod);
+			else
+				gopcode(o, l->type, &nod1, &nod);
+			regfree(&nod1);
+		} else
+			gopcode(o, l->type, l, &nod);
+		regfree(&nod);
+	fixfloat:
+		if(typefd[l->type->etype]) {
+			switch(o) {
+			case OEQ:
+				// Already emitted AJEQ; want AJEQ and AJPC.
+				p1 = p;
+				gbranch(OGOTO);
+				p2 = p;
+				patch(p1, pc);
+				gins(AJPC, Z, Z);
+				patch(p2, pc);
+				break;
+
+			case ONE:
+				// Already emitted AJNE; want AJNE or AJPS.
+				p1 = p;
+				gins(AJPS, Z, Z);
+				p2 = p;
+				gbranch(OGOTO);
+				p3 = p;
+				patch(p1, pc);
+				patch(p2, pc);
+				gbranch(OGOTO);
+				patch(p3, pc);
+				break;
+			}
+		}
+
+	com:
+		if(nn != Z) {
+			p1 = p;
+			gmove(nodconst(1L), nn);
+			gbranch(OGOTO);
+			p2 = p;
+			patch(p1, pc);
+			gmove(nodconst(0L), nn);
+			patch(p2, pc);
+		}
+		break;
+	}
+	cursafe = curs;
+}
+
+void
+sugen(Node *n, Node *nn, int32 w)
+{
+	Prog *p1;
+	Node nod0, nod1, nod2, nod3, nod4, *l, *r;
+	Type *t;
+	int c, mt, mo;
+	vlong o0, o1;
+
+	if(n == Z || n->type == T)
+		return;
+	if(debug['g']) {
+		prtree(nn, "sugen lhs");
+		prtree(n, "sugen");
+	}
+	if(nn == nodrat)
+		if(w > nrathole)
+			nrathole = w;
+	switch(n->op) {
+	case OIND:
+		if(nn == Z) {
+			nullwarn(n->left, Z);
+			break;
+		}
+
+	default:
+		goto copy;
+
+	case OCONST:
+		goto copy;
+
+	case ODOT:
+		l = n->left;
+		sugen(l, nodrat, l->type->width);
+		if(nn == Z)
+			break;
+		warn(n, "non-interruptable temporary");
+		nod1 = *nodrat;
+		r = n->right;
+		if(!r || r->op != OCONST) {
+			diag(n, "DOT and no offset");
+			break;
+		}
+		nod1.xoffset += (int32)r->vconst;
+		nod1.type = n->type;
+		sugen(&nod1, nn, w);
+		break;
+
+	case OSTRUCT:
+		/*
+		 * rewrite so lhs has no fn call
+		 */
+		if(nn != Z && side(nn)) {
+			nod1 = *n;
+			nod1.type = typ(TIND, n->type);
+			regret(&nod2, &nod1, 0, 0);
+			lcgen(nn, &nod2);
+			regsalloc(&nod0, &nod1);
+			cgen(&nod2, &nod0);
+			regfree(&nod2);
+
+			nod1 = *n;
+			nod1.op = OIND;
+			nod1.left = &nod0;
+			nod1.right = Z;
+			nod1.complex = 1;
+
+			sugen(n, &nod1, w);
+			return;
+		}
+
+		r = n->left;
+		for(t = n->type->link; t != T; t = t->down) {
+			l = r;
+			if(r->op == OLIST) {
+				l = r->left;
+				r = r->right;
+			}
+			if(nn == Z) {
+				cgen(l, nn);
+				continue;
+			}
+			/*
+			 * hand craft *(&nn + o) = l
+			 */
+			nod0 = znode;
+			nod0.op = OAS;
+			nod0.type = t;
+			nod0.left = &nod1;
+			nod0.right = nil;
+
+			nod1 = znode;
+			nod1.op = OIND;
+			nod1.type = t;
+			nod1.left = &nod2;
+
+			nod2 = znode;
+			nod2.op = OADD;
+			nod2.type = typ(TIND, t);
+			nod2.left = &nod3;
+			nod2.right = &nod4;
+
+			nod3 = znode;
+			nod3.op = OADDR;
+			nod3.type = nod2.type;
+			nod3.left = nn;
+
+			nod4 = znode;
+			nod4.op = OCONST;
+			nod4.type = nod2.type;
+			nod4.vconst = t->offset;
+
+			ccom(&nod0);
+			acom(&nod0);
+			xcom(&nod0);
+			nod0.addable = 0;
+			nod0.right = l;
+
+			// prtree(&nod0, "hand craft");
+			cgen(&nod0, Z);
+		}
+		break;
+
+	case OAS:
+		if(nn == Z) {
+			if(n->addable < INDEXED)
+				sugen(n->right, n->left, w);
+			break;
+		}
+
+		sugen(n->right, nodrat, w);
+		warn(n, "non-interruptable temporary");
+		sugen(nodrat, n->left, w);
+		sugen(nodrat, nn, w);
+		break;
+
+	case OFUNC:
+		if(!hasdotdotdot(n->left->type)) {
+			cgen(n, Z);
+			if(nn != Z) {
+				curarg -= n->type->width;
+				regret(&nod1, n, n->left->type, 1);
+				if(nn->complex >= FNX) {
+					regsalloc(&nod2, n);
+					cgen(&nod1, &nod2);
+					nod1 = nod2;
+				}
+				cgen(&nod1, nn);
+			}
+			break;
+		}
+		if(nn == Z) {
+			sugen(n, nodrat, w);
+			break;
+		}
+		if(nn->op != OIND) {
+			nn = new1(OADDR, nn, Z);
+			nn->type = types[TIND];
+			nn->addable = 0;
+		} else
+			nn = nn->left;
+		n = new(OFUNC, n->left, new(OLIST, nn, n->right));
+		n->type = types[TVOID];
+		n->left->type = types[TVOID];
+		cgen(n, Z);
+		break;
+
+	case OCOND:
+		bcgen(n->left, 1);
+		p1 = p;
+		sugen(n->right->left, nn, w);
+		gbranch(OGOTO);
+		patch(p1, pc);
+		p1 = p;
+		sugen(n->right->right, nn, w);
+		patch(p1, pc);
+		break;
+
+	case OCOMMA:
+		cgen(n->left, Z);
+		sugen(n->right, nn, w);
+		break;
+	}
+	return;
+
+copy:
+	if(nn == Z) {
+		switch(n->op) {
+		case OASADD:
+		case OASSUB:
+		case OASAND:
+		case OASOR:
+		case OASXOR:
+
+		case OASMUL:
+		case OASLMUL:
+
+
+		case OASASHL:
+		case OASASHR:
+		case OASLSHR:
+			break;
+
+		case OPOSTINC:
+		case OPOSTDEC:
+		case OPREINC:
+		case OPREDEC:
+			break;
+
+		default:
+			return;
+		}
+	}
+
+	if(n->complex >= FNX && nn != nil && nn->complex >= FNX) {
+		t = nn->type;
+		nn->type = types[TIND];
+		regialloc(&nod1, nn, Z);
+		lcgen(nn, &nod1);
+		regsalloc(&nod2, nn);
+		nn->type = t;
+
+		gins(AMOVQ, &nod1, &nod2);
+		regfree(&nod1);
+
+		nod2.type = typ(TIND, t);
+
+		nod1 = nod2;
+		nod1.op = OIND;
+		nod1.left = &nod2;
+		nod1.right = Z;
+		nod1.complex = 1;
+		nod1.type = t;
+
+		sugen(n, &nod1, w);
+		return;
+	}
+
+	if(w <= 32) {
+		c = cursafe;
+		if(n->left != Z && n->left->complex >= FNX
+		&& n->right != Z && n->right->complex >= FNX) {
+			regsalloc(&nod1, n->right);
+			cgen(n->right, &nod1);
+			nod2 = *n;
+			nod2.right = &nod1;
+			cgen(&nod2, nn);
+			cursafe = c;
+			return;
+		}
+		if(w & 7) {
+			mt = TLONG;
+			mo = AMOVL;
+		} else {
+			mt = TVLONG;
+			mo = AMOVQ;
+		}
+		if(n->complex > nn->complex) {
+			t = n->type;
+			n->type = types[mt];
+			regalloc(&nod0, n, Z);
+			if(!vaddr(n, 0)) {
+				reglcgen(&nod1, n, Z);
+				n->type = t;
+				n = &nod1;
+			}
+			else
+				n->type = t;
+
+			t = nn->type;
+			nn->type = types[mt];
+			if(!vaddr(nn, 0)) {
+				reglcgen(&nod2, nn, Z);
+				nn->type = t;
+				nn = &nod2;
+			}
+			else
+				nn->type = t;
+		} else {
+			t = nn->type;
+			nn->type = types[mt];
+			regalloc(&nod0, nn, Z);
+			if(!vaddr(nn, 0)) {
+				reglcgen(&nod2, nn, Z);
+				nn->type = t;
+				nn = &nod2;
+			}
+			else
+				nn->type = t;
+
+			t = n->type;
+			n->type = types[mt];
+			if(!vaddr(n, 0)) {
+				reglcgen(&nod1, n, Z);
+				n->type = t;
+				n = &nod1;
+			}
+			else
+				n->type = t;
+		}
+		o0 = n->xoffset;
+		o1 = nn->xoffset;
+		w /= ewidth[mt];
+		while(--w >= 0) {
+			gins(mo, n, &nod0);
+			gins(mo, &nod0, nn);
+			n->xoffset += ewidth[mt];
+			nn->xoffset += ewidth[mt];
+		}
+		n->xoffset = o0;
+		nn->xoffset = o1;
+		if(nn == &nod2)
+			regfree(&nod2);
+		if(n == &nod1)
+			regfree(&nod1);
+		regfree(&nod0);
+		return;
+	}
+
+	/* botch, need to save in .safe */
+	c = 0;
+	if(n->complex > nn->complex) {
+		t = n->type;
+		n->type = types[TIND];
+		nodreg(&nod1, n, D_SI);
+		if(reg[D_SI]) {
+			gins(APUSHQ, &nod1, Z);
+			c |= 1;
+			reg[D_SI]++;
+		}
+		lcgen(n, &nod1);
+		n->type = t;
+
+		t = nn->type;
+		nn->type = types[TIND];
+		nodreg(&nod2, nn, D_DI);
+		if(reg[D_DI]) {
+warn(Z, "DI botch");
+			gins(APUSHQ, &nod2, Z);
+			c |= 2;
+			reg[D_DI]++;
+		}
+		lcgen(nn, &nod2);
+		nn->type = t;
+	} else {
+		t = nn->type;
+		nn->type = types[TIND];
+		nodreg(&nod2, nn, D_DI);
+		if(reg[D_DI]) {
+warn(Z, "DI botch");
+			gins(APUSHQ, &nod2, Z);
+			c |= 2;
+			reg[D_DI]++;
+		}
+		lcgen(nn, &nod2);
+		nn->type = t;
+
+		t = n->type;
+		n->type = types[TIND];
+		nodreg(&nod1, n, D_SI);
+		if(reg[D_SI]) {
+			gins(APUSHQ, &nod1, Z);
+			c |= 1;
+			reg[D_SI]++;
+		}
+		lcgen(n, &nod1);
+		n->type = t;
+	}
+	nodreg(&nod3, n, D_CX);
+	if(reg[D_CX]) {
+		gins(APUSHQ, &nod3, Z);
+		c |= 4;
+		reg[D_CX]++;
+	}
+	gins(AMOVL, nodconst(w/SZ_INT), &nod3);
+	gins(ACLD, Z, Z);
+	gins(AREP, Z, Z);
+	gins(AMOVSL, Z, Z);
+	if(c & 4) {
+		gins(APOPQ, Z, &nod3);
+		reg[D_CX]--;
+	}
+	if(c & 2) {
+		gins(APOPQ, Z, &nod2);
+		reg[nod2.reg]--;
+	}
+	if(c & 1) {
+		gins(APOPQ, Z, &nod1);
+		reg[nod1.reg]--;
+	}
+}
+
+/*
+ * TO DO
+ */
+void
+layout(Node *f, Node *t, int c, int cv, Node *cn)
+{
+	Node t1, t2;
+
+	while(c > 3) {
+		layout(f, t, 2, 0, Z);
+		c -= 2;
+	}
+
+	regalloc(&t1, &lregnode, Z);
+	regalloc(&t2, &lregnode, Z);
+	if(c > 0) {
+		gmove(f, &t1);
+		f->xoffset += SZ_INT;
+	}
+	if(cn != Z)
+		gmove(nodconst(cv), cn);
+	if(c > 1) {
+		gmove(f, &t2);
+		f->xoffset += SZ_INT;
+	}
+	if(c > 0) {
+		gmove(&t1, t);
+		t->xoffset += SZ_INT;
+	}
+	if(c > 2) {
+		gmove(f, &t1);
+		f->xoffset += SZ_INT;
+	}
+	if(c > 1) {
+		gmove(&t2, t);
+		t->xoffset += SZ_INT;
+	}
+	if(c > 2) {
+		gmove(&t1, t);
+		t->xoffset += SZ_INT;
+	}
+	regfree(&t1);
+	regfree(&t2);
+}
+
+/*
+ * constant is not vlong or fits as 32-bit signed immediate
+ */
+int
+immconst(Node *n)
+{
+	int32 v;
+
+	if(n->op != OCONST || !typechlpv[n->type->etype])
+		return 0;
+	if(typechl[n->type->etype])
+		return 1;
+	v = n->vconst;
+	return n->vconst == (vlong)v;
+}
+
+/*
+ * if a constant and vlong, doesn't fit as 32-bit signed immediate
+ */
+int
+hardconst(Node *n)
+{
+	return n->op == OCONST && !immconst(n);
+}
+
+/*
+ * casting up to t2 covers an intermediate cast to t1
+ */
+int
+castup(Type *t1, Type *t2)
+{
+	int ft;
+
+	if(!nilcast(t1, t2))
+		return 0;
+	/* known to be small to large */
+	ft = t1->etype;
+	switch(t2->etype){
+	case TINT:
+	case TLONG:
+		return ft == TLONG || ft == TINT || ft == TSHORT || ft == TCHAR;
+	case TUINT:
+	case TULONG:
+		return ft == TULONG || ft == TUINT || ft == TUSHORT || ft == TUCHAR;
+	case TVLONG:
+		return ft == TLONG || ft == TINT || ft == TSHORT;
+	case TUVLONG:
+		return ft == TULONG || ft == TUINT || ft == TUSHORT;
+	}
+	return 0;
+}
+
+void
+zeroregm(Node *n)
+{
+	gins(AMOVL, nodconst(0), n);
+}
+
+/* do we need to load the address of a vlong? */
+int
+vaddr(Node *n, int a)
+{
+	switch(n->op) {
+	case ONAME:
+		if(a)
+			return 1;
+		return !(n->class == CEXTERN || n->class == CGLOBL || n->class == CSTATIC);
+
+	case OCONST:
+	case OREGISTER:
+	case OINDREG:
+		return 1;
+	}
+	return 0;
+}
+
+int32
+hi64v(Node *n)
+{
+	if(align(0, types[TCHAR], Aarg1, nil))	/* isbigendian */
+		return (int32)(n->vconst) & ~0L;
+	else
+		return (int32)((uvlong)n->vconst>>32) & ~0L;
+}
+
+int32
+lo64v(Node *n)
+{
+	if(align(0, types[TCHAR], Aarg1, nil))	/* isbigendian */
+		return (int32)((uvlong)n->vconst>>32) & ~0L;
+	else
+		return (int32)(n->vconst) & ~0L;
+}
+
+Node *
+hi64(Node *n)
+{
+	return nodconst(hi64v(n));
+}
+
+Node *
+lo64(Node *n)
+{
+	return nodconst(lo64v(n));
+}
+
+int
+cond(int op)
+{
+	switch(op) {
+	case OANDAND:
+	case OOROR:
+	case ONOT:
+		return 1;
+
+	case OEQ:
+	case ONE:
+	case OLE:
+	case OLT:
+	case OGE:
+	case OGT:
+	case OHI:
+	case OHS:
+	case OLO:
+	case OLS:
+		return 1;
+	}
+	return 0;
+}
diff --git a/src/cmd/6c/div.c b/src/cmd/6c/div.c
new file mode 100644
index 0000000..bad6c5e
--- /dev/null
+++ b/src/cmd/6c/div.c
@@ -0,0 +1,236 @@
+// Inferno utils/6c/div.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/div.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 "gc.h"
+
+/*
+ * Based on: Granlund, T.; Montgomery, P.L.
+ * "Division by Invariant Integers using Multiplication".
+ * SIGPLAN Notices, Vol. 29, June 1994, page 61.
+ */
+
+#define	TN(n)	((uvlong)1 << (n))
+#define	T31	TN(31)
+#define	T32	TN(32)
+
+int
+multiplier(uint32 d, int p, uvlong *mp)
+{
+	int l;
+	uvlong mlo, mhi, tlo, thi;
+
+	l = topbit(d - 1) + 1;
+	mlo = (((TN(l) - d) << 32) / d) + T32;
+	if(l + p == 64)
+		mhi = (((TN(l) + 1 - d) << 32) / d) + T32;
+	else
+		mhi = (TN(32 + l) + TN(32 + l - p)) / d;
+	/*assert(mlo < mhi);*/
+	while(l > 0) {
+		tlo = mlo >> 1;
+		thi = mhi >> 1;
+		if(tlo == thi)
+			break;
+		mlo = tlo;
+		mhi = thi;
+		l--;
+	}
+	*mp = mhi;
+	return l;
+}
+
+int
+sdiv(uint32 d, uint32 *mp, int *sp)
+{
+	int s;
+	uvlong m;
+
+	s = multiplier(d, 32 - 1, &m);
+	*mp = m;
+	*sp = s;
+	if(m >= T31)
+		return 1;
+	else
+		return 0;
+}
+
+int
+udiv(uint32 d, uint32 *mp, int *sp, int *pp)
+{
+	int p, s;
+	uvlong m;
+
+	s = multiplier(d, 32, &m);
+	p = 0;
+	if(m >= T32) {
+		while((d & 1) == 0) {
+			d >>= 1;
+			p++;
+		}
+		s = multiplier(d, 32 - p, &m);
+	}
+	*mp = m;
+	*pp = p;
+	if(m >= T32) {
+		/*assert(p == 0);*/
+		*sp = s - 1;
+		return 1;
+	}
+	else {
+		*sp = s;
+		return 0;
+	}
+}
+
+void
+sdivgen(Node *l, Node *r, Node *ax, Node *dx)
+{
+	int a, s;
+	uint32 m;
+	vlong c;
+
+	c = r->vconst;
+	if(c < 0)
+		c = -c;
+	a = sdiv(c, &m, &s);
+//print("a=%d i=%d s=%d m=%ux\n", a, (long)r->vconst, s, m);
+	gins(AMOVL, nodconst(m), ax);
+	gins(AIMULL, l, Z);
+	gins(AMOVL, l, ax);
+	if(a)
+		gins(AADDL, ax, dx);
+	gins(ASHRL, nodconst(31), ax);
+	gins(ASARL, nodconst(s), dx);
+	gins(AADDL, ax, dx);
+	if(r->vconst < 0)
+		gins(ANEGL, Z, dx);
+}
+
+void
+udivgen(Node *l, Node *r, Node *ax, Node *dx)
+{
+	int a, s, t;
+	uint32 m;
+	Node nod;
+
+	a = udiv(r->vconst, &m, &s, &t);
+//print("a=%ud i=%d p=%d s=%d m=%ux\n", a, (long)r->vconst, t, s, m);
+	if(t != 0) {
+		gins(AMOVL, l, ax);
+		gins(ASHRL, nodconst(t), ax);
+		gins(AMOVL, nodconst(m), dx);
+		gins(AMULL, dx, Z);
+	}
+	else if(a) {
+		if(l->op != OREGISTER) {
+			regalloc(&nod, l, Z);
+			gins(AMOVL, l, &nod);
+			l = &nod;
+		}
+		gins(AMOVL, nodconst(m), ax);
+		gins(AMULL, l, Z);
+		gins(AADDL, l, dx);
+		gins(ARCRL, nodconst(1), dx);
+		if(l == &nod)
+			regfree(l);
+	}
+	else {
+		gins(AMOVL, nodconst(m), ax);
+		gins(AMULL, l, Z);
+	}
+	if(s != 0)
+		gins(ASHRL, nodconst(s), dx);
+}
+
+void
+sext(Node *d, Node *s, Node *l)
+{
+	if(s->reg == D_AX && !nodreg(d, Z, D_DX)) {
+		reg[D_DX]++;
+		gins(ACDQ, Z, Z);
+	}
+	else {
+		regalloc(d, l, Z);
+		gins(AMOVL, s, d);
+		gins(ASARL, nodconst(31), d);
+	}
+}
+
+void
+sdiv2(int32 c, int v, Node *l, Node *n)
+{
+	Node nod;
+
+	if(v > 0) {
+		if(v > 1) {
+			sext(&nod, n, l);
+			gins(AANDL, nodconst((1 << v) - 1), &nod);
+			gins(AADDL, &nod, n);
+			regfree(&nod);
+		}
+		else {
+			gins(ACMPL, n, nodconst(0x80000000));
+			gins(ASBBL, nodconst(-1), n);
+		}
+		gins(ASARL, nodconst(v), n);
+	}
+	if(c < 0)
+		gins(ANEGL, Z, n);
+}
+
+void
+smod2(int32 c, int v, Node *l, Node *n)
+{
+	Node nod;
+
+	if(c == 1) {
+		zeroregm(n);
+		return;
+	}
+
+	sext(&nod, n, l);
+	if(v == 0) {
+		zeroregm(n);
+		gins(AXORL, &nod, n);
+		gins(ASUBL, &nod, n);
+	}
+	else if(v > 1) {
+		gins(AANDL, nodconst((1 << v) - 1), &nod);
+		gins(AADDL, &nod, n);
+		gins(AANDL, nodconst((1 << v) - 1), n);
+		gins(ASUBL, &nod, n);
+	}
+	else {
+		gins(AANDL, nodconst(1), n);
+		gins(AXORL, &nod, n);
+		gins(ASUBL, &nod, n);
+	}
+	regfree(&nod);
+}
diff --git a/src/cmd/6c/doc.go b/src/cmd/6c/doc.go
new file mode 100644
index 0000000..e0a22e7
--- /dev/null
+++ b/src/cmd/6c/doc.go
@@ -0,0 +1,16 @@
+// 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
+
+/*
+
+6c is a version of the Plan 9 C compiler.  The original is documented at
+
+	http://plan9.bell-labs.com/magic/man2html/1/8c
+
+Its target architecture is the x86-64, referred to by these tools as amd64.
+
+*/
+package main
diff --git a/src/cmd/6c/gc.h b/src/cmd/6c/gc.h
new file mode 100644
index 0000000..aa9d95d
--- /dev/null
+++ b/src/cmd/6c/gc.h
@@ -0,0 +1,359 @@
+// Inferno utils/6c/gc.h
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/gc.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.
+
+#include	<u.h>
+#include	"../cc/cc.h"
+#include	"../6l/6.out.h"
+
+/*
+ * 6c/amd64
+ * Intel 386 with AMD64 extensions
+ */
+#define	SZ_CHAR		1
+#define	SZ_SHORT	2
+#define	SZ_INT		4
+#define	SZ_LONG		4
+#define	SZ_IND		8
+#define	SZ_FLOAT	4
+#define	SZ_VLONG	8
+#define	SZ_DOUBLE	8
+#define	FNX		100
+
+typedef	struct	Case	Case;
+typedef	struct	C1	C1;
+typedef	struct	Reg	Reg;
+typedef	struct	Rgn	Rgn;
+typedef	struct	Renv	Renv;
+
+EXTERN	struct
+{
+	Node*	regtree;
+	Node*	basetree;
+	short	scale;
+	short	reg;
+	short	ptr;
+} idx;
+
+#define	INDEXED	9
+
+#define	A	((Addr*)0)
+#define	P	((Prog*)0)
+
+struct	Case
+{
+	Case*	link;
+	vlong	val;
+	int32	label;
+	char	def;
+	char	isv;
+};
+#define	C	((Case*)0)
+
+struct	C1
+{
+	vlong	val;
+	int32	label;
+};
+
+struct	Reg
+{
+	int32	pc;
+	int32	rpo;		/* reverse post ordering */
+
+	Bits	set;
+	Bits	use1;
+	Bits	use2;
+
+	Bits	refbehind;
+	Bits	refahead;
+	Bits	calbehind;
+	Bits	calahead;
+	Bits	regdiff;
+	Bits	act;
+
+	int32	regu;
+	int32	loop;		/* could be shorter */
+
+	Reg*	log5;
+	int32	active;
+
+	Reg*	p1;
+	Reg*	p2;
+	Reg*	p2link;
+	Reg*	s1;
+	Reg*	s2;
+	Reg*	link;
+	Prog*	prog;
+};
+#define	R	((Reg*)0)
+
+struct	Renv
+{
+	int	safe;
+	Node	base;
+	Node*	saved;
+	Node*	scope;
+};
+
+#define	NRGN	600
+struct	Rgn
+{
+	Reg*	enter;
+	short	cost;
+	short	varno;
+	short	regno;
+};
+
+EXTERN	int32	breakpc;
+EXTERN	int32	nbreak;
+EXTERN	Case*	cases;
+EXTERN	Node	constnode;
+EXTERN	Node	fconstnode;
+EXTERN	Node	vconstnode;
+EXTERN	int32	continpc;
+EXTERN	int32	curarg;
+EXTERN	int32	cursafe;
+EXTERN	Prog*	lastp;
+EXTERN	int32	maxargsafe;
+EXTERN	int	mnstring;
+EXTERN	Node*	nodrat;
+EXTERN	Node*	nodret;
+EXTERN	Node*	nodsafe;
+EXTERN	int32	nrathole;
+EXTERN	int32	nstring;
+EXTERN	Prog*	p;
+EXTERN	int32	pc;
+EXTERN	Node	lregnode;
+EXTERN	Node	qregnode;
+EXTERN	char	string[NSNAME];
+EXTERN	Sym*	symrathole;
+EXTERN	Node	znode;
+EXTERN	Prog	zprog;
+EXTERN	int	reg[D_NONE];
+EXTERN	int32	exregoffset;
+EXTERN	int32	exfregoffset;
+EXTERN	uchar	typechlpv[NTYPE];
+
+#define	BLOAD(r)	band(bnot(r->refbehind), r->refahead)
+#define	BSTORE(r)	band(bnot(r->calbehind), r->calahead)
+#define	LOAD(r)		(~r->refbehind.b[z] & r->refahead.b[z])
+#define	STORE(r)	(~r->calbehind.b[z] & r->calahead.b[z])
+
+#define	bset(a,n)	((a).b[(n)/32]&(1L<<(n)%32))
+
+#define	CLOAD	5
+#define	CREF	5
+#define	CINF	1000
+#define	LOOP	3
+
+EXTERN	Rgn	region[NRGN];
+EXTERN	Rgn*	rgp;
+EXTERN	int	nregion;
+EXTERN	int	nvar;
+
+EXTERN	Bits	externs;
+EXTERN	Bits	params;
+EXTERN	Bits	consts;
+EXTERN	Bits	addrs;
+
+EXTERN	int32	regbits;
+EXTERN	int32	exregbits;
+
+EXTERN	int	change;
+EXTERN	int	suppress;
+
+EXTERN	Reg*	firstr;
+EXTERN	Reg*	lastr;
+EXTERN	Reg	zreg;
+EXTERN	Reg*	freer;
+EXTERN	int32*	idom;
+EXTERN	Reg**	rpo2r;
+EXTERN	int32	maxnr;
+
+extern	char*	anames[];
+
+/*
+ * sgen.c
+ */
+void	codgen(Node*, Node*);
+void	gen(Node*);
+void	noretval(int);
+void	usedset(Node*, int);
+void	xcom(Node*);
+void	indx(Node*);
+int	bcomplex(Node*, Node*);
+Prog*	gtext(Sym*, int32);
+vlong	argsize(int);
+
+/*
+ * cgen.c
+ */
+void	zeroregm(Node*);
+void	cgen(Node*, Node*);
+void	reglcgen(Node*, Node*, Node*);
+void	lcgen(Node*, Node*);
+void	bcgen(Node*, int);
+void	boolgen(Node*, int, Node*);
+void	sugen(Node*, Node*, int32);
+int	needreg(Node*, int);
+int	hardconst(Node*);
+int	immconst(Node*);
+
+/*
+ * txt.c
+ */
+void	ginit(void);
+void	gclean(void);
+void	nextpc(void);
+void	gargs(Node*, Node*, Node*);
+void	garg1(Node*, Node*, Node*, int, Node**);
+Node*	nodconst(int32);
+Node*	nodfconst(double);
+Node*	nodgconst(vlong, Type*);
+int	nodreg(Node*, Node*, int);
+int	isreg(Node*, int);
+void	regret(Node*, Node*, Type*, int);
+void	regalloc(Node*, Node*, Node*);
+void	regfree(Node*);
+void	regialloc(Node*, Node*, Node*);
+void	regsalloc(Node*, Node*);
+void	regaalloc1(Node*, Node*);
+void	regaalloc(Node*, Node*);
+void	regind(Node*, Node*);
+void	gprep(Node*, Node*);
+void	naddr(Node*, Addr*);
+void	gcmp(int, Node*, vlong);
+void	gmove(Node*, Node*);
+void	gins(int a, Node*, Node*);
+void	gopcode(int, Type*, Node*, Node*);
+int	samaddr(Node*, Node*);
+void	gbranch(int);
+void	patch(Prog*, int32);
+int	sconst(Node*);
+void	gpseudo(int, Sym*, Node*);
+void	gprefetch(Node*);
+void	gpcdata(int, int);
+
+/*
+ * swt.c
+ */
+int	swcmp(const void*, const void*);
+void	doswit(Node*);
+void	swit1(C1*, int, int32, Node*);
+void	swit2(C1*, int, int32, Node*);
+void	newcase(void);
+void	bitload(Node*, Node*, Node*, Node*, Node*);
+void	bitstore(Node*, Node*, Node*, Node*, Node*);
+int32	outstring(char*, int32);
+void	nullwarn(Node*, Node*);
+void	sextern(Sym*, Node*, int32, int32);
+void	gextern(Sym*, Node*, int32, int32);
+void	outcode(void);
+
+/*
+ * list
+ */
+void	listinit(void);
+
+/*
+ * reg.c
+ */
+Reg*	rega(void);
+int	rcmp(const void*, const void*);
+void	regopt(Prog*);
+void	addmove(Reg*, int, int, int);
+Bits	mkvar(Reg*, Addr*);
+void	prop(Reg*, Bits, Bits);
+void	loopit(Reg*, int32);
+void	synch(Reg*, Bits);
+uint32	allreg(uint32, Rgn*);
+void	paint1(Reg*, int);
+uint32	paint2(Reg*, int);
+void	paint3(Reg*, int, int32, int);
+void	addreg(Addr*, int);
+
+/*
+ * peep.c
+ */
+void	peep(void);
+void	excise(Reg*);
+Reg*	uniqp(Reg*);
+Reg*	uniqs(Reg*);
+int	regtyp(Addr*);
+int	anyvar(Addr*);
+int	subprop(Reg*);
+int	copyprop(Reg*);
+int	copy1(Addr*, Addr*, Reg*, int);
+int	copyu(Prog*, Addr*, Addr*);
+
+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);
+int	BtoR(int32);
+int	BtoF(int32);
+
+#define	D_HI	D_NONE
+#define	D_LO	D_NONE
+
+/*
+ * bound
+ */
+void	comtarg(void);
+
+/*
+ * com64
+ */
+int	cond(int);
+int	com64(Node*);
+void	com64init(void);
+void	bool64(Node*);
+int32	lo64v(Node*);
+int32	hi64v(Node*);
+Node*	lo64(Node*);
+Node*	hi64(Node*);
+
+/*
+ * div/mul
+ */
+void	sdivgen(Node*, Node*, Node*, Node*);
+void	udivgen(Node*, Node*, Node*, Node*);
+void	sdiv2(int32, int, Node*, Node*);
+void	smod2(int32, int, Node*, Node*);
+void	mulgen(Type*, Node*, Node*);
+void	genmuladd(Node*, Node*, int, Node*);
+void	shiftit(Type*, Node*, Node*);
+
+#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
new file mode 100644
index 0000000..28f5b8d
--- /dev/null
+++ b/src/cmd/6c/list.c
@@ -0,0 +1,38 @@
+// 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.
+
+#define EXTERN
+#include "gc.h"
+
+void
+listinit(void)
+{
+	listinit6();
+}
diff --git a/src/cmd/6c/machcap.c b/src/cmd/6c/machcap.c
new file mode 100644
index 0000000..820d9a0
--- /dev/null
+++ b/src/cmd/6c/machcap.c
@@ -0,0 +1,107 @@
+// Inferno utils/6c/machcap.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/machcap.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 "gc.h"
+
+int
+machcap(Node *n)
+{
+
+	if(n == Z)
+		return 1;	/* test */
+
+	switch(n->op) {
+	case OMUL:
+	case OLMUL:
+	case OASMUL:
+	case OASLMUL:
+		if(typechl[n->type->etype])
+			return 1;
+		if(typev[n->type->etype])
+			return 1;
+		break;
+
+	case OCOM:
+	case ONEG:
+	case OADD:
+	case OAND:
+	case OOR:
+	case OSUB:
+	case OXOR:
+	case OASHL:
+	case OLSHR:
+	case OASHR:
+		if(typechlv[n->left->type->etype])
+			return 1;
+		break;
+
+	case OCAST:
+		return 1;
+
+	case OCOND:
+	case OCOMMA:
+	case OLIST:
+	case OANDAND:
+	case OOROR:
+	case ONOT:
+		return 1;
+
+	case OASADD:
+	case OASSUB:
+	case OASAND:
+	case OASOR:
+	case OASXOR:
+		return 1;
+
+	case OASASHL:
+	case OASASHR:
+	case OASLSHR:
+		return 1;
+
+	case OPOSTINC:
+	case OPOSTDEC:
+	case OPREINC:
+	case OPREDEC:
+		return 1;
+
+	case OEQ:
+	case ONE:
+	case OLE:
+	case OGT:
+	case OLT:
+	case OGE:
+	case OHI:
+	case OHS:
+	case OLO:
+	case OLS:
+		return 1;
+	}
+	return 0;
+}
diff --git a/src/cmd/6c/mul.c b/src/cmd/6c/mul.c
new file mode 100644
index 0000000..510edc0
--- /dev/null
+++ b/src/cmd/6c/mul.c
@@ -0,0 +1,458 @@
+// Inferno utils/6c/mul.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/mul.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 "gc.h"
+
+typedef struct	Malg	Malg;
+typedef struct	Mparam	Mparam;
+
+struct	Malg
+{
+	schar	vals[10];
+};
+
+struct	Mparam
+{
+	uint32	value;
+	schar	alg;
+	char	neg;
+	char	shift;
+	char	arg;
+	schar	off;
+};
+
+static	Mparam	multab[32];
+static	int	mulptr;
+
+static	Malg	malgs[]	=
+{
+	{0, 100},
+	{-1, 1, 100},
+	{-9, -5, -3, 3, 5, 9, 100},
+	{6, 10, 12, 18, 20, 24, 36, 40, 72, 100},
+	{-8, -4, -2, 2, 4, 8, 100},
+};
+
+/*
+ * return position of lowest 1
+ */
+int
+lowbit(uint32 v)
+{
+	int s, i;
+	uint32 m;
+
+	s = 0;
+	m = 0xFFFFFFFFUL;
+	for(i = 16; i > 0; i >>= 1) {
+		m >>= i;
+		if((v & m) == 0) {
+			v >>= i;
+			s += i;
+		}
+	}
+	return s;
+}
+
+void
+genmuladd(Node *d, Node *s, int m, Node *a)
+{
+	Node nod;
+
+	nod.op = OINDEX;
+	nod.left = a;
+	nod.right = s;
+	nod.scale = m;
+	nod.type = types[TIND];
+	nod.xoffset = 0;
+	xcom(&nod);
+	gopcode(OADDR, d->type, &nod, d);
+}
+
+void
+mulparam(uint32 m, Mparam *mp)
+{
+	int c, i, j, n, o, q, s;
+	int bc, bi, bn, bo, bq, bs, bt;
+	schar *p;
+	int32 u;
+	uint32 t;
+
+	bc = bq = 10;
+	bi = bn = bo = bs = bt = 0;
+	for(i = 0; i < nelem(malgs); i++) {
+		for(p = malgs[i].vals, j = 0; (o = p[j]) < 100; j++)
+		for(s = 0; s < 2; s++) {
+			c = 10;
+			q = 10;
+			u = m - o;
+			if(u == 0)
+				continue;
+			if(s) {
+				o = -o;
+				if(o > 0)
+					continue;
+				u = -u;
+			}
+			n = lowbit(u);
+			t = (uint32)u >> n;
+			switch(i) {
+			case 0:
+				if(t == 1) {
+					c = s + 1;
+					q = 0;
+					break;
+				}
+				switch(t) {
+				case 3:
+				case 5:
+				case 9:
+					c = s + 1;
+					if(n)
+						c++;
+					q = 0;
+					break;
+				}
+				if(s)
+					break;
+				switch(t) {
+				case 15:
+				case 25:
+				case 27:
+				case 45:
+				case 81:
+					c = 2;
+					if(n)
+						c++;
+					q = 1;
+					break;
+				}
+				break;
+			case 1:
+				if(t == 1) {
+					c = 3;
+					q = 3;
+					break;
+				}
+				switch(t) {
+				case 3:
+				case 5:
+				case 9:
+					c = 3;
+					q = 2;
+					break;
+				}
+				break;
+			case 2:
+				if(t == 1) {
+					c = 3;
+					q = 2;
+					break;
+				}
+				break;
+			case 3:
+				if(s)
+					break;
+				if(t == 1) {
+					c = 3;
+					q = 1;
+					break;
+				}
+				break;
+			case 4:
+				if(t == 1) {
+					c = 3;
+					q = 0;
+					break;
+				}
+				break;
+			}
+			if(c < bc || (c == bc && q > bq)) {
+				bc = c;
+				bi = i;
+				bn = n;
+				bo = o;
+				bq = q;
+				bs = s;
+				bt = t;
+			}
+		}
+	}
+	mp->value = m;
+	if(bc <= 3) {
+		mp->alg = bi;
+		mp->shift = bn;
+		mp->off = bo;
+		mp->neg = bs;
+		mp->arg = bt;
+	}
+	else
+		mp->alg = -1;
+}
+
+int
+m0(int a)
+{
+	switch(a) {
+	case -2:
+	case 2:
+		return 2;
+	case -3:
+	case 3:
+		return 2;
+	case -4:
+	case 4:
+		return 4;
+	case -5:
+	case 5:
+		return 4;
+	case 6:
+		return 2;
+	case -8:
+	case 8:
+		return 8;
+	case -9:
+	case 9:
+		return 8;
+	case 10:
+		return 4;
+	case 12:
+		return 2;
+	case 15:
+		return 2;
+	case 18:
+		return 8;
+	case 20:
+		return 4;
+	case 24:
+		return 2;
+	case 25:
+		return 4;
+	case 27:
+		return 2;
+	case 36:
+		return 8;
+	case 40:
+		return 4;
+	case 45:
+		return 4;
+	case 72:
+		return 8;
+	case 81:
+		return 8;
+	}
+	diag(Z, "bad m0");
+	return 0;
+}
+
+int
+m1(int a)
+{
+	switch(a) {
+	case 15:
+		return 4;
+	case 25:
+		return 4;
+	case 27:
+		return 8;
+	case 45:
+		return 8;
+	case 81:
+		return 8;
+	}
+	diag(Z, "bad m1");
+	return 0;
+}
+
+int
+m2(int a)
+{
+	switch(a) {
+	case 6:
+		return 2;
+	case 10:
+		return 2;
+	case 12:
+		return 4;
+	case 18:
+		return 2;
+	case 20:
+		return 4;
+	case 24:
+		return 8;
+	case 36:
+		return 4;
+	case 40:
+		return 8;
+	case 72:
+		return 8;
+	}
+	diag(Z, "bad m2");
+	return 0;
+}
+
+void
+shiftit(Type *t, Node *s, Node *d)
+{
+	int32 c;
+
+	c = (int32)s->vconst & 31;
+	switch(c) {
+	case 0:
+		break;
+	case 1:
+		gopcode(OADD, t, d, d);
+		break;
+	default:
+		gopcode(OASHL, t, s, d);
+	}
+}
+
+static int
+mulgen1(uint32 v, Node *n)
+{
+	int i, o;
+	Mparam *p;
+	Node nod, nods;
+
+	for(i = 0; i < nelem(multab); i++) {
+		p = &multab[i];
+		if(p->value == v)
+			goto found;
+	}
+
+	p = &multab[mulptr];
+	if(++mulptr == nelem(multab))
+		mulptr = 0;
+
+	mulparam(v, p);
+
+found:
+//	print("v=%.x a=%d n=%d s=%d g=%d o=%d \n", p->value, p->alg, p->neg, p->shift, p->arg, p->off);
+	if(p->alg < 0)
+		return 0;
+
+	nods = *nodconst(p->shift);
+
+	o = OADD;
+	if(p->alg > 0) {
+		regalloc(&nod, n, Z);
+		if(p->off < 0)
+			o = OSUB;
+	}
+
+	switch(p->alg) {
+	case 0:
+		switch(p->arg) {
+		case 1:
+			shiftit(n->type, &nods, n);
+			break;
+		case 15:
+		case 25:
+		case 27:
+		case 45:
+		case 81:
+			genmuladd(n, n, m1(p->arg), n);
+			/* fall thru */
+		case 3:
+		case 5:
+		case 9:
+			genmuladd(n, n, m0(p->arg), n);
+			shiftit(n->type, &nods, n);
+			break;
+		default:
+			goto bad;
+		}
+		if(p->neg == 1)
+			gins(ANEGL, Z, n);
+		break;
+	case 1:
+		switch(p->arg) {
+		case 1:
+			gmove(n, &nod);
+			shiftit(n->type, &nods, &nod);
+			break;
+		case 3:
+		case 5:
+		case 9:
+			genmuladd(&nod, n, m0(p->arg), n);
+			shiftit(n->type, &nods, &nod);
+			break;
+		default:
+			goto bad;
+		}
+		if(p->neg)
+			gopcode(o, n->type, &nod, n);
+		else {
+			gopcode(o, n->type, n, &nod);
+			gmove(&nod, n);
+		}
+		break;
+	case 2:
+		genmuladd(&nod, n, m0(p->off), n);
+		shiftit(n->type, &nods, n);
+		goto comop;
+	case 3:
+		genmuladd(&nod, n, m0(p->off), n);
+		shiftit(n->type, &nods, n);
+		genmuladd(n, &nod, m2(p->off), n);
+		break;
+	case 4:
+		genmuladd(&nod, n, m0(p->off), nodconst(0));
+		shiftit(n->type, &nods, n);
+		goto comop;
+	default:
+		diag(Z, "bad mul alg");
+		break;
+	comop:
+		if(p->neg) {
+			gopcode(o, n->type, n, &nod);
+			gmove(&nod, n);
+		}
+		else
+			gopcode(o, n->type, &nod, n);
+	}
+
+	if(p->alg > 0)
+		regfree(&nod);
+
+	return 1;
+
+bad:
+	diag(Z, "mulgen botch");
+	return 1;
+}
+
+void
+mulgen(Type *t, Node *r, Node *n)
+{
+	if(!mulgen1(r->vconst, n))
+		gopcode(OMUL, t, r, n);
+}
diff --git a/src/cmd/6c/peep.c b/src/cmd/6c/peep.c
new file mode 100644
index 0000000..a11067c
--- /dev/null
+++ b/src/cmd/6c/peep.c
@@ -0,0 +1,902 @@
+// Inferno utils/6c/peep.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/peep.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 "gc.h"
+
+static int
+needc(Prog *p)
+{
+	while(p != P) {
+		switch(p->as) {
+		case AADCL:
+		case AADCQ:
+		case ASBBL:
+		case ASBBQ:
+		case ARCRL:
+		case ARCRQ:
+			return 1;
+		case AADDL:
+		case AADDQ:
+		case ASUBL:
+		case ASUBQ:
+		case AJMP:
+		case ARET:
+		case ACALL:
+			return 0;
+		default:
+			if(p->to.type == D_BRANCH)
+				return 0;
+		}
+		p = p->link;
+	}
+	return 0;
+}
+
+static Reg*
+rnops(Reg *r)
+{
+	Prog *p;
+	Reg *r1;
+
+	if(r != R)
+	for(;;){
+		p = r->prog;
+		if(p->as != ANOP || p->from.type != D_NONE || p->to.type != D_NONE)
+			break;
+		r1 = uniqs(r);
+		if(r1 == R)
+			break;
+		r = r1;
+	}
+	return r;
+}
+
+void
+peep(void)
+{
+	Reg *r, *r1, *r2;
+	Prog *p, *p1;
+	int t;
+
+	/*
+	 * complete R structure
+	 */
+	t = 0;
+	for(r=firstr; r!=R; r=r1) {
+		r1 = r->link;
+		if(r1 == R)
+			break;
+		p = r->prog->link;
+		while(p != r1->prog)
+		switch(p->as) {
+		default:
+			r2 = rega();
+			r->link = r2;
+			r2->link = r1;
+
+			r2->prog = p;
+			r2->p1 = r;
+			r->s1 = r2;
+			r2->s1 = r1;
+			r1->p1 = r2;
+
+			r = r2;
+			t++;
+
+		case ADATA:
+		case AGLOBL:
+		case ANAME:
+		case ASIGNAME:
+			p = p->link;
+		}
+	}
+
+	pc = 0;	/* speculating it won't kill */
+
+loop1:
+
+	t = 0;
+	for(r=firstr; r!=R; r=r->link) {
+		p = r->prog;
+		switch(p->as) {
+		case AMOVL:
+		case AMOVQ:
+		case AMOVSS:
+		case AMOVSD:
+			if(regtyp(&p->to))
+			if(regtyp(&p->from)) {
+				if(copyprop(r)) {
+					excise(r);
+					t++;
+				} else
+				if(subprop(r) && copyprop(r)) {
+					excise(r);
+					t++;
+				}
+			}
+			break;
+
+		case AMOVBLZX:
+		case AMOVWLZX:
+		case AMOVBLSX:
+		case AMOVWLSX:
+			if(regtyp(&p->to)) {
+				r1 = rnops(uniqs(r));
+				if(r1 != R) {
+					p1 = r1->prog;
+					if(p->as == p1->as && p->to.type == p1->from.type){
+						p1->as = AMOVL;
+						t++;
+					}
+				}
+			}
+			break;
+
+		case AMOVBQSX:
+		case AMOVBQZX:
+		case AMOVWQSX:
+		case AMOVWQZX:
+		case AMOVLQSX:
+		case AMOVLQZX:
+			if(regtyp(&p->to)) {
+				r1 = rnops(uniqs(r));
+				if(r1 != R) {
+					p1 = r1->prog;
+					if(p->as == p1->as && p->to.type == p1->from.type){
+						p1->as = AMOVQ;
+						t++;
+					}
+				}
+			}
+			break;
+
+		case AADDL:
+		case AADDQ:
+		case AADDW:
+			if(p->from.type != D_CONST || needc(p->link))
+				break;
+			if(p->from.offset == -1){
+				if(p->as == AADDQ)
+					p->as = ADECQ;
+				else if(p->as == AADDL)
+					p->as = ADECL;
+				else
+					p->as = ADECW;
+				p->from = zprog.from;
+			}
+			else if(p->from.offset == 1){
+				if(p->as == AADDQ)
+					p->as = AINCQ;
+				else if(p->as == AADDL)
+					p->as = AINCL;
+				else
+					p->as = AINCW;
+				p->from = zprog.from;
+			}
+			break;
+
+		case ASUBL:
+		case ASUBQ:
+		case ASUBW:
+			if(p->from.type != D_CONST || needc(p->link))
+				break;
+			if(p->from.offset == -1) {
+				if(p->as == ASUBQ)
+					p->as = AINCQ;
+				else if(p->as == ASUBL)
+					p->as = AINCL;
+				else
+					p->as = AINCW;
+				p->from = zprog.from;
+			}
+			else if(p->from.offset == 1){
+				if(p->as == ASUBQ)
+					p->as = ADECQ;
+				else if(p->as == ASUBL)
+					p->as = ADECL;
+				else
+					p->as = ADECW;
+				p->from = zprog.from;
+			}
+			break;
+		}
+	}
+	if(t)
+		goto loop1;
+}
+
+void
+excise(Reg *r)
+{
+	Prog *p;
+
+	p = r->prog;
+	p->as = ANOP;
+	p->from = zprog.from;
+	p->to = zprog.to;
+}
+
+Reg*
+uniqp(Reg *r)
+{
+	Reg *r1;
+
+	r1 = r->p1;
+	if(r1 == R) {
+		r1 = r->p2;
+		if(r1 == R || r1->p2link != R)
+			return R;
+	} else
+		if(r->p2 != R)
+			return R;
+	return r1;
+}
+
+Reg*
+uniqs(Reg *r)
+{
+	Reg *r1;
+
+	r1 = r->s1;
+	if(r1 == R) {
+		r1 = r->s2;
+		if(r1 == R)
+			return R;
+	} else
+		if(r->s2 != R)
+			return R;
+	return r1;
+}
+
+int
+regtyp(Addr *a)
+{
+	int t;
+
+	t = a->type;
+	if(t >= D_AX && t <= D_R15)
+		return 1;
+	if(t >= D_X0 && t <= D_X0+15)
+		return 1;
+	return 0;
+}
+
+/*
+ * the idea is to substitute
+ * one register for another
+ * from one MOV to another
+ *	MOV	a, R0
+ *	ADD	b, R0	/ no use of R1
+ *	MOV	R0, R1
+ * would be converted to
+ *	MOV	a, R1
+ *	ADD	b, R1
+ *	MOV	R1, R0
+ * hopefully, then the former or latter MOV
+ * will be eliminated by copy propagation.
+ */
+int
+subprop(Reg *r0)
+{
+	Prog *p;
+	Addr *v1, *v2;
+	Reg *r;
+	int t;
+
+	p = r0->prog;
+	v1 = &p->from;
+	if(!regtyp(v1))
+		return 0;
+	v2 = &p->to;
+	if(!regtyp(v2))
+		return 0;
+	for(r=uniqp(r0); r!=R; r=uniqp(r)) {
+		if(uniqs(r) == R)
+			break;
+		p = r->prog;
+		switch(p->as) {
+		case ACALL:
+			return 0;
+
+		case AIMULL:
+		case AIMULQ:
+		case AIMULW:
+			if(p->to.type != D_NONE)
+				break;
+			goto giveup;
+
+		case AROLB:
+		case AROLL:
+		case AROLQ:
+		case AROLW:
+		case ARORB:
+		case ARORL:
+		case ARORQ:
+		case ARORW:
+		case ASALB:
+		case ASALL:
+		case ASALQ:
+		case ASALW:
+		case ASARB:
+		case ASARL:
+		case ASARQ:
+		case ASARW:
+		case ASHLB:
+		case ASHLL:
+		case ASHLQ:
+		case ASHLW:
+		case ASHRB:
+		case ASHRL:
+		case ASHRQ:
+		case ASHRW:
+			if(p->from.type == D_CONST)
+				break;
+			goto giveup;
+
+		case ADIVB:
+		case ADIVL:
+		case ADIVQ:
+		case ADIVW:
+		case AIDIVB:
+		case AIDIVL:
+		case AIDIVQ:
+		case AIDIVW:
+		case AIMULB:
+		case AMULB:
+		case AMULL:
+		case AMULQ:
+		case AMULW:
+
+		case AREP:
+		case AREPN:
+
+		case ACWD:
+		case ACDQ:
+		case ACQO:
+
+		case ASTOSB:
+		case ASTOSL:
+		case ASTOSQ:
+		case AMOVSB:
+		case AMOVSL:
+		case AMOVSQ:
+		case AMOVQL:
+		giveup:
+			return 0;
+
+		case AMOVL:
+		case AMOVQ:
+			if(p->to.type == v1->type)
+				goto gotit;
+			break;
+		}
+		if(copyau(&p->from, v2) ||
+		   copyau(&p->to, v2))
+			break;
+		if(copysub(&p->from, v1, v2, 0) ||
+		   copysub(&p->to, v1, v2, 0))
+			break;
+	}
+	return 0;
+
+gotit:
+	copysub(&p->to, v1, v2, 1);
+	if(debug['P']) {
+		print("gotit: %D->%D\n%P", v1, v2, r->prog);
+		if(p->from.type == v2->type)
+			print(" excise");
+		print("\n");
+	}
+	for(r=uniqs(r); r!=r0; r=uniqs(r)) {
+		p = r->prog;
+		copysub(&p->from, v1, v2, 1);
+		copysub(&p->to, v1, v2, 1);
+		if(debug['P'])
+			print("%P\n", r->prog);
+	}
+	t = v1->type;
+	v1->type = v2->type;
+	v2->type = t;
+	if(debug['P'])
+		print("%P last\n", r->prog);
+	return 1;
+}
+
+/*
+ * The idea is to remove redundant copies.
+ *	v1->v2	F=0
+ *	(use v2	s/v2/v1/)*
+ *	set v1	F=1
+ *	use v2	return fail
+ *	-----------------
+ *	v1->v2	F=0
+ *	(use v2	s/v2/v1/)*
+ *	set v1	F=1
+ *	set v2	return success
+ */
+int
+copyprop(Reg *r0)
+{
+	Prog *p;
+	Addr *v1, *v2;
+	Reg *r;
+
+	p = r0->prog;
+	v1 = &p->from;
+	v2 = &p->to;
+	if(copyas(v1, v2))
+		return 1;
+	for(r=firstr; r!=R; r=r->link)
+		r->active = 0;
+	return copy1(v1, v2, r0->s1, 0);
+}
+
+int
+copy1(Addr *v1, Addr *v2, Reg *r, int f)
+{
+	int t;
+	Prog *p;
+
+	if(r->active) {
+		if(debug['P'])
+			print("act set; return 1\n");
+		return 1;
+	}
+	r->active = 1;
+	if(debug['P'])
+		print("copy %D->%D f=%d\n", v1, v2, f);
+	for(; r != R; r = r->s1) {
+		p = r->prog;
+		if(debug['P'])
+			print("%P", p);
+		if(!f && uniqp(r) == R) {
+			f = 1;
+			if(debug['P'])
+				print("; merge; f=%d", f);
+		}
+		t = copyu(p, v2, A);
+		switch(t) {
+		case 2:	/* rar, can't split */
+			if(debug['P'])
+				print("; %D rar; return 0\n", v2);
+			return 0;
+
+		case 3:	/* set */
+			if(debug['P'])
+				print("; %D set; return 1\n", v2);
+			return 1;
+
+		case 1:	/* used, substitute */
+		case 4:	/* use and set */
+			if(f) {
+				if(!debug['P'])
+					return 0;
+				if(t == 4)
+					print("; %D used+set and f=%d; return 0\n", v2, f);
+				else
+					print("; %D used and f=%d; return 0\n", v2, f);
+				return 0;
+			}
+			if(copyu(p, v2, v1)) {
+				if(debug['P'])
+					print("; sub fail; return 0\n");
+				return 0;
+			}
+			if(debug['P'])
+				print("; sub %D/%D", v2, v1);
+			if(t == 4) {
+				if(debug['P'])
+					print("; %D used+set; return 1\n", v2);
+				return 1;
+			}
+			break;
+		}
+		if(!f) {
+			t = copyu(p, v1, A);
+			if(!f && (t == 2 || t == 3 || t == 4)) {
+				f = 1;
+				if(debug['P'])
+					print("; %D set and !f; f=%d", v1, f);
+			}
+		}
+		if(debug['P'])
+			print("\n");
+		if(r->s2)
+			if(!copy1(v1, v2, r->s2, f))
+				return 0;
+	}
+	return 1;
+}
+
+/*
+ * return
+ * 1 if v only used (and substitute),
+ * 2 if read-alter-rewrite
+ * 3 if set
+ * 4 if set and used
+ * 0 otherwise (not touched)
+ */
+int
+copyu(Prog *p, Addr *v, Addr *s)
+{
+
+	switch(p->as) {
+
+	default:
+		if(debug['P'])
+			print("unknown op %A\n", p->as);
+		/* SBBL; ADCL; FLD1; SAHF */
+		return 2;
+
+
+	case ANEGB:
+	case ANEGW:
+	case ANEGL:
+	case ANEGQ:
+	case ANOTB:
+	case ANOTW:
+	case ANOTL:
+	case ANOTQ:
+		if(copyas(&p->to, v))
+			return 2;
+		break;
+
+	case ALEAL:	/* lhs addr, rhs store */
+	case ALEAQ:
+		if(copyas(&p->from, v))
+			return 2;
+
+
+	case ANOP:	/* rhs store */
+	case AMOVL:
+	case AMOVQ:
+	case AMOVBLSX:
+	case AMOVBLZX:
+	case AMOVBQSX:
+	case AMOVBQZX:
+	case AMOVLQSX:
+	case AMOVLQZX:
+	case AMOVWLSX:
+	case AMOVWLZX:
+	case AMOVWQSX:
+	case AMOVWQZX:
+	case AMOVQL:
+
+	case AMOVSS:
+	case AMOVSD:
+	case ACVTSD2SL:
+	case ACVTSD2SQ:
+	case ACVTSD2SS:
+	case ACVTSL2SD:
+	case ACVTSL2SS:
+	case ACVTSQ2SD:
+	case ACVTSQ2SS:
+	case ACVTSS2SD:
+	case ACVTSS2SL:
+	case ACVTSS2SQ:
+	case ACVTTSD2SL:
+	case ACVTTSD2SQ:
+	case ACVTTSS2SL:
+	case ACVTTSS2SQ:
+		if(copyas(&p->to, v)) {
+			if(s != A)
+				return copysub(&p->from, v, s, 1);
+			if(copyau(&p->from, v))
+				return 4;
+			return 3;
+		}
+		goto caseread;
+
+	case AROLB:
+	case AROLL:
+	case AROLQ:
+	case AROLW:
+	case ARORB:
+	case ARORL:
+	case ARORQ:
+	case ARORW:
+	case ASALB:
+	case ASALL:
+	case ASALQ:
+	case ASALW:
+	case ASARB:
+	case ASARL:
+	case ASARQ:
+	case ASARW:
+	case ASHLB:
+	case ASHLL:
+	case ASHLQ:
+	case ASHLW:
+	case ASHRB:
+	case ASHRL:
+	case ASHRQ:
+	case ASHRW:
+		if(copyas(&p->to, v))
+			return 2;
+		if(copyas(&p->from, v))
+			if(p->from.type == D_CX)
+				return 2;
+		goto caseread;
+
+	case AADDB:	/* rhs rar */
+	case AADDL:
+	case AADDQ:
+	case AADDW:
+	case AANDB:
+	case AANDL:
+	case AANDQ:
+	case AANDW:
+	case ADECL:
+	case ADECQ:
+	case ADECW:
+	case AINCL:
+	case AINCQ:
+	case AINCW:
+	case ASUBB:
+	case ASUBL:
+	case ASUBQ:
+	case ASUBW:
+	case AORB:
+	case AORL:
+	case AORQ:
+	case AORW:
+	case AXORB:
+	case AXORL:
+	case AXORQ:
+	case AXORW:
+	case AMOVB:
+	case AMOVW:
+
+	case AADDSD:
+	case AADDSS:
+	case ACMPSD:
+	case ACMPSS:
+	case ADIVSD:
+	case ADIVSS:
+	case AMAXSD:
+	case AMAXSS:
+	case AMINSD:
+	case AMINSS:
+	case AMULSD:
+	case AMULSS:
+	case ARCPSS:
+	case ARSQRTSS:
+	case ASQRTSD:
+	case ASQRTSS:
+	case ASUBSD:
+	case ASUBSS:
+	case AXORPD:
+		if(copyas(&p->to, v))
+			return 2;
+		goto caseread;
+
+	case ACMPL:	/* read only */
+	case ACMPW:
+	case ACMPB:
+	case ACMPQ:
+
+	case APREFETCHT0:
+	case APREFETCHT1:
+	case APREFETCHT2:
+	case APREFETCHNTA:
+
+	case ACOMISD:
+	case ACOMISS:
+	case AUCOMISD:
+	case AUCOMISS:
+	caseread:
+		if(s != A) {
+			if(copysub(&p->from, v, s, 1))
+				return 1;
+			return copysub(&p->to, v, s, 1);
+		}
+		if(copyau(&p->from, v))
+			return 1;
+		if(copyau(&p->to, v))
+			return 1;
+		break;
+
+	case AJGE:	/* no reference */
+	case AJNE:
+	case AJLE:
+	case AJEQ:
+	case AJHI:
+	case AJLS:
+	case AJMI:
+	case AJPL:
+	case AJGT:
+	case AJLT:
+	case AJCC:
+	case AJCS:
+
+	case AADJSP:
+	case AWAIT:
+	case ACLD:
+		break;
+
+	case AIMULL:
+	case AIMULQ:
+	case AIMULW:
+		if(p->to.type != D_NONE) {
+			if(copyas(&p->to, v))
+				return 2;
+			goto caseread;
+		}
+
+	case ADIVB:
+	case ADIVL:
+	case ADIVQ:
+	case ADIVW:
+	case AIDIVB:
+	case AIDIVL:
+	case AIDIVQ:
+	case AIDIVW:
+	case AIMULB:
+	case AMULB:
+	case AMULL:
+	case AMULQ:
+	case AMULW:
+
+	case ACWD:
+	case ACDQ:
+	case ACQO:
+		if(v->type == D_AX || v->type == D_DX)
+			return 2;
+		goto caseread;
+
+	case AREP:
+	case AREPN:
+		if(v->type == D_CX)
+			return 2;
+		goto caseread;
+
+	case AMOVSB:
+	case AMOVSL:
+	case AMOVSQ:
+		if(v->type == D_DI || v->type == D_SI)
+			return 2;
+		goto caseread;
+
+	case ASTOSB:
+	case ASTOSL:
+	case ASTOSQ:
+		if(v->type == D_AX || v->type == D_DI)
+			return 2;
+		goto caseread;
+
+	case AJMP:	/* funny */
+		if(s != A) {
+			if(copysub(&p->to, v, s, 1))
+				return 1;
+			return 0;
+		}
+		if(copyau(&p->to, v))
+			return 1;
+		return 0;
+
+	case ARET:	/* funny */
+		if(v->type == REGRET || v->type == FREGRET)
+			return 2;
+		if(s != A)
+			return 1;
+		return 3;
+
+	case ACALL:	/* funny */
+		if(REGARG >= 0 && v->type == (uchar)REGARG)
+			return 2;
+
+		if(s != A) {
+			if(copysub(&p->to, v, s, 1))
+				return 1;
+			return 0;
+		}
+		if(copyau(&p->to, v))
+			return 4;
+		return 3;
+
+	case ATEXT:	/* funny */
+		if(REGARG >= 0 && v->type == (uchar)REGARG)
+			return 3;
+		return 0;
+	}
+	return 0;
+}
+
+/*
+ * direct reference,
+ * could be set/use depending on
+ * semantics
+ */
+int
+copyas(Addr *a, Addr *v)
+{
+	if(a->type != v->type)
+		return 0;
+	if(regtyp(v))
+		return 1;
+	if(v->type == D_AUTO || v->type == D_PARAM)
+		if(v->offset == a->offset)
+			return 1;
+	return 0;
+}
+
+/*
+ * either direct or indirect
+ */
+int
+copyau(Addr *a, Addr *v)
+{
+
+	if(copyas(a, v))
+		return 1;
+	if(regtyp(v)) {
+		if(a->type-D_INDIR == v->type)
+			return 1;
+		if(a->index == v->type)
+			return 1;
+	}
+	return 0;
+}
+
+/*
+ * substitute s for v in a
+ * return failure to substitute
+ */
+int
+copysub(Addr *a, Addr *v, Addr *s, int f)
+{
+	int t;
+
+	if(copyas(a, v)) {
+		t = s->type;
+		if(t >= D_AX && t <= D_R15 || t >= D_X0 && t <= D_X0+15) {
+			if(f)
+				a->type = t;
+		}
+		return 0;
+	}
+	if(regtyp(v)) {
+		t = v->type;
+		if(a->type == t+D_INDIR) {
+			if((s->type == D_BP || s->type == D_R13) && a->index != D_NONE)
+				return 1;	/* can't use BP-base with index */
+			if(f)
+				a->type = s->type+D_INDIR;
+//			return 0;
+		}
+		if(a->index == t) {
+			if(f)
+				a->index = s->type;
+			return 0;
+		}
+		return 0;
+	}
+	return 0;
+}
diff --git a/src/cmd/6c/reg.c b/src/cmd/6c/reg.c
new file mode 100644
index 0000000..6f8d3ce
--- /dev/null
+++ b/src/cmd/6c/reg.c
@@ -0,0 +1,1523 @@
+// Inferno utils/6c/reg.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/reg.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 "gc.h"
+
+static	void	fixjmp(Reg*);
+
+Reg*
+rega(void)
+{
+	Reg *r;
+
+	r = freer;
+	if(r == R) {
+		r = alloc(sizeof(*r));
+	} else
+		freer = r->link;
+
+	*r = zreg;
+	return r;
+}
+
+int
+rcmp(const void *a1, const void *a2)
+{
+	Rgn *p1, *p2;
+	int c1, c2;
+
+	p1 = (Rgn*)a1;
+	p2 = (Rgn*)a2;
+	c1 = p2->cost;
+	c2 = p1->cost;
+	if(c1 -= c2)
+		return c1;
+	return p2->varno - p1->varno;
+}
+
+void
+regopt(Prog *p)
+{
+	Reg *r, *r1, *r2;
+	Prog *p1;
+	int i, z;
+	int32 initpc, val, npc;
+	uint32 vreg;
+	Bits bit;
+	struct
+	{
+		int32	m;
+		int32	c;
+		Reg*	p;
+	} log5[6], *lp;
+
+	firstr = R;
+	lastr = R;
+	nvar = 0;
+	regbits = RtoB(D_SP) | RtoB(D_AX) | RtoB(D_X0);
+	for(z=0; z<BITS; z++) {
+		externs.b[z] = 0;
+		params.b[z] = 0;
+		consts.b[z] = 0;
+		addrs.b[z] = 0;
+	}
+
+	/*
+	 * pass 1
+	 * build aux data structure
+	 * allocate pcs
+	 * find use and set of variables
+	 */
+	val = 5L * 5L * 5L * 5L * 5L;
+	lp = log5;
+	for(i=0; i<5; i++) {
+		lp->m = val;
+		lp->c = 0;
+		lp->p = R;
+		val /= 5L;
+		lp++;
+	}
+	val = 0;
+	for(; p != P; p = p->link) {
+		switch(p->as) {
+		case ADATA:
+		case AGLOBL:
+		case ANAME:
+		case ASIGNAME:
+		case AFUNCDATA:
+			continue;
+		}
+		r = rega();
+		if(firstr == R) {
+			firstr = r;
+			lastr = r;
+		} else {
+			lastr->link = r;
+			r->p1 = lastr;
+			lastr->s1 = r;
+			lastr = r;
+		}
+		r->prog = p;
+		r->pc = val;
+		val++;
+
+		lp = log5;
+		for(i=0; i<5; i++) {
+			lp->c--;
+			if(lp->c <= 0) {
+				lp->c = lp->m;
+				if(lp->p != R)
+					lp->p->log5 = r;
+				lp->p = r;
+				(lp+1)->c = 0;
+				break;
+			}
+			lp++;
+		}
+
+		r1 = r->p1;
+		if(r1 != R)
+		switch(r1->prog->as) {
+		case ARET:
+		case AJMP:
+		case AIRETL:
+		case AIRETQ:
+			r->p1 = R;
+			r1->s1 = R;
+		}
+
+		bit = mkvar(r, &p->from);
+		if(bany(&bit))
+		switch(p->as) {
+		/*
+		 * funny
+		 */
+		case ALEAL:
+		case ALEAQ:
+			for(z=0; z<BITS; z++)
+				addrs.b[z] |= bit.b[z];
+			break;
+
+		/*
+		 * left side read
+		 */
+		default:
+			for(z=0; z<BITS; z++)
+				r->use1.b[z] |= bit.b[z];
+			break;
+		}
+
+		bit = mkvar(r, &p->to);
+		if(bany(&bit))
+		switch(p->as) {
+		default:
+			diag(Z, "reg: unknown op: %A", p->as);
+			break;
+
+		/*
+		 * right side read
+		 */
+		case ACMPB:
+		case ACMPL:
+		case ACMPQ:
+		case ACMPW:
+		case APREFETCHT0:
+		case APREFETCHT1:
+		case APREFETCHT2:
+		case APREFETCHNTA:
+		case ACOMISS:
+		case ACOMISD:
+		case AUCOMISS:
+		case AUCOMISD:
+			for(z=0; z<BITS; z++)
+				r->use2.b[z] |= bit.b[z];
+			break;
+
+		/*
+		 * right side write
+		 */
+		case ANOP:
+		case AMOVL:
+		case AMOVQ:
+		case AMOVB:
+		case AMOVW:
+		case AMOVBLSX:
+		case AMOVBLZX:
+		case AMOVBQSX:
+		case AMOVBQZX:
+		case AMOVLQSX:
+		case AMOVLQZX:
+		case AMOVWLSX:
+		case AMOVWLZX:
+		case AMOVWQSX:
+		case AMOVWQZX:
+		case AMOVQL:
+
+		case AMOVSS:
+		case AMOVSD:
+		case ACVTSD2SL:
+		case ACVTSD2SQ:
+		case ACVTSD2SS:
+		case ACVTSL2SD:
+		case ACVTSL2SS:
+		case ACVTSQ2SD:
+		case ACVTSQ2SS:
+		case ACVTSS2SD:
+		case ACVTSS2SL:
+		case ACVTSS2SQ:
+		case ACVTTSD2SL:
+		case ACVTTSD2SQ:
+		case ACVTTSS2SL:
+		case ACVTTSS2SQ:
+			for(z=0; z<BITS; z++)
+				r->set.b[z] |= bit.b[z];
+			break;
+
+		/*
+		 * right side read+write
+		 */
+		case AADDB:
+		case AADDL:
+		case AADDQ:
+		case AADDW:
+		case AANDB:
+		case AANDL:
+		case AANDQ:
+		case AANDW:
+		case ASUBB:
+		case ASUBL:
+		case ASUBQ:
+		case ASUBW:
+		case AORB:
+		case AORL:
+		case AORQ:
+		case AORW:
+		case AXORB:
+		case AXORL:
+		case AXORQ:
+		case AXORW:
+		case ASALB:
+		case ASALL:
+		case ASALQ:
+		case ASALW:
+		case ASARB:
+		case ASARL:
+		case ASARQ:
+		case ASARW:
+		case AROLB:
+		case AROLL:
+		case AROLQ:
+		case AROLW:
+		case ARORB:
+		case ARORL:
+		case ARORQ:
+		case ARORW:
+		case ASHLB:
+		case ASHLL:
+		case ASHLQ:
+		case ASHLW:
+		case ASHRB:
+		case ASHRL:
+		case ASHRQ:
+		case ASHRW:
+		case AIMULL:
+		case AIMULQ:
+		case AIMULW:
+		case ANEGL:
+		case ANEGQ:
+		case ANOTL:
+		case ANOTQ:
+		case AADCL:
+		case AADCQ:
+		case ASBBL:
+		case ASBBQ:
+
+		case AADDSD:
+		case AADDSS:
+		case ACMPSD:
+		case ACMPSS:
+		case ADIVSD:
+		case ADIVSS:
+		case AMAXSD:
+		case AMAXSS:
+		case AMINSD:
+		case AMINSS:
+		case AMULSD:
+		case AMULSS:
+		case ARCPSS:
+		case ARSQRTSS:
+		case ASQRTSD:
+		case ASQRTSS:
+		case ASUBSD:
+		case ASUBSS:
+		case AXORPD:
+			for(z=0; z<BITS; z++) {
+				r->set.b[z] |= bit.b[z];
+				r->use2.b[z] |= bit.b[z];
+			}
+			break;
+
+		/*
+		 * funny
+		 */
+		case ACALL:
+			for(z=0; z<BITS; z++)
+				addrs.b[z] |= bit.b[z];
+			break;
+		}
+
+		switch(p->as) {
+		case AIMULL:
+		case AIMULQ:
+		case AIMULW:
+			if(p->to.type != D_NONE)
+				break;
+
+		case AIDIVB:
+		case AIDIVL:
+		case AIDIVQ:
+		case AIDIVW:
+		case AIMULB:
+		case ADIVB:
+		case ADIVL:
+		case ADIVQ:
+		case ADIVW:
+		case AMULB:
+		case AMULL:
+		case AMULQ:
+		case AMULW:
+
+		case ACWD:
+		case ACDQ:
+		case ACQO:
+			r->regu |= RtoB(D_AX) | RtoB(D_DX);
+			break;
+
+		case AREP:
+		case AREPN:
+		case ALOOP:
+		case ALOOPEQ:
+		case ALOOPNE:
+			r->regu |= RtoB(D_CX);
+			break;
+
+		case AMOVSB:
+		case AMOVSL:
+		case AMOVSQ:
+		case AMOVSW:
+		case ACMPSB:
+		case ACMPSL:
+		case ACMPSQ:
+		case ACMPSW:
+			r->regu |= RtoB(D_SI) | RtoB(D_DI);
+			break;
+
+		case ASTOSB:
+		case ASTOSL:
+		case ASTOSQ:
+		case ASTOSW:
+		case ASCASB:
+		case ASCASL:
+		case ASCASQ:
+		case ASCASW:
+			r->regu |= RtoB(D_AX) | RtoB(D_DI);
+			break;
+
+		case AINSB:
+		case AINSL:
+		case AINSW:
+		case AOUTSB:
+		case AOUTSL:
+		case AOUTSW:
+			r->regu |= RtoB(D_DI) | RtoB(D_DX);
+			break;
+		}
+	}
+	if(firstr == R)
+		return;
+	initpc = pc - val;
+	npc = val;
+
+	/*
+	 * pass 2
+	 * turn branch references to pointers
+	 * build back pointers
+	 */
+	for(r = firstr; r != R; r = r->link) {
+		p = r->prog;
+		if(p->to.type == D_BRANCH) {
+			val = p->to.offset - initpc;
+			r1 = firstr;
+			while(r1 != R) {
+				r2 = r1->log5;
+				if(r2 != R && val >= r2->pc) {
+					r1 = r2;
+					continue;
+				}
+				if(r1->pc == val)
+					break;
+				r1 = r1->link;
+			}
+			if(r1 == R) {
+				nearln = p->lineno;
+				diag(Z, "ref not found\n%P", p);
+				continue;
+			}
+			if(r1 == r) {
+				nearln = p->lineno;
+				diag(Z, "ref to self\n%P", p);
+				continue;
+			}
+			r->s2 = r1;
+			r->p2link = r1->p2;
+			r1->p2 = r;
+		}
+	}
+	if(debug['R']) {
+		p = firstr->prog;
+		print("\n%L %D\n", p->lineno, &p->from);
+	}
+
+	/*
+	 * pass 2.1
+	 * fix jumps
+	 */
+	fixjmp(firstr);
+
+	/*
+	 * pass 2.5
+	 * find looping structure
+	 */
+	for(r = firstr; r != R; r = r->link)
+		r->active = 0;
+	change = 0;
+	loopit(firstr, npc);
+	if(debug['R'] && debug['v']) {
+		print("\nlooping structure:\n");
+		for(r = firstr; r != R; r = r->link) {
+			print("%d:%P", r->loop, r->prog);
+			for(z=0; z<BITS; z++)
+				bit.b[z] = r->use1.b[z] |
+					   r->use2.b[z] |
+					   r->set.b[z];
+			if(bany(&bit)) {
+				print("\t");
+				if(bany(&r->use1))
+					print(" u1=%B", r->use1);
+				if(bany(&r->use2))
+					print(" u2=%B", r->use2);
+				if(bany(&r->set))
+					print(" st=%B", r->set);
+			}
+			print("\n");
+		}
+	}
+
+	/*
+	 * pass 3
+	 * iterate propagating usage
+	 * 	back until flow graph is complete
+	 */
+loop1:
+	change = 0;
+	for(r = firstr; r != R; r = r->link)
+		r->active = 0;
+	for(r = firstr; r != R; r = r->link)
+		if(r->prog->as == ARET)
+			prop(r, zbits, zbits);
+loop11:
+	/* pick up unreachable code */
+	i = 0;
+	for(r = firstr; r != R; r = r1) {
+		r1 = r->link;
+		if(r1 && r1->active && !r->active) {
+			prop(r, zbits, zbits);
+			i = 1;
+		}
+	}
+	if(i)
+		goto loop11;
+	if(change)
+		goto loop1;
+
+
+	/*
+	 * pass 4
+	 * iterate propagating register/variable synchrony
+	 * 	forward until graph is complete
+	 */
+loop2:
+	change = 0;
+	for(r = firstr; r != R; r = r->link)
+		r->active = 0;
+	synch(firstr, zbits);
+	if(change)
+		goto loop2;
+
+
+	/*
+	 * pass 5
+	 * isolate regions
+	 * calculate costs (paint1)
+	 */
+	r = firstr;
+	if(r) {
+		for(z=0; z<BITS; z++)
+			bit.b[z] = (r->refahead.b[z] | r->calahead.b[z]) &
+			  ~(externs.b[z] | params.b[z] | addrs.b[z] | consts.b[z]);
+		if(bany(&bit)) {
+			nearln = r->prog->lineno;
+			warn(Z, "used and not set: %B", bit);
+			if(debug['R'] && !debug['w'])
+				print("used and not set: %B\n", bit);
+		}
+	}
+	if(debug['R'] && debug['v'])
+		print("\nprop structure:\n");
+	for(r = firstr; r != R; r = r->link)
+		r->act = zbits;
+	rgp = region;
+	nregion = 0;
+	for(r = firstr; r != R; r = r->link) {
+		if(debug['R'] && debug['v']) {
+			print("%P\t", r->prog);
+			if(bany(&r->set))
+				print("s:%B ", r->set);
+			if(bany(&r->refahead))
+				print("ra:%B ", r->refahead);
+			if(bany(&r->calahead))
+				print("ca:%B ", r->calahead);
+			print("\n");
+		}
+		for(z=0; z<BITS; z++)
+			bit.b[z] = r->set.b[z] &
+			  ~(r->refahead.b[z] | r->calahead.b[z] | addrs.b[z]);
+		if(bany(&bit)) {
+			nearln = r->prog->lineno;
+			warn(Z, "set and not used: %B", bit);
+			if(debug['R'])
+				print("set and not used: %B\n", bit);
+			excise(r);
+		}
+		for(z=0; z<BITS; z++)
+			bit.b[z] = LOAD(r) & ~(r->act.b[z] | addrs.b[z]);
+		while(bany(&bit)) {
+			i = bnum(bit);
+			rgp->enter = r;
+			rgp->varno = i;
+			change = 0;
+			if(debug['R'] && debug['v'])
+				print("\n");
+			paint1(r, i);
+			bit.b[i/32] &= ~(1L<<(i%32));
+			if(change <= 0) {
+				if(debug['R'])
+					print("%L$%d: %B\n",
+						r->prog->lineno, change, blsh(i));
+				continue;
+			}
+			rgp->cost = change;
+			nregion++;
+			if(nregion >= NRGN)
+				fatal(Z, "too many regions");
+			rgp++;
+		}
+	}
+	qsort(region, nregion, sizeof(region[0]), rcmp);
+
+	/*
+	 * pass 6
+	 * determine used registers (paint2)
+	 * replace code (paint3)
+	 */
+	rgp = region;
+	for(i=0; i<nregion; i++) {
+		bit = blsh(rgp->varno);
+		vreg = paint2(rgp->enter, rgp->varno);
+		vreg = allreg(vreg, rgp);
+		if(debug['R']) {
+			print("%L$%d %R: %B\n",
+				rgp->enter->prog->lineno,
+				rgp->cost,
+				rgp->regno,
+				bit);
+		}
+		if(rgp->regno != 0)
+			paint3(rgp->enter, rgp->varno, vreg, rgp->regno);
+		rgp++;
+	}
+	/*
+	 * pass 7
+	 * peep-hole on basic block
+	 */
+	if(!debug['R'] || debug['P'])
+		peep();
+
+	/*
+	 * pass 8
+	 * recalculate pc
+	 */
+	val = initpc;
+	for(r = firstr; r != R; r = r1) {
+		r->pc = val;
+		p = r->prog;
+		p1 = P;
+		r1 = r->link;
+		if(r1 != R)
+			p1 = r1->prog;
+		for(; p != p1; p = p->link) {
+			switch(p->as) {
+			default:
+				val++;
+				break;
+
+			case ANOP:
+			case ADATA:
+			case AGLOBL:
+			case ANAME:
+			case ASIGNAME:
+			case AFUNCDATA:
+				break;
+			}
+		}
+	}
+	pc = val;
+
+	/*
+	 * fix up branches
+	 */
+	if(debug['R'])
+		if(bany(&addrs))
+			print("addrs: %B\n", addrs);
+
+	r1 = 0; /* set */
+	for(r = firstr; r != R; r = r->link) {
+		p = r->prog;
+		if(p->to.type == D_BRANCH) {
+			p->to.offset = r->s2->pc;
+			p->to.u.branch = r->s2->prog;
+		}
+		r1 = r;
+	}
+
+	/*
+	 * last pass
+	 * eliminate nops
+	 * free aux structures
+	 */
+	for(p = firstr->prog; p != P; p = p->link){
+		while(p->link && p->link->as == ANOP)
+			p->link = p->link->link;
+	}
+	if(r1 != R) {
+		r1->link = freer;
+		freer = firstr;
+	}
+}
+
+/*
+ * add mov b,rn
+ * just after r
+ */
+void
+addmove(Reg *r, int bn, int rn, int f)
+{
+	Prog *p, *p1;
+	Addr *a;
+	Var *v;
+
+	p1 = alloc(sizeof(*p1));
+	*p1 = zprog;
+	p = r->prog;
+
+	p1->link = p->link;
+	p->link = p1;
+	p1->lineno = p->lineno;
+
+	v = var + bn;
+
+	a = &p1->to;
+	a->sym = v->sym;
+	a->offset = v->offset;
+	a->etype = v->etype;
+	a->type = v->name;
+
+	p1->as = AMOVL;
+	if(v->etype == TCHAR || v->etype == TUCHAR)
+		p1->as = AMOVB;
+	if(v->etype == TSHORT || v->etype == TUSHORT)
+		p1->as = AMOVW;
+	if(v->etype == TVLONG || v->etype == TUVLONG || (v->etype == TIND && ewidth[TIND] == 8))
+		p1->as = AMOVQ;
+	if(v->etype == TFLOAT)
+		p1->as = AMOVSS;
+	if(v->etype == TDOUBLE)
+		p1->as = AMOVSD;
+
+	p1->from.type = rn;
+	if(!f) {
+		p1->from = *a;
+		*a = zprog.from;
+		a->type = rn;
+		if(v->etype == TUCHAR)
+			p1->as = AMOVB;
+		if(v->etype == TUSHORT)
+			p1->as = AMOVW;
+	}
+	if(debug['R'])
+		print("%P\t.a%P\n", p, p1);
+}
+
+uint32
+doregbits(int r)
+{
+	uint32 b;
+
+	b = 0;
+	if(r >= D_INDIR)
+		r -= D_INDIR;
+	if(r >= D_AX && r <= D_R15)
+		b |= RtoB(r);
+	else
+	if(r >= D_AL && r <= D_R15B)
+		b |= RtoB(r-D_AL+D_AX);
+	else
+	if(r >= D_AH && r <= D_BH)
+		b |= RtoB(r-D_AH+D_AX);
+	else
+	if(r >= D_X0 && r <= D_X0+15)
+		b |= FtoB(r);
+	return b;
+}
+
+Bits
+mkvar(Reg *r, Addr *a)
+{
+	Var *v;
+	int i, t, n, et, z;
+	int32 o;
+	Bits bit;
+	LSym *s;
+
+	/*
+	 * mark registers used
+	 */
+	t = a->type;
+	r->regu |= doregbits(t);
+	r->regu |= doregbits(a->index);
+
+	switch(t) {
+	default:
+		goto none;
+	case D_ADDR:
+		a->type = a->index;
+		bit = mkvar(r, a);
+		for(z=0; z<BITS; z++)
+			addrs.b[z] |= bit.b[z];
+		a->type = t;
+		goto none;
+	case D_EXTERN:
+	case D_STATIC:
+	case D_PARAM:
+	case D_AUTO:
+		n = t;
+		break;
+	}
+	s = a->sym;
+	if(s == nil)
+		goto none;
+	if(s->name[0] == '.')
+		goto none;
+	et = a->etype;
+	o = a->offset;
+	v = var;
+	for(i=0; i<nvar; i++) {
+		if(s == v->sym)
+		if(n == v->name)
+		if(o == v->offset)
+			goto out;
+		v++;
+	}
+	if(nvar >= NVAR)
+		fatal(Z, "variable not optimized: %s", s->name);
+	i = nvar;
+	nvar++;
+	v = &var[i];
+	v->sym = s;
+	v->offset = o;
+	v->name = n;
+	v->etype = et;
+	if(debug['R'])
+		print("bit=%2d et=%2d %D\n", i, et, a);
+
+out:
+	bit = blsh(i);
+	if(n == D_EXTERN || n == D_STATIC)
+		for(z=0; z<BITS; z++)
+			externs.b[z] |= bit.b[z];
+	if(n == D_PARAM)
+		for(z=0; z<BITS; z++)
+			params.b[z] |= bit.b[z];
+	if(v->etype != et || !(typechlpfd[et] || typev[et]))	/* funny punning */
+		for(z=0; z<BITS; z++)
+			addrs.b[z] |= bit.b[z];
+	return bit;
+
+none:
+	return zbits;
+}
+
+void
+prop(Reg *r, Bits ref, Bits cal)
+{
+	Reg *r1, *r2;
+	int z;
+
+	for(r1 = r; r1 != R; r1 = r1->p1) {
+		for(z=0; z<BITS; z++) {
+			ref.b[z] |= r1->refahead.b[z];
+			if(ref.b[z] != r1->refahead.b[z]) {
+				r1->refahead.b[z] = ref.b[z];
+				change++;
+			}
+			cal.b[z] |= r1->calahead.b[z];
+			if(cal.b[z] != r1->calahead.b[z]) {
+				r1->calahead.b[z] = cal.b[z];
+				change++;
+			}
+		}
+		switch(r1->prog->as) {
+		case ACALL:
+			for(z=0; z<BITS; z++) {
+				cal.b[z] |= ref.b[z] | externs.b[z];
+				ref.b[z] = 0;
+			}
+			break;
+
+		case ATEXT:
+			for(z=0; z<BITS; z++) {
+				cal.b[z] = 0;
+				ref.b[z] = 0;
+			}
+			break;
+
+		case ARET:
+			for(z=0; z<BITS; z++) {
+				cal.b[z] = externs.b[z];
+				ref.b[z] = 0;
+			}
+		}
+		for(z=0; z<BITS; z++) {
+			ref.b[z] = (ref.b[z] & ~r1->set.b[z]) |
+				r1->use1.b[z] | r1->use2.b[z];
+			cal.b[z] &= ~(r1->set.b[z] | r1->use1.b[z] | r1->use2.b[z]);
+			r1->refbehind.b[z] = ref.b[z];
+			r1->calbehind.b[z] = cal.b[z];
+		}
+		if(r1->active)
+			break;
+		r1->active = 1;
+	}
+	for(; r != r1; r = r->p1)
+		for(r2 = r->p2; r2 != R; r2 = r2->p2link)
+			prop(r2, r->refbehind, r->calbehind);
+}
+
+/*
+ * find looping structure
+ *
+ * 1) find reverse postordering
+ * 2) find approximate dominators,
+ *	the actual dominators if the flow graph is reducible
+ *	otherwise, dominators plus some other non-dominators.
+ *	See Matthew S. Hecht and Jeffrey D. Ullman,
+ *	"Analysis of a Simple Algorithm for Global Data Flow Problems",
+ *	Conf.  Record of ACM Symp. on Principles of Prog. Langs, Boston, Massachusetts,
+ *	Oct. 1-3, 1973, pp.  207-217.
+ * 3) find all nodes with a predecessor dominated by the current node.
+ *	such a node is a loop head.
+ *	recursively, all preds with a greater rpo number are in the loop
+ */
+int32
+postorder(Reg *r, Reg **rpo2r, int32 n)
+{
+	Reg *r1;
+
+	r->rpo = 1;
+	r1 = r->s1;
+	if(r1 && !r1->rpo)
+		n = postorder(r1, rpo2r, n);
+	r1 = r->s2;
+	if(r1 && !r1->rpo)
+		n = postorder(r1, rpo2r, n);
+	rpo2r[n] = r;
+	n++;
+	return n;
+}
+
+int32
+rpolca(int32 *idom, int32 rpo1, int32 rpo2)
+{
+	int32 t;
+
+	if(rpo1 == -1)
+		return rpo2;
+	while(rpo1 != rpo2){
+		if(rpo1 > rpo2){
+			t = rpo2;
+			rpo2 = rpo1;
+			rpo1 = t;
+		}
+		while(rpo1 < rpo2){
+			t = idom[rpo2];
+			if(t >= rpo2)
+				fatal(Z, "bad idom");
+			rpo2 = t;
+		}
+	}
+	return rpo1;
+}
+
+int
+doms(int32 *idom, int32 r, int32 s)
+{
+	while(s > r)
+		s = idom[s];
+	return s == r;
+}
+
+int
+loophead(int32 *idom, Reg *r)
+{
+	int32 src;
+
+	src = r->rpo;
+	if(r->p1 != R && doms(idom, src, r->p1->rpo))
+		return 1;
+	for(r = r->p2; r != R; r = r->p2link)
+		if(doms(idom, src, r->rpo))
+			return 1;
+	return 0;
+}
+
+void
+loopmark(Reg **rpo2r, int32 head, Reg *r)
+{
+	if(r->rpo < head || r->active == head)
+		return;
+	r->active = head;
+	r->loop += LOOP;
+	if(r->p1 != R)
+		loopmark(rpo2r, head, r->p1);
+	for(r = r->p2; r != R; r = r->p2link)
+		loopmark(rpo2r, head, r);
+}
+
+void
+loopit(Reg *r, int32 nr)
+{
+	Reg *r1;
+	int32 i, d, me;
+
+	if(nr > maxnr) {
+		rpo2r = alloc(nr * sizeof(Reg*));
+		idom = alloc(nr * sizeof(int32));
+		maxnr = nr;
+	}
+
+	d = postorder(r, rpo2r, 0);
+	if(d > nr)
+		fatal(Z, "too many reg nodes");
+	nr = d;
+	for(i = 0; i < nr / 2; i++){
+		r1 = rpo2r[i];
+		rpo2r[i] = rpo2r[nr - 1 - i];
+		rpo2r[nr - 1 - i] = r1;
+	}
+	for(i = 0; i < nr; i++)
+		rpo2r[i]->rpo = i;
+
+	idom[0] = 0;
+	for(i = 0; i < nr; i++){
+		r1 = rpo2r[i];
+		me = r1->rpo;
+		d = -1;
+		if(r1->p1 != R && r1->p1->rpo < me)
+			d = r1->p1->rpo;
+		for(r1 = r1->p2; r1 != nil; r1 = r1->p2link)
+			if(r1->rpo < me)
+				d = rpolca(idom, d, r1->rpo);
+		idom[i] = d;
+	}
+
+	for(i = 0; i < nr; i++){
+		r1 = rpo2r[i];
+		r1->loop++;
+		if(r1->p2 != R && loophead(idom, r1))
+			loopmark(rpo2r, i, r1);
+	}
+}
+
+void
+synch(Reg *r, Bits dif)
+{
+	Reg *r1;
+	int z;
+
+	for(r1 = r; r1 != R; r1 = r1->s1) {
+		for(z=0; z<BITS; z++) {
+			dif.b[z] = (dif.b[z] &
+				~(~r1->refbehind.b[z] & r1->refahead.b[z])) |
+					r1->set.b[z] | r1->regdiff.b[z];
+			if(dif.b[z] != r1->regdiff.b[z]) {
+				r1->regdiff.b[z] = dif.b[z];
+				change++;
+			}
+		}
+		if(r1->active)
+			break;
+		r1->active = 1;
+		for(z=0; z<BITS; z++)
+			dif.b[z] &= ~(~r1->calbehind.b[z] & r1->calahead.b[z]);
+		if(r1->s2 != R)
+			synch(r1->s2, dif);
+	}
+}
+
+uint32
+allreg(uint32 b, Rgn *r)
+{
+	Var *v;
+	int i;
+
+	v = var + r->varno;
+	r->regno = 0;
+	switch(v->etype) {
+
+	default:
+		diag(Z, "unknown etype %d/%d", bitno(b), v->etype);
+		break;
+
+	case TCHAR:
+	case TUCHAR:
+	case TSHORT:
+	case TUSHORT:
+	case TINT:
+	case TUINT:
+	case TLONG:
+	case TULONG:
+	case TVLONG:
+	case TUVLONG:
+	case TIND:
+	case TARRAY:
+		i = BtoR(~b);
+		if(i && r->cost > 0) {
+			r->regno = i;
+			return RtoB(i);
+		}
+		break;
+
+	case TDOUBLE:
+	case TFLOAT:
+		i = BtoF(~b);
+		if(i && r->cost > 0) {
+			r->regno = i;
+			return FtoB(i);
+		}
+		break;
+	}
+	return 0;
+}
+
+void
+paint1(Reg *r, int bn)
+{
+	Reg *r1;
+	Prog *p;
+	int z;
+	uint32 bb;
+
+	z = bn/32;
+	bb = 1L<<(bn%32);
+	if(r->act.b[z] & bb)
+		return;
+	for(;;) {
+		if(!(r->refbehind.b[z] & bb))
+			break;
+		r1 = r->p1;
+		if(r1 == R)
+			break;
+		if(!(r1->refahead.b[z] & bb))
+			break;
+		if(r1->act.b[z] & bb)
+			break;
+		r = r1;
+	}
+
+	if(LOAD(r) & ~(r->set.b[z]&~(r->use1.b[z]|r->use2.b[z])) & bb) {
+		change -= CLOAD * r->loop;
+		if(debug['R'] && debug['v'])
+			print("%d%P\td %B $%d\n", r->loop,
+				r->prog, blsh(bn), change);
+	}
+	for(;;) {
+		r->act.b[z] |= bb;
+		p = r->prog;
+
+		if(r->use1.b[z] & bb) {
+			change += CREF * r->loop;
+			if(debug['R'] && debug['v'])
+				print("%d%P\tu1 %B $%d\n", r->loop,
+					p, blsh(bn), change);
+		}
+
+		if((r->use2.b[z]|r->set.b[z]) & bb) {
+			change += CREF * r->loop;
+			if(debug['R'] && debug['v'])
+				print("%d%P\tu2 %B $%d\n", r->loop,
+					p, blsh(bn), change);
+		}
+
+		if(STORE(r) & r->regdiff.b[z] & bb) {
+			change -= CLOAD * r->loop;
+			if(debug['R'] && debug['v'])
+				print("%d%P\tst %B $%d\n", r->loop,
+					p, blsh(bn), change);
+		}
+
+		if(r->refbehind.b[z] & bb)
+			for(r1 = r->p2; r1 != R; r1 = r1->p2link)
+				if(r1->refahead.b[z] & bb)
+					paint1(r1, bn);
+
+		if(!(r->refahead.b[z] & bb))
+			break;
+		r1 = r->s2;
+		if(r1 != R)
+			if(r1->refbehind.b[z] & bb)
+				paint1(r1, bn);
+		r = r->s1;
+		if(r == R)
+			break;
+		if(r->act.b[z] & bb)
+			break;
+		if(!(r->refbehind.b[z] & bb))
+			break;
+	}
+}
+
+uint32
+regset(Reg *r, uint32 bb)
+{
+	uint32 b, set;
+	Addr v;
+	int c;
+
+	set = 0;
+	v = zprog.from;
+	while(b = bb & ~(bb-1)) {
+		v.type = b & 0xFFFF? BtoR(b): BtoF(b);
+		if(v.type == 0)
+			diag(Z, "zero v.type for %#ux", b);
+		c = copyu(r->prog, &v, A);
+		if(c == 3)
+			set |= b;
+		bb &= ~b;
+	}
+	return set;
+}
+
+uint32
+reguse(Reg *r, uint32 bb)
+{
+	uint32 b, set;
+	Addr v;
+	int c;
+
+	set = 0;
+	v = zprog.from;
+	while(b = bb & ~(bb-1)) {
+		v.type = b & 0xFFFF? BtoR(b): BtoF(b);
+		c = copyu(r->prog, &v, A);
+		if(c == 1 || c == 2 || c == 4)
+			set |= b;
+		bb &= ~b;
+	}
+	return set;
+}
+
+uint32
+paint2(Reg *r, int bn)
+{
+	Reg *r1;
+	int z;
+	uint32 bb, vreg, x;
+
+	z = bn/32;
+	bb = 1L << (bn%32);
+	vreg = regbits;
+	if(!(r->act.b[z] & bb))
+		return vreg;
+	for(;;) {
+		if(!(r->refbehind.b[z] & bb))
+			break;
+		r1 = r->p1;
+		if(r1 == R)
+			break;
+		if(!(r1->refahead.b[z] & bb))
+			break;
+		if(!(r1->act.b[z] & bb))
+			break;
+		r = r1;
+	}
+	for(;;) {
+		r->act.b[z] &= ~bb;
+
+		vreg |= r->regu;
+
+		if(r->refbehind.b[z] & bb)
+			for(r1 = r->p2; r1 != R; r1 = r1->p2link)
+				if(r1->refahead.b[z] & bb)
+					vreg |= paint2(r1, bn);
+
+		if(!(r->refahead.b[z] & bb))
+			break;
+		r1 = r->s2;
+		if(r1 != R)
+			if(r1->refbehind.b[z] & bb)
+				vreg |= paint2(r1, bn);
+		r = r->s1;
+		if(r == R)
+			break;
+		if(!(r->act.b[z] & bb))
+			break;
+		if(!(r->refbehind.b[z] & bb))
+			break;
+	}
+
+	bb = vreg;
+	for(; r; r=r->s1) {
+		x = r->regu & ~bb;
+		if(x) {
+			vreg |= reguse(r, x);
+			bb |= regset(r, x);
+		}
+	}
+	return vreg;
+}
+
+void
+paint3(Reg *r, int bn, int32 rb, int rn)
+{
+	Reg *r1;
+	Prog *p;
+	int z;
+	uint32 bb;
+
+	z = bn/32;
+	bb = 1L << (bn%32);
+	if(r->act.b[z] & bb)
+		return;
+	for(;;) {
+		if(!(r->refbehind.b[z] & bb))
+			break;
+		r1 = r->p1;
+		if(r1 == R)
+			break;
+		if(!(r1->refahead.b[z] & bb))
+			break;
+		if(r1->act.b[z] & bb)
+			break;
+		r = r1;
+	}
+
+	if(LOAD(r) & ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z])) & bb)
+		addmove(r, bn, rn, 0);
+	for(;;) {
+		r->act.b[z] |= bb;
+		p = r->prog;
+
+		if(r->use1.b[z] & bb) {
+			if(debug['R'])
+				print("%P", p);
+			addreg(&p->from, rn);
+			if(debug['R'])
+				print("\t.c%P\n", p);
+		}
+		if((r->use2.b[z]|r->set.b[z]) & bb) {
+			if(debug['R'])
+				print("%P", p);
+			addreg(&p->to, rn);
+			if(debug['R'])
+				print("\t.c%P\n", p);
+		}
+
+		if(STORE(r) & r->regdiff.b[z] & bb)
+			addmove(r, bn, rn, 1);
+		r->regu |= rb;
+
+		if(r->refbehind.b[z] & bb)
+			for(r1 = r->p2; r1 != R; r1 = r1->p2link)
+				if(r1->refahead.b[z] & bb)
+					paint3(r1, bn, rb, rn);
+
+		if(!(r->refahead.b[z] & bb))
+			break;
+		r1 = r->s2;
+		if(r1 != R)
+			if(r1->refbehind.b[z] & bb)
+				paint3(r1, bn, rb, rn);
+		r = r->s1;
+		if(r == R)
+			break;
+		if(r->act.b[z] & bb)
+			break;
+		if(!(r->refbehind.b[z] & bb))
+			break;
+	}
+}
+
+void
+addreg(Addr *a, int rn)
+{
+
+	a->sym = 0;
+	a->offset = 0;
+	a->type = rn;
+}
+
+int32
+RtoB(int r)
+{
+
+	if(r < D_AX || r > D_R15)
+		return 0;
+	return 1L << (r-D_AX);
+}
+
+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;
+}
+
+/*
+ *	bit	reg
+ *	16	X5
+ *	17	X6
+ *	18	X7
+ */
+int32
+FtoB(int f)
+{
+	if(f < FREGMIN || f > FREGEXT)
+		return 0;
+	return 1L << (f - FREGMIN + 16);
+}
+
+int
+BtoF(int32 b)
+{
+
+	b &= 0x70000L;
+	if(b == 0)
+		return 0;
+	return bitno(b) - 16 + FREGMIN;
+}
+
+/* what instruction does a JMP to p eventually land on? */
+static Reg*
+chasejmp(Reg *r, int *jmploop)
+{
+	int n;
+
+	n = 0;
+	for(; r; r=r->s2) {
+		if(r->prog->as != AJMP || r->prog->to.type != D_BRANCH)
+			break;
+		if(++n > 10) {
+			*jmploop = 1;
+			break;
+		}
+	}
+	return r;
+}
+
+/* mark all code reachable from firstp as alive */
+static void
+mark(Reg *firstr)
+{
+	Reg *r;
+	Prog *p;
+
+	for(r=firstr; r; r=r->link) {
+		if(r->active)
+			break;
+		r->active = 1;
+		p = r->prog;
+		if(p->as != ACALL && p->to.type == D_BRANCH)
+			mark(r->s2);
+		if(p->as == AJMP || p->as == ARET || p->as == AUNDEF)
+			break;
+	}
+}
+
+/*
+ * the code generator depends on being able to write out JMP
+ * instructions that it can jump to now but fill in later.
+ * the linker will resolve them nicely, but they make the code
+ * longer and more difficult to follow during debugging.
+ * remove them.
+ */
+static void
+fixjmp(Reg *firstr)
+{
+	int jmploop;
+	Reg *r;
+	Prog *p;
+
+	if(debug['R'] && debug['v'])
+		print("\nfixjmp\n");
+
+	// pass 1: resolve jump to AJMP, mark all code as dead.
+	jmploop = 0;
+	for(r=firstr; r; r=r->link) {
+		p = r->prog;
+		if(debug['R'] && debug['v'])
+			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);
+		}
+		r->active = 0;
+	}
+	if(debug['R'] && debug['v'])
+		print("\n");
+
+	// pass 2: mark all reachable code alive
+	mark(firstr);
+
+	// pass 3: delete dead code (mostly JMPs).
+	for(r=firstr; r; r=r->link) {
+		if(!r->active) {
+			p = r->prog;
+			if(p->link == P && p->as == ARET && r->p1 && r->p1->prog->as != ARET) {
+				// This is the final ARET, and the code so far doesn't have one.
+				// Let it stay.
+			} else {
+				if(debug['R'] && debug['v'])
+					print("del %04d %P\n", (int)r->pc, p);
+				p->as = ANOP;
+			}
+		}
+	}
+
+	// pass 4: elide JMP to next instruction.
+	// only safe if there are no jumps to JMPs anymore.
+	if(!jmploop) {
+		for(r=firstr; r; r=r->link) {
+			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", (int)r->pc, p);
+				p->as = ANOP;
+			}
+		}
+	}
+
+	// fix back pointers.
+	for(r=firstr; r; r=r->link) {
+		r->p2 = R;
+		r->p2link = R;
+	}
+	for(r=firstr; r; r=r->link) {
+		if(r->s2) {
+			r->p2link = r->s2->p2;
+			r->s2->p2 = r;
+		}
+	}
+
+	if(debug['R'] && debug['v']) {
+		print("\n");
+		for(r=firstr; r; r=r->link)
+			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
new file mode 100644
index 0000000..fceb332
--- /dev/null
+++ b/src/cmd/6c/sgen.c
@@ -0,0 +1,483 @@
+// Inferno utils/6c/sgen.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/sgen.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 "gc.h"
+#include "../../runtime/funcdata.h"
+
+Prog*
+gtext(Sym *s, int32 stkoff)
+{
+	vlong v;
+
+	v = ((uvlong)argsize(1) << 32) | (stkoff & 0xffffffff);
+	if((textflag & NOSPLIT) && stkoff >= 128)
+		yyerror("stack frame too large for NOSPLIT function");
+
+	gpseudo(ATEXT, s, nodgconst(v, types[TVLONG]));
+	return p;
+}
+
+void
+noretval(int n)
+{
+
+	if(n & 1) {
+		gins(ANOP, Z, Z);
+		p->to.type = REGRET;
+	}
+	if(n & 2) {
+		gins(ANOP, Z, Z);
+		p->to.type = FREGRET;
+	}
+}
+
+/* welcome to commute */
+static void
+commute(Node *n)
+{
+	Node *l, *r;
+
+	l = n->left;
+	r = n->right;
+	if(r->complex > l->complex) {
+		n->left = r;
+		n->right = l;
+	}
+}
+
+void
+indexshift(Node *n)
+{
+	int g;
+
+	if(!typechlpv[n->type->etype])
+		return;
+	simplifyshift(n);
+	if(n->op == OASHL && n->right->op == OCONST){
+		g = vconst(n->right);
+		if(g >= 0 && g <= 3)
+			n->addable = 7;
+	}
+}
+
+/*
+ *	calculate addressability as follows
+ *		NAME ==> 10/11		name+value(SB/SP)
+ *		REGISTER ==> 12		register
+ *		CONST ==> 20		$value
+ *		*(20) ==> 21		value
+ *		&(10) ==> 13		$name+value(SB)
+ *		&(11) ==> 1		$name+value(SP)
+ *		(13) + (20) ==> 13	fold constants
+ *		(1) + (20) ==> 1	fold constants
+ *		*(13) ==> 10		back to name
+ *		*(1) ==> 11		back to name
+ *
+ *		(20) * (X) ==> 7	multiplier in indexing
+ *		(X,7) + (13,1) ==> 8	adder in indexing (addresses)
+ *		(8) ==> &9(OINDEX)	index, almost addressable
+ *
+ *	calculate complexity (number of registers)
+ */
+void
+xcom(Node *n)
+{
+	Node *l, *r;
+	int g;
+
+	if(n == Z)
+		return;
+	l = n->left;
+	r = n->right;
+	n->complex = 0;
+	n->addable = 0;
+	switch(n->op) {
+	case OCONST:
+		n->addable = 20;
+		break;
+
+	case ONAME:
+		n->addable = 9;
+		if(n->class == CPARAM || n->class == CAUTO)
+			n->addable = 11;
+		break;
+
+	case OEXREG:
+		n->addable = 0;
+		break;
+
+	case OREGISTER:
+		n->addable = 12;
+		break;
+
+	case OINDREG:
+		n->addable = 12;
+		break;
+
+	case OADDR:
+		xcom(l);
+		if(l->addable == 10)
+			n->addable = 13;
+		else
+		if(l->addable == 11)
+			n->addable = 1;
+		break;
+
+	case OADD:
+		xcom(l);
+		xcom(r);
+		if(n->type->etype != TIND)
+			break;
+
+		switch(r->addable) {
+		case 20:
+			switch(l->addable) {
+			case 1:
+			case 13:
+			commadd:
+				l->type = n->type;
+				*n = *l;
+				l = new(0, Z, Z);
+				*l = *(n->left);
+				l->xoffset += r->vconst;
+				n->left = l;
+				r = n->right;
+				goto brk;
+			}
+			break;
+
+		case 1:
+		case 13:
+		case 10:
+		case 11:
+			/* l is the base, r is the index */
+			if(l->addable != 20)
+				n->addable = 8;
+			break;
+		}
+		switch(l->addable) {
+		case 20:
+			switch(r->addable) {
+			case 13:
+			case 1:
+				r = n->left;
+				l = n->right;
+				n->left = l;
+				n->right = r;
+				goto commadd;
+			}
+			break;
+
+		case 13:
+		case 1:
+		case 10:
+		case 11:
+			/* r is the base, l is the index */
+			if(r->addable != 20)
+				n->addable = 8;
+			break;
+		}
+		if(n->addable == 8 && !side(n) && !nacl) {
+			indx(n);
+			l = new1(OINDEX, idx.basetree, idx.regtree);
+			l->scale = idx.scale;
+			l->addable = 9;
+			l->complex = l->right->complex;
+			l->type = l->left->type;
+			n->op = OADDR;
+			n->left = l;
+			n->right = Z;
+			n->addable = 8;
+			break;
+		}
+		break;
+
+	case OINDEX:
+		xcom(l);
+		xcom(r);
+		n->addable = 9;
+		break;
+
+	case OIND:
+		xcom(l);
+		if(l->op == OADDR) {
+			l = l->left;
+			l->type = n->type;
+			*n = *l;
+			return;
+		}
+		switch(l->addable) {
+		case 20:
+			n->addable = 21;
+			break;
+		case 1:
+			n->addable = 11;
+			break;
+		case 13:
+			n->addable = 10;
+			break;
+		}
+		break;
+
+	case OASHL:
+		xcom(l);
+		xcom(r);
+		indexshift(n);
+		break;
+
+	case OMUL:
+	case OLMUL:
+		xcom(l);
+		xcom(r);
+		g = vlog(l);
+		if(g >= 0) {
+			n->left = r;
+			n->right = l;
+			l = r;
+			r = n->right;
+		}
+		g = vlog(r);
+		if(g >= 0) {
+			n->op = OASHL;
+			r->vconst = g;
+			r->type = types[TINT];
+			indexshift(n);
+			break;
+		}
+		commute(n);
+		break;
+
+	case OASLDIV:
+		xcom(l);
+		xcom(r);
+		g = vlog(r);
+		if(g >= 0) {
+			n->op = OASLSHR;
+			r->vconst = g;
+			r->type = types[TINT];
+		}
+		break;
+
+	case OLDIV:
+		xcom(l);
+		xcom(r);
+		g = vlog(r);
+		if(g >= 0) {
+			n->op = OLSHR;
+			r->vconst = g;
+			r->type = types[TINT];
+			indexshift(n);
+			break;
+		}
+		break;
+
+	case OASLMOD:
+		xcom(l);
+		xcom(r);
+		g = vlog(r);
+		if(g >= 0) {
+			n->op = OASAND;
+			r->vconst--;
+		}
+		break;
+
+	case OLMOD:
+		xcom(l);
+		xcom(r);
+		g = vlog(r);
+		if(g >= 0) {
+			n->op = OAND;
+			r->vconst--;
+		}
+		break;
+
+	case OASMUL:
+	case OASLMUL:
+		xcom(l);
+		xcom(r);
+		g = vlog(r);
+		if(g >= 0) {
+			n->op = OASASHL;
+			r->vconst = g;
+		}
+		break;
+
+	case OLSHR:
+	case OASHR:
+		xcom(l);
+		xcom(r);
+		indexshift(n);
+		break;
+
+	default:
+		if(l != Z)
+			xcom(l);
+		if(r != Z)
+			xcom(r);
+		break;
+	}
+brk:
+	if(n->addable >= 10)
+		return;
+	if(l != Z)
+		n->complex = l->complex;
+	if(r != Z) {
+		if(r->complex == n->complex)
+			n->complex = r->complex+1;
+		else
+		if(r->complex > n->complex)
+			n->complex = r->complex;
+	}
+	if(n->complex == 0)
+		n->complex++;
+
+	switch(n->op) {
+
+	case OFUNC:
+		n->complex = FNX;
+		break;
+
+	case OCAST:
+		if(l->type->etype == TUVLONG && typefd[n->type->etype])
+			n->complex += 2;
+		break;
+
+	case OLMOD:
+	case OMOD:
+	case OLMUL:
+	case OLDIV:
+	case OMUL:
+	case ODIV:
+	case OASLMUL:
+	case OASLDIV:
+	case OASLMOD:
+	case OASMUL:
+	case OASDIV:
+	case OASMOD:
+		if(r->complex >= l->complex) {
+			n->complex = l->complex + 3;
+			if(r->complex > n->complex)
+				n->complex = r->complex;
+		} else {
+			n->complex = r->complex + 3;
+			if(l->complex > n->complex)
+				n->complex = l->complex;
+		}
+		break;
+
+	case OLSHR:
+	case OASHL:
+	case OASHR:
+	case OASLSHR:
+	case OASASHL:
+	case OASASHR:
+		if(r->complex >= l->complex) {
+			n->complex = l->complex + 2;
+			if(r->complex > n->complex)
+				n->complex = r->complex;
+		} else {
+			n->complex = r->complex + 2;
+			if(l->complex > n->complex)
+				n->complex = l->complex;
+		}
+		break;
+
+	case OADD:
+	case OXOR:
+	case OAND:
+	case OOR:
+		/*
+		 * immediate operators, make const on right
+		 */
+		if(l->op == OCONST) {
+			n->left = r;
+			n->right = l;
+		}
+		break;
+
+	case OEQ:
+	case ONE:
+	case OLE:
+	case OLT:
+	case OGE:
+	case OGT:
+	case OHI:
+	case OHS:
+	case OLO:
+	case OLS:
+		/*
+		 * compare operators, make const on left
+		 */
+		if(r->op == OCONST) {
+			n->left = r;
+			n->right = l;
+			n->op = invrel[relindex(n->op)];
+		}
+		break;
+	}
+}
+
+void
+indx(Node *n)
+{
+	Node *l, *r;
+
+	if(debug['x'])
+		prtree(n, "indx");
+
+	l = n->left;
+	r = n->right;
+	if(l->addable == 1 || l->addable == 13 || r->complex > l->complex) {
+		n->right = l;
+		n->left = r;
+		l = r;
+		r = n->right;
+	}
+	if(l->addable != 7) {
+		idx.regtree = l;
+		idx.scale = 1;
+	} else
+	if(l->right->addable == 20) {
+		idx.regtree = l->left;
+		idx.scale = 1 << l->right->vconst;
+	} else
+	if(l->left->addable == 20) {
+		idx.regtree = l->right;
+		idx.scale = 1 << l->left->vconst;
+	} else
+		diag(n, "bad index");
+
+	idx.basetree = r;
+	if(debug['x']) {
+		print("scale = %d\n", idx.scale);
+		prtree(idx.regtree, "index");
+		prtree(idx.basetree, "base");
+	}
+}
diff --git a/src/cmd/6c/swt.c b/src/cmd/6c/swt.c
new file mode 100644
index 0000000..6e918eb
--- /dev/null
+++ b/src/cmd/6c/swt.c
@@ -0,0 +1,353 @@
+// Inferno utils/6c/swt.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/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 "gc.h"
+
+void
+swit1(C1 *q, int nc, int32 def, Node *n)
+{
+	Node nreg;
+
+	regalloc(&nreg, n, Z);
+	if(typev[n->type->etype])
+		nreg.type = types[TVLONG];
+	else
+		nreg.type = types[TLONG];
+	cgen(n, &nreg);
+	swit2(q, nc, def, &nreg);
+	regfree(&nreg);
+}
+
+void
+swit2(C1 *q, int nc, int32 def, Node *n)
+{
+	C1 *r;
+	int i;
+	Prog *sp;
+
+	if(nc < 5) {
+		for(i=0; i<nc; i++) {
+			if(debug['W'])
+				print("case = %.8llux\n", q->val);
+			gcmp(OEQ, n, q->val);
+			patch(p, q->label);
+			q++;
+		}
+		gbranch(OGOTO);
+		patch(p, def);
+		return;
+	}
+	i = nc / 2;
+	r = q+i;
+	if(debug['W'])
+		print("case > %.8llux\n", r->val);
+	gcmp(OGT, n, r->val);
+	sp = p;
+	gbranch(OGOTO);
+	p->as = AJEQ;
+	patch(p, r->label);
+	swit2(q, i, def, n);
+
+	if(debug['W'])
+		print("case < %.8llux\n", r->val);
+	patch(sp, pc);
+	swit2(r+1, nc-i-1, def, n);
+}
+
+void
+bitload(Node *b, Node *n1, Node *n2, Node *n3, Node *nn)
+{
+	int sh;
+	int32 v;
+	Node *l;
+
+	/*
+	 * n1 gets adjusted/masked value
+	 * n2 gets address of cell
+	 * n3 gets contents of cell
+	 */
+	l = b->left;
+	if(n2 != Z) {
+		regalloc(n1, l, nn);
+		reglcgen(n2, l, Z);
+		regalloc(n3, l, Z);
+		gmove(n2, n3);
+		gmove(n3, n1);
+	} else {
+		regalloc(n1, l, nn);
+		cgen(l, n1);
+	}
+	if(b->type->shift == 0 && typeu[b->type->etype]) {
+		v = ~0 + (1L << b->type->nbits);
+		gopcode(OAND, tfield, nodconst(v), n1);
+	} else {
+		sh = 32 - b->type->shift - b->type->nbits;
+		if(sh > 0)
+			gopcode(OASHL, tfield, nodconst(sh), n1);
+		sh += b->type->shift;
+		if(sh > 0)
+			if(typeu[b->type->etype])
+				gopcode(OLSHR, tfield, nodconst(sh), n1);
+			else
+				gopcode(OASHR, tfield, nodconst(sh), n1);
+	}
+}
+
+void
+bitstore(Node *b, Node *n1, Node *n2, Node *n3, Node *nn)
+{
+	int32 v;
+	Node nod;
+	int sh;
+
+	regalloc(&nod, b->left, Z);
+	v = ~0 + (1L << b->type->nbits);
+	gopcode(OAND, types[TLONG], nodconst(v), n1);
+	gmove(n1, &nod);
+	if(nn != Z)
+		gmove(n1, nn);
+	sh = b->type->shift;
+	if(sh > 0)
+		gopcode(OASHL, types[TLONG], nodconst(sh), &nod);
+	v <<= sh;
+	gopcode(OAND, types[TLONG], nodconst(~v), n3);
+	gopcode(OOR, types[TLONG], n3, &nod);
+	gmove(&nod, n2);
+
+	regfree(&nod);
+	regfree(n1);
+	regfree(n2);
+	regfree(n3);
+}
+
+int32
+outstring(char *s, int32 n)
+{
+	int32 r;
+
+	if(suppress)
+		return nstring;
+	r = nstring;
+	while(n) {
+		string[mnstring] = *s++;
+		mnstring++;
+		nstring++;
+		if(mnstring >= NSNAME) {
+			gpseudo(ADATA, symstring, nodconst(0L));
+			p->from.offset += nstring - NSNAME;
+			p->from.scale = NSNAME;
+			p->to.type = D_SCONST;
+			memmove(p->to.u.sval, string, NSNAME);
+			mnstring = 0;
+		}
+		n--;
+	}
+	return r;
+}
+
+void
+sextern(Sym *s, Node *a, int32 o, int32 w)
+{
+	int32 e, lw;
+
+	for(e=0; e<w; e+=NSNAME) {
+		lw = NSNAME;
+		if(w-e < lw)
+			lw = w-e;
+		gpseudo(ADATA, s, nodconst(0L));
+		p->from.offset += o+e;
+		p->from.scale = lw;
+		p->to.type = D_SCONST;
+		memmove(p->to.u.sval, a->cstring+e, lw);
+	}
+}
+
+void
+gextern(Sym *s, Node *a, int32 o, int32 w)
+{
+	if(0 && a->op == OCONST && typev[a->type->etype]) {
+		gpseudo(ADATA, s, lo64(a));
+		p->from.offset += o;
+		p->from.scale = 4;
+		gpseudo(ADATA, s, hi64(a));
+		p->from.offset += o + 4;
+		p->from.scale = 4;
+		return;
+	}
+	gpseudo(ADATA, s, a);
+	p->from.offset += o;
+	p->from.scale = w;
+	switch(p->to.type) {
+	default:
+		p->to.index = p->to.type;
+		p->to.type = D_ADDR;
+	case D_CONST:
+	case D_FCONST:
+	case D_ADDR:
+		break;
+	}
+}
+
+void
+outcode(void)
+{
+	int f;
+	Biobuf b;
+
+	f = open(outfile, OWRITE);
+	if(f < 0) {
+		diag(Z, "cannot open %s", outfile);
+		return;
+	}
+	Binit(&b, f, OWRITE);
+
+	Bprint(&b, "go object %s %s %s\n", getgoos(), getgoarch(), getgoversion());
+	if(pragcgobuf.to > pragcgobuf.start) {
+		Bprint(&b, "\n");
+		Bprint(&b, "$$  // exports\n\n");
+		Bprint(&b, "$$  // local types\n\n");
+		Bprint(&b, "$$  // cgo\n");
+		Bprint(&b, "%s", fmtstrflush(&pragcgobuf));
+		Bprint(&b, "\n$$\n\n");
+	}
+	Bprint(&b, "!\n");
+
+	writeobj(ctxt, &b);
+	Bterm(&b);
+	close(f);
+	lastp = P;
+}
+
+int32
+align(int32 i, Type *t, int op, int32 *maxalign)
+{
+	int32 o;
+	Type *v;
+	int w, packw;
+
+	o = i;
+	w = 1;
+	packw = 0;
+	switch(op) {
+	default:
+		diag(Z, "unknown align opcode %d", op);
+		break;
+
+	case Asu2:	/* padding at end of a struct */
+		w = *maxalign;
+		if(w < 1)
+			w = 1;
+		if(packflg)
+			packw = packflg;
+		break;
+
+	case Ael1:	/* initial align of struct element */
+		for(v=t; v->etype==TARRAY; v=v->link)
+			;
+		if(v->etype == TSTRUCT || v->etype == TUNION)
+			w = v->align;
+		else
+			w = ewidth[v->etype];
+		if(w < 1 || w > SZ_VLONG)
+			fatal(Z, "align");
+		if(packflg) 
+			packw = packflg;
+		break;
+
+	case Ael2:	/* width of a struct element */
+		o += t->width;
+		break;
+
+	case Aarg0:	/* initial passbyptr argument in arg list */
+		if(typesu[t->etype]) {
+			o = align(o, types[TIND], Aarg1, nil);
+			o = align(o, types[TIND], Aarg2, nil);
+		}
+		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;
+			break;
+		}
+		w = 1;		/* little endian no adjustment */
+		break;
+
+	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;
+		break;
+
+	case Aaut3:	/* total align of automatic */
+		o = align(o, t, Ael1, nil);
+		o = align(o, t, Ael2, nil);
+		break;
+	}
+	if(packw != 0 && xround(o, w) != xround(o, packw))
+		diag(Z, "#pragma pack changes offset of %T", t);
+	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;
+}
+
+int32
+maxround(int32 max, int32 v)
+{
+	v = xround(v, SZ_VLONG);
+	if(v > max)
+		return v;
+	return max;
+}
diff --git a/src/cmd/6c/txt.c b/src/cmd/6c/txt.c
new file mode 100644
index 0000000..3bdbf41
--- /dev/null
+++ b/src/cmd/6c/txt.c
@@ -0,0 +1,1674 @@
+// Inferno utils/6c/txt.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/txt.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 "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;
+
+	dodefine("_64BITREG");
+	if(ewidth[TIND] == 8)
+		dodefine("_64BIT");
+	listinit();
+	nstring = 0;
+	mnstring = 0;
+	nrathole = 0;
+	pc = 0;
+	breakpc = -1;
+	continpc = -1;
+	cases = C;
+	lastp = P;
+	tfield = types[TINT];
+
+	typeword = typechlvp;
+	typecmplx = typesu;
+
+	/* TO DO */
+	memmove(typechlpv, typechlp, sizeof(typechlpv));
+	typechlpv[TVLONG] = 1;
+	typechlpv[TUVLONG] = 1;
+
+	zprog.link = P;
+	zprog.as = AGOK;
+	zprog.from.type = D_NONE;
+	zprog.from.index = D_NONE;
+	zprog.from.scale = 0;
+	zprog.to = zprog.from;
+
+	lregnode.op = OREGISTER;
+	lregnode.class = CEXREG;
+	lregnode.reg = REGTMP;
+	lregnode.complex = 0;
+	lregnode.addable = 11;
+	lregnode.type = types[TLONG];
+
+	qregnode = lregnode;
+	qregnode.type = types[TVLONG];
+
+	constnode.op = OCONST;
+	constnode.class = CXXX;
+	constnode.complex = 0;
+	constnode.addable = 20;
+	constnode.type = types[TLONG];
+
+	vconstnode = constnode;
+	vconstnode.type = types[TVLONG];
+
+	fconstnode.op = OCONST;
+	fconstnode.class = CXXX;
+	fconstnode.complex = 0;
+	fconstnode.addable = 20;
+	fconstnode.type = types[TDOUBLE];
+
+	nodsafe = new(ONAME, Z, Z);
+	nodsafe->sym = slookup(".safe");
+	nodsafe->type = types[TINT];
+	nodsafe->etype = types[TINT]->etype;
+	nodsafe->class = CAUTO;
+	complex(nodsafe);
+
+	t = typ(TARRAY, types[TCHAR]);
+	symrathole = slookup(".rathole");
+	symrathole->class = CGLOBL;
+	symrathole->type = t;
+
+	nodrat = new(ONAME, Z, Z);
+	nodrat->sym = symrathole;
+	nodrat->type = types[TIND];
+	nodrat->etype = TVOID;
+	nodrat->class = CGLOBL;
+	complex(nodrat);
+	nodrat->type = t;
+
+	nodret = new(ONAME, Z, Z);
+	nodret->sym = slookup(".ret");
+	nodret->type = types[TIND];
+	nodret->etype = TIND;
+	nodret->class = CPARAM;
+	nodret = new(OIND, nodret, Z);
+	complex(nodret);
+
+	if(0)
+		com64init();
+
+	for(i=0; i<nelem(reg); i++) {
+		reg[i] = 1;
+		if(i >= D_AX && i <= D_R15 && i != D_SP)
+			reg[i] = 0;
+		if(i >= D_X0 && i <= D_X7)
+			reg[i] = 0;
+	}
+	if(nacl) {
+		reg[D_BP] = 1;
+		reg[D_R15] = 1;
+	}
+}
+
+void
+gclean(void)
+{
+	int i;
+	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);
+	for(i=D_X0; i<=D_X7; i++)
+		if(reg[i])
+			diag(Z, "reg %R left allocated", i);
+	while(mnstring)
+		outstring("", 1L);
+	symstring->type->width = nstring;
+	symrathole->type->width = nrathole;
+	for(i=0; i<NHASH; i++)
+	for(s = hash[i]; s != S; s = s->link) {
+		if(s->type == T)
+			continue;
+		if(s->type->width == 0)
+			continue;
+		if(s->class != CGLOBL && s->class != CSTATIC)
+			continue;
+		if(s->type == types[TENUM])
+			continue;
+		gpseudo(AGLOBL, s, nodconst(s->type->width));
+	}
+	nextpc();
+	p->as = AEND;
+	outcode();
+}
+
+void
+nextpc(void)
+{
+	Plist *pl;
+
+	p = alloc(sizeof(*p));
+	*p = zprog;
+	p->lineno = nearln;
+	p->pc = pc;
+	pc++;
+	if(lastp == nil) {
+		pl = linknewplist(ctxt);
+		pl->firstpc = p;
+	} else
+		lastp->link = p;
+	lastp = p;
+}
+
+void
+gargs(Node *n, Node *tn1, Node *tn2)
+{
+	int32 regs;
+	Node fnxargs[20], *fnxp;
+
+	regs = cursafe;
+
+	fnxp = fnxargs;
+	garg1(n, tn1, tn2, 0, &fnxp);	/* compile fns to temps */
+
+	curarg = 0;
+	fnxp = fnxargs;
+	garg1(n, tn1, tn2, 1, &fnxp);	/* compile normal args and temps */
+
+	cursafe = regs;
+}
+
+int
+nareg(void)
+{
+	int i, n;
+
+	n = 0;
+	for(i=D_AX; i<=D_R15; i++)
+		if(reg[i] == 0)
+			n++;
+	return n;
+}
+
+void
+garg1(Node *n, Node *tn1, Node *tn2, int f, Node **fnxp)
+{
+	Node nod;
+
+	if(n == Z)
+		return;
+	if(n->op == OLIST) {
+		garg1(n->left, tn1, tn2, f, fnxp);
+		garg1(n->right, tn1, tn2, f, fnxp);
+		return;
+	}
+	if(f == 0) {
+		if(n->complex >= FNX) {
+			regsalloc(*fnxp, n);
+			nod = znode;
+			nod.op = OAS;
+			nod.left = *fnxp;
+			nod.right = n;
+			nod.type = n->type;
+			cgen(&nod, Z);
+			(*fnxp)++;
+		}
+		return;
+	}
+	if(typesu[n->type->etype]) {
+		regaalloc(tn2, n);
+		if(n->complex >= FNX) {
+			sugen(*fnxp, tn2, n->type->width);
+			(*fnxp)++;
+		} else
+			sugen(n, tn2, n->type->width);
+		return;
+	}
+	if(REGARG >= 0 && curarg == 0 && typechlpv[n->type->etype]) {
+		regaalloc1(tn1, n);
+		if(n->complex >= FNX) {
+			cgen(*fnxp, tn1);
+			(*fnxp)++;
+		} else
+			cgen(n, tn1);
+		return;
+	}
+	if(vconst(n) == 0) {
+		regaalloc(tn2, n);
+		gmove(n, tn2);
+		return;
+	}
+	regalloc(tn1, n, Z);
+	if(n->complex >= FNX) {
+		cgen(*fnxp, tn1);
+		(*fnxp)++;
+	} else
+		cgen(n, tn1);
+	regaalloc(tn2, n);
+	gmove(tn1, tn2);
+	regfree(tn1);
+}
+
+Node*
+nodgconst(vlong v, Type *t)
+{
+	if(!typev[t->etype])
+		return nodconst((int32)v);
+	vconstnode.vconst = v;
+	return &vconstnode;
+}
+
+Node*
+nodconst(int32 v)
+{
+	constnode.vconst = v;
+	return &constnode;
+}
+
+Node*
+nodfconst(double d)
+{
+	fconstnode.fconst = d;
+	return &fconstnode;
+}
+
+int
+isreg(Node *n, int r)
+{
+
+	if(n->op == OREGISTER)
+		if(n->reg == r)
+			return 1;
+	return 0;
+}
+
+int
+nodreg(Node *n, Node *nn, int r)
+{
+	int et;
+
+	*n = qregnode;
+	n->reg = r;
+	if(nn != Z){
+		et = nn->type->etype;
+		if(!typefd[et] && nn->type->width <= SZ_LONG && 0)
+			n->type = typeu[et]? types[TUINT]: types[TINT];
+		else
+			n->type = nn->type;
+//print("nodreg %s [%s]\n", tnames[et], tnames[n->type->etype]);
+		n->lineno = nn->lineno;
+	}
+	if(reg[r] == 0)
+		return 0;
+	if(nn != Z) {
+		if(nn->op == OREGISTER)
+		if(nn->reg == r)
+			return 0;
+	}
+	return 1;
+}
+
+void
+regret(Node *n, Node *nn, Type *t, int mode)
+{
+	int r;
+	
+	if(mode == 0 || hasdotdotdot(t) || nn->type->width == 0) {
+		r = REGRET;
+		if(typefd[nn->type->etype])
+			r = FREGRET;
+		nodreg(n, nn, r);
+		reg[r]++;
+		return;
+	}
+	
+	if(mode == 1) {
+		// fetch returned value after call.
+		// already called gargs, so curarg is set.
+		curarg = (curarg+7) & ~7;
+		regaalloc(n, nn);
+		return;
+	}
+
+	if(mode == 2) {
+		// store value to be returned.
+		// must compute arg offset.
+		if(t->etype != TFUNC)
+			fatal(Z, "bad regret func %T", t);
+		*n = *nn;
+		n->op = ONAME;
+		n->class = CPARAM;
+		n->sym = slookup(".ret");
+		n->complex = nodret->complex;
+		n->addable = 20;
+		n->xoffset = argsize(0);
+		return;
+	}
+	
+	fatal(Z, "bad regret");	
+}
+
+void
+regalloc(Node *n, Node *tn, Node *o)
+{
+	int i;
+
+	switch(tn->type->etype) {
+	case TCHAR:
+	case TUCHAR:
+	case TSHORT:
+	case TUSHORT:
+	case TINT:
+	case TUINT:
+	case TLONG:
+	case TULONG:
+	case TVLONG:
+	case TUVLONG:
+	case TIND:
+		if(o != Z && o->op == OREGISTER) {
+			i = o->reg;
+			if(i >= D_AX && i <= D_R15)
+				goto out;
+		}
+		for(i=D_AX; i<=D_R15; i++)
+			if(reg[i] == 0)
+				goto out;
+		diag(tn, "out of fixed registers");
+		goto err;
+
+	case TFLOAT:
+	case TDOUBLE:
+		if(o != Z && o->op == OREGISTER) {
+			i = o->reg;
+			if(i >= D_X0 && i <= D_X7)
+				goto out;
+		}
+		for(i=D_X0; i<=D_X7; i++)
+			if(reg[i] == 0)
+				goto out;
+		diag(tn, "out of float registers");
+		goto out;
+	}
+	diag(tn, "unknown type in regalloc: %T", tn->type);
+err:
+	i = 0;
+out:
+	if(i)
+		reg[i]++;
+	nodreg(n, tn, i);
+}
+
+void
+regialloc(Node *n, Node *tn, Node *o)
+{
+	Node nod;
+
+	nod = *tn;
+	nod.type = types[TIND];
+	regalloc(n, &nod, o);
+}
+
+void
+regfree(Node *n)
+{
+	int i;
+
+	i = 0;
+	if(n->op != OREGISTER && n->op != OINDREG)
+		goto err;
+	i = n->reg;
+	if(i < 0 || i >= nelem(reg))
+		goto err;
+	if(reg[i] <= 0)
+		goto err;
+	reg[i]--;
+	return;
+err:
+	diag(n, "error in regfree: %R", i);
+}
+
+void
+regsalloc(Node *n, Node *nn)
+{
+	cursafe = align(cursafe, nn->type, Aaut3, nil);
+	maxargsafe = maxround(maxargsafe, cursafe+curarg);
+	*n = *nodsafe;
+	n->xoffset = -(stkoff + cursafe);
+	n->type = nn->type;
+	n->etype = nn->type->etype;
+	n->lineno = nn->lineno;
+}
+
+void
+regaalloc1(Node *n, Node *nn)
+{
+	if(REGARG < 0) {
+		fatal(n, "regaalloc1 and REGARG<0");
+		return;
+	}
+	nodreg(n, nn, REGARG);
+	reg[(uchar)REGARG]++;
+	curarg = align(curarg, nn->type, Aarg1, nil);
+	curarg = align(curarg, nn->type, Aarg2, nil);
+	maxargsafe = maxround(maxargsafe, cursafe+curarg);
+}
+
+void
+regaalloc(Node *n, Node *nn)
+{
+	curarg = align(curarg, nn->type, Aarg1, nil);
+	*n = *nn;
+	n->op = OINDREG;
+	n->reg = REGSP;
+	n->xoffset = curarg;
+	n->complex = 0;
+	n->addable = 20;
+	curarg = align(curarg, nn->type, Aarg2, nil);
+	maxargsafe = maxround(maxargsafe, cursafe+curarg);
+}
+
+void
+regind(Node *n, Node *nn)
+{
+
+	if(n->op != OREGISTER) {
+		diag(n, "regind not OREGISTER");
+		return;
+	}
+	n->op = OINDREG;
+	n->type = nn->type;
+}
+
+void
+naddr(Node *n, Addr *a)
+{
+	int32 v;
+
+	a->type = D_NONE;
+	if(n == Z)
+		return;
+	switch(n->op) {
+	default:
+	bad:
+		diag(n, "bad in naddr: %O %D", n->op, a);
+		break;
+
+	case OREGISTER:
+		a->type = n->reg;
+		a->sym = nil;
+		break;
+
+	case OEXREG:
+		a->type = D_INDIR + D_TLS;
+		a->offset = n->reg - 1;
+		break;
+
+	case OIND:
+		naddr(n->left, a);
+		if(a->type >= D_AX && a->type <= D_R15)
+			a->type += D_INDIR;
+		else
+		if(a->type == D_CONST)
+			a->type = D_NONE+D_INDIR;
+		else
+		if(a->type == D_ADDR) {
+			a->type = a->index;
+			a->index = D_NONE;
+		} else
+			goto bad;
+		break;
+
+	case OINDEX:
+		a->type = idx.ptr;
+		if(n->left->op == OADDR || n->left->op == OCONST)
+			naddr(n->left, a);
+		if(a->type >= D_AX && a->type <= D_R15)
+			a->type += D_INDIR;
+		else
+		if(a->type == D_CONST)
+			a->type = D_NONE+D_INDIR;
+		else
+		if(a->type == D_ADDR) {
+			a->type = a->index;
+			a->index = D_NONE;
+		} else
+			goto bad;
+		a->index = idx.reg;
+		a->scale = n->scale;
+		a->offset += n->xoffset;
+		break;
+
+	case OINDREG:
+		a->type = n->reg+D_INDIR;
+		a->sym = nil;
+		a->offset = n->xoffset;
+		break;
+
+	case ONAME:
+		a->etype = n->etype;
+		a->type = D_STATIC;
+		a->sym = linksym(n->sym);
+		a->offset = n->xoffset;
+		if(n->class == CSTATIC)
+			break;
+		if(n->class == CEXTERN || n->class == CGLOBL) {
+			a->type = D_EXTERN;
+			break;
+		}
+		if(n->class == CAUTO) {
+			a->type = D_AUTO;
+			break;
+		}
+		if(n->class == CPARAM) {
+			a->type = D_PARAM;
+			break;
+		}
+		goto bad;
+
+	case OCONST:
+		if(typefd[n->type->etype]) {
+			a->type = D_FCONST;
+			a->u.dval = n->fconst;
+			break;
+		}
+		a->sym = nil;
+		a->type = D_CONST;
+		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);
+		break;
+
+	case OADDR:
+		naddr(n->left, a);
+		if(a->type >= D_INDIR) {
+			a->type -= D_INDIR;
+			break;
+		}
+		if(a->type == D_EXTERN || a->type == D_STATIC ||
+		   a->type == D_AUTO || a->type == D_PARAM)
+			if(a->index == D_NONE) {
+				a->index = a->type;
+				a->type = D_ADDR;
+				break;
+			}
+		goto bad;
+
+	case OADD:
+		if(n->right->op == OCONST) {
+			v = n->right->vconst;
+			naddr(n->left, a);
+		} else
+		if(n->left->op == OCONST) {
+			v = n->left->vconst;
+			naddr(n->right, a);
+		} else
+			goto bad;
+		a->offset += v;
+		break;
+
+	}
+}
+
+void
+gcmp(int op, Node *n, vlong val)
+{
+	Node *cn, nod;
+
+	cn = nodgconst(val, n->type);
+	if(!immconst(cn)){
+		regalloc(&nod, n, Z);
+		gmove(cn, &nod);
+		gopcode(op, n->type, n, &nod);
+		regfree(&nod);
+	}else
+		gopcode(op, n->type, n, cn);
+}
+
+#define	CASE(a,b)	((a<<8)|(b<<0))
+
+void
+gmove(Node *f, Node *t)
+{
+	int ft, tt, t64, a;
+	Node nod, nod1, nod2, nod3;
+	Prog *p1, *p2;
+
+	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,
+			f->op, tnames[ft], t->op, tnames[tt]);
+	if(typefd[ft] && f->op == OCONST) {
+		/* TO DO: pick up special constants, possibly preloaded */
+		if(f->fconst == 0.0){
+			regalloc(&nod, t, t);
+			gins(AXORPD, &nod, &nod);
+			gmove(&nod, t);
+			regfree(&nod);
+			return;
+		}
+	}
+/*
+ * load
+ */
+	if(ft == TVLONG || ft == TUVLONG)
+	if(f->op == OCONST)
+	if(f->vconst > 0x7fffffffLL || f->vconst < -0x7fffffffLL)
+	if(t->op != OREGISTER) {
+		regalloc(&nod, f, Z);
+		gmove(f, &nod);
+		gmove(&nod, t);
+		regfree(&nod);
+		return;
+	}
+
+	if(f->op == ONAME || f->op == OINDREG ||
+	   f->op == OIND || f->op == OINDEX)
+	switch(ft) {
+	case TCHAR:
+		a = AMOVBLSX;
+		if(t64)
+			a = AMOVBQSX;
+		goto ld;
+	case TUCHAR:
+		a = AMOVBLZX;
+		if(t64)
+			a = AMOVBQZX;
+		goto ld;
+	case TSHORT:
+		a = AMOVWLSX;
+		if(t64)
+			a = AMOVWQSX;
+		goto ld;
+	case TUSHORT:
+		a = AMOVWLZX;
+		if(t64)
+			a = AMOVWQZX;
+		goto ld;
+	case TINT:
+	case TLONG:
+		if(typefd[tt]) {
+			regalloc(&nod, t, t);
+			if(tt == TDOUBLE)
+				a = ACVTSL2SD;
+			else
+				a = ACVTSL2SS;
+			gins(a, f, &nod);
+			gmove(&nod, t);
+			regfree(&nod);
+			return;
+		}
+		a = AMOVL;
+		if(t64)
+			a = AMOVLQSX;
+		goto ld;
+	case TUINT:
+	case TULONG:
+		a = AMOVL;
+		if(t64)
+			a = AMOVLQZX;	/* could probably use plain MOVL */
+		goto ld;
+	case TVLONG:
+		if(typefd[tt]) {
+			regalloc(&nod, t, t);
+			if(tt == TDOUBLE)
+				a = ACVTSQ2SD;
+			else
+				a = ACVTSQ2SS;
+			gins(a, f, &nod);
+			gmove(&nod, t);
+			regfree(&nod);
+			return;
+		}
+	case TUVLONG:
+		a = AMOVQ;
+		goto ld;
+	case TIND:
+		a = AMOVQ;
+		if(ewidth[TIND] == 4)
+			a = AMOVL;
+
+	ld:
+		regalloc(&nod, f, t);
+		nod.type = t64? types[TVLONG]: types[TINT];
+		gins(a, f, &nod);
+		gmove(&nod, t);
+		regfree(&nod);
+		return;
+
+	case TFLOAT:
+		a = AMOVSS;
+		goto fld;
+	case TDOUBLE:
+		a = AMOVSD;
+	fld:
+		regalloc(&nod, f, t);
+		if(tt != TDOUBLE && tt != TFLOAT){	/* TO DO: why is this here */
+			prtree(f, "odd tree");
+			nod.type = t64? types[TVLONG]: types[TINT];
+		}
+		gins(a, f, &nod);
+		gmove(&nod, t);
+		regfree(&nod);
+		return;
+	}
+
+/*
+ * store
+ */
+	if(t->op == ONAME || t->op == OINDREG ||
+	   t->op == OIND || t->op == OINDEX)
+	switch(tt) {
+	case TCHAR:
+	case TUCHAR:
+		a = AMOVB;	goto st;
+	case TSHORT:
+	case TUSHORT:
+		a = AMOVW;	goto st;
+	case TINT:
+	case TUINT:
+	case TLONG:
+	case TULONG:
+		a = AMOVL;	goto st;
+	case TVLONG:
+	case TUVLONG:
+	case TIND:
+		a = AMOVQ;	goto st;
+
+	st:
+		if(f->op == OCONST) {
+			gins(a, f, t);
+			return;
+		}
+	fst:
+		regalloc(&nod, t, f);
+		gmove(f, &nod);
+		gins(a, &nod, t);
+		regfree(&nod);
+		return;
+
+	case TFLOAT:
+		a = AMOVSS;
+		goto fst;
+	case TDOUBLE:
+		a = AMOVSD;
+		goto fst;
+	}
+
+/*
+ * convert
+ */
+	switch(CASE(ft,tt)) {
+	default:
+/*
+ * integer to integer
+ ********
+		a = AGOK;	break;
+
+	case CASE(	TCHAR,	TCHAR):
+	case CASE(	TUCHAR,	TCHAR):
+	case CASE(	TSHORT,	TCHAR):
+	case CASE(	TUSHORT,TCHAR):
+	case CASE(	TINT,	TCHAR):
+	case CASE(	TUINT,	TCHAR):
+	case CASE(	TLONG,	TCHAR):
+	case CASE(	TULONG,	TCHAR):
+
+	case CASE(	TCHAR,	TUCHAR):
+	case CASE(	TUCHAR,	TUCHAR):
+	case CASE(	TSHORT,	TUCHAR):
+	case CASE(	TUSHORT,TUCHAR):
+	case CASE(	TINT,	TUCHAR):
+	case CASE(	TUINT,	TUCHAR):
+	case CASE(	TLONG,	TUCHAR):
+	case CASE(	TULONG,	TUCHAR):
+
+	case CASE(	TSHORT,	TSHORT):
+	case CASE(	TUSHORT,TSHORT):
+	case CASE(	TINT,	TSHORT):
+	case CASE(	TUINT,	TSHORT):
+	case CASE(	TLONG,	TSHORT):
+	case CASE(	TULONG,	TSHORT):
+
+	case CASE(	TSHORT,	TUSHORT):
+	case CASE(	TUSHORT,TUSHORT):
+	case CASE(	TINT,	TUSHORT):
+	case CASE(	TUINT,	TUSHORT):
+	case CASE(	TLONG,	TUSHORT):
+	case CASE(	TULONG,	TUSHORT):
+
+	case CASE(	TINT,	TINT):
+	case CASE(	TUINT,	TINT):
+	case CASE(	TLONG,	TINT):
+	case CASE(	TULONG,	TINT):
+
+	case CASE(	TINT,	TUINT):
+	case CASE(	TUINT,	TUINT):
+	case CASE(	TLONG,	TUINT):
+	case CASE(	TULONG,	TUINT):
+ *****/
+		a = AMOVL;
+		break;
+
+	case CASE(	TINT,	TIND):
+	case CASE(	TINT,	TVLONG):
+	case CASE(	TINT,	TUVLONG):
+	case CASE(	TLONG,	TIND):
+	case CASE(	TLONG,	TVLONG):
+	case CASE(	TLONG,	TUVLONG):
+		a = AMOVLQSX;
+		if(f->op == OCONST) {
+			f->vconst &= (uvlong)0xffffffffU;
+			if(f->vconst & 0x80000000)
+				f->vconst |= (vlong)0xffffffff << 32;
+			a = AMOVQ;
+		}
+		break;
+
+	case CASE(	TUINT,	TIND):
+	case CASE(	TUINT,	TVLONG):
+	case CASE(	TUINT,	TUVLONG):
+	case CASE(	TULONG,	TVLONG):
+	case CASE(	TULONG,	TUVLONG):
+	case CASE(	TULONG,	TIND):
+		a = AMOVLQZX;
+		if(f->op == OCONST) {
+			f->vconst &= (uvlong)0xffffffffU;
+			a = AMOVQ;
+		}
+		break;
+	
+	case CASE(	TIND,	TCHAR):
+	case CASE(	TIND,	TUCHAR):
+	case CASE(	TIND,	TSHORT):
+	case CASE(	TIND,	TUSHORT):
+	case CASE(	TIND,	TINT):
+	case CASE(	TIND,	TUINT):
+	case CASE(	TIND,	TLONG):
+	case CASE(	TIND,	TULONG):
+	case CASE(	TVLONG,	TCHAR):
+	case CASE(	TVLONG,	TUCHAR):
+	case CASE(	TVLONG,	TSHORT):
+	case CASE(	TVLONG,	TUSHORT):
+	case CASE(	TVLONG,	TINT):
+	case CASE(	TVLONG,	TUINT):
+	case CASE(	TVLONG,	TLONG):
+	case CASE(	TVLONG,	TULONG):
+	case CASE(	TUVLONG,	TCHAR):
+	case CASE(	TUVLONG,	TUCHAR):
+	case CASE(	TUVLONG,	TSHORT):
+	case CASE(	TUVLONG,	TUSHORT):
+	case CASE(	TUVLONG,	TINT):
+	case CASE(	TUVLONG,	TUINT):
+	case CASE(	TUVLONG,	TLONG):
+	case CASE(	TUVLONG,	TULONG):
+		a = AMOVQL;
+		if(f->op == OCONST) {
+			f->vconst &= (int)0xffffffffU;
+			a = AMOVL;
+		}
+		break;	
+
+	case CASE(	TIND,	TIND):
+	case CASE(	TIND,	TVLONG):
+	case CASE(	TIND,	TUVLONG):
+	case CASE(	TVLONG,	TIND):
+	case CASE(	TVLONG,	TVLONG):
+	case CASE(	TVLONG,	TUVLONG):
+	case CASE(	TUVLONG,	TIND):
+	case CASE(	TUVLONG,	TVLONG):
+	case CASE(	TUVLONG,	TUVLONG):
+		a = AMOVQ;
+		break;
+
+	case CASE(	TSHORT,	TINT):
+	case CASE(	TSHORT,	TUINT):
+	case CASE(	TSHORT,	TLONG):
+	case CASE(	TSHORT,	TULONG):
+		a = AMOVWLSX;
+		if(f->op == OCONST) {
+			f->vconst &= 0xffff;
+			if(f->vconst & 0x8000)
+				f->vconst |= 0xffff0000;
+			a = AMOVL;
+		}
+		break;
+
+	case CASE(	TSHORT,	TVLONG):
+	case CASE(	TSHORT,	TUVLONG):
+	case CASE(	TSHORT,	TIND):
+		a = AMOVWQSX;
+		if(f->op == OCONST) {
+			f->vconst &= 0xffff;
+			if(f->vconst & 0x8000){
+				f->vconst |= 0xffff0000;
+				f->vconst |= (vlong)~0 << 32;
+			}
+			a = AMOVL;
+		}
+		break;
+
+	case CASE(	TUSHORT,TINT):
+	case CASE(	TUSHORT,TUINT):
+	case CASE(	TUSHORT,TLONG):
+	case CASE(	TUSHORT,TULONG):
+		a = AMOVWLZX;
+		if(f->op == OCONST) {
+			f->vconst &= 0xffff;
+			a = AMOVL;
+		}
+		break;
+
+	case CASE(	TUSHORT,TVLONG):
+	case CASE(	TUSHORT,TUVLONG):
+	case CASE(	TUSHORT,TIND):
+		a = AMOVWQZX;
+		if(f->op == OCONST) {
+			f->vconst &= 0xffff;
+			a = AMOVL;	/* MOVL also zero-extends to 64 bits */
+		}
+		break;
+
+	case CASE(	TCHAR,	TSHORT):
+	case CASE(	TCHAR,	TUSHORT):
+	case CASE(	TCHAR,	TINT):
+	case CASE(	TCHAR,	TUINT):
+	case CASE(	TCHAR,	TLONG):
+	case CASE(	TCHAR,	TULONG):
+		a = AMOVBLSX;
+		if(f->op == OCONST) {
+			f->vconst &= 0xff;
+			if(f->vconst & 0x80)
+				f->vconst |= 0xffffff00;
+			a = AMOVL;
+		}
+		break;
+
+	case CASE(	TCHAR,	TVLONG):
+	case CASE(	TCHAR,	TUVLONG):
+	case CASE(	TCHAR,	TIND):
+		a = AMOVBQSX;
+		if(f->op == OCONST) {
+			f->vconst &= 0xff;
+			if(f->vconst & 0x80){
+				f->vconst |= 0xffffff00;
+				f->vconst |= (vlong)~0 << 32;
+			}
+			a = AMOVQ;
+		}
+		break;
+
+	case CASE(	TUCHAR,	TSHORT):
+	case CASE(	TUCHAR,	TUSHORT):
+	case CASE(	TUCHAR,	TINT):
+	case CASE(	TUCHAR,	TUINT):
+	case CASE(	TUCHAR,	TLONG):
+	case CASE(	TUCHAR,	TULONG):
+		a = AMOVBLZX;
+		if(f->op == OCONST) {
+			f->vconst &= 0xff;
+			a = AMOVL;
+		}
+		break;
+
+	case CASE(	TUCHAR,	TVLONG):
+	case CASE(	TUCHAR,	TUVLONG):
+	case CASE(	TUCHAR,	TIND):
+		a = AMOVBQZX;
+		if(f->op == OCONST) {
+			f->vconst &= 0xff;
+			a = AMOVL;	/* zero-extends to 64-bits */
+		}
+		break;
+
+/*
+ * float to fix
+ */
+	case CASE(	TFLOAT,	TCHAR):
+	case CASE(	TFLOAT,	TUCHAR):
+	case CASE(	TFLOAT,	TSHORT):
+	case CASE(	TFLOAT,	TUSHORT):
+	case CASE(	TFLOAT,	TINT):
+	case CASE(	TFLOAT,	TUINT):
+	case CASE(	TFLOAT,	TLONG):
+	case CASE(	TFLOAT,	TULONG):
+	case CASE(	TFLOAT,	TVLONG):
+	case CASE(	TFLOAT,	TUVLONG):
+	case CASE(	TFLOAT,	TIND):
+
+	case CASE(	TDOUBLE,TCHAR):
+	case CASE(	TDOUBLE,TUCHAR):
+	case CASE(	TDOUBLE,TSHORT):
+	case CASE(	TDOUBLE,TUSHORT):
+	case CASE(	TDOUBLE,TINT):
+	case CASE(	TDOUBLE,TUINT):
+	case CASE(	TDOUBLE,TLONG):
+	case CASE(	TDOUBLE,TULONG):
+	case CASE(	TDOUBLE,TVLONG):
+	case CASE(	TDOUBLE,TUVLONG):
+	case CASE(	TDOUBLE,TIND):
+		regalloc(&nod, t, Z);
+		if(ewidth[tt] == SZ_VLONG || typeu[tt] && ewidth[tt] == SZ_INT){
+			if(ft == TFLOAT)
+				a = ACVTTSS2SQ;
+			else
+				a = ACVTTSD2SQ;
+		}else{
+			if(ft == TFLOAT)
+				a = ACVTTSS2SL;
+			else
+				a = ACVTTSD2SL;
+		}
+		gins(a, f, &nod);
+		gmove(&nod, t);
+		regfree(&nod);
+		return;
+
+/*
+ * uvlong to float
+ */
+	case CASE(	TUVLONG,	TDOUBLE):
+	case CASE(	TUVLONG,	TFLOAT):
+		a = ACVTSQ2SS;
+		if(tt == TDOUBLE)
+			a = ACVTSQ2SD;
+		regalloc(&nod, f, f);
+		gmove(f, &nod);
+		regalloc(&nod1, t, t);
+		gins(ACMPQ, &nod, nodconst(0));
+		gins(AJLT, Z, Z);
+		p1 = p;
+		gins(a, &nod, &nod1);
+		gins(AJMP, Z, Z);
+		p2 = p;
+		patch(p1, pc);
+		regalloc(&nod2, f, Z);
+		regalloc(&nod3, f, Z);
+		gmove(&nod, &nod2);
+		gins(ASHRQ, nodconst(1), &nod2);
+		gmove(&nod, &nod3);
+		gins(AANDL, nodconst(1), &nod3);
+		gins(AORQ, &nod3, &nod2);
+		gins(a, &nod2, &nod1);
+		gins(tt == TDOUBLE? AADDSD: AADDSS, &nod1, &nod1);
+		regfree(&nod2);
+		regfree(&nod3);
+		patch(p2, pc);
+		regfree(&nod);
+		regfree(&nod1);
+		return;
+
+	case CASE(	TULONG,	TDOUBLE):
+	case CASE(	TUINT,	TDOUBLE):
+	case CASE(	TULONG,	TFLOAT):
+	case CASE(	TUINT,	TFLOAT):
+		a = ACVTSQ2SS;
+		if(tt == TDOUBLE)
+			a = ACVTSQ2SD;
+		regalloc(&nod, f, f);
+		gins(AMOVLQZX, f, &nod);
+		regalloc(&nod1, t, t);
+		gins(a, &nod, &nod1);
+		gmove(&nod1, t);
+		regfree(&nod);
+		regfree(&nod1);
+		return;
+
+/*
+ * fix to float
+ */
+	case CASE(	TCHAR,	TFLOAT):
+	case CASE(	TUCHAR,	TFLOAT):
+	case CASE(	TSHORT,	TFLOAT):
+	case CASE(	TUSHORT,TFLOAT):
+	case CASE(	TINT,	TFLOAT):
+	case CASE(	TLONG,	TFLOAT):
+	case	CASE(	TVLONG,	TFLOAT):
+	case CASE(	TIND,	TFLOAT):
+
+	case CASE(	TCHAR,	TDOUBLE):
+	case CASE(	TUCHAR,	TDOUBLE):
+	case CASE(	TSHORT,	TDOUBLE):
+	case CASE(	TUSHORT,TDOUBLE):
+	case CASE(	TINT,	TDOUBLE):
+	case CASE(	TLONG,	TDOUBLE):
+	case CASE(	TVLONG,	TDOUBLE):
+	case CASE(	TIND,	TDOUBLE):
+		regalloc(&nod, t, t);
+		if(ewidth[ft] == SZ_VLONG){
+			if(tt == TFLOAT)
+				a = ACVTSQ2SS;
+			else
+				a = ACVTSQ2SD;
+		}else{
+			if(tt == TFLOAT)
+				a = ACVTSL2SS;
+			else
+				a = ACVTSL2SD;
+		}
+		gins(a, f, &nod);
+		gmove(&nod, t);
+		regfree(&nod);
+		return;
+
+/*
+ * float to float
+ */
+	case CASE(	TFLOAT,	TFLOAT):
+		a = AMOVSS;
+		break;
+	case CASE(	TDOUBLE,TFLOAT):
+		a = ACVTSD2SS;
+		break;
+	case CASE(	TFLOAT,	TDOUBLE):
+		a = ACVTSS2SD;
+		break;
+	case CASE(	TDOUBLE,TDOUBLE):
+		a = AMOVSD;
+		break;
+	}
+	if(a == AMOVQ || a == AMOVSD || a == AMOVSS || a == AMOVL && ewidth[ft] == ewidth[tt])	/* TO DO: check AMOVL */
+	if(samaddr(f, t))
+		return;
+	gins(a, f, t);
+}
+
+void
+doindex(Node *n)
+{
+	Node nod, nod1;
+	int32 v;
+
+if(debug['Y'])
+prtree(n, "index");
+
+if(n->left->complex >= FNX)
+print("botch in doindex\n");
+
+	regalloc(&nod, &qregnode, Z);
+	v = constnode.vconst;
+	cgen(n->right, &nod);
+	idx.ptr = D_NONE;
+	if(n->left->op == OCONST)
+		idx.ptr = D_CONST;
+	else if(n->left->op == OREGISTER)
+		idx.ptr = n->left->reg;
+	else if(n->left->op != OADDR) {
+		reg[D_BP]++;	// can't be used as a base
+		regalloc(&nod1, &qregnode, Z);
+		cgen(n->left, &nod1);
+		idx.ptr = nod1.reg;
+		regfree(&nod1);
+		reg[D_BP]--;
+	}
+	idx.reg = nod.reg;
+	regfree(&nod);
+	constnode.vconst = v;
+}
+
+void
+gins(int a, Node *f, Node *t)
+{
+
+	if(f != Z && f->op == OINDEX)
+		doindex(f);
+	if(t != Z && t->op == OINDEX)
+		doindex(t);
+	nextpc();
+	p->as = a;
+	if(f != Z)
+		naddr(f, &p->from);
+	if(t != Z)
+		naddr(t, &p->to);
+	if(debug['g'])
+		print("%P\n", p);
+}
+
+void
+gopcode(int o, Type *ty, Node *f, Node *t)
+{
+	int a, et;
+
+	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]);
+		else
+			print("gop: %O Z,", o);
+		if(t != Z && t->type != T)
+			print("%O[%s]\n", t->op, tnames[t->type->etype]);
+		else
+			print("Z\n");
+	}
+	a = AGOK;
+	switch(o) {
+	case OCOM:
+		a = ANOTL;
+		if(et == TCHAR || et == TUCHAR)
+			a = ANOTB;
+		if(et == TSHORT || et == TUSHORT)
+			a = ANOTW;
+		if(et == TVLONG || et == TUVLONG || et == TIND)
+			a = ANOTQ;
+		break;
+
+	case ONEG:
+		a = ANEGL;
+		if(et == TCHAR || et == TUCHAR)
+			a = ANEGB;
+		if(et == TSHORT || et == TUSHORT)
+			a = ANEGW;
+		if(et == TVLONG || et == TUVLONG || et == TIND)
+			a = ANEGQ;
+		break;
+
+	case OADDR:
+		a = ALEAQ;
+		break;
+
+	case OASADD:
+	case OADD:
+		a = AADDL;
+		if(et == TCHAR || et == TUCHAR)
+			a = AADDB;
+		if(et == TSHORT || et == TUSHORT)
+			a = AADDW;
+		if(et == TVLONG || et == TUVLONG || et == TIND)
+			a = AADDQ;
+		if(et == TFLOAT)
+			a = AADDSS;
+		if(et == TDOUBLE)
+			a = AADDSD;
+		break;
+
+	case OASSUB:
+	case OSUB:
+		a = ASUBL;
+		if(et == TCHAR || et == TUCHAR)
+			a = ASUBB;
+		if(et == TSHORT || et == TUSHORT)
+			a = ASUBW;
+		if(et == TVLONG || et == TUVLONG || et == TIND)
+			a = ASUBQ;
+		if(et == TFLOAT)
+			a = ASUBSS;
+		if(et == TDOUBLE)
+			a = ASUBSD;
+		break;
+
+	case OASOR:
+	case OOR:
+		a = AORL;
+		if(et == TCHAR || et == TUCHAR)
+			a = AORB;
+		if(et == TSHORT || et == TUSHORT)
+			a = AORW;
+		if(et == TVLONG || et == TUVLONG || et == TIND)
+			a = AORQ;
+		break;
+
+	case OASAND:
+	case OAND:
+		a = AANDL;
+		if(et == TCHAR || et == TUCHAR)
+			a = AANDB;
+		if(et == TSHORT || et == TUSHORT)
+			a = AANDW;
+		if(et == TVLONG || et == TUVLONG || et == TIND)
+			a = AANDQ;
+		break;
+
+	case OASXOR:
+	case OXOR:
+		a = AXORL;
+		if(et == TCHAR || et == TUCHAR)
+			a = AXORB;
+		if(et == TSHORT || et == TUSHORT)
+			a = AXORW;
+		if(et == TVLONG || et == TUVLONG || et == TIND)
+			a = AXORQ;
+		break;
+
+	case OASLSHR:
+	case OLSHR:
+		a = ASHRL;
+		if(et == TCHAR || et == TUCHAR)
+			a = ASHRB;
+		if(et == TSHORT || et == TUSHORT)
+			a = ASHRW;
+		if(et == TVLONG || et == TUVLONG || et == TIND)
+			a = ASHRQ;
+		break;
+
+	case OASASHR:
+	case OASHR:
+		a = ASARL;
+		if(et == TCHAR || et == TUCHAR)
+			a = ASARB;
+		if(et == TSHORT || et == TUSHORT)
+			a = ASARW;
+		if(et == TVLONG || et == TUVLONG || et == TIND)
+			a = ASARQ;
+		break;
+
+	case OASASHL:
+	case OASHL:
+		a = ASALL;
+		if(et == TCHAR || et == TUCHAR)
+			a = ASALB;
+		if(et == TSHORT || et == TUSHORT)
+			a = ASALW;
+		if(et == TVLONG || et == TUVLONG || et == TIND)
+			a = ASALQ;
+		break;
+
+	case OROTL:
+		a = AROLL;
+		if(et == TCHAR || et == TUCHAR)
+			a = AROLB;
+		if(et == TSHORT || et == TUSHORT)
+			a = AROLW;
+		if(et == TVLONG || et == TUVLONG || et == TIND)
+			a = AROLQ;
+		break;
+
+	case OFUNC:
+		a = ACALL;
+		break;
+
+	case OASMUL:
+	case OMUL:
+		if(f->op == OREGISTER && t != Z && isreg(t, D_AX) && reg[D_DX] == 0)
+			t = Z;
+		a = AIMULL;
+		if(et == TVLONG || et == TUVLONG || et == TIND)
+			a = AIMULQ;
+		if(et == TFLOAT)
+			a = AMULSS;
+		if(et == TDOUBLE)
+			a = AMULSD;
+		break;
+
+	case OASMOD:
+	case OMOD:
+	case OASDIV:
+	case ODIV:
+		a = AIDIVL;
+		if(et == TVLONG || et == TUVLONG || et == TIND)
+			a = AIDIVQ;
+		if(et == TFLOAT)
+			a = ADIVSS;
+		if(et == TDOUBLE)
+			a = ADIVSD;
+		break;
+
+	case OASLMUL:
+	case OLMUL:
+		a = AMULL;
+		if(et == TVLONG || et == TUVLONG || et == TIND)
+			a = AMULQ;
+		break;
+
+	case OASLMOD:
+	case OLMOD:
+	case OASLDIV:
+	case OLDIV:
+		a = ADIVL;
+		if(et == TVLONG || et == TUVLONG || et == TIND)
+			a = ADIVQ;
+		break;
+
+	case OEQ:
+	case ONE:
+	case OLT:
+	case OLE:
+	case OGE:
+	case OGT:
+	case OLO:
+	case OLS:
+	case OHS:
+	case OHI:
+		a = ACMPL;
+		if(et == TCHAR || et == TUCHAR)
+			a = ACMPB;
+		if(et == TSHORT || et == TUSHORT)
+			a = ACMPW;
+		if(et == TVLONG || et == TUVLONG || et == TIND)
+			a = ACMPQ;
+		if(et == TFLOAT)
+			a = AUCOMISS;
+		if(et == TDOUBLE)
+			a = AUCOMISD;
+		gins(a, f, t);
+		switch(o) {
+		case OEQ:	a = AJEQ; break;
+		case ONE:	a = AJNE; break;
+		case OLT:	a = AJLT; break;
+		case OLE:	a = AJLE; break;
+		case OGE:	a = AJGE; break;
+		case OGT:	a = AJGT; break;
+		case OLO:	a = AJCS; break;
+		case OLS:	a = AJLS; break;
+		case OHS:	a = AJCC; break;
+		case OHI:	a = AJHI; break;
+		}
+		gins(a, Z, Z);
+		return;
+	}
+	if(a == AGOK)
+		diag(Z, "bad in gopcode %O", o);
+	gins(a, f, t);
+}
+
+int
+samaddr(Node *f, Node *t)
+{
+	return f->op == OREGISTER && t->op == OREGISTER && f->reg == t->reg;
+}
+
+void
+gbranch(int o)
+{
+	int a;
+
+	a = AGOK;
+	switch(o) {
+	case ORETURN:
+		a = ARET;
+		break;
+	case OGOTO:
+		a = AJMP;
+		break;
+	}
+	nextpc();
+	if(a == AGOK) {
+		diag(Z, "bad in gbranch %O",  o);
+		nextpc();
+	}
+	p->as = a;
+}
+
+void
+patch(Prog *op, int32 pc)
+{
+	op->to.offset = pc;
+	op->to.type = D_BRANCH;
+	op->to.u.branch = nil;
+	op->pcond = nil;
+}
+
+void
+gpseudo(int a, Sym *s, Node *n)
+{
+
+	nextpc();
+	p->as = a;
+	p->from.type = D_EXTERN;
+	p->from.sym = linksym(s);
+
+	switch(a) {
+	case ATEXT:
+		p->from.scale = textflag;
+		textflag = 0;
+		break;
+	case AGLOBL:
+		p->from.scale = s->dataflag;
+		break;
+	}
+
+	if(s->class == CSTATIC)
+		p->from.type = D_STATIC;
+	naddr(n, &p->to);
+	if(a == ADATA || a == AGLOBL)
+		pc--;
+}
+
+void
+gpcdata(int index, int value)
+{
+	Node n1;
+	
+	n1 = *nodconst(index);
+	gins(APCDATA, &n1, nodconst(value));
+}
+
+void
+gprefetch(Node *n)
+{
+	Node n1;
+	
+	regalloc(&n1, n, Z);
+	gmove(n, &n1);
+	n1.op = OINDREG;
+	gins(APREFETCHNTA, &n1, Z);
+	regfree(&n1);
+}
+
+int
+sconst(Node *n)
+{
+	int32 v;
+
+	if(n->op == OCONST && !typefd[n->type->etype]) {
+		v = n->vconst;
+		if(v >= -32766L && v < 32766L)
+			return 1;
+	}
+	return 0;
+}
+
+int32
+exreg(Type *t)
+{
+	int32 o;
+
+	if(typechlpv[t->etype]) {
+		if(exregoffset >= 64)
+			return 0;
+		o = exregoffset;
+		exregoffset += ewidth[TIND];
+		return o+1;	// +1 to avoid 0 == failure; naddr's case OEXREG will subtract 1.
+	}
+	return 0;
+}
+
+schar	ewidth[NTYPE] =
+{
+	-1,		/*[TXXX]*/
+	SZ_CHAR,	/*[TCHAR]*/
+	SZ_CHAR,	/*[TUCHAR]*/
+	SZ_SHORT,	/*[TSHORT]*/
+	SZ_SHORT,	/*[TUSHORT]*/
+	SZ_INT,		/*[TINT]*/
+	SZ_INT,		/*[TUINT]*/
+	SZ_LONG,	/*[TLONG]*/
+	SZ_LONG,	/*[TULONG]*/
+	SZ_VLONG,	/*[TVLONG]*/
+	SZ_VLONG,	/*[TUVLONG]*/
+	SZ_FLOAT,	/*[TFLOAT]*/
+	SZ_DOUBLE,	/*[TDOUBLE]*/
+	SZ_IND,		/*[TIND]*/
+	0,		/*[TFUNC]*/
+	-1,		/*[TARRAY]*/
+	0,		/*[TVOID]*/
+	-1,		/*[TSTRUCT]*/
+	-1,		/*[TUNION]*/
+	SZ_INT,		/*[TENUM]*/
+};
+int32	ncast[NTYPE] =
+{
+	0,				/*[TXXX]*/
+	BCHAR|BUCHAR,			/*[TCHAR]*/
+	BCHAR|BUCHAR,			/*[TUCHAR]*/
+	BSHORT|BUSHORT,			/*[TSHORT]*/
+	BSHORT|BUSHORT,			/*[TUSHORT]*/
+	BINT|BUINT|BLONG|BULONG,	/*[TINT]*/
+	BINT|BUINT|BLONG|BULONG,	/*[TUINT]*/
+	BINT|BUINT|BLONG|BULONG,	/*[TLONG]*/
+	BINT|BUINT|BLONG|BULONG,	/*[TULONG]*/
+	BVLONG|BUVLONG|BIND,			/*[TVLONG]*/
+	BVLONG|BUVLONG|BIND,			/*[TUVLONG]*/
+	BFLOAT,				/*[TFLOAT]*/
+	BDOUBLE,			/*[TDOUBLE]*/
+	BVLONG|BUVLONG|BIND,		/*[TIND]*/
+	0,				/*[TFUNC]*/
+	0,				/*[TARRAY]*/
+	0,				/*[TVOID]*/
+	BSTRUCT,			/*[TSTRUCT]*/
+	BUNION,				/*[TUNION]*/
+	0,				/*[TENUM]*/
+};
diff --git a/src/cmd/6g/Makefile b/src/cmd/6g/Makefile
new file mode 100644
index 0000000..3f528d7
--- /dev/null
+++ b/src/cmd/6g/Makefile
@@ -0,0 +1,5 @@
+# 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/6g/cgen.c b/src/cmd/6g/cgen.c
new file mode 100644
index 0000000..d13c98d
--- /dev/null
+++ b/src/cmd/6g/cgen.c
@@ -0,0 +1,1732 @@
+// 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 "gg.h"
+
+/*
+ * generate:
+ *	res = n;
+ * simplifies and calls gmove.
+ */
+void
+cgen(Node *n, Node *res)
+{
+	Node *nl, *nr, *r;
+	Node n1, n2;
+	int a, f;
+	Prog *p1, *p2, *p3;
+	Addr addr;
+
+	if(debug['g']) {
+		dump("\ncgen-n", n);
+		dump("cgen-res", res);
+	}
+	if(n == N || n->type == T)
+		goto ret;
+
+	if(res == N || res->type == T)
+		fatal("cgen: res nil");
+
+	while(n->op == OCONVNOP)
+		n = n->left;
+
+	switch(n->op) {
+	case OSLICE:
+	case OSLICEARR:
+	case OSLICESTR:
+	case OSLICE3:
+	case OSLICE3ARR:
+		if (res->op != ONAME || !res->addable) {
+			tempname(&n1, n->type);
+			cgen_slice(n, &n1);
+			cgen(&n1, res);
+		} else
+			cgen_slice(n, res);
+		goto ret;
+	case OEFACE:
+		if (res->op != ONAME || !res->addable) {
+			tempname(&n1, n->type);
+			cgen_eface(n, &n1);
+			cgen(&n1, res);
+		} else
+			cgen_eface(n, res);
+		goto ret;
+	}
+
+	if(n->ullman >= UINF) {
+		if(n->op == OINDREG)
+			fatal("cgen: this is going to misscompile");
+		if(res->ullman >= UINF) {
+			tempname(&n1, n->type);
+			cgen(n, &n1);
+			cgen(&n1, res);
+			goto ret;
+		}
+	}
+
+	if(isfat(n->type)) {
+		if(n->type->width < 0)
+			fatal("forgot to compute width for %T", n->type);
+		sgen(n, res, n->type->width);
+		goto ret;
+	}
+
+	if(!res->addable) {
+		if(n->ullman > res->ullman) {
+			regalloc(&n1, n->type, res);
+			cgen(n, &n1);
+			if(n1.ullman > res->ullman) {
+				dump("n1", &n1);
+				dump("res", res);
+				fatal("loop in cgen");
+			}
+			cgen(&n1, res);
+			regfree(&n1);
+			goto ret;
+		}
+
+		if(res->ullman >= UINF)
+			goto gen;
+
+		if(complexop(n, res)) {
+			complexgen(n, res);
+			goto ret;
+		}
+
+		f = 1;	// gen thru register
+		switch(n->op) {
+		case OLITERAL:
+			if(smallintconst(n))
+				f = 0;
+			break;
+		case OREGISTER:
+			f = 0;
+			break;
+		}
+
+		if(!iscomplex[n->type->etype]) {
+			a = optoas(OAS, res->type);
+			if(sudoaddable(a, res, &addr)) {
+				if(f) {
+					regalloc(&n2, res->type, N);
+					cgen(n, &n2);
+					p1 = gins(a, &n2, N);
+					regfree(&n2);
+				} else
+					p1 = gins(a, n, N);
+				p1->to = addr;
+				if(debug['g'])
+					print("%P [ignore previous line]\n", p1);
+				sudoclean();
+				goto ret;
+			}
+		}
+
+	gen:
+		igen(res, &n1, N);
+		cgen(n, &n1);
+		regfree(&n1);
+		goto ret;
+	}
+
+	// update addressability for string, slice
+	// can't do in walk because n->left->addable
+	// changes if n->left is an escaping local variable.
+	switch(n->op) {
+	case OSPTR:
+	case OLEN:
+		if(isslice(n->left->type) || istype(n->left->type, TSTRING))
+			n->addable = n->left->addable;
+		break;
+	case OCAP:
+		if(isslice(n->left->type))
+			n->addable = n->left->addable;
+		break;
+	case OITAB:
+		n->addable = n->left->addable;
+		break;
+	}
+
+	if(complexop(n, res)) {
+		complexgen(n, res);
+		goto ret;
+	}
+
+	if(n->addable) {
+		gmove(n, res);
+		goto ret;
+	}
+
+	nl = n->left;
+	nr = n->right;
+
+	if(nl != N && nl->ullman >= UINF)
+	if(nr != N && nr->ullman >= UINF) {
+		tempname(&n1, nl->type);
+		cgen(nl, &n1);
+		n2 = *n;
+		n2.left = &n1;
+		cgen(&n2, res);
+		goto ret;
+	}
+
+	if(!iscomplex[n->type->etype]) {
+		a = optoas(OAS, n->type);
+		if(sudoaddable(a, n, &addr)) {
+			if(res->op == OREGISTER) {
+				p1 = gins(a, N, res);
+				p1->from = addr;
+			} else {
+				regalloc(&n2, n->type, N);
+				p1 = gins(a, N, &n2);
+				p1->from = addr;
+				gins(a, &n2, res);
+				regfree(&n2);
+			}
+			sudoclean();
+			goto ret;
+		}
+	}
+
+	switch(n->op) {
+	default:
+		dump("cgen", n);
+		fatal("cgen: unknown op %+hN", n);
+		break;
+
+	// these call bgen to get a bool value
+	case OOROR:
+	case OANDAND:
+	case OEQ:
+	case ONE:
+	case OLT:
+	case OLE:
+	case OGE:
+	case OGT:
+	case ONOT:
+		p1 = gbranch(AJMP, T, 0);
+		p2 = pc;
+		gmove(nodbool(1), res);
+		p3 = gbranch(AJMP, T, 0);
+		patch(p1, pc);
+		bgen(n, 1, 0, p2);
+		gmove(nodbool(0), res);
+		patch(p3, pc);
+		goto ret;
+
+	case OPLUS:
+		cgen(nl, res);
+		goto ret;
+
+	// unary
+	case OCOM:
+		a = optoas(OXOR, nl->type);
+		regalloc(&n1, nl->type, N);
+		cgen(nl, &n1);
+		nodconst(&n2, nl->type, -1);
+		gins(a, &n2, &n1);
+		gmove(&n1, res);
+		regfree(&n1);
+		goto ret;
+
+	case OMINUS:
+		if(isfloat[nl->type->etype]) {
+			nr = nodintconst(-1);
+			convlit(&nr, n->type);
+			a = optoas(OMUL, nl->type);
+			goto sbop;
+		}
+		a = optoas(n->op, nl->type);
+		goto uop;
+
+	// symmetric binary
+	case OAND:
+	case OOR:
+	case OXOR:
+	case OADD:
+	case OMUL:
+		a = optoas(n->op, nl->type);
+		if(a == AIMULB) {
+			cgen_bmul(n->op, nl, nr, res);
+			break;
+		}
+		goto sbop;
+
+	// asymmetric binary
+	case OSUB:
+		a = optoas(n->op, nl->type);
+		goto abop;
+
+	case OHMUL:
+		cgen_hmul(nl, nr, res);
+		break;
+
+	case OCONV:
+		if(n->type->width > nl->type->width) {
+			// If loading from memory, do conversion during load,
+			// so as to avoid use of 8-bit register in, say, int(*byteptr).
+			switch(nl->op) {
+			case ODOT:
+			case ODOTPTR:
+			case OINDEX:
+			case OIND:
+			case ONAME:
+				igen(nl, &n1, res);
+				regalloc(&n2, n->type, res);
+				gmove(&n1, &n2);
+				gmove(&n2, res);
+				regfree(&n2);
+				regfree(&n1);
+				goto ret;
+			}
+		}
+
+		regalloc(&n1, nl->type, res);
+		regalloc(&n2, n->type, &n1);
+		cgen(nl, &n1);
+
+		// if we do the conversion n1 -> n2 here
+		// reusing the register, then gmove won't
+		// have to allocate its own register.
+		gmove(&n1, &n2);
+		gmove(&n2, res);
+		regfree(&n2);
+		regfree(&n1);
+		break;
+
+	case ODOT:
+	case ODOTPTR:
+	case OINDEX:
+	case OIND:
+	case ONAME:	// PHEAP or PPARAMREF var
+		igen(n, &n1, res);
+		gmove(&n1, res);
+		regfree(&n1);
+		break;
+	
+	case OITAB:
+		// interface table is first word of interface value
+		igen(nl, &n1, res);
+		n1.type = n->type;
+		gmove(&n1, res);
+		regfree(&n1);
+		break;
+
+	case OSPTR:
+		// pointer is the first word of string or slice.
+		if(isconst(nl, CTSTR)) {
+			regalloc(&n1, types[tptr], res);
+			p1 = gins(ALEAQ, N, &n1);
+			datastring(nl->val.u.sval->s, nl->val.u.sval->len, &p1->from);
+			gmove(&n1, res);
+			regfree(&n1);
+			break;
+		}
+		igen(nl, &n1, res);
+		n1.type = n->type;
+		gmove(&n1, res);
+		regfree(&n1);
+		break;
+
+	case OLEN:
+		if(istype(nl->type, TMAP) || istype(nl->type, TCHAN)) {
+			// map and chan have len in the first int-sized word.
+			// a zero pointer means zero length
+			regalloc(&n1, types[tptr], res);
+			cgen(nl, &n1);
+
+			nodconst(&n2, types[tptr], 0);
+			gins(optoas(OCMP, types[tptr]), &n1, &n2);
+			p1 = gbranch(optoas(OEQ, types[tptr]), T, 0);
+
+			n2 = n1;
+			n2.op = OINDREG;
+			n2.type = types[simtype[TINT]];
+			gmove(&n2, &n1);
+
+			patch(p1, pc);
+
+			gmove(&n1, res);
+			regfree(&n1);
+			break;
+		}
+		if(istype(nl->type, TSTRING) || isslice(nl->type)) {
+			// both slice and string have len one pointer into the struct.
+			// a zero pointer means zero length
+			igen(nl, &n1, res);
+			n1.type = types[simtype[TUINT]];
+			n1.xoffset += Array_nel;
+			gmove(&n1, res);
+			regfree(&n1);
+			break;
+		}
+		fatal("cgen: OLEN: unknown type %lT", nl->type);
+		break;
+
+	case OCAP:
+		if(istype(nl->type, TCHAN)) {
+			// chan has cap in the second int-sized word.
+			// a zero pointer means zero length
+			regalloc(&n1, types[tptr], res);
+			cgen(nl, &n1);
+
+			nodconst(&n2, types[tptr], 0);
+			gins(optoas(OCMP, types[tptr]), &n1, &n2);
+			p1 = gbranch(optoas(OEQ, types[tptr]), T, 0);
+
+			n2 = n1;
+			n2.op = OINDREG;
+			n2.xoffset = widthint;
+			n2.type = types[simtype[TINT]];
+			gmove(&n2, &n1);
+
+			patch(p1, pc);
+
+			gmove(&n1, res);
+			regfree(&n1);
+			break;
+		}
+		if(isslice(nl->type)) {
+			igen(nl, &n1, res);
+			n1.type = types[simtype[TUINT]];
+			n1.xoffset += Array_cap;
+			gmove(&n1, res);
+			regfree(&n1);
+			break;
+		}
+		fatal("cgen: OCAP: unknown type %lT", nl->type);
+		break;
+
+	case OADDR:
+		if(n->bounded) // let race detector avoid nil checks
+			disable_checknil++;
+		agen(nl, res);
+		if(n->bounded)
+			disable_checknil--;
+		break;
+
+	case OCALLMETH:
+		cgen_callmeth(n, 0);
+		cgen_callret(n, res);
+		break;
+
+	case OCALLINTER:
+		cgen_callinter(n, res, 0);
+		cgen_callret(n, res);
+		break;
+
+	case OCALLFUNC:
+		cgen_call(n, 0);
+		cgen_callret(n, res);
+		break;
+
+	case OMOD:
+	case ODIV:
+		if(isfloat[n->type->etype]) {
+			a = optoas(n->op, nl->type);
+			goto abop;
+		}
+
+		if(nl->ullman >= nr->ullman) {
+			regalloc(&n1, nl->type, res);
+			cgen(nl, &n1);
+			cgen_div(n->op, &n1, nr, res);
+			regfree(&n1);
+		} else {
+			if(!smallintconst(nr)) {
+				regalloc(&n2, nr->type, res);
+				cgen(nr, &n2);
+			} else {
+				n2 = *nr;
+			}
+			cgen_div(n->op, nl, &n2, res);
+			if(n2.op != OLITERAL)
+				regfree(&n2);
+		}
+		break;
+
+	case OLSH:
+	case ORSH:
+	case OLROT:
+		cgen_shift(n->op, n->bounded, nl, nr, res);
+		break;
+	}
+	goto ret;
+
+sbop:	// symmetric binary
+	/*
+	 * put simplest on right - we'll generate into left
+	 * and then adjust it using the computation of right.
+	 * constants and variables have the same ullman
+	 * count, so look for constants specially.
+	 *
+	 * an integer constant we can use as an immediate
+	 * is simpler than a variable - we can use the immediate
+	 * in the adjustment instruction directly - so it goes
+	 * on the right.
+	 *
+	 * other constants, like big integers or floating point
+	 * constants, require a mov into a register, so those
+	 * might as well go on the left, so we can reuse that
+	 * register for the computation.
+	 */
+	if(nl->ullman < nr->ullman ||
+	   (nl->ullman == nr->ullman &&
+	    (smallintconst(nl) || (nr->op == OLITERAL && !smallintconst(nr))))) {
+		r = nl;
+		nl = nr;
+		nr = r;
+	}
+
+abop:	// asymmetric binary
+	if(nl->ullman >= nr->ullman) {
+		regalloc(&n1, nl->type, res);
+		cgen(nl, &n1);
+	/*
+	 * This generates smaller code - it avoids a MOV - but it's
+	 * easily 10% slower due to not being able to
+	 * optimize/manipulate the move.
+	 * To see, run: go test -bench . crypto/md5
+	 * with and without.
+	 *
+		if(sudoaddable(a, nr, &addr)) {
+			p1 = gins(a, N, &n1);
+			p1->from = addr;
+			gmove(&n1, res);
+			sudoclean();
+			regfree(&n1);
+			goto ret;
+		}
+	 *
+	 */
+
+		if(smallintconst(nr))
+			n2 = *nr;
+		else {
+			regalloc(&n2, nr->type, N);
+			cgen(nr, &n2);
+		}
+	} else {
+		if(smallintconst(nr))
+			n2 = *nr;
+		else {
+			regalloc(&n2, nr->type, res);
+			cgen(nr, &n2);
+		}
+		regalloc(&n1, nl->type, N);
+		cgen(nl, &n1);
+	}
+	gins(a, &n2, &n1);
+	gmove(&n1, res);
+	regfree(&n1);
+	if(n2.op != OLITERAL)
+		regfree(&n2);
+	goto ret;
+
+uop:	// unary
+	regalloc(&n1, nl->type, res);
+	cgen(nl, &n1);
+	gins(a, N, &n1);
+	gmove(&n1, res);
+	regfree(&n1);
+	goto ret;
+
+ret:
+	;
+}
+
+/*
+ * allocate a register (reusing res if possible) and generate
+ *  a = n
+ * The caller must call regfree(a).
+ */
+void
+cgenr(Node *n, Node *a, Node *res)
+{
+	Node n1;
+
+	if(debug['g'])
+		dump("cgenr-n", n);
+
+	if(isfat(n->type))
+		fatal("cgenr on fat node");
+
+	if(n->addable) {
+		regalloc(a, n->type, res);
+		gmove(n, a);
+		return;
+	}
+
+	switch(n->op) {
+	case ONAME:
+	case ODOT:
+	case ODOTPTR:
+	case OINDEX:
+	case OCALLFUNC:
+	case OCALLMETH:
+	case OCALLINTER:
+		igen(n, &n1, res);
+		regalloc(a, types[tptr], &n1);
+		gmove(&n1, a);
+		regfree(&n1);
+		break;
+	default:
+		regalloc(a, n->type, res);
+		cgen(n, a);
+		break;
+	}
+}
+
+/*
+ * allocate a register (reusing res if possible) and generate
+ * a = &n
+ * The caller must call regfree(a).
+ * The generated code checks that the result is not nil.
+ */
+void
+agenr(Node *n, Node *a, Node *res)
+{
+	Node *nl, *nr;
+	Node n1, n2, n3, n5, tmp, tmp2, nlen;
+	Prog *p1;
+	Type *t;
+	uint64 w;
+	uint64 v;
+	int freelen;
+
+	if(debug['g']) {
+		dump("\nagenr-n", n);
+	}
+
+	nl = n->left;
+	nr = n->right;
+
+	switch(n->op) {
+	case ODOT:
+	case ODOTPTR:
+	case OCALLFUNC:
+	case OCALLMETH:
+	case OCALLINTER:
+		igen(n, &n1, res);
+		regalloc(a, types[tptr], &n1);
+		agen(&n1, a);
+		regfree(&n1);
+		break;
+
+	case OIND:
+		cgenr(n->left, a, res);
+		cgen_checknil(a);
+		break;
+
+	case OINDEX:
+		freelen = 0;
+		w = n->type->width;
+		// Generate the non-addressable child first.
+		if(nr->addable)
+			goto irad;
+		if(nl->addable) {
+			cgenr(nr, &n1, N);
+			if(!isconst(nl, CTSTR)) {
+				if(isfixedarray(nl->type)) {
+					agenr(nl, &n3, res);
+				} else {
+					igen(nl, &nlen, res);
+					freelen = 1;
+					nlen.type = types[tptr];
+					nlen.xoffset += Array_array;
+					regalloc(&n3, types[tptr], res);
+					gmove(&nlen, &n3);
+					nlen.type = types[simtype[TUINT]];
+					nlen.xoffset += Array_nel-Array_array;
+				}
+			}
+			goto index;
+		}
+		tempname(&tmp, nr->type);
+		cgen(nr, &tmp);
+		nr = &tmp;
+	irad:
+		if(!isconst(nl, CTSTR)) {
+			if(isfixedarray(nl->type)) {
+				agenr(nl, &n3, res);
+			} else {
+				if(!nl->addable) {
+					// igen will need an addressable node.
+					tempname(&tmp2, nl->type);
+					cgen(nl, &tmp2);
+					nl = &tmp2;
+				}
+				igen(nl, &nlen, res);
+				freelen = 1;
+				nlen.type = types[tptr];
+				nlen.xoffset += Array_array;
+				regalloc(&n3, types[tptr], res);
+				gmove(&nlen, &n3);
+				nlen.type = types[simtype[TUINT]];
+				nlen.xoffset += Array_nel-Array_array;
+			}
+		}
+		if(!isconst(nr, CTINT)) {
+			cgenr(nr, &n1, N);
+		}
+		goto index;
+
+	index:
+		// &a is in &n3 (allocated in res)
+		// i is in &n1 (if not constant)
+		// len(a) is in nlen (if needed)
+		// w is width
+
+		// constant index
+		if(isconst(nr, CTINT)) {
+			if(isconst(nl, CTSTR))
+				fatal("constant string constant index");	// front end should handle
+			v = mpgetfix(nr->val.u.xval);
+			if(isslice(nl->type) || nl->type->etype == TSTRING) {
+				if(!debug['B'] && !n->bounded) {
+					nodconst(&n2, types[simtype[TUINT]], v);
+					if(smallintconst(nr)) {
+						gins(optoas(OCMP, types[simtype[TUINT]]), &nlen, &n2);
+					} else {
+						regalloc(&tmp, types[simtype[TUINT]], N);
+						gmove(&n2, &tmp);
+						gins(optoas(OCMP, types[simtype[TUINT]]), &nlen, &tmp);
+						regfree(&tmp);
+					}
+					p1 = gbranch(optoas(OGT, types[simtype[TUINT]]), T, +1);
+					ginscall(panicindex, -1);
+					patch(p1, pc);
+				}
+				regfree(&nlen);
+			}
+
+			if (v*w != 0)
+				ginscon(optoas(OADD, types[tptr]), v*w, &n3);
+			*a = n3;
+			break;
+		}
+
+		// type of the index
+		t = types[TUINT64];
+		if(issigned[n1.type->etype])
+			t = types[TINT64];
+
+		regalloc(&n2, t, &n1);			// i
+		gmove(&n1, &n2);
+		regfree(&n1);
+
+		if(!debug['B'] && !n->bounded) {
+			// check bounds
+			t = types[simtype[TUINT]];
+			if(is64(nr->type))
+				t = types[TUINT64];
+			if(isconst(nl, CTSTR)) {
+				nodconst(&nlen, t, nl->val.u.sval->len);
+			} else if(isslice(nl->type) || nl->type->etype == TSTRING) {
+				if(is64(nr->type)) {
+					regalloc(&n5, t, N);
+					gmove(&nlen, &n5);
+					regfree(&nlen);
+					nlen = n5;
+				}
+			} else {
+				nodconst(&nlen, t, nl->type->bound);
+				if(!smallintconst(&nlen)) {
+					regalloc(&n5, t, N);
+					gmove(&nlen, &n5);
+					nlen = n5;
+					freelen = 1;
+				}
+			}
+			gins(optoas(OCMP, t), &n2, &nlen);
+			p1 = gbranch(optoas(OLT, t), T, +1);
+			ginscall(panicindex, -1);
+			patch(p1, pc);
+		}
+
+		if(isconst(nl, CTSTR)) {
+			regalloc(&n3, types[tptr], res);
+			p1 = gins(ALEAQ, N, &n3);
+			datastring(nl->val.u.sval->s, nl->val.u.sval->len, &p1->from);
+			gins(AADDQ, &n2, &n3);
+			goto indexdone;
+		}
+
+		if(w == 0) {
+			// nothing to do
+		} else if(w == 1 || w == 2 || w == 4 || w == 8) {
+			p1 = gins(ALEAQ, &n2, &n3);
+			p1->from.scale = w;
+			p1->from.index = p1->from.type;
+			p1->from.type = p1->to.type + D_INDIR;
+		} else {
+			ginscon(optoas(OMUL, t), w, &n2);
+			gins(optoas(OADD, types[tptr]), &n2, &n3);
+		}
+
+	indexdone:
+		*a = n3;
+		regfree(&n2);
+		if(freelen)
+			regfree(&nlen);
+		break;
+
+	default:
+		regalloc(a, types[tptr], res);
+		agen(n, a);
+		break;
+	}
+}
+
+/*
+ * generate:
+ *	res = &n;
+ * The generated code checks that the result is not nil.
+ */
+void
+agen(Node *n, Node *res)
+{
+	Node *nl, *nr;
+	Node n1, n2;
+
+	if(debug['g']) {
+		dump("\nagen-res", res);
+		dump("agen-r", n);
+	}
+	if(n == N || n->type == T)
+		return;
+
+	while(n->op == OCONVNOP)
+		n = n->left;
+
+	if(isconst(n, CTNIL) && n->type->width > widthptr) {
+		// Use of a nil interface or nil slice.
+		// Create a temporary we can take the address of and read.
+		// 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);
+		gmove(&n2, res);
+		regfree(&n2);
+		goto ret;
+	}
+		
+	if(n->addable) {
+		regalloc(&n1, types[tptr], res);
+		gins(ALEAQ, n, &n1);
+		gmove(&n1, res);
+		regfree(&n1);
+		goto ret;
+	}
+
+	nl = n->left;
+	nr = n->right;
+	USED(nr);
+
+	switch(n->op) {
+	default:
+		fatal("agen: unknown op %+hN", n);
+		break;
+
+	case OCALLMETH:
+		cgen_callmeth(n, 0);
+		cgen_aret(n, res);
+		break;
+
+	case OCALLINTER:
+		cgen_callinter(n, res, 0);
+		cgen_aret(n, res);
+		break;
+
+	case OCALLFUNC:
+		cgen_call(n, 0);
+		cgen_aret(n, res);
+		break;
+
+	case OSLICE:
+	case OSLICEARR:
+	case OSLICESTR:
+	case OSLICE3:
+	case OSLICE3ARR:
+		tempname(&n1, n->type);
+		cgen_slice(n, &n1);
+		agen(&n1, res);
+		break;
+
+	case OEFACE:
+		tempname(&n1, n->type);
+		cgen_eface(n, &n1);
+		agen(&n1, res);
+		break;
+
+	case OINDEX:
+		agenr(n, &n1, res);
+		gmove(&n1, res);
+		regfree(&n1);
+		break;
+
+	case ONAME:
+		// should only get here with names in this func.
+		if(n->funcdepth > 0 && n->funcdepth != funcdepth) {
+			dump("bad agen", n);
+			fatal("agen: bad ONAME funcdepth %d != %d",
+				n->funcdepth, funcdepth);
+		}
+
+		// should only get here for heap vars or paramref
+		if(!(n->class & PHEAP) && n->class != PPARAMREF) {
+			dump("bad agen", n);
+			fatal("agen: bad ONAME class %#x", n->class);
+		}
+		cgen(n->heapaddr, res);
+		if(n->xoffset != 0)
+			ginscon(optoas(OADD, types[tptr]), n->xoffset, res);
+		break;
+
+	case OIND:
+		cgen(nl, res);
+		cgen_checknil(res);
+		break;
+
+	case ODOT:
+		agen(nl, res);
+		if(n->xoffset != 0)
+			ginscon(optoas(OADD, types[tptr]), n->xoffset, res);
+		break;
+
+	case ODOTPTR:
+		cgen(nl, res);
+		cgen_checknil(res);
+		if(n->xoffset != 0)
+			ginscon(optoas(OADD, types[tptr]), n->xoffset, res);
+		break;
+	}
+
+ret:
+	;
+}
+
+/*
+ * generate:
+ *	newreg = &n;
+ *	res = newreg
+ *
+ * on exit, a has been changed to be *newreg.
+ * caller must regfree(a).
+ * The generated code checks that the result is not *nil.
+ */
+void
+igen(Node *n, Node *a, Node *res)
+{
+	Type *fp;
+	Iter flist;
+	Node n1;
+
+	if(debug['g']) {
+		dump("\nigen-n", n);
+	}
+	switch(n->op) {
+	case ONAME:
+		if((n->class&PHEAP) || n->class == PPARAMREF)
+			break;
+		*a = *n;
+		return;
+
+	case OINDREG:
+		// Increase the refcount of the register so that igen's caller
+		// has to call regfree.
+		if(n->val.u.reg != D_SP)
+			reg[n->val.u.reg]++;
+		*a = *n;
+		return;
+
+	case ODOT:
+		igen(n->left, a, res);
+		a->xoffset += n->xoffset;
+		a->type = n->type;
+		fixlargeoffset(a);
+		return;
+
+	case ODOTPTR:
+		cgenr(n->left, a, res);
+		cgen_checknil(a);
+		a->op = OINDREG;
+		a->xoffset += n->xoffset;
+		a->type = n->type;
+		fixlargeoffset(a);
+		return;
+
+	case OCALLFUNC:
+	case OCALLMETH:
+	case OCALLINTER:
+		switch(n->op) {
+		case OCALLFUNC:
+			cgen_call(n, 0);
+			break;
+		case OCALLMETH:
+			cgen_callmeth(n, 0);
+			break;
+		case OCALLINTER:
+			cgen_callinter(n, N, 0);
+			break;
+		}
+		fp = structfirst(&flist, getoutarg(n->left->type));
+		memset(a, 0, sizeof *a);
+		a->op = OINDREG;
+		a->val.u.reg = D_SP;
+		a->addable = 1;
+		a->xoffset = fp->width;
+		a->type = n->type;
+		return;
+
+	case OINDEX:
+		// Index of fixed-size array by constant can
+		// put the offset in the addressing.
+		// Could do the same for slice except that we need
+		// to use the real index for the bounds checking.
+		if(isfixedarray(n->left->type) ||
+		   (isptr[n->left->type->etype] && isfixedarray(n->left->left->type)))
+		if(isconst(n->right, CTINT)) {
+			// Compute &a.
+			if(!isptr[n->left->type->etype])
+				igen(n->left, a, res);
+			else {
+				igen(n->left, &n1, res);
+				cgen_checknil(&n1);
+				regalloc(a, types[tptr], res);
+				gmove(&n1, a);
+				regfree(&n1);
+				a->op = OINDREG;
+			}
+
+			// Compute &a[i] as &a + i*width.
+			a->type = n->type;
+			a->xoffset += mpgetfix(n->right->val.u.xval)*n->type->width;
+			fixlargeoffset(a);
+			return;
+		}
+		break;
+	}
+
+	agenr(n, a, res);
+	a->op = OINDREG;
+	a->type = n->type;
+}
+
+/*
+ * generate:
+ *	if(n == true) goto to;
+ */
+void
+bgen(Node *n, int true, int likely, Prog *to)
+{
+	int et, a;
+	Node *nl, *nr, *l, *r;
+	Node n1, n2, tmp;
+	NodeList *ll;
+	Prog *p1, *p2;
+
+	if(debug['g']) {
+		dump("\nbgen", n);
+	}
+
+	if(n == N)
+		n = nodbool(1);
+
+	if(n->ninit != nil)
+		genlist(n->ninit);
+
+	if(n->type == T) {
+		convlit(&n, types[TBOOL]);
+		if(n->type == T)
+			goto ret;
+	}
+
+	et = n->type->etype;
+	if(et != TBOOL) {
+		yyerror("cgen: bad type %T for %O", n->type, n->op);
+		patch(gins(AEND, N, N), to);
+		goto ret;
+	}
+	nr = N;
+
+	while(n->op == OCONVNOP) {
+		n = n->left;
+		if(n->ninit != nil)
+			genlist(n->ninit);
+	}
+
+	switch(n->op) {
+	default:
+	def:
+		regalloc(&n1, n->type, N);
+		cgen(n, &n1);
+		nodconst(&n2, n->type, 0);
+		gins(optoas(OCMP, n->type), &n1, &n2);
+		a = AJNE;
+		if(!true)
+			a = AJEQ;
+		patch(gbranch(a, n->type, likely), to);
+		regfree(&n1);
+		goto ret;
+
+	case OLITERAL:
+		// need to ask if it is bool?
+		if(!true == !n->val.u.bval)
+			patch(gbranch(AJMP, T, likely), to);
+		goto ret;
+
+	case ONAME:
+		if(n->addable == 0)
+			goto def;
+		nodconst(&n1, n->type, 0);
+		gins(optoas(OCMP, n->type), n, &n1);
+		a = AJNE;
+		if(!true)
+			a = AJEQ;
+		patch(gbranch(a, n->type, likely), to);
+		goto ret;
+
+	case OANDAND:
+		if(!true)
+			goto caseor;
+
+	caseand:
+		p1 = gbranch(AJMP, T, 0);
+		p2 = gbranch(AJMP, T, 0);
+		patch(p1, pc);
+		bgen(n->left, !true, -likely, p2);
+		bgen(n->right, !true, -likely, p2);
+		p1 = gbranch(AJMP, T, 0);
+		patch(p1, to);
+		patch(p2, pc);
+		goto ret;
+
+	case OOROR:
+		if(!true)
+			goto caseand;
+
+	caseor:
+		bgen(n->left, true, likely, to);
+		bgen(n->right, true, likely, to);
+		goto ret;
+
+	case OEQ:
+	case ONE:
+	case OLT:
+	case OGT:
+	case OLE:
+	case OGE:
+		nr = n->right;
+		if(nr == N || nr->type == T)
+			goto ret;
+
+	case ONOT:	// unary
+		nl = n->left;
+		if(nl == N || nl->type == T)
+			goto ret;
+		break;
+	}
+
+	switch(n->op) {
+
+	case ONOT:
+		bgen(nl, !true, likely, to);
+		goto ret;
+
+	case OEQ:
+	case ONE:
+	case OLT:
+	case OGT:
+	case OLE:
+	case OGE:
+		a = n->op;
+		if(!true) {
+			if(isfloat[nr->type->etype]) {
+				// brcom is not valid on floats when NaN is involved.
+				p1 = gbranch(AJMP, T, 0);
+				p2 = gbranch(AJMP, T, 0);
+				patch(p1, pc);
+				ll = n->ninit;   // avoid re-genning ninit
+				n->ninit = nil;
+				bgen(n, 1, -likely, p2);
+				n->ninit = ll;
+				patch(gbranch(AJMP, T, 0), to);
+				patch(p2, pc);
+				goto ret;
+			}				
+			a = brcom(a);
+			true = !true;
+		}
+
+		// make simplest on right
+		if(nl->op == OLITERAL || (nl->ullman < nr->ullman && nl->ullman < UINF)) {
+			a = brrev(a);
+			r = nl;
+			nl = nr;
+			nr = r;
+		}
+
+		if(isslice(nl->type)) {
+			// front end should only leave cmp to literal nil
+			if((a != OEQ && a != ONE) || nr->op != OLITERAL) {
+				yyerror("illegal slice comparison");
+				break;
+			}
+			a = optoas(a, types[tptr]);
+			igen(nl, &n1, N);
+			n1.xoffset += Array_array;
+			n1.type = types[tptr];
+			nodconst(&tmp, types[tptr], 0);
+			gins(optoas(OCMP, types[tptr]), &n1, &tmp);
+			patch(gbranch(a, types[tptr], likely), to);
+			regfree(&n1);
+			break;
+		}
+
+		if(isinter(nl->type)) {
+			// front end should only leave cmp to literal nil
+			if((a != OEQ && a != ONE) || nr->op != OLITERAL) {
+				yyerror("illegal interface comparison");
+				break;
+			}
+			a = optoas(a, types[tptr]);
+			igen(nl, &n1, N);
+			n1.type = types[tptr];
+			nodconst(&tmp, types[tptr], 0);
+			gins(optoas(OCMP, types[tptr]), &n1, &tmp);
+			patch(gbranch(a, types[tptr], likely), to);
+			regfree(&n1);
+			break;
+		}
+		if(iscomplex[nl->type->etype]) {
+			complexbool(a, nl, nr, true, likely, to);
+			break;
+		}
+
+		if(nr->ullman >= UINF) {
+			regalloc(&n1, nl->type, N);
+			cgen(nl, &n1);
+
+			tempname(&tmp, nl->type);
+			gmove(&n1, &tmp);
+			regfree(&n1);
+
+			regalloc(&n2, nr->type, N);
+			cgen(nr, &n2);
+
+			regalloc(&n1, nl->type, N);
+			cgen(&tmp, &n1);
+
+			goto cmp;
+		}
+
+		regalloc(&n1, nl->type, N);
+		cgen(nl, &n1);
+
+		if(smallintconst(nr)) {
+			gins(optoas(OCMP, nr->type), &n1, nr);
+			patch(gbranch(optoas(a, nr->type), nr->type, likely), to);
+			regfree(&n1);
+			break;
+		}
+
+		regalloc(&n2, nr->type, N);
+		cgen(nr, &n2);
+	cmp:
+		// only < and <= work right with NaN; reverse if needed
+		l = &n1;
+		r = &n2;
+		if(isfloat[nl->type->etype] && (a == OGT || a == OGE)) {
+			l = &n2;
+			r = &n1;
+			a = brrev(a);
+		}
+
+		gins(optoas(OCMP, nr->type), l, r);
+
+		if(isfloat[nr->type->etype] && (n->op == OEQ || n->op == ONE)) {
+			if(n->op == OEQ) {
+				// neither NE nor P
+				p1 = gbranch(AJNE, T, -likely);
+				p2 = gbranch(AJPS, T, -likely);
+				patch(gbranch(AJMP, T, 0), to);
+				patch(p1, pc);
+				patch(p2, pc);
+			} else {
+				// either NE or P
+				patch(gbranch(AJNE, T, likely), to);
+				patch(gbranch(AJPS, T, likely), to);
+			}
+		} else
+			patch(gbranch(optoas(a, nr->type), nr->type, likely), to);
+		regfree(&n1);
+		regfree(&n2);
+		break;
+	}
+	goto ret;
+
+ret:
+	;
+}
+
+/*
+ * n is on stack, either local variable
+ * or return value from function call.
+ * return n's offset from SP.
+ */
+int64
+stkof(Node *n)
+{
+	Type *t;
+	Iter flist;
+	int64 off;
+
+	switch(n->op) {
+	case OINDREG:
+		return n->xoffset;
+
+	case ODOT:
+		t = n->left->type;
+		if(isptr[t->etype])
+			break;
+		off = stkof(n->left);
+		if(off == -1000 || off == 1000)
+			return off;
+		return off + n->xoffset;
+
+	case OINDEX:
+		t = n->left->type;
+		if(!isfixedarray(t))
+			break;
+		off = stkof(n->left);
+		if(off == -1000 || off == 1000)
+			return off;
+		if(isconst(n->right, CTINT))
+			return off + t->type->width * mpgetfix(n->right->val.u.xval);
+		return 1000;
+		
+	case OCALLMETH:
+	case OCALLINTER:
+	case OCALLFUNC:
+		t = n->left->type;
+		if(isptr[t->etype])
+			t = t->type;
+
+		t = structfirst(&flist, getoutarg(t));
+		if(t != T)
+			return t->width;
+		break;
+	}
+
+	// botch - probably failing to recognize address
+	// arithmetic on the above. eg INDEX and DOT
+	return -1000;
+}
+
+/*
+ * block copy:
+ *	memmove(&ns, &n, w);
+ */
+void
+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);
+		dump("r", n);
+		dump("res", ns);
+	}
+
+	if(n->ullman >= UINF && ns->ullman >= UINF)
+		fatal("sgen UINF");
+
+	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))
+		return;
+	
+	if(w == 0) {
+		// evaluate side effects only
+		regalloc(&nodr, types[tptr], N);
+		agen(ns, &nodr);
+		agen(n, &nodr);
+		regfree(&nodr);
+		return;
+	}
+
+	// offset on the stack
+	osrc = stkof(n);
+	odst = stkof(ns);
+
+	if(osrc != -1000 && odst != -1000 && (osrc == 1000 || odst == 1000)) {
+		// osrc and odst both on stack, and at least one is in
+		// an unknown position.  Could generate code to test
+		// for forward/backward copy, but instead just copy
+		// to a temporary location first.
+		tempname(&tmp, n->type);
+		sgen(n, &tmp, w);
+		sgen(&tmp, ns, w);
+		return;
+	}
+
+	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);
+	gmove(&nodr, &nodsi);
+	regfree(&nodl);
+	regfree(&nodr);
+
+	c = w % 8;	// bytes
+	q = w / 8;	// quads
+
+	savex(D_CX, &cx, &oldcx, N, types[TINT64]);
+
+	// if we are copying forward on the stack and
+	// the src and dst overlap, then reverse direction
+	if(osrc < odst && odst < osrc+w) {
+		// reverse direction
+		gins(ASTD, N, N);		// set direction flag
+		if(c > 0) {
+			gconreg(addptr, w-1, D_SI);
+			gconreg(addptr, w-1, D_DI);
+
+			gconreg(movptr, c, D_CX);
+			gins(AREP, N, N);	// repeat
+			gins(AMOVSB, N, N);	// MOVB *(SI)-,*(DI)-
+		}
+
+		if(q > 0) {
+			if(c > 0) {
+				gconreg(addptr, -7, D_SI);
+				gconreg(addptr, -7, D_DI);
+			} else {
+				gconreg(addptr, w-8, D_SI);
+				gconreg(addptr, w-8, D_DI);
+			}
+			gconreg(movptr, q, D_CX);
+			gins(AREP, N, N);	// repeat
+			gins(AMOVSQ, N, N);	// MOVQ *(SI)-,*(DI)-
+		}
+		// we leave with the flag clear
+		gins(ACLD, N, N);
+	} else {
+		// normal direction
+		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 ../../runtime/asm_amd64.s
+			p->to.offset = 14*(128-q);
+		} else
+		while(q > 0) {
+			gins(AMOVSQ, N, N);	// MOVQ *(SI)+,*(DI)+
+			q--;
+		}
+		// 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);
+		}
+	}
+
+	restx(&cx, &oldcx);
+}
+
+static int
+cadable(Node *n)
+{
+	if(!n->addable) {
+		// dont know how it happens,
+		// but it does
+		return 0;
+	}
+
+	switch(n->op) {
+	case ONAME:
+		return 1;
+	}
+	return 0;
+}
+
+/*
+ * copy a composite value by moving its individual components.
+ * Slices, strings and interfaces are supported.
+ * Small structs or arrays with elements of basic type are
+ * also supported.
+ * nr is N when assigning a zero value.
+ * return 1 if can do, 0 if can't.
+ */
+int
+componentgen(Node *nr, Node *nl)
+{
+	Node nodl, nodr;
+	Type *t;
+	int freel, freer;
+	vlong fldcount;
+	vlong loffset, roffset;
+
+	freel = 0;
+	freer = 0;
+
+	switch(nl->type->etype) {
+	default:
+		goto no;
+
+	case TARRAY:
+		t = nl->type;
+
+		// Slices are ok.
+		if(isslice(t))
+			break;
+		// Small arrays are ok.
+		if(t->bound > 0 && t->bound <= 3 && !isfat(t->type))
+			break;
+
+		goto no;
+
+	case TSTRUCT:
+		// Small structs with non-fat types are ok.
+		// Zero-sized structs are treated separately elsewhere.
+		fldcount = 0;
+		for(t=nl->type->type; t; t=t->down) {
+			if(isfat(t->type))
+				goto no;
+			if(t->etype != TFIELD)
+				fatal("componentgen: not a TFIELD: %lT", t);
+			fldcount++;
+		}
+		if(fldcount == 0 || fldcount > 4)
+			goto no;
+
+		break;
+
+	case TSTRING:
+	case TINTER:
+		break;
+	}
+
+	nodl = *nl;
+	if(!cadable(nl)) {
+		if(nr == N || !cadable(nr))
+			goto no;
+		igen(nl, &nodl, N);
+		freel = 1;
+	}
+
+	if(nr != N) {
+		nodr = *nr;
+		if(!cadable(nr)) {
+			igen(nr, &nodr, N);
+			freer = 1;
+		}
+	}
+	
+	// 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;
+			nodr.type = nodl.type;
+			for(fldcount=0; fldcount < t->bound; fldcount++) {
+				if(nr == N)
+					clearslim(&nodl);
+				else
+					gmove(&nodr, &nodl);
+				nodl.xoffset += t->type->width;
+				nodr.xoffset += t->type->width;
+			}
+			goto yes;
+		}
+
+		// componentgen for slices.
+		nodl.xoffset += Array_array;
+		nodl.type = ptrto(nl->type->type);
+
+		if(nr != N) {
+			nodr.xoffset += Array_array;
+			nodr.type = nodl.type;
+		} else
+			nodconst(&nodr, nodl.type, 0);
+		gmove(&nodr, &nodl);
+
+		nodl.xoffset += Array_nel-Array_array;
+		nodl.type = types[simtype[TUINT]];
+
+		if(nr != N) {
+			nodr.xoffset += Array_nel-Array_array;
+			nodr.type = nodl.type;
+		} else
+			nodconst(&nodr, nodl.type, 0);
+		gmove(&nodr, &nodl);
+
+		nodl.xoffset += Array_cap-Array_nel;
+		nodl.type = types[simtype[TUINT]];
+
+		if(nr != N) {
+			nodr.xoffset += Array_cap-Array_nel;
+			nodr.type = nodl.type;
+		} else
+			nodconst(&nodr, nodl.type, 0);
+		gmove(&nodr, &nodl);
+
+		goto yes;
+
+	case TSTRING:
+		if(nl->op == ONAME)
+			gvardef(nl);
+		nodl.xoffset += Array_array;
+		nodl.type = ptrto(types[TUINT8]);
+
+		if(nr != N) {
+			nodr.xoffset += Array_array;
+			nodr.type = nodl.type;
+		} else
+			nodconst(&nodr, nodl.type, 0);
+		gmove(&nodr, &nodl);
+
+		nodl.xoffset += Array_nel-Array_array;
+		nodl.type = types[simtype[TUINT]];
+
+		if(nr != N) {
+			nodr.xoffset += Array_nel-Array_array;
+			nodr.type = nodl.type;
+		} else
+			nodconst(&nodr, nodl.type, 0);
+		gmove(&nodr, &nodl);
+
+		goto yes;
+
+	case TINTER:
+		if(nl->op == ONAME)
+			gvardef(nl);
+		nodl.xoffset += Array_array;
+		nodl.type = ptrto(types[TUINT8]);
+
+		if(nr != N) {
+			nodr.xoffset += Array_array;
+			nodr.type = nodl.type;
+		} else
+			nodconst(&nodr, nodl.type, 0);
+		gmove(&nodr, &nodl);
+
+		nodl.xoffset += Array_nel-Array_array;
+		nodl.type = ptrto(types[TUINT8]);
+
+		if(nr != N) {
+			nodr.xoffset += Array_nel-Array_array;
+			nodr.type = nodl.type;
+		} else
+			nodconst(&nodr, nodl.type, 0);
+		gmove(&nodr, &nodl);
+
+		goto yes;
+
+	case TSTRUCT:
+		if(nl->op == ONAME)
+			gvardef(nl);
+		loffset = nodl.xoffset;
+		roffset = nodr.xoffset;
+		// funarg structs may not begin at offset zero.
+		if(nl->type->etype == TSTRUCT && nl->type->funarg && nl->type->type)
+			loffset -= nl->type->type->width;
+		if(nr != N && nr->type->etype == TSTRUCT && nr->type->funarg && nr->type->type)
+			roffset -= nr->type->type->width;
+
+		for(t=nl->type->type; t; t=t->down) {
+			nodl.xoffset = loffset + t->width;
+			nodl.type = t->type;
+
+			if(nr == N)
+				clearslim(&nodl);
+			else {
+				nodr.xoffset = roffset + t->width;
+				nodr.type = nodl.type;
+				gmove(&nodr, &nodl);
+			}
+		}
+		goto yes;
+	}
+
+no:
+	if(freer)
+		regfree(&nodr);
+	if(freel)
+		regfree(&nodl);
+	return 0;
+
+yes:
+	if(freer)
+		regfree(&nodr);
+	if(freel)
+		regfree(&nodl);
+	return 1;
+}
diff --git a/src/cmd/6g/doc.go b/src/cmd/6g/doc.go
new file mode 100644
index 0000000..07b2818
--- /dev/null
+++ b/src/cmd/6g/doc.go
@@ -0,0 +1,15 @@
+// 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
+
+/*
+
+6g is the version of the gc compiler for the x86-64.
+The $GOARCH for these tools is amd64.
+
+It reads .go files and outputs .6 files. The flags are documented in ../gc/doc.go.
+
+*/
+package main
diff --git a/src/cmd/6g/galign.c b/src/cmd/6g/galign.c
new file mode 100644
index 0000000..5670e6f
--- /dev/null
+++ b/src/cmd/6g/galign.c
@@ -0,0 +1,66 @@
+// 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 "gg.h"
+
+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
+ */
+Typedef	typedefs[] =
+{
+	{"int",		TINT,		TINT64},
+	{"uint",		TUINT,		TUINT64},
+	{"uintptr",	TUINTPTR,	TUINT64},
+	{0}
+};
+
+void
+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;
+	zprog.from.type = D_NONE;
+	zprog.from.index = D_NONE;
+	zprog.from.scale = 0;
+	zprog.to = zprog.from;
+
+	listinit6();
+}
diff --git a/src/cmd/6g/gg.h b/src/cmd/6g/gg.h
new file mode 100644
index 0000000..fe69d5c
--- /dev/null
+++ b/src/cmd/6g/gg.h
@@ -0,0 +1,122 @@
+// 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.
+
+#ifndef	EXTERN
+#define	EXTERN	extern
+#endif
+
+#include "../gc/go.h"
+#include "../6l/6.out.h"
+
+#define TEXTFLAG from.scale
+
+EXTERN	int32	dynloc;
+EXTERN	uchar	reg[D_NONE];
+EXTERN	int32	pcloc;		// instruction counter
+EXTERN	Strlit	emptystring;
+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
+ */
+void	compile(Node*);
+void	gen(Node*);
+Node*	lookdot(Node*, Node*, int);
+void	cgen_as(Node*, Node*);
+void	cgen_callmeth(Node*, int);
+void	cgen_callinter(Node*, Node*, int);
+void	cgen_proc(Node*, int);
+void	cgen_callret(Node*, Node*);
+void	cgen_div(int, Node*, Node*, Node*);
+void	cgen_bmul(int, Node*, Node*, Node*);
+void	cgen_hmul(Node*, Node*, Node*);
+void	cgen_shift(int, int, Node*, Node*, Node*);
+void	cgen_dcl(Node*);
+int	needconvert(Type*, Type*);
+void	genconv(Type*, Type*);
+void	allocparams(void);
+void	checklabels(void);
+void	ginscall(Node*, int);
+int	gen_as_init(Node*);
+
+/*
+ * cgen.c
+ */
+void	agen(Node*, Node*);
+void	agenr(Node*, Node*, Node*);
+void	cgenr(Node*, Node*, Node*);
+void	igen(Node*, Node*, Node*);
+vlong	fieldoffset(Type*, Node*);
+void	sgen(Node*, Node*, int64);
+void	gmove(Node*, Node*);
+Prog*	gins(int, Node*, Node*);
+int	samaddr(Node*, Node*);
+void	naddr(Node*, Addr*, int);
+void	cgen_aret(Node*, Node*);
+void	restx(Node*, Node*);
+void	savex(int, Node*, Node*, Node*, Type*);
+int	componentgen(Node*, Node*);
+
+/*
+ * gsubr.c
+ */
+void	clearp(Prog*);
+Prog*	gbranch(int, Type*, int);
+Prog*	prog(int);
+void	gconv(int, int);
+int	conv2pt(Type*);
+vlong	convvtox(vlong, int);
+void	fnparam(Type*, int, int);
+Prog*	gop(int, Node*, Node*, Node*);
+int	optoas(int, Type*);
+void	ginit(void);
+void	gclean(void);
+void	regalloc(Node*, Type*, Node*);
+void	regfree(Node*);
+Node*	nodarg(Type*, int);
+void	nodreg(Node*, Type*, int);
+void	nodindreg(Node*, Type*, int);
+void	gconreg(int, vlong, int);
+void	ginscon(int, vlong, Node*);
+void	buildtxt(void);
+Plist*	newplist(void);
+int	isfat(Type*);
+void	sudoclean(void);
+int	sudoaddable(int, Node*, Addr*);
+void	afunclit(Addr*, Node*);
+void	nodfconst(Node*, Type*, Mpflt*);
+void	gtrack(Sym*);
+void	fixlargeoffset(Node *n);
+
+/*
+ * cplx.c
+ */
+int	complexop(Node*, Node*);
+void	complexmove(Node*, Node*);
+void	complexgen(Node*, Node*);
+
+/*
+ * gobj.c
+ */
+void	datastring(char*, int, Addr*);
+void	datagostring(Strlit*, Addr*);
+
+/*
+ * list.c
+ */
+void	listinit(void);
+
+void	zaddr(Biobuf*, Addr*, int, int);
diff --git a/src/cmd/6g/ggen.c b/src/cmd/6g/ggen.c
new file mode 100644
index 0000000..3636207
--- /dev/null
+++ b/src/cmd/6g/ggen.c
@@ -0,0 +1,1228 @@
+// 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.
+
+#undef	EXTERN
+#define	EXTERN
+#include <u.h>
+#include <libc.h>
+#include "gg.h"
+#include "opt.h"
+
+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)
+{
+	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, widthreg);
+	ptxt->to.offset |= frame;
+	
+	// insert code to zero ambiguously live variables
+	// so that the garbage collector only sees initialized values
+	// when it looks for pointers.
+	p = ptxt;
+	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*
+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;	
+}
+
+// Sweep the prog list to mark any used nodes.
+void
+markautoused(Prog* p)
+{
+	for (; p; p = p->link) {
+		if (p->as == ATYPE || p->as == AVARDEF || p->as == AVARKILL)
+			continue;
+
+		if (p->from.node)
+			p->from.node->used = 1;
+
+		if (p->to.node)
+			p->to.node->used = 1;
+	}
+}
+
+// Fixup instructions after allocauto (formerly compactframe) has moved all autos around.
+void
+fixautoused(Prog *p)
+{
+	Prog **lp;
+
+	for (lp=&p; (p=*lp) != P; ) {
+		if (p->as == ATYPE && p->from.node && p->from.type == D_AUTO && !p->from.node->used) {
+			*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;
+
+		if (p->to.type == D_AUTO && p->to.node)
+			p->to.offset += p->to.node->stkdelta;
+
+		lp = &p->link;
+	}
+}
+
+
+/*
+ * generate:
+ *	call f
+ *	proc=-1	normal call but no return
+ *	proc=0	normal call
+ *	proc=1	goroutine run in new proc
+ *	proc=2	defer call save away stack
+  *	proc=3	normal call to C pointer (not Go func value)
+ */
+void
+ginscall(Node *f, int proc)
+{
+	Prog *p;
+	Node reg, con;
+	Node r1;
+
+	if(f->type != T)
+		setmaxarg(f->type);
+
+	switch(proc) {
+	default:
+		fatal("ginscall: bad proc %d", proc);
+		break;
+
+	case 0:	// normal call
+	case -1:	// normal call but no return
+		if(f->op == ONAME && f->class == PFUNC) {
+			if(f == deferreturn) {
+				// Deferred calls will appear to be returning to
+				// the CALL deferreturn(SB) that we are about to emit.
+				// However, the stack trace code will show the line
+				// of the instruction byte before the return PC. 
+				// To avoid that being an unrelated instruction,
+				// insert an x86 NOP that we will have the right line number.
+				// x86 NOP 0x90 is really XCHG AX, AX; use that description
+				// because the NOP pseudo-instruction would be removed by
+				// the linker.
+				nodreg(&reg, types[TINT], D_AX);
+				gins(AXCHGL, &reg, &reg);
+			}
+			p = gins(ACALL, N, f);
+			afunclit(&p->to, f);
+			if(proc == -1 || noreturn(p))
+				gins(AUNDEF, N, N);
+			break;
+		}
+		nodreg(&reg, types[tptr], D_DX);
+		nodreg(&r1, types[tptr], D_BX);
+		gmove(f, &reg);
+		reg.op = OINDREG;
+		gmove(&reg, &r1);
+		reg.op = OREGISTER;
+		gins(ACALL, &reg, &r1);
+		break;
+	
+	case 3:	// normal call of c function pointer
+		gins(ACALL, N, f);
+		break;
+
+	case 1:	// call in new proc (go)
+	case 2:	// deferred call (defer)
+		nodconst(&con, types[TINT64], argsize(f->type));
+		if(widthptr == 4) {
+			nodreg(&r1, types[TINT32], D_CX);
+			gmove(f, &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 {
+			nodreg(&reg, types[TINT64], D_CX);
+			gmove(f, &reg);
+			gins(APUSHQ, &reg, N);
+			gins(APUSHQ, &con, N);
+		}
+		if(proc == 1)
+			ginscall(newproc, 0);
+		else {
+			if(!hasdefer)
+				fatal("hasdefer=0 but has defer");
+			ginscall(deferproc, 0);
+		}
+		nodreg(&reg, types[TINT64], D_CX);
+		gins(APOPQ, N, &reg);
+		if(widthptr == 8)
+			gins(APOPQ, N, &reg);
+		if(proc == 2) {
+			nodreg(&reg, types[TINT64], D_AX);
+			gins(ATESTQ, &reg, &reg);
+			p = gbranch(AJEQ, T, +1);
+			cgen_ret(N);
+			patch(p, pc);
+		}
+		break;
+	}
+}
+
+/*
+ * n is call to interface method.
+ * generate res = n.
+ */
+void
+cgen_callinter(Node *n, Node *res, int proc)
+{
+	Node *i, *f;
+	Node tmpi, nodi, nodo, nodr, nodsp;
+
+	i = n->left;
+	if(i->op != ODOTINTER)
+		fatal("cgen_callinter: not ODOTINTER %O", i->op);
+
+	f = i->right;		// field
+	if(f->op != ONAME)
+		fatal("cgen_callinter: not ONAME %O", f->op);
+
+	i = i->left;		// interface
+
+	if(!i->addable) {
+		tempname(&tmpi, i->type);
+		cgen(i, &tmpi);
+		i = &tmpi;
+	}
+
+	genlist(n->list);		// assign the args
+
+	// i is now addable, prepare an indirected
+	// register to hold its address.
+	igen(i, &nodi, res);		// REG = &inter
+
+	nodindreg(&nodsp, types[tptr], D_SP);
+	nodi.type = types[tptr];
+	nodi.xoffset += widthptr;
+	cgen(&nodi, &nodsp);	// 0(SP) = 8(REG) -- i.data
+
+	regalloc(&nodo, types[tptr], res);
+	nodi.type = types[tptr];
+	nodi.xoffset -= widthptr;
+	cgen(&nodi, &nodo);	// REG = 0(REG) -- i.tab
+	regfree(&nodi);
+
+	regalloc(&nodr, types[tptr], &nodo);
+	if(n->left->xoffset == BADWIDTH)
+		fatal("cgen_callinter: badwidth");
+	cgen_checknil(&nodo); // in case offset is huge
+	nodo.op = OINDREG;
+	nodo.xoffset = n->left->xoffset + 3*widthptr + 8;
+	if(proc == 0) {
+		// plain call: use direct c function pointer - more efficient
+		cgen(&nodo, &nodr);	// REG = 32+offset(REG) -- i.tab->fun[f]
+		proc = 3;
+	} else {
+		// go/defer. generate go func value.
+		gins(ALEAQ, &nodo, &nodr);	// REG = &(32+offset(REG)) -- i.tab->fun[f]
+	}
+
+	nodr.type = n->left->type;
+	ginscall(&nodr, proc);
+
+	regfree(&nodr);
+	regfree(&nodo);
+}
+
+/*
+ * generate function call;
+ *	proc=0	normal call
+ *	proc=1	goroutine run in new proc
+ *	proc=2	defer call save away stack
+ */
+void
+cgen_call(Node *n, int proc)
+{
+	Type *t;
+	Node nod, afun;
+
+	if(n == N)
+		return;
+
+	if(n->left->ullman >= UINF) {
+		// if name involves a fn call
+		// precompute the address of the fn
+		tempname(&afun, types[tptr]);
+		cgen(n->left, &afun);
+	}
+
+	genlist(n->list);		// assign the args
+	t = n->left->type;
+
+	// call tempname pointer
+	if(n->left->ullman >= UINF) {
+		regalloc(&nod, types[tptr], N);
+		cgen_as(&nod, &afun);
+		nod.type = t;
+		ginscall(&nod, proc);
+		regfree(&nod);
+		return;
+	}
+
+	// call pointer
+	if(n->left->op != ONAME || n->left->class != PFUNC) {
+		regalloc(&nod, types[tptr], N);
+		cgen_as(&nod, n->left);
+		nod.type = t;
+		ginscall(&nod, proc);
+		regfree(&nod);
+		return;
+	}
+
+	// call direct
+	n->left->method = 1;
+	ginscall(n->left, proc);
+}
+
+/*
+ * call to n has already been generated.
+ * generate:
+ *	res = return value from call.
+ */
+void
+cgen_callret(Node *n, Node *res)
+{
+	Node nod;
+	Type *fp, *t;
+	Iter flist;
+
+	t = n->left->type;
+	if(t->etype == TPTR32 || t->etype == TPTR64)
+		t = t->type;
+
+	fp = structfirst(&flist, getoutarg(t));
+	if(fp == T)
+		fatal("cgen_callret: nil");
+
+	memset(&nod, 0, sizeof(nod));
+	nod.op = OINDREG;
+	nod.val.u.reg = D_SP;
+	nod.addable = 1;
+
+	nod.xoffset = fp->width;
+	nod.type = fp->type;
+	cgen_as(res, &nod);
+}
+
+/*
+ * call to n has already been generated.
+ * generate:
+ *	res = &return value from call.
+ */
+void
+cgen_aret(Node *n, Node *res)
+{
+	Node nod1, nod2;
+	Type *fp, *t;
+	Iter flist;
+
+	t = n->left->type;
+	if(isptr[t->etype])
+		t = t->type;
+
+	fp = structfirst(&flist, getoutarg(t));
+	if(fp == T)
+		fatal("cgen_aret: nil");
+
+	memset(&nod1, 0, sizeof(nod1));
+	nod1.op = OINDREG;
+	nod1.val.u.reg = D_SP;
+	nod1.addable = 1;
+
+	nod1.xoffset = fp->width;
+	nod1.type = fp->type;
+
+	if(res->op != OREGISTER) {
+		regalloc(&nod2, types[tptr], res);
+		gins(leaptr, &nod1, &nod2);
+		gins(movptr, &nod2, res);
+		regfree(&nod2);
+	} else
+		gins(leaptr, &nod1, res);
+}
+
+/*
+ * generate return.
+ * n->left is assignments to return values.
+ */
+void
+cgen_ret(Node *n)
+{
+	Prog *p;
+
+	if(n != N)
+		genlist(n->list);		// copy out args
+	if(hasdefer)
+		ginscall(deferreturn, 0);
+	genlist(curfn->exit);
+	p = gins(ARET, N, N);
+	if(n != N && n->op == ORETJMP) {
+		p->to.type = D_EXTERN;
+		p->to.sym = linksym(n->left->sym);
+	}
+}
+
+/*
+ * generate += *= etc.
+ */
+void
+cgen_asop(Node *n)
+{
+	Node n1, n2, n3, n4;
+	Node *nl, *nr;
+	Prog *p1;
+	Addr addr;
+	int a;
+
+	nl = n->left;
+	nr = n->right;
+
+	if(nr->ullman >= UINF && nl->ullman >= UINF) {
+		tempname(&n1, nr->type);
+		cgen(nr, &n1);
+		n2 = *n;
+		n2.right = &n1;
+		cgen_asop(&n2);
+		goto ret;
+	}
+
+	if(!isint[nl->type->etype])
+		goto hard;
+	if(!isint[nr->type->etype])
+		goto hard;
+
+	switch(n->etype) {
+	case OADD:
+		if(smallintconst(nr))
+		if(mpgetfix(nr->val.u.xval) == 1) {
+			a = optoas(OINC, nl->type);
+			if(nl->addable) {
+				gins(a, N, nl);
+				goto ret;
+			}
+			if(sudoaddable(a, nl, &addr)) {
+				p1 = gins(a, N, N);
+				p1->to = addr;
+				sudoclean();
+				goto ret;
+			}
+		}
+		break;
+
+	case OSUB:
+		if(smallintconst(nr))
+		if(mpgetfix(nr->val.u.xval) == 1) {
+			a = optoas(ODEC, nl->type);
+			if(nl->addable) {
+				gins(a, N, nl);
+				goto ret;
+			}
+			if(sudoaddable(a, nl, &addr)) {
+				p1 = gins(a, N, N);
+				p1->to = addr;
+				sudoclean();
+				goto ret;
+			}
+		}
+		break;
+	}
+
+	switch(n->etype) {
+	case OADD:
+	case OSUB:
+	case OXOR:
+	case OAND:
+	case OOR:
+		a = optoas(n->etype, nl->type);
+		if(nl->addable) {
+			if(smallintconst(nr)) {
+				gins(a, nr, nl);
+				goto ret;
+			}
+			regalloc(&n2, nr->type, N);
+			cgen(nr, &n2);
+			gins(a, &n2, nl);
+			regfree(&n2);
+			goto ret;
+		}
+		if(nr->ullman < UINF)
+		if(sudoaddable(a, nl, &addr)) {
+			if(smallintconst(nr)) {
+				p1 = gins(a, nr, N);
+				p1->to = addr;
+				sudoclean();
+				goto ret;
+			}
+			regalloc(&n2, nr->type, N);
+			cgen(nr, &n2);
+			p1 = gins(a, &n2, N);
+			p1->to = addr;
+			regfree(&n2);
+			sudoclean();
+			goto ret;
+		}
+	}
+
+hard:
+	n2.op = 0;
+	n1.op = 0;
+	if(nr->op == OLITERAL) {
+		// don't allocate a register for literals.
+	} else if(nr->ullman >= nl->ullman || nl->addable) {
+		regalloc(&n2, nr->type, N);
+		cgen(nr, &n2);
+		nr = &n2;
+	} else {
+		tempname(&n2, nr->type);
+		cgen(nr, &n2);
+		nr = &n2;
+	}
+	if(!nl->addable) {
+		igen(nl, &n1, N);
+		nl = &n1;
+	}
+
+	n3 = *n;
+	n3.left = nl;
+	n3.right = nr;
+	n3.op = n->etype;
+
+	regalloc(&n4, nl->type, N);
+	cgen(&n3, &n4);
+	gmove(&n4, nl);
+
+	if(n1.op)
+		regfree(&n1);
+	if(n2.op == OREGISTER)
+		regfree(&n2);
+	regfree(&n4);
+
+ret:
+	;
+}
+
+int
+samereg(Node *a, Node *b)
+{
+	if(a == N || b == N)
+		return 0;
+	if(a->op != OREGISTER)
+		return 0;
+	if(b->op != OREGISTER)
+		return 0;
+	if(a->val.u.reg != b->val.u.reg)
+		return 0;
+	return 1;
+}
+
+/*
+ * generate division.
+ * generates one of:
+ *	res = nl / nr
+ *	res = nl % nr
+ * according to op.
+ */
+void
+dodiv(int op, Node *nl, Node *nr, Node *res)
+{
+	int a, check;
+	Node n3, n4;
+	Type *t, *t0;
+	Node ax, dx, ax1, n31, oldax, olddx;
+	Prog *p1, *p2;
+
+	// Have to be careful about handling
+	// most negative int divided by -1 correctly.
+	// The hardware will trap.
+	// Also the byte divide instruction needs AH,
+	// which we otherwise don't have to deal with.
+	// Easiest way to avoid for int8, int16: use int32.
+	// For int32 and int64, use explicit test.
+	// Could use int64 hw for int32.
+	t = nl->type;
+	t0 = t;
+	check = 0;
+	if(issigned[t->etype]) {
+		check = 1;
+		if(isconst(nl, CTINT) && mpgetfix(nl->val.u.xval) != -(1ULL<<(t->width*8-1)))
+			check = 0;
+		else if(isconst(nr, CTINT) && mpgetfix(nr->val.u.xval) != -1)
+			check = 0;
+	}
+	if(t->width < 4) {
+		if(issigned[t->etype])
+			t = types[TINT32];
+		else
+			t = types[TUINT32];
+		check = 0;
+	}
+	a = optoas(op, t);
+
+	regalloc(&n3, t0, N);
+	if(nl->ullman >= nr->ullman) {
+		savex(D_AX, &ax, &oldax, res, t0);
+		cgen(nl, &ax);
+		regalloc(&ax, t0, &ax);	// mark ax live during cgen
+		cgen(nr, &n3);
+		regfree(&ax);
+	} else {
+		cgen(nr, &n3);
+		savex(D_AX, &ax, &oldax, res, t0);
+		cgen(nl, &ax);
+	}
+	if(t != t0) {
+		// Convert
+		ax1 = ax;
+		n31 = n3;
+		ax.type = t;
+		n3.type = t;
+		gmove(&ax1, &ax);
+		gmove(&n31, &n3);
+	}
+
+	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);
+		p1 = gbranch(optoas(ONE, t), T, +1);
+		if(op == ODIV) {
+			// a / (-1) is -a.
+			gins(optoas(OMINUS, t), N, &ax);
+			gmove(&ax, res);
+		} else {
+			// a % (-1) is 0.
+			nodconst(&n4, t, 0);
+			gmove(&n4, res);
+		}
+		p2 = gbranch(AJMP, T, 0);
+		patch(p1, pc);
+	}
+	savex(D_DX, &dx, &olddx, res, t);
+	if(!issigned[t->etype]) {
+		nodconst(&n4, t, 0);
+		gmove(&n4, &dx);
+	} else
+		gins(optoas(OEXTEND, t), N, N);
+	gins(a, &n3, N);
+	regfree(&n3);
+	if(op == ODIV)
+		gmove(&ax, res);
+	else
+		gmove(&dx, res);
+	restx(&dx, &olddx);
+	if(check)
+		patch(p2, pc);
+	restx(&ax, &oldax);
+}
+
+/*
+ * register dr is one of the special ones (AX, CX, DI, SI, etc.).
+ * we need to use it.  if it is already allocated as a temporary
+ * (r > 1; can only happen if a routine like sgen passed a
+ * special as cgen's res and then cgen used regalloc to reuse
+ * it as its own temporary), then move it for now to another
+ * register.  caller must call restx to move it back.
+ * the move is not necessary if dr == res, because res is
+ * known to be dead.
+ */
+void
+savex(int dr, Node *x, Node *oldx, Node *res, Type *t)
+{
+	int r;
+
+	r = reg[dr];
+
+	// save current ax and dx if they are live
+	// and not the destination
+	memset(oldx, 0, sizeof *oldx);
+	nodreg(x, t, dr);
+	if(r > 1 && !samereg(x, res)) {
+		regalloc(oldx, types[TINT64], N);
+		x->type = types[TINT64];
+		gmove(x, oldx);
+		x->type = t;
+		oldx->ostk = r;	// squirrel away old r value
+		reg[dr] = 1;
+	}
+}
+
+void
+restx(Node *x, Node *oldx)
+{
+	if(oldx->op != 0) {
+		x->type = types[TINT64];
+		reg[x->val.u.reg] = oldx->ostk;
+		gmove(oldx, x);
+		regfree(oldx);
+	}
+}
+
+/*
+ * generate division according to op, one of:
+ *	res = nl / nr
+ *	res = nl % nr
+ */
+void
+cgen_div(int op, Node *nl, Node *nr, Node *res)
+{
+	Node n1, n2, n3;
+	int w, a;
+	Magic m;
+
+	if(nr->op != OLITERAL)
+		goto longdiv;
+	w = nl->type->width*8;
+
+	// Front end handled 32-bit division. We only need to handle 64-bit.
+	// try to do division by multiply by (2^w)/d
+	// see hacker's delight chapter 10
+	switch(simtype[nl->type->etype]) {
+	default:
+		goto longdiv;
+
+	case TUINT64:
+		m.w = w;
+		m.ud = mpgetfix(nr->val.u.xval);
+		umagic(&m);
+		if(m.bad)
+			break;
+		if(op == OMOD)
+			goto longmod;
+
+		cgenr(nl, &n1, N);
+		nodconst(&n2, nl->type, m.um);
+		regalloc(&n3, nl->type, res);
+		cgen_hmul(&n1, &n2, &n3);
+
+		if(m.ua) {
+			// need to add numerator accounting for overflow
+			gins(optoas(OADD, nl->type), &n1, &n3);
+			nodconst(&n2, nl->type, 1);
+			gins(optoas(ORROTC, nl->type), &n2, &n3);
+			nodconst(&n2, nl->type, m.s-1);
+			gins(optoas(ORSH, nl->type), &n2, &n3);
+		} else {
+			nodconst(&n2, nl->type, m.s);
+			gins(optoas(ORSH, nl->type), &n2, &n3);	// shift dx
+		}
+
+		gmove(&n3, res);
+		regfree(&n1);
+		regfree(&n3);
+		return;
+
+	case TINT64:
+		m.w = w;
+		m.sd = mpgetfix(nr->val.u.xval);
+		smagic(&m);
+		if(m.bad)
+			break;
+		if(op == OMOD)
+			goto longmod;
+
+		cgenr(nl, &n1, res);
+		nodconst(&n2, nl->type, m.sm);
+		regalloc(&n3, nl->type, N);
+		cgen_hmul(&n1, &n2, &n3);
+
+		if(m.sm < 0) {
+			// need to add numerator
+			gins(optoas(OADD, nl->type), &n1, &n3);
+		}
+
+		nodconst(&n2, nl->type, m.s);
+		gins(optoas(ORSH, nl->type), &n2, &n3);	// shift n3
+
+		nodconst(&n2, nl->type, w-1);
+		gins(optoas(ORSH, nl->type), &n2, &n1);	// -1 iff num is neg
+		gins(optoas(OSUB, nl->type), &n1, &n3);	// added
+
+		if(m.sd < 0) {
+			// this could probably be removed
+			// by factoring it into the multiplier
+			gins(optoas(OMINUS, nl->type), N, &n3);
+		}
+
+		gmove(&n3, res);
+		regfree(&n1);
+		regfree(&n3);
+		return;
+	}
+	goto longdiv;
+
+longdiv:
+	// division and mod using (slow) hardware instruction
+	dodiv(op, nl, nr, res);
+	return;
+
+longmod:
+	// mod using formula A%B = A-(A/B*B) but
+	// we know that there is a fast algorithm for A/B
+	regalloc(&n1, nl->type, res);
+	cgen(nl, &n1);
+	regalloc(&n2, nl->type, N);
+	cgen_div(ODIV, &n1, nr, &n2);
+	a = optoas(OMUL, nl->type);
+	if(w == 8) {
+		// use 2-operand 16-bit multiply
+		// because there is no 2-operand 8-bit multiply
+		a = AIMULW;
+	}
+	if(!smallintconst(nr)) {
+		regalloc(&n3, nl->type, N);
+		cgen(nr, &n3);
+		gins(a, &n3, &n2);
+		regfree(&n3);
+	} else
+		gins(a, nr, &n2);
+	gins(optoas(OSUB, nl->type), &n2, &n1);
+	gmove(&n1, res);
+	regfree(&n1);
+	regfree(&n2);
+}
+
+/*
+ * generate high multiply:
+ *   res = (nl*nr) >> width
+ */
+void
+cgen_hmul(Node *nl, Node *nr, Node *res)
+{
+	Type *t;
+	int a;
+	Node n1, n2, ax, dx, *tmp;
+
+	t = nl->type;
+	a = optoas(OHMUL, t);
+	if(nl->ullman < nr->ullman) {
+		tmp = nl;
+		nl = nr;
+		nr = tmp;
+	}
+	cgenr(nl, &n1, res);
+	cgenr(nr, &n2, N);
+	nodreg(&ax, t, D_AX);
+	gmove(&n1, &ax);
+	gins(a, &n2, N);
+	regfree(&n2);
+	regfree(&n1);
+
+	if(t->width == 1) {
+		// byte multiply behaves differently.
+		nodreg(&ax, t, D_AH);
+		nodreg(&dx, t, D_DX);
+		gmove(&ax, &dx);
+	}
+	nodreg(&dx, t, D_DX);
+	gmove(&dx, res);
+}
+
+/*
+ * generate shift according to op, one of:
+ *	res = nl << nr
+ *	res = nl >> nr
+ */
+void
+cgen_shift(int op, int bounded, Node *nl, Node *nr, Node *res)
+{
+	Node n1, n2, n3, n4, n5, cx, oldcx;
+	int a, rcx;
+	Prog *p1;
+	uvlong sc;
+	Type *tcount;
+
+	a = optoas(op, nl->type);
+
+	if(nr->op == OLITERAL) {
+		regalloc(&n1, nl->type, res);
+		cgen(nl, &n1);
+		sc = mpgetfix(nr->val.u.xval);
+		if(sc >= nl->type->width*8) {
+			// large shift gets 2 shifts by width-1
+			nodconst(&n3, types[TUINT32], nl->type->width*8-1);
+			gins(a, &n3, &n1);
+			gins(a, &n3, &n1);
+		} else
+			gins(a, nr, &n1);
+		gmove(&n1, res);
+		regfree(&n1);
+		goto ret;
+	}
+
+	if(nl->ullman >= UINF) {
+		tempname(&n4, nl->type);
+		cgen(nl, &n4);
+		nl = &n4;
+	}
+	if(nr->ullman >= UINF) {
+		tempname(&n5, nr->type);
+		cgen(nr, &n5);
+		nr = &n5;
+	}
+
+	rcx = reg[D_CX];
+	nodreg(&n1, types[TUINT32], D_CX);
+	
+	// Allow either uint32 or uint64 as shift type,
+	// to avoid unnecessary conversion from uint32 to uint64
+	// just to do the comparison.
+	tcount = types[simtype[nr->type->etype]];
+	if(tcount->etype < TUINT32)
+		tcount = types[TUINT32];
+
+	regalloc(&n1, nr->type, &n1);		// to hold the shift type in CX
+	regalloc(&n3, tcount, &n1);	// to clear high bits of CX
+
+	nodreg(&cx, types[TUINT64], D_CX);
+	memset(&oldcx, 0, sizeof oldcx);
+	if(rcx > 0 && !samereg(&cx, res)) {
+		regalloc(&oldcx, types[TUINT64], N);
+		gmove(&cx, &oldcx);
+	}
+	cx.type = tcount;
+
+	if(samereg(&cx, res))
+		regalloc(&n2, nl->type, N);
+	else
+		regalloc(&n2, nl->type, res);
+	if(nl->ullman >= nr->ullman) {
+		cgen(nl, &n2);
+		cgen(nr, &n1);
+		gmove(&n1, &n3);
+	} else {
+		cgen(nr, &n1);
+		gmove(&n1, &n3);
+		cgen(nl, &n2);
+	}
+	regfree(&n3);
+
+	// test and fix up large shifts
+	if(!bounded) {
+		nodconst(&n3, tcount, nl->type->width*8);
+		gins(optoas(OCMP, tcount), &n1, &n3);
+		p1 = gbranch(optoas(OLT, tcount), T, +1);
+		if(op == ORSH && issigned[nl->type->etype]) {
+			nodconst(&n3, types[TUINT32], nl->type->width*8-1);
+			gins(a, &n3, &n2);
+		} else {
+			nodconst(&n3, nl->type, 0);
+			gmove(&n3, &n2);
+		}
+		patch(p1, pc);
+	}
+
+	gins(a, &n1, &n2);
+
+	if(oldcx.op != 0) {
+		cx.type = types[TUINT64];
+		gmove(&oldcx, &cx);
+		regfree(&oldcx);
+	}
+
+	gmove(&n2, res);
+
+	regfree(&n1);
+	regfree(&n2);
+
+ret:
+	;
+}
+
+/*
+ * generate byte multiply:
+ *	res = nl * nr
+ * there is no 2-operand byte multiply instruction so
+ * we do a full-width multiplication and truncate afterwards.
+ */
+void
+cgen_bmul(int op, Node *nl, Node *nr, Node *res)
+{
+	Node n1, n2, n1b, n2b, *tmp;
+	Type *t;
+	int a;
+
+	// largest ullman on left.
+	if(nl->ullman < nr->ullman) {
+		tmp = nl;
+		nl = nr;
+		nr = tmp;
+	}
+
+	// generate operands in "8-bit" registers.
+	regalloc(&n1b, nl->type, res);
+	cgen(nl, &n1b);
+	regalloc(&n2b, nr->type, N);
+	cgen(nr, &n2b);
+
+	// perform full-width multiplication.
+	t = types[TUINT64];
+	if(issigned[nl->type->etype])
+		t = types[TINT64];
+	nodreg(&n1, t, n1b.val.u.reg);
+	nodreg(&n2, t, n2b.val.u.reg);
+	a = optoas(op, t);
+	gins(a, &n2, &n1);
+
+	// truncate.
+	gmove(&n1, res);
+	regfree(&n1b);
+	regfree(&n2b);
+}
+
+void
+clearfat(Node *nl)
+{
+	int64 w, c, q;
+	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))
+		return;
+
+	c = w % 8;	// bytes
+	q = w / 8;	// quads
+
+	if(q < 4) {
+		// Write sequence of MOV 0, off(base) instead of using STOSQ.
+		// The hope is that although the code will be slightly longer,
+		// the MOVs will have no dependencies and pipeline better
+		// than the unrolled STOSQ loop.
+		// NOTE: Must use agen, not igen, so that optimizer sees address
+		// being taken. We are not writing on field boundaries.
+		agenr(nl, &n1, N);
+		n1.op = OINDREG;
+		nodconst(&z, types[TUINT64], 0);
+		while(q-- > 0) {
+			n1.type = z.type;
+			gins(AMOVQ, &z, &n1);
+			n1.xoffset += 8;
+		}
+		if(c >= 4) {
+			nodconst(&z, types[TUINT32], 0);
+			n1.type = z.type;
+			gins(AMOVL, &z, &n1);
+			n1.xoffset += 4;
+			c -= 4;
+		}
+		nodconst(&z, types[TUINT8], 0);
+		while(c-- > 0) {
+			n1.type = z.type;
+			gins(AMOVB, &z, &n1);
+			n1.xoffset++;
+		}
+		regfree(&n1);
+		return;
+	}
+
+	savex(D_DI, &n1, &oldn1, N, types[tptr]);
+	agen(nl, &n1);
+
+	savex(D_AX, &ax, &oldax, N, types[tptr]);
+	gconreg(AMOVL, 0, D_AX);
+
+	if(q > 128 || nacl) {
+		gconreg(movptr, q, D_CX);
+		gins(AREP, N, N);	// repeat
+		gins(ASTOSQ, N, N);	// STOQ AL,*(DI)+
+	} else {
+		p = gins(ADUFFZERO, N, N);
+		p->to.type = D_ADDR;
+		p->to.sym = linksym(pkglookup("duffzero", runtimepkg));
+		// 2 and 128 = magic constants: see ../../runtime/asm_amd64.s
+		p->to.offset = 2*(128-q);
+	}
+
+	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)+
+		c--;
+	}
+
+	restx(&n1, &oldn1);
+	restx(&ax, &oldax);
+}
+
+// Called after regopt and peep have run.
+// Expand CHECKNIL pseudo-op into actual nil pointer check.
+void
+expandchecks(Prog *firstp)
+{
+	Prog *p, *p1, *p2;
+
+	for(p = firstp; p != P; p = p->link) {
+		if(p->as != ACHECKNIL)
+			continue;
+		if(debug_checknil && p->lineno > 1) // p->lineno==1 in generated wrappers
+			warnl(p->lineno, "generated nil check");
+		// check is
+		//	CMP arg, $0
+		//	JNE 2(PC) (likely)
+		//	MOV AX, 0
+		p1 = mal(sizeof *p1);
+		p2 = mal(sizeof *p2);
+		clearp(p1);
+		clearp(p2);
+		p1->link = p2;
+		p2->link = p->link;
+		p->link = p1;
+		p1->lineno = p->lineno;
+		p2->lineno = p->lineno;
+		p1->pc = 9999;
+		p2->pc = 9999;
+		p->as = cmpptr;
+		p->to.type = D_CONST;
+		p->to.offset = 0;
+		p1->as = AJNE;
+		p1->from.type = D_CONST;
+		p1->from.offset = 1; // likely
+		p1->to.type = D_BRANCH;
+		p1->to.u.branch = p2->link;
+		// crash by write to memory address 0.
+		// if possible, since we know arg is 0, use 0(arg),
+		// which will be shorter to encode than plain 0.
+		p2->as = AMOVL;
+		p2->from.type = D_AX;
+		if(regtyp(&p->from))
+			p2->to.type = p->from.type + D_INDIR;
+		else
+			p2->to.type = D_INDIR+D_NONE;
+		p2->to.offset = 0;
+	}
+}
diff --git a/src/cmd/6g/gobj.c b/src/cmd/6g/gobj.c
new file mode 100644
index 0000000..04e837b
--- /dev/null
+++ b/src/cmd/6g/gobj.c
@@ -0,0 +1,235 @@
+// Derived from Inferno utils/6c/swt.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/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 "gg.h"
+
+int
+dsname(Sym *s, int off, char *t, int n)
+{
+	Prog *p;
+
+	p = gins(ADATA, N, N);
+	p->from.type = D_EXTERN;
+	p->from.index = D_NONE;
+	p->from.offset = off;
+	p->from.scale = n;
+	p->from.sym = linksym(s);
+	
+	p->to.type = D_SCONST;
+	p->to.index = D_NONE;
+	memmove(p->to.u.sval, t, n);
+	return off + n;
+}
+
+/*
+ * make a refer to the data s, s+len
+ * emitting DATA if needed.
+ */
+void
+datastring(char *s, int len, Addr *a)
+{
+	Sym *sym;
+	
+	sym = stringsym(s, len);
+	a->type = D_EXTERN;
+	a->sym = linksym(sym);
+	a->node = sym->def;
+	a->offset = widthptr+widthint;  // skip header
+	a->etype = simtype[TINT];
+}
+
+/*
+ * make a refer to the string sval,
+ * emitting DATA if needed.
+ */
+void
+datagostring(Strlit *sval, Addr *a)
+{
+	Sym *sym;
+
+	sym = stringsym(sval->s, sval->len);
+	a->type = D_EXTERN;
+	a->sym = linksym(sym);
+	a->node = sym->def;
+	a->offset = 0;  // header
+	a->etype = TINT32;
+}
+
+void
+gdata(Node *nam, Node *nr, int wid)
+{
+	Prog *p;
+
+	if(nr->op == OLITERAL) {
+		switch(nr->val.ctype) {
+		case CTCPLX:
+			gdatacomplex(nam, nr->val.u.cval);
+			return;
+		case CTSTR:
+			gdatastring(nam, nr->val.u.sval);
+			return;
+		}
+	}
+	p = gins(ADATA, nam, nr);
+	p->from.scale = wid;
+}
+
+void
+gdatacomplex(Node *nam, Mpcplx *cval)
+{
+	Prog *p;
+	int w;
+
+	w = cplxsubtype(nam->type->etype);
+	w = types[w]->width;
+
+	p = gins(ADATA, nam, N);
+	p->from.scale = w;
+	p->to.type = D_FCONST;
+	p->to.u.dval = mpgetflt(&cval->real);
+
+	p = gins(ADATA, nam, N);
+	p->from.scale = w;
+	p->from.offset += w;
+	p->to.type = D_FCONST;
+	p->to.u.dval = mpgetflt(&cval->imag);
+}
+
+void
+gdatastring(Node *nam, Strlit *sval)
+{
+	Prog *p;
+	Node nod1;
+
+	p = gins(ADATA, nam, N);
+	datastring(sval->s, sval->len, &p->to);
+	p->from.scale = types[tptr]->width;
+	p->to.index = p->to.type;
+	p->to.type = D_ADDR;
+//print("%P\n", p);
+
+	nodconst(&nod1, types[TINT], sval->len);
+	p = gins(ADATA, nam, &nod1);
+	p->from.scale = widthint;
+	p->from.offset += widthptr;
+}
+
+int
+dstringptr(Sym *s, int off, char *str)
+{
+	Prog *p;
+
+	off = rnd(off, widthptr);
+	p = gins(ADATA, N, N);
+	p->from.type = D_EXTERN;
+	p->from.index = D_NONE;
+	p->from.sym = linksym(s);
+	p->from.offset = off;
+	p->from.scale = widthptr;
+
+	datastring(str, strlen(str)+1, &p->to);
+	p->to.index = p->to.type;
+	p->to.type = D_ADDR;
+	p->to.etype = simtype[TINT];
+	off += widthptr;
+
+	return off;
+}
+
+int
+dgostrlitptr(Sym *s, int off, Strlit *lit)
+{
+	Prog *p;
+
+	if(lit == nil)
+		return duintptr(s, off, 0);
+
+	off = rnd(off, widthptr);
+	p = gins(ADATA, N, N);
+	p->from.type = D_EXTERN;
+	p->from.index = D_NONE;
+	p->from.sym = linksym(s);
+	p->from.offset = off;
+	p->from.scale = widthptr;
+	datagostring(lit, &p->to);
+	p->to.index = p->to.type;
+	p->to.type = D_ADDR;
+	p->to.etype = simtype[TINT];
+	off += widthptr;
+
+	return off;
+}
+
+int
+dgostringptr(Sym *s, int off, char *str)
+{
+	int n;
+	Strlit *lit;
+
+	if(str == nil)
+		return duintptr(s, off, 0);
+
+	n = strlen(str);
+	lit = mal(sizeof *lit + n);
+	strcpy(lit->s, str);
+	lit->len = n;
+	return dgostrlitptr(s, off, lit);
+}
+
+int
+dsymptr(Sym *s, int off, Sym *x, int xoff)
+{
+	Prog *p;
+
+	off = rnd(off, widthptr);
+
+	p = gins(ADATA, N, N);
+	p->from.type = D_EXTERN;
+	p->from.index = D_NONE;
+	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 = linksym(x);
+	p->to.offset = xoff;
+	off += widthptr;
+
+	return off;
+}
+
+void
+nopout(Prog *p)
+{
+	p->as = ANOP;
+}
+
diff --git a/src/cmd/6g/gsubr.c b/src/cmd/6g/gsubr.c
new file mode 100644
index 0000000..5bd9246
--- /dev/null
+++ b/src/cmd/6g/gsubr.c
@@ -0,0 +1,2296 @@
+// Derived from Inferno utils/6c/txt.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/txt.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"
+#include "../../runtime/funcdata.h"
+
+// TODO(rsc): Can make this bigger if we move
+// the text segment up higher in 6l for all GOOS.
+// At the same time, can raise StackBig in ../../runtime/stack.h.
+vlong unmappedzero = 4096;
+
+void
+clearp(Prog *p)
+{
+	p->as = AEND;
+	p->from.type = D_NONE;
+	p->from.index = D_NONE;
+	p->to.type = D_NONE;
+	p->to.index = D_NONE;
+	p->pc = pcloc;
+	pcloc++;
+}
+
+static int ddumped;
+static Prog *dfirst;
+static Prog *dpc;
+
+/*
+ * generate and return proc with p->as = as,
+ * linked into program. pc is next instruction.
+ */
+Prog*
+prog(int as)
+{
+	Prog *p;
+
+	if(as == ADATA || as == AGLOBL) {
+		if(ddumped)
+			fatal("already dumped data");
+		if(dpc == nil) {
+			dpc = mal(sizeof(*dpc));
+			dfirst = dpc;
+		}
+		p = dpc;
+		dpc = mal(sizeof(*dpc));
+		p->link = dpc;
+	} else {
+		p = pc;
+		pc = mal(sizeof(*pc));
+		clearp(pc);
+		p->link = pc;
+	}
+
+	if(lineno == 0) {
+		if(debug['K'])
+			warn("prog: line 0");
+	}
+
+	p->as = as;
+	p->lineno = lineno;
+	return p;
+}
+
+void
+dumpdata(void)
+{
+	ddumped = 1;
+	if(dfirst == nil)
+		return;
+	newplist();
+	*pc = *dfirst;
+	pc = dpc;
+	clearp(pc);
+}
+
+/*
+ * generate a branch.
+ * t is ignored.
+ * likely values are for branch prediction:
+ *	-1 unlikely
+ *	0 no opinion
+ *	+1 likely
+ */
+Prog*
+gbranch(int as, Type *t, int likely)
+{
+	Prog *p;
+	
+	USED(t);
+
+	p = prog(as);
+	p->to.type = D_BRANCH;
+	p->to.u.branch = P;
+	if(as != AJMP && likely != 0) {
+		p->from.type = D_CONST;
+		p->from.offset = likely > 0;
+	}
+	return p;
+}
+
+/*
+ * patch previous branch to jump to to.
+ */
+void
+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->pc;
+}
+
+Prog*
+unpatch(Prog *p)
+{
+	Prog *q;
+
+	if(p->to.type != D_BRANCH)
+		fatal("unpatch: not a branch");
+	q = p->to.u.branch;
+	p->to.u.branch = P;
+	p->to.offset = 0;
+	return q;
+}
+
+/*
+ * start a new Prog list.
+ */
+Plist*
+newplist(void)
+{
+	Plist *pl;
+
+	pl = linknewplist(ctxt);
+
+	pc = mal(sizeof(*pc));
+	clearp(pc);
+	pl->firstpc = pc;
+
+	return pl;
+}
+
+void
+gused(Node *n)
+{
+	gins(ANOP, n, N);	// used
+}
+
+Prog*
+gjmp(Prog *to)
+{
+	Prog *p;
+
+	p = gbranch(AJMP, T, 0);
+	if(to != P)
+		patch(p, to);
+	return p;
+}
+
+void
+ggloblnod(Node *nam)
+{
+	Prog *p;
+
+	p = gins(AGLOBL, nam, N);
+	p->lineno = nam->lineno;
+	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)
+		p->from.scale = RODATA;
+	if(nam->type != T && !haspointers(nam->type))
+		p->from.scale |= NOPTR;
+}
+
+void
+gtrack(Sym *s)
+{
+	Prog *p;
+	
+	p = gins(AUSEFIELD, N, N);
+	p->from.type = D_EXTERN;
+	p->from.index = D_NONE;
+	p->from.sym = linksym(s);
+}
+
+void
+ggloblsym(Sym *s, int32 width, int8 flags)
+{
+	Prog *p;
+
+	p = gins(AGLOBL, N, N);
+	p->from.type = D_EXTERN;
+	p->from.index = D_NONE;
+	p->from.sym = linksym(s);
+	p->to.type = D_CONST;
+	p->to.index = D_NONE;
+	p->to.offset = width;
+	p->from.scale = flags;
+}
+
+int
+isfat(Type *t)
+{
+	if(t != T)
+	switch(t->etype) {
+	case TSTRUCT:
+	case TARRAY:
+	case TSTRING:
+	case TINTER:	// maybe remove later
+		return 1;
+	}
+	return 0;
+}
+
+/*
+ * naddr of func generates code for address of func.
+ * if using opcode that can take address implicitly,
+ * call afunclit to fix up the argument.
+ */
+void
+afunclit(Addr *a, Node *n)
+{
+	if(a->type == D_ADDR && a->index == D_EXTERN) {
+		a->type = D_EXTERN;
+		a->index = D_NONE;
+		a->sym = linksym(n->sym);
+	}
+}
+
+static	int	resvd[] =
+{
+	D_DI,	// for movstring
+	D_SI,	// for movstring
+
+	D_AX,	// for divide
+	D_CX,	// for shift
+	D_DX,	// for divide
+	D_SP,	// for stack
+};
+
+void
+ginit(void)
+{
+	int i;
+
+	for(i=0; i<nelem(reg); i++)
+		reg[i] = 1;
+	for(i=D_AX; i<=D_R15; i++)
+		reg[i] = 0;
+	for(i=D_X0; i<=D_X15; i++)
+		reg[i] = 0;
+
+	for(i=0; i<nelem(resvd); i++)
+		reg[resvd[i]]++;
+	
+	if(nacl) {
+		reg[D_BP]++;
+		reg[D_R15]++;
+	}
+}
+
+void
+gclean(void)
+{
+	int i;
+
+	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])
+			yyerror("reg %R left allocated\n", i);
+	for(i=D_X0; i<=D_X15; i++)
+		if(reg[i])
+			yyerror("reg %R left allocated\n", i);
+}
+
+int32
+anyregalloc(void)
+{
+	int i, j;
+
+	for(i=D_AX; i<=D_R15; i++) {
+		if(reg[i] == 0)
+			goto ok;
+		for(j=0; j<nelem(resvd); j++)
+			if(resvd[j] == i)
+				goto ok;
+		return 1;
+	ok:;
+	}
+	return 0;
+}
+
+static	uintptr	regpc[D_R15+1 - D_AX];
+
+/*
+ * allocate register of type t, leave in n.
+ * if o != N, o is desired fixed register.
+ * caller must regfree(n).
+ */
+void
+regalloc(Node *n, Type *t, Node *o)
+{
+	int i, et;
+
+	if(t == T)
+		fatal("regalloc: t nil");
+	et = simtype[t->etype];
+
+	switch(et) {
+	case TINT8:
+	case TUINT8:
+	case TINT16:
+	case TUINT16:
+	case TINT32:
+	case TUINT32:
+	case TINT64:
+	case TUINT64:
+	case TPTR32:
+	case TPTR64:
+	case TBOOL:
+		if(o != N && o->op == OREGISTER) {
+			i = o->val.u.reg;
+			if(i >= D_AX && i <= D_R15)
+				goto out;
+		}
+		for(i=D_AX; i<=D_R15; i++)
+			if(reg[i] == 0) {
+				regpc[i-D_AX] = (uintptr)getcallerpc(&n);
+				goto out;
+			}
+
+		flusherrors();
+		for(i=0; i+D_AX<=D_R15; i++)
+			print("%d %p\n", i, regpc[i]);
+		fatal("out of fixed registers");
+
+	case TFLOAT32:
+	case TFLOAT64:
+		if(o != N && o->op == OREGISTER) {
+			i = o->val.u.reg;
+			if(i >= D_X0 && i <= D_X15)
+				goto out;
+		}
+		for(i=D_X0; i<=D_X15; i++)
+			if(reg[i] == 0)
+				goto out;
+		fatal("out of floating registers");
+
+	case TCOMPLEX64:
+	case TCOMPLEX128:
+		tempname(n, t);
+		return;
+	}
+	fatal("regalloc: unknown type %T", t);
+	return;
+
+out:
+	reg[i]++;
+	nodreg(n, t, i);
+}
+
+void
+regfree(Node *n)
+{
+	int i;
+
+	if(n->op == ONAME)
+		return;
+	if(n->op != OREGISTER && n->op != OINDREG)
+		fatal("regfree: not a register");
+	i = n->val.u.reg;
+	if(i == D_SP)
+		return;
+	if(i < 0 || i >= nelem(reg))
+		fatal("regfree: reg out of range");
+	if(reg[i] <= 0)
+		fatal("regfree: reg not allocated");
+	reg[i]--;
+	if(reg[i] == 0 && D_AX <= i && i <= D_R15)
+		regpc[i - D_AX] = 0;
+}
+
+/*
+ * initialize n to be register r of type t.
+ */
+void
+nodreg(Node *n, Type *t, int r)
+{
+	if(t == T)
+		fatal("nodreg: t nil");
+
+	memset(n, 0, sizeof(*n));
+	n->op = OREGISTER;
+	n->addable = 1;
+	ullmancalc(n);
+	n->val.u.reg = r;
+	n->type = t;
+}
+
+/*
+ * initialize n to be indirect of register r; n is type t.
+ */
+void
+nodindreg(Node *n, Type *t, int r)
+{
+	nodreg(n, t, r);
+	n->op = OINDREG;
+}
+
+Node*
+nodarg(Type *t, int fp)
+{
+	Node *n;
+	NodeList *l;
+	Type *first;
+	Iter savet;
+
+	// entire argument struct, not just one arg
+	if(t->etype == TSTRUCT && t->funarg) {
+		n = nod(ONAME, N, N);
+		n->sym = lookup(".args");
+		n->type = t;
+		first = structfirst(&savet, &t);
+		if(first == nil)
+			fatal("nodarg: bad struct");
+		if(first->width == BADWIDTH)
+			fatal("nodarg: offset not computed for %T", t);
+		n->xoffset = first->width;
+		n->addable = 1;
+		goto 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;
+	
+	if(t->width == BADWIDTH)
+		fatal("nodarg: offset not computed for %T", t);
+	n->xoffset = t->width;
+	n->addable = 1;
+	n->orig = t->nname;
+
+fp:
+	// Rewrite argument named _ to __,
+	// or else the assignment to _ will be
+	// discarded during code generation.
+	if(isblank(n))
+		n->sym = lookup("__");
+
+	switch(fp) {
+	case 0:		// output arg
+		n->op = OINDREG;
+		n->val.u.reg = D_SP;
+		break;
+
+	case 1:		// input arg
+		n->class = PPARAM;
+		break;
+
+	case 2:		// offset output arg
+fatal("shouldn't be used");
+		n->op = OINDREG;
+		n->val.u.reg = D_SP;
+		n->xoffset += types[tptr]->width;
+		break;
+	}
+	n->typecheck = 1;
+	return n;
+}
+
+/*
+ * generate
+ *	as $c, reg
+ */
+void
+gconreg(int as, vlong c, int reg)
+{
+	Node nr;
+
+	switch(as) {
+	case AADDL:
+	case AMOVL:
+	case ALEAL:
+		nodreg(&nr, types[TINT32], reg);
+		break;
+	default:
+		nodreg(&nr, types[TINT64], reg);
+	}
+
+	ginscon(as, c, &nr);
+}
+
+/*
+ * generate
+ *	as $c, n
+ */
+void
+ginscon(int as, vlong c, Node *n2)
+{
+	Node n1, ntmp;
+
+	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 immediate in ADD, etc.
+		// instead, MOV into register first.
+		regalloc(&ntmp, types[TINT64], N);
+		gins(AMOVQ, &n1, &ntmp);
+		gins(as, &ntmp, n2);
+		regfree(&ntmp);
+		return;
+	}
+	gins(as, &n1, n2);
+}
+
+#define	CASE(a,b)	(((a)<<16)|((b)<<0))
+/*c2go int CASE(int, int); */
+
+/*
+ * Is this node a memory operand?
+ */
+int
+ismem(Node *n)
+{
+	switch(n->op) {
+	case OITAB:
+	case OSPTR:
+	case OLEN:
+	case OCAP:
+	case OINDREG:
+	case ONAME:
+	case OPARAM:
+	case OCLOSUREVAR:
+	case OADDR:
+		return 1;
+	}
+	return 0;
+}
+
+/*
+ * set up nodes representing 2^63
+ */
+Node bigi;
+Node bigf;
+
+void
+bignodes(void)
+{
+	static int did;
+
+	if(did)
+		return;
+	did = 1;
+
+	nodconst(&bigi, types[TUINT64], 1);
+	mpshiftfix(bigi.val.u.xval, 63);
+
+	bigf = bigi;
+	bigf.type = types[TFLOAT64];
+	bigf.val.ctype = CTFLT;
+	bigf.val.u.fval = mal(sizeof *bigf.val.u.fval);
+	mpmovefixflt(bigf.val.u.fval, bigi.val.u.xval);
+}
+
+/*
+ * generate move:
+ *	t = f
+ * hard part is conversions.
+ */
+// TODO: lost special constants for floating point.  XORPD for 0.0?
+void
+gmove(Node *f, Node *t)
+{
+	int a, ft, tt;
+	Type *cvt;
+	Node r1, r2, r3, r4, zero, one, con;
+	Prog *p1, *p2;
+
+	if(debug['M'])
+		print("gmove %lN -> %lN\n", f, t);
+
+	ft = simsimtype(f->type);
+	tt = simsimtype(t->type);
+	cvt = t->type;
+
+	if(iscomplex[ft] || iscomplex[tt]) {
+		complexmove(f, t);
+		return;
+	}
+
+	// cannot have two memory operands
+	if(ismem(f) && ismem(t))
+		goto hard;
+
+	// convert constant to desired type
+	if(f->op == OLITERAL) {
+		convconst(&con, t->type, &f->val);
+		f = &con;
+		ft = tt;	// so big switch will choose a simple mov
+
+		// some constants can't move directly to memory.
+		if(ismem(t)) {
+			// float constants come from memory.
+			if(isfloat[tt])
+				goto hard;
+
+			// 64-bit immediates are really 32-bit sign-extended
+			// unless moving into a register.
+			if(isint[tt]) {
+				if(mpcmpfixfix(con.val.u.xval, minintval[TINT32]) < 0)
+					goto hard;
+				if(mpcmpfixfix(con.val.u.xval, maxintval[TINT32]) > 0)
+					goto hard;
+			}
+		}
+	}
+
+	// value -> value copy, only one memory operand.
+	// figure out the instruction to use.
+	// break out of switch for one-instruction gins.
+	// goto rdst for "destination must be register".
+	// goto hard for "convert to cvt type first".
+	// otherwise handle and return.
+
+	switch(CASE(ft, tt)) {
+	default:
+		fatal("gmove %lT -> %lT", f->type, t->type);
+
+	/*
+	 * integer copy and truncate
+	 */
+	case CASE(TINT8, TINT8):	// same size
+	case CASE(TINT8, TUINT8):
+	case CASE(TUINT8, TINT8):
+	case CASE(TUINT8, TUINT8):
+	case CASE(TINT16, TINT8):	// truncate
+	case CASE(TUINT16, TINT8):
+	case CASE(TINT32, TINT8):
+	case CASE(TUINT32, TINT8):
+	case CASE(TINT64, TINT8):
+	case CASE(TUINT64, TINT8):
+	case CASE(TINT16, TUINT8):
+	case CASE(TUINT16, TUINT8):
+	case CASE(TINT32, TUINT8):
+	case CASE(TUINT32, TUINT8):
+	case CASE(TINT64, TUINT8):
+	case CASE(TUINT64, TUINT8):
+		a = AMOVB;
+		break;
+
+	case CASE(TINT16, TINT16):	// same size
+	case CASE(TINT16, TUINT16):
+	case CASE(TUINT16, TINT16):
+	case CASE(TUINT16, TUINT16):
+	case CASE(TINT32, TINT16):	// truncate
+	case CASE(TUINT32, TINT16):
+	case CASE(TINT64, TINT16):
+	case CASE(TUINT64, TINT16):
+	case CASE(TINT32, TUINT16):
+	case CASE(TUINT32, TUINT16):
+	case CASE(TINT64, TUINT16):
+	case CASE(TUINT64, TUINT16):
+		a = AMOVW;
+		break;
+
+	case CASE(TINT32, TINT32):	// same size
+	case CASE(TINT32, TUINT32):
+	case CASE(TUINT32, TINT32):
+	case CASE(TUINT32, TUINT32):
+		a = AMOVL;
+		break;
+
+	case CASE(TINT64, TINT32):	// truncate
+	case CASE(TUINT64, TINT32):
+	case CASE(TINT64, TUINT32):
+	case CASE(TUINT64, TUINT32):
+		a = AMOVQL;
+		break;
+
+	case CASE(TINT64, TINT64):	// same size
+	case CASE(TINT64, TUINT64):
+	case CASE(TUINT64, TINT64):
+	case CASE(TUINT64, TUINT64):
+		a = AMOVQ;
+		break;
+
+	/*
+	 * integer up-conversions
+	 */
+	case CASE(TINT8, TINT16):	// sign extend int8
+	case CASE(TINT8, TUINT16):
+		a = AMOVBWSX;
+		goto rdst;
+	case CASE(TINT8, TINT32):
+	case CASE(TINT8, TUINT32):
+		a = AMOVBLSX;
+		goto rdst;
+	case CASE(TINT8, TINT64):
+	case CASE(TINT8, TUINT64):
+		a = AMOVBQSX;
+		goto rdst;
+
+	case CASE(TUINT8, TINT16):	// zero extend uint8
+	case CASE(TUINT8, TUINT16):
+		a = AMOVBWZX;
+		goto rdst;
+	case CASE(TUINT8, TINT32):
+	case CASE(TUINT8, TUINT32):
+		a = AMOVBLZX;
+		goto rdst;
+	case CASE(TUINT8, TINT64):
+	case CASE(TUINT8, TUINT64):
+		a = AMOVBQZX;
+		goto rdst;
+
+	case CASE(TINT16, TINT32):	// sign extend int16
+	case CASE(TINT16, TUINT32):
+		a = AMOVWLSX;
+		goto rdst;
+	case CASE(TINT16, TINT64):
+	case CASE(TINT16, TUINT64):
+		a = AMOVWQSX;
+		goto rdst;
+
+	case CASE(TUINT16, TINT32):	// zero extend uint16
+	case CASE(TUINT16, TUINT32):
+		a = AMOVWLZX;
+		goto rdst;
+	case CASE(TUINT16, TINT64):
+	case CASE(TUINT16, TUINT64):
+		a = AMOVWQZX;
+		goto rdst;
+
+	case CASE(TINT32, TINT64):	// sign extend int32
+	case CASE(TINT32, TUINT64):
+		a = AMOVLQSX;
+		goto rdst;
+
+	case CASE(TUINT32, TINT64):	// zero extend uint32
+	case CASE(TUINT32, TUINT64):
+		// AMOVL into a register zeros the top of the register,
+		// so this is not always necessary, but if we rely on AMOVL
+		// the optimizer is almost certain to screw with us.
+		a = AMOVLQZX;
+		goto rdst;
+
+	/*
+	* float to integer
+	*/
+	case CASE(TFLOAT32, TINT32):
+		a = ACVTTSS2SL;
+		goto rdst;
+
+	case CASE(TFLOAT64, TINT32):
+		a = ACVTTSD2SL;
+		goto rdst;
+
+	case CASE(TFLOAT32, TINT64):
+		a = ACVTTSS2SQ;
+		goto rdst;
+
+	case CASE(TFLOAT64, TINT64):
+		a = ACVTTSD2SQ;
+		goto rdst;
+
+	case CASE(TFLOAT32, TINT16):
+	case CASE(TFLOAT32, TINT8):
+	case CASE(TFLOAT32, TUINT16):
+	case CASE(TFLOAT32, TUINT8):
+	case CASE(TFLOAT64, TINT16):
+	case CASE(TFLOAT64, TINT8):
+	case CASE(TFLOAT64, TUINT16):
+	case CASE(TFLOAT64, TUINT8):
+		// convert via int32.
+		cvt = types[TINT32];
+		goto hard;
+
+	case CASE(TFLOAT32, TUINT32):
+	case CASE(TFLOAT64, TUINT32):
+		// convert via int64.
+		cvt = types[TINT64];
+		goto hard;
+
+	case CASE(TFLOAT32, TUINT64):
+	case CASE(TFLOAT64, TUINT64):
+		// algorithm is:
+		//	if small enough, use native float64 -> int64 conversion.
+		//	otherwise, subtract 2^63, convert, and add it back.
+		a = ACVTTSS2SQ;
+		if(ft == TFLOAT64)
+			a = ACVTTSD2SQ;
+		bignodes();
+		regalloc(&r1, types[ft], N);
+		regalloc(&r2, types[tt], t);
+		regalloc(&r3, types[ft], N);
+		regalloc(&r4, types[tt], N);
+		gins(optoas(OAS, f->type), f, &r1);
+		gins(optoas(OCMP, f->type), &bigf, &r1);
+		p1 = gbranch(optoas(OLE, f->type), T, +1);
+		gins(a, &r1, &r2);
+		p2 = gbranch(AJMP, T, 0);
+		patch(p1, pc);
+		gins(optoas(OAS, f->type), &bigf, &r3);
+		gins(optoas(OSUB, f->type), &r3, &r1);
+		gins(a, &r1, &r2);
+		gins(AMOVQ, &bigi, &r4);
+		gins(AXORQ, &r4, &r2);
+		patch(p2, pc);
+		gmove(&r2, t);
+		regfree(&r4);
+		regfree(&r3);
+		regfree(&r2);
+		regfree(&r1);
+		return;
+
+	/*
+	 * integer to float
+	 */
+	case CASE(TINT32, TFLOAT32):
+		a = ACVTSL2SS;
+		goto rdst;
+
+
+	case CASE(TINT32, TFLOAT64):
+		a = ACVTSL2SD;
+		goto rdst;
+
+	case CASE(TINT64, TFLOAT32):
+		a = ACVTSQ2SS;
+		goto rdst;
+
+	case CASE(TINT64, TFLOAT64):
+		a = ACVTSQ2SD;
+		goto rdst;
+
+	case CASE(TINT16, TFLOAT32):
+	case CASE(TINT16, TFLOAT64):
+	case CASE(TINT8, TFLOAT32):
+	case CASE(TINT8, TFLOAT64):
+	case CASE(TUINT16, TFLOAT32):
+	case CASE(TUINT16, TFLOAT64):
+	case CASE(TUINT8, TFLOAT32):
+	case CASE(TUINT8, TFLOAT64):
+		// convert via int32
+		cvt = types[TINT32];
+		goto hard;
+
+	case CASE(TUINT32, TFLOAT32):
+	case CASE(TUINT32, TFLOAT64):
+		// convert via int64.
+		cvt = types[TINT64];
+		goto hard;
+
+	case CASE(TUINT64, TFLOAT32):
+	case CASE(TUINT64, TFLOAT64):
+		// algorithm is:
+		//	if small enough, use native int64 -> uint64 conversion.
+		//	otherwise, halve (rounding to odd?), convert, and double.
+		a = ACVTSQ2SS;
+		if(tt == TFLOAT64)
+			a = ACVTSQ2SD;
+		nodconst(&zero, types[TUINT64], 0);
+		nodconst(&one, types[TUINT64], 1);
+		regalloc(&r1, f->type, f);
+		regalloc(&r2, t->type, t);
+		regalloc(&r3, f->type, N);
+		regalloc(&r4, f->type, N);
+		gmove(f, &r1);
+		gins(ACMPQ, &r1, &zero);
+		p1 = gbranch(AJLT, T, +1);
+		gins(a, &r1, &r2);
+		p2 = gbranch(AJMP, T, 0);
+		patch(p1, pc);
+		gmove(&r1, &r3);
+		gins(ASHRQ, &one, &r3);
+		gmove(&r1, &r4);
+		gins(AANDL, &one, &r4);
+		gins(AORQ, &r4, &r3);
+		gins(a, &r3, &r2);
+		gins(optoas(OADD, t->type), &r2, &r2);
+		patch(p2, pc);
+		gmove(&r2, t);
+		regfree(&r4);
+		regfree(&r3);
+		regfree(&r2);
+		regfree(&r1);
+		return;
+
+	/*
+	 * float to float
+	 */
+	case CASE(TFLOAT32, TFLOAT32):
+		a = AMOVSS;
+		break;
+
+	case CASE(TFLOAT64, TFLOAT64):
+		a = AMOVSD;
+		break;
+
+	case CASE(TFLOAT32, TFLOAT64):
+		a = ACVTSS2SD;
+		goto rdst;
+
+	case CASE(TFLOAT64, TFLOAT32):
+		a = ACVTSD2SS;
+		goto rdst;
+	}
+
+	gins(a, f, t);
+	return;
+
+rdst:
+	// requires register destination
+	regalloc(&r1, t->type, t);
+	gins(a, f, &r1);
+	gmove(&r1, t);
+	regfree(&r1);
+	return;
+
+hard:
+	// requires register intermediate
+	regalloc(&r1, cvt, t);
+	gmove(f, &r1);
+	gmove(&r1, t);
+	regfree(&r1);
+	return;
+}
+
+int
+samaddr(Node *f, Node *t)
+{
+
+	if(f->op != t->op)
+		return 0;
+
+	switch(f->op) {
+	case OREGISTER:
+		if(f->val.u.reg != t->val.u.reg)
+			break;
+		return 1;
+	}
+	return 0;
+}
+
+/*
+ * generate one instruction:
+ *	as f, t
+ */
+Prog*
+gins(int as, Node *f, Node *t)
+{
+//	Node nod;
+	int32 w;
+	Prog *p;
+	Addr af, at;
+
+//	if(f != N && f->op == OINDEX) {
+//		regalloc(&nod, &regnode, Z);
+//		v = constnode.vconst;
+//		cgen(f->right, &nod);
+//		constnode.vconst = v;
+//		idx.reg = nod.reg;
+//		regfree(&nod);
+//	}
+//	if(t != N && t->op == OINDEX) {
+//		regalloc(&nod, &regnode, Z);
+//		v = constnode.vconst;
+//		cgen(t->right, &nod);
+//		constnode.vconst = v;
+//		idx.reg = nod.reg;
+//		regfree(&nod);
+//	}
+
+	switch(as) {
+	case AMOVB:
+	case AMOVW:
+	case AMOVL:
+	case AMOVQ:
+	case AMOVSS:
+	case AMOVSD:
+		if(f != N && t != N && samaddr(f, t))
+			return nil;
+		break;
+	
+	case ALEAQ:
+		if(f != N && isconst(f, CTNIL)) {
+			fatal("gins LEAQ nil %T", f->type);
+		}
+		break;
+	}
+
+	memset(&af, 0, sizeof af);
+	memset(&at, 0, sizeof at);
+	if(f != N)
+		naddr(f, &af, 1);
+	if(t != N)
+		naddr(t, &at, 1);
+	p = prog(as);
+	if(f != N)
+		p->from = af;
+	if(t != N)
+		p->to = at;
+	if(debug['g'])
+		print("%P\n", p);
+
+	w = 0;
+	switch(as) {
+	case AMOVB:
+		w = 1;
+		break;
+	case AMOVW:
+		w = 2;
+		break;
+	case AMOVL:
+		w = 4;
+		break;
+	case AMOVQ:
+		w = 8;
+		break;
+	}
+	if(w != 0 && ((f != N && af.width < w) || (t != N && at.width > w))) {
+		dump("f", f);
+		dump("t", t);
+		fatal("bad width: %P (%d, %d)\n", p, af.width, at.width);
+	}
+
+	return p;
+}
+
+void
+fixlargeoffset(Node *n)
+{
+	Node a;
+
+	if(n == N)
+		return;
+	if(n->op != OINDREG)
+		return;
+	if(n->val.u.reg == D_SP) // stack offset cannot be large
+		return;
+	if(n->xoffset != (int32)n->xoffset) {
+		// offset too large, add to register instead.
+		a = *n;
+		a.op = OREGISTER;
+		a.type = types[tptr];
+		a.xoffset = 0;
+		cgen_checknil(&a);
+		ginscon(optoas(OADD, types[tptr]), n->xoffset, &a);
+		n->xoffset = 0;
+	}
+}
+
+/*
+ * generate code to compute n;
+ * make a refer to result.
+ */
+void
+naddr(Node *n, Addr *a, int canemitcode)
+{
+	Sym *s;
+
+	a->scale = 0;
+	a->index = D_NONE;
+	a->type = D_NONE;
+	a->gotype = nil;
+	a->node = N;
+	a->width = 0;
+	if(n == N)
+		return;
+
+	if(n->type != T && n->type->etype != TIDEAL) {
+		dowidth(n->type);
+		a->width = n->type->width;
+	}
+
+	switch(n->op) {
+	default:
+		fatal("naddr: bad %O %D", n->op, a);
+		break;
+
+	case OREGISTER:
+		a->type = n->val.u.reg;
+		a->sym = nil;
+		break;
+
+//	case OINDEX:
+//	case OIND:
+//		naddr(n->left, a);
+//		if(a->type >= D_AX && a->type <= D_DI)
+//			a->type += D_INDIR;
+//		else
+//		if(a->type == D_CONST)
+//			a->type = D_NONE+D_INDIR;
+//		else
+//		if(a->type == D_ADDR) {
+//			a->type = a->index;
+//			a->index = D_NONE;
+//		} else
+//			goto bad;
+//		if(n->op == OINDEX) {
+//			a->index = idx.reg;
+//			a->scale = n->scale;
+//		}
+//		break;
+
+	case OINDREG:
+		a->type = n->val.u.reg+D_INDIR;
+		a->sym = linksym(n->sym);
+		a->offset = n->xoffset;
+		if(a->offset != (int32)a->offset)
+			yyerror("offset %lld too large for OINDREG", a->offset);
+		break;
+
+	case OPARAM:
+		// n->left is PHEAP ONAME for stack parameter.
+		// compute address of actual parameter on stack.
+		a->etype = simtype[n->left->type->etype];
+		a->width = n->left->type->width;
+		a->offset = n->xoffset;
+		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 = nil;
+		a->offset = n->xoffset;
+		break;
+	
+	case OCFUNC:
+		naddr(n->left, a, canemitcode);
+		a->sym = linksym(n->left->sym);
+		break;
+
+	case ONAME:
+		a->etype = 0;
+		if(n->type != T)
+			a->etype = simtype[n->type->etype];
+		a->offset = n->xoffset;
+		s = n->sym;
+		a->node = n->orig;
+		//if(a->node >= (Node*)&n)
+		//	fatal("stack node");
+		if(s == S)
+			s = lookup(".noname");
+		if(n->method) {
+			if(n->type != T)
+			if(n->type->sym != S)
+			if(n->type->sym->pkg != nil)
+				s = pkglookup(s->name, n->type->sym->pkg);
+		}
+
+		switch(n->class) {
+		default:
+			fatal("naddr: ONAME class %S %d\n", n->sym, n->class);
+		case PEXTERN:
+			a->type = D_EXTERN;
+			break;
+		case PAUTO:
+			a->type = D_AUTO;
+			break;
+		case PPARAM:
+		case PPARAMOUT:
+			a->type = D_PARAM;
+			break;
+		case PFUNC:
+			a->index = D_EXTERN;
+			a->type = D_ADDR;
+			a->width = widthptr;
+			s = funcsym(s);			
+			break;
+		}
+		a->sym = linksym(s);
+		break;
+
+	case OLITERAL:
+		switch(n->val.ctype) {
+		default:
+			fatal("naddr: const %lT", n->type);
+			break;
+		case CTFLT:
+			a->type = D_FCONST;
+			a->u.dval = mpgetflt(n->val.u.fval);
+			break;
+		case CTINT:
+		case CTRUNE:
+			a->sym = nil;
+			a->type = D_CONST;
+			a->offset = mpgetfix(n->val.u.xval);
+			break;
+		case CTSTR:
+			datagostring(n->val.u.sval, a);
+			break;
+		case CTBOOL:
+			a->sym = nil;
+			a->type = D_CONST;
+			a->offset = n->val.u.bval;
+			break;
+		case CTNIL:
+			a->sym = nil;
+			a->type = D_CONST;
+			a->offset = 0;
+			break;
+		}
+		break;
+
+	case OADDR:
+		naddr(n->left, a, canemitcode);
+		a->width = widthptr;
+		if(a->type >= D_INDIR) {
+			a->type -= D_INDIR;
+			break;
+		}
+		if(a->type == D_EXTERN || a->type == D_STATIC ||
+		   a->type == D_AUTO || a->type == D_PARAM)
+			if(a->index == D_NONE) {
+				a->index = a->type;
+				a->type = D_ADDR;
+				break;
+			}
+		fatal("naddr: OADDR\n");
+	
+	case OITAB:
+		// itable of interface value
+		naddr(n->left, a, canemitcode);
+		if(a->type == D_CONST && a->offset == 0)
+			break;  // itab(nil)
+		a->etype = tptr;
+		a->width = widthptr;
+		break;
+
+	case OSPTR:
+		// pointer in a string or slice
+		naddr(n->left, a, canemitcode);
+		if(a->type == D_CONST && a->offset == 0)
+			break;	// ptr(nil)
+		a->etype = simtype[tptr];
+		a->offset += Array_array;
+		a->width = widthptr;
+		break;
+
+	case OLEN:
+		// len of string or slice
+		naddr(n->left, a, canemitcode);
+		if(a->type == D_CONST && a->offset == 0)
+			break;	// len(nil)
+		a->etype = simtype[TUINT];
+		a->offset += Array_nel;
+		a->width = widthint;
+		break;
+
+	case OCAP:
+		// cap of string or slice
+		naddr(n->left, a, canemitcode);
+		if(a->type == D_CONST && a->offset == 0)
+			break;	// cap(nil)
+		a->etype = simtype[TUINT];
+		a->offset += Array_cap;
+		a->width = widthint;
+		break;
+
+//	case OADD:
+//		if(n->right->op == OLITERAL) {
+//			v = n->right->vconst;
+//			naddr(n->left, a, canemitcode);
+//		} else
+//		if(n->left->op == OLITERAL) {
+//			v = n->left->vconst;
+//			naddr(n->right, a, canemitcode);
+//		} else
+//			goto bad;
+//		a->offset += v;
+//		break;
+
+	}
+}
+
+/*
+ * return Axxx for Oxxx on type t.
+ */
+int
+optoas(int op, Type *t)
+{
+	int a;
+
+	if(t == T)
+		fatal("optoas: t is nil");
+
+	a = AGOK;
+	switch(CASE(op, simtype[t->etype])) {
+	default:
+		fatal("optoas: no entry %O-%T", op, t);
+		break;
+
+	case CASE(OADDR, TPTR32):
+		a = ALEAL;
+		break;
+
+	case CASE(OADDR, TPTR64):
+		a = ALEAQ;
+		break;
+
+	case CASE(OEQ, TBOOL):
+	case CASE(OEQ, TINT8):
+	case CASE(OEQ, TUINT8):
+	case CASE(OEQ, TINT16):
+	case CASE(OEQ, TUINT16):
+	case CASE(OEQ, TINT32):
+	case CASE(OEQ, TUINT32):
+	case CASE(OEQ, TINT64):
+	case CASE(OEQ, TUINT64):
+	case CASE(OEQ, TPTR32):
+	case CASE(OEQ, TPTR64):
+	case CASE(OEQ, TFLOAT32):
+	case CASE(OEQ, TFLOAT64):
+		a = AJEQ;
+		break;
+
+	case CASE(ONE, TBOOL):
+	case CASE(ONE, TINT8):
+	case CASE(ONE, TUINT8):
+	case CASE(ONE, TINT16):
+	case CASE(ONE, TUINT16):
+	case CASE(ONE, TINT32):
+	case CASE(ONE, TUINT32):
+	case CASE(ONE, TINT64):
+	case CASE(ONE, TUINT64):
+	case CASE(ONE, TPTR32):
+	case CASE(ONE, TPTR64):
+	case CASE(ONE, TFLOAT32):
+	case CASE(ONE, TFLOAT64):
+		a = AJNE;
+		break;
+
+	case CASE(OLT, TINT8):
+	case CASE(OLT, TINT16):
+	case CASE(OLT, TINT32):
+	case CASE(OLT, TINT64):
+		a = AJLT;
+		break;
+
+	case CASE(OLT, TUINT8):
+	case CASE(OLT, TUINT16):
+	case CASE(OLT, TUINT32):
+	case CASE(OLT, TUINT64):
+		a = AJCS;
+		break;
+
+	case CASE(OLE, TINT8):
+	case CASE(OLE, TINT16):
+	case CASE(OLE, TINT32):
+	case CASE(OLE, TINT64):
+		a = AJLE;
+		break;
+
+	case CASE(OLE, TUINT8):
+	case CASE(OLE, TUINT16):
+	case CASE(OLE, TUINT32):
+	case CASE(OLE, TUINT64):
+		a = AJLS;
+		break;
+
+	case CASE(OGT, TINT8):
+	case CASE(OGT, TINT16):
+	case CASE(OGT, TINT32):
+	case CASE(OGT, TINT64):
+		a = AJGT;
+		break;
+
+	case CASE(OGT, TUINT8):
+	case CASE(OGT, TUINT16):
+	case CASE(OGT, TUINT32):
+	case CASE(OGT, TUINT64):
+	case CASE(OLT, TFLOAT32):
+	case CASE(OLT, TFLOAT64):
+		a = AJHI;
+		break;
+
+	case CASE(OGE, TINT8):
+	case CASE(OGE, TINT16):
+	case CASE(OGE, TINT32):
+	case CASE(OGE, TINT64):
+		a = AJGE;
+		break;
+
+	case CASE(OGE, TUINT8):
+	case CASE(OGE, TUINT16):
+	case CASE(OGE, TUINT32):
+	case CASE(OGE, TUINT64):
+	case CASE(OLE, TFLOAT32):
+	case CASE(OLE, TFLOAT64):
+		a = AJCC;
+		break;
+
+	case CASE(OCMP, TBOOL):
+	case CASE(OCMP, TINT8):
+	case CASE(OCMP, TUINT8):
+		a = ACMPB;
+		break;
+
+	case CASE(OCMP, TINT16):
+	case CASE(OCMP, TUINT16):
+		a = ACMPW;
+		break;
+
+	case CASE(OCMP, TINT32):
+	case CASE(OCMP, TUINT32):
+	case CASE(OCMP, TPTR32):
+		a = ACMPL;
+		break;
+
+	case CASE(OCMP, TINT64):
+	case CASE(OCMP, TUINT64):
+	case CASE(OCMP, TPTR64):
+		a = ACMPQ;
+		break;
+
+	case CASE(OCMP, TFLOAT32):
+		a = AUCOMISS;
+		break;
+
+	case CASE(OCMP, TFLOAT64):
+		a = AUCOMISD;
+		break;
+
+	case CASE(OAS, TBOOL):
+	case CASE(OAS, TINT8):
+	case CASE(OAS, TUINT8):
+		a = AMOVB;
+		break;
+
+	case CASE(OAS, TINT16):
+	case CASE(OAS, TUINT16):
+		a = AMOVW;
+		break;
+
+	case CASE(OAS, TINT32):
+	case CASE(OAS, TUINT32):
+	case CASE(OAS, TPTR32):
+		a = AMOVL;
+		break;
+
+	case CASE(OAS, TINT64):
+	case CASE(OAS, TUINT64):
+	case CASE(OAS, TPTR64):
+		a = AMOVQ;
+		break;
+
+	case CASE(OAS, TFLOAT32):
+		a = AMOVSS;
+		break;
+
+	case CASE(OAS, TFLOAT64):
+		a = AMOVSD;
+		break;
+
+	case CASE(OADD, TINT8):
+	case CASE(OADD, TUINT8):
+		a = AADDB;
+		break;
+
+	case CASE(OADD, TINT16):
+	case CASE(OADD, TUINT16):
+		a = AADDW;
+		break;
+
+	case CASE(OADD, TINT32):
+	case CASE(OADD, TUINT32):
+	case CASE(OADD, TPTR32):
+		a = AADDL;
+		break;
+
+	case CASE(OADD, TINT64):
+	case CASE(OADD, TUINT64):
+	case CASE(OADD, TPTR64):
+		a = AADDQ;
+		break;
+
+	case CASE(OADD, TFLOAT32):
+		a = AADDSS;
+		break;
+
+	case CASE(OADD, TFLOAT64):
+		a = AADDSD;
+		break;
+
+	case CASE(OSUB, TINT8):
+	case CASE(OSUB, TUINT8):
+		a = ASUBB;
+		break;
+
+	case CASE(OSUB, TINT16):
+	case CASE(OSUB, TUINT16):
+		a = ASUBW;
+		break;
+
+	case CASE(OSUB, TINT32):
+	case CASE(OSUB, TUINT32):
+	case CASE(OSUB, TPTR32):
+		a = ASUBL;
+		break;
+
+	case CASE(OSUB, TINT64):
+	case CASE(OSUB, TUINT64):
+	case CASE(OSUB, TPTR64):
+		a = ASUBQ;
+		break;
+
+	case CASE(OSUB, TFLOAT32):
+		a = ASUBSS;
+		break;
+
+	case CASE(OSUB, TFLOAT64):
+		a = ASUBSD;
+		break;
+
+	case CASE(OINC, TINT8):
+	case CASE(OINC, TUINT8):
+		a = AINCB;
+		break;
+
+	case CASE(OINC, TINT16):
+	case CASE(OINC, TUINT16):
+		a = AINCW;
+		break;
+
+	case CASE(OINC, TINT32):
+	case CASE(OINC, TUINT32):
+	case CASE(OINC, TPTR32):
+		a = AINCL;
+		break;
+
+	case CASE(OINC, TINT64):
+	case CASE(OINC, TUINT64):
+	case CASE(OINC, TPTR64):
+		a = AINCQ;
+		break;
+
+	case CASE(ODEC, TINT8):
+	case CASE(ODEC, TUINT8):
+		a = ADECB;
+		break;
+
+	case CASE(ODEC, TINT16):
+	case CASE(ODEC, TUINT16):
+		a = ADECW;
+		break;
+
+	case CASE(ODEC, TINT32):
+	case CASE(ODEC, TUINT32):
+	case CASE(ODEC, TPTR32):
+		a = ADECL;
+		break;
+
+	case CASE(ODEC, TINT64):
+	case CASE(ODEC, TUINT64):
+	case CASE(ODEC, TPTR64):
+		a = ADECQ;
+		break;
+
+	case CASE(OMINUS, TINT8):
+	case CASE(OMINUS, TUINT8):
+		a = ANEGB;
+		break;
+
+	case CASE(OMINUS, TINT16):
+	case CASE(OMINUS, TUINT16):
+		a = ANEGW;
+		break;
+
+	case CASE(OMINUS, TINT32):
+	case CASE(OMINUS, TUINT32):
+	case CASE(OMINUS, TPTR32):
+		a = ANEGL;
+		break;
+
+	case CASE(OMINUS, TINT64):
+	case CASE(OMINUS, TUINT64):
+	case CASE(OMINUS, TPTR64):
+		a = ANEGQ;
+		break;
+
+	case CASE(OAND, TINT8):
+	case CASE(OAND, TUINT8):
+		a = AANDB;
+		break;
+
+	case CASE(OAND, TINT16):
+	case CASE(OAND, TUINT16):
+		a = AANDW;
+		break;
+
+	case CASE(OAND, TINT32):
+	case CASE(OAND, TUINT32):
+	case CASE(OAND, TPTR32):
+		a = AANDL;
+		break;
+
+	case CASE(OAND, TINT64):
+	case CASE(OAND, TUINT64):
+	case CASE(OAND, TPTR64):
+		a = AANDQ;
+		break;
+
+	case CASE(OOR, TINT8):
+	case CASE(OOR, TUINT8):
+		a = AORB;
+		break;
+
+	case CASE(OOR, TINT16):
+	case CASE(OOR, TUINT16):
+		a = AORW;
+		break;
+
+	case CASE(OOR, TINT32):
+	case CASE(OOR, TUINT32):
+	case CASE(OOR, TPTR32):
+		a = AORL;
+		break;
+
+	case CASE(OOR, TINT64):
+	case CASE(OOR, TUINT64):
+	case CASE(OOR, TPTR64):
+		a = AORQ;
+		break;
+
+	case CASE(OXOR, TINT8):
+	case CASE(OXOR, TUINT8):
+		a = AXORB;
+		break;
+
+	case CASE(OXOR, TINT16):
+	case CASE(OXOR, TUINT16):
+		a = AXORW;
+		break;
+
+	case CASE(OXOR, TINT32):
+	case CASE(OXOR, TUINT32):
+	case CASE(OXOR, TPTR32):
+		a = AXORL;
+		break;
+
+	case CASE(OXOR, TINT64):
+	case CASE(OXOR, TUINT64):
+	case CASE(OXOR, TPTR64):
+		a = AXORQ;
+		break;
+
+	case CASE(OLROT, TINT8):
+	case CASE(OLROT, TUINT8):
+		a = AROLB;
+		break;
+
+	case CASE(OLROT, TINT16):
+	case CASE(OLROT, TUINT16):
+		a = AROLW;
+		break;
+
+	case CASE(OLROT, TINT32):
+	case CASE(OLROT, TUINT32):
+	case CASE(OLROT, TPTR32):
+		a = AROLL;
+		break;
+
+	case CASE(OLROT, TINT64):
+	case CASE(OLROT, TUINT64):
+	case CASE(OLROT, TPTR64):
+		a = AROLQ;
+		break;
+
+	case CASE(OLSH, TINT8):
+	case CASE(OLSH, TUINT8):
+		a = ASHLB;
+		break;
+
+	case CASE(OLSH, TINT16):
+	case CASE(OLSH, TUINT16):
+		a = ASHLW;
+		break;
+
+	case CASE(OLSH, TINT32):
+	case CASE(OLSH, TUINT32):
+	case CASE(OLSH, TPTR32):
+		a = ASHLL;
+		break;
+
+	case CASE(OLSH, TINT64):
+	case CASE(OLSH, TUINT64):
+	case CASE(OLSH, TPTR64):
+		a = ASHLQ;
+		break;
+
+	case CASE(ORSH, TUINT8):
+		a = ASHRB;
+		break;
+
+	case CASE(ORSH, TUINT16):
+		a = ASHRW;
+		break;
+
+	case CASE(ORSH, TUINT32):
+	case CASE(ORSH, TPTR32):
+		a = ASHRL;
+		break;
+
+	case CASE(ORSH, TUINT64):
+	case CASE(ORSH, TPTR64):
+		a = ASHRQ;
+		break;
+
+	case CASE(ORSH, TINT8):
+		a = ASARB;
+		break;
+
+	case CASE(ORSH, TINT16):
+		a = ASARW;
+		break;
+
+	case CASE(ORSH, TINT32):
+		a = ASARL;
+		break;
+
+	case CASE(ORSH, TINT64):
+		a = ASARQ;
+		break;
+
+	case CASE(ORROTC, TINT8):
+	case CASE(ORROTC, TUINT8):
+		a = ARCRB;
+		break;
+
+	case CASE(ORROTC, TINT16):
+	case CASE(ORROTC, TUINT16):
+		a = ARCRW;
+		break;
+
+	case CASE(ORROTC, TINT32):
+	case CASE(ORROTC, TUINT32):
+		a = ARCRL;
+		break;
+
+	case CASE(ORROTC, TINT64):
+	case CASE(ORROTC, TUINT64):
+		a = ARCRQ;
+		break;
+
+	case CASE(OHMUL, TINT8):
+	case CASE(OMUL, TINT8):
+	case CASE(OMUL, TUINT8):
+		a = AIMULB;
+		break;
+
+	case CASE(OHMUL, TINT16):
+	case CASE(OMUL, TINT16):
+	case CASE(OMUL, TUINT16):
+		a = AIMULW;
+		break;
+
+	case CASE(OHMUL, TINT32):
+	case CASE(OMUL, TINT32):
+	case CASE(OMUL, TUINT32):
+	case CASE(OMUL, TPTR32):
+		a = AIMULL;
+		break;
+
+	case CASE(OHMUL, TINT64):
+	case CASE(OMUL, TINT64):
+	case CASE(OMUL, TUINT64):
+	case CASE(OMUL, TPTR64):
+		a = AIMULQ;
+		break;
+
+	case CASE(OHMUL, TUINT8):
+		a = AMULB;
+		break;
+
+	case CASE(OHMUL, TUINT16):
+		a = AMULW;
+		break;
+
+	case CASE(OHMUL, TUINT32):
+	case CASE(OHMUL, TPTR32):
+		a = AMULL;
+		break;
+
+	case CASE(OHMUL, TUINT64):
+	case CASE(OHMUL, TPTR64):
+		a = AMULQ;
+		break;
+
+	case CASE(OMUL, TFLOAT32):
+		a = AMULSS;
+		break;
+
+	case CASE(OMUL, TFLOAT64):
+		a = AMULSD;
+		break;
+
+	case CASE(ODIV, TINT8):
+	case CASE(OMOD, TINT8):
+		a = AIDIVB;
+		break;
+
+	case CASE(ODIV, TUINT8):
+	case CASE(OMOD, TUINT8):
+		a = ADIVB;
+		break;
+
+	case CASE(ODIV, TINT16):
+	case CASE(OMOD, TINT16):
+		a = AIDIVW;
+		break;
+
+	case CASE(ODIV, TUINT16):
+	case CASE(OMOD, TUINT16):
+		a = ADIVW;
+		break;
+
+	case CASE(ODIV, TINT32):
+	case CASE(OMOD, TINT32):
+		a = AIDIVL;
+		break;
+
+	case CASE(ODIV, TUINT32):
+	case CASE(ODIV, TPTR32):
+	case CASE(OMOD, TUINT32):
+	case CASE(OMOD, TPTR32):
+		a = ADIVL;
+		break;
+
+	case CASE(ODIV, TINT64):
+	case CASE(OMOD, TINT64):
+		a = AIDIVQ;
+		break;
+
+	case CASE(ODIV, TUINT64):
+	case CASE(ODIV, TPTR64):
+	case CASE(OMOD, TUINT64):
+	case CASE(OMOD, TPTR64):
+		a = ADIVQ;
+		break;
+
+	case CASE(OEXTEND, TINT16):
+		a = ACWD;
+		break;
+
+	case CASE(OEXTEND, TINT32):
+		a = ACDQ;
+		break;
+
+	case CASE(OEXTEND, TINT64):
+		a = ACQO;
+		break;
+
+	case CASE(ODIV, TFLOAT32):
+		a = ADIVSS;
+		break;
+
+	case CASE(ODIV, TFLOAT64):
+		a = ADIVSD;
+		break;
+
+	}
+	return a;
+}
+
+enum
+{
+	ODynam		= 1<<0,
+	OAddable	= 1<<1,
+};
+
+static	Node	clean[20];
+static	int	cleani = 0;
+
+int
+xgen(Node *n, Node *a, int o)
+{
+	regalloc(a, types[tptr], N);
+
+	if(o & ODynam)
+	if(n->addable)
+	if(n->op != OINDREG)
+	if(n->op != OREGISTER)
+		return 1;
+
+	agen(n, a);
+	return 0;
+}
+
+void
+sudoclean(void)
+{
+	if(clean[cleani-1].op != OEMPTY)
+		regfree(&clean[cleani-1]);
+	if(clean[cleani-2].op != OEMPTY)
+		regfree(&clean[cleani-2]);
+	cleani -= 2;
+}
+
+/*
+ * generate code to compute address of n,
+ * a reference to a (perhaps nested) field inside
+ * an array or struct.
+ * return 0 on failure, 1 on success.
+ * on success, leaves usable address in a.
+ *
+ * caller is responsible for calling sudoclean
+ * after successful sudoaddable,
+ * to release the register used for a.
+ */
+int
+sudoaddable(int as, Node *n, Addr *a)
+{
+	int o, i;
+	int64 oary[10];
+	int64 v, w;
+	Node n1, n2, n3, n4, *nn, *l, *r;
+	Node *reg, *reg1;
+	Prog *p1;
+	Type *t;
+
+	if(n->type == T)
+		return 0;
+
+	switch(n->op) {
+	case OLITERAL:
+		if(!isconst(n, CTINT))
+			break;
+		v = mpgetfix(n->val.u.xval);
+		if(v >= 32000 || v <= -32000)
+			break;
+		goto lit;
+
+	case ODOT:
+	case ODOTPTR:
+		cleani += 2;
+		reg = &clean[cleani-1];
+		reg1 = &clean[cleani-2];
+		reg->op = OEMPTY;
+		reg1->op = OEMPTY;
+		goto odot;
+
+	case OINDEX:
+		return 0;
+		// disabled: OINDEX case is now covered by agenr
+		// for a more suitable register allocation pattern.
+		if(n->left->type->etype == TSTRING)
+			return 0;
+		goto oindex;
+	}
+	return 0;
+
+lit:
+	switch(as) {
+	default:
+		return 0;
+	case AADDB: case AADDW: case AADDL: case AADDQ:
+	case ASUBB: case ASUBW: case ASUBL: case ASUBQ:
+	case AANDB: case AANDW: case AANDL: case AANDQ:
+	case AORB:  case AORW:  case AORL:  case AORQ:
+	case AXORB: case AXORW: case AXORL: case AXORQ:
+	case AINCB: case AINCW: case AINCL: case AINCQ:
+	case ADECB: case ADECW: case ADECL: case ADECQ:
+	case AMOVB: case AMOVW: case AMOVL: case AMOVQ:
+		break;
+	}
+
+	cleani += 2;
+	reg = &clean[cleani-1];
+	reg1 = &clean[cleani-2];
+	reg->op = OEMPTY;
+	reg1->op = OEMPTY;
+	naddr(n, a, 1);
+	goto yes;
+
+odot:
+	o = dotoffset(n, oary, &nn);
+	if(nn == N)
+		goto no;
+
+	if(nn->addable && o == 1 && oary[0] >= 0) {
+		// directly addressable set of DOTs
+		n1 = *nn;
+		n1.type = n->type;
+		n1.xoffset += oary[0];
+		naddr(&n1, a, 1);
+		goto yes;
+	}
+
+	regalloc(reg, types[tptr], N);
+	n1 = *reg;
+	n1.op = OINDREG;
+	if(oary[0] >= 0) {
+		agen(nn, reg);
+		n1.xoffset = oary[0];
+	} else {
+		cgen(nn, reg);
+		cgen_checknil(reg);
+		n1.xoffset = -(oary[0]+1);
+	}
+
+	for(i=1; i<o; i++) {
+		if(oary[i] >= 0)
+			fatal("can't happen");
+		gins(movptr, &n1, reg);
+		cgen_checknil(reg);
+		n1.xoffset = -(oary[i]+1);
+	}
+
+	a->type = D_NONE;
+	a->index = D_NONE;
+	fixlargeoffset(&n1);
+	naddr(&n1, a, 1);
+	goto yes;
+
+oindex:
+	l = n->left;
+	r = n->right;
+	if(l->ullman >= UINF && r->ullman >= UINF)
+		return 0;
+
+	// set o to type of array
+	o = 0;
+	if(isptr[l->type->etype])
+		fatal("ptr ary");
+	if(l->type->etype != TARRAY)
+		fatal("not ary");
+	if(l->type->bound < 0)
+		o |= ODynam;
+
+	w = n->type->width;
+	if(isconst(r, CTINT))
+		goto oindex_const;
+
+	switch(w) {
+	default:
+		return 0;
+	case 1:
+	case 2:
+	case 4:
+	case 8:
+		break;
+	}
+
+	cleani += 2;
+	reg = &clean[cleani-1];
+	reg1 = &clean[cleani-2];
+	reg->op = OEMPTY;
+	reg1->op = OEMPTY;
+
+	// load the array (reg)
+	if(l->ullman > r->ullman) {
+		if(xgen(l, reg, o))
+			o |= OAddable;
+	}
+
+	// load the index (reg1)
+	t = types[TUINT64];
+	if(issigned[r->type->etype])
+		t = types[TINT64];
+	regalloc(reg1, t, N);
+	regalloc(&n3, r->type, reg1);
+	cgen(r, &n3);
+	gmove(&n3, reg1);
+	regfree(&n3);
+
+	// load the array (reg)
+	if(l->ullman <= r->ullman) {
+		if(xgen(l, reg, o))
+			o |= OAddable;
+	}
+
+	// check bounds
+	if(!debug['B'] && !n->bounded) {
+		// check bounds
+		n4.op = OXXX;
+		t = types[simtype[TUINT]];
+		if(o & ODynam) {
+			if(o & OAddable) {
+				n2 = *l;
+				n2.xoffset += Array_nel;
+				n2.type = types[simtype[TUINT]];
+			} else {
+				n2 = *reg;
+				n2.xoffset = Array_nel;
+				n2.op = OINDREG;
+				n2.type = types[simtype[TUINT]];
+			}
+		} else {
+			if(is64(r->type))
+				t = types[TUINT64];
+			nodconst(&n2, types[TUINT64], l->type->bound);
+		}
+		gins(optoas(OCMP, t), reg1, &n2);
+		p1 = gbranch(optoas(OLT, t), T, +1);
+		if(n4.op != OXXX)
+			regfree(&n4);
+		ginscall(panicindex, -1);
+		patch(p1, pc);
+	}
+
+	if(o & ODynam) {
+		if(o & OAddable) {
+			n2 = *l;
+			n2.xoffset += Array_array;
+			n2.type = types[tptr];
+			gmove(&n2, reg);
+		} else {
+			n2 = *reg;
+			n2.op = OINDREG;
+			n2.xoffset = Array_array;
+			n2.type = types[tptr];
+			gmove(&n2, reg);
+		}
+	}
+
+	if(o & OAddable) {
+		naddr(reg1, a, 1);
+		a->offset = 0;
+		a->scale = w;
+		a->index = a->type;
+		a->type = reg->val.u.reg + D_INDIR;
+	} else {
+		naddr(reg1, a, 1);
+		a->offset = 0;
+		a->scale = w;
+		a->index = a->type;
+		a->type = reg->val.u.reg + D_INDIR;
+	}
+
+	goto yes;
+
+oindex_const:
+	// index is constant
+	// can check statically and
+	// can multiply by width statically
+
+	v = mpgetfix(r->val.u.xval);
+
+	if(sudoaddable(as, l, a))
+		goto oindex_const_sudo;
+
+	cleani += 2;
+	reg = &clean[cleani-1];
+	reg1 = &clean[cleani-2];
+	reg->op = OEMPTY;
+	reg1->op = OEMPTY;
+
+	if(o & ODynam) {
+		regalloc(reg, types[tptr], N);
+		agen(l, reg);
+	
+		if(!debug['B'] && !n->bounded) {
+			n1 = *reg;
+			n1.op = OINDREG;
+			n1.type = types[tptr];
+			n1.xoffset = Array_nel;
+			nodconst(&n2, types[TUINT64], v);
+			gins(optoas(OCMP, types[simtype[TUINT]]), &n1, &n2);
+			p1 = gbranch(optoas(OGT, types[simtype[TUINT]]), T, +1);
+			ginscall(panicindex, -1);
+			patch(p1, pc);
+		}
+
+		n1 = *reg;
+		n1.op = OINDREG;
+		n1.type = types[tptr];
+		n1.xoffset = Array_array;
+		gmove(&n1, reg);
+
+		n2 = *reg;
+		n2.op = OINDREG;
+		n2.xoffset = v*w;
+		fixlargeoffset(&n2);
+		a->type = D_NONE;
+		a->index = D_NONE;
+		naddr(&n2, a, 1);
+		goto yes;
+	}
+	
+	igen(l, &n1, N);
+	if(n1.op == OINDREG) {
+		*reg = n1;
+		reg->op = OREGISTER;
+	}
+	n1.xoffset += v*w;
+	fixlargeoffset(&n1);
+	a->type = D_NONE;
+	a->index= D_NONE;
+	naddr(&n1, a, 1);
+	goto yes;
+
+oindex_const_sudo:
+	if((o & ODynam) == 0) {
+		// array indexed by a constant
+		a->offset += v*w;
+		goto yes;
+	}
+
+	// slice indexed by a constant
+	if(!debug['B'] && !n->bounded) {
+		a->offset += Array_nel;
+		nodconst(&n2, types[TUINT64], v);
+		p1 = gins(optoas(OCMP, types[simtype[TUINT]]), N, &n2);
+		p1->from = *a;
+		p1 = gbranch(optoas(OGT, types[simtype[TUINT]]), T, +1);
+		ginscall(panicindex, -1);
+		patch(p1, pc);
+		a->offset -= Array_nel;
+	}
+
+	a->offset += Array_array;
+	reg = &clean[cleani-1];
+	if(reg->op == OEMPTY)
+		regalloc(reg, types[tptr], N);
+
+	p1 = gins(movptr, N, reg);
+	p1->from = *a;
+
+	n2 = *reg;
+	n2.op = OINDREG;
+	n2.xoffset = v*w;
+	fixlargeoffset(&n2);
+	a->type = D_NONE;
+	a->index = D_NONE;
+	naddr(&n2, a, 1);
+	goto yes;
+
+yes:
+	return 1;
+
+no:
+	sudoclean();
+	return 0;
+}
diff --git a/src/cmd/6g/opt.h b/src/cmd/6g/opt.h
new file mode 100644
index 0000000..dbd039d
--- /dev/null
+++ b/src/cmd/6g/opt.h
@@ -0,0 +1,220 @@
+// Derived from Inferno utils/6c/gc.h
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/gc.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.
+
+#include	"../gc/popt.h"
+
+#define	Z	N
+#define	Adr	Addr
+
+#define	D_HI	D_NONE
+#define	D_LO	D_NONE
+
+#define	BLOAD(r)	band(bnot(r->refbehind), r->refahead)
+#define	BSTORE(r)	band(bnot(r->calbehind), r->calahead)
+#define	LOAD(r)		(~r->refbehind.b[z] & r->refahead.b[z])
+#define	STORE(r)	(~r->calbehind.b[z] & r->calahead.b[z])
+
+#define	CLOAD	5
+#define	CREF	5
+#define	CINF	1000
+#define	LOOP	3
+
+typedef	struct	Reg	Reg;
+typedef	struct	Rgn	Rgn;
+
+/*c2go
+extern Node *Z;
+enum
+{
+	D_HI = D_NONE,
+	D_LO = D_NONE,
+	CLOAD = 5,
+	CREF = 5,
+	CINF = 1000,
+	LOOP = 3,
+};
+
+uint32 BLOAD(Reg*);
+uint32 BSTORE(Reg*);
+uint32 LOAD(Reg*);
+uint32 STORE(Reg*);
+*/
+
+// A Reg is a wrapper around a single Prog (one instruction) that holds
+// register optimization information while the optimizer runs.
+// r->prog is the instruction.
+// r->prog->opt points back to r.
+struct	Reg
+{
+	Flow	f;
+
+	Bits	set;  		// variables written by this instruction.
+	Bits	use1; 		// variables read by prog->from.
+	Bits	use2; 		// variables read by prog->to.
+
+	Bits	refbehind;
+	Bits	refahead;
+	Bits	calbehind;
+	Bits	calahead;
+	Bits	regdiff;
+	Bits	act;
+
+	int32	regu;		// register used bitmap
+};
+#define	R	((Reg*)0)
+/*c2go extern Reg *R; */
+
+#define	NRGN	600
+/*c2go enum { NRGN = 600 }; */
+struct	Rgn
+{
+	Reg*	enter;
+	short	cost;
+	short	varno;
+	short	regno;
+};
+
+EXTERN	int32	exregoffset;		// not set
+EXTERN	int32	exfregoffset;		// not set
+EXTERN	Reg	zreg;
+EXTERN	Rgn	region[NRGN];
+EXTERN	Rgn*	rgp;
+EXTERN	int	nregion;
+EXTERN	int	nvar;
+EXTERN	int32	regbits;
+EXTERN	int32	exregbits;
+EXTERN	Bits	externs;
+EXTERN	Bits	params;
+EXTERN	Bits	consts;
+EXTERN	Bits	addrs;
+EXTERN	Bits	ivar;
+EXTERN	Bits	ovar;
+EXTERN	int	change;
+EXTERN	int32	maxnr;
+
+EXTERN	struct
+{
+	int32	ncvtreg;
+	int32	nspill;
+	int32	nreload;
+	int32	ndelmov;
+	int32	nvar;
+	int32	naddr;
+} ostats;
+
+/*
+ * reg.c
+ */
+int	rcmp(const void*, const void*);
+void	regopt(Prog*);
+void	addmove(Reg*, int, int, int);
+Bits	mkvar(Reg*, Adr*);
+void	prop(Reg*, Bits, Bits);
+void	synch(Reg*, Bits);
+uint32	allreg(uint32, Rgn*);
+void	paint1(Reg*, int);
+uint32	paint2(Reg*, int);
+void	paint3(Reg*, int, int32, int);
+void	addreg(Adr*, int);
+void	dumpone(Flow*, int);
+void	dumpit(char*, Flow*, int);
+
+/*
+ * peep.c
+ */
+void	peep(Prog*);
+void	excise(Flow*);
+int	copyu(Prog*, Adr*, Adr*);
+
+int32	RtoB(int);
+int32	FtoB(int);
+int	BtoR(int32);
+int	BtoF(int32);
+
+/*
+ * prog.c
+ */
+typedef struct ProgInfo ProgInfo;
+struct ProgInfo
+{
+	uint32 flags; // the bits below
+	uint32 reguse; // required registers used by this instruction
+	uint32 regset; // required registers set by this instruction
+	uint32 regindex; // registers used by addressing mode
+};
+
+enum
+{
+	// Pseudo-op, like TEXT, GLOBL, TYPE, PCDATA, FUNCDATA.
+	Pseudo = 1<<1,
+	
+	// There's nothing to say about the instruction,
+	// but it's still okay to see.
+	OK = 1<<2,
+
+	// Size of right-side write, or right-side read if no write.
+	SizeB = 1<<3,
+	SizeW = 1<<4,
+	SizeL = 1<<5,
+	SizeQ = 1<<6,
+	SizeF = 1<<7, // float aka float32
+	SizeD = 1<<8, // double aka float64
+
+	// Left side: address taken, read, write.
+	LeftAddr = 1<<9,
+	LeftRead = 1<<10,
+	LeftWrite = 1<<11,
+	
+	// Right side: address taken, read, write.
+	RightAddr = 1<<12,
+	RightRead = 1<<13,
+	RightWrite = 1<<14,
+
+	// Set, use, or kill of carry bit.
+	// Kill means we never look at the carry bit after this kind of instruction.
+	SetCarry = 1<<15,
+	UseCarry = 1<<16,
+	KillCarry = 1<<17,
+
+	// Instruction kinds
+	Move = 1<<18, // straight move
+	Conv = 1<<19, // size conversion
+	Cjmp = 1<<20, // conditional jump
+	Break = 1<<21, // breaks control flow (no fallthrough)
+	Call = 1<<22, // function call
+	Jump = 1<<23, // jump
+	Skip = 1<<24, // data instruction
+
+	// Special cases for register use.
+	ShiftCX = 1<<25, // possible shift by CX
+	ImulAXDX = 1<<26, // possible multiply into DX:AX
+};
+
+void proginfo(ProgInfo*, Prog*);
diff --git a/src/cmd/6g/peep.c b/src/cmd/6g/peep.c
new file mode 100644
index 0000000..2461783
--- /dev/null
+++ b/src/cmd/6g/peep.c
@@ -0,0 +1,990 @@
+// Derived from Inferno utils/6c/peep.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/peep.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"
+#include "opt.h"
+
+static void	conprop(Flow *r);
+static void	elimshortmov(Graph *g);
+static int	prevl(Flow *r, int reg);
+static void	pushback(Flow *r);
+static int	regconsttyp(Adr*);
+static int	subprop(Flow*);
+static int	copyprop(Graph*, Flow*);
+static int	copy1(Adr*, Adr*, Flow*, int);
+static int	copyas(Adr*, Adr*);
+static int	copyau(Adr*, Adr*);
+static int	copysub(Adr*, Adr*, Adr*, int);
+
+static uint32	gactive;
+
+// do we need the carry bit
+static int
+needc(Prog *p)
+{
+	ProgInfo info;
+
+	while(p != P) {
+		proginfo(&info, p);
+		if(info.flags & UseCarry)
+			return 1;
+		if(info.flags & (SetCarry|KillCarry))
+			return 0;
+		p = p->link;
+	}
+	return 0;
+}
+
+static Flow*
+rnops(Flow *r)
+{
+	Prog *p;
+	Flow *r1;
+
+	if(r != nil)
+	for(;;) {
+		p = r->prog;
+		if(p->as != ANOP || p->from.type != D_NONE || p->to.type != D_NONE)
+			break;
+		r1 = uniqs(r);
+		if(r1 == nil)
+			break;
+		r = r1;
+	}
+	return r;
+}
+
+void
+peep(Prog *firstp)
+{
+	Flow *r, *r1;
+	Graph *g;
+	Prog *p, *p1;
+	int t;
+
+	g = flowstart(firstp, sizeof(Flow));
+	if(g == nil)
+		return;
+	gactive = 0;
+
+	// byte, word arithmetic elimination.
+	elimshortmov(g);
+
+	// constant propagation
+	// find MOV $con,R followed by
+	// another MOV $con,R without
+	// setting R in the interim
+	for(r=g->start; r!=nil; r=r->link) {
+		p = r->prog;
+		switch(p->as) {
+		case ALEAL:
+		case ALEAQ:
+			if(regtyp(&p->to))
+			if(p->from.sym != nil)
+			if(p->from.index == D_NONE || p->from.index == D_CONST)
+				conprop(r);
+			break;
+
+		case AMOVB:
+		case AMOVW:
+		case AMOVL:
+		case AMOVQ:
+		case AMOVSS:
+		case AMOVSD:
+			if(regtyp(&p->to))
+			if(p->from.type == D_CONST)
+				conprop(r);
+			break;
+		}
+	}
+
+loop1:
+	if(debug['P'] && debug['v'])
+		dumpit("loop1", g->start, 0);
+
+	t = 0;
+	for(r=g->start; r!=nil; r=r->link) {
+		p = r->prog;
+		switch(p->as) {
+		case AMOVL:
+		case AMOVQ:
+		case AMOVSS:
+		case AMOVSD:
+			if(regtyp(&p->to))
+			if(regtyp(&p->from)) {
+				if(copyprop(g, r)) {
+					excise(r);
+					t++;
+				} else
+				if(subprop(r) && copyprop(g, r)) {
+					excise(r);
+					t++;
+				}
+			}
+			break;
+
+		case AMOVBLZX:
+		case AMOVWLZX:
+		case AMOVBLSX:
+		case AMOVWLSX:
+			if(regtyp(&p->to)) {
+				r1 = rnops(uniqs(r));
+				if(r1 != nil) {
+					p1 = r1->prog;
+					if(p->as == p1->as && p->to.type == p1->from.type){
+						p1->as = AMOVL;
+						t++;
+					}
+				}
+			}
+			break;
+
+		case AMOVBQSX:
+		case AMOVBQZX:
+		case AMOVWQSX:
+		case AMOVWQZX:
+		case AMOVLQSX:
+		case AMOVLQZX:
+		case AMOVQL:
+			if(regtyp(&p->to)) {
+				r1 = rnops(uniqs(r));
+				if(r1 != nil) {
+					p1 = r1->prog;
+					if(p->as == p1->as && p->to.type == p1->from.type){
+						p1->as = AMOVQ;
+						t++;
+					}
+				}
+			}
+			break;
+
+		case AADDL:
+		case AADDQ:
+		case AADDW:
+			if(p->from.type != D_CONST || needc(p->link))
+				break;
+			if(p->from.offset == -1){
+				if(p->as == AADDQ)
+					p->as = ADECQ;
+				else
+				if(p->as == AADDL)
+					p->as = ADECL;
+				else
+					p->as = ADECW;
+				p->from = zprog.from;
+				break;
+			}
+			if(p->from.offset == 1){
+				if(p->as == AADDQ)
+					p->as = AINCQ;
+				else if(p->as == AADDL)
+					p->as = AINCL;
+				else
+					p->as = AINCW;
+				p->from = zprog.from;
+				break;
+			}
+			break;
+
+		case ASUBL:
+		case ASUBQ:
+		case ASUBW:
+			if(p->from.type != D_CONST || needc(p->link))
+				break;
+			if(p->from.offset == -1) {
+				if(p->as == ASUBQ)
+					p->as = AINCQ;
+				else
+				if(p->as == ASUBL)
+					p->as = AINCL;
+				else
+					p->as = AINCW;
+				p->from = zprog.from;
+				break;
+			}
+			if(p->from.offset == 1){
+				if(p->as == ASUBQ)
+					p->as = ADECQ;
+				else
+				if(p->as == ASUBL)
+					p->as = ADECL;
+				else
+					p->as = ADECW;
+				p->from = zprog.from;
+				break;
+			}
+			break;
+		}
+	}
+	if(t)
+		goto loop1;
+
+	// MOVLQZX removal.
+	// The MOVLQZX exists to avoid being confused for a
+	// MOVL that is just copying 32-bit data around during
+	// copyprop.  Now that copyprop is done, remov MOVLQZX R1, R2
+	// if it is dominated by an earlier ADDL/MOVL/etc into R1 that
+	// will have already cleared the high bits.
+	//
+	// MOVSD removal.
+	// We never use packed registers, so a MOVSD between registers
+	// can be replaced by MOVAPD, which moves the pair of float64s
+	// instead of just the lower one.  We only use the lower one, but
+	// the processor can do better if we do moves using both.
+	for(r=g->start; r!=nil; r=r->link) {
+		p = r->prog;
+		if(p->as == AMOVLQZX)
+		if(regtyp(&p->from))
+		if(p->from.type == p->to.type)
+		if(prevl(r, p->from.type))
+			excise(r);
+		
+		if(p->as == AMOVSD)
+		if(regtyp(&p->from))
+		if(regtyp(&p->to))
+			p->as = AMOVAPD;
+	}
+
+	// load pipelining
+	// push any load from memory as early as possible
+	// to give it time to complete before use.
+	for(r=g->start; r!=nil; r=r->link) {
+		p = r->prog;
+		switch(p->as) {
+		case AMOVB:
+		case AMOVW:
+		case AMOVL:
+		case AMOVQ:
+		case AMOVLQZX:
+			if(regtyp(&p->to) && !regconsttyp(&p->from))
+				pushback(r);
+		}
+	}
+	
+	flowend(g);
+}
+
+static void
+pushback(Flow *r0)
+{
+	Flow *r, *b;
+	Prog *p0, *p, t;
+	
+	b = nil;
+	p0 = r0->prog;
+	for(r=uniqp(r0); r!=nil && uniqs(r)!=nil; r=uniqp(r)) {
+		p = r->prog;
+		if(p->as != ANOP) {
+			if(!regconsttyp(&p->from) || !regtyp(&p->to))
+				break;
+			if(copyu(p, &p0->to, nil) || copyu(p0, &p->to, nil))
+				break;
+		}
+		if(p->as == ACALL)
+			break;
+		b = r;
+	}
+	
+	if(b == nil) {
+		if(debug['v']) {
+			print("no pushback: %P\n", r0->prog);
+			if(r)
+				print("\t%P [%d]\n", r->prog, uniqs(r)!=nil);
+		}
+		return;
+	}
+
+	if(debug['v']) {
+		print("pushback\n");
+		for(r=b;; r=r->link) {
+			print("\t%P\n", r->prog);
+			if(r == r0)
+				break;
+		}
+	}
+
+	t = *r0->prog;
+	for(r=uniqp(r0);; r=uniqp(r)) {
+		p0 = r->link->prog;
+		p = r->prog;
+		p0->as = p->as;
+		p0->lineno = p->lineno;
+		p0->from = p->from;
+		p0->to = p->to;
+
+		if(r == b)
+			break;
+	}
+	p0 = r->prog;
+	p0->as = t.as;
+	p0->lineno = t.lineno;
+	p0->from = t.from;
+	p0->to = t.to;
+
+	if(debug['v']) {
+		print("\tafter\n");
+		for(r=b;; r=r->link) {
+			print("\t%P\n", r->prog);
+			if(r == r0)
+				break;
+		}
+	}
+}
+
+void
+excise(Flow *r)
+{
+	Prog *p;
+
+	p = r->prog;
+	if(debug['P'] && debug['v'])
+		print("%P ===delete===\n", p);
+
+	p->as = ANOP;
+	p->from = zprog.from;
+	p->to = zprog.to;
+
+	ostats.ndelmov++;
+}
+
+int
+regtyp(Adr *a)
+{
+	int t;
+
+	t = a->type;
+	if(t >= D_AX && t <= D_R15)
+		return 1;
+	if(t >= D_X0 && t <= D_X0+15)
+		return 1;
+	return 0;
+}
+
+// movb elimination.
+// movb is simulated by the linker
+// when a register other than ax, bx, cx, dx
+// is used, so rewrite to other instructions
+// when possible.  a movb into a register
+// can smash the entire 32-bit register without
+// causing any trouble.
+//
+// TODO: Using the Q forms here instead of the L forms
+// seems unnecessary, and it makes the instructions longer.
+static void
+elimshortmov(Graph *g)
+{
+	Prog *p;
+	Flow *r;
+
+	for(r=g->start; r!=nil; r=r->link) {
+		p = r->prog;
+		if(regtyp(&p->to)) {
+			switch(p->as) {
+			case AINCB:
+			case AINCW:
+				p->as = AINCQ;
+				break;
+			case ADECB:
+			case ADECW:
+				p->as = ADECQ;
+				break;
+			case ANEGB:
+			case ANEGW:
+				p->as = ANEGQ;
+				break;
+			case ANOTB:
+			case ANOTW:
+				p->as = ANOTQ;
+				break;
+			}
+			if(regtyp(&p->from) || p->from.type == D_CONST) {
+				// move or artihmetic into partial register.
+				// from another register or constant can be movl.
+				// we don't switch to 64-bit arithmetic if it can
+				// change how the carry bit is set (and the carry bit is needed).
+				switch(p->as) {
+				case AMOVB:
+				case AMOVW:
+					p->as = AMOVQ;
+					break;
+				case AADDB:
+				case AADDW:
+					if(!needc(p->link))
+						p->as = AADDQ;
+					break;
+				case ASUBB:
+				case ASUBW:
+					if(!needc(p->link))
+						p->as = ASUBQ;
+					break;
+				case AMULB:
+				case AMULW:
+					p->as = AMULQ;
+					break;
+				case AIMULB:
+				case AIMULW:
+					p->as = AIMULQ;
+					break;
+				case AANDB:
+				case AANDW:
+					p->as = AANDQ;
+					break;
+				case AORB:
+				case AORW:
+					p->as = AORQ;
+					break;
+				case AXORB:
+				case AXORW:
+					p->as = AXORQ;
+					break;
+				case ASHLB:
+				case ASHLW:
+					p->as = ASHLQ;
+					break;
+				}
+			} else if(p->from.type >= D_NONE) {
+				// explicit zero extension, but don't
+				// do that if source is a byte register
+				// (only AH can occur and it's forbidden).
+				switch(p->as) {
+				case AMOVB:
+					p->as = AMOVBQZX;
+					break;
+				case AMOVW:
+					p->as = AMOVWQZX;
+					break;
+				}
+			}
+		}
+	}
+}
+
+// is 'a' a register or constant?
+static int
+regconsttyp(Adr *a)
+{
+	if(regtyp(a))
+		return 1;
+	switch(a->type) {
+	case D_CONST:
+	case D_FCONST:
+	case D_SCONST:
+	case D_ADDR:
+		return 1;
+	}
+	return 0;
+}
+
+// is reg guaranteed to be truncated by a previous L instruction?
+static int
+prevl(Flow *r0, int reg)
+{
+	Prog *p;
+	Flow *r;
+	ProgInfo info;
+
+	for(r=uniqp(r0); r!=nil; r=uniqp(r)) {
+		p = r->prog;
+		if(p->to.type == reg) {
+			proginfo(&info, p);
+			if(info.flags & RightWrite) {
+				if(info.flags & SizeL)
+					return 1;
+				return 0;
+			}
+		}
+	}
+	return 0;
+}
+
+/*
+ * the idea is to substitute
+ * one register for another
+ * from one MOV to another
+ *	MOV	a, R0
+ *	ADD	b, R0	/ no use of R1
+ *	MOV	R0, R1
+ * would be converted to
+ *	MOV	a, R1
+ *	ADD	b, R1
+ *	MOV	R1, R0
+ * hopefully, then the former or latter MOV
+ * will be eliminated by copy propagation.
+ */
+static int
+subprop(Flow *r0)
+{
+	Prog *p;
+	ProgInfo info;
+	Adr *v1, *v2;
+	Flow *r;
+	int t;
+
+	if(debug['P'] && debug['v'])
+		print("subprop %P\n", r0->prog);
+	p = r0->prog;
+	v1 = &p->from;
+	if(!regtyp(v1)) {
+		if(debug['P'] && debug['v'])
+			print("\tnot regtype %D; return 0\n", v1);
+		return 0;
+	}
+	v2 = &p->to;
+	if(!regtyp(v2)) {
+		if(debug['P'] && debug['v'])
+			print("\tnot regtype %D; return 0\n", v2);
+		return 0;
+	}
+	for(r=uniqp(r0); r!=nil; r=uniqp(r)) {
+		if(debug['P'] && debug['v'])
+			print("\t? %P\n", r->prog);
+		if(uniqs(r) == nil) {
+			if(debug['P'] && debug['v'])
+				print("\tno unique successor\n");
+			break;
+		}
+		p = r->prog;
+		if(p->as == AVARDEF || p->as == AVARKILL)
+			continue;
+		proginfo(&info, p);
+		if(info.flags & Call) {
+			if(debug['P'] && debug['v'])
+				print("\tfound %P; return 0\n", p);
+			return 0;
+		}
+
+		if(info.reguse | info.regset) {
+			if(debug['P'] && debug['v'])
+				print("\tfound %P; return 0\n", p);
+			return 0;
+		}
+
+		if((info.flags & Move) && (info.flags & (SizeL|SizeQ|SizeF|SizeD)) && p->to.type == v1->type)
+			goto gotit;
+
+		if(copyau(&p->from, v2) ||
+		   copyau(&p->to, v2)) {
+		   	if(debug['P'] && debug['v'])
+		   		print("\tcopyau %D failed\n", v2);
+			break;
+		}
+		if(copysub(&p->from, v1, v2, 0) ||
+		   copysub(&p->to, v1, v2, 0)) {
+		   	if(debug['P'] && debug['v'])
+		   		print("\tcopysub failed\n");
+			break;
+		}
+	}
+	if(debug['P'] && debug['v'])
+		print("\tran off end; return 0\n");
+	return 0;
+
+gotit:
+	copysub(&p->to, v1, v2, 1);
+	if(debug['P']) {
+		print("gotit: %D->%D\n%P", v1, v2, r->prog);
+		if(p->from.type == v2->type)
+			print(" excise");
+		print("\n");
+	}
+	for(r=uniqs(r); r!=r0; r=uniqs(r)) {
+		p = r->prog;
+		copysub(&p->from, v1, v2, 1);
+		copysub(&p->to, v1, v2, 1);
+		if(debug['P'])
+			print("%P\n", r->prog);
+	}
+	t = v1->type;
+	v1->type = v2->type;
+	v2->type = t;
+	if(debug['P'])
+		print("%P last\n", r->prog);
+	return 1;
+}
+
+/*
+ * The idea is to remove redundant copies.
+ *	v1->v2	F=0
+ *	(use v2	s/v2/v1/)*
+ *	set v1	F=1
+ *	use v2	return fail
+ *	-----------------
+ *	v1->v2	F=0
+ *	(use v2	s/v2/v1/)*
+ *	set v1	F=1
+ *	set v2	return success
+ */
+static int
+copyprop(Graph *g, Flow *r0)
+{
+	Prog *p;
+	Adr *v1, *v2;
+
+	USED(g);
+	if(debug['P'] && debug['v'])
+		print("copyprop %P\n", r0->prog);
+	p = r0->prog;
+	v1 = &p->from;
+	v2 = &p->to;
+	if(copyas(v1, v2))
+		return 1;
+	gactive++;
+	return copy1(v1, v2, r0->s1, 0);
+}
+
+static int
+copy1(Adr *v1, Adr *v2, Flow *r, int f)
+{
+	int t;
+	Prog *p;
+
+	if(r->active == gactive) {
+		if(debug['P'])
+			print("act set; return 1\n");
+		return 1;
+	}
+	r->active = gactive;
+	if(debug['P'])
+		print("copy %D->%D f=%d\n", v1, v2, f);
+	for(; r != nil; r = r->s1) {
+		p = r->prog;
+		if(debug['P'])
+			print("%P", p);
+		if(!f && uniqp(r) == nil) {
+			f = 1;
+			if(debug['P'])
+				print("; merge; f=%d", f);
+		}
+		t = copyu(p, v2, nil);
+		switch(t) {
+		case 2:	/* rar, can't split */
+			if(debug['P'])
+				print("; %D rar; return 0\n", v2);
+			return 0;
+
+		case 3:	/* set */
+			if(debug['P'])
+				print("; %D set; return 1\n", v2);
+			return 1;
+
+		case 1:	/* used, substitute */
+		case 4:	/* use and set */
+			if(f) {
+				if(!debug['P'])
+					return 0;
+				if(t == 4)
+					print("; %D used+set and f=%d; return 0\n", v2, f);
+				else
+					print("; %D used and f=%d; return 0\n", v2, f);
+				return 0;
+			}
+			if(copyu(p, v2, v1)) {
+				if(debug['P'])
+					print("; sub fail; return 0\n");
+				return 0;
+			}
+			if(debug['P'])
+				print("; sub %D/%D", v2, v1);
+			if(t == 4) {
+				if(debug['P'])
+					print("; %D used+set; return 1\n", v2);
+				return 1;
+			}
+			break;
+		}
+		if(!f) {
+			t = copyu(p, v1, nil);
+			if(!f && (t == 2 || t == 3 || t == 4)) {
+				f = 1;
+				if(debug['P'])
+					print("; %D set and !f; f=%d", v1, f);
+			}
+		}
+		if(debug['P'])
+			print("\n");
+		if(r->s2)
+			if(!copy1(v1, v2, r->s2, f))
+				return 0;
+	}
+	return 1;
+}
+
+/*
+ * return
+ * 1 if v only used (and substitute),
+ * 2 if read-alter-rewrite
+ * 3 if set
+ * 4 if set and used
+ * 0 otherwise (not touched)
+ */
+int
+copyu(Prog *p, Adr *v, Adr *s)
+{
+	ProgInfo info;
+
+	switch(p->as) {
+	case AJMP:
+		if(s != nil) {
+			if(copysub(&p->to, v, s, 1))
+				return 1;
+			return 0;
+		}
+		if(copyau(&p->to, v))
+			return 1;
+		return 0;
+
+	case ARET:
+		if(s != nil)
+			return 1;
+		return 3;
+
+	case ACALL:
+		if(REGEXT && v->type <= REGEXT && v->type > exregoffset)
+			return 2;
+		if(REGARG >= 0 && v->type == (uchar)REGARG)
+			return 2;
+		if(v->type == p->from.type)
+			return 2;
+
+		if(s != nil) {
+			if(copysub(&p->to, v, s, 1))
+				return 1;
+			return 0;
+		}
+		if(copyau(&p->to, v))
+			return 4;
+		return 3;
+
+	case ATEXT:
+		if(REGARG >= 0 && v->type == (uchar)REGARG)
+			return 3;
+		return 0;
+	}
+
+	if(p->as == AVARDEF || p->as == AVARKILL)
+		return 0;
+	proginfo(&info, p);
+
+	if((info.reguse|info.regset) & RtoB(v->type))
+		return 2;
+		
+	if(info.flags & LeftAddr)
+		if(copyas(&p->from, v))
+			return 2;
+
+	if((info.flags & (RightRead|RightWrite)) == (RightRead|RightWrite))
+		if(copyas(&p->to, v))
+			return 2;
+	
+	if(info.flags & RightWrite) {
+		if(copyas(&p->to, v)) {
+			if(s != nil)
+				return copysub(&p->from, v, s, 1);
+			if(copyau(&p->from, v))
+				return 4;
+			return 3;
+		}
+	}
+	
+	if(info.flags & (LeftAddr|LeftRead|LeftWrite|RightAddr|RightRead|RightWrite)) {
+		if(s != nil) {
+			if(copysub(&p->from, v, s, 1))
+				return 1;
+			return copysub(&p->to, v, s, 1);
+		}
+		if(copyau(&p->from, v))
+			return 1;
+		if(copyau(&p->to, v))
+			return 1;
+	}
+
+	return 0;
+}
+
+/*
+ * direct reference,
+ * could be set/use depending on
+ * semantics
+ */
+static int
+copyas(Adr *a, Adr *v)
+{
+	if(D_AL <= a->type && a->type <= D_R15B)
+		fatal("use of byte register");
+	if(D_AL <= v->type && v->type <= D_R15B)
+		fatal("use of byte register");
+
+	if(a->type != v->type)
+		return 0;
+	if(regtyp(v))
+		return 1;
+	if(v->type == D_AUTO || v->type == D_PARAM)
+		if(v->offset == a->offset)
+			return 1;
+	return 0;
+}
+
+int
+sameaddr(Addr *a, Addr *v)
+{
+	if(a->type != v->type)
+		return 0;
+	if(regtyp(v))
+		return 1;
+	if(v->type == D_AUTO || v->type == D_PARAM)
+		if(v->offset == a->offset)
+			return 1;
+	return 0;
+}
+
+/*
+ * either direct or indirect
+ */
+static int
+copyau(Adr *a, Adr *v)
+{
+
+	if(copyas(a, v)) {
+		if(debug['P'] && debug['v'])
+			print("\tcopyau: copyas returned 1\n");
+		return 1;
+	}
+	if(regtyp(v)) {
+		if(a->type-D_INDIR == v->type) {
+			if(debug['P'] && debug['v'])
+				print("\tcopyau: found indir use - return 1\n");
+			return 1;
+		}
+		if(a->index == v->type) {
+			if(debug['P'] && debug['v'])
+				print("\tcopyau: found index use - return 1\n");
+			return 1;
+		}
+	}
+	return 0;
+}
+
+/*
+ * substitute s for v in a
+ * return failure to substitute
+ */
+static int
+copysub(Adr *a, Adr *v, Adr *s, int f)
+{
+	int t;
+
+	if(copyas(a, v)) {
+		t = s->type;
+		if(t >= D_AX && t <= D_R15 || t >= D_X0 && t <= D_X0+15) {
+			if(f)
+				a->type = t;
+		}
+		return 0;
+	}
+	if(regtyp(v)) {
+		t = v->type;
+		if(a->type == t+D_INDIR) {
+			if((s->type == D_BP || s->type == D_R13) && a->index != D_NONE)
+				return 1;	/* can't use BP-base with index */
+			if(f)
+				a->type = s->type+D_INDIR;
+//			return 0;
+		}
+		if(a->index == t) {
+			if(f)
+				a->index = s->type;
+			return 0;
+		}
+		return 0;
+	}
+	return 0;
+}
+
+static void
+conprop(Flow *r0)
+{
+	Flow *r;
+	Prog *p, *p0;
+	int t;
+	Adr *v0;
+
+	p0 = r0->prog;
+	v0 = &p0->to;
+	r = r0;
+
+loop:
+	r = uniqs(r);
+	if(r == nil || r == r0)
+		return;
+	if(uniqp(r) == nil)
+		return;
+
+	p = r->prog;
+	t = copyu(p, v0, nil);
+	switch(t) {
+	case 0:	// miss
+	case 1:	// use
+		goto loop;
+
+	case 2:	// rar
+	case 4:	// use and set
+		break;
+
+	case 3:	// set
+		if(p->as == p0->as)
+		if(p->from.type == p0->from.type)
+		if(p->from.node == p0->from.node)
+		if(p->from.offset == p0->from.offset)
+		if(p->from.scale == p0->from.scale)
+		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;
+		}
+		break;
+	}
+}
+
+int
+smallindir(Addr *a, Addr *reg)
+{
+	return regtyp(reg) &&
+		a->type == D_INDIR + reg->type &&
+		a->index == D_NONE &&
+		0 <= a->offset && a->offset < 4096;
+}
+
+int
+stackaddr(Addr *a)
+{
+	return regtyp(a) && a->type == D_SP;
+}
diff --git a/src/cmd/6g/prog.c b/src/cmd/6g/prog.c
new file mode 100644
index 0000000..ee68399
--- /dev/null
+++ b/src/cmd/6g/prog.c
@@ -0,0 +1,318 @@
+// 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 "gg.h"
+#include "opt.h"
+
+// Matches real RtoB but can be used in global initializer.
+#define RtoB(r) (1<<((r)-D_AX))
+
+enum {
+	AX = RtoB(D_AX),
+	BX = RtoB(D_BX),
+	CX = RtoB(D_CX),
+	DX = RtoB(D_DX),
+	DI = RtoB(D_DI),
+	SI = RtoB(D_SI),
+	
+	LeftRdwr = LeftRead | LeftWrite,
+	RightRdwr = RightRead | RightWrite,
+};
+
+#undef RtoB
+
+// This table gives the basic information about instruction
+// generated by the compiler and processed in the optimizer.
+// See opt.h for bit definitions.
+//
+// Instructions not generated need not be listed.
+// As an exception to that rule, we typically write down all the
+// size variants of an operation even if we just use a subset.
+//
+// The table is formatted for 8-space tabs.
+static ProgInfo progtable[ALAST] = {
+	[ATYPE]=	{Pseudo | Skip},
+	[ATEXT]=	{Pseudo},
+	[AFUNCDATA]=	{Pseudo},
+	[APCDATA]=	{Pseudo},
+	[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.
+	[ANOP]=		{LeftRead | RightWrite},
+
+	[AADCL]=	{SizeL | LeftRead | RightRdwr | SetCarry | UseCarry},
+	[AADCQ]=	{SizeQ | LeftRead | RightRdwr | SetCarry | UseCarry},
+	[AADCW]=	{SizeW | LeftRead | RightRdwr | SetCarry | UseCarry},
+
+	[AADDB]=	{SizeB | LeftRead | RightRdwr | SetCarry},
+	[AADDL]=	{SizeL | LeftRead | RightRdwr | SetCarry},
+	[AADDW]=	{SizeW | LeftRead | RightRdwr | SetCarry},
+	[AADDQ]=	{SizeQ | LeftRead | RightRdwr | SetCarry},
+	
+	[AADDSD]=	{SizeD | LeftRead | RightRdwr},
+	[AADDSS]=	{SizeF | LeftRead | RightRdwr},
+
+	[AANDB]=	{SizeB | LeftRead | RightRdwr | SetCarry},
+	[AANDL]=	{SizeL | LeftRead | RightRdwr | SetCarry},
+	[AANDQ]=	{SizeQ | LeftRead | RightRdwr | SetCarry},
+	[AANDW]=	{SizeW | LeftRead | RightRdwr | SetCarry},
+
+	[ACALL]=	{RightAddr | Call | KillCarry},
+
+	[ACDQ]=		{OK, AX, AX | DX},
+	[ACQO]=		{OK, AX, AX | DX},
+	[ACWD]=		{OK, AX, AX | DX},
+
+	[ACLD]=		{OK},
+	[ASTD]=		{OK},
+
+	[ACMPB]=	{SizeB | LeftRead | RightRead | SetCarry},
+	[ACMPL]=	{SizeL | LeftRead | RightRead | SetCarry},
+	[ACMPQ]=	{SizeQ | LeftRead | RightRead | SetCarry},
+	[ACMPW]=	{SizeW | LeftRead | RightRead | SetCarry},
+
+	[ACOMISD]=	{SizeD | LeftRead | RightRead | SetCarry},
+	[ACOMISS]=	{SizeF | LeftRead | RightRead | SetCarry},
+
+	[ACVTSD2SL]=	{SizeL | LeftRead | RightWrite | Conv},
+	[ACVTSD2SQ]=	{SizeQ | LeftRead | RightWrite | Conv},
+	[ACVTSD2SS]=	{SizeF | LeftRead | RightWrite | Conv},
+	[ACVTSL2SD]=	{SizeD | LeftRead | RightWrite | Conv},
+	[ACVTSL2SS]=	{SizeF | LeftRead | RightWrite | Conv},
+	[ACVTSQ2SD]=	{SizeD | LeftRead | RightWrite | Conv},
+	[ACVTSQ2SS]=	{SizeF | LeftRead | RightWrite | Conv},
+	[ACVTSS2SD]=	{SizeD | LeftRead | RightWrite | Conv},
+	[ACVTSS2SL]=	{SizeL | LeftRead | RightWrite | Conv},
+	[ACVTSS2SQ]=	{SizeQ | LeftRead | RightWrite | Conv},
+	[ACVTTSD2SL]=	{SizeL | LeftRead | RightWrite | Conv},
+	[ACVTTSD2SQ]=	{SizeQ | LeftRead | RightWrite | Conv},
+	[ACVTTSS2SL]=	{SizeL | LeftRead | RightWrite | Conv},
+	[ACVTTSS2SQ]=	{SizeQ | LeftRead | RightWrite | Conv},
+
+	[ADECB]=	{SizeB | RightRdwr},
+	[ADECL]=	{SizeL | RightRdwr},
+	[ADECQ]=	{SizeQ | RightRdwr},
+	[ADECW]=	{SizeW | RightRdwr},
+
+	[ADIVB]=	{SizeB | LeftRead | SetCarry, AX, AX},
+	[ADIVL]=	{SizeL | LeftRead | SetCarry, AX|DX, AX|DX},
+	[ADIVQ]=	{SizeQ | LeftRead | SetCarry, AX|DX, AX|DX},
+	[ADIVW]=	{SizeW | LeftRead | SetCarry, AX|DX, AX|DX},
+
+	[ADIVSD]=	{SizeD | LeftRead | RightRdwr},
+	[ADIVSS]=	{SizeF | LeftRead | RightRdwr},
+
+	[AIDIVB]=	{SizeB | LeftRead | SetCarry, AX, AX},
+	[AIDIVL]=	{SizeL | LeftRead | SetCarry, AX|DX, AX|DX},
+	[AIDIVQ]=	{SizeQ | LeftRead | SetCarry, AX|DX, AX|DX},
+	[AIDIVW]=	{SizeW | LeftRead | SetCarry, AX|DX, AX|DX},
+
+	[AIMULB]=	{SizeB | LeftRead | SetCarry, AX, AX},
+	[AIMULL]=	{SizeL | LeftRead | ImulAXDX | SetCarry},
+	[AIMULQ]=	{SizeQ | LeftRead | ImulAXDX | SetCarry},
+	[AIMULW]=	{SizeW | LeftRead | ImulAXDX | SetCarry},
+
+	[AINCB]=	{SizeB | RightRdwr},
+	[AINCL]=	{SizeL | RightRdwr},
+	[AINCQ]=	{SizeQ | RightRdwr},
+	[AINCW]=	{SizeW | RightRdwr},
+
+	[AJCC]=		{Cjmp | UseCarry},
+	[AJCS]=		{Cjmp | UseCarry},
+	[AJEQ]=		{Cjmp | UseCarry},
+	[AJGE]=		{Cjmp | UseCarry},
+	[AJGT]=		{Cjmp | UseCarry},
+	[AJHI]=		{Cjmp | UseCarry},
+	[AJLE]=		{Cjmp | UseCarry},
+	[AJLS]=		{Cjmp | UseCarry},
+	[AJLT]=		{Cjmp | UseCarry},
+	[AJMI]=		{Cjmp | UseCarry},
+	[AJNE]=		{Cjmp | UseCarry},
+	[AJOC]=		{Cjmp | UseCarry},
+	[AJOS]=		{Cjmp | UseCarry},
+	[AJPC]=		{Cjmp | UseCarry},
+	[AJPL]=		{Cjmp | UseCarry},
+	[AJPS]=		{Cjmp | UseCarry},
+
+	[AJMP]=		{Jump | Break | KillCarry},
+
+	[ALEAL]=	{LeftAddr | RightWrite},
+	[ALEAQ]=	{LeftAddr | RightWrite},
+
+	[AMOVBLSX]=	{SizeL | LeftRead | RightWrite | Conv},
+	[AMOVBLZX]=	{SizeL | LeftRead | RightWrite | Conv},
+	[AMOVBQSX]=	{SizeQ | LeftRead | RightWrite | Conv},
+	[AMOVBQZX]=	{SizeQ | LeftRead | RightWrite | Conv},
+	[AMOVBWSX]=	{SizeW | LeftRead | RightWrite | Conv},
+	[AMOVBWZX]=	{SizeW | LeftRead | RightWrite | Conv},
+	[AMOVLQSX]=	{SizeQ | LeftRead | RightWrite | Conv},
+	[AMOVLQZX]=	{SizeQ | LeftRead | RightWrite | Conv},
+	[AMOVWLSX]=	{SizeL | LeftRead | RightWrite | Conv},
+	[AMOVWLZX]=	{SizeL | LeftRead | RightWrite | Conv},
+	[AMOVWQSX]=	{SizeQ | LeftRead | RightWrite | Conv},
+	[AMOVWQZX]=	{SizeQ | LeftRead | RightWrite | Conv},
+	[AMOVQL]=	{SizeL | LeftRead | RightWrite | Conv},
+
+	[AMOVB]=	{SizeB | LeftRead | RightWrite | Move},
+	[AMOVL]=	{SizeL | LeftRead | RightWrite | Move},
+	[AMOVQ]=	{SizeQ | LeftRead | RightWrite | Move},
+	[AMOVW]=	{SizeW | LeftRead | RightWrite | Move},
+
+	[AMOVSB]=	{OK, DI|SI, DI|SI},
+	[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},
+
+	// We use MOVAPD as a faster synonym for MOVSD.
+	[AMOVAPD]=	{SizeD | LeftRead | RightWrite | Move},
+
+	[AMULB]=	{SizeB | LeftRead | SetCarry, AX, AX},
+	[AMULL]=	{SizeL | LeftRead | SetCarry, AX, AX|DX},
+	[AMULQ]=	{SizeQ | LeftRead | SetCarry, AX, AX|DX},
+	[AMULW]=	{SizeW | LeftRead | SetCarry, AX, AX|DX},
+	
+	[AMULSD]=	{SizeD | LeftRead | RightRdwr},
+	[AMULSS]=	{SizeF | LeftRead | RightRdwr},
+
+	[ANEGB]=	{SizeB | RightRdwr | SetCarry},
+	[ANEGL]=	{SizeL | RightRdwr | SetCarry},
+	[ANEGQ]=	{SizeQ | RightRdwr | SetCarry},
+	[ANEGW]=	{SizeW | RightRdwr | SetCarry},
+
+	[ANOTB]=	{SizeB | RightRdwr},
+	[ANOTL]=	{SizeL | RightRdwr},
+	[ANOTQ]=	{SizeQ | RightRdwr},
+	[ANOTW]=	{SizeW | RightRdwr},
+
+	[AORB]=		{SizeB | LeftRead | RightRdwr | SetCarry},
+	[AORL]=		{SizeL | LeftRead | RightRdwr | SetCarry},
+	[AORQ]=		{SizeQ | LeftRead | RightRdwr | SetCarry},
+	[AORW]=		{SizeW | LeftRead | RightRdwr | SetCarry},
+
+	[APOPQ]=	{SizeQ | RightWrite},
+	[APUSHQ]=	{SizeQ | LeftRead},
+
+	[ARCLB]=	{SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry | UseCarry},
+	[ARCLL]=	{SizeL | LeftRead | RightRdwr | ShiftCX | SetCarry | UseCarry},
+	[ARCLQ]=	{SizeQ | LeftRead | RightRdwr | ShiftCX | SetCarry | UseCarry},
+	[ARCLW]=	{SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry | UseCarry},
+
+	[ARCRB]=	{SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry | UseCarry},
+	[ARCRL]=	{SizeL | LeftRead | RightRdwr | ShiftCX | SetCarry | UseCarry},
+	[ARCRQ]=	{SizeQ | LeftRead | RightRdwr | ShiftCX | SetCarry | UseCarry},
+	[ARCRW]=	{SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry | UseCarry},
+
+	[AREP]=		{OK, CX, CX},
+	[AREPN]=	{OK, CX, CX},
+
+	[ARET]=		{Break | KillCarry},
+
+	[AROLB]=	{SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry},
+	[AROLL]=	{SizeL | LeftRead | RightRdwr | ShiftCX | SetCarry},
+	[AROLQ]=	{SizeQ | LeftRead | RightRdwr | ShiftCX | SetCarry},
+	[AROLW]=	{SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry},
+
+	[ARORB]=	{SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry},
+	[ARORL]=	{SizeL | LeftRead | RightRdwr | ShiftCX | SetCarry},
+	[ARORQ]=	{SizeQ | LeftRead | RightRdwr | ShiftCX | SetCarry},
+	[ARORW]=	{SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry},
+
+	[ASALB]=	{SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry},
+	[ASALL]=	{SizeL | LeftRead | RightRdwr | ShiftCX | SetCarry},
+	[ASALQ]=	{SizeQ | LeftRead | RightRdwr | ShiftCX | SetCarry},
+	[ASALW]=	{SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry},
+
+	[ASARB]=	{SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry},
+	[ASARL]=	{SizeL | LeftRead | RightRdwr | ShiftCX | SetCarry},
+	[ASARQ]=	{SizeQ | LeftRead | RightRdwr | ShiftCX | SetCarry},
+	[ASARW]=	{SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry},
+
+	[ASBBB]=	{SizeB | LeftRead | RightRdwr | SetCarry | UseCarry},
+	[ASBBL]=	{SizeL | LeftRead | RightRdwr | SetCarry | UseCarry},
+	[ASBBQ]=	{SizeQ | LeftRead | RightRdwr | SetCarry | UseCarry},
+	[ASBBW]=	{SizeW | LeftRead | RightRdwr | SetCarry | UseCarry},
+
+	[ASHLB]=	{SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry},
+	[ASHLL]=	{SizeL | LeftRead | RightRdwr | ShiftCX | SetCarry},
+	[ASHLQ]=	{SizeQ | LeftRead | RightRdwr | ShiftCX | SetCarry},
+	[ASHLW]=	{SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry},
+
+	[ASHRB]=	{SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry},
+	[ASHRL]=	{SizeL | LeftRead | RightRdwr | ShiftCX | SetCarry},
+	[ASHRQ]=	{SizeQ | LeftRead | RightRdwr | ShiftCX | SetCarry},
+	[ASHRW]=	{SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry},
+
+	[ASTOSB]=	{OK, AX|DI, DI},
+	[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},
+	[ASUBQ]=	{SizeQ | LeftRead | RightRdwr | SetCarry},
+	[ASUBW]=	{SizeW | LeftRead | RightRdwr | SetCarry},
+
+	[ASUBSD]=	{SizeD | LeftRead | RightRdwr},
+	[ASUBSS]=	{SizeF | LeftRead | RightRdwr},
+
+	[ATESTB]=	{SizeB | LeftRead | RightRead | SetCarry},
+	[ATESTL]=	{SizeL | LeftRead | RightRead | SetCarry},
+	[ATESTQ]=	{SizeQ | LeftRead | RightRead | SetCarry},
+	[ATESTW]=	{SizeW | LeftRead | RightRead | SetCarry},
+
+	[AUCOMISD]=	{SizeD | LeftRead | RightRead},
+	[AUCOMISS]=	{SizeF | LeftRead | RightRead},
+
+	[AXCHGB]=	{SizeB | LeftRdwr | RightRdwr},
+	[AXCHGL]=	{SizeL | LeftRdwr | RightRdwr},
+	[AXCHGQ]=	{SizeQ | LeftRdwr | RightRdwr},
+	[AXCHGW]=	{SizeW | LeftRdwr | RightRdwr},
+
+	[AXORB]=	{SizeB | LeftRead | RightRdwr | SetCarry},
+	[AXORL]=	{SizeL | LeftRead | RightRdwr | SetCarry},
+	[AXORQ]=	{SizeQ | LeftRead | RightRdwr | SetCarry},
+	[AXORW]=	{SizeW | LeftRead | RightRdwr | SetCarry},
+};
+
+void
+proginfo(ProgInfo *info, Prog *p)
+{
+	*info = progtable[p->as];
+	if(info->flags == 0)
+		fatal("unknown instruction %P", p);
+
+	if((info->flags & ShiftCX) && p->from.type != D_CONST)
+		info->reguse |= CX;
+
+	if(info->flags & ImulAXDX) {
+		if(p->to.type == D_NONE) {
+			info->reguse |= AX;
+			info->regset |= AX | DX;
+		} else {
+			info->flags |= RightRdwr;
+		}
+	}
+
+	// Addressing makes some registers used.
+	if(p->from.type >= D_INDIR)
+		info->regindex |= RtoB(p->from.type-D_INDIR);
+	if(p->from.index != D_NONE)
+		info->regindex |= RtoB(p->from.index);
+	if(p->to.type >= D_INDIR)
+		info->regindex |= RtoB(p->to.type-D_INDIR);
+	if(p->to.index != D_NONE)
+		info->regindex |= RtoB(p->to.index);
+}
diff --git a/src/cmd/6g/reg.c b/src/cmd/6g/reg.c
new file mode 100644
index 0000000..1f757e1
--- /dev/null
+++ b/src/cmd/6g/reg.c
@@ -0,0 +1,1315 @@
+// Derived from Inferno utils/6c/reg.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/reg.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"
+#include "opt.h"
+
+#define	NREGVAR	32	/* 16 general + 16 floating */
+#define	REGBITS	((uint32)0xffffffff)
+/*c2go enum {
+	NREGVAR = 32,
+	REGBITS = 0xffffffff,
+};
+*/
+
+static	Reg*	firstr;
+static	int	first	= 1;
+
+int
+rcmp(const void *a1, const void *a2)
+{
+	Rgn *p1, *p2;
+	int c1, c2;
+
+	p1 = (Rgn*)a1;
+	p2 = (Rgn*)a2;
+	c1 = p2->cost;
+	c2 = p1->cost;
+	if(c1 -= c2)
+		return c1;
+	return p2->varno - p1->varno;
+}
+
+static void
+setaddrs(Bits bit)
+{
+	int i, n;
+	Var *v;
+	Node *node;
+
+	while(bany(&bit)) {
+		// convert each bit to a variable
+		i = bnum(bit);
+		node = var[i].node;
+		n = var[i].name;
+		bit.b[i/32] &= ~(1L<<(i%32));
+
+		// disable all pieces of that variable
+		for(i=0; i<nvar; i++) {
+			v = var+i;
+			if(v->node == node && v->name == n)
+				v->addr = 2;
+		}
+	}
+}
+
+static char* regname[] = {
+	".AX",
+	".CX",
+	".DX",
+	".BX",
+	".SP",
+	".BP",
+	".SI",
+	".DI",
+	".R8",
+	".R9",
+	".R10",
+	".R11",
+	".R12",
+	".R13",
+	".R14",
+	".R15",
+	".X0",
+	".X1",
+	".X2",
+	".X3",
+	".X4",
+	".X5",
+	".X6",
+	".X7",
+	".X8",
+	".X9",
+	".X10",
+	".X11",
+	".X12",
+	".X13",
+	".X14",
+	".X15",
+};
+
+static Node* regnodes[NREGVAR];
+
+static void walkvardef(Node *n, Reg *r, int active);
+
+void
+regopt(Prog *firstp)
+{
+	Reg *r, *r1;
+	Prog *p;
+	Graph *g;
+	ProgInfo info;
+	int i, z, active;
+	uint32 vreg;
+	Bits bit;
+
+	if(first) {
+		fmtinstall('Q', Qconv);
+		exregoffset = D_R15;
+		first = 0;
+	}
+
+	mergetemp(firstp);
+
+	/*
+	 * control flow is more complicated in generated go code
+	 * than in generated c code.  define pseudo-variables for
+	 * registers, so we have complete register usage information.
+	 */
+	nvar = NREGVAR;
+	memset(var, 0, NREGVAR*sizeof var[0]);
+	for(i=0; i<NREGVAR; i++) {
+		if(regnodes[i] == N)
+			regnodes[i] = newname(lookup(regname[i]));
+		var[i].node = regnodes[i];
+	}
+
+	regbits = RtoB(D_SP);
+	for(z=0; z<BITS; z++) {
+		externs.b[z] = 0;
+		params.b[z] = 0;
+		consts.b[z] = 0;
+		addrs.b[z] = 0;
+		ivar.b[z] = 0;
+		ovar.b[z] = 0;
+	}
+
+	/*
+	 * pass 1
+	 * build aux data structure
+	 * allocate pcs
+	 * find use and set of variables
+	 */
+	g = flowstart(firstp, sizeof(Reg));
+	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.
+		if(p->as == ACALL && p->to.type == D_EXTERN)
+			continue;
+
+		r->use1.b[0] |= info.reguse | info.regindex;
+		r->set.b[0] |= info.regset;
+
+		bit = mkvar(r, &p->from);
+		if(bany(&bit)) {
+			if(info.flags & LeftAddr)
+				setaddrs(bit);
+			if(info.flags & LeftRead)
+				for(z=0; z<BITS; z++)
+					r->use1.b[z] |= bit.b[z];
+			if(info.flags & LeftWrite)
+				for(z=0; z<BITS; z++)
+					r->set.b[z] |= bit.b[z];
+		}
+
+		bit = mkvar(r, &p->to);
+		if(bany(&bit)) {	
+			if(info.flags & RightAddr)
+				setaddrs(bit);
+			if(info.flags & RightRead)
+				for(z=0; z<BITS; z++)
+					r->use2.b[z] |= bit.b[z];
+			if(info.flags & RightWrite)
+				for(z=0; z<BITS; z++)
+					r->set.b[z] |= bit.b[z];
+		}
+	}
+
+	for(i=0; i<nvar; i++) {
+		Var *v = var+i;
+		if(v->addr) {
+			bit = blsh(i);
+			for(z=0; z<BITS; z++)
+				addrs.b[z] |= bit.b[z];
+		}
+
+		if(debug['R'] && debug['v'])
+			print("bit=%2d addr=%d et=%-6E w=%-2d s=%N + %lld\n",
+				i, v->addr, v->etype, v->width, v->node, v->offset);
+	}
+
+	if(debug['R'] && debug['v'])
+		dumpit("pass1", &firstr->f, 1);
+
+	/*
+	 * pass 2
+	 * find looping structure
+	 */
+	flowrpo(g);
+
+	if(debug['R'] && debug['v'])
+		dumpit("pass2", &firstr->f, 1);
+
+	/*
+	 * pass 2.5
+	 * iterate propagating fat vardef covering forward
+	 * r->act records vars with a VARDEF since the last CALL.
+	 * (r->act will be reused in pass 5 for something else,
+	 * but we'll be done with it by then.)
+	 */
+	active = 0;
+	for(r = firstr; r != R; r = (Reg*)r->f.link) {
+		r->f.active = 0;
+		r->act = zbits;
+	}
+	for(r = firstr; r != R; r = (Reg*)r->f.link) {
+		p = r->f.prog;
+		if(p->as == AVARDEF && isfat(p->to.node->type) && p->to.node->opt != nil) {
+			active++;
+			walkvardef(p->to.node, r, active);
+		}
+	}
+
+	/*
+	 * pass 3
+	 * iterate propagating usage
+	 * 	back until flow graph is complete
+	 */
+loop1:
+	change = 0;
+	for(r = firstr; r != R; r = (Reg*)r->f.link)
+		r->f.active = 0;
+	for(r = firstr; r != R; r = (Reg*)r->f.link)
+		if(r->f.prog->as == ARET)
+			prop(r, zbits, zbits);
+loop11:
+	/* pick up unreachable code */
+	i = 0;
+	for(r = firstr; r != R; r = r1) {
+		r1 = (Reg*)r->f.link;
+		if(r1 && r1->f.active && !r->f.active) {
+			prop(r, zbits, zbits);
+			i = 1;
+		}
+	}
+	if(i)
+		goto loop11;
+	if(change)
+		goto loop1;
+
+	if(debug['R'] && debug['v'])
+		dumpit("pass3", &firstr->f, 1);
+
+	/*
+	 * pass 4
+	 * iterate propagating register/variable synchrony
+	 * 	forward until graph is complete
+	 */
+loop2:
+	change = 0;
+	for(r = firstr; r != R; r = (Reg*)r->f.link)
+		r->f.active = 0;
+	synch(firstr, zbits);
+	if(change)
+		goto loop2;
+
+	if(debug['R'] && debug['v'])
+		dumpit("pass4", &firstr->f, 1);
+
+	/*
+	 * pass 4.5
+	 * move register pseudo-variables into regu.
+	 */
+	for(r = firstr; r != R; r = (Reg*)r->f.link) {
+		r->regu = (r->refbehind.b[0] | r->set.b[0]) & REGBITS;
+
+		r->set.b[0] &= ~REGBITS;
+		r->use1.b[0] &= ~REGBITS;
+		r->use2.b[0] &= ~REGBITS;
+		r->refbehind.b[0] &= ~REGBITS;
+		r->refahead.b[0] &= ~REGBITS;
+		r->calbehind.b[0] &= ~REGBITS;
+		r->calahead.b[0] &= ~REGBITS;
+		r->regdiff.b[0] &= ~REGBITS;
+		r->act.b[0] &= ~REGBITS;
+	}
+
+	/*
+	 * pass 5
+	 * isolate regions
+	 * calculate costs (paint1)
+	 */
+	r = firstr;
+	if(r) {
+		for(z=0; z<BITS; z++)
+			bit.b[z] = (r->refahead.b[z] | r->calahead.b[z]) &
+			  ~(externs.b[z] | params.b[z] | addrs.b[z] | consts.b[z]);
+		if(bany(&bit) && !r->f.refset) {
+			// should never happen - all variables are preset
+			if(debug['w'])
+				print("%L: used and not set: %Q\n", r->f.prog->lineno, bit);
+			r->f.refset = 1;
+		}
+	}
+	for(r = firstr; r != R; r = (Reg*)r->f.link)
+		r->act = zbits;
+	rgp = region;
+	nregion = 0;
+	for(r = firstr; r != R; r = (Reg*)r->f.link) {
+		for(z=0; z<BITS; z++)
+			bit.b[z] = r->set.b[z] &
+			  ~(r->refahead.b[z] | r->calahead.b[z] | addrs.b[z]);
+		if(bany(&bit) && !r->f.refset) {
+			if(debug['w'])
+				print("%L: set and not used: %Q\n", r->f.prog->lineno, bit);
+			r->f.refset = 1;
+			excise(&r->f);
+		}
+		for(z=0; z<BITS; z++)
+			bit.b[z] = LOAD(r) & ~(r->act.b[z] | addrs.b[z]);
+		while(bany(&bit)) {
+			i = bnum(bit);
+			rgp->enter = r;
+			rgp->varno = i;
+			change = 0;
+			paint1(r, i);
+			bit.b[i/32] &= ~(1L<<(i%32));
+			if(change <= 0)
+				continue;
+			rgp->cost = change;
+			nregion++;
+			if(nregion >= NRGN) {
+				if(debug['R'] && debug['v'])
+					print("too many regions\n");
+				goto brk;
+			}
+			rgp++;
+		}
+	}
+brk:
+	qsort(region, nregion, sizeof(region[0]), rcmp);
+
+	if(debug['R'] && debug['v'])
+		dumpit("pass5", &firstr->f, 1);
+
+	/*
+	 * pass 6
+	 * determine used registers (paint2)
+	 * replace code (paint3)
+	 */
+	rgp = region;
+	for(i=0; i<nregion; i++) {
+		bit = blsh(rgp->varno);
+		vreg = paint2(rgp->enter, rgp->varno);
+		vreg = allreg(vreg, rgp);
+		if(rgp->regno != 0) {
+			if(debug['R'] && debug['v']) {
+				Var *v;
+
+				v = var + rgp->varno;
+				print("registerize %N+%lld (bit=%2d et=%2E) in %R\n",
+						v->node, v->offset, rgp->varno, v->etype, rgp->regno);
+			}
+			paint3(rgp->enter, rgp->varno, vreg, rgp->regno);
+		}
+		rgp++;
+	}
+
+	if(debug['R'] && debug['v'])
+		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
+	 */
+	if(!debug['R'] || debug['P'])
+		peep(firstp);
+
+	/*
+	 * eliminate nops
+	 */
+	for(p=firstp; p!=P; p=p->link) {
+		while(p->link != P && p->link->as == ANOP)
+			p->link = p->link->link;
+		if(p->to.type == D_BRANCH)
+			while(p->to.u.branch != P && p->to.u.branch->as == ANOP)
+				p->to.u.branch = p->to.u.branch->link;
+	}
+
+	if(debug['R']) {
+		if(ostats.ncvtreg ||
+		   ostats.nspill ||
+		   ostats.nreload ||
+		   ostats.ndelmov ||
+		   ostats.nvar ||
+		   ostats.naddr ||
+		   0)
+			print("\nstats\n");
+
+		if(ostats.ncvtreg)
+			print("	%4d cvtreg\n", ostats.ncvtreg);
+		if(ostats.nspill)
+			print("	%4d spill\n", ostats.nspill);
+		if(ostats.nreload)
+			print("	%4d reload\n", ostats.nreload);
+		if(ostats.ndelmov)
+			print("	%4d delmov\n", ostats.ndelmov);
+		if(ostats.nvar)
+			print("	%4d var\n", ostats.nvar);
+		if(ostats.naddr)
+			print("	%4d addr\n", ostats.naddr);
+
+		memset(&ostats, 0, sizeof(ostats));
+	}
+}
+
+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
+ */
+void
+addmove(Reg *r, int bn, int rn, int f)
+{
+	Prog *p, *p1;
+	Adr *a;
+	Var *v;
+
+	p1 = mal(sizeof(*p1));
+	clearp(p1);
+	p1->pc = 9999;
+
+	p = r->f.prog;
+	p1->link = p->link;
+	p->link = p1;
+	p1->lineno = p->lineno;
+
+	v = var + bn;
+
+	a = &p1->to;
+	a->offset = v->offset;
+	a->etype = v->etype;
+	a->type = v->name;
+	a->node = v->node;
+	a->sym = linksym(v->node->sym);
+
+	// need to clean this up with wptr and
+	// some of the defaults
+	p1->as = AMOVL;
+	switch(simtype[(uchar)v->etype]) {
+	default:
+		fatal("unknown type %E", v->etype);
+	case TINT8:
+	case TUINT8:
+	case TBOOL:
+		p1->as = AMOVB;
+		break;
+	case TINT16:
+	case TUINT16:
+		p1->as = AMOVW;
+		break;
+	case TINT64:
+	case TUINT64:
+	case TPTR64:
+		p1->as = AMOVQ;
+		break;
+	case TFLOAT32:
+		p1->as = AMOVSS;
+		break;
+	case TFLOAT64:
+		p1->as = AMOVSD;
+		break;
+	case TINT32:
+	case TUINT32:
+	case TPTR32:
+		break;
+	}
+
+	p1->from.type = rn;
+	if(!f) {
+		p1->from = *a;
+		*a = zprog.from;
+		a->type = rn;
+		if(v->etype == TUINT8)
+			p1->as = AMOVB;
+		if(v->etype == TUINT16)
+			p1->as = AMOVW;
+	}
+	if(debug['R'] && debug['v'])
+		print("%P ===add=== %P\n", p, p1);
+	ostats.nspill++;
+}
+
+uint32
+doregbits(int r)
+{
+	uint32 b;
+
+	b = 0;
+	if(r >= D_INDIR)
+		r -= D_INDIR;
+	if(r >= D_AX && r <= D_R15)
+		b |= RtoB(r);
+	else
+	if(r >= D_AL && r <= D_R15B)
+		b |= RtoB(r-D_AL+D_AX);
+	else
+	if(r >= D_AH && r <= D_BH)
+		b |= RtoB(r-D_AH+D_AX);
+	else
+	if(r >= D_X0 && r <= D_X0+15)
+		b |= FtoB(r);
+	return b;
+}
+
+static int
+overlap(int64 o1, int w1, int64 o2, int w2)
+{
+	int64 t1, t2;
+
+	t1 = o1+w1;
+	t2 = o2+w2;
+
+	if(!(t1 > o2 && t2 > o1))
+		return 0;
+
+	return 1;
+}
+
+Bits
+mkvar(Reg *r, Adr *a)
+{
+	Var *v;
+	int i, t, n, et, z, flag;
+	int64 w;
+	uint32 regu;
+	int64 o;
+	Bits bit;
+	Node *node;
+
+	/*
+	 * mark registers used
+	 */
+	t = a->type;
+	if(t == D_NONE)
+		goto none;
+
+	if(r != R)
+		r->use1.b[0] |= doregbits(a->index);
+
+	switch(t) {
+	default:
+		regu = doregbits(t);
+		if(regu == 0)
+			goto none;
+		bit = zbits;
+		bit.b[0] = regu;
+		return bit;
+
+	case D_ADDR:
+		a->type = a->index;
+		bit = mkvar(r, a);
+		setaddrs(bit);
+		a->type = t;
+		ostats.naddr++;
+		goto none;
+
+	case D_EXTERN:
+	case D_STATIC:
+	case D_PARAM:
+	case D_AUTO:
+		n = t;
+		break;
+	}
+
+	node = a->node;
+	if(node == N || node->op != ONAME || node->orig == N)
+		goto none;
+	node = node->orig;
+	if(node->orig != node)
+		fatal("%D: bad node", a);
+	if(node->sym == S || node->sym->name[0] == '.')
+		goto none;
+	et = a->etype;
+	o = a->offset;
+	w = a->width;
+	if(w < 0)
+		fatal("bad width %lld for %D", w, a);
+
+	flag = 0;
+	for(i=0; i<nvar; i++) {
+		v = var+i;
+		if(v->node == node && v->name == n) {
+			if(v->offset == o)
+			if(v->etype == et)
+			if(v->width == w)
+				return blsh(i);
+
+			// if they overlaps, disable both
+			if(overlap(v->offset, v->width, o, w)) {
+//				print("disable overlap %s %d %d %d %d, %E != %E\n", s->name, v->offset, v->width, o, w, v->etype, et);
+				v->addr = 1;
+				flag = 1;
+			}
+		}
+	}
+	switch(et) {
+	case 0:
+	case TFUNC:
+		goto none;
+	}
+
+	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;
+	}
+
+	i = nvar;
+	nvar++;
+	v = var+i;
+	v->offset = o;
+	v->name = n;
+	v->etype = et;
+	v->width = w;
+	v->addr = flag;		// funny punning
+	v->node = node;
+	
+	// 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++)
+			externs.b[z] |= bit.b[z];
+	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=%lld+%lld %#N %D flag=%d\n", i, et, o, w, node, a, v->addr);
+	ostats.nvar++;
+
+	return bit;
+
+none:
+	return zbits;
+}
+
+void
+prop(Reg *r, Bits ref, Bits cal)
+{
+	Reg *r1, *r2;
+	int z, i, j;
+	Var *v, *v1;
+
+	for(r1 = r; r1 != R; r1 = (Reg*)r1->f.p1) {
+		for(z=0; z<BITS; z++) {
+			ref.b[z] |= r1->refahead.b[z];
+			if(ref.b[z] != r1->refahead.b[z]) {
+				r1->refahead.b[z] = ref.b[z];
+				change++;
+			}
+			cal.b[z] |= r1->calahead.b[z];
+			if(cal.b[z] != r1->calahead.b[z]) {
+				r1->calahead.b[z] = cal.b[z];
+				change++;
+			}
+		}
+		switch(r1->f.prog->as) {
+		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] | 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] |= 1UL<<(j&31);
+						}
+					}
+				}
+			}
+			break;
+
+		case ATEXT:
+			for(z=0; z<BITS; z++) {
+				cal.b[z] = 0;
+				ref.b[z] = 0;
+			}
+			break;
+
+		case ARET:
+			for(z=0; z<BITS; z++) {
+				cal.b[z] = externs.b[z] | ovar.b[z];
+				ref.b[z] = 0;
+			}
+			break;
+		}
+		for(z=0; z<BITS; z++) {
+			ref.b[z] = (ref.b[z] & ~r1->set.b[z]) |
+				r1->use1.b[z] | r1->use2.b[z];
+			cal.b[z] &= ~(r1->set.b[z] | r1->use1.b[z] | r1->use2.b[z]);
+			r1->refbehind.b[z] = ref.b[z];
+			r1->calbehind.b[z] = cal.b[z];
+		}
+		if(r1->f.active)
+			break;
+		r1->f.active = 1;
+	}
+	for(; r != r1; r = (Reg*)r->f.p1)
+		for(r2 = (Reg*)r->f.p2; r2 != R; r2 = (Reg*)r2->f.p2link)
+			prop(r2, r->refbehind, r->calbehind);
+}
+
+void
+synch(Reg *r, Bits dif)
+{
+	Reg *r1;
+	int z;
+
+	for(r1 = r; r1 != R; r1 = (Reg*)r1->f.s1) {
+		for(z=0; z<BITS; z++) {
+			dif.b[z] = (dif.b[z] &
+				~(~r1->refbehind.b[z] & r1->refahead.b[z])) |
+					r1->set.b[z] | r1->regdiff.b[z];
+			if(dif.b[z] != r1->regdiff.b[z]) {
+				r1->regdiff.b[z] = dif.b[z];
+				change++;
+			}
+		}
+		if(r1->f.active)
+			break;
+		r1->f.active = 1;
+		for(z=0; z<BITS; z++)
+			dif.b[z] &= ~(~r1->calbehind.b[z] & r1->calahead.b[z]);
+		if(r1->f.s2 != nil)
+			synch((Reg*)r1->f.s2, dif);
+	}
+}
+
+uint32
+allreg(uint32 b, Rgn *r)
+{
+	Var *v;
+	int i;
+
+	v = var + r->varno;
+	r->regno = 0;
+	switch(v->etype) {
+
+	default:
+		fatal("unknown etype %d/%E", bitno(b), v->etype);
+		break;
+
+	case TINT8:
+	case TUINT8:
+	case TINT16:
+	case TUINT16:
+	case TINT32:
+	case TUINT32:
+	case TINT64:
+	case TUINT64:
+	case TINT:
+	case TUINT:
+	case TUINTPTR:
+	case TBOOL:
+	case TPTR32:
+	case TPTR64:
+		i = BtoR(~b);
+		if(i && r->cost > 0) {
+			r->regno = i;
+			return RtoB(i);
+		}
+		break;
+
+	case TFLOAT32:
+	case TFLOAT64:
+		i = BtoF(~b);
+		if(i && r->cost > 0) {
+			r->regno = i;
+			return FtoB(i);
+		}
+		break;
+	}
+	return 0;
+}
+
+void
+paint1(Reg *r, int bn)
+{
+	Reg *r1;
+	int z;
+	uint32 bb;
+
+	z = bn/32;
+	bb = 1L<<(bn%32);
+	if(r->act.b[z] & bb)
+		return;
+	for(;;) {
+		if(!(r->refbehind.b[z] & bb))
+			break;
+		r1 = (Reg*)r->f.p1;
+		if(r1 == R)
+			break;
+		if(!(r1->refahead.b[z] & bb))
+			break;
+		if(r1->act.b[z] & bb)
+			break;
+		r = r1;
+	}
+
+	if(LOAD(r) & ~(r->set.b[z]&~(r->use1.b[z]|r->use2.b[z])) & bb) {
+		change -= CLOAD * r->f.loop;
+	}
+	for(;;) {
+		r->act.b[z] |= bb;
+
+		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) {
+			change -= CLOAD * r->f.loop;
+		}
+
+		if(r->refbehind.b[z] & bb)
+			for(r1 = (Reg*)r->f.p2; r1 != R; r1 = (Reg*)r1->f.p2link)
+				if(r1->refahead.b[z] & bb)
+					paint1(r1, bn);
+
+		if(!(r->refahead.b[z] & bb))
+			break;
+		r1 = (Reg*)r->f.s2;
+		if(r1 != R)
+			if(r1->refbehind.b[z] & bb)
+				paint1(r1, bn);
+		r = (Reg*)r->f.s1;
+		if(r == R)
+			break;
+		if(r->act.b[z] & bb)
+			break;
+		if(!(r->refbehind.b[z] & bb))
+			break;
+	}
+}
+
+uint32
+regset(Reg *r, uint32 bb)
+{
+	uint32 b, set;
+	Adr v;
+	int c;
+
+	set = 0;
+	v = zprog.from;
+	while(b = bb & ~(bb-1)) {
+		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, nil);
+		if(c == 3)
+			set |= b;
+		bb &= ~b;
+	}
+	return set;
+}
+
+uint32
+reguse(Reg *r, uint32 bb)
+{
+	uint32 b, set;
+	Adr v;
+	int c;
+
+	set = 0;
+	v = zprog.from;
+	while(b = bb & ~(bb-1)) {
+		v.type = b & 0xFFFF? BtoR(b): BtoF(b);
+		c = copyu(r->f.prog, &v, nil);
+		if(c == 1 || c == 2 || c == 4)
+			set |= b;
+		bb &= ~b;
+	}
+	return set;
+}
+
+uint32
+paint2(Reg *r, int bn)
+{
+	Reg *r1;
+	int z;
+	uint32 bb, vreg, x;
+
+	z = bn/32;
+	bb = 1L << (bn%32);
+	vreg = regbits;
+	if(!(r->act.b[z] & bb))
+		return vreg;
+	for(;;) {
+		if(!(r->refbehind.b[z] & bb))
+			break;
+		r1 = (Reg*)r->f.p1;
+		if(r1 == R)
+			break;
+		if(!(r1->refahead.b[z] & bb))
+			break;
+		if(!(r1->act.b[z] & bb))
+			break;
+		r = r1;
+	}
+	for(;;) {
+		r->act.b[z] &= ~bb;
+
+		vreg |= r->regu;
+
+		if(r->refbehind.b[z] & bb)
+			for(r1 = (Reg*)r->f.p2; r1 != R; r1 = (Reg*)r1->f.p2link)
+				if(r1->refahead.b[z] & bb)
+					vreg |= paint2(r1, bn);
+
+		if(!(r->refahead.b[z] & bb))
+			break;
+		r1 = (Reg*)r->f.s2;
+		if(r1 != R)
+			if(r1->refbehind.b[z] & bb)
+				vreg |= paint2(r1, bn);
+		r = (Reg*)r->f.s1;
+		if(r == R)
+			break;
+		if(!(r->act.b[z] & bb))
+			break;
+		if(!(r->refbehind.b[z] & bb))
+			break;
+	}
+
+	bb = vreg;
+	for(; r; r=(Reg*)r->f.s1) {
+		x = r->regu & ~bb;
+		if(x) {
+			vreg |= reguse(r, x);
+			bb |= regset(r, x);
+		}
+	}
+	return vreg;
+}
+
+void
+paint3(Reg *r, int bn, int32 rb, int rn)
+{
+	Reg *r1;
+	Prog *p;
+	int z;
+	uint32 bb;
+
+	z = bn/32;
+	bb = 1L << (bn%32);
+	if(r->act.b[z] & bb)
+		return;
+	for(;;) {
+		if(!(r->refbehind.b[z] & bb))
+			break;
+		r1 = (Reg*)r->f.p1;
+		if(r1 == R)
+			break;
+		if(!(r1->refahead.b[z] & bb))
+			break;
+		if(r1->act.b[z] & bb)
+			break;
+		r = r1;
+	}
+
+	if(LOAD(r) & ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z])) & bb)
+		addmove(r, bn, rn, 0);
+	for(;;) {
+		r->act.b[z] |= bb;
+		p = r->f.prog;
+
+		if(r->use1.b[z] & bb) {
+			if(debug['R'] && debug['v'])
+				print("%P", p);
+			addreg(&p->from, rn);
+			if(debug['R'] && debug['v'])
+				print(" ===change== %P\n", p);
+		}
+		if((r->use2.b[z]|r->set.b[z]) & bb) {
+			if(debug['R'] && debug['v'])
+				print("%P", p);
+			addreg(&p->to, rn);
+			if(debug['R'] && debug['v'])
+				print(" ===change== %P\n", p);
+		}
+
+		if(STORE(r) & r->regdiff.b[z] & bb)
+			addmove(r, bn, rn, 1);
+		r->regu |= rb;
+
+		if(r->refbehind.b[z] & bb)
+			for(r1 = (Reg*)r->f.p2; r1 != R; r1 = (Reg*)r1->f.p2link)
+				if(r1->refahead.b[z] & bb)
+					paint3(r1, bn, rb, rn);
+
+		if(!(r->refahead.b[z] & bb))
+			break;
+		r1 = (Reg*)r->f.s2;
+		if(r1 != R)
+			if(r1->refbehind.b[z] & bb)
+				paint3(r1, bn, rb, rn);
+		r = (Reg*)r->f.s1;
+		if(r == R)
+			break;
+		if(r->act.b[z] & bb)
+			break;
+		if(!(r->refbehind.b[z] & bb))
+			break;
+	}
+}
+
+void
+addreg(Adr *a, int rn)
+{
+	a->sym = nil;
+	a->node = nil;
+	a->offset = 0;
+	a->type = rn;
+
+	ostats.ncvtreg++;
+}
+
+int32
+RtoB(int r)
+{
+
+	if(r < D_AX || r > D_R15)
+		return 0;
+	return 1L << (r-D_AX);
+}
+
+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;
+}
+
+/*
+ *	bit	reg
+ *	16	X0
+ *	...
+ *	31	X15
+ */
+int32
+FtoB(int f)
+{
+	if(f < D_X0 || f > D_X15)
+		return 0;
+	return 1L << (f - D_X0 + 16);
+}
+
+int
+BtoF(int32 b)
+{
+
+	b &= 0xFFFF0000L;
+	if(b == 0)
+		return 0;
+	return bitno(b) - 16 + D_X0;
+}
+
+void
+dumpone(Flow *f, int isreg)
+{
+	int z;
+	Bits bit;
+	Reg *r;
+
+	print("%d:%P", f->loop, f->prog);
+	if(isreg) {	
+		r = (Reg*)f;
+		for(z=0; z<BITS; z++)
+			bit.b[z] =
+				r->set.b[z] |
+				r->use1.b[z] |
+				r->use2.b[z] |
+				r->refbehind.b[z] |
+				r->refahead.b[z] |
+				r->calbehind.b[z] |
+				r->calahead.b[z] |
+				r->regdiff.b[z] |
+				r->act.b[z] |
+					0;
+		if(bany(&bit)) {
+			print("\t");
+			if(bany(&r->set))
+				print(" s:%Q", r->set);
+			if(bany(&r->use1))
+				print(" u1:%Q", r->use1);
+			if(bany(&r->use2))
+				print(" u2:%Q", r->use2);
+			if(bany(&r->refbehind))
+				print(" rb:%Q ", r->refbehind);
+			if(bany(&r->refahead))
+				print(" ra:%Q ", r->refahead);
+			if(bany(&r->calbehind))
+				print(" cb:%Q ", r->calbehind);
+			if(bany(&r->calahead))
+				print(" ca:%Q ", r->calahead);
+			if(bany(&r->regdiff))
+				print(" d:%Q ", r->regdiff);
+			if(bany(&r->act))
+				print(" a:%Q ", r->act);
+		}
+	}
+	print("\n");
+}
+
+void
+dumpit(char *str, Flow *r0, int isreg)
+{
+	Flow *r, *r1;
+
+	print("\n%s\n", str);
+	for(r = r0; r != nil; r = r->link) {
+		dumpone(r, isreg);
+		r1 = r->p2;
+		if(r1 != nil) {
+			print("	pred:");
+			for(; r1 != nil; r1 = r1->p2link)
+				print(" %.4ud", (int)r1->prog->pc);
+			print("\n");
+		}
+//		r1 = r->s1;
+//		if(r1 != R) {
+//			print("	succ:");
+//			for(; r1 != R; r1 = r1->s1)
+//				print(" %.4ud", (int)r1->prog->pc);
+//			print("\n");
+//		}
+	}
+}
diff --git a/src/cmd/6l/6.out.h b/src/cmd/6l/6.out.h
new file mode 100644
index 0000000..af72784
--- /dev/null
+++ b/src/cmd/6l/6.out.h
@@ -0,0 +1,890 @@
+// Inferno utils/6c/6.out.h
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/6.out.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.
+
+#define	NSYM	50
+#define	NSNAME	8
+#include "../ld/textflag.h"
+
+/*
+ *	amd64
+ */
+
+enum
+{
+	AXXX,
+	AAAA,
+	AAAD,
+	AAAM,
+	AAAS,
+	AADCB,
+	AADCL,
+	AADCW,
+	AADDB,
+	AADDL,
+	AADDW,
+	AADJSP,
+	AANDB,
+	AANDL,
+	AANDW,
+	AARPL,
+	ABOUNDL,
+	ABOUNDW,
+	ABSFL,
+	ABSFW,
+	ABSRL,
+	ABSRW,
+	ABTL,
+	ABTW,
+	ABTCL,
+	ABTCW,
+	ABTRL,
+	ABTRW,
+	ABTSL,
+	ABTSW,
+	ABYTE,
+	ACALL,
+	ACLC,
+	ACLD,
+	ACLI,
+	ACLTS,
+	ACMC,
+	ACMPB,
+	ACMPL,
+	ACMPW,
+	ACMPSB,
+	ACMPSL,
+	ACMPSW,
+	ADAA,
+	ADAS,
+	ADATA,
+	ADECB,
+	ADECL,
+	ADECQ,
+	ADECW,
+	ADIVB,
+	ADIVL,
+	ADIVW,
+	AENTER,
+	AGLOBL,
+	AGOK,
+	AHISTORY,
+	AHLT,
+	AIDIVB,
+	AIDIVL,
+	AIDIVW,
+	AIMULB,
+	AIMULL,
+	AIMULW,
+	AINB,
+	AINL,
+	AINW,
+	AINCB,
+	AINCL,
+	AINCQ,
+	AINCW,
+	AINSB,
+	AINSL,
+	AINSW,
+	AINT,
+	AINTO,
+	AIRETL,
+	AIRETW,
+	AJCC,
+	AJCS,
+	AJCXZL,
+	AJEQ,
+	AJGE,
+	AJGT,
+	AJHI,
+	AJLE,
+	AJLS,
+	AJLT,
+	AJMI,
+	AJMP,
+	AJNE,
+	AJOC,
+	AJOS,
+	AJPC,
+	AJPL,
+	AJPS,
+	ALAHF,
+	ALARL,
+	ALARW,
+	ALEAL,
+	ALEAW,
+	ALEAVEL,
+	ALEAVEW,
+	ALOCK,
+	ALODSB,
+	ALODSL,
+	ALODSW,
+	ALONG,
+	ALOOP,
+	ALOOPEQ,
+	ALOOPNE,
+	ALSLL,
+	ALSLW,
+	AMOVB,
+	AMOVL,
+	AMOVW,
+	AMOVBLSX,
+	AMOVBLZX,
+	AMOVBQSX,
+	AMOVBQZX,
+	AMOVBWSX,
+	AMOVBWZX,
+	AMOVWLSX,
+	AMOVWLZX,
+	AMOVWQSX,
+	AMOVWQZX,
+	AMOVSB,
+	AMOVSL,
+	AMOVSW,
+	AMULB,
+	AMULL,
+	AMULW,
+	ANAME,
+	ANEGB,
+	ANEGL,
+	ANEGW,
+	ANOP,
+	ANOTB,
+	ANOTL,
+	ANOTW,
+	AORB,
+	AORL,
+	AORW,
+	AOUTB,
+	AOUTL,
+	AOUTW,
+	AOUTSB,
+	AOUTSL,
+	AOUTSW,
+	APAUSE,
+	APOPAL,
+	APOPAW,
+	APOPFL,
+	APOPFW,
+	APOPL,
+	APOPW,
+	APUSHAL,
+	APUSHAW,
+	APUSHFL,
+	APUSHFW,
+	APUSHL,
+	APUSHW,
+	ARCLB,
+	ARCLL,
+	ARCLW,
+	ARCRB,
+	ARCRL,
+	ARCRW,
+	AREP,
+	AREPN,
+	ARET,
+	AROLB,
+	AROLL,
+	AROLW,
+	ARORB,
+	ARORL,
+	ARORW,
+	ASAHF,
+	ASALB,
+	ASALL,
+	ASALW,
+	ASARB,
+	ASARL,
+	ASARW,
+	ASBBB,
+	ASBBL,
+	ASBBW,
+	ASCASB,
+	ASCASL,
+	ASCASW,
+	ASETCC,
+	ASETCS,
+	ASETEQ,
+	ASETGE,
+	ASETGT,
+	ASETHI,
+	ASETLE,
+	ASETLS,
+	ASETLT,
+	ASETMI,
+	ASETNE,
+	ASETOC,
+	ASETOS,
+	ASETPC,
+	ASETPL,
+	ASETPS,
+	ACDQ,
+	ACWD,
+	ASHLB,
+	ASHLL,
+	ASHLW,
+	ASHRB,
+	ASHRL,
+	ASHRW,
+	ASTC,
+	ASTD,
+	ASTI,
+	ASTOSB,
+	ASTOSL,
+	ASTOSW,
+	ASUBB,
+	ASUBL,
+	ASUBW,
+	ASYSCALL,
+	ATESTB,
+	ATESTL,
+	ATESTW,
+	ATEXT,
+	AVERR,
+	AVERW,
+	AWAIT,
+	AWORD,
+	AXCHGB,
+	AXCHGL,
+	AXCHGW,
+	AXLAT,
+	AXORB,
+	AXORL,
+	AXORW,
+
+	AFMOVB,
+	AFMOVBP,
+	AFMOVD,
+	AFMOVDP,
+	AFMOVF,
+	AFMOVFP,
+	AFMOVL,
+	AFMOVLP,
+	AFMOVV,
+	AFMOVVP,
+	AFMOVW,
+	AFMOVWP,
+	AFMOVX,
+	AFMOVXP,
+
+	AFCOMB,
+	AFCOMBP,
+	AFCOMD,
+	AFCOMDP,
+	AFCOMDPP,
+	AFCOMF,
+	AFCOMFP,
+	AFCOML,
+	AFCOMLP,
+	AFCOMW,
+	AFCOMWP,
+	AFUCOM,
+	AFUCOMP,
+	AFUCOMPP,
+
+	AFADDDP,
+	AFADDW,
+	AFADDL,
+	AFADDF,
+	AFADDD,
+
+	AFMULDP,
+	AFMULW,
+	AFMULL,
+	AFMULF,
+	AFMULD,
+
+	AFSUBDP,
+	AFSUBW,
+	AFSUBL,
+	AFSUBF,
+	AFSUBD,
+
+	AFSUBRDP,
+	AFSUBRW,
+	AFSUBRL,
+	AFSUBRF,
+	AFSUBRD,
+
+	AFDIVDP,
+	AFDIVW,
+	AFDIVL,
+	AFDIVF,
+	AFDIVD,
+
+	AFDIVRDP,
+	AFDIVRW,
+	AFDIVRL,
+	AFDIVRF,
+	AFDIVRD,
+
+	AFXCHD,
+	AFFREE,
+
+	AFLDCW,
+	AFLDENV,
+	AFRSTOR,
+	AFSAVE,
+	AFSTCW,
+	AFSTENV,
+	AFSTSW,
+
+	AF2XM1,
+	AFABS,
+	AFCHS,
+	AFCLEX,
+	AFCOS,
+	AFDECSTP,
+	AFINCSTP,
+	AFINIT,
+	AFLD1,
+	AFLDL2E,
+	AFLDL2T,
+	AFLDLG2,
+	AFLDLN2,
+	AFLDPI,
+	AFLDZ,
+	AFNOP,
+	AFPATAN,
+	AFPREM,
+	AFPREM1,
+	AFPTAN,
+	AFRNDINT,
+	AFSCALE,
+	AFSIN,
+	AFSINCOS,
+	AFSQRT,
+	AFTST,
+	AFXAM,
+	AFXTRACT,
+	AFYL2X,
+	AFYL2XP1,
+
+	AEND,
+
+	ADYNT_,
+	AINIT_,
+
+	ASIGNAME,
+
+	/* extra 32-bit operations */
+	ACMPXCHGB,
+	ACMPXCHGL,
+	ACMPXCHGW,
+	ACMPXCHG8B,
+	ACPUID,
+	AINVD,
+	AINVLPG,
+	ALFENCE,
+	AMFENCE,
+	AMOVNTIL,
+	ARDMSR,
+	ARDPMC,
+	ARDTSC,
+	ARSM,
+	ASFENCE,
+	ASYSRET,
+	AWBINVD,
+	AWRMSR,
+	AXADDB,
+	AXADDL,
+	AXADDW,
+
+	/* conditional move */
+	ACMOVLCC,
+	ACMOVLCS,
+	ACMOVLEQ,
+	ACMOVLGE,
+	ACMOVLGT,
+	ACMOVLHI,
+	ACMOVLLE,
+	ACMOVLLS,
+	ACMOVLLT,
+	ACMOVLMI,
+	ACMOVLNE,
+	ACMOVLOC,
+	ACMOVLOS,
+	ACMOVLPC,
+	ACMOVLPL,
+	ACMOVLPS,
+	ACMOVQCC,
+	ACMOVQCS,
+	ACMOVQEQ,
+	ACMOVQGE,
+	ACMOVQGT,
+	ACMOVQHI,
+	ACMOVQLE,
+	ACMOVQLS,
+	ACMOVQLT,
+	ACMOVQMI,
+	ACMOVQNE,
+	ACMOVQOC,
+	ACMOVQOS,
+	ACMOVQPC,
+	ACMOVQPL,
+	ACMOVQPS,
+	ACMOVWCC,
+	ACMOVWCS,
+	ACMOVWEQ,
+	ACMOVWGE,
+	ACMOVWGT,
+	ACMOVWHI,
+	ACMOVWLE,
+	ACMOVWLS,
+	ACMOVWLT,
+	ACMOVWMI,
+	ACMOVWNE,
+	ACMOVWOC,
+	ACMOVWOS,
+	ACMOVWPC,
+	ACMOVWPL,
+	ACMOVWPS,
+
+	/* 64-bit */
+	AADCQ,
+	AADDQ,
+	AANDQ,
+	ABSFQ,
+	ABSRQ,
+	ABTCQ,
+	ABTQ,
+	ABTRQ,
+	ABTSQ,
+	ACMPQ,
+	ACMPSQ,
+	ACMPXCHGQ,
+	ACQO,
+	ADIVQ,
+	AIDIVQ,
+	AIMULQ,
+	AIRETQ,
+	AJCXZQ,
+	ALEAQ,
+	ALEAVEQ,
+	ALODSQ,
+	AMOVQ,
+	AMOVLQSX,
+	AMOVLQZX,
+	AMOVNTIQ,
+	AMOVSQ,
+	AMULQ,
+	ANEGQ,
+	ANOTQ,
+	AORQ,
+	APOPFQ,
+	APOPQ,
+	APUSHFQ,
+	APUSHQ,
+	ARCLQ,
+	ARCRQ,
+	AROLQ,
+	ARORQ,
+	AQUAD,
+	ASALQ,
+	ASARQ,
+	ASBBQ,
+	ASCASQ,
+	ASHLQ,
+	ASHRQ,
+	ASTOSQ,
+	ASUBQ,
+	ATESTQ,
+	AXADDQ,
+	AXCHGQ,
+	AXORQ,
+
+	/* media */
+	AADDPD,
+	AADDPS,
+	AADDSD,
+	AADDSS,
+	AANDNPD,
+	AANDNPS,
+	AANDPD,
+	AANDPS,
+	ACMPPD,
+	ACMPPS,
+	ACMPSD,
+	ACMPSS,
+	ACOMISD,
+	ACOMISS,
+	ACVTPD2PL,
+	ACVTPD2PS,
+	ACVTPL2PD,
+	ACVTPL2PS,
+	ACVTPS2PD,
+	ACVTPS2PL,
+	ACVTSD2SL,
+	ACVTSD2SQ,
+	ACVTSD2SS,
+	ACVTSL2SD,
+	ACVTSL2SS,
+	ACVTSQ2SD,
+	ACVTSQ2SS,
+	ACVTSS2SD,
+	ACVTSS2SL,
+	ACVTSS2SQ,
+	ACVTTPD2PL,
+	ACVTTPS2PL,
+	ACVTTSD2SL,
+	ACVTTSD2SQ,
+	ACVTTSS2SL,
+	ACVTTSS2SQ,
+	ADIVPD,
+	ADIVPS,
+	ADIVSD,
+	ADIVSS,
+	AEMMS,
+	AFXRSTOR,
+	AFXRSTOR64,
+	AFXSAVE,
+	AFXSAVE64,
+	ALDMXCSR,
+	AMASKMOVOU,
+	AMASKMOVQ,
+	AMAXPD,
+	AMAXPS,
+	AMAXSD,
+	AMAXSS,
+	AMINPD,
+	AMINPS,
+	AMINSD,
+	AMINSS,
+	AMOVAPD,
+	AMOVAPS,
+	AMOVOU,
+	AMOVHLPS,
+	AMOVHPD,
+	AMOVHPS,
+	AMOVLHPS,
+	AMOVLPD,
+	AMOVLPS,
+	AMOVMSKPD,
+	AMOVMSKPS,
+	AMOVNTO,
+	AMOVNTPD,
+	AMOVNTPS,
+	AMOVNTQ,
+	AMOVO,
+	AMOVQOZX,
+	AMOVSD,
+	AMOVSS,
+	AMOVUPD,
+	AMOVUPS,
+	AMULPD,
+	AMULPS,
+	AMULSD,
+	AMULSS,
+	AORPD,
+	AORPS,
+	APACKSSLW,
+	APACKSSWB,
+	APACKUSWB,
+	APADDB,
+	APADDL,
+	APADDQ,
+	APADDSB,
+	APADDSW,
+	APADDUSB,
+	APADDUSW,
+	APADDW,
+	APANDB,
+	APANDL,
+	APANDSB,
+	APANDSW,
+	APANDUSB,
+	APANDUSW,
+	APANDW,
+	APAND,
+	APANDN,
+	APAVGB,
+	APAVGW,
+	APCMPEQB,
+	APCMPEQL,
+	APCMPEQW,
+	APCMPGTB,
+	APCMPGTL,
+	APCMPGTW,
+	APEXTRW,
+	APFACC,
+	APFADD,
+	APFCMPEQ,
+	APFCMPGE,
+	APFCMPGT,
+	APFMAX,
+	APFMIN,
+	APFMUL,
+	APFNACC,
+	APFPNACC,
+	APFRCP,
+	APFRCPIT1,
+	APFRCPI2T,
+	APFRSQIT1,
+	APFRSQRT,
+	APFSUB,
+	APFSUBR,
+	APINSRW,
+	APINSRD,
+	APINSRQ,
+	APMADDWL,
+	APMAXSW,
+	APMAXUB,
+	APMINSW,
+	APMINUB,
+	APMOVMSKB,
+	APMULHRW,
+	APMULHUW,
+	APMULHW,
+	APMULLW,
+	APMULULQ,
+	APOR,
+	APSADBW,
+	APSHUFHW,
+	APSHUFL,
+	APSHUFLW,
+	APSHUFW,
+	APSHUFB,
+	APSLLO,
+	APSLLL,
+	APSLLQ,
+	APSLLW,
+	APSRAL,
+	APSRAW,
+	APSRLO,
+	APSRLL,
+	APSRLQ,
+	APSRLW,
+	APSUBB,
+	APSUBL,
+	APSUBQ,
+	APSUBSB,
+	APSUBSW,
+	APSUBUSB,
+	APSUBUSW,
+	APSUBW,
+	APSWAPL,
+	APUNPCKHBW,
+	APUNPCKHLQ,
+	APUNPCKHQDQ,
+	APUNPCKHWL,
+	APUNPCKLBW,
+	APUNPCKLLQ,
+	APUNPCKLQDQ,
+	APUNPCKLWL,
+	APXOR,
+	ARCPPS,
+	ARCPSS,
+	ARSQRTPS,
+	ARSQRTSS,
+	ASHUFPD,
+	ASHUFPS,
+	ASQRTPD,
+	ASQRTPS,
+	ASQRTSD,
+	ASQRTSS,
+	ASTMXCSR,
+	ASUBPD,
+	ASUBPS,
+	ASUBSD,
+	ASUBSS,
+	AUCOMISD,
+	AUCOMISS,
+	AUNPCKHPD,
+	AUNPCKHPS,
+	AUNPCKLPD,
+	AUNPCKLPS,
+	AXORPD,
+	AXORPS,
+
+	APF2IW,
+	APF2IL,
+	API2FW,
+	API2FL,
+	ARETFW,
+	ARETFL,
+	ARETFQ,
+	ASWAPGS,
+
+	AMODE,
+	ACRC32B,
+	ACRC32Q,
+	AIMUL3Q,
+	
+	APREFETCHT0,
+	APREFETCHT1,
+	APREFETCHT2,
+	APREFETCHNTA,
+	
+	AMOVQL,
+	ABSWAPL,
+	ABSWAPQ,
+	
+	AUNDEF,
+
+	AAESENC,
+	AAESENCLAST,
+	AAESDEC,
+	AAESDECLAST,
+	AAESIMC,
+	AAESKEYGENASSIST,
+
+	APSHUFD,
+	APCLMULQDQ,
+	
+	AUSEFIELD,
+	ATYPE,
+	AFUNCDATA,
+	APCDATA,
+	ACHECKNIL,
+	AVARDEF,
+	AVARKILL,
+	ADUFFCOPY,
+	ADUFFZERO,
+	
+	ALAST
+};
+
+enum
+{
+
+	D_AL		= 0,
+	D_CL,
+	D_DL,
+	D_BL,
+	D_SPB,
+	D_BPB,
+	D_SIB,
+	D_DIB,
+	D_R8B,
+	D_R9B,
+	D_R10B,
+	D_R11B,
+	D_R12B,
+	D_R13B,
+	D_R14B,
+	D_R15B,
+
+	D_AX		= 16,
+	D_CX,
+	D_DX,
+	D_BX,
+	D_SP,
+	D_BP,
+	D_SI,
+	D_DI,
+	D_R8,
+	D_R9,
+	D_R10,
+	D_R11,
+	D_R12,
+	D_R13,
+	D_R14,
+	D_R15,
+
+	D_AH		= 32,
+	D_CH,
+	D_DH,
+	D_BH,
+
+	D_F0		= 36,
+
+	D_M0		= 44,
+
+	D_X0		= 52,
+	D_X1,
+	D_X2,
+	D_X3,
+	D_X4,
+	D_X5,
+	D_X6,
+	D_X7,
+	D_X8,
+	D_X9,
+	D_X10,
+	D_X11,
+	D_X12,
+	D_X13,
+	D_X14,
+	D_X15,
+
+	D_CS		= 68,
+	D_SS,
+	D_DS,
+	D_ES,
+	D_FS,
+	D_GS,
+
+	D_GDTR,		/* global descriptor table register */
+	D_IDTR,		/* interrupt descriptor table register */
+	D_LDTR,		/* local descriptor table register */
+	D_MSW,		/* machine status word */
+	D_TASK,		/* task register */
+
+	D_CR		= 79,
+	D_DR		= 95,
+	D_TR		= 103,
+
+	D_TLS		= 111,
+	D_NONE		= 112,
+
+	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 */
+
+	T_TYPE		= 1<<0,
+	T_INDEX		= 1<<1,
+	T_OFFSET	= 1<<2,
+	T_FCONST	= 1<<3,
+	T_SYM		= 1<<4,
+	T_SCONST	= 1<<5,
+	T_64		= 1<<6,
+	T_GOTYPE	= 1<<7,
+
+	REGARG		= -1,
+	REGRET		= D_AX,
+	FREGRET		= D_X0,
+	REGSP		= D_SP,
+	REGTMP		= D_DI,
+	REGEXT		= D_R15,	/* compiler allocates external registers R15 down */
+	FREGMIN		= D_X0+5,	/* first register variable */
+	FREGEXT		= D_X0+15	/* first external register */
+};
+
+/*
+ * this is the ranlib header
+ */
+#define	SYMDEF	"__.GOSYMDEF"
diff --git a/src/cmd/6l/Makefile b/src/cmd/6l/Makefile
new file mode 100644
index 0000000..3f528d7
--- /dev/null
+++ b/src/cmd/6l/Makefile
@@ -0,0 +1,5 @@
+# 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/6l/asm.c b/src/cmd/6l/asm.c
new file mode 100644
index 0000000..18b5aa3
--- /dev/null
+++ b/src/cmd/6l/asm.c
@@ -0,0 +1,817 @@
+// Inferno utils/6l/asm.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/asm.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.
+
+// Writing object files.
+
+#include	"l.h"
+#include	"../ld/lib.h"
+#include	"../ld/elf.h"
+#include	"../ld/dwarf.h"
+#include	"../ld/macho.h"
+#include	"../ld/pe.h"
+
+#define PADDR(a)	((uint32)(a) & ~0x80000000)
+
+char linuxdynld[] = "/lib64/ld-linux-x86-64.so.2";
+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];
+
+static int
+needlib(char *name)
+{
+	char *p;
+	LSym *s;
+
+	if(*name == '\0')
+		return 0;
+
+	/* reuse hash code in symbol table */
+	p = smprint(".elfload.%s", name);
+	s = linklookup(ctxt, p, 0);
+	free(p);
+	if(s->type == 0) {
+		s->type = 100;	// avoid SDATA, etc.
+		return 1;
+	}
+	return 0;
+}
+
+int nelfsym = 1;
+
+static void addpltsym(LSym*);
+static void addgotsym(LSym*);
+
+void
+adddynrela(LSym *rela, LSym *s, Reloc *r)
+{
+	addaddrplus(ctxt, rela, s, r->off);
+	adduint64(ctxt, rela, R_X86_64_RELATIVE);
+	addaddrplus(ctxt, rela, r->sym, r->add); // Addend
+}
+
+void
+adddynrel(LSym *s, Reloc *r)
+{
+	LSym *targ, *rela, *got;
+	
+	targ = r->sym;
+	ctxt->cursym = s;
+
+	switch(r->type) {
+	default:
+		if(r->type >= 256) {
+			diag("unexpected relocation type %d", r->type);
+			return;
+		}
+		break;
+
+	// Handle relocations found in ELF object files.
+	case 256 + R_X86_64_PC32:
+		if(targ->type == SDYNIMPORT)
+			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 = R_PCREL;
+		r->add += 4;
+		return;
+	
+	case 256 + R_X86_64_PLT32:
+		r->type = R_PCREL;
+		r->add += 4;
+		if(targ->type == SDYNIMPORT) {
+			addpltsym(targ);
+			r->sym = linklookup(ctxt, ".plt", 0);
+			r->add += targ->plt;
+		}
+		return;
+	
+	case 256 + R_X86_64_GOTPCREL:
+		if(targ->type != SDYNIMPORT) {
+			// have symbol
+			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 = R_PCREL;
+				r->add += 4;
+				return;
+			}
+			// fall back to using GOT and hope for the best (CMOV*)
+			// TODO: just needs relocation, no need to put in .dynsym
+		}
+		addgotsym(targ);
+		r->type = R_PCREL;
+		r->sym = linklookup(ctxt, ".got", 0);
+		r->add += 4;
+		r->add += targ->got;
+		return;
+	
+	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 = R_ADDR;
+		return;
+	
+	// Handle relocations found in Mach-O object files.
+	case 512 + MACHO_X86_64_RELOC_UNSIGNED*2 + 0:
+	case 512 + MACHO_X86_64_RELOC_SIGNED*2 + 0:
+	case 512 + MACHO_X86_64_RELOC_BRANCH*2 + 0:
+		// TODO: What is the difference between all these?
+		r->type = R_ADDR;
+		if(targ->type == SDYNIMPORT)
+			diag("unexpected reloc for dynamic symbol %s", targ->name);
+		return;
+
+	case 512 + MACHO_X86_64_RELOC_BRANCH*2 + 1:
+		if(targ->type == SDYNIMPORT) {
+			addpltsym(targ);
+			r->sym = linklookup(ctxt, ".plt", 0);
+			r->add = targ->plt;
+			r->type = R_PCREL;
+			return;
+		}
+		// fall through
+	case 512 + MACHO_X86_64_RELOC_UNSIGNED*2 + 1:
+	case 512 + MACHO_X86_64_RELOC_SIGNED*2 + 1:
+	case 512 + MACHO_X86_64_RELOC_SIGNED_1*2 + 1:
+	case 512 + MACHO_X86_64_RELOC_SIGNED_2*2 + 1:
+	case 512 + MACHO_X86_64_RELOC_SIGNED_4*2 + 1:
+		r->type = R_PCREL;
+		if(targ->type == SDYNIMPORT)
+			diag("unexpected pc-relative reloc for dynamic symbol %s", targ->name);
+		return;
+
+	case 512 + MACHO_X86_64_RELOC_GOT_LOAD*2 + 1:
+		if(targ->type != SDYNIMPORT) {
+			// have symbol
+			// turn MOVQ of GOT entry into LEAQ of symbol itself
+			if(r->off < 2 || s->p[r->off-2] != 0x8b) {
+				diag("unexpected GOT_LOAD reloc for non-dynamic symbol %s", targ->name);
+				return;
+			}
+			s->p[r->off-2] = 0x8d;
+			r->type = R_PCREL;
+			return;
+		}
+		// fall through
+	case 512 + MACHO_X86_64_RELOC_GOT*2 + 1:
+		if(targ->type != SDYNIMPORT)
+			diag("unexpected GOT reloc for non-dynamic symbol %s", targ->name);
+		addgotsym(targ);
+		r->type = R_PCREL;
+		r->sym = linklookup(ctxt, ".got", 0);
+		r->add += targ->got;
+		return;
+	}
+	
+	// Handle references to ELF symbols from our own object files.
+	if(targ->type != SDYNIMPORT)
+		return;
+
+	switch(r->type) {
+	case R_CALL:
+	case R_PCREL:
+		addpltsym(targ);
+		r->sym = linklookup(ctxt, ".plt", 0);
+		r->add = targ->plt;
+		return;
+	
+	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(ctxt, targ);
+			rela = linklookup(ctxt, ".rela", 0);
+			addaddrplus(ctxt, rela, s, r->off);
+			if(r->siz == 8)
+				adduint64(ctxt, rela, ELF64_R_INFO(targ->dynid, R_X86_64_64));
+			else
+				adduint64(ctxt, rela, ELF64_R_INFO(targ->dynid, R_X86_64_32));
+			adduint64(ctxt, rela, r->add);
+			r->type = 256;	// ignore during relocsym
+			return;
+		}
+		if(HEADTYPE == Hdarwin && s->size == PtrSize && r->off == 0) {
+			// Mach-O relocations are a royal pain to lay out.
+			// They use a compact stateful bytecode representation
+			// that is too much bother to deal with.
+			// Instead, interpret the C declaration
+			//	void *_Cvar_stderr = &stderr;
+			// as making _Cvar_stderr the name of a GOT entry
+			// for stderr.  This is separate from the usual GOT entry,
+			// just in case the C code assigns to the variable,
+			// and of course it only works for single pointers,
+			// but we only need to support cgo and that's all it needs.
+			adddynsym(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(ctxt, got, 0);
+			adduint32(ctxt, linklookup(ctxt, ".linkedit.got", 0), targ->dynid);
+			r->type = 256;	// ignore during relocsym
+			return;
+		}
+		break;
+	}
+	
+	ctxt->cursym = s;
+	diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ->name, r->type, targ->type);
+}
+
+int
+elfreloc1(Reloc *r, vlong sectoff)
+{
+	int32 elfsym;
+
+	VPUT(sectoff);
+
+	elfsym = r->xsym->elfsym;
+	switch(r->type) {
+	default:
+		return -1;
+
+	case R_ADDR:
+		if(r->siz == 4)
+			VPUT(R_X86_64_32 | (uint64)elfsym<<32);
+		else if(r->siz == 8)
+			VPUT(R_X86_64_64 | (uint64)elfsym<<32);
+		else
+			return -1;
+		break;
+
+	case R_TLS_LE:
+		if(r->siz == 4)
+			VPUT(R_X86_64_TPOFF32 | (uint64)elfsym<<32);
+		else
+			return -1;
+		break;
+		
+	case R_CALL:
+		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 R_PCREL:
+		if(r->siz == 4) {
+			VPUT(R_X86_64_PC32 | (uint64)elfsym<<32);
+		} else
+			return -1;
+		break;
+
+	case R_TLS:
+		if(r->siz == 4) {
+			if(flag_shared)
+				VPUT(R_X86_64_GOTTPOFF | (uint64)elfsym<<32);
+			else
+				VPUT(R_X86_64_TPOFF32 | (uint64)elfsym<<32);
+		} else
+			return -1;
+		break;		
+	}
+
+	VPUT(r->xadd);
+	return 0;
+}
+
+int
+machoreloc1(Reloc *r, vlong sectoff)
+{
+	uint32 v;
+	LSym *rs;
+	
+	rs = r->xsym;
+
+	if(rs->type == SHOSTOBJ || r->type == R_PCREL) {
+		if(rs->dynid < 0) {
+			diag("reloc %d to non-macho symbol %s type=%d", r->type, rs->name, rs->type);
+			return -1;
+		}
+		v = rs->dynid;			
+		v |= 1<<27; // external relocation
+	} else {
+		v = rs->sect->extnum;
+		if(v == 0) {
+			diag("reloc %d to symbol %s in non-macho section %s type=%d", r->type, rs->name, rs->sect->name, rs->type);
+			return -1;
+		}
+	}
+
+	switch(r->type) {
+	default:
+		return -1;
+	case R_ADDR:
+		v |= MACHO_X86_64_RELOC_UNSIGNED<<28;
+		break;
+	case R_CALL:
+		v |= 1<<24; // pc-relative bit
+		v |= MACHO_X86_64_RELOC_BRANCH<<28;
+		break;
+	case R_PCREL:
+		// NOTE: Only works with 'external' relocation. Forced above.
+		v |= 1<<24; // pc-relative bit
+		v |= MACHO_X86_64_RELOC_SIGNED<<28;
+	}
+	
+	switch(r->siz) {
+	default:
+		return -1;
+	case 1:
+		v |= 0<<25;
+		break;
+	case 2:
+		v |= 1<<25;
+		break;
+	case 4:
+		v |= 2<<25;
+		break;
+	case 8:
+		v |= 3<<25;
+		break;
+	}
+
+	LPUT(sectoff);
+	LPUT(v);
+	return 0;
+}
+
+int
+archreloc(Reloc *r, LSym *s, vlong *val)
+{
+	USED(r);
+	USED(s);
+	USED(val);
+	return -1;
+}
+
+void
+elfsetupplt(void)
+{
+	LSym *plt, *got;
+
+	plt = linklookup(ctxt, ".plt", 0);
+	got = linklookup(ctxt, ".got.plt", 0);
+	if(plt->size == 0) {
+		// pushq got+8(IP)
+		adduint8(ctxt, plt, 0xff);
+		adduint8(ctxt, plt, 0x35);
+		addpcrelplus(ctxt, plt, got, 8);
+		
+		// jmpq got+16(IP)
+		adduint8(ctxt, plt, 0xff);
+		adduint8(ctxt, plt, 0x25);
+		addpcrelplus(ctxt, plt, got, 16);
+		
+		// nopl 0(AX)
+		adduint32(ctxt, plt, 0x00401f0f);
+		
+		// assume got->size == 0 too
+		addaddrplus(ctxt, got, linklookup(ctxt, ".dynamic", 0), 0);
+		adduint64(ctxt, got, 0);
+		adduint64(ctxt, got, 0);
+	}
+}
+
+static void
+addpltsym(LSym *s)
+{
+	if(s->plt >= 0)
+		return;
+	
+	adddynsym(ctxt, s);
+	
+	if(iself) {
+		LSym *plt, *got, *rela;
+
+		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(ctxt, plt, 0xff);
+		adduint8(ctxt, plt, 0x25);
+		addpcrelplus(ctxt, plt, got, got->size);
+	
+		// add to got: pointer to current pos in plt
+		addaddrplus(ctxt, got, plt, plt->size);
+		
+		// pushq $x
+		adduint8(ctxt, plt, 0x68);
+		adduint32(ctxt, plt, (got->size-24-8)/8);
+		
+		// jmpq .plt
+		adduint8(ctxt, plt, 0xe9);
+		adduint32(ctxt, plt, -(plt->size+4));
+		
+		// rela
+		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) {
+		// To do lazy symbol lookup right, we're supposed
+		// to tell the dynamic loader which library each 
+		// symbol comes from and format the link info
+		// section just so.  I'm too lazy (ha!) to do that
+		// so for now we'll just use non-lazy pointers,
+		// which don't need to be told which library to use.
+		//
+		// http://networkpx.blogspot.com/2009/09/about-lcdyldinfoonly-command.html
+		// has details about what we're avoiding.
+
+		LSym *plt;
+		
+		addgotsym(s);
+		plt = linklookup(ctxt, ".plt", 0);
+
+		adduint32(ctxt, linklookup(ctxt, ".linkedit.plt", 0), s->dynid);
+
+		// jmpq *got+size(IP)
+		s->plt = plt->size;
+
+		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(LSym *s)
+{
+	LSym *got, *rela;
+
+	if(s->got >= 0)
+		return;
+
+	adddynsym(ctxt, s);
+	got = linklookup(ctxt, ".got", 0);
+	s->got = got->size;
+	adduint64(ctxt, got, 0);
+
+	if(iself) {
+		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(ctxt, linklookup(ctxt, ".linkedit.got", 0), s->dynid);
+	} else {
+		diag("addgotsym: unsupported binary format");
+	}
+}
+
+void
+adddynsym(Link *ctxt, LSym *s)
+{
+	LSym *d;
+	int t;
+	char *name;
+
+	if(s->dynid >= 0)
+		return;
+
+	if(iself) {
+		s->dynid = nelfsym++;
+
+		d = linklookup(ctxt, ".dynsym", 0);
+
+		name = s->extname;
+		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(ctxt, d, t);
+	
+		/* reserved */
+		adduint8(ctxt, d, 0);
+	
+		/* section where symbol is defined */
+		if(s->type == SDYNIMPORT)
+			adduint16(ctxt, d, SHN_UNDEF);
+		else {
+			switch(s->type) {
+			default:
+			case STEXT:
+				t = 11;
+				break;
+			case SRODATA:
+				t = 12;
+				break;
+			case SDATA:
+				t = 13;
+				break;
+			case SBSS:
+				t = 14;
+				break;
+			}
+			adduint16(ctxt, d, t);
+		}
+	
+		/* value */
+		if(s->type == SDYNIMPORT)
+			adduint64(ctxt, d, 0);
+		else
+			addaddr(ctxt, d, s);
+	
+		/* size of object */
+		adduint64(ctxt, d, s->size);
+	
+		if(!(s->cgoexport & CgoExportDynamic) && s->dynimplib && needlib(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);
+	} else if(HEADTYPE == Hwindows) {
+		// already taken care of
+	} else {
+		diag("adddynsym: unsupported binary format");
+	}
+}
+
+void
+adddynlib(char *lib)
+{
+	LSym *s;
+	
+	if(!needlib(lib))
+		return;
+	
+	if(iself) {
+		s = linklookup(ctxt, ".dynstr", 0);
+		if(s->size == 0)
+			addstring(s, "");
+		elfwritedynent(linklookup(ctxt, ".dynamic", 0), DT_NEEDED, addstring(s, lib));
+	} else if(HEADTYPE == Hdarwin) {
+		machoadddynlib(lib);
+	} else {
+		diag("adddynlib: unsupported binary format");
+	}
+}
+
+void
+asmb(void)
+{
+	int32 magic;
+	int i;
+	vlong vl, symo, dwarfoff, machlink;
+	Section *sect;
+	LSym *sym;
+
+	if(debug['v'])
+		Bprint(&bso, "%5.2f asmb\n", cputime());
+	Bflush(&bso);
+
+	if(debug['v'])
+		Bprint(&bso, "%5.2f codeblk\n", cputime());
+	Bflush(&bso);
+
+	if(iself)
+		asmbelfsetup();
+
+	sect = segtext.sect;
+	cseek(sect->vaddr - segtext.vaddr + segtext.fileoff);
+	codeblk(sect->vaddr, sect->len);
+	for(sect = sect->next; sect != nil; sect = sect->next) {
+		cseek(sect->vaddr - segtext.vaddr + segtext.fileoff);
+		datblk(sect->vaddr, sect->len);
+	}
+
+	if(segrodata.filelen > 0) {
+		if(debug['v'])
+			Bprint(&bso, "%5.2f rodatblk\n", cputime());
+		Bflush(&bso);
+
+		cseek(segrodata.fileoff);
+		datblk(segrodata.vaddr, segrodata.filelen);
+	}
+
+	if(debug['v'])
+		Bprint(&bso, "%5.2f datblk\n", cputime());
+	Bflush(&bso);
+
+	cseek(segdata.fileoff);
+	datblk(segdata.vaddr, segdata.filelen);
+
+	machlink = 0;
+	if(HEADTYPE == Hdarwin) {
+		if(debug['v'])
+			Bprint(&bso, "%5.2f dwarf\n", cputime());
+
+		dwarfoff = rnd(HEADR+segtext.len, INITRND) + rnd(segdata.filelen, INITRND);
+		cseek(dwarfoff);
+
+		segdwarf.fileoff = cpos();
+		dwarfemitdebugsections();
+		segdwarf.filelen = cpos() - segdwarf.fileoff;
+
+		machlink = domacholink();
+	}
+
+	switch(HEADTYPE) {
+	default:
+		diag("unknown header type %d", HEADTYPE);
+	case Hplan9:
+	case Helf:
+		break;
+	case Hdarwin:
+		debug['8'] = 1;	/* 64-bit addresses */
+		break;
+	case Hlinux:
+	case Hfreebsd:
+	case Hnetbsd:
+	case Hopenbsd:
+	case Hdragonfly:
+	case Hsolaris:
+		debug['8'] = 1;	/* 64-bit addresses */
+		break;
+	case Hnacl:
+	case Hwindows:
+		break;
+	}
+
+	symsize = 0;
+	spsize = 0;
+	lcsize = 0;
+	symo = 0;
+	if(!debug['s']) {
+		if(debug['v'])
+			Bprint(&bso, "%5.2f sym\n", cputime());
+		Bflush(&bso);
+		switch(HEADTYPE) {
+		default:
+		case Hplan9:
+		case Helf:
+			debug['s'] = 1;
+			symo = segdata.fileoff+segdata.filelen;
+			break;
+		case Hdarwin:
+			symo = segdata.fileoff+rnd(segdata.filelen, INITRND)+machlink;
+			break;
+		case Hlinux:
+		case Hfreebsd:
+		case Hnetbsd:
+		case Hopenbsd:
+		case Hdragonfly:
+		case Hsolaris:
+		case Hnacl:
+			symo = segdata.fileoff+segdata.filelen;
+			symo = rnd(symo, INITRND);
+			break;
+		case Hwindows:
+			symo = segdata.fileoff+segdata.filelen;
+			symo = rnd(symo, PEFILEALIGN);
+			break;
+		}
+		cseek(symo);
+		switch(HEADTYPE) {
+		default:
+			if(iself) {
+				cseek(symo);
+				asmelfsym();
+				cflush();
+				cwrite(elfstrdat, elfstrsize);
+
+				if(debug['v'])
+				       Bprint(&bso, "%5.2f dwarf\n", cputime());
+
+				dwarfemitdebugsections();
+				
+				if(linkmode == LinkExternal)
+					elfemitreloc();
+			}
+			break;
+		case Hplan9:
+			asmplan9sym();
+			cflush();
+
+			sym = linklookup(ctxt, "pclntab", 0);
+			if(sym != nil) {
+				lcsize = sym->np;
+				for(i=0; i < lcsize; i++)
+					cput(sym->p[i]);
+				
+				cflush();
+			}
+			break;
+		case Hwindows:
+			if(debug['v'])
+			       Bprint(&bso, "%5.2f dwarf\n", cputime());
+
+			dwarfemitdebugsections();
+			break;
+		case Hdarwin:
+			if(linkmode == LinkExternal)
+				machoemitreloc();
+			break;
+		}
+	}
+
+	if(debug['v'])
+		Bprint(&bso, "%5.2f headr\n", cputime());
+	Bflush(&bso);
+	cseek(0L);
+	switch(HEADTYPE) {
+	default:
+	case Hplan9:	/* plan9 */
+		magic = 4*26*26+7;
+		magic |= 0x00008000;		/* fat header */
+		lputb(magic);			/* magic */
+		lputb(segtext.filelen);			/* sizes */
+		lputb(segdata.filelen);
+		lputb(segdata.len - segdata.filelen);
+		lputb(symsize);			/* nsyms */
+		vl = entryvalue();
+		lputb(PADDR(vl));		/* va of entry */
+		lputb(spsize);			/* sp offsets */
+		lputb(lcsize);			/* line offsets */
+		vputb(vl);			/* va of entry */
+		break;
+	case Hdarwin:
+		asmbmacho();
+		break;
+	case Hlinux:
+	case Hfreebsd:
+	case Hnetbsd:
+	case Hopenbsd:
+	case Hdragonfly:
+	case Hsolaris:
+	case Hnacl:
+		asmbelf(symo);
+		break;
+	case Hwindows:
+		asmbpe();
+		break;
+	}
+	cflush();
+}
+
+vlong
+rnd(vlong v, vlong r)
+{
+	vlong c;
+
+	if(r <= 0)
+		return v;
+	v += r - 1;
+	c = v % r;
+	if(c < 0)
+		c += r;
+	v -= c;
+	return v;
+}
diff --git a/src/cmd/6l/doc.go b/src/cmd/6l/doc.go
new file mode 100644
index 0000000..6287dd9
--- /dev/null
+++ b/src/cmd/6l/doc.go
@@ -0,0 +1,15 @@
+// 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
+
+/*
+
+6l is the linker for the x86-64.
+The $GOARCH for these tools is amd64.
+
+The flags are documented in ../ld/doc.go.
+
+*/
+package main
diff --git a/src/cmd/6l/l.h b/src/cmd/6l/l.h
new file mode 100644
index 0000000..ff2e694
--- /dev/null
+++ b/src/cmd/6l/l.h
@@ -0,0 +1,109 @@
+// Inferno utils/6l/l.h
+// 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.
+
+#include	<u.h>
+#include	<libc.h>
+#include	<bio.h>
+#include	<link.h>
+#include	"6.out.h"
+
+#ifndef	EXTERN
+#define	EXTERN	extern
+#endif
+
+enum
+{
+	thechar = '6',
+	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	int	PtrSize;
+EXTERN	int	IntSize;
+EXTERN	int	RegSize;
+
+#define	P		((Prog*)0)
+#define	S		((LSym*)0)
+enum
+{
+	MINLC		= 1,
+};
+
+#pragma	varargck	type	"I"	uchar*
+
+EXTERN	LSym*	datap;
+EXTERN	int	debug[128];
+EXTERN	char	literal[32];
+EXTERN	int32	lcsize;
+EXTERN	char*	rpath;
+EXTERN	int32	spsize;
+EXTERN	LSym*	symlist;
+EXTERN	int32	symsize;
+
+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);
+int	elfreloc1(Reloc *r, vlong sectoff);
+void	elfsetupplt(void);
+void	listinit(void);
+int	machoreloc1(Reloc *r, vlong sectoff);
+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)
+
+/* Used by ../ld/dwarf.c */
+enum
+{
+	DWARFREGSP = 7
+};
diff --git a/src/cmd/6l/list.c b/src/cmd/6l/list.c
new file mode 100644
index 0000000..d960fcc
--- /dev/null
+++ b/src/cmd/6l/list.c
@@ -0,0 +1,67 @@
+// Inferno utils/6l/list.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/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.
+
+// Printing.
+
+#include	"l.h"
+#include	"../ld/lib.h"
+
+void
+listinit(void)
+{
+	listinit6();
+	fmtinstall('I', Iconv);
+}
+
+int
+Iconv(Fmt *fp)
+{
+	int i, n;
+	uchar *p;
+	char *s;
+	Fmt fmt;
+	
+	n = fp->prec;
+	fp->prec = 0;
+	if(!(fp->flags&FmtPrec) || n < 0)
+		return fmtstrcpy(fp, "%I");
+	fp->flags &= ~FmtPrec;
+	p = va_arg(fp->args, uchar*);
+
+	// format into temporary buffer and
+	// call fmtstrcpy to handle padding.
+	fmtstrinit(&fmt);
+	for(i=0; i<n; i++)
+		fmtprint(&fmt, "%.2ux", *p++);
+	s = fmtstrflush(&fmt);
+	fmtstrcpy(fp, s);
+	free(s);
+	return 0;
+}
diff --git a/src/cmd/6l/obj.c b/src/cmd/6l/obj.c
new file mode 100644
index 0000000..3b8e8f4
--- /dev/null
+++ b/src/cmd/6l/obj.c
@@ -0,0 +1,157 @@
+// 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.
+
+#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*	thestring 	= "amd64";
+LinkArch*	thelinkarch = &linkamd64;
+
+void
+linkarchinit(void)
+{
+	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)
+		linkmode = LinkInternal;
+
+	if(flag_shared)
+		linkmode = LinkExternal;
+
+	switch(HEADTYPE) {
+	default:
+		if(linkmode == LinkAuto)
+			linkmode = LinkInternal;
+		if(linkmode == LinkExternal && strcmp(getgoextlinkenabled(), "1") != 0)
+			sysfatal("cannot use -linkmode=external with -H %s", headstr(HEADTYPE));
+		break;
+	case Hdarwin:
+	case Hdragonfly:
+	case Hfreebsd:
+	case Hlinux:
+	case Hnacl:
+	case Hnetbsd:
+	case Hopenbsd:
+	case Hsolaris:
+		break;
+	}
+
+	switch(HEADTYPE) {
+	default:
+		diag("unknown -H option");
+		errorexit();
+	case Hplan9:		/* plan 9 */
+		HEADR = 32L + 8L;
+		if(INITTEXT == -1)
+			INITTEXT = 0x200000+HEADR;
+		if(INITDAT == -1)
+			INITDAT = 0;
+		if(INITRND == -1)
+			INITRND = 0x200000;
+		break;
+	case Helf:		/* elf32 executable */
+		HEADR = rnd(52L+3*32L, 16);
+		if(INITTEXT == -1)
+			INITTEXT = 0x80110000L;
+		if(INITDAT == -1)
+			INITDAT = 0;
+		if(INITRND == -1)
+			INITRND = 4096;
+		break;
+	case Hdarwin:		/* apple MACH */
+		machoinit();
+		HEADR = INITIAL_MACHO_HEADR;
+		if(INITRND == -1)
+			INITRND = 4096;
+		if(INITTEXT == -1)
+			INITTEXT = 4096+HEADR;
+		if(INITDAT == -1)
+			INITDAT = 0;
+		break;
+	case Hlinux:		/* elf64 executable */
+	case Hfreebsd:		/* freebsd */
+	case Hnetbsd:		/* netbsd */
+	case Hopenbsd:		/* openbsd */
+	case Hdragonfly:	/* dragonfly */
+	case Hsolaris:		/* solaris */
+		elfinit();
+		HEADR = ELFRESERVE;
+		if(INITTEXT == -1)
+			INITTEXT = (1<<22)+HEADR;
+		if(INITDAT == -1)
+			INITDAT = 0;
+		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;
+		if(INITTEXT == -1)
+			INITTEXT = PEBASE+PESECTHEADR;
+		if(INITDAT == -1)
+			INITDAT = 0;
+		if(INITRND == -1)
+			INITRND = PESECTALIGN;
+		break;
+	}
+
+	if(INITDAT != 0 && INITRND != 0)
+		print("warning: -D0x%llux is ignored because of -R0x%ux\n",
+			INITDAT, INITRND);
+}
diff --git a/src/cmd/8a/Makefile b/src/cmd/8a/Makefile
new file mode 100644
index 0000000..27290dd
--- /dev/null
+++ b/src/cmd/8a/Makefile
@@ -0,0 +1,10 @@
+# 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
+
+install: y.tab.h
+
+y.tab.h: a.y
+	LANG=C LANGUAGE=en_US.UTF8 bison -d -v -y a.y
diff --git a/src/cmd/8a/a.h b/src/cmd/8a/a.h
new file mode 100644
index 0000000..adc388c
--- /dev/null
+++ b/src/cmd/8a/a.h
@@ -0,0 +1,182 @@
+// Inferno utils/8a/a.h
+// http://code.google.com/p/inferno-os/source/browse/utils/8a/a.h
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.	All rights reserved.
+//	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 <bio.h>
+#include <link.h>
+#include "../8l/8.out.h"
+
+#ifndef	EXTERN
+#define	EXTERN	extern
+#endif
+
+#undef	getc
+#undef	ungetc
+#undef	BUFSIZ
+
+#define	getc	ccgetc
+#define	ungetc	ccungetc
+
+typedef	struct	Sym	Sym;
+typedef	struct	Ref	Ref;
+typedef	struct	Io	Io;
+typedef	struct	Addr2	Addr2;
+
+#define	MAXALIGN	7
+#define	FPCHIP		1
+#define	NSYMB		500
+#define	BUFSIZ		8192
+#define	HISTSZ		20
+#ifndef	EOF
+#define	EOF		(-1)
+#endif
+#define	IGN		(-2)
+#define	GETC()		((--fi.c < 0)? filbuf(): *fi.p++ & 0xff)
+#define	NHASH		503
+#define	STRINGSZ	200
+#define	NMACRO		10
+
+struct	Sym
+{
+	Sym*	link;
+	Ref*	ref;
+	char*	macro;
+	int32	value;
+	ushort	type;
+	char	*name;
+	char	sym;
+};
+#define	S	((Sym*)0)
+
+struct	Ref
+{
+	int	class;
+};
+
+EXTERN struct
+{
+	char*	p;
+	int	c;
+} fi;
+
+struct	Io
+{
+	Io*	link;
+	char	b[BUFSIZ];
+	char*	p;
+	short	c;
+	short	f;
+};
+#define	I	((Io*)0)
+
+struct	Addr2
+{
+	Addr	from;
+	Addr	to;
+};
+
+enum
+{
+	CLAST,
+	CMACARG,
+	CMACRO,
+	CPREPROC,
+};
+
+EXTERN	int	debug[256];
+EXTERN	Sym*	hash[NHASH];
+EXTERN	char**	Dlist;
+EXTERN	int	nDlist;
+EXTERN	int	newflag;
+EXTERN	char*	hunk;
+EXTERN	char**	include;
+EXTERN	Io*	iofree;
+EXTERN	Io*	ionext;
+EXTERN	Io*	iostack;
+EXTERN	int32	lineno;
+EXTERN	int	nerrors;
+EXTERN	int32	nhunk;
+EXTERN	int	ninclude;
+EXTERN	int32	nsymb;
+EXTERN	Addr	nullgen;
+EXTERN	char*	outfile;
+EXTERN	int	pass;
+EXTERN	int32	pc;
+EXTERN	int	peekc;
+EXTERN	int32	stmtline;
+EXTERN	int	sym;
+EXTERN	char*	symb;
+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);
+void	ensuresymb(int32);
+void	errorexit(void);
+void	pushio(void);
+void	newio(void);
+void	newfile(char*, int);
+Sym*	slookup(char*);
+Sym*	lookup(void);
+void	syminit(Sym*);
+int32	yylex(void);
+int	getc(void);
+int	getnsc(void);
+void	unget(int);
+int	escchar(int);
+void	cinit(void);
+void	checkscale(int);
+void	pinit(char*);
+void	cclean(void);
+int	isreg(Addr*);
+void	outcode(int, Addr2*);
+void	outhist(void);
+int	filbuf(void);
+Sym*	getsym(void);
+void	domacro(void);
+void	macund(void);
+void	macdef(void);
+void	macexpand(Sym*, char*);
+void	macinc(void);
+void	macprag(void);
+void	maclin(void);
+void	macif(int);
+void	macend(void);
+void	dodefine(char*);
+void	prfile(int32);
+void	linehist(char*, int);
+void	gethunk(void);
+void	yyerror(char*, ...);
+int	yyparse(void);
+void	setinclude(char*);
+int	assemble(char*);
diff --git a/src/cmd/8a/a.y b/src/cmd/8a/a.y
new file mode 100644
index 0000000..6bcf131
--- /dev/null
+++ b/src/cmd/8a/a.y
@@ -0,0 +1,687 @@
+// Inferno utils/8a/a.y
+// http://code.google.com/p/inferno-os/source/browse/utils/8a/a.y
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.	All rights reserved.
+//	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 <stdio.h>	/* if we don't, bison will, and a.h re-#defines getc */
+#include <libc.h>
+#include "a.h"
+#include "../../runtime/funcdata.h"
+%}
+%union	{
+	Sym	*sym;
+	int32	lval;
+	struct {
+		int32 v1;
+		int32 v2;
+	} con2;
+	double	dval;
+	char	sval[8];
+	Addr	addr;
+	Addr2	addr2;
+}
+%left	'|'
+%left	'^'
+%left	'&'
+%left	'<' '>'
+%left	'+' '-'
+%left	'*' '/' '%'
+%token	<lval>	LTYPE0 LTYPE1 LTYPE2 LTYPE3 LTYPE4
+%token	<lval>	LTYPEC LTYPED LTYPEN LTYPER LTYPET LTYPES LTYPEM LTYPEI LTYPEG LTYPEXC
+%token	<lval>	LTYPEX LTYPEPC LTYPEF LCONST LFP LPC LSB
+%token	<lval>	LBREG LLREG LSREG LFREG LXREG
+%token	<dval>	LFCONST
+%token	<sval>	LSCONST LSP
+%token	<sym>	LNAME LLAB LVAR
+%type	<lval>	con expr pointer offset
+%type	<con2>	con2
+%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
+	{
+		stmtline = lineno;
+	}
+	line
+
+line:
+	LLAB ':'
+	{
+		if($1->value != pc)
+			yyerror("redeclaration of %s", $1->name);
+		$1->value = pc;
+	}
+	line
+|	LNAME ':'
+	{
+		$1->type = LLAB;
+		$1->value = pc;
+	}
+	line
+|	';'
+|	inst ';'
+|	error ';'
+
+inst:
+	LNAME '=' expr
+	{
+		$1->type = LVAR;
+		$1->value = $3;
+	}
+|	LVAR '=' expr
+	{
+		if($1->value != $3)
+			yyerror("redeclaration of %s", $1->name);
+		$1->value = $3;
+	}
+|	LTYPE0 nonnon	{ outcode($1, &$2); }
+|	LTYPE1 nonrem	{ outcode($1, &$2); }
+|	LTYPE2 rimnon	{ outcode($1, &$2); }
+|	LTYPE3 rimrem	{ outcode($1, &$2); }
+|	LTYPE4 remrim	{ outcode($1, &$2); }
+|	LTYPER nonrel	{ outcode($1, &$2); }
+|	LTYPED spec1	{ outcode($1, &$2); }
+|	LTYPET spec2	{ outcode($1, &$2); }
+|	LTYPEC spec3	{ outcode($1, &$2); }
+|	LTYPEN spec4	{ outcode($1, &$2); }
+|	LTYPES spec5	{ outcode($1, &$2); }
+|	LTYPEM spec6	{ outcode($1, &$2); }
+|	LTYPEI spec7	{ outcode($1, &$2); }
+|	LTYPEG spec8	{ outcode($1, &$2); }
+|	LTYPEXC spec9	{ outcode($1, &$2); }
+|	LTYPEX spec10	{ outcode($1, &$2); }
+|	LTYPEPC spec11	{ outcode($1, &$2); }
+|	LTYPEF spec12	{ outcode($1, &$2); }
+
+nonnon:
+	{
+		$$.from = nullgen;
+		$$.to = nullgen;
+	}
+|	','
+	{
+		$$.from = nullgen;
+		$$.to = nullgen;
+	}
+
+rimrem:
+	rim ',' rem
+	{
+		$$.from = $1;
+		$$.to = $3;
+	}
+
+remrim:
+	rem ',' rim
+	{
+		$$.from = $1;
+		$$.to = $3;
+	}
+
+rimnon:
+	rim ','
+	{
+		$$.from = $1;
+		$$.to = nullgen;
+	}
+|	rim
+	{
+		$$.from = $1;
+		$$.to = nullgen;
+	}
+
+nonrem:
+	',' rem
+	{
+		$$.from = nullgen;
+		$$.to = $2;
+	}
+|	rem
+	{
+		$$.from = nullgen;
+		$$.to = $1;
+	}
+
+nonrel:
+	',' rel
+	{
+		$$.from = nullgen;
+		$$.to = $2;
+	}
+|	rel
+	{
+		$$.from = nullgen;
+		$$.to = $1;
+	}
+|	imm ',' rel
+	{
+		$$.from = $1;
+		$$.to = $3;
+	}
+
+spec1:	/* DATA */
+	nam '/' con ',' imm
+	{
+		$$.from = $1;
+		$$.from.scale = $3;
+		$$.to = $5;
+	}
+
+spec2:	/* TEXT */
+	mem ',' imm2
+	{
+		$$.from = $1;
+		$$.to = $3;
+	}
+|	mem ',' con ',' imm2
+	{
+		$$.from = $1;
+		$$.from.scale = $3;
+		$$.to = $5;
+	}
+
+spec3:	/* JMP/CALL */
+	',' rom
+	{
+		$$.from = nullgen;
+		$$.to = $2;
+	}
+|	rom
+	{
+		$$.from = nullgen;
+		$$.to = $1;
+	}
+|	'*' nam
+	{
+		$$.from = nullgen;
+		$$.to = $2;
+		$$.to.index = $2.type;
+		$$.to.type = D_INDIR+D_ADDR;
+	}
+
+spec4:	/* NOP */
+	nonnon
+|	nonrem
+
+spec5:	/* SHL/SHR */
+	rim ',' rem
+	{
+		$$.from = $1;
+		$$.to = $3;
+	}
+|	rim ',' rem ':' LLREG
+	{
+		$$.from = $1;
+		$$.to = $3;
+		if($$.from.index != D_NONE)
+			yyerror("dp shift with lhs index");
+		$$.from.index = $5;
+	}
+
+spec6:	/* MOVW/MOVL */
+	rim ',' rem
+	{
+		$$.from = $1;
+		$$.to = $3;
+	}
+|	rim ',' rem ':' LSREG
+	{
+		$$.from = $1;
+		$$.to = $3;
+		if($$.to.index != D_NONE)
+			yyerror("dp move with lhs index");
+		$$.to.index = $5;
+	}
+
+spec7:
+	rim ','
+	{
+		$$.from = $1;
+		$$.to = nullgen;
+	}
+|	rim
+	{
+		$$.from = $1;
+		$$.to = nullgen;
+	}
+|	rim ',' rem
+	{
+		$$.from = $1;
+		$$.to = $3;
+	}
+
+spec8:	/* GLOBL */
+	mem ',' imm
+	{
+		$$.from = $1;
+		$$.to = $3;
+	}
+|	mem ',' con ',' imm
+	{
+		$$.from = $1;
+		$$.from.scale = $3;
+		$$.to = $5;
+	}
+
+spec9:	/* CMPPS/CMPPD */
+	reg ',' rem ',' con
+	{
+		$$.from = $1;
+		$$.to = $3;
+		$$.to.offset = $5;
+	}
+
+spec10:	/* PINSRD */
+	imm ',' rem ',' reg
+	{
+		$$.from = $3;
+		$$.to = $5;
+		if($1.type != D_CONST)
+			yyerror("illegal constant");
+		$$.to.offset = $1.offset;
+	}
+
+spec11:	/* PCDATA */
+	rim ',' rim
+	{
+		if($1.type != D_CONST || $3.type != D_CONST)
+			yyerror("arguments to PCDATA must be integer constants");
+		$$.from = $1;
+		$$.to = $3;
+	}
+
+spec12:	/* FUNCDATA */
+	rim ',' rim
+	{
+		if($1.type != D_CONST)
+			yyerror("index for FUNCDATA must be integer constant");
+		if($3.type != D_EXTERN && $3.type != D_STATIC)
+			yyerror("value for FUNCDATA must be symbol reference");
+ 		$$.from = $1;
+ 		$$.to = $3;
+ 	}
+
+rem:
+	reg
+|	mem
+
+rom:
+	rel
+|	nmem
+|	'*' reg
+	{
+		$$ = $2;
+	}
+|	'*' omem
+	{
+		$$ = $2;
+	}
+|	reg
+|	omem
+|	imm
+
+rim:
+	rem
+|	imm
+
+rel:
+	con '(' LPC ')'
+	{
+		$$ = nullgen;
+		$$.type = D_BRANCH;
+		$$.offset = $1 + pc;
+	}
+|	LNAME offset
+	{
+		$$ = nullgen;
+		if(pass == 2)
+			yyerror("undefined label: %s", $1->name);
+		$$.type = D_BRANCH;
+		$$.offset = $2;
+	}
+|	LLAB offset
+	{
+		$$ = nullgen;
+		$$.type = D_BRANCH;
+		$$.offset = $1->value + $2;
+	}
+
+reg:
+	LBREG
+	{
+		$$ = nullgen;
+		$$.type = $1;
+	}
+|	LFREG
+	{
+		$$ = nullgen;
+		$$.type = $1;
+	}
+|	LLREG
+	{
+		$$ = nullgen;
+		$$.type = $1;
+	}
+|	LXREG
+	{
+		$$ = nullgen;
+		$$.type = $1;
+	}
+|	LSP
+	{
+		$$ = nullgen;
+		$$.type = D_SP;
+	}
+|	LSREG
+	{
+		$$ = nullgen;
+		$$.type = $1;
+	}
+
+imm:
+	'$' con
+	{
+		$$ = nullgen;
+		$$.type = D_CONST;
+		$$.offset = $2;
+	}
+|	'$' nam
+	{
+		$$ = $2;
+		$$.index = $2.type;
+		$$.type = D_ADDR;
+		/*
+		if($2.type == D_AUTO || $2.type == D_PARAM)
+			yyerror("constant cannot be automatic: %s",
+				$2.sym->name);
+		 */
+	}
+|	'$' LSCONST
+	{
+		$$ = nullgen;
+		$$.type = D_SCONST;
+		memcpy($$.u.sval, $2, sizeof($$.u.sval));
+	}
+|	'$' LFCONST
+	{
+		$$ = nullgen;
+		$$.type = D_FCONST;
+		$$.u.dval = $2;
+	}
+|	'$' '(' LFCONST ')'
+	{
+		$$ = nullgen;
+		$$.type = D_FCONST;
+		$$.u.dval = $3;
+	}
+|	'$' '(' '-' LFCONST ')'
+	{
+		$$ = nullgen;
+		$$.type = D_FCONST;
+		$$.u.dval = -$4;
+	}
+|	'$' '-' LFCONST
+	{
+		$$ = nullgen;
+		$$.type = D_FCONST;
+		$$.u.dval = -$3;
+	}
+
+imm2:
+	'$' con2
+	{
+		$$ = nullgen;
+		$$.type = D_CONST2;
+		$$.offset = $2.v1;
+		$$.offset2 = $2.v2;
+	}
+
+con2:
+	LCONST
+	{
+		$$.v1 = $1;
+		$$.v2 = ArgsSizeUnknown;
+	}
+|	'-' LCONST
+	{
+		$$.v1 = -$2;
+		$$.v2 = ArgsSizeUnknown;
+	}
+|	LCONST '-' LCONST
+	{
+		$$.v1 = $1;
+		$$.v2 = $3;
+	}
+|	'-' LCONST '-' LCONST
+	{
+		$$.v1 = -$2;
+		$$.v2 = $4;
+	}
+
+mem:
+	omem
+|	nmem
+
+omem:
+	con
+	{
+		$$ = nullgen;
+		$$.type = D_INDIR+D_NONE;
+		$$.offset = $1;
+	}
+|	con '(' LLREG ')'
+	{
+		$$ = nullgen;
+		$$.type = D_INDIR+$3;
+		$$.offset = $1;
+	}
+|	con '(' LSP ')'
+	{
+		$$ = nullgen;
+		$$.type = D_INDIR+D_SP;
+		$$.offset = $1;
+	}
+|	con '(' LLREG '*' con ')'
+	{
+		$$ = nullgen;
+		$$.type = D_INDIR+D_NONE;
+		$$.offset = $1;
+		$$.index = $3;
+		$$.scale = $5;
+		checkscale($$.scale);
+	}
+|	con '(' LLREG ')' '(' LLREG '*' con ')'
+	{
+		$$ = nullgen;
+		$$.type = D_INDIR+$3;
+		$$.offset = $1;
+		$$.index = $6;
+		$$.scale = $8;
+		checkscale($$.scale);
+	}
+|	con '(' LLREG ')' '(' LSREG '*' con ')'
+	{
+		$$ = nullgen;
+		$$.type = D_INDIR+$3;
+		$$.offset = $1;
+		$$.index = $6;
+		$$.scale = $8;
+		checkscale($$.scale);
+	}
+|	'(' LLREG ')'
+	{
+		$$ = nullgen;
+		$$.type = D_INDIR+$2;
+	}
+|	'(' LSP ')'
+	{
+		$$ = nullgen;
+		$$.type = D_INDIR+D_SP;
+	}
+|	con '(' LSREG ')'
+	{
+		$$ = nullgen;
+		$$.type = D_INDIR+$3;
+		$$.offset = $1;
+	}
+|	'(' LLREG '*' con ')'
+	{
+		$$ = nullgen;
+		$$.type = D_INDIR+D_NONE;
+		$$.index = $2;
+		$$.scale = $4;
+		checkscale($$.scale);
+	}
+|	'(' LLREG ')' '(' LLREG '*' con ')'
+	{
+		$$ = nullgen;
+		$$.type = D_INDIR+$2;
+		$$.index = $5;
+		$$.scale = $7;
+		checkscale($$.scale);
+	}
+
+nmem:
+	nam
+	{
+		$$ = $1;
+	}
+|	nam '(' LLREG '*' con ')'
+	{
+		$$ = $1;
+		$$.index = $3;
+		$$.scale = $5;
+		checkscale($$.scale);
+	}
+
+nam:
+	LNAME offset '(' pointer ')'
+	{
+		$$ = nullgen;
+		$$.type = $4;
+		$$.sym = linklookup(ctxt, $1->name, 0);
+		$$.offset = $2;
+	}
+|	LNAME '<' '>' offset '(' LSB ')'
+	{
+		$$ = nullgen;
+		$$.type = D_STATIC;
+		$$.sym = linklookup(ctxt, $1->name, 1);
+		$$.offset = $4;
+	}
+
+offset:
+	{
+		$$ = 0;
+	}
+|	'+' con
+	{
+		$$ = $2;
+	}
+|	'-' con
+	{
+		$$ = -$2;
+	}
+
+pointer:
+	LSB
+|	LSP
+	{
+		$$ = D_AUTO;
+	}
+|	LFP
+
+con:
+	LCONST
+|	LVAR
+	{
+		$$ = $1->value;
+	}
+|	'-' con
+	{
+		$$ = -$2;
+	}
+|	'+' con
+	{
+		$$ = $2;
+	}
+|	'~' con
+	{
+		$$ = ~$2;
+	}
+|	'(' expr ')'
+	{
+		$$ = $2;
+	}
+
+expr:
+	con
+|	expr '+' expr
+	{
+		$$ = $1 + $3;
+	}
+|	expr '-' expr
+	{
+		$$ = $1 - $3;
+	}
+|	expr '*' expr
+	{
+		$$ = $1 * $3;
+	}
+|	expr '/' expr
+	{
+		$$ = $1 / $3;
+	}
+|	expr '%' expr
+	{
+		$$ = $1 % $3;
+	}
+|	expr '<' '<' expr
+	{
+		$$ = $1 << $4;
+	}
+|	expr '>' '>' expr
+	{
+		$$ = $1 >> $4;
+	}
+|	expr '&' expr
+	{
+		$$ = $1 & $3;
+	}
+|	expr '^' expr
+	{
+		$$ = $1 ^ $3;
+	}
+|	expr '|' expr
+	{
+		$$ = $1 | $3;
+	}
diff --git a/src/cmd/8a/doc.go b/src/cmd/8a/doc.go
new file mode 100644
index 0000000..84c7254
--- /dev/null
+++ b/src/cmd/8a/doc.go
@@ -0,0 +1,21 @@
+// 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
+
+/*
+
+8a is a version of the Plan 9 assembler.  The original is documented at
+
+	http://plan9.bell-labs.com/magic/man2html/1/8a
+
+Go-specific considerations are documented at
+
+	http://golang.org/doc/asm
+
+I
+Its target architecture is the x86, referred to by these tools for historical reasons as 386.
+
+*/
+package main
diff --git a/src/cmd/8a/lex.c b/src/cmd/8a/lex.c
new file mode 100644
index 0000000..6ce6a18
--- /dev/null
+++ b/src/cmd/8a/lex.c
@@ -0,0 +1,910 @@
+// Inferno utils/8a/lex.c
+// http://code.google.com/p/inferno-os/source/browse/utils/8a/lex.c
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.	All rights reserved.
+//	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.
+
+#define	EXTERN
+#include <u.h>
+#include <libc.h>
+#include "a.h"
+#include "y.tab.h"
+
+enum
+{
+	Plan9	= 1<<0,
+	Unix	= 1<<1,
+	Windows	= 1<<2,
+};
+
+int
+systemtype(int sys)
+{
+#ifdef _WIN32
+	return sys&Windows;
+#else
+	return sys&Plan9;
+#endif
+}
+
+int
+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;
+
+	thechar = '8';
+	thestring = "386";
+
+	ctxt = linknew(&link386);
+	ctxt->diag = yyerror;
+	ctxt->bso = &bstdout;
+	ctxt->enforce_data_order = 1;
+	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(".");
+	
+	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);
+}
+
+int
+assemble(char *file)
+{
+	char *ofile, *p;
+	int i, of;
+
+	ofile = alloc(strlen(file)+3); // +3 for .x\0 (x=thechar)
+	strcpy(ofile, file);
+	p = utfrrune(ofile, pathchar());
+	if(p) {
+		include[0] = ofile;
+		*p++ = 0;
+	} else
+		p = ofile;
+	if(outfile == 0) {
+		outfile = p;
+		if(outfile){
+			p = utfrrune(outfile, '.');
+			if(p)
+				if(p[1] == 's' && p[2] == 0)
+					p[0] = 0;
+			p = utfrune(outfile, 0);
+			p[0] = '.';
+			p[1] = thechar;
+			p[2] = 0;
+		} else
+			outfile = "/dev/null";
+	}
+
+	of = create(outfile, OWRITE, 0664);
+	if(of < 0) {
+		yyerror("%ca: cannot create %s", thechar, outfile);
+		errorexit();
+	}
+	Binit(&obuf, of, OWRITE);
+	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();
+		if(nerrors)
+			return nerrors;
+	}
+
+	writeobj(ctxt, &obuf);
+	Bflush(&obuf);
+	return 0;
+}
+
+struct
+{
+	char	*name;
+	ushort	type;
+	ushort	value;
+} itab[] =
+{
+	"SP",		LSP,	D_AUTO,
+	"SB",		LSB,	D_EXTERN,
+	"FP",		LFP,	D_PARAM,
+	"PC",		LPC,	D_BRANCH,
+
+	"AL",		LBREG,	D_AL,
+	"CL",		LBREG,	D_CL,
+	"DL",		LBREG,	D_DL,
+	"BL",		LBREG,	D_BL,
+	"AH",		LBREG,	D_AH,
+	"CH",		LBREG,	D_CH,
+	"DH",		LBREG,	D_DH,
+	"BH",		LBREG,	D_BH,
+
+	"AX",		LLREG,	D_AX,
+	"CX",		LLREG,	D_CX,
+	"DX",		LLREG,	D_DX,
+	"BX",		LLREG,	D_BX,
+/*	"SP",		LLREG,	D_SP,	*/
+	"BP",		LLREG,	D_BP,
+	"SI",		LLREG,	D_SI,
+	"DI",		LLREG,	D_DI,
+
+	"F0",		LFREG,	D_F0+0,
+	"F1",		LFREG,	D_F0+1,
+	"F2",		LFREG,	D_F0+2,
+	"F3",		LFREG,	D_F0+3,
+	"F4",		LFREG,	D_F0+4,
+	"F5",		LFREG,	D_F0+5,
+	"F6",		LFREG,	D_F0+6,
+	"F7",		LFREG,	D_F0+7,
+
+	"X0",		LXREG,	D_X0+0,
+	"X1",		LXREG,	D_X0+1,
+	"X2",		LXREG,	D_X0+2,
+	"X3",		LXREG,	D_X0+3,
+	"X4",		LXREG,	D_X0+4,
+	"X5",		LXREG,	D_X0+5,
+	"X6",		LXREG,	D_X0+6,
+	"X7",		LXREG,	D_X0+7,
+
+	"CS",		LSREG,	D_CS,
+	"SS",		LSREG,	D_SS,
+	"DS",		LSREG,	D_DS,
+	"ES",		LSREG,	D_ES,
+	"FS",		LSREG,	D_FS,
+	"GS",		LSREG,	D_GS,
+	"TLS",		LSREG,	D_TLS,
+
+	"GDTR",		LBREG,	D_GDTR,
+	"IDTR",		LBREG,	D_IDTR,
+	"LDTR",		LBREG,	D_LDTR,
+	"MSW",		LBREG,	D_MSW,
+	"TASK",		LBREG,	D_TASK,
+
+	"CR0",		LBREG,	D_CR+0,
+	"CR1",		LBREG,	D_CR+1,
+	"CR2",		LBREG,	D_CR+2,
+	"CR3",		LBREG,	D_CR+3,
+	"CR4",		LBREG,	D_CR+4,
+	"CR5",		LBREG,	D_CR+5,
+	"CR6",		LBREG,	D_CR+6,
+	"CR7",		LBREG,	D_CR+7,
+
+	"DR0",		LBREG,	D_DR+0,
+	"DR1",		LBREG,	D_DR+1,
+	"DR2",		LBREG,	D_DR+2,
+	"DR3",		LBREG,	D_DR+3,
+	"DR4",		LBREG,	D_DR+4,
+	"DR5",		LBREG,	D_DR+5,
+	"DR6",		LBREG,	D_DR+6,
+	"DR7",		LBREG,	D_DR+7,
+
+	"TR0",		LBREG,	D_TR+0,
+	"TR1",		LBREG,	D_TR+1,
+	"TR2",		LBREG,	D_TR+2,
+	"TR3",		LBREG,	D_TR+3,
+	"TR4",		LBREG,	D_TR+4,
+	"TR5",		LBREG,	D_TR+5,
+	"TR6",		LBREG,	D_TR+6,
+	"TR7",		LBREG,	D_TR+7,
+
+	"AAA",		LTYPE0,	AAAA,
+	"AAD",		LTYPE0,	AAAD,
+	"AAM",		LTYPE0,	AAAM,
+	"AAS",		LTYPE0,	AAAS,
+	"ADCB",		LTYPE3,	AADCB,
+	"ADCL",		LTYPE3,	AADCL,
+	"ADCW",		LTYPE3,	AADCW,
+	"ADDB",		LTYPE3,	AADDB,
+	"ADDL",		LTYPE3,	AADDL,
+	"ADDW",		LTYPE3,	AADDW,
+	"ADJSP",	LTYPE2,	AADJSP,
+	"ANDB",		LTYPE3,	AANDB,
+	"ANDL",		LTYPE3,	AANDL,
+	"ANDW",		LTYPE3,	AANDW,
+	"ARPL",		LTYPE3,	AARPL,
+	"BOUNDL",	LTYPE3,	ABOUNDL,
+	"BOUNDW",	LTYPE3,	ABOUNDW,
+	"BSFL",		LTYPE3,	ABSFL,
+	"BSFW",		LTYPE3,	ABSFW,
+	"BSRL",		LTYPE3,	ABSRL,
+	"BSRW",		LTYPE3,	ABSRW,
+	"BSWAPL",	LTYPE1,	ABSWAPL,
+	"BTCL",		LTYPE3,	ABTCL,
+	"BTCW",		LTYPE3,	ABTCW,
+	"BTL",		LTYPE3,	ABTL,
+	"BTRL",		LTYPE3,	ABTRL,
+	"BTRW",		LTYPE3,	ABTRW,
+	"BTSL",		LTYPE3,	ABTSL,
+	"BTSW",		LTYPE3,	ABTSW,
+	"BTW",		LTYPE3,	ABTW,
+	"BYTE",		LTYPE2,	ABYTE,
+	"CALL",		LTYPEC,	ACALL,
+	"CLC",		LTYPE0,	ACLC,
+	"CLD",		LTYPE0,	ACLD,
+	"CLI",		LTYPE0,	ACLI,
+	"CLTS",		LTYPE0,	ACLTS,
+	"CMC",		LTYPE0,	ACMC,
+	"CMPB",		LTYPE4,	ACMPB,
+	"CMPL",		LTYPE4,	ACMPL,
+	"CMPW",		LTYPE4,	ACMPW,
+	"CMPSB",	LTYPE0,	ACMPSB,
+	"CMPSL",	LTYPE0,	ACMPSL,
+	"CMPSW",	LTYPE0,	ACMPSW,
+	"CMPXCHG8B",	LTYPE1,	ACMPXCHG8B,
+	"CMPXCHGB",	LTYPE3,	ACMPXCHGB,
+	"CMPXCHGL",	LTYPE3,	ACMPXCHGL,
+	"CMPXCHGW",	LTYPE3,	ACMPXCHGW,
+	"CPUID",	LTYPE0,	ACPUID,
+	"DAA",		LTYPE0,	ADAA,
+	"DAS",		LTYPE0,	ADAS,
+	"DATA",		LTYPED,	ADATA,
+	"DECB",		LTYPE1,	ADECB,
+	"DECL",		LTYPE1,	ADECL,
+	"DECW",		LTYPE1,	ADECW,
+	"DIVB",		LTYPE2,	ADIVB,
+	"DIVL",		LTYPE2,	ADIVL,
+	"DIVW",		LTYPE2,	ADIVW,
+	"END",		LTYPE0,	AEND,
+	"ENTER",	LTYPE2,	AENTER,
+	"GLOBL",	LTYPEG,	AGLOBL,
+	"HLT",		LTYPE0,	AHLT,
+	"IDIVB",	LTYPE2,	AIDIVB,
+	"IDIVL",	LTYPE2,	AIDIVL,
+	"IDIVW",	LTYPE2,	AIDIVW,
+	"IMULB",	LTYPE2,	AIMULB,
+	"IMULL",	LTYPEI,	AIMULL,
+	"IMULW",	LTYPEI,	AIMULW,
+	"INB",		LTYPE0,	AINB,
+	"INL",		LTYPE0,	AINL,
+	"INW",		LTYPE0,	AINW,
+	"INCB",		LTYPE1,	AINCB,
+	"INCL",		LTYPE1,	AINCL,
+	"INCW",		LTYPE1,	AINCW,
+	"INSB",		LTYPE0,	AINSB,
+	"INSL",		LTYPE0,	AINSL,
+	"INSW",		LTYPE0,	AINSW,
+	"INT",		LTYPE2,	AINT,
+	"INTO",		LTYPE0,	AINTO,
+	"IRETL",	LTYPE0,	AIRETL,
+	"IRETW",	LTYPE0,	AIRETW,
+
+	"JOS",		LTYPER,	AJOS,	/* overflow set (OF = 1) */
+	"JO",		LTYPER,	AJOS,	/* alternate */
+	"JOC",		LTYPER,	AJOC,	/* overflow clear (OF = 0) */
+	"JNO",		LTYPER,	AJOC,	/* alternate */
+	"JCS",		LTYPER,	AJCS,	/* carry set (CF = 1) */
+	"JB",		LTYPER,	AJCS,	/* alternate */
+	"JC",		LTYPER,	AJCS,	/* alternate */
+	"JNAE",		LTYPER,	AJCS,	/* alternate */
+	"JLO",		LTYPER,	AJCS,	/* alternate */
+	"JCC",		LTYPER,	AJCC,	/* carry clear (CF = 0) */
+	"JAE",		LTYPER,	AJCC,	/* alternate */
+	"JNB",		LTYPER,	AJCC,	/* alternate */
+	"JNC",		LTYPER,	AJCC,	/* alternate */
+	"JHS",		LTYPER,	AJCC,	/* alternate */
+	"JEQ",		LTYPER,	AJEQ,	/* equal (ZF = 1) */
+	"JE",		LTYPER,	AJEQ,	/* alternate */
+	"JZ",		LTYPER,	AJEQ,	/* alternate */
+	"JNE",		LTYPER,	AJNE,	/* not equal (ZF = 0) */
+	"JNZ",		LTYPER,	AJNE,	/* alternate */
+	"JLS",		LTYPER,	AJLS,	/* lower or same (unsigned) (CF = 1 || ZF = 1) */
+	"JBE",		LTYPER,	AJLS,	/* alternate */
+	"JNA",		LTYPER,	AJLS,	/* alternate */
+	"JHI",		LTYPER,	AJHI,	/* higher (unsigned) (CF = 0 && ZF = 0) */
+	"JA",		LTYPER,	AJHI,	/* alternate */
+	"JNBE",		LTYPER,	AJHI,	/* alternate */
+	"JMI",		LTYPER,	AJMI,	/* negative (minus) (SF = 1) */
+	"JS",		LTYPER,	AJMI,	/* alternate */
+	"JPL",		LTYPER,	AJPL,	/* non-negative (plus) (SF = 0) */
+	"JNS",		LTYPER,	AJPL,	/* alternate */
+	"JPS",		LTYPER,	AJPS,	/* parity set (PF = 1) */
+	"JP",		LTYPER,	AJPS,	/* alternate */
+	"JPE",		LTYPER,	AJPS,	/* alternate */
+	"JPC",		LTYPER,	AJPC,	/* parity clear (PF = 0) */
+	"JNP",		LTYPER,	AJPC,	/* alternate */
+	"JPO",		LTYPER,	AJPC,	/* alternate */
+	"JLT",		LTYPER,	AJLT,	/* less than (signed) (SF != OF) */
+	"JL",		LTYPER,	AJLT,	/* alternate */
+	"JNGE",		LTYPER,	AJLT,	/* alternate */
+	"JGE",		LTYPER,	AJGE,	/* greater than or equal (signed) (SF = OF) */
+	"JNL",		LTYPER,	AJGE,	/* alternate */
+	"JLE",		LTYPER,	AJLE,	/* less than or equal (signed) (ZF = 1 || SF != OF) */
+	"JNG",		LTYPER,	AJLE,	/* alternate */
+	"JGT",		LTYPER,	AJGT,	/* greater than (signed) (ZF = 0 && SF = OF) */
+	"JG",		LTYPER,	AJGT,	/* alternate */
+	"JNLE",		LTYPER,	AJGT,	/* alternate */
+
+	"JCXZL",	LTYPER,	AJCXZL,
+	"JCXZW",	LTYPER,	AJCXZW,
+	"JMP",		LTYPEC,	AJMP,
+	"LAHF",		LTYPE0,	ALAHF,
+	"LARL",		LTYPE3,	ALARL,
+	"LARW",		LTYPE3,	ALARW,
+	"LEAL",		LTYPE3,	ALEAL,
+	"LEAW",		LTYPE3,	ALEAW,
+	"LEAVEL",	LTYPE0,	ALEAVEL,
+	"LEAVEW",	LTYPE0,	ALEAVEW,
+	"LOCK",		LTYPE0,	ALOCK,
+	"LODSB",	LTYPE0,	ALODSB,
+	"LODSL",	LTYPE0,	ALODSL,
+	"LODSW",	LTYPE0,	ALODSW,
+	"LONG",		LTYPE2,	ALONG,
+	"LOOP",		LTYPER,	ALOOP,
+	"LOOPEQ",	LTYPER,	ALOOPEQ,
+	"LOOPNE",	LTYPER,	ALOOPNE,
+	"LSLL",		LTYPE3,	ALSLL,
+	"LSLW",		LTYPE3,	ALSLW,
+	"MOVB",		LTYPE3,	AMOVB,
+	"MOVL",		LTYPEM,	AMOVL,
+	"MOVW",		LTYPEM,	AMOVW,
+	"MOVQ",		LTYPEM, AMOVQ,
+	"MOVBLSX",	LTYPE3, AMOVBLSX,
+	"MOVBLZX",	LTYPE3, AMOVBLZX,
+	"MOVBWSX",	LTYPE3, AMOVBWSX,
+	"MOVBWZX",	LTYPE3, AMOVBWZX,
+	"MOVWLSX",	LTYPE3, AMOVWLSX,
+	"MOVWLZX",	LTYPE3, AMOVWLZX,
+	"MOVSB",	LTYPE0,	AMOVSB,
+	"MOVSL",	LTYPE0,	AMOVSL,
+	"MOVSW",	LTYPE0,	AMOVSW,
+	"MULB",		LTYPE2,	AMULB,
+	"MULL",		LTYPE2,	AMULL,
+	"MULW",		LTYPE2,	AMULW,
+	"NEGB",		LTYPE1,	ANEGB,
+	"NEGL",		LTYPE1,	ANEGL,
+	"NEGW",		LTYPE1,	ANEGW,
+	"NOP",		LTYPEN,	ANOP,
+	"NOTB",		LTYPE1,	ANOTB,
+	"NOTL",		LTYPE1,	ANOTL,
+	"NOTW",		LTYPE1,	ANOTW,
+	"ORB",		LTYPE3,	AORB,
+	"ORL",		LTYPE3,	AORL,
+	"ORW",		LTYPE3,	AORW,
+	"OUTB",		LTYPE0,	AOUTB,
+	"OUTL",		LTYPE0,	AOUTL,
+	"OUTW",		LTYPE0,	AOUTW,
+	"OUTSB",	LTYPE0,	AOUTSB,
+	"OUTSL",	LTYPE0,	AOUTSL,
+	"OUTSW",	LTYPE0,	AOUTSW,
+	"PAUSE",	LTYPEN,	APAUSE,
+	"PINSRD",	LTYPEX,	APINSRD,
+	"POPAL",	LTYPE0,	APOPAL,
+	"POPAW",	LTYPE0,	APOPAW,
+	"POPFL",	LTYPE0,	APOPFL,
+	"POPFW",	LTYPE0,	APOPFW,
+	"POPL",		LTYPE1,	APOPL,
+	"POPW",		LTYPE1,	APOPW,
+	"PUSHAL",	LTYPE0,	APUSHAL,
+	"PUSHAW",	LTYPE0,	APUSHAW,
+	"PUSHFL",	LTYPE0,	APUSHFL,
+	"PUSHFW",	LTYPE0,	APUSHFW,
+	"PUSHL",	LTYPE2,	APUSHL,
+	"PUSHW",	LTYPE2,	APUSHW,
+	"RCLB",		LTYPE3,	ARCLB,
+	"RCLL",		LTYPE3,	ARCLL,
+	"RCLW",		LTYPE3,	ARCLW,
+	"RCRB",		LTYPE3,	ARCRB,
+	"RCRL",		LTYPE3,	ARCRL,
+	"RCRW",		LTYPE3,	ARCRW,
+	"RDTSC",	LTYPE0,	ARDTSC,
+	"REP",		LTYPE0,	AREP,
+	"REPN",		LTYPE0,	AREPN,
+	"RET",		LTYPE0,	ARET,
+	"ROLB",		LTYPE3,	AROLB,
+	"ROLL",		LTYPE3,	AROLL,
+	"ROLW",		LTYPE3,	AROLW,
+	"RORB",		LTYPE3,	ARORB,
+	"RORL",		LTYPE3,	ARORL,
+	"RORW",		LTYPE3,	ARORW,
+	"SAHF",		LTYPE0,	ASAHF,
+	"SALB",		LTYPE3,	ASALB,
+	"SALL",		LTYPE3,	ASALL,
+	"SALW",		LTYPE3,	ASALW,
+	"SARB",		LTYPE3,	ASARB,
+	"SARL",		LTYPE3,	ASARL,
+	"SARW",		LTYPE3,	ASARW,
+	"SBBB",		LTYPE3,	ASBBB,
+	"SBBL",		LTYPE3,	ASBBL,
+	"SBBW",		LTYPE3,	ASBBW,
+	"SCASB",	LTYPE0,	ASCASB,
+	"SCASL",	LTYPE0,	ASCASL,
+	"SCASW",	LTYPE0,	ASCASW,
+	"SETCC",	LTYPE1,	ASETCC,	/* see JCC etc above for condition codes */
+	"SETCS",	LTYPE1,	ASETCS,
+	"SETEQ",	LTYPE1,	ASETEQ,
+	"SETGE",	LTYPE1,	ASETGE,
+	"SETGT",	LTYPE1,	ASETGT,
+	"SETHI",	LTYPE1,	ASETHI,
+	"SETLE",	LTYPE1,	ASETLE,
+	"SETLS",	LTYPE1,	ASETLS,
+	"SETLT",	LTYPE1,	ASETLT,
+	"SETMI",	LTYPE1,	ASETMI,
+	"SETNE",	LTYPE1,	ASETNE,
+	"SETOC",	LTYPE1,	ASETOC,
+	"SETOS",	LTYPE1,	ASETOS,
+	"SETPC",	LTYPE1,	ASETPC,
+	"SETPL",	LTYPE1,	ASETPL,
+	"SETPS",	LTYPE1,	ASETPS,
+	"CDQ",		LTYPE0,	ACDQ,
+	"CWD",		LTYPE0,	ACWD,
+	"SHLB",		LTYPE3,	ASHLB,
+	"SHLL",		LTYPES,	ASHLL,
+	"SHLW",		LTYPES,	ASHLW,
+	"SHRB",		LTYPE3,	ASHRB,
+	"SHRL",		LTYPES,	ASHRL,
+	"SHRW",		LTYPES,	ASHRW,
+	"STC",		LTYPE0,	ASTC,
+	"STD",		LTYPE0,	ASTD,
+	"STI",		LTYPE0,	ASTI,
+	"STOSB",	LTYPE0,	ASTOSB,
+	"STOSL",	LTYPE0,	ASTOSL,
+	"STOSW",	LTYPE0,	ASTOSW,
+	"SUBB",		LTYPE3,	ASUBB,
+	"SUBL",		LTYPE3,	ASUBL,
+	"SUBW",		LTYPE3,	ASUBW,
+	"SYSCALL",	LTYPE0,	ASYSCALL,
+	"TESTB",	LTYPE3,	ATESTB,
+	"TESTL",	LTYPE3,	ATESTL,
+	"TESTW",	LTYPE3,	ATESTW,
+	"TEXT",		LTYPET,	ATEXT,
+	"VERR",		LTYPE2,	AVERR,
+	"VERW",		LTYPE2,	AVERW,
+	"WAIT",		LTYPE0,	AWAIT,
+	"WORD",		LTYPE2,	AWORD,
+	"XADDB",	LTYPE3,	AXADDB,
+	"XADDL",	LTYPE3,	AXADDL,
+	"XADDW",	LTYPE3,	AXADDW,
+	"XCHGB",	LTYPE3,	AXCHGB,
+	"XCHGL",	LTYPE3,	AXCHGL,
+	"XCHGW",	LTYPE3,	AXCHGW,
+	"XLAT",		LTYPE2,	AXLAT,
+	"XORB",		LTYPE3,	AXORB,
+	"XORL",		LTYPE3,	AXORL,
+	"XORW",		LTYPE3,	AXORW,
+
+	"CMOVLCC",	LTYPE3,	ACMOVLCC,
+	"CMOVLCS",	LTYPE3,	ACMOVLCS,
+	"CMOVLEQ",	LTYPE3,	ACMOVLEQ,
+	"CMOVLGE",	LTYPE3,	ACMOVLGE,
+	"CMOVLGT",	LTYPE3,	ACMOVLGT,
+	"CMOVLHI",	LTYPE3,	ACMOVLHI,
+	"CMOVLLE",	LTYPE3,	ACMOVLLE,
+	"CMOVLLS",	LTYPE3,	ACMOVLLS,
+	"CMOVLLT",	LTYPE3,	ACMOVLLT,
+	"CMOVLMI",	LTYPE3,	ACMOVLMI,
+	"CMOVLNE",	LTYPE3,	ACMOVLNE,
+	"CMOVLOC",	LTYPE3,	ACMOVLOC,
+	"CMOVLOS",	LTYPE3,	ACMOVLOS,
+	"CMOVLPC",	LTYPE3,	ACMOVLPC,
+	"CMOVLPL",	LTYPE3,	ACMOVLPL,
+	"CMOVLPS",	LTYPE3,	ACMOVLPS,
+	"CMOVWCC",	LTYPE3,	ACMOVWCC,
+	"CMOVWCS",	LTYPE3,	ACMOVWCS,
+	"CMOVWEQ",	LTYPE3,	ACMOVWEQ,
+	"CMOVWGE",	LTYPE3,	ACMOVWGE,
+	"CMOVWGT",	LTYPE3,	ACMOVWGT,
+	"CMOVWHI",	LTYPE3,	ACMOVWHI,
+	"CMOVWLE",	LTYPE3,	ACMOVWLE,
+	"CMOVWLS",	LTYPE3,	ACMOVWLS,
+	"CMOVWLT",	LTYPE3,	ACMOVWLT,
+	"CMOVWMI",	LTYPE3,	ACMOVWMI,
+	"CMOVWNE",	LTYPE3,	ACMOVWNE,
+	"CMOVWOC",	LTYPE3,	ACMOVWOC,
+	"CMOVWOS",	LTYPE3,	ACMOVWOS,
+	"CMOVWPC",	LTYPE3,	ACMOVWPC,
+	"CMOVWPL",	LTYPE3,	ACMOVWPL,
+	"CMOVWPS",	LTYPE3,	ACMOVWPS,
+
+	"FMOVB",	LTYPE3, AFMOVB,
+	"FMOVBP",	LTYPE3, AFMOVBP,
+	"FMOVD",	LTYPE3, AFMOVD,
+	"FMOVDP",	LTYPE3, AFMOVDP,
+	"FMOVF",	LTYPE3, AFMOVF,
+	"FMOVFP",	LTYPE3, AFMOVFP,
+	"FMOVL",	LTYPE3, AFMOVL,
+	"FMOVLP",	LTYPE3, AFMOVLP,
+	"FMOVV",	LTYPE3, AFMOVV,
+	"FMOVVP",	LTYPE3, AFMOVVP,
+	"FMOVW",	LTYPE3, AFMOVW,
+	"FMOVWP",	LTYPE3, AFMOVWP,
+	"FMOVX",	LTYPE3, AFMOVX,
+	"FMOVXP",	LTYPE3, AFMOVXP,
+	"FCMOVCC",	LTYPE3, AFCMOVCC,
+	"FCMOVCS",	LTYPE3, AFCMOVCS,
+	"FCMOVEQ",	LTYPE3, AFCMOVEQ,
+	"FCMOVHI",	LTYPE3, AFCMOVHI,
+	"FCMOVLS",	LTYPE3, AFCMOVLS,
+	"FCMOVNE",	LTYPE3, AFCMOVNE,
+	"FCMOVNU",	LTYPE3, AFCMOVNU,
+	"FCMOVUN",	LTYPE3, AFCMOVUN,
+	"FCOMB",	LTYPE3, AFCOMB,
+	"FCOMBP",	LTYPE3, AFCOMBP,
+	"FCOMD",	LTYPE3, AFCOMD,
+	"FCOMDP",	LTYPE3, AFCOMDP,
+	"FCOMDPP",	LTYPE3, AFCOMDPP,
+	"FCOMF",	LTYPE3, AFCOMF,
+	"FCOMFP",	LTYPE3, AFCOMFP,
+	"FCOMI",	LTYPE3, AFCOMI,
+	"FCOMIP",	LTYPE3, AFCOMIP,
+	"FCOML",	LTYPE3, AFCOML,
+	"FCOMLP",	LTYPE3, AFCOMLP,
+	"FCOMW",	LTYPE3, AFCOMW,
+	"FCOMWP",	LTYPE3, AFCOMWP,
+	"FUCOM",	LTYPE3, AFUCOM,
+	"FUCOMI",	LTYPE3, AFUCOMI,
+	"FUCOMIP",	LTYPE3, AFUCOMIP,
+	"FUCOMP",	LTYPE3, AFUCOMP,
+	"FUCOMPP",	LTYPE3, AFUCOMPP,
+	"FADDW",	LTYPE3, AFADDW,
+	"FADDL",	LTYPE3, AFADDL,
+	"FADDF",	LTYPE3, AFADDF,
+	"FADDD",	LTYPE3, AFADDD,
+	"FADDDP",	LTYPE3, AFADDDP,
+	"FSUBDP",	LTYPE3, AFSUBDP,
+	"FSUBW",	LTYPE3, AFSUBW,
+	"FSUBL",	LTYPE3, AFSUBL,
+	"FSUBF",	LTYPE3, AFSUBF,
+	"FSUBD",	LTYPE3, AFSUBD,
+	"FSUBRDP",	LTYPE3, AFSUBRDP,
+	"FSUBRW",	LTYPE3, AFSUBRW,
+	"FSUBRL",	LTYPE3, AFSUBRL,
+	"FSUBRF",	LTYPE3, AFSUBRF,
+	"FSUBRD",	LTYPE3, AFSUBRD,
+	"FMULDP",	LTYPE3, AFMULDP,
+	"FMULW",	LTYPE3, AFMULW,
+	"FMULL",	LTYPE3, AFMULL,
+	"FMULF",	LTYPE3, AFMULF,
+	"FMULD",	LTYPE3, AFMULD,
+	"FDIVDP",	LTYPE3, AFDIVDP,
+	"FDIVW",	LTYPE3, AFDIVW,
+	"FDIVL",	LTYPE3, AFDIVL,
+	"FDIVF",	LTYPE3, AFDIVF,
+	"FDIVD",	LTYPE3, AFDIVD,
+	"FDIVRDP",	LTYPE3, AFDIVRDP,
+	"FDIVRW",	LTYPE3, AFDIVRW,
+	"FDIVRL",	LTYPE3, AFDIVRL,
+	"FDIVRF",	LTYPE3, AFDIVRF,
+	"FDIVRD",	LTYPE3, AFDIVRD,
+	"FXCHD",	LTYPE3, AFXCHD,
+	"FFREE",	LTYPE1, AFFREE,
+	"FLDCW",	LTYPE2, AFLDCW,
+	"FLDENV",	LTYPE1, AFLDENV,
+	"FRSTOR",	LTYPE2, AFRSTOR,
+	"FSAVE",	LTYPE1, AFSAVE,
+	"FSTCW",	LTYPE1, AFSTCW,
+	"FSTENV",	LTYPE1, AFSTENV,
+	"FSTSW",	LTYPE1, AFSTSW,
+	"F2XM1",	LTYPE0, AF2XM1,
+	"FABS",		LTYPE0, AFABS,
+	"FCHS",		LTYPE0, AFCHS,
+	"FCLEX",	LTYPE0, AFCLEX,
+	"FCOS",		LTYPE0, AFCOS,
+	"FDECSTP",	LTYPE0, AFDECSTP,
+	"FINCSTP",	LTYPE0, AFINCSTP,
+	"FINIT",	LTYPE0, AFINIT,
+	"FLD1",		LTYPE0, AFLD1,
+	"FLDL2E",	LTYPE0, AFLDL2E,
+	"FLDL2T",	LTYPE0, AFLDL2T,
+	"FLDLG2",	LTYPE0, AFLDLG2,
+	"FLDLN2",	LTYPE0, AFLDLN2,
+	"FLDPI",	LTYPE0, AFLDPI,
+	"FLDZ",		LTYPE0, AFLDZ,
+	"FNOP",		LTYPE0, AFNOP,
+	"FPATAN",	LTYPE0, AFPATAN,
+	"FPREM",	LTYPE0, AFPREM,
+	"FPREM1",	LTYPE0, AFPREM1,
+	"FPTAN",	LTYPE0, AFPTAN,
+	"FRNDINT",	LTYPE0, AFRNDINT,
+	"FSCALE",	LTYPE0, AFSCALE,
+	"FSIN",		LTYPE0, AFSIN,
+	"FSINCOS",	LTYPE0, AFSINCOS,
+	"FSQRT",	LTYPE0, AFSQRT,
+	"FTST",		LTYPE0, AFTST,
+	"FXAM",		LTYPE0, AFXAM,
+	"FXTRACT",	LTYPE0, AFXTRACT,
+	"FYL2X",	LTYPE0, AFYL2X,
+	"FYL2XP1",	LTYPE0, AFYL2XP1,
+	"LFENCE",	LTYPE0, ALFENCE,
+	"MFENCE",	LTYPE0, AMFENCE,
+	"SFENCE",	LTYPE0, ASFENCE,
+	"EMMS",		LTYPE0, AEMMS,
+	"PREFETCHT0",		LTYPE2,	APREFETCHT0,
+	"PREFETCHT1",		LTYPE2,	APREFETCHT1,
+	"PREFETCHT2",		LTYPE2,	APREFETCHT2,
+	"PREFETCHNTA",		LTYPE2,	APREFETCHNTA,
+	"UNDEF",	LTYPE0,	AUNDEF,
+
+	"ADDPD",	LTYPE3,	AADDPD,
+	"ADDPS",	LTYPE3,	AADDPS,
+	"ADDSD",	LTYPE3,	AADDSD,
+	"ADDSS",	LTYPE3,	AADDSS,
+	"AESENC",	LTYPE3,	AAESENC,
+	"ANDNPD",	LTYPE3,	AANDNPD,
+	"ANDNPS",	LTYPE3,	AANDNPS,
+	"ANDPD",	LTYPE3,	AANDPD,
+	"ANDPS",	LTYPE3,	AANDPS,
+	"CMPPD",	LTYPEXC,ACMPPD,
+	"CMPPS",	LTYPEXC,ACMPPS,
+	"CMPSD",	LTYPEXC,ACMPSD,
+	"CMPSS",	LTYPEXC,ACMPSS,
+	"COMISD",	LTYPE3,	ACOMISD,
+	"COMISS",	LTYPE3,	ACOMISS,
+	"CVTPL2PD",	LTYPE3,	ACVTPL2PD,
+	"CVTPL2PS",	LTYPE3,	ACVTPL2PS,
+	"CVTPD2PL",	LTYPE3,	ACVTPD2PL,
+	"CVTPD2PS",	LTYPE3,	ACVTPD2PS,
+	"CVTPS2PL",	LTYPE3,	ACVTPS2PL,
+	"CVTPS2PD",	LTYPE3,	ACVTPS2PD,
+	"CVTSD2SL",	LTYPE3,	ACVTSD2SL,
+	"CVTSD2SS",	LTYPE3,	ACVTSD2SS,
+	"CVTSL2SD",	LTYPE3,	ACVTSL2SD,
+	"CVTSL2SS",	LTYPE3,	ACVTSL2SS,
+	"CVTSS2SD",	LTYPE3,	ACVTSS2SD,
+	"CVTSS2SL",	LTYPE3,	ACVTSS2SL,
+	"CVTTPD2PL",	LTYPE3,	ACVTTPD2PL,
+	"CVTTPS2PL",	LTYPE3,	ACVTTPS2PL,
+	"CVTTSD2SL",	LTYPE3,	ACVTTSD2SL,
+	"CVTTSS2SL",	LTYPE3,	ACVTTSS2SL,
+	"DIVPD",	LTYPE3,	ADIVPD,
+	"DIVPS",	LTYPE3,	ADIVPS,
+	"DIVSD",	LTYPE3,	ADIVSD,
+	"DIVSS",	LTYPE3,	ADIVSS,
+	"MASKMOVOU",	LTYPE3,	AMASKMOVOU,
+	"MASKMOVDQU",	LTYPE3,	AMASKMOVOU,	/* syn */
+	"MAXPD",	LTYPE3,	AMAXPD,
+	"MAXPS",	LTYPE3,	AMAXPS,
+	"MAXSD",	LTYPE3,	AMAXSD,
+	"MAXSS",	LTYPE3,	AMAXSS,
+	"MINPD",	LTYPE3,	AMINPD,
+	"MINPS",	LTYPE3,	AMINPS,
+	"MINSD",	LTYPE3,	AMINSD,
+	"MINSS",	LTYPE3,	AMINSS,
+	"MOVAPD",	LTYPE3,	AMOVAPD,
+	"MOVAPS",	LTYPE3,	AMOVAPS,
+	"MOVO",		LTYPE3,	AMOVO,
+	"MOVOA",	LTYPE3,	AMOVO,	/* syn */
+	"MOVOU",	LTYPE3,	AMOVOU,
+	"MOVHLPS",	LTYPE3,	AMOVHLPS,
+	"MOVHPD",	LTYPE3,	AMOVHPD,
+	"MOVHPS",	LTYPE3,	AMOVHPS,
+	"MOVLHPS",	LTYPE3,	AMOVLHPS,
+	"MOVLPD",	LTYPE3,	AMOVLPD,
+	"MOVLPS",	LTYPE3,	AMOVLPS,
+	"MOVMSKPD",	LTYPE3,	AMOVMSKPD,
+	"MOVMSKPS",	LTYPE3,	AMOVMSKPS,
+	"MOVNTO",	LTYPE3,	AMOVNTO,
+	"MOVNTDQ",	LTYPE3,	AMOVNTO,	/* syn */
+	"MOVNTPD",	LTYPE3,	AMOVNTPD,
+	"MOVNTPS",	LTYPE3,	AMOVNTPS,
+	"MOVSD",	LTYPE3,	AMOVSD,
+	"MOVSS",	LTYPE3,	AMOVSS,
+	"MOVUPD",	LTYPE3,	AMOVUPD,
+	"MOVUPS",	LTYPE3,	AMOVUPS,
+	"MULPD",	LTYPE3,	AMULPD,
+	"MULPS",	LTYPE3,	AMULPS,
+	"MULSD",	LTYPE3,	AMULSD,
+	"MULSS",	LTYPE3,	AMULSS,
+	"ORPD",		LTYPE3,	AORPD,
+	"ORPS",		LTYPE3,	AORPS,
+	"PADDQ",	LTYPE3,	APADDQ,
+	"PAND",		LTYPE3,	APAND,
+	"PCMPEQB",	LTYPE3,	APCMPEQB,
+	"PMAXSW",	LTYPE3,	APMAXSW,
+	"PMAXUB",	LTYPE3,	APMAXUB,
+	"PMINSW",	LTYPE3,	APMINSW,
+	"PMINUB",	LTYPE3,	APMINUB,
+	"PMOVMSKB",	LTYPE3,	APMOVMSKB,
+	"PSADBW",	LTYPE3,	APSADBW,
+	"PSHUFB",	LTYPE3, APSHUFB,
+	"PSUBB",	LTYPE3,	APSUBB,
+	"PSUBL",	LTYPE3,	APSUBL,
+	"PSUBQ",	LTYPE3,	APSUBQ,
+	"PSUBSB",	LTYPE3,	APSUBSB,
+	"PSUBSW",	LTYPE3,	APSUBSW,
+	"PSUBUSB",	LTYPE3,	APSUBUSB,
+	"PSUBUSW",	LTYPE3,	APSUBUSW,
+	"PSUBW",	LTYPE3,	APSUBW,
+	"PUNPCKHQDQ",	LTYPE3,	APUNPCKHQDQ,
+	"PUNPCKLQDQ",	LTYPE3,	APUNPCKLQDQ,
+	"PXOR",		LTYPE3, APXOR,
+	"RCPPS",	LTYPE3,	ARCPPS,
+	"RCPSS",	LTYPE3,	ARCPSS,
+	"RSQRTPS",	LTYPE3,	ARSQRTPS,
+	"RSQRTSS",	LTYPE3,	ARSQRTSS,
+	"SQRTPD",	LTYPE3,	ASQRTPD,
+	"SQRTPS",	LTYPE3,	ASQRTPS,
+	"SQRTSD",	LTYPE3,	ASQRTSD,
+	"SQRTSS",	LTYPE3,	ASQRTSS,
+	"SUBPD",	LTYPE3,	ASUBPD,
+	"SUBPS",	LTYPE3,	ASUBPS,
+	"SUBSD",	LTYPE3,	ASUBSD,
+	"SUBSS",	LTYPE3,	ASUBSS,
+	"UCOMISD",	LTYPE3,	AUCOMISD,
+	"UCOMISS",	LTYPE3,	AUCOMISS,
+	"UNPCKHPD",	LTYPE3,	AUNPCKHPD,
+	"UNPCKHPS",	LTYPE3,	AUNPCKHPS,
+	"UNPCKLPD",	LTYPE3,	AUNPCKLPD,
+	"UNPCKLPS",	LTYPE3,	AUNPCKLPS,
+	"XORPD",	LTYPE3,	AXORPD,
+	"XORPS",	LTYPE3,	AXORPS,
+	"USEFIELD",	LTYPEN, AUSEFIELD,
+	"PCDATA",	LTYPEPC,	APCDATA,
+	"FUNCDATA",	LTYPEF,	AFUNCDATA,
+	0
+};
+
+void
+cinit(void)
+{
+	Sym *s;
+	int i;
+
+	nullgen.type = D_NONE;
+	nullgen.index = D_NONE;
+
+	nerrors = 0;
+	iostack = I;
+	iofree = I;
+	peekc = IGN;
+	nhunk = 0;
+	for(i=0; i<NHASH; i++)
+		hash[i] = S;
+	for(i=0; itab[i].name; i++) {
+		s = slookup(itab[i].name);
+		if(s->type != LNAME)
+			yyerror("double initialization %s", itab[i].name);
+		s->type = itab[i].type;
+		s->value = itab[i].value;
+	}
+}
+
+void
+checkscale(int scale)
+{
+
+	switch(scale) {
+	case 1:
+	case 2:
+	case 4:
+	case 8:
+		return;
+	}
+	yyerror("scale must be 1248: %d", scale);
+}
+
+void
+syminit(Sym *s)
+{
+
+	s->type = LNAME;
+	s->value = 0;
+}
+
+void
+cclean(void)
+{
+	Addr2 g2;
+
+	g2.from = nullgen;
+	g2.to = nullgen;
+	outcode(AEND, &g2);
+}
+
+static Prog *lastpc;
+
+void
+outcode(int a, Addr2 *g2)
+{
+	Prog *p;
+	Plist *pl;
+	
+	if(pass == 1)
+		goto out;
+
+	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++;
+}
+
+#include "../cc/lexbody"
+#include "../cc/macbody"
diff --git a/src/cmd/8a/y.tab.c b/src/cmd/8a/y.tab.c
new file mode 100644
index 0000000..85279c2
--- /dev/null
+++ b/src/cmd/8a/y.tab.c
@@ -0,0 +1,2779 @@
+/* A Bison parser, made by GNU Bison 2.3.  */
+
+/* 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 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, 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
+   under terms of your choice, so long as that work isn't itself a
+   parser generator using the skeleton or a modified version thereof
+   as a parser skeleton.  Alternatively, if you modify or redistribute
+   the parser skeleton itself, you may (at your option) remove this
+   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.  */
+
+/* C LALR(1) parser skeleton written by Richard Stallman, by
+   simplifying the original so-called "semantic" parser.  */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+   infringing on user name space.  This should be done even for local
+   variables, as they might otherwise be expanded by user macros.
+   There are some unavoidable exceptions within include files to
+   define necessary library symbols; they are noted "INFRINGES ON
+   USER NAME SPACE" below.  */
+
+/* Identify Bison output.  */
+#define YYBISON 1
+
+/* Bison version.  */
+#define YYBISON_VERSION "2.3"
+
+/* Skeleton name.  */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers.  */
+#define YYPURE 0
+
+/* Using locations.  */
+#define YYLSP_NEEDED 0
+
+
+
+/* Tokens.  */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+   /* Put the tokens into the symbol table, so that GDB and other debuggers
+      know about them.  */
+   enum yytokentype {
+     LTYPE0 = 258,
+     LTYPE1 = 259,
+     LTYPE2 = 260,
+     LTYPE3 = 261,
+     LTYPE4 = 262,
+     LTYPEC = 263,
+     LTYPED = 264,
+     LTYPEN = 265,
+     LTYPER = 266,
+     LTYPET = 267,
+     LTYPES = 268,
+     LTYPEM = 269,
+     LTYPEI = 270,
+     LTYPEG = 271,
+     LTYPEXC = 272,
+     LTYPEX = 273,
+     LTYPEPC = 274,
+     LTYPEF = 275,
+     LCONST = 276,
+     LFP = 277,
+     LPC = 278,
+     LSB = 279,
+     LBREG = 280,
+     LLREG = 281,
+     LSREG = 282,
+     LFREG = 283,
+     LXREG = 284,
+     LFCONST = 285,
+     LSCONST = 286,
+     LSP = 287,
+     LNAME = 288,
+     LLAB = 289,
+     LVAR = 290
+   };
+#endif
+/* Tokens.  */
+#define LTYPE0 258
+#define LTYPE1 259
+#define LTYPE2 260
+#define LTYPE3 261
+#define LTYPE4 262
+#define LTYPEC 263
+#define LTYPED 264
+#define LTYPEN 265
+#define LTYPER 266
+#define LTYPET 267
+#define LTYPES 268
+#define LTYPEM 269
+#define LTYPEI 270
+#define LTYPEG 271
+#define LTYPEXC 272
+#define LTYPEX 273
+#define LTYPEPC 274
+#define LTYPEF 275
+#define LCONST 276
+#define LFP 277
+#define LPC 278
+#define LSB 279
+#define LBREG 280
+#define LLREG 281
+#define LSREG 282
+#define LFREG 283
+#define LXREG 284
+#define LFCONST 285
+#define LSCONST 286
+#define LSP 287
+#define LNAME 288
+#define LLAB 289
+#define LVAR 290
+
+
+
+
+/* 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 "../../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 38 "a.y"
+{
+	Sym	*sym;
+	int32	lval;
+	struct {
+		int32 v1;
+		int32 v2;
+	} con2;
+	double	dval;
+	char	sval[8];
+	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 216 of yacc.c.  */
+#line 200 "y.tab.c"
+
+#ifdef short
+# undef short
+#endif
+
+#ifdef YYTYPE_UINT8
+typedef YYTYPE_UINT8 yytype_uint8;
+#else
+typedef unsigned char yytype_uint8;
+#endif
+
+#ifdef YYTYPE_INT8
+typedef YYTYPE_INT8 yytype_int8;
+#elif (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+typedef signed char yytype_int8;
+#else
+typedef short int yytype_int8;
+#endif
+
+#ifdef YYTYPE_UINT16
+typedef YYTYPE_UINT16 yytype_uint16;
+#else
+typedef unsigned short int yytype_uint16;
+#endif
+
+#ifdef YYTYPE_INT16
+typedef YYTYPE_INT16 yytype_int16;
+#else
+typedef short int yytype_int16;
+#endif
+
+#ifndef YYSIZE_T
+# ifdef __SIZE_TYPE__
+#  define YYSIZE_T __SIZE_TYPE__
+# elif defined size_t
+#  define YYSIZE_T size_t
+# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+#  include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+#  define YYSIZE_T size_t
+# else
+#  define YYSIZE_T unsigned int
+# endif
+#endif
+
+#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
+
+#ifndef YY_
+# if defined YYENABLE_NLS && YYENABLE_NLS
+#  if ENABLE_NLS
+#   include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+#   define YY_(msgid) dgettext ("bison-runtime", msgid)
+#  endif
+# endif
+# ifndef YY_
+#  define YY_(msgid) msgid
+# endif
+#endif
+
+/* Suppress unused-variable warnings by "using" E.  */
+#if ! defined lint || defined __GNUC__
+# define YYUSE(e) ((void) (e))
+#else
+# define YYUSE(e) /* empty */
+#endif
+
+/* Identity function, used to suppress warnings about constant conditions.  */
+#ifndef lint
+# define YYID(n) (n)
+#else
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static int
+YYID (int i)
+#else
+static int
+YYID (i)
+    int i;
+#endif
+{
+  return i;
+}
+#endif
+
+#if ! defined yyoverflow || YYERROR_VERBOSE
+
+/* The parser invokes alloca or malloc; define the necessary symbols.  */
+
+# ifdef YYSTACK_USE_ALLOCA
+#  if YYSTACK_USE_ALLOCA
+#   ifdef __GNUC__
+#    define YYSTACK_ALLOC __builtin_alloca
+#   elif defined __BUILTIN_VA_ARG_INCR
+#    include <alloca.h> /* INFRINGES ON USER NAME SPACE */
+#   elif defined _AIX
+#    define YYSTACK_ALLOC __alloca
+#   elif defined _MSC_VER
+#    include <malloc.h> /* INFRINGES ON USER NAME SPACE */
+#    define alloca _alloca
+#   else
+#    define YYSTACK_ALLOC alloca
+#    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 _STDLIB_H
+#      define _STDLIB_H 1
+#     endif
+#    endif
+#   endif
+#  endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+   /* Pacify GCC's `empty if-body' warning.  */
+#  define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
+#  ifndef YYSTACK_ALLOC_MAXIMUM
+    /* The OS might guarantee only one guard page at the bottom of the stack,
+       and a page size can be as small as 4096 bytes.  So we cannot safely
+       invoke alloca (N) if N exceeds 4096.  Use a slightly smaller number
+       to allow for a few compiler-allocated temporary stack slots.  */
+#   define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
+#  endif
+# else
+#  define YYSTACK_ALLOC YYMALLOC
+#  define YYSTACK_FREE YYFREE
+#  ifndef YYSTACK_ALLOC_MAXIMUM
+#   define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
+#  endif
+#  if (defined __cplusplus && ! defined _STDLIB_H \
+       && ! ((defined YYMALLOC || defined malloc) \
+	     && (defined YYFREE || defined free)))
+#   include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+#   ifndef _STDLIB_H
+#    define _STDLIB_H 1
+#   endif
+#  endif
+#  ifndef YYMALLOC
+#   define YYMALLOC malloc
+#   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 _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+#   endif
+#  endif
+# endif
+#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
+
+
+#if (! defined yyoverflow \
+     && (! defined __cplusplus \
+	 || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member.  */
+union yyalloc
+{
+  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)
+
+/* The size of an array large to enough to hold all stacks, each with
+   N elements.  */
+# define YYSTACK_BYTES(N) \
+     ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
+      + YYSTACK_GAP_MAXIMUM)
+
+/* Copy COUNT objects from FROM to TO.  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)))
+#  else
+#   define YYCOPY(To, From, Count)		\
+      do					\
+	{					\
+	  YYSIZE_T yyi;				\
+	  for (yyi = 0; yyi < (Count); yyi++)	\
+	    (To)[yyi] = (From)[yyi];		\
+	}					\
+      while (YYID (0))
+#  endif
+# endif
+
+/* 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
+/* YYLAST -- Last index in YYTABLE.  */
+#define YYLAST   546
+
+/* YYNTOKENS -- Number of terminals.  */
+#define YYNTOKENS  54
+/* YYNNTS -- Number of nonterminals.  */
+#define YYNNTS  41
+/* YYNRULES -- Number of rules.  */
+#define YYNRULES  135
+/* YYNRULES -- Number of states.  */
+#define YYNSTATES  276
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX.  */
+#define YYUNDEFTOK  2
+#define YYMAXUTOK   290
+
+#define YYTRANSLATE(YYX)						\
+  ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX.  */
+static const yytype_uint8 yytranslate[] =
+{
+       0,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,    52,    12,     5,     2,
+      50,    51,    10,     8,    49,     9,     2,    11,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,    46,    47,
+       6,    48,     7,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     4,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     3,     2,    53,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     1,     2,    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
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+   YYRHS.  */
+static const yytype_uint16 yyprhs[] =
+{
+       0,     0,     3,     4,     5,     9,    10,    15,    16,    21,
+      23,    26,    29,    33,    37,    40,    43,    46,    49,    52,
+      55,    58,    61,    64,    67,    70,    73,    76,    79,    82,
+      85,    88,    91,    92,    94,    98,   102,   105,   107,   110,
+     112,   115,   117,   121,   127,   131,   137,   140,   142,   145,
+     147,   149,   153,   159,   163,   169,   172,   174,   178,   182,
+     188,   194,   200,   204,   208,   210,   212,   214,   216,   219,
+     222,   224,   226,   228,   230,   232,   237,   240,   243,   245,
+     247,   249,   251,   253,   255,   258,   261,   264,   267,   272,
+     278,   282,   285,   287,   290,   294,   299,   301,   303,   305,
+     310,   315,   322,   332,   342,   346,   350,   355,   361,   370,
+     372,   379,   385,   393,   394,   397,   400,   402,   404,   406,
+     408,   410,   413,   416,   419,   423,   425,   429,   433,   437,
+     441,   445,   450,   455,   459,   463
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS.  */
+static const yytype_int8 yyrhs[] =
+{
+      55,     0,    -1,    -1,    -1,    55,    56,    57,    -1,    -1,
+      44,    46,    58,    57,    -1,    -1,    43,    46,    59,    57,
+      -1,    47,    -1,    60,    47,    -1,     1,    47,    -1,    43,
+      48,    94,    -1,    45,    48,    94,    -1,    13,    61,    -1,
+      14,    65,    -1,    15,    64,    -1,    16,    62,    -1,    17,
+      63,    -1,    21,    66,    -1,    19,    67,    -1,    22,    68,
+      -1,    18,    69,    -1,    20,    70,    -1,    23,    71,    -1,
+      24,    72,    -1,    25,    73,    -1,    26,    74,    -1,    27,
+      75,    -1,    28,    76,    -1,    29,    77,    -1,    30,    78,
+      -1,    -1,    49,    -1,    81,    49,    79,    -1,    79,    49,
+      81,    -1,    81,    49,    -1,    81,    -1,    49,    79,    -1,
+      79,    -1,    49,    82,    -1,    82,    -1,    84,    49,    82,
+      -1,    90,    11,    93,    49,    84,    -1,    87,    49,    85,
+      -1,    87,    49,    93,    49,    85,    -1,    49,    80,    -1,
+      80,    -1,    10,    90,    -1,    61,    -1,    65,    -1,    81,
+      49,    79,    -1,    81,    49,    79,    46,    36,    -1,    81,
+      49,    79,    -1,    81,    49,    79,    46,    37,    -1,    81,
+      49,    -1,    81,    -1,    81,    49,    79,    -1,    87,    49,
+      84,    -1,    87,    49,    93,    49,    84,    -1,    83,    49,
+      79,    49,    93,    -1,    84,    49,    79,    49,    83,    -1,
+      81,    49,    81,    -1,    81,    49,    81,    -1,    83,    -1,
+      87,    -1,    82,    -1,    89,    -1,    10,    83,    -1,    10,
+      88,    -1,    83,    -1,    88,    -1,    84,    -1,    79,    -1,
+      84,    -1,    93,    50,    33,    51,    -1,    43,    91,    -1,
+      44,    91,    -1,    35,    -1,    38,    -1,    36,    -1,    39,
+      -1,    42,    -1,    37,    -1,    52,    93,    -1,    52,    90,
+      -1,    52,    41,    -1,    52,    40,    -1,    52,    50,    40,
+      51,    -1,    52,    50,     9,    40,    51,    -1,    52,     9,
+      40,    -1,    52,    86,    -1,    31,    -1,     9,    31,    -1,
+      31,     9,    31,    -1,     9,    31,     9,    31,    -1,    88,
+      -1,    89,    -1,    93,    -1,    93,    50,    36,    51,    -1,
+      93,    50,    42,    51,    -1,    93,    50,    36,    10,    93,
+      51,    -1,    93,    50,    36,    51,    50,    36,    10,    93,
+      51,    -1,    93,    50,    36,    51,    50,    37,    10,    93,
+      51,    -1,    50,    36,    51,    -1,    50,    42,    51,    -1,
+      93,    50,    37,    51,    -1,    50,    36,    10,    93,    51,
+      -1,    50,    36,    51,    50,    36,    10,    93,    51,    -1,
+      90,    -1,    90,    50,    36,    10,    93,    51,    -1,    43,
+      91,    50,    92,    51,    -1,    43,     6,     7,    91,    50,
+      34,    51,    -1,    -1,     8,    93,    -1,     9,    93,    -1,
+      34,    -1,    42,    -1,    32,    -1,    31,    -1,    45,    -1,
+       9,    93,    -1,     8,    93,    -1,    53,    93,    -1,    50,
+      94,    51,    -1,    93,    -1,    94,     8,    94,    -1,    94,
+       9,    94,    -1,    94,    10,    94,    -1,    94,    11,    94,
+      -1,    94,    12,    94,    -1,    94,     6,     6,    94,    -1,
+      94,     7,     7,    94,    -1,    94,     5,    94,    -1,    94,
+       4,    94,    -1,    94,     3,    94,    -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
+static const yytype_uint16 yyrline[] =
+{
+       0,    69,    69,    71,    70,    78,    77,    85,    84,    90,
+      91,    92,    95,   100,   106,   107,   108,   109,   110,   111,
+     112,   113,   114,   115,   116,   117,   118,   119,   120,   121,
+     122,   123,   126,   130,   137,   144,   151,   156,   163,   168,
+     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,   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
+
+#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+   First, the terminals, then, starting at YYNTOKENS, nonterminals.  */
+static const char *const yytname[] =
+{
+  "$end", "error", "$undefined", "'|'", "'^'", "'&'", "'<'", "'>'", "'+'",
+  "'-'", "'*'", "'/'", "'%'", "LTYPE0", "LTYPE1", "LTYPE2", "LTYPE3",
+  "LTYPE4", "LTYPEC", "LTYPED", "LTYPEN", "LTYPER", "LTYPET", "LTYPES",
+  "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
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+   token YYLEX-NUM.  */
+static const yytype_uint16 yytoknum[] =
+{
+       0,   256,   257,   124,    94,    38,    60,    62,    43,    45,
+      42,    47,    37,   258,   259,   260,   261,   262,   263,   264,
+     265,   266,   267,   268,   269,   270,   271,   272,   273,   274,
+     275,   276,   277,   278,   279,   280,   281,   282,   283,   284,
+     285,   286,   287,   288,   289,   290,    58,    59,    61,    44,
+      40,    41,    36,   126
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
+static const yytype_uint8 yyr1[] =
+{
+       0,    54,    55,    56,    55,    58,    57,    59,    57,    57,
+      57,    57,    60,    60,    60,    60,    60,    60,    60,    60,
+      60,    60,    60,    60,    60,    60,    60,    60,    60,    60,
+      60,    60,    61,    61,    62,    63,    64,    64,    65,    65,
+      66,    66,    66,    67,    68,    68,    69,    69,    69,    70,
+      70,    71,    71,    72,    72,    73,    73,    73,    74,    74,
+      75,    76,    77,    78,    79,    79,    80,    80,    80,    80,
+      80,    80,    80,    81,    81,    82,    82,    82,    83,    83,
+      83,    83,    83,    83,    84,    84,    84,    84,    84,    84,
+      84,    85,    86,    86,    86,    86,    87,    87,    88,    88,
+      88,    88,    88,    88,    88,    88,    88,    88,    88,    89,
+      89,    90,    90,    91,    91,    91,    92,    92,    92,    93,
+      93,    93,    93,    93,    93,    94,    94,    94,    94,    94,
+      94,    94,    94,    94,    94,    94
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN.  */
+static const yytype_uint8 yyr2[] =
+{
+       0,     2,     0,     0,     3,     0,     4,     0,     4,     1,
+       2,     2,     3,     3,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     0,     1,     3,     3,     2,     1,     2,     1,
+       2,     1,     3,     5,     3,     5,     2,     1,     2,     1,
+       1,     3,     5,     3,     5,     2,     1,     3,     3,     5,
+       5,     5,     3,     3,     1,     1,     1,     1,     2,     2,
+       1,     1,     1,     1,     1,     4,     2,     2,     1,     1,
+       1,     1,     1,     1,     2,     2,     2,     2,     4,     5,
+       3,     2,     1,     2,     3,     4,     1,     1,     1,     4,
+       4,     6,     9,     9,     3,     3,     4,     5,     8,     1,
+       6,     5,     7,     0,     2,     2,     1,     1,     1,     1,
+       1,     2,     2,     2,     3,     1,     3,     3,     3,     3,
+       3,     4,     4,     3,     3,     3
+};
+
+/* 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[] =
+{
+       2,     3,     1,     0,     0,    32,     0,     0,     0,     0,
+       0,     0,    32,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     9,     4,     0,    11,
+      33,    14,     0,     0,   119,    78,    80,    83,    79,    81,
+      82,   113,   120,     0,     0,     0,    15,    39,    64,    65,
+      96,    97,   109,    98,     0,    16,    73,    37,    74,    17,
+       0,    18,     0,     0,   113,   113,     0,    22,    47,    66,
+      70,    72,    71,    67,    98,    20,     0,    33,    49,    50,
+      23,   113,     0,     0,    19,    41,     0,     0,    21,     0,
+      24,     0,    25,     0,    26,    56,    27,     0,    28,     0,
+      29,     0,    30,     0,    31,     0,     7,     0,     5,     0,
+      10,   122,   121,     0,     0,     0,     0,    38,     0,     0,
+     125,     0,   123,     0,     0,     0,    87,    86,     0,    85,
+      84,    36,     0,     0,    68,    69,    48,    76,    77,     0,
+      46,     0,     0,    76,    40,     0,     0,     0,     0,     0,
+      55,     0,     0,     0,     0,     0,     0,    12,     0,    13,
+     113,   114,   115,     0,     0,   104,   105,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,   124,     0,     0,
+       0,     0,    90,     0,     0,    34,    35,     0,     0,    42,
+       0,    44,     0,    51,    53,    57,    58,     0,     0,     0,
+      62,    63,     8,     6,     0,   118,   116,   117,     0,     0,
+       0,   135,   134,   133,     0,     0,   126,   127,   128,   129,
+     130,     0,     0,    99,   106,   100,     0,    88,    75,     0,
+       0,    92,    91,     0,     0,     0,     0,     0,     0,     0,
+     111,   107,     0,   131,   132,     0,     0,     0,    89,    43,
+      93,     0,    45,    52,    54,    59,    60,    61,     0,     0,
+     110,   101,     0,     0,     0,    94,   112,     0,     0,     0,
+      95,   108,     0,     0,   102,   103
+};
+
+/* YYDEFGOTO[NTERM-NUM].  */
+static const yytype_int16 yydefgoto[] =
+{
+      -1,     1,     3,    27,   158,   156,    28,    31,    59,    61,
+      55,    46,    84,    75,    88,    67,    80,    90,    92,    94,
+      96,    98,   100,   102,   104,    56,    68,    57,    69,    48,
+      58,   191,   232,    49,    50,    51,    52,   116,   208,    53,
+     121
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+   STATE-NUM.  */
+#define YYPACT_NINF -104
+static const yytype_int16 yypact[] =
+{
+    -104,     4,  -104,   173,   -26,   -25,   277,   297,   297,   349,
+     225,   -14,   329,   396,    18,   297,   297,   297,    18,   171,
+     -20,   297,   297,     2,    -4,    26,  -104,  -104,    43,  -104,
+    -104,  -104,   478,   478,  -104,  -104,  -104,  -104,  -104,  -104,
+    -104,   111,  -104,   349,   402,   478,  -104,  -104,  -104,  -104,
+    -104,  -104,   -12,    -5,    83,  -104,  -104,    44,  -104,  -104,
+      46,  -104,    49,   349,   111,   113,   245,  -104,  -104,  -104,
+    -104,  -104,  -104,  -104,    50,  -104,   100,   349,  -104,  -104,
+    -104,   113,   420,   478,  -104,  -104,    64,    66,  -104,    78,
+    -104,    80,  -104,    85,  -104,    89,  -104,    93,  -104,    98,
+    -104,   101,  -104,   112,  -104,   121,  -104,   478,  -104,   478,
+    -104,  -104,  -104,   153,   478,   478,   135,  -104,     8,   163,
+    -104,    74,  -104,   179,    52,   427,  -104,  -104,   445,  -104,
+    -104,  -104,   349,   297,  -104,  -104,  -104,   135,  -104,   381,
+    -104,    33,   478,  -104,  -104,   420,   186,   451,   349,   349,
+     349,   460,   349,   349,   297,   297,   173,   172,   173,   172,
+     113,  -104,  -104,     5,   478,   180,  -104,   478,   478,   478,
+     226,   224,   478,   478,   478,   478,   478,  -104,   235,    36,
+     195,   196,  -104,   466,   197,  -104,  -104,   199,   202,  -104,
+      21,  -104,   203,   211,   219,  -104,  -104,   217,   222,   223,
+    -104,  -104,  -104,  -104,   229,  -104,  -104,  -104,   240,   241,
+     237,   232,   527,   534,   478,   478,   134,   134,  -104,  -104,
+    -104,   478,   478,   243,  -104,  -104,   248,  -104,  -104,   -20,
+     263,   287,  -104,   249,   264,   265,   -20,   478,   171,   269,
+    -104,  -104,   294,   214,   214,   256,   258,   119,  -104,  -104,
+     301,   280,  -104,  -104,  -104,  -104,  -104,  -104,   266,   478,
+    -104,  -104,   308,   311,   292,  -104,  -104,   273,   478,   478,
+    -104,  -104,   274,   278,  -104,  -104
+};
+
+/* YYPGOTO[NTERM-NUM].  */
+static const yytype_int16 yypgoto[] =
+{
+    -104,  -104,  -104,  -103,  -104,  -104,  -104,   319,  -104,  -104,
+    -104,   331,  -104,  -104,  -104,  -104,  -104,  -104,  -104,  -104,
+    -104,  -104,  -104,  -104,  -104,    19,   275,    -2,    -6,    -9,
+      -8,   115,  -104,    22,     1,    -1,    -3,   -48,  -104,   -10,
+     -66
+};
+
+/* 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 zero, do what YYDEFACT says.
+   If YYTABLE_NINF, syntax error.  */
+#define YYTABLE_NINF -1
+static const yytype_uint16 yytable[] =
+{
+      74,    70,    71,    87,     2,    86,    60,    85,    76,    73,
+      99,    72,   101,    91,    93,    95,   137,   138,   164,   103,
+     105,    29,   111,   112,    30,    47,    32,    33,    62,    41,
+     230,    47,    54,   143,   120,   122,    89,   205,   123,   206,
+      97,   157,   108,   159,   130,   124,   222,   207,   106,    34,
+     107,   129,   231,   202,   134,   203,    74,    70,    71,   165,
+     136,    41,   117,    42,   135,    73,   187,    72,    44,   179,
+     180,    45,    87,   120,   109,   181,   144,   167,   168,   169,
+     170,   171,   172,   173,   174,   175,   176,   223,   179,   180,
+     110,    32,   125,   131,   181,   132,   117,   120,   133,   120,
+     141,   211,   212,   213,   161,   162,   216,   217,   218,   219,
+     220,   142,   204,   145,    34,   112,   146,   113,   120,   114,
+     115,   114,   115,   126,   127,   177,    41,   147,    42,   148,
+     134,   186,   188,   128,   149,    87,    45,   192,   150,   189,
+     135,   197,   151,   196,   174,   175,   176,   152,   243,   244,
+     153,   185,   200,   201,   209,   262,   263,   120,   120,   120,
+     160,   154,   120,   120,   120,   120,   120,   193,   194,   195,
+     155,   198,   199,   112,     4,   167,   168,   169,   170,   171,
+     172,   173,   174,   175,   176,   163,     5,     6,     7,     8,
+       9,    10,    11,    12,    13,    14,    15,    16,    17,    18,
+      19,    20,    21,    22,   120,   120,    35,    36,    37,    38,
+      39,   245,   246,    40,   166,   178,    23,    24,    25,   187,
+      26,   249,   172,   173,   174,   175,   176,   256,   255,   257,
+     210,   215,   214,    32,    33,    63,   168,   169,   170,   171,
+     172,   173,   174,   175,   176,   221,   224,   225,   227,   267,
+     228,   229,   233,    32,    33,   139,    34,   234,   272,   273,
+      35,    36,    37,    38,    39,   235,   236,    40,    64,    65,
+      42,   237,   238,   242,    66,    44,    34,    54,    45,   239,
+      35,    36,    37,    38,    39,    32,    33,    40,    64,    65,
+      42,   240,   241,   247,   250,    44,   251,    54,    45,   248,
+     253,   190,   254,   258,   259,    32,    33,   260,    34,   261,
+     264,   265,    35,    36,    37,    38,    39,   266,   268,    40,
+      41,   269,    42,   270,   271,   274,    43,    44,    34,   275,
+      45,    78,    35,    36,    37,    38,    39,    32,    33,    40,
+      41,   140,    42,    79,     0,     0,     0,    44,   252,    54,
+      45,     0,     0,     0,     0,     0,     0,    32,    33,     0,
+      34,     0,     0,     0,    35,    36,    37,    38,    39,     0,
+       0,    40,    41,     0,    42,     0,     0,     0,    77,    44,
+      34,     0,    45,     0,    35,    36,    37,    38,    39,    32,
+      33,    40,    41,     0,    42,     0,     0,     0,     0,    44,
+       0,     0,    45,     0,    32,    33,     0,     0,     0,     0,
+      32,    33,    34,     0,     0,     0,    35,    36,    37,    38,
+      39,     0,     0,    40,     0,     0,    42,    34,    32,    33,
+       0,    44,     0,    34,    45,    32,    33,     0,   118,    81,
+      65,    42,     0,     0,   119,    82,    83,    42,    54,    45,
+       0,    34,    83,    32,   183,    45,     0,     0,    34,    32,
+      33,     0,     0,    81,    65,    42,     0,   182,    32,    33,
+      83,     0,    42,    45,    32,    33,    34,    83,     0,     0,
+      45,     0,    34,     0,     0,   184,    32,    33,     0,     0,
+      42,    34,     0,     0,     0,    83,    42,    34,    45,     0,
+       0,    83,     0,   190,    45,    42,   226,     0,     0,    34,
+      83,    42,    54,    45,     0,     0,    83,     0,     0,    45,
+       0,     0,     0,    42,     0,     0,     0,     0,    83,     0,
+       0,    45,   169,   170,   171,   172,   173,   174,   175,   176,
+     170,   171,   172,   173,   174,   175,   176
+};
+
+static const yytype_int16 yycheck[] =
+{
+      10,    10,    10,    13,     0,    13,     8,    13,    11,    10,
+      19,    10,    20,    15,    16,    17,    64,    65,    10,    21,
+      22,    47,    32,    33,    49,     6,     8,     9,     9,    43,
+       9,    12,    52,    81,    44,    45,    14,    32,    50,    34,
+      18,   107,    46,   109,    54,    50,    10,    42,    46,    31,
+      48,    54,    31,   156,    63,   158,    66,    66,    66,    51,
+      63,    43,    43,    45,    63,    66,    33,    66,    50,    36,
+      37,    53,    82,    83,    48,    42,    82,     3,     4,     5,
+       6,     7,     8,     9,    10,    11,    12,    51,    36,    37,
+      47,     8,     9,    49,    42,    49,    77,   107,    49,   109,
+      50,   167,   168,   169,   114,   115,   172,   173,   174,   175,
+     176,    11,   160,    49,    31,   125,    50,     6,   128,     8,
+       9,     8,     9,    40,    41,    51,    43,    49,    45,    49,
+     139,   133,   142,    50,    49,   145,    53,   147,    49,   145,
+     139,   151,    49,   151,    10,    11,    12,    49,   214,   215,
+      49,   132,   154,   155,   164,    36,    37,   167,   168,   169,
+       7,    49,   172,   173,   174,   175,   176,   148,   149,   150,
+      49,   152,   153,   183,     1,     3,     4,     5,     6,     7,
+       8,     9,    10,    11,    12,    50,    13,    14,    15,    16,
+      17,    18,    19,    20,    21,    22,    23,    24,    25,    26,
+      27,    28,    29,    30,   214,   215,    35,    36,    37,    38,
+      39,   221,   222,    42,    51,    36,    43,    44,    45,    33,
+      47,   229,     8,     9,    10,    11,    12,   237,   236,   238,
+      50,     7,     6,     8,     9,    10,     4,     5,     6,     7,
+       8,     9,    10,    11,    12,    10,    51,    51,    51,   259,
+      51,    49,    49,     8,     9,    10,    31,    46,   268,   269,
+      35,    36,    37,    38,    39,    46,    49,    42,    43,    44,
+      45,    49,    49,    36,    49,    50,    31,    52,    53,    50,
+      35,    36,    37,    38,    39,     8,     9,    42,    43,    44,
+      45,    51,    51,    50,    31,    50,     9,    52,    53,    51,
+      36,    52,    37,    34,    10,     8,     9,    51,    31,    51,
+       9,    31,    35,    36,    37,    38,    39,    51,    10,    42,
+      43,    10,    45,    31,    51,    51,    49,    50,    31,    51,
+      53,    12,    35,    36,    37,    38,    39,     8,     9,    42,
+      43,    66,    45,    12,    -1,    -1,    -1,    50,   233,    52,
+      53,    -1,    -1,    -1,    -1,    -1,    -1,     8,     9,    -1,
+      31,    -1,    -1,    -1,    35,    36,    37,    38,    39,    -1,
+      -1,    42,    43,    -1,    45,    -1,    -1,    -1,    49,    50,
+      31,    -1,    53,    -1,    35,    36,    37,    38,    39,     8,
+       9,    42,    43,    -1,    45,    -1,    -1,    -1,    -1,    50,
+      -1,    -1,    53,    -1,     8,     9,    -1,    -1,    -1,    -1,
+       8,     9,    31,    -1,    -1,    -1,    35,    36,    37,    38,
+      39,    -1,    -1,    42,    -1,    -1,    45,    31,     8,     9,
+      -1,    50,    -1,    31,    53,     8,     9,    -1,    36,    43,
+      44,    45,    -1,    -1,    42,    49,    50,    45,    52,    53,
+      -1,    31,    50,     8,     9,    53,    -1,    -1,    31,     8,
+       9,    -1,    -1,    43,    44,    45,    -1,    40,     8,     9,
+      50,    -1,    45,    53,     8,     9,    31,    50,    -1,    -1,
+      53,    -1,    31,    -1,    -1,    40,     8,     9,    -1,    -1,
+      45,    31,    -1,    -1,    -1,    50,    45,    31,    53,    -1,
+      -1,    50,    -1,    52,    53,    45,    40,    -1,    -1,    31,
+      50,    45,    52,    53,    -1,    -1,    50,    -1,    -1,    53,
+      -1,    -1,    -1,    45,    -1,    -1,    -1,    -1,    50,    -1,
+      -1,    53,     5,     6,     7,     8,     9,    10,    11,    12,
+       6,     7,     8,     9,    10,    11,    12
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+   symbol of state STATE-NUM.  */
+static const yytype_uint8 yystos[] =
+{
+       0,    55,     0,    56,     1,    13,    14,    15,    16,    17,
+      18,    19,    20,    21,    22,    23,    24,    25,    26,    27,
+      28,    29,    30,    43,    44,    45,    47,    57,    60,    47,
+      49,    61,     8,     9,    31,    35,    36,    37,    38,    39,
+      42,    43,    45,    49,    50,    53,    65,    79,    83,    87,
+      88,    89,    90,    93,    52,    64,    79,    81,    84,    62,
+      81,    63,    79,    10,    43,    44,    49,    69,    80,    82,
+      83,    84,    88,    89,    93,    67,    90,    49,    61,    65,
+      70,    43,    49,    50,    66,    82,    84,    93,    68,    87,
+      71,    81,    72,    81,    73,    81,    74,    87,    75,    83,
+      76,    84,    77,    81,    78,    81,    46,    48,    46,    48,
+      47,    93,    93,     6,     8,     9,    91,    79,    36,    42,
+      93,    94,    93,    50,    50,     9,    40,    41,    50,    90,
+      93,    49,    49,    49,    83,    88,    90,    91,    91,    10,
+      80,    50,    11,    91,    82,    49,    50,    49,    49,    49,
+      49,    49,    49,    49,    49,    49,    59,    94,    58,    94,
+       7,    93,    93,    50,    10,    51,    51,     3,     4,     5,
+       6,     7,     8,     9,    10,    11,    12,    51,    36,    36,
+      37,    42,    40,     9,    40,    79,    81,    33,    93,    82,
+      52,    85,    93,    79,    79,    79,    84,    93,    79,    79,
+      81,    81,    57,    57,    91,    32,    34,    42,    92,    93,
+      50,    94,    94,    94,     6,     7,    94,    94,    94,    94,
+      94,    10,    10,    51,    51,    51,    40,    51,    51,    49,
+       9,    31,    86,    49,    46,    46,    49,    49,    49,    50,
+      51,    51,    36,    94,    94,    93,    93,    50,    51,    84,
+      31,     9,    85,    36,    37,    84,    93,    83,    34,    10,
+      51,    51,    36,    37,     9,    31,    51,    93,    10,    10,
+      31,    51,    93,    93,    51,    51
+};
+
+#define yyerrok		(yyerrstatus = 0)
+#define yyclearin	(yychar = YYEMPTY)
+#define YYEMPTY		(-2)
+#define YYEOF		0
+
+#define YYACCEPT	goto yyacceptlab
+#define YYABORT		goto yyabortlab
+#define YYERROR		goto yyerrorlab
+
+
+/* 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.  */
+
+#define YYFAIL		goto yyerrlab
+
+#define YYRECOVERING()  (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value)					\
+do								\
+  if (yychar == YYEMPTY && yylen == 1)				\
+    {								\
+      yychar = (Token);						\
+      yylval = (Value);						\
+      yytoken = YYTRANSLATE (yychar);				\
+      YYPOPSTACK (1);						\
+      goto yybackup;						\
+    }								\
+  else								\
+    {								\
+      yyerror (YY_("syntax error: cannot back up")); \
+      YYERROR;							\
+    }								\
+while (YYID (0))
+
+
+#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
+
+
+/* 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
+# 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
+
+
+/* YYLEX -- calling `yylex' with the right arguments.  */
+
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (YYLEX_PARAM)
+#else
+# define YYLEX yylex ()
+#endif
+
+/* Enable debugging if requested.  */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+#  include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+#  define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args)			\
+do {						\
+  if (yydebug)					\
+    YYFPRINTF Args;				\
+} while (YYID (0))
+
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)			  \
+do {									  \
+  if (yydebug)								  \
+    {									  \
+      YYFPRINTF (stderr, "%s ", Title);					  \
+      yy_symbol_print (stderr,						  \
+		  Type, Value); \
+      YYFPRINTF (stderr, "\n");						  \
+    }									  \
+} while (YYID (0))
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT.  |
+`--------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_value_print (yyoutput, yytype, yyvaluep)
+    FILE *yyoutput;
+    int yytype;
+    YYSTYPE const * const yyvaluep;
+#endif
+{
+  if (!yyvaluep)
+    return;
+# ifdef YYPRINT
+  if (yytype < YYNTOKENS)
+    YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# else
+  YYUSE (yyoutput);
+# endif
+  switch (yytype)
+    {
+      default:
+	break;
+    }
+}
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT.  |
+`--------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_print (yyoutput, yytype, yyvaluep)
+    FILE *yyoutput;
+    int yytype;
+    YYSTYPE const * const yyvaluep;
+#endif
+{
+  if (yytype < YYNTOKENS)
+    YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+  else
+    YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+  yy_symbol_value_print (yyoutput, yytype, yyvaluep);
+  YYFPRINTF (yyoutput, ")");
+}
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included).                                                   |
+`------------------------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_stack_print (yytype_int16 *bottom, yytype_int16 *top)
+#else
+static void
+yy_stack_print (bottom, top)
+    yytype_int16 *bottom;
+    yytype_int16 *top;
+#endif
+{
+  YYFPRINTF (stderr, "Stack now");
+  for (; bottom <= top; ++bottom)
+    YYFPRINTF (stderr, " %d", *bottom);
+  YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top)				\
+do {								\
+  if (yydebug)							\
+    yy_stack_print ((Bottom), (Top));				\
+} while (YYID (0))
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced.  |
+`------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_reduce_print (YYSTYPE *yyvsp, int yyrule)
+#else
+static void
+yy_reduce_print (yyvsp, yyrule)
+    YYSTYPE *yyvsp;
+    int yyrule;
+#endif
+{
+  int yynrhs = yyr2[yyrule];
+  int yyi;
+  unsigned long int yylno = yyrline[yyrule];
+  YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
+	     yyrule - 1, yylno);
+  /* The symbols being reduced.  */
+  for (yyi = 0; yyi < yynrhs; yyi++)
+    {
+      fprintf (stderr, "   $%d = ", yyi + 1);
+      yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
+		       &(yyvsp[(yyi + 1) - (yynrhs)])
+		       		       );
+      fprintf (stderr, "\n");
+    }
+}
+
+# define YY_REDUCE_PRINT(Rule)		\
+do {					\
+  if (yydebug)				\
+    yy_reduce_print (yyvsp, Rule); \
+} while (YYID (0))
+
+/* Nonzero means print parse trace.  It is left uninitialized so that
+   multiple parsers can coexist.  */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks.  */
+#ifndef	YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+   if the built-in stack extension method is used).
+
+   Do not make this value too large; the results are undefined if
+   YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+   evaluated with infinite-precision integer arithmetic.  */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+

+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+#  if defined __GLIBC__ && defined _STRING_H
+#   define yystrlen strlen
+#  else
+/* Return the length of YYSTR.  */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static YYSIZE_T
+yystrlen (const char *yystr)
+#else
+static YYSIZE_T
+yystrlen (yystr)
+    const char *yystr;
+#endif
+{
+  YYSIZE_T yylen;
+  for (yylen = 0; yystr[yylen]; yylen++)
+    continue;
+  return yylen;
+}
+#  endif
+# endif
+
+# ifndef yystpcpy
+#  if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
+#   define yystpcpy stpcpy
+#  else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+   YYDEST.  */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static char *
+yystpcpy (char *yydest, const char *yysrc)
+#else
+static char *
+yystpcpy (yydest, yysrc)
+    char *yydest;
+    const char *yysrc;
+#endif
+{
+  char *yyd = yydest;
+  const char *yys = yysrc;
+
+  while ((*yyd++ = *yys++) != '\0')
+    continue;
+
+  return yyd - 1;
+}
+#  endif
+# endif
+
+# ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+   quotes and backslashes, so that it's suitable for yyerror.  The
+   heuristic is that double-quoting is unnecessary unless the string
+   contains an apostrophe, a comma, or backslash (other than
+   backslash-backslash).  YYSTR is taken from yytname.  If YYRES is
+   null, do not copy; instead, return the length of what the result
+   would have been.  */
+static YYSIZE_T
+yytnamerr (char *yyres, const char *yystr)
+{
+  if (*yystr == '"')
+    {
+      YYSIZE_T yyn = 0;
+      char const *yyp = yystr;
+
+      for (;;)
+	switch (*++yyp)
+	  {
+	  case '\'':
+	  case ',':
+	    goto do_not_strip_quotes;
+
+	  case '\\':
+	    if (*++yyp != '\\')
+	      goto do_not_strip_quotes;
+	    /* Fall through.  */
+	  default:
+	    if (yyres)
+	      yyres[yyn] = *yyp;
+	    yyn++;
+	    break;
+
+	  case '"':
+	    if (yyres)
+	      yyres[yyn] = '\0';
+	    return yyn;
+	  }
+    do_not_strip_quotes: ;
+    }
+
+  if (! yyres)
+    return yystrlen (yystr);
+
+  return yystpcpy (yyres, yystr) - yyres;
+}
+# endif
+
+/* 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)
+{
+  int yyn = yypact[yystate];
+
+  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;
+	  }
+
+      yyf = YY_(yyformat);
+      yysize1 = yysize + yystrlen (yyf);
+      yysize_overflow |= (yysize1 < yysize);
+      yysize = yysize1;
+
+      if (yysize_overflow)
+	return YYSIZE_MAXIMUM;
+
+      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.  |
+`-----------------------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yydestruct (yymsg, yytype, yyvaluep)
+    const char *yymsg;
+    int yytype;
+    YYSTYPE *yyvaluep;
+#endif
+{
+  YYUSE (yyvaluep);
+
+  if (!yymsg)
+    yymsg = "Deleting";
+  YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
+  switch (yytype)
+    {
+
+      default:
+	break;
+    }
+}
+

+
+/* 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 look-ahead symbol.  */
+int yychar;
+
+/* The semantic value of the look-ahead symbol.  */
+YYSTYPE yylval;
+
+/* Number of syntax errors so far.  */
+int yynerrs;
+
+
+
+/*----------.
+| yyparse.  |
+`----------*/
+
+#ifdef YYPARSE_PARAM
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void *YYPARSE_PARAM)
+#else
+int
+yyparse (YYPARSE_PARAM)
+    void *YYPARSE_PARAM;
+#endif
+#else /* ! YYPARSE_PARAM */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void)
+#else
+int
+yyparse ()
+
+#endif
+#endif
+{
+  
+  int yystate;
+  int yyn;
+  int yyresult;
+  /* 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];
+  char *yymsg = yymsgbuf;
+  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;
+
+  YYDPRINTF ((stderr, "Starting parse\n"));
+
+  yystate = 0;
+  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;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate.  |
+`------------------------------------------------------------*/
+ yynewstate:
+  /* In all cases, when you get here, the value and location stacks
+     have just been pushed.  So pushing a state here evens the stacks.  */
+  yyssp++;
+
+ yysetstate:
+  *yyssp = yystate;
+
+  if (yyss + yystacksize - 1 <= yyssp)
+    {
+      /* Get the current used size of the three stacks, in elements.  */
+      YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+      {
+	/* Give user a chance to reallocate the stack.  Use copies of
+	   these so that the &'s don't force the real ones into
+	   memory.  */
+	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
+	   be undefined if yyoverflow is a macro.  */
+	yyoverflow (YY_("memory exhausted"),
+		    &yyss1, yysize * sizeof (*yyssp),
+		    &yyvs1, yysize * sizeof (*yyvsp),
+
+		    &yystacksize);
+
+	yyss = yyss1;
+	yyvs = yyvs1;
+      }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+      goto yyexhaustedlab;
+# else
+      /* Extend the stack our own way.  */
+      if (YYMAXDEPTH <= yystacksize)
+	goto yyexhaustedlab;
+      yystacksize *= 2;
+      if (YYMAXDEPTH < yystacksize)
+	yystacksize = YYMAXDEPTH;
+
+      {
+	yytype_int16 *yyss1 = yyss;
+	union yyalloc *yyptr =
+	  (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+	if (! yyptr)
+	  goto yyexhaustedlab;
+	YYSTACK_RELOCATE (yyss);
+	YYSTACK_RELOCATE (yyvs);
+
+#  undef YYSTACK_RELOCATE
+	if (yyss1 != yyssa)
+	  YYSTACK_FREE (yyss1);
+      }
+# endif
+#endif /* no yyoverflow */
+
+      yyssp = yyss + yysize - 1;
+      yyvsp = yyvs + yysize - 1;
+
+
+      YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+		  (unsigned long int) yystacksize));
+
+      if (yyss + yystacksize - 1 <= yyssp)
+	YYABORT;
+    }
+
+  YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+  goto yybackup;
+
+/*-----------.
+| yybackup.  |
+`-----------*/
+yybackup:
+
+  /* Do appropriate processing given the current state.  Read a
+     look-ahead token if we need one and don't already have one.  */
+
+  /* First try to decide what to do without reference to look-ahead token.  */
+  yyn = yypact[yystate];
+  if (yyn == YYPACT_NINF)
+    goto yydefault;
+
+  /* Not known => get a look-ahead token if don't already have one.  */
+
+  /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol.  */
+  if (yychar == YYEMPTY)
+    {
+      YYDPRINTF ((stderr, "Reading a token: "));
+      yychar = YYLEX;
+    }
+
+  if (yychar <= YYEOF)
+    {
+      yychar = yytoken = YYEOF;
+      YYDPRINTF ((stderr, "Now at end of input.\n"));
+    }
+  else
+    {
+      yytoken = YYTRANSLATE (yychar);
+      YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
+    }
+
+  /* If the proper action on seeing token YYTOKEN is to reduce or to
+     detect an error, take that action.  */
+  yyn += yytoken;
+  if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+    goto yydefault;
+  yyn = yytable[yyn];
+  if (yyn <= 0)
+    {
+      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 look-ahead token.  */
+  YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+
+  /* Discard the shifted token unless it is eof.  */
+  if (yychar != YYEOF)
+    yychar = YYEMPTY;
+
+  yystate = yyn;
+  *++yyvsp = yylval;
+
+  goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state.  |
+`-----------------------------------------------------------*/
+yydefault:
+  yyn = yydefact[yystate];
+  if (yyn == 0)
+    goto yyerrlab;
+  goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction.  |
+`-----------------------------*/
+yyreduce:
+  /* yyn is the number of a rule to reduce with.  */
+  yylen = yyr2[yyn];
+
+  /* If YYLEN is nonzero, implement the default value of the action:
+     `$$ = $1'.
+
+     Otherwise, the following line sets YYVAL to garbage.
+     This behavior is undocumented and Bison
+     users should not rely upon it.  Assigning to YYVAL
+     unconditionally makes the parser a bit smaller, and it avoids a
+     GCC warning that YYVAL may be used uninitialized.  */
+  yyval = yyvsp[1-yylen];
+
+
+  YY_REDUCE_PRINT (yyn);
+  switch (yyn)
+    {
+        case 3:
+#line 71 "a.y"
+    {
+		stmtline = lineno;
+	}
+    break;
+
+  case 5:
+#line 78 "a.y"
+    {
+		if((yyvsp[(1) - (2)].sym)->value != pc)
+			yyerror("redeclaration of %s", (yyvsp[(1) - (2)].sym)->name);
+		(yyvsp[(1) - (2)].sym)->value = pc;
+	}
+    break;
+
+  case 7:
+#line 85 "a.y"
+    {
+		(yyvsp[(1) - (2)].sym)->type = LLAB;
+		(yyvsp[(1) - (2)].sym)->value = pc;
+	}
+    break;
+
+  case 12:
+#line 96 "a.y"
+    {
+		(yyvsp[(1) - (3)].sym)->type = LVAR;
+		(yyvsp[(1) - (3)].sym)->value = (yyvsp[(3) - (3)].lval);
+	}
+    break;
+
+  case 13:
+#line 101 "a.y"
+    {
+		if((yyvsp[(1) - (3)].sym)->value != (yyvsp[(3) - (3)].lval))
+			yyerror("redeclaration of %s", (yyvsp[(1) - (3)].sym)->name);
+		(yyvsp[(1) - (3)].sym)->value = (yyvsp[(3) - (3)].lval);
+	}
+    break;
+
+  case 14:
+#line 106 "a.y"
+    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
+    break;
+
+  case 15:
+#line 107 "a.y"
+    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
+    break;
+
+  case 16:
+#line 108 "a.y"
+    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
+    break;
+
+  case 17:
+#line 109 "a.y"
+    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
+    break;
+
+  case 18:
+#line 110 "a.y"
+    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
+    break;
+
+  case 19:
+#line 111 "a.y"
+    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
+    break;
+
+  case 20:
+#line 112 "a.y"
+    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
+    break;
+
+  case 21:
+#line 113 "a.y"
+    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
+    break;
+
+  case 22:
+#line 114 "a.y"
+    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
+    break;
+
+  case 23:
+#line 115 "a.y"
+    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
+    break;
+
+  case 24:
+#line 116 "a.y"
+    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
+    break;
+
+  case 25:
+#line 117 "a.y"
+    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
+    break;
+
+  case 26:
+#line 118 "a.y"
+    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
+    break;
+
+  case 27:
+#line 119 "a.y"
+    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
+    break;
+
+  case 28:
+#line 120 "a.y"
+    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
+    break;
+
+  case 29:
+#line 121 "a.y"
+    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
+    break;
+
+  case 30:
+#line 122 "a.y"
+    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
+    break;
+
+  case 31:
+#line 123 "a.y"
+    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
+    break;
+
+  case 32:
+#line 126 "a.y"
+    {
+		(yyval.addr2).from = nullgen;
+		(yyval.addr2).to = nullgen;
+	}
+    break;
+
+  case 33:
+#line 131 "a.y"
+    {
+		(yyval.addr2).from = nullgen;
+		(yyval.addr2).to = nullgen;
+	}
+    break;
+
+  case 34:
+#line 138 "a.y"
+    {
+		(yyval.addr2).from = (yyvsp[(1) - (3)].addr);
+		(yyval.addr2).to = (yyvsp[(3) - (3)].addr);
+	}
+    break;
+
+  case 35:
+#line 145 "a.y"
+    {
+		(yyval.addr2).from = (yyvsp[(1) - (3)].addr);
+		(yyval.addr2).to = (yyvsp[(3) - (3)].addr);
+	}
+    break;
+
+  case 36:
+#line 152 "a.y"
+    {
+		(yyval.addr2).from = (yyvsp[(1) - (2)].addr);
+		(yyval.addr2).to = nullgen;
+	}
+    break;
+
+  case 37:
+#line 157 "a.y"
+    {
+		(yyval.addr2).from = (yyvsp[(1) - (1)].addr);
+		(yyval.addr2).to = nullgen;
+	}
+    break;
+
+  case 38:
+#line 164 "a.y"
+    {
+		(yyval.addr2).from = nullgen;
+		(yyval.addr2).to = (yyvsp[(2) - (2)].addr);
+	}
+    break;
+
+  case 39:
+#line 169 "a.y"
+    {
+		(yyval.addr2).from = nullgen;
+		(yyval.addr2).to = (yyvsp[(1) - (1)].addr);
+	}
+    break;
+
+  case 40:
+#line 176 "a.y"
+    {
+		(yyval.addr2).from = nullgen;
+		(yyval.addr2).to = (yyvsp[(2) - (2)].addr);
+	}
+    break;
+
+  case 41:
+#line 181 "a.y"
+    {
+		(yyval.addr2).from = nullgen;
+		(yyval.addr2).to = (yyvsp[(1) - (1)].addr);
+	}
+    break;
+
+  case 42:
+#line 186 "a.y"
+    {
+		(yyval.addr2).from = (yyvsp[(1) - (3)].addr);
+		(yyval.addr2).to = (yyvsp[(3) - (3)].addr);
+	}
+    break;
+
+  case 43:
+#line 193 "a.y"
+    {
+		(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 201 "a.y"
+    {
+		(yyval.addr2).from = (yyvsp[(1) - (3)].addr);
+		(yyval.addr2).to = (yyvsp[(3) - (3)].addr);
+	}
+    break;
+
+  case 45:
+#line 206 "a.y"
+    {
+		(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 214 "a.y"
+    {
+		(yyval.addr2).from = nullgen;
+		(yyval.addr2).to = (yyvsp[(2) - (2)].addr);
+	}
+    break;
+
+  case 47:
+#line 219 "a.y"
+    {
+		(yyval.addr2).from = nullgen;
+		(yyval.addr2).to = (yyvsp[(1) - (1)].addr);
+	}
+    break;
+
+  case 48:
+#line 224 "a.y"
+    {
+		(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 237 "a.y"
+    {
+		(yyval.addr2).from = (yyvsp[(1) - (3)].addr);
+		(yyval.addr2).to = (yyvsp[(3) - (3)].addr);
+	}
+    break;
+
+  case 52:
+#line 242 "a.y"
+    {
+		(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.addr2).from.index = (yyvsp[(5) - (5)].lval);
+	}
+    break;
+
+  case 53:
+#line 252 "a.y"
+    {
+		(yyval.addr2).from = (yyvsp[(1) - (3)].addr);
+		(yyval.addr2).to = (yyvsp[(3) - (3)].addr);
+	}
+    break;
+
+  case 54:
+#line 257 "a.y"
+    {
+		(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.addr2).to.index = (yyvsp[(5) - (5)].lval);
+	}
+    break;
+
+  case 55:
+#line 267 "a.y"
+    {
+		(yyval.addr2).from = (yyvsp[(1) - (2)].addr);
+		(yyval.addr2).to = nullgen;
+	}
+    break;
+
+  case 56:
+#line 272 "a.y"
+    {
+		(yyval.addr2).from = (yyvsp[(1) - (1)].addr);
+		(yyval.addr2).to = nullgen;
+	}
+    break;
+
+  case 57:
+#line 277 "a.y"
+    {
+		(yyval.addr2).from = (yyvsp[(1) - (3)].addr);
+		(yyval.addr2).to = (yyvsp[(3) - (3)].addr);
+	}
+    break;
+
+  case 58:
+#line 284 "a.y"
+    {
+		(yyval.addr2).from = (yyvsp[(1) - (3)].addr);
+		(yyval.addr2).to = (yyvsp[(3) - (3)].addr);
+	}
+    break;
+
+  case 59:
+#line 289 "a.y"
+    {
+		(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 297 "a.y"
+    {
+		(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 305 "a.y"
+    {
+		(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.addr2).to.offset = (yyvsp[(1) - (5)].addr).offset;
+	}
+    break;
+
+  case 62:
+#line 315 "a.y"
+    {
+		if((yyvsp[(1) - (3)].addr).type != D_CONST || (yyvsp[(3) - (3)].addr).type != D_CONST)
+			yyerror("arguments to PCDATA must be integer constants");
+		(yyval.addr2).from = (yyvsp[(1) - (3)].addr);
+		(yyval.addr2).to = (yyvsp[(3) - (3)].addr);
+	}
+    break;
+
+  case 63:
+#line 324 "a.y"
+    {
+		if((yyvsp[(1) - (3)].addr).type != D_CONST)
+			yyerror("index for FUNCDATA must be integer constant");
+		if((yyvsp[(3) - (3)].addr).type != D_EXTERN && (yyvsp[(3) - (3)].addr).type != D_STATIC)
+			yyerror("value for FUNCDATA must be symbol reference");
+ 		(yyval.addr2).from = (yyvsp[(1) - (3)].addr);
+ 		(yyval.addr2).to = (yyvsp[(3) - (3)].addr);
+ 	}
+    break;
+
+  case 68:
+#line 341 "a.y"
+    {
+		(yyval.addr) = (yyvsp[(2) - (2)].addr);
+	}
+    break;
+
+  case 69:
+#line 345 "a.y"
+    {
+		(yyval.addr) = (yyvsp[(2) - (2)].addr);
+	}
+    break;
+
+  case 75:
+#line 358 "a.y"
+    {
+		(yyval.addr) = nullgen;
+		(yyval.addr).type = D_BRANCH;
+		(yyval.addr).offset = (yyvsp[(1) - (4)].lval) + pc;
+	}
+    break;
+
+  case 76:
+#line 364 "a.y"
+    {
+		(yyval.addr) = nullgen;
+		if(pass == 2)
+			yyerror("undefined label: %s", (yyvsp[(1) - (2)].sym)->name);
+		(yyval.addr).type = D_BRANCH;
+		(yyval.addr).offset = (yyvsp[(2) - (2)].lval);
+	}
+    break;
+
+  case 77:
+#line 372 "a.y"
+    {
+		(yyval.addr) = nullgen;
+		(yyval.addr).type = D_BRANCH;
+		(yyval.addr).offset = (yyvsp[(1) - (2)].sym)->value + (yyvsp[(2) - (2)].lval);
+	}
+    break;
+
+  case 78:
+#line 380 "a.y"
+    {
+		(yyval.addr) = nullgen;
+		(yyval.addr).type = (yyvsp[(1) - (1)].lval);
+	}
+    break;
+
+  case 79:
+#line 385 "a.y"
+    {
+		(yyval.addr) = nullgen;
+		(yyval.addr).type = (yyvsp[(1) - (1)].lval);
+	}
+    break;
+
+  case 80:
+#line 390 "a.y"
+    {
+		(yyval.addr) = nullgen;
+		(yyval.addr).type = (yyvsp[(1) - (1)].lval);
+	}
+    break;
+
+  case 81:
+#line 395 "a.y"
+    {
+		(yyval.addr) = nullgen;
+		(yyval.addr).type = (yyvsp[(1) - (1)].lval);
+	}
+    break;
+
+  case 82:
+#line 400 "a.y"
+    {
+		(yyval.addr) = nullgen;
+		(yyval.addr).type = D_SP;
+	}
+    break;
+
+  case 83:
+#line 405 "a.y"
+    {
+		(yyval.addr) = nullgen;
+		(yyval.addr).type = (yyvsp[(1) - (1)].lval);
+	}
+    break;
+
+  case 84:
+#line 412 "a.y"
+    {
+		(yyval.addr) = nullgen;
+		(yyval.addr).type = D_CONST;
+		(yyval.addr).offset = (yyvsp[(2) - (2)].lval);
+	}
+    break;
+
+  case 85:
+#line 418 "a.y"
+    {
+		(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",
+				$2.sym->name);
+		 */
+	}
+    break;
+
+  case 86:
+#line 429 "a.y"
+    {
+		(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 435 "a.y"
+    {
+		(yyval.addr) = nullgen;
+		(yyval.addr).type = D_FCONST;
+		(yyval.addr).u.dval = (yyvsp[(2) - (2)].dval);
+	}
+    break;
+
+  case 88:
+#line 441 "a.y"
+    {
+		(yyval.addr) = nullgen;
+		(yyval.addr).type = D_FCONST;
+		(yyval.addr).u.dval = (yyvsp[(3) - (4)].dval);
+	}
+    break;
+
+  case 89:
+#line 447 "a.y"
+    {
+		(yyval.addr) = nullgen;
+		(yyval.addr).type = D_FCONST;
+		(yyval.addr).u.dval = -(yyvsp[(4) - (5)].dval);
+	}
+    break;
+
+  case 90:
+#line 453 "a.y"
+    {
+		(yyval.addr) = nullgen;
+		(yyval.addr).type = D_FCONST;
+		(yyval.addr).u.dval = -(yyvsp[(3) - (3)].dval);
+	}
+    break;
+
+  case 91:
+#line 461 "a.y"
+    {
+		(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 470 "a.y"
+    {
+		(yyval.con2).v1 = (yyvsp[(1) - (1)].lval);
+		(yyval.con2).v2 = ArgsSizeUnknown;
+	}
+    break;
+
+  case 93:
+#line 475 "a.y"
+    {
+		(yyval.con2).v1 = -(yyvsp[(2) - (2)].lval);
+		(yyval.con2).v2 = ArgsSizeUnknown;
+	}
+    break;
+
+  case 94:
+#line 480 "a.y"
+    {
+		(yyval.con2).v1 = (yyvsp[(1) - (3)].lval);
+		(yyval.con2).v2 = (yyvsp[(3) - (3)].lval);
+	}
+    break;
+
+  case 95:
+#line 485 "a.y"
+    {
+		(yyval.con2).v1 = -(yyvsp[(2) - (4)].lval);
+		(yyval.con2).v2 = (yyvsp[(4) - (4)].lval);
+	}
+    break;
+
+  case 98:
+#line 496 "a.y"
+    {
+		(yyval.addr) = nullgen;
+		(yyval.addr).type = D_INDIR+D_NONE;
+		(yyval.addr).offset = (yyvsp[(1) - (1)].lval);
+	}
+    break;
+
+  case 99:
+#line 502 "a.y"
+    {
+		(yyval.addr) = nullgen;
+		(yyval.addr).type = D_INDIR+(yyvsp[(3) - (4)].lval);
+		(yyval.addr).offset = (yyvsp[(1) - (4)].lval);
+	}
+    break;
+
+  case 100:
+#line 508 "a.y"
+    {
+		(yyval.addr) = nullgen;
+		(yyval.addr).type = D_INDIR+D_SP;
+		(yyval.addr).offset = (yyvsp[(1) - (4)].lval);
+	}
+    break;
+
+  case 101:
+#line 514 "a.y"
+    {
+		(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 523 "a.y"
+    {
+		(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 532 "a.y"
+    {
+		(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 541 "a.y"
+    {
+		(yyval.addr) = nullgen;
+		(yyval.addr).type = D_INDIR+(yyvsp[(2) - (3)].lval);
+	}
+    break;
+
+  case 105:
+#line 546 "a.y"
+    {
+		(yyval.addr) = nullgen;
+		(yyval.addr).type = D_INDIR+D_SP;
+	}
+    break;
+
+  case 106:
+#line 551 "a.y"
+    {
+		(yyval.addr) = nullgen;
+		(yyval.addr).type = D_INDIR+(yyvsp[(3) - (4)].lval);
+		(yyval.addr).offset = (yyvsp[(1) - (4)].lval);
+	}
+    break;
+
+  case 107:
+#line 557 "a.y"
+    {
+		(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 565 "a.y"
+    {
+		(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 575 "a.y"
+    {
+		(yyval.addr) = (yyvsp[(1) - (1)].addr);
+	}
+    break;
+
+  case 110:
+#line 579 "a.y"
+    {
+		(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 588 "a.y"
+    {
+		(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 595 "a.y"
+    {
+		(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 603 "a.y"
+    {
+		(yyval.lval) = 0;
+	}
+    break;
+
+  case 114:
+#line 607 "a.y"
+    {
+		(yyval.lval) = (yyvsp[(2) - (2)].lval);
+	}
+    break;
+
+  case 115:
+#line 611 "a.y"
+    {
+		(yyval.lval) = -(yyvsp[(2) - (2)].lval);
+	}
+    break;
+
+  case 117:
+#line 618 "a.y"
+    {
+		(yyval.lval) = D_AUTO;
+	}
+    break;
+
+  case 120:
+#line 626 "a.y"
+    {
+		(yyval.lval) = (yyvsp[(1) - (1)].sym)->value;
+	}
+    break;
+
+  case 121:
+#line 630 "a.y"
+    {
+		(yyval.lval) = -(yyvsp[(2) - (2)].lval);
+	}
+    break;
+
+  case 122:
+#line 634 "a.y"
+    {
+		(yyval.lval) = (yyvsp[(2) - (2)].lval);
+	}
+    break;
+
+  case 123:
+#line 638 "a.y"
+    {
+		(yyval.lval) = ~(yyvsp[(2) - (2)].lval);
+	}
+    break;
+
+  case 124:
+#line 642 "a.y"
+    {
+		(yyval.lval) = (yyvsp[(2) - (3)].lval);
+	}
+    break;
+
+  case 126:
+#line 649 "a.y"
+    {
+		(yyval.lval) = (yyvsp[(1) - (3)].lval) + (yyvsp[(3) - (3)].lval);
+	}
+    break;
+
+  case 127:
+#line 653 "a.y"
+    {
+		(yyval.lval) = (yyvsp[(1) - (3)].lval) - (yyvsp[(3) - (3)].lval);
+	}
+    break;
+
+  case 128:
+#line 657 "a.y"
+    {
+		(yyval.lval) = (yyvsp[(1) - (3)].lval) * (yyvsp[(3) - (3)].lval);
+	}
+    break;
+
+  case 129:
+#line 661 "a.y"
+    {
+		(yyval.lval) = (yyvsp[(1) - (3)].lval) / (yyvsp[(3) - (3)].lval);
+	}
+    break;
+
+  case 130:
+#line 665 "a.y"
+    {
+		(yyval.lval) = (yyvsp[(1) - (3)].lval) % (yyvsp[(3) - (3)].lval);
+	}
+    break;
+
+  case 131:
+#line 669 "a.y"
+    {
+		(yyval.lval) = (yyvsp[(1) - (4)].lval) << (yyvsp[(4) - (4)].lval);
+	}
+    break;
+
+  case 132:
+#line 673 "a.y"
+    {
+		(yyval.lval) = (yyvsp[(1) - (4)].lval) >> (yyvsp[(4) - (4)].lval);
+	}
+    break;
+
+  case 133:
+#line 677 "a.y"
+    {
+		(yyval.lval) = (yyvsp[(1) - (3)].lval) & (yyvsp[(3) - (3)].lval);
+	}
+    break;
+
+  case 134:
+#line 681 "a.y"
+    {
+		(yyval.lval) = (yyvsp[(1) - (3)].lval) ^ (yyvsp[(3) - (3)].lval);
+	}
+    break;
+
+  case 135:
+#line 685 "a.y"
+    {
+		(yyval.lval) = (yyvsp[(1) - (3)].lval) | (yyvsp[(3) - (3)].lval);
+	}
+    break;
+
+
+/* Line 1267 of yacc.c.  */
+#line 2566 "y.tab.c"
+      default: break;
+    }
+  YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
+
+  YYPOPSTACK (yylen);
+  yylen = 0;
+  YY_STACK_PRINT (yyss, yyssp);
+
+  *++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.  */
+
+  yyn = yyr1[yyn];
+
+  yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+  if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+    yystate = yytable[yystate];
+  else
+    yystate = yydefgoto[yyn - YYNTOKENS];
+
+  goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+  /* If not already recovering from an error, report this error.  */
+  if (!yyerrstatus)
+    {
+      ++yynerrs;
+#if ! YYERROR_VERBOSE
+      yyerror (YY_("syntax error"));
+#else
+      {
+	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;
+	  }
+      }
+#endif
+    }
+
+
+
+  if (yyerrstatus == 3)
+    {
+      /* If just tried and failed to reuse look-ahead token after an
+	 error, discard it.  */
+
+      if (yychar <= YYEOF)
+	{
+	  /* Return failure if at end of input.  */
+	  if (yychar == YYEOF)
+	    YYABORT;
+	}
+      else
+	{
+	  yydestruct ("Error: discarding",
+		      yytoken, &yylval);
+	  yychar = YYEMPTY;
+	}
+    }
+
+  /* Else will try to reuse look-ahead token after shifting the error
+     token.  */
+  goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR.  |
+`---------------------------------------------------*/
+yyerrorlab:
+
+  /* Pacify compilers like GCC when the user code never invokes
+     YYERROR and the label yyerrorlab therefore never appears in user
+     code.  */
+  if (/*CONSTCOND*/ 0)
+     goto yyerrorlab;
+
+  /* Do not reclaim the symbols of the rule which action triggered
+     this YYERROR.  */
+  YYPOPSTACK (yylen);
+  yylen = 0;
+  YY_STACK_PRINT (yyss, yyssp);
+  yystate = *yyssp;
+  goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR.  |
+`-------------------------------------------------------------*/
+yyerrlab1:
+  yyerrstatus = 3;	/* Each real token shifted decrements this.  */
+
+  for (;;)
+    {
+      yyn = yypact[yystate];
+      if (yyn != YYPACT_NINF)
+	{
+	  yyn += YYTERROR;
+	  if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+	    {
+	      yyn = yytable[yyn];
+	      if (0 < yyn)
+		break;
+	    }
+	}
+
+      /* Pop the current state because it cannot handle the error token.  */
+      if (yyssp == yyss)
+	YYABORT;
+
+
+      yydestruct ("Error: popping",
+		  yystos[yystate], yyvsp);
+      YYPOPSTACK (1);
+      yystate = *yyssp;
+      YY_STACK_PRINT (yyss, yyssp);
+    }
+
+  if (yyn == YYFINAL)
+    YYACCEPT;
+
+  *++yyvsp = yylval;
+
+
+  /* Shift the error token.  */
+  YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+
+  yystate = yyn;
+  goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here.  |
+`-------------------------------------*/
+yyacceptlab:
+  yyresult = 0;
+  goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here.  |
+`-----------------------------------*/
+yyabortlab:
+  yyresult = 1;
+  goto yyreturn;
+
+#ifndef yyoverflow
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here.  |
+`-------------------------------------------------*/
+yyexhaustedlab:
+  yyerror (YY_("memory exhausted"));
+  yyresult = 2;
+  /* Fall through.  */
+#endif
+
+yyreturn:
+  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);
+  YY_STACK_PRINT (yyss, yyssp);
+  while (yyssp != yyss)
+    {
+      yydestruct ("Cleanup: popping",
+		  yystos[*yyssp], yyvsp);
+      YYPOPSTACK (1);
+    }
+#ifndef yyoverflow
+  if (yyss != yyssa)
+    YYSTACK_FREE (yyss);
+#endif
+#if YYERROR_VERBOSE
+  if (yymsg != yymsgbuf)
+    YYSTACK_FREE (yymsg);
+#endif
+  /* Make sure YYID is used.  */
+  return YYID (yyresult);
+}
+
+
+
diff --git a/src/cmd/8a/y.tab.h b/src/cmd/8a/y.tab.h
new file mode 100644
index 0000000..d191455
--- /dev/null
+++ b/src/cmd/8a/y.tab.h
@@ -0,0 +1,139 @@
+/* A Bison parser, made by GNU Bison 2.3.  */
+
+/* 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 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, 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
+   under terms of your choice, so long as that work isn't itself a
+   parser generator using the skeleton or a modified version thereof
+   as a parser skeleton.  Alternatively, if you modify or redistribute
+   the parser skeleton itself, you may (at your option) remove this
+   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
+   /* Put the tokens into the symbol table, so that GDB and other debuggers
+      know about them.  */
+   enum yytokentype {
+     LTYPE0 = 258,
+     LTYPE1 = 259,
+     LTYPE2 = 260,
+     LTYPE3 = 261,
+     LTYPE4 = 262,
+     LTYPEC = 263,
+     LTYPED = 264,
+     LTYPEN = 265,
+     LTYPER = 266,
+     LTYPET = 267,
+     LTYPES = 268,
+     LTYPEM = 269,
+     LTYPEI = 270,
+     LTYPEG = 271,
+     LTYPEXC = 272,
+     LTYPEX = 273,
+     LTYPEPC = 274,
+     LTYPEF = 275,
+     LCONST = 276,
+     LFP = 277,
+     LPC = 278,
+     LSB = 279,
+     LBREG = 280,
+     LLREG = 281,
+     LSREG = 282,
+     LFREG = 283,
+     LXREG = 284,
+     LFCONST = 285,
+     LSCONST = 286,
+     LSP = 287,
+     LNAME = 288,
+     LLAB = 289,
+     LVAR = 290
+   };
+#endif
+/* Tokens.  */
+#define LTYPE0 258
+#define LTYPE1 259
+#define LTYPE2 260
+#define LTYPE3 261
+#define LTYPE4 262
+#define LTYPEC 263
+#define LTYPED 264
+#define LTYPEN 265
+#define LTYPER 266
+#define LTYPET 267
+#define LTYPES 268
+#define LTYPEM 269
+#define LTYPEI 270
+#define LTYPEG 271
+#define LTYPEXC 272
+#define LTYPEX 273
+#define LTYPEPC 274
+#define LTYPEF 275
+#define LCONST 276
+#define LFP 277
+#define LPC 278
+#define LSB 279
+#define LBREG 280
+#define LLREG 281
+#define LSREG 282
+#define LFREG 283
+#define LXREG 284
+#define LFCONST 285
+#define LSCONST 286
+#define LSP 287
+#define LNAME 288
+#define LLAB 289
+#define LVAR 290
+
+
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+#line 38 "a.y"
+{
+	Sym	*sym;
+	int32	lval;
+	struct {
+		int32 v1;
+		int32 v2;
+	} con2;
+	double	dval;
+	char	sval[8];
+	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/Makefile b/src/cmd/8c/Makefile
new file mode 100644
index 0000000..3f528d7
--- /dev/null
+++ b/src/cmd/8c/Makefile
@@ -0,0 +1,5 @@
+# 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/8c/cgen.c b/src/cmd/8c/cgen.c
new file mode 100644
index 0000000..87e8fda
--- /dev/null
+++ b/src/cmd/8c/cgen.c
@@ -0,0 +1,1939 @@
+// Inferno utils/8c/cgen.c
+// http://code.google.com/p/inferno-os/source/browse/utils/8c/cgen.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 "gc.h"
+#include "../../runtime/funcdata.h"
+
+/* ,x/^(print|prtree)\(/i/\/\/ */
+
+void
+cgen(Node *n, Node *nn)
+{
+	Node *l, *r, *t;
+	Prog *p1;
+	Node nod, nod1, nod2, nod3, nod4;
+	int o, hardleft;
+	int32 v, curs;
+	vlong c;
+
+	if(debug['g']) {
+		prtree(nn, "cgen lhs");
+		prtree(n, "cgen");
+	}
+	if(n == Z || n->type == T)
+		return;
+	if(typesuv[n->type->etype] && (n->op != OFUNC || nn != Z)) {
+		sugen(n, nn, n->type->width);
+		return;
+	}
+	l = n->left;
+	r = n->right;
+	o = n->op;
+
+	if(n->op == OEXREG || (nn != Z && nn->op == OEXREG)) {
+		gmove(n, nn);
+		return;
+	}
+
+	if(n->addable >= INDEXED) {
+		if(nn == Z) {
+			switch(o) {
+			default:
+				nullwarn(Z, Z);
+				break;
+			case OINDEX:
+				nullwarn(l, r);
+				break;
+			}
+			return;
+		}
+		gmove(n, nn);
+		return;
+	}
+	curs = cursafe;
+
+	if(l->complex >= FNX)
+	if(r != Z && r->complex >= FNX)
+	switch(o) {
+	default:
+		if(cond(o) && typesuv[l->type->etype])
+			break;
+
+		regret(&nod, r, 0, 0);
+		cgen(r, &nod);
+
+		regsalloc(&nod1, r);
+		gmove(&nod, &nod1);
+
+		regfree(&nod);
+		nod = *n;
+		nod.right = &nod1;
+
+		cgen(&nod, nn);
+		return;
+
+	case OFUNC:
+	case OCOMMA:
+	case OANDAND:
+	case OOROR:
+	case OCOND:
+	case ODOT:
+		break;
+	}
+
+	hardleft = l->addable < INDEXED || l->complex >= FNX;
+	switch(o) {
+	default:
+		diag(n, "unknown op in cgen: %O", o);
+		break;
+
+	case ONEG:
+	case OCOM:
+		if(nn == Z) {
+			nullwarn(l, Z);
+			break;
+		}
+		regalloc(&nod, l, nn);
+		cgen(l, &nod);
+		gopcode(o, n->type, Z, &nod);
+		gmove(&nod, nn);
+		regfree(&nod);
+		break;
+
+	case OAS:
+		if(typefd[n->type->etype]) {
+			cgen(r, &fregnode0);
+			if(nn != Z)
+				gins(AFMOVD, &fregnode0, &fregnode0);
+			if(l->addable < INDEXED) {
+				reglcgen(&nod, l, Z);
+				gmove(&fregnode0, &nod);
+				regfree(&nod);
+			} else
+				gmove(&fregnode0, l);
+			if(nn != Z)
+				gmove(&fregnode0, nn);
+			return;
+		}
+		if(l->op == OBIT)
+			goto bitas;
+		if(!hardleft) {
+			if(nn != Z || r->addable < INDEXED) {
+				if(r->complex >= FNX && nn == Z)
+					regret(&nod, r, 0, 0);
+				else
+					regalloc(&nod, r, nn);
+				cgen(r, &nod);
+				gmove(&nod, l);
+				if(nn != Z)
+					gmove(&nod, nn);
+				regfree(&nod);
+			} else
+				gmove(r, l);
+			break;
+		}
+		if(l->complex >= r->complex) {
+			if(l->op == OINDEX && r->op == OCONST) {
+				gmove(r, l);
+				break;
+			}
+			reglcgen(&nod1, l, Z);
+			if(r->addable >= INDEXED) {
+				gmove(r, &nod1);
+				if(nn != Z)
+					gmove(r, nn);
+				regfree(&nod1);
+				break;
+			}
+			regalloc(&nod, r, nn);
+			cgen(r, &nod);
+		} else {
+			regalloc(&nod, r, nn);
+			cgen(r, &nod);
+			reglcgen(&nod1, l, Z);
+		}
+		gmove(&nod, &nod1);
+		regfree(&nod);
+		regfree(&nod1);
+		break;
+
+	bitas:
+		n = l->left;
+		regalloc(&nod, r, nn);
+		if(l->complex >= r->complex) {
+			reglcgen(&nod1, n, Z);
+			cgen(r, &nod);
+		} else {
+			cgen(r, &nod);
+			reglcgen(&nod1, n, Z);
+		}
+		regalloc(&nod2, n, Z);
+		gmove(&nod1, &nod2);
+		bitstore(l, &nod, &nod1, &nod2, nn);
+		break;
+
+	case OBIT:
+		if(nn == Z) {
+			nullwarn(l, Z);
+			break;
+		}
+		bitload(n, &nod, Z, Z, nn);
+		gmove(&nod, nn);
+		regfree(&nod);
+		break;
+
+	case OLSHR:
+	case OASHL:
+	case OASHR:
+		if(nn == Z) {
+			nullwarn(l, r);
+			break;
+		}
+		if(r->op == OCONST) {
+			if(r->vconst == 0) {
+				cgen(l, nn);
+				break;
+			}
+			regalloc(&nod, l, nn);
+			cgen(l, &nod);
+			if(o == OASHL && r->vconst == 1)
+				gopcode(OADD, n->type, &nod, &nod);
+			else
+				gopcode(o, n->type, r, &nod);
+			gmove(&nod, nn);
+			regfree(&nod);
+			break;
+		}
+
+		/*
+		 * get nod to be D_CX
+		 */
+		if(nodreg(&nod, nn, D_CX)) {
+			regsalloc(&nod1, n);
+			gmove(&nod, &nod1);
+			cgen(n, &nod);		/* probably a bug */
+			gmove(&nod, nn);
+			gmove(&nod1, &nod);
+			break;
+		}
+		reg[D_CX]++;
+		if(nn->op == OREGISTER && nn->reg == D_CX)
+			regalloc(&nod1, l, Z);
+		else
+			regalloc(&nod1, l, nn);
+		if(r->complex >= l->complex) {
+			cgen(r, &nod);
+			cgen(l, &nod1);
+		} else {
+			cgen(l, &nod1);
+			cgen(r, &nod);
+		}
+		gopcode(o, n->type, &nod, &nod1);
+		gmove(&nod1, nn);
+		regfree(&nod);
+		regfree(&nod1);
+		break;
+
+	case OADD:
+	case OSUB:
+	case OOR:
+	case OXOR:
+	case OAND:
+		if(nn == Z) {
+			nullwarn(l, r);
+			break;
+		}
+		if(typefd[n->type->etype])
+			goto fop;
+		if(r->op == OCONST) {
+			if(r->vconst == 0 && o != OAND) {
+				cgen(l, nn);
+				break;
+			}
+		}
+		if(n->op == OOR && l->op == OASHL && r->op == OLSHR
+		&& l->right->op == OCONST && r->right->op == OCONST
+		&& l->left->op == ONAME && r->left->op == ONAME
+		&& l->left->sym == r->left->sym
+		&& l->right->vconst + r->right->vconst == 8 * l->left->type->width) {
+			regalloc(&nod, l->left, nn);
+			cgen(l->left, &nod);
+			gopcode(OROTL, n->type, l->right, &nod);
+			gmove(&nod, nn);
+			regfree(&nod);
+			break;
+		}
+		if(n->op == OADD && l->op == OASHL && l->right->op == OCONST
+		&& (r->op != OCONST || r->vconst < -128 || r->vconst > 127)) {
+			c = l->right->vconst;
+			if(c > 0 && c <= 3) {
+				if(l->left->complex >= r->complex) {
+					regalloc(&nod, l->left, nn);
+					cgen(l->left, &nod);
+					if(r->addable < INDEXED) {
+						regalloc(&nod1, r, Z);
+						cgen(r, &nod1);
+						genmuladd(&nod, &nod, 1 << c, &nod1);
+						regfree(&nod1);
+					}
+					else
+						genmuladd(&nod, &nod, 1 << c, r);
+				}
+				else {
+					regalloc(&nod, r, nn);
+					cgen(r, &nod);
+					regalloc(&nod1, l->left, Z);
+					cgen(l->left, &nod1);
+					genmuladd(&nod, &nod1, 1 << c, &nod);
+					regfree(&nod1);
+				}
+				gmove(&nod, nn);
+				regfree(&nod);
+				break;
+			}
+		}
+		if(r->addable >= INDEXED) {
+			regalloc(&nod, l, nn);
+			cgen(l, &nod);
+			gopcode(o, n->type, r, &nod);
+			gmove(&nod, nn);
+			regfree(&nod);
+			break;
+		}
+		if(l->complex >= r->complex) {
+			regalloc(&nod, l, nn);
+			cgen(l, &nod);
+			regalloc(&nod1, r, Z);
+			cgen(r, &nod1);
+			gopcode(o, n->type, &nod1, &nod);
+		} else {
+			regalloc(&nod1, r, nn);
+			cgen(r, &nod1);
+			regalloc(&nod, l, Z);
+			cgen(l, &nod);
+			gopcode(o, n->type, &nod1, &nod);
+		}
+		gmove(&nod, nn);
+		regfree(&nod);
+		regfree(&nod1);
+		break;
+
+	case OLMOD:
+	case OMOD:
+	case OLMUL:
+	case OLDIV:
+	case OMUL:
+	case ODIV:
+		if(nn == Z) {
+			nullwarn(l, r);
+			break;
+		}
+		if(typefd[n->type->etype])
+			goto fop;
+		if(r->op == OCONST) {
+			SET(v);
+			switch(o) {
+			case ODIV:
+			case OMOD:
+				c = r->vconst;
+				if(c < 0)
+					c = -c;
+				v = xlog2(c);
+				if(v < 0)
+					break;
+				/* fall thru */
+			case OMUL:
+			case OLMUL:
+				regalloc(&nod, l, nn);
+				cgen(l, &nod);
+				switch(o) {
+				case OMUL:
+				case OLMUL:
+					mulgen(n->type, r, &nod);
+					break;
+				case ODIV:
+					sdiv2(r->vconst, v, l, &nod);
+					break;
+				case OMOD:
+					smod2(r->vconst, v, l, &nod);
+					break;
+				}
+				gmove(&nod, nn);
+				regfree(&nod);
+				goto done;
+			case OLDIV:
+				c = r->vconst;
+				if((c & 0x80000000) == 0)
+					break;
+				regalloc(&nod1, l, Z);
+				cgen(l, &nod1);
+				regalloc(&nod, l, nn);
+				zeroregm(&nod);
+				gins(ACMPL, &nod1, nodconst(c));
+				gins(ASBBL, nodconst(-1), &nod);
+				regfree(&nod1);
+				gmove(&nod, nn);
+				regfree(&nod);
+				goto done;
+			}
+		}
+
+		if(o == OMUL || o == OLMUL) {
+			if(l->addable >= INDEXED) {
+				t = l;
+				l = r;
+				r = t;
+			}
+			reg[D_DX]++; // for gopcode case OMUL
+			regalloc(&nod, l, nn);
+			cgen(l, &nod);
+			if(r->addable < INDEXED) {
+				regalloc(&nod1, r, Z);
+				cgen(r, &nod1);
+				gopcode(OMUL, n->type, &nod1, &nod);
+				regfree(&nod1);
+			}else
+				gopcode(OMUL, n->type, r, &nod);	/* addressible */
+			gmove(&nod, nn);
+			regfree(&nod);
+			reg[D_DX]--;
+			break;
+		}
+
+		/*
+		 * get nod to be D_AX
+		 * get nod1 to be D_DX
+		 */
+		if(nodreg(&nod, nn, D_AX)) {
+			regsalloc(&nod2, n);
+			gmove(&nod, &nod2);
+			v = reg[D_AX];
+			reg[D_AX] = 0;
+
+			if(isreg(l, D_AX)) {
+				nod3 = *n;
+				nod3.left = &nod2;
+				cgen(&nod3, nn);
+			} else
+			if(isreg(r, D_AX)) {
+				nod3 = *n;
+				nod3.right = &nod2;
+				cgen(&nod3, nn);
+			} else
+				cgen(n, nn);
+
+			gmove(&nod2, &nod);
+			reg[D_AX] = v;
+			break;
+		}
+		if(nodreg(&nod1, nn, D_DX)) {
+			regsalloc(&nod2, n);
+			gmove(&nod1, &nod2);
+			v = reg[D_DX];
+			reg[D_DX] = 0;
+
+			if(isreg(l, D_DX)) {
+				nod3 = *n;
+				nod3.left = &nod2;
+				cgen(&nod3, nn);
+			} else
+			if(isreg(r, D_DX)) {
+				nod3 = *n;
+				nod3.right = &nod2;
+				cgen(&nod3, nn);
+			} else
+				cgen(n, nn);
+
+			gmove(&nod2, &nod1);
+			reg[D_DX] = v;
+			break;
+		}
+		reg[D_AX]++;
+
+		if(r->op == OCONST && (o == ODIV || o == OLDIV)) {
+			reg[D_DX]++;
+			if(l->addable < INDEXED) {
+				regalloc(&nod2, l, Z);
+				cgen(l, &nod2);
+				l = &nod2;
+			}
+			if(o == ODIV)
+				sdivgen(l, r, &nod, &nod1);
+			else
+				udivgen(l, r, &nod, &nod1);
+			gmove(&nod1, nn);
+			if(l == &nod2)
+				regfree(l);
+			goto freeaxdx;
+		}
+
+		if(l->complex >= r->complex) {
+			cgen(l, &nod);
+			reg[D_DX]++;
+			if(o == ODIV || o == OMOD)
+				gins(ACDQ, Z, Z);
+			if(o == OLDIV || o == OLMOD)
+				zeroregm(&nod1);
+			if(r->addable < INDEXED || r->op == OCONST) {
+				regsalloc(&nod3, r);
+				cgen(r, &nod3);
+				gopcode(o, n->type, &nod3, Z);
+			} else
+				gopcode(o, n->type, r, Z);
+		} else {
+			regsalloc(&nod3, r);
+			cgen(r, &nod3);
+			cgen(l, &nod);
+			reg[D_DX]++;
+			if(o == ODIV || o == OMOD)
+				gins(ACDQ, Z, Z);
+			if(o == OLDIV || o == OLMOD)
+				zeroregm(&nod1);
+			gopcode(o, n->type, &nod3, Z);
+		}
+		if(o == OMOD || o == OLMOD)
+			gmove(&nod1, nn);
+		else
+			gmove(&nod, nn);
+	freeaxdx:
+		regfree(&nod);
+		regfree(&nod1);
+		break;
+
+	case OASLSHR:
+	case OASASHL:
+	case OASASHR:
+		if(r->op == OCONST)
+			goto asand;
+		if(l->op == OBIT)
+			goto asbitop;
+		if(typefd[n->type->etype])
+			goto asfop;
+
+		/*
+		 * get nod to be D_CX
+		 */
+		if(nodreg(&nod, nn, D_CX)) {
+			regsalloc(&nod1, n);
+			gmove(&nod, &nod1);
+			cgen(n, &nod);
+			if(nn != Z)
+				gmove(&nod, nn);
+			gmove(&nod1, &nod);
+			break;
+		}
+		reg[D_CX]++;
+
+		if(r->complex >= l->complex) {
+			cgen(r, &nod);
+			if(hardleft)
+				reglcgen(&nod1, l, Z);
+			else
+				nod1 = *l;
+		} else {
+			if(hardleft)
+				reglcgen(&nod1, l, Z);
+			else
+				nod1 = *l;
+			cgen(r, &nod);
+		}
+
+		gopcode(o, l->type, &nod, &nod1);
+		regfree(&nod);
+		if(nn != Z)
+			gmove(&nod1, nn);
+		if(hardleft)
+			regfree(&nod1);
+		break;
+
+	case OASAND:
+	case OASADD:
+	case OASSUB:
+	case OASXOR:
+	case OASOR:
+	asand:
+		if(l->op == OBIT)
+			goto asbitop;
+		if(typefd[n->type->etype]||typefd[r->type->etype])
+			goto asfop;
+		if(l->complex >= r->complex) {
+			if(hardleft)
+				reglcgen(&nod, l, Z);
+			else
+				nod = *l;
+			if(r->op != OCONST) {
+				regalloc(&nod1, r, nn);
+				cgen(r, &nod1);
+				gopcode(o, l->type, &nod1, &nod);
+				regfree(&nod1);
+			} else
+				gopcode(o, l->type, r, &nod);
+		} else {
+			regalloc(&nod1, r, nn);
+			cgen(r, &nod1);
+			if(hardleft)
+				reglcgen(&nod, l, Z);
+			else
+				nod = *l;
+			gopcode(o, l->type, &nod1, &nod);
+			regfree(&nod1);
+		}
+		if(nn != Z)
+			gmove(&nod, nn);
+		if(hardleft)
+			regfree(&nod);
+		break;
+
+	case OASLMUL:
+	case OASLDIV:
+	case OASLMOD:
+	case OASMUL:
+	case OASDIV:
+	case OASMOD:
+		if(l->op == OBIT)
+			goto asbitop;
+		if(typefd[n->type->etype]||typefd[r->type->etype])
+			goto asfop;
+		if(r->op == OCONST) {
+			SET(v);
+			switch(o) {
+			case OASDIV:
+			case OASMOD:
+				c = r->vconst;
+				if(c < 0)
+					c = -c;
+				v = xlog2(c);
+				if(v < 0)
+					break;
+				/* fall thru */
+			case OASMUL:
+			case OASLMUL:
+				if(hardleft)
+					reglcgen(&nod2, l, Z);
+				else
+					nod2 = *l;
+				regalloc(&nod, l, nn);
+				cgen(&nod2, &nod);
+				switch(o) {
+				case OASMUL:
+				case OASLMUL:
+					mulgen(n->type, r, &nod);
+					break;
+				case OASDIV:
+					sdiv2(r->vconst, v, l, &nod);
+					break;
+				case OASMOD:
+					smod2(r->vconst, v, l, &nod);
+					break;
+				}
+			havev:
+				gmove(&nod, &nod2);
+				if(nn != Z)
+					gmove(&nod, nn);
+				if(hardleft)
+					regfree(&nod2);
+				regfree(&nod);
+				goto done;
+			case OASLDIV:
+				c = r->vconst;
+				if((c & 0x80000000) == 0)
+					break;
+				if(hardleft)
+					reglcgen(&nod2, l, Z);
+				else
+					nod2 = *l;
+				regalloc(&nod1, l, nn);
+				cgen(&nod2, &nod1);
+				regalloc(&nod, l, nn);
+				zeroregm(&nod);
+				gins(ACMPL, &nod1, nodconst(c));
+				gins(ASBBL, nodconst(-1), &nod);
+				regfree(&nod1);
+				goto havev;
+			}
+		}
+
+		if(o == OASMUL) {
+			/* should favour AX */
+			regalloc(&nod, l, nn);
+			if(r->complex >= FNX) {
+				regalloc(&nod1, r, Z);
+				cgen(r, &nod1);
+				r = &nod1;
+			}
+			if(hardleft)
+				reglcgen(&nod2, l, Z);
+			else
+				nod2 = *l;
+			cgen(&nod2, &nod);
+			if(r->addable < INDEXED) {
+				if(r->complex < FNX) {
+					regalloc(&nod1, r, Z);
+					cgen(r, &nod1);
+				}
+				gopcode(OASMUL, n->type, &nod1, &nod);
+				regfree(&nod1);
+			}
+			else
+				gopcode(OASMUL, n->type, r, &nod);
+			if(r == &nod1)
+				regfree(r);
+			gmove(&nod, &nod2);
+			if(nn != Z)
+				gmove(&nod, nn);
+			regfree(&nod);
+			if(hardleft)
+				regfree(&nod2);
+			break;
+		}
+
+		/*
+		 * get nod to be D_AX
+		 * get nod1 to be D_DX
+		 */
+		if(nodreg(&nod, nn, D_AX)) {
+			regsalloc(&nod2, n);
+			gmove(&nod, &nod2);
+			v = reg[D_AX];
+			reg[D_AX] = 0;
+
+			if(isreg(l, D_AX)) {
+				nod3 = *n;
+				nod3.left = &nod2;
+				cgen(&nod3, nn);
+			} else
+			if(isreg(r, D_AX)) {
+				nod3 = *n;
+				nod3.right = &nod2;
+				cgen(&nod3, nn);
+			} else
+				cgen(n, nn);
+
+			gmove(&nod2, &nod);
+			reg[D_AX] = v;
+			break;
+		}
+		if(nodreg(&nod1, nn, D_DX)) {
+			regsalloc(&nod2, n);
+			gmove(&nod1, &nod2);
+			v = reg[D_DX];
+			reg[D_DX] = 0;
+
+			if(isreg(l, D_DX)) {
+				nod3 = *n;
+				nod3.left = &nod2;
+				cgen(&nod3, nn);
+			} else
+			if(isreg(r, D_DX)) {
+				nod3 = *n;
+				nod3.right = &nod2;
+				cgen(&nod3, nn);
+			} else
+				cgen(n, nn);
+
+			gmove(&nod2, &nod1);
+			reg[D_DX] = v;
+			break;
+		}
+		reg[D_AX]++;
+		reg[D_DX]++;
+
+		if(l->complex >= r->complex) {
+			if(hardleft)
+				reglcgen(&nod2, l, Z);
+			else
+				nod2 = *l;
+			cgen(&nod2, &nod);
+			if(r->op == OCONST) {
+				switch(o) {
+				case OASDIV:
+					sdivgen(&nod2, r, &nod, &nod1);
+					goto divdone;
+				case OASLDIV:
+					udivgen(&nod2, r, &nod, &nod1);
+				divdone:
+					gmove(&nod1, &nod2);
+					if(nn != Z)
+						gmove(&nod1, nn);
+					goto freelxaxdx;
+				}
+			}
+			if(o == OASDIV || o == OASMOD)
+				gins(ACDQ, Z, Z);
+			if(o == OASLDIV || o == OASLMOD)
+				zeroregm(&nod1);
+			if(r->addable < INDEXED || r->op == OCONST ||
+			   !typeil[r->type->etype]) {
+				regalloc(&nod3, r, Z);
+				cgen(r, &nod3);
+				gopcode(o, l->type, &nod3, Z);
+				regfree(&nod3);
+			} else
+				gopcode(o, n->type, r, Z);
+		} else {
+			regalloc(&nod3, r, Z);
+			cgen(r, &nod3);
+			if(hardleft)
+				reglcgen(&nod2, l, Z);
+			else
+				nod2 = *l;
+			cgen(&nod2, &nod);
+			if(o == OASDIV || o == OASMOD)
+				gins(ACDQ, Z, Z);
+			if(o == OASLDIV || o == OASLMOD)
+				zeroregm(&nod1);
+			gopcode(o, l->type, &nod3, Z);
+			regfree(&nod3);
+		}
+		if(o == OASMOD || o == OASLMOD) {
+			gmove(&nod1, &nod2);
+			if(nn != Z)
+				gmove(&nod1, nn);
+		} else {
+			gmove(&nod, &nod2);
+			if(nn != Z)
+				gmove(&nod, nn);
+		}
+	freelxaxdx:
+		if(hardleft)
+			regfree(&nod2);
+		regfree(&nod);
+		regfree(&nod1);
+		break;
+
+	fop:
+		if(l->complex >= r->complex) {
+			cgen(l, &fregnode0);
+			if(r->addable < INDEXED) {
+				cgen(r, &fregnode0);
+				fgopcode(o, &fregnode0, &fregnode1, 1, 0);
+			} else
+				fgopcode(o, r, &fregnode0, 0, 0);
+		} else {
+			cgen(r, &fregnode0);
+			if(l->addable < INDEXED) {
+				cgen(l, &fregnode0);
+				fgopcode(o, &fregnode0, &fregnode1, 1, 1);
+			} else
+				fgopcode(o, l, &fregnode0, 0, 1);
+		}
+		gmove(&fregnode0, nn);
+		break;
+
+	asfop:
+		if(l->complex >= r->complex) {
+			if(hardleft)
+				reglcgen(&nod, l, Z);
+			else
+				nod = *l;
+			cgen(r, &fregnode0);
+		} else {
+			cgen(r, &fregnode0);
+			if(hardleft)
+				reglcgen(&nod, l, Z);
+			else
+				nod = *l;
+		}
+		if(!typefd[l->type->etype]) {
+			gmove(&nod, &fregnode0);
+			fgopcode(o, &fregnode0, &fregnode1, 1, 1);
+		} else
+			fgopcode(o, &nod, &fregnode0, 0, 1);
+		if(nn != Z)
+			gins(AFMOVD, &fregnode0, &fregnode0);
+		gmove(&fregnode0, &nod);
+		if(nn != Z)
+			gmove(&fregnode0, nn);
+		if(hardleft)
+			regfree(&nod);
+		break;
+
+	asbitop:
+		regalloc(&nod4, n, nn);
+		if(l->complex >= r->complex) {
+			bitload(l, &nod, &nod1, &nod2, &nod4);
+			regalloc(&nod3, r, Z);
+			cgen(r, &nod3);
+		} else {
+			regalloc(&nod3, r, Z);
+			cgen(r, &nod3);
+			bitload(l, &nod, &nod1, &nod2, &nod4);
+		}
+		gmove(&nod, &nod4);
+
+		if(typefd[nod3.type->etype])
+			fgopcode(o, &fregnode0, &fregnode1, 1, 1);
+		else {
+			Node onod;
+
+			/* incredible grot ... */
+			onod = nod3;
+			onod.op = o;
+			onod.complex = 2;
+			onod.addable = 0;
+			onod.type = tfield;
+			onod.left = &nod4;
+			onod.right = &nod3;
+			cgen(&onod, Z);
+		}
+		regfree(&nod3);
+		gmove(&nod4, &nod);
+		regfree(&nod4);
+		bitstore(l, &nod, &nod1, &nod2, nn);
+		break;
+
+	case OADDR:
+		if(nn == Z) {
+			nullwarn(l, Z);
+			break;
+		}
+		lcgen(l, nn);
+		break;
+
+	case OFUNC:
+		if(l->complex >= FNX) {
+			if(l->op != OIND)
+				diag(n, "bad function call");
+
+			regret(&nod, l->left, 0, 0);
+			cgen(l->left, &nod);
+			regsalloc(&nod1, l->left);
+			gmove(&nod, &nod1);
+			regfree(&nod);
+
+			nod = *n;
+			nod.left = &nod2;
+			nod2 = *l;
+			nod2.left = &nod1;
+			nod2.complex = 1;
+			cgen(&nod, nn);
+
+			return;
+		}
+		gargs(r, &nod, &nod1);
+		if(l->addable < INDEXED) {
+			reglcgen(&nod, l, nn);
+			nod.op = OREGISTER;
+			gopcode(OFUNC, n->type, Z, &nod);
+			regfree(&nod);
+		} else
+			gopcode(OFUNC, n->type, Z, l);
+		if(REGARG >= 0 && reg[REGARG])
+			reg[REGARG]--;
+		regret(&nod, n, l->type, 1); // update maxarg if nothing else
+		if(nn != Z)
+			gmove(&nod, nn);
+		if(nod.op == OREGISTER)
+			regfree(&nod);
+		if(nn == Z && hasdotdotdot(l->type) && typefd[n->type->etype])
+			gins(AFMOVDP, &fregnode0, &fregnode0);
+		break;
+
+	case OIND:
+		if(nn == Z) {
+			nullwarn(l, Z);
+			break;
+		}
+		regialloc(&nod, n, nn);
+		r = l;
+		while(r->op == OADD)
+			r = r->right;
+		if(sconst(r)) {
+			v = r->vconst;
+			r->vconst = 0;
+			cgen(l, &nod);
+			nod.xoffset += v;
+			r->vconst = v;
+		} else
+			cgen(l, &nod);
+		regind(&nod, n);
+		gmove(&nod, nn);
+		regfree(&nod);
+		break;
+
+	case OEQ:
+	case ONE:
+	case OLE:
+	case OLT:
+	case OGE:
+	case OGT:
+	case OLO:
+	case OLS:
+	case OHI:
+	case OHS:
+		if(nn == Z) {
+			nullwarn(l, r);
+			break;
+		}
+		boolgen(n, 1, nn);
+		break;
+
+	case OANDAND:
+	case OOROR:
+		boolgen(n, 1, nn);
+		if(nn == Z)
+			patch(p, pc);
+		break;
+
+	case ONOT:
+		if(nn == Z) {
+			nullwarn(l, Z);
+			break;
+		}
+		boolgen(n, 1, nn);
+		break;
+
+	case OCOMMA:
+		cgen(l, Z);
+		cgen(r, nn);
+		break;
+
+	case OCAST:
+		if(nn == Z) {
+			nullwarn(l, Z);
+			break;
+		}
+		/*
+		 * convert from types l->n->nn
+		 */
+		if(nocast(l->type, n->type) && nocast(n->type, nn->type)) {
+			/* both null, gen l->nn */
+			cgen(l, nn);
+			break;
+		}
+		if(typev[l->type->etype]) {
+			cgen64(n, nn);
+			break;
+		}
+		regalloc(&nod, l, nn);
+		cgen(l, &nod);
+		regalloc(&nod1, n, &nod);
+		gmove(&nod, &nod1);
+		gmove(&nod1, nn);
+		regfree(&nod1);
+		regfree(&nod);
+		break;
+
+	case ODOT:
+		sugen(l, nodrat, l->type->width);
+		if(nn == Z)
+			break;
+		warn(n, "non-interruptable temporary");
+		nod = *nodrat;
+		if(!r || r->op != OCONST) {
+			diag(n, "DOT and no offset");
+			break;
+		}
+		nod.xoffset += (int32)r->vconst;
+		nod.type = n->type;
+		cgen(&nod, nn);
+		break;
+
+	case OCOND:
+		bcgen(l, 1);
+		p1 = p;
+		cgen(r->left, nn);
+		gbranch(OGOTO);
+		patch(p1, pc);
+		p1 = p;
+		cgen(r->right, nn);
+		patch(p1, pc);
+		break;
+
+	case OPOSTINC:
+	case OPOSTDEC:
+		v = 1;
+		if(l->type->etype == TIND)
+			v = l->type->link->width;
+		if(o == OPOSTDEC)
+			v = -v;
+		if(l->op == OBIT)
+			goto bitinc;
+		if(nn == Z)
+			goto pre;
+
+		if(hardleft)
+			reglcgen(&nod, l, Z);
+		else
+			nod = *l;
+
+		if(typefd[n->type->etype])
+			goto fltinc;
+		gmove(&nod, nn);
+		gopcode(OADD, n->type, nodconst(v), &nod);
+		if(hardleft)
+			regfree(&nod);
+		break;
+
+	case OPREINC:
+	case OPREDEC:
+		v = 1;
+		if(l->type->etype == TIND)
+			v = l->type->link->width;
+		if(o == OPREDEC)
+			v = -v;
+		if(l->op == OBIT)
+			goto bitinc;
+
+	pre:
+		if(hardleft)
+			reglcgen(&nod, l, Z);
+		else
+			nod = *l;
+		if(typefd[n->type->etype])
+			goto fltinc;
+		gopcode(OADD, n->type, nodconst(v), &nod);
+		if(nn != Z)
+			gmove(&nod, nn);
+		if(hardleft)
+			regfree(&nod);
+		break;
+
+	fltinc:
+		gmove(&nod, &fregnode0);
+		if(nn != Z && (o == OPOSTINC || o == OPOSTDEC))
+			gins(AFMOVD, &fregnode0, &fregnode0);
+		gins(AFLD1, Z, Z);
+		if(v < 0)
+			fgopcode(OSUB, &fregnode0, &fregnode1, 1, 0);
+		else
+			fgopcode(OADD, &fregnode0, &fregnode1, 1, 0);
+		if(nn != Z && (o == OPREINC || o == OPREDEC))
+			gins(AFMOVD, &fregnode0, &fregnode0);
+		gmove(&fregnode0, &nod);
+		if(hardleft)
+			regfree(&nod);
+		break;
+
+	bitinc:
+		if(nn != Z && (o == OPOSTINC || o == OPOSTDEC)) {
+			bitload(l, &nod, &nod1, &nod2, Z);
+			gmove(&nod, nn);
+			gopcode(OADD, tfield, nodconst(v), &nod);
+			bitstore(l, &nod, &nod1, &nod2, Z);
+			break;
+		}
+		bitload(l, &nod, &nod1, &nod2, nn);
+		gopcode(OADD, tfield, nodconst(v), &nod);
+		bitstore(l, &nod, &nod1, &nod2, nn);
+		break;
+	}
+done:
+	cursafe = curs;
+}
+
+void
+reglcgen(Node *t, Node *n, Node *nn)
+{
+	Node *r;
+	int32 v;
+
+	regialloc(t, n, nn);
+	if(n->op == OIND) {
+		r = n->left;
+		while(r->op == OADD)
+			r = r->right;
+		if(sconst(r)) {
+			v = r->vconst;
+			r->vconst = 0;
+			lcgen(n, t);
+			t->xoffset += v;
+			r->vconst = v;
+			regind(t, n);
+			return;
+		}
+	}
+	lcgen(n, t);
+	regind(t, n);
+}
+
+void
+lcgen(Node *n, Node *nn)
+{
+	Prog *p1;
+	Node nod;
+
+	if(debug['g']) {
+		prtree(nn, "lcgen lhs");
+		prtree(n, "lcgen");
+	}
+	if(n == Z || n->type == T)
+		return;
+	if(nn == Z) {
+		nn = &nod;
+		regalloc(&nod, n, Z);
+	}
+	switch(n->op) {
+	default:
+		if(n->addable < INDEXED) {
+			diag(n, "unknown op in lcgen: %O", n->op);
+			break;
+		}
+		gopcode(OADDR, n->type, n, nn);
+		break;
+
+	case OCOMMA:
+		cgen(n->left, n->left);
+		lcgen(n->right, nn);
+		break;
+
+	case OIND:
+		cgen(n->left, nn);
+		break;
+
+	case OCOND:
+		bcgen(n->left, 1);
+		p1 = p;
+		lcgen(n->right->left, nn);
+		gbranch(OGOTO);
+		patch(p1, pc);
+		p1 = p;
+		lcgen(n->right->right, nn);
+		patch(p1, pc);
+		break;
+	}
+}
+
+void
+bcgen(Node *n, int true)
+{
+
+	if(n->type == T)
+		gbranch(OGOTO);
+	else
+		boolgen(n, true, Z);
+}
+
+void
+boolgen(Node *n, int true, Node *nn)
+{
+	int o;
+	Prog *p1, *p2, *p3;
+	Node *l, *r, nod, nod1;
+	int32 curs;
+
+	if(debug['g']) {
+		prtree(nn, "boolgen lhs");
+		prtree(n, "boolgen");
+	}
+	curs = cursafe;
+	l = n->left;
+	r = n->right;
+	switch(n->op) {
+
+	default:
+		if(typev[n->type->etype]) {
+			testv(n, true);
+			goto com;
+		}
+		o = ONE;
+		if(true)
+			o = OEQ;
+		if(typefd[n->type->etype]) {
+			if(n->addable < INDEXED) {
+				cgen(n, &fregnode0);
+				gins(AFLDZ, Z, Z);
+				fgopcode(o, &fregnode0, &fregnode1, 1, 1);
+			} else {
+				gins(AFLDZ, Z, Z);
+				fgopcode(o, n, &fregnode0, 0, 1);
+			}
+			goto com;
+		}
+		/* bad, 13 is address of external that becomes constant */
+		if(n->addable >= INDEXED && n->addable != 13) {
+			gopcode(o, n->type, n, nodconst(0));
+			goto com;
+		}
+		regalloc(&nod, n, nn);
+		cgen(n, &nod);
+		gopcode(o, n->type, &nod, nodconst(0));
+		regfree(&nod);
+		goto com;
+
+	case OCONST:
+		o = vconst(n);
+		if(!true)
+			o = !o;
+		gbranch(OGOTO);
+		if(o) {
+			p1 = p;
+			gbranch(OGOTO);
+			patch(p1, pc);
+		}
+		goto com;
+
+	case OCOMMA:
+		cgen(l, Z);
+		boolgen(r, true, nn);
+		break;
+
+	case ONOT:
+		boolgen(l, !true, nn);
+		break;
+
+	case OCOND:
+		bcgen(l, 1);
+		p1 = p;
+		bcgen(r->left, true);
+		p2 = p;
+		gbranch(OGOTO);
+		patch(p1, pc);
+		p1 = p;
+		bcgen(r->right, !true);
+		patch(p2, pc);
+		p2 = p;
+		gbranch(OGOTO);
+		patch(p1, pc);
+		patch(p2, pc);
+		goto com;
+
+	case OANDAND:
+		if(!true)
+			goto caseor;
+
+	caseand:
+		bcgen(l, true);
+		p1 = p;
+		bcgen(r, !true);
+		p2 = p;
+		patch(p1, pc);
+		gbranch(OGOTO);
+		patch(p2, pc);
+		goto com;
+
+	case OOROR:
+		if(!true)
+			goto caseand;
+
+	caseor:
+		bcgen(l, !true);
+		p1 = p;
+		bcgen(r, !true);
+		p2 = p;
+		gbranch(OGOTO);
+		patch(p1, pc);
+		patch(p2, pc);
+		goto com;
+
+	case OEQ:
+	case ONE:
+	case OLE:
+	case OLT:
+	case OGE:
+	case OGT:
+	case OHI:
+	case OHS:
+	case OLO:
+	case OLS:
+		o = n->op;
+		if(typev[l->type->etype]) {
+			if(!true)
+				n->op = comrel[relindex(o)];
+			cgen64(n, Z);
+			goto com;
+		}
+		if(true && typefd[l->type->etype] && (o == OEQ || o == ONE)) {
+			// Cannot rewrite !(l == r) into l != r with float64; it breaks NaNs.
+			// Jump around instead.
+			boolgen(n, 0, Z);
+			p1 = p;
+			gbranch(OGOTO);
+			patch(p1, pc);
+			goto com;
+		}
+		if(true)
+			o = comrel[relindex(o)];
+		if(l->complex >= FNX && r->complex >= FNX) {
+			regret(&nod, r, 0, 0);
+			cgen(r, &nod);
+			regsalloc(&nod1, r);
+			gmove(&nod, &nod1);
+			regfree(&nod);
+			nod = *n;
+			nod.right = &nod1;
+			boolgen(&nod, true, nn);
+			break;
+		}
+		if(typefd[l->type->etype]) {
+			if(l->complex >= r->complex) {
+				cgen(l, &fregnode0);
+				if(r->addable < INDEXED) {
+					cgen(r, &fregnode0);
+					o = invrel[relindex(o)];
+					fgopcode(o, &fregnode0, &fregnode1, 1, 1);
+				} else
+					fgopcode(o, r, &fregnode0, 0, 1);
+			} else {
+				o = invrel[relindex(o)];
+				cgen(r, &fregnode0);
+				if(l->addable < INDEXED) {
+					cgen(l, &fregnode0);
+					o = invrel[relindex(o)];
+					fgopcode(o, &fregnode0, &fregnode1, 1, 1);
+				} else
+					fgopcode(o, l, &fregnode0, 0, 1);
+			}
+			switch(o) {
+			case OEQ:
+				// Already emitted AJEQ; want AJEQ and AJPC.
+				p1 = p;
+				gbranch(OGOTO);
+				p2 = p;
+				patch(p1, pc);
+				gins(AJPC, Z, Z);
+				patch(p2, pc);
+				break;
+
+			case ONE:
+				// Already emitted AJNE; want AJNE or AJPS.
+				p1 = p;
+				gins(AJPS, Z, Z);
+				p2 = p;
+				gbranch(OGOTO);
+				p3 = p;
+				patch(p1, pc);
+				patch(p2, pc);
+				gbranch(OGOTO);
+				patch(p3, pc);
+				break;
+			}
+			goto com;
+		}
+		if(l->op == OCONST) {
+			o = invrel[relindex(o)];
+			/* bad, 13 is address of external that becomes constant */
+			if(r->addable < INDEXED || r->addable == 13) {
+				regalloc(&nod, r, nn);
+				cgen(r, &nod);
+				gopcode(o, l->type, &nod, l);
+				regfree(&nod);
+			} else
+				gopcode(o, l->type, r, l);
+			goto com;
+		}
+		if(l->complex >= r->complex) {
+			regalloc(&nod, l, nn);
+			cgen(l, &nod);
+			if(r->addable < INDEXED) {
+				regalloc(&nod1, r, Z);
+				cgen(r, &nod1);
+				gopcode(o, l->type, &nod, &nod1);
+				regfree(&nod1);
+			} else
+				gopcode(o, l->type, &nod, r);
+			regfree(&nod);
+			goto com;
+		}
+		regalloc(&nod, r, nn);
+		cgen(r, &nod);
+		if(l->addable < INDEXED || l->addable == 13) {
+			regalloc(&nod1, l, Z);
+			cgen(l, &nod1);
+			if(typechlp[l->type->etype])
+				gopcode(o, types[TINT], &nod1, &nod);
+			else
+				gopcode(o, l->type, &nod1, &nod);
+			regfree(&nod1);
+		} else
+			gopcode(o, l->type, l, &nod);
+		regfree(&nod);
+
+	com:
+		if(nn != Z) {
+			p1 = p;
+			gmove(nodconst(1L), nn);
+			gbranch(OGOTO);
+			p2 = p;
+			patch(p1, pc);
+			gmove(nodconst(0L), nn);
+			patch(p2, pc);
+		}
+		break;
+	}
+	cursafe = curs;
+}
+
+void
+sugen(Node *n, Node *nn, int32 w)
+{
+	Prog *p1;
+	Node nod0, nod1, nod2, nod3, nod4, *h, *l, *r;
+	Type *t;
+	int c, v, x;
+
+	if(n == Z || n->type == T)
+		return;
+	if(debug['g']) {
+		prtree(nn, "sugen lhs");
+		prtree(n, "sugen");
+	}
+	if(nn == nodrat)
+		if(w > nrathole)
+			nrathole = w;
+	switch(n->op) {
+	case OIND:
+		if(nn == Z) {
+			nullwarn(n->left, Z);
+			break;
+		}
+
+	default:
+		goto copy;
+
+	case OCONST:
+		if(n->type && typev[n->type->etype]) {
+			if(nn == Z) {
+				nullwarn(n->left, Z);
+				break;
+			}
+
+			if(nn->op == OREGPAIR) {
+				loadpair(n, nn);
+				break;
+			}
+			else if(!vaddr(nn, 0)) {
+				t = nn->type;
+				nn->type = types[TLONG];
+				reglcgen(&nod1, nn, Z);
+				nn->type = t;
+
+				gmove(lo64(n), &nod1);
+				nod1.xoffset += SZ_LONG;
+				gmove(hi64(n), &nod1);
+				regfree(&nod1);
+			}
+			else {
+				gins(AMOVL, lo64(n), nn);
+				nn->xoffset += SZ_LONG;
+				gins(AMOVL, hi64(n), nn);
+				nn->xoffset -= SZ_LONG;
+				break;
+			}
+			break;
+		}
+		goto copy;
+
+	case ODOT:
+		l = n->left;
+		sugen(l, nodrat, l->type->width);
+		if(nn == Z)
+			break;
+		warn(n, "non-interruptable temporary");
+		nod1 = *nodrat;
+		r = n->right;
+		if(!r || r->op != OCONST) {
+			diag(n, "DOT and no offset");
+			break;
+		}
+		nod1.xoffset += (int32)r->vconst;
+		nod1.type = n->type;
+		sugen(&nod1, nn, w);
+		break;
+
+	case OSTRUCT:
+		/*
+		 * rewrite so lhs has no fn call
+		 */
+		if(nn != Z && side(nn)) {
+			nod1 = *n;
+			nod1.type = typ(TIND, n->type);
+			regret(&nod2, &nod1, 0, 0);
+			lcgen(nn, &nod2);
+			regsalloc(&nod0, &nod1);
+			cgen(&nod2, &nod0);
+			regfree(&nod2);
+
+			nod1 = *n;
+			nod1.op = OIND;
+			nod1.left = &nod0;
+			nod1.right = Z;
+			nod1.complex = 1;
+
+			sugen(n, &nod1, w);
+			return;
+		}
+
+		r = n->left;
+		for(t = n->type->link; t != T; t = t->down) {
+			l = r;
+			if(r->op == OLIST) {
+				l = r->left;
+				r = r->right;
+			}
+			if(nn == Z) {
+				cgen(l, nn);
+				continue;
+			}
+			/*
+			 * hand craft *(&nn + o) = l
+			 */
+			nod0 = znode;
+			nod0.op = OAS;
+			nod0.type = t;
+			nod0.left = &nod1;
+			nod0.right = nil;
+
+			nod1 = znode;
+			nod1.op = OIND;
+			nod1.type = t;
+			nod1.left = &nod2;
+
+			nod2 = znode;
+			nod2.op = OADD;
+			nod2.type = typ(TIND, t);
+			nod2.left = &nod3;
+			nod2.right = &nod4;
+
+			nod3 = znode;
+			nod3.op = OADDR;
+			nod3.type = nod2.type;
+			nod3.left = nn;
+
+			nod4 = znode;
+			nod4.op = OCONST;
+			nod4.type = nod2.type;
+			nod4.vconst = t->offset;
+
+			ccom(&nod0);
+			acom(&nod0);
+			xcom(&nod0);
+			nod0.addable = 0;
+			nod0.right = l;
+
+			// prtree(&nod0, "hand craft");
+			cgen(&nod0, Z);
+		}
+		break;
+
+	case OAS:
+		if(nn == Z) {
+			if(n->addable < INDEXED)
+				sugen(n->right, n->left, w);
+			break;
+		}
+
+		sugen(n->right, nodrat, w);
+		warn(n, "non-interruptable temporary");
+		sugen(nodrat, n->left, w);
+		sugen(nodrat, nn, w);
+		break;
+
+	case OFUNC:
+		if(!hasdotdotdot(n->left->type)) {
+			cgen(n, Z);
+			if(nn != Z) {
+				curarg -= n->type->width;
+				regret(&nod1, n, n->left->type, 1);
+				if(nn->complex >= FNX) {
+					regsalloc(&nod2, n);
+					cgen(&nod1, &nod2);
+					nod1 = nod2;
+				}
+				cgen(&nod1, nn);
+			}
+			break;
+		}
+		if(nn == Z) {
+			sugen(n, nodrat, w);
+			break;
+		}
+		h = nn;
+		if(nn->op == OREGPAIR) {
+			regsalloc(&nod1, nn);
+			nn = &nod1;
+		}
+		if(nn->op != OIND) {
+			nn = new1(OADDR, nn, Z);
+			nn->type = types[TIND];
+			nn->addable = 0;
+		} else
+			nn = nn->left;
+		n = new(OFUNC, n->left, new(OLIST, nn, n->right));
+		n->type = types[TVOID];
+		n->left->type = types[TVOID];
+		cgen(n, Z);
+		if(h->op == OREGPAIR)
+			loadpair(nn->left, h);
+		break;
+
+	case OCOND:
+		bcgen(n->left, 1);
+		p1 = p;
+		sugen(n->right->left, nn, w);
+		gbranch(OGOTO);
+		patch(p1, pc);
+		p1 = p;
+		sugen(n->right->right, nn, w);
+		patch(p1, pc);
+		break;
+
+	case OCOMMA:
+		cgen(n->left, Z);
+		sugen(n->right, nn, w);
+		break;
+	}
+	return;
+
+copy:
+	if(nn == Z) {
+		switch(n->op) {
+		case OASADD:
+		case OASSUB:
+		case OASAND:
+		case OASOR:
+		case OASXOR:
+
+		case OASMUL:
+		case OASLMUL:
+
+
+		case OASASHL:
+		case OASASHR:
+		case OASLSHR:
+			break;
+
+		case OPOSTINC:
+		case OPOSTDEC:
+		case OPREINC:
+		case OPREDEC:
+			break;
+
+		default:
+			return;
+		}
+	}
+
+	v = w == 8;
+	if(n->complex >= FNX && nn != nil && nn->complex >= FNX) {
+		t = nn->type;
+		nn->type = types[TLONG];
+		regialloc(&nod1, nn, Z);
+		lcgen(nn, &nod1);
+		regsalloc(&nod2, nn);
+		nn->type = t;
+
+		gins(AMOVL, &nod1, &nod2);
+		regfree(&nod1);
+
+		nod2.type = typ(TIND, t);
+
+		nod1 = nod2;
+		nod1.op = OIND;
+		nod1.left = &nod2;
+		nod1.right = Z;
+		nod1.complex = 1;
+		nod1.type = t;
+
+		sugen(n, &nod1, w);
+		return;
+	}
+
+	x = 0;
+	if(v) {
+		if(nn != nil && nn->complex >= FNX) {
+			t = nn->type;
+			nn->type = types[TLONG];
+			regialloc(&nod2, nn, Z);
+			lcgen(nn, &nod2);
+			nn->type = t;
+			
+			nod2.type = typ(TIND, t);
+	
+			nod1 = nod2;
+			nod1.op = OIND;
+			nod1.left = &nod2;
+			nod1.right = Z;
+			nod1.complex = 1;
+			nod1.type = t;
+	
+			sugen(n, &nod1, w);
+			regfree(&nod2);
+			return;
+		}
+			
+		c = cursafe;
+		if(n->left != Z && n->left->complex >= FNX
+		&& n->right != Z && n->right->complex >= FNX) {
+//			warn(n, "toughie");
+			regsalloc(&nod1, n->right);
+			cgen(n->right, &nod1);
+			nod2 = *n;
+			nod2.right = &nod1;
+			cgen(&nod2, nn);
+			cursafe = c;
+			return;
+		}
+		if(cgen64(n, nn)) {
+			cursafe = c;
+			return;
+		}
+		if(n->op == OCOM) {
+			n = n->left;
+			x = 1;
+		}
+	}
+
+	/* botch, need to save in .safe */
+	c = 0;
+	if(n->complex > nn->complex) {
+		t = n->type;
+		n->type = types[TLONG];
+		if(v) {
+			regalloc(&nod0, n, Z);
+			if(!vaddr(n, 0)) {
+				reglcgen(&nod1, n, Z);
+				n->type = t;
+				n = &nod1;
+			}
+			else
+				n->type = t;
+		}
+		else {
+			nodreg(&nod1, n, D_SI);
+			if(reg[D_SI]) {
+				gins(APUSHL, &nod1, Z);
+				c |= 1;
+				reg[D_SI]++;
+			}
+			lcgen(n, &nod1);
+			n->type = t;
+		}
+
+		t = nn->type;
+		nn->type = types[TLONG];
+		if(v) {
+			if(!vaddr(nn, 0)) {
+				reglcgen(&nod2, nn, Z);
+				nn->type = t;
+				nn = &nod2;
+			}
+			else
+				nn->type = t;
+		}
+		else {
+			nodreg(&nod2, nn, D_DI);
+			if(reg[D_DI]) {
+				gins(APUSHL, &nod2, Z);
+				c |= 2;
+				reg[D_DI]++;
+			}
+			lcgen(nn, &nod2);
+			nn->type = t;
+		}
+	} else {
+		t = nn->type;
+		nn->type = types[TLONG];
+		if(v) {
+			regalloc(&nod0, nn, Z);
+			if(!vaddr(nn, 0)) {
+				reglcgen(&nod2, nn, Z);
+				nn->type = t;
+				nn = &nod2;
+			}
+			else
+				nn->type = t;
+		}
+		else {
+			nodreg(&nod2, nn, D_DI);
+			if(reg[D_DI]) {
+				gins(APUSHL, &nod2, Z);
+				c |= 2;
+				reg[D_DI]++;
+			}
+			lcgen(nn, &nod2);
+			nn->type = t;
+		}
+
+		t = n->type;
+		n->type = types[TLONG];
+		if(v) {
+			if(!vaddr(n, 0)) {
+				reglcgen(&nod1, n, Z);
+				n->type = t;
+				n = &nod1;
+			}
+			else
+				n->type = t;
+		}
+		else {
+			nodreg(&nod1, n, D_SI);
+			if(reg[D_SI]) {
+				gins(APUSHL, &nod1, Z);
+				c |= 1;
+				reg[D_SI]++;
+			}
+			lcgen(n, &nod1);
+			n->type = t;
+		}
+	}
+	if(v) {
+		gins(AMOVL, n, &nod0);
+		if(x)
+			gins(ANOTL, Z, &nod0);
+		gins(AMOVL, &nod0, nn);
+		n->xoffset += SZ_LONG;
+		nn->xoffset += SZ_LONG;
+		gins(AMOVL, n, &nod0);
+		if(x)
+			gins(ANOTL, Z, &nod0);
+		gins(AMOVL, &nod0, nn);
+		n->xoffset -= SZ_LONG;
+		nn->xoffset -= SZ_LONG;
+		if(nn == &nod2)
+			regfree(&nod2);
+		if(n == &nod1)
+			regfree(&nod1);
+		regfree(&nod0);
+		return;
+	}
+	nodreg(&nod3, n, D_CX);
+	if(reg[D_CX]) {
+		gins(APUSHL, &nod3, Z);
+		c |= 4;
+		reg[D_CX]++;
+	}
+	gins(AMOVL, nodconst(w/SZ_LONG), &nod3);
+	gins(ACLD, Z, Z);
+	gins(AREP, Z, Z);
+	gins(AMOVSL, Z, Z);
+	if(c & 4) {
+		gins(APOPL, Z, &nod3);
+		reg[D_CX]--;
+	}
+	if(c & 2) {
+		gins(APOPL, Z, &nod2);
+		reg[nod2.reg]--;
+	}
+	if(c & 1) {
+		gins(APOPL, Z, &nod1);
+		reg[nod1.reg]--;
+	}
+}
diff --git a/src/cmd/8c/cgen64.c b/src/cmd/8c/cgen64.c
new file mode 100644
index 0000000..3424f76
--- /dev/null
+++ b/src/cmd/8c/cgen64.c
@@ -0,0 +1,2657 @@
+// Inferno utils/8c/cgen64.c
+// http://code.google.com/p/inferno-os/source/browse/utils/8c/cgen64.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 "gc.h"
+
+void
+zeroregm(Node *n)
+{
+	gins(AMOVL, nodconst(0), n);
+}
+
+/* do we need to load the address of a vlong? */
+int
+vaddr(Node *n, int a)
+{
+	switch(n->op) {
+	case ONAME:
+		if(a)
+			return 1;
+		return !(n->class == CEXTERN || n->class == CGLOBL || n->class == CSTATIC);
+
+	case OCONST:
+	case OREGISTER:
+	case OINDREG:
+		return 1;
+	}
+	return 0;
+}
+
+int32
+hi64v(Node *n)
+{
+	if(align(0, types[TCHAR], Aarg1, nil))	/* isbigendian */
+		return (int32)(n->vconst) & ~0L;
+	else
+		return (int32)((uvlong)n->vconst>>32) & ~0L;
+}
+
+int32
+lo64v(Node *n)
+{
+	if(align(0, types[TCHAR], Aarg1, nil))	/* isbigendian */
+		return (int32)((uvlong)n->vconst>>32) & ~0L;
+	else
+		return (int32)(n->vconst) & ~0L;
+}
+
+Node *
+hi64(Node *n)
+{
+	return nodconst(hi64v(n));
+}
+
+Node *
+lo64(Node *n)
+{
+	return nodconst(lo64v(n));
+}
+
+static Node *
+anonreg(void)
+{
+	Node *n;
+
+	n = new(OREGISTER, Z, Z);
+	n->reg = D_NONE;
+	n->type = types[TLONG];
+	return n;
+}
+
+static Node *
+regpair(Node *n, Node *t)
+{
+	Node *r;
+
+	if(n != Z && n->op == OREGPAIR)
+		return n;
+	r = new(OREGPAIR, anonreg(), anonreg());
+	if(n != Z)
+		r->type = n->type;
+	else
+		r->type = t->type;
+	return r;
+}
+
+static void
+evacaxdx(Node *r)
+{
+	Node nod1, nod2;
+
+	if(r->reg == D_AX || r->reg == D_DX) {
+		reg[D_AX]++;
+		reg[D_DX]++;
+		/*
+		 * this is just an optim that should
+		 * check for spill
+		 */
+		r->type = types[TULONG];
+		regalloc(&nod1, r, Z);
+		nodreg(&nod2, Z, r->reg);
+		gins(AMOVL, &nod2, &nod1);
+		regfree(r);
+		r->reg = nod1.reg;
+		reg[D_AX]--;
+		reg[D_DX]--;
+	}
+}
+
+/* lazy instantiation of register pair */
+static int
+instpair(Node *n, Node *l)
+{
+	int r;
+
+	r = 0;
+	if(n->left->reg == D_NONE) {
+		if(l != Z) {
+			n->left->reg = l->reg;
+			r = 1;
+		}
+		else
+			regalloc(n->left, n->left, Z);
+	}
+	if(n->right->reg == D_NONE)
+		regalloc(n->right, n->right, Z);
+	return r;
+}
+
+static void
+zapreg(Node *n)
+{
+	if(n->reg != D_NONE) {
+		regfree(n);
+		n->reg = D_NONE;
+	}
+}
+
+static void
+freepair(Node *n)
+{
+	regfree(n->left);
+	regfree(n->right);
+}
+
+/* n is not OREGPAIR, nn is */
+void
+loadpair(Node *n, Node *nn)
+{
+	Node nod;
+
+	instpair(nn, Z);
+	if(n->op == OCONST) {
+		gins(AMOVL, lo64(n), nn->left);
+		n->xoffset += SZ_LONG;
+		gins(AMOVL, hi64(n), nn->right);
+		n->xoffset -= SZ_LONG;
+		return;
+	}
+	if(!vaddr(n, 0)) {
+		/* steal the right register for the laddr */
+		nod = regnode;
+		nod.reg = nn->right->reg;
+		lcgen(n, &nod);
+		n = &nod;
+		regind(n, n);
+		n->xoffset = 0;
+	}
+	gins(AMOVL, n, nn->left);
+	n->xoffset += SZ_LONG;
+	gins(AMOVL, n, nn->right);
+	n->xoffset -= SZ_LONG;
+}
+
+/* n is OREGPAIR, nn is not */
+static void
+storepair(Node *n, Node *nn, int f)
+{
+	Node nod;
+
+	if(!vaddr(nn, 0)) {
+		reglcgen(&nod, nn, Z);
+		nn = &nod;
+	}
+	gins(AMOVL, n->left, nn);
+	nn->xoffset += SZ_LONG;
+	gins(AMOVL, n->right, nn);
+	nn->xoffset -= SZ_LONG;
+	if(nn == &nod)
+		regfree(&nod);
+	if(f)
+		freepair(n);
+}
+
+enum
+{
+/* 4 only, see WW */
+	WNONE	= 0,
+	WCONST,
+	WADDR,
+	WHARD,
+};
+
+static int
+whatof(Node *n, int a)
+{
+	if(n->op == OCONST)
+		return WCONST;
+	return !vaddr(n, a) ? WHARD : WADDR;
+}
+
+/* can upgrade an extern to addr for AND */
+static int
+reduxv(Node *n)
+{
+	return lo64v(n) == 0 || hi64v(n) == 0;
+}
+
+int
+cond(int op)
+{
+	switch(op) {
+	case OANDAND:
+	case OOROR:
+	case ONOT:
+		return 1;
+
+	case OEQ:
+	case ONE:
+	case OLE:
+	case OLT:
+	case OGE:
+	case OGT:
+	case OHI:
+	case OHS:
+	case OLO:
+	case OLS:
+		return 1;
+	}
+	return 0;
+}
+
+/*
+ * for a func operand call it and then return
+ * the safe node
+ */
+static Node *
+vfunc(Node *n, Node *nn)
+{
+	Node *t;
+
+	if(n->op != OFUNC)
+		return n;
+	t = new(0, Z, Z);
+	if(nn == Z || nn == nodret)
+		nn = n;
+	regsalloc(t, nn);
+	sugen(n, t, 8);
+	return t;
+}
+
+/* try to steal a reg */
+static int
+getreg(Node **np, Node *t, int r)
+{
+	Node *n, *p;
+
+	n = *np;
+	if(n->reg == r) {
+		p = new(0, Z, Z);
+		regalloc(p, n, Z);
+		gins(AMOVL, n, p);
+		*t = *n;
+		*np = p;
+		return 1;
+	}
+	return 0;
+}
+
+static Node *
+snarfreg(Node *n, Node *t, int r, Node *d, Node *c)
+{
+	if(n == Z || n->op != OREGPAIR || (!getreg(&n->left, t, r) && !getreg(&n->right, t, r))) {
+		if(nodreg(t, Z, r)) {
+			regalloc(c, d, Z);
+			gins(AMOVL, t, c);
+			reg[r]++;
+			return c;
+		}
+		reg[r]++;
+	}
+	return Z;
+}
+
+enum
+{
+	Vstart	= OEND,
+
+	Vgo,
+	Vamv,
+	Vmv,
+	Vzero,
+	Vop,
+	Vopx,
+	Vins,
+	Vins0,
+	Vinsl,
+	Vinsr,
+	Vinsla,
+	Vinsra,
+	Vinsx,
+	Vmul,
+	Vshll,
+	VT,
+	VF,
+	V_l_lo_f,
+	V_l_hi_f,
+	V_l_lo_t,
+	V_l_hi_t,
+	V_l_lo_u,
+	V_l_hi_u,
+	V_r_lo_f,
+	V_r_hi_f,
+	V_r_lo_t,
+	V_r_hi_t,
+	V_r_lo_u,
+	V_r_hi_u,
+	Vspazz,
+	Vend,
+
+	V_T0,
+	V_T1,
+	V_F0,
+	V_F1,
+
+	V_a0,
+	V_a1,
+	V_f0,
+	V_f1,
+
+	V_p0,
+	V_p1,
+	V_p2,
+	V_p3,
+	V_p4,
+
+	V_s0,
+	V_s1,
+	V_s2,
+	V_s3,
+	V_s4,
+
+	C00,
+	C01,
+	C31,
+	C32,
+
+	O_l_lo,
+	O_l_hi,
+	O_r_lo,
+	O_r_hi,
+	O_t_lo,
+	O_t_hi,
+	O_l,
+	O_r,
+	O_l_rp,
+	O_r_rp,
+	O_t_rp,
+	O_r0,
+	O_r1,
+	O_Zop,
+
+	O_a0,
+	O_a1,
+
+	V_C0,
+	V_C1,
+
+	V_S0,
+	V_S1,
+
+	VOPS	= 5,
+	VLEN	= 5,
+	VARGS	= 2,
+
+	S00	= 0,
+	Sc0,
+	Sc1,
+	Sc2,
+	Sac3,
+	Sac4,
+	S10,
+
+	SAgen	= 0,
+	SAclo,
+	SAc32,
+	SAchi,
+	SAdgen,
+	SAdclo,
+	SAdc32,
+	SAdchi,
+
+	B0c	= 0,
+	Bca,
+	Bac,
+
+	T0i	= 0,
+	Tii,
+
+	Bop0	= 0,
+	Bop1,
+};
+
+/*
+ * _testv:
+ * 	CMPL	lo,$0
+ * 	JNE	true
+ * 	CMPL	hi,$0
+ * 	JNE	true
+ * 	GOTO	false
+ * false:
+ * 	GOTO	code
+ * true:
+ * 	GOTO	patchme
+ * code:
+ */
+
+static uchar	testi[][VLEN] =
+{
+	{Vop, ONE, O_l_lo, C00},
+	{V_s0, Vop, ONE, O_l_hi, C00},
+	{V_s1, Vgo, V_s2, Vgo, V_s3},
+	{VF, V_p0, V_p1, VT, V_p2},
+	{Vgo, V_p3},
+	{VT, V_p0, V_p1, VF, V_p2},
+	{Vend},
+};
+
+/* shift left general case */
+static uchar	shll00[][VLEN] =
+{
+	{Vop, OGE, O_r, C32},
+	{V_s0, Vinsl, ASHLL, O_r, O_l_rp},
+	{Vins, ASHLL, O_r, O_l_lo, Vgo},
+	{V_p0, V_s0},
+	{Vins, ASHLL, O_r, O_l_lo},
+	{Vins, AMOVL, O_l_lo, O_l_hi},
+	{Vzero, O_l_lo, V_p0, Vend},
+};
+
+/* shift left rp, const < 32 */
+static uchar	shllc0[][VLEN] =
+{
+	{Vinsl, ASHLL, O_r, O_l_rp},
+	{Vshll, O_r, O_l_lo, Vend},
+};
+
+/* shift left rp, const == 32 */
+static uchar	shllc1[][VLEN] =
+{
+	{Vins, AMOVL, O_l_lo, O_l_hi},
+	{Vzero, O_l_lo, Vend},
+};
+
+/* shift left rp, const > 32 */
+static uchar	shllc2[][VLEN] =
+{
+	{Vshll, O_r, O_l_lo},
+	{Vins, AMOVL, O_l_lo, O_l_hi},
+	{Vzero, O_l_lo, Vend},
+};
+
+/* shift left addr, const == 32 */
+static uchar	shllac3[][VLEN] =
+{
+	{Vins, AMOVL, O_l_lo, O_t_hi},
+	{Vzero, O_t_lo, Vend},
+};
+
+/* shift left addr, const > 32 */
+static uchar	shllac4[][VLEN] =
+{
+	{Vins, AMOVL, O_l_lo, O_t_hi},
+	{Vshll, O_r, O_t_hi},
+	{Vzero, O_t_lo, Vend},
+};
+
+/* shift left of constant */
+static uchar	shll10[][VLEN] =
+{
+	{Vop, OGE, O_r, C32},
+	{V_s0, Vins, AMOVL, O_l_lo, O_t_lo},
+	{Vins, AMOVL, O_l_hi, O_t_hi},
+	{Vinsl, ASHLL, O_r, O_t_rp},
+	{Vins, ASHLL, O_r, O_t_lo, Vgo},
+	{V_p0, V_s0},
+	{Vins, AMOVL, O_l_lo, O_t_hi},
+	{V_l_lo_t, Vins, ASHLL, O_r, O_t_hi},
+	{Vzero, O_t_lo, V_p0, Vend},
+};
+
+static uchar	(*shlltab[])[VLEN] =
+{
+	shll00,
+	shllc0,
+	shllc1,
+	shllc2,
+	shllac3,
+	shllac4,
+	shll10,
+};
+
+/* shift right general case */
+static uchar	shrl00[][VLEN] =
+{
+	{Vop, OGE, O_r, C32},
+	{V_s0, Vinsr, ASHRL, O_r, O_l_rp},
+	{Vins, O_a0, O_r, O_l_hi, Vgo},
+	{V_p0, V_s0},
+	{Vins, O_a0, O_r, O_l_hi},
+	{Vins, AMOVL, O_l_hi, O_l_lo},
+	{V_T1, Vzero, O_l_hi},
+	{V_F1, Vins, ASARL, C31, O_l_hi},
+	{V_p0, Vend},
+};
+
+/* shift right rp, const < 32 */
+static uchar	shrlc0[][VLEN] =
+{
+	{Vinsr, ASHRL, O_r, O_l_rp},
+	{Vins, O_a0, O_r, O_l_hi, Vend},
+};
+
+/* shift right rp, const == 32 */
+static uchar	shrlc1[][VLEN] =
+{
+	{Vins, AMOVL, O_l_hi, O_l_lo},
+	{V_T1, Vzero, O_l_hi},
+	{V_F1, Vins, ASARL, C31, O_l_hi},
+	{Vend},
+};
+
+/* shift right rp, const > 32 */
+static uchar	shrlc2[][VLEN] =
+{
+	{Vins, O_a0, O_r, O_l_hi},
+	{Vins, AMOVL, O_l_hi, O_l_lo},
+	{V_T1, Vzero, O_l_hi},
+	{V_F1, Vins, ASARL, C31, O_l_hi},
+	{Vend},
+};
+
+/* shift right addr, const == 32 */
+static uchar	shrlac3[][VLEN] =
+{
+	{Vins, AMOVL, O_l_hi, O_t_lo},
+	{V_T1, Vzero, O_t_hi},
+	{V_F1, Vins, AMOVL, O_t_lo, O_t_hi},
+	{V_F1, Vins, ASARL, C31, O_t_hi},
+	{Vend},
+};
+
+/* shift right addr, const > 32 */
+static uchar	shrlac4[][VLEN] =
+{
+	{Vins, AMOVL, O_l_hi, O_t_lo},
+	{Vins, O_a0, O_r, O_t_lo},
+	{V_T1, Vzero, O_t_hi},
+	{V_F1, Vins, AMOVL, O_t_lo, O_t_hi},
+	{V_F1, Vins, ASARL, C31, O_t_hi},
+	{Vend},
+};
+
+/* shift right of constant */
+static uchar	shrl10[][VLEN] =
+{
+	{Vop, OGE, O_r, C32},
+	{V_s0, Vins, AMOVL, O_l_lo, O_t_lo},
+	{Vins, AMOVL, O_l_hi, O_t_hi},
+	{Vinsr, ASHRL, O_r, O_t_rp},
+	{Vins, O_a0, O_r, O_t_hi, Vgo},
+	{V_p0, V_s0},
+	{Vins, AMOVL, O_l_hi, O_t_lo},
+	{V_l_hi_t, Vins, O_a0, O_r, O_t_lo},
+	{V_l_hi_u, V_S1},
+	{V_T1, Vzero, O_t_hi, V_p0},
+	{V_F1, Vins, AMOVL, O_t_lo, O_t_hi},
+	{V_F1, Vins, ASARL, C31, O_t_hi},
+	{Vend},
+};
+
+static uchar	(*shrltab[])[VLEN] =
+{
+	shrl00,
+	shrlc0,
+	shrlc1,
+	shrlc2,
+	shrlac3,
+	shrlac4,
+	shrl10,
+};
+
+/* shift asop left general case */
+static uchar	asshllgen[][VLEN] =
+{
+	{V_a0, V_a1},
+	{Vop, OGE, O_r, C32},
+	{V_s0, Vins, AMOVL, O_l_lo, O_r0},
+	{Vins, AMOVL, O_l_hi, O_r1},
+	{Vinsla, ASHLL, O_r, O_r0},
+	{Vins, ASHLL, O_r, O_r0},
+	{Vins, AMOVL, O_r1, O_l_hi},
+	{Vins, AMOVL, O_r0, O_l_lo, Vgo},
+	{V_p0, V_s0},
+	{Vins, AMOVL, O_l_lo, O_r0},
+	{Vzero, O_l_lo},
+	{Vins, ASHLL, O_r, O_r0},
+	{Vins, AMOVL, O_r0, O_l_hi, V_p0},
+	{V_f0, V_f1, Vend},
+};
+
+/* shift asop left, const < 32 */
+static uchar	asshllclo[][VLEN] =
+{
+	{V_a0, V_a1},
+	{Vins, AMOVL, O_l_lo, O_r0},
+	{Vins, AMOVL, O_l_hi, O_r1},
+	{Vinsla, ASHLL, O_r, O_r0},
+	{Vshll, O_r, O_r0},
+	{Vins, AMOVL, O_r1, O_l_hi},
+	{Vins, AMOVL, O_r0, O_l_lo},
+	{V_f0, V_f1, Vend},
+};
+
+/* shift asop left, const == 32 */
+static uchar	asshllc32[][VLEN] =
+{
+	{V_a0},
+	{Vins, AMOVL, O_l_lo, O_r0},
+	{Vzero, O_l_lo},
+	{Vins, AMOVL, O_r0, O_l_hi},
+	{V_f0, Vend},
+};
+
+/* shift asop left, const > 32 */
+static uchar	asshllchi[][VLEN] =
+{
+	{V_a0},
+	{Vins, AMOVL, O_l_lo, O_r0},
+	{Vzero, O_l_lo},
+	{Vshll, O_r, O_r0},
+	{Vins, AMOVL, O_r0, O_l_hi},
+	{V_f0, Vend},
+};
+
+/* shift asop dest left general case */
+static uchar	asdshllgen[][VLEN] =
+{
+	{Vop, OGE, O_r, C32},
+	{V_s0, Vins, AMOVL, O_l_lo, O_t_lo},
+	{Vins, AMOVL, O_l_hi, O_t_hi},
+	{Vinsl, ASHLL, O_r, O_t_rp},
+	{Vins, ASHLL, O_r, O_t_lo},
+	{Vins, AMOVL, O_t_hi, O_l_hi},
+	{Vins, AMOVL, O_t_lo, O_l_lo, Vgo},
+	{V_p0, V_s0},
+	{Vins, AMOVL, O_l_lo, O_t_hi},
+	{Vzero, O_l_lo},
+	{Vins, ASHLL, O_r, O_t_hi},
+	{Vzero, O_t_lo},
+	{Vins, AMOVL, O_t_hi, O_l_hi, V_p0},
+	{Vend},
+};
+
+/* shift asop dest left, const < 32 */
+static uchar	asdshllclo[][VLEN] =
+{
+	{Vins, AMOVL, O_l_lo, O_t_lo},
+	{Vins, AMOVL, O_l_hi, O_t_hi},
+	{Vinsl, ASHLL, O_r, O_t_rp},
+	{Vshll, O_r, O_t_lo},
+	{Vins, AMOVL, O_t_hi, O_l_hi},
+	{Vins, AMOVL, O_t_lo, O_l_lo},
+	{Vend},
+};
+
+/* shift asop dest left, const == 32 */
+static uchar	asdshllc32[][VLEN] =
+{
+	{Vins, AMOVL, O_l_lo, O_t_hi},
+	{Vzero, O_t_lo},
+	{Vins, AMOVL, O_t_hi, O_l_hi},
+	{Vins, AMOVL, O_t_lo, O_l_lo},
+	{Vend},
+};
+
+/* shift asop dest, const > 32 */
+static uchar	asdshllchi[][VLEN] =
+{
+	{Vins, AMOVL, O_l_lo, O_t_hi},
+	{Vzero, O_t_lo},
+	{Vshll, O_r, O_t_hi},
+	{Vins, AMOVL, O_t_lo, O_l_lo},
+	{Vins, AMOVL, O_t_hi, O_l_hi},
+	{Vend},
+};
+
+static uchar	(*asshlltab[])[VLEN] =
+{
+	asshllgen,
+	asshllclo,
+	asshllc32,
+	asshllchi,
+	asdshllgen,
+	asdshllclo,
+	asdshllc32,
+	asdshllchi,
+};
+
+/* shift asop right general case */
+static uchar	asshrlgen[][VLEN] =
+{
+	{V_a0, V_a1},
+	{Vop, OGE, O_r, C32},
+	{V_s0, Vins, AMOVL, O_l_lo, O_r0},
+	{Vins, AMOVL, O_l_hi, O_r1},
+	{Vinsra, ASHRL, O_r, O_r0},
+	{Vinsx, Bop0, O_r, O_r1},
+	{Vins, AMOVL, O_r0, O_l_lo},
+	{Vins, AMOVL, O_r1, O_l_hi, Vgo},
+	{V_p0, V_s0},
+	{Vins, AMOVL, O_l_hi, O_r0},
+	{Vinsx, Bop0, O_r, O_r0},
+	{V_T1, Vzero, O_l_hi},
+	{Vins, AMOVL, O_r0, O_l_lo},
+	{V_F1, Vins, ASARL, C31, O_r0},
+	{V_F1, Vins, AMOVL, O_r0, O_l_hi},
+	{V_p0, V_f0, V_f1, Vend},
+};
+
+/* shift asop right, const < 32 */
+static uchar	asshrlclo[][VLEN] =
+{
+	{V_a0, V_a1},
+	{Vins, AMOVL, O_l_lo, O_r0},
+	{Vins, AMOVL, O_l_hi, O_r1},
+	{Vinsra, ASHRL, O_r, O_r0},
+	{Vinsx, Bop0, O_r, O_r1},
+	{Vins, AMOVL, O_r0, O_l_lo},
+	{Vins, AMOVL, O_r1, O_l_hi},
+	{V_f0, V_f1, Vend},
+};
+
+/* shift asop right, const == 32 */
+static uchar	asshrlc32[][VLEN] =
+{
+	{V_a0},
+	{Vins, AMOVL, O_l_hi, O_r0},
+	{V_T1, Vzero, O_l_hi},
+	{Vins, AMOVL, O_r0, O_l_lo},
+	{V_F1, Vins, ASARL, C31, O_r0},
+	{V_F1, Vins, AMOVL, O_r0, O_l_hi},
+	{V_f0, Vend},
+};
+
+/* shift asop right, const > 32 */
+static uchar	asshrlchi[][VLEN] =
+{
+	{V_a0},
+	{Vins, AMOVL, O_l_hi, O_r0},
+	{V_T1, Vzero, O_l_hi},
+	{Vinsx, Bop0, O_r, O_r0},
+	{Vins, AMOVL, O_r0, O_l_lo},
+	{V_F1, Vins, ASARL, C31, O_r0},
+	{V_F1, Vins, AMOVL, O_r0, O_l_hi},
+	{V_f0, Vend},
+};
+
+/* shift asop dest right general case */
+static uchar	asdshrlgen[][VLEN] =
+{
+	{Vop, OGE, O_r, C32},
+	{V_s0, Vins, AMOVL, O_l_lo, O_t_lo},
+	{Vins, AMOVL, O_l_hi, O_t_hi},
+	{Vinsr, ASHRL, O_r, O_t_rp},
+	{Vinsx, Bop0, O_r, O_t_hi},
+	{Vins, AMOVL, O_t_lo, O_l_lo},
+	{Vins, AMOVL, O_t_hi, O_l_hi, Vgo},
+	{V_p0, V_s0},
+	{Vins, AMOVL, O_l_hi, O_t_lo},
+	{V_T1, Vzero, O_t_hi},
+	{Vinsx, Bop0, O_r, O_t_lo},
+	{V_F1, Vins, AMOVL, O_t_lo, O_t_hi},
+	{V_F1, Vins, ASARL, C31, O_t_hi},
+	{Vins, AMOVL, O_t_hi, O_l_hi, V_p0},
+	{Vend},
+};
+
+/* shift asop dest right, const < 32 */
+static uchar	asdshrlclo[][VLEN] =
+{
+	{Vins, AMOVL, O_l_lo, O_t_lo},
+	{Vins, AMOVL, O_l_hi, O_t_hi},
+	{Vinsr, ASHRL, O_r, O_t_rp},
+	{Vinsx, Bop0, O_r, O_t_hi},
+	{Vins, AMOVL, O_t_lo, O_l_lo},
+	{Vins, AMOVL, O_t_hi, O_l_hi},
+	{Vend},
+};
+
+/* shift asop dest right, const == 32 */
+static uchar	asdshrlc32[][VLEN] =
+{
+	{Vins, AMOVL, O_l_hi, O_t_lo},
+	{V_T1, Vzero, O_t_hi},
+	{V_F1, Vins, AMOVL, O_t_lo, O_t_hi},
+	{V_F1, Vins, ASARL, C31, O_t_hi},
+	{Vins, AMOVL, O_t_lo, O_l_lo},
+	{Vins, AMOVL, O_t_hi, O_l_hi},
+	{Vend},
+};
+
+/* shift asop dest, const > 32 */
+static uchar	asdshrlchi[][VLEN] =
+{
+	{Vins, AMOVL, O_l_hi, O_t_lo},
+	{V_T1, Vzero, O_t_hi},
+	{Vinsx, Bop0, O_r, O_t_lo},
+	{V_T1, Vins, AMOVL, O_t_hi, O_l_hi},
+	{V_T1, Vins, AMOVL, O_t_lo, O_l_lo},
+	{V_F1, Vins, AMOVL, O_t_lo, O_t_hi},
+	{V_F1, Vins, ASARL, C31, O_t_hi},
+	{V_F1, Vins, AMOVL, O_t_lo, O_l_lo},
+	{V_F1, Vins, AMOVL, O_t_hi, O_l_hi},
+	{Vend},
+};
+
+static uchar	(*asshrltab[])[VLEN] =
+{
+	asshrlgen,
+	asshrlclo,
+	asshrlc32,
+	asshrlchi,
+	asdshrlgen,
+	asdshrlclo,
+	asdshrlc32,
+	asdshrlchi,
+};
+
+static uchar	shrlargs[]	= { ASHRL, 1 };
+static uchar	sarlargs[]	= { ASARL, 0 };
+
+/* ++ -- */
+static uchar	incdec[][VLEN] =
+{
+	{Vinsx, Bop0, C01, O_l_lo},
+	{Vinsx, Bop1, C00, O_l_hi, Vend},
+};
+
+/* ++ -- *p */
+static uchar	incdecpre[][VLEN] =
+{
+	{Vins, AMOVL, O_l_lo, O_t_lo},
+	{Vins, AMOVL, O_l_hi, O_t_hi},
+	{Vinsx, Bop0, C01, O_t_lo},
+	{Vinsx, Bop1, C00, O_t_hi},
+	{Vins, AMOVL, O_t_lo, O_l_lo},
+	{Vins, AMOVL, O_t_hi, O_l_hi, Vend},
+};
+
+/* *p ++ -- */
+static uchar	incdecpost[][VLEN] =
+{
+	{Vins, AMOVL, O_l_lo, O_t_lo},
+	{Vins, AMOVL, O_l_hi, O_t_hi},
+	{Vinsx, Bop0, C01, O_l_lo},
+	{Vinsx, Bop1, C00, O_l_hi, Vend},
+};
+
+/* binop rp, rp */
+static uchar	binop00[][VLEN] =
+{
+	{Vinsx, Bop0, O_r_lo, O_l_lo},
+	{Vinsx, Bop1, O_r_hi, O_l_hi, Vend},
+	{Vend},
+};
+
+/* binop rp, addr */
+static uchar	binoptmp[][VLEN] =
+{
+	{V_a0, Vins, AMOVL, O_r_lo, O_r0},
+	{Vinsx, Bop0, O_r0, O_l_lo},
+	{Vins, AMOVL, O_r_hi, O_r0},
+	{Vinsx, Bop1, O_r0, O_l_hi},
+	{V_f0, Vend},
+};
+
+/* binop t = *a op *b */
+static uchar	binop11[][VLEN] =
+{
+	{Vins, AMOVL, O_l_lo, O_t_lo},
+	{Vinsx, Bop0, O_r_lo, O_t_lo},
+	{Vins, AMOVL, O_l_hi, O_t_hi},
+	{Vinsx, Bop1, O_r_hi, O_t_hi, Vend},
+};
+
+/* binop t = rp +- c */
+static uchar	add0c[][VLEN] =
+{
+	{V_r_lo_t, Vinsx, Bop0, O_r_lo, O_l_lo},
+	{V_r_lo_f, Vamv, Bop0, Bop1},
+	{Vinsx, Bop1, O_r_hi, O_l_hi},
+	{Vend},
+};
+
+/* binop t = rp & c */
+static uchar	and0c[][VLEN] =
+{
+	{V_r_lo_t, Vinsx, Bop0, O_r_lo, O_l_lo},
+	{V_r_lo_f, Vins, AMOVL, C00, O_l_lo},
+	{V_r_hi_t, Vinsx, Bop1, O_r_hi, O_l_hi},
+	{V_r_hi_f, Vins, AMOVL, C00, O_l_hi},
+	{Vend},
+};
+
+/* binop t = rp | c */
+static uchar	or0c[][VLEN] =
+{
+	{V_r_lo_t, Vinsx, Bop0, O_r_lo, O_l_lo},
+	{V_r_hi_t, Vinsx, Bop1, O_r_hi, O_l_hi},
+	{Vend},
+};
+
+/* binop t = c - rp */
+static uchar	sub10[][VLEN] =
+{
+	{V_a0, Vins, AMOVL, O_l_lo, O_r0},
+	{Vinsx, Bop0, O_r_lo, O_r0},
+	{Vins, AMOVL, O_l_hi, O_r_lo},
+	{Vinsx, Bop1, O_r_hi, O_r_lo},
+	{Vspazz, V_f0, Vend},
+};
+
+/* binop t = c + *b */
+static uchar	addca[][VLEN] =
+{
+	{Vins, AMOVL, O_r_lo, O_t_lo},
+	{V_l_lo_t, Vinsx, Bop0, O_l_lo, O_t_lo},
+	{V_l_lo_f, Vamv, Bop0, Bop1},
+	{Vins, AMOVL, O_r_hi, O_t_hi},
+	{Vinsx, Bop1, O_l_hi, O_t_hi},
+	{Vend},
+};
+
+/* binop t = c & *b */
+static uchar	andca[][VLEN] =
+{
+	{V_l_lo_t, Vins, AMOVL, O_r_lo, O_t_lo},
+	{V_l_lo_t, Vinsx, Bop0, O_l_lo, O_t_lo},
+	{V_l_lo_f, Vzero, O_t_lo},
+	{V_l_hi_t, Vins, AMOVL, O_r_hi, O_t_hi},
+	{V_l_hi_t, Vinsx, Bop1, O_l_hi, O_t_hi},
+	{V_l_hi_f, Vzero, O_t_hi},
+	{Vend},
+};
+
+/* binop t = c | *b */
+static uchar	orca[][VLEN] =
+{
+	{Vins, AMOVL, O_r_lo, O_t_lo},
+	{V_l_lo_t, Vinsx, Bop0, O_l_lo, O_t_lo},
+	{Vins, AMOVL, O_r_hi, O_t_hi},
+	{V_l_hi_t, Vinsx, Bop1, O_l_hi, O_t_hi},
+	{Vend},
+};
+
+/* binop t = c - *b */
+static uchar	subca[][VLEN] =
+{
+	{Vins, AMOVL, O_l_lo, O_t_lo},
+	{Vins, AMOVL, O_l_hi, O_t_hi},
+	{Vinsx, Bop0, O_r_lo, O_t_lo},
+	{Vinsx, Bop1, O_r_hi, O_t_hi},
+	{Vend},
+};
+
+/* binop t = *a +- c */
+static uchar	addac[][VLEN] =
+{
+	{Vins, AMOVL, O_l_lo, O_t_lo},
+	{V_r_lo_t, Vinsx, Bop0, O_r_lo, O_t_lo},
+	{V_r_lo_f, Vamv, Bop0, Bop1},
+	{Vins, AMOVL, O_l_hi, O_t_hi},
+	{Vinsx, Bop1, O_r_hi, O_t_hi},
+	{Vend},
+};
+
+/* binop t = *a | c */
+static uchar	orac[][VLEN] =
+{
+	{Vins, AMOVL, O_l_lo, O_t_lo},
+	{V_r_lo_t, Vinsx, Bop0, O_r_lo, O_t_lo},
+	{Vins, AMOVL, O_l_hi, O_t_hi},
+	{V_r_hi_t, Vinsx, Bop1, O_r_hi, O_t_hi},
+	{Vend},
+};
+
+/* binop t = *a & c */
+static uchar	andac[][VLEN] =
+{
+	{V_r_lo_t, Vins, AMOVL, O_l_lo, O_t_lo},
+	{V_r_lo_t, Vinsx, Bop0, O_r_lo, O_t_lo},
+	{V_r_lo_f, Vzero, O_t_lo},
+	{V_r_hi_t, Vins, AMOVL, O_l_hi, O_t_hi},
+	{V_r_hi_t, Vinsx, Bop0, O_r_hi, O_t_hi},
+	{V_r_hi_f, Vzero, O_t_hi},
+	{Vend},
+};
+
+static uchar	ADDargs[]	= { AADDL, AADCL };
+static uchar	ANDargs[]	= { AANDL, AANDL };
+static uchar	ORargs[]	= { AORL, AORL };
+static uchar	SUBargs[]	= { ASUBL, ASBBL };
+static uchar	XORargs[]	= { AXORL, AXORL };
+
+static uchar	(*ADDtab[])[VLEN] =
+{
+	add0c, addca, addac,
+};
+
+static uchar	(*ANDtab[])[VLEN] =
+{
+	and0c, andca, andac,
+};
+
+static uchar	(*ORtab[])[VLEN] =
+{
+	or0c, orca, orac,
+};
+
+static uchar	(*SUBtab[])[VLEN] =
+{
+	add0c, subca, addac,
+};
+
+/* mul of const32 */
+static uchar	mulc32[][VLEN] =
+{
+	{V_a0, Vop, ONE, O_l_hi, C00},
+	{V_s0, Vins, AMOVL, O_r_lo, O_r0},
+	{Vins, AMULL, O_r0, O_Zop},
+	{Vgo, V_p0, V_s0},
+	{Vins, AMOVL, O_l_hi, O_r0},
+	{Vmul, O_r_lo, O_r0},
+	{Vins, AMOVL, O_r_lo, O_l_hi},
+	{Vins, AMULL, O_l_hi, O_Zop},
+	{Vins, AADDL, O_r0, O_l_hi},
+	{V_f0, V_p0, Vend},
+};
+
+/* mul of const64 */
+static uchar	mulc64[][VLEN] =
+{
+	{V_a0, Vins, AMOVL, O_r_hi, O_r0},
+	{Vop, OOR, O_l_hi, O_r0},
+	{Vop, ONE, O_r0, C00},
+	{V_s0, Vins, AMOVL, O_r_lo, O_r0},
+	{Vins, AMULL, O_r0, O_Zop},
+	{Vgo, V_p0, V_s0},
+	{Vmul, O_r_lo, O_l_hi},
+	{Vins, AMOVL, O_l_lo, O_r0},
+	{Vmul, O_r_hi, O_r0},
+	{Vins, AADDL, O_l_hi, O_r0},
+	{Vins, AMOVL, O_r_lo, O_l_hi},
+	{Vins, AMULL, O_l_hi, O_Zop},
+	{Vins, AADDL, O_r0, O_l_hi},
+	{V_f0, V_p0, Vend},
+};
+
+/* mul general */
+static uchar	mull[][VLEN] =
+{
+	{V_a0, Vins, AMOVL, O_r_hi, O_r0},
+	{Vop, OOR, O_l_hi, O_r0},
+	{Vop, ONE, O_r0, C00},
+	{V_s0, Vins, AMOVL, O_r_lo, O_r0},
+	{Vins, AMULL, O_r0, O_Zop},
+	{Vgo, V_p0, V_s0},
+	{Vins, AIMULL, O_r_lo, O_l_hi},
+	{Vins, AMOVL, O_l_lo, O_r0},
+	{Vins, AIMULL, O_r_hi, O_r0},
+	{Vins, AADDL, O_l_hi, O_r0},
+	{Vins, AMOVL, O_r_lo, O_l_hi},
+	{Vins, AMULL, O_l_hi, O_Zop},
+	{Vins, AADDL, O_r0, O_l_hi},
+	{V_f0, V_p0, Vend},
+};
+
+/* cast rp l to rp t */
+static uchar	castrp[][VLEN] =
+{
+	{Vmv, O_l, O_t_lo},
+	{VT, Vins, AMOVL, O_t_lo, O_t_hi},
+	{VT, Vins, ASARL, C31, O_t_hi},
+	{VF, Vzero, O_t_hi},
+	{Vend},
+};
+
+/* cast rp l to addr t */
+static uchar	castrpa[][VLEN] =
+{
+	{VT, V_a0, Vmv, O_l, O_r0},
+	{VT, Vins, AMOVL, O_r0, O_t_lo},
+	{VT, Vins, ASARL, C31, O_r0},
+	{VT, Vins, AMOVL, O_r0, O_t_hi},
+	{VT, V_f0},
+	{VF, Vmv, O_l, O_t_lo},
+	{VF, Vzero, O_t_hi},
+	{Vend},
+};
+
+static uchar	netab0i[][VLEN] =
+{
+	{Vop, ONE, O_l_lo, O_r_lo},
+	{V_s0, Vop, ONE, O_l_hi, O_r_hi},
+	{V_s1, Vgo, V_s2, Vgo, V_s3},
+	{VF, V_p0, V_p1, VT, V_p2},
+	{Vgo, V_p3},
+	{VT, V_p0, V_p1, VF, V_p2},
+	{Vend},
+};
+
+static uchar	netabii[][VLEN] =
+{
+	{V_a0, Vins, AMOVL, O_l_lo, O_r0},
+	{Vop, ONE, O_r0, O_r_lo},
+	{V_s0, Vins, AMOVL, O_l_hi, O_r0},
+	{Vop, ONE, O_r0, O_r_hi},
+	{V_s1, Vgo, V_s2, Vgo, V_s3},
+	{VF, V_p0, V_p1, VT, V_p2},
+	{Vgo, V_p3},
+	{VT, V_p0, V_p1, VF, V_p2},
+	{V_f0, Vend},
+};
+
+static uchar	cmptab0i[][VLEN] =
+{
+	{Vopx, Bop0, O_l_hi, O_r_hi},
+	{V_s0, Vins0, AJNE},
+	{V_s1, Vopx, Bop1, O_l_lo, O_r_lo},
+	{V_s2, Vgo, V_s3, Vgo, V_s4},
+	{VT, V_p1, V_p3},
+	{VF, V_p0, V_p2},
+	{Vgo, V_p4},
+	{VT, V_p0, V_p2},
+	{VF, V_p1, V_p3},
+	{Vend},
+};
+
+static uchar	cmptabii[][VLEN] =
+{
+	{V_a0, Vins, AMOVL, O_l_hi, O_r0},
+	{Vopx, Bop0, O_r0, O_r_hi},
+	{V_s0, Vins0, AJNE},
+	{V_s1, Vins, AMOVL, O_l_lo, O_r0},
+	{Vopx, Bop1, O_r0, O_r_lo},
+	{V_s2, Vgo, V_s3, Vgo, V_s4},
+	{VT, V_p1, V_p3},
+	{VF, V_p0, V_p2},
+	{Vgo, V_p4},
+	{VT, V_p0, V_p2},
+	{VF, V_p1, V_p3},
+	{V_f0, Vend},
+};
+
+static uchar	(*NEtab[])[VLEN] =
+{
+	netab0i, netabii,
+};
+
+static uchar	(*cmptab[])[VLEN] =
+{
+	cmptab0i, cmptabii,
+};
+
+static uchar	GEargs[]	= { OGT, OHS };
+static uchar	GTargs[]	= { OGT, OHI };
+static uchar	HIargs[]	= { OHI, OHI };
+static uchar	HSargs[]	= { OHI, OHS };
+
+/* Big Generator */
+static void
+biggen(Node *l, Node *r, Node *t, int true, uchar code[][VLEN], uchar *a)
+{
+	int i, j, g, oc, op, lo, ro, to, xo, *xp;
+	Type *lt;
+	Prog *pr[VOPS];
+	Node *ot, *tl, *tr, tmps[2];
+	uchar *c, (*cp)[VLEN], args[VARGS];
+
+	if(a != nil)
+		memmove(args, a, VARGS);
+//print("biggen %d %d %d\n", args[0], args[1], args[2]);
+//if(l) prtree(l, "l");
+//if(r) prtree(r, "r");
+//if(t) prtree(t, "t");
+	lo = ro = to = 0;
+	cp = code;
+
+	for (;;) {
+		c = *cp++;
+		g = 1;
+		i = 0;
+//print("code %d %d %d %d %d\n", c[0], c[1], c[2], c[3], c[4]);
+		for(;;) {
+			switch(op = c[i]) {
+			case Vgo:
+				if(g)
+					gbranch(OGOTO);
+				i++;
+				break;
+
+			case Vamv:
+				i += 3;
+				if(i > VLEN) {
+					diag(l, "bad Vop");
+					return;
+				}
+				if(g)
+					args[c[i - 1]] = args[c[i - 2]];
+				break;
+
+			case Vzero:
+				i += 2;
+				if(i > VLEN) {
+					diag(l, "bad Vop");
+					return;
+				}
+				j = i - 1;
+				goto op;
+
+			case Vspazz:	// nasty hack to save a reg in SUB
+//print("spazz\n");
+				if(g) {
+//print("hi %R lo %R t %R\n", r->right->reg, r->left->reg, tmps[0].reg);
+					ot = r->right;
+					r->right = r->left;
+					tl = new(0, Z, Z);
+					*tl = tmps[0];
+					r->left = tl;
+					tmps[0] = *ot;
+//print("hi %R lo %R t %R\n", r->right->reg, r->left->reg, tmps[0].reg);
+				}
+				i++;
+				break;
+
+			case Vmv:
+			case Vmul:
+			case Vshll:
+				i += 3;
+				if(i > VLEN) {
+					diag(l, "bad Vop");
+					return;
+				}
+				j = i - 2;
+				goto op;
+
+			case Vins0:
+				i += 2;
+				if(i > VLEN) {
+					diag(l, "bad Vop");
+					return;
+				}
+				gins(c[i - 1], Z, Z);
+				break;
+
+			case Vop:
+			case Vopx:
+			case Vins:
+			case Vinsl:
+			case Vinsr:
+			case Vinsla:
+			case Vinsra:
+			case Vinsx:
+				i += 4;
+				if(i > VLEN) {
+					diag(l, "bad Vop");
+					return;
+				}
+				j = i - 2;
+				goto op;
+
+			op:
+				if(!g)
+					break;
+				tl = Z;
+				tr = Z;
+				for(; j < i; j++) {
+					switch(c[j]) {
+					case C00:
+						ot = nodconst(0);
+						break;
+					case C01:
+						ot = nodconst(1);
+						break;
+					case C31:
+						ot = nodconst(31);
+						break;
+					case C32:
+						ot = nodconst(32);
+						break;
+
+					case O_l:
+					case O_l_lo:
+						ot = l; xp = &lo; xo = 0;
+						goto op0;
+					case O_l_hi:
+						ot = l; xp = &lo; xo = SZ_LONG;
+						goto op0;
+					case O_r:
+					case O_r_lo:
+						ot = r; xp = &ro; xo = 0;
+						goto op0;
+					case O_r_hi:
+						ot = r; xp = &ro; xo = SZ_LONG;
+						goto op0;
+					case O_t_lo:
+						ot = t; xp = &to; xo = 0;
+						goto op0;
+					case O_t_hi:
+						ot = t; xp = &to; xo = SZ_LONG;
+						goto op0;
+					case O_l_rp:
+						ot = l;
+						break;
+					case O_r_rp:
+						ot = r;
+						break;
+					case O_t_rp:
+						ot = t;
+						break;
+					case O_r0:
+					case O_r1:
+						ot = &tmps[c[j] - O_r0];
+						break;
+					case O_Zop:
+						ot = Z;
+						break;
+
+					op0:
+						switch(ot->op) {
+						case OCONST:
+							if(xo)
+								ot = hi64(ot);
+							else
+								ot = lo64(ot);
+							break;
+						case OREGPAIR:
+							if(xo)
+								ot = ot->right;
+							else
+								ot = ot->left;
+							break;
+						case OREGISTER:
+							break;
+						default:
+							if(xo != *xp) {
+								ot->xoffset += xo - *xp;
+								*xp = xo;
+							}
+						}
+						break;
+					
+					default:
+						diag(l, "bad V_lop");
+						return;
+					}
+					if(tl == nil)
+						tl = ot;
+					else
+						tr = ot;
+				}
+				if(op == Vzero) {
+					zeroregm(tl);
+					break;
+				}
+				oc = c[i - 3];
+				if(op == Vinsx || op == Vopx) {
+//print("%d -> %d\n", oc, args[oc]);
+					oc = args[oc];
+				}
+				else {
+					switch(oc) {
+					case O_a0:
+					case O_a1:
+						oc = args[oc - O_a0];
+						break;
+					}
+				}
+				switch(op) {
+				case Vmul:
+					mulgen(tr->type, tl, tr);
+					break;
+				case Vmv:
+					gmove(tl, tr);
+					break;
+				case Vshll:
+					shiftit(tr->type, tl, tr);
+					break;
+				case Vop:
+				case Vopx:
+					gopcode(oc, types[TULONG], tl, tr);
+					break;
+				case Vins:
+				case Vinsx:
+					gins(oc, tl, tr);
+					break;
+				case Vinsl:
+					gins(oc, tl, tr->right);
+					p->from.index = tr->left->reg;
+					break;
+				case Vinsr:
+					gins(oc, tl, tr->left);
+					p->from.index = tr->right->reg;
+					break;
+				case Vinsla:
+					gins(oc, tl, tr + 1);
+					p->from.index = tr->reg;
+					break;
+				case Vinsra:
+					gins(oc, tl, tr);
+					p->from.index = (tr + 1)->reg;
+					break;
+				}
+				break;
+
+			case VT:
+				g = true;
+				i++;
+				break;
+			case VF:
+				g = !true;
+				i++;
+				break;
+
+			case V_T0: case V_T1:
+				g = args[op - V_T0];
+				i++;
+				break;
+
+			case V_F0: case V_F1:
+				g = !args[op - V_F0];
+				i++;
+				break;
+
+			case V_C0: case V_C1:
+				if(g)
+					args[op - V_C0] = 0;
+				i++;
+				break;
+
+			case V_S0: case V_S1:
+				if(g)
+					args[op - V_S0] = 1;
+				i++;
+				break;
+
+			case V_l_lo_f:
+				g = lo64v(l) == 0;
+				i++;
+				break;
+			case V_l_hi_f:
+				g = hi64v(l) == 0;
+				i++;
+				break;
+			case V_l_lo_t:
+				g = lo64v(l) != 0;
+				i++;
+				break;
+			case V_l_hi_t:
+				g = hi64v(l) != 0;
+				i++;
+				break;
+			case V_l_lo_u:
+				g = lo64v(l) >= 0;
+				i++;
+				break;
+			case V_l_hi_u:
+				g = hi64v(l) >= 0;
+				i++;
+				break;
+			case V_r_lo_f:
+				g = lo64v(r) == 0;
+				i++;
+				break;
+			case V_r_hi_f:
+				g = hi64v(r) == 0;
+				i++;
+				break;
+			case V_r_lo_t:
+				g = lo64v(r) != 0;
+				i++;
+				break;
+			case V_r_hi_t:
+				g = hi64v(r) != 0;
+				i++;
+				break;
+			case V_r_lo_u:
+				g = lo64v(r) >= 0;
+				i++;
+				break;
+			case V_r_hi_u:
+				g = hi64v(r) >= 0;
+				i++;
+				break;
+
+			case Vend:
+				goto out;
+
+			case V_a0: case V_a1:
+				if(g) {
+					lt = l->type;
+					l->type = types[TULONG];
+					regalloc(&tmps[op - V_a0], l, Z);
+					l->type = lt;
+				}
+				i++;
+				break;
+
+			case V_f0: case V_f1:
+				if(g)
+					regfree(&tmps[op - V_f0]);
+				i++;
+				break;
+
+			case V_p0: case V_p1: case V_p2: case V_p3: case V_p4:
+				if(g)
+					patch(pr[op - V_p0], pc);
+				i++;
+				break;
+
+			case V_s0: case V_s1: case V_s2: case V_s3: case V_s4:
+				if(g)
+					pr[op - V_s0] = p;
+				i++;
+				break;
+
+			default:
+				diag(l, "bad biggen: %d", op);
+				return;
+			}
+			if(i == VLEN || c[i] == 0)
+				break;
+		}
+	}
+out:
+	if(lo)
+		l->xoffset -= lo;
+	if(ro)
+		r->xoffset -= ro;
+	if(to)
+		t->xoffset -= to;
+}
+
+int
+cgen64(Node *n, Node *nn)
+{
+	Type *dt;
+	uchar *args, (*cp)[VLEN], (**optab)[VLEN];
+	int li, ri, lri, dr, si, m, op, sh, cmp, true;
+	Node *c, *d, *l, *r, *t, *s, nod1, nod2, nod3, nod4, nod5;
+
+	if(debug['g']) {
+		prtree(nn, "cgen64 lhs");
+		prtree(n, "cgen64");
+		print("AX = %d\n", reg[D_AX]);
+	}
+	cmp = 0;
+	sh = 0;
+
+	switch(n->op) {
+	case ONEG:
+		d = regpair(nn, n);
+		sugen(n->left, d, 8);
+		gins(ANOTL, Z, d->right);
+		gins(ANEGL, Z, d->left);
+		gins(ASBBL, nodconst(-1), d->right);
+		break;
+
+	case OCOM:
+		if(!vaddr(n->left, 0) || !vaddr(nn, 0))
+			d = regpair(nn, n);
+		else
+			return 0;
+		sugen(n->left, d, 8);
+		gins(ANOTL, Z, d->left);
+		gins(ANOTL, Z, d->right);
+		break;
+
+	case OADD:
+		optab = ADDtab;
+		args = ADDargs;
+		goto twoop;
+	case OAND:
+		optab = ANDtab;
+		args = ANDargs;
+		goto twoop;
+	case OOR:
+		optab = ORtab;
+		args = ORargs;
+		goto twoop;
+	case OSUB:
+		optab = SUBtab;
+		args = SUBargs;
+		goto twoop;
+	case OXOR:
+		optab = ORtab;
+		args = XORargs;
+		goto twoop;
+	case OASHL:
+		sh = 1;
+		args = nil;
+		optab = shlltab;
+		goto twoop;
+	case OLSHR:
+		sh = 1;
+		args = shrlargs;
+		optab = shrltab;
+		goto twoop;
+	case OASHR:
+		sh = 1;
+		args = sarlargs;
+		optab = shrltab;
+		goto twoop;
+	case OEQ:
+		cmp = 1;
+		args = nil;
+		optab = nil;
+		goto twoop;
+	case ONE:
+		cmp = 1;
+		args = nil;
+		optab = nil;
+		goto twoop;
+	case OLE:
+		cmp = 1;
+		args = nil;
+		optab = nil;
+		goto twoop;
+	case OLT:
+		cmp = 1;
+		args = nil;
+		optab = nil;
+		goto twoop;
+	case OGE:
+		cmp = 1;
+		args = nil;
+		optab = nil;
+		goto twoop;
+	case OGT:
+		cmp = 1;
+		args = nil;
+		optab = nil;
+		goto twoop;
+	case OHI:
+		cmp = 1;
+		args = nil;
+		optab = nil;
+		goto twoop;
+	case OHS:
+		cmp = 1;
+		args = nil;
+		optab = nil;
+		goto twoop;
+	case OLO:
+		cmp = 1;
+		args = nil;
+		optab = nil;
+		goto twoop;
+	case OLS:
+		cmp = 1;
+		args = nil;
+		optab = nil;
+		goto twoop;
+
+twoop:
+		dr = nn != Z && nn->op == OREGPAIR;
+		l = vfunc(n->left, nn);
+		if(sh)
+			r = n->right;
+		else
+			r = vfunc(n->right, nn);
+
+		li = l->op == ONAME || l->op == OINDREG || l->op == OCONST;
+		ri = r->op == ONAME || r->op == OINDREG || r->op == OCONST;
+
+#define	IMM(l, r)	((l) | ((r) << 1))
+
+		lri = IMM(li, ri);
+
+		/* find out what is so easy about some operands */
+		if(li)
+			li = whatof(l, sh | cmp);
+		if(ri)
+			ri = whatof(r, cmp);
+
+		if(sh)
+			goto shift;
+
+		if(cmp)
+			goto cmp;
+
+		/* evaluate hard subexps, stealing nn if possible. */
+		switch(lri) {
+		case IMM(0, 0):
+		bin00:
+			if(l->complex > r->complex) {
+				if(dr)
+					t = nn;
+				else
+					t = regpair(Z, n);
+				sugen(l, t, 8);
+				l = t;
+				t = regpair(Z, n);
+				sugen(r, t, 8);
+				r = t;
+			}
+			else {
+				t = regpair(Z, n);
+				sugen(r, t, 8);
+				r = t;
+				if(dr)
+					t = nn;
+				else
+					t = regpair(Z, n);
+				sugen(l, t, 8);
+				l = t;
+			}
+			break;
+		case IMM(0, 1):
+			if(dr)
+				t = nn;
+			else
+				t = regpair(Z, n);
+			sugen(l, t, 8);
+			l = t;
+			break;
+		case IMM(1, 0):
+			if(n->op == OSUB && l->op == OCONST && hi64v(l) == 0) {
+				lri = IMM(0, 0);
+				goto bin00;
+			}
+			if(dr)
+				t = nn;
+			else
+				t = regpair(Z, n);
+			sugen(r, t, 8);
+			r = t;
+			break;
+		case IMM(1, 1):
+			break;
+		}
+
+#define	WW(l, r)	((l) | ((r) << 2))
+		d = Z;
+		dt = nn->type;
+		nn->type = types[TLONG];
+
+		switch(lri) {
+		case IMM(0, 0):
+			biggen(l, r, Z, 0, binop00, args);
+			break;
+		case IMM(0, 1):
+			switch(ri) {
+			case WNONE:
+				diag(r, "bad whatof\n");
+				break;
+			case WCONST:
+				biggen(l, r, Z, 0, optab[B0c], args);
+				break;
+			case WHARD:
+				reglcgen(&nod2, r, Z);
+				r = &nod2;
+				/* fall thru */
+			case WADDR:
+				biggen(l, r, Z, 0, binoptmp, args);
+				if(ri == WHARD)
+					regfree(r);
+				break;
+			}
+			break;
+		case IMM(1, 0):
+			if(n->op == OSUB) {
+				switch(li) {
+				case WNONE:
+					diag(l, "bad whatof\n");
+					break;
+				case WHARD:
+					reglcgen(&nod2, l, Z);
+					l = &nod2;
+					/* fall thru */
+				case WADDR:
+				case WCONST:
+					biggen(l, r, Z, 0, sub10, args);
+					break;
+				}
+				if(li == WHARD)
+					regfree(l);
+			}
+			else {
+				switch(li) {
+				case WNONE:
+					diag(l, "bad whatof\n");
+					break;
+				case WCONST:
+					biggen(r, l, Z, 0, optab[B0c], args);
+					break;
+				case WHARD:
+					reglcgen(&nod2, l, Z);
+					l = &nod2;
+					/* fall thru */
+				case WADDR:
+					biggen(r, l, Z, 0, binoptmp, args);
+					if(li == WHARD)
+						regfree(l);
+					break;
+				}
+			}
+			break;
+		case IMM(1, 1):
+			switch(WW(li, ri)) {
+			case WW(WCONST, WHARD):
+				if(r->op == ONAME && n->op == OAND && reduxv(l))
+					ri = WADDR;
+				break;
+			case WW(WHARD, WCONST):
+				if(l->op == ONAME && n->op == OAND && reduxv(r))
+					li = WADDR;
+				break;
+			}
+			if(li == WHARD) {
+				reglcgen(&nod3, l, Z);
+				l = &nod3;
+			}
+			if(ri == WHARD) {
+				reglcgen(&nod2, r, Z);
+				r = &nod2;
+			}
+			d = regpair(nn, n);
+			instpair(d, Z);
+			switch(WW(li, ri)) {
+			case WW(WCONST, WADDR):
+			case WW(WCONST, WHARD):
+				biggen(l, r, d, 0, optab[Bca], args);
+				break;
+
+			case WW(WADDR, WCONST):
+			case WW(WHARD, WCONST):
+				biggen(l, r, d, 0, optab[Bac], args);
+				break;
+
+			case WW(WADDR, WADDR):
+			case WW(WADDR, WHARD):
+			case WW(WHARD, WADDR):
+			case WW(WHARD, WHARD):
+				biggen(l, r, d, 0, binop11, args);
+				break;
+
+			default:
+				diag(r, "bad whatof pair %d %d\n", li, ri);
+				break;
+			}
+			if(li == WHARD)
+				regfree(l);
+			if(ri == WHARD)
+				regfree(r);
+			break;
+		}
+
+		nn->type = dt;
+
+		if(d != Z)
+			goto finished;
+
+		switch(lri) {
+		case IMM(0, 0):
+			freepair(r);
+			/* fall thru */;
+		case IMM(0, 1):
+			if(!dr)
+				storepair(l, nn, 1);
+			break;
+		case IMM(1, 0):
+			if(!dr)
+				storepair(r, nn, 1);
+			break;
+		case IMM(1, 1):
+			break;
+		}
+		return 1;
+
+	shift:
+		c = Z;
+
+		/* evaluate hard subexps, stealing nn if possible. */
+		/* must also secure CX.  not as many optims as binop. */
+		switch(lri) {
+		case IMM(0, 0):
+		imm00:
+			if(l->complex + 1 > r->complex) {
+				if(dr)
+					t = nn;
+				else
+					t = regpair(Z, l);
+				sugen(l, t, 8);
+				l = t;
+				t = &nod1;
+				c = snarfreg(l, t, D_CX, r, &nod2);
+				cgen(r, t);
+				r = t;
+			}
+			else {
+				t = &nod1;
+				c = snarfreg(nn, t, D_CX, r, &nod2);
+				cgen(r, t);
+				r = t;
+				if(dr)
+					t = nn;
+				else
+					t = regpair(Z, l);
+				sugen(l, t, 8);
+				l = t;
+			}
+			break;
+		case IMM(0, 1):
+		imm01:
+			if(ri != WCONST) {
+				lri = IMM(0, 0);
+				goto imm00;
+			}
+			if(dr)
+				t = nn;
+			else
+				t = regpair(Z, n);
+			sugen(l, t, 8);
+			l = t;
+			break;
+		case IMM(1, 0):
+		imm10:
+			if(li != WCONST) {
+				lri = IMM(0, 0);
+				goto imm00;
+			}
+			t = &nod1;
+			c = snarfreg(nn, t, D_CX, r, &nod2);
+			cgen(r, t);
+			r = t;
+			break;
+		case IMM(1, 1):
+			if(ri != WCONST) {
+				lri = IMM(1, 0);
+				goto imm10;
+			}
+			if(li == WHARD) {
+				lri = IMM(0, 1);
+				goto imm01;
+			}
+			break;
+		}
+
+		d = Z;
+
+		switch(lri) {
+		case IMM(0, 0):
+			biggen(l, r, Z, 0, optab[S00], args);
+			break;
+		case IMM(0, 1):
+			switch(ri) {
+			case WNONE:
+			case WADDR:
+			case WHARD:
+				diag(r, "bad whatof\n");
+				break;
+			case WCONST:
+				m = r->vconst & 63;
+				s = nodconst(m);
+				if(m < 32)
+					cp = optab[Sc0];
+				else if(m == 32)
+					cp = optab[Sc1];
+				else
+					cp = optab[Sc2];
+				biggen(l, s, Z, 0, cp, args);
+				break;
+			}
+			break;
+		case IMM(1, 0):
+			/* left is const */
+			d = regpair(nn, n);
+			instpair(d, Z);
+			biggen(l, r, d, 0, optab[S10], args);
+			regfree(r);
+			break;
+		case IMM(1, 1):
+			d = regpair(nn, n);
+			instpair(d, Z);
+			switch(WW(li, ri)) {
+			case WW(WADDR, WCONST):
+				m = r->vconst & 63;
+				s = nodconst(m);
+				if(m < 32) {
+					loadpair(l, d);
+					l = d;
+					cp = optab[Sc0];
+				}
+				else if(m == 32)
+					cp = optab[Sac3];
+				else
+					cp = optab[Sac4];
+				biggen(l, s, d, 0, cp, args);
+				break;
+
+			default:
+				diag(r, "bad whatof pair %d %d\n", li, ri);
+				break;
+			}
+			break;
+		}
+
+		if(c != Z) {
+			gins(AMOVL, c, r);
+			regfree(c);
+		}
+
+		if(d != Z)
+			goto finished;
+
+		switch(lri) {
+		case IMM(0, 0):
+			regfree(r);
+			/* fall thru */
+		case IMM(0, 1):
+			if(!dr)
+				storepair(l, nn, 1);
+			break;
+		case IMM(1, 0):
+			regfree(r);
+			break;
+		case IMM(1, 1):
+			break;
+		}
+		return 1;
+
+	cmp:
+		op = n->op;
+		/* evaluate hard subexps */
+		switch(lri) {
+		case IMM(0, 0):
+			if(l->complex > r->complex) {
+				t = regpair(Z, l);
+				sugen(l, t, 8);
+				l = t;
+				t = regpair(Z, r);
+				sugen(r, t, 8);
+				r = t;
+			}
+			else {
+				t = regpair(Z, r);
+				sugen(r, t, 8);
+				r = t;
+				t = regpair(Z, l);
+				sugen(l, t, 8);
+				l = t;
+			}
+			break;
+		case IMM(1, 0):
+			t = r;
+			r = l;
+			l = t;
+			ri = li;
+			op = invrel[relindex(op)];
+			/* fall thru */
+		case IMM(0, 1):
+			t = regpair(Z, l);
+			sugen(l, t, 8);
+			l = t;
+			break;
+		case IMM(1, 1):
+			break;
+		}
+
+		true = 1;
+		optab = cmptab;
+		switch(op) {
+		case OEQ:
+			optab = NEtab;
+			true = 0;
+			break;
+		case ONE:
+			optab = NEtab;
+			break;
+		case OLE:
+			args = GTargs;
+			true = 0;
+			break;
+		case OGT:
+			args = GTargs;
+			break;
+		case OLS:
+			args = HIargs;
+			true = 0;
+			break;
+		case OHI:
+			args = HIargs;
+			break;
+		case OLT:
+			args = GEargs;
+			true = 0;
+			break;
+		case OGE:
+			args = GEargs;
+			break;
+		case OLO:
+			args = HSargs;
+			true = 0;
+			break;
+		case OHS:
+			args = HSargs;
+			break;
+		default:
+			diag(n, "bad cmp\n");
+			SET(optab);
+		}
+
+		switch(lri) {
+		case IMM(0, 0):
+			biggen(l, r, Z, true, optab[T0i], args);
+			break;
+		case IMM(0, 1):
+		case IMM(1, 0):
+			switch(ri) {
+			case WNONE:
+				diag(l, "bad whatof\n");
+				break;
+			case WCONST:
+				biggen(l, r, Z, true, optab[T0i], args);
+				break;
+			case WHARD:
+				reglcgen(&nod2, r, Z);
+				r = &nod2;
+				/* fall thru */
+			case WADDR:
+				biggen(l, r, Z, true, optab[T0i], args);
+				if(ri == WHARD)
+					regfree(r);
+				break;
+			}
+			break;
+		case IMM(1, 1):
+			if(li == WHARD) {
+				reglcgen(&nod3, l, Z);
+				l = &nod3;
+			}
+			if(ri == WHARD) {
+				reglcgen(&nod2, r, Z);
+				r = &nod2;
+			}
+			biggen(l, r, Z, true, optab[Tii], args);
+			if(li == WHARD)
+				regfree(l);
+			if(ri == WHARD)
+				regfree(r);
+			break;
+		}
+
+		switch(lri) {
+		case IMM(0, 0):
+			freepair(r);
+			/* fall thru */;
+		case IMM(0, 1):
+		case IMM(1, 0):
+			freepair(l);
+			break;
+		case IMM(1, 1):
+			break;
+		}
+		return 1;
+
+	case OASMUL:
+	case OASLMUL:
+		m = 0;
+		goto mulop;
+
+	case OMUL:
+	case OLMUL:
+		m = 1;
+		goto mulop;
+
+	mulop:
+		dr = nn != Z && nn->op == OREGPAIR;
+		l = vfunc(n->left, nn);
+		r = vfunc(n->right, nn);
+		if(r->op != OCONST) {
+			if(l->complex > r->complex) {
+				if(m) {
+					t = l;
+					l = r;
+					r = t;
+				}
+				else if(!vaddr(l, 1)) {
+					reglcgen(&nod5, l, Z);
+					l = &nod5;
+					evacaxdx(l);
+				}
+			}
+			t = regpair(Z, n);
+			sugen(r, t, 8);
+			r = t;
+			evacaxdx(r->left);
+			evacaxdx(r->right);
+			if(l->complex <= r->complex && !m && !vaddr(l, 1)) {
+				reglcgen(&nod5, l, Z);
+				l = &nod5;
+				evacaxdx(l);
+			}
+		}
+		if(dr)
+			t = nn;
+		else
+			t = regpair(Z, n);
+		c = Z;
+		d = Z;
+		if(!nodreg(&nod1, t->left, D_AX)) {
+			if(t->left->reg != D_AX){
+				t->left->reg = D_AX;
+				reg[D_AX]++;
+			}else if(reg[D_AX] == 0)
+				fatal(Z, "vlong mul AX botch");
+		}
+		if(!nodreg(&nod2, t->right, D_DX)) {
+			if(t->right->reg != D_DX){
+				t->right->reg = D_DX;
+				reg[D_DX]++;
+			}else if(reg[D_DX] == 0)
+				fatal(Z, "vlong mul DX botch");
+		}
+		if(m)
+			sugen(l, t, 8);
+		else
+			loadpair(l, t);
+		if(t->left->reg != D_AX) {
+			c = &nod3;
+			regsalloc(c, t->left);
+			gmove(&nod1, c);
+			gmove(t->left, &nod1);
+			zapreg(t->left);
+		}
+		if(t->right->reg != D_DX) {
+			d = &nod4;
+			regsalloc(d, t->right);
+			gmove(&nod2, d);
+			gmove(t->right, &nod2);
+			zapreg(t->right);
+		}
+		if(c != Z || d != Z) {
+			s = regpair(Z, n);
+			s->left = &nod1;
+			s->right = &nod2;
+		}
+		else
+			s = t;
+		if(r->op == OCONST) {
+			if(hi64v(r) == 0)
+				biggen(s, r, Z, 0, mulc32, nil);
+			else
+				biggen(s, r, Z, 0, mulc64, nil);
+		}
+		else
+			biggen(s, r, Z, 0, mull, nil);
+		instpair(t, Z);
+		if(c != Z) {
+			gmove(&nod1, t->left);
+			gmove(&nod3, &nod1);
+		}
+		if(d != Z) {
+			gmove(&nod2, t->right);
+			gmove(&nod4, &nod2);
+		}
+		if(r->op == OREGPAIR)
+			freepair(r);
+		if(!m)
+			storepair(t, l, 0);
+		if(l == &nod5)
+			regfree(l);
+		if(!dr) {
+			if(nn != Z)
+				storepair(t, nn, 1);
+			else
+				freepair(t);
+		}
+		return 1;
+
+	case OASADD:
+		args = ADDargs;
+		goto vasop;
+	case OASAND:
+		args = ANDargs;
+		goto vasop;
+	case OASOR:
+		args = ORargs;
+		goto vasop;
+	case OASSUB:
+		args = SUBargs;
+		goto vasop;
+	case OASXOR:
+		args = XORargs;
+		goto vasop;
+
+	vasop:
+		l = n->left;
+		r = n->right;
+		dr = nn != Z && nn->op == OREGPAIR;
+		m = 0;
+		if(l->complex > r->complex) {
+			if(!vaddr(l, 1)) {
+				reglcgen(&nod1, l, Z);
+				l = &nod1;
+			}
+			if(!vaddr(r, 1) || nn != Z || r->op == OCONST) {
+				if(dr)
+					t = nn;
+				else
+					t = regpair(Z, r);
+				sugen(r, t, 8);
+				r = t;
+				m = 1;
+			}
+		}
+		else {
+			if(!vaddr(r, 1) || nn != Z || r->op == OCONST) {
+				if(dr)
+					t = nn;
+				else
+					t = regpair(Z, r);
+				sugen(r, t, 8);
+				r = t;
+				m = 1;
+			}
+			if(!vaddr(l, 1)) {
+				reglcgen(&nod1, l, Z);
+				l = &nod1;
+			}
+		}
+		if(nn != Z) {
+			if(n->op == OASSUB)
+				biggen(l, r, Z, 0, sub10, args);
+			else
+				biggen(r, l, Z, 0, binoptmp, args);
+			storepair(r, l, 0);
+		}
+		else {
+			if(m)
+				biggen(l, r, Z, 0, binop00, args);
+			else
+				biggen(l, r, Z, 0, binoptmp, args);
+		}
+		if(l == &nod1)
+			regfree(&nod1);
+		if(m) {
+			if(nn == Z)
+				freepair(r);
+			else if(!dr)
+				storepair(r, nn, 1);
+		}
+		return 1;
+
+	case OASASHL:
+		args = nil;
+		optab = asshlltab;
+		goto assh;
+	case OASLSHR:
+		args = shrlargs;
+		optab = asshrltab;
+		goto assh;
+	case OASASHR:
+		args = sarlargs;
+		optab = asshrltab;
+		goto assh;
+
+	assh:
+		c = Z;
+		l = n->left;
+		r = n->right;
+		if(r->op == OCONST) {
+			m = r->vconst & 63;
+			if(m < 32)
+				m = SAclo;
+			else if(m == 32)
+				m = SAc32;
+			else
+				m = SAchi;
+		}
+		else
+			m = SAgen;
+		if(l->complex > r->complex) {
+			if(!vaddr(l, 0)) {
+				reglcgen(&nod1, l, Z);
+				l = &nod1;
+			}
+			if(m == SAgen) {
+				t = &nod2;
+				if(l->reg == D_CX) {
+					regalloc(t, r, Z);
+					gmove(l, t);
+					l->reg = t->reg;
+					t->reg = D_CX;
+				}
+				else
+					c = snarfreg(nn, t, D_CX, r, &nod3);
+				cgen(r, t);
+				r = t;
+			}
+		}
+		else {
+			if(m == SAgen) {
+				t = &nod2;
+				c = snarfreg(nn, t, D_CX, r, &nod3);
+				cgen(r, t);
+				r = t;
+			}
+			if(!vaddr(l, 0)) {
+				reglcgen(&nod1, l, Z);
+				l = &nod1;
+			}
+		}
+
+		if(nn != Z) {
+			m += SAdgen - SAgen;
+			d = regpair(nn, n);
+			instpair(d, Z);
+			biggen(l, r, d, 0, optab[m], args);
+			if(l == &nod1) {
+				regfree(&nod1);
+				l = Z;
+			}
+			if(r == &nod2 && c == Z) {
+				regfree(&nod2);
+				r = Z;
+			}
+			if(d != nn)
+				storepair(d, nn, 1);
+		}
+		else
+			biggen(l, r, Z, 0, optab[m], args);
+
+		if(c != Z) {
+			gins(AMOVL, c, r);
+			regfree(c);
+		}
+		if(l == &nod1)
+			regfree(&nod1);
+		if(r == &nod2)
+			regfree(&nod2);
+		return 1;
+
+	case OPOSTINC:
+		args = ADDargs;
+		cp = incdecpost;
+		goto vinc;
+	case OPOSTDEC:
+		args = SUBargs;
+		cp = incdecpost;
+		goto vinc;
+	case OPREINC:
+		args = ADDargs;
+		cp = incdecpre;
+		goto vinc;
+	case OPREDEC:
+		args = SUBargs;
+		cp = incdecpre;
+		goto vinc;
+
+	vinc:
+		l = n->left;
+		if(!vaddr(l, 1)) {
+			reglcgen(&nod1, l, Z);
+			l = &nod1;
+		}
+		
+		if(nn != Z) {
+			d = regpair(nn, n);
+			instpair(d, Z);
+			biggen(l, Z, d, 0, cp, args);
+			if(l == &nod1) {
+				regfree(&nod1);
+				l = Z;
+			}
+			if(d != nn)
+				storepair(d, nn, 1);
+		}
+		else
+			biggen(l, Z, Z, 0, incdec, args);
+
+		if(l == &nod1)
+			regfree(&nod1);
+		return 1;
+
+	case OCAST:
+		l = n->left;
+		if(typev[l->type->etype]) {
+			if(!vaddr(l, 1)) {
+				if(l->complex + 1 > nn->complex) {
+					d = regpair(Z, l);
+					sugen(l, d, 8);
+					if(!vaddr(nn, 1)) {
+						reglcgen(&nod1, nn, Z);
+						r = &nod1;
+					}
+					else
+						r = nn;
+				}
+				else {
+					if(!vaddr(nn, 1)) {
+						reglcgen(&nod1, nn, Z);
+						r = &nod1;
+					}
+					else
+						r = nn;
+					d = regpair(Z, l);
+					sugen(l, d, 8);
+				}
+//				d->left->type = r->type;
+				d->left->type = types[TLONG];
+				gmove(d->left, r);
+				freepair(d);
+			}
+			else {
+				if(nn->op != OREGISTER && !vaddr(nn, 1)) {
+					reglcgen(&nod1, nn, Z);
+					r = &nod1;
+				}
+				else
+					r = nn;
+//				l->type = r->type;
+				l->type = types[TLONG];
+				gmove(l, r);
+			}
+			if(r != nn)
+				regfree(r);
+		}
+		else {
+			if(typeu[l->type->etype] || cond(l->op))
+				si = TUNSIGNED;
+			else
+				si = TSIGNED;
+			regalloc(&nod1, l, Z);
+			cgen(l, &nod1);
+			if(nn->op == OREGPAIR) {
+				m = instpair(nn, &nod1);
+				biggen(&nod1, Z, nn, si == TSIGNED, castrp, nil);
+			}
+			else {
+				m = 0;
+				if(!vaddr(nn, si != TSIGNED)) {
+					dt = nn->type;
+					nn->type = types[TLONG];
+					reglcgen(&nod2, nn, Z);
+					nn->type = dt;
+					nn = &nod2;
+				}
+				dt = nn->type;
+				nn->type = types[TLONG];
+				biggen(&nod1, Z, nn, si == TSIGNED, castrpa, nil);
+				nn->type = dt;
+				if(nn == &nod2)
+					regfree(&nod2);
+			}
+			if(!m)
+				regfree(&nod1);
+		}
+		return 1;
+
+	default:
+		if(n->op == OREGPAIR) {
+			storepair(n, nn, 1);
+			return 1;
+		}
+		if(nn->op == OREGPAIR) {
+			loadpair(n, nn);
+			return 1;
+		}
+		return 0;
+	}
+finished:
+	if(d != nn)
+		storepair(d, nn, 1);
+	return 1;
+}
+
+void
+testv(Node *n, int true)
+{
+	Type *t;
+	Node *nn, nod;
+
+	switch(n->op) {
+	case OINDREG:
+	case ONAME:
+		biggen(n, Z, Z, true, testi, nil);
+		break;
+
+	default:
+		n = vfunc(n, n);
+		if(n->addable >= INDEXED) {
+			t = n->type;
+			n->type = types[TLONG];
+			reglcgen(&nod, n, Z);
+			n->type = t;
+			n = &nod;
+			biggen(n, Z, Z, true, testi, nil);
+			if(n == &nod)
+				regfree(n);
+		}
+		else {
+			nn = regpair(Z, n);
+			sugen(n, nn, 8);
+			biggen(nn, Z, Z, true, testi, nil);
+			freepair(nn);
+		}
+	}
+}
diff --git a/src/cmd/8c/div.c b/src/cmd/8c/div.c
new file mode 100644
index 0000000..1494505
--- /dev/null
+++ b/src/cmd/8c/div.c
@@ -0,0 +1,236 @@
+// Inferno utils/8c/div.c
+// http://code.google.com/p/inferno-os/source/browse/utils/8c/div.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 "gc.h"
+
+/*
+ * Based on: Granlund, T.; Montgomery, P.L.
+ * "Division by Invariant Integers using Multiplication".
+ * SIGPLAN Notices, Vol. 29, June 1994, page 61.
+ */
+
+#define	TN(n)	((uvlong)1 << (n))
+#define	T31	TN(31)
+#define	T32	TN(32)
+
+int
+multiplier(uint32 d, int p, uvlong *mp)
+{
+	int l;
+	uvlong mlo, mhi, tlo, thi;
+
+	l = topbit(d - 1) + 1;
+	mlo = (((TN(l) - d) << 32) / d) + T32;
+	if(l + p == 64)
+		mhi = (((TN(l) + 1 - d) << 32) / d) + T32;
+	else
+		mhi = (TN(32 + l) + TN(32 + l - p)) / d;
+	/*assert(mlo < mhi);*/
+	while(l > 0) {
+		tlo = mlo >> 1;
+		thi = mhi >> 1;
+		if(tlo == thi)
+			break;
+		mlo = tlo;
+		mhi = thi;
+		l--;
+	}
+	*mp = mhi;
+	return l;
+}
+
+int
+sdiv(uint32 d, uint32 *mp, int *sp)
+{
+	int s;
+	uvlong m;
+
+	s = multiplier(d, 32 - 1, &m);
+	*mp = m;
+	*sp = s;
+	if(m >= T31)
+		return 1;
+	else
+		return 0;
+}
+
+int
+udiv(uint32 d, uint32 *mp, int *sp, int *pp)
+{
+	int p, s;
+	uvlong m;
+
+	s = multiplier(d, 32, &m);
+	p = 0;
+	if(m >= T32) {
+		while((d & 1) == 0) {
+			d >>= 1;
+			p++;
+		}
+		s = multiplier(d, 32 - p, &m);
+	}
+	*mp = m;
+	*pp = p;
+	if(m >= T32) {
+		/*assert(p == 0);*/
+		*sp = s - 1;
+		return 1;
+	}
+	else {
+		*sp = s;
+		return 0;
+	}
+}
+
+void
+sdivgen(Node *l, Node *r, Node *ax, Node *dx)
+{
+	int a, s;
+	uint32 m;
+	vlong c;
+
+	c = r->vconst;
+	if(c < 0)
+		c = -c;
+	a = sdiv(c, &m, &s);
+//print("a=%d i=%d s=%d m=%ux\n", a, (int32)r->vconst, s, m);
+	gins(AMOVL, nodconst(m), ax);
+	gins(AIMULL, l, Z);
+	gins(AMOVL, l, ax);
+	if(a)
+		gins(AADDL, ax, dx);
+	gins(ASHRL, nodconst(31), ax);
+	gins(ASARL, nodconst(s), dx);
+	gins(AADDL, ax, dx);
+	if(r->vconst < 0)
+		gins(ANEGL, Z, dx);
+}
+
+void
+udivgen(Node *l, Node *r, Node *ax, Node *dx)
+{
+	int a, s, t;
+	uint32 m;
+	Node nod;
+
+	a = udiv(r->vconst, &m, &s, &t);
+//print("a=%ud i=%d p=%d s=%d m=%ux\n", a, (int32)r->vconst, t, s, m);
+	if(t != 0) {
+		gins(AMOVL, l, ax);
+		gins(ASHRL, nodconst(t), ax);
+		gins(AMOVL, nodconst(m), dx);
+		gins(AMULL, dx, Z);
+	}
+	else if(a) {
+		if(l->op != OREGISTER) {
+			regalloc(&nod, l, Z);
+			gins(AMOVL, l, &nod);
+			l = &nod;
+		}
+		gins(AMOVL, nodconst(m), ax);
+		gins(AMULL, l, Z);
+		gins(AADDL, l, dx);
+		gins(ARCRL, nodconst(1), dx);
+		if(l == &nod)
+			regfree(l);
+	}
+	else {
+		gins(AMOVL, nodconst(m), ax);
+		gins(AMULL, l, Z);
+	}
+	if(s != 0)
+		gins(ASHRL, nodconst(s), dx);
+}
+
+void
+sext(Node *d, Node *s, Node *l)
+{
+	if(s->reg == D_AX && !nodreg(d, Z, D_DX)) {
+		reg[D_DX]++;
+		gins(ACDQ, Z, Z);
+	}
+	else {
+		regalloc(d, l, Z);
+		gins(AMOVL, s, d);
+		gins(ASARL, nodconst(31), d);
+	}
+}
+
+void
+sdiv2(int32 c, int v, Node *l, Node *n)
+{
+	Node nod;
+
+	if(v > 0) {
+		if(v > 1) {
+			sext(&nod, n, l);
+			gins(AANDL, nodconst((1 << v) - 1), &nod);
+			gins(AADDL, &nod, n);
+			regfree(&nod);
+		}
+		else {
+			gins(ACMPL, n, nodconst(0x80000000));
+			gins(ASBBL, nodconst(-1), n);
+		}
+		gins(ASARL, nodconst(v), n);
+	}
+	if(c < 0)
+		gins(ANEGL, Z, n);
+}
+
+void
+smod2(int32 c, int v, Node *l, Node *n)
+{
+	Node nod;
+
+	if(c == 1) {
+		zeroregm(n);
+		return;
+	}
+
+	sext(&nod, n, l);
+	if(v == 0) {
+		zeroregm(n);
+		gins(AXORL, &nod, n);
+		gins(ASUBL, &nod, n);
+	}
+	else if(v > 1) {
+		gins(AANDL, nodconst((1 << v) - 1), &nod);
+		gins(AADDL, &nod, n);
+		gins(AANDL, nodconst((1 << v) - 1), n);
+		gins(ASUBL, &nod, n);
+	}
+	else {
+		gins(AANDL, nodconst(1), n);
+		gins(AXORL, &nod, n);
+		gins(ASUBL, &nod, n);
+	}
+	regfree(&nod);
+}
diff --git a/src/cmd/8c/doc.go b/src/cmd/8c/doc.go
new file mode 100644
index 0000000..0d07db1
--- /dev/null
+++ b/src/cmd/8c/doc.go
@@ -0,0 +1,16 @@
+// 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
+
+/*
+
+8c is a version of the Plan 9 C compiler.  The original is documented at
+
+	http://plan9.bell-labs.com/magic/man2html/1/8c
+
+Its target architecture is the x86, referred to by these tools for historical reasons as 386.
+
+*/
+package main
diff --git a/src/cmd/8c/gc.h b/src/cmd/8c/gc.h
new file mode 100644
index 0000000..aa3888d
--- /dev/null
+++ b/src/cmd/8c/gc.h
@@ -0,0 +1,364 @@
+// Inferno utils/8c/gc.h
+// http://code.google.com/p/inferno-os/source/browse/utils/8c/gc.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.
+
+#include	<u.h>
+#include	"../cc/cc.h"
+#include	"../8l/8.out.h"
+
+/*
+ * 8c/386
+ * Intel 386
+ */
+#define	SZ_CHAR		1
+#define	SZ_SHORT	2
+#define	SZ_INT		4
+#define	SZ_LONG		4
+#define	SZ_IND		4
+#define	SZ_FLOAT	4
+#define	SZ_VLONG	8
+#define	SZ_DOUBLE	8
+#define	FNX		100
+
+typedef	struct	Case	Case;
+typedef	struct	C1	C1;
+typedef	struct	Reg	Reg;
+typedef	struct	Rgn	Rgn;
+typedef	struct	Renv	Renv;
+
+EXTERN	struct
+{
+	Node*	regtree;
+	Node*	basetree;
+	short	scale;
+	short	reg;
+	short	ptr;
+} idx;
+
+#define	A	((Addr*)0)
+
+#define	INDEXED	9
+
+#define	P	((Prog*)0)
+
+struct	Case
+{
+	Case*	link;
+	int32	val;
+	int32	label;
+	char	def;
+	char	isv;
+};
+#define	C	((Case*)0)
+
+struct	C1
+{
+	int32	val;
+	int32	label;
+};
+
+struct	Reg
+{
+	int32	pc;
+	int32	rpo;		/* reverse post ordering */
+
+	Bits	set;
+	Bits	use1;
+	Bits	use2;
+
+	Bits	refbehind;
+	Bits	refahead;
+	Bits	calbehind;
+	Bits	calahead;
+	Bits	regdiff;
+	Bits	act;
+
+	int32	regu;
+	int32	loop;		/* could be shorter */
+
+	Reg*	log5;
+	int32	active;
+
+	Reg*	p1;
+	Reg*	p2;
+	Reg*	p2link;
+	Reg*	s1;
+	Reg*	s2;
+	Reg*	link;
+	Prog*	prog;
+};
+#define	R	((Reg*)0)
+
+struct	Renv
+{
+	int	safe;
+	Node	base;
+	Node*	saved;
+	Node*	scope;
+};
+
+#define	NRGN	600
+struct	Rgn
+{
+	Reg*	enter;
+	short	cost;
+	short	varno;
+	short	regno;
+};
+
+EXTERN	int32	breakpc;
+EXTERN	int32	nbreak;
+EXTERN	Case*	cases;
+EXTERN	Node	constnode;
+EXTERN	Node	fconstnode;
+EXTERN	int32	continpc;
+EXTERN	int32	curarg;
+EXTERN	int32	cursafe;
+EXTERN	Prog*	lastp;
+EXTERN	int32	maxargsafe;
+EXTERN	int	mnstring;
+EXTERN	Node*	nodrat;
+EXTERN	Node*	nodret;
+EXTERN	Node*	nodsafe;
+EXTERN	int32	nrathole;
+EXTERN	int32	nstring;
+EXTERN	Prog*	p;
+EXTERN	int32	pc;
+EXTERN	Node	regnode;
+EXTERN	Node	fregnode0;
+EXTERN	Node	fregnode1;
+EXTERN	char	string[NSNAME];
+EXTERN	Sym*	symrathole;
+EXTERN	Node	znode;
+EXTERN	Prog	zprog;
+EXTERN	int	reg[D_NONE];
+EXTERN	int32	exregoffset;
+EXTERN	int32	exfregoffset;
+
+#define	BLOAD(r)	band(bnot(r->refbehind), r->refahead)
+#define	BSTORE(r)	band(bnot(r->calbehind), r->calahead)
+#define	LOAD(r)		(~r->refbehind.b[z] & r->refahead.b[z])
+#define	STORE(r)	(~r->calbehind.b[z] & r->calahead.b[z])
+
+#define	bset(a,n)	((a).b[(n)/32]&(1L<<(n)%32))
+
+#define	CLOAD	5
+#define	CREF	5
+#define	CINF	1000
+#define	LOOP	3
+
+EXTERN	Rgn	region[NRGN];
+EXTERN	Rgn*	rgp;
+EXTERN	int	nregion;
+EXTERN	int	nvar;
+
+EXTERN	Bits	externs;
+EXTERN	Bits	params;
+EXTERN	Bits	consts;
+EXTERN	Bits	addrs;
+
+EXTERN	int32	regbits;
+EXTERN	int32	exregbits;
+
+EXTERN	int	change;
+EXTERN	int	suppress;
+
+EXTERN	Reg*	firstr;
+EXTERN	Reg*	lastr;
+EXTERN	Reg	zreg;
+EXTERN	Reg*	freer;
+EXTERN	int32*	idom;
+EXTERN	Reg**	rpo2r;
+EXTERN	int32	maxnr;
+
+extern	char*	anames[];
+
+/*
+ * sgen.c
+ */
+void	codgen(Node*, Node*);
+void	gen(Node*);
+void	noretval(int);
+void	usedset(Node*, int);
+void	xcom(Node*);
+void	indx(Node*);
+int	bcomplex(Node*, Node*);
+Prog*	gtext(Sym*, int32);
+vlong	argsize(int);
+
+/*
+ * cgen.c
+ */
+void	zeroregm(Node*);
+void	cgen(Node*, Node*);
+void	reglcgen(Node*, Node*, Node*);
+void	lcgen(Node*, Node*);
+void	bcgen(Node*, int);
+void	boolgen(Node*, int, Node*);
+void	sugen(Node*, Node*, int32);
+int	needreg(Node*, int);
+
+/*
+ * cgen64.c
+ */
+int	vaddr(Node*, int);
+void	loadpair(Node*, Node*);
+int	cgen64(Node*, Node*);
+void	testv(Node*, int);
+
+/*
+ * txt.c
+ */
+void	ginit(void);
+void	gclean(void);
+void	nextpc(void);
+void	gargs(Node*, Node*, Node*);
+void	garg1(Node*, Node*, Node*, int, Node**);
+Node*	nodconst(int32);
+Node*	nodfconst(double);
+int	nodreg(Node*, Node*, int);
+int	isreg(Node*, int);
+void	regret(Node*, Node*, Type*, int);
+void	regalloc(Node*, Node*, Node*);
+void	regfree(Node*);
+void	regialloc(Node*, Node*, Node*);
+void	regsalloc(Node*, Node*);
+void	regaalloc1(Node*, Node*);
+void	regaalloc(Node*, Node*);
+void	regind(Node*, Node*);
+void	gprep(Node*, Node*);
+void	naddr(Node*, Addr*);
+void	gmove(Node*, Node*);
+void	gins(int a, Node*, Node*);
+void	fgopcode(int, Node*, Node*, int, int);
+void	gopcode(int, Type*, Node*, Node*);
+int	samaddr(Node*, Node*);
+void	gbranch(int);
+void	patch(Prog*, int32);
+int	sconst(Node*);
+void	gpseudo(int, Sym*, Node*);
+void	gprefetch(Node*);
+void	gpcdata(int, int);
+
+/*
+ * swt.c
+ */
+int	swcmp(const void*, const void*);
+void	doswit(Node*);
+void	swit1(C1*, int, int32, Node*);
+void	swit2(C1*, int, int32, Node*);
+void	newcase(void);
+void	bitload(Node*, Node*, Node*, Node*, Node*);
+void	bitstore(Node*, Node*, Node*, Node*, Node*);
+int32	outstring(char*, int32);
+void	nullwarn(Node*, Node*);
+void	sextern(Sym*, Node*, int32, int32);
+void	gextern(Sym*, Node*, int32, int32);
+void	outcode(void);
+
+/*
+ * list
+ */
+void	listinit(void);
+
+/*
+ * reg.c
+ */
+Reg*	rega(void);
+int	rcmp(const void*, const void*);
+void	regopt(Prog*);
+void	addmove(Reg*, int, int, int);
+Bits	mkvar(Reg*, Addr*);
+void	prop(Reg*, Bits, Bits);
+void	loopit(Reg*, int32);
+void	synch(Reg*, Bits);
+uint32	allreg(uint32, Rgn*);
+void	paint1(Reg*, int);
+uint32	paint2(Reg*, int);
+void	paint3(Reg*, int, int32, int);
+void	addreg(Addr*, int);
+
+/*
+ * peep.c
+ */
+void	peep(void);
+void	excise(Reg*);
+Reg*	uniqp(Reg*);
+Reg*	uniqs(Reg*);
+int	regtyp(Addr*);
+int	anyvar(Addr*);
+int	subprop(Reg*);
+int	copyprop(Reg*);
+int	copy1(Addr*, Addr*, Reg*, int);
+int	copyu(Prog*, Addr*, Addr*);
+
+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);
+int	BtoR(int32);
+int	BtoF(int32);
+
+#define	D_HI	D_NONE
+#define	D_LO	D_NONE
+
+/*
+ * bound
+ */
+void	comtarg(void);
+
+/*
+ * com64
+ */
+int	cond(int);
+int	com64(Node*);
+void	com64init(void);
+void	bool64(Node*);
+int32	lo64v(Node*);
+int32	hi64v(Node*);
+Node*	lo64(Node*);
+Node*	hi64(Node*);
+
+/*
+ * div/mul
+ */
+void	sdivgen(Node*, Node*, Node*, Node*);
+void	udivgen(Node*, Node*, Node*, Node*);
+void	sdiv2(int32, int, Node*, Node*);
+void	smod2(int32, int, Node*, Node*);
+void	mulgen(Type*, Node*, Node*);
+void	genmuladd(Node*, Node*, int, Node*);
+void	shiftit(Type*, Node*, Node*);
+
+/* wrecklessly steal a field */
+
+#define	rplink	label
diff --git a/src/cmd/8c/list.c b/src/cmd/8c/list.c
new file mode 100644
index 0000000..1730ecc
--- /dev/null
+++ b/src/cmd/8c/list.c
@@ -0,0 +1,38 @@
+// 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.
+
+#define EXTERN
+#include "gc.h"
+
+void
+listinit(void)
+{
+	listinit8();
+}
diff --git a/src/cmd/8c/machcap.c b/src/cmd/8c/machcap.c
new file mode 100644
index 0000000..61e5aad
--- /dev/null
+++ b/src/cmd/8c/machcap.c
@@ -0,0 +1,116 @@
+// Inferno utils/8c/machcap.c
+// http://code.google.com/p/inferno-os/source/browse/utils/8c/machcap.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 "gc.h"
+
+int
+machcap(Node *n)
+{
+
+	if(n == Z)
+		return 1;	/* test */
+
+	switch(n->op) {
+	case OMUL:
+	case OLMUL:
+	case OASMUL:
+	case OASLMUL:
+		if(typechl[n->type->etype])
+			return 1;
+		if(typev[n->type->etype]) {
+				return 1;
+		}
+		break;
+
+	case OCOM:
+	case ONEG:
+	case OADD:
+	case OAND:
+	case OOR:
+	case OSUB:
+	case OXOR:
+	case OASHL:
+	case OLSHR:
+	case OASHR:
+		if(typechlv[n->left->type->etype])
+			return 1;
+		break;
+
+	case OCAST:
+		if(typev[n->type->etype]) {
+			if(typechlp[n->left->type->etype])
+				return 1;
+		}
+		else if(!typefd[n->type->etype]) {
+			if(typev[n->left->type->etype])
+				return 1;
+		}
+		break;
+
+	case OCOND:
+	case OCOMMA:
+	case OLIST:
+	case OANDAND:
+	case OOROR:
+	case ONOT:
+		return 1;
+
+	case OASADD:
+	case OASSUB:
+	case OASAND:
+	case OASOR:
+	case OASXOR:
+		return 1;
+
+	case OASASHL:
+	case OASASHR:
+	case OASLSHR:
+		return 1;
+
+	case OPOSTINC:
+	case OPOSTDEC:
+	case OPREINC:
+	case OPREDEC:
+		return 1;
+
+	case OEQ:
+	case ONE:
+	case OLE:
+	case OGT:
+	case OLT:
+	case OGE:
+	case OHI:
+	case OHS:
+	case OLO:
+	case OLS:
+		return 1;
+	}
+	return 0;
+}
diff --git a/src/cmd/8c/mul.c b/src/cmd/8c/mul.c
new file mode 100644
index 0000000..9955e76
--- /dev/null
+++ b/src/cmd/8c/mul.c
@@ -0,0 +1,458 @@
+// Inferno utils/8c/mul.c
+// http://code.google.com/p/inferno-os/source/browse/utils/8c/mul.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 "gc.h"
+
+typedef struct	Malg	Malg;
+typedef struct	Mparam	Mparam;
+
+struct	Malg
+{
+	schar	vals[10];
+};
+
+struct	Mparam
+{
+	uint32	value;
+	schar	alg;
+	char	neg;
+	char	shift;
+	char	arg;
+	schar	off;
+};
+
+static	Mparam	multab[32];
+static	int	mulptr;
+
+static	Malg	malgs[]	=
+{
+	{0, 100},
+	{-1, 1, 100},
+	{-9, -5, -3, 3, 5, 9, 100},
+	{6, 10, 12, 18, 20, 24, 36, 40, 72, 100},
+	{-8, -4, -2, 2, 4, 8, 100},
+};
+
+/*
+ * return position of lowest 1
+ */
+int
+lowbit(uint32 v)
+{
+	int s, i;
+	uint32 m;
+
+	s = 0;
+	m = 0xFFFFFFFFUL;
+	for(i = 16; i > 0; i >>= 1) {
+		m >>= i;
+		if((v & m) == 0) {
+			v >>= i;
+			s += i;
+		}
+	}
+	return s;
+}
+
+void
+genmuladd(Node *d, Node *s, int m, Node *a)
+{
+	Node nod;
+
+	nod.op = OINDEX;
+	nod.left = a;
+	nod.right = s;
+	nod.scale = m;
+	nod.type = types[TIND];
+	nod.xoffset = 0;
+	xcom(&nod);
+	gopcode(OADDR, d->type, &nod, d);
+}
+
+void
+mulparam(uint32 m, Mparam *mp)
+{
+	int c, i, j, n, o, q, s;
+	int bc, bi, bn, bo, bq, bs, bt;
+	schar *p;
+	int32 u;
+	uint32 t;
+
+	bc = bq = 10;
+	bi = bn = bo = bs = bt = 0;
+	for(i = 0; i < nelem(malgs); i++) {
+		for(p = malgs[i].vals, j = 0; (o = p[j]) < 100; j++)
+		for(s = 0; s < 2; s++) {
+			c = 10;
+			q = 10;
+			u = m - o;
+			if(u == 0)
+				continue;
+			if(s) {
+				o = -o;
+				if(o > 0)
+					continue;
+				u = -u;
+			}
+			n = lowbit(u);
+			t = (uint32)u >> n;
+			switch(i) {
+			case 0:
+				if(t == 1) {
+					c = s + 1;
+					q = 0;
+					break;
+				}
+				switch(t) {
+				case 3:
+				case 5:
+				case 9:
+					c = s + 1;
+					if(n)
+						c++;
+					q = 0;
+					break;
+				}
+				if(s)
+					break;
+				switch(t) {
+				case 15:
+				case 25:
+				case 27:
+				case 45:
+				case 81:
+					c = 2;
+					if(n)
+						c++;
+					q = 1;
+					break;
+				}
+				break;
+			case 1:
+				if(t == 1) {
+					c = 3;
+					q = 3;
+					break;
+				}
+				switch(t) {
+				case 3:
+				case 5:
+				case 9:
+					c = 3;
+					q = 2;
+					break;
+				}
+				break;
+			case 2:
+				if(t == 1) {
+					c = 3;
+					q = 2;
+					break;
+				}
+				break;
+			case 3:
+				if(s)
+					break;
+				if(t == 1) {
+					c = 3;
+					q = 1;
+					break;
+				}
+				break;
+			case 4:
+				if(t == 1) {
+					c = 3;
+					q = 0;
+					break;
+				}
+				break;
+			}
+			if(c < bc || (c == bc && q > bq)) {
+				bc = c;
+				bi = i;
+				bn = n;
+				bo = o;
+				bq = q;
+				bs = s;
+				bt = t;
+			}
+		}
+	}
+	mp->value = m;
+	if(bc <= 3) {
+		mp->alg = bi;
+		mp->shift = bn;
+		mp->off = bo;
+		mp->neg = bs;
+		mp->arg = bt;
+	}
+	else
+		mp->alg = -1;
+}
+
+int
+m0(int a)
+{
+	switch(a) {
+	case -2:
+	case 2:
+		return 2;
+	case -3:
+	case 3:
+		return 2;
+	case -4:
+	case 4:
+		return 4;
+	case -5:
+	case 5:
+		return 4;
+	case 6:
+		return 2;
+	case -8:
+	case 8:
+		return 8;
+	case -9:
+	case 9:
+		return 8;
+	case 10:
+		return 4;
+	case 12:
+		return 2;
+	case 15:
+		return 2;
+	case 18:
+		return 8;
+	case 20:
+		return 4;
+	case 24:
+		return 2;
+	case 25:
+		return 4;
+	case 27:
+		return 2;
+	case 36:
+		return 8;
+	case 40:
+		return 4;
+	case 45:
+		return 4;
+	case 72:
+		return 8;
+	case 81:
+		return 8;
+	}
+	diag(Z, "bad m0");
+	return 0;
+}
+
+int
+m1(int a)
+{
+	switch(a) {
+	case 15:
+		return 4;
+	case 25:
+		return 4;
+	case 27:
+		return 8;
+	case 45:
+		return 8;
+	case 81:
+		return 8;
+	}
+	diag(Z, "bad m1");
+	return 0;
+}
+
+int
+m2(int a)
+{
+	switch(a) {
+	case 6:
+		return 2;
+	case 10:
+		return 2;
+	case 12:
+		return 4;
+	case 18:
+		return 2;
+	case 20:
+		return 4;
+	case 24:
+		return 8;
+	case 36:
+		return 4;
+	case 40:
+		return 8;
+	case 72:
+		return 8;
+	}
+	diag(Z, "bad m2");
+	return 0;
+}
+
+void
+shiftit(Type *t, Node *s, Node *d)
+{
+	int32 c;
+
+	c = (int32)s->vconst & 31;
+	switch(c) {
+	case 0:
+		break;
+	case 1:
+		gopcode(OADD, t, d, d);
+		break;
+	default:
+		gopcode(OASHL, t, s, d);
+	}
+}
+
+static int
+mulgen1(uint32 v, Node *n)
+{
+	int i, o;
+	Mparam *p;
+	Node nod, nods;
+
+	for(i = 0; i < nelem(multab); i++) {
+		p = &multab[i];
+		if(p->value == v)
+			goto found;
+	}
+
+	p = &multab[mulptr];
+	if(++mulptr == nelem(multab))
+		mulptr = 0;
+
+	mulparam(v, p);
+
+found:
+//	print("v=%.x a=%d n=%d s=%d g=%d o=%d \n", p->value, p->alg, p->neg, p->shift, p->arg, p->off);
+	if(p->alg < 0)
+		return 0;
+
+	nods = *nodconst(p->shift);
+
+	o = OADD;
+	if(p->alg > 0) {
+		regalloc(&nod, n, Z);
+		if(p->off < 0)
+			o = OSUB;
+	}
+
+	switch(p->alg) {
+	case 0:
+		switch(p->arg) {
+		case 1:
+			shiftit(n->type, &nods, n);
+			break;
+		case 15:
+		case 25:
+		case 27:
+		case 45:
+		case 81:
+			genmuladd(n, n, m1(p->arg), n);
+			/* fall thru */
+		case 3:
+		case 5:
+		case 9:
+			genmuladd(n, n, m0(p->arg), n);
+			shiftit(n->type, &nods, n);
+			break;
+		default:
+			goto bad;
+		}
+		if(p->neg == 1)
+			gins(ANEGL, Z, n);
+		break;
+	case 1:
+		switch(p->arg) {
+		case 1:
+			gmove(n, &nod);
+			shiftit(n->type, &nods, &nod);
+			break;
+		case 3:
+		case 5:
+		case 9:
+			genmuladd(&nod, n, m0(p->arg), n);
+			shiftit(n->type, &nods, &nod);
+			break;
+		default:
+			goto bad;
+		}
+		if(p->neg)
+			gopcode(o, n->type, &nod, n);
+		else {
+			gopcode(o, n->type, n, &nod);
+			gmove(&nod, n);
+		}
+		break;
+	case 2:
+		genmuladd(&nod, n, m0(p->off), n);
+		shiftit(n->type, &nods, n);
+		goto comop;
+	case 3:
+		genmuladd(&nod, n, m0(p->off), n);
+		shiftit(n->type, &nods, n);
+		genmuladd(n, &nod, m2(p->off), n);
+		break;
+	case 4:
+		genmuladd(&nod, n, m0(p->off), nodconst(0));
+		shiftit(n->type, &nods, n);
+		goto comop;
+	default:
+		diag(Z, "bad mul alg");
+		break;
+	comop:
+		if(p->neg) {
+			gopcode(o, n->type, n, &nod);
+			gmove(&nod, n);
+		}
+		else
+			gopcode(o, n->type, &nod, n);
+	}
+
+	if(p->alg > 0)
+		regfree(&nod);
+
+	return 1;
+
+bad:
+	diag(Z, "mulgen botch");
+	return 1;
+}
+
+void
+mulgen(Type *t, Node *r, Node *n)
+{
+	if(!mulgen1(r->vconst, n))
+		gopcode(OMUL, t, r, n);
+}
diff --git a/src/cmd/8c/peep.c b/src/cmd/8c/peep.c
new file mode 100644
index 0000000..4f58fc05
--- /dev/null
+++ b/src/cmd/8c/peep.c
@@ -0,0 +1,807 @@
+// Inferno utils/8c/peep.c
+// http://code.google.com/p/inferno-os/source/browse/utils/8c/peep.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 "gc.h"
+
+static int
+needc(Prog *p)
+{
+	while(p != P) {
+		switch(p->as) {
+		case AADCL:
+		case ASBBL:
+		case ARCRL:
+			return 1;
+		case AADDL:
+		case ASUBL:
+		case AJMP:
+		case ARET:
+		case ACALL:
+			return 0;
+		default:
+			if(p->to.type == D_BRANCH)
+				return 0;
+		}
+		p = p->link;
+	}
+	return 0;
+}
+
+void
+peep(void)
+{
+	Reg *r, *r1, *r2;
+	Prog *p, *p1;
+	int t;
+
+	/*
+	 * complete R structure
+	 */
+	t = 0;
+	for(r=firstr; r!=R; r=r1) {
+		r1 = r->link;
+		if(r1 == R)
+			break;
+		p = r->prog->link;
+		while(p != r1->prog)
+		switch(p->as) {
+		default:
+			r2 = rega();
+			r->link = r2;
+			r2->link = r1;
+
+			r2->prog = p;
+			r2->p1 = r;
+			r->s1 = r2;
+			r2->s1 = r1;
+			r1->p1 = r2;
+
+			r = r2;
+			t++;
+
+		case ADATA:
+		case AGLOBL:
+		case ANAME:
+		case ASIGNAME:
+			p = p->link;
+		}
+	}
+
+	pc = 0;	/* speculating it won't kill */
+
+loop1:
+
+	t = 0;
+	for(r=firstr; r!=R; r=r->link) {
+		p = r->prog;
+		switch(p->as) {
+		case AMOVL:
+			if(regtyp(&p->to))
+			if(regtyp(&p->from)) {
+				if(copyprop(r)) {
+					excise(r);
+					t++;
+				}
+				if(subprop(r) && copyprop(r)) {
+					excise(r);
+					t++;
+				}
+			}
+			break;
+
+		case AMOVBLSX:
+		case AMOVBLZX:
+		case AMOVWLSX:
+		case AMOVWLZX:
+			if(regtyp(&p->to)) {
+				r1 = uniqs(r);
+				if(r1 != R) {
+					p1 = r1->prog;
+					if(p->as == p1->as && p->to.type == p1->from.type)
+						p1->as = AMOVL;
+				}
+			}
+			break;
+		case AADDL:
+		case AADDW:
+			if(p->from.type != D_CONST || needc(p->link))
+				break;
+			if(p->from.offset == -1){
+				if(p->as == AADDL)
+					p->as = ADECL;
+				else
+					p->as = ADECW;
+				p->from = zprog.from;
+			}
+			else if(p->from.offset == 1){
+				if(p->as == AADDL)
+					p->as = AINCL;
+				else
+					p->as = AINCW;
+				p->from = zprog.from;
+			}
+			break;
+		case ASUBL:
+		case ASUBW:
+			if(p->from.type != D_CONST || needc(p->link))
+				break;
+			if(p->from.offset == -1) {
+				if(p->as == ASUBL)
+					p->as = AINCL;
+				else
+					p->as = AINCW;
+				p->from = zprog.from;
+			}
+			else if(p->from.offset == 1){
+				if(p->as == ASUBL)
+					p->as = ADECL;
+				else
+					p->as = ADECW;
+				p->from = zprog.from;
+			}
+			break;
+		}
+	}
+	if(t)
+		goto loop1;
+}
+
+void
+excise(Reg *r)
+{
+	Prog *p;
+
+	p = r->prog;
+	p->as = ANOP;
+	p->from = zprog.from;
+	p->to = zprog.to;
+}
+
+Reg*
+uniqp(Reg *r)
+{
+	Reg *r1;
+
+	r1 = r->p1;
+	if(r1 == R) {
+		r1 = r->p2;
+		if(r1 == R || r1->p2link != R)
+			return R;
+	} else
+		if(r->p2 != R)
+			return R;
+	return r1;
+}
+
+Reg*
+uniqs(Reg *r)
+{
+	Reg *r1;
+
+	r1 = r->s1;
+	if(r1 == R) {
+		r1 = r->s2;
+		if(r1 == R)
+			return R;
+	} else
+		if(r->s2 != R)
+			return R;
+	return r1;
+}
+
+int
+regtyp(Addr *a)
+{
+	int t;
+
+	t = a->type;
+	if(t >= D_AX && t <= D_DI)
+		return 1;
+	return 0;
+}
+
+/*
+ * the idea is to substitute
+ * one register for another
+ * from one MOV to another
+ *	MOV	a, R0
+ *	ADD	b, R0	/ no use of R1
+ *	MOV	R0, R1
+ * would be converted to
+ *	MOV	a, R1
+ *	ADD	b, R1
+ *	MOV	R1, R0
+ * hopefully, then the former or latter MOV
+ * will be eliminated by copy propagation.
+ */
+int
+subprop(Reg *r0)
+{
+	Prog *p;
+	Addr *v1, *v2;
+	Reg *r;
+	int t;
+
+	p = r0->prog;
+	v1 = &p->from;
+	if(!regtyp(v1))
+		return 0;
+	v2 = &p->to;
+	if(!regtyp(v2))
+		return 0;
+	for(r=uniqp(r0); r!=R; r=uniqp(r)) {
+		if(uniqs(r) == R)
+			break;
+		p = r->prog;
+		switch(p->as) {
+		case ACALL:
+			return 0;
+
+		case AIMULL:
+		case AIMULW:
+			if(p->to.type != D_NONE)
+				break;
+
+		case ADIVB:
+		case ADIVL:
+		case ADIVW:
+		case AIDIVB:
+		case AIDIVL:
+		case AIDIVW:
+		case AIMULB:
+		case AMULB:
+		case AMULL:
+		case AMULW:
+
+		case AROLB:
+		case AROLL:
+		case AROLW:
+		case ARORB:
+		case ARORL:
+		case ARORW:
+		case ASALB:
+		case ASALL:
+		case ASALW:
+		case ASARB:
+		case ASARL:
+		case ASARW:
+		case ASHLB:
+		case ASHLL:
+		case ASHLW:
+		case ASHRB:
+		case ASHRL:
+		case ASHRW:
+
+		case AREP:
+		case AREPN:
+
+		case ACWD:
+		case ACDQ:
+
+		case ASTOSB:
+		case ASTOSL:
+		case AMOVSB:
+		case AMOVSL:
+		case AFSTSW:
+			return 0;
+
+		case AMOVL:
+			if(p->to.type == v1->type)
+				goto gotit;
+			break;
+		}
+		if(copyau(&p->from, v2) ||
+		   copyau(&p->to, v2))
+			break;
+		if(copysub(&p->from, v1, v2, 0) ||
+		   copysub(&p->to, v1, v2, 0))
+			break;
+	}
+	return 0;
+
+gotit:
+	copysub(&p->to, v1, v2, 1);
+	if(debug['P']) {
+		print("gotit: %D->%D\n%P", v1, v2, r->prog);
+		if(p->from.type == v2->type)
+			print(" excise");
+		print("\n");
+	}
+	for(r=uniqs(r); r!=r0; r=uniqs(r)) {
+		p = r->prog;
+		copysub(&p->from, v1, v2, 1);
+		copysub(&p->to, v1, v2, 1);
+		if(debug['P'])
+			print("%P\n", r->prog);
+	}
+	t = v1->type;
+	v1->type = v2->type;
+	v2->type = t;
+	if(debug['P'])
+		print("%P last\n", r->prog);
+	return 1;
+}
+
+/*
+ * The idea is to remove redundant copies.
+ *	v1->v2	F=0
+ *	(use v2	s/v2/v1/)*
+ *	set v1	F=1
+ *	use v2	return fail
+ *	-----------------
+ *	v1->v2	F=0
+ *	(use v2	s/v2/v1/)*
+ *	set v1	F=1
+ *	set v2	return success
+ */
+int
+copyprop(Reg *r0)
+{
+	Prog *p;
+	Addr *v1, *v2;
+	Reg *r;
+
+	p = r0->prog;
+	v1 = &p->from;
+	v2 = &p->to;
+	if(copyas(v1, v2))
+		return 1;
+	for(r=firstr; r!=R; r=r->link)
+		r->active = 0;
+	return copy1(v1, v2, r0->s1, 0);
+}
+
+int
+copy1(Addr *v1, Addr *v2, Reg *r, int f)
+{
+	int t;
+	Prog *p;
+
+	if(r->active) {
+		if(debug['P'])
+			print("act set; return 1\n");
+		return 1;
+	}
+	r->active = 1;
+	if(debug['P'])
+		print("copy %D->%D f=%d\n", v1, v2, f);
+	for(; r != R; r = r->s1) {
+		p = r->prog;
+		if(debug['P'])
+			print("%P", p);
+		if(!f && uniqp(r) == R) {
+			f = 1;
+			if(debug['P'])
+				print("; merge; f=%d", f);
+		}
+		t = copyu(p, v2, A);
+		switch(t) {
+		case 2:	/* rar, can't split */
+			if(debug['P'])
+				print("; %D rar; return 0\n", v2);
+			return 0;
+
+		case 3:	/* set */
+			if(debug['P'])
+				print("; %D set; return 1\n", v2);
+			return 1;
+
+		case 1:	/* used, substitute */
+		case 4:	/* use and set */
+			if(f) {
+				if(!debug['P'])
+					return 0;
+				if(t == 4)
+					print("; %D used+set and f=%d; return 0\n", v2, f);
+				else
+					print("; %D used and f=%d; return 0\n", v2, f);
+				return 0;
+			}
+			if(copyu(p, v2, v1)) {
+				if(debug['P'])
+					print("; sub fail; return 0\n");
+				return 0;
+			}
+			if(debug['P'])
+				print("; sub %D/%D", v2, v1);
+			if(t == 4) {
+				if(debug['P'])
+					print("; %D used+set; return 1\n", v2);
+				return 1;
+			}
+			break;
+		}
+		if(!f) {
+			t = copyu(p, v1, A);
+			if(!f && (t == 2 || t == 3 || t == 4)) {
+				f = 1;
+				if(debug['P'])
+					print("; %D set and !f; f=%d", v1, f);
+			}
+		}
+		if(debug['P'])
+			print("\n");
+		if(r->s2)
+			if(!copy1(v1, v2, r->s2, f))
+				return 0;
+	}
+	return 1;
+}
+
+/*
+ * return
+ * 1 if v only used (and substitute),
+ * 2 if read-alter-rewrite
+ * 3 if set
+ * 4 if set and used
+ * 0 otherwise (not touched)
+ */
+int
+copyu(Prog *p, Addr *v, Addr *s)
+{
+
+	switch(p->as) {
+
+	default:
+		if(debug['P'])
+			print("unknown op %A\n", p->as);
+		return 2;
+
+	case ANEGB:
+	case ANEGW:
+	case ANEGL:
+	case ANOTB:
+	case ANOTW:
+	case ANOTL:
+		if(copyas(&p->to, v))
+			return 2;
+		break;
+
+	case ALEAL:	/* lhs addr, rhs store */
+		if(copyas(&p->from, v))
+			return 2;
+
+
+	case ANOP:	/* rhs store */
+	case AMOVL:
+	case AMOVBLSX:
+	case AMOVBLZX:
+	case AMOVWLSX:
+	case AMOVWLZX:
+		if(copyas(&p->to, v)) {
+			if(s != A)
+				return copysub(&p->from, v, s, 1);
+			if(copyau(&p->from, v))
+				return 4;
+			return 3;
+		}
+		goto caseread;
+
+	case AROLB:
+	case AROLL:
+	case AROLW:
+	case ARORB:
+	case ARORL:
+	case ARORW:
+	case ASALB:
+	case ASALL:
+	case ASALW:
+	case ASARB:
+	case ASARL:
+	case ASARW:
+	case ASHLB:
+	case ASHLL:
+	case ASHLW:
+	case ASHRB:
+	case ASHRL:
+	case ASHRW:
+		if(copyas(&p->to, v))
+			return 2;
+		if(copyas(&p->from, v))
+			if(p->from.type == D_CX)
+				return 2;
+		goto caseread;
+
+	case AADDB:	/* rhs rar */
+	case AADDL:
+	case AADDW:
+	case AANDB:
+	case AANDL:
+	case AANDW:
+	case ADECL:
+	case ADECW:
+	case AINCL:
+	case AINCW:
+	case ASUBB:
+	case ASUBL:
+	case ASUBW:
+	case AORB:
+	case AORL:
+	case AORW:
+	case AXORB:
+	case AXORL:
+	case AXORW:
+	case AMOVB:
+	case AMOVW:
+
+	case AFMOVB:
+	case AFMOVBP:
+	case AFMOVD:
+	case AFMOVDP:
+	case AFMOVF:
+	case AFMOVFP:
+	case AFMOVL:
+	case AFMOVLP:
+	case AFMOVV:
+	case AFMOVVP:
+	case AFMOVW:
+	case AFMOVWP:
+	case AFMOVX:
+	case AFMOVXP:
+	case AFADDDP:
+	case AFADDW:
+	case AFADDL:
+	case AFADDF:
+	case AFADDD:
+	case AFMULDP:
+	case AFMULW:
+	case AFMULL:
+	case AFMULF:
+	case AFMULD:
+	case AFSUBDP:
+	case AFSUBW:
+	case AFSUBL:
+	case AFSUBF:
+	case AFSUBD:
+	case AFSUBRDP:
+	case AFSUBRW:
+	case AFSUBRL:
+	case AFSUBRF:
+	case AFSUBRD:
+	case AFDIVDP:
+	case AFDIVW:
+	case AFDIVL:
+	case AFDIVF:
+	case AFDIVD:
+	case AFDIVRDP:
+	case AFDIVRW:
+	case AFDIVRL:
+	case AFDIVRF:
+	case AFDIVRD:
+		if(copyas(&p->to, v))
+			return 2;
+		goto caseread;
+
+	case ACMPL:	/* read only */
+	case ACMPW:
+	case ACMPB:
+	
+	case APREFETCHT0:
+	case APREFETCHT1:
+	case APREFETCHT2:
+	case APREFETCHNTA:
+
+
+	case AFCOMB:
+	case AFCOMBP:
+	case AFCOMD:
+	case AFCOMDP:
+	case AFCOMDPP:
+	case AFCOMF:
+	case AFCOMFP:
+	case AFCOML:
+	case AFCOMLP:
+	case AFCOMW:
+	case AFCOMWP:
+	case AFUCOM:
+	case AFUCOMP:
+	case AFUCOMPP:
+	caseread:
+		if(s != A) {
+			if(copysub(&p->from, v, s, 1))
+				return 1;
+			return copysub(&p->to, v, s, 1);
+		}
+		if(copyau(&p->from, v))
+			return 1;
+		if(copyau(&p->to, v))
+			return 1;
+		break;
+
+	case AJGE:	/* no reference */
+	case AJNE:
+	case AJLE:
+	case AJEQ:
+	case AJHI:
+	case AJLS:
+	case AJMI:
+	case AJPL:
+	case AJGT:
+	case AJLT:
+	case AJCC:
+	case AJCS:
+
+	case AADJSP:
+	case AFLDZ:
+	case AWAIT:
+		break;
+
+	case AIMULL:
+	case AIMULW:
+		if(p->to.type != D_NONE) {
+			if(copyas(&p->to, v))
+				return 2;
+			goto caseread;
+		}
+
+	case ADIVB:
+	case ADIVL:
+	case ADIVW:
+	case AIDIVB:
+	case AIDIVL:
+	case AIDIVW:
+	case AIMULB:
+	case AMULB:
+	case AMULL:
+	case AMULW:
+
+	case ACWD:
+	case ACDQ:
+		if(v->type == D_AX || v->type == D_DX)
+			return 2;
+		goto caseread;
+
+	case AREP:
+	case AREPN:
+		if(v->type == D_CX)
+			return 2;
+		goto caseread;
+
+	case AMOVSB:
+	case AMOVSL:
+		if(v->type == D_DI || v->type == D_SI)
+			return 2;
+		goto caseread;
+
+	case ASTOSB:
+	case ASTOSL:
+		if(v->type == D_AX || v->type == D_DI)
+			return 2;
+		goto caseread;
+
+	case AFSTSW:
+		if(v->type == D_AX)
+			return 2;
+		goto caseread;
+
+	case AJMP:	/* funny */
+		if(s != A) {
+			if(copysub(&p->to, v, s, 1))
+				return 1;
+			return 0;
+		}
+		if(copyau(&p->to, v))
+			return 1;
+		return 0;
+
+	case ARET:	/* funny */
+		if(v->type == REGRET)
+			return 2;
+		if(s != A)
+			return 1;
+		return 3;
+
+	case ACALL:	/* funny */
+		if(REGARG >= 0 && v->type == (uchar)REGARG)
+			return 2;
+
+		if(s != A) {
+			if(copysub(&p->to, v, s, 1))
+				return 1;
+			return 0;
+		}
+		if(copyau(&p->to, v))
+			return 4;
+		return 3;
+	}
+	return 0;
+}
+
+/*
+ * direct reference,
+ * could be set/use depending on
+ * semantics
+ */
+int
+copyas(Addr *a, Addr *v)
+{
+	if(a->type != v->type)
+		return 0;
+	if(regtyp(v))
+		return 1;
+	if(v->type == D_AUTO || v->type == D_PARAM)
+		if(v->offset == a->offset)
+			return 1;
+	return 0;
+}
+
+/*
+ * either direct or indirect
+ */
+int
+copyau(Addr *a, Addr *v)
+{
+
+	if(copyas(a, v))
+		return 1;
+	if(regtyp(v)) {
+		if(a->type-D_INDIR == v->type)
+			return 1;
+		if(a->index == v->type)
+			return 1;
+	}
+	return 0;
+}
+
+/*
+ * substitute s for v in a
+ * return failure to substitute
+ */
+int
+copysub(Addr *a, Addr *v, Addr *s, int f)
+{
+	int t;
+
+	if(copyas(a, v)) {
+		t = s->type;
+		if(t >= D_AX && t <= D_DI) {
+			if(f)
+				a->type = t;
+		}
+		return 0;
+	}
+	if(regtyp(v)) {
+		t = v->type;
+		if(a->type == t+D_INDIR) {
+			if(s->type == D_BP && a->index != D_NONE)
+				return 1;	/* can't use BP-base with index */
+			if(f)
+				a->type = s->type+D_INDIR;
+//			return 0;
+		}
+		if(a->index == t) {
+			if(f)
+				a->index = s->type;
+			return 0;
+		}
+		return 0;
+	}
+	return 0;
+}
diff --git a/src/cmd/8c/reg.c b/src/cmd/8c/reg.c
new file mode 100644
index 0000000..ea862f3
--- /dev/null
+++ b/src/cmd/8c/reg.c
@@ -0,0 +1,1438 @@
+// Inferno utils/8c/reg.c
+// http://code.google.com/p/inferno-os/source/browse/utils/8c/reg.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 "gc.h"
+
+static	void	fixjmp(Reg*);
+
+Reg*
+rega(void)
+{
+	Reg *r;
+
+	r = freer;
+	if(r == R) {
+		r = alloc(sizeof(*r));
+	} else
+		freer = r->link;
+
+	*r = zreg;
+	return r;
+}
+
+int
+rcmp(const void *a1, const void *a2)
+{
+	Rgn *p1, *p2;
+	int c1, c2;
+
+	p1 = (Rgn*)a1;
+	p2 = (Rgn*)a2;
+	c1 = p2->cost;
+	c2 = p1->cost;
+	if(c1 -= c2)
+		return c1;
+	return p2->varno - p1->varno;
+}
+
+void
+regopt(Prog *p)
+{
+	Reg *r, *r1, *r2;
+	Prog *p1;
+	int i, z;
+	int32 initpc, val, npc;
+	uint32 vreg;
+	Bits bit;
+	struct
+	{
+		int32	m;
+		int32	c;
+		Reg*	p;
+	} log5[6], *lp;
+
+	firstr = R;
+	lastr = R;
+	nvar = 0;
+	regbits = RtoB(D_SP) | RtoB(D_AX);
+	for(z=0; z<BITS; z++) {
+		externs.b[z] = 0;
+		params.b[z] = 0;
+		consts.b[z] = 0;
+		addrs.b[z] = 0;
+	}
+
+	/*
+	 * pass 1
+	 * build aux data structure
+	 * allocate pcs
+	 * find use and set of variables
+	 */
+	val = 5L * 5L * 5L * 5L * 5L;
+	lp = log5;
+	for(i=0; i<5; i++) {
+		lp->m = val;
+		lp->c = 0;
+		lp->p = R;
+		val /= 5L;
+		lp++;
+	}
+	val = 0;
+	for(; p != P; p = p->link) {
+		switch(p->as) {
+		case ADATA:
+		case AGLOBL:
+		case ANAME:
+		case ASIGNAME:
+		case AFUNCDATA:
+			continue;
+		}
+		r = rega();
+		if(firstr == R) {
+			firstr = r;
+			lastr = r;
+		} else {
+			lastr->link = r;
+			r->p1 = lastr;
+			lastr->s1 = r;
+			lastr = r;
+		}
+		r->prog = p;
+		r->pc = val;
+		val++;
+
+		lp = log5;
+		for(i=0; i<5; i++) {
+			lp->c--;
+			if(lp->c <= 0) {
+				lp->c = lp->m;
+				if(lp->p != R)
+					lp->p->log5 = r;
+				lp->p = r;
+				(lp+1)->c = 0;
+				break;
+			}
+			lp++;
+		}
+
+		r1 = r->p1;
+		if(r1 != R)
+		switch(r1->prog->as) {
+		case ARET:
+		case AJMP:
+		case AIRETL:
+			r->p1 = R;
+			r1->s1 = R;
+		}
+		bit = mkvar(r, &p->from);
+		if(bany(&bit))
+		switch(p->as) {
+		/*
+		 * funny
+		 */
+		case ALEAL:
+			for(z=0; z<BITS; z++)
+				addrs.b[z] |= bit.b[z];
+			break;
+
+		/*
+		 * left side read
+		 */
+		default:
+			for(z=0; z<BITS; z++)
+				r->use1.b[z] |= bit.b[z];
+			break;
+		}
+
+		bit = mkvar(r, &p->to);
+		if(bany(&bit))
+		switch(p->as) {
+		default:
+			diag(Z, "reg: unknown op: %A", p->as);
+			break;
+
+		/*
+		 * right side read
+		 */
+		case ACMPB:
+		case ACMPL:
+		case ACMPW:
+		case APREFETCHT0:
+		case APREFETCHT1:
+		case APREFETCHT2:
+		case APREFETCHNTA:
+			for(z=0; z<BITS; z++)
+				r->use2.b[z] |= bit.b[z];
+			break;
+
+		/*
+		 * right side write
+		 */
+		case ANOP:
+		case AMOVL:
+		case AMOVB:
+		case AMOVW:
+		case AMOVBLSX:
+		case AMOVBLZX:
+		case AMOVWLSX:
+		case AMOVWLZX:
+			for(z=0; z<BITS; z++)
+				r->set.b[z] |= bit.b[z];
+			break;
+
+		/*
+		 * right side read+write
+		 */
+		case AADDB:
+		case AADDL:
+		case AADDW:
+		case AANDB:
+		case AANDL:
+		case AANDW:
+		case ASUBB:
+		case ASUBL:
+		case ASUBW:
+		case AORB:
+		case AORL:
+		case AORW:
+		case AXORB:
+		case AXORL:
+		case AXORW:
+		case ASALB:
+		case ASALL:
+		case ASALW:
+		case ASARB:
+		case ASARL:
+		case ASARW:
+		case AROLB:
+		case AROLL:
+		case AROLW:
+		case ARORB:
+		case ARORL:
+		case ARORW:
+		case ASHLB:
+		case ASHLL:
+		case ASHLW:
+		case ASHRB:
+		case ASHRL:
+		case ASHRW:
+		case AIMULL:
+		case AIMULW:
+		case ANEGL:
+		case ANOTL:
+		case AADCL:
+		case ASBBL:
+			for(z=0; z<BITS; z++) {
+				r->set.b[z] |= bit.b[z];
+				r->use2.b[z] |= bit.b[z];
+			}
+			break;
+
+		/*
+		 * funny
+		 */
+		case AFMOVDP:
+		case AFMOVFP:
+		case AFMOVLP:
+		case AFMOVVP:
+		case AFMOVWP:
+		case ACALL:
+			for(z=0; z<BITS; z++)
+				addrs.b[z] |= bit.b[z];
+			break;
+		}
+
+		switch(p->as) {
+		case AIMULL:
+		case AIMULW:
+			if(p->to.type != D_NONE)
+				break;
+
+		case AIDIVB:
+		case AIDIVL:
+		case AIDIVW:
+		case AIMULB:
+		case ADIVB:
+		case ADIVL:
+		case ADIVW:
+		case AMULB:
+		case AMULL:
+		case AMULW:
+
+		case ACWD:
+		case ACDQ:
+			r->regu |= RtoB(D_AX) | RtoB(D_DX);
+			break;
+
+		case AREP:
+		case AREPN:
+		case ALOOP:
+		case ALOOPEQ:
+		case ALOOPNE:
+			r->regu |= RtoB(D_CX);
+			break;
+
+		case AMOVSB:
+		case AMOVSL:
+		case AMOVSW:
+		case ACMPSB:
+		case ACMPSL:
+		case ACMPSW:
+			r->regu |= RtoB(D_SI) | RtoB(D_DI);
+			break;
+
+		case ASTOSB:
+		case ASTOSL:
+		case ASTOSW:
+		case ASCASB:
+		case ASCASL:
+		case ASCASW:
+			r->regu |= RtoB(D_AX) | RtoB(D_DI);
+			break;
+
+		case AINSB:
+		case AINSL:
+		case AINSW:
+		case AOUTSB:
+		case AOUTSL:
+		case AOUTSW:
+			r->regu |= RtoB(D_DI) | RtoB(D_DX);
+			break;
+
+		case AFSTSW:
+		case ASAHF:
+			r->regu |= RtoB(D_AX);
+			break;
+		}
+	}
+	if(firstr == R)
+		return;
+	initpc = pc - val;
+	npc = val;
+
+	/*
+	 * pass 2
+	 * turn branch references to pointers
+	 * build back pointers
+	 */
+	for(r = firstr; r != R; r = r->link) {
+		p = r->prog;
+		if(p->to.type == D_BRANCH) {
+			val = p->to.offset - initpc;
+			r1 = firstr;
+			while(r1 != R) {
+				r2 = r1->log5;
+				if(r2 != R && val >= r2->pc) {
+					r1 = r2;
+					continue;
+				}
+				if(r1->pc == val)
+					break;
+				r1 = r1->link;
+			}
+			if(r1 == R) {
+				nearln = p->lineno;
+				diag(Z, "ref not found\n%P", p);
+				continue;
+			}
+			if(r1 == r) {
+				nearln = p->lineno;
+				diag(Z, "ref to self\n%P", p);
+				continue;
+			}
+			r->s2 = r1;
+			r->p2link = r1->p2;
+			r1->p2 = r;
+		}
+	}
+	if(debug['R']) {
+		p = firstr->prog;
+		print("\n%L %D\n", p->lineno, &p->from);
+	}
+
+	/*
+	 * pass 2.1
+	 * fix jumps
+	 */
+	fixjmp(firstr);
+
+	/*
+	 * pass 2.5
+	 * find looping structure
+	 */
+	for(r = firstr; r != R; r = r->link)
+		r->active = 0;
+	change = 0;
+	loopit(firstr, npc);
+	if(debug['R'] && debug['v']) {
+		print("\nlooping structure:\n");
+		for(r = firstr; r != R; r = r->link) {
+			print("%d:%P", r->loop, r->prog);
+			for(z=0; z<BITS; z++)
+				bit.b[z] = r->use1.b[z] |
+					   r->use2.b[z] |
+					   r->set.b[z];
+			if(bany(&bit)) {
+				print("\t");
+				if(bany(&r->use1))
+					print(" u1=%B", r->use1);
+				if(bany(&r->use2))
+					print(" u2=%B", r->use2);
+				if(bany(&r->set))
+					print(" st=%B", r->set);
+			}
+			print("\n");
+		}
+	}
+
+	/*
+	 * pass 3
+	 * iterate propagating usage
+	 * 	back until flow graph is complete
+	 */
+loop1:
+	change = 0;
+	for(r = firstr; r != R; r = r->link)
+		r->active = 0;
+	for(r = firstr; r != R; r = r->link)
+		if(r->prog->as == ARET)
+			prop(r, zbits, zbits);
+loop11:
+	/* pick up unreachable code */
+	i = 0;
+	for(r = firstr; r != R; r = r1) {
+		r1 = r->link;
+		if(r1 && r1->active && !r->active) {
+			prop(r, zbits, zbits);
+			i = 1;
+		}
+	}
+	if(i)
+		goto loop11;
+	if(change)
+		goto loop1;
+
+
+	/*
+	 * pass 4
+	 * iterate propagating register/variable synchrony
+	 * 	forward until graph is complete
+	 */
+loop2:
+	change = 0;
+	for(r = firstr; r != R; r = r->link)
+		r->active = 0;
+	synch(firstr, zbits);
+	if(change)
+		goto loop2;
+
+
+	/*
+	 * pass 5
+	 * isolate regions
+	 * calculate costs (paint1)
+	 */
+	r = firstr;
+	if(r) {
+		for(z=0; z<BITS; z++)
+			bit.b[z] = (r->refahead.b[z] | r->calahead.b[z]) &
+			  ~(externs.b[z] | params.b[z] | addrs.b[z] | consts.b[z]);
+		if(bany(&bit)) {
+			nearln = r->prog->lineno;
+			warn(Z, "used and not set: %B", bit);
+			if(debug['R'] && !debug['w'])
+				print("used and not set: %B\n", bit);
+		}
+	}
+	if(debug['R'] && debug['v'])
+		print("\nprop structure:\n");
+	for(r = firstr; r != R; r = r->link)
+		r->act = zbits;
+	rgp = region;
+	nregion = 0;
+	for(r = firstr; r != R; r = r->link) {
+		if(debug['R'] && debug['v']) {
+			print("%P\t", r->prog);
+			if(bany(&r->set))
+				print("s:%B ", r->set);
+			if(bany(&r->refahead))
+				print("ra:%B ", r->refahead);
+			if(bany(&r->calahead))
+				print("ca:%B ", r->calahead);
+			print("\n");
+		}
+		for(z=0; z<BITS; z++)
+			bit.b[z] = r->set.b[z] &
+			  ~(r->refahead.b[z] | r->calahead.b[z] | addrs.b[z]);
+		if(bany(&bit)) {
+			nearln = r->prog->lineno;
+			warn(Z, "set and not used: %B", bit);
+			if(debug['R'])
+				print("set and not used: %B\n", bit);
+			excise(r);
+		}
+		for(z=0; z<BITS; z++)
+			bit.b[z] = LOAD(r) & ~(r->act.b[z] | addrs.b[z]);
+		while(bany(&bit)) {
+			i = bnum(bit);
+			rgp->enter = r;
+			rgp->varno = i;
+			change = 0;
+			if(debug['R'] && debug['v'])
+				print("\n");
+			paint1(r, i);
+			bit.b[i/32] &= ~(1L<<(i%32));
+			if(change <= 0) {
+				if(debug['R'])
+					print("%L$%d: %B\n",
+						r->prog->lineno, change, blsh(i));
+				continue;
+			}
+			rgp->cost = change;
+			nregion++;
+			if(nregion >= NRGN) {
+				fatal(Z, "too many regions");
+				goto brk;
+			}
+			rgp++;
+		}
+	}
+brk:
+	qsort(region, nregion, sizeof(region[0]), rcmp);
+
+	/*
+	 * pass 6
+	 * determine used registers (paint2)
+	 * replace code (paint3)
+	 */
+	rgp = region;
+	for(i=0; i<nregion; i++) {
+		bit = blsh(rgp->varno);
+		vreg = paint2(rgp->enter, rgp->varno);
+		vreg = allreg(vreg, rgp);
+		if(debug['R']) {
+			print("%L$%d %R: %B\n",
+				rgp->enter->prog->lineno,
+				rgp->cost,
+				rgp->regno,
+				bit);
+		}
+		if(rgp->regno != 0)
+			paint3(rgp->enter, rgp->varno, vreg, rgp->regno);
+		rgp++;
+	}
+	/*
+	 * pass 7
+	 * peep-hole on basic block
+	 */
+	if(!debug['R'] || debug['P'])
+		peep();
+
+	if(debug['R'] && debug['v']) {
+		print("after pass 7 (peep)\n");
+		for(r=firstr; r; r=r->link)
+			print("%04d %P\n", (int)r->pc, r->prog);
+		print("\n");
+	}
+
+	/*
+	 * pass 8
+	 * recalculate pc
+	 */
+	val = initpc;
+	for(r = firstr; r != R; r = r1) {
+		r->pc = val;
+		p = r->prog;
+		p1 = P;
+		r1 = r->link;
+		if(r1 != R)
+			p1 = r1->prog;
+		for(; p != p1; p = p->link) {
+			switch(p->as) {
+			default:
+				val++;
+				break;
+
+			case ANOP:
+			case ADATA:
+			case AGLOBL:
+			case ANAME:
+			case ASIGNAME:
+			case AFUNCDATA:
+				break;
+			}
+		}
+	}
+	pc = val;
+
+	/*
+	 * fix up branches
+	 */
+	if(debug['R'])
+		if(bany(&addrs))
+			print("addrs: %B\n", addrs);
+
+	r1 = 0; /* set */
+	for(r = firstr; r != R; r = r->link) {
+		p = r->prog;
+		if(p->to.type == D_BRANCH) {
+			p->to.offset = r->s2->pc;
+			p->to.u.branch = r->s2->prog;
+		}
+		r1 = r;
+	}
+
+	/*
+	 * last pass
+	 * eliminate nops
+	 * free aux structures
+	 */
+	for(p = firstr->prog; p != P; p = p->link){
+		while(p->link && p->link->as == ANOP)
+			p->link = p->link->link;
+	}
+
+	if(debug['R'] && debug['v']) {
+		print("after pass 8 (fixup pc)\n");
+		for(p1=firstr->prog; p1!=P; p1=p1->link)
+			print("%P\n", p1);
+		print("\n");
+	}
+
+	if(r1 != R) {
+		r1->link = freer;
+		freer = firstr;
+	}
+}
+
+/*
+ * add mov b,rn
+ * just after r
+ */
+void
+addmove(Reg *r, int bn, int rn, int f)
+{
+	Prog *p, *p1;
+	Addr *a;
+	Var *v;
+
+	p1 = alloc(sizeof(*p1));
+	*p1 = zprog;
+	p = r->prog;
+
+	p1->link = p->link;
+	p->link = p1;
+	p1->lineno = p->lineno;
+
+	v = var + bn;
+
+	a = &p1->to;
+	a->sym = v->sym;
+	a->offset = v->offset;
+	a->etype = v->etype;
+	a->type = v->name;
+
+	p1->as = AMOVL;
+	if(v->etype == TCHAR || v->etype == TUCHAR)
+		p1->as = AMOVB;
+	if(v->etype == TSHORT || v->etype == TUSHORT)
+		p1->as = AMOVW;
+
+	p1->from.type = rn;
+	if(!f) {
+		p1->from = *a;
+		*a = zprog.from;
+		a->type = rn;
+		if(v->etype == TUCHAR)
+			p1->as = AMOVB;
+		if(v->etype == TUSHORT)
+			p1->as = AMOVW;
+	}
+	if(debug['R'])
+		print("%P\t.a%P\n", p, p1);
+}
+
+uint32
+doregbits(int r)
+{
+	uint32 b;
+
+	b = 0;
+	if(r >= D_INDIR)
+		r -= D_INDIR;
+	if(r >= D_AX && r <= D_DI)
+		b |= RtoB(r);
+	else
+	if(r >= D_AL && r <= D_BL)
+		b |= RtoB(r-D_AL+D_AX);
+	else
+	if(r >= D_AH && r <= D_BH)
+		b |= RtoB(r-D_AH+D_AX);
+	return b;
+}
+
+Bits
+mkvar(Reg *r, Addr *a)
+{
+	Var *v;
+	int i, t, n, et, z;
+	int32 o;
+	Bits bit;
+	LSym *s;
+
+	/*
+	 * mark registers used
+	 */
+	t = a->type;
+	r->regu |= doregbits(t);
+	r->regu |= doregbits(a->index);
+
+	switch(t) {
+	default:
+		goto none;
+	case D_ADDR:
+		a->type = a->index;
+		bit = mkvar(r, a);
+		for(z=0; z<BITS; z++)
+			addrs.b[z] |= bit.b[z];
+		a->type = t;
+		goto none;
+	case D_EXTERN:
+	case D_STATIC:
+	case D_PARAM:
+	case D_AUTO:
+		n = t;
+		break;
+	}
+	s = a->sym;
+	if(s == nil)
+		goto none;
+	if(s->name[0] == '.')
+		goto none;
+	et = a->etype;
+	o = a->offset;
+	v = var;
+	for(i=0; i<nvar; i++) {
+		if(s == v->sym)
+		if(n == v->name)
+		if(o == v->offset)
+			goto out;
+		v++;
+	}
+	if(nvar >= NVAR)
+		fatal(Z, "variable not optimized: %s", s->name);
+	i = nvar;
+	nvar++;
+	v = &var[i];
+	v->sym = s;
+	v->offset = o;
+	v->name = n;
+	v->etype = et;
+	if(debug['R'])
+		print("bit=%2d et=%2d %D\n", i, et, a);
+
+out:
+	bit = blsh(i);
+	if(n == D_EXTERN || n == D_STATIC)
+		for(z=0; z<BITS; z++)
+			externs.b[z] |= bit.b[z];
+	if(n == D_PARAM)
+		for(z=0; z<BITS; z++)
+			params.b[z] |= bit.b[z];
+	if(v->etype != et || !typechlpfd[et])	/* funny punning */
+		for(z=0; z<BITS; z++)
+			addrs.b[z] |= bit.b[z];
+	return bit;
+
+none:
+	return zbits;
+}
+
+void
+prop(Reg *r, Bits ref, Bits cal)
+{
+	Reg *r1, *r2;
+	int z;
+
+	for(r1 = r; r1 != R; r1 = r1->p1) {
+		for(z=0; z<BITS; z++) {
+			ref.b[z] |= r1->refahead.b[z];
+			if(ref.b[z] != r1->refahead.b[z]) {
+				r1->refahead.b[z] = ref.b[z];
+				change++;
+			}
+			cal.b[z] |= r1->calahead.b[z];
+			if(cal.b[z] != r1->calahead.b[z]) {
+				r1->calahead.b[z] = cal.b[z];
+				change++;
+			}
+		}
+		switch(r1->prog->as) {
+		case ACALL:
+			for(z=0; z<BITS; z++) {
+				cal.b[z] |= ref.b[z] | externs.b[z];
+				ref.b[z] = 0;
+			}
+			break;
+
+		case ATEXT:
+			for(z=0; z<BITS; z++) {
+				cal.b[z] = 0;
+				ref.b[z] = 0;
+			}
+			break;
+
+		case ARET:
+			for(z=0; z<BITS; z++) {
+				cal.b[z] = externs.b[z];
+				ref.b[z] = 0;
+			}
+		}
+		for(z=0; z<BITS; z++) {
+			ref.b[z] = (ref.b[z] & ~r1->set.b[z]) |
+				r1->use1.b[z] | r1->use2.b[z];
+			cal.b[z] &= ~(r1->set.b[z] | r1->use1.b[z] | r1->use2.b[z]);
+			r1->refbehind.b[z] = ref.b[z];
+			r1->calbehind.b[z] = cal.b[z];
+		}
+		if(r1->active)
+			break;
+		r1->active = 1;
+	}
+	for(; r != r1; r = r->p1)
+		for(r2 = r->p2; r2 != R; r2 = r2->p2link)
+			prop(r2, r->refbehind, r->calbehind);
+}
+
+/*
+ * find looping structure
+ *
+ * 1) find reverse postordering
+ * 2) find approximate dominators,
+ *	the actual dominators if the flow graph is reducible
+ *	otherwise, dominators plus some other non-dominators.
+ *	See Matthew S. Hecht and Jeffrey D. Ullman,
+ *	"Analysis of a Simple Algorithm for Global Data Flow Problems",
+ *	Conf.  Record of ACM Symp. on Principles of Prog. Langs, Boston, Massachusetts,
+ *	Oct. 1-3, 1973, pp.  207-217.
+ * 3) find all nodes with a predecessor dominated by the current node.
+ *	such a node is a loop head.
+ *	recursively, all preds with a greater rpo number are in the loop
+ */
+int32
+postorder(Reg *r, Reg **rpo2r, int32 n)
+{
+	Reg *r1;
+
+	r->rpo = 1;
+	r1 = r->s1;
+	if(r1 && !r1->rpo)
+		n = postorder(r1, rpo2r, n);
+	r1 = r->s2;
+	if(r1 && !r1->rpo)
+		n = postorder(r1, rpo2r, n);
+	rpo2r[n] = r;
+	n++;
+	return n;
+}
+
+int32
+rpolca(int32 *idom, int32 rpo1, int32 rpo2)
+{
+	int32 t;
+
+	if(rpo1 == -1)
+		return rpo2;
+	while(rpo1 != rpo2){
+		if(rpo1 > rpo2){
+			t = rpo2;
+			rpo2 = rpo1;
+			rpo1 = t;
+		}
+		while(rpo1 < rpo2){
+			t = idom[rpo2];
+			if(t >= rpo2)
+				fatal(Z, "bad idom");
+			rpo2 = t;
+		}
+	}
+	return rpo1;
+}
+
+int
+doms(int32 *idom, int32 r, int32 s)
+{
+	while(s > r)
+		s = idom[s];
+	return s == r;
+}
+
+int
+loophead(int32 *idom, Reg *r)
+{
+	int32 src;
+
+	src = r->rpo;
+	if(r->p1 != R && doms(idom, src, r->p1->rpo))
+		return 1;
+	for(r = r->p2; r != R; r = r->p2link)
+		if(doms(idom, src, r->rpo))
+			return 1;
+	return 0;
+}
+
+void
+loopmark(Reg **rpo2r, int32 head, Reg *r)
+{
+	if(r->rpo < head || r->active == head)
+		return;
+	r->active = head;
+	r->loop += LOOP;
+	if(r->p1 != R)
+		loopmark(rpo2r, head, r->p1);
+	for(r = r->p2; r != R; r = r->p2link)
+		loopmark(rpo2r, head, r);
+}
+
+void
+loopit(Reg *r, int32 nr)
+{
+	Reg *r1;
+	int32 i, d, me;
+
+	if(nr > maxnr) {
+		rpo2r = alloc(nr * sizeof(Reg*));
+		idom = alloc(nr * sizeof(int32));
+		maxnr = nr;
+	}
+
+	d = postorder(r, rpo2r, 0);
+	if(d > nr)
+		fatal(Z, "too many reg nodes");
+	nr = d;
+	for(i = 0; i < nr / 2; i++){
+		r1 = rpo2r[i];
+		rpo2r[i] = rpo2r[nr - 1 - i];
+		rpo2r[nr - 1 - i] = r1;
+	}
+	for(i = 0; i < nr; i++)
+		rpo2r[i]->rpo = i;
+
+	idom[0] = 0;
+	for(i = 0; i < nr; i++){
+		r1 = rpo2r[i];
+		me = r1->rpo;
+		d = -1;
+		if(r1->p1 != R && r1->p1->rpo < me)
+			d = r1->p1->rpo;
+		for(r1 = r1->p2; r1 != nil; r1 = r1->p2link)
+			if(r1->rpo < me)
+				d = rpolca(idom, d, r1->rpo);
+		idom[i] = d;
+	}
+
+	for(i = 0; i < nr; i++){
+		r1 = rpo2r[i];
+		r1->loop++;
+		if(r1->p2 != R && loophead(idom, r1))
+			loopmark(rpo2r, i, r1);
+	}
+}
+
+void
+synch(Reg *r, Bits dif)
+{
+	Reg *r1;
+	int z;
+
+	for(r1 = r; r1 != R; r1 = r1->s1) {
+		for(z=0; z<BITS; z++) {
+			dif.b[z] = (dif.b[z] &
+				~(~r1->refbehind.b[z] & r1->refahead.b[z])) |
+					r1->set.b[z] | r1->regdiff.b[z];
+			if(dif.b[z] != r1->regdiff.b[z]) {
+				r1->regdiff.b[z] = dif.b[z];
+				change++;
+			}
+		}
+		if(r1->active)
+			break;
+		r1->active = 1;
+		for(z=0; z<BITS; z++)
+			dif.b[z] &= ~(~r1->calbehind.b[z] & r1->calahead.b[z]);
+		if(r1->s2 != R)
+			synch(r1->s2, dif);
+	}
+}
+
+uint32
+allreg(uint32 b, Rgn *r)
+{
+	Var *v;
+	int i;
+
+	v = var + r->varno;
+	r->regno = 0;
+	switch(v->etype) {
+
+	default:
+		diag(Z, "unknown etype %d/%d", bitno(b), v->etype);
+		break;
+
+	case TCHAR:
+	case TUCHAR:
+	case TSHORT:
+	case TUSHORT:
+	case TINT:
+	case TUINT:
+	case TLONG:
+	case TULONG:
+	case TIND:
+	case TARRAY:
+		i = BtoR(~b);
+		if(i && r->cost > 0) {
+			r->regno = i;
+			return RtoB(i);
+		}
+		break;
+
+	case TDOUBLE:
+	case TFLOAT:
+		break;
+	}
+	return 0;
+}
+
+void
+paint1(Reg *r, int bn)
+{
+	Reg *r1;
+	Prog *p;
+	int z;
+	uint32 bb;
+
+	z = bn/32;
+	bb = 1L<<(bn%32);
+	if(r->act.b[z] & bb)
+		return;
+	for(;;) {
+		if(!(r->refbehind.b[z] & bb))
+			break;
+		r1 = r->p1;
+		if(r1 == R)
+			break;
+		if(!(r1->refahead.b[z] & bb))
+			break;
+		if(r1->act.b[z] & bb)
+			break;
+		r = r1;
+	}
+
+	if(LOAD(r) & ~(r->set.b[z]&~(r->use1.b[z]|r->use2.b[z])) & bb) {
+		change -= CLOAD * r->loop;
+		if(debug['R'] && debug['v'])
+			print("%d%P\td %B $%d\n", r->loop,
+				r->prog, blsh(bn), change);
+	}
+	for(;;) {
+		r->act.b[z] |= bb;
+		p = r->prog;
+
+		if(r->use1.b[z] & bb) {
+			change += CREF * r->loop;
+			if(p->as == AFMOVL)
+				if(BtoR(bb) != D_F0)
+					change = -CINF;
+			if(debug['R'] && debug['v'])
+				print("%d%P\tu1 %B $%d\n", r->loop,
+					p, blsh(bn), change);
+		}
+
+		if((r->use2.b[z]|r->set.b[z]) & bb) {
+			change += CREF * r->loop;
+			if(p->as == AFMOVL)
+				if(BtoR(bb) != D_F0)
+					change = -CINF;
+			if(debug['R'] && debug['v'])
+				print("%d%P\tu2 %B $%d\n", r->loop,
+					p, blsh(bn), change);
+		}
+
+		if(STORE(r) & r->regdiff.b[z] & bb) {
+			change -= CLOAD * r->loop;
+			if(p->as == AFMOVL)
+				if(BtoR(bb) != D_F0)
+					change = -CINF;
+			if(debug['R'] && debug['v'])
+				print("%d%P\tst %B $%d\n", r->loop,
+					p, blsh(bn), change);
+		}
+
+		if(r->refbehind.b[z] & bb)
+			for(r1 = r->p2; r1 != R; r1 = r1->p2link)
+				if(r1->refahead.b[z] & bb)
+					paint1(r1, bn);
+
+		if(!(r->refahead.b[z] & bb))
+			break;
+		r1 = r->s2;
+		if(r1 != R)
+			if(r1->refbehind.b[z] & bb)
+				paint1(r1, bn);
+		r = r->s1;
+		if(r == R)
+			break;
+		if(r->act.b[z] & bb)
+			break;
+		if(!(r->refbehind.b[z] & bb))
+			break;
+	}
+}
+
+uint32
+regset(Reg *r, uint32 bb)
+{
+	uint32 b, set;
+	Addr v;
+	int c;
+
+	set = 0;
+	v = zprog.from;
+	while(b = bb & ~(bb-1)) {
+		v.type = BtoR(b);
+		c = copyu(r->prog, &v, A);
+		if(c == 3)
+			set |= b;
+		bb &= ~b;
+	}
+	return set;
+}
+
+uint32
+reguse(Reg *r, uint32 bb)
+{
+	uint32 b, set;
+	Addr v;
+	int c;
+
+	set = 0;
+	v = zprog.from;
+	while(b = bb & ~(bb-1)) {
+		v.type = BtoR(b);
+		c = copyu(r->prog, &v, A);
+		if(c == 1 || c == 2 || c == 4)
+			set |= b;
+		bb &= ~b;
+	}
+	return set;
+}
+
+uint32
+paint2(Reg *r, int bn)
+{
+	Reg *r1;
+	int z;
+	uint32 bb, vreg, x;
+
+	z = bn/32;
+	bb = 1L << (bn%32);
+	vreg = regbits;
+	if(!(r->act.b[z] & bb))
+		return vreg;
+	for(;;) {
+		if(!(r->refbehind.b[z] & bb))
+			break;
+		r1 = r->p1;
+		if(r1 == R)
+			break;
+		if(!(r1->refahead.b[z] & bb))
+			break;
+		if(!(r1->act.b[z] & bb))
+			break;
+		r = r1;
+	}
+	for(;;) {
+		r->act.b[z] &= ~bb;
+
+		vreg |= r->regu;
+
+		if(r->refbehind.b[z] & bb)
+			for(r1 = r->p2; r1 != R; r1 = r1->p2link)
+				if(r1->refahead.b[z] & bb)
+					vreg |= paint2(r1, bn);
+
+		if(!(r->refahead.b[z] & bb))
+			break;
+		r1 = r->s2;
+		if(r1 != R)
+			if(r1->refbehind.b[z] & bb)
+				vreg |= paint2(r1, bn);
+		r = r->s1;
+		if(r == R)
+			break;
+		if(!(r->act.b[z] & bb))
+			break;
+		if(!(r->refbehind.b[z] & bb))
+			break;
+	}
+
+	bb = vreg;
+	for(; r; r=r->s1) {
+		x = r->regu & ~bb;
+		if(x) {
+			vreg |= reguse(r, x);
+			bb |= regset(r, x);
+		}
+	}
+	return vreg;
+}
+
+void
+paint3(Reg *r, int bn, int32 rb, int rn)
+{
+	Reg *r1;
+	Prog *p;
+	int z;
+	uint32 bb;
+
+	z = bn/32;
+	bb = 1L << (bn%32);
+	if(r->act.b[z] & bb)
+		return;
+	for(;;) {
+		if(!(r->refbehind.b[z] & bb))
+			break;
+		r1 = r->p1;
+		if(r1 == R)
+			break;
+		if(!(r1->refahead.b[z] & bb))
+			break;
+		if(r1->act.b[z] & bb)
+			break;
+		r = r1;
+	}
+
+	if(LOAD(r) & ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z])) & bb)
+		addmove(r, bn, rn, 0);
+	for(;;) {
+		r->act.b[z] |= bb;
+		p = r->prog;
+
+		if(r->use1.b[z] & bb) {
+			if(debug['R'])
+				print("%P", p);
+			addreg(&p->from, rn);
+			if(debug['R'])
+				print("\t.c%P\n", p);
+		}
+		if((r->use2.b[z]|r->set.b[z]) & bb) {
+			if(debug['R'])
+				print("%P", p);
+			addreg(&p->to, rn);
+			if(debug['R'])
+				print("\t.c%P\n", p);
+		}
+
+		if(STORE(r) & r->regdiff.b[z] & bb)
+			addmove(r, bn, rn, 1);
+		r->regu |= rb;
+
+		if(r->refbehind.b[z] & bb)
+			for(r1 = r->p2; r1 != R; r1 = r1->p2link)
+				if(r1->refahead.b[z] & bb)
+					paint3(r1, bn, rb, rn);
+
+		if(!(r->refahead.b[z] & bb))
+			break;
+		r1 = r->s2;
+		if(r1 != R)
+			if(r1->refbehind.b[z] & bb)
+				paint3(r1, bn, rb, rn);
+		r = r->s1;
+		if(r == R)
+			break;
+		if(r->act.b[z] & bb)
+			break;
+		if(!(r->refbehind.b[z] & bb))
+			break;
+	}
+}
+
+void
+addreg(Addr *a, int rn)
+{
+
+	a->sym = 0;
+	a->offset = 0;
+	a->type = rn;
+}
+
+int32
+RtoB(int r)
+{
+
+	if(r < D_AX || r > D_DI)
+		return 0;
+	return 1L << (r-D_AX);
+}
+
+int
+BtoR(int32 b)
+{
+
+	b &= 0xffL;
+	if(b == 0)
+		return 0;
+	return bitno(b) + D_AX;
+}
+
+/* what instruction does a JMP to p eventually land on? */
+static Reg*
+chasejmp(Reg *r, int *jmploop)
+{
+	int n;
+
+	n = 0;
+	for(; r; r=r->s2) {
+		if(r->prog->as != AJMP || r->prog->to.type != D_BRANCH)
+			break;
+		if(++n > 10) {
+			*jmploop = 1;
+			break;
+		}
+	}
+	return r;
+}
+
+/* mark all code reachable from firstp as alive */
+static void
+mark(Reg *firstr)
+{
+	Reg *r;
+	Prog *p;
+
+	for(r=firstr; r; r=r->link) {
+		if(r->active)
+			break;
+		r->active = 1;
+		p = r->prog;
+		if(p->as != ACALL && p->to.type == D_BRANCH)
+			mark(r->s2);
+		if(p->as == AJMP || p->as == ARET || p->as == AUNDEF)
+			break;
+	}
+}
+
+/*
+ * the code generator depends on being able to write out JMP
+ * instructions that it can jump to now but fill in later.
+ * the linker will resolve them nicely, but they make the code
+ * longer and more difficult to follow during debugging.
+ * remove them.
+ */
+static void
+fixjmp(Reg *firstr)
+{
+	int jmploop;
+	Reg *r;
+	Prog *p;
+
+	if(debug['R'] && debug['v'])
+		print("\nfixjmp\n");
+
+	// pass 1: resolve jump to AJMP, mark all code as dead.
+	jmploop = 0;
+	for(r=firstr; r; r=r->link) {
+		p = r->prog;
+		if(debug['R'] && debug['v'])
+			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);
+		}
+		r->active = 0;
+	}
+	if(debug['R'] && debug['v'])
+		print("\n");
+
+	// pass 2: mark all reachable code alive
+	mark(firstr);
+
+	// pass 3: delete dead code (mostly JMPs).
+	for(r=firstr; r; r=r->link) {
+		if(!r->active) {
+			p = r->prog;
+			if(p->link == P && p->as == ARET && r->p1 && r->p1->prog->as != ARET) {
+				// This is the final ARET, and the code so far doesn't have one.
+				// Let it stay.
+			} else {
+				if(debug['R'] && debug['v'])
+					print("del %04d %P\n", (int)r->pc, p);
+				p->as = ANOP;
+			}
+		}
+	}
+
+	// pass 4: elide JMP to next instruction.
+	// only safe if there are no jumps to JMPs anymore.
+	if(!jmploop) {
+		for(r=firstr; r; r=r->link) {
+			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", (int)r->pc, p);
+				p->as = ANOP;
+			}
+		}
+	}
+
+	// fix back pointers.
+	for(r=firstr; r; r=r->link) {
+		r->p2 = R;
+		r->p2link = R;
+	}
+	for(r=firstr; r; r=r->link) {
+		if(r->s2) {
+			r->p2link = r->s2->p2;
+			r->s2->p2 = r;
+		}
+	}
+
+	if(debug['R'] && debug['v']) {
+		print("\n");
+		for(r=firstr; r; r=r->link)
+			print("%04d %P\n", (int)r->pc, r->prog);
+		print("\n");
+	}
+}
+
diff --git a/src/cmd/8c/sgen.c b/src/cmd/8c/sgen.c
new file mode 100644
index 0000000..d647010
--- /dev/null
+++ b/src/cmd/8c/sgen.c
@@ -0,0 +1,483 @@
+// Inferno utils/8c/sgen.c
+// http://code.google.com/p/inferno-os/source/browse/utils/8c/sgen.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 "gc.h"
+
+Prog*
+gtext(Sym *s, int32 stkoff)
+{
+	int32 a;
+
+	a = argsize(1);
+	if((textflag & NOSPLIT) != 0 && stkoff >= 128)
+		yyerror("stack frame too large for NOSPLIT function");
+
+	gpseudo(ATEXT, s, nodconst(stkoff));
+	p->to.type = D_CONST2;
+	p->to.offset2 = a;
+	return p;
+}
+
+void
+noretval(int n)
+{
+
+	if(n & 1) {
+		gins(ANOP, Z, Z);
+		p->to.type = REGRET;
+	}
+	if(n & 2) {
+		gins(ANOP, Z, Z);
+		p->to.type = FREGRET;
+	}
+}
+
+/* welcome to commute */
+static void
+commute(Node *n)
+{
+	Node *l, *r;
+
+	l = n->left;
+	r = n->right;
+	if(r->complex > l->complex) {
+		n->left = r;
+		n->right = l;
+	}
+}
+
+void
+indexshift(Node *n)
+{
+	int g;
+
+	if(!typechlp[n->type->etype])
+		return;
+	simplifyshift(n);
+	if(n->op == OASHL && n->right->op == OCONST){
+		g = vconst(n->right);
+		if(g >= 0 && g < 4)
+			n->addable = 7;
+	}
+}
+
+/*
+ *	calculate addressability as follows
+ *		NAME ==> 10/11		name+value(SB/SP)
+ *		REGISTER ==> 12		register
+ *		CONST ==> 20		$value
+ *		*(20) ==> 21		value
+ *		&(10) ==> 13		$name+value(SB)
+ *		&(11) ==> 1		$name+value(SP)
+ *		(13) + (20) ==> 13	fold constants
+ *		(1) + (20) ==> 1	fold constants
+ *		*(13) ==> 10		back to name
+ *		*(1) ==> 11		back to name
+ *
+ *		(20) * (X) ==> 7	multiplier in indexing
+ *		(X,7) + (13,1) ==> 8	adder in indexing (addresses)
+ *		(8) ==> &9(OINDEX)	index, almost addressable
+ *		100					extern register
+ *
+ *	calculate complexity (number of registers)
+ */
+void
+xcom(Node *n)
+{
+	Node *l, *r;
+	int g;
+
+	if(n == Z)
+		return;
+	l = n->left;
+	r = n->right;
+	n->complex = 0;
+	n->addable = 0;
+	switch(n->op) {
+	case OCONST:
+		n->addable = 20;
+		break;
+
+	case ONAME:
+		n->addable = 10;
+		if(n->class == CPARAM || n->class == CAUTO)
+			n->addable = 11;
+		break;
+
+	case OEXREG:
+		n->addable = 0;
+		break;
+
+	case OREGISTER:
+		n->addable = 12;
+		break;
+
+	case OINDREG:
+		n->addable = 12;
+		break;
+
+	case OADDR:
+		xcom(l);
+		if(l->addable == 10)
+			n->addable = 13;
+		else
+		if(l->addable == 11)
+			n->addable = 1;
+		break;
+
+	case OADD:
+		xcom(l);
+		xcom(r);
+		if(n->type->etype != TIND)
+			break;
+
+		switch(r->addable) {
+		case 20:
+			switch(l->addable) {
+			case 1:
+			case 13:
+			commadd:
+				l->type = n->type;
+				*n = *l;
+				l = new(0, Z, Z);
+				*l = *(n->left);
+				l->xoffset += r->vconst;
+				n->left = l;
+				r = n->right;
+				goto brk;
+			}
+			break;
+
+		case 1:
+		case 13:
+		case 10:
+		case 11:
+			/* l is the base, r is the index */
+			if(l->addable != 20)
+				n->addable = 8;
+			break;
+		}
+		switch(l->addable) {
+		case 20:
+			switch(r->addable) {
+			case 13:
+			case 1:
+				r = n->left;
+				l = n->right;
+				n->left = l;
+				n->right = r;
+				goto commadd;
+			}
+			break;
+
+		case 13:
+		case 1:
+		case 10:
+		case 11:
+			/* r is the base, l is the index */
+			if(r->addable != 20)
+				n->addable = 8;
+			break;
+		}
+		if(n->addable == 8 && !side(n)) {
+			indx(n);
+			l = new1(OINDEX, idx.basetree, idx.regtree);
+			l->scale = idx.scale;
+			l->addable = 9;
+			l->complex = l->right->complex;
+			l->type = l->left->type;
+			n->op = OADDR;
+			n->left = l;
+			n->right = Z;
+			n->addable = 8;
+			break;
+		}
+		break;
+
+	case OINDEX:
+		xcom(l);
+		xcom(r);
+		n->addable = 9;
+		break;
+
+	case OIND:
+		xcom(l);
+		if(l->op == OADDR) {
+			l = l->left;
+			l->type = n->type;
+			*n = *l;
+			return;
+		}
+		switch(l->addable) {
+		case 20:
+			n->addable = 21;
+			break;
+		case 1:
+			n->addable = 11;
+			break;
+		case 13:
+			n->addable = 10;
+			break;
+		}
+		break;
+
+	case OASHL:
+		xcom(l);
+		xcom(r);
+		indexshift(n);
+		break;
+
+	case OMUL:
+	case OLMUL:
+		xcom(l);
+		xcom(r);
+		g = vlog(l);
+		if(g >= 0) {
+			n->left = r;
+			n->right = l;
+			l = r;
+			r = n->right;
+		}
+		g = vlog(r);
+		if(g >= 0) {
+			n->op = OASHL;
+			r->vconst = g;
+			r->type = types[TINT];
+			indexshift(n);
+			break;
+		}
+commute(n);
+		break;
+
+	case OASLDIV:
+		xcom(l);
+		xcom(r);
+		g = vlog(r);
+		if(g >= 0) {
+			n->op = OASLSHR;
+			r->vconst = g;
+			r->type = types[TINT];
+		}
+		break;
+
+	case OLDIV:
+		xcom(l);
+		xcom(r);
+		g = vlog(r);
+		if(g >= 0) {
+			n->op = OLSHR;
+			r->vconst = g;
+			r->type = types[TINT];
+			indexshift(n);
+			break;
+		}
+		break;
+
+	case OASLMOD:
+		xcom(l);
+		xcom(r);
+		g = vlog(r);
+		if(g >= 0) {
+			n->op = OASAND;
+			r->vconst--;
+		}
+		break;
+
+	case OLMOD:
+		xcom(l);
+		xcom(r);
+		g = vlog(r);
+		if(g >= 0) {
+			n->op = OAND;
+			r->vconst--;
+		}
+		break;
+
+	case OASMUL:
+	case OASLMUL:
+		xcom(l);
+		xcom(r);
+		g = vlog(r);
+		if(g >= 0) {
+			n->op = OASASHL;
+			r->vconst = g;
+		}
+		break;
+
+	case OLSHR:
+	case OASHR:
+		xcom(l);
+		xcom(r);
+		indexshift(n);
+		break;
+
+	default:
+		if(l != Z)
+			xcom(l);
+		if(r != Z)
+			xcom(r);
+		break;
+	}
+brk:
+	if(n->addable >= 10)
+		return;
+	if(l != Z)
+		n->complex = l->complex;
+	if(r != Z) {
+		if(r->complex == n->complex)
+			n->complex = r->complex+1;
+		else
+		if(r->complex > n->complex)
+			n->complex = r->complex;
+	}
+	if(n->complex == 0)
+		n->complex++;
+
+	if(com64(n))
+		return;
+
+	switch(n->op) {
+
+	case OFUNC:
+		n->complex = FNX;
+		break;
+
+	case OLMOD:
+	case OMOD:
+	case OLMUL:
+	case OLDIV:
+	case OMUL:
+	case ODIV:
+	case OASLMUL:
+	case OASLDIV:
+	case OASLMOD:
+	case OASMUL:
+	case OASDIV:
+	case OASMOD:
+		if(r->complex >= l->complex) {
+			n->complex = l->complex + 3;
+			if(r->complex > n->complex)
+				n->complex = r->complex;
+		} else {
+			n->complex = r->complex + 3;
+			if(l->complex > n->complex)
+				n->complex = l->complex;
+		}
+		break;
+
+	case OLSHR:
+	case OASHL:
+	case OASHR:
+	case OASLSHR:
+	case OASASHL:
+	case OASASHR:
+		if(r->complex >= l->complex) {
+			n->complex = l->complex + 2;
+			if(r->complex > n->complex)
+				n->complex = r->complex;
+		} else {
+			n->complex = r->complex + 2;
+			if(l->complex > n->complex)
+				n->complex = l->complex;
+		}
+		break;
+
+	case OADD:
+	case OXOR:
+	case OAND:
+	case OOR:
+		/*
+		 * immediate operators, make const on right
+		 */
+		if(l->op == OCONST) {
+			n->left = r;
+			n->right = l;
+		}
+		break;
+
+	case OEQ:
+	case ONE:
+	case OLE:
+	case OLT:
+	case OGE:
+	case OGT:
+	case OHI:
+	case OHS:
+	case OLO:
+	case OLS:
+		/*
+		 * compare operators, make const on left
+		 */
+		if(r->op == OCONST) {
+			n->left = r;
+			n->right = l;
+			n->op = invrel[relindex(n->op)];
+		}
+		break;
+	}
+}
+
+void
+indx(Node *n)
+{
+	Node *l, *r;
+
+	if(debug['x'])
+		prtree(n, "indx");
+
+	l = n->left;
+	r = n->right;
+	if(l->addable == 1 || l->addable == 13 || r->complex > l->complex) {
+		n->right = l;
+		n->left = r;
+		l = r;
+		r = n->right;
+	}
+	if(l->addable != 7) {
+		idx.regtree = l;
+		idx.scale = 1;
+	} else
+	if(l->right->addable == 20) {
+		idx.regtree = l->left;
+		idx.scale = 1 << l->right->vconst;
+	} else
+	if(l->left->addable == 20) {
+		idx.regtree = l->right;
+		idx.scale = 1 << l->left->vconst;
+	} else
+		diag(n, "bad index");
+
+	idx.basetree = r;
+	if(debug['x']) {
+		print("scale = %d\n", idx.scale);
+		prtree(idx.regtree, "index");
+		prtree(idx.basetree, "base");
+	}
+}
diff --git a/src/cmd/8c/swt.c b/src/cmd/8c/swt.c
new file mode 100644
index 0000000..d960519
--- /dev/null
+++ b/src/cmd/8c/swt.c
@@ -0,0 +1,341 @@
+// Inferno utils/8c/swt.c
+// http://code.google.com/p/inferno-os/source/browse/utils/8c/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 "gc.h"
+
+void
+swit1(C1 *q, int nc, int32 def, Node *n)
+{
+	Node nreg;
+
+	if(typev[n->type->etype]) {
+		regsalloc(&nreg, n);
+		nreg.type = types[TVLONG];
+		cgen(n, &nreg);
+		swit2(q, nc, def, &nreg);
+		return;
+	}
+
+	regalloc(&nreg, n, Z);
+	nreg.type = types[TLONG];
+	cgen(n, &nreg);
+	swit2(q, nc, def, &nreg);
+	regfree(&nreg);
+}
+
+void
+swit2(C1 *q, int nc, int32 def, Node *n)
+{
+	C1 *r;
+	int i;
+	Prog *sp;
+
+	if(nc < 5) {
+		for(i=0; i<nc; i++) {
+			if(debug['W'])
+				print("case = %.8ux\n", q->val);
+			gopcode(OEQ, n->type, n, nodconst(q->val));
+			patch(p, q->label);
+			q++;
+		}
+		gbranch(OGOTO);
+		patch(p, def);
+		return;
+	}
+	i = nc / 2;
+	r = q+i;
+	if(debug['W'])
+		print("case > %.8ux\n", r->val);
+	gopcode(OGT, n->type, n, nodconst(r->val));
+	sp = p;
+	gbranch(OGOTO);
+	p->as = AJEQ;
+	patch(p, r->label);
+	swit2(q, i, def, n);
+
+	if(debug['W'])
+		print("case < %.8ux\n", r->val);
+	patch(sp, pc);
+	swit2(r+1, nc-i-1, def, n);
+}
+
+void
+bitload(Node *b, Node *n1, Node *n2, Node *n3, Node *nn)
+{
+	int sh;
+	int32 v;
+	Node *l;
+
+	/*
+	 * n1 gets adjusted/masked value
+	 * n2 gets address of cell
+	 * n3 gets contents of cell
+	 */
+	l = b->left;
+	if(n2 != Z) {
+		regalloc(n1, l, nn);
+		reglcgen(n2, l, Z);
+		regalloc(n3, l, Z);
+		gmove(n2, n3);
+		gmove(n3, n1);
+	} else {
+		regalloc(n1, l, nn);
+		cgen(l, n1);
+	}
+	if(b->type->shift == 0 && typeu[b->type->etype]) {
+		v = ~0 + (1L << b->type->nbits);
+		gopcode(OAND, types[TLONG], nodconst(v), n1);
+	} else {
+		sh = 32 - b->type->shift - b->type->nbits;
+		if(sh > 0)
+			gopcode(OASHL, types[TLONG], nodconst(sh), n1);
+		sh += b->type->shift;
+		if(sh > 0)
+			if(typeu[b->type->etype])
+				gopcode(OLSHR, types[TLONG], nodconst(sh), n1);
+			else
+				gopcode(OASHR, types[TLONG], nodconst(sh), n1);
+	}
+}
+
+void
+bitstore(Node *b, Node *n1, Node *n2, Node *n3, Node *nn)
+{
+	int32 v;
+	Node nod;
+	int sh;
+
+	regalloc(&nod, b->left, Z);
+	v = ~0 + (1L << b->type->nbits);
+	gopcode(OAND, types[TLONG], nodconst(v), n1);
+	gmove(n1, &nod);
+	if(nn != Z)
+		gmove(n1, nn);
+	sh = b->type->shift;
+	if(sh > 0)
+		gopcode(OASHL, types[TLONG], nodconst(sh), &nod);
+	v <<= sh;
+	gopcode(OAND, types[TLONG], nodconst(~v), n3);
+	gopcode(OOR, types[TLONG], n3, &nod);
+	gmove(&nod, n2);
+
+	regfree(&nod);
+	regfree(n1);
+	regfree(n2);
+	regfree(n3);
+}
+
+int32
+outstring(char *s, int32 n)
+{
+	int32 r;
+
+	if(suppress)
+		return nstring;
+	r = nstring;
+	while(n) {
+		string[mnstring] = *s++;
+		mnstring++;
+		nstring++;
+		if(mnstring >= NSNAME) {
+			gpseudo(ADATA, symstring, nodconst(0L));
+			p->from.offset += nstring - NSNAME;
+			p->from.scale = NSNAME;
+			p->to.type = D_SCONST;
+			memmove(p->to.u.sval, string, NSNAME);
+			mnstring = 0;
+		}
+		n--;
+	}
+	return r;
+}
+
+void
+sextern(Sym *s, Node *a, int32 o, int32 w)
+{
+	int32 e, lw;
+
+	for(e=0; e<w; e+=NSNAME) {
+		lw = NSNAME;
+		if(w-e < lw)
+			lw = w-e;
+		gpseudo(ADATA, s, nodconst(0L));
+		p->from.offset += o+e;
+		p->from.scale = lw;
+		p->to.type = D_SCONST;
+		memmove(p->to.u.sval, a->cstring+e, lw);
+	}
+}
+
+void
+gextern(Sym *s, Node *a, int32 o, int32 w)
+{
+	if(a->op == OCONST && typev[a->type->etype]) {
+		gpseudo(ADATA, s, lo64(a));
+		p->from.offset += o;
+		p->from.scale = 4;
+		gpseudo(ADATA, s, hi64(a));
+		p->from.offset += o + 4;
+		p->from.scale = 4;
+		return;
+	}
+	gpseudo(ADATA, s, a);
+	p->from.offset += o;
+	p->from.scale = w;
+	switch(p->to.type) {
+	default:
+		p->to.index = p->to.type;
+		p->to.type = D_ADDR;
+	case D_CONST:
+	case D_FCONST:
+	case D_ADDR:
+		break;
+	}
+}
+
+void
+outcode(void)
+{
+	int f;
+	Biobuf b;
+
+	f = open(outfile, OWRITE);
+	if(f < 0) {
+		diag(Z, "cannot open %s", outfile);
+		return;
+	}
+	Binit(&b, f, OWRITE);
+
+	Bprint(&b, "go object %s %s %s\n", getgoos(), getgoarch(), getgoversion());
+	if(pragcgobuf.to > pragcgobuf.start) {
+		Bprint(&b, "\n");
+		Bprint(&b, "$$  // exports\n\n");
+		Bprint(&b, "$$  // local types\n\n");
+		Bprint(&b, "$$  // cgo\n");
+		Bprint(&b, "%s", fmtstrflush(&pragcgobuf));
+		Bprint(&b, "\n$$\n\n");
+	}
+	Bprint(&b, "!\n");
+
+	writeobj(ctxt, &b);
+	Bterm(&b);
+	close(f);
+	lastp = P;
+}
+
+int32
+align(int32 i, Type *t, int op, int32 *maxalign)
+{
+	int32 o;
+	Type *v;
+	int w, packw;
+
+	o = i;
+	w = 1;
+	packw = 0;
+	switch(op) {
+	default:
+		diag(Z, "unknown align opcode %d", op);
+		break;
+
+	case Asu2:	/* padding at end of a struct */
+		w = *maxalign;
+		if(w < 1)
+			w = 1;
+		if(packflg)
+			packw = packflg;
+		break;
+
+	case Ael1:	/* initial align of struct element */
+		for(v=t; v->etype==TARRAY; v=v->link)
+			;
+		if(v->etype == TSTRUCT || v->etype == TUNION)
+			w = v->align;
+		else {
+			w = ewidth[v->etype];
+			if(w == 8)
+				w = 4;
+		}
+		if(w < 1 || w > SZ_LONG)
+			fatal(Z, "align");
+		if(packflg) 
+			packw = packflg;
+		break;
+
+	case Ael2:	/* width of a struct element */
+		o += t->width;
+		break;
+
+	case Aarg0:	/* initial passbyptr argument in arg list */
+		if(typesuv[t->etype]) {
+			o = align(o, types[TIND], Aarg1, nil);
+			o = align(o, types[TIND], Aarg2, nil);
+		}
+		break;
+
+	case Aarg1:	/* initial align of parameter */
+		w = ewidth[t->etype];
+		if(w <= 0 || w >= SZ_LONG) {
+			w = SZ_LONG;
+			break;
+		}
+		w = 1;		/* little endian no adjustment */
+		break;
+
+	case Aarg2:	/* width of a parameter */
+		o += t->width;
+		w = t->width;
+		if(w > SZ_LONG)
+			w = SZ_LONG;
+		break;
+
+	case Aaut3:	/* total align of automatic */
+		o = align(o, t, Ael1, nil);
+		o = align(o, t, Ael2, nil);
+		break;
+	}
+	if(packw != 0 && xround(o, w) != xround(o, packw))
+		diag(Z, "#pragma pack changes offset of %T", t);
+	o = xround(o, w);
+	if(maxalign && *maxalign < w)
+		*maxalign = w;
+	if(debug['A'])
+		print("align %s %d %T = %d\n", bnames[op], i, t, o);
+	return o;
+}
+
+int32
+maxround(int32 max, int32 v)
+{
+	v = xround(v, SZ_LONG);
+	if(v > max)
+		return v;
+	return max;
+}
diff --git a/src/cmd/8c/txt.c b/src/cmd/8c/txt.c
new file mode 100644
index 0000000..7f87a0a
--- /dev/null
+++ b/src/cmd/8c/txt.c
@@ -0,0 +1,1537 @@
+// Inferno utils/8c/txt.c
+// http://code.google.com/p/inferno-os/source/browse/utils/8c/txt.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 "gc.h"
+
+
+int thechar = '8';
+char *thestring = "386";
+
+LinkArch	*thelinkarch = &link386;
+
+void
+linkarchinit(void)
+{
+}
+
+void
+ginit(void)
+{
+	int i;
+	Type *t;
+
+	exregoffset = 0;
+	exfregoffset = 0;
+	listinit();
+	nstring = 0;
+	mnstring = 0;
+	nrathole = 0;
+	pc = 0;
+	breakpc = -1;
+	continpc = -1;
+	cases = C;
+	lastp = P;
+	tfield = types[TLONG];
+
+	zprog.link = P;
+	zprog.as = AGOK;
+	zprog.from.type = D_NONE;
+	zprog.from.index = D_NONE;
+	zprog.from.scale = 0;
+	zprog.to = zprog.from;
+
+	regnode.op = OREGISTER;
+	regnode.class = CEXREG;
+	regnode.reg = REGTMP;
+	regnode.complex = 0;
+	regnode.addable = 11;
+	regnode.type = types[TLONG];
+
+	fregnode0 = regnode;
+	fregnode0.reg = D_F0;
+	fregnode0.type = types[TDOUBLE];
+
+	fregnode1 = fregnode0;
+	fregnode1.reg = D_F0+1;
+
+	constnode.op = OCONST;
+	constnode.class = CXXX;
+	constnode.complex = 0;
+	constnode.addable = 20;
+	constnode.type = types[TLONG];
+
+	fconstnode.op = OCONST;
+	fconstnode.class = CXXX;
+	fconstnode.complex = 0;
+	fconstnode.addable = 20;
+	fconstnode.type = types[TDOUBLE];
+
+	nodsafe = new(ONAME, Z, Z);
+	nodsafe->sym = slookup(".safe");
+	nodsafe->type = types[TINT];
+	nodsafe->etype = types[TINT]->etype;
+	nodsafe->class = CAUTO;
+	complex(nodsafe);
+
+	t = typ(TARRAY, types[TCHAR]);
+	symrathole = slookup(".rathole");
+	symrathole->class = CGLOBL;
+	symrathole->type = t;
+
+	nodrat = new(ONAME, Z, Z);
+	nodrat->sym = symrathole;
+	nodrat->type = types[TIND];
+	nodrat->etype = TVOID;
+	nodrat->class = CGLOBL;
+	complex(nodrat);
+	nodrat->type = t;
+
+	nodret = new(ONAME, Z, Z);
+	nodret->sym = slookup(".ret");
+	nodret->type = types[TIND];
+	nodret->etype = TIND;
+	nodret->class = CPARAM;
+	nodret = new(OIND, nodret, Z);
+	complex(nodret);
+
+	com64init();
+
+	for(i=0; i<nelem(reg); i++) {
+		reg[i] = 1;
+		if(i >= D_AX && i <= D_DI && i != D_SP)
+			reg[i] = 0;
+	}
+}
+
+void
+gclean(void)
+{
+	int i;
+	Sym *s;
+
+	reg[D_SP]--;
+	for(i=D_AX; i<=D_DI; i++)
+		if(reg[i])
+			diag(Z, "reg %R left allocated", i);
+	while(mnstring)
+		outstring("", 1L);
+	symstring->type->width = nstring;
+	symrathole->type->width = nrathole;
+	for(i=0; i<NHASH; i++)
+	for(s = hash[i]; s != S; s = s->link) {
+		if(s->type == T)
+			continue;
+		if(s->type->width == 0)
+			continue;
+		if(s->class != CGLOBL && s->class != CSTATIC)
+			continue;
+		if(s->type == types[TENUM])
+			continue;
+		gpseudo(AGLOBL, s, nodconst(s->type->width));
+	}
+	nextpc();
+	p->as = AEND;
+	outcode();
+}
+
+void
+nextpc(void)
+{
+	Plist *pl;
+
+	p = alloc(sizeof(*p));
+	*p = zprog;
+	p->lineno = nearln;
+	p->pc = pc;
+	pc++;
+	if(lastp == nil) {
+		pl = linknewplist(ctxt);
+		pl->firstpc = p;
+	} else
+		lastp->link = p;
+	lastp = p;
+}
+
+void
+gargs(Node *n, Node *tn1, Node *tn2)
+{
+	int32 regs;
+	Node fnxargs[20], *fnxp;
+
+	regs = cursafe;
+
+	fnxp = fnxargs;
+	garg1(n, tn1, tn2, 0, &fnxp);	/* compile fns to temps */
+
+	curarg = 0;
+	fnxp = fnxargs;
+	garg1(n, tn1, tn2, 1, &fnxp);	/* compile normal args and temps */
+
+	cursafe = regs;
+}
+
+int
+nareg(void)
+{
+	int i, n;
+
+	n = 0;
+	for(i=D_AX; i<=D_DI; i++)
+		if(reg[i] == 0)
+			n++;
+	return n;
+}
+
+void
+garg1(Node *n, Node *tn1, Node *tn2, int f, Node **fnxp)
+{
+	Node nod;
+
+	if(n == Z)
+		return;
+	if(n->op == OLIST) {
+		garg1(n->left, tn1, tn2, f, fnxp);
+		garg1(n->right, tn1, tn2, f, fnxp);
+		return;
+	}
+	if(f == 0) {
+		if(n->complex >= FNX) {
+			regsalloc(*fnxp, n);
+			nod = znode;
+			nod.op = OAS;
+			nod.left = *fnxp;
+			nod.right = n;
+			nod.type = n->type;
+			cgen(&nod, Z);
+			(*fnxp)++;
+		}
+		return;
+	}
+	if(typesu[n->type->etype] || typev[n->type->etype]) {
+		regaalloc(tn2, n);
+		if(n->complex >= FNX) {
+			sugen(*fnxp, tn2, n->type->width);
+			(*fnxp)++;
+		} else
+			sugen(n, tn2, n->type->width);
+		return;
+	}
+	if(REGARG >= 0 && curarg == 0 && typeilp[n->type->etype]) {
+		regaalloc1(tn1, n);
+		if(n->complex >= FNX) {
+			cgen(*fnxp, tn1);
+			(*fnxp)++;
+		} else
+			cgen(n, tn1);
+		return;
+	}
+	if(vconst(n) == 0) {
+		regaalloc(tn2, n);
+		gmove(n, tn2);
+		return;
+	}
+	regalloc(tn1, n, Z);
+	if(n->complex >= FNX) {
+		cgen(*fnxp, tn1);
+		(*fnxp)++;
+	} else
+		cgen(n, tn1);
+	regaalloc(tn2, n);
+	gmove(tn1, tn2);
+	regfree(tn1);
+}
+
+Node*
+nodconst(int32 v)
+{
+	constnode.vconst = v;
+	return &constnode;
+}
+
+Node*
+nodfconst(double d)
+{
+	fconstnode.fconst = d;
+	return &fconstnode;
+}
+
+int
+isreg(Node *n, int r)
+{
+
+	if(n->op == OREGISTER)
+		if(n->reg == r)
+			return 1;
+	return 0;
+}
+
+int
+nodreg(Node *n, Node *nn, int r)
+{
+
+	*n = regnode;
+	n->reg = r;
+	if(reg[r] == 0)
+		return 0;
+	if(nn != Z) {
+		n->type = nn->type;
+		n->lineno = nn->lineno;
+		if(nn->op == OREGISTER)
+		if(nn->reg == r)
+			return 0;
+	}
+	return 1;
+}
+
+void
+regret(Node *n, Node *nn, Type *t, int mode)
+{
+	int r;
+
+	if(mode == 0 || hasdotdotdot(t) || nn->type->width == 0) {
+		r = REGRET;
+		if(typefd[nn->type->etype])
+			r = FREGRET;
+		nodreg(n, nn, r);
+		reg[r]++;
+		return;
+	}
+	
+	if(mode == 1) {
+		// fetch returned value after call.
+		// already called gargs, so curarg is set.
+		curarg = (curarg+3) & ~3;
+		regaalloc(n, nn);
+		return;
+	}
+	
+	if(mode == 2) {
+		// store value to be returned.
+		// must compute arg offset.
+		if(t->etype != TFUNC)
+			fatal(Z, "bad regret func %T", t);
+		*n = *nn;
+		n->op = ONAME;
+		n->class = CPARAM;
+		n->sym = slookup(".retx");
+		n->complex = 0;
+		n->addable = 20;
+		n->xoffset = argsize(0);
+		return;
+	}
+	
+	fatal(Z, "bad regret");
+}
+
+void
+regalloc(Node *n, Node *tn, Node *o)
+{
+	int i;
+
+	switch(tn->type->etype) {
+	case TCHAR:
+	case TUCHAR:
+	case TSHORT:
+	case TUSHORT:
+	case TINT:
+	case TUINT:
+	case TLONG:
+	case TULONG:
+	case TIND:
+		if(o != Z && o->op == OREGISTER) {
+			i = o->reg;
+			if(i >= D_AX && i <= D_DI)
+				goto out;
+		}
+		for(i=D_AX; i<=D_DI; i++)
+			if(reg[i] == 0)
+				goto out;
+		diag(tn, "out of fixed registers");
+		goto err;
+
+	case TFLOAT:
+	case TDOUBLE:
+	case TVLONG:
+		i = D_F0;
+		goto out;
+	}
+	diag(tn, "unknown type in regalloc: %T", tn->type);
+err:
+	i = 0;
+out:
+	if(i)
+		reg[i]++;
+	nodreg(n, tn, i);
+}
+
+void
+regialloc(Node *n, Node *tn, Node *o)
+{
+	Node nod;
+
+	nod = *tn;
+	nod.type = types[TIND];
+	regalloc(n, &nod, o);
+}
+
+void
+regfree(Node *n)
+{
+	int i;
+
+	i = 0;
+	if(n->op != OREGISTER && n->op != OINDREG)
+		goto err;
+	i = n->reg;
+	if(i < 0 || i >= nelem(reg))
+		goto err;
+	if(reg[i] <= 0)
+		goto err;
+	reg[i]--;
+	return;
+err:
+	diag(n, "error in regfree: %R", i);
+}
+
+void
+regsalloc(Node *n, Node *nn)
+{
+	cursafe = align(cursafe, nn->type, Aaut3, nil);
+	maxargsafe = maxround(maxargsafe, cursafe+curarg);
+	*n = *nodsafe;
+	n->xoffset = -(stkoff + cursafe);
+	n->type = nn->type;
+	n->etype = nn->type->etype;
+	n->lineno = nn->lineno;
+}
+
+void
+regaalloc1(Node *n, Node *nn)
+{
+	if(REGARG < 0) {
+		fatal(n, "regaalloc1 and REGARG<0");
+		return;
+	}
+	nodreg(n, nn, REGARG);
+	reg[REGARG]++;
+	curarg = align(curarg, nn->type, Aarg1, nil);
+	curarg = align(curarg, nn->type, Aarg2, nil);
+	maxargsafe = maxround(maxargsafe, cursafe+curarg);
+}
+
+void
+regaalloc(Node *n, Node *nn)
+{
+	curarg = align(curarg, nn->type, Aarg1, nil);
+	*n = *nn;
+	n->op = OINDREG;
+	n->reg = REGSP;
+	n->xoffset = curarg;
+	n->complex = 0;
+	n->addable = 20;
+	curarg = align(curarg, nn->type, Aarg2, nil);
+	maxargsafe = maxround(maxargsafe, cursafe+curarg);
+}
+
+void
+regind(Node *n, Node *nn)
+{
+
+	if(n->op != OREGISTER) {
+		diag(n, "regind not OREGISTER");
+		return;
+	}
+	n->op = OINDREG;
+	n->type = nn->type;
+}
+
+void
+naddr(Node *n, Addr *a)
+{
+	int32 v;
+
+	a->type = D_NONE;
+	if(n == Z)
+		return;
+	switch(n->op) {
+	default:
+	bad:
+		diag(n, "bad in naddr: %O %D", n->op, a);
+		break;
+
+	case OREGISTER:
+		a->type = n->reg;
+		a->sym = nil;
+		break;
+
+	case OEXREG:
+		a->type = D_INDIR + D_TLS;
+		a->offset = n->reg - 1;
+		break;
+
+	case OIND:
+		naddr(n->left, a);
+		if(a->type >= D_AX && a->type <= D_DI)
+			a->type += D_INDIR;
+		else
+		if(a->type == D_CONST)
+			a->type = D_NONE+D_INDIR;
+		else
+		if(a->type == D_ADDR) {
+			a->type = a->index;
+			a->index = D_NONE;
+		} else
+			goto bad;
+		break;
+
+	case OINDEX:
+		a->type = idx.ptr;
+		if(n->left->op == OADDR || n->left->op == OCONST)
+			naddr(n->left, a);
+		if(a->type >= D_AX && a->type <= D_DI)
+			a->type += D_INDIR;
+		else
+		if(a->type == D_CONST)
+			a->type = D_NONE+D_INDIR;
+		else
+		if(a->type == D_ADDR) {
+			a->type = a->index;
+			a->index = D_NONE;
+		} else
+			goto bad;
+		a->index = idx.reg;
+		a->scale = n->scale;
+		a->offset += n->xoffset;
+		break;
+
+	case OINDREG:
+		a->type = n->reg+D_INDIR;
+		a->sym = nil;
+		a->offset = n->xoffset;
+		break;
+
+	case ONAME:
+		a->etype = n->etype;
+		a->type = D_STATIC;
+		a->sym = linksym(n->sym);
+		a->offset = n->xoffset;
+		if(n->class == CSTATIC)
+			break;
+		if(n->class == CEXTERN || n->class == CGLOBL) {
+			a->type = D_EXTERN;
+			break;
+		}
+		if(n->class == CAUTO) {
+			a->type = D_AUTO;
+			break;
+		}
+		if(n->class == CPARAM) {
+			a->type = D_PARAM;
+			break;
+		}
+		goto bad;
+
+	case OCONST:
+		if(typefd[n->type->etype]) {
+			a->type = D_FCONST;
+			a->u.dval = n->fconst;
+			break;
+		}
+		a->sym = nil;
+		a->type = D_CONST;
+		a->offset = n->vconst;
+		break;
+
+	case OADDR:
+		naddr(n->left, a);
+		if(a->type >= D_INDIR) {
+			a->type -= D_INDIR;
+			break;
+		}
+		if(a->type == D_EXTERN || a->type == D_STATIC ||
+		   a->type == D_AUTO || a->type == D_PARAM)
+			if(a->index == D_NONE) {
+				a->index = a->type;
+				a->type = D_ADDR;
+				break;
+			}
+		goto bad;
+
+	case OADD:
+		if(n->right->op == OCONST) {
+			v = n->right->vconst;
+			naddr(n->left, a);
+		} else
+		if(n->left->op == OCONST) {
+			v = n->left->vconst;
+			naddr(n->right, a);
+		} else
+			goto bad;
+		a->offset += v;
+		break;
+
+	}
+}
+
+#define	CASE(a,b)	((a<<8)|(b<<0))
+
+void
+gmove(Node *f, Node *t)
+{
+	int ft, tt, a;
+	Node nod, nod1;
+	Prog *p1;
+
+	ft = f->type->etype;
+	tt = t->type->etype;
+	if(debug['M'])
+		print("gop: %O %O[%s],%O[%s]\n", OAS,
+			f->op, tnames[ft], t->op, tnames[tt]);
+	if(typefd[ft] && f->op == OCONST) {
+		if(f->fconst == 0)
+			gins(AFLDZ, Z, Z);
+		else
+		if(f->fconst == 1)
+			gins(AFLD1, Z, Z);
+		else
+			gins(AFMOVD, f, &fregnode0);
+		gmove(&fregnode0, t);
+		return;
+	}
+/*
+ * load
+ */
+	if(f->op == ONAME || f->op == OINDREG ||
+	   f->op == OIND || f->op == OINDEX)
+	switch(ft) {
+	case TCHAR:
+		a = AMOVBLSX;
+		goto ld;
+	case TUCHAR:
+		a = AMOVBLZX;
+		goto ld;
+	case TSHORT:
+		if(typefd[tt]) {
+			gins(AFMOVW, f, &fregnode0);
+			gmove(&fregnode0, t);
+			return;
+		}
+		a = AMOVWLSX;
+		goto ld;
+	case TUSHORT:
+		a = AMOVWLZX;
+		goto ld;
+	case TINT:
+	case TUINT:
+	case TLONG:
+	case TULONG:
+	case TIND:
+		if(typefd[tt]) {
+			gins(AFMOVL, f, &fregnode0);
+			gmove(&fregnode0, t);
+			return;
+		}
+		a = AMOVL;
+
+	ld:
+		regalloc(&nod, f, t);
+		nod.type = types[TLONG];
+		gins(a, f, &nod);
+		gmove(&nod, t);
+		regfree(&nod);
+		return;
+
+	case TFLOAT:
+		gins(AFMOVF, f, t);
+		return;
+	case TDOUBLE:
+		gins(AFMOVD, f, t);
+		return;
+	case TVLONG:
+		gins(AFMOVV, f, t);
+		return;
+	}
+
+/*
+ * store
+ */
+	if(t->op == ONAME || t->op == OINDREG ||
+	   t->op == OIND || t->op == OINDEX)
+	switch(tt) {
+	case TCHAR:
+	case TUCHAR:
+		a = AMOVB;	goto st;
+	case TSHORT:
+	case TUSHORT:
+		a = AMOVW;	goto st;
+	case TINT:
+	case TUINT:
+	case TLONG:
+	case TULONG:
+	case TIND:
+		a = AMOVL;	goto st;
+
+	st:
+		if(f->op == OCONST) {
+			gins(a, f, t);
+			return;
+		}
+		regalloc(&nod, t, f);
+		gmove(f, &nod);
+		gins(a, &nod, t);
+		regfree(&nod);
+		return;
+
+	case TFLOAT:
+		gins(AFMOVFP, f, t);
+		return;
+	case TDOUBLE:
+		gins(AFMOVDP, f, t);
+		return;
+	case TVLONG:
+		gins(AFMOVVP, f, t);
+		return;
+	}
+
+/*
+ * convert
+ */
+	switch(CASE(ft,tt)) {
+	default:
+/*
+ * integer to integer
+ ********
+		a = AGOK;	break;
+
+	case CASE(	TCHAR,	TCHAR):
+	case CASE(	TUCHAR,	TCHAR):
+	case CASE(	TSHORT,	TCHAR):
+	case CASE(	TUSHORT,TCHAR):
+	case CASE(	TINT,	TCHAR):
+	case CASE(	TUINT,	TCHAR):
+	case CASE(	TLONG,	TCHAR):
+	case CASE(	TULONG,	TCHAR):
+	case CASE(	TIND,	TCHAR):
+
+	case CASE(	TCHAR,	TUCHAR):
+	case CASE(	TUCHAR,	TUCHAR):
+	case CASE(	TSHORT,	TUCHAR):
+	case CASE(	TUSHORT,TUCHAR):
+	case CASE(	TINT,	TUCHAR):
+	case CASE(	TUINT,	TUCHAR):
+	case CASE(	TLONG,	TUCHAR):
+	case CASE(	TULONG,	TUCHAR):
+	case CASE(	TIND,	TUCHAR):
+
+	case CASE(	TSHORT,	TSHORT):
+	case CASE(	TUSHORT,TSHORT):
+	case CASE(	TINT,	TSHORT):
+	case CASE(	TUINT,	TSHORT):
+	case CASE(	TLONG,	TSHORT):
+	case CASE(	TULONG,	TSHORT):
+	case CASE(	TIND,	TSHORT):
+
+	case CASE(	TSHORT,	TUSHORT):
+	case CASE(	TUSHORT,TUSHORT):
+	case CASE(	TINT,	TUSHORT):
+	case CASE(	TUINT,	TUSHORT):
+	case CASE(	TLONG,	TUSHORT):
+	case CASE(	TULONG,	TUSHORT):
+	case CASE(	TIND,	TUSHORT):
+
+	case CASE(	TINT,	TINT):
+	case CASE(	TUINT,	TINT):
+	case CASE(	TLONG,	TINT):
+	case CASE(	TULONG,	TINT):
+	case CASE(	TIND,	TINT):
+
+	case CASE(	TINT,	TUINT):
+	case CASE(	TUINT,	TUINT):
+	case CASE(	TLONG,	TUINT):
+	case CASE(	TULONG,	TUINT):
+	case CASE(	TIND,	TUINT):
+
+	case CASE(	TINT,	TLONG):
+	case CASE(	TUINT,	TLONG):
+	case CASE(	TLONG,	TLONG):
+	case CASE(	TULONG,	TLONG):
+	case CASE(	TIND,	TLONG):
+
+	case CASE(	TINT,	TULONG):
+	case CASE(	TUINT,	TULONG):
+	case CASE(	TLONG,	TULONG):
+	case CASE(	TULONG,	TULONG):
+	case CASE(	TIND,	TULONG):
+
+	case CASE(	TINT,	TIND):
+	case CASE(	TUINT,	TIND):
+	case CASE(	TLONG,	TIND):
+	case CASE(	TULONG,	TIND):
+	case CASE(	TIND,	TIND):
+ *****/
+		a = AMOVL;
+		break;
+
+	case CASE(	TSHORT,	TINT):
+	case CASE(	TSHORT,	TUINT):
+	case CASE(	TSHORT,	TLONG):
+	case CASE(	TSHORT,	TULONG):
+	case CASE(	TSHORT,	TIND):
+		a = AMOVWLSX;
+		if(f->op == OCONST) {
+			f->vconst &= 0xffff;
+			if(f->vconst & 0x8000)
+				f->vconst |= 0xffff0000;
+			a = AMOVL;
+		}
+		break;
+
+	case CASE(	TUSHORT,TINT):
+	case CASE(	TUSHORT,TUINT):
+	case CASE(	TUSHORT,TLONG):
+	case CASE(	TUSHORT,TULONG):
+	case CASE(	TUSHORT,TIND):
+		a = AMOVWLZX;
+		if(f->op == OCONST) {
+			f->vconst &= 0xffff;
+			a = AMOVL;
+		}
+		break;
+
+	case CASE(	TCHAR,	TSHORT):
+	case CASE(	TCHAR,	TUSHORT):
+	case CASE(	TCHAR,	TINT):
+	case CASE(	TCHAR,	TUINT):
+	case CASE(	TCHAR,	TLONG):
+	case CASE(	TCHAR,	TULONG):
+	case CASE(	TCHAR,	TIND):
+		a = AMOVBLSX;
+		if(f->op == OCONST) {
+			f->vconst &= 0xff;
+			if(f->vconst & 0x80)
+				f->vconst |= 0xffffff00;
+			a = AMOVL;
+		}
+		break;
+
+	case CASE(	TUCHAR,	TSHORT):
+	case CASE(	TUCHAR,	TUSHORT):
+	case CASE(	TUCHAR,	TINT):
+	case CASE(	TUCHAR,	TUINT):
+	case CASE(	TUCHAR,	TLONG):
+	case CASE(	TUCHAR,	TULONG):
+	case CASE(	TUCHAR,	TIND):
+		a = AMOVBLZX;
+		if(f->op == OCONST) {
+			f->vconst &= 0xff;
+			a = AMOVL;
+		}
+		break;
+
+/*
+ * float to fix
+ */
+	case CASE(	TFLOAT,	TCHAR):
+	case CASE(	TFLOAT,	TUCHAR):
+	case CASE(	TFLOAT,	TSHORT):
+	case CASE(	TFLOAT,	TUSHORT):
+	case CASE(	TFLOAT,	TINT):
+	case CASE(	TFLOAT,	TUINT):
+	case CASE(	TFLOAT,	TLONG):
+	case CASE(	TFLOAT,	TULONG):
+	case CASE(	TFLOAT,	TIND):
+
+	case CASE(	TDOUBLE,TCHAR):
+	case CASE(	TDOUBLE,TUCHAR):
+	case CASE(	TDOUBLE,TSHORT):
+	case CASE(	TDOUBLE,TUSHORT):
+	case CASE(	TDOUBLE,TINT):
+	case CASE(	TDOUBLE,TUINT):
+	case CASE(	TDOUBLE,TLONG):
+	case CASE(	TDOUBLE,TULONG):
+	case CASE(	TDOUBLE,TIND):
+
+	case CASE(	TVLONG,	TCHAR):
+	case CASE(	TVLONG,	TUCHAR):
+	case CASE(	TVLONG,	TSHORT):
+	case CASE(	TVLONG,	TUSHORT):
+	case CASE(	TVLONG,	TINT):
+	case CASE(	TVLONG,	TUINT):
+	case CASE(	TVLONG,	TLONG):
+	case CASE(	TVLONG,	TULONG):
+	case CASE(	TVLONG,	TIND):
+		if(fproundflg) {
+			regsalloc(&nod, &regnode);
+			gins(AFMOVLP, f, &nod);
+			gmove(&nod, t);
+			return;
+		}
+		regsalloc(&nod, &regnode);
+		regsalloc(&nod1, &regnode);
+		gins(AFSTCW, Z, &nod1);
+		nod1.xoffset += 2;
+		gins(AMOVW, nodconst(0xf7f), &nod1);
+		gins(AFLDCW, &nod1, Z);
+		gins(AFMOVLP, f, &nod);
+		nod1.xoffset -= 2;
+		gins(AFLDCW, &nod1, Z);
+		gmove(&nod, t);
+		return;
+
+/*
+ * ulong to float
+ */
+	case CASE(	TULONG,	TDOUBLE):
+	case CASE(	TULONG,	TVLONG):
+	case CASE(	TULONG,	TFLOAT):
+	case CASE(	TUINT,	TDOUBLE):
+	case CASE(	TUINT,	TVLONG):
+	case CASE(	TUINT,	TFLOAT):
+		regalloc(&nod, f, f);
+		gmove(f, &nod);
+		regsalloc(&nod1, &regnode);
+		gmove(&nod, &nod1);
+		gins(AFMOVL, &nod1, &fregnode0);
+		gins(ACMPL, &nod, nodconst(0));
+		gins(AJGE, Z, Z);
+		p1 = p;
+		gins(AFADDD, nodfconst(4294967296.), &fregnode0);
+		patch(p1, pc);
+		regfree(&nod);
+		return;
+
+/*
+ * fix to float
+ */
+	case CASE(	TCHAR,	TFLOAT):
+	case CASE(	TUCHAR,	TFLOAT):
+	case CASE(	TSHORT,	TFLOAT):
+	case CASE(	TUSHORT,TFLOAT):
+	case CASE(	TINT,	TFLOAT):
+	case CASE(	TLONG,	TFLOAT):
+	case CASE(	TIND,	TFLOAT):
+
+	case CASE(	TCHAR,	TDOUBLE):
+	case CASE(	TUCHAR,	TDOUBLE):
+	case CASE(	TSHORT,	TDOUBLE):
+	case CASE(	TUSHORT,TDOUBLE):
+	case CASE(	TINT,	TDOUBLE):
+	case CASE(	TLONG,	TDOUBLE):
+	case CASE(	TIND,	TDOUBLE):
+
+	case CASE(	TCHAR,	TVLONG):
+	case CASE(	TUCHAR,	TVLONG):
+	case CASE(	TSHORT,	TVLONG):
+	case CASE(	TUSHORT,TVLONG):
+	case CASE(	TINT,	TVLONG):
+	case CASE(	TLONG,	TVLONG):
+	case CASE(	TIND,	TVLONG):
+		regsalloc(&nod, &regnode);
+		gmove(f, &nod);
+		gins(AFMOVL, &nod, &fregnode0);
+		return;
+
+/*
+ * float to float
+ */
+	case CASE(	TFLOAT,	TFLOAT):
+	case CASE(	TDOUBLE,TFLOAT):
+	case CASE(	TVLONG,	TFLOAT):
+
+	case CASE(	TFLOAT,	TDOUBLE):
+	case CASE(	TDOUBLE,TDOUBLE):
+	case CASE(	TVLONG,	TDOUBLE):
+
+	case CASE(	TFLOAT,	TVLONG):
+	case CASE(	TDOUBLE,TVLONG):
+	case CASE(	TVLONG,	TVLONG):
+		a = AFMOVD;	break;
+	}
+	if(a == AMOVL || a == AFMOVD)
+	if(samaddr(f, t))
+		return;
+	gins(a, f, t);
+}
+
+void
+doindex(Node *n)
+{
+	Node nod, nod1;
+	int32 v;
+
+if(debug['Y'])
+prtree(n, "index");
+
+if(n->left->complex >= FNX)
+print("botch in doindex\n");
+
+	regalloc(&nod, &regnode, Z);
+	v = constnode.vconst;
+	cgen(n->right, &nod);
+	idx.ptr = D_NONE;
+	if(n->left->op == OCONST)
+		idx.ptr = D_CONST;
+	else if(n->left->op == OREGISTER)
+		idx.ptr = n->left->reg;
+	else if(n->left->op != OADDR) {
+		reg[D_BP]++;	// can't be used as a base
+		regalloc(&nod1, &regnode, Z);
+		cgen(n->left, &nod1);
+		idx.ptr = nod1.reg;
+		regfree(&nod1);
+		reg[D_BP]--;
+	}
+	idx.reg = nod.reg;
+	regfree(&nod);
+	constnode.vconst = v;
+}
+
+void
+gins(int a, Node *f, Node *t)
+{
+
+	if(f != Z && f->op == OINDEX)
+		doindex(f);
+	if(t != Z && t->op == OINDEX)
+		doindex(t);
+	nextpc();
+	p->as = a;
+	if(f != Z)
+		naddr(f, &p->from);
+	if(t != Z)
+		naddr(t, &p->to);
+	if(debug['g'])
+		print("%P\n", p);
+}
+
+void
+fgopcode(int o, Node *f, Node *t, int pop, int rev)
+{
+	int a, et;
+	Node nod;
+
+	et = TLONG;
+	if(f != Z && f->type != T)
+		et = f->type->etype;
+	if(!typefd[et]) {
+		diag(f, "fop: integer %O", o);
+		return;
+	}
+	if(debug['M']) {
+		if(t != Z && t->type != T)
+			print("gop: %O %O-%s Z\n", o, f->op, tnames[et]);
+		else
+			print("gop: %O %O-%s %O-%s\n", o,
+				f->op, tnames[et], t->op, tnames[t->type->etype]);
+	}
+	a = AGOK;
+	switch(o) {
+
+	case OASADD:
+	case OADD:
+		if(et == TFLOAT)
+			a = AFADDF;
+		else
+		if(et == TDOUBLE || et == TVLONG) {
+			a = AFADDD;
+			if(pop)
+				a = AFADDDP;
+		}
+		break;
+
+	case OASSUB:
+	case OSUB:
+		if(et == TFLOAT) {
+			a = AFSUBF;
+			if(rev)
+				a = AFSUBRF;
+		} else
+		if(et == TDOUBLE || et == TVLONG) {
+			a = AFSUBD;
+			if(pop)
+				a = AFSUBDP;
+			if(rev) {
+				a = AFSUBRD;
+				if(pop)
+					a = AFSUBRDP;
+			}
+		}
+		break;
+
+	case OASMUL:
+	case OMUL:
+		if(et == TFLOAT)
+			a = AFMULF;
+		else
+		if(et == TDOUBLE || et == TVLONG) {
+			a = AFMULD;
+			if(pop)
+				a = AFMULDP;
+		}
+		break;
+
+	case OASMOD:
+	case OMOD:
+	case OASDIV:
+	case ODIV:
+		if(et == TFLOAT) {
+			a = AFDIVF;
+			if(rev)
+				a = AFDIVRF;
+		} else
+		if(et == TDOUBLE || et == TVLONG) {
+			a = AFDIVD;
+			if(pop)
+				a = AFDIVDP;
+			if(rev) {
+				a = AFDIVRD;
+				if(pop)
+					a = AFDIVRDP;
+			}
+		}
+		break;
+
+	case OEQ:
+	case ONE:
+	case OLT:
+	case OLE:
+	case OGE:
+	case OGT:
+		pop += rev;
+		if(et == TFLOAT) {
+			a = AFCOMF;
+			if(pop) {
+				a = AFCOMFP;
+				if(pop > 1)
+					a = AGOK;
+			}
+		} else
+		if(et == TDOUBLE || et == TVLONG) {
+			a = AFCOMF;
+			if(pop) {
+				a = AFCOMDP;
+				if(pop > 1)
+					a = AFCOMDPP;
+			}
+		}
+		gins(a, f, t);
+		regalloc(&nod, &regnode, Z);
+		if(nod.reg != D_AX) {
+			regfree(&nod);
+			nod.reg = D_AX;
+			gins(APUSHL, &nod, Z);
+			gins(AWAIT, Z, Z);
+			gins(AFSTSW, Z, &nod);
+			gins(ASAHF, Z, Z);
+			gins(APOPL, Z, &nod);
+		} else {
+			gins(AWAIT, Z, Z);
+			gins(AFSTSW, Z, &nod);
+			gins(ASAHF, Z, Z);
+			regfree(&nod);
+		}
+		switch(o) {
+		case OEQ:	a = AJEQ; break;
+		case ONE:	a = AJNE; break;
+		case OLT:	a = AJCS; break;
+		case OLE:	a = AJLS; break;
+		case OGE:	a = AJCC; break;
+		case OGT:	a = AJHI; break;
+		}
+		gins(a, Z, Z);
+		return;
+	}
+	if(a == AGOK)
+		diag(Z, "bad in gopcode %O", o);
+	gins(a, f, t);
+}
+
+void
+gopcode(int o, Type *ty, Node *f, Node *t)
+{
+	int a, et;
+
+	et = TLONG;
+	if(ty != T)
+		et = ty->etype;
+	if(typefd[et] && o != OADDR && o != OFUNC) {
+		diag(f, "gop: float %O", o);
+		return;
+	}
+	if(debug['M']) {
+		if(f != Z && f->type != T)
+			print("gop: %O %O[%s],", o, f->op, tnames[et]);
+		else
+			print("gop: %O Z,", o);
+		if(t != Z && t->type != T)
+			print("%O[%s]\n", t->op, tnames[t->type->etype]);
+		else
+			print("Z\n");
+	}
+	a = AGOK;
+	switch(o) {
+	case OCOM:
+		a = ANOTL;
+		if(et == TCHAR || et == TUCHAR)
+			a = ANOTB;
+		if(et == TSHORT || et == TUSHORT)
+			a = ANOTW;
+		break;
+
+	case ONEG:
+		a = ANEGL;
+		if(et == TCHAR || et == TUCHAR)
+			a = ANEGB;
+		if(et == TSHORT || et == TUSHORT)
+			a = ANEGW;
+		break;
+
+	case OADDR:
+		a = ALEAL;
+		break;
+
+	case OASADD:
+	case OADD:
+		a = AADDL;
+		if(et == TCHAR || et == TUCHAR)
+			a = AADDB;
+		if(et == TSHORT || et == TUSHORT)
+			a = AADDW;
+		break;
+
+	case OASSUB:
+	case OSUB:
+		a = ASUBL;
+		if(et == TCHAR || et == TUCHAR)
+			a = ASUBB;
+		if(et == TSHORT || et == TUSHORT)
+			a = ASUBW;
+		break;
+
+	case OASOR:
+	case OOR:
+		a = AORL;
+		if(et == TCHAR || et == TUCHAR)
+			a = AORB;
+		if(et == TSHORT || et == TUSHORT)
+			a = AORW;
+		break;
+
+	case OASAND:
+	case OAND:
+		a = AANDL;
+		if(et == TCHAR || et == TUCHAR)
+			a = AANDB;
+		if(et == TSHORT || et == TUSHORT)
+			a = AANDW;
+		break;
+
+	case OASXOR:
+	case OXOR:
+		a = AXORL;
+		if(et == TCHAR || et == TUCHAR)
+			a = AXORB;
+		if(et == TSHORT || et == TUSHORT)
+			a = AXORW;
+		break;
+
+	case OASLSHR:
+	case OLSHR:
+		a = ASHRL;
+		if(et == TCHAR || et == TUCHAR)
+			a = ASHRB;
+		if(et == TSHORT || et == TUSHORT)
+			a = ASHRW;
+		break;
+
+	case OASASHR:
+	case OASHR:
+		a = ASARL;
+		if(et == TCHAR || et == TUCHAR)
+			a = ASARB;
+		if(et == TSHORT || et == TUSHORT)
+			a = ASARW;
+		break;
+
+	case OASASHL:
+	case OASHL:
+		a = ASALL;
+		if(et == TCHAR || et == TUCHAR)
+			a = ASALB;
+		if(et == TSHORT || et == TUSHORT)
+			a = ASALW;
+		break;
+
+	case OROTL:
+		a = AROLL;
+		if(et == TCHAR || et == TUCHAR)
+			a = AROLB;
+		if(et == TSHORT || et == TUSHORT)
+			a = AROLW;
+		break;
+
+	case OFUNC:
+		a = ACALL;
+		break;
+
+	case OASMUL:
+	case OMUL:
+		if(f->op == OREGISTER && t != Z && isreg(t, D_AX) && reg[D_DX] == 0)
+			t = Z;
+		a = AIMULL;
+		break;
+
+	case OASMOD:
+	case OMOD:
+	case OASDIV:
+	case ODIV:
+		a = AIDIVL;
+		break;
+
+	case OASLMUL:
+	case OLMUL:
+		a = AMULL;
+		break;
+
+	case OASLMOD:
+	case OLMOD:
+	case OASLDIV:
+	case OLDIV:
+		a = ADIVL;
+		break;
+
+	case OEQ:
+	case ONE:
+	case OLT:
+	case OLE:
+	case OGE:
+	case OGT:
+	case OLO:
+	case OLS:
+	case OHS:
+	case OHI:
+		a = ACMPL;
+		if(et == TCHAR || et == TUCHAR)
+			a = ACMPB;
+		if(et == TSHORT || et == TUSHORT)
+			a = ACMPW;
+		gins(a, f, t);
+		switch(o) {
+		case OEQ:	a = AJEQ; break;
+		case ONE:	a = AJNE; break;
+		case OLT:	a = AJLT; break;
+		case OLE:	a = AJLE; break;
+		case OGE:	a = AJGE; break;
+		case OGT:	a = AJGT; break;
+		case OLO:	a = AJCS; break;
+		case OLS:	a = AJLS; break;
+		case OHS:	a = AJCC; break;
+		case OHI:	a = AJHI; break;
+		}
+		gins(a, Z, Z);
+		return;
+	}
+	if(a == AGOK)
+		diag(Z, "bad in gopcode %O", o);
+	gins(a, f, t);
+}
+
+int
+samaddr(Node *f, Node *t)
+{
+
+	if(f->op != t->op)
+		return 0;
+	switch(f->op) {
+
+	case OREGISTER:
+		if(f->reg != t->reg)
+			break;
+		return 1;
+	}
+	return 0;
+}
+
+void
+gbranch(int o)
+{
+	int a;
+
+	a = AGOK;
+	switch(o) {
+	case ORETURN:
+		a = ARET;
+		break;
+	case OGOTO:
+		a = AJMP;
+		break;
+	}
+	nextpc();
+	if(a == AGOK) {
+		diag(Z, "bad in gbranch %O",  o);
+		nextpc();
+	}
+	p->as = a;
+}
+
+void
+patch(Prog *op, int32 pc)
+{
+	op->to.offset = pc;
+	op->to.type = D_BRANCH;
+	op->to.u.branch = nil;
+	op->pcond = nil;
+}
+
+void
+gpseudo(int a, Sym *s, Node *n)
+{
+
+	nextpc();
+	p->as = a;
+	p->from.type = D_EXTERN;
+	p->from.sym = linksym(s);
+
+	switch(a) {
+	case ATEXT:
+		p->from.scale = textflag;
+		textflag = 0;
+		break;
+	case AGLOBL:
+		p->from.scale = s->dataflag;
+		break;
+	}
+
+	if(s->class == CSTATIC)
+		p->from.type = D_STATIC;
+	naddr(n, &p->to);
+	if(a == ADATA || a == AGLOBL)
+		pc--;
+}
+
+void
+gpcdata(int index, int value)
+{
+	Node n1;
+	
+	n1 = *nodconst(index);
+	gins(APCDATA, &n1, nodconst(value));
+}
+
+void
+gprefetch(Node *n)
+{
+	Node n1;
+	
+	if(strcmp(getgo386(), "sse2") != 0) // assume no prefetch on old machines
+		return;
+
+	regalloc(&n1, n, Z);
+	gmove(n, &n1);
+	n1.op = OINDREG;
+	gins(APREFETCHNTA, &n1, Z);
+	regfree(&n1);
+}
+
+int
+sconst(Node *n)
+{
+	int32 v;
+
+	if(n->op == OCONST && !typefd[n->type->etype]) {
+		v = n->vconst;
+		if(v >= -32766L && v < 32766L)
+			return 1;
+	}
+	return 0;
+}
+
+int32
+exreg(Type *t)
+{
+	int32 o;
+
+	if(typechlp[t->etype]){
+		if(exregoffset >= 32)
+			return 0;
+		o = exregoffset;
+		exregoffset += 4;
+		return o+1;	// +1 to avoid 0 == failure; naddr case OEXREG will -1.
+	}
+
+	return 0;
+}
+
+schar	ewidth[NTYPE] =
+{
+	-1,		/*[TXXX]*/
+	SZ_CHAR,	/*[TCHAR]*/
+	SZ_CHAR,	/*[TUCHAR]*/
+	SZ_SHORT,	/*[TSHORT]*/
+	SZ_SHORT,	/*[TUSHORT]*/
+	SZ_INT,		/*[TINT]*/
+	SZ_INT,		/*[TUINT]*/
+	SZ_LONG,	/*[TLONG]*/
+	SZ_LONG,	/*[TULONG]*/
+	SZ_VLONG,	/*[TVLONG]*/
+	SZ_VLONG,	/*[TUVLONG]*/
+	SZ_FLOAT,	/*[TFLOAT]*/
+	SZ_DOUBLE,	/*[TDOUBLE]*/
+	SZ_IND,		/*[TIND]*/
+	0,		/*[TFUNC]*/
+	-1,		/*[TARRAY]*/
+	0,		/*[TVOID]*/
+	-1,		/*[TSTRUCT]*/
+	-1,		/*[TUNION]*/
+	SZ_INT,		/*[TENUM]*/
+};
+int32	ncast[NTYPE] =
+{
+	0,				/*[TXXX]*/
+	BCHAR|BUCHAR,			/*[TCHAR]*/
+	BCHAR|BUCHAR,			/*[TUCHAR]*/
+	BSHORT|BUSHORT,			/*[TSHORT]*/
+	BSHORT|BUSHORT,			/*[TUSHORT]*/
+	BINT|BUINT|BLONG|BULONG|BIND,	/*[TINT]*/
+	BINT|BUINT|BLONG|BULONG|BIND,	/*[TUINT]*/
+	BINT|BUINT|BLONG|BULONG|BIND,	/*[TLONG]*/
+	BINT|BUINT|BLONG|BULONG|BIND,	/*[TULONG]*/
+	BVLONG|BUVLONG,			/*[TVLONG]*/
+	BVLONG|BUVLONG,			/*[TUVLONG]*/
+	BFLOAT,				/*[TFLOAT]*/
+	BDOUBLE,			/*[TDOUBLE]*/
+	BLONG|BULONG|BIND,		/*[TIND]*/
+	0,				/*[TFUNC]*/
+	0,				/*[TARRAY]*/
+	0,				/*[TVOID]*/
+	BSTRUCT,			/*[TSTRUCT]*/
+	BUNION,				/*[TUNION]*/
+	0,				/*[TENUM]*/
+};
diff --git a/src/cmd/8g/Makefile b/src/cmd/8g/Makefile
new file mode 100644
index 0000000..3f528d7
--- /dev/null
+++ b/src/cmd/8g/Makefile
@@ -0,0 +1,5 @@
+# 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/8g/cgen.c b/src/cmd/8g/cgen.c
new file mode 100644
index 0000000..2735fb6
--- /dev/null
+++ b/src/cmd/8g/cgen.c
@@ -0,0 +1,1579 @@
+// 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.
+
+// TODO(rsc):
+//	assume CLD?
+
+#include <u.h>
+#include <libc.h>
+#include "gg.h"
+
+void
+mgen(Node *n, Node *n1, Node *rg)
+{
+	Node n2;
+
+	n1->op = OEMPTY;
+
+	if(n->addable) {
+		*n1 = *n;
+		if(n1->op == OREGISTER || n1->op == OINDREG)
+			reg[n->val.u.reg]++;
+		return;
+	}
+	tempname(n1, n->type);
+	cgen(n, n1);
+	if(n->type->width <= widthptr || isfloat[n->type->etype]) {
+		n2 = *n1;
+		regalloc(n1, n->type, rg);
+		gmove(&n2, n1);
+	}
+}
+
+void
+mfree(Node *n)
+{
+	if(n->op == OREGISTER)
+		regfree(n);
+}
+
+/*
+ * generate:
+ *	res = n;
+ * simplifies and calls gmove.
+ *
+ * TODO:
+ *	sudoaddable
+ */
+void
+cgen(Node *n, Node *res)
+{
+	Node *nl, *nr, *r, n1, n2, nt;
+	Prog *p1, *p2, *p3;
+	int a;
+
+	if(debug['g']) {
+		dump("\ncgen-n", n);
+		dump("cgen-res", res);
+	}
+
+	if(n == N || n->type == T)
+		fatal("cgen: n nil");
+	if(res == N || res->type == T)
+		fatal("cgen: res nil");
+
+	switch(n->op) {
+	case OSLICE:
+	case OSLICEARR:
+	case OSLICESTR:
+	case OSLICE3:
+	case OSLICE3ARR:
+		if (res->op != ONAME || !res->addable) {
+			tempname(&n1, n->type);
+			cgen_slice(n, &n1);
+			cgen(&n1, res);
+		} else
+			cgen_slice(n, res);
+		return;
+	case OEFACE:
+		if (res->op != ONAME || !res->addable) {
+			tempname(&n1, n->type);
+			cgen_eface(n, &n1);
+			cgen(&n1, res);
+		} else
+			cgen_eface(n, res);
+		return;
+	}
+
+	while(n->op == OCONVNOP)
+		n = n->left;
+
+	// function calls on both sides?  introduce temporary
+	if(n->ullman >= UINF && res->ullman >= UINF) {
+		tempname(&n1, n->type);
+		cgen(n, &n1);
+		cgen(&n1, res);
+		return;
+	}
+
+	// structs etc get handled specially
+	if(isfat(n->type)) {
+		if(n->type->width < 0)
+			fatal("forgot to compute width for %T", n->type);
+		sgen(n, res, n->type->width);
+		return;
+	}
+
+	// update addressability for string, slice
+	// can't do in walk because n->left->addable
+	// changes if n->left is an escaping local variable.
+	switch(n->op) {
+	case OSPTR:
+	case OLEN:
+		if(isslice(n->left->type) || istype(n->left->type, TSTRING))
+			n->addable = n->left->addable;
+		break;
+	case OCAP:
+		if(isslice(n->left->type))
+			n->addable = n->left->addable;
+		break;
+	case OITAB:
+		n->addable = n->left->addable;
+		break;
+	}
+
+	// if both are addressable, move
+	if(n->addable && res->addable) {
+		gmove(n, res);
+		return;
+	}
+
+	// if both are not addressable, use a temporary.
+	if(!n->addable && !res->addable) {
+		// could use regalloc here sometimes,
+		// but have to check for ullman >= UINF.
+		tempname(&n1, n->type);
+		cgen(n, &n1);
+		cgen(&n1, res);
+		return;
+	}
+
+	// if result is not addressable directly but n is,
+	// compute its address and then store via the address.
+	if(!res->addable) {
+		igen(res, &n1, N);
+		cgen(n, &n1);
+		regfree(&n1);
+		return;
+	}
+
+	// complex types
+	if(complexop(n, res)) {
+		complexgen(n, res);
+		return;
+	}
+
+	// otherwise, the result is addressable but n is not.
+	// let's do some computation.
+
+	// use ullman to pick operand to eval first.
+	nl = n->left;
+	nr = n->right;
+	if(nl != N && nl->ullman >= UINF)
+	if(nr != N && nr->ullman >= UINF) {
+		// both are hard
+		tempname(&n1, nl->type);
+		cgen(nl, &n1);
+		n2 = *n;
+		n2.left = &n1;
+		cgen(&n2, res);
+		return;
+	}
+
+	// 64-bit ops are hard on 32-bit machine.
+	if(is64(n->type) || is64(res->type) || n->left != N && is64(n->left->type)) {
+		switch(n->op) {
+		// math goes to cgen64.
+		case OMINUS:
+		case OCOM:
+		case OADD:
+		case OSUB:
+		case OMUL:
+		case OLROT:
+		case OLSH:
+		case ORSH:
+		case OAND:
+		case OOR:
+		case OXOR:
+			cgen64(n, res);
+			return;
+		}
+	}
+
+	if(nl != N && isfloat[n->type->etype] && isfloat[nl->type->etype]) {
+		cgen_float(n, res);
+		return;
+	}
+
+	switch(n->op) {
+	default:
+		dump("cgen", n);
+		fatal("cgen %O", n->op);
+		break;
+
+	case OREAL:
+	case OIMAG:
+	case OCOMPLEX:
+		fatal("unexpected complex");
+		return;
+
+	// these call bgen to get a bool value
+	case OOROR:
+	case OANDAND:
+	case OEQ:
+	case ONE:
+	case OLT:
+	case OLE:
+	case OGE:
+	case OGT:
+	case ONOT:
+		p1 = gbranch(AJMP, T, 0);
+		p2 = pc;
+		gmove(nodbool(1), res);
+		p3 = gbranch(AJMP, T, 0);
+		patch(p1, pc);
+		bgen(n, 1, 0, p2);
+		gmove(nodbool(0), res);
+		patch(p3, pc);
+		return;
+
+	case OPLUS:
+		cgen(nl, res);
+		return;
+
+	case OMINUS:
+	case OCOM:
+		a = optoas(n->op, nl->type);
+		goto uop;
+
+	// symmetric binary
+	case OAND:
+	case OOR:
+	case OXOR:
+	case OADD:
+	case OMUL:
+		a = optoas(n->op, nl->type);
+		if(a == AIMULB) {
+			cgen_bmul(n->op, nl, nr, res);
+			break;
+		}
+		goto sbop;
+
+	// asymmetric binary
+	case OSUB:
+		a = optoas(n->op, nl->type);
+		goto abop;
+
+	case OHMUL:
+		cgen_hmul(nl, nr, res);
+		break;
+
+	case OCONV:
+		if(eqtype(n->type, nl->type) || noconv(n->type, nl->type)) {
+			cgen(nl, res);
+			break;
+		}
+
+		tempname(&n2, n->type);
+		mgen(nl, &n1, res);
+		gmove(&n1, &n2);
+		gmove(&n2, res);
+		mfree(&n1);
+		break;
+
+	case ODOT:
+	case ODOTPTR:
+	case OINDEX:
+	case OIND:
+	case ONAME:	// PHEAP or PPARAMREF var
+		igen(n, &n1, res);
+		gmove(&n1, res);
+		regfree(&n1);
+		break;
+
+	case OITAB:
+		igen(nl, &n1, res);
+		n1.type = ptrto(types[TUINTPTR]);
+		gmove(&n1, res);
+		regfree(&n1);
+		break;
+
+	case OSPTR:
+		// pointer is the first word of string or slice.
+		if(isconst(nl, CTSTR)) {
+			regalloc(&n1, types[tptr], res);
+			p1 = gins(ALEAL, N, &n1);
+			datastring(nl->val.u.sval->s, nl->val.u.sval->len, &p1->from);
+			gmove(&n1, res);
+			regfree(&n1);
+			break;
+		}
+		igen(nl, &n1, res);
+		n1.type = n->type;
+		gmove(&n1, res);
+		regfree(&n1);
+		break;
+
+	case OLEN:
+		if(istype(nl->type, TMAP) || istype(nl->type, TCHAN)) {
+			// map has len in the first 32-bit word.
+			// a zero pointer means zero length
+			tempname(&n1, types[tptr]);
+			cgen(nl, &n1);
+			regalloc(&n2, types[tptr], N);
+			gmove(&n1, &n2);
+			n1 = n2;
+
+			nodconst(&n2, types[tptr], 0);
+			gins(optoas(OCMP, types[tptr]), &n1, &n2);
+			p1 = gbranch(optoas(OEQ, types[tptr]), T, -1);
+
+			n2 = n1;
+			n2.op = OINDREG;
+			n2.type = types[TINT32];
+			gmove(&n2, &n1);
+
+			patch(p1, pc);
+
+			gmove(&n1, res);
+			regfree(&n1);
+			break;
+		}
+		if(istype(nl->type, TSTRING) || isslice(nl->type)) {
+			// both slice and string have len one pointer into the struct.
+			igen(nl, &n1, res);
+			n1.type = types[TUINT32];
+			n1.xoffset += Array_nel;
+			gmove(&n1, res);
+			regfree(&n1);
+			break;
+		}
+		fatal("cgen: OLEN: unknown type %lT", nl->type);
+		break;
+
+	case OCAP:
+		if(istype(nl->type, TCHAN)) {
+			// chan has cap in the second 32-bit word.
+			// a zero pointer means zero length
+			tempname(&n1, types[tptr]);
+			cgen(nl, &n1);
+			regalloc(&n2, types[tptr], N);
+			gmove(&n1, &n2);
+			n1 = n2;
+
+			nodconst(&n2, types[tptr], 0);
+			gins(optoas(OCMP, types[tptr]), &n1, &n2);
+			p1 = gbranch(optoas(OEQ, types[tptr]), T, -1);
+
+			n2 = n1;
+			n2.op = OINDREG;
+			n2.xoffset = 4;
+			n2.type = types[TINT32];
+			gmove(&n2, &n1);
+
+			patch(p1, pc);
+
+			gmove(&n1, res);
+			regfree(&n1);
+			break;
+		}
+		if(isslice(nl->type)) {
+			igen(nl, &n1, res);
+			n1.type = types[TUINT32];
+			n1.xoffset += Array_cap;
+			gmove(&n1, res);
+			regfree(&n1);
+			break;
+		}
+		fatal("cgen: OCAP: unknown type %lT", nl->type);
+		break;
+
+	case OADDR:
+		agen(nl, res);
+		break;
+
+	case OCALLMETH:
+		cgen_callmeth(n, 0);
+		cgen_callret(n, res);
+		break;
+
+	case OCALLINTER:
+		cgen_callinter(n, res, 0);
+		cgen_callret(n, res);
+		break;
+
+	case OCALLFUNC:
+		cgen_call(n, 0);
+		cgen_callret(n, res);
+		break;
+
+	case OMOD:
+	case ODIV:
+		cgen_div(n->op, nl, nr, res);
+		break;
+
+	case OLSH:
+	case ORSH:
+	case OLROT:
+		cgen_shift(n->op, n->bounded, nl, nr, res);
+		break;
+	}
+	return;
+
+sbop:	// symmetric binary
+	if(nl->ullman < nr->ullman || nl->op == OLITERAL) {
+		r = nl;
+		nl = nr;
+		nr = r;
+	}
+
+abop:	// asymmetric binary
+	if(smallintconst(nr)) {
+		mgen(nl, &n1, res);
+		regalloc(&n2, nl->type, &n1);
+		gmove(&n1, &n2);
+		gins(a, nr, &n2);
+		gmove(&n2, res);
+		regfree(&n2);
+		mfree(&n1);
+	} else if(nl->ullman >= nr->ullman) {
+		tempname(&nt, nl->type);
+		cgen(nl, &nt);
+		mgen(nr, &n2, N);
+		regalloc(&n1, nl->type, res);
+		gmove(&nt, &n1);
+		gins(a, &n2, &n1);
+		gmove(&n1, res);
+		regfree(&n1);
+		mfree(&n2);
+	} else {
+		regalloc(&n2, nr->type, res);
+		cgen(nr, &n2);
+		regalloc(&n1, nl->type, N);
+		cgen(nl, &n1);
+		gins(a, &n2, &n1);
+		regfree(&n2);
+		gmove(&n1, res);
+		regfree(&n1);
+	}
+	return;
+
+uop:	// unary
+	tempname(&n1, nl->type);
+	cgen(nl, &n1);
+	gins(a, N, &n1);
+	gmove(&n1, res);
+	return;
+}
+
+/*
+ * generate an addressable node in res, containing the value of n.
+ * n is an array index, and might be any size; res width is <= 32-bit.
+ * returns Prog* to patch to panic call.
+ */
+static Prog*
+igenindex(Node *n, Node *res, int bounded)
+{
+	Node tmp, lo, hi, zero;
+
+	if(!is64(n->type)) {
+		if(n->addable) {
+			// nothing to do.
+			*res = *n;
+		} else {
+			tempname(res, types[TUINT32]);
+			cgen(n, res);
+		}
+		return nil;
+	}
+
+	tempname(&tmp, types[TINT64]);
+	cgen(n, &tmp);
+	split64(&tmp, &lo, &hi);
+	tempname(res, types[TUINT32]);
+	gmove(&lo, res);
+	if(bounded) {
+		splitclean();
+		return nil;
+	}
+	nodconst(&zero, types[TINT32], 0);
+	gins(ACMPL, &hi, &zero);
+	splitclean();
+	return gbranch(AJNE, T, +1);
+}
+		
+/*
+ * address gen
+ *	res = &n;
+ * The generated code checks that the result is not nil.
+ */
+void
+agen(Node *n, Node *res)
+{
+	Node *nl, *nr;
+	Node n1, n2, n3, tmp, nlen;
+	Type *t;
+	uint32 w;
+	uint64 v;
+	Prog *p1, *p2;
+	int bounded;
+
+	if(debug['g']) {
+		dump("\nagen-res", res);
+		dump("agen-r", n);
+	}
+	if(n == N || n->type == T || res == N || res->type == T)
+		fatal("agen");
+
+	while(n->op == OCONVNOP)
+		n = n->left;
+
+	if(isconst(n, CTNIL) && n->type->width > widthptr) {
+		// Use of a nil interface or nil slice.
+		// Create a temporary we can take the address of and read.
+		// 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);
+		gmove(&n2, res);
+		regfree(&n2);
+		return;
+	}
+		
+	// addressable var is easy
+	if(n->addable) {
+		if(n->op == OREGISTER)
+			fatal("agen OREGISTER");
+		regalloc(&n1, types[tptr], res);
+		gins(ALEAL, n, &n1);
+		gmove(&n1, res);
+		regfree(&n1);
+		return;
+	}
+
+	// let's compute
+	nl = n->left;
+	nr = n->right;
+
+	switch(n->op) {
+	default:
+		fatal("agen %O", n->op);
+
+	case OCALLMETH:
+		cgen_callmeth(n, 0);
+		cgen_aret(n, res);
+		break;
+
+	case OCALLINTER:
+		cgen_callinter(n, res, 0);
+		cgen_aret(n, res);
+		break;
+
+	case OCALLFUNC:
+		cgen_call(n, 0);
+		cgen_aret(n, res);
+		break;
+
+	case OSLICE:
+	case OSLICEARR:
+	case OSLICESTR:
+	case OSLICE3:
+	case OSLICE3ARR:
+		tempname(&n1, n->type);
+		cgen_slice(n, &n1);
+		agen(&n1, res);
+		break;
+
+	case OEFACE:
+		tempname(&n1, n->type);
+		cgen_eface(n, &n1);
+		agen(&n1, res);
+		break;
+
+	case OINDEX:
+		p2 = nil;  // to be patched to panicindex.
+		w = n->type->width;
+		bounded = debug['B'] || n->bounded;
+		if(nr->addable) {
+			// Generate &nl first, and move nr into register.
+			if(!isconst(nl, CTSTR))
+				igen(nl, &n3, res);
+			if(!isconst(nr, CTINT)) {
+				p2 = igenindex(nr, &tmp, bounded);
+				regalloc(&n1, tmp.type, N);
+				gmove(&tmp, &n1);
+			}
+		} else if(nl->addable) {
+			// Generate nr first, and move &nl into register.
+			if(!isconst(nr, CTINT)) {
+				p2 = igenindex(nr, &tmp, bounded);
+				regalloc(&n1, tmp.type, N);
+				gmove(&tmp, &n1);
+			}
+			if(!isconst(nl, CTSTR))
+				igen(nl, &n3, res);
+		} else {
+			p2 = igenindex(nr, &tmp, bounded);
+			nr = &tmp;
+			if(!isconst(nl, CTSTR))
+				igen(nl, &n3, res);
+			regalloc(&n1, tmp.type, N);
+			gins(optoas(OAS, tmp.type), &tmp, &n1);
+		}
+
+		// For fixed array we really want the pointer in n3.
+		if(isfixedarray(nl->type)) {
+			regalloc(&n2, types[tptr], &n3);
+			agen(&n3, &n2);
+			regfree(&n3);
+			n3 = n2;
+		}
+
+		// &a[0] is in n3 (allocated in res)
+		// i is in n1 (if not constant)
+		// len(a) is in nlen (if needed)
+		// w is width
+
+		// constant index
+		if(isconst(nr, CTINT)) {
+			if(isconst(nl, CTSTR))
+				fatal("constant string constant index");  // front end should handle
+			v = mpgetfix(nr->val.u.xval);
+			if(isslice(nl->type) || nl->type->etype == TSTRING) {
+				if(!debug['B'] && !n->bounded) {
+					nlen = n3;
+					nlen.type = types[TUINT32];
+					nlen.xoffset += Array_nel;
+					nodconst(&n2, types[TUINT32], v);
+					gins(optoas(OCMP, types[TUINT32]), &nlen, &n2);
+					p1 = gbranch(optoas(OGT, types[TUINT32]), T, +1);
+					ginscall(panicindex, -1);
+					patch(p1, pc);
+				}
+			}
+
+			// Load base pointer in n2 = n3.
+			regalloc(&n2, types[tptr], &n3);
+			n3.type = types[tptr];
+			n3.xoffset += Array_array;
+			gmove(&n3, &n2);
+			regfree(&n3);
+			if (v*w != 0) {
+				nodconst(&n1, types[tptr], v*w);
+				gins(optoas(OADD, types[tptr]), &n1, &n2);
+			}
+			gmove(&n2, res);
+			regfree(&n2);
+			break;
+		}
+
+		// i is in register n1, extend to 32 bits.
+		t = types[TUINT32];
+		if(issigned[n1.type->etype])
+			t = types[TINT32];
+
+		regalloc(&n2, t, &n1);			// i
+		gmove(&n1, &n2);
+		regfree(&n1);
+
+		if(!debug['B'] && !n->bounded) {
+			// check bounds
+			t = types[TUINT32];
+			if(isconst(nl, CTSTR)) {
+				nodconst(&nlen, t, nl->val.u.sval->len);
+			} else if(isslice(nl->type) || nl->type->etype == TSTRING) {
+				nlen = n3;
+				nlen.type = t;
+				nlen.xoffset += Array_nel;
+			} else {
+				nodconst(&nlen, t, nl->type->bound);
+			}
+			gins(optoas(OCMP, t), &n2, &nlen);
+			p1 = gbranch(optoas(OLT, t), T, +1);
+			if(p2)
+				patch(p2, pc);
+			ginscall(panicindex, -1);
+			patch(p1, pc);
+		}
+
+		if(isconst(nl, CTSTR)) {
+			regalloc(&n3, types[tptr], res);
+			p1 = gins(ALEAL, N, &n3);
+			datastring(nl->val.u.sval->s, nl->val.u.sval->len, &p1->from);
+			p1->from.scale = 1;
+			p1->from.index = n2.val.u.reg;
+			goto indexdone;
+		}
+
+		// Load base pointer in n3.
+		regalloc(&tmp, types[tptr], &n3);
+		if(isslice(nl->type) || nl->type->etype == TSTRING) {
+			n3.type = types[tptr];
+			n3.xoffset += Array_array;
+			gmove(&n3, &tmp);
+		}
+		regfree(&n3);
+		n3 = tmp;
+
+		if(w == 0) {
+			// nothing to do
+		} else if(w == 1 || w == 2 || w == 4 || w == 8) {
+			// LEAL (n3)(n2*w), n3
+			p1 = gins(ALEAL, &n2, &n3);
+			p1->from.scale = w;
+			p1->from.index = p1->from.type;
+			p1->from.type = p1->to.type + D_INDIR;
+		} else {
+			nodconst(&tmp, types[TUINT32], w);
+			gins(optoas(OMUL, types[TUINT32]), &tmp, &n2);
+			gins(optoas(OADD, types[tptr]), &n2, &n3);
+		}
+
+	indexdone:
+		gmove(&n3, res);
+		regfree(&n2);
+		regfree(&n3);
+		break;
+
+	case ONAME:
+		// should only get here with names in this func.
+		if(n->funcdepth > 0 && n->funcdepth != funcdepth) {
+			dump("bad agen", n);
+			fatal("agen: bad ONAME funcdepth %d != %d",
+				n->funcdepth, funcdepth);
+		}
+
+		// should only get here for heap vars or paramref
+		if(!(n->class & PHEAP) && n->class != PPARAMREF) {
+			dump("bad agen", n);
+			fatal("agen: bad ONAME class %#x", n->class);
+		}
+		cgen(n->heapaddr, res);
+		if(n->xoffset != 0) {
+			nodconst(&n1, types[tptr], n->xoffset);
+			gins(optoas(OADD, types[tptr]), &n1, res);
+		}
+		break;
+
+	case OIND:
+		cgen(nl, res);
+		cgen_checknil(res);
+		break;
+
+	case ODOT:
+		agen(nl, res);
+		if(n->xoffset != 0) {
+			nodconst(&n1, types[tptr], n->xoffset);
+			gins(optoas(OADD, types[tptr]), &n1, res);
+		}
+		break;
+
+	case ODOTPTR:
+		t = nl->type;
+		if(!isptr[t->etype])
+			fatal("agen: not ptr %N", n);
+		cgen(nl, res);
+		cgen_checknil(res);
+		if(n->xoffset != 0) {
+			nodconst(&n1, types[tptr], n->xoffset);
+			gins(optoas(OADD, types[tptr]), &n1, res);
+		}
+		break;
+	}
+}
+
+/*
+ * generate:
+ *	newreg = &n;
+ *	res = newreg
+ *
+ * on exit, a has been changed to be *newreg.
+ * caller must regfree(a).
+ * The generated code checks that the result is not *nil.
+ */
+void
+igen(Node *n, Node *a, Node *res)
+{
+	Type *fp;
+	Iter flist;
+	Node n1;
+
+	if(debug['g']) {
+		dump("\nigen-n", n);
+	}
+	switch(n->op) {
+	case ONAME:
+		if((n->class&PHEAP) || n->class == PPARAMREF)
+			break;
+		*a = *n;
+		return;
+
+	case OINDREG:
+		// Increase the refcount of the register so that igen's caller
+		// has to call regfree.
+		if(n->val.u.reg != D_SP)
+			reg[n->val.u.reg]++;
+		*a = *n;
+		return;
+
+	case ODOT:
+		igen(n->left, a, res);
+		a->xoffset += n->xoffset;
+		a->type = n->type;
+		return;
+
+	case ODOTPTR:
+		switch(n->left->op) {
+		case ODOT:
+		case ODOTPTR:
+		case OCALLFUNC:
+		case OCALLMETH:
+		case OCALLINTER:
+			// igen-able nodes.
+			igen(n->left, &n1, res);
+			regalloc(a, types[tptr], &n1);
+			gmove(&n1, a);
+			regfree(&n1);
+			break;
+		default:
+			regalloc(a, types[tptr], res);
+			cgen(n->left, a);
+		}
+		cgen_checknil(a);
+		a->op = OINDREG;
+		a->xoffset += n->xoffset;
+		a->type = n->type;
+		return;
+
+	case OCALLFUNC:
+	case OCALLMETH:
+	case OCALLINTER:
+		switch(n->op) {
+		case OCALLFUNC:
+			cgen_call(n, 0);
+			break;
+		case OCALLMETH:
+			cgen_callmeth(n, 0);
+			break;
+		case OCALLINTER:
+			cgen_callinter(n, N, 0);
+			break;
+		}
+		fp = structfirst(&flist, getoutarg(n->left->type));
+		memset(a, 0, sizeof *a);
+		a->op = OINDREG;
+		a->val.u.reg = D_SP;
+		a->addable = 1;
+		a->xoffset = fp->width;
+		a->type = n->type;
+		return;
+
+	case OINDEX:
+		// Index of fixed-size array by constant can
+		// put the offset in the addressing.
+		// Could do the same for slice except that we need
+		// to use the real index for the bounds checking.
+		if(isfixedarray(n->left->type) ||
+		   (isptr[n->left->type->etype] && isfixedarray(n->left->left->type)))
+		if(isconst(n->right, CTINT)) {
+			// Compute &a.
+			if(!isptr[n->left->type->etype])
+				igen(n->left, a, res);
+			else {
+				igen(n->left, &n1, res);
+				cgen_checknil(&n1);
+				regalloc(a, types[tptr], res);
+				gmove(&n1, a);
+				regfree(&n1);
+				a->op = OINDREG;
+			}
+
+			// Compute &a[i] as &a + i*width.
+			a->type = n->type;
+			a->xoffset += mpgetfix(n->right->val.u.xval)*n->type->width;
+			return;
+		}
+		break;
+	}
+
+	// release register for now, to avoid
+	// confusing tempname.
+	if(res != N && res->op == OREGISTER)
+		reg[res->val.u.reg]--;
+	tempname(&n1, types[tptr]);
+	agen(n, &n1);
+	if(res != N && res->op == OREGISTER)
+		reg[res->val.u.reg]++;
+	regalloc(a, types[tptr], res);
+	gmove(&n1, a);
+	a->op = OINDREG;
+	a->type = n->type;
+}
+
+/*
+ * branch gen
+ *	if(n == true) goto to;
+ */
+void
+bgen(Node *n, int true, int likely, Prog *to)
+{
+	int et, a;
+	Node *nl, *nr, *r;
+	Node n1, n2, tmp;
+	Prog *p1, *p2;
+
+	if(debug['g']) {
+		dump("\nbgen", n);
+	}
+
+	if(n == N)
+		n = nodbool(1);
+
+	if(n->ninit != nil)
+		genlist(n->ninit);
+
+	if(n->type == T) {
+		convlit(&n, types[TBOOL]);
+		if(n->type == T)
+			return;
+	}
+
+	et = n->type->etype;
+	if(et != TBOOL) {
+		yyerror("cgen: bad type %T for %O", n->type, n->op);
+		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;
+
+	if(nl != N && isfloat[nl->type->etype]) {
+		bgen_float(n, true, likely, to);
+		return;
+	}
+
+	switch(n->op) {
+	default:
+	def:
+		regalloc(&n1, n->type, N);
+		cgen(n, &n1);
+		nodconst(&n2, n->type, 0);
+		gins(optoas(OCMP, n->type), &n1, &n2);
+		a = AJNE;
+		if(!true)
+			a = AJEQ;
+		patch(gbranch(a, n->type, likely), to);
+		regfree(&n1);
+		return;
+
+	case OLITERAL:
+		// need to ask if it is bool?
+		if(!true == !n->val.u.bval)
+			patch(gbranch(AJMP, T, 0), to);
+		return;
+
+	case ONAME:
+		if(!n->addable)
+			goto def;
+		nodconst(&n1, n->type, 0);
+		gins(optoas(OCMP, n->type), n, &n1);
+		a = AJNE;
+		if(!true)
+			a = AJEQ;
+		patch(gbranch(a, n->type, likely), to);
+		return;
+
+	case OANDAND:
+		if(!true)
+			goto caseor;
+
+	caseand:
+		p1 = gbranch(AJMP, T, 0);
+		p2 = gbranch(AJMP, T, 0);
+		patch(p1, pc);
+		bgen(n->left, !true, -likely, p2);
+		bgen(n->right, !true, -likely, p2);
+		p1 = gbranch(AJMP, T, 0);
+		patch(p1, to);
+		patch(p2, pc);
+		return;
+
+	case OOROR:
+		if(!true)
+			goto caseand;
+
+	caseor:
+		bgen(n->left, true, likely, to);
+		bgen(n->right, true, likely, to);
+		return;
+
+	case OEQ:
+	case ONE:
+	case OLT:
+	case OGT:
+	case OLE:
+	case OGE:
+		nr = n->right;
+		if(nr == N || nr->type == T)
+			return;
+
+	case ONOT:	// unary
+		nl = n->left;
+		if(nl == N || nl->type == T)
+			return;
+	}
+
+	switch(n->op) {
+	case ONOT:
+		bgen(nl, !true, likely, to);
+		break;
+
+	case OEQ:
+	case ONE:
+	case OLT:
+	case OGT:
+	case OLE:
+	case OGE:
+		a = n->op;
+		if(!true) {
+			a = brcom(a);
+			true = !true;
+		}
+
+		// make simplest on right
+		if(nl->op == OLITERAL || (nl->ullman < nr->ullman && nl->ullman < UINF)) {
+			a = brrev(a);
+			r = nl;
+			nl = nr;
+			nr = r;
+		}
+
+		if(isslice(nl->type)) {
+			// front end should only leave cmp to literal nil
+			if((a != OEQ && a != ONE) || nr->op != OLITERAL) {
+				yyerror("illegal slice comparison");
+				break;
+			}
+			a = optoas(a, types[tptr]);
+			igen(nl, &n1, N);
+			n1.xoffset += Array_array;
+			n1.type = types[tptr];
+			nodconst(&tmp, types[tptr], 0);
+			gins(optoas(OCMP, types[tptr]), &n1, &tmp);
+			patch(gbranch(a, types[tptr], likely), to);
+			regfree(&n1);
+			break;
+		}
+
+		if(isinter(nl->type)) {
+			// front end should only leave cmp to literal nil
+			if((a != OEQ && a != ONE) || nr->op != OLITERAL) {
+				yyerror("illegal interface comparison");
+				break;
+			}
+			a = optoas(a, types[tptr]);
+			igen(nl, &n1, N);
+			n1.type = types[tptr];
+			nodconst(&tmp, types[tptr], 0);
+			gins(optoas(OCMP, types[tptr]), &n1, &tmp);
+			patch(gbranch(a, types[tptr], likely), to);
+			regfree(&n1);
+			break;
+		}
+
+		if(iscomplex[nl->type->etype]) {
+			complexbool(a, nl, nr, true, likely, to);
+			break;
+		}
+
+		if(is64(nr->type)) {
+			if(!nl->addable || isconst(nl, CTINT)) {
+				tempname(&n1, nl->type);
+				cgen(nl, &n1);
+				nl = &n1;
+			}
+			if(!nr->addable) {
+				tempname(&n2, nr->type);
+				cgen(nr, &n2);
+				nr = &n2;
+			}
+			cmp64(nl, nr, a, likely, to);
+			break;
+		}
+
+		if(nr->ullman >= UINF) {
+			if(!nl->addable) {
+				tempname(&n1, nl->type);
+				cgen(nl, &n1);
+				nl = &n1;
+			}
+			if(!nr->addable) {
+				tempname(&tmp, nr->type);
+				cgen(nr, &tmp);
+				nr = &tmp;
+			}
+			regalloc(&n2, nr->type, N);
+			cgen(nr, &n2);
+			nr = &n2;
+			goto cmp;
+		}
+
+		if(!nl->addable) {
+			tempname(&n1, nl->type);
+			cgen(nl, &n1);
+			nl = &n1;
+		}
+
+		if(smallintconst(nr)) {
+			gins(optoas(OCMP, nr->type), nl, nr);
+			patch(gbranch(optoas(a, nr->type), nr->type, likely), to);
+			break;
+		}
+
+		if(!nr->addable) {
+			tempname(&tmp, nr->type);
+			cgen(nr, &tmp);
+			nr = &tmp;
+		}
+		regalloc(&n2, nr->type, N);
+		gmove(nr, &n2);
+		nr = &n2;
+
+cmp:
+		gins(optoas(OCMP, nr->type), nl, nr);
+		patch(gbranch(optoas(a, nr->type), nr->type, likely), to);
+
+		if(nl->op == OREGISTER)
+			regfree(nl);
+		regfree(nr);
+		break;
+	}
+}
+
+/*
+ * n is on stack, either local variable
+ * or return value from function call.
+ * return n's offset from SP.
+ */
+int32
+stkof(Node *n)
+{
+	Type *t;
+	Iter flist;
+	int32 off;
+
+	switch(n->op) {
+	case OINDREG:
+		return n->xoffset;
+
+	case ODOT:
+		t = n->left->type;
+		if(isptr[t->etype])
+			break;
+		off = stkof(n->left);
+		if(off == -1000 || off == 1000)
+			return off;
+		return off + n->xoffset;
+
+	case OINDEX:
+		t = n->left->type;
+		if(!isfixedarray(t))
+			break;
+		off = stkof(n->left);
+		if(off == -1000 || off == 1000)
+			return off;
+		if(isconst(n->right, CTINT))
+			return off + t->type->width * mpgetfix(n->right->val.u.xval);
+		return 1000;
+		
+	case OCALLMETH:
+	case OCALLINTER:
+	case OCALLFUNC:
+		t = n->left->type;
+		if(isptr[t->etype])
+			t = t->type;
+
+		t = structfirst(&flist, getoutarg(t));
+		if(t != T)
+			return t->width;
+		break;
+	}
+
+	// botch - probably failing to recognize address
+	// arithmetic on the above. eg INDEX and DOT
+	return -1000;
+}
+
+/*
+ * struct gen
+ *	memmove(&res, &n, w);
+ */
+void
+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);
+		dump("r", n);
+		dump("res", res);
+	}
+	if(n->ullman >= UINF && res->ullman >= UINF)
+		fatal("sgen UINF");
+
+	if(w < 0 || (int32)w != w)
+		fatal("sgen copy %lld", w);
+
+	if(w == 0) {
+		// evaluate side effects only.
+		tempname(&tdst, types[tptr]);
+		agen(res, &tdst);
+		agen(n, &tdst);
+		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;
+
+	// offset on the stack
+	osrc = stkof(n);
+	odst = stkof(res);
+	
+	if(osrc != -1000 && odst != -1000 && (osrc == 1000 || odst == 1000)) {
+		// osrc and odst both on stack, and at least one is in
+		// an unknown position.  Could generate code to test
+		// for forward/backward copy, but instead just copy
+		// to a temporary location first.
+		tempname(&tsrc, n->type);
+		sgen(n, &tsrc, w);
+		sgen(&tsrc, res, w);
+		return;
+	}
+
+	nodreg(&dst, types[tptr], D_DI);
+	nodreg(&src, types[tptr], D_SI);
+
+	tempname(&tsrc, types[tptr]);
+	tempname(&tdst, types[tptr]);
+	if(!n->addable)
+		agen(n, &tsrc);
+	if(!res->addable)
+		agen(res, &tdst);
+	if(n->addable)
+		agen(n, &src);
+	else
+		gmove(&tsrc, &src);
+
+	if(res->op == ONAME)
+		gvardef(res);
+
+	if(res->addable)
+		agen(res, &dst);
+	else
+		gmove(&tdst, &dst);
+
+	c = w % 4;	// bytes
+	q = w / 4;	// doublewords
+
+	// if we are copying forward on the stack and
+	// the src and dst overlap, then reverse direction
+	if(osrc < odst && odst < osrc+w) {
+		// reverse direction
+		gins(ASTD, N, N);		// set direction flag
+		if(c > 0) {
+			gconreg(AADDL, w-1, D_SI);
+			gconreg(AADDL, w-1, D_DI);
+
+			gconreg(AMOVL, c, D_CX);
+			gins(AREP, N, N);	// repeat
+			gins(AMOVSB, N, N);	// MOVB *(SI)-,*(DI)-
+		}
+
+		if(q > 0) {
+			if(c > 0) {
+				gconreg(AADDL, -3, D_SI);
+				gconreg(AADDL, -3, D_DI);
+			} else {
+				gconreg(AADDL, w-4, D_SI);
+				gconreg(AADDL, w-4, D_DI);
+			}
+			gconreg(AMOVL, q, D_CX);
+			gins(AREP, N, N);	// repeat
+			gins(AMOVSL, N, N);	// MOVL *(SI)-,*(DI)-
+		}
+		// we leave with the flag clear
+		gins(ACLD, N, N);
+	} else {
+		gins(ACLD, N, N);	// paranoia.  TODO(rsc): remove?
+		// normal direction
+		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 ../../runtime/asm_386.s
+			p->to.offset = 10*(128-q);
+		} else
+		while(q > 0) {
+			gins(AMOVSL, N, N);	// MOVL *(SI)+,*(DI)+
+			q--;
+		}
+		while(c > 0) {
+			gins(AMOVSB, N, N);	// MOVB *(SI)+,*(DI)+
+			c--;
+		}
+	}
+}
+
+static int
+cadable(Node *n)
+{
+	if(!n->addable) {
+		// dont know how it happens,
+		// but it does
+		return 0;
+	}
+
+	switch(n->op) {
+	case ONAME:
+		return 1;
+	}
+	return 0;
+}
+
+/*
+ * copy a composite value by moving its individual components.
+ * Slices, strings and interfaces are supported.
+ * nr is N when assigning a zero value.
+ * return 1 if can do, 0 if can't.
+ */
+int
+componentgen(Node *nr, Node *nl)
+{
+	Node nodl, nodr;
+	Type *t;
+	int freel, freer;
+	vlong fldcount;
+	vlong loffset, roffset;
+
+	freel = 0;
+	freer = 0;
+
+	switch(nl->type->etype) {
+	default:
+		goto no;
+
+	case TARRAY:
+		t = nl->type;
+
+		// Slices are ok.
+		if(isslice(t))
+			break;
+		// Small arrays are ok.
+		if(t->bound > 0 && t->bound <= 3 && !isfat(t->type))
+			break;
+
+		goto no;
+
+	case TSTRUCT:
+		// Small structs with non-fat types are ok.
+		// Zero-sized structs are treated separately elsewhere.
+		fldcount = 0;
+		for(t=nl->type->type; t; t=t->down) {
+			if(isfat(t->type))
+				goto no;
+			if(t->etype != TFIELD)
+				fatal("componentgen: not a TFIELD: %lT", t);
+			fldcount++;
+		}
+		if(fldcount == 0 || fldcount > 4)
+			goto no;
+
+		break;
+
+	case TSTRING:
+	case TINTER:
+		break;
+	}
+
+	nodl = *nl;
+	if(!cadable(nl)) {
+		if(nr == N || !cadable(nr))
+			goto no;
+		igen(nl, &nodl, N);
+		freel = 1;
+	}
+
+	if(nr != N) {
+		nodr = *nr;
+		if(!cadable(nr)) {
+			igen(nr, &nodr, N);
+			freer = 1;
+		}
+	}
+	
+	// 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;
+			nodr.type = nodl.type;
+			for(fldcount=0; fldcount < t->bound; fldcount++) {
+				if(nr == N)
+					clearslim(&nodl);
+				else
+					gmove(&nodr, &nodl);
+				nodl.xoffset += t->type->width;
+				nodr.xoffset += t->type->width;
+			}
+			goto yes;
+		}
+
+		// componentgen for slices.
+		nodl.xoffset += Array_array;
+		nodl.type = ptrto(nl->type->type);
+
+		if(nr != N) {
+			nodr.xoffset += Array_array;
+			nodr.type = nodl.type;
+		} else
+			nodconst(&nodr, nodl.type, 0);
+		gmove(&nodr, &nodl);
+
+		nodl.xoffset += Array_nel-Array_array;
+		nodl.type = types[simtype[TUINT]];
+
+		if(nr != N) {
+			nodr.xoffset += Array_nel-Array_array;
+			nodr.type = nodl.type;
+		} else
+			nodconst(&nodr, nodl.type, 0);
+		gmove(&nodr, &nodl);
+
+		nodl.xoffset += Array_cap-Array_nel;
+		nodl.type = types[simtype[TUINT]];
+
+		if(nr != N) {
+			nodr.xoffset += Array_cap-Array_nel;
+			nodr.type = nodl.type;
+		} else
+			nodconst(&nodr, nodl.type, 0);
+		gmove(&nodr, &nodl);
+
+		goto yes;
+
+	case TSTRING:
+		if(nl->op == ONAME)
+			gvardef(nl);
+		nodl.xoffset += Array_array;
+		nodl.type = ptrto(types[TUINT8]);
+
+		if(nr != N) {
+			nodr.xoffset += Array_array;
+			nodr.type = nodl.type;
+		} else
+			nodconst(&nodr, nodl.type, 0);
+		gmove(&nodr, &nodl);
+
+		nodl.xoffset += Array_nel-Array_array;
+		nodl.type = types[simtype[TUINT]];
+
+		if(nr != N) {
+			nodr.xoffset += Array_nel-Array_array;
+			nodr.type = nodl.type;
+		} else
+			nodconst(&nodr, nodl.type, 0);
+		gmove(&nodr, &nodl);
+
+		goto yes;
+
+	case TINTER:
+		if(nl->op == ONAME)
+			gvardef(nl);
+		nodl.xoffset += Array_array;
+		nodl.type = ptrto(types[TUINT8]);
+
+		if(nr != N) {
+			nodr.xoffset += Array_array;
+			nodr.type = nodl.type;
+		} else
+			nodconst(&nodr, nodl.type, 0);
+		gmove(&nodr, &nodl);
+
+		nodl.xoffset += Array_nel-Array_array;
+		nodl.type = ptrto(types[TUINT8]);
+
+		if(nr != N) {
+			nodr.xoffset += Array_nel-Array_array;
+			nodr.type = nodl.type;
+		} else
+			nodconst(&nodr, nodl.type, 0);
+		gmove(&nodr, &nodl);
+
+		goto yes;
+
+	case TSTRUCT:
+		if(nl->op == ONAME)
+			gvardef(nl);
+		loffset = nodl.xoffset;
+		roffset = nodr.xoffset;
+		// funarg structs may not begin at offset zero.
+		if(nl->type->etype == TSTRUCT && nl->type->funarg && nl->type->type)
+			loffset -= nl->type->type->width;
+		if(nr != N && nr->type->etype == TSTRUCT && nr->type->funarg && nr->type->type)
+			roffset -= nr->type->type->width;
+
+		for(t=nl->type->type; t; t=t->down) {
+			nodl.xoffset = loffset + t->width;
+			nodl.type = t->type;
+
+			if(nr == N)
+				clearslim(&nodl);
+			else {
+				nodr.xoffset = roffset + t->width;
+				nodr.type = nodl.type;
+				gmove(&nodr, &nodl);
+			}
+		}
+		goto yes;
+	}
+
+no:
+	if(freer)
+		regfree(&nodr);
+	if(freel)
+		regfree(&nodl);
+	return 0;
+
+yes:
+	if(freer)
+		regfree(&nodr);
+	if(freel)
+		regfree(&nodl);
+	return 1;
+}
diff --git a/src/cmd/8g/cgen64.c b/src/cmd/8g/cgen64.c
new file mode 100644
index 0000000..dc50a40
--- /dev/null
+++ b/src/cmd/8g/cgen64.c
@@ -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.
+
+#include <u.h>
+#include <libc.h>
+#include "gg.h"
+
+/*
+ * attempt to generate 64-bit
+ *	res = n
+ * return 1 on success, 0 if op not handled.
+ */
+void
+cgen64(Node *n, Node *res)
+{
+	Node t1, t2, ax, dx, cx, ex, fx, *l, *r;
+	Node lo1, lo2, hi1, hi2;
+	Prog *p1, *p2;
+	uint64 v;
+	uint32 lv, hv;
+
+	if(res->op != OINDREG && res->op != ONAME) {
+		dump("n", n);
+		dump("res", res);
+		fatal("cgen64 %O of %O", n->op, res->op);
+	}
+	switch(n->op) {
+	default:
+		fatal("cgen64 %O", n->op);
+
+	case OMINUS:
+		cgen(n->left, res);
+		split64(res, &lo1, &hi1);
+		gins(ANEGL, N, &lo1);
+		gins(AADCL, ncon(0), &hi1);
+		gins(ANEGL, N, &hi1);
+		splitclean();
+		return;
+
+	case OCOM:
+		cgen(n->left, res);
+		split64(res, &lo1, &hi1);
+		gins(ANOTL, N, &lo1);
+		gins(ANOTL, N, &hi1);
+		splitclean();
+		return;
+
+	case OADD:
+	case OSUB:
+	case OMUL:
+	case OLROT:
+	case OLSH:
+	case ORSH:
+	case OAND:
+	case OOR:
+	case OXOR:
+		// binary operators.
+		// common setup below.
+		break;
+	}
+
+	l = n->left;
+	r = n->right;
+	if(!l->addable) {
+		tempname(&t1, l->type);
+		cgen(l, &t1);
+		l = &t1;
+	}
+	if(r != N && !r->addable) {
+		tempname(&t2, r->type);
+		cgen(r, &t2);
+		r = &t2;
+	}
+
+	nodreg(&ax, types[TINT32], D_AX);
+	nodreg(&cx, types[TINT32], D_CX);
+	nodreg(&dx, types[TINT32], D_DX);
+
+	// Setup for binary operation.
+	split64(l, &lo1, &hi1);
+	if(is64(r->type))
+		split64(r, &lo2, &hi2);
+
+	// Do op.  Leave result in DX:AX.
+	switch(n->op) {
+	case OADD:
+		// TODO: Constants
+		gins(AMOVL, &lo1, &ax);
+		gins(AMOVL, &hi1, &dx);
+		gins(AADDL, &lo2, &ax);
+		gins(AADCL, &hi2, &dx);
+		break;
+
+	case OSUB:
+		// TODO: Constants.
+		gins(AMOVL, &lo1, &ax);
+		gins(AMOVL, &hi1, &dx);
+		gins(ASUBL, &lo2, &ax);
+		gins(ASBBL, &hi2, &dx);
+		break;
+
+	case OMUL:
+		// let's call the next two EX and FX.
+		regalloc(&ex, types[TPTR32], N);
+		regalloc(&fx, types[TPTR32], N);
+
+		// load args into DX:AX and EX:CX.
+		gins(AMOVL, &lo1, &ax);
+		gins(AMOVL, &hi1, &dx);
+		gins(AMOVL, &lo2, &cx);
+		gins(AMOVL, &hi2, &ex);
+
+		// if DX and EX are zero, use 32 x 32 -> 64 unsigned multiply.
+		gins(AMOVL, &dx, &fx);
+		gins(AORL, &ex, &fx);
+		p1 = gbranch(AJNE, T, 0);
+		gins(AMULL, &cx, N);	// implicit &ax
+		p2 = gbranch(AJMP, T, 0);
+		patch(p1, pc);
+
+		// full 64x64 -> 64, from 32x32 -> 64.
+		gins(AIMULL, &cx, &dx);
+		gins(AMOVL, &ax, &fx);
+		gins(AIMULL, &ex, &fx);
+		gins(AADDL, &dx, &fx);
+		gins(AMOVL, &cx, &dx);
+		gins(AMULL, &dx, N);	// implicit &ax
+		gins(AADDL, &fx, &dx);
+		patch(p2, pc);
+
+		regfree(&ex);
+		regfree(&fx);
+		break;
+	
+	case OLROT:
+		// We only rotate by a constant c in [0,64).
+		// if c >= 32:
+		//	lo, hi = hi, lo
+		//	c -= 32
+		// if c == 0:
+		//	no-op
+		// else:
+		//	t = hi
+		//	shld hi:lo, c
+		//	shld lo:t, c
+		v = mpgetfix(r->val.u.xval);
+		if(v >= 32) {
+			// reverse during load to do the first 32 bits of rotate
+			v -= 32;
+			gins(AMOVL, &lo1, &dx);
+			gins(AMOVL, &hi1, &ax);
+		} else {
+			gins(AMOVL, &lo1, &ax);
+			gins(AMOVL, &hi1, &dx);
+		}
+		if(v == 0) {
+			// done
+		} else {
+			gins(AMOVL, &dx, &cx);
+			p1 = gins(ASHLL, ncon(v), &dx);
+			p1->from.index = D_AX;	// double-width shift
+			p1->from.scale = 0;
+			p1 = gins(ASHLL, ncon(v), &ax);
+			p1->from.index = D_CX;	// double-width shift
+			p1->from.scale = 0;
+		}
+		break;
+
+	case OLSH:
+		if(r->op == OLITERAL) {
+			v = mpgetfix(r->val.u.xval);
+			if(v >= 64) {
+				if(is64(r->type))
+					splitclean();
+				splitclean();
+				split64(res, &lo2, &hi2);
+				gins(AMOVL, ncon(0), &lo2);
+				gins(AMOVL, ncon(0), &hi2);
+				splitclean();
+				goto out;
+			}
+			if(v >= 32) {
+				if(is64(r->type))
+					splitclean();
+				split64(res, &lo2, &hi2);
+				gmove(&lo1, &hi2);
+				if(v > 32) {
+					gins(ASHLL, ncon(v - 32), &hi2);
+				}
+				gins(AMOVL, ncon(0), &lo2);
+				splitclean();
+				splitclean();
+				goto out;
+			}
+
+			// general shift
+			gins(AMOVL, &lo1, &ax);
+			gins(AMOVL, &hi1, &dx);
+			p1 = gins(ASHLL, ncon(v), &dx);
+			p1->from.index = D_AX;	// double-width shift
+			p1->from.scale = 0;
+			gins(ASHLL, ncon(v), &ax);
+			break;
+		}
+
+		// load value into DX:AX.
+		gins(AMOVL, &lo1, &ax);
+		gins(AMOVL, &hi1, &dx);
+
+		// load shift value into register.
+		// if high bits are set, zero value.
+		p1 = P;
+		if(is64(r->type)) {
+			gins(ACMPL, &hi2, ncon(0));
+			p1 = gbranch(AJNE, T, +1);
+			gins(AMOVL, &lo2, &cx);
+		} else {
+			cx.type = types[TUINT32];
+			gmove(r, &cx);
+		}
+
+		// if shift count is >=64, zero value
+		gins(ACMPL, &cx, ncon(64));
+		p2 = gbranch(optoas(OLT, types[TUINT32]), T, +1);
+		if(p1 != P)
+			patch(p1, pc);
+		gins(AXORL, &dx, &dx);
+		gins(AXORL, &ax, &ax);
+		patch(p2, pc);
+
+		// if shift count is >= 32, zero low.
+		gins(ACMPL, &cx, ncon(32));
+		p1 = gbranch(optoas(OLT, types[TUINT32]), T, +1);
+		gins(AMOVL, &ax, &dx);
+		gins(ASHLL, &cx, &dx);	// SHLL only uses bottom 5 bits of count
+		gins(AXORL, &ax, &ax);
+		p2 = gbranch(AJMP, T, 0);
+		patch(p1, pc);
+
+		// general shift
+		p1 = gins(ASHLL, &cx, &dx);
+		p1->from.index = D_AX;	// double-width shift
+		p1->from.scale = 0;
+		gins(ASHLL, &cx, &ax);
+		patch(p2, pc);
+		break;
+
+	case ORSH:
+		if(r->op == OLITERAL) {
+			v = mpgetfix(r->val.u.xval);
+			if(v >= 64) {
+				if(is64(r->type))
+					splitclean();
+				splitclean();
+				split64(res, &lo2, &hi2);
+				if(hi1.type->etype == TINT32) {
+					gmove(&hi1, &lo2);
+					gins(ASARL, ncon(31), &lo2);
+					gmove(&hi1, &hi2);
+					gins(ASARL, ncon(31), &hi2);
+				} else {
+					gins(AMOVL, ncon(0), &lo2);
+					gins(AMOVL, ncon(0), &hi2);
+				}
+				splitclean();
+				goto out;
+			}
+			if(v >= 32) {
+				if(is64(r->type))
+					splitclean();
+				split64(res, &lo2, &hi2);
+				gmove(&hi1, &lo2);
+				if(v > 32)
+					gins(optoas(ORSH, hi1.type), ncon(v-32), &lo2);
+				if(hi1.type->etype == TINT32) {
+					gmove(&hi1, &hi2);
+					gins(ASARL, ncon(31), &hi2);
+				} else
+					gins(AMOVL, ncon(0), &hi2);
+				splitclean();
+				splitclean();
+				goto out;
+			}
+
+			// general shift
+			gins(AMOVL, &lo1, &ax);
+			gins(AMOVL, &hi1, &dx);
+			p1 = gins(ASHRL, ncon(v), &ax);
+			p1->from.index = D_DX;	// double-width shift
+			p1->from.scale = 0;
+			gins(optoas(ORSH, hi1.type), ncon(v), &dx);
+			break;
+		}
+
+		// load value into DX:AX.
+		gins(AMOVL, &lo1, &ax);
+		gins(AMOVL, &hi1, &dx);
+
+		// load shift value into register.
+		// if high bits are set, zero value.
+		p1 = P;
+		if(is64(r->type)) {
+			gins(ACMPL, &hi2, ncon(0));
+			p1 = gbranch(AJNE, T, +1);
+			gins(AMOVL, &lo2, &cx);
+		} else {
+			cx.type = types[TUINT32];
+			gmove(r, &cx);
+		}
+
+		// if shift count is >=64, zero or sign-extend value
+		gins(ACMPL, &cx, ncon(64));
+		p2 = gbranch(optoas(OLT, types[TUINT32]), T, +1);
+		if(p1 != P)
+			patch(p1, pc);
+		if(hi1.type->etype == TINT32) {
+			gins(ASARL, ncon(31), &dx);
+			gins(AMOVL, &dx, &ax);
+		} else {
+			gins(AXORL, &dx, &dx);
+			gins(AXORL, &ax, &ax);
+		}
+		patch(p2, pc);
+
+		// if shift count is >= 32, sign-extend hi.
+		gins(ACMPL, &cx, ncon(32));
+		p1 = gbranch(optoas(OLT, types[TUINT32]), T, +1);
+		gins(AMOVL, &dx, &ax);
+		if(hi1.type->etype == TINT32) {
+			gins(ASARL, &cx, &ax);	// SARL only uses bottom 5 bits of count
+			gins(ASARL, ncon(31), &dx);
+		} else {
+			gins(ASHRL, &cx, &ax);
+			gins(AXORL, &dx, &dx);
+		}
+		p2 = gbranch(AJMP, T, 0);
+		patch(p1, pc);
+
+		// general shift
+		p1 = gins(ASHRL, &cx, &ax);
+		p1->from.index = D_DX;	// double-width shift
+		p1->from.scale = 0;
+		gins(optoas(ORSH, hi1.type), &cx, &dx);
+		patch(p2, pc);
+		break;
+
+	case OXOR:
+	case OAND:
+	case OOR:
+		// make constant the right side (it usually is anyway).
+		if(lo1.op == OLITERAL) {
+			nswap(&lo1, &lo2);
+			nswap(&hi1, &hi2);
+		}
+		if(lo2.op == OLITERAL) {
+			// special cases for constants.
+			lv = mpgetfix(lo2.val.u.xval);
+			hv = mpgetfix(hi2.val.u.xval);
+			splitclean();	// right side
+			split64(res, &lo2, &hi2);
+			switch(n->op) {
+			case OXOR:
+				gmove(&lo1, &lo2);
+				gmove(&hi1, &hi2);
+				switch(lv) {
+				case 0:
+					break;
+				case 0xffffffffu:
+					gins(ANOTL, N, &lo2);
+					break;
+				default:
+					gins(AXORL, ncon(lv), &lo2);
+					break;
+				}
+				switch(hv) {
+				case 0:
+					break;
+				case 0xffffffffu:
+					gins(ANOTL, N, &hi2);
+					break;
+				default:
+					gins(AXORL, ncon(hv), &hi2);
+					break;
+				}
+				break;
+
+			case OAND:
+				switch(lv) {
+				case 0:
+					gins(AMOVL, ncon(0), &lo2);
+					break;
+				default:
+					gmove(&lo1, &lo2);
+					if(lv != 0xffffffffu)
+						gins(AANDL, ncon(lv), &lo2);
+					break;
+				}
+				switch(hv) {
+				case 0:
+					gins(AMOVL, ncon(0), &hi2);
+					break;
+				default:
+					gmove(&hi1, &hi2);
+					if(hv != 0xffffffffu)
+						gins(AANDL, ncon(hv), &hi2);
+					break;
+				}
+				break;
+
+			case OOR:
+				switch(lv) {
+				case 0:
+					gmove(&lo1, &lo2);
+					break;
+				case 0xffffffffu:
+					gins(AMOVL, ncon(0xffffffffu), &lo2);
+					break;
+				default:
+					gmove(&lo1, &lo2);
+					gins(AORL, ncon(lv), &lo2);
+					break;
+				}
+				switch(hv) {
+				case 0:
+					gmove(&hi1, &hi2);
+					break;
+				case 0xffffffffu:
+					gins(AMOVL, ncon(0xffffffffu), &hi2);
+					break;
+				default:
+					gmove(&hi1, &hi2);
+					gins(AORL, ncon(hv), &hi2);
+					break;
+				}
+				break;
+			}
+			splitclean();
+			splitclean();
+			goto out;
+		}
+		gins(AMOVL, &lo1, &ax);
+		gins(AMOVL, &hi1, &dx);
+		gins(optoas(n->op, lo1.type), &lo2, &ax);
+		gins(optoas(n->op, lo1.type), &hi2, &dx);
+		break;
+	}
+	if(is64(r->type))
+		splitclean();
+	splitclean();
+
+	split64(res, &lo1, &hi1);
+	gins(AMOVL, &ax, &lo1);
+	gins(AMOVL, &dx, &hi1);
+	splitclean();
+
+out:;
+}
+
+/*
+ * generate comparison of nl, nr, both 64-bit.
+ * nl is memory; nr is constant or memory.
+ */
+void
+cmp64(Node *nl, Node *nr, int op, int likely, Prog *to)
+{
+	Node lo1, hi1, lo2, hi2, rr;
+	Prog *br;
+	Type *t;
+
+	split64(nl, &lo1, &hi1);
+	split64(nr, &lo2, &hi2);
+
+	// compare most significant word;
+	// if they differ, we're done.
+	t = hi1.type;
+	if(nl->op == OLITERAL || nr->op == OLITERAL)
+		gins(ACMPL, &hi1, &hi2);
+	else {
+		regalloc(&rr, types[TINT32], N);
+		gins(AMOVL, &hi1, &rr);
+		gins(ACMPL, &rr, &hi2);
+		regfree(&rr);
+	}
+	br = P;
+	switch(op) {
+	default:
+		fatal("cmp64 %O %T", op, t);
+	case OEQ:
+		// cmp hi
+		// jne L
+		// cmp lo
+		// jeq to
+		// L:
+		br = gbranch(AJNE, T, -likely);
+		break;
+	case ONE:
+		// cmp hi
+		// jne to
+		// cmp lo
+		// jne to
+		patch(gbranch(AJNE, T, likely), to);
+		break;
+	case OGE:
+	case OGT:
+		// cmp hi
+		// jgt to
+		// jlt L
+		// cmp lo
+		// jge to (or jgt to)
+		// L:
+		patch(gbranch(optoas(OGT, t), T, likely), to);
+		br = gbranch(optoas(OLT, t), T, -likely);
+		break;
+	case OLE:
+	case OLT:
+		// cmp hi
+		// jlt to
+		// jgt L
+		// cmp lo
+		// jle to (or jlt to)
+		// L:
+		patch(gbranch(optoas(OLT, t), T, likely), to);
+		br = gbranch(optoas(OGT, t), T, -likely);
+		break;
+	}
+
+	// compare least significant word
+	t = lo1.type;
+	if(nl->op == OLITERAL || nr->op == OLITERAL)
+		gins(ACMPL, &lo1, &lo2);
+	else {
+		regalloc(&rr, types[TINT32], N);
+		gins(AMOVL, &lo1, &rr);
+		gins(ACMPL, &rr, &lo2);
+		regfree(&rr);
+	}
+
+	// jump again
+	patch(gbranch(optoas(op, t), T, likely), to);
+
+	// point first branch down here if appropriate
+	if(br != P)
+		patch(br, pc);
+
+	splitclean();
+	splitclean();
+}
+
diff --git a/src/cmd/8g/doc.go b/src/cmd/8g/doc.go
new file mode 100644
index 0000000..9e46dca
--- /dev/null
+++ b/src/cmd/8g/doc.go
@@ -0,0 +1,15 @@
+// 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
+
+/*
+
+8g is the version of the gc compiler for the x86.
+The $GOARCH for these tools is 386.
+
+It reads .go files and outputs .8 files. The flags are documented in ../gc/doc.go.
+
+*/
+package main
diff --git a/src/cmd/8g/galign.c b/src/cmd/8g/galign.c
new file mode 100644
index 0000000..a0eb349
--- /dev/null
+++ b/src/cmd/8g/galign.c
@@ -0,0 +1,47 @@
+// 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 "gg.h"
+
+int	thechar	= '8';
+char*	thestring	= "386";
+LinkArch*	thelinkarch = &link386;
+
+void
+linkarchinit(void)
+{
+}
+
+vlong MAXWIDTH = (1LL<<32) - 1;
+
+/*
+ * go declares several platform-specific type aliases:
+ * int, uint, float, and uintptr
+ */
+Typedef	typedefs[] =
+{
+	{"int",		TINT,		TINT32},
+	{"uint",		TUINT,		TUINT32},
+	{"uintptr",	TUINTPTR,	TUINT32},
+	{0}
+};
+
+void
+betypeinit(void)
+{
+	widthptr = 4;
+	widthint = 4;
+	widthreg = 4;
+
+	zprog.link = P;
+	zprog.as = AGOK;
+	zprog.from.type = D_NONE;
+	zprog.from.index = D_NONE;
+	zprog.from.scale = 0;
+	zprog.to = zprog.from;
+
+	listinit8();
+}
diff --git a/src/cmd/8g/gg.h b/src/cmd/8g/gg.h
new file mode 100644
index 0000000..238f927
--- /dev/null
+++ b/src/cmd/8g/gg.h
@@ -0,0 +1,135 @@
+// 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.
+
+#ifndef	EXTERN
+#define	EXTERN	extern
+#endif
+
+#include "../gc/go.h"
+#include "../8l/8.out.h"
+
+#define TEXTFLAG from.scale
+
+// foptoas flags
+enum
+{
+	Frev = 1<<0,
+	Fpop = 1<<1,
+	Fpop2 = 1<<2,
+};
+
+EXTERN	int32	dynloc;
+EXTERN	uchar	reg[D_NONE];
+EXTERN	int32	pcloc;		// instruction counter
+EXTERN	Strlit	emptystring;
+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	uint32	unmappedzero;
+
+
+/*
+ * ggen.c
+ */
+void	compile(Node*);
+void	gen(Node*);
+Node*	lookdot(Node*, Node*, int);
+void	cgen_as(Node*, Node*);
+void	cgen_callmeth(Node*, int);
+void	cgen_callinter(Node*, Node*, int);
+void	cgen_proc(Node*, int);
+void	cgen_callret(Node*, Node*);
+void	cgen_div(int, Node*, Node*, Node*);
+void	cgen_bmul(int, Node*, Node*, Node*);
+void	cgen_hmul(Node*, Node*, Node*);
+void	cgen_shift(int, int, Node*, Node*, Node*);
+void	cgen_float(Node*, Node*);
+void	bgen_float(Node *n, int true, int likely, Prog *to);
+void	cgen_dcl(Node*);
+int	needconvert(Type*, Type*);
+void	genconv(Type*, Type*);
+void	allocparams(void);
+void	checklabels(void);
+void	ginscall(Node*, int);
+
+/*
+ * cgen.c
+ */
+void	agen(Node*, Node*);
+void	igen(Node*, Node*, Node*);
+vlong	fieldoffset(Type*, Node*);
+void	sgen(Node*, Node*, int64);
+void	gmove(Node*, Node*);
+Prog*	gins(int, Node*, Node*);
+int	samaddr(Node*, Node*);
+void	naddr(Node*, Addr*, int);
+void	cgen_aret(Node*, Node*);
+Node*	ncon(uint32);
+void	mgen(Node*, Node*, Node*);
+void	mfree(Node*);
+int	componentgen(Node*, Node*);
+
+/*
+ * cgen64.c
+ */
+void	cmp64(Node*, Node*, int, int, Prog*);
+void	cgen64(Node*, Node*);
+
+/*
+ * gsubr.c
+ */
+void	clearp(Prog*);
+Prog*	gbranch(int, Type*, int);
+Prog*	prog(int);
+void	gconv(int, int);
+int	conv2pt(Type*);
+vlong	convvtox(vlong, int);
+void	fnparam(Type*, int, int);
+Prog*	gop(int, Node*, Node*, Node*);
+int	optoas(int, Type*);
+int	foptoas(int, Type*, int);
+void	ginit(void);
+void	gclean(void);
+void	regalloc(Node*, Type*, Node*);
+void	regfree(Node*);
+Node*	nodarg(Type*, int);
+void	nodreg(Node*, Type*, int);
+void	nodindreg(Node*, Type*, int);
+void	nodconst(Node*, Type*, int64);
+void	gconreg(int, vlong, int);
+void	buildtxt(void);
+Plist*	newplist(void);
+int	isfat(Type*);
+void	sudoclean(void);
+int	sudoaddable(int, Node*, Addr*);
+int	dotaddable(Node*, Node*);
+void	afunclit(Addr*, Node*);
+void	split64(Node*, Node*, Node*);
+void	splitclean(void);
+void	nswap(Node*, Node*);
+void	gtrack(Sym*);
+/*
+ * cplx.c
+ */
+int	complexop(Node*, Node*);
+void	complexmove(Node*, Node*);
+void	complexgen(Node*, Node*);
+
+/*
+ * gobj.c
+ */
+void	datastring(char*, int, Addr*);
+void	datagostring(Strlit*, Addr*);
+
+/*
+ * list.c
+ */
+void	listinit(void);
+
+void	zaddr(Biobuf*, Addr*, int, int);
diff --git a/src/cmd/8g/ggen.c b/src/cmd/8g/ggen.c
new file mode 100644
index 0000000..6333a60
--- /dev/null
+++ b/src/cmd/8g/ggen.c
@@ -0,0 +1,1342 @@
+// 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.
+
+#undef	EXTERN
+#define	EXTERN
+#include <u.h>
+#include <libc.h>
+#include "gg.h"
+#include "opt.h"
+
+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)
+{
+	uint32 frame, ax;
+	Prog *p;
+	vlong lo, hi;
+	NodeList *l;
+	Node *n;
+
+	// fill in argument size
+	ptxt->to.offset2 = rnd(curfn->type->argwid, widthptr);
+
+	// fill in final stack size
+	frame = rnd(stksize+maxarg, widthptr);
+	ptxt->to.offset = frame;
+	
+	// insert code to zero ambiguously live variables
+	// so that the garbage collector only sees initialized values
+	// when it looks for pointers.
+	p = ptxt;
+	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*
+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;	
+}
+
+// Sweep the prog list to mark any used nodes.
+void
+markautoused(Prog* p)
+{
+	for (; p; p = p->link) {
+		if (p->as == ATYPE || p->as == AVARDEF || p->as == AVARKILL)
+			continue;
+
+		if (p->from.node)
+			p->from.node->used = 1;
+
+		if (p->to.node)
+			p->to.node->used = 1;
+	}
+}
+
+// Fixup instructions after allocauto (formerly compactframe) has moved all autos around.
+void
+fixautoused(Prog* p)
+{
+	Prog **lp;
+
+	for (lp=&p; (p=*lp) != P; ) {
+		if (p->as == ATYPE && p->from.node && p->from.type == D_AUTO && !p->from.node->used) {
+			*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;
+
+		if (p->to.type == D_AUTO && p->to.node)
+			p->to.offset += p->to.node->stkdelta;
+
+		lp = &p->link;
+	}
+}
+
+void
+clearfat(Node *nl)
+{
+	uint32 w, c, q;
+	Node n1, 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))
+		return;
+
+	c = w % 4;	// bytes
+	q = w / 4;	// quads
+
+	if(q < 4) {
+		// Write sequence of MOV 0, off(base) instead of using STOSL.
+		// The hope is that although the code will be slightly longer,
+		// the MOVs will have no dependencies and pipeline better
+		// than the unrolled STOSL loop.
+		// NOTE: Must use agen, not igen, so that optimizer sees address
+		// being taken. We are not writing on field boundaries.
+		regalloc(&n1, types[tptr], N);
+		agen(nl, &n1);
+		n1.op = OINDREG;
+		nodconst(&z, types[TUINT64], 0);
+		while(q-- > 0) {
+			n1.type = z.type;
+			gins(AMOVL, &z, &n1);
+			n1.xoffset += 4;
+		}
+		nodconst(&z, types[TUINT8], 0);
+		while(c-- > 0) {
+			n1.type = z.type;
+			gins(AMOVB, &z, &n1);
+			n1.xoffset++;
+		}
+		regfree(&n1);
+		return;
+	}
+
+	nodreg(&n1, types[tptr], D_DI);
+	agen(nl, &n1);
+	gconreg(AMOVL, 0, D_AX);
+
+	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 ../../runtime/asm_386.s
+		p->to.offset = 1*(128-q);
+	} else
+	while(q > 0) {
+		gins(ASTOSL, N, N);	// STOL AL,*(DI)+
+		q--;
+	}
+
+	while(c > 0) {
+		gins(ASTOSB, N, N);	// STOB AL,*(DI)+
+		c--;
+	}
+}
+
+/*
+ * generate:
+ *	call f
+ *	proc=-1	normal call but no return
+ *	proc=0	normal call
+ *	proc=1	goroutine run in new proc
+ *	proc=2	defer call save away stack
+  *	proc=3	normal call to C pointer (not Go func value)
+ */
+void
+ginscall(Node *f, int proc)
+{
+	Prog *p;
+	Node reg, r1, con;
+
+	if(f->type != T)
+		setmaxarg(f->type);
+
+	switch(proc) {
+	default:
+		fatal("ginscall: bad proc %d", proc);
+		break;
+
+	case 0:	// normal call
+	case -1:	// normal call but no return
+		if(f->op == ONAME && f->class == PFUNC) {
+			if(f == deferreturn) {
+				// Deferred calls will appear to be returning to
+				// the CALL deferreturn(SB) that we are about to emit.
+				// However, the stack trace code will show the line
+				// of the instruction byte before the return PC. 
+				// To avoid that being an unrelated instruction,
+				// insert an x86 NOP that we will have the right line number.
+				// x86 NOP 0x90 is really XCHG AX, AX; use that description
+				// because the NOP pseudo-instruction will be removed by
+				// the linker.
+				nodreg(&reg, types[TINT], D_AX);
+				gins(AXCHGL, &reg, &reg);
+			}
+			p = gins(ACALL, N, f);
+			afunclit(&p->to, f);
+			if(proc == -1 || noreturn(p))
+				gins(AUNDEF, N, N);
+			break;
+		}
+		nodreg(&reg, types[tptr], D_DX);
+		nodreg(&r1, types[tptr], D_BX);
+		gmove(f, &reg);
+		reg.op = OINDREG;
+		gmove(&reg, &r1);
+		reg.op = OREGISTER;
+		gins(ACALL, &reg, &r1);
+		break;
+	
+	case 3:	// normal call of c function pointer
+		gins(ACALL, N, f);
+		break;
+
+	case 1:	// call in new proc (go)
+	case 2:	// deferred call (defer)
+		nodreg(&reg, types[TINT32], D_CX);
+		gins(APUSHL, f, N);
+		nodconst(&con, types[TINT32], argsize(f->type));
+		gins(APUSHL, &con, N);
+		if(proc == 1)
+			ginscall(newproc, 0);
+		else
+			ginscall(deferproc, 0);
+		gins(APOPL, N, &reg);
+		gins(APOPL, N, &reg);
+		if(proc == 2) {
+			nodreg(&reg, types[TINT64], D_AX);
+			gins(ATESTL, &reg, &reg);
+			p = gbranch(AJEQ, T, +1);
+			cgen_ret(N);
+			patch(p, pc);
+		}
+		break;
+	}
+}
+
+/*
+ * n is call to interface method.
+ * generate res = n.
+ */
+void
+cgen_callinter(Node *n, Node *res, int proc)
+{
+	Node *i, *f;
+	Node tmpi, nodi, nodo, nodr, nodsp;
+
+	i = n->left;
+	if(i->op != ODOTINTER)
+		fatal("cgen_callinter: not ODOTINTER %O", i->op);
+
+	f = i->right;		// field
+	if(f->op != ONAME)
+		fatal("cgen_callinter: not ONAME %O", f->op);
+
+	i = i->left;		// interface
+
+	if(!i->addable) {
+		tempname(&tmpi, i->type);
+		cgen(i, &tmpi);
+		i = &tmpi;
+	}
+
+	genlist(n->list);		// assign the args
+
+	// i is now addable, prepare an indirected
+	// register to hold its address.
+	igen(i, &nodi, res);		// REG = &inter
+
+	nodindreg(&nodsp, types[tptr], D_SP);
+	nodi.type = types[tptr];
+	nodi.xoffset += widthptr;
+	cgen(&nodi, &nodsp);	// 0(SP) = 4(REG) -- i.data
+
+	regalloc(&nodo, types[tptr], res);
+	nodi.type = types[tptr];
+	nodi.xoffset -= widthptr;
+	cgen(&nodi, &nodo);	// REG = 0(REG) -- i.tab
+	regfree(&nodi);
+
+	regalloc(&nodr, types[tptr], &nodo);
+	if(n->left->xoffset == BADWIDTH)
+		fatal("cgen_callinter: badwidth");
+	cgen_checknil(&nodo);
+	nodo.op = OINDREG;
+	nodo.xoffset = n->left->xoffset + 3*widthptr + 8;
+	
+	if(proc == 0) {
+		// plain call: use direct c function pointer - more efficient
+		cgen(&nodo, &nodr);	// REG = 20+offset(REG) -- i.tab->fun[f]
+		proc = 3;
+	} else {
+		// go/defer. generate go func value.
+		gins(ALEAL, &nodo, &nodr);	// REG = &(20+offset(REG)) -- i.tab->fun[f]
+	}
+
+	nodr.type = n->left->type;
+	ginscall(&nodr, proc);
+
+	regfree(&nodr);
+	regfree(&nodo);
+}
+
+/*
+ * generate function call;
+ *	proc=0	normal call
+ *	proc=1	goroutine run in new proc
+ *	proc=2	defer call save away stack
+ */
+void
+cgen_call(Node *n, int proc)
+{
+	Type *t;
+	Node nod, afun;
+
+	if(n == N)
+		return;
+
+	if(n->left->ullman >= UINF) {
+		// if name involves a fn call
+		// precompute the address of the fn
+		tempname(&afun, types[tptr]);
+		cgen(n->left, &afun);
+	}
+
+	genlist(n->list);		// assign the args
+	t = n->left->type;
+
+	// call tempname pointer
+	if(n->left->ullman >= UINF) {
+		regalloc(&nod, types[tptr], N);
+		cgen_as(&nod, &afun);
+		nod.type = t;
+		ginscall(&nod, proc);
+		regfree(&nod);
+		return;
+	}
+
+	// call pointer
+	if(n->left->op != ONAME || n->left->class != PFUNC) {
+		regalloc(&nod, types[tptr], N);
+		cgen_as(&nod, n->left);
+		nod.type = t;
+		ginscall(&nod, proc);
+		regfree(&nod);
+		return;
+	}
+
+	// call direct
+	n->left->method = 1;
+	ginscall(n->left, proc);
+}
+
+/*
+ * call to n has already been generated.
+ * generate:
+ *	res = return value from call.
+ */
+void
+cgen_callret(Node *n, Node *res)
+{
+	Node nod;
+	Type *fp, *t;
+	Iter flist;
+
+	t = n->left->type;
+	if(t->etype == TPTR32 || t->etype == TPTR64)
+		t = t->type;
+
+	fp = structfirst(&flist, getoutarg(t));
+	if(fp == T)
+		fatal("cgen_callret: nil");
+
+	memset(&nod, 0, sizeof(nod));
+	nod.op = OINDREG;
+	nod.val.u.reg = D_SP;
+	nod.addable = 1;
+
+	nod.xoffset = fp->width;
+	nod.type = fp->type;
+	cgen_as(res, &nod);
+}
+
+/*
+ * call to n has already been generated.
+ * generate:
+ *	res = &return value from call.
+ */
+void
+cgen_aret(Node *n, Node *res)
+{
+	Node nod1, nod2;
+	Type *fp, *t;
+	Iter flist;
+
+	t = n->left->type;
+	if(isptr[t->etype])
+		t = t->type;
+
+	fp = structfirst(&flist, getoutarg(t));
+	if(fp == T)
+		fatal("cgen_aret: nil");
+
+	memset(&nod1, 0, sizeof(nod1));
+	nod1.op = OINDREG;
+	nod1.val.u.reg = D_SP;
+	nod1.addable = 1;
+
+	nod1.xoffset = fp->width;
+	nod1.type = fp->type;
+
+	if(res->op != OREGISTER) {
+		regalloc(&nod2, types[tptr], res);
+		gins(ALEAL, &nod1, &nod2);
+		gins(AMOVL, &nod2, res);
+		regfree(&nod2);
+	} else
+		gins(ALEAL, &nod1, res);
+}
+
+/*
+ * generate return.
+ * n->left is assignments to return values.
+ */
+void
+cgen_ret(Node *n)
+{
+	Prog *p;
+
+	if(n != N)
+		genlist(n->list);		// copy out args
+	if(hasdefer)
+		ginscall(deferreturn, 0);
+	genlist(curfn->exit);
+	p = gins(ARET, N, N);
+	if(n != N && n->op == ORETJMP) {
+		p->to.type = D_EXTERN;
+		p->to.sym = linksym(n->left->sym);
+	}
+}
+
+/*
+ * generate += *= etc.
+ */
+void
+cgen_asop(Node *n)
+{
+	Node n1, n2, n3, n4;
+	Node *nl, *nr;
+	Prog *p1;
+	Addr addr;
+	int a;
+
+	nl = n->left;
+	nr = n->right;
+
+	if(nr->ullman >= UINF && nl->ullman >= UINF) {
+		tempname(&n1, nr->type);
+		cgen(nr, &n1);
+		n2 = *n;
+		n2.right = &n1;
+		cgen_asop(&n2);
+		goto ret;
+	}
+
+	if(!isint[nl->type->etype])
+		goto hard;
+	if(!isint[nr->type->etype])
+		goto hard;
+	if(is64(nl->type) || is64(nr->type))
+		goto hard;
+
+	switch(n->etype) {
+	case OADD:
+		if(smallintconst(nr))
+		if(mpgetfix(nr->val.u.xval) == 1) {
+			a = optoas(OINC, nl->type);
+			if(nl->addable) {
+				gins(a, N, nl);
+				goto ret;
+			}
+			if(sudoaddable(a, nl, &addr)) {
+				p1 = gins(a, N, N);
+				p1->to = addr;
+				sudoclean();
+				goto ret;
+			}
+		}
+		break;
+
+	case OSUB:
+		if(smallintconst(nr))
+		if(mpgetfix(nr->val.u.xval) == 1) {
+			a = optoas(ODEC, nl->type);
+			if(nl->addable) {
+				gins(a, N, nl);
+				goto ret;
+			}
+			if(sudoaddable(a, nl, &addr)) {
+				p1 = gins(a, N, N);
+				p1->to = addr;
+				sudoclean();
+				goto ret;
+			}
+		}
+		break;
+	}
+
+	switch(n->etype) {
+	case OADD:
+	case OSUB:
+	case OXOR:
+	case OAND:
+	case OOR:
+		a = optoas(n->etype, nl->type);
+		if(nl->addable) {
+			if(smallintconst(nr)) {
+				gins(a, nr, nl);
+				goto ret;
+			}
+			regalloc(&n2, nr->type, N);
+			cgen(nr, &n2);
+			gins(a, &n2, nl);
+			regfree(&n2);
+			goto ret;
+		}
+		if(nr->ullman < UINF)
+		if(sudoaddable(a, nl, &addr)) {
+			if(smallintconst(nr)) {
+				p1 = gins(a, nr, N);
+				p1->to = addr;
+				sudoclean();
+				goto ret;
+			}
+			regalloc(&n2, nr->type, N);
+			cgen(nr, &n2);
+			p1 = gins(a, &n2, N);
+			p1->to = addr;
+			regfree(&n2);
+			sudoclean();
+			goto ret;
+		}
+	}
+
+hard:
+	n2.op = 0;
+	n1.op = 0;
+	if(nr->ullman >= nl->ullman || nl->addable) {
+		mgen(nr, &n2, N);
+		nr = &n2;
+	} else {
+		tempname(&n2, nr->type);
+		cgen(nr, &n2);
+		nr = &n2;
+	}
+	if(!nl->addable) {
+		igen(nl, &n1, N);
+		nl = &n1;
+	}
+
+	n3 = *n;
+	n3.left = nl;
+	n3.right = nr;
+	n3.op = n->etype;
+
+	mgen(&n3, &n4, N);
+	gmove(&n4, nl);
+
+	if(n1.op)
+		regfree(&n1);
+	mfree(&n2);
+	mfree(&n4);
+
+ret:
+	;
+}
+
+int
+samereg(Node *a, Node *b)
+{
+	if(a->op != OREGISTER)
+		return 0;
+	if(b->op != OREGISTER)
+		return 0;
+	if(a->val.u.reg != b->val.u.reg)
+		return 0;
+	return 1;
+}
+
+/*
+ * generate division.
+ * caller must set:
+ *	ax = allocated AX register
+ *	dx = allocated DX register
+ * generates one of:
+ *	res = nl / nr
+ *	res = nl % nr
+ * according to op.
+ */
+void
+dodiv(int op, Node *nl, Node *nr, Node *res, Node *ax, Node *dx)
+{
+	int check;
+	Node n1, t1, t2, t3, t4, n4, nz;
+	Type *t, *t0;
+	Prog *p1, *p2;
+
+	// Have to be careful about handling
+	// most negative int divided by -1 correctly.
+	// The hardware will trap.
+	// Also the byte divide instruction needs AH,
+	// which we otherwise don't have to deal with.
+	// Easiest way to avoid for int8, int16: use int32.
+	// For int32 and int64, use explicit test.
+	// Could use int64 hw for int32.
+	t = nl->type;
+	t0 = t;
+	check = 0;
+	if(issigned[t->etype]) {
+		check = 1;
+		if(isconst(nl, CTINT) && mpgetfix(nl->val.u.xval) != -1LL<<(t->width*8-1))
+			check = 0;
+		else if(isconst(nr, CTINT) && mpgetfix(nr->val.u.xval) != -1)
+			check = 0;
+	}
+	if(t->width < 4) {
+		if(issigned[t->etype])
+			t = types[TINT32];
+		else
+			t = types[TUINT32];
+		check = 0;
+	}
+
+	tempname(&t1, t);
+	tempname(&t2, t);
+	if(t0 != t) {
+		tempname(&t3, t0);
+		tempname(&t4, t0);
+		cgen(nl, &t3);
+		cgen(nr, &t4);
+		// Convert.
+		gmove(&t3, &t1);
+		gmove(&t4, &t2);
+	} else {
+		cgen(nl, &t1);
+		cgen(nr, &t2);
+	}
+
+	if(!samereg(ax, res) && !samereg(dx, res))
+		regalloc(&n1, t, res);
+	else
+		regalloc(&n1, t, N);
+	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);
+		p1 = gbranch(optoas(ONE, t), T, +1);
+		if(op == ODIV) {
+			// a / (-1) is -a.
+			gins(optoas(OMINUS, t), N, ax);
+			gmove(ax, res);
+		} else {
+			// a % (-1) is 0.
+			nodconst(&n4, t, 0);
+			gmove(&n4, res);
+		}
+		p2 = gbranch(AJMP, T, 0);
+		patch(p1, pc);
+	}
+	if(!issigned[t->etype]) {
+		nodconst(&nz, t, 0);
+		gmove(&nz, dx);
+	} else
+		gins(optoas(OEXTEND, t), N, N);
+	gins(optoas(op, t), &n1, N);
+	regfree(&n1);
+
+	if(op == ODIV)
+		gmove(ax, res);
+	else
+		gmove(dx, res);
+	if(check)
+		patch(p2, pc);
+}
+
+static void
+savex(int dr, Node *x, Node *oldx, Node *res, Type *t)
+{
+	int r;
+
+	r = reg[dr];
+	nodreg(x, types[TINT32], dr);
+
+	// save current ax and dx if they are live
+	// and not the destination
+	memset(oldx, 0, sizeof *oldx);
+	if(r > 0 && !samereg(x, res)) {
+		tempname(oldx, types[TINT32]);
+		gmove(x, oldx);
+	}
+
+	regalloc(x, t, x);
+}
+
+static void
+restx(Node *x, Node *oldx)
+{
+	regfree(x);
+
+	if(oldx->op != 0) {
+		x->type = types[TINT32];
+		gmove(oldx, x);
+	}
+}
+
+/*
+ * generate division according to op, one of:
+ *	res = nl / nr
+ *	res = nl % nr
+ */
+void
+cgen_div(int op, Node *nl, Node *nr, Node *res)
+{
+	Node ax, dx, oldax, olddx;
+	Type *t;
+
+	if(is64(nl->type))
+		fatal("cgen_div %T", nl->type);
+
+	if(issigned[nl->type->etype])
+		t = types[TINT32];
+	else
+		t = types[TUINT32];
+	savex(D_AX, &ax, &oldax, res, t);
+	savex(D_DX, &dx, &olddx, res, t);
+	dodiv(op, nl, nr, res, &ax, &dx);
+	restx(&dx, &olddx);
+	restx(&ax, &oldax);
+}
+
+/*
+ * generate shift according to op, one of:
+ *	res = nl << nr
+ *	res = nl >> nr
+ */
+void
+cgen_shift(int op, int bounded, Node *nl, Node *nr, Node *res)
+{
+	Node n1, n2, nt, cx, oldcx, hi, lo;
+	int a, w;
+	Prog *p1, *p2;
+	uvlong sc;
+
+	if(nl->type->width > 4)
+		fatal("cgen_shift %T", nl->type);
+
+	w = nl->type->width * 8;
+
+	a = optoas(op, nl->type);
+
+	if(nr->op == OLITERAL) {
+		tempname(&n2, nl->type);
+		cgen(nl, &n2);
+		regalloc(&n1, nl->type, res);
+		gmove(&n2, &n1);
+		sc = mpgetfix(nr->val.u.xval);
+		if(sc >= nl->type->width*8) {
+			// large shift gets 2 shifts by width-1
+			gins(a, ncon(w-1), &n1);
+			gins(a, ncon(w-1), &n1);
+		} else
+			gins(a, nr, &n1);
+		gmove(&n1, res);
+		regfree(&n1);
+		return;
+	}
+
+	memset(&oldcx, 0, sizeof oldcx);
+	nodreg(&cx, types[TUINT32], D_CX);
+	if(reg[D_CX] > 1 && !samereg(&cx, res)) {
+		tempname(&oldcx, types[TUINT32]);
+		gmove(&cx, &oldcx);
+	}
+
+	if(nr->type->width > 4) {
+		tempname(&nt, nr->type);
+		n1 = nt;
+	} else {
+		nodreg(&n1, types[TUINT32], D_CX);
+		regalloc(&n1, nr->type, &n1);		// to hold the shift type in CX
+	}
+
+	if(samereg(&cx, res))
+		regalloc(&n2, nl->type, N);
+	else
+		regalloc(&n2, nl->type, res);
+	if(nl->ullman >= nr->ullman) {
+		cgen(nl, &n2);
+		cgen(nr, &n1);
+	} else {
+		cgen(nr, &n1);
+		cgen(nl, &n2);
+	}
+
+	// test and fix up large shifts
+	if(bounded) {
+		if(nr->type->width > 4) {
+			// delayed reg alloc
+			nodreg(&n1, types[TUINT32], D_CX);
+			regalloc(&n1, types[TUINT32], &n1);		// to hold the shift type in CX
+			split64(&nt, &lo, &hi);
+			gmove(&lo, &n1);
+			splitclean();
+		}
+	} else {
+		if(nr->type->width > 4) {
+			// delayed reg alloc
+			nodreg(&n1, types[TUINT32], D_CX);
+			regalloc(&n1, types[TUINT32], &n1);		// to hold the shift type in CX
+			split64(&nt, &lo, &hi);
+			gmove(&lo, &n1);
+			gins(optoas(OCMP, types[TUINT32]), &hi, ncon(0));
+			p2 = gbranch(optoas(ONE, types[TUINT32]), T, +1);
+			gins(optoas(OCMP, types[TUINT32]), &n1, ncon(w));
+			p1 = gbranch(optoas(OLT, types[TUINT32]), T, +1);
+			splitclean();
+			patch(p2, pc);
+		} else {
+			gins(optoas(OCMP, nr->type), &n1, ncon(w));
+			p1 = gbranch(optoas(OLT, types[TUINT32]), T, +1);
+		}
+		if(op == ORSH && issigned[nl->type->etype]) {
+			gins(a, ncon(w-1), &n2);
+		} else {
+			gmove(ncon(0), &n2);
+		}
+		patch(p1, pc);
+	}
+	gins(a, &n1, &n2);
+
+	if(oldcx.op != 0)
+		gmove(&oldcx, &cx);
+
+	gmove(&n2, res);
+
+	regfree(&n1);
+	regfree(&n2);
+}
+
+/*
+ * generate byte multiply:
+ *	res = nl * nr
+ * there is no 2-operand byte multiply instruction so
+ * we do a full-width multiplication and truncate afterwards.
+ */
+void
+cgen_bmul(int op, Node *nl, Node *nr, Node *res)
+{
+	Node n1, n2, nt, *tmp;
+	Type *t;
+	int a;
+
+	// copy from byte to full registers
+	t = types[TUINT32];
+	if(issigned[nl->type->etype])
+		t = types[TINT32];
+
+	// largest ullman on left.
+	if(nl->ullman < nr->ullman) {
+		tmp = nl;
+		nl = nr;
+		nr = tmp;
+	}
+
+	tempname(&nt, nl->type);
+	cgen(nl, &nt);
+	regalloc(&n1, t, res);
+	cgen(nr, &n1);
+	regalloc(&n2, t, N);
+	gmove(&nt, &n2);
+	a = optoas(op, t);
+	gins(a, &n2, &n1);
+	regfree(&n2);
+	gmove(&n1, res);
+	regfree(&n1);
+}
+
+/*
+ * generate high multiply:
+ *   res = (nl*nr) >> width
+ */
+void
+cgen_hmul(Node *nl, Node *nr, Node *res)
+{
+	Type *t;
+	int a;
+	Node n1, n2, ax, dx;
+
+	t = nl->type;
+	a = optoas(OHMUL, t);
+	// gen nl in n1.
+	tempname(&n1, t);
+	cgen(nl, &n1);
+	// gen nr in n2.
+	regalloc(&n2, t, res);
+	cgen(nr, &n2);
+
+	// multiply.
+	nodreg(&ax, t, D_AX);
+	gmove(&n2, &ax);
+	gins(a, &n1, N);
+	regfree(&n2);
+
+	if(t->width == 1) {
+		// byte multiply behaves differently.
+		nodreg(&ax, t, D_AH);
+		nodreg(&dx, t, D_DX);
+		gmove(&ax, &dx);
+	}
+	nodreg(&dx, t, D_DX);
+	gmove(&dx, res);
+}
+
+static void cgen_float387(Node *n, Node *res);
+static void cgen_floatsse(Node *n, Node *res);
+
+/*
+ * generate floating-point operation.
+ */
+void
+cgen_float(Node *n, Node *res)
+{
+	Node *nl;
+	Node n1, n2;
+	Prog *p1, *p2, *p3;
+
+	nl = n->left;
+	switch(n->op) {
+	case OEQ:
+	case ONE:
+	case OLT:
+	case OLE:
+	case OGE:
+		p1 = gbranch(AJMP, T, 0);
+		p2 = pc;
+		gmove(nodbool(1), res);
+		p3 = gbranch(AJMP, T, 0);
+		patch(p1, pc);
+		bgen(n, 1, 0, p2);
+		gmove(nodbool(0), res);
+		patch(p3, pc);
+		return;
+
+	case OPLUS:
+		cgen(nl, res);
+		return;
+
+	case OCONV:
+		if(eqtype(n->type, nl->type) || noconv(n->type, nl->type)) {
+			cgen(nl, res);
+			return;
+		}
+
+		tempname(&n2, n->type);
+		mgen(nl, &n1, res);
+		gmove(&n1, &n2);
+		gmove(&n2, res);
+		mfree(&n1);
+		return;
+	}
+
+	if(use_sse)
+		cgen_floatsse(n, res);
+	else
+		cgen_float387(n, res);
+}
+
+// floating-point.  387 (not SSE2)
+static void
+cgen_float387(Node *n, Node *res)
+{
+	Node f0, f1;
+	Node *nl, *nr;
+
+	nl = n->left;
+	nr = n->right;
+	nodreg(&f0, nl->type, D_F0);
+	nodreg(&f1, n->type, D_F0+1);
+	if(nr != N)
+		goto flt2;
+
+	// unary
+	cgen(nl, &f0);
+	if(n->op != OCONV && n->op != OPLUS)
+		gins(foptoas(n->op, n->type, 0), N, N);
+	gmove(&f0, res);
+	return;
+
+flt2:	// binary
+	if(nl->ullman >= nr->ullman) {
+		cgen(nl, &f0);
+		if(nr->addable)
+			gins(foptoas(n->op, n->type, 0), nr, &f0);
+		else {
+			cgen(nr, &f0);
+			gins(foptoas(n->op, n->type, Fpop), &f0, &f1);
+		}
+	} else {
+		cgen(nr, &f0);
+		if(nl->addable)
+			gins(foptoas(n->op, n->type, Frev), nl, &f0);
+		else {
+			cgen(nl, &f0);
+			gins(foptoas(n->op, n->type, Frev|Fpop), &f0, &f1);
+		}
+	}
+	gmove(&f0, res);
+	return;
+
+}
+
+static void
+cgen_floatsse(Node *n, Node *res)
+{
+	Node *nl, *nr, *r;
+	Node n1, n2, nt;
+	int a;
+
+	nl = n->left;
+	nr = n->right;
+	switch(n->op) {
+	default:
+		dump("cgen_floatsse", n);
+		fatal("cgen_floatsse %O", n->op);
+		return;
+
+	case OMINUS:
+	case OCOM:
+		nr = nodintconst(-1);
+		convlit(&nr, n->type);
+		a = foptoas(OMUL, nl->type, 0);
+		goto sbop;
+
+	// symmetric binary
+	case OADD:
+	case OMUL:
+		a = foptoas(n->op, nl->type, 0);
+		goto sbop;
+
+	// asymmetric binary
+	case OSUB:
+	case OMOD:
+	case ODIV:
+		a = foptoas(n->op, nl->type, 0);
+		goto abop;
+	}
+
+sbop:	// symmetric binary
+	if(nl->ullman < nr->ullman || nl->op == OLITERAL) {
+		r = nl;
+		nl = nr;
+		nr = r;
+	}
+
+abop:	// asymmetric binary
+	if(nl->ullman >= nr->ullman) {
+		tempname(&nt, nl->type);
+		cgen(nl, &nt);
+		mgen(nr, &n2, N);
+		regalloc(&n1, nl->type, res);
+		gmove(&nt, &n1);
+		gins(a, &n2, &n1);
+		gmove(&n1, res);
+		regfree(&n1);
+		mfree(&n2);
+	} else {
+		regalloc(&n2, nr->type, res);
+		cgen(nr, &n2);
+		regalloc(&n1, nl->type, N);
+		cgen(nl, &n1);
+		gins(a, &n2, &n1);
+		regfree(&n2);
+		gmove(&n1, res);
+		regfree(&n1);
+	}
+	return;
+}
+
+void
+bgen_float(Node *n, int true, int likely, Prog *to)
+{
+	int et, a;
+	Node *nl, *nr, *r;
+	Node n1, n2, n3, tmp, t1, t2, ax;
+	Prog *p1, *p2;
+
+	nl = n->left;
+	nr = n->right;
+	a = n->op;
+	if(!true) {
+		// brcom is not valid on floats when NaN is involved.
+		p1 = gbranch(AJMP, T, 0);
+		p2 = gbranch(AJMP, T, 0);
+		patch(p1, pc);
+		// No need to avoid re-genning ninit.
+		bgen_float(n, 1, -likely, p2);
+		patch(gbranch(AJMP, T, 0), to);
+		patch(p2, pc);
+		return;
+	}
+
+	if(use_sse)
+		goto sse;
+	else
+		goto x87;
+
+x87:
+	a = brrev(a);	// because the args are stacked
+	if(a == OGE || a == OGT) {
+		// only < and <= work right with NaN; reverse if needed
+		r = nr;
+		nr = nl;
+		nl = r;
+		a = brrev(a);
+	}
+
+	nodreg(&tmp, nr->type, D_F0);
+	nodreg(&n2, nr->type, D_F0 + 1);
+	nodreg(&ax, types[TUINT16], D_AX);
+	et = simsimtype(nr->type);
+	if(et == TFLOAT64) {
+		if(nl->ullman > nr->ullman) {
+			cgen(nl, &tmp);
+			cgen(nr, &tmp);
+			gins(AFXCHD, &tmp, &n2);
+		} else {
+			cgen(nr, &tmp);
+			cgen(nl, &tmp);
+		}
+		gins(AFUCOMIP, &tmp, &n2);
+		gins(AFMOVDP, &tmp, &tmp);	// annoying pop but still better than STSW+SAHF
+	} else {
+		// TODO(rsc): The moves back and forth to memory
+		// here are for truncating the value to 32 bits.
+		// This handles 32-bit comparison but presumably
+		// all the other ops have the same problem.
+		// We need to figure out what the right general
+		// solution is, besides telling people to use float64.
+		tempname(&t1, types[TFLOAT32]);
+		tempname(&t2, types[TFLOAT32]);
+		cgen(nr, &t1);
+		cgen(nl, &t2);
+		gmove(&t2, &tmp);
+		gins(AFCOMFP, &t1, &tmp);
+		gins(AFSTSW, N, &ax);
+		gins(ASAHF, N, N);
+	}
+
+	goto ret;
+
+sse:
+	if(!nl->addable) {
+		tempname(&n1, nl->type);
+		cgen(nl, &n1);
+		nl = &n1;
+	}
+	if(!nr->addable) {
+		tempname(&tmp, nr->type);
+		cgen(nr, &tmp);
+		nr = &tmp;
+	}
+	regalloc(&n2, nr->type, N);
+	gmove(nr, &n2);
+	nr = &n2;
+
+	if(nl->op != OREGISTER) {
+		regalloc(&n3, nl->type, N);
+		gmove(nl, &n3);
+		nl = &n3;
+	}
+
+	if(a == OGE || a == OGT) {
+		// only < and <= work right with NaN; reverse if needed
+		r = nr;
+		nr = nl;
+		nl = r;
+		a = brrev(a);
+	}
+
+	gins(foptoas(OCMP, nr->type, 0), nl, nr);
+	if(nl->op == OREGISTER)
+		regfree(nl);
+	regfree(nr);
+
+ret:
+	if(a == OEQ) {
+		// neither NE nor P
+		p1 = gbranch(AJNE, T, -likely);
+		p2 = gbranch(AJPS, T, -likely);
+		patch(gbranch(AJMP, T, 0), to);
+		patch(p1, pc);
+		patch(p2, pc);
+	} else if(a == ONE) {
+		// either NE or P
+		patch(gbranch(AJNE, T, likely), to);
+		patch(gbranch(AJPS, T, likely), to);
+	} else
+		patch(gbranch(optoas(a, nr->type), T, likely), to);
+
+}
+
+// Called after regopt and peep have run.
+// Expand CHECKNIL pseudo-op into actual nil pointer check.
+void
+expandchecks(Prog *firstp)
+{
+	Prog *p, *p1, *p2;
+
+	for(p = firstp; p != P; p = p->link) {
+		if(p->as != ACHECKNIL)
+			continue;
+		if(debug_checknil && p->lineno > 1) // p->lineno==1 in generated wrappers
+			warnl(p->lineno, "generated nil check");
+		// check is
+		//	CMP arg, $0
+		//	JNE 2(PC) (likely)
+		//	MOV AX, 0
+		p1 = mal(sizeof *p1);
+		p2 = mal(sizeof *p2);
+		clearp(p1);
+		clearp(p2);
+		p1->link = p2;
+		p2->link = p->link;
+		p->link = p1;
+		p1->lineno = p->lineno;
+		p2->lineno = p->lineno;
+		p1->pc = 9999;
+		p2->pc = 9999;
+		p->as = ACMPL;
+		p->to.type = D_CONST;
+		p->to.offset = 0;
+		p1->as = AJNE;
+		p1->from.type = D_CONST;
+		p1->from.offset = 1; // likely
+		p1->to.type = D_BRANCH;
+		p1->to.u.branch = p2->link;
+		// crash by write to memory address 0.
+		// if possible, since we know arg is 0, use 0(arg),
+		// which will be shorter to encode than plain 0.
+		p2->as = AMOVL;
+		p2->from.type = D_AX;
+		if(regtyp(&p->from))
+			p2->to.type = p->from.type + D_INDIR;
+		else
+			p2->to.type = D_INDIR+D_NONE;
+		p2->to.offset = 0;
+	}
+}
diff --git a/src/cmd/8g/gobj.c b/src/cmd/8g/gobj.c
new file mode 100644
index 0000000..fa0605e
--- /dev/null
+++ b/src/cmd/8g/gobj.c
@@ -0,0 +1,246 @@
+// Derived from Inferno utils/8c/swt.c
+// http://code.google.com/p/inferno-os/source/browse/utils/8c/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 "gg.h"
+
+int
+dsname(Sym *s, int off, char *t, int n)
+{
+	Prog *p;
+
+	p = gins(ADATA, N, N);
+	p->from.type = D_EXTERN;
+	p->from.index = D_NONE;
+	p->from.offset = off;
+	p->from.scale = n;
+	p->from.sym = linksym(s);
+	
+	p->to.type = D_SCONST;
+	p->to.index = D_NONE;
+	memmove(p->to.u.sval, t, n);
+	return off + n;
+}
+
+/*
+ * make a refer to the data s, s+len
+ * emitting DATA if needed.
+ */
+void
+datastring(char *s, int len, Addr *a)
+{
+	Sym *sym;
+	
+	sym = stringsym(s, len);
+	a->type = D_EXTERN;
+	a->sym = linksym(sym);
+	a->node = sym->def;
+	a->offset = widthptr+4;  // skip header
+	a->etype = TINT32;
+}
+
+/*
+ * make a refer to the string sval,
+ * emitting DATA if needed.
+ */
+void
+datagostring(Strlit *sval, Addr *a)
+{
+	Sym *sym;
+	
+	sym = stringsym(sval->s, sval->len);
+	a->type = D_EXTERN;
+	a->sym = linksym(sym);
+	a->node = sym->def;
+	a->offset = 0;  // header
+	a->etype = TINT32;
+}
+
+void
+gdata(Node *nam, Node *nr, int wid)
+{
+	Prog *p;
+	vlong v;
+
+	if(nr->op == OLITERAL) {
+		switch(nr->val.ctype) {
+		case CTCPLX:
+			gdatacomplex(nam, nr->val.u.cval);
+			return;
+		case CTSTR:
+			gdatastring(nam, nr->val.u.sval);
+			return;
+		}
+	}
+
+	if(wid == 8 && is64(nr->type)) {
+		v = mpgetfix(nr->val.u.xval);
+		p = gins(ADATA, nam, nodintconst(v));
+		p->from.scale = 4;
+		p = gins(ADATA, nam, nodintconst(v>>32));
+		p->from.scale = 4;
+		p->from.offset += 4;
+		return;
+	}
+	p = gins(ADATA, nam, nr);
+	p->from.scale = wid;
+}
+
+void
+gdatacomplex(Node *nam, Mpcplx *cval)
+{
+	Prog *p;
+	int w;
+
+	w = cplxsubtype(nam->type->etype);
+	w = types[w]->width;
+
+	p = gins(ADATA, nam, N);
+	p->from.scale = w;
+	p->to.type = D_FCONST;
+	p->to.u.dval = mpgetflt(&cval->real);
+
+	p = gins(ADATA, nam, N);
+	p->from.scale = w;
+	p->from.offset += w;
+	p->to.type = D_FCONST;
+	p->to.u.dval = mpgetflt(&cval->imag);
+}
+
+void
+gdatastring(Node *nam, Strlit *sval)
+{
+	Prog *p;
+	Node nod1;
+
+	p = gins(ADATA, nam, N);
+	datastring(sval->s, sval->len, &p->to);
+	p->from.scale = types[tptr]->width;
+	p->to.index = p->to.type;
+	p->to.type = D_ADDR;
+//print("%P\n", p);
+
+	nodconst(&nod1, types[TINT32], sval->len);
+	p = gins(ADATA, nam, &nod1);
+	p->from.scale = types[TINT32]->width;
+	p->from.offset += types[tptr]->width;
+}
+
+int
+dstringptr(Sym *s, int off, char *str)
+{
+	Prog *p;
+
+	off = rnd(off, widthptr);
+	p = gins(ADATA, N, N);
+	p->from.type = D_EXTERN;
+	p->from.index = D_NONE;
+	p->from.sym = linksym(s);
+	p->from.offset = off;
+	p->from.scale = widthptr;
+
+	datastring(str, strlen(str)+1, &p->to);
+	p->to.index = p->to.type;
+	p->to.type = D_ADDR;
+	p->to.etype = TINT32;
+	off += widthptr;
+
+	return off;
+}
+
+int
+dgostrlitptr(Sym *s, int off, Strlit *lit)
+{
+	Prog *p;
+
+	if(lit == nil)
+		return duintptr(s, off, 0);
+
+	off = rnd(off, widthptr);
+	p = gins(ADATA, N, N);
+	p->from.type = D_EXTERN;
+	p->from.index = D_NONE;
+	p->from.sym = linksym(s);
+	p->from.offset = off;
+	p->from.scale = widthptr;
+	datagostring(lit, &p->to);
+	p->to.index = p->to.type;
+	p->to.type = D_ADDR;
+	p->to.etype = TINT32;
+	off += widthptr;
+
+	return off;
+}
+
+int
+dgostringptr(Sym *s, int off, char *str)
+{
+	int n;
+	Strlit *lit;
+
+	if(str == nil)
+		return duintptr(s, off, 0);
+
+	n = strlen(str);
+	lit = mal(sizeof *lit + n);
+	strcpy(lit->s, str);
+	lit->len = n;
+	return dgostrlitptr(s, off, lit);
+}
+
+int
+dsymptr(Sym *s, int off, Sym *x, int xoff)
+{
+	Prog *p;
+
+	off = rnd(off, widthptr);
+
+	p = gins(ADATA, N, N);
+	p->from.type = D_EXTERN;
+	p->from.index = D_NONE;
+	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 = linksym(x);
+	p->to.offset = xoff;
+	off += widthptr;
+
+	return off;
+}
+
+void
+nopout(Prog *p)
+{
+	p->as = ANOP;
+}
+
diff --git a/src/cmd/8g/gsubr.c b/src/cmd/8g/gsubr.c
new file mode 100644
index 0000000..3077e0a
--- /dev/null
+++ b/src/cmd/8g/gsubr.c
@@ -0,0 +1,2401 @@
+// Derived from Inferno utils/8c/txt.c
+// http://code.google.com/p/inferno-os/source/browse/utils/8c/txt.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"
+#include "../../runtime/funcdata.h"
+
+// TODO(rsc): Can make this bigger if we move
+// the text segment up higher in 8l for all GOOS.
+// At the same time, can raise StackBig in ../../runtime/stack.h.
+uint32 unmappedzero = 4096;
+
+#define	CASE(a,b)	(((a)<<16)|((b)<<0))
+/*c2go int CASE(int, int);*/
+
+void
+clearp(Prog *p)
+{
+	p->as = AEND;
+	p->from.type = D_NONE;
+	p->from.index = D_NONE;
+	p->to.type = D_NONE;
+	p->to.index = D_NONE;
+	p->pc = pcloc;
+	pcloc++;
+}
+
+static int ddumped;
+static Prog *dfirst;
+static Prog *dpc;
+
+/*
+ * generate and return proc with p->as = as,
+ * linked into program.  pc is next instruction.
+ */
+Prog*
+prog(int as)
+{
+	Prog *p;
+
+	if(as == ADATA || as == AGLOBL) {
+		if(ddumped)
+			fatal("already dumped data");
+		if(dpc == nil) {
+			dpc = mal(sizeof(*dpc));
+			dfirst = dpc;
+		}
+		p = dpc;
+		dpc = mal(sizeof(*dpc));
+		p->link = dpc;
+	} else {
+		p = pc;
+		pc = mal(sizeof(*pc));
+		clearp(pc);
+		p->link = pc;
+	}
+
+	if(lineno == 0) {
+		if(debug['K'])
+			warn("prog: line 0");
+	}
+
+	p->as = as;
+	p->lineno = lineno;
+	return p;
+}
+
+void
+dumpdata(void)
+{
+	ddumped = 1;
+	if(dfirst == nil)
+		return;
+	newplist();
+	*pc = *dfirst;
+	pc = dpc;
+	clearp(pc);
+}
+
+/*
+ * generate a branch.
+ * t is ignored.
+ * likely values are for branch prediction:
+ *	-1 unlikely
+ *	0 no opinion
+ *	+1 likely
+ */
+Prog*
+gbranch(int as, Type *t, int likely)
+{
+	Prog *p;
+
+	USED(t);
+	p = prog(as);
+	p->to.type = D_BRANCH;
+	p->to.u.branch = P;
+	if(likely != 0) {
+		p->from.type = D_CONST;
+		p->from.offset = likely > 0;
+	}
+	return p;
+}
+
+/*
+ * patch previous branch to jump to to.
+ */
+void
+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->pc;
+}
+
+Prog*
+unpatch(Prog *p)
+{
+	Prog *q;
+
+	if(p->to.type != D_BRANCH)
+		fatal("unpatch: not a branch");
+	q = p->to.u.branch;
+	p->to.u.branch = P;
+	p->to.offset = 0;
+	return q;
+}
+
+/*
+ * start a new Prog list.
+ */
+Plist*
+newplist(void)
+{
+	Plist *pl;
+
+	pl = linknewplist(ctxt);
+	
+	pc = mal(sizeof(*pc));
+	clearp(pc);
+	pl->firstpc = pc;
+
+	return pl;
+}
+
+void
+gused(Node *n)
+{
+	gins(ANOP, n, N);	// used
+}
+
+Prog*
+gjmp(Prog *to)
+{
+	Prog *p;
+
+	p = gbranch(AJMP, T, 0);
+	if(to != P)
+		patch(p, to);
+	return p;
+}
+
+void
+ggloblnod(Node *nam)
+{
+	Prog *p;
+
+	p = gins(AGLOBL, nam, N);
+	p->lineno = nam->lineno;
+	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)
+		p->from.scale = RODATA;
+	if(nam->type != T && !haspointers(nam->type))
+		p->from.scale |= NOPTR;
+}
+
+void
+ggloblsym(Sym *s, int32 width, int8 flags)
+{
+	Prog *p;
+
+	p = gins(AGLOBL, N, N);
+	p->from.type = D_EXTERN;
+	p->from.index = D_NONE;
+	p->from.sym = linksym(s);
+	p->to.type = D_CONST;
+	p->to.index = D_NONE;
+	p->to.offset = width;
+	p->from.scale = flags;
+}
+
+void
+gtrack(Sym *s)
+{
+	Prog *p;
+	
+	p = gins(AUSEFIELD, N, N);
+	p->from.type = D_EXTERN;
+	p->from.index = D_NONE;
+	p->from.sym = linksym(s);
+}
+
+int
+isfat(Type *t)
+{
+	if(t != T)
+	switch(t->etype) {
+	case TSTRUCT:
+	case TARRAY:
+	case TSTRING:
+	case TINTER:	// maybe remove later
+		return 1;
+	}
+	return 0;
+}
+
+/*
+ * naddr of func generates code for address of func.
+ * if using opcode that can take address implicitly,
+ * call afunclit to fix up the argument.
+ */
+void
+afunclit(Addr *a, Node *n)
+{
+	if(a->type == D_ADDR && a->index == D_EXTERN) {
+		a->type = D_EXTERN;
+		a->index = D_NONE;
+		a->sym = linksym(n->sym);
+	}
+}
+
+/*
+ * return Axxx for Oxxx on type t.
+ */
+int
+optoas(int op, Type *t)
+{
+	int a;
+
+	if(t == T)
+		fatal("optoas: t is nil");
+
+	a = AGOK;
+	switch(CASE(op, simtype[t->etype])) {
+	default:
+		fatal("optoas: no entry %O-%T", op, t);
+		break;
+
+	case CASE(OADDR, TPTR32):
+		a = ALEAL;
+		break;
+
+	case CASE(OEQ, TBOOL):
+	case CASE(OEQ, TINT8):
+	case CASE(OEQ, TUINT8):
+	case CASE(OEQ, TINT16):
+	case CASE(OEQ, TUINT16):
+	case CASE(OEQ, TINT32):
+	case CASE(OEQ, TUINT32):
+	case CASE(OEQ, TINT64):
+	case CASE(OEQ, TUINT64):
+	case CASE(OEQ, TPTR32):
+	case CASE(OEQ, TPTR64):
+	case CASE(OEQ, TFLOAT32):
+	case CASE(OEQ, TFLOAT64):
+		a = AJEQ;
+		break;
+
+	case CASE(ONE, TBOOL):
+	case CASE(ONE, TINT8):
+	case CASE(ONE, TUINT8):
+	case CASE(ONE, TINT16):
+	case CASE(ONE, TUINT16):
+	case CASE(ONE, TINT32):
+	case CASE(ONE, TUINT32):
+	case CASE(ONE, TINT64):
+	case CASE(ONE, TUINT64):
+	case CASE(ONE, TPTR32):
+	case CASE(ONE, TPTR64):
+	case CASE(ONE, TFLOAT32):
+	case CASE(ONE, TFLOAT64):
+		a = AJNE;
+		break;
+
+	case CASE(OLT, TINT8):
+	case CASE(OLT, TINT16):
+	case CASE(OLT, TINT32):
+	case CASE(OLT, TINT64):
+		a = AJLT;
+		break;
+
+	case CASE(OLT, TUINT8):
+	case CASE(OLT, TUINT16):
+	case CASE(OLT, TUINT32):
+	case CASE(OLT, TUINT64):
+		a = AJCS;
+		break;
+
+	case CASE(OLE, TINT8):
+	case CASE(OLE, TINT16):
+	case CASE(OLE, TINT32):
+	case CASE(OLE, TINT64):
+		a = AJLE;
+		break;
+
+	case CASE(OLE, TUINT8):
+	case CASE(OLE, TUINT16):
+	case CASE(OLE, TUINT32):
+	case CASE(OLE, TUINT64):
+		a = AJLS;
+		break;
+
+	case CASE(OGT, TINT8):
+	case CASE(OGT, TINT16):
+	case CASE(OGT, TINT32):
+	case CASE(OGT, TINT64):
+		a = AJGT;
+		break;
+
+	case CASE(OGT, TUINT8):
+	case CASE(OGT, TUINT16):
+	case CASE(OGT, TUINT32):
+	case CASE(OGT, TUINT64):
+	case CASE(OLT, TFLOAT32):
+	case CASE(OLT, TFLOAT64):
+		a = AJHI;
+		break;
+
+	case CASE(OGE, TINT8):
+	case CASE(OGE, TINT16):
+	case CASE(OGE, TINT32):
+	case CASE(OGE, TINT64):
+		a = AJGE;
+		break;
+
+	case CASE(OGE, TUINT8):
+	case CASE(OGE, TUINT16):
+	case CASE(OGE, TUINT32):
+	case CASE(OGE, TUINT64):
+	case CASE(OLE, TFLOAT32):
+	case CASE(OLE, TFLOAT64):
+		a = AJCC;
+		break;
+
+	case CASE(OCMP, TBOOL):
+	case CASE(OCMP, TINT8):
+	case CASE(OCMP, TUINT8):
+		a = ACMPB;
+		break;
+
+	case CASE(OCMP, TINT16):
+	case CASE(OCMP, TUINT16):
+		a = ACMPW;
+		break;
+
+	case CASE(OCMP, TINT32):
+	case CASE(OCMP, TUINT32):
+	case CASE(OCMP, TPTR32):
+		a = ACMPL;
+		break;
+
+	case CASE(OAS, TBOOL):
+	case CASE(OAS, TINT8):
+	case CASE(OAS, TUINT8):
+		a = AMOVB;
+		break;
+
+	case CASE(OAS, TINT16):
+	case CASE(OAS, TUINT16):
+		a = AMOVW;
+		break;
+
+	case CASE(OAS, TINT32):
+	case CASE(OAS, TUINT32):
+	case CASE(OAS, TPTR32):
+		a = AMOVL;
+		break;
+
+	case CASE(OADD, TINT8):
+	case CASE(OADD, TUINT8):
+		a = AADDB;
+		break;
+
+	case CASE(OADD, TINT16):
+	case CASE(OADD, TUINT16):
+		a = AADDW;
+		break;
+
+	case CASE(OADD, TINT32):
+	case CASE(OADD, TUINT32):
+	case CASE(OADD, TPTR32):
+		a = AADDL;
+		break;
+
+	case CASE(OSUB, TINT8):
+	case CASE(OSUB, TUINT8):
+		a = ASUBB;
+		break;
+
+	case CASE(OSUB, TINT16):
+	case CASE(OSUB, TUINT16):
+		a = ASUBW;
+		break;
+
+	case CASE(OSUB, TINT32):
+	case CASE(OSUB, TUINT32):
+	case CASE(OSUB, TPTR32):
+		a = ASUBL;
+		break;
+
+	case CASE(OINC, TINT8):
+	case CASE(OINC, TUINT8):
+		a = AINCB;
+		break;
+
+	case CASE(OINC, TINT16):
+	case CASE(OINC, TUINT16):
+		a = AINCW;
+		break;
+
+	case CASE(OINC, TINT32):
+	case CASE(OINC, TUINT32):
+	case CASE(OINC, TPTR32):
+		a = AINCL;
+		break;
+
+	case CASE(ODEC, TINT8):
+	case CASE(ODEC, TUINT8):
+		a = ADECB;
+		break;
+
+	case CASE(ODEC, TINT16):
+	case CASE(ODEC, TUINT16):
+		a = ADECW;
+		break;
+
+	case CASE(ODEC, TINT32):
+	case CASE(ODEC, TUINT32):
+	case CASE(ODEC, TPTR32):
+		a = ADECL;
+		break;
+
+	case CASE(OCOM, TINT8):
+	case CASE(OCOM, TUINT8):
+		a = ANOTB;
+		break;
+
+	case CASE(OCOM, TINT16):
+	case CASE(OCOM, TUINT16):
+		a = ANOTW;
+		break;
+
+	case CASE(OCOM, TINT32):
+	case CASE(OCOM, TUINT32):
+	case CASE(OCOM, TPTR32):
+		a = ANOTL;
+		break;
+
+	case CASE(OMINUS, TINT8):
+	case CASE(OMINUS, TUINT8):
+		a = ANEGB;
+		break;
+
+	case CASE(OMINUS, TINT16):
+	case CASE(OMINUS, TUINT16):
+		a = ANEGW;
+		break;
+
+	case CASE(OMINUS, TINT32):
+	case CASE(OMINUS, TUINT32):
+	case CASE(OMINUS, TPTR32):
+		a = ANEGL;
+		break;
+
+	case CASE(OAND, TINT8):
+	case CASE(OAND, TUINT8):
+		a = AANDB;
+		break;
+
+	case CASE(OAND, TINT16):
+	case CASE(OAND, TUINT16):
+		a = AANDW;
+		break;
+
+	case CASE(OAND, TINT32):
+	case CASE(OAND, TUINT32):
+	case CASE(OAND, TPTR32):
+		a = AANDL;
+		break;
+
+	case CASE(OOR, TINT8):
+	case CASE(OOR, TUINT8):
+		a = AORB;
+		break;
+
+	case CASE(OOR, TINT16):
+	case CASE(OOR, TUINT16):
+		a = AORW;
+		break;
+
+	case CASE(OOR, TINT32):
+	case CASE(OOR, TUINT32):
+	case CASE(OOR, TPTR32):
+		a = AORL;
+		break;
+
+	case CASE(OXOR, TINT8):
+	case CASE(OXOR, TUINT8):
+		a = AXORB;
+		break;
+
+	case CASE(OXOR, TINT16):
+	case CASE(OXOR, TUINT16):
+		a = AXORW;
+		break;
+
+	case CASE(OXOR, TINT32):
+	case CASE(OXOR, TUINT32):
+	case CASE(OXOR, TPTR32):
+		a = AXORL;
+		break;
+
+	case CASE(OLROT, TINT8):
+	case CASE(OLROT, TUINT8):
+		a = AROLB;
+		break;
+
+	case CASE(OLROT, TINT16):
+	case CASE(OLROT, TUINT16):
+		a = AROLW;
+		break;
+
+	case CASE(OLROT, TINT32):
+	case CASE(OLROT, TUINT32):
+	case CASE(OLROT, TPTR32):
+		a = AROLL;
+		break;
+
+	case CASE(OLSH, TINT8):
+	case CASE(OLSH, TUINT8):
+		a = ASHLB;
+		break;
+
+	case CASE(OLSH, TINT16):
+	case CASE(OLSH, TUINT16):
+		a = ASHLW;
+		break;
+
+	case CASE(OLSH, TINT32):
+	case CASE(OLSH, TUINT32):
+	case CASE(OLSH, TPTR32):
+		a = ASHLL;
+		break;
+
+	case CASE(ORSH, TUINT8):
+		a = ASHRB;
+		break;
+
+	case CASE(ORSH, TUINT16):
+		a = ASHRW;
+		break;
+
+	case CASE(ORSH, TUINT32):
+	case CASE(ORSH, TPTR32):
+		a = ASHRL;
+		break;
+
+	case CASE(ORSH, TINT8):
+		a = ASARB;
+		break;
+
+	case CASE(ORSH, TINT16):
+		a = ASARW;
+		break;
+
+	case CASE(ORSH, TINT32):
+		a = ASARL;
+		break;
+
+	case CASE(OHMUL, TINT8):
+	case CASE(OMUL, TINT8):
+	case CASE(OMUL, TUINT8):
+		a = AIMULB;
+		break;
+
+	case CASE(OHMUL, TINT16):
+	case CASE(OMUL, TINT16):
+	case CASE(OMUL, TUINT16):
+		a = AIMULW;
+		break;
+
+	case CASE(OHMUL, TINT32):
+	case CASE(OMUL, TINT32):
+	case CASE(OMUL, TUINT32):
+	case CASE(OMUL, TPTR32):
+		a = AIMULL;
+		break;
+
+	case CASE(OHMUL, TUINT8):
+		a = AMULB;
+		break;
+
+	case CASE(OHMUL, TUINT16):
+		a = AMULW;
+		break;
+
+	case CASE(OHMUL, TUINT32):
+	case CASE(OHMUL, TPTR32):
+		a = AMULL;
+		break;
+
+	case CASE(ODIV, TINT8):
+	case CASE(OMOD, TINT8):
+		a = AIDIVB;
+		break;
+
+	case CASE(ODIV, TUINT8):
+	case CASE(OMOD, TUINT8):
+		a = ADIVB;
+		break;
+
+	case CASE(ODIV, TINT16):
+	case CASE(OMOD, TINT16):
+		a = AIDIVW;
+		break;
+
+	case CASE(ODIV, TUINT16):
+	case CASE(OMOD, TUINT16):
+		a = ADIVW;
+		break;
+
+	case CASE(ODIV, TINT32):
+	case CASE(OMOD, TINT32):
+		a = AIDIVL;
+		break;
+
+	case CASE(ODIV, TUINT32):
+	case CASE(ODIV, TPTR32):
+	case CASE(OMOD, TUINT32):
+	case CASE(OMOD, TPTR32):
+		a = ADIVL;
+		break;
+
+	case CASE(OEXTEND, TINT16):
+		a = ACWD;
+		break;
+
+	case CASE(OEXTEND, TINT32):
+		a = ACDQ;
+		break;
+	}
+	return a;
+}
+
+#define FCASE(a, b, c)  (((a)<<16)|((b)<<8)|(c))
+/*c2go int FCASE(int, int, int); */
+int
+foptoas(int op, Type *t, int flg)
+{
+	int et, a;
+
+	a = AGOK;
+	et = simtype[t->etype];
+
+	if(use_sse)
+		goto sse;
+
+	// If we need Fpop, it means we're working on
+	// two different floating-point registers, not memory.
+	// There the instruction only has a float64 form.
+	if(flg & Fpop)
+		et = TFLOAT64;
+
+	// clear Frev if unneeded
+	switch(op) {
+	case OADD:
+	case OMUL:
+		flg &= ~Frev;
+		break;
+	}
+
+	switch(FCASE(op, et, flg)) {
+	case FCASE(OADD, TFLOAT32, 0):
+		return AFADDF;
+	case FCASE(OADD, TFLOAT64, 0):
+		return AFADDD;
+	case FCASE(OADD, TFLOAT64, Fpop):
+		return AFADDDP;
+
+	case FCASE(OSUB, TFLOAT32, 0):
+		return AFSUBF;
+	case FCASE(OSUB, TFLOAT32, Frev):
+		return AFSUBRF;
+
+	case FCASE(OSUB, TFLOAT64, 0):
+		return AFSUBD;
+	case FCASE(OSUB, TFLOAT64, Frev):
+		return AFSUBRD;
+	case FCASE(OSUB, TFLOAT64, Fpop):
+		return AFSUBDP;
+	case FCASE(OSUB, TFLOAT64, Fpop|Frev):
+		return AFSUBRDP;
+
+	case FCASE(OMUL, TFLOAT32, 0):
+		return AFMULF;
+	case FCASE(OMUL, TFLOAT64, 0):
+		return AFMULD;
+	case FCASE(OMUL, TFLOAT64, Fpop):
+		return AFMULDP;
+
+	case FCASE(ODIV, TFLOAT32, 0):
+		return AFDIVF;
+	case FCASE(ODIV, TFLOAT32, Frev):
+		return AFDIVRF;
+
+	case FCASE(ODIV, TFLOAT64, 0):
+		return AFDIVD;
+	case FCASE(ODIV, TFLOAT64, Frev):
+		return AFDIVRD;
+	case FCASE(ODIV, TFLOAT64, Fpop):
+		return AFDIVDP;
+	case FCASE(ODIV, TFLOAT64, Fpop|Frev):
+		return AFDIVRDP;
+
+	case FCASE(OCMP, TFLOAT32, 0):
+		return AFCOMF;
+	case FCASE(OCMP, TFLOAT32, Fpop):
+		return AFCOMFP;
+	case FCASE(OCMP, TFLOAT64, 0):
+		return AFCOMD;
+	case FCASE(OCMP, TFLOAT64, Fpop):
+		return AFCOMDP;
+	case FCASE(OCMP, TFLOAT64, Fpop2):
+		return AFCOMDPP;
+	
+	case FCASE(OMINUS, TFLOAT32, 0):
+		return AFCHS;
+	case FCASE(OMINUS, TFLOAT64, 0):
+		return AFCHS;
+	}
+
+	fatal("foptoas %O %T %#x", op, t, flg);
+	return 0;
+
+sse:
+	switch(CASE(op, et)) {
+	default:
+		fatal("foptoas-sse: no entry %O-%T", op, t);
+		break;
+
+	case CASE(OCMP, TFLOAT32):
+		a = AUCOMISS;
+		break;
+
+	case CASE(OCMP, TFLOAT64):
+		a = AUCOMISD;
+		break;
+
+	case CASE(OAS, TFLOAT32):
+		a = AMOVSS;
+		break;
+
+	case CASE(OAS, TFLOAT64):
+		a = AMOVSD;
+		break;
+
+	case CASE(OADD, TFLOAT32):
+		a = AADDSS;
+		break;
+
+	case CASE(OADD, TFLOAT64):
+		a = AADDSD;
+		break;
+
+	case CASE(OSUB, TFLOAT32):
+		a = ASUBSS;
+		break;
+
+	case CASE(OSUB, TFLOAT64):
+		a = ASUBSD;
+		break;
+
+	case CASE(OMUL, TFLOAT32):
+		a = AMULSS;
+		break;
+
+	case CASE(OMUL, TFLOAT64):
+		a = AMULSD;
+		break;
+
+	case CASE(ODIV, TFLOAT32):
+		a = ADIVSS;
+		break;
+
+	case CASE(ODIV, TFLOAT64):
+		a = ADIVSD;
+		break;
+	}
+	return a;
+}
+
+
+static	int	resvd[] =
+{
+//	D_DI,	// for movstring
+//	D_SI,	// for movstring
+
+	D_AX,	// for divide
+	D_CX,	// for shift
+	D_DX,	// for divide
+	D_SP,	// for stack
+
+	D_BL,	// because D_BX can be allocated
+	D_BH,
+};
+
+void
+ginit(void)
+{
+	int i;
+
+	for(i=0; i<nelem(reg); i++)
+		reg[i] = 1;
+	for(i=D_AX; i<=D_DI; i++)
+		reg[i] = 0;
+	for(i=D_X0; i<=D_X7; i++)
+		reg[i] = 0;
+	for(i=0; i<nelem(resvd); i++)
+		reg[resvd[i]]++;
+}
+
+uintptr regpc[D_NONE];
+
+void
+gclean(void)
+{
+	int i;
+
+	for(i=0; i<nelem(resvd); i++)
+		reg[resvd[i]]--;
+
+	for(i=D_AX; i<=D_DI; i++)
+		if(reg[i])
+			yyerror("reg %R left allocated at %ux", i, regpc[i]);
+	for(i=D_X0; i<=D_X7; i++)
+		if(reg[i])
+			yyerror("reg %R left allocated\n", i);
+}
+
+int32
+anyregalloc(void)
+{
+	int i, j;
+
+	for(i=D_AX; i<=D_DI; i++) {
+		if(reg[i] == 0)
+			goto ok;
+		for(j=0; j<nelem(resvd); j++)
+			if(resvd[j] == i)
+				goto ok;
+		return 1;
+	ok:;
+	}
+	for(i=D_X0; i<=D_X7; i++)
+		if(reg[i])
+			return 1;
+	return 0;
+}
+
+/*
+ * allocate register of type t, leave in n.
+ * if o != N, o is desired fixed register.
+ * caller must regfree(n).
+ */
+void
+regalloc(Node *n, Type *t, Node *o)
+{
+	int i, et;
+
+	if(t == T)
+		fatal("regalloc: t nil");
+	et = simtype[t->etype];
+
+	switch(et) {
+	case TINT64:
+	case TUINT64:
+		fatal("regalloc64");
+
+	case TINT8:
+	case TUINT8:
+	case TINT16:
+	case TUINT16:
+	case TINT32:
+	case TUINT32:
+	case TPTR32:
+	case TPTR64:
+	case TBOOL:
+		if(o != N && o->op == OREGISTER) {
+			i = o->val.u.reg;
+			if(i >= D_AX && i <= D_DI)
+				goto out;
+		}
+		for(i=D_AX; i<=D_DI; i++)
+			if(reg[i] == 0)
+				goto out;
+
+		fprint(2, "registers allocated at\n");
+		for(i=D_AX; i<=D_DI; i++)
+			fprint(2, "\t%R\t%#lux\n", i, regpc[i]);
+		fatal("out of fixed registers");
+		goto err;
+
+	case TFLOAT32:
+	case TFLOAT64:
+		if(!use_sse) {
+			i = D_F0;
+			goto out;
+		}
+		if(o != N && o->op == OREGISTER) {
+			i = o->val.u.reg;
+			if(i >= D_X0 && i <= D_X7)
+				goto out;
+		}
+		for(i=D_X0; i<=D_X7; i++)
+			if(reg[i] == 0)
+				goto out;
+		fprint(2, "registers allocated at\n");
+		for(i=D_X0; i<=D_X7; i++)
+			fprint(2, "\t%R\t%#lux\n", i, regpc[i]);
+		fatal("out of floating registers");
+	}
+	yyerror("regalloc: unknown type %T", t);
+
+err:
+	nodreg(n, t, 0);
+	return;
+
+out:
+	if (i == D_SP)
+		print("alloc SP\n");
+	if(reg[i] == 0) {
+		regpc[i] = (uintptr)getcallerpc(&n);
+		if(i == D_AX || i == D_CX || i == D_DX || i == D_SP) {
+			dump("regalloc-o", o);
+			fatal("regalloc %R", i);
+		}
+	}
+	reg[i]++;
+	nodreg(n, t, i);
+}
+
+void
+regfree(Node *n)
+{
+	int i;
+	
+	if(n->op == ONAME)
+		return;
+	if(n->op != OREGISTER && n->op != OINDREG)
+		fatal("regfree: not a register");
+	i = n->val.u.reg;
+	if(i == D_SP)
+		return;
+	if(i < 0 || i >= nelem(reg))
+		fatal("regfree: reg out of range");
+	if(reg[i] <= 0)
+		fatal("regfree: reg not allocated");
+	reg[i]--;
+	if(reg[i] == 0 && (i == D_AX || i == D_CX || i == D_DX || i == D_SP))
+		fatal("regfree %R", i);
+}
+
+/*
+ * initialize n to be register r of type t.
+ */
+void
+nodreg(Node *n, Type *t, int r)
+{
+	if(t == T)
+		fatal("nodreg: t nil");
+
+	memset(n, 0, sizeof(*n));
+	n->op = OREGISTER;
+	n->addable = 1;
+	ullmancalc(n);
+	n->val.u.reg = r;
+	n->type = t;
+}
+
+/*
+ * initialize n to be indirect of register r; n is type t.
+ */
+void
+nodindreg(Node *n, Type *t, int r)
+{
+	nodreg(n, t, r);
+	n->op = OINDREG;
+}
+
+Node*
+nodarg(Type *t, int fp)
+{
+	Node *n;
+	NodeList *l;
+	Type *first;
+	Iter savet;
+
+	// entire argument struct, not just one arg
+	switch(t->etype) {
+	default:
+		fatal("nodarg %T", t);
+
+	case TSTRUCT:
+		if(!t->funarg)
+			fatal("nodarg: TSTRUCT but not funarg");
+		n = nod(ONAME, N, N);
+		n->sym = lookup(".args");
+		n->type = t;
+		first = structfirst(&savet, &t);
+		if(first == nil)
+			fatal("nodarg: bad struct");
+		if(first->width == BADWIDTH)
+			fatal("nodarg: offset not computed for %T", t);
+		n->xoffset = first->width;
+		n->addable = 1;
+		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;
+		if(t->width == BADWIDTH)
+			fatal("nodarg: offset not computed for %T", t);
+		n->xoffset = t->width;
+		n->addable = 1;
+		n->orig = t->nname;
+		break;
+	}
+	
+	// Rewrite argument named _ to __,
+	// or else the assignment to _ will be
+	// discarded during code generation.
+	if(isblank(n))
+		n->sym = lookup("__");
+
+	switch(fp) {
+	default:
+		fatal("nodarg %T %d", t, fp);
+
+	case 0:		// output arg
+		n->op = OINDREG;
+		n->val.u.reg = D_SP;
+		break;
+
+	case 1:		// input arg
+		n->class = PPARAM;
+		break;
+	}
+
+	n->typecheck = 1;
+	return n;
+}
+
+/*
+ * generate
+ *	as $c, reg
+ */
+void
+gconreg(int as, vlong c, int reg)
+{
+	Node n1, n2;
+
+	nodconst(&n1, types[TINT64], c);
+	nodreg(&n2, types[TINT64], reg);
+	gins(as, &n1, &n2);
+}
+
+/*
+ * swap node contents
+ */
+void
+nswap(Node *a, Node *b)
+{
+	Node t;
+
+	t = *a;
+	*a = *b;
+	*b = t;
+}
+
+/*
+ * return constant i node.
+ * overwritten by next call, but useful in calls to gins.
+ */
+Node*
+ncon(uint32 i)
+{
+	static Node n;
+
+	if(n.type == T)
+		nodconst(&n, types[TUINT32], 0);
+	mpmovecfix(n.val.u.xval, i);
+	return &n;
+}
+
+/*
+ * Is this node a memory operand?
+ */
+int
+ismem(Node *n)
+{
+	switch(n->op) {
+	case OITAB:
+	case OSPTR:
+	case OLEN:
+	case OCAP:
+	case OINDREG:
+	case ONAME:
+	case OPARAM:
+	case OCLOSUREVAR:
+		return 1;
+	}
+	return 0;
+}
+
+Node sclean[10];
+int nsclean;
+
+/*
+ * n is a 64-bit value.  fill in lo and hi to refer to its 32-bit halves.
+ */
+void
+split64(Node *n, Node *lo, Node *hi)
+{
+	Node n1;
+	int64 i;
+
+	if(!is64(n->type))
+		fatal("split64 %T", n->type);
+
+	if(nsclean >= nelem(sclean))
+		fatal("split64 clean");
+	sclean[nsclean].op = OEMPTY;
+	nsclean++;
+	switch(n->op) {
+	default:
+		if(!dotaddable(n, &n1)) {
+			igen(n, &n1, N);
+			sclean[nsclean-1] = n1;
+		}
+		n = &n1;
+		goto common;
+	case ONAME:
+		if(n->class == PPARAMREF) {
+			cgen(n->heapaddr, &n1);
+			sclean[nsclean-1] = n1;
+			// fall through.
+			n = &n1;
+		}
+		goto common;
+	case OINDREG:
+	common:
+		*lo = *n;
+		*hi = *n;
+		lo->type = types[TUINT32];
+		if(n->type->etype == TINT64)
+			hi->type = types[TINT32];
+		else
+			hi->type = types[TUINT32];
+		hi->xoffset += 4;
+		break;
+
+	case OLITERAL:
+		convconst(&n1, n->type, &n->val);
+		i = mpgetfix(n1.val.u.xval);
+		nodconst(lo, types[TUINT32], (uint32)i);
+		i >>= 32;
+		if(n->type->etype == TINT64)
+			nodconst(hi, types[TINT32], (int32)i);
+		else
+			nodconst(hi, types[TUINT32], (uint32)i);
+		break;
+	}
+}
+
+void
+splitclean(void)
+{
+	if(nsclean <= 0)
+		fatal("splitclean");
+	nsclean--;
+	if(sclean[nsclean].op != OEMPTY)
+		regfree(&sclean[nsclean]);
+}
+
+/*
+ * set up nodes representing fp constants
+ */
+Node zerof;
+Node two64f;
+Node two63f;
+
+void
+bignodes(void)
+{
+	static int did;
+
+	if(did)
+		return;
+	did = 1;
+
+	two64f = *ncon(0);
+	two64f.type = types[TFLOAT64];
+	two64f.val.ctype = CTFLT;
+	two64f.val.u.fval = mal(sizeof *two64f.val.u.fval);
+	mpmovecflt(two64f.val.u.fval, 18446744073709551616.);
+
+	two63f = two64f;
+	two63f.val.u.fval = mal(sizeof *two63f.val.u.fval);
+	mpmovecflt(two63f.val.u.fval, 9223372036854775808.);
+
+	zerof = two64f;
+	zerof.val.u.fval = mal(sizeof *zerof.val.u.fval);
+	mpmovecflt(zerof.val.u.fval, 0);
+}
+
+void
+memname(Node *n, Type *t)
+{
+	tempname(n, t);
+	strcpy(namebuf, n->sym->name);
+	namebuf[0] = '.';	// keep optimizer from registerizing
+	n->sym = lookup(namebuf);
+	n->orig->sym = n->sym;
+}
+
+static void floatmove(Node *f, Node *t);
+static void floatmove_387(Node *f, Node *t);
+static void floatmove_sse(Node *f, Node *t);
+
+void
+gmove(Node *f, Node *t)
+{
+	int a, ft, tt;
+	Type *cvt;
+	Node r1, r2, flo, fhi, tlo, thi, con;
+
+	if(debug['M'])
+		print("gmove %N -> %N\n", f, t);
+
+	ft = simsimtype(f->type);
+	tt = simsimtype(t->type);
+	cvt = t->type;
+	
+	if(iscomplex[ft] || iscomplex[tt]) {
+		complexmove(f, t);
+		return;
+	}
+	if(isfloat[ft] || isfloat[tt]) {
+		floatmove(f, t);
+		return;
+	}
+
+	// cannot have two integer memory operands;
+	// except 64-bit, which always copies via registers anyway.
+	if(isint[ft] && isint[tt] && !is64(f->type) && !is64(t->type) && ismem(f) && ismem(t))
+		goto hard;
+
+	// convert constant to desired type
+	if(f->op == OLITERAL) {
+		convconst(&con, t->type, &f->val);
+		f = &con;
+		ft = simsimtype(con.type);
+	}
+
+	// value -> value copy, only one memory operand.
+	// figure out the instruction to use.
+	// break out of switch for one-instruction gins.
+	// goto rdst for "destination must be register".
+	// goto hard for "convert to cvt type first".
+	// otherwise handle and return.
+
+	switch(CASE(ft, tt)) {
+	default:
+		goto fatal;
+
+	/*
+	 * integer copy and truncate
+	 */
+	case CASE(TINT8, TINT8):	// same size
+	case CASE(TINT8, TUINT8):
+	case CASE(TUINT8, TINT8):
+	case CASE(TUINT8, TUINT8):
+		a = AMOVB;
+		break;
+
+	case CASE(TINT16, TINT8):	// truncate
+	case CASE(TUINT16, TINT8):
+	case CASE(TINT32, TINT8):
+	case CASE(TUINT32, TINT8):
+	case CASE(TINT16, TUINT8):
+	case CASE(TUINT16, TUINT8):
+	case CASE(TINT32, TUINT8):
+	case CASE(TUINT32, TUINT8):
+		a = AMOVB;
+		goto rsrc;
+
+	case CASE(TINT64, TINT8):	// truncate low word
+	case CASE(TUINT64, TINT8):
+	case CASE(TINT64, TUINT8):
+	case CASE(TUINT64, TUINT8):
+		split64(f, &flo, &fhi);
+		nodreg(&r1, t->type, D_AX);
+		gmove(&flo, &r1);
+		gins(AMOVB, &r1, t);
+		splitclean();
+		return;
+
+	case CASE(TINT16, TINT16):	// same size
+	case CASE(TINT16, TUINT16):
+	case CASE(TUINT16, TINT16):
+	case CASE(TUINT16, TUINT16):
+		a = AMOVW;
+		break;
+
+	case CASE(TINT32, TINT16):	// truncate
+	case CASE(TUINT32, TINT16):
+	case CASE(TINT32, TUINT16):
+	case CASE(TUINT32, TUINT16):
+		a = AMOVW;
+		goto rsrc;
+
+	case CASE(TINT64, TINT16):	// truncate low word
+	case CASE(TUINT64, TINT16):
+	case CASE(TINT64, TUINT16):
+	case CASE(TUINT64, TUINT16):
+		split64(f, &flo, &fhi);
+		nodreg(&r1, t->type, D_AX);
+		gmove(&flo, &r1);
+		gins(AMOVW, &r1, t);
+		splitclean();
+		return;
+
+	case CASE(TINT32, TINT32):	// same size
+	case CASE(TINT32, TUINT32):
+	case CASE(TUINT32, TINT32):
+	case CASE(TUINT32, TUINT32):
+		a = AMOVL;
+		break;
+
+	case CASE(TINT64, TINT32):	// truncate
+	case CASE(TUINT64, TINT32):
+	case CASE(TINT64, TUINT32):
+	case CASE(TUINT64, TUINT32):
+		split64(f, &flo, &fhi);
+		nodreg(&r1, t->type, D_AX);
+		gmove(&flo, &r1);
+		gins(AMOVL, &r1, t);
+		splitclean();
+		return;
+
+	case CASE(TINT64, TINT64):	// same size
+	case CASE(TINT64, TUINT64):
+	case CASE(TUINT64, TINT64):
+	case CASE(TUINT64, TUINT64):
+		split64(f, &flo, &fhi);
+		split64(t, &tlo, &thi);
+		if(f->op == OLITERAL) {
+			gins(AMOVL, &flo, &tlo);
+			gins(AMOVL, &fhi, &thi);
+		} else {
+			nodreg(&r1, t->type, D_AX);
+			nodreg(&r2, t->type, D_DX);
+			gins(AMOVL, &flo, &r1);
+			gins(AMOVL, &fhi, &r2);
+			gins(AMOVL, &r1, &tlo);
+			gins(AMOVL, &r2, &thi);
+		}
+		splitclean();
+		splitclean();
+		return;
+
+	/*
+	 * integer up-conversions
+	 */
+	case CASE(TINT8, TINT16):	// sign extend int8
+	case CASE(TINT8, TUINT16):
+		a = AMOVBWSX;
+		goto rdst;
+	case CASE(TINT8, TINT32):
+	case CASE(TINT8, TUINT32):
+		a = AMOVBLSX;
+		goto rdst;
+	case CASE(TINT8, TINT64):	// convert via int32
+	case CASE(TINT8, TUINT64):
+		cvt = types[TINT32];
+		goto hard;
+
+	case CASE(TUINT8, TINT16):	// zero extend uint8
+	case CASE(TUINT8, TUINT16):
+		a = AMOVBWZX;
+		goto rdst;
+	case CASE(TUINT8, TINT32):
+	case CASE(TUINT8, TUINT32):
+		a = AMOVBLZX;
+		goto rdst;
+	case CASE(TUINT8, TINT64):	// convert via uint32
+	case CASE(TUINT8, TUINT64):
+		cvt = types[TUINT32];
+		goto hard;
+
+	case CASE(TINT16, TINT32):	// sign extend int16
+	case CASE(TINT16, TUINT32):
+		a = AMOVWLSX;
+		goto rdst;
+	case CASE(TINT16, TINT64):	// convert via int32
+	case CASE(TINT16, TUINT64):
+		cvt = types[TINT32];
+		goto hard;
+
+	case CASE(TUINT16, TINT32):	// zero extend uint16
+	case CASE(TUINT16, TUINT32):
+		a = AMOVWLZX;
+		goto rdst;
+	case CASE(TUINT16, TINT64):	// convert via uint32
+	case CASE(TUINT16, TUINT64):
+		cvt = types[TUINT32];
+		goto hard;
+
+	case CASE(TINT32, TINT64):	// sign extend int32
+	case CASE(TINT32, TUINT64):
+		split64(t, &tlo, &thi);
+		nodreg(&flo, tlo.type, D_AX);
+		nodreg(&fhi, thi.type, D_DX);
+		gmove(f, &flo);
+		gins(ACDQ, N, N);
+		gins(AMOVL, &flo, &tlo);
+		gins(AMOVL, &fhi, &thi);
+		splitclean();
+		return;
+
+	case CASE(TUINT32, TINT64):	// zero extend uint32
+	case CASE(TUINT32, TUINT64):
+		split64(t, &tlo, &thi);
+		gmove(f, &tlo);
+		gins(AMOVL, ncon(0), &thi);
+		splitclean();
+		return;
+	}
+
+	gins(a, f, t);
+	return;
+
+rsrc:
+	// requires register source
+	regalloc(&r1, f->type, t);
+	gmove(f, &r1);
+	gins(a, &r1, t);
+	regfree(&r1);
+	return;
+
+rdst:
+	// requires register destination
+	regalloc(&r1, t->type, t);
+	gins(a, f, &r1);
+	gmove(&r1, t);
+	regfree(&r1);
+	return;
+
+hard:
+	// requires register intermediate
+	regalloc(&r1, cvt, t);
+	gmove(f, &r1);
+	gmove(&r1, t);
+	regfree(&r1);
+	return;
+
+fatal:
+	// should not happen
+	fatal("gmove %N -> %N", f, t);
+}
+
+static void
+floatmove(Node *f, Node *t)
+{
+	Node r1, r2, t1, t2, tlo, thi, con, f0, f1, ax, dx, cx;
+	Type *cvt;
+	int ft, tt;
+	Prog *p1, *p2, *p3;
+
+	ft = simsimtype(f->type);
+	tt = simsimtype(t->type);
+	cvt = t->type;
+
+	// cannot have two floating point memory operands.
+	if(isfloat[ft] && isfloat[tt] && ismem(f) && ismem(t))
+		goto hard;
+
+	// convert constant to desired type
+	if(f->op == OLITERAL) {
+		convconst(&con, t->type, &f->val);
+		f = &con;
+		ft = simsimtype(con.type);
+
+		// some constants can't move directly to memory.
+		if(ismem(t)) {
+			// float constants come from memory.
+			if(isfloat[tt])
+				goto hard;
+		}
+	}
+
+	// value -> value copy, only one memory operand.
+	// figure out the instruction to use.
+	// break out of switch for one-instruction gins.
+	// goto rdst for "destination must be register".
+	// goto hard for "convert to cvt type first".
+	// otherwise handle and return.
+
+	switch(CASE(ft, tt)) {
+	default:
+		if(use_sse)
+			floatmove_sse(f, t);
+		else
+			floatmove_387(f, t);
+		return;
+
+	// float to very long integer.
+	case CASE(TFLOAT32, TINT64):
+	case CASE(TFLOAT64, TINT64):
+		if(f->op == OREGISTER) {
+			cvt = f->type;
+			goto hardmem;
+		}
+		nodreg(&r1, types[ft], D_F0);
+		if(ft == TFLOAT32)
+			gins(AFMOVF, f, &r1);
+		else
+			gins(AFMOVD, f, &r1);
+
+		// set round to zero mode during conversion
+		memname(&t1, types[TUINT16]);
+		memname(&t2, types[TUINT16]);
+		gins(AFSTCW, N, &t1);
+		gins(AMOVW, ncon(0xf7f), &t2);
+		gins(AFLDCW, &t2, N);
+		if(tt == TINT16)
+			gins(AFMOVWP, &r1, t);
+		else if(tt == TINT32)
+			gins(AFMOVLP, &r1, t);
+		else
+			gins(AFMOVVP, &r1, t);
+		gins(AFLDCW, &t1, N);
+		return;
+
+	case CASE(TFLOAT32, TUINT64):
+	case CASE(TFLOAT64, TUINT64):
+		if(!ismem(f)) {
+			cvt = f->type;
+			goto hardmem;
+		}
+		bignodes();
+		nodreg(&f0, types[ft], D_F0);
+		nodreg(&f1, types[ft], D_F0 + 1);
+		nodreg(&ax, types[TUINT16], D_AX);
+
+		if(ft == TFLOAT32)
+			gins(AFMOVF, f, &f0);
+		else
+			gins(AFMOVD, f, &f0);
+
+		// if 0 > v { answer = 0 }
+		gins(AFMOVD, &zerof, &f0);
+		gins(AFUCOMIP, &f0, &f1);
+		p1 = gbranch(optoas(OGT, types[tt]), T, 0);
+		// if 1<<64 <= v { answer = 0 too }
+		gins(AFMOVD, &two64f, &f0);
+		gins(AFUCOMIP, &f0, &f1);
+		p2 = gbranch(optoas(OGT, types[tt]), T, 0);
+		patch(p1, pc);
+		gins(AFMOVVP, &f0, t);	// don't care about t, but will pop the stack
+		split64(t, &tlo, &thi);
+		gins(AMOVL, ncon(0), &tlo);
+		gins(AMOVL, ncon(0), &thi);
+		splitclean();
+		p1 = gbranch(AJMP, T, 0);
+		patch(p2, pc);
+
+		// in range; algorithm is:
+		//	if small enough, use native float64 -> int64 conversion.
+		//	otherwise, subtract 2^63, convert, and add it back.
+
+		// set round to zero mode during conversion
+		memname(&t1, types[TUINT16]);
+		memname(&t2, types[TUINT16]);
+		gins(AFSTCW, N, &t1);
+		gins(AMOVW, ncon(0xf7f), &t2);
+		gins(AFLDCW, &t2, N);
+
+		// actual work
+		gins(AFMOVD, &two63f, &f0);
+		gins(AFUCOMIP, &f0, &f1);
+		p2 = gbranch(optoas(OLE, types[tt]), T, 0);
+		gins(AFMOVVP, &f0, t);
+		p3 = gbranch(AJMP, T, 0);
+		patch(p2, pc);
+		gins(AFMOVD, &two63f, &f0);
+		gins(AFSUBDP, &f0, &f1);
+		gins(AFMOVVP, &f0, t);
+		split64(t, &tlo, &thi);
+		gins(AXORL, ncon(0x80000000), &thi);	// + 2^63
+		patch(p3, pc);
+		splitclean();
+		// restore rounding mode
+		gins(AFLDCW, &t1, N);
+
+		patch(p1, pc);
+		return;
+
+	/*
+	 * integer to float
+	 */
+	case CASE(TINT64, TFLOAT32):
+	case CASE(TINT64, TFLOAT64):
+		if(t->op == OREGISTER)
+			goto hardmem;
+		nodreg(&f0, t->type, D_F0);
+		gins(AFMOVV, f, &f0);
+		if(tt == TFLOAT32)
+			gins(AFMOVFP, &f0, t);
+		else
+			gins(AFMOVDP, &f0, t);
+		return;
+
+	case CASE(TUINT64, TFLOAT32):
+	case CASE(TUINT64, TFLOAT64):
+		// algorithm is:
+		//	if small enough, use native int64 -> float64 conversion.
+		//	otherwise, halve (rounding to odd?), convert, and double.
+		nodreg(&ax, types[TUINT32], D_AX);
+		nodreg(&dx, types[TUINT32], D_DX);
+		nodreg(&cx, types[TUINT32], D_CX);
+		tempname(&t1, f->type);
+		split64(&t1, &tlo, &thi);
+		gmove(f, &t1);
+		gins(ACMPL, &thi, ncon(0));
+		p1 = gbranch(AJLT, T, 0);
+		// native
+		nodreg(&r1, types[tt], D_F0);
+		gins(AFMOVV, &t1, &r1);
+		if(tt == TFLOAT32)
+			gins(AFMOVFP, &r1, t);
+		else
+			gins(AFMOVDP, &r1, t);
+		p2 = gbranch(AJMP, T, 0);
+		// simulated
+		patch(p1, pc);
+		gmove(&tlo, &ax);
+		gmove(&thi, &dx);
+		p1 = gins(ASHRL, ncon(1), &ax);
+		p1->from.index = D_DX;	// double-width shift DX -> AX
+		p1->from.scale = 0;
+		gins(AMOVL, ncon(0), &cx);
+		gins(ASETCC, N, &cx);
+		gins(AORL, &cx, &ax);
+		gins(ASHRL, ncon(1), &dx);
+		gmove(&dx, &thi);
+		gmove(&ax, &tlo);
+		nodreg(&r1, types[tt], D_F0);
+		nodreg(&r2, types[tt], D_F0 + 1);
+		gins(AFMOVV, &t1, &r1);
+		gins(AFMOVD, &r1, &r1);
+		gins(AFADDDP, &r1, &r2);
+		if(tt == TFLOAT32)
+			gins(AFMOVFP, &r1, t);
+		else
+			gins(AFMOVDP, &r1, t);
+		patch(p2, pc);
+		splitclean();
+		return;
+	}
+
+hard:
+	// requires register intermediate
+	regalloc(&r1, cvt, t);
+	gmove(f, &r1);
+	gmove(&r1, t);
+	regfree(&r1);
+	return;
+
+hardmem:
+	// requires memory intermediate
+	tempname(&r1, cvt);
+	gmove(f, &r1);
+	gmove(&r1, t);
+	return;
+}
+
+static void
+floatmove_387(Node *f, Node *t)
+{
+	Node r1, t1, t2;
+	Type *cvt;
+	Prog *p1, *p2, *p3;
+	int a, ft, tt;
+
+	ft = simsimtype(f->type);
+	tt = simsimtype(t->type);
+	cvt = t->type;
+
+	switch(CASE(ft, tt)) {
+	default:
+		goto fatal;
+
+	/*
+	* float to integer
+	*/
+	case CASE(TFLOAT32, TINT16):
+	case CASE(TFLOAT32, TINT32):
+	case CASE(TFLOAT32, TINT64):
+	case CASE(TFLOAT64, TINT16):
+	case CASE(TFLOAT64, TINT32):
+	case CASE(TFLOAT64, TINT64):
+		if(t->op == OREGISTER)
+			goto hardmem;
+		nodreg(&r1, types[ft], D_F0);
+		if(f->op != OREGISTER) {
+			if(ft == TFLOAT32)
+				gins(AFMOVF, f, &r1);
+			else
+				gins(AFMOVD, f, &r1);
+		}
+
+		// set round to zero mode during conversion
+		memname(&t1, types[TUINT16]);
+		memname(&t2, types[TUINT16]);
+		gins(AFSTCW, N, &t1);
+		gins(AMOVW, ncon(0xf7f), &t2);
+		gins(AFLDCW, &t2, N);
+		if(tt == TINT16)
+			gins(AFMOVWP, &r1, t);
+		else if(tt == TINT32)
+			gins(AFMOVLP, &r1, t);
+		else
+			gins(AFMOVVP, &r1, t);
+		gins(AFLDCW, &t1, N);
+		return;
+
+	case CASE(TFLOAT32, TINT8):
+	case CASE(TFLOAT32, TUINT16):
+	case CASE(TFLOAT32, TUINT8):
+	case CASE(TFLOAT64, TINT8):
+	case CASE(TFLOAT64, TUINT16):
+	case CASE(TFLOAT64, TUINT8):
+		// convert via int32.
+		tempname(&t1, types[TINT32]);
+		gmove(f, &t1);
+		switch(tt) {
+		default:
+			fatal("gmove %T", t);
+		case TINT8:
+			gins(ACMPL, &t1, ncon(-0x80));
+			p1 = gbranch(optoas(OLT, types[TINT32]), T, -1);
+			gins(ACMPL, &t1, ncon(0x7f));
+			p2 = gbranch(optoas(OGT, types[TINT32]), T, -1);
+			p3 = gbranch(AJMP, T, 0);
+			patch(p1, pc);
+			patch(p2, pc);
+			gmove(ncon(-0x80), &t1);
+			patch(p3, pc);
+			gmove(&t1, t);
+			break;
+		case TUINT8:
+			gins(ATESTL, ncon(0xffffff00), &t1);
+			p1 = gbranch(AJEQ, T, +1);
+			gins(AMOVL, ncon(0), &t1);
+			patch(p1, pc);
+			gmove(&t1, t);
+			break;
+		case TUINT16:
+			gins(ATESTL, ncon(0xffff0000), &t1);
+			p1 = gbranch(AJEQ, T, +1);
+			gins(AMOVL, ncon(0), &t1);
+			patch(p1, pc);
+			gmove(&t1, t);
+			break;
+		}
+		return;
+
+	case CASE(TFLOAT32, TUINT32):
+	case CASE(TFLOAT64, TUINT32):
+		// convert via int64.
+		cvt = types[TINT64];
+		goto hardmem;
+
+	/*
+	 * integer to float
+	 */
+	case CASE(TINT16, TFLOAT32):
+	case CASE(TINT16, TFLOAT64):
+	case CASE(TINT32, TFLOAT32):
+	case CASE(TINT32, TFLOAT64):
+	case CASE(TINT64, TFLOAT32):
+	case CASE(TINT64, TFLOAT64):
+		if(t->op != OREGISTER)
+			goto hard;
+		if(f->op == OREGISTER) {
+			cvt = f->type;
+			goto hardmem;
+		}
+		switch(ft) {
+		case TINT16:
+			a = AFMOVW;
+			break;
+		case TINT32:
+			a = AFMOVL;
+			break;
+		default:
+			a = AFMOVV;
+			break;
+		}
+		break;
+
+	case CASE(TINT8, TFLOAT32):
+	case CASE(TINT8, TFLOAT64):
+	case CASE(TUINT16, TFLOAT32):
+	case CASE(TUINT16, TFLOAT64):
+	case CASE(TUINT8, TFLOAT32):
+	case CASE(TUINT8, TFLOAT64):
+		// convert via int32 memory
+		cvt = types[TINT32];
+		goto hardmem;
+
+	case CASE(TUINT32, TFLOAT32):
+	case CASE(TUINT32, TFLOAT64):
+		// convert via int64 memory
+		cvt = types[TINT64];
+		goto hardmem;
+
+	/*
+	 * float to float
+	 */
+	case CASE(TFLOAT32, TFLOAT32):
+	case CASE(TFLOAT64, TFLOAT64):
+		// The way the code generator uses floating-point
+		// registers, a move from F0 to F0 is intended as a no-op.
+		// On the x86, it's not: it pushes a second copy of F0
+		// on the floating point stack.  So toss it away here.
+		// Also, F0 is the *only* register we ever evaluate
+		// into, so we should only see register/register as F0/F0.
+		if(ismem(f) && ismem(t))
+			goto hard;
+		if(f->op == OREGISTER && t->op == OREGISTER) {
+			if(f->val.u.reg != D_F0 || t->val.u.reg != D_F0)
+				goto fatal;
+			return;
+		}
+		a = AFMOVF;
+		if(ft == TFLOAT64)
+			a = AFMOVD;
+		if(ismem(t)) {
+			if(f->op != OREGISTER || f->val.u.reg != D_F0)
+				fatal("gmove %N", f);
+			a = AFMOVFP;
+			if(ft == TFLOAT64)
+				a = AFMOVDP;
+		}
+		break;
+
+	case CASE(TFLOAT32, TFLOAT64):
+		if(ismem(f) && ismem(t))
+			goto hard;
+		if(f->op == OREGISTER && t->op == OREGISTER) {
+			if(f->val.u.reg != D_F0 || t->val.u.reg != D_F0)
+				goto fatal;
+			return;
+		}
+		if(f->op == OREGISTER)
+			gins(AFMOVDP, f, t);
+		else
+			gins(AFMOVF, f, t);
+		return;
+
+	case CASE(TFLOAT64, TFLOAT32):
+		if(ismem(f) && ismem(t))
+			goto hard;
+		if(f->op == OREGISTER && t->op == OREGISTER) {
+			tempname(&r1, types[TFLOAT32]);
+			gins(AFMOVFP, f, &r1);
+			gins(AFMOVF, &r1, t);
+			return;
+		}
+		if(f->op == OREGISTER)
+			gins(AFMOVFP, f, t);
+		else
+			gins(AFMOVD, f, t);
+		return;
+	}
+
+	gins(a, f, t);
+	return;
+
+hard:
+	// requires register intermediate
+	regalloc(&r1, cvt, t);
+	gmove(f, &r1);
+	gmove(&r1, t);
+	regfree(&r1);
+	return;
+
+hardmem:
+	// requires memory intermediate
+	tempname(&r1, cvt);
+	gmove(f, &r1);
+	gmove(&r1, t);
+	return;
+
+fatal:
+	// should not happen
+	fatal("gmove %lN -> %lN", f, t);
+	return;
+}
+
+static void
+floatmove_sse(Node *f, Node *t)
+{
+	Node r1;
+	Type *cvt;
+	int a, ft, tt;
+
+	ft = simsimtype(f->type);
+	tt = simsimtype(t->type);
+
+	switch(CASE(ft, tt)) {
+	default:
+		// should not happen
+		fatal("gmove %N -> %N", f, t);
+		return;
+	/*
+	* float to integer
+	*/
+	case CASE(TFLOAT32, TINT16):
+	case CASE(TFLOAT32, TINT8):
+	case CASE(TFLOAT32, TUINT16):
+	case CASE(TFLOAT32, TUINT8):
+	case CASE(TFLOAT64, TINT16):
+	case CASE(TFLOAT64, TINT8):
+	case CASE(TFLOAT64, TUINT16):
+	case CASE(TFLOAT64, TUINT8):
+		// convert via int32.
+		cvt = types[TINT32];
+		goto hard;
+
+	case CASE(TFLOAT32, TUINT32):
+	case CASE(TFLOAT64, TUINT32):
+		// convert via int64.
+		cvt = types[TINT64];
+		goto hardmem;
+
+	case CASE(TFLOAT32, TINT32):
+		a = ACVTTSS2SL;
+		goto rdst;
+
+	case CASE(TFLOAT64, TINT32):
+		a = ACVTTSD2SL;
+		goto rdst;
+
+	/*
+	 * integer to float
+	 */
+	case CASE(TINT8, TFLOAT32):
+	case CASE(TINT8, TFLOAT64):
+	case CASE(TINT16, TFLOAT32):
+	case CASE(TINT16, TFLOAT64):
+	case CASE(TUINT16, TFLOAT32):
+	case CASE(TUINT16, TFLOAT64):
+	case CASE(TUINT8, TFLOAT32):
+	case CASE(TUINT8, TFLOAT64):
+		// convert via int32 memory
+		cvt = types[TINT32];
+		goto hard;
+
+	case CASE(TUINT32, TFLOAT32):
+	case CASE(TUINT32, TFLOAT64):
+		// convert via int64 memory
+		cvt = types[TINT64];
+		goto hardmem;
+
+	case CASE(TINT32, TFLOAT32):
+		a = ACVTSL2SS;
+		goto rdst;
+
+	case CASE(TINT32, TFLOAT64):
+		a = ACVTSL2SD;
+		goto rdst;
+
+	/*
+	 * float to float
+	 */
+	case CASE(TFLOAT32, TFLOAT32):
+		a = AMOVSS;
+		break;
+
+	case CASE(TFLOAT64, TFLOAT64):
+		a = AMOVSD;
+		break;
+
+	case CASE(TFLOAT32, TFLOAT64):
+		a = ACVTSS2SD;
+		goto rdst;
+
+	case CASE(TFLOAT64, TFLOAT32):
+		a = ACVTSD2SS;
+		goto rdst;
+	}
+
+	gins(a, f, t);
+	return;
+
+hard:
+	// requires register intermediate
+	regalloc(&r1, cvt, t);
+	gmove(f, &r1);
+	gmove(&r1, t);
+	regfree(&r1);
+	return;
+
+hardmem:
+	// requires memory intermediate
+	tempname(&r1, cvt);
+	gmove(f, &r1);
+	gmove(&r1, t);
+	return;
+
+rdst:
+	// requires register destination
+	regalloc(&r1, t->type, t);
+	gins(a, f, &r1);
+	gmove(&r1, t);
+	regfree(&r1);
+	return;
+}
+
+int
+samaddr(Node *f, Node *t)
+{
+
+	if(f->op != t->op)
+		return 0;
+
+	switch(f->op) {
+	case OREGISTER:
+		if(f->val.u.reg != t->val.u.reg)
+			break;
+		return 1;
+	}
+	return 0;
+}
+/*
+ * generate one instruction:
+ *	as f, t
+ */
+Prog*
+gins(int as, Node *f, Node *t)
+{
+	Prog *p;
+	Addr af, at;
+	int w;
+
+	if(as == AFMOVF && f && f->op == OREGISTER && t && t->op == OREGISTER)
+		fatal("gins MOVF reg, reg");
+	if(as == ACVTSD2SS && f && f->op == OLITERAL)
+		fatal("gins CVTSD2SS const");
+	if(as == AMOVSD && t && t->op == OREGISTER && t->val.u.reg == D_F0)
+		fatal("gins MOVSD into F0");
+
+	switch(as) {
+	case AMOVB:
+	case AMOVW:
+	case AMOVL:
+		if(f != N && t != N && samaddr(f, t))
+			return nil;
+		break;
+	
+	case ALEAL:
+		if(f != N && isconst(f, CTNIL))
+			fatal("gins LEAL nil %T", f->type);
+		break;
+	}
+
+	memset(&af, 0, sizeof af);
+	memset(&at, 0, sizeof at);
+	if(f != N)
+		naddr(f, &af, 1);
+	if(t != N)
+		naddr(t, &at, 1);
+	p = prog(as);
+	if(f != N)
+		p->from = af;
+	if(t != N)
+		p->to = at;
+	if(debug['g'])
+		print("%P\n", p);
+
+	w = 0;
+	switch(as) {
+	case AMOVB:
+		w = 1;
+		break;
+	case AMOVW:
+		w = 2;
+		break;
+	case AMOVL:
+		w = 4;
+		break;
+	}
+
+	if(1 && w != 0 && f != N && (af.width > w || at.width > w)) {
+		dump("bad width from:", f);
+		dump("bad width to:", t);
+		fatal("bad width: %P (%d, %d)\n", p, af.width, at.width);
+	}
+
+	return p;
+}
+
+/*
+ * generate code to compute n;
+ * make a refer to result.
+ */
+void
+naddr(Node *n, Addr *a, int canemitcode)
+{
+	Sym *s;
+
+	a->scale = 0;
+	a->index = D_NONE;
+	a->type = D_NONE;
+	a->gotype = nil;
+	a->node = N;
+	if(n == N)
+		return;
+
+	switch(n->op) {
+	default:
+		fatal("naddr: bad %O %D", n->op, a);
+		break;
+
+	case OREGISTER:
+		a->type = n->val.u.reg;
+		a->sym = nil;
+		break;
+
+	case OINDREG:
+		a->type = n->val.u.reg+D_INDIR;
+		a->sym = linksym(n->sym);
+		a->offset = n->xoffset;
+		break;
+
+	case OPARAM:
+		// n->left is PHEAP ONAME for stack parameter.
+		// compute address of actual parameter on stack.
+		a->etype = n->left->type->etype;
+		a->width = n->left->type->width;
+		a->offset = n->xoffset;
+		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 = nil;
+		break;
+
+	case OCFUNC:
+		naddr(n->left, a, canemitcode);
+		a->sym = linksym(n->left->sym);
+		break;
+
+	case ONAME:
+		a->etype = 0;
+		a->width = 0;
+		if(n->type != T) {
+			a->etype = simtype[n->type->etype];
+			dowidth(n->type);
+			a->width = n->type->width;
+		}
+		a->offset = n->xoffset;
+		s = n->sym;
+		a->node = n->orig;
+		//if(a->node >= (Node*)&n)
+		//	fatal("stack node");
+		if(s == S)
+			s = lookup(".noname");
+		if(n->method) {
+			if(n->type != T)
+			if(n->type->sym != S)
+			if(n->type->sym->pkg != nil)
+				s = pkglookup(s->name, n->type->sym->pkg);
+		}
+
+		switch(n->class) {
+		default:
+			fatal("naddr: ONAME class %S %d\n", n->sym, n->class);
+		case PEXTERN:
+			a->type = D_EXTERN;
+			break;
+		case PAUTO:
+			a->type = D_AUTO;
+			break;
+		case PPARAM:
+		case PPARAMOUT:
+			a->type = D_PARAM;
+			break;
+		case PFUNC:
+			a->index = D_EXTERN;
+			a->type = D_ADDR;
+			s = funcsym(s);
+			break;
+		}
+		a->sym = linksym(s);
+		break;
+
+	case OLITERAL:
+		switch(n->val.ctype) {
+		default:
+			fatal("naddr: const %lT", n->type);
+			break;
+		case CTFLT:
+			a->type = D_FCONST;
+			a->u.dval = mpgetflt(n->val.u.fval);
+			break;
+		case CTINT:
+		case CTRUNE:
+			a->sym = nil;
+			a->type = D_CONST;
+			a->offset = mpgetfix(n->val.u.xval);
+			break;
+		case CTSTR:
+			datagostring(n->val.u.sval, a);
+			break;
+		case CTBOOL:
+			a->sym = nil;
+			a->type = D_CONST;
+			a->offset = n->val.u.bval;
+			break;
+		case CTNIL:
+			a->sym = nil;
+			a->type = D_CONST;
+			a->offset = 0;
+			break;
+		}
+		break;
+
+	case OADDR:
+		naddr(n->left, a, canemitcode);
+		if(a->type >= D_INDIR) {
+			a->type -= D_INDIR;
+			break;
+		}
+		if(a->type == D_EXTERN || a->type == D_STATIC ||
+		   a->type == D_AUTO || a->type == D_PARAM)
+			if(a->index == D_NONE) {
+				a->index = a->type;
+				a->type = D_ADDR;
+				break;
+			}
+		fatal("naddr: OADDR\n");
+	
+	case OITAB:
+		// itable of interface value
+		naddr(n->left, a, canemitcode);
+		if(a->type == D_CONST && a->offset == 0)
+			break;	// len(nil)
+		a->etype = tptr;
+		a->width = widthptr;
+		break;
+
+	case OSPTR:
+		// pointer in a string or slice
+		naddr(n->left, a, canemitcode);
+		if(a->type == D_CONST && a->offset == 0)
+			break;	// ptr(nil)
+		a->etype = simtype[tptr];
+		a->offset += Array_array;
+		a->width = widthptr;
+		break;
+
+	case OLEN:
+		// len of string or slice
+		naddr(n->left, a, canemitcode);
+		if(a->type == D_CONST && a->offset == 0)
+			break;	// len(nil)
+		a->etype = TUINT32;
+		a->offset += Array_nel;
+		a->width = 4;
+		break;
+
+	case OCAP:
+		// cap of string or slice
+		naddr(n->left, a, canemitcode);
+		if(a->type == D_CONST && a->offset == 0)
+			break;	// cap(nil)
+		a->etype = TUINT32;
+		a->offset += Array_cap;
+		a->width = 4;
+		break;
+
+//	case OADD:
+//		if(n->right->op == OLITERAL) {
+//			v = n->right->vconst;
+//			naddr(n->left, a, canemitcode);
+//		} else
+//		if(n->left->op == OLITERAL) {
+//			v = n->left->vconst;
+//			naddr(n->right, a, canemitcode);
+//		} else
+//			goto bad;
+//		a->offset += v;
+//		break;
+
+	}
+}
+
+int
+dotaddable(Node *n, Node *n1)
+{
+	int o;
+	int64 oary[10];
+	Node *nn;
+
+	if(n->op != ODOT)
+		return 0;
+
+	o = dotoffset(n, oary, &nn);
+	if(nn != N && nn->addable && o == 1 && oary[0] >= 0) {
+		*n1 = *nn;
+		n1->type = n->type;
+		n1->xoffset += oary[0];
+		return 1;
+	}
+	return 0;
+}
+
+void
+sudoclean(void)
+{
+}
+
+int
+sudoaddable(int as, Node *n, Addr *a)
+{
+	USED(as);
+	USED(n);
+	USED(a);
+
+	return 0;
+}
diff --git a/src/cmd/8g/opt.h b/src/cmd/8g/opt.h
new file mode 100644
index 0000000..09f58c4
--- /dev/null
+++ b/src/cmd/8g/opt.h
@@ -0,0 +1,238 @@
+// Derived from Inferno utils/6c/gc.h
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/gc.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.
+
+#include	"../gc/popt.h"
+
+#define	Z	N
+#define	Adr	Addr
+
+#define	D_HI	D_NONE
+#define	D_LO	D_NONE
+
+#define	BLOAD(r)	band(bnot(r->refbehind), r->refahead)
+#define	BSTORE(r)	band(bnot(r->calbehind), r->calahead)
+#define	LOAD(r)		(~r->refbehind.b[z] & r->refahead.b[z])
+#define	STORE(r)	(~r->calbehind.b[z] & r->calahead.b[z])
+
+#define	CLOAD	5
+#define	CREF	5
+#define	CINF	1000
+#define	LOOP	3
+
+typedef	struct	Reg	Reg;
+typedef	struct	Rgn	Rgn;
+
+/*c2go
+extern Node *Z;
+enum
+{
+	D_HI = D_NONE,
+	D_LO = D_NONE,
+	CLOAD = 5,
+	CREF = 5,
+	CINF = 1000,
+	LOOP = 3,
+};
+
+uint32 BLOAD(Reg*);
+uint32 BSTORE(Reg*);
+uint32 LOAD(Reg*);
+uint32 STORE(Reg*);
+*/
+
+// A Reg is a wrapper around a single Prog (one instruction) that holds
+// register optimization information while the optimizer runs.
+// r->prog is the instruction.
+// r->prog->opt points back to r.
+struct	Reg
+{
+	Flow	f;
+
+	Bits	set;  		// variables written by this instruction.
+	Bits	use1; 		// variables read by prog->from.
+	Bits	use2; 		// variables read by prog->to.
+
+	Bits	refbehind;
+	Bits	refahead;
+	Bits	calbehind;
+	Bits	calahead;
+	Bits	regdiff;
+	Bits	act;
+
+	int32	regu;		// register used bitmap
+	int32	rpo;		// reverse post ordering
+	int32	active;
+
+	uint16	loop;		// x5 for every loop
+	uchar	refset;		// diagnostic generated
+
+	Reg*	p1;     	// predecessors of this instruction: p1,
+	Reg*	p2;     	// and then p2 linked though p2link.
+	Reg*	p2link;
+	Reg*	s1;     	// successors of this instruction (at most two: s1 and s2).
+	Reg*	s2;
+	Reg*	link;   	// next instruction in function code
+	Prog*	prog;   	// actual instruction
+};
+#define	R	((Reg*)0)
+/*c2go extern Reg *R; */
+
+#define	NRGN	600
+/*c2go enum { NRGN = 600 }; */
+struct	Rgn
+{
+	Reg*	enter;
+	short	cost;
+	short	varno;
+	short	regno;
+};
+
+EXTERN	int32	exregoffset;		// not set
+EXTERN	int32	exfregoffset;		// not set
+EXTERN	Reg	zreg;
+EXTERN	Reg*	freer;
+EXTERN	Reg**	rpo2r;
+EXTERN	Rgn	region[NRGN];
+EXTERN	Rgn*	rgp;
+EXTERN	int	nregion;
+EXTERN	int	nvar;
+EXTERN	int32	regbits;
+EXTERN	int32	exregbits;
+EXTERN	Bits	externs;
+EXTERN	Bits	params;
+EXTERN	Bits	consts;
+EXTERN	Bits	addrs;
+EXTERN	Bits	ivar;
+EXTERN	Bits	ovar;
+EXTERN	int	change;
+EXTERN	int32	maxnr;
+EXTERN	int32*	idom;
+
+EXTERN	struct
+{
+	int32	ncvtreg;
+	int32	nspill;
+	int32	nreload;
+	int32	ndelmov;
+	int32	nvar;
+	int32	naddr;
+} ostats;
+
+/*
+ * reg.c
+ */
+Reg*	rega(void);
+int	rcmp(const void*, const void*);
+void	regopt(Prog*);
+void	addmove(Reg*, int, int, int);
+Bits	mkvar(Reg*, Adr*);
+void	prop(Reg*, Bits, Bits);
+void	loopit(Reg*, int32);
+void	synch(Reg*, Bits);
+uint32	allreg(uint32, Rgn*);
+void	paint1(Reg*, int);
+uint32	paint2(Reg*, int);
+void	paint3(Reg*, int, int32, int);
+void	addreg(Adr*, int);
+void	dumpone(Flow*, int);
+void	dumpit(char*, Flow*, int);
+
+/*
+ * peep.c
+ */
+void	peep(Prog*);
+void	excise(Flow*);
+int	copyu(Prog*, Adr*, Adr*);
+
+int32	RtoB(int);
+int32	FtoB(int);
+int	BtoR(int32);
+int	BtoF(int32);
+
+/*
+ * prog.c
+ */
+typedef struct ProgInfo ProgInfo;
+struct ProgInfo
+{
+	uint32 flags; // the bits below
+	uint32 reguse; // required registers used by this instruction
+	uint32 regset; // required registers set by this instruction
+	uint32 regindex; // registers used by addressing mode
+};
+
+enum
+{
+	// Pseudo-op, like TEXT, GLOBL, TYPE, PCDATA, FUNCDATA.
+	Pseudo = 1<<1,
+	
+	// There's nothing to say about the instruction,
+	// but it's still okay to see.
+	OK = 1<<2,
+
+	// Size of right-side write, or right-side read if no write.
+	SizeB = 1<<3,
+	SizeW = 1<<4,
+	SizeL = 1<<5,
+	SizeQ = 1<<6,
+	SizeF = 1<<7, // float aka float32
+	SizeD = 1<<8, // double aka float64
+
+	// Left side: address taken, read, write.
+	LeftAddr = 1<<9,
+	LeftRead = 1<<10,
+	LeftWrite = 1<<11,
+	
+	// Right side: address taken, read, write.
+	RightAddr = 1<<12,
+	RightRead = 1<<13,
+	RightWrite = 1<<14,
+
+	// Set, use, or kill of carry bit.
+	// Kill means we never look at the carry bit after this kind of instruction.
+	SetCarry = 1<<15,
+	UseCarry = 1<<16,
+	KillCarry = 1<<17,
+
+	// Instruction kinds
+	Move = 1<<18, // straight move
+	Conv = 1<<19, // size conversion
+	Cjmp = 1<<20, // conditional jump
+	Break = 1<<21, // breaks control flow (no fallthrough)
+	Call = 1<<22, // function call
+	Jump = 1<<23, // jump
+	Skip = 1<<24, // data instruction
+
+	// Special cases for register use.
+	ShiftCX = 1<<25, // possible shift by CX
+	ImulAXDX = 1<<26, // possible multiply into DX:AX
+};
+
+void proginfo(ProgInfo*, Prog*);
diff --git a/src/cmd/8g/peep.c b/src/cmd/8g/peep.c
new file mode 100644
index 0000000..91a91d2
--- /dev/null
+++ b/src/cmd/8g/peep.c
@@ -0,0 +1,779 @@
+// Derived from Inferno utils/6c/peep.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/peep.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"
+#include "opt.h"
+
+enum {
+	REGEXT = 0,
+};
+
+static void	conprop(Flow *r);
+static void	elimshortmov(Graph*);
+static int	subprop(Flow*);
+static int	copyprop(Graph*, Flow*);
+static int	copy1(Adr*, Adr*, Flow*, int);
+static int	copyas(Adr*, Adr*);
+static int	copyau(Adr*, Adr*);
+static int	copysub(Adr*, Adr*, Adr*, int);
+
+static uint32	gactive;
+
+// do we need the carry bit
+static int
+needc(Prog *p)
+{
+	ProgInfo info;
+
+	while(p != P) {
+		proginfo(&info, p);
+		if(info.flags & UseCarry)
+			return 1;
+		if(info.flags & (SetCarry|KillCarry))
+			return 0;
+		p = p->link;
+	}
+	return 0;
+}
+
+static Flow*
+rnops(Flow *r)
+{
+	Prog *p;
+	Flow *r1;
+
+	if(r != nil)
+	for(;;) {
+		p = r->prog;
+		if(p->as != ANOP || p->from.type != D_NONE || p->to.type != D_NONE)
+			break;
+		r1 = uniqs(r);
+		if(r1 == nil)
+			break;
+		r = r1;
+	}
+	return r;
+}
+
+void
+peep(Prog *firstp)
+{
+	Flow *r, *r1;
+	Graph *g;
+	Prog *p, *p1;
+	int t;
+
+	g = flowstart(firstp, sizeof(Flow));
+	if(g == nil)
+		return;
+	gactive = 0;
+
+	// byte, word arithmetic elimination.
+	elimshortmov(g);
+
+	// constant propagation
+	// find MOV $con,R followed by
+	// another MOV $con,R without
+	// setting R in the interim
+	for(r=g->start; r!=nil; r=r->link) {
+		p = r->prog;
+		switch(p->as) {
+		case ALEAL:
+			if(regtyp(&p->to))
+			if(p->from.sym != nil)
+			if(p->from.index == D_NONE || p->from.index == D_CONST)
+				conprop(r);
+			break;
+
+		case AMOVB:
+		case AMOVW:
+		case AMOVL:
+		case AMOVSS:
+		case AMOVSD:
+			if(regtyp(&p->to))
+			if(p->from.type == D_CONST)
+				conprop(r);
+			break;
+		}
+	}
+
+loop1:
+	if(debug['P'] && debug['v'])
+		dumpit("loop1", g->start, 0);
+
+	t = 0;
+	for(r=g->start; r!=nil; r=r->link) {
+		p = r->prog;
+		switch(p->as) {
+		case AMOVL:
+		case AMOVSS:
+		case AMOVSD:
+			if(regtyp(&p->to))
+			if(regtyp(&p->from)) {
+				if(copyprop(g, r)) {
+					excise(r);
+					t++;
+				} else
+				if(subprop(r) && copyprop(g, r)) {
+					excise(r);
+					t++;
+				}
+			}
+			break;
+
+		case AMOVBLZX:
+		case AMOVWLZX:
+		case AMOVBLSX:
+		case AMOVWLSX:
+			if(regtyp(&p->to)) {
+				r1 = rnops(uniqs(r));
+				if(r1 != nil) {
+					p1 = r1->prog;
+					if(p->as == p1->as && p->to.type == p1->from.type){
+						p1->as = AMOVL;
+						t++;
+					}
+				}
+			}
+			break;
+
+		case AADDL:
+		case AADDW:
+			if(p->from.type != D_CONST || needc(p->link))
+				break;
+			if(p->from.offset == -1){
+				if(p->as == AADDL)
+					p->as = ADECL;
+				else
+					p->as = ADECW;
+				p->from = zprog.from;
+				break;
+			}
+			if(p->from.offset == 1){
+				if(p->as == AADDL)
+					p->as = AINCL;
+				else
+					p->as = AINCW;
+				p->from = zprog.from;
+				break;
+			}
+			break;
+
+		case ASUBL:
+		case ASUBW:
+			if(p->from.type != D_CONST || needc(p->link))
+				break;
+			if(p->from.offset == -1) {
+				if(p->as == ASUBL)
+					p->as = AINCL;
+				else
+					p->as = AINCW;
+				p->from = zprog.from;
+				break;
+			}
+			if(p->from.offset == 1){
+				if(p->as == ASUBL)
+					p->as = ADECL;
+				else
+					p->as = ADECW;
+				p->from = zprog.from;
+				break;
+			}
+			break;
+		}
+	}
+	if(t)
+		goto loop1;
+
+	// MOVSD removal.
+	// We never use packed registers, so a MOVSD between registers
+	// can be replaced by MOVAPD, which moves the pair of float64s
+	// instead of just the lower one.  We only use the lower one, but
+	// the processor can do better if we do moves using both.
+	for(r=g->start; r!=nil; r=r->link) {
+		p = r->prog;
+		if(p->as == AMOVSD)
+		if(regtyp(&p->from))
+		if(regtyp(&p->to))
+			p->as = AMOVAPD;
+	}
+	
+	flowend(g);
+}
+
+void
+excise(Flow *r)
+{
+	Prog *p;
+
+	p = r->prog;
+	if(debug['P'] && debug['v'])
+		print("%P ===delete===\n", p);
+
+	p->as = ANOP;
+	p->from = zprog.from;
+	p->to = zprog.to;
+
+	ostats.ndelmov++;
+}
+
+int
+regtyp(Adr *a)
+{
+	int t;
+
+	t = a->type;
+	if(t >= D_AX && t <= D_DI)
+		return 1;
+	if(t >= D_X0 && t <= D_X7)
+		return 1;
+	return 0;
+}
+
+// movb elimination.
+// movb is simulated by the linker
+// when a register other than ax, bx, cx, dx
+// is used, so rewrite to other instructions
+// when possible.  a movb into a register
+// can smash the entire 64-bit register without
+// causing any trouble.
+static void
+elimshortmov(Graph *g)
+{
+	Prog *p;
+	Flow *r;
+
+	for(r=g->start; r!=nil; r=r->link) {
+		p = r->prog;
+		if(regtyp(&p->to)) {
+			switch(p->as) {
+			case AINCB:
+			case AINCW:
+				p->as = AINCL;
+				break;
+			case ADECB:
+			case ADECW:
+				p->as = ADECL;
+				break;
+			case ANEGB:
+			case ANEGW:
+				p->as = ANEGL;
+				break;
+			case ANOTB:
+			case ANOTW:
+				p->as = ANOTL;
+				break;
+			}
+			if(regtyp(&p->from) || p->from.type == D_CONST) {
+				// move or artihmetic into partial register.
+				// from another register or constant can be movl.
+				// we don't switch to 32-bit arithmetic if it can
+				// change how the carry bit is set (and the carry bit is needed).
+				switch(p->as) {
+				case AMOVB:
+				case AMOVW:
+					p->as = AMOVL;
+					break;
+				case AADDB:
+				case AADDW:
+					if(!needc(p->link))
+						p->as = AADDL;
+					break;
+				case ASUBB:
+				case ASUBW:
+					if(!needc(p->link))
+						p->as = ASUBL;
+					break;
+				case AMULB:
+				case AMULW:
+					p->as = AMULL;
+					break;
+				case AIMULB:
+				case AIMULW:
+					p->as = AIMULL;
+					break;
+				case AANDB:
+				case AANDW:
+					p->as = AANDL;
+					break;
+				case AORB:
+				case AORW:
+					p->as = AORL;
+					break;
+				case AXORB:
+				case AXORW:
+					p->as = AXORL;
+					break;
+				case ASHLB:
+				case ASHLW:
+					p->as = ASHLL;
+					break;
+				}
+			} else {
+				// explicit zero extension
+				switch(p->as) {
+				case AMOVB:
+					p->as = AMOVBLZX;
+					break;
+				case AMOVW:
+					p->as = AMOVWLZX;
+					break;
+				}
+			}
+		}
+	}
+}
+
+/*
+ * the idea is to substitute
+ * one register for another
+ * from one MOV to another
+ *	MOV	a, R0
+ *	ADD	b, R0	/ no use of R1
+ *	MOV	R0, R1
+ * would be converted to
+ *	MOV	a, R1
+ *	ADD	b, R1
+ *	MOV	R1, R0
+ * hopefully, then the former or latter MOV
+ * will be eliminated by copy propagation.
+ */
+static int
+subprop(Flow *r0)
+{
+	Prog *p;
+	Adr *v1, *v2;
+	Flow *r;
+	int t;
+	ProgInfo info;
+
+	p = r0->prog;
+	v1 = &p->from;
+	if(!regtyp(v1))
+		return 0;
+	v2 = &p->to;
+	if(!regtyp(v2))
+		return 0;
+	for(r=uniqp(r0); r!=nil; r=uniqp(r)) {
+		if(debug['P'] && debug['v'])
+			print("\t? %P\n", r->prog);
+		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;
+
+		if(info.reguse | info.regset)
+			return 0;
+
+		if((info.flags & Move) && (info.flags & (SizeL|SizeQ|SizeF|SizeD)) && p->to.type == v1->type)
+			goto gotit;
+
+		if(copyau(&p->from, v2) || copyau(&p->to, v2))
+			break;
+		if(copysub(&p->from, v1, v2, 0) || copysub(&p->to, v1, v2, 0))
+			break;
+	}
+	return 0;
+
+gotit:
+	copysub(&p->to, v1, v2, 1);
+	if(debug['P']) {
+		print("gotit: %D->%D\n%P", v1, v2, r->prog);
+		if(p->from.type == v2->type)
+			print(" excise");
+		print("\n");
+	}
+	for(r=uniqs(r); r!=r0; r=uniqs(r)) {
+		p = r->prog;
+		copysub(&p->from, v1, v2, 1);
+		copysub(&p->to, v1, v2, 1);
+		if(debug['P'])
+			print("%P\n", r->prog);
+	}
+	t = v1->type;
+	v1->type = v2->type;
+	v2->type = t;
+	if(debug['P'])
+		print("%P last\n", r->prog);
+	return 1;
+}
+
+/*
+ * The idea is to remove redundant copies.
+ *	v1->v2	F=0
+ *	(use v2	s/v2/v1/)*
+ *	set v1	F=1
+ *	use v2	return fail
+ *	-----------------
+ *	v1->v2	F=0
+ *	(use v2	s/v2/v1/)*
+ *	set v1	F=1
+ *	set v2	return success
+ */
+static int
+copyprop(Graph *g, Flow *r0)
+{
+	Prog *p;
+	Adr *v1, *v2;
+
+	USED(g);
+	p = r0->prog;
+	v1 = &p->from;
+	v2 = &p->to;
+	if(copyas(v1, v2))
+		return 1;
+	gactive++;
+	return copy1(v1, v2, r0->s1, 0);
+}
+
+static int
+copy1(Adr *v1, Adr *v2, Flow *r, int f)
+{
+	int t;
+	Prog *p;
+
+	if(r->active == gactive) {
+		if(debug['P'])
+			print("act set; return 1\n");
+		return 1;
+	}
+	r->active = gactive;
+	if(debug['P'])
+		print("copy %D->%D f=%d\n", v1, v2, f);
+	for(; r != nil; r = r->s1) {
+		p = r->prog;
+		if(debug['P'])
+			print("%P", p);
+		if(!f && uniqp(r) == nil) {
+			f = 1;
+			if(debug['P'])
+				print("; merge; f=%d", f);
+		}
+		t = copyu(p, v2, nil);
+		switch(t) {
+		case 2:	/* rar, can't split */
+			if(debug['P'])
+				print("; %D rar; return 0\n", v2);
+			return 0;
+
+		case 3:	/* set */
+			if(debug['P'])
+				print("; %D set; return 1\n", v2);
+			return 1;
+
+		case 1:	/* used, substitute */
+		case 4:	/* use and set */
+			if(f) {
+				if(!debug['P'])
+					return 0;
+				if(t == 4)
+					print("; %D used+set and f=%d; return 0\n", v2, f);
+				else
+					print("; %D used and f=%d; return 0\n", v2, f);
+				return 0;
+			}
+			if(copyu(p, v2, v1)) {
+				if(debug['P'])
+					print("; sub fail; return 0\n");
+				return 0;
+			}
+			if(debug['P'])
+				print("; sub %D/%D", v2, v1);
+			if(t == 4) {
+				if(debug['P'])
+					print("; %D used+set; return 1\n", v2);
+				return 1;
+			}
+			break;
+		}
+		if(!f) {
+			t = copyu(p, v1, nil);
+			if(!f && (t == 2 || t == 3 || t == 4)) {
+				f = 1;
+				if(debug['P'])
+					print("; %D set and !f; f=%d", v1, f);
+			}
+		}
+		if(debug['P'])
+			print("\n");
+		if(r->s2)
+			if(!copy1(v1, v2, r->s2, f))
+				return 0;
+	}
+	return 1;
+}
+
+/*
+ * return
+ * 1 if v only used (and substitute),
+ * 2 if read-alter-rewrite
+ * 3 if set
+ * 4 if set and used
+ * 0 otherwise (not touched)
+ */
+int
+copyu(Prog *p, Adr *v, Adr *s)
+{
+	ProgInfo info;
+
+	switch(p->as) {
+	case AJMP:
+		if(s != nil) {
+			if(copysub(&p->to, v, s, 1))
+				return 1;
+			return 0;
+		}
+		if(copyau(&p->to, v))
+			return 1;
+		return 0;
+
+	case ARET:
+		if(s != nil)
+			return 1;
+		return 3;
+
+	case ACALL:
+		if(REGEXT && v->type <= REGEXT && v->type > exregoffset)
+			return 2;
+		if(REGARG >= 0 && v->type == (uchar)REGARG)
+			return 2;
+		if(v->type == p->from.type)
+			return 2;
+
+		if(s != nil) {
+			if(copysub(&p->to, v, s, 1))
+				return 1;
+			return 0;
+		}
+		if(copyau(&p->to, v))
+			return 4;
+		return 3;
+
+	case ATEXT:
+		if(REGARG >= 0 && v->type == (uchar)REGARG)
+			return 3;
+		return 0;
+	}
+
+	if(p->as == AVARDEF || p->as == AVARKILL)
+		return 0;
+	proginfo(&info, p);
+
+	if((info.reguse|info.regset) & RtoB(v->type))
+		return 2;
+		
+	if(info.flags & LeftAddr)
+		if(copyas(&p->from, v))
+			return 2;
+
+	if((info.flags & (RightRead|RightWrite)) == (RightRead|RightWrite))
+		if(copyas(&p->to, v))
+			return 2;
+	
+	if(info.flags & RightWrite) {
+		if(copyas(&p->to, v)) {
+			if(s != nil)
+				return copysub(&p->from, v, s, 1);
+			if(copyau(&p->from, v))
+				return 4;
+			return 3;
+		}
+	}
+	
+	if(info.flags & (LeftAddr|LeftRead|LeftWrite|RightAddr|RightRead|RightWrite)) {
+		if(s != nil) {
+			if(copysub(&p->from, v, s, 1))
+				return 1;
+			return copysub(&p->to, v, s, 1);
+		}
+		if(copyau(&p->from, v))
+			return 1;
+		if(copyau(&p->to, v))
+			return 1;
+	}
+
+	return 0;
+}
+
+/*
+ * direct reference,
+ * could be set/use depending on
+ * semantics
+ */
+static int
+copyas(Adr *a, Adr *v)
+{
+	if(D_AL <= a->type && a->type <= D_BL)
+		fatal("use of byte register");
+	if(D_AL <= v->type && v->type <= D_BL)
+		fatal("use of byte register");
+
+	if(a->type != v->type)
+		return 0;
+	if(regtyp(v))
+		return 1;
+	if(v->type == D_AUTO || v->type == D_PARAM)
+		if(v->offset == a->offset)
+			return 1;
+	return 0;
+}
+
+int
+sameaddr(Addr *a, Addr *v)
+{
+	if(a->type != v->type)
+		return 0;
+	if(regtyp(v))
+		return 1;
+	if(v->type == D_AUTO || v->type == D_PARAM)
+		if(v->offset == a->offset)
+			return 1;
+	return 0;
+}
+
+/*
+ * either direct or indirect
+ */
+static int
+copyau(Adr *a, Adr *v)
+{
+
+	if(copyas(a, v))
+		return 1;
+	if(regtyp(v)) {
+		if(a->type-D_INDIR == v->type)
+			return 1;
+		if(a->index == v->type)
+			return 1;
+	}
+	return 0;
+}
+
+/*
+ * substitute s for v in a
+ * return failure to substitute
+ */
+static int
+copysub(Adr *a, Adr *v, Adr *s, int f)
+{
+	int t;
+
+	if(copyas(a, v)) {
+		t = s->type;
+		if(t >= D_AX && t <= D_DI || t >= D_X0 && t <= D_X7) {
+			if(f)
+				a->type = t;
+		}
+		return 0;
+	}
+	if(regtyp(v)) {
+		t = v->type;
+		if(a->type == t+D_INDIR) {
+			if((s->type == D_BP) && a->index != D_NONE)
+				return 1;	/* can't use BP-base with index */
+			if(f)
+				a->type = s->type+D_INDIR;
+//			return 0;
+		}
+		if(a->index == t) {
+			if(f)
+				a->index = s->type;
+			return 0;
+		}
+		return 0;
+	}
+	return 0;
+}
+
+static void
+conprop(Flow *r0)
+{
+	Flow *r;
+	Prog *p, *p0;
+	int t;
+	Adr *v0;
+
+	p0 = r0->prog;
+	v0 = &p0->to;
+	r = r0;
+
+loop:
+	r = uniqs(r);
+	if(r == nil || r == r0)
+		return;
+	if(uniqp(r) == nil)
+		return;
+
+	p = r->prog;
+	t = copyu(p, v0, nil);
+	switch(t) {
+	case 0:	// miss
+	case 1:	// use
+		goto loop;
+
+	case 2:	// rar
+	case 4:	// use and set
+		break;
+
+	case 3:	// set
+		if(p->as == p0->as)
+		if(p->from.type == p0->from.type)
+		if(p->from.node == p0->from.node)
+		if(p->from.offset == p0->from.offset)
+		if(p->from.scale == p0->from.scale)
+		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;
+		}
+		break;
+	}
+}
+
+int
+smallindir(Addr *a, Addr *reg)
+{
+	return regtyp(reg) &&
+		a->type == D_INDIR + reg->type &&
+		a->index == D_NONE &&
+		0 <= a->offset && a->offset < 4096;
+}
+
+int
+stackaddr(Addr *a)
+{
+	return regtyp(a) && a->type == D_SP;
+}
diff --git a/src/cmd/8g/prog.c b/src/cmd/8g/prog.c
new file mode 100644
index 0000000..8eed67f
--- /dev/null
+++ b/src/cmd/8g/prog.c
@@ -0,0 +1,349 @@
+// 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 "gg.h"
+#include "opt.h"
+
+// Matches real RtoB but can be used in global initializer.
+#define RtoB(r) (1<<((r)-D_AX))
+
+enum {
+	AX = RtoB(D_AX),
+	BX = RtoB(D_BX),
+	CX = RtoB(D_CX),
+	DX = RtoB(D_DX),
+	DI = RtoB(D_DI),
+	SI = RtoB(D_SI),
+	
+	LeftRdwr = LeftRead | LeftWrite,
+	RightRdwr = RightRead | RightWrite,
+};
+
+#undef RtoB
+
+// This table gives the basic information about instruction
+// generated by the compiler and processed in the optimizer.
+// See opt.h for bit definitions.
+//
+// Instructions not generated need not be listed.
+// As an exception to that rule, we typically write down all the
+// size variants of an operation even if we just use a subset.
+//
+// The table is formatted for 8-space tabs.
+static ProgInfo progtable[ALAST] = {
+	[ATYPE]=	{Pseudo | Skip},
+	[ATEXT]=	{Pseudo},
+	[AFUNCDATA]=	{Pseudo},
+	[APCDATA]=	{Pseudo},
+	[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.
+	[ANOP]=		{LeftRead | RightWrite},
+
+	[AADCL]=	{SizeL | LeftRead | RightRdwr | SetCarry | UseCarry},
+	[AADCW]=	{SizeW | LeftRead | RightRdwr | SetCarry | UseCarry},
+
+	[AADDB]=	{SizeB | LeftRead | RightRdwr | SetCarry},
+	[AADDL]=	{SizeL | LeftRead | RightRdwr | SetCarry},
+	[AADDW]=	{SizeW | LeftRead | RightRdwr | SetCarry},
+	
+	[AADDSD]=	{SizeD | LeftRead | RightRdwr},
+	[AADDSS]=	{SizeF | LeftRead | RightRdwr},
+
+	[AANDB]=	{SizeB | LeftRead | RightRdwr | SetCarry},
+	[AANDL]=	{SizeL | LeftRead | RightRdwr | SetCarry},
+	[AANDW]=	{SizeW | LeftRead | RightRdwr | SetCarry},
+
+	[ACALL]=	{RightAddr | Call | KillCarry},
+
+	[ACDQ]=		{OK, AX, AX | DX},
+	[ACWD]=		{OK, AX, AX | DX},
+
+	[ACLD]=		{OK},
+	[ASTD]=		{OK},
+
+	[ACMPB]=	{SizeB | LeftRead | RightRead | SetCarry},
+	[ACMPL]=	{SizeL | LeftRead | RightRead | SetCarry},
+	[ACMPW]=	{SizeW | LeftRead | RightRead | SetCarry},
+
+	[ACOMISD]=	{SizeD | LeftRead | RightRead | SetCarry},
+	[ACOMISS]=	{SizeF | LeftRead | RightRead | SetCarry},
+
+	[ACVTSD2SL]=	{SizeL | LeftRead | RightWrite | Conv},
+	[ACVTSD2SS]=	{SizeF | LeftRead | RightWrite | Conv},
+	[ACVTSL2SD]=	{SizeD | LeftRead | RightWrite | Conv},
+	[ACVTSL2SS]=	{SizeF | LeftRead | RightWrite | Conv},
+	[ACVTSS2SD]=	{SizeD | LeftRead | RightWrite | Conv},
+	[ACVTSS2SL]=	{SizeL | LeftRead | RightWrite | Conv},
+	[ACVTTSD2SL]=	{SizeL | LeftRead | RightWrite | Conv},
+	[ACVTTSS2SL]=	{SizeL | LeftRead | RightWrite | Conv},
+
+	[ADECB]=	{SizeB | RightRdwr},
+	[ADECL]=	{SizeL | RightRdwr},
+	[ADECW]=	{SizeW | RightRdwr},
+
+	[ADIVB]=	{SizeB | LeftRead | SetCarry, AX, AX},
+	[ADIVL]=	{SizeL | LeftRead | SetCarry, AX|DX, AX|DX},
+	[ADIVW]=	{SizeW | LeftRead | SetCarry, AX|DX, AX|DX},
+
+	[ADIVSD]=	{SizeD | LeftRead | RightRdwr},
+	[ADIVSS]=	{SizeF | LeftRead | RightRdwr},
+	
+	[AFLDCW]=	{SizeW | LeftAddr},
+	[AFSTCW]=	{SizeW | RightAddr},
+
+	[AFSTSW]=	{SizeW | RightAddr | RightWrite},
+
+	[AFADDD]=	{SizeD | LeftAddr | RightRdwr},
+	[AFADDDP]=	{SizeD | LeftAddr | RightRdwr},
+	[AFADDF]=	{SizeF | LeftAddr | RightRdwr},
+
+	[AFCOMD]=	{SizeD | LeftAddr | RightRead},
+	[AFCOMDP]=	{SizeD | LeftAddr | RightRead},
+	[AFCOMDPP]=	{SizeD | LeftAddr | RightRead},
+	[AFCOMF]=	{SizeF | LeftAddr | RightRead},
+	[AFCOMFP]=	{SizeF | LeftAddr | RightRead},
+	[AFUCOMIP]=	{SizeF | LeftAddr | RightRead},
+
+	[AFCHS]=	{SizeD | RightRdwr}, // also SizeF
+
+	[AFDIVDP]=	{SizeD | LeftAddr | RightRdwr},
+	[AFDIVF]=	{SizeF | LeftAddr | RightRdwr},
+	[AFDIVD]=	{SizeD | LeftAddr | RightRdwr},
+
+	[AFDIVRDP]=	{SizeD | LeftAddr | RightRdwr},
+	[AFDIVRF]=	{SizeF | LeftAddr | RightRdwr},
+	[AFDIVRD]=	{SizeD | LeftAddr | RightRdwr},
+
+	[AFXCHD]=	{SizeD | LeftRdwr | RightRdwr},
+
+	[AFSUBD]=	{SizeD | LeftAddr | RightRdwr},
+	[AFSUBDP]=	{SizeD | LeftAddr | RightRdwr},
+	[AFSUBF]=	{SizeF | LeftAddr | RightRdwr},
+	[AFSUBRD]=	{SizeD | LeftAddr | RightRdwr},
+	[AFSUBRDP]=	{SizeD | LeftAddr | RightRdwr},
+	[AFSUBRF]=	{SizeF | LeftAddr | RightRdwr},
+
+	[AFMOVD]=	{SizeD | LeftAddr | RightWrite},
+	[AFMOVF]=	{SizeF | LeftAddr | RightWrite},
+	[AFMOVL]=	{SizeL | LeftAddr | RightWrite},
+	[AFMOVW]=	{SizeW | LeftAddr | RightWrite},
+	[AFMOVV]=	{SizeQ | LeftAddr | RightWrite},
+
+	// 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},
+	[AFMULF]=	{SizeF | LeftAddr | RightRdwr},
+
+	[AIDIVB]=	{SizeB | LeftRead | SetCarry, AX, AX},
+	[AIDIVL]=	{SizeL | LeftRead | SetCarry, AX|DX, AX|DX},
+	[AIDIVW]=	{SizeW | LeftRead | SetCarry, AX|DX, AX|DX},
+
+	[AIMULB]=	{SizeB | LeftRead | SetCarry, AX, AX},
+	[AIMULL]=	{SizeL | LeftRead | ImulAXDX | SetCarry},
+	[AIMULW]=	{SizeW | LeftRead | ImulAXDX | SetCarry},
+
+	[AINCB]=	{SizeB | RightRdwr},
+	[AINCL]=	{SizeL | RightRdwr},
+	[AINCW]=	{SizeW | RightRdwr},
+
+	[AJCC]=		{Cjmp | UseCarry},
+	[AJCS]=		{Cjmp | UseCarry},
+	[AJEQ]=		{Cjmp | UseCarry},
+	[AJGE]=		{Cjmp | UseCarry},
+	[AJGT]=		{Cjmp | UseCarry},
+	[AJHI]=		{Cjmp | UseCarry},
+	[AJLE]=		{Cjmp | UseCarry},
+	[AJLS]=		{Cjmp | UseCarry},
+	[AJLT]=		{Cjmp | UseCarry},
+	[AJMI]=		{Cjmp | UseCarry},
+	[AJNE]=		{Cjmp | UseCarry},
+	[AJOC]=		{Cjmp | UseCarry},
+	[AJOS]=		{Cjmp | UseCarry},
+	[AJPC]=		{Cjmp | UseCarry},
+	[AJPL]=		{Cjmp | UseCarry},
+	[AJPS]=		{Cjmp | UseCarry},
+
+	[AJMP]=		{Jump | Break | KillCarry},
+
+	[ALEAL]=	{LeftAddr | RightWrite},
+
+	[AMOVBLSX]=	{SizeL | LeftRead | RightWrite | Conv},
+	[AMOVBLZX]=	{SizeL | LeftRead | RightWrite | Conv},
+	[AMOVBWSX]=	{SizeW | LeftRead | RightWrite | Conv},
+	[AMOVBWZX]=	{SizeW | LeftRead | RightWrite | Conv},
+	[AMOVWLSX]=	{SizeL | LeftRead | RightWrite | Conv},
+	[AMOVWLZX]=	{SizeL | LeftRead | RightWrite | Conv},
+
+	[AMOVB]=	{SizeB | LeftRead | RightWrite | Move},
+	[AMOVL]=	{SizeL | LeftRead | RightWrite | Move},
+	[AMOVW]=	{SizeW | LeftRead | RightWrite | Move},
+
+	[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},
+
+	// We use MOVAPD as a faster synonym for MOVSD.
+	[AMOVAPD]=	{SizeD | LeftRead | RightWrite | Move},
+
+	[AMULB]=	{SizeB | LeftRead | SetCarry, AX, AX},
+	[AMULL]=	{SizeL | LeftRead | SetCarry, AX, AX|DX},
+	[AMULW]=	{SizeW | LeftRead | SetCarry, AX, AX|DX},
+	
+	[AMULSD]=	{SizeD | LeftRead | RightRdwr},
+	[AMULSS]=	{SizeF | LeftRead | RightRdwr},
+
+	[ANEGB]=	{SizeB | RightRdwr | SetCarry},
+	[ANEGL]=	{SizeL | RightRdwr | SetCarry},
+	[ANEGW]=	{SizeW | RightRdwr | SetCarry},
+
+	[ANOTB]=	{SizeB | RightRdwr},
+	[ANOTL]=	{SizeL | RightRdwr},
+	[ANOTW]=	{SizeW | RightRdwr},
+
+	[AORB]=		{SizeB | LeftRead | RightRdwr | SetCarry},
+	[AORL]=		{SizeL | LeftRead | RightRdwr | SetCarry},
+	[AORW]=		{SizeW | LeftRead | RightRdwr | SetCarry},
+
+	[APOPL]=	{SizeL | RightWrite},
+	[APUSHL]=	{SizeL | LeftRead},
+
+	[ARCLB]=	{SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry | UseCarry},
+	[ARCLL]=	{SizeL | LeftRead | RightRdwr | ShiftCX | SetCarry | UseCarry},
+	[ARCLW]=	{SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry | UseCarry},
+
+	[ARCRB]=	{SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry | UseCarry},
+	[ARCRL]=	{SizeL | LeftRead | RightRdwr | ShiftCX | SetCarry | UseCarry},
+	[ARCRW]=	{SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry | UseCarry},
+
+	[AREP]=		{OK, CX, CX},
+	[AREPN]=	{OK, CX, CX},
+
+	[ARET]=		{Break | KillCarry},
+
+	[AROLB]=	{SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry},
+	[AROLL]=	{SizeL | LeftRead | RightRdwr | ShiftCX | SetCarry},
+	[AROLW]=	{SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry},
+
+	[ARORB]=	{SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry},
+	[ARORL]=	{SizeL | LeftRead | RightRdwr | ShiftCX | SetCarry},
+	[ARORW]=	{SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry},
+
+	[ASAHF]=	{OK, AX, AX},
+
+	[ASALB]=	{SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry},
+	[ASALL]=	{SizeL | LeftRead | RightRdwr | ShiftCX | SetCarry},
+	[ASALW]=	{SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry},
+
+	[ASARB]=	{SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry},
+	[ASARL]=	{SizeL | LeftRead | RightRdwr | ShiftCX | SetCarry},
+	[ASARW]=	{SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry},
+
+	[ASBBB]=	{SizeB | LeftRead | RightRdwr | SetCarry | UseCarry},
+	[ASBBL]=	{SizeL | LeftRead | RightRdwr | SetCarry | UseCarry},
+	[ASBBW]=	{SizeW | LeftRead | RightRdwr | SetCarry | UseCarry},
+
+	[ASETCC]=	{SizeB | RightRdwr | UseCarry},
+	[ASETCS]=	{SizeB | RightRdwr | UseCarry},
+	[ASETEQ]=	{SizeB | RightRdwr | UseCarry},
+	[ASETGE]=	{SizeB | RightRdwr | UseCarry},
+	[ASETGT]=	{SizeB | RightRdwr | UseCarry},
+	[ASETHI]=	{SizeB | RightRdwr | UseCarry},
+	[ASETLE]=	{SizeB | RightRdwr | UseCarry},
+	[ASETLS]=	{SizeB | RightRdwr | UseCarry},
+	[ASETLT]=	{SizeB | RightRdwr | UseCarry},
+	[ASETMI]=	{SizeB | RightRdwr | UseCarry},
+	[ASETNE]=	{SizeB | RightRdwr | UseCarry},
+	[ASETOC]=	{SizeB | RightRdwr | UseCarry},
+	[ASETOS]=	{SizeB | RightRdwr | UseCarry},
+	[ASETPC]=	{SizeB | RightRdwr | UseCarry},
+	[ASETPL]=	{SizeB | RightRdwr | UseCarry},
+	[ASETPS]=	{SizeB | RightRdwr | UseCarry},
+
+	[ASHLB]=	{SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry},
+	[ASHLL]=	{SizeL | LeftRead | RightRdwr | ShiftCX | SetCarry},
+	[ASHLW]=	{SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry},
+
+	[ASHRB]=	{SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry},
+	[ASHRL]=	{SizeL | LeftRead | RightRdwr | ShiftCX | SetCarry},
+	[ASHRW]=	{SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry},
+
+	[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},
+	[ASUBW]=	{SizeW | LeftRead | RightRdwr | SetCarry},
+
+	[ASUBSD]=	{SizeD | LeftRead | RightRdwr},
+	[ASUBSS]=	{SizeF | LeftRead | RightRdwr},
+
+	[ATESTB]=	{SizeB | LeftRead | RightRead | SetCarry},
+	[ATESTL]=	{SizeL | LeftRead | RightRead | SetCarry},
+	[ATESTW]=	{SizeW | LeftRead | RightRead | SetCarry},
+
+	[AUCOMISD]=	{SizeD | LeftRead | RightRead},
+	[AUCOMISS]=	{SizeF | LeftRead | RightRead},
+
+	[AXCHGB]=	{SizeB | LeftRdwr | RightRdwr},
+	[AXCHGL]=	{SizeL | LeftRdwr | RightRdwr},
+	[AXCHGW]=	{SizeW | LeftRdwr | RightRdwr},
+
+	[AXORB]=	{SizeB | LeftRead | RightRdwr | SetCarry},
+	[AXORL]=	{SizeL | LeftRead | RightRdwr | SetCarry},
+	[AXORW]=	{SizeW | LeftRead | RightRdwr | SetCarry},
+};
+
+void
+proginfo(ProgInfo *info, Prog *p)
+{
+	*info = progtable[p->as];
+	if(info->flags == 0)
+		fatal("unknown instruction %P", p);
+
+	if((info->flags & ShiftCX) && p->from.type != D_CONST)
+		info->reguse |= CX;
+
+	if(info->flags & ImulAXDX) {
+		if(p->to.type == D_NONE) {
+			info->reguse |= AX;
+			info->regset |= AX | DX;
+		} else {
+			info->flags |= RightRdwr;
+		}
+	}
+
+	// Addressing makes some registers used.
+	if(p->from.type >= D_INDIR)
+		info->regindex |= RtoB(p->from.type-D_INDIR);
+	if(p->from.index != D_NONE)
+		info->regindex |= RtoB(p->from.index);
+	if(p->to.type >= D_INDIR)
+		info->regindex |= RtoB(p->to.type-D_INDIR);
+	if(p->to.index != D_NONE)
+		info->regindex |= RtoB(p->to.index);
+}
diff --git a/src/cmd/8g/reg.c b/src/cmd/8g/reg.c
new file mode 100644
index 0000000..302b273
--- /dev/null
+++ b/src/cmd/8g/reg.c
@@ -0,0 +1,1284 @@
+// Derived from Inferno utils/6c/reg.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/reg.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"
+#include "opt.h"
+
+#define	NREGVAR	16	/* 8 integer + 8 floating */
+#define	REGBITS	((uint32)0xffff)
+/*c2go enum {
+	NREGVAR = 16,
+	REGBITS = (1<<NREGVAR) - 1,
+};
+*/
+
+static	Reg*	firstr;
+static	int	first	= 1;
+
+int
+rcmp(const void *a1, const void *a2)
+{
+	Rgn *p1, *p2;
+	int c1, c2;
+
+	p1 = (Rgn*)a1;
+	p2 = (Rgn*)a2;
+	c1 = p2->cost;
+	c2 = p1->cost;
+	if(c1 -= c2)
+		return c1;
+	return p2->varno - p1->varno;
+}
+
+static void
+setaddrs(Bits bit)
+{
+	int i, n;
+	Var *v;
+	Node *node;
+
+	while(bany(&bit)) {
+		// convert each bit to a variable
+		i = bnum(bit);
+		node = var[i].node;
+		n = var[i].name;
+		bit.b[i/32] &= ~(1L<<(i%32));
+
+		// disable all pieces of that variable
+		for(i=0; i<nvar; i++) {
+			v = var+i;
+			if(v->node == node && v->name == n)
+				v->addr = 2;
+		}
+	}
+}
+
+static char* regname[] = {
+	".ax", ".cx", ".dx", ".bx", ".sp", ".bp", ".si", ".di",
+	".x0", ".x1", ".x2", ".x3", ".x4", ".x5", ".x6", ".x7",
+};
+
+static Node* regnodes[NREGVAR];
+
+static void walkvardef(Node *n, Reg *r, int active);
+
+void
+regopt(Prog *firstp)
+{
+	Reg *r, *r1;
+	Prog *p;
+	Graph *g;
+	ProgInfo info;
+	int i, z, active;
+	uint32 vreg;
+	Bits bit;
+
+	if(first) {
+		fmtinstall('Q', Qconv);
+		exregoffset = D_DI;	// no externals
+		first = 0;
+	}
+
+	mergetemp(firstp);
+
+	/*
+	 * control flow is more complicated in generated go code
+	 * than in generated c code.  define pseudo-variables for
+	 * registers, so we have complete register usage information.
+	 */
+	nvar = NREGVAR;
+	memset(var, 0, NREGVAR*sizeof var[0]);
+	for(i=0; i<NREGVAR; i++) {
+		if(regnodes[i] == N)
+			regnodes[i] = newname(lookup(regname[i]));
+		var[i].node = regnodes[i];
+	}
+
+	regbits = RtoB(D_SP);
+	for(z=0; z<BITS; z++) {
+		externs.b[z] = 0;
+		params.b[z] = 0;
+		consts.b[z] = 0;
+		addrs.b[z] = 0;
+		ivar.b[z] = 0;
+		ovar.b[z] = 0;
+	}
+
+	/*
+	 * pass 1
+	 * build aux data structure
+	 * allocate pcs
+	 * find use and set of variables
+	 */
+	g = flowstart(firstp, sizeof(Reg));
+	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.
+		if(p->as == ACALL && p->to.type == D_EXTERN)
+			continue;
+
+		r->use1.b[0] |= info.reguse | info.regindex;
+		r->set.b[0] |= info.regset;
+
+		bit = mkvar(r, &p->from);
+		if(bany(&bit)) {
+			if(info.flags & LeftAddr)
+				setaddrs(bit);
+			if(info.flags & LeftRead)
+				for(z=0; z<BITS; z++)
+					r->use1.b[z] |= bit.b[z];
+			if(info.flags & LeftWrite)
+				for(z=0; z<BITS; z++)
+					r->set.b[z] |= bit.b[z];
+		}
+
+		bit = mkvar(r, &p->to);
+		if(bany(&bit)) {	
+			if(info.flags & RightAddr)
+				setaddrs(bit);
+			if(info.flags & RightRead)
+				for(z=0; z<BITS; z++)
+					r->use2.b[z] |= bit.b[z];
+			if(info.flags & RightWrite)
+				for(z=0; z<BITS; z++)
+					r->set.b[z] |= bit.b[z];
+		}
+	}
+	if(firstr == R)
+		return;
+
+	for(i=0; i<nvar; i++) {
+		Var *v = var+i;
+		if(v->addr) {
+			bit = blsh(i);
+			for(z=0; z<BITS; z++)
+				addrs.b[z] |= bit.b[z];
+		}
+
+		if(debug['R'] && debug['v'])
+			print("bit=%2d addr=%d et=%-6E w=%-2d s=%N + %lld\n",
+				i, v->addr, v->etype, v->width, v->node, v->offset);
+	}
+
+	if(debug['R'] && debug['v'])
+		dumpit("pass1", &firstr->f, 1);
+
+	/*
+	 * pass 2
+	 * find looping structure
+	 */
+	flowrpo(g);
+
+	if(debug['R'] && debug['v'])
+		dumpit("pass2", &firstr->f, 1);
+
+	/*
+	 * pass 2.5
+	 * iterate propagating fat vardef covering forward
+	 * r->act records vars with a VARDEF since the last CALL.
+	 * (r->act will be reused in pass 5 for something else,
+	 * but we'll be done with it by then.)
+	 */
+	active = 0;
+	for(r = firstr; r != R; r = (Reg*)r->f.link) {
+		r->f.active = 0;
+		r->act = zbits;
+	}
+	for(r = firstr; r != R; r = (Reg*)r->f.link) {
+		p = r->f.prog;
+		if(p->as == AVARDEF && isfat(p->to.node->type) && p->to.node->opt != nil) {
+			active++;
+			walkvardef(p->to.node, r, active);
+		}
+	}
+
+	/*
+	 * pass 3
+	 * iterate propagating usage
+	 * 	back until flow graph is complete
+	 */
+loop1:
+	change = 0;
+	for(r = firstr; r != R; r = (Reg*)r->f.link)
+		r->f.active = 0;
+	for(r = firstr; r != R; r = (Reg*)r->f.link)
+		if(r->f.prog->as == ARET)
+			prop(r, zbits, zbits);
+loop11:
+	/* pick up unreachable code */
+	i = 0;
+	for(r = firstr; r != R; r = r1) {
+		r1 = (Reg*)r->f.link;
+		if(r1 && r1->f.active && !r->f.active) {
+			prop(r, zbits, zbits);
+			i = 1;
+		}
+	}
+	if(i)
+		goto loop11;
+	if(change)
+		goto loop1;
+
+	if(debug['R'] && debug['v'])
+		dumpit("pass3", &firstr->f, 1);
+
+	/*
+	 * pass 4
+	 * iterate propagating register/variable synchrony
+	 * 	forward until graph is complete
+	 */
+loop2:
+	change = 0;
+	for(r = firstr; r != R; r = (Reg*)r->f.link)
+		r->f.active = 0;
+	synch(firstr, zbits);
+	if(change)
+		goto loop2;
+
+	if(debug['R'] && debug['v'])
+		dumpit("pass4", &firstr->f, 1);
+
+	/*
+	 * pass 4.5
+	 * move register pseudo-variables into regu.
+	 */
+	for(r = firstr; r != R; r = (Reg*)r->f.link) {
+		r->regu = (r->refbehind.b[0] | r->set.b[0]) & REGBITS;
+
+		r->set.b[0] &= ~REGBITS;
+		r->use1.b[0] &= ~REGBITS;
+		r->use2.b[0] &= ~REGBITS;
+		r->refbehind.b[0] &= ~REGBITS;
+		r->refahead.b[0] &= ~REGBITS;
+		r->calbehind.b[0] &= ~REGBITS;
+		r->calahead.b[0] &= ~REGBITS;
+		r->regdiff.b[0] &= ~REGBITS;
+		r->act.b[0] &= ~REGBITS;
+	}
+
+	/*
+	 * pass 5
+	 * isolate regions
+	 * calculate costs (paint1)
+	 */
+	r = firstr;
+	if(r) {
+		for(z=0; z<BITS; z++)
+			bit.b[z] = (r->refahead.b[z] | r->calahead.b[z]) &
+			  ~(externs.b[z] | params.b[z] | addrs.b[z] | consts.b[z]);
+		if(bany(&bit) && !r->f.refset) {
+			// should never happen - all variables are preset
+			if(debug['w'])
+				print("%L: used and not set: %Q\n", r->f.prog->lineno, bit);
+			r->f.refset = 1;
+		}
+	}
+	for(r = firstr; r != R; r = (Reg*)r->f.link)
+		r->act = zbits;
+	rgp = region;
+	nregion = 0;
+	for(r = firstr; r != R; r = (Reg*)r->f.link) {
+		for(z=0; z<BITS; z++)
+			bit.b[z] = r->set.b[z] &
+			  ~(r->refahead.b[z] | r->calahead.b[z] | addrs.b[z]);
+		if(bany(&bit) && !r->f.refset) {
+			if(debug['w'])
+				print("%L: set and not used: %Q\n", r->f.prog->lineno, bit);
+			r->f.refset = 1;
+			excise(&r->f);
+		}
+		for(z=0; z<BITS; z++)
+			bit.b[z] = LOAD(r) & ~(r->act.b[z] | addrs.b[z]);
+		while(bany(&bit)) {
+			i = bnum(bit);
+			rgp->enter = r;
+			rgp->varno = i;
+			change = 0;
+			paint1(r, i);
+			bit.b[i/32] &= ~(1L<<(i%32));
+			if(change <= 0)
+				continue;
+			rgp->cost = change;
+			nregion++;
+			if(nregion >= NRGN) {
+				if(debug['R'] && debug['v'])
+					print("too many regions\n");
+				goto brk;
+			}
+			rgp++;
+		}
+	}
+brk:
+	qsort(region, nregion, sizeof(region[0]), rcmp);
+
+	/*
+	 * pass 6
+	 * determine used registers (paint2)
+	 * replace code (paint3)
+	 */
+	rgp = region;
+	for(i=0; i<nregion; i++) {
+		bit = blsh(rgp->varno);
+		vreg = paint2(rgp->enter, rgp->varno);
+		vreg = allreg(vreg, rgp);
+		if(rgp->regno != 0)
+			paint3(rgp->enter, rgp->varno, vreg, rgp->regno);
+		rgp++;
+	}
+
+	if(debug['R'] && debug['v'])
+		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
+	 */
+	if(!debug['R'] || debug['P'])
+		peep(firstp);
+
+	/*
+	 * eliminate nops
+	 */
+	for(p=firstp; p!=P; p=p->link) {
+		while(p->link != P && p->link->as == ANOP)
+			p->link = p->link->link;
+		if(p->to.type == D_BRANCH)
+			while(p->to.u.branch != P && p->to.u.branch->as == ANOP)
+				p->to.u.branch = p->to.u.branch->link;
+	}
+
+	if(!use_sse)
+	for(p=firstp; p!=P; p=p->link) {
+		if(p->from.type >= D_X0 && p->from.type <= D_X7)
+			fatal("invalid use of %R with GO386=387: %P", p->from.type, p);
+		if(p->to.type >= D_X0 && p->to.type <= D_X7)
+			fatal("invalid use of %R with GO386=387: %P", p->to.type, p);
+	}
+
+	if(debug['R']) {
+		if(ostats.ncvtreg ||
+		   ostats.nspill ||
+		   ostats.nreload ||
+		   ostats.ndelmov ||
+		   ostats.nvar ||
+		   ostats.naddr ||
+		   0)
+			print("\nstats\n");
+
+		if(ostats.ncvtreg)
+			print("	%4d cvtreg\n", ostats.ncvtreg);
+		if(ostats.nspill)
+			print("	%4d spill\n", ostats.nspill);
+		if(ostats.nreload)
+			print("	%4d reload\n", ostats.nreload);
+		if(ostats.ndelmov)
+			print("	%4d delmov\n", ostats.ndelmov);
+		if(ostats.nvar)
+			print("	%4d var\n", ostats.nvar);
+		if(ostats.naddr)
+			print("	%4d addr\n", ostats.naddr);
+
+		memset(&ostats, 0, sizeof(ostats));
+	}
+}
+
+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
+ */
+void
+addmove(Reg *r, int bn, int rn, int f)
+{
+	Prog *p, *p1;
+	Adr *a;
+	Var *v;
+
+	p1 = mal(sizeof(*p1));
+	clearp(p1);
+	p1->pc = 9999;
+
+	p = r->f.prog;
+	p1->link = p->link;
+	p->link = p1;
+	p1->lineno = p->lineno;
+
+	v = var + bn;
+
+	a = &p1->to;
+	a->offset = v->offset;
+	a->etype = v->etype;
+	a->type = v->name;
+	a->node = v->node;
+	a->sym = linksym(v->node->sym);
+
+	// need to clean this up with wptr and
+	// some of the defaults
+	p1->as = AMOVL;
+	switch(v->etype) {
+	default:
+		fatal("unknown type %E", v->etype);
+	case TINT8:
+	case TUINT8:
+	case TBOOL:
+		p1->as = AMOVB;
+		break;
+	case TINT16:
+	case TUINT16:
+		p1->as = AMOVW;
+		break;
+	case TFLOAT32:
+		p1->as = AMOVSS;
+		break;
+	case TFLOAT64:
+		p1->as = AMOVSD;
+		break;
+	case TINT:
+	case TUINT:
+	case TINT32:
+	case TUINT32:
+	case TPTR32:
+		break;
+	}
+
+	p1->from.type = rn;
+	if(!f) {
+		p1->from = *a;
+		*a = zprog.from;
+		a->type = rn;
+		if(v->etype == TUINT8)
+			p1->as = AMOVB;
+		if(v->etype == TUINT16)
+			p1->as = AMOVW;
+	}
+	if(debug['R'] && debug['v'])
+		print("%P ===add=== %P\n", p, p1);
+	ostats.nspill++;
+}
+
+uint32
+doregbits(int r)
+{
+	uint32 b;
+
+	b = 0;
+	if(r >= D_INDIR)
+		r -= D_INDIR;
+	if(r >= D_AX && r <= D_DI)
+		b |= RtoB(r);
+	else
+	if(r >= D_AL && r <= D_BL)
+		b |= RtoB(r-D_AL+D_AX);
+	else
+	if(r >= D_AH && r <= D_BH)
+		b |= RtoB(r-D_AH+D_AX);
+	else
+	if(r >= D_X0 && r <= D_X0+7)
+		b |= FtoB(r);
+	return b;
+}
+
+static int
+overlap(int32 o1, int w1, int32 o2, int w2)
+{
+	int32 t1, t2;
+
+	t1 = o1+w1;
+	t2 = o2+w2;
+
+	if(!(t1 > o2 && t2 > o1))
+		return 0;
+
+	return 1;
+}
+
+Bits
+mkvar(Reg *r, Adr *a)
+{
+	Var *v;
+	int i, t, n, et, z, w, flag, regu;
+	int32 o;
+	Bits bit;
+	Node *node;
+
+	/*
+	 * mark registers used
+	 */
+	t = a->type;
+	if(t == D_NONE)
+		goto none;
+
+	if(r != R)
+		r->use1.b[0] |= doregbits(a->index);
+
+	switch(t) {
+	default:
+		regu = doregbits(t);
+		if(regu == 0)
+			goto none;
+		bit = zbits;
+		bit.b[0] = regu;
+		return bit;
+
+	case D_ADDR:
+		a->type = a->index;
+		bit = mkvar(r, a);
+		setaddrs(bit);
+		a->type = t;
+		ostats.naddr++;
+		goto none;
+
+	case D_EXTERN:
+	case D_STATIC:
+	case D_PARAM:
+	case D_AUTO:
+		n = t;
+		break;
+	}
+
+	node = a->node;
+	if(node == N || node->op != ONAME || node->orig == N)
+		goto none;
+	node = node->orig;
+	if(node->orig != node)
+		fatal("%D: bad node", a);
+	if(node->sym == S || node->sym->name[0] == '.')
+		goto none;
+	et = a->etype;
+	o = a->offset;
+	w = a->width;
+	if(w < 0)
+		fatal("bad width %d for %D", w, a);
+
+	flag = 0;
+	for(i=0; i<nvar; i++) {
+		v = var+i;
+		if(v->node == node && v->name == n) {
+			if(v->offset == o)
+			if(v->etype == et)
+			if(v->width == w)
+				return blsh(i);
+
+			// if they overlap, disable both
+			if(overlap(v->offset, v->width, o, w)) {
+				if(debug['R'])
+					print("disable %s\n", node->sym->name);
+				v->addr = 1;
+				flag = 1;
+			}
+		}
+	}
+
+	switch(et) {
+	case 0:
+	case TFUNC:
+		goto none;
+	}
+
+	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;
+	}
+
+	i = nvar;
+	nvar++;
+	v = var+i;
+	v->offset = o;
+	v->name = n;
+	v->etype = et;
+	v->width = w;
+	v->addr = flag;		// funny punning
+	v->node = node;
+	
+	// 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++)
+			externs.b[z] |= bit.b[z];
+	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;
+
+none:
+	return zbits;
+}
+
+void
+prop(Reg *r, Bits ref, Bits cal)
+{
+	Reg *r1, *r2;
+	int z, i, j;
+	Var *v, *v1;
+
+	for(r1 = r; r1 != R; r1 = (Reg*)r1->f.p1) {
+		for(z=0; z<BITS; z++) {
+			ref.b[z] |= r1->refahead.b[z];
+			if(ref.b[z] != r1->refahead.b[z]) {
+				r1->refahead.b[z] = ref.b[z];
+				change++;
+			}
+			cal.b[z] |= r1->calahead.b[z];
+			if(cal.b[z] != r1->calahead.b[z]) {
+				r1->calahead.b[z] = cal.b[z];
+				change++;
+			}
+		}
+		switch(r1->f.prog->as) {
+		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] | 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:
+			for(z=0; z<BITS; z++) {
+				cal.b[z] = 0;
+				ref.b[z] = 0;
+			}
+			break;
+
+		case ARET:
+			for(z=0; z<BITS; z++) {
+				cal.b[z] = externs.b[z] | ovar.b[z];
+				ref.b[z] = 0;
+			}
+			break;
+		}
+		for(z=0; z<BITS; z++) {
+			ref.b[z] = (ref.b[z] & ~r1->set.b[z]) |
+				r1->use1.b[z] | r1->use2.b[z];
+			cal.b[z] &= ~(r1->set.b[z] | r1->use1.b[z] | r1->use2.b[z]);
+			r1->refbehind.b[z] = ref.b[z];
+			r1->calbehind.b[z] = cal.b[z];
+		}
+		if(r1->f.active)
+			break;
+		r1->f.active = 1;
+	}
+	for(; r != r1; r = (Reg*)r->f.p1)
+		for(r2 = (Reg*)r->f.p2; r2 != R; r2 = (Reg*)r2->f.p2link)
+			prop(r2, r->refbehind, r->calbehind);
+}
+
+void
+synch(Reg *r, Bits dif)
+{
+	Reg *r1;
+	int z;
+
+	for(r1 = r; r1 != R; r1 = (Reg*)r1->f.s1) {
+		for(z=0; z<BITS; z++) {
+			dif.b[z] = (dif.b[z] &
+				~(~r1->refbehind.b[z] & r1->refahead.b[z])) |
+					r1->set.b[z] | r1->regdiff.b[z];
+			if(dif.b[z] != r1->regdiff.b[z]) {
+				r1->regdiff.b[z] = dif.b[z];
+				change++;
+			}
+		}
+		if(r1->f.active)
+			break;
+		r1->f.active = 1;
+		for(z=0; z<BITS; z++)
+			dif.b[z] &= ~(~r1->calbehind.b[z] & r1->calahead.b[z]);
+		if((Reg*)r1->f.s2 != R)
+			synch((Reg*)r1->f.s2, dif);
+	}
+}
+
+uint32
+allreg(uint32 b, Rgn *r)
+{
+	Var *v;
+	int i;
+
+	v = var + r->varno;
+	r->regno = 0;
+	switch(v->etype) {
+
+	default:
+		fatal("unknown etype %d/%E", bitno(b), v->etype);
+		break;
+
+	case TINT8:
+	case TUINT8:
+	case TINT16:
+	case TUINT16:
+	case TINT32:
+	case TUINT32:
+	case TINT64:
+	case TINT:
+	case TUINT:
+	case TUINTPTR:
+	case TBOOL:
+	case TPTR32:
+		i = BtoR(~b);
+		if(i && r->cost > 0) {
+			r->regno = i;
+			return RtoB(i);
+		}
+		break;
+
+	case TFLOAT32:
+	case TFLOAT64:
+		if(!use_sse)
+			break;
+		i = BtoF(~b);
+		if(i && r->cost > 0) {
+			r->regno = i;
+			return FtoB(i);
+		}
+		break;
+	}
+	return 0;
+}
+
+void
+paint1(Reg *r, int bn)
+{
+	Reg *r1;
+	Prog *p;
+	int z;
+	uint32 bb;
+
+	z = bn/32;
+	bb = 1L<<(bn%32);
+	if(r->act.b[z] & bb)
+		return;
+	for(;;) {
+		if(!(r->refbehind.b[z] & bb))
+			break;
+		r1 = (Reg*)r->f.p1;
+		if(r1 == R)
+			break;
+		if(!(r1->refahead.b[z] & bb))
+			break;
+		if(r1->act.b[z] & bb)
+			break;
+		r = r1;
+	}
+
+	if(LOAD(r) & ~(r->set.b[z]&~(r->use1.b[z]|r->use2.b[z])) & bb) {
+		change -= CLOAD * r->f.loop;
+	}
+	for(;;) {
+		r->act.b[z] |= bb;
+		p = r->f.prog;
+
+		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) {
+			change -= CLOAD * r->f.loop;
+			if(p->as == AFMOVL || p->as == AFMOVW)
+				if(BtoR(bb) != D_F0)
+					change = -CINF;
+		}
+
+		if(r->refbehind.b[z] & bb)
+			for(r1 = (Reg*)r->f.p2; r1 != R; r1 = (Reg*)r1->f.p2link)
+				if(r1->refahead.b[z] & bb)
+					paint1(r1, bn);
+
+		if(!(r->refahead.b[z] & bb))
+			break;
+		r1 = (Reg*)r->f.s2;
+		if(r1 != R)
+			if(r1->refbehind.b[z] & bb)
+				paint1(r1, bn);
+		r = (Reg*)r->f.s1;
+		if(r == R)
+			break;
+		if(r->act.b[z] & bb)
+			break;
+		if(!(r->refbehind.b[z] & bb))
+			break;
+	}
+}
+
+uint32
+regset(Reg *r, uint32 bb)
+{
+	uint32 b, set;
+	Adr v;
+	int c;
+
+	set = 0;
+	v = zprog.from;
+	while(b = bb & ~(bb-1)) {
+		v.type = b & 0xFF ? BtoR(b): BtoF(b);
+		c = copyu(r->f.prog, &v, nil);
+		if(c == 3)
+			set |= b;
+		bb &= ~b;
+	}
+	return set;
+}
+
+uint32
+reguse(Reg *r, uint32 bb)
+{
+	uint32 b, set;
+	Adr v;
+	int c;
+
+	set = 0;
+	v = zprog.from;
+	while(b = bb & ~(bb-1)) {
+		v.type = b & 0xFF ? BtoR(b): BtoF(b);
+		c = copyu(r->f.prog, &v, nil);
+		if(c == 1 || c == 2 || c == 4)
+			set |= b;
+		bb &= ~b;
+	}
+	return set;
+}
+
+uint32
+paint2(Reg *r, int bn)
+{
+	Reg *r1;
+	int z;
+	uint32 bb, vreg, x;
+
+	z = bn/32;
+	bb = 1L << (bn%32);
+	vreg = regbits;
+	if(!(r->act.b[z] & bb))
+		return vreg;
+	for(;;) {
+		if(!(r->refbehind.b[z] & bb))
+			break;
+		r1 = (Reg*)r->f.p1;
+		if(r1 == R)
+			break;
+		if(!(r1->refahead.b[z] & bb))
+			break;
+		if(!(r1->act.b[z] & bb))
+			break;
+		r = r1;
+	}
+	for(;;) {
+		r->act.b[z] &= ~bb;
+
+		vreg |= r->regu;
+
+		if(r->refbehind.b[z] & bb)
+			for(r1 = (Reg*)r->f.p2; r1 != R; r1 = (Reg*)r1->f.p2link)
+				if(r1->refahead.b[z] & bb)
+					vreg |= paint2(r1, bn);
+
+		if(!(r->refahead.b[z] & bb))
+			break;
+		r1 = (Reg*)r->f.s2;
+		if(r1 != R)
+			if(r1->refbehind.b[z] & bb)
+				vreg |= paint2(r1, bn);
+		r = (Reg*)r->f.s1;
+		if(r == R)
+			break;
+		if(!(r->act.b[z] & bb))
+			break;
+		if(!(r->refbehind.b[z] & bb))
+			break;
+	}
+
+	bb = vreg;
+	for(; r; r=(Reg*)r->f.s1) {
+		x = r->regu & ~bb;
+		if(x) {
+			vreg |= reguse(r, x);
+			bb |= regset(r, x);
+		}
+	}
+	return vreg;
+}
+
+void
+paint3(Reg *r, int bn, int32 rb, int rn)
+{
+	Reg *r1;
+	Prog *p;
+	int z;
+	uint32 bb;
+
+	z = bn/32;
+	bb = 1L << (bn%32);
+	if(r->act.b[z] & bb)
+		return;
+	for(;;) {
+		if(!(r->refbehind.b[z] & bb))
+			break;
+		r1 = (Reg*)r->f.p1;
+		if(r1 == R)
+			break;
+		if(!(r1->refahead.b[z] & bb))
+			break;
+		if(r1->act.b[z] & bb)
+			break;
+		r = r1;
+	}
+
+	if(LOAD(r) & ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z])) & bb)
+		addmove(r, bn, rn, 0);
+	for(;;) {
+		r->act.b[z] |= bb;
+		p = r->f.prog;
+
+		if(r->use1.b[z] & bb) {
+			if(debug['R'] && debug['v'])
+				print("%P", p);
+			addreg(&p->from, rn);
+			if(debug['R'] && debug['v'])
+				print(" ===change== %P\n", p);
+		}
+		if((r->use2.b[z]|r->set.b[z]) & bb) {
+			if(debug['R'] && debug['v'])
+				print("%P", p);
+			addreg(&p->to, rn);
+			if(debug['R'] && debug['v'])
+				print(" ===change== %P\n", p);
+		}
+
+		if(STORE(r) & r->regdiff.b[z] & bb)
+			addmove(r, bn, rn, 1);
+		r->regu |= rb;
+
+		if(r->refbehind.b[z] & bb)
+			for(r1 = (Reg*)r->f.p2; r1 != R; r1 = (Reg*)r1->f.p2link)
+				if(r1->refahead.b[z] & bb)
+					paint3(r1, bn, rb, rn);
+
+		if(!(r->refahead.b[z] & bb))
+			break;
+		r1 = (Reg*)r->f.s2;
+		if(r1 != R)
+			if(r1->refbehind.b[z] & bb)
+				paint3(r1, bn, rb, rn);
+		r = (Reg*)r->f.s1;
+		if(r == R)
+			break;
+		if(r->act.b[z] & bb)
+			break;
+		if(!(r->refbehind.b[z] & bb))
+			break;
+	}
+}
+
+void
+addreg(Adr *a, int rn)
+{
+	a->sym = nil;
+	a->node = nil;
+	a->offset = 0;
+	a->type = rn;
+
+	ostats.ncvtreg++;
+}
+
+int32
+RtoB(int r)
+{
+
+	if(r < D_AX || r > D_DI)
+		return 0;
+	return 1L << (r-D_AX);
+}
+
+int
+BtoR(int32 b)
+{
+
+	b &= 0xffL;
+	if(b == 0)
+		return 0;
+	return bitno(b) + D_AX;
+}
+
+int32
+FtoB(int f)
+{
+	if(f < D_X0 || f > D_X7)
+		return 0;
+	return 1L << (f - D_X0 + 8);
+}
+
+int
+BtoF(int32 b)
+{
+	b &= 0xFF00L;
+	if(b == 0)
+		return 0;
+	return bitno(b) - 8 + D_X0;
+}
+
+void
+dumpone(Flow *f, int isreg)
+{
+	int z;
+	Bits bit;
+	Reg *r;
+
+	print("%d:%P", f->loop, f->prog);
+	if(isreg) {
+		r = (Reg*)f;
+		for(z=0; z<BITS; z++)
+			bit.b[z] =
+				r->set.b[z] |
+				r->use1.b[z] |
+				r->use2.b[z] |
+				r->refbehind.b[z] |
+				r->refahead.b[z] |
+				r->calbehind.b[z] |
+				r->calahead.b[z] |
+				r->regdiff.b[z] |
+				r->act.b[z] |
+					0;
+		if(bany(&bit)) {
+			print("\t");
+			if(bany(&r->set))
+				print(" s:%Q", r->set);
+			if(bany(&r->use1))
+				print(" u1:%Q", r->use1);
+			if(bany(&r->use2))
+				print(" u2:%Q", r->use2);
+			if(bany(&r->refbehind))
+				print(" rb:%Q ", r->refbehind);
+			if(bany(&r->refahead))
+				print(" ra:%Q ", r->refahead);
+			if(bany(&r->calbehind))
+				print(" cb:%Q ", r->calbehind);
+			if(bany(&r->calahead))
+				print(" ca:%Q ", r->calahead);
+			if(bany(&r->regdiff))
+				print(" d:%Q ", r->regdiff);
+			if(bany(&r->act))
+				print(" a:%Q ", r->act);
+		}
+	}
+	print("\n");
+}
+
+void
+dumpit(char *str, Flow *r0, int isreg)
+{
+	Flow *r, *r1;
+
+	print("\n%s\n", str);
+	for(r = r0; r != nil; r = r->link) {
+		dumpone(r, isreg);
+		r1 = r->p2;
+		if(r1 != nil) {
+			print("	pred:");
+			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", (int)r1->prog->pc);
+//			print("\n");
+//		}
+	}
+}
diff --git a/src/cmd/8l/8.out.h b/src/cmd/8l/8.out.h
new file mode 100644
index 0000000..ed54f67
--- /dev/null
+++ b/src/cmd/8l/8.out.h
@@ -0,0 +1,676 @@
+// Inferno utils/8c/8.out.h
+// http://code.google.com/p/inferno-os/source/browse/utils/8c/8.out.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.
+
+#define	NSYM	50
+#define	NSNAME	8
+#include "../ld/textflag.h"
+
+enum
+{
+	AXXX,
+	AAAA,
+	AAAD,
+	AAAM,
+	AAAS,
+	AADCB,
+	AADCL,
+	AADCW,
+	AADDB,
+	AADDL,
+	AADDW,
+	AADJSP,
+	AANDB,
+	AANDL,
+	AANDW,
+	AARPL,
+	ABOUNDL,
+	ABOUNDW,
+	ABSFL,
+	ABSFW,
+	ABSRL,
+	ABSRW,
+	ABTL,
+	ABTW,
+	ABTCL,
+	ABTCW,
+	ABTRL,
+	ABTRW,
+	ABTSL,
+	ABTSW,
+	ABYTE,
+	ACALL,
+	ACLC,
+	ACLD,
+	ACLI,
+	ACLTS,
+	ACMC,
+	ACMPB,
+	ACMPL,
+	ACMPW,
+	ACMPSB,
+	ACMPSL,
+	ACMPSW,
+	ADAA,
+	ADAS,
+	ADATA,
+	ADECB,
+	ADECL,
+	ADECW,
+	ADIVB,
+	ADIVL,
+	ADIVW,
+	AENTER,
+	AGLOBL,
+	AGOK,
+	AHISTORY,
+	AHLT,
+	AIDIVB,
+	AIDIVL,
+	AIDIVW,
+	AIMULB,
+	AIMULL,
+	AIMULW,
+	AINB,
+	AINL,
+	AINW,
+	AINCB,
+	AINCL,
+	AINCW,
+	AINSB,
+	AINSL,
+	AINSW,
+	AINT,
+	AINTO,
+	AIRETL,
+	AIRETW,
+	AJCC,
+	AJCS,
+	AJCXZL,
+	AJCXZW,
+	AJEQ,
+	AJGE,
+	AJGT,
+	AJHI,
+	AJLE,
+	AJLS,
+	AJLT,
+	AJMI,
+	AJMP,
+	AJNE,
+	AJOC,
+	AJOS,
+	AJPC,
+	AJPL,
+	AJPS,
+	ALAHF,
+	ALARL,
+	ALARW,
+	ALEAL,
+	ALEAW,
+	ALEAVEL,
+	ALEAVEW,
+	ALOCK,
+	ALODSB,
+	ALODSL,
+	ALODSW,
+	ALONG,
+	ALOOP,
+	ALOOPEQ,
+	ALOOPNE,
+	ALSLL,
+	ALSLW,
+	AMOVB,
+	AMOVL,
+	AMOVW,
+	AMOVQ,
+	AMOVBLSX,
+	AMOVBLZX,
+	AMOVBWSX,
+	AMOVBWZX,
+	AMOVWLSX,
+	AMOVWLZX,
+	AMOVSB,
+	AMOVSL,
+	AMOVSW,
+	AMULB,
+	AMULL,
+	AMULW,
+	ANAME,
+	ANEGB,
+	ANEGL,
+	ANEGW,
+	ANOP,
+	ANOTB,
+	ANOTL,
+	ANOTW,
+	AORB,
+	AORL,
+	AORW,
+	AOUTB,
+	AOUTL,
+	AOUTW,
+	AOUTSB,
+	AOUTSL,
+	AOUTSW,
+	APAUSE,
+	APOPAL,
+	APOPAW,
+	APOPFL,
+	APOPFW,
+	APOPL,
+	APOPW,
+	APUSHAL,
+	APUSHAW,
+	APUSHFL,
+	APUSHFW,
+	APUSHL,
+	APUSHW,
+	ARCLB,
+	ARCLL,
+	ARCLW,
+	ARCRB,
+	ARCRL,
+	ARCRW,
+	AREP,
+	AREPN,
+	ARET,
+	AROLB,
+	AROLL,
+	AROLW,
+	ARORB,
+	ARORL,
+	ARORW,
+	ASAHF,
+	ASALB,
+	ASALL,
+	ASALW,
+	ASARB,
+	ASARL,
+	ASARW,
+	ASBBB,
+	ASBBL,
+	ASBBW,
+	ASCASB,
+	ASCASL,
+	ASCASW,
+	ASETCC,
+	ASETCS,
+	ASETEQ,
+	ASETGE,
+	ASETGT,
+	ASETHI,
+	ASETLE,
+	ASETLS,
+	ASETLT,
+	ASETMI,
+	ASETNE,
+	ASETOC,
+	ASETOS,
+	ASETPC,
+	ASETPL,
+	ASETPS,
+	ACDQ,
+	ACWD,
+	ASHLB,
+	ASHLL,
+	ASHLW,
+	ASHRB,
+	ASHRL,
+	ASHRW,
+	ASTC,
+	ASTD,
+	ASTI,
+	ASTOSB,
+	ASTOSL,
+	ASTOSW,
+	ASUBB,
+	ASUBL,
+	ASUBW,
+	ASYSCALL,
+	ATESTB,
+	ATESTL,
+	ATESTW,
+	ATEXT,
+	AVERR,
+	AVERW,
+	AWAIT,
+	AWORD,
+	AXCHGB,
+	AXCHGL,
+	AXCHGW,
+	AXLAT,
+	AXORB,
+	AXORL,
+	AXORW,
+
+	AFMOVB,
+	AFMOVBP,
+	AFMOVD,
+	AFMOVDP,
+	AFMOVF,
+	AFMOVFP,
+	AFMOVL,
+	AFMOVLP,
+	AFMOVV,
+	AFMOVVP,
+	AFMOVW,
+	AFMOVWP,
+	AFMOVX,
+	AFMOVXP,
+
+	AFCOMB,
+	AFCOMBP,
+	AFCOMD,
+	AFCOMDP,
+	AFCOMDPP,
+	AFCOMF,
+	AFCOMFP,
+	AFCOMI,
+	AFCOMIP,
+	AFCOML,
+	AFCOMLP,
+	AFCOMW,
+	AFCOMWP,
+	AFUCOM,
+	AFUCOMI,
+	AFUCOMIP,
+	AFUCOMP,
+	AFUCOMPP,
+
+	AFADDDP,
+	AFADDW,
+	AFADDL,
+	AFADDF,
+	AFADDD,
+
+	AFMULDP,
+	AFMULW,
+	AFMULL,
+	AFMULF,
+	AFMULD,
+
+	AFSUBDP,
+	AFSUBW,
+	AFSUBL,
+	AFSUBF,
+	AFSUBD,
+
+	AFSUBRDP,
+	AFSUBRW,
+	AFSUBRL,
+	AFSUBRF,
+	AFSUBRD,
+
+	AFDIVDP,
+	AFDIVW,
+	AFDIVL,
+	AFDIVF,
+	AFDIVD,
+
+	AFDIVRDP,
+	AFDIVRW,
+	AFDIVRL,
+	AFDIVRF,
+	AFDIVRD,
+
+	AFXCHD,
+	AFFREE,
+
+	AFLDCW,
+	AFLDENV,
+	AFRSTOR,
+	AFSAVE,
+	AFSTCW,
+	AFSTENV,
+	AFSTSW,
+
+	AF2XM1,
+	AFABS,
+	AFCHS,
+	AFCLEX,
+	AFCOS,
+	AFDECSTP,
+	AFINCSTP,
+	AFINIT,
+	AFLD1,
+	AFLDL2E,
+	AFLDL2T,
+	AFLDLG2,
+	AFLDLN2,
+	AFLDPI,
+	AFLDZ,
+	AFNOP,
+	AFPATAN,
+	AFPREM,
+	AFPREM1,
+	AFPTAN,
+	AFRNDINT,
+	AFSCALE,
+	AFSIN,
+	AFSINCOS,
+	AFSQRT,
+	AFTST,
+	AFXAM,
+	AFXTRACT,
+	AFYL2X,
+	AFYL2XP1,
+
+	AEND,
+
+	ADYNT_,
+	AINIT_,
+
+	ASIGNAME,
+
+	ACMPXCHGB,
+	ACMPXCHGL,
+	ACMPXCHGW,
+	ACMPXCHG8B,
+
+	ACPUID,
+	ARDTSC,
+
+	AXADDB,
+	AXADDL,
+	AXADDW,
+
+	/* conditional move */
+	ACMOVLCC,
+	ACMOVLCS,
+	ACMOVLEQ,
+	ACMOVLGE,
+	ACMOVLGT,
+	ACMOVLHI,
+	ACMOVLLE,
+	ACMOVLLS,
+	ACMOVLLT,
+	ACMOVLMI,
+	ACMOVLNE,
+	ACMOVLOC,
+	ACMOVLOS,
+	ACMOVLPC,
+	ACMOVLPL,
+	ACMOVLPS,
+	ACMOVWCC,
+	ACMOVWCS,
+	ACMOVWEQ,
+	ACMOVWGE,
+	ACMOVWGT,
+	ACMOVWHI,
+	ACMOVWLE,
+	ACMOVWLS,
+	ACMOVWLT,
+	ACMOVWMI,
+	ACMOVWNE,
+	ACMOVWOC,
+	ACMOVWOS,
+	ACMOVWPC,
+	ACMOVWPL,
+	ACMOVWPS,
+
+	AFCMOVCC,
+	AFCMOVCS,
+	AFCMOVEQ,
+	AFCMOVHI,
+	AFCMOVLS,
+	AFCMOVNE,
+	AFCMOVNU,
+	AFCMOVUN,
+
+	ALFENCE,
+	AMFENCE,
+	ASFENCE,
+
+	AEMMS,
+	
+	APREFETCHT0,
+	APREFETCHT1,
+	APREFETCHT2,
+	APREFETCHNTA,
+	
+	ABSWAPL,
+	
+	AUNDEF,
+
+	// SSE2
+	AADDPD,
+	AADDPS,
+	AADDSD,
+	AADDSS,
+	AANDNPD,
+	AANDNPS,
+	AANDPD,
+	AANDPS,
+	ACMPPD,
+	ACMPPS,
+	ACMPSD,
+	ACMPSS,
+	ACOMISD,
+	ACOMISS,
+	ACVTPL2PD,
+	ACVTPL2PS,
+	ACVTPD2PL,
+	ACVTPD2PS,
+	ACVTPS2PL,
+	ACVTPS2PD,
+	ACVTSD2SL,
+	ACVTSD2SS,
+	ACVTSL2SD,
+	ACVTSL2SS,
+	ACVTSS2SD,
+	ACVTSS2SL,
+	ACVTTPD2PL,
+	ACVTTPS2PL,
+	ACVTTSD2SL,
+	ACVTTSS2SL,
+	ADIVPD,
+	ADIVPS,
+	ADIVSD,
+	ADIVSS,
+	AMASKMOVOU,
+	AMAXPD,
+	AMAXPS,
+	AMAXSD,
+	AMAXSS,
+	AMINPD,
+	AMINPS,
+	AMINSD,
+	AMINSS,
+	AMOVAPD,
+	AMOVAPS,
+	AMOVO,
+	AMOVOU,
+	AMOVHLPS,
+	AMOVHPD,
+	AMOVHPS,
+	AMOVLHPS,
+	AMOVLPD,
+	AMOVLPS,
+	AMOVMSKPD,
+	AMOVMSKPS,
+	AMOVNTO,
+	AMOVNTPD,
+	AMOVNTPS,
+	AMOVSD,
+	AMOVSS,
+	AMOVUPD,
+	AMOVUPS,
+	AMULPD,
+	AMULPS,
+	AMULSD,
+	AMULSS,
+	AORPD,
+	AORPS,
+	APADDQ,
+	APAND,
+	APCMPEQB,
+	APMAXSW,
+	APMAXUB,
+	APMINSW,
+	APMINUB,
+	APMOVMSKB,
+	APSADBW,
+	APSUBB,
+	APSUBL,
+	APSUBQ,
+	APSUBSB,
+	APSUBSW,
+	APSUBUSB,
+	APSUBUSW,
+	APSUBW,
+	APUNPCKHQDQ,
+	APUNPCKLQDQ,
+	APXOR,
+	ARCPPS,
+	ARCPSS,
+	ARSQRTPS,
+	ARSQRTSS,
+	ASQRTPD,
+	ASQRTPS,
+	ASQRTSD,
+	ASQRTSS,
+	ASUBPD,
+	ASUBPS,
+	ASUBSD,
+	ASUBSS,
+	AUCOMISD,
+	AUCOMISS,
+	AUNPCKHPD,
+	AUNPCKHPS,
+	AUNPCKLPD,
+	AUNPCKLPS,
+	AXORPD,
+	AXORPS,
+
+	/* SSE 3+ */
+	AAESENC,
+	APINSRD,
+	APSHUFB,
+
+	AUSEFIELD,
+	ATYPE,
+	AFUNCDATA,
+	APCDATA,
+	ACHECKNIL,
+	AVARDEF,
+	AVARKILL,
+	ADUFFCOPY,
+	ADUFFZERO,
+	
+	ALAST
+};
+
+enum
+{
+	D_AL		= 0,
+	D_CL,
+	D_DL,
+	D_BL,
+
+	D_AH		= 4,
+	D_CH,
+	D_DH,
+	D_BH,
+
+	D_AX		= 8,
+	D_CX,
+	D_DX,
+	D_BX,
+	D_SP,
+	D_BP,
+	D_SI,
+	D_DI,
+
+	D_F0		= 16,
+	D_F7		= D_F0 + 7,
+
+	D_CS		= 24,
+	D_SS,
+	D_DS,
+	D_ES,
+	D_FS,
+	D_GS,
+
+	D_GDTR,		/* global descriptor table register */
+	D_IDTR,		/* interrupt descriptor table register */
+	D_LDTR,		/* local descriptor table register */
+	D_MSW,		/* machine status word */
+	D_TASK,		/* task register */
+
+	D_CR		= 35,
+	D_DR		= 43,
+	D_TR		= 51,
+
+	D_X0		= 59,
+	D_X1,
+	D_X2,
+	D_X3,
+	D_X4,
+	D_X5,
+	D_X6,
+	D_X7,
+	
+	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,
+
+	T_TYPE		= 1<<0,
+	T_INDEX		= 1<<1,
+	T_OFFSET	= 1<<2,
+	T_FCONST	= 1<<3,
+	T_SYM		= 1<<4,
+	T_SCONST	= 1<<5,
+	T_OFFSET2	= 1<<6,
+	T_GOTYPE	= 1<<7,
+
+	REGARG		= -1,
+	REGRET		= D_AX,
+	FREGRET		= D_F0,
+	REGSP		= D_SP,
+	REGTMP		= D_DI,
+};
+
+/*
+ * this is the ranlib header
+ */
+#define	SYMDEF	"__.GOSYMDEF"
diff --git a/src/cmd/8l/Makefile b/src/cmd/8l/Makefile
new file mode 100644
index 0000000..3f528d7
--- /dev/null
+++ b/src/cmd/8l/Makefile
@@ -0,0 +1,5 @@
+# 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/8l/asm.c b/src/cmd/8l/asm.c
new file mode 100644
index 0000000..98c0424
--- /dev/null
+++ b/src/cmd/8l/asm.c
@@ -0,0 +1,745 @@
+// Inferno utils/8l/asm.c
+// http://code.google.com/p/inferno-os/source/browse/utils/8l/asm.c
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth 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.
+
+// Writing object files.
+
+#include	"l.h"
+#include	"../ld/lib.h"
+#include	"../ld/elf.h"
+#include	"../ld/dwarf.h"
+#include	"../ld/macho.h"
+#include	"../ld/pe.h"
+
+char linuxdynld[] = "/lib/ld-linux.so.2";
+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";
+char solarisdynld[] = "/lib/ld.so.1";
+
+static int
+needlib(char *name)
+{
+	char *p;
+	LSym *s;
+
+	if(*name == '\0')
+		return 0;
+
+	/* reuse hash code in symbol table */
+	p = smprint(".dynlib.%s", name);
+	s = linklookup(ctxt, p, 0);
+	free(p);
+	if(s->type == 0) {
+		s->type = 100;	// avoid SDATA, etc.
+		return 1;
+	}
+	return 0;
+}
+
+int	nelfsym = 1;
+
+static void	addpltsym(Link*, LSym*);
+static void	addgotsym(Link*, LSym*);
+
+void
+adddynrela(LSym *rela, LSym *s, Reloc *r)
+{
+	USED(rela);
+	USED(s);
+	USED(r);
+	sysfatal("adddynrela not implemented");
+}
+
+void
+adddynrel(LSym *s, Reloc *r)
+{
+	LSym *targ, *rel, *got;
+
+	targ = r->sym;
+	ctxt->cursym = s;
+
+	switch(r->type) {
+	default:
+		if(r->type >= 256) {
+			diag("unexpected relocation type %d", r->type);
+			return;
+		}
+		break;
+
+	// Handle relocations found in ELF object files.
+	case 256 + R_386_PC32:
+		if(targ->type == SDYNIMPORT)
+			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 = R_PCREL;
+		r->add += 4;
+		return;
+
+	case 256 + R_386_PLT32:
+		r->type = R_PCREL;
+		r->add += 4;
+		if(targ->type == SDYNIMPORT) {
+			addpltsym(ctxt, targ);
+			r->sym = linklookup(ctxt, ".plt", 0);
+			r->add += targ->plt;
+		}
+		return;		
+	
+	case 256 + R_386_GOT32:
+		if(targ->type != SDYNIMPORT) {
+			// have symbol
+			if(r->off >= 2 && s->p[r->off-2] == 0x8b) {
+				// turn MOVL of GOT entry into LEAL of symbol address, relative to GOT.
+				s->p[r->off-2] = 0x8d;
+				r->type = R_GOTOFF;
+				return;
+			}
+			if(r->off >= 2 && s->p[r->off-2] == 0xff && s->p[r->off-1] == 0xb3) {
+				// turn PUSHL of GOT entry into PUSHL of symbol itself.
+				// use unnecessary SS prefix to keep instruction same length.
+				s->p[r->off-2] = 0x36;
+				s->p[r->off-1] = 0x68;
+				r->type = R_ADDR;
+				return;
+			}
+			diag("unexpected GOT reloc for non-dynamic symbol %s", targ->name);
+			return;
+		}
+		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 = R_GOTOFF;
+		return;
+	
+	case 256 + R_386_GOTPC:
+		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 = R_ADDR;
+		return;
+	
+	case 512 + MACHO_GENERIC_RELOC_VANILLA*2 + 0:
+		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(ctxt, targ);
+			r->sym = linklookup(ctxt, ".plt", 0);
+			r->add = targ->plt;
+			r->type = R_PCREL;
+			return;
+		}
+		r->type = R_PCREL;
+		return;
+	
+	case 512 + MACHO_FAKE_GOTPCREL:
+		if(targ->type != SDYNIMPORT) {
+			// have symbol
+			// turn MOVL of GOT entry into LEAL of symbol itself
+			if(r->off < 2 || s->p[r->off-2] != 0x8b) {
+				diag("unexpected GOT reloc for non-dynamic symbol %s", targ->name);
+				return;
+			}
+			s->p[r->off-2] = 0x8d;
+			r->type = R_PCREL;
+			return;
+		}
+		addgotsym(ctxt, targ);
+		r->sym = linklookup(ctxt, ".got", 0);
+		r->add += targ->got;
+		r->type = R_PCREL;
+		return;
+	}
+	
+	// Handle references to ELF symbols from our own object files.
+	if(targ->type != SDYNIMPORT)
+		return;
+
+	switch(r->type) {
+	case R_CALL:
+	case R_PCREL:
+		addpltsym(ctxt, targ);
+		r->sym = linklookup(ctxt, ".plt", 0);
+		r->add = targ->plt;
+		return;
+	
+	case R_ADDR:
+		if(s->type != SDATA)
+			break;
+		if(iself) {
+			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;
+		}
+		if(HEADTYPE == Hdarwin && s->size == PtrSize && r->off == 0) {
+			// Mach-O relocations are a royal pain to lay out.
+			// They use a compact stateful bytecode representation
+			// that is too much bother to deal with.
+			// Instead, interpret the C declaration
+			//	void *_Cvar_stderr = &stderr;
+			// as making _Cvar_stderr the name of a GOT entry
+			// for stderr.  This is separate from the usual GOT entry,
+			// just in case the C code assigns to the variable,
+			// and of course it only works for single pointers,
+			// but we only need to support cgo and that's all it needs.
+			adddynsym(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(ctxt, got, 0);
+			adduint32(ctxt, linklookup(ctxt, ".linkedit.got", 0), targ->dynid);
+			r->type = 256;	// ignore during relocsym
+			return;
+		}
+		break;
+	}
+	
+	ctxt->cursym = s;
+	diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ->name, r->type, targ->type);
+}
+
+int
+elfreloc1(Reloc *r, vlong sectoff)
+{
+	int32 elfsym;
+
+	LPUT(sectoff);
+
+	elfsym = r->xsym->elfsym;
+	switch(r->type) {
+	default:
+		return -1;
+
+	case R_ADDR:
+		if(r->siz == 4)
+			LPUT(R_386_32 | elfsym<<8);
+		else
+			return -1;
+		break;
+
+	case R_CALL:
+	case R_PCREL:
+		if(r->siz == 4)
+			LPUT(R_386_PC32 | elfsym<<8);
+		else
+			return -1;
+		break;
+	
+	case R_TLS_LE:
+	case R_TLS_IE:
+		if(r->siz == 4)
+			LPUT(R_386_TLS_LE | elfsym<<8);
+		else
+			return -1;
+	}
+
+	return 0;
+}
+
+int
+machoreloc1(Reloc *r, vlong sectoff)
+{
+	uint32 v;
+	LSym *rs;
+	
+	rs = r->xsym;
+
+	if(rs->type == SHOSTOBJ) {
+		if(rs->dynid < 0) {
+			diag("reloc %d to non-macho symbol %s type=%d", r->type, rs->name, rs->type);
+			return -1;
+		}
+		v = rs->dynid;			
+		v |= 1<<27; // external relocation
+	} else {
+		v = rs->sect->extnum;
+		if(v == 0) {
+			diag("reloc %d to symbol %s in non-macho section %s type=%d", r->type, rs->name, rs->sect->name, rs->type);
+			return -1;
+		}
+	}
+
+	switch(r->type) {
+	default:
+		return -1;
+	case R_ADDR:
+		v |= MACHO_GENERIC_RELOC_VANILLA<<28;
+		break;
+	case R_CALL:
+	case R_PCREL:
+		v |= 1<<24; // pc-relative bit
+		v |= MACHO_GENERIC_RELOC_VANILLA<<28;
+		break;
+	}
+	
+	switch(r->siz) {
+	default:
+		return -1;
+	case 1:
+		v |= 0<<25;
+		break;
+	case 2:
+		v |= 1<<25;
+		break;
+	case 4:
+		v |= 2<<25;
+		break;
+	case 8:
+		v |= 3<<25;
+		break;
+	}
+
+	LPUT(sectoff);
+	LPUT(v);
+	return 0;
+}
+
+int
+archreloc(Reloc *r, LSym *s, vlong *val)
+{
+	USED(s);
+	if(linkmode == LinkExternal)
+		return -1;
+	switch(r->type) {
+	case R_CONST:
+		*val = r->add;
+		return 0;
+	case R_GOTOFF:
+		*val = symaddr(r->sym) + r->add - symaddr(linklookup(ctxt, ".got", 0));
+		return 0;
+	}
+	return -1;
+}
+
+void
+elfsetupplt(void)
+{
+	LSym *plt, *got;
+	
+	plt = linklookup(ctxt, ".plt", 0);
+	got = linklookup(ctxt, ".got.plt", 0);
+	if(plt->size == 0) {
+		// pushl got+4
+		adduint8(ctxt, plt, 0xff);
+		adduint8(ctxt, plt, 0x35);
+		addaddrplus(ctxt, plt, got, 4);
+		
+		// jmp *got+8
+		adduint8(ctxt, plt, 0xff);
+		adduint8(ctxt, plt, 0x25);
+		addaddrplus(ctxt, plt, got, 8);
+
+		// zero pad
+		adduint32(ctxt, plt, 0);
+		
+		// assume got->size == 0 too
+		addaddrplus(ctxt, got, linklookup(ctxt, ".dynamic", 0), 0);
+		adduint32(ctxt, got, 0);
+		adduint32(ctxt, got, 0);
+	}
+}
+
+static void
+addpltsym(Link *ctxt, LSym *s)
+{
+	LSym *plt, *got, *rel;
+	
+	if(s->plt >= 0)
+		return;
+
+	adddynsym(ctxt, s);
+	
+	if(iself) {
+		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(ctxt, plt, 0xff);
+		adduint8(ctxt, plt, 0x25);
+		addaddrplus(ctxt, plt, got, got->size);
+		
+		// add to got: pointer to current pos in plt
+		addaddrplus(ctxt, got, plt, plt->size);
+		
+		// pushl $x
+		adduint8(ctxt, plt, 0x68);
+		adduint32(ctxt, plt, rel->size);
+		
+		// jmp .plt
+		adduint8(ctxt, plt, 0xe9);
+		adduint32(ctxt, plt, -(plt->size+4));
+		
+		// rel
+		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.
+		
+		LSym *plt;
+
+		plt = linklookup(ctxt, ".plt", 0);
+
+		addgotsym(ctxt, s);
+
+		adduint32(ctxt, linklookup(ctxt, ".linkedit.plt", 0), s->dynid);
+
+		// jmpq *got+size(IP)
+		s->plt = plt->size;
+
+		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(Link *ctxt, LSym *s)
+{
+	LSym *got, *rel;
+	
+	if(s->got >= 0)
+		return;
+	
+	adddynsym(ctxt, s);
+	got = linklookup(ctxt, ".got", 0);
+	s->got = got->size;
+	adduint32(ctxt, got, 0);
+	
+	if(iself) {
+		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(ctxt, linklookup(ctxt, ".linkedit.got", 0), s->dynid);
+	} else {
+		diag("addgotsym: unsupported binary format");
+	}
+}
+
+void
+adddynsym(Link *ctxt, LSym *s)
+{
+	LSym *d;
+	int t;
+	char *name;
+	
+	if(s->dynid >= 0)
+		return;
+	
+	if(iself) {
+		s->dynid = nelfsym++;
+		
+		d = linklookup(ctxt, ".dynsym", 0);
+
+		/* name */
+		name = s->extname;
+		adduint32(ctxt, d, addstring(linklookup(ctxt, ".dynstr", 0), name));
+		
+		/* value */
+		if(s->type == SDYNIMPORT)
+			adduint32(ctxt, d, 0);
+		else
+			addaddr(ctxt, d, s);
+		
+		/* size */
+		adduint32(ctxt, d, 0);
+	
+		/* type */
+		t = STB_GLOBAL << 4;
+		if(s->cgoexport && (s->type&SMASK) == STEXT)
+			t |= STT_FUNC;
+		else
+			t |= STT_OBJECT;
+		adduint8(ctxt, d, t);
+		adduint8(ctxt, d, 0);
+	
+		/* shndx */
+		if(s->type == SDYNIMPORT)
+			adduint16(ctxt, d, SHN_UNDEF);
+		else {
+			switch(s->type) {
+			default:
+			case STEXT:
+				t = 11;
+				break;
+			case SRODATA:
+				t = 12;
+				break;
+			case SDATA:
+				t = 13;
+				break;
+			case SBSS:
+				t = 14;
+				break;
+			}
+			adduint16(ctxt, d, t);
+		}
+	} else if(HEADTYPE == Hdarwin) {
+		diag("adddynsym: missed symbol %s (%s)", s->name, s->extname);
+	} else if(HEADTYPE == Hwindows) {
+		// already taken care of
+	} else {
+		diag("adddynsym: unsupported binary format");
+	}
+}
+
+void
+adddynlib(char *lib)
+{
+	LSym *s;
+	
+	if(!needlib(lib))
+		return;
+	
+	if(iself) {
+		s = linklookup(ctxt, ".dynstr", 0);
+		if(s->size == 0)
+			addstring(s, "");
+		elfwritedynent(linklookup(ctxt, ".dynamic", 0), DT_NEEDED, addstring(s, lib));
+	} else if(HEADTYPE == Hdarwin) {
+		machoadddynlib(lib);
+	} else if(HEADTYPE != Hwindows) {
+		diag("adddynlib: unsupported binary format");
+	}
+}
+
+void
+asmb(void)
+{
+	int32 magic;
+	uint32 symo, dwarfoff, machlink;
+	Section *sect;
+	LSym *sym;
+	int i;
+
+	if(debug['v'])
+		Bprint(&bso, "%5.2f asmb\n", cputime());
+	Bflush(&bso);
+
+	if(iself)
+		asmbelfsetup();
+
+	sect = segtext.sect;
+	cseek(sect->vaddr - segtext.vaddr + segtext.fileoff);
+	codeblk(sect->vaddr, sect->len);
+	for(sect = sect->next; sect != nil; sect = sect->next) {
+		cseek(sect->vaddr - segtext.vaddr + segtext.fileoff);
+		datblk(sect->vaddr, sect->len);
+	}
+	
+	if(segrodata.filelen > 0) {
+		if(debug['v'])
+			Bprint(&bso, "%5.2f rodatblk\n", cputime());
+		Bflush(&bso);
+
+		cseek(segrodata.fileoff);
+		datblk(segrodata.vaddr, segrodata.filelen);
+	}
+
+	if(debug['v'])
+		Bprint(&bso, "%5.2f datblk\n", cputime());
+	Bflush(&bso);
+
+	cseek(segdata.fileoff);
+	datblk(segdata.vaddr, segdata.filelen);
+
+	machlink = 0;
+	if(HEADTYPE == Hdarwin) {
+		if(debug['v'])
+			Bprint(&bso, "%5.2f dwarf\n", cputime());
+
+		dwarfoff = rnd(HEADR+segtext.len, INITRND) + rnd(segdata.filelen, INITRND);
+		cseek(dwarfoff);
+
+		segdwarf.fileoff = cpos();
+		dwarfemitdebugsections();
+		segdwarf.filelen = cpos() - segdwarf.fileoff;
+
+		machlink = domacholink();
+	}
+
+	symsize = 0;
+	spsize = 0;
+	lcsize = 0;
+	symo = 0;
+	if(!debug['s']) {
+		// TODO: rationalize
+		if(debug['v'])
+			Bprint(&bso, "%5.2f sym\n", cputime());
+		Bflush(&bso);
+		switch(HEADTYPE) {
+		default:
+			if(iself)
+				goto Elfsym;
+		case Hplan9:
+			symo = segdata.fileoff+segdata.filelen;
+			break;
+		case Hdarwin:
+			symo = segdata.fileoff+rnd(segdata.filelen, INITRND)+machlink;
+			break;
+		Elfsym:
+			symo = segdata.fileoff+segdata.filelen;
+			symo = rnd(symo, INITRND);
+			break;
+		case Hwindows:
+			symo = segdata.fileoff+segdata.filelen;
+			symo = rnd(symo, PEFILEALIGN);
+			break;
+		}
+		cseek(symo);
+		switch(HEADTYPE) {
+		default:
+			if(iself) {
+				if(debug['v'])
+					Bprint(&bso, "%5.2f elfsym\n", cputime());
+				asmelfsym();
+				cflush();
+				cwrite(elfstrdat, elfstrsize);
+
+				if(debug['v'])
+					Bprint(&bso, "%5.2f dwarf\n", cputime());
+				dwarfemitdebugsections();
+				
+				if(linkmode == LinkExternal)
+					elfemitreloc();
+			}
+			break;
+		case Hplan9:
+			asmplan9sym();
+			cflush();
+
+			sym = linklookup(ctxt, "pclntab", 0);
+			if(sym != nil) {
+				lcsize = sym->np;
+				for(i=0; i < lcsize; i++)
+					cput(sym->p[i]);
+				
+				cflush();
+			}
+			break;
+		case Hwindows:
+			if(debug['v'])
+				Bprint(&bso, "%5.2f dwarf\n", cputime());
+			dwarfemitdebugsections();
+			break;
+		case Hdarwin:
+			if(linkmode == LinkExternal)
+				machoemitreloc();
+			break;
+		}
+	}
+	if(debug['v'])
+		Bprint(&bso, "%5.2f headr\n", cputime());
+	Bflush(&bso);
+	cseek(0L);
+	switch(HEADTYPE) {
+	default:
+	case Hplan9:	/* plan9 */
+		magic = 4*11*11+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;
+	case Hlinux:
+	case Hfreebsd:
+	case Hnetbsd:
+	case Hopenbsd:
+	case Hdragonfly:
+	case Hnacl:
+		asmbelf(symo);
+		break;
+	case Hwindows:
+		asmbpe();
+		break;
+	}
+	cflush();
+}
+
+void
+s8put(char *n)
+{
+	char name[8];
+	int i;
+
+	strncpy(name, n, sizeof(name));
+	for(i=0; i<sizeof(name); i++)
+		cput(name[i]);
+}
+
+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;
+}
diff --git a/src/cmd/8l/doc.go b/src/cmd/8l/doc.go
new file mode 100644
index 0000000..ff06bc3
--- /dev/null
+++ b/src/cmd/8l/doc.go
@@ -0,0 +1,15 @@
+// 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
+
+/*
+
+8l is the linker for the 32-bit x86.
+The $GOARCH for these tools is 386.
+
+The flags are documented in ../ld/doc.go.
+
+*/
+package main
diff --git a/src/cmd/8l/l.h b/src/cmd/8l/l.h
new file mode 100644
index 0000000..70d3a4b
--- /dev/null
+++ b/src/cmd/8l/l.h
@@ -0,0 +1,95 @@
+// Inferno utils/8l/l.h
+// http://code.google.com/p/inferno-os/source/browse/utils/8l/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.
+
+#include	<u.h>
+#include	<libc.h>
+#include	<bio.h>
+#include	<link.h>
+#include	"8.out.h"
+
+#ifndef	EXTERN
+#define	EXTERN	extern
+#endif
+
+enum
+{
+	thechar = '8',
+	PtrSize = 4,
+	IntSize = 4,
+	RegSize = 4,
+	MaxAlign = 32,	// max data alignment
+	FuncAlign = 16
+};
+
+#define	P		((Prog*)0)
+#define	S		((LSym*)0)
+
+enum
+{
+	MINLC		= 1,
+};
+
+#pragma	varargck	type	"I"	uchar*
+
+EXTERN	LSym*	datap;
+EXTERN	int	debug[128];
+EXTERN	char	literal[32];
+EXTERN	Prog*	firstp;
+EXTERN	int32	lcsize;
+EXTERN	char*	rpath;
+EXTERN	int32	spsize;
+EXTERN	LSym*	symlist;
+EXTERN	int32	symsize;
+
+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);
+int	elfreloc1(Reloc *r, vlong sectoff);
+void	elfsetupplt(void);
+void	listinit(void);
+int	machoreloc1(Reloc *r, vlong sectoff);
+int32	rnd(int32 v, int32 r);
+void	s8put(char *n);
+char*	xsymname(LSym *s);
+
+/* Native is little-endian */
+#define	LPUT(a)	lputl(a)
+#define	WPUT(a)	wputl(a)
+#define	VPUT(a)	vputl(a)
+
+/* Used by ../ld/dwarf.c */
+enum
+{
+	DWARFREGSP = 4
+};
diff --git a/src/cmd/8l/list.c b/src/cmd/8l/list.c
new file mode 100644
index 0000000..0a75340
--- /dev/null
+++ b/src/cmd/8l/list.c
@@ -0,0 +1,67 @@
+// Inferno utils/8l/list.c
+// http://code.google.com/p/inferno-os/source/browse/utils/8l/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.
+
+// Printing.
+
+#include	"l.h"
+#include	"../ld/lib.h"
+
+void
+listinit(void)
+{
+	listinit8();
+	fmtinstall('I', Iconv);
+}
+
+int
+Iconv(Fmt *fp)
+{
+	int i, n;
+	uchar *p;
+	char *s;
+	Fmt fmt;
+	
+	n = fp->prec;
+	fp->prec = 0;
+	if(!(fp->flags&FmtPrec) || n < 0)
+		return fmtstrcpy(fp, "%I");
+	fp->flags &= ~FmtPrec;
+	p = va_arg(fp->args, uchar*);
+
+	// format into temporary buffer and
+	// call fmtstrcpy to handle padding.
+	fmtstrinit(&fmt);
+	for(i=0; i<n; i++)
+		fmtprint(&fmt, "%.2ux", *p++);
+	s = fmtstrflush(&fmt);
+	fmtstrcpy(fp, s);
+	free(s);
+	return 0;
+}
diff --git a/src/cmd/8l/obj.c b/src/cmd/8l/obj.c
new file mode 100644
index 0000000..1b65c5e
--- /dev/null
+++ b/src/cmd/8l/obj.c
@@ -0,0 +1,138 @@
+// 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.
+
+// Reading object files.
+
+#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*	thestring 	= "386";
+LinkArch*	thelinkarch = &link386;
+
+void
+linkarchinit(void)
+{
+}
+
+void
+archinit(void)
+{
+	// getgoextlinkenabled is based on GO_EXTLINK_ENABLED when
+	// Go was built; see ../../make.bash.
+	if(linkmode == LinkAuto && strcmp(getgoextlinkenabled(), "0") == 0)
+		linkmode = LinkInternal;
+
+	switch(HEADTYPE) {
+	default:
+		if(linkmode == LinkAuto)
+			linkmode = LinkInternal;
+		if(linkmode == LinkExternal && strcmp(getgoextlinkenabled(), "1") != 0)
+			sysfatal("cannot use -linkmode=external with -H %s", headstr(HEADTYPE));
+		break;
+	case Hdarwin:
+	case Hdragonfly:
+	case Hfreebsd:
+	case Hlinux:
+	case Hnetbsd:
+	case Hopenbsd:
+		break;
+	}
+
+	switch(HEADTYPE) {
+	default:
+		diag("unknown -H option");
+		errorexit();
+
+	case Hplan9:	/* plan 9 */
+		HEADR = 32L;
+		if(INITTEXT == -1)
+			INITTEXT = 4096+32;
+		if(INITDAT == -1)
+			INITDAT = 0;
+		if(INITRND == -1)
+			INITRND = 4096;
+		break;
+	case Hdarwin:	/* apple MACH */
+		machoinit();
+		HEADR = INITIAL_MACHO_HEADR;
+		if(INITTEXT == -1)
+			INITTEXT = 4096+HEADR;
+		if(INITDAT == -1)
+			INITDAT = 0;
+		if(INITRND == -1)
+			INITRND = 4096;
+		break;
+	case Hlinux:	/* elf32 executable */
+	case Hfreebsd:
+	case Hnetbsd:
+	case Hopenbsd:
+	case Hdragonfly:
+		elfinit();
+		HEADR = ELFRESERVE;
+		if(INITTEXT == -1)
+			INITTEXT = 0x08048000+HEADR;
+		if(INITDAT == -1)
+			INITDAT = 0;
+		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;
+		if(INITTEXT == -1)
+			INITTEXT = PEBASE+PESECTHEADR;
+		if(INITDAT == -1)
+			INITDAT = 0;
+		if(INITRND == -1)
+			INITRND = PESECTALIGN;
+		break;
+	}
+	if(INITDAT != 0 && INITRND != 0)
+		print("warning: -D0x%llux is ignored because of -R0x%ux\n",
+			INITDAT, INITRND);
+}
diff --git a/src/cmd/addr2line/addr2line_test.go b/src/cmd/addr2line/addr2line_test.go
index 620b416..10d1dc9 100644
--- a/src/cmd/addr2line/addr2line_test.go
+++ b/src/cmd/addr2line/addr2line_test.go
@@ -7,7 +7,6 @@ package main
 import (
 	"bufio"
 	"bytes"
-	"internal/testenv"
 	"io/ioutil"
 	"os"
 	"os/exec"
@@ -52,9 +51,15 @@ func runAddr2Line(t *testing.T, exepath, addr string) (funcname, path, lineno st
 	funcname = f[0]
 	pathAndLineNo := f[1]
 	f = strings.Split(pathAndLineNo, ":")
-	if runtime.GOOS == "windows" && len(f) == 3 {
-		// Reattach drive letter.
-		f = []string{f[0] + ":" + f[1], f[2]}
+	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)
@@ -80,14 +85,17 @@ func testAddr2Line(t *testing.T, exepath, addr string) {
 	if !os.SameFile(fi1, fi2) {
 		t.Fatalf("addr2line_test.go and %s are not same file", srcPath)
 	}
-	if srcLineNo != "89" {
-		t.Fatalf("line number = %v; want 89", srcLineNo)
+	if srcLineNo != "94" {
+		t.Fatalf("line number = %v; want 94", srcLineNo)
 	}
 }
 
-// This is line 88. The test depends on that.
+// This is line 93. The test depends on that.
 func TestAddr2Line(t *testing.T) {
-	testenv.MustHaveGoBuild(t)
+	switch runtime.GOOS {
+	case "nacl", "android":
+		t.Skipf("skipping on %s", runtime.GOOS)
+	}
 
 	syms := loadSyms(t)
 
diff --git a/src/cmd/api/goapi.go b/src/cmd/api/goapi.go
index 01b6def..4a63eac 100644
--- a/src/cmd/api/goapi.go
+++ b/src/cmd/api/goapi.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 api_tool
+
 // Binary api computes the exported API of a set of Go packages.
 package main
 
@@ -14,7 +16,6 @@ import (
 	"go/build"
 	"go/parser"
 	"go/token"
-	"go/types"
 	"io"
 	"io/ioutil"
 	"log"
@@ -25,6 +26,8 @@ import (
 	"runtime"
 	"sort"
 	"strings"
+
+	"code.google.com/p/go.tools/go/types"
 )
 
 // Flags
@@ -152,8 +155,7 @@ func main() {
 					// w.Import(name) will return nil
 					continue
 				}
-				pkg, _ := w.Import(name)
-				w.export(pkg)
+				w.export(w.Import(name))
 			}
 		}
 
@@ -203,8 +205,7 @@ func main() {
 	}
 	optional := fileFeatures(*nextFile)
 	exception := fileFeatures(*exceptFile)
-	fail = !compareAPI(bw, features, required, optional, exception,
-		*allowNew && strings.Contains(runtime.Version(), "devel"))
+	fail = !compareAPI(bw, features, required, optional, exception)
 }
 
 // export emits the exported package features.
@@ -240,7 +241,7 @@ func featureWithoutContext(f string) string {
 	return spaceParensRx.ReplaceAllString(f, "")
 }
 
-func compareAPI(w io.Writer, features, required, optional, exception []string, allowAdd bool) (ok bool) {
+func compareAPI(w io.Writer, features, required, optional, exception []string) (ok bool) {
 	ok = true
 
 	optionalSet := set(optional)
@@ -282,7 +283,7 @@ func compareAPI(w io.Writer, features, required, optional, exception []string, a
 				delete(optionalSet, newFeature)
 			} else {
 				fmt.Fprintf(w, "+%s\n", newFeature)
-				if !allowAdd {
+				if !*allowNew || !strings.Contains(runtime.Version(), "devel") {
 					ok = false // we're in lock-down mode for next release
 				}
 			}
@@ -355,16 +356,139 @@ var parsedFileCache = make(map[string]*ast.File)
 
 func (w *Walker) parseFile(dir, file string) (*ast.File, error) {
 	filename := filepath.Join(dir, file)
-	if f := parsedFileCache[filename]; f != nil {
+	f, _ := parsedFileCache[filename]
+	if f != nil {
 		return f, nil
 	}
 
-	f, err := parser.ParseFile(fset, filename, nil, 0)
-	if err != nil {
-		return nil, err
+	var err error
+
+	// generate missing context-dependent files.
+
+	if w.context != nil && file == fmt.Sprintf("zgoos_%s.go", w.context.GOOS) {
+		src := fmt.Sprintf("package runtime; const theGoos = `%s`", w.context.GOOS)
+		f, err = parser.ParseFile(fset, filename, src, 0)
+		if err != nil {
+			log.Fatalf("incorrect generated file: %s", err)
+		}
+	}
+
+	if w.context != nil && file == fmt.Sprintf("zgoarch_%s.go", w.context.GOARCH) {
+		src := fmt.Sprintf("package runtime; const theGoarch = `%s`", w.context.GOARCH)
+		f, err = parser.ParseFile(fset, filename, src, 0)
+		if err != nil {
+			log.Fatalf("incorrect generated file: %s", err)
+		}
+	}
+	if w.context != nil && file == fmt.Sprintf("zruntime_defs_%s_%s.go", w.context.GOOS, w.context.GOARCH) {
+		// Just enough to keep the api checker happy. Keep sorted.
+		src := "package runtime; type (" +
+			" _defer struct{};" +
+			" _func struct{};" +
+			" _panic struct{};" +
+			" _select struct{}; " +
+			" _type struct{};" +
+			" alg struct{};" +
+			" chantype struct{};" +
+			" context struct{};" + // windows
+			" eface struct{};" +
+			" epollevent struct{};" +
+			" funcval struct{};" +
+			" g struct{};" +
+			" gobuf struct{};" +
+			" hchan struct{};" +
+			" iface struct{};" +
+			" interfacetype struct{};" +
+			" itab struct{};" +
+			" keventt struct{};" +
+			" m struct{};" +
+			" maptype struct{};" +
+			" mcache struct{};" +
+			" mspan struct{};" +
+			" mutex struct{};" +
+			" note struct{};" +
+			" p struct{};" +
+			" parfor struct{};" +
+			" slicetype struct{};" +
+			" stkframe struct{};" +
+			" sudog struct{};" +
+			" timespec struct{};" +
+			" waitq struct{};" +
+			" wincallbackcontext struct{};" +
+			"); " +
+			"const (" +
+			" cb_max = 2000;" +
+			" _CacheLineSize = 64;" +
+			" _Gidle = 1;" +
+			" _Grunnable = 2;" +
+			" _Grunning = 3;" +
+			" _Gsyscall = 4;" +
+			" _Gwaiting = 5;" +
+			" _Gdead = 6;" +
+			" _Genqueue = 7;" +
+			" _Gcopystack = 8;" +
+			" _NSIG = 32;" +
+			" _FlagNoScan = iota;" +
+			" _FlagNoZero;" +
+			" _TinySize;" +
+			" _TinySizeClass;" +
+			" _MaxSmallSize;" +
+			" _PageShift;" +
+			" _PageSize;" +
+			" _PageMask;" +
+			" _BitsPerPointer;" +
+			" _BitsMask;" +
+			" _PointersPerByte;" +
+			" _MaxGCMask;" +
+			" _BitsDead;" +
+			" _BitsPointer;" +
+			" _MSpanInUse;" +
+			" _ConcurrentSweep;" +
+			" _KindBool;" +
+			" _KindInt;" +
+			" _KindInt8;" +
+			" _KindInt16;" +
+			" _KindInt32;" +
+			" _KindInt64;" +
+			" _KindUint;" +
+			" _KindUint8;" +
+			" _KindUint16;" +
+			" _KindUint32;" +
+			" _KindUint64;" +
+			" _KindUintptr;" +
+			" _KindFloat32;" +
+			" _KindFloat64;" +
+			" _KindComplex64;" +
+			" _KindComplex128;" +
+			" _KindArray;" +
+			" _KindChan;" +
+			" _KindFunc;" +
+			" _KindInterface;" +
+			" _KindMap;" +
+			" _KindPtr;" +
+			" _KindSlice;" +
+			" _KindString;" +
+			" _KindStruct;" +
+			" _KindUnsafePointer;" +
+			" _KindDirectIface;" +
+			" _KindGCProg;" +
+			" _KindNoPointers;" +
+			" _KindMask;" +
+			")"
+		f, err = parser.ParseFile(fset, filename, src, 0)
+		if err != nil {
+			log.Fatalf("incorrect generated file: %s", err)
+		}
+	}
+
+	if f == nil {
+		f, err = parser.ParseFile(fset, filename, nil, 0)
+		if err != nil {
+			return nil, err
+		}
 	}
-	parsedFileCache[filename] = f
 
+	parsedFileCache[filename] = f
 	return f, nil
 }
 
@@ -418,13 +542,13 @@ func tagKey(dir string, context *build.Context, tags []string) string {
 // for a package that is in the process of being imported.
 var importing types.Package
 
-func (w *Walker) Import(name string) (*types.Package, error) {
-	pkg := w.imported[name]
+func (w *Walker) Import(name string) (pkg *types.Package) {
+	pkg = w.imported[name]
 	if pkg != nil {
 		if pkg == &importing {
 			log.Fatalf("cycle importing package %q", name)
 		}
-		return pkg, nil
+		return pkg
 	}
 	w.imported[name] = &importing
 
@@ -448,7 +572,7 @@ func (w *Walker) Import(name string) (*types.Package, error) {
 			key = tagKey(dir, context, tags)
 			if pkg := pkgCache[key]; pkg != nil {
 				w.imported[name] = pkg
-				return pkg, nil
+				return pkg
 			}
 		}
 	}
@@ -456,7 +580,7 @@ func (w *Walker) Import(name string) (*types.Package, error) {
 	info, err := context.ImportDir(dir, 0)
 	if err != nil {
 		if _, nogo := err.(*build.NoGoError); nogo {
-			return nil, nil
+			return
 		}
 		log.Fatalf("pkg %q, dir %q: ScanDir: %v", name, dir, err)
 	}
@@ -471,6 +595,25 @@ func (w *Walker) Import(name string) (*types.Package, error) {
 
 	filenames := append(append([]string{}, info.GoFiles...), info.CgoFiles...)
 
+	// Certain files only exist when building for the specified context.
+	// Add them manually.
+	if name == "runtime" {
+		n := fmt.Sprintf("zgoos_%s.go", w.context.GOOS)
+		if !contains(filenames, n) {
+			filenames = append(filenames, n)
+		}
+
+		n = fmt.Sprintf("zgoarch_%s.go", w.context.GOARCH)
+		if !contains(filenames, n) {
+			filenames = append(filenames, n)
+		}
+
+		n = fmt.Sprintf("zruntime_defs_%s_%s.go", w.context.GOOS, w.context.GOARCH)
+		if !contains(filenames, n) {
+			filenames = append(filenames, n)
+		}
+	}
+
 	// Parse package files.
 	var files []*ast.File
 	for _, file := range filenames {
@@ -485,7 +628,11 @@ func (w *Walker) Import(name string) (*types.Package, error) {
 	conf := types.Config{
 		IgnoreFuncBodies: true,
 		FakeImportC:      true,
-		Importer:         w,
+		Import: func(imports map[string]*types.Package, name string) (*types.Package, error) {
+			pkg := w.Import(name)
+			imports[name] = pkg
+			return pkg, nil
+		},
 	}
 	pkg, err = conf.Check(name, fset, files, nil)
 	if err != nil {
@@ -501,7 +648,7 @@ func (w *Walker) Import(name string) (*types.Package, error) {
 	}
 
 	w.imported[name] = pkg
-	return pkg, nil
+	return
 }
 
 // pushScope enters a new scope (walking a package, type, node, etc)
@@ -603,14 +750,12 @@ func (w *Walker) writeType(buf *bytes.Buffer, typ types.Type) {
 	case *types.Chan:
 		var s string
 		switch typ.Dir() {
-		case types.SendOnly:
+		case ast.SEND:
 			s = "chan<- "
-		case types.RecvOnly:
+		case ast.RECV:
 			s = "<-chan "
-		case types.SendRecv:
-			s = "chan "
 		default:
-			panic("unreachable")
+			s = "chan "
 		}
 		buf.WriteString(s)
 		w.writeType(buf, typ.Elem())
@@ -630,7 +775,7 @@ func (w *Walker) writeType(buf *bytes.Buffer, typ types.Type) {
 }
 
 func (w *Walker) writeSignature(buf *bytes.Buffer, sig *types.Signature) {
-	w.writeParams(buf, sig.Params(), sig.Variadic())
+	w.writeParams(buf, sig.Params(), sig.IsVariadic())
 	switch res := sig.Results(); res.Len() {
 	case 0:
 		// nothing to do
@@ -702,10 +847,10 @@ func (w *Walker) emitType(obj *types.TypeName) {
 
 	// emit methods with value receiver
 	var methodNames map[string]bool
-	vset := types.NewMethodSet(typ)
+	vset := typ.MethodSet()
 	for i, n := 0, vset.Len(); i < n; i++ {
 		m := vset.At(i)
-		if m.Obj().Exported() {
+		if m.Obj().IsExported() {
 			w.emitMethod(m)
 			if methodNames == nil {
 				methodNames = make(map[string]bool)
@@ -717,10 +862,10 @@ func (w *Walker) emitType(obj *types.TypeName) {
 	// emit methods with pointer receiver; exclude
 	// methods that we have emitted already
 	// (the method set of *T includes the methods of T)
-	pset := types.NewMethodSet(types.NewPointer(typ))
+	pset := types.NewPointer(typ).MethodSet()
 	for i, n := 0, pset.Len(); i < n; i++ {
 		m := pset.At(i)
-		if m.Obj().Exported() && !methodNames[m.Obj().Name()] {
+		if m.Obj().IsExported() && !methodNames[m.Obj().Name()] {
 			w.emitMethod(m)
 		}
 	}
@@ -733,7 +878,7 @@ func (w *Walker) emitStructType(name string, typ *types.Struct) {
 
 	for i := 0; i < typ.NumFields(); i++ {
 		f := typ.Field(i)
-		if !f.Exported() {
+		if !f.IsExported() {
 			continue
 		}
 		typ := f.Type()
@@ -750,10 +895,10 @@ func (w *Walker) emitIfaceType(name string, typ *types.Interface) {
 
 	var methodNames []string
 	complete := true
-	mset := types.NewMethodSet(typ)
+	mset := typ.MethodSet()
 	for i, n := 0, mset.Len(); i < n; i++ {
 		m := mset.At(i).Obj().(*types.Func)
-		if !m.Exported() {
+		if !m.IsExported() {
 			complete = false
 			continue
 		}
@@ -804,7 +949,7 @@ func (w *Walker) emitMethod(m *types.Selection) {
 		if p, _ := recv.(*types.Pointer); p != nil {
 			base = p.Elem()
 		}
-		if obj := base.(*types.Named).Obj(); !obj.Exported() {
+		if obj := base.(*types.Named).Obj(); !obj.IsExported() {
 			log.Fatalf("exported method with unexported receiver base type: %s", m)
 		}
 	}
diff --git a/src/cmd/api/goapi_test.go b/src/cmd/api/goapi_test.go
index 1d2cc9a..f4fb7d3 100644
--- a/src/cmd/api/goapi_test.go
+++ b/src/cmd/api/goapi_test.go
@@ -1,3 +1,5 @@
+// +build api_tool
+
 // 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,11 +38,9 @@ func TestGolden(t *testing.T) {
 			continue
 		}
 
-		// TODO(gri) remove extra pkg directory eventually
-		goldenFile := filepath.Join("testdata", "src", "pkg", fi.Name(), "golden.txt")
+		goldenFile := filepath.Join("testdata", "src", fi.Name(), "golden.txt")
 		w := NewWalker(nil, "testdata/src/pkg")
-		pkg, _ := w.Import(fi.Name())
-		w.export(pkg)
+		w.export(w.Import(fi.Name()))
 
 		if *updateGolden {
 			os.Remove(goldenFile)
@@ -115,7 +115,7 @@ func TestCompareAPI(t *testing.T) {
 			out:       "",
 		},
 		{
-			// https://golang.org/issue/4303
+			// http://golang.org/issue/4303
 			name: "contexts reconverging",
 			required: []string{
 				"A",
@@ -132,7 +132,7 @@ func TestCompareAPI(t *testing.T) {
 	}
 	for _, tt := range tests {
 		buf := new(bytes.Buffer)
-		gotok := compareAPI(buf, tt.features, tt.required, tt.optional, tt.exception, true)
+		gotok := compareAPI(buf, tt.features, tt.required, tt.optional, tt.exception)
 		if gotok != tt.ok {
 			t.Errorf("%s: ok = %v; want %v", tt.name, gotok, tt.ok)
 		}
@@ -179,8 +179,7 @@ func BenchmarkAll(b *testing.B) {
 			w := NewWalker(context, filepath.Join(build.Default.GOROOT, "src"))
 			for _, name := range pkgNames {
 				if name != "unsafe" && !strings.HasPrefix(name, "cmd/") {
-					pkg, _ := w.Import(name)
-					w.export(pkg)
+					w.export(w.Import(name))
 				}
 			}
 			w.Features()
diff --git a/src/cmd/api/run.go b/src/cmd/api/run.go
index eaffa0a..ed5613e 100644
--- a/src/cmd/api/run.go
+++ b/src/cmd/api/run.go
@@ -4,18 +4,32 @@
 
 // +build ignore
 
-// The run program is invoked via the dist tool.
-// To invoke manually: go tool dist test -run api --no-rebuild
+// The run program is invoked via "go run" from src/run.bash or
+// src/run.bat conditionally builds and runs the cmd/api tool.
+//
+// TODO(bradfitz): the "conditional" condition is always true.
+// We should only do this if the user has the hg codereview extension
+// enabled and verifies that the go.tools subrepo is checked out with
+// a suitably recently version. In prep for the cmd/api rewrite.
 package main
 
 import (
 	"fmt"
 	"log"
+	"net/http"
 	"os"
 	"os/exec"
+	"os/user"
 	"path/filepath"
+	"runtime"
+	"strings"
 )
 
+// goToolsVersion is the hg revision of the go.tools subrepo we need
+// to build cmd/api.  This only needs to be updated whenever a go/types
+// bug fix is needed by the cmd/api tool.
+const goToolsVersion = "6698ca2900e2"
+
 var goroot string
 
 func main() {
@@ -24,9 +38,23 @@ func main() {
 	if goroot == "" {
 		log.Fatal("No $GOROOT set.")
 	}
+	_, err := exec.LookPath("hg")
+	if err != nil {
+		fmt.Println("Skipping cmd/api checks; hg not available")
+		return
+	}
+
+	gopath := prepGoPath()
+
+	cmd := exec.Command("go", "install", "--tags=api_tool", "cmd/api")
+	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", "go1.3", "go1.4", "go1.5"),
+	out, err = exec.Command("go", "tool", "api",
+		"-c", file("go1", "go1.1", "go1.2", "go1.3", "go1.4"),
 		"-next", file("next"),
 		"-except", file("except")).CombinedOutput()
 	if err != nil {
@@ -35,6 +63,22 @@ func main() {
 	fmt.Print(string(out))
 }
 
+// filterOut returns a copy of the src environment without environment
+// variables from remove.
+// TODO: delete when issue 6201 is fixed.
+func filterOut(src []string, remove ...string) (out []string) {
+S:
+	for _, s := range src {
+		for _, r := range remove {
+			if strings.HasPrefix(s, r) && strings.HasPrefix(s, r+"=") {
+				continue S
+			}
+		}
+		out = append(out, s)
+	}
+	return
+}
+
 // file expands s to $GOROOT/api/s.txt.
 // If there are more than 1, they're comma-separated.
 func file(s ...string) string {
@@ -43,3 +87,99 @@ func file(s ...string) string {
 	}
 	return filepath.Join(goroot, "api", s[0]+".txt")
 }
+
+// prepGoPath returns a GOPATH for the "go" tool to compile the API tool with.
+// It tries to re-use a go.tools checkout from a previous run if possible,
+// else it hg clones it.
+func prepGoPath() string {
+	const tempBase = "go.tools.TMP"
+
+	username := ""
+	u, err := user.Current()
+	if err == nil {
+		username = u.Username
+	} else {
+		username = os.Getenv("USER")
+		if username == "" {
+			username = "nobody"
+		}
+	}
+
+	// The GOPATH we'll return
+	gopath := filepath.Join(os.TempDir(), "gopath-api-"+cleanUsername(username)+"-"+cleanUsername(strings.Fields(runtime.Version())[0]), goToolsVersion)
+
+	// cloneDir is where we run "hg clone".
+	cloneDir := filepath.Join(gopath, "src", "code.google.com", "p")
+
+	// The dir we clone into. We only atomically rename it to finalDir on
+	// clone success.
+	tmpDir := filepath.Join(cloneDir, tempBase)
+
+	// finalDir is where the checkout will live once it's complete.
+	finalDir := filepath.Join(cloneDir, "go.tools")
+
+	if goToolsCheckoutGood(finalDir) {
+		return gopath
+	}
+	os.RemoveAll(finalDir) // in case it's there but corrupt
+	os.RemoveAll(tmpDir)   // in case of aborted hg clone before
+
+	if err := os.MkdirAll(cloneDir, 0700); err != nil {
+		log.Fatal(err)
+	}
+	cmd := exec.Command("hg",
+		"clone", "--rev="+goToolsVersion,
+		"https://code.google.com/p/go.tools",
+		tempBase)
+	cmd.Dir = cloneDir
+	out, err := cmd.CombinedOutput()
+	if err != nil {
+		if _, err := http.Head("http://ip.appspot.com/"); err != nil {
+			log.Printf("# Skipping API check; network appears to be unavailable")
+			os.Exit(0)
+		}
+		log.Fatalf("Error running hg clone on go.tools: %v\n%s", err, out)
+	}
+	if err := os.Rename(tmpDir, finalDir); err != nil {
+		log.Fatal(err)
+	}
+	return gopath
+}
+
+func cleanUsername(n string) string {
+	b := make([]rune, len(n))
+	for i, r := range n {
+		if r == '\\' || r == '/' || r == ':' {
+			b[i] = '_'
+		} else {
+			b[i] = r
+		}
+	}
+	return string(b)
+}
+
+func goToolsCheckoutGood(dir string) bool {
+	if _, err := os.Stat(dir); err != nil {
+		return false
+	}
+
+	cmd := exec.Command("hg", "id", "--id")
+	cmd.Dir = dir
+	out, err := cmd.Output()
+	if err != nil {
+		return false
+	}
+	id := strings.TrimSpace(string(out))
+	if id != goToolsVersion {
+		return false
+	}
+
+	cmd = exec.Command("hg", "status")
+	cmd.Dir = dir
+	out, err = cmd.Output()
+	if err != nil || len(out) > 0 {
+		return false
+	}
+
+	return true
+}
diff --git a/src/cmd/cc/Makefile b/src/cmd/cc/Makefile
new file mode 100644
index 0000000..34df31d
--- /dev/null
+++ b/src/cmd/cc/Makefile
@@ -0,0 +1,10 @@
+# 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
+
+install: y.tab.h
+
+y.tab.h: cc.y
+	LANG=C LANGUAGE=en_US.UTF8 bison -d -v -y cc.y
diff --git a/src/cmd/cc/acid.c b/src/cmd/cc/acid.c
new file mode 100644
index 0000000..23147e5
--- /dev/null
+++ b/src/cmd/cc/acid.c
@@ -0,0 +1,344 @@
+// Inferno utils/cc/acid.c
+// http://code.google.com/p/inferno-os/source/browse/utils/cc/acid.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 "cc.h"
+
+static char *kwd[] =
+{
+	"$adt", "$aggr", "$append", "$complex", "$defn",
+	"$delete", "$do", "$else", "$eval", "$head", "$if",
+	"$local", "$loop", "$return", "$tail", "$then",
+	"$union", "$whatis", "$while",
+};
+
+char*
+amap(char *s)
+{
+	int i, bot, top, new;
+
+	bot = 0;
+	top = bot + nelem(kwd) - 1;
+	while(bot <= top){
+		new = bot + (top - bot)/2;
+		i = strcmp(kwd[new]+1, s);
+		if(i == 0)
+			return kwd[new];
+
+		if(i < 0)
+			bot = new + 1;
+		else
+			top = new - 1;
+	}
+	return s;
+}
+
+Sym*
+acidsue(Type *t)
+{
+	int h;
+	Sym *s;
+
+	if(t != T)
+	for(h=0; h<nelem(hash); h++)
+		for(s = hash[h]; s != S; s = s->link)
+			if(s->suetag && s->suetag->link == t)
+				return s;
+	return 0;
+}
+
+Sym*
+acidfun(Type *t)
+{
+	int h;
+	Sym *s;
+
+	for(h=0; h<nelem(hash); h++)
+		for(s = hash[h]; s != S; s = s->link)
+			if(s->type == t)
+				return s;
+	return 0;
+}
+
+char	acidchar[NTYPE];
+Init	acidcinit[] =
+{
+	TCHAR,		'C',	0,
+	TUCHAR,		'b',	0,
+	TSHORT,		'd',	0,
+	TUSHORT,	'u',	0,
+	TLONG,		'D',	0,
+	TULONG,		'U',	0,
+	TVLONG,		'V',	0,
+	TUVLONG,	'W',	0,
+	TFLOAT,		'f',	0,
+	TDOUBLE,	'F',	0,
+	TARRAY,		'a',	0,
+	TIND,		'X',	0,
+	-1,		0,	0,
+};
+
+static void
+acidinit(void)
+{
+	Init *p;
+
+	for(p=acidcinit; p->code >= 0; p++)
+		acidchar[p->code] = p->value;
+
+	acidchar[TINT] = acidchar[TLONG];
+	acidchar[TUINT] = acidchar[TULONG];
+	if(types[TINT]->width != types[TLONG]->width) {
+		acidchar[TINT] = acidchar[TSHORT];
+		acidchar[TUINT] = acidchar[TUSHORT];
+		if(types[TINT]->width != types[TSHORT]->width)
+			warn(Z, "acidmember int not long or short");
+	}
+	if(types[TIND]->width == types[TUVLONG]->width)
+		acidchar[TIND] = 'Y';
+	
+}
+
+void
+acidmember(Type *t, int32 off, int flag)
+{
+	Sym *s, *s1;
+	Type *l;
+	static int acidcharinit = 0;
+
+	if(acidcharinit == 0) {
+		acidinit();
+		acidcharinit = 1;
+	}
+	s = t->sym;
+	switch(t->etype) {
+	default:
+		Bprint(&outbuf, "	T%d\n", t->etype);
+		break;
+
+	case TIND:
+		if(s == S)
+			break;
+		l = t->link;
+		if(flag) { 
+			if(typesu[l->etype]) {
+				s1 = acidsue(l->link);
+				if(s1 != S) {
+					Bprint(&outbuf, "	'A' %s %d %s;\n",
+						amap(s1->name),
+						t->offset+off, amap(s->name));
+					break;
+				}
+			}
+		} else {
+			l = t->link;
+			s1 = S;
+			if(typesu[l->etype])
+				s1 = acidsue(l->link);
+			if(s1 != S) {
+				Bprint(&outbuf,
+					"\tprint(indent, \"%s\t(%s)\", addr.%s\\X, \"\\n\");\n",
+					amap(s->name), amap(s1->name), amap(s->name));
+			} else {
+				Bprint(&outbuf,
+					"\tprint(indent, \"%s\t\", addr.%s\\X, \"\\n\");\n",
+					amap(s->name), amap(s->name));
+			}
+			break;
+		}
+
+	case TINT:
+	case TUINT:
+	case TCHAR:
+	case TUCHAR:
+	case TSHORT:
+	case TUSHORT:
+	case TLONG:
+	case TULONG:
+	case TVLONG:
+	case TUVLONG:
+	case TFLOAT:
+	case TDOUBLE:
+	case TARRAY:
+		if(s == S)
+			break;
+		if(flag) {
+			Bprint(&outbuf, "	'%c' %d %s;\n",
+			acidchar[t->etype], t->offset+off, amap(s->name));
+		} else {
+			Bprint(&outbuf, "\tprint(indent, \"%s\t\", addr.%s, \"\\n\");\n",
+				amap(s->name), amap(s->name));
+		}
+		break;
+
+	case TSTRUCT:
+	case TUNION:
+		s1 = acidsue(t->link);
+		if(s1 == S)
+			break;
+		if(flag) {
+			if(s == S) {
+				Bprint(&outbuf, "	{\n");
+				for(l = t->link; l != T; l = l->down)
+					acidmember(l, t->offset+off, flag);
+				Bprint(&outbuf, "	};\n");
+			} else {
+				Bprint(&outbuf, "	%s %d %s;\n",
+					amap(s1->name),
+					t->offset+off, amap(s->name));
+			}
+		} else {
+			if(s != S) {
+				Bprint(&outbuf, "\tprint(indent, \"%s %s {\\n\");\n",
+					amap(s1->name), amap(s->name));
+				Bprint(&outbuf, "\tindent_%s(addr.%s, indent+\"\\t\");\n",
+					amap(s1->name), amap(s->name));
+				Bprint(&outbuf, "\tprint(indent, \"}\\n\");\n");
+			} else {
+				Bprint(&outbuf, "\tprint(indent, \"%s {\\n\");\n",
+					amap(s1->name));
+				Bprint(&outbuf, "\tindent_%s(addr+%d, indent+\"\\t\");\n",
+					amap(s1->name), t->offset+off);
+				Bprint(&outbuf, "\tprint(indent, \"}\\n\");\n");
+			}
+		}
+		break;
+	}
+}
+
+void
+acidtype(Type *t)
+{
+	Sym *s;
+	Type *l;
+	Io *i;
+	int n;
+	char *an;
+
+	if(!debug['a'])
+		return;
+	if(debug['a'] > 1) {
+		n = 0;
+		for(i=iostack; i; i=i->link)
+			n++;
+		if(n > 1)
+			return;
+	}
+	s = acidsue(t->link);
+	if(s == S)
+		return;
+	switch(t->etype) {
+	default:
+		Bprint(&outbuf, "T%d\n", t->etype);
+		return;
+
+	case TUNION:
+	case TSTRUCT:
+		if(debug['s'])
+			goto asmstr;
+		an = amap(s->name);
+		Bprint(&outbuf, "sizeof%s = %d;\n", an, t->width);
+		Bprint(&outbuf, "aggr %s\n{\n", an);
+		for(l = t->link; l != T; l = l->down)
+			acidmember(l, 0, 1);
+		Bprint(&outbuf, "};\n\n");
+
+		Bprint(&outbuf, "defn\n%s(addr) {\n\tindent_%s(addr, \"\\t\");\n}\n", an, an);
+		Bprint(&outbuf, "defn\nindent_%s(addr, indent) {\n\tcomplex %s addr;\n", an, an);
+		for(l = t->link; l != T; l = l->down)
+			acidmember(l, 0, 0);
+		Bprint(&outbuf, "};\n\n");
+		break;
+	asmstr:
+		if(s == S)
+			break;
+		for(l = t->link; l != T; l = l->down)
+			if(l->sym != S)
+				Bprint(&outbuf, "#define\t%s.%s\t%d\n",
+					s->name,
+					l->sym->name,
+					l->offset);
+		break;
+	}
+}
+
+void
+acidvar(Sym *s)
+{
+	int n;
+	Io *i;
+	Type *t;
+	Sym *s1, *s2;
+
+	if(!debug['a'] || debug['s'])
+		return;
+	if(debug['a'] > 1) {
+		n = 0;
+		for(i=iostack; i; i=i->link)
+			n++;
+		if(n > 1)
+			return;
+	}
+	t = s->type;
+	while(t && t->etype == TIND)
+		t = t->link;
+	if(t == T)
+		return;
+	if(t->etype == TENUM) {
+		Bprint(&outbuf, "%s = ", amap(s->name));
+		if(!typefd[t->etype])
+			Bprint(&outbuf, "%lld;\n", s->vconst);
+		else
+			Bprint(&outbuf, "%f\n;", s->fconst);
+		return;
+	}
+	if(!typesu[t->etype])
+		return;
+	s1 = acidsue(t->link);
+	if(s1 == S)
+		return;
+	switch(s->class) {
+	case CAUTO:
+	case CPARAM:
+		s2 = acidfun(thisfn);
+		if(s2)
+			Bprint(&outbuf, "complex %s %s:%s;\n",
+				amap(s1->name), amap(s2->name), amap(s->name));
+		break;
+	
+	case CSTATIC:
+	case CEXTERN:
+	case CGLOBL:
+	case CLOCAL:
+		Bprint(&outbuf, "complex %s %s;\n",
+			amap(s1->name), amap(s->name));
+		break;
+	}
+}
diff --git a/src/cmd/cc/bits.c b/src/cmd/cc/bits.c
new file mode 100644
index 0000000..4496d65
--- /dev/null
+++ b/src/cmd/cc/bits.c
@@ -0,0 +1,120 @@
+// Inferno utils/cc/bits.c
+// http://code.google.com/p/inferno-os/source/browse/utils/cc/bits.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	"cc.h"
+
+Bits
+bor(Bits a, Bits b)
+{
+	Bits c;
+	int i;
+
+	for(i=0; i<BITS; i++)
+		c.b[i] = a.b[i] | b.b[i];
+	return c;
+}
+
+Bits
+band(Bits a, Bits b)
+{
+	Bits c;
+	int i;
+
+	for(i=0; i<BITS; i++)
+		c.b[i] = a.b[i] & b.b[i];
+	return c;
+}
+
+/*
+Bits
+bnot(Bits a)
+{
+	Bits c;
+	int i;
+
+	for(i=0; i<BITS; i++)
+		c.b[i] = ~a.b[i];
+	return c;
+}
+*/
+
+int
+bany(Bits *a)
+{
+	int i;
+
+	for(i=0; i<BITS; i++)
+		if(a->b[i])
+			return 1;
+	return 0;
+}
+
+int
+beq(Bits a, Bits b)
+{
+	int i;
+
+	for(i=0; i<BITS; i++)
+		if(a.b[i] != b.b[i])
+			return 0;
+	return 1;
+}
+
+int
+bnum(Bits a)
+{
+	int i;
+	int32 b;
+
+	for(i=0; i<BITS; i++)
+		if(b = a.b[i])
+			return 32*i + bitno(b);
+	diag(Z, "bad in bnum");
+	return 0;
+}
+
+Bits
+blsh(uint n)
+{
+	Bits c;
+
+	c = zbits;
+	c.b[n/32] = 1L << (n%32);
+	return c;
+}
+
+int
+bset(Bits a, uint n)
+{
+	if(a.b[n/32] & (1L << (n%32)))
+		return 1;
+	return 0;
+}
diff --git a/src/cmd/cc/cc.h b/src/cmd/cc/cc.h
new file mode 100644
index 0000000..9530f5c
--- /dev/null
+++ b/src/cmd/cc/cc.h
@@ -0,0 +1,835 @@
+// Inferno utils/cc/cc.h
+// http://code.google.com/p/inferno-os/source/browse/utils/cc/cc.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.
+
+#include <libc.h>
+#include <bio.h>
+#include <link.h>
+
+#ifndef	EXTERN
+#define EXTERN	extern
+#endif
+
+#undef	getc
+#undef	ungetc
+#undef	BUFSIZ
+
+#define	getc	ccgetc
+#define	ungetc	ccungetc
+
+typedef	struct	Node	Node;
+typedef	struct	Sym	Sym;
+typedef	struct	Type	Type;
+typedef	struct	Funct	Funct;
+typedef	struct	Decl	Decl;
+typedef	struct	Io	Io;
+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 */
+
+#define	BUFSIZ		8192
+#define	NSYMB		500
+#define	NHASH		1024
+#define	STRINGSZ	200
+#define	HISTSZ		20
+#define YYMAXDEPTH	500
+#define	NTERM		10
+#define	MAXALIGN	7
+
+#define	SIGN(n)		((uvlong)1<<(n-1))
+#define	MASK(n)		(SIGN(n)|(SIGN(n)-1))
+
+#define	BITS	5
+#define	NVAR	(BITS*sizeof(uint32)*8)
+struct	Bits
+{
+	uint32	b[BITS];
+};
+
+struct Bvec
+{
+	int32	n;	// number of bits
+	uint32	b[];
+};
+
+struct	Var
+{
+	vlong	offset;
+	LSym*	sym;
+	char	name;
+	char	etype;
+};
+
+struct	Node
+{
+	Node*	left;
+	Node*	right;
+	void*	label;
+	int32	pc;
+	int	reg;
+	int32	xoffset;
+	double	fconst;		/* fp constant */
+	vlong	vconst;		/* non fp const */
+	char*	cstring;	/* character string */
+	TRune*	rstring;	/* rune string */
+
+	Sym*	sym;
+	Type*	type;
+	int32	lineno;
+	uchar	op;
+	uchar	oldop;
+	uchar	xcast;
+	uchar	class;
+	uchar	etype;
+	uchar	complex;
+	uchar	addable;
+	uchar	scale;
+	uchar	garb;
+};
+#define	Z	((Node*)0)
+
+struct	Sym
+{
+	Sym*	link;
+	LSym*	lsym;
+	Type*	type;
+	Type*	suetag;
+	Type*	tenum;
+	char*	macro;
+	int32	varlineno;
+	int32	offset;
+	vlong	vconst;
+	double	fconst;
+	Node*	label;
+	ushort	lexical;
+	char	*name;
+	ushort	block;
+	ushort	sueblock;
+	uchar	class;
+	uchar	sym;
+	uchar	aused;
+	uchar	sig;
+	uchar	dataflag;
+};
+#define	S	((Sym*)0)
+
+enum{
+	SIGNONE = 0,
+	SIGDONE = 1,
+	SIGINTERN = 2,
+
+	SIGNINTERN = 1729*325*1729,
+};
+
+struct	Decl
+{
+	Decl*	link;
+	Sym*	sym;
+	Type*	type;
+	int32	varlineno;
+	int32	offset;
+	short	val;
+	ushort	block;
+	uchar	class;
+	uchar	aused;
+};
+#define	D	((Decl*)0)
+
+struct	Type
+{
+	Sym*	sym;
+	Sym*	tag;
+	Funct*	funct;
+	Type*	link;
+	Type*	down;
+	int32	width;
+	int32	offset;
+	int32	lineno;
+	uchar	shift;
+	uchar	nbits;
+	uchar	etype;
+	uchar	garb;
+	uchar	align;
+};
+
+#define	T	((Type*)0)
+#define	NODECL	((void(*)(int, Type*, Sym*))0)
+
+struct	Init			/* general purpose initialization */
+{
+	int	code;
+	uint32	value;
+	char*	s;
+};
+
+EXTERN struct
+{
+	char*	p;
+	int	c;
+} fi;
+
+struct	Io
+{
+	Io*	link;
+	char*	p;
+	char	b[BUFSIZ];
+	short	c;
+	short	f;
+};
+#define	I	((Io*)0)
+
+struct	Term
+{
+	vlong	mult;
+	Node	*node;
+};
+
+enum
+{
+	Axxx,
+	Ael1,
+	Ael2,
+	Asu2,
+	Aarg0,
+	Aarg1,
+	Aarg2,
+	Aaut3,
+	NALIGN,
+};
+
+enum
+{
+	DMARK,
+	DAUTO,
+	DSUE,
+	DLABEL,
+};
+enum
+{
+	OXXX,
+	OADD,
+	OADDR,
+	OAND,
+	OANDAND,
+	OARRAY,
+	OAS,
+	OASI,
+	OASADD,
+	OASAND,
+	OASASHL,
+	OASASHR,
+	OASDIV,
+	OASHL,
+	OASHR,
+	OASLDIV,
+	OASLMOD,
+	OASLMUL,
+	OASLSHR,
+	OASMOD,
+	OASMUL,
+	OASOR,
+	OASSUB,
+	OASXOR,
+	OBIT,
+	OBREAK,
+	OCASE,
+	OCAST,
+	OCOMMA,
+	OCOND,
+	OCONST,
+	OCONTINUE,
+	ODIV,
+	ODOT,
+	ODOTDOT,
+	ODWHILE,
+	OENUM,
+	OEQ,
+	OEXREG,
+	OFOR,
+	OFUNC,
+	OGE,
+	OGOTO,
+	OGT,
+	OHI,
+	OHS,
+	OIF,
+	OIND,
+	OINDREG,
+	OINIT,
+	OLABEL,
+	OLDIV,
+	OLE,
+	OLIST,
+	OLMOD,
+	OLMUL,
+	OLO,
+	OLS,
+	OLSHR,
+	OLT,
+	OMOD,
+	OMUL,
+	ONAME,
+	ONE,
+	ONOT,
+	OOR,
+	OOROR,
+	OPOSTDEC,
+	OPOSTINC,
+	OPREDEC,
+	OPREINC,
+	OPREFETCH,
+	OPROTO,
+	OREGISTER,
+	ORETURN,
+	OSET,
+	OSIGN,
+	OSIZE,
+	OSTRING,
+	OLSTRING,
+	OSTRUCT,
+	OSUB,
+	OSWITCH,
+	OUNION,
+	OUSED,
+	OWHILE,
+	OXOR,
+	ONEG,
+	OCOM,
+	OPOS,
+	OELEM,
+
+	OTST,		/* used in some compilers */
+	OINDEX,
+	OFAS,
+	OREGPAIR,
+	OROTL,
+
+	OEND
+};
+enum
+{
+	TXXX,
+	TCHAR,
+	TUCHAR,
+	TSHORT,
+	TUSHORT,
+	TINT,
+	TUINT,
+	TLONG,
+	TULONG,
+	TVLONG,
+	TUVLONG,
+	TFLOAT,
+	TDOUBLE,
+	TIND,
+	TFUNC,
+	TARRAY,
+	TVOID,
+	TSTRUCT,
+	TUNION,
+	TENUM,
+	NTYPE,
+
+	TAUTO	= NTYPE,
+	TEXTERN,
+	TSTATIC,
+	TTYPEDEF,
+	TTYPESTR,
+	TREGISTER,
+	TCONSTNT,
+	TVOLATILE,
+	TUNSIGNED,
+	TSIGNED,
+	TDOT,
+	TFILE,
+	TOLD,
+	NALLTYPES,
+
+	/* adapt size of Rune to target system's size */
+	TRUNE = sizeof(TRune)==4? TUINT: TUSHORT,
+};
+enum
+{
+	CXXX,
+	CAUTO,
+	CEXTERN,
+	CGLOBL,
+	CSTATIC,
+	CLOCAL,
+	CTYPEDEF,
+	CTYPESTR,
+	CPARAM,
+	CSELEM,
+	CLABEL,
+	CEXREG,
+	NCTYPES,
+};
+enum
+{
+	GXXX		= 0,
+	GCONSTNT	= 1<<0,
+	GVOLATILE	= 1<<1,
+	NGTYPES		= 1<<2,
+
+	GINCOMPLETE	= 1<<2,
+};
+enum
+{
+	BCHAR		= 1L<<TCHAR,
+	BUCHAR		= 1L<<TUCHAR,
+	BSHORT		= 1L<<TSHORT,
+	BUSHORT		= 1L<<TUSHORT,
+	BINT		= 1L<<TINT,
+	BUINT		= 1L<<TUINT,
+	BLONG		= 1L<<TLONG,
+	BULONG		= 1L<<TULONG,
+	BVLONG		= 1L<<TVLONG,
+	BUVLONG		= 1L<<TUVLONG,
+	BFLOAT		= 1L<<TFLOAT,
+	BDOUBLE		= 1L<<TDOUBLE,
+	BIND		= 1L<<TIND,
+	BFUNC		= 1L<<TFUNC,
+	BARRAY		= 1L<<TARRAY,
+	BVOID		= 1L<<TVOID,
+	BSTRUCT		= 1L<<TSTRUCT,
+	BUNION		= 1L<<TUNION,
+	BENUM		= 1L<<TENUM,
+	BFILE		= 1L<<TFILE,
+	BDOT		= 1L<<TDOT,
+	BCONSTNT	= 1L<<TCONSTNT,
+	BVOLATILE	= 1L<<TVOLATILE,
+	BUNSIGNED	= 1L<<TUNSIGNED,
+	BSIGNED		= 1L<<TSIGNED,
+	BAUTO		= 1L<<TAUTO,
+	BEXTERN		= 1L<<TEXTERN,
+	BSTATIC		= 1L<<TSTATIC,
+	BTYPEDEF	= 1L<<TTYPEDEF,
+	BTYPESTR	= 1L<<TTYPESTR,
+	BREGISTER	= 1L<<TREGISTER,
+
+	BINTEGER	= BCHAR|BUCHAR|BSHORT|BUSHORT|BINT|BUINT|
+				BLONG|BULONG|BVLONG|BUVLONG,
+	BNUMBER		= BINTEGER|BFLOAT|BDOUBLE,
+
+/* these can be overloaded with complex types */
+
+	BCLASS		= BAUTO|BEXTERN|BSTATIC|BTYPEDEF|BTYPESTR|BREGISTER,
+	BGARB		= BCONSTNT|BVOLATILE,
+};
+
+struct	Funct
+{
+	Sym*	sym[OEND];
+	Sym*	castto[NTYPE];
+	Sym*	castfr[NTYPE];
+};
+
+EXTERN struct
+{
+	Type*	tenum;		/* type of entire enum */
+	Type*	cenum;		/* type of current enum run */
+	vlong	lastenum;	/* value of current enum */
+	double	floatenum;	/* value of current enum */
+} en;
+
+EXTERN	int	autobn;
+EXTERN	int32	autoffset;
+EXTERN	int	blockno;
+EXTERN	Decl*	dclstack;
+EXTERN	int	debug[256];
+EXTERN	int32	firstbit;
+EXTERN	Sym*	firstarg;
+EXTERN	Type*	firstargtype;
+EXTERN	Decl*	firstdcl;
+EXTERN	int	fperror;
+EXTERN	Sym*	hash[NHASH];
+EXTERN	char*	hunk;
+EXTERN	char**	include;
+EXTERN	Io*	iofree;
+EXTERN	Io*	ionext;
+EXTERN	Io*	iostack;
+EXTERN	int32	lastbit;
+EXTERN	char	lastclass;
+EXTERN	Type*	lastdcl;
+EXTERN	int32	lastfield;
+EXTERN	Type*	lasttype;
+EXTERN	int32	lineno;
+EXTERN	int32	nearln;
+EXTERN	int	nerrors;
+EXTERN	int	newflag;
+EXTERN	int32	nhunk;
+EXTERN	int	ninclude;
+EXTERN	Node*	nodproto;
+EXTERN	Node*	nodcast;
+EXTERN	int32	nsymb;
+EXTERN	Biobuf	outbuf;
+EXTERN	Biobuf	diagbuf;
+EXTERN	char*	outfile;
+EXTERN	int	peekc;
+EXTERN	int32	stkoff;
+EXTERN	Type*	strf;
+EXTERN	Type*	strl;
+EXTERN	char*	symb;
+EXTERN	Sym*	symstring;
+EXTERN	int	taggen;
+EXTERN	Type*	tfield;
+EXTERN	Type*	tufield;
+extern	int	thechar;
+extern	char*	thestring;
+extern	LinkArch*	thelinkarch;
+EXTERN	Type*	thisfn;
+EXTERN	int32	thunk;
+EXTERN	Type*	types[NALLTYPES];
+EXTERN	Type*	fntypes[NALLTYPES];
+EXTERN	Node*	initlist;
+EXTERN	Term	term[NTERM];
+EXTERN	int	nterm;
+EXTERN	int	packflg;
+EXTERN	int	fproundflg;
+EXTERN	int	textflag;
+EXTERN	int	dataflag;
+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[];
+extern	uchar	tab[NTYPE][NTYPE];
+extern	uchar	comrel[], invrel[], logrel[];
+extern	int32	ncast[], tadd[], tand[];
+extern	int32	targ[], tasadd[], tasign[], tcast[];
+extern	int32	tdot[], tfunct[], tindir[], tmul[];
+extern	int32	tnot[], trel[], tsub[];
+
+extern	uchar	typeaf[];
+extern	uchar	typefd[];
+extern	uchar	typei[];
+extern	uchar	typesu[];
+extern	uchar	typesuv[];
+extern	uchar	typeu[];
+extern	uchar	typev[];
+extern	uchar	typec[];
+extern	uchar	typeh[];
+extern	uchar	typeil[];
+extern	uchar	typeilp[];
+extern	uchar	typechl[];
+extern	uchar	typechlv[];
+extern	uchar	typechlvp[];
+extern	uchar	typechlp[];
+extern	uchar	typechlpfd[];
+
+EXTERN	uchar*	typeword;
+EXTERN	uchar*	typecmplx;
+EXTERN	Link*	ctxt;
+
+extern	uint32	thash1;
+extern	uint32	thash2;
+extern	uint32	thash3;
+extern	uint32	thash[];
+
+/*
+ *	compat.c/unix.c/windows.c
+ */
+int	systemtype(int);
+int	pathchar(void);
+
+/*
+ *	parser
+ */
+int	yyparse(void);
+int	mpatov(char*, vlong*);
+
+/*
+ *	lex.c
+ */
+void*	allocn(void*, int32, int32);
+void*	alloc(int32);
+void    ensuresymb(int32);
+void	cinit(void);
+int	compile(char*, char**, int);
+void	errorexit(void);
+int	filbuf(void);
+int	getc(void);
+int32	getr(void);
+int	getnsc(void);
+Sym*	lookup(void);
+void	main(int, char*[]);
+void	newfile(char*, int);
+void	newio(void);
+void	pushio(void);
+int32	escchar(int32, int, int);
+Sym*	slookup(char*);
+void	syminit(Sym*);
+void	unget(int);
+int32	yylex(void);
+int	Lconv(Fmt*);
+int	Tconv(Fmt*);
+int	FNconv(Fmt*);
+int	Oconv(Fmt*);
+int	Qconv(Fmt*);
+int	VBconv(Fmt*);
+int	Bconv(Fmt*);
+void	setinclude(char*);
+
+/*
+ * mac.c
+ */
+void	dodefine(char*);
+void	domacro(void);
+Sym*	getsym(void);
+int32	getnsn(void);
+void	macdef(void);
+void	macprag(void);
+void	macend(void);
+void	macexpand(Sym*, char*);
+void	macif(int);
+void	macinc(void);
+void	maclin(void);
+void	macund(void);
+
+/*
+ * dcl.c
+ */
+Node*	doinit(Sym*, Type*, int32, Node*);
+Type*	tcopy(Type*);
+Node*	init1(Sym*, Type*, int32, int);
+Node*	newlist(Node*, Node*);
+void	adecl(int, Type*, Sym*);
+int	anyproto(Node*);
+void	argmark(Node*, int);
+void	dbgdecl(Sym*);
+Node*	dcllabel(Sym*, int);
+Node*	dodecl(void(*)(int, Type*, Sym*), int, Type*, Node*);
+Sym*	mkstatic(Sym*);
+void	doenum(Sym*, Node*);
+void	snap(Type*);
+Type*	dotag(Sym*, int, int);
+void	edecl(int, Type*, Sym*);
+Type*	fnproto(Node*);
+Type*	fnproto1(Node*);
+void	markdcl(void);
+Type*	paramconv(Type*, int);
+void	pdecl(int, Type*, Sym*);
+Decl*	push(void);
+Decl*	push1(Sym*);
+Node*	revertdcl(void);
+int32	xround(int32, int);
+int	rsametype(Type*, Type*, int, int);
+int	sametype(Type*, Type*);
+uint32	sign(Sym*);
+uint32	signature(Type*);
+void	sualign(Type*);
+void	tmerge(Type*, Sym*);
+void	walkparam(Node*, int);
+void	xdecl(int, Type*, Sym*);
+Node*	contig(Sym*, Node*, int32);
+
+/*
+ * com.c
+ */
+void	ccom(Node*);
+void	complex(Node*);
+int	tcom(Node*);
+int	tcoma(Node*, Node*, Type*, int);
+int	tcomd(Node*);
+int	tcomo(Node*, int);
+int	tcomx(Node*);
+int	tlvalue(Node*);
+void	constas(Node*, Type*, Type*);
+
+/*
+ * con.c
+ */
+void	acom(Node*);
+void	acom1(vlong, Node*);
+void	acom2(Node*, Type*);
+int	acomcmp1(const void*, const void*);
+int	acomcmp2(const void*, const void*);
+int	addo(Node*);
+void	evconst(Node*);
+
+/*
+ * funct.c
+ */
+int	isfunct(Node*);
+void	dclfunct(Type*, Sym*);
+
+/*
+ * sub.c
+ */
+void	arith(Node*, int);
+int	deadheads(Node*);
+Type*	dotsearch(Sym*, Type*, Node*, int32*);
+int32	dotoffset(Type*, Type*, Node*);
+void	gethunk(void);
+Node*	invert(Node*);
+int	bitno(int32);
+void	makedot(Node*, Type*, int32);
+int	mixedasop(Type*, Type*);
+Node*	new(int, Node*, Node*);
+Node*	new1(int, Node*, Node*);
+int	nilcast(Type*, Type*);
+int	nocast(Type*, Type*);
+void	prtree(Node*, char*);
+void	prtree1(Node*, int, int);
+void	relcon(Node*, Node*);
+int	relindex(int);
+int	simpleg(int32);
+Type*	garbt(Type*, int32);
+int	simplec(int32);
+Type*	simplet(int32);
+int	stcompat(Node*, Type*, Type*, int32[]);
+int	tcompat(Node*, Type*, Type*, int32[]);
+void	tinit(void);
+Type*	typ(int, Type*);
+Type*	copytyp(Type*);
+void	typeext(Type*, Node*);
+void	typeext1(Type*, Node*);
+int	side(Node*);
+int	vconst(Node*);
+int	xlog2(uvlong);
+int	vlog(Node*);
+int	topbit(uint32);
+void	simplifyshift(Node*);
+int32	typebitor(int32, int32);
+void	diag(Node*, char*, ...);
+void	warn(Node*, char*, ...);
+void	yyerror(char*, ...);
+void	fatal(Node*, char*, ...);
+LSym*	linksym(Sym*);
+
+/*
+ * acid.c
+ */
+void	acidtype(Type*);
+void	acidvar(Sym*);
+
+/*
+ * godefs.c
+ */
+int	Uconv(Fmt*);
+void	godeftype(Type*);
+void	godefvar(Sym*);
+
+/*
+ * bits.c
+ */
+Bits	bor(Bits, Bits);
+Bits	band(Bits, Bits);
+Bits	bnot(Bits);
+int	bany(Bits*);
+int	bnum(Bits);
+Bits	blsh(uint);
+int	beq(Bits, Bits);
+int	bset(Bits, uint);
+
+/*
+ * dpchk.c
+ */
+void	dpcheck(Node*);
+void	arginit(void);
+void	pragvararg(void);
+void	pragpack(void);
+void	pragfpround(void);
+void	pragdataflag(void);
+void	pragtextflag(void);
+void	pragincomplete(void);
+void	pragcgo(char*);
+
+/*
+ * calls to machine depend part
+ */
+void	codgen(Node*, Node*);
+void	gclean(void);
+void	gextern(Sym*, Node*, int32, int32);
+void	ginit(void);
+int32	outstring(char*, int32);
+int32	outlstring(TRune*, int32);
+void	sextern(Sym*, Node*, int32, int32);
+void	xcom(Node*);
+int32	exreg(Type*);
+int32	align(int32, Type*, int, int32*);
+int32	maxround(int32, int32);
+int	hasdotdotdot(Type*);
+void    linkarchinit(void);
+
+extern	schar	ewidth[];
+
+/*
+ * com64
+ */
+int	com64(Node*);
+void	com64init(void);
+void	bool64(Node*);
+double	convvtof(vlong);
+vlong	convftov(double);
+double	convftox(double, int);
+vlong	convvtox(vlong, int);
+
+/*
+ * machcap
+ */
+int	machcap(Node*);
+
+#pragma	varargck	argpos	warn	2
+#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
+#pragma	varargck	type	"O"	int
+#pragma	varargck	type	"O"	uint
+#pragma	varargck	type	"T"	Type*
+#pragma	varargck	type	"U"	char*
+#pragma	varargck	type	"|"	int
+
+enum
+{
+	Plan9	= 1<<0,
+	Unix	= 1<<1,
+	Windows	= 1<<2,
+};
+int	pathchar(void);
+int	systemtype(int);
+void*	alloc(int32 n);
+void*	allocn(void*, int32, int32);
diff --git a/src/cmd/cc/cc.y b/src/cmd/cc/cc.y
new file mode 100644
index 0000000..8d7cb14
--- /dev/null
+++ b/src/cmd/cc/cc.y
@@ -0,0 +1,1220 @@
+// Inferno utils/cc/cc.y
+// http://code.google.com/p/inferno-os/source/browse/utils/cc/cc.y
+//
+//	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 <stdio.h>	/* if we don't, bison will, and cc.h re-#defines getc */
+#include "cc.h"
+%}
+%union	{
+	Node*	node;
+	Sym*	sym;
+	Type*	type;
+	struct
+	{
+		Type*	t;
+		uchar	c;
+	} tycl;
+	struct
+	{
+		Type*	t1;
+		Type*	t2;
+		Type*	t3;
+		uchar	c;
+	} tyty;
+	struct
+	{
+		char*	s;
+		int32	l;
+	} sval;
+	int32	lval;
+	double	dval;
+	vlong	vval;
+}
+%type	<sym>	ltag
+%type	<lval>	gctname gcname cname gname tname
+%type	<lval>	gctnlist gcnlist zgnlist
+%type	<type>	tlist sbody complex
+%type	<tycl>	types
+%type	<node>	zarglist arglist zcexpr
+%type	<node>	name block stmnt cexpr expr xuexpr pexpr
+%type	<node>	zelist elist adecl slist uexpr string lstring
+%type	<node>	xdecor xdecor2 labels label ulstmnt
+%type	<node>	adlist edecor tag qual qlist
+%type	<node>	abdecor abdecor1 abdecor2 abdecor3
+%type	<node>	zexpr lexpr init ilist forexpr
+
+%left	';'
+%left	','
+%right	'=' LPE LME LMLE LDVE LMDE LRSHE LLSHE LANDE LXORE LORE
+%right	'?' ':'
+%left	LOROR
+%left	LANDAND
+%left	'|'
+%left	'^'
+%left	'&'
+%left	LEQ LNE
+%left	'<' '>' LLE LGE
+%left	LLSH LRSH
+%left	'+' '-'
+%left	'*' '/' '%'
+%right	LMM LPP LMG '.' '[' '('
+
+%token	<sym>	LNAME LTYPE
+%token	<dval>	LFCONST LDCONST
+%token	<vval>	LCONST LLCONST LUCONST LULCONST LVLCONST LUVLCONST
+%token	<sval>	LSTRING LLSTRING
+%token		LAUTO LBREAK LCASE LCHAR LCONTINUE LDEFAULT LDO
+%token		LDOUBLE LELSE LEXTERN LFLOAT LFOR LGOTO
+%token	LIF LINT LLONG LPREFETCH LREGISTER LRETURN LSHORT LSIZEOF LUSED
+%token	LSTATIC LSTRUCT LSWITCH LTYPEDEF LTYPESTR LUNION LUNSIGNED
+%token	LWHILE LVOID LENUM LSIGNED LCONSTNT LVOLATILE LSET LSIGNOF
+%token	LRESTRICT LINLINE
+%%
+prog:
+|	prog xdecl
+
+/*
+ * external declarator
+ */
+xdecl:
+	zctlist ';'
+	{
+		dodecl(xdecl, lastclass, lasttype, Z);
+	}
+|	zctlist xdlist ';'
+|	zctlist xdecor
+	{
+		lastdcl = T;
+		firstarg = S;
+		dodecl(xdecl, lastclass, lasttype, $2);
+		if(lastdcl == T || lastdcl->etype != TFUNC) {
+			diag($2, "not a function");
+			lastdcl = types[TFUNC];
+		}
+		thisfn = lastdcl;
+		markdcl();
+		firstdcl = dclstack;
+		argmark($2, 0);
+	}
+	pdecl
+	{
+		argmark($2, 1);
+	}
+	block
+	{
+		Node *n;
+
+		n = revertdcl();
+		if(n)
+			$6 = new(OLIST, n, $6);
+		if(!debug['a'] && !debug['Z'])
+			codgen($6, $2);
+	}
+
+xdlist:
+	xdecor
+	{
+		dodecl(xdecl, lastclass, lasttype, $1);
+	}
+|	xdecor
+	{
+		$1 = dodecl(xdecl, lastclass, lasttype, $1);
+	}
+	'=' init
+	{
+		doinit($1->sym, $1->type, 0L, $4);
+	}
+|	xdlist ',' xdlist
+
+xdecor:
+	xdecor2
+|	'*' zgnlist xdecor
+	{
+		$$ = new(OIND, $3, Z);
+		$$->garb = simpleg($2);
+	}
+
+xdecor2:
+	tag
+|	'(' xdecor ')'
+	{
+		$$ = $2;
+	}
+|	xdecor2 '(' zarglist ')'
+	{
+		$$ = new(OFUNC, $1, $3);
+	}
+|	xdecor2 '[' zexpr ']'
+	{
+		$$ = new(OARRAY, $1, $3);
+	}
+
+/*
+ * automatic declarator
+ */
+adecl:
+	ctlist ';'
+	{
+		$$ = dodecl(adecl, lastclass, lasttype, Z);
+	}
+|	ctlist adlist ';'
+	{
+		$$ = $2;
+	}
+
+adlist:
+	xdecor
+	{
+		dodecl(adecl, lastclass, lasttype, $1);
+		$$ = Z;
+	}
+|	xdecor
+	{
+		$1 = dodecl(adecl, lastclass, lasttype, $1);
+	}
+	'=' init
+	{
+		int32 w;
+
+		w = $1->sym->type->width;
+		$$ = doinit($1->sym, $1->type, 0L, $4);
+		$$ = contig($1->sym, $$, w);
+	}
+|	adlist ',' adlist
+	{
+		$$ = $1;
+		if($3 != Z) {
+			$$ = $3;
+			if($1 != Z)
+				$$ = new(OLIST, $1, $3);
+		}
+	}
+
+/*
+ * parameter declarator
+ */
+pdecl:
+|	pdecl ctlist pdlist ';'
+
+pdlist:
+	xdecor
+	{
+		dodecl(pdecl, lastclass, lasttype, $1);
+	}
+|	pdlist ',' pdlist
+
+/*
+ * structure element declarator
+ */
+edecl:
+	tlist
+	{
+		lasttype = $1;
+	}
+	zedlist ';'
+|	edecl tlist
+	{
+		lasttype = $2;
+	}
+	zedlist ';'
+
+zedlist:					/* extension */
+	{
+		lastfield = 0;
+		edecl(CXXX, lasttype, S);
+	}
+|	edlist
+
+edlist:
+	edecor
+	{
+		dodecl(edecl, CXXX, lasttype, $1);
+	}
+|	edlist ',' edlist
+
+edecor:
+	xdecor
+	{
+		lastbit = 0;
+		firstbit = 1;
+	}
+|	tag ':' lexpr
+	{
+		$$ = new(OBIT, $1, $3);
+	}
+|	':' lexpr
+	{
+		$$ = new(OBIT, Z, $2);
+	}
+
+/*
+ * abstract declarator
+ */
+abdecor:
+	{
+		$$ = (Z);
+	}
+|	abdecor1
+
+abdecor1:
+	'*' zgnlist
+	{
+		$$ = new(OIND, (Z), Z);
+		$$->garb = simpleg($2);
+	}
+|	'*' zgnlist abdecor1
+	{
+		$$ = new(OIND, $3, Z);
+		$$->garb = simpleg($2);
+	}
+|	abdecor2
+
+abdecor2:
+	abdecor3
+|	abdecor2 '(' zarglist ')'
+	{
+		$$ = new(OFUNC, $1, $3);
+	}
+|	abdecor2 '[' zexpr ']'
+	{
+		$$ = new(OARRAY, $1, $3);
+	}
+
+abdecor3:
+	'(' ')'
+	{
+		$$ = new(OFUNC, (Z), Z);
+	}
+|	'[' zexpr ']'
+	{
+		$$ = new(OARRAY, (Z), $2);
+	}
+|	'(' abdecor1 ')'
+	{
+		$$ = $2;
+	}
+
+init:
+	expr
+|	'{' ilist '}'
+	{
+		$$ = new(OINIT, invert($2), Z);
+	}
+
+qual:
+	'[' lexpr ']'
+	{
+		$$ = new(OARRAY, $2, Z);
+	}
+|	'.' ltag
+	{
+		$$ = new(OELEM, Z, Z);
+		$$->sym = $2;
+	}
+|	qual '='
+
+qlist:
+	init ','
+|	qlist init ','
+	{
+		$$ = new(OLIST, $1, $2);
+	}
+|	qual
+|	qlist qual
+	{
+		$$ = new(OLIST, $1, $2);
+	}
+
+ilist:
+	qlist
+|	init
+|	qlist init
+	{
+		$$ = new(OLIST, $1, $2);
+	}
+
+zarglist:
+	{
+		$$ = Z;
+	}
+|	arglist
+	{
+		$$ = invert($1);
+	}
+
+
+arglist:
+	name
+|	tlist abdecor
+	{
+		$$ = new(OPROTO, $2, Z);
+		$$->type = $1;
+	}
+|	tlist xdecor
+	{
+		$$ = new(OPROTO, $2, Z);
+		$$->type = $1;
+	}
+|	'.' '.' '.'
+	{
+		$$ = new(ODOTDOT, Z, Z);
+	}
+|	arglist ',' arglist
+	{
+		$$ = new(OLIST, $1, $3);
+	}
+
+block:
+	'{' slist '}'
+	{
+		$$ = invert($2);
+	//	if($2 != Z)
+	//		$$ = new(OLIST, $2, $$);
+		if($$ == Z)
+			$$ = new(OLIST, Z, Z);
+	}
+
+slist:
+	{
+		$$ = Z;
+	}
+|	slist adecl
+	{
+		$$ = new(OLIST, $1, $2);
+	}
+|	slist stmnt
+	{
+		$$ = new(OLIST, $1, $2);
+	}
+
+labels:
+	label
+|	labels label
+	{
+		$$ = new(OLIST, $1, $2);
+	}
+
+label:
+	LCASE expr ':'
+	{
+		$$ = new(OCASE, $2, Z);
+	}
+|	LDEFAULT ':'
+	{
+		$$ = new(OCASE, Z, Z);
+	}
+|	LNAME ':'
+	{
+		$$ = new(OLABEL, dcllabel($1, 1), Z);
+	}
+
+stmnt:
+	error ';'
+	{
+		$$ = Z;
+	}
+|	ulstmnt
+|	labels ulstmnt
+	{
+		$$ = new(OLIST, $1, $2);
+	}
+
+forexpr:
+	zcexpr
+|	ctlist adlist
+	{
+		$$ = $2;
+	}
+
+ulstmnt:
+	zcexpr ';'
+|	{
+		markdcl();
+	}
+	block
+	{
+		$$ = revertdcl();
+		if($$)
+			$$ = new(OLIST, $$, $2);
+		else
+			$$ = $2;
+	}
+|	LIF '(' cexpr ')' stmnt
+	{
+		$$ = new(OIF, $3, new(OLIST, $5, Z));
+		if($5 == Z)
+			warn($3, "empty if body");
+	}
+|	LIF '(' cexpr ')' stmnt LELSE stmnt
+	{
+		$$ = new(OIF, $3, new(OLIST, $5, $7));
+		if($5 == Z)
+			warn($3, "empty if body");
+		if($7 == Z)
+			warn($3, "empty else body");
+	}
+|	{ markdcl(); } LFOR '(' forexpr ';' zcexpr ';' zcexpr ')' stmnt
+	{
+		$$ = revertdcl();
+		if($$){
+			if($4)
+				$4 = new(OLIST, $$, $4);
+			else
+				$4 = $$;
+		}
+		$$ = new(OFOR, new(OLIST, $6, new(OLIST, $4, $8)), $10);
+	}
+|	LWHILE '(' cexpr ')' stmnt
+	{
+		$$ = new(OWHILE, $3, $5);
+	}
+|	LDO stmnt LWHILE '(' cexpr ')' ';'
+	{
+		$$ = new(ODWHILE, $5, $2);
+	}
+|	LRETURN zcexpr ';'
+	{
+		$$ = new(ORETURN, $2, Z);
+		$$->type = thisfn->link;
+	}
+|	LSWITCH '(' cexpr ')' stmnt
+	{
+		$$ = new(OCONST, Z, Z);
+		$$->vconst = 0;
+		$$->type = types[TINT];
+		$3 = new(OSUB, $$, $3);
+
+		$$ = new(OCONST, Z, Z);
+		$$->vconst = 0;
+		$$->type = types[TINT];
+		$3 = new(OSUB, $$, $3);
+
+		$$ = new(OSWITCH, $3, $5);
+	}
+|	LBREAK ';'
+	{
+		$$ = new(OBREAK, Z, Z);
+	}
+|	LCONTINUE ';'
+	{
+		$$ = new(OCONTINUE, Z, Z);
+	}
+|	LGOTO ltag ';'
+	{
+		$$ = new(OGOTO, dcllabel($2, 0), Z);
+	}
+|	LUSED '(' zelist ')' ';'
+	{
+		$$ = new(OUSED, $3, Z);
+	}
+|	LPREFETCH '(' zelist ')' ';'
+	{
+		$$ = new(OPREFETCH, $3, Z);
+	}
+|	LSET '(' zelist ')' ';'
+	{
+		$$ = new(OSET, $3, Z);
+	}
+
+zcexpr:
+	{
+		$$ = Z;
+	}
+|	cexpr
+
+zexpr:
+	{
+		$$ = Z;
+	}
+|	lexpr
+
+lexpr:
+	expr
+	{
+		$$ = new(OCAST, $1, Z);
+		$$->type = types[TLONG];
+	}
+
+cexpr:
+	expr
+|	cexpr ',' cexpr
+	{
+		$$ = new(OCOMMA, $1, $3);
+	}
+
+expr:
+	xuexpr
+|	expr '*' expr
+	{
+		$$ = new(OMUL, $1, $3);
+	}
+|	expr '/' expr
+	{
+		$$ = new(ODIV, $1, $3);
+	}
+|	expr '%' expr
+	{
+		$$ = new(OMOD, $1, $3);
+	}
+|	expr '+' expr
+	{
+		$$ = new(OADD, $1, $3);
+	}
+|	expr '-' expr
+	{
+		$$ = new(OSUB, $1, $3);
+	}
+|	expr LRSH expr
+	{
+		$$ = new(OASHR, $1, $3);
+	}
+|	expr LLSH expr
+	{
+		$$ = new(OASHL, $1, $3);
+	}
+|	expr '<' expr
+	{
+		$$ = new(OLT, $1, $3);
+	}
+|	expr '>' expr
+	{
+		$$ = new(OGT, $1, $3);
+	}
+|	expr LLE expr
+	{
+		$$ = new(OLE, $1, $3);
+	}
+|	expr LGE expr
+	{
+		$$ = new(OGE, $1, $3);
+	}
+|	expr LEQ expr
+	{
+		$$ = new(OEQ, $1, $3);
+	}
+|	expr LNE expr
+	{
+		$$ = new(ONE, $1, $3);
+	}
+|	expr '&' expr
+	{
+		$$ = new(OAND, $1, $3);
+	}
+|	expr '^' expr
+	{
+		$$ = new(OXOR, $1, $3);
+	}
+|	expr '|' expr
+	{
+		$$ = new(OOR, $1, $3);
+	}
+|	expr LANDAND expr
+	{
+		$$ = new(OANDAND, $1, $3);
+	}
+|	expr LOROR expr
+	{
+		$$ = new(OOROR, $1, $3);
+	}
+|	expr '?' cexpr ':' expr
+	{
+		$$ = new(OCOND, $1, new(OLIST, $3, $5));
+	}
+|	expr '=' expr
+	{
+		$$ = new(OAS, $1, $3);
+	}
+|	expr LPE expr
+	{
+		$$ = new(OASADD, $1, $3);
+	}
+|	expr LME expr
+	{
+		$$ = new(OASSUB, $1, $3);
+	}
+|	expr LMLE expr
+	{
+		$$ = new(OASMUL, $1, $3);
+	}
+|	expr LDVE expr
+	{
+		$$ = new(OASDIV, $1, $3);
+	}
+|	expr LMDE expr
+	{
+		$$ = new(OASMOD, $1, $3);
+	}
+|	expr LLSHE expr
+	{
+		$$ = new(OASASHL, $1, $3);
+	}
+|	expr LRSHE expr
+	{
+		$$ = new(OASASHR, $1, $3);
+	}
+|	expr LANDE expr
+	{
+		$$ = new(OASAND, $1, $3);
+	}
+|	expr LXORE expr
+	{
+		$$ = new(OASXOR, $1, $3);
+	}
+|	expr LORE expr
+	{
+		$$ = new(OASOR, $1, $3);
+	}
+
+xuexpr:
+	uexpr
+|	'(' tlist abdecor ')' xuexpr
+	{
+		$$ = new(OCAST, $5, Z);
+		dodecl(NODECL, CXXX, $2, $3);
+		$$->type = lastdcl;
+		$$->xcast = 1;
+	}
+|	'(' tlist abdecor ')' '{' ilist '}'	/* extension */
+	{
+		$$ = new(OSTRUCT, $6, Z);
+		dodecl(NODECL, CXXX, $2, $3);
+		$$->type = lastdcl;
+	}
+
+uexpr:
+	pexpr
+|	'*' xuexpr
+	{
+		$$ = new(OIND, $2, Z);
+	}
+|	'&' xuexpr
+	{
+		$$ = new(OADDR, $2, Z);
+	}
+|	'+' xuexpr
+	{
+		$$ = new(OPOS, $2, Z);
+	}
+|	'-' xuexpr
+	{
+		$$ = new(ONEG, $2, Z);
+	}
+|	'!' xuexpr
+	{
+		$$ = new(ONOT, $2, Z);
+	}
+|	'~' xuexpr
+	{
+		$$ = new(OCOM, $2, Z);
+	}
+|	LPP xuexpr
+	{
+		$$ = new(OPREINC, $2, Z);
+	}
+|	LMM xuexpr
+	{
+		$$ = new(OPREDEC, $2, Z);
+	}
+|	LSIZEOF uexpr
+	{
+		$$ = new(OSIZE, $2, Z);
+	}
+|	LSIGNOF uexpr
+	{
+		$$ = new(OSIGN, $2, Z);
+	}
+
+pexpr:
+	'(' cexpr ')'
+	{
+		$$ = $2;
+	}
+|	LSIZEOF '(' tlist abdecor ')'
+	{
+		$$ = new(OSIZE, Z, Z);
+		dodecl(NODECL, CXXX, $3, $4);
+		$$->type = lastdcl;
+	}
+|	LSIGNOF '(' tlist abdecor ')'
+	{
+		$$ = new(OSIGN, Z, Z);
+		dodecl(NODECL, CXXX, $3, $4);
+		$$->type = lastdcl;
+	}
+|	pexpr '(' zelist ')'
+	{
+		$$ = new(OFUNC, $1, Z);
+		if($1->op == ONAME)
+		if($1->type == T)
+			dodecl(xdecl, CXXX, types[TINT], $$);
+		$$->right = invert($3);
+	}
+|	pexpr '[' cexpr ']'
+	{
+		$$ = new(OIND, new(OADD, $1, $3), Z);
+	}
+|	pexpr LMG ltag
+	{
+		$$ = new(ODOT, new(OIND, $1, Z), Z);
+		$$->sym = $3;
+	}
+|	pexpr '.' ltag
+	{
+		$$ = new(ODOT, $1, Z);
+		$$->sym = $3;
+	}
+|	pexpr LPP
+	{
+		$$ = new(OPOSTINC, $1, Z);
+	}
+|	pexpr LMM
+	{
+		$$ = new(OPOSTDEC, $1, Z);
+	}
+|	name
+|	LCONST
+	{
+		$$ = new(OCONST, Z, Z);
+		$$->type = types[TINT];
+		$$->vconst = $1;
+		$$->cstring = strdup(symb);
+	}
+|	LLCONST
+	{
+		$$ = new(OCONST, Z, Z);
+		$$->type = types[TLONG];
+		$$->vconst = $1;
+		$$->cstring = strdup(symb);
+	}
+|	LUCONST
+	{
+		$$ = new(OCONST, Z, Z);
+		$$->type = types[TUINT];
+		$$->vconst = $1;
+		$$->cstring = strdup(symb);
+	}
+|	LULCONST
+	{
+		$$ = new(OCONST, Z, Z);
+		$$->type = types[TULONG];
+		$$->vconst = $1;
+		$$->cstring = strdup(symb);
+	}
+|	LDCONST
+	{
+		$$ = new(OCONST, Z, Z);
+		$$->type = types[TDOUBLE];
+		$$->fconst = $1;
+		$$->cstring = strdup(symb);
+	}
+|	LFCONST
+	{
+		$$ = new(OCONST, Z, Z);
+		$$->type = types[TFLOAT];
+		$$->fconst = $1;
+		$$->cstring = strdup(symb);
+	}
+|	LVLCONST
+	{
+		$$ = new(OCONST, Z, Z);
+		$$->type = types[TVLONG];
+		$$->vconst = $1;
+		$$->cstring = strdup(symb);
+	}
+|	LUVLCONST
+	{
+		$$ = new(OCONST, Z, Z);
+		$$->type = types[TUVLONG];
+		$$->vconst = $1;
+		$$->cstring = strdup(symb);
+	}
+|	string
+|	lstring
+
+string:
+	LSTRING
+	{
+		$$ = new(OSTRING, Z, Z);
+		$$->type = typ(TARRAY, types[TCHAR]);
+		$$->type->width = $1.l + 1;
+		$$->cstring = $1.s;
+		$$->sym = symstring;
+		$$->etype = TARRAY;
+		$$->class = CSTATIC;
+	}
+|	string LSTRING
+	{
+		char *s;
+		int n;
+
+		n = $1->type->width - 1;
+		s = alloc(n+$2.l+MAXALIGN);
+
+		memcpy(s, $1->cstring, n);
+		memcpy(s+n, $2.s, $2.l);
+		s[n+$2.l] = 0;
+
+		$$ = $1;
+		$$->type->width += $2.l;
+		$$->cstring = s;
+	}
+
+lstring:
+	LLSTRING
+	{
+		$$ = new(OLSTRING, Z, Z);
+		$$->type = typ(TARRAY, types[TRUNE]);
+		$$->type->width = $1.l + sizeof(TRune);
+		$$->rstring = (TRune*)$1.s;
+		$$->sym = symstring;
+		$$->etype = TARRAY;
+		$$->class = CSTATIC;
+	}
+|	lstring LLSTRING
+	{
+		char *s;
+		int n;
+
+		n = $1->type->width - sizeof(TRune);
+		s = alloc(n+$2.l+MAXALIGN);
+
+		memcpy(s, $1->rstring, n);
+		memcpy(s+n, $2.s, $2.l);
+		*(TRune*)(s+n+$2.l) = 0;
+
+		$$ = $1;
+		$$->type->width += $2.l;
+		$$->rstring = (TRune*)s;
+	}
+
+zelist:
+	{
+		$$ = Z;
+	}
+|	elist
+
+elist:
+	expr
+|	elist ',' elist
+	{
+		$$ = new(OLIST, $1, $3);
+	}
+
+sbody:
+	'{'
+	{
+		$<tyty>$.t1 = strf;
+		$<tyty>$.t2 = strl;
+		$<tyty>$.t3 = lasttype;
+		$<tyty>$.c = lastclass;
+		strf = T;
+		strl = T;
+		lastbit = 0;
+		firstbit = 1;
+		lastclass = CXXX;
+		lasttype = T;
+	}
+	edecl '}'
+	{
+		$$ = strf;
+		strf = $<tyty>2.t1;
+		strl = $<tyty>2.t2;
+		lasttype = $<tyty>2.t3;
+		lastclass = $<tyty>2.c;
+	}
+
+zctlist:
+	{
+		lastclass = CXXX;
+		lasttype = types[TINT];
+	}
+|	ctlist
+
+types:
+	complex
+	{
+		$$.t = $1;
+		$$.c = CXXX;
+	}
+|	tname
+	{
+		$$.t = simplet($1);
+		$$.c = CXXX;
+	}
+|	gcnlist
+	{
+		$$.t = simplet($1);
+		$$.c = simplec($1);
+		$$.t = garbt($$.t, $1);
+	}
+|	complex gctnlist
+	{
+		$$.t = $1;
+		$$.c = simplec($2);
+		$$.t = garbt($$.t, $2);
+		if($2 & ~BCLASS & ~BGARB)
+			diag(Z, "duplicate types given: %T and %Q", $1, $2);
+	}
+|	tname gctnlist
+	{
+		$$.t = simplet(typebitor($1, $2));
+		$$.c = simplec($2);
+		$$.t = garbt($$.t, $2);
+	}
+|	gcnlist complex zgnlist
+	{
+		$$.t = $2;
+		$$.c = simplec($1);
+		$$.t = garbt($$.t, $1|$3);
+	}
+|	gcnlist tname
+	{
+		$$.t = simplet($2);
+		$$.c = simplec($1);
+		$$.t = garbt($$.t, $1);
+	}
+|	gcnlist tname gctnlist
+	{
+		$$.t = simplet(typebitor($2, $3));
+		$$.c = simplec($1|$3);
+		$$.t = garbt($$.t, $1|$3);
+	}
+
+tlist:
+	types
+	{
+		$$ = $1.t;
+		if($1.c != CXXX)
+			diag(Z, "illegal combination of class 4: %s", cnames[$1.c]);
+	}
+
+ctlist:
+	types
+	{
+		lasttype = $1.t;
+		lastclass = $1.c;
+	}
+
+complex:
+	LSTRUCT ltag
+	{
+		dotag($2, TSTRUCT, 0);
+		$$ = $2->suetag;
+	}
+|	LSTRUCT ltag
+	{
+		dotag($2, TSTRUCT, autobn);
+	}
+	sbody
+	{
+		$$ = $2->suetag;
+		if($$->link != T)
+			diag(Z, "redeclare tag: %s", $2->name);
+		$$->link = $4;
+		sualign($$);
+	}
+|	LSTRUCT sbody
+	{
+		diag(Z, "struct must have tag");
+		taggen++;
+		sprint(symb, "_%d_", taggen);
+		$$ = dotag(lookup(), TSTRUCT, autobn);
+		$$->link = $2;
+		sualign($$);
+	}
+|	LUNION ltag
+	{
+		dotag($2, TUNION, 0);
+		$$ = $2->suetag;
+	}
+|	LUNION ltag
+	{
+		dotag($2, TUNION, autobn);
+	}
+	sbody
+	{
+		$$ = $2->suetag;
+		if($$->link != T)
+			diag(Z, "redeclare tag: %s", $2->name);
+		$$->link = $4;
+		sualign($$);
+	}
+|	LUNION sbody
+	{
+		taggen++;
+		sprint(symb, "_%d_", taggen);
+		$$ = dotag(lookup(), TUNION, autobn);
+		$$->link = $2;
+		sualign($$);
+	}
+|	LENUM ltag
+	{
+		dotag($2, TENUM, 0);
+		$$ = $2->suetag;
+		if($$->link == T)
+			$$->link = types[TINT];
+		$$ = $$->link;
+	}
+|	LENUM ltag
+	{
+		dotag($2, TENUM, autobn);
+	}
+	'{'
+	{
+		en.tenum = T;
+		en.cenum = T;
+	}
+	enum '}'
+	{
+		$$ = $2->suetag;
+		if($$->link != T)
+			diag(Z, "redeclare tag: %s", $2->name);
+		if(en.tenum == T) {
+			diag(Z, "enum type ambiguous: %s", $2->name);
+			en.tenum = types[TINT];
+		}
+		$$->link = en.tenum;
+		$$ = en.tenum;
+	}
+|	LENUM '{'
+	{
+		en.tenum = T;
+		en.cenum = T;
+	}
+	enum '}'
+	{
+		$$ = en.tenum;
+	}
+|	LTYPE
+	{
+		$$ = tcopy($1->type);
+	}
+
+gctnlist:
+	gctname
+|	gctnlist gctname
+	{
+		$$ = typebitor($1, $2);
+	}
+
+zgnlist:
+	{
+		$$ = 0;
+	}
+|	zgnlist gname
+	{
+		$$ = typebitor($1, $2);
+	}
+
+gctname:
+	tname
+|	gname
+|	cname
+
+gcnlist:
+	gcname
+|	gcnlist gcname
+	{
+		$$ = typebitor($1, $2);
+	}
+
+gcname:
+	gname
+|	cname
+
+enum:
+	LNAME
+	{
+		doenum($1, Z);
+	}
+|	LNAME '=' expr
+	{
+		doenum($1, $3);
+	}
+|	enum ','
+|	enum ',' enum
+
+tname:	/* type words */
+	LCHAR { $$ = BCHAR; }
+|	LSHORT { $$ = BSHORT; }
+|	LINT { $$ = BINT; }
+|	LLONG { $$ = BLONG; }
+|	LSIGNED { $$ = BSIGNED; }
+|	LUNSIGNED { $$ = BUNSIGNED; }
+|	LFLOAT { $$ = BFLOAT; }
+|	LDOUBLE { $$ = BDOUBLE; }
+|	LVOID { $$ = BVOID; }
+
+cname:	/* class words */
+	LAUTO { $$ = BAUTO; }
+|	LSTATIC { $$ = BSTATIC; }
+|	LEXTERN { $$ = BEXTERN; }
+|	LTYPEDEF { $$ = BTYPEDEF; }
+|	LTYPESTR { $$ = BTYPESTR; }
+|	LREGISTER { $$ = BREGISTER; }
+|	LINLINE { $$ = 0; }
+
+gname:	/* garbage words */
+	LCONSTNT { $$ = BCONSTNT; }
+|	LVOLATILE { $$ = BVOLATILE; }
+|	LRESTRICT { $$ = 0; }
+
+name:
+	LNAME
+	{
+		$$ = new(ONAME, Z, Z);
+		if($1->class == CLOCAL)
+			$1 = mkstatic($1);
+		$$->sym = $1;
+		$$->type = $1->type;
+		$$->etype = TVOID;
+		if($$->type != T)
+			$$->etype = $$->type->etype;
+		$$->xoffset = $1->offset;
+		$$->class = $1->class;
+		$1->aused = 1;
+	}
+tag:
+	ltag
+	{
+		$$ = new(ONAME, Z, Z);
+		$$->sym = $1;
+		$$->type = $1->type;
+		$$->etype = TVOID;
+		if($$->type != T)
+			$$->etype = $$->type->etype;
+		$$->xoffset = $1->offset;
+		$$->class = $1->class;
+	}
+ltag:
+	LNAME
+|	LTYPE
+%%
diff --git a/src/cmd/cc/com.c b/src/cmd/cc/com.c
new file mode 100644
index 0000000..4886b73
--- /dev/null
+++ b/src/cmd/cc/com.c
@@ -0,0 +1,1384 @@
+// Inferno utils/cc/com.c
+// http://code.google.com/p/inferno-os/source/browse/utils/cc/com.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 "cc.h"
+
+int compar(Node*, int);
+
+void
+complex(Node *n)
+{
+
+	if(n == Z)
+		return;
+
+	nearln = n->lineno;
+	if(debug['t'])
+		if(n->op != OCONST)
+			prtree(n, "pre complex");
+	if(tcom(n))
+		return;
+	if(debug['t'])
+		if(n->op != OCONST)
+			prtree(n, "t complex");
+	ccom(n);
+	if(debug['t'])
+		if(n->op != OCONST)
+			prtree(n, "c complex");
+	acom(n);
+	if(debug['t'])
+		if(n->op != OCONST)
+			prtree(n, "a complex");
+	xcom(n);
+	if(debug['t'])
+		if(n->op != OCONST)
+			prtree(n, "x complex");
+}
+
+/*
+ * evaluate types
+ * evaluate lvalues (addable == 1)
+ */
+enum
+{
+	ADDROF	= 1<<0,
+	CASTOF	= 1<<1,
+	ADDROP	= 1<<2,
+};
+
+int
+tcom(Node *n)
+{
+
+	return tcomo(n, ADDROF);
+}
+
+int
+tcomo(Node *n, int f)
+{
+	Node *l, *r;
+	Type *t;
+	int o;
+	static TRune zer;
+
+	if(n == Z) {
+		diag(Z, "Z in tcom");
+		errorexit();
+	}
+	n->addable = 0;
+	l = n->left;
+	r = n->right;
+
+	switch(n->op) {
+	default:
+		diag(n, "unknown op in type complex: %O", n->op);
+		goto bad;
+
+	case ODOTDOT:
+		/*
+		 * tcom has already been called on this subtree
+		 */
+		*n = *n->left;
+		if(n->type == T)
+			goto bad;
+		break;
+
+	case OCAST:
+		if(n->type == T)
+			break;
+		if(n->type->width == types[TLONG]->width) {
+			if(tcomo(l, ADDROF|CASTOF))
+				goto bad;
+		} else
+			if(tcom(l))
+				goto bad;
+		if(isfunct(n))
+			break;
+		if(tcompat(n, l->type, n->type, tcast))
+			goto bad;
+		break;
+
+	case ORETURN:
+		if(l == Z) {
+			if(n->type->etype != TVOID)
+				diag(n, "null return of a typed function");
+			break;
+		}
+		if(tcom(l))
+			goto bad;
+		typeext(n->type, l);
+		if(tcompat(n, n->type, l->type, tasign))
+			break;
+		constas(n, n->type, l->type);
+		if(!sametype(n->type, l->type)) {
+			l = new1(OCAST, l, Z);
+			l->type = n->type;
+			n->left = l;
+		}
+		break;
+
+	case OASI:	/* same as as, but no test for const */
+		n->op = OAS;
+		o = tcom(l);
+		if(o | tcom(r))
+			goto bad;
+
+		typeext(l->type, r);
+		if(tlvalue(l) || tcompat(n, l->type, r->type, tasign))
+			goto bad;
+		if(!sametype(l->type, r->type)) {
+			r = new1(OCAST, r, Z);
+			r->type = l->type;
+			n->right = r;
+		}
+		n->type = l->type;
+		break;
+
+	case OAS:
+		o = tcom(l);
+		if(o | tcom(r))
+			goto bad;
+		if(tlvalue(l))
+			goto bad;
+		if(isfunct(n))
+			break;
+		typeext(l->type, r);
+		if(tcompat(n, l->type, r->type, tasign))
+			goto bad;
+		constas(n, l->type, r->type);
+		if(!sametype(l->type, r->type)) {
+			r = new1(OCAST, r, Z);
+			r->type = l->type;
+			n->right = r;
+		}
+		n->type = l->type;
+		break;
+
+	case OASADD:
+	case OASSUB:
+		o = tcom(l);
+		if(o | tcom(r))
+			goto bad;
+		if(tlvalue(l))
+			goto bad;
+		if(isfunct(n))
+			break;
+		typeext1(l->type, r);
+		if(tcompat(n, l->type, r->type, tasadd))
+			goto bad;
+		constas(n, l->type, r->type);
+		t = l->type;
+		arith(n, 0);
+		while(n->left->op == OCAST)
+			n->left = n->left->left;
+		if(!sametype(t, n->type) && !mixedasop(t, n->type)) {
+			r = new1(OCAST, n->right, Z);
+			r->type = t;
+			n->right = r;
+			n->type = t;
+		}
+		break;
+
+	case OASMUL:
+	case OASLMUL:
+	case OASDIV:
+	case OASLDIV:
+		o = tcom(l);
+		if(o | tcom(r))
+			goto bad;
+		if(tlvalue(l))
+			goto bad;
+		if(isfunct(n))
+			break;
+		typeext1(l->type, r);
+		if(tcompat(n, l->type, r->type, tmul))
+			goto bad;
+		constas(n, l->type, r->type);
+		t = l->type;
+		arith(n, 0);
+		while(n->left->op == OCAST)
+			n->left = n->left->left;
+		if(!sametype(t, n->type) && !mixedasop(t, n->type)) {
+			r = new1(OCAST, n->right, Z);
+			r->type = t;
+			n->right = r;
+			n->type = t;
+		}
+		if(typeu[n->type->etype]) {
+			if(n->op == OASDIV)
+				n->op = OASLDIV;
+			if(n->op == OASMUL)
+				n->op = OASLMUL;
+		}
+		break;
+
+	case OASLSHR:
+	case OASASHR:
+	case OASASHL:
+		o = tcom(l);
+		if(o | tcom(r))
+			goto bad;
+		if(tlvalue(l))
+			goto bad;
+		if(isfunct(n))
+			break;
+		if(tcompat(n, l->type, r->type, tand))
+			goto bad;
+		n->type = l->type;
+		if(typeu[n->type->etype]) {
+			if(n->op == OASASHR)
+				n->op = OASLSHR;
+		}
+		break;
+
+	case OASMOD:
+	case OASLMOD:
+	case OASOR:
+	case OASAND:
+	case OASXOR:
+		o = tcom(l);
+		if(o | tcom(r))
+			goto bad;
+		if(tlvalue(l))
+			goto bad;
+		if(isfunct(n))
+			break;
+		if(tcompat(n, l->type, r->type, tand))
+			goto bad;
+		t = l->type;
+		arith(n, 0);
+		while(n->left->op == OCAST)
+			n->left = n->left->left;
+		if(!sametype(t, n->type) && !mixedasop(t, n->type)) {
+			r = new1(OCAST, n->right, Z);
+			r->type = t;
+			n->right = r;
+			n->type = t;
+		}
+		if(typeu[n->type->etype]) {
+			if(n->op == OASMOD)
+				n->op = OASLMOD;
+		}
+		break;
+
+	case OPREINC:
+	case OPREDEC:
+	case OPOSTINC:
+	case OPOSTDEC:
+		if(tcom(l))
+			goto bad;
+		if(tlvalue(l))
+			goto bad;
+		if(isfunct(n))
+			break;
+		if(tcompat(n, l->type, types[TINT], tadd))
+			goto bad;
+		n->type = l->type;
+		if(n->type->etype == TIND)
+		if(n->type->link->width < 1)
+			diag(n, "inc/dec of a void pointer");
+		break;
+
+	case OEQ:
+	case ONE:
+		o = tcom(l);
+		if(o | tcom(r))
+			goto bad;
+		if(isfunct(n))
+			break;
+		typeext(l->type, r);
+		typeext(r->type, l);
+		if(tcompat(n, l->type, r->type, trel))
+			goto bad;
+		arith(n, 0);
+		n->type = types[TINT];
+		break;
+
+	case OLT:
+	case OGE:
+	case OGT:
+	case OLE:
+		o = tcom(l);
+		if(o | tcom(r))
+			goto bad;
+		if(isfunct(n))
+			break;
+		typeext1(l->type, r);
+		typeext1(r->type, l);
+		if(tcompat(n, l->type, r->type, trel))
+			goto bad;
+		arith(n, 0);
+		if(typeu[n->type->etype])
+			n->op = logrel[relindex(n->op)];
+		n->type = types[TINT];
+		break;
+
+	case OCOND:
+		o = tcom(l);
+		o |= tcom(r->left);
+		if(o | tcom(r->right))
+			goto bad;
+		if(r->right->type->etype == TIND && vconst(r->left) == 0) {
+			r->left->type = r->right->type;
+			r->left->vconst = 0;
+		}
+		if(r->left->type->etype == TIND && vconst(r->right) == 0) {
+			r->right->type = r->left->type;
+			r->right->vconst = 0;
+		}
+		if(sametype(r->right->type, r->left->type)) {
+			r->type = r->right->type;
+			n->type = r->type;
+			break;
+		}
+		if(tcompat(r, r->left->type, r->right->type, trel))
+			goto bad;
+		arith(r, 0);
+		n->type = r->type;
+		break;
+
+	case OADD:
+		o = tcom(l);
+		if(o | tcom(r))
+			goto bad;
+		if(isfunct(n))
+			break;
+		if(tcompat(n, l->type, r->type, tadd))
+			goto bad;
+		arith(n, 1);
+		break;
+
+	case OSUB:
+		o = tcom(l);
+		if(o | tcom(r))
+			goto bad;
+		if(isfunct(n))
+			break;
+		if(tcompat(n, l->type, r->type, tsub))
+			goto bad;
+		arith(n, 1);
+		break;
+
+	case OMUL:
+	case OLMUL:
+	case ODIV:
+	case OLDIV:
+		o = tcom(l);
+		if(o | tcom(r))
+			goto bad;
+		if(isfunct(n))
+			break;
+		if(tcompat(n, l->type, r->type, tmul))
+			goto bad;
+		arith(n, 1);
+		if(typeu[n->type->etype]) {
+			if(n->op == ODIV)
+				n->op = OLDIV;
+			if(n->op == OMUL)
+				n->op = OLMUL;
+		}
+		break;
+
+	case OLSHR:
+	case OASHL:
+	case OASHR:
+		o = tcom(l);
+		if(o | tcom(r))
+			goto bad;
+		if(isfunct(n))
+			break;
+		if(tcompat(n, l->type, r->type, tand))
+			goto bad;
+		n->right = Z;
+		arith(n, 1);
+		n->right = new1(OCAST, r, Z);
+		n->right->type = types[TINT];
+		if(typeu[n->type->etype])
+			if(n->op == OASHR)
+				n->op = OLSHR;
+		break;
+
+	case OAND:
+	case OOR:
+	case OXOR:
+		o = tcom(l);
+		if(o | tcom(r))
+			goto bad;
+		if(isfunct(n))
+			break;
+		if(tcompat(n, l->type, r->type, tand))
+			goto bad;
+		arith(n, 1);
+		break;
+
+	case OMOD:
+	case OLMOD:
+		o = tcom(l);
+		if(o | tcom(r))
+			goto bad;
+		if(isfunct(n))
+			break;
+		if(tcompat(n, l->type, r->type, tand))
+			goto bad;
+		arith(n, 1);
+		if(typeu[n->type->etype])
+			n->op = OLMOD;
+		break;
+
+	case OPOS:
+		if(tcom(l))
+			goto bad;
+		if(isfunct(n))
+			break;
+
+		r = l;
+		l = new(OCONST, Z, Z);
+		l->vconst = 0;
+		l->type = types[TINT];
+		n->op = OADD;
+		n->right = r;
+		n->left = l;
+
+		if(tcom(l))
+			goto bad;
+		if(tcompat(n, l->type, r->type, tsub))
+			goto bad;
+		arith(n, 1);
+		break;
+
+	case ONEG:
+		if(tcom(l))
+			goto bad;
+		if(isfunct(n))
+			break;
+
+		if(!machcap(n)) {
+			r = l;
+			l = new(OCONST, Z, Z);
+			l->vconst = 0;
+			l->type = types[TINT];
+			n->op = OSUB;
+			n->right = r;
+			n->left = l;
+
+			if(tcom(l))
+				goto bad;
+			if(tcompat(n, l->type, r->type, tsub))
+				goto bad;
+		}
+		arith(n, 1);
+		break;
+
+	case OCOM:
+		if(tcom(l))
+			goto bad;
+		if(isfunct(n))
+			break;
+
+		if(!machcap(n)) {
+			r = l;
+			l = new(OCONST, Z, Z);
+			l->vconst = -1;
+			l->type = types[TINT];
+			n->op = OXOR;
+			n->right = r;
+			n->left = l;
+
+			if(tcom(l))
+				goto bad;
+			if(tcompat(n, l->type, r->type, tand))
+				goto bad;
+		}
+		arith(n, 1);
+		break;
+
+	case ONOT:
+		if(tcom(l))
+			goto bad;
+		if(isfunct(n))
+			break;
+		if(tcompat(n, T, l->type, tnot))
+			goto bad;
+		n->type = types[TINT];
+		break;
+
+	case OANDAND:
+	case OOROR:
+		o = tcom(l);
+		if(o | tcom(r))
+			goto bad;
+		if(tcompat(n, T, l->type, tnot) |
+		   tcompat(n, T, r->type, tnot))
+			goto bad;
+		n->type = types[TINT];
+		break;
+
+	case OCOMMA:
+		o = tcom(l);
+		if(o | tcom(r))
+			goto bad;
+		n->type = r->type;
+		break;
+
+
+	case OSIGN:	/* extension signof(type) returns a hash */
+		if(l != Z) {
+			if(l->op != OSTRING && l->op != OLSTRING)
+				if(tcomo(l, 0))
+					goto bad;
+			if(l->op == OBIT) {
+				diag(n, "signof bitfield");
+				goto bad;
+			}
+			n->type = l->type;
+		}
+		if(n->type == T)
+			goto bad;
+		if(n->type->width < 0) {
+			diag(n, "signof undefined type");
+			goto bad;
+		}
+		n->op = OCONST;
+		n->left = Z;
+		n->right = Z;
+		n->vconst = convvtox(signature(n->type), TULONG);
+		n->type = types[TULONG];
+		break;
+
+	case OSIZE:
+		if(l != Z) {
+			if(l->op != OSTRING && l->op != OLSTRING)
+				if(tcomo(l, 0))
+					goto bad;
+			if(l->op == OBIT) {
+				diag(n, "sizeof bitfield");
+				goto bad;
+			}
+			n->type = l->type;
+		}
+		if(n->type == T)
+			goto bad;
+		if(n->type->width <= 0) {
+			diag(n, "sizeof undefined type");
+			goto bad;
+		}
+		if(n->type->etype == TFUNC) {
+			diag(n, "sizeof function");
+			goto bad;
+		}
+		n->op = OCONST;
+		n->left = Z;
+		n->right = Z;
+		n->vconst = convvtox(n->type->width, TINT);
+		n->type = types[TINT];
+		break;
+
+	case OFUNC:
+		o = tcomo(l, 0);
+		if(o)
+			goto bad;
+		if(l->type->etype == TIND && l->type->link->etype == TFUNC) {
+			l = new1(OIND, l, Z);
+			l->type = l->left->type->link;
+			n->left = l;
+		}
+		if(tcompat(n, T, l->type, tfunct))
+			goto bad;
+		if(o | tcoma(l, r, l->type->down, 1))
+			goto bad;
+		n->type = l->type->link;
+		if(!debug['B'])
+			if(l->type->down == T || l->type->down->etype == TOLD) {
+				nerrors--;
+				diag(n, "function args not checked: %F", l);
+			}
+		dpcheck(n);
+		break;
+
+	case ONAME:
+		if(n->type == T) {
+			diag(n, "name not declared: %F", n);
+			goto bad;
+		}
+		if(n->type->etype == TENUM) {
+			n->op = OCONST;
+			n->type = n->sym->tenum;
+			if(!typefd[n->type->etype])
+				n->vconst = n->sym->vconst;
+			else
+				n->fconst = n->sym->fconst;
+			break;
+		}
+		n->addable = 1;
+		if(n->class == CEXREG) {
+			n->op = OREGISTER;
+			// on 386 or amd64, "extern register" generates
+			// memory references relative to the
+			// gs or fs segment.
+			if(thechar == '8' || thechar == '6')	// [sic]
+				n->op = OEXREG;
+			n->reg = n->sym->offset;
+			n->xoffset = 0;
+			break;
+		}
+		break;
+
+	case OLSTRING:
+		if(n->type->link != types[TRUNE]) {
+			o = outstring(0, 0);
+			while(o & 3) {
+				outlstring(&zer, sizeof(TRune));
+				o = outlstring(0, 0);
+			}
+		}
+		n->op = ONAME;
+		n->xoffset = outlstring(n->rstring, n->type->width);
+		n->addable = 1;
+		break;
+
+	case OSTRING:
+		if(n->type->link != types[TCHAR]) {
+			o = outstring(0, 0);
+			while(o & 3) {
+				outstring("", 1);
+				o = outstring(0, 0);
+			}
+		}
+		n->op = ONAME;
+		n->xoffset = outstring(n->cstring, n->type->width);
+		n->addable = 1;
+		break;
+
+	case OCONST:
+		break;
+
+	case ODOT:
+		if(tcom(l))
+			goto bad;
+		if(tcompat(n, T, l->type, tdot))
+			goto bad;
+		if(tcomd(n))
+			goto bad;
+		break;
+
+	case OADDR:
+		if(tcomo(l, ADDROP))
+			goto bad;
+		if(tlvalue(l))
+			goto bad;
+		if(l->type->nbits) {
+			diag(n, "address of a bit field");
+			goto bad;
+		}
+		if(l->op == OREGISTER) {
+			diag(n, "address of a register");
+			goto bad;
+		}
+		n->type = typ(TIND, l->type);
+		n->type->width = types[TIND]->width;
+		break;
+
+	case OIND:
+		if(tcom(l))
+			goto bad;
+		if(tcompat(n, T, l->type, tindir))
+			goto bad;
+		n->type = l->type->link;
+		n->addable = 1;
+		break;
+
+	case OSTRUCT:
+		if(tcomx(n))
+			goto bad;
+		break;
+	}
+	t = n->type;
+	if(t == T)
+		goto bad;
+	if(t->width < 0) {
+		snap(t);
+		if(t->width < 0) {
+			if(typesu[t->etype] && t->tag)
+				diag(n, "structure not fully declared %s", t->tag->name);
+			else
+				diag(n, "structure not fully declared");
+			goto bad;
+		}
+	}
+	if(typeaf[t->etype]) {
+		if(f & ADDROF)
+			goto addaddr;
+		if(f & ADDROP)
+			warn(n, "address of array/func ignored");
+	}
+	return 0;
+
+addaddr:
+	if(tlvalue(n))
+		goto bad;
+	l = new1(OXXX, Z, Z);
+	*l = *n;
+	n->op = OADDR;
+	if(l->type->etype == TARRAY)
+		l->type = l->type->link;
+	n->left = l;
+	n->right = Z;
+	n->addable = 0;
+	n->type = typ(TIND, l->type);
+	n->type->width = types[TIND]->width;
+	return 0;
+
+bad:
+	n->type = T;
+	return 1;
+}
+
+int
+tcoma(Node *l, Node *n, Type *t, int f)
+{
+	Node *n1;
+	int o;
+
+	if(t != T)
+	if(t->etype == TOLD || t->etype == TDOT)	/* .../old in prototype */
+		t = T;
+	if(n == Z) {
+		if(t != T && !sametype(t, types[TVOID])) {
+			diag(n, "not enough function arguments: %F", l);
+			return 1;
+		}
+		return 0;
+	}
+	if(n->op == OLIST) {
+		o = tcoma(l, n->left, t, 0);
+		if(t != T) {
+			t = t->down;
+			if(t == T)
+				t = types[TVOID];
+		}
+		return o | tcoma(l, n->right, t, 1);
+	}
+	if(f && t != T)
+		tcoma(l, Z, t->down, 0);
+	if(tcom(n) || tcompat(n, T, n->type, targ))
+		return 1;
+	if(sametype(t, types[TVOID])) {
+		diag(n, "too many function arguments: %F", l);
+		return 1;
+	}
+	if(t != T) {
+		typeext(t, n);
+		if(stcompat(nodproto, t, n->type, tasign)) {
+			diag(l, "argument prototype mismatch \"%T\" for \"%T\": %F",
+				n->type, t, l);
+			return 1;
+		}
+//		switch(t->etype) {
+//		case TCHAR:
+//		case TSHORT:
+//			t = types[TINT];
+//			break;
+//
+//		case TUCHAR:
+//		case TUSHORT:
+//			t = types[TUINT];
+//			break;
+//		}
+	} else {
+		switch(n->type->etype) {
+		case TCHAR:
+		case TSHORT:
+			t = types[TINT];
+			break;
+
+		case TUCHAR:
+		case TUSHORT:
+			t = types[TUINT];
+			break;
+
+		case TFLOAT:
+			t = types[TDOUBLE];
+		}
+	}
+
+	if(t != T && !sametype(t, n->type)) {
+		n1 = new1(OXXX, Z, Z);
+		*n1 = *n;
+		n->op = OCAST;
+		n->left = n1;
+		n->right = Z;
+		n->type = t;
+		n->addable = 0;
+	}
+	return 0;
+}
+
+int
+tcomd(Node *n)
+{
+	Type *t;
+	int32 o;
+
+	o = 0;
+	t = dotsearch(n->sym, n->left->type->link, n, &o);
+	if(t == T) {
+		diag(n, "not a member of struct/union: %F", n);
+		return 1;
+	}
+	makedot(n, t, o);
+	return 0;
+}
+
+int
+tcomx(Node *n)
+{
+	Type *t;
+	Node *l, *r, **ar, **al;
+	int e;
+
+	e = 0;
+	if(n->type->etype != TSTRUCT) {
+		diag(n, "constructor must be a structure");
+		return 1;
+	}
+	l = invert(n->left);
+	n->left = l;
+	al = &n->left;
+	for(t = n->type->link; t != T; t = t->down) {
+		if(l == Z) {
+			diag(n, "constructor list too short");
+			return 1;
+		}
+		if(l->op == OLIST) {
+			r = l->left;
+			ar = &l->left;
+			al = &l->right;
+			l = l->right;
+		} else {
+			r = l;
+			ar = al;
+			l = Z;
+		}
+		if(tcom(r))
+			e++;
+		typeext(t, r);
+		if(tcompat(n, t, r->type, tasign))
+			e++;
+		constas(n, t, r->type);
+		if(!e && !sametype(t, r->type)) {
+			r = new1(OCAST, r, Z);
+			r->type = t;
+			*ar = r;
+		}
+	}
+	if(l != Z) {
+		diag(n, "constructor list too long");
+		return 1;
+	}
+	return e;
+}
+
+int
+tlvalue(Node *n)
+{
+
+	if(!n->addable) {
+		diag(n, "not an l-value");
+		return 1;
+	}
+	return 0;
+}
+
+/*
+ *	general rewrite
+ *	(IND(ADDR x)) ==> x
+ *	(ADDR(IND x)) ==> x
+ *	remove some zero operands
+ *	remove no op casts
+ *	evaluate constants
+ */
+void
+ccom(Node *n)
+{
+	Node *l, *r;
+	int t;
+
+loop:
+	if(n == Z)
+		return;
+	l = n->left;
+	r = n->right;
+	switch(n->op) {
+
+	case OAS:
+	case OASXOR:
+	case OASAND:
+	case OASOR:
+	case OASMOD:
+	case OASLMOD:
+	case OASLSHR:
+	case OASASHR:
+	case OASASHL:
+	case OASDIV:
+	case OASLDIV:
+	case OASMUL:
+	case OASLMUL:
+	case OASSUB:
+	case OASADD:
+		ccom(l);
+		ccom(r);
+		if(n->op == OASLSHR || n->op == OASASHR || n->op == OASASHL)
+		if(r->op == OCONST) {
+			t = n->type->width * 8;	/* bits per byte */
+			if(r->vconst >= t || r->vconst < 0)
+				warn(n, "stupid shift: %lld", r->vconst);
+		}
+		break;
+
+	case OCAST:
+		ccom(l);
+		if(l->op == OCONST) {
+			evconst(n);
+			if(n->op == OCONST)
+				break;
+		}
+		if(nocast(l->type, n->type)) {
+			l->type = n->type;
+			*n = *l;
+		}
+		break;
+
+	case OCOND:
+		ccom(l);
+		ccom(r);
+		if(l->op == OCONST)
+			if(vconst(l) == 0)
+				*n = *r->right;
+			else
+				*n = *r->left;
+		break;
+
+	case OREGISTER:
+	case OINDREG:
+	case OCONST:
+	case ONAME:
+		break;
+
+	case OADDR:
+		ccom(l);
+		l->etype = TVOID;
+		if(l->op == OIND) {
+			l->left->type = n->type;
+			*n = *l->left;
+			break;
+		}
+		goto common;
+
+	case OIND:
+		ccom(l);
+		if(l->op == OADDR) {
+			l->left->type = n->type;
+			*n = *l->left;
+			break;
+		}
+		goto common;
+
+	case OEQ:
+	case ONE:
+
+	case OLE:
+	case OGE:
+	case OLT:
+	case OGT:
+
+	case OLS:
+	case OHS:
+	case OLO:
+	case OHI:
+		ccom(l);
+		ccom(r);
+		if(compar(n, 0) || compar(n, 1))
+			break;
+		relcon(l, r);
+		relcon(r, l);
+		goto common;
+
+	case OASHR:
+	case OASHL:
+	case OLSHR:
+		ccom(l);
+		if(vconst(l) == 0 && !side(r)) {
+			*n = *l;
+			break;
+		}
+		ccom(r);
+		if(vconst(r) == 0) {
+			*n = *l;
+			break;
+		}
+		if(r->op == OCONST) {
+			t = n->type->width * 8;	/* bits per byte */
+			if(r->vconst >= t || r->vconst <= -t)
+				warn(n, "stupid shift: %lld", r->vconst);
+		}
+		goto common;
+
+	case OMUL:
+	case OLMUL:
+		ccom(l);
+		t = vconst(l);
+		if(t == 0 && !side(r)) {
+			*n = *l;
+			break;
+		}
+		if(t == 1) {
+			*n = *r;
+			goto loop;
+		}
+		ccom(r);
+		t = vconst(r);
+		if(t == 0 && !side(l)) {
+			*n = *r;
+			break;
+		}
+		if(t == 1) {
+			*n = *l;
+			break;
+		}
+		goto common;
+
+	case ODIV:
+	case OLDIV:
+		ccom(l);
+		if(vconst(l) == 0 && !side(r)) {
+			*n = *l;
+			break;
+		}
+		ccom(r);
+		t = vconst(r);
+		if(t == 0) {
+			diag(n, "divide check");
+			*n = *r;
+			break;
+		}
+		if(t == 1) {
+			*n = *l;
+			break;
+		}
+		goto common;
+
+	case OSUB:
+		ccom(r);
+		if(r->op == OCONST) {
+			if(typefd[r->type->etype]) {
+				n->op = OADD;
+				r->fconst = -r->fconst;
+				goto loop;
+			} else {
+				n->op = OADD;
+				r->vconst = -r->vconst;
+				goto loop;
+			}
+		}
+		ccom(l);
+		goto common;
+
+	case OXOR:
+	case OOR:
+	case OADD:
+		ccom(l);
+		if(vconst(l) == 0) {
+			*n = *r;
+			goto loop;
+		}
+		ccom(r);
+		if(vconst(r) == 0) {
+			*n = *l;
+			break;
+		}
+		goto commute;
+
+	case OAND:
+		ccom(l);
+		ccom(r);
+		if(vconst(l) == 0 && !side(r)) {
+			*n = *l;
+			break;
+		}
+		if(vconst(r) == 0 && !side(l)) {
+			*n = *r;
+			break;
+		}
+
+	commute:
+		/* look for commutative constant */
+		if(r->op == OCONST) {
+			if(l->op == n->op) {
+				if(l->left->op == OCONST) {
+					n->right = l->right;
+					l->right = r;
+					goto loop;
+				}
+				if(l->right->op == OCONST) {
+					n->right = l->left;
+					l->left = r;
+					goto loop;
+				}
+			}
+		}
+		if(l->op == OCONST) {
+			if(r->op == n->op) {
+				if(r->left->op == OCONST) {
+					n->left = r->right;
+					r->right = l;
+					goto loop;
+				}
+				if(r->right->op == OCONST) {
+					n->left = r->left;
+					r->left = l;
+					goto loop;
+				}
+			}
+		}
+		goto common;
+
+	case OANDAND:
+		ccom(l);
+		if(vconst(l) == 0) {
+			*n = *l;
+			break;
+		}
+		ccom(r);
+		goto common;
+
+	case OOROR:
+		ccom(l);
+		if(l->op == OCONST && l->vconst != 0) {
+			*n = *l;
+			n->vconst = 1;
+			break;
+		}
+		ccom(r);
+		goto common;
+
+	default:
+		if(l != Z)
+			ccom(l);
+		if(r != Z)
+			ccom(r);
+	common:
+		if(l != Z)
+		if(l->op != OCONST)
+			break;
+		if(r != Z)
+		if(r->op != OCONST)
+			break;
+		evconst(n);
+	}
+}
+
+/*	OEQ, ONE, OLE, OLS, OLT, OLO, OGE, OHS, OGT, OHI */
+static char *cmps[12] = 
+{
+	"==", "!=", "<=", "<=", "<", "<", ">=", ">=", ">", ">",
+};
+
+/* 128-bit numbers */
+typedef struct Big Big;
+struct Big
+{
+	vlong a;
+	uvlong b;
+};
+static int
+cmp(Big x, Big y)
+{
+	if(x.a != y.a){
+		if(x.a < y.a)
+			return -1;
+		return 1;
+	}
+	if(x.b != y.b){
+		if(x.b < y.b)
+			return -1;
+		return 1;
+	}
+	return 0;
+}
+static Big
+add(Big x, int y)
+{
+	uvlong ob;
+	
+	ob = x.b;
+	x.b += y;
+	if(y > 0 && x.b < ob)
+		x.a++;
+	if(y < 0 && x.b > ob)
+		x.a--;
+	return x;
+} 
+
+Big
+big(vlong a, uvlong b)
+{
+	Big x;
+
+	x.a = a;
+	x.b = b;
+	return x;
+}
+
+int
+compar(Node *n, int reverse)
+{
+	Big lo, hi, x;
+	int op;
+	char xbuf[40], cmpbuf[50];
+	Node *l, *r;
+	Type *lt, *rt;
+
+	/*
+	 * The point of this function is to diagnose comparisons 
+	 * that can never be true or that look misleading because
+	 * of the `usual arithmetic conversions'.  As an example 
+	 * of the latter, if x is a ulong, then if(x <= -1) really means
+	 * if(x <= 0xFFFFFFFF), while if(x <= -1LL) really means
+	 * what it says (but 8c compiles it wrong anyway).
+	 */
+
+	if(reverse){
+		r = n->left;
+		l = n->right;
+		op = comrel[relindex(n->op)];
+	}else{
+		l = n->left;
+		r = n->right;
+		op = n->op;
+	}
+
+	/*
+	 * Skip over left casts to find out the original expression range.
+	 */
+	while(l->op == OCAST)
+		l = l->left;
+	if(l->op == OCONST)
+		return 0;
+	lt = l->type;
+	if(l->op == ONAME && l->sym->type){
+		lt = l->sym->type;
+		if(lt->etype == TARRAY)
+			lt = lt->link;
+	}
+	if(lt == T)
+		return 0;
+	if(lt->etype == TXXX || lt->etype > TUVLONG)
+		return 0;
+	
+	/*
+	 * Skip over the right casts to find the on-screen value.
+	 */
+	if(r->op != OCONST)
+		return 0;
+	while(r->oldop == OCAST && !r->xcast)
+		r = r->left;
+	rt = r->type;
+	if(rt == T)
+		return 0;
+
+	x.b = r->vconst;
+	x.a = 0;
+	if((rt->etype&1) && r->vconst < 0)	/* signed negative */
+		x.a = ~0ULL;
+
+	if((lt->etype&1)==0){
+		/* unsigned */
+		lo = big(0, 0);
+		if(lt->width == 8)
+			hi = big(0, ~0ULL);
+		else
+			hi = big(0, (1ULL<<(l->type->width*8))-1);
+	}else{
+		lo = big(~0ULL, -(1ULL<<(l->type->width*8-1)));
+		hi = big(0, (1ULL<<(l->type->width*8-1))-1);
+	}
+
+	switch(op){
+	case OLT:
+	case OLO:
+	case OGE:
+	case OHS:
+		if(cmp(x, lo) <= 0)
+			goto useless;
+		if(cmp(x, add(hi, 1)) >= 0)
+			goto useless;
+		break;
+	case OLE:
+	case OLS:
+	case OGT:
+	case OHI:
+		if(cmp(x, add(lo, -1)) <= 0)
+			goto useless;
+		if(cmp(x, hi) >= 0)
+			goto useless;
+		break;
+	case OEQ:
+	case ONE:
+		/*
+		 * Don't warn about comparisons if the expression
+		 * is as wide as the value: the compiler-supplied casts
+		 * will make both outcomes possible.
+		 */
+		if(lt->width >= rt->width && debug['w'] < 2)
+			return 0;
+		if(cmp(x, lo) < 0 || cmp(x, hi) > 0)
+			goto useless;
+		break;
+	}
+	return 0;
+
+useless:
+	if((x.a==0 && x.b<=9) || (x.a==~0LL && x.b >= -9ULL))
+		snprint(xbuf, sizeof xbuf, "%lld", x.b);
+	else if(x.a == 0)
+		snprint(xbuf, sizeof xbuf, "%#llux", x.b);
+	else
+		snprint(xbuf, sizeof xbuf, "%#llx", x.b);
+	if(reverse)
+		snprint(cmpbuf, sizeof cmpbuf, "%s %s %T",
+			xbuf, cmps[relindex(n->op)], lt);
+	else
+		snprint(cmpbuf, sizeof cmpbuf, "%T %s %s",
+			lt, cmps[relindex(n->op)], xbuf);
+	warn(n, "useless or misleading comparison: %s", cmpbuf);
+	return 0;
+}
+
diff --git a/src/cmd/cc/com64.c b/src/cmd/cc/com64.c
new file mode 100644
index 0000000..f46fedc
--- /dev/null
+++ b/src/cmd/cc/com64.c
@@ -0,0 +1,644 @@
+// Inferno utils/cc/com64.c
+// http://code.google.com/p/inferno-os/source/browse/utils/cc/com64.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 "cc.h"
+
+/*
+ * this is machine depend, but it is totally
+ * common on all of the 64-bit symulating machines.
+ */
+
+#define	FNX	100	/* botch -- redefinition */
+
+Node*	nodaddv;
+Node*	nodsubv;
+Node*	nodmulv;
+Node*	noddivv;
+Node*	noddivvu;
+Node*	nodmodv;
+Node*	nodmodvu;
+Node*	nodlshv;
+Node*	nodrshav;
+Node*	nodrshlv;
+Node*	nodandv;
+Node*	nodorv;
+Node*	nodxorv;
+Node*	nodnegv;
+Node*	nodcomv;
+
+Node*	nodtestv;
+Node*	nodeqv;
+Node*	nodnev;
+Node*	nodlev;
+Node*	nodltv;
+Node*	nodgev;
+Node*	nodgtv;
+Node*	nodhiv;
+Node*	nodhsv;
+Node*	nodlov;
+Node*	nodlsv;
+
+Node*	nodf2v;
+Node*	nodd2v;
+Node*	nodp2v;
+Node*	nodsi2v;
+Node*	nodui2v;
+Node*	nodsl2v;
+Node*	nodul2v;
+Node*	nodsh2v;
+Node*	noduh2v;
+Node*	nodsc2v;
+Node*	noduc2v;
+
+Node*	nodv2f;
+Node*	nodv2d;
+Node*	nodv2ui;
+Node*	nodv2si;
+Node*	nodv2ul;
+Node*	nodv2sl;
+Node*	nodv2uh;
+Node*	nodv2sh;
+Node*	nodv2uc;
+Node*	nodv2sc;
+
+Node*	nodvpp;
+Node*	nodppv;
+Node*	nodvmm;
+Node*	nodmmv;
+
+Node*	nodvasop;
+
+char	etconv[NALLTYPES];	/* for _vasop */
+Init	initetconv[] =
+{
+	TCHAR,		1,	0,
+	TUCHAR,		2,	0,
+	TSHORT,		3,	0,
+	TUSHORT,	4,	0,
+	TLONG,		5,	0,
+	TULONG,		6,	0,
+	TVLONG,		7,	0,
+	TUVLONG,	8,	0,
+	TINT,		9,	0,
+	TUINT,		10,	0,
+	-1,		0,	0,
+};
+
+Node*
+fvn(char *name, int type)
+{
+	Node *n;
+
+	n = new(ONAME, Z, Z);
+	n->sym = slookup(name);
+	n->sym->sig = SIGINTERN;
+	if(fntypes[type] == 0)
+		fntypes[type] = typ(TFUNC, types[type]);
+	n->type = fntypes[type];
+	n->etype = type;
+	n->class = CGLOBL;
+	n->addable = 10;
+	n->complex = 0;
+	return n;
+}
+
+void
+com64init(void)
+{
+	Init *p;
+
+	nodaddv = fvn("_addv", TVLONG);
+	nodsubv = fvn("_subv", TVLONG);
+	nodmulv = fvn("_mulv", TVLONG);
+	noddivv = fvn("_divv", TVLONG);
+	noddivvu = fvn("_divvu", TVLONG);
+	nodmodv = fvn("_modv", TVLONG);
+	nodmodvu = fvn("_modvu", TVLONG);
+	nodlshv = fvn("_lshv", TVLONG);
+	nodrshav = fvn("_rshav", TVLONG);
+	nodrshlv = fvn("_rshlv", TVLONG);
+	nodandv = fvn("_andv", TVLONG);
+	nodorv = fvn("_orv", TVLONG);
+	nodxorv = fvn("_xorv", TVLONG);
+	nodnegv = fvn("_negv", TVLONG);
+	nodcomv = fvn("_comv", TVLONG);
+
+	nodtestv = fvn("_testv", TLONG);
+	nodeqv = fvn("_eqv", TLONG);
+	nodnev = fvn("_nev", TLONG);
+	nodlev = fvn("_lev", TLONG);
+	nodltv = fvn("_ltv", TLONG);
+	nodgev = fvn("_gev", TLONG);
+	nodgtv = fvn("_gtv", TLONG);
+	nodhiv = fvn("_hiv", TLONG);
+	nodhsv = fvn("_hsv", TLONG);
+	nodlov = fvn("_lov", TLONG);
+	nodlsv = fvn("_lsv", TLONG);
+
+	nodf2v = fvn("_f2v", TVLONG);
+	nodd2v = fvn("_d2v", TVLONG);
+	nodp2v = fvn("_p2v", TVLONG);
+	nodsi2v = fvn("_si2v", TVLONG);
+	nodui2v = fvn("_ui2v", TVLONG);
+	nodsl2v = fvn("_sl2v", TVLONG);
+	nodul2v = fvn("_ul2v", TVLONG);
+	nodsh2v = fvn("_sh2v", TVLONG);
+	noduh2v = fvn("_uh2v", TVLONG);
+	nodsc2v = fvn("_sc2v", TVLONG);
+	noduc2v = fvn("_uc2v", TVLONG);
+
+	nodv2f = fvn("_v2f", TFLOAT);
+	nodv2d = fvn("_v2d", TDOUBLE);
+	nodv2sl = fvn("_v2sl", TLONG);
+	nodv2ul = fvn("_v2ul", TULONG);
+	nodv2si = fvn("_v2si", TINT);
+	nodv2ui = fvn("_v2ui", TUINT);
+	nodv2sh = fvn("_v2sh", TSHORT);
+	nodv2uh = fvn("_v2ul", TUSHORT);
+	nodv2sc = fvn("_v2sc", TCHAR);
+	nodv2uc = fvn("_v2uc", TUCHAR);
+
+	nodvpp = fvn("_vpp", TVLONG);
+	nodppv = fvn("_ppv", TVLONG);
+	nodvmm = fvn("_vmm", TVLONG);
+	nodmmv = fvn("_mmv", TVLONG);
+
+	nodvasop = fvn("_vasop", TVLONG);
+
+	for(p = initetconv; p->code >= 0; p++)
+		etconv[p->code] = p->value;
+}
+
+int
+com64(Node *n)
+{
+	Node *l, *r, *a, *t;
+	int lv, rv;
+
+	if(n->type == 0)
+		return 0;
+
+	l = n->left;
+	r = n->right;
+
+	lv = 0;
+	if(l && l->type && typev[l->type->etype])
+		lv = 1;
+	rv = 0;
+	if(r && r->type && typev[r->type->etype])
+		rv = 1;
+
+	if(lv) {
+		switch(n->op) {
+		case OEQ:
+			a = nodeqv;
+			goto setbool;
+		case ONE:
+			a = nodnev;
+			goto setbool;
+		case OLE:
+			a = nodlev;
+			goto setbool;
+		case OLT:
+			a = nodltv;
+			goto setbool;
+		case OGE:
+			a = nodgev;
+			goto setbool;
+		case OGT:
+			a = nodgtv;
+			goto setbool;
+		case OHI:
+			a = nodhiv;
+			goto setbool;
+		case OHS:
+			a = nodhsv;
+			goto setbool;
+		case OLO:
+			a = nodlov;
+			goto setbool;
+		case OLS:
+			a = nodlsv;
+			goto setbool;
+
+		case OANDAND:
+		case OOROR:
+			if(machcap(n))
+				return 1;
+
+			if(rv) {
+				r = new(OFUNC, nodtestv, r);
+				n->right = r;
+				r->complex = FNX;
+				r->op = OFUNC;
+				r->type = types[TLONG];
+			}
+
+		case OCOND:
+		case ONOT:
+			if(machcap(n))
+				return 1;
+
+			l = new(OFUNC, nodtestv, l);
+			n->left = l;
+			l->complex = FNX;
+			l->op = OFUNC;
+			l->type = types[TLONG];
+			n->complex = FNX;
+			return 1;
+		}
+	}
+
+	if(rv) {
+		if(machcap(n))
+			return 1;
+		switch(n->op) {
+		case OANDAND:
+		case OOROR:
+			r = new(OFUNC, nodtestv, r);
+			n->right = r;
+			r->complex = FNX;
+			r->op = OFUNC;
+			r->type = types[TLONG];
+			return 1;
+		}
+	}
+
+	if(typev[n->type->etype]) {
+		if(machcap(n))
+			return 1;
+		switch(n->op) {
+		default:
+			diag(n, "unknown vlong %O", n->op);
+		case OFUNC:
+			n->complex = FNX;
+		case ORETURN:
+		case OAS:
+		case OIND:
+			return 1;
+		case OADD:
+			a = nodaddv;
+			goto setbop;
+		case OSUB:
+			a = nodsubv;
+			goto setbop;
+		case OMUL:
+		case OLMUL:
+			a = nodmulv;
+			goto setbop;
+		case ODIV:
+			a = noddivv;
+			goto setbop;
+		case OLDIV:
+			a = noddivvu;
+			goto setbop;
+		case OMOD:
+			a = nodmodv;
+			goto setbop;
+		case OLMOD:
+			a = nodmodvu;
+			goto setbop;
+		case OASHL:
+			a = nodlshv;
+			goto setbop;
+		case OASHR:
+			a = nodrshav;
+			goto setbop;
+		case OLSHR:
+			a = nodrshlv;
+			goto setbop;
+		case OAND:
+			a = nodandv;
+			goto setbop;
+		case OOR:
+			a = nodorv;
+			goto setbop;
+		case OXOR:
+			a = nodxorv;
+			goto setbop;
+		case OPOSTINC:
+			a = nodvpp;
+			goto setvinc;
+		case OPOSTDEC:
+			a = nodvmm;
+			goto setvinc;
+		case OPREINC:
+			a = nodppv;
+			goto setvinc;
+		case OPREDEC:
+			a = nodmmv;
+			goto setvinc;
+		case ONEG:
+			a = nodnegv;
+			goto setfnx;
+		case OCOM:
+			a = nodcomv;
+			goto setfnx;
+		case OCAST:
+			switch(l->type->etype) {
+			case TCHAR:
+				a = nodsc2v;
+				goto setfnxl;
+			case TUCHAR:
+				a = noduc2v;
+				goto setfnxl;
+			case TSHORT:
+				a = nodsh2v;
+				goto setfnxl;
+			case TUSHORT:
+				a = noduh2v;
+				goto setfnxl;
+			case TINT:
+				a = nodsi2v;
+				goto setfnx;
+			case TUINT:
+				a = nodui2v;
+				goto setfnx;
+			case TLONG:
+				a = nodsl2v;
+				goto setfnx;
+			case TULONG:
+				a = nodul2v;
+				goto setfnx;
+			case TFLOAT:
+				a = nodf2v;
+				goto setfnx;
+			case TDOUBLE:
+				a = nodd2v;
+				goto setfnx;
+			case TIND:
+				a = nodp2v;
+				goto setfnx;
+			}
+			diag(n, "unknown %T->vlong cast", l->type);
+			return 1;
+		case OASADD:
+			a = nodaddv;
+			goto setasop;
+		case OASSUB:
+			a = nodsubv;
+			goto setasop;
+		case OASMUL:
+		case OASLMUL:
+			a = nodmulv;
+			goto setasop;
+		case OASDIV:
+			a = noddivv;
+			goto setasop;
+		case OASLDIV:
+			a = noddivvu;
+			goto setasop;
+		case OASMOD:
+			a = nodmodv;
+			goto setasop;
+		case OASLMOD:
+			a = nodmodvu;
+			goto setasop;
+		case OASASHL:
+			a = nodlshv;
+			goto setasop;
+		case OASASHR:
+			a = nodrshav;
+			goto setasop;
+		case OASLSHR:
+			a = nodrshlv;
+			goto setasop;
+		case OASAND:
+			a = nodandv;
+			goto setasop;
+		case OASOR:
+			a = nodorv;
+			goto setasop;
+		case OASXOR:
+			a = nodxorv;
+			goto setasop;
+		}
+	}
+
+	if(typefd[n->type->etype] && l && l->op == OFUNC) {
+		switch(n->op) {
+		case OASADD:
+		case OASSUB:
+		case OASMUL:
+		case OASLMUL:
+		case OASDIV:
+		case OASLDIV:
+		case OASMOD:
+		case OASLMOD:
+		case OASASHL:
+		case OASASHR:
+		case OASLSHR:
+		case OASAND:
+		case OASOR:
+		case OASXOR:
+			if(l->right && typev[l->right->etype]) {
+				diag(n, "sorry float <asop> vlong not implemented\n");
+			}
+		}
+	}
+
+	if(n->op == OCAST) {
+		if(l->type && typev[l->type->etype]) {
+			if(machcap(n))
+				return 1;
+			switch(n->type->etype) {
+			case TDOUBLE:
+				a = nodv2d;
+				goto setfnx;
+			case TFLOAT:
+				a = nodv2f;
+				goto setfnx;
+			case TLONG:
+				a = nodv2sl;
+				goto setfnx;
+			case TULONG:
+				a = nodv2ul;
+				goto setfnx;
+			case TINT:
+				a = nodv2si;
+				goto setfnx;
+			case TUINT:
+				a = nodv2ui;
+				goto setfnx;
+			case TSHORT:
+				a = nodv2sh;
+				goto setfnx;
+			case TUSHORT:
+				a = nodv2uh;
+				goto setfnx;
+			case TCHAR:
+				a = nodv2sc;
+				goto setfnx;
+			case TUCHAR:
+				a = nodv2uc;
+				goto setfnx;
+			case TIND:	// small pun here
+				a = nodv2ul;
+				goto setfnx;
+			}
+			diag(n, "unknown vlong->%T cast", n->type);
+			return 1;
+		}
+	}
+
+	return 0;
+
+setbop:
+	n->left = a;
+	n->right = new(OLIST, l, r);
+	n->complex = FNX;
+	n->op = OFUNC;
+	return 1;
+
+setfnxl:
+	l = new(OCAST, l, 0);
+	l->type = types[TLONG];
+	l->complex = l->left->complex;
+
+setfnx:
+	n->left = a;
+	n->right = l;
+	n->complex = FNX;
+	n->op = OFUNC;
+	return 1;
+
+setvinc:
+	n->left = a;
+	l = new(OADDR, l, Z);
+	l->type = typ(TIND, l->left->type);
+	n->right = new(OLIST, l, r);
+	n->complex = FNX;
+	n->op = OFUNC;
+	return 1;
+
+setbool:
+	if(machcap(n))
+		return 1;
+	n->left = a;
+	n->right = new(OLIST, l, r);
+	n->complex = FNX;
+	n->op = OFUNC;
+	n->type = types[TLONG];
+	return 1;
+
+setasop:
+	if(l->op == OFUNC) {
+		l = l->right;
+		goto setasop;
+	}
+
+	t = new(OCONST, 0, 0);
+	t->vconst = etconv[l->type->etype];
+	t->type = types[TLONG];
+	t->addable = 20;
+	r = new(OLIST, t, r);
+
+	t = new(OADDR, a, 0);
+	t->type = typ(TIND, a->type);
+	r = new(OLIST, t, r);
+
+	t = new(OADDR, l, 0);
+	t->type = typ(TIND, l->type);
+	r = new(OLIST, t, r);
+
+	n->left = nodvasop;
+	n->right = r;
+	n->complex = FNX;
+	n->op = OFUNC;
+
+	return 1;
+}
+
+void
+bool64(Node *n)
+{
+	Node *n1;
+
+	if(machcap(Z))
+		return;
+	if(typev[n->type->etype]) {
+		n1 = new(OXXX, 0, 0);
+		*n1 = *n;
+
+		n->right = n1;
+		n->left = nodtestv;
+		n->complex = FNX;
+		n->addable = 0;
+		n->op = OFUNC;
+		n->type = types[TLONG];
+	}
+}
+
+/*
+ * more machine depend stuff.
+ * this is common for 8,16,32,64 bit machines.
+ * this is common for ieee machines.
+ */
+double
+convvtof(vlong v)
+{
+	double d;
+
+	d = v;		/* BOTCH */
+	return d;
+}
+
+vlong
+convftov(double d)
+{
+	vlong v;
+
+
+	v = d;		/* BOTCH */
+	return v;
+}
+
+double
+convftox(double d, int et)
+{
+
+	if(!typefd[et])
+		diag(Z, "bad type in castftox %s", tnames[et]);
+	return d;
+}
+
+vlong
+convvtox(vlong c, int et)
+{
+	int n;
+
+	n = 8 * ewidth[et];
+	c &= MASK(n);
+	if(!typeu[et])
+		if(c & SIGN(n))
+			c |= ~MASK(n);
+	return c;
+}
diff --git a/src/cmd/cc/dcl.c b/src/cmd/cc/dcl.c
new file mode 100644
index 0000000..117508f
--- /dev/null
+++ b/src/cmd/cc/dcl.c
@@ -0,0 +1,1707 @@
+// Inferno utils/cc/dcl.c
+// http://code.google.com/p/inferno-os/source/browse/utils/cc/dcl.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 "cc.h"
+#include "../ld/textflag.h"
+
+static int haspointers(Type*);
+
+Node*
+dodecl(void (*f)(int,Type*,Sym*), int c, Type *t, Node *n)
+{
+	Sym *s;
+	Node *n1;
+	int32 v;
+
+	nearln = lineno;
+	lastfield = 0;
+
+loop:
+	if(n != Z)
+	switch(n->op) {
+	default:
+		diag(n, "unknown declarator: %O", n->op);
+		break;
+
+	case OARRAY:
+		t = typ(TARRAY, t);
+		t->width = 0;
+		n1 = n->right;
+		n = n->left;
+		if(n1 != Z) {
+			complex(n1);
+			v = -1;
+			if(n1->op == OCONST)
+				v = n1->vconst;
+			if(v <= 0) {
+				diag(n, "array size must be a positive constant");
+				v = 1;
+			}
+			t->width = v * t->link->width;
+		}
+		goto loop;
+
+	case OIND:
+		t = typ(TIND, t);
+		t->garb = n->garb;
+		n = n->left;
+		goto loop;
+
+	case OFUNC:
+		t = typ(TFUNC, t);
+		t->down = fnproto(n);
+		n = n->left;
+		goto loop;
+
+	case OBIT:
+		n1 = n->right;
+		complex(n1);
+		lastfield = -1;
+		if(n1->op == OCONST)
+			lastfield = n1->vconst;
+		if(lastfield < 0) {
+			diag(n, "field width must be non-negative constant");
+			lastfield = 1;
+		}
+		if(lastfield == 0) {
+			lastbit = 0;
+			firstbit = 1;
+			if(n->left != Z) {
+				diag(n, "zero width named field");
+				lastfield = 1;
+			}
+		}
+		if(!typei[t->etype]) {
+			diag(n, "field type must be int-like");
+			t = types[TINT];
+			lastfield = 1;
+		}
+		if(lastfield > tfield->width*8) {
+			diag(n, "field width larger than field unit");
+			lastfield = 1;
+		}
+		lastbit += lastfield;
+		if(lastbit > tfield->width*8) {
+			lastbit = lastfield;
+			firstbit = 1;
+		}
+		n = n->left;
+		goto loop;
+
+	case ONAME:
+		if(f == NODECL)
+			break;
+		s = n->sym;
+		(*f)(c, t, s);
+		if(s->class == CLOCAL)
+			s = mkstatic(s);
+		if(dataflag) {
+			s->dataflag = dataflag;
+			dataflag = 0;
+		} else if(s->type != T && !haspointers(s->type))
+			s->dataflag = NOPTR;
+		firstbit = 0;
+		n->sym = s;
+		n->type = s->type;
+		n->xoffset = s->offset;
+		n->class = s->class;
+		n->etype = TVOID;
+		if(n->type != T)
+			n->etype = n->type->etype;
+		if(debug['d'])
+			dbgdecl(s);
+		acidvar(s);
+		godefvar(s);
+		s->varlineno = lineno;
+		break;
+	}
+	lastdcl = t;
+	return n;
+}
+
+Sym*
+mkstatic(Sym *s)
+{
+	Sym *s1;
+
+	if(s->class != CLOCAL)
+		return s;
+	snprint(symb, NSYMB, "%s$%d", s->name, s->block);
+	s1 = lookup();
+	if(s1->class != CSTATIC) {
+		s1->type = s->type;
+		s1->offset = s->offset;
+		s1->block = s->block;
+		s1->class = CSTATIC;
+	}
+	return s1;
+}
+
+/*
+ * make a copy of a typedef
+ * the problem is to split out incomplete
+ * arrays so that it is in the variable
+ * rather than the typedef.
+ */
+Type*
+tcopy(Type *t)
+{
+	Type *tl, *tx;
+	int et;
+
+	if(t == T)
+		return t;
+	et = t->etype;
+	if(typesu[et])
+		return t;
+	tl = tcopy(t->link);
+	if(tl != t->link ||
+	  (et == TARRAY && t->width == 0)) {
+		tx = copytyp(t);
+		tx->link = tl;
+		return tx;
+	}
+	return t;
+}
+
+Node*
+doinit(Sym *s, Type *t, int32 o, Node *a)
+{
+	Node *n;
+
+	if(t == T)
+		return Z;
+	if(s->class == CEXTERN) {
+		s->class = CGLOBL;
+		if(debug['d'])
+			dbgdecl(s);
+	}
+	if(debug['i']) {
+		print("t = %T; o = %d; n = %s\n", t, o, s->name);
+		prtree(a, "doinit value");
+	}
+
+
+	n = initlist;
+	if(a->op == OINIT)
+		a = a->left;
+	initlist = a;
+
+	a = init1(s, t, o, 0);
+	if(initlist != Z)
+		diag(initlist, "more initializers than structure: %s",
+			s->name);
+	initlist = n;
+
+	return a;
+}
+
+/*
+ * get next major operator,
+ * dont advance initlist.
+ */
+Node*
+peekinit(void)
+{
+	Node *a;
+
+	a = initlist;
+
+loop:
+	if(a == Z)
+		return a;
+	if(a->op == OLIST) {
+		a = a->left;
+		goto loop;
+	}
+	return a;
+}
+
+/*
+ * consume and return next element on
+ * initlist. expand strings.
+ */
+Node*
+nextinit(void)
+{
+	Node *a, *b, *n;
+
+	a = initlist;
+	n = Z;
+
+	if(a == Z)
+		return a;
+	if(a->op == OLIST) {
+		n = a->right;
+		a = a->left;
+	}
+	if(a->op == OUSED) {
+		a = a->left;
+		b = new(OCONST, Z, Z);
+		b->type = a->type->link;
+		if(a->op == OSTRING) {
+			b->vconst = convvtox(*a->cstring, TCHAR);
+			a->cstring++;
+		}
+		if(a->op == OLSTRING) {
+			b->vconst = convvtox(*a->rstring, TRUNE);
+			a->rstring++;
+		}
+		a->type->width -= b->type->width;
+		if(a->type->width <= 0)
+			initlist = n;
+		return b;
+	}
+	initlist = n;
+	return a;
+}
+
+int
+isstruct(Node *a, Type *t)
+{
+	Node *n;
+
+	switch(a->op) {
+	case ODOTDOT:
+		n = a->left;
+		if(n && n->type && sametype(n->type, t))
+			return 1;
+	case OSTRING:
+	case OLSTRING:
+	case OCONST:
+	case OINIT:
+	case OELEM:
+		return 0;
+	}
+
+	n = new(ODOTDOT, Z, Z);
+	*n = *a;
+
+	/*
+	 * ODOTDOT is a flag for tcom
+	 * a second tcom will not be performed
+	 */
+	a->op = ODOTDOT;
+	a->left = n;
+	a->right = Z;
+
+	if(tcom(n))
+		return 0;
+
+	if(sametype(n->type, t))
+		return 1;
+	return 0;
+}
+
+Node*
+init1(Sym *s, Type *t, int32 o, int exflag)
+{
+	Node *a, *l, *r, nod;
+	Type *t1;
+	int32 e, w, so, mw;
+
+	a = peekinit();
+	if(a == Z)
+		return Z;
+
+	if(debug['i']) {
+		print("t = %T; o = %d; n = %s\n", t, o, s->name);
+		prtree(a, "init1 value");
+	}
+
+	if(exflag && a->op == OINIT)
+		return doinit(s, t, o, nextinit());
+
+	switch(t->etype) {
+	default:
+		diag(Z, "unknown type in initialization: %T to: %s", t, s->name);
+		return Z;
+
+	case TCHAR:
+	case TUCHAR:
+	case TINT:
+	case TUINT:
+	case TSHORT:
+	case TUSHORT:
+	case TLONG:
+	case TULONG:
+	case TVLONG:
+	case TUVLONG:
+	case TFLOAT:
+	case TDOUBLE:
+	case TIND:
+	single:
+		if(a->op == OARRAY || a->op == OELEM)
+			return Z;
+
+		a = nextinit();
+		if(a == Z)
+			return Z;
+
+		if(t->nbits)
+			diag(Z, "cannot initialize bitfields");
+		if(s->class == CAUTO) {
+			l = new(ONAME, Z, Z);
+			l->sym = s;
+			l->type = t;
+			l->etype = TVOID;
+			if(s->type)
+				l->etype = s->type->etype;
+			l->xoffset = s->offset + o;
+			l->class = s->class;
+
+			l = new(OASI, l, a);
+			return l;
+		}
+
+		complex(a);
+		if(a->type == T)
+			return Z;
+
+		if(a->op == OCONST) {
+			if(vconst(a) && t->etype == TIND && a->type && a->type->etype != TIND){
+				diag(a, "initialize pointer to an integer: %s", s->name);
+				return Z;
+			}
+			if(!sametype(a->type, t)) {
+				/* hoop jumping to save malloc */
+				if(nodcast == Z)
+					nodcast = new(OCAST, Z, Z);
+				nod = *nodcast;
+				nod.left = a;
+				nod.type = t;
+				nod.lineno = a->lineno;
+				complex(&nod);
+				if(nod.type)
+					*a = nod;
+			}
+			if(a->op != OCONST) {
+				diag(a, "initializer is not a constant: %s",
+					s->name);
+				return Z;
+			}
+			if(vconst(a) == 0)
+				return Z;
+			goto gext;
+		}
+		if(t->etype == TIND) {
+			while(a->op == OCAST) {
+				warn(a, "CAST in initialization ignored");
+				a = a->left;
+			}
+			if(!sametype(t, a->type)) {
+				diag(a, "initialization of incompatible pointers: %s\n%T and %T",
+					s->name, t, a->type);
+			}
+			if(a->op == OADDR)
+				a = a->left;
+			goto gext;
+		}
+
+		while(a->op == OCAST)
+			a = a->left;
+		if(a->op == OADDR) {
+			warn(a, "initialize pointer to an integer: %s", s->name);
+			a = a->left;
+			goto gext;
+		}
+		diag(a, "initializer is not a constant: %s", s->name);
+		return Z;
+
+	gext:
+		gextern(s, a, o, t->width);
+
+		return Z;
+
+	case TARRAY:
+		w = t->link->width;
+		if(a->op == OSTRING || a->op == OLSTRING)
+		if(typei[t->link->etype]) {
+			/*
+			 * get rid of null if sizes match exactly
+			 */
+			a = nextinit();
+			mw = t->width/w;
+			so = a->type->width/a->type->link->width;
+			if(mw && so > mw) {
+				if(so != mw+1)
+					diag(a, "string initialization larger than array");
+				a->type->width -= a->type->link->width;
+			}
+
+			/*
+			 * arrange strings to be expanded
+			 * inside OINIT braces.
+			 */
+			a = new(OUSED, a, Z);
+			return doinit(s, t, o, a);
+		}
+
+		mw = -w;
+		l = Z;
+		for(e=0;;) {
+			/*
+			 * peek ahead for element initializer
+			 */
+			a = peekinit();
+			if(a == Z)
+				break;
+			if(a->op == OELEM && t->link->etype != TSTRUCT)
+				break;
+			if(a->op == OARRAY) {
+				if(e && exflag)
+					break;
+				a = nextinit();
+				r = a->left;
+				complex(r);
+				if(r->op != OCONST) {
+					diag(r, "initializer subscript must be constant");
+					return Z;
+				}
+				e = r->vconst;
+				if(t->width != 0)
+					if(e < 0 || e*w >= t->width) {
+						diag(a, "initialization index out of range: %d", e);
+						continue;
+					}
+			}
+
+			so = e*w;
+			if(so > mw)
+				mw = so;
+			if(t->width != 0)
+				if(mw >= t->width)
+					break;
+			r = init1(s, t->link, o+so, 1);
+			l = newlist(l, r);
+			e++;
+		}
+		if(t->width == 0)
+			t->width = mw+w;
+		return l;
+
+	case TUNION:
+	case TSTRUCT:
+		/*
+		 * peek ahead to find type of rhs.
+		 * if its a structure, then treat
+		 * this element as a variable
+		 * rather than an aggregate.
+		 */
+		if(isstruct(a, t))
+			goto single;
+
+		if(t->width <= 0) {
+			diag(Z, "incomplete structure: %s", s->name);
+			return Z;
+		}
+		l = Z;
+
+	again:
+		for(t1 = t->link; t1 != T; t1 = t1->down) {
+			if(a->op == OARRAY && t1->etype != TARRAY)
+				break;
+			if(a->op == OELEM) {
+				if(t1->sym != a->sym)
+					continue;
+				nextinit();
+			}
+			r = init1(s, t1, o+t1->offset, 1);
+			l = newlist(l, r);
+			a = peekinit();
+			if(a == Z)
+				break;
+			if(a->op == OELEM)
+				goto again;
+		}
+		if(a && a->op == OELEM)
+			diag(a, "structure element not found %F", a);
+		return l;
+	}
+}
+
+Node*
+newlist(Node *l, Node *r)
+{
+	if(r == Z)
+		return l;
+	if(l == Z)
+		return r;
+	return new(OLIST, l, r);
+}
+
+static int
+haspointers(Type *t)
+{
+	Type *fld;
+
+	switch(t->etype) {
+	case TSTRUCT:
+		for(fld = t->link; fld != T; fld = fld->down) {
+			if(haspointers(fld))
+				return 1;
+		}
+		return 0;
+	case TARRAY:
+		return haspointers(t->link);
+	case TIND:
+		return t->link->etype != TFUNC;
+	default:
+		return 0;
+	}
+}
+
+void
+sualign(Type *t)
+{
+	Type *l;
+	int32 o, w, maxal;
+
+	o = 0;
+	maxal = 0;
+	switch(t->etype) {
+
+	case TSTRUCT:
+		t->offset = 0;
+		w = 0;
+		for(l = t->link; l != T; l = l->down) {
+			if(l->nbits) {
+				if(l->shift <= 0) {
+					l->shift = -l->shift;
+					w = xround(w, tfield->width);
+					o = w;
+					w += tfield->width;
+				}
+				l->offset = o;
+			} else {
+				if(l->width <= 0)
+				if(l->down != T)
+					if(l->sym)
+						diag(Z, "incomplete structure element: %s",
+							l->sym->name);
+					else
+						diag(Z, "incomplete structure element");
+				w = align(w, l, Ael1, &maxal);
+				l->offset = w;
+				w = align(w, l, Ael2, &maxal);
+			}
+		}
+		w = align(w, t, Asu2, &maxal);
+		t->width = w;
+		t->align = maxal;
+		acidtype(t);
+		godeftype(t);
+		return;
+
+	case TUNION:
+		t->offset = 0;
+		w = 0;
+		for(l = t->link; l != T; l = l->down) {
+			if(l->width <= 0)
+				if(l->sym)
+					diag(Z, "incomplete union element: %s",
+						l->sym->name);
+				else
+					diag(Z, "incomplete union element");
+			l->offset = 0;
+			l->shift = 0;
+			if((debug['q'] || debug['Q']) && haspointers(l))
+				diag(Z, "precise garbage collector cannot handle unions with pointers");
+
+			o = align(align(0, l, Ael1, &maxal), l, Ael2, &maxal);
+			if(o > w)
+				w = o;
+		}
+		w = align(w, t, Asu2, &maxal);
+		t->width = w;
+		t->align = maxal;
+		acidtype(t);
+		godeftype(t);
+		return;
+
+	default:
+		diag(Z, "unknown type in sualign: %T", t);
+		break;
+	}
+}
+
+int32
+xround(int32 v, int w)
+{
+	int r;
+
+	if(w <= 0 || w > 8) {
+		diag(Z, "rounding by %d", w);
+		w = 1;
+	}
+	r = v%w;
+	if(r)
+		v += w-r;
+	return v;
+}
+
+Type*
+ofnproto(Node *n)
+{
+	Type *tl, *tr, *t;
+
+	if(n == Z)
+		return T;
+	switch(n->op) {
+	case OLIST:
+		tl = ofnproto(n->left);
+		tr = ofnproto(n->right);
+		if(tl == T)
+			return tr;
+		tl->down = tr;
+		return tl;
+
+	case ONAME:
+		t = copytyp(n->sym->type);
+		t->down = T;
+		return t;
+	}
+	return T;
+}
+
+#define	ANSIPROTO	1
+#define	OLDPROTO	2
+
+void
+argmark(Node *n, int pass)
+{
+	Type *t;
+
+	if(hasdotdotdot(thisfn->link))
+		autoffset = align(0, thisfn->link, Aarg0, nil);
+	stkoff = 0;
+	for(; n->left != Z; n = n->left) {
+		if(n->op != OFUNC || n->left->op != ONAME)
+			continue;
+		walkparam(n->right, pass);
+		if(pass != 0 && anyproto(n->right) == OLDPROTO) {
+			t = typ(TFUNC, n->left->sym->type->link);
+			t->down = typ(TOLD, T);
+			t->down->down = ofnproto(n->right);
+			tmerge(t, n->left->sym);
+			n->left->sym->type = t;
+		}
+		break;
+	}
+	autoffset = 0;
+	stkoff = 0;
+}
+
+void
+walkparam(Node *n, int pass)
+{
+	Sym *s;
+	Node *n1;
+
+	if(n != Z && n->op == OPROTO && n->left == Z && n->type == types[TVOID])
+		return;
+
+loop:
+	if(n == Z)
+		return;
+	switch(n->op) {
+	default:
+		diag(n, "argument not a name/prototype: %O", n->op);
+		break;
+
+	case OLIST:
+		walkparam(n->left, pass);
+		n = n->right;
+		goto loop;
+
+	case OPROTO:
+		for(n1 = n; n1 != Z; n1=n1->left)
+			if(n1->op == ONAME) {
+				if(pass == 0) {
+					s = n1->sym;
+					push1(s);
+					s->offset = -1;
+					break;
+				}
+				dodecl(pdecl, CPARAM, n->type, n->left);
+				break;
+			}
+		if(n1)
+			break;
+		if(pass == 0) {
+			/*
+			 * extension:
+			 *	allow no name in argument declaration
+			diag(Z, "no name in argument declaration");
+			 */
+			break;
+		}
+		dodecl(NODECL, CPARAM, n->type, n->left);
+		pdecl(CPARAM, lastdcl, S);
+		break;
+
+	case ODOTDOT:
+		break;
+	
+	case ONAME:
+		s = n->sym;
+		if(pass == 0) {
+			push1(s);
+			s->offset = -1;
+			break;
+		}
+		if(s->offset != -1) {
+			if(autoffset == 0) {
+				firstarg = s;
+				firstargtype = s->type;
+			}
+			autoffset = align(autoffset, s->type, Aarg1, nil);
+			s->offset = autoffset;
+			autoffset = align(autoffset, s->type, Aarg2, nil);
+		} else
+			dodecl(pdecl, CXXX, types[TINT], n);
+		break;
+	}
+}
+
+void
+markdcl(void)
+{
+	Decl *d;
+
+	blockno++;
+	d = push();
+	d->val = DMARK;
+	d->offset = autoffset;
+	d->block = autobn;
+	autobn = blockno;
+}
+
+Node*
+revertdcl(void)
+{
+	Decl *d;
+	Sym *s;
+	Node *n, *n1;
+
+	n = Z;
+	for(;;) {
+		d = dclstack;
+		if(d == D) {
+			diag(Z, "pop off dcl stack");
+			break;
+		}
+		dclstack = d->link;
+		s = d->sym;
+		switch(d->val) {
+		case DMARK:
+			autoffset = d->offset;
+			autobn = d->block;
+			return n;
+
+		case DAUTO:
+			if(debug['d'])
+				print("revert1 \"%s\"\n", s->name);
+			if(s->aused == 0) {
+				nearln = s->varlineno;
+				if(s->class == CAUTO)
+					warn(Z, "auto declared and not used: %s", s->name);
+				if(s->class == CPARAM)
+					warn(Z, "param declared and not used: %s", s->name);
+			}
+			if(s->type && (s->type->garb & GVOLATILE)) {
+				n1 = new(ONAME, Z, Z);
+				n1->sym = s;
+				n1->type = s->type;
+				n1->etype = TVOID;
+				if(n1->type != T)
+					n1->etype = n1->type->etype;
+				n1->xoffset = s->offset;
+				n1->class = s->class;
+
+				n1 = new(OADDR, n1, Z);
+				n1 = new(OUSED, n1, Z);
+				if(n == Z)
+					n = n1;
+				else
+					n = new(OLIST, n1, n);
+			}
+			s->type = d->type;
+			s->class = d->class;
+			s->offset = d->offset;
+			s->block = d->block;
+			s->varlineno = d->varlineno;
+			s->aused = d->aused;
+			break;
+
+		case DSUE:
+			if(debug['d'])
+				print("revert2 \"%s\"\n", s->name);
+			s->suetag = d->type;
+			s->sueblock = d->block;
+			break;
+
+		case DLABEL:
+			if(debug['d'])
+				print("revert3 \"%s\"\n", s->name);
+			if(s->label && s->label->addable == 0)
+				warn(s->label, "label declared and not used \"%s\"", s->name);
+			s->label = Z;
+			break;
+		}
+	}
+	return n;
+}
+
+Type*
+fnproto(Node *n)
+{
+	int r;
+
+	r = anyproto(n->right);
+	if(r == 0 || (r & OLDPROTO)) {
+		if(r & ANSIPROTO)
+			diag(n, "mixed ansi/old function declaration: %F", n->left);
+		return T;
+	}
+	return fnproto1(n->right);
+}
+
+int
+anyproto(Node *n)
+{
+	int r;
+
+	r = 0;
+
+loop:
+	if(n == Z)
+		return r;
+	switch(n->op) {
+	case OLIST:
+		r |= anyproto(n->left);
+		n = n->right;
+		goto loop;
+
+	case ODOTDOT:
+	case OPROTO:
+		return r | ANSIPROTO;
+	}
+	return r | OLDPROTO;
+}
+
+Type*
+fnproto1(Node *n)
+{
+	Type *t;
+
+	if(n == Z)
+		return T;
+	switch(n->op) {
+	case OLIST:
+		t = fnproto1(n->left);
+		if(t != T)
+			t->down = fnproto1(n->right);
+		return t;
+
+	case OPROTO:
+		lastdcl = T;
+		dodecl(NODECL, CXXX, n->type, n->left);
+		t = typ(TXXX, T);
+		if(lastdcl != T)
+			*t = *paramconv(lastdcl, 1);
+		return t;
+
+	case ONAME:
+		diag(n, "incomplete argument prototype");
+		return typ(TINT, T);
+
+	case ODOTDOT:
+		return typ(TDOT, T);
+	}
+	diag(n, "unknown op in fnproto");
+	return T;
+}
+
+void
+dbgdecl(Sym *s)
+{
+	print("decl \"%s\": C=%s [B=%d:O=%d] T=%T\n",
+		s->name, cnames[s->class], s->block, s->offset, s->type);
+}
+
+Decl*
+push(void)
+{
+	Decl *d;
+
+	d = alloc(sizeof(*d));
+	d->link = dclstack;
+	dclstack = d;
+	return d;
+}
+
+Decl*
+push1(Sym *s)
+{
+	Decl *d;
+
+	d = push();
+	d->sym = s;
+	d->val = DAUTO;
+	d->type = s->type;
+	d->class = s->class;
+	d->offset = s->offset;
+	d->block = s->block;
+	d->varlineno = s->varlineno;
+	d->aused = s->aused;
+	return d;
+}
+
+int
+sametype(Type *t1, Type *t2)
+{
+
+	if(t1 == t2)
+		return 1;
+	return rsametype(t1, t2, 5, 1);
+}
+
+int
+rsametype(Type *t1, Type *t2, int n, int f)
+{
+	int et;
+
+	n--;
+	for(;;) {
+		if(t1 == t2)
+			return 1;
+		if(t1 == T || t2 == T)
+			return 0;
+		if(n <= 0)
+			return 1;
+		et = t1->etype;
+		if(et != t2->etype)
+			return 0;
+		if(et == TFUNC) {
+			if(!rsametype(t1->link, t2->link, n, 0))
+				return 0;
+			t1 = t1->down;
+			t2 = t2->down;
+			while(t1 != T && t2 != T) {
+				if(t1->etype == TOLD) {
+					t1 = t1->down;
+					continue;
+				}
+				if(t2->etype == TOLD) {
+					t2 = t2->down;
+					continue;
+				}
+				while(t1 != T || t2 != T) {
+					if(!rsametype(t1, t2, n, 0))
+						return 0;
+					t1 = t1->down;
+					t2 = t2->down;
+				}
+				break;
+			}
+			return 1;
+		}
+		if(et == TARRAY)
+			if(t1->width != t2->width && t1->width != 0 && t2->width != 0)
+				return 0;
+		if(typesu[et]) {
+			if(t1->link == T)
+				snap(t1);
+			if(t2->link == T)
+				snap(t2);
+			t1 = t1->link;
+			t2 = t2->link;
+			for(;;) {
+				if(t1 == t2)
+					return 1;
+				if(!rsametype(t1, t2, n, 0))
+					return 0;
+				t1 = t1->down;
+				t2 = t2->down;
+			}
+		}
+		t1 = t1->link;
+		t2 = t2->link;
+		if((f || !debug['V']) && et == TIND) {
+			if(t1 != T && t1->etype == TVOID)
+				return 1;
+			if(t2 != T && t2->etype == TVOID)
+				return 1;
+		}
+	}
+}
+
+typedef struct Typetab Typetab;
+
+struct Typetab{
+	int n;
+	Type **a;
+};
+
+static int
+sigind(Type *t, Typetab *tt)
+{
+	int n;
+	Type **a, **na, **p, **e;
+
+	n = tt->n;
+	a = tt->a;
+	e = a+n;
+	/* linear search seems ok */
+	for(p = a ; p < e; p++)
+		if(sametype(*p, t))
+			return p-a;
+	if((n&15) == 0){
+		na = malloc((n+16)*sizeof(Type*));
+		if(na == nil) {
+			print("%s: out of memory", argv0);
+			errorexit();
+		}
+		memmove(na, a, n*sizeof(Type*));
+		free(a);
+		a = tt->a = na;
+	}
+	a[tt->n++] = t;
+	return -1;
+}
+
+static uint32
+signat(Type *t, Typetab *tt)
+{
+	int i;
+	Type *t1;
+	int32 s;
+
+	s = 0;
+	for(; t; t=t->link) {
+		s = s*thash1 + thash[t->etype];
+		if(t->garb&GINCOMPLETE)
+			return s;
+		switch(t->etype) {
+		default:
+			return s;
+		case TARRAY:
+			s = s*thash2 + 0;	/* was t->width */
+			break;
+		case TFUNC:
+			for(t1=t->down; t1; t1=t1->down)
+				s = s*thash3 + signat(t1, tt);
+			break;
+		case TSTRUCT:
+		case TUNION:
+			if((i = sigind(t, tt)) >= 0){
+				s = s*thash2 + i;
+				return s;
+			}
+			for(t1=t->link; t1; t1=t1->down)
+				s = s*thash3 + signat(t1, tt);
+			return s;
+		case TIND:
+			break;
+		}
+	}
+	return s;
+}
+
+uint32
+signature(Type *t)
+{
+	uint32 s;
+	Typetab tt;
+
+	tt.n = 0;
+	tt.a = nil;
+	s = signat(t, &tt);
+	free(tt.a);
+	return s;
+}
+
+uint32
+sign(Sym *s)
+{
+	uint32 v;
+	Type *t;
+
+	if(s->sig == SIGINTERN)
+		return SIGNINTERN;
+	if((t = s->type) == T)
+		return 0;
+	v = signature(t);
+	if(v == 0)
+		v = SIGNINTERN;
+	return v;
+}
+
+void
+snap(Type *t)
+{
+	if(typesu[t->etype])
+	if(t->link == T && t->tag && t->tag->suetag) {
+		t->link = t->tag->suetag->link;
+		t->width = t->tag->suetag->width;
+	}
+}
+
+Type*
+dotag(Sym *s, int et, int bn)
+{
+	Decl *d;
+
+	if(bn != 0 && bn != s->sueblock) {
+		d = push();
+		d->sym = s;
+		d->val = DSUE;
+		d->type = s->suetag;
+		d->block = s->sueblock;
+		s->suetag = T;
+	}
+	if(s->suetag == T) {
+		s->suetag = typ(et, T);
+		s->sueblock = autobn;
+	}
+	if(s->suetag->etype != et)
+		diag(Z, "tag used for more than one type: %s",
+			s->name);
+	if(s->suetag->tag == S)
+		s->suetag->tag = s;
+	return s->suetag;
+}
+
+Node*
+dcllabel(Sym *s, int f)
+{
+	Decl *d, d1;
+	Node *n;
+
+	n = s->label;
+	if(n != Z) {
+		if(f) {
+			if(n->complex)
+				diag(Z, "label reused: %s", s->name);
+			n->complex = 1;	// declared
+		} else
+			n->addable = 1;	// used
+		return n;
+	}
+
+	d = push();
+	d->sym = s;
+	d->val = DLABEL;
+	dclstack = d->link;
+
+	d1 = *firstdcl;
+	*firstdcl = *d;
+	*d = d1;
+
+	firstdcl->link = d;
+	firstdcl = d;
+
+	n = new(OXXX, Z, Z);
+	n->sym = s;
+	n->complex = f;
+	n->addable = !f;
+	s->label = n;
+
+	if(debug['d'])
+		dbgdecl(s);
+	return n;
+}
+
+Type*
+paramconv(Type *t, int f)
+{
+
+	switch(t->etype) {
+	case TUNION:
+	case TSTRUCT:
+		if(t->width <= 0)
+			diag(Z, "incomplete structure: %s", t->tag->name);
+		break;
+
+	case TARRAY:
+		t = typ(TIND, t->link);
+		t->width = types[TIND]->width;
+		break;
+
+	case TFUNC:
+		t = typ(TIND, t);
+		t->width = types[TIND]->width;
+		break;
+
+	case TFLOAT:
+		if(!f)
+			t = types[TDOUBLE];
+		break;
+
+	case TCHAR:
+	case TSHORT:
+		if(!f)
+			t = types[TINT];
+		break;
+
+	case TUCHAR:
+	case TUSHORT:
+		if(!f)
+			t = types[TUINT];
+		break;
+	}
+	return t;
+}
+
+void
+adecl(int c, Type *t, Sym *s)
+{
+
+	if(c == CSTATIC)
+		c = CLOCAL;
+	if(t->etype == TFUNC) {
+		if(c == CXXX)
+			c = CEXTERN;
+		if(c == CLOCAL)
+			c = CSTATIC;
+		if(c == CAUTO || c == CEXREG)
+			diag(Z, "function cannot be %s %s", cnames[c], s->name);
+	}
+	if(c == CXXX)
+		c = CAUTO;
+	if(s) {
+		if(s->class == CSTATIC)
+			if(c == CEXTERN || c == CGLOBL) {
+				warn(Z, "just say static: %s", s->name);
+				c = CSTATIC;
+			}
+		if(s->class == CAUTO || s->class == CPARAM || s->class == CLOCAL)
+		if(s->block == autobn)
+			diag(Z, "auto redeclaration of: %s", s->name);
+		if(c != CPARAM)
+			push1(s);
+		s->block = autobn;
+		s->offset = 0;
+		s->type = t;
+		s->class = c;
+		s->aused = 0;
+	}
+	switch(c) {
+	case CAUTO:
+		autoffset = align(autoffset, t, Aaut3, nil);
+		stkoff = maxround(stkoff, autoffset);
+		s->offset = -autoffset;
+		break;
+
+	case CPARAM:
+		if(autoffset == 0) {
+			firstarg = s;
+			firstargtype = t;
+		}
+		autoffset = align(autoffset, t, Aarg1, nil);
+		if(s)
+			s->offset = autoffset;
+		autoffset = align(autoffset, t, Aarg2, nil);
+		break;
+	}
+}
+
+void
+pdecl(int c, Type *t, Sym *s)
+{
+	if(s && s->offset != -1) {
+		diag(Z, "not a parameter: %s", s->name);
+		return;
+	}
+	t = paramconv(t, c==CPARAM);
+	if(c == CXXX)
+		c = CPARAM;
+	if(c != CPARAM) {
+		diag(Z, "parameter cannot have class: %s", s->name);
+		c = CPARAM;
+	}
+	adecl(c, t, s);
+}
+
+void
+xdecl(int c, Type *t, Sym *s)
+{
+	int32 o;
+
+	o = 0;
+	switch(c) {
+	case CEXREG:
+		o = exreg(t);
+		if(o == 0)
+			c = CEXTERN;
+		if(s->class == CGLOBL)
+			c = CGLOBL;
+		break;
+
+	case CEXTERN:
+		if(s->class == CGLOBL)
+			c = CGLOBL;
+		break;
+
+	case CXXX:
+		c = CGLOBL;
+		if(s->class == CEXTERN)
+			s->class = CGLOBL;
+		break;
+
+	case CAUTO:
+		diag(Z, "overspecified class: %s %s %s", s->name, cnames[c], cnames[s->class]);
+		c = CEXTERN;
+		break;
+
+	case CTYPESTR:
+		if(!typesuv[t->etype]) {
+			diag(Z, "typestr must be struct/union: %s", s->name);
+			break;
+		}
+		dclfunct(t, s);
+		break;
+	}
+
+	if(s->class == CSTATIC)
+		if(c == CEXTERN || c == CGLOBL) {
+			warn(Z, "overspecified class: %s %s %s", s->name, cnames[c], cnames[s->class]);
+			c = CSTATIC;
+		}
+	if(s->type != T)
+		if(s->class != c || !sametype(t, s->type) || t->etype == TENUM) {
+			diag(Z, "external redeclaration of: %s", s->name);
+			Bprint(&diagbuf, "	%s %T %L\n", cnames[c], t, nearln);
+			Bprint(&diagbuf, "	%s %T %L\n", cnames[s->class], s->type, s->varlineno);
+		}
+	tmerge(t, s);
+	s->type = t;
+	if(c == CTYPEDEF && (typechlv[t->etype] || typefd[t->etype])) {
+		s->type = copytyp(t);
+		s->type->tag = s;
+	}
+	s->class = c;
+	s->block = 0;
+	s->offset = o;
+}
+
+void
+tmerge(Type *t1, Sym *s)
+{
+	Type *ta, *tb, *t2;
+
+	t2 = s->type;
+	for(;;) {
+		if(t1 == T || t2 == T || t1 == t2)
+			break;
+		if(t1->etype != t2->etype)
+			break;
+		switch(t1->etype) {
+		case TFUNC:
+			ta = t1->down;
+			tb = t2->down;
+			if(ta == T) {
+				t1->down = tb;
+				break;
+			}
+			if(tb == T)
+				break;
+			while(ta != T && tb != T) {
+				if(ta == tb)
+					break;
+				/* ignore old-style flag */
+				if(ta->etype == TOLD) {
+					ta = ta->down;
+					continue;
+				}
+				if(tb->etype == TOLD) {
+					tb = tb->down;
+					continue;
+				}
+				/* checking terminated by ... */
+				if(ta->etype == TDOT && tb->etype == TDOT) {
+					ta = T;
+					tb = T;
+					break;
+				}
+				if(!sametype(ta, tb))
+					break;
+				ta = ta->down;
+				tb = tb->down;
+			}
+			if(ta != tb)
+				diag(Z, "function inconsistently declared: %s", s->name);
+
+			/* take new-style over old-style */
+			ta = t1->down;
+			tb = t2->down;
+			if(ta != T && ta->etype == TOLD)
+				if(tb != T && tb->etype != TOLD)
+					t1->down = tb;
+			break;
+
+		case TARRAY:
+			/* should we check array size change? */
+			if(t2->width > t1->width)
+				t1->width = t2->width;
+			break;
+
+		case TUNION:
+		case TSTRUCT:
+			return;
+		}
+		t1 = t1->link;
+		t2 = t2->link;
+	}
+}
+
+void
+edecl(int c, Type *t, Sym *s)
+{
+	Type *t1;
+
+	if(s == S)
+		diag(Z, "unnamed structure elements not supported");
+	else
+		if(c != CXXX)
+			diag(Z, "structure element cannot have class: %s", s->name);
+	t1 = t;
+	t = copytyp(t1);
+	t->sym = s;
+	t->down = T;
+	if(lastfield) {
+		t->shift = lastbit - lastfield;
+		t->nbits = lastfield;
+		if(firstbit)
+			t->shift = -t->shift;
+		if(typeu[t->etype])
+			t->etype = tufield->etype;
+		else
+			t->etype = tfield->etype;
+	}
+	if(strf == T)
+		strf = t;
+	else
+		strl->down = t;
+	strl = t;
+}
+
+/*
+ * this routine is very suspect.
+ * ansi requires the enum type to
+ * be represented as an 'int'
+ * this means that 0x81234567
+ * would be illegal. this routine
+ * makes signed and unsigned go
+ * to unsigned.
+ */
+Type*
+maxtype(Type *t1, Type *t2)
+{
+
+	if(t1 == T)
+		return t2;
+	if(t2 == T)
+		return t1;
+	if(t1->etype > t2->etype)
+		return t1;
+	return t2;
+}
+
+void
+doenum(Sym *s, Node *n)
+{
+
+	if(n) {
+		complex(n);
+		if(n->op != OCONST) {
+			diag(n, "enum not a constant: %s", s->name);
+			return;
+		}
+		en.cenum = n->type;
+		en.tenum = maxtype(en.cenum, en.tenum);
+
+		if(!typefd[en.cenum->etype])
+			en.lastenum = n->vconst;
+		else
+			en.floatenum = n->fconst;
+	}
+	if(dclstack)
+		push1(s);
+	xdecl(CXXX, types[TENUM], s);
+
+	if(en.cenum == T) {
+		en.tenum = types[TINT];
+		en.cenum = types[TINT];
+		en.lastenum = 0;
+	}
+	s->tenum = en.cenum;
+
+	if(!typefd[s->tenum->etype]) {
+		s->vconst = convvtox(en.lastenum, s->tenum->etype);
+		en.lastenum++;
+	} else {
+		s->fconst = en.floatenum;
+		en.floatenum++;
+	}
+
+	if(debug['d'])
+		dbgdecl(s);
+	acidvar(s);
+	godefvar(s);
+}
+
+void
+symadjust(Sym *s, Node *n, int32 del)
+{
+
+	switch(n->op) {
+	default:
+		if(n->left)
+			symadjust(s, n->left, del);
+		if(n->right)
+			symadjust(s, n->right, del);
+		return;
+
+	case ONAME:
+		if(n->sym == s)
+			n->xoffset -= del;
+		return;
+
+	case OCONST:
+	case OSTRING:
+	case OLSTRING:
+	case OINDREG:
+	case OREGISTER:
+		return;
+	}
+}
+
+Node*
+contig(Sym *s, Node *n, int32 v)
+{
+	Node *p, *r, *q, *m;
+	int32 w;
+	Type *zt;
+
+	if(debug['i']) {
+		print("contig v = %d; s = %s\n", v, s->name);
+		prtree(n, "doinit value");
+	}
+
+	if(n == Z)
+		goto no;
+	w = s->type->width;
+
+	/*
+	 * nightmare: an automatic array whose size
+	 * increases when it is initialized
+	 */
+	if(v != w) {
+		if(v != 0)
+			diag(n, "automatic adjustable array: %s", s->name);
+		v = s->offset;
+		autoffset = align(autoffset, s->type, Aaut3, nil);
+		s->offset = -autoffset;
+		stkoff = maxround(stkoff, autoffset);
+		symadjust(s, n, v - s->offset);
+	}
+	if(w <= ewidth[TIND])
+		goto no;
+	if(n->op == OAS)
+		diag(Z, "oops in contig");
+/*ZZZ this appears incorrect
+need to check if the list completely covers the data.
+if not, bail
+ */
+	if(n->op == OLIST)
+		goto no;
+	if(n->op == OASI)
+		if(n->left->type)
+		if(n->left->type->width == w)
+			goto no;
+	while(w & (ewidth[TIND]-1))
+		w++;
+/*
+ * insert the following code, where long becomes vlong if pointers are fat
+ *
+	*(long**)&X = (long*)((char*)X + sizeof(X));
+	do {
+		*(long**)&X -= 1;
+		**(long**)&X = 0;
+	} while(*(long**)&X);
+ */
+
+	for(q=n; q->op != ONAME; q=q->left)
+		;
+
+	zt = ewidth[TIND] > ewidth[TLONG]? types[TVLONG]: types[TLONG];
+
+	p = new(ONAME, Z, Z);
+	*p = *q;
+	p->type = typ(TIND, zt);
+	p->xoffset = s->offset;
+
+	r = new(ONAME, Z, Z);
+	*r = *p;
+	r = new(OPOSTDEC, r, Z);
+
+	q = new(ONAME, Z, Z);
+	*q = *p;
+	q = new(OIND, q, Z);
+
+	m = new(OCONST, Z, Z);
+	m->vconst = 0;
+	m->type = zt;
+
+	q = new(OAS, q, m);
+
+	r = new(OLIST, r, q);
+
+	q = new(ONAME, Z, Z);
+	*q = *p;
+	r = new(ODWHILE, q, r);
+
+	q = new(ONAME, Z, Z);
+	*q = *p;
+	q->type = q->type->link;
+	q->xoffset += w;
+	q = new(OADDR, q, 0);
+
+	q = new(OASI, p, q);
+	r = new(OLIST, q, r);
+
+	n = new(OLIST, r, n);
+
+no:
+	return n;
+}
diff --git a/src/cmd/cc/doc.go b/src/cmd/cc/doc.go
new file mode 100644
index 0000000..10901b4
--- /dev/null
+++ b/src/cmd/cc/doc.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.
+
+// +build ignore
+
+/*
+
+This directory contains the portable section of the Plan 9 C compilers.
+See ../6c, ../8c, and ../5c for more information.
+
+*/
+package main
diff --git a/src/cmd/cc/dpchk.c b/src/cmd/cc/dpchk.c
new file mode 100644
index 0000000..606bf40
--- /dev/null
+++ b/src/cmd/cc/dpchk.c
@@ -0,0 +1,793 @@
+// Inferno utils/cc/dpchk.c
+// http://code.google.com/p/inferno-os/source/browse/utils/cc/dpchk.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	"cc.h"
+#include	"y.tab.h"
+
+enum
+{
+	Fnone	= 0,
+	Fl,
+	Fvl,
+	Fignor,
+	Fstar,
+	Fadj,
+
+	Fverb	= 10,
+};
+
+typedef	struct	Tprot	Tprot;
+struct	Tprot
+{
+	Type*	type;
+	Bits	flag;
+	Tprot*	link;
+};
+
+typedef	struct	Tname	Tname;
+struct	Tname
+{
+	char*	name;
+	int	param;
+	int	count;
+	Tname*	link;
+	Tprot*	prot;
+};
+
+static	Type*	indchar;
+static	uchar	flagbits[512];
+static	char*	lastfmt;
+static	int	lastadj;
+static	int	lastverb;
+static	int	nstar;
+static	Tprot*	tprot;
+static	Tname*	tname;
+
+void
+argflag(int c, int v)
+{
+
+	switch(v) {
+	case Fignor:
+	case Fstar:
+	case Fl:
+	case Fvl:
+		flagbits[c] = v;
+		break;
+	case Fverb:
+		flagbits[c] = lastverb;
+/*print("flag-v %c %d\n", c, lastadj);*/
+		lastverb++;
+		break;
+	case Fadj:
+		flagbits[c] = lastadj;
+/*print("flag-l %c %d\n", c, lastadj);*/
+		lastadj++;
+		break;
+	}
+}
+
+Bits
+getflag(char *s)
+{
+	Bits flag;
+	int f;
+	Fmt fmt;
+	Rune c;
+
+	flag = zbits;
+	nstar = 0;
+	fmtstrinit(&fmt);
+	for(;;) {
+		s += chartorune(&c, s);
+		if(c == 0 || c >= nelem(flagbits))
+			break;
+		fmtrune(&fmt, c);
+		f = flagbits[c];
+		switch(f) {
+		case Fnone:
+			argflag(c, Fverb);
+			f = flagbits[c];
+			break;
+		case Fstar:
+			nstar++;
+		case Fignor:
+			continue;
+		case Fl:
+			if(bset(flag, Fl))
+				flag = bor(flag, blsh(Fvl));
+		}
+		flag = bor(flag, blsh(f));
+		if(f >= Fverb)
+			break;
+	}
+	free(lastfmt);
+	lastfmt = fmtstrflush(&fmt);
+	return flag;
+}
+
+static void
+newprot(Sym *m, Type *t, char *s, Tprot **prot)
+{
+	Bits flag;
+	Tprot *l;
+
+	if(t == T) {
+		warn(Z, "%s: newprot: type not defined", m->name);
+		return;
+	}
+	flag = getflag(s);
+	for(l=*prot; l; l=l->link)
+		if(beq(flag, l->flag) && sametype(t, l->type))
+			return;
+	l = alloc(sizeof(*l));
+	l->type = t;
+	l->flag = flag;
+	l->link = *prot;
+	*prot = l;
+}
+
+static Tname*
+newname(char *s, int p, int count)
+{
+	Tname *l;
+
+	for(l=tname; l; l=l->link)
+		if(strcmp(l->name, s) == 0) {
+			if(p >= 0 && l->param != p)
+				yyerror("vargck %s already defined\n", s);
+			return l;
+		}
+	if(p < 0)
+		return nil;
+
+	l = alloc(sizeof(*l));
+	l->name = s;
+	l->param = p;
+	l->link = tname;
+	l->count = count;
+	tname = l;
+	return l;
+}
+
+void
+arginit(void)
+{
+	int i;
+
+/* debug['F'] = 1;*/
+/* debug['w'] = 1;*/
+
+	lastadj = Fadj;
+	lastverb = Fverb;
+	indchar = typ(TIND, types[TCHAR]);
+
+	memset(flagbits, Fnone, sizeof(flagbits));
+
+	for(i='0'; i<='9'; i++)
+		argflag(i, Fignor);
+	argflag('.', Fignor);
+	argflag('#', Fignor);
+	argflag('u', Fignor);
+	argflag('h', Fignor);
+	argflag('+', Fignor);
+	argflag('-', Fignor);
+
+	argflag('*', Fstar);
+	argflag('l', Fl);
+
+	argflag('o', Fverb);
+	flagbits['x'] = flagbits['o'];
+	flagbits['X'] = flagbits['o'];
+}
+
+static char*
+getquoted(void)
+{
+	int c;
+	Rune r;
+	Fmt fmt;
+
+	c = getnsc();
+	if(c != '"')
+		return nil;
+	fmtstrinit(&fmt);
+	for(;;) {
+		r = getr();
+		if(r == '\n') {
+			free(fmtstrflush(&fmt));
+			return nil;
+		}
+		if(r == '"')
+			break;
+		fmtrune(&fmt, r);
+	}
+	free(lastfmt);
+	lastfmt = fmtstrflush(&fmt);
+	return strdup(lastfmt);
+}
+
+void
+pragvararg(void)
+{
+	Sym *s;
+	int n, c;
+	char *t;
+	Type *ty;
+	Tname *l;
+
+	if(!debug['F'])
+		goto out;
+	s = getsym();
+	if(s && strcmp(s->name, "argpos") == 0)
+		goto ckpos;
+	if(s && strcmp(s->name, "type") == 0)
+		goto cktype;
+	if(s && strcmp(s->name, "flag") == 0)
+		goto ckflag;
+	if(s && strcmp(s->name, "countpos") == 0)
+		goto ckcount;
+	yyerror("syntax in #pragma varargck");
+	goto out;
+
+ckpos:
+/*#pragma	varargck	argpos	warn	2*/
+	s = getsym();
+	if(s == S)
+		goto bad;
+	n = getnsn();
+	if(n < 0)
+		goto bad;
+	newname(s->name, n, 0);
+	goto out;
+
+ckcount:
+/*#pragma	varargck	countpos	name 2*/
+	s = getsym();
+	if(s == S)
+		goto bad;
+	n = getnsn();
+	if(n < 0)
+		goto bad;
+	newname(s->name, 0, n);
+	goto out;
+
+ckflag:
+/*#pragma	varargck	flag	'c'*/
+	c = getnsc();
+	if(c != '\'')
+		goto bad;
+	c = getr();
+	if(c == '\\')
+		c = getr();
+	else if(c == '\'')
+		goto bad;
+	if(c == '\n')
+		goto bad;
+	if(getc() != '\'')
+		goto bad;
+	argflag(c, Fignor);
+	goto out;
+
+cktype:
+	c = getnsc();
+	unget(c);
+	if(c != '"') {
+/*#pragma	varargck	type	name	int*/
+		s = getsym();
+		if(s == S)
+			goto bad;
+		l = newname(s->name, -1, -1);
+		s = getsym();
+		if(s == S)
+			goto bad;
+		ty = s->type;
+		while((c = getnsc()) == '*')
+			ty = typ(TIND, ty);
+		unget(c);
+		newprot(s, ty, "a", &l->prot);
+		goto out;
+	}
+
+/*#pragma	varargck	type	O	int*/
+	t = getquoted();
+	if(t == nil)
+		goto bad;
+	s = getsym();
+	if(s == S)
+		goto bad;
+	ty = s->type;
+	while((c = getnsc()) == '*')
+		ty = typ(TIND, ty);
+	unget(c);
+	newprot(s, ty, t, &tprot);
+	goto out;
+
+bad:
+	yyerror("syntax in #pragma varargck");
+
+out:
+	while(getnsc() != '\n')
+		;
+}
+
+Node*
+nextarg(Node *n, Node **a)
+{
+	if(n == Z) {
+		*a = Z;
+		return Z;
+	}
+	if(n->op == OLIST) {
+		*a = n->left;
+		return n->right;
+	}
+	*a = n;
+	return Z;
+}
+
+void
+checkargs(Node *nn, char *s, int pos)
+{
+	Node *a, *n;
+	Bits flag;
+	Tprot *l;
+
+	if(!debug['F'])
+		return;
+	n = nn;
+	for(;;) {
+		s = strchr(s, '%');
+		if(s == 0) {
+			nextarg(n, &a);
+			if(a != Z)
+				warn(nn, "more arguments than format %T",
+					a->type);
+			return;
+		}
+		s++;
+		flag = getflag(s);
+		while(nstar > 0) {
+			n = nextarg(n, &a);
+			pos++;
+			nstar--;
+			if(a == Z) {
+				warn(nn, "more format than arguments %s",
+					lastfmt);
+				return;
+			}
+			if(a->type == T)
+				continue;
+			if(!sametype(types[TINT], a->type) &&
+			   !sametype(types[TUINT], a->type))
+				warn(nn, "format mismatch '*' in %s %T, arg %d",
+					lastfmt, a->type, pos);
+		}
+		for(l=tprot; l; l=l->link)
+			if(sametype(types[TVOID], l->type)) {
+				if(beq(flag, l->flag)) {
+					s++;
+					goto loop;
+				}
+			}
+
+		n = nextarg(n, &a);
+		pos++;
+		if(a == Z) {
+			warn(nn, "more format than arguments %s",
+				lastfmt);
+			return;
+		}
+		if(a->type == 0)
+			continue;
+		for(l=tprot; l; l=l->link)
+			if(sametype(a->type, l->type)) {
+/*print("checking %T/%ux %T/%ux\n", a->type, flag.b[0], l->type, l->flag.b[0]);*/
+				if(beq(flag, l->flag))
+					goto loop;
+			}
+		warn(nn, "format mismatch %s %T, arg %d", lastfmt, a->type, pos);
+	loop:;
+	}
+}
+
+void
+dpcheck(Node *n)
+{
+	char *s;
+	Node *a, *b;
+	Tname *l;
+	Tprot *tl;
+	int i, j;
+
+	if(n == Z)
+		return;
+	b = n->left;
+	if(b == Z || b->op != ONAME)
+		return;
+	s = b->sym->name;
+	for(l=tname; l; l=l->link)
+		if(strcmp(s, l->name) == 0)
+			break;
+	if(l == 0)
+		return;
+
+	if(l->count > 0) {
+		// fetch count, then check remaining length
+		i = l->count;
+		a = nil;
+		b = n->right;
+		while(i > 0) {
+			b = nextarg(b, &a);
+			i--;
+		}
+		if(a == Z) {
+			diag(n, "can't find count arg");
+			return;
+		}
+		if(a->op != OCONST || !typechl[a->type->etype]) {
+			diag(n, "count is invalid constant");
+			return;
+		}
+		j = a->vconst;
+		i = 0;
+		while(b != Z) {
+			b = nextarg(b, &a);
+			i++;
+		}
+		if(i != j)
+			diag(n, "found %d argument%s after count %d", i, i == 1 ? "" : "s", j);
+	}
+
+	if(l->prot != nil) {
+		// check that all arguments after param or count
+		// are listed in type list.
+		i = l->count;
+		if(i == 0)
+			i = l->param;
+		if(i == 0)
+			return;
+		a = nil;
+		b = n->right;
+		while(i > 0) {
+			b = nextarg(b, &a);
+			i--;
+		}
+		if(a == Z) {
+			diag(n, "can't find count/param arg");
+			return;
+		}
+		while(b != Z) {
+			b = nextarg(b, &a);
+			for(tl=l->prot; tl; tl=tl->link)
+				if(sametype(a->type, tl->type))
+					break;
+			if(tl == nil)
+				diag(a, "invalid type %T in call to %s", a->type, s);
+		}
+	}
+
+	if(l->param <= 0)
+		return;
+	i = l->param;
+	a = nil;
+	b = n->right;
+	while(i > 0) {
+		b = nextarg(b, &a);
+		i--;
+	}
+	if(a == Z) {
+		diag(n, "can't find format arg");
+		return;
+	}
+	if(!sametype(indchar, a->type)) {
+		diag(n, "format arg type %T", a->type);
+		return;
+	}
+	if(a->op != OADDR || a->left->op != ONAME || a->left->sym != symstring) {
+/*		warn(n, "format arg not constant string");*/
+		return;
+	}
+	s = a->left->cstring;
+	checkargs(b, s, l->param);
+}
+
+void
+pragpack(void)
+{
+	Sym *s;
+
+	packflg = 0;
+	s = getsym();
+	if(s) {
+		packflg = atoi(s->name+1);
+		if(strcmp(s->name, "on") == 0 ||
+		   strcmp(s->name, "yes") == 0)
+			packflg = 1;
+	}
+	while(getnsc() != '\n')
+		;
+	if(debug['f'])
+		if(packflg)
+			print("%4d: pack %d\n", lineno, packflg);
+		else
+			print("%4d: pack off\n", lineno);
+}
+
+void
+pragfpround(void)
+{
+	Sym *s;
+
+	fproundflg = 0;
+	s = getsym();
+	if(s) {
+		fproundflg = atoi(s->name+1);
+		if(strcmp(s->name, "on") == 0 ||
+		   strcmp(s->name, "yes") == 0)
+			fproundflg = 1;
+	}
+	while(getnsc() != '\n')
+		;
+	if(debug['f'])
+		if(fproundflg)
+			print("%4d: fproundflg %d\n", lineno, fproundflg);
+		else
+			print("%4d: fproundflg off\n", lineno);
+}
+
+void
+pragtextflag(void)
+{
+	Sym *s;
+
+	s = getsym();
+	if(s == S) {
+		textflag = getnsn();
+	} else {
+		if(s->macro) {
+			macexpand(s, symb);
+		}
+		if(symb[0] < '0' || symb[0] > '9')
+			yyerror("pragma textflag not an integer");
+		textflag = atoi(symb);
+	}
+	while(getnsc() != '\n')
+		;
+	if(debug['f'])
+		print("%4d: textflag %d\n", lineno, textflag);
+}
+
+void
+pragdataflag(void)
+{
+	Sym *s;
+
+	s = getsym();
+	if(s == S) {
+		dataflag = getnsn();
+	} else {
+		if(s->macro) {
+			macexpand(s, symb);
+		}
+		if(symb[0] < '0' || symb[0] > '9')
+			yyerror("pragma dataflag not an integer");
+		dataflag = atoi(symb);
+	}
+	while(getnsc() != '\n')
+		;
+	if(debug['f'])
+		print("%4d: dataflag %d\n", lineno, dataflag);
+}
+
+void
+pragincomplete(void)
+{
+	Sym *s;
+	Type *t;
+	int istag, w, et;
+
+	istag = 0;
+	s = getsym();
+	if(s == nil)
+		goto out;
+	et = 0;
+	w = s->lexical;
+	if(w == LSTRUCT)
+		et = TSTRUCT;
+	else if(w == LUNION)
+		et = TUNION;
+	if(et != 0){
+		s = getsym();
+		if(s == nil){
+			yyerror("missing struct/union tag in pragma incomplete");
+			goto out;
+		}
+		if(s->lexical != LNAME && s->lexical != LTYPE){
+			yyerror("invalid struct/union tag: %s", s->name);
+			goto out;
+		}
+		dotag(s, et, 0);
+		istag = 1;
+	}else if(strcmp(s->name, "_off_") == 0){
+		debug['T'] = 0;
+		goto out;
+	}else if(strcmp(s->name, "_on_") == 0){
+		debug['T'] = 1;
+		goto out;
+	}
+	t = s->type;
+	if(istag)
+		t = s->suetag;
+	if(t == T)
+		yyerror("unknown type %s in pragma incomplete", s->name);
+	else if(!typesu[t->etype])
+		yyerror("not struct/union type in pragma incomplete: %s", s->name);
+	else
+		t->garb |= GINCOMPLETE;
+out:
+	while(getnsc() != '\n')
+		;
+	if(debug['f'])
+		print("%s incomplete\n", s->name);
+}
+
+Sym*
+getimpsym(void)
+{
+	int c;
+	char *cp;
+
+	c = getnsc();
+	if(isspace(c) || c == '"') {
+		unget(c);
+		return S;
+	}
+	for(cp = symb;;) {
+		if(cp <= symb+NSYMB-4)
+			*cp++ = c;
+		c = getc();
+		if(c > 0 && !isspace(c) && c != '"')
+			continue;
+		unget(c);
+		break;
+	}
+	*cp = 0;
+	if(cp > symb+NSYMB-4)
+		yyerror("symbol too large: %s", symb);
+	return lookup();
+}
+
+static int
+more(void)
+{
+	int c;
+	
+	do
+		c = getnsc();
+	while(c == ' ' || c == '\t');
+	unget(c);
+	return c != '\n';
+}
+
+void
+pragcgo(char *verb)
+{
+	Sym *local, *remote;
+	char *p;
+
+	if(strcmp(verb, "cgo_dynamic_linker") == 0 || strcmp(verb, "dynlinker") == 0) {
+		p = getquoted();
+		if(p == nil)
+			goto err1;
+		fmtprint(&pragcgobuf, "cgo_dynamic_linker %q\n", p);
+		goto out;
+	
+	err1:
+		yyerror("usage: #pragma cgo_dynamic_linker \"path\"");
+		goto out;
+	}	
+	
+	if(strcmp(verb, "dynexport") == 0)
+		verb = "cgo_export_dynamic";
+	if(strcmp(verb, "cgo_export_static") == 0 || strcmp(verb, "cgo_export_dynamic") == 0) {
+		local = getimpsym();
+		if(local == nil)
+			goto err2;
+		if(!more()) {
+			fmtprint(&pragcgobuf, "%s %q\n", verb, local->name);
+			goto out;
+		}
+		remote = getimpsym();
+		if(remote == nil)
+			goto err2;
+		fmtprint(&pragcgobuf, "%s %q %q\n", verb, local->name, remote->name);
+		goto out;
+	
+	err2:
+		yyerror("usage: #pragma %s local [remote]", verb);
+		goto out;
+	}
+	
+	if(strcmp(verb, "cgo_import_dynamic") == 0 || strcmp(verb, "dynimport") == 0) {
+		local = getimpsym();
+		if(local == nil)
+			goto err3;
+		if(!more()) {
+			fmtprint(&pragcgobuf, "cgo_import_dynamic %q\n", local->name);
+			goto out;
+		}
+		remote = getimpsym();
+		if(remote == nil)
+			goto err3;
+		if(!more()) {
+			fmtprint(&pragcgobuf, "cgo_import_dynamic %q %q\n", local->name, remote->name);
+			goto out;
+		}
+		p = getquoted();
+		if(p == nil)	
+			goto err3;
+		fmtprint(&pragcgobuf, "cgo_import_dynamic %q %q %q\n", local->name, remote->name, p);
+		goto out;
+	
+	err3:
+		yyerror("usage: #pragma cgo_import_dynamic local [remote [\"library\"]]");
+		goto out;
+	}
+	
+	if(strcmp(verb, "cgo_import_static") == 0) {
+		local = getimpsym();
+		if(local == nil)
+			goto err4;
+		fmtprint(&pragcgobuf, "cgo_import_static %q\n", local->name);
+		goto out;
+
+	err4:
+		yyerror("usage: #pragma cgo_import_static local [remote]");
+		goto out;
+	}
+	
+	if(strcmp(verb, "cgo_ldflag") == 0) {
+		p = getquoted();
+		if(p == nil)
+			goto err5;
+		fmtprint(&pragcgobuf, "cgo_ldflag %q\n", p);
+		goto out;
+
+	err5:
+		yyerror("usage: #pragma cgo_ldflag \"arg\"");
+		goto out;
+	}
+	
+out:
+	while(getnsc() != '\n')
+		;
+}
diff --git a/src/cmd/cc/funct.c b/src/cmd/cc/funct.c
new file mode 100644
index 0000000..92c067d
--- /dev/null
+++ b/src/cmd/cc/funct.c
@@ -0,0 +1,431 @@
+// Inferno utils/cc/funct.c
+// http://code.google.com/p/inferno-os/source/browse/utils/cc/funct.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	"cc.h"
+
+typedef	struct	Ftab	Ftab;
+struct	Ftab
+{
+	char	op;
+	char*	name;
+	char	typ;
+};
+typedef	struct	Gtab	Gtab;
+struct	Gtab
+{
+	char	etype;
+	char*	name;
+};
+
+Ftab	ftabinit[OEND];
+Gtab	gtabinit[NALLTYPES];
+
+int
+isfunct(Node *n)
+{
+	Type *t, *t1;
+	Funct *f;
+	Node *l;
+	Sym *s;
+	int o;
+
+	o = n->op;
+	if(n->left == Z)
+		goto no;
+	t = n->left->type;
+	if(t == T)
+		goto no;
+	f = t->funct;
+
+	switch(o) {
+	case OAS:	// put cast on rhs
+	case OASI:
+	case OASADD:
+	case OASAND:
+	case OASASHL:
+	case OASASHR:
+	case OASDIV:
+	case OASLDIV:
+	case OASLMOD:
+	case OASLMUL:
+	case OASLSHR:
+	case OASMOD:
+	case OASMUL:
+	case OASOR:
+	case OASSUB:
+	case OASXOR:
+		if(n->right == Z)
+			goto no;
+		t1 = n->right->type;
+		if(t1 == T)
+			goto no;
+		if(t1->funct == f)
+			break;
+
+		l = new(OXXX, Z, Z);
+		*l = *n->right;
+
+		n->right->left = l;
+		n->right->right = Z;
+		n->right->type = t;
+		n->right->op = OCAST;
+
+		if(!isfunct(n->right))
+			prtree(n, "isfunc !");
+		break;
+
+	case OCAST:	// t f(T) or T f(t)
+		t1 = n->type;
+		if(t1 == T)
+			goto no;
+		if(f != nil) {
+			s = f->castfr[t1->etype];
+			if(s == S)
+				goto no;
+			n->right = n->left;
+			goto build;
+		}
+		f = t1->funct;
+		if(f != nil) {
+			s = f->castto[t->etype];
+			if(s == S)
+				goto no;
+			n->right = n->left;
+			goto build;
+		}
+		goto no;
+	}
+
+	if(f == nil)
+		goto no;
+	s = f->sym[o];
+	if(s == S)
+		goto no;
+
+	/*
+	 * the answer is yes,
+	 * now we rewrite the node
+	 * and give diagnostics
+	 */
+	switch(o) {
+	default:
+		diag(n, "isfunct op missing %O\n", o);
+		goto bad;
+
+	case OADD:	// T f(T, T)
+	case OAND:
+	case OASHL:
+	case OASHR:
+	case ODIV:
+	case OLDIV:
+	case OLMOD:
+	case OLMUL:
+	case OLSHR:
+	case OMOD:
+	case OMUL:
+	case OOR:
+	case OSUB:
+	case OXOR:
+
+	case OEQ:	// int f(T, T)
+	case OGE:
+	case OGT:
+	case OHI:
+	case OHS:
+	case OLE:
+	case OLO:
+	case OLS:
+	case OLT:
+	case ONE:
+		if(n->right == Z)
+			goto bad;
+		t1 = n->right->type;
+		if(t1 == T)
+			goto bad;
+		if(t1->funct != f)
+			goto bad;
+		n->right = new(OLIST, n->left, n->right);
+		break;
+
+	case OAS:	// structure copies done by the compiler
+	case OASI:
+		goto no;
+
+	case OASADD:	// T f(T*, T)
+	case OASAND:
+	case OASASHL:
+	case OASASHR:
+	case OASDIV:
+	case OASLDIV:
+	case OASLMOD:
+	case OASLMUL:
+	case OASLSHR:
+	case OASMOD:
+	case OASMUL:
+	case OASOR:
+	case OASSUB:
+	case OASXOR:
+		if(n->right == Z)
+			goto bad;
+		t1 = n->right->type;
+		if(t1 == T)
+			goto bad;
+		if(t1->funct != f)
+			goto bad;
+		n->right = new(OLIST, new(OADDR, n->left, Z), n->right);
+		break;
+
+	case OPOS:	// T f(T)
+	case ONEG:
+	case ONOT:
+	case OCOM:
+		n->right = n->left;
+		break;
+
+
+	}
+
+build:
+	l = new(ONAME, Z, Z);
+	l->sym = s;
+	l->type = s->type;
+	l->etype = s->type->etype;
+	l->xoffset = s->offset;
+	l->class = s->class;
+	tcomo(l, 0);
+
+	n->op = OFUNC;
+	n->left = l;
+	n->type = l->type->link;
+	if(tcompat(n, T, l->type, tfunct))
+		goto bad;
+	if(tcoma(n->left, n->right, l->type->down, 1))
+		goto bad;
+	return 1;
+
+no:
+	return 0;
+
+bad:
+	diag(n, "can't rewrite typestr for op %O\n", o);
+	prtree(n, "isfunct");
+	n->type = T;
+	return 1;
+}
+
+void
+dclfunct(Type *t, Sym *s)
+{
+	Funct *f;
+	Node *n;
+	Type *f1, *f2, *f3, *f4;
+	int o, i, c;
+	char str[100];
+
+	if(t->funct)
+		return;
+
+	// recognize generated tag of dorm _%d_
+	if(t->tag == S)
+		goto bad;
+	for(i=0; c = t->tag->name[i]; i++) {
+		if(c == '_') {
+			if(i == 0 || t->tag->name[i+1] == 0)
+				continue;
+			break;
+		}
+		if(c < '0' || c > '9')
+			break;
+	}
+	if(c == 0)
+		goto bad;
+
+	f = alloc(sizeof(*f));
+	for(o=0; o<nelem(f->sym); o++)
+		f->sym[o] = S;
+
+	t->funct = f;
+
+	f1 = typ(TFUNC, t);
+	f1->down = copytyp(t);
+	f1->down->down = t;
+
+	f2 = typ(TFUNC, types[TINT]);
+	f2->down = copytyp(t);
+	f2->down->down = t;
+
+	f3 = typ(TFUNC, t);
+	f3->down = typ(TIND, t);
+	f3->down->down = t;
+
+	f4 = typ(TFUNC, t);
+	f4->down = t;
+
+	for(i=0;; i++) {
+		o = ftabinit[i].op;
+		if(o == OXXX)
+			break;
+		sprint(str, "%s_%s_", t->tag->name, ftabinit[i].name);
+		n = new(ONAME, Z, Z);
+		n->sym = slookup(str);
+		f->sym[o] = n->sym;
+		switch(ftabinit[i].typ) {
+		default:
+			diag(Z, "dclfunct op missing %d\n", ftabinit[i].typ);
+			break;
+
+		case 1:	// T f(T,T)	+
+			dodecl(xdecl, CEXTERN, f1, n);
+			break;
+
+		case 2:	// int f(T,T)	==
+			dodecl(xdecl, CEXTERN, f2, n);
+			break;
+
+		case 3:	// void f(T*,T)	+=
+			dodecl(xdecl, CEXTERN, f3, n);
+			break;
+
+		case 4:	// T f(T)	~
+			dodecl(xdecl, CEXTERN, f4, n);
+			break;
+		}
+	}
+	for(i=0;; i++) {
+		o = gtabinit[i].etype;
+		if(o == TXXX)
+			break;
+
+		/*
+		 * OCAST types T1 _T2_T1_(T2)
+		 */
+		sprint(str, "_%s%s_", gtabinit[i].name, t->tag->name);
+		n = new(ONAME, Z, Z);
+		n->sym = slookup(str);
+		f->castto[o] = n->sym;
+
+		f1 = typ(TFUNC, t);
+		f1->down = types[o];
+		dodecl(xdecl, CEXTERN, f1, n);
+
+		sprint(str, "%s_%s_", t->tag->name, gtabinit[i].name);
+		n = new(ONAME, Z, Z);
+		n->sym = slookup(str);
+		f->castfr[o] = n->sym;
+
+		f1 = typ(TFUNC, types[o]);
+		f1->down = t;
+		dodecl(xdecl, CEXTERN, f1, n);
+	}
+	return;
+bad:
+	diag(Z, "dclfunct bad %T %s\n", t, s->name);
+}
+
+Gtab	gtabinit[NALLTYPES] =
+{
+	TCHAR,		"c",
+	TUCHAR,		"uc",
+	TSHORT,		"h",
+	TUSHORT,	"uh",
+	TINT,		"i",
+	TUINT,		"ui",
+	TLONG,		"l",
+	TULONG,		"ul",
+	TVLONG,		"v",
+	TUVLONG,	"uv",
+	TFLOAT,		"f",
+	TDOUBLE,	"d",
+	TXXX
+};
+
+Ftab	ftabinit[OEND] =
+{
+	OADD,		"add",		1,
+	OAND,		"and",		1,
+	OASHL,		"ashl",		1,
+	OASHR,		"ashr",		1,
+	ODIV,		"div",		1,
+	OLDIV,		"ldiv",		1,
+	OLMOD,		"lmod",		1,
+	OLMUL,		"lmul",		1,
+	OLSHR,		"lshr",		1,
+	OMOD,		"mod",		1,
+	OMUL,		"mul",		1,
+	OOR,		"or",		1,
+	OSUB,		"sub",		1,
+	OXOR,		"xor",		1,
+
+	OEQ,		"eq",		2,
+	OGE,		"ge",		2,
+	OGT,		"gt",		2,
+	OHI,		"hi",		2,
+	OHS,		"hs",		2,
+	OLE,		"le",		2,
+	OLO,		"lo",		2,
+	OLS,		"ls",		2,
+	OLT,		"lt",		2,
+	ONE,		"ne",		2,
+
+	OASADD,		"asadd",	3,
+	OASAND,		"asand",	3,
+	OASASHL,	"asashl",	3,
+	OASASHR,	"asashr",	3,
+	OASDIV,		"asdiv",	3,
+	OASLDIV,	"asldiv",	3,
+	OASLMOD,	"aslmod",	3,
+	OASLMUL,	"aslmul",	3,
+	OASLSHR,	"aslshr",	3,
+	OASMOD,		"asmod",	3,
+	OASMUL,		"asmul",	3,
+	OASOR,		"asor",		3,
+	OASSUB,		"assub",	3,
+	OASXOR,		"asxor",	3,
+
+	OPOS,		"pos",		4,
+	ONEG,		"neg",		4,
+	OCOM,		"com",		4,
+	ONOT,		"not",		4,
+
+//	OPOSTDEC,
+//	OPOSTINC,
+//	OPREDEC,
+//	OPREINC,
+
+	OXXX,
+};
+
+//	Node*	nodtestv;
+
+//	Node*	nodvpp;
+//	Node*	nodppv;
+//	Node*	nodvmm;
+//	Node*	nodmmv;
diff --git a/src/cmd/cc/godefs.c b/src/cmd/cc/godefs.c
new file mode 100644
index 0000000..d9f67f0
--- /dev/null
+++ b/src/cmd/cc/godefs.c
@@ -0,0 +1,367 @@
+//   cmd/cc/godefs.cc
+//
+//   derived from pickle.cc which itself was derived from acid.cc.
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth 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-2011 The Go Authors.	All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include <u.h>
+#include "cc.h"
+
+static int upper;
+
+static char *kwd[] =
+{
+	"_bool",
+	"_break",
+	"_byte",
+	"_case",
+	"_chan",
+	"_complex128",
+	"_complex64",
+	"_const",
+	"_continue",
+	"_default",
+	"_defer",
+	"_else",
+	"_fallthrough",
+	"_false",
+	"_float32",
+	"_float64",
+	"_for",
+	"_func",
+	"_go",
+	"_goto",
+	"_if",
+	"_import",
+	"_int",
+	"_int16",
+	"_int32",
+	"_int64",
+	"_int8",
+	"_interface",
+	"_intptr",
+	"_map",
+	"_package",
+	"_panic",
+	"_range",
+	"_return",
+	"_select",
+	"_string",
+	"_struct",
+	"_switch",
+	"_true",
+	"_type",
+	"_uint",
+	"_uint16",
+	"_uint32",
+	"_uint64",
+	"_uint8",
+	"_uintptr",
+	"_var",
+};
+
+static char*
+pmap(char *s)
+{
+	int i, bot, top, mid;
+
+	bot = -1;
+	top = nelem(kwd);
+	while(top - bot > 1){
+		mid = (bot + top) / 2;
+		i = strcmp(kwd[mid]+1, s);
+		if(i == 0)
+			return kwd[mid];
+		if(i < 0)
+			bot = mid;
+		else
+			top = mid;
+	}
+
+	return s;
+}
+
+
+int
+Uconv(Fmt *fp)
+{
+	char str[STRINGSZ+1];
+	char *s, *n;
+	int i;
+
+	str[0] = 0;
+	s = va_arg(fp->args, char*);
+
+	// strip package name
+	n = strrchr(s, '.');
+	if(n != nil)
+		s = n + 1;
+
+	if(s && *s) {
+		if(upper)
+			str[0] = toupper((uchar)*s);
+		else
+			str[0] = tolower((uchar)*s);
+		for(i = 1; i < STRINGSZ && s[i] != 0; i++)
+			str[i] = tolower((uchar)s[i]);
+		str[i] = 0;
+	}
+
+	return fmtstrcpy(fp, pmap(str));
+}
+
+
+static Sym*
+findsue(Type *t)
+{
+	int h;
+	Sym *s;
+
+	if(t != T)
+	for(h=0; h<nelem(hash); h++)
+		for(s = hash[h]; s != S; s = s->link)
+			if(s->suetag && s->suetag->link == t)
+				return s;
+	return 0;
+}
+
+static void
+printtypename(Type *t)
+{
+	Sym *s;
+	int w;
+	char *n;
+
+	for( ; t != nil; t = t->link) {
+		switch(t->etype) {
+		case TIND:
+			// Special handling of *void.
+			if(t->link != nil && t->link->etype==TVOID) {
+				Bprint(&outbuf, "unsafe.Pointer");
+				return;
+			}
+			// *func == func
+			if(t->link != nil && t->link->etype==TFUNC)
+				continue;
+			Bprint(&outbuf, "*");
+			continue;
+		case TARRAY:
+			w = t->width;
+			if(t->link && t->link->width)
+				w /= t->link->width;
+			Bprint(&outbuf, "[%d]", w);
+			continue;
+		}
+		break;
+	}
+
+	if(t == nil) {
+		Bprint(&outbuf, "bad // should not happen");
+		return;
+	}
+
+	switch(t->etype) {
+	case TINT:
+	case TUINT:
+	case TCHAR:
+	case TUCHAR:
+	case TSHORT:
+	case TUSHORT:
+	case TLONG:
+	case TULONG:
+	case TVLONG:
+	case TUVLONG:
+	case TFLOAT:
+	case TDOUBLE:
+		// All names used in the runtime code should be typedefs.
+		if(t->tag != nil) {
+			if(strcmp(t->tag->name, "intgo") == 0)
+				Bprint(&outbuf, "int");
+			else if(strcmp(t->tag->name, "uintgo") == 0)
+				Bprint(&outbuf, "uint");
+			else
+				Bprint(&outbuf, "%s", t->tag->name);
+		} else	
+			Bprint(&outbuf, "C.%T", t);
+		break;
+	case TUNION:
+	case TSTRUCT:
+		s = findsue(t->link);
+		n = "bad";
+		if(s != S)
+			n = s->name;
+		else if(t->tag)
+			n = t->tag->name;
+		if(strcmp(n, "String") == 0)
+			Bprint(&outbuf, "string");
+		else if(strcmp(n, "Slice") == 0)
+			Bprint(&outbuf, "[]byte");
+		else if(strcmp(n, "Eface") == 0)
+			Bprint(&outbuf, "interface{}");
+		else
+			Bprint(&outbuf, "%U", n);
+		break;
+	case TFUNC:
+		// There's no equivalent to a C function in the Go world.
+		Bprint(&outbuf, "unsafe.Pointer");
+		break;
+	case TDOT:
+		Bprint(&outbuf, "...interface{}");
+		break;
+	default:
+		Bprint(&outbuf, " weird<%T>", t);
+	}
+}
+
+static int
+dontrun(void)
+{
+	Io *i;
+	int n;
+
+	if(!debug['q'] && !debug['Q'])
+		return 1;
+	if(debug['q'] + debug['Q'] > 1) {
+		n = 0;
+		for(i=iostack; i; i=i->link)
+			n++;
+		if(n > 1)
+			return 1;
+	}
+
+	upper = debug['Q'];
+	return 0;
+}
+
+void
+godeftype(Type *t)
+{
+	Sym *s;
+	Type *l;
+	int gotone;
+
+	if(dontrun())
+		return;
+
+	switch(t->etype) {
+	case TUNION:
+	case TSTRUCT:
+		s = findsue(t->link);
+		if(s == S) {
+			Bprint(&outbuf, "/* can't find %T */\n\n", t);
+			return;
+		}
+
+		gotone = 0; // for unions, take first member of size equal to union
+		Bprint(&outbuf, "type %U struct {\n", s->name);
+		for(l = t->link; l != T; l = l->down) {
+			Bprint(&outbuf, "\t");
+			if(t->etype == TUNION) {
+				if(!gotone && l->width == t->width)
+					gotone = 1;
+				else
+					Bprint(&outbuf, "// (union)\t");
+			}
+			if(l->sym != nil)  // not anonymous field
+				Bprint(&outbuf, "%U\t", l->sym->name);
+			printtypename(l);
+			Bprint(&outbuf, "\n");
+		}
+		Bprint(&outbuf, "}\n\n");
+		break;
+
+	default:
+		Bprint(&outbuf, "/* %T */\n\n", t);
+		break;
+	}
+}
+
+void
+godefvar(Sym *s)
+{
+	Type *t, *t1;
+	char n;
+
+	if(dontrun())
+		return;
+
+	t = s->type;
+	if(t == nil)
+		return;
+
+	switch(t->etype) {
+	case TENUM:
+		if(!typefd[t->etype])
+			Bprint(&outbuf, "const %s = %lld\n", s->name, s->vconst);
+		else
+			Bprint(&outbuf, "const %s = %f\n;", s->name, s->fconst);
+		break;
+
+	case TFUNC:
+		Bprint(&outbuf, "func %U(", s->name);
+		n = 'a';
+		for(t1 = t->down; t1 != T; t1 = t1->down) {
+			if(t1->etype == TVOID)
+				break;
+			if(t1 != t->down)
+				Bprint(&outbuf, ", ");
+			Bprint(&outbuf, "%c ", n++);
+			printtypename(t1);
+		}
+		Bprint(&outbuf, ")");
+		if(t->link && t->link->etype != TVOID) {
+			Bprint(&outbuf, " ");
+			printtypename(t->link);
+		}
+		Bprint(&outbuf, "\n");
+		break;
+
+	default:
+		switch(s->class) {
+		case CTYPEDEF:
+			if(!typesu[t->etype]) {
+				Bprint(&outbuf, "// type %U\t", s->name);
+				printtypename(t);
+				Bprint(&outbuf, "\n");
+			}
+			break;
+		case CSTATIC:
+		case CEXTERN:
+		case CGLOBL:
+			if(strchr(s->name, '$') != nil)
+				break;
+			if(strncmp(s->name, "go.weak.", 8) == 0)
+				break;
+			Bprint(&outbuf, "var %U\t", s->name);
+			printtypename(t);
+			Bprint(&outbuf, "\n");
+			break;
+		}
+		break;
+	}
+}
diff --git a/src/cmd/cc/lex.c b/src/cmd/cc/lex.c
new file mode 100644
index 0000000..7c9f718
--- /dev/null
+++ b/src/cmd/cc/lex.c
@@ -0,0 +1,1593 @@
+// Inferno utils/cc/lex.c
+// http://code.google.com/p/inferno-os/source/browse/utils/cc/lex.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	"cc.h"
+#include	"y.tab.h"
+#include	"../ld/textflag.h"
+
+#ifndef	CPP
+#define	CPP	"cpp"
+#endif
+
+int
+systemtype(int sys)
+{
+#ifdef _WIN32
+	return sys&Windows;
+#else
+	return sys&Plan9;
+#endif
+}
+
+int
+pathchar(void)
+{
+	return '/';
+}
+
+/*
+ * known debug flags
+ *	-a		acid declaration output
+ *	-A		!B
+ *	-B		non ANSI
+ *	-d		print declarations
+ *	-D name		define
+ *	-F		format specification check
+ *	-G		print pgen stuff
+ *	-g		print cgen trees
+ *	-i		print initialization
+ *	-I path		include
+ *	-l		generate little-endian code
+ *	-L		print every NAME symbol
+ *	-M		constant multiplication
+ *	-m		print add/sub/mul trees
+ *	-n		print acid or godefs to file (%.c=%.acid) (with -a or -aa)
+ *	-o file		output file
+ *	-p		use standard cpp ANSI preprocessor (not on windows)
+ *	-p		something with peepholes
+ *	-q		print equivalent Go code for variables and types (lower-case identifiers)
+ *	-Q		print equivalent Go code for variables and types (upper-case identifiers)
+ *	-r		print registerization
+ *	-s		print structure offsets (with -a or -aa)
+ *	-S		print assembly
+ *	-t		print type trees
+ *	-V		enable void* conversion warnings
+ *	-v		verbose printing
+ *	-w		print warnings
+ *	-X		abort on error
+ *	-.		Inhibit search for includes in source directory
+ */
+
+void
+usage(void)
+{
+	print("usage: %cc [options] file.c...\n", thechar);
+	flagprint(1);
+	errorexit();
+}
+
+void
+dospim(void)
+{
+	thechar = '0';
+	thestring = "spim";
+}
+
+char **defs;
+int ndef;
+
+void
+dodef(char *p)
+{
+	if(ndef%8 == 0)
+		defs = allocn(defs, ndef*sizeof(char *),
+			8*sizeof(char *));
+	defs[ndef++] = p;
+	dodefine(p);
+}
+
+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();
+	cinit();
+	ginit();
+	arginit();
+	
+	fmtstrinit(&pragcgobuf);
+
+	tufield = simplet((1L<<tfield->etype) | BUNSIGNED);
+	ndef = 0;
+	defs = nil;
+	outfile = 0;
+	setinclude(".");
+
+	flagcount("+", "pass -+ to preprocessor", &debug['+']);	
+	flagcount(".", "pass -. to preprocessor", &debug['.']);	
+	flagcount("<", "debug shift", &debug['<']);
+	flagcount("A", "debug alignment", &debug['A']);
+	flagcount("B", "allow pre-ANSI code", &debug['B']);
+	if(thechar == '5')
+		flagcount("C", "debug constant propagation", &debug['C']);
+	flagfn1("D", "name[=value]: add #define", dodef);
+	flagcount("F", "enable print format checks", &debug['F']);
+	if(thechar == '5')
+		flagcount("H", "debug shift propagation", &debug['H']);
+	flagfn1("I", "dir: add dir to include path", setinclude);
+	flagcount("L", "debug lexer", &debug['L']);
+	flagcount("M", "debug move generation", &debug['M']);
+	flagcount("N", "disable optimizations", &debug['N']);
+	flagcount("P", "debug peephole optimizer", &debug['P']);
+	flagcount("Q", "print exported Go definitions", &debug['Q']);
+	flagcount("R", "debug register optimizer", &debug['R']);
+	flagcount("S", "print assembly", &debug['S']);
+	flagcount("T", "enable type signatures", &debug['T']);
+	flagcount("V", "enable pointer type checks", &debug['V']);
+	flagcount("W", "debug switch generation", &debug['W']);
+	flagcount("X", "abort on error", &debug['X']);
+	flagcount("Y", "debug index generation", &debug['Y']);
+	flagcount("Z", "skip code generation", &debug['Z']);
+	flagcount("a", "print acid definitions", &debug['a']);
+	flagcount("c", "debug constant evaluation", &debug['c']);
+	flagcount("d", "debug declarations", &debug['d']);
+	flagcount("e", "debug macro expansion", &debug['e']);
+	flagcount("f", "debug pragmas", &debug['f']);
+	flagcount("g", "debug code generation", &debug['g']);
+	flagcount("i", "debug initialization", &debug['i']);
+	if(thechar == 'v')
+		flagfn0("l", "little-endian mips mode", dospim);
+	flagcount("m", "debug multiplication", &debug['m']);
+	flagcount("n", "print acid/Go to file, not stdout", &debug['n']);
+	flagstr("o", "file: set output file", &outfile);
+	flagcount("p", "invoke C preprocessor", &debug['p']);	
+	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'];
+	ctxt->debugvlog = debug['v'];
+
+	if(argc < 1 && outfile == 0)
+		usage();
+
+	if(argc > 1){
+		print("can't compile multiple files\n");
+		errorexit();
+	}
+
+	if(argc == 0)
+		c = compile("stdin", defs, ndef);
+	else
+		c = compile(argv[0], defs, ndef);
+
+	Bflush(&bstdout);
+	if(c)
+		errorexit();
+	exits(0);
+}
+
+int
+compile(char *file, char **defs, int ndef)
+{
+	char *ofile;
+	char *p, **av, opt[256];
+	int i, c, fd[2];
+	static int first = 1;
+
+	ofile = alloc(strlen(file)+10);
+	strcpy(ofile, file);
+	p = utfrrune(ofile, pathchar());
+	if(p) {
+		*p++ = 0;
+		if(!debug['.'])
+			include[0] = strdup(ofile);
+	} else
+		p = ofile;
+
+	if(outfile == 0) {
+		outfile = p;
+		if(outfile) {
+			if(p = utfrrune(outfile, '.'))
+				if(p[1] == 'c' && p[2] == 0)
+					p[0] = 0;
+			p = utfrune(outfile, 0);
+			if(debug['a'] && debug['n'])
+				strcat(p, ".acid");
+			else if((debug['q'] || debug['Q']) && debug['n'])
+				strcat(p, ".go");
+			else {
+				p[0] = '.';
+				p[1] = thechar;
+				p[2] = 0;
+			}
+		} else
+			outfile = "/dev/null";
+	}
+
+	if (first)
+		Binit(&diagbuf, 1, OWRITE);
+	/*
+	 * if we're writing acid to standard output, don't keep scratching
+	 * outbuf.
+	 */
+	if((debug['a'] || debug['q'] || debug['Q']) && !debug['n']) {
+		if (first) {
+			outfile = 0;
+			Binit(&outbuf, dup(1, -1), OWRITE);
+			dup(2, 1);
+		}
+	} else {
+		c = create(outfile, OWRITE, 0664);
+		if(c < 0) {
+			diag(Z, "cannot open %s - %r", outfile);
+			outfile = 0;
+			errorexit();
+		}
+		Binit(&outbuf, c, OWRITE);
+		outfile = strdup(outfile);
+	}
+	newio();
+	first = 0;
+
+	/* Use an ANSI preprocessor */
+	if(debug['p']) {
+		if(systemtype(Windows)) {
+			diag(Z, "-p option not supported on windows");
+			errorexit();
+		}
+		if(access(file, AREAD) < 0) {
+			diag(Z, "%s does not exist", file);
+			errorexit();
+		}
+		if(pipe(fd) < 0) {
+			diag(Z, "pipe failed");
+			errorexit();
+		}
+		switch(fork()) {
+		case -1:
+			diag(Z, "fork failed");
+			errorexit();
+		case 0:
+			close(fd[0]);
+			dup(fd[1], 1);
+			close(fd[1]);
+			av = alloc((ndef+ninclude+5)*sizeof(char *));
+			av[0] = CPP;
+			i = 1;
+			if(debug['.']){
+				sprint(opt, "-.");
+				av[i++] = strdup(opt);
+			}
+			if(debug['+']) {
+				sprint(opt, "-+");
+				av[i++] = strdup(opt);
+			}
+			for(c = 0; c < ndef; c++)
+				av[i++] = smprint("-D%s", defs[c]);
+			for(c = 0; c < ninclude; c++)
+				av[i++] = smprint("-I%s", include[c]);
+			if(strcmp(file, "stdin") != 0)
+				av[i++] = file;
+			av[i] = 0;
+			if(debug['p'] > 1) {
+				for(c = 0; c < i; c++)
+					fprint(2, "%s ", av[c]);
+				fprint(2, "\n");
+			}
+			exec(av[0], av);
+			fprint(2, "can't exec C preprocessor %s: %r\n", CPP);
+			errorexit();
+		default:
+			close(fd[1]);
+			newfile(file, fd[0]);
+			break;
+		}
+	} else {
+		if(strcmp(file, "stdin") == 0)
+			newfile(file, 0);
+		else
+			newfile(file, -1);
+	}
+	yyparse();
+	if(!debug['a'] && !debug['q'] && !debug['Q'])
+		gclean();
+	return nerrors;
+}
+
+void
+errorexit(void)
+{
+	Bflush(&bstdout);
+	if(outfile)
+		remove(outfile);
+	exits("error");
+}
+
+void
+pushio(void)
+{
+	Io *i;
+
+	i = iostack;
+	if(i == I) {
+		yyerror("botch in pushio");
+		errorexit();
+	}
+	i->p = fi.p;
+	i->c = fi.c;
+}
+
+void
+newio(void)
+{
+	Io *i;
+	static int pushdepth = 0;
+
+	i = iofree;
+	if(i == I) {
+		pushdepth++;
+		if(pushdepth > 1000) {
+			yyerror("macro/io expansion too deep");
+			errorexit();
+		}
+		i = alloc(sizeof(*i));
+	} else
+		iofree = i->link;
+	i->c = 0;
+	i->f = -1;
+	ionext = i;
+}
+
+void
+newfile(char *s, int f)
+{
+	Io *i;
+
+	if(debug['e'])
+		print("%L: %s\n", lineno, s);
+
+	i = ionext;
+	i->link = iostack;
+	iostack = i;
+	i->f = f;
+	if(f < 0)
+		i->f = open(s, 0);
+	if(i->f < 0) {
+		yyerror("%cc: %r: %s", thechar, s);
+		errorexit();
+	}
+	fi.c = 0;
+	linklinehist(ctxt, lineno, s, 0);
+}
+
+Sym*
+slookup(char *s)
+{
+	ensuresymb(strlen(s));
+	strcpy(symb, s);
+	return lookup();
+}
+
+Sym*
+lookup(void)
+{
+	Sym *s;
+	uint32 h;
+	char *p;
+	int c, n;
+	char *r, *w;
+
+	if((uchar)symb[0] == 0xc2 && (uchar)symb[1] == 0xb7) {
+		// turn leading · into ""·
+		h = strlen(symb);
+		ensuresymb(h+2);
+		memmove(symb+2, symb, h+1);
+		symb[0] = '"';
+		symb[1] = '"';
+	}
+
+	for(r=w=symb; *r; r++) {
+		// turn · (U+00B7) into .
+		// turn ∕ (U+2215) into /
+		if((uchar)*r == 0xc2 && (uchar)*(r+1) == 0xb7) {
+			*w++ = '.';
+			r++;
+		}else if((uchar)*r == 0xe2 && (uchar)*(r+1) == 0x88 && (uchar)*(r+2) == 0x95) {
+			*w++ = '/';
+			r++;
+			r++;
+		}else
+			*w++ = *r;
+	}
+	*w = '\0';
+
+	h = 0;
+	for(p=symb; *p;) {
+		h = h * 3;
+		h += *p++;
+	}
+	n = (p - symb) + 1;
+	h &= 0xffffff;
+	h %= NHASH;
+	c = symb[0];
+	for(s = hash[h]; s != S; s = s->link) {
+		if(s->name[0] != c)
+			continue;
+		if(strcmp(s->name, symb) == 0)
+			return s;
+	}
+	s = alloc(sizeof(*s));
+	s->name = alloc(n);
+	memmove(s->name, symb, n);
+	s->link = hash[h];
+	hash[h] = s;
+	syminit(s);
+
+	return s;
+}
+
+void
+syminit(Sym *s)
+{
+	s->lexical = LNAME;
+	s->block = 0;
+	s->offset = 0;
+	s->type = T;
+	s->suetag = T;
+	s->class = CXXX;
+	s->aused = 0;
+	s->sig = SIGNONE;
+}
+
+#define	EOF	(-1)
+#define	IGN	(-2)
+#define	ESC	(1<<20)
+#define	GETC()	((--fi.c < 0)? filbuf(): (*fi.p++ & 0xff))
+
+enum
+{
+	Numdec		= 1<<0,
+	Numlong		= 1<<1,
+	Numuns		= 1<<2,
+	Numvlong	= 1<<3,
+	Numflt		= 1<<4,
+};
+
+int32
+yylex(void)
+{
+	vlong vv;
+	int32 c, c1, t;
+	char *cp;
+	Rune rune;
+	Sym *s;
+
+	if(peekc != IGN) {
+		c = peekc;
+		peekc = IGN;
+		goto l1;
+	}
+l0:
+	c = GETC();
+
+l1:
+	if(c >= Runeself) {
+		/*
+		 * extension --
+		 *	all multibyte runes are alpha
+		 */
+		cp = symb;
+		goto talph;
+	}
+	if(isspace(c)) {
+		if(c == '\n')
+			lineno++;
+		goto l0;
+	}
+	if(isalpha(c)) {
+		cp = symb;
+		if(c != 'L')
+			goto talph;
+		*cp++ = c;
+		c = GETC();
+		if(c == '\'') {
+			/* L'x' */
+			c = escchar('\'', 1, 0);
+			if(c == EOF)
+				c = '\'';
+			c1 = escchar('\'', 1, 0);
+			if(c1 != EOF) {
+				yyerror("missing '");
+				peekc = c1;
+			}
+			yylval.vval = convvtox(c, TRUNE);
+			return LUCONST;
+		}
+		if(c == '"') {
+			goto caselq;
+		}
+		goto talph;
+	}
+	if(isdigit(c))
+		goto tnum;
+	switch(c)
+	{
+
+	case EOF:
+		peekc = EOF;
+		return -1;
+
+	case '_':
+		cp = symb;
+		goto talph;
+
+	case '#':
+		domacro();
+		goto l0;
+
+	case '.':
+		c1 = GETC();
+		if(isdigit(c1)) {
+			cp = symb;
+			*cp++ = c;
+			c = c1;
+			c1 = 0;
+			goto casedot;
+		}
+		break;
+
+	case '"':
+		strcpy(symb, "\"<string>\"");
+		cp = alloc(0);
+		c1 = 0;
+
+		/* "..." */
+		for(;;) {
+			c = escchar('"', 0, 1);
+			if(c == EOF)
+				break;
+			if(c & ESC) {
+				cp = allocn(cp, c1, 1);
+				cp[c1++] = c;
+			} else {
+				rune = c;
+				c = runelen(rune);
+				cp = allocn(cp, c1, c);
+				runetochar(cp+c1, &rune);
+				c1 += c;
+			}
+		}
+		yylval.sval.l = c1;
+		do {
+			cp = allocn(cp, c1, 1);
+			cp[c1++] = 0;
+		} while(c1 & MAXALIGN);
+		yylval.sval.s = cp;
+		return LSTRING;
+
+	caselq:
+		/* L"..." */
+		strcpy(symb, "\"L<string>\"");
+		cp = alloc(0);
+		c1 = 0;
+		for(;;) {
+			c = escchar('"', 1, 0);
+			if(c == EOF)
+				break;
+			cp = allocn(cp, c1, sizeof(TRune));
+			*(TRune*)(cp + c1) = c;
+			c1 += sizeof(TRune);
+		}
+		yylval.sval.l = c1;
+		do {
+			cp = allocn(cp, c1, sizeof(TRune));
+			*(TRune*)(cp + c1) = 0;
+			c1 += sizeof(TRune);
+		} while(c1 & MAXALIGN);
+		yylval.sval.s = cp;
+		return LLSTRING;
+
+	case '\'':
+		/* '.' */
+		c = escchar('\'', 0, 0);
+		if(c == EOF)
+			c = '\'';
+		c1 = escchar('\'', 0, 0);
+		if(c1 != EOF) {
+			yyerror("missing '");
+			peekc = c1;
+		}
+		vv = c;
+		yylval.vval = convvtox(vv, TUCHAR);
+		if(yylval.vval != vv)
+			yyerror("overflow in character constant: 0x%x", c);
+		else
+		if(c & 0x80){
+			nearln = lineno;
+			warn(Z, "sign-extended character constant");
+		}
+		yylval.vval = convvtox(vv, TCHAR);
+		return LCONST;
+
+	case '/':
+		c1 = GETC();
+		if(c1 == '*') {
+			for(;;) {
+				c = getr();
+				while(c == '*') {
+					c = getr();
+					if(c == '/')
+						goto l0;
+				}
+				if(c == EOF) {
+					yyerror("eof in comment");
+					errorexit();
+				}
+			}
+		}
+		if(c1 == '/') {
+			for(;;) {
+				c = getr();
+				if(c == '\n')
+					goto l0;
+				if(c == EOF) {
+					yyerror("eof in comment");
+					errorexit();
+				}
+			}
+		}
+		if(c1 == '=')
+			return LDVE;
+		break;
+
+	case '*':
+		c1 = GETC();
+		if(c1 == '=')
+			return LMLE;
+		break;
+
+	case '%':
+		c1 = GETC();
+		if(c1 == '=')
+			return LMDE;
+		break;
+
+	case '+':
+		c1 = GETC();
+		if(c1 == '+')
+			return LPP;
+		if(c1 == '=')
+			return LPE;
+		break;
+
+	case '-':
+		c1 = GETC();
+		if(c1 == '-')
+			return LMM;
+		if(c1 == '=')
+			return LME;
+		if(c1 == '>')
+			return LMG;
+		break;
+
+	case '>':
+		c1 = GETC();
+		if(c1 == '>') {
+			c = LRSH;
+			c1 = GETC();
+			if(c1 == '=')
+				return LRSHE;
+			break;
+		}
+		if(c1 == '=')
+			return LGE;
+		break;
+
+	case '<':
+		c1 = GETC();
+		if(c1 == '<') {
+			c = LLSH;
+			c1 = GETC();
+			if(c1 == '=')
+				return LLSHE;
+			break;
+		}
+		if(c1 == '=')
+			return LLE;
+		break;
+
+	case '=':
+		c1 = GETC();
+		if(c1 == '=')
+			return LEQ;
+		break;
+
+	case '!':
+		c1 = GETC();
+		if(c1 == '=')
+			return LNE;
+		break;
+
+	case '&':
+		c1 = GETC();
+		if(c1 == '&')
+			return LANDAND;
+		if(c1 == '=')
+			return LANDE;
+		break;
+
+	case '|':
+		c1 = GETC();
+		if(c1 == '|')
+			return LOROR;
+		if(c1 == '=')
+			return LORE;
+		break;
+
+	case '^':
+		c1 = GETC();
+		if(c1 == '=')
+			return LXORE;
+		break;
+
+	default:
+		return c;
+	}
+	peekc = c1;
+	return c;
+
+talph:
+	/*
+	 * cp is set to symb and some
+	 * prefix has been stored
+	 */
+	for(;;) {
+		if(c >= Runeself) {
+			for(c1=0;;) {
+				cp[c1++] = c;
+				if(fullrune(cp, c1))
+					break;
+				c = GETC();
+			}
+			cp += c1;
+			c = GETC();
+			continue;
+		}
+		if(!isalnum(c) && c != '_')
+			break;
+		*cp++ = c;
+		c = GETC();
+	}
+	*cp = 0;
+	if(debug['L'])
+		print("%L: %s\n", lineno, symb);
+	peekc = c;
+	s = lookup();
+	if(s->macro) {
+		newio();
+		cp = ionext->b;
+		macexpand(s, cp);
+		pushio();
+		ionext->link = iostack;
+		iostack = ionext;
+		fi.p = cp;
+		fi.c = strlen(cp);
+		if(peekc != IGN) {
+			cp[fi.c++] = peekc;
+			cp[fi.c] = 0;
+			peekc = IGN;
+		}
+		goto l0;
+	}
+	yylval.sym = s;
+	if(s->class == CTYPEDEF || s->class == CTYPESTR)
+		return LTYPE;
+	return s->lexical;
+
+tnum:
+	c1 = 0;
+	cp = symb;
+	if(c != '0') {
+		c1 |= Numdec;
+		for(;;) {
+			*cp++ = c;
+			c = GETC();
+			if(isdigit(c))
+				continue;
+			goto dc;
+		}
+	}
+	*cp++ = c;
+	c = GETC();
+	if(c == 'x' || c == 'X')
+		for(;;) {
+			*cp++ = c;
+			c = GETC();
+			if(isdigit(c))
+				continue;
+			if(c >= 'a' && c <= 'f')
+				continue;
+			if(c >= 'A' && c <= 'F')
+				continue;
+			if(cp == symb+2)
+				yyerror("malformed hex constant");
+			goto ncu;
+		}
+	if(c < '0' || c > '7')
+		goto dc;
+	for(;;) {
+		if(c >= '0' && c <= '7') {
+			*cp++ = c;
+			c = GETC();
+			continue;
+		}
+		goto ncu;
+	}
+
+dc:
+	if(c == '.')
+		goto casedot;
+	if(c == 'e' || c == 'E')
+		goto casee;
+
+ncu:
+	if((c == 'U' || c == 'u') && !(c1 & Numuns)) {
+		c = GETC();
+		c1 |= Numuns;
+		goto ncu;
+	}
+	if((c == 'L' || c == 'l') && !(c1 & Numvlong)) {
+		c = GETC();
+		if(c1 & Numlong)
+			c1 |= Numvlong;
+		c1 |= Numlong;
+		goto ncu;
+	}
+	*cp = 0;
+	peekc = c;
+	if(mpatov(symb, &yylval.vval))
+		yyerror("overflow in constant");
+
+	vv = yylval.vval;
+	if(c1 & Numvlong) {
+		if((c1 & Numuns) || convvtox(vv, TVLONG) < 0) {
+			c = LUVLCONST;
+			t = TUVLONG;
+			goto nret;
+		}
+		c = LVLCONST;
+		t = TVLONG;
+		goto nret;
+	}
+	if(c1 & Numlong) {
+		if((c1 & Numuns) || convvtox(vv, TLONG) < 0) {
+			c = LULCONST;
+			t = TULONG;
+			goto nret;
+		}
+		c = LLCONST;
+		t = TLONG;
+		goto nret;
+	}
+	if((c1 & Numuns) || convvtox(vv, TINT) < 0) {
+		c = LUCONST;
+		t = TUINT;
+		goto nret;
+	}
+	c = LCONST;
+	t = TINT;
+	goto nret;
+
+nret:
+	yylval.vval = convvtox(vv, t);
+	if(yylval.vval != vv){
+		nearln = lineno;
+		warn(Z, "truncated constant: %T %s", types[t], symb);
+	}
+	return c;
+
+casedot:
+	for(;;) {
+		*cp++ = c;
+		c = GETC();
+		if(!isdigit(c))
+			break;
+	}
+	if(c != 'e' && c != 'E')
+		goto caseout;
+
+casee:
+	*cp++ = 'e';
+	c = GETC();
+	if(c == '+' || c == '-') {
+		*cp++ = c;
+		c = GETC();
+	}
+	if(!isdigit(c))
+		yyerror("malformed fp constant exponent");
+	while(isdigit(c)) {
+		*cp++ = c;
+		c = GETC();
+	}
+
+caseout:
+	if(c == 'L' || c == 'l') {
+		c = GETC();
+		c1 |= Numlong;
+	} else
+	if(c == 'F' || c == 'f') {
+		c = GETC();
+		c1 |= Numflt;
+	}
+	*cp = 0;
+	peekc = c;
+	yylval.dval = strtod(symb, nil);
+	if(isInf(yylval.dval, 1) || isInf(yylval.dval, -1)) {
+		yyerror("overflow in float constant");
+		yylval.dval = 0;
+	}
+	if(c1 & Numflt)
+		return LFCONST;
+	return LDCONST;
+}
+
+/*
+ * convert a string, s, to vlong in *v
+ * return conversion overflow.
+ * required syntax is [0[x]]d*
+ */
+int
+mpatov(char *s, vlong *v)
+{
+	vlong n, nn;
+	int c;
+
+	n = 0;
+	c = *s;
+	if(c == '0')
+		goto oct;
+	while(c = *s++) {
+		if(c >= '0' && c <= '9')
+			nn = n*10 + c-'0';
+		else
+			goto bad;
+		if(n < 0 && nn >= 0)
+			goto bad;
+		n = nn;
+	}
+	goto out;
+
+oct:
+	s++;
+	c = *s;
+	if(c == 'x' || c == 'X')
+		goto hex;
+	while(c = *s++) {
+		if(c >= '0' || c <= '7')
+			nn = n*8 + c-'0';
+		else
+			goto bad;
+		if(n < 0 && nn >= 0)
+			goto bad;
+		n = nn;
+	}
+	goto out;
+
+hex:
+	s++;
+	while(c = *s++) {
+		if(c >= '0' && c <= '9')
+			c += 0-'0';
+		else
+		if(c >= 'a' && c <= 'f')
+			c += 10-'a';
+		else
+		if(c >= 'A' && c <= 'F')
+			c += 10-'A';
+		else
+			goto bad;
+		nn = (uvlong)n*16 + c;
+		if(n < 0 && nn >= 0)
+			goto bad;
+		n = nn;
+	}
+out:
+	*v = n;
+	return 0;
+
+bad:
+	*v = ~0;
+	return 1;
+}
+
+int
+getc(void)
+{
+	int c;
+
+	if(peekc != IGN) {
+		c = peekc;
+		peekc = IGN;
+	} else
+		c = GETC();
+	if(c == '\n')
+		lineno++;
+	if(c == EOF) {
+		yyerror("End of file");
+		errorexit();
+	}
+	return c;
+}
+
+int32
+getr(void)
+{
+	int c, i;
+	char str[UTFmax+1];
+	Rune rune;
+
+
+	c = getc();
+	if(c < Runeself)
+		return c;
+	i = 0;
+	str[i++] = c;
+
+loop:
+	c = getc();
+	str[i++] = c;
+	if(!fullrune(str, i))
+		goto loop;
+	c = chartorune(&rune, str);
+	if(rune == Runeerror && c == 1) {
+		nearln = lineno;
+		diag(Z, "illegal rune in string");
+		for(c=0; c<i; c++)
+			print(" %.2x", *(uchar*)(str+c));
+		print("\n");
+	}
+	return rune;
+}
+
+int
+getnsc(void)
+{
+	int c;
+
+	if(peekc != IGN) {
+		c = peekc;
+		peekc = IGN;
+	} else
+		c = GETC();
+	for(;;) {
+		if(c >= Runeself || !isspace(c))
+			return c;
+		if(c == '\n') {
+			lineno++;
+			return c;
+		}
+		c = GETC();
+	}
+}
+
+void
+unget(int c)
+{
+
+	peekc = c;
+	if(c == '\n')
+		lineno--;
+}
+
+int32
+escchar(int32 e, int longflg, int escflg)
+{
+	int32 c, l;
+	int i;
+
+loop:
+	c = getr();
+	if(c == '\n') {
+		yyerror("newline in string");
+		return EOF;
+	}
+	if(c != '\\') {
+		if(c == e)
+			c = EOF;
+		return c;
+	}
+	c = getr();
+	if(c == 'x') {
+		/*
+		 * note this is not ansi,
+		 * supposed to only accept 2 hex
+		 */
+		i = 2;
+		if(longflg)
+			i = 6;
+		l = 0;
+		for(; i>0; i--) {
+			c = getc();
+			if(c >= '0' && c <= '9') {
+				l = l*16 + c-'0';
+				continue;
+			}
+			if(c >= 'a' && c <= 'f') {
+				l = l*16 + c-'a' + 10;
+				continue;
+			}
+			if(c >= 'A' && c <= 'F') {
+				l = l*16 + c-'A' + 10;
+				continue;
+			}
+			unget(c);
+			break;
+		}
+		if(escflg)
+			l |= ESC;
+		return l;
+	}
+	if(c >= '0' && c <= '7') {
+		/*
+		 * note this is not ansi,
+		 * supposed to only accept 3 oct
+		 */
+		i = 2;
+		if(longflg)
+			i = 8;
+		l = c - '0';
+		for(; i>0; i--) {
+			c = getc();
+			if(c >= '0' && c <= '7') {
+				l = l*8 + c-'0';
+				continue;
+			}
+			unget(c);
+		}
+		if(escflg)
+			l |= ESC;
+		return l;
+	}
+	switch(c)
+	{
+	case '\n':	goto loop;
+	case 'n':	return '\n';
+	case 't':	return '\t';
+	case 'b':	return '\b';
+	case 'r':	return '\r';
+	case 'f':	return '\f';
+	case 'a':	return '\a';
+	case 'v':	return '\v';
+	}
+	return c;
+}
+
+struct
+{
+	char	*name;
+	ushort	lexical;
+	ushort	type;
+} itab[] =
+{
+	"auto",		LAUTO,		0,
+	"break",	LBREAK,		0,
+	"case",		LCASE,		0,
+	"char",		LCHAR,		TCHAR,
+	"const",	LCONSTNT,	0,
+	"continue",	LCONTINUE,	0,
+	"default",	LDEFAULT,	0,
+	"do",		LDO,		0,
+	"double",	LDOUBLE,	TDOUBLE,
+	"else",		LELSE,		0,
+	"enum",		LENUM,		0,
+	"extern",	LEXTERN,	0,
+	"float",	LFLOAT,		TFLOAT,
+	"for",		LFOR,		0,
+	"goto",		LGOTO,		0,
+	"if",		LIF,		0,
+	"inline",	LINLINE,	0,
+	"int",		LINT,		TINT,
+	"long",		LLONG,		TLONG,
+	"PREFETCH",	LPREFETCH,	0,
+	"register",	LREGISTER,	0,
+	"restrict",	LRESTRICT,	0,
+	"return",	LRETURN,	0,
+	"SET",		LSET,		0,
+	"short",	LSHORT,		TSHORT,
+	"signed",	LSIGNED,	0,
+	"signof",	LSIGNOF,	0,
+	"sizeof",	LSIZEOF,	0,
+	"static",	LSTATIC,	0,
+	"struct",	LSTRUCT,	0,
+	"switch",	LSWITCH,	0,
+	"typedef",	LTYPEDEF,	0,
+	"typestr",	LTYPESTR,	0,
+	"union",	LUNION,		0,
+	"unsigned",	LUNSIGNED,	0,
+	"USED",		LUSED,		0,
+	"void",		LVOID,		TVOID,
+	"volatile",	LVOLATILE,	0,
+	"while",	LWHILE,		0,
+	0
+};
+
+void
+cinit(void)
+{
+	Sym *s;
+	int i;
+	Type *t;
+
+	nerrors = 0;
+	lineno = 1;
+	iostack = I;
+	iofree = I;
+	peekc = IGN;
+	nhunk = 0;
+
+	types[TXXX] = T;
+	types[TCHAR] = typ(TCHAR, T);
+	types[TUCHAR] = typ(TUCHAR, T);
+	types[TSHORT] = typ(TSHORT, T);
+	types[TUSHORT] = typ(TUSHORT, T);
+	types[TINT] = typ(TINT, T);
+	types[TUINT] = typ(TUINT, T);
+	types[TLONG] = typ(TLONG, T);
+	types[TULONG] = typ(TULONG, T);
+	types[TVLONG] = typ(TVLONG, T);
+	types[TUVLONG] = typ(TUVLONG, T);
+	types[TFLOAT] = typ(TFLOAT, T);
+	types[TDOUBLE] = typ(TDOUBLE, T);
+	types[TVOID] = typ(TVOID, T);
+	types[TENUM] = typ(TENUM, T);
+	types[TFUNC] = typ(TFUNC, types[TINT]);
+	types[TIND] = typ(TIND, types[TVOID]);
+
+	for(i=0; i<NHASH; i++)
+		hash[i] = S;
+	for(i=0; itab[i].name; i++) {
+		s = slookup(itab[i].name);
+		s->lexical = itab[i].lexical;
+		if(itab[i].type != 0)
+			s->type = types[itab[i].type];
+	}
+	blockno = 0;
+	autobn = 0;
+	autoffset = 0;
+
+	t = typ(TARRAY, types[TCHAR]);
+	t->width = 0;
+	symstring = slookup(".string");
+	symstring->class = CSTATIC;
+	symstring->dataflag = NOPTR;
+	symstring->type = t;
+
+	t = typ(TARRAY, types[TCHAR]);
+	t->width = 0;
+
+	nodproto = new(OPROTO, Z, Z);
+	dclstack = D;
+
+	fmtinstall('O', Oconv);
+	fmtinstall('T', Tconv);
+	fmtinstall('F', FNconv);
+	fmtinstall('L', Lconv);
+	fmtinstall('Q', Qconv);
+	fmtinstall('|', VBconv);
+	fmtinstall('U', Uconv);
+	fmtinstall('B', Bconv);
+}
+
+int
+filbuf(void)
+{
+	Io *i;
+
+loop:
+	i = iostack;
+	if(i == I)
+		return EOF;
+	if(i->f < 0)
+		goto pop;
+	fi.c = read(i->f, i->b, BUFSIZ) - 1;
+	if(fi.c < 0) {
+		close(i->f);
+		linklinehist(ctxt, lineno, nil, 0);
+		goto pop;
+	}
+	fi.p = i->b + 1;
+	return i->b[0] & 0xff;
+
+pop:
+	iostack = i->link;
+	i->link = iofree;
+	iofree = i;
+	i = iostack;
+	if(i == I)
+		return EOF;
+	fi.p = i->p;
+	fi.c = i->c;
+	if(--fi.c < 0)
+		goto loop;
+	return *fi.p++ & 0xff;
+}
+
+int
+Oconv(Fmt *fp)
+{
+	int a;
+
+	a = va_arg(fp->args, int);
+	if(a < OXXX || a > OEND)
+		return fmtprint(fp, "***badO %d***", a);
+
+	return fmtstrcpy(fp, onames[a]);
+}
+
+int
+Lconv(Fmt *fp)
+{
+	return linklinefmt(ctxt, fp);
+}
+
+int
+Tconv(Fmt *fp)
+{
+	char str[STRINGSZ+20], s[STRINGSZ+20];
+	Type *t, *t1;
+	int et;
+	int32 n;
+
+	str[0] = 0;
+	for(t = va_arg(fp->args, Type*); t != T; t = t->link) {
+		et = t->etype;
+		if(str[0])
+			strcat(str, " ");
+		if(t->garb&~GINCOMPLETE) {
+			sprint(s, "%s ", gnames[t->garb&~GINCOMPLETE]);
+			if(strlen(str) + strlen(s) < STRINGSZ)
+				strcat(str, s);
+		}
+		sprint(s, "%s", tnames[et]);
+		if(strlen(str) + strlen(s) < STRINGSZ)
+			strcat(str, s);
+		if(et == TFUNC && (t1 = t->down)) {
+			sprint(s, "(%T", t1);
+			if(strlen(str) + strlen(s) < STRINGSZ)
+				strcat(str, s);
+			while(t1 = t1->down) {
+				sprint(s, ", %T", t1);
+				if(strlen(str) + strlen(s) < STRINGSZ)
+					strcat(str, s);
+			}
+			if(strlen(str) + strlen(s) < STRINGSZ)
+				strcat(str, ")");
+		}
+		if(et == TARRAY) {
+			n = t->width;
+			if(t->link && t->link->width)
+				n /= t->link->width;
+			sprint(s, "[%d]", n);
+			if(strlen(str) + strlen(s) < STRINGSZ)
+				strcat(str, s);
+		}
+		if(t->nbits) {
+			sprint(s, " %d:%d", t->shift, t->nbits);
+			if(strlen(str) + strlen(s) < STRINGSZ)
+				strcat(str, s);
+		}
+		if(typesu[et]) {
+			if(t->tag) {
+				strcat(str, " ");
+				if(strlen(str) + strlen(t->tag->name) < STRINGSZ)
+					strcat(str, t->tag->name);
+			} else
+				strcat(str, " {}");
+			break;
+		}
+	}
+	return fmtstrcpy(fp, str);
+}
+
+int
+FNconv(Fmt *fp)
+{
+	char *str;
+	Node *n;
+
+	n = va_arg(fp->args, Node*);
+	str = "<indirect>";
+	if(n != Z && (n->op == ONAME || n->op == ODOT || n->op == OELEM))
+		str = n->sym->name;
+	return fmtstrcpy(fp, str);
+}
+
+int
+Qconv(Fmt *fp)
+{
+	char str[STRINGSZ+20], *s;
+	int32 b;
+	int i;
+
+	str[0] = 0;
+	for(b = va_arg(fp->args, int32); b;) {
+		i = bitno(b);
+		if(str[0])
+			strcat(str, " ");
+		s = qnames[i];
+		if(strlen(str) + strlen(s) >= STRINGSZ)
+			break;
+		strcat(str, s);
+		b &= ~(1L << i);
+	}
+	return fmtstrcpy(fp, str);
+}
+
+int
+VBconv(Fmt *fp)
+{
+	char str[STRINGSZ];
+	int i, n, t, pc;
+
+	n = va_arg(fp->args, int);
+	pc = 0;	/* BUG: was printcol */
+	i = 0;
+	while(pc < n) {
+		t = (pc+4) & ~3;
+		if(t <= n) {
+			str[i++] = '\t';
+			pc = t;
+			continue;
+		}
+		str[i++] = ' ';
+		pc++;
+	}
+	str[i] = 0;
+
+	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)
+{
+	int i;
+
+	if(*p != 0) {
+		for(i=1; i < ninclude; i++)
+			if(strcmp(p, include[i]) == 0)
+				return;
+
+		if(ninclude%8 == 0)
+			include = allocn(include, ninclude*sizeof(char *),
+				8*sizeof(char *));
+		include[ninclude++] = p;
+	}
+}
+
+void*
+alloc(int32 n)
+{
+	void *p;
+
+	p = malloc(n);
+	if(p == nil) {
+		print("alloc out of mem\n");
+		exits("alloc: out of mem");
+	}
+	memset(p, 0, n);
+	return p;
+}
+
+void*
+allocn(void *p, int32 n, int32 d)
+{
+	if(p == nil)
+		return alloc(n+d);
+	p = realloc(p, n+d);
+	if(p == nil) {
+		print("allocn out of mem\n");
+		exits("allocn: out of mem");
+	}
+	if(d > 0)
+		memset((char*)p+n, 0, d);
+	return p;
+}
+
+void
+ensuresymb(int32 n)
+{
+	if(symb == nil) {
+		symb = alloc(NSYMB+1);
+		nsymb = NSYMB;
+	}
+
+	if(n > nsymb) {
+		symb = allocn(symb, nsymb, n+1-nsymb);
+		nsymb = n;
+	}
+}
diff --git a/src/cmd/cc/lexbody b/src/cmd/cc/lexbody
new file mode 100644
index 0000000..e24db1b
--- /dev/null
+++ b/src/cmd/cc/lexbody
@@ -0,0 +1,709 @@
+// Inferno utils/cc/lexbody
+// http://code.google.com/p/inferno-os/source/browse/utils/cc/lexbody
+//
+//	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.
+
+/*
+ * common code for all the assemblers
+ */
+
+void
+pragpack(void)
+{
+	while(getnsc() != '\n')
+		;
+}
+
+void
+pragvararg(void)
+{
+	while(getnsc() != '\n')
+		;
+}
+
+void
+pragcgo(char *name)
+{
+	USED(name);
+	while(getnsc() != '\n')
+		;
+}
+
+void
+pragfpround(void)
+{
+	while(getnsc() != '\n')
+		;
+}
+
+void
+pragtextflag(void)
+{
+	while(getnsc() != '\n')
+		;
+}
+
+void
+pragdataflag(void)
+{
+	while(getnsc() != '\n')
+		;
+}
+
+void
+pragprofile(void)
+{
+	while(getnsc() != '\n')
+		;
+}
+
+void
+pragincomplete(void)
+{
+	while(getnsc() != '\n')
+		;
+}
+
+void*
+alloc(int32 n)
+{
+	void *p;
+
+	p = malloc(n);
+	if(p == nil) {
+		print("alloc out of mem\n");
+		exits("alloc: out of mem");
+	}
+	memset(p, 0, n);
+	return p;
+}
+
+void*
+allocn(void *p, int32 n, int32 d)
+{
+	if(p == nil)
+		return alloc(n+d);
+	p = realloc(p, n+d);
+	if(p == nil) {
+		print("allocn out of mem\n");
+		exits("allocn: out of mem");
+	}
+	if(d > 0)
+		memset((char*)p+n, 0, d);
+	return p;
+}
+
+void
+ensuresymb(int32 n)
+{
+	if(symb == nil) {
+		symb = alloc(NSYMB+1);
+		nsymb = NSYMB;
+	}
+
+	if(n > nsymb) {
+		symb = allocn(symb, nsymb, n+1-nsymb);
+		nsymb = n;
+	}
+}
+
+void
+setinclude(char *p)
+{
+	int i;
+
+	if(p == 0)
+		return;
+	for(i=1; i < ninclude; i++)
+		if(strcmp(p, include[i]) == 0)
+			return;
+	
+	if(ninclude%8 == 0)
+		include = allocn(include, ninclude*sizeof(char *), 
+			8*sizeof(char *));
+	include[ninclude++] = p;
+}
+
+void
+errorexit(void)
+{
+	Bflush(&bstdout);
+	if(outfile)
+		remove(outfile);
+	exits("error");
+}
+
+void
+pushio(void)
+{
+	Io *i;
+
+	i = iostack;
+	if(i == I) {
+		yyerror("botch in pushio");
+		errorexit();
+	}
+	i->p = fi.p;
+	i->c = fi.c;
+}
+
+void
+newio(void)
+{
+	Io *i;
+	static int pushdepth = 0;
+
+	i = iofree;
+	if(i == I) {
+		pushdepth++;
+		if(pushdepth > 1000) {
+			yyerror("macro/io expansion too deep");
+			errorexit();
+		}
+		i = alloc(sizeof(*i));
+	} else
+		iofree = i->link;
+	i->c = 0;
+	i->f = -1;
+	ionext = i;
+}
+
+void
+newfile(char *s, int f)
+{
+	Io *i;
+
+	i = ionext;
+	i->link = iostack;
+	iostack = i;
+	i->f = f;
+	if(f < 0)
+		i->f = open(s, 0);
+	if(i->f < 0) {
+		yyerror("%ca: %r: %s", thechar, s);
+		errorexit();
+	}
+	fi.c = 0;
+	linklinehist(ctxt, lineno, s, 0);
+}
+
+Sym*
+slookup(char *s)
+{
+	ensuresymb(strlen(s));
+	strcpy(symb, s);
+	return lookup();
+}
+
+Sym*
+lookup(void)
+{
+	Sym *s;
+	uint32 h;
+	char *p;
+	int c, l;
+	char *r, *w;
+
+	if((uchar)symb[0] == 0xc2 && (uchar)symb[1] == 0xb7) {
+		// turn leading · into ""·
+		h = strlen(symb);
+		ensuresymb(h+2);
+		memmove(symb+2, symb, h+1);
+		symb[0] = '"';
+		symb[1] = '"';
+	}
+
+	for(r=w=symb; *r; r++) {
+		// turn · (U+00B7) into .
+		// turn ∕ (U+2215) into /
+		if((uchar)*r == 0xc2 && (uchar)*(r+1) == 0xb7) {
+			*w++ = '.';
+			r++;
+		}else if((uchar)*r == 0xe2 && (uchar)*(r+1) == 0x88 && (uchar)*(r+2) == 0x95) {
+			*w++ = '/';
+			r++;
+			r++;
+		}else
+			*w++ = *r;
+	}
+	*w = '\0';
+
+	h = 0;
+	for(p=symb; c = *p; p++)
+		h = h+h+h + c;
+	l = (p - symb) + 1;
+	h &= 0xffffff;
+	h %= NHASH;
+	c = symb[0];
+	for(s = hash[h]; s != S; s = s->link) {
+		if(s->name[0] != c)
+			continue;
+		if(strcmp(s->name, symb) == 0)
+			return s;
+	}
+	s = alloc(sizeof(*s));
+	s->name = alloc(l);
+	memmove(s->name, symb, l);
+
+	s->link = hash[h];
+	hash[h] = s;
+	syminit(s);
+	return s;
+}
+
+int
+ISALPHA(int c)
+{
+	if(isalpha(c))
+		return 1;
+	if(c >= Runeself)
+		return 1;
+	return 0;
+}
+
+int32
+yylex(void)
+{
+	int c, c1;
+	char *cp;
+	Sym *s;
+
+	c = peekc;
+	if(c != IGN) {
+		peekc = IGN;
+		goto l1;
+	}
+l0:
+	c = GETC();
+
+l1:
+	if(c == EOF) {
+		peekc = EOF;
+		return -1;
+	}
+	if(isspace(c)) {
+		if(c == '\n') {
+			lineno++;
+			return ';';
+		}
+		goto l0;
+	}
+	if(ISALPHA(c))
+		goto talph;
+	if(isdigit(c))
+		goto tnum;
+	switch(c)
+	{
+	case '\n':
+		lineno++;
+		return ';';
+
+	case '#':
+		domacro();
+		goto l0;
+
+	case '.':
+		c = GETC();
+		if(ISALPHA(c)) {
+			cp = symb;
+			*cp++ = '.';
+			goto aloop;
+		}
+		if(isdigit(c)) {
+			cp = symb;
+			*cp++ = '.';
+			goto casedot;
+		}
+		peekc = c;
+		return '.';
+
+	talph:
+	case '_':
+	case '@':
+		cp = symb;
+
+	aloop:
+		*cp++ = c;
+		c = GETC();
+		if(ISALPHA(c) || isdigit(c) || c == '_' || c == '$')
+			goto aloop;
+		*cp = 0;
+		peekc = c;
+		s = lookup();
+		if(s->macro) {
+			newio();
+			cp = ionext->b;
+			macexpand(s, cp);
+			pushio();
+			ionext->link = iostack;
+			iostack = ionext;
+			fi.p = cp;
+			fi.c = strlen(cp);
+			if(peekc != IGN) {
+				cp[fi.c++] = peekc;
+				cp[fi.c] = 0;
+				peekc = IGN;
+			}
+			goto l0;
+		}
+		if(s->type == 0)
+			s->type = LNAME;
+		if(s->type == LNAME ||
+		   s->type == LVAR ||
+		   s->type == LLAB) {
+			yylval.sym = s;
+			return s->type;
+		}
+		yylval.lval = s->value;
+		return s->type;
+
+	tnum:
+		cp = symb;
+		if(c != '0')
+			goto dc;
+		*cp++ = c;
+		c = GETC();
+		c1 = 3;
+		if(c == 'x' || c == 'X') {
+			c1 = 4;
+			c = GETC();
+		} else
+		if(c < '0' || c > '7')
+			goto dc;
+		yylval.lval = 0;
+		for(;;) {
+			if(c >= '0' && c <= '9') {
+				if(c > '7' && c1 == 3)
+					break;
+				yylval.lval = (uvlong)yylval.lval << c1;
+				yylval.lval += c - '0';
+				c = GETC();
+				continue;
+			}
+			if(c1 == 3)
+				break;
+			if(c >= 'A' && c <= 'F')
+				c += 'a' - 'A';
+			if(c >= 'a' && c <= 'f') {
+				yylval.lval = (uvlong)yylval.lval << c1;
+				yylval.lval += c - 'a' + 10;
+				c = GETC();
+				continue;
+			}
+			break;
+		}
+		goto ncu;
+
+	dc:
+		for(;;) {
+			if(!isdigit(c))
+				break;
+			*cp++ = c;
+			c = GETC();
+		}
+		if(c == '.')
+			goto casedot;
+		if(c == 'e' || c == 'E')
+			goto casee;
+		*cp = 0;
+		if(sizeof(yylval.lval) == sizeof(vlong))
+			yylval.lval = strtoll(symb, nil, 10);
+		else
+			yylval.lval = strtol(symb, nil, 10);
+
+	ncu:
+		while(c == 'U' || c == 'u' || c == 'l' || c == 'L')
+			c = GETC();
+		peekc = c;
+		return LCONST;
+
+	casedot:
+		for(;;) {
+			*cp++ = c;
+			c = GETC();
+			if(!isdigit(c))
+				break;
+		}
+		if(c == 'e' || c == 'E')
+			goto casee;
+		goto caseout;
+
+	casee:
+		*cp++ = 'e';
+		c = GETC();
+		if(c == '+' || c == '-') {
+			*cp++ = c;
+			c = GETC();
+		}
+		while(isdigit(c)) {
+			*cp++ = c;
+			c = GETC();
+		}
+
+	caseout:
+		*cp = 0;
+		peekc = c;
+		if(FPCHIP) {
+			yylval.dval = atof(symb);
+			return LFCONST;
+		}
+		yyerror("assembler cannot interpret fp constants");
+		yylval.lval = 1L;
+		return LCONST;
+
+	case '"':
+		memcpy(yylval.sval, nullgen.u.sval, sizeof(yylval.sval));
+		cp = yylval.sval;
+		c1 = 0;
+		for(;;) {
+			c = escchar('"');
+			if(c == EOF)
+				break;
+			if(c1 < sizeof(yylval.sval))
+				*cp++ = c;
+			c1++;
+		}
+		if(c1 > sizeof(yylval.sval))
+			yyerror("string constant too long");
+		return LSCONST;
+
+	case '\'':
+		c = escchar('\'');
+		if(c == EOF)
+			c = '\'';
+		if(escchar('\'') != EOF)
+			yyerror("missing '");
+		yylval.lval = c;
+		return LCONST;
+
+	case '/':
+		c1 = GETC();
+		if(c1 == '/') {
+			for(;;) {
+				c = GETC();
+				if(c == '\n')
+					goto l1;
+				if(c == EOF) {
+					yyerror("eof in comment");
+					errorexit();
+				}
+			}
+		}
+		if(c1 == '*') {
+			for(;;) {
+				c = GETC();
+				while(c == '*') {
+					c = GETC();
+					if(c == '/')
+						goto l0;
+				}
+				if(c == EOF) {
+					yyerror("eof in comment");
+					errorexit();
+				}
+				if(c == '\n')
+					lineno++;
+			}
+		}
+		break;
+
+	default:
+		return c;
+	}
+	peekc = c1;
+	return c;
+}
+
+int
+getc(void)
+{
+	int c;
+
+	c = peekc;
+	if(c != IGN) {
+		peekc = IGN;
+		return c;
+	}
+	c = GETC();
+	if(c == '\n')
+		lineno++;
+	if(c == EOF) {
+		yyerror("End of file");
+		errorexit();
+	}
+	return c;
+}
+
+int
+getnsc(void)
+{
+	int c;
+
+	for(;;) {
+		c = getc();
+		if(!isspace(c) || c == '\n')
+			return c;
+	}
+}
+
+void
+unget(int c)
+{
+
+	peekc = c;
+	if(c == '\n')
+		lineno--;
+}
+
+int
+escchar(int e)
+{
+	int c, l;
+
+loop:
+	c = getc();
+	if(c == '\n') {
+		yyerror("newline in string");
+		return EOF;
+	}
+	if(c != '\\') {
+		if(c == e)
+			return EOF;
+		return c;
+	}
+	c = getc();
+	if(c >= '0' && c <= '7') {
+		l = c - '0';
+		c = getc();
+		if(c >= '0' && c <= '7') {
+			l = l*8 + c-'0';
+			c = getc();
+			if(c >= '0' && c <= '7') {
+				l = l*8 + c-'0';
+				return l;
+			}
+		}
+		peekc = c;
+		return l;
+	}
+	switch(c)
+	{
+	case '\n':	goto loop;
+	case 'n':	return '\n';
+	case 't':	return '\t';
+	case 'b':	return '\b';
+	case 'r':	return '\r';
+	case 'f':	return '\f';
+	case 'a':	return 0x07;
+	case 'v':	return 0x0b;
+	case 'z':	return 0x00;
+	}
+	return c;
+}
+
+void
+pinit(char *f)
+{
+	int i;
+	Sym *s;
+
+	lineno = 1;
+	newio();
+	newfile(f, -1);
+	pc = 0;
+	peekc = IGN;
+	sym = 1;
+	for(i=0; i<NHASH; i++)
+		for(s = hash[i]; s != S; s = s->link)
+			s->macro = 0;
+}
+
+int
+filbuf(void)
+{
+	Io *i;
+
+loop:
+	i = iostack;
+	if(i == I)
+		return EOF;
+	if(i->f < 0)
+		goto pop;
+	fi.c = read(i->f, i->b, BUFSIZ) - 1;
+	if(fi.c < 0) {
+		close(i->f);
+		linklinehist(ctxt, lineno, 0, 0);
+		goto pop;
+	}
+	fi.p = i->b + 1;
+	return i->b[0] & 0xff;
+
+pop:
+	iostack = i->link;
+	i->link = iofree;
+	iofree = i;
+	i = iostack;
+	if(i == I)
+		return EOF;
+	fi.p = i->p;
+	fi.c = i->c;
+	if(--fi.c < 0)
+		goto loop;
+	return *fi.p++ & 0xff;
+}
+
+void
+yyerror(char *a, ...)
+{
+	char buf[200];
+	va_list arg;
+
+	/*
+	 * hack to intercept message from yaccpar
+	 */
+	if(strcmp(a, "syntax error") == 0) {
+		yyerror("syntax error, last name: %s", symb);
+		return;
+	}
+	prfile(lineno);
+	va_start(arg, a);
+	vseprint(buf, buf+sizeof(buf), a, arg);
+	va_end(arg);
+	print("%s\n", buf);
+	nerrors++;
+	if(nerrors > 10) {
+		print("too many errors\n");
+		errorexit();
+	}
+}
+
+void
+prfile(int32 l)
+{
+	linkprfile(ctxt, l);
+}
diff --git a/src/cmd/cc/mac.c b/src/cmd/cc/mac.c
new file mode 100644
index 0000000..b969662
--- /dev/null
+++ b/src/cmd/cc/mac.c
@@ -0,0 +1,34 @@
+// Inferno utils/cc/mac.c
+// http://code.google.com/p/inferno-os/source/browse/utils/cc/mac.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	"cc.h"
+
+#include	"macbody"
diff --git a/src/cmd/cc/macbody b/src/cmd/cc/macbody
new file mode 100644
index 0000000..f6927b2
--- /dev/null
+++ b/src/cmd/cc/macbody
@@ -0,0 +1,800 @@
+// Inferno utils/cc/macbody
+// http://code.google.com/p/inferno-os/source/browse/utils/cc/macbody
+//
+//	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.
+
+#define VARMAC 0x80
+
+int32
+getnsn(void)
+{
+	int32 n;
+	int c;
+
+	c = getnsc();
+	if(c < '0' || c > '9')
+		return -1;
+	n = 0;
+	while(c >= '0' && c <= '9') {
+		n = n*10 + c-'0';
+		c = getc();
+	}
+	unget(c);
+	return n;
+}
+
+Sym*
+getsym(void)
+{
+	int c;
+	char *cp;
+
+	c = getnsc();
+	if(!isalpha(c) && c != '_' && c < 0x80) {
+		unget(c);
+		return S;
+	}
+	for(cp = symb;;) {
+		if(cp <= symb+NSYMB-4)
+			*cp++ = c;
+		c = getc();
+		if(isalnum(c) || c == '_' || c >= 0x80)
+			continue;
+		unget(c);
+		break;
+	}
+	*cp = 0;
+	if(cp > symb+NSYMB-4)
+		yyerror("symbol too large: %s", symb);
+	return lookup();
+}
+
+Sym*
+getsymdots(int *dots)
+{
+	int c;
+	Sym *s;
+
+	s = getsym();
+	if(s != S)
+		return s;
+
+	c = getnsc();
+	if(c != '.'){
+		unget(c);
+		return S;
+	}
+	if(getc() != '.' || getc() != '.')
+		yyerror("bad dots in macro");
+	*dots = 1;
+	return slookup("__VA_ARGS__");
+}
+
+int
+getcom(void)
+{
+	int c;
+
+	for(;;) {
+		c = getnsc();
+		if(c != '/')
+			break;
+		c = getc();
+		if(c == '/') {
+			while(c != '\n')
+				c = getc();
+			break;
+		}
+		if(c != '*')
+			break;
+		c = getc();
+		for(;;) {
+			if(c == '*') {
+				c = getc();
+				if(c != '/')
+					continue;
+				c = getc();
+				break;
+			}
+			if(c == '\n') {
+				yyerror("comment across newline");
+				break;
+			}
+			c = getc();
+		}
+		if(c == '\n')
+			break;
+	}
+	return c;
+}
+
+void
+dodefine(char *cp)
+{
+	Sym *s;
+	char *p;
+	int32 l;
+
+	ensuresymb(strlen(cp));
+	strcpy(symb, cp);
+	p = strchr(symb, '=');
+	if(p) {
+		*p++ = 0;
+		s = lookup();
+		l = strlen(p) + 2;	/* +1 null, +1 nargs */
+		s->macro = alloc(l);
+		strcpy(s->macro+1, p);
+	} else {
+		s = lookup();
+		s->macro = "\0001";	/* \000 is nargs */
+	}
+	if(debug['m'])
+		print("#define (-D) %s %s\n", s->name, s->macro+1);
+}
+
+struct
+{
+	char	*macname;
+	void	(*macf)(void);
+} mactab[] =
+{
+	"ifdef",	0,	/* macif(0) */
+	"ifndef",	0,	/* macif(1) */
+	"else",		0,	/* macif(2) */
+
+	"line",		maclin,
+	"define",	macdef,
+	"include",	macinc,
+	"undef",	macund,
+
+	"pragma",	macprag,
+	"endif",	macend,
+	0
+};
+
+void
+domacro(void)
+{
+	int i;
+	Sym *s;
+
+	s = getsym();
+	if(s == S)
+		s = slookup("endif");
+	for(i=0; mactab[i].macname; i++)
+		if(strcmp(s->name, mactab[i].macname) == 0) {
+			if(mactab[i].macf)
+				(*mactab[i].macf)();
+			else
+				macif(i);
+			return;
+		}
+	yyerror("unknown #: %s", s->name);
+	macend();
+}
+
+void
+macund(void)
+{
+	Sym *s;
+
+	s = getsym();
+	macend();
+	if(s == S) {
+		yyerror("syntax in #undef");
+		return;
+	}
+	s->macro = 0;
+}
+
+#define	NARG	25
+void
+macdef(void)
+{
+	Sym *s, *a;
+	char *args[NARG], *np, *base;
+	int n, i, c, len, dots;
+	int ischr;
+
+	s = getsym();
+	if(s == S)
+		goto bad;
+	if(s->macro)
+		yyerror("macro redefined: %s", s->name);
+	c = getc();
+	n = -1;
+	dots = 0;
+	if(c == '(') {
+		n++;
+		c = getnsc();
+		if(c != ')') {
+			unget(c);
+			for(;;) {
+				a = getsymdots(&dots);
+				if(a == S)
+					goto bad;
+				if(n >= NARG) {
+					yyerror("too many arguments in #define: %s", s->name);
+					goto bad;
+				}
+				args[n++] = a->name;
+				c = getnsc();
+				if(c == ')')
+					break;
+				if(c != ',' || dots)
+					goto bad;
+			}
+		}
+		c = getc();
+	}
+	if(isspace(c))
+		if(c != '\n')
+			c = getnsc();
+	base = hunk;
+	len = 1;
+	ischr = 0;
+	for(;;) {
+		if(isalpha(c) || c == '_') {
+			np = symb;
+			*np++ = c;
+			c = getc();
+			while(isalnum(c) || c == '_') {
+				*np++ = c;
+				c = getc();
+			}
+			*np = 0;
+			for(i=0; i<n; i++)
+				if(strcmp(symb, args[i]) == 0)
+					break;
+			if(i >= n) {
+				i = strlen(symb);
+				base = allocn(base, len, i);
+				memcpy(base+len, symb, i);
+				len += i;
+				continue;
+			}
+			base = allocn(base, len, 2);
+			base[len++] = '#';
+			base[len++] = 'a' + i;
+			continue;
+		}
+		if(ischr){
+			if(c == '\\'){
+				base = allocn(base, len, 1);
+				base[len++] = c;
+				c = getc();
+			}else if(c == ischr)
+				ischr = 0;
+		}else{
+			if(c == '"' || c == '\''){
+				base = allocn(base, len, 1);
+				base[len++] = c;
+				ischr = c;
+				c = getc();
+				continue;
+			}
+			if(c == '/') {
+				c = getc();
+				if(c == '/'){
+					c = getc();
+					for(;;) {
+						if(c == '\n')
+							break;
+						c = getc();
+					}
+					continue;
+				}
+				if(c == '*'){
+					c = getc();
+					for(;;) {
+						if(c == '*') {
+							c = getc();
+							if(c != '/')
+								continue;
+							c = getc();
+							break;
+						}
+						if(c == '\n') {
+							yyerror("comment and newline in define: %s", s->name);
+							break;
+						}
+						c = getc();
+					}
+					continue;
+				}
+				base = allocn(base, len, 1);
+				base[len++] = '/';
+				continue;
+			}
+		}
+		if(c == '\\') {
+			c = getc();
+			if(c == '\n') {
+				c = getc();
+				continue;
+			}
+			else if(c == '\r') {
+				c = getc();
+				if(c == '\n') {
+					c = getc();
+					continue;
+				}
+			}
+			base = allocn(base, len, 1);
+			base[len++] = '\\';
+			continue;
+		}
+		if(c == '\n')
+			break;
+		if(c == '#')
+		if(n > 0) {
+			base = allocn(base, len, 1);
+			base[len++] = c;
+		}
+		base = allocn(base, len, 1);
+		base[len++] = c;
+		c = ((--fi.c < 0)? filbuf(): (*fi.p++ & 0xff));
+		if(c == '\n')
+			lineno++;
+		if(c == -1) {
+			yyerror("eof in a macro: %s", s->name);
+			break;
+		}
+	}
+	do {
+		base = allocn(base, len, 1);
+		base[len++] = 0;
+	} while(len & 3);
+
+	*base = n+1;
+	if(dots)
+		*base |= VARMAC;
+	s->macro = base;
+	if(debug['m'])
+		print("#define %s %s\n", s->name, s->macro+1);
+	return;
+
+bad:
+	if(s == S)
+		yyerror("syntax in #define");
+	else
+		yyerror("syntax in #define: %s", s->name);
+	macend();
+}
+
+void
+macexpand(Sym *s, char *b)
+{
+	char buf[2000];
+	int n, l, c, nargs;
+	char *arg[NARG], *cp, *ob, *ecp, dots;
+
+	ob = b;
+	if(*s->macro == 0) {
+		strcpy(b, s->macro+1);
+		if(debug['m'])
+			print("#expand %s %s\n", s->name, ob);
+		return;
+	}
+
+	nargs = (char)(*s->macro & ~VARMAC) - 1;
+	dots = *s->macro & VARMAC;
+
+	c = getnsc();
+	if(c != '(')
+		goto bad;
+	n = 0;
+	c = getc();
+	if(c != ')') {
+		unget(c);
+		l = 0;
+		cp = buf;
+		ecp = cp + sizeof(buf)-4;
+		arg[n++] = cp;
+		for(;;) {
+			if(cp >= ecp)
+				goto toobig;
+			c = getc();
+			if(c == '"')
+				for(;;) {
+					if(cp >= ecp)
+						goto toobig;
+					*cp++ = c;
+					c = getc();
+					if(c == '\\') {
+						*cp++ = c;
+						c = getc();
+						continue;
+					}
+					if(c == '\n')
+						goto bad;
+					if(c == '"')
+						break;
+				}
+			if(c == '\'')
+				for(;;) {
+					if(cp >= ecp)
+						goto toobig;
+					*cp++ = c;
+					c = getc();
+					if(c == '\\') {
+						*cp++ = c;
+						c = getc();
+						continue;
+					}
+					if(c == '\n')
+						goto bad;
+					if(c == '\'')
+						break;
+				}
+			if(c == '/') {
+				c = getc();
+				switch(c) {
+				case '*':
+					for(;;) {
+						c = getc();
+						if(c == '*') {
+							c = getc();
+							if(c == '/')
+								break;
+						}
+					}
+					*cp++ = ' ';
+					continue;
+				case '/':
+					while((c = getc()) != '\n')
+						;
+					break;
+				default:
+					unget(c);
+					c = '/';
+				}
+			}
+			if(l == 0) {
+				if(c == ',') {
+					if(n == nargs && dots) {
+						*cp++ = ',';
+						continue;
+					}
+					*cp++ = 0;
+					arg[n++] = cp;
+					if(n > nargs)
+						break;
+					continue;
+				}
+				if(c == ')')
+					break;
+			}
+			if(c == '\n')
+				c = ' ';
+			*cp++ = c;
+			if(c == '(')
+				l++;
+			if(c == ')')
+				l--;
+		}
+		*cp = 0;
+	}
+	if(n != nargs) {
+		yyerror("argument mismatch expanding: %s", s->name);
+		*b = 0;
+		return;
+	}
+	cp = s->macro+1;
+	for(;;) {
+		c = *cp++;
+		if(c == '\n')
+			c = ' ';
+		if(c != '#') {
+			*b++ = c;
+			if(c == 0)
+				break;
+			continue;
+		}
+		c = *cp++;
+		if(c == 0)
+			goto bad;
+		if(c == '#') {
+			*b++ = c;
+			continue;
+		}
+		c -= 'a';
+		if(c < 0 || c >= n)
+			continue;
+		strcpy(b, arg[c]);
+		b += strlen(arg[c]);
+	}
+	*b = 0;
+	if(debug['m'])
+		print("#expand %s %s\n", s->name, ob);
+	return;
+
+bad:
+	yyerror("syntax in macro expansion: %s", s->name);
+	*b = 0;
+	return;
+
+toobig:
+	yyerror("too much text in macro expansion: %s", s->name);
+	*b = 0;
+}
+
+void
+macinc(void)
+{
+	int c0, c, i, f;
+	char str[STRINGSZ], *hp;
+
+	c0 = getnsc();
+	if(c0 != '"') {
+		c = c0;
+		if(c0 != '<')
+			goto bad;
+		c0 = '>';
+	}
+	for(hp = str;;) {
+		c = getc();
+		if(c == c0)
+			break;
+		if(c == '\n')
+			goto bad;
+		*hp++ = c;
+	}
+	*hp = 0;
+
+	c = getcom();
+	if(c != '\n')
+		goto bad;
+
+	f = -1;
+	for(i=0; i<ninclude; i++) {
+		if(i == 0 && c0 == '>')
+			continue;
+		ensuresymb(strlen(include[i])+strlen(str)+2);
+		strcpy(symb, include[i]);
+		strcat(symb, "/");
+		if(strcmp(symb, "./") == 0)
+			symb[0] = 0;
+		strcat(symb, str);
+		f = open(symb, OREAD);
+		if(f >= 0)
+			break;
+	}
+	if(f < 0)
+		strcpy(symb, str);
+	c = strlen(symb) + 1;
+	hp = alloc(c);
+	memcpy(hp, symb, c);
+	newio();
+	pushio();
+	newfile(hp, f);
+	return;
+
+bad:
+	unget(c);
+	yyerror("syntax in #include");
+	macend();
+}
+
+void
+maclin(void)
+{
+	char *cp;
+	int c;
+	int32 n;
+
+	n = getnsn();
+	c = getc();
+	if(n < 0)
+		goto bad;
+
+	for(;;) {
+		if(c == ' ' || c == '\t') {
+			c = getc();
+			continue;
+		}
+		if(c == '"')
+			break;
+		if(c == '\n') {
+			strcpy(symb, "<noname>");
+			goto nn;
+		}
+		goto bad;
+	}
+	cp = symb;
+	for(;;) {
+		c = getc();
+		if(c == '"')
+			break;
+		*cp++ = c;
+	}
+	*cp = 0;
+	c = getcom();
+	if(c != '\n')
+		goto bad;
+
+nn:
+	c = strlen(symb) + 1;
+	cp = alloc(c);
+	memcpy(cp, symb, c);
+	linklinehist(ctxt, lineno, cp, n);
+	return;
+
+bad:
+	unget(c);
+	yyerror("syntax in #line");
+	macend();
+}
+
+void
+macif(int f)
+{
+	int c, l, bol;
+	Sym *s;
+
+	if(f == 2)
+		goto skip;
+	s = getsym();
+	if(s == S)
+		goto bad;
+	if(getcom() != '\n')
+		goto bad;
+	if((s->macro != 0) ^ f)
+		return;
+
+skip:
+	bol = 1;
+	l = 0;
+	for(;;) {
+		c = getc();
+		if(c != '#') {
+			if(!isspace(c))
+				bol = 0;
+			if(c == '\n')
+				bol = 1;
+			continue;
+		}
+		if(!bol)
+			continue;
+		s = getsym();
+		if(s == S)
+			continue;
+		if(strcmp(s->name, "endif") == 0) {
+			if(l) {
+				l--;
+				continue;
+			}
+			macend();
+			return;
+		}
+		if(strcmp(s->name, "ifdef") == 0 || strcmp(s->name, "ifndef") == 0) {
+			l++;
+			continue;
+		}
+		if(l == 0 && f != 2 && strcmp(s->name, "else") == 0) {
+			macend();
+			return;
+		}
+	}
+
+bad:
+	yyerror("syntax in #if(n)def");
+	macend();
+}
+
+void
+macprag(void)
+{
+	Sym *s;
+	int c0, c;
+	char *hp;
+
+	s = getsym();
+
+	if(s && strcmp(s->name, "lib") == 0)
+		goto praglib;
+	if(s && strcmp(s->name, "pack") == 0) {
+		pragpack();
+		return;
+	}
+	if(s && strcmp(s->name, "fpround") == 0) {
+		pragfpround();
+		return;
+	}
+	if(s && strcmp(s->name, "textflag") == 0) {
+		pragtextflag();
+		return;
+	}
+	if(s && strcmp(s->name, "dataflag") == 0) {
+		pragdataflag();
+		return;
+	}
+	if(s && strcmp(s->name, "varargck") == 0) {
+		pragvararg();
+		return;
+	}
+	if(s && strcmp(s->name, "incomplete") == 0) {
+		pragincomplete();
+		return;
+	}
+	if(s && (strncmp(s->name, "cgo_", 4) == 0 || strncmp(s->name, "dyn", 3) == 0)) {
+		pragcgo(s->name);
+		return;
+	}
+	while(getnsc() != '\n')
+		;
+	return;
+
+praglib:
+	c0 = getnsc();
+	if(c0 != '"') {
+		c = c0;
+		if(c0 != '<')
+			goto bad;
+		c0 = '>';
+	}
+	for(hp = symb;;) {
+		c = getc();
+		if(c == c0)
+			break;
+		if(c == '\n')
+			goto bad;
+		*hp++ = c;
+	}
+	*hp = 0;
+	c = getcom();
+	if(c != '\n')
+		goto bad;
+
+	/*
+	 * put pragma-line in as a funny history
+	 */
+	c = strlen(symb) + 1;
+	hp = alloc(c);
+	memcpy(hp, symb, c);
+
+	linklinehist(ctxt, lineno, hp, -1);
+	return;
+
+bad:
+	unget(c);
+	yyerror("syntax in #pragma lib");
+	macend();
+}
+
+void
+macend(void)
+{
+	int c;
+
+	for(;;) {
+		c = getnsc();
+		if(c < 0 || c == '\n')
+			return;
+	}
+}
diff --git a/src/cmd/cc/omachcap.c b/src/cmd/cc/omachcap.c
new file mode 100644
index 0000000..f8fc1d8
--- /dev/null
+++ b/src/cmd/cc/omachcap.c
@@ -0,0 +1,40 @@
+// Inferno utils/cc/machcap.c
+// http://code.google.com/p/inferno-os/source/browse/utils/cc/machcap.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	"cc.h"
+
+/* default, like old cc */
+int
+machcap(Node *n)
+{
+	USED(n);
+	return 0;
+}
diff --git a/src/cmd/cc/pgen.c b/src/cmd/cc/pgen.c
new file mode 100644
index 0000000..db9aae9
--- /dev/null
+++ b/src/cmd/cc/pgen.c
@@ -0,0 +1,622 @@
+// Inferno utils/6c/sgen.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/sgen.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 "gc.h"
+#include "../../runtime/funcdata.h"
+
+int
+hasdotdotdot(Type *t)
+{
+	for(t=t->down; t!=T; t=t->down)
+		if(t->etype == TDOT)
+			return 1;
+	return 0;
+}
+
+vlong
+argsize(int doret)
+{
+	Type *t;
+	int32 s;
+
+//print("t=%T\n", thisfn);
+	s = 0;
+	if(hasdotdotdot(thisfn))
+		s = align(s, thisfn->link, Aarg0, nil);
+	for(t=thisfn->down; t!=T; t=t->down) {
+		switch(t->etype) {
+		case TVOID:
+			break;
+		case TDOT:
+			if((textflag & NOSPLIT) == 0)
+				yyerror("function takes ... without textflag NOSPLIT");
+			return ArgsSizeUnknown;
+		default:
+			s = align(s, t, Aarg1, nil);
+			s = align(s, t, Aarg2, nil);
+			break;
+		}
+//print("	%d %T\n", s, t);
+	}
+	if(thechar == '6')
+		s = (s+7) & ~7;
+	else
+		s = (s+3) & ~3;
+	if(doret && thisfn->link->etype != TVOID) {
+		s = align(s, thisfn->link, Aarg1, nil);
+		s = align(s, thisfn->link, Aarg2, nil);
+		if(thechar == '6')
+			s = (s+7) & ~7;
+		else
+			s = (s+3) & ~3;
+	}
+	return s;
+}
+
+void
+codgen(Node *n, Node *nn)
+{
+	Prog *sp;
+	Node *n1, nod, nod1;
+
+	cursafe = 0;
+	curarg = 0;
+	maxargsafe = 0;
+
+	/*
+	 * isolate name
+	 */
+	for(n1 = nn;; n1 = n1->left) {
+		if(n1 == Z) {
+			diag(nn, "can't find function name");
+			return;
+		}
+		if(n1->op == ONAME)
+			break;
+	}
+	nearln = nn->lineno;
+
+	p = gtext(n1->sym, stkoff);
+	p->from.sym->cfunc = 1;
+	sp = p;
+
+	/*
+	 * isolate first argument
+	 */
+	if(REGARG >= 0) {
+		if(typesuv[thisfn->link->etype]) {
+			nod1 = *nodret->left;
+			nodreg(&nod, &nod1, REGARG);
+			gmove(&nod, &nod1);
+		} else
+		if(firstarg && typechlp[firstargtype->etype]) {
+			nod1 = *nodret->left;
+			nod1.sym = firstarg;
+			nod1.type = firstargtype;
+			nod1.xoffset = align(0, firstargtype, Aarg1, nil);
+			nod1.etype = firstargtype->etype;
+			nodreg(&nod, &nod1, REGARG);
+			gmove(&nod, &nod1);
+		}
+	}
+
+	canreach = 1;
+	warnreach = 1;
+	gen(n);
+	if(canreach && thisfn->link->etype != TVOID)
+		diag(Z, "no return at end of function: %s", n1->sym->name);
+	noretval(3);
+	gbranch(ORETURN);
+
+	if(!debug['N'] || debug['R'] || debug['P'])
+		regopt(sp);
+
+	if(thechar=='6' || thechar=='7')	/* [sic] */
+		maxargsafe = xround(maxargsafe, 8);
+	sp->to.offset += maxargsafe;
+}
+
+void
+supgen(Node *n)
+{
+	int owarn;
+	long spc;
+	Prog *sp;
+
+	if(n == Z)
+		return;
+	suppress++;
+	owarn = warnreach;
+	warnreach = 0;
+	spc = pc;
+	sp = lastp;
+	gen(n);
+	lastp = sp;
+	pc = spc;
+	sp->link = nil;
+	suppress--;
+	warnreach = owarn;
+}
+
+void
+gen(Node *n)
+{
+	Node *l, nod, nod1;
+	Prog *sp, *spc, *spb;
+	Case *cn;
+	long sbc, scc;
+	int snbreak, sncontin;
+	int f, o, oldreach;
+
+loop:
+	if(n == Z)
+		return;
+	nearln = n->lineno;
+	o = n->op;
+	if(debug['G'])
+		if(o != OLIST)
+			print("%L %O\n", nearln, o);
+
+	if(!canreach) {
+		switch(o) {
+		case OLABEL:
+		case OCASE:
+		case OLIST:
+		case OBREAK:
+		case OFOR:
+		case OWHILE:
+		case ODWHILE:
+			/* all handled specially - see switch body below */
+			break;
+		default:
+			if(warnreach) {
+				warn(n, "unreachable code %O", o);
+				warnreach = 0;
+			}
+		}
+	}
+
+	switch(o) {
+
+	default:
+		complex(n);
+		cgen(n, Z);
+		break;
+
+	case OLIST:
+		gen(n->left);
+
+	rloop:
+		n = n->right;
+		goto loop;
+
+	case ORETURN:
+		canreach = 0;
+		warnreach = !suppress;
+		complex(n);
+		if(n->type == T)
+			break;
+		l = n->left;
+		if(l == Z) {
+			noretval(3);
+			gbranch(ORETURN);
+			break;
+		}
+		if(typecmplx[n->type->etype] && !hasdotdotdot(thisfn)) {
+			regret(&nod, n, thisfn, 2);
+			sugen(l, &nod, n->type->width);
+			noretval(3);
+			gbranch(ORETURN);
+			break;
+		}
+		if(typecmplx[n->type->etype]) {
+			sugen(l, nodret, n->type->width);
+			noretval(3);
+			gbranch(ORETURN);
+			break;
+		}
+		regret(&nod1, n, thisfn, 2);
+		nod = nod1;
+		if(nod.op != OREGISTER)
+			regalloc(&nod, n, Z);
+		cgen(l, &nod);
+		if(nod1.op != OREGISTER)
+			gmove(&nod, &nod1);
+		regfree(&nod);
+		if(typefd[n->type->etype])
+			noretval(1);
+		else
+			noretval(2);
+		gbranch(ORETURN);
+		break;
+
+	case OLABEL:
+		canreach = 1;
+		l = n->left;
+		if(l) {
+			l->pc = pc;
+			if(l->label)
+				patch(l->label, pc);
+		}
+		gbranch(OGOTO);	/* prevent self reference in reg */
+		patch(p, pc);
+		goto rloop;
+
+	case OGOTO:
+		canreach = 0;
+		warnreach = !suppress;
+		n = n->left;
+		if(n == Z)
+			return;
+		if(n->complex == 0) {
+			diag(Z, "label undefined: %s", n->sym->name);
+			return;
+		}
+		if(suppress)
+			return;
+		gbranch(OGOTO);
+		if(n->pc) {
+			patch(p, n->pc);
+			return;
+		}
+		if(n->label)
+			patch(n->label, pc-1);
+		n->label = p;
+		return;
+
+	case OCASE:
+		canreach = 1;
+		l = n->left;
+		if(cases == C)
+			diag(n, "case/default outside a switch");
+		if(l == Z) {
+			newcase();
+			cases->val = 0;
+			cases->def = 1;
+			cases->label = pc;
+			cases->isv = 0;
+			goto rloop;
+		}
+		complex(l);
+		if(l->type == T)
+			goto rloop;
+		if(l->op == OCONST)
+		if(typeword[l->type->etype] && l->type->etype != TIND) {
+			newcase();
+			cases->val = l->vconst;
+			cases->def = 0;
+			cases->label = pc;
+			cases->isv = typev[l->type->etype];
+			goto rloop;
+		}
+		diag(n, "case expression must be integer constant");
+		goto rloop;
+
+	case OSWITCH:
+		l = n->left;
+		complex(l);
+		if(l->type == T)
+			break;
+		if(!typechlvp[l->type->etype] || l->type->etype == TIND) {
+			diag(n, "switch expression must be integer");
+			break;
+		}
+
+		gbranch(OGOTO);		/* entry */
+		sp = p;
+
+		cn = cases;
+		cases = C;
+		newcase();
+
+		sbc = breakpc;
+		breakpc = pc;
+		snbreak = nbreak;
+		nbreak = 0;
+		gbranch(OGOTO);
+		spb = p;
+
+		gen(n->right);		/* body */
+		if(canreach){
+			gbranch(OGOTO);
+			patch(p, breakpc);
+			nbreak++;
+		}
+
+		patch(sp, pc);
+		doswit(l);
+		patch(spb, pc);
+
+		cases = cn;
+		breakpc = sbc;
+		canreach = nbreak!=0;
+		if(canreach == 0)
+			warnreach = !suppress;
+		nbreak = snbreak;
+		break;
+
+	case OWHILE:
+	case ODWHILE:
+		l = n->left;
+		gbranch(OGOTO);		/* entry */
+		sp = p;
+
+		scc = continpc;
+		continpc = pc;
+		gbranch(OGOTO);
+		spc = p;
+
+		sbc = breakpc;
+		breakpc = pc;
+		snbreak = nbreak;
+		nbreak = 0;
+		gbranch(OGOTO);
+		spb = p;
+
+		patch(spc, pc);
+		if(n->op == OWHILE)
+			patch(sp, pc);
+		bcomplex(l, Z);		/* test */
+		patch(p, breakpc);
+		if(l->op != OCONST || vconst(l) == 0)
+			nbreak++;
+
+		if(n->op == ODWHILE)
+			patch(sp, pc);
+		gen(n->right);		/* body */
+		gbranch(OGOTO);
+		patch(p, continpc);
+
+		patch(spb, pc);
+		continpc = scc;
+		breakpc = sbc;
+		canreach = nbreak!=0;
+		if(canreach == 0)
+			warnreach = !suppress;
+		nbreak = snbreak;
+		break;
+
+	case OFOR:
+		l = n->left;
+		if(!canreach && l->right->left && warnreach) {
+			warn(n, "unreachable code FOR");
+			warnreach = 0;
+		}
+		gen(l->right->left);	/* init */
+		gbranch(OGOTO);		/* entry */
+		sp = p;
+
+		/*
+		 * if there are no incoming labels in the
+		 * body and the top's not reachable, warn
+		 */
+		if(!canreach && warnreach && deadheads(n)) {
+			warn(n, "unreachable code %O", o);
+			warnreach = 0;
+		}
+
+		scc = continpc;
+		continpc = pc;
+		gbranch(OGOTO);
+		spc = p;
+
+		sbc = breakpc;
+		breakpc = pc;
+		snbreak = nbreak;
+		nbreak = 0;
+		sncontin = ncontin;
+		ncontin = 0;
+		gbranch(OGOTO);
+		spb = p;
+
+		patch(spc, pc);
+		gen(l->right->right);	/* inc */
+		patch(sp, pc);
+		if(l->left != Z) {	/* test */
+			bcomplex(l->left, Z);
+			patch(p, breakpc);
+			if(l->left->op != OCONST || vconst(l->left) == 0)
+				nbreak++;
+		}
+		canreach = 1;
+		gen(n->right);		/* body */
+		if(canreach){
+			gbranch(OGOTO);
+			patch(p, continpc);
+			ncontin++;
+		}
+		if(!ncontin && l->right->right && warnreach) {
+			warn(l->right->right, "unreachable FOR inc");
+			warnreach = 0;
+		}
+
+		patch(spb, pc);
+		continpc = scc;
+		breakpc = sbc;
+		canreach = nbreak!=0;
+		if(canreach == 0)
+			warnreach = !suppress;
+		nbreak = snbreak;
+		ncontin = sncontin;
+		break;
+
+	case OCONTINUE:
+		if(continpc < 0) {
+			diag(n, "continue not in a loop");
+			break;
+		}
+		gbranch(OGOTO);
+		patch(p, continpc);
+		ncontin++;
+		canreach = 0;
+		warnreach = !suppress;
+		break;
+
+	case OBREAK:
+		if(breakpc < 0) {
+			diag(n, "break not in a loop");
+			break;
+		}
+		/*
+		 * Don't complain about unreachable break statements.
+		 * There are breaks hidden in yacc's output and some people
+		 * write return; break; in their switch statements out of habit.
+		 * However, don't confuse the analysis by inserting an
+		 * unreachable reference to breakpc either.
+		 */
+		if(!canreach)
+			break;
+		gbranch(OGOTO);
+		patch(p, breakpc);
+		nbreak++;
+		canreach = 0;
+		warnreach = !suppress;
+		break;
+
+	case OIF:
+		l = n->left;
+		if(bcomplex(l, n->right)) {
+			if(typefd[l->type->etype])
+				f = !l->fconst;
+			else
+				f = !l->vconst;
+			if(debug['c'])
+				print("%L const if %s\n", nearln, f ? "false" : "true");
+			if(f) {
+				canreach = 1;
+				supgen(n->right->left);
+				oldreach = canreach;
+				canreach = 1;
+				gen(n->right->right);
+				/*
+				 * treat constant ifs as regular ifs for
+				 * reachability warnings.
+				 */
+				if(!canreach && oldreach && debug['w'] < 2)
+					warnreach = 0;
+			}
+			else {
+				canreach = 1;
+				gen(n->right->left);
+				oldreach = canreach;
+				canreach = 1;
+				supgen(n->right->right);
+				/*
+				 * treat constant ifs as regular ifs for
+				 * reachability warnings.
+				 */
+				if(!oldreach && canreach && debug['w'] < 2)
+					warnreach = 0;
+				canreach = oldreach;
+			}
+		}
+		else {
+			sp = p;
+			canreach = 1;
+			if(n->right->left != Z)
+				gen(n->right->left);
+			oldreach = canreach;
+			canreach = 1;
+			if(n->right->right != Z) {
+				gbranch(OGOTO);
+				patch(sp, pc);
+				sp = p;
+				gen(n->right->right);
+			}
+			patch(sp, pc);
+			canreach = canreach || oldreach;
+			if(canreach == 0)
+				warnreach = !suppress;
+		}
+		break;
+
+	case OSET:
+	case OUSED:
+	case OPREFETCH:
+		usedset(n->left, o);
+		break;
+	}
+}
+
+void
+usedset(Node *n, int o)
+{
+	if(n->op == OLIST) {
+		usedset(n->left, o);
+		usedset(n->right, o);
+		return;
+	}
+	complex(n);
+	if(o == OPREFETCH) {
+		gprefetch(n);
+		return;
+	}
+	switch(n->op) {
+	case OADDR:	/* volatile */
+		gins(ANOP, n, Z);
+		break;
+	case ONAME:
+		if(o == OSET)
+			gins(ANOP, Z, n);
+		else
+			gins(ANOP, n, Z);
+		break;
+	}
+}
+
+int
+bcomplex(Node *n, Node *c)
+{
+	Node *b, nod;
+
+	complex(n);
+	if(n->type != T)
+	if(tcompat(n, T, n->type, tnot))
+		n->type = T;
+	if(n->type == T) {
+		gbranch(OGOTO);
+		return 0;
+	}
+	if(c != Z && n->op == OCONST && deadheads(c))
+		return 1;
+	if(typev[n->type->etype] && machcap(Z)) {
+		b = &nod;
+		b->op = ONE;
+		b->left = n;
+		b->right = new(0, Z, Z);
+		*b->right = *nodconst(0);
+		b->right->type = n->type;
+		b->type = types[TLONG];
+		n = b;
+	}
+	bool64(n);
+	boolgen(n, 1, Z);
+	return 0;
+}
diff --git a/src/cmd/cc/pswt.c b/src/cmd/cc/pswt.c
new file mode 100644
index 0000000..bae57c6
--- /dev/null
+++ b/src/cmd/cc/pswt.c
@@ -0,0 +1,140 @@
+// Inferno utils/6c/swt.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/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 "gc.h"
+
+int
+swcmp(const void *a1, const void *a2)
+{
+	C1 *p1, *p2;
+
+	p1 = (C1*)a1;
+	p2 = (C1*)a2;
+	if(p1->val < p2->val)
+		return -1;
+	return p1->val > p2->val;
+}
+
+void
+doswit(Node *n)
+{
+	Case *c;
+	C1 *q, *iq;
+	int32 def, nc, i, isv;
+
+	def = 0;
+	nc = 0;
+	isv = 0;
+	for(c = cases; c->link != C; c = c->link) {
+		if(c->def) {
+			if(def)
+				diag(n, "more than one default in switch");
+			def = c->label;
+			continue;
+		}
+		isv |= c->isv;
+		nc++;
+	}
+	if(isv && !typev[n->type->etype])
+		warn(n, "32-bit switch expression with 64-bit case constant");
+
+	iq = alloc(nc*sizeof(C1));
+	q = iq;
+	for(c = cases; c->link != C; c = c->link) {
+		if(c->def)
+			continue;
+		q->label = c->label;
+		if(isv)
+			q->val = c->val;
+		else
+			q->val = (int32)c->val;	/* cast ensures correct value for 32-bit switch on 64-bit architecture */
+		q++;
+	}
+	qsort(iq, nc, sizeof(C1), swcmp);
+	if(debug['W'])
+	for(i=0; i<nc; i++)
+		print("case %2d: = %.8llux\n", i, (vlong)iq[i].val);
+	for(i=0; i<nc-1; i++)
+		if(iq[i].val == iq[i+1].val)
+			diag(n, "duplicate cases in switch %lld", (vlong)iq[i].val);
+	if(def == 0) {
+		def = breakpc;
+		nbreak++;
+	}
+	swit1(iq, nc, def, n);
+}
+
+void
+newcase(void)
+{
+	Case *c;
+
+	c = alloc(sizeof(*c));
+	c->link = cases;
+	cases = c;
+}
+
+int32
+outlstring(TRune *s, int32 n)
+{
+	char buf[sizeof(TRune)];
+	uint c;
+	int i;
+	int32 r;
+
+	if(suppress)
+		return nstring;
+	while(nstring & (sizeof(TRune)-1))
+		outstring("", 1);
+	r = nstring;
+	while(n > 0) {
+		c = *s++;
+		if(align(0, types[TCHAR], Aarg1, nil)) {
+			for(i = 0; i < sizeof(TRune); i++)
+				buf[i] = c>>(8*(sizeof(TRune) - i - 1));
+		} else {
+			for(i = 0; i < sizeof(TRune); i++)
+				buf[i] = c>>(8*i);
+		}
+		outstring(buf, sizeof(TRune));
+		n -= sizeof(TRune);
+	}
+	return r;
+}
+
+void
+nullwarn(Node *l, Node *r)
+{
+	warn(Z, "result of operation not used");
+	if(l != Z)
+		cgen(l, Z);
+	if(r != Z)
+		cgen(r, Z);
+}
diff --git a/src/cmd/cc/scon.c b/src/cmd/cc/scon.c
new file mode 100644
index 0000000..b0b9097
--- /dev/null
+++ b/src/cmd/cc/scon.c
@@ -0,0 +1,640 @@
+// Inferno utils/cc/scon.c
+// http://code.google.com/p/inferno-os/source/browse/utils/cc/scon.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 "cc.h"
+
+static Node*
+acast(Type *t, Node *n)
+{
+	if(n->type->etype != t->etype || n->op == OBIT) {
+		n = new1(OCAST, n, Z);
+		if(nocast(n->left->type, t))
+			*n = *n->left;
+		n->type = t;
+	}
+	return n;
+}
+
+
+void
+evconst(Node *n)
+{
+	Node *l, *r;
+	int et, isf;
+	vlong v;
+	double d;
+
+	if(n == Z || n->type == T)
+		return;
+
+	et = n->type->etype;
+	isf = typefd[et];
+
+	l = n->left;
+	r = n->right;
+
+	d = 0;
+	v = 0;
+
+	switch(n->op) {
+	default:
+		return;
+
+	case ONEG:
+		if(isf)
+			d = -l->fconst;
+		else
+			v = -l->vconst;
+		break;
+
+	case OCOM:
+		v = ~l->vconst;
+		break;
+
+	case OCAST:
+		if(et == TVOID)
+			return;
+		et = l->type->etype;
+		if(isf) {
+			if(typefd[et])
+				d = l->fconst;
+			else
+				d = l->vconst;
+		} else {
+			if(typefd[et])
+				v = l->fconst;
+			else
+				v = convvtox(l->vconst, n->type->etype);
+		}
+		break;
+
+	case OCONST:
+		break;
+
+	case OADD:
+		if(isf)
+			d = l->fconst + r->fconst;
+		else {
+			v = l->vconst + r->vconst;
+		}
+		break;
+
+	case OSUB:
+		if(isf)
+			d = l->fconst - r->fconst;
+		else
+			v = l->vconst - r->vconst;
+		break;
+
+	case OMUL:
+		if(isf)
+			d = l->fconst * r->fconst;
+		else {
+			v = l->vconst * r->vconst;
+		}
+		break;
+
+	case OLMUL:
+		v = (uvlong)l->vconst * (uvlong)r->vconst;
+		break;
+
+
+	case ODIV:
+		if(vconst(r) == 0) {
+			warn(n, "divide by zero");
+			return;
+		}
+		if(isf)
+			d = l->fconst / r->fconst;
+		else
+			v = l->vconst / r->vconst;
+		break;
+
+	case OLDIV:
+		if(vconst(r) == 0) {
+			warn(n, "divide by zero");
+			return;
+		}
+		v = (uvlong)l->vconst / (uvlong)r->vconst;
+		break;
+
+	case OMOD:
+		if(vconst(r) == 0) {
+			warn(n, "modulo by zero");
+			return;
+		}
+		v = l->vconst % r->vconst;
+		break;
+
+	case OLMOD:
+		if(vconst(r) == 0) {
+			warn(n, "modulo by zero");
+			return;
+		}
+		v = (uvlong)l->vconst % (uvlong)r->vconst;
+		break;
+
+	case OAND:
+		v = l->vconst & r->vconst;
+		break;
+
+	case OOR:
+		v = l->vconst | r->vconst;
+		break;
+
+	case OXOR:
+		v = l->vconst ^ r->vconst;
+		break;
+
+	case OLSHR:
+		if(l->type->width != sizeof(uvlong))
+			v = ((uvlong)l->vconst & 0xffffffffULL) >> r->vconst;
+		else
+			v = (uvlong)l->vconst >> r->vconst;
+		break;
+
+	case OASHR:
+		v = l->vconst >> r->vconst;
+		break;
+
+	case OASHL:
+		v = (uvlong)l->vconst << r->vconst;
+		break;
+
+	case OLO:
+		v = (uvlong)l->vconst < (uvlong)r->vconst;
+		break;
+
+	case OLT:
+		if(typefd[l->type->etype])
+			v = l->fconst < r->fconst;
+		else
+			v = l->vconst < r->vconst;
+		break;
+
+	case OHI:
+		v = (uvlong)l->vconst > (uvlong)r->vconst;
+		break;
+
+	case OGT:
+		if(typefd[l->type->etype])
+			v = l->fconst > r->fconst;
+		else
+			v = l->vconst > r->vconst;
+		break;
+
+	case OLS:
+		v = (uvlong)l->vconst <= (uvlong)r->vconst;
+		break;
+
+	case OLE:
+		if(typefd[l->type->etype])
+			v = l->fconst <= r->fconst;
+		else
+			v = l->vconst <= r->vconst;
+		break;
+
+	case OHS:
+		v = (uvlong)l->vconst >= (uvlong)r->vconst;
+		break;
+
+	case OGE:
+		if(typefd[l->type->etype])
+			v = l->fconst >= r->fconst;
+		else
+			v = l->vconst >= r->vconst;
+		break;
+
+	case OEQ:
+		if(typefd[l->type->etype])
+			v = l->fconst == r->fconst;
+		else
+			v = l->vconst == r->vconst;
+		break;
+
+	case ONE:
+		if(typefd[l->type->etype])
+			v = l->fconst != r->fconst;
+		else
+			v = l->vconst != r->vconst;
+		break;
+
+	case ONOT:
+		if(typefd[l->type->etype])
+			v = !l->fconst;
+		else
+			v = !l->vconst;
+		break;
+
+	case OANDAND:
+		if(typefd[l->type->etype])
+			v = l->fconst && r->fconst;
+		else
+			v = l->vconst && r->vconst;
+		break;
+
+	case OOROR:
+		if(typefd[l->type->etype])
+			v = l->fconst || r->fconst;
+		else
+			v = l->vconst || r->vconst;
+		break;
+	}
+	if(isf) {
+		n->fconst = d;
+	} else {
+		n->vconst = convvtox(v, n->type->etype);
+	}
+	n->oldop = n->op;
+	n->op = OCONST;
+}
+
+void
+acom(Node *n)
+{
+	Type *t;
+	Node *l, *r;
+	int i;
+
+	switch(n->op)
+	{
+
+	case ONAME:
+	case OCONST:
+	case OSTRING:
+	case OINDREG:
+	case OREGISTER:
+		return;
+
+	case ONEG:
+		l = n->left;
+		if(addo(n) && addo(l))
+			break;
+		acom(l);
+		return;
+
+	case OADD:
+	case OSUB:
+	case OMUL:
+		l = n->left;
+		r = n->right;
+		if(addo(n)) {
+			if(addo(r))
+				break;
+			if(addo(l))
+				break;
+		}
+		acom(l);
+		acom(r);
+		return;
+
+	default:
+		l = n->left;
+		r = n->right;
+		if(l != Z)
+			acom(l);
+		if(r != Z)
+			acom(r);
+		return;
+	}
+
+	/* bust terms out */
+	t = n->type;
+	term[0].mult = 0;
+	term[0].node = Z;
+	nterm = 1;
+	acom1(1, n);
+	if(debug['m'])
+	for(i=0; i<nterm; i++) {
+		print("%d %3lld ", i, term[i].mult);
+		prtree1(term[i].node, 1, 0);
+	}
+	if(nterm < NTERM)
+		acom2(n, t);
+	n->type = t;
+}
+
+int
+acomcmp1(const void *a1, const void *a2)
+{
+	vlong c1, c2;
+	Term *t1, *t2;
+
+	t1 = (Term*)a1;
+	t2 = (Term*)a2;
+	c1 = t1->mult;
+	if(c1 < 0)
+		c1 = -c1;
+	c2 = t2->mult;
+	if(c2 < 0)
+		c2 = -c2;
+	if(c1 > c2)
+		return 1;
+	if(c1 < c2)
+		return -1;
+	c1 = 1;
+	if(t1->mult < 0)
+		c1 = 0;
+	c2 = 1;
+	if(t2->mult < 0)
+		c2 = 0;
+	if(c2 -= c1)
+		return c2;
+	if(t2 > t1)
+		return 1;
+	return -1;
+}
+
+int
+acomcmp2(const void *a1, const void *a2)
+{
+	vlong c1, c2;
+	Term *t1, *t2;
+
+	t1 = (Term*)a1;
+	t2 = (Term*)a2;
+	c1 = t1->mult;
+	c2 = t2->mult;
+	if(c1 > c2)
+		return 1;
+	if(c1 < c2)
+		return -1;
+	if(t2 > t1)
+		return 1;
+	return -1;
+}
+
+void
+acom2(Node *n, Type *t)
+{
+	Node *l, *r;
+	Term trm[NTERM];
+	int et, nt, i, j;
+	vlong c1, c2;
+
+	/*
+	 * copy into automatic
+	 */
+	c2 = 0;
+	nt = nterm;
+	for(i=0; i<nt; i++)
+		trm[i] = term[i];
+	/*
+	 * recur on subtrees
+	 */
+	j = 0;
+	for(i=1; i<nt; i++) {
+		c1 = trm[i].mult;
+		if(c1 == 0)
+			continue;
+		l = trm[i].node;
+		if(l != Z) {
+			j = 1;
+			acom(l);
+		}
+	}
+	c1 = trm[0].mult;
+	if(j == 0) {
+		n->oldop = n->op;
+		n->op = OCONST;
+		n->vconst = c1;
+		return;
+	}
+	et = t->etype;
+
+	/*
+	 * prepare constant term,
+	 * combine it with an addressing term
+	 */
+	if(c1 != 0) {
+		l = new1(OCONST, Z, Z);
+		l->type = t;
+		l->vconst = c1;
+		trm[0].mult = 1;
+		for(i=1; i<nt; i++) {
+			if(trm[i].mult != 1)
+				continue;
+			r = trm[i].node;
+			if(r->op != OADDR)
+				continue;
+			r->type = t;
+			l = new1(OADD, r, l);
+			l->type = t;
+			trm[i].mult = 0;
+			break;
+		}
+		trm[0].node = l;
+	}
+	/*
+	 * look for factorable terms
+	 * c1*i + c1*c2*j -> c1*(i + c2*j)
+	 */
+	qsort(trm+1, nt-1, sizeof(trm[0]), acomcmp1);
+	for(i=nt-1; i>=0; i--) {
+		c1 = trm[i].mult;
+		if(c1 < 0)
+			c1 = -c1;
+		if(c1 <= 1)
+			continue;
+		for(j=i+1; j<nt; j++) {
+			c2 = trm[j].mult;
+			if(c2 < 0)
+				c2 = -c2;
+			if(c2 <= 1)
+				continue;
+			if(c2 % c1)
+				continue;
+			r = trm[j].node;
+			if(r->type->etype != et)
+				r = acast(t, r);
+			c2 = trm[j].mult/trm[i].mult;
+			if(c2 != 1 && c2 != -1) {
+				r = new1(OMUL, r, new(OCONST, Z, Z));
+				r->type = t;
+				r->right->type = t;
+				r->right->vconst = c2;
+			}
+			l = trm[i].node;
+			if(l->type->etype != et)
+				l = acast(t, l);
+			r = new1(OADD, l, r);
+			r->type = t;
+			if(c2 == -1)
+				r->op = OSUB;
+			trm[i].node = r;
+			trm[j].mult = 0;
+		}
+	}
+	if(debug['m']) {
+		print("\n");
+		for(i=0; i<nt; i++) {
+			print("%d %3lld ", i, trm[i].mult);
+			prtree1(trm[i].node, 1, 0);
+		}
+	}
+
+	/*
+	 * put it all back together
+	 */
+	qsort(trm+1, nt-1, sizeof(trm[0]), acomcmp2);
+	l = Z;
+	for(i=nt-1; i>=0; i--) {
+		c1 = trm[i].mult;
+		if(c1 == 0)
+			continue;
+		r = trm[i].node;
+		if(r->type->etype != et || r->op == OBIT)
+			r = acast(t, r);
+		if(c1 != 1 && c1 != -1) {
+			r = new1(OMUL, r, new(OCONST, Z, Z));
+			r->type = t;
+			r->right->type = t;
+			if(c1 < 0) {
+				r->right->vconst = -c1;
+				c1 = -1;
+			} else {
+				r->right->vconst = c1;
+				c1 = 1;
+			}
+		}
+		if(l == Z) {
+			l = r;
+			c2 = c1;
+			continue;
+		}
+		if(c1 < 0)
+			if(c2 < 0)
+				l = new1(OADD, l, r);
+			else
+				l = new1(OSUB, l, r);
+		else
+			if(c2 < 0) {
+				l = new1(OSUB, r, l);
+				c2 = 1;
+			} else
+				l = new1(OADD, l, r);
+		l->type = t;
+	}
+	if(c2 < 0) {
+		r = new1(OCONST, 0, 0);
+		r->vconst = 0;
+		r->type = t;
+		l = new1(OSUB, r, l);
+		l->type = t;
+	}
+	*n = *l;
+}
+
+void
+acom1(vlong v, Node *n)
+{
+	Node *l, *r;
+
+	if(v == 0 || nterm >= NTERM)
+		return;
+	if(!addo(n)) {
+		if(n->op == OCONST)
+		if(!typefd[n->type->etype]) {
+			term[0].mult += v*n->vconst;
+			return;
+		}
+		term[nterm].mult = v;
+		term[nterm].node = n;
+		nterm++;
+		return;
+	}
+	switch(n->op) {
+
+	case OCAST:
+		acom1(v, n->left);
+		break;
+
+	case ONEG:
+		acom1(-v, n->left);
+		break;
+
+	case OADD:
+		acom1(v, n->left);
+		acom1(v, n->right);
+		break;
+
+	case OSUB:
+		acom1(v, n->left);
+		acom1(-v, n->right);
+		break;
+
+	case OMUL:
+		l = n->left;
+		r = n->right;
+		if(l->op == OCONST)
+		if(!typefd[n->type->etype]) {
+			acom1(v*l->vconst, r);
+			break;
+		}
+		if(r->op == OCONST)
+		if(!typefd[n->type->etype]) {
+			acom1(v*r->vconst, l);
+			break;
+		}
+		break;
+
+	default:
+		diag(n, "not addo");
+	}
+}
+
+int
+addo(Node *n)
+{
+
+	if(n != Z)
+	if(!typefd[n->type->etype])
+	if(!typev[n->type->etype] || ewidth[TVLONG] == ewidth[TIND])
+	switch(n->op) {
+
+	case OCAST:
+		if(nilcast(n->left->type, n->type))
+			return 1;
+		break;
+
+	case ONEG:
+	case OADD:
+	case OSUB:
+		return 1;
+
+	case OMUL:
+		if(n->left->op == OCONST)
+			return 1;
+		if(n->right->op == OCONST)
+			return 1;
+	}
+	return 0;
+}
diff --git a/src/cmd/cc/sub.c b/src/cmd/cc/sub.c
new file mode 100644
index 0000000..94c11d0
--- /dev/null
+++ b/src/cmd/cc/sub.c
@@ -0,0 +1,2068 @@
+// Inferno utils/cc/sub.c
+// http://code.google.com/p/inferno-os/source/browse/utils/cc/sub.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	"cc.h"
+
+Node*
+new(int t, Node *l, Node *r)
+{
+	Node *n;
+
+	n = alloc(sizeof(*n));
+	n->op = t;
+	n->left = l;
+	n->right = r;
+	if(l && t != OGOTO)
+		n->lineno = l->lineno;
+	else if(r)
+		n->lineno = r->lineno;
+	else
+		n->lineno = lineno;
+	newflag = 1;
+	return n;
+}
+
+Node*
+new1(int o, Node *l, Node *r)
+{
+	Node *n;
+
+	n = new(o, l, r);
+	n->lineno = nearln;
+	return n;
+}
+
+void
+prtree(Node *n, char *s)
+{
+
+	print(" == %s ==\n", s);
+	prtree1(n, 0, 0);
+	print("\n");
+}
+
+void
+prtree1(Node *n, int d, int f)
+{
+	int i;
+
+	if(f)
+	for(i=0; i<d; i++)
+		print("   ");
+	if(n == Z) {
+		print("Z\n");
+		return;
+	}
+	if(n->op == OLIST) {
+		prtree1(n->left, d, 0);
+		prtree1(n->right, d, 1);
+		return;
+	}
+	d++;
+	print("%O", n->op);
+	i = 3;
+	switch(n->op)
+	{
+	case ONAME:
+		print(" \"%F\"", n);
+		print(" %d", n->xoffset);
+		i = 0;
+		break;
+
+	case OINDREG:
+		print(" %d(R%d)", n->xoffset, n->reg);
+		i = 0;
+		break;
+
+	case OREGISTER:
+		if(n->xoffset)
+			print(" %d+R%d", n->xoffset, n->reg);
+		else
+			print(" R%d", n->reg);
+		i = 0;
+		break;
+
+	case OSTRING:
+		print(" \"%s\"", n->cstring);
+		i = 0;
+		break;
+
+	case OLSTRING:
+		if(sizeof(TRune) == sizeof(Rune))
+			print(" \"%S\"", (Rune*)n->rstring);
+		else
+			print(" \"...\"");
+		i = 0;
+		break;
+
+	case ODOT:
+	case OELEM:
+		print(" \"%F\"", n);
+		break;
+
+	case OCONST:
+		if(typefd[n->type->etype])
+			print(" \"%.8e\"", n->fconst);
+		else
+			print(" \"%lld\"", n->vconst);
+		i = 0;
+		break;
+	}
+	if(n->addable != 0)
+		print(" <%d>", n->addable);
+	if(n->type != T)
+		print(" %T", n->type);
+	if(n->complex != 0)
+		print(" (%d)", n->complex);
+	print(" %L\n", n->lineno);
+	if(i & 2)
+		prtree1(n->left, d, 1);
+	if(i & 1)
+		prtree1(n->right, d, 1);
+}
+
+Type*
+typ(int et, Type *d)
+{
+	Type *t;
+
+	t = alloc(sizeof(*t));
+	t->etype = et;
+	t->link = d;
+	t->down = T;
+	t->sym = S;
+	if(et < NTYPE)
+		t->width = ewidth[et];
+	else
+		t->width = -1; // for TDOT or TOLD in prototype
+	t->offset = 0;
+	t->shift = 0;
+	t->nbits = 0;
+	t->garb = 0;
+	return t;
+}
+
+Type*
+copytyp(Type *t)
+{
+	Type *nt;
+
+	nt = typ(TXXX, T);
+	*nt = *t;
+	return nt;
+}
+
+Type*
+garbt(Type *t, int32 b)
+{
+	Type *t1;
+
+	if(b & BGARB) {
+		t1 = copytyp(t);
+		t1->garb = simpleg(b);
+		return t1;
+	}
+	return t;
+}
+
+int
+simpleg(int32 b)
+{
+
+	b &= BGARB;
+	switch(b) {
+	case BCONSTNT:
+		return GCONSTNT;
+	case BVOLATILE:
+		return GVOLATILE;
+	case BVOLATILE|BCONSTNT:
+		return GCONSTNT|GVOLATILE;
+	}
+	return GXXX;
+}
+
+int
+simplec(int32 b)
+{
+
+	b &= BCLASS;
+	switch(b) {
+	case 0:
+	case BREGISTER:
+		return CXXX;
+	case BAUTO:
+	case BAUTO|BREGISTER:
+		return CAUTO;
+	case BEXTERN:
+		return CEXTERN;
+	case BEXTERN|BREGISTER:
+		return CEXREG;
+	case BSTATIC:
+		return CSTATIC;
+	case BTYPEDEF:
+		return CTYPEDEF;
+	case BTYPESTR:
+		return CTYPESTR;
+	}
+	diag(Z, "illegal combination of classes %Q", b);
+	return CXXX;
+}
+
+Type*
+simplet(int32 b)
+{
+
+	b &= ~BCLASS & ~BGARB;
+	switch(b) {
+	case BCHAR:
+	case BCHAR|BSIGNED:
+		return types[TCHAR];
+
+	case BCHAR|BUNSIGNED:
+		return types[TUCHAR];
+
+	case BSHORT:
+	case BSHORT|BINT:
+	case BSHORT|BSIGNED:
+	case BSHORT|BINT|BSIGNED:
+		return types[TSHORT];
+
+	case BUNSIGNED|BSHORT:
+	case BUNSIGNED|BSHORT|BINT:
+		return types[TUSHORT];
+
+	case 0:
+	case BINT:
+	case BINT|BSIGNED:
+	case BSIGNED:
+		return types[TINT];
+
+	case BUNSIGNED:
+	case BUNSIGNED|BINT:
+		return types[TUINT];
+
+	case BLONG:
+	case BLONG|BINT:
+	case BLONG|BSIGNED:
+	case BLONG|BINT|BSIGNED:
+		return types[TLONG];
+
+	case BUNSIGNED|BLONG:
+	case BUNSIGNED|BLONG|BINT:
+		return types[TULONG];
+
+	case BVLONG|BLONG:
+	case BVLONG|BLONG|BINT:
+	case BVLONG|BLONG|BSIGNED:
+	case BVLONG|BLONG|BINT|BSIGNED:
+		return types[TVLONG];
+
+	case BVLONG|BLONG|BUNSIGNED:
+	case BVLONG|BLONG|BINT|BUNSIGNED:
+		return types[TUVLONG];
+
+	case BFLOAT:
+		return types[TFLOAT];
+
+	case BDOUBLE:
+	case BDOUBLE|BLONG:
+	case BFLOAT|BLONG:
+		return types[TDOUBLE];
+
+	case BVOID:
+		return types[TVOID];
+	}
+
+	diag(Z, "illegal combination of types %Q", b);
+	return types[TINT];
+}
+
+int
+stcompat(Node *n, Type *t1, Type *t2, int32 ttab[])
+{
+	int i;
+	uint32 b;
+
+	i = 0;
+	if(t2 != T)
+		i = t2->etype;
+	b = 1L << i;
+	i = 0;
+	if(t1 != T)
+		i = t1->etype;
+	if(b & ttab[i]) {
+		if(ttab == tasign)
+			if(b == BSTRUCT || b == BUNION)
+				if(!sametype(t1, t2))
+					return 1;
+		if(n->op != OCAST)
+		 	if(b == BIND && i == TIND)
+				if(!sametype(t1, t2))
+					return 1;
+		return 0;
+	}
+	return 1;
+}
+
+int
+tcompat(Node *n, Type *t1, Type *t2, int32 ttab[])
+{
+
+	if(stcompat(n, t1, t2, ttab)) {
+		if(t1 == T)
+			diag(n, "incompatible type: \"%T\" for op \"%O\"",
+				t2, n->op);
+		else
+			diag(n, "incompatible types: \"%T\" and \"%T\" for op \"%O\"",
+				t1, t2, n->op);
+		return 1;
+	}
+	return 0;
+}
+
+void
+makedot(Node *n, Type *t, int32 o)
+{
+	Node *n1, *n2;
+
+	if(t->nbits) {
+		n1 = new(OXXX, Z, Z);
+		*n1 = *n;
+		n->op = OBIT;
+		n->left = n1;
+		n->right = Z;
+		n->type = t;
+		n->addable = n1->left->addable;
+		n = n1;
+	}
+	n->addable = n->left->addable;
+	if(n->addable == 0) {
+		n1 = new1(OCONST, Z, Z);
+		n1->vconst = o;
+		n1->type = types[TLONG];
+		n->right = n1;
+		n->type = t;
+		return;
+	}
+	n->left->type = t;
+	if(o == 0) {
+		*n = *n->left;
+		return;
+	}
+	n->type = t;
+	n1 = new1(OCONST, Z, Z);
+	n1->vconst = o;
+	t = typ(TIND, t);
+	t->width = types[TIND]->width;
+	n1->type = t;
+
+	n2 = new1(OADDR, n->left, Z);
+	n2->type = t;
+
+	n1 = new1(OADD, n1, n2);
+	n1->type = t;
+
+	n->op = OIND;
+	n->left = n1;
+	n->right = Z;
+}
+
+Type*
+dotsearch(Sym *s, Type *t, Node *n, int32 *off)
+{
+	Type *t1, *xt, *rt;
+
+	xt = T;
+
+	/*
+	 * look it up by name
+	 */
+	for(t1 = t; t1 != T; t1 = t1->down)
+		if(t1->sym == s) {
+			if(xt != T)
+				goto ambig;
+			xt = t1;
+		}
+
+	/*
+	 * look it up by type
+	 */
+	if(s->class == CTYPEDEF || s->class == CTYPESTR)
+		for(t1 = t; t1 != T; t1 = t1->down)
+			if(t1->sym == S && typesu[t1->etype])
+				if(sametype(s->type, t1)) {
+					if(xt != T)
+						goto ambig;
+					xt = t1;
+				}
+	if(xt != T) {
+		*off = xt->offset;
+		return xt;
+	}
+
+	/*
+	 * look it up in unnamed substructures
+	 */
+	for(t1 = t; t1 != T; t1 = t1->down)
+		if(t1->sym == S && typesu[t1->etype]){
+			rt = dotsearch(s, t1->link, n, off);
+			if(rt != T) {
+				if(xt != T)
+					goto ambig;
+				xt = rt;
+				*off += t1->offset;
+			}
+		}
+	return xt;
+
+ambig:
+	diag(n, "ambiguous structure element: %s", s->name);
+	return xt;
+}
+
+int32
+dotoffset(Type *st, Type *lt, Node *n)
+{
+	Type *t;
+	Sym *g;
+	int32 o, o1;
+
+	o = -1;
+	/*
+	 * first try matching at the top level
+	 * for matching tag names
+	 */
+	g = st->tag;
+	if(g != S)
+		for(t=lt->link; t!=T; t=t->down)
+			if(t->sym == S)
+				if(g == t->tag) {
+					if(o >= 0)
+						goto ambig;
+					o = t->offset;
+				}
+	if(o >= 0)
+		return o;
+
+	/*
+	 * second try matching at the top level
+	 * for similar types
+	 */
+	for(t=lt->link; t!=T; t=t->down)
+		if(t->sym == S)
+			if(sametype(st, t)) {
+				if(o >= 0)
+					goto ambig;
+				o = t->offset;
+			}
+	if(o >= 0)
+		return o;
+
+	/*
+	 * last try matching sub-levels
+	 */
+	for(t=lt->link; t!=T; t=t->down)
+		if(t->sym == S)
+		if(typesu[t->etype]) {
+			o1 = dotoffset(st, t, n);
+			if(o1 >= 0) {
+				if(o >= 0)
+					goto ambig;
+				o = o1 + t->offset;
+			}
+		}
+	return o;
+
+ambig:
+	diag(n, "ambiguous unnamed structure element");
+	return o;
+}
+
+/*
+ * look into tree for floating point constant expressions
+ */
+int
+allfloat(Node *n, int flag)
+{
+
+	if(n != Z) {
+		if(n->type->etype != TDOUBLE)
+			return 1;
+		switch(n->op) {
+		case OCONST:
+			if(flag)
+				n->type = types[TFLOAT];
+			return 1;
+		case OADD:	/* no need to get more exotic than this */
+		case OSUB:
+		case OMUL:
+		case ODIV:
+			if(!allfloat(n->right, flag))
+				break;
+		case OCAST:
+			if(!allfloat(n->left, flag))
+				break;
+			if(flag)
+				n->type = types[TFLOAT];
+			return 1;
+		}
+	}
+	return 0;
+}
+
+void
+constas(Node *n, Type *il, Type *ir)
+{
+	Type *l, *r;
+
+	l = il;
+	r = ir;
+
+	if(l == T)
+		return;
+	if(l->garb & GCONSTNT) {
+		warn(n, "assignment to a constant type (%T)", il);
+		return;
+	}
+	if(r == T)
+		return;
+	for(;;) {
+		if(l->etype != TIND || r->etype != TIND)
+			break;
+		l = l->link;
+		r = r->link;
+		if(l == T || r == T)
+			break;
+		if(r->garb & GCONSTNT)
+			if(!(l->garb & GCONSTNT)) {
+				warn(n, "assignment of a constant pointer type (%T)", ir);
+				break;
+			}
+	}
+}
+
+void
+typeext1(Type *st, Node *l)
+{
+	if(st->etype == TFLOAT && allfloat(l, 0))
+		allfloat(l, 1);
+}
+
+void
+typeext(Type *st, Node *l)
+{
+	Type *lt;
+	Node *n1, *n2;
+	int32 o;
+
+	lt = l->type;
+	if(lt == T)
+		return;
+	if(st->etype == TIND && vconst(l) == 0) {
+		l->type = st;
+		l->vconst = 0;
+		return;
+	}
+	typeext1(st, l);
+
+	/*
+	 * extension of C
+	 * if assign of struct containing unnamed sub-struct
+	 * to type of sub-struct, insert the DOT.
+	 * if assign of *struct containing unnamed substruct
+	 * to type of *sub-struct, insert the add-offset
+	 */
+	if(typesu[st->etype] && typesu[lt->etype]) {
+		o = dotoffset(st, lt, l);
+		if(o >= 0) {
+			n1 = new1(OXXX, Z, Z);
+			*n1 = *l;
+			l->op = ODOT;
+			l->left = n1;
+			l->right = Z;
+			makedot(l, st, o);
+		}
+		return;
+	}
+	if(st->etype == TIND && typesu[st->link->etype])
+	if(lt->etype == TIND && typesu[lt->link->etype]) {
+		o = dotoffset(st->link, lt->link, l);
+		if(o >= 0) {
+			l->type = st;
+			if(o == 0)
+				return;
+			n1 = new1(OXXX, Z, Z);
+			*n1 = *l;
+			n2 = new1(OCONST, Z, Z);
+			n2->vconst = o;
+			n2->type = st;
+			l->op = OADD;
+			l->left = n1;
+			l->right = n2;
+		}
+		return;
+	}
+}
+
+/*
+ * a cast that generates no code
+ * (same size move)
+ */
+int
+nocast(Type *t1, Type *t2)
+{
+	int i, b;
+
+	if(t1->nbits)
+		return 0;
+	i = 0;
+	if(t2 != T)
+		i = t2->etype;
+	b = 1<<i;
+	i = 0;
+	if(t1 != T)
+		i = t1->etype;
+	if(b & ncast[i])
+		return 1;
+	return 0;
+}
+
+/*
+ * a cast that has a noop semantic
+ * (small to large, convert)
+ */
+int
+nilcast(Type *t1, Type *t2)
+{
+	int et1, et2;
+
+	if(t1 == T)
+		return 0;
+	if(t1->nbits)
+		return 0;
+	if(t2 == T)
+		return 0;
+	et1 = t1->etype;
+	et2 = t2->etype;
+	if(et1 == et2)
+		return 1;
+	if(typefd[et1] && typefd[et2]) {
+		if(ewidth[et1] < ewidth[et2])
+			return 1;
+		return 0;
+	}
+	if(typechlp[et1] && typechlp[et2]) {
+		if(ewidth[et1] < ewidth[et2])
+			return 1;
+		return 0;
+	}
+	return 0;
+}
+
+/*
+ * "the usual arithmetic conversions are performed"
+ */
+void
+arith(Node *n, int f)
+{
+	Type *t1, *t2;
+	int i, j, k;
+	Node *n1;
+	int32 w;
+
+	t1 = n->left->type;
+	if(n->right == Z)
+		t2 = t1;
+	else
+		t2 = n->right->type;
+	i = TXXX;
+	if(t1 != T)
+		i = t1->etype;
+	j = TXXX;
+	if(t2 != T)
+		j = t2->etype;
+	k = tab[i][j];
+	if(k == TIND) {
+		if(i == TIND)
+			n->type = t1;
+		else
+		if(j == TIND)
+			n->type = t2;
+	} else {
+		/* convert up to at least int */
+		if(f == 1)
+		while(k < TINT)
+			k += 2;
+		n->type = types[k];
+	}
+	if(n->op == OSUB)
+	if(i == TIND && j == TIND) {
+		w = n->right->type->link->width;
+		if(w < 1 || n->left->type->link == T || n->left->type->link->width < 1)
+			goto bad;
+		n->type = types[ewidth[TIND] <= ewidth[TLONG]? TLONG: TVLONG];
+		if(0 && ewidth[TIND] > ewidth[TLONG]){
+			n1 = new1(OXXX, Z, Z);
+			*n1 = *n;
+			n->op = OCAST;
+			n->left = n1;
+			n->right = Z;
+			n->type = types[TLONG];
+		}
+		if(w > 1) {
+			n1 = new1(OXXX, Z, Z);
+			*n1 = *n;
+			n->op = ODIV;
+			n->left = n1;
+			n1 = new1(OCONST, Z, Z);
+			n1->vconst = w;
+			n1->type = n->type;
+			n->right = n1;
+			w = vlog(n1);
+			if(w >= 0) {
+				n->op = OASHR;
+				n1->vconst = w;
+			}
+		}
+		return;
+	}
+	if(!sametype(n->type, n->left->type)) {
+		n->left = new1(OCAST, n->left, Z);
+		n->left->type = n->type;
+		if(n->type->etype == TIND) {
+			w = n->type->link->width;
+			if(w < 1) {
+				snap(n->type->link);
+				w = n->type->link->width;
+				if(w < 1)
+					goto bad;
+			}
+			if(w > 1) {
+				n1 = new1(OCONST, Z, Z);
+				n1->vconst = w;
+				n1->type = n->type;
+				n->left = new1(OMUL, n->left, n1);
+				n->left->type = n->type;
+			}
+		}
+	}
+	if(n->right != Z)
+	if(!sametype(n->type, n->right->type)) {
+		n->right = new1(OCAST, n->right, Z);
+		n->right->type = n->type;
+		if(n->type->etype == TIND) {
+			w = n->type->link->width;
+			if(w < 1) {
+				snap(n->type->link);
+				w = n->type->link->width;
+				if(w < 1)
+					goto bad;
+			}
+			if(w != 1) {
+				n1 = new1(OCONST, Z, Z);
+				n1->vconst = w;
+				n1->type = n->type;
+				n->right = new1(OMUL, n->right, n1);
+				n->right->type = n->type;
+			}
+		}
+	}
+	return;
+bad:
+	diag(n, "pointer addition not fully declared: %T", n->type->link);
+}
+
+/*
+ * try to rewrite shift & mask
+ */
+void
+simplifyshift(Node *n)
+{
+	uint32 c3;
+	int o, s1, s2, c1, c2;
+
+	if(!typechlp[n->type->etype])
+		return;
+	switch(n->op) {
+	default:
+		return;
+	case OASHL:
+		s1 = 0;
+		break;
+	case OLSHR:
+		s1 = 1;
+		break;
+	case OASHR:
+		s1 = 2;
+		break;
+	}
+	if(n->right->op != OCONST)
+		return;
+	if(n->left->op != OAND)
+		return;
+	if(n->left->right->op != OCONST)
+		return;
+	switch(n->left->left->op) {
+	default:
+		return;
+	case OASHL:
+		s2 = 0;
+		break;
+	case OLSHR:
+		s2 = 1;
+		break;
+	case OASHR:
+		s2 = 2;
+		break;
+	}
+	if(n->left->left->right->op != OCONST)
+		return;
+
+	c1 = n->right->vconst;
+	c2 = n->left->left->right->vconst;
+	c3 = n->left->right->vconst;
+
+	o = n->op;
+	switch((s1<<3)|s2) {
+	case 000:	/* (((e <<u c2) & c3) <<u c1) */
+		c3 >>= c2;
+		c1 += c2;
+		if(c1 >= 32)
+			break;
+		goto rewrite1;
+
+	case 002:	/* (((e >>s c2) & c3) <<u c1) */
+		if(topbit(c3) >= (32-c2))
+			break;
+	case 001:	/* (((e >>u c2) & c3) <<u c1) */
+		if(c1 > c2) {
+			c3 <<= c2;
+			c1 -= c2;
+			o = OASHL;
+			goto rewrite1;
+		}
+		c3 <<= c1;
+		if(c1 == c2)
+			goto rewrite0;
+		c1 = c2-c1;
+		o = OLSHR;
+		goto rewrite2;
+
+	case 022:	/* (((e >>s c2) & c3) >>s c1) */
+		if(c2 <= 0)
+			break;
+	case 012:	/* (((e >>s c2) & c3) >>u c1) */
+		if(topbit(c3) >= (32-c2))
+			break;
+		goto s11;
+	case 021:	/* (((e >>u c2) & c3) >>s c1) */
+		if(topbit(c3) >= 31 && c2 <= 0)
+			break;
+		goto s11;
+	case 011:	/* (((e >>u c2) & c3) >>u c1) */
+	s11:
+		c3 <<= c2;
+		c1 += c2;
+		if(c1 >= 32)
+			break;
+		o = OLSHR;
+		goto rewrite1;
+
+	case 020:	/* (((e <<u c2) & c3) >>s c1) */
+		if(topbit(c3) >= 31)
+			break;
+	case 010:	/* (((e <<u c2) & c3) >>u c1) */
+		c3 >>= c1;
+		if(c1 == c2)
+			goto rewrite0;
+		if(c1 > c2) {
+			c1 -= c2;
+			goto rewrite2;
+		}
+		c1 = c2 - c1;
+		o = OASHL;
+		goto rewrite2;
+	}
+	return;
+
+rewrite0:	/* get rid of both shifts */
+if(debug['<'])prtree(n, "rewrite0");
+	*n = *n->left;
+	n->left = n->left->left;
+	n->right->vconst = c3;
+	return;
+rewrite1:	/* get rid of lower shift */
+if(debug['<'])prtree(n, "rewrite1");
+	n->left->left = n->left->left->left;
+	n->left->right->vconst = c3;
+	n->right->vconst = c1;
+	n->op = o;
+	return;
+rewrite2:	/* get rid of upper shift */
+if(debug['<'])prtree(n, "rewrite2");
+	*n = *n->left;
+	n->right->vconst = c3;
+	n->left->right->vconst = c1;
+	n->left->op = o;
+}
+
+int
+side(Node *n)
+{
+
+loop:
+	if(n != Z)
+	switch(n->op) {
+	case OCAST:
+	case ONOT:
+	case OADDR:
+	case OIND:
+		n = n->left;
+		goto loop;
+
+	case OCOND:
+		if(side(n->left))
+			break;
+		n = n->right;
+
+	case OEQ:
+	case ONE:
+	case OLT:
+	case OGE:
+	case OGT:
+	case OLE:
+	case OADD:
+	case OSUB:
+	case OMUL:
+	case OLMUL:
+	case ODIV:
+	case OLDIV:
+	case OLSHR:
+	case OASHL:
+	case OASHR:
+	case OAND:
+	case OOR:
+	case OXOR:
+	case OMOD:
+	case OLMOD:
+	case OANDAND:
+	case OOROR:
+	case OCOMMA:
+	case ODOT:
+		if(side(n->left))
+			break;
+		n = n->right;
+		goto loop;
+
+	case OSIGN:
+	case OSIZE:
+	case OCONST:
+	case OSTRING:
+	case OLSTRING:
+	case ONAME:
+		return 0;
+	}
+	return 1;
+}
+
+int
+vconst(Node *n)
+{
+	int i;
+
+	if(n == Z)
+		goto no;
+	if(n->op != OCONST)
+		goto no;
+	if(n->type == T)
+		goto no;
+	switch(n->type->etype)
+	{
+	case TFLOAT:
+	case TDOUBLE:
+		i = 100;
+		if(n->fconst > i || n->fconst < -i)
+			goto no;
+		i = n->fconst;
+		if(i != n->fconst)
+			goto no;
+		return i;
+
+	case TVLONG:
+	case TUVLONG:
+		i = n->vconst;
+		if(i != n->vconst)
+			goto no;
+		return i;
+
+	case TCHAR:
+	case TUCHAR:
+	case TSHORT:
+	case TUSHORT:
+	case TINT:
+	case TUINT:
+	case TLONG:
+	case TULONG:
+	case TIND:
+		i = n->vconst;
+		if(i != n->vconst)
+			goto no;
+		return i;
+	}
+no:
+	return -159;	/* first uninteresting constant */
+}
+
+/*
+ * return log(n) if n is a power of 2 constant
+ */
+int
+xlog2(uvlong v)
+{
+	int s, i;
+	uvlong m;
+
+	s = 0;
+	m = MASK(8*sizeof(uvlong));
+	for(i=32; i; i>>=1) {
+		m >>= i;
+		if(!(v & m)) {
+			v >>= i;
+			s += i;
+		}
+	}
+	if(v == 1)
+		return s;
+	return -1;
+}
+
+int
+vlog(Node *n)
+{
+	if(n->op != OCONST)
+		goto bad;
+	if(typefd[n->type->etype])
+		goto bad;
+
+	return xlog2(n->vconst);
+
+bad:
+	return -1;
+}
+
+int
+topbit(uint32 v)
+{
+	int i;
+
+	for(i = -1; v; i++)
+		v >>= 1;
+	return i;
+}
+
+/*
+ * try to cast a constant down
+ * rather than cast a variable up
+ * example:
+ *	if(c == 'a')
+ */
+void
+relcon(Node *l, Node *r)
+{
+	vlong v;
+
+	if(l->op != OCONST)
+		return;
+	if(r->op != OCAST)
+		return;
+	if(!nilcast(r->left->type, r->type))
+		return;
+	switch(r->type->etype) {
+	default:
+		return;
+	case TCHAR:
+	case TUCHAR:
+	case TSHORT:
+	case TUSHORT:
+		v = convvtox(l->vconst, r->type->etype);
+		if(v != l->vconst)
+			return;
+		break;
+	}
+	l->type = r->left->type;
+	*r = *r->left;
+}
+
+int
+relindex(int o)
+{
+
+	switch(o) {
+	default:
+		diag(Z, "bad in relindex: %O", o);
+	case OEQ: return 0;
+	case ONE: return 1;
+	case OLE: return 2;
+	case OLS: return 3;
+	case OLT: return 4;
+	case OLO: return 5;
+	case OGE: return 6;
+	case OHS: return 7;
+	case OGT: return 8;
+	case OHI: return 9;
+	}
+}
+
+Node*
+invert(Node *n)
+{
+	Node *i;
+
+	if(n == Z || n->op != OLIST)
+		return n;
+	i = n;
+	for(n = n->left; n != Z; n = n->left) {
+		if(n->op != OLIST)
+			break;
+		i->left = n->right;
+		n->right = i;
+		i = n;
+	}
+	i->left = n;
+	return i;
+}
+
+int
+bitno(int32 b)
+{
+	int i;
+
+	for(i=0; i<32; i++)
+		if(b & (1L<<i))
+			return i;
+	diag(Z, "bad in bitno");
+	return 0;
+}
+
+int32
+typebitor(int32 a, int32 b)
+{
+	int32 c;
+
+	c = a | b;
+	if(a & b)
+		if((a & b) == BLONG)
+			c |= BVLONG;		/* long long => vlong */
+		else
+			warn(Z, "once is enough: %Q", a & b);
+	return c;
+}
+
+void
+diag(Node *n, char *fmt, ...)
+{
+	char buf[STRINGSZ];
+	va_list arg;
+
+	va_start(arg, fmt);
+	vseprint(buf, buf+sizeof(buf), fmt, arg);
+	va_end(arg);
+	Bprint(&diagbuf, "%L %s\n", (n==Z)? nearln: n->lineno, buf);
+
+	if(debug['X']){
+		Bflush(&diagbuf);
+		abort();
+	}
+	if(n != Z)
+	if(debug['v'])
+		prtree(n, "diagnostic");
+
+	nerrors++;
+	if(nerrors > 10) {
+		Bprint(&diagbuf, "too many errors\n");
+		errorexit();
+	}
+}
+
+void
+warn(Node *n, char *fmt, ...)
+{
+	char buf[STRINGSZ];
+	va_list arg;
+
+	if(debug['w']) {
+		Bprint(&diagbuf, "warning: ");
+		va_start(arg, fmt);
+		vseprint(buf, buf+sizeof(buf), fmt, arg);
+		va_end(arg);
+		Bprint(&diagbuf, "%L %s\n", (n==Z)? nearln: n->lineno, buf);
+
+		if(n != Z)
+		if(debug['v'])
+			prtree(n, "warning");
+	}
+}
+
+void
+yyerror(char *fmt, ...)
+{
+	char buf[STRINGSZ];
+	va_list arg;
+
+	/*
+	 * hack to intercept message from yaccpar
+	 */
+	if(strcmp(fmt, "syntax error") == 0) {
+		yyerror("syntax error, last name: %s", symb);
+		return;
+	}
+	va_start(arg, fmt);
+	vseprint(buf, buf+sizeof(buf), fmt, arg);
+	va_end(arg);
+	Bprint(&diagbuf, "%L %s\n", lineno, buf);
+	nerrors++;
+	if(nerrors > 10) {
+		Bprint(&diagbuf, "too many errors\n");
+		errorexit();
+	}
+}
+
+void
+fatal(Node *n, char *fmt, ...)
+{
+	char buf[STRINGSZ];
+	va_list arg;
+
+	va_start(arg, fmt);
+	vseprint(buf, buf+sizeof(buf), fmt, arg);
+	va_end(arg);
+	Bprint(&diagbuf, "%L %s\n", (n==Z)? nearln: n->lineno, buf);
+
+	if(debug['X']){
+		Bflush(&diagbuf);
+		abort();
+	}
+	if(n != Z)
+	if(debug['v'])
+		prtree(n, "diagnostic");
+
+	nerrors++;
+	errorexit();
+}
+
+uint32	thash1	= 0x2edab8c9;
+uint32	thash2	= 0x1dc74fb8;
+uint32	thash3	= 0x1f241331;
+uint32	thash[NALLTYPES];
+Init	thashinit[] =
+{
+	TXXX,		0x17527bbd,	0,
+	TCHAR,		0x5cedd32b,	0,
+	TUCHAR,		0x552c4454,	0,
+	TSHORT,		0x63040b4b,	0,
+	TUSHORT,	0x32a45878,	0,
+	TINT,		0x4151d5bd,	0,
+	TUINT,		0x5ae707d6,	0,
+	TLONG,		0x5ef20f47,	0,
+	TULONG,		0x36d8eb8f,	0,
+	TVLONG,		0x6e5e9590,	0,
+	TUVLONG,	0x75910105,	0,
+	TFLOAT,		0x25fd7af1,	0,
+	TDOUBLE,	0x7c40a1b2,	0,
+	TIND,		0x1b832357,	0,
+	TFUNC,		0x6babc9cb,	0,
+	TARRAY,		0x7c50986d,	0,
+	TVOID,		0x44112eff,	0,
+	TSTRUCT,	0x7c2da3bf,	0,
+	TUNION,		0x3eb25e98,	0,
+	TENUM,		0x44b54f61,	0,
+	TFILE,		0x19242ac3,	0,
+	TOLD,		0x22b15988,	0,
+	TDOT,		0x0204f6b3,	0,
+	-1,		0,		0,
+};
+
+char*	bnames[NALIGN];
+Init	bnamesinit[] =
+{
+	Axxx,	0,	"Axxx",
+	Ael1,	0,	"el1",
+	Ael2,	0,	"el2",
+	Asu2,	0,	"su2",
+	Aarg0,	0,	"arg0",
+	Aarg1,	0,	"arg1",
+	Aarg2,	0,	"arg2",
+	Aaut3,	0,	"aut3",
+	-1,	0,	0,
+};
+
+char*	tnames[NALLTYPES];
+Init	tnamesinit[] =
+{
+	TXXX,		0,	"TXXX",
+	TCHAR,		0,	"CHAR",
+	TUCHAR,		0,	"UCHAR",
+	TSHORT,		0,	"SHORT",
+	TUSHORT,	0,	"USHORT",
+	TINT,		0,	"INT",
+	TUINT,		0,	"UINT",
+	TLONG,		0,	"LONG",
+	TULONG,		0,	"ULONG",
+	TVLONG,		0,	"VLONG",
+	TUVLONG,	0,	"UVLONG",
+	TFLOAT,		0,	"FLOAT",
+	TDOUBLE,	0,	"DOUBLE",
+	TIND,		0,	"IND",
+	TFUNC,		0,	"FUNC",
+	TARRAY,		0,	"ARRAY",
+	TVOID,		0,	"VOID",
+	TSTRUCT,	0,	"STRUCT",
+	TUNION,		0,	"UNION",
+	TENUM,		0,	"ENUM",
+	TFILE,		0,	"FILE",
+	TOLD,		0,	"OLD",
+	TDOT,		0,	"DOT",
+	-1,		0,	0,
+};
+
+char*	gnames[NGTYPES];
+Init	gnamesinit[] =
+{
+	GXXX,			0,	"GXXX",
+	GCONSTNT,		0,	"CONST",
+	GVOLATILE,		0,	"VOLATILE",
+	GVOLATILE|GCONSTNT,	0,	"CONST-VOLATILE",
+	-1,			0,	0,
+};
+
+char*	qnames[NALLTYPES];
+Init	qnamesinit[] =
+{
+	TXXX,		0,	"TXXX",
+	TCHAR,		0,	"CHAR",
+	TUCHAR,		0,	"UCHAR",
+	TSHORT,		0,	"SHORT",
+	TUSHORT,	0,	"USHORT",
+	TINT,		0,	"INT",
+	TUINT,		0,	"UINT",
+	TLONG,		0,	"LONG",
+	TULONG,		0,	"ULONG",
+	TVLONG,		0,	"VLONG",
+	TUVLONG,	0,	"UVLONG",
+	TFLOAT,		0,	"FLOAT",
+	TDOUBLE,	0,	"DOUBLE",
+	TIND,		0,	"IND",
+	TFUNC,		0,	"FUNC",
+	TARRAY,		0,	"ARRAY",
+	TVOID,		0,	"VOID",
+	TSTRUCT,	0,	"STRUCT",
+	TUNION,		0,	"UNION",
+	TENUM,		0,	"ENUM",
+
+	TAUTO,		0,	"AUTO",
+	TEXTERN,	0,	"EXTERN",
+	TSTATIC,	0,	"STATIC",
+	TTYPEDEF,	0,	"TYPEDEF",
+	TTYPESTR,	0,	"TYPESTR",
+	TREGISTER,	0,	"REGISTER",
+	TCONSTNT,	0,	"CONSTNT",
+	TVOLATILE,	0,	"VOLATILE",
+	TUNSIGNED,	0,	"UNSIGNED",
+	TSIGNED,	0,	"SIGNED",
+	TDOT,		0,	"DOT",
+	TFILE,		0,	"FILE",
+	TOLD,		0,	"OLD",
+	-1,		0,	0,
+};
+char*	cnames[NCTYPES];
+Init	cnamesinit[] =
+{
+	CXXX,		0,	"CXXX",
+	CAUTO,		0,	"AUTO",
+	CEXTERN,	0,	"EXTERN",
+	CGLOBL,		0,	"GLOBL",
+	CSTATIC,	0,	"STATIC",
+	CLOCAL,		0,	"LOCAL",
+	CTYPEDEF,	0,	"TYPEDEF",
+	CTYPESTR,	0,	"TYPESTR",
+	CPARAM,		0,	"PARAM",
+	CSELEM,		0,	"SELEM",
+	CLABEL,		0,	"LABEL",
+	CEXREG,		0,	"EXREG",
+	-1,		0,	0,
+};
+
+char*	onames[OEND+1];
+Init	onamesinit[] =
+{
+	OXXX,		0,	"OXXX",
+	OADD,		0,	"ADD",
+	OADDR,		0,	"ADDR",
+	OAND,		0,	"AND",
+	OANDAND,	0,	"ANDAND",
+	OARRAY,		0,	"ARRAY",
+	OAS,		0,	"AS",
+	OASI,		0,	"ASI",
+	OASADD,		0,	"ASADD",
+	OASAND,		0,	"ASAND",
+	OASASHL,	0,	"ASASHL",
+	OASASHR,	0,	"ASASHR",
+	OASDIV,		0,	"ASDIV",
+	OASHL,		0,	"ASHL",
+	OASHR,		0,	"ASHR",
+	OASLDIV,	0,	"ASLDIV",
+	OASLMOD,	0,	"ASLMOD",
+	OASLMUL,	0,	"ASLMUL",
+	OASLSHR,	0,	"ASLSHR",
+	OASMOD,		0,	"ASMOD",
+	OASMUL,		0,	"ASMUL",
+	OASOR,		0,	"ASOR",
+	OASSUB,		0,	"ASSUB",
+	OASXOR,		0,	"ASXOR",
+	OBIT,		0,	"BIT",
+	OBREAK,		0,	"BREAK",
+	OCASE,		0,	"CASE",
+	OCAST,		0,	"CAST",
+	OCOMMA,		0,	"COMMA",
+	OCOND,		0,	"COND",
+	OCONST,		0,	"CONST",
+	OCONTINUE,	0,	"CONTINUE",
+	ODIV,		0,	"DIV",
+	ODOT,		0,	"DOT",
+	ODOTDOT,	0,	"DOTDOT",
+	ODWHILE,	0,	"DWHILE",
+	OENUM,		0,	"ENUM",
+	OEQ,		0,	"EQ",
+	OEXREG,	0,	"EXREG",
+	OFOR,		0,	"FOR",
+	OFUNC,		0,	"FUNC",
+	OGE,		0,	"GE",
+	OGOTO,		0,	"GOTO",
+	OGT,		0,	"GT",
+	OHI,		0,	"HI",
+	OHS,		0,	"HS",
+	OIF,		0,	"IF",
+	OIND,		0,	"IND",
+	OINDREG,	0,	"INDREG",
+	OINIT,		0,	"INIT",
+	OLABEL,		0,	"LABEL",
+	OLDIV,		0,	"LDIV",
+	OLE,		0,	"LE",
+	OLIST,		0,	"LIST",
+	OLMOD,		0,	"LMOD",
+	OLMUL,		0,	"LMUL",
+	OLO,		0,	"LO",
+	OLS,		0,	"LS",
+	OLSHR,		0,	"LSHR",
+	OLT,		0,	"LT",
+	OMOD,		0,	"MOD",
+	OMUL,		0,	"MUL",
+	ONAME,		0,	"NAME",
+	ONE,		0,	"NE",
+	ONOT,		0,	"NOT",
+	OOR,		0,	"OR",
+	OOROR,		0,	"OROR",
+	OPOSTDEC,	0,	"POSTDEC",
+	OPOSTINC,	0,	"POSTINC",
+	OPREDEC,	0,	"PREDEC",
+	OPREINC,	0,	"PREINC",
+	OPREFETCH,		0,	"PREFETCH",
+	OPROTO,		0,	"PROTO",
+	OREGISTER,	0,	"REGISTER",
+	ORETURN,	0,	"RETURN",
+	OSET,		0,	"SET",
+	OSIGN,		0,	"SIGN",
+	OSIZE,		0,	"SIZE",
+	OSTRING,	0,	"STRING",
+	OLSTRING,	0,	"LSTRING",
+	OSTRUCT,	0,	"STRUCT",
+	OSUB,		0,	"SUB",
+	OSWITCH,	0,	"SWITCH",
+	OUNION,		0,	"UNION",
+	OUSED,		0,	"USED",
+	OWHILE,		0,	"WHILE",
+	OXOR,		0,	"XOR",
+	OPOS,		0,	"POS",
+	ONEG,		0,	"NEG",
+	OCOM,		0,	"COM",
+	OELEM,		0,	"ELEM",
+	OTST,		0,	"TST",
+	OINDEX,		0,	"INDEX",
+	OFAS,		0,	"FAS",
+	OREGPAIR,	0,	"REGPAIR",
+	OROTL,		0,	"ROTL",
+	OEND,		0,	"END",
+	-1,		0,	0,
+};
+
+/*	OEQ, ONE, OLE, OLS, OLT, OLO, OGE, OHS, OGT, OHI */
+uchar	comrel[12] =
+{
+	ONE, OEQ, OGT, OHI, OGE, OHS, OLT, OLO, OLE, OLS,
+};
+uchar	invrel[12] =
+{
+	OEQ, ONE, OGE, OHS, OGT, OHI, OLE, OLS, OLT, OLO,
+};
+uchar	logrel[12] =
+{
+	OEQ, ONE, OLS, OLS, OLO, OLO, OHS, OHS, OHI, OHI,
+};
+
+uchar	typei[NALLTYPES];
+int	typeiinit[] =
+{
+	TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG, TVLONG, TUVLONG, -1,
+};
+uchar	typeu[NALLTYPES];
+int	typeuinit[] =
+{
+	TUCHAR, TUSHORT, TUINT, TULONG, TUVLONG, TIND, -1,
+};
+
+uchar	typesuv[NALLTYPES];
+int	typesuvinit[] =
+{
+	TVLONG, TUVLONG, TSTRUCT, TUNION, -1,
+};
+
+uchar	typeilp[NALLTYPES];
+int	typeilpinit[] =
+{
+	TINT, TUINT, TLONG, TULONG, TIND, -1
+};
+
+uchar	typechl[NALLTYPES];
+uchar	typechlv[NALLTYPES];
+uchar	typechlvp[NALLTYPES];
+int	typechlinit[] =
+{
+	TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG, -1,
+};
+
+uchar	typechlp[NALLTYPES];
+int	typechlpinit[] =
+{
+	TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG, TIND, -1,
+};
+
+uchar	typechlpfd[NALLTYPES];
+int	typechlpfdinit[] =
+{
+	TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG, TFLOAT, TDOUBLE, TIND, -1,
+};
+
+uchar	typec[NALLTYPES];
+int	typecinit[] =
+{
+	TCHAR, TUCHAR, -1
+};
+
+uchar	typeh[NALLTYPES];
+int	typehinit[] =
+{
+	TSHORT, TUSHORT, -1,
+};
+
+uchar	typeil[NALLTYPES];
+int	typeilinit[] =
+{
+	TINT, TUINT, TLONG, TULONG, -1,
+};
+
+uchar	typev[NALLTYPES];
+int	typevinit[] =
+{
+	TVLONG,	TUVLONG, -1,
+};
+
+uchar	typefd[NALLTYPES];
+int	typefdinit[] =
+{
+	TFLOAT, TDOUBLE, -1,
+};
+
+uchar	typeaf[NALLTYPES];
+int	typeafinit[] =
+{
+	TFUNC, TARRAY, -1,
+};
+
+uchar	typesu[NALLTYPES];
+int	typesuinit[] =
+{
+	TSTRUCT, TUNION, -1,
+};
+
+int32	tasign[NALLTYPES];
+Init	tasigninit[] =
+{
+	TCHAR,		BNUMBER,	0,
+	TUCHAR,		BNUMBER,	0,
+	TSHORT,		BNUMBER,	0,
+	TUSHORT,	BNUMBER,	0,
+	TINT,		BNUMBER,	0,
+	TUINT,		BNUMBER,	0,
+	TLONG,		BNUMBER,	0,
+	TULONG,		BNUMBER,	0,
+	TVLONG,		BNUMBER,	0,
+	TUVLONG,	BNUMBER,	0,
+	TFLOAT,		BNUMBER,	0,
+	TDOUBLE,	BNUMBER,	0,
+	TIND,		BIND,		0,
+	TSTRUCT,	BSTRUCT,	0,
+	TUNION,		BUNION,		0,
+	-1,		0,		0,
+};
+
+int32	tasadd[NALLTYPES];
+Init	tasaddinit[] =
+{
+	TCHAR,		BNUMBER,	0,
+	TUCHAR,		BNUMBER,	0,
+	TSHORT,		BNUMBER,	0,
+	TUSHORT,	BNUMBER,	0,
+	TINT,		BNUMBER,	0,
+	TUINT,		BNUMBER,	0,
+	TLONG,		BNUMBER,	0,
+	TULONG,		BNUMBER,	0,
+	TVLONG,		BNUMBER,	0,
+	TUVLONG,	BNUMBER,	0,
+	TFLOAT,		BNUMBER,	0,
+	TDOUBLE,	BNUMBER,	0,
+	TIND,		BINTEGER,	0,
+	-1,		0,		0,
+};
+
+int32	tcast[NALLTYPES];
+Init	tcastinit[] =
+{
+	TCHAR,		BNUMBER|BIND|BVOID,	0,
+	TUCHAR,		BNUMBER|BIND|BVOID,	0,
+	TSHORT,		BNUMBER|BIND|BVOID,	0,
+	TUSHORT,	BNUMBER|BIND|BVOID,	0,
+	TINT,		BNUMBER|BIND|BVOID,	0,
+	TUINT,		BNUMBER|BIND|BVOID,	0,
+	TLONG,		BNUMBER|BIND|BVOID,	0,
+	TULONG,		BNUMBER|BIND|BVOID,	0,
+	TVLONG,		BNUMBER|BIND|BVOID,	0,
+	TUVLONG,	BNUMBER|BIND|BVOID,	0,
+	TFLOAT,		BNUMBER|BVOID,		0,
+	TDOUBLE,	BNUMBER|BVOID,		0,
+	TIND,		BINTEGER|BIND|BVOID,	0,
+	TVOID,		BVOID,			0,
+	TSTRUCT,	BSTRUCT|BVOID,		0,
+	TUNION,		BUNION|BVOID,		0,
+	-1,		0,			0,
+};
+
+int32	tadd[NALLTYPES];
+Init	taddinit[] =
+{
+	TCHAR,		BNUMBER|BIND,	0,
+	TUCHAR,		BNUMBER|BIND,	0,
+	TSHORT,		BNUMBER|BIND,	0,
+	TUSHORT,	BNUMBER|BIND,	0,
+	TINT,		BNUMBER|BIND,	0,
+	TUINT,		BNUMBER|BIND,	0,
+	TLONG,		BNUMBER|BIND,	0,
+	TULONG,		BNUMBER|BIND,	0,
+	TVLONG,		BNUMBER|BIND,	0,
+	TUVLONG,	BNUMBER|BIND,	0,
+	TFLOAT,		BNUMBER,	0,
+	TDOUBLE,	BNUMBER,	0,
+	TIND,		BINTEGER,	0,
+	-1,		0,		0,
+};
+
+int32	tsub[NALLTYPES];
+Init	tsubinit[] =
+{
+	TCHAR,		BNUMBER,	0,
+	TUCHAR,		BNUMBER,	0,
+	TSHORT,		BNUMBER,	0,
+	TUSHORT,	BNUMBER,	0,
+	TINT,		BNUMBER,	0,
+	TUINT,		BNUMBER,	0,
+	TLONG,		BNUMBER,	0,
+	TULONG,		BNUMBER,	0,
+	TVLONG,		BNUMBER,	0,
+	TUVLONG,	BNUMBER,	0,
+	TFLOAT,		BNUMBER,	0,
+	TDOUBLE,	BNUMBER,	0,
+	TIND,		BINTEGER|BIND,	0,
+	-1,		0,		0,
+};
+
+int32	tmul[NALLTYPES];
+Init	tmulinit[] =
+{
+	TCHAR,		BNUMBER,	0,
+	TUCHAR,		BNUMBER,	0,
+	TSHORT,		BNUMBER,	0,
+	TUSHORT,	BNUMBER,	0,
+	TINT,		BNUMBER,	0,
+	TUINT,		BNUMBER,	0,
+	TLONG,		BNUMBER,	0,
+	TULONG,		BNUMBER,	0,
+	TVLONG,		BNUMBER,	0,
+	TUVLONG,	BNUMBER,	0,
+	TFLOAT,		BNUMBER,	0,
+	TDOUBLE,	BNUMBER,	0,
+	-1,		0,		0,
+};
+
+int32	tand[NALLTYPES];
+Init	tandinit[] =
+{
+	TCHAR,		BINTEGER,	0,
+	TUCHAR,		BINTEGER,	0,
+	TSHORT,		BINTEGER,	0,
+	TUSHORT,	BINTEGER,	0,
+	TINT,		BNUMBER,	0,
+	TUINT,		BNUMBER,	0,
+	TLONG,		BINTEGER,	0,
+	TULONG,		BINTEGER,	0,
+	TVLONG,		BINTEGER,	0,
+	TUVLONG,	BINTEGER,	0,
+	-1,		0,		0,
+};
+
+int32	trel[NALLTYPES];
+Init	trelinit[] =
+{
+	TCHAR,		BNUMBER,	0,
+	TUCHAR,		BNUMBER,	0,
+	TSHORT,		BNUMBER,	0,
+	TUSHORT,	BNUMBER,	0,
+	TINT,		BNUMBER,	0,
+	TUINT,		BNUMBER,	0,
+	TLONG,		BNUMBER,	0,
+	TULONG,		BNUMBER,	0,
+	TVLONG,		BNUMBER,	0,
+	TUVLONG,	BNUMBER,	0,
+	TFLOAT,		BNUMBER,	0,
+	TDOUBLE,	BNUMBER,	0,
+	TIND,		BIND,		0,
+	-1,		0,		0,
+};
+
+int32	tfunct[1] =
+{
+	BFUNC,
+};
+
+int32	tindir[1] =
+{
+	BIND,
+};
+
+int32	tdot[1] =
+{
+	BSTRUCT|BUNION,
+};
+
+int32	tnot[1] =
+{
+	BNUMBER|BIND,
+};
+
+int32	targ[1] =
+{
+	BNUMBER|BIND|BSTRUCT|BUNION,
+};
+
+uchar	tab[NTYPE][NTYPE] =
+{
+/*TXXX*/	{ 0,
+		},
+
+/*TCHAR*/	{ 0,	TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG,
+			TULONG, TVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
+		},
+/*TUCHAR*/	{ 0,	TUCHAR, TUCHAR, TUSHORT, TUSHORT, TUINT, TUINT, TULONG,
+			TULONG, TUVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
+		},
+/*TSHORT*/	{ 0,	TSHORT, TUSHORT, TSHORT, TUSHORT, TINT, TUINT, TLONG,
+			TULONG, TVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
+		},
+/*TUSHORT*/	{ 0,	TUSHORT, TUSHORT, TUSHORT, TUSHORT, TUINT, TUINT, TULONG,
+			TULONG, TUVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
+		},
+/*TINT*/	{ 0,	TINT, TUINT, TINT, TUINT, TINT, TUINT, TLONG,
+			TULONG, TVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
+		},
+/*TUINT*/	{ 0,	TUINT, TUINT, TUINT, TUINT, TUINT, TUINT, TULONG,
+			TULONG, TUVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
+		},
+/*TLONG*/	{ 0,	TLONG, TULONG, TLONG, TULONG, TLONG, TULONG, TLONG,
+			TULONG, TVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
+		},
+/*TULONG*/	{ 0,	TULONG, TULONG, TULONG, TULONG, TULONG, TULONG, TULONG,
+			TULONG, TUVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
+		},
+/*TVLONG*/	{ 0,	TVLONG, TUVLONG, TVLONG, TUVLONG, TVLONG, TUVLONG, TVLONG,
+			TUVLONG, TVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
+		},
+/*TUVLONG*/	{ 0,	TUVLONG, TUVLONG, TUVLONG, TUVLONG, TUVLONG, TUVLONG, TUVLONG,
+			TUVLONG, TUVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
+		},
+/*TFLOAT*/	{ 0,	TFLOAT, TFLOAT, TFLOAT, TFLOAT, TFLOAT, TFLOAT, TFLOAT,
+			TFLOAT, TFLOAT, TFLOAT, TFLOAT, TDOUBLE, TIND,
+		},
+/*TDOUBLE*/	{ 0,	TDOUBLE, TDOUBLE, TDOUBLE, TDOUBLE, TDOUBLE, TDOUBLE, TDOUBLE,
+			TDOUBLE, TDOUBLE, TDOUBLE, TFLOAT, TDOUBLE, TIND,
+		},
+/*TIND*/	{ 0,	TIND, TIND, TIND, TIND, TIND, TIND, TIND,
+			 TIND, TIND, TIND, TIND, TIND, TIND,
+		},
+};
+
+void
+urk(char *name, int max, int i)
+{
+	if(i >= max) {
+		fprint(2, "bad tinit: %s %d>=%d\n", name, i, max);
+		exits("init");
+	}
+}
+
+void
+tinit(void)
+{
+	int *ip;
+	Init *p;
+
+	for(p=thashinit; p->code >= 0; p++) {
+		urk("thash", nelem(thash), p->code);
+		thash[p->code] = p->value;
+	}
+	for(p=bnamesinit; p->code >= 0; p++) {
+		urk("bnames", nelem(bnames), p->code);
+		bnames[p->code] = p->s;
+	}
+	for(p=tnamesinit; p->code >= 0; p++) {
+		urk("tnames", nelem(tnames), p->code);
+		tnames[p->code] = p->s;
+	}
+	for(p=gnamesinit; p->code >= 0; p++) {
+		urk("gnames", nelem(gnames), p->code);
+		gnames[p->code] = p->s;
+	}
+	for(p=qnamesinit; p->code >= 0; p++) {
+		urk("qnames", nelem(qnames), p->code);
+		qnames[p->code] = p->s;
+	}
+	for(p=cnamesinit; p->code >= 0; p++) {
+		urk("cnames", nelem(cnames), p->code);
+		cnames[p->code] = p->s;
+	}
+	for(p=onamesinit; p->code >= 0; p++) {
+		urk("onames", nelem(onames), p->code);
+		onames[p->code] = p->s;
+	}
+	for(ip=typeiinit; *ip>=0; ip++) {
+		urk("typei", nelem(typei), *ip);
+		typei[*ip] = 1;
+	}
+	for(ip=typeuinit; *ip>=0; ip++) {
+		urk("typeu", nelem(typeu), *ip);
+		typeu[*ip] = 1;
+	}
+	for(ip=typesuvinit; *ip>=0; ip++) {
+		urk("typesuv", nelem(typesuv), *ip);
+		typesuv[*ip] = 1;
+	}
+	for(ip=typeilpinit; *ip>=0; ip++) {
+		urk("typeilp", nelem(typeilp), *ip);
+		typeilp[*ip] = 1;
+	}
+	for(ip=typechlinit; *ip>=0; ip++) {
+		urk("typechl", nelem(typechl), *ip);
+		typechl[*ip] = 1;
+		typechlv[*ip] = 1;
+		typechlvp[*ip] = 1;
+	}
+	for(ip=typechlpinit; *ip>=0; ip++) {
+		urk("typechlp", nelem(typechlp), *ip);
+		typechlp[*ip] = 1;
+		typechlvp[*ip] = 1;
+	}
+	for(ip=typechlpfdinit; *ip>=0; ip++) {
+		urk("typechlpfd", nelem(typechlpfd), *ip);
+		typechlpfd[*ip] = 1;
+	}
+	for(ip=typecinit; *ip>=0; ip++) {
+		urk("typec", nelem(typec), *ip);
+		typec[*ip] = 1;
+	}
+	for(ip=typehinit; *ip>=0; ip++) {
+		urk("typeh", nelem(typeh), *ip);
+		typeh[*ip] = 1;
+	}
+	for(ip=typeilinit; *ip>=0; ip++) {
+		urk("typeil", nelem(typeil), *ip);
+		typeil[*ip] = 1;
+	}
+	for(ip=typevinit; *ip>=0; ip++) {
+		urk("typev", nelem(typev), *ip);
+		typev[*ip] = 1;
+		typechlv[*ip] = 1;
+		typechlvp[*ip] = 1;
+	}
+	for(ip=typefdinit; *ip>=0; ip++) {
+		urk("typefd", nelem(typefd), *ip);
+		typefd[*ip] = 1;
+	}
+	for(ip=typeafinit; *ip>=0; ip++) {
+		urk("typeaf", nelem(typeaf), *ip);
+		typeaf[*ip] = 1;
+	}
+	for(ip=typesuinit; *ip >= 0; ip++) {
+		urk("typesu", nelem(typesu), *ip);
+		typesu[*ip] = 1;
+	}
+	for(p=tasigninit; p->code >= 0; p++) {
+		urk("tasign", nelem(tasign), p->code);
+		tasign[p->code] = p->value;
+	}
+	for(p=tasaddinit; p->code >= 0; p++) {
+		urk("tasadd", nelem(tasadd), p->code);
+		tasadd[p->code] = p->value;
+	}
+	for(p=tcastinit; p->code >= 0; p++) {
+		urk("tcast", nelem(tcast), p->code);
+		tcast[p->code] = p->value;
+	}
+	for(p=taddinit; p->code >= 0; p++) {
+		urk("tadd", nelem(tadd), p->code);
+		tadd[p->code] = p->value;
+	}
+	for(p=tsubinit; p->code >= 0; p++) {
+		urk("tsub", nelem(tsub), p->code);
+		tsub[p->code] = p->value;
+	}
+	for(p=tmulinit; p->code >= 0; p++) {
+		urk("tmul", nelem(tmul), p->code);
+		tmul[p->code] = p->value;
+	}
+	for(p=tandinit; p->code >= 0; p++) {
+		urk("tand", nelem(tand), p->code);
+		tand[p->code] = p->value;
+	}
+	for(p=trelinit; p->code >= 0; p++) {
+		urk("trel", nelem(trel), p->code);
+		trel[p->code] = p->value;
+	}
+	
+	/* 32-bit defaults */
+	typeword = typechlp;
+	typecmplx = typesuv;
+}
+
+/*
+ * return 1 if it is impossible to jump into the middle of n.
+ */
+static int
+deadhead(Node *n, int caseok)
+{
+loop:
+	if(n == Z)
+		return 1;
+	switch(n->op) {
+	case OLIST:
+		if(!deadhead(n->left, caseok))
+			return 0;
+	rloop:
+		n = n->right;
+		goto loop;
+
+	case ORETURN:
+		break;
+
+	case OLABEL:
+		return 0;
+
+	case OGOTO:
+		break;
+
+	case OCASE:
+		if(!caseok)
+			return 0;
+		goto rloop;
+
+	case OSWITCH:
+		return deadhead(n->right, 1);
+
+	case OWHILE:
+	case ODWHILE:
+		goto rloop;
+
+	case OFOR:
+		goto rloop;
+
+	case OCONTINUE:
+		break;
+
+	case OBREAK:
+		break;
+
+	case OIF:
+		return deadhead(n->right->left, caseok) && deadhead(n->right->right, caseok);
+
+	case OSET:
+	case OUSED:
+		break;
+	}
+	return 1;
+}
+
+int
+deadheads(Node *c)
+{
+	return deadhead(c->left, 0) && deadhead(c->right, 0);
+}
+
+int
+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/cc/y.tab.c b/src/cmd/cc/y.tab.c
new file mode 100644
index 0000000..94932ef
--- /dev/null
+++ b/src/cmd/cc/y.tab.c
@@ -0,0 +1,3822 @@
+/* A Bison parser, made by GNU Bison 2.3.  */
+
+/* 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 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, 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
+   under terms of your choice, so long as that work isn't itself a
+   parser generator using the skeleton or a modified version thereof
+   as a parser skeleton.  Alternatively, if you modify or redistribute
+   the parser skeleton itself, you may (at your option) remove this
+   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.  */
+
+/* C LALR(1) parser skeleton written by Richard Stallman, by
+   simplifying the original so-called "semantic" parser.  */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+   infringing on user name space.  This should be done even for local
+   variables, as they might otherwise be expanded by user macros.
+   There are some unavoidable exceptions within include files to
+   define necessary library symbols; they are noted "INFRINGES ON
+   USER NAME SPACE" below.  */
+
+/* Identify Bison output.  */
+#define YYBISON 1
+
+/* Bison version.  */
+#define YYBISON_VERSION "2.3"
+
+/* Skeleton name.  */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers.  */
+#define YYPURE 0
+
+/* Using locations.  */
+#define YYLSP_NEEDED 0
+
+
+
+/* Tokens.  */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+   /* Put the tokens into the symbol table, so that GDB and other debuggers
+      know about them.  */
+   enum yytokentype {
+     LORE = 258,
+     LXORE = 259,
+     LANDE = 260,
+     LLSHE = 261,
+     LRSHE = 262,
+     LMDE = 263,
+     LDVE = 264,
+     LMLE = 265,
+     LME = 266,
+     LPE = 267,
+     LOROR = 268,
+     LANDAND = 269,
+     LNE = 270,
+     LEQ = 271,
+     LGE = 272,
+     LLE = 273,
+     LRSH = 274,
+     LLSH = 275,
+     LMG = 276,
+     LPP = 277,
+     LMM = 278,
+     LNAME = 279,
+     LTYPE = 280,
+     LFCONST = 281,
+     LDCONST = 282,
+     LCONST = 283,
+     LLCONST = 284,
+     LUCONST = 285,
+     LULCONST = 286,
+     LVLCONST = 287,
+     LUVLCONST = 288,
+     LSTRING = 289,
+     LLSTRING = 290,
+     LAUTO = 291,
+     LBREAK = 292,
+     LCASE = 293,
+     LCHAR = 294,
+     LCONTINUE = 295,
+     LDEFAULT = 296,
+     LDO = 297,
+     LDOUBLE = 298,
+     LELSE = 299,
+     LEXTERN = 300,
+     LFLOAT = 301,
+     LFOR = 302,
+     LGOTO = 303,
+     LIF = 304,
+     LINT = 305,
+     LLONG = 306,
+     LPREFETCH = 307,
+     LREGISTER = 308,
+     LRETURN = 309,
+     LSHORT = 310,
+     LSIZEOF = 311,
+     LUSED = 312,
+     LSTATIC = 313,
+     LSTRUCT = 314,
+     LSWITCH = 315,
+     LTYPEDEF = 316,
+     LTYPESTR = 317,
+     LUNION = 318,
+     LUNSIGNED = 319,
+     LWHILE = 320,
+     LVOID = 321,
+     LENUM = 322,
+     LSIGNED = 323,
+     LCONSTNT = 324,
+     LVOLATILE = 325,
+     LSET = 326,
+     LSIGNOF = 327,
+     LRESTRICT = 328,
+     LINLINE = 329
+   };
+#endif
+/* Tokens.  */
+#define LORE 258
+#define LXORE 259
+#define LANDE 260
+#define LLSHE 261
+#define LRSHE 262
+#define LMDE 263
+#define LDVE 264
+#define LMLE 265
+#define LME 266
+#define LPE 267
+#define LOROR 268
+#define LANDAND 269
+#define LNE 270
+#define LEQ 271
+#define LGE 272
+#define LLE 273
+#define LRSH 274
+#define LLSH 275
+#define LMG 276
+#define LPP 277
+#define LMM 278
+#define LNAME 279
+#define LTYPE 280
+#define LFCONST 281
+#define LDCONST 282
+#define LCONST 283
+#define LLCONST 284
+#define LUCONST 285
+#define LULCONST 286
+#define LVLCONST 287
+#define LUVLCONST 288
+#define LSTRING 289
+#define LLSTRING 290
+#define LAUTO 291
+#define LBREAK 292
+#define LCASE 293
+#define LCHAR 294
+#define LCONTINUE 295
+#define LDEFAULT 296
+#define LDO 297
+#define LDOUBLE 298
+#define LELSE 299
+#define LEXTERN 300
+#define LFLOAT 301
+#define LFOR 302
+#define LGOTO 303
+#define LIF 304
+#define LINT 305
+#define LLONG 306
+#define LPREFETCH 307
+#define LREGISTER 308
+#define LRETURN 309
+#define LSHORT 310
+#define LSIZEOF 311
+#define LUSED 312
+#define LSTATIC 313
+#define LSTRUCT 314
+#define LSWITCH 315
+#define LTYPEDEF 316
+#define LTYPESTR 317
+#define LUNION 318
+#define LUNSIGNED 319
+#define LWHILE 320
+#define LVOID 321
+#define LENUM 322
+#define LSIGNED 323
+#define LCONSTNT 324
+#define LVOLATILE 325
+#define LSET 326
+#define LSIGNOF 327
+#define LRESTRICT 328
+#define LINLINE 329
+
+
+
+
+/* Copy the first part of user declarations.  */
+#line 31 "cc.y"
+
+#include <u.h>
+#include <stdio.h>	/* if we don't, bison will, and cc.h re-#defines getc */
+#include "cc.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 36 "cc.y"
+{
+	Node*	node;
+	Sym*	sym;
+	Type*	type;
+	struct
+	{
+		Type*	t;
+		uchar	c;
+	} tycl;
+	struct
+	{
+		Type*	t1;
+		Type*	t2;
+		Type*	t3;
+		uchar	c;
+	} tyty;
+	struct
+	{
+		char*	s;
+		int32	l;
+	} sval;
+	int32	lval;
+	double	dval;
+	vlong	vval;
+}
+/* Line 193 of yacc.c.  */
+#line 276 "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 216 of yacc.c.  */
+#line 289 "y.tab.c"
+
+#ifdef short
+# undef short
+#endif
+
+#ifdef YYTYPE_UINT8
+typedef YYTYPE_UINT8 yytype_uint8;
+#else
+typedef unsigned char yytype_uint8;
+#endif
+
+#ifdef YYTYPE_INT8
+typedef YYTYPE_INT8 yytype_int8;
+#elif (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+typedef signed char yytype_int8;
+#else
+typedef short int yytype_int8;
+#endif
+
+#ifdef YYTYPE_UINT16
+typedef YYTYPE_UINT16 yytype_uint16;
+#else
+typedef unsigned short int yytype_uint16;
+#endif
+
+#ifdef YYTYPE_INT16
+typedef YYTYPE_INT16 yytype_int16;
+#else
+typedef short int yytype_int16;
+#endif
+
+#ifndef YYSIZE_T
+# ifdef __SIZE_TYPE__
+#  define YYSIZE_T __SIZE_TYPE__
+# elif defined size_t
+#  define YYSIZE_T size_t
+# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+#  include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+#  define YYSIZE_T size_t
+# else
+#  define YYSIZE_T unsigned int
+# endif
+#endif
+
+#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
+
+#ifndef YY_
+# if defined YYENABLE_NLS && YYENABLE_NLS
+#  if ENABLE_NLS
+#   include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+#   define YY_(msgid) dgettext ("bison-runtime", msgid)
+#  endif
+# endif
+# ifndef YY_
+#  define YY_(msgid) msgid
+# endif
+#endif
+
+/* Suppress unused-variable warnings by "using" E.  */
+#if ! defined lint || defined __GNUC__
+# define YYUSE(e) ((void) (e))
+#else
+# define YYUSE(e) /* empty */
+#endif
+
+/* Identity function, used to suppress warnings about constant conditions.  */
+#ifndef lint
+# define YYID(n) (n)
+#else
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static int
+YYID (int i)
+#else
+static int
+YYID (i)
+    int i;
+#endif
+{
+  return i;
+}
+#endif
+
+#if ! defined yyoverflow || YYERROR_VERBOSE
+
+/* The parser invokes alloca or malloc; define the necessary symbols.  */
+
+# ifdef YYSTACK_USE_ALLOCA
+#  if YYSTACK_USE_ALLOCA
+#   ifdef __GNUC__
+#    define YYSTACK_ALLOC __builtin_alloca
+#   elif defined __BUILTIN_VA_ARG_INCR
+#    include <alloca.h> /* INFRINGES ON USER NAME SPACE */
+#   elif defined _AIX
+#    define YYSTACK_ALLOC __alloca
+#   elif defined _MSC_VER
+#    include <malloc.h> /* INFRINGES ON USER NAME SPACE */
+#    define alloca _alloca
+#   else
+#    define YYSTACK_ALLOC alloca
+#    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 _STDLIB_H
+#      define _STDLIB_H 1
+#     endif
+#    endif
+#   endif
+#  endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+   /* Pacify GCC's `empty if-body' warning.  */
+#  define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
+#  ifndef YYSTACK_ALLOC_MAXIMUM
+    /* The OS might guarantee only one guard page at the bottom of the stack,
+       and a page size can be as small as 4096 bytes.  So we cannot safely
+       invoke alloca (N) if N exceeds 4096.  Use a slightly smaller number
+       to allow for a few compiler-allocated temporary stack slots.  */
+#   define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
+#  endif
+# else
+#  define YYSTACK_ALLOC YYMALLOC
+#  define YYSTACK_FREE YYFREE
+#  ifndef YYSTACK_ALLOC_MAXIMUM
+#   define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
+#  endif
+#  if (defined __cplusplus && ! defined _STDLIB_H \
+       && ! ((defined YYMALLOC || defined malloc) \
+	     && (defined YYFREE || defined free)))
+#   include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+#   ifndef _STDLIB_H
+#    define _STDLIB_H 1
+#   endif
+#  endif
+#  ifndef YYMALLOC
+#   define YYMALLOC malloc
+#   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 _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+#   endif
+#  endif
+# endif
+#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
+
+
+#if (! defined yyoverflow \
+     && (! defined __cplusplus \
+	 || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member.  */
+union yyalloc
+{
+  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)
+
+/* The size of an array large to enough to hold all stacks, each with
+   N elements.  */
+# define YYSTACK_BYTES(N) \
+     ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
+      + YYSTACK_GAP_MAXIMUM)
+
+/* Copy COUNT objects from FROM to TO.  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)))
+#  else
+#   define YYCOPY(To, From, Count)		\
+      do					\
+	{					\
+	  YYSIZE_T yyi;				\
+	  for (yyi = 0; yyi < (Count); yyi++)	\
+	    (To)[yyi] = (From)[yyi];		\
+	}					\
+      while (YYID (0))
+#  endif
+# endif
+
+/* 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
+/* YYLAST -- Last index in YYTABLE.  */
+#define YYLAST   1188
+
+/* YYNTOKENS -- Number of terminals.  */
+#define YYNTOKENS  99
+/* YYNNTS -- Number of nonterminals.  */
+#define YYNNTS  75
+/* YYNRULES -- Number of rules.  */
+#define YYNRULES  247
+/* YYNRULES -- Number of states.  */
+#define YYNSTATES  417
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX.  */
+#define YYUNDEFTOK  2
+#define YYMAXUTOK   329
+
+#define YYTRANSLATE(YYX)						\
+  ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX.  */
+static const yytype_uint8 yytranslate[] =
+{
+       0,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,    97,     2,     2,     2,    35,    22,     2,
+      38,    93,    33,    31,     4,    32,    36,    34,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,    17,     3,
+      25,     5,    26,    16,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,    37,     2,    94,    21,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,    95,    20,    96,    98,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     1,     2,     6,     7,
+       8,     9,    10,    11,    12,    13,    14,    15,    18,    19,
+      23,    24,    27,    28,    29,    30,    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
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+   YYRHS.  */
+static const yytype_uint16 yyprhs[] =
+{
+       0,     0,     3,     4,     7,    10,    14,    15,    16,    23,
+      25,    26,    31,    35,    37,    41,    43,    47,    52,    57,
+      60,    64,    66,    67,    72,    76,    77,    82,    84,    88,
+      89,    94,    95,   101,   102,   104,   106,   110,   112,   116,
+     119,   120,   122,   125,   129,   131,   133,   138,   143,   146,
+     150,   154,   156,   160,   164,   167,   170,   173,   177,   179,
+     182,   184,   186,   189,   190,   192,   194,   197,   200,   204,
+     208,   212,   213,   216,   219,   221,   224,   228,   231,   234,
+     237,   239,   242,   244,   247,   250,   251,   254,   260,   268,
+     269,   280,   286,   294,   298,   304,   307,   310,   314,   320,
+     326,   332,   333,   335,   336,   338,   340,   342,   346,   348,
+     352,   356,   360,   364,   368,   372,   376,   380,   384,   388,
+     392,   396,   400,   404,   408,   412,   416,   420,   426,   430,
+     434,   438,   442,   446,   450,   454,   458,   462,   466,   470,
+     472,   478,   486,   488,   491,   494,   497,   500,   503,   506,
+     509,   512,   515,   518,   522,   528,   534,   539,   544,   548,
+     552,   555,   558,   560,   562,   564,   566,   568,   570,   572,
+     574,   576,   578,   580,   582,   585,   587,   590,   591,   593,
+     595,   599,   600,   605,   606,   608,   610,   612,   614,   617,
+     620,   624,   627,   631,   633,   635,   638,   639,   644,   647,
+     650,   651,   656,   659,   662,   663,   664,   672,   673,   679,
+     681,   683,   686,   687,   690,   692,   694,   696,   698,   701,
+     703,   705,   707,   711,   714,   718,   720,   722,   724,   726,
+     728,   730,   732,   734,   736,   738,   740,   742,   744,   746,
+     748,   750,   752,   754,   756,   758,   760,   762
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS.  */
+static const yytype_int16 yyrhs[] =
+{
+     100,     0,    -1,    -1,   100,   101,    -1,   152,     3,    -1,
+     152,   104,     3,    -1,    -1,    -1,   152,   106,   102,   111,
+     103,   129,    -1,   106,    -1,    -1,   106,   105,     5,   123,
+      -1,   104,     4,   104,    -1,   107,    -1,    33,   163,   106,
+      -1,   172,    -1,    38,   106,    93,    -1,   107,    38,   127,
+      93,    -1,   107,    37,   139,    94,    -1,   155,     3,    -1,
+     155,   109,     3,    -1,   106,    -1,    -1,   106,   110,     5,
+     123,    -1,   109,     4,   109,    -1,    -1,   111,   155,   112,
+       3,    -1,   106,    -1,   112,     4,   112,    -1,    -1,   154,
+     114,   116,     3,    -1,    -1,   113,   154,   115,   116,     3,
+      -1,    -1,   117,    -1,   118,    -1,   117,     4,   117,    -1,
+     106,    -1,   172,    17,   140,    -1,    17,   140,    -1,    -1,
+     120,    -1,    33,   163,    -1,    33,   163,   120,    -1,   121,
+      -1,   122,    -1,   121,    38,   127,    93,    -1,   121,    37,
+     139,    94,    -1,    38,    93,    -1,    37,   139,    94,    -1,
+      38,   120,    93,    -1,   142,    -1,    95,   126,    96,    -1,
+      37,   140,    94,    -1,    36,   173,    -1,   124,     5,    -1,
+     123,     4,    -1,   125,   123,     4,    -1,   124,    -1,   125,
+     124,    -1,   125,    -1,   123,    -1,   125,   123,    -1,    -1,
+     128,    -1,   171,    -1,   154,   119,    -1,   154,   106,    -1,
+      36,    36,    36,    -1,   128,     4,   128,    -1,    95,   130,
+      96,    -1,    -1,   130,   108,    -1,   130,   133,    -1,   132,
+      -1,   131,   132,    -1,    56,   142,    17,    -1,    59,    17,
+      -1,    42,    17,    -1,     1,     3,    -1,   135,    -1,   131,
+     135,    -1,   138,    -1,   155,   109,    -1,   138,     3,    -1,
+      -1,   136,   129,    -1,    67,    38,   141,    93,   133,    -1,
+      67,    38,   141,    93,   133,    62,   133,    -1,    -1,   137,
+      65,    38,   134,     3,   138,     3,   138,    93,   133,    -1,
+      83,    38,   141,    93,   133,    -1,    60,   133,    83,    38,
+     141,    93,     3,    -1,    72,   138,     3,    -1,    78,    38,
+     141,    93,   133,    -1,    55,     3,    -1,    58,     3,    -1,
+      66,   173,     3,    -1,    75,    38,   148,    93,     3,    -1,
+      70,    38,   148,    93,     3,    -1,    89,    38,   148,    93,
+       3,    -1,    -1,   141,    -1,    -1,   140,    -1,   142,    -1,
+     142,    -1,   141,     4,   141,    -1,   143,    -1,   142,    33,
+     142,    -1,   142,    34,   142,    -1,   142,    35,   142,    -1,
+     142,    31,   142,    -1,   142,    32,   142,    -1,   142,    29,
+     142,    -1,   142,    30,   142,    -1,   142,    25,   142,    -1,
+     142,    26,   142,    -1,   142,    28,   142,    -1,   142,    27,
+     142,    -1,   142,    24,   142,    -1,   142,    23,   142,    -1,
+     142,    22,   142,    -1,   142,    21,   142,    -1,   142,    20,
+     142,    -1,   142,    19,   142,    -1,   142,    18,   142,    -1,
+     142,    16,   141,    17,   142,    -1,   142,     5,   142,    -1,
+     142,    15,   142,    -1,   142,    14,   142,    -1,   142,    13,
+     142,    -1,   142,    12,   142,    -1,   142,    11,   142,    -1,
+     142,     9,   142,    -1,   142,    10,   142,    -1,   142,     8,
+     142,    -1,   142,     7,   142,    -1,   142,     6,   142,    -1,
+     144,    -1,    38,   154,   119,    93,   143,    -1,    38,   154,
+     119,    93,    95,   126,    96,    -1,   145,    -1,    33,   143,
+      -1,    22,   143,    -1,    31,   143,    -1,    32,   143,    -1,
+      97,   143,    -1,    98,   143,    -1,    40,   143,    -1,    41,
+     143,    -1,    74,   144,    -1,    90,   144,    -1,    38,   141,
+      93,    -1,    74,    38,   154,   119,    93,    -1,    90,    38,
+     154,   119,    93,    -1,   145,    38,   148,    93,    -1,   145,
+      37,   141,    94,    -1,   145,    39,   173,    -1,   145,    36,
+     173,    -1,   145,    40,    -1,   145,    41,    -1,   171,    -1,
+      46,    -1,    47,    -1,    48,    -1,    49,    -1,    45,    -1,
+      44,    -1,    50,    -1,    51,    -1,   146,    -1,   147,    -1,
+      52,    -1,   146,    52,    -1,    53,    -1,   147,    53,    -1,
+      -1,   149,    -1,   142,    -1,   149,     4,   149,    -1,    -1,
+      95,   151,   113,    96,    -1,    -1,   155,    -1,   156,    -1,
+     168,    -1,   165,    -1,   156,   162,    -1,   168,   162,    -1,
+     165,   156,   163,    -1,   165,   168,    -1,   165,   168,   162,
+      -1,   153,    -1,   153,    -1,    77,   173,    -1,    -1,    77,
+     173,   157,   150,    -1,    77,   150,    -1,    81,   173,    -1,
+      -1,    81,   173,   158,   150,    -1,    81,   150,    -1,    85,
+     173,    -1,    -1,    -1,    85,   173,   159,    95,   160,   167,
+      96,    -1,    -1,    85,    95,   161,   167,    96,    -1,    43,
+      -1,   164,    -1,   162,   164,    -1,    -1,   163,   170,    -1,
+     168,    -1,   170,    -1,   169,    -1,   166,    -1,   165,   166,
+      -1,   170,    -1,   169,    -1,    42,    -1,    42,     5,   142,
+      -1,   167,     4,    -1,   167,     4,   167,    -1,    57,    -1,
+      73,    -1,    68,    -1,    69,    -1,    86,    -1,    82,    -1,
+      64,    -1,    61,    -1,    84,    -1,    54,    -1,    76,    -1,
+      63,    -1,    79,    -1,    80,    -1,    71,    -1,    92,    -1,
+      87,    -1,    88,    -1,    91,    -1,    42,    -1,   173,    -1,
+      42,    -1,    43,    -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
+static const yytype_uint16 yyrline[] =
+{
+       0,   101,   101,   102,   108,   112,   114,   128,   113,   143,
+     148,   147,   155,   158,   159,   166,   167,   171,   175,   184,
+     188,   194,   200,   199,   211,   224,   225,   228,   232,   239,
+     238,   244,   243,   250,   254,   257,   261,   264,   269,   273,
+     282,   285,   288,   293,   298,   301,   302,   306,   312,   316,
+     320,   326,   327,   333,   337,   342,   345,   346,   350,   351,
+     357,   358,   359,   365,   368,   375,   376,   381,   386,   390,
+     396,   406,   409,   413,   419,   420,   426,   430,   434,   440,
+     444,   445,   451,   452,   458,   459,   459,   470,   476,   484,
+     484,   495,   499,   503,   508,   522,   526,   530,   534,   538,
+     542,   548,   551,   554,   557,   560,   567,   568,   574,   575,
+     579,   583,   587,   591,   595,   599,   603,   607,   611,   615,
+     619,   623,   627,   631,   635,   639,   643,   647,   651,   655,
+     659,   663,   667,   671,   675,   679,   683,   687,   691,   697,
+     698,   705,   713,   714,   718,   722,   726,   730,   734,   738,
+     742,   746,   750,   756,   760,   766,   772,   780,   784,   789,
+     794,   798,   802,   803,   810,   817,   824,   831,   838,   845,
+     852,   859,   860,   863,   873,   891,   901,   919,   922,   925,
+     926,   933,   932,   955,   959,   962,   967,   972,   978,   986,
+     992,   998,  1004,  1012,  1020,  1027,  1033,  1032,  1044,  1053,
+    1059,  1058,  1070,  1078,  1087,  1091,  1086,  1108,  1107,  1116,
+    1122,  1123,  1129,  1132,  1138,  1139,  1140,  1143,  1144,  1150,
+    1151,  1154,  1158,  1162,  1163,  1166,  1167,  1168,  1169,  1170,
+    1171,  1172,  1173,  1174,  1177,  1178,  1179,  1180,  1181,  1182,
+    1183,  1186,  1187,  1188,  1191,  1206,  1218,  1219
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+   First, the terminals, then, starting at YYNTOKENS, nonterminals.  */
+static const char *const yytname[] =
+{
+  "$end", "error", "$undefined", "';'", "','", "'='", "LORE", "LXORE",
+  "LANDE", "LLSHE", "LRSHE", "LMDE", "LDVE", "LMLE", "LME", "LPE", "'?'",
+  "':'", "LOROR", "LANDAND", "'|'", "'^'", "'&'", "LNE", "LEQ", "'<'",
+  "'>'", "LGE", "LLE", "LRSH", "LLSH", "'+'", "'-'", "'*'", "'/'", "'%'",
+  "'.'", "'['", "'('", "LMG", "LPP", "LMM", "LNAME", "LTYPE", "LFCONST",
+  "LDCONST", "LCONST", "LLCONST", "LUCONST", "LULCONST", "LVLCONST",
+  "LUVLCONST", "LSTRING", "LLSTRING", "LAUTO", "LBREAK", "LCASE", "LCHAR",
+  "LCONTINUE", "LDEFAULT", "LDO", "LDOUBLE", "LELSE", "LEXTERN", "LFLOAT",
+  "LFOR", "LGOTO", "LIF", "LINT", "LLONG", "LPREFETCH", "LREGISTER",
+  "LRETURN", "LSHORT", "LSIZEOF", "LUSED", "LSTATIC", "LSTRUCT", "LSWITCH",
+  "LTYPEDEF", "LTYPESTR", "LUNION", "LUNSIGNED", "LWHILE", "LVOID",
+  "LENUM", "LSIGNED", "LCONSTNT", "LVOLATILE", "LSET", "LSIGNOF",
+  "LRESTRICT", "LINLINE", "')'", "']'", "'{'", "'}'", "'!'", "'~'",
+  "$accept", "prog", "xdecl", "@1", "@2", "xdlist", "@3", "xdecor",
+  "xdecor2", "adecl", "adlist", "@4", "pdecl", "pdlist", "edecl", "@5",
+  "@6", "zedlist", "edlist", "edecor", "abdecor", "abdecor1", "abdecor2",
+  "abdecor3", "init", "qual", "qlist", "ilist", "zarglist", "arglist",
+  "block", "slist", "labels", "label", "stmnt", "forexpr", "ulstmnt", "@7",
+  "@8", "zcexpr", "zexpr", "lexpr", "cexpr", "expr", "xuexpr", "uexpr",
+  "pexpr", "string", "lstring", "zelist", "elist", "sbody", "@9",
+  "zctlist", "types", "tlist", "ctlist", "complex", "@10", "@11", "@12",
+  "@13", "@14", "gctnlist", "zgnlist", "gctname", "gcnlist", "gcname",
+  "enum", "tname", "cname", "gname", "name", "tag", "ltag", 0
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+   token YYLEX-NUM.  */
+static const yytype_uint16 yytoknum[] =
+{
+       0,   256,   257,    59,    44,    61,   258,   259,   260,   261,
+     262,   263,   264,   265,   266,   267,    63,    58,   268,   269,
+     124,    94,    38,   270,   271,    60,    62,   272,   273,   274,
+     275,    43,    45,    42,    47,    37,    46,    91,    40,   276,
+     277,   278,   279,   280,   281,   282,   283,   284,   285,   286,
+     287,   288,   289,   290,   291,   292,   293,   294,   295,   296,
+     297,   298,   299,   300,   301,   302,   303,   304,   305,   306,
+     307,   308,   309,   310,   311,   312,   313,   314,   315,   316,
+     317,   318,   319,   320,   321,   322,   323,   324,   325,   326,
+     327,   328,   329,    41,    93,   123,   125,    33,   126
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
+static const yytype_uint8 yyr1[] =
+{
+       0,    99,   100,   100,   101,   101,   102,   103,   101,   104,
+     105,   104,   104,   106,   106,   107,   107,   107,   107,   108,
+     108,   109,   110,   109,   109,   111,   111,   112,   112,   114,
+     113,   115,   113,   116,   116,   117,   117,   118,   118,   118,
+     119,   119,   120,   120,   120,   121,   121,   121,   122,   122,
+     122,   123,   123,   124,   124,   124,   125,   125,   125,   125,
+     126,   126,   126,   127,   127,   128,   128,   128,   128,   128,
+     129,   130,   130,   130,   131,   131,   132,   132,   132,   133,
+     133,   133,   134,   134,   135,   136,   135,   135,   135,   137,
+     135,   135,   135,   135,   135,   135,   135,   135,   135,   135,
+     135,   138,   138,   139,   139,   140,   141,   141,   142,   142,
+     142,   142,   142,   142,   142,   142,   142,   142,   142,   142,
+     142,   142,   142,   142,   142,   142,   142,   142,   142,   142,
+     142,   142,   142,   142,   142,   142,   142,   142,   142,   143,
+     143,   143,   144,   144,   144,   144,   144,   144,   144,   144,
+     144,   144,   144,   145,   145,   145,   145,   145,   145,   145,
+     145,   145,   145,   145,   145,   145,   145,   145,   145,   145,
+     145,   145,   145,   146,   146,   147,   147,   148,   148,   149,
+     149,   151,   150,   152,   152,   153,   153,   153,   153,   153,
+     153,   153,   153,   154,   155,   156,   157,   156,   156,   156,
+     158,   156,   156,   156,   159,   160,   156,   161,   156,   156,
+     162,   162,   163,   163,   164,   164,   164,   165,   165,   166,
+     166,   167,   167,   167,   167,   168,   168,   168,   168,   168,
+     168,   168,   168,   168,   169,   169,   169,   169,   169,   169,
+     169,   170,   170,   170,   171,   172,   173,   173
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN.  */
+static const yytype_uint8 yyr2[] =
+{
+       0,     2,     0,     2,     2,     3,     0,     0,     6,     1,
+       0,     4,     3,     1,     3,     1,     3,     4,     4,     2,
+       3,     1,     0,     4,     3,     0,     4,     1,     3,     0,
+       4,     0,     5,     0,     1,     1,     3,     1,     3,     2,
+       0,     1,     2,     3,     1,     1,     4,     4,     2,     3,
+       3,     1,     3,     3,     2,     2,     2,     3,     1,     2,
+       1,     1,     2,     0,     1,     1,     2,     2,     3,     3,
+       3,     0,     2,     2,     1,     2,     3,     2,     2,     2,
+       1,     2,     1,     2,     2,     0,     2,     5,     7,     0,
+      10,     5,     7,     3,     5,     2,     2,     3,     5,     5,
+       5,     0,     1,     0,     1,     1,     1,     3,     1,     3,
+       3,     3,     3,     3,     3,     3,     3,     3,     3,     3,
+       3,     3,     3,     3,     3,     3,     3,     5,     3,     3,
+       3,     3,     3,     3,     3,     3,     3,     3,     3,     1,
+       5,     7,     1,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     3,     5,     5,     4,     4,     3,     3,
+       2,     2,     1,     1,     1,     1,     1,     1,     1,     1,
+       1,     1,     1,     1,     2,     1,     2,     0,     1,     1,
+       3,     0,     4,     0,     1,     1,     1,     1,     2,     2,
+       3,     2,     3,     1,     1,     2,     0,     4,     2,     2,
+       0,     4,     2,     2,     0,     0,     7,     0,     5,     1,
+       1,     2,     0,     2,     1,     1,     1,     1,     2,     1,
+       1,     1,     3,     2,     3,     1,     1,     1,     1,     1,
+       1,     1,     1,     1,     1,     1,     1,     1,     1,     1,
+       1,     1,     1,     1,     1,     1,     1,     1
+};
+
+/* 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[] =
+{
+       2,   183,     1,   209,   234,   225,   232,   236,   231,   227,
+     228,   239,   226,   235,     0,   237,   238,     0,   230,   233,
+       0,   229,   241,   242,   243,   240,     3,     0,   194,   184,
+     185,   187,   217,   186,   220,   219,   246,   247,   181,   198,
+     195,   202,   199,   207,   203,     4,   212,     0,     0,     6,
+      13,    15,   245,   188,   210,   214,   216,   215,   212,   218,
+     191,   189,     0,     0,     0,     0,     0,     0,     0,     5,
+       0,    25,     0,   103,    63,   211,   190,   192,     0,   193,
+      29,   197,   201,   221,     0,   205,    14,   213,    16,    12,
+       9,     7,     0,     0,     0,     0,     0,     0,     0,     0,
+     244,   168,   167,   163,   164,   165,   166,   169,   170,   173,
+     175,     0,     0,     0,     0,     0,   104,   105,   108,   139,
+     142,   171,   172,   162,     0,     0,    64,    40,    65,   182,
+      31,    33,     0,   223,   208,     0,     0,     0,     0,    11,
+      51,   144,   145,   146,   143,     0,   106,    40,   149,   150,
+       0,   151,     0,   152,   147,   148,    18,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,   177,
+       0,   160,   161,   174,   176,     0,    17,     0,   212,   103,
+       0,    67,    66,    41,    44,    45,    33,     0,    37,     0,
+      34,    35,    15,   222,   224,     0,    71,     8,    27,     0,
+       0,     0,    61,    58,    60,     0,     0,   153,   212,     0,
+       0,    40,    40,   128,   138,   137,   136,   134,   135,   133,
+     132,   131,   130,   129,     0,   126,   125,   124,   123,   122,
+     121,   120,   116,   117,   119,   118,   114,   115,   112,   113,
+     109,   110,   111,   159,     0,   179,     0,   178,   158,    68,
+      69,    42,     0,    48,     0,   103,    63,     0,    39,    30,
+       0,     0,   206,     0,    26,     0,    54,     0,    56,    55,
+      62,    59,    52,   107,    42,     0,     0,     0,     0,   157,
+     156,     0,    43,    49,    50,     0,     0,    32,    36,    38,
+       0,   244,     0,     0,     0,     0,     0,     0,     0,     0,
+     101,     0,     0,     0,     0,    70,    72,    85,    74,    73,
+      80,     0,     0,     0,   102,     0,    28,    53,    57,     0,
+     140,   154,   155,   127,   180,    47,    46,    79,    78,    95,
+       0,    96,    77,     0,     0,     0,   177,     0,   177,     0,
+       0,   177,    75,    81,    86,     0,    84,    19,    21,     0,
+       0,    76,     0,    97,     0,     0,    93,     0,     0,     0,
+       0,   101,     0,    20,     0,   141,     0,     0,     0,     0,
+       0,     0,     0,     0,    82,     0,     0,    24,     0,    87,
+      99,    98,    94,    91,   100,   101,    83,    23,     0,     0,
+       0,    92,    88,   101,     0,     0,    90
+};
+
+/* YYDEFGOTO[NTERM-NUM].  */
+static const yytype_int16 yydefgoto[] =
+{
+      -1,     1,    26,    71,   136,    48,    72,   208,    50,   326,
+     369,   382,    91,   219,    78,   131,   206,   209,   210,   211,
+     202,   203,   204,   205,   222,   223,   224,   225,   125,   126,
+     217,   283,   327,   328,   329,   393,   330,   331,   332,   333,
+     115,   116,   334,   146,   118,   119,   120,   121,   122,   266,
+     267,    39,    62,    27,    79,   127,    29,    30,    63,    64,
+      66,   135,    65,    53,    67,    54,    31,    32,    84,    33,
+      34,    35,   123,    51,    52
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+   STATE-NUM.  */
+#define YYPACT_NINF -331
+static const yytype_int16 yypact[] =
+{
+    -331,   548,  -331,  -331,  -331,  -331,  -331,  -331,  -331,  -331,
+    -331,  -331,  -331,  -331,    -3,  -331,  -331,    -3,  -331,  -331,
+     149,  -331,  -331,  -331,  -331,  -331,  -331,   264,  -331,  -331,
+     965,   929,  -331,   965,  -331,  -331,  -331,  -331,  -331,  -331,
+     -75,  -331,   -72,  -331,   -60,  -331,  -331,   307,    60,   270,
+     156,  -331,  -331,   965,  -331,  -331,  -331,  -331,  -331,  -331,
+     965,   965,   929,   -44,   -44,    29,   -15,   199,   -10,  -331,
+     307,  -331,    83,   756,   849,  -331,   140,   965,   889,  -331,
+    -331,  -331,  -331,    86,    12,  -331,  -331,  -331,  -331,  -331,
+      90,   929,   686,   756,   756,   756,   756,   615,   756,   756,
+    -331,  -331,  -331,  -331,  -331,  -331,  -331,  -331,  -331,  -331,
+    -331,   791,   826,   756,   756,     9,  -331,  1084,  -331,  -331,
+     708,    54,    57,  -331,   110,    56,   152,   310,  -331,  -331,
+    -331,   279,   756,    29,  -331,    29,    63,   307,   165,  -331,
+    1084,  -331,  -331,  -331,  -331,    30,  1084,    44,  -331,  -331,
+     615,  -331,   615,  -331,  -331,  -331,  -331,   756,   756,   756,
+     756,   756,   756,   756,   756,   756,   756,   756,   756,   756,
+     756,   756,   756,   756,   756,   756,   756,   756,   756,   756,
+     756,   756,   756,   756,   756,   756,   756,   157,   756,   756,
+     157,  -331,  -331,  -331,  -331,   115,  -331,   849,  -331,   756,
+     128,  -331,  -331,  -331,   182,  -331,   279,   756,  -331,   164,
+     200,  -331,   208,  1084,  -331,    13,  -331,  -331,  -331,   262,
+     157,   756,   225,   228,   165,    73,   756,  -331,  -331,    -7,
+     150,    44,    44,  1084,  1084,  1084,  1084,  1084,  1084,  1084,
+    1084,  1084,  1084,  1084,    28,   304,  1100,  1115,  1129,  1142,
+    1153,  1153,   433,   433,   433,   433,   333,   333,   265,   265,
+    -331,  -331,  -331,  -331,     8,  1084,   153,   236,  -331,  -331,
+    -331,   147,   158,  -331,   161,   756,   849,   247,  -331,  -331,
+     279,   756,  -331,   341,  -331,   307,  -331,   175,  -331,  -331,
+     254,   228,  -331,  -331,   135,   721,   188,   190,   756,  -331,
+    -331,   756,  -331,  -331,  -331,   191,   211,  -331,  -331,  -331,
+     298,   301,   338,   756,   343,   339,   439,   157,   319,   321,
+     756,   322,   323,   324,   332,  -331,  -331,   509,  -331,  -331,
+    -331,    63,   306,   372,   373,   277,  -331,  -331,  -331,   165,
+    -331,  -331,  -331,   425,  -331,  -331,  -331,  -331,  -331,  -331,
+    1053,  -331,  -331,   293,   375,   756,   756,   400,   756,   756,
+     756,   756,  -331,  -331,  -331,   396,  -331,  -331,   430,   285,
+     377,  -331,   431,  -331,    55,   381,  -331,   382,    62,    64,
+     383,   615,   473,  -331,   307,  -331,   756,   439,   479,   490,
+     439,   439,   493,   497,  -331,   307,   686,  -331,    66,   440,
+    -331,  -331,  -331,  -331,  -331,   756,   499,  -331,   498,   439,
+     504,  -331,  -331,   756,   415,   439,  -331
+};
+
+/* YYPGOTO[NTERM-NUM].  */
+static const yytype_int16 yypgoto[] =
+{
+    -331,  -331,  -331,  -331,  -331,   445,  -331,   -26,  -331,  -331,
+    -330,  -331,  -331,   233,  -331,  -331,  -331,   313,   230,  -331,
+    -132,  -187,  -331,  -331,   -82,   292,  -331,   181,   245,   326,
+     193,  -331,  -331,   198,  -227,  -331,   203,  -331,  -331,  -309,
+    -181,  -183,   -83,   -45,   -38,   243,  -331,  -331,  -331,  -175,
+     226,    10,  -331,  -331,    -1,     0,   -88,   495,  -331,  -331,
+    -331,  -331,  -331,   -14,   -51,   -28,  -331,   501,   -85,   218,
+     231,   -24,   -52,  -127,   -12
+};
+
+/* 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 zero, do what YYDEFACT says.
+   If YYTABLE_NINF, syntax error.  */
+#define YYTABLE_NINF -205
+static const yytype_int16 yytable[] =
+{
+      28,    49,    40,   137,   212,    42,    57,    76,    44,    57,
+     139,   357,   226,   274,   145,   230,   133,   133,   272,    61,
+    -196,    68,   128,  -200,   278,    75,   228,    41,   117,    57,
+     199,   229,   226,    75,   226,  -204,    57,    57,   287,    36,
+      37,    86,   274,    87,    90,   298,    77,   140,   214,    75,
+     215,    38,    87,    57,   397,   141,   142,   143,   144,   226,
+     148,   149,    80,    69,    70,   406,   226,   145,   226,   145,
+     226,    83,   394,    81,    82,   154,   155,   228,   130,   212,
+      85,   199,   229,    88,   302,   244,   273,   213,    92,   353,
+      28,   132,    38,   140,   305,   -10,   410,   147,   309,   296,
+     297,   201,   299,   156,   414,   264,   193,   302,   134,   282,
+     194,   218,   233,   234,   235,   236,   237,   238,   239,   240,
+     241,   242,   243,   227,   245,   246,   247,   248,   249,   250,
+     251,   252,   253,   254,   255,   256,   257,   258,   259,   260,
+     261,   262,   290,   293,   265,   128,   195,   271,   387,   196,
+     231,   269,   232,   212,   117,   390,   197,   391,   216,   408,
+     399,   198,   117,   402,   403,   199,   200,   279,   228,   292,
+      36,    37,   199,   229,    68,   263,   117,   294,   268,   140,
+     198,   375,   412,   377,   199,   200,   380,    93,   416,    36,
+      37,    36,    37,    73,    74,   335,    94,    95,    96,    36,
+      37,   220,   221,    97,   280,    98,    99,   100,   286,   101,
+     102,   103,   104,   105,   106,   107,   108,   109,   110,   275,
+     276,   273,    22,    23,   128,   281,    24,    22,    23,   288,
+     117,    24,    46,   289,    22,    23,   117,    47,    24,   111,
+     301,    36,    37,   295,    43,    86,   300,    87,    55,    60,
+     307,    55,   303,   343,   304,   112,   265,   340,   338,   218,
+     138,    56,   113,   114,    56,   284,   285,    45,   350,   337,
+      87,    55,   374,    -9,    -9,   -10,   378,   379,    55,    55,
+     367,   341,    28,   342,    56,   345,    22,    23,   383,   384,
+      24,    56,    56,   395,   140,    55,   207,    46,   184,   185,
+     186,   347,    47,   398,   346,   354,    36,    37,    56,   368,
+      46,   265,    46,   265,   407,    47,   265,    47,   348,    36,
+      37,    36,    37,   170,   171,   172,   173,   174,   175,   176,
+     177,   178,   179,   180,   181,   182,   183,   184,   185,   186,
+      46,   349,   310,   198,  -101,    47,   351,   199,   200,    36,
+      37,   140,    36,    37,   151,   153,   352,   355,   368,   356,
+     358,   359,   360,    93,   182,   183,   184,   185,   186,   368,
+     361,   365,    94,    95,    96,   366,   372,   226,   373,    97,
+      28,    98,    99,   311,     3,   101,   102,   103,   104,   105,
+     106,   107,   108,   109,   110,     4,   312,   313,     5,   314,
+     315,   316,     6,   376,     7,     8,   -89,   317,   318,     9,
+      10,   319,    11,   320,    12,   111,   321,    13,    14,   322,
+      15,    16,    17,    18,   323,    19,    20,    21,    22,    23,
+     324,   112,    24,    25,   381,   -22,   -85,   325,   113,   114,
+     310,   168,  -101,   169,   170,   171,   172,   173,   174,   175,
+     176,   177,   178,   179,   180,   181,   182,   183,   184,   185,
+     186,    93,   180,   181,   182,   183,   184,   185,   186,   386,
+      94,    95,    96,   385,   388,   389,   392,    97,   396,    98,
+      99,   311,   400,   101,   102,   103,   104,   105,   106,   107,
+     108,   109,   110,   401,   312,   313,   404,   314,   315,   316,
+     405,   411,   409,   384,   -89,   317,   318,   413,   415,   319,
+     308,   320,  -101,   111,   321,    89,   291,   322,   336,   277,
+     370,   306,   323,   270,   364,   362,    58,   344,   324,   112,
+     363,    93,    59,     0,   -85,     0,   113,   114,     0,     0,
+      94,    95,    96,     0,     0,     0,     0,    97,     2,    98,
+      99,   311,     0,   101,   102,   103,   104,   105,   106,   107,
+     108,   109,   110,     0,   312,   313,     0,   314,   315,   316,
+       0,     0,     0,     0,   -89,   317,   318,     0,     0,   319,
+       0,   320,     0,   111,   321,     0,     0,   322,     0,     0,
+       0,     3,   323,     0,     0,     0,     0,     0,   324,   112,
+       0,     0,     4,     0,     0,     5,   113,   114,     0,     6,
+       0,     7,     8,     0,     0,     0,     9,    10,     0,    11,
+       0,    12,     0,     0,    13,    14,     0,    15,    16,    17,
+      18,     0,    19,    20,    21,    22,    23,    93,     0,    24,
+      25,     0,     0,     0,     0,     0,    94,    95,    96,     0,
+       0,     0,     0,    97,     0,    98,    99,   100,     3,   101,
+     102,   103,   104,   105,   106,   107,   108,   109,   110,     4,
+       0,     0,     5,     0,     0,     0,     6,     0,     7,     8,
+       0,     0,     0,     9,    10,     0,    11,     0,    12,   111,
+       0,    13,    14,     0,    15,    16,    17,    18,     0,    19,
+      20,    21,    22,    23,     0,   112,    24,    25,    93,     0,
+       0,     0,   113,   114,     0,     0,     0,    94,    95,    96,
+       0,     0,     0,     0,    97,     0,    98,    99,   100,     0,
+     101,   102,   103,   104,   105,   106,   107,   108,   109,   110,
+       0,     0,     0,    93,   187,   188,   189,   190,   191,   192,
+       0,     0,    94,    95,    96,     0,     0,     0,     0,    97,
+     111,    98,    99,   100,     0,   101,   102,   103,   104,   105,
+     106,   107,   108,   109,   110,     0,   112,     0,    93,     0,
+       0,   138,     0,   113,   114,     0,     0,    94,    95,    96,
+       0,     0,     0,     0,    97,   111,    98,    99,   100,     0,
+     101,   102,   103,   104,   105,   106,   107,   108,   109,   110,
+       0,   112,     0,    93,     0,     0,   339,     0,   113,   114,
+       0,     0,    94,    95,    96,     0,     0,     0,     0,   150,
+     111,    98,    99,   100,     0,   101,   102,   103,   104,   105,
+     106,   107,   108,   109,   110,     0,   112,     0,    93,     0,
+       0,     0,     0,   113,   114,     0,     0,    94,    95,    96,
+       0,     0,     0,     0,   152,   111,    98,    99,   100,     0,
+     101,   102,   103,   104,   105,   106,   107,   108,   109,   110,
+       0,   112,     0,     0,     0,   124,     0,     0,   113,   114,
+       0,   100,     3,     0,     0,     0,     0,     0,     0,     0,
+     111,     0,     0,     4,     0,     0,     5,     0,     0,     0,
+       6,     0,     7,     8,     0,     0,   112,     9,    10,     0,
+      11,     0,    12,   113,   114,    13,    14,     0,    15,    16,
+      17,    18,     3,    19,    20,    21,    22,    23,     0,     0,
+      24,    25,     0,     4,     0,     0,     5,     0,     0,     0,
+       6,     0,     7,     8,     0,     0,     0,     9,    10,     0,
+      11,     0,    12,     0,     0,    13,    14,     0,    15,    16,
+      17,    18,     3,    19,    20,    21,    22,    23,     0,     0,
+      24,    25,     0,     4,     0,   129,     5,     0,     0,     0,
+       6,     0,     7,     8,     0,     0,     0,     9,    10,     0,
+      11,     0,    12,     0,     0,    13,    14,     0,    15,    16,
+      17,    18,     0,    19,    20,    21,    22,    23,     0,     4,
+      24,    25,     5,     0,     0,     0,     6,     0,     7,     8,
+       0,     0,     0,     9,    10,     0,    11,     0,    12,     0,
+       0,    13,     0,     0,    15,    16,     0,    18,     0,    19,
+       0,    21,    22,    23,     0,     0,    24,    25,   157,   158,
+     159,   160,   161,   162,   163,   164,   165,   166,   167,   168,
+     371,   169,   170,   171,   172,   173,   174,   175,   176,   177,
+     178,   179,   180,   181,   182,   183,   184,   185,   186,   157,
+     158,   159,   160,   161,   162,   163,   164,   165,   166,   167,
+     168,     0,   169,   170,   171,   172,   173,   174,   175,   176,
+     177,   178,   179,   180,   181,   182,   183,   184,   185,   186,
+     171,   172,   173,   174,   175,   176,   177,   178,   179,   180,
+     181,   182,   183,   184,   185,   186,   172,   173,   174,   175,
+     176,   177,   178,   179,   180,   181,   182,   183,   184,   185,
+     186,   173,   174,   175,   176,   177,   178,   179,   180,   181,
+     182,   183,   184,   185,   186,   174,   175,   176,   177,   178,
+     179,   180,   181,   182,   183,   184,   185,   186,   176,   177,
+     178,   179,   180,   181,   182,   183,   184,   185,   186
+};
+
+static const yytype_int16 yycheck[] =
+{
+       1,    27,    14,    91,   131,    17,    30,    58,    20,    33,
+      92,   320,     4,   200,    97,   147,     4,     4,   199,    33,
+      95,    47,    74,    95,   207,    53,    33,    17,    73,    53,
+      37,    38,     4,    61,     4,    95,    60,    61,   221,    42,
+      43,    67,   229,    67,    70,    17,    60,    92,   133,    77,
+     135,    95,    76,    77,   384,    93,    94,    95,    96,     4,
+      98,    99,    62,     3,     4,   395,     4,   150,     4,   152,
+       4,    42,   381,    63,    64,   113,   114,    33,    78,   206,
+      95,    37,    38,    93,   271,   168,    93,   132,     5,   316,
+      91,     5,    95,   138,   275,     5,   405,    97,   281,   231,
+     232,   127,    94,    94,   413,   188,    52,   294,    96,    96,
+      53,   137,   157,   158,   159,   160,   161,   162,   163,   164,
+     165,   166,   167,    93,   169,   170,   171,   172,   173,   174,
+     175,   176,   177,   178,   179,   180,   181,   182,   183,   184,
+     185,   186,   224,   226,   189,   197,    36,   198,    93,    93,
+     150,    36,   152,   280,   199,    93,     4,    93,    95,    93,
+     387,    33,   207,   390,   391,    37,    38,     3,    33,    96,
+      42,    43,    37,    38,   200,   187,   221,   228,   190,   224,
+      33,   356,   409,   358,    37,    38,   361,    22,   415,    42,
+      43,    42,    43,    37,    38,   283,    31,    32,    33,    42,
+      43,    36,    37,    38,     4,    40,    41,    42,   220,    44,
+      45,    46,    47,    48,    49,    50,    51,    52,    53,    37,
+      38,    93,    87,    88,   276,    17,    91,    87,    88,     4,
+     275,    91,    33,     5,    87,    88,   281,    38,    91,    74,
+       4,    42,    43,    93,    95,   271,    93,   271,    30,    31,
+       3,    33,    94,   298,    93,    90,   301,   295,     4,   285,
+      95,    30,    97,    98,    33,     3,     4,     3,   313,    94,
+     294,    53,   355,     3,     4,     5,   359,   360,    60,    61,
+       3,    93,   283,    93,    53,    94,    87,    88,     3,     4,
+      91,    60,    61,   381,   339,    77,    17,    33,    33,    34,
+      35,     3,    38,   386,    93,   317,    42,    43,    77,   335,
+      33,   356,    33,   358,   396,    38,   361,    38,    17,    42,
+      43,    42,    43,    19,    20,    21,    22,    23,    24,    25,
+      26,    27,    28,    29,    30,    31,    32,    33,    34,    35,
+      33,     3,     1,    33,     3,    38,     3,    37,    38,    42,
+      43,   396,    42,    43,   111,   112,    17,    38,   384,    38,
+      38,    38,    38,    22,    31,    32,    33,    34,    35,   395,
+      38,    65,    31,    32,    33,     3,    83,     4,     3,    38,
+     381,    40,    41,    42,    43,    44,    45,    46,    47,    48,
+      49,    50,    51,    52,    53,    54,    55,    56,    57,    58,
+      59,    60,    61,     3,    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,    38,     5,    95,    96,    97,    98,
+       1,    16,     3,    18,    19,    20,    21,    22,    23,    24,
+      25,    26,    27,    28,    29,    30,    31,    32,    33,    34,
+      35,    22,    29,    30,    31,    32,    33,    34,    35,    38,
+      31,    32,    33,    96,    93,    93,    93,    38,     5,    40,
+      41,    42,     3,    44,    45,    46,    47,    48,    49,    50,
+      51,    52,    53,     3,    55,    56,     3,    58,    59,    60,
+       3,     3,    62,     4,    65,    66,    67,     3,    93,    70,
+     280,    72,     3,    74,    75,    70,   224,    78,   285,   206,
+     339,   276,    83,   197,   331,   327,    31,   301,    89,    90,
+     327,    22,    31,    -1,    95,    -1,    97,    98,    -1,    -1,
+      31,    32,    33,    -1,    -1,    -1,    -1,    38,     0,    40,
+      41,    42,    -1,    44,    45,    46,    47,    48,    49,    50,
+      51,    52,    53,    -1,    55,    56,    -1,    58,    59,    60,
+      -1,    -1,    -1,    -1,    65,    66,    67,    -1,    -1,    70,
+      -1,    72,    -1,    74,    75,    -1,    -1,    78,    -1,    -1,
+      -1,    43,    83,    -1,    -1,    -1,    -1,    -1,    89,    90,
+      -1,    -1,    54,    -1,    -1,    57,    97,    98,    -1,    61,
+      -1,    63,    64,    -1,    -1,    -1,    68,    69,    -1,    71,
+      -1,    73,    -1,    -1,    76,    77,    -1,    79,    80,    81,
+      82,    -1,    84,    85,    86,    87,    88,    22,    -1,    91,
+      92,    -1,    -1,    -1,    -1,    -1,    31,    32,    33,    -1,
+      -1,    -1,    -1,    38,    -1,    40,    41,    42,    43,    44,
+      45,    46,    47,    48,    49,    50,    51,    52,    53,    54,
+      -1,    -1,    57,    -1,    -1,    -1,    61,    -1,    63,    64,
+      -1,    -1,    -1,    68,    69,    -1,    71,    -1,    73,    74,
+      -1,    76,    77,    -1,    79,    80,    81,    82,    -1,    84,
+      85,    86,    87,    88,    -1,    90,    91,    92,    22,    -1,
+      -1,    -1,    97,    98,    -1,    -1,    -1,    31,    32,    33,
+      -1,    -1,    -1,    -1,    38,    -1,    40,    41,    42,    -1,
+      44,    45,    46,    47,    48,    49,    50,    51,    52,    53,
+      -1,    -1,    -1,    22,    36,    37,    38,    39,    40,    41,
+      -1,    -1,    31,    32,    33,    -1,    -1,    -1,    -1,    38,
+      74,    40,    41,    42,    -1,    44,    45,    46,    47,    48,
+      49,    50,    51,    52,    53,    -1,    90,    -1,    22,    -1,
+      -1,    95,    -1,    97,    98,    -1,    -1,    31,    32,    33,
+      -1,    -1,    -1,    -1,    38,    74,    40,    41,    42,    -1,
+      44,    45,    46,    47,    48,    49,    50,    51,    52,    53,
+      -1,    90,    -1,    22,    -1,    -1,    95,    -1,    97,    98,
+      -1,    -1,    31,    32,    33,    -1,    -1,    -1,    -1,    38,
+      74,    40,    41,    42,    -1,    44,    45,    46,    47,    48,
+      49,    50,    51,    52,    53,    -1,    90,    -1,    22,    -1,
+      -1,    -1,    -1,    97,    98,    -1,    -1,    31,    32,    33,
+      -1,    -1,    -1,    -1,    38,    74,    40,    41,    42,    -1,
+      44,    45,    46,    47,    48,    49,    50,    51,    52,    53,
+      -1,    90,    -1,    -1,    -1,    36,    -1,    -1,    97,    98,
+      -1,    42,    43,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      74,    -1,    -1,    54,    -1,    -1,    57,    -1,    -1,    -1,
+      61,    -1,    63,    64,    -1,    -1,    90,    68,    69,    -1,
+      71,    -1,    73,    97,    98,    76,    77,    -1,    79,    80,
+      81,    82,    43,    84,    85,    86,    87,    88,    -1,    -1,
+      91,    92,    -1,    54,    -1,    -1,    57,    -1,    -1,    -1,
+      61,    -1,    63,    64,    -1,    -1,    -1,    68,    69,    -1,
+      71,    -1,    73,    -1,    -1,    76,    77,    -1,    79,    80,
+      81,    82,    43,    84,    85,    86,    87,    88,    -1,    -1,
+      91,    92,    -1,    54,    -1,    96,    57,    -1,    -1,    -1,
+      61,    -1,    63,    64,    -1,    -1,    -1,    68,    69,    -1,
+      71,    -1,    73,    -1,    -1,    76,    77,    -1,    79,    80,
+      81,    82,    -1,    84,    85,    86,    87,    88,    -1,    54,
+      91,    92,    57,    -1,    -1,    -1,    61,    -1,    63,    64,
+      -1,    -1,    -1,    68,    69,    -1,    71,    -1,    73,    -1,
+      -1,    76,    -1,    -1,    79,    80,    -1,    82,    -1,    84,
+      -1,    86,    87,    88,    -1,    -1,    91,    92,     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,     5,
+       6,     7,     8,     9,    10,    11,    12,    13,    14,    15,
+      16,    -1,    18,    19,    20,    21,    22,    23,    24,    25,
+      26,    27,    28,    29,    30,    31,    32,    33,    34,    35,
+      20,    21,    22,    23,    24,    25,    26,    27,    28,    29,
+      30,    31,    32,    33,    34,    35,    21,    22,    23,    24,
+      25,    26,    27,    28,    29,    30,    31,    32,    33,    34,
+      35,    22,    23,    24,    25,    26,    27,    28,    29,    30,
+      31,    32,    33,    34,    35,    23,    24,    25,    26,    27,
+      28,    29,    30,    31,    32,    33,    34,    35,    25,    26,
+      27,    28,    29,    30,    31,    32,    33,    34,    35
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+   symbol of state STATE-NUM.  */
+static const yytype_uint8 yystos[] =
+{
+       0,   100,     0,    43,    54,    57,    61,    63,    64,    68,
+      69,    71,    73,    76,    77,    79,    80,    81,    82,    84,
+      85,    86,    87,    88,    91,    92,   101,   152,   153,   155,
+     156,   165,   166,   168,   169,   170,    42,    43,    95,   150,
+     173,   150,   173,    95,   173,     3,    33,    38,   104,   106,
+     107,   172,   173,   162,   164,   168,   169,   170,   156,   166,
+     168,   162,   151,   157,   158,   161,   159,   163,   106,     3,
+       4,   102,   105,    37,    38,   164,   163,   162,   113,   153,
+     154,   150,   150,    42,   167,    95,   106,   170,    93,   104,
+     106,   111,     5,    22,    31,    32,    33,    38,    40,    41,
+      42,    44,    45,    46,    47,    48,    49,    50,    51,    52,
+      53,    74,    90,    97,    98,   139,   140,   142,   143,   144,
+     145,   146,   147,   171,    36,   127,   128,   154,   171,    96,
+     154,   114,     5,     4,    96,   160,   103,   155,    95,   123,
+     142,   143,   143,   143,   143,   141,   142,   154,   143,   143,
+      38,   144,    38,   144,   143,   143,    94,     5,     6,     7,
+       8,     9,    10,    11,    12,    13,    14,    15,    16,    18,
+      19,    20,    21,    22,    23,    24,    25,    26,    27,    28,
+      29,    30,    31,    32,    33,    34,    35,    36,    37,    38,
+      39,    40,    41,    52,    53,    36,    93,     4,    33,    37,
+      38,   106,   119,   120,   121,   122,   115,    17,   106,   116,
+     117,   118,   172,   142,   167,   167,    95,   129,   106,   112,
+      36,    37,   123,   124,   125,   126,     4,    93,    33,    38,
+     119,   154,   154,   142,   142,   142,   142,   142,   142,   142,
+     142,   142,   142,   142,   141,   142,   142,   142,   142,   142,
+     142,   142,   142,   142,   142,   142,   142,   142,   142,   142,
+     142,   142,   142,   173,   141,   142,   148,   149,   173,    36,
+     128,   163,   139,    93,   120,    37,    38,   116,   140,     3,
+       4,    17,    96,   130,     3,     4,   173,   140,     4,     5,
+     123,   124,    96,   141,   163,    93,   119,   119,    17,    94,
+      93,     4,   120,    94,    93,   139,   127,     3,   117,   140,
+       1,    42,    55,    56,    58,    59,    60,    66,    67,    70,
+      72,    75,    78,    83,    89,    96,   108,   131,   132,   133,
+     135,   136,   137,   138,   141,   155,   112,    94,     4,    95,
+     143,    93,    93,   142,   149,    94,    93,     3,    17,     3,
+     142,     3,    17,   133,   173,    38,    38,   138,    38,    38,
+      38,    38,   132,   135,   129,    65,     3,     3,   106,   109,
+     126,    17,    83,     3,   141,   148,     3,   148,   141,   141,
+     148,    38,   110,     3,     4,    96,    38,    93,    93,    93,
+      93,    93,    93,   134,   138,   155,     5,   109,   141,   133,
+       3,     3,   133,   133,     3,     3,   109,   123,    93,    62,
+     138,     3,   133,     3,   138,    93,   133
+};
+
+#define yyerrok		(yyerrstatus = 0)
+#define yyclearin	(yychar = YYEMPTY)
+#define YYEMPTY		(-2)
+#define YYEOF		0
+
+#define YYACCEPT	goto yyacceptlab
+#define YYABORT		goto yyabortlab
+#define YYERROR		goto yyerrorlab
+
+
+/* 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.  */
+
+#define YYFAIL		goto yyerrlab
+
+#define YYRECOVERING()  (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value)					\
+do								\
+  if (yychar == YYEMPTY && yylen == 1)				\
+    {								\
+      yychar = (Token);						\
+      yylval = (Value);						\
+      yytoken = YYTRANSLATE (yychar);				\
+      YYPOPSTACK (1);						\
+      goto yybackup;						\
+    }								\
+  else								\
+    {								\
+      yyerror (YY_("syntax error: cannot back up")); \
+      YYERROR;							\
+    }								\
+while (YYID (0))
+
+
+#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
+
+
+/* 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
+# 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
+
+
+/* YYLEX -- calling `yylex' with the right arguments.  */
+
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (YYLEX_PARAM)
+#else
+# define YYLEX yylex ()
+#endif
+
+/* Enable debugging if requested.  */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+#  include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+#  define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args)			\
+do {						\
+  if (yydebug)					\
+    YYFPRINTF Args;				\
+} while (YYID (0))
+
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)			  \
+do {									  \
+  if (yydebug)								  \
+    {									  \
+      YYFPRINTF (stderr, "%s ", Title);					  \
+      yy_symbol_print (stderr,						  \
+		  Type, Value); \
+      YYFPRINTF (stderr, "\n");						  \
+    }									  \
+} while (YYID (0))
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT.  |
+`--------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_value_print (yyoutput, yytype, yyvaluep)
+    FILE *yyoutput;
+    int yytype;
+    YYSTYPE const * const yyvaluep;
+#endif
+{
+  if (!yyvaluep)
+    return;
+# ifdef YYPRINT
+  if (yytype < YYNTOKENS)
+    YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# else
+  YYUSE (yyoutput);
+# endif
+  switch (yytype)
+    {
+      default:
+	break;
+    }
+}
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT.  |
+`--------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_print (yyoutput, yytype, yyvaluep)
+    FILE *yyoutput;
+    int yytype;
+    YYSTYPE const * const yyvaluep;
+#endif
+{
+  if (yytype < YYNTOKENS)
+    YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+  else
+    YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+  yy_symbol_value_print (yyoutput, yytype, yyvaluep);
+  YYFPRINTF (yyoutput, ")");
+}
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included).                                                   |
+`------------------------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_stack_print (yytype_int16 *bottom, yytype_int16 *top)
+#else
+static void
+yy_stack_print (bottom, top)
+    yytype_int16 *bottom;
+    yytype_int16 *top;
+#endif
+{
+  YYFPRINTF (stderr, "Stack now");
+  for (; bottom <= top; ++bottom)
+    YYFPRINTF (stderr, " %d", *bottom);
+  YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top)				\
+do {								\
+  if (yydebug)							\
+    yy_stack_print ((Bottom), (Top));				\
+} while (YYID (0))
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced.  |
+`------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_reduce_print (YYSTYPE *yyvsp, int yyrule)
+#else
+static void
+yy_reduce_print (yyvsp, yyrule)
+    YYSTYPE *yyvsp;
+    int yyrule;
+#endif
+{
+  int yynrhs = yyr2[yyrule];
+  int yyi;
+  unsigned long int yylno = yyrline[yyrule];
+  YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
+	     yyrule - 1, yylno);
+  /* The symbols being reduced.  */
+  for (yyi = 0; yyi < yynrhs; yyi++)
+    {
+      fprintf (stderr, "   $%d = ", yyi + 1);
+      yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
+		       &(yyvsp[(yyi + 1) - (yynrhs)])
+		       		       );
+      fprintf (stderr, "\n");
+    }
+}
+
+# define YY_REDUCE_PRINT(Rule)		\
+do {					\
+  if (yydebug)				\
+    yy_reduce_print (yyvsp, Rule); \
+} while (YYID (0))
+
+/* Nonzero means print parse trace.  It is left uninitialized so that
+   multiple parsers can coexist.  */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks.  */
+#ifndef	YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+   if the built-in stack extension method is used).
+
+   Do not make this value too large; the results are undefined if
+   YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+   evaluated with infinite-precision integer arithmetic.  */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+

+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+#  if defined __GLIBC__ && defined _STRING_H
+#   define yystrlen strlen
+#  else
+/* Return the length of YYSTR.  */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static YYSIZE_T
+yystrlen (const char *yystr)
+#else
+static YYSIZE_T
+yystrlen (yystr)
+    const char *yystr;
+#endif
+{
+  YYSIZE_T yylen;
+  for (yylen = 0; yystr[yylen]; yylen++)
+    continue;
+  return yylen;
+}
+#  endif
+# endif
+
+# ifndef yystpcpy
+#  if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
+#   define yystpcpy stpcpy
+#  else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+   YYDEST.  */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static char *
+yystpcpy (char *yydest, const char *yysrc)
+#else
+static char *
+yystpcpy (yydest, yysrc)
+    char *yydest;
+    const char *yysrc;
+#endif
+{
+  char *yyd = yydest;
+  const char *yys = yysrc;
+
+  while ((*yyd++ = *yys++) != '\0')
+    continue;
+
+  return yyd - 1;
+}
+#  endif
+# endif
+
+# ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+   quotes and backslashes, so that it's suitable for yyerror.  The
+   heuristic is that double-quoting is unnecessary unless the string
+   contains an apostrophe, a comma, or backslash (other than
+   backslash-backslash).  YYSTR is taken from yytname.  If YYRES is
+   null, do not copy; instead, return the length of what the result
+   would have been.  */
+static YYSIZE_T
+yytnamerr (char *yyres, const char *yystr)
+{
+  if (*yystr == '"')
+    {
+      YYSIZE_T yyn = 0;
+      char const *yyp = yystr;
+
+      for (;;)
+	switch (*++yyp)
+	  {
+	  case '\'':
+	  case ',':
+	    goto do_not_strip_quotes;
+
+	  case '\\':
+	    if (*++yyp != '\\')
+	      goto do_not_strip_quotes;
+	    /* Fall through.  */
+	  default:
+	    if (yyres)
+	      yyres[yyn] = *yyp;
+	    yyn++;
+	    break;
+
+	  case '"':
+	    if (yyres)
+	      yyres[yyn] = '\0';
+	    return yyn;
+	  }
+    do_not_strip_quotes: ;
+    }
+
+  if (! yyres)
+    return yystrlen (yystr);
+
+  return yystpcpy (yyres, yystr) - yyres;
+}
+# endif
+
+/* 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)
+{
+  int yyn = yypact[yystate];
+
+  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;
+	  }
+
+      yyf = YY_(yyformat);
+      yysize1 = yysize + yystrlen (yyf);
+      yysize_overflow |= (yysize1 < yysize);
+      yysize = yysize1;
+
+      if (yysize_overflow)
+	return YYSIZE_MAXIMUM;
+
+      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.  |
+`-----------------------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yydestruct (yymsg, yytype, yyvaluep)
+    const char *yymsg;
+    int yytype;
+    YYSTYPE *yyvaluep;
+#endif
+{
+  YYUSE (yyvaluep);
+
+  if (!yymsg)
+    yymsg = "Deleting";
+  YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
+  switch (yytype)
+    {
+
+      default:
+	break;
+    }
+}
+

+
+/* 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 look-ahead symbol.  */
+int yychar;
+
+/* The semantic value of the look-ahead symbol.  */
+YYSTYPE yylval;
+
+/* Number of syntax errors so far.  */
+int yynerrs;
+
+
+
+/*----------.
+| yyparse.  |
+`----------*/
+
+#ifdef YYPARSE_PARAM
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void *YYPARSE_PARAM)
+#else
+int
+yyparse (YYPARSE_PARAM)
+    void *YYPARSE_PARAM;
+#endif
+#else /* ! YYPARSE_PARAM */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void)
+#else
+int
+yyparse ()
+
+#endif
+#endif
+{
+  
+  int yystate;
+  int yyn;
+  int yyresult;
+  /* 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];
+  char *yymsg = yymsgbuf;
+  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;
+
+  YYDPRINTF ((stderr, "Starting parse\n"));
+
+  yystate = 0;
+  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;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate.  |
+`------------------------------------------------------------*/
+ yynewstate:
+  /* In all cases, when you get here, the value and location stacks
+     have just been pushed.  So pushing a state here evens the stacks.  */
+  yyssp++;
+
+ yysetstate:
+  *yyssp = yystate;
+
+  if (yyss + yystacksize - 1 <= yyssp)
+    {
+      /* Get the current used size of the three stacks, in elements.  */
+      YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+      {
+	/* Give user a chance to reallocate the stack.  Use copies of
+	   these so that the &'s don't force the real ones into
+	   memory.  */
+	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
+	   be undefined if yyoverflow is a macro.  */
+	yyoverflow (YY_("memory exhausted"),
+		    &yyss1, yysize * sizeof (*yyssp),
+		    &yyvs1, yysize * sizeof (*yyvsp),
+
+		    &yystacksize);
+
+	yyss = yyss1;
+	yyvs = yyvs1;
+      }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+      goto yyexhaustedlab;
+# else
+      /* Extend the stack our own way.  */
+      if (YYMAXDEPTH <= yystacksize)
+	goto yyexhaustedlab;
+      yystacksize *= 2;
+      if (YYMAXDEPTH < yystacksize)
+	yystacksize = YYMAXDEPTH;
+
+      {
+	yytype_int16 *yyss1 = yyss;
+	union yyalloc *yyptr =
+	  (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+	if (! yyptr)
+	  goto yyexhaustedlab;
+	YYSTACK_RELOCATE (yyss);
+	YYSTACK_RELOCATE (yyvs);
+
+#  undef YYSTACK_RELOCATE
+	if (yyss1 != yyssa)
+	  YYSTACK_FREE (yyss1);
+      }
+# endif
+#endif /* no yyoverflow */
+
+      yyssp = yyss + yysize - 1;
+      yyvsp = yyvs + yysize - 1;
+
+
+      YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+		  (unsigned long int) yystacksize));
+
+      if (yyss + yystacksize - 1 <= yyssp)
+	YYABORT;
+    }
+
+  YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+  goto yybackup;
+
+/*-----------.
+| yybackup.  |
+`-----------*/
+yybackup:
+
+  /* Do appropriate processing given the current state.  Read a
+     look-ahead token if we need one and don't already have one.  */
+
+  /* First try to decide what to do without reference to look-ahead token.  */
+  yyn = yypact[yystate];
+  if (yyn == YYPACT_NINF)
+    goto yydefault;
+
+  /* Not known => get a look-ahead token if don't already have one.  */
+
+  /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol.  */
+  if (yychar == YYEMPTY)
+    {
+      YYDPRINTF ((stderr, "Reading a token: "));
+      yychar = YYLEX;
+    }
+
+  if (yychar <= YYEOF)
+    {
+      yychar = yytoken = YYEOF;
+      YYDPRINTF ((stderr, "Now at end of input.\n"));
+    }
+  else
+    {
+      yytoken = YYTRANSLATE (yychar);
+      YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
+    }
+
+  /* If the proper action on seeing token YYTOKEN is to reduce or to
+     detect an error, take that action.  */
+  yyn += yytoken;
+  if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+    goto yydefault;
+  yyn = yytable[yyn];
+  if (yyn <= 0)
+    {
+      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 look-ahead token.  */
+  YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+
+  /* Discard the shifted token unless it is eof.  */
+  if (yychar != YYEOF)
+    yychar = YYEMPTY;
+
+  yystate = yyn;
+  *++yyvsp = yylval;
+
+  goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state.  |
+`-----------------------------------------------------------*/
+yydefault:
+  yyn = yydefact[yystate];
+  if (yyn == 0)
+    goto yyerrlab;
+  goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction.  |
+`-----------------------------*/
+yyreduce:
+  /* yyn is the number of a rule to reduce with.  */
+  yylen = yyr2[yyn];
+
+  /* If YYLEN is nonzero, implement the default value of the action:
+     `$$ = $1'.
+
+     Otherwise, the following line sets YYVAL to garbage.
+     This behavior is undocumented and Bison
+     users should not rely upon it.  Assigning to YYVAL
+     unconditionally makes the parser a bit smaller, and it avoids a
+     GCC warning that YYVAL may be used uninitialized.  */
+  yyval = yyvsp[1-yylen];
+
+
+  YY_REDUCE_PRINT (yyn);
+  switch (yyn)
+    {
+        case 4:
+#line 109 "cc.y"
+    {
+		dodecl(xdecl, lastclass, lasttype, Z);
+	}
+    break;
+
+  case 6:
+#line 114 "cc.y"
+    {
+		lastdcl = T;
+		firstarg = S;
+		dodecl(xdecl, lastclass, lasttype, (yyvsp[(2) - (2)].node));
+		if(lastdcl == T || lastdcl->etype != TFUNC) {
+			diag((yyvsp[(2) - (2)].node), "not a function");
+			lastdcl = types[TFUNC];
+		}
+		thisfn = lastdcl;
+		markdcl();
+		firstdcl = dclstack;
+		argmark((yyvsp[(2) - (2)].node), 0);
+	}
+    break;
+
+  case 7:
+#line 128 "cc.y"
+    {
+		argmark((yyvsp[(2) - (4)].node), 1);
+	}
+    break;
+
+  case 8:
+#line 132 "cc.y"
+    {
+		Node *n;
+
+		n = revertdcl();
+		if(n)
+			(yyvsp[(6) - (6)].node) = new(OLIST, n, (yyvsp[(6) - (6)].node));
+		if(!debug['a'] && !debug['Z'])
+			codgen((yyvsp[(6) - (6)].node), (yyvsp[(2) - (6)].node));
+	}
+    break;
+
+  case 9:
+#line 144 "cc.y"
+    {
+		dodecl(xdecl, lastclass, lasttype, (yyvsp[(1) - (1)].node));
+	}
+    break;
+
+  case 10:
+#line 148 "cc.y"
+    {
+		(yyvsp[(1) - (1)].node) = dodecl(xdecl, lastclass, lasttype, (yyvsp[(1) - (1)].node));
+	}
+    break;
+
+  case 11:
+#line 152 "cc.y"
+    {
+		doinit((yyvsp[(1) - (4)].node)->sym, (yyvsp[(1) - (4)].node)->type, 0L, (yyvsp[(4) - (4)].node));
+	}
+    break;
+
+  case 14:
+#line 160 "cc.y"
+    {
+		(yyval.node) = new(OIND, (yyvsp[(3) - (3)].node), Z);
+		(yyval.node)->garb = simpleg((yyvsp[(2) - (3)].lval));
+	}
+    break;
+
+  case 16:
+#line 168 "cc.y"
+    {
+		(yyval.node) = (yyvsp[(2) - (3)].node);
+	}
+    break;
+
+  case 17:
+#line 172 "cc.y"
+    {
+		(yyval.node) = new(OFUNC, (yyvsp[(1) - (4)].node), (yyvsp[(3) - (4)].node));
+	}
+    break;
+
+  case 18:
+#line 176 "cc.y"
+    {
+		(yyval.node) = new(OARRAY, (yyvsp[(1) - (4)].node), (yyvsp[(3) - (4)].node));
+	}
+    break;
+
+  case 19:
+#line 185 "cc.y"
+    {
+		(yyval.node) = dodecl(adecl, lastclass, lasttype, Z);
+	}
+    break;
+
+  case 20:
+#line 189 "cc.y"
+    {
+		(yyval.node) = (yyvsp[(2) - (3)].node);
+	}
+    break;
+
+  case 21:
+#line 195 "cc.y"
+    {
+		dodecl(adecl, lastclass, lasttype, (yyvsp[(1) - (1)].node));
+		(yyval.node) = Z;
+	}
+    break;
+
+  case 22:
+#line 200 "cc.y"
+    {
+		(yyvsp[(1) - (1)].node) = dodecl(adecl, lastclass, lasttype, (yyvsp[(1) - (1)].node));
+	}
+    break;
+
+  case 23:
+#line 204 "cc.y"
+    {
+		int32 w;
+
+		w = (yyvsp[(1) - (4)].node)->sym->type->width;
+		(yyval.node) = doinit((yyvsp[(1) - (4)].node)->sym, (yyvsp[(1) - (4)].node)->type, 0L, (yyvsp[(4) - (4)].node));
+		(yyval.node) = contig((yyvsp[(1) - (4)].node)->sym, (yyval.node), w);
+	}
+    break;
+
+  case 24:
+#line 212 "cc.y"
+    {
+		(yyval.node) = (yyvsp[(1) - (3)].node);
+		if((yyvsp[(3) - (3)].node) != Z) {
+			(yyval.node) = (yyvsp[(3) - (3)].node);
+			if((yyvsp[(1) - (3)].node) != Z)
+				(yyval.node) = new(OLIST, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+		}
+	}
+    break;
+
+  case 27:
+#line 229 "cc.y"
+    {
+		dodecl(pdecl, lastclass, lasttype, (yyvsp[(1) - (1)].node));
+	}
+    break;
+
+  case 29:
+#line 239 "cc.y"
+    {
+		lasttype = (yyvsp[(1) - (1)].type);
+	}
+    break;
+
+  case 31:
+#line 244 "cc.y"
+    {
+		lasttype = (yyvsp[(2) - (2)].type);
+	}
+    break;
+
+  case 33:
+#line 250 "cc.y"
+    {
+		lastfield = 0;
+		edecl(CXXX, lasttype, S);
+	}
+    break;
+
+  case 35:
+#line 258 "cc.y"
+    {
+		dodecl(edecl, CXXX, lasttype, (yyvsp[(1) - (1)].node));
+	}
+    break;
+
+  case 37:
+#line 265 "cc.y"
+    {
+		lastbit = 0;
+		firstbit = 1;
+	}
+    break;
+
+  case 38:
+#line 270 "cc.y"
+    {
+		(yyval.node) = new(OBIT, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+	}
+    break;
+
+  case 39:
+#line 274 "cc.y"
+    {
+		(yyval.node) = new(OBIT, Z, (yyvsp[(2) - (2)].node));
+	}
+    break;
+
+  case 40:
+#line 282 "cc.y"
+    {
+		(yyval.node) = (Z);
+	}
+    break;
+
+  case 42:
+#line 289 "cc.y"
+    {
+		(yyval.node) = new(OIND, (Z), Z);
+		(yyval.node)->garb = simpleg((yyvsp[(2) - (2)].lval));
+	}
+    break;
+
+  case 43:
+#line 294 "cc.y"
+    {
+		(yyval.node) = new(OIND, (yyvsp[(3) - (3)].node), Z);
+		(yyval.node)->garb = simpleg((yyvsp[(2) - (3)].lval));
+	}
+    break;
+
+  case 46:
+#line 303 "cc.y"
+    {
+		(yyval.node) = new(OFUNC, (yyvsp[(1) - (4)].node), (yyvsp[(3) - (4)].node));
+	}
+    break;
+
+  case 47:
+#line 307 "cc.y"
+    {
+		(yyval.node) = new(OARRAY, (yyvsp[(1) - (4)].node), (yyvsp[(3) - (4)].node));
+	}
+    break;
+
+  case 48:
+#line 313 "cc.y"
+    {
+		(yyval.node) = new(OFUNC, (Z), Z);
+	}
+    break;
+
+  case 49:
+#line 317 "cc.y"
+    {
+		(yyval.node) = new(OARRAY, (Z), (yyvsp[(2) - (3)].node));
+	}
+    break;
+
+  case 50:
+#line 321 "cc.y"
+    {
+		(yyval.node) = (yyvsp[(2) - (3)].node);
+	}
+    break;
+
+  case 52:
+#line 328 "cc.y"
+    {
+		(yyval.node) = new(OINIT, invert((yyvsp[(2) - (3)].node)), Z);
+	}
+    break;
+
+  case 53:
+#line 334 "cc.y"
+    {
+		(yyval.node) = new(OARRAY, (yyvsp[(2) - (3)].node), Z);
+	}
+    break;
+
+  case 54:
+#line 338 "cc.y"
+    {
+		(yyval.node) = new(OELEM, Z, Z);
+		(yyval.node)->sym = (yyvsp[(2) - (2)].sym);
+	}
+    break;
+
+  case 57:
+#line 347 "cc.y"
+    {
+		(yyval.node) = new(OLIST, (yyvsp[(1) - (3)].node), (yyvsp[(2) - (3)].node));
+	}
+    break;
+
+  case 59:
+#line 352 "cc.y"
+    {
+		(yyval.node) = new(OLIST, (yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].node));
+	}
+    break;
+
+  case 62:
+#line 360 "cc.y"
+    {
+		(yyval.node) = new(OLIST, (yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].node));
+	}
+    break;
+
+  case 63:
+#line 365 "cc.y"
+    {
+		(yyval.node) = Z;
+	}
+    break;
+
+  case 64:
+#line 369 "cc.y"
+    {
+		(yyval.node) = invert((yyvsp[(1) - (1)].node));
+	}
+    break;
+
+  case 66:
+#line 377 "cc.y"
+    {
+		(yyval.node) = new(OPROTO, (yyvsp[(2) - (2)].node), Z);
+		(yyval.node)->type = (yyvsp[(1) - (2)].type);
+	}
+    break;
+
+  case 67:
+#line 382 "cc.y"
+    {
+		(yyval.node) = new(OPROTO, (yyvsp[(2) - (2)].node), Z);
+		(yyval.node)->type = (yyvsp[(1) - (2)].type);
+	}
+    break;
+
+  case 68:
+#line 387 "cc.y"
+    {
+		(yyval.node) = new(ODOTDOT, Z, Z);
+	}
+    break;
+
+  case 69:
+#line 391 "cc.y"
+    {
+		(yyval.node) = new(OLIST, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+	}
+    break;
+
+  case 70:
+#line 397 "cc.y"
+    {
+		(yyval.node) = invert((yyvsp[(2) - (3)].node));
+	//	if($2 != Z)
+	//		$$ = new(OLIST, $2, $$);
+		if((yyval.node) == Z)
+			(yyval.node) = new(OLIST, Z, Z);
+	}
+    break;
+
+  case 71:
+#line 406 "cc.y"
+    {
+		(yyval.node) = Z;
+	}
+    break;
+
+  case 72:
+#line 410 "cc.y"
+    {
+		(yyval.node) = new(OLIST, (yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].node));
+	}
+    break;
+
+  case 73:
+#line 414 "cc.y"
+    {
+		(yyval.node) = new(OLIST, (yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].node));
+	}
+    break;
+
+  case 75:
+#line 421 "cc.y"
+    {
+		(yyval.node) = new(OLIST, (yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].node));
+	}
+    break;
+
+  case 76:
+#line 427 "cc.y"
+    {
+		(yyval.node) = new(OCASE, (yyvsp[(2) - (3)].node), Z);
+	}
+    break;
+
+  case 77:
+#line 431 "cc.y"
+    {
+		(yyval.node) = new(OCASE, Z, Z);
+	}
+    break;
+
+  case 78:
+#line 435 "cc.y"
+    {
+		(yyval.node) = new(OLABEL, dcllabel((yyvsp[(1) - (2)].sym), 1), Z);
+	}
+    break;
+
+  case 79:
+#line 441 "cc.y"
+    {
+		(yyval.node) = Z;
+	}
+    break;
+
+  case 81:
+#line 446 "cc.y"
+    {
+		(yyval.node) = new(OLIST, (yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].node));
+	}
+    break;
+
+  case 83:
+#line 453 "cc.y"
+    {
+		(yyval.node) = (yyvsp[(2) - (2)].node);
+	}
+    break;
+
+  case 85:
+#line 459 "cc.y"
+    {
+		markdcl();
+	}
+    break;
+
+  case 86:
+#line 463 "cc.y"
+    {
+		(yyval.node) = revertdcl();
+		if((yyval.node))
+			(yyval.node) = new(OLIST, (yyval.node), (yyvsp[(2) - (2)].node));
+		else
+			(yyval.node) = (yyvsp[(2) - (2)].node);
+	}
+    break;
+
+  case 87:
+#line 471 "cc.y"
+    {
+		(yyval.node) = new(OIF, (yyvsp[(3) - (5)].node), new(OLIST, (yyvsp[(5) - (5)].node), Z));
+		if((yyvsp[(5) - (5)].node) == Z)
+			warn((yyvsp[(3) - (5)].node), "empty if body");
+	}
+    break;
+
+  case 88:
+#line 477 "cc.y"
+    {
+		(yyval.node) = new(OIF, (yyvsp[(3) - (7)].node), new(OLIST, (yyvsp[(5) - (7)].node), (yyvsp[(7) - (7)].node)));
+		if((yyvsp[(5) - (7)].node) == Z)
+			warn((yyvsp[(3) - (7)].node), "empty if body");
+		if((yyvsp[(7) - (7)].node) == Z)
+			warn((yyvsp[(3) - (7)].node), "empty else body");
+	}
+    break;
+
+  case 89:
+#line 484 "cc.y"
+    { markdcl(); }
+    break;
+
+  case 90:
+#line 485 "cc.y"
+    {
+		(yyval.node) = revertdcl();
+		if((yyval.node)){
+			if((yyvsp[(4) - (10)].node))
+				(yyvsp[(4) - (10)].node) = new(OLIST, (yyval.node), (yyvsp[(4) - (10)].node));
+			else
+				(yyvsp[(4) - (10)].node) = (yyval.node);
+		}
+		(yyval.node) = new(OFOR, new(OLIST, (yyvsp[(6) - (10)].node), new(OLIST, (yyvsp[(4) - (10)].node), (yyvsp[(8) - (10)].node))), (yyvsp[(10) - (10)].node));
+	}
+    break;
+
+  case 91:
+#line 496 "cc.y"
+    {
+		(yyval.node) = new(OWHILE, (yyvsp[(3) - (5)].node), (yyvsp[(5) - (5)].node));
+	}
+    break;
+
+  case 92:
+#line 500 "cc.y"
+    {
+		(yyval.node) = new(ODWHILE, (yyvsp[(5) - (7)].node), (yyvsp[(2) - (7)].node));
+	}
+    break;
+
+  case 93:
+#line 504 "cc.y"
+    {
+		(yyval.node) = new(ORETURN, (yyvsp[(2) - (3)].node), Z);
+		(yyval.node)->type = thisfn->link;
+	}
+    break;
+
+  case 94:
+#line 509 "cc.y"
+    {
+		(yyval.node) = new(OCONST, Z, Z);
+		(yyval.node)->vconst = 0;
+		(yyval.node)->type = types[TINT];
+		(yyvsp[(3) - (5)].node) = new(OSUB, (yyval.node), (yyvsp[(3) - (5)].node));
+
+		(yyval.node) = new(OCONST, Z, Z);
+		(yyval.node)->vconst = 0;
+		(yyval.node)->type = types[TINT];
+		(yyvsp[(3) - (5)].node) = new(OSUB, (yyval.node), (yyvsp[(3) - (5)].node));
+
+		(yyval.node) = new(OSWITCH, (yyvsp[(3) - (5)].node), (yyvsp[(5) - (5)].node));
+	}
+    break;
+
+  case 95:
+#line 523 "cc.y"
+    {
+		(yyval.node) = new(OBREAK, Z, Z);
+	}
+    break;
+
+  case 96:
+#line 527 "cc.y"
+    {
+		(yyval.node) = new(OCONTINUE, Z, Z);
+	}
+    break;
+
+  case 97:
+#line 531 "cc.y"
+    {
+		(yyval.node) = new(OGOTO, dcllabel((yyvsp[(2) - (3)].sym), 0), Z);
+	}
+    break;
+
+  case 98:
+#line 535 "cc.y"
+    {
+		(yyval.node) = new(OUSED, (yyvsp[(3) - (5)].node), Z);
+	}
+    break;
+
+  case 99:
+#line 539 "cc.y"
+    {
+		(yyval.node) = new(OPREFETCH, (yyvsp[(3) - (5)].node), Z);
+	}
+    break;
+
+  case 100:
+#line 543 "cc.y"
+    {
+		(yyval.node) = new(OSET, (yyvsp[(3) - (5)].node), Z);
+	}
+    break;
+
+  case 101:
+#line 548 "cc.y"
+    {
+		(yyval.node) = Z;
+	}
+    break;
+
+  case 103:
+#line 554 "cc.y"
+    {
+		(yyval.node) = Z;
+	}
+    break;
+
+  case 105:
+#line 561 "cc.y"
+    {
+		(yyval.node) = new(OCAST, (yyvsp[(1) - (1)].node), Z);
+		(yyval.node)->type = types[TLONG];
+	}
+    break;
+
+  case 107:
+#line 569 "cc.y"
+    {
+		(yyval.node) = new(OCOMMA, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+	}
+    break;
+
+  case 109:
+#line 576 "cc.y"
+    {
+		(yyval.node) = new(OMUL, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+	}
+    break;
+
+  case 110:
+#line 580 "cc.y"
+    {
+		(yyval.node) = new(ODIV, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+	}
+    break;
+
+  case 111:
+#line 584 "cc.y"
+    {
+		(yyval.node) = new(OMOD, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+	}
+    break;
+
+  case 112:
+#line 588 "cc.y"
+    {
+		(yyval.node) = new(OADD, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+	}
+    break;
+
+  case 113:
+#line 592 "cc.y"
+    {
+		(yyval.node) = new(OSUB, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+	}
+    break;
+
+  case 114:
+#line 596 "cc.y"
+    {
+		(yyval.node) = new(OASHR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+	}
+    break;
+
+  case 115:
+#line 600 "cc.y"
+    {
+		(yyval.node) = new(OASHL, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+	}
+    break;
+
+  case 116:
+#line 604 "cc.y"
+    {
+		(yyval.node) = new(OLT, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+	}
+    break;
+
+  case 117:
+#line 608 "cc.y"
+    {
+		(yyval.node) = new(OGT, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+	}
+    break;
+
+  case 118:
+#line 612 "cc.y"
+    {
+		(yyval.node) = new(OLE, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+	}
+    break;
+
+  case 119:
+#line 616 "cc.y"
+    {
+		(yyval.node) = new(OGE, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+	}
+    break;
+
+  case 120:
+#line 620 "cc.y"
+    {
+		(yyval.node) = new(OEQ, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+	}
+    break;
+
+  case 121:
+#line 624 "cc.y"
+    {
+		(yyval.node) = new(ONE, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+	}
+    break;
+
+  case 122:
+#line 628 "cc.y"
+    {
+		(yyval.node) = new(OAND, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+	}
+    break;
+
+  case 123:
+#line 632 "cc.y"
+    {
+		(yyval.node) = new(OXOR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+	}
+    break;
+
+  case 124:
+#line 636 "cc.y"
+    {
+		(yyval.node) = new(OOR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+	}
+    break;
+
+  case 125:
+#line 640 "cc.y"
+    {
+		(yyval.node) = new(OANDAND, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+	}
+    break;
+
+  case 126:
+#line 644 "cc.y"
+    {
+		(yyval.node) = new(OOROR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+	}
+    break;
+
+  case 127:
+#line 648 "cc.y"
+    {
+		(yyval.node) = new(OCOND, (yyvsp[(1) - (5)].node), new(OLIST, (yyvsp[(3) - (5)].node), (yyvsp[(5) - (5)].node)));
+	}
+    break;
+
+  case 128:
+#line 652 "cc.y"
+    {
+		(yyval.node) = new(OAS, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+	}
+    break;
+
+  case 129:
+#line 656 "cc.y"
+    {
+		(yyval.node) = new(OASADD, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+	}
+    break;
+
+  case 130:
+#line 660 "cc.y"
+    {
+		(yyval.node) = new(OASSUB, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+	}
+    break;
+
+  case 131:
+#line 664 "cc.y"
+    {
+		(yyval.node) = new(OASMUL, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+	}
+    break;
+
+  case 132:
+#line 668 "cc.y"
+    {
+		(yyval.node) = new(OASDIV, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+	}
+    break;
+
+  case 133:
+#line 672 "cc.y"
+    {
+		(yyval.node) = new(OASMOD, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+	}
+    break;
+
+  case 134:
+#line 676 "cc.y"
+    {
+		(yyval.node) = new(OASASHL, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+	}
+    break;
+
+  case 135:
+#line 680 "cc.y"
+    {
+		(yyval.node) = new(OASASHR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+	}
+    break;
+
+  case 136:
+#line 684 "cc.y"
+    {
+		(yyval.node) = new(OASAND, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+	}
+    break;
+
+  case 137:
+#line 688 "cc.y"
+    {
+		(yyval.node) = new(OASXOR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+	}
+    break;
+
+  case 138:
+#line 692 "cc.y"
+    {
+		(yyval.node) = new(OASOR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+	}
+    break;
+
+  case 140:
+#line 699 "cc.y"
+    {
+		(yyval.node) = new(OCAST, (yyvsp[(5) - (5)].node), Z);
+		dodecl(NODECL, CXXX, (yyvsp[(2) - (5)].type), (yyvsp[(3) - (5)].node));
+		(yyval.node)->type = lastdcl;
+		(yyval.node)->xcast = 1;
+	}
+    break;
+
+  case 141:
+#line 706 "cc.y"
+    {
+		(yyval.node) = new(OSTRUCT, (yyvsp[(6) - (7)].node), Z);
+		dodecl(NODECL, CXXX, (yyvsp[(2) - (7)].type), (yyvsp[(3) - (7)].node));
+		(yyval.node)->type = lastdcl;
+	}
+    break;
+
+  case 143:
+#line 715 "cc.y"
+    {
+		(yyval.node) = new(OIND, (yyvsp[(2) - (2)].node), Z);
+	}
+    break;
+
+  case 144:
+#line 719 "cc.y"
+    {
+		(yyval.node) = new(OADDR, (yyvsp[(2) - (2)].node), Z);
+	}
+    break;
+
+  case 145:
+#line 723 "cc.y"
+    {
+		(yyval.node) = new(OPOS, (yyvsp[(2) - (2)].node), Z);
+	}
+    break;
+
+  case 146:
+#line 727 "cc.y"
+    {
+		(yyval.node) = new(ONEG, (yyvsp[(2) - (2)].node), Z);
+	}
+    break;
+
+  case 147:
+#line 731 "cc.y"
+    {
+		(yyval.node) = new(ONOT, (yyvsp[(2) - (2)].node), Z);
+	}
+    break;
+
+  case 148:
+#line 735 "cc.y"
+    {
+		(yyval.node) = new(OCOM, (yyvsp[(2) - (2)].node), Z);
+	}
+    break;
+
+  case 149:
+#line 739 "cc.y"
+    {
+		(yyval.node) = new(OPREINC, (yyvsp[(2) - (2)].node), Z);
+	}
+    break;
+
+  case 150:
+#line 743 "cc.y"
+    {
+		(yyval.node) = new(OPREDEC, (yyvsp[(2) - (2)].node), Z);
+	}
+    break;
+
+  case 151:
+#line 747 "cc.y"
+    {
+		(yyval.node) = new(OSIZE, (yyvsp[(2) - (2)].node), Z);
+	}
+    break;
+
+  case 152:
+#line 751 "cc.y"
+    {
+		(yyval.node) = new(OSIGN, (yyvsp[(2) - (2)].node), Z);
+	}
+    break;
+
+  case 153:
+#line 757 "cc.y"
+    {
+		(yyval.node) = (yyvsp[(2) - (3)].node);
+	}
+    break;
+
+  case 154:
+#line 761 "cc.y"
+    {
+		(yyval.node) = new(OSIZE, Z, Z);
+		dodecl(NODECL, CXXX, (yyvsp[(3) - (5)].type), (yyvsp[(4) - (5)].node));
+		(yyval.node)->type = lastdcl;
+	}
+    break;
+
+  case 155:
+#line 767 "cc.y"
+    {
+		(yyval.node) = new(OSIGN, Z, Z);
+		dodecl(NODECL, CXXX, (yyvsp[(3) - (5)].type), (yyvsp[(4) - (5)].node));
+		(yyval.node)->type = lastdcl;
+	}
+    break;
+
+  case 156:
+#line 773 "cc.y"
+    {
+		(yyval.node) = new(OFUNC, (yyvsp[(1) - (4)].node), Z);
+		if((yyvsp[(1) - (4)].node)->op == ONAME)
+		if((yyvsp[(1) - (4)].node)->type == T)
+			dodecl(xdecl, CXXX, types[TINT], (yyval.node));
+		(yyval.node)->right = invert((yyvsp[(3) - (4)].node));
+	}
+    break;
+
+  case 157:
+#line 781 "cc.y"
+    {
+		(yyval.node) = new(OIND, new(OADD, (yyvsp[(1) - (4)].node), (yyvsp[(3) - (4)].node)), Z);
+	}
+    break;
+
+  case 158:
+#line 785 "cc.y"
+    {
+		(yyval.node) = new(ODOT, new(OIND, (yyvsp[(1) - (3)].node), Z), Z);
+		(yyval.node)->sym = (yyvsp[(3) - (3)].sym);
+	}
+    break;
+
+  case 159:
+#line 790 "cc.y"
+    {
+		(yyval.node) = new(ODOT, (yyvsp[(1) - (3)].node), Z);
+		(yyval.node)->sym = (yyvsp[(3) - (3)].sym);
+	}
+    break;
+
+  case 160:
+#line 795 "cc.y"
+    {
+		(yyval.node) = new(OPOSTINC, (yyvsp[(1) - (2)].node), Z);
+	}
+    break;
+
+  case 161:
+#line 799 "cc.y"
+    {
+		(yyval.node) = new(OPOSTDEC, (yyvsp[(1) - (2)].node), Z);
+	}
+    break;
+
+  case 163:
+#line 804 "cc.y"
+    {
+		(yyval.node) = new(OCONST, Z, Z);
+		(yyval.node)->type = types[TINT];
+		(yyval.node)->vconst = (yyvsp[(1) - (1)].vval);
+		(yyval.node)->cstring = strdup(symb);
+	}
+    break;
+
+  case 164:
+#line 811 "cc.y"
+    {
+		(yyval.node) = new(OCONST, Z, Z);
+		(yyval.node)->type = types[TLONG];
+		(yyval.node)->vconst = (yyvsp[(1) - (1)].vval);
+		(yyval.node)->cstring = strdup(symb);
+	}
+    break;
+
+  case 165:
+#line 818 "cc.y"
+    {
+		(yyval.node) = new(OCONST, Z, Z);
+		(yyval.node)->type = types[TUINT];
+		(yyval.node)->vconst = (yyvsp[(1) - (1)].vval);
+		(yyval.node)->cstring = strdup(symb);
+	}
+    break;
+
+  case 166:
+#line 825 "cc.y"
+    {
+		(yyval.node) = new(OCONST, Z, Z);
+		(yyval.node)->type = types[TULONG];
+		(yyval.node)->vconst = (yyvsp[(1) - (1)].vval);
+		(yyval.node)->cstring = strdup(symb);
+	}
+    break;
+
+  case 167:
+#line 832 "cc.y"
+    {
+		(yyval.node) = new(OCONST, Z, Z);
+		(yyval.node)->type = types[TDOUBLE];
+		(yyval.node)->fconst = (yyvsp[(1) - (1)].dval);
+		(yyval.node)->cstring = strdup(symb);
+	}
+    break;
+
+  case 168:
+#line 839 "cc.y"
+    {
+		(yyval.node) = new(OCONST, Z, Z);
+		(yyval.node)->type = types[TFLOAT];
+		(yyval.node)->fconst = (yyvsp[(1) - (1)].dval);
+		(yyval.node)->cstring = strdup(symb);
+	}
+    break;
+
+  case 169:
+#line 846 "cc.y"
+    {
+		(yyval.node) = new(OCONST, Z, Z);
+		(yyval.node)->type = types[TVLONG];
+		(yyval.node)->vconst = (yyvsp[(1) - (1)].vval);
+		(yyval.node)->cstring = strdup(symb);
+	}
+    break;
+
+  case 170:
+#line 853 "cc.y"
+    {
+		(yyval.node) = new(OCONST, Z, Z);
+		(yyval.node)->type = types[TUVLONG];
+		(yyval.node)->vconst = (yyvsp[(1) - (1)].vval);
+		(yyval.node)->cstring = strdup(symb);
+	}
+    break;
+
+  case 173:
+#line 864 "cc.y"
+    {
+		(yyval.node) = new(OSTRING, Z, Z);
+		(yyval.node)->type = typ(TARRAY, types[TCHAR]);
+		(yyval.node)->type->width = (yyvsp[(1) - (1)].sval).l + 1;
+		(yyval.node)->cstring = (yyvsp[(1) - (1)].sval).s;
+		(yyval.node)->sym = symstring;
+		(yyval.node)->etype = TARRAY;
+		(yyval.node)->class = CSTATIC;
+	}
+    break;
+
+  case 174:
+#line 874 "cc.y"
+    {
+		char *s;
+		int n;
+
+		n = (yyvsp[(1) - (2)].node)->type->width - 1;
+		s = alloc(n+(yyvsp[(2) - (2)].sval).l+MAXALIGN);
+
+		memcpy(s, (yyvsp[(1) - (2)].node)->cstring, n);
+		memcpy(s+n, (yyvsp[(2) - (2)].sval).s, (yyvsp[(2) - (2)].sval).l);
+		s[n+(yyvsp[(2) - (2)].sval).l] = 0;
+
+		(yyval.node) = (yyvsp[(1) - (2)].node);
+		(yyval.node)->type->width += (yyvsp[(2) - (2)].sval).l;
+		(yyval.node)->cstring = s;
+	}
+    break;
+
+  case 175:
+#line 892 "cc.y"
+    {
+		(yyval.node) = new(OLSTRING, Z, Z);
+		(yyval.node)->type = typ(TARRAY, types[TRUNE]);
+		(yyval.node)->type->width = (yyvsp[(1) - (1)].sval).l + sizeof(TRune);
+		(yyval.node)->rstring = (TRune*)(yyvsp[(1) - (1)].sval).s;
+		(yyval.node)->sym = symstring;
+		(yyval.node)->etype = TARRAY;
+		(yyval.node)->class = CSTATIC;
+	}
+    break;
+
+  case 176:
+#line 902 "cc.y"
+    {
+		char *s;
+		int n;
+
+		n = (yyvsp[(1) - (2)].node)->type->width - sizeof(TRune);
+		s = alloc(n+(yyvsp[(2) - (2)].sval).l+MAXALIGN);
+
+		memcpy(s, (yyvsp[(1) - (2)].node)->rstring, n);
+		memcpy(s+n, (yyvsp[(2) - (2)].sval).s, (yyvsp[(2) - (2)].sval).l);
+		*(TRune*)(s+n+(yyvsp[(2) - (2)].sval).l) = 0;
+
+		(yyval.node) = (yyvsp[(1) - (2)].node);
+		(yyval.node)->type->width += (yyvsp[(2) - (2)].sval).l;
+		(yyval.node)->rstring = (TRune*)s;
+	}
+    break;
+
+  case 177:
+#line 919 "cc.y"
+    {
+		(yyval.node) = Z;
+	}
+    break;
+
+  case 180:
+#line 927 "cc.y"
+    {
+		(yyval.node) = new(OLIST, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+	}
+    break;
+
+  case 181:
+#line 933 "cc.y"
+    {
+		(yyval.tyty).t1 = strf;
+		(yyval.tyty).t2 = strl;
+		(yyval.tyty).t3 = lasttype;
+		(yyval.tyty).c = lastclass;
+		strf = T;
+		strl = T;
+		lastbit = 0;
+		firstbit = 1;
+		lastclass = CXXX;
+		lasttype = T;
+	}
+    break;
+
+  case 182:
+#line 946 "cc.y"
+    {
+		(yyval.type) = strf;
+		strf = (yyvsp[(2) - (4)].tyty).t1;
+		strl = (yyvsp[(2) - (4)].tyty).t2;
+		lasttype = (yyvsp[(2) - (4)].tyty).t3;
+		lastclass = (yyvsp[(2) - (4)].tyty).c;
+	}
+    break;
+
+  case 183:
+#line 955 "cc.y"
+    {
+		lastclass = CXXX;
+		lasttype = types[TINT];
+	}
+    break;
+
+  case 185:
+#line 963 "cc.y"
+    {
+		(yyval.tycl).t = (yyvsp[(1) - (1)].type);
+		(yyval.tycl).c = CXXX;
+	}
+    break;
+
+  case 186:
+#line 968 "cc.y"
+    {
+		(yyval.tycl).t = simplet((yyvsp[(1) - (1)].lval));
+		(yyval.tycl).c = CXXX;
+	}
+    break;
+
+  case 187:
+#line 973 "cc.y"
+    {
+		(yyval.tycl).t = simplet((yyvsp[(1) - (1)].lval));
+		(yyval.tycl).c = simplec((yyvsp[(1) - (1)].lval));
+		(yyval.tycl).t = garbt((yyval.tycl).t, (yyvsp[(1) - (1)].lval));
+	}
+    break;
+
+  case 188:
+#line 979 "cc.y"
+    {
+		(yyval.tycl).t = (yyvsp[(1) - (2)].type);
+		(yyval.tycl).c = simplec((yyvsp[(2) - (2)].lval));
+		(yyval.tycl).t = garbt((yyval.tycl).t, (yyvsp[(2) - (2)].lval));
+		if((yyvsp[(2) - (2)].lval) & ~BCLASS & ~BGARB)
+			diag(Z, "duplicate types given: %T and %Q", (yyvsp[(1) - (2)].type), (yyvsp[(2) - (2)].lval));
+	}
+    break;
+
+  case 189:
+#line 987 "cc.y"
+    {
+		(yyval.tycl).t = simplet(typebitor((yyvsp[(1) - (2)].lval), (yyvsp[(2) - (2)].lval)));
+		(yyval.tycl).c = simplec((yyvsp[(2) - (2)].lval));
+		(yyval.tycl).t = garbt((yyval.tycl).t, (yyvsp[(2) - (2)].lval));
+	}
+    break;
+
+  case 190:
+#line 993 "cc.y"
+    {
+		(yyval.tycl).t = (yyvsp[(2) - (3)].type);
+		(yyval.tycl).c = simplec((yyvsp[(1) - (3)].lval));
+		(yyval.tycl).t = garbt((yyval.tycl).t, (yyvsp[(1) - (3)].lval)|(yyvsp[(3) - (3)].lval));
+	}
+    break;
+
+  case 191:
+#line 999 "cc.y"
+    {
+		(yyval.tycl).t = simplet((yyvsp[(2) - (2)].lval));
+		(yyval.tycl).c = simplec((yyvsp[(1) - (2)].lval));
+		(yyval.tycl).t = garbt((yyval.tycl).t, (yyvsp[(1) - (2)].lval));
+	}
+    break;
+
+  case 192:
+#line 1005 "cc.y"
+    {
+		(yyval.tycl).t = simplet(typebitor((yyvsp[(2) - (3)].lval), (yyvsp[(3) - (3)].lval)));
+		(yyval.tycl).c = simplec((yyvsp[(1) - (3)].lval)|(yyvsp[(3) - (3)].lval));
+		(yyval.tycl).t = garbt((yyval.tycl).t, (yyvsp[(1) - (3)].lval)|(yyvsp[(3) - (3)].lval));
+	}
+    break;
+
+  case 193:
+#line 1013 "cc.y"
+    {
+		(yyval.type) = (yyvsp[(1) - (1)].tycl).t;
+		if((yyvsp[(1) - (1)].tycl).c != CXXX)
+			diag(Z, "illegal combination of class 4: %s", cnames[(yyvsp[(1) - (1)].tycl).c]);
+	}
+    break;
+
+  case 194:
+#line 1021 "cc.y"
+    {
+		lasttype = (yyvsp[(1) - (1)].tycl).t;
+		lastclass = (yyvsp[(1) - (1)].tycl).c;
+	}
+    break;
+
+  case 195:
+#line 1028 "cc.y"
+    {
+		dotag((yyvsp[(2) - (2)].sym), TSTRUCT, 0);
+		(yyval.type) = (yyvsp[(2) - (2)].sym)->suetag;
+	}
+    break;
+
+  case 196:
+#line 1033 "cc.y"
+    {
+		dotag((yyvsp[(2) - (2)].sym), TSTRUCT, autobn);
+	}
+    break;
+
+  case 197:
+#line 1037 "cc.y"
+    {
+		(yyval.type) = (yyvsp[(2) - (4)].sym)->suetag;
+		if((yyval.type)->link != T)
+			diag(Z, "redeclare tag: %s", (yyvsp[(2) - (4)].sym)->name);
+		(yyval.type)->link = (yyvsp[(4) - (4)].type);
+		sualign((yyval.type));
+	}
+    break;
+
+  case 198:
+#line 1045 "cc.y"
+    {
+		diag(Z, "struct must have tag");
+		taggen++;
+		sprint(symb, "_%d_", taggen);
+		(yyval.type) = dotag(lookup(), TSTRUCT, autobn);
+		(yyval.type)->link = (yyvsp[(2) - (2)].type);
+		sualign((yyval.type));
+	}
+    break;
+
+  case 199:
+#line 1054 "cc.y"
+    {
+		dotag((yyvsp[(2) - (2)].sym), TUNION, 0);
+		(yyval.type) = (yyvsp[(2) - (2)].sym)->suetag;
+	}
+    break;
+
+  case 200:
+#line 1059 "cc.y"
+    {
+		dotag((yyvsp[(2) - (2)].sym), TUNION, autobn);
+	}
+    break;
+
+  case 201:
+#line 1063 "cc.y"
+    {
+		(yyval.type) = (yyvsp[(2) - (4)].sym)->suetag;
+		if((yyval.type)->link != T)
+			diag(Z, "redeclare tag: %s", (yyvsp[(2) - (4)].sym)->name);
+		(yyval.type)->link = (yyvsp[(4) - (4)].type);
+		sualign((yyval.type));
+	}
+    break;
+
+  case 202:
+#line 1071 "cc.y"
+    {
+		taggen++;
+		sprint(symb, "_%d_", taggen);
+		(yyval.type) = dotag(lookup(), TUNION, autobn);
+		(yyval.type)->link = (yyvsp[(2) - (2)].type);
+		sualign((yyval.type));
+	}
+    break;
+
+  case 203:
+#line 1079 "cc.y"
+    {
+		dotag((yyvsp[(2) - (2)].sym), TENUM, 0);
+		(yyval.type) = (yyvsp[(2) - (2)].sym)->suetag;
+		if((yyval.type)->link == T)
+			(yyval.type)->link = types[TINT];
+		(yyval.type) = (yyval.type)->link;
+	}
+    break;
+
+  case 204:
+#line 1087 "cc.y"
+    {
+		dotag((yyvsp[(2) - (2)].sym), TENUM, autobn);
+	}
+    break;
+
+  case 205:
+#line 1091 "cc.y"
+    {
+		en.tenum = T;
+		en.cenum = T;
+	}
+    break;
+
+  case 206:
+#line 1096 "cc.y"
+    {
+		(yyval.type) = (yyvsp[(2) - (7)].sym)->suetag;
+		if((yyval.type)->link != T)
+			diag(Z, "redeclare tag: %s", (yyvsp[(2) - (7)].sym)->name);
+		if(en.tenum == T) {
+			diag(Z, "enum type ambiguous: %s", (yyvsp[(2) - (7)].sym)->name);
+			en.tenum = types[TINT];
+		}
+		(yyval.type)->link = en.tenum;
+		(yyval.type) = en.tenum;
+	}
+    break;
+
+  case 207:
+#line 1108 "cc.y"
+    {
+		en.tenum = T;
+		en.cenum = T;
+	}
+    break;
+
+  case 208:
+#line 1113 "cc.y"
+    {
+		(yyval.type) = en.tenum;
+	}
+    break;
+
+  case 209:
+#line 1117 "cc.y"
+    {
+		(yyval.type) = tcopy((yyvsp[(1) - (1)].sym)->type);
+	}
+    break;
+
+  case 211:
+#line 1124 "cc.y"
+    {
+		(yyval.lval) = typebitor((yyvsp[(1) - (2)].lval), (yyvsp[(2) - (2)].lval));
+	}
+    break;
+
+  case 212:
+#line 1129 "cc.y"
+    {
+		(yyval.lval) = 0;
+	}
+    break;
+
+  case 213:
+#line 1133 "cc.y"
+    {
+		(yyval.lval) = typebitor((yyvsp[(1) - (2)].lval), (yyvsp[(2) - (2)].lval));
+	}
+    break;
+
+  case 218:
+#line 1145 "cc.y"
+    {
+		(yyval.lval) = typebitor((yyvsp[(1) - (2)].lval), (yyvsp[(2) - (2)].lval));
+	}
+    break;
+
+  case 221:
+#line 1155 "cc.y"
+    {
+		doenum((yyvsp[(1) - (1)].sym), Z);
+	}
+    break;
+
+  case 222:
+#line 1159 "cc.y"
+    {
+		doenum((yyvsp[(1) - (3)].sym), (yyvsp[(3) - (3)].node));
+	}
+    break;
+
+  case 225:
+#line 1166 "cc.y"
+    { (yyval.lval) = BCHAR; }
+    break;
+
+  case 226:
+#line 1167 "cc.y"
+    { (yyval.lval) = BSHORT; }
+    break;
+
+  case 227:
+#line 1168 "cc.y"
+    { (yyval.lval) = BINT; }
+    break;
+
+  case 228:
+#line 1169 "cc.y"
+    { (yyval.lval) = BLONG; }
+    break;
+
+  case 229:
+#line 1170 "cc.y"
+    { (yyval.lval) = BSIGNED; }
+    break;
+
+  case 230:
+#line 1171 "cc.y"
+    { (yyval.lval) = BUNSIGNED; }
+    break;
+
+  case 231:
+#line 1172 "cc.y"
+    { (yyval.lval) = BFLOAT; }
+    break;
+
+  case 232:
+#line 1173 "cc.y"
+    { (yyval.lval) = BDOUBLE; }
+    break;
+
+  case 233:
+#line 1174 "cc.y"
+    { (yyval.lval) = BVOID; }
+    break;
+
+  case 234:
+#line 1177 "cc.y"
+    { (yyval.lval) = BAUTO; }
+    break;
+
+  case 235:
+#line 1178 "cc.y"
+    { (yyval.lval) = BSTATIC; }
+    break;
+
+  case 236:
+#line 1179 "cc.y"
+    { (yyval.lval) = BEXTERN; }
+    break;
+
+  case 237:
+#line 1180 "cc.y"
+    { (yyval.lval) = BTYPEDEF; }
+    break;
+
+  case 238:
+#line 1181 "cc.y"
+    { (yyval.lval) = BTYPESTR; }
+    break;
+
+  case 239:
+#line 1182 "cc.y"
+    { (yyval.lval) = BREGISTER; }
+    break;
+
+  case 240:
+#line 1183 "cc.y"
+    { (yyval.lval) = 0; }
+    break;
+
+  case 241:
+#line 1186 "cc.y"
+    { (yyval.lval) = BCONSTNT; }
+    break;
+
+  case 242:
+#line 1187 "cc.y"
+    { (yyval.lval) = BVOLATILE; }
+    break;
+
+  case 243:
+#line 1188 "cc.y"
+    { (yyval.lval) = 0; }
+    break;
+
+  case 244:
+#line 1192 "cc.y"
+    {
+		(yyval.node) = new(ONAME, Z, Z);
+		if((yyvsp[(1) - (1)].sym)->class == CLOCAL)
+			(yyvsp[(1) - (1)].sym) = mkstatic((yyvsp[(1) - (1)].sym));
+		(yyval.node)->sym = (yyvsp[(1) - (1)].sym);
+		(yyval.node)->type = (yyvsp[(1) - (1)].sym)->type;
+		(yyval.node)->etype = TVOID;
+		if((yyval.node)->type != T)
+			(yyval.node)->etype = (yyval.node)->type->etype;
+		(yyval.node)->xoffset = (yyvsp[(1) - (1)].sym)->offset;
+		(yyval.node)->class = (yyvsp[(1) - (1)].sym)->class;
+		(yyvsp[(1) - (1)].sym)->aused = 1;
+	}
+    break;
+
+  case 245:
+#line 1207 "cc.y"
+    {
+		(yyval.node) = new(ONAME, Z, Z);
+		(yyval.node)->sym = (yyvsp[(1) - (1)].sym);
+		(yyval.node)->type = (yyvsp[(1) - (1)].sym)->type;
+		(yyval.node)->etype = TVOID;
+		if((yyval.node)->type != T)
+			(yyval.node)->etype = (yyval.node)->type->etype;
+		(yyval.node)->xoffset = (yyvsp[(1) - (1)].sym)->offset;
+		(yyval.node)->class = (yyvsp[(1) - (1)].sym)->class;
+	}
+    break;
+
+
+/* Line 1267 of yacc.c.  */
+#line 3607 "y.tab.c"
+      default: break;
+    }
+  YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
+
+  YYPOPSTACK (yylen);
+  yylen = 0;
+  YY_STACK_PRINT (yyss, yyssp);
+
+  *++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.  */
+
+  yyn = yyr1[yyn];
+
+  yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+  if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+    yystate = yytable[yystate];
+  else
+    yystate = yydefgoto[yyn - YYNTOKENS];
+
+  goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+  /* If not already recovering from an error, report this error.  */
+  if (!yyerrstatus)
+    {
+      ++yynerrs;
+#if ! YYERROR_VERBOSE
+      yyerror (YY_("syntax error"));
+#else
+      {
+	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;
+	  }
+      }
+#endif
+    }
+
+
+
+  if (yyerrstatus == 3)
+    {
+      /* If just tried and failed to reuse look-ahead token after an
+	 error, discard it.  */
+
+      if (yychar <= YYEOF)
+	{
+	  /* Return failure if at end of input.  */
+	  if (yychar == YYEOF)
+	    YYABORT;
+	}
+      else
+	{
+	  yydestruct ("Error: discarding",
+		      yytoken, &yylval);
+	  yychar = YYEMPTY;
+	}
+    }
+
+  /* Else will try to reuse look-ahead token after shifting the error
+     token.  */
+  goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR.  |
+`---------------------------------------------------*/
+yyerrorlab:
+
+  /* Pacify compilers like GCC when the user code never invokes
+     YYERROR and the label yyerrorlab therefore never appears in user
+     code.  */
+  if (/*CONSTCOND*/ 0)
+     goto yyerrorlab;
+
+  /* Do not reclaim the symbols of the rule which action triggered
+     this YYERROR.  */
+  YYPOPSTACK (yylen);
+  yylen = 0;
+  YY_STACK_PRINT (yyss, yyssp);
+  yystate = *yyssp;
+  goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR.  |
+`-------------------------------------------------------------*/
+yyerrlab1:
+  yyerrstatus = 3;	/* Each real token shifted decrements this.  */
+
+  for (;;)
+    {
+      yyn = yypact[yystate];
+      if (yyn != YYPACT_NINF)
+	{
+	  yyn += YYTERROR;
+	  if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+	    {
+	      yyn = yytable[yyn];
+	      if (0 < yyn)
+		break;
+	    }
+	}
+
+      /* Pop the current state because it cannot handle the error token.  */
+      if (yyssp == yyss)
+	YYABORT;
+
+
+      yydestruct ("Error: popping",
+		  yystos[yystate], yyvsp);
+      YYPOPSTACK (1);
+      yystate = *yyssp;
+      YY_STACK_PRINT (yyss, yyssp);
+    }
+
+  if (yyn == YYFINAL)
+    YYACCEPT;
+
+  *++yyvsp = yylval;
+
+
+  /* Shift the error token.  */
+  YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+
+  yystate = yyn;
+  goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here.  |
+`-------------------------------------*/
+yyacceptlab:
+  yyresult = 0;
+  goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here.  |
+`-----------------------------------*/
+yyabortlab:
+  yyresult = 1;
+  goto yyreturn;
+
+#ifndef yyoverflow
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here.  |
+`-------------------------------------------------*/
+yyexhaustedlab:
+  yyerror (YY_("memory exhausted"));
+  yyresult = 2;
+  /* Fall through.  */
+#endif
+
+yyreturn:
+  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);
+  YY_STACK_PRINT (yyss, yyssp);
+  while (yyssp != yyss)
+    {
+      yydestruct ("Cleanup: popping",
+		  yystos[*yyssp], yyvsp);
+      YYPOPSTACK (1);
+    }
+#ifndef yyoverflow
+  if (yyss != yyssa)
+    YYSTACK_FREE (yyss);
+#endif
+#if YYERROR_VERBOSE
+  if (yymsg != yymsgbuf)
+    YYSTACK_FREE (yymsg);
+#endif
+  /* Make sure YYID is used.  */
+  return YYID (yyresult);
+}
+
+
+#line 1220 "cc.y"
+
+
diff --git a/src/cmd/cc/y.tab.h b/src/cmd/cc/y.tab.h
new file mode 100644
index 0000000..32daca9
--- /dev/null
+++ b/src/cmd/cc/y.tab.h
@@ -0,0 +1,230 @@
+/* A Bison parser, made by GNU Bison 2.3.  */
+
+/* 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 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, 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
+   under terms of your choice, so long as that work isn't itself a
+   parser generator using the skeleton or a modified version thereof
+   as a parser skeleton.  Alternatively, if you modify or redistribute
+   the parser skeleton itself, you may (at your option) remove this
+   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
+   /* Put the tokens into the symbol table, so that GDB and other debuggers
+      know about them.  */
+   enum yytokentype {
+     LORE = 258,
+     LXORE = 259,
+     LANDE = 260,
+     LLSHE = 261,
+     LRSHE = 262,
+     LMDE = 263,
+     LDVE = 264,
+     LMLE = 265,
+     LME = 266,
+     LPE = 267,
+     LOROR = 268,
+     LANDAND = 269,
+     LNE = 270,
+     LEQ = 271,
+     LGE = 272,
+     LLE = 273,
+     LRSH = 274,
+     LLSH = 275,
+     LMG = 276,
+     LPP = 277,
+     LMM = 278,
+     LNAME = 279,
+     LTYPE = 280,
+     LFCONST = 281,
+     LDCONST = 282,
+     LCONST = 283,
+     LLCONST = 284,
+     LUCONST = 285,
+     LULCONST = 286,
+     LVLCONST = 287,
+     LUVLCONST = 288,
+     LSTRING = 289,
+     LLSTRING = 290,
+     LAUTO = 291,
+     LBREAK = 292,
+     LCASE = 293,
+     LCHAR = 294,
+     LCONTINUE = 295,
+     LDEFAULT = 296,
+     LDO = 297,
+     LDOUBLE = 298,
+     LELSE = 299,
+     LEXTERN = 300,
+     LFLOAT = 301,
+     LFOR = 302,
+     LGOTO = 303,
+     LIF = 304,
+     LINT = 305,
+     LLONG = 306,
+     LPREFETCH = 307,
+     LREGISTER = 308,
+     LRETURN = 309,
+     LSHORT = 310,
+     LSIZEOF = 311,
+     LUSED = 312,
+     LSTATIC = 313,
+     LSTRUCT = 314,
+     LSWITCH = 315,
+     LTYPEDEF = 316,
+     LTYPESTR = 317,
+     LUNION = 318,
+     LUNSIGNED = 319,
+     LWHILE = 320,
+     LVOID = 321,
+     LENUM = 322,
+     LSIGNED = 323,
+     LCONSTNT = 324,
+     LVOLATILE = 325,
+     LSET = 326,
+     LSIGNOF = 327,
+     LRESTRICT = 328,
+     LINLINE = 329
+   };
+#endif
+/* Tokens.  */
+#define LORE 258
+#define LXORE 259
+#define LANDE 260
+#define LLSHE 261
+#define LRSHE 262
+#define LMDE 263
+#define LDVE 264
+#define LMLE 265
+#define LME 266
+#define LPE 267
+#define LOROR 268
+#define LANDAND 269
+#define LNE 270
+#define LEQ 271
+#define LGE 272
+#define LLE 273
+#define LRSH 274
+#define LLSH 275
+#define LMG 276
+#define LPP 277
+#define LMM 278
+#define LNAME 279
+#define LTYPE 280
+#define LFCONST 281
+#define LDCONST 282
+#define LCONST 283
+#define LLCONST 284
+#define LUCONST 285
+#define LULCONST 286
+#define LVLCONST 287
+#define LUVLCONST 288
+#define LSTRING 289
+#define LLSTRING 290
+#define LAUTO 291
+#define LBREAK 292
+#define LCASE 293
+#define LCHAR 294
+#define LCONTINUE 295
+#define LDEFAULT 296
+#define LDO 297
+#define LDOUBLE 298
+#define LELSE 299
+#define LEXTERN 300
+#define LFLOAT 301
+#define LFOR 302
+#define LGOTO 303
+#define LIF 304
+#define LINT 305
+#define LLONG 306
+#define LPREFETCH 307
+#define LREGISTER 308
+#define LRETURN 309
+#define LSHORT 310
+#define LSIZEOF 311
+#define LUSED 312
+#define LSTATIC 313
+#define LSTRUCT 314
+#define LSWITCH 315
+#define LTYPEDEF 316
+#define LTYPESTR 317
+#define LUNION 318
+#define LUNSIGNED 319
+#define LWHILE 320
+#define LVOID 321
+#define LENUM 322
+#define LSIGNED 323
+#define LCONSTNT 324
+#define LVOLATILE 325
+#define LSET 326
+#define LSIGNOF 327
+#define LRESTRICT 328
+#define LINLINE 329
+
+
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+#line 36 "cc.y"
+{
+	Node*	node;
+	Sym*	sym;
+	Type*	type;
+	struct
+	{
+		Type*	t;
+		uchar	c;
+	} tycl;
+	struct
+	{
+		Type*	t1;
+		Type*	t2;
+		Type*	t3;
+		uchar	c;
+	} tyty;
+	struct
+	{
+		char*	s;
+		int32	l;
+	} sval;
+	int32	lval;
+	double	dval;
+	vlong	vval;
+}
+/* Line 1529 of yacc.c.  */
+#line 223 "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/cgo/ast.go b/src/cmd/cgo/ast.go
index 8bbd1cc..10e2278 100644
--- a/src/cmd/cgo/ast.go
+++ b/src/cmd/cgo/ast.go
@@ -235,17 +235,9 @@ func (f *File) saveExport(x interface{}, context string) {
 			error_(c.Pos(), "export comment has wrong name %q, want %q", name, n.Name.Name)
 		}
 
-		doc := ""
-		for _, c1 := range n.Doc.List {
-			if c1 != c {
-				doc += c1.Text + "\n"
-			}
-		}
-
 		f.ExpFunc = append(f.ExpFunc, &ExpFunc{
 			Func:    n,
 			ExpName: name,
-			Doc:     doc,
 		})
 		break
 	}
diff --git a/src/cmd/cgo/doc.go b/src/cmd/cgo/doc.go
index b2a5428..6179c7a 100644
--- a/src/cmd/cgo/doc.go
+++ b/src/cmd/cgo/doc.go
@@ -20,23 +20,16 @@ the C parts of the package.  For example:
 	// #include <errno.h>
 	import "C"
 
-The preamble may contain any C code, including function and variable
-declarations and definitions.  These may then be referred to from Go
-code as though they were defined in the package "C".  All names
-declared in the preamble may be used, even if they start with a
-lower-case letter.  Exception: static variables in the preamble may
-not be referenced from Go code; static functions are permitted.
-
 See $GOROOT/misc/cgo/stdio and $GOROOT/misc/cgo/gmp for examples.  See
 "C? Go? Cgo!" for an introduction to using cgo:
-https://golang.org/doc/articles/c_go_cgo.html.
+http://golang.org/doc/articles/c_go_cgo.html.
 
 CFLAGS, CPPFLAGS, CXXFLAGS and LDFLAGS may be defined with pseudo #cgo
 directives within these comments to tweak the behavior of the C or C++
 compiler.  Values defined in multiple directives are concatenated
 together.  The directive can include a list of build constraints limiting its
 effect to systems satisfying one of the constraints
-(see https://golang.org/pkg/go/build/#hdr-Build_Constraints for details about the constraint syntax).
+(see http://golang.org/pkg/go/build/#hdr-Build_Constraints for details about the constraint syntax).
 For example:
 
 	// #cgo CFLAGS: -DPNG_DEBUG=1
@@ -67,18 +60,6 @@ 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 cgo directives are parsed, any occurrence of the string ${SRCDIR}
-will be replaced by the absolute path to the directory containing the source
-file. This allows pre-compiled static libraries to be included in the package
-directory and linked properly.
-For example if package foo is in the directory /go/src/foo:
-
-       // #cgo LDFLAGS: -L${SRCDIR}/libs -lfoo
-
-Will be expanded to:
-
-       // #cgo LDFLAGS: -L/go/src/foo/libs -lfoo
-
 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
@@ -90,19 +71,17 @@ compilers may be changed by the CC and CXX environment variables,
 respectively; those environment variables may include command line
 options.
 
-The cgo tool is enabled by default for native builds on systems where
-it is expected to work.  It is disabled by default when
-cross-compiling.  You can control this by setting the CGO_ENABLED
-environment variable when running the go tool: set it to 1 to enable
-the use of cgo, and to 0 to disable it.  The go tool will set the
-build constraint "cgo" if cgo is enabled.
+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.
 
-When cross-compiling, you must specify a C cross-compiler for cgo to
-use.  You can do this by setting the CC_FOR_TARGET environment
-variable when building the toolchain using make.bash, or by setting
-the CC environment variable any time you run the go tool.  The
-CXX_FOR_TARGET and CXX environment variables work in a similar way for
-C++ code.
+CXX_FOR_TARGET works in a similar way for C++ code.
 
 Go references to C
 
@@ -216,18 +195,16 @@ Not all Go types can be mapped to C types in a useful way.
 
 Using //export in a file places a restriction on the preamble:
 since it is copied into two different C output files, it must not
-contain any definitions, only declarations. If a file contains both
-definitions and declarations, then the two output files will produce
-duplicate symbols and the linker will fail. To avoid this, definitions
-must be placed in preambles in other files, or in C source files.
+contain any definitions, only declarations. Definitions must be
+placed in preambles in other files, or in C source files.
 
 Using cgo directly
 
 Usage:
-	go tool cgo [cgo options] [-- compiler options] gofiles...
+	go tool cgo [cgo options] [-- compiler options] file.go
 
-Cgo transforms the specified input Go source files into several output
-Go and C source files.
+Cgo transforms the input file.go into four output files: two Go source
+files, a C file for 6c (or 8c or 5c), and a C file for gcc.
 
 The compiler options are passed through uninterpreted when
 invoking the C compiler to compile the C parts of the package.
@@ -240,23 +217,18 @@ The following options are available when running cgo directly:
 		build when building a cgo package.
 	-dynout file
 		Write -dynimport output to file.
-	-dynpackage package
-		Set Go package for -dynimport output.
 	-dynlinker
 		Write dynamic linker as part of -dynimport output.
 	-godefs
 		Write out input file in Go syntax replacing C package
 		names with real values. Used to generate files in the
 		syscall package when bootstrapping a new target.
+	-cdefs
+		Like -godefs, but write file in C syntax.
+		Used to generate files in the runtime package when
+		bootstrapping a new target.
 	-objdir directory
 		Put all generated files in directory.
-	-importpath string
-		The import path for the Go package. Optional; used for
-		nicer comments in the generated files.
-	-exportheader file
-		If there are any exported functions, write the
-		generated export declarations to file.
-		C code can #include this to see the declarations.
 	-gccgo
 		Generate output for the gccgo compiler rather than the
 		gc compiler.
@@ -391,9 +363,9 @@ the translation process.
 
 Translating Go
 
-[The rest of this comment refers to 6g, the Go compiler that is part
-of the amd64 port of the gc Go toolchain. Everything here applies to
-another architecture's compilers as well.]
+[The rest of this comment refers to 6g and 6c, the Go and C compilers
+that are part of the amd64 port of the gc Go toolchain. Everything here
+applies to another architecture's compilers as well.]
 
 Given the input Go files x.go and y.go, cgo generates these source
 files:
@@ -401,41 +373,44 @@ files:
 	x.cgo1.go       # for 6g
 	y.cgo1.go       # for 6g
 	_cgo_gotypes.go # for 6g
-	_cgo_import.go  # for 6g (if -dynout _cgo_import.go)
+	_cgo_defun.c    # for 6c
 	x.cgo2.c        # for gcc
 	y.cgo2.c        # for gcc
-	_cgo_defun.c    # for gcc (if -gccgo)
 	_cgo_export.c   # for gcc
-	_cgo_export.h   # for gcc
 	_cgo_main.c     # for gcc
-	_cgo_flags      # for alternative build tools
 
 The file x.cgo1.go is a copy of x.go with the import "C" removed and
 references to C.xxx replaced with names like _Cfunc_xxx or _Ctype_xxx.
 The definitions of those identifiers, written as Go functions, types,
 or variables, are provided in _cgo_gotypes.go.
 
-Here is a _cgo_gotypes.go containing definitions for needed C types:
+Here is a _cgo_gotypes.go containing definitions for C.flush (provided
+in the preamble) and C.puts (from stdio):
 
 	type _Ctype_char int8
 	type _Ctype_int int32
 	type _Ctype_void [0]byte
 
-The _cgo_gotypes.go file also contains the definitions of the
-functions.  They all have similar bodies that invoke runtime·cgocall
-to make a switch from the Go runtime world to the system C (GCC-based)
-world.
+	func _Cfunc_CString(string) *_Ctype_char
+	func _Cfunc_flush() _Ctype_void
+	func _Cfunc_puts(*_Ctype_char) _Ctype_int
+
+For functions, cgo only writes an external declaration in the Go
+output. The implementation is in a combination of C for 6c (meaning
+any gc-toolchain compiler) and C for gcc.
+
+The 6c file contains the definitions of the functions. They all have
+similar bodies that invoke runtime·cgocall to make a switch from the
+Go runtime world to the system C (GCC-based) world.
 
 For example, here is the definition of _Cfunc_puts:
 
-	//go:cgo_import_static _cgo_be59f0f25121_Cfunc_puts
-	//go:linkname __cgofn__cgo_be59f0f25121_Cfunc_puts _cgo_be59f0f25121_Cfunc_puts
-	var __cgofn__cgo_be59f0f25121_Cfunc_puts byte
-	var _cgo_be59f0f25121_Cfunc_puts = unsafe.Pointer(&__cgofn__cgo_be59f0f25121_Cfunc_puts)
+	void _cgo_be59f0f25121_Cfunc_puts(void*);
 
-	func _Cfunc_puts(p0 *_Ctype_char) (r1 _Ctype_int) {
-		_cgo_runtime_cgocall(_cgo_be59f0f25121_Cfunc_puts, uintptr(unsafe.Pointer(&p0)))
-		return
+	void
+	·_Cfunc_puts(struct{uint8 x[1];}p)
+	{
+		runtime·cgocall(_cgo_be59f0f25121_Cfunc_puts, &p);
 	}
 
 The hexadecimal number is a hash of cgo's input, chosen to be
@@ -446,7 +421,6 @@ file compiled by gcc, the file x.cgo2.c:
 	void
 	_cgo_be59f0f25121_Cfunc_puts(void *v)
 	{
-		_cgo_wait_runtime_init_done();
 		struct {
 			char* p0;
 			int r;
@@ -455,8 +429,7 @@ file compiled by gcc, the file x.cgo2.c:
 		a->r = puts((void*)a->p0);
 	}
 
-It waits for Go runtime to be initialized (required for shared libraries),
-extracts the arguments from the pointer to _Cfunc_puts's argument
+It extracts the arguments from the pointer to _Cfunc_puts's argument
 frame, invokes the system C function (in this case, puts), stores the
 result in the frame, and returns.
 
@@ -475,7 +448,6 @@ _cgo_main.c:
 
 	int main() { return 0; }
 	void crosscall2(void(*fn)(void*, int), void *a, int c) { }
-	void _cgo_wait_runtime_init_done() { }
 	void _cgo_allocate(void *a, int c) { }
 	void _cgo_panic(void *a, int c) { }
 
@@ -484,21 +456,23 @@ code generated for gcc. The build process links this stub, along with
 _cgo_export.c and *.cgo2.c, into a dynamic executable and then lets
 cgo examine the executable. Cgo records the list of shared library
 references and resolved names and writes them into a new file
-_cgo_import.go, which looks like:
+_cgo_import.c, which looks like:
 
-	//go:cgo_dynamic_linker "/lib64/ld-linux-x86-64.so.2"
-	//go:cgo_import_dynamic puts puts#GLIBC_2.2.5 "libc.so.6"
-	//go:cgo_import_dynamic __libc_start_main __libc_start_main#GLIBC_2.2.5 "libc.so.6"
-	//go:cgo_import_dynamic stdout stdout#GLIBC_2.2.5 "libc.so.6"
-	//go:cgo_import_dynamic fflush fflush#GLIBC_2.2.5 "libc.so.6"
-	//go:cgo_import_dynamic _ _ "libpthread.so.0"
-	//go:cgo_import_dynamic _ _ "libc.so.6"
+	#pragma cgo_dynamic_linker "/lib64/ld-linux-x86-64.so.2"
+	#pragma cgo_import_dynamic puts puts#GLIBC_2.2.5 "libc.so.6"
+	#pragma cgo_import_dynamic __libc_start_main __libc_start_main#GLIBC_2.2.5 "libc.so.6"
+	#pragma cgo_import_dynamic stdout stdout#GLIBC_2.2.5 "libc.so.6"
+	#pragma cgo_import_dynamic fflush fflush#GLIBC_2.2.5 "libc.so.6"
+	#pragma cgo_import_dynamic _ _ "libpthread.so.0"
+	#pragma cgo_import_dynamic _ _ "libc.so.6"
 
 In the end, the compiled Go package, which will eventually be
 presented to 6l as part of a larger program, contains:
 
-	_go_.6        # 6g-compiled object for _cgo_gotypes.go, _cgo_import.go, *.cgo1.go
+	_go_.6        # 6g-compiled object for _cgo_gotypes.go *.cgo1.go
+	_cgo_defun.6  # 6c-compiled object for _cgo_defun.c
 	_all.o        # gcc-compiled object for _cgo_export.c, *.cgo2.c
+	_cgo_import.6 # 6c-compiled object for _cgo_import.c
 
 The final program will be a dynamic executable, so that 6l can avoid
 needing to process arbitrary .o files. It only needs to process the .o
@@ -522,21 +496,20 @@ Runtime
 
 When using cgo, Go must not assume that it owns all details of the
 process. In particular it needs to coordinate with C in the use of
-threads and thread-local storage. The runtime package declares a few
+threads and thread-local storage. The runtime package, in its own
+(6c-compiled) C code, declares a few uninitialized (default bss)
 variables:
 
-	var (
-		iscgo             bool
-		_cgo_init         unsafe.Pointer
-		_cgo_thread_start unsafe.Pointer
-	)
+	bool	runtime·iscgo;
+	void	(*libcgo_thread_start)(void*);
+	void	(*initcgo)(G*);
 
 Any package using cgo imports "runtime/cgo", which provides
-initializations for these variables. It sets iscgo to true, _cgo_init
-to a gcc-compiled function that can be called early during program
-startup, and _cgo_thread_start to a gcc-compiled function that can be
-used to create a new thread, in place of the runtime's usual direct
-system calls.
+initializations for these variables. It sets iscgo to 1, initcgo to a
+gcc-compiled function that can be called early during program startup,
+and libcgo_thread_start to a gcc-compiled function that can be used to
+create a new thread, in place of the runtime's usual direct system
+calls.
 
 Internal and External Linking
 
@@ -549,12 +522,12 @@ code can only be used as a dynamic library). On the other hand, when
 using internal linking, 6l can generate Go binaries by itself.
 
 In order to allow linking arbitrary object files without requiring
-dynamic libraries, cgo supports an "external" linking mode too. In
-external linking mode, 6l does not process any host object files.
-Instead, it collects all the Go code and writes a single go.o object
-file containing it. Then it invokes the host linker (usually gcc) to
-combine the go.o object file and any supporting non-Go code into a
-final executable. External linking avoids the dynamic library
+dynamic libraries, cgo will soon support an "external" linking mode
+too. In external linking mode, 6l does not process any host object
+files. Instead, it collects all the Go code and writes a single go.o
+object file containing it. Then it invokes the host linker (usually
+gcc) to combine the go.o object file and any supporting non-Go code
+into a final executable. External linking avoids the dynamic library
 requirement but introduces a requirement that the host linker be
 present to create such a binary.
 
@@ -582,13 +555,13 @@ to be made when linking the final binary.
 Linking Directives
 
 In either linking mode, package-specific directives must be passed
-through to 6l. These are communicated by writing //go: directives in a
-Go source file compiled by 6g. The directives are copied into the .6
-object file and then processed by the linker.
+through to 6l. These are communicated by writing #pragma directives
+in a C source file compiled by 6c. The directives are copied into the .6 object file
+and then processed by the linker.
 
 The directives are:
 
-//go:cgo_import_dynamic <local> [<remote> ["<library>"]]
+#pragma cgo_import_dynamic <local> [<remote> ["<library>"]]
 
 	In internal linking mode, allow an unresolved reference to
 	<local>, assuming it will be resolved by a dynamic library
@@ -599,9 +572,9 @@ The directives are:
 	In the <remote>, # or @ can be used to introduce a symbol version.
 
 	Examples:
-	//go:cgo_import_dynamic puts
-	//go:cgo_import_dynamic puts puts#GLIBC_2.2.5
-	//go:cgo_import_dynamic puts puts#GLIBC_2.2.5 "libc.so.6"
+	#pragma cgo_import_dynamic puts
+	#pragma cgo_import_dynamic puts puts#GLIBC_2.2.5
+	#pragma cgo_import_dynamic puts puts#GLIBC_2.2.5 "libc.so.6"
 
 	A side effect of the cgo_import_dynamic directive with a
 	library is to make the final binary depend on that dynamic
@@ -609,12 +582,12 @@ The directives are:
 	symbols, use _ for local and remote.
 
 	Example:
-	//go:cgo_import_dynamic _ _ "libc.so.6"
+	#pragma cgo_import_dynamic _ _ "libc.so.6"
 
 	For compatibility with current versions of SWIG,
-	#pragma dynimport is an alias for //go:cgo_import_dynamic.
+	#pragma dynimport is an alias for #pragma cgo_import_dynamic.
 
-//go:cgo_dynamic_linker "<path>"
+#pragma cgo_dynamic_linker "<path>"
 
 	In internal linking mode, use "<path>" as the dynamic linker
 	in the final binary. This directive is only needed from one
@@ -622,9 +595,9 @@ The directives are:
 	supplied by runtime/cgo.
 
 	Example:
-	//go:cgo_dynamic_linker "/lib/ld-linux.so.2"
+	#pragma cgo_dynamic_linker "/lib/ld-linux.so.2"
 
-//go:cgo_export_dynamic <local> <remote>
+#pragma cgo_export_dynamic <local> <remote>
 
 	In internal linking mode, put the Go symbol
 	named <local> into the program's exported symbol table as
@@ -633,9 +606,9 @@ The directives are:
 	to share Go's data.
 
 	For compatibility with current versions of SWIG,
-	#pragma dynexport is an alias for //go:cgo_export_dynamic.
+	#pragma dynexport is an alias for #pragma cgo_export_dynamic.
 
-//go:cgo_import_static <local>
+#pragma cgo_import_static <local>
 
 	In external linking mode, allow unresolved references to
 	<local> in the go.o object file prepared for the host linker,
@@ -643,9 +616,9 @@ The directives are:
 	other object files that will be linked with go.o.
 
 	Example:
-	//go:cgo_import_static puts_wrapper
+	#pragma cgo_import_static puts_wrapper
 
-//go:cgo_export_static <local> <remote>
+#pragma cgo_export_static <local> <remote>
 
 	In external linking mode, put the Go symbol
 	named <local> into the program's exported symbol table as
@@ -653,15 +626,15 @@ The directives are:
 	mechanism makes it possible for C code to call back into Go or
 	to share Go's data.
 
-//go:cgo_ldflag "<arg>"
+#pragma cgo_ldflag "<arg>"
 
 	In external linking mode, invoke the host linker (usually gcc)
 	with "<arg>" as a command-line argument following the .o files.
 	Note that the arguments are for "gcc", not "ld".
 
 	Example:
-	//go:cgo_ldflag "-lpthread"
-	//go:cgo_ldflag "-L/usr/local/sqlite3/lib"
+	#pragma cgo_ldflag "-lpthread"
+	#pragma cgo_ldflag "-L/usr/local/sqlite3/lib"
 
 A package compiled with cgo will include directives for both
 internal and external linking; the linker will select the appropriate
@@ -674,18 +647,22 @@ The following code will be generated by cgo:
 
 	// compiled by 6g
 
-	//go:cgo_ldflag "-lm"
-
 	type _Ctype_double float64
+	func _Cfunc_sin(_Ctype_double) _Ctype_double
+
+	// compiled by 6c
 
-	//go:cgo_import_static _cgo_gcc_Cfunc_sin
-	//go:linkname __cgo_gcc_Cfunc_sin _cgo_gcc_Cfunc_sin
-	var __cgo_gcc_Cfunc_sin byte
-	var _cgo_gcc_Cfunc_sin = unsafe.Pointer(&__cgo_gcc_Cfunc_sin)
+	#pragma cgo_import_dynamic sin sin#GLIBC_2.2.5 "libm.so.6"
 
-	func _Cfunc_sin(p0 _Ctype_double) (r1 _Ctype_double) {
-		_cgo_runtime_cgocall(_cgo_gcc_Cfunc_sin, uintptr(unsafe.Pointer(&p0)))
-		return
+	#pragma cgo_import_static _cgo_gcc_Cfunc_sin
+	#pragma cgo_ldflag "-lm"
+
+	void _cgo_gcc_Cfunc_sin(void*);
+
+	void
+	·_Cfunc_sin(struct{uint8 x[16];}p)
+	{
+		runtime·cgocall(_cgo_gcc_Cfunc_sin, &p);
 	}
 
 	// compiled by gcc, into foo.cgo2.o
@@ -705,8 +682,8 @@ using the internal or external mode. If other packages are compiled in
 "external only" mode, then the final link will be an external one.
 Otherwise the link will be an internal one.
 
-The linking directives are used according to the kind of final link
-used.
+The directives in the 6c-compiled file are used according to the kind
+of final link used.
 
 In internal mode, 6l itself processes all the host object files, in
 particular foo.cgo2.o. To do so, it uses the cgo_import_dynamic and
@@ -717,10 +694,10 @@ symbol sin with version GLIBC_2.2.5 from the dynamic library
 runtime dynamic linker.
 
 In external mode, 6l does not process any host object files, in
-particular foo.cgo2.o. It links together the 6g-generated object
-files, along with any other Go code, into a go.o file. While doing
-that, 6l will discover that there is no definition for
-_cgo_gcc_Cfunc_sin, referred to by the 6g-compiled source file. This
+particular foo.cgo2.o. It links together the 6g- and 6c-generated
+object files, along with any other Go code, into a go.o file. While
+doing that, 6l will discover that there is no definition for
+_cgo_gcc_Cfunc_sin, referred to by the 6c-compiled source file. This
 is okay, because 6l also processes the cgo_import_static directive and
 knows that _cgo_gcc_Cfunc_sin is expected to be supplied by a host
 object file, so 6l does not treat the missing symbol as an error when
diff --git a/src/cmd/cgo/gcc.go b/src/cmd/cgo/gcc.go
index b64849a..abdd369 100644
--- a/src/cmd/cgo/gcc.go
+++ b/src/cmd/cgo/gcc.go
@@ -154,6 +154,20 @@ func splitQuoted(s string) (r []string, err error) {
 	return args, err
 }
 
+var safeBytes = []byte(`+-.,/0123456789:=ABCDEFGHIJKLMNOPQRSTUVWXYZ\_abcdefghijklmnopqrstuvwxyz`)
+
+func safeName(s string) bool {
+	if s == "" {
+		return false
+	}
+	for i := 0; i < len(s); i++ {
+		if c := s[i]; c < 0x80 && bytes.IndexByte(safeBytes, c) < 0 {
+			return false
+		}
+	}
+	return true
+}
+
 // Translate rewrites f.AST, the original Go input, to remove
 // references to the imported package C, replacing them with
 // references to the equivalent Go types, functions, and variables.
@@ -199,10 +213,6 @@ func (p *Package) loadDefines(f *File) {
 			val = strings.TrimSpace(line[tabIndex:])
 		}
 
-		if key == "__clang__" {
-			p.GccIsClang = true
-		}
-
 		if n := f.Name[key]; n != nil {
 			if *debugDefine {
 				fmt.Fprintf(os.Stderr, "#define %s %s\n", key, val)
@@ -572,7 +582,7 @@ func (p *Package) mangleName(n *Name) {
 
 // rewriteRef rewrites all the C.xxx references in f.AST to refer to the
 // Go equivalents, now that we have figured out the meaning of all
-// the xxx.  In *godefs mode, rewriteRef replaces the names
+// the xxx.  In *godefs or *cdefs mode, rewriteRef replaces the names
 // with full definitions instead of mangled names.
 func (p *Package) rewriteRef(f *File) {
 	// Keep a list of all the functions, to remove the ones
@@ -663,13 +673,6 @@ func (p *Package) rewriteRef(f *File) {
 				expr = &ast.StarExpr{Star: (*r.Expr).Pos(), X: expr}
 			}
 
-		case "selector":
-			if r.Name.Kind == "var" {
-				expr = &ast.StarExpr{Star: (*r.Expr).Pos(), X: expr}
-			} else {
-				error_(r.Pos(), "only C variables allowed in selector expression", fixGo(r.Name.Go))
-			}
-
 		case "type":
 			if r.Name.Kind != "type" {
 				error_(r.Pos(), "expression C.%s used as type", fixGo(r.Name.Go))
@@ -685,7 +688,7 @@ func (p *Package) rewriteRef(f *File) {
 				error_(r.Pos(), "must call C.%s", fixGo(r.Name.Go))
 			}
 		}
-		if *godefs {
+		if *godefs || *cdefs {
 			// Substitute definition for mangled type name.
 			if id, ok := expr.(*ast.Ident); ok {
 				if t := typedef[id.Name]; t != nil {
@@ -743,10 +746,6 @@ func (p *Package) gccMachine() []string {
 		return []string{"-m32"}
 	case "arm":
 		return []string{"-marm"} // not thumb
-	case "s390":
-		return []string{"-m31"}
-	case "s390x":
-		return []string{"-m64"}
 	}
 	return nil
 }
@@ -766,7 +765,7 @@ func (p *Package) gccCmd() []string {
 		"-c",          // do not link
 		"-xc",         // input language is C
 	)
-	if p.GccIsClang {
+	if strings.Contains(c[0], "clang") {
 		c = append(c,
 			"-ferror-limit=0",
 			// Apple clang version 1.7 (tags/Apple/clang-77) (based on LLVM 2.9svn)
@@ -781,7 +780,7 @@ func (p *Package) gccCmd() []string {
 			// incorrectly typed unsigned long. We work around that
 			// by disabling the builtin functions (this is safe as
 			// it won't affect the actual compilation of the C code).
-			// See: https://golang.org/issue/6506.
+			// See: http://golang.org/issue/6506.
 			"-fno-builtin",
 		)
 	}
@@ -993,8 +992,8 @@ func (c *typeConv) Init(ptrSize, intSize int64) {
 	c.goVoid = c.Ident("_Ctype_void")
 
 	// Normally cgo translates void* to unsafe.Pointer,
-	// but for historical reasons -godefs uses *byte instead.
-	if *godefs {
+	// but for historical reasons -cdefs and -godefs use *byte instead.
+	if *cdefs || *godefs {
 		c.goVoidPtr = &ast.StarExpr{X: c.byte}
 	} else {
 		c.goVoidPtr = c.Ident("unsafe.Pointer")
@@ -1046,7 +1045,7 @@ func (tr *TypeRepr) String() string {
 	return fmt.Sprintf(tr.Repr, tr.FormatArgs...)
 }
 
-// Empty reports whether the result of String would be "".
+// Empty returns true if the result of String would be "".
 func (tr *TypeRepr) Empty() bool {
 	return len(tr.Repr) == 0
 }
@@ -1335,8 +1334,8 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
 		// 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 mode, do this for all typedefs.
-		if isStructUnionClass(sub.Go) || *godefs {
+		// In -godefs and -cdefs mode, do this for all typedefs.
+		if isStructUnionClass(sub.Go) || *godefs || *cdefs {
 			t.Go = sub.Go
 
 			if isStructUnionClass(sub.Go) {
@@ -1398,7 +1397,7 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
 			name := c.Ident("_Ctype_" + s)
 			tt := *t
 			typedef[name.Name] = &tt
-			if !*godefs {
+			if !*godefs && !*cdefs {
 				t.Go = name
 			}
 		}
@@ -1544,16 +1543,14 @@ func (c *typeConv) intExpr(n int64) ast.Expr {
 }
 
 // Add padding of given size to fld.
-func (c *typeConv) pad(fld []*ast.Field, sizes []int64, size int64) ([]*ast.Field, []int64) {
+func (c *typeConv) pad(fld []*ast.Field, size int64) []*ast.Field {
 	n := len(fld)
 	fld = fld[0 : n+1]
 	fld[n] = &ast.Field{Names: []*ast.Ident{c.Ident("_")}, Type: c.Opaque(size)}
-	sizes = sizes[0 : n+1]
-	sizes[n] = size
-	return fld, sizes
+	return fld
 }
 
-// Struct conversion: return Go and (gc) C syntax for type.
+// Struct conversion: return Go and (6g) C syntax for type.
 func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.StructType, csyntax string, align int64) {
 	// Minimum alignment for a struct is 1 byte.
 	align = 1
@@ -1561,7 +1558,6 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct
 	var buf bytes.Buffer
 	buf.WriteString("struct {")
 	fld := make([]*ast.Field, 0, 2*len(dt.Field)+1) // enough for padding around every field
-	sizes := make([]int64, 0, 2*len(dt.Field)+1)
 	off := int64(0)
 
 	// Rename struct fields that happen to be named Go keywords into
@@ -1577,7 +1573,7 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct
 		used[f.Name] = true
 	}
 
-	if !*godefs {
+	if !*godefs && !*cdefs {
 		for cid, goid := range ident {
 			if token.Lookup(goid).IsKeyword() {
 				// Avoid keyword
@@ -1597,19 +1593,19 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct
 	anon := 0
 	for _, f := range dt.Field {
 		if f.ByteOffset > off {
-			fld, sizes = c.pad(fld, sizes, f.ByteOffset-off)
+			fld = c.pad(fld, f.ByteOffset-off)
 			off = f.ByteOffset
 		}
 
 		name := f.Name
 		ft := f.Type
 
-		// In godefs mode, if this field is a C11
+		// In godefs or cdefs mode, if this field is a C11
 		// anonymous union then treat the first field in the
 		// union as the field in the struct.  This handles
 		// cases like the glibc <sys/resource.h> file; see
 		// issue 6677.
-		if *godefs {
+		if *godefs || *cdefs {
 			if st, ok := f.Type.(*dwarf.StructType); ok && name == "" && st.Kind == "union" && len(st.Field) > 0 && !used[st.Field[0].Name] {
 				name = st.Field[0].Name
 				ident[name] = name
@@ -1639,12 +1635,14 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct
 			talign = size
 		}
 
-		if talign > 0 && f.ByteOffset%talign != 0 {
+		if talign > 0 && f.ByteOffset%talign != 0 && !*cdefs {
 			// 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.
+			// Exception: In -cdefs mode, we use #pragma pack, so misaligned
+			// fields should still work.
 			continue
 		}
 		n := len(fld)
@@ -1655,8 +1653,6 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct
 			ident[name] = name
 		}
 		fld[n] = &ast.Field{Names: []*ast.Ident{c.Ident(ident[name])}, Type: tgo}
-		sizes = sizes[0 : n+1]
-		sizes[n] = size
 		off += size
 		buf.WriteString(t.C.String())
 		buf.WriteString(" ")
@@ -1667,29 +1663,16 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct
 		}
 	}
 	if off < dt.ByteSize {
-		fld, sizes = c.pad(fld, sizes, dt.ByteSize-off)
+		fld = c.pad(fld, dt.ByteSize-off)
 		off = dt.ByteSize
 	}
-
-	// If the last field in a non-zero-sized struct is zero-sized
-	// the compiler is going to pad it by one (see issue 9401).
-	// We can't permit that, because then the size of the Go
-	// struct will not be the same as the size of the C struct.
-	// Our only option in such a case is to remove the field,
-	// which means that it can not be referenced from Go.
-	for off > 0 && sizes[len(sizes)-1] == 0 {
-		n := len(sizes)
-		fld = fld[0 : n-1]
-		sizes = sizes[0 : n-1]
-	}
-
 	if off != dt.ByteSize {
 		fatalf("%s: struct size calculation error off=%d bytesize=%d", lineno(pos), off, dt.ByteSize)
 	}
 	buf.WriteString("}")
 	csyntax = buf.String()
 
-	if *godefs {
+	if *godefs || *cdefs {
 		godefsFields(fld)
 	}
 	expr = &ast.StructType{Fields: &ast.FieldList{List: fld}}
@@ -1724,7 +1707,9 @@ func godefsFields(fld []*ast.Field) {
 				n.Name = "Pad_cgo_" + strconv.Itoa(npad)
 				npad++
 			}
-			n.Name = upper(n.Name)
+			if !*cdefs {
+				n.Name = upper(n.Name)
+			}
 		}
 	}
 }
@@ -1736,6 +1721,9 @@ func godefsFields(fld []*ast.Field) {
 // package syscall's data structures, we drop a common prefix
 // (so sec, usec, which will get turned into Sec, Usec for exporting).
 func fieldPrefix(fld []*ast.Field) string {
+	if *cdefs {
+		return ""
+	}
 	prefix := ""
 	for _, f := range fld {
 		for _, n := range f.Names {
diff --git a/src/cmd/cgo/godefs.go b/src/cmd/cgo/godefs.go
index 1b0ece2..ce5ac27 100644
--- a/src/cmd/cgo/godefs.go
+++ b/src/cmd/cgo/godefs.go
@@ -114,6 +114,173 @@ func (p *Package) godefs(f *File, srcfile string) string {
 	return buf.String()
 }
 
+// cdefs returns the output for -cdefs mode.
+// The easiest way to do this is to translate the godefs Go to C.
+func (p *Package) cdefs(f *File, srcfile string) string {
+	godefsOutput := p.godefs(f, srcfile)
+
+	lines := strings.Split(godefsOutput, "\n")
+	lines[0] = "// Created by cgo -cdefs - DO NOT EDIT"
+
+	for i, line := range lines {
+		lines[i] = strings.TrimSpace(line)
+	}
+
+	var out bytes.Buffer
+	printf := func(format string, args ...interface{}) { fmt.Fprintf(&out, format, args...) }
+
+	didTypedef := false
+	for i := 0; i < len(lines); i++ {
+		line := lines[i]
+
+		// Delete
+		//	package x
+		if strings.HasPrefix(line, "package ") {
+			continue
+		}
+
+		// Convert
+		//	const (
+		//		A = 1
+		//		B = 2
+		//	)
+		//
+		// to
+		//
+		//	enum {
+		//		A = 1,
+		//		B = 2,
+		//	};
+		if line == "const (" {
+			printf("enum {\n")
+			for i++; i < len(lines) && lines[i] != ")"; i++ {
+				line = lines[i]
+				if line != "" {
+					printf("\t%s,", line)
+				}
+				printf("\n")
+			}
+			printf("};\n")
+			continue
+		}
+
+		// Convert
+		//	const A = 1
+		// to
+		//	enum { A = 1 };
+		if strings.HasPrefix(line, "const ") {
+			printf("enum { %s };\n", line[len("const "):])
+			continue
+		}
+
+		// On first type definition, typedef all the structs
+		// in case there are dependencies between them.
+		if !didTypedef && strings.HasPrefix(line, "type ") {
+			didTypedef = true
+			for _, line := range lines {
+				line = strings.TrimSpace(line)
+				if strings.HasPrefix(line, "type ") && strings.HasSuffix(line, " struct {") {
+					s := strings.TrimSuffix(strings.TrimPrefix(line, "type "), " struct {")
+					printf("typedef struct %s %s;\n", s, s)
+				}
+			}
+			printf("\n")
+			printf("#pragma pack on\n")
+			printf("\n")
+		}
+
+		// Convert
+		//	type T struct {
+		//		X int64
+		//		Y *int32
+		//		Z [4]byte
+		//	}
+		//
+		// to
+		//
+		//	struct T {
+		//		int64 X;
+		//		int32 *Y;
+		//		byte Z[4];
+		//	}
+		if strings.HasPrefix(line, "type ") && strings.HasSuffix(line, " struct {") {
+			if len(lines) > i+1 && lines[i+1] == "}" {
+				// do not output empty struct
+				i++
+				continue
+			}
+			s := line[len("type ") : len(line)-len(" struct {")]
+			printf("struct %s {\n", s)
+			for i++; i < len(lines) && lines[i] != "}"; i++ {
+				line := lines[i]
+				if line != "" {
+					f := strings.Fields(line)
+					if len(f) != 2 {
+						fmt.Fprintf(os.Stderr, "cgo: cannot parse struct field: %s\n", line)
+						nerrors++
+						continue
+					}
+					printf("\t%s;", cdecl(f[0], f[1]))
+				}
+				printf("\n")
+			}
+			printf("};\n")
+			continue
+		}
+
+		// Convert
+		//	type T int
+		// to
+		//	typedef int T;
+		if strings.HasPrefix(line, "type ") {
+			f := strings.Fields(line[len("type "):])
+			if len(f) != 2 {
+				fmt.Fprintf(os.Stderr, "cgo: cannot parse type definition: %s\n", line)
+				nerrors++
+				continue
+			}
+			printf("typedef\t%s;\n", cdecl(f[0], f[1]))
+			continue
+		}
+
+		printf("%s\n", line)
+	}
+
+	if didTypedef {
+		printf("\n")
+		printf("#pragma pack off\n")
+	}
+
+	return out.String()
+}
+
+// cdecl returns the C declaration for the given Go name and type.
+// It only handles the specific cases necessary for converting godefs output.
+func cdecl(name, typ string) string {
+	// X *[0]byte -> X *void
+	if strings.HasPrefix(typ, "*[0]") {
+		typ = "*void"
+	}
+	// X [4]byte -> X[4] byte
+	for strings.HasPrefix(typ, "[") {
+		i := strings.Index(typ, "]") + 1
+		name = name + typ[:i]
+		typ = typ[i:]
+	}
+	// X *byte -> *X byte
+	for strings.HasPrefix(typ, "*") {
+		name = "*" + name
+		typ = typ[1:]
+	}
+	// X T -> T X
+	// Handle the special case: 'unsafe.Pointer' is 'void *'
+	if typ == "unsafe.Pointer" {
+		typ = "void"
+		name = "*" + name
+	}
+	return typ + "\t" + name
+}
+
 var gofmtBuf bytes.Buffer
 
 // gofmt returns the gofmt-formatted string for an AST node.
diff --git a/src/cmd/cgo/main.go b/src/cmd/cgo/main.go
index 02d297c..17b0cdd 100644
--- a/src/cmd/cgo/main.go
+++ b/src/cmd/cgo/main.go
@@ -6,7 +6,7 @@
 
 // TODO(rsc):
 //	Emit correct line number annotations.
-//	Make gc understand the annotations.
+//	Make 6g understand the annotations.
 
 package main
 
@@ -33,7 +33,6 @@ type Package struct {
 	PtrSize     int64
 	IntSize     int64
 	GccOptions  []string
-	GccIsClang  bool
 	CgoFlags    map[string][]string // #cgo flags (CFLAGS, LDFLAGS)
 	Written     map[string]bool
 	Name        map[string]*Name // accumulated Name from Files
@@ -88,7 +87,7 @@ type Name struct {
 	Const    string // constant definition
 }
 
-// IsVar reports whether Kind is either "var" or "fpvar"
+// IsVar returns true if Kind is either "var" or "fpvar"
 func (n *Name) IsVar() bool {
 	return n.Kind == "var" || n.Kind == "fpvar"
 }
@@ -99,7 +98,6 @@ func (n *Name) IsVar() bool {
 type ExpFunc struct {
 	Func    *ast.FuncDecl
 	ExpName string // name to use from C
-	Doc     string
 }
 
 // A TypeRepr contains the string representation of a type.
@@ -132,25 +130,15 @@ func usage() {
 }
 
 var ptrSizeMap = map[string]int64{
-	"386":     4,
-	"amd64":   8,
-	"arm":     4,
-	"arm64":   8,
-	"ppc64":   8,
-	"ppc64le": 8,
-	"s390":    4,
-	"s390x":   8,
+	"386":   4,
+	"amd64": 8,
+	"arm":   4,
 }
 
 var intSizeMap = map[string]int64{
-	"386":     4,
-	"amd64":   8,
-	"arm":     4,
-	"arm64":   8,
-	"ppc64":   8,
-	"ppc64le": 8,
-	"s390":    4,
-	"s390x":   4,
+	"386":   4,
+	"amd64": 8,
+	"arm":   4,
 }
 
 var cPrefix string
@@ -158,18 +146,15 @@ var cPrefix string
 var fset = token.NewFileSet()
 
 var dynobj = flag.String("dynimport", "", "if non-empty, print dynamic import data for that file")
-var dynout = flag.String("dynout", "", "write -dynimport output to this file")
-var dynpackage = flag.String("dynpackage", "main", "set Go package for -dynimport output")
-var dynlinker = flag.Bool("dynlinker", false, "record dynamic linker information in -dynimport mode")
+var dynout = flag.String("dynout", "", "write -dynobj output to this file")
+var dynlinker = flag.Bool("dynlinker", false, "record dynamic linker information in dynimport mode")
 
-// This flag is for bootstrapping a new Go implementation,
-// to generate Go types that match the data layout and
+// These flags are for bootstrapping a new Go implementation,
+// to generate Go and C headers that match the data layout and
 // constant values used in the host's C libraries and system calls.
 var godefs = flag.Bool("godefs", false, "for bootstrap: write Go definitions for C file to standard output")
-
+var cdefs = flag.Bool("cdefs", false, "for bootstrap: write C definitions for C file to standard output")
 var objDir = flag.String("objdir", "", "object directory")
-var importPath = flag.String("importpath", "", "import path of package being built (for comments in generated files)")
-var exportHeader = flag.String("exportheader", "", "where to write export header if any exported functions")
 
 var gccgo = flag.Bool("gccgo", false, "generate files for use with gccgo")
 var gccgoprefix = flag.String("gccgoprefix", "", "-fgo-prefix option used with gccgo")
@@ -195,7 +180,12 @@ func main() {
 		return
 	}
 
-	if *godefs {
+	if *godefs && *cdefs {
+		fmt.Fprintf(os.Stderr, "cgo: cannot use -cdefs and -godefs together\n")
+		os.Exit(2)
+	}
+
+	if *godefs || *cdefs {
 		// Generating definitions pulled from header files,
 		// to be checked into Go repositories.
 		// Line numbers are just noise.
@@ -287,12 +277,14 @@ func main() {
 		p.Record(f)
 		if *godefs {
 			os.Stdout.WriteString(p.godefs(f, input))
+		} else if *cdefs {
+			os.Stdout.WriteString(p.cdefs(f, input))
 		} else {
 			p.writeOutput(f, input)
 		}
 	}
 
-	if !*godefs {
+	if !*godefs && !*cdefs {
 		p.writeDefs()
 	}
 	if nerrors > 0 {
diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go
index 90a7441..d92bed9 100644
--- a/src/cmd/cgo/out.go
+++ b/src/cmd/cgo/out.go
@@ -13,7 +13,6 @@ import (
 	"go/ast"
 	"go/printer"
 	"go/token"
-	"io"
 	"os"
 	"sort"
 	"strings"
@@ -21,17 +20,11 @@ import (
 
 var conf = printer.Config{Mode: printer.SourcePos, Tabwidth: 8}
 
-// writeDefs creates output files to be compiled by gc and gcc.
+// writeDefs creates output files to be compiled by 6g, 6c, and gcc.
+// (The comments here say 6g and 6c but the code applies to the 8 and 5 tools too.)
 func (p *Package) writeDefs() {
-	var fgo2, fc io.Writer
-	f := creat(*objDir + "_cgo_gotypes.go")
-	defer f.Close()
-	fgo2 = f
-	if *gccgo {
-		f := creat(*objDir + "_cgo_defun.c")
-		defer f.Close()
-		fc = f
-	}
+	fgo2 := creat(*objDir + "_cgo_gotypes.go")
+	fc := creat(*objDir + "_cgo_defun.c")
 	fm := creat(*objDir + "_cgo_main.c")
 
 	var gccgoInit bytes.Buffer
@@ -41,7 +34,7 @@ func (p *Package) writeDefs() {
 		fmt.Fprintf(fflg, "_CGO_%s=%s\n", k, strings.Join(v, " "))
 		if k == "LDFLAGS" && !*gccgo {
 			for _, arg := range v {
-				fmt.Fprintf(fgo2, "//go:cgo_ldflag %q\n", arg)
+				fmt.Fprintf(fc, "#pragma cgo_ldflag %q\n", arg)
 			}
 		}
 	}
@@ -51,17 +44,14 @@ func (p *Package) writeDefs() {
 	fmt.Fprintf(fm, "int main() { return 0; }\n")
 	if *importRuntimeCgo {
 		fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*, int), void *a, int c) { }\n")
-		fmt.Fprintf(fm, "void _cgo_wait_runtime_init_done() { }\n")
 		fmt.Fprintf(fm, "char* _cgo_topofstack(void) { return (char*)0; }\n")
 	} else {
 		// If we're not importing runtime/cgo, we *are* runtime/cgo,
-		// which provides these functions.  We just need a prototype.
+		// which provides crosscall2.  We just need a prototype.
 		fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*, int), void *a, int c);\n")
-		fmt.Fprintf(fm, "void _cgo_wait_runtime_init_done();\n")
 	}
 	fmt.Fprintf(fm, "void _cgo_allocate(void *a, int c) { }\n")
 	fmt.Fprintf(fm, "void _cgo_panic(void *a, int c) { }\n")
-	fmt.Fprintf(fm, "void _cgo_reginit(void) { }\n")
 
 	// Write second Go output: definitions of _C_xxx.
 	// In a separate file so that the import of "unsafe" does not
@@ -78,13 +68,6 @@ func (p *Package) writeDefs() {
 	}
 	fmt.Fprintf(fgo2, "func _Cgo_ptr(ptr unsafe.Pointer) unsafe.Pointer { return ptr }\n\n")
 
-	if !*gccgo {
-		fmt.Fprintf(fgo2, "//go:linkname _Cgo_always_false runtime.cgoAlwaysFalse\n")
-		fmt.Fprintf(fgo2, "var _Cgo_always_false bool\n")
-		fmt.Fprintf(fgo2, "//go:linkname _Cgo_use runtime.cgoUse\n")
-		fmt.Fprintf(fgo2, "func _Cgo_use(interface{})\n")
-	}
-
 	typedefNames := make([]string, 0, len(typedef))
 	for name := range typedef {
 		typedefNames = append(typedefNames, name)
@@ -105,6 +88,7 @@ func (p *Package) writeDefs() {
 	if *gccgo {
 		fmt.Fprint(fc, p.cPrologGccgo())
 	} else {
+		fmt.Fprint(fc, cProlog)
 		fmt.Fprint(fgo2, goProlog)
 	}
 
@@ -118,44 +102,44 @@ func (p *Package) writeDefs() {
 		}
 
 		if !cVars[n.C] {
-			if *gccgo {
-				fmt.Fprintf(fc, "extern byte *%s;\n", n.C)
-			} else {
-				fmt.Fprintf(fm, "extern char %s[];\n", n.C)
-				fmt.Fprintf(fm, "void *_cgohack_%s = %s;\n\n", n.C, n.C)
-				fmt.Fprintf(fgo2, "//go:linkname __cgo_%s %s\n", n.C, n.C)
-				fmt.Fprintf(fgo2, "//go:cgo_import_static %s\n", n.C)
-				fmt.Fprintf(fgo2, "var __cgo_%s byte\n", n.C)
+			fmt.Fprintf(fm, "extern char %s[];\n", n.C)
+			fmt.Fprintf(fm, "void *_cgohack_%s = %s;\n\n", n.C, n.C)
+
+			if !*gccgo {
+				fmt.Fprintf(fc, "#pragma cgo_import_static %s\n", n.C)
 			}
+
+			fmt.Fprintf(fc, "extern byte *%s;\n", n.C)
+
 			cVars[n.C] = true
 		}
-
+		var amp string
 		var node ast.Node
 		if n.Kind == "var" {
+			amp = "&"
 			node = &ast.StarExpr{X: n.Type.Go}
 		} else if n.Kind == "fpvar" {
 			node = n.Type.Go
+			if *gccgo {
+				amp = "&"
+			}
 		} else {
 			panic(fmt.Errorf("invalid var kind %q", n.Kind))
 		}
 		if *gccgo {
 			fmt.Fprintf(fc, `extern void *%s __asm__("%s.%s");`, n.Mangle, gccgoSymbolPrefix, n.Mangle)
-			fmt.Fprintf(&gccgoInit, "\t%s = &%s;\n", n.Mangle, n.C)
-			fmt.Fprintf(fc, "\n")
+			fmt.Fprintf(&gccgoInit, "\t%s = %s%s;\n", n.Mangle, amp, n.C)
+		} else {
+			fmt.Fprintf(fc, "#pragma dataflag NOPTR /* C pointer, not heap pointer */ \n")
+			fmt.Fprintf(fc, "void *·%s = %s%s;\n", n.Mangle, amp, n.C)
 		}
+		fmt.Fprintf(fc, "\n")
 
 		fmt.Fprintf(fgo2, "var %s ", n.Mangle)
 		conf.Fprint(fgo2, fset, node)
-		if !*gccgo {
-			fmt.Fprintf(fgo2, " = (")
-			conf.Fprint(fgo2, fset, node)
-			fmt.Fprintf(fgo2, ")(unsafe.Pointer(&__cgo_%s))", n.C)
-		}
 		fmt.Fprintf(fgo2, "\n")
 	}
-	if *gccgo {
-		fmt.Fprintf(fc, "\n")
-	}
+	fmt.Fprintf(fc, "\n")
 
 	for _, key := range nameKeys(p.Name) {
 		n := p.Name[key]
@@ -168,37 +152,14 @@ func (p *Package) writeDefs() {
 	for _, key := range nameKeys(p.Name) {
 		n := p.Name[key]
 		if n.FuncType != nil {
-			p.writeDefsFunc(fgo2, n)
+			p.writeDefsFunc(fc, fgo2, n)
 		}
 	}
 
-	fgcc := creat(*objDir + "_cgo_export.c")
-	fgcch := creat(*objDir + "_cgo_export.h")
 	if *gccgo {
-		p.writeGccgoExports(fgo2, fm, fgcc, fgcch)
+		p.writeGccgoExports(fgo2, fc, fm)
 	} else {
-		p.writeExports(fgo2, fm, fgcc, fgcch)
-	}
-	if err := fgcc.Close(); err != nil {
-		fatalf("%s", err)
-	}
-	if err := fgcch.Close(); err != nil {
-		fatalf("%s", err)
-	}
-
-	if *exportHeader != "" && len(p.ExpFunc) > 0 {
-		fexp := creat(*exportHeader)
-		fgcch, err := os.Open(*objDir + "_cgo_export.h")
-		if err != nil {
-			fatalf("%s", err)
-		}
-		_, err = io.Copy(fexp, fgcch)
-		if err != nil {
-			fatalf("%s", err)
-		}
-		if err = fexp.Close(); err != nil {
-			fatalf("%s", err)
-		}
+		p.writeExports(fgo2, fc, fm)
 	}
 
 	init := gccgoInit.String()
@@ -208,6 +169,9 @@ func (p *Package) writeDefs() {
 		fmt.Fprint(fc, init)
 		fmt.Fprintln(fc, "}")
 	}
+
+	fgo2.Close()
+	fc.Close()
 }
 
 func dynimport(obj string) {
@@ -220,15 +184,13 @@ func dynimport(obj string) {
 		stdout = f
 	}
 
-	fmt.Fprintf(stdout, "package %s\n", *dynpackage)
-
 	if f, err := elf.Open(obj); err == nil {
 		if *dynlinker {
 			// Emit the cgo_dynamic_linker line.
 			if sec := f.Section(".interp"); sec != nil {
 				if data, err := sec.Data(); err == nil && len(data) > 1 {
 					// skip trailing \0 in data
-					fmt.Fprintf(stdout, "//go:cgo_dynamic_linker %q\n", string(data[:len(data)-1]))
+					fmt.Fprintf(stdout, "#pragma cgo_dynamic_linker %q\n", string(data[:len(data)-1]))
 				}
 			}
 		}
@@ -241,14 +203,14 @@ func dynimport(obj string) {
 			if s.Version != "" {
 				targ += "#" + s.Version
 			}
-			fmt.Fprintf(stdout, "//go:cgo_import_dynamic %s %s %q\n", s.Name, targ, s.Library)
+			fmt.Fprintf(stdout, "#pragma cgo_import_dynamic %s %s %q\n", s.Name, targ, s.Library)
 		}
 		lib, err := f.ImportedLibraries()
 		if err != nil {
 			fatalf("cannot load imported libraries from ELF file %s: %v", obj, err)
 		}
 		for _, l := range lib {
-			fmt.Fprintf(stdout, "//go:cgo_import_dynamic _ _ %q\n", l)
+			fmt.Fprintf(stdout, "#pragma cgo_import_dynamic _ _ %q\n", l)
 		}
 		return
 	}
@@ -262,14 +224,14 @@ func dynimport(obj string) {
 			if len(s) > 0 && s[0] == '_' {
 				s = s[1:]
 			}
-			fmt.Fprintf(stdout, "//go:cgo_import_dynamic %s %s %q\n", s, s, "")
+			fmt.Fprintf(stdout, "#pragma cgo_import_dynamic %s %s %q\n", s, s, "")
 		}
 		lib, err := f.ImportedLibraries()
 		if err != nil {
 			fatalf("cannot load imported libraries from Mach-O file %s: %v", obj, err)
 		}
 		for _, l := range lib {
-			fmt.Fprintf(stdout, "//go:cgo_import_dynamic _ _ %q\n", l)
+			fmt.Fprintf(stdout, "#pragma cgo_import_dynamic _ _ %q\n", l)
 		}
 		return
 	}
@@ -282,7 +244,7 @@ func dynimport(obj string) {
 		for _, s := range sym {
 			ss := strings.Split(s, ":")
 			name := strings.Split(ss[0], "@")[0]
-			fmt.Fprintf(stdout, "//go:cgo_import_dynamic %s %s %q\n", name, ss[0], strings.ToLower(ss[1]))
+			fmt.Fprintf(stdout, "#pragma cgo_import_dynamic %s %s %q\n", name, ss[0], strings.ToLower(ss[1]))
 		}
 		return
 	}
@@ -290,10 +252,10 @@ func dynimport(obj string) {
 	fatalf("cannot parse %s as ELF, Mach-O or PE", obj)
 }
 
-// Construct a gcc struct matching the gc argument frame.
+// Construct a gcc struct matching the 6c argument frame.
 // Assumes that in gcc, char is 1 byte, short 2 bytes, int 4 bytes, long long 8 bytes.
 // These assumptions are checked by the gccProlog.
-// Also assumes that gc convention is to word-align the
+// Also assumes that 6c convention is to word-align the
 // input and output parameters.
 func (p *Package) structType(n *Name) (string, int64) {
 	var buf bytes.Buffer
@@ -342,7 +304,7 @@ func (p *Package) structType(n *Name) (string, int64) {
 	return buf.String(), off
 }
 
-func (p *Package) writeDefsFunc(fgo2 io.Writer, n *Name) {
+func (p *Package) writeDefsFunc(fc, fgo2 *os.File, n *Name) {
 	name := n.Go
 	gtype := n.FuncType.Go
 	void := gtype.Results == nil || len(gtype.Results.List) == 0
@@ -434,11 +396,11 @@ func (p *Package) writeDefsFunc(fgo2 io.Writer, n *Name) {
 		return
 	}
 
-	// Wrapper calls into gcc, passing a pointer to the argument frame.
-	fmt.Fprintf(fgo2, "//go:cgo_import_static %s\n", cname)
-	fmt.Fprintf(fgo2, "//go:linkname __cgofn_%s %s\n", cname, cname)
-	fmt.Fprintf(fgo2, "var __cgofn_%s byte\n", cname)
-	fmt.Fprintf(fgo2, "var %s = unsafe.Pointer(&__cgofn_%s)\n", cname, cname)
+	// C wrapper calls into gcc, passing a pointer to the argument frame.
+	fmt.Fprintf(fc, "#pragma cgo_import_static %s\n", cname)
+	fmt.Fprintf(fc, "void %s(void*);\n", cname)
+	fmt.Fprintf(fc, "#pragma dataflag NOPTR\n")
+	fmt.Fprintf(fc, "void *·%s = %s;\n", cname, cname)
 
 	nret := 0
 	if !void {
@@ -450,6 +412,7 @@ func (p *Package) writeDefsFunc(fgo2 io.Writer, n *Name) {
 	}
 
 	fmt.Fprint(fgo2, "\n")
+	fmt.Fprintf(fgo2, "var %s unsafe.Pointer\n", cname)
 	conf.Fprint(fgo2, fset, d)
 	fmt.Fprint(fgo2, " {\n")
 
@@ -465,20 +428,16 @@ func (p *Package) writeDefsFunc(fgo2 io.Writer, n *Name) {
 	if n.AddError {
 		prefix = "errno := "
 	}
-	fmt.Fprintf(fgo2, "\t%s_cgo_runtime_cgocall(%s, %s)\n", prefix, cname, arg)
+	fmt.Fprintf(fgo2, "\t%s_cgo_runtime_cgocall_errno(%s, %s)\n", prefix, cname, arg)
 	if n.AddError {
 		fmt.Fprintf(fgo2, "\tif errno != 0 { r2 = syscall.Errno(errno) }\n")
 	}
-	fmt.Fprintf(fgo2, "\tif _Cgo_always_false {\n")
-	for i := range d.Type.Params.List {
-		fmt.Fprintf(fgo2, "\t\t_Cgo_use(p%d)\n", i)
-	}
-	fmt.Fprintf(fgo2, "\t}\n")
 	fmt.Fprintf(fgo2, "\treturn\n")
 	fmt.Fprintf(fgo2, "}\n")
 }
 
-// writeOutput creates stubs for a specific source file to be compiled by gc
+// writeOutput creates stubs for a specific source file to be compiled by 6g
+// (The comments here say 6g and 6c but the code applies to the 8 and 5 tools too.)
 func (p *Package) writeOutput(f *File, srcfile string) {
 	base := srcfile
 	if strings.HasSuffix(base, ".go") {
@@ -495,7 +454,7 @@ func (p *Package) writeOutput(f *File, srcfile string) {
 	fmt.Fprintf(fgo1, "// Created by cgo - DO NOT EDIT\n\n")
 	conf.Fprint(fgo1, fset, f.AST)
 
-	// While we process the vars and funcs, also write gcc output.
+	// While we process the vars and funcs, also write 6c and gcc output.
 	// Gcc output starts with the preamble.
 	fmt.Fprintf(fgcc, "%s\n", f.Preamble)
 	fmt.Fprintf(fgcc, "%s\n", gccProlog)
@@ -557,7 +516,7 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) {
 	if n.AddError {
 		fmt.Fprintf(fgcc, "\terrno = 0;\n")
 	}
-	// We're trying to write a gcc struct that matches gc's layout.
+	// 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.
 	fmt.Fprintf(fgcc, "\t%s %v *a = v;\n", ctype, p.packedAttribute())
@@ -653,13 +612,13 @@ func (p *Package) writeGccgoOutputFunc(fgcc *os.File, n *Name) {
 }
 
 // packedAttribute returns host compiler struct attribute that will be
-// used to match gc's struct layout. For example, on 386 Windows,
-// gcc wants to 8-align int64s, but gc does not.
+// 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 https://golang.org/issue/5603.
+// and http://golang.org/issue/5603.
 func (p *Package) packedAttribute() string {
 	s := "__attribute__((__packed__"
-	if !p.GccIsClang && (goarch == "amd64" || goarch == "386") {
+	if !strings.Contains(p.gccBaseCmd()[0], "clang") && (goarch == "amd64" || goarch == "386") {
 		s += ", __gcc_struct__"
 	}
 	return s + "))"
@@ -667,19 +626,23 @@ func (p *Package) packedAttribute() string {
 
 // 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, fm, fgcc, fgcch io.Writer) {
-	p.writeExportHeader(fgcch)
+func (p *Package) writeExports(fgo2, fc, fm *os.File) {
+	fgcc := creat(*objDir + "_cgo_export.c")
+	fgcch := creat(*objDir + "_cgo_export.h")
+
+	fmt.Fprintf(fgcch, "/* Created by cgo - DO NOT EDIT. */\n")
+	fmt.Fprintf(fgcch, "%s\n", p.Preamble)
+	fmt.Fprintf(fgcch, "%s\n", p.gccExportHeaderProlog())
 
 	fmt.Fprintf(fgcc, "/* Created by cgo - DO NOT EDIT. */\n")
-	fmt.Fprintf(fgcc, "#include \"_cgo_export.h\"\n\n")
+	fmt.Fprintf(fgcc, "#include \"_cgo_export.h\"\n")
 
-	fmt.Fprintf(fgcc, "extern void crosscall2(void (*fn)(void *, int), void *, int);\n")
-	fmt.Fprintf(fgcc, "extern void _cgo_wait_runtime_init_done();\n\n")
+	fmt.Fprintf(fgcc, "\nextern void crosscall2(void (*fn)(void *, int), void *, int);\n\n")
 
 	for _, exp := range p.ExpFunc {
 		fn := exp.Func
 
-		// Construct a gcc struct matching the gc argument and
+		// Construct a gcc struct matching the 6c argument and
 		// result frame.  The gcc struct will be compiled with
 		// __attribute__((packed)) so all padding must be accounted
 		// for explicitly.
@@ -765,16 +728,11 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
 				s += fmt.Sprintf("%s p%d", p.cgoType(atype).C, i)
 			})
 		s += ")"
-
-		if len(exp.Doc) > 0 {
-			fmt.Fprintf(fgcch, "\n%s", exp.Doc)
-		}
 		fmt.Fprintf(fgcch, "\nextern %s;\n", s)
 
 		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_cgo_wait_runtime_init_done();\n")
 		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)
@@ -800,21 +758,20 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
 		}
 		fmt.Fprintf(fgcc, "}\n")
 
-		// Build the wrapper function compiled by gc.
+		// Build the wrapper function compiled by 6c/8c
 		goname := exp.Func.Name.Name
 		if fn.Recv != nil {
 			goname = "_cgoexpwrap" + cPrefix + "_" + fn.Recv.List[0].Names[0].Name + "_" + goname
 		}
-		fmt.Fprintf(fgo2, "//go:cgo_export_dynamic %s\n", goname)
-		fmt.Fprintf(fgo2, "//go:linkname _cgoexp%s_%s _cgoexp%s_%s\n", cPrefix, exp.ExpName, cPrefix, exp.ExpName)
-		fmt.Fprintf(fgo2, "//go:cgo_export_static _cgoexp%s_%s\n", cPrefix, exp.ExpName)
-		fmt.Fprintf(fgo2, "//go:nosplit\n") // no split stack, so no use of m or g
-		fmt.Fprintf(fgo2, "//go:norace\n")  // must not have race detector calls inserted
-		fmt.Fprintf(fgo2, "func _cgoexp%s_%s(a unsafe.Pointer, n int32) {", cPrefix, exp.ExpName)
-		fmt.Fprintf(fgo2, "\tfn := %s\n", goname)
-		// The indirect here is converting from a Go function pointer to a C function pointer.
-		fmt.Fprintf(fgo2, "\t_cgo_runtime_cgocallback(**(**unsafe.Pointer)(unsafe.Pointer(&fn)), a, uintptr(n));\n")
-		fmt.Fprintf(fgo2, "}\n")
+		fmt.Fprintf(fc, "#pragma cgo_export_dynamic %s\n", goname)
+		fmt.Fprintf(fc, "extern void ·%s();\n\n", goname)
+		fmt.Fprintf(fc, "#pragma cgo_export_static _cgoexp%s_%s\n", cPrefix, exp.ExpName)
+		fmt.Fprintf(fc, "#pragma textflag 7\n") // no split stack, so no use of m or g
+		fmt.Fprintf(fc, "void\n")
+		fmt.Fprintf(fc, "_cgoexp%s_%s(void *a, int32 n)\n", cPrefix, exp.ExpName)
+		fmt.Fprintf(fc, "{\n")
+		fmt.Fprintf(fc, "\truntime·cgocallback(·%s, a, n);\n", goname)
+		fmt.Fprintf(fc, "}\n")
 
 		fmt.Fprintf(fm, "int _cgoexp%s_%s;\n", cPrefix, exp.ExpName)
 
@@ -857,20 +814,23 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
 			fmt.Fprint(fgo2, "}\n")
 		}
 	}
-
-	fmt.Fprintf(fgcch, "%s", gccExportHeaderEpilog)
 }
 
 // Write out the C header allowing C code to call exported gccgo functions.
-func (p *Package) writeGccgoExports(fgo2, fm, fgcc, fgcch io.Writer) {
+func (p *Package) writeGccgoExports(fgo2, fc, fm *os.File) {
+	fgcc := creat(*objDir + "_cgo_export.c")
+	fgcch := creat(*objDir + "_cgo_export.h")
+
 	gccgoSymbolPrefix := p.gccgoSymbolPrefix()
 
-	p.writeExportHeader(fgcch)
+	fmt.Fprintf(fgcch, "/* Created by cgo - DO NOT EDIT. */\n")
+	fmt.Fprintf(fgcch, "%s\n", p.Preamble)
+	fmt.Fprintf(fgcch, "%s\n", p.gccExportHeaderProlog())
 
 	fmt.Fprintf(fgcc, "/* Created by cgo - DO NOT EDIT. */\n")
 	fmt.Fprintf(fgcc, "#include \"_cgo_export.h\"\n")
 
-	fmt.Fprintf(fgcc, "%s\n", gccgoExportFileProlog)
+	fmt.Fprintf(fm, "#include \"_cgo_export.h\"\n")
 
 	for _, exp := range p.ExpFunc {
 		fn := exp.Func
@@ -891,7 +851,6 @@ func (p *Package) writeGccgoExports(fgo2, fm, fgcc, fgcch io.Writer) {
 				})
 		default:
 			// Declare a result struct.
-			fmt.Fprintf(fgcch, "\n/* Return type for %s */\n", exp.ExpName)
 			fmt.Fprintf(fgcch, "struct %s_result {\n", exp.ExpName)
 			forFieldList(fntype.Results,
 				func(i int, atype ast.Expr) {
@@ -921,10 +880,6 @@ func (p *Package) writeGccgoExports(fgo2, fm, fgcc, fgcch io.Writer) {
 		fmt.Fprintf(cdeclBuf, ")")
 		cParams := cdeclBuf.String()
 
-		if len(exp.Doc) > 0 {
-			fmt.Fprintf(fgcch, "\n%s", exp.Doc)
-		}
-
 		// 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
@@ -945,8 +900,6 @@ func (p *Package) writeGccgoExports(fgo2, fm, fgcc, fgcch io.Writer) {
 
 		fmt.Fprint(fgcc, "\n")
 		fmt.Fprintf(fgcc, "%s %s %s {\n", cRet, exp.ExpName, cParams)
-		fmt.Fprintf(fgcc, "\tif(_cgo_wait_runtime_init_done)\n")
-		fmt.Fprintf(fgcc, "\t\t_cgo_wait_runtime_init_done();\n")
 		fmt.Fprint(fgcc, "\t")
 		if resultCount > 0 {
 			fmt.Fprint(fgcc, "return ")
@@ -966,8 +919,7 @@ func (p *Package) writeGccgoExports(fgo2, fm, fgcc, fgcch io.Writer) {
 		fmt.Fprint(fgcc, "}\n")
 
 		// Dummy declaration for _cgo_main.c
-		fmt.Fprintf(fm, `char %s[1] __asm__("%s.%s");`, goName, gccgoSymbolPrefix, goName)
-		fmt.Fprint(fm, "\n")
+		fmt.Fprintf(fm, "%s %s %s {}\n", cRet, goName, cParams)
 
 		// For gccgo we use a wrapper function in Go, in order
 		// to call CgocallBack and CgocallBackDone.
@@ -1022,24 +974,6 @@ func (p *Package) writeGccgoExports(fgo2, fm, fgcc, fgcch io.Writer) {
 		fmt.Fprint(fgo2, ")\n")
 		fmt.Fprint(fgo2, "}\n")
 	}
-
-	fmt.Fprintf(fgcch, "%s", gccExportHeaderEpilog)
-}
-
-// writeExportHeader writes out the start of the _cgo_export.h file.
-func (p *Package) writeExportHeader(fgcch io.Writer) {
-	fmt.Fprintf(fgcch, "/* Created by \"go tool cgo\" - DO NOT EDIT. */\n\n")
-	pkg := *importPath
-	if pkg == "" {
-		pkg = p.PackagePath
-	}
-	fmt.Fprintf(fgcch, "/* package %s */\n\n", pkg)
-
-	fmt.Fprintf(fgcch, "/* Start of preamble from import \"C\" comments.  */\n\n")
-	fmt.Fprintf(fgcch, "%s\n", p.Preamble)
-	fmt.Fprintf(fgcch, "\n/* End of preamble from import \"C\" comments.  */\n\n")
-
-	fmt.Fprintf(fgcch, "%s\n", p.gccExportHeaderProlog())
 }
 
 // Return the package prefix when using gccgo.
@@ -1230,39 +1164,60 @@ char *CString(_GoString_);
 void *_CMalloc(size_t);
 `
 
-const goProlog = `
-//go:linkname _cgo_runtime_cgocall runtime.cgocall
-func _cgo_runtime_cgocall(unsafe.Pointer, uintptr) int32
-
-//go:linkname _cgo_runtime_cmalloc runtime.cmalloc
-func _cgo_runtime_cmalloc(uintptr) unsafe.Pointer
+const cProlog = `
+#include "runtime.h"
+#include "cgocall.h"
+#include "textflag.h"
+
+#pragma dataflag NOPTR
+static void *cgocall_errno = runtime·cgocall_errno;
+#pragma dataflag NOPTR
+void *·_cgo_runtime_cgocall_errno = &cgocall_errno;
+
+#pragma dataflag NOPTR
+static void *runtime_gostring = runtime·gostring;
+#pragma dataflag NOPTR
+void *·_cgo_runtime_gostring = &runtime_gostring;
+
+#pragma dataflag NOPTR
+static void *runtime_gostringn = runtime·gostringn;
+#pragma dataflag NOPTR
+void *·_cgo_runtime_gostringn = &runtime_gostringn;
+
+#pragma dataflag NOPTR
+static void *runtime_gobytes = runtime·gobytes;
+#pragma dataflag NOPTR
+void *·_cgo_runtime_gobytes = &runtime_gobytes;
+
+#pragma dataflag NOPTR
+static void *runtime_cmalloc = runtime·cmalloc;
+#pragma dataflag NOPTR
+void *·_cgo_runtime_cmalloc = &runtime_cmalloc;
+
+void ·_Cerrno(void*, int32);
+`
 
-//go:linkname _cgo_runtime_cgocallback runtime.cgocallback
-func _cgo_runtime_cgocallback(unsafe.Pointer, unsafe.Pointer, uintptr)
+const goProlog = `
+var _cgo_runtime_cgocall_errno func(unsafe.Pointer, uintptr) int32
+var _cgo_runtime_cmalloc func(uintptr) unsafe.Pointer
 `
 
 const goStringDef = `
-//go:linkname _cgo_runtime_gostring runtime.gostring
-func _cgo_runtime_gostring(*_Ctype_char) string
-
+var _cgo_runtime_gostring func(*_Ctype_char) string
 func _Cfunc_GoString(p *_Ctype_char) string {
 	return _cgo_runtime_gostring(p)
 }
 `
 
 const goStringNDef = `
-//go:linkname _cgo_runtime_gostringn runtime.gostringn
-func _cgo_runtime_gostringn(*_Ctype_char, int) string
-
+var _cgo_runtime_gostringn func(*_Ctype_char, int) string
 func _Cfunc_GoStringN(p *_Ctype_char, l _Ctype_int) string {
 	return _cgo_runtime_gostringn(p, int(l))
 }
 `
 
 const goBytesDef = `
-//go:linkname _cgo_runtime_gobytes runtime.gobytes
-func _cgo_runtime_gobytes(unsafe.Pointer, int) []byte
-
+var _cgo_runtime_gobytes func(unsafe.Pointer, int) []byte
 func _Cfunc_GoBytes(p unsafe.Pointer, l _Ctype_int) []byte {
 	return _cgo_runtime_gobytes(p, int(l))
 }
@@ -1355,11 +1310,6 @@ func (p *Package) gccExportHeaderProlog() string {
 }
 
 const gccExportHeaderProlog = `
-/* Start of boilerplate cgo prologue.  */
-
-#ifndef GO_CGO_PROLOGUE_H
-#define GO_CGO_PROLOGUE_H
-
 typedef signed char GoInt8;
 typedef unsigned char GoUint8;
 typedef short GoInt16;
@@ -1376,44 +1326,9 @@ typedef double GoFloat64;
 typedef __complex float GoComplex64;
 typedef __complex double GoComplex128;
 
-// static assertion to make sure the file is being used on architecture
-// at least with matching size of GoInt.
-typedef char _check_for_GOINTBITS_bit_pointer_matching_GoInt[sizeof(void*)==GOINTBITS/8 ? 1:-1];
-
 typedef struct { char *p; GoInt n; } GoString;
 typedef void *GoMap;
 typedef void *GoChan;
 typedef struct { void *t; void *v; } GoInterface;
 typedef struct { void *data; GoInt len; GoInt cap; } GoSlice;
-
-#endif
-
-/* End of boilerplate cgo prologue.  */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-`
-
-// gccExportHeaderEpilog goes at the end of the generated header file.
-const gccExportHeaderEpilog = `
-#ifdef __cplusplus
-}
-#endif
-`
-
-// gccgoExportFileProlog is written to the _cgo_export.c file when
-// using gccgo.
-// We use weak declarations, and test the addresses, so that this code
-// works with older versions of gccgo.
-const gccgoExportFileProlog = `
-extern _Bool runtime_iscgo __attribute__ ((weak));
-
-static void GoInit(void) __attribute__ ((constructor));
-static void GoInit(void) {
-	if(&runtime_iscgo)
-		runtime_iscgo = 1;
-}
-
-extern void _cgo_wait_runtime_init_done() __attribute__ ((weak));
 `
diff --git a/src/cmd/cgo/util.go b/src/cmd/cgo/util.go
index 3adb8e8..4e7800d 100644
--- a/src/cmd/cgo/util.go
+++ b/src/cmd/cgo/util.go
@@ -55,7 +55,7 @@ func error_(pos token.Pos, msg string, args ...interface{}) {
 	fmt.Fprintf(os.Stderr, "\n")
 }
 
-// isName reports whether s is a valid C identifier
+// isName returns true if s is a valid C identifier
 func isName(s string) bool {
 	for i, v := range s {
 		if v != '_' && (v < 'A' || v > 'Z') && (v < 'a' || v > 'z') && (v < '0' || v > '9') {
diff --git a/src/cmd/dist/README b/src/cmd/dist/README
index 0649e88..e6d08cf 100644
--- a/src/cmd/dist/README
+++ b/src/cmd/dist/README
@@ -1,27 +1,45 @@
 This program, dist, is the bootstrapping tool for the Go distribution.
+It takes care of building the C programs (like the Go compiler) and
+the initial bootstrap copy of the go tool.  It also serves as a catch-all
+to replace odd jobs previously done with shell scripts.
 
-As of Go 1.5, dist and other parts of the compiler toolchain are written
-in Go, making bootstrapping a little more involved than in the past.
-The approach is to build the current release of Go with an earlier one.
+Dist is itself written in very simple C.  All interaction with C libraries,
+even standard C libraries, is confined to a single system-specific file
+(plan9.c, unix.c, windows.c), to aid portability.  Functionality needed
+by other files should be exposed via the portability layer.  Functions
+in the portability layer begin with an x prefix when they would otherwise
+use the same name as or be confused for an existing function.
+For example, xprintf is the portable printf.
 
-The process to install Go 1.x, for x ≥ 5, is:
+By far the most common data types in dist are strings and arrays of
+strings.  Instead of using char* and char**, though, dist uses two named
+data structures, Buf and Vec, which own all the data they point at.
+The Buf operations are functions beginning with b; the Vec operations
+are functions beginning with v.  The basic form of any function declaring
+Bufs or Vecs on the stack should be
 
-1. Build cmd/dist with Go 1.4.
-2. Using dist, build Go 1.x compiler toolchain with Go 1.4.
-3. Using dist, rebuild Go 1.x compiler toolchain with itself.
-4. Using dist, build Go 1.x cmd/go (as go_bootstrap) with Go 1.x compiler toolchain.
-5. Using go_bootstrap, build the remaining Go 1.x standard library and commands.
+	void
+	myfunc(void)
+	{
+		Buf b1, b2;
+		Vec v1;
+		
+		binit(&b1);
+		binit(&b2);
+		vinit(&v1);
+		
+		... main code ...
+		bprintf(&b1, "hello, world");
+		vadd(&v1, bstr(&b1));  // v1 takes a copy of its argument
+		bprintf(&b2, "another string");
+		vadd(&v1, bstr(&b2));  // v1 now has two strings
+		
+		bfree(&b1);
+		bfree(&b2);
+		vfree(&v1);
+	}
+	
+The binit/vinit calls prepare a buffer or vector for use, initializing the 
+data structures, and the bfree/vfree calls free any memory they are still
+holding onto.  Use of this idiom gives us lexically scoped allocations.
 
-NOTE: During the transition from the old C-based toolchain to the Go-based one,
-step 2 also builds the parts of the toolchain written in C, and step 3 does not
-recompile those.
-
-Because of backward compatibility, although the steps above say Go 1.4,
-in practice any release ≥ Go 1.4 but < Go 1.x will work as the bootstrap base.
-
-See golang.org/s/go15bootstrap for more details.
-
-Compared to Go 1.4 and earlier, dist will also take over much of what used to
-be done by make.bash/make.bat/make.rc and all of what used to be done by
-run.bash/run.bat/run.rc, because it is nicer to implement that logic in Go
-than in three different scripting languages simultaneously.
diff --git a/src/cmd/dist/a.h b/src/cmd/dist/a.h
new file mode 100644
index 0000000..288063b
--- /dev/null
+++ b/src/cmd/dist/a.h
@@ -0,0 +1,165 @@
+// 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.
+
+typedef int bool;
+
+// The Time unit is unspecified; we just need to
+// be able to compare whether t1 is older than t2 with t1 < t2.
+typedef long long Time;
+
+#define nil ((void*)0)
+#define nelem(x) (sizeof(x)/sizeof((x)[0]))
+#ifndef PLAN9
+#define USED(x) ((void)(x))
+#endif
+
+// A Buf is a byte buffer, like Go's []byte.
+typedef struct Buf Buf;
+struct Buf
+{
+	char *p;
+	int len;
+	int cap;
+};
+
+// A Vec is a string vector, like Go's []string.
+typedef struct Vec Vec;
+struct Vec
+{
+	char **p;
+	int len;
+	int cap;
+};
+
+// Modes for run.
+enum {
+	CheckExit = 1,
+};
+
+// buf.c
+bool	bequal(Buf *s, Buf *t);
+void	bsubst(Buf *b, char *x, char *y);
+void	bfree(Buf *b);
+void	bgrow(Buf *b, int n);
+void	binit(Buf *b);
+char*	bpathf(Buf *b, char *fmt, ...);
+char*	bprintf(Buf *b, char *fmt, ...);
+void	bwritef(Buf *b, char *fmt, ...);
+void	breset(Buf *b);
+char*	bstr(Buf *b);
+char*	btake(Buf *b);
+void	bwrite(Buf *b, void *v, int n);
+void	bwriteb(Buf *dst, Buf *src);
+void	bwritestr(Buf *b, char *p);
+void	bswap(Buf *b, Buf *b1);
+void	vadd(Vec *v, char *p);
+void	vcopy(Vec *dst, char **src, int n);
+void	vfree(Vec *v);
+void	vgrow(Vec *v, int n);
+void	vinit(Vec *v);
+void	vreset(Vec *v);
+void	vuniq(Vec *v);
+void	splitlines(Vec*, char*);
+void	splitfields(Vec*, char*);
+
+// build.c
+extern char *goarch;
+extern char *gobin;
+extern char *gochar;
+extern char *gohostarch;
+extern char *gohostos;
+extern char *goos;
+extern char *goroot;
+extern char *goroot_final;
+extern char *goextlinkenabled;
+extern char *goversion;
+extern char *defaultcc;
+extern char *defaultcxxtarget;
+extern char *defaultcctarget;
+extern char *workdir;
+extern char *tooldir;
+extern char *slash;
+extern bool rebuildall;
+extern bool defaultclang;
+
+int	find(char*, char**, int);
+void	init(void);
+void	cmdbanner(int, char**);
+void	cmdbootstrap(int, char**);
+void	cmdclean(int, char**);
+void	cmdenv(int, char**);
+void	cmdinstall(int, char**);
+void	cmdversion(int, char**);
+
+// buildgc.c
+void	gcopnames(char*, char*);
+void	mkanames(char*, char*);
+
+// buildruntime.c
+void	mkzasm(char*, char*);
+void	mkzsys(char*, char*);
+void	mkzgoarch(char*, char*);
+void	mkzgoos(char*, char*);
+void	mkzruntimedefs(char*, char*);
+void	mkzversion(char*, char*);
+void	mkzexperiment(char*, char*);
+
+// buildgo.c
+void	mkzdefaultcc(char*, char*);
+
+// main.c
+extern int vflag;
+extern int sflag;
+void	usage(void);
+void	xmain(int argc, char **argv);
+
+// portability layer (plan9.c, unix.c, windows.c)
+bool	contains(char *p, char *sep);
+void	errprintf(char*, ...);
+void	fatal(char *msg, ...);
+bool	hasprefix(char *p, char *prefix);
+bool	hassuffix(char *p, char *suffix);
+bool	isabs(char*);
+bool	isdir(char *p);
+bool	isfile(char *p);
+char*	lastelem(char*);
+Time	mtime(char*);
+void	readfile(Buf*, char*);
+void	copyfile(char*, char*, int);
+void	run(Buf *b, char *dir, int mode, char *cmd, ...);
+void	runv(Buf *b, char *dir, int mode, Vec *argv);
+void	bgrunv(char *dir, int mode, Vec *argv);
+void	bgwait(void);
+bool	streq(char*, char*);
+bool	cansse2(void);
+void	writefile(Buf*, char*, int);
+void	xatexit(void (*f)(void));
+void	xexit(int);
+void	xfree(void*);
+void	xgetenv(Buf *b, char *name);
+void	xgetwd(Buf *b);
+void*	xmalloc(int n);
+void*	xmalloc(int);
+int	xmemcmp(void*, void*, int);
+void	xmemmove(void*, void*, int);
+void	xmkdir(char *p);
+void	xmkdirall(char*);
+Time	xmtime(char *p);
+void	xprintf(char*, ...);
+void	xqsort(void*, int, int, int(*)(const void*, const void*));
+void	xreaddir(Vec *dst, char *dir);
+void*	xrealloc(void*, int);
+void	xrealwd(Buf *b, char *path);
+void	xremove(char *p);
+void	xremoveall(char *p);
+void	xsetenv(char*, char*);
+int	xstrcmp(char*, char*);
+char*	xstrdup(char *p);
+int	xstrlen(char*);
+char*	xstrrchr(char*, int);
+char*	xstrstr(char*, char*);
+char*	xworkdir(void);
+int	xsamefile(char*, char*);
+char*	xgetgoarm(void);
+int	xtryexecfunc(void (*)(void));
diff --git a/src/cmd/dist/arg.h b/src/cmd/dist/arg.h
new file mode 100644
index 0000000..9819765
--- /dev/null
+++ b/src/cmd/dist/arg.h
@@ -0,0 +1,49 @@
+/*
+Derived from Inferno include/kern.h.
+
+http://code.google.com/p/inferno-os/source/browse/include/kern.h
+
+	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.
+*/
+
+/* command line */
+extern char	*argv0;
+#define	ARGBEGIN	for((argv0=(argv0?argv0:*argv)),argv++,argc--;\
+			    argv[0] && argv[0][0]=='-' && argv[0][1];\
+			    argc--, argv++) {\
+				char *_args, *_argt;\
+				char _argc;\
+				_args = &argv[0][1];\
+				if(_args[0]=='-' && _args[1]==0){\
+					argc--; argv++; break;\
+				}\
+				while((_argc = *_args++) != 0)\
+				switch(_argc)
+#define	ARGEND		_argt=0;USED(_argt);USED(_argc);USED(_args);}USED(argv);USED(argc);
+#define	ARGF()		(_argt=_args, _args="",\
+				(*_argt? _argt: argv[1]? (argc--, *++argv): 0))
+#define	EARGF(x)	(_argt=_args, _args="",\
+				(*_argt? _argt: argv[1]? (argc--, *++argv): ((x), fatal("usage"), (char*)0)))
+
+#define	ARGC()		_argc
+
diff --git a/src/cmd/dist/arm.c b/src/cmd/dist/arm.c
new file mode 100644
index 0000000..1ce7b77
--- /dev/null
+++ b/src/cmd/dist/arm.c
@@ -0,0 +1,72 @@
+// 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 "a.h"
+
+#ifndef __ARMEL__
+char *
+xgetgoarm(void)
+{
+	return "6";
+}
+#else
+static void useVFPv3(void);
+static void useVFPv1(void);
+
+char *
+xgetgoarm(void)
+{
+#if defined(__FreeBSD__)
+	// FreeBSD has broken VFP support
+	return "5";
+#endif
+	// NaCl always has VFP support.
+	if(streq(goos, "nacl") || xtryexecfunc(useVFPv3))
+		return "7";
+	else if(xtryexecfunc(useVFPv1))
+		return "6";
+	return "5";
+}
+
+static void
+useVFPv3(void)
+{
+	// try to run VFPv3-only "vmov.f64 d0, #112" instruction
+	// we can't use that instruction directly, because we
+	// might be compiling with a soft-float only toolchain.
+	//
+	// some newer toolchains are configured to use thumb
+	// by default, so we need to do some mode changing magic
+	// here.
+	// We can use "bx pc; nop" here, but GNU as(1) insists
+	// on warning us
+	// "use of r15 in bx in ARM mode is not really useful"
+	// so we workaround that by using "bx r0"
+	__asm__ __volatile__ ("mov r0, pc");
+	__asm__ __volatile__ ("bx r0");
+	__asm__ __volatile__ (".word 0xeeb70b00"); // vmov.f64 d0, #112
+	__asm__ __volatile__ (".word 0xe12fff1e"); // bx lr
+}
+
+static void
+useVFPv1(void)
+{
+	// try to run "vmov.f64 d0, d0" instruction
+	// we can't use that instruction directly, because we
+	// might be compiling with a soft-float only toolchain
+	//
+	// some newer toolchains are configured to use thumb
+	// by default, so we need to do some mode changing magic
+	// here.
+	// We can use "bx pc; nop" here, but GNU as(1) insists
+	// on warning us
+	// "use of r15 in bx in ARM mode is not really useful"
+	// so we workaround that by using "bx r0"
+	__asm__ __volatile__ ("mov r0, pc");
+	__asm__ __volatile__ ("bx r0");
+	__asm__ __volatile__ (".word 0xeeb00b40"); // vomv.f64 d0, d0
+	__asm__ __volatile__ (".word 0xe12fff1e"); // bx lr
+}
+
+#endif
diff --git a/src/cmd/dist/buf.c b/src/cmd/dist/buf.c
new file mode 100644
index 0000000..2ddc6be
--- /dev/null
+++ b/src/cmd/dist/buf.c
@@ -0,0 +1,279 @@
+// 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.
+
+// Byte buffers and string vectors.
+
+#include "a.h"
+
+// binit prepares an uninitialized buffer for use.
+void
+binit(Buf *b)
+{
+	b->p = nil;
+	b->len = 0;
+	b->cap = 0;
+}
+
+// breset truncates the buffer back to zero length.
+void
+breset(Buf *b)
+{
+	b->len = 0;
+}
+
+// bfree frees the storage associated with a buffer.
+void
+bfree(Buf *b)
+{
+	xfree(b->p);
+	binit(b);
+}
+
+// bgrow ensures that the buffer has at least n more bytes
+// between its len and cap.
+void
+bgrow(Buf *b, int n)
+{
+	int want;
+	
+	want = b->len+n;
+	if(want > b->cap) {
+		b->cap = 2*want;
+		if(b->cap < 64)
+			b->cap = 64;
+		b->p = xrealloc(b->p, b->cap);
+	}
+}
+
+// bwrite appends the n bytes at v to the buffer.
+void
+bwrite(Buf *b, void *v, int n)
+{
+	bgrow(b, n);
+	xmemmove(b->p+b->len, v, n);
+	b->len += n;
+}
+
+// bwritestr appends the string p to the buffer.
+void
+bwritestr(Buf *b, char *p)
+{
+	bwrite(b, p, xstrlen(p));
+}
+
+// bstr returns a pointer to a NUL-terminated string of the
+// buffer contents.  The pointer points into the buffer.
+char*
+bstr(Buf *b)
+{
+	bgrow(b, 1);
+	b->p[b->len] = '\0';
+	return b->p;
+}
+
+// btake takes ownership of the string form of the buffer.
+// After this call, the buffer has zero length and does not
+// refer to the memory that btake returned.
+char*
+btake(Buf *b)
+{
+	char *p;
+	
+	p = bstr(b);
+	binit(b);
+	return p;
+}
+
+// bwriteb appends the src buffer to the dst buffer.
+void
+bwriteb(Buf *dst, Buf *src)
+{
+	bwrite(dst, src->p, src->len);
+}
+
+// bequal reports whether the buffers have the same content.
+bool
+bequal(Buf *s, Buf *t)
+{
+	return s->len == t->len && xmemcmp(s->p, t->p, s->len) == 0;
+}
+
+// bsubst rewites b to replace all occurrences of x with y.
+void
+bsubst(Buf *b, char *x, char *y)
+{
+	char *p;
+	int nx, ny, pos;
+
+	nx = xstrlen(x);
+	ny = xstrlen(y);
+
+	pos = 0;
+	for(;;) {
+		p = xstrstr(bstr(b)+pos, x);
+		if(p == nil)
+			break;
+		if(nx != ny) {
+			if(nx < ny) {
+				pos = p - b->p;
+				bgrow(b, ny-nx);
+				p = b->p + pos;
+			}
+			xmemmove(p+ny, p+nx, (b->p+b->len)-(p+nx));
+		}
+		xmemmove(p, y, ny);
+		pos = p+ny - b->p;
+		b->len += ny - nx;
+	}
+}
+
+// The invariant with the vectors is that v->p[0:v->len] is allocated
+// strings that are owned by the vector.  The data beyond v->len may
+// be garbage.
+
+// vinit prepares an uninitialized vector for use.
+void
+vinit(Vec *v)
+{
+	v->p = nil;
+	v->len = 0;
+	v->cap = 0;
+}
+
+// vreset truncates the vector back to zero length.
+void
+vreset(Vec *v)
+{
+	int i;
+	
+	for(i=0; i<v->len; i++) {
+		xfree(v->p[i]);
+		v->p[i] = nil;
+	}
+	v->len = 0;
+}
+
+// vfree frees the storage associated with the vector.
+void
+vfree(Vec *v)
+{
+	vreset(v);
+	xfree(v->p);
+	vinit(v);
+}
+
+
+// vgrow ensures that the vector has room for at least 
+// n more entries between len and cap.
+void
+vgrow(Vec *v, int n)
+{
+	int want;
+	
+	want = v->len+n;
+	if(want > v->cap) {
+		v->cap = 2*want;
+		if(v->cap < 64)
+			v->cap = 64;
+		v->p = xrealloc(v->p, v->cap*sizeof v->p[0]);
+	}
+}
+
+// vcopy copies the srclen strings at src into the vector.
+void
+vcopy(Vec *dst, char **src, int srclen)
+{
+	int i;
+	
+	// use vadd, to make copies of strings
+	for(i=0; i<srclen; i++)
+		vadd(dst, src[i]);
+}
+
+// vadd adds a copy of the string p to the vector.
+void
+vadd(Vec *v, char *p)
+{
+	vgrow(v, 1);
+	if(p != nil)
+		p = xstrdup(p);
+	v->p[v->len++] = p;
+}
+
+// vaddn adds a string consisting of the n bytes at p to the vector.
+static void
+vaddn(Vec *v, char *p, int n)
+{
+	char *q;
+
+	vgrow(v, 1);
+	q = xmalloc(n+1);
+	xmemmove(q, p, n);
+	q[n] = '\0';
+	v->p[v->len++] = q;
+}
+
+static int
+strpcmp(const void *a, const void *b)
+{
+	return xstrcmp(*(char**)a, *(char**)b);
+}
+
+// vuniq sorts the vector and then discards duplicates,
+// in the manner of sort | uniq.
+void
+vuniq(Vec *v)
+{
+	int i, n;
+
+	xqsort(v->p, v->len, sizeof(v->p[0]), strpcmp);
+	n = 0;
+	for(i=0; i<v->len; i++) {
+		if(n>0 && streq(v->p[i], v->p[n-1]))
+			xfree(v->p[i]);
+		else
+			v->p[n++] = v->p[i];
+	}
+	v->len = n;
+}
+
+// splitlines replaces the vector v with the result of splitting
+// the input p after each \n.
+void
+splitlines(Vec *v, char *p)
+{
+	int i;
+	char *start;
+	
+	vreset(v);
+	start = p;
+	for(i=0; p[i]; i++) {
+		if(p[i] == '\n') {
+			vaddn(v, start, (p+i+1)-start);
+			start = p+i+1;
+		}
+	}
+	if(*start != '\0')
+		vadd(v, start);
+}
+
+// splitfields replaces the vector v with the result of splitting
+// the input p into non-empty fields containing no spaces.
+void
+splitfields(Vec *v, char *p)
+{
+	char *start;
+
+	vreset(v);
+	for(;;) {
+		while(*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n')
+			p++;
+		if(*p == '\0')
+			break;
+		start = p;
+		while(*p != ' ' && *p != '\t' && *p != '\r' && *p != '\n' && *p != '\0')
+			p++;
+		vaddn(v, start, p-start);
+	}
+}
diff --git a/src/cmd/dist/build.c b/src/cmd/dist/build.c
new file mode 100644
index 0000000..b6c61b4
--- /dev/null
+++ b/src/cmd/dist/build.c
@@ -0,0 +1,1804 @@
+// 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 "a.h"
+#include "arg.h"
+
+/*
+ * Initialization for any invocation.
+ */
+
+// The usual variables.
+char *goarch;
+char *gobin;
+char *gohostarch;
+char *gohostchar;
+char *gohostos;
+char *goos;
+char *goarm;
+char *go386;
+char *goroot = GOROOT_FINAL;
+char *goroot_final = GOROOT_FINAL;
+char *goextlinkenabled = "";
+char *workdir;
+char *tooldir;
+char *gochar;
+char *goversion;
+char *slash;	// / for unix, \ for windows
+char *defaultcc;
+char *defaultcflags;
+char *defaultldflags;
+char *defaultcxxtarget;
+char *defaultcctarget;
+bool	rebuildall;
+bool defaultclang;
+
+static bool shouldbuild(char*, char*);
+static void dopack(char*, char*, char**, int);
+static char *findgoversion(void);
+
+// The known architecture letters.
+static char *gochars = "5668";
+
+// The known architectures.
+static char *okgoarch[] = {
+	// same order as gochars
+	"arm",
+	"amd64",
+	"amd64p32",
+	"386",
+};
+
+// The known operating systems.
+static char *okgoos[] = {
+	"darwin",
+	"dragonfly",
+	"linux",
+	"android",
+	"solaris",
+	"freebsd",
+	"nacl",
+	"netbsd",
+	"openbsd",
+	"plan9",
+	"windows",
+};
+
+static void rmworkdir(void);
+
+// find reports the first index of p in l[0:n], or else -1.
+int
+find(char *p, char **l, int n)
+{
+	int i;
+
+	for(i=0; i<n; i++)
+		if(streq(p, l[i]))
+			return i;
+	return -1;
+}
+
+// init handles initialization of the various global state, like goroot and goarch.
+void
+init(void)
+{
+	char *p;
+	int i;
+	Buf b;
+
+	binit(&b);
+
+	xgetenv(&b, "GOROOT");
+	if(b.len > 0) {
+		// if not "/", then strip trailing path separator
+		if(b.len >= 2 && b.p[b.len - 1] == slash[0])
+			b.len--;
+		goroot = btake(&b);
+	}
+
+	xgetenv(&b, "GOBIN");
+	if(b.len == 0)
+		bprintf(&b, "%s%sbin", goroot, slash);
+	gobin = btake(&b);
+
+	xgetenv(&b, "GOOS");
+	if(b.len == 0)
+		bwritestr(&b, gohostos);
+	goos = btake(&b);
+	if(find(goos, okgoos, nelem(okgoos)) < 0)
+		fatal("unknown $GOOS %s", goos);
+
+	xgetenv(&b, "GOARM");
+	if(b.len == 0)
+		bwritestr(&b, xgetgoarm());
+	goarm = btake(&b);
+
+	xgetenv(&b, "GO386");
+	if(b.len == 0) {
+		if(cansse2())
+			bwritestr(&b, "sse2");
+		else
+			bwritestr(&b, "387");
+	}
+	go386 = btake(&b);
+
+	p = bpathf(&b, "%s/include/u.h", goroot);
+	if(!isfile(p)) {
+		fatal("$GOROOT is not set correctly or not exported\n"
+			"\tGOROOT=%s\n"
+			"\t%s does not exist", goroot, p);
+	}
+
+	xgetenv(&b, "GOHOSTARCH");
+	if(b.len > 0)
+		gohostarch = btake(&b);
+
+	i = find(gohostarch, okgoarch, nelem(okgoarch));
+	if(i < 0)
+		fatal("unknown $GOHOSTARCH %s", gohostarch);
+	bprintf(&b, "%c", gochars[i]);
+	gohostchar = btake(&b);
+
+	xgetenv(&b, "GOARCH");
+	if(b.len == 0)
+		bwritestr(&b, gohostarch);
+	goarch = btake(&b);
+	i = find(goarch, okgoarch, nelem(okgoarch));
+	if(i < 0)
+		fatal("unknown $GOARCH %s", goarch);
+	bprintf(&b, "%c", gochars[i]);
+	gochar = btake(&b);
+
+	xgetenv(&b, "GO_EXTLINK_ENABLED");
+	if(b.len > 0) {
+		goextlinkenabled = btake(&b);
+		if(!streq(goextlinkenabled, "0") && !streq(goextlinkenabled, "1"))
+			fatal("unknown $GO_EXTLINK_ENABLED %s", goextlinkenabled);
+	}
+	
+	xgetenv(&b, "CC");
+	if(b.len == 0) {
+		// Use clang on OS X, because gcc is deprecated there.
+		// Xcode for OS X 10.9 Mavericks will ship a fake "gcc" binary that
+		// actually runs clang. We prepare different command
+		// lines for the two binaries, so it matters what we call it.
+		// See golang.org/issue/5822.
+		if(defaultclang)
+			bprintf(&b, "clang");
+		else
+			bprintf(&b, "gcc");
+	}
+	defaultcc = btake(&b);
+
+	xgetenv(&b, "CFLAGS");
+	defaultcflags = btake(&b);
+
+	xgetenv(&b, "LDFLAGS");
+	defaultldflags = btake(&b);
+
+	xgetenv(&b, "CC_FOR_TARGET");
+	if(b.len == 0) {
+		bprintf(&b, defaultcc);
+	}
+	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);
+	xsetenv("GOOS", goos);
+	xsetenv("GOARM", goarm);
+	xsetenv("GO386", go386);
+
+	// Make the environment more predictable.
+	xsetenv("LANG", "C");
+	xsetenv("LANGUAGE", "en_US.UTF8");
+
+	goversion = findgoversion();
+
+	workdir = xworkdir();
+	xatexit(rmworkdir);
+
+	bpathf(&b, "%s/pkg/tool/%s_%s", goroot, gohostos, gohostarch);
+	tooldir = btake(&b);
+
+	bfree(&b);
+}
+
+// rmworkdir deletes the work directory.
+static void
+rmworkdir(void)
+{
+	if(vflag > 1)
+		errprintf("rm -rf %s\n", workdir);
+	xremoveall(workdir);
+}
+
+// Remove trailing spaces.
+static void
+chomp(Buf *b)
+{
+	int c;
+
+	while(b->len > 0 && ((c=b->p[b->len-1]) == ' ' || c == '\t' || c == '\r' || c == '\n'))
+		b->len--;
+}
+
+static char*
+branchtag(char *branch, bool *precise)
+{
+	char *tag, *p, *q;
+	int i;
+	Buf b, arg;
+	Vec tags;
+
+	binit(&b);
+	binit(&arg);
+	vinit(&tags);
+
+	bprintf(&arg, "master..%s", branch);
+	run(&b, goroot, CheckExit, "git", "log", "--decorate=full", "--format=format:%d", bstr(&arg), nil);
+
+	splitlines(&tags, bstr(&b));
+	tag = branch;
+	for(i=0; i < tags.len; i++) {
+		// Each line is either blank, or looks like
+		//	  (tag: refs/tags/go1.4rc2, refs/remotes/origin/release-branch.go1.4, refs/heads/release-branch.go1.4)
+		// We need to find an element starting with refs/tags/.
+		p = xstrstr(tags.p[i], " refs/tags/");
+		if(p == nil)
+			continue;
+		p += xstrlen(" refs/tags/");
+		// The tag name ends at a comma or paren (prefer the first).
+		q = xstrstr(p, ",");
+		if(q == nil)
+			q = xstrstr(p, ")");
+		if(q == nil)
+			continue;  // malformed line; ignore it
+		*q = '\0';
+		tag = xstrdup(p);
+		if(i == 0)
+			*precise = 1;  // tag denotes HEAD
+		break;
+	}
+
+	bfree(&b);
+	bfree(&arg);
+	vfree(&tags);
+	return tag;
+}
+
+// findgoversion determines the Go version to use in the version string.
+static char*
+findgoversion(void)
+{
+	char *tag, *p;
+	bool precise;
+	Buf b, path, bmore, branch;
+
+	binit(&b);
+	binit(&path);
+	binit(&bmore);
+	binit(&branch);
+
+	// The $GOROOT/VERSION file takes priority, for distributions
+	// without the source repo.
+	bpathf(&path, "%s/VERSION", goroot);
+	if(isfile(bstr(&path))) {
+		readfile(&b, bstr(&path));
+		chomp(&b);
+		// Commands such as "dist version > VERSION" will cause
+		// the shell to create an empty VERSION file and set dist's
+		// stdout to its fd. dist in turn looks at VERSION and uses
+		// its content if available, which is empty at this point.
+		if(b.len > 0)
+			goto done;
+	}
+
+	// The $GOROOT/VERSION.cache file is a cache to avoid invoking
+	// git every time we run this command.  Unlike VERSION, it gets
+	// deleted by the clean command.
+	bpathf(&path, "%s/VERSION.cache", goroot);
+	if(isfile(bstr(&path))) {
+		readfile(&b, bstr(&path));
+		chomp(&b);
+		goto done;
+	}
+
+	// Otherwise, use Git.
+	// What is the current branch?
+	run(&branch, goroot, CheckExit, "git", "rev-parse", "--abbrev-ref", "HEAD", nil);
+	chomp(&branch);
+
+	// What are the tags along the current branch?
+	tag = "devel";
+	precise = 0;
+
+	// If we're on a release branch, use the closest matching tag
+	// that is on the release branch (and not on the master branch).
+	if(hasprefix(bstr(&branch), "release-branch."))
+		tag = branchtag(bstr(&branch), &precise);
+
+	bprintf(&b, "%s", tag);
+	if(!precise) {
+		// Tag does not point at HEAD; add hash and date to version.
+		run(&bmore, goroot, CheckExit, "git", "log", "-n", "1", "--format=format: +%h %cd", "HEAD", nil);
+		chomp(&bmore);
+		bwriteb(&b, &bmore);
+	}
+
+	// Cache version.
+	writefile(&b, bstr(&path), 0);
+
+done:
+	p = btake(&b);
+
+
+	bfree(&b);
+	bfree(&path);
+	bfree(&bmore);
+	bfree(&branch);
+
+	return p;
+}
+
+/*
+ * Initial tree setup.
+ */
+
+// The old tools that no longer live in $GOBIN or $GOROOT/bin.
+static char *oldtool[] = {
+	"5a", "5c", "5g", "5l",
+	"6a", "6c", "6g", "6l",
+	"8a", "8c", "8g", "8l",
+	"6cov",
+	"6nm",
+	"6prof",
+	"cgo",
+	"ebnflint",
+	"goapi",
+	"gofix",
+	"goinstall",
+	"gomake",
+	"gopack",
+	"gopprof",
+	"gotest",
+	"gotype",
+	"govet",
+	"goyacc",
+	"quietgcc",
+};
+
+// Unreleased directories (relative to $GOROOT) that should
+// not be in release branches.
+static char *unreleased[] = {
+	"src/cmd/link",
+	"src/debug/goobj",
+	"src/old",
+};
+
+// setup sets up the tree for the initial build.
+static void
+setup(void)
+{
+	int i;
+	Buf b;
+	char *p;
+
+	binit(&b);
+
+	// Create bin directory.
+	p = bpathf(&b, "%s/bin", goroot);
+	if(!isdir(p))
+		xmkdir(p);
+
+	// Create package directory.
+	p = bpathf(&b, "%s/pkg", goroot);
+	if(!isdir(p))
+		xmkdir(p);
+	p = bpathf(&b, "%s/pkg/%s_%s", goroot, gohostos, gohostarch);
+	if(rebuildall)
+		xremoveall(p);
+	xmkdirall(p);
+	if(!streq(goos, gohostos) || !streq(goarch, gohostarch)) {
+		p = bpathf(&b, "%s/pkg/%s_%s", goroot, goos, goarch);
+		if(rebuildall)
+			xremoveall(p);
+		xmkdirall(p);
+	}
+
+	// Create object directory.
+	// We keep it in pkg/ so that all the generated binaries
+	// are in one tree.  If pkg/obj/libgc.a exists, it is a dreg from
+	// before we used subdirectories of obj.  Delete all of obj
+	// to clean up.
+	bpathf(&b, "%s/pkg/obj/libgc.a", goroot);
+	if(isfile(bstr(&b)))
+		xremoveall(bpathf(&b, "%s/pkg/obj", goroot));
+	p = bpathf(&b, "%s/pkg/obj/%s_%s", goroot, gohostos, gohostarch);
+	if(rebuildall)
+		xremoveall(p);
+	xmkdirall(p);
+
+	// Create tool directory.
+	// We keep it in pkg/, just like the object directory above.
+	if(rebuildall)
+		xremoveall(tooldir);
+	xmkdirall(tooldir);
+
+	// Remove tool binaries from before the tool/gohostos_gohostarch
+	xremoveall(bpathf(&b, "%s/bin/tool", goroot));
+
+	// Remove old pre-tool binaries.
+	for(i=0; i<nelem(oldtool); i++)
+		xremove(bpathf(&b, "%s/bin/%s", goroot, oldtool[i]));
+
+	// If $GOBIN is set and has a Go compiler, it must be cleaned.
+	for(i=0; gochars[i]; i++) {
+		if(isfile(bprintf(&b, "%s%s%c%s", gobin, slash, gochars[i], "g"))) {
+			for(i=0; i<nelem(oldtool); i++)
+				xremove(bprintf(&b, "%s%s%s", gobin, slash, oldtool[i]));
+			break;
+		}
+	}
+
+	// For release, make sure excluded things are excluded.
+	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));
+	}
+
+	bfree(&b);
+}
+
+/*
+ * C library and tool building
+ */
+
+// gccargs is the gcc command line to use for compiling a single C file.
+static char *proto_gccargs[] = {
+	"-Wall",
+	// native Plan 9 compilers don't like non-standard prototypes
+	// so let gcc catch them.
+	"-Wstrict-prototypes",
+	"-Wextra",
+	"-Wunused",
+	"-Wno-sign-compare",
+	"-Wno-missing-braces",
+	"-Wno-parentheses",
+	"-Wno-unknown-pragmas",
+	"-Wno-switch",
+	"-Wno-comment",
+	"-Wno-missing-field-initializers",
+	"-Werror",
+	"-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/.
+	"-O1",
+#else
+	"-O2",
+#endif
+};
+
+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 -
+// exclude files with that prefix.
+static struct {
+	char *prefix;  // prefix of target
+	char *dep[20];  // dependency tweaks for targets with that prefix
+} deptab[] = {
+	{"lib9", {
+		"$GOROOT/include/u.h",
+		"$GOROOT/include/utf.h",
+		"$GOROOT/include/fmt.h",
+		"$GOROOT/include/libc.h",
+		"fmt/*",
+		"utf/*",
+	}},
+	{"libbio", {
+		"$GOROOT/include/u.h",
+		"$GOROOT/include/utf.h",
+		"$GOROOT/include/fmt.h",
+		"$GOROOT/include/libc.h",
+		"$GOROOT/include/bio.h",
+	}},
+	{"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/link.h",
+		"anames5.c",
+		"anames6.c",
+		"anames8.c",
+	}},
+	{"cmd/cc", {
+		"-pgen.c",
+		"-pswt.c",
+	}},
+	{"cmd/gc", {
+		"-cplx.c",
+		"-pgen.c",
+		"-plive.c",
+		"-popt.c",
+		"-y1.tab.c",  // makefile dreg
+		"opnames.h",
+	}},
+	{"cmd/5c", {
+		"../cc/pgen.c",
+		"../cc/pswt.c",
+		"$GOROOT/pkg/obj/$GOHOSTOS_$GOHOSTARCH/libcc.a",
+	}},
+	{"cmd/6c", {
+		"../cc/pgen.c",
+		"../cc/pswt.c",
+		"$GOROOT/pkg/obj/$GOHOSTOS_$GOHOSTARCH/libcc.a",
+	}},
+	{"cmd/8c", {
+		"../cc/pgen.c",
+		"../cc/pswt.c",
+		"$GOROOT/pkg/obj/$GOHOSTOS_$GOHOSTARCH/libcc.a",
+	}},
+	{"cmd/5g", {
+		"../gc/cplx.c",
+		"../gc/pgen.c",
+		"../gc/plive.c",
+		"../gc/popt.c",
+		"../gc/popt.h",
+		"$GOROOT/pkg/obj/$GOHOSTOS_$GOHOSTARCH/libgc.a",
+	}},
+	{"cmd/6g", {
+		"../gc/cplx.c",
+		"../gc/pgen.c",
+		"../gc/plive.c",
+		"../gc/popt.c",
+		"../gc/popt.h",
+		"$GOROOT/pkg/obj/$GOHOSTOS_$GOHOSTARCH/libgc.a",
+	}},
+	{"cmd/8g", {
+		"../gc/cplx.c",
+		"../gc/pgen.c",
+		"../gc/plive.c",
+		"../gc/popt.c",
+		"../gc/popt.h",
+		"$GOROOT/pkg/obj/$GOHOSTOS_$GOHOSTARCH/libgc.a",
+	}},
+	{"cmd/5l", {
+		"../ld/*",
+	}},
+	{"cmd/6l", {
+		"../ld/*",
+	}},
+	{"cmd/8l", {
+		"../ld/*",
+	}},
+	{"cmd/go", {
+		"zdefaultcc.go",
+	}},
+	{"cmd/", {
+		"$GOROOT/pkg/obj/$GOHOSTOS_$GOHOSTARCH/liblink.a",
+		"$GOROOT/pkg/obj/$GOHOSTOS_$GOHOSTARCH/libbio.a",
+		"$GOROOT/pkg/obj/$GOHOSTOS_$GOHOSTARCH/lib9.a",
+	}},
+	{"runtime", {
+		"zaexperiment.h", // must sort above zasm
+		"zasm_$GOOS_$GOARCH.h",
+		"zsys_$GOOS_$GOARCH.s",
+		"zgoarch_$GOARCH.go",
+		"zgoos_$GOOS.go",
+		"zruntime_defs_$GOOS_$GOARCH.go",
+		"zversion.go",
+	}},
+};
+
+// depsuffix records the allowed suffixes for source files.
+char *depsuffix[] = {
+	".c",
+	".h",
+	".s",
+	".go",
+};
+
+// gentab records how to generate some trivial files.
+static struct {
+	char *nameprefix;
+	void (*gen)(char*, char*);
+} gentab[] = {
+	{"opnames.h", gcopnames},
+	{"anames5.c", mkanames},
+	{"anames6.c", mkanames},
+	{"anames8.c", mkanames},
+	{"zasm_", mkzasm},
+	{"zdefaultcc.go", mkzdefaultcc},
+	{"zsys_", mkzsys},
+	{"zgoarch_", mkzgoarch},
+	{"zgoos_", mkzgoos},
+	{"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,
+// which is relative to $GOROOT/src.
+static void
+install(char *dir)
+{
+	char *name, *p, *elem, *prefix, *exe;
+	bool islib, ispkg, isgo, stale, ispackcmd;
+	Buf b, b1, path, final_path, final_name;
+	Vec compile, files, link, go, missing, clean, lib, extra;
+	Time ttarg, t;
+	int i, j, k, n, doclean, targ;
+
+	if(vflag) {
+		if(!streq(goos, gohostos) || !streq(goarch, gohostarch))
+			errprintf("%s (%s/%s)\n", dir, goos, goarch);
+		else
+			errprintf("%s\n", dir);
+	}
+
+	binit(&b);
+	binit(&b1);
+	binit(&path);
+	binit(&final_path);
+	binit(&final_name);
+	vinit(&compile);
+	vinit(&files);
+	vinit(&link);
+	vinit(&go);
+	vinit(&missing);
+	vinit(&clean);
+	vinit(&lib);
+	vinit(&extra);
+
+
+	// path = full path to dir.
+	bpathf(&path, "%s/src/%s", goroot, dir);
+	bpathf(&final_path, "%s/src/%s", goroot_final, dir);
+	name = lastelem(dir);
+
+	// set up gcc command line on first run.
+	if(gccargs.len == 0) {
+		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 = !islib && !hasprefix(dir, "cmd/");
+	isgo = ispkg || streq(dir, "cmd/go") || streq(dir, "cmd/cgo");
+
+	exe = "";
+	if(streq(gohostos, "windows"))
+		exe = ".exe";
+
+	// 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");
+		if(streq(gohostos, "plan9"))
+			vadd(&link, "rc");
+		else
+			vadd(&link, "rsc");
+		prefix = "";
+		if(!hasprefix(name, "lib"))
+			prefix = "lib";
+		targ = link.len;
+		vadd(&link, bpathf(&b, "%s/pkg/obj/%s_%s/%s%s.a", goroot, gohostos, gohostarch, prefix, name));
+	} else if(ispkg) {
+		// Go library (package).
+		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);
+		*xstrrchr(p, '/') = '\0';
+		xmkdirall(p);
+		targ = link.len;
+		vadd(&link, bpathf(&b, "%s/pkg/%s_%s/%s.a", goroot, goos, goarch, dir));
+	} else if(streq(dir, "cmd/go") || streq(dir, "cmd/cgo")) {
+		// Go command.
+		vadd(&link, bpathf(&b, "%s/%sl", tooldir, gochar));
+		vadd(&link, "-o");
+		elem = name;
+		if(streq(elem, "go"))
+			elem = "go_bootstrap";
+		targ = link.len;
+		vadd(&link, bpathf(&b, "%s/%s%s", tooldir, elem, exe));
+	} else {
+		// C command. Use gccargs and ldargs.
+		if(streq(gohostos, "plan9")) {
+			vadd(&link, bprintf(&b, "%sl", gohostchar));
+			vadd(&link, "-o");
+			targ = link.len;
+			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");
+			targ = link.len;
+			vadd(&link, bpathf(&b, "%s/%s%s", tooldir, name, exe));
+			if(streq(gohostarch, "amd64"))
+				vadd(&link, "-m64");
+			else if(streq(gohostarch, "386"))
+				vadd(&link, "-m32");
+		}
+	}
+	ttarg = mtime(link.p[targ]);
+
+	// Gather files that are sources for this target.
+	// Everything in that directory, and any target-specific
+	// additions.
+	xreaddir(&files, bstr(&path));
+
+	// Remove files beginning with . or _,
+	// which are likely to be editor temporary files.
+	// This is the same heuristic build.ScanDir uses.
+	// There do exist real C files beginning with _,
+	// so limit that check to just Go files.
+	n = 0;
+	for(i=0; i<files.len; i++) {
+		p = files.p[i];
+		if(hasprefix(p, ".") || (hasprefix(p, "_") && hassuffix(p, ".go")))
+			xfree(p);
+		else
+			files.p[n++] = p;
+	}
+	files.len = n;
+
+	for(i=0; i<nelem(deptab); i++) {
+		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")) {
+					vadd(&lib, bpathf(&b, "%s", p));
+					continue;
+				}
+				if(hassuffix(p, "/*")) {
+					bpathf(&b, "%s/%s", bstr(&path), p);
+					b.len -= 2;
+					xreaddir(&extra, bstr(&b));
+					bprintf(&b, "%s", p);
+					b.len -= 2;
+					for(k=0; k<extra.len; k++)
+						vadd(&files, bpathf(&b1, "%s/%s", bstr(&b), extra.p[k]));
+					continue;
+				}
+				if(hasprefix(p, "-")) {
+					p++;
+					n = 0;
+					for(k=0; k<files.len; k++) {
+						if(hasprefix(files.p[k], p))
+							xfree(files.p[k]);
+						else
+							files.p[n++] = files.p[k];
+					}
+					files.len = n;
+					continue;
+				}
+				vadd(&files, p);
+			}
+		}
+	}
+	vuniq(&files);
+
+	// Convert to absolute paths.
+	for(i=0; i<files.len; i++) {
+		if(!isabs(files.p[i])) {
+			bpathf(&b, "%s/%s", bstr(&path), files.p[i]);
+			xfree(files.p[i]);
+			files.p[i] = btake(&b);
+		}
+	}
+
+	// Is the target up-to-date?
+	stale = rebuildall;
+	n = 0;
+	for(i=0; i<files.len; i++) {
+		p = files.p[i];
+		for(j=0; j<nelem(depsuffix); j++)
+			if(hassuffix(p, depsuffix[j]))
+				goto ok;
+		xfree(files.p[i]);
+		continue;
+	ok:
+		t = mtime(p);
+		if(t != 0 && !hassuffix(p, ".a") && !shouldbuild(p, dir)) {
+			xfree(files.p[i]);
+			continue;
+		}
+		if(hassuffix(p, ".go"))
+			vadd(&go, p);
+		if(t > ttarg)
+			stale = 1;
+		if(t == 0) {
+			vadd(&missing, p);
+			files.p[n++] = files.p[i];
+			continue;
+		}
+		files.p[n++] = files.p[i];
+	}
+	files.len = n;
+
+	// If there are no files to compile, we're done.
+	if(files.len == 0)
+		goto out;
+	
+	for(i=0; i<lib.len && !stale; i++)
+		if(mtime(lib.p[i]) > ttarg)
+			stale = 1;
+
+	if(!stale)
+		goto out;
+
+	// For package runtime, copy some files into the work space.
+	if(streq(dir, "runtime")) {
+		copyfile(bpathf(&b, "%s/arch_GOARCH.h", workdir),
+			bpathf(&b1, "%s/arch_%s.h", bstr(&path), goarch), 0);
+		copyfile(bpathf(&b, "%s/defs_GOOS_GOARCH.h", workdir),
+			bpathf(&b1, "%s/defs_%s_%s.h", bstr(&path), goos, goarch), 0);
+		p = bpathf(&b1, "%s/signal_%s_%s.h", bstr(&path), goos, goarch);
+		if(isfile(p))
+			copyfile(bpathf(&b, "%s/signal_GOOS_GOARCH.h", workdir), p, 0);
+		copyfile(bpathf(&b, "%s/os_GOOS.h", workdir),
+			bpathf(&b1, "%s/os_%s.h", bstr(&path), goos), 0);
+		copyfile(bpathf(&b, "%s/signals_GOOS.h", workdir),
+			bpathf(&b1, "%s/signals_%s.h", bstr(&path), goos), 0);
+		copyfile(bpathf(&b, "%s/pkg/%s_%s/textflag.h", goroot, goos, goarch),
+			bpathf(&b1, "%s/src/cmd/ld/textflag.h", goroot), 0);
+		copyfile(bpathf(&b, "%s/pkg/%s_%s/funcdata.h", goroot, goos, goarch),
+			bpathf(&b1, "%s/src/runtime/funcdata.h", goroot), 0);
+	}
+
+	// Generate any missing files; regenerate existing ones.
+	for(i=0; i<files.len; i++) {
+		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);
+				gentab[j].gen(bstr(&path), p);
+				// Do not add generated file to clean list.
+				// In runtime, we want to be able to
+				// build the package with the go tool,
+				// and it assumes these generated files already
+				// exist (it does not know how to build them).
+				// The 'clean' command can remove
+				// the generated files.
+				goto built;
+			}
+		}
+		// Did not rebuild p.
+		if(find(p, missing.p, missing.len) >= 0)
+			fatal("missing file %s", p);
+	built:;
+	}
+
+	// One more copy for package runtime.
+	// The last batch was required for the generators.
+	// This one is generated.
+	if(streq(dir, "runtime")) {
+		copyfile(bpathf(&b, "%s/zasm_GOOS_GOARCH.h", workdir),
+			bpathf(&b1, "%s/zasm_%s_%s.h", bstr(&path), goos, goarch), 0);
+	}
+
+	if((!streq(goos, gohostos) || !streq(goarch, gohostarch)) && isgo) {
+		// We've generated the right files; the go command can do the build.
+		if(vflag > 1)
+			errprintf("skip build for cross-compile %s\n", dir);
+		goto nobuild;
+	}
+
+	// Compile the files.
+	for(i=0; i<files.len; i++) {
+		if(!hassuffix(files.p[i], ".c") && !hassuffix(files.p[i], ".s"))
+			continue;
+		name = lastelem(files.p[i]);
+
+		vreset(&compile);
+		if(!isgo) {
+			// C library or tool.
+			if(streq(gohostos, "plan9")) {
+				vadd(&compile, bprintf(&b, "%sc", gohostchar));
+				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));
+			} else {
+				vcopy(&compile, gccargs.p, gccargs.len);
+				vadd(&compile, "-c");
+				if(streq(gohostarch, "amd64"))
+					vadd(&compile, "-m64");
+				else if(streq(gohostarch, "386"))
+					vadd(&compile, "-m32");
+	
+				vadd(&compile, "-I");
+				vadd(&compile, bpathf(&b, "%s/include", goroot));
+			}
+
+			if(streq(dir, "lib9"))
+				vadd(&compile, "-DPLAN9PORT");
+
+
+			vadd(&compile, "-I");
+			vadd(&compile, bstr(&path));
+
+			// lib9/goos.c gets the default constants hard-coded.
+			if(streq(name, "goos.c")) {
+				vadd(&compile, "-D");
+				vadd(&compile, bprintf(&b, "GOOS=\"%s\"", goos));
+				vadd(&compile, "-D");
+				vadd(&compile, bprintf(&b, "GOARCH=\"%s\"", goarch));
+				bprintf(&b1, "%s", goroot_final);
+				bsubst(&b1, "\\", "\\\\");  // turn into C string
+				vadd(&compile, "-D");
+				vadd(&compile, bprintf(&b, "GOROOT=\"%s\"", bstr(&b1)));
+				vadd(&compile, "-D");
+				vadd(&compile, bprintf(&b, "GOVERSION=\"%s\"", goversion));
+				vadd(&compile, "-D");
+				vadd(&compile, bprintf(&b, "GOARM=\"%s\"", goarm));
+				vadd(&compile, "-D");
+				vadd(&compile, bprintf(&b, "GO386=\"%s\"", go386));
+				vadd(&compile, "-D");
+				vadd(&compile, bprintf(&b, "GO_EXTLINK_ENABLED=\"%s\"", goextlinkenabled));
+			}
+
+			// gc/lex.c records the GOEXPERIMENT setting used during the build.
+			if(streq(name, "lex.c")) {
+				xgetenv(&b, "GOEXPERIMENT");
+				vadd(&compile, "-D");
+				vadd(&compile, bprintf(&b1, "GOEXPERIMENT=\"%s\"", bstr(&b)));
+			}
+		} else {
+			// Supporting files for a Go package.
+			if(hassuffix(files.p[i], ".s"))
+				vadd(&compile, bpathf(&b, "%s/%sa", tooldir, gochar));
+			else {
+				vadd(&compile, bpathf(&b, "%s/%sc", tooldir, gochar));
+				vadd(&compile, "-F");
+				vadd(&compile, "-V");
+				vadd(&compile, "-w");
+			}
+			vadd(&compile, "-I");
+			vadd(&compile, workdir);
+			vadd(&compile, "-I");
+			vadd(&compile, bprintf(&b, "%s/pkg/%s_%s", goroot, goos, goarch));
+			vadd(&compile, "-D");
+			vadd(&compile, bprintf(&b, "GOOS_%s", goos));
+			vadd(&compile, "-D");
+			vadd(&compile, bprintf(&b, "GOARCH_%s", goarch));
+			vadd(&compile, "-D");
+			vadd(&compile, bprintf(&b, "GOOS_GOARCH_%s_%s", goos, goarch));
+		}
+
+		bpathf(&b, "%s/%s", workdir, lastelem(files.p[i]));
+		doclean = 1;
+		if(!isgo && streq(gohostos, "darwin")) {
+			// To debug C programs on OS X, it is not enough to say -ggdb
+			// on the command line.  You have to leave the object files
+			// lying around too.  Leave them in pkg/obj/, which does not
+			// get removed when this tool exits.
+			bpathf(&b1, "%s/pkg/obj/%s", goroot, dir);
+			xmkdirall(bstr(&b1));
+			bpathf(&b, "%s/%s", bstr(&b1), lastelem(files.p[i]));
+			doclean = 0;
+		}
+
+		// Change the last character of the output file (which was c or s).
+		if(streq(gohostos, "plan9"))
+			b.p[b.len-1] = gohostchar[0];
+		else
+			b.p[b.len-1] = 'o';
+		vadd(&compile, "-o");
+		vadd(&compile, bstr(&b));
+		vadd(&compile, files.p[i]);
+		bgrunv(bstr(&path), CheckExit, &compile);
+
+		vadd(&link, bstr(&b));
+		if(doclean)
+			vadd(&clean, bstr(&b));
+	}
+	bgwait();
+
+	if(isgo) {
+		// The last loop was compiling individual files.
+		// Hand the Go files to the compiler en masse.
+		vreset(&compile);
+		vadd(&compile, bpathf(&b, "%s/%sg", tooldir, gochar));
+
+		bpathf(&b, "%s/_go_.a", workdir);
+		vadd(&compile, "-pack");
+		vadd(&compile, "-o");
+		vadd(&compile, bstr(&b));
+		vadd(&clean, bstr(&b));
+		if(!ispackcmd)
+			vadd(&link, bstr(&b));
+
+		vadd(&compile, "-p");
+		if(hasprefix(dir, "pkg/"))
+			vadd(&compile, dir+4);
+		else
+			vadd(&compile, "main");
+
+		if(streq(dir, "runtime"))
+			vadd(&compile, "-+");
+
+		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) {
+		// C binaries need the libraries explicitly, and -lm.
+		vcopy(&link, lib.p, lib.len);
+		if(!streq(gohostos, "plan9"))
+			vadd(&link, "-lm");
+	}
+
+	// Remove target before writing it.
+	xremove(link.p[targ]);
+
+	runv(nil, nil, CheckExit, &link);
+
+nobuild:
+	// In package runtime, we install runtime.h and cgocall.h too,
+	// for use by cgo compilation.
+	if(streq(dir, "runtime")) {
+		copyfile(bpathf(&b, "%s/pkg/%s_%s/cgocall.h", goroot, goos, goarch),
+			bpathf(&b1, "%s/src/runtime/cgocall.h", goroot), 0);
+		copyfile(bpathf(&b, "%s/pkg/%s_%s/runtime.h", goroot, goos, goarch),
+			bpathf(&b1, "%s/src/runtime/runtime.h", goroot), 0);
+	}
+
+
+out:
+	for(i=0; i<clean.len; i++)
+		xremove(clean.p[i]);
+
+	bfree(&b);
+	bfree(&b1);
+	bfree(&path);
+	vfree(&compile);
+	vfree(&files);
+	vfree(&link);
+	vfree(&go);
+	vfree(&missing);
+	vfree(&clean);
+	vfree(&lib);
+	vfree(&extra);
+}
+
+// matchfield reports whether the field matches this build.
+static bool
+matchfield(char *f)
+{
+	char *p;
+	bool res;
+
+	p = xstrrchr(f, ',');
+	if(p == nil)
+		return streq(f, goos) || streq(f, goarch) || streq(f, "cmd_go_bootstrap") || streq(f, "go1.1") || (streq(goos, "android") && streq(f, "linux"));
+	*p = 0;
+	res = matchfield(f) && matchfield(p+1);
+	*p = ',';
+	return res;
+}
+
+// shouldbuild reports whether we should build this file.
+// It applies the same rules that are used with context tags
+// in package go/build, except that the GOOS and GOARCH
+// can appear anywhere in the file name, not just after _.
+// In particular, they can be the entire file name (like windows.c).
+// We also allow the special tag cmd_go_bootstrap.
+// See ../go/bootstrap.go and package go/build.
+static bool
+shouldbuild(char *file, char *dir)
+{
+	char *name, *p;
+	int i, j, ret;
+	Buf b;
+	Vec lines, fields;
+	
+	// Check file name for GOOS or GOARCH.
+	name = lastelem(file);
+	for(i=0; i<nelem(okgoos); i++)
+		if(contains(name, okgoos[i]) && !streq(okgoos[i], goos))
+			return 0;
+	for(i=0; i<nelem(okgoarch); i++)
+		if(contains(name, okgoarch[i]) && !streq(okgoarch[i], goarch))
+			return 0;
+
+	// Omit test files.
+	if(contains(name, "_test"))
+		return 0;
+
+	// cmd/go/doc.go has a giant /* */ comment before
+	// it gets to the important detail that it is not part of
+	// package main.  We don't parse those comments,
+	// so special case that file.
+	if(hassuffix(file, "cmd/go/doc.go") || hassuffix(file, "cmd\\go\\doc.go"))
+		return 0;
+	if(hassuffix(file, "cmd/cgo/doc.go") || hassuffix(file, "cmd\\cgo\\doc.go"))
+		return 0;
+
+	// Check file contents for // +build lines.
+	binit(&b);
+	vinit(&lines);
+	vinit(&fields);
+
+	ret = 1;
+	readfile(&b, file);
+	splitlines(&lines, bstr(&b));
+	for(i=0; i<lines.len; i++) {
+		p = lines.p[i];
+		while(*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n')
+			p++;
+		if(*p == '\0')
+			continue;
+		if(contains(p, "package documentation")) {
+			ret = 0;
+			goto out;
+		}
+		if(contains(p, "package main") && !streq(dir, "cmd/go") && !streq(dir, "cmd/cgo")) {
+			ret = 0;
+			goto out;
+		}
+		if(!hasprefix(p, "//"))
+			break;
+		if(!contains(p, "+build"))
+			continue;
+		splitfields(&fields, lines.p[i]);
+		if(fields.len < 2 || !streq(fields.p[1], "+build"))
+			continue;
+		for(j=2; j<fields.len; j++) {
+			p = fields.p[j];
+			if((*p == '!' && !matchfield(p+1)) || matchfield(p))
+				goto fieldmatch;
+		}
+		ret = 0;
+		goto out;
+	fieldmatch:;
+	}
+
+out:
+	bfree(&b);
+	vfree(&lines);
+	vfree(&fields);
+
+	return ret;
+}
+
+// copy copies the file src to dst, via memory (so only good for small files).
+void
+copyfile(char *dst, char *src, int exec)
+{
+	Buf b;
+
+	if(vflag > 1)
+		errprintf("cp %s %s\n", src, dst);
+
+	binit(&b);
+	readfile(&b, src);
+	writefile(&b, dst, 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",
+	"liblink",
+
+	"cmd/cc",  // must be before c
+	"cmd/gc",  // must be before g
+	"cmd/%sl",  // must be before a, c, g
+	"cmd/%sa",
+	"cmd/%sc",
+	"cmd/%sg",
+
+	// The dependency order here was copied from a buildscript
+	// back when there were build scripts.  Will have to
+	// be maintained by hand, but shouldn't change very
+	// often.
+	"runtime",
+	"errors",
+	"sync/atomic",
+	"sync",
+	"io",
+	"unicode",
+	"unicode/utf8",
+	"unicode/utf16",
+	"bytes",
+	"math",
+	"strings",
+	"strconv",
+	"bufio",
+	"sort",
+	"container/heap",
+	"encoding/base64",
+	"syscall",
+	"time",
+	"os",
+	"reflect",
+	"fmt",
+	"encoding",
+	"encoding/json",
+	"flag",
+	"path/filepath",
+	"path",
+	"io/ioutil",
+	"log",
+	"regexp/syntax",
+	"regexp",
+	"go/token",
+	"go/scanner",
+	"go/ast",
+	"go/parser",
+	"os/exec",
+	"os/signal",
+	"net/url",
+	"text/template/parse",
+	"text/template",
+	"go/doc",
+	"go/build",
+	"cmd/go",
+};
+
+// cleantab records the directories to clean in 'go clean'.
+// It is bigger than the buildorder because we clean all the
+// compilers but build only the $GOARCH ones.
+static char *cleantab[] = {
+	// Commands and C libraries.
+	"cmd/5a",
+	"cmd/5c",
+	"cmd/5g",
+	"cmd/5l",
+	"cmd/6a",
+	"cmd/6c",
+	"cmd/6g",
+	"cmd/6l",
+	"cmd/8a",
+	"cmd/8c",
+	"cmd/8g",
+	"cmd/8l",
+	"cmd/cc",
+	"cmd/gc",
+	"cmd/go",	
+	"lib9",
+	"libbio",
+	"liblink",
+
+	// Go packages.
+	"bufio",
+	"bytes",
+	"container/heap",
+	"encoding",
+	"encoding/base64",
+	"encoding/json",
+	"errors",
+	"flag",
+	"fmt",
+	"go/ast",
+	"go/build",
+	"go/doc",
+	"go/parser",
+	"go/scanner",
+	"go/token",
+	"io",
+	"io/ioutil",
+	"log",
+	"math",
+	"net/url",
+	"os",
+	"os/exec",
+	"path",
+	"path/filepath",
+	"reflect",
+	"regexp",
+	"regexp/syntax",
+	"runtime",
+	"sort",
+	"strconv",
+	"strings",
+	"sync",
+	"sync/atomic",
+	"syscall",
+	"text/template",
+	"text/template/parse",
+	"time",
+	"unicode",
+	"unicode/utf16",
+	"unicode/utf8",
+};
+
+static void
+clean(void)
+{
+	int i, j, k;
+	Buf b, path;
+	Vec dir;
+
+	binit(&b);
+	binit(&path);
+	vinit(&dir);
+
+	for(i=0; i<nelem(cleantab); i++) {
+		bpathf(&path, "%s/src/%s", goroot, cleantab[i]);
+		xreaddir(&dir, bstr(&path));
+		// Remove generated files.
+		for(j=0; j<dir.len; j++) {
+			for(k=0; k<nelem(gentab); k++) {
+				if(hasprefix(dir.p[j], gentab[k].nameprefix))
+					xremove(bpathf(&b, "%s/%s", bstr(&path), dir.p[j]));
+			}
+		}
+		// Remove generated binary named for directory.
+		if(hasprefix(cleantab[i], "cmd/"))
+			xremove(bpathf(&b, "%s/%s", bstr(&path), cleantab[i]+4));
+	}
+
+	// remove src/runtime/z* unconditionally
+	vreset(&dir);
+	bpathf(&path, "%s/src/runtime", goroot);
+	xreaddir(&dir, bstr(&path));
+	for(j=0; j<dir.len; j++) {
+		if(hasprefix(dir.p[j], "z"))
+			xremove(bpathf(&b, "%s/%s", bstr(&path), dir.p[j]));
+	}
+
+	if(rebuildall) {
+		// Remove object tree.
+		xremoveall(bpathf(&b, "%s/pkg/obj/%s_%s", goroot, gohostos, gohostarch));
+
+		// Remove installed packages and tools.
+		xremoveall(bpathf(&b, "%s/pkg/%s_%s", goroot, gohostos, gohostarch));
+		xremoveall(bpathf(&b, "%s/pkg/%s_%s", goroot, goos, goarch));
+		xremoveall(tooldir);
+
+		// Remove cached version info.
+		xremove(bpathf(&b, "%s/VERSION.cache", goroot));
+	}
+
+	bfree(&b);
+	bfree(&path);
+	vfree(&dir);
+}
+
+/*
+ * command implementations
+ */
+
+void
+usage(void)
+{
+	xprintf("usage: go tool dist [command]\n"
+		"Commands are:\n"
+		"\n"
+		"banner         print installation banner\n"
+		"bootstrap      rebuild everything\n"
+		"clean          deletes all built files\n"
+		"env [-p]       print environment (-p: include $PATH)\n"
+		"install [dir]  install individual directory\n"
+		"version        print Go version\n"
+		"\n"
+		"All commands take -v flags to emit extra information.\n"
+	);
+	xexit(2);
+}
+
+// The env command prints the default environment.
+void
+cmdenv(int argc, char **argv)
+{
+	bool pflag;
+	char *sep;
+	Buf b, b1;
+	char *format;
+
+	binit(&b);
+	binit(&b1);
+
+	format = "%s=\"%s\"\n";
+	pflag = 0;
+	ARGBEGIN{
+	case '9':
+		format = "%s='%s'\n";
+		break;
+	case 'p':
+		pflag = 1;
+		break;
+	case 'v':
+		vflag++;
+		break;
+	case 'w':
+		format = "set %s=%s\r\n";
+		break;
+	default:
+		usage();
+	}ARGEND
+
+	if(argc > 0)
+		usage();
+
+	xprintf(format, "CC", defaultcc);
+	xprintf(format, "CC_FOR_TARGET", defaultcctarget);
+	xprintf(format, "GOROOT", goroot);
+	xprintf(format, "GOBIN", gobin);
+	xprintf(format, "GOARCH", goarch);
+	xprintf(format, "GOOS", goos);
+	xprintf(format, "GOHOSTARCH", gohostarch);
+	xprintf(format, "GOHOSTOS", gohostos);
+	xprintf(format, "GOTOOLDIR", tooldir);
+	xprintf(format, "GOCHAR", gochar);
+	if(streq(goarch, "arm"))
+		xprintf(format, "GOARM", goarm);
+	if(streq(goarch, "386"))
+		xprintf(format, "GO386", go386);
+
+	if(pflag) {
+		sep = ":";
+		if(streq(gohostos, "windows"))
+			sep = ";";
+		xgetenv(&b, "PATH");
+		bprintf(&b1, "%s%s%s", gobin, sep, bstr(&b));
+		xprintf(format, "PATH", bstr(&b1));
+	}
+
+	bfree(&b);
+	bfree(&b1);
+}
+
+// The bootstrap command runs a build from scratch,
+// stopping at having installed the go_bootstrap command.
+void
+cmdbootstrap(int argc, char **argv)
+{
+	int i;
+	Buf b;
+	char *oldgoos, *oldgoarch, *oldgochar;
+
+	binit(&b);
+
+	ARGBEGIN{
+	case 'a':
+		rebuildall = 1;
+		break;
+	case 's':
+		sflag++;
+		break;
+	case 'v':
+		vflag++;
+		break;
+	default:
+		usage();
+	}ARGEND
+
+	if(argc > 0)
+		usage();
+
+	if(isdir(bpathf(&b, "%s/src/pkg", goroot))) {
+		fatal("\n\n"
+			"The Go package sources have moved to $GOROOT/src.\n"
+			"*** %s still exists. ***\n"
+			"It probably contains stale files that may confuse the build.\n"
+			"Please (check what's there and) remove it and try again.\n"
+			"See http://golang.org/s/go14nopkg\n", bpathf(&b, "%s/src/pkg", goroot));
+	}
+	
+	if(rebuildall)
+		clean();
+	goversion = findgoversion();
+	setup();
+
+	xsetenv("GOROOT", goroot);
+	xsetenv("GOROOT_FINAL", goroot_final);
+
+	// For the main bootstrap, building for host os/arch.
+	oldgoos = goos;
+	oldgoarch = goarch;
+	oldgochar = gochar;
+	goos = gohostos;
+	goarch = gohostarch;
+	gochar = gohostchar;
+	xsetenv("GOARCH", goarch);
+	xsetenv("GOOS", goos);
+
+	for(i=0; i<nelem(buildorder); i++) {
+		install(bprintf(&b, buildorder[i], gohostchar));
+		if(!streq(oldgochar, gohostchar) && xstrstr(buildorder[i], "%s"))
+			install(bprintf(&b, buildorder[i], oldgochar));
+	}
+
+	goos = oldgoos;
+	goarch = oldgoarch;
+	gochar = oldgochar;
+	xsetenv("GOARCH", goarch);
+	xsetenv("GOOS", goos);
+
+	// Build runtime for actual goos/goarch too.
+	if(!streq(goos, gohostos) || !streq(goarch, gohostarch))
+		install("runtime");
+
+	bfree(&b);
+}
+
+static char*
+defaulttarg(void)
+{
+	char *p;
+	Buf pwd, src, real_src;
+
+	binit(&pwd);
+	binit(&src);
+	binit(&real_src);
+
+	// xgetwd might return a path with symlinks fully resolved, and if
+	// there happens to be symlinks in goroot, then the hasprefix test
+	// will never succeed. Instead, we use xrealwd to get a canonical
+	// goroot/src before the comparison to avoid this problem.
+	xgetwd(&pwd);
+	p = btake(&pwd);
+	bpathf(&src, "%s/src/", goroot);
+	xrealwd(&real_src, bstr(&src));
+	if(!hasprefix(p, bstr(&real_src)))
+		fatal("current directory %s is not under %s", p, bstr(&real_src));
+	p += real_src.len;
+	// guard againt xrealwd return the directory without the trailing /
+	if(*p == slash[0])
+		p++;
+
+	bfree(&pwd);
+	bfree(&src);
+	bfree(&real_src);
+
+	return p;
+}
+
+// Install installs the list of packages named on the command line.
+void
+cmdinstall(int argc, char **argv)
+{
+	int i;
+
+	ARGBEGIN{
+	case 's':
+		sflag++;
+		break;
+	case 'v':
+		vflag++;
+		break;
+	default:
+		usage();
+	}ARGEND
+
+	if(argc == 0)
+		install(defaulttarg());
+
+	for(i=0; i<argc; i++)
+		install(argv[i]);
+}
+
+// Clean deletes temporary objects.
+// Clean -i deletes the installed objects too.
+void
+cmdclean(int argc, char **argv)
+{
+	ARGBEGIN{
+	case 'v':
+		vflag++;
+		break;
+	default:
+		usage();
+	}ARGEND
+
+	if(argc > 0)
+		usage();
+
+	clean();
+}
+
+// Banner prints the 'now you've installed Go' banner.
+void
+cmdbanner(int argc, char **argv)
+{
+	char *pathsep, *pid, *ns;
+	Buf b, b1, search, path;
+
+	ARGBEGIN{
+	case 'v':
+		vflag++;
+		break;
+	default:
+		usage();
+	}ARGEND
+
+	if(argc > 0)
+		usage();
+
+	binit(&b);
+	binit(&b1);
+	binit(&search);
+	binit(&path);
+
+	xprintf("\n");
+	xprintf("---\n");
+	xprintf("Installed Go for %s/%s in %s\n", goos, goarch, goroot);
+	xprintf("Installed commands in %s\n", gobin);
+
+	if(!xsamefile(goroot_final, goroot)) {
+		// If the files are to be moved, don't check that gobin
+		// is on PATH; assume they know what they are doing.
+	} else if(streq(gohostos, "plan9")) {
+		// Check that gobin is bound before /bin.
+		readfile(&b, "#c/pid");
+		bsubst(&b, " ", "");
+		pid = btake(&b);
+		bprintf(&b, "/proc/%s/ns", pid);
+		ns = btake(&b);
+		readfile(&b, ns);
+		bprintf(&search, "bind -b %s /bin\n", gobin);
+		if(xstrstr(bstr(&b), bstr(&search)) == nil)
+			xprintf("*** You need to bind %s before /bin.\n", gobin);
+	} else {
+		// Check that gobin appears in $PATH.
+		xgetenv(&b, "PATH");
+		pathsep = ":";
+		if(streq(gohostos, "windows"))
+			pathsep = ";";
+		bprintf(&b1, "%s%s%s", pathsep, bstr(&b), pathsep);
+		bprintf(&search, "%s%s%s", pathsep, gobin, pathsep);
+		if(xstrstr(bstr(&b1), bstr(&search)) == nil)
+			xprintf("*** You need to add %s to your PATH.\n", gobin);
+	}
+
+	if(streq(gohostos, "darwin")) {
+		if(isfile(bpathf(&path, "%s/cov", tooldir)))
+			xprintf("\n"
+				"On OS X the debuggers must be installed setgid procmod.\n"
+				"Read and run ./sudo.bash to install the debuggers.\n");
+	}
+
+	if(!xsamefile(goroot_final, goroot)) {
+		xprintf("\n"
+			"The binaries expect %s to be copied or moved to %s\n",
+			goroot, goroot_final);
+	}
+
+	bfree(&b);
+	bfree(&b1);
+	bfree(&search);
+	bfree(&path);
+}
+
+// Version prints the Go version.
+void
+cmdversion(int argc, char **argv)
+{
+	ARGBEGIN{
+	case 'v':
+		vflag++;
+		break;
+	default:
+		usage();
+	}ARGEND
+
+	if(argc > 0)
+		usage();
+
+	xprintf("%s\n", goversion);
+}
diff --git a/src/cmd/dist/buildgc.c b/src/cmd/dist/buildgc.c
new file mode 100644
index 0000000..66adf68
--- /dev/null
+++ b/src/cmd/dist/buildgc.c
@@ -0,0 +1,137 @@
+// 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 "a.h"
+
+/*
+ * Helpers for building cmd/gc.
+ */
+
+// gcopnames creates opnames.h from go.h.
+// It finds the OXXX enum, pulls out all the constants
+// from OXXX to OEND, and writes a table mapping
+// op to string.
+void
+gcopnames(char *dir, char *file)
+{
+	char *p, *q;
+	int i, j, end;
+	Buf in, b, out;
+	Vec lines, fields;
+	
+	binit(&in);
+	binit(&b);
+	binit(&out);
+	vinit(&lines);
+	vinit(&fields);
+	
+	bwritestr(&out, bprintf(&b, "// auto generated by go tool dist\n"));
+	bwritestr(&out, bprintf(&b, "static char *opnames[] = {\n"));
+
+	readfile(&in, bprintf(&b, "%s/go.h", dir));
+	splitlines(&lines, bstr(&in));
+	i = 0;
+	while(i<lines.len && !contains(lines.p[i], "OXXX"))
+		i++;
+	end = 0;
+	for(; i<lines.len && !end; i++) {
+		p = xstrstr(lines.p[i], "//");
+		if(p != nil)
+			*p = '\0';
+		end = contains(lines.p[i], "OEND");
+		splitfields(&fields, lines.p[i]);
+		for(j=0; j<fields.len; j++) {
+			q = fields.p[j];
+			if(*q == 'O')
+				q++;
+			p = q+xstrlen(q)-1;
+			if(*p == ',')
+				*p = '\0';
+			bwritestr(&out, bprintf(&b, "	[O%s] = \"%s\",\n", q, q));
+		}
+	}
+	
+	bwritestr(&out, bprintf(&b, "};\n"));
+
+	writefile(&out, file, 0);
+
+	bfree(&in);
+	bfree(&b);
+	bfree(&out);
+	vfree(&lines);
+	vfree(&fields);
+}
+
+// mkanames reads [568].out.h and writes anames[568].c
+// The format is much the same as the Go opcodes above.
+// it also writes out cnames array for C_* constants.
+void
+mkanames(char *dir, char *file)
+{
+	int i, j, ch;
+	Buf in, b, out, out2;
+	Vec lines;
+	char *p;
+
+	binit(&b);
+	binit(&in);
+	binit(&out);
+	binit(&out2);
+	vinit(&lines);
+
+	ch = file[xstrlen(file)-3];
+	bprintf(&b, "%s/../cmd/%cl/%c.out.h", dir, ch, ch);
+	readfile(&in, bstr(&b));
+	splitlines(&lines, bstr(&in));
+	
+	// Include link.h so that the extern declaration there is
+	// checked against the non-extern declaration we are generating.
+	bwritestr(&out, bprintf(&b, "#include <u.h>\n"));
+	bwritestr(&out, bprintf(&b, "#include <libc.h>\n"));
+	bwritestr(&out, bprintf(&b, "#include <bio.h>\n"));
+	bwritestr(&out, bprintf(&b, "#include <link.h>\n"));
+	bwritestr(&out, bprintf(&b, "\n"));
+
+	bwritestr(&out, bprintf(&b, "char*	anames%c[] = {\n", ch));
+	for(i=0; i<lines.len; i++) {
+		if(hasprefix(lines.p[i], "\tA")) {
+			p = xstrstr(lines.p[i], ",");
+			if(p)
+				*p = '\0';
+			p = xstrstr(lines.p[i], "\n");
+			if(p)
+				*p = '\0';
+			p = lines.p[i] + 2;
+			bwritestr(&out, bprintf(&b, "\t\"%s\",\n", p));
+		}
+	}
+	bwritestr(&out, "};\n");
+
+	j=0;
+	bprintf(&out2, "char*	cnames%c[] = {\n", ch);
+	for(i=0; i<lines.len; i++) {
+		if(hasprefix(lines.p[i], "\tC_")) {
+			p = xstrstr(lines.p[i], ",");
+			if(p)
+				*p = '\0';
+			p = xstrstr(lines.p[i], "\n");
+			if(p)
+				*p = '\0';
+			p = lines.p[i] + 3;
+			bwritestr(&out2, bprintf(&b, "\t\"%s\",\n", p));
+			j++;
+		}
+	}
+	bwritestr(&out2, "};\n");
+	if(j>0)
+		bwriteb(&out, &out2);
+
+	writefile(&out, file, 0);
+
+	bfree(&b);
+	bfree(&in);
+	bfree(&out);
+	bfree(&out2);
+	vfree(&lines);
+}
diff --git a/src/cmd/dist/buildgo.c b/src/cmd/dist/buildgo.c
new file mode 100644
index 0000000..41208fa
--- /dev/null
+++ b/src/cmd/dist/buildgo.c
@@ -0,0 +1,49 @@
+// 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 "a.h"
+
+/*
+ * Helpers for building cmd/go and cmd/cgo.
+ */
+
+// mkzdefaultcc writes zdefaultcc.go:
+//
+//	package main
+//	const defaultCC = <defaultcc>
+//	const defaultCXX = <defaultcxx>
+//
+// It is invoked to write cmd/go/zdefaultcc.go
+// but we also write cmd/cgo/zdefaultcc.go.
+void
+mkzdefaultcc(char *dir, char *file)
+{
+	Buf b, out;
+	
+	USED(dir);
+
+	binit(&out);
+	bprintf(&out,
+		"// auto generated by go tool dist\n"
+		"\n"
+		"package main\n"
+		"\n"
+		"const defaultCC = `%s`\n"
+		"const defaultCXX = `%s`\n",
+		defaultcctarget, defaultcxxtarget);
+
+	writefile(&out, file, 0);
+
+	// Convert file name to replace.
+	binit(&b);	
+	bwritestr(&b, file);
+	if(slash[0] == '/')
+		bsubst(&b, "/go/zdefaultcc.go", "/cgo/zdefaultcc.go");
+	else
+		bsubst(&b, "\\go\\zdefaultcc.go", "\\cgo\\zdefaultcc.go");
+	writefile(&out, bstr(&b), 0);
+
+	bfree(&b);
+	bfree(&out);
+}
diff --git a/src/cmd/dist/buildruntime.c b/src/cmd/dist/buildruntime.c
new file mode 100644
index 0000000..bb774e0
--- /dev/null
+++ b/src/cmd/dist/buildruntime.c
@@ -0,0 +1,468 @@
+// 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 "a.h"
+
+/*
+ * Helpers for building runtime.
+ */
+
+// mkzversion writes zversion.go:
+//
+//	package runtime
+//	const defaultGoroot = <goroot>
+//	const theVersion = <version>
+//
+void
+mkzversion(char *dir, char *file)
+{
+	Buf b, out;
+	
+	USED(dir);
+
+	binit(&b);
+	binit(&out);
+	
+	bwritestr(&out, bprintf(&b,
+		"// auto generated by go tool dist\n"
+		"\n"
+		"package runtime\n"
+		"\n"
+		"const defaultGoroot = `%s`\n"
+		"const theVersion = `%s`\n"
+		"var buildVersion = theVersion\n", goroot_final, goversion));
+
+	writefile(&out, file, 0);
+	
+	bfree(&b);
+	bfree(&out);
+}
+
+// mkzexperiment writes zaexperiment.h (sic):
+//
+//	#define GOEXPERIMENT "experiment string"
+//
+void
+mkzexperiment(char *dir, char *file)
+{
+	Buf b, out, exp;
+	
+	USED(dir);
+
+	binit(&b);
+	binit(&out);
+	binit(&exp);
+	
+	xgetenv(&exp, "GOEXPERIMENT");
+	bwritestr(&out, bprintf(&b,
+		"// auto generated by go tool dist\n"
+		"\n"
+		"#define GOEXPERIMENT \"%s\"\n", bstr(&exp)));
+
+	writefile(&out, file, 0);
+	
+	bfree(&b);
+	bfree(&out);
+	bfree(&exp);
+}
+
+// mkzgoarch writes zgoarch_$GOARCH.go:
+//
+//	package runtime
+//	const theGoarch = <goarch>
+//
+void
+mkzgoarch(char *dir, char *file)
+{
+	Buf b, out;
+
+	USED(dir);
+	
+	binit(&b);
+	binit(&out);
+	
+	bwritestr(&out, bprintf(&b,
+		"// auto generated by go tool dist\n"
+		"\n"
+		"package runtime\n"
+		"\n"
+		"const theGoarch = `%s`\n", goarch));
+
+	writefile(&out, file, 0);
+	
+	bfree(&b);
+	bfree(&out);
+}
+
+// mkzgoos writes zgoos_$GOOS.go:
+//
+//	package runtime
+//	const theGoos = <goos>
+//
+void
+mkzgoos(char *dir, char *file)
+{
+	Buf b, out;
+
+	USED(dir);
+	
+	binit(&b);
+	binit(&out);
+
+	bwritestr(&out, "// auto generated by go tool dist\n\n");
+
+	if(streq(goos, "linux")) {
+		bwritestr(&out, "// +build !android\n\n");
+	}
+	
+	bwritestr(&out, bprintf(&b,
+		"package runtime\n"
+		"\n"
+		"const theGoos = `%s`\n", goos));
+
+	writefile(&out, file, 0);
+	
+	bfree(&b);
+	bfree(&out);
+}
+
+static struct {
+	char *goarch;
+	char *goos;
+	char *hdr;
+} zasmhdr[] = {
+	{"386", "",
+		"#define	get_tls(r)	MOVL TLS, r\n"
+		"#define	g(r)	0(r)(TLS*1)\n"
+	},
+	{"amd64p32", "",
+		"#define	get_tls(r)	MOVL TLS, r\n"
+		"#define	g(r)	0(r)(TLS*1)\n"
+	},
+	{"amd64", "",
+		"#define	get_tls(r)	MOVQ TLS, r\n"
+		"#define	g(r)	0(r)(TLS*1)\n"
+	},	
+
+	{"arm", "",
+	"#define	LR	R14\n"
+	},
+};
+
+#define MAXWINCB 2000 /* maximum number of windows callbacks allowed */
+
+// mkzasm writes zasm_$GOOS_$GOARCH.h,
+// which contains struct offsets for use by
+// assembly files.  It also writes a copy to the work space
+// under the name zasm_GOOS_GOARCH.h (no expansion).
+// 
+void
+mkzasm(char *dir, char *file)
+{
+	int i, n;
+	char *aggr, *p;
+	Buf in, b, b1, out, exp;
+	Vec argv, lines, fields;
+
+	binit(&in);
+	binit(&b);
+	binit(&b1);
+	binit(&out);
+	binit(&exp);
+	vinit(&argv);
+	vinit(&lines);
+	vinit(&fields);
+	
+	bwritestr(&out, "// auto generated by go tool dist\n\n");
+	if(streq(goos, "linux")) {
+		bwritestr(&out, "// +build !android\n\n");
+	}
+	
+	for(i=0; i<nelem(zasmhdr); i++) {
+		if(hasprefix(goarch, zasmhdr[i].goarch) && hasprefix(goos, zasmhdr[i].goos)) {
+			bwritestr(&out, zasmhdr[i].hdr);
+			goto ok;
+		}
+	}
+	fatal("unknown $GOOS/$GOARCH in mkzasm");
+ok:
+
+	copyfile(bpathf(&b, "%s/pkg/%s_%s/textflag.h", goroot, goos, goarch),
+		bpathf(&b1, "%s/src/cmd/ld/textflag.h", goroot), 0);
+
+	// Run 6c -D GOOS_goos -D GOARCH_goarch -I workdir -a -n -o workdir/proc.acid proc.c
+	// 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");
+	vadd(&argv, bprintf(&b, "GOOS_%s", goos));
+	vadd(&argv, "-D");
+	vadd(&argv, bprintf(&b, "GOARCH_%s", goarch));
+	vadd(&argv, "-I");
+	vadd(&argv, bprintf(&b, "%s", workdir));
+	vadd(&argv, "-I");
+	vadd(&argv, bprintf(&b, "%s/pkg/%s_%s", goroot, goos, goarch));
+	vadd(&argv, "-n");
+	vadd(&argv, "-a");
+	vadd(&argv, "-o");
+	vadd(&argv, bpathf(&b, "%s/proc.acid", workdir));
+	vadd(&argv, "proc.c");
+	runv(nil, dir, CheckExit, &argv);
+	readfile(&in, bpathf(&b, "%s/proc.acid", workdir));
+	
+	// Convert input like
+	//	aggr G
+	//	{
+	//		Gobuf 24 sched;
+	//		'Y' 48 stack0;
+	//	}
+	//	StackMin = 128;
+	// into output like
+	//	#define g_sched 24
+	//	#define g_stack0 48
+	//	#define const_StackMin 128
+	aggr = nil;
+	splitlines(&lines, bstr(&in));
+	for(i=0; i<lines.len; i++) {
+		splitfields(&fields, lines.p[i]);
+		if(fields.len == 2 && streq(fields.p[0], "aggr")) {
+			if(streq(fields.p[1], "G"))
+				aggr = "g";
+			else if(streq(fields.p[1], "M"))
+				aggr = "m";
+			else if(streq(fields.p[1], "P"))
+				aggr = "p";
+			else if(streq(fields.p[1], "Gobuf"))
+				aggr = "gobuf";
+			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"))
+				aggr = "seh";
+			else if(streq(fields.p[1], "Alg"))
+				aggr = "alg";
+			else if(streq(fields.p[1], "Panic"))
+				aggr = "panic";
+			else if(streq(fields.p[1], "Stack"))
+				aggr = "stack";
+		}
+		if(hasprefix(lines.p[i], "}"))
+			aggr = nil;
+		if(aggr && hasprefix(lines.p[i], "\t") && fields.len >= 2) {
+			n = fields.len;
+			p = fields.p[n-1];
+			if(p[xstrlen(p)-1] == ';')
+				p[xstrlen(p)-1] = '\0';
+			bwritestr(&out, bprintf(&b, "#define %s_%s %s\n", aggr, fields.p[n-1], fields.p[n-2]));
+		}
+		if(fields.len == 3 && streq(fields.p[1], "=")) { // generated from enumerated constants
+			p = fields.p[2];
+			if(p[xstrlen(p)-1] == ';')
+				p[xstrlen(p)-1] = '\0';
+			bwritestr(&out, bprintf(&b, "#define const_%s %s\n", fields.p[0], p));
+		}
+	}
+
+	// Some #defines that are used for .c files.
+	if(streq(goos, "windows")) {
+		bwritestr(&out, bprintf(&b, "#define cb_max %d\n", MAXWINCB));
+	}
+	
+	xgetenv(&exp, "GOEXPERIMENT");
+	bwritestr(&out, bprintf(&b, "#define GOEXPERIMENT \"%s\"\n", bstr(&exp)));
+	
+	// Write both to file and to workdir/zasm_GOOS_GOARCH.h.
+	writefile(&out, file, 0);
+	writefile(&out, bprintf(&b, "%s/zasm_GOOS_GOARCH.h", workdir), 0);
+
+	bfree(&in);
+	bfree(&b);
+	bfree(&b1);
+	bfree(&out);
+	bfree(&exp);
+	vfree(&argv);
+	vfree(&lines);
+	vfree(&fields);
+}
+
+// mkzsys writes zsys_$GOOS_$GOARCH.s,
+// which contains arch or os specific asm code.
+// 
+void
+mkzsys(char *dir, char *file)
+{
+	int i;
+	Buf out;
+
+	USED(dir);
+	
+	binit(&out);
+	
+	bwritestr(&out, "// auto generated by go tool dist\n\n");
+	if(streq(goos, "linux")) {
+		bwritestr(&out, "// +build !android\n\n");
+	}
+	
+	if(streq(goos, "windows")) {
+		bwritef(&out,
+			"// runtime·callbackasm is called by external code to\n"
+			"// execute Go implemented callback function. It is not\n"
+			"// called from the start, instead runtime·compilecallback\n"
+			"// always returns address into runtime·callbackasm offset\n"
+			"// appropriately so different callbacks start with different\n"
+			"// CALL instruction in runtime·callbackasm. This determines\n"
+			"// which Go callback function is executed later on.\n"
+			"TEXT runtime·callbackasm(SB),7,$0\n");
+		for(i=0; i<MAXWINCB; i++) {
+			bwritef(&out, "\tCALL\truntime·callbackasm1(SB)\n");
+		}
+		bwritef(&out, "\tRET\n");
+	}
+
+	writefile(&out, file, 0);
+	
+	bfree(&out);
+}
+
+static char *runtimedefs[] = {
+	"defs.c",
+	"malloc.c",
+	"mcache.c",
+	"mgc0.c",
+	"proc.c",
+	"parfor.c",
+	"stack.c",
+};
+
+// mkzruntimedefs writes zruntime_defs_$GOOS_$GOARCH.h,
+// which contains Go struct definitions equivalent to the C ones.
+// Mostly we just write the output of 6c -q to the file.
+// However, we run it on multiple files, so we have to delete
+// the duplicated definitions, and we don't care about the funcs,
+// so we delete those too.
+// 
+void
+mkzruntimedefs(char *dir, char *file)
+{
+	int i, skip;
+	char *p;
+	Buf in, b, b1, out;
+	Vec argv, lines, fields, seen;
+	
+	binit(&in);
+	binit(&b);
+	binit(&b1);
+	binit(&out);
+	vinit(&argv);
+	vinit(&lines);
+	vinit(&fields);
+	vinit(&seen);
+	
+	bwritestr(&out, "// auto generated by go tool dist\n"
+		"\n");
+
+	if(streq(goos, "linux")) {
+		bwritestr(&out, "// +build !android\n\n");
+	}
+	
+	bwritestr(&out,
+		"package runtime\n"
+		"import \"unsafe\"\n"
+		"var _ unsafe.Pointer\n"
+		"\n"
+	);
+
+	// Do not emit definitions for these.
+	vadd(&seen, "true");
+	vadd(&seen, "false");
+	vadd(&seen, "raceenabled");
+	vadd(&seen, "allgs");
+	
+	// Run 6c -D GOOS_goos -D GOARCH_goarch -I workdir -q -n -o workdir/runtimedefs
+	// on each of the runtimedefs C files.
+	vadd(&argv, bpathf(&b, "%s/%sc", tooldir, gochar));
+	vadd(&argv, "-D");
+	vadd(&argv, bprintf(&b, "GOOS_%s", goos));
+	vadd(&argv, "-D");
+	vadd(&argv, bprintf(&b, "GOARCH_%s", goarch));
+	vadd(&argv, "-I");
+	vadd(&argv, bprintf(&b, "%s", workdir));
+	vadd(&argv, "-I");
+	vadd(&argv, bprintf(&b, "%s/pkg/%s_%s", goroot, goos, goarch));
+	vadd(&argv, "-q");
+	vadd(&argv, "-n");
+	vadd(&argv, "-o");
+	vadd(&argv, bpathf(&b, "%s/runtimedefs", workdir));
+	vadd(&argv, "");
+	p = argv.p[argv.len-1];
+	for(i=0; i<nelem(runtimedefs); i++) {
+		argv.p[argv.len-1] = runtimedefs[i];
+		runv(nil, dir, CheckExit, &argv);
+		readfile(&b, bpathf(&b1, "%s/runtimedefs", workdir));
+		bwriteb(&in, &b);
+	}
+	argv.p[argv.len-1] = p;
+		
+	// Process the aggregate output.
+	skip = 0;
+	splitlines(&lines, bstr(&in));
+	for(i=0; i<lines.len; i++) {
+		p = lines.p[i];
+		// Drop comment and func lines.
+		if(hasprefix(p, "//") || hasprefix(p, "func"))
+			continue;
+		
+		// Note beginning of type or var decl, which can be multiline.
+		// Remove duplicates.  The linear check of seen here makes the
+		// whole processing quadratic in aggregate, but there are only
+		// about 100 declarations, so this is okay (and simple).
+		if(hasprefix(p, "type ") || hasprefix(p, "var ") || hasprefix(p, "const ")) {
+			splitfields(&fields, p);
+			if(fields.len < 2)
+				continue;
+			if(find(fields.p[1], seen.p, seen.len) >= 0) {
+				if(streq(fields.p[fields.len-1], "{"))
+					skip = 1;  // skip until }
+				continue;
+			}
+			vadd(&seen, fields.p[1]);
+		}
+
+		// Const lines are printed in original case (usually upper). Add a leading _ as needed.
+		if(hasprefix(p, "const ")) {
+			if('A' <= p[6] && p[6] <= 'Z')
+				bwritestr(&out, "const _");
+			else
+				bwritestr(&out, "const ");
+			bwritestr(&out, p+6);
+			continue;
+		}
+
+		if(skip) {
+			if(hasprefix(p, "}"))
+				skip = 0;
+			continue;
+		}
+		
+		bwritestr(&out, p);
+	}
+
+	// Some windows specific const.
+	if(streq(goos, "windows")) {
+		bwritestr(&out, bprintf(&b, "const cb_max = %d\n", MAXWINCB));
+	}
+	
+	writefile(&out, file, 0);
+
+	bfree(&in);
+	bfree(&b);
+	bfree(&b1);
+	bfree(&out);
+	vfree(&argv);
+	vfree(&lines);
+	vfree(&fields);
+	vfree(&seen);
+}
diff --git a/src/cmd/dist/main.c b/src/cmd/dist/main.c
new file mode 100644
index 0000000..fad0180
--- /dev/null
+++ b/src/cmd/dist/main.c
@@ -0,0 +1,42 @@
+// 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 "a.h"
+
+int vflag;
+int sflag;
+char *argv0;
+
+// cmdtab records the available commands.
+static struct {
+	char *name;
+	void (*f)(int, char**);
+} cmdtab[] = {
+	{"banner", cmdbanner},
+	{"bootstrap", cmdbootstrap},
+	{"clean", cmdclean},
+	{"env", cmdenv},
+	{"install", cmdinstall},
+	{"version", cmdversion},
+};
+
+// The OS-specific main calls into the portable code here.
+void
+xmain(int argc, char **argv)
+{
+	int i;
+
+	if(argc <= 1)
+		usage();
+	
+	for(i=0; i<nelem(cmdtab); i++) {
+		if(streq(cmdtab[i].name, argv[1])) {
+			cmdtab[i].f(argc-1, argv+1);
+			return;
+		}
+	}
+
+	xprintf("unknown command %s\n", argv[1]);
+	usage();
+}
diff --git a/src/cmd/dist/plan9.c b/src/cmd/dist/plan9.c
new file mode 100644
index 0000000..e4bf251
--- /dev/null
+++ b/src/cmd/dist/plan9.c
@@ -0,0 +1,764 @@
+// 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.
+
+// These #ifdefs are being used as a substitute for
+// build configuration, so that on any system, this
+// tool can be built with the local equivalent of
+//	cc *.c
+//
+#ifdef PLAN9
+
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#undef nil
+#undef nelem
+#include "a.h"
+
+// bprintf replaces the buffer with the result of the printf formatting
+// and returns a pointer to the NUL-terminated buffer contents.
+char*
+bprintf(Buf *b, char *fmt, ...)
+{
+	va_list arg;
+	char buf[4096];
+
+	breset(b);
+	va_start(arg, fmt);
+	vsnprintf(buf, sizeof buf, fmt, arg);
+	va_end(arg);
+	bwritestr(b, buf);
+	return bstr(b);
+}
+
+// bpathf is the same as bprintf (on windows it turns / into \ after the printf).
+// It returns a pointer to the NUL-terminated buffer contents.
+char*
+bpathf(Buf *b, char *fmt, ...)
+{
+	va_list arg;
+	char buf[4096];
+	
+	breset(b);
+	va_start(arg, fmt);
+	vsnprintf(buf, sizeof buf, fmt, arg);
+	va_end(arg);
+	bwritestr(b, buf);
+	return bstr(b);
+}
+
+// bwritef is like bprintf but does not reset the buffer
+// and does not return the NUL-terminated string.
+void
+bwritef(Buf *b, char *fmt, ...)
+{
+	va_list arg;
+	char buf[4096];
+	
+	va_start(arg, fmt);
+	vsnprintf(buf, sizeof buf, fmt, arg);
+	va_end(arg);
+	bwritestr(b, buf);
+}
+
+// breadfrom appends to b all the data that can be read from fd.
+static void
+breadfrom(Buf *b, int fd)
+{
+	int n;
+
+	for(;;) {
+		bgrow(b, 4096);
+		n = read(fd, b->p+b->len, 4096);
+		if(n < 0)
+			fatal("read");
+		if(n == 0)
+			break;
+		b->len += n;
+	}
+}
+
+// xgetenv replaces b with the value of the named environment variable.
+void
+xgetenv(Buf *b, char *name)
+{
+	char *p;
+	
+	breset(b);
+	p = getenv(name);
+	if(p != nil)
+		bwritestr(b, p);
+}
+
+static void genrun(Buf *b, char *dir, int mode, Vec *argv, int bg);
+
+// run runs the command named by cmd.
+// If b is not nil, run replaces b with the output of the command.
+// If dir is not nil, run runs the command in that directory.
+// If mode is CheckExit, run calls fatal if the command is not successful.
+void
+run(Buf *b, char *dir, int mode, char *cmd, ...)
+{
+	va_list arg;
+	Vec argv;
+	char *p;
+	
+	vinit(&argv);
+	vadd(&argv, cmd);
+	va_start(arg, cmd);
+	while((p = va_arg(arg, char*)) != nil)
+		vadd(&argv, p);
+	va_end(arg);
+	
+	runv(b, dir, mode, &argv);
+	
+	vfree(&argv);
+}
+
+// runv is like run but takes a vector.
+void
+runv(Buf *b, char *dir, int mode, Vec *argv)
+{
+	genrun(b, dir, mode, argv, 1);
+}
+
+// bgrunv is like run but runs the command in the background.
+// bgwait waits for pending bgrunv to finish.
+void
+bgrunv(char *dir, int mode, Vec *argv)
+{
+	genrun(nil, dir, mode, argv, 0);
+}
+
+#define MAXBG 4 /* maximum number of jobs to run at once */
+
+static struct {
+	int pid;
+	int mode;
+	char *cmd;
+	Buf *b;
+} bg[MAXBG];
+static int nbg;
+static int maxnbg = nelem(bg);
+
+static void bgwait1(void);
+
+// genrun is the generic run implementation.
+static void
+genrun(Buf *b, char *dir, int mode, Vec *argv, int wait)
+{
+	int i, p[2], pid;
+	Buf b1, cmd;
+	char *q;
+
+	while(nbg >= maxnbg)
+		bgwait1();
+
+	binit(&b1);
+	binit(&cmd);
+
+	if(!isabs(argv->p[0])) {
+		bpathf(&b1, "/bin/%s", argv->p[0]);
+		free(argv->p[0]);
+		argv->p[0] = xstrdup(bstr(&b1));
+	}
+
+	// Generate a copy of the command to show in a log.
+	// Substitute $WORK for the work directory.
+	for(i=0; i<argv->len; i++) {
+		if(i > 0)
+			bwritestr(&cmd, " ");
+		q = argv->p[i];
+		if(workdir != nil && hasprefix(q, workdir)) {
+			bwritestr(&cmd, "$WORK");
+			q += strlen(workdir);
+		}
+		bwritestr(&cmd, q);
+	}
+	if(vflag > 1)
+		errprintf("%s\n", bstr(&cmd));
+
+	if(b != nil) {
+		breset(b);
+		if(pipe(p) < 0)
+			fatal("pipe");
+	}
+
+	switch(pid = fork()) {
+	case -1:
+		fatal("fork");
+	case 0:
+		if(b != nil) {
+			close(0);
+			close(p[0]);
+			dup(p[1], 1);
+			dup(p[1], 2);
+			if(p[1] > 2)
+				close(p[1]);
+		}
+		if(dir != nil) {
+			if(chdir(dir) < 0) {
+				fprint(2, "chdir: %r\n");
+				_exits("chdir");
+			}
+		}
+		vadd(argv, nil);
+		exec(argv->p[0], argv->p);
+		fprint(2, "%s\n", bstr(&cmd));
+		fprint(2, "exec: %r\n");
+		_exits("exec");
+	}
+	if(b != nil) {
+		close(p[1]);
+		breadfrom(b, p[0]);
+		close(p[0]);
+	}
+
+	if(nbg < 0)
+		fatal("bad bookkeeping");
+	bg[nbg].pid = pid;
+	bg[nbg].mode = mode;
+	bg[nbg].cmd = btake(&cmd);
+	bg[nbg].b = b;
+	nbg++;
+	
+	if(wait)
+		bgwait();
+
+	bfree(&cmd);
+	bfree(&b1);
+}
+
+// bgwait1 waits for a single background job.
+static void
+bgwait1(void)
+{
+	Waitmsg *w;
+	int i, mode;
+	char *cmd;
+	Buf *b;
+
+	w = wait();
+	if(w == nil)
+		fatal("wait");
+		
+	for(i=0; i<nbg; i++)
+		if(bg[i].pid == w->pid)
+			goto ok;
+	fatal("wait: unexpected pid");
+
+ok:
+	cmd = bg[i].cmd;
+	mode = bg[i].mode;
+	bg[i].pid = 0;
+	b = bg[i].b;
+	bg[i].b = nil;
+	bg[i] = bg[--nbg];
+	
+	if(mode == CheckExit && w->msg[0]) {
+		if(b != nil)
+			xprintf("%s\n", bstr(b));
+		fatal("FAILED: %s", cmd);
+	}
+	xfree(cmd);
+}
+
+// bgwait waits for all the background jobs.
+void
+bgwait(void)
+{
+	while(nbg > 0)
+		bgwait1();
+}
+
+// xgetwd replaces b with the current directory.
+void
+xgetwd(Buf *b)
+{
+	char buf[4096];
+	
+	breset(b);
+	if(getwd(buf, sizeof buf) == nil)
+		fatal("getwd");
+	bwritestr(b, buf);
+}
+
+// xrealwd replaces b with the 'real' name for the given path.
+// real is defined as what getcwd returns in that directory.
+void
+xrealwd(Buf *b, char *path)
+{
+	char buf[4096];
+	int fd;
+
+	fd = open(path, OREAD);
+	if(fd2path(fd, buf, sizeof buf) < 0)
+		fatal("fd2path");
+	close(fd);
+	breset(b);
+	bwritestr(b, buf);
+}
+
+// isdir reports whether p names an existing directory.
+bool
+isdir(char *p)
+{
+	Dir *d;
+	ulong mode;
+
+	d = dirstat(p);
+	if(d == nil)
+		return 0;
+	mode = d->mode;
+	free(d);
+	return (mode & DMDIR) == DMDIR;
+}
+
+// isfile reports whether p names an existing file.
+bool
+isfile(char *p)
+{
+	Dir *d;
+	ulong mode;
+
+	d = dirstat(p);
+	if(d == nil)
+		return 0;
+	mode = d->mode;
+	free(d);
+	return (mode & DMDIR) == 0;
+}
+
+// mtime returns the modification time of the file p.
+Time
+mtime(char *p)
+{
+	Dir *d;
+	ulong t;
+
+	d = dirstat(p);
+	if(d == nil)
+		return 0;
+	t = d->mtime;
+	free(d);
+	return (Time)t;
+}
+
+// isabs reports whether p is an absolute path.
+bool
+isabs(char *p)
+{
+	return hasprefix(p, "/");
+}
+
+// readfile replaces b with the content of the named file.
+void
+readfile(Buf *b, char *file)
+{
+	int fd;
+
+	breset(b);
+	fd = open(file, OREAD);
+	if(fd < 0)
+		fatal("open %s", file);
+	breadfrom(b, fd);
+	close(fd);
+}
+
+// writefile writes b to the named file, creating it if needed.
+void
+writefile(Buf *b, char *file, int exec)
+{
+	int fd;
+	Dir d;
+	
+	fd = create(file, ORDWR, 0666);
+	if(fd < 0)
+		fatal("create %s", file);
+	if(write(fd, b->p, b->len) != b->len)
+		fatal("short write");
+	if(exec) {
+		nulldir(&d);
+		d.mode = 0755;
+		dirfwstat(fd, &d);
+	}
+	close(fd);
+}
+
+// xmkdir creates the directory p.
+void
+xmkdir(char *p)
+{
+	int fd;
+
+	if(isdir(p))
+		return;
+	fd = create(p, OREAD, 0777|DMDIR);
+	close(fd);
+	if(fd < 0)
+		fatal("mkdir %s", p);
+}
+
+// xmkdirall creates the directory p and its parents, as needed.
+void
+xmkdirall(char *p)
+{
+	char *q;
+
+	if(isdir(p))
+		return;
+	q = strrchr(p, '/');
+	if(q != nil) {
+		*q = '\0';
+		xmkdirall(p);
+		*q = '/';
+	}
+	xmkdir(p);
+}
+
+// xremove removes the file p.
+void
+xremove(char *p)
+{
+	if(vflag > 2)
+		errprintf("rm %s\n", p);
+	remove(p);
+}
+
+// xremoveall removes the file or directory tree rooted at p.
+void
+xremoveall(char *p)
+{
+	int i;
+	Buf b;
+	Vec dir;
+
+	binit(&b);
+	vinit(&dir);
+
+	if(isdir(p)) {
+		xreaddir(&dir, p);
+		for(i=0; i<dir.len; i++) {
+			bprintf(&b, "%s/%s", p, dir.p[i]);
+			xremoveall(bstr(&b));
+		}
+	}
+	if(vflag > 2)
+		errprintf("rm %s\n", p);
+	remove(p);
+	
+	bfree(&b);
+	vfree(&dir);	
+}
+
+// xreaddir replaces dst with a list of the names of the files in dir.
+// The names are relative to dir; they are not full paths.
+void
+xreaddir(Vec *dst, char *dir)
+{
+	Dir *d;
+	int fd, i, n;
+
+	vreset(dst);
+
+	fd = open(dir, OREAD);
+	if(fd < 0)
+		fatal("open %s", dir);
+	n = dirreadall(fd, &d);
+	for(i=0; i<n; i++)
+		vadd(dst, d[i].name);
+	free(d);
+	close(fd);
+}
+
+// xworkdir creates a new temporary directory to hold object files
+// and returns the name of that directory.
+char*
+xworkdir(void)
+{
+	Buf b;
+	char *p;
+	int fd, tries;
+
+	binit(&b);
+
+	fd = 0;
+	for(tries=0; tries<1000; tries++) {
+		bprintf(&b, "/tmp/go-cbuild-%06x", nrand((1<<24)-1));
+		fd = create(bstr(&b), OREAD|OEXCL, 0700|DMDIR);
+		if(fd >= 0)
+			goto done;
+	}
+	fatal("xworkdir create");
+
+done:
+	close(fd);
+	p = btake(&b);
+
+	bfree(&b);
+	return p;
+}
+
+// fatal prints an error message to standard error and exits.
+void
+fatal(char *msg, ...)
+{
+	char buf[ERRMAX];
+	va_list arg;
+	
+	rerrstr(buf, sizeof buf);
+
+	fflush(stdout);
+	fprintf(stderr, "go tool dist: ");
+	va_start(arg, msg);
+	vfprintf(stderr, msg, arg);
+	va_end(arg);
+
+	if(buf[0])
+		fprintf(stderr, ": %s", buf);
+	fprintf(stderr, "\n");
+
+	bgwait();
+	exits(msg);
+}
+
+// xmalloc returns a newly allocated zeroed block of n bytes of memory.
+// It calls fatal if it runs out of memory.
+void*
+xmalloc(int n)
+{
+	void *p;
+	
+	p = malloc(n);
+	if(p == nil)
+		fatal("out of memory");
+	memset(p, 0, n);
+	return p;
+}
+
+// xstrdup returns a newly allocated copy of p.
+// It calls fatal if it runs out of memory.
+char*
+xstrdup(char *p)
+{
+	p = strdup(p);
+	if(p == nil)
+		fatal("out of memory");
+	return p;
+}
+
+// xrealloc grows the allocation p to n bytes and
+// returns the new (possibly moved) pointer.
+// It calls fatal if it runs out of memory.
+void*
+xrealloc(void *p, int n)
+{
+	p = realloc(p, n);
+	if(p == nil)
+		fatal("out of memory");
+	return p;
+}
+
+// xfree frees the result returned by xmalloc, xstrdup, or xrealloc.
+void
+xfree(void *p)
+{
+	free(p);
+}
+
+// hassuffix reports whether p ends with suffix.
+bool
+hassuffix(char *p, char *suffix)
+{
+	int np, ns;
+
+	np = strlen(p);
+	ns = strlen(suffix);
+	return np >= ns && streq(p+np-ns, suffix);
+}
+
+// hasprefix reports whether p begins with prefix.
+bool
+hasprefix(char *p, char *prefix)
+{
+	return strncmp(p, prefix, strlen(prefix)) == 0;
+}
+
+// contains reports whether sep appears in p.
+bool
+contains(char *p, char *sep)
+{
+	return strstr(p, sep) != nil;
+}
+
+// streq reports whether p and q are the same string.
+bool
+streq(char *p, char *q)
+{
+	return strcmp(p, q) == 0;
+}
+
+// lastelem returns the final path element in p.
+char*
+lastelem(char *p)
+{
+	char *out;
+
+	out = p;
+	for(; *p; p++)
+		if(*p == '/')
+			out = p+1;
+	return out;
+}
+
+// xmemmove copies n bytes from src to dst.
+void
+xmemmove(void *dst, void *src, int n)
+{
+	memmove(dst, src, n);
+}
+
+// xmemcmp compares the n-byte regions starting at a and at b.
+int
+xmemcmp(void *a, void *b, int n)
+{
+	return memcmp(a, b, n);
+}
+
+// xstrlen returns the length of the NUL-terminated string at p.
+int
+xstrlen(char *p)
+{
+	return strlen(p);
+}
+
+// xexit exits the process with return code n.
+void
+xexit(int n)
+{
+	char buf[32];
+
+	snprintf(buf, sizeof buf, "%d", n);
+	exits(buf);
+}
+
+// xatexit schedules the exit-handler f to be run when the program exits.
+void
+xatexit(void (*f)(void))
+{
+	atexit(f);
+}
+
+// xprintf prints a message to standard output.
+void
+xprintf(char *fmt, ...)
+{
+	va_list arg;
+	
+	va_start(arg, fmt);
+	vprintf(fmt, arg);
+	va_end(arg);
+}
+
+// errprintf prints a message to standard output.
+void
+errprintf(char *fmt, ...)
+{
+	va_list arg;
+	
+	va_start(arg, fmt);
+	vfprintf(stderr, fmt, arg);
+	va_end(arg);
+}
+
+// xsetenv sets the environment variable $name to the given value.
+void
+xsetenv(char *name, char *value)
+{
+	putenv(name, value);
+}
+
+// main takes care of OS-specific startup and dispatches to xmain.
+void
+main(int argc, char **argv)
+{
+	Buf b;
+
+	setvbuf(stdout, nil, _IOLBF, BUFSIZ);
+	setvbuf(stderr, nil, _IOLBF, BUFSIZ);
+
+	binit(&b);
+
+	rfork(RFENVG);
+
+	slash = "/";
+	gohostos = "plan9";
+
+	xgetenv(&b, "objtype");
+	if(b.len == 0)
+		fatal("$objtype is unset");
+	gohostarch = btake(&b);
+
+	srand(time(0)+getpid());
+	init();
+	xmain(argc, argv);
+
+	bfree(&b);
+	exits(nil);
+}
+
+// xqsort is a wrapper for the C standard qsort.
+void
+xqsort(void *data, int n, int elemsize, int (*cmp)(const void*, const void*))
+{
+	qsort(data, n, elemsize, cmp);
+}
+
+// xstrcmp compares the NUL-terminated strings a and b.
+int
+xstrcmp(char *a, char *b)
+{
+	return strcmp(a, b);
+}
+
+// xstrstr returns a pointer to the first occurrence of b in a.
+char*
+xstrstr(char *a, char *b)
+{
+	return strstr(a, b);
+}
+
+// xstrrchr returns a pointer to the final occurrence of c in p.
+char*
+xstrrchr(char *p, int c)
+{
+	return strrchr(p, c);
+}
+
+// xsamefile reports whether f1 and f2 are the same file (or dir)
+int
+xsamefile(char *f1, char *f2)
+{
+	return streq(f1, f2); // suffice for now
+}
+
+// xtryexecfunc tries to execute function f, if any illegal instruction
+// signal received in the course of executing that function, it will
+// return 0, otherwise it will return 1.
+int
+xtryexecfunc(void (*f)(void))
+{
+	USED(f);
+	return 0; // suffice for now
+}
+
+bool
+cansse2(void)
+{
+	// if we had access to cpuid, could answer this question
+	// less conservatively.
+	return 0;
+}
+
+#endif // PLAN9
diff --git a/src/cmd/dist/unix.c b/src/cmd/dist/unix.c
new file mode 100644
index 0000000..4a78684
--- /dev/null
+++ b/src/cmd/dist/unix.c
@@ -0,0 +1,843 @@
+// 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.
+
+// These #ifdefs are being used as a substitute for
+// build configuration, so that on any system, this
+// tool can be built with the local equivalent of
+//	cc *.c
+//
+#ifndef WIN32
+#ifndef PLAN9
+
+#include "a.h"
+#include <unistd.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <sys/param.h>
+#include <sys/utsname.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#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.
+char*
+bprintf(Buf *b, char *fmt, ...)
+{
+	va_list arg;
+	char buf[4096];
+	
+	breset(b);
+	va_start(arg, fmt);
+	vsnprintf(buf, sizeof buf, fmt, arg);
+	va_end(arg);
+	bwritestr(b, buf);
+	return bstr(b);
+}
+
+// bpathf is the same as bprintf (on windows it turns / into \ after the printf).
+// It returns a pointer to the NUL-terminated buffer contents.
+char*
+bpathf(Buf *b, char *fmt, ...)
+{
+	va_list arg;
+	char buf[4096];
+	
+	breset(b);
+	va_start(arg, fmt);
+	vsnprintf(buf, sizeof buf, fmt, arg);
+	va_end(arg);
+	bwritestr(b, buf);
+	return bstr(b);
+}
+
+// bwritef is like bprintf but does not reset the buffer
+// and does not return the NUL-terminated string.
+void
+bwritef(Buf *b, char *fmt, ...)
+{
+	va_list arg;
+	char buf[4096];
+	
+	va_start(arg, fmt);
+	vsnprintf(buf, sizeof buf, fmt, arg);
+	va_end(arg);
+	bwritestr(b, buf);
+}
+
+// breadfrom appends to b all the data that can be read from fd.
+static void
+breadfrom(Buf *b, int fd)
+{
+	int n;
+
+	for(;;) {
+		bgrow(b, 4096);
+		n = read(fd, b->p+b->len, 4096);
+		if(n < 0)
+			fatal("read: %s", strerror(errno));
+		if(n == 0)
+			break;
+		b->len += n;
+	}
+}
+
+// xgetenv replaces b with the value of the named environment variable.
+void
+xgetenv(Buf *b, char *name)
+{
+	char *p;
+	
+	breset(b);
+	p = getenv(name);
+	if(p != NULL)
+		bwritestr(b, p);
+}
+
+static void genrun(Buf *b, char *dir, int mode, Vec *argv, int bg);
+
+// run runs the command named by cmd.
+// If b is not nil, run replaces b with the output of the command.
+// If dir is not nil, run runs the command in that directory.
+// If mode is CheckExit, run calls fatal if the command is not successful.
+void
+run(Buf *b, char *dir, int mode, char *cmd, ...)
+{
+	va_list arg;
+	Vec argv;
+	char *p;
+	
+	vinit(&argv);
+	vadd(&argv, cmd);
+	va_start(arg, cmd);
+	while((p = va_arg(arg, char*)) != nil)
+		vadd(&argv, p);
+	va_end(arg);
+	
+	runv(b, dir, mode, &argv);
+	
+	vfree(&argv);
+}
+
+// runv is like run but takes a vector.
+void
+runv(Buf *b, char *dir, int mode, Vec *argv)
+{
+	genrun(b, dir, mode, argv, 1);
+}
+
+// bgrunv is like run but runs the command in the background.
+// bgwait waits for pending bgrunv to finish.
+void
+bgrunv(char *dir, int mode, Vec *argv)
+{
+	genrun(nil, dir, mode, argv, 0);
+}
+
+#define MAXBG 4 /* maximum number of jobs to run at once */
+
+static struct {
+	int pid;
+	int mode;
+	char *cmd;
+	Buf *b;
+} bg[MAXBG];
+static int nbg;
+static int maxnbg = nelem(bg);
+
+static void bgwait1(void);
+
+// genrun is the generic run implementation.
+static void
+genrun(Buf *b, char *dir, int mode, Vec *argv, int wait)
+{
+	int i, p[2], pid;
+	Buf cmd;
+	char *q;
+
+	while(nbg >= maxnbg)
+		bgwait1();
+
+	// Generate a copy of the command to show in a log.
+	// Substitute $WORK for the work directory.
+	binit(&cmd);
+	for(i=0; i<argv->len; i++) {
+		if(i > 0)
+			bwritestr(&cmd, " ");
+		q = argv->p[i];
+		if(workdir != nil && hasprefix(q, workdir)) {
+			bwritestr(&cmd, "$WORK");
+			q += strlen(workdir);
+		}
+		bwritestr(&cmd, q);
+	}
+	if(vflag > 1)
+		errprintf("%s\n", bstr(&cmd));
+
+	if(b != nil) {
+		breset(b);
+		if(pipe(p) < 0)
+			fatal("pipe: %s", strerror(errno));
+	}
+
+	switch(pid = fork()) {
+	case -1:
+		fatal("fork: %s", strerror(errno));
+	case 0:
+		if(b != nil) {
+			close(0);
+			close(p[0]);
+			dup2(p[1], 1);
+			dup2(p[1], 2);
+			if(p[1] > 2)
+				close(p[1]);
+		}
+		if(dir != nil) {
+			if(chdir(dir) < 0) {
+				fprintf(stderr, "chdir %s: %s\n", dir, strerror(errno));
+				_exit(1);
+			}
+		}
+		vadd(argv, nil);
+		execvp(argv->p[0], argv->p);
+		fprintf(stderr, "%s\n", bstr(&cmd));
+		fprintf(stderr, "exec %s: %s\n", argv->p[0], strerror(errno));
+		_exit(1);
+	}
+	if(b != nil) {
+		close(p[1]);
+		breadfrom(b, p[0]);
+		close(p[0]);
+	}
+
+	if(nbg < 0)
+		fatal("bad bookkeeping");
+	bg[nbg].pid = pid;
+	bg[nbg].mode = mode;
+	bg[nbg].cmd = btake(&cmd);
+	bg[nbg].b = b;
+	nbg++;
+	
+	if(wait)
+		bgwait();
+
+	bfree(&cmd);
+}
+
+// bgwait1 waits for a single background job.
+static void
+bgwait1(void)
+{
+	int i, pid, status, mode;
+	char *cmd;
+	Buf *b;
+
+	errno = 0;
+	while((pid = wait(&status)) < 0) {
+		if(errno != EINTR)
+			fatal("waitpid: %s", strerror(errno));
+	}
+	for(i=0; i<nbg; i++)
+		if(bg[i].pid == pid)
+			goto ok;
+	fatal("waitpid: unexpected pid");
+
+ok:
+	cmd = bg[i].cmd;
+	mode = bg[i].mode;
+	bg[i].pid = 0;
+	b = bg[i].b;
+	bg[i].b = nil;
+	bg[i] = bg[--nbg];
+	
+	if(mode == CheckExit && (!WIFEXITED(status) || WEXITSTATUS(status) != 0)) {
+		if(b != nil)
+			xprintf("%s\n", bstr(b));
+		fatal("FAILED: %s", cmd);
+	}
+	xfree(cmd);
+}
+
+// bgwait waits for all the background jobs.
+void
+bgwait(void)
+{
+	while(nbg > 0)
+		bgwait1();
+}
+
+// xgetwd replaces b with the current directory.
+void
+xgetwd(Buf *b)
+{
+	char buf[MAXPATHLEN];
+	
+	breset(b);
+	if(getcwd(buf, MAXPATHLEN) == nil)
+		fatal("getcwd: %s", strerror(errno));
+	bwritestr(b, buf);	
+}
+
+// xrealwd replaces b with the 'real' name for the given path.
+// real is defined as what getcwd returns in that directory.
+void
+xrealwd(Buf *b, char *path)
+{
+	int fd;
+	
+	fd = open(".", 0);
+	if(fd < 0)
+		fatal("open .: %s", strerror(errno));
+	if(chdir(path) < 0)
+		fatal("chdir %s: %s", path, strerror(errno));
+	xgetwd(b);
+	if(fchdir(fd) < 0)
+		fatal("fchdir: %s", strerror(errno));
+	close(fd);
+}
+
+// isdir reports whether p names an existing directory.
+bool
+isdir(char *p)
+{
+	struct stat st;
+	
+	return stat(p, &st) >= 0 && S_ISDIR(st.st_mode);
+}
+
+// isfile reports whether p names an existing file.
+bool
+isfile(char *p)
+{
+	struct stat st;
+	
+	return stat(p, &st) >= 0 && S_ISREG(st.st_mode);
+}
+
+// mtime returns the modification time of the file p.
+Time
+mtime(char *p)
+{
+	struct stat st;
+	
+	if(stat(p, &st) < 0)
+		return 0;
+	return (Time)st.st_mtime*1000000000LL;
+}
+
+// isabs reports whether p is an absolute path.
+bool
+isabs(char *p)
+{
+	return hasprefix(p, "/");
+}
+
+// readfile replaces b with the content of the named file.
+void
+readfile(Buf *b, char *file)
+{
+	int fd;
+	
+	breset(b);
+	fd = open(file, 0);
+	if(fd < 0)
+		fatal("open %s: %s", file, strerror(errno));
+	breadfrom(b, fd);
+	close(fd);
+}
+
+// writefile writes b to the named file, creating it if needed.  if
+// exec is non-zero, marks the file as executable.
+void
+writefile(Buf *b, char *file, int exec)
+{
+	int fd;
+	
+	fd = creat(file, 0666);
+	if(fd < 0)
+		fatal("create %s: %s", file, strerror(errno));
+	if(write(fd, b->p, b->len) != b->len)
+		fatal("short write: %s", strerror(errno));
+	if(exec)
+		fchmod(fd, 0755);
+	close(fd);
+}
+
+// xmkdir creates the directory p.
+void
+xmkdir(char *p)
+{
+	if(mkdir(p, 0777) < 0)
+		fatal("mkdir %s: %s", p, strerror(errno));
+}
+
+// xmkdirall creates the directory p and its parents, as needed.
+void
+xmkdirall(char *p)
+{
+	char *q;
+
+	if(isdir(p))
+		return;
+	q = strrchr(p, '/');
+	if(q != nil) {
+		*q = '\0';
+		xmkdirall(p);
+		*q = '/';
+	}
+	xmkdir(p);
+}
+
+// xremove removes the file p.
+void
+xremove(char *p)
+{
+	if(vflag > 2)
+		errprintf("rm %s\n", p);
+	unlink(p);
+}
+
+// xremoveall removes the file or directory tree rooted at p.
+void
+xremoveall(char *p)
+{
+	int i;
+	Buf b;
+	Vec dir;
+
+	binit(&b);
+	vinit(&dir);
+
+	if(isdir(p)) {
+		xreaddir(&dir, p);
+		for(i=0; i<dir.len; i++) {
+			bprintf(&b, "%s/%s", p, dir.p[i]);
+			xremoveall(bstr(&b));
+		}
+		if(vflag > 2)
+			errprintf("rm %s\n", p);
+		rmdir(p);
+	} else {
+		if(vflag > 2)
+			errprintf("rm %s\n", p);
+		unlink(p);
+	}
+	
+	bfree(&b);
+	vfree(&dir);
+}
+
+// xreaddir replaces dst with a list of the names of the files in dir.
+// The names are relative to dir; they are not full paths.
+void
+xreaddir(Vec *dst, char *dir)
+{
+	DIR *d;
+	struct dirent *dp;
+
+	vreset(dst);
+	d = opendir(dir);
+	if(d == nil)
+		fatal("opendir %s: %s", dir, strerror(errno));
+	while((dp = readdir(d)) != nil) {
+		if(streq(dp->d_name, ".") || streq(dp->d_name, ".."))
+			continue;
+		vadd(dst, dp->d_name);
+	}
+	closedir(d);
+}
+
+// xworkdir creates a new temporary directory to hold object files
+// and returns the name of that directory.
+char*
+xworkdir(void)
+{
+	Buf b;
+	char *p;
+
+	binit(&b);
+
+	xgetenv(&b, "TMPDIR");
+	if(b.len == 0)
+		bwritestr(&b, "/var/tmp");
+	if(b.p[b.len-1] != '/')
+		bwrite(&b, "/", 1);
+	bwritestr(&b, "go-cbuild-XXXXXX");
+	p = bstr(&b);
+	if(mkdtemp(p) == nil)
+		fatal("mkdtemp(%s): %s", p, strerror(errno));
+	p = btake(&b);
+
+	bfree(&b);
+
+	return p;
+}
+
+// fatal prints an error message to standard error and exits.
+void
+fatal(char *msg, ...)
+{
+	va_list arg;
+	
+	fflush(stdout);
+	fprintf(stderr, "go tool dist: ");
+	va_start(arg, msg);
+	vfprintf(stderr, msg, arg);
+	va_end(arg);
+	fprintf(stderr, "\n");
+	
+	bgwait();
+	exit(1);
+}
+
+// xmalloc returns a newly allocated zeroed block of n bytes of memory.
+// It calls fatal if it runs out of memory.
+void*
+xmalloc(int n)
+{
+	void *p;
+	
+	p = malloc(n);
+	if(p == nil)
+		fatal("out of memory");
+	memset(p, 0, n);
+	return p;
+}
+
+// xstrdup returns a newly allocated copy of p.
+// It calls fatal if it runs out of memory.
+char*
+xstrdup(char *p)
+{
+	p = strdup(p);
+	if(p == nil)
+		fatal("out of memory");
+	return p;
+}
+
+// xrealloc grows the allocation p to n bytes and
+// returns the new (possibly moved) pointer.
+// It calls fatal if it runs out of memory.
+void*
+xrealloc(void *p, int n)
+{
+	p = realloc(p, n);
+	if(p == nil)
+		fatal("out of memory");
+	return p;
+}
+
+// xfree frees the result returned by xmalloc, xstrdup, or xrealloc.
+void
+xfree(void *p)
+{
+	free(p);
+}
+
+// hassuffix reports whether p ends with suffix.
+bool
+hassuffix(char *p, char *suffix)
+{
+	int np, ns;
+
+	np = strlen(p);
+	ns = strlen(suffix);
+	return np >= ns && streq(p+np-ns, suffix);
+}
+
+// hasprefix reports whether p begins with prefix.
+bool
+hasprefix(char *p, char *prefix)
+{
+	return strncmp(p, prefix, strlen(prefix)) == 0;
+}
+
+// contains reports whether sep appears in p.
+bool
+contains(char *p, char *sep)
+{
+	return strstr(p, sep) != nil;
+}
+
+// streq reports whether p and q are the same string.
+bool
+streq(char *p, char *q)
+{
+	return strcmp(p, q) == 0;
+}
+
+// lastelem returns the final path element in p.
+char*
+lastelem(char *p)
+{
+	char *out;
+
+	out = p;
+	for(; *p; p++)
+		if(*p == '/')
+			out = p+1;
+	return out;
+}
+
+// xmemmove copies n bytes from src to dst.
+void
+xmemmove(void *dst, void *src, int n)
+{
+	memmove(dst, src, n);
+}
+
+// xmemcmp compares the n-byte regions starting at a and at b.
+int
+xmemcmp(void *a, void *b, int n)
+{
+	return memcmp(a, b, n);
+}
+
+// xstrlen returns the length of the NUL-terminated string at p.
+int
+xstrlen(char *p)
+{
+	return strlen(p);
+}
+
+// xexit exits the process with return code n.
+void
+xexit(int n)
+{
+	exit(n);
+}
+
+// xatexit schedules the exit-handler f to be run when the program exits.
+void
+xatexit(void (*f)(void))
+{
+	atexit(f);
+}
+
+// xprintf prints a message to standard output.
+void
+xprintf(char *fmt, ...)
+{
+	va_list arg;
+	
+	va_start(arg, fmt);
+	vprintf(fmt, arg);
+	va_end(arg);
+}
+
+// errprintf prints a message to standard output.
+void
+errprintf(char *fmt, ...)
+{
+	va_list arg;
+	
+	va_start(arg, fmt);
+	vfprintf(stderr, fmt, arg);
+	va_end(arg);
+}
+
+// xsetenv sets the environment variable $name to the given value.
+void
+xsetenv(char *name, char *value)
+{
+	setenv(name, value, 1);
+}
+
+// main takes care of OS-specific startup and dispatches to xmain.
+int
+main(int argc, char **argv)
+{
+	Buf b;
+	int osx;
+	struct utsname u;
+
+	setvbuf(stdout, nil, _IOLBF, 0);
+	setvbuf(stderr, nil, _IOLBF, 0);
+
+	setenv("TERM", "dumb", 1); // disable escape codes in clang errors
+
+	binit(&b);
+	
+	slash = "/";
+
+#if defined(__APPLE__)
+	gohostos = "darwin";
+	// Even on 64-bit platform, darwin uname -m prints i386.
+	run(&b, nil, 0, "sysctl", "machdep.cpu.extfeatures", nil);
+	if(contains(bstr(&b), "EM64T"))
+		gohostarch = "amd64";
+#elif defined(__linux__)
+	gohostos = "linux";
+#elif defined(__DragonFly__)
+	gohostos = "dragonfly";
+#elif defined(__FreeBSD__)
+	gohostos = "freebsd";
+#elif defined(__FreeBSD_kernel__)
+	// detect debian/kFreeBSD. 
+	// http://wiki.debian.org/Debian_GNU/kFreeBSD_FAQ#Q._How_do_I_detect_kfreebsd_with_preprocessor_directives_in_a_C_program.3F
+	gohostos = "freebsd";	
+#elif defined(__OpenBSD__)
+	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
+
+	if(gohostarch == nil) {
+		if(uname(&u) < 0)
+			fatal("uname: %s", strerror(errno));
+		if(contains(u.machine, "x86_64") || contains(u.machine, "amd64"))
+			gohostarch = "amd64";
+		else if(hassuffix(u.machine, "86"))
+			gohostarch = "386";
+		else if(contains(u.machine, "arm"))
+			gohostarch = "arm";
+		else
+			fatal("unknown architecture: %s", u.machine);
+	}
+
+	if(streq(gohostarch, "arm"))
+		maxnbg = 1;
+
+	// The OS X 10.6 linker does not support external linking mode.
+	// See golang.org/issue/5130.
+	//
+	// OS X 10.6 does not work with clang either, but OS X 10.9 requires it.
+	// It seems to work with OS X 10.8, so we default to clang for 10.8 and later.
+	// See golang.org/issue/5822.
+	//
+	// Roughly, OS X 10.N shows up as uname release (N+4),
+	// so OS X 10.6 is uname version 10 and OS X 10.8 is uname version 12.
+	if(streq(gohostos, "darwin")) {
+		if(uname(&u) < 0)
+			fatal("uname: %s", strerror(errno));
+		osx = atoi(u.release) - 4;
+		if(osx <= 6)
+			goextlinkenabled = "0";
+		if(osx >= 8)
+			defaultclang = 1;
+	}
+
+	init();
+	xmain(argc, argv);
+	bfree(&b);
+	return 0;
+}
+
+// xqsort is a wrapper for the C standard qsort.
+void
+xqsort(void *data, int n, int elemsize, int (*cmp)(const void*, const void*))
+{
+	qsort(data, n, elemsize, cmp);
+}
+
+// xstrcmp compares the NUL-terminated strings a and b.
+int
+xstrcmp(char *a, char *b)
+{
+	return strcmp(a, b);
+}
+
+// xstrstr returns a pointer to the first occurrence of b in a.
+char*
+xstrstr(char *a, char *b)
+{
+	return strstr(a, b);
+}
+
+// xstrrchr returns a pointer to the final occurrence of c in p.
+char*
+xstrrchr(char *p, int c)
+{
+	return strrchr(p, c);
+}
+
+// xsamefile reports whether f1 and f2 are the same file (or dir)
+int
+xsamefile(char *f1, char *f2)
+{
+	return streq(f1, f2); // suffice for now
+}
+
+sigjmp_buf sigill_jmpbuf;
+static void sigillhand(int);
+
+// xtryexecfunc tries to execute function f, if any illegal instruction
+// signal received in the course of executing that function, it will
+// return 0, otherwise it will return 1.
+// Some systems (notably NetBSD) will spin and spin when executing VFPv3
+// instructions on VFPv2 system (e.g. Raspberry Pi) without ever triggering
+// SIGILL, so we set a 1-second alarm to catch that case.
+int
+xtryexecfunc(void (*f)(void))
+{
+	int r;
+	r = 0;
+	signal(SIGILL, sigillhand);
+	signal(SIGALRM, sigillhand);
+	alarm(1);
+	if(sigsetjmp(sigill_jmpbuf, 1) == 0) {
+		f();
+		r = 1;
+	}
+	signal(SIGILL, SIG_DFL);
+	alarm(0);
+	signal(SIGALRM, SIG_DFL);
+	return r;
+}
+
+// SIGILL handler helper
+static void
+sigillhand(int signum)
+{
+	USED(signum);
+	siglongjmp(sigill_jmpbuf, 1);
+}
+
+static void
+__cpuid(int dst[4], int ax)
+{
+#ifdef __i386__
+	// we need to avoid ebx on i386 (esp. when -fPIC).
+	asm volatile(
+		"mov %%ebx, %%edi\n\t"
+		"cpuid\n\t"
+		"xchgl %%ebx, %%edi"
+		: "=a" (dst[0]), "=D" (dst[1]), "=c" (dst[2]), "=d" (dst[3])
+		: "0" (ax));
+#elif defined(__x86_64__)
+	asm volatile("cpuid"
+		: "=a" (dst[0]), "=b" (dst[1]), "=c" (dst[2]), "=d" (dst[3])
+		: "0" (ax));
+#else
+	dst[0] = dst[1] = dst[2] = dst[3] = 0;
+#endif
+}
+
+bool
+cansse2(void)
+{
+	int info[4];
+	
+	__cpuid(info, 1);
+	return (info[3] & (1<<26)) != 0;	// SSE2
+}
+
+#endif // PLAN9
+#endif // __WINDOWS__
diff --git a/src/cmd/dist/windows.c b/src/cmd/dist/windows.c
new file mode 100644
index 0000000..ff1a273
--- /dev/null
+++ b/src/cmd/dist/windows.c
@@ -0,0 +1,989 @@
+// 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.
+
+// These #ifdefs are being used as a substitute for
+// build configuration, so that on any system, this
+// tool can be built with the local equivalent of
+//	cc *.c
+//
+#ifdef WIN32
+
+// Portability layer implemented for Windows.
+// See unix.c for doc comments about exported functions.
+
+#include "a.h"
+#include <windows.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+/*
+ * Windows uses 16-bit rune strings in the APIs.
+ * Define conversions between Rune* and UTF-8 char*.
+ */
+
+typedef unsigned char uchar;
+typedef unsigned short Rune;  // same as Windows
+
+// encoderune encodes the rune r into buf and returns
+// the number of bytes used.
+static int
+encoderune(char *buf, Rune r)
+{
+	if(r < 0x80) {  // 7 bits
+		buf[0] = r;
+		return 1;
+	}
+	if(r < 0x800) {  // 5+6 bits
+		buf[0] = 0xc0 | (r>>6);
+		buf[1] = 0x80 | (r&0x3f);
+		return 2;
+	}
+	buf[0] = 0xe0 | (r>>12);
+	buf[1] = 0x80 | ((r>>6)&0x3f);
+	buf[2] = 0x80 | (r&0x3f);
+	return 3;
+}
+
+// decoderune decodes the rune encoding at sbuf into r
+// and returns the number of bytes used.
+static int
+decoderune(Rune *r, char *sbuf)
+{
+	uchar *buf;
+
+	buf = (uchar*)sbuf;
+	if(buf[0] < 0x80) {
+		*r = buf[0];
+		return 1;
+	}
+	if((buf[0]&0xe0) == 0xc0 && (buf[1]&0xc0) == 0x80) {
+		*r = (buf[0]&~0xc0)<<6 | (buf[1]&~0x80);
+		if(*r < 0x80)
+			goto err;
+		return 2;
+	}
+	if((buf[0]&0xf0) == 0xe0 && (buf[1]&0xc0) == 0x80 && (buf[2]&0xc0) == 0x80) {
+		*r = (buf[0]&~0xc0)<<12 | (buf[1]&~0x80)<<6 | (buf[2]&~0x80);
+		if(*r < 0x800)
+			goto err;
+		return 3;
+	}
+err:
+	*r = 0xfffd;
+	return 1;
+}
+
+// toutf replaces b with the UTF-8 encoding of the rune string r.	
+static void
+toutf(Buf *b, Rune *r)
+{
+	int i, n;
+	char buf[4];
+
+	breset(b);
+	for(i=0; r[i]; i++) {
+		n = encoderune(buf, r[i]);
+		bwrite(b, buf, n);
+	}
+}
+
+// torune replaces *rp with a pointer to a newly allocated
+// rune string equivalent of the UTF-8 string p.
+static void
+torune(Rune **rp, char *p)
+{
+	Rune *r, *w;
+
+	r = xmalloc((strlen(p)+1) * sizeof r[0]);
+	w = r;
+	while(*p)
+		p += decoderune(w++, p);
+	*w = 0;
+	*rp = r;
+}
+
+// errstr returns the most recent Windows error, in string form.
+static char*
+errstr(void)
+{
+	DWORD code;
+	Rune *r;
+	Buf b;
+
+	binit(&b);
+	code = GetLastError();
+	r = nil;
+	FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
+		nil, code, 0, (Rune*)&r, 0, nil);
+	toutf(&b, r);
+	return bstr(&b);  // leak but we're dying anyway
+}
+
+void
+xgetenv(Buf *b, char *name)
+{
+	Rune *buf;
+	int n;
+	Rune *r;
+
+	breset(b);
+	torune(&r, name);
+	n = GetEnvironmentVariableW(r, NULL, 0);
+	if(n > 0) {
+		buf = xmalloc((n+1)*sizeof buf[0]);
+		GetEnvironmentVariableW(r, buf, n+1);
+		buf[n] = '\0';
+		toutf(b, buf);
+		xfree(buf);
+	}
+	xfree(r);
+}
+
+void
+xsetenv(char *name, char *value)
+{
+	Rune *rname, *rvalue;
+
+	torune(&rname, name);
+	torune(&rvalue, value);
+	SetEnvironmentVariableW(rname, rvalue);
+	xfree(rname);
+	xfree(rvalue);
+}
+
+char*
+bprintf(Buf *b, char *fmt, ...)
+{
+	va_list arg;
+	char buf[4096];
+	
+	breset(b);
+	va_start(arg, fmt);
+	vsnprintf(buf, sizeof buf, fmt, arg);
+	va_end(arg);
+	bwritestr(b, buf);
+	return bstr(b);
+}
+
+void
+bwritef(Buf *b, char *fmt, ...)
+{
+	va_list arg;
+	char buf[4096];
+	
+	// no reset
+	va_start(arg, fmt);
+	vsnprintf(buf, sizeof buf, fmt, arg);
+	va_end(arg);
+	bwritestr(b, buf);
+}
+
+// bpathf is like bprintf but replaces / with \ in the result,
+// to make it a canonical windows file path.
+char*
+bpathf(Buf *b, char *fmt, ...)
+{
+	int i;
+	va_list arg;
+	char buf[4096];
+	
+	breset(b);
+	va_start(arg, fmt);
+	vsnprintf(buf, sizeof buf, fmt, arg);
+	va_end(arg);
+	bwritestr(b, buf);
+
+	for(i=0; i<b->len; i++)
+		if(b->p[i] == '/')
+			b->p[i] = '\\';
+
+	return bstr(b);
+}
+
+
+static void
+breadfrom(Buf *b, HANDLE h)
+{
+	DWORD n;
+
+	for(;;) {
+		if(b->len > 1<<22)
+			fatal("unlikely file size in readfrom");
+		bgrow(b, 4096);
+		n = 0;
+		if(!ReadFile(h, b->p+b->len, 4096, &n, nil)) {
+			// Happens for pipe reads.
+			break;
+		}
+		if(n == 0)
+			break;
+		b->len += n;
+	}
+}
+
+void
+run(Buf *b, char *dir, int mode, char *cmd, ...)
+{
+	va_list arg;
+	Vec argv;
+	char *p;
+	
+	vinit(&argv);
+	vadd(&argv, cmd);
+	va_start(arg, cmd);
+	while((p = va_arg(arg, char*)) != nil)
+		vadd(&argv, p);
+	va_end(arg);
+	
+	runv(b, dir, mode, &argv);
+	
+	vfree(&argv);
+}
+
+static void genrun(Buf*, char*, int, Vec*, int);
+
+void
+runv(Buf *b, char *dir, int mode, Vec *argv)
+{
+	genrun(b, dir, mode, argv, 1);
+}
+
+void
+bgrunv(char *dir, int mode, Vec *argv)
+{
+	genrun(nil, dir, mode, argv, 0);
+}
+
+#define MAXBG 4 /* maximum number of jobs to run at once */
+
+static struct {
+	PROCESS_INFORMATION pi;
+	int mode;
+	char *cmd;
+} bg[MAXBG];
+
+static int nbg;
+
+static void bgwait1(void);
+
+static void
+genrun(Buf *b, char *dir, int mode, Vec *argv, int wait)
+{
+	// Another copy of this logic is in ../../lib9/run_windows.c.
+	// If there's a bug here, fix the logic there too.
+	int i, j, nslash;
+	Buf cmd;
+	char *q;
+	Rune *rcmd, *rexe, *rdir;
+	STARTUPINFOW si;
+	PROCESS_INFORMATION pi;
+	HANDLE p[2];
+
+	while(nbg >= nelem(bg))
+		bgwait1();
+
+	binit(&cmd);
+
+	for(i=0; i<argv->len; i++) {
+		q = argv->p[i];
+		if(i == 0 && streq(q, "hg"))
+			bwritestr(&cmd, "cmd.exe /c ");
+		if(i > 0)
+			bwritestr(&cmd, " ");
+		if(contains(q, " ") || contains(q, "\t") || contains(q, "\"") || contains(q, "\\\\") || hassuffix(q, "\\")) {
+			bwritestr(&cmd, "\"");
+			nslash = 0;
+			for(; *q; q++) {
+				if(*q == '\\') {
+					nslash++;
+					continue;
+				}
+				if(*q == '"') {
+					for(j=0; j<2*nslash+1; j++)
+						bwritestr(&cmd, "\\");
+					nslash = 0;
+				}
+				for(j=0; j<nslash; j++)
+					bwritestr(&cmd, "\\");
+				nslash = 0;
+				bwrite(&cmd, q, 1);
+			}
+			for(j=0; j<2*nslash; j++)
+				bwritestr(&cmd, "\\");
+			bwritestr(&cmd, "\"");
+		} else {
+			bwritestr(&cmd, q);
+		}
+	}
+	if(vflag > 1)
+		errprintf("%s\n", bstr(&cmd));
+
+	torune(&rcmd, bstr(&cmd));
+	rexe = nil;
+	rdir = nil;
+	if(dir != nil)
+		torune(&rdir, dir);
+
+	memset(&si, 0, sizeof si);
+	si.cb = sizeof si;
+	si.dwFlags = STARTF_USESTDHANDLES;
+	si.hStdInput = INVALID_HANDLE_VALUE;
+	if(b == nil) {
+		si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
+		si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
+	} else {
+		SECURITY_ATTRIBUTES seci;
+
+		memset(&seci, 0, sizeof seci);
+		seci.nLength = sizeof seci;
+		seci.bInheritHandle = 1;
+		breset(b);
+		if(!CreatePipe(&p[0], &p[1], &seci, 0))
+			fatal("CreatePipe: %s", errstr());
+		si.hStdOutput = p[1];
+		si.hStdError = p[1];
+	}
+
+	if(!CreateProcessW(rexe, rcmd, nil, nil, TRUE, 0, nil, rdir, &si, &pi)) {
+		if(mode!=CheckExit)
+			return;
+		fatal("%s: %s", argv->p[0], errstr());
+	}
+	if(rexe != nil)
+		xfree(rexe);
+	xfree(rcmd);
+	if(rdir != nil)
+		xfree(rdir);
+	if(b != nil) {
+		CloseHandle(p[1]);
+		breadfrom(b, p[0]);
+		CloseHandle(p[0]);
+	}
+
+	if(nbg < 0)
+		fatal("bad bookkeeping");
+	bg[nbg].pi = pi;
+	bg[nbg].mode = mode;
+	bg[nbg].cmd = btake(&cmd);
+	nbg++;
+
+	if(wait)
+		bgwait();
+
+	bfree(&cmd);
+}
+
+// closes the background job for bgwait1
+static void
+bgwaitclose(int i)
+{
+	if(i < 0 || i >= nbg)
+		return;
+
+	CloseHandle(bg[i].pi.hProcess);
+	CloseHandle(bg[i].pi.hThread);
+	
+	bg[i] = bg[--nbg];
+}
+
+// bgwait1 waits for a single background job
+static void
+bgwait1(void)
+{
+	int i, mode;
+	char *cmd;
+	HANDLE bgh[MAXBG];
+	DWORD code;
+
+	if(nbg == 0)
+		fatal("bgwait1: nothing left");
+
+	for(i=0; i<nbg; i++)
+		bgh[i] = bg[i].pi.hProcess;
+	i = WaitForMultipleObjects(nbg, bgh, FALSE, INFINITE);
+	if(i < 0 || i >= nbg)
+		fatal("WaitForMultipleObjects: %s", errstr());
+
+	cmd = bg[i].cmd;
+	mode = bg[i].mode;
+	if(!GetExitCodeProcess(bg[i].pi.hProcess, &code)) {
+		bgwaitclose(i);
+		fatal("GetExitCodeProcess: %s", errstr());
+		return;
+	}
+
+	if(mode==CheckExit && code != 0) {
+		bgwaitclose(i);
+		fatal("FAILED: %s", cmd);
+		return;
+	}
+
+	bgwaitclose(i);
+}
+
+void
+bgwait(void)
+{
+	while(nbg > 0)
+		bgwait1();
+}
+
+// rgetwd returns a rune string form of the current directory's path.
+static Rune*
+rgetwd(void)
+{
+	int n;
+	Rune *r;
+
+	n = GetCurrentDirectoryW(0, nil);
+	r = xmalloc((n+1)*sizeof r[0]);
+	GetCurrentDirectoryW(n+1, r);
+	r[n] = '\0';
+	return r;
+}
+
+void
+xgetwd(Buf *b)
+{
+	Rune *r;
+
+	r = rgetwd();
+	breset(b);
+	toutf(b, r);
+	xfree(r);
+}
+
+void
+xrealwd(Buf *b, char *path)
+{
+	Rune *old;
+	Rune *rnew;
+
+	old = rgetwd();
+	torune(&rnew, path);
+	if(!SetCurrentDirectoryW(rnew))
+		fatal("chdir %s: %s", path, errstr());
+	xfree(rnew);
+	xgetwd(b);
+	if(!SetCurrentDirectoryW(old)) {
+		breset(b);
+		toutf(b, old);
+		fatal("chdir %s: %s", bstr(b), errstr());
+	}
+}
+
+bool
+isdir(char *p)
+{
+	DWORD attr;
+	Rune *r;
+
+	torune(&r, p);
+	attr = GetFileAttributesW(r);
+	xfree(r);
+	return attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY);
+}
+
+bool
+isfile(char *p)
+{
+	DWORD attr;
+	Rune *r;
+
+	torune(&r, p);
+	attr = GetFileAttributesW(r);
+	xfree(r);
+	return attr != INVALID_FILE_ATTRIBUTES && !(attr & FILE_ATTRIBUTE_DIRECTORY);
+}
+
+Time
+mtime(char *p)
+{
+	HANDLE h;
+	WIN32_FIND_DATAW data;
+	Rune *r;
+	FILETIME *ft;
+
+	torune(&r, p);
+	h = FindFirstFileW(r, &data);
+	xfree(r);
+	if(h == INVALID_HANDLE_VALUE)
+		return 0;
+	FindClose(h);
+	ft = &data.ftLastWriteTime;
+	return (Time)ft->dwLowDateTime + ((Time)ft->dwHighDateTime<<32);
+}
+
+bool
+isabs(char *p)
+{
+	// c:/ or c:\ at beginning
+	if(('A' <= p[0] && p[0] <= 'Z') || ('a' <= p[0] && p[0] <= 'z'))
+		return p[1] == ':' && (p[2] == '/' || p[2] == '\\');
+	// / or \ at beginning
+	return p[0] == '/' || p[0] == '\\';
+}
+
+void
+readfile(Buf *b, char *file)
+{
+	HANDLE h;
+	Rune *r;
+
+	breset(b);
+	if(vflag > 2)
+		errprintf("read %s\n", file);
+	torune(&r, file);
+	h = CreateFileW(r, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0);
+	if(h == INVALID_HANDLE_VALUE)
+		fatal("open %s: %s", file, errstr());
+	breadfrom(b, h);
+	CloseHandle(h);
+}
+
+void
+writefile(Buf *b, char *file, int exec)
+{
+	HANDLE h;
+	Rune *r;
+	DWORD n;
+
+	USED(exec);
+
+	if(vflag > 2)
+		errprintf("write %s\n", file);
+	torune(&r, file);
+	h = CreateFileW(r, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, nil, CREATE_ALWAYS, 0, 0);
+	if(h == INVALID_HANDLE_VALUE)
+		fatal("create %s: %s", file, errstr());
+	n = 0;
+	if(!WriteFile(h, b->p, b->len, &n, 0))
+		fatal("write %s: %s", file, errstr());
+	CloseHandle(h);
+}
+	
+
+void
+xmkdir(char *p)
+{
+	Rune *r;
+
+	torune(&r, p);
+	if(!CreateDirectoryW(r, nil))
+		fatal("mkdir %s: %s", p, errstr());
+	xfree(r);
+}
+
+void
+xmkdirall(char *p)
+{
+	int c;
+	char *q, *q2;
+	
+	if(isdir(p))
+		return;
+	q = strrchr(p, '/');
+	q2 = strrchr(p, '\\');
+	if(q2 != nil && (q == nil || q < q2))
+		q = q2;
+	if(q != nil) {
+		c = *q;
+		*q = '\0';
+		xmkdirall(p);
+		*q = c;
+	}
+	xmkdir(p);
+}
+
+void
+xremove(char *p)
+{
+	int attr;
+	Rune *r;
+
+	torune(&r, p);
+	attr = GetFileAttributesW(r);
+	if(attr >= 0) {
+		if(attr & FILE_ATTRIBUTE_DIRECTORY)
+			RemoveDirectoryW(r);
+		else
+			DeleteFileW(r);
+	}
+	xfree(r);
+}
+
+void
+xreaddir(Vec *dst, char *dir)
+{
+	Rune *r;
+	Buf b;
+	HANDLE h;
+	WIN32_FIND_DATAW data;
+	char *p, *q;
+
+	binit(&b);
+	vreset(dst);
+
+	bwritestr(&b, dir);
+	bwritestr(&b, "\\*");
+	torune(&r, bstr(&b));
+
+	h = FindFirstFileW(r, &data);
+	xfree(r);
+	if(h == INVALID_HANDLE_VALUE)
+		goto out;
+	do{
+		toutf(&b, data.cFileName);
+		p = bstr(&b);
+		q = xstrrchr(p, '\\');
+		if(q != nil)
+			p = q+1;
+		if(!streq(p, ".") && !streq(p, ".."))
+			vadd(dst, p);
+	}while(FindNextFileW(h, &data));
+	FindClose(h);
+
+out:
+	bfree(&b);
+}
+
+char*
+xworkdir(void)
+{
+	Rune buf[1024];
+	Rune tmp[MAX_PATH];
+	Rune go[3] = {'g', 'o', '\0'};
+	int n;
+	Buf b;
+
+	n = GetTempPathW(nelem(buf), buf);
+	if(n <= 0)
+		fatal("GetTempPath: %s", errstr());
+	buf[n] = '\0';
+
+	if(GetTempFileNameW(buf, go, 0, tmp) == 0)
+		fatal("GetTempFileName: %s", errstr());
+	DeleteFileW(tmp);
+	if(!CreateDirectoryW(tmp, nil))
+		fatal("create tempdir: %s", errstr());
+	
+	binit(&b);
+	toutf(&b, tmp);
+	return btake(&b);
+}
+
+void
+xremoveall(char *p)
+{
+	int i;
+	Buf b;
+	Vec dir;
+	Rune *r;
+
+	binit(&b);
+	vinit(&dir);
+
+	torune(&r, p);
+	if(isdir(p)) {
+		xreaddir(&dir, p);
+		for(i=0; i<dir.len; i++) {
+			bprintf(&b, "%s/%s", p, dir.p[i]);
+			xremoveall(bstr(&b));
+		}
+		RemoveDirectoryW(r);
+	} else {
+		DeleteFileW(r);
+	}
+	xfree(r);
+	
+	bfree(&b);
+	vfree(&dir);	
+}
+
+void
+fatal(char *msg, ...)
+{
+	static char buf1[1024];
+	va_list arg;
+
+	va_start(arg, msg);
+	vsnprintf(buf1, sizeof buf1, msg, arg);
+	va_end(arg);
+
+	errprintf("go tool dist: %s\n", buf1);
+	
+	bgwait();
+	ExitProcess(1);
+}
+
+// HEAP is the persistent handle to the default process heap.
+static HANDLE HEAP = INVALID_HANDLE_VALUE;
+
+void*
+xmalloc(int n)
+{
+	void *p;
+
+	if(HEAP == INVALID_HANDLE_VALUE)
+		HEAP = GetProcessHeap();
+	p = HeapAlloc(HEAP, 0, n);
+	if(p == nil)
+		fatal("out of memory allocating %d: %s", n, errstr());
+	memset(p, 0, n);
+	return p;
+}
+
+char*
+xstrdup(char *p)
+{
+	char *q;
+
+	q = xmalloc(strlen(p)+1);
+	strcpy(q, p);
+	return q;
+}
+
+void
+xfree(void *p)
+{
+	if(HEAP == INVALID_HANDLE_VALUE)
+		HEAP = GetProcessHeap();
+	HeapFree(HEAP, 0, p);
+}
+
+void*
+xrealloc(void *p, int n)
+{
+	if(p == nil)
+		return xmalloc(n);
+	if(HEAP == INVALID_HANDLE_VALUE)
+		HEAP = GetProcessHeap();
+	p = HeapReAlloc(HEAP, 0, p, n);
+	if(p == nil)
+		fatal("out of memory reallocating %d", n);
+	return p;
+}
+
+bool
+hassuffix(char *p, char *suffix)
+{
+	int np, ns;
+
+	np = strlen(p);
+	ns = strlen(suffix);
+	return np >= ns && streq(p+np-ns, suffix);
+}
+
+bool
+hasprefix(char *p, char *prefix)
+{
+	return strncmp(p, prefix, strlen(prefix)) == 0;
+}
+
+bool
+contains(char *p, char *sep)
+{
+	return strstr(p, sep) != nil;
+}
+
+bool
+streq(char *p, char *q)
+{
+	return strcmp(p, q) == 0;
+}
+
+char*
+lastelem(char *p)
+{
+	char *out;
+
+	out = p;
+	for(; *p; p++)
+		if(*p == '/' || *p == '\\')
+			out = p+1;
+	return out;
+}
+
+void
+xmemmove(void *dst, void *src, int n)
+{
+	memmove(dst, src, n);
+}
+
+int
+xmemcmp(void *a, void *b, int n)
+{
+	return memcmp(a, b, n);
+}
+
+int
+xstrlen(char *p)
+{
+	return strlen(p);
+}
+
+void
+xexit(int n)
+{
+	ExitProcess(n);
+}
+
+void
+xatexit(void (*f)(void))
+{
+	atexit(f);
+}
+
+void
+xprintf(char *fmt, ...)
+{
+	va_list arg;
+	
+	va_start(arg, fmt);
+	vprintf(fmt, arg);
+	va_end(arg);
+}
+
+void
+errprintf(char *fmt, ...)
+{
+	va_list arg;
+	
+	va_start(arg, fmt);
+	vfprintf(stderr, fmt, arg);
+	va_end(arg);
+}
+
+int
+main(int argc, char **argv)
+{
+	SYSTEM_INFO si;
+
+	setvbuf(stdout, nil, _IOLBF, 0);
+	setvbuf(stderr, nil, _IOLBF, 0);
+
+	slash = "\\";
+	gohostos = "windows";
+
+	GetSystemInfo(&si);
+	switch(si.wProcessorArchitecture) {
+	case PROCESSOR_ARCHITECTURE_AMD64:
+		gohostarch = "amd64";
+		break;
+	case PROCESSOR_ARCHITECTURE_INTEL:
+		gohostarch = "386";
+		break;
+	default:
+		fatal("unknown processor architecture");
+	}
+
+	init();
+
+	xmain(argc, argv);
+	return 0;
+}
+
+void
+xqsort(void *data, int n, int elemsize, int (*cmp)(const void*, const void*))
+{
+	qsort(data, n, elemsize, cmp);
+}
+
+int
+xstrcmp(char *a, char *b)
+{
+	return strcmp(a, b);
+}
+
+char*
+xstrstr(char *a, char *b)
+{
+	return strstr(a, b);
+}
+
+char*
+xstrrchr(char *p, int c)
+{
+	char *ep;
+	
+	ep = p+strlen(p);
+	for(ep=p+strlen(p); ep >= p; ep--)
+		if(*ep == c)
+			return ep;
+	return nil;
+}
+
+// xsamefile reports whether f1 and f2 are the same file (or dir)
+int
+xsamefile(char *f1, char *f2)
+{
+	Rune *ru;
+	HANDLE fd1, fd2;
+	BY_HANDLE_FILE_INFORMATION fi1, fi2;
+	int r;
+
+	// trivial case
+	if(streq(f1, f2))
+		return 1;
+	
+	torune(&ru, f1);
+	// refer to ../../os/stat_windows.go:/sameFile
+	fd1 = CreateFileW(ru, 0, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
+	xfree(ru);
+	if(fd1 == INVALID_HANDLE_VALUE)
+		return 0;
+	torune(&ru, f2);
+	fd2 = CreateFileW(ru, 0, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
+	xfree(ru);
+	if(fd2 == INVALID_HANDLE_VALUE) {
+		CloseHandle(fd1);
+		return 0;
+	}
+	r = GetFileInformationByHandle(fd1, &fi1) != 0 && GetFileInformationByHandle(fd2, &fi2) != 0;
+	CloseHandle(fd2);
+	CloseHandle(fd1);
+	if(r != 0 &&
+	   fi1.dwVolumeSerialNumber == fi2.dwVolumeSerialNumber &&
+	   fi1.nFileIndexHigh == fi2.nFileIndexHigh &&
+	   fi1.nFileIndexLow == fi2.nFileIndexLow)
+	   	return 1;
+	return 0;
+}
+
+// xtryexecfunc tries to execute function f, if any illegal instruction
+// signal received in the course of executing that function, it will
+// return 0, otherwise it will return 1.
+int
+xtryexecfunc(void (*f)(void))
+{
+	return 0; // suffice for now
+}
+
+static void
+cpuid(int dst[4], int ax)
+{
+	// NOTE: This asm statement is for mingw.
+	// If we ever support MSVC, use __cpuid(dst, ax)
+	// to use the built-in.
+#if defined(__i386__) || defined(__x86_64__)
+	asm volatile("cpuid"
+		: "=a" (dst[0]), "=b" (dst[1]), "=c" (dst[2]), "=d" (dst[3])
+		: "0" (ax));
+#else
+	dst[0] = dst[1] = dst[2] = dst[3] = 0;
+#endif
+}
+
+bool
+cansse2(void)
+{
+	int info[4];
+	
+	cpuid(info, 1);
+	return (info[3] & (1<<26)) != 0;	// SSE2
+}
+
+
+#endif // __WINDOWS__
diff --git a/src/cmd/fix/fix.go b/src/cmd/fix/fix.go
index 160336c..a07bbac 100644
--- a/src/cmd/fix/fix.go
+++ b/src/cmd/fix/fix.go
@@ -282,7 +282,7 @@ func walkBeforeAfter(x interface{}, before, after func(interface{})) {
 	after(x)
 }
 
-// imports reports whether f imports path.
+// imports returns true if f imports path.
 func imports(f *ast.File, path string) bool {
 	return importSpec(f, path) != nil
 }
@@ -322,33 +322,33 @@ func declImports(gen *ast.GenDecl, path string) bool {
 	return false
 }
 
-// isPkgDot reports whether t is the expression "pkg.name"
+// isPkgDot returns true if t is the expression "pkg.name"
 // where pkg is an imported identifier.
 func isPkgDot(t ast.Expr, pkg, name string) bool {
 	sel, ok := t.(*ast.SelectorExpr)
 	return ok && isTopName(sel.X, pkg) && sel.Sel.String() == name
 }
 
-// isPtrPkgDot reports whether f is the expression "*pkg.name"
+// isPtrPkgDot returns true if f is the expression "*pkg.name"
 // where pkg is an imported identifier.
 func isPtrPkgDot(t ast.Expr, pkg, name string) bool {
 	ptr, ok := t.(*ast.StarExpr)
 	return ok && isPkgDot(ptr.X, pkg, name)
 }
 
-// isTopName reports whether n is a top-level unresolved identifier with the given name.
+// isTopName returns true if n is a top-level unresolved identifier with the given name.
 func isTopName(n ast.Expr, name string) bool {
 	id, ok := n.(*ast.Ident)
 	return ok && id.Name == name && id.Obj == nil
 }
 
-// isName reports whether n is an identifier with the given name.
+// isName returns true if n is an identifier with the given name.
 func isName(n ast.Expr, name string) bool {
 	id, ok := n.(*ast.Ident)
 	return ok && id.String() == name
 }
 
-// isCall reports whether t is a call to pkg.name.
+// isCall returns true if t is a call to pkg.name.
 func isCall(t ast.Expr, pkg, name string) bool {
 	call, ok := t.(*ast.CallExpr)
 	return ok && isPkgDot(call.Fun, pkg, name)
@@ -360,7 +360,7 @@ func isIdent(n interface{}) *ast.Ident {
 	return id
 }
 
-// refersTo reports whether n is a reference to the same object as x.
+// refersTo returns true if n is a reference to the same object as x.
 func refersTo(n ast.Node, x *ast.Ident) bool {
 	id, ok := n.(*ast.Ident)
 	// The test of id.Name == x.Name handles top-level unresolved
@@ -368,12 +368,12 @@ func refersTo(n ast.Node, x *ast.Ident) bool {
 	return ok && id.Obj == x.Obj && id.Name == x.Name
 }
 
-// isBlank reports whether n is the blank identifier.
+// isBlank returns true if n is the blank identifier.
 func isBlank(n ast.Expr) bool {
 	return isName(n, "_")
 }
 
-// isEmptyString reports whether n is an empty string literal.
+// isEmptyString returns true if n is an empty string literal.
 func isEmptyString(n ast.Expr) bool {
 	lit, ok := n.(*ast.BasicLit)
 	return ok && lit.Kind == token.STRING && len(lit.Value) == 2
@@ -430,7 +430,7 @@ func rewriteUses(x *ast.Ident, f, fnot func(token.Pos) ast.Expr, scope []ast.Stm
 	}
 }
 
-// assignsTo reports whether any of the code in scope assigns to or takes the address of x.
+// assignsTo returns true if any of the code in scope assigns to or takes the address of x.
 func assignsTo(x *ast.Ident, scope []ast.Stmt) bool {
 	assigned := false
 	ff := func(n interface{}) {
diff --git a/src/cmd/gc/Makefile b/src/cmd/gc/Makefile
new file mode 100644
index 0000000..58e25fa
--- /dev/null
+++ b/src/cmd/gc/Makefile
@@ -0,0 +1,17 @@
+# 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
+
+install: y.tab.h builtin.c
+
+y.tab.h: go.y go.errors bisonerrors
+	bison -v -y -d go.y
+	# make yystate global, yytname mutable
+	cat y.tab.c | sed '/ int yystate;/d; s/int yychar;/int yychar, yystate;/; s/static const char \*const yytname/const char *yytname/; s/char const \*yymsgp/char *yymsgp/' >y1.tab.c
+	mv y1.tab.c y.tab.c
+	awk -f bisonerrors y.output go.errors >yerr.h
+
+builtin.c: runtime.go unsafe.go
+	./mkbuiltin
diff --git a/src/cmd/gc/align.c b/src/cmd/gc/align.c
new file mode 100644
index 0000000..63ed2e5
--- /dev/null
+++ b/src/cmd/gc/align.c
@@ -0,0 +1,680 @@
+// 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 "go.h"
+
+/*
+ * machine size and rounding
+ * alignment is dictated around
+ * the size of a pointer, set in betypeinit
+ * (see ../6g/galign.c).
+ */
+
+static int defercalc;
+
+vlong
+rnd(vlong o, vlong r)
+{
+	if(r < 1 || r > 8 || (r&(r-1)) != 0)
+		fatal("rnd");
+	return (o+r-1)&~(r-1);
+}
+
+static void
+offmod(Type *t)
+{
+	Type *f;
+	int32 o;
+
+	o = 0;
+	for(f=t->type; f!=T; f=f->down) {
+		if(f->etype != TFIELD)
+			fatal("offmod: not TFIELD: %lT", f);
+		f->width = o;
+		o += widthptr;
+		if(o >= MAXWIDTH) {
+			yyerror("interface too large");
+			o = widthptr;
+		}
+	}
+}
+
+static vlong
+widstruct(Type *errtype, Type *t, vlong o, int flag)
+{
+	Type *f;
+	int64 w;
+	int32 maxalign;
+	
+	maxalign = flag;
+	if(maxalign < 1)
+		maxalign = 1;
+	for(f=t->type; f!=T; f=f->down) {
+		if(f->etype != TFIELD)
+			fatal("widstruct: not TFIELD: %lT", f);
+		if(f->type == T) {
+			// broken field, just skip it so that other valid fields
+			// get a width.
+			continue;
+		}
+		dowidth(f->type);
+		if(f->type->align > maxalign)
+			maxalign = f->type->align;
+		if(f->type->width < 0)
+			fatal("invalid width %lld", f->type->width);
+		w = f->type->width;
+		if(f->type->align > 0)
+			o = rnd(o, f->type->align);
+		f->width = o;	// really offset for TFIELD
+		if(f->nname != N) {
+			// this same stackparam logic is in addrescapes
+			// in typecheck.c.  usually addrescapes runs after
+			// widstruct, in which case we could drop this,
+			// but function closure functions are the exception.
+			if(f->nname->stackparam) {
+				f->nname->stackparam->xoffset = o;
+				f->nname->xoffset = 0;
+			} else
+				f->nname->xoffset = o;
+		}
+		o += w;
+		if(o >= MAXWIDTH) {
+			yyerror("type %lT too large", errtype);
+			o = 8;  // small but nonzero
+		}
+	}
+	// final width is rounded
+	if(flag)
+		o = rnd(o, maxalign);
+	t->align = maxalign;
+
+	// type width only includes back to first field's offset
+	if(t->type == T)
+		t->width = 0;
+	else
+		t->width = o - t->type->width;
+	return o;
+}
+
+void
+dowidth(Type *t)
+{
+	int32 et;
+	int64 w;
+	int lno;
+	Type *t1;
+
+	if(widthptr == 0)
+		fatal("dowidth without betypeinit");
+
+	if(t == T)
+		return;
+
+	if(t->width > 0)
+		return;
+
+	if(t->width == -2) {
+		lno = lineno;
+		lineno = t->lineno;
+		if(!t->broke) {
+			t->broke = 1;
+			yyerror("invalid recursive type %T", t);
+		}
+		t->width = 0;
+		lineno = lno;
+		return;
+	}
+
+	// break infinite recursion if the broken recursive type
+	// is referenced again
+	if(t->broke && t->width == 0)
+		return;
+
+	// defer checkwidth calls until after we're done
+	defercalc++;
+
+	lno = lineno;
+	lineno = t->lineno;
+	t->width = -2;
+	t->align = 0;
+
+	et = t->etype;
+	switch(et) {
+	case TFUNC:
+	case TCHAN:
+	case TMAP:
+	case TSTRING:
+		break;
+
+	default:
+		/* simtype == 0 during bootstrap */
+		if(simtype[t->etype] != 0)
+			et = simtype[t->etype];
+		break;
+	}
+
+	w = 0;
+	switch(et) {
+	default:
+		fatal("dowidth: unknown type: %T", t);
+		break;
+
+	/* compiler-specific stuff */
+	case TINT8:
+	case TUINT8:
+	case TBOOL:		// bool is int8
+		w = 1;
+		break;
+	case TINT16:
+	case TUINT16:
+		w = 2;
+		break;
+	case TINT32:
+	case TUINT32:
+	case TFLOAT32:
+		w = 4;
+		break;
+	case TINT64:
+	case TUINT64:
+	case TFLOAT64:
+	case TCOMPLEX64:
+		w = 8;
+		t->align = widthreg;
+		break;
+	case TCOMPLEX128:
+		w = 16;
+		t->align = widthreg;
+		break;
+	case TPTR32:
+		w = 4;
+		checkwidth(t->type);
+		break;
+	case TPTR64:
+		w = 8;
+		checkwidth(t->type);
+		break;
+	case TUNSAFEPTR:
+		w = widthptr;
+		break;
+	case TINTER:		// implemented as 2 pointers
+		w = 2*widthptr;
+		t->align = widthptr;
+		offmod(t);
+		break;
+	case TCHAN:		// implemented as pointer
+		w = widthptr;
+		checkwidth(t->type);
+
+		// make fake type to check later to
+		// trigger channel argument check.
+		t1 = typ(TCHANARGS);
+		t1->type = t;
+		checkwidth(t1);
+		break;
+	case TCHANARGS:
+		t1 = t->type;
+		dowidth(t->type);	// just in case
+		if(t1->type->width >= (1<<16))
+			yyerror("channel element type too large (>64kB)");
+		t->width = 1;
+		break;
+	case TMAP:		// implemented as pointer
+		w = widthptr;
+		checkwidth(t->type);
+		checkwidth(t->down);
+		break;
+	case TFORW:		// should have been filled in
+		if(!t->broke)
+			yyerror("invalid recursive type %T", t);
+		w = 1;	// anything will do
+		break;
+	case TANY:
+		// dummy type; should be replaced before use.
+		if(!debug['A'])
+			fatal("dowidth any");
+		w = 1;	// anything will do
+		break;
+	case TSTRING:
+		if(sizeof_String == 0)
+			fatal("early dowidth string");
+		w = sizeof_String;
+		t->align = widthptr;
+		break;
+	case TARRAY:
+		if(t->type == T)
+			break;
+		if(t->bound >= 0) {
+			uint64 cap;
+
+			dowidth(t->type);
+			if(t->type->width != 0) {
+				cap = (MAXWIDTH-1) / t->type->width;
+				if(t->bound > cap)
+					yyerror("type %lT larger than address space", t);
+			}
+			w = t->bound * t->type->width;
+			t->align = t->type->align;
+		}
+		else if(t->bound == -1) {
+			w = sizeof_Array;
+			checkwidth(t->type);
+			t->align = widthptr;
+		}
+		else if(t->bound == -100) {
+			if(!t->broke) {
+				yyerror("use of [...] array outside of array literal");
+				t->broke = 1;
+			}
+		}
+		else
+			fatal("dowidth %T", t);	// probably [...]T
+		break;
+
+	case TSTRUCT:
+		if(t->funarg)
+			fatal("dowidth fn struct %T", t);
+		w = widstruct(t, t, 0, 1);
+		break;
+
+	case TFUNC:
+		// make fake type to check later to
+		// trigger function argument computation.
+		t1 = typ(TFUNCARGS);
+		t1->type = t;
+		checkwidth(t1);
+
+		// width of func type is pointer
+		w = widthptr;
+		break;
+
+	case TFUNCARGS:
+		// function is 3 cated structures;
+		// compute their widths as side-effect.
+		t1 = t->type;
+		w = widstruct(t->type, *getthis(t1), 0, 0);
+		w = widstruct(t->type, *getinarg(t1), w, widthreg);
+		w = widstruct(t->type, *getoutarg(t1), w, widthreg);
+		t1->argwid = w;
+		if(w%widthreg)
+			warn("bad type %T %d\n", t1, w);
+		t->align = 1;
+		break;
+	}
+
+	if(widthptr == 4 && w != (int32)w)
+		yyerror("type %T too large", t);
+
+	t->width = w;
+	if(t->align == 0) {
+		if(w > 8 || (w&(w-1)) != 0)
+			fatal("invalid alignment for %T", t);
+		t->align = w;
+	}
+	lineno = lno;
+
+	if(defercalc == 1)
+		resumecheckwidth();
+	else
+		--defercalc;
+}
+
+/*
+ * when a type's width should be known, we call checkwidth
+ * to compute it.  during a declaration like
+ *
+ *	type T *struct { next T }
+ *
+ * it is necessary to defer the calculation of the struct width
+ * until after T has been initialized to be a pointer to that struct.
+ * similarly, during import processing structs may be used
+ * before their definition.  in those situations, calling
+ * defercheckwidth() stops width calculations until
+ * resumecheckwidth() is called, at which point all the
+ * checkwidths that were deferred are executed.
+ * dowidth should only be called when the type's size
+ * is needed immediately.  checkwidth makes sure the
+ * size is evaluated eventually.
+ */
+typedef struct TypeList TypeList;
+struct TypeList {
+	Type *t;
+	TypeList *next;
+};
+
+static TypeList *tlfree;
+static TypeList *tlq;
+
+void
+checkwidth(Type *t)
+{
+	TypeList *l;
+
+	if(t == T)
+		return;
+
+	// function arg structs should not be checked
+	// outside of the enclosing function.
+	if(t->funarg)
+		fatal("checkwidth %T", t);
+
+	if(!defercalc) {
+		dowidth(t);
+		return;
+	}
+	if(t->deferwidth)
+		return;
+	t->deferwidth = 1;
+
+	l = tlfree;
+	if(l != nil)
+		tlfree = l->next;
+	else
+		l = mal(sizeof *l);
+
+	l->t = t;
+	l->next = tlq;
+	tlq = l;
+}
+
+void
+defercheckwidth(void)
+{
+	// we get out of sync on syntax errors, so don't be pedantic.
+	if(defercalc && nerrors == 0)
+		fatal("defercheckwidth");
+	defercalc = 1;
+}
+
+void
+resumecheckwidth(void)
+{
+	TypeList *l;
+
+	if(!defercalc)
+		fatal("resumecheckwidth");
+	for(l = tlq; l != nil; l = tlq) {
+		l->t->deferwidth = 0;
+		tlq = l->next;
+		dowidth(l->t);
+		l->next = tlfree;
+		tlfree = l;
+	}
+	defercalc = 0;
+}
+
+void
+typeinit(void)
+{
+	int i, etype, sameas;
+	Type *t;
+	Sym *s, *s1;
+
+	if(widthptr == 0)
+		fatal("typeinit before betypeinit");
+
+	for(i=0; i<NTYPE; i++)
+		simtype[i] = i;
+
+	types[TPTR32] = typ(TPTR32);
+	dowidth(types[TPTR32]);
+
+	types[TPTR64] = typ(TPTR64);
+	dowidth(types[TPTR64]);
+	
+	t = typ(TUNSAFEPTR);
+	types[TUNSAFEPTR] = t;
+	t->sym = pkglookup("Pointer", unsafepkg);
+	t->sym->def = typenod(t);
+	
+	dowidth(types[TUNSAFEPTR]);
+
+	tptr = TPTR32;
+	if(widthptr == 8)
+		tptr = TPTR64;
+
+	for(i=TINT8; i<=TUINT64; i++)
+		isint[i] = 1;
+	isint[TINT] = 1;
+	isint[TUINT] = 1;
+	isint[TUINTPTR] = 1;
+
+	isfloat[TFLOAT32] = 1;
+	isfloat[TFLOAT64] = 1;
+
+	iscomplex[TCOMPLEX64] = 1;
+	iscomplex[TCOMPLEX128] = 1;
+
+	isptr[TPTR32] = 1;
+	isptr[TPTR64] = 1;
+
+	isforw[TFORW] = 1;
+
+	issigned[TINT] = 1;
+	issigned[TINT8] = 1;
+	issigned[TINT16] = 1;
+	issigned[TINT32] = 1;
+	issigned[TINT64] = 1;
+
+	/*
+	 * initialize okfor
+	 */
+	for(i=0; i<NTYPE; i++) {
+		if(isint[i] || i == TIDEAL) {
+			okforeq[i] = 1;
+			okforcmp[i] = 1;
+			okforarith[i] = 1;
+			okforadd[i] = 1;
+			okforand[i] = 1;
+			okforconst[i] = 1;
+			issimple[i] = 1;
+			minintval[i] = mal(sizeof(*minintval[i]));
+			maxintval[i] = mal(sizeof(*maxintval[i]));
+		}
+		if(isfloat[i]) {
+			okforeq[i] = 1;
+			okforcmp[i] = 1;
+			okforadd[i] = 1;
+			okforarith[i] = 1;
+			okforconst[i] = 1;
+			issimple[i] = 1;
+			minfltval[i] = mal(sizeof(*minfltval[i]));
+			maxfltval[i] = mal(sizeof(*maxfltval[i]));
+		}
+		if(iscomplex[i]) {
+			okforeq[i] = 1;
+			okforadd[i] = 1;
+			okforarith[i] = 1;
+			okforconst[i] = 1;
+			issimple[i] = 1;
+		}
+	}
+
+	issimple[TBOOL] = 1;
+
+	okforadd[TSTRING] = 1;
+
+	okforbool[TBOOL] = 1;
+
+	okforcap[TARRAY] = 1;
+	okforcap[TCHAN] = 1;
+
+	okforconst[TBOOL] = 1;
+	okforconst[TSTRING] = 1;
+
+	okforlen[TARRAY] = 1;
+	okforlen[TCHAN] = 1;
+	okforlen[TMAP] = 1;
+	okforlen[TSTRING] = 1;
+
+	okforeq[TPTR32] = 1;
+	okforeq[TPTR64] = 1;
+	okforeq[TUNSAFEPTR] = 1;
+	okforeq[TINTER] = 1;
+	okforeq[TCHAN] = 1;
+	okforeq[TSTRING] = 1;
+	okforeq[TBOOL] = 1;
+	okforeq[TMAP] = 1;	// nil only; refined in typecheck
+	okforeq[TFUNC] = 1;	// nil only; refined in typecheck
+	okforeq[TARRAY] = 1;	// nil slice only; refined in typecheck
+	okforeq[TSTRUCT] = 1;	// it's complicated; refined in typecheck
+
+	okforcmp[TSTRING] = 1;
+
+	for(i=0; i<nelem(okfor); i++)
+		okfor[i] = okfornone;
+
+	// binary
+	okfor[OADD] = okforadd;
+	okfor[OAND] = okforand;
+	okfor[OANDAND] = okforbool;
+	okfor[OANDNOT] = okforand;
+	okfor[ODIV] = okforarith;
+	okfor[OEQ] = okforeq;
+	okfor[OGE] = okforcmp;
+	okfor[OGT] = okforcmp;
+	okfor[OLE] = okforcmp;
+	okfor[OLT] = okforcmp;
+	okfor[OMOD] = okforand;
+	okfor[OMUL] = okforarith;
+	okfor[ONE] = okforeq;
+	okfor[OOR] = okforand;
+	okfor[OOROR] = okforbool;
+	okfor[OSUB] = okforarith;
+	okfor[OXOR] = okforand;
+	okfor[OLSH] = okforand;
+	okfor[ORSH] = okforand;
+
+	// unary
+	okfor[OCOM] = okforand;
+	okfor[OMINUS] = okforarith;
+	okfor[ONOT] = okforbool;
+	okfor[OPLUS] = okforarith;
+
+	// special
+	okfor[OCAP] = okforcap;
+	okfor[OLEN] = okforlen;
+
+	// comparison
+	iscmp[OLT] = 1;
+	iscmp[OGT] = 1;
+	iscmp[OGE] = 1;
+	iscmp[OLE] = 1;
+	iscmp[OEQ] = 1;
+	iscmp[ONE] = 1;
+
+	mpatofix(maxintval[TINT8], "0x7f");
+	mpatofix(minintval[TINT8], "-0x80");
+	mpatofix(maxintval[TINT16], "0x7fff");
+	mpatofix(minintval[TINT16], "-0x8000");
+	mpatofix(maxintval[TINT32], "0x7fffffff");
+	mpatofix(minintval[TINT32], "-0x80000000");
+	mpatofix(maxintval[TINT64], "0x7fffffffffffffff");
+	mpatofix(minintval[TINT64], "-0x8000000000000000");
+
+	mpatofix(maxintval[TUINT8], "0xff");
+	mpatofix(maxintval[TUINT16], "0xffff");
+	mpatofix(maxintval[TUINT32], "0xffffffff");
+	mpatofix(maxintval[TUINT64], "0xffffffffffffffff");
+
+	/* f is valid float if min < f < max.  (min and max are not themselves valid.) */
+	mpatoflt(maxfltval[TFLOAT32], "33554431p103");	/* 2^24-1 p (127-23) + 1/2 ulp*/
+	mpatoflt(minfltval[TFLOAT32], "-33554431p103");
+	mpatoflt(maxfltval[TFLOAT64], "18014398509481983p970");	/* 2^53-1 p (1023-52) + 1/2 ulp */
+	mpatoflt(minfltval[TFLOAT64], "-18014398509481983p970");
+
+	maxfltval[TCOMPLEX64] = maxfltval[TFLOAT32];
+	minfltval[TCOMPLEX64] = minfltval[TFLOAT32];
+	maxfltval[TCOMPLEX128] = maxfltval[TFLOAT64];
+	minfltval[TCOMPLEX128] = minfltval[TFLOAT64];
+
+	/* for walk to use in error messages */
+	types[TFUNC] = functype(N, nil, nil);
+
+	/* types used in front end */
+	// types[TNIL] got set early in lexinit
+	types[TIDEAL] = typ(TIDEAL);
+	types[TINTER] = typ(TINTER);
+
+	/* simple aliases */
+	simtype[TMAP] = tptr;
+	simtype[TCHAN] = tptr;
+	simtype[TFUNC] = tptr;
+	simtype[TUNSAFEPTR] = tptr;
+
+	/* pick up the backend typedefs */
+	for(i=0; typedefs[i].name; i++) {
+		s = lookup(typedefs[i].name);
+		s1 = pkglookup(typedefs[i].name, builtinpkg);
+
+		etype = typedefs[i].etype;
+		if(etype < 0 || etype >= nelem(types))
+			fatal("typeinit: %s bad etype", s->name);
+		sameas = typedefs[i].sameas;
+		if(sameas < 0 || sameas >= nelem(types))
+			fatal("typeinit: %s bad sameas", s->name);
+		simtype[etype] = sameas;
+		minfltval[etype] = minfltval[sameas];
+		maxfltval[etype] = maxfltval[sameas];
+		minintval[etype] = minintval[sameas];
+		maxintval[etype] = maxintval[sameas];
+
+		t = types[etype];
+		if(t != T)
+			fatal("typeinit: %s already defined", s->name);
+
+		t = typ(etype);
+		t->sym = s1;
+
+		dowidth(t);
+		types[etype] = t;
+		s1->def = typenod(t);
+	}
+
+	Array_array = rnd(0, widthptr);
+	Array_nel = rnd(Array_array+widthptr, widthint);
+	Array_cap = rnd(Array_nel+widthint, widthint);
+	sizeof_Array = rnd(Array_cap+widthint, widthptr);
+
+	// string is same as slice wo the cap
+	sizeof_String = rnd(Array_nel+widthint, widthptr);
+
+	dowidth(types[TSTRING]);
+	dowidth(idealstring);
+}
+
+/*
+ * compute total size of f's in/out arguments.
+ */
+int
+argsize(Type *t)
+{
+	Iter save;
+	Type *fp;
+	int64 w, x;
+
+	w = 0;
+
+	fp = structfirst(&save, getoutarg(t));
+	while(fp != T) {
+		x = fp->width + fp->type->width;
+		if(x > w)
+			w = x;
+		fp = structnext(&save);
+	}
+
+	fp = funcfirst(&save, t);
+	while(fp != T) {
+		x = fp->width + fp->type->width;
+		if(x > w)
+			w = x;
+		fp = funcnext(&save);
+	}
+
+	w = (w+widthptr-1) & ~(widthptr-1);
+	if((int)w != w)
+		fatal("argsize too big");
+	return w;
+}
diff --git a/src/cmd/gc/array.c b/src/cmd/gc/array.c
new file mode 100644
index 0000000..611fc9f
--- /dev/null
+++ b/src/cmd/gc/array.c
@@ -0,0 +1,115 @@
+// 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);
+}
+
+void
+arraysort(Array *array, int (*cmp)(const void*, const void*))
+{
+	qsort(array->data, array->length, array->size, cmp);
+}
diff --git a/src/cmd/gc/bisonerrors b/src/cmd/gc/bisonerrors
new file mode 100755
index 0000000..fa74c67
--- /dev/null
+++ b/src/cmd/gc/bisonerrors
@@ -0,0 +1,156 @@
+#!/usr/bin/awk -f
+# Copyright 2010 The Go Authors.  All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+# This program implements the core idea from
+#
+#	Clinton L. Jeffery, Generating LR syntax error messages from examples,
+#	ACM TOPLAS 25(5) (September 2003).  http://doi.acm.org/10.1145/937563.937566
+# 
+# It reads Bison's summary of a grammar followed by a file
+# like go.errors, replacing lines beginning with % by the 
+# yystate and yychar that will be active when an error happens
+# while parsing that line.  
+#
+# Unlike the system described in the paper, the lines in go.errors
+# give grammar symbol name lists, not actual program fragments.
+# This is a little less programmer-friendly but doesn't require being
+# able to run the text through lex.c.
+
+BEGIN{
+	bison = 1
+	grammar = 0
+	states = 0
+	open = 0
+}
+
+# In Grammar section of y.output,
+# record lhs and length of rhs for each rule.
+bison && /^Grammar/ { grammar = 1 }
+bison && /^(Terminals|state 0)/ { grammar = 0 }
+grammar && NF>0 {
+	if($2 != "|") {
+		r = $2
+		sub(/:$/, "", r)
+	}
+	rulelhs[$1] = r
+	rulesize[$1] = NF-2
+	if(rulesize[$1] == 1 && $3 == "%empty") {
+		rulesize[$1] = 0
+	}
+	if(rulesize[$1] == 3 && $3 $4 $5 == "/*empty*/") {
+		rulesize[$1] = 0
+	}
+}
+
+# In state dumps, record shift/reduce actions.
+bison && /^[Ss]tate 0/ { grammar = 0; states = 1 }
+
+states && /^[Ss]tate / { state = $2 }
+states { statetext[state] = statetext[state] $0 "\n" }
+
+states && / shift/ {
+	n = nshift[state]++
+	if($0 ~ /and go to/)
+		shift[state,n] = $7 # GNU Bison
+	else
+		shift[state,n] = $3 # Plan 9 Yacc
+	shifttoken[state,n] = $1
+	next
+}
+states && / (go to|goto)/ {
+	n = nshift[state]++
+	if($0 ~ /go to/)
+		shift[state,n] = $5 # GNU Bison
+	else
+		shift[state,n] = $3 # Plan 9 Yacc
+	shifttoken[state,n] = $1
+	next
+}
+states && / reduce/ {
+	n = nreduce[state]++
+	if($0 ~ /reduce using rule/)
+		reduce[state,n] = $5 # GNU Bison
+	else
+		reduce[state,n] = $3 # Plan 9 yacc
+	reducetoken[state,n] = $1
+	next
+}
+
+# Skip over the summary information printed by Plan 9 yacc.
+/nonterminals$/,/^maximum spread/ { next }
+
+# First // comment marks the beginning of the pattern file.
+/^\/\// { bison = 0; grammar = 0; state = 0 }
+bison { next }
+
+# Treat % as first field on line as introducing a pattern (token sequence).
+# Run it through the LR machine and print the induced "yystate, yychar,"
+# at the point where the error happens.
+$1 == "%" {
+	nstack = 0
+	state = 0
+	f = 2
+	tok = ""
+	for(;;) {
+		if(tok == "" && f <= NF) {
+			tok = $f
+			f++
+		}
+		found = 0
+		for(j=0; j<nshift[state]; j++) {
+			if(shifttoken[state,j] == tok) {
+				# print "SHIFT " tok " " state " -> " shift[state,j]
+				stack[nstack++] = state
+				state = shift[state,j]
+				found = 1
+				tok = ""
+				break
+			}
+		}
+		if(found)
+			continue
+		for(j=0; j<nreduce[state]; j++) {
+			t = reducetoken[state,j]
+			if(t == tok || t == "$default" || t == ".") {
+				stack[nstack++] = state
+				rule = reduce[state,j]
+				nstack -= rulesize[rule]
+				state = stack[--nstack]
+				lhs = rulelhs[rule]
+				if(tok != "")
+					--f
+				tok = rulelhs[rule]
+				# print "REDUCE " nstack " " state " " tok " rule " rule " size " rulesize[rule]
+				found = 1
+				break
+			}
+		}
+		if(found)
+			continue
+
+		# No shift or reduce applied - found the error.
+		printf("\t{%s, %s,\n", state, tok);
+		open = 1;
+		break
+	}
+	next
+}
+
+# Print other lines verbatim.
+open && /,$/ {
+	s = $0;
+	sub(",", "},", s)
+	print s
+	open = 0
+	next
+}
+
+open && /"$/ {
+	print $0 "}"
+	open = 0
+	next
+}
+
+{print}
diff --git a/src/cmd/gc/bits.c b/src/cmd/gc/bits.c
new file mode 100644
index 0000000..2e79f6f
--- /dev/null
+++ b/src/cmd/gc/bits.c
@@ -0,0 +1,163 @@
+// Inferno utils/cc/bits.c
+// http://code.google.com/p/inferno-os/source/browse/utils/cc/bits.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 "go.h"
+
+/*
+Bits
+bor(Bits a, Bits b)
+{
+	Bits c;
+	int i;
+
+	for(i=0; i<BITS; i++)
+		c.b[i] = a.b[i] | b.b[i];
+	return c;
+}
+
+Bits
+band(Bits a, Bits b)
+{
+	Bits c;
+	int i;
+
+	for(i=0; i<BITS; i++)
+		c.b[i] = a.b[i] & b.b[i];
+	return c;
+}
+
+Bits
+bnot(Bits a)
+{
+	Bits c;
+	int i;
+
+	for(i=0; i<BITS; i++)
+		c.b[i] = ~a.b[i];
+	return c;
+}
+*/
+
+int
+bany(Bits *a)
+{
+	int i;
+
+	for(i=0; i<BITS; i++)
+		if(a->b[i])
+			return 1;
+	return 0;
+}
+
+/*
+int
+beq(Bits a, Bits b)
+{
+	int i;
+
+	for(i=0; i<BITS; i++)
+		if(a.b[i] != b.b[i])
+			return 0;
+	return 1;
+}
+*/
+
+int
+bnum(Bits a)
+{
+	int i;
+	int32 b;
+
+	for(i=0; i<BITS; i++)
+		if(b = a.b[i])
+			return 32*i + bitno(b);
+	fatal("bad in bnum");
+	return 0;
+}
+
+Bits
+blsh(uint n)
+{
+	Bits c;
+
+	c = zbits;
+	c.b[n/32] = 1L << (n%32);
+	return c;
+}
+
+/*
+int
+bset(Bits a, uint n)
+{
+	if(a.b[n/32] & (1L << (n%32)))
+		return 1;
+	return 0;
+}
+*/
+
+int
+bitno(int32 b)
+{
+	int i;
+
+	for(i=0; i<32; i++)
+		if(b & (1L<<i))
+			return i;
+	fatal("bad in bitno");
+	return 0;
+}
+
+int
+Qconv(Fmt *fp)
+{
+	Bits bits;
+	int i, first;
+
+	first = 1;
+	bits = va_arg(fp->args, Bits);
+	while(bany(&bits)) {
+		i = bnum(bits);
+		if(first)
+			first = 0;
+		else
+			fmtprint(fp, " ");
+		if(var[i].node == N || var[i].node->sym == S)
+			fmtprint(fp, "$%d", i);
+		else {
+			fmtprint(fp, "%s(%d)", var[i].node->sym->name, i);
+			if(var[i].offset != 0)
+				fmtprint(fp, "%+lld", (vlong)var[i].offset);
+		}
+		bits.b[i/32] &= ~(1L << (i%32));
+	}
+	return 0;
+}
diff --git a/src/cmd/gc/builtin.c b/src/cmd/gc/builtin.c
new file mode 100644
index 0000000..fbca4ee
--- /dev/null
+++ b/src/cmd/gc/builtin.c
@@ -0,0 +1,137 @@
+// AUTO-GENERATED by mkbuiltin; DO NOT EDIT
+char *runtimeimport =
+	"package runtime\n"
+	"import runtime \"runtime\"\n"
+	"func @\"\".newobject (@\"\".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"
+	"func @\"\".gopanic (? interface {})\n"
+	"func @\"\".gorecover (? *int32) (? interface {})\n"
+	"func @\"\".printbool (? bool)\n"
+	"func @\"\".printfloat (? float64)\n"
+	"func @\"\".printint (? int64)\n"
+	"func @\"\".printhex (? uint64)\n"
+	"func @\"\".printuint (? uint64)\n"
+	"func @\"\".printcomplex (? complex128)\n"
+	"func @\"\".printstring (? string)\n"
+	"func @\"\".printpointer (? any)\n"
+	"func @\"\".printiface (? any)\n"
+	"func @\"\".printeface (? any)\n"
+	"func @\"\".printslice (? any)\n"
+	"func @\"\".printnl ()\n"
+	"func @\"\".printsp ()\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"
+	"func @\"\".stringiter (? string, ? int) (? int)\n"
+	"func @\"\".stringiter2 (? string, ? int) (@\"\".retk·1 int, @\"\".retv·2 rune)\n"
+	"func @\"\".slicecopy (@\"\".to·2 any, @\"\".fr·3 any, @\"\".wid·4 uintptr) (? int)\n"
+	"func @\"\".slicestringcopy (@\"\".to·2 any, @\"\".fr·3 any) (? int)\n"
+	"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 @\"\".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"
+	"func @\"\".assertE2I2 (@\"\".typ·3 *byte, @\"\".iface·4 any) (@\"\".ret·1 any, @\"\".ok·2 bool)\n"
+	"func @\"\".assertE2T (@\"\".typ·2 *byte, @\"\".iface·3 any) (@\"\".ret·1 any)\n"
+	"func @\"\".assertE2T2 (@\"\".typ·3 *byte, @\"\".iface·4 any) (@\"\".ret·1 any, @\"\".ok·2 bool)\n"
+	"func @\"\".assertI2E (@\"\".typ·2 *byte, @\"\".iface·3 any) (@\"\".ret·1 any)\n"
+	"func @\"\".assertI2E2 (@\"\".typ·3 *byte, @\"\".iface·4 any) (@\"\".ret·1 any, @\"\".ok·2 bool)\n"
+	"func @\"\".assertI2I (@\"\".typ·2 *byte, @\"\".iface·3 any) (@\"\".ret·1 any)\n"
+	"func @\"\".assertI2I2 (@\"\".typ·3 *byte, @\"\".iface·4 any) (@\"\".ret·1 any, @\"\".ok·2 bool)\n"
+	"func @\"\".assertI2T (@\"\".typ·2 *byte, @\"\".iface·3 any) (@\"\".ret·1 any)\n"
+	"func @\"\".assertI2T2 (@\"\".typ·3 *byte, @\"\".iface·4 any) (@\"\".ret·1 any, @\"\".ok·2 bool)\n"
+	"func @\"\".assertI2TOK (@\"\".typ·2 *byte, @\"\".iface·3 any) (@\"\".ok·1 bool)\n"
+	"func @\"\".assertE2TOK (@\"\".typ·2 *byte, @\"\".iface·3 any) (@\"\".ok·1 bool)\n"
+	"func @\"\".ifaceeq (@\"\".i1·2 any, @\"\".i2·3 any) (@\"\".ret·1 bool)\n"
+	"func @\"\".efaceeq (@\"\".i1·2 any, @\"\".i2·3 any) (@\"\".ret·1 bool)\n"
+	"func @\"\".ifacethash (@\"\".i1·2 any) (@\"\".ret·1 uint32)\n"
+	"func @\"\".efacethash (@\"\".i1·2 any) (@\"\".ret·1 uint32)\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_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_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 @\"\".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 @\"\".mapiternext (@\"\".hiter·1 *any)\n"
+	"func @\"\".makechan (@\"\".chanType·2 *byte, @\"\".hint·3 int64) (@\"\".hchan·1 chan 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 @\"\".writebarrierptr (@\"\".dst·1 *any, @\"\".src·2 any)\n"
+	"func @\"\".writebarrierstring (@\"\".dst·1 *any, @\"\".src·2 any)\n"
+	"func @\"\".writebarrierslice (@\"\".dst·1 *any, @\"\".src·2 any)\n"
+	"func @\"\".writebarrieriface (@\"\".dst·1 *any, @\"\".src·2 any)\n"
+	"func @\"\".writebarrierfat2 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n"
+	"func @\"\".writebarrierfat3 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n"
+	"func @\"\".writebarrierfat4 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n"
+	"func @\"\".writebarrierfat (@\"\".typ·1 *byte, @\"\".dst·2 *any, @\"\".src·3 *any)\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 (@\"\".sel·1 *byte, @\"\".selsize·2 int64, @\"\".size·3 int32)\n"
+	"func @\"\".selectsend (@\"\".sel·2 *byte, @\"\".hchan·3 chan<- any, @\"\".elem·4 *any) (@\"\".selected·1 bool)\n"
+	"func @\"\".selectrecv (@\"\".sel·2 *byte, @\"\".hchan·3 <-chan any, @\"\".elem·4 *any) (@\"\".selected·1 bool)\n"
+	"func @\"\".selectrecv2 (@\"\".sel·2 *byte, @\"\".hchan·3 <-chan any, @\"\".elem·4 *any, @\"\".received·5 *bool) (@\"\".selected·1 bool)\n"
+	"func @\"\".selectdefault (@\"\".sel·2 *byte) (@\"\".selected·1 bool)\n"
+	"func @\"\".selectgo (@\"\".sel·1 *byte)\n"
+	"func @\"\".block ()\n"
+	"func @\"\".makeslice (@\"\".typ·2 *byte, @\"\".nel·3 int64, @\"\".cap·4 int64) (@\"\".ary·1 []any)\n"
+	"func @\"\".growslice (@\"\".typ·2 *byte, @\"\".old·3 []any, @\"\".n·4 int64) (@\"\".ary·1 []any)\n"
+	"func @\"\".memmove (@\"\".to·1 *any, @\"\".frm·2 *any, @\"\".length·3 uintptr)\n"
+	"func @\"\".memequal (@\"\".x·2 *any, @\"\".y·3 *any, @\"\".size·4 uintptr) (? bool)\n"
+	"func @\"\".memequal8 (@\"\".x·2 *any, @\"\".y·3 *any, @\"\".size·4 uintptr) (? bool)\n"
+	"func @\"\".memequal16 (@\"\".x·2 *any, @\"\".y·3 *any, @\"\".size·4 uintptr) (? bool)\n"
+	"func @\"\".memequal32 (@\"\".x·2 *any, @\"\".y·3 *any, @\"\".size·4 uintptr) (? bool)\n"
+	"func @\"\".memequal64 (@\"\".x·2 *any, @\"\".y·3 *any, @\"\".size·4 uintptr) (? bool)\n"
+	"func @\"\".memequal128 (@\"\".x·2 *any, @\"\".y·3 *any, @\"\".size·4 uintptr) (? bool)\n"
+	"func @\"\".int64div (? int64, ? int64) (? int64)\n"
+	"func @\"\".uint64div (? uint64, ? uint64) (? uint64)\n"
+	"func @\"\".int64mod (? int64, ? int64) (? int64)\n"
+	"func @\"\".uint64mod (? uint64, ? uint64) (? uint64)\n"
+	"func @\"\".float64toint64 (? float64) (? int64)\n"
+	"func @\"\".float64touint64 (? float64) (? uint64)\n"
+	"func @\"\".int64tofloat64 (? int64) (? float64)\n"
+	"func @\"\".uint64tofloat64 (? uint64) (? float64)\n"
+	"func @\"\".complex128div (@\"\".num·2 complex128, @\"\".den·3 complex128) (@\"\".quo·1 complex128)\n"
+	"func @\"\".racefuncenter (? uintptr)\n"
+	"func @\"\".racefuncexit ()\n"
+	"func @\"\".raceread (? uintptr)\n"
+	"func @\"\".racewrite (? uintptr)\n"
+	"func @\"\".racereadrange (@\"\".addr·1 uintptr, @\"\".size·2 uintptr)\n"
+	"func @\"\".racewriterange (@\"\".addr·1 uintptr, @\"\".size·2 uintptr)\n"
+	"\n"
+	"$$\n";
+char *unsafeimport =
+	"package unsafe\n"
+	"import runtime \"runtime\"\n"
+	"type @\"\".Pointer uintptr\n"
+	"func @\"\".Offsetof (? any) (? uintptr)\n"
+	"func @\"\".Sizeof (? any) (? uintptr)\n"
+	"func @\"\".Alignof (? any) (? uintptr)\n"
+	"\n"
+	"$$\n";
diff --git a/src/cmd/gc/bv.c b/src/cmd/gc/bv.c
new file mode 100644
index 0000000..cfd1cd2
--- /dev/null
+++ b/src/cmd/gc/bv.c
@@ -0,0 +1,213 @@
+// 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 {
+	WORDSIZE = sizeof(uint32),
+	WORDBITS = 32,
+	WORDMASK = WORDBITS - 1,
+	WORDSHIFT = 5,
+};
+
+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)
+{
+	Bvec *bv;
+	uintptr nbytes;
+
+	if(n < 0)
+		fatal("bvalloc: initial size is negative\n");
+	nbytes = sizeof(Bvec) + bvsize(n);
+	bv = malloc(nbytes);
+	if(bv == nil)
+		fatal("bvalloc: malloc failed\n");
+	memset(bv, 0, nbytes);
+	bv->n = n;
+	return bv;
+}
+
+/* difference */
+void
+bvandnot(Bvec *dst, Bvec *src1, Bvec *src2)
+{
+	int32 i, w;
+
+	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
+bvcopy(Bvec *dst, Bvec *src)
+{
+	memmove(dst->b, src->b, bvsize(dst->n));
+}
+
+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
+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);
+	return (bv->b[i>>WORDSHIFT] >> (i&WORDMASK)) & 1;
+}
+
+// bvnext returns the smallest index >= i for which bvget(bv, i) == 1.
+// If there is no such index, bvnext returns -1.
+int
+bvnext(Bvec *bv, int32 i)
+{
+	uint32 w;
+
+	if(i >= bv->n)
+		return -1;
+
+	// Jump i ahead to next word with bits.
+	if((bv->b[i>>WORDSHIFT]>>(i&WORDMASK)) == 0) {
+		i &= ~WORDMASK;
+		i += WORDBITS;
+		while(i < bv->n && bv->b[i>>WORDSHIFT] == 0)
+			i += WORDBITS;
+	}
+	if(i >= bv->n)
+		return -1;
+
+	// Find 1 bit.
+	w = bv->b[i>>WORDSHIFT]>>(i&WORDMASK);
+	while((w&1) == 0) {
+		w>>=1;
+		i++;
+	}
+	return i;
+}
+
+int
+bvisempty(Bvec *bv)
+{
+	int32 i;
+
+	for(i = 0; i < bv->n; i += WORDBITS)
+		if(bv->b[i>>WORDSHIFT] != 0)
+			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
new file mode 100644
index 0000000..ad4e5bd
--- /dev/null
+++ b/src/cmd/gc/closure.c
@@ -0,0 +1,467 @@
+// 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.
+
+/*
+ * function literals aka closures
+ */
+
+#include <u.h>
+#include <libc.h>
+#include "go.h"
+
+void
+closurehdr(Node *ntype)
+{
+	Node *n, *name, *a;
+	NodeList *l;
+
+	n = nod(OCLOSURE, N, N);
+	n->ntype = ntype;
+	n->funcdepth = funcdepth;
+
+	funchdr(n);
+
+	// steal ntype's argument names and
+	// leave a fresh copy in their place.
+	// references to these variables need to
+	// refer to the variables in the external
+	// function declared below; see walkclosure.
+	n->list = ntype->list;
+	n->rlist = ntype->rlist;
+	ntype->list = nil;
+	ntype->rlist = nil;
+	for(l=n->list; l; l=l->next) {
+		name = l->n->left;
+		if(name)
+			name = newname(name->sym);
+		a = nod(ODCLFIELD, name, l->n->right);
+		a->isddd = l->n->isddd;
+		if(name)
+			name->isddd = a->isddd;
+		ntype->list = list(ntype->list, a);
+	}
+	for(l=n->rlist; l; l=l->next) {
+		name = l->n->left;
+		if(name)
+			name = newname(name->sym);
+		ntype->rlist = list(ntype->rlist, nod(ODCLFIELD, name, l->n->right));
+	}
+}
+
+Node*
+closurebody(NodeList *body)
+{
+	Node *func, *v;
+	NodeList *l;
+
+	if(body == nil)
+		body = list1(nod(OEMPTY, N, N));
+
+	func = curfn;
+	func->nbody = body;
+	func->endlineno = lineno;
+	funcbody(func);
+
+	// closure-specific variables are hanging off the
+	// ordinary ones in the symbol table; see oldname.
+	// unhook them.
+	// make the list of pointers for the closure call.
+	for(l=func->cvars; l; l=l->next) {
+		v = l->n;
+		v->closure->closure = v->outer;
+		v->heapaddr = nod(OADDR, oldname(v->sym), N);
+	}
+
+	return func;
+}
+
+static Node* makeclosure(Node *func);
+
+void
+typecheckclosure(Node *func, int top)
+{
+	Node *oldfn;
+	NodeList *l;
+	Node *v;
+
+	oldfn = curfn;
+	typecheck(&func->ntype, Etype);
+	func->type = func->ntype->type;
+	
+	// Type check the body now, but only if we're inside a function.
+	// At top level (in a variable initialization: curfn==nil) we're not
+	// ready to type check code yet; we'll check it later, because the
+	// underlying closure function we create is added to xtop.
+	if(curfn && func->type != T) {
+		curfn = func;
+		typechecklist(func->nbody, Etop);
+		curfn = oldfn;
+	}
+
+	// type check the & of closed variables outside the closure,
+	// so that the outer frame also grabs them and knows they
+	// escape.
+	func->enter = nil;
+	for(l=func->cvars; l; l=l->next) {
+		v = l->n;
+		if(v->type == T) {
+			// if v->type is nil, it means v looked like it was
+			// going to be used in the closure but wasn't.
+			// this happens because when parsing a, b, c := f()
+			// the a, b, c gets parsed as references to older
+			// a, b, c before the parser figures out this is a
+			// declaration.
+			v->op = 0;
+			continue;
+		}
+		// For a closure that is called in place, but not
+		// inside a go statement, avoid moving variables to the heap.
+		if ((top & (Ecall|Eproc)) == Ecall)
+			v->heapaddr->etype = 1;
+		typecheck(&v->heapaddr, Erv);
+		func->enter = list(func->enter, v->heapaddr);
+		v->heapaddr = N;
+	}
+
+	// Create top-level function 
+	xtop = list(xtop, makeclosure(func));
+}
+
+static Node*
+makeclosure(Node *func)
+{
+	Node *xtype, *v, *addr, *xfunc, *cv;
+	NodeList *l, *body;
+	static int closgen;
+	char *p;
+	vlong offset;
+
+	/*
+	 * wrap body in external function
+	 * that begins by reading closure parameters.
+	 */
+	xtype = nod(OTFUNC, N, N);
+	xtype->list = func->list;
+	xtype->rlist = func->rlist;
+
+	// create the function
+	xfunc = nod(ODCLFUNC, N, N);
+	snprint(namebuf, sizeof namebuf, "func·%.3d", ++closgen);
+	xfunc->nname = newname(lookup(namebuf));
+	xfunc->nname->sym->flags |= SymExported; // disable export
+	xfunc->nname->ntype = xtype;
+	xfunc->nname->defn = xfunc;
+	declare(xfunc->nname, PFUNC);
+	xfunc->nname->funcdepth = func->funcdepth;
+	xfunc->funcdepth = func->funcdepth;
+	xfunc->endlineno = func->endlineno;
+	
+	// declare variables holding addresses taken from closure
+	// 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)
+			continue;
+		addr = nod(ONAME, N, N);
+		p = smprint("&%s", v->sym->name);
+		addr->sym = lookup(p);
+		free(p);
+		addr->ntype = nod(OIND, typenod(v->type), N);
+		addr->class = PAUTO;
+		addr->addable = 1;
+		addr->ullman = 1;
+		addr->used = 1;
+		addr->curfn = xfunc;
+		xfunc->dcl = list(xfunc->dcl, addr);
+		v->heapaddr = addr;
+		cv = nod(OCLOSUREVAR, N, N);
+		cv->type = ptrto(v->type);
+		cv->xoffset = offset;
+		body = list(body, nod(OAS, addr, cv));
+		offset += widthptr;
+	}
+	typechecklist(body, Etop);
+	walkstmtlist(body);
+	xfunc->enter = body;
+
+	xfunc->nbody = func->nbody;
+	xfunc->dcl = concat(func->dcl, xfunc->dcl);
+	if(xfunc->nbody == nil)
+		fatal("empty body - won't generate any code");
+	typecheck(&xfunc, Etop);
+
+	xfunc->closure = func;
+	func->closure = xfunc;
+	
+	func->nbody = nil;
+	func->list = nil;
+	func->rlist = nil;
+
+	return xfunc;
+}
+
+Node*
+walkclosure(Node *func, NodeList **init)
+{
+	Node *clos, *typ;
+	NodeList *l;
+	char buf[20];
+	int narg;
+
+	// If no closure vars, don't bother wrapping.
+	if(func->cvars == nil)
+		return func->closure->nname;
+
+	// Create closure in the form of a composite literal.
+	// supposing the closure captures an int i and a string s
+	// and has one float64 argument and no results,
+	// the generated code looks like:
+	//
+	//	clos = &struct{F uintptr; A0 *int; A1 *string}{func·001, &i, &s}
+	//
+	// The use of the struct provides type information to the garbage
+	// collector so that it can walk the closure. We could use (in this case)
+	// [3]unsafe.Pointer instead, but that would leave the gc in the dark.
+	// The information appears in the binary in the form of type descriptors;
+	// the struct is unnamed so that closures in multiple packages with the
+	// same struct type can share the descriptor.
+
+	narg = 0;
+	typ = nod(OTSTRUCT, N, N);
+	typ->list = list1(nod(ODCLFIELD, newname(lookup("F")), typenod(types[TUINTPTR])));
+	for(l=func->cvars; l; l=l->next) {
+		if(l->n->op == 0)
+			continue;
+		snprint(buf, sizeof buf, "A%d", narg++);
+		typ->list = list(typ->list, nod(ODCLFIELD, newname(lookup(buf)), l->n->heapaddr->ntype));
+	}
+
+	clos = nod(OCOMPLIT, N, nod(OIND, typ, N));
+	clos->esc = func->esc;
+	clos->right->implicit = 1;
+	clos->list = concat(list1(nod(OCFUNC, func->closure->nname, N)), func->enter);
+
+	// Force type conversion from *struct to the func type.
+	clos = nod(OCONVNOP, clos, N);
+	clos->type = func->type;
+
+	typecheck(&clos, Erv);
+	// 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;
+}
+
+static Node *makepartialcall(Node*, Type*, Node*);
+
+void
+typecheckpartialcall(Node *fn, Node *sym)
+{
+	switch(fn->op) {
+	case ODOTINTER:
+	case ODOTMETH:
+		break;
+	default:
+		fatal("invalid typecheckpartialcall");
+	}
+
+	// Create top-level function.
+	fn->nname = makepartialcall(fn, fn->type, sym);
+	fn->right = sym;
+	fn->op = OCALLPART;
+	fn->type = fn->nname->type;
+}
+
+static Node*
+makepartialcall(Node *fn, Type *t0, Node *meth)
+{
+	Node *ptr, *n, *fld, *call, *xtype, *xfunc, *cv, *savecurfn;
+	Type *rcvrtype, *basetype, *t;
+	NodeList *body, *l, *callargs, *retargs;
+	char *p;
+	Sym *sym;
+	Pkg *spkg;
+	static Pkg* gopkg;
+	int i, ddd;
+
+	// TODO: names are not right
+	rcvrtype = fn->left->type;
+	if(exportname(meth->sym->name))
+		p = smprint("%-hT.%s·fm", rcvrtype, meth->sym->name);
+	else
+		p = smprint("%-hT.(%-S)·fm", rcvrtype, meth->sym);
+	basetype = rcvrtype;
+	if(isptr[rcvrtype->etype])
+		basetype = basetype->type;
+	if(basetype->etype != TINTER && basetype->sym == S)
+		fatal("missing base type for %T", rcvrtype);
+
+	spkg = nil;
+	if(basetype->sym != S)
+		spkg = basetype->sym->pkg;
+	if(spkg == nil) {
+		if(gopkg == nil)
+			gopkg = mkpkg(strlit("go"));
+		spkg = gopkg;
+	}
+	sym = pkglookup(p, spkg);
+	free(p);
+	if(sym->flags & SymUniq)
+		return sym->def;
+	sym->flags |= SymUniq;
+	
+	savecurfn = curfn;
+	curfn = N;
+
+	xtype = nod(OTFUNC, N, N);
+	i = 0;
+	l = nil;
+	callargs = nil;
+	ddd = 0;
+	xfunc = nod(ODCLFUNC, N, N);
+	curfn = xfunc;
+	for(t = getinargx(t0)->type; t; t = t->down) {
+		snprint(namebuf, sizeof namebuf, "a%d", i++);
+		n = newname(lookup(namebuf));
+		n->class = PPARAM;
+		xfunc->dcl = list(xfunc->dcl, n);
+		callargs = list(callargs, n);
+		fld = nod(ODCLFIELD, n, typenod(t->type));
+		if(t->isddd) {
+			fld->isddd = 1;
+			ddd = 1;
+		}
+		l = list(l, fld);
+	}
+	xtype->list = l;
+	i = 0;
+	l = nil;
+	retargs = nil;
+	for(t = getoutargx(t0)->type; t; t = t->down) {
+		snprint(namebuf, sizeof namebuf, "r%d", i++);
+		n = newname(lookup(namebuf));
+		n->class = PPARAMOUT;
+		xfunc->dcl = list(xfunc->dcl, n);
+		retargs = list(retargs, n);
+		l = list(l, nod(ODCLFIELD, n, typenod(t->type)));
+	}
+	xtype->rlist = l;
+
+	xfunc->dupok = 1;
+	xfunc->nname = newname(sym);
+	xfunc->nname->sym->flags |= SymExported; // disable export
+	xfunc->nname->ntype = xtype;
+	xfunc->nname->defn = xfunc;
+	declare(xfunc->nname, PFUNC);
+
+	// 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;
+	ptr->addable = 1;
+	ptr->ullman = 1;
+	ptr->used = 1;
+	ptr->curfn = xfunc;
+	xfunc->dcl = list(xfunc->dcl, ptr);
+	if(isptr[rcvrtype->etype] || isinter(rcvrtype)) {
+		ptr->ntype = typenod(rcvrtype);
+		body = list(body, nod(OAS, ptr, cv));
+	} else {
+		ptr->ntype = typenod(ptrto(rcvrtype));
+		body = list(body, nod(OAS, ptr, nod(OADDR, cv, N)));
+	}
+
+	call = nod(OCALL, nod(OXDOT, ptr, meth), N);
+	call->list = callargs;
+	call->isddd = ddd;
+	if(t0->outtuple == 0) {
+		body = list(body, call);
+	} else {
+		n = nod(OAS2, N, N);
+		n->list = retargs;
+		n->rlist = list1(call);
+		body = list(body, n);
+		n = nod(ORETURN, N, N);
+		body = list(body, n);
+	}
+
+	xfunc->nbody = body;
+
+	typecheck(&xfunc, Etop);
+	sym->def = xfunc;
+	xtop = list(xtop, xfunc);
+	curfn = savecurfn;
+
+	return xfunc;
+}
+
+Node*
+walkpartialcall(Node *n, NodeList **init)
+{
+	Node *clos, *typ;
+
+	// Create closure in the form of a composite literal.
+	// For x.M with receiver (x) type T, the generated code looks like:
+	//
+	//	clos = &struct{F uintptr; R T}{M.T·f, x}
+	//
+	// Like walkclosure above.
+
+	if(isinter(n->left->type)) {
+		// Trigger panic for method on nil interface now.
+		// Otherwise it happens in the wrapper and is confusing.
+		n->left = cheapexpr(n->left, init);
+		checknil(n->left, init);
+	}
+
+	typ = nod(OTSTRUCT, N, N);
+	typ->list = list1(nod(ODCLFIELD, newname(lookup("F")), typenod(types[TUINTPTR])));
+	typ->list = list(typ->list, nod(ODCLFIELD, newname(lookup("R")), typenod(n->left->type)));
+
+	clos = nod(OCOMPLIT, N, nod(OIND, typ, N));
+	clos->esc = n->esc;
+	clos->right->implicit = 1;
+	clos->list = list1(nod(OCFUNC, n->nname->nname, N));
+	clos->list = list(clos->list, n->left);
+
+	// Force type conversion from *struct to the func type.
+	clos = nod(OCONVNOP, clos, N);
+	clos->type = n->type;
+
+	typecheck(&clos, Erv);
+	// 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
new file mode 100644
index 0000000..e418b9c
--- /dev/null
+++ b/src/cmd/gc/const.c
@@ -0,0 +1,1674 @@
+// 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	"go.h"
+#define	TUP(x,y)	(((x)<<16)|(y))
+/*c2go int TUP(int, int); */
+
+static	Val	tocplx(Val);
+static	Val	toflt(Val);
+static	Val	tostr(Val);
+static	Val	copyval(Val);
+static	void	cmplxmpy(Mpcplx*, Mpcplx*);
+static	void	cmplxdiv(Mpcplx*, Mpcplx*);
+
+/*
+ * truncate float literal fv to 32-bit or 64-bit precision
+ * according to type; return truncated value.
+ */
+Mpflt*
+truncfltlit(Mpflt *oldv, Type *t)
+{
+	double d;
+	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)
+	switch(t->etype) {
+	case TFLOAT64:
+		d = mpgetflt(fv);
+		mpmovecflt(fv, d);
+		break;
+
+	case TFLOAT32:
+		d = mpgetflt32(fv);
+		mpmovecflt(fv, d);
+
+		break;
+	}
+	return fv;
+}
+
+/*
+ * convert n, if literal, to type t.
+ * implicit conversion.
+ */
+void
+convlit(Node **np, Type *t)
+{
+	convlit1(np, t, 0);
+}
+
+/*
+ * convert n, if literal, to type t.
+ * return a new node if necessary
+ * (if n is a named constant, can't edit n->type directly).
+ */
+void
+convlit1(Node **np, Type *t, int explicit)
+{
+	int ct, et;
+	Node *n, *nn;
+
+	n = *np;
+	if(n == N || t == T || n->type == T || isideal(t) || n->type == t)
+		return;
+	if(!explicit && !isideal(n->type))
+		return;
+
+	if(n->op == OLITERAL) {
+		nn = nod(OXXX, N, N);
+		*nn = *n;
+		n = nn;
+		*np = n;
+	}
+
+	switch(n->op) {
+	default:
+		if(n->type == idealbool) {
+			if(t->etype == TBOOL)
+				n->type = t;
+			else
+				n->type = types[TBOOL];
+		}
+		if(n->type->etype == TIDEAL) {
+			convlit(&n->left, t);
+			convlit(&n->right, t);
+			n->type = t;
+		}
+		return;
+	case OLITERAL:
+		// target is invalid type for a constant?  leave alone.
+		if(!okforconst[t->etype] && n->type->etype != TNIL) {
+			defaultlit(&n, T);
+			*np = n;
+			return;
+		}
+		break;
+	case OLSH:
+	case ORSH:
+		convlit1(&n->left, t, explicit && isideal(n->left->type));
+		t = n->left->type;
+		if(t != T && t->etype == TIDEAL && n->val.ctype != CTINT)
+			n->val = toint(n->val);
+		if(t != T && !isint[t->etype]) {
+			yyerror("invalid operation: %N (shift of type %T)", n, t);
+			t = T;
+		}
+		n->type = t;
+		return;
+	case OCOMPLEX:
+		if(n->type->etype == TIDEAL) {
+			switch(t->etype) {
+			default:
+				// If trying to convert to non-complex type,
+				// leave as complex128 and let typechecker complain.
+				t = types[TCOMPLEX128];
+				//fallthrough
+			case TCOMPLEX128:
+				n->type = t;
+				convlit(&n->left, types[TFLOAT64]);
+				convlit(&n->right, types[TFLOAT64]);
+				break;
+			case TCOMPLEX64:
+				n->type = t;
+				convlit(&n->left, types[TFLOAT32]);
+				convlit(&n->right, types[TFLOAT32]);
+				break;
+			}
+		}
+		return;
+	}
+
+	// avoided repeated calculations, errors
+	if(eqtype(n->type, t))
+		return;
+
+	ct = consttype(n);
+	if(ct < 0)
+		goto bad;
+
+	et = t->etype;
+	if(et == TINTER) {
+		if(ct == CTNIL && n->type == types[TNIL]) {
+			n->type = t;
+			return;
+		}
+		defaultlit(np, T);
+		return;
+	}
+
+	switch(ct) {
+	default:
+		goto bad;
+
+	case CTNIL:
+		switch(et) {
+		default:
+			n->type = T;
+			goto bad;
+
+		case TSTRING:
+			// let normal conversion code handle it
+			return;
+
+		case TARRAY:
+			if(!isslice(t))
+				goto bad;
+			break;
+
+		case TPTR32:
+		case TPTR64:
+		case TINTER:
+		case TMAP:
+		case TCHAN:
+		case TFUNC:
+		case TUNSAFEPTR:
+			break;
+
+		case TUINTPTR:
+			// A nil literal may be converted to uintptr
+			// if it is an unsafe.Pointer
+			if(n->type->etype == TUNSAFEPTR) {
+				n->val.u.xval = mal(sizeof(*n->val.u.xval));
+				mpmovecfix(n->val.u.xval, 0);
+				n->val.ctype = CTINT;
+			} else
+				goto bad;
+		}
+		break;
+
+	case CTSTR:
+	case CTBOOL:
+		if(et != n->type->etype)
+			goto bad;
+		break;
+
+	case CTINT:
+	case CTRUNE:
+	case CTFLT:
+	case CTCPLX:
+		ct = n->val.ctype;
+		if(isint[et]) {
+			switch(ct) {
+			default:
+				goto bad;
+			case CTCPLX:
+			case CTFLT:
+			case CTRUNE:
+				n->val = toint(n->val);
+				// flowthrough
+			case CTINT:
+				overflow(n->val, t);
+				break;
+			}
+		} else
+		if(isfloat[et]) {
+			switch(ct) {
+			default:
+				goto bad;
+			case CTCPLX:
+			case CTINT:
+			case CTRUNE:
+				n->val = toflt(n->val);
+				// flowthrough
+			case CTFLT:
+				n->val.u.fval = truncfltlit(n->val.u.fval, t);
+				break;
+			}
+		} else
+		if(iscomplex[et]) {
+			switch(ct) {
+			default:
+				goto bad;
+			case CTFLT:
+			case CTINT:
+			case CTRUNE:
+				n->val = tocplx(n->val);
+				break;
+			case CTCPLX:
+				overflow(n->val, t);
+				break;
+			}
+		} else
+		if(et == TSTRING && (ct == CTINT || ct == CTRUNE) && explicit)
+			n->val = tostr(n->val);
+		else
+			goto bad;
+		break;
+	}
+	n->type = t;
+	return;
+
+bad:
+	if(!n->diag) {
+		if(!t->broke)
+			yyerror("cannot convert %N to type %T", n, t);
+		n->diag = 1;
+	}
+	if(isideal(n->type)) {
+		defaultlit(&n, T);
+		*np = n;
+	}
+	return;
+}
+
+static Val
+copyval(Val v)
+{
+	Mpint *i;
+	Mpflt *f;
+	Mpcplx *c;
+
+	switch(v.ctype) {
+	case CTINT:
+	case CTRUNE:
+		i = mal(sizeof(*i));
+		mpmovefixfix(i, v.u.xval);
+		v.u.xval = i;
+		break;
+	case CTFLT:
+		f = mal(sizeof(*f));
+		mpmovefltflt(f, v.u.fval);
+		v.u.fval = f;
+		break;
+	case CTCPLX:
+		c = mal(sizeof(*c));
+		mpmovefltflt(&c->real, &v.u.cval->real);
+		mpmovefltflt(&c->imag, &v.u.cval->imag);
+		v.u.cval = c;
+		break;
+	}
+	return v;
+}
+
+static Val
+tocplx(Val v)
+{
+	Mpcplx *c;
+
+	switch(v.ctype) {
+	case CTINT:
+	case CTRUNE:
+		c = mal(sizeof(*c));
+		mpmovefixflt(&c->real, v.u.xval);
+		mpmovecflt(&c->imag, 0.0);
+		v.ctype = CTCPLX;
+		v.u.cval = c;
+		break;
+	case CTFLT:
+		c = mal(sizeof(*c));
+		mpmovefltflt(&c->real, v.u.fval);
+		mpmovecflt(&c->imag, 0.0);
+		v.ctype = CTCPLX;
+		v.u.cval = c;
+		break;
+	}
+	return v;
+}
+
+static Val
+toflt(Val v)
+{
+	Mpflt *f;
+
+	switch(v.ctype) {
+	case CTINT:
+	case CTRUNE:
+		f = mal(sizeof(*f));
+		mpmovefixflt(f, v.u.xval);
+		v.ctype = CTFLT;
+		v.u.fval = f;
+		break;
+	case CTCPLX:
+		f = mal(sizeof(*f));
+		mpmovefltflt(f, &v.u.cval->real);
+		if(mpcmpfltc(&v.u.cval->imag, 0) != 0)
+			yyerror("constant %#F%+#Fi truncated to real", &v.u.cval->real, &v.u.cval->imag);
+		v.ctype = CTFLT;
+		v.u.fval = f;
+		break;
+	}
+	return v;
+}
+
+Val
+toint(Val v)
+{
+	Mpint *i;
+
+	switch(v.ctype) {
+	case CTRUNE:
+		v.ctype = CTINT;
+		break;
+	case CTFLT:
+		i = mal(sizeof(*i));
+		if(mpmovefltfix(i, v.u.fval) < 0)
+			yyerror("constant %#F truncated to integer", v.u.fval);
+		v.ctype = CTINT;
+		v.u.xval = i;
+		break;
+	case CTCPLX:
+		i = mal(sizeof(*i));
+		if(mpmovefltfix(i, &v.u.cval->real) < 0)
+			yyerror("constant %#F%+#Fi truncated to integer", &v.u.cval->real, &v.u.cval->imag);
+		if(mpcmpfltc(&v.u.cval->imag, 0) != 0)
+			yyerror("constant %#F%+#Fi truncated to real", &v.u.cval->real, &v.u.cval->imag);
+		v.ctype = CTINT;
+		v.u.xval = i;
+		break;
+	}
+	return v;
+}
+
+int
+doesoverflow(Val v, Type *t)
+{
+	switch(v.ctype) {
+	case CTINT:
+	case CTRUNE:
+		if(!isint[t->etype])
+			fatal("overflow: %T integer constant", t);
+		if(mpcmpfixfix(v.u.xval, minintval[t->etype]) < 0 ||
+		   mpcmpfixfix(v.u.xval, maxintval[t->etype]) > 0)
+			return 1;
+		break;
+	case CTFLT:
+		if(!isfloat[t->etype])
+			fatal("overflow: %T floating-point constant", t);
+		if(mpcmpfltflt(v.u.fval, minfltval[t->etype]) <= 0 ||
+		   mpcmpfltflt(v.u.fval, maxfltval[t->etype]) >= 0)
+			return 1;
+		break;
+	case CTCPLX:
+		if(!iscomplex[t->etype])
+			fatal("overflow: %T complex constant", t);
+		if(mpcmpfltflt(&v.u.cval->real, minfltval[t->etype]) <= 0 ||
+		   mpcmpfltflt(&v.u.cval->real, maxfltval[t->etype]) >= 0 ||
+		   mpcmpfltflt(&v.u.cval->imag, minfltval[t->etype]) <= 0 ||
+		   mpcmpfltflt(&v.u.cval->imag, maxfltval[t->etype]) >= 0)
+			return 1;
+		break;
+	}
+	return 0;
+}
+
+void
+overflow(Val v, Type *t)
+{
+	// v has already been converted
+	// to appropriate form for t.
+	if(t == T || t->etype == TIDEAL)
+		return;
+
+	if(!doesoverflow(v, t))
+		return;
+
+	switch(v.ctype) {
+	case CTINT:
+	case CTRUNE:
+		yyerror("constant %B overflows %T", v.u.xval, t);
+		break;
+	case CTFLT:
+		yyerror("constant %#F overflows %T", v.u.fval, t);
+		break;
+	case CTCPLX:
+		yyerror("constant %#F overflows %T", v.u.fval, t);
+		break;
+	}
+}
+
+static Val
+tostr(Val v)
+{
+	Rune rune;
+	int l;
+	Strlit *s;
+
+	switch(v.ctype) {
+	case CTINT:
+	case CTRUNE:
+		if(mpcmpfixfix(v.u.xval, minintval[TINT]) < 0 ||
+		   mpcmpfixfix(v.u.xval, maxintval[TINT]) > 0)
+			yyerror("overflow in int -> string");
+		rune = mpgetfix(v.u.xval);
+		l = runelen(rune);
+		s = mal(sizeof(*s)+l);
+		s->len = l;
+		runetochar((char*)s->s, &rune);
+		memset(&v, 0, sizeof v);
+		v.ctype = CTSTR;
+		v.u.sval = s;
+		break;
+
+	case CTFLT:
+		yyerror("no float -> string");
+
+	case CTNIL:
+		memset(&v, 0, sizeof v);
+		v.ctype = CTSTR;
+		v.u.sval = mal(sizeof *s);
+		break;
+	}
+	return v;
+}
+
+int
+consttype(Node *n)
+{
+	if(n == N || n->op != OLITERAL)
+		return -1;
+	return n->val.ctype;
+}
+
+int
+isconst(Node *n, int ct)
+{
+	int t;
+	
+	t = consttype(n);
+	// If the caller is asking for CTINT, allow CTRUNE too.
+	// Makes life easier for back ends.
+	return t == ct || (ct == CTINT && t == CTRUNE);
+}
+
+static Node*
+saveorig(Node *n)
+{
+	Node *n1;
+
+	if(n == n->orig) {
+		// duplicate node for n->orig.
+		n1 = nod(OLITERAL, N, N);
+		n->orig = n1;
+		*n1 = *n;
+	}
+	return n->orig;
+}
+
+/*
+ * if n is constant, rewrite as OLITERAL node.
+ */
+void
+evconst(Node *n)
+{
+	Node *nl, *nr, *norig;
+	int32 len;
+	Strlit *str;
+	int wl, wr, lno, et;
+	Val v, rv;
+	Mpint b;
+	NodeList *l1, *l2;
+
+	// pick off just the opcodes that can be
+	// constant evaluated.
+	switch(n->op) {
+	default:
+		return;
+	case OADD:
+	case OAND:
+	case OANDAND:
+	case OANDNOT:
+	case OARRAYBYTESTR:
+	case OCOM:
+	case ODIV:
+	case OEQ:
+	case OGE:
+	case OGT:
+	case OLE:
+	case OLSH:
+	case OLT:
+	case OMINUS:
+	case OMOD:
+	case OMUL:
+	case ONE:
+	case ONOT:
+	case OOR:
+	case OOROR:
+	case OPLUS:
+	case ORSH:
+	case OSUB:
+	case OXOR:
+		break;
+	case OCONV:
+		if(n->type == T)
+			return;
+		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;
+	if(nl == N || nl->type == T)
+		return;
+	if(consttype(nl) < 0)
+		return;
+	wl = nl->type->etype;
+	if(isint[wl] || isfloat[wl] || iscomplex[wl])
+		wl = TIDEAL;
+
+	nr = n->right;
+	if(nr == N)
+		goto unary;
+	if(nr->type == T)
+		return;
+	if(consttype(nr) < 0)
+		return;
+	wr = nr->type->etype;
+	if(isint[wr] || isfloat[wr] || iscomplex[wr])
+		wr = TIDEAL;
+
+	// check for compatible general types (numeric, string, etc)
+	if(wl != wr)
+		goto illegal;
+
+	// check for compatible types.
+	switch(n->op) {
+	default:
+		// ideal const mixes with anything but otherwise must match.
+		if(nl->type->etype != TIDEAL) {
+			defaultlit(&nr, nl->type);
+			n->right = nr;
+		}
+		if(nr->type->etype != TIDEAL) {
+			defaultlit(&nl, nr->type);
+			n->left = nl;
+		}
+		if(nl->type->etype != nr->type->etype)
+			goto illegal;
+		break;
+
+	case OLSH:
+	case ORSH:
+		// right must be unsigned.
+		// left can be ideal.
+		defaultlit(&nr, types[TUINT]);
+		n->right = nr;
+		if(nr->type && (issigned[nr->type->etype] || !isint[nr->type->etype]))
+			goto illegal;
+		if(nl->val.ctype != CTRUNE)
+			nl->val = toint(nl->val);
+		nr->val = toint(nr->val);
+		break;
+	}
+
+	// copy numeric value to avoid modifying
+	// n->left, in case someone still refers to it (e.g. iota).
+	v = nl->val;
+	if(wl == TIDEAL)
+		v = copyval(v);
+
+	rv = nr->val;
+
+	// convert to common ideal
+	if(v.ctype == CTCPLX || rv.ctype == CTCPLX) {
+		v = tocplx(v);
+		rv = tocplx(rv);
+	}
+	if(v.ctype == CTFLT || rv.ctype == CTFLT) {
+		v = toflt(v);
+		rv = toflt(rv);
+	}
+
+	// Rune and int turns into rune.
+	if(v.ctype == CTRUNE && rv.ctype == CTINT)
+		rv.ctype = CTRUNE;
+	if(v.ctype == CTINT && rv.ctype == CTRUNE) {
+		if(n->op == OLSH || n->op == ORSH)
+			rv.ctype = CTINT;
+		else
+			v.ctype = CTRUNE;
+	}
+
+	if(v.ctype != rv.ctype) {
+		// Use of undefined name as constant?
+		if((v.ctype == 0 || rv.ctype == 0) && nerrors > 0)
+			return;
+		fatal("constant type mismatch %T(%d) %T(%d)", nl->type, v.ctype, nr->type, rv.ctype);
+	}
+
+	// run op
+	switch(TUP(n->op, v.ctype)) {
+	default:
+	illegal:
+		if(!n->diag) {
+			yyerror("illegal constant expression: %T %O %T",
+				nl->type, n->op, nr->type);
+			n->diag = 1;
+		}
+		return;
+
+	case TUP(OADD, CTINT):
+	case TUP(OADD, CTRUNE):
+		mpaddfixfix(v.u.xval, rv.u.xval, 0);
+		break;
+	case TUP(OSUB, CTINT):
+	case TUP(OSUB, CTRUNE):
+		mpsubfixfix(v.u.xval, rv.u.xval);
+		break;
+	case TUP(OMUL, CTINT):
+	case TUP(OMUL, CTRUNE):
+		mpmulfixfix(v.u.xval, rv.u.xval);
+		break;
+	case TUP(ODIV, CTINT):
+	case TUP(ODIV, CTRUNE):
+		if(mpcmpfixc(rv.u.xval, 0) == 0) {
+			yyerror("division by zero");
+			mpmovecfix(v.u.xval, 1);
+			break;
+		}
+		mpdivfixfix(v.u.xval, rv.u.xval);
+		break;
+	case TUP(OMOD, CTINT):
+	case TUP(OMOD, CTRUNE):
+		if(mpcmpfixc(rv.u.xval, 0) == 0) {
+			yyerror("division by zero");
+			mpmovecfix(v.u.xval, 1);
+			break;
+		}
+		mpmodfixfix(v.u.xval, rv.u.xval);
+		break;
+
+	case TUP(OLSH, CTINT):
+	case TUP(OLSH, CTRUNE):
+		mplshfixfix(v.u.xval, rv.u.xval);
+		break;
+	case TUP(ORSH, CTINT):
+	case TUP(ORSH, CTRUNE):
+		mprshfixfix(v.u.xval, rv.u.xval);
+		break;
+	case TUP(OOR, CTINT):
+	case TUP(OOR, CTRUNE):
+		mporfixfix(v.u.xval, rv.u.xval);
+		break;
+	case TUP(OAND, CTINT):
+	case TUP(OAND, CTRUNE):
+		mpandfixfix(v.u.xval, rv.u.xval);
+		break;
+	case TUP(OANDNOT, CTINT):
+	case TUP(OANDNOT, CTRUNE):
+		mpandnotfixfix(v.u.xval, rv.u.xval);
+		break;
+	case TUP(OXOR, CTINT):
+	case TUP(OXOR, CTRUNE):
+		mpxorfixfix(v.u.xval, rv.u.xval);
+		break;
+
+	case TUP(OADD, CTFLT):
+		mpaddfltflt(v.u.fval, rv.u.fval);
+		break;
+	case TUP(OSUB, CTFLT):
+		mpsubfltflt(v.u.fval, rv.u.fval);
+		break;
+	case TUP(OMUL, CTFLT):
+		mpmulfltflt(v.u.fval, rv.u.fval);
+		break;
+	case TUP(ODIV, CTFLT):
+		if(mpcmpfltc(rv.u.fval, 0) == 0) {
+			yyerror("division by zero");
+			mpmovecflt(v.u.fval, 1.0);
+			break;
+		}
+		mpdivfltflt(v.u.fval, rv.u.fval);
+		break;
+	case TUP(OMOD, CTFLT):
+		// The default case above would print 'ideal % ideal',
+		// which is not quite an ideal error.
+		if(!n->diag) {
+			yyerror("illegal constant expression: floating-point %% operation");
+			n->diag = 1;
+		}
+		return;
+
+	case TUP(OADD, CTCPLX):
+		mpaddfltflt(&v.u.cval->real, &rv.u.cval->real);
+		mpaddfltflt(&v.u.cval->imag, &rv.u.cval->imag);
+		break;
+	case TUP(OSUB, CTCPLX):
+		mpsubfltflt(&v.u.cval->real, &rv.u.cval->real);
+		mpsubfltflt(&v.u.cval->imag, &rv.u.cval->imag);
+		break;
+	case TUP(OMUL, CTCPLX):
+		cmplxmpy(v.u.cval, rv.u.cval);
+		break;
+	case TUP(ODIV, CTCPLX):
+		if(mpcmpfltc(&rv.u.cval->real, 0) == 0 &&
+		   mpcmpfltc(&rv.u.cval->imag, 0) == 0) {
+			yyerror("complex division by zero");
+			mpmovecflt(&rv.u.cval->real, 1.0);
+			mpmovecflt(&rv.u.cval->imag, 0.0);
+			break;
+		}
+		cmplxdiv(v.u.cval, rv.u.cval);
+		break;
+
+	case TUP(OEQ, CTNIL):
+		goto settrue;
+	case TUP(ONE, CTNIL):
+		goto setfalse;
+
+	case TUP(OEQ, CTINT):
+	case TUP(OEQ, CTRUNE):
+		if(mpcmpfixfix(v.u.xval, rv.u.xval) == 0)
+			goto settrue;
+		goto setfalse;
+	case TUP(ONE, CTINT):
+	case TUP(ONE, CTRUNE):
+		if(mpcmpfixfix(v.u.xval, rv.u.xval) != 0)
+			goto settrue;
+		goto setfalse;
+	case TUP(OLT, CTINT):
+	case TUP(OLT, CTRUNE):
+		if(mpcmpfixfix(v.u.xval, rv.u.xval) < 0)
+			goto settrue;
+		goto setfalse;
+	case TUP(OLE, CTINT):
+	case TUP(OLE, CTRUNE):
+		if(mpcmpfixfix(v.u.xval, rv.u.xval) <= 0)
+			goto settrue;
+		goto setfalse;
+	case TUP(OGE, CTINT):
+	case TUP(OGE, CTRUNE):
+		if(mpcmpfixfix(v.u.xval, rv.u.xval) >= 0)
+			goto settrue;
+		goto setfalse;
+	case TUP(OGT, CTINT):
+	case TUP(OGT, CTRUNE):
+		if(mpcmpfixfix(v.u.xval, rv.u.xval) > 0)
+			goto settrue;
+		goto setfalse;
+
+	case TUP(OEQ, CTFLT):
+		if(mpcmpfltflt(v.u.fval, rv.u.fval) == 0)
+			goto settrue;
+		goto setfalse;
+	case TUP(ONE, CTFLT):
+		if(mpcmpfltflt(v.u.fval, rv.u.fval) != 0)
+			goto settrue;
+		goto setfalse;
+	case TUP(OLT, CTFLT):
+		if(mpcmpfltflt(v.u.fval, rv.u.fval) < 0)
+			goto settrue;
+		goto setfalse;
+	case TUP(OLE, CTFLT):
+		if(mpcmpfltflt(v.u.fval, rv.u.fval) <= 0)
+			goto settrue;
+		goto setfalse;
+	case TUP(OGE, CTFLT):
+		if(mpcmpfltflt(v.u.fval, rv.u.fval) >= 0)
+			goto settrue;
+		goto setfalse;
+	case TUP(OGT, CTFLT):
+		if(mpcmpfltflt(v.u.fval, rv.u.fval) > 0)
+			goto settrue;
+		goto setfalse;
+
+	case TUP(OEQ, CTCPLX):
+		if(mpcmpfltflt(&v.u.cval->real, &rv.u.cval->real) == 0 &&
+		   mpcmpfltflt(&v.u.cval->imag, &rv.u.cval->imag) == 0)
+			goto settrue;
+		goto setfalse;
+	case TUP(ONE, CTCPLX):
+		if(mpcmpfltflt(&v.u.cval->real, &rv.u.cval->real) != 0 ||
+		   mpcmpfltflt(&v.u.cval->imag, &rv.u.cval->imag) != 0)
+			goto settrue;
+		goto setfalse;
+
+	case TUP(OEQ, CTSTR):
+		if(cmpslit(nl, nr) == 0)
+			goto settrue;
+		goto setfalse;
+	case TUP(ONE, CTSTR):
+		if(cmpslit(nl, nr) != 0)
+			goto settrue;
+		goto setfalse;
+	case TUP(OLT, CTSTR):
+		if(cmpslit(nl, nr) < 0)
+			goto settrue;
+		goto setfalse;
+	case TUP(OLE, CTSTR):
+		if(cmpslit(nl, nr) <= 0)
+			goto settrue;
+		goto setfalse;
+	case TUP(OGE, CTSTR):
+		if(cmpslit(nl, nr) >= 0l)
+			goto settrue;
+		goto setfalse;
+	case TUP(OGT, CTSTR):
+		if(cmpslit(nl, nr) > 0)
+			goto settrue;
+		goto setfalse;
+
+	case TUP(OOROR, CTBOOL):
+		if(v.u.bval || rv.u.bval)
+			goto settrue;
+		goto setfalse;
+	case TUP(OANDAND, CTBOOL):
+		if(v.u.bval && rv.u.bval)
+			goto settrue;
+		goto setfalse;
+	case TUP(OEQ, CTBOOL):
+		if(v.u.bval == rv.u.bval)
+			goto settrue;
+		goto setfalse;
+	case TUP(ONE, CTBOOL):
+		if(v.u.bval != rv.u.bval)
+			goto settrue;
+		goto setfalse;
+	}
+	goto ret;
+
+unary:
+	// copy numeric value to avoid modifying
+	// nl, in case someone still refers to it (e.g. iota).
+	v = nl->val;
+	if(wl == TIDEAL)
+		v = copyval(v);
+
+	switch(TUP(n->op, v.ctype)) {
+	default:
+		if(!n->diag) {
+			yyerror("illegal constant expression %O %T", n->op, nl->type);
+			n->diag = 1;
+		}
+		return;
+
+	case TUP(OCONV, CTNIL):
+	case TUP(OARRAYBYTESTR, CTNIL):
+		if(n->type->etype == TSTRING) {
+			v = tostr(v);
+			nl->type = n->type;
+			break;
+		}
+		// fall through
+	case TUP(OCONV, CTINT):
+	case TUP(OCONV, CTRUNE):
+	case TUP(OCONV, CTFLT):
+	case TUP(OCONV, CTSTR):
+		convlit1(&nl, n->type, 1);
+		v = nl->val;
+		break;
+
+	case TUP(OPLUS, CTINT):
+	case TUP(OPLUS, CTRUNE):
+		break;
+	case TUP(OMINUS, CTINT):
+	case TUP(OMINUS, CTRUNE):
+		mpnegfix(v.u.xval);
+		break;
+	case TUP(OCOM, CTINT):
+	case TUP(OCOM, CTRUNE):
+		et = Txxx;
+		if(nl->type != T)
+			et = nl->type->etype;
+
+		// calculate the mask in b
+		// result will be (a ^ mask)
+		switch(et) {
+		default:
+			// signed guys change sign
+			mpmovecfix(&b, -1);
+			break;
+
+		case TUINT8:
+		case TUINT16:
+		case TUINT32:
+		case TUINT64:
+		case TUINT:
+		case TUINTPTR:
+			// unsigned guys invert their bits
+			mpmovefixfix(&b, maxintval[et]);
+			break;
+		}
+		mpxorfixfix(v.u.xval, &b);
+		break;
+
+	case TUP(OPLUS, CTFLT):
+		break;
+	case TUP(OMINUS, CTFLT):
+		mpnegflt(v.u.fval);
+		break;
+
+	case TUP(OPLUS, CTCPLX):
+		break;
+	case TUP(OMINUS, CTCPLX):
+		mpnegflt(&v.u.cval->real);
+		mpnegflt(&v.u.cval->imag);
+		break;
+
+	case TUP(ONOT, CTBOOL):
+		if(!v.u.bval)
+			goto settrue;
+		goto setfalse;
+	}
+
+ret:
+	norig = saveorig(n);
+	*n = *nl;
+	// restore value of n->orig.
+	n->orig = norig;
+	n->val = v;
+
+	// check range.
+	lno = setlineno(n);
+	overflow(v, n->type);
+	lineno = lno;
+
+	// truncate precision for non-ideal float.
+	if(v.ctype == CTFLT && n->type->etype != TIDEAL)
+		n->val.u.fval = truncfltlit(v.u.fval, n->type);
+	return;
+
+settrue:
+	norig = saveorig(n);
+	*n = *nodbool(1);
+	n->orig = norig;
+	return;
+
+setfalse:
+	norig = saveorig(n);
+	*n = *nodbool(0);
+	n->orig = norig;
+	return;
+}
+
+Node*
+nodlit(Val v)
+{
+	Node *n;
+
+	n = nod(OLITERAL, N, N);
+	n->val = v;
+	switch(v.ctype) {
+	default:
+		fatal("nodlit ctype %d", v.ctype);
+	case CTSTR:
+		n->type = idealstring;
+		break;
+	case CTBOOL:
+		n->type = idealbool;
+		break;
+	case CTINT:
+	case CTRUNE:
+	case CTFLT:
+	case CTCPLX:
+		n->type = types[TIDEAL];
+		break;
+	case CTNIL:
+		n->type = types[TNIL];
+		break;
+	}
+	return n;
+}
+
+Node*
+nodcplxlit(Val r, Val i)
+{
+	Node *n;
+	Mpcplx *c;
+
+	r = toflt(r);
+	i = toflt(i);
+
+	c = mal(sizeof(*c));
+	n = nod(OLITERAL, N, N);
+	n->type = types[TIDEAL];
+	n->val.u.cval = c;
+	n->val.ctype = CTCPLX;
+
+	if(r.ctype != CTFLT || i.ctype != CTFLT)
+		fatal("nodcplxlit ctype %d/%d", r.ctype, i.ctype);
+
+	mpmovefltflt(&c->real, r.u.fval);
+	mpmovefltflt(&c->imag, i.u.fval);
+	return n;
+}
+
+// idealkind returns a constant kind like consttype
+// but for an arbitrary "ideal" (untyped constant) expression.
+static int
+idealkind(Node *n)
+{
+	int k1, k2;
+
+	if(n == N || !isideal(n->type))
+		return CTxxx;
+
+	switch(n->op) {
+	default:
+		return CTxxx;
+	case OLITERAL:
+		return n->val.ctype;
+	case OADD:
+	case OAND:
+	case OANDNOT:
+	case OCOM:
+	case ODIV:
+	case OMINUS:
+	case OMOD:
+	case OMUL:
+	case OSUB:
+	case OXOR:
+	case OOR:
+	case OPLUS:
+		// numeric kinds.
+		k1 = idealkind(n->left);
+		k2 = idealkind(n->right);
+		if(k1 > k2)
+			return k1;
+		else
+			return k2;
+	case OREAL:
+	case OIMAG:
+		return CTFLT;
+	case OCOMPLEX:
+		return CTCPLX;
+	case OADDSTR:
+		return CTSTR;
+	case OANDAND:
+	case OEQ:
+	case OGE:
+	case OGT:
+	case OLE:
+	case OLT:
+	case ONE:
+	case ONOT:
+	case OOROR:
+	case OCMPSTR:
+	case OCMPIFACE:
+		return CTBOOL;
+	case OLSH:
+	case ORSH:
+		// shifts (beware!).
+		return idealkind(n->left);
+	}
+}
+
+void
+defaultlit(Node **np, Type *t)
+{
+	int lno;
+	int ctype;
+	Node *n, *nn;
+	Type *t1;
+
+	n = *np;
+	if(n == N || !isideal(n->type))
+		return;
+
+	if(n->op == OLITERAL) {
+		nn = nod(OXXX, N, N);
+		*nn = *n;
+		n = nn;
+		*np = n;
+	}
+
+	lno = setlineno(n);
+	ctype = idealkind(n);
+	switch(ctype) {
+	default:
+		if(t != T) {
+			convlit(np, t);
+			return;
+		}
+		if(n->val.ctype == CTNIL) {
+			lineno = lno;
+			if(!n->diag) {
+				yyerror("use of untyped nil");
+				n->diag = 1;
+			}
+			n->type = T;
+			break;
+		}
+		if(n->val.ctype == CTSTR) {
+			t1 = types[TSTRING];
+			convlit(np, t1);
+			break;
+		}
+		yyerror("defaultlit: unknown literal: %N", n);
+		break;
+	case CTxxx:
+		fatal("defaultlit: idealkind is CTxxx: %+N", n);
+		break;
+	case CTBOOL:
+		t1 = types[TBOOL];
+		if(t != T && t->etype == TBOOL)
+			t1 = t;
+		convlit(np, t1);
+		break;
+	case CTINT:
+		t1 = types[TINT];
+		goto num;
+	case CTRUNE:
+		t1 = runetype;
+		goto num;
+	case CTFLT:
+		t1 = types[TFLOAT64];
+		goto num;
+	case CTCPLX:
+		t1 = types[TCOMPLEX128];
+		goto num;
+	num:
+		if(t != T) {
+			if(isint[t->etype]) {
+				t1 = t;
+				n->val = toint(n->val);
+			}
+			else
+			if(isfloat[t->etype]) {
+				t1 = t;
+				n->val = toflt(n->val);
+			}
+			else
+			if(iscomplex[t->etype]) {
+				t1 = t;
+				n->val = tocplx(n->val);
+			}
+		}
+		overflow(n->val, t1);
+		convlit(np, t1);
+		break;
+	}
+	lineno = lno;
+}
+
+/*
+ * defaultlit on both nodes simultaneously;
+ * if they're both ideal going in they better
+ * get the same type going out.
+ * force means must assign concrete (non-ideal) type.
+ */
+void
+defaultlit2(Node **lp, Node **rp, int force)
+{
+	Node *l, *r;
+	int lkind, rkind;
+
+	l = *lp;
+	r = *rp;
+	if(l->type == T || r->type == T)
+		return;
+	if(!isideal(l->type)) {
+		convlit(rp, l->type);
+		return;
+	}
+	if(!isideal(r->type)) {
+		convlit(lp, r->type);
+		return;
+	}
+	if(!force)
+		return;
+	if(l->type->etype == TBOOL) {
+		convlit(lp, types[TBOOL]);
+		convlit(rp, types[TBOOL]);
+	}
+	lkind = idealkind(l);
+	rkind = idealkind(r);
+	if(lkind == CTCPLX || rkind == CTCPLX) {
+		convlit(lp, types[TCOMPLEX128]);
+		convlit(rp, types[TCOMPLEX128]);
+		return;
+	}
+	if(lkind == CTFLT || rkind == CTFLT) {
+		convlit(lp, types[TFLOAT64]);
+		convlit(rp, types[TFLOAT64]);
+		return;
+	}
+
+	if(lkind == CTRUNE || rkind == CTRUNE) {
+		convlit(lp, runetype);
+		convlit(rp, runetype);
+		return;
+	}
+
+	convlit(lp, types[TINT]);
+	convlit(rp, types[TINT]);
+}
+
+int
+cmpslit(Node *l, Node *r)
+{
+	int32 l1, l2, i, m;
+	uchar *s1, *s2;
+
+	l1 = l->val.u.sval->len;
+	l2 = r->val.u.sval->len;
+	s1 = (uchar*)l->val.u.sval->s;
+	s2 = (uchar*)r->val.u.sval->s;
+
+	m = l1;
+	if(l2 < m)
+		m = l2;
+
+	for(i=0; i<m; i++) {
+		if(s1[i] == s2[i])
+			continue;
+		if(s1[i] > s2[i])
+			return +1;
+		return -1;
+	}
+	if(l1 == l2)
+		return 0;
+	if(l1 > l2)
+		return +1;
+	return -1;
+}
+
+int
+smallintconst(Node *n)
+{
+	if(n->op == OLITERAL && isconst(n, CTINT) && n->type != T)
+	switch(simtype[n->type->etype]) {
+	case TINT8:
+	case TUINT8:
+	case TINT16:
+	case TUINT16:
+	case TINT32:
+	case TUINT32:
+	case TBOOL:
+	case TPTR32:
+		return 1;
+	case TIDEAL:
+	case TINT64:
+	case TUINT64:
+	case TPTR64:
+		if(mpcmpfixfix(n->val.u.xval, minintval[TINT32]) < 0
+		|| mpcmpfixfix(n->val.u.xval, maxintval[TINT32]) > 0)
+			break;
+		return 1;
+	}
+	return 0;
+}
+
+long
+nonnegconst(Node *n)
+{
+	if(n->op == OLITERAL && n->type != T)
+	switch(simtype[n->type->etype]) {
+	case TINT8:
+	case TUINT8:
+	case TINT16:
+	case TUINT16:
+	case TINT32:
+	case TUINT32:
+	case TINT64:
+	case TUINT64:
+	case TIDEAL:
+		// check negative and 2^31
+		if(mpcmpfixfix(n->val.u.xval, minintval[TUINT32]) < 0
+		|| mpcmpfixfix(n->val.u.xval, maxintval[TINT32]) > 0)
+			break;
+		return mpgetfix(n->val.u.xval);
+	}
+	return -1;
+}
+
+/*
+ * convert x to type et and back to int64
+ * for sign extension and truncation.
+ */
+static int64
+iconv(int64 x, int et)
+{
+	switch(et) {
+	case TINT8:
+		x = (int8)x;
+		break;
+	case TUINT8:
+		x = (uint8)x;
+		break;
+	case TINT16:
+		x = (int16)x;
+		break;
+	case TUINT16:
+		x = (uint64)x;
+		break;
+	case TINT32:
+		x = (int32)x;
+		break;
+	case TUINT32:
+		x = (uint32)x;
+		break;
+	case TINT64:
+	case TUINT64:
+		break;
+	}
+	return x;
+}
+
+/*
+ * convert constant val to type t; leave in con.
+ * for back end.
+ */
+void
+convconst(Node *con, Type *t, Val *val)
+{
+	int64 i;
+	int tt;
+
+	tt = simsimtype(t);
+
+	// copy the constant for conversion
+	nodconst(con, types[TINT8], 0);
+	con->type = t;
+	con->val = *val;
+
+	if(isint[tt]) {
+		con->val.ctype = CTINT;
+		con->val.u.xval = mal(sizeof *con->val.u.xval);
+		switch(val->ctype) {
+		default:
+			fatal("convconst ctype=%d %lT", val->ctype, t);
+		case CTINT:
+		case CTRUNE:
+			i = mpgetfix(val->u.xval);
+			break;
+		case CTBOOL:
+			i = val->u.bval;
+			break;
+		case CTNIL:
+			i = 0;
+			break;
+		}
+		i = iconv(i, tt);
+		mpmovecfix(con->val.u.xval, i);
+		return;
+	}
+
+	if(isfloat[tt]) {
+		con->val = toflt(con->val);
+		if(con->val.ctype != CTFLT)
+			fatal("convconst ctype=%d %T", con->val.ctype, t);
+		if(tt == TFLOAT32)
+			con->val.u.fval = truncfltlit(con->val.u.fval, t);
+		return;
+	}
+
+	if(iscomplex[tt]) {
+		con->val = tocplx(con->val);
+		if(tt == TCOMPLEX64) {
+			con->val.u.cval->real = *truncfltlit(&con->val.u.cval->real, types[TFLOAT32]);
+			con->val.u.cval->imag = *truncfltlit(&con->val.u.cval->imag, types[TFLOAT32]);
+		}
+		return;
+	}
+
+	fatal("convconst %lT constant", t);
+
+}
+
+// complex multiply v *= rv
+//	(a, b) * (c, d) = (a*c - b*d, b*c + a*d)
+static void
+cmplxmpy(Mpcplx *v, Mpcplx *rv)
+{
+	Mpflt ac, bd, bc, ad;
+
+	mpmovefltflt(&ac, &v->real);
+	mpmulfltflt(&ac, &rv->real);	// ac
+
+	mpmovefltflt(&bd, &v->imag);
+	mpmulfltflt(&bd, &rv->imag);	// bd
+
+	mpmovefltflt(&bc, &v->imag);
+	mpmulfltflt(&bc, &rv->real);	// bc
+
+	mpmovefltflt(&ad, &v->real);
+	mpmulfltflt(&ad, &rv->imag);	// ad
+
+	mpmovefltflt(&v->real, &ac);
+	mpsubfltflt(&v->real, &bd);	// ac-bd
+
+	mpmovefltflt(&v->imag, &bc);
+	mpaddfltflt(&v->imag, &ad);	// bc+ad
+}
+
+// complex divide v /= rv
+//	(a, b) / (c, d) = ((a*c + b*d), (b*c - a*d))/(c*c + d*d)
+static void
+cmplxdiv(Mpcplx *v, Mpcplx *rv)
+{
+	Mpflt ac, bd, bc, ad, cc_plus_dd;
+
+	mpmovefltflt(&cc_plus_dd, &rv->real);
+	mpmulfltflt(&cc_plus_dd, &rv->real);	// cc
+
+	mpmovefltflt(&ac, &rv->imag);
+	mpmulfltflt(&ac, &rv->imag);		// dd
+
+	mpaddfltflt(&cc_plus_dd, &ac);		// cc+dd
+
+	mpmovefltflt(&ac, &v->real);
+	mpmulfltflt(&ac, &rv->real);		// ac
+
+	mpmovefltflt(&bd, &v->imag);
+	mpmulfltflt(&bd, &rv->imag);		// bd
+
+	mpmovefltflt(&bc, &v->imag);
+	mpmulfltflt(&bc, &rv->real);		// bc
+
+	mpmovefltflt(&ad, &v->real);
+	mpmulfltflt(&ad, &rv->imag);		// ad
+
+	mpmovefltflt(&v->real, &ac);
+	mpaddfltflt(&v->real, &bd);		// ac+bd
+	mpdivfltflt(&v->real, &cc_plus_dd);	// (ac+bd)/(cc+dd)
+
+	mpmovefltflt(&v->imag, &bc);
+	mpsubfltflt(&v->imag, &ad);		// bc-ad
+	mpdivfltflt(&v->imag, &cc_plus_dd);	// (bc+ad)/(cc+dd)
+}
+
+static int hascallchan(Node*);
+
+// Is n a Go language constant (as opposed to a compile-time constant)?
+// Expressions derived from nil, like string([]byte(nil)), while they
+// may be known at compile time, are not Go language constants.
+// Only called for expressions known to evaluated to compile-time
+// constants.
+int
+isgoconst(Node *n)
+{
+	Node *l;
+	Type *t;
+
+	if(n->orig != N)
+		n = n->orig;
+
+	switch(n->op) {
+	case OADD:
+	case OADDSTR:
+	case OAND:
+	case OANDAND:
+	case OANDNOT:
+	case OCOM:
+	case ODIV:
+	case OEQ:
+	case OGE:
+	case OGT:
+	case OLE:
+	case OLSH:
+	case OLT:
+	case OMINUS:
+	case OMOD:
+	case OMUL:
+	case ONE:
+	case ONOT:
+	case OOR:
+	case OOROR:
+	case OPLUS:
+	case ORSH:
+	case OSUB:
+	case OXOR:
+	case OIOTA:
+	case OCOMPLEX:
+	case OREAL:
+	case OIMAG:
+		if(isgoconst(n->left) && (n->right == N || isgoconst(n->right)))
+			return 1;
+		break;
+
+	case OCONV:
+		if(okforconst[n->type->etype] && isgoconst(n->left))
+			return 1;
+		break;
+
+	case OLEN:
+	case OCAP:
+		l = n->left;
+		if(isgoconst(l))
+			return 1;
+		// Special case: len/cap is constant when applied to array or
+		// pointer to array when the expression does not contain
+		// function calls or channel receive operations.
+		t = l->type;
+		if(t != T && isptr[t->etype])
+			t = t->type;
+		if(isfixedarray(t) && !hascallchan(l))
+			return 1;
+		break;
+
+	case OLITERAL:
+		if(n->val.ctype != CTNIL)
+			return 1;
+		break;
+
+	case ONAME:
+		l = n->sym->def;
+		if(l && l->op == OLITERAL && n->val.ctype != CTNIL)
+			return 1;
+		break;
+	
+	case ONONAME:
+		if(n->sym->def != N && n->sym->def->op == OIOTA)
+			return 1;
+		break;
+	
+	case OCALL:
+		// Only constant calls are unsafe.Alignof, Offsetof, and Sizeof.
+		l = n->left;
+		while(l->op == OPAREN)
+			l = l->left;
+		if(l->op != ONAME || l->sym->pkg != unsafepkg)
+			break;
+		if(strcmp(l->sym->name, "Alignof") == 0 ||
+		   strcmp(l->sym->name, "Offsetof") == 0 ||
+		   strcmp(l->sym->name, "Sizeof") == 0)
+			return 1;
+		break;		
+	}
+
+	//dump("nonconst", n);
+	return 0;
+}
+
+static int
+hascallchan(Node *n)
+{
+	NodeList *l;
+
+	if(n == N)
+		return 0;
+	switch(n->op) {
+	case OAPPEND:
+	case OCALL:
+	case OCALLFUNC:
+	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;
+	}
+	
+	if(hascallchan(n->left) ||
+	   hascallchan(n->right))
+		return 1;
+	
+	for(l=n->list; l; l=l->next)
+		if(hascallchan(l->n))
+			return 1;
+	for(l=n->rlist; l; l=l->next)
+		if(hascallchan(l->n))
+			return 1;
+
+	return 0;
+}
diff --git a/src/cmd/gc/cplx.c b/src/cmd/gc/cplx.c
new file mode 100644
index 0000000..c9bab7a
--- /dev/null
+++ b/src/cmd/gc/cplx.c
@@ -0,0 +1,486 @@
+// 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 "gg.h"
+
+static	void	subnode(Node *nr, Node *ni, Node *nc);
+static	void	minus(Node *nl, Node *res);
+	void	complexminus(Node*, Node*);
+	void	complexadd(int op, Node*, Node*, Node*);
+	void	complexmul(Node*, Node*, Node*);
+
+#define	CASE(a,b)	(((a)<<16)|((b)<<0))
+
+static int
+overlap(Node *f, Node *t)
+{
+	// check whether f and t could be overlapping stack references.
+	// not exact, because it's hard to check for the stack register
+	// in portable code.  close enough: worst case we will allocate
+	// an extra temporary and the registerizer will clean it up.
+	return f->op == OINDREG &&
+		t->op == OINDREG &&
+		f->xoffset+f->type->width >= t->xoffset &&
+		t->xoffset+t->type->width >= f->xoffset;
+}
+
+/*
+ * generate:
+ *	res = n;
+ * simplifies and calls gmove.
+ */
+void
+complexmove(Node *f, Node *t)
+{
+	int ft, tt;
+	Node n1, n2, n3, n4, tmp;
+
+	if(debug['g']) {
+		dump("\ncomplexmove-f", f);
+		dump("complexmove-t", t);
+	}
+
+	if(!t->addable)
+		fatal("complexmove: to not addable");
+
+	ft = simsimtype(f->type);
+	tt = simsimtype(t->type);
+	switch(CASE(ft,tt)) {
+
+	default:
+		fatal("complexmove: unknown conversion: %T -> %T\n",
+			f->type, t->type);
+
+	case CASE(TCOMPLEX64,TCOMPLEX64):
+	case CASE(TCOMPLEX64,TCOMPLEX128):
+	case CASE(TCOMPLEX128,TCOMPLEX64):
+	case CASE(TCOMPLEX128,TCOMPLEX128):
+		// complex to complex move/convert.
+		// make f addable.
+		// also use temporary if possible stack overlap.
+		if(!f->addable || overlap(f, t)) {
+			tempname(&tmp, f->type);
+			complexmove(f, &tmp);
+			f = &tmp;
+		}
+
+		subnode(&n1, &n2, f);
+		subnode(&n3, &n4, t);
+
+		cgen(&n1, &n3);
+		cgen(&n2, &n4);
+		break;
+	}
+}
+
+int
+complexop(Node *n, Node *res)
+{
+	if(n != N && n->type != T)
+	if(iscomplex[n->type->etype]) {
+		goto maybe;
+	}
+	if(res != N && res->type != T)
+	if(iscomplex[res->type->etype]) {
+		goto maybe;
+	}
+
+	if(n->op == OREAL || n->op == OIMAG)
+		goto yes;
+
+	goto no;
+
+maybe:
+	switch(n->op) {
+	case OCONV:	// implemented ops
+	case OADD:
+	case OSUB:
+	case OMUL:
+	case OMINUS:
+	case OCOMPLEX:
+	case OREAL:
+	case OIMAG:
+		goto yes;
+
+	case ODOT:
+	case ODOTPTR:
+	case OINDEX:
+	case OIND:
+	case ONAME:
+		goto yes;
+	}
+
+no:
+//dump("\ncomplex-no", n);
+	return 0;
+yes:
+//dump("\ncomplex-yes", n);
+	return 1;
+}
+
+void
+complexgen(Node *n, Node *res)
+{
+	Node *nl, *nr;
+	Node tnl, tnr;
+	Node n1, n2, tmp;
+	int tl, tr;
+
+	if(debug['g']) {
+		dump("\ncomplexgen-n", n);
+		dump("complexgen-res", res);
+	}
+	
+	while(n->op == OCONVNOP)
+		n = n->left;
+
+	// pick off float/complex opcodes
+	switch(n->op) {
+	case OCOMPLEX:
+		if(res->addable) {
+			subnode(&n1, &n2, res);
+			tempname(&tmp, n1.type);
+			cgen(n->left, &tmp);
+			cgen(n->right, &n2);
+			cgen(&tmp, &n1);
+			return;
+		}
+		break;
+
+	case OREAL:
+	case OIMAG:
+		nl = n->left;
+		if(!nl->addable) {
+			tempname(&tmp, nl->type);
+			complexgen(nl, &tmp);
+			nl = &tmp;
+		}
+		subnode(&n1, &n2, nl);
+		if(n->op == OREAL) {
+			cgen(&n1, res);
+			return;
+		}
+		cgen(&n2, res);
+		return;
+	}
+
+	// perform conversion from n to res
+	tl = simsimtype(res->type);
+	tl = cplxsubtype(tl);
+	tr = simsimtype(n->type);
+	tr = cplxsubtype(tr);
+	if(tl != tr) {
+		if(!n->addable) {
+			tempname(&n1, n->type);
+			complexmove(n, &n1);
+			n = &n1;
+		}
+		complexmove(n, res);
+		return;
+	}
+
+	if(!res->addable) {
+		igen(res, &n1, N);
+		cgen(n, &n1);
+		regfree(&n1);
+		return;
+	}
+	if(n->addable) {
+		complexmove(n, res);
+		return;
+	}
+
+	switch(n->op) {
+	default:
+		dump("complexgen: unknown op", n);
+		fatal("complexgen: unknown op %O", n->op);
+
+	case ODOT:
+	case ODOTPTR:
+	case OINDEX:
+	case OIND:
+	case ONAME:	// PHEAP or PPARAMREF var
+	case OCALLFUNC:
+	case OCALLMETH:
+	case OCALLINTER:
+		igen(n, &n1, res);
+		complexmove(&n1, res);
+		regfree(&n1);
+		return;
+
+	case OCONV:
+	case OADD:
+	case OSUB:
+	case OMUL:
+	case OMINUS:
+	case OCOMPLEX:
+	case OREAL:
+	case OIMAG:
+		break;
+	}
+
+	nl = n->left;
+	if(nl == N)
+		return;
+	nr = n->right;
+
+	// make both sides addable in ullman order
+	if(nr != N) {
+		if(nl->ullman > nr->ullman && !nl->addable) {
+			tempname(&tnl, nl->type);
+			cgen(nl, &tnl);
+			nl = &tnl;
+		}
+		if(!nr->addable) {
+			tempname(&tnr, nr->type);
+			cgen(nr, &tnr);
+			nr = &tnr;
+		}
+	}
+	if(!nl->addable) {
+		tempname(&tnl, nl->type);
+		cgen(nl, &tnl);
+		nl = &tnl;
+	}
+
+	switch(n->op) {
+	default:
+		fatal("complexgen: unknown op %O", n->op);
+		break;
+
+	case OCONV:
+		complexmove(nl, res);
+		break;
+
+	case OMINUS:
+		complexminus(nl, res);
+		break;
+
+	case OADD:
+	case OSUB:
+		complexadd(n->op, nl, nr, res);
+		break;
+
+	case OMUL:
+		complexmul(nl, nr, res);
+		break;
+	}
+}
+
+void
+complexbool(int op, Node *nl, Node *nr, int true, int likely, Prog *to)
+{
+	Node tnl, tnr;
+	Node n1, n2, n3, n4;
+	Node na, nb, nc;
+
+	// make both sides addable in ullman order
+	if(nr != N) {
+		if(nl->ullman > nr->ullman && !nl->addable) {
+			tempname(&tnl, nl->type);
+			cgen(nl, &tnl);
+			nl = &tnl;
+		}
+		if(!nr->addable) {
+			tempname(&tnr, nr->type);
+			cgen(nr, &tnr);
+			nr = &tnr;
+		}
+	}
+	if(!nl->addable) {
+		tempname(&tnl, nl->type);
+		cgen(nl, &tnl);
+		nl = &tnl;
+	}
+
+	// build tree
+	// real(l) == real(r) && imag(l) == imag(r)
+
+	subnode(&n1, &n2, nl);
+	subnode(&n3, &n4, nr);
+
+	memset(&na, 0, sizeof(na));
+	na.op = OANDAND;
+	na.left = &nb;
+	na.right = &nc;
+	na.type = types[TBOOL];
+
+	memset(&nb, 0, sizeof(na));
+	nb.op = OEQ;
+	nb.left = &n1;
+	nb.right = &n3;
+	nb.type = types[TBOOL];
+
+	memset(&nc, 0, sizeof(na));
+	nc.op = OEQ;
+	nc.left = &n2;
+	nc.right = &n4;
+	nc.type = types[TBOOL];
+
+	if(op == ONE)
+		true = !true;
+
+	bgen(&na, true, likely, to);
+}
+
+void
+nodfconst(Node *n, Type *t, Mpflt* fval)
+{
+	memset(n, 0, sizeof(*n));
+	n->op = OLITERAL;
+	n->addable = 1;
+	ullmancalc(n);
+	n->val.u.fval = fval;
+	n->val.ctype = CTFLT;
+	n->type = t;
+
+	if(!isfloat[t->etype])
+		fatal("nodfconst: bad type %T", t);
+}
+
+// break addable nc-complex into nr-real and ni-imaginary
+static void
+subnode(Node *nr, Node *ni, Node *nc)
+{
+	int tc;
+	Type *t;
+
+	if(!nc->addable)
+		fatal("subnode not addable");
+
+	tc = simsimtype(nc->type);
+	tc = cplxsubtype(tc);
+	t = types[tc];
+
+	if(nc->op == OLITERAL) {
+		nodfconst(nr, t, &nc->val.u.cval->real);
+		nodfconst(ni, t, &nc->val.u.cval->imag);
+		return;
+	}
+
+	*nr = *nc;
+	nr->type = t;
+
+	*ni = *nc;
+	ni->type = t;
+	ni->xoffset += t->width;
+}
+
+// generate code res = -nl
+static void
+minus(Node *nl, Node *res)
+{
+	Node ra;
+
+	memset(&ra, 0, sizeof(ra));
+	ra.op = OMINUS;
+	ra.left = nl;
+	ra.type = nl->type;
+	cgen(&ra, res);
+}
+
+// build and execute tree
+//	real(res) = -real(nl)
+//	imag(res) = -imag(nl)
+void
+complexminus(Node *nl, Node *res)
+{
+	Node n1, n2, n5, n6;
+
+	subnode(&n1, &n2, nl);
+	subnode(&n5, &n6, res);
+
+	minus(&n1, &n5);
+	minus(&n2, &n6);
+}
+
+
+// build and execute tree
+//	real(res) = real(nl) op real(nr)
+//	imag(res) = imag(nl) op imag(nr)
+void
+complexadd(int op, Node *nl, Node *nr, Node *res)
+{
+	Node n1, n2, n3, n4, n5, n6;
+	Node ra;
+
+	subnode(&n1, &n2, nl);
+	subnode(&n3, &n4, nr);
+	subnode(&n5, &n6, res);
+
+	memset(&ra, 0, sizeof(ra));
+	ra.op = op;
+	ra.left = &n1;
+	ra.right = &n3;
+	ra.type = n1.type;
+	cgen(&ra, &n5);
+
+	memset(&ra, 0, sizeof(ra));
+	ra.op = op;
+	ra.left = &n2;
+	ra.right = &n4;
+	ra.type = n2.type;
+	cgen(&ra, &n6);
+}
+
+// build and execute tree
+//	tmp       = real(nl)*real(nr) - imag(nl)*imag(nr)
+//	imag(res) = real(nl)*imag(nr) + imag(nl)*real(nr)
+//	real(res) = tmp
+void
+complexmul(Node *nl, Node *nr, Node *res)
+{
+	Node n1, n2, n3, n4, n5, n6;
+	Node rm1, rm2, ra, tmp;
+
+	subnode(&n1, &n2, nl);
+	subnode(&n3, &n4, nr);
+	subnode(&n5, &n6, res);
+	tempname(&tmp, n5.type);
+
+	// real part -> tmp
+	memset(&rm1, 0, sizeof(ra));
+	rm1.op = OMUL;
+	rm1.left = &n1;
+	rm1.right = &n3;
+	rm1.type = n1.type;
+
+	memset(&rm2, 0, sizeof(ra));
+	rm2.op = OMUL;
+	rm2.left = &n2;
+	rm2.right = &n4;
+	rm2.type = n2.type;
+
+	memset(&ra, 0, sizeof(ra));
+	ra.op = OSUB;
+	ra.left = &rm1;
+	ra.right = &rm2;
+	ra.type = rm1.type;
+	cgen(&ra, &tmp);
+
+	// imag part
+	memset(&rm1, 0, sizeof(ra));
+	rm1.op = OMUL;
+	rm1.left = &n1;
+	rm1.right = &n4;
+	rm1.type = n1.type;
+
+	memset(&rm2, 0, sizeof(ra));
+	rm2.op = OMUL;
+	rm2.left = &n2;
+	rm2.right = &n3;
+	rm2.type = n2.type;
+
+	memset(&ra, 0, sizeof(ra));
+	ra.op = OADD;
+	ra.left = &rm1;
+	ra.right = &rm2;
+	ra.type = rm1.type;
+	cgen(&ra, &n6);
+
+	// tmp ->real part
+	cgen(&tmp, &n5);
+}
diff --git a/src/cmd/gc/dcl.c b/src/cmd/gc/dcl.c
new file mode 100644
index 0000000..dfcf475
--- /dev/null
+++ b/src/cmd/gc/dcl.c
@@ -0,0 +1,1494 @@
+// 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	"go.h"
+#include	"y.tab.h"
+
+static	void	funcargs(Node*);
+static	void	funcargs2(Type*);
+
+static int
+dflag(void)
+{
+	if(!debug['d'])
+		return 0;
+	if(debug['y'])
+		return 1;
+	if(incannedimport)
+		return 0;
+	return 1;
+}
+
+/*
+ * declaration stack & operations
+ */
+
+static void
+dcopy(Sym *a, Sym *b)
+{
+	a->pkg = b->pkg;
+	a->name = b->name;
+	a->def = b->def;
+	a->block = b->block;
+	a->lastlineno = b->lastlineno;
+}
+
+static Sym*
+push(void)
+{
+	Sym *d;
+
+	d = mal(sizeof(*d));
+	d->lastlineno = lineno;
+	d->link = dclstack;
+	dclstack = d;
+	return d;
+}
+
+static Sym*
+pushdcl(Sym *s)
+{
+	Sym *d;
+
+	d = push();
+	dcopy(d, s);
+	if(dflag())
+		print("\t%L push %S %p\n", lineno, s, s->def);
+	return d;
+}
+
+void
+popdcl(void)
+{
+	Sym *d, *s;
+	int lno;
+
+//	if(dflag())
+//		print("revert\n");
+
+	for(d=dclstack; d!=S; d=d->link) {
+		if(d->name == nil)
+			break;
+		s = pkglookup(d->name, d->pkg);
+		lno = s->lastlineno;
+		dcopy(s, d);
+		d->lastlineno = lno;
+		if(dflag())
+			print("\t%L pop %S %p\n", lineno, s, s->def);
+	}
+	if(d == S)
+		fatal("popdcl: no mark");
+	dclstack = d->link;
+	block = d->block;
+}
+
+void
+poptodcl(void)
+{
+	// pop the old marker and push a new one
+	// (cannot reuse the existing one)
+	// because we use the markers to identify blocks
+	// for the goto restriction checks.
+	popdcl();
+	markdcl();
+}
+
+void
+markdcl(void)
+{
+	Sym *d;
+
+	d = push();
+	d->name = nil;		// used as a mark in fifo
+	d->block = block;
+
+	blockgen++;
+	block = blockgen;
+
+//	if(dflag())
+//		print("markdcl\n");
+}
+
+void
+dumpdcl(char *st)
+{
+	Sym *s, *d;
+	int i;
+
+	USED(st);
+
+	i = 0;
+	for(d=dclstack; d!=S; d=d->link) {
+		i++;
+		print("    %.2d %p", i, d);
+		if(d->name == nil) {
+			print("\n");
+			continue;
+		}
+		print(" '%s'", d->name);
+		s = pkglookup(d->name, d->pkg);
+		print(" %S\n", s);
+	}
+}
+
+void
+testdclstack(void)
+{
+	Sym *d;
+
+	for(d=dclstack; d!=S; d=d->link) {
+		if(d->name == nil) {
+			if(nerrors != 0)
+				errorexit();
+			yyerror("mark left on the stack");
+			continue;
+		}
+	}
+}
+
+void
+redeclare(Sym *s, char *where)
+{
+	Strlit *pkgstr;
+	int line1, line2;
+
+	if(s->lastlineno == 0) {
+		pkgstr = s->origpkg ? s->origpkg->path : s->pkg->path;
+		yyerror("%S redeclared %s\n"
+			"\tprevious declaration during import \"%Z\"",
+			s, where, pkgstr);
+	} else {
+		line1 = parserline();
+		line2 = s->lastlineno;
+		
+		// When an import and a declaration collide in separate files,
+		// present the import as the "redeclared", because the declaration
+		// is visible where the import is, but not vice versa.
+		// See issue 4510.
+		if(s->def == N) {
+			line2 = line1;
+			line1 = s->lastlineno;
+		}
+
+		yyerrorl(line1, "%S redeclared %s\n"
+			"\tprevious declaration at %L",
+			s, where, line2);
+	}
+}
+
+static int vargen;
+
+/*
+ * declare individual names - var, typ, const
+ */
+void
+declare(Node *n, int ctxt)
+{
+	Sym *s;
+	int gen;
+	static int typegen;
+	
+	if(ctxt == PDISCARD)
+		return;
+
+	if(isblank(n))
+		return;
+
+	n->lineno = parserline();
+	s = n->sym;
+
+	// kludgy: typecheckok means we're past parsing.  Eg genwrapper may declare out of package names later.
+	if(importpkg == nil && !typecheckok && s->pkg != localpkg)
+		yyerror("cannot declare name %S", s);
+
+	if(ctxt == PEXTERN && strcmp(s->name, "init") == 0)
+		yyerror("cannot declare init - must be func", s);
+
+	gen = 0;
+	if(ctxt == PEXTERN) {
+		externdcl = list(externdcl, n);
+		if(dflag())
+			print("\t%L global decl %S %p\n", lineno, s, n);
+	} else {
+		if(curfn == nil && ctxt == PAUTO)
+			fatal("automatic outside function");
+		if(curfn != nil)
+			curfn->dcl = list(curfn->dcl, n);
+		if(n->op == OTYPE)
+			gen = ++typegen;
+		else if(n->op == ONAME && ctxt == PAUTO && strstr(s->name, "·") == nil)
+			gen = ++vargen;
+		pushdcl(s);
+		n->curfn = curfn;
+	}
+	if(ctxt == PAUTO)
+		n->xoffset = 0;
+
+	if(s->block == block) {
+		// functype will print errors about duplicate function arguments.
+		// Don't repeat the error here.
+		if(ctxt != PPARAM && ctxt != PPARAMOUT)
+			redeclare(s, "in this block");
+	}
+
+	s->block = block;
+	s->lastlineno = parserline();
+	s->def = n;
+	n->vargen = gen;
+	n->funcdepth = funcdepth;
+	n->class = ctxt;
+
+	autoexport(n, ctxt);
+}
+
+void
+addvar(Node *n, Type *t, int ctxt)
+{
+	if(n==N || n->sym == S || (n->op != ONAME && n->op != ONONAME) || t == T)
+		fatal("addvar: n=%N t=%T nil", n, t);
+
+	n->op = ONAME;
+	declare(n, ctxt);
+	n->type = t;
+}
+
+/*
+ * declare variables from grammar
+ * new_name_list (type | [type] = expr_list)
+ */
+NodeList*
+variter(NodeList *vl, Node *t, NodeList *el)
+{
+	int doexpr;
+	Node *v, *e, *as2;
+	NodeList *init;
+
+	init = nil;
+	doexpr = el != nil;
+
+	if(count(el) == 1 && count(vl) > 1) {
+		e = el->n;
+		as2 = nod(OAS2, N, N);
+		as2->list = vl;
+		as2->rlist = list1(e);
+		for(; vl; vl=vl->next) {
+			v = vl->n;
+			v->op = ONAME;
+			declare(v, dclcontext);
+			v->ntype = t;
+			v->defn = as2;
+			if(funcdepth > 0)
+				init = list(init, nod(ODCL, v, N));
+		}
+		return list(init, as2);
+	}
+	
+	for(; vl; vl=vl->next) {
+		if(doexpr) {
+			if(el == nil) {
+				yyerror("missing expression in var declaration");
+				break;
+			}
+			e = el->n;
+			el = el->next;
+		} else
+			e = N;
+
+		v = vl->n;
+		v->op = ONAME;
+		declare(v, dclcontext);
+		v->ntype = t;
+
+		if(e != N || funcdepth > 0 || isblank(v)) {
+			if(funcdepth > 0)
+				init = list(init, nod(ODCL, v, N));
+			e = nod(OAS, v, e);
+			init = list(init, e);
+			if(e->right != N)
+				v->defn = e;
+		}
+	}
+	if(el != nil)
+		yyerror("extra expression in var declaration");
+	return init;
+}
+
+/*
+ * declare constants from grammar
+ * new_name_list [[type] = expr_list]
+ */
+NodeList*
+constiter(NodeList *vl, Node *t, NodeList *cl)
+{
+	Node *v, *c;
+	NodeList *vv;
+
+	vv = nil;
+	if(cl == nil) {
+		if(t != N)
+			yyerror("const declaration cannot have type without expression");
+		cl = lastconst;
+		t = lasttype;
+	} else {
+		lastconst = cl;
+		lasttype = t;
+	}
+	cl = listtreecopy(cl);
+
+	for(; vl; vl=vl->next) {
+		if(cl == nil) {
+			yyerror("missing value in const declaration");
+			break;
+		}
+		c = cl->n;
+		cl = cl->next;
+
+		v = vl->n;
+		v->op = OLITERAL;
+		declare(v, dclcontext);
+
+		v->ntype = t;
+		v->defn = c;
+
+		vv = list(vv, nod(ODCLCONST, v, N));
+	}
+	if(cl != nil)
+		yyerror("extra expression in const declaration");
+	iota += 1;
+	return vv;
+}
+
+/*
+ * this generates a new name node,
+ * typically for labels or other one-off names.
+ */
+Node*
+newname(Sym *s)
+{
+	Node *n;
+
+	if(s == S)
+		fatal("newname nil");
+
+	n = nod(ONAME, N, N);
+	n->sym = s;
+	n->type = T;
+	n->addable = 1;
+	n->ullman = 1;
+	n->xoffset = 0;
+	return n;
+}
+
+/*
+ * this generates a new name node for a name
+ * being declared.
+ */
+Node*
+dclname(Sym *s)
+{
+	Node *n;
+
+	n = newname(s);
+	n->op = ONONAME;	// caller will correct it
+	return n;
+}
+
+Node*
+typenod(Type *t)
+{
+	// if we copied another type with *t = *u
+	// then t->nod might be out of date, so
+	// check t->nod->type too
+	if(t->nod == N || t->nod->type != t) {
+		t->nod = nod(OTYPE, N, N);
+		t->nod->type = t;
+		t->nod->sym = t->sym;
+	}
+	return t->nod;
+}
+
+
+/*
+ * this will return an old name
+ * that has already been pushed on the
+ * declaration list. a diagnostic is
+ * generated if no name has been defined.
+ */
+Node*
+oldname(Sym *s)
+{
+	Node *n;
+	Node *c;
+
+	n = s->def;
+	if(n == N) {
+		// maybe a top-level name will come along
+		// to give this a definition later.
+		// walkdef will check s->def again once
+		// all the input source has been processed.
+		n = newname(s);
+		n->op = ONONAME;
+		n->iota = iota;	// save current iota value in const declarations
+	}
+	if(curfn != nil && n->funcdepth > 0 && n->funcdepth != funcdepth && n->op == ONAME) {
+		// inner func is referring to var in outer func.
+		//
+		// TODO(rsc): If there is an outer variable x and we
+		// are parsing x := 5 inside the closure, until we get to
+		// the := it looks like a reference to the outer x so we'll
+		// make x a closure variable unnecessarily.
+		if(n->closure == N || n->closure->funcdepth != funcdepth) {
+			// create new closure var.
+			c = nod(ONAME, N, N);
+			c->sym = s;
+			c->class = PPARAMREF;
+			c->isddd = n->isddd;
+			c->defn = n;
+			c->addable = 0;
+			c->ullman = 2;
+			c->funcdepth = funcdepth;
+			c->outer = n->closure;
+			n->closure = c;
+			n->addrtaken = 1;
+			c->closure = n;
+			c->xoffset = 0;
+			curfn->cvars = list(curfn->cvars, c);
+		}
+		// return ref to closure var, not original
+		return n->closure;
+	}
+	return n;
+}
+
+/*
+ * := declarations
+ */
+
+static int
+colasname(Node *n)
+{
+	switch(n->op) {
+	case ONAME:
+	case ONONAME:
+	case OPACK:
+	case OTYPE:
+	case OLITERAL:
+		return n->sym != S;
+	}
+	return 0;
+}
+
+void
+colasdefn(NodeList *left, Node *defn)
+{
+	int nnew, nerr;
+	NodeList *l;
+	Node *n;
+
+	for(l=left; l; l=l->next)
+		if(l->n->sym != S)
+			l->n->sym->flags |= SymUniq;
+
+	nnew = 0;
+	nerr = 0;
+	for(l=left; l; l=l->next) {
+		n = l->n;
+		if(isblank(n))
+			continue;
+		if(!colasname(n)) {
+			yyerrorl(defn->lineno, "non-name %N on left side of :=", n);
+			nerr++;
+			continue;
+		}
+		if((n->sym->flags & SymUniq) == 0) {
+			yyerrorl(defn->lineno, "%S repeated on left side of :=", n->sym);
+			n->diag++;
+			nerr++;
+			continue;
+		}
+		n->sym->flags &= ~SymUniq;
+		if(n->sym->block == block)
+			continue;
+
+		nnew++;
+		n = newname(n->sym);
+		declare(n, dclcontext);
+		n->defn = defn;
+		defn->ninit = list(defn->ninit, nod(ODCL, n, N));
+		l->n = n;
+	}
+	if(nnew == 0 && nerr == 0)
+		yyerrorl(defn->lineno, "no new variables on left side of :=");
+}
+
+Node*
+colas(NodeList *left, NodeList *right, int32 lno)
+{
+	Node *as;
+
+	as = nod(OAS2, N, N);
+	as->list = left;
+	as->rlist = right;
+	as->colas = 1;
+	as->lineno = lno;
+	colasdefn(left, as);
+
+	// make the tree prettier; not necessary
+	if(count(left) == 1 && count(right) == 1) {
+		as->left = as->list->n;
+		as->right = as->rlist->n;
+		as->list = nil;
+		as->rlist = nil;
+		as->op = OAS;
+	}
+
+	return as;
+}
+
+/*
+ * declare the arguments in an
+ * interface field declaration.
+ */
+void
+ifacedcl(Node *n)
+{
+	if(n->op != ODCLFIELD || n->right == N)
+		fatal("ifacedcl");
+
+	if(isblank(n->left))
+		yyerror("methods must have a unique non-blank name");
+
+	dclcontext = PPARAM;
+	markdcl();
+	funcdepth++;
+	n->outer = curfn;
+	curfn = n;
+	funcargs(n->right);
+
+	// funcbody is normally called after the parser has
+	// seen the body of a function but since an interface
+	// field declaration does not have a body, we must
+	// call it now to pop the current declaration context.
+	dclcontext = PAUTO;
+	funcbody(n);
+}
+
+/*
+ * declare the function proper
+ * and declare the arguments.
+ * called in extern-declaration context
+ * returns in auto-declaration context.
+ */
+void
+funchdr(Node *n)
+{
+	// change the declaration context from extern to auto
+	if(funcdepth == 0 && dclcontext != PEXTERN)
+		fatal("funchdr: dclcontext");
+
+	dclcontext = PAUTO;
+	markdcl();
+	funcdepth++;
+
+	n->outer = curfn;
+	curfn = n;
+
+	if(n->nname)
+		funcargs(n->nname->ntype);
+	else if (n->ntype)
+		funcargs(n->ntype);
+	else
+		funcargs2(n->type);
+}
+
+static void
+funcargs(Node *nt)
+{
+	Node *n, *nn;
+	NodeList *l;
+	int gen;
+
+	if(nt->op != OTFUNC)
+		fatal("funcargs %O", nt->op);
+
+	// re-start the variable generation number
+	// we want to use small numbers for the return variables,
+	// so let them have the chunk starting at 1.
+	vargen = count(nt->rlist);
+
+	// declare the receiver and in arguments.
+	// no n->defn because type checking of func header
+	// will not fill in the types until later
+	if(nt->left != N) {
+		n = nt->left;
+		if(n->op != ODCLFIELD)
+			fatal("funcargs receiver %O", n->op);
+		if(n->left != N) {
+			n->left->op = ONAME;
+			n->left->ntype = n->right;
+			declare(n->left, PPARAM);
+			if(dclcontext == PAUTO)
+				n->left->vargen = ++vargen;
+		}
+	}
+	for(l=nt->list; l; l=l->next) {
+		n = l->n;
+		if(n->op != ODCLFIELD)
+			fatal("funcargs in %O", n->op);
+		if(n->left != N) {
+			n->left->op = ONAME;
+			n->left->ntype = n->right;
+			declare(n->left, PPARAM);
+			if(dclcontext == PAUTO)
+				n->left->vargen = ++vargen;
+		}
+	}
+
+	// declare the out arguments.
+	gen = count(nt->list);
+	int i = 0;
+	for(l=nt->rlist; l; l=l->next) {
+		n = l->n;
+
+		if(n->op != ODCLFIELD)
+			fatal("funcargs out %O", n->op);
+
+		if(n->left == N) {
+			// 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;
+		} 
+
+		n->left->op = ONAME;
+
+		if(isblank(n->left)) {
+			// 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;
+		}
+
+		n->left->ntype = n->right;
+		declare(n->left, PPARAMOUT);
+		if(dclcontext == PAUTO)
+			n->left->vargen = ++i;
+	}
+}
+
+/*
+ * Same as funcargs, except run over an already constructed TFUNC.
+ * This happens during import, where the hidden_fndcl rule has
+ * used functype directly to parse the function's type.
+ */
+static void
+funcargs2(Type *t)
+{
+	Type *ft;
+	Node *n;
+
+	if(t->etype != TFUNC)
+		fatal("funcargs2 %T", t);
+	
+	if(t->thistuple)
+		for(ft=getthisx(t)->type; ft; ft=ft->down) {
+			if(!ft->nname || !ft->nname->sym)
+				continue;
+			n = ft->nname;  // no need for newname(ft->nname->sym)
+			n->type = ft->type;
+			declare(n, PPARAM);
+		}
+
+	if(t->intuple)
+		for(ft=getinargx(t)->type; ft; ft=ft->down) {
+			if(!ft->nname || !ft->nname->sym)
+				continue;
+			n = ft->nname;
+			n->type = ft->type;
+			declare(n, PPARAM);
+		}
+
+	if(t->outtuple)
+		for(ft=getoutargx(t)->type; ft; ft=ft->down) {
+			if(!ft->nname || !ft->nname->sym)
+				continue;
+			n = ft->nname;
+			n->type = ft->type;
+			declare(n, PPARAMOUT);
+		}
+}
+
+/*
+ * finish the body.
+ * called in auto-declaration context.
+ * returns in extern-declaration context.
+ */
+void
+funcbody(Node *n)
+{
+	// change the declaration context from auto to extern
+	if(dclcontext != PAUTO)
+		fatal("funcbody: dclcontext");
+	popdcl();
+	funcdepth--;
+	curfn = n->outer;
+	n->outer = N;
+	if(funcdepth == 0)
+		dclcontext = PEXTERN;
+}
+
+/*
+ * new type being defined with name s.
+ */
+Node*
+typedcl0(Sym *s)
+{
+	Node *n;
+
+	n = newname(s);
+	n->op = OTYPE;
+	declare(n, dclcontext);
+	return n;
+}
+
+/*
+ * node n, which was returned by typedcl0
+ * is being declared to have uncompiled type t.
+ * return the ODCLTYPE node to use.
+ */
+Node*
+typedcl1(Node *n, Node *t, int local)
+{
+	n->ntype = t;
+	n->local = local;
+	return nod(ODCLTYPE, n, N);
+}
+
+/*
+ * structs, functions, and methods.
+ * they don't belong here, but where do they belong?
+ */
+
+static void
+checkembeddedtype(Type *t)
+{
+	if (t == T)
+		return;
+
+	if(t->sym == S && isptr[t->etype]) {
+		t = t->type;
+		if(t->etype == TINTER)
+			yyerror("embedded type cannot be a pointer to interface");
+	}
+	if(isptr[t->etype])
+		yyerror("embedded type cannot be a pointer");
+	else if(t->etype == TFORW && t->embedlineno == 0)
+		t->embedlineno = lineno;
+}
+
+static Type*
+structfield(Node *n)
+{
+	Type *f;
+	int lno;
+
+	lno = lineno;
+	lineno = n->lineno;
+
+	if(n->op != ODCLFIELD)
+		fatal("structfield: oops %N\n", n);
+
+	f = typ(TFIELD);
+	f->isddd = n->isddd;
+
+	if(n->right != N) {
+		typecheck(&n->right, Etype);
+		n->type = n->right->type;
+		if(n->left != N)
+			n->left->type = n->type;
+		if(n->embedded)
+			checkembeddedtype(n->type);
+	}
+	n->right = N;
+		
+	f->type = n->type;
+	if(f->type == T)
+		f->broke = 1;
+
+	switch(n->val.ctype) {
+	case CTSTR:
+		f->note = n->val.u.sval;
+		break;
+	default:
+		yyerror("field annotation must be string");
+		// fallthrough
+	case CTxxx:
+		f->note = nil;
+		break;
+	}
+
+	if(n->left && n->left->op == ONAME) {
+		f->nname = n->left;
+		f->embedded = n->embedded;
+		f->sym = f->nname->sym;
+	}
+
+	lineno = lno;
+	return f;
+}
+
+static uint32 uniqgen;
+
+static void
+checkdupfields(Type *t, char* what)
+{
+	int lno;
+
+	lno = lineno;
+
+	for( ; t; t=t->down) {
+		if(t->sym && t->nname && !isblank(t->nname)) {
+			if(t->sym->uniqgen == uniqgen) {
+				lineno = t->nname->lineno;
+				yyerror("duplicate %s %s", what, t->sym->name);
+			} else
+				t->sym->uniqgen = uniqgen;
+		}
+	}
+
+	lineno = lno;
+}
+
+/*
+ * convert a parsed id/type list into
+ * a type for struct/interface/arglist
+ */
+Type*
+tostruct(NodeList *l)
+{
+	Type *t, *f, **tp;
+	t = typ(TSTRUCT);
+
+	for(tp = &t->type; l; l=l->next) {
+		f = structfield(l->n);
+
+		*tp = f;
+		tp = &f->down;
+	}
+
+	for(f=t->type; f && !t->broke; f=f->down)
+		if(f->broke)
+			t->broke = 1;
+
+	uniqgen++;
+	checkdupfields(t->type, "field");
+
+	if (!t->broke)
+		checkwidth(t);
+
+	return t;
+}
+
+static Type*
+tofunargs(NodeList *l)
+{
+	Type *t, *f, **tp;
+
+	t = typ(TSTRUCT);
+	t->funarg = 1;
+
+	for(tp = &t->type; l; l=l->next) {
+		f = structfield(l->n);
+		f->funarg = 1;
+
+		// esc.c needs to find f given a PPARAM to add the tag.
+		if(l->n->left && l->n->left->class == PPARAM)
+			l->n->left->paramfld = f;
+
+		*tp = f;
+		tp = &f->down;
+	}
+
+	for(f=t->type; f && !t->broke; f=f->down)
+		if(f->broke)
+			t->broke = 1;
+
+	return t;
+}
+
+static Type*
+interfacefield(Node *n)
+{
+	Type *f;
+	int lno;
+
+	lno = lineno;
+	lineno = n->lineno;
+
+	if(n->op != ODCLFIELD)
+		fatal("interfacefield: oops %N\n", n);
+
+	if (n->val.ctype != CTxxx)
+		yyerror("interface method cannot have annotation");
+
+	f = typ(TFIELD);
+	f->isddd = n->isddd;
+	
+	if(n->right != N) {
+		if(n->left != N) {
+			// queue resolution of method type for later.
+			// right now all we need is the name list.
+			// avoids cycles for recursive interface types.
+			n->type = typ(TINTERMETH);
+			n->type->nname = n->right;
+			n->left->type = n->type;
+			queuemethod(n);
+
+			if(n->left->op == ONAME) {
+				f->nname = n->left;
+				f->embedded = n->embedded;
+				f->sym = f->nname->sym;
+			}
+
+		} else {
+
+			typecheck(&n->right, Etype);
+			n->type = n->right->type;
+
+			if(n->embedded)
+				checkembeddedtype(n->type);
+
+			if(n->type)
+				switch(n->type->etype) {
+				case TINTER:
+					break;
+				case TFORW:
+					yyerror("interface type loop involving %T", n->type);
+					f->broke = 1;
+					break;
+				default:
+					yyerror("interface contains embedded non-interface %T", n->type);
+					f->broke = 1;
+					break;
+				}
+		}
+	}
+
+	n->right = N;
+	
+	f->type = n->type;
+	if(f->type == T)
+		f->broke = 1;
+	
+	lineno = lno;
+	return f;
+}
+
+Type*
+tointerface(NodeList *l)
+{
+	Type *t, *f, **tp, *t1;
+
+	t = typ(TINTER);
+
+	tp = &t->type;
+	for(; l; l=l->next) {
+		f = interfacefield(l->n);
+
+		if (l->n->left == N && f->type->etype == TINTER) {
+			// embedded interface, inline methods
+			for(t1=f->type->type; t1; t1=t1->down) {
+				f = typ(TFIELD);
+				f->type = t1->type;
+				f->broke = t1->broke;
+				f->sym = t1->sym;
+				if(f->sym)
+					f->nname = newname(f->sym);
+				*tp = f;
+				tp = &f->down;
+			}
+		} else {
+			*tp = f;
+			tp = &f->down;
+		}
+	}
+
+	for(f=t->type; f && !t->broke; f=f->down)
+		if(f->broke)
+			t->broke = 1;
+
+	uniqgen++;
+	checkdupfields(t->type, "method");
+	t = sortinter(t);
+	checkwidth(t);
+
+	return t;
+}
+
+Node*
+embedded(Sym *s, Pkg *pkg)
+{
+	Node *n;
+	char *name;
+
+	// Names sometimes have disambiguation junk
+	// appended after a center dot.  Discard it when
+	// making the name for the embedded struct field.
+	enum { CenterDot = 0xB7 };
+	name = s->name;
+	if(utfrune(s->name, CenterDot)) {
+		name = strdup(s->name);
+		*utfrune(name, CenterDot) = 0;
+	}
+
+	if(exportname(name))
+		n = newname(lookup(name));
+	else if(s->pkg == builtinpkg)
+		// The name of embedded builtins belongs to pkg.
+		n = newname(pkglookup(name, pkg));
+	else
+		n = newname(pkglookup(name, s->pkg));
+	n = nod(ODCLFIELD, n, oldname(s));
+	n->embedded = 1;
+	return n;
+}
+
+/*
+ * check that the list of declarations is either all anonymous or all named
+ */
+
+static Node*
+findtype(NodeList *l)
+{
+	for(; l; l=l->next)
+		if(l->n->op == OKEY)
+			return l->n->right;
+	return N;
+}
+
+NodeList*
+checkarglist(NodeList *all, int input)
+{
+	int named;
+	Node *n, *t, *nextt;
+	NodeList *l;
+
+	named = 0;
+	for(l=all; l; l=l->next) {
+		if(l->n->op == OKEY) {
+			named = 1;
+			break;
+		}
+	}
+	if(named) {
+		n = N;
+		for(l=all; l; l=l->next) {
+			n = l->n;
+			if(n->op != OKEY && n->sym == S) {
+				yyerror("mixed named and unnamed function parameters");
+				break;
+			}
+		}
+		if(l == nil && n != N && n->op != OKEY)
+			yyerror("final function parameter must have type");
+	}
+
+	nextt = nil;
+	for(l=all; l; l=l->next) {
+		// can cache result from findtype to avoid
+		// quadratic behavior here, but unlikely to matter.
+		n = l->n;
+		if(named) {
+			if(n->op == OKEY) {
+				t = n->right;
+				n = n->left;
+				nextt = nil;
+			} else {
+				if(nextt == nil)
+					nextt = findtype(l);
+				t = nextt;
+			}
+		} else {
+			t = n;
+			n = N;
+		}
+
+		// during import l->n->op is OKEY, but l->n->left->sym == S
+		// means it was a '?', not that it was
+		// a lone type This doesn't matter for the exported
+		// declarations, which are parsed by rules that don't
+		// use checkargs, but can happen for func literals in
+		// the inline bodies.
+		// TODO(rsc) this can go when typefmt case TFIELD in exportmode fmt.c prints _ instead of ?
+		if(importpkg && n->sym == S)
+			n = N;
+
+		if(n != N && n->sym == S) {
+			t = n;
+			n = N;
+		}
+		if(n != N)
+			n = newname(n->sym);
+		n = nod(ODCLFIELD, n, t);
+		if(n->right != N && n->right->op == ODDD) {
+			if(!input)
+				yyerror("cannot use ... in output argument list");
+			else if(l->next != nil)
+				yyerror("can only use ... as final argument in list");
+			n->right->op = OTARRAY;
+			n->right->right = n->right->left;
+			n->right->left = N;
+			n->isddd = 1;
+			if(n->left != N)
+				n->left->isddd = 1;
+		}
+		l->n = n;
+	}
+	return all;
+}
+
+
+Node*
+fakethis(void)
+{
+	Node *n;
+
+	n = nod(ODCLFIELD, N, typenod(ptrto(typ(TSTRUCT))));
+	return n;
+}
+
+/*
+ * Is this field a method on an interface?
+ * Those methods have an anonymous
+ * *struct{} as the receiver.
+ * (See fakethis above.)
+ */
+int
+isifacemethod(Type *f)
+{
+	Type *rcvr;
+	Type *t;
+
+	rcvr = getthisx(f)->type;
+	if(rcvr->sym != S)
+		return 0;
+	t = rcvr->type;
+	if(!isptr[t->etype])
+		return 0;
+	t = t->type;
+	if(t->sym != S || t->etype != TSTRUCT || t->type != T)
+		return 0;
+	return 1;
+}
+
+/*
+ * turn a parsed function declaration
+ * into a type
+ */
+Type*
+functype(Node *this, NodeList *in, NodeList *out)
+{
+	Type *t;
+	NodeList *rcvr;
+	Sym *s;
+
+	t = typ(TFUNC);
+
+	rcvr = nil;
+	if(this)
+		rcvr = list1(this);
+	t->type = tofunargs(rcvr);
+	t->type->down = tofunargs(out);
+	t->type->down->down = tofunargs(in);
+
+	uniqgen++;
+	checkdupfields(t->type->type, "argument");
+	checkdupfields(t->type->down->type, "argument");
+	checkdupfields(t->type->down->down->type, "argument");
+
+	if (t->type->broke || t->type->down->broke || t->type->down->down->broke)
+		t->broke = 1;
+
+	if(this)
+		t->thistuple = 1;
+	t->outtuple = count(out);
+	t->intuple = count(in);
+	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] != '~' || s->name[1] != 'r')) // ~r%d is the name invented for an unnamed result
+			t->outnamed = 1;
+	}
+
+	return t;
+}
+
+Sym*
+methodsym(Sym *nsym, Type *t0, int iface)
+{
+	Sym *s;
+	char *p;
+	Type *t;
+	char *suffix;
+	Pkg *spkg;
+	static Pkg *toppkg;
+
+	t = t0;
+	if(t == T)
+		goto bad;
+	s = t->sym;
+	if(s == S && isptr[t->etype]) {
+		t = t->type;
+		if(t == T)
+			goto bad;
+		s = t->sym;
+	}
+	spkg = nil;
+	if(s != S)
+		spkg = s->pkg;
+
+	// if t0 == *t and t0 has a sym,
+	// we want to see *t, not t0, in the method name.
+	if(t != t0 && t0->sym)
+		t0 = ptrto(t);
+
+	suffix = "";
+	if(iface) {
+		dowidth(t0);
+		if(t0->width < types[tptr]->width)
+			suffix = "·i";
+	}
+	if((spkg == nil || nsym->pkg != spkg) && !exportname(nsym->name)) {
+		if(t0->sym == S && isptr[t0->etype])
+			p = smprint("(%-hT).%s.%s%s", t0, nsym->pkg->prefix, nsym->name, suffix);
+		else
+			p = smprint("%-hT.%s.%s%s", t0, nsym->pkg->prefix, nsym->name, suffix);
+	} else {
+		if(t0->sym == S && isptr[t0->etype])
+			p = smprint("(%-hT).%s%s", t0, nsym->name, suffix);
+		else
+			p = smprint("%-hT.%s%s", t0, nsym->name, suffix);
+	}
+	if(spkg == nil) {
+		if(toppkg == nil)
+			toppkg = mkpkg(strlit("go"));
+		spkg = toppkg;
+	}
+	s = pkglookup(p, spkg);
+	free(p);
+	return s;
+
+bad:
+	yyerror("illegal receiver type: %T", t0);
+	return S;
+}
+
+Node*
+methodname(Node *n, Type *t)
+{
+	Sym *s;
+
+	s = methodsym(n->sym, t, 0);
+	if(s == S)
+		return n;
+	return newname(s);
+}
+
+Node*
+methodname1(Node *n, Node *t)
+{
+	char *star;
+	char *p;
+
+	star = nil;
+	if(t->op == OIND) {
+		star = "*";
+		t = t->left;
+	}
+	if(t->sym == S || isblank(n))
+		return newname(n->sym);
+
+	if(star)
+		p = smprint("(%s%S).%S", star, t->sym, n->sym);
+	else
+		p = smprint("%S.%S", t->sym, n->sym);
+
+	if(exportname(t->sym->name))
+		n = newname(lookup(p));
+	else
+		n = newname(pkglookup(p, t->sym->pkg));
+	free(p);
+	return n;
+}
+
+/*
+ * add a method, declared as a function,
+ * n is fieldname, pa is base type, t is function type
+ */
+void
+addmethod(Sym *sf, Type *t, int local, int nointerface)
+{
+	Type *f, *d, *pa;
+	Node *n;
+
+	// get field sym
+	if(sf == S)
+		fatal("no method symbol");
+
+	// get parent type sym
+	pa = getthisx(t)->type;	// ptr to this structure
+	if(pa == T) {
+		yyerror("missing receiver");
+		return;
+	}
+
+	pa = pa->type;
+	f = methtype(pa, 1);
+	if(f == T) {
+		t = pa;
+		if(t == T) // rely on typecheck having complained before
+			return;
+		if(t != T) {
+			if(isptr[t->etype]) {
+				if(t->sym != S) {
+					yyerror("invalid receiver type %T (%T is a pointer type)", pa, t);
+					return;
+				}
+				t = t->type;
+			}
+			if(t->broke) // rely on typecheck having complained before
+				return;
+			if(t->sym == S) {
+				yyerror("invalid receiver type %T (%T is an unnamed type)", pa, t);
+				return;
+			}
+			if(isptr[t->etype]) {
+				yyerror("invalid receiver type %T (%T is a pointer type)", pa, t);
+				return;
+			}
+			if(t->etype == TINTER) {
+				yyerror("invalid receiver type %T (%T is an interface type)", pa, t);
+				return;
+			}
+		}
+		// Should have picked off all the reasons above,
+		// but just in case, fall back to generic error.
+		yyerror("invalid receiver type %T (%lT / %lT)", pa, pa, t);
+		return;
+	}
+
+	pa = f;
+	if(pa->etype == TSTRUCT) {
+		for(f=pa->type; f; f=f->down) {
+			if(f->sym == sf) {
+				yyerror("type %T has both field and method named %S", pa, sf);
+				return;
+			}
+		}
+	}
+
+	if(local && !pa->local) {
+		// defining method on non-local type.
+		yyerror("cannot define new methods on non-local type %T", pa);
+		return;
+	}
+
+	n = nod(ODCLFIELD, newname(sf), N);
+	n->type = t;
+
+	d = T;	// last found
+	for(f=pa->method; f!=T; f=f->down) {
+		d = f;
+		if(f->etype != TFIELD)
+			fatal("addmethod: not TFIELD: %N", f);
+		if(strcmp(sf->name, f->sym->name) != 0)
+			continue;
+		if(!eqtype(t, f->type))
+			yyerror("method redeclared: %T.%S\n\t%T\n\t%T", pa, sf, f->type, t);
+		return;
+	}
+
+	f = structfield(n);
+	f->nointerface = nointerface;
+
+	// during import unexported method names should be in the type's package
+	if(importpkg && f->sym && !exportname(f->sym->name) && f->sym->pkg != structpkg)
+		fatal("imported method name %+S in wrong package %s\n", f->sym, structpkg->name);
+
+	if(d == T)
+		pa->method = f;
+	else
+		d->down = f;
+	return;
+}
+
+void
+funccompile(Node *n, int isclosure)
+{
+	stksize = BADWIDTH;
+	maxarg = 0;
+
+	if(n->type == T) {
+		if(nerrors == 0)
+			fatal("funccompile missing type");
+		return;
+	}
+
+	// assign parameter offsets
+	checkwidth(n->type);
+	
+	// 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;
+		for(l=n->nname->ntype->list; l; l=l->next) {
+			nodfp->xoffset += widthptr;
+			if(l->n->left == N)	// found slot for PC
+				break;
+		}
+	}
+
+	if(curfn)
+		fatal("funccompile %S inside %S", n->nname->sym, curfn->nname->sym);
+
+	stksize = 0;
+	dclcontext = PAUTO;
+	funcdepth = n->funcdepth + 1;
+	compile(n);
+	curfn = nil;
+	funcdepth = 0;
+	dclcontext = PEXTERN;
+}
+
+Sym*
+funcsym(Sym *s)
+{
+	char *p;
+	Sym *s1;
+	
+	p = smprint("%s·f", s->name);
+	s1 = pkglookup(p, s->pkg);
+	free(p);
+	if(s1->def == N) {
+		s1->def = newname(s1);
+		s1->def->shortname = newname(s);
+		funcsyms = list(funcsyms, s1->def);
+	}
+	return s1;
+}
diff --git a/src/cmd/gc/doc.go b/src/cmd/gc/doc.go
new file mode 100644
index 0000000..03df93a
--- /dev/null
+++ b/src/cmd/gc/doc.go
@@ -0,0 +1,95 @@
+// 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
+
+/*
+
+Gc is the generic label for the family of Go compilers
+that function as part of the (modified) Plan 9 tool chain.  The C compiler
+documentation at
+
+	http://plan9.bell-labs.com/sys/doc/comp.pdf     (Tools overview)
+	http://plan9.bell-labs.com/sys/doc/compiler.pdf (C compiler architecture)
+
+gives the overall design of the tool chain.  Aside from a few adapted pieces,
+such as the optimizer, the Go compilers are wholly new programs.
+
+The compiler reads in a set of Go files, typically suffixed ".go".  They
+must all be part of one package.  The output is a single intermediate file
+representing the "binary assembly" of the compiled package, ready as input
+for the linker (6l, etc.).
+
+The generated files contain type information about the symbols exported by
+the package and about types used by symbols imported by the package from
+other packages. It is therefore not necessary when compiling client C of
+package P to read the files of P's dependencies, only the compiled output
+of P.
+
+Command Line
+
+Usage:
+	go tool 6g [flags] file...
+The specified files must be Go source files and all part of the same package.
+Substitute 6g with 8g or 5g where appropriate.
+
+Flags:
+	-o file
+		output file, default 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
+		assume that path is the eventual import path for this code,
+		and diagnose any attempt to import a package that depends on it.
+	-D path
+		treat a relative import as relative to path
+	-L
+		show entire file path when printing line numbers in errors
+	-I dir1 -I dir2
+		add dir1 and dir2 to the list of paths to check for imported packages
+	-N
+		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; implies -nolocalimports
+	-V
+		print the compiler version
+	-race
+		compile with race detection enabled
+
+There are also a number of debugging flags; run the command with no arguments
+to get a usage message.
+
+Compiler Directives
+
+The compiler accepts two compiler directives in the form of // comments at the
+beginning of a line. To distinguish them from non-directive comments, the directives
+require no space between the slashes and the name of the directive. However, since
+they are comments, tools unaware of the directive convention or of a particular
+directive can skip over a directive like any other comment.
+
+    //line path/to/file:linenumber
+
+The //line directive specifies that the source line that follows should be recorded
+as having come from the given file path and line number. Successive lines are
+recorded using increasing line numbers, until the next directive. This directive
+typically appears in machine-generated code, so that compilers and debuggers
+will show lines in the original input to the generator.
+
+    //go:noescape
+
+The //go:noescape directive specifies that the next declaration in the file, which
+must be a func without a body (meaning that it has an implementation not written
+in Go) does not allow any of the pointers passed as arguments to escape into the
+heap or into the values returned from the function. This information can be used as
+during the compiler's escape analysis of Go code calling the function.
+*/
+package main
diff --git a/src/cmd/gc/esc.c b/src/cmd/gc/esc.c
new file mode 100644
index 0000000..324f24f
--- /dev/null
+++ b/src/cmd/gc/esc.c
@@ -0,0 +1,1281 @@
+// 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.
+
+// Escape analysis.
+
+#include <u.h>
+#include <libc.h>
+#include "go.h"
+
+// Run analysis on minimal sets of mutually recursive functions
+// or single non-recursive functions, bottom up.
+//
+// Finding these sets is finding strongly connected components
+// in the static call graph.  The algorithm for doing that is taken
+// from Sedgewick, Algorithms, Second Edition, p. 482, with two
+// adaptations.
+//
+// First, a hidden closure function (n->curfn != N) cannot be the
+// root of a connected component. Refusing to use it as a root
+// forces it into the component of the function in which it appears.
+// The analysis assumes that closures and the functions in which they
+// appear are analyzed together, so that the aliasing between their
+// variables can be modeled more precisely.
+//
+// Second, each function becomes two virtual nodes in the graph,
+// with numbers n and n+1. We record the function's node number as n
+// but search from node n+1. If the search tells us that the component
+// number (min) is n+1, we know that this is a trivial component: one function
+// plus its closures. If the search tells us that the component number is
+// n, then there was a path from node n+1 back to node n, meaning that
+// the function set is mutually recursive. The escape analysis can be
+// more precise when analyzing a single non-recursive function than
+// when analyzing a set of mutually recursive functions.
+
+static NodeList *stack;
+static uint32 visitgen;
+static uint32 visit(Node*);
+static uint32 visitcode(Node*, uint32);
+static uint32 visitcodelist(NodeList*, uint32);
+
+static void analyze(NodeList*, int);
+
+enum
+{
+	EscFuncUnknown = 0,
+	EscFuncPlanned,
+	EscFuncStarted,
+	EscFuncTagged,
+};
+
+void
+escapes(NodeList *all)
+{
+	NodeList *l;
+
+	for(l=all; l; l=l->next)
+		l->n->walkgen = 0;
+
+	visitgen = 0;
+	for(l=all; l; l=l->next)
+		if(l->n->op == ODCLFUNC && l->n->curfn == N)
+			visit(l->n);
+
+	for(l=all; l; l=l->next)
+		l->n->walkgen = 0;
+}
+
+static uint32
+visit(Node *n)
+{
+	uint32 min, recursive;
+	NodeList *l, *block;
+
+	if(n->walkgen > 0) {
+		// already visited
+		return n->walkgen;
+	}
+	
+	visitgen++;
+	n->walkgen = visitgen;
+	visitgen++;
+	min = visitgen;
+
+	l = mal(sizeof *l);
+	l->next = stack;
+	l->n = n;
+	stack = l;
+	min = visitcodelist(n->nbody, min);
+	if((min == n->walkgen || min == n->walkgen+1) && n->curfn == N) {
+		// This node is the root of a strongly connected component.
+
+		// The original min passed to visitcodelist was n->walkgen+1.
+		// If visitcodelist found its way back to n->walkgen, then this
+		// block is a set of mutually recursive functions.
+		// Otherwise it's just a lone function that does not recurse.
+		recursive = min == n->walkgen;
+
+		// Remove connected component from stack.
+		// Mark walkgen so that future visits return a large number
+		// so as not to affect the caller's min.
+		block = stack;
+		for(l=stack; l->n != n; l=l->next)
+			l->n->walkgen = (uint32)~0U;
+		n->walkgen = (uint32)~0U;
+		stack = l->next;
+		l->next = nil;
+
+		// Run escape analysis on this set of functions.
+		analyze(block, recursive);
+	}
+
+	return min;
+}
+
+static uint32
+visitcodelist(NodeList *l, uint32 min)
+{
+	for(; l; l=l->next)
+		min = visitcode(l->n, min);
+	return min;
+}
+
+static uint32
+visitcode(Node *n, uint32 min)
+{
+	Node *fn;
+	uint32 m;
+
+	if(n == N)
+		return min;
+
+	min = visitcodelist(n->ninit, min);
+	min = visitcode(n->left, min);
+	min = visitcode(n->right, min);
+	min = visitcodelist(n->list, min);
+	min = visitcode(n->ntest, min);
+	min = visitcode(n->nincr, min);
+	min = visitcodelist(n->nbody, min);
+	min = visitcodelist(n->nelse, min);
+	min = visitcodelist(n->rlist, min);
+	
+	if(n->op == OCALLFUNC || n->op == OCALLMETH) {
+		fn = n->left;
+		if(n->op == OCALLMETH)
+			fn = n->left->right->sym->def;
+		if(fn && fn->op == ONAME && fn->class == PFUNC && fn->defn)
+			if((m = visit(fn->defn)) < min)
+				min = m;
+	}
+	
+	if(n->op == OCLOSURE)
+		if((m = visit(n->closure)) < min)
+			min = m;
+
+	return min;
+}
+
+// An escape analysis pass for a set of functions.
+//
+// First escfunc, esc and escassign recurse over the ast of each
+// function to dig out flow(dst,src) edges between any
+// pointer-containing nodes and store them in dst->escflowsrc.  For
+// variables assigned to a variable in an outer scope or used as a
+// return value, they store a flow(theSink, src) edge to a fake node
+// 'the Sink'.  For variables referenced in closures, an edge
+// flow(closure, &var) is recorded and the flow of a closure itself to
+// an outer scope is tracked the same way as other variables.
+//
+// Then escflood walks the graph starting at theSink and tags all
+// variables of it can reach an & node as escaping and all function
+// parameters it can reach as leaking.
+//
+// If a value's address is taken but the address does not escape,
+// then the value can stay on the stack.  If the value new(T) does
+// not escape, then new(T) can be rewritten into a stack allocation.
+// The same is true of slice literals.
+//
+// If optimizations are disabled (-N), this code is not used.
+// Instead, the compiler assumes that any value whose address
+// is taken without being immediately dereferenced
+// needs to be moved to the heap, and new(T) and slice
+// literals are always real allocations.
+
+typedef struct EscState EscState;
+
+static void escfunc(EscState*, Node *func);
+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*, 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);
+static void esctag(EscState*, Node *func);
+
+struct EscState {
+	// Fake node that all
+	//   - return values and output variables
+	//   - parameters on imported functions not marked 'safe'
+	//   - assignments to global variables
+	// 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.
+	int	dstcount, edgecount;	// diagnostic
+	NodeList*	noesc;	// list of possible non-escaping nodes, for printing
+	int	recursive;	// recursive function or group of mutually recursive functions.
+};
+
+static Strlit *tags[16];
+
+static Strlit*
+mktag(int mask)
+{
+	Strlit *s;
+	char buf[40];
+
+	switch(mask&EscMask) {
+	case EscNone:
+	case EscReturn:
+		break;
+	default:
+		fatal("escape mktag");
+	}
+
+	mask >>= EscBits;
+
+	if(mask < nelem(tags) && tags[mask] != nil)
+		return tags[mask];
+
+	snprint(buf, sizeof buf, "esc:0x%x", mask);
+	s = strlit(buf);
+	if(mask < nelem(tags))
+		tags[mask] = s;
+	return s;
+}
+
+static int
+parsetag(Strlit *note)
+{
+	int em;
+
+	if(note == nil)
+		return EscUnknown;
+	if(strncmp(note->s, "esc:", 4) != 0)
+		return EscUnknown;
+	em = atoi(note->s + 4);
+	if (em == 0)
+		return EscNone;
+	return EscReturn | (em << EscBits);
+}
+
+static void
+analyze(NodeList *all, int recursive)
+{
+	NodeList *l;
+	EscState es, *e;
+	
+	memset(&es, 0, sizeof es);
+	e = &es;
+	e->theSink.op = ONAME;
+	e->theSink.orig = &e->theSink;
+	e->theSink.class = PEXTERN;
+	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;
+
+	// flow-analyze functions
+	for(l=all; l; l=l->next)
+		if(l->n->op == ODCLFUNC)
+			escfunc(e, l->n);
+
+	// print("escapes: %d e->dsts, %d edges\n", e->dstcount, e->edgecount);
+
+	// visit the upstream of each dst, mark address nodes with
+	// addrescapes, mark parameters unsafe
+	for(l = e->dsts; l; l=l->next)
+		escflood(e, l->n);
+
+	// for all top level functions, tag the typenodes corresponding to the param nodes
+	for(l=all; l; l=l->next)
+		if(l->n->op == ODCLFUNC)
+			esctag(e, l->n);
+
+	if(debug['m']) {
+		for(l=e->noesc; l; l=l->next)
+			if(l->n->esc == EscNone)
+				warnl(l->n->lineno, "%S %hN does not escape",
+					(l->n->curfn && l->n->curfn->nname) ? l->n->curfn->nname->sym : S,
+					l->n);
+	}
+}
+
+
+static void
+escfunc(EscState *e, Node *func)
+{
+	Node *savefn;
+	NodeList *ll;
+	int saveld;
+
+//	print("escfunc %N %s\n", func->nname, e->recursive?"(recursive)":"");
+
+	if(func->esc != 1)
+		fatal("repeat escfunc %N", func->nname);
+	func->esc = EscFuncStarted;
+
+	saveld = e->loopdepth;
+	e->loopdepth = 1;
+	savefn = curfn;
+	curfn = func;
+
+	for(ll=curfn->dcl; ll; ll=ll->next) {
+		if(ll->n->op != ONAME)
+			continue;
+		switch (ll->n->class) {
+		case PPARAMOUT:
+			// out params are in a loopdepth between the sink and all local variables
+			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)
+				ll->n->esc = EscHeap;
+			else
+				ll->n->esc = EscNone;	// prime for escflood later
+			e->noesc = list(e->noesc, ll->n);
+			break;
+		}
+	}
+
+	// in a mutually recursive group we lose track of the return values
+	if(e->recursive)
+		for(ll=curfn->dcl; ll; ll=ll->next)
+			if(ll->n->op == ONAME && ll->n->class == PPARAMOUT)
+				escflows(e, &e->theSink, ll->n);
+
+	escloopdepthlist(e, curfn->nbody);
+	esclist(e, curfn->nbody, curfn);
+	curfn = savefn;
+	e->loopdepth = saveld;
+}
+
+// Mark labels that have no backjumps to them as not increasing e->loopdepth.
+// Walk hasn't generated (goto|label)->left->sym->label yet, so we'll cheat
+// and set it to one of the following two.  Then in esc we'll clear it again.
+static Label looping;
+static Label nonlooping;
+
+static void
+escloopdepthlist(EscState *e, NodeList *l)
+{
+	for(; l; l=l->next)
+		escloopdepth(e, l->n);
+}
+
+static void
+escloopdepth(EscState *e, Node *n)
+{
+	if(n == N)
+		return;
+
+	escloopdepthlist(e, n->ninit);
+
+	switch(n->op) {
+	case OLABEL:
+		if(!n->left || !n->left->sym)
+			fatal("esc:label without label: %+N", n);
+		// Walk will complain about this label being already defined, but that's not until
+		// after escape analysis. in the future, maybe pull label & goto analysis out of walk and put before esc
+		// if(n->left->sym->label != nil)
+		//	fatal("escape analysis messed up analyzing label: %+N", n);
+		n->left->sym->label = &nonlooping;
+		break;
+	case OGOTO:
+		if(!n->left || !n->left->sym)
+			fatal("esc:goto without label: %+N", n);
+		// If we come past one that's uninitialized, this must be a (harmless) forward jump
+		// but if it's set to nonlooping the label must have preceded this goto.
+		if(n->left->sym->label == &nonlooping)
+			n->left->sym->label = &looping;
+		break;
+	}
+
+	escloopdepth(e, n->left);
+	escloopdepth(e, n->right);
+	escloopdepthlist(e, n->list);
+	escloopdepth(e, n->ntest);
+	escloopdepth(e, n->nincr);
+	escloopdepthlist(e, n->nbody);
+	escloopdepthlist(e, n->nelse);
+	escloopdepthlist(e, n->rlist);
+
+}
+
+static void
+esclist(EscState *e, NodeList *l, Node *up)
+{
+	for(; l; l=l->next)
+		esc(e, l->n, up);
+}
+
+static void
+esc(EscState *e, Node *n, Node *up)
+{
+	int lno;
+	NodeList *ll, *lr;
+	Node *a;
+
+	if(n == N)
+		return;
+
+	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++;
+
+	// 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--;
+
+	if(debug['m'] > 1)
+		print("%L:[%d] %S esc: %N\n", lineno, e->loopdepth,
+		      (curfn && curfn->nname) ? curfn->nname->sym : S, n);
+
+	switch(n->op) {
+	case ODCL:
+		// Record loop depth at declaration.
+		if(n->left)
+			n->left->escloopdepth = e->loopdepth;
+		break;
+
+	case OLABEL:
+		if(n->left->sym->label == &nonlooping) {
+			if(debug['m'] > 1)
+				print("%L:%N non-looping label\n", lineno, n);
+		} else if(n->left->sym->label == &looping) {
+			if(debug['m'] > 1)
+				print("%L: %N looping label\n", lineno, n);
+			e->loopdepth++;
+		}
+		// See case OLABEL in escloopdepth above
+		// else if(n->left->sym->label == nil)
+		//	fatal("escape analysis missed or messed up a label: %+N", n);
+
+		n->left->sym->label = nil;
+		break;
+
+	case ORANGE:
+		// Everything but fixed array is a dereference.
+		if(isfixedarray(n->type) && n->list && n->list->next)
+			escassign(e, n->list->next->n, n->right);
+		break;
+
+	case OSWITCH:
+		if(n->ntest && n->ntest->op == OTYPESW) {
+			for(ll=n->list; ll; ll=ll->next) {  // cases
+				// ntest->right is the argument of the .(type),
+				// ll->n->nname is the variable per case
+				escassign(e, ll->n->nname, n->ntest->right);
+			}
+		}
+		break;
+
+	case OAS:
+	case OASOP:
+		escassign(e, n->left, n->right);
+		break;
+
+	case OAS2:	// x,y = a,b
+		if(count(n->list) == count(n->rlist))
+			for(ll=n->list, lr=n->rlist; ll; ll=ll->next, lr=lr->next)
+				escassign(e, ll->n, lr->n);
+		break;
+
+	case OAS2RECV:		// v, ok = <-ch
+	case OAS2MAPR:		// v, ok = m[k]
+	case OAS2DOTTYPE:	// v, ok = x.(type)
+		escassign(e, n->list->n, n->rlist->n);
+		break;
+
+	case OSEND:		// ch <- x
+		escassign(e, &e->theSink, n->right);
+		break;
+
+	case ODEFER:
+		if(e->loopdepth == 1)  // top level
+			break;
+		// arguments leak out of scope
+		// TODO: leak to a dummy node instead
+		// fallthrough
+	case OPROC:
+		// go f(x) - f and x escape
+		escassign(e, &e->theSink, n->left->left);
+		escassign(e, &e->theSink, n->left->right);  // ODDDARG for call
+		for(ll=n->left->list; ll; ll=ll->next)
+			escassign(e, &e->theSink, ll->n);
+		break;
+
+	case OCALLMETH:
+	case OCALLFUNC:
+	case OCALLINTER:
+		esccall(e, n, up);
+		break;
+
+	case OAS2FUNC:	// x,y = f()
+		// esccall already done on n->rlist->n. tie it's escretval to n->list
+		lr=n->rlist->n->escretval;
+		for(ll=n->list; lr && ll; lr=lr->next, ll=ll->next)
+			escassign(e, ll->n, lr->n);
+		if(lr || ll)
+			fatal("esc oas2func");
+		break;
+
+	case ORETURN:
+		ll=n->list;
+		if(count(n->list) == 1 && curfn->type->outtuple > 1) {
+			// OAS2FUNC in disguise
+			// esccall already done on n->list->n
+			// tie n->list->n->escretval to curfn->dcl PPARAMOUT's
+			ll = n->list->n->escretval;
+		}
+
+		for(lr = curfn->dcl; lr && ll; lr=lr->next) {
+			if (lr->n->op != ONAME || lr->n->class != PPARAMOUT)
+				continue;
+			escassign(e, lr->n, ll->n);
+			ll = ll->next;
+		}
+		if (ll != nil)
+			fatal("esc return list");
+		break;
+
+	case OPANIC:
+		// Argument could leak through recover.
+		escassign(e, &e->theSink, n->left);
+		break;
+
+	case OAPPEND:
+		if(!n->isddd)
+			for(ll=n->list->next; ll; ll=ll->next)
+				escassign(e, &e->theSink, ll->n);  // lose track of assign to dereference
+		break;
+
+	case OCONV:
+	case OCONVNOP:
+	case OCONVIFACE:
+		escassign(e, n, n->left);
+		break;
+
+	case OARRAYLIT:
+		if(isslice(n->type)) {
+			n->esc = EscNone;  // until proven otherwise
+			e->noesc = list(e->noesc, n);
+			n->escloopdepth = e->loopdepth;
+			// Values make it to memory, lose track.
+			for(ll=n->list; ll; ll=ll->next)
+				escassign(e, &e->theSink, ll->n->right);
+		} else {
+			// Link values to array.
+			for(ll=n->list; ll; ll=ll->next)
+				escassign(e, n, ll->n->right);
+		}
+		break;
+
+	case OSTRUCTLIT:
+		// Link values to struct.
+		for(ll=n->list; ll; ll=ll->next)
+			escassign(e, n, ll->n->right);
+		break;
+	
+	case OPTRLIT:
+		n->esc = EscNone;  // until proven otherwise
+		e->noesc = list(e->noesc, n);
+		n->escloopdepth = e->loopdepth;
+		// Contents make it to memory, lose track.
+		escassign(e, &e->theSink, n->left);
+		break;
+	
+	case OCALLPART:
+		n->esc = EscNone; // until proven otherwise
+		e->noesc = list(e->noesc, n);
+		n->escloopdepth = e->loopdepth;
+		// Contents make it to memory, lose track.
+		escassign(e, &e->theSink, n->left);
+		break;
+
+	case OMAPLIT:
+		n->esc = EscNone;  // until proven otherwise
+		e->noesc = list(e->noesc, n);
+		n->escloopdepth = e->loopdepth;
+		// Keys and values make it to memory, lose track.
+		for(ll=n->list; ll; ll=ll->next) {
+			escassign(e, &e->theSink, ll->n->left);
+			escassign(e, &e->theSink, ll->n->right);
+		}
+		break;
+	
+	case OCLOSURE:
+		// Link addresses of captured variables to closure.
+		for(ll=n->cvars; ll; ll=ll->next) {
+			if(ll->n->op == OXXX)  // unnamed out argument; see dcl.c:/^funcargs
+				continue;
+			a = nod(OADDR, ll->n->closure, N);
+			a->lineno = ll->n->lineno;
+			a->escloopdepth = e->loopdepth;
+			typecheck(&a, Erv);
+			escassign(e, n, a);
+		}
+		// fallthrough
+	case OMAKECHAN:
+	case OMAKEMAP:
+	case OMAKESLICE:
+	case ONEW:
+		n->escloopdepth = e->loopdepth;
+		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;
+}
+
+// Assert that expr somehow gets assigned to dst, if non nil.  for
+// dst==nil, any name node expr still must be marked as being
+// evaluated in curfn.	For expr==nil, dst must still be examined for
+// evaluations inside it (e.g *f(x) = y)
+static void
+escassign(EscState *e, Node *dst, Node *src)
+{
+	int lno;
+	NodeList *ll;
+
+	if(isblank(dst) || dst == N || src == N || src->op == ONONAME || src->op == OXXX)
+		return;
+
+	if(debug['m'] > 1)
+		print("%L:[%d] %S escassign: %hN(%hJ) = %hN(%hJ)\n", lineno, e->loopdepth,
+		      (curfn && curfn->nname) ? curfn->nname->sym : S, dst, dst, src, src);
+
+	setlineno(dst);
+	
+	// Analyze lhs of assignment.
+	// Replace dst with e->theSink if we can't track it.
+	switch(dst->op) {
+	default:
+		dump("dst", dst);
+		fatal("escassign: unexpected dst");
+
+	case OARRAYLIT:
+	case OCLOSURE:
+	case OCONV:
+	case OCONVIFACE:
+	case OCONVNOP:
+	case OMAPLIT:
+	case OSTRUCTLIT:
+	case OCALLPART:
+		break;
+
+	case ONAME:
+		if(dst->class == PEXTERN)
+			dst = &e->theSink;
+		break;
+	case ODOT:	      // treat "dst.x  = src" as "dst = src"
+		escassign(e, dst->left, src);
+		return;
+	case OINDEX:
+		if(isfixedarray(dst->left->type)) {
+			escassign(e, dst->left, src);
+			return;
+		}
+		dst = &e->theSink;  // lose track of dereference
+		break;
+	case OIND:
+	case ODOTPTR:
+		dst = &e->theSink;  // lose track of dereference
+		break;
+	case OINDEXMAP:
+		// lose track of key and value
+		escassign(e, &e->theSink, dst->right);
+		dst = &e->theSink;
+		break;
+	}
+
+	lno = setlineno(src);
+	e->pdepth++;
+
+	switch(src->op) {
+	case OADDR:	// dst = &x
+	case OIND:	// dst = *x
+	case ODOTPTR:	// dst = (*x).f
+	case ONAME:
+	case OPARAM:
+	case ODDDARG:
+	case OPTRLIT:
+	case OARRAYLIT:
+	case OMAPLIT:
+	case OSTRUCTLIT:
+	case OMAKECHAN:
+	case OMAKEMAP:
+	case OMAKESLICE:
+	case ONEW:
+	case OCLOSURE:
+	case OCALLPART:
+		escflows(e, dst, src);
+		break;
+
+	case OCALLMETH:
+	case OCALLFUNC:
+	case OCALLINTER:
+		// Flowing multiple returns to a single dst happens when
+		// analyzing "go f(g())": here g() flows to sink (issue 4529).
+		for(ll=src->escretval; ll; ll=ll->next)
+			escflows(e, dst, ll->n);
+		break;
+
+	case ODOT:
+		// A non-pointer escaping from a struct does not concern us.
+		if(src->type && !haspointers(src->type))
+			break;
+		// fallthrough
+	case OCONV:
+	case OCONVIFACE:
+	case OCONVNOP:
+	case ODOTMETH:	// treat recv.meth as a value with recv in it, only happens in ODEFER and OPROC
+			// iface.method already leaks iface in esccall, no need to put in extra ODOTINTER edge here
+	case ODOTTYPE:
+	case ODOTTYPE2:
+	case OSLICE:
+	case OSLICE3:
+	case OSLICEARR:
+	case OSLICE3ARR:
+		// Conversions, field access, slice all preserve the input value.
+		escassign(e, dst, src->left);
+		break;
+
+	case OAPPEND:
+		// Append returns first argument.
+		escassign(e, dst, src->list->n);
+		break;
+	
+	case OINDEX:
+		// Index of array preserves input value.
+		if(isfixedarray(src->left->type))
+			escassign(e, dst, src->left);
+		break;
+
+	case OADD:
+	case OSUB:
+	case OOR:
+	case OXOR:
+	case OMUL:
+	case ODIV:
+	case OMOD:
+	case OLSH:
+	case ORSH:
+	case OAND:
+	case OANDNOT:
+	case OPLUS:
+	case OMINUS:
+	case OCOM:
+		// Might be pointer arithmetic, in which case
+		// the operands flow into the result.
+		// TODO(rsc): Decide what the story is here.  This is unsettling.
+		escassign(e, dst, src->left);
+		escassign(e, dst, src->right);
+		break;
+	}
+
+	e->pdepth--;
+	lineno = lno;
+}
+
+static int
+escassignfromtag(EscState *e, Strlit *note, NodeList *dsts, Node *src)
+{
+	int em, em0;
+	
+	em = parsetag(note);
+
+	if(em == EscUnknown) {
+		escassign(e, &e->theSink, src);
+		return em;
+	}
+
+	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
+// switch for clarity.	We either have the paramnodes, which may be
+// connected to other things through flows or we have the parameter type
+// nodes, which may be marked "noescape". Navigating the ast is slightly
+// different for methods vs plain functions and for imported vs
+// this-package
+static void
+esccall(EscState *e, Node *n, Node *up)
+{
+	NodeList *ll, *lr;
+	Node *a, *fn, *src;
+	Type *t, *fntype;
+	char buf[40];
+	int i;
+
+	fn = N;
+	switch(n->op) {
+	default:
+		fatal("esccall");
+
+	case OCALLFUNC:
+		fn = n->left;
+		fntype = fn->type;
+		break;
+
+	case OCALLMETH:
+		fn = n->left->right->sym->def;
+		if(fn)
+			fntype = fn->type;
+		else
+			fntype = n->left->type;
+		break;
+
+	case OCALLINTER:
+		fntype = n->left->type;
+		break;
+	}
+
+	ll = n->list;
+	if(n->list != nil && n->list->next == nil) {
+		a = n->list->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);
+		if(fn->defn->esc == EscFuncUnknown || n->escretval != nil)
+			fatal("graph inconsistency");
+
+		// set up out list on this call node
+		for(lr=fn->ntype->rlist; lr; lr=lr->next)
+			n->escretval = list(n->escretval, lr->n->left);  // type.rlist ->  dclfield -> ONAME (PPARAMOUT)
+
+		// Receiver.
+		if(n->op != OCALLFUNC)
+			escassign(e, fn->ntype->left->left, n->left->left);
+
+		for(lr=fn->ntype->list; ll && lr; ll=ll->next, lr=lr->next) {
+			src = ll->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
+				e->noesc = list(e->noesc, src);
+				n->right = src;
+			}
+			if(lr->n->left != N)
+				escassign(e, lr->n->left, src);
+			if(src != ll->n)
+				break;
+		}
+		// "..." arguments are untracked
+		for(; ll; ll=ll->next)
+			escassign(e, &e->theSink, ll->n);
+
+		return;
+	}
+
+	// Imported or completely analyzed function.  Use the escape tags.
+	if(n->escretval != nil)
+		fatal("esc already decorated call %+N\n", n);
+
+	// set up out list on this call node with dummy auto ONAMES in the current (calling) function.
+	i = 0;
+	for(t=getoutargx(fntype)->type; t; t=t->down) {
+		src = nod(ONAME, N, N);
+		snprint(buf, sizeof buf, ".dum%d", i++);
+		src->sym = lookup(buf);
+		src->type = t->type;
+		src->class = PAUTO;
+		src->curfn = curfn;
+		src->escloopdepth = e->loopdepth;
+		src->used = 1;
+		src->lineno = n->lineno;
+		n->escretval = list(n->escretval, src); 
+	}
+
+//	print("esc analyzed fn: %#N (%+T) returning (%+H)\n", fn, fntype, n->escretval);
+
+	// Receiver.
+	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;
+		if(t->isddd && !n->isddd) {
+			// Introduce ODDDARG node to represent ... allocation.
+			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;
+		}
+		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;
+	}
+	// "..." arguments are untracked
+	for(; ll; ll=ll->next)
+		escassign(e, &e->theSink, ll->n);
+}
+
+// Store the link src->dst in dst, throwing out some quick wins.
+static void
+escflows(EscState *e, Node *dst, Node *src)
+{
+	if(dst == nil || src == nil || dst == src)
+		return;
+
+	// Don't bother building a graph for scalars.
+	if(src->type && !haspointers(src->type))
+		return;
+
+	if(debug['m']>2)
+		print("%L::flows:: %hN <- %hN\n", lineno, dst, src);
+
+	if(dst->escflowsrc == nil) {
+		e->dsts = list(e->dsts, dst);
+		e->dstcount++;
+	}
+	e->edgecount++;
+
+	dst->escflowsrc = list(dst->escflowsrc, src);
+}
+
+// Whenever we hit a reference node, the level goes up by one, and whenever
+// we hit an OADDR, the level goes down by one. as long as we're on a level > 0
+// finding an OADDR just means we're following the upstream of a dereference,
+// so this address doesn't leak (yet).
+// If level == 0, it means the /value/ of this node can reach the root of this flood.
+// so if this node is an OADDR, it's argument should be marked as escaping iff
+// it's currfn/e->loopdepth are different from the flood's root.
+// Once an object has been moved to the heap, all of it's upstream should be considered
+// escaping to the global scope.
+static void
+escflood(EscState *e, Node *dst)
+{
+	NodeList *l;
+
+	switch(dst->op) {
+	case ONAME:
+	case OCLOSURE:
+		break;
+	default:
+		return;
+	}
+
+	if(debug['m']>1)
+		print("\nescflood:%d: dst %hN scope:%S[%d]\n", walkgen, dst,
+		      (dst->curfn && dst->curfn->nname) ? dst->curfn->nname->sym : S,
+		      dst->escloopdepth);
+
+	for(l = dst->escflowsrc; l; l=l->next) {
+		walkgen++;
+		escwalk(e, 0, dst, l->n);
+	}
+}
+
+// There appear to be some loops in the escape graph, causing
+// arbitrary recursion into deeper and deeper levels.
+// Cut this off safely by making minLevel sticky: once you
+// get that deep, you cannot go down any further but you also
+// cannot go up any further. This is a conservative fix.
+// Making minLevel smaller (more negative) would handle more
+// complex chains of indirections followed by address-of operations,
+// at the cost of repeating the traversal once for each additional
+// allowed level when a loop is encountered. Using -2 suffices to
+// pass all the tests we have written so far, which we assume matches
+// the level of complexity we want the escape analysis code to handle.
+#define MinLevel (-2)
+/*c2go enum { MinLevel = -2 };*/
+
+static void
+escwalk(EscState *e, int level, Node *dst, Node *src)
+{
+	NodeList *ll;
+	int leaks, newlevel;
+
+	if(src->walkgen == walkgen && src->esclevel <= level)
+		return;
+	src->walkgen = walkgen;
+	src->esclevel = level;
+
+	if(debug['m']>1)
+		print("escwalk: level:%d depth:%d %.*s %hN(%hJ) scope:%S[%d]\n",
+		      level, e->pdepth, e->pdepth, "\t\t\t\t\t\t\t\t\t\t", src, src,
+		      (src->curfn && src->curfn->nname) ? src->curfn->nname->sym : S, src->escloopdepth);
+
+	e->pdepth++;
+
+	// Input parameter flowing to output parameter?
+	if(dst->op == ONAME && dst->class == PPARAMOUT && dst->vargen <= 20) {
+		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) + 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;
+			}
+		}
+	}
+
+	// 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:
+		if(src->class == PPARAM && (leaks || dst->escloopdepth < 0) && src->esc != EscHeap) {
+			src->esc = EscScope;
+			if(debug['m'])
+				warnl(src->lineno, "leaking param: %hN", src);
+		}
+
+		// Treat a PPARAMREF closure variable as equivalent to the
+		// original variable.
+		if(src->class == PPARAMREF) {
+			if(leaks && debug['m'])
+				warnl(src->lineno, "leaking closure reference %hN", src);
+			escwalk(e, level, dst, src->closure);
+		}
+		break;
+
+	case OPTRLIT:
+	case OADDR:
+		if(leaks) {
+			src->esc = EscHeap;
+			addrescapes(src->left);
+			if(debug['m'])
+				warnl(src->lineno, "%hN escapes to heap", src);
+		}
+		newlevel = level;
+		if(level > MinLevel)
+			newlevel--;
+		escwalk(e, newlevel, dst, src->left);
+		break;
+
+	case OARRAYLIT:
+		if(isfixedarray(src->type))
+			break;
+		// fall through
+	case ODDDARG:
+	case OMAKECHAN:
+	case OMAKEMAP:
+	case OMAKESLICE:
+	case OMAPLIT:
+	case ONEW:
+	case OCLOSURE:
+	case OCALLPART:
+		if(leaks) {
+			src->esc = EscHeap;
+			if(debug['m'])
+				warnl(src->lineno, "%hN escapes to heap", src);
+		}
+		break;
+
+	case ODOT:
+	case OSLICE:
+	case OSLICEARR:
+	case OSLICE3:
+	case OSLICE3ARR:
+		escwalk(e, level, dst, src->left);
+		break;
+
+	case OINDEX:
+		if(isfixedarray(src->left->type)) {
+			escwalk(e, level, dst, src->left);
+			break;
+		}
+		// fall through
+	case ODOTPTR:
+	case OINDEXMAP:
+	case OIND:
+		newlevel = level;
+		if(level > MinLevel)
+			newlevel++;
+		escwalk(e, newlevel, dst, src->left);
+	}
+
+recurse:
+	for(ll=src->escflowsrc; ll; ll=ll->next)
+		escwalk(e, level, dst, ll->n);
+
+	e->pdepth--;
+}
+
+static void
+esctag(EscState *e, Node *func)
+{
+	Node *savefn;
+	NodeList *ll;
+	Type *t;
+
+	USED(e);
+	func->esc = EscFuncTagged;
+	
+	// External functions are assumed unsafe,
+	// unless //go:noescape is given before the declaration.
+	if(func->nbody == nil) {
+		if(func->noescape) {
+			for(t=getinargx(func->type)->type; t; t=t->down)
+				if(haspointers(t->type))
+					t->note = mktag(EscNone);
+		}
+		return;
+	}
+
+	savefn = curfn;
+	curfn = func;
+
+	for(ll=curfn->dcl; ll; ll=ll->next) {
+		if(ll->n->op != ONAME || ll->n->class != PPARAM)
+			continue;
+
+		switch (ll->n->esc&EscMask) {
+		case EscNone:	// not touched by escflood
+		case EscReturn:	
+			if(haspointers(ll->n->type)) // don't bother tagging for scalars
+				ll->n->paramfld->note = mktag(ll->n->esc);
+			break;
+		case EscHeap:	// touched by escflood, moved to heap
+		case EscScope:	// touched by escflood, value leaves scope
+			break;
+		}
+	}
+
+	curfn = savefn;
+}
diff --git a/src/cmd/gc/export.c b/src/cmd/gc/export.c
new file mode 100644
index 0000000..da5984c
--- /dev/null
+++ b/src/cmd/gc/export.c
@@ -0,0 +1,521 @@
+// 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	"go.h"
+#include	"y.tab.h"
+
+static void	dumpexporttype(Type *t);
+
+// Mark n's symbol as exported
+void
+exportsym(Node *n)
+{
+	if(n == N || n->sym == S)
+		return;
+	if(n->sym->flags & (SymExport|SymPackage)) {
+		if(n->sym->flags & SymPackage)
+			yyerror("export/package mismatch: %S", n->sym);
+		return;
+	}
+	n->sym->flags |= SymExport;
+
+	if(debug['E'])
+		print("export symbol %S\n", n->sym);
+	exportlist = list(exportlist, n);
+}
+
+int
+exportname(char *s)
+{
+	Rune r;
+
+	if((uchar)s[0] < Runeself)
+		return 'A' <= s[0] && s[0] <= 'Z';
+	chartorune(&r, s);
+	return isupperrune(r);
+}
+
+static int
+initname(char *s)
+{
+	return strcmp(s, "init") == 0;
+}
+
+// exportedsym reports whether a symbol will be visible
+// to files that import our package.
+static int
+exportedsym(Sym *sym)
+{
+	// Builtins are visible everywhere.
+	if(sym->pkg == builtinpkg || sym->origpkg == builtinpkg)
+		return 1;
+
+	return sym->pkg == localpkg && exportname(sym->name);
+}
+
+void
+autoexport(Node *n, int ctxt)
+{
+	if(n == N || n->sym == S)
+		return;
+	if((ctxt != PEXTERN && ctxt != PFUNC) || dclcontext != PEXTERN)
+		return;
+	if(n->ntype && n->ntype->op == OTFUNC && n->ntype->left)	// method
+		return;
+	// -A is for cmd/gc/mkbuiltin script, so export everything
+	if(debug['A'] || exportname(n->sym->name) || initname(n->sym->name))
+		exportsym(n);
+}
+
+static void
+dumppkg(Pkg *p)
+{
+	char *suffix;
+
+	if(p == nil || p == localpkg || p->exported || p == builtinpkg)
+		return;
+	p->exported = 1;
+	suffix = "";
+	if(!p->direct)
+		suffix = " // indirect";
+	Bprint(bout, "\timport %s \"%Z\"%s\n", p->name, p->path, suffix);
+}
+
+// Look for anything we need for the inline body
+static void reexportdep(Node *n);
+static void
+reexportdeplist(NodeList *ll)
+{
+	for(; ll ;ll=ll->next)
+		reexportdep(ll->n);
+}
+
+static void
+reexportdep(Node *n)
+{
+	Type *t;
+
+	if(!n)
+		return;
+
+	//print("reexportdep %+hN\n", n);
+	switch(n->op) {
+	case ONAME:
+		switch(n->class&~PHEAP) {
+		case PFUNC:
+			// methods will be printed along with their type
+			// nodes for T.Method expressions
+			if(n->left && n->left->op == OTYPE)
+				break;
+			// nodes for method calls.
+			if(!n->type || n->type->thistuple > 0)
+				break;
+			// fallthrough
+		case PEXTERN:
+			if(n->sym && !exportedsym(n->sym)) {
+				if(debug['E'])
+					print("reexport name %S\n", n->sym);
+				exportlist = list(exportlist, n);
+			}
+		}
+		break;
+
+	case ODCL:
+		// Local variables in the bodies need their type.
+		t = n->left->type;
+		if(t != types[t->etype] && t != idealbool && t != idealstring) {
+			if(isptr[t->etype])
+				t = t->type;
+			if(t && t->sym && t->sym->def && !exportedsym(t->sym)) {
+				if(debug['E'])
+					print("reexport type %S from declaration\n", t->sym);
+				exportlist = list(exportlist, t->sym->def);
+			}
+		}
+		break;
+
+	case OLITERAL:
+		t = n->type;
+		if(t != types[n->type->etype] && t != idealbool && t != idealstring) {
+			if(isptr[t->etype])
+				t = t->type;
+			if(t && t->sym && t->sym->def && !exportedsym(t->sym)) {
+				if(debug['E'])
+					print("reexport literal type %S\n", t->sym);
+				exportlist = list(exportlist, t->sym->def);
+			}
+		}
+		// fallthrough
+	case OTYPE:
+		if(n->sym && !exportedsym(n->sym)) {
+			if(debug['E'])
+				print("reexport literal/type %S\n", n->sym);
+			exportlist = list(exportlist, n);
+		}
+		break;
+
+	// for operations that need a type when rendered, put the type on the export list.
+	case OCONV:
+	case OCONVIFACE:
+	case OCONVNOP:
+	case ORUNESTR:
+	case OARRAYBYTESTR:
+	case OARRAYRUNESTR:
+	case OSTRARRAYBYTE:
+	case OSTRARRAYRUNE:
+	case ODOTTYPE:
+	case ODOTTYPE2:
+	case OSTRUCTLIT:
+	case OARRAYLIT:
+	case OPTRLIT:
+	case OMAKEMAP:
+	case OMAKESLICE:
+	case OMAKECHAN:
+		t = n->type;
+		if(!t->sym && t->type)
+			t = t->type;
+		if(t && t->sym && t->sym->def && !exportedsym(t->sym)) {
+			if(debug['E'])
+				print("reexport type for expression %S\n", t->sym);
+			exportlist = list(exportlist, t->sym->def);
+		}
+		break;
+	}
+
+	reexportdep(n->left);
+	reexportdep(n->right);
+	reexportdeplist(n->list);
+	reexportdeplist(n->rlist);
+	reexportdeplist(n->ninit);
+	reexportdep(n->ntest);
+	reexportdep(n->nincr);
+	reexportdeplist(n->nbody);
+	reexportdeplist(n->nelse);
+}
+
+
+static void
+dumpexportconst(Sym *s)
+{
+	Node *n;
+	Type *t;
+
+	n = s->def;
+	typecheck(&n, Erv);
+	if(n == N || n->op != OLITERAL)
+		fatal("dumpexportconst: oconst nil: %S", s);
+
+	t = n->type;	// may or may not be specified
+	dumpexporttype(t);
+
+	if(t != T && !isideal(t))
+		Bprint(bout, "\tconst %#S %#T = %#V\n", s, t, &n->val);
+	else
+		Bprint(bout, "\tconst %#S = %#V\n", s, &n->val);
+}
+
+static void
+dumpexportvar(Sym *s)
+{
+	Node *n;
+	Type *t;
+
+	n = s->def;
+	typecheck(&n, Erv|Ecall);
+	if(n == N || n->type == T) {
+		yyerror("variable exported but not defined: %S", s);
+		return;
+	}
+
+	t = n->type;
+	dumpexporttype(t);
+
+	if(t->etype == TFUNC && n->class == PFUNC) {
+		if (n->inl) {
+			// when lazily typechecking inlined bodies, some re-exported ones may not have been typechecked yet.
+			// currently that can leave unresolved ONONAMEs in import-dot-ed packages in the wrong package
+			if(debug['l'] < 2)
+				typecheckinl(n);
+			// NOTE: The space after %#S here is necessary for ld's export data parser.
+			Bprint(bout, "\tfunc %#S %#hT { %#H }\n", s, t, n->inl);
+			reexportdeplist(n->inl);
+		} else
+			Bprint(bout, "\tfunc %#S %#hT\n", s, t);
+	} else
+		Bprint(bout, "\tvar %#S %#T\n", s, t);
+}
+
+static int
+methcmp(const void *va, const void *vb)
+{
+	Type *a, *b;
+	
+	a = *(Type**)va;
+	b = *(Type**)vb;
+	return strcmp(a->sym->name, b->sym->name);
+}
+
+static void
+dumpexporttype(Type *t)
+{
+	Type *f;
+	Type **m;
+	int i, n;
+
+	if(t == T)
+		return;
+	if(t->printed || t == types[t->etype] || t == bytetype || t == runetype || t == errortype)
+		return;
+	t->printed = 1;
+
+	if(t->sym != S && t->etype != TFIELD)
+		dumppkg(t->sym->pkg);
+
+	dumpexporttype(t->type);
+	dumpexporttype(t->down);
+
+	if (t->sym == S || t->etype == TFIELD)
+		return;
+
+	n = 0;
+	for(f=t->method; f!=T; f=f->down) {	
+		dumpexporttype(f);
+		n++;
+	}
+
+	m = mal(n*sizeof m[0]);
+	i = 0;
+	for(f=t->method; f!=T; f=f->down)
+		m[i++] = f;
+	qsort(m, n, sizeof m[0], methcmp);
+
+	Bprint(bout, "\ttype %#S %#lT\n", t->sym, t);
+	for(i=0; i<n; i++) {
+		f = m[i];
+		if(f->nointerface)
+			Bprint(bout, "\t//go:nointerface\n");
+		if (f->type->nname && f->type->nname->inl) { // nname was set by caninl
+			// when lazily typechecking inlined bodies, some re-exported ones may not have been typechecked yet.
+			// currently that can leave unresolved ONONAMEs in import-dot-ed packages in the wrong package
+			if(debug['l'] < 2)
+				typecheckinl(f->type->nname);
+			Bprint(bout, "\tfunc (%#T) %#hhS %#hT { %#H }\n", getthisx(f->type)->type, f->sym, f->type, f->type->nname->inl);
+			reexportdeplist(f->type->nname->inl);
+		} else
+			Bprint(bout, "\tfunc (%#T) %#hhS %#hT\n", getthisx(f->type)->type, f->sym, f->type);
+	}
+}
+
+static void
+dumpsym(Sym *s)
+{
+	if(s->flags & SymExported)
+		return;
+	s->flags |= SymExported;
+
+	if(s->def == N) {
+		yyerror("unknown export symbol: %S", s);
+		return;
+	}
+//	print("dumpsym %O %+S\n", s->def->op, s);
+	dumppkg(s->pkg);
+
+	switch(s->def->op) {
+	default:
+		yyerror("unexpected export symbol: %O %S", s->def->op, s);
+		break;
+
+	case OLITERAL:
+		dumpexportconst(s);
+		break;
+
+	case OTYPE:
+		if(s->def->type->etype == TFORW)
+			yyerror("export of incomplete type %S", s);
+		else
+			dumpexporttype(s->def->type);
+		break;
+
+	case ONAME:
+		dumpexportvar(s);
+		break;
+	}
+}
+
+void
+dumpexport(void)
+{
+	NodeList *l;
+	int32 i, lno;
+	Pkg *p;
+
+	lno = lineno;
+
+	Bprint(bout, "\n$$\npackage %s", localpkg->name);
+	if(safemode)
+		Bprint(bout, " safe");
+	Bprint(bout, "\n");
+
+	for(i=0; i<nelem(phash); i++)
+		for(p=phash[i]; p; p=p->link)
+			if(p->direct)
+				dumppkg(p);
+
+	for(l=exportlist; l; l=l->next) {
+		lineno = l->n->lineno;
+		dumpsym(l->n->sym);
+	}
+
+	Bprint(bout, "\n$$\n");
+	lineno = lno;
+}
+
+/*
+ * import
+ */
+
+/*
+ * return the sym for ss, which should match lexical
+ */
+Sym*
+importsym(Sym *s, int op)
+{
+	char *pkgstr;
+
+	if(s->def != N && s->def->op != op) {
+		pkgstr = smprint("during import \"%Z\"", importpkg->path);
+		redeclare(s, pkgstr);
+	}
+
+	// mark the symbol so it is not reexported
+	if(s->def == N) {
+		if(exportname(s->name) || initname(s->name))
+			s->flags |= SymExport;
+		else
+			s->flags |= SymPackage;	// package scope
+	}
+	return s;
+}
+
+/*
+ * return the type pkg.name, forward declaring if needed
+ */
+Type*
+pkgtype(Sym *s)
+{
+	Type *t;
+
+	importsym(s, OTYPE);
+	if(s->def == N || s->def->op != OTYPE) {
+		t = typ(TFORW);
+		t->sym = s;
+		s->def = typenod(t);
+	}
+	if(s->def->type == T)
+		yyerror("pkgtype %S", s);
+	return s->def->type;
+}
+
+void
+importimport(Sym *s, Strlit *z)
+{
+	// Informational: record package name
+	// associated with import path, for use in
+	// human-readable messages.
+	Pkg *p;
+
+	if(isbadimport(z))
+		errorexit();
+	p = mkpkg(z);
+	if(p->name == nil) {
+		p->name = s->name;
+		pkglookup(s->name, nil)->npkg++;
+	} else if(strcmp(p->name, s->name) != 0)
+		yyerror("conflicting names %s and %s for package \"%Z\"", p->name, s->name, p->path);
+	
+	if(!incannedimport && myimportpath != nil && strcmp(z->s, myimportpath) == 0) {
+		yyerror("import \"%Z\": package depends on \"%Z\" (import cycle)", importpkg->path, z);
+		errorexit();
+	}
+}
+
+void
+importconst(Sym *s, Type *t, Node *n)
+{
+	Node *n1;
+
+	importsym(s, OLITERAL);
+	convlit(&n, t);
+
+	if(s->def != N)	 // TODO: check if already the same.
+		return;
+
+	if(n->op != OLITERAL) {
+		yyerror("expression must be a constant");
+		return;
+	}
+
+	if(n->sym != S) {
+		n1 = nod(OXXX, N, N);
+		*n1 = *n;
+		n = n1;
+	}
+	n->orig = newname(s);
+	n->sym = s;
+	declare(n, PEXTERN);
+
+	if(debug['E'])
+		print("import const %S\n", s);
+}
+
+void
+importvar(Sym *s, Type *t)
+{
+	Node *n;
+
+	importsym(s, ONAME);
+	if(s->def != N && s->def->op == ONAME) {
+		if(eqtype(t, s->def->type))
+			return;
+		yyerror("inconsistent definition for var %S during import\n\t%T (in \"%Z\")\n\t%T (in \"%Z\")", s, s->def->type, s->importdef->path, t, importpkg->path);
+	}
+	n = newname(s);
+	s->importdef = importpkg;
+	n->type = t;
+	declare(n, PEXTERN);
+
+	if(debug['E'])
+		print("import var %S %lT\n", s, t);
+}
+
+void
+importtype(Type *pt, Type *t)
+{
+	Node *n;
+
+	// override declaration in unsafe.go for Pointer.
+	// there is no way in Go code to define unsafe.Pointer
+	// so we have to supply it.
+	if(incannedimport &&
+	   strcmp(importpkg->name, "unsafe") == 0 &&
+	   strcmp(pt->nod->sym->name, "Pointer") == 0) {
+		t = types[TUNSAFEPTR];
+	}
+
+	if(pt->etype == TFORW) {
+		n = pt->nod;
+		copytype(pt->nod, t);
+		pt->nod = n;		// unzero nod
+		pt->sym->importdef = importpkg;
+		pt->sym->lastlineno = parserline();
+		declare(n, PEXTERN);
+		checkwidth(pt);
+	} else if(!eqtype(pt->orig, t))
+		yyerror("inconsistent definition for type %S during import\n\t%lT (in \"%Z\")\n\t%lT (in \"%Z\")", pt->sym, pt, pt->sym->importdef->path, t, importpkg->path);
+
+	if(debug['E'])
+		print("import type %T %lT\n", pt, t);
+}
diff --git a/src/cmd/gc/fmt.c b/src/cmd/gc/fmt.c
new file mode 100644
index 0000000..89d2a14
--- /dev/null
+++ b/src/cmd/gc/fmt.c
@@ -0,0 +1,1691 @@
+// 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	<u.h>
+#include	<libc.h>
+#include	"go.h"
+#include	"opnames.h"
+
+//
+// Format conversions
+//	%L int		Line numbers
+//
+//	%E int		etype values (aka 'Kind')
+//
+//	%O int		Node Opcodes
+//		Flags: "%#O": print go syntax. (automatic unless fmtmode == FDbg)
+//
+//	%J Node*	Node details
+//		Flags: "%hJ" suppresses things not relevant until walk.
+//
+//	%V Val*		Constant values
+//
+//	%S Sym*		Symbols
+//		Flags: +,- #: mode (see below)
+//			"%hS"	unqualified identifier in any mode
+//			"%hhS"  in export mode: unqualified identifier if exported, qualified if not
+//
+//	%T Type*	Types
+//		Flags: +,- #: mode (see below)
+//			'l' definition instead of name.
+//			'h' omit "func" and receiver in function types
+//			'u' (only in -/Sym mode) print type identifiers wit package name instead of prefix.
+//
+//	%N Node*	Nodes
+//		Flags: +,- #: mode (see below)
+//			'h' (only in +/debug mode) suppress recursion
+//			'l' (only in Error mode) print "foo (type Bar)"
+//
+//	%H NodeList*	NodeLists
+//		Flags: those of %N
+//			','  separate items with ',' instead of ';'
+//
+//	%Z Strlit*	String literals
+//
+//   In mparith1.c:
+//      %B Mpint*	Big integers
+//	%F Mpflt*	Big floats
+//
+//   %S, %T and %N obey use the following flags to set the format mode:
+enum {
+	FErr,	//     error mode (default)
+	FDbg,	//     "%+N" debug mode
+	FExp,	//     "%#N" export mode
+	FTypeId,  //   "%-N" turning-types-into-symbols-mode: identical types give identical strings
+};
+static int fmtmode;
+static int fmtpkgpfx;	// %uT stickyness
+//
+// E.g. for %S:	%+S %#S %-S	print an identifier properly qualified for debug/export/internal mode.
+//
+// The mode flags  +, - and # are sticky, meaning they persist through
+// recursions of %N, %T and %S, but not the h and l flags.  The u flag is
+// sticky only on %T recursions and only used in %-/Sym mode.
+
+//
+// Useful format combinations:
+//
+//	%+N   %+H	multiline recursive debug dump of node/nodelist
+//	%+hN  %+hH	non recursive debug dump
+//
+//	%#N   %#T	export format
+//	%#lT		type definition instead of name
+//	%#hT		omit"func" and receiver in function signature
+//
+//	%lN		"foo (type Bar)" for error messages
+//
+//	%-T		type identifiers
+//	%-hT		type identifiers without "func" and arg names in type signatures (methodsym)
+//	%-uT		type identifiers with package name instead of prefix (typesym, dcommontype, typehash)
+//
+
+
+static int
+setfmode(unsigned long *flags)
+{
+	int fm;
+
+	fm = fmtmode;
+	if(*flags & FmtSign)
+		fmtmode = FDbg;
+	else if(*flags & FmtSharp)
+		fmtmode = FExp;
+	else if(*flags & FmtLeft)
+		fmtmode = FTypeId;
+
+	*flags &= ~(FmtSharp|FmtLeft|FmtSign);
+	return fm;
+}
+
+// Fmt "%L": Linenumbers
+static int
+Lconv(Fmt *fp)
+{
+	return linklinefmt(ctxt, fp);
+}
+
+static char*
+goopnames[] =
+{
+	[OADDR]		= "&",
+	[OADD]		= "+",
+	[OADDSTR]	= "+",
+	[OANDAND]	= "&&",
+	[OANDNOT]	= "&^",
+	[OAND]		= "&",
+	[OAPPEND]	= "append",
+	[OAS]		= "=",
+	[OAS2]		= "=",
+	[OBREAK]	= "break",
+	[OCALL]		= "function call",	// not actual syntax
+	[OCAP]		= "cap",
+	[OCASE]		= "case",
+	[OCLOSE]	= "close",
+	[OCOMPLEX]	= "complex",
+	[OCOM]		= "^",
+	[OCONTINUE]	= "continue",
+	[OCOPY]		= "copy",
+	[ODEC]		= "--",
+	[ODELETE]	= "delete",
+	[ODEFER]	= "defer",
+	[ODIV]		= "/",
+	[OEQ]		= "==",
+	[OFALL]		= "fallthrough",
+	[OFOR]		= "for",
+	[OGE]		= ">=",
+	[OGOTO]		= "goto",
+	[OGT]		= ">",
+	[OIF]		= "if",
+	[OIMAG]		= "imag",
+	[OINC]		= "++",
+	[OIND]		= "*",
+	[OLEN]		= "len",
+	[OLE]		= "<=",
+	[OLSH]		= "<<",
+	[OLT]		= "<",
+	[OMAKE]		= "make",
+	[OMINUS]	= "-",
+	[OMOD]		= "%",
+	[OMUL]		= "*",
+	[ONEW]		= "new",
+	[ONE]		= "!=",
+	[ONOT]		= "!",
+	[OOROR]		= "||",
+	[OOR]		= "|",
+	[OPANIC]	= "panic",
+	[OPLUS]		= "+",
+	[OPRINTN]	= "println",
+	[OPRINT]	= "print",
+	[ORANGE]	= "range",
+	[OREAL]		= "real",
+	[ORECV]		= "<-",
+	[ORECOVER]	= "recover",
+	[ORETURN]	= "return",
+	[ORSH]		= ">>",
+	[OSELECT]	= "select",
+	[OSEND]		= "<-",
+	[OSUB]		= "-",
+	[OSWITCH]	= "switch",
+	[OXOR]		= "^",
+};
+
+// Fmt "%O":  Node opcodes
+static int
+Oconv(Fmt *fp)
+{
+	int o;
+
+	o = va_arg(fp->args, int);
+	if((fp->flags & FmtSharp) || fmtmode != FDbg)
+		if(o >= 0 && o < nelem(goopnames) && goopnames[o] != nil)
+			return fmtstrcpy(fp, goopnames[o]);
+
+	if(o >= 0 && o < nelem(opnames) && opnames[o] != nil)
+		return fmtstrcpy(fp, opnames[o]);
+
+	return fmtprint(fp, "O-%d", o);
+}
+
+static const char* classnames[] = {
+	"Pxxx",
+	"PEXTERN",
+	"PAUTO",
+	"PPARAM",
+	"PPARAMOUT",
+	"PPARAMREF",
+	"PFUNC",
+};
+
+// Fmt "%J": Node details.
+static int
+Jconv(Fmt *fp)
+{
+	Node *n;
+	char *s;
+	int c;
+
+	n = va_arg(fp->args, Node*);
+
+	c = fp->flags&FmtShort;
+
+	if(!c && n->ullman != 0)
+		fmtprint(fp, " u(%d)", n->ullman);
+
+	if(!c && n->addable != 0)
+		fmtprint(fp, " a(%d)", n->addable);
+
+	if(!c && n->vargen != 0)
+		fmtprint(fp, " g(%d)", n->vargen);
+
+	if(n->lineno != 0)
+		fmtprint(fp, " l(%d)", n->lineno);
+
+	if(!c && n->xoffset != BADWIDTH)
+		fmtprint(fp, " x(%lld%+lld)", n->xoffset, n->stkdelta);
+
+	if(n->class != 0) {
+		s = "";
+		if(n->class & PHEAP) s = ",heap";
+		if((n->class & ~PHEAP) < nelem(classnames))
+			fmtprint(fp, " class(%s%s)", classnames[n->class&~PHEAP], s);
+		else
+			fmtprint(fp, " class(%d?%s)", n->class&~PHEAP, s);
+	}
+
+	if(n->colas != 0)
+		fmtprint(fp, " colas(%d)", n->colas);
+
+	if(n->funcdepth != 0)
+		fmtprint(fp, " f(%d)", n->funcdepth);
+
+	switch(n->esc) {
+	case EscUnknown:
+		break;
+	case EscHeap:
+		fmtprint(fp, " esc(h)");
+		break;
+	case EscScope:
+		fmtprint(fp, " esc(s)");
+		break;
+	case EscNone:
+		fmtprint(fp, " esc(no)");
+		break;
+	case EscNever:
+		if(!c)
+			fmtprint(fp, " esc(N)");
+		break;
+	default:
+		fmtprint(fp, " esc(%d)", n->esc);
+		break;
+	}
+
+	if(n->escloopdepth)
+		fmtprint(fp, " ld(%d)", n->escloopdepth);
+
+	if(!c && n->typecheck != 0)
+		fmtprint(fp, " tc(%d)", n->typecheck);
+
+	if(!c && n->dodata != 0)
+		fmtprint(fp, " dd(%d)", n->dodata);
+
+	if(n->isddd != 0)
+		fmtprint(fp, " isddd(%d)", n->isddd);
+
+	if(n->implicit != 0)
+		fmtprint(fp, " implicit(%d)", n->implicit);
+
+	if(n->embedded != 0)
+		fmtprint(fp, " embedded(%d)", n->embedded);
+
+	if(!c && n->used != 0)
+		fmtprint(fp, " used(%d)", n->used);
+	return 0;
+}
+
+// Fmt "%V": Values
+static int
+Vconv(Fmt *fp)
+{
+	Val *v;
+	vlong x;
+
+	v = va_arg(fp->args, Val*);
+
+	switch(v->ctype) {
+	case CTINT:
+		if((fp->flags & FmtSharp) || fmtmode == FExp)
+			return fmtprint(fp, "%#B", v->u.xval);
+		return fmtprint(fp, "%B", v->u.xval);
+	case CTRUNE:
+		x = mpgetfix(v->u.xval);
+		if(' ' <= x && x < 0x80 && x != '\\' && x != '\'')
+			return fmtprint(fp, "'%c'", (int)x);
+		if(0 <= x && x < (1<<16))
+			return fmtprint(fp, "'\\u%04ux'", (int)x);
+		if(0 <= x && x <= Runemax)
+			return fmtprint(fp, "'\\U%08llux'", x);
+		return fmtprint(fp, "('\\x00' + %B)", v->u.xval);
+	case CTFLT:
+		if((fp->flags & FmtSharp) || fmtmode == FExp)
+			return fmtprint(fp, "%F", v->u.fval);
+		return fmtprint(fp, "%#F", v->u.fval);
+	case CTCPLX:
+		if((fp->flags & FmtSharp) || fmtmode == FExp)
+			return fmtprint(fp, "(%F+%Fi)", &v->u.cval->real, &v->u.cval->imag);
+		if(mpcmpfltc(&v->u.cval->real, 0) == 0)
+			return fmtprint(fp, "%#Fi", &v->u.cval->imag);
+		if(mpcmpfltc(&v->u.cval->imag, 0) == 0)
+			return fmtprint(fp, "%#F", &v->u.cval->real);
+		if(mpcmpfltc(&v->u.cval->imag, 0) < 0)
+			return fmtprint(fp, "(%#F%#Fi)", &v->u.cval->real, &v->u.cval->imag);
+		return fmtprint(fp, "(%#F+%#Fi)", &v->u.cval->real, &v->u.cval->imag);
+	case CTSTR:
+		return fmtprint(fp, "\"%Z\"", v->u.sval);
+	case CTBOOL:
+		if( v->u.bval)
+			return fmtstrcpy(fp, "true");
+		return fmtstrcpy(fp, "false");
+	case CTNIL:
+		return fmtstrcpy(fp, "nil");
+	}
+	return fmtprint(fp, "<ctype=%d>", v->ctype);
+}
+
+// Fmt "%Z": escaped string literals
+static int
+Zconv(Fmt *fp)
+{
+	Rune r;
+	Strlit *sp;
+	char *s, *se;
+	int n;
+
+	sp = va_arg(fp->args, Strlit*);
+	if(sp == nil)
+		return fmtstrcpy(fp, "<nil>");
+
+	s = sp->s;
+	se = s + sp->len;
+
+	// NOTE: Keep in sync with ../ld/go.c:/^Zconv.
+	while(s < se) {
+		n = chartorune(&r, s);
+		s += n;
+		switch(r) {
+		case Runeerror:
+			if(n == 1) {
+				fmtprint(fp, "\\x%02x", (uchar)*(s-1));
+				break;
+			}
+			// fall through
+		default:
+			if(r < ' ') {
+				fmtprint(fp, "\\x%02x", r);
+				break;
+			}
+			fmtrune(fp, r);
+			break;
+		case '\t':
+			fmtstrcpy(fp, "\\t");
+			break;
+		case '\n':
+			fmtstrcpy(fp, "\\n");
+			break;
+		case '\"':
+		case '\\':
+			fmtrune(fp, '\\');
+			fmtrune(fp, r);
+			break;
+		case 0xFEFF: // BOM, basically disallowed in source code
+			fmtstrcpy(fp, "\\uFEFF");
+			break;
+		}
+	}
+	return 0;
+}
+
+/*
+s%,%,\n%g
+s%\n+%\n%g
+s%^[	]*T%%g
+s%,.*%%g
+s%.+%	[T&]		= "&",%g
+s%^	........*\]%&~%g
+s%~	%%g
+*/
+
+static char*
+etnames[] =
+{
+	[TINT]		= "INT",
+	[TUINT]		= "UINT",
+	[TINT8]		= "INT8",
+	[TUINT8]	= "UINT8",
+	[TINT16]	= "INT16",
+	[TUINT16]	= "UINT16",
+	[TINT32]	= "INT32",
+	[TUINT32]	= "UINT32",
+	[TINT64]	= "INT64",
+	[TUINT64]	= "UINT64",
+	[TUINTPTR]	= "UINTPTR",
+	[TFLOAT32]	= "FLOAT32",
+	[TFLOAT64]	= "FLOAT64",
+	[TCOMPLEX64]	= "COMPLEX64",
+	[TCOMPLEX128]	= "COMPLEX128",
+	[TBOOL]		= "BOOL",
+	[TPTR32]	= "PTR32",
+	[TPTR64]	= "PTR64",
+	[TFUNC]		= "FUNC",
+	[TARRAY]	= "ARRAY",
+	[TSTRUCT]	= "STRUCT",
+	[TCHAN]		= "CHAN",
+	[TMAP]		= "MAP",
+	[TINTER]	= "INTER",
+	[TFORW]		= "FORW",
+	[TFIELD]	= "FIELD",
+	[TSTRING]	= "STRING",
+	[TANY]		= "ANY",
+};
+
+// Fmt "%E": etype
+static int
+Econv(Fmt *fp)
+{
+	int et;
+
+	et = va_arg(fp->args, int);
+	if(et >= 0 && et < nelem(etnames) && etnames[et] != nil)
+		return fmtstrcpy(fp, etnames[et]);
+	return fmtprint(fp, "E-%d", et);
+}
+
+// Fmt "%S": syms
+static int
+symfmt(Fmt *fp, Sym *s)
+{
+	char *p;
+
+	if(s->pkg && !(fp->flags&FmtShort)) {
+		switch(fmtmode) {
+		case FErr:	// This is for the user
+			if(s->pkg == localpkg)
+				return fmtstrcpy(fp, s->name);
+			// If the name was used by multiple packages, display the full path,
+			if(s->pkg->name && pkglookup(s->pkg->name, nil)->npkg > 1)
+				return fmtprint(fp, "\"%Z\".%s", s->pkg->path, s->name);
+			return fmtprint(fp, "%s.%s", s->pkg->name, s->name);
+		case FDbg:
+			return fmtprint(fp, "%s.%s", s->pkg->name, s->name);
+		case FTypeId:
+			if(fp->flags&FmtUnsigned)
+				return fmtprint(fp, "%s.%s", s->pkg->name, s->name);	// dcommontype, typehash
+			return fmtprint(fp, "%s.%s", s->pkg->prefix, s->name);	// (methodsym), typesym, weaksym
+		case FExp:
+			if(s->name && s->name[0] == '.')
+				fatal("exporting synthetic symbol %s", s->name);
+			if(s->pkg != builtinpkg)
+				return fmtprint(fp, "@\"%Z\".%s", s->pkg->path, s->name);
+		}
+	}
+
+	if(fp->flags&FmtByte) {  // FmtByte (hh) implies FmtShort (h)
+		// skip leading "type." in method name
+		p = utfrrune(s->name, '.');
+		if(p)
+			p++;
+		else
+			p = s->name;
+
+		// exportname needs to see the name without the prefix too.
+		if((fmtmode == FExp && !exportname(p)) || fmtmode == FDbg)
+			return fmtprint(fp, "@\"%Z\".%s", s->pkg->path, p);
+
+		return fmtstrcpy(fp, p);
+	}
+
+	return fmtstrcpy(fp, s->name);
+}
+
+static char*
+basicnames[] =
+{
+	[TINT]		= "int",
+	[TUINT]		= "uint",
+	[TINT8]		= "int8",
+	[TUINT8]	= "uint8",
+	[TINT16]	= "int16",
+	[TUINT16]	= "uint16",
+	[TINT32]	= "int32",
+	[TUINT32]	= "uint32",
+	[TINT64]	= "int64",
+	[TUINT64]	= "uint64",
+	[TUINTPTR]	= "uintptr",
+	[TFLOAT32]	= "float32",
+	[TFLOAT64]	= "float64",
+	[TCOMPLEX64]	= "complex64",
+	[TCOMPLEX128]	= "complex128",
+	[TBOOL]		= "bool",
+	[TANY]		= "any",
+	[TSTRING]	= "string",
+	[TNIL]		= "nil",
+	[TIDEAL]	= "untyped number",
+	[TBLANK]	= "blank",
+};
+
+static int
+typefmt(Fmt *fp, Type *t)
+{
+	Type *t1;
+	Sym *s;
+
+	if(t == T)
+		return fmtstrcpy(fp, "<T>");
+
+	if (t == bytetype || t == runetype) {
+		// in %-T mode collapse rune and byte with their originals.
+		if(fmtmode != FTypeId)
+			return fmtprint(fp, "%hS", t->sym);
+		t = types[t->etype];
+	}
+
+	if(t == errortype)
+		return fmtstrcpy(fp, "error");
+
+	// Unless the 'l' flag was specified, if the type has a name, just print that name.
+	if(!(fp->flags&FmtLong) && t->sym && t->etype != TFIELD && t != types[t->etype]) {
+		switch(fmtmode) {
+		case FTypeId:
+			if(fp->flags&FmtShort) {
+				if(t->vargen)
+					return fmtprint(fp, "%hS·%d", t->sym, t->vargen);
+				return fmtprint(fp, "%hS", t->sym);
+			}
+			if(fp->flags&FmtUnsigned)
+				return fmtprint(fp, "%uS", t->sym);
+			// fallthrough
+		case FExp:
+			if(t->sym->pkg == localpkg && t->vargen)
+				return fmtprint(fp, "%S·%d", t->sym, t->vargen);
+			break;
+		}
+		return fmtprint(fp, "%S", t->sym);
+	}
+
+	if(t->etype < nelem(basicnames) && basicnames[t->etype] != nil) {
+		if(fmtmode == FErr && (t == idealbool || t == idealstring))
+			fmtstrcpy(fp, "untyped ");
+		return fmtstrcpy(fp, basicnames[t->etype]);
+	}
+
+	if(fmtmode == FDbg)
+		fmtprint(fp, "%E-", t->etype);
+
+	switch(t->etype) {
+	case TPTR32:
+	case TPTR64:
+		if(fmtmode == FTypeId && (fp->flags&FmtShort))
+			return fmtprint(fp, "*%hT", t->type);
+		return fmtprint(fp, "*%T", t->type);
+
+	case TARRAY:
+		if(t->bound >= 0)
+			return fmtprint(fp, "[%lld]%T", t->bound, t->type);
+		if(t->bound == -100)
+			return fmtprint(fp, "[...]%T", t->type);
+		return fmtprint(fp, "[]%T", t->type);
+
+	case TCHAN:
+		switch(t->chan) {
+		case Crecv:
+			return fmtprint(fp, "<-chan %T", t->type);
+		case Csend:
+			return fmtprint(fp, "chan<- %T", t->type);
+		}
+
+		if(t->type != T && t->type->etype == TCHAN && t->type->sym == S && t->type->chan == Crecv)
+			return fmtprint(fp, "chan (%T)", t->type);
+		return fmtprint(fp, "chan %T", t->type);
+
+	case TMAP:
+		return fmtprint(fp, "map[%T]%T", t->down, t->type);
+
+	case TINTER:
+		fmtstrcpy(fp, "interface {");
+		for(t1=t->type; t1!=T; t1=t1->down)
+			if(exportname(t1->sym->name)) {
+				if(t1->down)
+					fmtprint(fp, " %hS%hT;", t1->sym, t1->type);
+				else
+					fmtprint(fp, " %hS%hT ", t1->sym, t1->type);
+			} else {
+				// non-exported method names must be qualified
+				if(t1->down)
+					fmtprint(fp, " %uS%hT;", t1->sym, t1->type);
+				else
+					fmtprint(fp, " %uS%hT ", t1->sym, t1->type);
+			}
+		fmtstrcpy(fp, "}");
+		return 0;
+
+	case TFUNC:
+		if(fp->flags & FmtShort) {
+			fmtprint(fp, "%T", getinargx(t));
+		} else {
+			if(t->thistuple)
+				fmtprint(fp, "method%T func%T", getthisx(t), getinargx(t));
+			else
+				fmtprint(fp, "func%T", getinargx(t));
+		}
+		switch(t->outtuple) {
+		case 0:
+			break;
+		case 1:
+			if(fmtmode != FExp) {
+				fmtprint(fp, " %T", getoutargx(t)->type->type);	 // struct->field->field's type
+				break;
+			}
+		default:
+			fmtprint(fp, " %T", getoutargx(t));
+			break;
+		}
+		return 0;
+
+	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->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) {
+			fmtstrcpy(fp, "(");
+			if(fmtmode == FTypeId || fmtmode == FErr) {	// no argument names on function signature, and no "noescape"/"nosplit" tags
+				for(t1=t->type; t1!=T; t1=t1->down)
+					if(t1->down)
+						fmtprint(fp, "%hT, ", t1);
+					else
+						fmtprint(fp, "%hT", t1);
+			} else {
+				for(t1=t->type; t1!=T; t1=t1->down)
+					if(t1->down)
+						fmtprint(fp, "%T, ", t1);
+					else
+						fmtprint(fp, "%T", t1);
+			}
+			fmtstrcpy(fp, ")");
+		} else {
+			fmtstrcpy(fp, "struct {");
+			for(t1=t->type; t1!=T; t1=t1->down)
+				if(t1->down)
+					fmtprint(fp, " %lT;", t1);
+				else
+					fmtprint(fp, " %lT ", t1);
+			fmtstrcpy(fp, "}");
+		}
+		return 0;
+
+	case TFIELD:
+		if(!(fp->flags&FmtShort)) {
+			s = t->sym;
+
+			// 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] == '~') {
+						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;
+			}
+			
+			if(s != S && !t->embedded) {
+				if(t->funarg)
+					fmtprint(fp, "%N ", t->nname);
+				else if(fp->flags&FmtLong)
+					fmtprint(fp, "%hhS ", s);  // qualify non-exported names (used on structs, not on funarg)
+				else 
+					fmtprint(fp, "%S ", s);
+			} else if(fmtmode == FExp) {
+				// TODO(rsc) this breaks on the eliding of unused arguments in the backend
+				// when this is fixed, the special case in dcl.c checkarglist can go.
+				//if(t->funarg)
+				//	fmtstrcpy(fp, "_ ");
+				//else
+				if(t->embedded && s->pkg != nil && s->pkg->path->len > 0)
+					fmtprint(fp, "@\"%Z\".? ", s->pkg->path);
+				else
+					fmtstrcpy(fp, "? ");
+			}
+		}
+
+		if(t->isddd)
+			fmtprint(fp, "...%T", t->type->type);
+		else
+			fmtprint(fp, "%T", t->type);
+
+		if(!(fp->flags&FmtShort) && t->note)
+			fmtprint(fp, " \"%Z\"", t->note);
+		return 0;
+
+	case TFORW:
+		if(t->sym)
+			return fmtprint(fp, "undefined %S", t->sym);
+		return fmtstrcpy(fp, "undefined");
+
+	case TUNSAFEPTR:
+		if(fmtmode == FExp)
+			return fmtprint(fp, "@\"unsafe\".Pointer");
+		return fmtprint(fp, "unsafe.Pointer");
+	}
+
+	if(fmtmode == FExp)
+		fatal("missing %E case during export", t->etype);
+	// Don't know how to handle - fall back to detailed prints.
+	return fmtprint(fp, "%E <%S> %T", t->etype, t->sym, t->type);
+}
+
+// Statements which may be rendered with a simplestmt as init.
+static int
+stmtwithinit(int op)
+{
+	switch(op) {
+	case OIF:
+	case OFOR:
+	case OSWITCH:
+		return 1;
+	}
+	return 0;
+}
+
+static int
+stmtfmt(Fmt *f, Node *n)
+{
+	int complexinit, simpleinit, extrablock;
+
+	// some statements allow for an init, but at most one,
+	// but we may have an arbitrary number added, eg by typecheck
+	// and inlining.  If it doesn't fit the syntax, emit an enclosing
+	// block starting with the init statements.
+
+	// if we can just say "for" n->ninit; ... then do so
+	simpleinit = n->ninit && !n->ninit->next && !n->ninit->n->ninit && stmtwithinit(n->op);
+	// otherwise, print the inits as separate statements
+	complexinit = n->ninit && !simpleinit && (fmtmode != FErr);
+	// but if it was for if/for/switch, put in an extra surrounding block to limit the scope
+	extrablock = complexinit && stmtwithinit(n->op);
+
+	if(extrablock)
+		fmtstrcpy(f, "{");
+
+	if(complexinit)
+		fmtprint(f, " %H; ", n->ninit);
+
+	switch(n->op){
+	case ODCL:
+		if(fmtmode == FExp) {
+			switch(n->left->class&~PHEAP) {
+			case PPARAM:
+			case PPARAMOUT:
+			case PAUTO:
+				fmtprint(f, "var %N %T", n->left, n->left->type);
+				goto ret;
+			}
+		}			
+		fmtprint(f, "var %S %T", n->left->sym, n->left->type);
+		break;
+
+	case ODCLFIELD:
+		if(n->left)
+			fmtprint(f, "%N %N", n->left, n->right);
+		else
+			fmtprint(f, "%N", n->right);
+		break;
+
+	case OAS:
+		// Don't export "v = <N>" initializing statements, hope they're always 
+		// preceded by the DCL which will be re-parsed and typecheck to reproduce
+		// the "v = <N>" again.
+		if(fmtmode == FExp && n->right == N)
+			break;
+
+		if(n->colas && !complexinit)
+			fmtprint(f, "%N := %N", n->left, n->right);
+		else
+			fmtprint(f, "%N = %N", n->left, n->right);
+		break;
+
+	case OASOP:
+		if(n->implicit) {
+			if(n->etype == OADD)
+				fmtprint(f, "%N++", n->left);
+			else
+				fmtprint(f, "%N--", n->left);
+			break;
+		}
+		fmtprint(f, "%N %#O= %N", n->left, n->etype, n->right);
+		break;
+
+	case OAS2:
+		if(n->colas && !complexinit) {
+			fmtprint(f, "%,H := %,H", n->list, n->rlist);
+			break;
+		}
+		// fallthrough
+	case OAS2DOTTYPE:
+	case OAS2FUNC:
+	case OAS2MAPR:
+	case OAS2RECV:
+		fmtprint(f, "%,H = %,H", n->list, n->rlist);
+		break;
+
+	case ORETURN:
+		fmtprint(f, "return %,H", n->list);
+		break;
+
+	case ORETJMP:
+		fmtprint(f, "retjmp %S", n->sym);
+		break;
+	
+	case OPROC:
+		fmtprint(f, "go %N", n->left);
+		break;
+
+	case ODEFER:
+		fmtprint(f, "defer %N", n->left);
+		break;
+
+	case OIF:
+		if(simpleinit)
+			fmtprint(f, "if %N; %N { %H }", n->ninit->n, n->ntest, n->nbody);
+		else
+			fmtprint(f, "if %N { %H }", n->ntest, n->nbody);
+		if(n->nelse)
+			fmtprint(f, " else { %H }", n->nelse);
+		break;
+
+	case OFOR:
+		if(fmtmode == FErr) {	// TODO maybe only if FmtShort, same below
+			fmtstrcpy(f, "for loop");
+			break;
+		}
+
+		fmtstrcpy(f, "for");
+		if(simpleinit)
+			fmtprint(f, " %N;", n->ninit->n);
+		else if(n->nincr)
+			fmtstrcpy(f, " ;");
+
+		if(n->ntest)
+			fmtprint(f, " %N", n->ntest);
+
+		if(n->nincr)
+			fmtprint(f, "; %N", n->nincr);
+		else if(simpleinit)
+			fmtstrcpy(f, ";");
+
+
+		fmtprint(f, " { %H }", n->nbody);
+		break;
+
+	case ORANGE:
+		if(fmtmode == FErr) {
+			fmtstrcpy(f, "for loop");
+			break;
+		}
+		
+		if(n->list == nil) {
+			fmtprint(f, "for range %N { %H }", n->right, n->nbody);
+			break;
+		}
+		fmtprint(f, "for %,H = range %N { %H }", n->list, n->right, n->nbody);
+		break;
+
+	case OSELECT:
+	case OSWITCH:
+		if(fmtmode == FErr) {
+			fmtprint(f, "%O statement", n->op);
+			break;
+		}
+
+		fmtprint(f, "%#O", n->op);
+		if(simpleinit)
+			fmtprint(f, " %N;", n->ninit->n);
+		if(n->ntest)
+			fmtprint(f, "%N", n->ntest);
+
+		fmtprint(f, " { %H }", n->list);
+		break;
+
+	case OCASE:
+	case OXCASE:
+		if(n->list)
+			fmtprint(f, "case %,H: %H", n->list, n->nbody);
+		else
+			fmtprint(f, "default: %H", n->nbody);
+		break;
+
+	case OBREAK:
+	case OCONTINUE:
+	case OGOTO:
+	case OFALL:
+	case OXFALL:
+		if(n->left)
+			fmtprint(f, "%#O %N", n->op, n->left);
+		else
+			fmtprint(f, "%#O", n->op);
+		break;
+
+	case OEMPTY:
+		break;
+
+	case OLABEL:
+		fmtprint(f, "%N: ", n->left);
+		break;
+	  
+	}
+ret:
+
+	if(extrablock)
+		fmtstrcpy(f, "}");
+
+	return 0;
+}
+
+
+static int opprec[] = {
+	[OAPPEND] = 8,
+	[OARRAYBYTESTR] = 8,
+	[OARRAYLIT] = 8,
+	[OARRAYRUNESTR] = 8,
+	[OCALLFUNC] = 8,
+	[OCALLINTER] = 8,
+	[OCALLMETH] = 8,
+	[OCALL] = 8,
+	[OCAP] = 8,
+	[OCLOSE] = 8,
+	[OCONVIFACE] = 8,
+	[OCONVNOP] = 8,
+	[OCONV] = 8,
+	[OCOPY] = 8,
+	[ODELETE] = 8,
+	[OLEN] = 8,
+	[OLITERAL] = 8,
+	[OMAKESLICE] = 8,
+	[OMAKE] = 8,
+	[OMAPLIT] = 8,
+	[ONAME] = 8,
+	[ONEW] = 8,
+	[ONONAME] = 8,
+	[OPACK] = 8,
+	[OPANIC] = 8,
+	[OPAREN] = 8,
+	[OPRINTN] = 8,
+	[OPRINT] = 8,
+	[ORUNESTR] = 8,
+	[OSTRARRAYBYTE] = 8,
+	[OSTRARRAYRUNE] = 8,
+	[OSTRUCTLIT] = 8,
+	[OTARRAY] = 8,
+	[OTCHAN] = 8,
+	[OTFUNC] = 8,
+	[OTINTER] = 8,
+	[OTMAP] = 8,
+	[OTSTRUCT] = 8,
+
+	[OINDEXMAP] = 8,
+	[OINDEX] = 8,
+	[OSLICE] = 8,
+	[OSLICESTR] = 8,
+	[OSLICEARR] = 8,
+	[OSLICE3] = 8,
+	[OSLICE3ARR] = 8,
+	[ODOTINTER] = 8,
+	[ODOTMETH] = 8,
+	[ODOTPTR] = 8,
+	[ODOTTYPE2] = 8,
+	[ODOTTYPE] = 8,
+	[ODOT] = 8,
+	[OXDOT] = 8,
+	[OCALLPART] = 8,
+
+	[OPLUS] = 7,
+	[ONOT] = 7,
+	[OCOM] = 7,
+	[OMINUS] = 7,
+	[OADDR] = 7,
+	[OIND] = 7,
+	[ORECV] = 7,
+
+	[OMUL] = 6,
+	[ODIV] = 6,
+	[OMOD] = 6,
+	[OLSH] = 6,
+	[ORSH] = 6,
+	[OAND] = 6,
+	[OANDNOT] = 6,
+
+	[OADD] = 5,
+	[OSUB] = 5,
+	[OOR] = 5,
+	[OXOR] = 5,
+
+	[OEQ] = 4,
+	[OLT] = 4,
+	[OLE] = 4,
+	[OGE] = 4,
+	[OGT] = 4,
+	[ONE] = 4,
+	[OCMPSTR] = 4,
+	[OCMPIFACE] = 4,
+
+	[OSEND] = 3,
+	[OANDAND] = 2,
+	[OOROR] = 1,
+
+	// Statements handled by stmtfmt
+	[OAS] = -1,
+	[OAS2] = -1,
+	[OAS2DOTTYPE] = -1,
+	[OAS2FUNC] = -1,
+	[OAS2MAPR] = -1,
+	[OAS2RECV] = -1,
+	[OASOP] = -1,
+	[OBREAK] = -1,
+	[OCASE] = -1,
+	[OCONTINUE] = -1,
+	[ODCL] = -1,
+	[ODCLFIELD] = -1,
+	[ODEFER] = -1,
+	[OEMPTY] = -1,
+	[OFALL] = -1,
+	[OFOR] = -1,
+	[OGOTO] = -1,
+	[OIF] = -1,
+	[OLABEL] = -1,
+	[OPROC] = -1,
+	[ORANGE] = -1,
+	[ORETURN] = -1,
+	[OSELECT] = -1,
+	[OSWITCH] = -1,
+	[OXCASE] = -1,
+	[OXFALL] = -1,
+
+	[OEND] = 0
+};
+
+static int
+exprfmt(Fmt *f, Node *n, int prec)
+{
+	int nprec;
+	int ptrlit;
+	NodeList *l;
+
+	while(n && n->implicit && (n->op == OIND || n->op == OADDR))
+		n = n->left;
+
+	if(n == N)
+		return fmtstrcpy(f, "<N>");
+
+	nprec = opprec[n->op];
+	if(n->op == OTYPE && n->sym != S)
+		nprec = 8;
+
+	if(prec > nprec)
+		return fmtprint(f, "(%N)", n);
+
+	switch(n->op) {
+	case OPAREN:
+		return fmtprint(f, "(%N)", n->left);
+
+	case ODDDARG:
+		return fmtprint(f, "... argument");
+
+	case OREGISTER:
+		return fmtprint(f, "%R", n->val.u.reg);
+
+	case OLITERAL:  // this is a bit of a mess
+		if(fmtmode == FErr && n->sym != S)
+			return fmtprint(f, "%S", n->sym);
+		if(n->val.ctype == CTNIL && n->orig != N && n->orig != n)
+			return exprfmt(f, n->orig, prec);
+		if(n->type != T && n->type != types[n->type->etype] && n->type != idealbool && n->type != idealstring) {
+			// Need parens when type begins with what might
+			// be misinterpreted as a unary operator: * or <-.
+			if(isptr[n->type->etype] || (n->type->etype == TCHAN && n->type->chan == Crecv))
+				return fmtprint(f, "(%T)(%V)", n->type, &n->val);
+			else 
+				return fmtprint(f, "%T(%V)", n->type, &n->val);
+		}
+		return fmtprint(f, "%V", &n->val);
+
+	case ONAME:
+		// Special case: name used as local variable in export.
+		// _ 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);
+
+		// Special case: explicit name of func (*T) method(...) is turned into pkg.(*T).method,
+		// but for export, this should be rendered as (*pkg.T).meth.
+		// These nodes have the special property that they are names with a left OTYPE and a right ONAME.
+		if(fmtmode == FExp && n->left && n->left->op == OTYPE && n->right && n->right->op == ONAME) {
+			if(isptr[n->left->type->etype])
+				return fmtprint(f, "(%T).%hhS", n->left->type, n->right->sym);
+			else
+				return fmtprint(f, "%T.%hhS", n->left->type, n->right->sym);
+		}
+		//fallthrough
+	case OPACK:
+	case ONONAME:
+		return fmtprint(f, "%S", n->sym);
+
+	case OTYPE:
+		if(n->type == T && n->sym != S)
+			return fmtprint(f, "%S", n->sym);
+		return fmtprint(f, "%T", n->type);
+
+	case OTARRAY:
+		if(n->left)
+			return fmtprint(f, "[]%N", n->left);
+		return fmtprint(f, "[]%N", n->right);  // happens before typecheck
+
+	case OTMAP:
+		return fmtprint(f, "map[%N]%N", n->left, n->right);
+
+	case OTCHAN:
+		switch(n->etype) {
+		case Crecv:
+			return fmtprint(f, "<-chan %N", n->left);
+		case Csend:
+			return fmtprint(f, "chan<- %N", n->left);
+		default:
+			if(n->left != N && n->left->op == OTCHAN && n->left->sym == S && n->left->etype == Crecv)
+				return fmtprint(f, "chan (%N)", n->left);
+			else
+				return fmtprint(f, "chan %N", n->left);
+		}
+
+	case OTSTRUCT:
+		return fmtprint(f, "<struct>");
+
+	case OTINTER:
+		return fmtprint(f, "<inter>");
+
+	case OTFUNC:
+		return fmtprint(f, "<func>");
+
+	case OCLOSURE:
+		if(fmtmode == FErr)
+			return fmtstrcpy(f, "func literal");
+		if(n->nbody)
+			return fmtprint(f, "%T { %H }", n->type, n->nbody);
+		return fmtprint(f, "%T { %H }", n->type, n->closure->nbody);
+
+	case OCOMPLIT:
+		ptrlit = n->right != N && n->right->implicit && n->right->type && isptr[n->right->type->etype];
+		if(fmtmode == FErr) {
+			if(n->right != N && n->right->type != T && !n->implicit) {
+				if(ptrlit)
+					return fmtprint(f, "&%T literal", n->right->type->type);
+				else
+					return fmtprint(f, "%T literal", n->right->type);
+			}
+			return fmtstrcpy(f, "composite literal");
+		}
+		if(fmtmode == FExp && ptrlit)
+			// typecheck has overwritten OIND by OTYPE with pointer type.
+			return fmtprint(f, "(&%T{ %,H })", n->right->type->type, n->list);
+		return fmtprint(f, "(%N{ %,H })", n->right, n->list);
+
+	case OPTRLIT:
+		if(fmtmode == FExp && n->left->implicit)
+			return fmtprint(f, "%N", n->left);
+		return fmtprint(f, "&%N", n->left);
+
+	case OSTRUCTLIT:
+		if(fmtmode == FExp) {   // requires special handling of field names
+			if(n->implicit)
+				fmtstrcpy(f, "{");
+			else
+				fmtprint(f, "(%T{", n->type);
+			for(l=n->list; l; l=l->next) {
+				fmtprint(f, " %hhS:%N", l->n->left->sym, l->n->right);
+
+				if(l->next)
+					fmtstrcpy(f, ",");
+				else
+					fmtstrcpy(f, " ");
+			}
+			if(!n->implicit)
+				return fmtstrcpy(f, "})");
+			return fmtstrcpy(f, "}");
+		}
+		// fallthrough
+
+	case OARRAYLIT:
+	case OMAPLIT:
+		if(fmtmode == FErr)
+			return fmtprint(f, "%T literal", n->type);
+		if(fmtmode == FExp && n->implicit)
+			return fmtprint(f, "{ %,H }", n->list);
+		return fmtprint(f, "(%T{ %,H })", n->type, n->list);
+
+	case OKEY:
+		if(n->left && n->right) {
+			if(fmtmode == FExp && n->left->type && n->left->type->etype == TFIELD) {
+				// requires special handling of field names
+				return fmtprint(f, "%hhS:%N", n->left->sym, n->right);
+			} else
+				return fmtprint(f, "%N:%N", n->left, n->right);
+		}
+		if(!n->left && n->right)
+			return fmtprint(f, ":%N", n->right);
+		if(n->left && !n->right)
+			return fmtprint(f, "%N:", n->left);
+		return fmtstrcpy(f, ":");
+
+	case OXDOT:
+	case ODOT:
+	case ODOTPTR:
+	case ODOTINTER:
+	case ODOTMETH:
+	case OCALLPART:
+		exprfmt(f, n->left, nprec);
+		if(n->right == N || n->right->sym == S)
+			return fmtstrcpy(f, ".<nil>");
+		return fmtprint(f, ".%hhS", n->right->sym);
+
+	case ODOTTYPE:
+	case ODOTTYPE2:
+		exprfmt(f, n->left, nprec);
+		if(n->right != N)
+			return fmtprint(f, ".(%N)", n->right);
+		return fmtprint(f, ".(%T)", n->type);
+
+	case OINDEX:
+	case OINDEXMAP:
+	case OSLICE:
+	case OSLICESTR:
+	case OSLICEARR:
+	case OSLICE3:
+	case OSLICE3ARR:
+		exprfmt(f, n->left, nprec);
+		return fmtprint(f, "[%N]", n->right);
+
+	case OCOPY:
+	case OCOMPLEX:
+		return fmtprint(f, "%#O(%N, %N)", n->op, n->left, n->right);
+
+	case OCONV:
+	case OCONVIFACE:
+	case OCONVNOP:
+	case OARRAYBYTESTR:
+	case OARRAYRUNESTR:
+	case OSTRARRAYBYTE:
+	case OSTRARRAYRUNE:
+	case ORUNESTR:
+		if(n->type == T || n->type->sym == S)
+			return fmtprint(f, "(%T)(%N)", n->type, n->left);
+		if(n->left)
+			return fmtprint(f, "%T(%N)", n->type, n->left);
+		return fmtprint(f, "%T(%,H)", n->type, n->list);
+
+	case OREAL:
+	case OIMAG:
+	case OAPPEND:
+	case OCAP:
+	case OCLOSE:
+	case ODELETE:
+	case OLEN:
+	case OMAKE:
+	case ONEW:
+	case OPANIC:
+	case ORECOVER:
+	case OPRINT:
+	case OPRINTN:
+		if(n->left)
+			return fmtprint(f, "%#O(%N)", n->op, n->left);
+		if(n->isddd)
+			return fmtprint(f, "%#O(%,H...)", n->op, n->list);
+		return fmtprint(f, "%#O(%,H)", n->op, n->list);
+
+	case OCALL:
+	case OCALLFUNC:
+	case OCALLINTER:
+	case OCALLMETH:
+		exprfmt(f, n->left, nprec);
+		if(n->isddd)
+			return fmtprint(f, "(%,H...)", n->list);
+		return fmtprint(f, "(%,H)", n->list);
+
+	case OMAKEMAP:
+	case OMAKECHAN:
+	case OMAKESLICE:
+		if(n->list) // pre-typecheck
+			return fmtprint(f, "make(%T, %,H)", n->type, n->list);
+		if(n->right)
+			return fmtprint(f, "make(%T, %N, %N)", n->type, n->left, n->right);
+		if(n->left)
+			return fmtprint(f, "make(%T, %N)", n->type, n->left);
+		return fmtprint(f, "make(%T)", n->type);
+
+	// Unary
+	case OPLUS:
+	case OMINUS:
+	case OADDR:
+	case OCOM:
+	case OIND:
+	case ONOT:
+	case ORECV:
+		if(n->left->op == n->op)
+			fmtprint(f, "%#O ", n->op);
+		else
+			fmtprint(f, "%#O", n->op);
+		return exprfmt(f, n->left, nprec+1);
+
+	// Binary
+	case OADD:
+	case OAND:
+	case OANDAND:
+	case OANDNOT:
+	case ODIV:
+	case OEQ:
+	case OGE:
+	case OGT:
+	case OLE:
+	case OLT:
+	case OLSH:
+	case OMOD:
+	case OMUL:
+	case ONE:
+	case OOR:
+	case OOROR:
+	case ORSH:
+	case OSEND:
+	case OSUB:
+	case OXOR:
+		exprfmt(f, n->left, nprec);
+		fmtprint(f, " %#O ", n->op);
+		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);
+		fmtprint(f, " %#O ", n->etype);
+		exprfmt(f, n->right, nprec+1);
+		return 0;
+	}
+
+	return fmtprint(f, "<node %O>", n->op);
+}
+
+static int
+nodefmt(Fmt *f, Node *n)
+{
+	Type *t;
+
+	t = n->type;
+
+	// we almost always want the original, except in export mode for literals
+	// this saves the importer some work, and avoids us having to redo some
+	// special casing for package unsafe
+	if((fmtmode != FExp || n->op != OLITERAL) && n->orig != N)
+		n = n->orig;
+
+	if(f->flags&FmtLong && t != T) {
+		if(t->etype == TNIL)
+			return fmtprint(f, "nil");
+		else
+			return fmtprint(f, "%N (type %T)", n, t);
+	}
+
+	// TODO inlining produces expressions with ninits. we can't print these yet.
+
+	if(opprec[n->op] < 0)
+		return stmtfmt(f, n);
+
+	return exprfmt(f, n, 0);
+}
+
+static int dumpdepth;
+
+static void
+indent(Fmt *fp)
+{
+	int i;
+
+	fmtstrcpy(fp, "\n");
+	for(i = 0; i < dumpdepth; ++i)
+		fmtstrcpy(fp, ".   ");
+}
+
+static int
+nodedump(Fmt *fp, Node *n)
+{
+	int recur;
+
+	if(n == N)
+		return 0;
+
+	recur = !(fp->flags&FmtShort);
+
+	if(recur) {
+		indent(fp);
+		if(dumpdepth > 10)
+			return fmtstrcpy(fp, "...");
+
+		if(n->ninit != nil) {
+			fmtprint(fp, "%O-init%H", n->op, n->ninit);
+			indent(fp);
+		}
+	}
+
+//	fmtprint(fp, "[%p]", n);
+
+	switch(n->op) {
+	default:
+		fmtprint(fp, "%O%J", n->op, n);
+		break;
+	case OREGISTER:
+	case OINDREG:
+		fmtprint(fp, "%O-%R%J", n->op, n->val.u.reg, n);
+		break;
+	case OLITERAL:
+		fmtprint(fp, "%O-%V%J", n->op, &n->val, n);
+		break;
+	case ONAME:
+	case ONONAME:
+		if(n->sym != S)
+			fmtprint(fp, "%O-%S%J", n->op, n->sym, n);
+		else
+			fmtprint(fp, "%O%J", n->op, n);
+		if(recur && n->type == T && n->ntype) {
+			indent(fp);
+			fmtprint(fp, "%O-ntype%N", n->op, n->ntype);
+		}
+		break;
+	case OASOP:
+		fmtprint(fp, "%O-%O%J", n->op, n->etype, n);
+		break;
+	case OTYPE:
+		fmtprint(fp, "%O %S%J type=%T", n->op, n->sym, n, n->type);
+		if(recur && n->type == T && n->ntype) {
+			indent(fp);
+			fmtprint(fp, "%O-ntype%N", n->op, n->ntype);
+		}
+		break;
+	}
+
+	if(n->sym != S && n->op != ONAME)
+		fmtprint(fp, " %S G%d", n->sym, n->vargen);
+
+	if(n->type != T)
+		fmtprint(fp, " %T", n->type);
+
+	if(recur) {
+		if(n->left)
+			fmtprint(fp, "%N", n->left);
+		if(n->right)
+			fmtprint(fp, "%N", n->right);
+		if(n->list) {
+			indent(fp);
+			fmtprint(fp, "%O-list%H", n->op, n->list);
+		}
+		if(n->rlist) {
+			indent(fp);
+			fmtprint(fp, "%O-rlist%H", n->op, n->rlist);
+		}
+		if(n->ntest) {
+			indent(fp);
+			fmtprint(fp, "%O-test%N", n->op, n->ntest);
+		}
+		if(n->nbody) {
+			indent(fp);
+			fmtprint(fp, "%O-body%H", n->op, n->nbody);
+		}
+		if(n->nelse) {
+			indent(fp);
+			fmtprint(fp, "%O-else%H", n->op, n->nelse);
+		}
+		if(n->nincr) {
+			indent(fp);
+			fmtprint(fp, "%O-incr%N", n->op, n->nincr);
+		}
+	}
+
+	return 0;
+}
+
+// Fmt "%S": syms
+// Flags:  "%hS" suppresses qualifying with package
+static int
+Sconv(Fmt *fp)
+{
+	Sym *s;
+	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>");
+
+	if(s->name && s->name[0] == '_' && s->name[1] == '\0')
+		return fmtstrcpy(fp, "_");
+
+	sf = fp->flags;
+	sm = setfmode(&fp->flags);
+	r = symfmt(fp, s);
+	fp->flags = sf;
+	fmtmode = sm;
+	return r;
+}
+
+// Fmt "%T": types.
+// Flags: 'l' print definition, not name
+//	  'h' omit 'func' and receiver from function types, short type names
+//	  'u' package name, not prefix (FTypeId mode, sticky)
+static int
+Tconv(Fmt *fp)
+{
+	Type *t;
+	int r, sm;
+	unsigned long sf;
+
+	t = va_arg(fp->args, Type*);
+	if(t == T)
+		return fmtstrcpy(fp, "<T>");
+
+	if(t->trecur > 4)
+		return fmtstrcpy(fp, "<...>");
+
+	t->trecur++;
+	sf = fp->flags;
+	sm = setfmode(&fp->flags);
+
+	if(fmtmode == FTypeId && (sf&FmtUnsigned))
+		fmtpkgpfx++;
+	if(fmtpkgpfx)
+		fp->flags |= FmtUnsigned;
+
+	r = typefmt(fp, t);
+
+	if(fmtmode == FTypeId && (sf&FmtUnsigned))
+		fmtpkgpfx--;
+
+	fp->flags = sf;
+	fmtmode = sm;
+	t->trecur--;
+	return r;
+}
+
+// Fmt '%N': Nodes.
+// Flags: 'l' suffix with "(type %T)" where possible
+//	  '+h' in debug mode, don't recurse, no multiline output
+static int
+Nconv(Fmt *fp)
+{
+	Node *n;
+	int r, sm;
+	unsigned long sf;
+
+	n = va_arg(fp->args, Node*);
+	if(n == N)
+		return fmtstrcpy(fp, "<N>");
+	sf = fp->flags;
+	sm = setfmode(&fp->flags);
+
+	r = -1;
+	switch(fmtmode) {
+	case FErr:
+	case FExp:
+		r = nodefmt(fp, n);
+		break;
+	case FDbg:
+		dumpdepth++;
+		r = nodedump(fp, n);
+		dumpdepth--;
+		break;
+	default:
+		fatal("unhandled %%N mode");
+	}
+
+	fp->flags = sf;
+	fmtmode = sm;
+	return r;
+}
+
+// Fmt '%H': NodeList.
+// Flags: all those of %N plus ',': separate with comma's instead of semicolons.
+static int
+Hconv(Fmt *fp)
+{
+	NodeList *l;
+	int r, sm;
+	unsigned long sf;
+	char *sep;
+
+	l = va_arg(fp->args, NodeList*);
+
+	if(l == nil && fmtmode == FDbg)
+		return fmtstrcpy(fp, "<nil>");
+
+	sf = fp->flags;
+	sm = setfmode(&fp->flags);
+	r = 0;
+	sep = "; ";
+	if(fmtmode == FDbg)
+		sep = "\n";
+	else if(fp->flags & FmtComma)
+		sep = ", ";
+
+	for(;l; l=l->next) {
+		r += fmtprint(fp, "%N", l->n);
+		if(l->next)
+			r += fmtstrcpy(fp, sep);
+	}
+
+	fp->flags = sf;
+	fmtmode = sm;
+	return r;
+}
+
+void
+fmtinstallgo(void)
+{
+	fmtmode = FErr;
+	fmtinstall('E', Econv);		// etype opcodes
+	fmtinstall('J', Jconv);		// all the node flags
+	fmtinstall('H', Hconv);		// node lists
+	fmtinstall('L', Lconv);		// line number
+	fmtinstall('N', Nconv);		// node pointer
+	fmtinstall('O', Oconv);		// node opcodes
+	fmtinstall('S', Sconv);		// sym pointer
+	fmtinstall('T', Tconv);		// type pointer
+	fmtinstall('V', Vconv);		// val pointer
+	fmtinstall('Z', Zconv);		// escaped string
+
+	// These are in mparith1.c
+	fmtinstall('B', Bconv);	// big numbers
+	fmtinstall('F', Fconv);	// big float numbers
+
+}
+
+void
+dumplist(char *s, NodeList *l)
+{
+	print("%s%+H\n", s, l);
+}
+
+void
+dump(char *s, Node *n)
+{
+	print("%s [%p]%+N\n", s, n, n);
+}
diff --git a/src/cmd/gc/gen.c b/src/cmd/gc/gen.c
new file mode 100644
index 0000000..c7c9fcd
--- /dev/null
+++ b/src/cmd/gc/gen.c
@@ -0,0 +1,991 @@
+// 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.
+
+/*
+ * portable half of code generator.
+ * mainly statements and control flow.
+ */
+
+#include <u.h>
+#include <libc.h>
+#include "go.h"
+
+static void	cgen_dcl(Node *n);
+static void	cgen_proc(Node *n, int proc);
+static void	checkgoto(Node*, Node*);
+
+static Label *labellist;
+static Label *lastlabel;
+
+Node*
+sysfunc(char *name)
+{
+	Node *n;
+
+	n = newname(pkglookup(name, runtimepkg));
+	n->class = PFUNC;
+	return n;
+}
+
+/*
+ * the address of n has been taken and might be used after
+ * the current function returns.  mark any local vars
+ * as needing to move to the heap.
+ */
+void
+addrescapes(Node *n)
+{
+	char buf[100];
+	Node *oldfn;
+
+	switch(n->op) {
+	default:
+		// probably a type error already.
+		// dump("addrescapes", n);
+		break;
+
+	case ONAME:
+		if(n == nodfp)
+			break;
+
+		// if this is a tmpname (PAUTO), it was tagged by tmpname as not escaping.
+		// on PPARAM it means something different.
+		if(n->class == PAUTO && n->esc == EscNever)
+			break;
+
+		switch(n->class) {
+		case PPARAMREF:
+			addrescapes(n->defn);
+			break;
+		case PPARAM:
+		case PPARAMOUT:
+			// if func param, need separate temporary
+			// to hold heap pointer.
+			// the function type has already been checked
+			// (we're in the function body)
+			// so the param already has a valid xoffset.
+
+			// expression to refer to stack copy
+			n->stackparam = nod(OPARAM, n, N);
+			n->stackparam->type = n->type;
+			n->stackparam->addable = 1;
+			if(n->xoffset == BADWIDTH)
+				fatal("addrescapes before param assignment");
+			n->stackparam->xoffset = n->xoffset;
+			// fallthrough
+
+		case PAUTO:
+			n->class |= PHEAP;
+			n->addable = 0;
+			n->ullman = 2;
+			n->xoffset = 0;
+
+			// create stack variable to hold pointer to heap
+			oldfn = curfn;
+			curfn = n->curfn;
+			n->heapaddr = temp(ptrto(n->type));
+			snprint(buf, sizeof buf, "&%S", n->sym);
+			n->heapaddr->sym = lookup(buf);
+			n->heapaddr->orig->sym = n->heapaddr->sym;
+			n->esc = EscHeap;
+			if(debug['m'])
+				print("%L: moved to heap: %N\n", n->lineno, n);
+			curfn = oldfn;
+			break;
+		}
+		break;
+
+	case OIND:
+	case ODOTPTR:
+		break;
+
+	case ODOT:
+	case OINDEX:
+		// ODOTPTR has already been introduced,
+		// so these are the non-pointer ODOT and OINDEX.
+		// In &x[0], if x is a slice, then x does not
+		// escape--the pointer inside x does, but that
+		// is always a heap pointer anyway.
+		if(!isslice(n->left->type))
+			addrescapes(n->left);
+		break;
+	}
+}
+
+void
+clearlabels(void)
+{
+	Label *l;
+
+	for(l=labellist; l!=L; l=l->link)
+		l->sym->label = L;
+	
+	labellist = L;
+	lastlabel = L;
+}
+
+static Label*
+newlab(Node *n)
+{
+	Sym *s;
+	Label *lab;
+	
+	s = n->left->sym;
+	if((lab = s->label) == L) {
+		lab = mal(sizeof(*lab));
+		if(lastlabel == nil)
+			labellist = lab;
+		else
+			lastlabel->link = lab;
+		lastlabel = lab;
+		lab->sym = s;
+		s->label = lab;
+	}
+	
+	if(n->op == OLABEL) {
+		if(lab->def != N)
+			yyerror("label %S already defined at %L", s, lab->def->lineno);
+		else
+			lab->def = n;
+	} else
+		lab->use = list(lab->use, n);
+
+	return lab;
+}
+
+void
+checklabels(void)
+{
+	Label *lab;
+	NodeList *l;
+
+	for(lab=labellist; lab!=L; lab=lab->link) {
+		if(lab->def == N) {
+			for(l=lab->use; l; l=l->next)
+				yyerrorl(l->n->lineno, "label %S not defined", lab->sym);
+			continue;
+		}
+		if(lab->use == nil && !lab->used) {
+			yyerrorl(lab->def->lineno, "label %S defined and not used", lab->sym);
+			continue;
+		}
+		if(lab->gotopc != P)
+			fatal("label %S never resolved", lab->sym);
+		for(l=lab->use; l; l=l->next)
+			checkgoto(l->n, lab->def);
+	}
+}
+
+static void
+checkgoto(Node *from, Node *to)
+{
+	int nf, nt;
+	Sym *block, *dcl, *fs, *ts;
+	int lno;
+
+	if(from->sym == to->sym)
+		return;
+
+	nf = 0;
+	for(fs=from->sym; fs; fs=fs->link)
+		nf++;
+	nt = 0;
+	for(fs=to->sym; fs; fs=fs->link)
+		nt++;
+	fs = from->sym;
+	for(; nf > nt; nf--)
+		fs = fs->link;
+	if(fs != to->sym) {
+		lno = lineno;
+		setlineno(from);
+
+		// decide what to complain about.
+		// prefer to complain about 'into block' over declarations,
+		// so scan backward to find most recent block or else dcl.
+		block = S;
+		dcl = S;
+		ts = to->sym;
+		for(; nt > nf; nt--) {
+			if(ts->pkg == nil)
+				block = ts;
+			else
+				dcl = ts;
+			ts = ts->link;
+		}
+		while(ts != fs) {
+			if(ts->pkg == nil)
+				block = ts;
+			else
+				dcl = ts;
+			ts = ts->link;
+			fs = fs->link;
+		}
+
+		if(block)
+			yyerror("goto %S jumps into block starting at %L", from->left->sym, block->lastlineno);
+		else
+			yyerror("goto %S jumps over declaration of %S at %L", from->left->sym, dcl, dcl->lastlineno);
+		lineno = lno;
+	}
+}
+
+static Label*
+stmtlabel(Node *n)
+{
+	Label *lab;
+
+	if(n->sym != S)
+	if((lab = n->sym->label) != L)
+	if(lab->def != N)
+	if(lab->def->defn == n)
+		return lab;
+	return L;
+}
+
+/*
+ * compile statements
+ */
+void
+genlist(NodeList *l)
+{
+	for(; l; l=l->next)
+		gen(l->n);
+}
+
+void
+gen(Node *n)
+{
+	int32 lno;
+	Prog *scontin, *sbreak;
+	Prog *p1, *p2, *p3;
+	Label *lab;
+	int32 wasregalloc;
+
+//dump("gen", n);
+
+	lno = setlineno(n);
+	wasregalloc = anyregalloc();
+
+	if(n == N)
+		goto ret;
+
+	if(n->ninit)
+		genlist(n->ninit);
+
+	setlineno(n);
+
+	switch(n->op) {
+	default:
+		fatal("gen: unknown op %+hN", n);
+		break;
+
+	case OCASE:
+	case OFALL:
+	case OXCASE:
+	case OXFALL:
+	case ODCLCONST:
+	case ODCLFUNC:
+	case ODCLTYPE:
+		break;
+
+	case OEMPTY:
+		break;
+
+	case OBLOCK:
+		genlist(n->list);
+		break;
+
+	case OLABEL:
+		if(isblanksym(n->left->sym))
+			break;
+		
+		lab = newlab(n);
+
+		// if there are pending gotos, resolve them all to the current pc.
+		for(p1=lab->gotopc; p1; p1=p2) {
+			p2 = unpatch(p1);
+			patch(p1, pc);
+		}
+		lab->gotopc = P;
+		if(lab->labelpc == P)
+			lab->labelpc = pc;
+
+		if(n->defn) {
+			switch(n->defn->op) {
+			case OFOR:
+			case OSWITCH:
+			case OSELECT:
+				// so stmtlabel can find the label
+				n->defn->sym = lab->sym;
+			}
+		}
+		break;
+
+	case OGOTO:
+		// if label is defined, emit jump to it.
+		// otherwise save list of pending gotos in lab->gotopc.
+		// the list is linked through the normal jump target field
+		// to avoid a second list.  (the jumps are actually still
+		// valid code, since they're just going to another goto
+		// to the same label.  we'll unwind it when we learn the pc
+		// of the label in the OLABEL case above.)
+		lab = newlab(n);
+		if(lab->labelpc != P)
+			gjmp(lab->labelpc);
+		else
+			lab->gotopc = gjmp(lab->gotopc);
+		break;
+
+	case OBREAK:
+		if(n->left != N) {
+			lab = n->left->sym->label;
+			if(lab == L) {
+				yyerror("break label not defined: %S", n->left->sym);
+				break;
+			}
+			lab->used = 1;
+			if(lab->breakpc == P) {
+				yyerror("invalid break label %S", n->left->sym);
+				break;
+			}
+			gjmp(lab->breakpc);
+			break;
+		}
+		if(breakpc == P) {
+			yyerror("break is not in a loop");
+			break;
+		}
+		gjmp(breakpc);
+		break;
+
+	case OCONTINUE:
+		if(n->left != N) {
+			lab = n->left->sym->label;
+			if(lab == L) {
+				yyerror("continue label not defined: %S", n->left->sym);
+				break;
+			}
+			lab->used = 1;
+			if(lab->continpc == P) {
+				yyerror("invalid continue label %S", n->left->sym);
+				break;
+			}
+			gjmp(lab->continpc);
+			break;
+		}
+		if(continpc == P) {
+			yyerror("continue is not in a loop");
+			break;
+		}
+		gjmp(continpc);
+		break;
+
+	case OFOR:
+		sbreak = breakpc;
+		p1 = gjmp(P);			//		goto test
+		breakpc = gjmp(P);		// break:	goto done
+		scontin = continpc;
+		continpc = pc;
+
+		// define break and continue labels
+		if((lab = stmtlabel(n)) != L) {
+			lab->breakpc = breakpc;
+			lab->continpc = continpc;
+		}
+		gen(n->nincr);				// contin:	incr
+		patch(p1, pc);				// test:
+		bgen(n->ntest, 0, -1, breakpc);		//		if(!test) goto break
+		genlist(n->nbody);				//		body
+		gjmp(continpc);
+		patch(breakpc, pc);			// done:
+		continpc = scontin;
+		breakpc = sbreak;
+		if(lab) {
+			lab->breakpc = P;
+			lab->continpc = P;
+		}
+		break;
+
+	case OIF:
+		p1 = gjmp(P);			//		goto test
+		p2 = gjmp(P);			// p2:		goto else
+		patch(p1, pc);				// test:
+		bgen(n->ntest, 0, -n->likely, p2);		//		if(!test) goto p2
+		genlist(n->nbody);				//		then
+		p3 = gjmp(P);			//		goto done
+		patch(p2, pc);				// else:
+		genlist(n->nelse);				//		else
+		patch(p3, pc);				// done:
+		break;
+
+	case OSWITCH:
+		sbreak = breakpc;
+		p1 = gjmp(P);			//		goto test
+		breakpc = gjmp(P);		// break:	goto done
+
+		// define break label
+		if((lab = stmtlabel(n)) != L)
+			lab->breakpc = breakpc;
+
+		patch(p1, pc);				// test:
+		genlist(n->nbody);				//		switch(test) body
+		patch(breakpc, pc);			// done:
+		breakpc = sbreak;
+		if(lab != L)
+			lab->breakpc = P;
+		break;
+
+	case OSELECT:
+		sbreak = breakpc;
+		p1 = gjmp(P);			//		goto test
+		breakpc = gjmp(P);		// break:	goto done
+
+		// define break label
+		if((lab = stmtlabel(n)) != L)
+			lab->breakpc = breakpc;
+
+		patch(p1, pc);				// test:
+		genlist(n->nbody);				//		select() body
+		patch(breakpc, pc);			// done:
+		breakpc = sbreak;
+		if(lab != L)
+			lab->breakpc = P;
+		break;
+
+	case OASOP:
+		cgen_asop(n);
+		break;
+
+	case ODCL:
+		cgen_dcl(n->left);
+		break;
+
+	case OAS:
+		if(gen_as_init(n))
+			break;
+		cgen_as(n->left, n->right);
+		break;
+
+	case OCALLMETH:
+		cgen_callmeth(n, 0);
+		break;
+
+	case OCALLINTER:
+		cgen_callinter(n, N, 0);
+		break;
+
+	case OCALLFUNC:
+		cgen_call(n, 0);
+		break;
+
+	case OPROC:
+		cgen_proc(n, 1);
+		break;
+
+	case ODEFER:
+		cgen_proc(n, 2);
+		break;
+
+	case ORETURN:
+	case ORETJMP:
+		cgen_ret(n);
+		break;
+	
+	case OCHECKNIL:
+		cgen_checknil(n->left);
+		break;
+	
+	case OVARKILL:
+		gvarkill(n->left);
+		break;
+	}
+
+ret:
+	if(anyregalloc() != wasregalloc) {
+		dump("node", n);
+		fatal("registers left allocated");
+	}
+
+	lineno = lno;
+}
+
+/*
+ * generate call to non-interface method
+ *	proc=0	normal call
+ *	proc=1	goroutine run in new proc
+ *	proc=2	defer call save away stack
+ */
+void
+cgen_callmeth(Node *n, int proc)
+{
+	Node n2;
+	Node *l;
+
+	// generate a rewrite in n2 for the method call
+	// (p.f)(...) goes to (f)(p,...)
+
+	l = n->left;
+	if(l->op != ODOTMETH)
+		fatal("cgen_callmeth: not dotmethod: %N");
+
+	n2 = *n;
+	n2.op = OCALLFUNC;
+	n2.left = l->right;
+	n2.left->type = l->type;
+
+	if(n2.left->op == ONAME)
+		n2.left->class = PFUNC;
+	cgen_call(&n2, proc);
+}
+
+/*
+ * generate code to start new proc running call n.
+ */
+static void
+cgen_proc(Node *n, int proc)
+{
+	switch(n->left->op) {
+	default:
+		fatal("cgen_proc: unknown call %O", n->left->op);
+
+	case OCALLMETH:
+		cgen_callmeth(n->left, proc);
+		break;
+
+	case OCALLINTER:
+		cgen_callinter(n->left, N, proc);
+		break;
+
+	case OCALLFUNC:
+		cgen_call(n->left, proc);
+		break;
+	}
+
+}
+
+/*
+ * generate declaration.
+ * have to allocate heap copy
+ * for escaped variables.
+ */
+static void
+cgen_dcl(Node *n)
+{
+	if(debug['g'])
+		dump("\ncgen-dcl", n);
+	if(n->op != ONAME) {
+		dump("cgen_dcl", n);
+		fatal("cgen_dcl");
+	}
+	if(!(n->class & PHEAP))
+		return;
+	if(compiling_runtime)
+		yyerror("%N escapes to heap, not allowed in runtime.", n);
+	if(n->alloc == nil)
+		n->alloc = callnew(n->type);
+	cgen_as(n->heapaddr, n->alloc);
+}
+
+/*
+ * generate discard of value
+ */
+static void
+cgen_discard(Node *nr)
+{
+	Node tmp;
+
+	if(nr == N)
+		return;
+
+	switch(nr->op) {
+	case ONAME:
+		if(!(nr->class & PHEAP) && nr->class != PEXTERN && nr->class != PFUNC && nr->class != PPARAMREF)
+			gused(nr);
+		break;
+
+	// unary
+	case OADD:
+	case OAND:
+	case ODIV:
+	case OEQ:
+	case OGE:
+	case OGT:
+	case OLE:
+	case OLSH:
+	case OLT:
+	case OMOD:
+	case OMUL:
+	case ONE:
+	case OOR:
+	case ORSH:
+	case OSUB:
+	case OXOR:
+		cgen_discard(nr->left);
+		cgen_discard(nr->right);
+		break;
+
+	// binary
+	case OCAP:
+	case OCOM:
+	case OLEN:
+	case OMINUS:
+	case ONOT:
+	case OPLUS:
+		cgen_discard(nr->left);
+		break;
+	
+	case OIND:
+		cgen_checknil(nr->left);
+		break;
+
+	// special enough to just evaluate
+	default:
+		tempname(&tmp, nr->type);
+		cgen_as(&tmp, nr);
+		gused(&tmp);
+	}
+}
+
+/*
+ * clearslim generates code to zero a slim node.
+ */
+void
+clearslim(Node *n)
+{
+	Node z;
+	Mpflt zero;
+
+	memset(&z, 0, sizeof(z));
+	z.op = OLITERAL;
+	z.type = n->type;
+	z.addable = 1;
+
+	switch(simtype[n->type->etype]) {
+	case TCOMPLEX64:
+	case TCOMPLEX128:
+		z.val.u.cval = mal(sizeof(*z.val.u.cval));
+		mpmovecflt(&z.val.u.cval->real, 0.0);
+		mpmovecflt(&z.val.u.cval->imag, 0.0);
+		break;
+
+	case TFLOAT32:
+	case TFLOAT64:
+		mpmovecflt(&zero, 0.0);
+		z.val.ctype = CTFLT;
+		z.val.u.fval = &zero;
+		break;
+
+	case TPTR32:
+	case TPTR64:
+	case TCHAN:
+	case TMAP:
+		z.val.ctype = CTNIL;
+		break;
+
+	case TBOOL:
+		z.val.ctype = CTBOOL;
+		break;
+
+	case TINT8:
+	case TINT16:
+	case TINT32:
+	case TINT64:
+	case TUINT8:
+	case TUINT16:
+	case TUINT32:
+	case TUINT64:
+		z.val.ctype = CTINT;
+		z.val.u.xval = mal(sizeof(*z.val.u.xval));
+		mpmovecfix(z.val.u.xval, 0);
+		break;
+
+	default:
+		fatal("clearslim called on type %T", n->type);
+	}
+
+	ullmancalc(&z);
+	cgen(&z, n);
+}
+
+/*
+ * generate assignment:
+ *	nl = nr
+ * nr == N means zero nl.
+ */
+void
+cgen_as(Node *nl, Node *nr)
+{
+	Type *tl;
+
+	if(debug['g']) {
+		dump("cgen_as", nl);
+		dump("cgen_as = ", nr);
+	}
+
+	while(nr != N && nr->op == OCONVNOP)
+		nr = nr->left;
+
+	if(nl == N || isblank(nl)) {
+		cgen_discard(nr);
+		return;
+	}
+
+	if(nr == N || iszero(nr)) {
+		// heaps should already be clear
+		if(nr == N && (nl->class & PHEAP))
+			return;
+
+		tl = nl->type;
+		if(tl == T)
+			return;
+		if(isfat(tl)) {
+			if(nl->op == ONAME)
+				gvardef(nl);
+			clearfat(nl);
+			return;
+		}
+		clearslim(nl);
+		return;
+	}
+
+	tl = nl->type;
+	if(tl == T)
+		return;
+
+	cgen(nr, nl);
+}
+
+/*
+ * generate:
+ *	res = iface{typ, data}
+ * n->left is typ
+ * n->right is data
+ */
+void
+cgen_eface(Node *n, Node *res)
+{
+	/* 
+	 * the right node of an eface may contain function calls that uses res as an argument,
+	 * 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(tmp, &dst);
+
+	dst.xoffset -= widthptr;
+	cgen(n->left, &dst);
+}
+
+/*
+ * generate:
+ *	res = s[lo, hi];
+ * n->left is s
+ * n->list is (cap(s)-lo(TUINT), hi-lo(TUINT)[, lo*width(TUINTPTR)])
+ * caller (cgen) guarantees res is an addable ONAME.
+ *
+ * called for OSLICE, OSLICE3, OSLICEARR, OSLICE3ARR, OSLICESTR.
+ */
+void
+cgen_slice(Node *n, Node *res)
+{
+	Node src, dst, *cap, *len, *offs, *add, *base, *tmpcap, *tmplen, *cmp, con;
+	Prog *p1, *p2;
+
+	cap = n->list->n;
+	len = n->list->next->n;
+	offs = N;
+	if(n->list->next->next)
+		offs = n->list->next->next->n;
+
+	// 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]);
+	tmplen = temp(types[TINT]);
+	if(n->op != OSLICESTR)
+		tmpcap = temp(types[TINT]);
+	else
+		tmpcap = tmplen;
+
+	if(isnil(n->left)) {
+		tempname(&src, n->left->type);
+		cgen(n->left, &src);
+	} else
+		src = *n->left;
+	if(n->op == OSLICE || n->op == OSLICE3 || n->op == OSLICESTR)
+		src.xoffset += Array_array;
+
+	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, base);
+		cgen_checknil(base);
+	} else {
+		src.type = types[tptr];
+		cgen(&src, base);
+	}
+	
+	// committed to the update
+	gvardef(res);
+
+	// compute len and cap.
+	// len = n-i, cap = m-i, and offs = i*width.
+	// computing offs last lets the multiply overwrite i.
+	cgen(len, tmplen);
+	if(n->op != OSLICESTR)
+		cgen(cap, tmpcap);
+
+	// if new cap != 0 { base += add }
+	// This avoids advancing base past the end of the underlying array/string,
+	// so that it cannot point at the next object in memory.
+	// If cap == 0, the base doesn't matter except insofar as it is 0 or non-zero.
+	// In essence we are replacing x[i:j:k] where i == j == k
+	// or x[i:j] where i == j == cap(x) with x[0:0:0].
+	if(offs != N) {
+		p1 = gjmp(P);
+		p2 = gjmp(P);
+		patch(p1, pc);
+
+		nodconst(&con, tmpcap->type, 0);
+		cmp = nod(OEQ, tmpcap, &con);
+		typecheck(&cmp, Erv);
+		bgen(cmp, 1, -1, p2);
+
+		add = nod(OADD, base, offs);
+		typecheck(&add, Erv);
+		cgen(add, base);
+
+		patch(p2, pc);
+	}
+
+	// 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(tmplen, &dst);
+
+	if(n->op != OSLICESTR) {
+		// dst.cap = cap [ - lo ]
+		dst = *res;
+		dst.xoffset += Array_cap;
+		dst.type = types[simtype[TUINT]];
+		cgen(tmpcap, &dst);
+	}
+}
+
+/*
+ * gather series of offsets
+ * >=0 is direct addressed field
+ * <0 is pointer to next field (+1)
+ */
+int
+dotoffset(Node *n, int64 *oary, Node **nn)
+{
+	int i;
+
+	switch(n->op) {
+	case ODOT:
+		if(n->xoffset == BADWIDTH) {
+			dump("bad width in dotoffset", n);
+			fatal("bad width in dotoffset");
+		}
+		i = dotoffset(n->left, oary, nn);
+		if(i > 0) {
+			if(oary[i-1] >= 0)
+				oary[i-1] += n->xoffset;
+			else
+				oary[i-1] -= n->xoffset;
+			break;
+		}
+		if(i < 10)
+			oary[i++] = n->xoffset;
+		break;
+
+	case ODOTPTR:
+		if(n->xoffset == BADWIDTH) {
+			dump("bad width in dotoffset", n);
+			fatal("bad width in dotoffset");
+		}
+		i = dotoffset(n->left, oary, nn);
+		if(i < 10)
+			oary[i++] = -(n->xoffset+1);
+		break;
+
+	default:
+		*nn = n;
+		return 0;
+	}
+	if(i >= 10)
+		*nn = N;
+	return i;
+}
+
+/*
+ * make a new off the books
+ */
+void
+tempname(Node *nn, Type *t)
+{
+	Node *n;
+	Sym *s;
+
+	if(curfn == N)
+		fatal("no curfn for tempname");
+
+	if(t == T) {
+		yyerror("tempname called with nil type");
+		t = types[TINT32];
+	}
+
+	// give each tmp a different name so that there
+	// a chance to registerizer them
+	snprint(namebuf, sizeof(namebuf), "autotmp_%.4d", statuniqgen);
+	statuniqgen++;
+	s = lookup(namebuf);
+	n = nod(ONAME, N, N);
+	n->sym = s;
+	s->def = n;
+	n->type = t;
+	n->class = PAUTO;
+	n->addable = 1;
+	n->ullman = 1;
+	n->esc = EscNever;
+	n->curfn = curfn;
+	curfn->dcl = list(curfn->dcl, n);
+
+	dowidth(t);
+	n->xoffset = 0;
+	*nn = *n;
+}
+
+Node*
+temp(Type *t)
+{
+	Node *n;
+	
+	n = nod(OXXX, N, N);
+	tempname(n, t);
+	n->sym->def->used = 1;
+	return n->orig;
+}
diff --git a/src/cmd/gc/go.errors b/src/cmd/gc/go.errors
new file mode 100644
index 0000000..f90d619
--- /dev/null
+++ b/src/cmd/gc/go.errors
@@ -0,0 +1,79 @@
+// 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.
+
+// Example-based syntax error messages.
+// See bisonerrors, Makefile, go.y.
+
+static struct {
+	int yystate;
+	int yychar;
+	char *msg;
+} yymsg[] = {
+	// Each line of the form % token list
+	// is converted by bisonerrors into the yystate and yychar caused
+	// by that token list.
+
+	% loadsys package LIMPORT '(' LLITERAL import_package import_there ','
+	"unexpected comma during import block",
+
+	% loadsys package LIMPORT LNAME ';'
+	"missing import path; require quoted string",
+
+	% loadsys package imports LFUNC LNAME '(' ')' '{' LIF if_header ';'
+	"missing { after if clause",
+
+	% loadsys package imports LFUNC LNAME '(' ')' '{' LSWITCH if_header ';'
+	"missing { after switch clause",
+
+	% loadsys package imports LFUNC LNAME '(' ')' '{' LFOR for_header ';'
+	"missing { after for clause",
+
+	% loadsys package imports LFUNC LNAME '(' ')' '{' LFOR ';' LBODY
+	"missing { after for clause",
+
+	% loadsys package imports LFUNC LNAME '(' ')' ';' '{'
+	"unexpected semicolon or newline before {",
+
+	% loadsys package imports LTYPE LNAME ';'
+	"unexpected semicolon or newline in type declaration",
+
+	% loadsys package imports LCHAN '}'
+	"unexpected } in channel type",
+	
+	% loadsys package imports LCHAN ')'
+	"unexpected ) in channel type",
+	
+	% loadsys package imports LCHAN ','
+	"unexpected comma in channel type",
+
+	% loadsys package imports LFUNC LNAME '(' ')' '{' if_stmt ';' LELSE
+	"unexpected semicolon or newline before else",
+
+	% loadsys package imports LTYPE LNAME LINTERFACE '{' LNAME ',' LNAME
+	"name list not allowed in interface type",
+
+	% loadsys package imports LFUNC LNAME '(' ')' '{' LFOR LVAR LNAME '=' LNAME
+	"var declaration not allowed in for initializer",
+
+	% loadsys package imports LVAR LNAME '[' ']' LNAME '{'
+	"unexpected { at end of statement",
+
+	% loadsys package imports LFUNC LNAME '(' ')' '{' LVAR LNAME '[' ']' LNAME '{'
+	"unexpected { at end of statement",
+	
+	% loadsys package imports LFUNC LNAME '(' ')' '{' LDEFER LNAME ';'
+	"argument to go/defer must be function call",
+	
+	% loadsys package imports LVAR LNAME '=' LNAME '{' LNAME ';'
+	"need trailing comma before newline in composite literal",
+	
+	% loadsys package imports LVAR LNAME '=' comptype '{' LNAME ';'
+	"need trailing comma before newline in composite literal",
+	
+	% loadsys package imports LFUNC LNAME '(' ')' '{' LFUNC LNAME
+	"nested func not allowed",
+
+	% loadsys package imports LFUNC LNAME '(' ')' '{' LIF if_header loop_body LELSE ';'
+	"else must be followed by if or statement block"
+};
diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h
new file mode 100644
index 0000000..bbb8835
--- /dev/null
+++ b/src/cmd/gc/go.h
@@ -0,0 +1,1555 @@
+// 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	<bio.h>
+#include	<link.h>
+
+#undef OAPPEND
+
+// avoid <ctype.h>
+#undef isblank
+#define isblank goisblank
+
+#ifndef	EXTERN
+#define	EXTERN	extern
+#endif
+
+#undef	BUFSIZ
+
+// The parser's maximum stack size.
+// We have to use a #define macro here since yacc
+// or bison will check for its definition and use
+// a potentially smaller value if it is undefined.
+#define YYMAXDEPTH 500
+
+enum
+{
+	NHUNK		= 50000,
+	BUFSIZ		= 8192,
+	NSYMB		= 500,
+	NHASH		= 1024,
+	STRINGSZ	= 200,
+	MAXALIGN	= 7,
+	UINF		= 100,
+
+	PRIME1		= 3,
+
+	AUNK		= 100,
+
+	// These values are known by runtime.
+	// The MEMx and NOEQx values must run in parallel.  See algtype.
+	AMEM		= 0,
+	AMEM0,
+	AMEM8,
+	AMEM16,
+	AMEM32,
+	AMEM64,
+	AMEM128,
+	ANOEQ,
+	ANOEQ0,
+	ANOEQ8,
+	ANOEQ16,
+	ANOEQ32,
+	ANOEQ64,
+	ANOEQ128,
+	ASTRING,
+	AINTER,
+	ANILINTER,
+	ASLICE,
+	AFLOAT32,
+	AFLOAT64,
+	ACPLX64,
+	ACPLX128,
+
+	BADWIDTH	= -1000000000,
+	
+	MaxStackVarSize = 10*1024*1024,
+};
+
+extern vlong	MAXWIDTH;
+
+/*
+ * note this is the representation
+ * of the compilers string literals,
+ * it is not the runtime representation
+ */
+typedef	struct	Strlit	Strlit;
+struct	Strlit
+{
+	int32	len;
+	char	s[1]; // variable
+};
+
+enum
+{
+	Mpscale	= 29,		// safely smaller than bits in a long
+	Mpprec	= 16,		// Mpscale*Mpprec is max number of bits
+	Mpnorm	= Mpprec - 1,	// significant words in a normalized float
+	Mpbase	= 1L << Mpscale,
+	Mpsign	= Mpbase >> 1,
+	Mpmask	= Mpbase - 1,
+	Mpdebug	= 0,
+};
+
+typedef	struct	Mpint	Mpint;
+struct	Mpint
+{
+	long	a[Mpprec];
+	uchar	neg;
+	uchar	ovf;
+};
+
+typedef	struct	Mpflt	Mpflt;
+struct	Mpflt
+{
+	Mpint	val;
+	short	exp;
+};
+
+typedef	struct	Mpcplx	Mpcplx;
+struct	Mpcplx
+{
+	Mpflt	real;
+	Mpflt	imag;
+};
+
+typedef	struct	Val	Val;
+struct	Val
+{
+	short	ctype;
+	union
+	{
+		short	reg;		// OREGISTER
+		short	bval;		// bool value CTBOOL
+		Mpint*	xval;		// int CTINT, rune CTRUNE
+		Mpflt*	fval;		// float CTFLT
+		Mpcplx*	cval;		// float CTCPLX
+		Strlit*	sval;		// string CTSTR
+	} 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;
+typedef	struct	Node	Node;
+typedef	struct	NodeList	NodeList;
+typedef	struct	Type	Type;
+typedef	struct	Label	Label;
+
+struct	Type
+{
+	uchar	etype;
+	uchar	nointerface;
+	uchar	noalg;
+	uchar	chan;
+	uchar	trecur;		// to detect loops
+	uchar	printed;
+	uchar	embedded;	// TFIELD embedded type
+	uchar	siggen;
+	uchar	funarg;		// on TSTRUCT and TFIELD
+	uchar	copyany;
+	uchar	local;		// created in this file
+	uchar	deferwidth;
+	uchar	broke;  	// broken type definition.
+	uchar	isddd;		// TFIELD is ... argument
+	uchar	align;
+	uchar	haspointers;	// 0 unknown, 1 no, 2 yes
+
+	Node*	nod;		// canonical OTYPE node
+	Type*	orig;		// original type (type literal or predefined type)
+	int		lineno;
+
+	// TFUNC
+	int	thistuple;
+	int	outtuple;
+	int	intuple;
+	uchar	outnamed;
+
+	Type*	method;
+	Type*	xmethod;
+
+	Sym*	sym;
+	int32	vargen;		// unique name for OTYPE/ONAME
+
+	Node*	nname;
+	vlong	argwid;
+
+	// most nodes
+	Type*	type;   	// actual type for TFIELD, element type for TARRAY, TCHAN, TMAP, TPTRxx
+	vlong	width;  	// offset in TFIELD, width in all others
+
+	// TFIELD
+	Type*	down;		// next struct field, also key type in TMAP
+	Type*	outer;		// outer struct
+	Strlit*	note;		// literal string annotation
+
+	// TARRAY
+	vlong	bound;		// negative is dynamic array
+
+	// 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
+	
+	// for TFORW, where to copy the eventual value to
+	NodeList	*copyto;
+	
+	Node	*lastfn;	// for usefield
+};
+#define	T	((Type*)0)
+
+typedef struct InitEntry InitEntry;
+typedef struct InitPlan InitPlan;
+
+struct InitEntry
+{
+	vlong xoffset;  // struct, array only
+	Node *key;  // map only
+	Node *expr;
+};
+
+struct InitPlan
+{
+	vlong lit;  // bytes of initialized non-zero literals
+	vlong zero;  // bytes of zeros
+	vlong expr;  // bytes of run-time computed expressions
+
+	InitEntry *e;
+	int len;
+	int cap;
+};
+
+enum
+{
+	EscUnknown,
+	EscHeap,
+	EscScope,
+	EscNone,
+	EscReturn,
+	EscNever,
+	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
+{
+	// Tree structure.
+	// Generic recursive walks should follow these fields.
+	Node*	left;
+	Node*	right;
+	Node*	ntest;
+	Node*	nincr;
+	NodeList*	ninit;
+	NodeList*	nbody;
+	NodeList*	nelse;
+	NodeList*	list;
+	NodeList*	rlist;
+
+	uchar	op;
+	uchar	nointerface;
+	uchar	ullman;		// sethi/ullman number
+	uchar	addable;	// type of addressability - 0 is not addressable
+	uchar	trecur;		// to detect loops
+	uchar	etype;		// op for OASOP, etype for OTYPE, exclam for export
+	uchar	bounded;	// bounds check unnecessary
+	uchar	class;		// PPARAM, PAUTO, PEXTERN, etc
+	uchar	method;		// OCALLMETH name
+	uchar	embedded;	// ODCLFIELD embedded type
+	uchar	colas;		// OAS resulting from :=
+	uchar	diag;		// already printed error about this
+	uchar	noescape;	// func arguments do not escape
+	uchar	nosplit;	// func should not execute on separate stack
+	uchar	builtin;	// built-in name, like len or close
+	uchar	walkdef;
+	uchar	typecheck;
+	uchar	local;
+	uchar	dodata;
+	uchar	initorder;
+	uchar	used;
+	uchar	isddd;
+	uchar	readonly;
+	uchar	implicit;
+	uchar	addrtaken;	// address taken, even if not moved to heap
+	uchar	dupok;	// duplicate definitions ok (for func)
+	uchar	wrapper;	// is method wrapper (for func)
+	uchar	reslice;	// this is a reslice x = x[0:y] or x = append(x, ...)
+	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;
+
+	// most nodes
+	Type*	type;
+	Node*	orig;		// original form, for printing, and tracking copies of ONAMEs
+
+	// func
+	Node*	nname;
+	Node*	shortname;
+	NodeList*	enter;
+	NodeList*	exit;
+	NodeList*	cvars;	// closure params
+	NodeList*	dcl;	// autodcl for this func/closure
+	NodeList*	inl;	// copy of the body for use in inlining
+	NodeList*	inldcl;	// copy of dcl for use in inlining
+
+	// OLITERAL/OREGISTER
+	Val	val;
+
+	// ONAME
+	Node*	ntype;
+	Node*	defn;	// ONAME: initializing assignment; OLABEL: labeled statement
+	Node*	pack;	// real package for import . names
+	Node*	curfn;	// function for local variables
+	Type*	paramfld; // TFIELD for this PPARAM; also for ODOT, curfn
+
+	// ONAME func param with PHEAP
+	Node*	heapaddr;	// temp holding heap address of param
+	Node*	stackparam;	// OPARAM node referring to stack copy of param
+	Node*	alloc;	// allocation call
+
+	// ONAME closure param with PPARAMREF
+	Node*	outer;	// outer PPARAMREF in nested closure
+	Node*	closure;	// ONAME/PHEAP <-> ONAME/PPARAMREF
+
+	// ONAME substitute while inlining
+	Node* inlvar;
+
+	// OPACK
+	Pkg*	pkg;
+	
+	// OARRAYLIT, OMAPLIT, OSTRUCTLIT.
+	InitPlan*	initplan;
+
+	// Escape analysis.
+	NodeList* escflowsrc;	// flow(this, src)
+	NodeList* escretval;	// on OCALLxxx, list of dummy return values
+	int	escloopdepth;	// -1: global, 0: return variables, 1:function top level, increased inside function for every loop or label to mark scopes
+
+	Sym*	sym;		// various
+	int32	vargen;		// unique name for OTYPE/ONAME
+	int32	lineno;
+	int32	endlineno;
+	vlong	xoffset;
+	vlong	stkdelta;	// offset added by stack frame compaction phase.
+	int32	ostk;
+	int32	iota;
+	uint32	walkgen;
+	int32	esclevel;
+	void*	opt;	// for optimization passes
+};
+#define	N	((Node*)0)
+
+/*
+ * Every node has a walkgen field.
+ * If you want to do a traversal of a node graph that
+ * might contain duplicates and want to avoid
+ * visiting the same nodes twice, increment walkgen
+ * before starting.  Then before processing a node, do
+ *
+ *	if(n->walkgen == walkgen)
+ *		return;
+ *	n->walkgen = walkgen;
+ *
+ * Such a walk cannot call another such walk recursively,
+ * because of the use of the global walkgen.
+ */
+EXTERN	uint32	walkgen;
+
+struct	NodeList
+{
+	Node*	n;
+	NodeList*	next;
+	NodeList*	end;
+};
+
+enum
+{
+	SymExport	= 1<<0,	// to be exported
+	SymPackage	= 1<<1,
+	SymExported	= 1<<2,	// already written out by export
+	SymUniq		= 1<<3,
+	SymSiggen	= 1<<4,
+};
+
+struct	Sym
+{
+	ushort	lexical;
+	uchar	flags;
+	uchar	sym;		// huffman encoding in object file
+	Sym*	link;
+	int32	npkg;	// number of imported packages with this name
+	uint32	uniqgen;
+	Pkg*	importdef;	// where imported definition was found
+
+	// saved and restored by dcopy
+	Pkg*	pkg;
+	char*	name;		// variable name
+	Node*	def;		// definition: ONAME OTYPE OPACK or OLITERAL
+	Label*	label;	// corresponding label (ephemeral)
+	int32	block;		// blocknumber to catch redeclaration
+	int32	lastlineno;	// last declaration for diagnostic
+	Pkg*	origpkg;	// original package for . import
+	LSym*	lsym;
+};
+#define	S	((Sym*)0)
+
+EXTERN	Sym*	dclstack;
+
+struct	Pkg
+{
+	char*	name;		// package name
+	Strlit*	path;		// string literal used in import statement
+	Sym*	pathsym;
+	char*	prefix;		// escaped path for use in symbol table
+	Pkg*	link;
+	uchar	imported;	// export data of this package was parsed
+	char	exported;	// import line written in export data
+	char	direct;	// imported directly
+	char	safe;	// whether the package is marked as safe
+};
+
+typedef	struct	Iter	Iter;
+struct	Iter
+{
+	int	done;
+	Type*	tfunc;
+	Type*	t;
+	Node**	an;
+	Node*	n;
+};
+
+// Node ops.
+enum
+{
+	OXXX,
+
+	// names
+	ONAME,	// var, const or func name
+	ONONAME,	// unnamed arg or return value: f(int, string) (int, error) { etc }
+	OTYPE,	// type name
+	OPACK,	// import
+	OLITERAL, // literal
+
+	// expressions
+	OADD,	// x + y
+	OSUB,	// x - y
+	OOR,	// x | y
+	OXOR,	// x ^ y
+	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)
+	OAS,	// x = y or x := y
+	OAS2,	// x, y, z = xx, yy, zz
+	OAS2FUNC,	// x, y = f()
+	OAS2RECV,	// x, ok = <-c
+	OAS2MAPR,	// x, ok = m["foo"]
+	OAS2DOTTYPE,	// x, ok = I.(int)
+	OASOP,	// x += y
+	OCALL,	// function call, method call or type conversion, possibly preceded by defer or go.
+	OCALLFUNC,	// f()
+	OCALLMETH,	// t.Method()
+	OCALLINTER,	// err.Error()
+	OCALLPART,	// t.Method (without ())
+	OCAP,	// cap
+	OCLOSE,	// close
+	OCLOSURE,	// f = func() { etc }
+	OCMPIFACE,	// err1 == err2
+	OCMPSTR,	// s1 == s2
+	OCOMPLIT,	// composite literal, typechecking may convert to a more specific OXXXLIT.
+	OMAPLIT,	// M{"foo":3, "bar":4}
+	OSTRUCTLIT,	// T{x:3, y:4}
+	OARRAYLIT,	// [2]int{3, 4}
+	OPTRLIT,	// &T{x:3, y:4}
+	OCONV,	// var i int; var u uint; i = int(u)
+	OCONVIFACE,	// I(t)
+	OCONVNOP,	// type Int int; var i int; var j Int; i = int(j)
+	OCOPY,	// copy
+	ODCL,	// var x int
+	ODCLFUNC,	// func f() or func (r) f()
+	ODCLFIELD,	// struct field, interface field, or func/method argument/return value.
+	ODCLCONST,	// const pi = 3.14
+	ODCLTYPE,	// type Int int
+	ODELETE,	// delete
+	ODOT,	// t.x
+	ODOTPTR,	// p.x that is implicitly (*p).x
+	ODOTMETH,	// t.Method
+	ODOTINTER,	// err.Error
+	OXDOT,	// t.x, typechecking may convert to a more specific ODOTXXX.
+	ODOTTYPE,	// e = err.(MyErr)
+	ODOTTYPE2,	// e, ok = err.(MyErr)
+	OEQ,	// x == y
+	ONE,	// x != y
+	OLT,	// x < y
+	OLE,	// x <= y
+	OGE,	// x >= y
+	OGT,	// x > y
+	OIND,	// *p
+	OINDEX,	// a[i]
+	OINDEXMAP,	// m[s]
+	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 specific OMAKEXXX.
+	OMAKECHAN,	// make(chan int)
+	OMAKEMAP,	// make(map[string]int)
+	OMAKESLICE,	// make([]int, 0)
+	OMUL,	// x * y
+	ODIV,	// x / y
+	OMOD,	// x % y
+	OLSH,	// x << u
+	ORSH,	// x >> u
+	OAND,	// x & y
+	OANDNOT,	// x &^ y
+	ONEW,	// new
+	ONOT,	// !b
+	OCOM,	// ^x
+	OPLUS,	// +x
+	OMINUS,	// -y
+	OOROR,	// b1 || b2
+	OPANIC,	// panic
+	OPRINT,	// print
+	OPRINTN,	// println
+	OPAREN,	// (x)
+	OSEND,	// c <- x
+	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.
+	OSLICE3ARR,	// a[1:2:3]
+	ORECOVER,	// recover
+	ORECV,	// <-c
+	ORUNESTR,	// string(i)
+	OSELRECV,	// case x = <-c:
+	OSELRECV2,	// case x, ok = <-c:
+	OIOTA,	// iota
+	OREAL,	// real
+	OIMAG,	// imag
+	OCOMPLEX,	// complex
+
+	// statements
+	OBLOCK,	// block of code
+	OBREAK,	// break
+	OCASE,	// case, after being verified by swt.c's casebody.
+	OXCASE,	// case, before verification.
+	OCONTINUE,	// continue
+	ODEFER,	// defer
+	OEMPTY,	// no-op
+	OFALL,	// fallthrough, after being verified by swt.c's casebody.
+	OXFALL,	// fallthrough, before verification.
+	OFOR,	// for
+	OGOTO,	// goto
+	OIF,	// if
+	OLABEL,	// label:
+	OPROC,	// go
+	ORANGE,	// range
+	ORETURN,	// return
+	OSELECT,	// select
+	OSWITCH,	// switch x
+	OTYPESW,	// switch err.(type)
+
+	// types
+	OTCHAN,	// chan int
+	OTMAP,	// map[string]int
+	OTSTRUCT,	// struct{}
+	OTINTER,	// interface{}
+	OTFUNC,	// func()
+	OTARRAY,	// []int, [8]int, [N]int or [...]int
+
+	// misc
+	ODDD,	// func f(args ...int) or f(l...) or var a = [...]int{0, 1, 2}.
+	ODDDARG,	// func f(args ...int), introduced by escape analysis.
+	OINLCALL,	// intermediary representation of an inlined call.
+	OEFACE,	// itable and data words of an empty-interface value.
+	OITAB,	// itable word of an interface value.
+	OSPTR,  // base pointer of a slice or string.
+	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.
+	OINDREG,	// offset plus indirect of a register, such as 8(SP).
+
+	// 386/amd64-specific opcodes
+	OCMP,	// compare: ACMP.
+	ODEC,	// decrement: ADEC.
+	OINC,	// increment: AINC.
+	OEXTEND,	// extend: ACWD/ACDQ/ACQO.
+	OHMUL, // high mul: AMUL/AIMUL for unsigned/signed (OMUL uses AIMUL for both).
+	OLROT,	// left rotate: AROL.
+	ORROTC, // right rotate-carry: ARCR.
+	ORETJMP,	// return to other function
+
+	OEND,
+};
+
+enum
+{
+	Txxx,			// 0
+
+	TINT8,	TUINT8,		// 1
+	TINT16,	TUINT16,
+	TINT32,	TUINT32,
+	TINT64,	TUINT64,
+	TINT, TUINT, TUINTPTR,
+
+	TCOMPLEX64,		// 12
+	TCOMPLEX128,
+
+	TFLOAT32,		// 14
+	TFLOAT64,
+
+	TBOOL,			// 16
+
+	TPTR32, TPTR64,		// 17
+
+	TFUNC,			// 19
+	TARRAY,
+	T_old_DARRAY,
+	TSTRUCT,		// 22
+	TCHAN,
+	TMAP,
+	TINTER,			// 25
+	TFORW,
+	TFIELD,
+	TANY,
+	TSTRING,
+	TUNSAFEPTR,
+
+	// pseudo-types for literals
+	TIDEAL,			// 31
+	TNIL,
+	TBLANK,
+
+	// pseudo-type for frame layout
+	TFUNCARGS,
+	TCHANARGS,
+	TINTERMETH,
+
+	NTYPE,
+};
+
+enum
+{
+	CTxxx,
+
+	CTINT,
+	CTRUNE,
+	CTFLT,
+	CTCPLX,
+	CTSTR,
+	CTBOOL,
+	CTNIL,
+};
+
+enum
+{
+	/* types of channel */
+	/* must match ../../pkg/nreflect/type.go:/Chandir */
+	Cxxx,
+	Crecv = 1<<0,
+	Csend = 1<<1,
+	Cboth = Crecv | Csend,
+};
+
+// declaration context
+enum
+{
+	Pxxx,
+
+	PEXTERN,	// global variable
+	PAUTO,		// local variables
+	PPARAM,		// input arguments
+	PPARAMOUT,	// output results
+	PPARAMREF,	// closure variable reference
+	PFUNC,		// global function
+
+	PDISCARD,	// discard during parse of duplicate import
+
+	PHEAP = 1<<7,	// an extra bit to identify an escaped variable
+};
+
+enum
+{
+	Etop = 1<<1,		// evaluated at statement level
+	Erv = 1<<2,		// evaluated in value context
+	Etype = 1<<3,
+	Ecall = 1<<4,		// call-only expressions are ok
+	Efnstruct = 1<<5,	// multivalue function returns are ok
+	Eiota = 1<<6,		// iota is ok
+	Easgn = 1<<7,		// assigning to expression
+	Eindir = 1<<8,		// indirecting through expression
+	Eaddr = 1<<9,		// taking address of expression
+	Eproc = 1<<10,		// inside a go statement
+	Ecomplit = 1<<11,	// type in composite literal
+};
+
+#define	BITS	5
+#define	NVAR	(BITS*sizeof(uint32)*8)
+
+typedef	struct	Bits	Bits;
+struct	Bits
+{
+	uint32	b[BITS];
+};
+
+EXTERN	Bits	zbits;
+
+struct Bvec
+{
+	int32	n;	// number of bits
+	uint32	b[];
+};
+
+typedef	struct	Var	Var;
+struct	Var
+{
+	vlong	offset;
+	Node*	node;
+	Var*	nextinnode;
+	int	width;
+	char	name;
+	char	etype;
+	char	addr;
+};
+
+EXTERN	Var	var[NVAR];
+
+typedef	struct	Typedef	Typedef;
+struct	Typedef
+{
+	char*	name;
+	int	etype;
+	int	sameas;
+};
+
+extern	Typedef	typedefs[];
+
+typedef	struct	Sig	Sig;
+struct	Sig
+{
+	char*	name;
+	Pkg*	pkg;
+	Sym*	isym;
+	Sym*	tsym;
+	Type*	type;
+	Type*	mtype;
+	int32	offset;
+	Sig*	link;
+};
+
+typedef	struct	Io	Io;
+struct	Io
+{
+	char*	infile;
+	Biobuf*	bin;
+	int32	ilineno;
+	int	nlsemi;
+	int	eofnl;
+	int	last;
+	int	peekc;
+	int	peekc1;	// second peekc for ...
+	char*	cp;	// used for content when bin==nil
+	int	importsafe;
+};
+
+typedef	struct	Dlist	Dlist;
+struct	Dlist
+{
+	Type*	field;
+};
+
+typedef	struct	Idir	Idir;
+struct Idir
+{
+	Idir*	link;
+	char*	dir;
+};
+
+/*
+ * argument passing to/from
+ * smagic and umagic
+ */
+typedef	struct	Magic Magic;
+struct	Magic
+{
+	int	w;	// input for both - width
+	int	s;	// output for both - shift
+	int	bad;	// output for both - unexpected failure
+
+	// magic multiplier for signed literal divisors
+	int64	sd;	// input - literal divisor
+	int64	sm;	// output - multiplier
+
+	// magic multiplier for unsigned literal divisors
+	uint64	ud;	// input - literal divisor
+	uint64	um;	// output - multiplier
+	int	ua;	// output - adder
+};
+
+struct	Label
+{
+	uchar	used;
+	Sym*	sym;
+	Node*	def;
+	NodeList*	use;
+	Label*	link;
+	
+	// for use during gen
+	Prog*	gotopc;	// pointer to unresolved gotos
+	Prog*	labelpc;	// pointer to code
+	Prog*	breakpc;	// pointer to code
+	Prog*	continpc;	// pointer to code
+};
+#define	L	((Label*)0)
+
+/*
+ * note this is the runtime representation
+ * of the compilers arrays.
+ *
+ * typedef	struct
+ * {				// must not move anything
+ *	uchar	array[8];	// pointer to data
+ *	uchar	nel[4];		// number of elements
+ *	uchar	cap[4];		// allocated number of elements
+ * } Array;
+ */
+EXTERN	int	Array_array;	// runtime offsetof(Array,array) - same for String
+EXTERN	int	Array_nel;	// runtime offsetof(Array,nel) - same for String
+EXTERN	int	Array_cap;	// runtime offsetof(Array,cap)
+EXTERN	int	sizeof_Array;	// runtime sizeof(Array)
+
+
+/*
+ * note this is the runtime representation
+ * of the compilers strings.
+ *
+ * typedef	struct
+ * {				// must not move anything
+ *	uchar	array[8];	// pointer to data
+ *	uchar	nel[4];		// number of elements
+ * } String;
+ */
+EXTERN	int	sizeof_String;	// runtime sizeof(String)
+
+EXTERN	Dlist	dotlist[10];	// size is max depth of embeddeds
+
+EXTERN	Io	curio;
+EXTERN	Io	pushedio;
+EXTERN	int32	lexlineno;
+EXTERN	int32	lineno;
+EXTERN	int32	prevlineno;
+
+EXTERN	char*	infile;
+EXTERN	char*	outfile;
+EXTERN	Biobuf*	bout;
+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];
+EXTERN	int	debug[256];
+EXTERN	char*	debugstr;
+EXTERN	int	debug_checknil;
+EXTERN	Sym*	hash[NHASH];
+EXTERN	Sym*	importmyname;	// my name for package
+EXTERN	Pkg*	localpkg;	// package being compiled
+EXTERN	Pkg*	importpkg;	// package being imported
+EXTERN	Pkg*	structpkg;	// package that declared struct, during import
+EXTERN	Pkg*	builtinpkg;	// fake package for builtins
+EXTERN	Pkg*	gostringpkg;	// fake pkg for Go strings
+EXTERN	Pkg*	itabpkg;	// fake pkg for itab cache
+EXTERN	Pkg*	runtimepkg;	// package runtime
+EXTERN	Pkg*	racepkg;	// package runtime/race
+EXTERN	Pkg*	stringpkg;	// fake package for C strings
+EXTERN	Pkg*	typepkg;	// fake package for runtime type info (headers)
+EXTERN	Pkg*	typelinkpkg;	// fake package for runtime type info (data)
+EXTERN	Pkg*	weaktypepkg;	// weak references to runtime type info
+EXTERN	Pkg*	unsafepkg;	// package unsafe
+EXTERN	Pkg*	trackpkg;	// fake package for field tracking
+EXTERN	Pkg*	phash[128];
+EXTERN	int	tptr;		// either TPTR32 or TPTR64
+extern	char*	runtimeimport;
+extern	char*	unsafeimport;
+EXTERN	char*	myimportpath;
+EXTERN	Idir*	idirs;
+EXTERN	char*	localimport;
+
+EXTERN	Type*	types[NTYPE];
+EXTERN	Type*	idealstring;
+EXTERN	Type*	idealbool;
+EXTERN	Type*	bytetype;
+EXTERN	Type*	runetype;
+EXTERN	Type*	errortype;
+EXTERN	uchar	simtype[NTYPE];
+EXTERN	uchar	isptr[NTYPE];
+EXTERN	uchar	isforw[NTYPE];
+EXTERN	uchar	isint[NTYPE];
+EXTERN	uchar	isfloat[NTYPE];
+EXTERN	uchar	iscomplex[NTYPE];
+EXTERN	uchar	issigned[NTYPE];
+EXTERN	uchar	issimple[NTYPE];
+
+EXTERN	uchar	okforeq[NTYPE];
+EXTERN	uchar	okforadd[NTYPE];
+EXTERN	uchar	okforand[NTYPE];
+EXTERN	uchar	okfornone[NTYPE];
+EXTERN	uchar	okforcmp[NTYPE];
+EXTERN	uchar	okforbool[NTYPE];
+EXTERN	uchar	okforcap[NTYPE];
+EXTERN	uchar	okforlen[NTYPE];
+EXTERN	uchar	okforarith[NTYPE];
+EXTERN	uchar	okforconst[NTYPE];
+EXTERN	uchar*	okfor[OEND];
+EXTERN	uchar	iscmp[OEND];
+
+EXTERN	Mpint*	minintval[NTYPE];
+EXTERN	Mpint*	maxintval[NTYPE];
+EXTERN	Mpflt*	minfltval[NTYPE];
+EXTERN	Mpflt*	maxfltval[NTYPE];
+
+EXTERN	NodeList*	xtop;
+EXTERN	NodeList*	externdcl;
+EXTERN	NodeList*	closures;
+EXTERN	NodeList*	exportlist;
+EXTERN	NodeList*	importlist;	// imported functions and methods with inlinable bodies
+EXTERN	NodeList*	funcsyms;
+EXTERN	int	dclcontext;		// PEXTERN/PAUTO
+EXTERN	int	incannedimport;
+EXTERN	int	statuniqgen;		// name generator for static temps
+EXTERN	int	loophack;
+
+EXTERN	int32	iota;
+EXTERN	NodeList*	lastconst;
+EXTERN	Node*	lasttype;
+EXTERN	vlong	maxarg;
+EXTERN	vlong	stksize;		// stack size for current frame
+EXTERN	vlong	stkptrsize;		// prefix of stack containing pointers
+EXTERN	int32	blockgen;		// max block number
+EXTERN	int32	block;			// current block number
+EXTERN	int	hasdefer;		// flag that curfn has defer statetment
+
+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;
+EXTERN	int32	nhunk;
+EXTERN	int32	thunk;
+
+EXTERN	int	funcdepth;
+EXTERN	int	typecheckok;
+EXTERN	int	compiling_runtime;
+EXTERN	int	compiling_wrappers;
+EXTERN	int	inl_nonlocal;
+EXTERN	int	use_writebarrier;
+EXTERN	int	pure_go;
+EXTERN	char*	flag_installsuffix;
+EXTERN	int	flag_race;
+EXTERN	int	flag_largemodel;
+EXTERN	int	noescape;
+EXTERN	int	nosplit;
+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
+ */
+int	yyparse(void);
+
+/*
+ *	align.c
+ */
+int	argsize(Type *t);
+void	checkwidth(Type *t);
+void	defercheckwidth(void);
+void	dowidth(Type *t);
+void	resumecheckwidth(void);
+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);
+void	arraysort(Array* array, int (*cmp)(const void*, const void*));
+
+/*
+ *	bits.c
+ */
+int	Qconv(Fmt *fp);
+Bits	band(Bits a, Bits b);
+int	bany(Bits *a);
+int	beq(Bits a, Bits b);
+int	bitno(int32 b);
+Bits	blsh(uint n);
+Bits	bnot(Bits a);
+int	bnum(Bits a);
+Bits	bor(Bits a, Bits b);
+int	bset(Bits a, uint n);
+
+/*
+ *	bv.c
+ */
+Bvec*	bvalloc(int32 n);
+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);
+int32	bvnext(Bvec *bv, int32 i);
+int	bvisempty(Bvec *bv);
+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
+ */
+Node*	closurebody(NodeList *body);
+void	closurehdr(Node *ntype);
+void	typecheckclosure(Node *func, int top);
+Node*	walkclosure(Node *func, NodeList **init);
+void	typecheckpartialcall(Node*, Node*);
+Node*	walkpartialcall(Node*, NodeList**);
+
+/*
+ *	const.c
+ */
+int	cmpslit(Node *l, Node *r);
+int	consttype(Node *n);
+void	convconst(Node *con, Type *t, Val *val);
+void	convlit(Node **np, Type *t);
+void	convlit1(Node **np, Type *t, int explicit);
+void	defaultlit(Node **np, Type *t);
+void	defaultlit2(Node **lp, Node **rp, int force);
+void	evconst(Node *n);
+int	isconst(Node *n, int ct);
+int	isgoconst(Node *n);
+Node*	nodcplxlit(Val r, Val i);
+Node*	nodlit(Val v);
+long	nonnegconst(Node *n);
+int	doesoverflow(Val v, Type *t);
+void	overflow(Val v, Type *t);
+int	smallintconst(Node *n);
+Val	toint(Val v);
+Mpflt*	truncfltlit(Mpflt *oldv, Type *t);
+
+/*
+ *	cplx.c
+ */
+void	complexadd(int op, Node *nl, Node *nr, Node *res);
+void	complexbool(int op, Node *nl, Node *nr, int true, int likely, Prog *to);
+void	complexgen(Node *n, Node *res);
+void	complexminus(Node *nl, Node *res);
+void	complexmove(Node *f, Node *t);
+void	complexmul(Node *nl, Node *nr, Node *res);
+int	complexop(Node *n, Node *res);
+void	nodfconst(Node *n, Type *t, Mpflt* fval);
+
+/*
+ *	dcl.c
+ */
+void	addmethod(Sym *sf, Type *t, int local, int nointerface);
+void	addvar(Node *n, Type *t, int ctxt);
+NodeList*	checkarglist(NodeList *all, int input);
+Node*	colas(NodeList *left, NodeList *right, int32 lno);
+void	colasdefn(NodeList *left, Node *defn);
+NodeList*	constiter(NodeList *vl, Node *t, NodeList *cl);
+Node*	dclname(Sym *s);
+void	declare(Node *n, int ctxt);
+void	dumpdcl(char *st);
+Node*	embedded(Sym *s, Pkg *pkg);
+Node*	fakethis(void);
+void	funcbody(Node *n);
+void	funccompile(Node *n, int isclosure);
+void	funchdr(Node *n);
+Type*	functype(Node *this, NodeList *in, NodeList *out);
+void	ifacedcl(Node *n);
+int	isifacemethod(Type *f);
+void	markdcl(void);
+Node*	methodname(Node *n, Type *t);
+Node*	methodname1(Node *n, Node *t);
+Sym*	methodsym(Sym *nsym, Type *t0, int iface);
+Node*	newname(Sym *s);
+Node*	oldname(Sym *s);
+void	popdcl(void);
+void	poptodcl(void);
+void	redeclare(Sym *s, char *where);
+void	testdclstack(void);
+Type*	tointerface(NodeList *l);
+Type*	tostruct(NodeList *l);
+Node*	typedcl0(Sym *s);
+Node*	typedcl1(Node *n, Node *t, int local);
+Node*	typenod(Type *t);
+NodeList*	variter(NodeList *vl, Node *t, NodeList *el);
+Sym*	funcsym(Sym*);
+
+/*
+ *	esc.c
+ */
+void	escapes(NodeList*);
+
+/*
+ *	export.c
+ */
+void	autoexport(Node *n, int ctxt);
+void	dumpexport(void);
+int	exportname(char *s);
+void	exportsym(Node *n);
+void    importconst(Sym *s, Type *t, Node *n);
+void	importimport(Sym *s, Strlit *z);
+Sym*    importsym(Sym *s, int op);
+void    importtype(Type *pt, Type *t);
+void    importvar(Sym *s, Type *t);
+Type*	pkgtype(Sym *s);
+
+/*
+ *	fmt.c
+ */
+void	fmtinstallgo(void);
+void	dump(char *s, Node *n);
+void	dumplist(char *s, NodeList *l);
+
+/*
+ *	gen.c
+ */
+void	addrescapes(Node *n);
+void	cgen_as(Node *nl, Node *nr);
+void	cgen_callmeth(Node *n, int proc);
+void	cgen_eface(Node* n, Node* res);
+void	cgen_slice(Node* n, Node* res);
+void	clearlabels(void);
+void	clearslim(Node*);
+void	checklabels(void);
+int	dotoffset(Node *n, int64 *oary, Node **nn);
+void	gen(Node *n);
+void	genlist(NodeList *l);
+Node*	sysfunc(char *name);
+void	tempname(Node *n, Type *t);
+Node*	temp(Type*);
+
+/*
+ *	init.c
+ */
+void	fninit(NodeList *n);
+Sym*	renameinit(void);
+
+/*
+ *	inl.c
+ */
+void	caninl(Node *fn);
+void	inlcalls(Node *fn);
+void	typecheckinl(Node *fn);
+
+/*
+ *	lex.c
+ */
+void	cannedimports(char *file, char *cp);
+void	importfile(Val *f, int line);
+char*	lexname(int lex);
+char*	expstring(void);
+void	mkpackage(char* pkgname);
+void	unimportfile(void);
+int32	yylex(void);
+extern	int	yylast;
+extern	int	yyprev;
+
+/*
+ *	mparith1.c
+ */
+int	Bconv(Fmt *fp);
+int	Fconv(Fmt *fp);
+void	mpaddcfix(Mpint *a, vlong c);
+void	mpaddcflt(Mpflt *a, double c);
+void	mpatofix(Mpint *a, char *as);
+void	mpatoflt(Mpflt *a, char *as);
+int	mpcmpfixc(Mpint *b, vlong c);
+int	mpcmpfixfix(Mpint *a, Mpint *b);
+int	mpcmpfixflt(Mpint *a, Mpflt *b);
+int	mpcmpfltc(Mpflt *b, double c);
+int	mpcmpfltfix(Mpflt *a, Mpint *b);
+int	mpcmpfltflt(Mpflt *a, Mpflt *b);
+void	mpcomfix(Mpint *a);
+void	mpdivfixfix(Mpint *a, Mpint *b);
+void	mpmodfixfix(Mpint *a, Mpint *b);
+void	mpmovefixfix(Mpint *a, Mpint *b);
+void	mpmovefixflt(Mpflt *a, Mpint *b);
+int	mpmovefltfix(Mpint *a, Mpflt *b);
+void	mpmovefltflt(Mpflt *a, Mpflt *b);
+void	mpmulcfix(Mpint *a, vlong c);
+void	mpmulcflt(Mpflt *a, double c);
+void	mpsubfixfix(Mpint *a, Mpint *b);
+void	mpsubfltflt(Mpflt *a, Mpflt *b);
+
+/*
+ *	mparith2.c
+ */
+void	mpaddfixfix(Mpint *a, Mpint *b, int);
+void	mpandfixfix(Mpint *a, Mpint *b);
+void	mpandnotfixfix(Mpint *a, Mpint *b);
+void	mpdivfract(Mpint *a, Mpint *b);
+void	mpdivmodfixfix(Mpint *q, Mpint *r, Mpint *n, Mpint *d);
+vlong	mpgetfix(Mpint *a);
+void	mplshfixfix(Mpint *a, Mpint *b);
+void	mpmovecfix(Mpint *a, vlong c);
+void	mpmulfixfix(Mpint *a, Mpint *b);
+void	mpmulfract(Mpint *a, Mpint *b);
+void	mpnegfix(Mpint *a);
+void	mporfixfix(Mpint *a, Mpint *b);
+void	mprshfixfix(Mpint *a, Mpint *b);
+void	mpshiftfix(Mpint *a, int s);
+int	mptestfix(Mpint *a);
+void	mpxorfixfix(Mpint *a, Mpint *b);
+
+/*
+ *	mparith3.c
+ */
+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, 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);
+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);
+Sym*	stringsym(char*, int);
+void	slicebytes(Node*, char*, int);
+LSym*	linksym(Sym*);
+
+/*
+ *	order.c
+ */
+void	order(Node *fn);
+void	orderstmtinplace(Node **stmt);
+
+/*
+ *	range.c
+ */
+void	typecheckrange(Node *n);
+void	walkrange(Node *n);
+
+/*
+ *	reflect.c
+ */
+void	dumptypestructs(void);
+Type*	methodfunc(Type *f, Type*);
+Node*	typename(Type *t);
+Sym*	typesym(Type *t);
+Sym*	typenamesym(Type *t);
+Sym*	tracksym(Type *t);
+Sym*	typesymprefix(char *prefix, Type *t);
+int	haspointers(Type *t);
+Type*	hiter(Type* t);
+
+/*
+ *	select.c
+ */
+void	typecheckselect(Node *sel);
+void	walkselect(Node *sel);
+
+/*
+ *	sinit.c
+ */
+void	anylit(int, Node *n, Node *var, NodeList **init);
+int	gen_as_init(Node *n);
+NodeList*	initfix(NodeList *l);
+int	oaslit(Node *n, NodeList **init);
+int	stataddr(Node *nam, Node *n);
+
+/*
+ *	subr.c
+ */
+Node*	adddot(Node *n);
+int	adddot1(Sym *s, Type *t, int d, Type **save, int ignorecase);
+void	addinit(Node**, NodeList*);
+Type*	aindex(Node *b, Type *t);
+int	algtype(Type *t);
+int	algtype1(Type *t, Type **bad);
+void	argtype(Node *on, Type *t);
+Node*	assignconv(Node *n, Type *t, char *context);
+int	assignop(Type *src, Type *dst, char **why);
+void	badtype(int o, Type *tl, Type *tr);
+int	brcom(int a);
+int	brrev(int a);
+NodeList*	concat(NodeList *a, NodeList *b);
+int	convertop(Type *src, Type *dst, char **why);
+Node*	copyexpr(Node*, Type*, NodeList**);
+int	count(NodeList *l);
+int	cplxsubtype(int et);
+int	eqtype(Type *t1, Type *t2);
+int	eqtypenoname(Type *t1, Type *t2);
+void	errorexit(void);
+void	expandmeth(Type *t);
+void	fatal(char *fmt, ...);
+void	flusherrors(void);
+void	frame(int context);
+Type*	funcfirst(Iter *s, Type *t);
+Type*	funcnext(Iter *s);
+void	genwrapper(Type *rcvr, Type *method, Sym *newnam, int iface);
+void	genhash(Sym *sym, Type *t);
+void	geneq(Sym *sym, Type *t);
+Type**	getinarg(Type *t);
+Type*	getinargx(Type *t);
+Type**	getoutarg(Type *t);
+Type*	getoutargx(Type *t);
+Type**	getthis(Type *t);
+Type*	getthisx(Type *t);
+int	implements(Type *t, Type *iface, Type **missing, Type **have, int *ptr);
+void	importdot(Pkg *opkg, Node *pack);
+int	is64(Type *t);
+int	isbadimport(Strlit *s);
+int	isblank(Node *n);
+int	isblanksym(Sym *s);
+int	isdirectiface(Type*);
+int	isfixedarray(Type *t);
+int	isideal(Type *t);
+int	isinter(Type *t);
+int	isnil(Node *n);
+int	isnilinter(Type *t);
+int	isptrto(Type *t, int et);
+int	isslice(Type *t);
+int	istype(Type *t, int et);
+int	iszero(Node *n);
+void	linehist(char *file, int32 off, int relative);
+NodeList*	list(NodeList *l, Node *n);
+NodeList*	list1(Node *n);
+void	listsort(NodeList**, int(*f)(Node*, Node*));
+Node*	liststmt(NodeList *l);
+NodeList*	listtreecopy(NodeList *l);
+Sym*	lookup(char *name);
+void*	mal(int32 n);
+Type*	maptype(Type *key, Type *val);
+Type*	methtype(Type *t, int mustname);
+Pkg*	mkpkg(Strlit *path);
+Sym*	ngotype(Node *n);
+int	noconv(Type *t1, Type *t2);
+Node*	nod(int op, Node *nleft, Node *nright);
+Node*	nodbool(int b);
+void	nodconst(Node *n, Type *t, int64 v);
+Node*	nodintconst(int64 v);
+Node*	nodfltconst(Mpflt *v);
+Node*	nodnil(void);
+int	parserline(void);
+Sym*	pkglookup(char *name, Pkg *pkg);
+int	powtwo(Node *n);
+Type*	ptrto(Type *t);
+void*	remal(void *p, int32 on, int32 n);
+Sym*	restrictlookup(char *name, Pkg *pkg);
+Node*	safeexpr(Node *n, NodeList **init);
+void	saveerrors(void);
+Node*	cheapexpr(Node *n, NodeList **init);
+Node*	localexpr(Node *n, Type *t, NodeList **init);
+void	saveorignode(Node *n);
+int32	setlineno(Node *n);
+void	setmaxarg(Type *t);
+Type*	shallow(Type *t);
+int	simsimtype(Type *t);
+void	smagic(Magic *m);
+Type*	sortinter(Type *t);
+uint32	stringhash(char *p);
+Strlit*	strlit(char *s);
+int	structcount(Type *t);
+Type*	structfirst(Iter *s, Type **nn);
+Type*	structnext(Iter *s);
+Node*	syslook(char *name, int copy);
+Type*	tounsigned(Type *t);
+Node*	treecopy(Node *n);
+Type*	typ(int et);
+uint32	typehash(Type *t);
+void	ullmancalc(Node *n);
+void	umagic(Magic *m);
+void	warn(char *fmt, ...);
+void	warnl(int line, char *fmt, ...);
+void	yyerror(char *fmt, ...);
+void	yyerrorl(int line, char *fmt, ...);
+
+/*
+ *	swt.c
+ */
+void	typecheckswitch(Node *n);
+void	walkswitch(Node *sw);
+
+/*
+ *	typecheck.c
+ */
+int	islvalue(Node *n);
+Node*	typecheck(Node **np, int top);
+void	typechecklist(NodeList *l, int top);
+Node*	typecheckdef(Node *n);
+void	copytype(Node *n, Type *t);
+void	checkreturn(Node*);
+void	queuemethod(Node *n);
+
+/*
+ *	unsafe.c
+ */
+int	isunsafebuiltin(Node *n);
+Node*	unsafenmagic(Node *n);
+
+/*
+ *	walk.c
+ */
+Node*	callnew(Type *t);
+Node*	chanfn(char *name, int n, Type *t);
+Node*	mkcall(char *name, Type *t, NodeList **init, ...);
+Node*	mkcall1(Node *fn, Type *t, NodeList **init, ...);
+int	vmatch1(Node *l, Node *r);
+void	walk(Node *fn);
+void	walkexpr(Node **np, NodeList **init);
+void	walkexprlist(NodeList *l, NodeList **init);
+void	walkexprlistsafe(NodeList *l, NodeList **init);
+void	walkstmt(Node **np);
+void	walkstmtlist(NodeList *l);
+Node*	conv(Node*, Type*);
+int	candiscard(Node*);
+int	needwritebarrier(Node*, Node*);
+Node*	outervalue(Node*);
+void	usefield(Node*);
+
+/*
+ *	arch-specific ggen.c/gsubr.c/gobj.c/pgen.c/plive.c
+ */
+#define	P	((Prog*)0)
+
+EXTERN	Prog*	continpc;
+EXTERN	Prog*	breakpc;
+EXTERN	Prog*	pc;
+EXTERN	Prog*	firstpc;
+
+EXTERN	Node*	nodfp;
+EXTERN	int	disable_checknil;
+EXTERN	vlong	zerosize;
+
+int	anyregalloc(void);
+void	betypeinit(void);
+void	bgen(Node *n, int true, int likely, Prog *to);
+void	checknil(Node*, NodeList**);
+void	expandchecks(Prog*);
+void	cgen(Node*, Node*);
+void	cgen_asop(Node *n);
+void	cgen_call(Node *n, int proc);
+void	cgen_callinter(Node *n, Node *res, int proc);
+void	cgen_checknil(Node*);
+void	cgen_ret(Node *n);
+void	clearfat(Node *n);
+void	compile(Node*);
+void	defframe(Prog*);
+int	dgostringptr(Sym*, int off, char *str);
+int	dgostrlitptr(Sym*, int off, Strlit*);
+int	dstringptr(Sym *s, int off, char *str);
+int	dsymptr(Sym *s, int off, Sym *x, int xoff);
+int	duintxx(Sym *s, int off, uint64 v, int wid);
+void	dumpdata(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, int8 flags);
+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	twobitwalktype1(Type*, vlong*, Bvec*);
+void	markautoused(Prog*);
+Plist*	newplist(void);
+Node*	nodarg(Type*, int);
+void	nopout(Prog*);
+void	patch(Prog*, Prog*);
+Prog*	unpatch(Prog*);
+
+#pragma	varargck	type	"B"	Mpint*
+#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"	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	"Q"	Bits
+#pragma	varargck	type	"S"	Sym*
+#pragma	varargck	type	"lS"	LSym*
+#pragma	varargck	type	"T"	Type*
+#pragma	varargck	type	"lT"	Type*
+#pragma	varargck	type	"V"	Val*
+#pragma	varargck	type	"Z"	Strlit*
+
+/*
+ *	racewalk.c
+ */
+void	racewalk(Node *fn);
diff --git a/src/cmd/gc/go.y b/src/cmd/gc/go.y
new file mode 100644
index 0000000..68fccc1
--- /dev/null
+++ b/src/cmd/gc/go.y
@@ -0,0 +1,2223 @@
+// 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 language grammar.
+ *
+ * The Go semicolon rules are:
+ *
+ *  1. all statements and declarations are terminated by semicolons.
+ *  2. semicolons can be omitted before a closing ) or }.
+ *  3. semicolons are inserted by the lexer before a newline
+ *      following a specific list of tokens.
+ *
+ * Rules #1 and #2 are accomplished by writing the lists as
+ * semicolon-separated lists with an optional trailing semicolon.
+ * Rule #3 is implemented in yylex.
+ */
+
+%{
+#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);
+%}
+%union	{
+	Node*		node;
+	NodeList*		list;
+	Type*		type;
+	Sym*		sym;
+	struct	Val	val;
+	int		i;
+}
+
+// |sed 's/.*	//' |9 fmt -l1 |sort |9 fmt -l50 | sed 's/^/%xxx		/'
+
+%token	<val>	LLITERAL
+%token	<i>	LASOP LCOLAS
+%token	<sym>	LBREAK LCASE LCHAN LCONST LCONTINUE LDDD
+%token	<sym>	LDEFAULT LDEFER LELSE LFALL LFOR LFUNC LGO LGOTO
+%token	<sym>	LIF LIMPORT LINTERFACE LMAP LNAME
+%token	<sym>	LPACKAGE LRANGE LRETURN LSELECT LSTRUCT LSWITCH
+%token	<sym>	LTYPE LVAR
+
+%token		LANDAND LANDNOT LBODY LCOMM LDEC LEQ LGE LGT
+%token		LIGNORE LINC LLE LLSH LLT LNE LOROR LRSH
+
+%type	<i>	lbrace import_here
+%type	<sym>	sym packname
+%type	<val>	oliteral
+
+%type	<node>	stmt ntype
+%type	<node>	arg_type
+%type	<node>	case caseblock
+%type	<node>	compound_stmt dotname embed expr complitexpr bare_complitexpr
+%type	<node>	expr_or_type
+%type	<node>	fndcl hidden_fndcl fnliteral
+%type	<node>	for_body for_header for_stmt if_header if_stmt non_dcl_stmt
+%type	<node>	interfacedcl keyval labelname name
+%type	<node>	name_or_type non_expr_type
+%type	<node>	new_name dcl_name oexpr typedclname
+%type	<node>	onew_name
+%type	<node>	osimple_stmt pexpr pexpr_no_paren
+%type	<node>	pseudocall range_stmt select_stmt
+%type	<node>	simple_stmt
+%type	<node>	switch_stmt uexpr
+%type	<node>	xfndcl typedcl start_complit
+
+%type	<list>	xdcl fnbody fnres loop_body dcl_name_list
+%type	<list>	new_name_list expr_list keyval_list braced_keyval_list expr_or_type_list xdcl_list
+%type	<list>	oexpr_list caseblock_list elseif elseif_list else stmt_list oarg_type_list_ocomma arg_type_list
+%type	<list>	interfacedcl_list vardcl vardcl_list structdcl structdcl_list
+%type	<list>	common_dcl constdcl constdcl1 constdcl_list typedcl_list
+
+%type	<node>	convtype comptype dotdotdot
+%type	<node>	indcl interfacetype structtype ptrtype
+%type	<node>	recvchantype non_recvchantype othertype fnret_type fntype
+
+%type	<sym>	hidden_importsym hidden_pkg_importsym
+
+%type	<node>	hidden_constant hidden_literal hidden_funarg
+%type	<node>	hidden_interfacedcl hidden_structdcl
+
+%type	<list>	hidden_funres
+%type	<list>	ohidden_funres
+%type	<list>	hidden_funarg_list ohidden_funarg_list
+%type	<list>	hidden_interfacedcl_list ohidden_interfacedcl_list
+%type	<list>	hidden_structdcl_list ohidden_structdcl_list
+
+%type	<type>	hidden_type hidden_type_misc hidden_pkgtype
+%type	<type>	hidden_type_func
+%type	<type>	hidden_type_recv_chan hidden_type_non_recv_chan
+
+%left		LCOMM	/* outside the usual hierarchy; here for good error messages */
+
+%left		LOROR
+%left		LANDAND
+%left		LEQ LNE LLE LGE LLT LGT
+%left		'+' '-' '|' '^'
+%left		'*' '/' '%' '&' LLSH LRSH LANDNOT
+
+/*
+ * manual override of shift/reduce conflicts.
+ * the general form is that we assign a precedence
+ * to the token being shifted and then introduce
+ * NotToken with lower precedence or PreferToToken with higher
+ * and annotate the reducing rule accordingly.
+ */
+%left		NotPackage
+%left		LPACKAGE
+
+%left		NotParen
+%left		'('
+
+%left		')'
+%left		PreferToRightParen
+
+%error-verbose
+
+%%
+file:
+	loadsys
+	package
+	imports
+	xdcl_list
+	{
+		xtop = concat(xtop, $4);
+	}
+
+package:
+	%prec NotPackage
+	{
+		prevlineno = lineno;
+		yyerror("package statement must be first");
+		errorexit();
+	}
+|	LPACKAGE sym ';'
+	{
+		mkpackage($2->name);
+	}
+
+/*
+ * this loads the definitions for the low-level runtime functions,
+ * so that the compiler can generate calls to them,
+ * but does not make the name "runtime" visible as a package.
+ */
+loadsys:
+	{
+		importpkg = runtimepkg;
+
+		if(debug['A'])
+			cannedimports("runtime.builtin", "package runtime\n\n$$\n\n");
+		else
+			cannedimports("runtime.builtin", runtimeimport);
+		curio.importsafe = 1;
+	}
+	import_package
+	import_there
+	{
+		importpkg = nil;
+	}
+
+imports:
+|	imports import ';'
+
+import:
+	LIMPORT import_stmt
+|	LIMPORT '(' import_stmt_list osemi ')'
+|	LIMPORT '(' ')'
+
+import_stmt:
+	import_here import_package import_there
+	{
+		Pkg *ipkg;
+		Sym *my;
+		Node *pack;
+		
+		ipkg = importpkg;
+		my = importmyname;
+		importpkg = nil;
+		importmyname = S;
+
+		if(my == nil)
+			my = lookup(ipkg->name);
+
+		pack = nod(OPACK, N, N);
+		pack->sym = my;
+		pack->pkg = ipkg;
+		pack->lineno = $1;
+
+		if(my->name[0] == '.') {
+			importdot(ipkg, pack);
+			break;
+		}
+		if(strcmp(my->name, "init") == 0) {
+			yyerror("cannot import package as init - init must be a func");
+			break;
+		}
+		if(my->name[0] == '_' && my->name[1] == '\0')
+			break;
+		if(my->def) {
+			lineno = $1;
+			redeclare(my, "as imported package name");
+		}
+		my->def = pack;
+		my->lastlineno = $1;
+		my->block = 1;	// at top level
+	}
+|	import_here import_there
+	{
+		// When an invalid import path is passed to importfile,
+		// it calls yyerror and then sets up a fake import with
+		// no package statement. This allows us to test more
+		// than one invalid import statement in a single file.
+		if(nerrors == 0)
+			fatal("phase error in import");
+	}
+
+import_stmt_list:
+	import_stmt
+|	import_stmt_list ';' import_stmt
+
+import_here:
+	LLITERAL
+	{
+		// import with original name
+		$$ = parserline();
+		importmyname = S;
+		importfile(&$1, $$);
+	}
+|	sym LLITERAL
+	{
+		// import with given name
+		$$ = parserline();
+		importmyname = $1;
+		importfile(&$2, $$);
+	}
+|	'.' LLITERAL
+	{
+		// import into my name space
+		$$ = parserline();
+		importmyname = lookup(".");
+		importfile(&$2, $$);
+	}
+
+import_package:
+	LPACKAGE LNAME import_safety ';'
+	{
+		if(importpkg->name == nil) {
+			importpkg->name = $2->name;
+			pkglookup($2->name, nil)->npkg++;
+		} else if(strcmp(importpkg->name, $2->name) != 0)
+			yyerror("conflicting names %s and %s for package \"%Z\"", importpkg->name, $2->name, importpkg->path);
+		importpkg->direct = 1;
+		importpkg->safe = curio.importsafe;
+
+		if(safemode && !curio.importsafe)
+			yyerror("cannot import unsafe package \"%Z\"", importpkg->path);
+	}
+
+import_safety:
+|	LNAME
+	{
+		if(strcmp($1->name, "safe") == 0)
+			curio.importsafe = 1;
+	}
+
+import_there:
+	{
+		defercheckwidth();
+	}
+	hidden_import_list '$' '$'
+	{
+		resumecheckwidth();
+		unimportfile();
+	}
+
+/*
+ * declarations
+ */
+xdcl:
+	{
+		yyerror("empty top-level declaration");
+		$$ = nil;
+	}
+|	common_dcl
+|	xfndcl
+	{
+		$$ = list1($1);
+	}
+|	non_dcl_stmt
+	{
+		yyerror("non-declaration statement outside function body");
+		$$ = nil;
+	}
+|	error
+	{
+		$$ = nil;
+	}
+
+common_dcl:
+	LVAR vardcl
+	{
+		$$ = $2;
+	}
+|	LVAR '(' vardcl_list osemi ')'
+	{
+		$$ = $3;
+	}
+|	LVAR '(' ')'
+	{
+		$$ = nil;
+	}
+|	lconst constdcl
+	{
+		$$ = $2;
+		iota = -100000;
+		lastconst = nil;
+	}
+|	lconst '(' constdcl osemi ')'
+	{
+		$$ = $3;
+		iota = -100000;
+		lastconst = nil;
+	}
+|	lconst '(' constdcl ';' constdcl_list osemi ')'
+	{
+		$$ = concat($3, $5);
+		iota = -100000;
+		lastconst = nil;
+	}
+|	lconst '(' ')'
+	{
+		$$ = nil;
+		iota = -100000;
+	}
+|	LTYPE typedcl
+	{
+		$$ = list1($2);
+	}
+|	LTYPE '(' typedcl_list osemi ')'
+	{
+		$$ = $3;
+	}
+|	LTYPE '(' ')'
+	{
+		$$ = nil;
+	}
+
+lconst:
+	LCONST
+	{
+		iota = 0;
+	}
+
+vardcl:
+	dcl_name_list ntype
+	{
+		$$ = variter($1, $2, nil);
+	}
+|	dcl_name_list ntype '=' expr_list
+	{
+		$$ = variter($1, $2, $4);
+	}
+|	dcl_name_list '=' expr_list
+	{
+		$$ = variter($1, nil, $3);
+	}
+
+constdcl:
+	dcl_name_list ntype '=' expr_list
+	{
+		$$ = constiter($1, $2, $4);
+	}
+|	dcl_name_list '=' expr_list
+	{
+		$$ = constiter($1, N, $3);
+	}
+
+constdcl1:
+	constdcl
+|	dcl_name_list ntype
+	{
+		$$ = constiter($1, $2, nil);
+	}
+|	dcl_name_list
+	{
+		$$ = constiter($1, N, nil);
+	}
+
+typedclname:
+	sym
+	{
+		// different from dclname because the name
+		// becomes visible right here, not at the end
+		// of the declaration.
+		$$ = typedcl0($1);
+	}
+
+typedcl:
+	typedclname ntype
+	{
+		$$ = typedcl1($1, $2, 1);
+	}
+
+simple_stmt:
+	expr
+	{
+		$$ = $1;
+
+		// These nodes do not carry line numbers.
+		// Since a bare name used as an expression is an error,
+		// introduce a wrapper node to give the correct line.
+		switch($$->op) {
+		case ONAME:
+		case ONONAME:
+		case OTYPE:
+		case OPACK:
+		case OLITERAL:
+			$$ = nod(OPAREN, $$, N);
+			$$->implicit = 1;
+			break;
+		}
+	}
+|	expr LASOP expr
+	{
+		$$ = nod(OASOP, $1, $3);
+		$$->etype = $2;			// rathole to pass opcode
+	}
+|	expr_list '=' expr_list
+	{
+		if($1->next == nil && $3->next == nil) {
+			// simple
+			$$ = nod(OAS, $1->n, $3->n);
+			break;
+		}
+		// multiple
+		$$ = nod(OAS2, N, N);
+		$$->list = $1;
+		$$->rlist = $3;
+	}
+|	expr_list LCOLAS expr_list
+	{
+		if($3->n->op == OTYPESW) {
+			$$ = nod(OTYPESW, N, $3->n->right);
+			if($3->next != nil)
+				yyerror("expr.(type) must be alone in list");
+			if($1->next != nil)
+				yyerror("argument count mismatch: %d = %d", count($1), 1);
+			else if(($1->n->op != ONAME && $1->n->op != OTYPE && $1->n->op != ONONAME) || isblank($1->n))
+				yyerror("invalid variable name %N in type switch", $1->n);
+			else
+				$$->left = dclname($1->n->sym);  // it's a colas, so must not re-use an oldname.
+			break;
+		}
+		$$ = colas($1, $3, $2);
+	}
+|	expr LINC
+	{
+		$$ = nod(OASOP, $1, nodintconst(1));
+		$$->implicit = 1;
+		$$->etype = OADD;
+	}
+|	expr LDEC
+	{
+		$$ = nod(OASOP, $1, nodintconst(1));
+		$$->implicit = 1;
+		$$->etype = OSUB;
+	}
+
+case:
+	LCASE expr_or_type_list ':'
+	{
+		Node *n, *nn;
+
+		// will be converted to OCASE
+		// right will point to next case
+		// done in casebody()
+		markdcl();
+		$$ = nod(OXCASE, N, N);
+		$$->list = $2;
+		if(typesw != N && typesw->right != N && (n=typesw->right->left) != N) {
+			// type switch - declare variable
+			nn = newname(n->sym);
+			declare(nn, dclcontext);
+			$$->nname = nn;
+
+			// keep track of the instances for reporting unused
+			nn->defn = typesw->right;
+		}
+	}
+|	LCASE expr_or_type_list '=' expr ':'
+	{
+		Node *n;
+
+		// will be converted to OCASE
+		// right will point to next case
+		// done in casebody()
+		markdcl();
+		$$ = nod(OXCASE, N, N);
+		if($2->next == nil)
+			n = nod(OAS, $2->n, $4);
+		else {
+			n = nod(OAS2, N, N);
+			n->list = $2;
+			n->rlist = list1($4);
+		}
+		$$->list = list1(n);
+	}
+|	LCASE expr_or_type_list LCOLAS expr ':'
+	{
+		// will be converted to OCASE
+		// right will point to next case
+		// done in casebody()
+		markdcl();
+		$$ = nod(OXCASE, N, N);
+		$$->list = list1(colas($2, list1($4), $3));
+	}
+|	LDEFAULT ':'
+	{
+		Node *n, *nn;
+
+		markdcl();
+		$$ = nod(OXCASE, N, N);
+		if(typesw != N && typesw->right != N && (n=typesw->right->left) != N) {
+			// type switch - declare variable
+			nn = newname(n->sym);
+			declare(nn, dclcontext);
+			$$->nname = nn;
+
+			// keep track of the instances for reporting unused
+			nn->defn = typesw->right;
+		}
+	}
+
+compound_stmt:
+	'{'
+	{
+		markdcl();
+	}
+	stmt_list '}'
+	{
+		if($3 == nil)
+			$$ = nod(OEMPTY, N, N);
+		else
+			$$ = liststmt($3);
+		popdcl();
+	}
+
+caseblock:
+	case
+	{
+		// If the last token read by the lexer was consumed
+		// as part of the case, clear it (parser has cleared yychar).
+		// If the last token read by the lexer was the lookahead
+		// leave it alone (parser has it cached in yychar).
+		// This is so that the stmt_list action doesn't look at
+		// the case tokens if the stmt_list is empty.
+		yylast = yychar;
+		$1->xoffset = block;
+	}
+	stmt_list
+	{
+		int last;
+
+		// This is the only place in the language where a statement
+		// list is not allowed to drop the final semicolon, because
+		// it's the only place where a statement list is not followed 
+		// by a closing brace.  Handle the error for pedantry.
+
+		// Find the final token of the statement list.
+		// yylast is lookahead; yyprev is last of stmt_list
+		last = yyprev;
+
+		if(last > 0 && last != ';' && yychar != '}')
+			yyerror("missing statement after label");
+		$$ = $1;
+		$$->nbody = $3;
+		popdcl();
+	}
+
+caseblock_list:
+	{
+		$$ = nil;
+	}
+|	caseblock_list caseblock
+	{
+		$$ = list($1, $2);
+	}
+
+loop_body:
+	LBODY
+	{
+		markdcl();
+	}
+	stmt_list '}'
+	{
+		$$ = $3;
+		popdcl();
+	}
+
+range_stmt:
+	expr_list '=' LRANGE expr
+	{
+		$$ = nod(ORANGE, N, $4);
+		$$->list = $1;
+		$$->etype = 0;	// := flag
+	}
+|	expr_list LCOLAS LRANGE expr
+	{
+		$$ = nod(ORANGE, N, $4);
+		$$->list = $1;
+		$$->colas = 1;
+		colasdefn($1, $$);
+	}
+|	LRANGE expr
+	{
+		$$ = nod(ORANGE, N, $2);
+		$$->etype = 0; // := flag
+	}
+
+for_header:
+	osimple_stmt ';' osimple_stmt ';' osimple_stmt
+	{
+		// init ; test ; incr
+		if($5 != N && $5->colas != 0)
+			yyerror("cannot declare in the for-increment");
+		$$ = nod(OFOR, N, N);
+		if($1 != N)
+			$$->ninit = list1($1);
+		$$->ntest = $3;
+		$$->nincr = $5;
+	}
+|	osimple_stmt
+	{
+		// normal test
+		$$ = nod(OFOR, N, N);
+		$$->ntest = $1;
+	}
+|	range_stmt
+
+for_body:
+	for_header loop_body
+	{
+		$$ = $1;
+		$$->nbody = concat($$->nbody, $2);
+	}
+
+for_stmt:
+	LFOR
+	{
+		markdcl();
+	}
+	for_body
+	{
+		$$ = $3;
+		popdcl();
+	}
+
+if_header:
+	osimple_stmt
+	{
+		// test
+		$$ = nod(OIF, N, N);
+		$$->ntest = $1;
+	}
+|	osimple_stmt ';' osimple_stmt
+	{
+		// init ; test
+		$$ = nod(OIF, N, N);
+		if($1 != N)
+			$$->ninit = list1($1);
+		$$->ntest = $3;
+	}
+
+/* IF cond body (ELSE IF cond body)* (ELSE block)? */
+if_stmt:
+	LIF
+	{
+		markdcl();
+	}
+	if_header
+	{
+		if($3->ntest == N)
+			yyerror("missing condition in if statement");
+	}
+	loop_body
+	{
+		$3->nbody = $5;
+	}
+	elseif_list else
+	{
+		Node *n;
+		NodeList *nn;
+
+		$$ = $3;
+		n = $3;
+		popdcl();
+		for(nn = concat($7, $8); nn; nn = nn->next) {
+			if(nn->n->op == OIF)
+				popdcl();
+			n->nelse = list1(nn->n);
+			n = nn->n;
+		}
+	}
+
+elseif:
+	LELSE LIF 
+	{
+		markdcl();
+	}
+	if_header loop_body
+	{
+		if($4->ntest == N)
+			yyerror("missing condition in if statement");
+		$4->nbody = $5;
+		$$ = list1($4);
+	}
+
+elseif_list:
+	{
+		$$ = nil;
+	}
+|	elseif_list elseif
+	{
+		$$ = concat($1, $2);
+	}
+
+else:
+	{
+		$$ = nil;
+	}
+|	LELSE compound_stmt
+	{
+		NodeList *node;
+		
+		node = mal(sizeof *node);
+		node->n = $2;
+		node->end = node;
+		$$ = node;
+	}
+
+switch_stmt:
+	LSWITCH
+	{
+		markdcl();
+	}
+	if_header
+	{
+		Node *n;
+		n = $3->ntest;
+		if(n != N && n->op != OTYPESW)
+			n = N;
+		typesw = nod(OXXX, typesw, n);
+	}
+	LBODY caseblock_list '}'
+	{
+		$$ = $3;
+		$$->op = OSWITCH;
+		$$->list = $6;
+		typesw = typesw->left;
+		popdcl();
+	}
+
+select_stmt:
+	LSELECT
+	{
+		typesw = nod(OXXX, typesw, N);
+	}
+	LBODY caseblock_list '}'
+	{
+		$$ = nod(OSELECT, N, N);
+		$$->lineno = typesw->lineno;
+		$$->list = $4;
+		typesw = typesw->left;
+	}
+
+/*
+ * expressions
+ */
+expr:
+	uexpr
+|	expr LOROR expr
+	{
+		$$ = nod(OOROR, $1, $3);
+	}
+|	expr LANDAND expr
+	{
+		$$ = nod(OANDAND, $1, $3);
+	}
+|	expr LEQ expr
+	{
+		$$ = nod(OEQ, $1, $3);
+	}
+|	expr LNE expr
+	{
+		$$ = nod(ONE, $1, $3);
+	}
+|	expr LLT expr
+	{
+		$$ = nod(OLT, $1, $3);
+	}
+|	expr LLE expr
+	{
+		$$ = nod(OLE, $1, $3);
+	}
+|	expr LGE expr
+	{
+		$$ = nod(OGE, $1, $3);
+	}
+|	expr LGT expr
+	{
+		$$ = nod(OGT, $1, $3);
+	}
+|	expr '+' expr
+	{
+		$$ = nod(OADD, $1, $3);
+	}
+|	expr '-' expr
+	{
+		$$ = nod(OSUB, $1, $3);
+	}
+|	expr '|' expr
+	{
+		$$ = nod(OOR, $1, $3);
+	}
+|	expr '^' expr
+	{
+		$$ = nod(OXOR, $1, $3);
+	}
+|	expr '*' expr
+	{
+		$$ = nod(OMUL, $1, $3);
+	}
+|	expr '/' expr
+	{
+		$$ = nod(ODIV, $1, $3);
+	}
+|	expr '%' expr
+	{
+		$$ = nod(OMOD, $1, $3);
+	}
+|	expr '&' expr
+	{
+		$$ = nod(OAND, $1, $3);
+	}
+|	expr LANDNOT expr
+	{
+		$$ = nod(OANDNOT, $1, $3);
+	}
+|	expr LLSH expr
+	{
+		$$ = nod(OLSH, $1, $3);
+	}
+|	expr LRSH expr
+	{
+		$$ = nod(ORSH, $1, $3);
+	}
+	/* not an expression anymore, but left in so we can give a good error */
+|	expr LCOMM expr
+	{
+		$$ = nod(OSEND, $1, $3);
+	}
+
+uexpr:
+	pexpr
+|	'*' uexpr
+	{
+		$$ = nod(OIND, $2, N);
+	}
+|	'&' uexpr
+	{
+		if($2->op == OCOMPLIT) {
+			// Special case for &T{...}: turn into (*T){...}.
+			$$ = $2;
+			$$->right = nod(OIND, $$->right, N);
+			$$->right->implicit = 1;
+		} else {
+			$$ = nod(OADDR, $2, N);
+		}
+	}
+|	'+' uexpr
+	{
+		$$ = nod(OPLUS, $2, N);
+	}
+|	'-' uexpr
+	{
+		$$ = nod(OMINUS, $2, N);
+	}
+|	'!' uexpr
+	{
+		$$ = nod(ONOT, $2, N);
+	}
+|	'~' uexpr
+	{
+		yyerror("the bitwise complement operator is ^");
+		$$ = nod(OCOM, $2, N);
+	}
+|	'^' uexpr
+	{
+		$$ = nod(OCOM, $2, N);
+	}
+|	LCOMM uexpr
+	{
+		$$ = nod(ORECV, $2, N);
+	}
+
+/*
+ * call-like statements that
+ * can be preceded by 'defer' and 'go'
+ */
+pseudocall:
+	pexpr '(' ')'
+	{
+		$$ = nod(OCALL, $1, N);
+	}
+|	pexpr '(' expr_or_type_list ocomma ')'
+	{
+		$$ = nod(OCALL, $1, N);
+		$$->list = $3;
+	}
+|	pexpr '(' expr_or_type_list LDDD ocomma ')'
+	{
+		$$ = nod(OCALL, $1, N);
+		$$->list = $3;
+		$$->isddd = 1;
+	}
+
+pexpr_no_paren:
+	LLITERAL
+	{
+		$$ = nodlit($1);
+	}
+|	name
+|	pexpr '.' sym
+	{
+		if($1->op == OPACK) {
+			Sym *s;
+			s = restrictlookup($3->name, $1->pkg);
+			$1->used = 1;
+			$$ = oldname(s);
+			break;
+		}
+		$$ = nod(OXDOT, $1, newname($3));
+	}
+|	pexpr '.' '(' expr_or_type ')'
+	{
+		$$ = nod(ODOTTYPE, $1, $4);
+	}
+|	pexpr '.' '(' LTYPE ')'
+	{
+		$$ = nod(OTYPESW, N, $1);
+	}
+|	pexpr '[' expr ']'
+	{
+		$$ = nod(OINDEX, $1, $3);
+	}
+|	pexpr '[' oexpr ':' oexpr ']'
+	{
+		$$ = nod(OSLICE, $1, nod(OKEY, $3, $5));
+	}
+|	pexpr '[' oexpr ':' oexpr ':' oexpr ']'
+	{
+		if($5 == N)
+			yyerror("middle index required in 3-index slice");
+		if($7 == N)
+			yyerror("final index required in 3-index slice");
+		$$ = nod(OSLICE3, $1, nod(OKEY, $3, nod(OKEY, $5, $7)));
+	}
+|	pseudocall
+|	convtype '(' expr ocomma ')'
+	{
+		// conversion
+		$$ = nod(OCALL, $1, N);
+		$$->list = list1($3);
+	}
+|	comptype lbrace start_complit braced_keyval_list '}'
+	{
+		$$ = $3;
+		$$->right = $1;
+		$$->list = $4;
+		fixlbrace($2);
+	}
+|	pexpr_no_paren '{' start_complit braced_keyval_list '}'
+	{
+		$$ = $3;
+		$$->right = $1;
+		$$->list = $4;
+	}
+|	'(' expr_or_type ')' '{' start_complit braced_keyval_list '}'
+	{
+		yyerror("cannot parenthesize type in composite literal");
+		$$ = $5;
+		$$->right = $2;
+		$$->list = $6;
+	}
+|	fnliteral
+
+start_complit:
+	{
+		// composite expression.
+		// make node early so we get the right line number.
+		$$ = nod(OCOMPLIT, N, N);
+	}
+
+keyval:
+	expr ':' complitexpr
+	{
+		$$ = nod(OKEY, $1, $3);
+	}
+
+bare_complitexpr:
+	expr
+	{
+		// These nodes do not carry line numbers.
+		// Since a composite literal commonly spans several lines,
+		// the line number on errors may be misleading.
+		// Introduce a wrapper node to give the correct line.
+		$$ = $1;
+		switch($$->op) {
+		case ONAME:
+		case ONONAME:
+		case OTYPE:
+		case OPACK:
+		case OLITERAL:
+			$$ = nod(OPAREN, $$, N);
+			$$->implicit = 1;
+		}
+	}
+|	'{' start_complit braced_keyval_list '}'
+	{
+		$$ = $2;
+		$$->list = $3;
+	}
+
+complitexpr:
+	expr
+|	'{' start_complit braced_keyval_list '}'
+	{
+		$$ = $2;
+		$$->list = $3;
+	}
+
+pexpr:
+	pexpr_no_paren
+|	'(' expr_or_type ')'
+	{
+		$$ = $2;
+		
+		// Need to know on lhs of := whether there are ( ).
+		// Don't bother with the OPAREN in other cases:
+		// it's just a waste of memory and time.
+		switch($$->op) {
+		case ONAME:
+		case ONONAME:
+		case OPACK:
+		case OTYPE:
+		case OLITERAL:
+		case OTYPESW:
+			$$ = nod(OPAREN, $$, N);
+		}
+	}
+
+expr_or_type:
+	expr
+|	non_expr_type	%prec PreferToRightParen
+
+name_or_type:
+	ntype
+
+lbrace:
+	LBODY
+	{
+		$$ = LBODY;
+	}
+|	'{'
+	{
+		$$ = '{';
+	}
+
+/*
+ * names and types
+ *	newname is used before declared
+ *	oldname is used after declared
+ */
+new_name:
+	sym
+	{
+		if($1 == S)
+			$$ = N;
+		else
+			$$ = newname($1);
+	}
+
+dcl_name:
+	sym
+	{
+		$$ = dclname($1);
+	}
+
+onew_name:
+	{
+		$$ = N;
+	}
+|	new_name
+
+sym:
+	LNAME
+	{
+		$$ = $1;
+		// during imports, unqualified non-exported identifiers are from builtinpkg
+		if(importpkg != nil && !exportname($1->name))
+			$$ = pkglookup($1->name, builtinpkg);
+	}
+|	hidden_importsym
+|	'?'
+	{
+		$$ = S;
+	}
+
+hidden_importsym:
+	'@' LLITERAL '.' LNAME
+	{
+		Pkg *p;
+
+		if($2.u.sval->len == 0)
+			p = importpkg;
+		else {
+			if(isbadimport($2.u.sval))
+				errorexit();
+			p = mkpkg($2.u.sval);
+		}
+		$$ = pkglookup($4->name, p);
+	}
+|	'@' LLITERAL '.' '?'
+	{
+		Pkg *p;
+
+		if($2.u.sval->len == 0)
+			p = importpkg;
+		else {
+			if(isbadimport($2.u.sval))
+				errorexit();
+			p = mkpkg($2.u.sval);
+		}
+		$$ = pkglookup("?", p);
+	}
+
+name:
+	sym	%prec NotParen
+	{
+		$$ = oldname($1);
+		if($$->pack != N)
+			$$->pack->used = 1;
+	}
+
+labelname:
+	new_name
+
+/*
+ * to avoid parsing conflicts, type is split into
+ *	channel types
+ *	function types
+ *	parenthesized types
+ *	any other type
+ * the type system makes additional restrictions,
+ * but those are not implemented in the grammar.
+ */
+dotdotdot:
+	LDDD
+	{
+		yyerror("final argument in variadic function missing type");
+		$$ = nod(ODDD, typenod(typ(TINTER)), N);
+	}
+|	LDDD ntype
+	{
+		$$ = nod(ODDD, $2, N);
+	}
+
+ntype:
+	recvchantype
+|	fntype
+|	othertype
+|	ptrtype
+|	dotname
+|	'(' ntype ')'
+	{
+		$$ = $2;
+	}
+
+non_expr_type:
+	recvchantype
+|	fntype
+|	othertype
+|	'*' non_expr_type
+	{
+		$$ = nod(OIND, $2, N);
+	}
+
+non_recvchantype:
+	fntype
+|	othertype
+|	ptrtype
+|	dotname
+|	'(' ntype ')'
+	{
+		$$ = $2;
+	}
+
+convtype:
+	fntype
+|	othertype
+
+comptype:
+	othertype
+
+fnret_type:
+	recvchantype
+|	fntype
+|	othertype
+|	ptrtype
+|	dotname
+
+dotname:
+	name
+|	name '.' sym
+	{
+		if($1->op == OPACK) {
+			Sym *s;
+			s = restrictlookup($3->name, $1->pkg);
+			$1->used = 1;
+			$$ = oldname(s);
+			break;
+		}
+		$$ = nod(OXDOT, $1, newname($3));
+	}
+
+othertype:
+	'[' oexpr ']' ntype
+	{
+		$$ = nod(OTARRAY, $2, $4);
+	}
+|	'[' LDDD ']' ntype
+	{
+		// array literal of nelem
+		$$ = nod(OTARRAY, nod(ODDD, N, N), $4);
+	}
+|	LCHAN non_recvchantype
+	{
+		$$ = nod(OTCHAN, $2, N);
+		$$->etype = Cboth;
+	}
+|	LCHAN LCOMM ntype
+	{
+		$$ = nod(OTCHAN, $3, N);
+		$$->etype = Csend;
+	}
+|	LMAP '[' ntype ']' ntype
+	{
+		$$ = nod(OTMAP, $3, $5);
+	}
+|	structtype
+|	interfacetype
+
+ptrtype:
+	'*' ntype
+	{
+		$$ = nod(OIND, $2, N);
+	}
+
+recvchantype:
+	LCOMM LCHAN ntype
+	{
+		$$ = nod(OTCHAN, $3, N);
+		$$->etype = Crecv;
+	}
+
+structtype:
+	LSTRUCT lbrace structdcl_list osemi '}'
+	{
+		$$ = nod(OTSTRUCT, N, N);
+		$$->list = $3;
+		fixlbrace($2);
+	}
+|	LSTRUCT lbrace '}'
+	{
+		$$ = nod(OTSTRUCT, N, N);
+		fixlbrace($2);
+	}
+
+interfacetype:
+	LINTERFACE lbrace interfacedcl_list osemi '}'
+	{
+		$$ = nod(OTINTER, N, N);
+		$$->list = $3;
+		fixlbrace($2);
+	}
+|	LINTERFACE lbrace '}'
+	{
+		$$ = nod(OTINTER, N, N);
+		fixlbrace($2);
+	}
+
+/*
+ * function stuff
+ * all in one place to show how crappy it all is
+ */
+xfndcl:
+	LFUNC fndcl fnbody
+	{
+		$$ = $2;
+		if($$ == N)
+			break;
+		if(noescape && $3 != nil)
+			yyerror("can only use //go:noescape with external func implementations");
+		$$->nbody = $3;
+		$$->endlineno = lineno;
+		$$->noescape = noescape;
+		$$->nosplit = nosplit;
+		funcbody($$);
+	}
+
+fndcl:
+	sym '(' oarg_type_list_ocomma ')' fnres
+	{
+		Node *t;
+
+		$$ = N;
+		$3 = checkarglist($3, 1);
+
+		if(strcmp($1->name, "init") == 0) {
+			$1 = renameinit();
+			if($3 != nil || $5 != nil)
+				yyerror("func init must have no arguments and no return values");
+		}
+		if(strcmp(localpkg->name, "main") == 0 && strcmp($1->name, "main") == 0) {
+			if($3 != nil || $5 != nil)
+				yyerror("func main must have no arguments and no return values");
+		}
+
+		t = nod(OTFUNC, N, N);
+		t->list = $3;
+		t->rlist = $5;
+
+		$$ = nod(ODCLFUNC, N, N);
+		$$->nname = newname($1);
+		$$->nname->defn = $$;
+		$$->nname->ntype = t;		// TODO: check if nname already has an ntype
+		declare($$->nname, PFUNC);
+
+		funchdr($$);
+	}
+|	'(' oarg_type_list_ocomma ')' sym '(' oarg_type_list_ocomma ')' fnres
+	{
+		Node *rcvr, *t;
+
+		$$ = N;
+		$2 = checkarglist($2, 0);
+		$6 = checkarglist($6, 1);
+
+		if($2 == nil) {
+			yyerror("method has no receiver");
+			break;
+		}
+		if($2->next != nil) {
+			yyerror("method has multiple receivers");
+			break;
+		}
+		rcvr = $2->n;
+		if(rcvr->op != ODCLFIELD) {
+			yyerror("bad receiver in method");
+			break;
+		}
+
+		t = nod(OTFUNC, rcvr, N);
+		t->list = $6;
+		t->rlist = $8;
+
+		$$ = nod(ODCLFUNC, N, N);
+		$$->shortname = newname($4);
+		$$->nname = methodname1($$->shortname, rcvr->right);
+		$$->nname->defn = $$;
+		$$->nname->ntype = t;
+		$$->nname->nointerface = nointerface;
+		declare($$->nname, PFUNC);
+
+		funchdr($$);
+	}
+
+hidden_fndcl:
+	hidden_pkg_importsym '(' ohidden_funarg_list ')' ohidden_funres
+	{
+		Sym *s;
+		Type *t;
+
+		$$ = N;
+
+		s = $1;
+		t = functype(N, $3, $5);
+
+		importsym(s, ONAME);
+		if(s->def != N && s->def->op == ONAME) {
+			if(eqtype(t, s->def->type)) {
+				dclcontext = PDISCARD;  // since we skip funchdr below
+				break;
+			}
+			yyerror("inconsistent definition for func %S during import\n\t%T\n\t%T", s, s->def->type, t);
+		}
+
+		$$ = newname(s);
+		$$->type = t;
+		declare($$, PFUNC);
+
+		funchdr($$);
+	}
+|	'(' hidden_funarg_list ')' sym '(' ohidden_funarg_list ')' ohidden_funres
+	{
+		$$ = methodname1(newname($4), $2->n->right); 
+		$$->type = functype($2->n, $6, $8);
+
+		checkwidth($$->type);
+		addmethod($4, $$->type, 0, nointerface);
+		nointerface = 0;
+		funchdr($$);
+		
+		// inl.c's inlnode in on a dotmeth node expects to find the inlineable body as
+		// (dotmeth's type)->nname->inl, and dotmeth's type has been pulled
+		// out by typecheck's lookdot as this $$->ttype.  So by providing
+		// this back link here we avoid special casing there.
+		$$->type->nname = $$;
+	}
+
+fntype:
+	LFUNC '(' oarg_type_list_ocomma ')' fnres
+	{
+		$3 = checkarglist($3, 1);
+		$$ = nod(OTFUNC, N, N);
+		$$->list = $3;
+		$$->rlist = $5;
+	}
+
+fnbody:
+	{
+		$$ = nil;
+	}
+|	'{' stmt_list '}'
+	{
+		$$ = $2;
+		if($$ == nil)
+			$$ = list1(nod(OEMPTY, N, N));
+	}
+
+fnres:
+	%prec NotParen
+	{
+		$$ = nil;
+	}
+|	fnret_type
+	{
+		$$ = list1(nod(ODCLFIELD, N, $1));
+	}
+|	'(' oarg_type_list_ocomma ')'
+	{
+		$2 = checkarglist($2, 0);
+		$$ = $2;
+	}
+
+fnlitdcl:
+	fntype
+	{
+		closurehdr($1);
+	}
+
+fnliteral:
+	fnlitdcl lbrace stmt_list '}'
+	{
+		$$ = closurebody($3);
+		fixlbrace($2);
+	}
+|	fnlitdcl error
+	{
+		$$ = closurebody(nil);
+	}
+
+/*
+ * lists of things
+ * note that they are left recursive
+ * to conserve yacc stack. they need to
+ * be reversed to interpret correctly
+ */
+xdcl_list:
+	{
+		$$ = nil;
+	}
+|	xdcl_list xdcl ';'
+	{
+		$$ = concat($1, $2);
+		if(nsyntaxerrors == 0)
+			testdclstack();
+		nointerface = 0;
+		noescape = 0;
+		nosplit = 0;
+	}
+
+vardcl_list:
+	vardcl
+|	vardcl_list ';' vardcl
+	{
+		$$ = concat($1, $3);
+	}
+
+constdcl_list:
+	constdcl1
+|	constdcl_list ';' constdcl1
+	{
+		$$ = concat($1, $3);
+	}
+
+typedcl_list:
+	typedcl
+	{
+		$$ = list1($1);
+	}
+|	typedcl_list ';' typedcl
+	{
+		$$ = list($1, $3);
+	}
+
+structdcl_list:
+	structdcl
+|	structdcl_list ';' structdcl
+	{
+		$$ = concat($1, $3);
+	}
+
+interfacedcl_list:
+	interfacedcl
+	{
+		$$ = list1($1);
+	}
+|	interfacedcl_list ';' interfacedcl
+	{
+		$$ = list($1, $3);
+	}
+
+structdcl:
+	new_name_list ntype oliteral
+	{
+		NodeList *l;
+
+		Node *n;
+		l = $1;
+		if(l == nil) {
+			// ? symbol, during import (list1(N) == nil)
+			n = $2;
+			if(n->op == OIND)
+				n = n->left;
+			n = embedded(n->sym, importpkg);
+			n->right = $2;
+			n->val = $3;
+			$$ = list1(n);
+			break;
+		}
+
+		for(l=$1; l; l=l->next) {
+			l->n = nod(ODCLFIELD, l->n, $2);
+			l->n->val = $3;
+		}
+	}
+|	embed oliteral
+	{
+		$1->val = $2;
+		$$ = list1($1);
+	}
+|	'(' embed ')' oliteral
+	{
+		$2->val = $4;
+		$$ = list1($2);
+		yyerror("cannot parenthesize embedded type");
+	}
+|	'*' embed oliteral
+	{
+		$2->right = nod(OIND, $2->right, N);
+		$2->val = $3;
+		$$ = list1($2);
+	}
+|	'(' '*' embed ')' oliteral
+	{
+		$3->right = nod(OIND, $3->right, N);
+		$3->val = $5;
+		$$ = list1($3);
+		yyerror("cannot parenthesize embedded type");
+	}
+|	'*' '(' embed ')' oliteral
+	{
+		$3->right = nod(OIND, $3->right, N);
+		$3->val = $5;
+		$$ = list1($3);
+		yyerror("cannot parenthesize embedded type");
+	}
+
+packname:
+	LNAME
+	{
+		Node *n;
+
+		$$ = $1;
+		n = oldname($1);
+		if(n->pack != N)
+			n->pack->used = 1;
+	}
+|	LNAME '.' sym
+	{
+		Pkg *pkg;
+
+		if($1->def == N || $1->def->op != OPACK) {
+			yyerror("%S is not a package", $1);
+			pkg = localpkg;
+		} else {
+			$1->def->used = 1;
+			pkg = $1->def->pkg;
+		}
+		$$ = restrictlookup($3->name, pkg);
+	}
+
+embed:
+	packname
+	{
+		$$ = embedded($1, localpkg);
+	}
+
+interfacedcl:
+	new_name indcl
+	{
+		$$ = nod(ODCLFIELD, $1, $2);
+		ifacedcl($$);
+	}
+|	packname
+	{
+		$$ = nod(ODCLFIELD, N, oldname($1));
+	}
+|	'(' packname ')'
+	{
+		$$ = nod(ODCLFIELD, N, oldname($2));
+		yyerror("cannot parenthesize embedded type");
+	}
+
+indcl:
+	'(' oarg_type_list_ocomma ')' fnres
+	{
+		// without func keyword
+		$2 = checkarglist($2, 1);
+		$$ = nod(OTFUNC, fakethis(), N);
+		$$->list = $2;
+		$$->rlist = $4;
+	}
+
+/*
+ * function arguments.
+ */
+arg_type:
+	name_or_type
+|	sym name_or_type
+	{
+		$$ = nod(ONONAME, N, N);
+		$$->sym = $1;
+		$$ = nod(OKEY, $$, $2);
+	}
+|	sym dotdotdot
+	{
+		$$ = nod(ONONAME, N, N);
+		$$->sym = $1;
+		$$ = nod(OKEY, $$, $2);
+	}
+|	dotdotdot
+
+arg_type_list:
+	arg_type
+	{
+		$$ = list1($1);
+	}
+|	arg_type_list ',' arg_type
+	{
+		$$ = list($1, $3);
+	}
+
+oarg_type_list_ocomma:
+	{
+		$$ = nil;
+	}
+|	arg_type_list ocomma
+	{
+		$$ = $1;
+	}
+
+/*
+ * statement
+ */
+stmt:
+	{
+		$$ = N;
+	}
+|	compound_stmt
+|	common_dcl
+	{
+		$$ = liststmt($1);
+	}
+|	non_dcl_stmt
+|	error
+	{
+		$$ = N;
+	}
+
+non_dcl_stmt:
+	simple_stmt
+|	for_stmt
+|	switch_stmt
+|	select_stmt
+|	if_stmt
+|	labelname ':'
+	{
+		$1 = nod(OLABEL, $1, N);
+		$1->sym = dclstack;  // context, for goto restrictions
+	}
+	stmt
+	{
+		NodeList *l;
+
+		$1->defn = $4;
+		l = list1($1);
+		if($4)
+			l = list(l, $4);
+		$$ = liststmt(l);
+	}
+|	LFALL
+	{
+		// will be converted to OFALL
+		$$ = nod(OXFALL, N, N);
+		$$->xoffset = block;
+	}
+|	LBREAK onew_name
+	{
+		$$ = nod(OBREAK, $2, N);
+	}
+|	LCONTINUE onew_name
+	{
+		$$ = nod(OCONTINUE, $2, N);
+	}
+|	LGO pseudocall
+	{
+		$$ = nod(OPROC, $2, N);
+	}
+|	LDEFER pseudocall
+	{
+		$$ = nod(ODEFER, $2, N);
+	}
+|	LGOTO new_name
+	{
+		$$ = nod(OGOTO, $2, N);
+		$$->sym = dclstack;  // context, for goto restrictions
+	}
+|	LRETURN oexpr_list
+	{
+		$$ = nod(ORETURN, N, N);
+		$$->list = $2;
+		if($$->list == nil && curfn != N) {
+			NodeList *l;
+
+			for(l=curfn->dcl; l; l=l->next) {
+				if(l->n->class == PPARAM)
+					continue;
+				if(l->n->class != PPARAMOUT)
+					break;
+				if(l->n->sym->def != l->n)
+					yyerror("%s is shadowed during return", l->n->sym->name);
+			}
+		}
+	}
+
+stmt_list:
+	stmt
+	{
+		$$ = nil;
+		if($1 != N)
+			$$ = list1($1);
+	}
+|	stmt_list ';' stmt
+	{
+		$$ = $1;
+		if($3 != N)
+			$$ = list($$, $3);
+	}
+
+new_name_list:
+	new_name
+	{
+		$$ = list1($1);
+	}
+|	new_name_list ',' new_name
+	{
+		$$ = list($1, $3);
+	}
+
+dcl_name_list:
+	dcl_name
+	{
+		$$ = list1($1);
+	}
+|	dcl_name_list ',' dcl_name
+	{
+		$$ = list($1, $3);
+	}
+
+expr_list:
+	expr
+	{
+		$$ = list1($1);
+	}
+|	expr_list ',' expr
+	{
+		$$ = list($1, $3);
+	}
+
+expr_or_type_list:
+	expr_or_type
+	{
+		$$ = list1($1);
+	}
+|	expr_or_type_list ',' expr_or_type
+	{
+		$$ = list($1, $3);
+	}
+
+/*
+ * list of combo of keyval and val
+ */
+keyval_list:
+	keyval
+	{
+		$$ = list1($1);
+	}
+|	bare_complitexpr
+	{
+		$$ = list1($1);
+	}
+|	keyval_list ',' keyval
+	{
+		$$ = list($1, $3);
+	}
+|	keyval_list ',' bare_complitexpr
+	{
+		$$ = list($1, $3);
+	}
+
+braced_keyval_list:
+	{
+		$$ = nil;
+	}
+|	keyval_list ocomma
+	{
+		$$ = $1;
+	}
+
+/*
+ * optional things
+ */
+osemi:
+|	';'
+
+ocomma:
+|	','
+
+oexpr:
+	{
+		$$ = N;
+	}
+|	expr
+
+oexpr_list:
+	{
+		$$ = nil;
+	}
+|	expr_list
+
+osimple_stmt:
+	{
+		$$ = N;
+	}
+|	simple_stmt
+
+ohidden_funarg_list:
+	{
+		$$ = nil;
+	}
+|	hidden_funarg_list
+
+ohidden_structdcl_list:
+	{
+		$$ = nil;
+	}
+|	hidden_structdcl_list
+
+ohidden_interfacedcl_list:
+	{
+		$$ = nil;
+	}
+|	hidden_interfacedcl_list
+
+oliteral:
+	{
+		$$.ctype = CTxxx;
+	}
+|	LLITERAL
+
+/*
+ * import syntax from package header
+ */
+hidden_import:
+	LIMPORT LNAME LLITERAL ';'
+	{
+		importimport($2, $3.u.sval);
+	}
+|	LVAR hidden_pkg_importsym hidden_type ';'
+	{
+		importvar($2, $3);
+	}
+|	LCONST hidden_pkg_importsym '=' hidden_constant ';'
+	{
+		importconst($2, types[TIDEAL], $4);
+	}
+|	LCONST hidden_pkg_importsym hidden_type '=' hidden_constant ';'
+	{
+		importconst($2, $3, $5);
+	}
+|	LTYPE hidden_pkgtype hidden_type ';'
+	{
+		importtype($2, $3);
+	}
+|	LFUNC hidden_fndcl fnbody ';'
+	{
+		if($2 == N) {
+			dclcontext = PEXTERN;  // since we skip the funcbody below
+			break;
+		}
+
+		$2->inl = $3;
+
+		funcbody($2);
+		importlist = list(importlist, $2);
+
+		if(debug['E']) {
+			print("import [%Z] func %lN \n", importpkg->path, $2);
+			if(debug['m'] > 2 && $2->inl)
+				print("inl body:%+H\n", $2->inl);
+		}
+	}
+
+hidden_pkg_importsym:
+	hidden_importsym
+	{
+		$$ = $1;
+		structpkg = $$->pkg;
+	}
+
+hidden_pkgtype:
+	hidden_pkg_importsym
+	{
+		$$ = pkgtype($1);
+		importsym($1, OTYPE);
+	}
+
+/*
+ *  importing types
+ */
+
+hidden_type:
+	hidden_type_misc
+|	hidden_type_recv_chan
+|	hidden_type_func
+
+hidden_type_non_recv_chan:
+	hidden_type_misc
+|	hidden_type_func
+
+hidden_type_misc:
+	hidden_importsym
+	{
+		$$ = pkgtype($1);
+	}
+|	LNAME
+	{
+		// predefined name like uint8
+		$1 = pkglookup($1->name, builtinpkg);
+		if($1->def == N || $1->def->op != OTYPE) {
+			yyerror("%s is not a type", $1->name);
+			$$ = T;
+		} else
+			$$ = $1->def->type;
+	}
+|	'[' ']' hidden_type
+	{
+		$$ = aindex(N, $3);
+	}
+|	'[' LLITERAL ']' hidden_type
+	{
+		$$ = aindex(nodlit($2), $4);
+	}
+|	LMAP '[' hidden_type ']' hidden_type
+	{
+		$$ = maptype($3, $5);
+	}
+|	LSTRUCT '{' ohidden_structdcl_list '}'
+	{
+		$$ = tostruct($3);
+	}
+|	LINTERFACE '{' ohidden_interfacedcl_list '}'
+	{
+		$$ = tointerface($3);
+	}
+|	'*' hidden_type
+	{
+		$$ = ptrto($2);
+	}
+|	LCHAN hidden_type_non_recv_chan
+	{
+		$$ = typ(TCHAN);
+		$$->type = $2;
+		$$->chan = Cboth;
+	}
+|	LCHAN '(' hidden_type_recv_chan ')'
+	{
+		$$ = typ(TCHAN);
+		$$->type = $3;
+		$$->chan = Cboth;
+	}
+|	LCHAN LCOMM hidden_type
+	{
+		$$ = typ(TCHAN);
+		$$->type = $3;
+		$$->chan = Csend;
+	}
+
+hidden_type_recv_chan:
+	LCOMM LCHAN hidden_type
+	{
+		$$ = typ(TCHAN);
+		$$->type = $3;
+		$$->chan = Crecv;
+	}
+
+hidden_type_func:
+	LFUNC '(' ohidden_funarg_list ')' ohidden_funres
+	{
+		$$ = functype(nil, $3, $5);
+	}
+
+hidden_funarg:
+	sym hidden_type oliteral
+	{
+		$$ = nod(ODCLFIELD, N, typenod($2));
+		if($1)
+			$$->left = newname($1);
+		$$->val = $3;
+	}
+|	sym LDDD hidden_type oliteral
+	{
+		Type *t;
+	
+		t = typ(TARRAY);
+		t->bound = -1;
+		t->type = $3;
+
+		$$ = nod(ODCLFIELD, N, typenod(t));
+		if($1)
+			$$->left = newname($1);
+		$$->isddd = 1;
+		$$->val = $4;
+	}
+
+hidden_structdcl:
+	sym hidden_type oliteral
+	{
+		Sym *s;
+		Pkg *p;
+
+		if($1 != S && strcmp($1->name, "?") != 0) {
+			$$ = nod(ODCLFIELD, newname($1), typenod($2));
+			$$->val = $3;
+		} else {
+			s = $2->sym;
+			if(s == S && isptr[$2->etype])
+				s = $2->type->sym;
+			p = importpkg;
+			if($1 != S)
+				p = $1->pkg;
+			$$ = embedded(s, p);
+			$$->right = typenod($2);
+			$$->val = $3;
+		}
+	}
+
+hidden_interfacedcl:
+	sym '(' ohidden_funarg_list ')' ohidden_funres
+	{
+		$$ = nod(ODCLFIELD, newname($1), typenod(functype(fakethis(), $3, $5)));
+	}
+|	hidden_type
+	{
+		$$ = nod(ODCLFIELD, N, typenod($1));
+	}
+
+ohidden_funres:
+	{
+		$$ = nil;
+	}
+|	hidden_funres
+
+hidden_funres:
+	'(' ohidden_funarg_list ')'
+	{
+		$$ = $2;
+	}
+|	hidden_type
+	{
+		$$ = list1(nod(ODCLFIELD, N, typenod($1)));
+	}
+
+/*
+ *  importing constants
+ */
+
+hidden_literal:
+	LLITERAL
+	{
+		$$ = nodlit($1);
+	}
+|	'-' LLITERAL
+	{
+		$$ = nodlit($2);
+		switch($$->val.ctype){
+		case CTINT:
+		case CTRUNE:
+			mpnegfix($$->val.u.xval);
+			break;
+		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");
+		}
+	}
+|	sym
+	{
+		$$ = oldname(pkglookup($1->name, builtinpkg));
+		if($$->op != OLITERAL)
+			yyerror("bad constant %S", $$->sym);
+	}
+
+hidden_constant:
+	hidden_literal
+|	'(' hidden_literal '+' hidden_literal ')'
+	{
+		if($2->val.ctype == CTRUNE && $4->val.ctype == CTINT) {
+			$$ = $2;
+			mpaddfixfix($2->val.u.xval, $4->val.u.xval, 0);
+			break;
+		}
+		$4->val.u.cval->real = $4->val.u.cval->imag;
+		mpmovecflt(&$4->val.u.cval->imag, 0.0);
+		$$ = nodcplxlit($2->val, $4->val);
+	}
+
+hidden_import_list:
+|	hidden_import_list hidden_import
+
+hidden_funarg_list:
+	hidden_funarg
+	{
+		$$ = list1($1);
+	}
+|	hidden_funarg_list ',' hidden_funarg
+	{
+		$$ = list($1, $3);
+	}
+
+hidden_structdcl_list:
+	hidden_structdcl
+	{
+		$$ = list1($1);
+	}
+|	hidden_structdcl_list ';' hidden_structdcl
+	{
+		$$ = list($1, $3);
+	}
+
+hidden_interfacedcl_list:
+	hidden_interfacedcl
+	{
+		$$ = list1($1);
+	}
+|	hidden_interfacedcl_list ';' hidden_interfacedcl
+	{
+		$$ = list($1, $3);
+	}
+
+%%
+
+static void
+fixlbrace(int lbr)
+{
+	// If the opening brace was an LBODY,
+	// set up for another one now that we're done.
+	// See comment in lex.c about loophack.
+	if(lbr == LBODY)
+		loophack = 1;
+}
+
diff --git a/src/cmd/gc/init.c b/src/cmd/gc/init.c
new file mode 100644
index 0000000..918d371
--- /dev/null
+++ b/src/cmd/gc/init.c
@@ -0,0 +1,195 @@
+// 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 "go.h"
+
+/*
+ * a function named init is a special case.
+ * it is called by the initialization before
+ * main is run. to make it unique within a
+ * package and also uncallable, the name,
+ * normally "pkg.init", is altered to "pkg.init·1".
+ */
+Sym*
+renameinit(void)
+{
+	static int initgen;
+
+	snprint(namebuf, sizeof(namebuf), "init·%d", ++initgen);
+	return lookup(namebuf);
+}
+
+/*
+ * hand-craft the following initialization code
+ *	var initdone· uint8 				(1)
+ *	func init()					(2)
+ *		if initdone· != 0 {			(3)
+ *			if initdone· == 2		(4)
+ *				return
+ *			throw();			(5)
+ *		}
+ *		initdone· = 1;				(6)
+ *		// over all matching imported symbols
+ *			<pkg>.init()			(7)
+ *		{ <init stmts> }			(8)
+ *		init·<n>() // if any			(9)
+ *		initdone· = 2;				(10)
+ *		return					(11)
+ *	}
+ */
+static int
+anyinit(NodeList *n)
+{
+	uint32 h;
+	Sym *s;
+	NodeList *l;
+
+	// are there any interesting init statements
+	for(l=n; l; l=l->next) {
+		switch(l->n->op) {
+		case ODCLFUNC:
+		case ODCLCONST:
+		case ODCLTYPE:
+		case OEMPTY:
+			break;
+		case OAS:
+			if(isblank(l->n->left) && candiscard(l->n->right))
+				break;
+			// fall through
+		default:
+			return 1;
+		}
+	}
+
+	// is this main
+	if(strcmp(localpkg->name, "main") == 0)
+		return 1;
+
+	// is there an explicit init function
+	snprint(namebuf, sizeof(namebuf), "init·1");
+	s = lookup(namebuf);
+	if(s->def != N)
+		return 1;
+
+	// are there any imported init functions
+	for(h=0; h<NHASH; h++)
+	for(s = hash[h]; s != S; s = s->link) {
+		if(s->name[0] != 'i' || strcmp(s->name, "init") != 0)
+			continue;
+		if(s->def == N)
+			continue;
+		return 1;
+	}
+
+	// then none
+	return 0;
+}
+
+void
+fninit(NodeList *n)
+{
+	int i;
+	Node *gatevar;
+	Node *a, *b, *fn;
+	NodeList *r;
+	uint32 h;
+	Sym *s, *initsym;
+
+	if(debug['A']) {
+		// sys.go or unsafe.go during compiler build
+		return;
+	}
+
+	n = initfix(n);
+	if(!anyinit(n))
+		return;
+
+	r = nil;
+
+	// (1)
+	snprint(namebuf, sizeof(namebuf), "initdone·");
+	gatevar = newname(lookup(namebuf));
+	addvar(gatevar, types[TUINT8], PEXTERN);
+
+	// (2)
+	maxarg = 0;
+	snprint(namebuf, sizeof(namebuf), "init");
+
+	fn = nod(ODCLFUNC, N, N);
+	initsym = lookup(namebuf);
+	fn->nname = newname(initsym);
+	fn->nname->defn = fn;
+	fn->nname->ntype = nod(OTFUNC, N, N);
+	declare(fn->nname, PFUNC);
+	funchdr(fn);
+
+	// (3)
+	a = nod(OIF, N, N);
+	a->ntest = nod(ONE, gatevar, nodintconst(0));
+	r = list(r, a);
+
+	// (4)
+	b = nod(OIF, N, N);
+	b->ntest = nod(OEQ, gatevar, nodintconst(2));
+	b->nbody = list1(nod(ORETURN, N, N));
+	a->nbody = list1(b);
+
+	// (5)
+	b = syslook("throwinit", 0);
+	b = nod(OCALL, b, N);
+	a->nbody = list(a->nbody, b);
+
+	// (6)
+	a = nod(OAS, gatevar, nodintconst(1));
+	r = list(r, a);
+
+	// (7)
+	for(h=0; h<NHASH; h++)
+	for(s = hash[h]; s != S; s = s->link) {
+		if(s->name[0] != 'i' || strcmp(s->name, "init") != 0)
+			continue;
+		if(s->def == N)
+			continue;
+		if(s == initsym)
+			continue;
+
+		// could check that it is fn of no args/returns
+		a = nod(OCALL, s->def, N);
+		r = list(r, a);
+	}
+
+	// (8)
+	r = concat(r, n);
+
+	// (9)
+	// could check that it is fn of no args/returns
+	for(i=1;; i++) {
+		snprint(namebuf, sizeof(namebuf), "init·%d", i);
+		s = lookup(namebuf);
+		if(s->def == N)
+			break;
+		a = nod(OCALL, s->def, N);
+		r = list(r, a);
+	}
+
+	// (10)
+	a = nod(OAS, gatevar, nodintconst(2));
+	r = list(r, a);
+
+	// (11)
+	a = nod(ORETURN, N, N);
+	r = list(r, a);
+	exportsym(fn->nname);
+
+	fn->nbody = r;
+	funcbody(fn);
+
+	curfn = fn;
+	typecheck(&fn, Etop);
+	typechecklist(r, Etop);
+	curfn = nil;
+	funccompile(fn, 0);
+}
diff --git a/src/cmd/gc/inl.c b/src/cmd/gc/inl.c
new file mode 100644
index 0000000..45e15bb
--- /dev/null
+++ b/src/cmd/gc/inl.c
@@ -0,0 +1,986 @@
+// 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.
+//
+// The inlining facility makes 2 passes: first caninl determines which
+// functions are suitable for inlining, and for those that are it
+// saves a copy of the body. Then inlcalls walks each function body to
+// expand calls to inlinable functions.
+//
+// The debug['l'] flag controls the agressiveness. Note that main() swaps level 0 and 1,
+// making 1 the default and -l disable.  -ll and more is useful to flush out bugs.
+// These additional levels (beyond -l) may be buggy and are not supported.
+//      0: disabled
+//      1: 40-nodes leaf functions, oneliners, lazy typechecking (default)
+//      2: early typechecking of all imported bodies 
+//      3: allow variadic functions
+//      4: allow non-leaf functions , (breaks runtime.Caller)
+//      5: transitive inlining
+//
+//  At some point this may get another default and become switch-offable with -N.
+//
+//  The debug['m'] flag enables diagnostic output.  a single -m is useful for verifying
+//  which calls get inlined or not, more is for debugging, and may go away at any point.
+//
+// TODO:
+//   - inline functions with ... args
+//   - handle T.meth(f()) with func f() (t T, arg, arg, )
+
+#include <u.h>
+#include <libc.h>
+#include "go.h"
+
+// Used by caninl.
+static Node*	inlcopy(Node *n);
+static NodeList* inlcopylist(NodeList *ll);
+static int	ishairy(Node *n, int *budget);
+static int	ishairylist(NodeList *ll, int *budget); 
+
+// Used by inlcalls
+static void	inlnodelist(NodeList *l);
+static void	inlnode(Node **np);
+static void	mkinlcall(Node **np, Node *fn, int isddd);
+static Node*	inlvar(Node *n);
+static Node*	retvar(Type *n, int i);
+static Node*	argvar(Type *n, int i);
+static Node*	newlabel(void);
+static Node*	inlsubst(Node *n);
+static NodeList* inlsubstlist(NodeList *l);
+
+static void	setlno(Node*, int);
+
+// Used during inlsubst[list]
+static Node *inlfn;		// function currently being inlined
+static Node *inlretlabel;	// target of the goto substituted in place of a return
+static NodeList *inlretvars;	// temp out variables
+
+// Get the function's package.  For ordinary functions it's on the ->sym, but for imported methods
+// the ->sym can be re-used in the local package, so peel it off the receiver's type.
+static Pkg*
+fnpkg(Node *fn)
+{
+	Type *rcvr;
+	
+	if(fn->type->thistuple) {
+		// method
+		rcvr = getthisx(fn->type)->type->type;
+		if(isptr[rcvr->etype])
+			rcvr = rcvr->type;
+		if(!rcvr->sym)
+			fatal("receiver with no sym: [%S] %lN  (%T)", fn->sym, fn, rcvr);
+		return rcvr->sym->pkg;
+	}
+	// non-method
+	return fn->sym->pkg;
+}
+
+// Lazy typechecking of imported bodies.  For local functions, caninl will set ->typecheck
+// because they're a copy of an already checked body. 
+void
+typecheckinl(Node *fn)
+{
+	Node *savefn;
+	Pkg *pkg;
+	int save_safemode, lno;
+
+	lno = setlineno(fn);
+
+	// typecheckinl is only for imported functions;
+	// their bodies may refer to unsafe as long as the package
+	// was marked safe during import (which was checked then).
+	// the ->inl of a local function has been typechecked before caninl copied it.
+	pkg = fnpkg(fn);
+	if (pkg == localpkg || pkg == nil)
+		return; // typecheckinl on local function
+
+	if (debug['m']>2)
+		print("typecheck import [%S] %lN { %#H }\n", fn->sym, fn, fn->inl);
+
+	save_safemode = safemode;
+	safemode = 0;
+
+	savefn = curfn;
+	curfn = fn;
+	typechecklist(fn->inl, Etop);
+	curfn = savefn;
+
+	safemode = save_safemode;
+
+	lineno = lno;
+}
+
+// Caninl determines whether fn is inlineable.
+// If so, caninl saves fn->nbody in fn->inl and substitutes it with a copy.
+// fn and ->nbody will already have been typechecked.
+void
+caninl(Node *fn)
+{
+	Node *savefn;
+	Type *t;
+	int budget;
+
+	if(fn->op != ODCLFUNC)
+		fatal("caninl %N", fn);
+	if(!fn->nname)
+		fatal("caninl no nname %+N", fn);
+
+	// If fn has no body (is defined outside of Go), cannot inline it.
+	if(fn->nbody == nil)
+		return;
+
+	if(fn->typecheck == 0)
+		fatal("caninl on non-typechecked function %N", fn);
+
+	// can't handle ... args yet
+	if(debug['l'] < 3)
+		for(t=fn->type->type->down->down->type; t; t=t->down)
+			if(t->isddd)
+				return;
+
+	budget = 40;  // allowed hairyness
+	if(ishairylist(fn->nbody, &budget))
+		return;
+
+	savefn = curfn;
+	curfn = fn;
+
+	fn->nname->inl = fn->nbody;
+	fn->nbody = inlcopylist(fn->nname->inl);
+	fn->nname->inldcl = inlcopylist(fn->nname->defn->dcl);
+
+	// hack, TODO, check for better way to link method nodes back to the thing with the ->inl
+	// this is so export can find the body of a method
+	fn->type->nname = fn->nname;
+
+	if(debug['m'] > 1)
+		print("%L: can inline %#N as: %#T { %#H }\n", fn->lineno, fn->nname, fn->type, fn->nname->inl);
+	else if(debug['m'])
+		print("%L: can inline %N\n", fn->lineno, fn->nname);
+
+	curfn = savefn;
+}
+
+// Look for anything we want to punt on.
+static int
+ishairylist(NodeList *ll, int* budget)
+{
+	for(;ll;ll=ll->next)
+		if(ishairy(ll->n, budget))
+			return 1;
+	return 0;
+}
+
+static int
+ishairy(Node *n, int *budget)
+{
+	if(!n)
+		return 0;
+
+	// Things that are too hairy, irrespective of the budget
+	switch(n->op) {
+	case OCALL:
+	case OCALLFUNC:
+	case OCALLINTER:
+	case OCALLMETH:
+	case OPANIC:
+	case ORECOVER:
+		if(debug['l'] < 4)
+			return 1;
+		break;
+
+	case OCLOSURE:
+	case OCALLPART:
+	case ORANGE:
+	case OFOR:
+	case OSELECT:
+	case OSWITCH:
+	case OPROC:
+	case ODEFER:
+	case ODCLTYPE:  // can't print yet
+	case ODCLCONST:  // can't print yet
+	case ORETJMP:
+		return 1;
+
+		break;
+	}
+
+	(*budget)--;
+
+	return  *budget < 0 ||
+		ishairy(n->left, budget) ||
+		ishairy(n->right, budget) ||
+		ishairylist(n->list, budget) ||
+		ishairylist(n->rlist, budget) ||
+		ishairylist(n->ninit, budget) ||
+		ishairy(n->ntest, budget) ||
+		ishairy(n->nincr, budget) ||
+		ishairylist(n->nbody, budget) ||
+		ishairylist(n->nelse, budget);
+}
+
+// Inlcopy and inlcopylist recursively copy the body of a function.
+// Any name-like node of non-local class is marked for re-export by adding it to
+// the exportlist.
+static NodeList*
+inlcopylist(NodeList *ll)
+{
+	NodeList *l;
+
+	l = nil;
+	for(; ll; ll=ll->next)
+		l = list(l, inlcopy(ll->n));
+	return l;
+}
+
+static Node*
+inlcopy(Node *n)
+{
+	Node *m;
+
+	if(n == N)
+		return N;
+
+	switch(n->op) {
+	case ONAME:
+	case OTYPE:
+	case OLITERAL:
+		return n;
+	}
+
+	m = nod(OXXX, N, N);
+	*m = *n;
+	m->inl = nil;
+	m->left	  = inlcopy(n->left);
+	m->right  = inlcopy(n->right);
+	m->list   = inlcopylist(n->list);
+	m->rlist  = inlcopylist(n->rlist);
+	m->ninit  = inlcopylist(n->ninit);
+	m->ntest  = inlcopy(n->ntest);
+	m->nincr  = inlcopy(n->nincr);
+	m->nbody  = inlcopylist(n->nbody);
+	m->nelse  = inlcopylist(n->nelse);
+
+	return m;
+}
+
+
+// Inlcalls/nodelist/node walks fn's statements and expressions and substitutes any
+// calls made to inlineable functions.  This is the external entry point.
+void
+inlcalls(Node *fn)
+{
+	Node *savefn;
+
+	savefn = curfn;
+	curfn = fn;
+	inlnode(&fn);
+	if(fn != curfn)
+		fatal("inlnode replaced curfn");
+	curfn = savefn;
+}
+
+// Turn an OINLCALL into a statement.
+static void
+inlconv2stmt(Node *n)
+{
+	n->op = OBLOCK;
+	// n->ninit stays
+	n->list = n->nbody;
+	n->nbody = nil;
+	n->rlist = nil;
+}
+
+// Turn an OINLCALL into a single valued expression.
+static void
+inlconv2expr(Node **np)
+{
+	Node *n, *r;
+	n = *np;
+	r = n->rlist->n;
+	addinit(&r, concat(n->ninit, n->nbody));
+	*np = r;
+}
+
+// Turn the rlist (with the return values) of the OINLCALL in
+// n into an expression list lumping the ninit and body
+// containing the inlined statements on the first list element so
+// order will be preserved Used in return, oas2func and call
+// statements.
+static NodeList*
+inlconv2list(Node *n)
+{
+	NodeList *l;
+
+	if(n->op != OINLCALL || n->rlist == nil)
+		fatal("inlconv2list %+N\n", n);
+	
+	l = n->rlist;
+	addinit(&l->n, concat(n->ninit, n->nbody));
+	return l;
+} 
+ 
+static void
+inlnodelist(NodeList *l)
+{
+	for(; l; l=l->next)
+		inlnode(&l->n);
+}
+
+// inlnode recurses over the tree to find inlineable calls, which will
+// be turned into OINLCALLs by mkinlcall.  When the recursion comes
+// back up will examine left, right, list, rlist, ninit, ntest, nincr,
+// nbody and nelse and use one of the 4 inlconv/glue functions above
+// to turn the OINLCALL into an expression, a statement, or patch it
+// in to this nodes list or rlist as appropriate.
+// NOTE it makes no sense to pass the glue functions down the
+// recursion to the level where the OINLCALL gets created because they
+// have to edit /this/ n, so you'd have to push that one down as well,
+// but then you may as well do it here.  so this is cleaner and
+// shorter and less complicated.
+static void
+inlnode(Node **np)
+{
+	Node *n;
+	NodeList *l;
+	int lno;
+
+	if(*np == nil)
+		return;
+
+	n = *np;
+	
+	switch(n->op) {
+	case ODEFER:
+	case OPROC:
+		// inhibit inlining of their argument
+		switch(n->left->op) {
+		case OCALLFUNC:
+		case OCALLMETH:
+			n->left->etype = n->op;
+		}
+
+	case OCLOSURE:
+		// TODO do them here (or earlier),
+		// so escape analysis can avoid more heapmoves.
+		return;
+	}
+
+	lno = setlineno(n);
+
+	inlnodelist(n->ninit);
+	for(l=n->ninit; l; l=l->next)
+		if(l->n->op == OINLCALL)
+			inlconv2stmt(l->n);
+
+	inlnode(&n->left);
+	if(n->left && n->left->op == OINLCALL)
+		inlconv2expr(&n->left);
+
+	inlnode(&n->right);
+	if(n->right && n->right->op == OINLCALL)
+		inlconv2expr(&n->right);
+
+	inlnodelist(n->list);
+	switch(n->op) {
+	case OBLOCK:
+		for(l=n->list; l; l=l->next)
+			if(l->n->op == OINLCALL)
+				inlconv2stmt(l->n);
+		break;
+
+	case ORETURN:
+	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) {
+			n->list = inlconv2list(n->list->n);
+			break;
+		}
+
+		// fallthrough
+	default:
+		for(l=n->list; l; l=l->next)
+			if(l->n->op == OINLCALL)
+				inlconv2expr(&l->n);
+	}
+
+	inlnodelist(n->rlist);
+	switch(n->op) {
+	case OAS2FUNC:
+		if(n->rlist->n->op == OINLCALL) {
+			n->rlist = inlconv2list(n->rlist->n);
+			n->op = OAS2;
+			n->typecheck = 0;
+			typecheck(np, Etop);
+			break;
+		}
+
+		// fallthrough
+	default:
+		for(l=n->rlist; l; l=l->next)
+			if(l->n->op == OINLCALL)
+				inlconv2expr(&l->n);
+
+	}
+
+	inlnode(&n->ntest);
+	if(n->ntest && n->ntest->op == OINLCALL)
+		inlconv2expr(&n->ntest);
+
+	inlnode(&n->nincr);
+	if(n->nincr && n->nincr->op == OINLCALL)
+		inlconv2stmt(n->nincr);
+
+	inlnodelist(n->nbody);
+	for(l=n->nbody; l; l=l->next)
+		if(l->n->op == OINLCALL)
+			inlconv2stmt(l->n);
+
+	inlnodelist(n->nelse);
+	for(l=n->nelse; l; l=l->next)
+		if(l->n->op == OINLCALL)
+			inlconv2stmt(l->n);
+
+	// with all the branches out of the way, it is now time to
+	// transmogrify this node itself unless inhibited by the
+	// switch at the top of this function.
+	switch(n->op) {
+	case OCALLFUNC:
+	case OCALLMETH:
+		if (n->etype == OPROC || n->etype == ODEFER)
+			return;
+	}
+
+	switch(n->op) {
+	case OCALLFUNC:
+		if(debug['m']>3)
+			print("%L:call to func %+N\n", n->lineno, n->left);
+		if(n->left->inl)	// normal case
+			mkinlcall(np, n->left, n->isddd);
+		else if(n->left->op == ONAME && n->left->left && n->left->left->op == OTYPE && n->left->right &&  n->left->right->op == ONAME)  // methods called as functions
+			if(n->left->sym->def)
+				mkinlcall(np, n->left->sym->def, n->isddd);
+		break;
+
+	case OCALLMETH:
+		if(debug['m']>3)
+			print("%L:call to meth %lN\n", n->lineno, n->left->right);
+		// typecheck should have resolved ODOTMETH->type, whose nname points to the actual function.
+		if(n->left->type == T) 
+			fatal("no function type for [%p] %+N\n", n->left, n->left);
+
+		if(n->left->type->nname == N) 
+			fatal("no function definition for [%p] %+T\n", n->left->type, n->left->type);
+
+		mkinlcall(np, n->left->type->nname, n->isddd);
+
+		break;
+	}
+	
+	lineno = lno;
+}
+
+static void	mkinlcall1(Node **np, Node *fn, int isddd);
+
+static void
+mkinlcall(Node **np, Node *fn, int isddd)
+{
+	int save_safemode;
+	Pkg *pkg;
+
+	save_safemode = safemode;
+
+	// imported functions may refer to unsafe as long as the
+	// package was marked safe during import (already checked).
+	pkg = fnpkg(fn);
+	if(pkg != localpkg && pkg != nil)
+		safemode = 0;
+	mkinlcall1(np, fn, isddd);
+	safemode = save_safemode;
+}
+
+static Node*
+tinlvar(Type *t)
+{
+	if(t->nname && !isblank(t->nname)) {
+		if(!t->nname->inlvar)
+			fatal("missing inlvar for %N\n", t->nname);
+		return t->nname->inlvar;
+	}
+	typecheck(&nblank, Erv | Easgn);
+	return nblank;
+}
+
+static int inlgen;
+
+// if *np is a call, and fn is a function with an inlinable body, substitute *np with an OINLCALL.
+// On return ninit has the parameter assignments, the nbody is the
+// inlined function body and list, rlist contain the input, output
+// parameters.
+static void
+mkinlcall1(Node **np, Node *fn, int isddd)
+{
+	int i;
+	int chkargcount;
+	Node *n, *call, *saveinlfn, *as, *m;
+	NodeList *dcl, *ll, *ninit, *body;
+	Type *t;
+	// For variadic fn.
+	int variadic, varargcount, multiret;
+	Node *vararg;
+	NodeList *varargs;
+	Type *varargtype, *vararrtype;
+
+	if (fn->inl == nil)
+		return;
+
+	if (fn == curfn || fn->defn == curfn)
+		return;
+
+	if(debug['l']<2)
+		typecheckinl(fn);
+
+	n = *np;
+
+	// Bingo, we have a function node, and it has an inlineable body
+	if(debug['m']>1)
+		print("%L: inlining call to %S %#T { %#H }\n", n->lineno, fn->sym, fn->type, fn->inl);
+	else if(debug['m'])
+		print("%L: inlining call to %N\n", n->lineno, fn);
+
+	if(debug['m']>2)
+		print("%L: Before inlining: %+N\n", n->lineno, n);
+
+	saveinlfn = inlfn;
+	inlfn = fn;
+
+	ninit = n->ninit;
+
+//dumplist("ninit pre", ninit);
+
+	if(fn->defn) // local function
+		dcl = fn->inldcl;
+	else // imported function
+		dcl = fn->dcl;
+
+	inlretvars = nil;
+	i = 0;
+	// Make temp names to use instead of the originals
+	for(ll = dcl; ll; ll=ll->next) {
+		if(ll->n->class == PPARAMOUT)  // return values handled below.
+			continue;
+		if(ll->n->op == ONAME) {
+			ll->n->inlvar = inlvar(ll->n);
+			// Typecheck because inlvar is not necessarily a function parameter.
+			typecheck(&ll->n->inlvar, Erv);
+			if ((ll->n->class&~PHEAP) != PAUTO)
+				ninit = list(ninit, nod(ODCL, ll->n->inlvar, N));  // otherwise gen won't emit the allocations for heapallocs
+		}
+	}
+
+	// temporaries for return values.
+	for(t = getoutargx(fn->type)->type; t; t = t->down) {
+		if(t != T && t->nname != N && !isblank(t->nname)) {
+			m = inlvar(t->nname);
+			typecheck(&m, Erv);
+			t->nname->inlvar = m;
+		} else {
+			// anonymous return values, synthesize names for use in assignment that replaces return
+			m = retvar(t, i++);
+		}
+		ninit = list(ninit, nod(ODCL, m, N));
+		inlretvars = list(inlretvars, m);
+	}
+
+	// assign receiver.
+	if(fn->type->thistuple && n->left->op == ODOTMETH) {
+		// method call with a receiver.
+		t = getthisx(fn->type)->type;
+		if(t != T && t->nname != N && !isblank(t->nname) && !t->nname->inlvar)
+			fatal("missing inlvar for %N\n", t->nname);
+		if(!n->left->left)
+			fatal("method call without receiver: %+N", n);
+		if(t == T)
+			fatal("method call unknown receiver type: %+N", n);
+		as = nod(OAS, tinlvar(t), n->left->left);
+		if(as != N) {
+			typecheck(&as, Etop);
+			ninit = list(ninit, as);
+		}
+	}
+
+	// check if inlined function is variadic.
+	variadic = 0;
+	varargtype = T;
+	varargcount = 0;
+	for(t=fn->type->type->down->down->type; t; t=t->down) {
+		if(t->isddd) {
+			variadic = 1;
+			varargtype = t->type;
+		}
+	}
+	// but if argument is dotted too forget about variadicity.
+	if(variadic && isddd)
+		variadic = 0;
+
+	// check if argument is actually a returned tuple from call.
+	multiret = 0;
+	if(n->list && !n->list->next) {
+		switch(n->list->n->op) {
+		case OCALL:
+		case OCALLFUNC:
+		case OCALLINTER:
+		case OCALLMETH:
+			if(n->list->n->left->type->outtuple > 1)
+				multiret = n->list->n->left->type->outtuple-1;
+		}
+	}
+
+	if(variadic) {
+		varargcount = count(n->list) + multiret;
+		if(n->left->op != ODOTMETH)
+			varargcount -= fn->type->thistuple;
+		varargcount -= fn->type->intuple - 1;
+	}
+
+	// assign arguments to the parameters' temp names
+	as = nod(OAS2, N, N);
+	as->rlist = n->list;
+	ll = n->list;
+
+	// TODO: if len(nlist) == 1 but multiple args, check that n->list->n is a call?
+	if(fn->type->thistuple && n->left->op != ODOTMETH) {
+		// non-method call to method
+		if(!n->list)
+			fatal("non-method call to method without first arg: %+N", n);
+		// append receiver inlvar to LHS.
+		t = getthisx(fn->type)->type;
+		if(t != T && t->nname != N && !isblank(t->nname) && !t->nname->inlvar)
+			fatal("missing inlvar for %N\n", t->nname);
+		if(t == T)
+			fatal("method call unknown receiver type: %+N", n);
+		as->list = list(as->list, tinlvar(t));
+		ll = ll->next; // track argument count.
+	}
+
+	// append ordinary arguments to LHS.
+	chkargcount = n->list && n->list->next;
+	vararg = N;    // the slice argument to a variadic call
+	varargs = nil; // the list of LHS names to put in vararg.
+	if(!chkargcount) {
+		// 0 or 1 expression on RHS.
+		for(t = getinargx(fn->type)->type; t; t=t->down) {
+			if(variadic && t->isddd) {
+				vararg = tinlvar(t);
+				for(i=0; i<varargcount && ll; i++) {
+					m = argvar(varargtype, i);
+					varargs = list(varargs, m);
+					as->list = list(as->list, m);
+				}
+				break;
+			}
+			as->list = list(as->list, tinlvar(t));
+		}
+	} else {
+		// match arguments except final variadic (unless the call is dotted itself)
+		for(t = getinargx(fn->type)->type; t;) {
+			if(!ll)
+				break;
+			if(variadic && t->isddd)
+				break;
+			as->list = list(as->list, tinlvar(t));
+			t=t->down;
+			ll=ll->next;
+		}
+		// match varargcount arguments with variadic parameters.
+		if(variadic && t && t->isddd) {
+			vararg = tinlvar(t);
+			for(i=0; i<varargcount && ll; i++) {
+				m = argvar(varargtype, i);
+				varargs = list(varargs, m);
+				as->list = list(as->list, m);
+				ll=ll->next;
+			}
+			if(i==varargcount)
+				t=t->down;
+		}
+		if(ll || t)
+			fatal("arg count mismatch: %#T  vs %,H\n",  getinargx(fn->type), n->list);
+	}
+
+	if (as->rlist) {
+		typecheck(&as, Etop);
+		ninit = list(ninit, as);
+	}
+
+	// turn the variadic args into a slice.
+	if(variadic) {
+		as = nod(OAS, vararg, N);
+		if(!varargcount) {
+			as->right = nodnil();
+			as->right->type = varargtype;
+		} else {
+			vararrtype = typ(TARRAY);
+			vararrtype->type = varargtype->type;
+			vararrtype->bound = varargcount;
+
+			as->right = nod(OCOMPLIT, N, typenod(varargtype));
+			as->right->list = varargs;
+			as->right = nod(OSLICE, as->right, nod(OKEY, N, N));
+		}
+		typecheck(&as, Etop);
+		ninit = list(ninit, as);
+	}
+
+	// zero the outparams
+	for(ll = inlretvars; ll; ll=ll->next) {
+		as = nod(OAS, ll->n, N);
+		typecheck(&as, Etop);
+		ninit = list(ninit, as);
+	}
+
+	inlretlabel = newlabel();
+	inlgen++;
+	body = inlsubstlist(fn->inl);
+
+	body = list(body, nod(OGOTO, inlretlabel, N));	// avoid 'not used' when function doesnt have return
+	body = list(body, nod(OLABEL, inlretlabel, N));
+
+	typechecklist(body, Etop);
+//dumplist("ninit post", ninit);
+
+	call = nod(OINLCALL, N, N);
+	call->ninit = ninit;
+	call->nbody = body;
+	call->rlist = inlretvars;
+	call->type = n->type;
+	call->typecheck = 1;
+
+	setlno(call, n->lineno);
+//dumplist("call body", body);
+
+	*np = call;
+
+	inlfn =	saveinlfn;
+
+	// transitive inlining
+	// TODO do this pre-expansion on fn->inl directly.  requires
+	// either supporting exporting statemetns with complex ninits
+	// or saving inl and making inlinl
+	if(debug['l'] >= 5) {
+		body = fn->inl;
+		fn->inl = nil;	// prevent infinite recursion
+		inlnodelist(call->nbody);
+		for(ll=call->nbody; ll; ll=ll->next)
+			if(ll->n->op == OINLCALL)
+				inlconv2stmt(ll->n);
+		fn->inl = body;
+	}
+
+	if(debug['m']>2)
+		print("%L: After inlining %+N\n\n", n->lineno, *np);
+
+}
+
+// Every time we expand a function we generate a new set of tmpnames,
+// PAUTO's in the calling functions, and link them off of the
+// PPARAM's, PAUTOS and PPARAMOUTs of the called function. 
+static Node*
+inlvar(Node *var)
+{
+	Node *n;
+
+	if(debug['m']>3)
+		print("inlvar %+N\n", var);
+
+	n = newname(var->sym);
+	n->type = var->type;
+	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.
+	// If inlining a function defined in another package after
+	// escape analysis is done, treat all local vars as escaping.
+	// See issue 9537.
+	if(var->esc == EscHeap || (inl_nonlocal && var->op == ONAME))
+		addrescapes(n);
+
+	curfn->dcl = list(curfn->dcl, n);
+	return n;
+}
+
+// Synthesize a variable to store the inlined function's results in.
+static Node*
+retvar(Type *t, int i)
+{
+	Node *n;
+
+	snprint(namebuf, sizeof(namebuf), "~r%d", i);
+	n = newname(lookup(namebuf));
+	n->type = t->type;
+	n->class = PAUTO;
+	n->used = 1;
+	n->curfn = curfn;   // the calling function, not the called one
+	curfn->dcl = list(curfn->dcl, n);
+	return n;
+}
+
+// Synthesize a variable to store the inlined function's arguments
+// when they come from a multiple return call.
+static Node*
+argvar(Type *t, int i)
+{
+	Node *n;
+
+	snprint(namebuf, sizeof(namebuf), "~arg%d", i);
+	n = newname(lookup(namebuf));
+	n->type = t->type;
+	n->class = PAUTO;
+	n->used = 1;
+	n->curfn = curfn;   // the calling function, not the called one
+	curfn->dcl = list(curfn->dcl, n);
+	return n;
+}
+
+static Node*
+newlabel(void)
+{
+	Node *n;
+	static int label;
+	
+	label++;
+	snprint(namebuf, sizeof(namebuf), ".inlret%.6d", label);
+	n = newname(lookup(namebuf));
+	n->etype = 1;  // flag 'safe' for escape analysis (no backjumps)
+	return n;
+}
+
+// inlsubst and inlsubstlist recursively copy the body of the saved
+// pristine ->inl body of the function while substituting references
+// to input/output parameters with ones to the tmpnames, and
+// substituting returns with assignments to the output.
+static NodeList*
+inlsubstlist(NodeList *ll)
+{
+	NodeList *l;
+
+	l = nil;
+	for(; ll; ll=ll->next)
+		l = list(l, inlsubst(ll->n));
+	return l;
+}
+
+static Node*
+inlsubst(Node *n)
+{
+	char *p;
+	Node *m, *as;
+	NodeList *ll;
+
+	if(n == N)
+		return N;
+
+	switch(n->op) {
+	case ONAME:
+		if(n->inlvar) { // These will be set during inlnode
+			if (debug['m']>2)
+				print ("substituting name %+N  ->  %+N\n", n, n->inlvar);
+			return n->inlvar;
+		}
+		if (debug['m']>2)
+			print ("not substituting name %+N\n", n);
+		return n;
+
+	case OLITERAL:
+	case OTYPE:
+		return n;
+
+	case ORETURN:
+		// Since we don't handle bodies with closures, this return is guaranteed to belong to the current inlined function.
+
+//		dump("Return before substitution", n);
+		m = nod(OGOTO, inlretlabel, N);
+		m->ninit  = inlsubstlist(n->ninit);
+
+		if(inlretvars && n->list) {
+			as = nod(OAS2, N, N);
+			// shallow copy or OINLCALL->rlist will be the same list, and later walk and typecheck may clobber that.
+			for(ll=inlretvars; ll; ll=ll->next)
+				as->list = list(as->list, ll->n);
+			as->rlist = inlsubstlist(n->list);
+			typecheck(&as, Etop);
+			m->ninit = list(m->ninit, as);
+		}
+
+		typechecklist(m->ninit, Etop);
+		typecheck(&m, Etop);
+//		dump("Return after substitution", m);
+		return m;
+	
+	case OGOTO:
+	case OLABEL:
+		m = nod(OXXX, N, N);
+		*m = *n;
+		m->ninit = nil;
+		p = smprint("%s·%d", n->left->sym->name, inlgen);	
+		m->left = newname(lookup(p));
+		free(p);
+		return m;	
+	}
+
+
+	m = nod(OXXX, N, N);
+	*m = *n;
+	m->ninit = nil;
+	
+	if(n->op == OCLOSURE)
+		fatal("cannot inline function containing closure: %+N", n);
+
+	m->left	  = inlsubst(n->left);
+	m->right  = inlsubst(n->right);
+	m->list	  = inlsubstlist(n->list);
+	m->rlist  = inlsubstlist(n->rlist);
+	m->ninit  = concat(m->ninit, inlsubstlist(n->ninit));
+	m->ntest  = inlsubst(n->ntest);
+	m->nincr  = inlsubst(n->nincr);
+	m->nbody  = inlsubstlist(n->nbody);
+	m->nelse  = inlsubstlist(n->nelse);
+
+	return m;
+}
+
+// Plaster over linenumbers
+static void
+setlnolist(NodeList *ll, int lno)
+{
+	for(;ll;ll=ll->next)
+		setlno(ll->n, lno);
+}
+
+static void
+setlno(Node *n, int lno)
+{
+	if(!n)
+		return;
+
+	// don't clobber names, unless they're freshly synthesized
+	if(n->op != ONAME || n->lineno == 0)
+		n->lineno = lno;
+	
+	setlno(n->left, lno);
+	setlno(n->right, lno);
+	setlnolist(n->list, lno);
+	setlnolist(n->rlist, lno);
+	setlnolist(n->ninit, lno);
+	setlno(n->ntest, lno);
+	setlno(n->nincr, lno);
+	setlnolist(n->nbody, lno);
+	setlnolist(n->nelse, lno);
+}
diff --git a/src/cmd/gc/lex.c b/src/cmd/gc/lex.c
new file mode 100644
index 0000000..523ba37
--- /dev/null
+++ b/src/cmd/gc/lex.c
@@ -0,0 +1,2414 @@
+// 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	"go.h"
+#include	"y.tab.h"
+#include	<ar.h>
+
+#undef	getc
+#undef	ungetc
+#define	getc	ccgetc
+#define	ungetc	ccungetc
+
+extern int yychar;
+int yyprev;
+int yylast;
+
+static void	lexinit(void);
+static void	lexinit1(void);
+static void	lexfini(void);
+static void	yytinit(void);
+static int	getc(void);
+static void	ungetc(int);
+static int32	getr(void);
+static int	escchar(int, int*, vlong*);
+static void	addidir(char*);
+static int	getlinepragma(void);
+static char *goos, *goarch, *goroot;
+
+#define	BOM	0xFEFF
+
+// Compiler experiments.
+// These are controlled by the GOEXPERIMENT environment
+// variable recorded when the compiler is built.
+static struct {
+	char *name;
+	int *val;
+} exper[] = {
+//	{"rune32", &rune32},
+	{"fieldtrack", &fieldtrack_enabled},
+	{"precisestack", &precisestack_enabled},
+	{nil, nil},
+};
+
+// Debug arguments.
+// These can be specified with the -d flag, as in "-d nil"
+// to set the debug_checknil variable. In general the list passed
+// to -d can be comma-separated.
+static struct {
+	char *name;
+	int *val;
+} debugtab[] = {
+	{"nil", &debug_checknil},
+	{nil, nil},
+};
+
+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;
+			return;
+		}
+	}
+	
+	print("unknown experiment %s\n", s);
+	exits("unknown experiment");
+}
+
+static void
+setexp(void)
+{
+	char *f[20];
+	int i, nf;
+
+	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]);
+}
+
+char*
+expstring(void)
+{
+	int i;
+	static char buf[512];
+
+	strcpy(buf, "X");
+	for(i=0; exper[i].name != nil; i++)
+		if(*exper[i].val)
+			seprint(buf+strlen(buf), buf+sizeof buf, ",%s", exper[i].name);
+	if(strlen(buf) == 1)
+		strcpy(buf, "X,none");
+	buf[1] = ':';
+	return buf;
+}
+
+// Our own isdigit, isspace, isalpha, isalnum that take care 
+// of EOF and other out of range arguments.
+static int
+yy_isdigit(int c)
+{
+	return c >= 0 && c <= 0xFF && isdigit(c);
+}
+
+static int
+yy_isspace(int c)
+{
+	return c == ' ' || c == '\t' || c == '\n' || c == '\r';
+}
+
+static int
+yy_isalpha(int c)
+{
+	return c >= 0 && c <= 0xFF && isalpha(c);
+}
+
+static int
+yy_isalnum(int c)
+{
+	return c >= 0 && c <= 0xFF && isalnum(c);
+}
+
+// Disallow use of isdigit etc.
+#undef isdigit
+#undef isspace
+#undef isalpha
+#undef isalnum
+#define isdigit use_yy_isdigit_instead_of_isdigit
+#define isspace use_yy_isspace_instead_of_isspace
+#define isalpha use_yy_isalpha_instead_of_isalpha
+#define isalnum use_yy_isalnum_instead_of_isalnum
+
+#define	DBG	if(!debug['x']){}else print
+/*c2go void DBG(char*, ...); */
+
+enum
+{
+	EOF		= -1,
+};
+
+void
+usage(void)
+{
+	print("usage: %cg [options] file.go...\n", thechar);
+	flagprint(1);
+	exits("usage");
+}
+
+void
+fault(int s)
+{
+	USED(s);
+
+	// If we've already complained about things
+	// in the program, don't bother complaining
+	// about the seg fault too; let the user clean up
+	// the code and try again.
+	if(nsavederrors + nerrors > 0)
+		errorexit();
+	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)
+{
+	char *p;
+
+	p = expstring();
+	if(strcmp(p, "X:none") == 0)
+		p = "";
+	print("%cg version %s%s%s\n", thechar, getgoversion(), *p ? " " : "", p);
+	exits(0);
+}
+
+int
+main(int argc, char *argv[])
+{
+	int i;
+	NodeList *l;
+	char *p;
+
+#ifdef	SIGBUS	
+	signal(SIGBUS, fault);
+	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 = "\"\"";
+	
+	// pseudo-package, for scoping
+	builtinpkg = mkpkg(strlit("go.builtin"));
+
+	// pseudo-package, accessed by import "unsafe"
+	unsafepkg = mkpkg(strlit("unsafe"));
+	unsafepkg->name = "unsafe";
+
+	// real package, referred to by generated runtime calls
+	runtimepkg = mkpkg(strlit("runtime"));
+	runtimepkg->name = "runtime";
+
+	// pseudo-packages used in symbol tables
+	gostringpkg = mkpkg(strlit("go.string"));
+	gostringpkg->name = "go.string";
+	gostringpkg->prefix = "go.string";	// not go%2estring
+
+	itabpkg = mkpkg(strlit("go.itab"));
+	itabpkg->name = "go.itab";
+	itabpkg->prefix = "go.itab";	// not go%2eitab
+
+	weaktypepkg = mkpkg(strlit("go.weak.type"));
+	weaktypepkg->name = "go.weak.type";
+	weaktypepkg->prefix = "go.weak.type";  // not go%2eweak%2etype
+	
+	typelinkpkg = mkpkg(strlit("go.typelink"));
+	typelinkpkg->name = "go.typelink";
+	typelinkpkg->prefix = "go.typelink"; // not go%2etypelink
+
+	trackpkg = mkpkg(strlit("go.track"));
+	trackpkg->name = "go.track";
+	trackpkg->prefix = "go.track";  // not go%2etrack
+
+	typepkg = mkpkg(strlit("type"));
+	typepkg->name = "type";
+
+	goroot = getgoroot();
+	goos = getgoos();
+
+	nacl = strcmp(goos, "nacl") == 0;
+	if(nacl)
+		flag_largemodel = 1;
+
+	setexp();
+
+	outfile = nil;
+	flagcount("+", "compiling runtime", &compiling_runtime);
+	flagcount("%", "debug non-static initializers", &debug['%']);
+	flagcount("A", "for bootstrapping, allow 'any' type", &debug['A']);
+	flagcount("B", "disable bounds checking", &debug['B']);
+	flagstr("D", "path: set relative path for local imports", &localimport);
+	flagcount("E", "debug symbol export", &debug['E']);
+	flagfn1("I", "dir: add dir to import search path", addidir);
+	flagcount("K", "debug missing line numbers", &debug['K']);
+	flagcount("L", "use full (long) path in error messages", &debug['L']);
+	flagcount("M", "debug move generation", &debug['M']);
+	flagcount("N", "disable optimizations", &debug['N']);
+	flagcount("P", "debug peephole optimizer", &debug['P']);
+	flagcount("R", "debug register optimizer", &debug['R']);
+	flagcount("S", "print assembly listing", &debug['S']);
+	flagfn0("V", "print compiler version", doversion);
+	flagcount("W", "debug parse tree after type checking", &debug['W']);
+	flagcount("complete", "compiling complete package (no C or assembly)", &pure_go);
+	flagstr("d", "list: print debug information about items in list", &debugstr);
+	flagcount("e", "no limit on number of errors reported", &debug['e']);
+	flagcount("f", "debug stack frames", &debug['f']);
+	flagcount("g", "debug code generation", &debug['g']);
+	flagcount("h", "halt on error", &debug['h']);
+	flagcount("i", "debug line number stack", &debug['i']);
+	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']);
+	use_writebarrier = 1;
+	flagcount("wb", "enable write barrier", &use_writebarrier);
+	flagcount("x", "debug lexer", &debug['x']);
+	flagcount("y", "debug declarations in canned imports (with -d)", &debug['y']);
+	if(thechar == '6')
+		flagcount("largemodel", "generate code that assumes a large memory model", &flag_largemodel);
+
+	flagparse(&argc, &argv, usage);
+	ctxt->debugasm = debug['S'];
+	ctxt->debugvlog = debug['v'];
+
+	if(argc < 1)
+		usage();
+
+	if(flag_race) {
+		racepkg = mkpkg(strlit("runtime/race"));
+		racepkg->name = "race";
+	}
+	
+	// parse -d argument
+	if(debugstr) {
+		char *f[100];
+		int i, j, nf;
+		
+		nf = getfields(debugstr, f, nelem(f), 1, ",");
+		for(i=0; i<nf; i++) {
+			for(j=0; debugtab[j].name != nil; j++) {
+				if(strcmp(debugtab[j].name, f[i]) == 0) {
+					*debugtab[j].val = 1;
+					break;
+				}
+			}
+			if(debugtab[j].name == nil)
+				sysfatal("unknown debug information -d '%s'\n", f[i]);
+		}
+	}
+
+	// enable inlining.  for now:
+	//	default: inlining on.  (debug['l'] == 1)
+	//	-l: inlining off  (debug['l'] == 0)
+	//	-ll, -lll: inlining on again, with extra debugging (debug['l'] > 1)
+	if(debug['l'] <= 1)
+		debug['l'] = 1 - debug['l'];
+
+	if(thechar == '8') {
+		p = getgo386();
+		if(strcmp(p, "387") == 0)
+			use_sse = 0;
+		else if(strcmp(p, "sse2") == 0)
+			use_sse = 1;
+		else
+			sysfatal("unsupported setting GO386=%s", p);
+	}
+
+	fmtinstallgo();
+	betypeinit();
+	if(widthptr == 0)
+		fatal("betypeinit failed");
+
+	lexinit();
+	typeinit();
+	lexinit1();
+	yytinit();
+
+	blockgen = 1;
+	dclcontext = PEXTERN;
+	nerrors = 0;
+	lexlineno = 1;
+
+	for(i=0; i<argc; i++) {
+		infile = argv[i];
+		linehist(infile, 0, 0);
+
+		curio.infile = infile;
+		curio.bin = Bopen(infile, OREAD);
+		if(curio.bin == nil) {
+			print("open %s: %r\n", infile);
+			errorexit();
+		}
+		curio.peekc = 0;
+		curio.peekc1 = 0;
+		curio.nlsemi = 0;
+		curio.eofnl = 0;
+		curio.last = 0;
+
+		// Skip initial BOM if present.
+		if(Bgetrune(curio.bin) != BOM)
+			Bungetrune(curio.bin);
+
+		block = 1;
+		iota = -1000000;
+
+		yyparse();
+		if(nsyntaxerrors != 0)
+			errorexit();
+
+		linehist(nil, 0, 0);
+		if(curio.bin != nil)
+			Bterm(curio.bin);
+	}
+	testdclstack();
+	mkpackage(localpkg->name);	// final import not used checks
+	lexfini();
+
+	typecheckok = 1;
+	if(debug['f'])
+		frame(1);
+
+	// Process top-level declarations in phases.
+
+	// Phase 1: const, type, and names and types of funcs.
+	//   This will gather all the information about types
+	//   and methods but doesn't depend on any of it.
+	defercheckwidth();
+	for(l=xtop; l; l=l->next)
+		if(l->n->op != ODCL && l->n->op != OAS)
+			typecheck(&l->n, Etop);
+
+	// Phase 2: Variable assignments.
+	//   To check interface assignments, depends on phase 1.
+	for(l=xtop; l; l=l->next)
+		if(l->n->op == ODCL || l->n->op == OAS)
+			typecheck(&l->n, Etop);
+	resumecheckwidth();
+
+	// Phase 3: Type check function bodies.
+	for(l=xtop; l; l=l->next) {
+		if(l->n->op == ODCLFUNC || l->n->op == OCLOSURE) {
+			curfn = l->n;
+			saveerrors();
+			typechecklist(l->n->nbody, Etop);
+			checkreturn(l->n);
+			if(nerrors != 0)
+				l->n->nbody = nil;  // type errors; do not compile
+		}
+	}
+
+	curfn = nil;
+	
+	if(nsavederrors+nerrors)
+		errorexit();
+
+	// Phase 4: Inlining
+	if(debug['l'] > 1) {
+		// Typecheck imported function bodies if debug['l'] > 1,
+		// otherwise lazily when used or re-exported.
+		for(l=importlist; l; l=l->next)
+			if (l->n->inl) {
+				saveerrors();
+				typecheckinl(l->n);
+			}
+		
+		if(nsavederrors+nerrors)
+			errorexit();
+	}
+
+	if(debug['l']) {
+		// Find functions that can be inlined and clone them before walk expands them.
+		for(l=xtop; l; l=l->next)
+			if(l->n->op == ODCLFUNC)
+				caninl(l->n);
+		
+		// Expand inlineable calls in all functions
+		for(l=xtop; l; l=l->next)
+			if(l->n->op == ODCLFUNC)
+				inlcalls(l->n);
+	}
+
+	// Phase 5: Escape analysis.
+	// Required for moving heap allocations onto stack,
+	// which in turn is required by the closure implementation,
+	// which stores the addresses of stack variables into the closure.
+	// If the closure does not escape, it needs to be on the stack
+	// or else the stack copier will not update it.
+	escapes(xtop);
+	
+	// Escape analysis moved escaped values off stack.
+	// Move large values off stack too.
+	movelarge(xtop);
+
+	// Phase 6: Compile top level functions.
+	for(l=xtop; l; l=l->next)
+		if(l->n->op == ODCLFUNC)
+			funccompile(l->n, 0);
+
+	if(nsavederrors+nerrors == 0)
+		fninit(xtop);
+
+	// Phase 7: Check external declarations.
+	for(l=externdcl; l; l=l->next)
+		if(l->n->op == ONAME)
+			typecheck(&l->n, Erv);
+
+	if(nerrors+nsavederrors)
+		errorexit();
+
+	dumpobj();
+
+	if(nerrors+nsavederrors)
+		errorexit();
+
+	flusherrors();
+	exits(0);
+	return 0;
+}
+
+void
+saveerrors(void)
+{
+	nsavederrors += nerrors;
+	nerrors = 0;
+}
+
+static int
+arsize(Biobuf *b, char *name)
+{
+	struct ar_hdr a;
+
+	if(Bread(b, a.name, sizeof(a.name)) != sizeof(a.name) ||
+	   Bread(b, a.date, sizeof(a.date)) != sizeof(a.date) ||
+	   Bread(b, a.uid, sizeof(a.uid)) != sizeof(a.uid) ||
+	   Bread(b, a.gid, sizeof(a.gid)) != sizeof(a.gid) ||
+	   Bread(b, a.mode, sizeof(a.mode)) != sizeof(a.mode) ||
+	   Bread(b, a.size, sizeof(a.size)) != sizeof(a.size) ||
+	   Bread(b, a.fmag, sizeof(a.fmag)) != sizeof(a.fmag))
+		return -1;
+
+	if(strncmp(a.name, name, strlen(name)) != 0)
+		return -1;
+
+	return atoi(a.size);
+}
+
+static int
+skiptopkgdef(Biobuf *b)
+{
+	char *p;
+	int sz;
+
+	/* archive header */
+	if((p = Brdline(b, '\n')) == nil)
+		return 0;
+	if(Blinelen(b) != 8)
+		return 0;
+	if(memcmp(p, "!<arch>\n", 8) != 0)
+		return 0;
+	/* symbol table may be first; skip it */
+	sz = arsize(b, "__.GOSYMDEF");
+	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;
+	return 1;
+}
+
+static void
+addidir(char* dir)
+{
+	Idir** pp;
+
+	if(dir == nil)
+		return;
+
+	for(pp = &idirs; *pp != nil; pp = &(*pp)->link)
+		;
+	*pp = mal(sizeof(Idir));
+	(*pp)->link = nil;
+	(*pp)->dir = dir;
+}
+
+// is this path a local name?  begins with ./ or ../ or /
+static int
+islocalname(Strlit *name)
+{
+	if(name->len >= 1 && name->s[0] == '/')
+		return 1;
+	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)
+		return 1;
+	if(name->len == 1 && strncmp(name->s, ".", 1) == 0)
+		return 1;
+	if(name->len >= 3 && strncmp(name->s, "../", 3) == 0)
+		return 1;
+	if(name->len == 2 && strncmp(name->s, "..", 2) == 0)
+		return 1;
+	return 0;
+}
+
+static int
+findpkg(Strlit *name)
+{
+	Idir *p;
+	char *q, *suffix, *suffixsep;
+
+	if(islocalname(name)) {
+		if(safemode || nolocalimports)
+			return 0;
+		// try .a before .6.  important for building libraries:
+		// if there is an array.6 in the array.a library,
+		// want to find all of array.a, not just array.6.
+		snprint(namebuf, sizeof(namebuf), "%Z.a", name);
+		if(access(namebuf, 0) >= 0)
+			return 1;
+		snprint(namebuf, sizeof(namebuf), "%Z.%c", name, thechar);
+		if(access(namebuf, 0) >= 0)
+			return 1;
+		return 0;
+	}
+
+	// local imports should be canonicalized already.
+	// don't want to see "encoding/../encoding/base64"
+	// as different from "encoding/base64".
+	q = mal(name->len+1);
+	memmove(q, name->s, name->len);
+	q[name->len] = '\0';
+	cleanname(q);
+	if(strlen(q) != name->len || memcmp(q, name->s, name->len) != 0) {
+		yyerror("non-canonical import path %Z (should be %s)", name, q);
+		return 0;
+	}
+
+	for(p = idirs; p != nil; p = p->link) {
+		snprint(namebuf, sizeof(namebuf), "%s/%Z.a", p->dir, name);
+		if(access(namebuf, 0) >= 0)
+			return 1;
+		snprint(namebuf, sizeof(namebuf), "%s/%Z.%c", p->dir, name, thechar);
+		if(access(namebuf, 0) >= 0)
+			return 1;
+	}
+	if(goroot != nil) {
+		suffix = "";
+		suffixsep = "";
+		if(flag_installsuffix != nil) {
+			suffixsep = "_";
+			suffix = flag_installsuffix;
+		} else if(flag_race) {
+			suffixsep = "_";
+			suffix = "race";
+		}
+		snprint(namebuf, sizeof(namebuf), "%s/pkg/%s_%s%s%s/%Z.a", goroot, goos, goarch, suffixsep, suffix, name);
+		if(access(namebuf, 0) >= 0)
+			return 1;
+		snprint(namebuf, sizeof(namebuf), "%s/pkg/%s_%s%s%s/%Z.%c", goroot, goos, goarch, suffixsep, suffix, name, thechar);
+		if(access(namebuf, 0) >= 0)
+			return 1;
+	}
+	return 0;
+}
+
+static void
+fakeimport(void)
+{
+	importpkg = mkpkg(strlit("fake"));
+	cannedimports("fake.6", "$$\n");
+}
+
+void
+importfile(Val *f, int line)
+{
+	Biobuf *imp;
+	char *file, *p, *q, *tag;
+	int32 c;
+	int len;
+	Strlit *path;
+	char *cleanbuf, *prefix;
+
+	USED(line);
+
+	if(f->ctype != CTSTR) {
+		yyerror("import statement not a string");
+		fakeimport();
+		return;
+	}
+
+	if(f->u.sval->len == 0) {
+		yyerror("import path is empty");
+		fakeimport();
+		return;
+	}
+
+	if(isbadimport(f->u.sval)) {
+		fakeimport();
+		return;
+	}
+
+	// The package name main is no longer reserved,
+	// but we reserve the import path "main" to identify
+	// the main package, just as we reserve the import 
+	// path "math" to identify the standard math package.
+	if(strcmp(f->u.sval->s, "main") == 0) {
+		yyerror("cannot import \"main\"");
+		errorexit();
+	}
+
+	if(myimportpath != nil && strcmp(f->u.sval->s, myimportpath) == 0) {
+		yyerror("import \"%Z\" while compiling that package (import cycle)", f->u.sval);
+		errorexit();
+	}
+
+	if(strcmp(f->u.sval->s, "unsafe") == 0) {
+		if(safemode) {
+			yyerror("cannot import package unsafe");
+			errorexit();
+		}
+		importpkg = mkpkg(f->u.sval);
+		cannedimports("unsafe.6", unsafeimport);
+		return;
+	}
+	
+	path = f->u.sval;
+	if(islocalname(path)) {
+		if(path->s[0] == '/') {
+			yyerror("import path cannot be absolute path");
+			fakeimport();
+			return;
+		}
+		prefix = ctxt->pathname;
+		if(localimport != nil)
+			prefix = localimport;
+		cleanbuf = mal(strlen(prefix) + strlen(path->s) + 2);
+		strcpy(cleanbuf, prefix);
+		strcat(cleanbuf, "/");
+		strcat(cleanbuf, path->s);
+		cleanname(cleanbuf);
+		path = strlit(cleanbuf);
+		
+		if(isbadimport(path)) {
+			fakeimport();
+			return;
+		}
+	}
+
+	if(!findpkg(path)) {
+		yyerror("can't find import: \"%Z\"", f->u.sval);
+		errorexit();
+	}
+	importpkg = mkpkg(path);
+
+	// If we already saw that package, feed a dummy statement
+	// to the lexer to avoid parsing export data twice.
+	if(importpkg->imported) {
+		file = strdup(namebuf);
+		tag = "";
+		if(importpkg->safe) {
+			tag = "safe";
+		}
+		p = smprint("package %s %s\n$$\n", importpkg->name, tag);
+		cannedimports(file, p);
+		return;
+	}
+	importpkg->imported = 1;
+
+	imp = Bopen(namebuf, OREAD);
+	if(imp == nil) {
+		yyerror("can't open import: \"%Z\": %r", f->u.sval);
+		errorexit();
+	}
+	file = strdup(namebuf);
+
+	len = strlen(namebuf);
+	if(len > 2 && namebuf[len-2] == '.' && namebuf[len-1] == 'a') {
+		if(!skiptopkgdef(imp)) {
+			yyerror("import %s: not a package file", file);
+			errorexit();
+		}
+	}
+	
+	// check object header
+	p = Brdstr(imp, '\n', 1);
+	if(strcmp(p, "empty archive") != 0) {
+		if(strncmp(p, "go object ", 10) != 0) {
+			yyerror("import %s: not a go object file", file);
+			errorexit();
+		}
+		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();
+		}
+		free(q);
+	}
+
+	// assume files move (get installed)
+	// so don't record the full path.
+	linehist(file + len - path->len - 2, -1, 1);	// acts as #pragma lib
+
+	/*
+	 * position the input right
+	 * after $$ and return
+	 */
+	pushedio = curio;
+	curio.bin = imp;
+	curio.peekc = 0;
+	curio.peekc1 = 0;
+	curio.infile = file;
+	curio.nlsemi = 0;
+	typecheckok = 1;
+
+	for(;;) {
+		c = getc();
+		if(c == EOF)
+			break;
+		if(c != '$')
+			continue;
+		c = getc();
+		if(c == EOF)
+			break;
+		if(c != '$')
+			continue;
+		return;
+	}
+	yyerror("no import in \"%Z\"", f->u.sval);
+	unimportfile();
+}
+
+void
+unimportfile(void)
+{
+	if(curio.bin != nil) {
+		Bterm(curio.bin);
+		curio.bin = nil;
+	} else
+		lexlineno--;	// re correct sys.6 line number
+
+	curio = pushedio;
+	pushedio.bin = nil;
+	incannedimport = 0;
+	typecheckok = 0;
+}
+
+void
+cannedimports(char *file, char *cp)
+{
+	lexlineno++;		// if sys.6 is included on line 1,
+
+	pushedio = curio;
+	curio.bin = nil;
+	curio.peekc = 0;
+	curio.peekc1 = 0;
+	curio.infile = file;
+	curio.cp = cp;
+	curio.nlsemi = 0;
+	curio.importsafe = 0;
+
+	typecheckok = 1;
+	incannedimport = 1;
+}
+
+static int
+isfrog(int c)
+{
+	// complain about possibly invisible control characters
+	if(c < ' ') {
+		return !yy_isspace(c);	// exclude good white space
+	}
+	if(0x7f <= c && c <= 0xa0)	// DEL, unicode block including unbreakable space.
+		return 1;
+	return 0;
+}
+
+typedef struct Loophack Loophack;
+struct Loophack {
+	int v;
+	Loophack *next;
+};
+
+static int32
+_yylex(void)
+{
+	int c, c1, clen, escflag, ncp;
+	vlong v;
+	char *cp, *ep;
+	Rune rune;
+	Sym *s;
+	static Loophack *lstk;
+	Loophack *h;
+
+	prevlineno = lineno;
+
+l0:
+	c = getc();
+	if(yy_isspace(c)) {
+		if(c == '\n' && curio.nlsemi) {
+			ungetc(c);
+			DBG("lex: implicit semi\n");
+			return ';';
+		}
+		goto l0;
+	}
+
+	lineno = lexlineno;	/* start of token */
+
+	if(c >= Runeself) {
+		/* all multibyte runes are alpha */
+		cp = lexbuf;
+		ep = lexbuf+sizeof lexbuf;
+		goto talph;
+	}
+
+	if(yy_isalpha(c)) {
+		cp = lexbuf;
+		ep = lexbuf+sizeof lexbuf;
+		goto talph;
+	}
+
+	if(yy_isdigit(c))
+		goto tnum;
+
+	switch(c) {
+	case EOF:
+		lineno = prevlineno;
+		ungetc(EOF);
+		return -1;
+
+	case '_':
+		cp = lexbuf;
+		ep = lexbuf+sizeof lexbuf;
+		goto talph;
+
+	case '.':
+		c1 = getc();
+		if(yy_isdigit(c1)) {
+			cp = lexbuf;
+			ep = lexbuf+sizeof lexbuf;
+			*cp++ = c;
+			c = c1;
+			goto casedot;
+		}
+		if(c1 == '.') {
+			c1 = getc();
+			if(c1 == '.') {
+				c = LDDD;
+				goto lx;
+			}
+			ungetc(c1);
+			c1 = '.';
+		}
+		break;
+
+	case '"':
+		/* "..." */
+		strcpy(lexbuf, "\"<string>\"");
+		cp = mal(8);
+		clen = sizeof(int32);
+		ncp = 8;
+
+		for(;;) {
+			if(clen+UTFmax > ncp) {
+				cp = remal(cp, ncp, ncp);
+				ncp += ncp;
+			}
+			if(escchar('"', &escflag, &v))
+				break;
+			if(v < Runeself || escflag) {
+				cp[clen++] = v;
+			} else {
+				rune = v;
+				c = runelen(rune);
+				runetochar(cp+clen, &rune);
+				clen += c;
+			}
+		}
+		goto strlit;
+	
+	case '`':
+		/* `...` */
+		strcpy(lexbuf, "`<string>`");
+		cp = mal(8);
+		clen = sizeof(int32);
+		ncp = 8;
+
+		for(;;) {
+			if(clen+UTFmax > ncp) {
+				cp = remal(cp, ncp, ncp);
+				ncp += ncp;
+			}
+			c = getr();
+			if(c == '\r')
+				continue;
+			if(c == EOF) {
+				yyerror("eof in string");
+				break;
+			}
+			if(c == '`')
+				break;
+			rune = c;
+			clen += runetochar(cp+clen, &rune);
+		}
+
+	strlit:
+		*(int32*)cp = clen-sizeof(int32);	// length
+		do {
+			cp[clen++] = 0;
+		} while(clen & MAXALIGN);
+		yylval.val.u.sval = (Strlit*)cp;
+		yylval.val.ctype = CTSTR;
+		DBG("lex: string literal\n");
+		strcpy(litbuf, "string literal");
+		return LLITERAL;
+
+	case '\'':
+		/* '.' */
+		if(escchar('\'', &escflag, &v)) {
+			yyerror("empty character literal or unescaped ' in character literal");
+			v = '\'';
+		}
+		if(!escchar('\'', &escflag, &v)) {
+			yyerror("missing '");
+			ungetc(v);
+		}
+		yylval.val.u.xval = mal(sizeof(*yylval.val.u.xval));
+		mpmovecfix(yylval.val.u.xval, v);
+		yylval.val.ctype = CTRUNE;
+		DBG("lex: codepoint literal\n");
+		strcpy(litbuf, "string literal");
+		return LLITERAL;
+
+	case '/':
+		c1 = getc();
+		if(c1 == '*') {
+			int nl;
+			
+			nl = 0;
+			for(;;) {
+				c = getr();
+				if(c == '\n')
+					nl = 1;
+				while(c == '*') {
+					c = getr();
+					if(c == '/') {
+						if(nl)
+							ungetc('\n');
+						goto l0;
+					}
+					if(c == '\n')
+						nl = 1;
+				}
+				if(c == EOF) {
+					yyerror("eof in comment");
+					errorexit();
+				}
+			}
+		}
+		if(c1 == '/') {
+			c = getlinepragma();
+			for(;;) {
+				if(c == '\n' || c == EOF) {
+					ungetc(c);
+					goto l0;
+				}
+				c = getr();
+			}
+		}
+		if(c1 == '=') {
+			c = ODIV;
+			goto asop;
+		}
+		break;
+
+	case ':':
+		c1 = getc();
+		if(c1 == '=') {
+			c = LCOLAS;
+			yylval.i = lexlineno;
+			goto lx;
+		}
+		break;
+
+	case '*':
+		c1 = getc();
+		if(c1 == '=') {
+			c = OMUL;
+			goto asop;
+		}
+		break;
+
+	case '%':
+		c1 = getc();
+		if(c1 == '=') {
+			c = OMOD;
+			goto asop;
+		}
+		break;
+
+	case '+':
+		c1 = getc();
+		if(c1 == '+') {
+			c = LINC;
+			goto lx;
+		}
+		if(c1 == '=') {
+			c = OADD;
+			goto asop;
+		}
+		break;
+
+	case '-':
+		c1 = getc();
+		if(c1 == '-') {
+			c = LDEC;
+			goto lx;
+		}
+		if(c1 == '=') {
+			c = OSUB;
+			goto asop;
+		}
+		break;
+
+	case '>':
+		c1 = getc();
+		if(c1 == '>') {
+			c = LRSH;
+			c1 = getc();
+			if(c1 == '=') {
+				c = ORSH;
+				goto asop;
+			}
+			break;
+		}
+		if(c1 == '=') {
+			c = LGE;
+			goto lx;
+		}
+		c = LGT;
+		break;
+
+	case '<':
+		c1 = getc();
+		if(c1 == '<') {
+			c = LLSH;
+			c1 = getc();
+			if(c1 == '=') {
+				c = OLSH;
+				goto asop;
+			}
+			break;
+		}
+		if(c1 == '=') {
+			c = LLE;
+			goto lx;
+		}
+		if(c1 == '-') {
+			c = LCOMM;
+			goto lx;
+		}
+		c = LLT;
+		break;
+
+	case '=':
+		c1 = getc();
+		if(c1 == '=') {
+			c = LEQ;
+			goto lx;
+		}
+		break;
+
+	case '!':
+		c1 = getc();
+		if(c1 == '=') {
+			c = LNE;
+			goto lx;
+		}
+		break;
+
+	case '&':
+		c1 = getc();
+		if(c1 == '&') {
+			c = LANDAND;
+			goto lx;
+		}
+		if(c1 == '^') {
+			c = LANDNOT;
+			c1 = getc();
+			if(c1 == '=') {
+				c = OANDNOT;
+				goto asop;
+			}
+			break;
+		}
+		if(c1 == '=') {
+			c = OAND;
+			goto asop;
+		}
+		break;
+
+	case '|':
+		c1 = getc();
+		if(c1 == '|') {
+			c = LOROR;
+			goto lx;
+		}
+		if(c1 == '=') {
+			c = OOR;
+			goto asop;
+		}
+		break;
+
+	case '^':
+		c1 = getc();
+		if(c1 == '=') {
+			c = OXOR;
+			goto asop;
+		}
+		break;
+
+	/*
+	 * clumsy dance:
+	 * to implement rule that disallows
+	 *	if T{1}[0] { ... }
+	 * but allows
+	 * 	if (T{1}[0]) { ... }
+	 * the block bodies for if/for/switch/select
+	 * begin with an LBODY token, not '{'.
+	 *
+	 * when we see the keyword, the next
+	 * non-parenthesized '{' becomes an LBODY.
+	 * loophack is normally 0.
+	 * a keyword makes it go up to 1.
+	 * parens push loophack onto a stack and go back to 0.
+	 * a '{' with loophack == 1 becomes LBODY and disables loophack.
+	 *
+	 * i said it was clumsy.
+	 */
+	case '(':
+	case '[':
+		if(loophack || lstk != nil) {
+			h = malloc(sizeof *h);
+			if(h == nil) {
+				flusherrors();
+				yyerror("out of memory");
+				errorexit();
+			}
+			h->v = loophack;
+			h->next = lstk;
+			lstk = h;
+			loophack = 0;
+		}
+		goto lx;
+	case ')':
+	case ']':
+		if(lstk != nil) {
+			h = lstk;
+			loophack = h->v;
+			lstk = h->next;
+			free(h);
+		}
+		goto lx;
+	case '{':
+		if(loophack == 1) {
+			DBG("%L lex: LBODY\n", lexlineno);
+			loophack = 0;
+			return LBODY;
+		}
+		goto lx;
+
+	default:
+		goto lx;
+	}
+	ungetc(c1);
+
+lx:
+	if(c > 0xff)
+		DBG("%L lex: TOKEN %s\n", lexlineno, lexname(c));
+	else
+		DBG("%L lex: TOKEN '%c'\n", lexlineno, c);
+	if(isfrog(c)) {
+		yyerror("illegal character 0x%ux", c);
+		goto l0;
+	}
+	if(importpkg == nil && (c == '#' || c == '$' || c == '?' || c == '@' || c == '\\')) {
+		yyerror("%s: unexpected %c", "syntax error", c);
+		goto l0;
+	}
+	return c;
+
+asop:
+	yylval.i = c;	// rathole to hold which asop
+	DBG("lex: TOKEN ASOP %c\n", c);
+	return LASOP;
+
+talph:
+	/*
+	 * cp is set to lexbuf and some
+	 * prefix has been stored
+	 */
+	for(;;) {
+		if(cp+10 >= ep) {
+			yyerror("identifier too long");
+			errorexit();
+		}
+		if(c >= Runeself) {
+			ungetc(c);
+			rune = getr();
+			// 0xb7 · is used for internal names
+			if(!isalpharune(rune) && !isdigitrune(rune) && (importpkg == nil || rune != 0xb7))
+				yyerror("invalid identifier character U+%04x", rune);
+			cp += runetochar(cp, &rune);
+		} else if(!yy_isalnum(c) && c != '_')
+			break;
+		else
+			*cp++ = c;
+		c = getc();
+	}
+	*cp = 0;
+	ungetc(c);
+
+	s = lookup(lexbuf);
+	switch(s->lexical) {
+	case LIGNORE:
+		goto l0;
+
+	case LFOR:
+	case LIF:
+	case LSWITCH:
+	case LSELECT:
+		loophack = 1;	// see comment about loophack above
+		break;
+	}
+
+	DBG("lex: %S %s\n", s, lexname(s->lexical));
+	yylval.sym = s;
+	return s->lexical;
+
+tnum:
+	cp = lexbuf;
+	ep = lexbuf+sizeof lexbuf;
+	if(c != '0') {
+		for(;;) {
+			if(cp+10 >= ep) {
+				yyerror("identifier too long");
+				errorexit();
+			}
+			*cp++ = c;
+			c = getc();
+			if(yy_isdigit(c))
+				continue;
+			goto dc;
+		}
+	}
+	*cp++ = c;
+	c = getc();
+	if(c == 'x' || c == 'X') {
+		for(;;) {
+			if(cp+10 >= ep) {
+				yyerror("identifier too long");
+				errorexit();
+			}
+			*cp++ = c;
+			c = getc();
+			if(yy_isdigit(c))
+				continue;
+			if(c >= 'a' && c <= 'f')
+				continue;
+			if(c >= 'A' && c <= 'F')
+				continue;
+			if(cp == lexbuf+2)
+				yyerror("malformed hex constant");
+			if(c == 'p')
+				goto caseep;
+			goto ncu;
+		}
+	}
+
+	if(c == 'p')	// 0p begins floating point zero
+		goto caseep;
+
+	c1 = 0;
+	for(;;) {
+		if(cp+10 >= ep) {
+			yyerror("identifier too long");
+			errorexit();
+		}
+		if(!yy_isdigit(c))
+			break;
+		if(c < '0' || c > '7')
+			c1 = 1;		// not octal
+		*cp++ = c;
+		c = getc();
+	}
+	if(c == '.')
+		goto casedot;
+	if(c == 'e' || c == 'E')
+		goto caseep;
+	if(c == 'i')
+		goto casei;
+	if(c1)
+		yyerror("malformed octal constant");
+	goto ncu;
+
+dc:
+	if(c == '.')
+		goto casedot;
+	if(c == 'e' || c == 'E' || c == 'p' || c == 'P')
+		goto caseep;
+	if(c == 'i')
+		goto casei;
+
+ncu:
+	*cp = 0;
+	ungetc(c);
+
+	yylval.val.u.xval = mal(sizeof(*yylval.val.u.xval));
+	mpatofix(yylval.val.u.xval, lexbuf);
+	if(yylval.val.u.xval->ovf) {
+		yyerror("overflow in constant");
+		mpmovecfix(yylval.val.u.xval, 0);
+	}
+	yylval.val.ctype = CTINT;
+	DBG("lex: integer literal\n");
+	strcpy(litbuf, "literal ");
+	strcat(litbuf, lexbuf);
+	return LLITERAL;
+
+casedot:
+	for(;;) {
+		if(cp+10 >= ep) {
+			yyerror("identifier too long");
+			errorexit();
+		}
+		*cp++ = c;
+		c = getc();
+		if(!yy_isdigit(c))
+			break;
+	}
+	if(c == 'i')
+		goto casei;
+	if(c != 'e' && c != 'E')
+		goto caseout;
+
+caseep:
+	*cp++ = c;
+	c = getc();
+	if(c == '+' || c == '-') {
+		*cp++ = c;
+		c = getc();
+	}
+	if(!yy_isdigit(c))
+		yyerror("malformed fp constant exponent");
+	while(yy_isdigit(c)) {
+		if(cp+10 >= ep) {
+			yyerror("identifier too long");
+			errorexit();
+		}
+		*cp++ = c;
+		c = getc();
+	}
+	if(c == 'i')
+		goto casei;
+	goto caseout;
+
+casei:
+	// imaginary constant
+	*cp = 0;
+	yylval.val.u.cval = mal(sizeof(*yylval.val.u.cval));
+	mpmovecflt(&yylval.val.u.cval->real, 0.0);
+	mpatoflt(&yylval.val.u.cval->imag, lexbuf);
+	if(yylval.val.u.cval->imag.val.ovf) {
+		yyerror("overflow in imaginary constant");
+		mpmovecflt(&yylval.val.u.cval->real, 0.0);
+	}
+	yylval.val.ctype = CTCPLX;
+	DBG("lex: imaginary literal\n");
+	strcpy(litbuf, "literal ");
+	strcat(litbuf, lexbuf);
+	return LLITERAL;
+
+caseout:
+	*cp = 0;
+	ungetc(c);
+
+	yylval.val.u.fval = mal(sizeof(*yylval.val.u.fval));
+	mpatoflt(yylval.val.u.fval, lexbuf);
+	if(yylval.val.u.fval->val.ovf) {
+		yyerror("overflow in float constant");
+		mpmovecflt(yylval.val.u.fval, 0.0);
+	}
+	yylval.val.ctype = CTFLT;
+	DBG("lex: floating literal\n");
+	strcpy(litbuf, "literal ");
+	strcat(litbuf, lexbuf);
+	return LLITERAL;
+}
+
+/*
+ * read and interpret syntax that looks like
+ * //line parse.y:15
+ * as a discontinuity in sequential line numbers.
+ * the next line of input comes from parse.y:15
+ */
+static int
+getlinepragma(void)
+{
+	int i, c, n;
+	char *cp, *ep, *linep;
+	Hist *h;
+
+	c = getr();
+	if(c == 'g')
+		goto go;
+	if(c != 'l')	
+		goto out;
+	for(i=1; i<5; i++) {
+		c = getr();
+		if(c != "line "[i])
+			goto out;
+	}
+
+	cp = lexbuf;
+	ep = lexbuf+sizeof(lexbuf)-5;
+	linep = nil;
+	for(;;) {
+		c = getr();
+		if(c == EOF)
+			goto out;
+		if(c == '\n')
+			break;
+		if(c == ' ')
+			continue;
+		if(c == ':')
+			linep = cp;
+		if(cp < ep)
+			*cp++ = c;
+	}
+	*cp = 0;
+
+	if(linep == nil || linep >= ep)
+		goto out;
+	*linep++ = '\0';
+	n = 0;
+	for(cp=linep; *cp; cp++) {
+		if(*cp < '0' || *cp > '9')
+			goto out;
+		n = n*10 + *cp - '0';
+		if(n > 1e8) {
+			yyerror("line number out of range");
+			errorexit();
+		}
+	}
+	if(n <= 0)
+		goto out;
+
+	// try to avoid allocating file name over and over
+	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;
+		}
+	}
+	linehist(strdup(lexbuf), n, 0);
+	goto out;
+
+go:
+	cp = lexbuf;
+	ep = lexbuf+sizeof(lexbuf)-5;
+	*cp++ = 'g'; // already read
+	for(;;) {
+		c = getr();
+		if(c == EOF || c >= Runeself)
+			goto out;
+		if(c == '\n')
+			break;
+		if(cp < ep)
+			*cp++ = c;
+	}
+	*cp = 0;
+	ep = strchr(lexbuf, ' ');
+	if(ep != nil)
+		*ep = 0;
+
+	if(strcmp(lexbuf, "go:nointerface") == 0 && fieldtrack_enabled) {
+		nointerface = 1;
+		goto out;
+	}
+	if(strcmp(lexbuf, "go:noescape") == 0) {
+		noescape = 1;
+		goto out;
+	}
+	if(strcmp(lexbuf, "go:nosplit") == 0) {
+		nosplit = 1;
+		goto out;
+	}
+	
+out:
+	return c;
+}
+
+int32
+yylex(void)
+{
+	int lx;
+	
+	lx = _yylex();
+	
+	if(curio.nlsemi && lx == EOF) {
+		// Treat EOF as "end of line" for the purposes
+		// of inserting a semicolon.
+		lx = ';';
+	}
+
+	switch(lx) {
+	case LNAME:
+	case LLITERAL:
+	case LBREAK:
+	case LCONTINUE:
+	case LFALL:
+	case LRETURN:
+	case LINC:
+	case LDEC:
+	case ')':
+	case '}':
+	case ']':
+		curio.nlsemi = 1;
+		break;
+	default:
+		curio.nlsemi = 0;
+		break;
+	}
+
+	// Track last two tokens returned by yylex.
+	yyprev = yylast;
+	yylast = lx;
+	return lx;
+}
+
+static int
+getc(void)
+{
+	int c, c1, c2;
+
+	c = curio.peekc;
+	if(c != 0) {
+		curio.peekc = curio.peekc1;
+		curio.peekc1 = 0;
+		goto check;
+	}
+	
+	if(curio.bin == nil) {
+		c = *curio.cp & 0xff;
+		if(c != 0)
+			curio.cp++;
+	} else {
+	loop:
+		c = BGETC(curio.bin);
+		if(c == 0xef) {
+			c1 = BGETC(curio.bin);
+			c2 = BGETC(curio.bin);
+			if(c1 == 0xbb && c2 == 0xbf) {
+				yyerrorl(lexlineno, "Unicode (UTF-8) BOM in middle of file");
+				goto loop;
+			}
+			Bungetc(curio.bin);
+			Bungetc(curio.bin);
+		}
+	}
+
+check:
+	switch(c) {
+	case 0:
+		if(curio.bin != nil) {
+			yyerror("illegal NUL byte");
+			break;
+		}
+	case EOF:
+		// insert \n at EOF
+		if(curio.eofnl || curio.last == '\n')
+			return EOF;
+		curio.eofnl = 1;
+		c = '\n';
+	case '\n':
+		if(pushedio.bin == nil)
+			lexlineno++;
+		break;
+	}
+	curio.last = c;
+	return c;
+}
+
+static void
+ungetc(int c)
+{
+	curio.peekc1 = curio.peekc;
+	curio.peekc = c;
+	if(c == '\n' && pushedio.bin == nil)
+		lexlineno--;
+}
+
+static int32
+getr(void)
+{
+	int c, i;
+	char str[UTFmax+1];
+	Rune rune;
+
+	c = getc();
+	if(c < Runeself)
+		return c;
+	i = 0;
+	str[i++] = c;
+
+loop:
+	c = getc();
+	str[i++] = c;
+	if(!fullrune(str, i))
+		goto loop;
+	c = chartorune(&rune, str);
+	if(rune == Runeerror && c == 1) {
+		lineno = lexlineno;
+		yyerror("illegal UTF-8 sequence");
+		flusherrors();
+		print("\t");
+		for(c=0; c<i; c++)
+			print("%s%.2x", c > 0 ? " " : "", *(uchar*)(str+c));
+		print("\n");
+	}
+	return rune;
+}
+
+static int
+escchar(int e, int *escflg, vlong *val)
+{
+	int i, u, c;
+	vlong l;
+
+	*escflg = 0;
+
+	c = getr();
+	switch(c) {
+	case EOF:
+		yyerror("eof in string");
+		return 1;
+	case '\n':
+		yyerror("newline in string");
+		return 1;
+	case '\\':
+		break;
+	default:
+		if(c == e)
+			return 1;
+		*val = c;
+		return 0;
+	}
+
+	u = 0;
+	c = getr();
+	switch(c) {
+	case 'x':
+		*escflg = 1;	// it's a byte
+		i = 2;
+		goto hex;
+
+	case 'u':
+		i = 4;
+		u = 1;
+		goto hex;
+
+	case 'U':
+		i = 8;
+		u = 1;
+		goto hex;
+
+	case '0':
+	case '1':
+	case '2':
+	case '3':
+	case '4':
+	case '5':
+	case '6':
+	case '7':
+		*escflg = 1;	// it's a byte
+		goto oct;
+
+	case 'a': c = '\a'; break;
+	case 'b': c = '\b'; break;
+	case 'f': c = '\f'; break;
+	case 'n': c = '\n'; break;
+	case 'r': c = '\r'; break;
+	case 't': c = '\t'; break;
+	case 'v': c = '\v'; break;
+	case '\\': c = '\\'; break;
+
+	default:
+		if(c != e)
+			yyerror("unknown escape sequence: %c", c);
+	}
+	*val = c;
+	return 0;
+
+hex:
+	l = 0;
+	for(; i>0; i--) {
+		c = getc();
+		if(c >= '0' && c <= '9') {
+			l = l*16 + c-'0';
+			continue;
+		}
+		if(c >= 'a' && c <= 'f') {
+			l = l*16 + c-'a' + 10;
+			continue;
+		}
+		if(c >= 'A' && c <= 'F') {
+			l = l*16 + c-'A' + 10;
+			continue;
+		}
+		yyerror("non-hex character in escape sequence: %c", c);
+		ungetc(c);
+		break;
+	}
+	if(u && (l > Runemax || (0xd800 <= l && l < 0xe000))) {
+		yyerror("invalid Unicode code point in escape sequence: %#llx", l);
+		l = Runeerror;
+	}
+	*val = l;
+	return 0;
+
+oct:
+	l = c - '0';
+	for(i=2; i>0; i--) {
+		c = getc();
+		if(c >= '0' && c <= '7') {
+			l = l*8 + c-'0';
+			continue;
+		}
+		yyerror("non-octal character in escape sequence: %c", c);
+		ungetc(c);
+	}
+	if(l > 255)
+		yyerror("octal escape value > 255: %d", l);
+
+	*val = l;
+	return 0;
+}
+
+static	struct
+{
+	char*	name;
+	int	lexical;
+	int	etype;
+	int	op;
+} syms[] =
+{
+/*	name		lexical		etype		op
+ */
+/* basic types */
+	{"int8",		LNAME,		TINT8,		OXXX},
+	{"int16",	LNAME,		TINT16,		OXXX},
+	{"int32",	LNAME,		TINT32,		OXXX},
+	{"int64",	LNAME,		TINT64,		OXXX},
+
+	{"uint8",	LNAME,		TUINT8,		OXXX},
+	{"uint16",	LNAME,		TUINT16,	OXXX},
+	{"uint32",	LNAME,		TUINT32,	OXXX},
+	{"uint64",	LNAME,		TUINT64,	OXXX},
+
+	{"float32",	LNAME,		TFLOAT32,	OXXX},
+	{"float64",	LNAME,		TFLOAT64,	OXXX},
+
+	{"complex64",	LNAME,		TCOMPLEX64,	OXXX},
+	{"complex128",	LNAME,		TCOMPLEX128,	OXXX},
+
+	{"bool",		LNAME,		TBOOL,		OXXX},
+	{"string",	LNAME,		TSTRING,	OXXX},
+
+	{"any",		LNAME,		TANY,		OXXX},
+
+	{"break",	LBREAK,		Txxx,		OXXX},
+	{"case",		LCASE,		Txxx,		OXXX},
+	{"chan",		LCHAN,		Txxx,		OXXX},
+	{"const",	LCONST,		Txxx,		OXXX},
+	{"continue",	LCONTINUE,	Txxx,		OXXX},
+	{"default",	LDEFAULT,	Txxx,		OXXX},
+	{"else",		LELSE,		Txxx,		OXXX},
+	{"defer",	LDEFER,		Txxx,		OXXX},
+	{"fallthrough",	LFALL,		Txxx,		OXXX},
+	{"for",		LFOR,		Txxx,		OXXX},
+	{"func",		LFUNC,		Txxx,		OXXX},
+	{"go",		LGO,		Txxx,		OXXX},
+	{"goto",		LGOTO,		Txxx,		OXXX},
+	{"if",		LIF,		Txxx,		OXXX},
+	{"import",	LIMPORT,	Txxx,		OXXX},
+	{"interface",	LINTERFACE,	Txxx,		OXXX},
+	{"map",		LMAP,		Txxx,		OXXX},
+	{"package",	LPACKAGE,	Txxx,		OXXX},
+	{"range",	LRANGE,		Txxx,		OXXX},
+	{"return",	LRETURN,	Txxx,		OXXX},
+	{"select",	LSELECT,	Txxx,		OXXX},
+	{"struct",	LSTRUCT,	Txxx,		OXXX},
+	{"switch",	LSWITCH,	Txxx,		OXXX},
+	{"type",		LTYPE,		Txxx,		OXXX},
+	{"var",		LVAR,		Txxx,		OXXX},
+
+	{"append",	LNAME,		Txxx,		OAPPEND},
+	{"cap",		LNAME,		Txxx,		OCAP},
+	{"close",	LNAME,		Txxx,		OCLOSE},
+	{"complex",	LNAME,		Txxx,		OCOMPLEX},
+	{"copy",		LNAME,		Txxx,		OCOPY},
+	{"delete",	LNAME,		Txxx,		ODELETE},
+	{"imag",		LNAME,		Txxx,		OIMAG},
+	{"len",		LNAME,		Txxx,		OLEN},
+	{"make",		LNAME,		Txxx,		OMAKE},
+	{"new",		LNAME,		Txxx,		ONEW},
+	{"panic",	LNAME,		Txxx,		OPANIC},
+	{"print",	LNAME,		Txxx,		OPRINT},
+	{"println",	LNAME,		Txxx,		OPRINTN},
+	{"real",		LNAME,		Txxx,		OREAL},
+	{"recover",	LNAME,		Txxx,		ORECOVER},
+
+	{"notwithstanding",		LIGNORE,	Txxx,		OXXX},
+	{"thetruthofthematter",		LIGNORE,	Txxx,		OXXX},
+	{"despiteallobjections",		LIGNORE,	Txxx,		OXXX},
+	{"whereas",			LIGNORE,	Txxx,		OXXX},
+	{"insofaras",			LIGNORE,	Txxx,		OXXX},
+};
+
+static void
+lexinit(void)
+{
+	int i, lex;
+	Sym *s, *s1;
+	Type *t;
+	int etype;
+	Val v;
+
+	/*
+	 * initialize basic types array
+	 * initialize known symbols
+	 */
+	for(i=0; i<nelem(syms); i++) {
+		lex = syms[i].lexical;
+		s = lookup(syms[i].name);
+		s->lexical = lex;
+
+		etype = syms[i].etype;
+		if(etype != Txxx) {
+			if(etype < 0 || etype >= nelem(types))
+				fatal("lexinit: %s bad etype", s->name);
+			s1 = pkglookup(syms[i].name, builtinpkg);
+			t = types[etype];
+			if(t == T) {
+				t = typ(etype);
+				t->sym = s1;
+
+				if(etype != TANY && etype != TSTRING)
+					dowidth(t);
+				types[etype] = t;
+			}
+			s1->lexical = LNAME;
+			s1->def = typenod(t);
+			continue;
+		}
+
+		etype = syms[i].op;
+		if(etype != OXXX) {
+			s1 = pkglookup(syms[i].name, builtinpkg);
+			s1->lexical = LNAME;
+			s1->def = nod(ONAME, N, N);
+			s1->def->sym = s1;
+			s1->def->etype = etype;
+			s1->def->builtin = 1;
+		}
+	}
+
+	// logically, the type of a string literal.
+	// types[TSTRING] is the named type string
+	// (the type of x in var x string or var x = "hello").
+	// this is the ideal form
+	// (the type of x in const x = "hello").
+	idealstring = typ(TSTRING);
+	idealbool = typ(TBOOL);
+
+	s = pkglookup("true", builtinpkg);
+	s->def = nodbool(1);
+	s->def->sym = lookup("true");
+	s->def->type = idealbool;
+
+	s = pkglookup("false", builtinpkg);
+	s->def = nodbool(0);
+	s->def->sym = lookup("false");
+	s->def->type = idealbool;
+
+	s = lookup("_");
+	s->block = -100;
+	s->def = nod(ONAME, N, N);
+	s->def->sym = s;
+	types[TBLANK] = typ(TBLANK);
+	s->def->type = types[TBLANK];
+	nblank = s->def;
+
+	s = pkglookup("_", builtinpkg);
+	s->block = -100;
+	s->def = nod(ONAME, N, N);
+	s->def->sym = s;
+	types[TBLANK] = typ(TBLANK);
+	s->def->type = types[TBLANK];
+
+	types[TNIL] = typ(TNIL);
+	s = pkglookup("nil", builtinpkg);
+	v.ctype = CTNIL;
+	s->def = nodlit(v);
+	s->def->sym = s;
+}
+
+static void
+lexinit1(void)
+{
+	Sym *s, *s1;
+	Type *t, *f, *rcvr, *in, *out;
+
+	// t = interface { Error() string }
+	rcvr = typ(TSTRUCT);
+	rcvr->type = typ(TFIELD);
+	rcvr->type->type = ptrto(typ(TSTRUCT));
+	rcvr->funarg = 1;
+	in = typ(TSTRUCT);
+	in->funarg = 1;
+	out = typ(TSTRUCT);
+	out->type = typ(TFIELD);
+	out->type->type = types[TSTRING];
+	out->funarg = 1;
+	f = typ(TFUNC);
+	*getthis(f) = rcvr;
+	*getoutarg(f) = out;
+	*getinarg(f) = in;
+	f->thistuple = 1;
+	f->intuple = 0;
+	f->outnamed = 0;
+	f->outtuple = 1;
+	t = typ(TINTER);
+	t->type = typ(TFIELD);
+	t->type->sym = lookup("Error");
+	t->type->type = f;
+
+	// error type
+	s = lookup("error");
+	s->lexical = LNAME;
+	s1 = pkglookup("error", builtinpkg);
+	errortype = t;
+	errortype->sym = s1;
+	s1->lexical = LNAME;
+	s1->def = typenod(errortype);
+
+	// byte alias
+	s = lookup("byte");
+	s->lexical = LNAME;
+	s1 = pkglookup("byte", builtinpkg);
+	bytetype = typ(TUINT8);
+	bytetype->sym = s1;
+	s1->lexical = LNAME;
+	s1->def = typenod(bytetype);
+
+	// rune alias
+	s = lookup("rune");
+	s->lexical = LNAME;
+	s1 = pkglookup("rune", builtinpkg);
+	runetype = typ(TINT32);
+	runetype->sym = s1;
+	s1->lexical = LNAME;
+	s1->def = typenod(runetype);
+}
+
+static void
+lexfini(void)
+{
+	Sym *s;
+	int lex, etype, i;
+	Val v;
+
+	for(i=0; i<nelem(syms); i++) {
+		lex = syms[i].lexical;
+		if(lex != LNAME)
+			continue;
+		s = lookup(syms[i].name);
+		s->lexical = lex;
+
+		etype = syms[i].etype;
+		if(etype != Txxx && (etype != TANY || debug['A']) && s->def == N) {
+			s->def = typenod(types[etype]);
+			s->origpkg = builtinpkg;
+		}
+
+		etype = syms[i].op;
+		if(etype != OXXX && s->def == N) {
+			s->def = nod(ONAME, N, N);
+			s->def->sym = s;
+			s->def->etype = etype;
+			s->def->builtin = 1;
+			s->origpkg = builtinpkg;
+		}
+	}
+
+	// backend-specific builtin types (e.g. int).
+	for(i=0; typedefs[i].name; i++) {
+		s = lookup(typedefs[i].name);
+		if(s->def == N) {
+			s->def = typenod(types[typedefs[i].etype]);
+			s->origpkg = builtinpkg;
+		}
+	}
+
+	// there's only so much table-driven we can handle.
+	// these are special cases.
+	s = lookup("byte");
+	if(s->def == N) {
+		s->def = typenod(bytetype);
+		s->origpkg = builtinpkg;
+	}
+
+	s = lookup("error");
+	if(s->def == N) {
+		s->def = typenod(errortype);
+		s->origpkg = builtinpkg;
+	}
+
+	s = lookup("rune");
+	if(s->def == N) {
+		s->def = typenod(runetype);
+		s->origpkg = builtinpkg;
+	}
+
+	s = lookup("nil");
+	if(s->def == N) {
+		v.ctype = CTNIL;
+		s->def = nodlit(v);
+		s->def->sym = s;
+		s->origpkg = builtinpkg;
+	}
+
+	s = lookup("iota");
+	if(s->def == N) {
+		s->def = nod(OIOTA, N, N);
+		s->def->sym = s;
+		s->origpkg = builtinpkg;
+	}
+
+	s = lookup("true");
+	if(s->def == N) {
+		s->def = nodbool(1);
+		s->def->sym = s;
+		s->origpkg = builtinpkg;
+	}
+
+	s = lookup("false");
+	if(s->def == N) {
+		s->def = nodbool(0);
+		s->def->sym = s;
+		s->origpkg = builtinpkg;
+	}
+
+	nodfp = nod(ONAME, N, N);
+	nodfp->type = types[TINT32];
+	nodfp->xoffset = 0;
+	nodfp->class = PPARAM;
+	nodfp->sym = lookup(".fp");
+}
+
+struct
+{
+	int	lex;
+	char*	name;
+} 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"},
+	{LFALL,		"FALL"},
+	{LFOR,		"FOR"},
+	{LFUNC,		"FUNC"},
+	{LGE,		"GE"},
+	{LGO,		"GO"},
+	{LGOTO,		"GOTO"},
+	{LGT,		"GT"},
+	{LIF,		"IF"},
+	{LIMPORT,	"IMPORT"},
+	{LINC,		"INC"},
+	{LINTERFACE,	"INTERFACE"},
+	{LLE,		"LE"},
+	{LLITERAL,	"LITERAL"},
+	{LLSH,		"LSH"},
+	{LLT,		"LT"},
+	{LMAP,		"MAP"},
+	{LNAME,		"NAME"},
+	{LNE,		"NE"},
+	{LOROR,		"OROR"},
+	{LPACKAGE,	"PACKAGE"},
+	{LRANGE,		"RANGE"},
+	{LRETURN,	"RETURN"},
+	{LRSH,		"RSH"},
+	{LSELECT,	"SELECT"},
+	{LSTRUCT,	"STRUCT"},
+	{LSWITCH,	"SWITCH"},
+	{LTYPE,		"TYPE"},
+	{LVAR,		"VAR"},
+};
+
+char*
+lexname(int lex)
+{
+	int i;
+	static char buf[100];
+
+	for(i=0; i<nelem(lexn); i++)
+		if(lexn[i].lex == lex)
+			return lexn[i].name;
+	snprint(buf, sizeof(buf), "LEX-%d", lex);
+	return buf;
+}
+
+struct
+{
+	char *have;
+	char *want;
+} yytfix[] =
+{
+	{"$end",	"EOF"},
+	{"LLITERAL",	"literal"},
+	{"LASOP",	"op="},
+	{"LBREAK",	"break"},
+	{"LCASE",	"case"},
+	{"LCHAN",	"chan"},
+	{"LCOLAS",	":="},
+	{"LCONST",	"const"},
+	{"LCONTINUE",	"continue"},
+	{"LDDD",	"..."},
+	{"LDEFAULT",	"default"},
+	{"LDEFER",	"defer"},
+	{"LELSE",	"else"},
+	{"LFALL",	"fallthrough"},
+	{"LFOR",	"for"},
+	{"LFUNC",	"func"},
+	{"LGO",	"go"},
+	{"LGOTO",	"goto"},
+	{"LIF",	"if"},
+	{"LIMPORT",	"import"},
+	{"LINTERFACE",	"interface"},
+	{"LMAP",	"map"},
+	{"LNAME",	"name"},
+	{"LPACKAGE",	"package"},
+	{"LRANGE",	"range"},
+	{"LRETURN",	"return"},
+	{"LSELECT",	"select"},
+	{"LSTRUCT",	"struct"},
+	{"LSWITCH",	"switch"},
+	{"LTYPE",	"type"},
+	{"LVAR",	"var"},
+	{"LANDAND",	"&&"},
+	{"LANDNOT",	"&^"},
+	{"LBODY",	"{"},
+	{"LCOMM",	"<-"},
+	{"LDEC",	"--"},
+	{"LINC",	"++"},
+	{"LEQ",	"=="},
+	{"LGE",	">="},
+	{"LGT",	">"},
+	{"LLE",	"<="},
+	{"LLT",	"<"},
+	{"LLSH",	"<<"},
+	{"LRSH",	">>"},
+	{"LOROR",	"||"},
+	{"LNE",	"!="},
+	
+	// spell out to avoid confusion with punctuation in error messages
+	{"';'",	"semicolon or newline"},
+	{"','",	"comma"},
+};
+
+static void
+yytinit(void)
+{
+	int i, j;
+	extern char *yytname[];
+	char *s, *t;
+
+	for(i=0; yytname[i] != nil; i++) {
+		s = yytname[i];
+		
+		if(strcmp(s, "LLITERAL") == 0) {
+			strcpy(litbuf, "literal");
+			yytname[i] = litbuf;
+			goto loop;
+		}
+		
+		// apply yytfix if possible
+		for(j=0; j<nelem(yytfix); j++) {
+			if(strcmp(s, yytfix[j].have) == 0) {
+				yytname[i] = yytfix[j].want;
+				goto loop;
+			}
+		}
+
+		// turn 'x' into x.
+		if(s[0] == '\'') {
+			t = strdup(s+1);
+			t[strlen(t)-1] = '\0';
+			yytname[i] = t;
+		}
+	loop:;
+	}		
+}
+
+static void
+pkgnotused(int lineno, Strlit *path, char *name)
+{
+	char *elem;
+	
+	// If the package was imported with a name other than the final
+	// import path element, show it explicitly in the error message.
+	// Note that this handles both renamed imports and imports of
+	// packages containing unconventional package declarations.
+	// Note that this uses / always, even on Windows, because Go import
+	// paths always use forward slashes.
+	elem = strrchr(path->s, '/');
+	if(elem != nil)
+		elem++;
+	else
+		elem = path->s;
+	if(name == nil || strcmp(elem, name) == 0)
+		yyerrorl(lineno, "imported and not used: \"%Z\"", path);
+	else
+		yyerrorl(lineno, "imported and not used: \"%Z\" as %s", path, name);
+}
+
+void
+mkpackage(char* pkgname)
+{
+	Sym *s;
+	int32 h;
+	char *p, *q;
+
+	if(localpkg->name == nil) {
+		if(strcmp(pkgname, "_") == 0)
+			yyerror("invalid package name _");
+		localpkg->name = pkgname;
+	} else {
+		if(strcmp(pkgname, localpkg->name) != 0)
+			yyerror("package %s; expected %s", pkgname, localpkg->name);
+		for(h=0; h<NHASH; h++) {
+			for(s = hash[h]; s != S; s = s->link) {
+				if(s->def == N || s->pkg != localpkg)
+					continue;
+				if(s->def->op == OPACK) {
+					// throw away top-level package name leftover
+					// from previous file.
+					// leave s->block set to cause redeclaration
+					// errors if a conflicting top-level name is
+					// introduced by a different file.
+					if(!s->def->used && !nsyntaxerrors)
+						pkgnotused(s->def->lineno, s->def->pkg->path, s->name);
+					s->def = N;
+					continue;
+				}
+				if(s->def->sym != s) {
+					// throw away top-level name left over
+					// from previous import . "x"
+					if(s->def->pack != N && !s->def->pack->used && !nsyntaxerrors) {
+						pkgnotused(s->def->pack->lineno, s->def->pack->pkg->path, nil);
+						s->def->pack->used = 1;
+					}
+					s->def = N;
+					continue;
+				}
+			}
+		}
+	}
+
+	if(outfile == nil) {
+		p = strrchr(infile, '/');
+		if(ctxt->windows) {
+			q = strrchr(infile, '\\');
+			if(q > p)
+				p = q;
+		}
+		if(p == nil)
+			p = infile;
+		else
+			p = p+1;
+		snprint(namebuf, sizeof(namebuf), "%s", p);
+		p = strrchr(namebuf, '.');
+		if(p != nil)
+			*p = 0;
+		outfile = smprint("%s.%c", namebuf, thechar);
+	}
+}
diff --git a/src/cmd/gc/md5.c b/src/cmd/gc/md5.c
new file mode 100644
index 0000000..46cb6b7
--- /dev/null
+++ b/src/cmd/gc/md5.c
@@ -0,0 +1,302 @@
+// 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.
+
+// 64-bit MD5 (does full MD5 but returns 64 bits only).
+// Translation of ../../crypto/md5/md5*.go.
+
+#include <u.h>
+#include <libc.h>
+#include "go.h"
+#include "md5.h"
+
+static int md5block(MD5 *dig, uchar *p, int nn);
+
+enum {
+	_Chunk = 64
+};
+
+#define _Init0 0x67452301
+#define _Init1 0xEFCDAB89
+#define _Init2 0x98BADCFE
+#define _Init3 0x10325476
+/*c2go
+enum {
+	_Init0 = 0x67452301,
+	_Init1 = 0xEFCDAB89,
+	_Init2 = 0x98BADCFE,
+	_Init3 = 0x10325476
+};
+*/
+	
+void
+md5reset(MD5 *d)
+{
+	d->s[0] = _Init0;
+	d->s[1] = _Init1;
+	d->s[2] = _Init2;
+	d->s[3] = _Init3;
+	d->nx = 0;
+	d->len = 0;
+}
+
+void
+md5write(MD5 *d, uchar *p, int nn)
+{
+	int i, n;
+
+	d->len += nn;
+	if(d->nx > 0) {
+		n = nn;
+		if(n > _Chunk - d->nx)
+			n = _Chunk - d->nx;
+		for(i=0; i<n; i++)
+			d->x[d->nx+i] = p[i];
+		d->nx += n;
+		if(d->nx == _Chunk) {
+			md5block(d, d->x, _Chunk);
+			d->nx = 0;
+		}
+		p += n;
+		nn -= n;
+	}
+	n = md5block(d, p, nn);
+	p += n;
+	nn -= n;
+	if(nn > 0) {
+		for(i=0; i<nn; i++)
+			d->x[i] = p[i];
+		d->nx = nn;
+	}
+}
+
+uint64
+md5sum(MD5 *d, uint64 *hi)
+{
+	uchar tmp[64];
+	int i;
+	uint64 len;
+
+	// Padding.  Add a 1 bit and 0 bits until 56 bytes mod 64.
+	len = d->len;
+	memset(tmp, 0, sizeof tmp);
+	tmp[0] = 0x80;
+	if(len%64 < 56)
+		md5write(d, tmp, 56-len%64);
+	else
+		md5write(d, tmp, 64+56-len%64);
+
+	// Length in bits.
+	len <<= 3;
+	for(i=0; i<8; i++)
+		tmp[i] = len>>(8*i);
+	md5write(d, tmp, 8);
+
+	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);
+}
+
+
+// MD5 block step.
+// In its own file so that a faster assembly or C version
+// can be substituted easily.
+
+// table[i] = int((1<<32) * abs(sin(i+1 radians))).
+static uint32 table[64] = {
+	// round 1
+	0xd76aa478,
+	0xe8c7b756,
+	0x242070db,
+	0xc1bdceee,
+	0xf57c0faf,
+	0x4787c62a,
+	0xa8304613,
+	0xfd469501,
+	0x698098d8,
+	0x8b44f7af,
+	0xffff5bb1,
+	0x895cd7be,
+	0x6b901122,
+	0xfd987193,
+	0xa679438e,
+	0x49b40821,
+
+	// round 2
+	0xf61e2562,
+	0xc040b340,
+	0x265e5a51,
+	0xe9b6c7aa,
+	0xd62f105d,
+	0x2441453,
+	0xd8a1e681,
+	0xe7d3fbc8,
+	0x21e1cde6,
+	0xc33707d6,
+	0xf4d50d87,
+	0x455a14ed,
+	0xa9e3e905,
+	0xfcefa3f8,
+	0x676f02d9,
+	0x8d2a4c8a,
+
+	// round3
+	0xfffa3942,
+	0x8771f681,
+	0x6d9d6122,
+	0xfde5380c,
+	0xa4beea44,
+	0x4bdecfa9,
+	0xf6bb4b60,
+	0xbebfbc70,
+	0x289b7ec6,
+	0xeaa127fa,
+	0xd4ef3085,
+	0x4881d05,
+	0xd9d4d039,
+	0xe6db99e5,
+	0x1fa27cf8,
+	0xc4ac5665,
+
+	// round 4
+	0xf4292244,
+	0x432aff97,
+	0xab9423a7,
+	0xfc93a039,
+	0x655b59c3,
+	0x8f0ccc92,
+	0xffeff47d,
+	0x85845dd1,
+	0x6fa87e4f,
+	0xfe2ce6e0,
+	0xa3014314,
+	0x4e0811a1,
+	0xf7537e82,
+	0xbd3af235,
+	0x2ad7d2bb,
+	0xeb86d391,
+};
+
+static uint32 shift1[] = { 7, 12, 17, 22 };
+static uint32 shift2[] = { 5, 9, 14, 20 };
+static uint32 shift3[] = { 4, 11, 16, 23 };
+static uint32 shift4[] = { 6, 10, 15, 21 };
+
+static int
+md5block(MD5 *dig, uchar *p, int nn)
+{
+	uint32 a, b, c, d, aa, bb, cc, dd;
+	int i, j, n;
+	uint32 X[16];
+
+	a = dig->s[0];
+	b = dig->s[1];
+	c = dig->s[2];
+	d = dig->s[3];
+	n = 0;
+
+	while(nn >= _Chunk) {
+		aa = a;
+		bb = b;
+		cc = c;
+		dd = d;
+
+		for(i=0; i<16; i++) {
+			j = i*4;
+			X[i] = p[j] | (p[j+1]<<8) | (p[j+2]<<16) | ((uint32)p[j+3]<<24);
+		}
+
+		// Round 1.
+		for(i=0; i<16; i++) {
+			uint32 x, t, s, f;
+			x = i;
+			t = i;
+			s = shift1[i%4];
+			f = ((c ^ d) & b) ^ d;
+			a += f + X[x] + table[t];
+			a = a<<s | a>>(32-s);
+			a += b;
+
+			t = d;
+			d = c;
+			c = b;
+			b = a;
+			a = t;
+		}
+
+		// Round 2.
+		for(i=0; i<16; i++) {
+			uint32 x, t, s, g;
+
+			x = (1+5*i)%16;
+			t = 16+i;
+			s = shift2[i%4];
+			g = ((b ^ c) & d) ^ c;
+			a += g + X[x] + table[t];
+			a = a<<s | a>>(32-s);
+			a += b;
+
+			t = d;
+			d = c;
+			c = b;
+			b = a;
+			a = t;
+		}
+
+		// Round 3.
+		for(i=0; i<16; i++) {
+			uint32 x, t, s, h;
+
+			x = (5+3*i)%16;
+			t = 32+i;
+			s = shift3[i%4];
+			h = b ^ c ^ d;
+			a += h + X[x] + table[t];
+			a = a<<s | a>>(32-s);
+			a += b;
+
+			t = d;
+			d = c;
+			c = b;
+			b = a;
+			a = t;
+		}
+
+		// Round 4.
+		for(i=0; i<16; i++) {
+			uint32 x, s, t, ii;
+
+			x = (7*i)%16;
+			s = shift4[i%4];
+			t = 48+i;
+			ii = c ^ (b | ~d);
+			a += ii + X[x] + table[t];
+			a = a<<s | a>>(32-s);
+			a += b;
+
+			t = d;
+			d = c;
+			c = b;
+			b = a;
+			a = t;
+		}
+
+		a += aa;
+		b += bb;
+		c += cc;
+		d += dd;
+
+		p += _Chunk;
+		n += _Chunk;
+		nn -= _Chunk;
+	}
+
+	dig->s[0] = a;
+	dig->s[1] = b;
+	dig->s[2] = c;
+	dig->s[3] = d;
+	return n;
+}
diff --git a/src/cmd/gc/md5.h b/src/cmd/gc/md5.h
new file mode 100644
index 0000000..5a60106
--- /dev/null
+++ b/src/cmd/gc/md5.h
@@ -0,0 +1,16 @@
+// 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.
+
+typedef struct MD5 MD5;
+struct MD5
+{
+	uint32 s[4];
+	uchar x[64];
+	int nx;
+	uint64 len;
+};
+
+void md5reset(MD5*);
+void md5write(MD5*, uchar*, int);
+uint64 md5sum(MD5*, uint64*);
diff --git a/src/cmd/gc/mkbuiltin b/src/cmd/gc/mkbuiltin
new file mode 100755
index 0000000..1dab1c9
--- /dev/null
+++ b/src/cmd/gc/mkbuiltin
@@ -0,0 +1,32 @@
+#!/bin/sh
+# 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 builtin.c from $* (runtime.go and unsafe.go).
+# Run this after changing runtime.go and unsafe.go
+# or after changing the export metadata format in the compiler.
+# Either way, you need to have a working compiler binary first.
+
+set -e
+
+eval $(go tool dist env)
+if [ -z "$GOCHAR" ]; then
+	echo 'missing $GOCHAR - go tool dist failed?' 1>&2
+	exit 1
+fi
+
+GC=${GOCHAR}g
+gcc -o mkbuiltin1 mkbuiltin1.c
+rm -f _builtin.c
+echo "// AUTO-GENERATED by mkbuiltin; DO NOT EDIT" >>_builtin.c
+for i in runtime unsafe
+do
+	go tool $GC -A $i.go
+	O=$GOCHAR ./mkbuiltin1 $i >>_builtin.c
+done
+
+# If _builtin.c has changed vs builtin.c,
+# check in the new change.
+cmp -s _builtin.c builtin.c || cp _builtin.c builtin.c
+rm _builtin.c mkbuiltin1 unsafe.$GOCHAR runtime.$GOCHAR
diff --git a/src/cmd/gc/mkbuiltin1.c b/src/cmd/gc/mkbuiltin1.c
new file mode 100644
index 0000000..69027fd
--- /dev/null
+++ b/src/cmd/gc/mkbuiltin1.c
@@ -0,0 +1,102 @@
+// 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
+
+// Compile .go file, import data from .6 file, and generate C string version.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <stdarg.h>
+
+void esc(char*);
+void fatal(char*, ...);
+
+int
+main(int argc, char **argv)
+{
+	char *name;
+	FILE *fin;
+	char buf[1024], initfunc[1024], *p, *q;
+
+	if(argc != 2) {
+		fprintf(stderr, "usage: mkbuiltin1 sys\n");
+		fatal("in file $1.6 s/PACKAGE/$1/");
+	}
+
+	name = argv[1];
+	snprintf(initfunc, sizeof(initfunc), "init_%s_function", name);
+
+	snprintf(buf, sizeof(buf), "%s.%s", name, getenv("O"));
+	if((fin = fopen(buf, "r")) == NULL) {
+		fatal("open %s: %s", buf, strerror(errno));
+	}
+
+	// look for $$ that introduces imports
+	while(fgets(buf, sizeof buf, fin) != NULL)
+		if(strstr(buf, "$$"))
+			goto begin;
+	fatal("did not find beginning of imports");
+
+begin:
+	printf("char *%simport =\n", name);
+
+	// process imports, stopping at $$ that closes them
+	while(fgets(buf, sizeof buf, fin) != NULL) {
+		buf[strlen(buf)-1] = 0;	// chop \n
+		if(strstr(buf, "$$"))
+			goto end;
+
+		// chop leading white space
+		for(p=buf; *p==' ' || *p == '\t'; p++)
+			;
+
+		// cut out decl of init_$1_function - it doesn't exist
+		if(strstr(buf, initfunc))
+			continue;
+
+		// sys.go claims to be in package PACKAGE to avoid
+		// conflicts during "6g sys.go".  rename PACKAGE to $2.
+		printf("\t\"");
+		while((q = strstr(p, "PACKAGE")) != NULL) {
+			*q = 0;
+			esc(p);	// up to the substitution
+			printf("%s", name);	// the sub name
+			p = q+7;		// continue with rest
+		}
+
+		esc(p);
+		printf("\\n\"\n");
+	}
+	fatal("did not find end of imports");
+
+end:
+	printf("\t\"$$\\n\";\n");
+	return 0;
+}
+
+void
+esc(char *p)
+{
+	for(; *p; p++) {
+		if(*p == '\\' || *p == '\"')
+			printf("\\");
+		putchar(*p);
+	}
+}
+
+void
+fatal(char *msg, ...)
+{
+	va_list arg;
+	
+	va_start(arg, msg);
+	fprintf(stderr, "fatal: ");
+	vfprintf(stderr, msg, arg);
+	fprintf(stderr, "\n");
+	exit(2);
+}
diff --git a/src/cmd/gc/mkopnames b/src/cmd/gc/mkopnames
new file mode 100755
index 0000000..d3f27e8
--- /dev/null
+++ b/src/cmd/gc/mkopnames
@@ -0,0 +1,24 @@
+#!/bin/sh
+# 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.
+
+# Disable colored grep if user has it set to --color=always.
+# (Arguably user error.)
+export GREP_OPTIONS=""
+
+echo '// auto generated by mkopnames'
+echo 'static char*'
+echo 'opnames[] = '
+echo '{'
+sed -n '/OXXX/,/OEND/p' go.h |
+	cpp |
+	sed 's!//.*!!; /^#/d'  |
+	tr ' ' '\012' |
+	tr -d ' \011,' |
+	grep . |
+	sort |
+	grep -v '^OEND$' |
+	sed 's/O//; s/.*/	[O&] =	"&",/'
+echo '};'
+
diff --git a/src/cmd/gc/mparith1.c b/src/cmd/gc/mparith1.c
new file mode 100644
index 0000000..d33a81e
--- /dev/null
+++ b/src/cmd/gc/mparith1.c
@@ -0,0 +1,641 @@
+// 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	"go.h"
+
+/// uses arithmetic
+
+int
+mpcmpfixflt(Mpint *a, Mpflt *b)
+{
+	char buf[500];
+	Mpflt c;
+
+	snprint(buf, sizeof(buf), "%B", a);
+	mpatoflt(&c, buf);
+	return mpcmpfltflt(&c, b);
+}
+
+int
+mpcmpfltfix(Mpflt *a, Mpint *b)
+{
+	char buf[500];
+	Mpflt c;
+
+	snprint(buf, sizeof(buf), "%B", b);
+	mpatoflt(&c, buf);
+	return mpcmpfltflt(a, &c);
+}
+
+int
+mpcmpfixfix(Mpint *a, Mpint *b)
+{
+	Mpint c;
+
+	mpmovefixfix(&c, a);
+	mpsubfixfix(&c, b);
+	return mptestfix(&c);
+}
+
+int
+mpcmpfixc(Mpint *b, vlong c)
+{
+	Mpint c1;
+
+	mpmovecfix(&c1, c);
+	return mpcmpfixfix(b, &c1);
+}
+
+int
+mpcmpfltflt(Mpflt *a, Mpflt *b)
+{
+	Mpflt c;
+
+	mpmovefltflt(&c, a);
+	mpsubfltflt(&c, b);
+	return mptestflt(&c);
+}
+
+int
+mpcmpfltc(Mpflt *b, double c)
+{
+	Mpflt a;
+
+	mpmovecflt(&a, c);
+	return mpcmpfltflt(b, &a);
+}
+
+void
+mpsubfixfix(Mpint *a, Mpint *b)
+{
+	mpnegfix(a);
+	mpaddfixfix(a, b, 0);
+	mpnegfix(a);
+}
+
+void
+mpsubfltflt(Mpflt *a, Mpflt *b)
+{
+	mpnegflt(a);
+	mpaddfltflt(a, b);
+	mpnegflt(a);
+}
+
+void
+mpaddcfix(Mpint *a, vlong c)
+{
+	Mpint b;
+
+	mpmovecfix(&b, c);
+	mpaddfixfix(a, &b, 0);
+}
+
+void
+mpaddcflt(Mpflt *a, double c)
+{
+	Mpflt b;
+
+	mpmovecflt(&b, c);
+	mpaddfltflt(a, &b);
+}
+
+void
+mpmulcfix(Mpint *a, vlong c)
+{
+	Mpint b;
+
+	mpmovecfix(&b, c);
+	mpmulfixfix(a, &b);
+}
+
+void
+mpmulcflt(Mpflt *a, double c)
+{
+	Mpflt b;
+
+	mpmovecflt(&b, c);
+	mpmulfltflt(a, &b);
+}
+
+void
+mpdivfixfix(Mpint *a, Mpint *b)
+{
+	Mpint q, r;
+
+	mpdivmodfixfix(&q, &r, a, b);
+	mpmovefixfix(a, &q);
+}
+
+void
+mpmodfixfix(Mpint *a, Mpint *b)
+{
+	Mpint q, r;
+
+	mpdivmodfixfix(&q, &r, a, b);
+	mpmovefixfix(a, &r);
+}
+
+void
+mpcomfix(Mpint *a)
+{
+	Mpint b;
+
+	mpmovecfix(&b, 1);
+	mpnegfix(a);
+	mpsubfixfix(a, &b);
+}
+
+void
+mpmovefixflt(Mpflt *a, Mpint *b)
+{
+	a->val = *b;
+	a->exp = 0;
+	mpnorm(a);
+}
+
+// convert (truncate) b to a.
+// return -1 (but still convert) if b was non-integer.
+static int
+mpexactfltfix(Mpint *a, Mpflt *b)
+{
+	Mpflt f;
+
+	*a = b->val;
+	mpshiftfix(a, b->exp);
+	if(b->exp < 0) {
+		f.val = *a;
+		f.exp = 0;
+		mpnorm(&f);
+		if(mpcmpfltflt(b, &f) != 0)
+			return -1;
+	}
+	return 0;
+}
+
+int
+mpmovefltfix(Mpint *a, Mpflt *b)
+{
+	Mpflt f;
+	int i;
+
+	if(mpexactfltfix(a, b) == 0)
+		return 0;
+
+	// try rounding down a little
+	f = *b;
+	f.val.a[0] = 0;
+	if(mpexactfltfix(a, &f) == 0)
+		return 0;
+
+	// try rounding up a little
+	for(i=1; i<Mpprec; i++) {
+		f.val.a[i]++;
+		if(f.val.a[i] != Mpbase)
+			break;
+		f.val.a[i] = 0;
+	}
+	mpnorm(&f);
+	if(mpexactfltfix(a, &f) == 0)
+		return 0;
+
+	return -1;
+}
+
+void
+mpmovefixfix(Mpint *a, Mpint *b)
+{
+	*a = *b;
+}
+
+void
+mpmovefltflt(Mpflt *a, Mpflt *b)
+{
+	*a = *b;
+}
+
+static	double	tab[] = { 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7 };
+static void
+mppow10flt(Mpflt *a, int p)
+{
+	if(p < 0)
+		abort();
+	if(p < nelem(tab)) {
+		mpmovecflt(a, tab[p]);
+		return;
+	}
+	mppow10flt(a, p>>1);
+	mpmulfltflt(a, a);
+	if(p & 1)
+		mpmulcflt(a, 10);
+}
+
+static void
+mphextofix(Mpint *a, char *s, int n)
+{
+	char *hexdigitp, *end, c;
+	long d;
+	int bit;
+
+	while(*s == '0') {
+		s++;
+		n--;
+	}
+
+	// overflow
+	if(4*n > Mpscale*Mpprec) {
+		a->ovf = 1;
+		return;
+	}
+
+	end = s+n-1;
+	for(hexdigitp=end; hexdigitp>=s; hexdigitp--) {
+		c = *hexdigitp;
+		if(c >= '0' && c <= '9')
+			d = c-'0';
+		else if(c >= 'A' && c <= 'F')
+			d = c-'A'+10;
+		else
+			d = c-'a'+10;
+
+		bit = 4*(end - hexdigitp);
+		while(d > 0) {
+			if(d & 1)
+				a->a[bit/Mpscale] |= (long)1 << (bit%Mpscale);
+			bit++;
+			d = d >> 1;
+		}
+	}
+}
+
+//
+// floating point input
+// required syntax is [+-]d*[.]d*[e[+-]d*] or [+-]0xH*[e[+-]d*]
+//
+void
+mpatoflt(Mpflt *a, char *as)
+{
+	Mpflt b;
+	int dp, c, f, ef, ex, eb, base;
+	char *s, *start;
+
+	while(*as == ' ' || *as == '\t')
+		as++;
+
+	/* determine base */
+	s = as;
+	base = -1;
+	while(base == -1) {
+		switch(*s++) {
+		case '-':
+		case '+':
+			break;
+
+		case '0':
+			if(*s == 'x')
+				base = 16;
+			else
+				base = 10;
+			break;
+
+		default:
+			base = 10;
+		}
+	}
+
+	s = as;
+	dp = 0;		/* digits after decimal point */
+	f = 0;		/* sign */
+	ex = 0;		/* exponent */
+	eb = 0;		/* binary point */
+
+	mpmovecflt(a, 0.0);
+	if(base == 16) {
+		start = nil;
+		for(;;) {
+			c = *s;
+			if(c == '-') {
+				f = 1;
+				s++;
+			}
+			else if(c == '+') {
+				s++;
+			}
+			else if(c == '0' && s[1] == 'x') {
+				s += 2;
+				start = s;
+			}
+			else if((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) {
+				s++;
+			}
+			else {
+				break;
+			}
+		}
+		if(start == nil)
+			goto bad;
+
+		mphextofix(&a->val, start, s-start);
+		if(a->val.ovf)
+			goto bad;
+		a->exp = 0;
+		mpnorm(a);
+	}
+	for(;;) {
+		switch(c = *s++) {
+		default:
+			goto bad;
+
+		case '-':
+			f = 1;
+
+		case ' ':
+		case '\t':
+		case '+':
+			continue;
+
+		case '.':
+			if(base == 16)
+				goto bad;
+			dp = 1;
+			continue;
+
+		case '1':
+		case '2':
+		case '3':
+		case '4':
+		case '5':
+		case '6':
+		case '7':
+		case '8':
+		case '9':
+		case '0':
+			mpmulcflt(a, 10);
+			mpaddcflt(a, c-'0');
+			if(dp)
+				dp++;
+			continue;
+
+		case 'P':
+		case 'p':
+			eb = 1;
+
+		case 'E':
+		case 'e':
+			ex = 0;
+			ef = 0;
+			for(;;) {
+				c = *s++;
+				if(c == '+' || c == ' ' || c == '\t')
+					continue;
+				if(c == '-') {
+					ef = 1;
+					continue;
+				}
+				if(c >= '0' && c <= '9') {
+					ex = ex*10 + (c-'0');
+					if(ex > 1e8) {
+						yyerror("constant exponent out of range: %s", as);
+						errorexit();
+					}
+					continue;
+				}
+				break;
+			}
+			if(ef)
+				ex = -ex;
+
+		case 0:
+			break;
+		}
+		break;
+	}
+
+	if(eb) {
+		if(dp)
+			goto bad;
+		mpsetexp(a, a->exp+ex);
+		goto out;
+	}
+
+	if(dp)
+		dp--;
+	if(mpcmpfltc(a, 0.0) != 0) {
+		if(ex >= dp) {
+			mppow10flt(&b, ex-dp);
+			mpmulfltflt(a, &b);
+		} else {
+			// 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);
+			}
+		}
+	}
+
+out:
+	if(f)
+		mpnegflt(a);
+	return;
+
+bad:
+	yyerror("constant too large: %s", as);
+	mpmovecflt(a, 0.0);
+}
+
+//
+// fixed point input
+// required syntax is [+-][0[x]]d*
+//
+void
+mpatofix(Mpint *a, char *as)
+{
+	int c, f;
+	char *s, *s0;
+
+	s = as;
+	f = 0;
+	mpmovecfix(a, 0);
+
+	c = *s++;
+	switch(c) {
+	case '-':
+		f = 1;
+
+	case '+':
+		c = *s++;
+		if(c != '0')
+			break;
+
+	case '0':
+		goto oct;
+	}
+
+	while(c) {
+		if(c >= '0' && c <= '9') {
+			mpmulcfix(a, 10);
+			mpaddcfix(a, c-'0');
+			c = *s++;
+			continue;
+		}
+		goto bad;
+	}
+	goto out;
+
+oct:
+	c = *s++;
+	if(c == 'x' || c == 'X')
+		goto hex;
+	while(c) {
+		if(c >= '0' && c <= '7') {
+			mpmulcfix(a, 8);
+			mpaddcfix(a, c-'0');
+			c = *s++;
+			continue;
+		}
+		goto bad;
+	}
+	goto out;
+
+hex:
+	s0 = s;
+	c = *s;
+	while(c) {
+		if((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) {
+			s++;
+			c = *s;
+			continue;
+		}
+		goto bad;
+	}
+	mphextofix(a, s0, s-s0);
+	if(a->ovf)
+		goto bad;
+
+out:
+	if(f)
+		mpnegfix(a);
+	return;
+
+bad:
+	yyerror("constant too large: %s", as);
+	mpmovecfix(a, 0);
+}
+
+int
+Bconv(Fmt *fp)
+{
+	char buf[500], *p;
+	Mpint *xval, q, r, ten, sixteen;
+	int f, digit;
+
+	xval = va_arg(fp->args, Mpint*);
+	mpmovefixfix(&q, xval);
+	f = 0;
+	if(mptestfix(&q) < 0) {
+		f = 1;
+		mpnegfix(&q);
+	}
+
+	p = &buf[sizeof(buf)];
+	*--p = 0;
+	if(fp->flags & FmtSharp) {
+		// Hexadecimal
+		mpmovecfix(&sixteen, 16);
+		for(;;) {
+			mpdivmodfixfix(&q, &r, &q, &sixteen);
+			digit = mpgetfix(&r);
+			if(digit < 10)
+				*--p = digit + '0';
+			else
+				*--p = digit - 10 + 'A';
+			if(mptestfix(&q) <= 0)
+				break;
+		}
+		*--p = 'x';
+		*--p = '0';
+	} else {
+		// Decimal
+		mpmovecfix(&ten, 10);
+		for(;;) {
+			mpdivmodfixfix(&q, &r, &q, &ten);
+			*--p = mpgetfix(&r) + '0';
+			if(mptestfix(&q) <= 0)
+				break;
+		}
+	}
+	if(f)
+		*--p = '-';
+	return fmtstrcpy(fp, p);
+}
+
+int
+Fconv(Fmt *fp)
+{
+	char buf[500];
+	Mpflt *fvp, fv;
+	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
+		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);
+		}
+		
+		// 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++;
+		}
+		if(fvp->val.neg)
+			fmtprint(fp, "-");
+		else if(fp->flags & FmtSign)
+			fmtprint(fp, "+");
+		return fmtprint(fp, "%.5fe+%d", d, exp);
+	}
+
+	if(sigfig(fvp) == 0) {
+		snprint(buf, sizeof(buf), "0p+0");
+		goto out;
+	}
+	fv = *fvp;
+
+	while(fv.val.a[0] == 0) {
+		mpshiftfix(&fv.val, -Mpscale);
+		fv.exp += Mpscale;
+	}
+	while((fv.val.a[0]&1) == 0) {
+		mpshiftfix(&fv.val, -1);
+		fv.exp += 1;
+	}
+
+	if(fv.exp >= 0) {
+		snprint(buf, sizeof(buf), "%#Bp+%d", &fv.val, fv.exp);
+		goto out;
+	}
+	snprint(buf, sizeof(buf), "%#Bp-%d", &fv.val, -fv.exp);
+
+out:
+	return fmtstrcpy(fp, buf);
+}
diff --git a/src/cmd/gc/mparith2.c b/src/cmd/gc/mparith2.c
new file mode 100644
index 0000000..fd9f591
--- /dev/null
+++ b/src/cmd/gc/mparith2.c
@@ -0,0 +1,716 @@
+// 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	"go.h"
+
+//
+// return the significant
+// words of the argument
+//
+static int
+mplen(Mpint *a)
+{
+	int i, n;
+	long *a1;
+
+	n = -1;
+	a1 = &a->a[0];
+	for(i=0; i<Mpprec; i++) {
+		if(*a1++ != 0)
+			n = i;
+	}
+	return n+1;
+}
+
+//
+// left shift mpint by one
+// ignores sign
+//
+static void
+mplsh(Mpint *a, int quiet)
+{
+	long *a1, x;
+	int i, c;
+
+	c = 0;
+	a1 = &a->a[0];
+	for(i=0; i<Mpprec; i++) {
+		x = (*a1 << 1) + c;
+		c = 0;
+		if(x >= Mpbase) {
+			x -= Mpbase;
+			c = 1;
+		}
+		*a1++ = x;
+	}
+	a->ovf = c;
+	if(a->ovf && !quiet)
+		yyerror("constant shift overflow");
+}
+
+//
+// left shift mpint by Mpscale
+// ignores sign
+//
+static void
+mplshw(Mpint *a, int quiet)
+{
+	long *a1;
+	int i;
+
+	a1 = &a->a[Mpprec-1];
+	if(*a1) {
+		a->ovf = 1;
+		if(!quiet)
+			yyerror("constant shift overflow");
+	}
+	for(i=1; i<Mpprec; i++) {
+		a1[0] = a1[-1];
+		a1--;
+	}
+	a1[0] = 0;
+}
+
+//
+// right shift mpint by one
+// ignores sign and overflow
+//
+static void
+mprsh(Mpint *a)
+{
+	long *a1, x, lo;
+	int i, c;
+
+	c = 0;
+	lo = a->a[0] & 1;
+	a1 = &a->a[Mpprec];
+	for(i=0; i<Mpprec; i++) {
+		x = *--a1;
+		*a1 = (x + c) >> 1;
+		c = 0;
+		if(x & 1)
+			c = Mpbase;
+	}
+	if(a->neg && lo != 0)
+		mpaddcfix(a, -1);
+}
+
+//
+// right shift mpint by Mpscale
+// ignores sign and overflow
+//
+static void
+mprshw(Mpint *a)
+{
+	long *a1, lo;
+	int i;
+
+	lo = a->a[0];
+	a1 = &a->a[0];
+	for(i=1; i<Mpprec; i++) {
+		a1[0] = a1[1];
+		a1++;
+	}
+	a1[0] = 0;
+	if(a->neg && lo != 0)
+		mpaddcfix(a, -1);
+}
+
+//
+// return the sign of (abs(a)-abs(b))
+//
+static int
+mpcmp(Mpint *a, Mpint *b)
+{
+	long x, *a1, *b1;
+	int i;
+
+	if(a->ovf || b->ovf) {
+		if(nsavederrors+nerrors == 0)
+			yyerror("ovf in cmp");
+		return 0;
+	}
+
+	a1 = &a->a[0] + Mpprec;
+	b1 = &b->a[0] + Mpprec;
+
+	for(i=0; i<Mpprec; i++) {
+		x = *--a1 - *--b1;
+		if(x > 0)
+			return +1;
+		if(x < 0)
+			return -1;
+	}
+	return 0;
+}
+
+//
+// negate a
+// ignore sign and ovf
+//
+static void
+mpneg(Mpint *a)
+{
+	long x, *a1;
+	int i, c;
+
+	a1 = &a->a[0];
+	c = 0;
+	for(i=0; i<Mpprec; i++) {
+		x = -*a1 -c;
+		c = 0;
+		if(x < 0) {
+			x += Mpbase;
+			c = 1;
+		}
+		*a1++ = x;
+	}
+}
+
+// shift left by s (or right by -s)
+void
+mpshiftfix(Mpint *a, int s)
+{
+	if(s >= 0) {
+		while(s >= Mpscale) {
+			mplshw(a, 0);
+			s -= Mpscale;
+		}
+		while(s > 0) {
+			mplsh(a, 0);
+			s--;
+		}
+	} else {
+		s = -s;
+		while(s >= Mpscale) {
+			mprshw(a);
+			s -= Mpscale;
+		}
+		while(s > 0) {
+			mprsh(a);
+			s--;
+		}
+	}
+}
+
+/// implements fix arihmetic
+
+void
+mpaddfixfix(Mpint *a, Mpint *b, int quiet)
+{
+	int i, c;
+	long x, *a1, *b1;
+
+	if(a->ovf || b->ovf) {
+		if(nsavederrors+nerrors == 0)
+			yyerror("ovf in mpaddxx");
+		a->ovf = 1;
+		return;
+	}
+
+	c = 0;
+	a1 = &a->a[0];
+	b1 = &b->a[0];
+	if(a->neg != b->neg)
+		goto sub;
+
+	// perform a+b
+	for(i=0; i<Mpprec; i++) {
+		x = *a1 + *b1++ + c;
+		c = 0;
+		if(x >= Mpbase) {
+			x -= Mpbase;
+			c = 1;
+		}
+		*a1++ = x;
+	}
+	a->ovf = c;
+	if(a->ovf && !quiet)
+		yyerror("constant addition overflow");
+
+	return;
+
+sub:
+	// perform a-b
+	switch(mpcmp(a, b)) {
+	case 0:
+		mpmovecfix(a, 0);
+		break;
+
+	case 1:
+		for(i=0; i<Mpprec; i++) {
+			x = *a1 - *b1++ - c;
+			c = 0;
+			if(x < 0) {
+				x += Mpbase;
+				c = 1;
+			}
+			*a1++ = x;
+		}
+		break;
+
+	case -1:
+		a->neg ^= 1;
+		for(i=0; i<Mpprec; i++) {
+			x = *b1++ - *a1 - c;
+			c = 0;
+			if(x < 0) {
+				x += Mpbase;
+				c = 1;
+			}
+			*a1++ = x;
+		}
+		break;
+	}
+}
+
+void
+mpmulfixfix(Mpint *a, Mpint *b)
+{
+
+	int i, j, na, nb;
+	long *a1, x;
+	Mpint s, q;
+
+	if(a->ovf || b->ovf) {
+		if(nsavederrors+nerrors == 0)
+			yyerror("ovf in mpmulfixfix");
+		a->ovf = 1;
+		return;
+	}
+
+	// pick the smaller
+	// to test for bits
+	na = mplen(a);
+	nb = mplen(b);
+	if(na > nb) {
+		mpmovefixfix(&s, a);
+		a1 = &b->a[0];
+		na = nb;
+	} else {
+		mpmovefixfix(&s, b);
+		a1 = &a->a[0];
+	}
+	s.neg = 0;
+
+	mpmovecfix(&q, 0);
+	for(i=0; i<na; i++) {
+		x = *a1++;
+		for(j=0; j<Mpscale; j++) {
+			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)
+		yyerror("constant multiplication overflow");
+}
+
+void
+mpmulfract(Mpint *a, Mpint *b)
+{
+
+	int i, j;
+	long *a1, x;
+	Mpint s, q;
+
+	if(a->ovf || b->ovf) {
+		if(nsavederrors+nerrors == 0)
+			yyerror("ovf in mpmulflt");
+		a->ovf = 1;
+		return;
+	}
+
+	mpmovefixfix(&s, b);
+	a1 = &a->a[Mpprec];
+	s.neg = 0;
+	mpmovecfix(&q, 0);
+
+	x = *--a1;
+	if(x != 0)
+		yyerror("mpmulfract not normal");
+
+	for(i=0; i<Mpprec-1; i++) {
+		x = *--a1;
+		if(x == 0) {
+			mprshw(&s);
+			continue;
+		}
+		for(j=0; j<Mpscale; j++) {
+			x <<= 1;
+			if(x & Mpbase)
+				mpaddfixfix(&q, &s, 1);
+			mprsh(&s);
+		}
+	}
+
+	q.neg = a->neg ^ b->neg;
+	mpmovefixfix(a, &q);
+	if(a->ovf)
+		yyerror("constant multiplication overflow");
+}
+
+void
+mporfixfix(Mpint *a, Mpint *b)
+{
+	int i;
+	long x, *a1, *b1;
+
+	x = 0;
+	if(a->ovf || b->ovf) {
+		if(nsavederrors+nerrors == 0)
+			yyerror("ovf in mporfixfix");
+		mpmovecfix(a, 0);
+		a->ovf = 1;
+		return;
+	}
+	if(a->neg) {
+		a->neg = 0;
+		mpneg(a);
+	}
+	if(b->neg)
+		mpneg(b);
+
+	a1 = &a->a[0];
+	b1 = &b->a[0];
+	for(i=0; i<Mpprec; i++) {
+		x = *a1 | *b1++;
+		*a1++ = x;
+	}
+
+	if(b->neg)
+		mpneg(b);
+	if(x & Mpsign) {
+		a->neg = 1;
+		mpneg(a);
+	}
+}
+
+void
+mpandfixfix(Mpint *a, Mpint *b)
+{
+	int i;
+	long x, *a1, *b1;
+
+	x = 0;
+	if(a->ovf || b->ovf) {
+		if(nsavederrors+nerrors == 0)
+			yyerror("ovf in mpandfixfix");
+		mpmovecfix(a, 0);
+		a->ovf = 1;
+		return;
+	}
+	if(a->neg) {
+		a->neg = 0;
+		mpneg(a);
+	}
+	if(b->neg)
+		mpneg(b);
+
+	a1 = &a->a[0];
+	b1 = &b->a[0];
+	for(i=0; i<Mpprec; i++) {
+		x = *a1 & *b1++;
+		*a1++ = x;
+	}
+
+	if(b->neg)
+		mpneg(b);
+	if(x & Mpsign) {
+		a->neg = 1;
+		mpneg(a);
+	}
+}
+
+void
+mpandnotfixfix(Mpint *a, Mpint *b)
+{
+	int i;
+	long x, *a1, *b1;
+
+	x = 0;
+	if(a->ovf || b->ovf) {
+		if(nsavederrors+nerrors == 0)
+			yyerror("ovf in mpandnotfixfix");
+		mpmovecfix(a, 0);
+		a->ovf = 1;
+		return;
+	}
+	if(a->neg) {
+		a->neg = 0;
+		mpneg(a);
+	}
+	if(b->neg)
+		mpneg(b);
+
+	a1 = &a->a[0];
+	b1 = &b->a[0];
+	for(i=0; i<Mpprec; i++) {
+		x = *a1 & ~*b1++;
+		*a1++ = x;
+	}
+
+	if(b->neg)
+		mpneg(b);
+	if(x & Mpsign) {
+		a->neg = 1;
+		mpneg(a);
+	}
+}
+
+void
+mpxorfixfix(Mpint *a, Mpint *b)
+{
+	int i;
+	long x, *a1, *b1;
+
+	x = 0;
+	if(a->ovf || b->ovf) {
+		if(nsavederrors+nerrors == 0)
+			yyerror("ovf in mporfixfix");
+		mpmovecfix(a, 0);
+		a->ovf = 1;
+		return;
+	}
+	if(a->neg) {
+		a->neg = 0;
+		mpneg(a);
+	}
+	if(b->neg)
+		mpneg(b);
+
+	a1 = &a->a[0];
+	b1 = &b->a[0];
+	for(i=0; i<Mpprec; i++) {
+		x = *a1 ^ *b1++;
+		*a1++ = x;
+	}
+
+	if(b->neg)
+		mpneg(b);
+	if(x & Mpsign) {
+		a->neg = 1;
+		mpneg(a);
+	}
+}
+
+void
+mplshfixfix(Mpint *a, Mpint *b)
+{
+	vlong s;
+
+	if(a->ovf || b->ovf) {
+		if(nsavederrors+nerrors == 0)
+			yyerror("ovf in mporfixfix");
+		mpmovecfix(a, 0);
+		a->ovf = 1;
+		return;
+	}
+	s = mpgetfix(b);
+	if(s < 0 || s >= Mpprec*Mpscale) {
+		yyerror("stupid shift: %lld", s);
+		mpmovecfix(a, 0);
+		return;
+	}
+
+	mpshiftfix(a, s);
+}
+
+void
+mprshfixfix(Mpint *a, Mpint *b)
+{
+	vlong s;
+
+	if(a->ovf || b->ovf) {
+		if(nsavederrors+nerrors == 0)
+			yyerror("ovf in mprshfixfix");
+		mpmovecfix(a, 0);
+		a->ovf = 1;
+		return;
+	}
+	s = mpgetfix(b);
+	if(s < 0 || s >= Mpprec*Mpscale) {
+		yyerror("stupid shift: %lld", s);
+		if(a->neg)
+			mpmovecfix(a, -1);
+		else
+			mpmovecfix(a, 0);
+		return;
+	}
+
+	mpshiftfix(a, -s);
+}
+
+void
+mpnegfix(Mpint *a)
+{
+	a->neg ^= 1;
+}
+
+vlong
+mpgetfix(Mpint *a)
+{
+	vlong v;
+
+	if(a->ovf) {
+		if(nsavederrors+nerrors == 0)
+			yyerror("constant overflow");
+		return 0;
+	}
+
+	v = (uvlong)a->a[0];
+	v |= (uvlong)a->a[1] << Mpscale;
+	v |= (uvlong)a->a[2] << (Mpscale+Mpscale);
+	if(a->neg)
+		v = -(uvlong)v;
+	return v;
+}
+
+void
+mpmovecfix(Mpint *a, vlong c)
+{
+	int i;
+	long *a1;
+	vlong x;
+
+	a->neg = 0;
+	a->ovf = 0;
+
+	x = c;
+	if(x < 0) {
+		a->neg = 1;
+		x = -(uvlong)x;
+	}
+
+	a1 = &a->a[0];
+	for(i=0; i<Mpprec; i++) {
+		*a1++ = x&Mpmask;
+		x >>= Mpscale;
+	}
+}
+
+void
+mpdivmodfixfix(Mpint *q, Mpint *r, Mpint *n, Mpint *d)
+{
+	int i, ns, ds;
+
+	ns = n->neg;
+	ds = d->neg;
+	n->neg = 0;
+	d->neg = 0;
+
+	mpmovefixfix(r, n);
+	mpmovecfix(q, 0);
+
+	// shift denominator until it
+	// is larger than numerator
+	for(i=0; i<Mpprec*Mpscale; i++) {
+		if(mpcmp(d, r) > 0)
+			break;
+		mplsh(d, 1);
+	}
+
+	// if it never happens
+	// denominator is probably zero
+	if(i >= Mpprec*Mpscale) {
+		q->ovf = 1;
+		r->ovf = 1;
+		n->neg = ns;
+		d->neg = ds;
+		yyerror("constant division overflow");
+		return;
+	}
+
+	// shift denominator back creating
+	// quotient a bit at a time
+	// when done the remaining numerator
+	// will be the remainder
+	for(; i>0; i--) {
+		mplsh(q, 1);
+		mprsh(d);
+		if(mpcmp(d, r) <= 0) {
+			mpaddcfix(q, 1);
+			mpsubfixfix(r, d);
+		}
+	}
+
+	n->neg = ns;
+	d->neg = ds;
+	r->neg = ns;
+	q->neg = ns^ds;
+}
+
+static int
+mpiszero(Mpint *a)
+{
+	long *a1;
+	int i;
+	a1 = &a->a[0] + Mpprec;
+	for(i=0; i<Mpprec; i++) {
+		if(*--a1 != 0)
+			return 0;
+	}
+	return 1;
+}
+
+void
+mpdivfract(Mpint *a, Mpint *b)
+{
+	Mpint n, d;
+	int i, j, neg;
+	long *a1, x;
+
+	mpmovefixfix(&n, a);	// numerator
+	mpmovefixfix(&d, b);	// denominator
+	a1 = &a->a[Mpprec];	// quotient
+
+	neg = n.neg ^ d.neg;
+	n.neg = 0;
+	d.neg = 0;
+	for(i=0; i<Mpprec; i++) {
+		x = 0;
+		for(j=0; j<Mpscale; j++) {
+			x <<= 1;
+			if(mpcmp(&d, &n) <= 0) {
+				if(!mpiszero(&d))
+					x |= 1;
+				mpsubfixfix(&n, &d);
+			}
+			mprsh(&d);
+		}
+		*--a1 = x;
+	}
+	a->neg = neg;
+}
+
+int
+mptestfix(Mpint *a)
+{
+	Mpint b;
+	int r;
+
+	mpmovecfix(&b, 0);
+	r = mpcmp(a, &b);
+	if(a->neg) {
+		if(r > 0)
+			return -1;
+		if(r < 0)
+			return +1;
+	}
+	return r;
+}
diff --git a/src/cmd/gc/mparith3.c b/src/cmd/gc/mparith3.c
new file mode 100644
index 0000000..6afd75c
--- /dev/null
+++ b/src/cmd/gc/mparith3.c
@@ -0,0 +1,346 @@
+// 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	"go.h"
+
+/*
+ * returns the leading non-zero
+ * word of the number
+ */
+int
+sigfig(Mpflt *a)
+{
+	int i;
+
+	for(i=Mpprec-1; i>=0; i--)
+		if(a->val.a[i] != 0)
+			break;
+//print("sigfig %d %d\n", i-z+1, z);
+	return i+1;
+}
+
+/*
+ * sets the exponent.
+ * a too large exponent is an error.
+ * a too small exponent rounds the number to zero.
+ */
+void
+mpsetexp(Mpflt *a, int exp) {
+	if((short)exp != exp) {
+		if(exp > 0) {
+			yyerror("float constant is too large");
+			a->exp = 0x7fff;
+		}
+		else {
+			mpmovecflt(a, 0);
+		}
+	}
+	else {
+		a->exp = exp;
+	}
+}
+
+/*
+ * shifts the leading non-zero
+ * word of the number to Mpnorm
+ */
+void
+mpnorm(Mpflt *a)
+{
+	int s, os;
+	long x;
+
+	os = sigfig(a);
+	if(os == 0) {
+		// zero
+		a->exp = 0;
+		a->val.neg = 0;
+		return;
+	}
+
+	// this will normalize to the nearest word
+	x = a->val.a[os-1];
+	s = (Mpnorm-os) * Mpscale;
+
+	// further normalize to the nearest bit
+	for(;;) {
+		x <<= 1;
+		if(x & Mpbase)
+			break;
+		s++;
+		if(x == 0) {
+			// this error comes from trying to
+			// convert an Inf or something
+			// where the initial x=0x80000000
+			s = (Mpnorm-os) * Mpscale;
+			break;
+		}
+	}
+
+	mpshiftfix(&a->val, s);
+	mpsetexp(a, a->exp-s);
+}
+
+/// implements float arihmetic
+
+void
+mpaddfltflt(Mpflt *a, Mpflt *b)
+{
+	int sa, sb, s;
+	Mpflt c;
+
+	if(Mpdebug)
+		print("\n%F + %F", a, b);
+
+	sa = sigfig(a);
+	if(sa == 0) {
+		mpmovefltflt(a, b);
+		goto out;
+	}
+
+	sb = sigfig(b);
+	if(sb == 0)
+		goto out;
+
+	s = a->exp - b->exp;
+	if(s > 0) {
+		// a is larger, shift b right
+		mpmovefltflt(&c, b);
+		mpshiftfix(&c.val, -s);
+		mpaddfixfix(&a->val, &c.val, 0);
+		goto out;
+	}
+	if(s < 0) {
+		// b is larger, shift a right
+		mpshiftfix(&a->val, s);
+		mpsetexp(a, a->exp-s);
+		mpaddfixfix(&a->val, &b->val, 0);
+		goto out;
+	}
+	mpaddfixfix(&a->val, &b->val, 0);
+
+out:
+	mpnorm(a);
+	if(Mpdebug)
+		print(" = %F\n\n", a);
+}
+
+void
+mpmulfltflt(Mpflt *a, Mpflt *b)
+{
+	int sa, sb;
+
+	if(Mpdebug)
+		print("%F\n * %F\n", a, b);
+
+	sa = sigfig(a);
+	if(sa == 0) {
+		// zero
+		a->exp = 0;
+		a->val.neg = 0;
+		return;
+	}
+
+	sb = sigfig(b);
+	if(sb == 0) {
+		// zero
+		mpmovefltflt(a, b);
+		return;
+	}
+
+	mpmulfract(&a->val, &b->val);
+	mpsetexp(a, (a->exp + b->exp) + Mpscale*Mpprec - Mpscale - 1);
+
+	mpnorm(a);
+	if(Mpdebug)
+		print(" = %F\n\n", a);
+}
+
+void
+mpdivfltflt(Mpflt *a, Mpflt *b)
+{
+	int sa, sb;
+	Mpflt c;
+
+	if(Mpdebug)
+		print("%F\n / %F\n", a, b);
+
+	sb = sigfig(b);
+	if(sb == 0) {
+		// zero and ovfl
+		a->exp = 0;
+		a->val.neg = 0;
+		a->val.ovf = 1;
+		yyerror("constant division by zero");
+		return;
+	}
+
+	sa = sigfig(a);
+	if(sa == 0) {
+		// zero
+		a->exp = 0;
+		a->val.neg = 0;
+		return;
+	}
+
+	// adjust b to top
+	mpmovefltflt(&c, b);
+	mpshiftfix(&c.val, Mpscale);
+
+	// divide
+	mpdivfract(&a->val, &c.val);
+	mpsetexp(a, (a->exp-c.exp) - Mpscale*(Mpprec-1) + 1);
+
+	mpnorm(a);
+	if(Mpdebug)
+		print(" = %F\n\n", a);
+}
+
+static double
+mpgetfltN(Mpflt *a, int prec, int bias)
+{
+	int s, i, e, minexp;
+	uvlong v;
+	double f;
+
+	if(a->val.ovf && nsavederrors+nerrors == 0)
+		yyerror("mpgetflt ovf");
+
+	s = sigfig(a);
+	if(s == 0)
+		return 0;
+
+	if(s != Mpnorm) {
+		yyerror("mpgetflt norm");
+		mpnorm(a);
+	}
+
+	while((a->val.a[Mpnorm-1] & Mpsign) == 0) {
+		mpshiftfix(&a->val, 1);
+		mpsetexp(a, a->exp-1);	// can set 'a' to zero
+		s = sigfig(a);
+		if(s == 0)
+			return 0;
+	}
+
+	// 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;
+	}
+	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 - prec;
+	minexp = bias+1-prec+1;
+	if(e < minexp) {
+		s = minexp - e;
+		if(s > prec+1)
+			s = prec+1;
+		if((v & ((1ULL<<s)-1)) != 0)
+			v |= 1ULL<<s;
+		v >>= s;
+		e = minexp;
+	}
+	
+	// round to even
+	v |= (v&4)>>2;
+	v += v&1;
+	v >>= 2;
+
+	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)
+{
+	int i;
+	double f;
+	long l;
+
+	if(Mpdebug)
+		print("\nconst %g", c);
+	mpmovecfix(&a->val, 0);
+	a->exp = 0;
+	if(c == 0)
+		goto out;
+	if(c < 0) {
+		a->val.neg = 1;
+		c = -c;
+	}
+
+	f = frexp(c, &i);
+	a->exp = i;
+
+	for(i=0; i<10; i++) {
+		f = f*Mpbase;
+		l = floor(f);
+		f = f - l;
+		a->exp -= Mpscale;
+		a->val.a[0] = l;
+		if(f == 0)
+			break;
+		mpshiftfix(&a->val, Mpscale);
+	}
+
+out:
+	mpnorm(a);
+	if(Mpdebug)
+		print(" = %F\n", a);
+}
+
+void
+mpnegflt(Mpflt *a)
+{
+	a->val.neg ^= 1;
+}
+
+int
+mptestflt(Mpflt *a)
+{
+	int s;
+
+	if(Mpdebug)
+		print("\n%F?", a);
+	s = sigfig(a);
+	if(s != 0) {
+		s = +1;
+		if(a->val.neg)
+			s = -1;
+	}
+	if(Mpdebug)
+		print(" = %d\n", s);
+	return s;
+}
diff --git a/src/cmd/gc/obj.c b/src/cmd/gc/obj.c
new file mode 100644
index 0000000..b752a13
--- /dev/null
+++ b/src/cmd/gc/obj.c
@@ -0,0 +1,284 @@
+// 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 "go.h"
+#include "../ld/textflag.h"
+
+/*
+ * architecture-independent object file output
+ */
+
+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) {
+		flusherrors();
+		print("can't create %s: %r\n", outfile);
+		errorexit();
+	}
+
+	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();
+	
+	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());
+	}
+
+	Bprint(bout, "\n!\n");
+
+	externs = nil;
+	if(externdcl != nil)
+		externs = externdcl->end;
+
+	dumpglobls();
+	dumptypestructs();
+
+	// Dump extra globals.
+	tmp = externdcl;
+	if(externs != nil)
+		externdcl = externs->next;
+	dumpglobls();
+	externdcl = tmp;
+
+	zero = pkglookup("zerovalue", runtimepkg);
+	ggloblsym(zero, zerosize, DUPOK|RODATA);
+
+	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);
+}
+
+static void
+dumpglobls(void)
+{
+	Node *n;
+	NodeList *l;
+
+	// add globals
+	for(l=externdcl; l; l=l->next) {
+		n = l->n;
+		if(n->op != ONAME)
+			continue;
+
+		if(n->type == T)
+			fatal("external %N nil type\n", n);
+		if(n->class == PFUNC)
+			continue;
+		if(n->sym->pkg != localpkg)
+			continue;
+		dowidth(n->type);
+
+		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, DUPOK|RODATA);
+	}
+	
+	// Do not reprocess funcsyms on next dumpglobls call.
+	funcsyms = nil;
+}
+
+void
+Bputname(Biobuf *b, LSym *s)
+{
+	Bwrite(b, s->name, strlen(s->name)+1);
+}
+
+LSym*
+linksym(Sym *s)
+{
+	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;	
+}
+
+int
+duintxx(Sym *s, int off, uint64 v, int wid)
+{
+	// 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
+duint8(Sym *s, int off, uint8 v)
+{
+	return duintxx(s, off, v, 1);
+}
+
+int
+duint16(Sym *s, int off, uint16 v)
+{
+	return duintxx(s, off, v, 2);
+}
+
+int
+duint32(Sym *s, int off, uint32 v)
+{
+	return duintxx(s, off, v, 4);
+}
+
+int
+duint64(Sym *s, int off, uint64 v)
+{
+	return duintxx(s, off, v, 8);
+}
+
+int
+duintptr(Sym *s, int off, uint64 v)
+{
+	return duintxx(s, off, v, widthptr);
+}
+
+Sym*
+stringsym(char *s, int len)
+{
+	static int gen;
+	Sym *sym;
+	int off, n, m;
+	struct {
+		Strlit lit;
+		char buf[110];
+	} tmp;
+	Pkg *pkg;
+
+	if(len > 100) {
+		// huge strings are made static to avoid long names
+		snprint(namebuf, sizeof(namebuf), ".gostring.%d", ++gen);
+		pkg = localpkg;
+	} else {
+		// small strings get named by their contents,
+		// so that multiple modules using the same string
+		// can share it.
+		tmp.lit.len = len;
+		memmove(tmp.lit.s, s, len);
+		tmp.lit.s[len] = '\0';
+		snprint(namebuf, sizeof(namebuf), "\"%Z\"", &tmp.lit);
+		pkg = gostringpkg;
+	}
+	sym = pkglookup(namebuf, pkg);
+	
+	// SymUniq flag indicates that data is generated already
+	if(sym->flags & SymUniq)
+		return sym;
+	sym->flags |= SymUniq;
+	sym->def = newname(sym);
+
+	off = 0;
+	
+	// string header
+	off = dsymptr(sym, off, sym, widthptr+widthint);
+	off = duintxx(sym, off, len, widthint);
+	
+	// string data
+	for(n=0; n<len; n+=m) {
+		m = 8;
+		if(m > len-n)
+			m = len-n;
+		off = dsname(sym, off, s+n, m);
+	}
+	off = duint8(sym, off, 0);  // terminating NUL for runtime
+	off = (off+widthptr-1)&~(widthptr-1);  // round to pointer alignment
+	ggloblsym(sym, off, DUPOK|RODATA);
+
+	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, NOPTR);
+	
+	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
new file mode 100644
index 0000000..76820fd
--- /dev/null
+++ b/src/cmd/gc/order.c
@@ -0,0 +1,1101 @@
+// 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.
+
+// 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"
+
+// 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**, 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
+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, order);
+}
+
+// Orderblock orders the block of statements *l onto a new list,
+// and then replaces *l with that list.
+static void
+orderblock(NodeList **l)
+{
+	Order order;
+	NodeList *mark;
+	
+	memset(&order, 0, sizeof order);
+	mark = marktemp(&order);
+	orderstmtlist(*l, &order);
+	cleantemp(mark, &order);
+	*l = order.out;
+}
+
+// Orderexprinplace orders the side effects in *np and
+// leaves them as the init list of the final *np.
+static void
+orderexprinplace(Node **np, Order *outer)
+{
+	Node *n;
+	NodeList **lp;
+	Order order;
+	
+	n = *np;
+	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;
+}
+
+// Orderstmtinplace orders the side effects of the single statement *np
+// and replaces it with the resulting statement list.
+void
+orderstmtinplace(Node **np)
+{
+	Node *n;
+	Order order;
+	NodeList *mark;
+	
+	n = *np;
+	memset(&order, 0, sizeof order);
+	mark = marktemp(&order);
+	orderstmt(n, &order);
+	cleantemp(mark, &order);
+	*np = liststmt(order.out);
+}
+
+// Orderinit moves n's init list to order->out.
+static void
+orderinit(Node *n, Order *order)
+{
+	orderstmtlist(n->ninit, order);
+	n->ninit = nil;
+}
+
+// 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)
+{
+	Node *n;
+	
+	// one arg only
+	if(l == nil || l->next != nil)
+		return 0;
+	n = l->n;
+	
+	// must be call
+	switch(n->op) {
+	default:
+		return 0;
+	case OCALLFUNC:
+	case OCALLMETH:
+	case OCALLINTER:
+		break;
+	}
+	
+	// call must return multiple values
+	return n->left->type->outtuple > 1;
+}
+
+// Copyret emits t1, t2, ... = n, where n is a function call,
+// and then returns the list t1, t2, ....
+static NodeList*
+copyret(Node *n, Order *order)
+{
+	Type *t;
+	Node *tmp, *as;
+	NodeList *l1, *l2;
+	Iter tl;
+	
+	if(n->type->etype != TSTRUCT || !n->type->funarg)
+		fatal("copyret %T %d", n->type, n->left->type->outtuple);
+
+	l1 = nil;
+	l2 = nil;
+	for(t=structfirst(&tl, &n->type); t; t=structnext(&tl)) {
+		tmp = temp(t->type);
+		l1 = list(l1, tmp);
+		l2 = list(l2, tmp);
+	}
+	
+	as = nod(OAS2, N, N);
+	as->list = l1;
+	as->rlist = list1(n);
+	typecheck(&as, Etop);
+	orderstmt(as, order);
+
+	return l2;
+}
+
+// Ordercallargs orders the list of call arguments *l.
+static void
+ordercallargs(NodeList **l, Order *order)
+{
+	if(ismulticall(*l)) {
+		// return f() where f() is multiple values.
+		*l = copyret((*l)->n, order);
+	} else {
+		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, Order *order)
+{
+	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.
+//
+// Ordermapassign also inserts these temporaries if needed for
+// calling writebarrierfat with a pointer to n->right.
+static void
+ordermapassign(Node *n, Order *order)
+{
+	Node *m, *a;
+	NodeList *l;
+	NodeList *post;
+
+	switch(n->op) {
+	default:
+		fatal("ordermapassign %O", n->op);
+
+	case OAS:
+		order->out = list(order->out, n);
+		// We call writebarrierfat only for values > 4 pointers long. See walk.c.
+		if((n->left->op == OINDEXMAP || (needwritebarrier(n->left, n->right) && n->left->type->width > 4*widthptr)) && !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, 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 OCLOSE:
+	case OCOPY:
+	case OPRINT:
+	case OPRINTN:
+	case ORECOVER:
+	case ORECV:
+		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.
+		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.
+		// 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));
+		if(!isblank(n->list->next->n))
+			tmp2 = ordertemp(n->list->next->n->type, order, 0);
+		else
+			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, order);
+		break;
+
+	case OBREAK:
+	case OCONTINUE:
+	case ODCL:
+	case ODCLCONST:
+	case ODCLTYPE:
+	case OFALL:
+	case OXFALL:
+	case OGOTO:
+	case OLABEL:
+	case ORETJMP:
+		// Special: n->left is not an expression; save as is.
+		order->out = list(order->out, n);
+		break;
+
+	case OCALLFUNC:
+	case OCALLINTER:
+	case OCALLMETH:
+		// Special: handle call arguments.
+		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.
+		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:
+		// 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);
+		orderstmtinplace(&n->nincr);
+		order->out = list(order->out, n);
+		cleantemp(t, order);
+		break;
+		
+	case OIF:
+		// 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);
+		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:
+		// 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, order);
+		orderblock(&n->nbody);
+		order->out = list(order->out, n);
+		cleantemp(t, order);
+		break;
+
+	case ORETURN:
+		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.
+		// Doubly special: evaluation order for select is stricter
+		// than ordinary expressions. Even something like p.c
+		// has to be hoisted into a temporary, so that it cannot be
+		// reordered after the channel evaluation for a different
+		// case (if p were nil, then the timing of the fault would
+		// give this away).
+		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;
+			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);
+					if(r->right->left->op != ONAME)
+						r->right->left = ordercopyexpr(r->right->left, r->right->left->type, order, 0);
+
+					// 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);
+		}
+		// 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:
+		// 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);
+			orderexprlistinplace(l->n->list, order);
+			orderblock(&l->n->nbody);
+		}
+		order->out = list(order->out, n);
+		cleantemp(t, order);
+		break;
+	}
+	
+	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
+orderexprlistinplace(NodeList *l, Order *order)
+{
+	for(; l; l=l->next)
+		orderexprinplace(&l->n, order);
+}
+
+// Orderexpr orders a single expression, appending side
+// effects to order->out as needed.
+static void
+orderexpr(Node **np, Order *order)
+{
+	Node *n;
+	NodeList *mark, *l;
+	Type *t;
+	int lno;
+
+	n = *np;
+	if(n == N)
+		return;
+
+	lno = setlineno(n);
+	orderinit(n, order);
+
+	switch(n->op) {
+	default:
+		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:
+		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 OAPPEND:
+	case OCALLFUNC:
+	case OCALLINTER:
+	case OCALLMETH:
+	case OCAP:
+	case OCOMPLEX:
+	case OCOPY:
+	case OIMAG:
+	case OLEN:
+	case OMAKECHAN:
+	case OMAKEMAP:
+	case OMAKESLICE:
+	case ONEW:
+	case OREAL:
+	case ORECOVER:
+		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:
+		orderexpr(&n->left, order);
+		n = ordercopyexpr(n, n->type, order, 1);
+		break;
+
+	case OEQ:
+	case ONE:
+		orderexpr(&n->left, order);
+		orderexpr(&n->right, order);
+		t = n->left->type;
+		if(t->etype == TSTRUCT || isfixedarray(t)) {
+			// for complex comparisons, we need both args to be
+			// addressable so we can pass them to the runtime.
+			orderaddrtemp(&n->left, order);
+			orderaddrtemp(&n->right, order);
+		}
+		break;
+	}
+	
+	lineno = lno;
+
+	*np = n;
+}
diff --git a/src/cmd/gc/pgen.c b/src/cmd/gc/pgen.c
new file mode 100644
index 0000000..39028e3
--- /dev/null
+++ b/src/cmd/gc/pgen.c
@@ -0,0 +1,539 @@
+// 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.
+
+// "Portable" code generation.
+// Compiled separately for 5g, 6g, and 8g, so allowed to use gg.h, opt.h.
+// Must code to the intersection of the three back ends.
+
+#include	<u.h>
+#include	<libc.h>
+#include	"md5.h"
+#include	"gg.h"
+#include	"opt.h"
+#include	"../../runtime/funcdata.h"
+
+static void allocauto(Prog* p);
+static void emitptrargsmap(void);
+
+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)
+{
+	Plist *pl;
+	Node nod1, *n;
+	Prog *ptxt, *p;
+	int32 lno;
+	Type *t;
+	Iter save;
+	vlong oldstksize;
+	NodeList *l;
+	Sym *gcargs;
+	Sym *gclocals;
+
+	if(newproc == N) {
+		newproc = sysfunc("newproc");
+		deferproc = sysfunc("deferproc");
+		deferreturn = sysfunc("deferreturn");
+		panicindex = sysfunc("panicindex");
+		panicslice = sysfunc("panicslice");
+		throwreturn = sysfunc("throwreturn");
+	}
+
+	lno = setlineno(fn);
+
+	curfn = fn;
+	dowidth(curfn->type);
+
+	if(fn->nbody == nil) {
+		if(pure_go || strncmp(fn->nname->sym->name, "init·", 6) == 0) {
+			yyerror("missing function body", fn);
+			goto ret;
+		}
+		if(debug['A'])
+			goto ret;
+		emitptrargsmap();
+		goto ret;
+	}
+
+	saveerrors();
+
+	// set up domain for labels
+	clearlabels();
+
+	if(curfn->type->outnamed) {
+		// add clearing of the output parameters
+		t = structfirst(&save, getoutarg(curfn->type));
+		while(t != T) {
+			if(t->nname != N) {
+				n = nod(OAS, t->nname, N);
+				typecheck(&n, Etop);
+				curfn->nbody = concat(list1(n), curfn->nbody);
+			}
+			t = structnext(&save);
+		}
+	}
+	
+	order(curfn);
+	if(nerrors != 0)
+		goto ret;
+	
+	hasdefer = 0;
+	walk(curfn);
+	if(nerrors != 0)
+		goto ret;
+	if(flag_race)
+		racewalk(curfn);
+	if(nerrors != 0)
+		goto ret;
+
+	continpc = P;
+	breakpc = P;
+
+	pl = newplist();
+	pl->name = linksym(curfn->nname->sym);
+
+	setlineno(curfn);
+
+	nodconst(&nod1, types[TINT32], 0);
+	ptxt = gins(ATEXT, isblank(curfn->nname) ? N : curfn->nname, &nod1);
+	if(fn->dupok)
+		ptxt->TEXTFLAG |= DUPOK;
+	if(fn->wrapper)
+		ptxt->TEXTFLAG |= WRAPPER;
+	if(fn->needctxt)
+		ptxt->TEXTFLAG |= NEEDCTXT;
+	if(fn->nosplit)
+		ptxt->TEXTFLAG |= NOSPLIT;
+
+	// Clumsy but important.
+	// See test/recover.go for test cases and src/reflect/value.go
+	// for the actual functions being considered.
+	if(myimportpath != nil && strcmp(myimportpath, "reflect") == 0) {
+		if(strcmp(curfn->nname->sym->name, "callReflect") == 0 || strcmp(curfn->nname->sym->name, "callMethod") == 0)
+			ptxt->TEXTFLAG |= WRAPPER;
+	}	
+	
+	afunclit(&ptxt->from, curfn->nname);
+
+	ginit();
+
+	gcargs = makefuncdatasym("gcargs·%d", FUNCDATA_ArgsPointerMaps);
+	gclocals = makefuncdatasym("gclocals·%d", FUNCDATA_LocalsPointerMaps);
+
+	for(t=curfn->paramfld; t; t=t->down)
+		gtrack(tracksym(t->type));
+
+	for(l=fn->dcl; l; l=l->next) {
+		n = l->n;
+		if(n->op != ONAME) // might be OTYPE or OLITERAL
+			continue;
+		switch(n->class) {
+		case PAUTO:
+		case PPARAM:
+		case PPARAMOUT:
+			nodconst(&nod1, types[TUINTPTR], l->n->type->width);
+			p = gins(ATYPE, l->n, &nod1);
+			p->from.gotype = linksym(ngotype(l->n));
+			break;
+		}
+	}
+
+	genlist(curfn->enter);
+	genlist(curfn->nbody);
+	gclean();
+	checklabels();
+	if(nerrors != 0)
+		goto ret;
+	if(curfn->endlineno)
+		lineno = curfn->endlineno;
+
+	if(curfn->type->outtuple != 0)
+		ginscall(throwreturn, 0);
+
+	ginit();
+	// 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;
+
+	pc->as = ARET;	// overwrite AEND
+	pc->lineno = lineno;
+
+	fixjmp(ptxt);
+	if(!debug['N'] || debug['R'] || debug['P']) {
+		regopt(ptxt);
+		nilopt(ptxt);
+	}
+	expandchecks(ptxt);
+
+	oldstksize = stksize;
+	allocauto(ptxt);
+
+	if(0)
+		print("allocauto: %lld to %lld\n", oldstksize, (vlong)stksize);
+	USED(oldstksize);
+
+	setlineno(curfn);
+	if((int64)stksize+maxarg > (1ULL<<31)) {
+		yyerror("stack frame too large (>2GB)");
+		goto ret;
+	}
+
+	// Emit garbage collection symbols.
+	liveness(curfn, ptxt, gcargs, gclocals);
+	gcsymdup(gcargs);
+	gcsymdup(gclocals);
+
+	defframe(ptxt);
+
+	if(0)
+		frame(0);
+
+	// Remove leftover instrumentation from the instruction stream.
+	removevardef(ptxt);
+ret:
+	lineno = lno;
+}
+
+static void
+emitptrargsmap(void)
+{
+	int nptr, nbitmap, j, off;
+	vlong xoffset;
+	Bvec *bv;
+	Sym *sym;
+	
+	sym = lookup(smprint("%s.args_stackmap", curfn->nname->sym->name));
+
+	nptr = curfn->type->argwid / widthptr;
+	bv = bvalloc(nptr*2);
+	nbitmap = 1;
+	if(curfn->type->outtuple > 0)
+		nbitmap = 2;
+	off = duint32(sym, 0, nbitmap);
+	off = duint32(sym, off, bv->n);
+	if(curfn->type->thistuple > 0) {
+		xoffset = 0;
+		twobitwalktype1(getthisx(curfn->type), &xoffset, bv);
+	}
+	if(curfn->type->intuple > 0) {
+		xoffset = 0;
+		twobitwalktype1(getinargx(curfn->type), &xoffset, bv);
+	}
+	for(j = 0; j < bv->n; j += 32)
+		off = duint32(sym, off, bv->b[j/32]);
+	if(curfn->type->outtuple > 0) {
+		xoffset = 0;
+		twobitwalktype1(getoutargx(curfn->type), &xoffset, bv);
+		for(j = 0; j < bv->n; j += 32)
+			off = duint32(sym, off, bv->b[j/32]);
+	}
+	ggloblsym(sym, off, RODATA);
+	free(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.
+// Because autos are laid out in decreasing addresses
+// on the stack, pointers first, zeroed things first and decreasing size
+// really means, in memory, things with pointers needing zeroing at
+// the top of the stack and increasing in size.
+// Non-autos sort on offset.
+static int
+cmpstackvar(Node *a, Node *b)
+{
+	int ap, bp;
+
+	if (a->class != b->class)
+		return (a->class == PAUTO) ? +1 : -1;
+	if (a->class != PAUTO) {
+		if (a->xoffset < b->xoffset)
+			return -1;
+		if (a->xoffset > b->xoffset)
+			return +1;
+		return 0;
+	}
+	if ((a->used == 0) != (b->used == 0))
+		return b->used - a->used;
+
+	ap = haspointers(a->type);
+	bp = haspointers(b->type);
+	if(ap != bp)
+		return bp - ap;
+
+	ap = a->needzero;
+	bp = b->needzero;
+	if(ap != bp)
+		return bp - ap;
+
+	if(a->type->width < b->type->width)
+		return +1;
+	if(a->type->width > b->type->width)
+		return -1;
+
+	return strcmp(a->sym->name, b->sym->name);
+}
+
+// TODO(lvd) find out where the PAUTO/OLITERAL nodes come from.
+static void
+allocauto(Prog* ptxt)
+{
+	NodeList *ll;
+	Node* n;
+	vlong w;
+
+	stksize = 0;
+	stkptrsize = 0;
+
+	if(curfn->dcl == nil)
+		return;
+
+	// Mark the PAUTO's unused.
+	for(ll=curfn->dcl; ll != nil; ll=ll->next)
+		if (ll->n->class == PAUTO)
+			ll->n->used = 0;
+
+	markautoused(ptxt);
+
+	listsort(&curfn->dcl, cmpstackvar);
+
+	// Unused autos are at the end, chop 'em off.
+	ll = curfn->dcl;
+	n = ll->n;
+	if (n->class == PAUTO && n->op == ONAME && !n->used) {
+		// No locals used at all
+		curfn->dcl = nil;
+		fixautoused(ptxt);
+		return;
+	}
+
+	for(ll = curfn->dcl; ll->next != nil; ll=ll->next) {
+		n = ll->next->n;
+		if (n->class == PAUTO && n->op == ONAME && !n->used) {
+			ll->next = nil;
+			curfn->dcl->end = ll;
+			break;
+		}
+	}
+
+	// Reassign stack offsets of the locals that are still there.
+	for(ll = curfn->dcl; ll != nil; ll=ll->next) {
+		n = ll->n;
+		if (n->class != PAUTO || n->op != ONAME)
+			continue;
+
+		dowidth(n->type);
+		w = n->type->width;
+		if(w >= MAXWIDTH || w < 0)
+			fatal("bad width");
+		stksize += w;
+		stksize = rnd(stksize, n->type->align);
+		if(haspointers(n->type))
+			stkptrsize = stksize;
+		if(thechar == '5')
+			stksize = rnd(stksize, widthptr);
+		if(stksize >= (1ULL<<31)) {
+			setlineno(curfn);
+			yyerror("stack frame too large (>2GB)");
+		}
+		n->stkdelta = -stksize - n->xoffset;
+	}
+	stksize = rnd(stksize, widthreg);
+	stkptrsize = rnd(stkptrsize, widthreg);
+
+	fixautoused(ptxt);
+
+	// The debug information needs accurate offsets on the symbols.
+	for(ll = curfn->dcl; ll != nil; ll=ll->next) {
+		if (ll->n->class != PAUTO || ll->n->op != ONAME)
+			continue;
+		ll->n->xoffset += ll->n->stkdelta;
+		ll->n->stkdelta = 0;
+	}
+}
+
+static void movelargefn(Node*);
+
+void
+movelarge(NodeList *l)
+{
+	for(; l; l=l->next)
+		if(l->n->op == ODCLFUNC)
+			movelargefn(l->n);
+}
+
+static void
+movelargefn(Node *fn)
+{
+	NodeList *l;
+	Node *n;
+
+	for(l=fn->dcl; l != nil; l=l->next) {
+		n = l->n;
+		if(n->class == PAUTO && n->type != T && n->type->width > MaxStackVarSize)
+			addrescapes(n);
+	}
+}
+
+void
+cgen_checknil(Node *n)
+{
+	Node reg;
+
+	if(disable_checknil)
+		return;
+	// 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 || n->op == OLITERAL) {
+		regalloc(&reg, types[tptr], n);
+		cgen(n, &reg);
+		gins(ACHECKNIL, &reg, N);
+		regfree(&reg);
+		return;
+	}
+	gins(ACHECKNIL, n, N);
+}
diff --git a/src/cmd/gc/plive.c b/src/cmd/gc/plive.c
new file mode 100644
index 0000000..0feb2c7
--- /dev/null
+++ b/src/cmd/gc/plive.c
@@ -0,0 +1,2017 @@
+// 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 "../ld/textflag.h"
+#include "../../runtime/funcdata.h"
+#include "../../runtime/mgc0.h"
+
+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.
+			//
+			// The Node.opt field is available for use by optimization passes.
+			// We use it to hold the index of the node in the variables array, plus 1
+			// (so that 0 means the Node is not in the variables array).
+			// Each pass should clear opt when done, but you never know,
+			// so clear them all ourselves too.
+			// The Node.curfn field is supposed to be set to the current function
+			// already, but for some compiler-introduced names it seems not to be,
+			// so fix that here.
+			// Later, when we want to find the index of a node in the variables list,
+			// we will check that n->curfn == curfn and n->opt > 0. Then n->opt - 1
+			// is the index in the variables list.
+			ll->n->opt = nil;
+			ll->n->curfn = curfn;
+			switch(ll->n->class) {
+			case PAUTO:
+				if(haspointers(ll->n->type)) {
+					ll->n->opt = (void*)(uintptr)(arraylength(result)+1);
+					arrayadd(result, &ll->n);
+				}
+				break;
+			case PPARAM:
+			case PPARAMOUT:
+				ll->n->opt = (void*)(uintptr)(arraylength(result)+1);
+				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;
+	Addr *from;
+	Addr *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 && from->node->curfn == curfn) {
+			switch(from->node->class & ~PHEAP) {
+			case PAUTO:
+			case PPARAM:
+			case PPARAMOUT:
+				pos = (int)(uintptr)from->node->opt - 1; // index in vars
+				if(pos == -1)
+					goto Next;
+				if(pos >= arraylength(vars) || *(Node**)arrayget(vars, pos) != from->node)
+					fatal("bad bookkeeping in liveness %N %d", from->node, pos);
+				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 && to->node->curfn == curfn) {
+			switch(to->node->class & ~PHEAP) {
+			case PAUTO:
+			case PPARAM:
+			case PPARAMOUT:
+				pos = (int)(uintptr)to->node->opt - 1; // index in vars
+				if(pos == -1)
+					goto Next1;
+				if(pos >= arraylength(vars) || *(Node**)arrayget(vars, pos) != to->node)
+					fatal("bad bookkeeping in liveness %N %d", to->node, pos);
+				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;
+
+	if(debuglive == 0)
+		return;
+
+	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.
+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 + 1); // 2 = live ptr in first slot
+		*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 + 1); // 2 = live ptr in first slot
+			*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 = bvnext(liveout, i)) >= 0; i++) {
+		node = *(Node**)arrayget(vars, i);
+		switch(node->class) {
+		case PAUTO:
+			xoffset = node->xoffset + stkptrsize;
+			twobitwalktype1(node->type, &xoffset, locals);
+			break;
+		case PPARAM:
+		case PPARAMOUT:
+			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
+/*c2go
+enum
+{
+	H0 = 2166136261,
+	Hp = 16777619,
+};
+*/
+
+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];
+			// Runtime reads the bitmaps as byte arrays. Oblige.
+			off = duint8(sym, off, word);
+			off = duint8(sym, off, word>>8);
+			off = duint8(sym, off, word>>16);
+			off = duint8(sym, off, word>>24);
+		}
+	}
+	duint32(sym, 0, i); // number of bitmaps
+	ggloblsym(sym, off, RODATA);
+}
+
+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;
+	NodeList *l;
+
+	// 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.
+	for(l=fn->dcl; l != nil; l = l->next)
+		if(l->n != N)
+			l->n->opt = nil;
+	freeliveness(lv);
+	arrayfree(vars);
+	freecfg(cfg);
+	
+	debuglive -= debugdelta;
+}
diff --git a/src/cmd/gc/popt.c b/src/cmd/gc/popt.c
new file mode 100644
index 0000000..993bb24
--- /dev/null
+++ b/src/cmd/gc/popt.c
@@ -0,0 +1,1005 @@
+// Derived from Inferno utils/6c/reg.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/reg.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.
+
+// "Portable" optimizations.
+// Compiled separately for 5g, 6g, and 8g, so allowed to use gg.h, opt.h.
+// Must code to the intersection of the three back ends.
+
+#include	<u.h>
+#include	<libc.h>
+#include	"gg.h"
+#include	"opt.h"
+
+// p is a call instruction. Does the call fail to return?
+int
+noreturn(Prog *p)
+{
+	Sym *s;
+	int i;
+	static Sym*	symlist[10];
+
+	if(symlist[0] == S) {
+		symlist[0] = pkglookup("panicindex", runtimepkg);
+		symlist[1] = pkglookup("panicslice", runtimepkg);
+		symlist[2] = pkglookup("throwinit", runtimepkg);
+		symlist[3] = pkglookup("gopanic", runtimepkg);
+		symlist[4] = pkglookup("panicwrap", runtimepkg);
+		symlist[5] = pkglookup("throwreturn", runtimepkg);
+		symlist[6] = pkglookup("selectgo", runtimepkg);
+		symlist[7] = pkglookup("block", runtimepkg);
+	}
+
+	if(p->to.node == nil)
+		return 0;
+	s = p->to.node->sym;
+	if(s == S)
+		return 0;
+	for(i=0; symlist[i]!=S; i++)
+		if(s == symlist[i])
+			return 1;
+	return 0;
+}
+
+// JMP chasing and removal.
+//
+// The code generator depends on being able to write out jump
+// instructions that it can jump to now but fill in later.
+// the linker will resolve them nicely, but they make the code
+// longer and more difficult to follow during debugging.
+// Remove them.
+
+/* what instruction does a JMP to p eventually land on? */
+static Prog*
+chasejmp(Prog *p, int *jmploop)
+{
+	int n;
+
+	n = 0;
+	while(p != P && p->as == AJMP && p->to.type == D_BRANCH) {
+		if(++n > 10) {
+			*jmploop = 1;
+			break;
+		}
+		p = p->to.u.branch;
+	}
+	return p;
+}
+
+/*
+ * reuse reg pointer for mark/sweep state.
+ * leave reg==nil at end because alive==nil.
+ */
+#define alive ((void*)0)
+#define dead ((void*)1)
+/*c2go
+extern void *alive;
+extern void *dead;
+*/
+
+/* mark all code reachable from firstp as alive */
+static void
+mark(Prog *firstp)
+{
+	Prog *p;
+	
+	for(p=firstp; p; p=p->link) {
+		if(p->opt != dead)
+			break;
+		p->opt = alive;
+		if(p->as != ACALL && p->to.type == D_BRANCH && p->to.u.branch)
+			mark(p->to.u.branch);
+		if(p->as == AJMP || p->as == ARET || p->as == AUNDEF)
+			break;
+	}
+}
+
+void
+fixjmp(Prog *firstp)
+{
+	int jmploop;
+	Prog *p, *last;
+	
+	if(debug['R'] && debug['v'])
+		print("\nfixjmp\n");
+
+	// pass 1: resolve jump to jump, mark all code as dead.
+	jmploop = 0;
+	for(p=firstp; p; p=p->link) {
+		if(debug['R'] && debug['v'])
+			print("%P\n", p);
+		if(p->as != ACALL && p->to.type == D_BRANCH && p->to.u.branch && p->to.u.branch->as == AJMP) {
+			p->to.u.branch = chasejmp(p->to.u.branch, &jmploop);
+			if(debug['R'] && debug['v'])
+				print("->%P\n", p);
+		}
+		p->opt = dead;
+	}
+	if(debug['R'] && debug['v'])
+		print("\n");
+
+	// pass 2: mark all reachable code alive
+	mark(firstp);
+	
+	// pass 3: delete dead code (mostly JMPs).
+	last = nil;
+	for(p=firstp; p; p=p->link) {
+		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. 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);
+				continue;
+			}
+		}
+		if(last)
+			last->link = p;
+		last = p;
+	}
+	last->link = P;
+	
+	// pass 4: elide JMP to next instruction.
+	// only safe if there are no jumps to JMPs anymore.
+	if(!jmploop) {
+		last = nil;
+		for(p=firstp; p; p=p->link) {
+			if(p->as == AJMP && p->to.type == D_BRANCH && p->to.u.branch == p->link) {
+				if(debug['R'] && debug['v'])
+					print("del %P\n", p);
+				continue;
+			}
+			if(last)
+				last->link = p;
+			last = p;
+		}
+		last->link = P;
+	}
+	
+	if(debug['R'] && debug['v']) {
+		print("\n");
+		for(p=firstp; p; p=p->link)
+			print("%P\n", p);
+		print("\n");
+	}
+}
+
+#undef alive
+#undef dead
+
+// Control flow analysis. The Flow structures hold predecessor and successor
+// information as well as basic loop analysis.
+//
+//	graph = flowstart(firstp, sizeof(Flow));
+//	... use flow graph ...
+//	flowend(graph); // free graph
+//
+// Typical uses of the flow graph are to iterate over all the flow-relevant instructions:
+//
+//	for(f = graph->start; f != nil; f = f->link)
+//
+// or, given an instruction f, to iterate over all the predecessors, which is
+// f->p1 and this list:
+//
+//	for(f2 = f->p2; f2 != nil; f2 = f2->p2link)
+//	
+// Often the Flow struct is embedded as the first field inside a larger struct S.
+// In that case casts are needed to convert Flow* to S* in many places but the
+// idea is the same. Pass sizeof(S) instead of sizeof(Flow) to flowstart.
+
+Graph*
+flowstart(Prog *firstp, int size)
+{
+	int nf;
+	Flow *f, *f1, *start, *last;
+	Graph *graph;
+	Prog *p;
+	ProgInfo info;
+
+	// Count and mark instructions to annotate.
+	nf = 0;
+	for(p = firstp; p != P; p = p->link) {
+		p->opt = nil; // should be already, but just in case
+		proginfo(&info, p);
+		if(info.flags & Skip)
+			continue;
+		p->opt = (void*)1;
+		nf++;
+	}
+	
+	if(nf == 0)
+		return nil;
+
+	if(nf >= 20000) {
+		// fatal("%S is too big (%d instructions)", curfn->nname->sym, nf);
+		return nil;
+	}
+
+	// Allocate annotations and assign to instructions.
+	graph = calloc(sizeof *graph + size*nf, 1);
+	if(graph == nil)
+		fatal("out of memory");
+	start = (Flow*)(graph+1);
+	last = nil;
+	f = start;
+	for(p = firstp; p != P; p = p->link) {
+		if(p->opt == nil)
+			continue;
+		p->opt = f;
+		f->prog = p;
+		if(last)
+			last->link = f;
+		last = f;
+		
+		f = (Flow*)((uchar*)f + size);
+	}
+
+	// Fill in pred/succ information.
+	for(f = start; f != nil; f = f->link) {
+		p = f->prog;
+		proginfo(&info, p);
+		if(!(info.flags & Break)) {
+			f1 = f->link;
+			f->s1 = f1;
+			f1->p1 = f;
+		}
+		if(p->to.type == D_BRANCH) {
+			if(p->to.u.branch == P)
+				fatal("pnil %P", p);
+			f1 = p->to.u.branch->opt;
+			if(f1 == nil)
+				fatal("fnil %P / %P", p, p->to.u.branch);
+			if(f1 == f) {
+				//fatal("self loop %P", p);
+				continue;
+			}
+			f->s2 = f1;
+			f->p2link = f1->p2;
+			f1->p2 = f;
+		}
+	}
+	
+	graph->start = start;
+	graph->num = nf;
+	return graph;
+}
+
+void
+flowend(Graph *graph)
+{
+	Flow *f;
+	
+	for(f = graph->start; f != nil; f = f->link)
+		f->prog->opt = nil;
+	free(graph);
+}
+
+/*
+ * find looping structure
+ *
+ * 1) find reverse postordering
+ * 2) find approximate dominators,
+ *	the actual dominators if the flow graph is reducible
+ *	otherwise, dominators plus some other non-dominators.
+ *	See Matthew S. Hecht and Jeffrey D. Ullman,
+ *	"Analysis of a Simple Algorithm for Global Data Flow Problems",
+ *	Conf.  Record of ACM Symp. on Principles of Prog. Langs, Boston, Massachusetts,
+ *	Oct. 1-3, 1973, pp.  207-217.
+ * 3) find all nodes with a predecessor dominated by the current node.
+ *	such a node is a loop head.
+ *	recursively, all preds with a greater rpo number are in the loop
+ */
+static int32
+postorder(Flow *r, Flow **rpo2r, int32 n)
+{
+	Flow *r1;
+
+	r->rpo = 1;
+	r1 = r->s1;
+	if(r1 && !r1->rpo)
+		n = postorder(r1, rpo2r, n);
+	r1 = r->s2;
+	if(r1 && !r1->rpo)
+		n = postorder(r1, rpo2r, n);
+	rpo2r[n] = r;
+	n++;
+	return n;
+}
+
+static int32
+rpolca(int32 *idom, int32 rpo1, int32 rpo2)
+{
+	int32 t;
+
+	if(rpo1 == -1)
+		return rpo2;
+	while(rpo1 != rpo2){
+		if(rpo1 > rpo2){
+			t = rpo2;
+			rpo2 = rpo1;
+			rpo1 = t;
+		}
+		while(rpo1 < rpo2){
+			t = idom[rpo2];
+			if(t >= rpo2)
+				fatal("bad idom");
+			rpo2 = t;
+		}
+	}
+	return rpo1;
+}
+
+static int
+doms(int32 *idom, int32 r, int32 s)
+{
+	while(s > r)
+		s = idom[s];
+	return s == r;
+}
+
+static int
+loophead(int32 *idom, Flow *r)
+{
+	int32 src;
+
+	src = r->rpo;
+	if(r->p1 != nil && doms(idom, src, r->p1->rpo))
+		return 1;
+	for(r = r->p2; r != nil; r = r->p2link)
+		if(doms(idom, src, r->rpo))
+			return 1;
+	return 0;
+}
+
+static void
+loopmark(Flow **rpo2r, int32 head, Flow *r)
+{
+	if(r->rpo < head || r->active == head)
+		return;
+	r->active = head;
+	r->loop += LOOP;
+	if(r->p1 != nil)
+		loopmark(rpo2r, head, r->p1);
+	for(r = r->p2; r != nil; r = r->p2link)
+		loopmark(rpo2r, head, r);
+}
+
+void
+flowrpo(Graph *g)
+{
+	Flow *r1;
+	int32 i, d, me, nr, *idom;
+	Flow **rpo2r;
+
+	free(g->rpo);
+	g->rpo = calloc(g->num*sizeof g->rpo[0], 1);
+	idom = calloc(g->num*sizeof idom[0], 1);
+	if(g->rpo == nil || idom == nil)
+		fatal("out of memory");
+
+	for(r1 = g->start; r1 != nil; r1 = r1->link)
+		r1->active = 0;
+
+	rpo2r = g->rpo;
+	d = postorder(g->start, rpo2r, 0);
+	nr = g->num;
+	if(d > nr)
+		fatal("too many reg nodes %d %d", d, nr);
+	nr = d;
+	for(i = 0; i < nr / 2; i++) {
+		r1 = rpo2r[i];
+		rpo2r[i] = rpo2r[nr - 1 - i];
+		rpo2r[nr - 1 - i] = r1;
+	}
+	for(i = 0; i < nr; i++)
+		rpo2r[i]->rpo = i;
+
+	idom[0] = 0;
+	for(i = 0; i < nr; i++) {
+		r1 = rpo2r[i];
+		me = r1->rpo;
+		d = -1;
+		// rpo2r[r->rpo] == r protects against considering dead code,
+		// which has r->rpo == 0.
+		if(r1->p1 != nil && rpo2r[r1->p1->rpo] == r1->p1 && r1->p1->rpo < me)
+			d = r1->p1->rpo;
+		for(r1 = r1->p2; r1 != nil; r1 = r1->p2link)
+			if(rpo2r[r1->rpo] == r1 && r1->rpo < me)
+				d = rpolca(idom, d, r1->rpo);
+		idom[i] = d;
+	}
+
+	for(i = 0; i < nr; i++) {
+		r1 = rpo2r[i];
+		r1->loop++;
+		if(r1->p2 != nil && loophead(idom, r1))
+			loopmark(rpo2r, i, r1);
+	}
+	free(idom);
+
+	for(r1 = g->start; r1 != nil; r1 = r1->link)
+		r1->active = 0;
+}
+
+Flow*
+uniqp(Flow *r)
+{
+	Flow *r1;
+
+	r1 = r->p1;
+	if(r1 == nil) {
+		r1 = r->p2;
+		if(r1 == nil || r1->p2link != nil)
+			return nil;
+	} else
+		if(r->p2 != nil)
+			return nil;
+	return r1;
+}
+
+Flow*
+uniqs(Flow *r)
+{
+	Flow *r1;
+
+	r1 = r->s1;
+	if(r1 == nil) {
+		r1 = r->s2;
+		if(r1 == nil)
+			return nil;
+	} else
+		if(r->s2 != nil)
+			return nil;
+	return r1;
+}
+
+// The compilers assume they can generate temporary variables
+// as needed to preserve the right semantics or simplify code
+// generation and the back end will still generate good code.
+// This results in a large number of ephemeral temporary variables.
+// Merge temps with non-overlapping lifetimes and equal types using the
+// greedy algorithm in Poletto and Sarkar, "Linear Scan Register Allocation",
+// ACM TOPLAS 1999.
+
+typedef struct TempVar TempVar;
+typedef struct TempFlow TempFlow;
+
+struct TempVar
+{
+	Node *node;
+	TempFlow *def; // definition of temp var
+	TempFlow *use; // use list, chained through TempFlow.uselink
+	TempVar *freelink; // next free temp in Type.opt list
+	TempVar *merge; // merge var with this one
+	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
+};
+
+struct TempFlow
+{
+	Flow	f;
+	TempFlow *uselink;
+};
+
+static int
+startcmp(const void *va, const void *vb)
+{
+	TempVar *a, *b;
+	
+	a = *(TempVar**)va;
+	b = *(TempVar**)vb;
+
+	if(a->start < b->start)
+		return -1;
+	if(a->start > b->start)
+		return +1;
+	return 0;
+}
+
+// Is n available for merging?
+static int
+canmerge(Node *n)
+{
+	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)
+{
+	int i, j, nvar, ninuse, nfree, nkill;
+	TempVar *var, *v, *v1, **bystart, **inuse;
+	TempFlow *r;
+	NodeList *l, **lp;
+	Node *n;
+	Prog *p, *p1;
+	Type *t;
+	ProgInfo info, info1;
+	int32 gen;
+	Graph *g;
+
+	enum { Debug = 0 };
+
+	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)
+		if(canmerge(l->n))
+			nvar++;
+	
+	var = calloc(nvar*sizeof var[0], 1);
+	nvar = 0;
+	for(l = curfn->dcl; l != nil; l = l->next) {
+		n = l->n;
+		if(canmerge(n)) {
+			v = &var[nvar++];
+			n->opt = v;
+			v->node = n;
+		}
+	}
+	
+	// Build list of uses.
+	// We assume that the earliest reference to a temporary is its definition.
+	// This is not true of variables in general but our temporaries are all
+	// single-use (that's why we have so many!).
+	for(r = (TempFlow*)g->start; r != nil; r = (TempFlow*)r->f.link) {
+		p = r->f.prog;
+		proginfo(&info, p);
+
+		if(p->from.node != N && p->from.node->opt && p->to.node != N && p->to.node->opt)
+			fatal("double node %P", p);
+		if((n = p->from.node) != N && (v = n->opt) != nil ||
+		   (n = p->to.node) != N && (v = n->opt) != nil) {
+		   	if(v->def == nil)
+		   		v->def = r;
+			r->uselink = v->use;
+			v->use = r;
+			if(n == p->from.node && (info.flags & LeftAddr))
+				v->addr = 1;
+		}
+	}
+	
+	if(Debug > 1)
+		dumpit("before", g->start, 0);
+	
+	nkill = 0;
+
+	// Special case.
+	for(v = var; v < var+nvar; v++) {
+		if(v->addr)
+			continue;
+		// Used in only one instruction, which had better be a write.
+		if((r = v->use) != nil && r->uselink == nil) {
+			p = r->f.prog;
+			proginfo(&info, p);
+			if(p->to.node == v->node && (info.flags & RightWrite) && !(info.flags & RightRead)) {
+				p->as = ANOP;
+				p->to = zprog.to;
+				v->removed = 1;
+				if(Debug)
+					print("drop write-only %S\n", v->node->sym);
+			} else
+				fatal("temp used and not set: %P", p);
+			nkill++;
+			continue;
+		}
+		
+		// Written in one instruction, read in the next, otherwise unused,
+		// no jumps to the next instruction. Happens mainly in 386 compiler.
+		if((r = v->use) != nil && r->f.link == &r->uselink->f && r->uselink->uselink == nil && uniqp(r->f.link) == &r->f) {
+			p = r->f.prog;
+			proginfo(&info, p);
+			p1 = r->f.link->prog;
+			proginfo(&info1, p1);
+			enum {
+				SizeAny = SizeB | SizeW | SizeL | SizeQ | SizeF | SizeD,
+			};
+			if(p->from.node == v->node && p1->to.node == v->node && (info.flags & Move) &&
+			   !((info.flags|info1.flags) & (LeftAddr|RightAddr)) &&
+			   (info.flags & SizeAny) == (info1.flags & SizeAny)) {
+				p1->from = p->from;
+				excise(&r->f);
+				v->removed = 1;
+				if(Debug)
+					print("drop immediate-use %S\n", v->node->sym);
+			}
+			nkill++;
+			continue;
+		}			   
+	}
+
+	// Traverse live range of each variable to set start, end.
+	// Each flood uses a new value of gen so that we don't have
+	// to clear all the r->f.active words after each variable.
+	gen = 0;
+	for(v = var; v < var+nvar; v++) {
+		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.
+	bystart = malloc(nvar*sizeof bystart[0]);
+	for(i=0; i<nvar; i++)
+		bystart[i] = &var[i];
+	qsort(bystart, nvar, sizeof bystart[0], startcmp);
+
+	// List of in-use variables, sorted by end, so that the ones that
+	// will last the longest are the earliest ones in the array.
+	// The tail inuse[nfree:] holds no-longer-used variables.
+	// In theory we should use a sorted tree so that insertions are
+	// guaranteed O(log n) and then the loop is guaranteed O(n log n).
+	// In practice, it doesn't really matter.
+	inuse = malloc(nvar*sizeof inuse[0]);
+	ninuse = 0;
+	nfree = nvar;
+	for(i=0; i<nvar; i++) {
+		v = bystart[i];
+		if(v->removed)
+			continue;
+
+		// Expire no longer in use.
+		while(ninuse > 0 && inuse[ninuse-1]->end < v->start) {
+			v1 = inuse[--ninuse];
+			inuse[--nfree] = v1;
+		}
+
+		// Find old temp to reuse if possible.
+		t = v->node->type;
+		for(j=nfree; j<nvar; j++) {
+			v1 = inuse[j];
+			// 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;
+				else
+					v->merge = v1;
+				nkill++;
+				break;
+			}
+		}
+
+		// Sort v into inuse.
+		j = ninuse++;
+		while(j > 0 && inuse[j-1]->end < v->end) {
+			inuse[j] = inuse[j-1];
+			j--;
+		}
+		inuse[j] = v;
+	}
+
+	if(Debug) {
+		print("%S [%d - %d]\n", curfn->nname->sym, nvar, nkill);
+		for(v=var; v<var+nvar; v++) {
+			print("var %#N %T %lld-%lld", v->node, v->node->type, v->start, v->end);
+			if(v->addr)
+				print(" addr=1");
+			if(v->removed)
+				print(" dead=1");
+			if(v->merge)
+				print(" merge %#N", v->merge->node);
+			if(v->start == v->end)
+				print(" %P", v->def->f.prog);
+			print("\n");
+		}
+	
+		if(Debug > 1)
+			dumpit("after", g->start, 0);
+	}
+
+	// Update node references to use merged temporaries.
+	for(r = (TempFlow*)g->start; r != nil; r = (TempFlow*)r->f.link) {
+		p = r->f.prog;
+		if((n = p->from.node) != N && (v = n->opt) != nil && v->merge != nil)
+			p->from.node = v->merge->node;
+		if((n = p->to.node) != N && (v = n->opt) != nil && v->merge != nil)
+			p->to.node = v->merge->node;
+	}
+
+	// Delete merged nodes from declaration list.
+	for(lp = &curfn->dcl; (l = *lp); ) {
+		curfn->dcl->end = l;
+		n = l->n;
+		v = n->opt;
+		if(v && (v->merge || v->removed)) {
+			*lp = l->next;
+			continue;
+		}
+		lp = &l->next;
+	}
+
+	// Clear aux structures.
+	for(v=var; v<var+nvar; v++)
+		v->node->opt = nil;
+	free(var);
+	free(bystart);
+	free(inuse);
+	flowend(g);
+}
+
+static void
+mergewalk(TempVar *v, TempFlow *r0, uint32 gen)
+{
+	Prog *p;
+	TempFlow *r1, *r, *r2;
+	
+	for(r1 = r0; r1 != nil; r1 = (TempFlow*)r1->f.p1) {
+		if(r1->f.active == gen)
+			break;
+		r1->f.active = gen;
+		p = r1->f.prog;
+		if(v->end < p->pc)
+			v->end = p->pc;
+		if(r1 == v->def) {
+			v->start = p->pc;
+			break;
+		}
+	}
+	
+	for(r = r0; r != r1; r = (TempFlow*)r->f.p1)
+		for(r2 = (TempFlow*)r->f.p2; r2 != nil; r2 = (TempFlow*)r2->f.p2link)
+			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.
+// This pass removes a CHECKNIL if every predecessor path has already
+// checked this value for nil.
+//
+// Simple backwards flood from check to definition.
+// Run prog loop backward from end of program to beginning to avoid quadratic
+// behavior removing a run of checks.
+//
+// Assume that stack variables with address not taken can be loaded multiple times
+// from memory without being rechecked. Other variables need to be checked on
+// each load.
+	
+typedef struct NilVar NilVar;
+typedef struct NilFlow NilFlow;
+
+struct NilFlow {
+	Flow f;
+	int kill;
+};
+
+static void nilwalkback(NilFlow *rcheck);
+static void nilwalkfwd(NilFlow *rcheck);
+
+void
+nilopt(Prog *firstp)
+{
+	NilFlow *r;
+	Prog *p;
+	Graph *g;
+	int ncheck, nkill;
+
+	g = flowstart(firstp, sizeof(NilFlow));
+	if(g == nil)
+		return;
+
+	if(debug_checknil > 1 /* || strcmp(curfn->nname->sym->name, "f1") == 0 */)
+		dumpit("nilopt", g->start, 0);
+
+	ncheck = 0;
+	nkill = 0;
+	for(r = (NilFlow*)g->start; r != nil; r = (NilFlow*)r->f.link) {
+		p = r->f.prog;
+		if(p->as != ACHECKNIL || !regtyp(&p->from))
+			continue;
+		ncheck++;
+		if(stackaddr(&p->from)) {
+			if(debug_checknil && p->lineno > 1)
+				warnl(p->lineno, "removed nil check of SP address");
+			r->kill = 1;
+			continue;
+		}
+		nilwalkfwd(r);
+		if(r->kill) {
+			if(debug_checknil && p->lineno > 1)
+				warnl(p->lineno, "removed nil check before indirect");
+			continue;
+		}
+		nilwalkback(r);
+		if(r->kill) {
+			if(debug_checknil && p->lineno > 1)
+				warnl(p->lineno, "removed repeated nil check");
+			continue;
+		}
+	}
+	
+	for(r = (NilFlow*)g->start; r != nil; r = (NilFlow*)r->f.link) {
+		if(r->kill) {
+			nkill++;
+			excise(&r->f);
+		}
+	}
+
+	flowend(g);
+	
+	if(debug_checknil > 1)
+		print("%S: removed %d of %d nil checks\n", curfn->nname->sym, nkill, ncheck);
+}
+
+static void
+nilwalkback(NilFlow *rcheck)
+{
+	Prog *p;
+	ProgInfo info;
+	NilFlow *r;
+	
+	for(r = rcheck; r != nil; r = (NilFlow*)uniqp(&r->f)) {
+		p = r->f.prog;
+		proginfo(&info, p);
+		if((info.flags & RightWrite) && sameaddr(&p->to, &rcheck->f.prog->from)) {
+			// Found initialization of value we're checking for nil.
+			// without first finding the check, so this one is unchecked.
+			return;
+		}
+		if(r != rcheck && p->as == ACHECKNIL && sameaddr(&p->from, &rcheck->f.prog->from)) {
+			rcheck->kill = 1;
+			return;
+		}
+	}
+
+	// Here is a more complex version that scans backward across branches.
+	// It assumes rcheck->kill = 1 has been set on entry, and its job is to find a reason
+	// to keep the check (setting rcheck->kill = 0).
+	// It doesn't handle copying of aggregates as well as I would like,
+	// nor variables with their address taken,
+	// and it's too subtle to turn on this late in Go 1.2. Perhaps for Go 1.3.
+	/*
+	for(r1 = r0; r1 != nil; r1 = (NilFlow*)r1->f.p1) {
+		if(r1->f.active == gen)
+			break;
+		r1->f.active = gen;
+		p = r1->f.prog;
+		
+		// If same check, stop this loop but still check
+		// alternate predecessors up to this point.
+		if(r1 != rcheck && p->as == ACHECKNIL && sameaddr(&p->from, &rcheck->f.prog->from))
+			break;
+
+		proginfo(&info, p);
+		if((info.flags & RightWrite) && sameaddr(&p->to, &rcheck->f.prog->from)) {
+			// Found initialization of value we're checking for nil.
+			// without first finding the check, so this one is unchecked.
+			rcheck->kill = 0;
+			return;
+		}
+		
+		if(r1->f.p1 == nil && r1->f.p2 == nil) {
+			print("lost pred for %P\n", rcheck->f.prog);
+			for(r1=r0; r1!=nil; r1=(NilFlow*)r1->f.p1) {
+				proginfo(&info, r1->f.prog);
+				print("\t%P %d %d %D %D\n", r1->f.prog, info.flags&RightWrite, sameaddr(&r1->f.prog->to, &rcheck->f.prog->from), &r1->f.prog->to, &rcheck->f.prog->from);
+			}
+			fatal("lost pred trail");
+		}
+	}
+
+	for(r = r0; r != r1; r = (NilFlow*)r->f.p1)
+		for(r2 = (NilFlow*)r->f.p2; r2 != nil; r2 = (NilFlow*)r2->f.p2link)
+			nilwalkback(rcheck, r2, gen);
+	*/
+}
+
+static void
+nilwalkfwd(NilFlow *rcheck)
+{
+	NilFlow *r, *last;
+	Prog *p;
+	ProgInfo info;
+	
+	// If the path down from rcheck dereferences the address
+	// (possibly with a small offset) before writing to memory
+	// and before any subsequent checks, it's okay to wait for
+	// that implicit check. Only consider this basic block to
+	// 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);
+		
+		if((info.flags & LeftRead) && smallindir(&p->from, &rcheck->f.prog->from)) {
+			rcheck->kill = 1;
+			return;
+		}
+		if((info.flags & (RightRead|RightWrite)) && smallindir(&p->to, &rcheck->f.prog->from)) {
+			rcheck->kill = 1;
+			return;
+		}
+		
+		// Stop if another nil check happens.
+		if(p->as == ACHECKNIL)
+			return;
+		// Stop if value is lost.
+		if((info.flags & RightWrite) && sameaddr(&p->to, &rcheck->f.prog->from))
+			return;
+		// 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/popt.h b/src/cmd/gc/popt.h
new file mode 100644
index 0000000..8d5dfff
--- /dev/null
+++ b/src/cmd/gc/popt.h
@@ -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.
+
+typedef struct Flow Flow;
+typedef struct Graph Graph;
+
+struct Flow {
+	Prog*	prog;   	// actual instruction
+	Flow*	p1;     	// predecessors of this instruction: p1,
+	Flow*	p2;     	// and then p2 linked though p2link.
+	Flow*	p2link;
+	Flow*	s1;     	// successors of this instruction (at most two: s1 and s2).
+	Flow*	s2;
+	Flow*	link;   	// next instruction in function code
+	
+	int32	active;	// usable by client
+
+	int32	rpo;		// reverse post ordering
+	uint16	loop;		// x5 for every loop
+	uchar	refset;		// diagnostic generated
+};
+
+struct Graph
+{
+	Flow*	start;
+	int	num;
+	
+	// After calling flowrpo, rpo lists the flow nodes in reverse postorder,
+	// and each non-dead Flow node f has g->rpo[f->rpo] == f.
+	Flow**	rpo;
+};
+
+void	fixjmp(Prog*);
+Graph*	flowstart(Prog*, int);
+void	flowrpo(Graph*);
+void	flowend(Graph*);
+void	mergetemp(Prog*);
+void	nilopt(Prog*);
+int	noreturn(Prog*);
+int	regtyp(Addr*);
+int	sameaddr(Addr*, Addr*);
+int	smallindir(Addr*, Addr*);
+int	stackaddr(Addr*);
+Flow*	uniqp(Flow*);
+Flow*	uniqs(Flow*);
diff --git a/src/cmd/gc/racewalk.c b/src/cmd/gc/racewalk.c
new file mode 100644
index 0000000..c9e27fe
--- /dev/null
+++ b/src/cmd/gc/racewalk.c
@@ -0,0 +1,664 @@
+// 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.
+
+// The racewalk pass modifies the code tree for the function as follows:
+//
+// 1. It inserts a call to racefuncenter at the beginning of each function.
+// 2. It inserts a call to racefuncexit at the end of each function.
+// 3. It inserts a call to raceread before each memory read.
+// 4. It inserts a call to racewrite before each memory write.
+//
+// The rewriting is not yet complete. Certain nodes are not rewritten
+// but should be.
+
+#include <u.h>
+#include <libc.h>
+#include "go.h"
+
+// TODO(dvyukov): do not instrument initialization as writes:
+// a := make([]int, 10)
+
+static void racewalklist(NodeList *l, NodeList **init);
+static void racewalknode(Node **np, NodeList **init, int wr, int skip);
+static int callinstr(Node **n, NodeList **init, int wr, int skip);
+static Node* uintptraddr(Node *n);
+static void makeaddable(Node *n);
+static Node* basenod(Node *n);
+static void foreach(Node *n, void(*f)(Node*, void*), void *c);
+static void hascallspred(Node *n, void *c);
+static void appendinit(Node **np, NodeList *init);
+static Node* detachexpr(Node *n, NodeList **init);
+
+// Do not instrument the following packages at all,
+// at best instrumentation would cause infinite recursion.
+static const char *omit_pkgs[] = {"runtime", "runtime/race"};
+// Only insert racefuncenter/racefuncexit into the following packages.
+// Memory accesses in the packages are either uninteresting or will cause false positives.
+static const char *noinst_pkgs[] = {"sync", "sync/atomic"};
+
+static int
+ispkgin(const char **pkgs, int n)
+{
+	int i;
+
+	if(myimportpath) {
+		for(i=0; i<n; i++) {
+			if(strcmp(myimportpath, pkgs[i]) == 0)
+				return 1;
+		}
+	}
+	return 0;
+}
+
+static int
+isforkfunc(Node *fn)
+{
+	// Special case for syscall.forkAndExecInChild.
+	// 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.
+	// Race instrumentation does all of the above.
+	return myimportpath != nil && strcmp(myimportpath, "syscall") == 0 &&
+		strcmp(fn->nname->sym->name, "forkAndExecInChild") == 0;
+}
+
+void
+racewalk(Node *fn)
+{
+	Node *nd;
+	Node *nodpc;
+	char s[1024];
+
+	if(ispkgin(omit_pkgs, nelem(omit_pkgs)) || isforkfunc(fn))
+		return;
+
+	if(!ispkgin(noinst_pkgs, nelem(noinst_pkgs))) {
+		racewalklist(fn->nbody, nil);
+		// nothing interesting for race detector in fn->enter
+		racewalklist(fn->exit, nil);
+	}
+
+	// nodpc is the PC of the caller as extracted by
+	// getcallerpc. We use -widthptr(FP) for x86.
+	// BUG: this will not work on arm.
+	nodpc = nod(OXXX, nil, nil);
+	*nodpc = *nodfp;
+	nodpc->type = types[TUINTPTR];
+	nodpc->xoffset = -widthptr;
+	nd = mkcall("racefuncenter", T, nil, nodpc);
+	fn->enter = concat(list1(nd), fn->enter);
+	nd = mkcall("racefuncexit", T, nil);
+	fn->exit = list(fn->exit, nd);
+
+	if(debug['W']) {
+		snprint(s, sizeof(s), "after racewalk %S", fn->nname->sym);
+		dumplist(s, fn->nbody);
+		snprint(s, sizeof(s), "enter %S", fn->nname->sym);
+		dumplist(s, fn->enter);
+		snprint(s, sizeof(s), "exit %S", fn->nname->sym);
+		dumplist(s, fn->exit);
+	}
+}
+
+static void
+racewalklist(NodeList *l, NodeList **init)
+{
+	NodeList *instr;
+
+	for(; l; l = l->next) {
+		instr = nil;
+		racewalknode(&l->n, &instr, 0, 0);
+		if(init == nil)
+			l->n->ninit = concat(l->n->ninit, instr);
+		else
+			*init = concat(*init, instr);
+	}
+}
+
+// walkexpr and walkstmt combined
+// walks the tree and adds calls to the
+// instrumentation code to top-level (statement) nodes' init
+static void
+racewalknode(Node **np, NodeList **init, int wr, int skip)
+{
+	Node *n, *n1;
+	NodeList *l;
+	NodeList *fini;
+
+	n = *np;
+
+	if(n == N)
+		return;
+
+	if(debug['w'] > 1)
+		dump("racewalk-before", n);
+	setlineno(n);
+	if(init == nil)
+		fatal("racewalk: bad init list");
+	if(init == &n->ninit) {
+		// If init == &n->ninit and n->ninit is non-nil,
+		// racewalknode might append it to itself.
+		// nil it out and handle it separately before putting it back.
+		l = n->ninit;
+		n->ninit = nil;
+		racewalklist(l, nil);
+		racewalknode(&n, &l, wr, skip);  // recurse with nil n->ninit
+		appendinit(&n, l);
+		*np = n;
+		return;
+	}
+
+	racewalklist(n->ninit, nil);
+
+	switch(n->op) {
+	default:
+		fatal("racewalk: unknown node type %O", n->op);
+
+	case OASOP:
+	case OAS:
+	case OAS2:
+	case OAS2RECV:
+	case OAS2FUNC:
+	case OAS2MAPR:
+		racewalknode(&n->left, init, 1, 0);
+		racewalknode(&n->right, init, 0, 0);
+		goto ret;
+
+	case OCFUNC:
+	case OVARKILL:
+		// can't matter
+		goto ret;
+
+	case OBLOCK:
+		if(n->list == nil)
+			goto ret;
+
+		switch(n->list->n->op) {
+		case OCALLFUNC:
+		case OCALLMETH:
+		case OCALLINTER:
+			// Blocks are used for multiple return function calls.
+			// 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->list->n->ninit, 0, 0);
+			fini = nil;
+			racewalklist(n->list->next, &fini);
+			n->list = concat(n->list, fini);
+			break;
+
+		default:
+			// Ordinary block, for loop initialization or inlined bodies.
+			racewalklist(n->list, nil);
+			break;
+		}
+		goto ret;
+
+	case ODEFER:
+		racewalknode(&n->left, init, 0, 0);
+		goto ret;
+
+	case OPROC:
+		racewalknode(&n->left, init, 0, 0);
+		goto ret;
+
+	case OCALLINTER:
+		racewalknode(&n->left, init, 0, 0);
+		goto ret;
+
+	case OCALLFUNC:
+		// Instrument dst argument of runtime.writebarrier* calls
+		// as we do not instrument runtime code.
+		if(n->left->sym != S && n->left->sym->pkg == runtimepkg && strncmp(n->left->sym->name, "writebarrier", 12) == 0) {
+			// Find the dst argument.
+			// The list can be reordered, so it's not necessary just the first or the second element.
+			for(l = n->list; l; l = l->next) {
+				if(strcmp(n->left->sym->name, "writebarrierfat") == 0) {
+					if(l->n->left->xoffset == widthptr)
+						break;
+				} else {
+					if(l->n->left->xoffset == 0)
+						break;
+				}
+			}
+			if(l == nil)
+				fatal("racewalk: writebarrier no arg");
+			if(l->n->right->op != OADDR)
+				fatal("racewalk: writebarrier bad arg");
+			callinstr(&l->n->right->left, init, 1, 0);
+		}
+		racewalknode(&n->left, init, 0, 0);
+		goto ret;
+
+	case ONOT:
+	case OMINUS:
+	case OPLUS:
+	case OREAL:
+	case OIMAG:
+	case OCOM:
+		racewalknode(&n->left, init, wr, 0);
+		goto ret;
+
+	case ODOTINTER:
+		racewalknode(&n->left, init, 0, 0);
+		goto ret;
+
+	case ODOT:
+		racewalknode(&n->left, init, 0, 1);
+		callinstr(&n, init, wr, skip);
+		goto ret;
+
+	case ODOTPTR: // dst = (*x).f with implicit *; otherwise it's ODOT+OIND
+		racewalknode(&n->left, init, 0, 0);
+		callinstr(&n, init, wr, skip);
+		goto ret;
+
+	case OIND: // *p
+		racewalknode(&n->left, init, 0, 0);
+		callinstr(&n, init, wr, skip);
+		goto ret;
+
+	case OSPTR:
+	case OLEN:
+	case OCAP:
+		racewalknode(&n->left, init, 0, 0);
+		if(istype(n->left->type, TMAP)) {
+			n1 = nod(OCONVNOP, n->left, N);
+			n1->type = ptrto(types[TUINT8]);
+			n1 = nod(OIND, n1, N);
+			typecheck(&n1, Erv);
+			callinstr(&n1, init, 0, skip);
+		}
+		goto ret;
+
+	case OLSH:
+	case ORSH:
+	case OLROT:
+	case OAND:
+	case OANDNOT:
+	case OOR:
+	case OXOR:
+	case OSUB:
+	case OMUL:
+	case OHMUL:
+	case OEQ:
+	case ONE:
+	case OLT:
+	case OLE:
+	case OGE:
+	case OGT:
+	case OADD:
+	case OCOMPLEX:
+		racewalknode(&n->left, init, wr, 0);
+		racewalknode(&n->right, init, wr, 0);
+		goto ret;
+
+	case OANDAND:
+	case OOROR:
+		racewalknode(&n->left, init, wr, 0);
+		// walk has ensured the node has moved to a location where
+		// side effects are safe.
+		// n->right may not be executed,
+		// so instrumentation goes to n->right->ninit, not init.
+		racewalknode(&n->right, &n->right->ninit, wr, 0);
+		goto ret;
+
+	case ONAME:
+		callinstr(&n, init, wr, skip);
+		goto ret;
+
+	case OCONV:
+		racewalknode(&n->left, init, wr, 0);
+		goto ret;
+
+	case OCONVNOP:
+		racewalknode(&n->left, init, wr, 0);
+		goto ret;
+
+	case ODIV:
+	case OMOD:
+		racewalknode(&n->left, init, wr, 0);
+		racewalknode(&n->right, init, wr, 0);
+		goto ret;
+
+	case OINDEX:
+		if(!isfixedarray(n->left->type))
+			racewalknode(&n->left, init, 0, 0);
+		else if(!islvalue(n->left)) {
+			// index of unaddressable array, like Map[k][i].
+			racewalknode(&n->left, init, wr, 0);
+			racewalknode(&n->right, init, 0, 0);
+			goto ret;
+		}
+		racewalknode(&n->right, init, 0, 0);
+		if(n->left->type->etype != TSTRING)
+			callinstr(&n, init, wr, skip);
+		goto ret;
+
+	case OSLICE:
+	case OSLICEARR:
+	case OSLICE3:
+	case OSLICE3ARR:
+		// Seems to only lead to double instrumentation.
+		//racewalknode(&n->left, init, 0, 0);
+		goto ret;
+
+	case OADDR:
+		racewalknode(&n->left, init, 0, 1);
+		goto ret;
+
+	case OEFACE:
+		racewalknode(&n->left, init, 0, 0);
+		racewalknode(&n->right, init, 0, 0);
+		goto ret;
+
+	case OITAB:
+		racewalknode(&n->left, init, 0, 0);
+		goto ret;
+
+	// should not appear in AST by now
+	case OSEND:
+	case ORECV:
+	case OCLOSE:
+	case ONEW:
+	case OXCASE:
+	case OXFALL:
+	case OCASE:
+	case OPANIC:
+	case ORECOVER:
+	case OCONVIFACE:
+	case OCMPIFACE:
+	case OMAKECHAN:
+	case OMAKEMAP:
+	case OMAKESLICE:
+	case OCALL:
+	case OCOPY:
+	case OAPPEND:
+	case ORUNESTR:
+	case OARRAYBYTESTR:
+	case OARRAYRUNESTR:
+	case OSTRARRAYBYTE:
+	case OSTRARRAYRUNE:
+	case OINDEXMAP:  // lowered to call
+	case OCMPSTR:
+	case OADDSTR:
+	case ODOTTYPE:
+	case ODOTTYPE2:
+	case OAS2DOTTYPE:
+	case OCALLPART: // lowered to PTRLIT
+	case OCLOSURE:  // lowered to PTRLIT
+	case ORANGE:    // lowered to ordinary for loop
+	case OARRAYLIT: // lowered to assignments
+	case OMAPLIT:
+	case OSTRUCTLIT:
+		yyerror("racewalk: %O must be lowered by now", n->op);
+		goto ret;
+
+	// impossible nodes: only appear in backend.
+	case ORROTC:
+	case OEXTEND:
+		yyerror("racewalk: %O cannot exist now", n->op);
+		goto ret;
+
+	// just do generic traversal
+	case OFOR:
+	case OIF:
+	case OCALLMETH:
+	case ORETURN:
+	case ORETJMP:
+	case OSWITCH:
+	case OSELECT:
+	case OEMPTY:
+	case OBREAK:
+	case OCONTINUE:
+	case OFALL:
+	case OGOTO:
+	case OLABEL:
+		goto ret;
+
+	// does not require instrumentation
+	case OPRINT:     // don't bother instrumenting it
+	case OPRINTN:    // don't bother instrumenting it
+	case OCHECKNIL: // always followed by a read.
+	case OPARAM:     // it appears only in fn->exit to copy heap params back
+	case OCLOSUREVAR:// immutable pointer to captured variable
+	case ODOTMETH:   // either part of CALLMETH or CALLPART (lowered to PTRLIT)
+	case OINDREG:    // at this stage, only n(SP) nodes from nodarg
+	case ODCL:       // declarations (without value) cannot be races
+	case ODCLCONST:
+	case ODCLTYPE:
+	case OTYPE:
+	case ONONAME:
+	case OLITERAL:
+	case OSLICESTR:  // always preceded by bounds checking, avoid double instrumentation.
+	case OTYPESW:    // ignored by code generation, do not instrument.
+		goto ret;
+	}
+
+ret:
+	if(n->op != OBLOCK)  // OBLOCK is handled above in a special way.
+		racewalklist(n->list, init);
+	if(n->ntest != N)
+		racewalknode(&n->ntest, &n->ntest->ninit, 0, 0);
+	if(n->nincr != N)
+		racewalknode(&n->nincr, &n->nincr->ninit, 0, 0);
+	racewalklist(n->nbody, nil);
+	racewalklist(n->nelse, nil);
+	racewalklist(n->rlist, nil);
+	*np = n;
+}
+
+static int
+isartificial(Node *n)
+{
+	// compiler-emitted artificial things that we do not want to instrument,
+	// cant' possibly participate in a data race.
+	if(n->op == ONAME && n->sym != S && n->sym->name != nil) {
+		if(strcmp(n->sym->name, "_") == 0)
+			return 1;
+		// autotmp's are always local
+		if(strncmp(n->sym->name, "autotmp_", sizeof("autotmp_")-1) == 0)
+			return 1;
+		// statictmp's are read-only
+		if(strncmp(n->sym->name, "statictmp_", sizeof("statictmp_")-1) == 0)
+			return 1;
+		// go.itab is accessed only by the compiler and runtime (assume safe)
+		if(n->sym->pkg && n->sym->pkg->name && strcmp(n->sym->pkg->name, "go.itab") == 0)
+			return 1;
+	}
+	return 0;
+}
+
+static int
+callinstr(Node **np, NodeList **init, int wr, int skip)
+{
+	Node *f, *b, *n;
+	Type *t;
+	int class, hascalls;
+
+	n = *np;
+	//print("callinstr for %+N [ %O ] etype=%E class=%d\n",
+	//	  n, n->op, n->type ? n->type->etype : -1, n->class);
+
+	if(skip || n->type == T || n->type->etype >= TIDEAL)
+		return 0;
+	t = n->type;
+	if(isartificial(n))
+		return 0;
+
+	b = basenod(n);
+	// it skips e.g. stores to ... parameter array
+	if(isartificial(b))
+		return 0;
+	class = b->class;
+	// BUG: we _may_ want to instrument PAUTO sometimes
+	// e.g. if we've got a local variable/method receiver
+	// that has got a pointer inside. Whether it points to
+	// the heap or not is impossible to know at compile time
+	if((class&PHEAP) || class == PPARAMREF || class == PEXTERN
+		|| b->op == OINDEX || b->op == ODOTPTR || b->op == OIND || b->op == OXDOT) {
+		hascalls = 0;
+		foreach(n, hascallspred, &hascalls);
+		if(hascalls) {
+			n = detachexpr(n, init);
+			*np = n;
+		}
+		n = treecopy(n);
+		makeaddable(n);
+		if(t->etype == TSTRUCT || isfixedarray(t)) {
+			f = mkcall(wr ? "racewriterange" : "racereadrange", T, init, uintptraddr(n),
+					nodintconst(t->width));
+		} else
+			f = mkcall(wr ? "racewrite" : "raceread", T, init, uintptraddr(n));
+		*init = list(*init, f);
+		return 1;
+	}
+	return 0;
+}
+
+// makeaddable returns a node whose memory location is the
+// same as n, but which is addressable in the Go language
+// sense.
+// This is different from functions like cheapexpr that may make
+// a copy of their argument.
+static void
+makeaddable(Node *n)
+{
+	// The arguments to uintptraddr technically have an address but
+	// may not be addressable in the Go sense: for example, in the case
+	// of T(v).Field where T is a struct type and v is
+	// an addressable value.
+	switch(n->op) {
+	case OINDEX:
+		if(isfixedarray(n->left->type))
+			makeaddable(n->left);
+		break;
+	case ODOT:
+	case OXDOT:
+		// Turn T(v).Field into v.Field
+		if(n->left->op == OCONVNOP)
+			n->left = n->left->left;
+		makeaddable(n->left);
+		break;
+	case ODOTPTR:
+	default:
+		// nothing to do
+		break;
+	}
+}
+
+static Node*
+uintptraddr(Node *n)
+{
+	Node *r;
+
+	r = nod(OADDR, n, N);
+	r->bounded = 1;
+	r = conv(r, types[TUNSAFEPTR]);
+	r = conv(r, types[TUINTPTR]);
+	return r;
+}
+
+// basenod returns the simplest child node of n pointing to the same
+// memory area.
+static Node*
+basenod(Node *n)
+{
+	for(;;) {
+		if(n->op == ODOT || n->op == OXDOT || n->op == OCONVNOP || n->op == OCONV || n->op == OPAREN) {
+			n = n->left;
+			continue;
+		}
+		if(n->op == OINDEX && isfixedarray(n->type)) {
+			n = n->left;
+			continue;
+		}
+		break;
+	}
+	return n;
+}
+
+static Node*
+detachexpr(Node *n, NodeList **init)
+{
+	Node *addr, *as, *ind, *l;
+
+	addr = nod(OADDR, n, N);
+	l = temp(ptrto(n->type));
+	as = nod(OAS, l, addr);
+	typecheck(&as, Etop);
+	walkexpr(&as, init);
+	*init = list(*init, as);
+	ind = nod(OIND, l, N);
+	typecheck(&ind, Erv);
+	walkexpr(&ind, init);
+	return ind;
+}
+
+static void
+foreachnode(Node *n, void(*f)(Node*, void*), void *c)
+{
+	if(n)
+		f(n, c);
+}
+
+static void
+foreachlist(NodeList *l, void(*f)(Node*, void*), void *c)
+{
+	for(; l; l = l->next)
+		foreachnode(l->n, f, c);
+}
+
+static void
+foreach(Node *n, void(*f)(Node*, void*), void *c)
+{
+	foreachlist(n->ninit, f, c);
+	foreachnode(n->left, f, c);
+	foreachnode(n->right, f, c);
+	foreachlist(n->list, f, c);
+	foreachnode(n->ntest, f, c);
+	foreachnode(n->nincr, f, c);
+	foreachlist(n->nbody, f, c);
+	foreachlist(n->nelse, f, c);
+	foreachlist(n->rlist, f, c);
+}
+
+static void
+hascallspred(Node *n, void *c)
+{
+	switch(n->op) {
+	case OCALL:
+	case OCALLFUNC:
+	case OCALLMETH:
+	case OCALLINTER:
+		(*(int*)c)++;
+	}
+}
+
+// appendinit is like addinit in subr.c
+// but appends rather than prepends.
+static void
+appendinit(Node **np, NodeList *init)
+{
+	Node *n;
+
+	if(init == nil)
+		return;
+
+	n = *np;
+	switch(n->op) {
+	case ONAME:
+	case OLITERAL:
+		// There may be multiple refs to this node;
+		// introduce OCONVNOP to hold init list.
+		n = nod(OCONVNOP, n, N);
+		n->type = n->left->type;
+		n->typecheck = 1;
+		*np = n;
+		break;
+	}
+	n->ninit = concat(n->ninit, init);
+	n->ullman = UINF;
+}
+
diff --git a/src/cmd/gc/range.c b/src/cmd/gc/range.c
new file mode 100644
index 0000000..4ed4528
--- /dev/null
+++ b/src/cmd/gc/range.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.
+
+/*
+ * range
+ */
+
+#include <u.h>
+#include <libc.h>
+#include "go.h"
+
+void
+typecheckrange(Node *n)
+{
+	char *why;
+	Type *t, *t1, *t2;
+	Node *v1, *v2;
+	NodeList *ll;
+
+	// delicate little dance.  see typecheckas2
+	for(ll=n->list; ll; ll=ll->next)
+		if(ll->n->defn != n)
+			typecheck(&ll->n, Erv | Easgn);
+
+	typecheck(&n->right, Erv);
+	if((t = n->right->type) == T)
+		goto out;
+	if(isptr[t->etype] && isfixedarray(t->type))
+		t = t->type;
+	n->type = t;
+
+	switch(t->etype) {
+	default:
+		yyerror("cannot range over %lN", n->right);
+		goto out;
+
+	case TARRAY:
+		t1 = types[TINT];
+		t2 = t->type;
+		break;
+
+	case TMAP:
+		t1 = t->down;
+		t2 = t->type;
+		break;
+
+	case TCHAN:
+		if(!(t->chan & Crecv)) {
+			yyerror("invalid operation: range %N (receive from send-only type %T)", n->right, n->right->type);
+			goto out;
+		}
+		t1 = t->type;
+		t2 = nil;
+		if(count(n->list) == 2)
+			goto toomany;
+		break;
+
+	case TSTRING:
+		t1 = types[TINT];
+		t2 = runetype;
+		break;
+	}
+
+	if(count(n->list) > 2) {
+	toomany:
+		yyerror("too many variables in range");
+	}
+
+	v1 = N;
+	if(n->list)
+		v1 = n->list->n;
+	v2 = N;
+	if(n->list && n->list->next)
+		v2 = n->list->next->n;
+
+	// this is not only a optimization but also a requirement in the spec.
+	// "if the second iteration variable is the blank identifier, the range
+	// clause is equivalent to the same clause with only the first variable
+	// present."
+	if(isblank(v2)) {
+		if(v1 != N)
+			n->list = list1(v1);
+		v2 = N;
+	}
+
+	if(v1) {
+		if(v1->defn == n)
+			v1->type = t1;
+		else if(v1->type != T && assignop(t1, v1->type, &why) == 0)
+			yyerror("cannot assign type %T to %lN in range%s", t1, v1, why);
+	}
+	if(v2) {
+		if(v2->defn == n)
+			v2->type = t2;
+		else if(v2->type != T && assignop(t2, v2->type, &why) == 0)
+			yyerror("cannot assign type %T to %lN in range%s", t2, v2, why);
+	}
+
+out:
+	typechecklist(n->nbody, Etop);
+
+	// second half of dance
+	n->typecheck = 1;
+	for(ll=n->list; ll; ll=ll->next)
+		if(ll->n->typecheck == 0)
+			typecheck(&ll->n, Erv | Easgn);
+}
+
+void
+walkrange(Node *n)
+{
+	Node *ohv1, *hv1, *hv2;	// hidden (old) val 1, 2
+	Node *ha, *hit;	// hidden aggregate, iterator
+	Node *hn, *hp;	// hidden len, pointer
+	Node *hb;  // hidden bool
+	Node *a, *v1, *v2;	// not hidden aggregate, val 1, 2
+	Node *fn, *tmp;
+	Node *keyname, *valname;
+	Node *key, *val;
+	NodeList *body, *init;
+	Type *th, *t;
+	int lno;
+
+	t = n->type;
+	init = nil;
+
+	a = n->right;
+	lno = setlineno(a);
+
+	v1 = N;
+	if(n->list)
+		v1 = n->list->n;
+	v2 = N;
+	if(n->list && 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;
+
+	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;
+
+		init = list(init, nod(OAS, hv1, N));
+		init = list(init, nod(OAS, hn, nod(OLEN, ha, N)));
+		if(v2) {
+			hp = temp(ptrto(n->type->type));
+			tmp = nod(OINDEX, ha, nodintconst(0));
+			tmp->bounded = 1;
+			init = list(init, nod(OAS, hp, nod(OADDR, tmp, N)));
+		}
+
+		n->ntest = nod(OLT, hv1, hn);
+		n->nincr = nod(OAS, hv1, nod(OADD, hv1, nodintconst(1)));
+		if(v1 == N)
+			body = nil;
+		else if(v2 == N)
+			body = list1(nod(OAS, v1, hv1));
+		else {
+			a = nod(OAS2, N, 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;
+			a = nod(OAS, hp, tmp);
+			typecheck(&a, Etop);
+			n->nincr->ninit = list1(a);
+		}
+		break;
+
+	case TMAP:
+		// 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(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(v1 == N)
+			body = nil;
+		else if(v2 == N) {
+			body = list1(nod(OAS, v1, key));
+		} else {
+			val = nod(ODOT, hit, valname);
+			val = nod(OIND, val, N);
+			a = nod(OAS2, N, N);
+			a->list = list(list1(v1), v2);
+			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);
+		hv1->typecheck = 1;
+		if(haspointers(t->type))
+			init = list(init, nod(OAS, hv1, N));
+		hb = temp(types[TBOOL]);
+
+		n->ntest = nod(ONE, hb, nodbool(0));
+		a = nod(OAS2RECV, N, N);
+		a->typecheck = 1;
+		a->list = list(list1(hv1), hb);
+		a->rlist = list1(nod(ORECV, ha, N));
+		n->ntest->ninit = list1(a);
+		if(v1 == N)
+			body = nil;
+		else
+			body = list1(nod(OAS, v1, hv1));
+		break;
+
+	case TSTRING:
+		// orderstmt arranged for a copy of the string variable.
+		ha = a;
+
+		ohv1 = temp(types[TINT]);
+
+		hv1 = temp(types[TINT]);
+		init = list(init, nod(OAS, hv1, N));
+
+		if(v2 == N)
+			a = nod(OAS, hv1, mkcall("stringiter", types[TINT], nil, ha, hv1));
+		else {
+			hv2 = temp(runetype);
+			a = nod(OAS2, N, N);
+			a->list = list(list1(hv1), hv2);
+			fn = syslook("stringiter2", 0);
+			a->rlist = list1(mkcall1(fn, getoutargx(fn->type), nil, ha, hv1));
+		}
+		n->ntest = nod(ONE, hv1, nodintconst(0));
+		n->ntest->ninit = list(list1(nod(OAS, ohv1, hv1)), a);
+
+		
+		body = nil;
+		if(v1 != N)
+			body = list1(nod(OAS, v1, ohv1));
+		if(v2 != N)
+			body = list(body, nod(OAS, v2, hv2));
+		break;
+	}
+
+	n->op = OFOR;
+	typechecklist(init, Etop);
+	n->ninit = concat(n->ninit, init);
+	typechecklist(n->ntest->ninit, Etop);
+	typecheck(&n->ntest, Erv);
+	typecheck(&n->nincr, Etop);
+	typechecklist(body, Etop);
+	n->nbody = concat(body, n->nbody);
+	walkstmt(&n);
+	
+	lineno = lno;
+}
+
diff --git a/src/cmd/gc/reflect.c b/src/cmd/gc/reflect.c
new file mode 100644
index 0000000..8788a67
--- /dev/null
+++ b/src/cmd/gc/reflect.c
@@ -0,0 +1,1577 @@
+// 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 "go.h"
+#include "../ld/textflag.h"
+#include "../../runtime/mgc0.h"
+#include "../../runtime/typekind.h"
+
+/*
+ * runtime interface and reflection data structures
+ */
+
+static	NodeList*	signatlist;
+static	Sym*	dtypesym(Type*);
+static	Sym*	weaktypesym(Type*);
+static	Sym*	dalgsym(Type*);
+static	int	usegcprog(Type*);
+static	void	gengcprog(Type*, Sym**, Sym**);
+static	void	gengcmask(Type*, uint8[16]);
+
+static int
+sigcmp(Sig *a, Sig *b)
+{
+	int i;
+
+	i = strcmp(a->name, b->name);
+	if(i != 0)
+		return i;
+	if(a->pkg == b->pkg)
+		return 0;
+	if(a->pkg == nil)
+		return -1;
+	if(b->pkg == nil)
+		return +1;
+	return strcmp(a->pkg->path->s, b->pkg->path->s);
+}
+
+static Sig*
+lsort(Sig *l, int(*f)(Sig*, Sig*))
+{
+	Sig *l1, *l2, *le;
+
+	if(l == 0 || l->link == 0)
+		return l;
+
+	l1 = l;
+	l2 = l;
+	for(;;) {
+		l2 = l2->link;
+		if(l2 == 0)
+			break;
+		l2 = l2->link;
+		if(l2 == 0)
+			break;
+		l1 = l1->link;
+	}
+
+	l2 = l1->link;
+	l1->link = 0;
+	l1 = lsort(l, f);
+	l2 = lsort(l2, f);
+
+	/* set up lead element */
+	if((*f)(l1, l2) < 0) {
+		l = l1;
+		l1 = l1->link;
+	} else {
+		l = l2;
+		l2 = l2->link;
+	}
+	le = l;
+
+	for(;;) {
+		if(l1 == 0) {
+			while(l2) {
+				le->link = l2;
+				le = l2;
+				l2 = l2->link;
+			}
+			le->link = 0;
+			break;
+		}
+		if(l2 == 0) {
+			while(l1) {
+				le->link = l1;
+				le = l1;
+				l1 = l1->link;
+			}
+			break;
+		}
+		if((*f)(l1, l2) < 0) {
+			le->link = l1;
+			le = l1;
+			l1 = l1->link;
+		} else {
+			le->link = l2;
+			le = l2;
+			l2 = l2->link;
+		}
+	}
+	le->link = 0;
+	return l;
+}
+
+// Builds a type respresenting a Bucket structure for
+// the given map type.  This type is not visible to users -
+// we include only enough information to generate a correct GC
+// program for it.
+// Make sure this stays in sync with ../../runtime/hashmap.c!
+enum {
+	BUCKETSIZE = 8,
+	MAXKEYSIZE = 128,
+	MAXVALSIZE = 128,
+};
+
+static Type*
+mapbucket(Type *t)
+{
+	Type *keytype, *valtype;
+	Type *bucket;
+	Type *overflowfield, *keysfield, *valuesfield;
+	int32 offset;
+
+	if(t->bucket != T)
+		return t->bucket;
+
+	keytype = t->down;
+	valtype = t->type;
+	dowidth(keytype);
+	dowidth(valtype);
+	if(keytype->width > MAXKEYSIZE)
+		keytype = ptrto(keytype);
+	if(valtype->width > MAXVALSIZE)
+		valtype = ptrto(valtype);
+
+	bucket = typ(TSTRUCT);
+	bucket->noalg = 1;
+
+	// The first field is: uint8 topbits[BUCKETSIZE].
+	// We don't need to encode it as GC doesn't care about it.
+	offset = BUCKETSIZE * 1;
+
+	keysfield = typ(TFIELD);
+	keysfield->type = typ(TARRAY);
+	keysfield->type->type = keytype;
+	keysfield->type->bound = BUCKETSIZE;
+	keysfield->type->width = BUCKETSIZE * keytype->width;
+	keysfield->width = offset;
+	keysfield->sym = mal(sizeof(Sym));
+	keysfield->sym->name = "keys";
+	offset += BUCKETSIZE * keytype->width;
+
+	valuesfield = typ(TFIELD);
+	valuesfield->type = typ(TARRAY);
+	valuesfield->type->type = valtype;
+	valuesfield->type->bound = BUCKETSIZE;
+	valuesfield->type->width = BUCKETSIZE * valtype->width;
+	valuesfield->width = offset;
+	valuesfield->sym = mal(sizeof(Sym));
+	valuesfield->sym->name = "values";
+	offset += BUCKETSIZE * valtype->width;
+
+	overflowfield = typ(TFIELD);
+	overflowfield->type = ptrto(bucket);
+	overflowfield->width = offset;         // "width" is offset in structure
+	overflowfield->sym = mal(sizeof(Sym)); // not important but needs to be set to give this type a name
+	overflowfield->sym->name = "overflow";
+	offset += widthptr;
+	
+	// Pad 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;
+
+	// link up fields
+	bucket->type = keysfield;
+	keysfield->down = valuesfield;
+	valuesfield->down = overflowfield;
+	overflowfield->down = T;
+
+	bucket->width = offset;
+	bucket->local = t->local;
+	t->bucket = bucket;
+	bucket->map = t;
+	return bucket;
+}
+
+// Builds a type respresenting a Hmap structure for
+// the given map type.  This type is not visible to users -
+// we include only enough information to generate a correct GC
+// program for it.
+// Make sure this stays in sync with ../../runtime/hashmap.go!
+static Type*
+hmap(Type *t)
+{
+	Type *h, *bucket;
+	Type *bucketsfield, *oldbucketsfield;
+	int32 offset;
+
+	if(t->hmap != T)
+		return t->hmap;
+
+	bucket = mapbucket(t);
+	h = typ(TSTRUCT);
+	h->noalg = 1;
+
+	offset = widthint; // count
+	offset += 4;       // flags
+	offset += 4;       // hash0
+	offset += 1;       // B
+	offset = (offset + widthptr - 1) / widthptr * widthptr;
+	
+	bucketsfield = typ(TFIELD);
+	bucketsfield->type = ptrto(bucket);
+	bucketsfield->width = offset;
+	bucketsfield->sym = mal(sizeof(Sym));
+	bucketsfield->sym->name = "buckets";
+	offset += widthptr;
+
+	oldbucketsfield = typ(TFIELD);
+	oldbucketsfield->type = ptrto(bucket);
+	oldbucketsfield->width = offset;
+	oldbucketsfield->sym = mal(sizeof(Sym));
+	oldbucketsfield->sym->name = "oldbuckets";
+	offset += widthptr;
+
+	offset += widthptr; // nevacuate (last field in Hmap)
+
+	// link up fields
+	h->type = bucketsfield;
+	bucketsfield->down = oldbucketsfield;
+	oldbucketsfield->down = T;
+
+	h->width = offset;
+	h->local = t->local;
+	t->hmap = h;
+	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 ../../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).
+ */
+Type*
+methodfunc(Type *f, Type *receiver)
+{
+	NodeList *in, *out;
+	Node *d;
+	Type *t;
+
+	in = nil;
+	if(receiver) {
+		d = nod(ODCLFIELD, N, N);
+		d->type = receiver;
+		in = list(in, d);
+	}
+	for(t=getinargx(f)->type; t; t=t->down) {
+		d = nod(ODCLFIELD, N, N);
+		d->type = t->type;
+		d->isddd = t->isddd;
+		in = list(in, d);
+	}
+
+	out = nil;
+	for(t=getoutargx(f)->type; t; t=t->down) {
+		d = nod(ODCLFIELD, N, N);
+		d->type = t->type;
+		out = list(out, d);
+	}
+
+	t = functype(N, in, out);
+	if(f->nname) {
+		// Link to name of original method function.
+		t->nname = f->nname;
+	}
+	return t;
+}
+
+/*
+ * return methods of non-interface type t, sorted by name.
+ * generates stub functions as needed.
+ */
+static Sig*
+methods(Type *t)
+{
+	Type *f, *mt, *it, *this;
+	Sig *a, *b;
+	Sym *method;
+
+	// method type
+	mt = methtype(t, 0);
+	if(mt == T)
+		return nil;
+	expandmeth(mt);
+
+	// type stored in interface word
+	it = t;
+	if(!isdirectiface(it))
+		it = ptrto(t);
+
+	// make list of methods for t,
+	// generating code if necessary.
+	a = nil;
+	for(f=mt->xmethod; f; f=f->down) {
+		if(f->etype != TFIELD)
+			fatal("methods: not field %T", f);
+		if (f->type->etype != TFUNC || f->type->thistuple == 0)
+			fatal("non-method on %T method %S %T\n", mt, f->sym, f);
+		if (!getthisx(f->type)->type)
+			fatal("receiver with no type on %T method %S %T\n", mt, f->sym, f);
+		if(f->nointerface)
+			continue;
+
+		method = f->sym;
+		if(method == nil)
+			continue;
+
+		// get receiver type for this particular method.
+		// if pointer receiver but non-pointer t and
+		// this is not an embedded pointer inside a struct,
+		// method does not apply.
+		this = getthisx(f->type)->type->type;
+		if(isptr[this->etype] && this->type == t)
+			continue;
+		if(isptr[this->etype] && !isptr[t->etype]
+		&& f->embedded != 2 && !isifacemethod(f->type))
+			continue;
+
+		b = mal(sizeof(*b));
+		b->link = a;
+		a = b;
+
+		a->name = method->name;
+		if(!exportname(method->name)) {
+			if(method->pkg == nil)
+				fatal("methods: missing package");
+			a->pkg = method->pkg;
+		}
+		a->isym = methodsym(method, it, 1);
+		a->tsym = methodsym(method, t, 0);
+		a->type = methodfunc(f->type, t);
+		a->mtype = methodfunc(f->type, nil);
+
+		if(!(a->isym->flags & SymSiggen)) {
+			a->isym->flags |= SymSiggen;
+			if(!eqtype(this, it) || this->width < types[tptr]->width) {
+				compiling_wrappers = 1;
+				genwrapper(it, f, a->isym, 1);
+				compiling_wrappers = 0;
+			}
+		}
+
+		if(!(a->tsym->flags & SymSiggen)) {
+			a->tsym->flags |= SymSiggen;
+			if(!eqtype(this, t)) {
+				compiling_wrappers = 1;
+				genwrapper(t, f, a->tsym, 0);
+				compiling_wrappers = 0;
+			}
+		}
+	}
+
+	return lsort(a, sigcmp);
+}
+
+/*
+ * return methods of interface type t, sorted by name.
+ */
+static Sig*
+imethods(Type *t)
+{
+	Sig *a, *all, *last;
+	Type *f;
+	Sym *method, *isym;
+
+	all = nil;
+	last = nil;
+	for(f=t->type; f; f=f->down) {
+		if(f->etype != TFIELD)
+			fatal("imethods: not field");
+		if(f->type->etype != TFUNC || f->sym == nil)
+			continue;
+		method = f->sym;
+		a = mal(sizeof(*a));
+		a->name = method->name;
+		if(!exportname(method->name)) {
+			if(method->pkg == nil)
+				fatal("imethods: missing package");
+			a->pkg = method->pkg;
+		}
+		a->mtype = f->type;
+		a->offset = 0;
+		a->type = methodfunc(f->type, nil);
+
+		if(last && sigcmp(last, a) >= 0)
+			fatal("sigcmp vs sortinter %s %s", last->name, a->name);
+		if(last == nil)
+			all = a;
+		else
+			last->link = a;
+		last = a;
+
+		// Compiler can only refer to wrappers for non-blank methods.
+		if(isblanksym(method))
+			continue;
+
+		// NOTE(rsc): Perhaps an oversight that
+		// IfaceType.Method is not in the reflect data.
+		// Generate the method body, so that compiled
+		// code can refer to it.
+		isym = methodsym(method, t, 0);
+		if(!(isym->flags & SymSiggen)) {
+			isym->flags |= SymSiggen;
+			genwrapper(t, f, isym, 0);
+		}
+	}
+	return all;
+}
+
+static void
+dimportpath(Pkg *p)
+{
+	static Pkg *gopkg;
+	char *nam;
+	Node *n;
+
+	if(p->pathsym != S)
+		return;
+
+	if(gopkg == nil) {
+		gopkg = mkpkg(strlit("go"));
+		gopkg->name = "go";
+	}
+	nam = smprint("importpath.%s.", p->prefix);
+
+	n = nod(ONAME, N, N);
+	n->sym = pkglookup(nam, gopkg);
+	free(nam);
+	n->class = PEXTERN;
+	n->xoffset = 0;
+	p->pathsym = n->sym;
+
+	gdatastring(n, p->path);
+	ggloblsym(n->sym, types[TSTRING]->width, DUPOK|RODATA);
+}
+
+static int
+dgopkgpath(Sym *s, int ot, Pkg *pkg)
+{
+	if(pkg == nil)
+		return dgostringptr(s, ot, nil);
+
+	// Emit reference to go.importpath.""., which 6l will
+	// rewrite using the correct import path.  Every package
+	// that imports this one directly defines the symbol.
+	if(pkg == localpkg) {
+		static Sym *ns;
+
+		if(ns == nil)
+			ns = pkglookup("importpath.\"\".", mkpkg(strlit("go")));
+		return dsymptr(s, ot, ns, 0);
+	}
+
+	dimportpath(pkg);
+	return dsymptr(s, ot, pkg->pathsym, 0);
+}
+
+/*
+ * uncommonType
+ * ../../runtime/type.go:/uncommonType
+ */
+static int
+dextratype(Sym *sym, int off, Type *t, int ptroff)
+{
+	int ot, n;
+	Sym *s;
+	Sig *a, *m;
+
+	m = methods(t);
+	if(t->sym == nil && m == nil)
+		return off;
+
+	// fill in *extraType pointer in header
+	off = rnd(off, widthptr);
+	dsymptr(sym, ptroff, sym, off);
+
+	n = 0;
+	for(a=m; a; a=a->link) {
+		dtypesym(a->type);
+		n++;
+	}
+
+	ot = off;
+	s = sym;
+	if(t->sym) {
+		ot = dgostringptr(s, ot, t->sym->name);
+		if(t != types[t->etype] && t != errortype)
+			ot = dgopkgpath(s, ot, t->sym->pkg);
+		else
+			ot = dgostringptr(s, ot, nil);
+	} else {
+		ot = dgostringptr(s, ot, nil);
+		ot = dgostringptr(s, ot, nil);
+	}
+
+	// slice header
+	ot = dsymptr(s, ot, s, ot + widthptr + 2*widthint);
+	ot = duintxx(s, ot, n, widthint);
+	ot = duintxx(s, ot, n, widthint);
+
+	// methods
+	for(a=m; a; a=a->link) {
+		// method
+		// ../../runtime/type.go:/method
+		ot = dgostringptr(s, ot, a->name);
+		ot = dgopkgpath(s, ot, a->pkg);
+		ot = dsymptr(s, ot, dtypesym(a->mtype), 0);
+		ot = dsymptr(s, ot, dtypesym(a->type), 0);
+		if(a->isym)
+			ot = dsymptr(s, ot, a->isym, 0);
+		else
+			ot = duintptr(s, ot, 0);
+		if(a->tsym)
+			ot = dsymptr(s, ot, a->tsym, 0);
+		else
+			ot = duintptr(s, ot, 0);
+	}
+
+	return ot;
+}
+
+static int
+kinds[] =
+{
+	[TINT]		= KindInt,
+	[TUINT]		= KindUint,
+	[TINT8]		= KindInt8,
+	[TUINT8]	= KindUint8,
+	[TINT16]	= KindInt16,
+	[TUINT16]	= KindUint16,
+	[TINT32]	= KindInt32,
+	[TUINT32]	= KindUint32,
+	[TINT64]	= KindInt64,
+	[TUINT64]	= KindUint64,
+	[TUINTPTR]	= KindUintptr,
+	[TFLOAT32]	= KindFloat32,
+	[TFLOAT64]	= KindFloat64,
+	[TBOOL]		= KindBool,
+	[TSTRING]		= KindString,
+	[TPTR32]		= KindPtr,
+	[TPTR64]		= KindPtr,
+	[TSTRUCT]	= KindStruct,
+	[TINTER]		= KindInterface,
+	[TCHAN]		= KindChan,
+	[TMAP]		= KindMap,
+	[TARRAY]		= KindArray,
+	[TFUNC]		= KindFunc,
+	[TCOMPLEX64]	= KindComplex64,
+	[TCOMPLEX128]	= KindComplex128,
+	[TUNSAFEPTR]	= KindUnsafePointer,
+};
+
+int
+haspointers(Type *t)
+{
+	Type *t1;
+	int ret;
+
+	if(t->haspointers != 0)
+		return t->haspointers - 1;
+
+	switch(t->etype) {
+	case TINT:
+	case TUINT:
+	case TINT8:
+	case TUINT8:
+	case TINT16:
+	case TUINT16:
+	case TINT32:
+	case TUINT32:
+	case TINT64:
+	case TUINT64:
+	case TUINTPTR:
+	case TFLOAT32:
+	case TFLOAT64:
+	case TCOMPLEX64:
+	case TCOMPLEX128:
+	case TBOOL:
+		ret = 0;
+		break;
+	case TARRAY:
+		if(t->bound < 0) {	// slice
+			ret = 1;
+			break;
+		}
+		if(t->bound == 0) {	// empty array
+			ret = 0;
+			break;
+		}
+		ret = haspointers(t->type);
+		break;
+	case TSTRUCT:
+		ret = 0;
+		for(t1=t->type; t1!=T; t1=t1->down) {
+			if(haspointers(t1->type)) {
+				ret = 1;
+				break;
+			}
+		}
+		break;
+	case TSTRING:
+	case TPTR32:
+	case TPTR64:
+	case TUNSAFEPTR:
+	case TINTER:
+	case TCHAN:
+	case TMAP:
+	case TFUNC:
+	default:
+		ret = 1;
+		break;
+	}
+	
+	t->haspointers = 1+ret;
+	return ret;
+}
+
+/*
+ * commonType
+ * ../../runtime/type.go:/commonType
+ */
+static int
+dcommontype(Sym *s, int ot, Type *t)
+{
+	int i, alg, sizeofAlg, gcprog;
+	Sym *sptr, *algsym, *zero, *gcprog0, *gcprog1, *sbits;
+	uint8 gcmask[16];
+	static Sym *algarray;
+	uint64 x1, x2;
+	char *p;
+	
+	if(ot != 0)
+		fatal("dcommontype %d", ot);
+
+	sizeofAlg = 2*widthptr;
+	if(algarray == nil)
+		algarray = pkglookup("algarray", runtimepkg);
+	dowidth(t);
+	alg = algtype(t);
+	algsym = S;
+	if(alg < 0)
+		algsym = dalgsym(t);
+
+	if(t->sym != nil && !isptr[t->etype])
+		sptr = dtypesym(ptrto(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 {
+	//		size          uintptr
+	//		hash          uint32
+	//		_             uint8
+	//		align         uint8
+	//		fieldAlign    uint8
+	//		kind          uint8
+	//		alg           unsafe.Pointer
+	//		gc            unsafe.Pointer
+	//		string        *string
+	//		*extraType
+	//		ptrToThis     *Type
+	//		zero          unsafe.Pointer
+	//	}
+	ot = duintptr(s, ot, t->width);
+	ot = duint32(s, ot, typehash(t));
+	ot = duint8(s, ot, 0);	// unused
+
+	// runtime (and common sense) expects alignment to be a power of two.
+	i = t->align;
+	if(i == 0)
+		i = 1;
+	if((i&(i-1)) != 0)
+		fatal("invalid alignment %d for %T", t->align, t);
+	ot = duint8(s, ot, t->align);	// align
+	ot = duint8(s, ot, t->align);	// fieldAlign
+
+	gcprog = usegcprog(t);
+	i = kinds[t->etype];
+	if(t->etype == TARRAY && t->bound < 0)
+		i = KindSlice;
+	if(!haspointers(t))
+		i |= KindNoPointers;
+	if(isdirectiface(t))
+		i |= KindDirectIface;
+	if(gcprog)
+		i |= KindGCProg;
+	ot = duint8(s, ot, i);  // kind
+	if(alg >= 0)
+		ot = dsymptr(s, ot, algarray, alg*sizeofAlg);
+	else
+		ot = dsymptr(s, ot, algsym, 0);
+	// gc
+	if(gcprog) {
+		gengcprog(t, &gcprog0, &gcprog1);
+		if(gcprog0 != S)
+			ot = dsymptr(s, ot, gcprog0, 0);
+		else
+			ot = duintptr(s, ot, 0);
+		ot = dsymptr(s, ot, gcprog1, 0);
+	} else {
+		gengcmask(t, gcmask);
+		x1 = 0;
+		for(i=0; i<8; i++)
+			x1 = x1<<8 | gcmask[i];
+		if(widthptr == 4) {
+			p = smprint("gcbits.%#016llux", x1);
+		} else {
+			x2 = 0;
+			for(i=0; i<8; i++)
+				x2 = x2<<8 | gcmask[i+8];
+			p = smprint("gcbits.%#016llux%016llux", x1, x2);
+		}
+		sbits = pkglookup(p, runtimepkg);
+		if((sbits->flags & SymUniq) == 0) {
+			sbits->flags |= SymUniq;
+			for(i = 0; i < 2*widthptr; i++)
+				duint8(sbits, i, gcmask[i]);
+			ggloblsym(sbits, 2*widthptr, DUPOK|RODATA);
+		}
+		ot = dsymptr(s, ot, sbits, 0);
+		ot = duintptr(s, ot, 0);
+	}
+	p = smprint("%-uT", t);
+	//print("dcommontype: %s\n", p);
+	ot = dgostringptr(s, ot, p);	// string
+	free(p);
+
+	// skip pointer to extraType,
+	// which follows the rest of this type structure.
+	// caller will fill in if needed.
+	// otherwise linker will assume 0.
+	ot += widthptr;
+
+	ot = dsymptr(s, ot, sptr, 0);  // ptrto type
+	ot = dsymptr(s, ot, zero, 0);  // ptr to zero value
+	return ot;
+}
+
+Sym*
+typesym(Type *t)
+{
+	char *p;
+	Sym *s;
+
+	p = smprint("%-T", t);
+	s = pkglookup(p, typepkg);
+	//print("typesym: %s -> %+S\n", p, s);
+	free(p);
+	return s;
+}
+
+Sym*
+tracksym(Type *t)
+{
+	char *p;
+	Sym *s;
+
+	p = smprint("%-T.%s", t->outer, t->sym->name);
+	s = pkglookup(p, trackpkg);
+	free(p);
+	return s;
+}
+
+Sym*
+typelinksym(Type *t)
+{
+	char *p;
+	Sym *s;
+
+	// %-uT is what the generated Type's string field says.
+	// It uses (ambiguous) package names instead of import paths.
+	// %-T is the complete, unambiguous type name.
+	// We want the types to end up sorted by string field,
+	// so use that first in the name, and then add :%-T to
+	// disambiguate. The names are a little long but they are
+	// discarded by the linker and do not end up in the symbol
+	// table of the final binary.
+	p = smprint("%-uT/%-T", t, t);
+	s = pkglookup(p, typelinkpkg);
+	//print("typelinksym: %s -> %+S\n", p, s);
+	free(p);
+	return s;
+}
+
+Sym*
+typesymprefix(char *prefix, Type *t)
+{
+	char *p;
+	Sym *s;
+
+	p = smprint("%s.%-T", prefix, t);
+	s = pkglookup(p, typepkg);
+	//print("algsym: %s -> %+S\n", p, s);
+	free(p);
+	return s;
+}
+
+Sym*
+typenamesym(Type *t)
+{
+	Sym *s;
+	Node *n;
+
+	if(t == T || (isptr[t->etype] && t->type == T) || isideal(t))
+		fatal("typename %T", t);
+	s = typesym(t);
+	if(s->def == N) {
+		n = nod(ONAME, N, N);
+		n->sym = s;
+		n->type = types[TUINT8];
+		n->addable = 1;
+		n->ullman = 1;
+		n->class = PEXTERN;
+		n->xoffset = 0;
+		n->typecheck = 1;
+		s->def = n;
+
+		signatlist = list(signatlist, typenod(t));
+	}
+	return s->def->sym;
+}
+
+Node*
+typename(Type *t)
+{
+	Sym *s;
+	Node *n;
+
+	s = typenamesym(t);
+	n = nod(OADDR, s->def, N);
+	n->type = ptrto(s->def->type);
+	n->addable = 1;
+	n->ullman = 2;
+	n->typecheck = 1;
+	return n;
+}
+
+static Sym*
+weaktypesym(Type *t)
+{
+	char *p;
+	Sym *s;
+
+	p = smprint("%-T", t);
+	s = pkglookup(p, weaktypepkg);
+	//print("weaktypesym: %s -> %+S\n", p, s);
+	free(p);
+	return s;
+}
+
+static Sym*
+dtypesym(Type *t)
+{
+	int ot, xt, n, isddd, dupok;
+	Sym *s, *s1, *s2, *s3, *s4, *slink;
+	Sig *a, *m;
+	Type *t1, *tbase, *t2;
+
+	// Replace byte, rune aliases with real type.
+	// They've been separate internally to make error messages
+	// better, but we have to merge them in the reflect tables.
+	if(t == bytetype || t == runetype)
+		t = types[t->etype];
+
+	if(isideal(t))
+		fatal("dtypesym %T", t);
+
+	s = typesym(t);
+	if(s->flags & SymSiggen)
+		return s;
+	s->flags |= SymSiggen;
+
+	// special case (look for runtime below):
+	// when compiling package runtime,
+	// emit the type structures for int, float, etc.
+	tbase = t;
+	if(isptr[t->etype] && t->sym == S && t->type->sym != S)
+		tbase = t->type;
+	dupok = 0;
+	if(tbase->sym == S)
+		dupok = DUPOK;
+
+	if(compiling_runtime &&
+			(tbase == types[tbase->etype] ||
+			tbase == bytetype ||
+			tbase == runetype ||
+			tbase == errortype)) { // int, float, etc
+		goto ok;
+	}
+
+	// named types from other files are defined only by those files
+	if(tbase->sym && !tbase->local)
+		return s;
+	if(isforw[tbase->etype])
+		return s;
+
+ok:
+	ot = 0;
+	xt = 0;
+	switch(t->etype) {
+	default:
+		ot = dcommontype(s, ot, t);
+		xt = ot - 3*widthptr;
+		break;
+
+	case TARRAY:
+		if(t->bound >= 0) {
+			// ../../runtime/type.go:/ArrayType
+			s1 = dtypesym(t->type);
+			t2 = typ(TARRAY);
+			t2->type = t->type;
+			t2->bound = -1;  // slice
+			s2 = dtypesym(t2);
+			ot = dcommontype(s, ot, t);
+			xt = ot - 3*widthptr;
+			ot = dsymptr(s, ot, s1, 0);
+			ot = dsymptr(s, ot, s2, 0);
+			ot = duintptr(s, ot, t->bound);
+		} else {
+			// ../../runtime/type.go:/SliceType
+			s1 = dtypesym(t->type);
+			ot = dcommontype(s, ot, t);
+			xt = ot - 3*widthptr;
+			ot = dsymptr(s, ot, s1, 0);
+		}
+		break;
+
+	case TCHAN:
+		// ../../runtime/type.go:/ChanType
+		s1 = dtypesym(t->type);
+		ot = dcommontype(s, ot, t);
+		xt = ot - 3*widthptr;
+		ot = dsymptr(s, ot, s1, 0);
+		ot = duintptr(s, ot, t->chan);
+		break;
+
+	case TFUNC:
+		for(t1=getthisx(t)->type; t1; t1=t1->down)
+			dtypesym(t1->type);
+		isddd = 0;
+		for(t1=getinargx(t)->type; t1; t1=t1->down) {
+			isddd = t1->isddd;
+			dtypesym(t1->type);
+		}
+		for(t1=getoutargx(t)->type; t1; t1=t1->down)
+			dtypesym(t1->type);
+
+		ot = dcommontype(s, ot, t);
+		xt = ot - 3*widthptr;
+		ot = duint8(s, ot, isddd);
+
+		// two slice headers: in and out.
+		ot = rnd(ot, widthptr);
+		ot = dsymptr(s, ot, s, ot+2*(widthptr+2*widthint));
+		n = t->thistuple + t->intuple;
+		ot = duintxx(s, ot, n, widthint);
+		ot = duintxx(s, ot, n, widthint);
+		ot = dsymptr(s, ot, s, ot+1*(widthptr+2*widthint)+n*widthptr);
+		ot = duintxx(s, ot, t->outtuple, widthint);
+		ot = duintxx(s, ot, t->outtuple, widthint);
+
+		// slice data
+		for(t1=getthisx(t)->type; t1; t1=t1->down, n++)
+			ot = dsymptr(s, ot, dtypesym(t1->type), 0);
+		for(t1=getinargx(t)->type; t1; t1=t1->down, n++)
+			ot = dsymptr(s, ot, dtypesym(t1->type), 0);
+		for(t1=getoutargx(t)->type; t1; t1=t1->down, n++)
+			ot = dsymptr(s, ot, dtypesym(t1->type), 0);
+		break;
+
+	case TINTER:
+		m = imethods(t);
+		n = 0;
+		for(a=m; a; a=a->link) {
+			dtypesym(a->type);
+			n++;
+		}
+
+		// ../../runtime/type.go:/InterfaceType
+		ot = dcommontype(s, ot, t);
+		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);
+		for(a=m; a; a=a->link) {
+			// ../../runtime/type.go:/imethod
+			ot = dgostringptr(s, ot, a->name);
+			ot = dgopkgpath(s, ot, a->pkg);
+			ot = dsymptr(s, ot, dtypesym(a->type), 0);
+		}
+		break;
+
+	case TMAP:
+		// ../../runtime/type.go:/MapType
+		s1 = dtypesym(t->down);
+		s2 = dtypesym(t->type);
+		s3 = dtypesym(mapbucket(t));
+		s4 = dtypesym(hmap(t));
+		ot = dcommontype(s, ot, t);
+		xt = ot - 3*widthptr;
+		ot = dsymptr(s, ot, s1, 0);
+		ot = dsymptr(s, ot, s2, 0);
+		ot = dsymptr(s, ot, s3, 0);
+		ot = dsymptr(s, ot, s4, 0);
+		if(t->down->width > MAXKEYSIZE) {
+			ot = duint8(s, ot, widthptr);
+			ot = duint8(s, ot, 1); // indirect
+		} else {
+			ot = duint8(s, ot, t->down->width);
+			ot = duint8(s, ot, 0); // not indirect
+		}
+		if(t->type->width > MAXVALSIZE) {
+			ot = duint8(s, ot, widthptr);
+			ot = duint8(s, ot, 1); // indirect
+		} else {
+			ot = duint8(s, ot, t->type->width);
+			ot = duint8(s, ot, 0); // not indirect
+		}
+		ot = duint16(s, ot, mapbucket(t)->width);
+		break;
+
+	case TPTR32:
+	case TPTR64:
+		if(t->type->etype == TANY) {
+			// ../../runtime/type.go:/UnsafePointerType
+			ot = dcommontype(s, ot, t);
+			break;
+		}
+		// ../../runtime/type.go:/PtrType
+		s1 = dtypesym(t->type);
+		ot = dcommontype(s, ot, t);
+		xt = ot - 3*widthptr;
+		ot = dsymptr(s, ot, s1, 0);
+		break;
+
+	case TSTRUCT:
+		// ../../runtime/type.go:/StructType
+		// for security, only the exported fields.
+		n = 0;
+		for(t1=t->type; t1!=T; t1=t1->down) {
+			dtypesym(t1->type);
+			n++;
+		}
+		ot = dcommontype(s, ot, t);
+		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);
+		for(t1=t->type; t1!=T; t1=t1->down) {
+			// ../../runtime/type.go:/structField
+			if(t1->sym && !t1->embedded) {
+				ot = dgostringptr(s, ot, t1->sym->name);
+				if(exportname(t1->sym->name))
+					ot = dgostringptr(s, ot, nil);
+				else
+					ot = dgopkgpath(s, ot, t1->sym->pkg);
+			} else {
+				ot = dgostringptr(s, ot, nil);
+				if(t1->type->sym != S && t1->type->sym->pkg == builtinpkg)
+					ot = dgopkgpath(s, ot, localpkg);
+				else
+					ot = dgostringptr(s, ot, nil);
+			}
+			ot = dsymptr(s, ot, dtypesym(t1->type), 0);
+			ot = dgostrlitptr(s, ot, t1->note);
+			ot = duintptr(s, ot, t1->width);	// field offset
+		}
+		break;
+	}
+	ot = dextratype(s, ot, t, xt);
+	ggloblsym(s, ot, dupok|RODATA);
+
+	// generate typelink.foo pointing at s = type.foo.
+	// The linker will leave a table of all the typelinks for
+	// types in the binary, so reflect can find them.
+	// We only need the link for unnamed composites that
+	// we want be able to find.
+	if(t->sym == S) {
+		switch(t->etype) {
+		case TARRAY:
+		case TCHAN:
+		case TMAP:
+			slink = typelinksym(t);
+			dsymptr(slink, 0, s, 0);
+			ggloblsym(slink, widthptr, dupok|RODATA);
+		}
+	}
+
+	return s;
+}
+
+void
+dumptypestructs(void)
+{
+	int i;
+	NodeList *l;
+	Node *n;
+	Type *t;
+	Pkg *p;
+
+	// copy types from externdcl list to signatlist
+	for(l=externdcl; l; l=l->next) {
+		n = l->n;
+		if(n->op != OTYPE)
+			continue;
+		signatlist = list(signatlist, n);
+	}
+
+	// process signatlist
+	for(l=signatlist; l; l=l->next) {
+		n = l->n;
+		if(n->op != OTYPE)
+			continue;
+		t = n->type;
+		dtypesym(t);
+		if(t->sym)
+			dtypesym(ptrto(t));
+	}
+
+	// generate import strings for imported packages
+	for(i=0; i<nelem(phash); i++)
+		for(p=phash[i]; p; p=p->link)
+			if(p->direct)
+				dimportpath(p);
+
+	// do basic types if compiling package runtime.
+	// they have to be in at least one package,
+	// and runtime is always loaded implicitly,
+	// so this is as good as any.
+	// another possible choice would be package main,
+	// but using runtime means fewer copies in .6 files.
+	if(compiling_runtime) {
+		for(i=1; i<=TBOOL; i++)
+			dtypesym(ptrto(types[i]));
+		dtypesym(ptrto(types[TSTRING]));
+		dtypesym(ptrto(types[TUNSAFEPTR]));
+
+		// emit type structs for error and func(error) string.
+		// The latter is the type of an auto-generated wrapper.
+		dtypesym(ptrto(errortype));
+		dtypesym(functype(nil,
+			list1(nod(ODCLFIELD, N, typenod(errortype))),
+			list1(nod(ODCLFIELD, N, typenod(types[TSTRING])))));
+
+		// add paths for runtime and main, which 6l imports implicitly.
+		dimportpath(runtimepkg);
+		if(flag_race)
+			dimportpath(racepkg);
+		dimportpath(mkpkg(strlit("main")));
+	}
+}
+
+static Sym*
+dalgsym(Type *t)
+{
+	int ot;
+	Sym *s, *hash, *hashfunc, *eq, *eqfunc;
+
+	// dalgsym is only called for a type that needs an algorithm table,
+	// which implies that the type is comparable (or else it would use ANOEQ).
+
+	s = typesymprefix(".alg", t);
+	hash = typesymprefix(".hash", t);
+	genhash(hash, t);
+	eq = typesymprefix(".eq", t);
+	geneq(eq, t);
+
+	// make Go funcs (closures) for calling hash and equal from Go
+	hashfunc = typesymprefix(".hashfunc", t);
+	dsymptr(hashfunc, 0, hash, 0);
+	ggloblsym(hashfunc, widthptr, DUPOK|RODATA);
+	eqfunc = typesymprefix(".eqfunc", t);
+	dsymptr(eqfunc, 0, eq, 0);
+	ggloblsym(eqfunc, widthptr, DUPOK|RODATA);
+
+	// ../../runtime/alg.go:/typeAlg
+	ot = 0;
+	ot = dsymptr(s, ot, hashfunc, 0);
+	ot = dsymptr(s, ot, eqfunc, 0);
+
+	ggloblsym(s, ot, DUPOK|RODATA);
+	return s;
+}
+
+static int
+usegcprog(Type *t)
+{
+	vlong size, nptr;
+
+	if(!haspointers(t))
+		return 0;
+	if(t->width == BADWIDTH)
+		dowidth(t);
+	// Calculate size of the unrolled GC mask.
+	nptr = (t->width+widthptr-1)/widthptr;
+	size = nptr;
+	if(size%2)
+		size *= 2;	// repeated
+	size = size*gcBits/8;	// 4 bits per word
+	// Decide whether to use unrolled GC mask or GC program.
+	// We could use a more elaborate condition, but this seems to work well in practice.
+	// For small objects GC program can't give significant reduction.
+	// While large objects usually contain arrays; and even if it don't
+	// the program uses 2-bits per word while mask uses 4-bits per word,
+	// so the program is still smaller.
+	return size > 2*widthptr;
+}
+
+// Generates sparse GC bitmask (4 bits per word).
+static void
+gengcmask(Type *t, uint8 gcmask[16])
+{
+	Bvec *vec;
+	vlong xoffset, nptr, i, j;
+	int  half, mw;
+	uint8 bits, *pos;
+
+	memset(gcmask, 0, 16);
+	if(!haspointers(t))
+		return;
+
+	// Generate compact mask as stacks use.
+	xoffset = 0;
+	vec = bvalloc(2*widthptr*8);
+	twobitwalktype1(t, &xoffset, vec);
+
+	// Unfold the mask for the GC bitmap format:
+	// 4 bits per word, 2 high bits encode pointer info.
+	pos = (uint8*)gcmask;
+	nptr = (t->width+widthptr-1)/widthptr;
+	half = 0;
+	mw = 0;
+	// If number of words is odd, repeat the mask.
+	// This makes simpler handling of arrays in runtime.
+	for(j=0; j<=(nptr%2); j++) {
+		for(i=0; i<nptr; i++) {
+			bits = bvget(vec, i*BitsPerPointer) | bvget(vec, i*BitsPerPointer+1)<<1;
+			// Some fake types (e.g. Hmap) has missing fileds.
+			// twobitwalktype1 generates BitsDead for that holes,
+			// replace BitsDead with BitsScalar.
+			if(!mw && bits == BitsDead)
+				bits = BitsScalar;
+			mw = !mw && bits == BitsMultiWord;
+			bits <<= 2;
+			if(half)
+				bits <<= 4;
+			*pos |= bits;
+			half = !half;
+			if(!half)
+				pos++;
+		}
+	}
+}
+
+// Helper object for generation of GC programs.
+typedef struct ProgGen ProgGen;
+struct ProgGen
+{
+	Sym*	s;
+	int32	datasize;
+	uint8	data[256/PointersPerByte];
+	vlong	ot;
+};
+
+static void
+proggeninit(ProgGen *g, Sym *s)
+{
+	g->s = s;
+	g->datasize = 0;
+	g->ot = 0;
+	memset(g->data, 0, sizeof(g->data));
+}
+
+static void
+proggenemit(ProgGen *g, uint8 v)
+{
+	g->ot = duint8(g->s, g->ot, v);
+}
+
+// Emits insData block from g->data.
+static void
+proggendataflush(ProgGen *g)
+{
+	int32 i, s;
+
+	if(g->datasize == 0)
+		return;
+	proggenemit(g, insData);
+	proggenemit(g, g->datasize);
+	s = (g->datasize + PointersPerByte - 1)/PointersPerByte;
+	for(i = 0; i < s; i++)
+		proggenemit(g, g->data[i]);
+	g->datasize = 0;
+	memset(g->data, 0, sizeof(g->data));
+}
+
+static void
+proggendata(ProgGen *g, uint8 d)
+{
+	g->data[g->datasize/PointersPerByte] |= d << ((g->datasize%PointersPerByte)*BitsPerPointer);
+	g->datasize++;
+	if(g->datasize == 255)
+		proggendataflush(g);
+}
+
+// Skip v bytes due to alignment, etc.
+static void
+proggenskip(ProgGen *g, vlong off, vlong v)
+{
+	vlong i;
+
+	for(i = off; i < off+v; i++) {
+		if((i%widthptr) == 0)
+			proggendata(g, BitsScalar);
+	}
+}
+
+// Emit insArray instruction.
+static void
+proggenarray(ProgGen *g, vlong len)
+{
+	int32 i;
+
+	proggendataflush(g);
+	proggenemit(g, insArray);
+	for(i = 0; i < widthptr; i++, len >>= 8)
+		proggenemit(g, len);
+}
+
+static void
+proggenarrayend(ProgGen *g)
+{
+	proggendataflush(g);
+	proggenemit(g, insArrayEnd);
+}
+
+static vlong
+proggenfini(ProgGen *g)
+{
+	proggendataflush(g);
+	proggenemit(g, insEnd);
+	return g->ot;
+}
+
+static void gengcprog1(ProgGen *g, Type *t, vlong *xoffset);
+
+// Generates GC program for large types.
+static void
+gengcprog(Type *t, Sym **pgc0, Sym **pgc1)
+{
+	Sym *gc0, *gc1;
+	vlong nptr, size, ot, xoffset;
+	ProgGen g;
+
+	nptr = (t->width+widthptr-1)/widthptr;
+	size = nptr;
+	if(size%2)
+		size *= 2;	// repeated twice
+	size = size*PointersPerByte/8;	// 4 bits per word
+	size++;	// unroll flag in the beginning, used by runtime (see runtime.markallocated)
+	// emity space in BSS for unrolled program
+	*pgc0 = S;
+	// Don't generate it if it's too large, runtime will unroll directly into GC bitmap.
+	if(size <= MaxGCMask) {
+		gc0 = typesymprefix(".gc", t);
+		ggloblsym(gc0, size, DUPOK|NOPTR);
+		*pgc0 = gc0;
+	}
+
+	// program in RODATA
+	gc1 = typesymprefix(".gcprog", t);
+	proggeninit(&g, gc1);
+	xoffset = 0;
+	gengcprog1(&g, t, &xoffset);
+	ot = proggenfini(&g);
+	ggloblsym(gc1, ot, DUPOK|RODATA);
+	*pgc1 = gc1;
+}
+
+// Recursively walks type t and writes GC program into g.
+static void
+gengcprog1(ProgGen *g, Type *t, vlong *xoffset)
+{
+	vlong fieldoffset, i, o, n;
+	Type *t1;
+
+	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:
+		proggenskip(g, *xoffset, t->width);
+		*xoffset += t->width;
+		break;
+	case TPTR32:
+	case TPTR64:
+	case TUNSAFEPTR:
+	case TFUNC:
+	case TCHAN:
+	case TMAP:
+		proggendata(g, BitsPointer);
+		*xoffset += t->width;
+		break;
+	case TSTRING:
+		proggendata(g, BitsPointer);
+		proggendata(g, BitsScalar);
+		*xoffset += t->width;
+		break;
+	case TINTER:
+		proggendata(g, BitsMultiWord);
+		if(isnilinter(t))
+			proggendata(g, BitsEface);
+		else
+			proggendata(g, BitsIface);
+		*xoffset += t->width;
+		break;
+	case TARRAY:
+		if(isslice(t)) {
+			proggendata(g, BitsPointer);
+			proggendata(g, BitsScalar);
+			proggendata(g, BitsScalar);
+		} else {
+			t1 = t->type;
+			if(t1->width == 0) {
+				// ignore
+			} if(t->bound <= 1 || t->bound*t1->width < 32*widthptr) {
+				for(i = 0; i < t->bound; i++)
+					gengcprog1(g, t1, xoffset);
+			} else if(!haspointers(t1)) {
+				n = t->width;
+				n -= -*xoffset&(widthptr-1); // skip to next ptr boundary
+				proggenarray(g, (n+widthptr-1)/widthptr);
+				proggendata(g, BitsScalar);
+				proggenarrayend(g);
+				*xoffset -= (n+widthptr-1)/widthptr*widthptr - t->width;
+			} else {
+				proggenarray(g, t->bound);
+				gengcprog1(g, t1, xoffset);
+				*xoffset += (t->bound-1)*t1->width;
+				proggenarrayend(g);
+			}
+		}
+		break;
+	case TSTRUCT:
+		o = 0;
+		for(t1 = t->type; t1 != T; t1 = t1->down) {
+			fieldoffset = t1->width;
+			proggenskip(g, *xoffset, fieldoffset - o);
+			*xoffset += fieldoffset - o;
+			gengcprog1(g, t1->type, xoffset);
+			o = fieldoffset + t1->type->width;
+		}
+		proggenskip(g, *xoffset, t->width - o);
+		*xoffset += t->width - o;
+		break;
+	default:
+		fatal("gengcprog1: unexpected type, %T", t);
+	}
+}
diff --git a/src/cmd/gc/runtime.go b/src/cmd/gc/runtime.go
new file mode 100644
index 0000000..0fb15c2
--- /dev/null
+++ b/src/cmd/gc/runtime.go
@@ -0,0 +1,164 @@
+// 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.
+
+// NOTE: If you change this file you must run "./mkbuiltin"
+// to update builtin.c.  This is not done automatically
+// to avoid depending on having a working compiler binary.
+
+// +build ignore
+
+package PACKAGE
+
+// emitted by compiler, not referred to by go programs
+
+func newobject(typ *byte) *any
+func panicindex()
+func panicslice()
+func panicdivide()
+func throwreturn()
+func throwinit()
+func panicwrap(string, string, string)
+
+func gopanic(interface{})
+func gorecover(*int32) interface{}
+
+func printbool(bool)
+func printfloat(float64)
+func printint(int64)
+func printhex(uint64)
+func printuint(uint64)
+func printcomplex(complex128)
+func printstring(string)
+func printpointer(any)
+func printiface(any)
+func printeface(any)
+func printslice(any)
+func printnl()
+func printsp()
+
+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
+func stringiter(string, int) int
+func stringiter2(string, int) (retk int, retv rune)
+func slicecopy(to any, fr any, wid uintptr) int
+func slicestringcopy(to any, fr any) int
+
+// interface conversions
+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)
+
+// interface type assertions  x.(T)
+func assertE2E(typ *byte, iface any) (ret any)
+func assertE2E2(typ *byte, iface any) (ret any, ok bool)
+func assertE2I(typ *byte, iface any) (ret any)
+func assertE2I2(typ *byte, iface any) (ret any, ok bool)
+func assertE2T(typ *byte, iface any) (ret any)
+func assertE2T2(typ *byte, iface any) (ret any, ok bool)
+func assertI2E(typ *byte, iface any) (ret any)
+func assertI2E2(typ *byte, iface any) (ret any, ok bool)
+func assertI2I(typ *byte, iface any) (ret any)
+func assertI2I2(typ *byte, iface any) (ret any, ok bool)
+func assertI2T(typ *byte, iface any) (ret any)
+func assertI2T2(typ *byte, iface any) (ret any, ok bool)
+func assertI2TOK(typ *byte, iface any) (ok bool)
+func assertE2TOK(typ *byte, iface any) (ok bool)
+
+func ifaceeq(i1 any, i2 any) (ret bool)
+func efaceeq(i1 any, i2 any) (ret bool)
+func ifacethash(i1 any) (ret uint32)
+func efacethash(i1 any) (ret uint32)
+
+// *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_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_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 mapiterinit(mapType *byte, hmap map[any]any, hiter *any)
+func mapdelete(mapType *byte, hmap map[any]any, key *any)
+func mapiternext(hiter *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) bool
+func chansend1(chanType *byte, hchan chan<- any, elem *any)
+func closechan(hchan any)
+
+// *byte is really *runtime.Type
+func writebarrierptr(dst *any, src any)
+func writebarrierstring(dst *any, src any)
+func writebarrierslice(dst *any, src any)
+func writebarrieriface(dst *any, src any)
+
+// The unused *byte argument makes sure that src is 2-pointer-aligned,
+// which is the maximum alignment on NaCl amd64p32
+// (and possibly on 32-bit systems if we start 64-bit aligning uint64s).
+func writebarrierfat2(dst *any, _ *byte, src any)
+func writebarrierfat3(dst *any, _ *byte, src any)
+func writebarrierfat4(dst *any, _ *byte, src any)
+func writebarrierfat(typ *byte, dst *any, src *any)
+
+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
+
+func newselect(sel *byte, selsize int64, size int32)
+func selectsend(sel *byte, hchan chan<- any, elem *any) (selected bool)
+func selectrecv(sel *byte, hchan <-chan any, elem *any) (selected bool)
+func selectrecv2(sel *byte, hchan <-chan any, elem *any, received *bool) (selected bool)
+func selectdefault(sel *byte) (selected bool)
+func selectgo(sel *byte)
+func block()
+
+func makeslice(typ *byte, nel int64, cap int64) (ary []any)
+func growslice(typ *byte, old []any, n int64) (ary []any)
+func memmove(to *any, frm *any, length uintptr)
+
+func memequal(x, y *any, size uintptr) bool
+func memequal8(x, y *any, size uintptr) bool
+func memequal16(x, y *any, size uintptr) bool
+func memequal32(x, y *any, size uintptr) bool
+func memequal64(x, y *any, size uintptr) bool
+func memequal128(x, y *any, size uintptr) bool
+
+// only used on 32-bit
+func int64div(int64, int64) int64
+func uint64div(uint64, uint64) uint64
+func int64mod(int64, int64) int64
+func uint64mod(uint64, uint64) uint64
+func float64toint64(float64) int64
+func float64touint64(float64) uint64
+func int64tofloat64(int64) float64
+func uint64tofloat64(uint64) float64
+
+func complex128div(num complex128, den complex128) (quo complex128)
+
+// race detection
+func racefuncenter(uintptr)
+func racefuncexit()
+func raceread(uintptr)
+func racewrite(uintptr)
+func racereadrange(addr, size uintptr)
+func racewriterange(addr, size uintptr)
diff --git a/src/cmd/gc/select.c b/src/cmd/gc/select.c
new file mode 100644
index 0000000..965ad27
--- /dev/null
+++ b/src/cmd/gc/select.c
@@ -0,0 +1,377 @@
+// 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.
+
+/*
+ * select
+ */
+
+#include <u.h>
+#include <libc.h>
+#include "go.h"
+
+static Type* selecttype(int32 size);
+
+void
+typecheckselect(Node *sel)
+{
+	Node *ncase, *n, *def;
+	NodeList *l;
+	int lno, count;
+
+	def = nil;
+	lno = setlineno(sel);
+	count = 0;
+	typechecklist(sel->ninit, Etop);
+	for(l=sel->list; l; l=l->next) {
+		count++;
+		ncase = l->n;
+		setlineno(ncase);
+		if(ncase->op != OXCASE)
+			fatal("typecheckselect %O", ncase->op);
+
+		if(ncase->list == nil) {
+			// default
+			if(def != N)
+				yyerror("multiple defaults in select (first at %L)", def->lineno);
+			else
+				def = ncase;
+		} else if(ncase->list->next) {
+			yyerror("select cases cannot be lists");
+		} else {
+			n = typecheck(&ncase->list->n, Etop);
+			ncase->left = n;
+			ncase->list = nil;
+			setlineno(n);
+			switch(n->op) {
+			default:
+				yyerror("select case must be receive, send or assign recv");
+				break;
+
+			case OAS:
+				// convert x = <-c into OSELRECV(x, <-c).
+				// remove implicit conversions; the eventual assignment
+				// will reintroduce them.
+				if((n->right->op == OCONVNOP || n->right->op == OCONVIFACE) && n->right->implicit)
+					n->right = n->right->left;
+
+				if(n->right->op != ORECV) {
+					yyerror("select assignment must have receive on right hand side");
+					break;
+				}
+				n->op = OSELRECV;
+				break;
+
+			case OAS2RECV:
+				// convert x, ok = <-c into OSELRECV2(x, <-c) with ntest=ok
+				if(n->rlist->n->op != ORECV) {
+					yyerror("select assignment must have receive on right hand side");
+					break;
+				}
+				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;
+
+			case ORECV:
+				// convert <-c into OSELRECV(N, <-c)
+				n = nod(OSELRECV, N, n);
+				n->typecheck = 1;
+				ncase->left = n;
+				break;
+
+			case OSEND:
+				break;
+			}
+		}
+		typechecklist(ncase->nbody, Etop);
+	}
+	sel->xoffset = count;
+	lineno = lno;
+}
+
+void
+walkselect(Node *sel)
+{
+	int lno, i;
+	Node *n, *r, *a, *var, *selv, *cas, *dflt, *ch;
+	NodeList *l, *init;
+	
+	if(sel->list == nil && sel->xoffset != 0)
+		fatal("double walkselect");	// already rewrote
+	
+	lno = setlineno(sel);
+	i = count(sel->list);
+	
+	// optimization: zero-case select
+	if(i == 0) {
+		sel->nbody = list1(mkcall("block", nil, nil));
+		goto out;
+	}
+
+	// optimization: one-case select: single op.
+	// TODO(rsc): Reenable optimization once order.c can handle it.
+	// golang.org/issue/7672.
+	if(i == 1) {
+		cas = sel->list->n;
+		setlineno(cas);
+		l = cas->ninit;
+		if(cas->left != N) {  // not default:
+			n = cas->left;
+			l = concat(l, n->ninit);
+			n->ninit = nil;
+			switch(n->op) {
+			default:
+				fatal("select %O", n->op);
+
+			case OSEND:
+				// ok already
+				ch = n->left;
+				break;
+
+			case OSELRECV:
+				ch = n->right->left;
+			Selrecv1:
+				if(n->left == N)
+					n = n->right;
+				else
+					n->op = OAS;
+				break;
+			
+			case OSELRECV2:
+				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;
+			}
+
+			// if ch == nil { block() }; n;
+			a = nod(OIF, N, N);
+			a->ntest = nod(OEQ, ch, nodnil());
+			a->nbody = list1(mkcall("block", nil, &l));
+			typecheck(&a, Etop);
+			l = list(l, a);
+			l = list(l, n);
+		}
+		l = concat(l, cas->nbody);
+		sel->nbody = l;
+		goto out;
+	}
+
+	// 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;
+		setlineno(cas);
+		n = cas->left;
+		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:
+			if(n->op == OSELRECV2 && n->ntest == N)
+				n->op = OSELRECV;
+			if(n->op == OSELRECV2) {
+				n->ntest = nod(OADDR, n->ntest, N);
+				typecheck(&n->ntest, Erv);
+			}
+			if(n->left == N)
+				n->left = nodnil();
+			else {
+				n->left = nod(OADDR, n->left, N);
+				typecheck(&n->left, Erv);
+			}			
+			break;
+		}
+	}
+
+	// optimization: two-case select but one is default: single non-blocking op.
+	if(i == 2 && (sel->list->n->left == nil || sel->list->next->n->left == nil)) {
+		if(sel->list->n->left == nil) {
+			cas = sel->list->next->n;
+			dflt = sel->list->n;
+		} else {
+			dflt = sel->list->next->n;
+			cas = sel->list->n;
+		}
+		
+		n = cas->left;
+		setlineno(n);
+		r = nod(OIF, N, N);
+		r->ninit = cas->ninit;
+		switch(n->op) {
+		default:
+			fatal("select %O", n->op);
+
+		case OSEND:
+			// 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;
+			
+		case OSELRECV:
+			// if c != nil && selectnbrecv(&v, c) { body } else { default body }
+			r = nod(OIF, N, N);
+			r->ninit = cas->ninit;
+			ch = n->right->left;
+			r->ntest = mkcall1(chanfn("selectnbrecv", 2, ch->type),
+					types[TBOOL], &r->ninit, typename(ch->type), n->left, ch);
+			break;
+
+		case OSELRECV2:
+			// if c != nil && selectnbrecv2(&v, c) { body } else { default body }
+			r = nod(OIF, N, N);
+			r->ninit = cas->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;
+		}
+		typecheck(&r->ntest, Erv);
+		r->nbody = cas->nbody;
+		r->nelse = concat(dflt->ninit, dflt->nbody);
+		sel->nbody = list1(r);
+		goto out;
+	}		
+
+	init = sel->ninit;
+	sel->ninit = nil;
+
+	// generate sel-struct
+	setlineno(sel);
+	selv = temp(selecttype(sel->xoffset));
+	r = nod(OAS, selv, N);
+	typecheck(&r, Etop);
+	init = list(init, r);
+	var = conv(conv(nod(OADDR, selv, N), types[TUNSAFEPTR]), ptrto(types[TUINT8]));
+	r = mkcall("newselect", T, nil, var, nodintconst(selv->type->width), nodintconst(sel->xoffset));
+	typecheck(&r, Etop);
+	init = list(init, r);
+
+	// register cases
+	for(l=sel->list; l; l=l->next) {
+		cas = l->n;
+		setlineno(cas);
+		n = cas->left;
+		r = nod(OIF, N, N);
+		r->ninit = cas->ninit;
+		cas->ninit = nil;
+		if(n != nil) {
+			r->ninit = concat(r->ninit, n->ninit);
+			n->ninit = nil;
+		}
+		if(n == nil) {
+			// selectdefault(sel *byte);
+			r->ntest = mkcall("selectdefault", types[TBOOL], &r->ninit, var);
+		} else {
+			switch(n->op) {
+			default:
+				fatal("select %O", n->op);
+	
+			case OSEND:
+				// selectsend(sel *byte, hchan *chan any, elem *any) (selected bool);
+				r->ntest = mkcall1(chanfn("selectsend", 2, n->left->type), types[TBOOL],
+					&r->ninit, var, n->left, n->right);
+				break;
+
+			case OSELRECV:
+				// selectrecv(sel *byte, hchan *chan any, elem *any) (selected bool);
+				r->ntest = mkcall1(chanfn("selectrecv", 2, n->right->left->type), types[TBOOL],
+					&r->ninit, var, n->right->left, n->left);
+				break;
+
+			case OSELRECV2:
+				// selectrecv2(sel *byte, hchan *chan any, elem *any, received *bool) (selected bool);
+				r->ntest = mkcall1(chanfn("selectrecv2", 2, n->right->left->type), types[TBOOL],
+					&r->ninit, var, n->right->left, n->left, n->ntest);
+				break;
+			}
+		}
+		// selv is no longer alive after use.
+		r->nbody = list(r->nbody, nod(OVARKILL, selv, N));
+		r->nbody = concat(r->nbody, cas->nbody);
+		r->nbody = list(r->nbody, nod(OBREAK, N, N));
+		init = list(init, r);
+	}
+
+	// run the select
+	setlineno(sel);
+	init = list(init, mkcall("selectgo", T, nil, var));
+	sel->nbody = init;
+
+out:
+	sel->list = nil;
+	walkstmtlist(sel->nbody);
+	lineno = lno;
+}
+
+// Keep in sync with src/runtime/chan.h.
+static Type*
+selecttype(int32 size)
+{
+	Node *sel, *sudog, *scase, *arr;
+
+	// TODO(dvyukov): it's possible to generate SudoG and Scase only once
+	// and then cache; and also cache Select per size.
+	sudog = nod(OTSTRUCT, N, N);
+	sudog->list = list(sudog->list, nod(ODCLFIELD, newname(lookup("g")), typenod(ptrto(types[TUINT8]))));
+	sudog->list = list(sudog->list, nod(ODCLFIELD, newname(lookup("selectdone")), typenod(ptrto(types[TUINT8]))));
+	sudog->list = list(sudog->list, nod(ODCLFIELD, newname(lookup("link")), typenod(ptrto(types[TUINT8]))));
+	sudog->list = list(sudog->list, nod(ODCLFIELD, newname(lookup("prev")), typenod(ptrto(types[TUINT8]))));
+	sudog->list = list(sudog->list, nod(ODCLFIELD, newname(lookup("elem")), typenod(ptrto(types[TUINT8]))));
+	sudog->list = list(sudog->list, nod(ODCLFIELD, newname(lookup("releasetime")), typenod(types[TUINT64])));
+	sudog->list = list(sudog->list, nod(ODCLFIELD, newname(lookup("nrelease")), typenod(types[TINT32])));
+	sudog->list = list(sudog->list, nod(ODCLFIELD, newname(lookup("waitlink")), typenod(ptrto(types[TUINT8]))));
+	typecheck(&sudog, Etype);
+	sudog->type->noalg = 1;
+	sudog->type->local = 1;
+
+	scase = nod(OTSTRUCT, N, N);
+	scase->list = list(scase->list, nod(ODCLFIELD, newname(lookup("elem")), typenod(ptrto(types[TUINT8]))));
+	scase->list = list(scase->list, nod(ODCLFIELD, newname(lookup("chan")), typenod(ptrto(types[TUINT8]))));
+	scase->list = list(scase->list, nod(ODCLFIELD, newname(lookup("pc")), typenod(types[TUINTPTR])));
+	scase->list = list(scase->list, nod(ODCLFIELD, newname(lookup("kind")), typenod(types[TUINT16])));
+	scase->list = list(scase->list, nod(ODCLFIELD, newname(lookup("so")), typenod(types[TUINT16])));
+	scase->list = list(scase->list, nod(ODCLFIELD, newname(lookup("receivedp")), typenod(ptrto(types[TUINT8]))));
+	scase->list = list(scase->list, nod(ODCLFIELD, newname(lookup("releasetime")), typenod(types[TUINT64])));
+	typecheck(&scase, Etype);
+	scase->type->noalg = 1;
+	scase->type->local = 1;
+
+	sel = nod(OTSTRUCT, N, N);
+	sel->list = list(sel->list, nod(ODCLFIELD, newname(lookup("tcase")), typenod(types[TUINT16])));
+	sel->list = list(sel->list, nod(ODCLFIELD, newname(lookup("ncase")), typenod(types[TUINT16])));
+	sel->list = list(sel->list, nod(ODCLFIELD, newname(lookup("pollorder")), typenod(ptrto(types[TUINT8]))));
+	sel->list = list(sel->list, nod(ODCLFIELD, newname(lookup("lockorder")), typenod(ptrto(types[TUINT8]))));
+	arr = nod(OTARRAY, nodintconst(size), scase);
+	sel->list = list(sel->list, nod(ODCLFIELD, newname(lookup("scase")), arr));
+	arr = nod(OTARRAY, nodintconst(size), typenod(ptrto(types[TUINT8])));
+	sel->list = list(sel->list, nod(ODCLFIELD, newname(lookup("lockorderarr")), arr));
+	arr = nod(OTARRAY, nodintconst(size), typenod(types[TUINT16]));
+	sel->list = list(sel->list, nod(ODCLFIELD, newname(lookup("pollorderarr")), arr));
+	typecheck(&sel, Etype);
+	sel->type->noalg = 1;
+	sel->type->local = 1;
+
+	return sel->type;
+}
diff --git a/src/cmd/gc/sinit.c b/src/cmd/gc/sinit.c
new file mode 100644
index 0000000..8ad7ae7
--- /dev/null
+++ b/src/cmd/gc/sinit.c
@@ -0,0 +1,1505 @@
+// 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.
+
+/*
+ * static initialization
+ */
+
+#include	<u.h>
+#include	<libc.h>
+#include	"go.h"
+
+enum
+{
+	InitNotStarted = 0,
+	InitDone = 1,
+	InitPending = 2,
+};
+
+static void initplan(Node*);
+static NodeList *initlist;
+static void init2(Node*, NodeList**);
+static void init2list(NodeList*, NodeList**);
+static int staticinit(Node*, NodeList**);
+static Node *staticname(Type*, int);
+
+// init1 walks the AST starting at n, and accumulates in out
+// the list of definitions needing init code in dependency order.
+static void
+init1(Node *n, NodeList **out)
+{
+	NodeList *l;
+	Node *nv;
+
+	if(n == N)
+		return;
+	init1(n->left, out);
+	init1(n->right, out);
+	for(l=n->list; l; l=l->next)
+		init1(l->n, out);
+
+	if(n->left && n->type && n->left->op == OTYPE && n->class == PFUNC) {
+		// Methods called as Type.Method(receiver, ...).
+		// Definitions for method expressions are stored in type->nname.
+		init1(n->type->nname, out);
+	}
+
+	if(n->op != ONAME)
+		return;
+	switch(n->class) {
+	case PEXTERN:
+	case PFUNC:
+		break;
+	default:
+		if(isblank(n) && n->curfn == N && n->defn != N && n->defn->initorder == InitNotStarted) {
+			// blank names initialization is part of init() but not
+			// when they are inside a function.
+			break;
+		}
+		return;
+	}
+
+	if(n->initorder == InitDone)
+		return;
+	if(n->initorder == InitPending) {
+		// Since mutually recursive sets of functions are allowed,
+		// we don't necessarily raise an error if n depends on a node
+		// which is already waiting for its dependencies to be visited.
+		//
+		// initlist contains a cycle of identifiers referring to each other.
+		// If this cycle contains a variable, then this variable refers to itself.
+		// Conversely, if there exists an initialization cycle involving
+		// a variable in the program, the tree walk will reach a cycle
+		// involving that variable.
+		if(n->class != PFUNC) {
+			nv = n;
+			goto foundinitloop;
+		}
+		for(l=initlist; l->n!=n; l=l->next) {
+			if(l->n->class != PFUNC) {
+				nv = l->n;
+				goto foundinitloop;
+			}
+		}
+		// The loop involves only functions, ok.
+		return;
+
+	foundinitloop:
+		// if there have already been errors printed,
+		// those errors probably confused us and
+		// there might not be a loop.  let the user
+		// fix those first.
+		flusherrors();
+		if(nerrors > 0)
+			errorexit();
+
+		// There is a loop involving nv. We know about
+		// n and initlist = n1 <- ... <- nv <- ... <- n <- ...
+		print("%L: initialization loop:\n", nv->lineno);
+		// Build back pointers in initlist.
+		for(l=initlist; l; l=l->next)
+			if(l->next != nil)
+				l->next->end = l;
+		// Print nv -> ... -> n1 -> n.
+		for(l=initlist; l->n!=nv; l=l->next);
+		for(; l; l=l->end)
+			print("\t%L %S refers to\n", l->n->lineno, l->n->sym);
+		// Print n -> ... -> nv.
+		for(l=initlist; l->n!=n; l=l->next);
+		for(; l->n != nv; l=l->end)
+			print("\t%L %S refers to\n", l->n->lineno, l->n->sym);
+		print("\t%L %S\n", nv->lineno, nv->sym);
+		errorexit();
+	}
+
+	// reached a new unvisited node.
+	n->initorder = InitPending;
+	l = malloc(sizeof *l);
+	if(l == nil) {
+		flusherrors();
+		yyerror("out of memory");
+		errorexit();
+	}
+	l->next = initlist;
+	l->n = n;
+	l->end = nil;
+	initlist = l;
+
+	// make sure that everything n depends on is initialized.
+	// n->defn is an assignment to n
+	if(n->defn != N) {
+		switch(n->defn->op) {
+		default:
+			goto bad;
+
+		case ODCLFUNC:
+			init2list(n->defn->nbody, out);
+			break;
+
+		case OAS:
+			if(n->defn->left != n)
+				goto bad;
+			if(isblank(n->defn->left) && candiscard(n->defn->right)) {
+				n->defn->op = OEMPTY;
+				n->defn->left = N;
+				n->defn->right = N;
+				break;
+			}
+
+			init2(n->defn->right, out);
+			if(debug['j'])
+				print("%S\n", n->sym);
+			if(isblank(n) || !staticinit(n, out)) {
+				if(debug['%'])
+					dump("nonstatic", n->defn);
+				*out = list(*out, n->defn);
+			}
+			break;
+
+		case OAS2FUNC:
+		case OAS2MAPR:
+		case OAS2DOTTYPE:
+		case OAS2RECV:
+			if(n->defn->initorder != InitNotStarted)
+				break;
+			n->defn->initorder = InitDone;
+			for(l=n->defn->rlist; l; l=l->next)
+				init1(l->n, out);
+			if(debug['%']) dump("nonstatic", n->defn);
+			*out = list(*out, n->defn);
+			break;
+		}
+	}
+	l = initlist;
+	initlist = l->next;
+	if(l->n != n)
+		fatal("bad initlist");
+	free(l);
+	n->initorder = InitDone;
+	return;
+
+bad:
+	dump("defn", n->defn);
+	fatal("init1: bad defn");
+}
+
+// recurse over n, doing init1 everywhere.
+static void
+init2(Node *n, NodeList **out)
+{
+	if(n == N || n->initorder == InitDone)
+		return;
+
+	if(n->op == ONAME && n->ninit)
+		fatal("name %S with ninit: %+N\n", n->sym, n);
+
+	init1(n, out);
+	init2(n->left, out);
+	init2(n->right, out);
+	init2(n->ntest, out);
+	init2list(n->ninit, out);
+	init2list(n->list, out);
+	init2list(n->rlist, out);
+	init2list(n->nbody, out);
+	init2list(n->nelse, out);
+	
+	if(n->op == OCLOSURE)
+		init2list(n->closure->nbody, out);
+	if(n->op == ODOTMETH || n->op == OCALLPART)
+		init2(n->type->nname, out);
+}
+
+static void
+init2list(NodeList *l, NodeList **out)
+{
+	for(; l; l=l->next)
+		init2(l->n, out);
+}
+
+static void
+initreorder(NodeList *l, NodeList **out)
+{
+	Node *n;
+
+	for(; l; l=l->next) {
+		n = l->n;
+		switch(n->op) {
+		case ODCLFUNC:
+		case ODCLCONST:
+		case ODCLTYPE:
+			continue;
+		}
+		initreorder(n->ninit, out);
+		n->ninit = nil;
+		init1(n, out);
+	}
+}
+
+// initfix computes initialization order for a list l of top-level
+// declarations and outputs the corresponding list of statements
+// to include in the init() function body.
+NodeList*
+initfix(NodeList *l)
+{
+	NodeList *lout;
+	int lno;
+
+	lout = nil;
+	lno = lineno;
+	initreorder(l, &lout);
+	lineno = lno;
+	return lout;
+}
+
+/*
+ * compilation of top-level (static) assignments
+ * into DATA statements if at all possible.
+ */
+
+static int staticassign(Node*, Node*, NodeList**);
+
+static int
+staticinit(Node *n, NodeList **out)
+{
+	Node *l, *r;
+
+	if(n->op != ONAME || n->class != PEXTERN || n->defn == N || n->defn->op != OAS)
+		fatal("staticinit");
+
+	lineno = n->lineno;
+	l = n->defn->left;
+	r = n->defn->right;
+	return staticassign(l, r, out);
+}
+
+// like staticassign but we are copying an already
+// initialized value r.
+static int
+staticcopy(Node *l, Node *r, NodeList **out)
+{
+	int i;
+	InitEntry *e;
+	InitPlan *p;
+	Node *a, *ll, *rr, *orig, n1;
+
+	if(r->op != ONAME || r->class != PEXTERN || r->sym->pkg != localpkg)
+		return 0;
+	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;
+	r = r->defn->right;
+	
+	switch(r->op) {
+	case ONAME:
+		if(staticcopy(l, r, out))
+			return 1;
+		*out = list(*out, nod(OAS, l, r));
+		return 1;
+	
+	case OLITERAL:
+		if(iszero(r))
+			return 1;
+		gdata(l, r, l->type->width);
+		return 1;
+
+	case OADDR:
+		switch(r->left->op) {
+		case ONAME:
+			gdata(l, r, l->type->width);
+			return 1;
+		}
+		break;
+	
+	case OPTRLIT:
+		switch(r->left->op) {
+		default:
+			//dump("not static addr", r);
+			break;
+		case OARRAYLIT:
+		case OSTRUCTLIT:
+		case OMAPLIT:
+			// copy pointer
+			gdata(l, nod(OADDR, r->nname, N), l->type->width);
+			return 1;
+		}
+		break;
+
+	case OARRAYLIT:
+		if(isslice(r->type)) {
+			// copy slice
+			a = r->nname;
+			n1 = *l;
+			n1.xoffset = l->xoffset + Array_array;
+			gdata(&n1, nod(OADDR, a, N), widthptr);
+			n1.xoffset = l->xoffset + Array_nel;
+			gdata(&n1, r->right, widthint);
+			n1.xoffset = l->xoffset + Array_cap;
+			gdata(&n1, r->right, widthint);
+			return 1;
+		}
+		// fall through
+	case OSTRUCTLIT:
+		p = r->initplan;
+		n1 = *l;
+		for(i=0; i<p->len; i++) {
+			e = &p->e[i];
+			n1.xoffset = l->xoffset + e->xoffset;
+			n1.type = e->expr->type;
+			if(e->expr->op == OLITERAL)
+				gdata(&n1, e->expr, n1.type->width);
+			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));
+				}
+			}
+		}
+		return 1;
+	}
+	return 0;
+}
+
+static int
+staticassign(Node *l, Node *r, NodeList **out)
+{
+	Node *a, n1;
+	Type *ta;
+	InitPlan *p;
+	InitEntry *e;
+	int i;
+	Strlit *sval;
+	
+	switch(r->op) {
+	default:
+		//dump("not static", r);
+		break;
+	
+	case ONAME:
+		if(r->class == PEXTERN && r->sym->pkg == localpkg)
+			return staticcopy(l, r, out);
+		break;
+
+	case OLITERAL:
+		if(iszero(r))
+			return 1;
+		gdata(l, r, l->type->width);
+		return 1;
+
+	case OADDR:
+		switch(r->left->op) {
+		default:
+			//dump("not static addr", r);
+			break;
+
+		case ONAME:
+			gdata(l, r, l->type->width);
+			return 1;
+		}
+	
+	case OPTRLIT:
+		switch(r->left->op) {
+		default:
+			//dump("not static ptrlit", r);
+			break;
+
+		case OARRAYLIT:
+		case OMAPLIT:
+		case OSTRUCTLIT:
+			// Init pointer.
+			a = staticname(r->left->type, 1);
+			r->nname = a;
+			gdata(l, nod(OADDR, a, N), l->type->width);
+			// Init underlying literal.
+			if(!staticassign(a, r->left, out))
+				*out = list(*out, nod(OAS, a, r->left));
+			return 1;
+		}
+		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)) {
+			// Init slice.
+			ta = typ(TARRAY);
+			ta->type = r->type->type;
+			ta->bound = mpgetfix(r->right->val.u.xval);
+			a = staticname(ta, 1);
+			r->nname = a;
+			n1 = *l;
+			n1.xoffset = l->xoffset + Array_array;
+			gdata(&n1, nod(OADDR, a, N), widthptr);
+			n1.xoffset = l->xoffset + Array_nel;
+			gdata(&n1, r->right, widthint);
+			n1.xoffset = l->xoffset + Array_cap;
+			gdata(&n1, r->right, widthint);
+			// Fall through to init underlying array.
+			l = a;
+		}
+		// fall through
+	case OSTRUCTLIT:
+		initplan(r);
+		p = r->initplan;
+		n1 = *l;
+		for(i=0; i<p->len; i++) {
+			e = &p->e[i];
+			n1.xoffset = l->xoffset + e->xoffset;
+			n1.type = e->expr->type;
+			if(e->expr->op == OLITERAL)
+				gdata(&n1, e->expr, n1.type->width);
+			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));
+			}
+		}
+		return 1;
+
+	case OMAPLIT:
+		// TODO: Table-driven map insert.
+		break;
+	}
+	return 0;
+}
+
+/*
+ * from here down is the walk analysis
+ * of composite literals.
+ * most of the work is to generate
+ * data statements for the constant
+ * part of the composite literal.
+ */
+
+static	void	structlit(int ctxt, int pass, Node *n, Node *var, NodeList **init);
+static	void	arraylit(int ctxt, int pass, Node *n, Node *var, NodeList **init);
+static	void	slicelit(int ctxt, Node *n, Node *var, NodeList **init);
+static	void	maplit(int ctxt, Node *n, Node *var, NodeList **init);
+
+static Node*
+staticname(Type *t, int ctxt)
+{
+	Node *n;
+
+	snprint(namebuf, sizeof(namebuf), "statictmp_%.4d", statuniqgen);
+	statuniqgen++;
+	n = newname(lookup(namebuf));
+	if(!ctxt)
+		n->readonly = 1;
+	addvar(n, t, PEXTERN);
+	return n;
+}
+
+static int
+isliteral(Node *n)
+{
+	if(n->op == OLITERAL)
+		if(n->val.ctype != CTNIL)
+			return 1;
+	return 0;
+}
+
+static int
+simplename(Node *n)
+{
+	if(n->op != ONAME)
+		goto no;
+	if(!n->addable)
+		goto no;
+	if(n->class & PHEAP)
+		goto no;
+	if(n->class == PPARAMREF)
+		goto no;
+	return 1;
+
+no:
+	return 0;
+}
+
+static void
+litas(Node *l, Node *r, NodeList **init)
+{
+	Node *a;
+
+	a = nod(OAS, l, r);
+	typecheck(&a, Etop);
+	walkexpr(&a, init);
+	*init = list(*init, a);
+}
+
+enum
+{
+	MODEDYNAM	= 1,
+	MODECONST	= 2,
+};
+
+static int
+getdyn(Node *n, int top)
+{
+	NodeList *nl;
+	Node *value;
+	int mode;
+
+	mode = 0;
+	switch(n->op) {
+	default:
+		if(isliteral(n))
+			return MODECONST;
+		return MODEDYNAM;
+	case OARRAYLIT:
+		if(!top && n->type->bound < 0)
+			return MODEDYNAM;
+	case OSTRUCTLIT:
+		break;
+	}
+
+	for(nl=n->list; nl; nl=nl->next) {
+		value = nl->n->right;
+		mode |= getdyn(value, 0);
+		if(mode == (MODEDYNAM|MODECONST))
+			break;
+	}
+	return mode;
+}
+
+static void
+structlit(int ctxt, int pass, Node *n, Node *var, NodeList **init)
+{
+	Node *r, *a;
+	NodeList *nl;
+	Node *index, *value;
+
+	for(nl=n->list; nl; nl=nl->next) {
+		r = nl->n;
+		if(r->op != OKEY)
+			fatal("structlit: rhs not OKEY: %N", r);
+		index = r->left;
+		value = r->right;
+
+		switch(value->op) {
+		case OARRAYLIT:
+			if(value->type->bound < 0) {
+				if(pass == 1 && ctxt != 0) {
+					a = nod(ODOT, var, newname(index->sym));
+					slicelit(ctxt, value, a, init);
+				} else
+				if(pass == 2 && ctxt == 0) {
+					a = nod(ODOT, var, newname(index->sym));
+					slicelit(ctxt, value, a, init);
+				} else
+				if(pass == 3)
+					break;
+				continue;
+			}
+			a = nod(ODOT, var, newname(index->sym));
+			arraylit(ctxt, pass, value, a, init);
+			continue;
+
+		case OSTRUCTLIT:
+			a = nod(ODOT, var, newname(index->sym));
+			structlit(ctxt, pass, value, a, init);
+			continue;
+		}
+
+		if(isliteral(value)) {
+			if(pass == 2)
+				continue;
+		} else
+			if(pass == 1)
+				continue;
+
+		// build list of var.field = expr
+		a = nod(ODOT, var, newname(index->sym));
+		a = nod(OAS, a, value);
+		typecheck(&a, Etop);
+		if(pass == 1) {
+			walkexpr(&a, init);	// add any assignments in r to top
+			if(a->op != OAS)
+				fatal("structlit: not as");
+			a->dodata = 2;
+		} else {
+			orderstmtinplace(&a);
+			walkstmt(&a);
+		}
+		*init = list(*init, a);
+	}
+}
+
+static void
+arraylit(int ctxt, int pass, Node *n, Node *var, NodeList **init)
+{
+	Node *r, *a;
+	NodeList *l;
+	Node *index, *value;
+
+	for(l=n->list; l; l=l->next) {
+		r = l->n;
+		if(r->op != OKEY)
+			fatal("arraylit: rhs not OKEY: %N", r);
+		index = r->left;
+		value = r->right;
+
+		switch(value->op) {
+		case OARRAYLIT:
+			if(value->type->bound < 0) {
+				if(pass == 1 && ctxt != 0) {
+					a = nod(OINDEX, var, index);
+					slicelit(ctxt, value, a, init);
+				} else
+				if(pass == 2 && ctxt == 0) {
+					a = nod(OINDEX, var, index);
+					slicelit(ctxt, value, a, init);
+				} else
+				if(pass == 3)
+					break;
+				continue;
+			}
+			a = nod(OINDEX, var, index);
+			arraylit(ctxt, pass, value, a, init);
+			continue;
+
+		case OSTRUCTLIT:
+			a = nod(OINDEX, var, index);
+			structlit(ctxt, pass, value, a, init);
+			continue;
+		}
+
+		if(isliteral(index) && isliteral(value)) {
+			if(pass == 2)
+				continue;
+		} else
+			if(pass == 1)
+				continue;
+
+		// build list of var[index] = value
+		a = nod(OINDEX, var, index);
+		a = nod(OAS, a, value);
+		typecheck(&a, Etop);
+		if(pass == 1) {
+			walkexpr(&a, init);
+			if(a->op != OAS)
+				fatal("arraylit: not as");
+			a->dodata = 2;
+		} else {
+			orderstmtinplace(&a);
+			walkstmt(&a);
+		}
+		*init = list(*init, a);
+	}
+}
+
+static void
+slicelit(int ctxt, Node *n, Node *var, NodeList **init)
+{
+	Node *r, *a;
+	NodeList *l;
+	Type *t;
+	Node *vstat, *vauto;
+	Node *index, *value;
+	int mode;
+
+	// make an array type
+	t = shallow(n->type);
+	t->bound = mpgetfix(n->right->val.u.xval);
+	t->width = 0;
+	t->sym = nil;
+	t->haspointers = 0;
+	dowidth(t);
+
+	if(ctxt != 0) {
+		// put everything into static array
+		vstat = staticname(t, ctxt);
+		arraylit(ctxt, 1, n, vstat, init);
+		arraylit(ctxt, 2, n, vstat, init);
+
+		// copy static to slice
+		a = nod(OSLICE, vstat, nod(OKEY, N, N));
+		a = nod(OAS, var, a);
+		typecheck(&a, Etop);
+		a->dodata = 2;
+		*init = list(*init, a);
+		return;
+	}
+
+	// recipe for var = []t{...}
+	// 1. make a static array
+	//	var vstat [...]t
+	// 2. assign (data statements) the constant part
+	//	vstat = constpart{}
+	// 3. make an auto pointer to array and allocate heap to it
+	//	var vauto *[...]t = new([...]t)
+	// 4. copy the static array to the auto array
+	//	*vauto = vstat
+	// 5. assign slice of allocated heap to var
+	//	var = [0:]*auto
+	// 6. for each dynamic part assign to the slice
+	//	var[i] = dynamic part
+	//
+	// an optimization is done if there is no constant part
+	//	3. var vauto *[...]t = new([...]t)
+	//	5. var = [0:]*auto
+	//	6. var[i] = dynamic part
+
+	// if the literal contains constants,
+	// make static initialized array (1),(2)
+	vstat = N;
+	mode = getdyn(n, 1);
+	if(mode & MODECONST) {
+		vstat = staticname(t, ctxt);
+		arraylit(ctxt, 1, n, vstat, init);
+	}
+
+	// make new auto *array (3 declare)
+	vauto = temp(ptrto(t));
+
+	// set auto to point at new temp or heap (3 assign)
+	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));
+	}
+	a = nod(OAS, vauto, a);
+	typecheck(&a, Etop);
+	walkexpr(&a, init);
+	*init = list(*init, a);
+
+	if(vstat != N) {
+		// copy static to heap (4)
+		a = nod(OIND, vauto, N);
+		a = nod(OAS, a, vstat);
+		typecheck(&a, Etop);
+		walkexpr(&a, init);
+		*init = list(*init, a);
+	}
+
+	// make slice out of heap (5)
+	a = nod(OAS, var, nod(OSLICE, vauto, nod(OKEY, N, N)));
+	typecheck(&a, Etop);
+	orderstmtinplace(&a);
+	walkstmt(&a);
+	*init = list(*init, a);
+
+	// put dynamics into slice (6)
+	for(l=n->list; l; l=l->next) {
+		r = l->n;
+		if(r->op != OKEY)
+			fatal("slicelit: rhs not OKEY: %N", r);
+		index = r->left;
+		value = r->right;
+		a = nod(OINDEX, var, index);
+		a->bounded = 1;
+		// TODO need to check bounds?
+
+		switch(value->op) {
+		case OARRAYLIT:
+			if(value->type->bound < 0)
+				break;
+			arraylit(ctxt, 2, value, a, init);
+			continue;
+
+		case OSTRUCTLIT:
+			structlit(ctxt, 2, value, a, init);
+			continue;
+		}
+
+		if(isliteral(index) && isliteral(value))
+			continue;
+
+		// build list of var[c] = expr
+		a = nod(OAS, a, value);
+		typecheck(&a, Etop);
+		orderstmtinplace(&a);
+		walkstmt(&a);
+		*init = list(*init, a);
+	}
+}
+
+static void
+maplit(int ctxt, Node *n, Node *var, NodeList **init)
+{
+	Node *r, *a;
+	NodeList *l;
+	int nerr;
+	int64 b;
+	Type *t, *tk, *tv, *t1;
+	Node *vstat, *index, *value, *key, *val;
+	Sym *syma, *symb;
+
+USED(ctxt);
+ctxt = 0;
+
+	// make the map var
+	nerr = nerrors;
+
+	a = nod(OMAKE, N, N);
+	a->list = list1(typenod(n->type));
+	litas(var, a, init);
+
+	// count the initializers
+	b = 0;
+	for(l=n->list; l; l=l->next) {
+		r = l->n;
+
+		if(r->op != OKEY)
+			fatal("maplit: rhs not OKEY: %N", r);
+		index = r->left;
+		value = r->right;
+
+		if(isliteral(index) && isliteral(value))
+			b++;
+	}
+
+	if(b != 0) {
+		// build type [count]struct { a Tindex, b Tvalue }
+		t = n->type;
+		tk = t->down;
+		tv = t->type;
+
+		symb = lookup("b");
+		t = typ(TFIELD);
+		t->type = tv;
+		t->sym = symb;
+
+		syma = lookup("a");
+		t1 = t;
+		t = typ(TFIELD);
+		t->type = tk;
+		t->sym = syma;
+		t->down = t1;
+
+		t1 = t;
+		t = typ(TSTRUCT);
+		t->type = t1;
+
+		t1 = t;
+		t = typ(TARRAY);
+		t->bound = b;
+		t->type = t1;
+
+		dowidth(t);
+
+		// make and initialize static array
+		vstat = staticname(t, ctxt);
+		b = 0;
+		for(l=n->list; l; l=l->next) {
+			r = l->n;
+
+			if(r->op != OKEY)
+				fatal("maplit: rhs not OKEY: %N", r);
+			index = r->left;
+			value = r->right;
+
+			if(isliteral(index) && isliteral(value)) {
+				// build vstat[b].a = key;
+				a = nodintconst(b);
+				a = nod(OINDEX, vstat, a);
+				a = nod(ODOT, a, newname(syma));
+				a = nod(OAS, a, index);
+				typecheck(&a, Etop);
+				walkexpr(&a, init);
+				a->dodata = 2;
+				*init = list(*init, a);
+
+				// build vstat[b].b = value;
+				a = nodintconst(b);
+				a = nod(OINDEX, vstat, a);
+				a = nod(ODOT, a, newname(symb));
+				a = nod(OAS, a, value);
+				typecheck(&a, Etop);
+				walkexpr(&a, init);
+				a->dodata = 2;
+				*init = list(*init, a);
+
+				b++;
+			}
+		}
+
+		// loop adding structure elements to map
+		// for i = 0; i < len(vstat); i++ {
+		//	map[vstat[i].a] = vstat[i].b
+		// }
+		index = temp(types[TINT]);
+
+		a = nod(OINDEX, vstat, index);
+		a->bounded = 1;
+		a = nod(ODOT, a, newname(symb));
+
+		r = nod(OINDEX, vstat, index);
+		r->bounded = 1;
+		r = nod(ODOT, r, newname(syma));
+		r = nod(OINDEX, var, r);
+
+		r = nod(OAS, r, a);
+
+		a = nod(OFOR, N, N);
+		a->nbody = list1(r);
+
+		a->ninit = list1(nod(OAS, index, nodintconst(0)));
+		a->ntest = nod(OLT, index, nodintconst(t->bound));
+		a->nincr = nod(OAS, index, nod(OADD, index, nodintconst(1)));
+
+		typecheck(&a, Etop);
+		walkstmt(&a);
+		*init = list(*init, a);
+	}
+
+	// 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("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);
+
+		a = nod(OAS, nod(OINDEX, var, key), val);
+		typecheck(&a, Etop);
+		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);
+	}
+}
+
+void
+anylit(int ctxt, Node *n, Node *var, NodeList **init)
+{
+	Type *t;
+	Node *a, *vstat, *r;
+
+	t = n->type;
+	switch(n->op) {
+	default:
+		fatal("anylit: not lit");
+
+	case OPTRLIT:
+		if(!isptr[t->etype])
+			fatal("anylit: not ptr");
+
+		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);
+		*init = list(*init, a);
+
+		var = nod(OIND, var, N);
+		typecheck(&var, Erv | Easgn);
+		anylit(ctxt, n->left, var, init);
+		break;
+
+	case OSTRUCTLIT:
+		if(t->etype != TSTRUCT)
+			fatal("anylit: not struct");
+
+		if(simplename(var) && count(n->list) > 4) {
+
+			if(ctxt == 0) {
+				// lay out static data
+				vstat = staticname(t, ctxt);
+				structlit(ctxt, 1, n, vstat, init);
+
+				// copy static to var
+				a = nod(OAS, var, vstat);
+				typecheck(&a, Etop);
+				walkexpr(&a, init);
+				*init = list(*init, a);
+
+				// add expressions to automatic
+				structlit(ctxt, 2, n, var, init);
+				break;
+			}
+			structlit(ctxt, 1, n, var, init);
+			structlit(ctxt, 2, n, var, init);
+			break;
+		}
+
+		// initialize of not completely specified
+		if(simplename(var) || count(n->list) < structcount(t)) {
+			a = nod(OAS, var, N);
+			typecheck(&a, Etop);
+			walkexpr(&a, init);
+			*init = list(*init, a);
+		}
+		structlit(ctxt, 3, n, var, init);
+		break;
+
+	case OARRAYLIT:
+		if(t->etype != TARRAY)
+			fatal("anylit: not array");
+		if(t->bound < 0) {
+			slicelit(ctxt, n, var, init);
+			break;
+		}
+
+		if(simplename(var) && count(n->list) > 4) {
+
+			if(ctxt == 0) {
+				// lay out static data
+				vstat = staticname(t, ctxt);
+				arraylit(1, 1, n, vstat, init);
+
+				// copy static to automatic
+				a = nod(OAS, var, vstat);
+				typecheck(&a, Etop);
+				walkexpr(&a, init);
+				*init = list(*init, a);
+
+				// add expressions to automatic
+				arraylit(ctxt, 2, n, var, init);
+				break;
+			}
+			arraylit(ctxt, 1, n, var, init);
+			arraylit(ctxt, 2, n, var, init);
+			break;
+		}
+
+		// initialize of not completely specified
+		if(simplename(var) || count(n->list) < t->bound) {
+			a = nod(OAS, var, N);
+			typecheck(&a, Etop);
+			walkexpr(&a, init);
+			*init = list(*init, a);
+		}
+		arraylit(ctxt, 3, n, var, init);
+		break;
+
+	case OMAPLIT:
+		if(t->etype != TMAP)
+			fatal("anylit: not map");
+		maplit(ctxt, n, var, init);
+		break;
+	}
+}
+
+int
+oaslit(Node *n, NodeList **init)
+{
+	int ctxt;
+
+	if(n->left == N || n->right == N)
+		goto no;
+	if(n->left->type == T || n->right->type == T)
+		goto no;
+	if(!simplename(n->left))
+		goto no;
+	if(!eqtype(n->left->type, n->right->type))
+		goto no;
+
+	// context is init() function.
+	// implies generated data executed
+	// exactly once and not subject to races.
+	ctxt = 0;
+//	if(n->dodata == 1)
+//		ctxt = 1;
+
+	switch(n->right->op) {
+	default:
+		goto no;
+
+	case OSTRUCTLIT:
+	case OARRAYLIT:
+	case OMAPLIT:
+		if(vmatch1(n->left, n->right))
+			goto no;
+		anylit(ctxt, n->right, n->left, init);
+		break;
+	}
+	n->op = OEMPTY;
+	return 1;
+
+no:
+	// not a special composit literal assignment
+	return 0;
+}
+
+static int
+getlit(Node *lit)
+{
+	if(smallintconst(lit))
+		return mpgetfix(lit->val.u.xval);
+	return -1;
+}
+
+int
+stataddr(Node *nam, Node *n)
+{
+	int l;
+
+	if(n == N)
+		goto no;
+
+	switch(n->op) {
+
+	case ONAME:
+		*nam = *n;
+		return n->addable;
+
+	case ODOT:
+		if(!stataddr(nam, n->left))
+			break;
+		nam->xoffset += n->xoffset;
+		nam->type = n->type;
+		return 1;
+
+	case OINDEX:
+		if(n->left->type->bound < 0)
+			break;
+		if(!stataddr(nam, n->left))
+			break;
+		l = getlit(n->right);
+		if(l < 0)
+			break;
+		// Check for overflow.
+		if(n->type->width != 0 && MAXWIDTH/n->type->width <= l)
+			break;
+ 		nam->xoffset += l*n->type->width;
+		nam->type = n->type;
+		return 1;
+	}
+
+no:
+	return 0;
+}
+
+int
+gen_as_init(Node *n)
+{
+	Node *nr, *nl;
+	Node nam, nod1;
+
+	if(n->dodata == 0)
+		goto no;
+
+	nr = n->right;
+	nl = n->left;
+	if(nr == N) {
+		if(!stataddr(&nam, nl))
+			goto no;
+		if(nam.class != PEXTERN)
+			goto no;
+		goto yes;
+	}
+
+	if(nr->type == T || !eqtype(nl->type, nr->type))
+		goto no;
+
+	if(!stataddr(&nam, nl))
+		goto no;
+
+	if(nam.class != PEXTERN)
+		goto no;
+
+	switch(nr->op) {
+	default:
+		goto no;
+
+	case OCONVNOP:
+		nr = nr->left;
+		if(nr == N || nr->op != OSLICEARR)
+			goto no;
+		// fall through
+	
+	case OSLICEARR:
+		if(nr->right->op == OKEY && nr->right->left == N && nr->right->right == N) {
+			nr = nr->left;
+			goto slice;
+		}
+		goto no;
+
+	case OLITERAL:
+		break;
+	}
+
+	switch(nr->type->etype) {
+	default:
+		goto no;
+
+	case TBOOL:
+	case TINT8:
+	case TUINT8:
+	case TINT16:
+	case TUINT16:
+	case TINT32:
+	case TUINT32:
+	case TINT64:
+	case TUINT64:
+	case TINT:
+	case TUINT:
+	case TUINTPTR:
+	case TPTR32:
+	case TPTR64:
+	case TFLOAT32:
+	case TFLOAT64:
+		gdata(&nam, nr, nr->type->width);
+		break;
+
+	case TCOMPLEX64:
+	case TCOMPLEX128:
+		gdatacomplex(&nam, nr->val.u.cval);
+		break;
+
+	case TSTRING:
+		gdatastring(&nam, nr->val.u.sval);
+		break;
+	}
+
+yes:
+	return 1;
+
+slice:
+	gused(N); // in case the data is the dest of a goto
+	nl = nr;
+	if(nr == N || nr->op != OADDR)
+		goto no;
+	nr = nr->left;
+	if(nr == N || nr->op != ONAME)
+		goto no;
+
+	// nr is the array being converted to a slice
+	if(nr->type == T || nr->type->etype != TARRAY || nr->type->bound < 0)
+		goto no;
+
+	nam.xoffset += Array_array;
+	gdata(&nam, nl, types[tptr]->width);
+
+	nam.xoffset += Array_nel-Array_array;
+	nodconst(&nod1, types[TINT], nr->type->bound);
+	gdata(&nam, &nod1, widthint);
+
+	nam.xoffset += Array_cap-Array_nel;
+	gdata(&nam, &nod1, widthint);
+
+	goto yes;
+
+no:
+	if(n->dodata == 2) {
+		dump("\ngen_as_init", n);
+		fatal("gen_as_init couldnt make data statement");
+	}
+	return 0;
+}
+
+static int isvaluelit(Node*);
+static InitEntry* entry(InitPlan*);
+static void addvalue(InitPlan*, vlong, Node*, Node*);
+
+static void
+initplan(Node *n)
+{
+	InitPlan *p;
+	Node *a;
+	NodeList *l;
+
+	if(n->initplan != nil)
+		return;
+	p = mal(sizeof *p);
+	n->initplan = p;
+	switch(n->op) {
+	default:
+		fatal("initplan");
+	case OARRAYLIT:
+		for(l=n->list; l; l=l->next) {
+			a = l->n;
+			if(a->op != OKEY || !smallintconst(a->left))
+				fatal("initplan arraylit");
+			addvalue(p, n->type->type->width*mpgetfix(a->left->val.u.xval), N, a->right);
+		}
+		break;
+	case OSTRUCTLIT:
+		for(l=n->list; l; l=l->next) {
+			a = l->n;
+			if(a->op != OKEY || a->left->type == T)
+				fatal("initplan structlit");
+			addvalue(p, a->left->type->width, N, a->right);
+		}
+		break;
+	case OMAPLIT:
+		for(l=n->list; l; l=l->next) {
+			a = l->n;
+			if(a->op != OKEY)
+				fatal("initplan maplit");
+			addvalue(p, -1, a->left, a->right);
+		}
+		break;
+	}
+}
+
+static void
+addvalue(InitPlan *p, vlong xoffset, Node *key, Node *n)
+{
+	int i;
+	InitPlan *q;
+	InitEntry *e;
+
+	USED(key);
+
+	// special case: zero can be dropped entirely
+	if(iszero(n)) {
+		p->zero += n->type->width;
+		return;
+	}
+	
+	// special case: inline struct and array (not slice) literals
+	if(isvaluelit(n)) {
+		initplan(n);
+		q = n->initplan;
+		for(i=0; i<q->len; i++) {
+			e = entry(p);
+			*e = q->e[i];
+			e->xoffset += xoffset;
+		}
+		return;
+	}
+	
+	// add to plan
+	if(n->op == OLITERAL)
+		p->lit += n->type->width;
+	else
+		p->expr += n->type->width;
+
+	e = entry(p);
+	e->xoffset = xoffset;
+	e->expr = n;
+}
+
+int
+iszero(Node *n)
+{
+	NodeList *l;
+
+	switch(n->op) {
+	case OLITERAL:
+		switch(n->val.ctype) {
+		default:
+			dump("unexpected literal", n);
+			fatal("iszero");
+	
+		case CTNIL:
+			return 1;
+		
+		case CTSTR:
+			return n->val.u.sval == nil || n->val.u.sval->len == 0;
+	
+		case CTBOOL:
+			return n->val.u.bval == 0;
+			
+		case CTINT:
+		case CTRUNE:
+			return mpcmpfixc(n->val.u.xval, 0) == 0;
+	
+		case CTFLT:
+			return mpcmpfltc(n->val.u.fval, 0) == 0;
+	
+		case CTCPLX:
+			return mpcmpfltc(&n->val.u.cval->real, 0) == 0 && mpcmpfltc(&n->val.u.cval->imag, 0) == 0;
+		}
+		break;
+	case OARRAYLIT:
+		if(isslice(n->type))
+			break;
+		// fall through
+	case OSTRUCTLIT:
+		for(l=n->list; l; l=l->next)
+			if(!iszero(l->n->right))
+				return 0;
+		return 1;
+	}
+	return 0;
+}
+
+static int
+isvaluelit(Node *n)
+{
+	return (n->op == OARRAYLIT && isfixedarray(n->type)) || n->op == OSTRUCTLIT;
+}
+
+static InitEntry*
+entry(InitPlan *p)
+{
+	if(p->len >= p->cap) {
+		if(p->cap == 0)
+			p->cap = 4;
+		else
+			p->cap *= 2;
+		p->e = realloc(p->e, p->cap*sizeof p->e[0]);
+		if(p->e == nil)
+			fatal("out of memory");
+	}
+	return &p->e[p->len++];
+}
diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c
new file mode 100644
index 0000000..26153d3
--- /dev/null
+++ b/src/cmd/gc/subr.c
@@ -0,0 +1,3849 @@
+// 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	"go.h"
+#include	"md5.h"
+#include	"y.tab.h"
+#include	"yerr.h"
+
+typedef struct Error Error;
+struct Error
+{
+	int lineno;
+	int seq;
+	char *msg;
+};
+static Error *err;
+static int nerr;
+static int merr;
+
+void
+errorexit(void)
+{
+	flusherrors();
+	if(outfile)
+		remove(outfile);
+	exits("error");
+}
+
+extern int yychar;
+int
+parserline(void)
+{
+	if(yychar != 0 && yychar != -2)	// parser has one symbol lookahead
+		return prevlineno;
+	return lineno;
+}
+
+static void
+adderr(int line, char *fmt, va_list arg)
+{
+	Fmt f;
+	Error *p;
+
+	fmtstrinit(&f);
+	fmtprint(&f, "%L: ", line);
+	fmtvprint(&f, fmt, arg);
+	fmtprint(&f, "\n");
+
+	if(nerr >= merr) {
+		if(merr == 0)
+			merr = 16;
+		else
+			merr *= 2;
+		p = realloc(err, merr*sizeof err[0]);
+		if(p == nil) {
+			merr = nerr;
+			flusherrors();
+			print("out of memory\n");
+			errorexit();
+		}
+		err = p;
+	}
+	err[nerr].seq = nerr;
+	err[nerr].lineno = line;
+	err[nerr].msg = fmtstrflush(&f);
+	nerr++;
+}
+
+static int
+errcmp(const void *va, const void *vb)
+{
+	Error *a, *b;
+
+	a = (Error*)va;
+	b = (Error*)vb;
+	if(a->lineno != b->lineno)
+		return a->lineno - b->lineno;
+	if(a->seq != b->seq)
+		return a->seq - b->seq;
+	return strcmp(a->msg, b->msg);
+}
+
+void
+flusherrors(void)
+{
+	int i;
+
+	Bflush(&bstdout);
+	if(nerr == 0)
+		return;
+	qsort(err, nerr, sizeof err[0], errcmp);
+	for(i=0; i<nerr; i++)
+		if(i==0 || strcmp(err[i].msg, err[i-1].msg) != 0)
+			print("%s", err[i].msg);
+	nerr = 0;
+}
+
+static void
+hcrash(void)
+{
+	if(debug['h']) {
+		flusherrors();
+		if(outfile)
+			remove(outfile);
+		*(volatile int*)0 = 0;
+	}
+}
+
+void
+yyerrorl(int line, char *fmt, ...)
+{
+	va_list arg;
+
+	va_start(arg, fmt);
+	adderr(line, fmt, arg);
+	va_end(arg);
+
+	hcrash();
+	nerrors++;
+	if(nsavederrors+nerrors >= 10 && !debug['e']) {
+		flusherrors();
+		print("%L: too many errors\n", line);
+		errorexit();
+	}
+}
+
+extern int yystate, yychar;
+
+void
+yyerror(char *fmt, ...)
+{
+	int i;
+	static int lastsyntax;
+	va_list arg;
+	char buf[512], *p;
+
+	if(strncmp(fmt, "syntax error", 12) == 0) {
+		nsyntaxerrors++;
+		
+		if(debug['x'])	
+			print("yyerror: yystate=%d yychar=%d\n", yystate, yychar);
+
+		// An unexpected EOF caused a syntax error. Use the previous
+		// line number since getc generated a fake newline character.
+		if(curio.eofnl)
+			lexlineno = prevlineno;
+
+		// only one syntax error per line
+		if(lastsyntax == lexlineno)
+			return;
+		lastsyntax = lexlineno;
+			
+		if(strstr(fmt, "{ or {") || strstr(fmt, " or ?") || strstr(fmt, " or @")) {
+			// The grammar has { and LBRACE but both show up as {.
+			// Rewrite syntax error referring to "{ or {" to say just "{".
+			strecpy(buf, buf+sizeof buf, fmt);
+			p = strstr(buf, "{ or {");
+			if(p)
+				memmove(p+1, p+6, strlen(p+6)+1);
+			
+			// The grammar has ? and @ but only for reading imports.
+			// Silence them in ordinary errors.
+			p = strstr(buf, " or ?");
+			if(p)
+				memmove(p, p+5, strlen(p+5)+1);
+			p = strstr(buf, " or @");
+			if(p)
+				memmove(p, p+5, strlen(p+5)+1);
+			fmt = buf;
+		}
+		
+		// look for parse state-specific errors in list (see go.errors).
+		for(i=0; i<nelem(yymsg); i++) {
+			if(yymsg[i].yystate == yystate && yymsg[i].yychar == yychar) {
+				yyerrorl(lexlineno, "syntax error: %s", yymsg[i].msg);
+				return;
+			}
+		}
+		
+		// plain "syntax error" gets "near foo" added
+		if(strcmp(fmt, "syntax error") == 0) {
+			yyerrorl(lexlineno, "syntax error near %s", lexbuf);
+			return;
+		}
+		
+		// if bison says "syntax error, more info"; print "syntax error: more info".
+		if(fmt[12] == ',') {
+			yyerrorl(lexlineno, "syntax error:%s", fmt+13);
+			return;
+		}
+
+		yyerrorl(lexlineno, "%s", fmt);
+		return;
+	}
+
+	va_start(arg, fmt);
+	adderr(parserline(), fmt, arg);
+	va_end(arg);
+
+	hcrash();
+	nerrors++;
+	if(nsavederrors+nerrors >= 10 && !debug['e']) {
+		flusherrors();
+		print("%L: too many errors\n", parserline());
+		errorexit();
+	}
+}
+
+void
+warn(char *fmt, ...)
+{
+	va_list arg;
+
+	va_start(arg, fmt);
+	adderr(parserline(), fmt, arg);
+	va_end(arg);
+
+	hcrash();
+}
+
+void
+warnl(int line, char *fmt, ...)
+{
+	va_list arg;
+
+	va_start(arg, fmt);
+	adderr(line, fmt, arg);
+	va_end(arg);
+	if(debug['m'])
+		flusherrors();
+}
+
+void
+fatal(char *fmt, ...)
+{
+	va_list arg;
+
+	flusherrors();
+
+	print("%L: internal compiler error: ", lineno);
+	va_start(arg, fmt);
+	vfprint(1, fmt, arg);
+	va_end(arg);
+	print("\n");
+	
+	// If this is a released compiler version, ask for a bug report.
+	if(strncmp(getgoversion(), "release", 7) == 0) {
+		print("\n");
+		print("Please file a bug report including a short program that triggers the error.\n");
+		print("http://code.google.com/p/go/issues/entry?template=compilerbug\n");
+	}
+	hcrash();
+	errorexit();
+}
+
+void
+linehist(char *file, int32 off, int relative)
+{
+	if(debug['i']) {
+		if(file != nil) {
+			if(off < 0)
+				print("pragma %s", file);
+			else
+			if(off > 0)
+				print("line %s", file);
+			else
+				print("import %s", file);
+		} else
+			print("end of import");
+		print(" at line %L\n", lexlineno);
+	}
+	
+	if(off < 0 && file[0] != '/' && !relative)
+		file = smprint("%s/%s", ctxt->pathname, file);
+	linklinehist(ctxt, lexlineno, file, off);
+}
+
+int32
+setlineno(Node *n)
+{
+	int32 lno;
+
+	lno = lineno;
+	if(n != N)
+	switch(n->op) {
+	case ONAME:
+	case OTYPE:
+	case OPACK:
+	case OLITERAL:
+		break;
+	default:
+		lineno = n->lineno;
+		if(lineno == 0) {
+			if(debug['K'])
+				warn("setlineno: line 0");
+			lineno = lno;
+		}
+	}
+	return lno;
+}
+
+uint32
+stringhash(char *p)
+{
+	uint32 h;
+	int c;
+
+	h = 0;
+	for(;;) {
+		c = *p++;
+		if(c == 0)
+			break;
+		h = h*PRIME1 + c;
+	}
+
+	if((int32)h < 0) {
+		h = -h;
+		if((int32)h < 0)
+			h = 0;
+	}
+	return h;
+}
+
+Sym*
+lookup(char *name)
+{
+	return pkglookup(name, localpkg);
+}
+
+Sym*
+pkglookup(char *name, Pkg *pkg)
+{
+	Sym *s;
+	uint32 h;
+	int c;
+
+	h = stringhash(name) % NHASH;
+	c = name[0];
+	for(s = hash[h]; s != S; s = s->link) {
+		if(s->name[0] != c || s->pkg != pkg)
+			continue;
+		if(strcmp(s->name, name) == 0)
+			return s;
+	}
+
+	s = mal(sizeof(*s));
+	s->name = mal(strlen(name)+1);
+	strcpy(s->name, name);
+
+	s->pkg = pkg;
+
+	s->link = hash[h];
+	hash[h] = s;
+	s->lexical = LNAME;
+
+	return s;
+}
+
+Sym*
+restrictlookup(char *name, Pkg *pkg)
+{
+	if(!exportname(name) && pkg != localpkg)
+		yyerror("cannot refer to unexported name %s.%s", pkg->name, name);
+	return pkglookup(name, pkg);
+}
+
+
+// find all the exported symbols in package opkg
+// and make them available in the current package
+void
+importdot(Pkg *opkg, Node *pack)
+{
+	Sym *s, *s1;
+	uint32 h;
+	int n;
+	char *pkgerror;
+
+	n = 0;
+	for(h=0; h<NHASH; h++) {
+		for(s = hash[h]; s != S; s = s->link) {
+			if(s->pkg != opkg)
+				continue;
+			if(s->def == N)
+				continue;
+			if(!exportname(s->name) || utfrune(s->name, 0xb7))	// 0xb7 = center dot
+				continue;
+			s1 = lookup(s->name);
+			if(s1->def != N) {
+				pkgerror = smprint("during import \"%Z\"", opkg->path);
+				redeclare(s1, pkgerror);
+				continue;
+			}
+			s1->def = s->def;
+			s1->block = s->block;
+			s1->def->pack = pack;
+			s1->origpkg = opkg;
+			n++;
+		}
+	}
+	if(n == 0) {
+		// can't possibly be used - there were no symbols
+		yyerrorl(pack->lineno, "imported and not used: \"%Z\"", opkg->path);
+	}
+}
+
+static void
+gethunk(void)
+{
+	char *h;
+	int32 nh;
+
+	nh = NHUNK;
+	if(thunk >= 10L*NHUNK)
+		nh = 10L*NHUNK;
+	h = (char*)malloc(nh);
+	if(h == nil) {
+		flusherrors();
+		yyerror("out of memory");
+		errorexit();
+	}
+	hunk = h;
+	nhunk = nh;
+	thunk += nh;
+}
+
+void*
+mal(int32 n)
+{
+	void *p;
+
+	if(n >= NHUNK) {
+		p = malloc(n);
+		if(p == nil) {
+			flusherrors();
+			yyerror("out of memory");
+			errorexit();
+		}
+		memset(p, 0, n);
+		return p;
+	}
+
+	while((uintptr)hunk & MAXALIGN) {
+		hunk++;
+		nhunk--;
+	}
+	if(nhunk < n)
+		gethunk();
+
+	p = hunk;
+	nhunk -= n;
+	hunk += n;
+	memset(p, 0, n);
+	return p;
+}
+
+void*
+remal(void *p, int32 on, int32 n)
+{
+	void *q;
+
+	q = (uchar*)p + on;
+	if(q != hunk || nhunk < n) {
+		if(on+n >= NHUNK) {
+			q = mal(on+n);
+			memmove(q, p, on);
+			return q;
+		}
+		if(nhunk < on+n)
+			gethunk();
+		memmove(hunk, p, on);
+		p = hunk;
+		hunk += on;
+		nhunk -= on;
+	}
+	hunk += n;
+	nhunk -= n;
+	return p;
+}
+
+Node*
+nod(int op, Node *nleft, Node *nright)
+{
+	Node *n;
+
+	n = mal(sizeof(*n));
+	n->op = op;
+	n->left = nleft;
+	n->right = nright;
+	n->lineno = parserline();
+	n->xoffset = BADWIDTH;
+	n->orig = n;
+	n->curfn = curfn;
+	return n;
+}
+
+void
+saveorignode(Node *n)
+{
+	Node *norig;
+
+	if(n->orig != N)
+		return;
+	norig = nod(n->op, N, N);
+	*norig = *n;
+	n->orig = norig;
+}
+
+// ispaddedfield reports whether the given field
+// is followed by padding. For the case where t is
+// the last field, total gives the size of the enclosing struct.
+static int
+ispaddedfield(Type *t, vlong total)
+{
+	if(t->etype != TFIELD)
+		fatal("ispaddedfield called non-field %T", t);
+	if(t->down == T)
+		return t->width + t->type->width != total;
+	return t->width + t->type->width != t->down->width;
+}
+
+int
+algtype1(Type *t, Type **bad)
+{
+	int a, ret;
+	Type *t1;
+	
+	if(bad)
+		*bad = T;
+	if(t->broke)
+		return AMEM;
+	if(t->noalg)
+		return ANOEQ;
+
+	switch(t->etype) {
+	case TANY:
+	case TFORW:
+		// will be defined later.
+		*bad = t;
+		return -1;
+
+	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 TPTR32:
+	case TPTR64:
+	case TCHAN:
+	case TUNSAFEPTR:
+		return AMEM;
+
+	case TFUNC:
+	case TMAP:
+		if(bad)
+			*bad = t;
+		return ANOEQ;
+
+	case TFLOAT32:
+		return AFLOAT32;
+
+	case TFLOAT64:
+		return AFLOAT64;
+
+	case TCOMPLEX64:
+		return ACPLX64;
+
+	case TCOMPLEX128:
+		return ACPLX128;
+
+	case TSTRING:
+		return ASTRING;
+	
+	case TINTER:
+		if(isnilinter(t))
+			return ANILINTER;
+		return AINTER;
+	
+	case TARRAY:
+		if(isslice(t)) {
+			if(bad)
+				*bad = t;
+			return ANOEQ;
+		}
+		a = algtype1(t->type, bad);
+		if(a == ANOEQ || a == AMEM) {
+			if(a == ANOEQ && bad)
+				*bad = t;
+			return a;
+		}
+		return -1;  // needs special compare
+
+	case TSTRUCT:
+		if(t->type != T && t->type->down == T && !isblanksym(t->type->sym)) {
+			// One-field struct is same as that one field alone.
+			return algtype1(t->type->type, bad);
+		}
+		ret = AMEM;
+		for(t1=t->type; t1!=T; t1=t1->down) {
+			// All fields must be comparable.
+			a = algtype1(t1->type, bad);
+			if(a == ANOEQ)
+				return ANOEQ;
+
+			// Blank fields, padded fields, fields with non-memory
+			// equality need special compare.
+			if(a != AMEM || isblanksym(t1->sym) || ispaddedfield(t1, t->width)) {
+				ret = -1;
+				continue;
+			}
+		}
+		return ret;
+	}
+
+	fatal("algtype1: unexpected type %T", t);
+	return 0;
+}
+
+int
+algtype(Type *t)
+{
+	int a;
+	
+	a = algtype1(t, nil);
+	if(a == AMEM || a == ANOEQ) {
+		if(isslice(t))
+			return ASLICE;
+		switch(t->width) {
+		case 0:
+			return a + AMEM0 - AMEM;
+		case 1:
+			return a + AMEM8 - AMEM;
+		case 2:
+			return a + AMEM16 - AMEM;
+		case 4:
+			return a + AMEM32 - AMEM;
+		case 8:
+			return a + AMEM64 - AMEM;
+		case 16:
+			return a + AMEM128 - AMEM;
+		}
+	}
+	return a;
+}
+
+Type*
+maptype(Type *key, Type *val)
+{
+	Type *t;
+	Type *bad;
+	int atype, mtype;
+
+	if(key != nil) {
+		atype = algtype1(key, &bad);
+		if(bad == T)
+			mtype = key->etype;
+		else
+			mtype = bad->etype;
+		switch(mtype) {
+		default:
+			if(atype == ANOEQ)
+				yyerror("invalid map key type %T", key);
+			break;
+		case TANY:
+			// will be resolved later.
+			break;
+		case TFORW:
+			// map[key] used during definition of key.
+			// postpone check until key is fully defined.
+			// if there are multiple uses of map[key]
+			// before key is fully defined, the error
+			// will only be printed for the first one.
+			// good enough.
+			if(key->maplineno == 0)
+				key->maplineno = lineno;
+			break;
+		}
+	}
+	t = typ(TMAP);
+	t->down = key;
+	t->type = val;
+	return t;
+}
+
+Type*
+typ(int et)
+{
+	Type *t;
+
+	t = mal(sizeof(*t));
+	t->etype = et;
+	t->width = BADWIDTH;
+	t->lineno = lineno;
+	t->orig = t;
+	return t;
+}
+
+static int
+methcmp(const void *va, const void *vb)
+{
+	Type *a, *b;
+	int i;
+	
+	a = *(Type**)va;
+	b = *(Type**)vb;
+	if(a->sym == S && b->sym == S)
+		return 0;
+	if(a->sym == S)
+		return -1;
+	if(b->sym == S)
+		return 1;
+	i = strcmp(a->sym->name, b->sym->name);
+	if(i != 0)
+		return i;
+	if(!exportname(a->sym->name)) {
+		i = strcmp(a->sym->pkg->path->s, b->sym->pkg->path->s);
+		if(i != 0)
+			return i;
+	}
+	return 0;
+}
+
+Type*
+sortinter(Type *t)
+{
+	Type *f;
+	int i;
+	Type **a;
+	
+	if(t->type == nil || t->type->down == nil)
+		return t;
+
+	i=0;
+	for(f=t->type; f; f=f->down)
+		i++;
+	a = mal(i*sizeof f);
+	i = 0;
+	for(f=t->type; f; f=f->down)
+		a[i++] = f;
+	qsort(a, i, sizeof a[0], methcmp);
+	while(i-- > 0) {
+		a[i]->down = f;
+		f = a[i];
+	}
+	t->type = f;
+	return t;
+}
+
+Node*
+nodintconst(int64 v)
+{
+	Node *c;
+
+	c = nod(OLITERAL, N, N);
+	c->addable = 1;
+	c->val.u.xval = mal(sizeof(*c->val.u.xval));
+	mpmovecfix(c->val.u.xval, v);
+	c->val.ctype = CTINT;
+	c->type = types[TIDEAL];
+	ullmancalc(c);
+	return c;
+}
+
+Node*
+nodfltconst(Mpflt* v)
+{
+	Node *c;
+
+	c = nod(OLITERAL, N, N);
+	c->addable = 1;
+	c->val.u.fval = mal(sizeof(*c->val.u.fval));
+	mpmovefltflt(c->val.u.fval, v);
+	c->val.ctype = CTFLT;
+	c->type = types[TIDEAL];
+	ullmancalc(c);
+	return c;
+}
+
+void
+nodconst(Node *n, Type *t, int64 v)
+{
+	memset(n, 0, sizeof(*n));
+	n->op = OLITERAL;
+	n->addable = 1;
+	ullmancalc(n);
+	n->val.u.xval = mal(sizeof(*n->val.u.xval));
+	mpmovecfix(n->val.u.xval, v);
+	n->val.ctype = CTINT;
+	n->type = t;
+
+	if(isfloat[t->etype])
+		fatal("nodconst: bad type %T", t);
+}
+
+Node*
+nodnil(void)
+{
+	Node *c;
+
+	c = nodintconst(0);
+	c->val.ctype = CTNIL;
+	c->type = types[TNIL];
+	return c;
+}
+
+Node*
+nodbool(int b)
+{
+	Node *c;
+
+	c = nodintconst(0);
+	c->val.ctype = CTBOOL;
+	c->val.u.bval = b;
+	c->type = idealbool;
+	return c;
+}
+
+Type*
+aindex(Node *b, Type *t)
+{
+	Type *r;
+	int64 bound;
+
+	bound = -1;	// open bound
+	typecheck(&b, Erv);
+	if(b != nil) {
+		switch(consttype(b)) {
+		default:
+			yyerror("array bound must be an integer expression");
+			break;
+		case CTINT:
+		case CTRUNE:
+			bound = mpgetfix(b->val.u.xval);
+			if(bound < 0)
+				yyerror("array bound must be non negative");
+			break;
+		}
+	}
+
+	// fixed array
+	r = typ(TARRAY);
+	r->type = t;
+	r->bound = bound;
+	return r;
+}
+
+Node*
+treecopy(Node *n)
+{
+	Node *m;
+
+	if(n == N)
+		return N;
+
+	switch(n->op) {
+	default:
+		m = nod(OXXX, N, N);
+		*m = *n;
+		m->orig = m;
+		m->left = treecopy(n->left);
+		m->right = treecopy(n->right);
+		m->list = listtreecopy(n->list);
+		if(m->defn)
+			abort();
+		break;
+
+	case ONONAME:
+		if(n->sym == lookup("iota")) {
+			// Not sure yet whether this is the real iota,
+			// but make a copy of the Node* just in case,
+			// so that all the copies of this const definition
+			// don't have the same iota value.
+			m = nod(OXXX, N, N);
+			*m = *n;
+			m->iota = iota;
+			break;
+		}
+		// fall through
+	case ONAME:
+	case OLITERAL:
+	case OTYPE:
+		m = n;
+		break;
+	}
+	return m;
+}
+
+
+int
+isnil(Node *n)
+{
+	if(n == N)
+		return 0;
+	if(n->op != OLITERAL)
+		return 0;
+	if(n->val.ctype != CTNIL)
+		return 0;
+	return 1;
+}
+
+int
+isptrto(Type *t, int et)
+{
+	if(t == T)
+		return 0;
+	if(!isptr[t->etype])
+		return 0;
+	t = t->type;
+	if(t == T)
+		return 0;
+	if(t->etype != et)
+		return 0;
+	return 1;
+}
+
+int
+istype(Type *t, int et)
+{
+	return t != T && t->etype == et;
+}
+
+int
+isfixedarray(Type *t)
+{
+	return t != T && t->etype == TARRAY && t->bound >= 0;
+}
+
+int
+isslice(Type *t)
+{
+	return t != T && t->etype == TARRAY && t->bound < 0;
+}
+
+int
+isblank(Node *n)
+{
+	if(n == N)
+		return 0;
+	return isblanksym(n->sym);
+}
+
+int
+isblanksym(Sym *s)
+{
+	char *p;
+
+	if(s == S)
+		return 0;
+	p = s->name;
+	if(p == nil)
+		return 0;
+	return p[0] == '_' && p[1] == '\0';
+}
+
+int
+isinter(Type *t)
+{
+	return t != T && t->etype == TINTER;
+}
+
+int
+isnilinter(Type *t)
+{
+	if(!isinter(t))
+		return 0;
+	if(t->type != T)
+		return 0;
+	return 1;
+}
+
+int
+isideal(Type *t)
+{
+	if(t == T)
+		return 0;
+	if(t == idealstring || t == idealbool)
+		return 1;
+	switch(t->etype) {
+	case TNIL:
+	case TIDEAL:
+		return 1;
+	}
+	return 0;
+}
+
+/*
+ * given receiver of type t (t == r or t == *r)
+ * return type to hang methods off (r).
+ */
+Type*
+methtype(Type *t, int mustname)
+{
+	if(t == T)
+		return T;
+
+	// strip away pointer if it's there
+	if(isptr[t->etype]) {
+		if(t->sym != S)
+			return T;
+		t = t->type;
+		if(t == T)
+			return T;
+	}
+
+	// need a type name
+	if(t->sym == S && (mustname || t->etype != TSTRUCT))
+		return T;
+
+	// check types
+	if(!issimple[t->etype])
+	switch(t->etype) {
+	default:
+		return T;
+	case TSTRUCT:
+	case TARRAY:
+	case TMAP:
+	case TCHAN:
+	case TSTRING:
+	case TFUNC:
+		break;
+	}
+
+	return t;
+}
+
+int
+cplxsubtype(int et)
+{
+	switch(et) {
+	case TCOMPLEX64:
+		return TFLOAT32;
+	case TCOMPLEX128:
+		return TFLOAT64;
+	}
+	fatal("cplxsubtype: %E\n", et);
+	return 0;
+}
+
+static int
+eqnote(Strlit *a, Strlit *b)
+{
+	if(a == b)
+		return 1;
+	if(a == nil || b == nil)
+		return 0;
+	if(a->len != b->len)
+		return 0;
+	return memcmp(a->s, b->s, a->len) == 0;
+}
+
+typedef struct TypePairList TypePairList;
+struct TypePairList
+{
+	Type *t1;
+	Type *t2;
+	TypePairList *next;
+};
+
+static int
+onlist(TypePairList *l, Type *t1, Type *t2) 
+{
+	for(; l; l=l->next)
+		if((l->t1 == t1 && l->t2 == t2) || (l->t1 == t2 && l->t2 == t1))
+			return 1;
+	return 0;
+}
+
+static int eqtype1(Type*, Type*, TypePairList*);
+
+// Return 1 if t1 and t2 are identical, following the spec rules.
+//
+// Any cyclic type must go through a named type, and if one is
+// named, it is only identical to the other if they are the same
+// pointer (t1 == t2), so there's no chance of chasing cycles
+// ad infinitum, so no need for a depth counter.
+int
+eqtype(Type *t1, Type *t2)
+{
+	return eqtype1(t1, t2, nil);
+}
+
+static int
+eqtype1(Type *t1, Type *t2, TypePairList *assumed_equal)
+{
+	TypePairList l;
+
+	if(t1 == t2)
+		return 1;
+	if(t1 == T || t2 == T || t1->etype != t2->etype)
+		return 0;
+	if(t1->sym || t2->sym) {
+		// Special case: we keep byte and uint8 separate
+		// for error messages.  Treat them as equal.
+		switch(t1->etype) {
+		case TUINT8:
+			if((t1 == types[TUINT8] || t1 == bytetype) && (t2 == types[TUINT8] || t2 == bytetype))
+				return 1;
+			break;
+		case TINT:
+		case TINT32:
+			if((t1 == types[runetype->etype] || t1 == runetype) && (t2 == types[runetype->etype] || t2 == runetype))
+				return 1;
+			break;
+		}
+		return 0;
+	}
+
+	if(onlist(assumed_equal, t1, t2))
+		return 1;
+	l.next = assumed_equal;
+	l.t1 = t1;
+	l.t2 = t2;
+
+	switch(t1->etype) {
+	case TINTER:
+	case TSTRUCT:
+		for(t1=t1->type, t2=t2->type; t1 && t2; t1=t1->down, t2=t2->down) {
+			if(t1->etype != TFIELD || t2->etype != TFIELD)
+				fatal("struct/interface missing field: %T %T", t1, t2);
+			if(t1->sym != t2->sym || t1->embedded != t2->embedded || !eqtype1(t1->type, t2->type, &l) || !eqnote(t1->note, t2->note))
+				goto no;
+		}
+		if(t1 == T && t2 == T)
+			goto yes;
+		goto no;
+
+	case TFUNC:
+		// Loop over structs: receiver, in, out.
+		for(t1=t1->type, t2=t2->type; t1 && t2; t1=t1->down, t2=t2->down) {
+			Type *ta, *tb;
+
+			if(t1->etype != TSTRUCT || t2->etype != TSTRUCT)
+				fatal("func missing struct: %T %T", t1, t2);
+
+			// Loop over fields in structs, ignoring argument names.
+			for(ta=t1->type, tb=t2->type; ta && tb; ta=ta->down, tb=tb->down) {
+				if(ta->etype != TFIELD || tb->etype != TFIELD)
+					fatal("func struct missing field: %T %T", ta, tb);
+				if(ta->isddd != tb->isddd || !eqtype1(ta->type, tb->type, &l))
+					goto no;
+			}
+			if(ta != T || tb != T)
+				goto no;
+		}
+		if(t1 == T && t2 == T)
+			goto yes;
+		goto no;
+	
+	case TARRAY:
+		if(t1->bound != t2->bound)
+			goto no;
+		break;
+	
+	case TCHAN:
+		if(t1->chan != t2->chan)
+			goto no;
+		break;
+	}
+
+	if(eqtype1(t1->down, t2->down, &l) && eqtype1(t1->type, t2->type, &l))
+		goto yes;
+	goto no;
+
+yes:
+	return 1;
+
+no:
+	return 0;
+}
+
+// Are t1 and t2 equal struct types when field names are ignored?
+// For deciding whether the result struct from g can be copied
+// directly when compiling f(g()).
+int
+eqtypenoname(Type *t1, Type *t2)
+{
+	if(t1 == T || t2 == T || t1->etype != TSTRUCT || t2->etype != TSTRUCT)
+		return 0;
+
+	t1 = t1->type;
+	t2 = t2->type;
+	for(;;) {
+		if(!eqtype(t1, t2))
+			return 0;
+		if(t1 == T)
+			return 1;
+		t1 = t1->down;
+		t2 = t2->down;
+	}
+}
+
+// Is type src assignment compatible to type dst?
+// If so, return op code to use in conversion.
+// If not, return 0.
+int
+assignop(Type *src, Type *dst, char **why)
+{
+	Type *missing, *have;
+	int ptr;
+
+	if(why != nil)
+		*why = "";
+
+	// TODO(rsc,lvd): This behaves poorly in the presence of inlining.
+	// https://code.google.com/p/go/issues/detail?id=2795
+	if(safemode && importpkg == nil && src != T && src->etype == TUNSAFEPTR) {
+		yyerror("cannot use unsafe.Pointer");
+		errorexit();
+	}
+
+	if(src == dst)
+		return OCONVNOP;
+	if(src == T || dst == T || src->etype == TFORW || dst->etype == TFORW || src->orig == T || dst->orig == T)
+		return 0;
+
+	// 1. src type is identical to dst.
+	if(eqtype(src, dst))
+		return OCONVNOP;
+	
+	// 2. src and dst have identical underlying types
+	// and either src or dst is not a named type or
+	// 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.
+	if(dst->etype == TINTER && src->etype != TNIL) {
+		if(implements(src, dst, &missing, &have, &ptr))
+			return OCONVIFACE;
+
+		// 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,
+					have->sym, have->type, missing->sym, missing->type);
+			else if(ptr)
+				*why = smprint(":\n\t%T does not implement %T (%S method has pointer receiver)",
+					src, dst, missing->sym);
+			else if(have)
+				*why = smprint(":\n\t%T does not implement %T (missing %S method)\n"
+					"\t\thave %S%hhT\n\t\twant %S%hhT", src, dst, missing->sym,
+					have->sym, have->type, missing->sym, missing->type);
+			else
+				*why = smprint(":\n\t%T does not implement %T (missing %S method)",
+					src, dst, missing->sym);
+		}
+		return 0;
+	}
+	if(isptrto(dst, TINTER)) {
+		if(why != nil)
+			*why = smprint(":\n\t%T is pointer to interface, not interface", dst);
+		return 0;
+	}
+	if(src->etype == TINTER && dst->etype != TBLANK) {
+		if(why != nil && implements(dst, src, &missing, &have, &ptr))
+			*why = ": need type assertion";
+		return 0;
+	}
+
+	// 4. src is a bidirectional channel value, dst is a channel type,
+	// src and dst have identical element types, and
+	// either src or dst is not a named type.
+	if(src->etype == TCHAN && src->chan == Cboth && dst->etype == TCHAN)
+	if(eqtype(src->type, dst->type) && (src->sym == S || dst->sym == S))
+		return OCONVNOP;
+
+	// 5. src is the predeclared identifier nil and dst is a nillable type.
+	if(src->etype == TNIL) {
+		switch(dst->etype) {
+		case TARRAY:
+			if(dst->bound != -100)	// not slice
+				break;
+		case TPTR32:
+		case TPTR64:
+		case TFUNC:
+		case TMAP:
+		case TCHAN:
+		case TINTER:
+			return OCONVNOP;
+		}
+	}
+
+	// 6. rule about untyped constants - already converted by defaultlit.
+	
+	// 7. Any typed value can be assigned to the blank identifier.
+	if(dst->etype == TBLANK)
+		return OCONVNOP;
+
+	return 0;
+}
+
+// Can we convert a value of type src to a value of type dst?
+// If so, return op code to use in conversion (maybe OCONVNOP).
+// If not, return 0.
+int
+convertop(Type *src, Type *dst, char **why)
+{
+	int op;
+	
+	if(why != nil)
+		*why = "";
+
+	if(src == dst)
+		return OCONVNOP;
+	if(src == T || dst == T)
+		return 0;
+	
+	// 1. src can be assigned to dst.
+	if((op = assignop(src, dst, why)) != 0)
+		return op;
+
+	// The rules for interfaces are no different in conversions
+	// than assignments.  If interfaces are involved, stop now
+	// with the good message from assignop.
+	// Otherwise clear the error.
+	if(src->etype == TINTER || dst->etype == TINTER)
+		return 0;
+	if(why != nil)
+		*why = "";
+
+	// 2. src and dst have identical underlying types.
+	if(eqtype(src->orig, dst->orig))
+		return OCONVNOP;
+	
+	// 3. src and dst are unnamed pointer types 
+	// and their base types have identical underlying types.
+	if(isptr[src->etype] && isptr[dst->etype] && src->sym == S && dst->sym == S)
+	if(eqtype(src->type->orig, dst->type->orig))
+		return OCONVNOP;
+
+	// 4. src and dst are both integer or floating point types.
+	if((isint[src->etype] || isfloat[src->etype]) && (isint[dst->etype] || isfloat[dst->etype])) {
+		if(simtype[src->etype] == simtype[dst->etype])
+			return OCONVNOP;
+		return OCONV;
+	}
+
+	// 5. src and dst are both complex types.
+	if(iscomplex[src->etype] && iscomplex[dst->etype]) {
+		if(simtype[src->etype] == simtype[dst->etype])
+			return OCONVNOP;
+		return OCONV;
+	}
+
+	// 6. src is an integer or has type []byte or []rune
+	// and dst is a string type.
+	if(isint[src->etype] && dst->etype == TSTRING)
+		return ORUNESTR;
+
+	if(isslice(src) && dst->etype == TSTRING) {
+		if(src->type->etype == bytetype->etype)
+			return OARRAYBYTESTR;
+		if(src->type->etype == runetype->etype)
+			return OARRAYRUNESTR;
+	}
+	
+	// 7. src is a string and dst is []byte or []rune.
+	// String to slice.
+	if(src->etype == TSTRING && isslice(dst)) {
+		if(dst->type->etype == bytetype->etype)
+			return OSTRARRAYBYTE;
+		if(dst->type->etype == runetype->etype)
+			return OSTRARRAYRUNE;
+	}
+	
+	// 8. src is a pointer or uintptr and dst is unsafe.Pointer.
+	if((isptr[src->etype] || src->etype == TUINTPTR) && dst->etype == TUNSAFEPTR)
+		return OCONVNOP;
+
+	// 9. src is unsafe.Pointer and dst is a pointer or uintptr.
+	if(src->etype == TUNSAFEPTR && (isptr[dst->etype] || dst->etype == TUINTPTR))
+		return OCONVNOP;
+
+	return 0;
+}
+
+// Convert node n for assignment to type t.
+Node*
+assignconv(Node *n, Type *t, char *context)
+{
+	int op;
+	Node *r, *old;
+	char *why;
+	
+	if(n == N || n->type == T || n->type->broke)
+		return n;
+
+	if(t->etype == TBLANK && n->type->etype == TNIL)
+		yyerror("use of untyped nil");
+
+	old = n;
+	old->diag++;  // silence errors about n; we'll issue one below
+	defaultlit(&n, t);
+	old->diag--;
+	if(t->etype == TBLANK)
+		return n;
+
+	// Convert ideal bool from comparison to plain bool
+	// if the next step is non-bool (like interface{}).
+	if(n->type == idealbool && t->etype != TBOOL) {
+		if(n->op == ONAME || n->op == OLITERAL) {
+			r = nod(OCONVNOP, n, N);
+			r->type = types[TBOOL];
+			r->typecheck = 1;
+			r->implicit = 1;
+			n = r;
+		}
+	}
+
+	if(eqtype(n->type, t))
+		return n;
+
+	op = assignop(n->type, t, &why);
+	if(op == 0) {
+		yyerror("cannot use %lN as type %T in %s%s", n, t, context, why);
+		op = OCONV;
+	}
+
+	r = nod(op, n, N);
+	r->type = t;
+	r->typecheck = 1;
+	r->implicit = 1;
+	r->orig = n->orig;
+	return r;
+}
+
+static int
+subtype(Type **stp, Type *t, int d)
+{
+	Type *st;
+
+loop:
+	st = *stp;
+	if(st == T)
+		return 0;
+
+	d++;
+	if(d >= 10)
+		return 0;
+
+	switch(st->etype) {
+	default:
+		return 0;
+
+	case TPTR32:
+	case TPTR64:
+	case TCHAN:
+	case TARRAY:
+		stp = &st->type;
+		goto loop;
+
+	case TANY:
+		if(!st->copyany)
+			return 0;
+		*stp = t;
+		break;
+
+	case TMAP:
+		if(subtype(&st->down, t, d))
+			break;
+		stp = &st->type;
+		goto loop;
+
+	case TFUNC:
+		for(;;) {
+			if(subtype(&st->type, t, d))
+				break;
+			if(subtype(&st->type->down->down, t, d))
+				break;
+			if(subtype(&st->type->down, t, d))
+				break;
+			return 0;
+		}
+		break;
+
+	case TSTRUCT:
+		for(st=st->type; st!=T; st=st->down)
+			if(subtype(&st->type, t, d))
+				return 1;
+		return 0;
+	}
+	return 1;
+}
+
+/*
+ * Is this a 64-bit type?
+ */
+int
+is64(Type *t)
+{
+	if(t == T)
+		return 0;
+	switch(simtype[t->etype]) {
+	case TINT64:
+	case TUINT64:
+	case TPTR64:
+		return 1;
+	}
+	return 0;
+}
+
+/*
+ * Is a conversion between t1 and t2 a no-op?
+ */
+int
+noconv(Type *t1, Type *t2)
+{
+	int e1, e2;
+
+	e1 = simtype[t1->etype];
+	e2 = simtype[t2->etype];
+
+	switch(e1) {
+	case TINT8:
+	case TUINT8:
+		return e2 == TINT8 || e2 == TUINT8;
+
+	case TINT16:
+	case TUINT16:
+		return e2 == TINT16 || e2 == TUINT16;
+
+	case TINT32:
+	case TUINT32:
+	case TPTR32:
+		return e2 == TINT32 || e2 == TUINT32 || e2 == TPTR32;
+
+	case TINT64:
+	case TUINT64:
+	case TPTR64:
+		return e2 == TINT64 || e2 == TUINT64 || e2 == TPTR64;
+
+	case TFLOAT32:
+		return e2 == TFLOAT32;
+
+	case TFLOAT64:
+		return e2 == TFLOAT64;
+	}
+	return 0;
+}
+
+void
+argtype(Node *on, Type *t)
+{
+	dowidth(t);
+	if(!subtype(&on->type, t, 0))
+		fatal("argtype: failed %N %T\n", on, t);
+}
+
+Type*
+shallow(Type *t)
+{
+	Type *nt;
+
+	if(t == T)
+		return T;
+	nt = typ(0);
+	*nt = *t;
+	if(t->orig == t)
+		nt->orig = nt;
+	return nt;
+}
+
+static Type*
+deep(Type *t)
+{
+	Type *nt, *xt;
+
+	if(t == T)
+		return T;
+
+	switch(t->etype) {
+	default:
+		nt = t;	// share from here down
+		break;
+
+	case TANY:
+		nt = shallow(t);
+		nt->copyany = 1;
+		break;
+
+	case TPTR32:
+	case TPTR64:
+	case TCHAN:
+	case TARRAY:
+		nt = shallow(t);
+		nt->type = deep(t->type);
+		break;
+
+	case TMAP:
+		nt = shallow(t);
+		nt->down = deep(t->down);
+		nt->type = deep(t->type);
+		break;
+
+	case TFUNC:
+		nt = shallow(t);
+		nt->type = deep(t->type);
+		nt->type->down = deep(t->type->down);
+		nt->type->down->down = deep(t->type->down->down);
+		break;
+
+	case TSTRUCT:
+		nt = shallow(t);
+		nt->type = shallow(t->type);
+		xt = nt->type;
+
+		for(t=t->type; t!=T; t=t->down) {
+			xt->type = deep(t->type);
+			xt->down = shallow(t->down);
+			xt = xt->down;
+		}
+		break;
+	}
+	return nt;
+}
+
+Node*
+syslook(char *name, int copy)
+{
+	Sym *s;
+	Node *n;
+
+	s = pkglookup(name, runtimepkg);
+	if(s == S || s->def == N)
+		fatal("syslook: can't find runtime.%s", name);
+
+	if(!copy)
+		return s->def;
+
+	n = nod(0, N, N);
+	*n = *s->def;
+	n->type = deep(s->def->type);
+
+	return n;
+}
+
+/*
+ * compute a hash value for type t.
+ * if t is a method type, ignore the receiver
+ * so that the hash can be used in interface checks.
+ * %T already contains
+ * all the necessary logic to generate a representation
+ * of the type that completely describes it.
+ * using smprint here avoids duplicating that code.
+ * using md5 here is overkill, but i got tired of
+ * accidental collisions making the runtime think
+ * two types are equal when they really aren't.
+ */
+uint32
+typehash(Type *t)
+{
+	char *p;
+	MD5 d;
+
+	if(t->thistuple) {
+		// hide method receiver from Tpretty
+		t->thistuple = 0;
+		p = smprint("%-uT", t);
+		t->thistuple = 1;
+	} else
+		p = smprint("%-uT", t);
+	//print("typehash: %s\n", p);
+	md5reset(&d);
+	md5write(&d, (uchar*)p, strlen(p));
+	free(p);
+	return md5sum(&d, nil);
+}
+
+Type*
+ptrto(Type *t)
+{
+	Type *t1;
+
+	if(tptr == 0)
+		fatal("ptrto: no tptr");
+	t1 = typ(tptr);
+	t1->type = t;
+	t1->width = widthptr;
+	t1->align = widthptr;
+	return t1;
+}
+
+void
+frame(int context)
+{
+	char *p;
+	NodeList *l;
+	Node *n;
+	int flag;
+
+	p = "stack";
+	l = nil;
+	if(curfn)
+		l = curfn->dcl;
+	if(context) {
+		p = "external";
+		l = externdcl;
+	}
+
+	flag = 1;
+	for(; l; l=l->next) {
+		n = l->n;
+		switch(n->op) {
+		case ONAME:
+			if(flag)
+				print("--- %s frame ---\n", p);
+			print("%O %S G%d %T\n", n->op, n->sym, n->vargen, n->type);
+			flag = 0;
+			break;
+
+		case OTYPE:
+			if(flag)
+				print("--- %s frame ---\n", p);
+			print("%O %T\n", n->op, n->type);
+			flag = 0;
+			break;
+		}
+	}
+}
+
+/*
+ * calculate sethi/ullman number
+ * roughly how many registers needed to
+ * compile a node. used to compile the
+ * hardest side first to minimize registers.
+ */
+void
+ullmancalc(Node *n)
+{
+	int ul, ur;
+
+	if(n == N)
+		return;
+
+	if(n->ninit != nil) {
+		ul = UINF;
+		goto out;
+	}
+
+	switch(n->op) {
+	case OREGISTER:
+	case OLITERAL:
+	case ONAME:
+		ul = 1;
+		if(n->class == PPARAMREF || (n->class & PHEAP))
+			ul++;
+		goto out;
+	case OCALL:
+	case OCALLFUNC:
+	case OCALLMETH:
+	case OCALLINTER:
+		ul = UINF;
+		goto out;
+	case OANDAND:
+	case OOROR:
+		// hard with race detector
+		if(flag_race) {
+			ul = UINF;
+			goto out;
+		}
+	}
+	ul = 1;
+	if(n->left != N)
+		ul = n->left->ullman;
+	ur = 1;
+	if(n->right != N)
+		ur = n->right->ullman;
+	if(ul == ur)
+		ul += 1;
+	if(ur > ul)
+		ul = ur;
+
+out:
+	if(ul > 200)
+		ul = 200; // clamp to uchar with room to grow
+	n->ullman = ul;
+}
+
+void
+badtype(int o, Type *tl, Type *tr)
+{
+	Fmt fmt;
+	char *s;
+	
+	fmtstrinit(&fmt);
+	if(tl != T)
+		fmtprint(&fmt, "\n	%T", tl);
+	if(tr != T)
+		fmtprint(&fmt, "\n	%T", tr);
+
+	// common mistake: *struct and *interface.
+	if(tl && tr && isptr[tl->etype] && isptr[tr->etype]) {
+		if(tl->type->etype == TSTRUCT && tr->type->etype == TINTER)
+			fmtprint(&fmt, "\n	(*struct vs *interface)");
+		else if(tl->type->etype == TINTER && tr->type->etype == TSTRUCT)
+			fmtprint(&fmt, "\n	(*interface vs *struct)");
+	}
+	s = fmtstrflush(&fmt);
+	yyerror("illegal types for operand: %O%s", o, s);
+}
+
+/*
+ * iterator to walk a structure declaration
+ */
+Type*
+structfirst(Iter *s, Type **nn)
+{
+	Type *n, *t;
+
+	n = *nn;
+	if(n == T)
+		goto bad;
+
+	switch(n->etype) {
+	default:
+		goto bad;
+
+	case TSTRUCT:
+	case TINTER:
+	case TFUNC:
+		break;
+	}
+
+	t = n->type;
+	if(t == T)
+		goto rnil;
+
+	if(t->etype != TFIELD)
+		fatal("structfirst: not field %T", t);
+
+	s->t = t;
+	return t;
+
+bad:
+	fatal("structfirst: not struct %T", n);
+
+rnil:
+	return T;
+}
+
+Type*
+structnext(Iter *s)
+{
+	Type *n, *t;
+
+	n = s->t;
+	t = n->down;
+	if(t == T)
+		goto rnil;
+
+	if(t->etype != TFIELD)
+		goto bad;
+
+	s->t = t;
+	return t;
+
+bad:
+	fatal("structnext: not struct %T", n);
+
+rnil:
+	return T;
+}
+
+/*
+ * iterator to this and inargs in a function
+ */
+Type*
+funcfirst(Iter *s, Type *t)
+{
+	Type *fp;
+
+	if(t == T)
+		goto bad;
+
+	if(t->etype != TFUNC)
+		goto bad;
+
+	s->tfunc = t;
+	s->done = 0;
+	fp = structfirst(s, getthis(t));
+	if(fp == T) {
+		s->done = 1;
+		fp = structfirst(s, getinarg(t));
+	}
+	return fp;
+
+bad:
+	fatal("funcfirst: not func %T", t);
+	return T;
+}
+
+Type*
+funcnext(Iter *s)
+{
+	Type *fp;
+
+	fp = structnext(s);
+	if(fp == T && !s->done) {
+		s->done = 1;
+		fp = structfirst(s, getinarg(s->tfunc));
+	}
+	return fp;
+}
+
+Type**
+getthis(Type *t)
+{
+	if(t->etype != TFUNC)
+		fatal("getthis: not a func %T", t);
+	return &t->type;
+}
+
+Type**
+getoutarg(Type *t)
+{
+	if(t->etype != TFUNC)
+		fatal("getoutarg: not a func %T", t);
+	return &t->type->down;
+}
+
+Type**
+getinarg(Type *t)
+{
+	if(t->etype != TFUNC)
+		fatal("getinarg: not a func %T", t);
+	return &t->type->down->down;
+}
+
+Type*
+getthisx(Type *t)
+{
+	return *getthis(t);
+}
+
+Type*
+getoutargx(Type *t)
+{
+	return *getoutarg(t);
+}
+
+Type*
+getinargx(Type *t)
+{
+	return *getinarg(t);
+}
+
+/*
+ * return !(op)
+ * eg == <=> !=
+ */
+int
+brcom(int a)
+{
+	switch(a) {
+	case OEQ:	return ONE;
+	case ONE:	return OEQ;
+	case OLT:	return OGE;
+	case OGT:	return OLE;
+	case OLE:	return OGT;
+	case OGE:	return OLT;
+	}
+	fatal("brcom: no com for %A\n", a);
+	return a;
+}
+
+/*
+ * return reverse(op)
+ * eg a op b <=> b r(op) a
+ */
+int
+brrev(int a)
+{
+	switch(a) {
+	case OEQ:	return OEQ;
+	case ONE:	return ONE;
+	case OLT:	return OGT;
+	case OGT:	return OLT;
+	case OLE:	return OGE;
+	case OGE:	return OLE;
+	}
+	fatal("brcom: no rev for %A\n", a);
+	return a;
+}
+
+/*
+ * return side effect-free n, appending side effects to init.
+ * result is assignable if n is.
+ */
+Node*
+safeexpr(Node *n, NodeList **init)
+{
+	Node *l;
+	Node *r;
+	Node *a;
+
+	if(n == N)
+		return N;
+
+	if(n->ninit) {
+		walkstmtlist(n->ninit);
+		*init = concat(*init, n->ninit);
+		n->ninit = nil;
+	}
+
+	switch(n->op) {
+	case ONAME:
+	case OLITERAL:
+		return n;
+
+	case ODOT:
+		l = safeexpr(n->left, init);
+		if(l == n->left)
+			return n;
+		r = nod(OXXX, N, N);
+		*r = *n;
+		r->left = l;
+		typecheck(&r, Erv);
+		walkexpr(&r, init);
+		return r;
+
+	case ODOTPTR:
+	case OIND:
+		l = safeexpr(n->left, init);
+		if(l == n->left)
+			return n;
+		a = nod(OXXX, N, N);
+		*a = *n;
+		a->left = l;
+		walkexpr(&a, init);
+		return a;
+
+	case OINDEX:
+	case OINDEXMAP:
+		l = safeexpr(n->left, init);
+		r = safeexpr(n->right, init);
+		if(l == n->left && r == n->right)
+			return n;
+		a = nod(OXXX, N, N);
+		*a = *n;
+		a->left = l;
+		a->right = r;
+		walkexpr(&a, init);
+		return a;
+	}
+
+	// make a copy; must not be used as an lvalue
+	if(islvalue(n))
+		fatal("missing lvalue case in safeexpr: %N", n);
+	return cheapexpr(n, init);
+}
+
+Node*
+copyexpr(Node *n, Type *t, NodeList **init)
+{
+	Node *a, *l;
+	
+	l = temp(t);
+	a = nod(OAS, l, n);
+	typecheck(&a, Etop);
+	walkexpr(&a, init);
+	*init = list(*init, a);
+	return l;
+}
+
+/*
+ * return side-effect free and cheap n, appending side effects to init.
+ * result may not be assignable.
+ */
+Node*
+cheapexpr(Node *n, NodeList **init)
+{
+	switch(n->op) {
+	case ONAME:
+	case OLITERAL:
+		return n;
+	}
+
+	return copyexpr(n, n->type, init);
+}
+
+/*
+ * return n in a local variable of type t if it is not already.
+ * the value is guaranteed not to change except by direct
+ * assignment to it.
+ */
+Node*
+localexpr(Node *n, Type *t, NodeList **init)
+{
+	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;
+	
+	return copyexpr(n, t, init);
+}
+
+void
+setmaxarg(Type *t)
+{
+	int64 w;
+
+	dowidth(t);
+	w = t->argwid;
+	if(t->argwid >= MAXWIDTH)
+		fatal("bad argwid %T", t);
+	if(w > maxarg)
+		maxarg = w;
+}
+
+/*
+ * unicode-aware case-insensitive strcmp
+ */
+
+static int
+ucistrcmp(char *p, char *q)
+{
+	Rune rp, rq;
+
+	while(*p || *q) {
+		if(*p == 0)
+			return +1;
+		if(*q == 0)
+			return -1;
+		p += chartorune(&rp, p);
+		q += chartorune(&rq, q);
+		rp = tolowerrune(rp);
+		rq = tolowerrune(rq);
+		if(rp < rq)
+			return -1;
+		if(rp > rq)
+			return +1;
+	}
+	return 0;
+}
+
+/*
+ * code to resolve elided DOTs
+ * in embedded types
+ */
+
+// search depth 0 --
+// return count of fields+methods
+// found with a given name
+static int
+lookdot0(Sym *s, Type *t, Type **save, int ignorecase)
+{
+	Type *f, *u;
+	int c;
+
+	u = t;
+	if(isptr[u->etype])
+		u = u->type;
+
+	c = 0;
+	if(u->etype == TSTRUCT || u->etype == TINTER) {
+		for(f=u->type; f!=T; f=f->down)
+			if(f->sym == s || (ignorecase && f->type->etype == TFUNC && f->type->thistuple > 0 && ucistrcmp(f->sym->name, s->name) == 0)) {
+				if(save)
+					*save = f;
+				c++;
+			}
+	}
+	u = methtype(t, 0);
+	if(u != T) {
+		for(f=u->method; f!=T; f=f->down)
+			if(f->embedded == 0 && (f->sym == s || (ignorecase && ucistrcmp(f->sym->name, s->name) == 0))) {
+				if(save)
+					*save = f;
+				c++;
+			}
+	}
+	return c;
+}
+
+// search depth d for field/method s --
+// return count of fields+methods
+// found at search depth.
+// answer is in dotlist array and
+// count of number of ways is returned.
+int
+adddot1(Sym *s, Type *t, int d, Type **save, int ignorecase)
+{
+	Type *f, *u;
+	int c, a;
+
+	if(t->trecur)
+		return 0;
+	t->trecur = 1;
+
+	if(d == 0) {
+		c = lookdot0(s, t, save, ignorecase);
+		goto out;
+	}
+
+	c = 0;
+	u = t;
+	if(isptr[u->etype])
+		u = u->type;
+	if(u->etype != TSTRUCT && u->etype != TINTER)
+		goto out;
+
+	d--;
+	for(f=u->type; f!=T; f=f->down) {
+		if(!f->embedded)
+			continue;
+		if(f->sym == S)
+			continue;
+		a = adddot1(s, f->type, d, save, ignorecase);
+		if(a != 0 && c == 0)
+			dotlist[d].field = f;
+		c += a;
+	}
+
+out:
+	t->trecur = 0;
+	return c;
+}
+
+// in T.field
+// find missing fields that
+// will give shortest unique addressing.
+// modify the tree with missing type names.
+Node*
+adddot(Node *n)
+{
+	Type *t;
+	Sym *s;
+	int c, d;
+
+	typecheck(&n->left, Etype|Erv);
+	n->diag |= n->left->diag;
+	t = n->left->type;
+	if(t == T)
+		goto ret;
+	
+	if(n->left->op == OTYPE)
+		goto ret;
+
+	if(n->right->op != ONAME)
+		goto ret;
+	s = n->right->sym;
+	if(s == S)
+		goto ret;
+
+	for(d=0; d<nelem(dotlist); d++) {
+		c = adddot1(s, t, d, nil, 0);
+		if(c > 0)
+			goto out;
+	}
+	goto ret;
+
+out:
+	if(c > 1) {
+		yyerror("ambiguous selector %N", n);
+		n->left = N;
+		return n;
+	}
+
+	// rebuild elided dots
+	for(c=d-1; c>=0; c--)
+		n->left = nod(ODOT, n->left, newname(dotlist[c].field->sym));
+ret:
+	return n;
+}
+
+
+/*
+ * code to help generate trampoline
+ * functions for methods on embedded
+ * subtypes.
+ * these are approx the same as
+ * the corresponding adddot routines
+ * except that they expect to be called
+ * with unique tasks and they return
+ * the actual methods.
+ */
+
+typedef	struct	Symlink	Symlink;
+struct	Symlink
+{
+	Type*		field;
+	uchar		good;
+	uchar		followptr;
+	Symlink*	link;
+};
+static	Symlink*	slist;
+
+static void
+expand0(Type *t, int followptr)
+{
+	Type *f, *u;
+	Symlink *sl;
+
+	u = t;
+	if(isptr[u->etype]) {
+		followptr = 1;
+		u = u->type;
+	}
+
+	if(u->etype == TINTER) {
+		for(f=u->type; f!=T; f=f->down) {
+			if(f->sym->flags & SymUniq)
+				continue;
+			f->sym->flags |= SymUniq;
+			sl = mal(sizeof(*sl));
+			sl->field = f;
+			sl->link = slist;
+			sl->followptr = followptr;
+			slist = sl;
+		}
+		return;
+	}
+
+	u = methtype(t, 0);
+	if(u != T) {
+		for(f=u->method; f!=T; f=f->down) {
+			if(f->sym->flags & SymUniq)
+				continue;
+			f->sym->flags |= SymUniq;
+			sl = mal(sizeof(*sl));
+			sl->field = f;
+			sl->link = slist;
+			sl->followptr = followptr;
+			slist = sl;
+		}
+	}
+}
+
+static void
+expand1(Type *t, int d, int followptr)
+{
+	Type *f, *u;
+
+	if(t->trecur)
+		return;
+	if(d == 0)
+		return;
+	t->trecur = 1;
+
+	if(d != nelem(dotlist)-1)
+		expand0(t, followptr);
+
+	u = t;
+	if(isptr[u->etype]) {
+		followptr = 1;
+		u = u->type;
+	}
+	if(u->etype != TSTRUCT && u->etype != TINTER)
+		goto out;
+
+	for(f=u->type; f!=T; f=f->down) {
+		if(!f->embedded)
+			continue;
+		if(f->sym == S)
+			continue;
+		expand1(f->type, d-1, followptr);
+	}
+
+out:
+	t->trecur = 0;
+}
+
+void
+expandmeth(Type *t)
+{
+	Symlink *sl;
+	Type *f;
+	int c, d;
+
+	if(t == T || t->xmethod != nil)
+		return;
+
+	// mark top-level method symbols
+	// so that expand1 doesn't consider them.
+	for(f=t->method; f != nil; f=f->down)
+		f->sym->flags |= SymUniq;
+
+	// generate all reachable methods
+	slist = nil;
+	expand1(t, nelem(dotlist)-1, 0);
+
+	// check each method to be uniquely reachable
+	for(sl=slist; sl!=nil; sl=sl->link) {
+		sl->field->sym->flags &= ~SymUniq;
+		for(d=0; d<nelem(dotlist); d++) {
+			c = adddot1(sl->field->sym, t, d, &f, 0);
+			if(c == 0)
+				continue;
+			if(c == 1) {
+				// addot1 may have dug out arbitrary fields, we only want methods.
+				if(f->type->etype == TFUNC && f->type->thistuple > 0) {
+					sl->good = 1;
+					sl->field = f;
+				}
+			}
+			break;
+		}
+	}
+
+	for(f=t->method; f != nil; f=f->down)
+		f->sym->flags &= ~SymUniq;
+
+	t->xmethod = t->method;
+	for(sl=slist; sl!=nil; sl=sl->link) {
+		if(sl->good) {
+			// add it to the base type method list
+			f = typ(TFIELD);
+			*f = *sl->field;
+			f->embedded = 1;	// needs a trampoline
+			if(sl->followptr)
+				f->embedded = 2;
+			f->down = t->xmethod;
+			t->xmethod = f;
+		}
+	}
+}
+
+/*
+ * Given funarg struct list, return list of ODCLFIELD Node fn args.
+ */
+static NodeList*
+structargs(Type **tl, int mustname)
+{
+	Iter savet;
+	Node *a, *n;
+	NodeList *args;
+	Type *t;
+	char buf[100];
+	int gen;
+
+	args = nil;
+	gen = 0;
+	for(t = structfirst(&savet, tl); t != T; t = structnext(&savet)) {
+		n = N;
+		if(mustname && (t->sym == nil || strcmp(t->sym->name, "_") == 0)) {
+			// invent a name so that we can refer to it in the trampoline
+			snprint(buf, sizeof buf, ".anon%d", gen++);
+			n = newname(lookup(buf));
+		} else if(t->sym)
+			n = newname(t->sym);
+		a = nod(ODCLFIELD, n, typenod(t->type));
+		a->isddd = t->isddd;
+		if(n != N)
+			n->isddd = t->isddd;
+		args = list(args, a);
+	}
+	return args;
+}
+
+/*
+ * Generate a wrapper function to convert from
+ * a receiver of type T to a receiver of type U.
+ * That is,
+ *
+ *	func (t T) M() {
+ *		...
+ *	}
+ *
+ * already exists; this function generates
+ *
+ *	func (u U) M() {
+ *		u.M()
+ *	}
+ *
+ * where the types T and U are such that u.M() is valid
+ * and calls the T.M method.
+ * The resulting function is for use in method tables.
+ *
+ *	rcvr - U
+ *	method - M func (t T)(), a TFIELD type struct
+ *	newnam - the eventual mangled name of this function
+ */
+void
+genwrapper(Type *rcvr, Type *method, Sym *newnam, int iface)
+{
+	Node *this, *fn, *call, *n, *t, *pad, *dot, *as;
+	NodeList *l, *args, *in, *out;
+	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);
+
+	lexlineno++;
+	lineno = lexlineno;
+	if (linehistdone == 0) {
+		// All the wrappers can share the same linehist entry.
+		linehist("<autogenerated>", 0, 0);
+		linehistdone = 1;
+	}
+
+	dclcontext = PEXTERN;
+	markdcl();
+
+	this = nod(ODCLFIELD, newname(lookup(".this")), typenod(rcvr));
+	this->left->ntype = this->right;
+	in = structargs(getinarg(method->type), 1);
+	out = structargs(getoutarg(method->type), 0);
+
+	t = nod(OTFUNC, N, N);
+	l = list1(this);
+	if(iface && rcvr->width < types[tptr]->width) {
+		// Building method for interface table and receiver
+		// is smaller than the single pointer-sized word
+		// that the interface call will pass in.
+		// Add a dummy padding argument after the
+		// receiver to make up the difference.
+		tpad = typ(TARRAY);
+		tpad->type = types[TUINT8];
+		tpad->bound = types[tptr]->width - rcvr->width;
+		pad = nod(ODCLFIELD, newname(lookup(".pad")), typenod(tpad));
+		l = list(l, pad);
+	}
+	t->list = concat(l, in);
+	t->rlist = out;
+
+	fn = nod(ODCLFUNC, N, N);
+	fn->nname = newname(newnam);
+	fn->nname->defn = fn;
+	fn->nname->ntype = t;
+	declare(fn->nname, PFUNC);
+	funchdr(fn);
+
+	// arg list
+	args = nil;
+	isddd = 0;
+	for(l=in; l; l=l->next) {
+		args = list(args, l->n->left);
+		isddd = l->n->left->isddd;
+	}
+	
+	methodrcvr = getthisx(method->type)->type->type;
+
+	// generate nil pointer check for better error
+	if(isptr[rcvr->etype] && rcvr->type == methodrcvr) {
+		// generating wrapper from *T to T.
+		n = nod(OIF, N, N);
+		n->ntest = nod(OEQ, this->left, nodnil());
+		// these strings are already in the reflect tables,
+		// so no space cost to use them here.
+		l = nil;
+		v.ctype = CTSTR;
+		v.u.sval = strlit(rcvr->type->sym->pkg->name);  // package name
+		l = list(l, nodlit(v));
+		v.u.sval = strlit(rcvr->type->sym->name);  // type name
+		l = list(l, nodlit(v));
+		v.u.sval = strlit(method->sym->name);
+		l = list(l, nodlit(v));  // method name
+		call = nod(OCALL, syslook("panicwrap", 0), N);
+		call->list = l;
+		n->nbody = list1(call);
+		fn->nbody = list(fn->nbody, n);
+	}
+	
+	dot = adddot(nod(OXDOT, this->left, newname(method->sym)));
+	
+	// generate call
+	if(!flag_race && isptr[rcvr->etype] && isptr[methodrcvr->etype] && method->embedded && !isifacemethod(method->type)) {
+		// generate tail call: adjust pointer receiver and jump to embedded method.
+		dot = dot->left;	// skip final .M
+		if(!isptr[dotlist[0].field->type->etype])
+			dot = nod(OADDR, dot, N);
+		as = nod(OAS, this->left, nod(OCONVNOP, dot, N));
+		as->right->type = rcvr;
+		fn->nbody = list(fn->nbody, as);
+		n = nod(ORETJMP, N, N);
+		n->left = newname(methodsym(method->sym, methodrcvr, 0));
+		fn->nbody = list(fn->nbody, n);
+	} else {
+		fn->wrapper = 1; // ignore frame for panic+recover matching
+		call = nod(OCALL, dot, N);
+		call->list = args;
+		call->isddd = isddd;
+		if(method->type->outtuple > 0) {
+			n = nod(ORETURN, N, N);
+			n->list = list1(call);
+			call = n;
+		}
+		fn->nbody = list(fn->nbody, call);
+	}
+
+	if(0 && debug['r'])
+		dumplist("genwrapper body", fn->nbody);
+
+	funcbody(fn);
+	curfn = fn;
+	// 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);
+
+	// Set inl_nonlocal to whether we are calling a method on a
+	// type defined in a different package.  Checked in inlvar.
+	if(!methodrcvr->local)
+		inl_nonlocal = 1;
+
+	inlcalls(fn);
+
+	inl_nonlocal = 0;
+
+	curfn = nil;
+	funccompile(fn, 0);
+}
+
+static Node*
+hashmem(Type *t)
+{
+	Node *tfn, *n;
+	Sym *sym;
+	
+	sym = pkglookup("memhash", runtimepkg);
+
+	n = newname(sym);
+	n->class = PFUNC;
+	tfn = nod(OTFUNC, N, N);
+	tfn->list = list(tfn->list, nod(ODCLFIELD, N, typenod(ptrto(t))));
+	tfn->list = list(tfn->list, nod(ODCLFIELD, N, typenod(types[TUINTPTR])));
+	tfn->list = list(tfn->list, nod(ODCLFIELD, N, typenod(types[TUINTPTR])));
+	tfn->rlist = list(tfn->rlist, nod(ODCLFIELD, N, typenod(types[TUINTPTR])));
+	typecheck(&tfn, Etype);
+	n->type = tfn->type;
+	return n;
+}
+
+static Node*
+hashfor(Type *t)
+{
+	int a;
+	Sym *sym;
+	Node *tfn, *n;
+
+	a = algtype1(t, nil);
+	switch(a) {
+	case AMEM:
+		return hashmem(t);
+	case AINTER:
+		sym = pkglookup("interhash", runtimepkg);
+		break;
+	case ANILINTER:
+		sym = pkglookup("nilinterhash", runtimepkg);
+		break;
+	case ASTRING:
+		sym = pkglookup("strhash", runtimepkg);
+		break;
+	case AFLOAT32:
+		sym = pkglookup("f32hash", runtimepkg);
+		break;
+	case AFLOAT64:
+		sym = pkglookup("f64hash", runtimepkg);
+		break;
+	case ACPLX64:
+		sym = pkglookup("c64hash", runtimepkg);
+		break;
+	case ACPLX128:
+		sym = pkglookup("c128hash", runtimepkg);
+		break;
+	default:
+		sym = typesymprefix(".hash", t);
+		break;
+	}
+
+	n = newname(sym);
+	n->class = PFUNC;
+	tfn = nod(OTFUNC, N, N);
+	tfn->list = list(tfn->list, nod(ODCLFIELD, N, typenod(ptrto(t))));
+	tfn->list = list(tfn->list, nod(ODCLFIELD, N, typenod(types[TUINTPTR])));
+	tfn->list = list(tfn->list, nod(ODCLFIELD, N, typenod(types[TUINTPTR])));
+	tfn->rlist = list(tfn->rlist, nod(ODCLFIELD, N, typenod(types[TUINTPTR])));
+	typecheck(&tfn, Etype);
+	n->type = tfn->type;
+	return n;
+}
+
+/*
+ * Generate a helper function to compute the hash of a value of type t.
+ */
+void
+genhash(Sym *sym, Type *t)
+{
+	Node *n, *fn, *np, *nh, *ni, *call, *nx, *na, *tfn, *r;
+	Node *hashel;
+	Type *first, *t1;
+	int old_safemode;
+	int64 size, mul, offend;
+
+	if(debug['r'])
+		print("genhash %S %T\n", sym, t);
+
+	lineno = 1;  // less confusing than end of input
+	dclcontext = PEXTERN;
+	markdcl();
+
+	// func sym(p *T, s uintptr, h uintptr) uintptr
+	fn = nod(ODCLFUNC, N, N);
+	fn->nname = newname(sym);
+	fn->nname->class = PFUNC;
+	tfn = nod(OTFUNC, N, N);
+	fn->nname->ntype = tfn;
+
+	n = nod(ODCLFIELD, newname(lookup("p")), typenod(ptrto(t)));
+	tfn->list = list(tfn->list, n);
+	np = n->left;
+	n = nod(ODCLFIELD, newname(lookup("s")), typenod(types[TUINTPTR]));
+	tfn->list = list(tfn->list, n);
+	n = nod(ODCLFIELD, newname(lookup("h")), typenod(types[TUINTPTR]));
+	tfn->list = list(tfn->list, n);
+	nh = n->left;
+	n = nod(ODCLFIELD, N, typenod(types[TUINTPTR])); // return value
+	tfn->rlist = list(tfn->rlist, n);
+
+	funchdr(fn);
+	typecheck(&fn->nname->ntype, Etype);
+
+	// genhash is only called for types that have equality but
+	// cannot be handled by the standard algorithms,
+	// so t must be either an array or a struct.
+	switch(t->etype) {
+	default:
+		fatal("genhash %T", t);
+	case TARRAY:
+		if(isslice(t))
+			fatal("genhash %T", t);
+		// An array of pure memory would be handled by the
+		// standard algorithm, so the element type must not be
+		// pure memory.
+		hashel = hashfor(t->type);
+		n = nod(ORANGE, N, nod(OIND, np, N));
+		ni = newname(lookup("i"));
+		ni->type = types[TINT];
+		n->list = list1(ni);
+		n->colas = 1;
+		colasdefn(n->list, n);
+		ni = n->list->n;
+
+		// TODO: with aeshash we don't need these shift/mul parts
+
+		// h = h<<3 | h>>61
+		n->nbody = list(n->nbody,
+			nod(OAS,
+			    nh,
+				nod(OOR,
+					nod(OLSH, nh, nodintconst(3)),
+					nod(ORSH, nh, nodintconst(widthptr*8-3)))));
+
+		// h *= mul
+		// Same multipliers as in runtime.memhash.
+		if(widthptr == 4)
+			mul = 3267000013LL;
+		else
+			mul = 23344194077549503LL;
+		n->nbody = list(n->nbody,
+			nod(OAS,
+				nh,
+				nod(OMUL, nh, nodintconst(mul))));
+
+		// h = hashel(&p[i], sizeof(p[i]), h)
+		call = nod(OCALL, hashel, N);
+		nx = nod(OINDEX, np, ni);
+		nx->bounded = 1;
+		na = nod(OADDR, nx, N);
+		na->etype = 1;  // no escape to heap
+		call->list = list(call->list, na);
+		call->list = list(call->list, nodintconst(t->type->width));
+		call->list = list(call->list, nh);
+		n->nbody = list(n->nbody, nod(OAS, nh, call));
+
+		fn->nbody = list(fn->nbody, n);
+		break;
+
+	case TSTRUCT:
+		// Walk the struct using memhash for runs of AMEM
+		// and calling specific hash functions for the others.
+		first = T;
+		offend = 0;
+		for(t1=t->type;; t1=t1->down) {
+			if(t1 != T && algtype1(t1->type, nil) == AMEM && !isblanksym(t1->sym)) {
+				offend = t1->width + t1->type->width;
+				if(first == T)
+					first = t1;
+				// If it's a memory field but it's padded, stop here.
+				if(ispaddedfield(t1, t->width))
+					t1 = t1->down;
+				else
+					continue;
+			}
+			// Run memhash for fields up to this one.
+			if(first != T) {
+				size = offend - first->width; // first->width is offset
+				hashel = hashmem(first->type);
+				// h = hashel(&p.first, size, h)
+				call = nod(OCALL, hashel, N);
+				nx = nod(OXDOT, np, newname(first->sym));  // TODO: fields from other packages?
+				na = nod(OADDR, nx, N);
+				na->etype = 1;  // no escape to heap
+				call->list = list(call->list, na);
+				call->list = list(call->list, nodintconst(size));
+				call->list = list(call->list, nh);
+				fn->nbody = list(fn->nbody, nod(OAS, nh, call));
+
+				first = T;
+			}
+			if(t1 == T)
+				break;
+			if(isblanksym(t1->sym))
+				continue;
+
+			// Run hash for this field.
+			hashel = hashfor(t1->type);
+			// h = hashel(&p.t1, size, h)
+			call = nod(OCALL, hashel, N);
+			nx = nod(OXDOT, np, newname(t1->sym));  // TODO: fields from other packages?
+			na = nod(OADDR, nx, N);
+			na->etype = 1;  // no escape to heap
+			call->list = list(call->list, na);
+			call->list = list(call->list, nodintconst(t1->type->width));
+			call->list = list(call->list, nh);
+			fn->nbody = list(fn->nbody, nod(OAS, nh, call));
+		}
+		break;
+	}
+	r = nod(ORETURN, N, N);
+	r->list = list(r->list, nh);
+	fn->nbody = list(fn->nbody, r);
+
+	if(debug['r'])
+		dumplist("genhash body", fn->nbody);
+
+	funcbody(fn);
+	curfn = fn;
+	fn->dupok = 1;
+	typecheck(&fn, Etop);
+	typechecklist(fn->nbody, Etop);
+	curfn = nil;
+
+	// Disable safemode while compiling this code: the code we
+	// generate internally can refer to unsafe.Pointer.
+	// In this case it can happen if we need to generate an ==
+	// for a struct containing a reflect.Value, which itself has
+	// an unexported field of type unsafe.Pointer.
+	old_safemode = safemode;
+	safemode = 0;
+	funccompile(fn, 0);
+	safemode = old_safemode;
+}
+
+// Return node for
+//	if p.field != q.field { return false }
+static Node*
+eqfield(Node *p, Node *q, Node *field)
+{
+	Node *nif, *nx, *ny, *r;
+
+	nx = nod(OXDOT, p, field);
+	ny = nod(OXDOT, q, field);
+	nif = nod(OIF, N, N);
+	nif->ntest = nod(ONE, nx, ny);
+	r = nod(ORETURN, N, N);
+	r->list = list(r->list, nodbool(0));
+	nif->nbody = list(nif->nbody, r);
+	return nif;
+}
+
+static Node*
+eqmemfunc(vlong size, Type *type)
+{
+	char buf[30];
+	Node *fn;
+
+	switch(size) {
+	default:
+		fn = syslook("memequal", 1);
+		break;
+	case 1:
+	case 2:
+	case 4:
+	case 8:
+	case 16:
+		snprint(buf, sizeof buf, "memequal%d", (int)size*8);
+		fn = syslook(buf, 1);
+		break;
+	}
+	argtype(fn, type);
+	argtype(fn, type);
+	return fn;
+}
+
+// Return node for
+//	if !memequal(&p.field, &q.field, size) { return false }
+static Node*
+eqmem(Node *p, Node *q, Node *field, vlong size)
+{
+	Node *nif, *nx, *ny, *call, *r;
+
+	nx = nod(OADDR, nod(OXDOT, p, field), N);
+	nx->etype = 1;  // does not escape
+	ny = nod(OADDR, nod(OXDOT, q, field), N);
+	ny->etype = 1;  // does not escape
+	typecheck(&nx, Erv);
+	typecheck(&ny, Erv);
+
+	call = nod(OCALL, eqmemfunc(size, nx->type->type), N);
+	call->list = list(call->list, nx);
+	call->list = list(call->list, ny);
+	call->list = list(call->list, nodintconst(size));
+
+	nif = nod(OIF, N, N);
+	nif->ninit = list(nif->ninit, call);
+	nif->ntest = nod(ONOT, call, N);
+	r = nod(ORETURN, N, N);
+	r->list = list(r->list, nodbool(0));
+	nif->nbody = list(nif->nbody, r);
+	return nif;
+}
+
+/*
+ * Generate a helper function to check equality of two values of type t.
+ */
+void
+geneq(Sym *sym, Type *t)
+{
+	Node *n, *fn, *np, *nq, *tfn, *nif, *ni, *nx, *ny, *nrange, *r;
+	Type *t1, *first;
+	int old_safemode;
+	int64 size;
+	int64 offend;
+
+	if(debug['r'])
+		print("geneq %S %T\n", sym, t);
+
+	lineno = 1;  // less confusing than end of input
+	dclcontext = PEXTERN;
+	markdcl();
+
+	// func sym(p, q *T, s uintptr) bool
+	fn = nod(ODCLFUNC, N, N);
+	fn->nname = newname(sym);
+	fn->nname->class = PFUNC;
+	tfn = nod(OTFUNC, N, N);
+	fn->nname->ntype = tfn;
+
+	n = nod(ODCLFIELD, newname(lookup("p")), typenod(ptrto(t)));
+	tfn->list = list(tfn->list, n);
+	np = n->left;
+	n = nod(ODCLFIELD, newname(lookup("q")), typenod(ptrto(t)));
+	tfn->list = list(tfn->list, n);
+	nq = n->left;
+	n = nod(ODCLFIELD, newname(lookup("s")), typenod(types[TUINTPTR]));
+	tfn->list = list(tfn->list, n);
+	n = nod(ODCLFIELD, N, typenod(types[TBOOL]));
+	tfn->rlist = list(tfn->rlist, n);
+
+	funchdr(fn);
+
+	// geneq is only called for types that have equality but
+	// cannot be handled by the standard algorithms,
+	// so t must be either an array or a struct.
+	switch(t->etype) {
+	default:
+		fatal("geneq %T", t);
+	case TARRAY:
+		if(isslice(t))
+			fatal("geneq %T", t);
+		// An array of pure memory would be handled by the
+		// standard memequal, so the element type must not be
+		// pure memory.  Even if we unrolled the range loop,
+		// each iteration would be a function call, so don't bother
+		// unrolling.
+		nrange = nod(ORANGE, N, nod(OIND, np, N));
+		ni = newname(lookup("i"));
+		ni->type = types[TINT];
+		nrange->list = list1(ni);
+		nrange->colas = 1;
+		colasdefn(nrange->list, nrange);
+		ni = nrange->list->n;
+		
+		// if p[i] != q[i] { return false }
+		nx = nod(OINDEX, np, ni);
+		nx->bounded = 1;
+		ny = nod(OINDEX, nq, ni);
+		ny->bounded = 1;
+
+		nif = nod(OIF, N, N);
+		nif->ntest = nod(ONE, nx, ny);
+		r = nod(ORETURN, N, N);
+		r->list = list(r->list, nodbool(0));
+		nif->nbody = list(nif->nbody, r);
+		nrange->nbody = list(nrange->nbody, nif);
+		fn->nbody = list(fn->nbody, nrange);
+		break;
+
+	case TSTRUCT:
+		// Walk the struct using memequal for runs of AMEM
+		// and calling specific equality tests for the others.
+		// Skip blank-named fields.
+		first = T;
+		offend = 0;
+		for(t1=t->type;; t1=t1->down) {
+			if(t1 != T && algtype1(t1->type, nil) == AMEM && !isblanksym(t1->sym)) {
+				offend = t1->width + t1->type->width;
+				if(first == T)
+					first = t1;
+				// If it's a memory field but it's padded, stop here.
+				if(ispaddedfield(t1, t->width))
+					t1 = t1->down;
+				else
+					continue;
+			}
+			// Run memequal for fields up to this one.
+			// TODO(rsc): All the calls to newname are wrong for
+			// cross-package unexported fields.
+			if(first != T) {
+				if(first->down == t1) {
+					fn->nbody = list(fn->nbody, eqfield(np, nq, newname(first->sym)));
+				} else if(first->down->down == t1) {
+					fn->nbody = list(fn->nbody, eqfield(np, nq, newname(first->sym)));
+					first = first->down;
+					if(!isblanksym(first->sym))
+						fn->nbody = list(fn->nbody, eqfield(np, nq, newname(first->sym)));
+				} else {
+					// More than two fields: use memequal.
+					size = offend - first->width; // first->width is offset
+					fn->nbody = list(fn->nbody, eqmem(np, nq, newname(first->sym), size));
+				}
+				first = T;
+			}
+			if(t1 == T)
+				break;
+			if(isblanksym(t1->sym))
+				continue;
+
+			// Check this field, which is not just memory.
+			fn->nbody = list(fn->nbody, eqfield(np, nq, newname(t1->sym)));
+		}
+
+		break;
+	}
+
+	// return true
+	r = nod(ORETURN, N, N);
+	r->list = list(r->list, nodbool(1));
+	fn->nbody = list(fn->nbody, r);
+
+	if(debug['r'])
+		dumplist("geneq body", fn->nbody);
+
+	funcbody(fn);
+	curfn = fn;
+	fn->dupok = 1;
+	typecheck(&fn, Etop);
+	typechecklist(fn->nbody, Etop);
+	curfn = nil;
+	
+	// Disable safemode while compiling this code: the code we
+	// generate internally can refer to unsafe.Pointer.
+	// In this case it can happen if we need to generate an ==
+	// for a struct containing a reflect.Value, which itself has
+	// an unexported field of type unsafe.Pointer.
+	old_safemode = safemode;
+	safemode = 0;
+	funccompile(fn, 0);
+	safemode = old_safemode;
+}
+
+static Type*
+ifacelookdot(Sym *s, Type *t, int *followptr, int ignorecase)
+{
+	int i, c, d;
+	Type *m;
+
+	*followptr = 0;
+
+	if(t == T)
+		return T;
+
+	for(d=0; d<nelem(dotlist); d++) {
+		c = adddot1(s, t, d, &m, ignorecase);
+		if(c > 1) {
+			yyerror("%T.%S is ambiguous", t, s);
+			return T;
+		}
+		if(c == 1) {
+			for(i=0; i<d; i++) {
+				if(isptr[dotlist[i].field->type->etype]) {
+					*followptr = 1;
+					break;
+				}
+			}
+			if(m->type->etype != TFUNC || m->type->thistuple == 0) {
+				yyerror("%T.%S is a field, not a method", t, s);
+				return T;
+			}
+			return m;
+		}
+	}
+	return T;
+}
+
+int
+implements(Type *t, Type *iface, Type **m, Type **samename, int *ptr)
+{
+	Type *t0, *im, *tm, *rcvr, *imtype;
+	int followptr;
+
+	t0 = t;
+	if(t == T)
+		return 0;
+
+	// if this is too slow,
+	// could sort these first
+	// and then do one loop.
+
+	if(t->etype == TINTER) {
+		for(im=iface->type; im; im=im->down) {
+			for(tm=t->type; tm; tm=tm->down) {
+				if(tm->sym == im->sym) {
+					if(eqtype(tm->type, im->type))
+						goto found;
+					*m = im;
+					*samename = tm;
+					*ptr = 0;
+					return 0;
+				}
+			}
+			*m = im;
+			*samename = nil;
+			*ptr = 0;
+			return 0;
+		found:;
+		}
+		return 1;
+	}
+
+	t = methtype(t, 0);
+	if(t != T)
+		expandmeth(t);
+	for(im=iface->type; im; im=im->down) {
+		imtype = methodfunc(im->type, 0);
+		tm = ifacelookdot(im->sym, t, &followptr, 0);
+		if(tm == T || tm->nointerface || !eqtype(methodfunc(tm->type, 0), imtype)) {
+			if(tm == T)
+				tm = ifacelookdot(im->sym, t, &followptr, 1);
+			*m = im;
+			*samename = tm;
+			*ptr = 0;
+			return 0;
+		}
+		// if pointer receiver in method,
+		// the method does not exist for value types.
+		rcvr = getthisx(tm->type)->type->type;
+		if(isptr[rcvr->etype] && !isptr[t0->etype] && !followptr && !isifacemethod(tm->type)) {
+			if(0 && debug['r'])
+				yyerror("interface pointer mismatch");
+
+			*m = im;
+			*samename = nil;
+			*ptr = 1;
+			return 0;
+		}
+	}
+	return 1;
+}
+
+/*
+ * even simpler simtype; get rid of ptr, bool.
+ * assuming that the front end has rejected
+ * all the invalid conversions (like ptr -> bool)
+ */
+int
+simsimtype(Type *t)
+{
+	int et;
+
+	if(t == 0)
+		return 0;
+
+	et = simtype[t->etype];
+	switch(et) {
+	case TPTR32:
+		et = TUINT32;
+		break;
+	case TPTR64:
+		et = TUINT64;
+		break;
+	case TBOOL:
+		et = TUINT8;
+		break;
+	}
+	return et;
+}
+
+NodeList*
+concat(NodeList *a, NodeList *b)
+{
+	if(a == nil)
+		return b;
+	if(b == nil)
+		return a;
+
+	a->end->next = b;
+	a->end = b->end;
+	b->end = nil;
+	return a;
+}
+
+NodeList*
+list1(Node *n)
+{
+	NodeList *l;
+
+	if(n == nil)
+		return nil;
+	if(n->op == OBLOCK && n->ninit == nil) {
+		// Flatten list and steal storage.
+		// Poison pointer to catch errant uses.
+		l = n->list;
+		n->list = (NodeList*)1;
+		return l;
+	}
+	l = mal(sizeof *l);
+	l->n = n;
+	l->end = l;
+	return l;
+}
+
+NodeList*
+list(NodeList *l, Node *n)
+{
+	return concat(l, list1(n));
+}
+
+void
+listsort(NodeList** l, int(*f)(Node*, Node*))
+{
+	NodeList *l1, *l2, *le;
+
+	if(*l == nil || (*l)->next == nil)
+		return;
+
+	l1 = *l;
+	l2 = *l;
+	for(;;) {
+		l2 = l2->next;
+		if(l2 == nil)
+			break;
+		l2 = l2->next;
+		if(l2 == nil)
+			break;
+		l1 = l1->next;
+	}
+
+	l2 = l1->next;
+	l1->next = nil;
+	l2->end = (*l)->end;
+	(*l)->end = l1;
+
+	l1 = *l;
+	listsort(&l1, f);
+	listsort(&l2, f);
+
+	if((*f)(l1->n, l2->n) < 0) {
+		*l = l1;
+	} else {
+		*l = l2;
+		l2 = l1;
+		l1 = *l;
+	}
+
+	// now l1 == *l; and l1 < l2
+
+	while ((l1 != nil) && (l2 != nil)) {
+		while ((l1->next != nil) && (*f)(l1->next->n, l2->n) < 0)
+			l1 = l1->next;
+		
+		// l1 is last one from l1 that is < l2
+		le = l1->next;		// le is the rest of l1, first one that is >= l2
+		if(le != nil)
+			le->end = (*l)->end;
+
+		(*l)->end = l1;		// cut *l at l1
+		*l = concat(*l, l2);	// glue l2 to *l's tail
+
+		l1 = l2;		// l1 is the first element of *l that is < the new l2
+		l2 = le;		// ... because l2 now is the old tail of l1
+	}
+
+	*l = concat(*l, l2);		// any remainder 
+}
+
+NodeList*
+listtreecopy(NodeList *l)
+{
+	NodeList *out;
+
+	out = nil;
+	for(; l; l=l->next)
+		out = list(out, treecopy(l->n));
+	return out;
+}
+
+Node*
+liststmt(NodeList *l)
+{
+	Node *n;
+
+	n = nod(OBLOCK, N, N);
+	n->list = l;
+	if(l)
+		n->lineno = l->n->lineno;
+	return n;
+}
+
+/*
+ * return nelem of list
+ */
+int
+count(NodeList *l)
+{
+	vlong n;
+
+	n = 0;
+	for(; l; l=l->next)
+		n++;
+	if((int)n != n) { // Overflow.
+		yyerror("too many elements in list");
+	}
+	return n;
+}
+
+/*
+ * return nelem of list
+ */
+int
+structcount(Type *t)
+{
+	int v;
+	Iter s;
+
+	v = 0;
+	for(t = structfirst(&s, &t); t != T; t = structnext(&s))
+		v++;
+	return v;
+}
+
+/*
+ * return power of 2 of the constant
+ * operand. -1 if it is not a power of 2.
+ * 1000+ if it is a -(power of 2)
+ */
+int
+powtwo(Node *n)
+{
+	uvlong v, b;
+	int i;
+
+	if(n == N || n->op != OLITERAL || n->type == T)
+		goto no;
+	if(!isint[n->type->etype])
+		goto no;
+
+	v = mpgetfix(n->val.u.xval);
+	b = 1ULL;
+	for(i=0; i<64; i++) {
+		if(b == v)
+			return i;
+		b = b<<1;
+	}
+
+	if(!issigned[n->type->etype])
+		goto no;
+
+	v = -v;
+	b = 1ULL;
+	for(i=0; i<64; i++) {
+		if(b == v)
+			return i+1000;
+		b = b<<1;
+	}
+
+no:
+	return -1;
+}
+
+/*
+ * return the unsigned type for
+ * a signed integer type.
+ * returns T if input is not a
+ * signed integer type.
+ */
+Type*
+tounsigned(Type *t)
+{
+
+	// this is types[et+1], but not sure
+	// that this relation is immutable
+	switch(t->etype) {
+	default:
+		print("tounsigned: unknown type %T\n", t);
+		t = T;
+		break;
+	case TINT:
+		t = types[TUINT];
+		break;
+	case TINT8:
+		t = types[TUINT8];
+		break;
+	case TINT16:
+		t = types[TUINT16];
+		break;
+	case TINT32:
+		t = types[TUINT32];
+		break;
+	case TINT64:
+		t = types[TUINT64];
+		break;
+	}
+	return t;
+}
+
+/*
+ * magic number for signed division
+ * see hacker's delight chapter 10
+ */
+void
+smagic(Magic *m)
+{
+	int p;
+	uint64 ad, anc, delta, q1, r1, q2, r2, t;
+	uint64 mask, two31;
+
+	m->bad = 0;
+	switch(m->w) {
+	default:
+		m->bad = 1;
+		return;
+	case 8:
+		mask = 0xffLL;
+		break;
+	case 16:
+		mask = 0xffffLL;
+		break;
+	case 32:
+		mask = 0xffffffffLL;
+		break;
+	case 64:
+		mask = 0xffffffffffffffffULL;
+		break;
+	}
+	two31 = mask ^ (mask>>1);
+
+	p = m->w-1;
+	ad = m->sd;
+	if(m->sd < 0)
+		ad = -(uvlong)m->sd;
+
+	// bad denominators
+	if(ad == 0 || ad == 1 || ad == two31) {
+		m->bad = 1;
+		return;
+	}
+
+	t = two31;
+	ad &= mask;
+
+	anc = t - 1 - t%ad;
+	anc &= mask;
+
+	q1 = two31/anc;
+	r1 = two31 - q1*anc;
+	q1 &= mask;
+	r1 &= mask;
+
+	q2 = two31/ad;
+	r2 = two31 - q2*ad;
+	q2 &= mask;
+	r2 &= mask;
+
+	for(;;) {
+		p++;
+		q1 <<= 1;
+		r1 <<= 1;
+		q1 &= mask;
+		r1 &= mask;
+		if(r1 >= anc) {
+			q1++;
+			r1 -= anc;
+			q1 &= mask;
+			r1 &= mask;
+		}
+
+		q2 <<= 1;
+		r2 <<= 1;
+		q2 &= mask;
+		r2 &= mask;
+		if(r2 >= ad) {
+			q2++;
+			r2 -= ad;
+			q2 &= mask;
+			r2 &= mask;
+		}
+
+		delta = ad - r2;
+		delta &= mask;
+		if(q1 < delta || (q1 == delta && r1 == 0)) {
+			continue;
+		}
+		break;
+	}
+
+	m->sm = q2+1;
+	if(m->sm & two31)
+		m->sm |= ~mask;
+	m->s = p-m->w;
+}
+
+/*
+ * magic number for unsigned division
+ * see hacker's delight chapter 10
+ */
+void
+umagic(Magic *m)
+{
+	int p;
+	uint64 nc, delta, q1, r1, q2, r2;
+	uint64 mask, two31;
+
+	m->bad = 0;
+	m->ua = 0;
+
+	switch(m->w) {
+	default:
+		m->bad = 1;
+		return;
+	case 8:
+		mask = 0xffLL;
+		break;
+	case 16:
+		mask = 0xffffLL;
+		break;
+	case 32:
+		mask = 0xffffffffLL;
+		break;
+	case 64:
+		mask = 0xffffffffffffffffULL;
+		break;
+	}
+	two31 = mask ^ (mask>>1);
+
+	m->ud &= mask;
+	if(m->ud == 0 || m->ud == two31) {
+		m->bad = 1;
+		return;
+	}
+	nc = mask - (-m->ud&mask)%m->ud;
+	p = m->w-1;
+
+	q1 = two31/nc;
+	r1 = two31 - q1*nc;
+	q1 &= mask;
+	r1 &= mask;
+
+	q2 = (two31-1) / m->ud;
+	r2 = (two31-1) - q2*m->ud;
+	q2 &= mask;
+	r2 &= mask;
+
+	for(;;) {
+		p++;
+		if(r1 >= nc-r1) {
+			q1 <<= 1;
+			q1++;
+			r1 <<= 1;
+			r1 -= nc;
+		} else {
+			q1 <<= 1;
+			r1 <<= 1;
+		}
+		q1 &= mask;
+		r1 &= mask;
+		if(r2+1 >= m->ud-r2) {
+			if(q2 >= two31-1) {
+				m->ua = 1;
+			}
+			q2 <<= 1;
+			q2++;
+			r2 <<= 1;
+			r2++;
+			r2 -= m->ud;
+		} else {
+			if(q2 >= two31) {
+				m->ua = 1;
+			}
+			q2 <<= 1;
+			r2 <<= 1;
+			r2++;
+		}
+		q2 &= mask;
+		r2 &= mask;
+
+		delta = m->ud - 1 - r2;
+		delta &= mask;
+
+		if(p < m->w+m->w)
+		if(q1 < delta || (q1 == delta && r1 == 0)) {
+			continue;
+		}
+		break;
+	}
+	m->um = q2+1;
+	m->s = p-m->w;
+}
+
+Sym*
+ngotype(Node *n)
+{
+	if(n->type != T)
+		return typenamesym(n->type);
+	return S;
+}
+
+/*
+ * Convert raw string to the prefix that will be used in the symbol
+ * table.  All control characters, space, '%' and '"', as well as
+ * non-7-bit clean bytes turn into %xx.  The period needs escaping
+ * 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 too.
+ * If you edit this, edit ../../debug/goobj/read.go:/importPathToPrefix too.
+ */
+static char*
+pathtoprefix(char *s)
+{
+	static char hex[] = "0123456789abcdef";
+	char *p, *r, *w, *l;
+	int n;
+
+	// find first character past the last slash, if any.
+	l = s;
+	for(r=s; *r; r++)
+		if(*r == '/')
+			l = r+1;
+
+	// check for chars that need escaping
+	n = 0;
+	for(r=s; *r; r++)
+		if(*r <= ' ' || (*r == '.' && r >= l) || *r == '%' || *r == '"' || *r >= 0x7f)
+			n++;
+
+	// quick exit
+	if(n == 0)
+		return s;
+
+	// escape
+	p = mal((r-s)+1+2*n);
+	for(r=s, w=p; *r; r++) {
+		if(*r <= ' ' || (*r == '.' && r >= l) || *r == '%' || *r == '"' || *r >= 0x7f) {
+			*w++ = '%';
+			*w++ = hex[(*r>>4)&0xF];
+			*w++ = hex[*r&0xF];
+		} else
+			*w++ = *r;
+	}
+	*w = '\0';
+	return p;
+}
+
+Pkg*
+mkpkg(Strlit *path)
+{
+	Pkg *p;
+	int h;
+
+	h = stringhash(path->s) & (nelem(phash)-1);
+	for(p=phash[h]; p; p=p->link)
+		if(p->path->len == path->len && memcmp(path->s, p->path->s, path->len) == 0)
+			return p;
+
+	p = mal(sizeof *p);
+	p->path = path;
+	p->prefix = pathtoprefix(path->s);
+	p->link = phash[h];
+	phash[h] = p;
+	return p;
+}
+
+Strlit*
+strlit(char *s)
+{
+	Strlit *t;
+	
+	t = mal(sizeof *t + strlen(s));
+	strcpy(t->s, s);
+	t->len = strlen(s);
+	return t;
+}
+
+void
+addinit(Node **np, NodeList *init)
+{
+	Node *n;
+	
+	if(init == nil)
+		return;
+
+	n = *np;
+	switch(n->op) {
+	case ONAME:
+	case OLITERAL:
+		// There may be multiple refs to this node;
+		// introduce OCONVNOP to hold init list.
+		n = nod(OCONVNOP, n, N);
+		n->type = n->left->type;
+		n->typecheck = 1;
+		*np = n;
+		break;
+	}
+	n->ninit = concat(init, n->ninit);
+	n->ullman = UINF;
+}
+
+static char* reservedimports[] = {
+	"go",
+	"type",
+};
+
+int
+isbadimport(Strlit *path)
+{
+	int i;
+	char *s;
+	Rune r;
+
+	if(strlen(path->s) != path->len) {
+		yyerror("import path contains NUL");
+		return 1;
+	}
+	
+	for(i=0; i<nelem(reservedimports); i++) {
+		if(strcmp(path->s, reservedimports[i]) == 0) {
+			yyerror("import path \"%s\" is reserved and cannot be used", path->s);
+			return 1;
+		}
+	}
+
+	s = path->s;
+	while(*s) {
+		s += chartorune(&r, s);
+		if(r == Runeerror) {
+			yyerror("import path contains invalid UTF-8 sequence: \"%Z\"", path);
+			return 1;
+		}
+		if(r < 0x20 || r == 0x7f) {
+			yyerror("import path contains control character: \"%Z\"", path);
+			return 1;
+		}
+		if(r == '\\') {
+			yyerror("import path contains backslash; use slash: \"%Z\"", path);
+			return 1;
+		}
+		if(isspacerune(r)) {
+			yyerror("import path contains space character: \"%Z\"", path);
+			return 1;
+		}
+		if(utfrune("!\"#$%&'()*,:;<=>?[]^`{|}", r)) {
+			yyerror("import path contains invalid character '%C': \"%Z\"", r, path);
+			return 1;
+		}
+	}
+	return 0;
+}
+
+void
+checknil(Node *x, NodeList **init)
+{
+	Node *n;
+	
+	if(isinter(x->type)) {
+		x = nod(OITAB, x, N);
+		typecheck(&x, Erv);
+	}
+	n = nod(OCHECKNIL, x, N);
+	n->typecheck = 1;
+	*init = list(*init, n);
+}
+
+/*
+ * Can this type be stored directly in an interface word?
+ */
+int
+isdirectiface(Type *t)
+{
+	// Setting IfacePointerOnly = 1 changes the
+	// interface representation so that the data word
+	// in an interface value must always be a pointer.
+	// Setting it to 0 uses the original representation,
+	// where the data word can hold a pointer or any
+	// non-pointer value no bigger than a pointer.
+	enum {
+		IfacePointerOnly = 1,
+	};
+
+	if(IfacePointerOnly) {
+		switch(t->etype) {
+		case TPTR32:
+		case TPTR64:
+		case TCHAN:
+		case TMAP:
+		case TFUNC:
+		case TUNSAFEPTR:
+			return 1;
+		case TARRAY:
+			// Array of 1 direct iface type can be direct.
+			return t->bound == 1 && isdirectiface(t->type);
+		case TSTRUCT:
+			// Struct with 1 field of direct iface type can be direct.
+			return t->type != T && t->type->down == T && isdirectiface(t->type->type);
+		}
+		return 0;
+	}
+	
+	dowidth(t);
+	return t->width <= widthptr;
+}
diff --git a/src/cmd/gc/swt.c b/src/cmd/gc/swt.c
new file mode 100644
index 0000000..e1d8af8
--- /dev/null
+++ b/src/cmd/gc/swt.c
@@ -0,0 +1,948 @@
+// 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	"go.h"
+
+enum
+{
+	Snorm		= 0,
+	Strue,
+	Sfalse,
+	Stype,
+
+	Tdefault,	// default case
+	Texprconst,	// normal constant case
+	Texprvar,	// normal variable case
+	Ttypenil,	// case nil
+	Ttypeconst,	// type hashes
+	Ttypevar,	// interface type
+
+	Ncase	= 4,	// count needed to split
+};
+
+typedef	struct	Case	Case;
+struct	Case
+{
+	Node*	node;		// points at case statement
+	uint32	hash;		// hash of a type switch
+	uint8	type;		// type of case
+	uint8	diag;		// suppress multiple diagnostics
+	uint16	ordinal;	// position in switch
+	Case*	link;		// linked list to link
+};
+#define	C	((Case*)nil)
+/*c2go Case *C; */
+
+void
+dumpcase(Case *c0)
+{
+	Case *c;
+
+	for(c=c0; c!=C; c=c->link) {
+		switch(c->type) {
+		case Tdefault:
+			print("case-default\n");
+			print("	ord=%d\n", c->ordinal);
+			break;
+		case Texprconst:
+			print("case-exprconst\n");
+			print("	ord=%d\n", c->ordinal);
+			break;
+		case Texprvar:
+			print("case-exprvar\n");
+			print("	ord=%d\n", c->ordinal);
+			print("	op=%O\n", c->node->left->op);
+			break;
+		case Ttypenil:
+			print("case-typenil\n");
+			print("	ord=%d\n", c->ordinal);
+			break;
+		case Ttypeconst:
+			print("case-typeconst\n");
+			print("	ord=%d\n", c->ordinal);
+			print("	hash=%ux\n", c->hash);
+			break;
+		case Ttypevar:
+			print("case-typevar\n");
+			print("	ord=%d\n", c->ordinal);
+			break;
+		default:
+			print("case-???\n");
+			print("	ord=%d\n", c->ordinal);
+			print("	op=%O\n", c->node->left->op);
+			print("	hash=%ux\n", c->hash);
+			break;
+		}
+	}
+	print("\n");
+}
+
+static int
+ordlcmp(Case *c1, Case *c2)
+{
+	// sort default first
+	if(c1->type == Tdefault)
+		return -1;
+	if(c2->type == Tdefault)
+		return +1;
+
+	// sort nil second
+	if(c1->type == Ttypenil)
+		return -1;
+	if(c2->type == Ttypenil)
+		return +1;
+
+	// sort by ordinal
+	if(c1->ordinal > c2->ordinal)
+		return +1;
+	if(c1->ordinal < c2->ordinal)
+		return -1;
+	return 0;
+}
+
+static int
+exprcmp(Case *c1, Case *c2)
+{
+	int ct, n;
+	Node *n1, *n2;
+
+	// sort non-constants last
+	if(c1->type != Texprconst)
+		return +1;
+	if(c2->type != Texprconst)
+		return -1;
+
+	n1 = c1->node->left;
+	n2 = c2->node->left;
+
+	// sort by type (for switches on interface)
+	ct = n1->val.ctype;
+	if(ct != n2->val.ctype)
+		return ct - n2->val.ctype;
+	if(!eqtype(n1->type, n2->type)) {
+		if(n1->type->vargen > n2->type->vargen)
+			return +1;
+		else
+			return -1;
+	}
+
+	// sort by constant value
+	n = 0;
+	switch(ct) {
+	case CTFLT:
+		n = mpcmpfltflt(n1->val.u.fval, n2->val.u.fval);
+		break;
+	case CTINT:
+	case CTRUNE:
+		n = mpcmpfixfix(n1->val.u.xval, n2->val.u.xval);
+		break;
+	case CTSTR:
+		n = cmpslit(n1, n2);
+		break;
+	}
+
+	return n;
+}
+
+static int
+typecmp(Case *c1, Case *c2)
+{
+
+	// sort non-constants last
+	if(c1->type != Ttypeconst)
+		return +1;
+	if(c2->type != Ttypeconst)
+		return -1;
+
+	// sort by hash code
+	if(c1->hash > c2->hash)
+		return +1;
+	if(c1->hash < c2->hash)
+		return -1;
+
+	// sort by ordinal so duplicate error
+	// happens on later case.
+	if(c1->ordinal > c2->ordinal)
+		return +1;
+	if(c1->ordinal < c2->ordinal)
+		return -1;
+	return 0;
+}
+
+static Case*
+csort(Case *l, int(*f)(Case*, Case*))
+{
+	Case *l1, *l2, *le;
+
+	if(l == C || l->link == C)
+		return l;
+
+	l1 = l;
+	l2 = l;
+	for(;;) {
+		l2 = l2->link;
+		if(l2 == C)
+			break;
+		l2 = l2->link;
+		if(l2 == C)
+			break;
+		l1 = l1->link;
+	}
+
+	l2 = l1->link;
+	l1->link = C;
+	l1 = csort(l, f);
+	l2 = csort(l2, f);
+
+	/* set up lead element */
+	if((*f)(l1, l2) < 0) {
+		l = l1;
+		l1 = l1->link;
+	} else {
+		l = l2;
+		l2 = l2->link;
+	}
+	le = l;
+
+	for(;;) {
+		if(l1 == C) {
+			while(l2) {
+				le->link = l2;
+				le = l2;
+				l2 = l2->link;
+			}
+			le->link = C;
+			break;
+		}
+		if(l2 == C) {
+			while(l1) {
+				le->link = l1;
+				le = l1;
+				l1 = l1->link;
+			}
+			break;
+		}
+		if((*f)(l1, l2) < 0) {
+			le->link = l1;
+			le = l1;
+			l1 = l1->link;
+		} else {
+			le->link = l2;
+			le = l2;
+			l2 = l2->link;
+		}
+	}
+	le->link = C;
+	return l;
+}
+
+static Node*
+newlabel(void)
+{
+	static int label;
+
+	label++;
+	snprint(namebuf, sizeof(namebuf), "%.6d", label);
+	return newname(lookup(namebuf));
+}
+
+/*
+ * build separate list of statements and cases
+ * make labels between cases and statements
+ * deal with fallthrough, break, unreachable statements
+ */
+static void
+casebody(Node *sw, Node *typeswvar)
+{
+	Node *n, *c, *last;
+	Node *def;
+	NodeList *cas, *stat, *l, *lc;
+	Node *go, *br;
+	int32 lno, needvar;
+
+	if(sw->list == nil)
+		return;
+
+	lno = setlineno(sw);
+
+	cas = nil;	// cases
+	stat = nil;	// statements
+	def = N;	// defaults
+	br = nod(OBREAK, N, N);
+
+	for(l=sw->list; l; l=l->next) {
+		n = l->n;
+		setlineno(n);
+		if(n->op != OXCASE)
+			fatal("casebody %O", n->op);
+		n->op = OCASE;
+		needvar = count(n->list) != 1 || n->list->n->op == OLITERAL;
+
+		go = nod(OGOTO, newlabel(), N);
+		if(n->list == nil) {
+			if(def != N)
+				yyerror("more than one default case");
+			// reuse original default case
+			n->right = go;
+			def = n;
+		}
+
+		if(n->list != nil && n->list->next == nil) {
+			// one case - reuse OCASE node.
+			c = n->list->n;
+			n->left = c;
+			n->right = go;
+			n->list = nil;
+			cas = list(cas, n);
+		} else {
+			// expand multi-valued cases
+			for(lc=n->list; lc; lc=lc->next) {
+				c = lc->n;
+				cas = list(cas, nod(OCASE, c, go));
+			}
+		}
+
+		stat = list(stat, nod(OLABEL, go->left, N));
+		if(typeswvar && needvar && n->nname != N) {
+			NodeList *l;
+
+			l = list1(nod(ODCL, n->nname, N));
+			l = list(l, nod(OAS, n->nname, typeswvar));
+			typechecklist(l, Etop);
+			stat = concat(stat, l);
+		}
+		stat = concat(stat, n->nbody);
+
+		// botch - shouldn't fall thru declaration
+		last = stat->end->n;
+		if(last->xoffset == n->xoffset && last->op == OXFALL) {
+			if(typeswvar) {
+				setlineno(last);
+				yyerror("cannot fallthrough in type switch");
+			}
+			if(l->next == nil) {
+				setlineno(last);
+				yyerror("cannot fallthrough final case in switch");
+			}
+			last->op = OFALL;
+		} else
+			stat = list(stat, br);
+	}
+
+	stat = list(stat, br);
+	if(def)
+		cas = list(cas, def);
+
+	sw->list = cas;
+	sw->nbody = stat;
+	lineno = lno;
+}
+
+static Case*
+mkcaselist(Node *sw, int arg)
+{
+	Node *n;
+	Case *c, *c1, *c2;
+	NodeList *l;
+	int ord;
+
+	c = C;
+	ord = 0;
+
+	for(l=sw->list; l; l=l->next) {
+		n = l->n;
+		c1 = mal(sizeof(*c1));
+		c1->link = c;
+		c = c1;
+
+		ord++;
+		if((uint16)ord != ord)
+			fatal("too many cases in switch");
+		c->ordinal = ord;
+		c->node = n;
+
+		if(n->left == N) {
+			c->type = Tdefault;
+			continue;
+		}
+
+		switch(arg) {
+		case Stype:
+			c->hash = 0;
+			if(n->left->op == OLITERAL) {
+				c->type = Ttypenil;
+				continue;
+			}
+			if(istype(n->left->type, TINTER)) {
+				c->type = Ttypevar;
+				continue;
+			}
+
+			c->hash = typehash(n->left->type);
+			c->type = Ttypeconst;
+			continue;
+
+		case Snorm:
+		case Strue:
+		case Sfalse:
+			c->type = Texprvar;
+			c->hash = typehash(n->left->type);
+			switch(consttype(n->left)) {
+			case CTFLT:
+			case CTINT:
+			case CTRUNE:
+			case CTSTR:
+				c->type = Texprconst;
+			}
+			continue;
+		}
+	}
+
+	if(c == C)
+		return C;
+
+	// sort by value and diagnose duplicate cases
+	switch(arg) {
+	case Stype:
+		c = csort(c, typecmp);
+		for(c1=c; c1!=C; c1=c1->link) {
+			for(c2=c1->link; c2!=C && c2->hash==c1->hash; c2=c2->link) {
+				if(c1->type == Ttypenil || c1->type == Tdefault)
+					break;
+				if(c2->type == Ttypenil || c2->type == Tdefault)
+					break;
+				if(!eqtype(c1->node->left->type, c2->node->left->type))
+					continue;
+				yyerrorl(c2->node->lineno, "duplicate case %T in type switch\n\tprevious case at %L", c2->node->left->type, c1->node->lineno);
+			}
+		}
+		break;
+	case Snorm:
+	case Strue:
+	case Sfalse:
+		c = csort(c, exprcmp);
+		for(c1=c; c1->link!=C; c1=c1->link) {
+			if(exprcmp(c1, c1->link) != 0)
+				continue;
+			setlineno(c1->link->node);
+			yyerror("duplicate case %N in switch\n\tprevious case at %L", c1->node->left, c1->node->lineno);
+		}
+		break;
+	}
+
+	// put list back in processing order
+	c = csort(c, ordlcmp);
+	return c;
+}
+
+static	Node*	exprname;
+
+static Node*
+exprbsw(Case *c0, int ncase, int arg)
+{
+	NodeList *cas;
+	Node *a, *n;
+	Case *c;
+	int i, half, lno;
+
+	cas = nil;
+	if(ncase < Ncase) {
+		for(i=0; i<ncase; i++) {
+			n = c0->node;
+			lno = setlineno(n);
+
+			if(assignop(n->left->type, exprname->type, nil) == OCONVIFACE ||
+			   assignop(exprname->type, n->left->type, nil) == OCONVIFACE)
+				goto snorm;
+
+			switch(arg) {
+			case Strue:
+				a = nod(OIF, N, N);
+				a->ntest = n->left;			// if val
+				a->nbody = list1(n->right);			// then goto l
+				break;
+
+			case Sfalse:
+				a = nod(OIF, N, N);
+				a->ntest = nod(ONOT, n->left, N);	// if !val
+				typecheck(&a->ntest, Erv);
+				a->nbody = list1(n->right);			// then goto l
+				break;
+
+			default:
+			snorm:
+				a = nod(OIF, N, N);
+				a->ntest = nod(OEQ, exprname, n->left);	// if name == val
+				typecheck(&a->ntest, Erv);
+				a->nbody = list1(n->right);			// then goto l
+				break;
+			}
+
+			cas = list(cas, a);
+			c0 = c0->link;
+			lineno = lno;
+		}
+		return liststmt(cas);
+	}
+
+	// find the middle and recur
+	c = c0;
+	half = ncase>>1;
+	for(i=1; i<half; i++)
+		c = c->link;
+	a = nod(OIF, N, N);
+	a->ntest = nod(OLE, exprname, c->node->left);
+	typecheck(&a->ntest, Erv);
+	a->nbody = list1(exprbsw(c0, half, arg));
+	a->nelse = list1(exprbsw(c->link, ncase-half, arg));
+	return a;
+}
+
+/*
+ * normal (expression) switch.
+ * rebulid case statements into if .. goto
+ */
+static void
+exprswitch(Node *sw)
+{
+	Node *def;
+	NodeList *cas;
+	Node *a;
+	Case *c0, *c, *c1;
+	Type *t;
+	int arg, ncase;
+
+	casebody(sw, N);
+
+	arg = Snorm;
+	if(isconst(sw->ntest, CTBOOL)) {
+		arg = Strue;
+		if(sw->ntest->val.u.bval == 0)
+			arg = Sfalse;
+	}
+	walkexpr(&sw->ntest, &sw->ninit);
+	t = sw->type;
+	if(t == T)
+		return;
+
+	/*
+	 * convert the switch into OIF statements
+	 */
+	exprname = N;
+	cas = nil;
+	if(arg != Strue && arg != Sfalse) {
+		exprname = temp(sw->ntest->type);
+		cas = list1(nod(OAS, exprname, sw->ntest));
+		typechecklist(cas, Etop);
+	} else {
+		exprname = nodbool(arg == Strue);
+	}
+
+	c0 = mkcaselist(sw, arg);
+	if(c0 != C && c0->type == Tdefault) {
+		def = c0->node->right;
+		c0 = c0->link;
+	} else {
+		def = nod(OBREAK, N, N);
+	}
+
+loop:
+	if(c0 == C) {
+		cas = list(cas, def);
+		sw->nbody = concat(cas, sw->nbody);
+		sw->list = nil;
+		walkstmtlist(sw->nbody);
+		return;
+	}
+
+	// deal with the variables one-at-a-time
+	if(!okforcmp[t->etype] || c0->type != Texprconst) {
+		a = exprbsw(c0, 1, arg);
+		cas = list(cas, a);
+		c0 = c0->link;
+		goto loop;
+	}
+
+	// do binary search on run of constants
+	ncase = 1;
+	for(c=c0; c->link!=C; c=c->link) {
+		if(c->link->type != Texprconst)
+			break;
+		ncase++;
+	}
+
+	// break the chain at the count
+	c1 = c->link;
+	c->link = C;
+
+	// sort and compile constants
+	c0 = csort(c0, exprcmp);
+	a = exprbsw(c0, ncase, arg);
+	cas = list(cas, a);
+
+	c0 = c1;
+	goto loop;
+
+}
+
+static	Node*	hashname;
+static	Node*	facename;
+static	Node*	boolname;
+
+static Node*
+typeone(Node *t)
+{
+	NodeList *init;
+	Node *a, *b, *var;
+
+	var = t->nname;
+	init = nil;
+	if(var == N) {
+		typecheck(&nblank, Erv | Easgn);
+		var = nblank;
+	} else
+		init = list1(nod(ODCL, var, N));
+
+	a = nod(OAS2, N, N);
+	a->list = list(list1(var), boolname);	// var,bool =
+	b = nod(ODOTTYPE, facename, N);
+	b->type = t->left->type;		// interface.(type)
+	a->rlist = list1(b);
+	typecheck(&a, Etop);
+	init = list(init, a);
+
+	b = nod(OIF, N, N);
+	b->ntest = boolname;
+	b->nbody = list1(t->right);		// if bool { goto l }
+	a = liststmt(list(init, b));
+	return a;
+}
+
+static Node*
+typebsw(Case *c0, int ncase)
+{
+	NodeList *cas;
+	Node *a, *n;
+	Case *c;
+	int i, half;
+
+	cas = nil;
+
+	if(ncase < Ncase) {
+		for(i=0; i<ncase; i++) {
+			n = c0->node;
+			if(c0->type != Ttypeconst)
+				fatal("typebsw");
+			a = nod(OIF, N, N);
+			a->ntest = nod(OEQ, hashname, nodintconst(c0->hash));
+			typecheck(&a->ntest, Erv);
+			a->nbody = list1(n->right);
+			cas = list(cas, a);
+			c0 = c0->link;
+		}
+		return liststmt(cas);
+	}
+
+	// find the middle and recur
+	c = c0;
+	half = ncase>>1;
+	for(i=1; i<half; i++)
+		c = c->link;
+	a = nod(OIF, N, N);
+	a->ntest = nod(OLE, hashname, nodintconst(c->hash));
+	typecheck(&a->ntest, Erv);
+	a->nbody = list1(typebsw(c0, half));
+	a->nelse = list1(typebsw(c->link, ncase-half));
+	return a;
+}
+
+/*
+ * convert switch of the form
+ *	switch v := i.(type) { case t1: ..; case t2: ..; }
+ * into if statements
+ */
+static void
+typeswitch(Node *sw)
+{
+	Node *def;
+	NodeList *cas, *hash;
+	Node *a, *n;
+	Case *c, *c0, *c1;
+	int ncase;
+	Type *t;
+	Val v;
+
+	if(sw->ntest == nil)
+		return;
+	if(sw->ntest->right == nil) {
+		setlineno(sw);
+		yyerror("type switch must have an assignment");
+		return;
+	}
+	walkexpr(&sw->ntest->right, &sw->ninit);
+	if(!istype(sw->ntest->right->type, TINTER)) {
+		yyerror("type switch must be on an interface");
+		return;
+	}
+	cas = nil;
+
+	/*
+	 * predeclare temporary variables
+	 * and the boolean var
+	 */
+	facename = temp(sw->ntest->right->type);
+	a = nod(OAS, facename, sw->ntest->right);
+	typecheck(&a, Etop);
+	cas = list(cas, a);
+
+	casebody(sw, facename);
+
+	boolname = temp(types[TBOOL]);
+	typecheck(&boolname, Erv);
+
+	hashname = temp(types[TUINT32]);
+	typecheck(&hashname, Erv);
+
+	t = sw->ntest->right->type;
+	if(isnilinter(t))
+		a = syslook("efacethash", 1);
+	else
+		a = syslook("ifacethash", 1);
+	argtype(a, t);
+	a = nod(OCALL, a, N);
+	a->list = list1(facename);
+	a = nod(OAS, hashname, a);
+	typecheck(&a, Etop);
+	cas = list(cas, a);
+
+	c0 = mkcaselist(sw, Stype);
+	if(c0 != C && c0->type == Tdefault) {
+		def = c0->node->right;
+		c0 = c0->link;
+	} else {
+		def = nod(OBREAK, N, N);
+	}
+	
+	/*
+	 * insert if statement into each case block
+	 */
+	for(c=c0; c!=C; c=c->link) {
+		n = c->node;
+		switch(c->type) {
+
+		case Ttypenil:
+			v.ctype = CTNIL;
+			a = nod(OIF, N, N);
+			a->ntest = nod(OEQ, facename, nodlit(v));
+			typecheck(&a->ntest, Erv);
+			a->nbody = list1(n->right);		// if i==nil { goto l }
+			n->right = a;
+			break;
+		
+		case Ttypevar:
+		case Ttypeconst:
+			n->right = typeone(n);
+			break;
+		}
+	}
+
+	/*
+	 * generate list of if statements, binary search for constant sequences
+	 */
+	while(c0 != C) {
+		if(c0->type != Ttypeconst) {
+			n = c0->node;
+			cas = list(cas, n->right);
+			c0=c0->link;
+			continue;
+		}
+		
+		// identify run of constants
+		c1 = c = c0;
+		while(c->link!=C && c->link->type==Ttypeconst)
+			c = c->link;
+		c0 = c->link;
+		c->link = nil;
+
+		// sort by hash
+		c1 = csort(c1, typecmp);
+		
+		// for debugging: linear search
+		if(0) {
+			for(c=c1; c!=C; c=c->link) {
+				n = c->node;
+				cas = list(cas, n->right);
+			}
+			continue;
+		}
+
+		// combine adjacent cases with the same hash
+		ncase = 0;
+		for(c=c1; c!=C; c=c->link) {
+			ncase++;
+			hash = list1(c->node->right);
+			while(c->link != C && c->link->hash == c->hash) {
+				hash = list(hash, c->link->node->right);
+				c->link = c->link->link;
+			}
+			c->node->right = liststmt(hash);
+		}
+		
+		// binary search among cases to narrow by hash
+		cas = list(cas, typebsw(c1, ncase));
+	}
+	if(nerrors == 0) {
+		cas = list(cas, def);
+		sw->nbody = concat(cas, sw->nbody);
+		sw->list = nil;
+		walkstmtlist(sw->nbody);
+	}
+}
+
+void
+walkswitch(Node *sw)
+{
+	/*
+	 * reorder the body into (OLIST, cases, statements)
+	 * cases have OGOTO into statements.
+	 * both have inserted OBREAK statements
+	 */
+	if(sw->ntest == N) {
+		sw->ntest = nodbool(1);
+		typecheck(&sw->ntest, Erv);
+	}
+
+	if(sw->ntest->op == OTYPESW) {
+		typeswitch(sw);
+//dump("sw", sw);
+		return;
+	}
+	exprswitch(sw);
+	// Discard old AST elements after a walk. They can confuse racewealk.
+	sw->ntest = nil;
+	sw->list = nil;
+}
+
+/*
+ * type check switch statement
+ */
+void
+typecheckswitch(Node *n)
+{
+	int top, lno, ptr;
+	char *nilonly;
+	Type *t, *badtype, *missing, *have;
+	NodeList *l, *ll;
+	Node *ncase, *nvar;
+	Node *def;
+
+	lno = lineno;
+	typechecklist(n->ninit, Etop);
+	nilonly = nil;
+
+	if(n->ntest != N && n->ntest->op == OTYPESW) {
+		// type switch
+		top = Etype;
+		typecheck(&n->ntest->right, Erv);
+		t = n->ntest->right->type;
+		if(t != T && t->etype != TINTER)
+			yyerror("cannot type switch on non-interface value %lN", n->ntest->right);
+	} else {
+		// value switch
+		top = Erv;
+		if(n->ntest) {
+			typecheck(&n->ntest, Erv);
+			defaultlit(&n->ntest, T);
+			t = n->ntest->type;
+		} else
+			t = types[TBOOL];
+		if(t) {
+			if(!okforeq[t->etype])
+				yyerror("cannot switch on %lN", n->ntest);
+			else if(t->etype == TARRAY && !isfixedarray(t))
+				nilonly = "slice";
+			else if(t->etype == TARRAY && isfixedarray(t) && algtype1(t, nil) == ANOEQ)
+				yyerror("cannot switch on %lN", n->ntest);
+			else if(t->etype == TSTRUCT && algtype1(t, &badtype) == ANOEQ)
+				yyerror("cannot switch on %lN (struct containing %T cannot be compared)", n->ntest, badtype);
+			else if(t->etype == TFUNC)
+				nilonly = "func";
+			else if(t->etype == TMAP)
+				nilonly = "map";
+		}
+	}
+	n->type = t;
+
+	def = N;
+	for(l=n->list; l; l=l->next) {
+		ncase = l->n;
+		setlineno(n);
+		if(ncase->list == nil) {
+			// default
+			if(def != N)
+				yyerror("multiple defaults in switch (first at %L)", def->lineno);
+			else
+				def = ncase;
+		} else {
+			for(ll=ncase->list; ll; ll=ll->next) {
+				setlineno(ll->n);
+				typecheck(&ll->n, Erv | Etype);
+				if(ll->n->type == T || t == T)
+					continue;
+				setlineno(ncase);
+				switch(top) {
+				case Erv:	// expression switch
+					defaultlit(&ll->n, t);
+					if(ll->n->op == OTYPE)
+						yyerror("type %T is not an expression", ll->n->type);
+					else if(ll->n->type != T && !assignop(ll->n->type, t, nil) && !assignop(t, ll->n->type, nil)) {
+						if(n->ntest)
+							yyerror("invalid case %N in switch on %N (mismatched types %T and %T)", ll->n, n->ntest, ll->n->type, t);
+						else
+							yyerror("invalid case %N in switch (mismatched types %T and bool)", ll->n, ll->n->type);
+					} else if(nilonly && !isconst(ll->n, CTNIL)) {
+						yyerror("invalid case %N in switch (can only compare %s %N to nil)", ll->n, nilonly, n->ntest);
+					}
+					break;
+				case Etype:	// type switch
+					if(ll->n->op == OLITERAL && istype(ll->n->type, TNIL)) {
+						;
+					} else if(ll->n->op != OTYPE && ll->n->type != T) {  // should this be ||?
+						yyerror("%lN is not a type", ll->n);
+						// reset to original type
+						ll->n = n->ntest->right;
+					} else if(ll->n->type->etype != TINTER && t->etype == TINTER && !implements(ll->n->type, t, &missing, &have, &ptr)) {
+						if(have && !missing->broke && !have->broke)
+							yyerror("impossible type switch case: %lN cannot have dynamic type %T"
+								" (wrong type for %S method)\n\thave %S%hT\n\twant %S%hT",
+								n->ntest->right, ll->n->type, missing->sym, have->sym, have->type,
+								missing->sym, missing->type);
+						else if(!missing->broke)
+							yyerror("impossible type switch case: %lN cannot have dynamic type %T"
+								" (missing %S method)", n->ntest->right, ll->n->type, missing->sym);
+					}
+					break;
+				}
+			}
+		}
+		if(top == Etype && n->type != T) {
+			ll = ncase->list;
+			nvar = ncase->nname;
+			if(nvar != N) {
+				if(ll && ll->next == nil && ll->n->type != T && !istype(ll->n->type, TNIL)) {
+					// single entry type switch
+					nvar->ntype = typenod(ll->n->type);
+				} else {
+					// multiple entry type switch or default
+					nvar->ntype = typenod(n->type);
+				}
+			}
+		}
+		typechecklist(ncase->nbody, Etop);
+	}
+
+	lineno = lno;
+}
diff --git a/src/cmd/gc/typecheck.c b/src/cmd/gc/typecheck.c
new file mode 100644
index 0000000..ce12f15
--- /dev/null
+++ b/src/cmd/gc/typecheck.c
@@ -0,0 +1,3582 @@
+// 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.
+
+/*
+ * type check the whole tree of an expression.
+ * calculates expression types.
+ * evaluates compile time constants.
+ * marks variables that escape the local frame.
+ * rewrites n->op to be more specific in some cases.
+ */
+
+#include <u.h>
+#include <libc.h>
+#include "go.h"
+
+static void	implicitstar(Node**);
+static int	onearg(Node*, char*, ...);
+static int	twoarg(Node*);
+static int	lookdot(Node*, Type*, int);
+static int	looktypedot(Node*, Type*, int);
+static void	typecheckaste(int, Node*, int, Type*, NodeList*, char*);
+static Type*	lookdot1(Node*, Sym *s, Type *t, Type *f, int);
+static int	nokeys(NodeList*);
+static void	typecheckcomplit(Node**);
+static void	typecheckas2(Node*);
+static void	typecheckas(Node*);
+static void	typecheckfunc(Node*);
+static void	checklvalue(Node*, char*);
+static void	checkassign(Node*);
+static void	checkassignlist(NodeList*);
+static void	stringtoarraylit(Node**);
+static Node*	resolve(Node*);
+static void	checkdefergo(Node*);
+static int	checkmake(Type*, char*, Node*);
+static int	checksliceindex(Node*, Node*, Type*);
+static int	checksliceconst(Node*, Node*);
+
+static	NodeList*	typecheckdefstack;
+
+/*
+ * resolve ONONAME to definition, if any.
+ */
+static Node*
+resolve(Node *n)
+{
+	Node *r;
+
+	if(n != N && n->op == ONONAME && n->sym != S && (r = n->sym->def) != N) {
+		if(r->op != OIOTA)
+			n = r;
+		else if(n->iota >= 0)
+			n = nodintconst(n->iota);
+	}
+	return n;
+}
+
+void
+typechecklist(NodeList *l, int top)
+{
+	for(; l; l=l->next)
+		typecheck(&l->n, top);
+}
+
+static char* _typekind[] = {
+	[TINT]		= "int",
+	[TUINT]		= "uint",
+	[TINT8]		= "int8",
+	[TUINT8]	= "uint8",
+	[TINT16]	= "int16",
+	[TUINT16]	= "uint16",
+	[TINT32]	= "int32",
+	[TUINT32]	= "uint32",
+	[TINT64]	= "int64",
+	[TUINT64]	= "uint64",
+	[TUINTPTR]	= "uintptr",
+	[TCOMPLEX64]	= "complex64",
+	[TCOMPLEX128]	= "complex128",
+	[TFLOAT32]	= "float32",
+	[TFLOAT64]	= "float64",
+	[TBOOL]		= "bool",
+	[TSTRING]	= "string",
+	[TPTR32]	= "pointer",
+	[TPTR64]	= "pointer",
+	[TUNSAFEPTR]	= "unsafe.Pointer",
+	[TSTRUCT]	= "struct",
+	[TINTER]	= "interface",
+	[TCHAN]		= "chan",
+	[TMAP]		= "map",
+	[TARRAY]	= "array",
+	[TFUNC]		= "func",
+	[TNIL]		= "nil",
+	[TIDEAL]	= "untyped number",
+};
+
+static char*
+typekind(Type *t)
+{
+	int et;
+	static char buf[50];
+	char *s;
+	
+	if(isslice(t))
+		return "slice";
+	et = t->etype;
+	if(0 <= et && et < nelem(_typekind) && (s=_typekind[et]) != nil)
+		return s;
+	snprint(buf, sizeof buf, "etype=%d", et);
+	return buf;
+}
+
+/*
+ * sprint_depchain prints a dependency chain
+ * of nodes into fmt.
+ * It is used by typecheck in the case of OLITERAL nodes
+ * to print constant definition loops.
+ */
+static void
+sprint_depchain(Fmt *fmt, NodeList *stack, Node *cur, Node *first)
+{
+	NodeList *l;
+
+	for(l = stack; l; l=l->next) {
+		if(l->n->op == cur->op) {
+			if(l->n != first)
+				sprint_depchain(fmt, l->next, l->n, first);
+			fmtprint(fmt, "\n\t%L: %N uses %N", l->n->lineno, l->n, cur);
+			return;
+		}
+	}
+}
+
+/*
+ * type check node *np.
+ * replaces *np with a new pointer in some cases.
+ * returns the final value of *np as a convenience.
+ */
+static void typecheck1(Node **, int);
+Node*
+typecheck(Node **np, int top)
+{
+	Node *n;
+	int lno;
+	Fmt fmt;
+	NodeList *l;
+	static NodeList *tcstack, *tcfree;
+
+	// cannot type check until all the source has been parsed
+	if(!typecheckok)
+		fatal("early typecheck");
+
+	n = *np;
+	if(n == N)
+		return N;
+	
+	lno = setlineno(n);
+
+	// Skip over parens.
+	while(n->op == OPAREN)
+		n = n->left;
+
+	// Resolve definition of name and value of iota lazily.
+	n = resolve(n);
+
+	*np = n;
+
+	// Skip typecheck if already done.
+	// But re-typecheck ONAME/OTYPE/OLITERAL/OPACK node in case context has changed.
+	if(n->typecheck == 1) {
+		switch(n->op) {
+		case ONAME:
+		case OTYPE:
+		case OLITERAL:
+		case OPACK:
+			break;
+		default:
+			lineno = lno;
+			return n;
+		}
+	}
+
+	if(n->typecheck == 2) {
+		// Typechecking loop. Trying printing a meaningful message,
+		// otherwise a stack trace of typechecking.
+		switch(n->op) {
+		case ONAME:
+			// We can already diagnose variables used as types.
+			if((top & (Erv|Etype)) == Etype)
+				yyerror("%N is not a type", n);
+			break;
+		case OLITERAL:
+			if((top & (Erv|Etype)) == Etype) {
+				yyerror("%N is not a type", n);
+				break;
+			}
+			fmtstrinit(&fmt);
+			sprint_depchain(&fmt, tcstack, n, n);
+			yyerrorl(n->lineno, "constant definition loop%s", fmtstrflush(&fmt));
+			break;
+		}
+		if(nsavederrors+nerrors == 0) {
+			fmtstrinit(&fmt);
+			for(l=tcstack; l; l=l->next)
+				fmtprint(&fmt, "\n\t%L %N", l->n->lineno, l->n);
+			yyerror("typechecking loop involving %N%s", n, fmtstrflush(&fmt));
+		}
+		lineno = lno;
+		return n;
+	}
+	n->typecheck = 2;
+
+	if(tcfree != nil) {
+		l = tcfree;
+		tcfree = l->next;
+	} else
+		l = mal(sizeof *l);
+	l->next = tcstack;
+	l->n = n;
+	tcstack = l;
+
+	typecheck1(&n, top);
+	*np = n;
+	n->typecheck = 1;
+
+	if(tcstack != l)
+		fatal("typecheck stack out of sync");
+	tcstack = l->next;
+	l->next = tcfree;
+	tcfree = l;
+
+	lineno = lno;
+	return n;
+}
+
+/*
+ * does n contain a call or receive operation?
+ */
+static int callrecvlist(NodeList*);
+
+static int
+callrecv(Node *n)
+{
+	if(n == nil)
+		return 0;
+	
+	switch(n->op) {
+	case OCALL:
+	case OCALLMETH:
+	case OCALLINTER:
+	case OCALLFUNC:
+	case ORECV:
+	case OCAP:
+	case OLEN:
+	case OCOPY:
+	case ONEW:
+	case OAPPEND:
+	case ODELETE:
+		return 1;
+	}
+
+	return callrecv(n->left) ||
+		callrecv(n->right) ||
+		callrecv(n->ntest) ||
+		callrecv(n->nincr) ||
+		callrecvlist(n->ninit) ||
+		callrecvlist(n->nbody) ||
+		callrecvlist(n->nelse) ||
+		callrecvlist(n->list) ||
+		callrecvlist(n->rlist);
+}
+
+static int
+callrecvlist(NodeList *l)
+{
+	for(; l; l=l->next)
+		if(callrecv(l->n))
+			return 1;
+	return 0;
+}
+
+// indexlit implements typechecking of untyped values as
+// array/slice indexes. It is equivalent to defaultlit
+// except for constants of numerical kind, which are acceptable
+// whenever they can be represented by a value of type int.
+static void
+indexlit(Node **np)
+{
+	Node *n;
+
+	n = *np;
+	if(n == N || !isideal(n->type))
+		return;
+	switch(consttype(n)) {
+	case CTINT:
+	case CTRUNE:
+	case CTFLT:
+	case CTCPLX:
+		defaultlit(np, types[TINT]);
+		break;
+	}
+	defaultlit(np, T);
+}
+
+static void
+typecheck1(Node **np, int top)
+{
+	int et, aop, op, ptr;
+	Node *n, *l, *r, *lo, *mid, *hi;
+	NodeList *args;
+	int ok, ntop;
+	Type *t, *tp, *missing, *have, *badtype;
+	Val v;
+	char *why, *desc, descbuf[64];
+	vlong x;
+	
+	n = *np;
+
+	if(n->sym) {
+		if(n->op == ONAME && n->etype != 0 && !(top & Ecall)) {
+			yyerror("use of builtin %S not in function call", n->sym);
+			goto error;
+		}
+
+		typecheckdef(n);
+		if(n->op == ONONAME)
+			goto error;
+	}
+	*np = n;
+
+reswitch:
+	ok = 0;
+	switch(n->op) {
+	default:
+		// until typecheck is complete, do nothing.
+		dump("typecheck", n);
+		fatal("typecheck %O", n->op);
+
+	/*
+	 * names
+	 */
+	case OLITERAL:
+		ok |= Erv;
+		if(n->type == T && n->val.ctype == CTSTR)
+			n->type = idealstring;
+		goto ret;
+
+	case ONONAME:
+		ok |= Erv;
+		goto ret;
+
+	case ONAME:
+		if(n->etype != 0) {
+			ok |= Ecall;
+			goto ret;
+		}
+		if(!(top & Easgn)) {
+			// not a write to the variable
+			if(isblank(n)) {
+				yyerror("cannot use _ as value");
+				goto error;
+			}
+			n->used = 1;
+		}
+		if(!(top &Ecall) && isunsafebuiltin(n)) {
+			yyerror("%N is not an expression, must be called", n);
+			goto error;
+		}
+		ok |= Erv;
+		goto ret;
+
+	case OPACK:
+		yyerror("use of package %S without selector", n->sym);
+		goto error;
+
+	case ODDD:
+		break;
+
+	/*
+	 * types (OIND is with exprs)
+	 */
+	case OTYPE:
+		ok |= Etype;
+		if(n->type == T)
+			goto error;
+		break;
+	
+	case OTARRAY:
+		ok |= Etype;
+		t = typ(TARRAY);
+		l = n->left;
+		r = n->right;
+		if(l == nil) {
+			t->bound = -1;	// slice
+		} else if(l->op == ODDD) {
+			t->bound = -100;	// to be filled in
+			if(!(top&Ecomplit) && !n->diag) {
+				t->broke = 1;
+				n->diag = 1;
+				yyerror("use of [...] array outside of array literal");
+			}
+		} else {
+			l = typecheck(&n->left, Erv);
+			switch(consttype(l)) {
+			case CTINT:
+			case CTRUNE:
+				v = l->val;
+				break;
+			case CTFLT:
+				v = toint(l->val);
+				break;
+			default:
+				if(l->type != T && isint[l->type->etype] && l->op != OLITERAL)
+					yyerror("non-constant array bound %N", l);
+				else
+					yyerror("invalid array bound %N", l);
+				goto error;
+			}
+			t->bound = mpgetfix(v.u.xval);
+			if(doesoverflow(v, types[TINT])) {
+				yyerror("array bound is too large"); 
+				goto error;
+			} else if(t->bound < 0) {
+				yyerror("array bound must be non-negative");
+				goto error;
+			}
+		}
+		typecheck(&r, Etype);
+		if(r->type == T)
+			goto error;
+		t->type = r->type;
+		n->op = OTYPE;
+		n->type = t;
+		n->left = N;
+		n->right = N;
+		if(t->bound != -100)
+			checkwidth(t);
+		break;
+
+	case OTMAP:
+		ok |= Etype;
+		l = typecheck(&n->left, Etype);
+		r = typecheck(&n->right, Etype);
+		if(l->type == T || r->type == T)
+			goto error;
+		n->op = OTYPE;
+		n->type = maptype(l->type, r->type);
+		n->left = N;
+		n->right = N;
+		break;
+
+	case OTCHAN:
+		ok |= Etype;
+		l = typecheck(&n->left, Etype);
+		if(l->type == T)
+			goto error;
+		t = typ(TCHAN);
+		t->type = l->type;
+		t->chan = n->etype;
+		n->op = OTYPE;
+		n->type = t;
+		n->left = N;
+		n->etype = 0;
+		break;
+
+	case OTSTRUCT:
+		ok |= Etype;
+		n->op = OTYPE;
+		n->type = tostruct(n->list);
+		if(n->type == T || n->type->broke)
+			goto error;
+		n->list = nil;
+		break;
+
+	case OTINTER:
+		ok |= Etype;
+		n->op = OTYPE;
+		n->type = tointerface(n->list);
+		if(n->type == T)
+			goto error;
+		break;
+
+	case OTFUNC:
+		ok |= Etype;
+		n->op = OTYPE;
+		n->type = functype(n->left, n->list, n->rlist);
+		if(n->type == T)
+			goto error;
+		break;
+
+	/*
+	 * type or expr
+	 */
+	case OIND:
+		ntop = Erv | Etype;
+		if(!(top & Eaddr))  		// The *x in &*x is not an indirect.
+			ntop |= Eindir;
+		ntop |= top & Ecomplit;
+		l = typecheck(&n->left, ntop);
+		if((t = l->type) == T)
+			goto error;
+		if(l->op == OTYPE) {
+			ok |= Etype;
+			n->op = OTYPE;
+			n->type = ptrto(l->type);
+			n->left = N;
+			goto ret;
+		}
+		if(!isptr[t->etype]) {
+			if(top & (Erv | Etop)) {
+				yyerror("invalid indirect of %lN", n->left);
+				goto error;
+			}
+			goto ret;
+		}
+		ok |= Erv;
+		n->type = t->type;
+		goto ret;
+
+	/*
+	 * arithmetic exprs
+	 */
+	case OASOP:
+		ok |= Etop;
+		l = typecheck(&n->left, Erv);
+		checkassign(n->left);
+		r = typecheck(&n->right, Erv);
+		if(l->type == T || r->type == T)
+			goto error;
+		op = n->etype;
+		goto arith;
+
+	case OADD:
+	case OAND:
+	case OANDAND:
+	case OANDNOT:
+	case ODIV:
+	case OEQ:
+	case OGE:
+	case OGT:
+	case OLE:
+	case OLT:
+	case OLSH:
+	case ORSH:
+	case OMOD:
+	case OMUL:
+	case ONE:
+	case OOR:
+	case OOROR:
+	case OSUB:
+	case OXOR:
+		ok |= Erv;
+		l = typecheck(&n->left, Erv | (top & Eiota));
+		r = typecheck(&n->right, Erv | (top & Eiota));
+		if(l->type == T || r->type == T)
+			goto error;
+		op = n->op;
+	arith:
+		if(op == OLSH || op == ORSH)
+			goto shift;
+		// ideal mixed with non-ideal
+		defaultlit2(&l, &r, 0);
+		n->left = l;
+		n->right = r;
+		if(l->type == T || r->type == T)
+			goto error;
+		t = l->type;
+		if(t->etype == TIDEAL)
+			t = r->type;
+		et = t->etype;
+		if(et == TIDEAL)
+			et = TINT;
+		if(iscmp[n->op] && t->etype != TIDEAL && !eqtype(l->type, r->type)) {
+			// comparison is okay as long as one side is
+			// assignable to the other.  convert so they have
+			// the same type.
+			//
+			// the only conversion that isn't a no-op is concrete == interface.
+			// in that case, check comparability of the concrete type.
+			if(r->type->etype != TBLANK && (aop = assignop(l->type, r->type, nil)) != 0) {
+				if(isinter(r->type) && !isinter(l->type) && algtype1(l->type, nil) == ANOEQ) {
+					yyerror("invalid operation: %N (operator %O not defined on %s)", n, op, typekind(l->type));
+					goto error;
+				}
+				l = nod(aop, l, N);
+				l->type = r->type;
+				l->typecheck = 1;
+				n->left = l;
+				t = l->type;
+			} else if(l->type->etype != TBLANK && (aop = assignop(r->type, l->type, nil)) != 0) {
+				if(isinter(l->type) && !isinter(r->type) && algtype1(r->type, nil) == ANOEQ) {
+					yyerror("invalid operation: %N (operator %O not defined on %s)", n, op, typekind(r->type));
+					goto error;
+				}
+				r = nod(aop, r, N);
+				r->type = l->type;
+				r->typecheck = 1;
+				n->right = r;
+				t = r->type;
+			}
+			et = t->etype;
+		}
+		if(t->etype != TIDEAL && !eqtype(l->type, r->type)) {
+			defaultlit2(&l, &r, 1);
+			if(n->op == OASOP && n->implicit) {
+				yyerror("invalid operation: %N (non-numeric type %T)", n, l->type);
+				goto error;
+			}
+			yyerror("invalid operation: %N (mismatched types %T and %T)", n, l->type, r->type);
+			goto error;
+		}
+		if(!okfor[op][et]) {
+			yyerror("invalid operation: %N (operator %O not defined on %s)", n, op, typekind(t));
+			goto error;
+		}
+		// okfor allows any array == array, map == map, func == func.
+		// restrict to slice/map/func == nil and nil == slice/map/func.
+		if(isfixedarray(l->type) && algtype1(l->type, nil) == ANOEQ) {
+			yyerror("invalid operation: %N (%T cannot be compared)", n, l->type);
+			goto error;
+		}
+		if(isslice(l->type) && !isnil(l) && !isnil(r)) {
+			yyerror("invalid operation: %N (slice can only be compared to nil)", n);
+			goto error;
+		}
+		if(l->type->etype == TMAP && !isnil(l) && !isnil(r)) {
+			yyerror("invalid operation: %N (map can only be compared to nil)", n);
+			goto error;
+		}
+		if(l->type->etype == TFUNC && !isnil(l) && !isnil(r)) {
+			yyerror("invalid operation: %N (func can only be compared to nil)", n);
+			goto error;
+		}
+		if(l->type->etype == TSTRUCT && algtype1(l->type, &badtype) == ANOEQ) {
+			yyerror("invalid operation: %N (struct containing %T cannot be compared)", n, badtype);
+			goto error;
+		}
+		
+		t = l->type;
+		if(iscmp[n->op]) {
+			evconst(n);
+			t = idealbool;
+			if(n->op != OLITERAL) {
+				defaultlit2(&l, &r, 1);
+				n->left = l;
+				n->right = r;
+			}
+		// non-comparison operators on ideal bools should make them lose their ideal-ness
+		} else if(t == idealbool)
+			t = types[TBOOL];
+
+		if(et == TSTRING) {
+			if(iscmp[n->op]) {
+				n->etype = n->op;
+				n->op = OCMPSTR;
+			} 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) {
+				// swap for back end
+				n->left = r;
+				n->right = l;
+			} else if(r->op == OLITERAL && r->val.ctype == CTNIL) {
+				// leave alone for back end
+			} else {
+				n->etype = n->op;
+				n->op = OCMPIFACE;
+			}
+		}
+
+		if((op == ODIV || op == OMOD) && isconst(r, CTINT))
+		if(mpcmpfixc(r->val.u.xval, 0) == 0) {
+			yyerror("division by zero");
+			goto error;
+		} 
+
+		n->type = t;
+		goto ret;
+
+	shift:
+		defaultlit(&r, types[TUINT]);
+		n->right = r;
+		t = r->type;
+		if(!isint[t->etype] || issigned[t->etype]) {
+			yyerror("invalid operation: %N (shift count type %T, must be unsigned integer)", n, r->type);
+			goto error;
+		}
+		t = l->type;
+		if(t != T && t->etype != TIDEAL && !isint[t->etype]) {
+			yyerror("invalid operation: %N (shift of type %T)", n, t);
+			goto error;
+		}
+		// no defaultlit for left
+		// the outer context gives the type
+		n->type = l->type;
+		goto ret;
+
+	case OCOM:
+	case OMINUS:
+	case ONOT:
+	case OPLUS:
+		ok |= Erv;
+		l = typecheck(&n->left, Erv | (top & Eiota));
+		if((t = l->type) == T)
+			goto error;
+		if(!okfor[n->op][t->etype]) {
+			yyerror("invalid operation: %O %T", n->op, t);
+			goto error;
+		}
+		n->type = t;
+		goto ret;
+
+	/*
+	 * exprs
+	 */
+	case OADDR:
+		ok |= Erv;
+		typecheck(&n->left, Erv | Eaddr);
+		if(n->left->type == T)
+			goto error;
+		checklvalue(n->left, "take the address of");
+		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;
+		if((t = l->type) == T)
+			goto error;
+		n->type = ptrto(t);
+		goto ret;
+
+	case OCOMPLIT:
+		ok |= Erv;
+		typecheckcomplit(&n);
+		if(n->type == T)
+			goto error;
+		goto ret;
+
+	case OXDOT:
+		n = adddot(n);
+		n->op = ODOT;
+		if(n->left == N)
+			goto error;
+		// fall through
+	case ODOT:
+		typecheck(&n->left, Erv|Etype);
+		defaultlit(&n->left, T);
+		if((t = n->left->type) == T)
+			goto error;
+		if(n->right->op != ONAME) {
+			yyerror("rhs of . must be a name");	// impossible
+			goto error;
+		}
+		r = n->right;
+
+		if(n->left->op == OTYPE) {
+			if(!looktypedot(n, t, 0)) {
+				if(looktypedot(n, t, 1))
+					yyerror("%N undefined (cannot refer to unexported method %S)", n, n->right->sym);
+				else
+					yyerror("%N undefined (type %T has no method %S)", n, t, n->right->sym);
+				goto error;
+			}
+			if(n->type->etype != TFUNC || n->type->thistuple != 1) {
+				yyerror("type %T has no method %hS", n->left->type, n->right->sym);
+				n->type = T;
+				goto error;
+			}
+			n->op = ONAME;
+			n->sym = n->right->sym;
+			n->type = methodfunc(n->type, n->left->type);
+			n->xoffset = 0;
+			n->class = PFUNC;
+			ok = Erv;
+			goto ret;
+		}
+		if(isptr[t->etype] && t->type->etype != TINTER) {
+			t = t->type;
+			if(t == T)
+				goto error;
+			n->op = ODOTPTR;
+			checkwidth(t);
+		}
+		if(isblank(n->right)) {
+			yyerror("cannot refer to blank field or method");
+			goto error;
+		}
+		if(!lookdot(n, t, 0)) {
+			if(lookdot(n, t, 1))
+				yyerror("%N undefined (cannot refer to unexported field or method %S)", n, n->right->sym);
+			else
+				yyerror("%N undefined (type %T has no field or method %S)", n, n->left->type, n->right->sym);
+			goto error;
+		}
+		switch(n->op) {
+		case ODOTINTER:
+		case ODOTMETH:
+			if(top&Ecall)
+				ok |= Ecall;
+			else {
+				typecheckpartialcall(n, r);
+				ok |= Erv;
+			}
+			break;
+		default:
+			ok |= Erv;
+			break;
+		}
+		goto ret;
+
+	case ODOTTYPE:
+		ok |= Erv;
+		typecheck(&n->left, Erv);
+		defaultlit(&n->left, T);
+		l = n->left;
+		if((t = l->type) == T)
+			goto error;
+		if(!isinter(t)) {
+			yyerror("invalid type assertion: %N (non-interface type %T on left)", n, t);
+			goto error;
+		}
+		if(n->right != N) {
+			typecheck(&n->right, Etype);
+			n->type = n->right->type;
+			n->right = N;
+			if(n->type == T)
+				goto error;
+		}
+		if(n->type != T && n->type->etype != TINTER)
+		if(!implements(n->type, t, &missing, &have, &ptr)) {
+			if(have && have->sym == missing->sym)
+				yyerror("impossible type assertion:\n\t%T does not implement %T (wrong type for %S method)\n"
+					"\t\thave %S%hhT\n\t\twant %S%hhT", n->type, t, missing->sym,
+					have->sym, have->type, missing->sym, missing->type);
+			else if(ptr)
+				yyerror("impossible type assertion:\n\t%T does not implement %T (%S method has pointer receiver)",
+					n->type, t, missing->sym);
+			else if(have)
+				yyerror("impossible type assertion:\n\t%T does not implement %T (missing %S method)\n"
+					"\t\thave %S%hhT\n\t\twant %S%hhT", n->type, t, missing->sym,
+					have->sym, have->type, missing->sym, missing->type);
+			else
+				yyerror("impossible type assertion:\n\t%T does not implement %T (missing %S method)",
+					n->type, t, missing->sym);
+			goto error;
+		}
+		goto ret;
+
+	case OINDEX:
+		ok |= Erv;
+		typecheck(&n->left, Erv);
+		defaultlit(&n->left, T);
+		implicitstar(&n->left);
+		l = n->left;
+		typecheck(&n->right, Erv);
+		r = n->right;
+		if((t = l->type) == T || r->type == T)
+			goto error;
+		switch(t->etype) {
+		default:
+			yyerror("invalid operation: %N (type %T does not support indexing)", n, t);
+			goto error;
+
+
+		case TSTRING:
+		case TARRAY:
+			indexlit(&n->right);
+			if(t->etype == TSTRING)
+				n->type = types[TUINT8];
+			else
+				n->type = t->type;
+			why = "string";
+			if(t->etype == TARRAY) {
+				if(isfixedarray(t))
+					why = "array";
+				else
+					why = "slice";
+			}
+			if(n->right->type != T && !isint[n->right->type->etype]) {
+				yyerror("non-integer %s index %N", why, n->right);
+				break;
+			}
+			if(isconst(n->right, CTINT)) {
+				x = mpgetfix(n->right->val.u.xval);
+				if(x < 0)
+					yyerror("invalid %s index %N (index must be non-negative)", why, n->right);
+				else if(isfixedarray(t) && t->bound > 0 && x >= t->bound)
+					yyerror("invalid array index %N (out of bounds for %d-element array)", n->right, t->bound);
+				else if(isconst(n->left, CTSTR) && x >= n->left->val.u.sval->len)
+					yyerror("invalid string index %N (out of bounds for %d-byte string)", n->right, n->left->val.u.sval->len);
+				else if(mpcmpfixfix(n->right->val.u.xval, maxintval[TINT]) > 0)
+					yyerror("invalid %s index %N (index too large)", why, n->right);
+			}
+			break;
+
+		case TMAP:
+			n->etype = 0;
+			defaultlit(&n->right, t->down);
+			if(n->right->type != T)
+				n->right = assignconv(n->right, t->down, "map index");
+			n->type = t->type;
+			n->op = OINDEXMAP;
+			break;
+		}
+		goto ret;
+
+	case ORECV:
+		ok |= Etop | Erv;
+		typecheck(&n->left, Erv);
+		defaultlit(&n->left, T);
+		l = n->left;
+		if((t = l->type) == T)
+			goto error;
+		if(t->etype != TCHAN) {
+			yyerror("invalid operation: %N (receive from non-chan type %T)", n, t);
+			goto error;
+		}
+		if(!(t->chan & Crecv)) {
+			yyerror("invalid operation: %N (receive from send-only type %T)", n, t);
+			goto error;
+		}
+		n->type = t->type;
+		goto ret;
+
+	case OSEND:
+		ok |= Etop;
+		l = typecheck(&n->left, Erv);
+		typecheck(&n->right, Erv);
+		defaultlit(&n->left, T);
+		l = n->left;
+		if((t = l->type) == T)
+			goto error;
+		if(t->etype != TCHAN) {
+			yyerror("invalid operation: %N (send to non-chan type %T)", n, t);
+			goto error;
+		}
+		if(!(t->chan & Csend)) {
+			yyerror("invalid operation: %N (send to receive-only type %T)", n, t);
+			goto error;
+		}
+		defaultlit(&n->right, t->type);
+		r = n->right;
+		if(r->type == T)
+			goto error;
+		n->right = assignconv(r, l->type->type, "send");
+		// TODO: more aggressive
+		n->etype = 0;
+		n->type = T;
+		goto ret;
+
+	case OSLICE:
+		ok |= Erv;
+		typecheck(&n->left, top);
+		typecheck(&n->right->left, Erv);
+		typecheck(&n->right->right, Erv);
+		defaultlit(&n->left, T);
+		indexlit(&n->right->left);
+		indexlit(&n->right->right);
+		l = n->left;
+		if(isfixedarray(l->type)) {
+			if(!islvalue(n->left)) {
+				yyerror("invalid operation %N (slice of unaddressable value)", n);
+				goto error;
+			}
+			n->left = nod(OADDR, n->left, N);
+			n->left->implicit = 1;
+			typecheck(&n->left, Erv);
+			l = n->left;
+		}
+		if((t = l->type) == T)
+			goto error;
+		tp = nil;
+		if(istype(t, TSTRING)) {
+			n->type = t;
+			n->op = OSLICESTR;
+		} else if(isptr[t->etype] && isfixedarray(t->type)) {
+			tp = t->type;
+			n->type = typ(TARRAY);
+			n->type->type = tp->type;
+			n->type->bound = -1;
+			dowidth(n->type);
+			n->op = OSLICEARR;
+		} else if(isslice(t)) {
+			n->type = t;
+		} else {
+			yyerror("cannot slice %N (type %T)", l, t);
+			goto error;
+		}
+		if((lo = n->right->left) != N && checksliceindex(l, lo, tp) < 0)
+			goto error;
+		if((hi = n->right->right) != N && checksliceindex(l, hi, tp) < 0)
+			goto error;
+		if(checksliceconst(lo, hi) < 0)
+			goto error;
+		goto ret;
+
+	case OSLICE3:
+		ok |= Erv;
+		typecheck(&n->left, top);
+		typecheck(&n->right->left, Erv);
+		typecheck(&n->right->right->left, Erv);
+		typecheck(&n->right->right->right, Erv);
+		defaultlit(&n->left, T);
+		indexlit(&n->right->left);
+		indexlit(&n->right->right->left);
+		indexlit(&n->right->right->right);
+		l = n->left;
+		if(isfixedarray(l->type)) {
+			if(!islvalue(n->left)) {
+				yyerror("invalid operation %N (slice of unaddressable value)", n);
+				goto error;
+			}
+			n->left = nod(OADDR, n->left, N);
+			n->left->implicit = 1;
+			typecheck(&n->left, Erv);
+			l = n->left;
+		}
+		if((t = l->type) == T)
+			goto error;
+		tp = nil;
+		if(istype(t, TSTRING)) {
+			yyerror("invalid operation %N (3-index slice of string)", n);
+			goto error;
+		}
+		if(isptr[t->etype] && isfixedarray(t->type)) {
+			tp = t->type;
+			n->type = typ(TARRAY);
+			n->type->type = tp->type;
+			n->type->bound = -1;
+			dowidth(n->type);
+			n->op = OSLICE3ARR;
+		} else if(isslice(t)) {
+			n->type = t;
+		} else {
+			yyerror("cannot slice %N (type %T)", l, t);
+			goto error;
+		}
+		if((lo = n->right->left) != N && checksliceindex(l, lo, tp) < 0)
+			goto error;
+		if((mid = n->right->right->left) != N && checksliceindex(l, mid, tp) < 0)
+			goto error;
+		if((hi = n->right->right->right) != N && checksliceindex(l, hi, tp) < 0)
+			goto error;
+		if(checksliceconst(lo, hi) < 0 || checksliceconst(lo, mid) < 0 || checksliceconst(mid, hi) < 0)
+			goto error;
+		goto ret;
+
+	/*
+	 * call and call like
+	 */
+	case OCALL:
+		l = n->left;
+		if(l->op == ONAME && (r = unsafenmagic(n)) != N) {
+			if(n->isddd)
+				yyerror("invalid use of ... with builtin %N", l);
+			n = r;
+			goto reswitch;
+		}
+		typecheck(&n->left, Erv | Etype | Ecall |(top&Eproc));
+		n->diag |= n->left->diag;
+		l = n->left;
+		if(l->op == ONAME && l->etype != 0) {
+			if(n->isddd && l->etype != OAPPEND)
+				yyerror("invalid use of ... with builtin %N", l);
+			// builtin: OLEN, OCAP, etc.
+			n->op = l->etype;
+			n->left = n->right;
+			n->right = N;
+			goto reswitch;
+		}
+		defaultlit(&n->left, T);
+		l = n->left;
+		if(l->op == OTYPE) {
+			if(n->isddd || l->type->bound == -100) {
+				if(!l->type->broke)
+					yyerror("invalid use of ... in type conversion", l);
+				n->diag = 1;
+			}
+			// pick off before type-checking arguments
+			ok |= Erv;
+			// turn CALL(type, arg) into CONV(arg) w/ type
+			n->left = N;
+			n->op = OCONV;
+			n->type = l->type;
+			if(onearg(n, "conversion to %T", l->type) < 0)
+				goto error;
+			goto doconv;
+		}
+
+		if(count(n->list) == 1 && !n->isddd)
+			typecheck(&n->list->n, Erv | Efnstruct);
+		else
+			typechecklist(n->list, Erv);
+		if((t = l->type) == T)
+			goto error;
+		checkwidth(t);
+
+		switch(l->op) {
+		case ODOTINTER:
+			n->op = OCALLINTER;
+			break;
+
+		case ODOTMETH:
+			n->op = OCALLMETH;
+			// typecheckaste was used here but there wasn't enough
+			// information further down the call chain to know if we
+			// were testing a method receiver for unexported fields.
+			// It isn't necessary, so just do a sanity check.
+			tp = getthisx(t)->type->type;
+			if(l->left == N || !eqtype(l->left->type, tp))
+				fatal("method receiver");
+			break;
+
+		default:
+			n->op = OCALLFUNC;
+			if(t->etype != TFUNC) {
+				yyerror("cannot call non-function %N (type %T)", l, t);
+				goto error;
+			}
+			break;
+		}
+		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;
+		ok |= Erv;
+		if(t->outtuple == 1) {
+			t = getoutargx(l->type)->type;
+			if(t == T)
+				goto error;
+			if(t->etype == TFIELD)
+				t = t->type;
+			n->type = t;
+			goto ret;
+		}
+		// multiple return
+		if(!(top & (Efnstruct | Etop))) {
+			yyerror("multiple-value %N() in single-value context", l);
+			goto ret;
+		}
+		n->type = getoutargx(l->type);
+		goto ret;
+
+	case OCAP:
+	case OLEN:
+	case OREAL:
+	case OIMAG:
+		ok |= Erv;
+		if(onearg(n, "%O", n->op) < 0)
+			goto error;
+		typecheck(&n->left, Erv);
+		defaultlit(&n->left, T);
+		implicitstar(&n->left);
+		l = n->left;
+		t = l->type;
+		if(t == T)
+			goto error;
+		switch(n->op) {
+		case OCAP:
+			if(!okforcap[t->etype])
+				goto badcall1;
+			break;
+		case OLEN:
+			if(!okforlen[t->etype])
+				goto badcall1;
+			break;
+		case OREAL:
+		case OIMAG:
+			if(!iscomplex[t->etype])
+				goto badcall1;
+			if(isconst(l, CTCPLX)){
+				r = n;
+				if(n->op == OREAL)
+					n = nodfltconst(&l->val.u.cval->real);
+				else
+					n = nodfltconst(&l->val.u.cval->imag);
+				n->orig = r;
+			}
+			n->type = types[cplxsubtype(t->etype)];
+			goto ret;
+		}
+		// might be constant
+		switch(t->etype) {
+		case TSTRING:
+			if(isconst(l, CTSTR)) {
+				r = nod(OXXX, N, N);
+				nodconst(r, types[TINT], l->val.u.sval->len);
+				r->orig = n;
+				n = r;
+			}
+			break;
+		case TARRAY:
+			if(t->bound < 0) // slice
+				break;
+			if(callrecv(l)) // has call or receive
+				break;
+			r = nod(OXXX, N, N);
+			nodconst(r, types[TINT], t->bound);
+			r->orig = n;
+			n = r;
+			break;
+		}
+		n->type = types[TINT];
+		goto ret;
+
+	case OCOMPLEX:
+		ok |= Erv;
+		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;
+		}
+		switch(l->type->etype) {
+		default:
+			yyerror("invalid operation: %N (arguments have type %T, expected floating-point)", n, l->type, r->type);
+			goto error;
+		case TIDEAL:
+			t = types[TIDEAL];
+			break;
+		case TFLOAT32:
+			t = types[TCOMPLEX64];
+			break;
+		case TFLOAT64:
+			t = types[TCOMPLEX128];
+			break;
+		}
+		if(l->op == OLITERAL && r->op == OLITERAL) {
+			// make it a complex literal
+			r = nodcplxlit(l->val, r->val);
+			r->orig = n;
+			n = r;
+		}
+		n->type = t;
+		goto ret;
+
+	case OCLOSE:
+		if(onearg(n, "%O", n->op) < 0)
+			goto error;
+		typecheck(&n->left, Erv);
+		defaultlit(&n->left, T);
+		l = n->left;
+		if((t = l->type) == T)
+			goto error;
+		if(t->etype != TCHAN) {
+			yyerror("invalid operation: %N (non-chan type %T)", n, t);
+			goto error;
+		}
+		if(!(t->chan & Csend)) {
+			yyerror("invalid operation: %N (cannot close receive-only channel)", n);
+			goto error;
+		}
+		ok |= Etop;
+		goto ret;
+
+	case ODELETE:
+		args = n->list;
+		if(args == nil) {
+			yyerror("missing arguments to delete");
+			goto error;
+		}
+		if(args->next == nil) {
+			yyerror("missing second (key) argument to delete");
+			goto error;
+		}
+		if(args->next->next != nil) {
+			yyerror("too many arguments to delete");
+			goto error;
+		}
+		ok |= Etop;
+		typechecklist(args, Erv);
+		l = args->n;
+		r = args->next->n;
+		if(l->type != T && l->type->etype != TMAP) {
+			yyerror("first argument to delete must be map; have %lT", l->type);
+			goto error;
+		}
+		args->next->n = assignconv(r, l->type->down, "delete");
+		goto ret;
+
+	case OAPPEND:
+		ok |= Erv;
+		args = n->list;
+		if(args == nil) {
+			yyerror("missing arguments to append");
+			goto error;
+		}
+
+		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->funarg) {
+			t = t->type;
+			if(istype(t, TFIELD))
+				t = t->type;
+		}
+
+		n->type = t;
+		if(!isslice(t)) {
+			if(isconst(args->n, CTNIL)) {
+				yyerror("first argument to append must be typed slice; have untyped nil", t);
+				goto error;
+			}
+			yyerror("first argument to append must be slice; have %lT", t);
+			goto error;
+		}
+
+		if(n->isddd) {
+			if(args->next == nil) {
+				yyerror("cannot use ... on first argument to append");
+				goto error;
+			}
+			if(args->next->next != nil) {
+				yyerror("too many arguments to append");
+				goto error;
+			}
+			if(istype(t->type, TUINT8) && istype(args->next->n->type, TSTRING)) {
+				defaultlit(&args->next->n, types[TSTRING]);
+				goto ret;
+			}
+			args->next->n = assignconv(args->next->n, t->orig, "append");
+			goto ret;
+		}
+		for(args=args->next; args != nil; args=args->next) {
+			if(args->n->type == T)
+				continue;
+			args->n = assignconv(args->n, t->type, "append");
+		}
+		goto ret;
+
+	case OCOPY:
+		ok |= Etop|Erv;
+		args = n->list;
+		if(args == nil || args->next == nil) {
+			yyerror("missing arguments to copy");
+			goto error;
+		}
+		if(args->next->next != nil) {
+			yyerror("too many arguments to copy");
+			goto error;
+		}
+		n->left = args->n;
+		n->right = args->next->n;
+		n->list = nil;
+		n->type = types[TINT];
+		typecheck(&n->left, Erv);
+		typecheck(&n->right, Erv);
+		if(n->left->type == T || n->right->type == T)
+			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) {
+			if(eqtype(n->left->type->type, bytetype))
+				goto ret;
+			yyerror("arguments to copy have different element types: %lT and string", n->left->type);
+			goto error;
+		}
+
+		if(!isslice(n->left->type) || !isslice(n->right->type)) {
+			if(!isslice(n->left->type) && !isslice(n->right->type))
+				yyerror("arguments to copy must be slices; have %lT, %lT", n->left->type, n->right->type);
+			else if(!isslice(n->left->type))
+				yyerror("first argument to copy should be slice; have %lT", n->left->type);
+			else
+				yyerror("second argument to copy should be slice or string; have %lT", n->right->type);
+			goto error;
+		}
+		if(!eqtype(n->left->type->type, n->right->type->type)) {
+			yyerror("arguments to copy have different element types: %lT and %lT", n->left->type, n->right->type);
+			goto error;
+		}
+		goto ret;
+
+	case OCONV:
+	doconv:
+		ok |= Erv;
+		saveorignode(n);
+		typecheck(&n->left, Erv | (top & (Eindir | Eiota)));
+		convlit1(&n->left, n->type, 1);
+		if((t = n->left->type) == T || n->type == T)
+			goto error;
+		if((n->op = convertop(t, n->type, &why)) == 0) {
+			if(!n->diag && !n->type->broke) {
+				yyerror("cannot convert %lN to type %T%s", n->left, n->type, why);
+				n->diag = 1;
+			}
+			n->op = OCONV;
+		}
+		switch(n->op) {
+		case OCONVNOP:
+			if(n->left->op == OLITERAL) {
+				r = nod(OXXX, N, N);
+				n->op = OCONV;
+				n->orig = r;
+				*r = *n;
+				n->op = OLITERAL;
+				n->val = n->left->val;
+			}
+			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);
+			break;
+		}
+		goto ret;
+
+	case OMAKE:
+		ok |= Erv;
+		args = n->list;
+		if(args == nil) {
+			yyerror("missing argument to make");
+			goto error;
+		}
+		n->list = nil;
+		l = args->n;
+		args = args->next;
+		typecheck(&l, Etype);
+		if((t = l->type) == T)
+			goto error;
+
+		switch(t->etype) {
+		default:
+		badmake:
+			yyerror("cannot make type %T", t);
+			goto error;
+
+		case TARRAY:
+			if(!isslice(t))
+				goto badmake;
+			if(args == nil) {
+				yyerror("missing len argument to make(%T)", t);
+				goto error;
+			}
+			l = args->n;
+			args = args->next;
+			typecheck(&l, Erv);
+			r = N;
+			if(args != nil) {
+				r = args->n;
+				args = args->next;
+				typecheck(&r, Erv);
+			}
+			if(l->type == T || (r && r->type == T))
+				goto error;
+			et = checkmake(t, "len", l) < 0;
+			et |= r && checkmake(t, "cap", r) < 0;
+			if(et)
+				goto error;
+			if(isconst(l, CTINT) && r && isconst(r, CTINT) && mpcmpfixfix(l->val.u.xval, r->val.u.xval) > 0) {
+				yyerror("len larger than cap in make(%T)", t);
+				goto error;
+			}
+			n->left = l;
+			n->right = r;
+			n->op = OMAKESLICE;
+			break;
+
+		case TMAP:
+			if(args != nil) {
+				l = args->n;
+				args = args->next;
+				typecheck(&l, Erv);
+				defaultlit(&l, types[TINT]);
+				if(l->type == T)
+					goto error;
+				if(checkmake(t, "size", l) < 0)
+					goto error;
+				n->left = l;
+			} else
+				n->left = nodintconst(0);
+			n->op = OMAKEMAP;
+			break;
+
+		case TCHAN:
+			l = N;
+			if(args != nil) {
+				l = args->n;
+				args = args->next;
+				typecheck(&l, Erv);
+				defaultlit(&l, types[TINT]);
+				if(l->type == T)
+					goto error;
+				if(checkmake(t, "buffer", l) < 0)
+					goto error;
+				n->left = l;
+			} else
+				n->left = nodintconst(0);
+			n->op = OMAKECHAN;
+			break;
+		}
+		if(args != nil) {
+			yyerror("too many arguments to make(%T)", t);
+			n->op = OMAKE;
+			goto error;
+		}
+		n->type = t;
+		goto ret;
+
+	case ONEW:
+		ok |= Erv;
+		args = n->list;
+		if(args == nil) {
+			yyerror("missing argument to new");
+			goto error;
+		}
+		l = args->n;
+		typecheck(&l, Etype);
+		if((t = l->type) == T)
+			goto error;
+		if(args->next != nil) {
+			yyerror("too many arguments to new(%T)", t);
+			goto error;
+		}
+		n->left = l;
+		n->type = ptrto(t);
+		goto ret;
+
+	case OPRINT:
+	case OPRINTN:
+		ok |= Etop;
+		typechecklist(n->list, Erv | Eindir);  // Eindir: address does not escape
+		for(args=n->list; args; args=args->next) {
+			// Special case for print: int constant is int64, not int.
+			if(isconst(args->n, CTINT))
+				defaultlit(&args->n, types[TINT64]);
+			else
+				defaultlit(&args->n, T);
+		}
+		goto ret;
+
+	case OPANIC:
+		ok |= Etop;
+		if(onearg(n, "panic") < 0)
+			goto error;
+		typecheck(&n->left, Erv);
+		defaultlit(&n->left, types[TINTER]);
+		if(n->left->type == T)
+			goto error;
+		goto ret;
+	
+	case ORECOVER:
+		ok |= Erv|Etop;
+		if(n->list != nil) {
+			yyerror("too many arguments to recover");
+			goto error;
+		}
+		n->type = types[TINTER];
+		goto ret;
+
+	case OCLOSURE:
+		ok |= Erv;
+		typecheckclosure(n, top);
+		if(n->type == T)
+			goto error;
+		goto ret;
+	
+	case OITAB:
+		ok |= Erv;
+		typecheck(&n->left, Erv);
+		if((t = n->left->type) == T)
+			goto error;
+		if(t->etype != TINTER)
+			fatal("OITAB of %T", t);
+		n->type = ptrto(types[TUINTPTR]);
+		goto ret;
+
+	case OSPTR:
+		ok |= Erv;
+		typecheck(&n->left, Erv);
+		if((t = n->left->type) == T)
+			goto error;
+		if(!isslice(t) && t->etype != TSTRING)
+			fatal("OSPTR of %T", t);
+		if(t->etype == TSTRING)
+			n->type = ptrto(types[TUINT8]);
+		else
+			n->type = ptrto(t->type);
+		goto ret;
+
+	case OCLOSUREVAR:
+		ok |= Erv;
+		goto ret;
+	
+	case OCFUNC:
+		ok |= Erv;
+		typecheck(&n->left, Erv);
+		n->type = types[TUINTPTR];
+		goto ret;
+
+	case OCONVNOP:
+		ok |= Erv;
+		typecheck(&n->left, Erv);
+		goto ret;
+
+	/*
+	 * statements
+	 */
+	case OAS:
+		ok |= Etop;
+		typecheckas(n);
+		goto ret;
+
+	case OAS2:
+		ok |= Etop;
+		typecheckas2(n);
+		goto ret;
+
+	case OBREAK:
+	case OCONTINUE:
+	case ODCL:
+	case OEMPTY:
+	case OGOTO:
+	case OLABEL:
+	case OXFALL:
+	case OVARKILL:
+		ok |= Etop;
+		goto ret;
+
+	case ODEFER:
+		ok |= Etop;
+		typecheck(&n->left, Etop|Erv);
+		if(!n->left->diag)
+			checkdefergo(n);
+		goto ret;
+
+	case OPROC:
+		ok |= Etop;
+		typecheck(&n->left, Etop|Eproc|Erv);
+		checkdefergo(n);
+		goto ret;
+
+	case OFOR:
+		ok |= Etop;
+		typechecklist(n->ninit, Etop);
+		typecheck(&n->ntest, Erv);
+		if(n->ntest != N && (t = n->ntest->type) != T && t->etype != TBOOL)
+			yyerror("non-bool %lN used as for condition", n->ntest);
+		typecheck(&n->nincr, Etop);
+		typechecklist(n->nbody, Etop);
+		goto ret;
+
+	case OIF:
+		ok |= Etop;
+		typechecklist(n->ninit, Etop);
+		typecheck(&n->ntest, Erv);
+		if(n->ntest != N && (t = n->ntest->type) != T && t->etype != TBOOL)
+			yyerror("non-bool %lN used as if condition", n->ntest);
+		typechecklist(n->nbody, Etop);
+		typechecklist(n->nelse, Etop);
+		goto ret;
+
+	case ORETURN:
+		ok |= Etop;
+		if(count(n->list) == 1)
+			typechecklist(n->list, Erv | Efnstruct);
+		else
+			typechecklist(n->list, Erv);
+		if(curfn == N) {
+			yyerror("return outside function");
+			goto error;
+		}
+		if(curfn->type->outnamed && n->list == nil)
+			goto ret;
+		typecheckaste(ORETURN, nil, 0, getoutargx(curfn->type), n->list, "return argument");
+		goto ret;
+	
+	case ORETJMP:
+		ok |= Etop;
+		goto ret;
+
+	case OSELECT:
+		ok |= Etop;
+		typecheckselect(n);
+		goto ret;
+
+	case OSWITCH:
+		ok |= Etop;
+		typecheckswitch(n);
+		goto ret;
+
+	case ORANGE:
+		ok |= Etop;
+		typecheckrange(n);
+		goto ret;
+
+	case OTYPESW:
+		yyerror("use of .(type) outside type switch");
+		goto error;
+
+	case OXCASE:
+		ok |= Etop;
+		typechecklist(n->list, Erv);
+		typechecklist(n->nbody, Etop);
+		goto ret;
+
+	case ODCLFUNC:
+		ok |= Etop;
+		typecheckfunc(n);
+		goto ret;
+
+	case ODCLCONST:
+		ok |= Etop;
+		typecheck(&n->left, Erv);
+		goto ret;
+
+	case ODCLTYPE:
+		ok |= Etop;
+		typecheck(&n->left, Etype);
+		if(!incannedimport)
+			checkwidth(n->left->type);
+		goto ret;
+	}
+
+ret:
+	t = n->type;
+	if(t && !t->funarg && n->op != OTYPE) {
+		switch(t->etype) {
+		case TFUNC:	// might have TANY; wait until its called
+		case TANY:
+		case TFORW:
+		case TIDEAL:
+		case TNIL:
+		case TBLANK:
+			break;
+		default:
+			checkwidth(t);
+		}
+	}
+
+	if(safemode && !incannedimport && !importpkg && !compiling_wrappers && t && t->etype == TUNSAFEPTR)
+		yyerror("cannot use unsafe.Pointer");
+
+	evconst(n);
+	if(n->op == OTYPE && !(top & Etype)) {
+		yyerror("type %T is not an expression", n->type);
+		goto error;
+	}
+	if((top & (Erv|Etype)) == Etype && n->op != OTYPE) {
+		yyerror("%N is not a type", n);
+		goto error;
+	}
+	// TODO(rsc): simplify
+	if((top & (Ecall|Erv|Etype)) && !(top & Etop) && !(ok & (Erv|Etype|Ecall))) {
+		yyerror("%N used as value", n);
+		goto error;
+	}
+	if((top & Etop) && !(top & (Ecall|Erv|Etype)) && !(ok & Etop)) {
+		if(n->diag == 0) {
+			yyerror("%N evaluated but not used", n);
+			n->diag = 1;
+		}
+		goto error;
+	}
+
+	/* TODO
+	if(n->type == T)
+		fatal("typecheck nil type");
+	*/
+	goto out;
+
+badcall1:
+	yyerror("invalid argument %lN for %O", n->left, n->op);
+	goto error;
+
+error:
+	n->type = T;
+
+out:
+	*np = n;
+}
+
+static int
+checksliceindex(Node *l, Node *r, Type *tp)
+{
+	Type *t;
+
+	if((t = r->type) == T)
+		return -1;
+	if(!isint[t->etype]) {
+		yyerror("invalid slice index %N (type %T)", r, t);
+		return -1;
+	}
+	if(r->op == OLITERAL) {
+		if(mpgetfix(r->val.u.xval) < 0) {
+			yyerror("invalid slice index %N (index must be non-negative)", r);
+			return -1;
+		} else if(tp != nil && tp->bound > 0 && mpgetfix(r->val.u.xval) > tp->bound) {
+			yyerror("invalid slice index %N (out of bounds for %d-element array)", r, tp->bound);
+			return -1;
+		} else if(isconst(l, CTSTR) && mpgetfix(r->val.u.xval) > l->val.u.sval->len) {
+			yyerror("invalid slice index %N (out of bounds for %d-byte string)", r, l->val.u.sval->len);
+			return -1;
+		} else if(mpcmpfixfix(r->val.u.xval, maxintval[TINT]) > 0) {
+			yyerror("invalid slice index %N (index too large)", r);
+			return -1;
+		}
+	}
+	return 0;
+}
+
+static int
+checksliceconst(Node *lo, Node *hi)
+{
+	if(lo != N && hi != N && lo->op == OLITERAL && hi->op == OLITERAL
+	   && mpcmpfixfix(lo->val.u.xval, hi->val.u.xval) > 0) {
+		yyerror("invalid slice index: %N > %N", lo, hi);
+		return -1;
+	}
+	return 0;
+}
+
+static void
+checkdefergo(Node *n)
+{
+	char *what;
+	
+	what = "defer";
+	if(n->op == OPROC)
+		what = "go";
+
+	switch(n->left->op) {
+	case OCALLINTER:
+	case OCALLMETH:
+	case OCALLFUNC:
+	case OCLOSE:
+	case OCOPY:
+	case ODELETE:
+	case OPANIC:
+	case OPRINT:
+	case OPRINTN:
+	case ORECOVER:
+		// ok
+		break;
+	case OAPPEND:
+	case OCAP:
+	case OCOMPLEX:
+	case OIMAG:
+	case OLEN:
+	case OMAKE:
+	case OMAKESLICE:
+	case OMAKECHAN:
+	case OMAKEMAP:
+	case ONEW:
+	case OREAL:
+	case OLITERAL: // conversion or unsafe.Alignof, Offsetof, Sizeof
+		if(n->left->orig != N && n->left->orig->op == OCONV)
+			goto conv;
+		yyerror("%s discards result of %N", what, n->left);
+		break;
+	default:
+	conv:
+		// type is broken or missing, most likely a method call on a broken type
+		// we will warn about the broken type elsewhere. no need to emit a potentially confusing error
+		if(n->left->type == T || n->left->type->broke)
+			break;
+
+		if(!n->diag) {
+			// The syntax made sure it was a call, so this must be
+			// a conversion.
+			n->diag = 1;
+			yyerror("%s requires function call, not conversion", what);
+		}
+		break;
+	}
+}
+
+static void
+implicitstar(Node **nn)
+{
+	Type *t;
+	Node *n;
+
+	// insert implicit * if needed for fixed array
+	n = *nn;
+	t = n->type;
+	if(t == T || !isptr[t->etype])
+		return;
+	t = t->type;
+	if(t == T)
+		return;
+	if(!isfixedarray(t))
+		return;
+	n = nod(OIND, n, N);
+	n->implicit = 1;
+	typecheck(&n, Erv);
+	*nn = n;
+}
+
+static int
+onearg(Node *n, char *f, ...)
+{
+	va_list arg;
+	char *p;
+
+	if(n->left != N)
+		return 0;
+	if(n->list == nil) {
+		va_start(arg, f);
+		p = vsmprint(f, arg);
+		va_end(arg);
+		yyerror("missing argument to %s: %N", p, n);
+		return -1;
+	}
+	if(n->list->next != nil) {
+		va_start(arg, f);
+		p = vsmprint(f, arg);
+		va_end(arg);
+		yyerror("too many arguments to %s: %N", p, n);
+		n->left = n->list->n;
+		n->list = nil;
+		return -1;
+	}
+	n->left = n->list->n;
+	n->list = nil;
+	return 0;
+}
+
+static int
+twoarg(Node *n)
+{
+	if(n->left != N)
+		return 0;
+	if(n->list == nil) {
+		yyerror("missing argument to %O - %N", n->op, n);
+		return -1;
+	}
+	n->left = n->list->n;
+	if(n->list->next == nil) {
+		yyerror("missing argument to %O - %N", n->op, n);
+		n->list = nil;
+		return -1;
+	}
+	if(n->list->next->next != nil) {
+		yyerror("too many arguments to %O - %N", n->op, n);
+		n->list = nil;
+		return -1;
+	}
+	n->right = n->list->next->n;
+	n->list = nil;
+	return 0;
+}
+
+static Type*
+lookdot1(Node *errnode, Sym *s, Type *t, Type *f, int dostrcmp)
+{
+	Type *r;
+
+	r = T;
+	for(; f!=T; f=f->down) {
+		if(dostrcmp && strcmp(f->sym->name, s->name) == 0)
+			return f;
+		if(f->sym != s)
+			continue;
+		if(r != T) {
+			if(errnode)
+				yyerror("ambiguous selector %N", errnode);
+			else if(isptr[t->etype])
+				yyerror("ambiguous selector (%T).%S", t, s);
+			else
+				yyerror("ambiguous selector %T.%S", t, s);
+			break;
+		}
+		r = f;
+	}
+	return r;
+}
+
+static int
+looktypedot(Node *n, Type *t, int dostrcmp)
+{
+	Type *f1, *f2;
+	Sym *s;
+	
+	s = n->right->sym;
+
+	if(t->etype == TINTER) {
+		f1 = lookdot1(n, s, t, t->type, dostrcmp);
+		if(f1 == T)
+			return 0;
+
+		n->right = methodname(n->right, t);
+		n->xoffset = f1->width;
+		n->type = f1->type;
+		n->op = ODOTINTER;
+		return 1;
+	}
+
+	// Find the base type: methtype will fail if t
+	// is not of the form T or *T.
+	f2 = methtype(t, 0);
+	if(f2 == T)
+		return 0;
+
+	expandmeth(f2);
+	f2 = lookdot1(n, s, f2, f2->xmethod, dostrcmp);
+	if(f2 == T)
+		return 0;
+
+	// disallow T.m if m requires *T receiver
+	if(isptr[getthisx(f2->type)->type->type->etype]
+	&& !isptr[t->etype]
+	&& f2->embedded != 2
+	&& !isifacemethod(f2->type)) {
+		yyerror("invalid method expression %N (needs pointer receiver: (*%T).%hS)", n, t, f2->sym);
+		return 0;
+	}
+
+	n->right = methodname(n->right, t);
+	n->xoffset = f2->width;
+	n->type = f2->type;
+	n->op = ODOTMETH;
+	return 1;
+}
+
+static Type*
+derefall(Type* t)
+{
+	while(t && t->etype == tptr)
+		t = t->type;
+	return t;
+}
+
+static int
+lookdot(Node *n, Type *t, int dostrcmp)
+{
+	Type *f1, *f2, *tt, *rcvr;
+	Sym *s;
+
+	s = n->right->sym;
+
+	dowidth(t);
+	f1 = T;
+	if(t->etype == TSTRUCT || t->etype == TINTER)
+		f1 = lookdot1(n, s, t, t->type, dostrcmp);
+
+	f2 = T;
+	if(n->left->type == t || n->left->type->sym == S) {
+		f2 = methtype(t, 0);
+		if(f2 != T) {
+			// Use f2->method, not f2->xmethod: adddot has
+			// already inserted all the necessary embedded dots.
+			f2 = lookdot1(n, s, f2, f2->method, dostrcmp);
+		}
+	}
+
+	if(f1 != T) {
+		if(f2 != T)
+			yyerror("%S is both field and method",
+				n->right->sym);
+		if(f1->width == BADWIDTH)
+			fatal("lookdot badwidth %T %p", f1, f1);
+		n->xoffset = f1->width;
+		n->type = f1->type;
+		n->paramfld = f1;
+		if(t->etype == TINTER) {
+			if(isptr[n->left->type->etype]) {
+				n->left = nod(OIND, n->left, N);	// implicitstar
+				n->left->implicit = 1;
+				typecheck(&n->left, Erv);
+			}
+			n->op = ODOTINTER;
+		}
+		return 1;
+	}
+
+	if(f2 != T) {
+		tt = n->left->type;
+		dowidth(tt);
+		rcvr = getthisx(f2->type)->type->type;
+		if(!eqtype(rcvr, tt)) {
+			if(rcvr->etype == tptr && eqtype(rcvr->type, tt)) {
+				checklvalue(n->left, "call pointer method on");
+				n->left = nod(OADDR, n->left, N);
+				n->left->implicit = 1;
+				typecheck(&n->left, Etype|Erv);
+			} else if(tt->etype == tptr && rcvr->etype != tptr && eqtype(tt->type, rcvr)) {
+				n->left = nod(OIND, n->left, N);
+				n->left->implicit = 1;
+				typecheck(&n->left, Etype|Erv);
+			} else if(tt->etype == tptr && tt->type->etype == tptr && eqtype(derefall(tt), derefall(rcvr))) {
+				yyerror("calling method %N with receiver %lN requires explicit dereference", n->right, n->left);
+				while(tt->etype == tptr) {
+					// Stop one level early for method with pointer receiver.
+					if(rcvr->etype == tptr && tt->type->etype != tptr)
+						break;
+					n->left = nod(OIND, n->left, N);
+					n->left->implicit = 1;
+					typecheck(&n->left, Etype|Erv);
+					tt = tt->type;
+				}
+			} else {
+				fatal("method mismatch: %T for %T", rcvr, tt);
+			}
+		}
+		n->right = methodname(n->right, n->left->type);
+		n->xoffset = f2->width;
+		n->type = f2->type;
+//		print("lookdot found [%p] %T\n", f2->type, f2->type);
+		n->op = ODOTMETH;
+		return 1;
+	}
+
+	return 0;
+}
+
+static int
+nokeys(NodeList *l)
+{
+	for(; l; l=l->next)
+		if(l->n->op == OKEY)
+			return 0;
+	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
+ */
+static void
+typecheckaste(int op, Node *call, int isddd, Type *tstruct, NodeList *nl, char *desc)
+{
+	Type *t, *tl, *tn;
+	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) {
+				for(; tn; tn=tn->down) {
+					if(assignop(tn->type, tl->type->type, &why) == 0) {
+						if(call != N)
+							yyerror("cannot use %T as type %T in argument to %N%s", tn->type, tl->type->type, call, why);
+						else
+							yyerror("cannot use %T as type %T in %s%s", tn->type, tl->type->type, desc, why);
+					}
+				}
+				goto out;
+			}
+			if(tn == T)
+				goto notenough;
+			if(assignop(tn->type, tl->type, &why) == 0) {
+				if(call != N)
+					yyerror("cannot use %T as type %T in argument to %N%s", tn->type, tl->type, call, why);
+				else
+					yyerror("cannot use %T as type %T in %s%s", tn->type, tl->type, desc, why);
+			}
+			tn = tn->down;
+		}
+		if(tn != T)
+			goto toomany;
+		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) {
+			if(isddd) {
+				if(nl == nil)
+					goto notenough;
+				if(nl->next != nil)
+					goto toomany;
+				n = nl->n;
+				setlineno(n);
+				if(n->type != T)
+					nl->n = assignconv(n, t, desc);
+				goto out;
+			}
+			for(; nl; nl=nl->next) {
+				n = nl->n;
+				setlineno(nl->n);
+				if(n->type != T)
+					nl->n = assignconv(n, t->type, desc);
+			}
+			goto out;
+		}
+		if(nl == nil)
+			goto notenough;
+		n = nl->n;
+		setlineno(n);
+		if(n->type != T)
+			nl->n = assignconv(n, t, desc);
+		nl = nl->next;
+	}
+	if(nl != nil)
+		goto toomany;
+	if(isddd) {
+		if(call != N)
+			yyerror("invalid use of ... in call to %N", call);
+		else
+			yyerror("invalid use of ... in %O", op);
+	}
+
+out:
+	lineno = lno;
+	return;
+
+notenough:
+	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:
+	if(call != N)
+		yyerror("too many arguments in call to %N", call);
+	else
+		yyerror("too many arguments to %O", op);
+	goto out;
+}
+
+/*
+ * type check composite
+ */
+
+static void
+fielddup(Node *n, Node *hash[], ulong nhash)
+{
+	uint h;
+	char *s;
+	Node *a;
+
+	if(n->op != ONAME)
+		fatal("fielddup: not ONAME");
+	s = n->sym->name;
+	h = stringhash(s)%nhash;
+	for(a=hash[h]; a!=N; a=a->ntest) {
+		if(strcmp(a->sym->name, s) == 0) {
+			yyerror("duplicate field name in struct literal: %s", s);
+			return;
+		}
+	}
+	n->ntest = hash[h];
+	hash[h] = n;
+}
+
+static void
+keydup(Node *n, Node *hash[], ulong nhash)
+{
+	uint h;
+	ulong b;
+	double d;
+	int i;
+	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
+
+	switch(n->val.ctype) {
+	default:	// unknown, bool, nil
+		b = 23;
+		break;
+	case CTINT:
+	case CTRUNE:
+		b = mpgetfix(n->val.u.xval);
+		break;
+	case CTFLT:
+		d = mpgetflt(n->val.u.fval);
+		s = (char*)&d;
+		b = 0;
+		for(i=sizeof(d); i>0; i--)
+			b = b*PRIME1 + *s++;
+		break;
+	case CTSTR:
+		b = 0;
+		s = n->val.u.sval->s;
+		for(i=n->val.u.sval->len; i>0; i--)
+			b = b*PRIME1 + *s++;
+		break;
+	}
+
+	h = b%nhash;
+	memset(&cmp, 0, sizeof(cmp));
+	for(a=hash[h]; a!=N; a=a->ntest) {
+		cmp.op = OEQ;
+		cmp.left = n;
+		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) {
+			yyerror("duplicate key %N in map literal", n);
+			return;
+		}
+	}
+	orign->ntest = hash[h];
+	hash[h] = orign;
+}
+
+static void
+indexdup(Node *n, Node *hash[], ulong nhash)
+{
+	uint h;
+	Node *a;
+	ulong b, c;
+
+	if(n->op != OLITERAL)
+		fatal("indexdup: not OLITERAL");
+
+	b = mpgetfix(n->val.u.xval);
+	h = b%nhash;
+	for(a=hash[h]; a!=N; a=a->ntest) {
+		c = mpgetfix(a->val.u.xval);
+		if(b == c) {
+			yyerror("duplicate index in array literal: %ld", b);
+			return;
+		}
+	}
+	n->ntest = hash[h];
+	hash[h] = n;
+}
+
+static int
+prime(ulong h, ulong sr)
+{
+	ulong n;
+
+	for(n=3; n<=sr; n+=2)
+		if(h%n == 0)
+			return 0;
+	return 1;
+}
+
+static ulong
+inithash(Node *n, Node ***hash, Node **autohash, ulong nautohash)
+{
+	ulong h, sr;
+	NodeList *ll;
+	int i;
+
+	// count the number of entries
+	h = 0;
+	for(ll=n->list; ll; ll=ll->next)
+		h++;
+
+	// if the auto hash table is
+	// large enough use it.
+	if(h <= nautohash) {
+		*hash = autohash;
+		memset(*hash, 0, nautohash * sizeof(**hash));
+		return nautohash;
+	}
+
+	// make hash size odd and 12% larger than entries
+	h += h/8;
+	h |= 1;
+
+	// calculate sqrt of h
+	sr = h/2;
+	for(i=0; i<5; i++)
+		sr = (sr + h/sr)/2;
+
+	// check for primeality
+	while(!prime(h, sr))
+		h += 2;
+
+	// build and return a throw-away hash table
+	*hash = mal(h * sizeof(**hash));
+	memset(*hash, 0, h * sizeof(**hash));
+	return h;
+}
+
+static int
+iscomptype(Type *t)
+{
+	switch(t->etype) {
+	case TARRAY:
+	case TSTRUCT:
+	case TMAP:
+		return 1;
+	case TPTR32:
+	case TPTR64:
+		switch(t->type->etype) {
+		case TARRAY:
+		case TSTRUCT:
+		case TMAP:
+			return 1;
+		}
+		break;
+	}
+	return 0;
+}
+
+static void
+pushtype(Node *n, Type *t)
+{
+	if(n == N || n->op != OCOMPLIT || !iscomptype(t))
+		return;
+	
+	if(n->right == N) {
+		n->right = typenod(t);
+		n->implicit = 1;  // don't print
+		n->right->implicit = 1;  // * is okay
+	}
+	else if(debug['s']) {
+		typecheck(&n->right, Etype);
+		if(n->right->type != T && eqtype(n->right->type, t))
+			print("%lL: redundant type: %T\n", n->lineno, t);
+	}
+}
+
+static void
+typecheckcomplit(Node **np)
+{
+	int bad, i, nerr;
+	int64 len;
+	Node *l, *n, *norig, *r, **hash;
+	NodeList *ll;
+	Type *t, *f;
+	Sym *s, *s1;
+	int32 lno;
+	ulong nhash;
+	Node *autohash[101];
+
+	n = *np;
+	lno = lineno;
+
+	if(n->right == N) {
+		if(n->list != nil)
+			setlineno(n->list->n);
+		yyerror("missing type in composite literal");
+		goto error;
+	}
+
+	// Save original node (including n->right)
+	norig = nod(n->op, N, N);
+	*norig = *n;
+
+	setlineno(n->right);
+	l = typecheck(&n->right /* sic */, Etype|Ecomplit);
+	if((t = l->type) == T)
+		goto error;
+	nerr = nerrors;
+	n->type = t;
+
+	if(isptr[t->etype]) {
+		// For better or worse, we don't allow pointers as the composite literal type,
+		// except when using the &T syntax, which sets implicit on the OIND.
+		if(!n->right->implicit) {
+			yyerror("invalid pointer type %T for composite literal (use &%T instead)", t, t->type);
+			goto error;
+		}
+		// Also, the underlying type must be a struct, map, slice, or array.
+		if(!iscomptype(t)) {
+			yyerror("invalid pointer type %T for composite literal", t);
+			goto error;
+		}
+		t = t->type;
+	}
+
+	switch(t->etype) {
+	default:
+		yyerror("invalid type for composite literal: %T", t);
+		n->type = T;
+		break;
+
+	case TARRAY:
+		nhash = inithash(n, &hash, autohash, nelem(autohash));
+
+		len = 0;
+		i = 0;
+		for(ll=n->list; ll; ll=ll->next) {
+			l = ll->n;
+			setlineno(l);
+			if(l->op != OKEY) {
+				l = nod(OKEY, nodintconst(i), l);
+				l->left->type = types[TINT];
+				l->left->typecheck = 1;
+				ll->n = l;
+			}
+
+			typecheck(&l->left, Erv);
+			evconst(l->left);
+			i = nonnegconst(l->left);
+			if(i < 0 && !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)
+				indexdup(l->left, hash, nhash);
+			i++;
+			if(i > len) {
+				len = i;
+				if(t->bound >= 0 && len > t->bound) {
+					setlineno(l);
+					yyerror("array index %lld out of bounds [0:%lld]", len-1, t->bound);
+					t->bound = -1;	// no more errors
+				}
+			}
+
+			r = l->right;
+			pushtype(r, t->type);
+			typecheck(&r, Erv);
+			defaultlit(&r, t->type);
+			l->right = assignconv(r, t->type, "array element");
+		}
+		if(t->bound == -100)
+			t->bound = len;
+		if(t->bound < 0)
+			n->right = nodintconst(len);
+		n->op = OARRAYLIT;
+		break;
+
+	case TMAP:
+		nhash = inithash(n, &hash, autohash, nelem(autohash));
+
+		for(ll=n->list; ll; ll=ll->next) {
+			l = ll->n;
+			setlineno(l);
+			if(l->op != OKEY) {
+				typecheck(&ll->n, Erv);
+				yyerror("missing key in map literal");
+				continue;
+			}
+
+			typecheck(&l->left, Erv);
+			defaultlit(&l->left, t->down);
+			l->left = assignconv(l->left, t->down, "map key");
+			if (l->left->op != OCONV)
+				keydup(l->left, hash, nhash);
+
+			r = l->right;
+			pushtype(r, t->type);
+			typecheck(&r, Erv);
+			defaultlit(&r, t->type);
+			l->right = assignconv(r, t->type, "map value");
+		}
+		n->op = OMAPLIT;
+		break;
+
+	case TSTRUCT:
+		bad = 0;
+		if(n->list != nil && nokeys(n->list)) {
+			// simple list of variables
+			f = t->type;
+			for(ll=n->list; ll; ll=ll->next) {
+				setlineno(ll->n);
+				typecheck(&ll->n, Erv);
+				if(f == nil) {
+					if(!bad++)
+						yyerror("too many values in struct initializer");
+					continue;
+				}
+				s = f->sym;
+				if(s != nil && !exportname(s->name) && s->pkg != localpkg)
+					yyerror("implicit assignment of unexported field '%s' in %T literal", s->name, t);
+				// No pushtype allowed here.  Must name fields for that.
+				ll->n = assignconv(ll->n, f->type, "field value");
+				ll->n = nod(OKEY, newname(f->sym), ll->n);
+				ll->n->left->type = f;
+				ll->n->left->typecheck = 1;
+				f = f->down;
+			}
+			if(f != nil)
+				yyerror("too few values in struct initializer");
+		} else {
+			nhash = inithash(n, &hash, autohash, nelem(autohash));
+
+			// keyed list
+			for(ll=n->list; ll; ll=ll->next) {
+				l = ll->n;
+				setlineno(l);
+				if(l->op != OKEY) {
+					if(!bad++)
+						yyerror("mixture of field:value and value initializers");
+					typecheck(&ll->n, Erv);
+					continue;
+				}
+				s = l->left->sym;
+				if(s == S) {
+					yyerror("invalid field name %N in struct initializer", l->left);
+					typecheck(&l->right, Erv);
+					continue;
+				}
+
+				// Sym might have resolved to name in other top-level
+				// package, because of import dot.  Redirect to correct sym
+				// before we do the lookup.
+				if(s->pkg != localpkg && exportname(s->name)) {
+					s1 = lookup(s->name);
+					if(s1->origpkg == s->pkg)
+						s = s1;
+				}
+				f = lookdot1(nil, s, t, t->type, 0);
+				if(f == nil) {
+					yyerror("unknown %T field '%S' in struct literal", t, s);
+					continue;
+				}
+				l->left = newname(s);
+				l->left->typecheck = 1;
+				l->left->type = f;
+				s = f->sym;
+				fielddup(newname(s), hash, nhash);
+				r = l->right;
+				// No pushtype allowed here.  Tried and rejected.
+				typecheck(&r, Erv);
+				l->right = assignconv(r, f->type, "field value");
+			}
+		}
+		n->op = OSTRUCTLIT;
+		break;
+	}
+	if(nerr != nerrors)
+		goto error;
+	
+	n->orig = norig;
+	if(isptr[n->type->etype]) {
+		n = nod(OPTRLIT, n, N);
+		n->typecheck = 1;
+		n->type = n->left->type;
+		n->left->type = t;
+		n->left->typecheck = 1;
+	}
+
+	n->orig = norig;
+	*np = n;
+	lineno = lno;
+	return;
+
+error:
+	n->type = T;
+	*np = n;
+	lineno = lno;
+}
+
+/*
+ * lvalue etc
+ */
+int
+islvalue(Node *n)
+{
+	switch(n->op) {
+	case OINDEX:
+		if(isfixedarray(n->left->type))
+			return islvalue(n->left);
+		if(n->left->type != T && n->left->type->etype == TSTRING)
+			return 0;
+		// fall through
+	case OIND:
+	case ODOTPTR:
+	case OCLOSUREVAR:
+		return 1;
+	case ODOT:
+		return islvalue(n->left);
+	case ONAME:
+		if(n->class == PFUNC)
+			return 0;
+		return 1;
+	}
+	return 0;
+}
+
+static void
+checklvalue(Node *n, char *verb)
+{
+	if(!islvalue(n))
+		yyerror("cannot %s %N", verb, n);
+}
+
+static void
+checkassign(Node *n)
+{
+	if(islvalue(n))
+		return;
+	if(n->op == OINDEXMAP) {
+		n->etype = 1;
+		return;
+	}
+
+	// have already complained about n being undefined
+	if(n->op == ONONAME)
+		return;
+
+	yyerror("cannot assign to %N", n);
+}
+
+static void
+checkassignlist(NodeList *l)
+{
+	for(; l; l=l->next)
+		checkassign(l->n);
+}
+
+// Check whether l and r are the same side effect-free expression,
+// so that it is safe to reuse one instead of computing both.
+static int
+samesafeexpr(Node *l, Node *r)
+{
+	if(l->op != r->op || !eqtype(l->type, r->type))
+		return 0;
+	
+	switch(l->op) {
+	case ONAME:
+	case OCLOSUREVAR:
+		return l == r;
+	
+	case ODOT:
+	case ODOTPTR:
+		return l->right != nil && r->right != nil && l->right->sym == r->right->sym && samesafeexpr(l->left, r->left);
+	
+	case OIND:
+		return samesafeexpr(l->left, r->left);
+	
+	case OINDEX:
+		return samesafeexpr(l->left, r->left) && samesafeexpr(l->right, r->right);
+	}
+	
+	return 0;
+}
+
+/*
+ * type check assignment.
+ * if this assignment is the definition of a var on the left side,
+ * fill in the var's type.
+ */
+
+static void
+typecheckas(Node *n)
+{
+	// delicate little dance.
+	// the definition of n may refer to this assignment
+	// as its definition, in which case it will call typecheckas.
+	// in that case, do not call typecheck back, or it will cycle.
+	// if the variable has a type (ntype) then typechecking
+	// will not look at defn, so it is okay (and desirable,
+	// so that the conversion below happens).
+	n->left = resolve(n->left);
+	if(n->left->defn != n || n->left->ntype)
+		typecheck(&n->left, Erv | Easgn);
+
+	checkassign(n->left);
+	typecheck(&n->right, Erv);
+	if(n->right && n->right->type != T) {
+		if(n->left->type != T)
+			n->right = assignconv(n->right, n->left->type, "assignment");
+	}
+	if(n->left->defn == n && n->left->ntype == N) {
+		defaultlit(&n->right, T);
+		n->left->type = n->right->type;
+	}
+
+	// second half of dance.
+	// now that right is done, typecheck the left
+	// just to get it over with.  see dance above.
+	n->typecheck = 1;
+	if(n->left->typecheck == 0)
+		typecheck(&n->left, Erv | Easgn);
+	
+	// Recognize slices being updated in place, for better code generation later.
+	// Don't rewrite if using race detector, to avoid needing to teach race detector
+	// about this optimization.
+	if(n->left && n->left->op != OINDEXMAP && n->right && !flag_race) {
+		switch(n->right->op) {
+		case OSLICE:
+		case OSLICE3:
+		case OSLICESTR:
+			// For x = x[0:y], x can be updated in place, without touching pointer.
+			if(samesafeexpr(n->left, n->right->left) && (n->right->right->left == N || iszero(n->right->right->left)))
+				n->right->reslice = 1;
+			break;
+		
+		case OAPPEND:
+			// For x = append(x, ...), x can be updated in place when there is capacity,
+			// without touching the pointer; otherwise the emitted code to growslice
+			// can take care of updating the pointer, and only in that case.
+			if(n->right->list != nil && samesafeexpr(n->left, n->right->list->n))
+				n->right->reslice = 1;
+			break;
+		}
+	}
+}
+
+static void
+checkassignto(Type *src, Node *dst)
+{
+	char *why;
+
+	if(assignop(src, dst->type, &why) == 0) {
+		yyerror("cannot assign %T to %lN in multiple assignment%s", src, dst, why);
+		return;
+	}
+}
+
+static void
+typecheckas2(Node *n)
+{
+	int cl, cr;
+	NodeList *ll, *lr;
+	Node *l, *r;
+	Iter s;
+	Type *t;
+
+	for(ll=n->list; ll; ll=ll->next) {
+		// delicate little dance.
+		ll->n = resolve(ll->n);
+		if(ll->n->defn != n || ll->n->ntype)
+			typecheck(&ll->n, Erv | Easgn);
+	}
+	cl = count(n->list);
+	cr = count(n->rlist);
+	checkassignlist(n->list);
+	if(cl > 1 && cr == 1)
+		typecheck(&n->rlist->n, Erv | Efnstruct);
+	else
+		typechecklist(n->rlist, Erv);
+
+	if(cl == cr) {
+		// easy
+		for(ll=n->list, lr=n->rlist; ll; ll=ll->next, lr=lr->next) {
+			if(ll->n->type != T && lr->n->type != T)
+				lr->n = assignconv(lr->n, ll->n->type, "assignment");
+			if(ll->n->defn == n && ll->n->ntype == N) {
+				defaultlit(&lr->n, T);
+				ll->n->type = lr->n->type;
+			}
+		}
+		goto out;
+	}
+
+
+	l = n->list->n;
+	r = n->rlist->n;
+
+	// m[i] = x, ok
+	if(cl == 1 && cr == 2 && l->op == OINDEXMAP) {
+		if(l->type == T)
+			goto out;
+		yyerror("assignment count mismatch: %d = %d (use delete)", cl, cr);
+		goto out;
+	}
+
+	// x,y,z = f()
+	if(cr == 1) {
+		if(r->type == T)
+			goto out;
+		switch(r->op) {
+		case OCALLMETH:
+		case OCALLINTER:
+		case OCALLFUNC:
+			if(r->type->etype != TSTRUCT || r->type->funarg == 0)
+				break;
+			cr = structcount(r->type);
+			if(cr != cl)
+				goto mismatch;
+			n->op = OAS2FUNC;
+			t = structfirst(&s, &r->type);
+			for(ll=n->list; ll; ll=ll->next) {
+				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;
+				t = structnext(&s);
+			}
+			goto out;
+		}
+	}
+
+	// x, ok = y
+	if(cl == 2 && cr == 1) {
+		if(r->type == T)
+			goto out;
+		switch(r->op) {
+		case OINDEXMAP:
+			n->op = OAS2MAPR;
+			goto common;
+		case ORECV:
+			n->op = OAS2RECV;
+			goto common;
+		case ODOTTYPE:
+			n->op = OAS2DOTTYPE;
+			r->op = ODOTTYPE2;
+		common:
+			if(l->type != T)
+				checkassignto(r->type, l);
+			if(l->defn == n)
+				l->type = r->type;
+			l = n->list->next->n;
+			if(l->type != T && l->type->etype != TBOOL)
+				checkassignto(types[TBOOL], l);
+			if(l->defn == n && l->ntype == N)
+				l->type = types[TBOOL];
+			goto out;
+		}
+	}
+
+mismatch:
+	yyerror("assignment count mismatch: %d = %d", cl, cr);
+
+out:
+	// second half of dance
+	n->typecheck = 1;
+	for(ll=n->list; ll; ll=ll->next)
+		if(ll->n->typecheck == 0)
+			typecheck(&ll->n, Erv | Easgn);
+}
+
+/*
+ * type check function definition
+ */
+static void
+typecheckfunc(Node *n)
+{
+	Type *t, *rcvr;
+
+	typecheck(&n->nname, Erv | Easgn);
+	if((t = n->nname->type) == T)
+		return;
+	n->type = t;
+	t->nname = n->nname;
+	rcvr = getthisx(t)->type;
+	if(rcvr != nil && n->shortname != N && !isblank(n->shortname))
+		addmethod(n->shortname->sym, t, 1, n->nname->nointerface);
+}
+
+static void
+stringtoarraylit(Node **np)
+{
+	int32 i;
+	NodeList *l;
+	Strlit *s;
+	char *p, *ep;
+	Rune r;
+	Node *nn, *n;
+
+	n = *np;
+	if(n->left->op != OLITERAL || n->left->val.ctype != CTSTR)
+		fatal("stringtoarraylit %N", n);
+
+	s = n->left->val.u.sval;
+	l = nil;
+	p = s->s;
+	ep = s->s + s->len;
+	i = 0;
+	if(n->type->type->etype == TUINT8) {
+		// raw []byte
+		while(p < ep)
+			l = list(l, nod(OKEY, nodintconst(i++), nodintconst((uchar)*p++)));
+	} else {
+		// utf-8 []rune
+		while(p < ep) {
+			p += chartorune(&r, p);
+			l = list(l, nod(OKEY, nodintconst(i++), nodintconst(r)));
+		}
+	}
+	nn = nod(OCOMPLIT, N, typenod(n->type));
+	nn->list = l;
+	typecheck(&nn, Erv);
+	*np = nn;
+}
+
+
+static int ntypecheckdeftype;
+static NodeList *methodqueue;
+
+static void
+domethod(Node *n)
+{
+	Node *nt;
+	Type *t;
+
+	nt = n->type->nname;
+	typecheck(&nt, Etype);
+	if(nt->type == T) {
+		// type check failed; leave empty func
+		n->type->etype = TFUNC;
+		n->type->nod = N;
+		return;
+	}
+	
+	// If we have
+	//	type I interface {
+	//		M(_ int)
+	//	}
+	// then even though I.M looks like it doesn't care about the
+	// value of its argument, a specific implementation of I may
+	// care.  The _ would suppress the assignment to that argument
+	// while generating a call, so remove it.
+	for(t=getinargx(nt->type)->type; t; t=t->down) {
+		if(t->sym != nil && strcmp(t->sym->name, "_") == 0)
+			t->sym = nil;
+	}
+
+	*n->type = *nt->type;
+	n->type->nod = N;
+	checkwidth(n->type);
+}
+
+static NodeList *mapqueue;
+
+void
+copytype(Node *n, Type *t)
+{
+	int maplineno, embedlineno, lno;
+	NodeList *l;
+
+	if(t->etype == TFORW) {
+		// This type isn't computed yet; when it is, update n.
+		t->copyto = list(t->copyto, n);
+		return;
+	}
+
+	maplineno = n->type->maplineno;
+	embedlineno = n->type->embedlineno;
+
+	l = n->type->copyto;
+	*n->type = *t;
+
+	t = n->type;
+	t->sym = n->sym;
+	t->local = n->local;
+	t->vargen = n->vargen;
+	t->siggen = 0;
+	t->method = nil;
+	t->xmethod = nil;
+	t->nod = N;
+	t->printed = 0;
+	t->deferwidth = 0;
+	t->copyto = nil;
+	
+	// Update nodes waiting on this type.
+	for(; l; l=l->next)
+		copytype(l->n, t);
+
+	// Double-check use of type as embedded type.
+	lno = lineno;
+	if(embedlineno) {
+		lineno = embedlineno;
+		if(isptr[t->etype])
+			yyerror("embedded type cannot be a pointer");
+	}
+	lineno = lno;
+	
+	// Queue check for map until all the types are done settling.
+	if(maplineno) {
+		t->maplineno = maplineno;
+		mapqueue = list(mapqueue, n);
+	}
+}
+
+static void
+typecheckdeftype(Node *n)
+{
+	int lno;
+	Type *t;
+	NodeList *l;
+
+	ntypecheckdeftype++;
+	lno = lineno;
+	setlineno(n);
+	n->type->sym = n->sym;
+	n->typecheck = 1;
+	typecheck(&n->ntype, Etype);
+	if((t = n->ntype->type) == T) {
+		n->diag = 1;
+		n->type = T;
+		goto ret;
+	}
+	if(n->type == T) {
+		n->diag = 1;
+		goto ret;
+	}
+
+	// copy new type and clear fields
+	// that don't come along.
+	// anything zeroed here must be zeroed in
+	// typedcl2 too.
+	copytype(n, t);
+
+ret:
+	lineno = lno;
+
+	// if there are no type definitions going on, it's safe to
+	// try to resolve the method types for the interfaces
+	// we just read.
+	if(ntypecheckdeftype == 1) {
+		while((l = methodqueue) != nil) {
+			methodqueue = nil;
+			for(; l; l=l->next)
+				domethod(l->n);
+		}
+		for(l=mapqueue; l; l=l->next) {
+			lineno = l->n->type->maplineno;
+			maptype(l->n->type, types[TBOOL]);
+		}
+		lineno = lno;
+	}
+	ntypecheckdeftype--;
+}
+
+void
+queuemethod(Node *n)
+{
+	if(ntypecheckdeftype == 0) {
+		domethod(n);
+		return;
+	}
+	methodqueue = list(methodqueue, n);
+}
+
+Node*
+typecheckdef(Node *n)
+{
+	int lno, nerrors0;
+	Node *e;
+	Type *t;
+	NodeList *l;
+
+	lno = lineno;
+	setlineno(n);
+
+	if(n->op == ONONAME) {
+		if(!n->diag) {
+			n->diag = 1;
+			if(n->lineno != 0)
+				lineno = n->lineno;
+			yyerror("undefined: %S", n->sym);
+		}
+		return n;
+	}
+
+	if(n->walkdef == 1)
+		return n;
+
+	l = mal(sizeof *l);
+	l->n = n;
+	l->next = typecheckdefstack;
+	typecheckdefstack = l;
+
+	if(n->walkdef == 2) {
+		flusherrors();
+		print("typecheckdef loop:");
+		for(l=typecheckdefstack; l; l=l->next)
+			print(" %S", l->n->sym);
+		print("\n");
+		fatal("typecheckdef loop");
+	}
+	n->walkdef = 2;
+
+	if(n->type != T || n->sym == S)	// builtin or no name
+		goto ret;
+
+	switch(n->op) {
+	default:
+		fatal("typecheckdef %O", n->op);
+
+	case OGOTO:
+	case OLABEL:
+		// not really syms
+		break;
+
+	case OLITERAL:
+		if(n->ntype != N) {
+			typecheck(&n->ntype, Etype);
+			n->type = n->ntype->type;
+			n->ntype = N;
+			if(n->type == T) {
+				n->diag = 1;
+				goto ret;
+			}
+		}
+		e = n->defn;
+		n->defn = N;
+		if(e == N) {
+			lineno = n->lineno;
+			dump("typecheckdef nil defn", n);
+			yyerror("xxx");
+		}
+		typecheck(&e, Erv | Eiota);
+		if(isconst(e, CTNIL)) {
+			yyerror("const initializer cannot be nil");
+			goto ret;
+		}
+		if(e->type != T && e->op != OLITERAL || !isgoconst(e)) {
+			if(!e->diag) {
+				yyerror("const initializer %N is not a constant", e);
+				e->diag = 1;
+			}
+			goto ret;
+		}
+		t = n->type;
+		if(t != T) {
+			if(!okforconst[t->etype]) {
+				yyerror("invalid constant type %T", t);
+				goto ret;
+			}
+			if(!isideal(e->type) && !eqtype(t, e->type)) {
+				yyerror("cannot use %lN as type %T in const initializer", e, t);
+				goto ret;
+			}
+			convlit(&e, t);
+		}
+		n->val = e->val;
+		n->type = e->type;
+		break;
+
+	case ONAME:
+		if(n->ntype != N) {
+			typecheck(&n->ntype, Etype);
+			n->type = n->ntype->type;
+
+			if(n->type == T) {
+				n->diag = 1;
+				goto ret;
+			}
+		}
+		if(n->type != T)
+			break;
+		if(n->defn == N) {
+			if(n->etype != 0)	// like OPRINTN
+				break;
+			if(nsavederrors+nerrors > 0) {
+				// Can have undefined variables in x := foo
+				// that make x have an n->ndefn == nil.
+				// If there are other errors anyway, don't
+				// bother adding to the noise.
+				break;
+			}
+			fatal("var without type, init: %S", n->sym);
+		}
+		if(n->defn->op == ONAME) {
+			typecheck(&n->defn, Erv);
+			n->type = n->defn->type;
+			break;
+		}
+		typecheck(&n->defn, Etop);	// fills in n->type
+		break;
+
+	case OTYPE:
+		if(curfn)
+			defercheckwidth();
+		n->walkdef = 1;
+		n->type = typ(TFORW);
+		n->type->sym = n->sym;
+		nerrors0 = nerrors;
+		typecheckdeftype(n);
+		if(n->type->etype == TFORW && nerrors > nerrors0) {
+			// Something went wrong during type-checking,
+			// but it was reported. Silence future errors.
+			n->type->broke = 1;
+		}
+		if(curfn)
+			resumecheckwidth();
+		break;
+
+	case OPACK:
+		// nothing to see here
+		break;
+	}
+
+ret:
+	if(n->op != OLITERAL && n->type != T && isideal(n->type))
+		fatal("got %T for %N", n->type, n);
+	if(typecheckdefstack->n != n)
+		fatal("typecheckdefstack mismatch");
+	l = typecheckdefstack;
+	typecheckdefstack = l->next;
+
+	lineno = lno;
+	n->walkdef = 1;
+	return n;
+}
+
+static int
+checkmake(Type *t, char *arg, Node *n)
+{
+	if(n->op == OLITERAL) {
+		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;
+		}
+	}
+
+	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;
+}
+
+static void	markbreaklist(NodeList*, Node*);
+
+static void
+markbreak(Node *n, Node *implicit)
+{
+	Label *lab;
+
+	if(n == N)
+		return;
+
+	switch(n->op) {
+	case OBREAK:
+		if(n->left == N) {
+			if(implicit)
+				implicit->hasbreak = 1;
+		} else {
+			lab = n->left->sym->label;
+			if(lab != L)
+				lab->def->hasbreak = 1;
+		}
+		break;
+	
+	case OFOR:
+	case OSWITCH:
+	case OTYPESW:
+	case OSELECT:
+	case ORANGE:
+		implicit = n;
+		// fall through
+	
+	default:
+		markbreak(n->left, implicit);
+		markbreak(n->right, implicit);
+		markbreak(n->ntest, implicit);
+		markbreak(n->nincr, implicit);
+		markbreaklist(n->ninit, implicit);
+		markbreaklist(n->nbody, implicit);
+		markbreaklist(n->nelse, implicit);
+		markbreaklist(n->list, implicit);
+		markbreaklist(n->rlist, implicit);
+		break;
+	}
+}
+
+static void
+markbreaklist(NodeList *l, Node *implicit)
+{
+	Node *n;
+	Label *lab;
+
+	for(; l; l=l->next) {
+		n = l->n;
+		if(n->op == OLABEL && l->next && n->defn == l->next->n) {
+			switch(n->defn->op) {
+			case OFOR:
+			case OSWITCH:
+			case OTYPESW:
+			case OSELECT:
+			case ORANGE:
+				lab = mal(sizeof *lab);
+				lab->def = n->defn;
+				n->left->sym->label = lab;
+				markbreak(n->defn, n->defn);
+				n->left->sym->label = L;
+				l = l->next;
+				continue;
+			}
+		}
+		markbreak(n, implicit);
+	}
+}
+
+static int
+isterminating(NodeList *l, int top)
+{
+	int def;
+	Node *n;
+
+	if(l == nil)
+		return 0;
+	if(top) {
+		while(l->next && l->n->op != OLABEL)
+			l = l->next;
+		markbreaklist(l, nil);
+	}
+	while(l->next)
+		l = l->next;
+	n = l->n;
+
+	if(n == N)
+		return 0;
+
+	switch(n->op) {
+	// NOTE: OLABEL is treated as a separate statement,
+	// not a separate prefix, so skipping to the last statement
+	// in the block handles the labeled statement case by
+	// skipping over the label. No case OLABEL here.
+
+	case OBLOCK:
+		return isterminating(n->list, 0);
+
+	case OGOTO:
+	case ORETURN:
+	case ORETJMP:
+	case OPANIC:
+	case OXFALL:
+		return 1;
+
+	case OFOR:
+		if(n->ntest != N)
+			return 0;
+		if(n->hasbreak)
+			return 0;
+		return 1;
+
+	case OIF:
+		return isterminating(n->nbody, 0) && isterminating(n->nelse, 0);
+
+	case OSWITCH:
+	case OTYPESW:
+	case OSELECT:
+		if(n->hasbreak)
+			return 0;
+		def = 0;
+		for(l=n->list; l; l=l->next) {
+			if(!isterminating(l->n->nbody, 0))
+				return 0;
+			if(l->n->list == nil) // default
+				def = 1;
+		}
+		if(n->op != OSELECT && !def)
+			return 0;
+		return 1;
+	}
+	
+	return 0;
+}
+
+void
+checkreturn(Node *fn)
+{
+	if(fn->type->outtuple && fn->nbody != nil)
+		if(!isterminating(fn->nbody, 1))
+			yyerrorl(fn->endlineno, "missing return at end of function");
+}
diff --git a/src/cmd/gc/unsafe.c b/src/cmd/gc/unsafe.c
new file mode 100644
index 0000000..ff08c0e
--- /dev/null
+++ b/src/cmd/gc/unsafe.c
@@ -0,0 +1,148 @@
+// 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 "go.h"
+
+/*
+ * look for
+ *	unsafe.Sizeof
+ *	unsafe.Offsetof
+ *	unsafe.Alignof
+ * rewrite with a constant
+ */
+Node*
+unsafenmagic(Node *nn)
+{
+	Node *r, *n, *base, *r1;
+	Sym *s;
+	Type *t, *tr;
+	vlong v;
+	Val val;
+	Node *fn;
+	NodeList *args;
+
+	fn = nn->left;
+	args = nn->list;
+
+	if(safemode || fn == N || fn->op != ONAME || (s = fn->sym) == S)
+		goto no;
+	if(s->pkg != unsafepkg)
+		goto no;
+
+	if(args == nil) {
+		yyerror("missing argument for %S", s);
+		goto no;
+	}
+	r = args->n;
+
+	if(strcmp(s->name, "Sizeof") == 0) {
+		typecheck(&r, Erv);
+		defaultlit(&r, T);
+		tr = r->type;
+		if(tr == T)
+			goto bad;
+		dowidth(tr);
+		v = tr->width;
+		goto yes;
+	}
+	if(strcmp(s->name, "Offsetof") == 0) {
+		// must be a selector.
+		if(r->op != OXDOT)
+			goto bad;
+		// Remember base of selector to find it back after dot insertion.
+		// Since r->left may be mutated by typechecking, check it explicitly
+		// first to track it correctly.
+		typecheck(&r->left, Erv);
+		base = r->left;
+		typecheck(&r, Erv);
+		switch(r->op) {
+		case ODOT:
+		case ODOTPTR:
+			break;
+		case OCALLPART:
+			yyerror("invalid expression %N: argument is a method value", nn);
+			v = 0;
+			goto ret;
+		default:
+			goto bad;
+		}
+		v = 0;
+		// add offsets for inserted dots.
+		for(r1=r; r1->left!=base; r1=r1->left) {
+			switch(r1->op) {
+			case ODOT:
+				v += r1->xoffset;
+				break;
+			case ODOTPTR:
+				yyerror("invalid expression %N: selector implies indirection of embedded %N", nn, r1->left);
+				goto ret;
+			default:
+				dump("unsafenmagic", r);
+				fatal("impossible %#O node after dot insertion", r1->op);
+				goto bad;
+			}
+		}
+		v += r1->xoffset;
+		goto yes;
+	}
+	if(strcmp(s->name, "Alignof") == 0) {
+		typecheck(&r, Erv);
+		defaultlit(&r, T);
+		tr = r->type;
+		if(tr == T)
+			goto bad;
+
+		// make struct { byte; T; }
+		t = typ(TSTRUCT);
+		t->type = typ(TFIELD);
+		t->type->type = types[TUINT8];
+		t->type->down = typ(TFIELD);
+		t->type->down->type = tr;
+		// compute struct widths
+		dowidth(t);
+
+		// the offset of T is its required alignment
+		v = t->type->down->width;
+		goto yes;
+	}
+
+no:
+	return N;
+
+bad:
+	yyerror("invalid expression %N", nn);
+	v = 0;
+	goto ret;
+
+yes:
+	if(args->next != nil)
+		yyerror("extra arguments for %S", s);
+ret:
+	// any side effects disappear; ignore init
+	val.ctype = CTINT;
+	val.u.xval = mal(sizeof(*n->val.u.xval));
+	mpmovecfix(val.u.xval, v);
+	n = nod(OLITERAL, N, N);
+	n->orig = nn;
+	n->val = val;
+	n->type = types[TUINTPTR];
+	nn->type = types[TUINTPTR];
+	return n;
+}
+
+int
+isunsafebuiltin(Node *n)
+{
+	if(n == N || n->op != ONAME || n->sym == S || n->sym->pkg != unsafepkg)
+		return 0;
+	if(strcmp(n->sym->name, "Sizeof") == 0)
+		return 1;
+	if(strcmp(n->sym->name, "Offsetof") == 0)
+		return 1;
+	if(strcmp(n->sym->name, "Alignof") == 0)
+		return 1;
+	return 0;
+}
diff --git a/src/cmd/gc/unsafe.go b/src/cmd/gc/unsafe.go
new file mode 100644
index 0000000..c3c6278
--- /dev/null
+++ b/src/cmd/gc/unsafe.go
@@ -0,0 +1,18 @@
+// 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.
+
+// NOTE: If you change this file you must run "./mkbuiltin"
+// to update builtin.c.boot.  This is not done automatically
+// to avoid depending on having a working compiler binary.
+
+// +build ignore
+
+package PACKAGE
+
+type Pointer uintptr // not really; filled in by compiler
+
+// return types here are ignored; see unsafe.c
+func Offsetof(any) uintptr
+func Sizeof(any) uintptr
+func Alignof(any) uintptr
diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c
new file mode 100644
index 0000000..ff9b362
--- /dev/null
+++ b/src/cmd/gc/walk.c
@@ -0,0 +1,3937 @@
+// 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	"go.h"
+#include	"../ld/textflag.h"
+
+static	Node*	walkprint(Node*, NodeList**);
+static	Node*	writebarrierfn(char*, Type*, Type*);
+static	Node*	applywritebarrier(Node*, NodeList**);
+static	Node*	mapfn(char*, Type*);
+static	Node*	mapfndel(char*, Type*);
+static	Node*	ascompatee1(int, Node*, Node*, NodeList**);
+static	NodeList*	ascompatee(int, NodeList*, NodeList*, NodeList**);
+static	NodeList*	ascompatet(int, NodeList*, Type**, int, NodeList**);
+static	NodeList*	ascompatte(int, Node*, int, Type**, NodeList*, int, NodeList**);
+static	Node*	convas(Node*, NodeList**);
+static	void	heapmoves(void);
+static	NodeList*	paramstoheap(Type **argin, int out);
+static	NodeList*	reorder1(NodeList*);
+static	NodeList*	reorder3(NodeList*);
+static	Node*	addstr(Node*, NodeList**);
+static	Node*	appendslice(Node*, NodeList**);
+static	Node*	append(Node*, NodeList**);
+static	Node*	copyany(Node*, NodeList**, int);
+static	Node*	sliceany(Node*, NodeList**);
+static	void	walkcompare(Node**, NodeList**);
+static	void	walkrotate(Node**);
+static	void	walkmul(Node**, NodeList**);
+static	void	walkdiv(Node**, NodeList**);
+static	int	bounded(Node*, int64);
+static	Mpint	mpzero;
+static	void	walkprintfunc(Node**, NodeList**);
+
+void
+walk(Node *fn)
+{
+	char s[50];
+	NodeList *l;
+	int lno;
+
+	curfn = fn;
+
+	if(debug['W']) {
+		snprint(s, sizeof(s), "\nbefore %S", curfn->nname->sym);
+		dumplist(s, curfn->nbody);
+	}
+
+	lno = lineno;
+
+	// Final typecheck for any unused variables.
+	// It's hard to be on the heap when not-used, but best to be consistent about &~PHEAP here and below.
+	for(l=fn->dcl; l; l=l->next)
+		if(l->n->op == ONAME && (l->n->class&~PHEAP) == PAUTO)
+			typecheck(&l->n, Erv | Easgn);
+
+	// Propagate the used flag for typeswitch variables up to the NONAME in it's definition.
+	for(l=fn->dcl; l; l=l->next)
+		if(l->n->op == ONAME && (l->n->class&~PHEAP) == PAUTO && l->n->defn && l->n->defn->op == OTYPESW && l->n->used)
+			l->n->defn->left->used++;
+	
+	for(l=fn->dcl; l; l=l->next) {
+		if(l->n->op != ONAME || (l->n->class&~PHEAP) != PAUTO || l->n->sym->name[0] == '&' || l->n->used)
+			continue;
+		if(l->n->defn && l->n->defn->op == OTYPESW) {
+			if(l->n->defn->left->used)
+				continue;
+			lineno = l->n->defn->left->lineno;
+			yyerror("%S declared and not used", l->n->sym);
+			l->n->defn->left->used = 1; // suppress repeats
+		} else {
+			lineno = l->n->lineno;
+			yyerror("%S declared and not used", l->n->sym);
+		}
+	}	
+
+	lineno = lno;
+	if(nerrors != 0)
+		return;
+	walkstmtlist(curfn->nbody);
+	if(debug['W']) {
+		snprint(s, sizeof(s), "after walk %S", curfn->nname->sym);
+		dumplist(s, curfn->nbody);
+	}
+	heapmoves();
+	if(debug['W'] && curfn->enter != nil) {
+		snprint(s, sizeof(s), "enter %S", curfn->nname->sym);
+		dumplist(s, curfn->enter);
+	}
+}
+
+
+void
+walkstmtlist(NodeList *l)
+{
+	for(; l; l=l->next)
+		walkstmt(&l->n);
+}
+
+static int
+samelist(NodeList *a, NodeList *b)
+{
+	for(; a && b; a=a->next, b=b->next)
+		if(a->n != b->n)
+			return 0;
+	return a == b;
+}
+
+static int
+paramoutheap(Node *fn)
+{
+	NodeList *l;
+
+	for(l=fn->dcl; l; l=l->next) {
+		switch(l->n->class) {
+		case PPARAMOUT:
+		case PPARAMOUT|PHEAP:
+			return l->n->addrtaken;
+		case PAUTO:
+		case PAUTO|PHEAP:
+			// stop early - parameters are over
+			return 0;
+		}
+	}
+	return 0;
+}
+
+void
+walkstmt(Node **np)
+{
+	NodeList *init;
+	NodeList *ll, *rl;
+	int cl;
+	Node *n, *f;
+
+	n = *np;
+	if(n == N)
+		return;
+	if(n->dodata == 2) // don't walk, generated by anylit.
+		return;
+
+	setlineno(n);
+
+	walkstmtlist(n->ninit);
+
+	switch(n->op) {
+	default:
+		if(n->op == ONAME)
+			yyerror("%S is not a top level statement", n->sym);
+		else
+			yyerror("%O is not a top level statement", n->op);
+		dump("nottop", n);
+		break;
+
+	case OAS:
+	case OASOP:
+	case OAS2:
+	case OAS2DOTTYPE:
+	case OAS2RECV:
+	case OAS2FUNC:
+	case OAS2MAPR:
+	case OCLOSE:
+	case OCOPY:
+	case OCALLMETH:
+	case OCALLINTER:
+	case OCALL:
+	case OCALLFUNC:
+	case ODELETE:
+	case OSEND:
+	case OPRINT:
+	case OPRINTN:
+	case OPANIC:
+	case OEMPTY:
+	case ORECOVER:
+		if(n->typecheck == 0)
+			fatal("missing typecheck: %+N", n);
+		init = n->ninit;
+		n->ninit = nil;
+		walkexpr(&n, &init);
+		addinit(&n, init);
+		if((*np)->op == OCOPY && n->op == OCONVNOP)
+			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:
+	case OFALL:
+	case OGOTO:
+	case OLABEL:
+	case ODCLCONST:
+	case ODCLTYPE:
+	case OCHECKNIL:
+	case OVARKILL:
+		break;
+
+	case OBLOCK:
+		walkstmtlist(n->list);
+		break;
+
+	case OXCASE:
+		yyerror("case statement out of place");
+		n->op = OCASE;
+	case OCASE:
+		walkstmt(&n->right);
+		break;
+
+	case ODEFER:
+		hasdefer = 1;
+		switch(n->left->op) {
+		case OPRINT:
+		case OPRINTN:
+			walkprintfunc(&n->left, &n->ninit);
+			break;
+		case OCOPY:
+			n->left = copyany(n->left, &n->ninit, 1);
+			break;
+		default:
+			walkexpr(&n->left, &n->ninit);
+			break;
+		}
+		break;
+
+	case OFOR:
+		if(n->ntest != N) {
+			walkstmtlist(n->ntest->ninit);
+			init = n->ntest->ninit;
+			n->ntest->ninit = nil;
+			walkexpr(&n->ntest, &init);
+			addinit(&n->ntest, init);
+		}
+		walkstmt(&n->nincr);
+		walkstmtlist(n->nbody);
+		break;
+
+	case OIF:
+		walkexpr(&n->ntest, &n->ninit);
+		walkstmtlist(n->nbody);
+		walkstmtlist(n->nelse);
+		break;
+
+	case OPROC:
+		switch(n->left->op) {
+		case OPRINT:
+		case OPRINTN:
+			walkprintfunc(&n->left, &n->ninit);
+			break;
+		case OCOPY:
+			n->left = copyany(n->left, &n->ninit, 1);
+			break;
+		default:
+			walkexpr(&n->left, &n->ninit);
+			break;
+		}
+		break;
+
+	case ORETURN:
+		walkexprlist(n->list, &n->ninit);
+		if(n->list == nil)
+			break;
+		if((curfn->type->outnamed && count(n->list) > 1) || paramoutheap(curfn)) {
+			// assign to the function out parameters,
+			// so that reorder3 can fix up conflicts
+			rl = nil;
+			for(ll=curfn->dcl; ll != nil; ll=ll->next) {
+				cl = ll->n->class & ~PHEAP;
+				if(cl == PAUTO)
+					break;
+				if(cl == PPARAMOUT)
+					rl = list(rl, ll->n);
+			}
+			if(samelist(rl, n->list)) {
+				// special return in disguise
+				n->list = nil;
+				break;
+			}
+			if(count(n->list) == 1 && count(rl) > 1) {
+				// OAS2FUNC in disguise
+				f = n->list->n;
+				if(f->op != OCALLFUNC && f->op != OCALLMETH && f->op != OCALLINTER)
+					fatal("expected return of call, have %N", f);
+				n->list = concat(list1(f), ascompatet(n->op, rl, &f->type, 0, &n->ninit));
+				break;
+			}
+
+			// move function calls out, to make reorder3's job easier.
+			walkexprlistsafe(n->list, &n->ninit);
+			ll = ascompatee(n->op, rl, n->list, &n->ninit);
+			n->list = reorder3(ll);
+			break;
+		}
+		ll = ascompatte(n->op, nil, 0, getoutarg(curfn->type), n->list, 1, &n->ninit);
+		n->list = ll;
+		break;
+
+	case ORETJMP:
+		break;
+
+	case OSELECT:
+		walkselect(n);
+		break;
+
+	case OSWITCH:
+		walkswitch(n);
+		break;
+
+	case ORANGE:
+		walkrange(n);
+		break;
+
+	case OXFALL:
+		yyerror("fallthrough statement out of place");
+		n->op = OFALL;
+		break;
+	}
+
+	if(n->op == ONAME)
+		fatal("walkstmt ended up with name: %+N", n);
+	
+	*np = n;
+}
+
+
+/*
+ * walk the whole tree of the body of an
+ * expression or simple statement.
+ * the types expressions are calculated.
+ * compile-time constants are evaluated.
+ * complex side effects like statements are appended to init
+ */
+
+void
+walkexprlist(NodeList *l, NodeList **init)
+{
+	for(; l; l=l->next)
+		walkexpr(&l->n, init);
+}
+
+void
+walkexprlistsafe(NodeList *l, NodeList **init)
+{
+	for(; l; l=l->next) {
+		l->n = safeexpr(l->n, init);
+		walkexpr(&l->n, init);
+	}
+}
+
+void
+walkexpr(Node **np, NodeList **init)
+{
+	Node *r, *l, *var, *a;
+	Node *map, *key;
+	NodeList *ll, *lr;
+	Type *t;
+	int et, old_safemode;
+	int64 v;
+	int32 lno;
+	Node *n, *fn, *n1, *n2;
+	Sym *sym;
+	char buf[100], *p;
+
+	n = *np;
+
+	if(n == N)
+		return;
+
+	if(init == &n->ninit) {
+		// not okay to use n->ninit when walking n,
+		// because we might replace n with some other node
+		// and would lose the init list.
+		fatal("walkexpr init == &n->ninit");
+	}
+
+	if(n->ninit != nil) {
+		walkstmtlist(n->ninit);
+		*init = concat(*init, n->ninit);
+		n->ninit = nil;
+	}
+
+	// annoying case - not typechecked
+	if(n->op == OKEY) {
+		walkexpr(&n->left, init);
+		walkexpr(&n->right, init);
+		return;
+	}
+
+	lno = setlineno(n);
+
+	if(debug['w'] > 1)
+		dump("walk-before", n);
+
+	if(n->typecheck != 1)
+		fatal("missed typecheck: %+N\n", n);
+
+	switch(n->op) {
+	default:
+		dump("walk", n);
+		fatal("walkexpr: switch 1 unknown op %+hN", n);
+		break;
+
+	case OTYPE:
+	case ONONAME:
+	case OINDREG:
+	case OEMPTY:
+		goto ret;
+
+	case ONOT:
+	case OMINUS:
+	case OPLUS:
+	case OCOM:
+	case OREAL:
+	case OIMAG:
+	case ODOTMETH:
+	case ODOTINTER:
+		walkexpr(&n->left, init);
+		goto ret;
+
+	case OIND:
+		walkexpr(&n->left, init);
+		goto ret;
+
+	case ODOT:
+		usefield(n);
+		walkexpr(&n->left, init);
+		goto ret;
+
+	case ODOTPTR:
+		usefield(n);
+		if(n->op == ODOTPTR && n->left->type->type->width == 0) {
+			// No actual copy will be generated, so emit an explicit nil check.
+			n->left = cheapexpr(n->left, init);
+			checknil(n->left, init);
+		}
+		walkexpr(&n->left, init);
+		goto ret;
+
+	case OEFACE:
+		walkexpr(&n->left, init);
+		walkexpr(&n->right, init);
+		goto ret;
+
+	case OSPTR:
+	case OITAB:
+		walkexpr(&n->left, init);
+		goto ret;
+
+	case OLEN:
+	case OCAP:
+		walkexpr(&n->left, init);
+
+		// replace len(*[10]int) with 10.
+		// delayed until now to preserve side effects.
+		t = n->left->type;
+		if(isptr[t->etype])
+			t = t->type;
+		if(isfixedarray(t)) {
+			safeexpr(n->left, init);
+			nodconst(n, n->type, t->bound);
+			n->typecheck = 1;
+		}
+		goto ret;
+
+	case OLSH:
+	case ORSH:
+		walkexpr(&n->left, init);
+		walkexpr(&n->right, init);
+		t = n->left->type;
+		n->bounded = bounded(n->right, 8*t->width);
+		if(debug['m'] && n->etype && !isconst(n->right, CTINT))
+			warn("shift bounds check elided");
+		goto ret;
+
+	case OAND:
+	case OSUB:
+	case OHMUL:
+	case OLT:
+	case OLE:
+	case OGE:
+	case OGT:
+	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;
+
+	case OOR:
+	case OXOR:
+		walkexpr(&n->left, init);
+		walkexpr(&n->right, init);
+		walkrotate(&n);
+		goto ret;
+
+	case OEQ:
+	case ONE:
+		walkexpr(&n->left, init);
+		walkexpr(&n->right, init);
+		// Disable safemode while compiling this code: the code we
+		// generate internally can refer to unsafe.Pointer.
+		// In this case it can happen if we need to generate an ==
+		// for a struct containing a reflect.Value, which itself has
+		// an unexported field of type unsafe.Pointer.
+		old_safemode = safemode;
+		safemode = 0;
+		walkcompare(&n, init);
+		safemode = old_safemode;
+		goto ret;
+
+	case OANDAND:
+	case OOROR:
+		walkexpr(&n->left, init);
+		// cannot put side effects from n->right on init,
+		// because they cannot run before n->left is checked.
+		// save elsewhere and store on the eventual n->right.
+		ll = nil;
+		walkexpr(&n->right, &ll);
+		addinit(&n->right, ll);
+		goto ret;
+
+	case OPRINT:
+	case OPRINTN:
+		walkexprlist(n->list, init);
+		n = walkprint(n, init);
+		goto ret;
+
+	case OPANIC:
+		n = mkcall("gopanic", T, init, n->left);
+		goto ret;
+
+	case ORECOVER:
+		n = mkcall("gorecover", n->type, init, nod(OADDR, nodfp, N));
+		goto ret;
+
+	case OLITERAL:
+		n->addable = 1;
+		goto ret;
+
+	case OCLOSUREVAR:
+	case OCFUNC:
+		n->addable = 1;
+		goto ret;
+
+	case ONAME:
+		if(!(n->class & PHEAP) && n->class != PPARAMREF)
+			n->addable = 1;
+		goto ret;
+
+	case OCALLINTER:
+		t = n->left->type;
+		if(n->list && n->list->n->op == OAS)
+			goto ret;
+		walkexpr(&n->left, init);
+		walkexprlist(n->list, init);
+		ll = ascompatte(n->op, n, n->isddd, getinarg(t), n->list, 0, init);
+		n->list = reorder1(ll);
+		goto ret;
+
+	case OCALLFUNC:
+		t = n->left->type;
+		if(n->list && n->list->n->op == OAS)
+			goto ret;
+
+		walkexpr(&n->left, init);
+		walkexprlist(n->list, init);
+
+		ll = ascompatte(n->op, n, n->isddd, getinarg(t), n->list, 0, init);
+		n->list = reorder1(ll);
+		goto ret;
+
+	case OCALLMETH:
+		t = n->left->type;
+		if(n->list && n->list->n->op == OAS)
+			goto ret;
+		walkexpr(&n->left, init);
+		walkexprlist(n->list, init);
+		ll = ascompatte(n->op, n, 0, getthis(t), list1(n->left->left), 0, init);
+		lr = ascompatte(n->op, n, n->isddd, getinarg(t), n->list, 0, init);
+		ll = concat(ll, lr);
+		n->left->left = N;
+		ullmancalc(n->left);
+		n->list = reorder1(ll);
+		goto ret;
+
+	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;
+
+		if(n->right == N || iszero(n->right) && !flag_race)
+			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;
+			n = r;
+			n = applywritebarrier(n, init);
+		}
+
+		goto ret;
+
+	case OAS2:
+		*init = concat(*init, n->ninit);
+		n->ninit = nil;
+		walkexprlistsafe(n->list, init);
+		walkexprlistsafe(n->rlist, init);
+		ll = ascompatee(OAS, n->list, n->rlist, init);
+		ll = reorder3(ll);
+		for(lr = ll; lr != nil; lr = lr->next)
+			lr->n = applywritebarrier(lr->n, init);
+		n = liststmt(ll);
+		goto ret;
+
+	case OAS2FUNC:
+		// a,b,... = fn()
+		*init = concat(*init, n->ninit);
+		n->ninit = nil;
+		r = n->rlist->n;
+		walkexprlistsafe(n->list, init);
+		walkexpr(&r, init);
+
+		ll = ascompatet(n->op, n->list, &r->type, 0, init);
+		for(lr = ll; lr != nil; lr = lr->next)
+			lr->n = applywritebarrier(lr->n, init);
+		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, n->list->next->n->type, 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];
+		*init = concat(*init, n->ninit);
+		n->ninit = nil;
+		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 ../../runtime/hashmap.c:MAXVALUESIZE before changing.
+			switch(simsimtype(t->down)) {
+			case TINT32:
+			case TUINT32:
+				p = "mapaccess2_fast32";
+				break;
+			case TINT64:
+			case TUINT64:
+				p = "mapaccess2_fast64";
+				break;
+			case TSTRING:
+				p = "mapaccess2_faststr";
+				break;
+			}
+		}
+		if(p != nil) {
+			// 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);
+
+		// mapaccess2* returns a typed bool, but due to spec changes,
+		// the boolean result of i.(T) is now untyped so we make it the
+		// same type as the variable on the lhs.
+		if(!isblank(n->list->next->n))
+			r->type->type->down->type = n->list->next->n->type;
+		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);
+		// 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;
+		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:
+		// a,b = i.(T)
+		*init = concat(*init, n->ninit);
+		n->ninit = nil;
+		r = n->rlist->n;
+		walkexprlistsafe(n->list, init);
+		if(isblank(n->list->n) && !isinter(r->type)) {
+			strcpy(buf, "assert");
+			p = buf+strlen(buf);
+			if(isnilinter(r->left->type))
+				*p++ = 'E';
+			else
+				*p++ = 'I';
+			*p++ = '2';
+			*p++ = 'T';
+			*p++ = 'O';
+			*p++ = 'K';
+			*p = '\0';
+			
+			fn = syslook(buf, 1);
+
+			// runtime.assert(E|I)2TOK returns a typed bool, but due
+			// to spec changes, the boolean result of i.(T) is now untyped
+			// so we make it the same type as the variable on the lhs.
+			if(!isblank(n->list->next->n))
+				fn->type->type->down->type->type = n->list->next->n->type;
+			ll = list1(typename(r->type));
+			ll = list(ll, r->left);
+			argtype(fn, r->left->type);
+			n1 = nod(OCALL, fn, N);
+			n1->list = ll;
+			n = nod(OAS, n->list->next->n, n1);
+			typecheck(&n, Etop);
+			walkexpr(&n, init);
+			goto ret;
+		}
+
+		r->op = ODOTTYPE2;
+		walkexpr(&r, init);
+		ll = ascompatet(n->op, n->list, &r->type, 0, init);
+		n = liststmt(concat(list1(r), ll));
+		goto ret;
+
+	case ODOTTYPE:
+	case ODOTTYPE2:
+		// Build name of function: assertI2E2 etc.
+		strcpy(buf, "assert");
+		p = buf+strlen(buf);
+		if(isnilinter(n->left->type))
+			*p++ = 'E';
+		else
+			*p++ = 'I';
+		*p++ = '2';
+		if(isnilinter(n->type))
+			*p++ = 'E';
+		else if(isinter(n->type))
+			*p++ = 'I';
+		else
+			*p++ = 'T';
+		if(n->op == ODOTTYPE2)
+			*p++ = '2';
+		*p = '\0';
+
+		fn = syslook(buf, 1);
+		ll = list1(typename(n->type));
+		ll = list(ll, n->left);
+		argtype(fn, n->left->type);
+		argtype(fn, n->type);
+		n = nod(OCALL, fn, N);
+		n->list = ll;
+		typecheck(&n, Erv | Efnstruct);
+		walkexpr(&n, init);
+		goto ret;
+
+	case OCONVIFACE:
+		walkexpr(&n->left, init);
+
+		// Optimize convT2E as a two-word copy when T is uintptr-shaped.
+		if(isnilinter(n->type) && isdirectiface(n->left->type) && n->left->type->width == widthptr && isint[simsimtype(n->left->type)]) {
+			l = nod(OEFACE, typename(n->left->type), n->left);
+			l->type = n->type;
+			l->typecheck = n->typecheck;
+			n = l;
+			goto ret;
+		}
+
+		// Build name of function: convI2E etc.
+		// Not all names are possible
+		// (e.g., we'll never generate convE2E or convE2I).
+		strcpy(buf, "conv");
+		p = buf+strlen(buf);
+		if(isnilinter(n->left->type))
+			*p++ = 'E';
+		else if(isinter(n->left->type))
+			*p++ = 'I';
+		else
+			*p++ = 'T';
+		*p++ = '2';
+		if(isnilinter(n->type))
+			*p++ = 'E';
+		else
+			*p++ = 'I';
+		*p = '\0';
+
+		fn = syslook(buf, 1);
+		ll = nil;
+		if(!isinter(n->left->type))
+			ll = list(ll, typename(n->left->type));
+		if(!isnilinter(n->type))
+			ll = list(ll, typename(n->type));
+		if(!isinter(n->left->type) && !isnilinter(n->type)){
+			sym = pkglookup(smprint("%-T.%-T", n->left->type, n->type), itabpkg);
+			if(sym->def == N) {
+				l = nod(ONAME, N, N);
+				l->sym = sym;
+				l->type = ptrto(types[TUINT8]);
+				l->addable = 1;
+				l->class = PEXTERN;
+				l->xoffset = 0;
+				sym->def = l;
+				ggloblsym(sym, widthptr, DUPOK|NOPTR);
+			}
+			l = nod(OADDR, sym->def, N);
+			l->addable = 1;
+			ll = list(ll, l);
+
+			if(isdirectiface(n->left->type) && n->left->type->width == widthptr && isint[simsimtype(n->left->type)]) {
+				/* For pointer types, we can make a special form of optimization
+				 *
+				 * These statements are put onto the expression init list:
+				 * 	Itab *tab = atomicloadtype(&cache);
+				 * 	if(tab == nil)
+				 * 		tab = typ2Itab(type, itype, &cache);
+				 *
+				 * The CONVIFACE expression is replaced with this:
+				 * 	OEFACE{tab, ptr};
+				 */
+				l = temp(ptrto(types[TUINT8]));
+
+				n1 = nod(OAS, l, sym->def);
+				typecheck(&n1, Etop);
+				*init = list(*init, n1);
+
+				fn = syslook("typ2Itab", 1);
+				n1 = nod(OCALL, fn, N);
+				n1->list = ll;
+				typecheck(&n1, Erv);
+				walkexpr(&n1, init);
+
+				n2 = nod(OIF, N, N);
+				n2->ntest = nod(OEQ, l, nodnil());
+				n2->nbody = list1(nod(OAS, l, n1));
+				n2->likely = -1;
+				typecheck(&n2, Etop);
+				*init = list(*init, n2);
+
+				l = nod(OEFACE, l, n->left);
+				l->typecheck = n->typecheck; 
+				l->type = n->type;
+				n = l;
+				goto ret;
+			}
+		}
+		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);
+		n = nod(OCALL, fn, N);
+		n->list = ll;
+		typecheck(&n, Erv);
+		walkexpr(&n, init);
+		goto ret;
+
+	case OCONV:
+	case OCONVNOP:
+		if(thechar == '5') {
+			if(isfloat[n->left->type->etype]) {
+				if(n->type->etype == TINT64) {
+					n = mkcall("float64toint64", n->type, init, conv(n->left, types[TFLOAT64]));
+					goto ret;
+				}
+				if(n->type->etype == TUINT64) {
+					n = mkcall("float64touint64", n->type, init, conv(n->left, types[TFLOAT64]));
+					goto ret;
+				}
+			}
+			if(isfloat[n->type->etype]) {
+				if(n->left->type->etype == TINT64) {
+					n = mkcall("int64tofloat64", n->type, init, conv(n->left, types[TINT64]));
+					goto ret;
+				}
+				if(n->left->type->etype == TUINT64) {
+					n = mkcall("uint64tofloat64", n->type, init, conv(n->left, types[TUINT64]));
+					goto ret;
+				}
+			}
+		}
+		walkexpr(&n->left, init);
+		goto ret;
+
+	case OANDNOT:
+		walkexpr(&n->left, init);
+		n->op = OAND;
+		n->right = nod(OCOM, n->right, N);
+		typecheck(&n->right, Erv);
+		walkexpr(&n->right, init);
+		goto ret;
+
+	case OMUL:
+		walkexpr(&n->left, init);
+		walkexpr(&n->right, init);
+		walkmul(&n, init);
+		goto ret;
+
+	case ODIV:
+	case OMOD:
+		walkexpr(&n->left, init);
+		walkexpr(&n->right, init);
+		/*
+		 * rewrite complex div into function call.
+		 */
+		et = n->left->type->etype;
+		if(iscomplex[et] && n->op == ODIV) {
+			t = n->type;
+			n = mkcall("complex128div", types[TCOMPLEX128], init,
+				conv(n->left, types[TCOMPLEX128]),
+				conv(n->right, types[TCOMPLEX128]));
+			n = conv(n, t);
+			goto ret;
+		}
+		// Nothing to do for float divisions.
+		if(isfloat[et])
+			goto ret;
+
+		// Try rewriting as shifts or magic multiplies.
+		walkdiv(&n, init);
+
+		/*
+		 * rewrite 64-bit div and mod into function calls
+		 * on 32-bit architectures.
+		 */
+		switch(n->op) {
+		case OMOD:
+		case ODIV:
+			if(widthreg >= 8 || (et != TUINT64 && et != TINT64))
+				goto ret;
+			if(et == TINT64)
+				strcpy(namebuf, "int64");
+			else
+				strcpy(namebuf, "uint64");
+			if(n->op == ODIV)
+				strcat(namebuf, "div");
+			else
+				strcat(namebuf, "mod");
+			n = mkcall(namebuf, n->type, init,
+				conv(n->left, types[et]), conv(n->right, types[et]));
+			break;
+		default:
+			break;
+		}
+		goto ret;
+
+	case OINDEX:
+		walkexpr(&n->left, init);
+		// save the original node for bounds checking elision.
+		// If it was a ODIV/OMOD walk might rewrite it.
+		r = n->right;
+		walkexpr(&n->right, init);
+
+		// if range of type cannot exceed static array bound,
+		// disable bounds check.
+		if(n->bounded)
+			goto ret;
+		t = n->left->type;
+		if(t != T && isptr[t->etype])
+			t = t->type;
+		if(isfixedarray(t)) {
+			n->bounded = bounded(r, t->bound);
+			if(debug['m'] && n->bounded && !isconst(n->right, CTINT))
+				warn("index bounds check elided");
+			if(smallintconst(n->right) && !n->bounded)
+				yyerror("index out of bounds");
+		} else if(isconst(n->left, CTSTR)) {
+			n->bounded = bounded(r, n->left->val.u.sval->len);
+			if(debug['m'] && n->bounded && !isconst(n->right, CTINT))
+				warn("index bounds check elided");
+			if(smallintconst(n->right)) {
+				if(!n->bounded)
+					yyerror("index out of bounds");
+				else {
+					// replace "abc"[1] with 'b'.
+					// delayed until now because "abc"[1] is not
+					// an ideal constant.
+					v = mpgetfix(n->right->val.u.xval);
+					nodconst(n, n->type, n->left->val.u.sval->s[v]);
+					n->typecheck = 1;
+				}
+			}
+		}
+
+		if(isconst(n->right, CTINT))
+		if(mpcmpfixfix(n->right->val.u.xval, &mpzero) < 0 ||
+		   mpcmpfixfix(n->right->val.u.xval, maxintval[TINT]) > 0)
+			yyerror("index out of bounds");
+		goto ret;
+
+	case OINDEXMAP:
+		if(n->etype == 1)
+			goto ret;
+		walkexpr(&n->left, init);
+		walkexpr(&n->right, init);
+
+		t = n->left->type;
+		p = nil;
+		if(t->type->width <= 128) {  // Check ../../runtime/hashmap.c:MAXVALUESIZE before changing.
+			switch(simsimtype(t->down)) {
+			case TINT32:
+			case TUINT32:
+				p = "mapaccess1_fast32";
+				break;
+			case TINT64:
+			case TUINT64:
+				p = "mapaccess1_fast64";
+				break;
+			case TSTRING:
+				p = "mapaccess1_faststr";
+				break;
+			}
+		}
+		if(p != nil) {
+			// fast versions take key by value
+			key = n->right;
+		} else {
+			// 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:
+		fatal("walkexpr ORECV"); // should see inside OAS only
+
+	case OSLICE:
+		if(n->right != N && n->right->left == N && n->right->right == N) { // noop
+			walkexpr(&n->left, init);
+			n = n->left;
+			goto ret;
+		}
+		// fallthrough
+	case OSLICEARR:
+	case OSLICESTR:
+		if(n->right == N) // already processed
+			goto ret;
+
+		walkexpr(&n->left, init);
+		// cgen_slice can't handle string literals as source
+		// TODO the OINDEX case is a bug elsewhere that needs to be traced.  it causes a crash on ([2][]int{ ... })[1][lo:hi]
+		if((n->op == OSLICESTR && n->left->op == OLITERAL) || (n->left->op == OINDEX))
+			n->left = copyexpr(n->left, n->left->type, init);
+		else
+			n->left = safeexpr(n->left, init);
+		walkexpr(&n->right->left, init);
+		n->right->left = safeexpr(n->right->left, init);
+		walkexpr(&n->right->right, init);
+		n->right->right = safeexpr(n->right->right, init);
+		n = sliceany(n, init);  // chops n->right, sets n->list
+		goto ret;
+	
+	case OSLICE3:
+	case OSLICE3ARR:
+		if(n->right == N) // already processed
+			goto ret;
+
+		walkexpr(&n->left, init);
+		// TODO the OINDEX case is a bug elsewhere that needs to be traced.  it causes a crash on ([2][]int{ ... })[1][lo:hi]
+		// TODO the comment on the previous line was copied from case OSLICE. it might not even be true.
+		if(n->left->op == OINDEX)
+			n->left = copyexpr(n->left, n->left->type, init);
+		else
+			n->left = safeexpr(n->left, init);
+		walkexpr(&n->right->left, init);
+		n->right->left = safeexpr(n->right->left, init);
+		walkexpr(&n->right->right->left, init);
+		n->right->right->left = safeexpr(n->right->right->left, init);
+		walkexpr(&n->right->right->right, init);
+		n->right->right->right = safeexpr(n->right->right->right, init);
+		n = sliceany(n, init);  // chops n->right, sets n->list
+		goto ret;
+
+	case OADDR:
+		walkexpr(&n->left, init);
+		goto ret;
+
+	case ONEW:
+		if(n->esc == EscNone && n->type->type->width < (1<<16)) {
+			r = temp(n->type->type);
+			r = nod(OAS, r, N);  // zero temp
+			typecheck(&r, Etop);
+			*init = list(*init, r);
+			r = nod(OADDR, r->left, N);
+			typecheck(&r, Erv);
+			n = r;
+		} else {
+			n = callnew(n->type->type);
+		}
+		goto ret;
+
+	case OCMPSTR:
+		// If one argument to the comparison is an empty string,
+		// comparing the lengths instead will yield the same result
+		// without the function call.
+		if((isconst(n->left, CTSTR) && n->left->val.u.sval->len == 0) ||
+		   (isconst(n->right, CTSTR) && n->right->val.u.sval->len == 0)) {
+			r = nod(n->etype, nod(OLEN, n->left, N), nod(OLEN, n->right, N));
+			typecheck(&r, Erv);
+			walkexpr(&r, init);
+			r->type = n->type;
+			n = r;
+			goto ret;
+		}
+
+		// s + "badgerbadgerbadger" == "badgerbadgerbadger"
+		if((n->etype == OEQ || n->etype == ONE) &&
+		   isconst(n->right, CTSTR) &&
+		   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;
+			n = r;
+			goto ret;
+		}
+
+		if(n->etype == OEQ || n->etype == ONE) {
+			// prepare for rewrite below
+			n->left = cheapexpr(n->left, init);
+			n->right = cheapexpr(n->right, init);
+
+			r = mkcall("eqstring", types[TBOOL], init,
+				conv(n->left, types[TSTRING]),
+				conv(n->right, types[TSTRING]));
+
+			// quick check of len before full compare for == or !=
+			if(n->etype == OEQ) {
+				// len(left) == len(right) && eqstring(left, right)
+				r = nod(OANDAND, nod(OEQ, nod(OLEN, n->left, N), nod(OLEN, n->right, N)), r);
+			} else {
+				// len(left) != len(right) || !eqstring(left, right)
+				r = nod(ONOT, r, N);
+				r = nod(OOROR, nod(ONE, nod(OLEN, n->left, N), nod(OLEN, n->right, N)), r);
+			}
+			typecheck(&r, Erv);
+			walkexpr(&r, nil);
+		} else {
+			// sys_cmpstring(s1, s2) :: 0
+			r = mkcall("cmpstring", types[TINT], init,
+				conv(n->left, types[TSTRING]),
+				conv(n->right, types[TSTRING]));
+			r = nod(n->etype, r, nodintconst(0));
+		}
+
+		typecheck(&r, Erv);
+		if(n->type->etype != TBOOL) fatal("cmp %T", n->type);
+		r->type = n->type;
+		n = r;
+		goto ret;
+
+	case OADDSTR:
+		n = addstr(n, init);
+		goto ret;
+	
+	case OAPPEND:
+		if(n->isddd)
+			n = appendslice(n, init); // also works for append(slice, string).
+		else
+			n = append(n, init);
+		goto ret;
+
+	case OCOPY:
+		n = copyany(n, init, flag_race);
+		goto ret;
+
+	case OCLOSE:
+		// cannot use chanfn - closechan takes any, not chan any
+		fn = syslook("closechan", 1);
+		argtype(fn, n->left->type);
+		n = mkcall1(fn, T, init, n->left);
+		goto ret;
+
+	case OMAKECHAN:
+		n = mkcall1(chanfn("makechan", 1, n->type), n->type, init,
+			typename(n->type),
+			conv(n->left, types[TINT64]));
+		goto ret;
+
+	case OMAKEMAP:
+		t = n->type;
+
+		fn = syslook("makemap", 1);
+		argtype(fn, t->down);	// any-1
+		argtype(fn, t->type);	// any-2
+
+		n = mkcall1(fn, n->type, init,
+			typename(n->type),
+			conv(n->left, types[TINT64]));
+		goto ret;
+
+	case OMAKESLICE:
+		l = n->left;
+		r = n->right;
+		if(r == nil)
+			l = r = safeexpr(l, init);
+		t = n->type;
+		if(n->esc == EscNone
+			&& smallintconst(l) && smallintconst(r)
+			&& (t->type->width == 0 || mpgetfix(r->val.u.xval) < (1ULL<<16) / t->type->width)) {
+			// var arr [r]T
+			// n = arr[:l]
+			t = aindex(r, t->type); // [r]T
+			var = temp(t);
+			a = nod(OAS, var, N); // zero temp
+			typecheck(&a, Etop);
+			*init = list(*init, a);
+			r = nod(OSLICE, var, nod(OKEY, N, l)); // arr[:l]
+			r = conv(r, n->type); // in case n->type is named.
+			typecheck(&r, Erv);
+			walkexpr(&r, init);
+			n = r;
+		} else {
+			// makeslice(t *Type, nel int64, max int64) (ary []any)
+			fn = syslook("makeslice", 1);
+			argtype(fn, t->type);			// any-1
+			n = mkcall1(fn, n->type, init,
+				typename(n->type),
+				conv(l, types[TINT64]),
+				conv(r, types[TINT64]));
+		}
+		goto ret;
+
+	case ORUNESTR:
+		// sys_intstring(v)
+		n = mkcall("intstring", n->type, init,
+			conv(n->left, types[TINT64]));
+		goto ret;
+
+	case OARRAYBYTESTR:
+		// slicebytetostring([]byte) string;
+		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);
+		goto ret;
+
+	case OSTRARRAYBYTE:
+		// stringtoslicebyte(string) []byte;
+		n = mkcall("stringtoslicebyte", n->type, init, conv(n->left, types[TSTRING]));
+		goto ret;
+
+	case OSTRARRAYRUNE:
+		// stringtoslicerune(string) []rune
+		n = mkcall("stringtoslicerune", n->type, init, n->left);
+		goto ret;
+
+	case OCMPIFACE:
+		// ifaceeq(i1 any-1, i2 any-2) (ret bool);
+		if(!eqtype(n->left->type, n->right->type))
+			fatal("ifaceeq %O %T %T", n->op, n->left->type, n->right->type);
+		if(isnilinter(n->left->type))
+			fn = syslook("efaceeq", 1);
+		else
+			fn = syslook("ifaceeq", 1);
+
+		n->right = cheapexpr(n->right, init);
+		n->left = cheapexpr(n->left, init);
+		argtype(fn, n->right->type);
+		argtype(fn, n->left->type);
+		r = mkcall1(fn, n->type, init, n->left, n->right);
+		if(n->etype == ONE)
+			r = nod(ONOT, r, N);
+		
+		// check itable/type before full compare.
+		if(n->etype == OEQ)
+			r = nod(OANDAND, nod(OEQ, nod(OITAB, n->left, N), nod(OITAB, n->right, N)), r);
+		else
+			r = nod(OOROR, nod(ONE, nod(OITAB, n->left, N), nod(OITAB, n->right, N)), r);
+		typecheck(&r, Erv);
+		walkexpr(&r, init);
+		r->type = n->type;
+		n = r;
+		goto ret;
+
+	case OARRAYLIT:
+	case OMAPLIT:
+	case OSTRUCTLIT:
+	case OPTRLIT:
+		var = temp(n->type);
+		anylit(0, n, var, init);
+		n = var;
+		goto ret;
+
+	case OSEND:
+		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:
+		n = walkclosure(n, init);
+		goto ret;
+	
+	case OCALLPART:
+		n = walkpartialcall(n, init);
+		goto ret;
+	}
+	fatal("missing switch %O", n->op);
+
+ret:
+	// Expressions that are constant at run time but not
+	// considered const by the language spec are not turned into
+	// constants until walk. For example, if n is y%1 == 0, the
+	// walk of y%1 may have replaced it by 0.
+	// Check whether n with its updated args is itself now a constant.
+	t = n->type;
+	evconst(n);
+	n->type = t;
+	if(n->op == OLITERAL)
+		typecheck(&n, Erv);
+
+	ullmancalc(n);
+
+	if(debug['w'] && n != N)
+		dump("walk", n);
+
+	lineno = lno;
+	*np = n;
+}
+
+static Node*
+ascompatee1(int op, Node *l, Node *r, NodeList **init)
+{
+	Node *n;
+	USED(op);
+	
+	// convas will turn map assigns into function calls,
+	// making it impossible for reorder3 to work.
+	n = nod(OAS, l, r);
+	if(l->op == OINDEXMAP)
+		return n;
+
+	return convas(n, init);
+}
+
+static NodeList*
+ascompatee(int op, NodeList *nl, NodeList *nr, NodeList **init)
+{
+	NodeList *ll, *lr, *nn;
+
+	/*
+	 * check assign expression list to
+	 * a expression list. called in
+	 *	expr-list = expr-list
+	 */
+
+	// ensure order of evaluation for function calls
+	for(ll=nl; ll; ll=ll->next)
+		ll->n = safeexpr(ll->n, init);
+	for(lr=nr; lr; lr=lr->next)
+		lr->n = safeexpr(lr->n, init);
+
+	nn = nil;
+	for(ll=nl, lr=nr; ll && lr; ll=ll->next, lr=lr->next) {
+		// Do not generate 'x = x' during return. See issue 4014.
+		if(op == ORETURN && ll->n == lr->n)
+			continue;
+		nn = list(nn, ascompatee1(op, ll->n, lr->n, init));
+	}
+
+	// cannot happen: caller checked that lists had same length
+	if(ll || lr)
+		yyerror("error in shape across %+H %O %+H / %d %d [%s]", nl, op, nr, count(nl), count(nr), curfn->nname->sym->name);
+	return nn;
+}
+
+/*
+ * l is an lv and rt is the type of an rv
+ * return 1 if this implies a function call
+ * evaluating the lv or a function call
+ * in the conversion of the types
+ */
+static int
+fncall(Node *l, Type *rt)
+{
+	Node r;
+
+	if(l->ullman >= UINF || l->op == OINDEXMAP)
+		return 1;
+	memset(&r, 0, sizeof r);
+	if(needwritebarrier(l, &r))
+		return 1;
+	if(eqtype(l->type, rt))
+		return 0;
+	return 1;
+}
+
+static NodeList*
+ascompatet(int op, NodeList *nl, Type **nr, int fp, NodeList **init)
+{
+	Node *l, *tmp, *a;
+	NodeList *ll;
+	Type *r;
+	Iter saver;
+	int ucount;
+	NodeList *nn, *mm;
+
+	USED(op);
+
+	/*
+	 * check assign type list to
+	 * a expression list. called in
+	 *	expr-list = func()
+	 */
+	r = structfirst(&saver, nr);
+	nn = nil;
+	mm = nil;
+	ucount = 0;
+	for(ll=nl; ll; ll=ll->next) {
+		if(r == T)
+			break;
+		l = ll->n;
+		if(isblank(l)) {
+			r = structnext(&saver);
+			continue;
+		}
+
+		// any lv that causes a fn call must be
+		// deferred until all the return arguments
+		// have been pulled from the output arguments
+		if(fncall(l, r->type)) {
+			tmp = temp(r->type);
+			typecheck(&tmp, Erv);
+			a = nod(OAS, l, tmp);
+			a = convas(a, init);
+			mm = list(mm, a);
+			l = tmp;
+		}
+
+		a = nod(OAS, l, nodarg(r, fp));
+		a = convas(a, init);
+		ullmancalc(a);
+		if(a->ullman >= UINF) {
+			dump("ascompatet ucount", a);
+			ucount++;
+		}
+		nn = list(nn, a);
+		r = structnext(&saver);
+	}
+
+	if(ll != nil || r != T)
+		yyerror("ascompatet: assignment count mismatch: %d = %d",
+			count(nl), structcount(*nr));
+
+	if(ucount)
+		fatal("ascompatet: too many function calls evaluating parameters");
+	return concat(nn, mm);
+}
+
+ /*
+ * 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, 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;
+
+	if(count(lr0) == 0) {
+		n = nodnil();
+		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);
+		if(n->type == T)
+			fatal("mkdotargslice: typecheck failed");
+		walkexpr(&n, init);
+	}
+
+	a = nod(OAS, nodarg(l, fp), n);
+	nn = list(nn, convas(a, init));
+	return nn;
+}
+
+/*
+ * helpers for shape errors
+ */
+static char*
+dumptypes(Type **nl, char *what)
+{
+	int first;
+	Type *l;
+	Iter savel;
+	Fmt fmt;
+
+	fmtstrinit(&fmt);
+	fmtprint(&fmt, "\t");
+	first = 1;
+	for(l = structfirst(&savel, nl); l != T; l = structnext(&savel)) {
+		if(first)
+			first = 0;
+		else
+			fmtprint(&fmt, ", ");
+		fmtprint(&fmt, "%T", l);
+	}
+	if(first)
+		fmtprint(&fmt, "[no arguments %s]", what);
+	return fmtstrflush(&fmt);
+}
+
+static char*
+dumpnodetypes(NodeList *l, char *what)
+{
+	int first;
+	Node *r;
+	Fmt fmt;
+
+	fmtstrinit(&fmt);
+	fmtprint(&fmt, "\t");
+	first = 1;
+	for(; l; l=l->next) {
+		r = l->n;
+		if(first)
+			first = 0;
+		else
+			fmtprint(&fmt, ", ");
+		fmtprint(&fmt, "%T", r->type);
+	}
+	if(first)
+		fmtprint(&fmt, "[no arguments %s]", what);
+	return fmtstrflush(&fmt);
+}
+
+/*
+ * check assign expression list to
+ * a type list. called in
+ *	return expr-list
+ *	func(expr-list)
+ */
+static NodeList*
+ascompatte(int op, Node *call, int isddd, Type **nl, NodeList *lr, int fp, NodeList **init)
+{
+	Type *l, *ll;
+	Node *r, *a;
+	NodeList *nn, *lr0, *alist;
+	Iter savel;
+	char *l1, *l2;
+
+	lr0 = lr;
+	l = structfirst(&savel, nl);
+	r = N;
+	if(lr)
+		r = lr->n;
+	nn = nil;
+
+	// f(g()) where g has multiple return values
+	if(r != N && lr->next == nil && r->type->etype == TSTRUCT && r->type->funarg) {
+		// optimization - can do block copy
+		if(eqtypenoname(r->type, *nl)) {
+			a = nodarg(*nl, fp);
+			r = nod(OCONVNOP, r, N);
+			r->type = a->type;
+			nn = list1(convas(nod(OAS, a, r), init));
+			goto ret;
+		}
+
+		// conversions involved.
+		// copy into temporaries.
+		alist = nil;
+		for(l=structfirst(&savel, &r->type); l; l=structnext(&savel)) {
+			a = temp(l->type);
+			alist = list(alist, a);
+		}
+		a = nod(OAS2, N, N);
+		a->list = alist;
+		a->rlist = lr;
+		typecheck(&a, Etop);
+		walkstmt(&a);
+		*init = list(*init, a);
+		lr = alist;
+		r = lr->n;
+		l = structfirst(&savel, nl);
+	}
+
+loop:
+	if(l != T && l->isddd) {
+		// the ddd parameter must be last
+		ll = structnext(&savel);
+		if(ll != T)
+			yyerror("... must be last argument");
+
+		// special case --
+		// only if we are assigning a single ddd
+		// argument to a ddd parameter then it is
+		// passed thru unencapsulated
+		if(r != N && lr->next == nil && isddd && eqtype(l->type, r->type)) {
+			a = nod(OAS, nodarg(l, fp), r);
+			a = convas(a, init);
+			nn = list(nn, a);
+			goto ret;
+		}
+
+		// normal case -- make a slice of all
+		// remaining arguments and pass it to
+		// the ddd parameter.
+		nn = mkdotargslice(lr, nn, l, fp, init, call->right);
+		goto ret;
+	}
+
+	if(l == T || r == N) {
+		if(l != T || r != N) {
+			l1 = dumptypes(nl, "expected");
+			l2 = dumpnodetypes(lr0, "given");
+			if(l != T)
+				yyerror("not enough arguments to %O\n%s\n%s", op, l1, l2);
+			else
+				yyerror("too many arguments to %O\n%s\n%s", op, l1, l2);
+		}
+		goto ret;
+	}
+
+	a = nod(OAS, nodarg(l, fp), r);
+	a = convas(a, init);
+	nn = list(nn, a);
+
+	l = structnext(&savel);
+	r = N;
+	lr = lr->next;
+	if(lr != nil)
+		r = lr->n;
+	goto loop;
+
+ret:
+	for(lr=nn; lr; lr=lr->next)
+		lr->n->typecheck = 1;
+	return nn;
+}
+
+// generate code for print
+static Node*
+walkprint(Node *nn, NodeList **init)
+{
+	Node *r;
+	Node *n;
+	NodeList *l, *all;
+	Node *on;
+	Type *t;
+	int notfirst, et, op;
+	NodeList *calls;
+
+	on = nil;
+	op = nn->op;
+	all = nn->list;
+	calls = nil;
+	notfirst = 0;
+
+	for(l=all; l; l=l->next) {
+		if(notfirst) {
+			calls = list(calls, mkcall("printsp", T, init));
+		}
+		notfirst = op == OPRINTN;
+
+		n = l->n;
+		if(n->op == OLITERAL) {
+			switch(n->val.ctype) {
+			case CTRUNE:
+				defaultlit(&n, runetype);
+				break;
+			case CTINT:
+				defaultlit(&n, types[TINT64]);
+				break;
+			case CTFLT:
+				defaultlit(&n, types[TFLOAT64]);
+				break;
+			}
+		}
+		if(n->op != OLITERAL && n->type && n->type->etype == TIDEAL)
+			defaultlit(&n, types[TINT64]);
+		defaultlit(&n, nil);
+		l->n = n;
+		if(n->type == T || n->type->etype == TFORW)
+			continue;
+
+		t = n->type;
+		et = n->type->etype;
+		if(isinter(n->type)) {
+			if(isnilinter(n->type))
+				on = syslook("printeface", 1);
+			else
+				on = syslook("printiface", 1);
+			argtype(on, n->type);		// any-1
+		} else if(isptr[et] || et == TCHAN || et == TMAP || et == TFUNC || et == TUNSAFEPTR) {
+			on = syslook("printpointer", 1);
+			argtype(on, n->type);	// any-1
+		} else if(isslice(n->type)) {
+			on = syslook("printslice", 1);
+			argtype(on, n->type);	// any-1
+		} else if(isint[et]) {
+			if(et == TUINT64) {
+				if((t->sym->pkg == runtimepkg || compiling_runtime) && strcmp(t->sym->name, "hex") == 0)
+					on = syslook("printhex", 0);
+				else
+					on = syslook("printuint", 0);
+			} else
+				on = syslook("printint", 0);
+		} else if(isfloat[et]) {
+			on = syslook("printfloat", 0);
+		} else if(iscomplex[et]) {
+			on = syslook("printcomplex", 0);
+		} else if(et == TBOOL) {
+			on = syslook("printbool", 0);
+		} else if(et == TSTRING) {
+			on = syslook("printstring", 0);
+		} else {
+			badtype(OPRINT, n->type, T);
+			continue;
+		}
+
+		t = *getinarg(on->type);
+		if(t != nil)
+			t = t->type;
+		if(t != nil)
+			t = t->type;
+
+		if(!eqtype(t, n->type)) {
+			n = nod(OCONV, n, N);
+			n->type = t;
+		}
+
+		r = nod(OCALL, on, N);
+		r->list = list1(n);
+		calls = list(calls, r);
+	}
+
+	if(op == OPRINTN)
+		calls = list(calls, mkcall("printnl", T, nil));
+	typechecklist(calls, Etop);
+	walkexprlist(calls, init);
+
+	r = nod(OEMPTY, N, N);
+	typecheck(&r, Etop);
+	walkexpr(&r, init);
+	r->ninit = calls;
+	return r;
+}
+
+Node*
+callnew(Type *t)
+{
+	Node *fn;
+
+	dowidth(t);
+	fn = syslook("newobject", 1);
+	argtype(fn, t);
+	return mkcall1(fn, ptrto(t), nil, typename(t));
+}
+
+static int
+isstack(Node *n)
+{
+	while(n->op == ODOT || n->op == OPAREN || n->op == OCONVNOP || n->op == OINDEX && isfixedarray(n->left->type))
+		n = n->left;
+	
+	switch(n->op) {
+	case OINDREG:
+		// OINDREG only ends up in walk if it's indirect of SP.
+		return 1;
+
+	case ONAME:
+		switch(n->class) {
+		case PAUTO:
+		case PPARAM:
+		case PPARAMOUT:
+			return 1;
+		}
+		break;
+	}
+	
+	return 0;
+}
+
+static int
+isglobal(Node *n)
+{
+	while(n->op == ODOT || n->op == OPAREN || n->op == OCONVNOP || n->op == OINDEX && isfixedarray(n->left->type))
+		n = n->left;
+	
+	switch(n->op) {
+	case ONAME:
+		switch(n->class) {
+		case PEXTERN:
+			return 1;
+		}
+		break;
+	}
+	
+	return 0;
+}
+
+// Do we need a write barrier for the assignment l = r?
+int
+needwritebarrier(Node *l, Node *r)
+{
+	if(!use_writebarrier)
+		return 0;
+
+	if(l == N || isblank(l))
+		return 0;
+
+	// No write barrier for write of non-pointers.
+	dowidth(l->type);
+	if(!haspointers(l->type))
+		return 0;
+
+	// No write barrier for write to stack.
+	if(isstack(l))
+		return 0;
+
+	// No write barrier for implicit or explicit zeroing.
+	if(r == N || iszero(r))
+		return 0;
+
+	// No write barrier for initialization to constant.
+	if(r->op == OLITERAL)
+		return 0;
+
+	// No write barrier for storing static (read-only) data.
+	if(r->op == ONAME && strncmp(r->sym->name, "statictmp_", 10) == 0)
+		return 0;
+
+	// No write barrier for storing address of stack values,
+	// which are guaranteed only to be written to the stack.
+	if(r->op == OADDR && isstack(r->left))
+		return 0;
+
+	// No write barrier for storing address of global, which
+	// is live no matter what.
+	if(r->op == OADDR && isglobal(r->left))
+		return 0;
+
+	// No write barrier for reslice: x = x[0:y] or x = append(x, ...).
+	// Both are compiled to modify x directly.
+	// In the case of append, a write barrier may still be needed
+	// if the underlying array grows, but the append code can
+	// generate the write barrier directly in that case.
+	// (It does not yet, but the cost of the write barrier will be
+	// small compared to the cost of the allocation.)
+	if(r->reslice) {
+		switch(r->op) {
+		case OSLICE:
+		case OSLICE3:
+		case OSLICESTR:
+		case OAPPEND:
+			break;
+		default:
+			dump("bad reslice-l", l);
+			dump("bad reslice-r", r);
+			break;
+		}
+		return 0;
+	}
+
+	// Otherwise, be conservative and use write barrier.
+	return 1;
+}
+
+// TODO(rsc): Perhaps componentgen should run before this.
+static Node*
+applywritebarrier(Node *n, NodeList **init)
+{
+	Node *l, *r;
+	Type *t;
+
+	if(n->left && n->right && needwritebarrier(n->left, n->right)) {
+		t = n->left->type;
+		l = nod(OADDR, n->left, N);
+		l->etype = 1; // addr does not escape
+		if(t->width == widthptr) {
+			n = mkcall1(writebarrierfn("writebarrierptr", t, n->right->type), T, init,
+				l, n->right);
+		} else if(t->etype == TSTRING) {
+			n = mkcall1(writebarrierfn("writebarrierstring", t, n->right->type), T, init,
+				l, n->right);
+		} else if(isslice(t)) {
+			n = mkcall1(writebarrierfn("writebarrierslice", t, n->right->type), T, init,
+				l, n->right);
+		} else if(isinter(t)) {
+			n = mkcall1(writebarrierfn("writebarrieriface", t, n->right->type), T, init,
+				l, n->right);
+		} else if(t->width == 2*widthptr) {
+			n = mkcall1(writebarrierfn("writebarrierfat2", t, n->right->type), T, init,
+				l, nodnil(), n->right);
+		} else if(t->width == 3*widthptr) {
+			n = mkcall1(writebarrierfn("writebarrierfat3", t, n->right->type), T, init,
+				l, nodnil(), n->right);
+		} else if(t->width == 4*widthptr) {
+			n = mkcall1(writebarrierfn("writebarrierfat4", t, n->right->type), T, init,
+				l, nodnil(), n->right);
+		} else {
+			r = n->right;
+			while(r->op == OCONVNOP)
+				r = r->left;
+			r = nod(OADDR, r, N);
+			r->etype = 1; // addr does not escape
+			//warnl(n->lineno, "writebarrierfat %T %N", t, r);
+			n = mkcall1(writebarrierfn("writebarrierfat", t, r->left->type), T, init,
+				typename(t), l, r);
+		}
+	}
+	return n;
+}
+
+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);
+
+	n->typecheck = 1;
+
+	if(n->left == N || n->right == N)
+		goto out;
+
+	lt = n->left->type;
+	rt = n->right->type;
+	if(lt == T || rt == T)
+		goto out;
+
+	if(isblank(n->left)) {
+		defaultlit(&n->right, T);
+		goto out;
+	}
+
+	if(n->left->op == OINDEXMAP) {
+		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;
+	}
+
+	if(!eqtype(lt, rt)) {
+		n->right = assignconv(n->right, lt, "assignment");
+		walkexpr(&n->right, init);
+	}
+
+out:
+	ullmancalc(n);
+	return n;
+}
+
+/*
+ * from ascompat[te]
+ * evaluating actual function arguments.
+ *	f(a,b)
+ * if there is exactly one function expr,
+ * then it is done first. otherwise must
+ * make temp variables
+ */
+static NodeList*
+reorder1(NodeList *all)
+{
+	Node *f, *a, *n;
+	NodeList *l, *r, *g;
+	int c, d, t;
+
+	c = 0;	// function calls
+	t = 0;	// total parameters
+
+	for(l=all; l; l=l->next) {
+		n = l->n;
+		t++;
+		ullmancalc(n);
+		if(n->ullman >= UINF)
+			c++;
+	}
+	if(c == 0 || t == 1)
+		return all;
+
+	g = nil;	// fncalls assigned to tempnames
+	f = N;	// last fncall assigned to stack
+	r = nil;	// non fncalls and tempnames assigned to stack
+	d = 0;
+	for(l=all; l; l=l->next) {
+		n = l->n;
+		if(n->ullman < UINF) {
+			r = list(r, n);
+			continue;
+		}
+		d++;
+		if(d == c) {
+			f = n;
+			continue;
+		}
+
+		// make assignment of fncall to tempname
+		a = temp(n->right->type);
+		a = nod(OAS, a, n->right);
+		g = list(g, a);
+
+		// put normal arg assignment on list
+		// with fncall replaced by tempname
+		n->right = a->left;
+		r = list(r, n);
+	}
+
+	if(f != N)
+		g = list(g, f);
+	return concat(g, r);
+}
+
+static void reorder3save(Node**, NodeList*, NodeList*, NodeList**);
+static int aliased(Node*, NodeList*, NodeList*);
+
+/*
+ * from ascompat[ee]
+ *	a,b = c,d
+ * simultaneous assignment. there cannot
+ * be later use of an earlier lvalue.
+ *
+ * function calls have been removed.
+ */
+static NodeList*
+reorder3(NodeList *all)
+{
+	NodeList *list, *early, *mapinit;
+	Node *l;
+
+	// If a needed expression may be affected by an
+	// earlier assignment, make an early copy of that
+	// expression and use the copy instead.
+	early = nil;
+	mapinit = nil;
+	for(list=all; list; list=list->next) {
+		l = list->n->left;
+
+		// Save subexpressions needed on left side.
+		// Drill through non-dereferences.
+		for(;;) {
+			if(l->op == ODOT || l->op == OPAREN) {
+				l = l->left;
+				continue;
+			}
+			if(l->op == OINDEX && isfixedarray(l->left->type)) {
+				reorder3save(&l->right, all, list, &early);
+				l = l->left;
+				continue;
+			}
+			break;
+		}
+		switch(l->op) {
+		default:
+			fatal("reorder3 unexpected lvalue %#O", l->op);
+		case ONAME:
+			break;
+		case OINDEX:
+		case OINDEXMAP:
+			reorder3save(&l->left, all, list, &early);
+			reorder3save(&l->right, all, list, &early);
+			if(l->op == OINDEXMAP)
+				list->n = convas(list->n, &mapinit);
+			break;
+		case OIND:
+		case ODOTPTR:
+			reorder3save(&l->left, all, list, &early);
+		}
+
+		// Save expression on right side.
+		reorder3save(&list->n->right, all, list, &early);
+	}
+
+	early = concat(mapinit, early);
+	return concat(early, all);
+}
+
+static int vmatch2(Node*, Node*);
+static int varexpr(Node*);
+
+/*
+ * if the evaluation of *np would be affected by the 
+ * assignments in all up to but not including stop,
+ * copy into a temporary during *early and
+ * replace *np with that temp.
+ */
+static void
+reorder3save(Node **np, NodeList *all, NodeList *stop, NodeList **early)
+{
+	Node *n, *q;
+
+	n = *np;
+	if(!aliased(n, all, stop))
+		return;
+	
+	q = temp(n->type);
+	q = nod(OAS, q, n);
+	typecheck(&q, Etop);
+	*early = list(*early, q);
+	*np = q->left;
+}
+
+/*
+ * what's the outer value that a write to n affects?
+ * outer value means containing struct or array.
+ */
+Node*
+outervalue(Node *n)
+{	
+	for(;;) {
+		if(n->op == ODOT || n->op == OPAREN) {
+			n = n->left;
+			continue;
+		}
+		if(n->op == OINDEX && isfixedarray(n->left->type)) {
+			n = n->left;
+			continue;
+		}
+		break;
+	}
+	return n;
+}
+
+/*
+ * Is it possible that the computation of n might be
+ * affected by writes in as up to but not including stop?
+ */
+static int
+aliased(Node *n, NodeList *all, NodeList *stop)
+{
+	int memwrite, varwrite;
+	Node *a;
+	NodeList *l;
+
+	if(n == N)
+		return 0;
+
+	// Look for obvious aliasing: a variable being assigned
+	// during the all list and appearing in n.
+	// Also record whether there are any writes to main memory.
+	// Also record whether there are any writes to variables
+	// whose addresses have been taken.
+	memwrite = 0;
+	varwrite = 0;
+	for(l=all; l!=stop; l=l->next) {
+		a = outervalue(l->n->left);
+		if(a->op != ONAME) {
+			memwrite = 1;
+			continue;
+		}
+		switch(n->class) {
+		default:
+			varwrite = 1;
+			continue;
+		case PAUTO:
+		case PPARAM:
+		case PPARAMOUT:
+			if(n->addrtaken) {
+				varwrite = 1;
+				continue;
+			}
+			if(vmatch2(a, n)) {
+				// Direct hit.
+				return 1;
+			}
+		}
+	}
+
+	// The variables being written do not appear in n.
+	// However, n might refer to computed addresses
+	// that are being written.
+	
+	// If no computed addresses are affected by the writes, no aliasing.
+	if(!memwrite && !varwrite)
+		return 0;
+
+	// If n does not refer to computed addresses
+	// (that is, if n only refers to variables whose addresses
+	// have not been taken), no aliasing.
+	if(varexpr(n))
+		return 0;
+
+	// Otherwise, both the writes and n refer to computed memory addresses.
+	// Assume that they might conflict.
+	return 1;
+}
+
+/*
+ * does the evaluation of n only refer to variables
+ * whose addresses have not been taken?
+ * (and no other memory)
+ */
+static int
+varexpr(Node *n)
+{
+	if(n == N)
+		return 1;
+
+	switch(n->op) {
+	case OLITERAL:	
+		return 1;
+	case ONAME:
+		switch(n->class) {
+		case PAUTO:
+		case PPARAM:
+		case PPARAMOUT:
+			if(!n->addrtaken)
+				return 1;
+		}
+		return 0;
+
+	case OADD:
+	case OSUB:
+	case OOR:
+	case OXOR:
+	case OMUL:
+	case ODIV:
+	case OMOD:
+	case OLSH:
+	case ORSH:
+	case OAND:
+	case OANDNOT:
+	case OPLUS:
+	case OMINUS:
+	case OCOM:
+	case OPAREN:
+	case OANDAND:
+	case OOROR:
+	case ODOT:  // but not ODOTPTR
+	case OCONV:
+	case OCONVNOP:
+	case OCONVIFACE:
+	case ODOTTYPE:
+		return varexpr(n->left) && varexpr(n->right);
+	}
+
+	// Be conservative.
+	return 0;
+}
+
+/*
+ * is the name l mentioned in r?
+ */
+static int
+vmatch2(Node *l, Node *r)
+{
+	NodeList *ll;
+
+	if(r == N)
+		return 0;
+	switch(r->op) {
+	case ONAME:
+		// match each right given left
+		return l == r;
+	case OLITERAL:
+		return 0;
+	}
+	if(vmatch2(l, r->left))
+		return 1;
+	if(vmatch2(l, r->right))
+		return 1;
+	for(ll=r->list; ll; ll=ll->next)
+		if(vmatch2(l, ll->n))
+			return 1;
+	return 0;
+}
+
+/*
+ * is any name mentioned in l also mentioned in r?
+ * called by sinit.c
+ */
+int
+vmatch1(Node *l, Node *r)
+{
+	NodeList *ll;
+
+	/*
+	 * isolate all left sides
+	 */
+	if(l == N || r == N)
+		return 0;
+	switch(l->op) {
+	case ONAME:
+		switch(l->class) {
+		case PPARAM:
+		case PPARAMREF:
+		case PAUTO:
+			break;
+		default:
+			// assignment to non-stack variable
+			// must be delayed if right has function calls.
+			if(r->ullman >= UINF)
+				return 1;
+			break;
+		}
+		return vmatch2(l, r);
+	case OLITERAL:
+		return 0;
+	}
+	if(vmatch1(l->left, r))
+		return 1;
+	if(vmatch1(l->right, r))
+		return 1;
+	for(ll=l->list; ll; ll=ll->next)
+		if(vmatch1(ll->n, r))
+			return 1;
+	return 0;
+}
+
+/*
+ * walk through argin parameters.
+ * generate and return code to allocate
+ * copies of escaped parameters to the heap.
+ */
+static NodeList*
+paramstoheap(Type **argin, int out)
+{
+	Type *t;
+	Iter savet;
+	Node *v;
+	NodeList *nn;
+
+	nn = nil;
+	for(t = structfirst(&savet, argin); t != T; t = structnext(&savet)) {
+		v = t->nname;
+		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.
+		if(out && (precisestack_enabled || (v == N && hasdefer))) {
+			// Defer might stop a panic and show the
+			// return values as they exist at the time of panic.
+			// Make sure to zero them on entry to the function.
+			nn = list(nn, nod(OAS, nodarg(t, 1), N));
+		}
+		if(v == N || !(v->class & PHEAP))
+			continue;
+
+		// generate allocation & copying code
+		if(compiling_runtime)
+			yyerror("%N escapes to heap, not allowed in runtime.", v);
+		if(v->alloc == nil)
+			v->alloc = callnew(v->type);
+		nn = list(nn, nod(OAS, v->heapaddr, v->alloc));
+		if((v->class & ~PHEAP) != PPARAMOUT)
+			nn = list(nn, nod(OAS, v, v->stackparam));
+	}
+	return nn;
+}
+
+/*
+ * walk through argout parameters copying back to stack
+ */
+static NodeList*
+returnsfromheap(Type **argin)
+{
+	Type *t;
+	Iter savet;
+	Node *v;
+	NodeList *nn;
+
+	nn = nil;
+	for(t = structfirst(&savet, argin); t != T; t = structnext(&savet)) {
+		v = t->nname;
+		if(v == N || v->class != (PHEAP|PPARAMOUT))
+			continue;
+		nn = list(nn, nod(OAS, v->stackparam, v));
+	}
+	return nn;
+}
+
+/*
+ * take care of migrating any function in/out args
+ * between the stack and the heap.  adds code to
+ * curfn's before and after lists.
+ */
+static void
+heapmoves(void)
+{
+	NodeList *nn;
+	int32 lno;
+
+	lno = lineno;
+	lineno = curfn->lineno;
+	nn = paramstoheap(getthis(curfn->type), 0);
+	nn = concat(nn, paramstoheap(getinarg(curfn->type), 0));
+	nn = concat(nn, paramstoheap(getoutarg(curfn->type), 1));
+	curfn->enter = concat(curfn->enter, nn);
+	lineno = curfn->endlineno;
+	curfn->exit = returnsfromheap(getoutarg(curfn->type));
+	lineno = lno;
+}
+
+static Node*
+vmkcall(Node *fn, Type *t, NodeList **init, va_list va)
+{
+	int i, n;
+	Node *r;
+	NodeList *args;
+
+	if(fn->type == T || fn->type->etype != TFUNC)
+		fatal("mkcall %N %T", fn, fn->type);
+
+	args = nil;
+	n = fn->type->intuple;
+	for(i=0; i<n; i++)
+		args = list(args, va_arg(va, Node*));
+
+	r = nod(OCALL, fn, N);
+	r->list = args;
+	if(fn->type->outtuple > 0)
+		typecheck(&r, Erv | Efnstruct);
+	else
+		typecheck(&r, Etop);
+	walkexpr(&r, init);
+	r->type = t;
+	return r;
+}
+
+Node*
+mkcall(char *name, Type *t, NodeList **init, ...)
+{
+	Node *r;
+	va_list va;
+
+	va_start(va, init);
+	r = vmkcall(syslook(name, 0), t, init, va);
+	va_end(va);
+	return r;
+}
+
+Node*
+mkcall1(Node *fn, Type *t, NodeList **init, ...)
+{
+	Node *r;
+	va_list va;
+
+	va_start(va, init);
+	r = vmkcall(fn, t, init, va);
+	va_end(va);
+	return r;
+}
+
+Node*
+conv(Node *n, Type *t)
+{
+	if(eqtype(n->type, t))
+		return n;
+	n = nod(OCONV, n, N);
+	n->type = t;
+	typecheck(&n, Erv);
+	return n;
+}
+
+Node*
+chanfn(char *name, int n, Type *t)
+{
+	Node *fn;
+	int i;
+
+	if(t->etype != TCHAN)
+		fatal("chanfn %T", t);
+	fn = syslook(name, 1);
+	for(i=0; i<n; i++)
+		argtype(fn, t->type);
+	return fn;
+}
+
+static Node*
+mapfn(char *name, Type *t)
+{
+	Node *fn;
+
+	if(t->etype != TMAP)
+		fatal("mapfn %T", t);
+	fn = syslook(name, 1);
+	argtype(fn, t->down);
+	argtype(fn, t->type);
+	argtype(fn, t->down);
+	argtype(fn, t->type);
+	return fn;
+}
+
+static Node*
+mapfndel(char *name, Type *t)
+{
+	Node *fn;
+
+	if(t->etype != TMAP)
+		fatal("mapfn %T", t);
+	fn = syslook(name, 1);
+	argtype(fn, t->down);
+	argtype(fn, t->type);
+	argtype(fn, t->down);
+	return fn;
+}
+
+static Node*
+writebarrierfn(char *name, Type *l, Type *r)
+{
+	Node *fn;
+
+	fn = syslook(name, 1);
+	argtype(fn, l);
+	argtype(fn, r);
+	return fn;
+}
+
+static Node*
+addstr(Node *n, NodeList **init)
+{
+	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(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);
+	walkexpr(&r, init);
+	r->type = n->type;
+
+	return r;
+}
+
+// expand append(l1, l2...) to
+//   init {
+//     s := l1
+//     if n := len(l1) + len(l2) - cap(s); n > 0 {
+//       s = growslice(s, n)
+//     }
+//     s = s[:len(l1)+len(l2)]
+//     memmove(&s[len(l1)], &l2[0], len(l2)*sizeof(T))
+//   }
+//   s
+//
+// l2 is allowed to be a string.
+static Node*
+appendslice(Node *n, NodeList **init)
+{
+	NodeList *l;
+	Node *l1, *l2, *nt, *nif, *fn;
+	Node *nptr1, *nptr2, *nwid;
+	Node *s;
+
+	walkexprlistsafe(n->list, init);
+
+	// walkexprlistsafe will leave OINDEX (s[n]) alone if both s
+	// and n are name or literal, but those may index the slice we're
+	// modifying here.  Fix explicitly.
+	for(l=n->list; l; l=l->next)
+		l->n = cheapexpr(l->n, init);
+
+	l1 = n->list->n;
+	l2 = n->list->next->n;
+
+	s = temp(l1->type); // var s []T
+	l = nil;
+	l = list(l, nod(OAS, s, l1)); // s = l1
+
+	nt = temp(types[TINT]);
+	nif = nod(OIF, N, N);
+	// n := len(s) + len(l2) - cap(s)
+	nif->ninit = list1(nod(OAS, nt,
+		nod(OSUB, nod(OADD, nod(OLEN, s, N), nod(OLEN, l2, N)), nod(OCAP, s, N))));
+	nif->ntest = nod(OGT, nt, nodintconst(0));
+	// instantiate growslice(Type*, []any, int64) []any
+	fn = syslook("growslice", 1);
+	argtype(fn, s->type->type);
+	argtype(fn, s->type->type);
+
+	// s = growslice(T, s, n)
+	nif->nbody = list1(nod(OAS, s, mkcall1(fn, s->type, &nif->ninit,
+					       typename(s->type),
+					       s,
+					       conv(nt, types[TINT64]))));
+
+	l = list(l, nif);
+
+	if(flag_race) {
+		// rely on runtime to instrument copy.
+		// copy(s[len(l1):len(l1)+len(l2)], l2)
+		nptr1 = nod(OSLICE, s, nod(OKEY,
+			nod(OLEN, l1, N),
+			nod(OADD, nod(OLEN, l1, N), nod(OLEN, l2, N))));
+		nptr1->etype = 1;
+		nptr2 = l2;
+		if(l2->type->etype == TSTRING)
+			fn = syslook("slicestringcopy", 1);
+		else
+			fn = syslook("slicecopy", 1);
+		argtype(fn, l1->type);
+		argtype(fn, l2->type);
+		nt = mkcall1(fn, types[TINT], &l,
+				nptr1, nptr2,
+				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));
+		nptr1->bounded = 1;
+		nptr1 = nod(OADDR, nptr1, N);
+
+		nptr2 = nod(OSPTR, l2, N);
+
+		fn = syslook("memmove", 1);
+		argtype(fn, s->type->type);	// 1 old []any
+		argtype(fn, s->type->type);	// 2 ret []any
+
+		nwid = cheapexpr(conv(nod(OLEN, l2, N), types[TUINTPTR]), &l);
+		nwid = nod(OMUL, nwid, nodintconst(s->type->type->width));
+		nt = mkcall1(fn, T, &l, nptr1, nptr2, nwid);
+		l = list(l, nt);
+	}
+
+	// s = s[:len(l1)+len(l2)]
+	nt = nod(OADD, nod(OLEN, l1, N), nod(OLEN, l2, N));
+	nt = nod(OSLICE, s, nod(OKEY, N, nt));
+	nt->etype = 1;
+	l = list(l, nod(OAS, s, nt));
+
+	typechecklist(l, Etop);
+	walkstmtlist(l);
+	*init = concat(*init, l);
+	return s;
+}
+
+// expand append(src, a [, b]* ) to
+//
+//   init {
+//     s := src
+//     const argc = len(args) - 1
+//     if cap(s) - len(s) < argc {
+//	    s = growslice(s, argc)
+//     }
+//     n := len(s)
+//     s = s[:n+argc]
+//     s[n] = a
+//     s[n+1] = b
+//     ...
+//   }
+//   s
+static Node*
+append(Node *n, NodeList **init)
+{
+	NodeList *l, *a;
+	Node *nsrc, *ns, *nn, *na, *nx, *fn;
+	int argc;
+
+	walkexprlistsafe(n->list, init);
+
+	// walkexprlistsafe will leave OINDEX (s[n]) alone if both s
+	// and n are name or literal, but those may index the slice we're
+	// modifying here.  Fix explicitly.
+	for(l=n->list; l; l=l->next)
+		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;
+	}
+
+	l = nil;
+
+	ns = temp(nsrc->type);
+	l = list(l, nod(OAS, ns, nsrc));  // s = src
+
+	na = nodintconst(argc);		// const argc
+	nx = nod(OIF, N, N);		// if cap(s) - len(s) < argc
+	nx->ntest = nod(OLT, nod(OSUB, nod(OCAP, ns, N), nod(OLEN, ns, N)), na);
+
+	fn = syslook("growslice", 1);	//   growslice(<type>, old []T, n int64) (ret []T)
+	argtype(fn, ns->type->type);	// 1 old []any
+	argtype(fn, ns->type->type);	// 2 ret []any
+
+	nx->nbody = list1(nod(OAS, ns, mkcall1(fn,  ns->type, &nx->ninit,
+					       typename(ns->type),
+					       ns,
+					       conv(na, types[TINT64]))));
+	l = list(l, nx);
+
+	nn = temp(types[TINT]);
+	l = list(l, nod(OAS, nn, nod(OLEN, ns, N)));	 // n = len(s)
+
+	nx = nod(OSLICE, ns, nod(OKEY, N, nod(OADD, nn, na)));	 // ...s[:n+argc]
+	nx->etype = 1;
+	l = list(l, nod(OAS, ns, nx));			// s = s[:n+argc]
+
+	for (a = n->list->next;	 a != nil; a = a->next) {
+		nx = nod(OINDEX, ns, nn);		// s[n] ...
+		nx->bounded = 1;
+		l = list(l, nod(OAS, nx, a->n));	// s[n] = arg
+		if (a->next != nil)
+			l = list(l, nod(OAS, nn, nod(OADD, nn, nodintconst(1))));  // n = n + 1
+	}
+
+	typechecklist(l, Etop);
+	walkstmtlist(l);
+	*init = concat(*init, l);
+	return ns;
+}
+
+// Lower copy(a, b) to a memmove call or a runtime call.
+//
+// init {
+//   n := len(a)
+//   if n > len(b) { n = len(b) }
+//   memmove(a.ptr, b.ptr, n*sizeof(elem(a)))
+// }
+// n;
+//
+// Also works if b is a string.
+//
+static Node*
+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("slicecopy", 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);
+	nr = temp(n->right->type);
+	l = nil;
+	l = list(l, nod(OAS, nl, n->left));
+	l = list(l, nod(OAS, nr, n->right));
+
+	nfrm = nod(OSPTR, nr, N);
+	nto = nod(OSPTR, nl, N);
+
+	nlen = temp(types[TINT]);
+	// n = len(to)
+	l = list(l, nod(OAS, nlen, nod(OLEN, nl, N)));
+	// if n > len(frm) { n = len(frm) }
+	nif = nod(OIF, N, N);
+	nif->ntest = nod(OGT, nlen, nod(OLEN, nr, N));
+	nif->nbody = list(nif->nbody,
+		nod(OAS, nlen, nod(OLEN, nr, N)));
+	l = list(l, nif);
+
+	// Call memmove.
+	fn = syslook("memmove", 1);
+	argtype(fn, nl->type->type);
+	argtype(fn, nl->type->type);
+	nwid = temp(types[TUINTPTR]);
+	l = list(l, nod(OAS, nwid, conv(nlen, types[TUINTPTR])));
+	nwid = nod(OMUL, nwid, nodintconst(nl->type->type->width));
+	l = list(l, mkcall1(fn, T, init, nto, nfrm, nwid));
+
+	typechecklist(l, Etop);
+	walkstmtlist(l);
+	*init = concat(*init, l);
+	return nlen;
+}
+
+// Generate frontend part for OSLICE[3][ARR|STR]
+// 
+static	Node*
+sliceany(Node* n, NodeList **init)
+{
+	int bounded, slice3;
+	Node *src, *lb, *hb, *cb, *bound, *chk, *chk0, *chk1, *chk2;
+	int64 lbv, hbv, cbv, bv, w;
+	Type *bt;
+
+//	print("before sliceany: %+N\n", n);
+
+	src = n->left;
+	lb = n->right->left;
+	slice3 = n->op == OSLICE3 || n->op == OSLICE3ARR;
+	if(slice3) {
+		hb = n->right->right->left;
+		cb = n->right->right->right;
+	} else {
+		hb = n->right->right;
+		cb = N;
+	}
+
+	bounded = n->etype;
+	
+	if(n->op == OSLICESTR)
+		bound = nod(OLEN, src, N);
+	else
+		bound = nod(OCAP, src, N);
+
+	typecheck(&bound, Erv);
+	walkexpr(&bound, init);  // if src is an array, bound will be a const now.
+
+	// static checks if possible
+	bv = 1LL<<50;
+	if(isconst(bound, CTINT)) {
+		if(!smallintconst(bound))
+			yyerror("array len too large");
+		else
+			bv = mpgetfix(bound->val.u.xval);
+	}
+
+	if(isconst(cb, CTINT)) {
+		cbv = mpgetfix(cb->val.u.xval);
+		if(cbv < 0 || cbv > bv)
+			yyerror("slice index out of bounds");
+	}
+	if(isconst(hb, CTINT)) {
+		hbv = mpgetfix(hb->val.u.xval);
+		if(hbv < 0 || hbv > bv)
+			yyerror("slice index out of bounds");
+	}
+	if(isconst(lb, CTINT)) {
+		lbv = mpgetfix(lb->val.u.xval);
+		if(lbv < 0 || lbv > bv) {
+			yyerror("slice index out of bounds");
+			lbv = -1;
+		}
+		if(lbv == 0)
+			lb = N;
+	}
+
+	// Checking src[lb:hb:cb] or src[lb:hb].
+	// if chk0 || chk1 || chk2 { panicslice() }
+	chk = N;
+	chk0 = N; // cap(src) < cb
+	chk1 = N; // cb < hb for src[lb:hb:cb]; cap(src) < hb for src[lb:hb]
+	chk2 = N; // hb < lb
+
+	// All comparisons are unsigned to avoid testing < 0.
+	bt = types[simtype[TUINT]];
+	if(cb != N && cb->type->width > 4)
+		bt = types[TUINT64];
+	if(hb != N && hb->type->width > 4)
+		bt = types[TUINT64];
+	if(lb != N && lb->type->width > 4)
+		bt = types[TUINT64];
+
+	bound = cheapexpr(conv(bound, bt), init);
+
+	if(cb != N) {
+		cb = cheapexpr(conv(cb, bt), init);
+		if(!bounded)
+			chk0 = nod(OLT, bound, cb);
+	} else if(slice3) {
+		// When we figure out what this means, implement it.
+		fatal("slice3 with cb == N"); // rejected by parser
+	}
+		
+	if(hb != N) {
+		hb = cheapexpr(conv(hb, bt), init);
+		if(!bounded) {
+			if(cb != N)
+				chk1 = nod(OLT, cb, hb);
+			else
+				chk1 = nod(OLT, bound, hb);
+		}
+	} else if(slice3) {
+		// When we figure out what this means, implement it.
+		fatal("slice3 with hb == N"); // rejected by parser
+	} else if(n->op == OSLICEARR) {
+		hb = bound;
+	} else {
+		hb = nod(OLEN, src, N);
+		typecheck(&hb, Erv);
+		walkexpr(&hb, init);
+		hb = cheapexpr(conv(hb, bt), init);
+	}
+
+	if(lb != N) {
+		lb = cheapexpr(conv(lb, bt), init);
+		if(!bounded)
+			chk2 = nod(OLT, hb, lb);  
+	}
+
+	if(chk0 != N || chk1 != N || chk2 != N) {
+		chk = nod(OIF, N, N);
+		chk->nbody = list1(mkcall("panicslice", T, init));
+		chk->likely = -1;
+		if(chk0 != N)
+			chk->ntest = chk0;
+		if(chk1 != N) {
+			if(chk->ntest == N)
+				chk->ntest = chk1;
+			else
+				chk->ntest = nod(OOROR, chk->ntest, chk1);
+		}
+		if(chk2 != N) {
+			if(chk->ntest == N)
+				chk->ntest = chk2;
+			else
+				chk->ntest = nod(OOROR, chk->ntest, chk2);
+		}
+		typecheck(&chk, Etop);
+		walkstmt(&chk);
+		*init = concat(*init, chk->ninit);
+		chk->ninit = nil;
+		*init = list(*init, chk);
+	}
+	
+	// prepare new cap, len and offs for backend cgen_slice
+	// cap = bound [ - lo ]
+	n->right = N;
+	n->list = nil;
+	if(!slice3)
+		cb = bound;
+	if(lb == N)
+		bound = conv(cb, types[simtype[TUINT]]);
+	else
+		bound = nod(OSUB, conv(cb, types[simtype[TUINT]]), conv(lb, types[simtype[TUINT]]));
+	typecheck(&bound, Erv);
+	walkexpr(&bound, init);
+	n->list = list(n->list, bound);
+
+	// len = hi [ - lo]
+	if(lb == N)
+		hb = conv(hb, types[simtype[TUINT]]);
+	else
+		hb = nod(OSUB, conv(hb, types[simtype[TUINT]]), conv(lb, types[simtype[TUINT]]));
+	typecheck(&hb, Erv);
+	walkexpr(&hb, init);
+	n->list = list(n->list, hb);
+
+	// offs = [width *] lo, but omit if zero
+	if(lb != N) {
+		if(n->op == OSLICESTR)
+			w = 1;
+		else
+			w = n->type->type->width;
+		lb = conv(lb, types[TUINTPTR]);
+		if(w > 1)
+			lb = nod(OMUL, nodintconst(w), lb);
+		typecheck(&lb, Erv);
+		walkexpr(&lb, init);
+		n->list = list(n->list, lb);
+	}
+
+//	print("after sliceany: %+N\n", n);
+
+	return n;
+}
+
+static Node*
+eqfor(Type *t)
+{
+	int a;
+	Node *n;
+	Node *ntype;
+	Sym *sym;
+
+	// Should only arrive here with large memory or
+	// a struct/array containing a non-memory field/element.
+	// Small memory is handled inline, and single non-memory
+	// is handled during type check (OCMPSTR etc).
+	a = algtype1(t, nil);
+	if(a != AMEM && a != -1)
+		fatal("eqfor %T", t);
+
+	if(a == AMEM) {
+		n = syslook("memequal", 1);
+		argtype(n, t);
+		argtype(n, t);
+		return n;
+	}
+
+	sym = typesymprefix(".eq", t);
+	n = newname(sym);
+	n->class = PFUNC;
+	ntype = nod(OTFUNC, N, N);
+	ntype->list = list(ntype->list, nod(ODCLFIELD, N, typenod(ptrto(t))));
+	ntype->list = list(ntype->list, nod(ODCLFIELD, N, typenod(ptrto(t))));
+	ntype->list = list(ntype->list, nod(ODCLFIELD, N, typenod(types[TUINTPTR])));
+	ntype->rlist = list(ntype->rlist, nod(ODCLFIELD, N, typenod(types[TBOOL])));
+	typecheck(&ntype, Etype);
+	n->type = ntype->type;
+	return n;
+}
+
+static int
+countfield(Type *t)
+{
+	Type *t1;
+	int n;
+	
+	n = 0;
+	for(t1=t->type; t1!=T; t1=t1->down)
+		n++;
+	return n;
+}
+
+static void
+walkcompare(Node **np, NodeList **init)
+{
+	Node *n, *l, *r, *call, *a, *li, *ri, *expr, *cmpl, *cmpr;
+	int andor, i;
+	Type *t, *t1;
+	
+	n = *np;
+	
+	// Must be comparison of array or struct.
+	// Otherwise back end handles it.
+	t = n->left->type;
+	switch(t->etype) {
+	default:
+		return;
+	case TARRAY:
+		if(isslice(t))
+			return;
+		break;
+	case TSTRUCT:
+		break;
+	}
+	
+	cmpl = n->left;
+	while(cmpl != N && cmpl->op == OCONVNOP)
+		cmpl = cmpl->left;
+	cmpr = n->right;
+	while(cmpr != N && cmpr->op == OCONVNOP)
+		cmpr = cmpr->left;
+	
+	if(!islvalue(cmpl) || !islvalue(cmpr)) {
+		fatal("arguments of comparison must be lvalues - %N %N", cmpl, cmpr);
+	}
+
+	l = temp(ptrto(t));
+	a = nod(OAS, l, nod(OADDR, cmpl, N));
+	a->right->etype = 1;  // addr does not escape
+	typecheck(&a, Etop);
+	*init = list(*init, a);
+
+	r = temp(ptrto(t));
+	a = nod(OAS, r, nod(OADDR, cmpr, N));
+	a->right->etype = 1;  // addr does not escape
+	typecheck(&a, Etop);
+	*init = list(*init, a);
+
+	expr = N;
+	andor = OANDAND;
+	if(n->op == ONE)
+		andor = OOROR;
+
+	if(t->etype == TARRAY &&
+		t->bound <= 4 &&
+		issimple[t->type->etype]) {
+		// Four or fewer elements of a basic type.
+		// Unroll comparisons.
+		for(i=0; i<t->bound; i++) {
+			li = nod(OINDEX, l, nodintconst(i));
+			ri = nod(OINDEX, r, nodintconst(i));
+			a = nod(n->op, li, ri);
+			if(expr == N)
+				expr = a;
+			else
+				expr = nod(andor, expr, a);
+		}
+		if(expr == N)
+			expr = nodbool(n->op == OEQ);
+		r = expr;
+		goto ret;
+	}
+
+	if(t->etype == TSTRUCT && countfield(t) <= 4) {
+		// Struct of four or fewer fields.
+		// Inline comparisons.
+		for(t1=t->type; t1; t1=t1->down) {
+			if(isblanksym(t1->sym))
+				continue;
+			li = nod(OXDOT, l, newname(t1->sym));
+			ri = nod(OXDOT, r, newname(t1->sym));
+			a = nod(n->op, li, ri);
+			if(expr == N)
+				expr = a;
+			else
+				expr = nod(andor, expr, a);
+		}
+		if(expr == N)
+			expr = nodbool(n->op == OEQ);
+		r = expr;
+		goto ret;
+	}
+
+	// Chose not to inline.  Call equality function directly.
+	call = nod(OCALL, eqfor(t), N);
+	call->list = list(call->list, l);
+	call->list = list(call->list, r);
+	call->list = list(call->list, nodintconst(t->width));
+	r = call;
+	if(n->op != OEQ)
+		r = nod(ONOT, r, N);
+	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;
+}
+
+static int
+samecheap(Node *a, Node *b)
+{
+	Node *ar, *br;
+	while(a != N && b != N && a->op == b->op) {
+		switch(a->op) {
+		default:
+			return 0;
+		case ONAME:
+			return a == b;
+		case ODOT:
+		case ODOTPTR:
+			ar = a->right;
+			br = b->right;
+			if(ar->op != ONAME || br->op != ONAME || ar->sym != br->sym)
+				return 0;
+			break;
+		case OINDEX:
+			ar = a->right;
+			br = b->right;
+			if(!isconst(ar, CTINT) || !isconst(br, CTINT) || mpcmpfixfix(ar->val.u.xval, br->val.u.xval) != 0)
+				return 0;
+			break;
+		}
+		a = a->left;
+		b = b->left;
+	}
+	return 0;
+}
+
+static void
+walkrotate(Node **np)
+{
+	int w, sl, sr, s;
+	Node *l, *r;
+	Node *n;
+	
+	n = *np;
+
+	// Want << | >> or >> | << or << ^ >> or >> ^ << on unsigned value.
+	l = n->left;
+	r = n->right;
+	if((n->op != OOR && n->op != OXOR) ||
+	   (l->op != OLSH && l->op != ORSH) ||
+	   (r->op != OLSH && r->op != ORSH) ||
+	   n->type == T || issigned[n->type->etype] ||
+	   l->op == r->op) {
+		return;
+	}
+
+	// Want same, side effect-free expression on lhs of both shifts.
+	if(!samecheap(l->left, r->left))
+		return;
+	
+	// Constants adding to width?
+	w = l->type->width * 8;
+	if(smallintconst(l->right) && smallintconst(r->right)) {
+		if((sl=mpgetfix(l->right->val.u.xval)) >= 0 && (sr=mpgetfix(r->right->val.u.xval)) >= 0 && sl+sr == w)
+			goto yes;
+		return;
+	}
+	
+	// TODO: Could allow s and 32-s if s is bounded (maybe s&31 and 32-s&31).
+	return;
+	
+yes:
+	// Rewrite left shift half to left rotate.
+	if(l->op == OLSH)
+		n = l;
+	else
+		n = r;
+	n->op = OLROT;
+	
+	// Remove rotate 0 and rotate w.
+	s = mpgetfix(n->right->val.u.xval);
+	if(s == 0 || s == w)
+		n = n->left;
+
+	*np = n;
+	return;
+}
+
+/*
+ * walkmul rewrites integer multiplication by powers of two as shifts.
+ */
+static void
+walkmul(Node **np, NodeList **init)
+{
+	Node *n, *nl, *nr;
+	int pow, neg, w;
+	
+	n = *np;
+	if(!isint[n->type->etype])
+		return;
+
+	if(n->right->op == OLITERAL) {
+		nl = n->left;
+		nr = n->right;
+	} else if(n->left->op == OLITERAL) {
+		nl = n->right;
+		nr = n->left;
+	} else
+		return;
+
+	neg = 0;
+
+	// x*0 is 0 (and side effects of x).
+	if(mpgetfix(nr->val.u.xval) == 0) {
+		cheapexpr(nl, init);
+		nodconst(n, n->type, 0);
+		goto ret;
+	}
+
+	// nr is a constant.
+	pow = powtwo(nr);
+	if(pow < 0)
+		return;
+	if(pow >= 1000) {
+		// negative power of 2, like -16
+		neg = 1;
+		pow -= 1000;
+	}
+
+	w = nl->type->width*8;
+	if(pow+1 >= w)// too big, shouldn't happen
+		return;
+
+	nl = cheapexpr(nl, init);
+
+	if(pow == 0) {
+		// x*1 is x
+		n = nl;
+		goto ret;
+	}
+	
+	n = nod(OLSH, nl, nodintconst(pow));
+
+ret:
+	if(neg)
+		n = nod(OMINUS, n, N);
+
+	typecheck(&n, Erv);
+	walkexpr(&n, init);
+	*np = n;
+}
+
+/*
+ * walkdiv rewrites division by a constant as less expensive
+ * operations.
+ */
+static void
+walkdiv(Node **np, NodeList **init)
+{
+	Node *n, *nl, *nr, *nc;
+	Node *n1, *n2, *n3, *n4;
+	int pow; // if >= 0, nr is 1<<pow
+	int s; // 1 if nr is negative.
+	int w;
+	Type *twide;
+	Magic m;
+
+	n = *np;
+	if(n->right->op != OLITERAL)
+		return;
+	// nr is a constant.
+	nl = cheapexpr(n->left, init);
+	nr = n->right;
+
+	// special cases of mod/div
+	// by a constant
+	w = nl->type->width*8;
+	s = 0;
+	pow = powtwo(nr);
+	if(pow >= 1000) {
+		// negative power of 2
+		s = 1;
+		pow -= 1000;
+	}
+
+	if(pow+1 >= w) {
+		// divisor too large.
+		return;
+	}
+	if(pow < 0) {
+		goto divbymul;
+	}
+
+	switch(pow) {
+	case 0:
+		if(n->op == OMOD) {
+			// nl % 1 is zero.
+			nodconst(n, n->type, 0);
+		} else if(s) {
+			// divide by -1
+			n->op = OMINUS;
+			n->right = N;
+		} else {
+			// divide by 1
+			n = nl;
+		}
+		break;
+	default:
+		if(issigned[n->type->etype]) {
+			if(n->op == OMOD) {
+				// signed modulo 2^pow is like ANDing
+				// with the last pow bits, but if nl < 0,
+				// nl & (2^pow-1) is (nl+1)%2^pow - 1.
+				nc = nod(OXXX, N, N);
+				nodconst(nc, types[simtype[TUINT]], w-1);
+				n1 = nod(ORSH, nl, nc); // n1 = -1 iff nl < 0.
+				if(pow == 1) {
+					typecheck(&n1, Erv);
+					n1 = cheapexpr(n1, init);
+					// n = (nl+ε)&1 -ε where ε=1 iff nl<0.
+					n2 = nod(OSUB, nl, n1);
+					nc = nod(OXXX, N, N);
+					nodconst(nc, nl->type, 1);
+					n3 = nod(OAND, n2, nc);
+					n = nod(OADD, n3, n1);
+				} else {
+					// n = (nl+ε)&(nr-1) - ε where ε=2^pow-1 iff nl<0.
+					nc = nod(OXXX, N, N);
+					nodconst(nc, nl->type, (1LL<<pow)-1);
+					n2 = nod(OAND, n1, nc); // n2 = 2^pow-1 iff nl<0.
+					typecheck(&n2, Erv);
+					n2 = cheapexpr(n2, init);
+
+					n3 = nod(OADD, nl, n2);
+					n4 = nod(OAND, n3, nc);
+					n = nod(OSUB, n4, n2);
+				}
+				break;
+			} else {
+				// arithmetic right shift does not give the correct rounding.
+				// if nl >= 0, nl >> n == nl / nr
+				// if nl < 0, we want to add 2^n-1 first.
+				nc = nod(OXXX, N, N);
+				nodconst(nc, types[simtype[TUINT]], w-1);
+				n1 = nod(ORSH, nl, nc); // n1 = -1 iff nl < 0.
+				if(pow == 1) {
+					// nl+1 is nl-(-1)
+					n->left = nod(OSUB, nl, n1);
+				} else {
+					// Do a logical right right on -1 to keep pow bits.
+					nc = nod(OXXX, N, N);
+					nodconst(nc, types[simtype[TUINT]], w-pow);
+					n2 = nod(ORSH, conv(n1, tounsigned(nl->type)), nc);
+					n->left = nod(OADD, nl, conv(n2, nl->type));
+				}
+				// n = (nl + 2^pow-1) >> pow
+				n->op = ORSH;
+				nc = nod(OXXX, N, N);
+				nodconst(nc, types[simtype[TUINT]], pow);
+				n->right = nc;
+				n->typecheck = 0;
+			}
+			if(s)
+				n = nod(OMINUS, n, N);
+			break;
+		}
+		nc = nod(OXXX, N, N);
+		if(n->op == OMOD) {
+			// n = nl & (nr-1)
+			n->op = OAND;
+			nodconst(nc, nl->type, mpgetfix(nr->val.u.xval)-1);
+		} else {
+			// n = nl >> pow
+			n->op = ORSH;
+			nodconst(nc, types[simtype[TUINT]], pow);
+		}
+		n->typecheck = 0;
+		n->right = nc;
+		break;
+	}
+	goto ret;
+
+divbymul:
+	// try to do division by multiply by (2^w)/d
+	// see hacker's delight chapter 10
+	// TODO: support 64-bit magic multiply here.
+	m.w = w;
+	if(issigned[nl->type->etype]) {
+		m.sd = mpgetfix(nr->val.u.xval);
+		smagic(&m);
+	} else {
+		m.ud = mpgetfix(nr->val.u.xval);
+		umagic(&m);
+	}
+	if(m.bad)
+		return;
+
+	// We have a quick division method so use it
+	// for modulo too.
+	if(n->op == OMOD)
+		goto longmod;
+
+	switch(simtype[nl->type->etype]) {
+	default:
+		return;
+
+	case TUINT8:
+	case TUINT16:
+	case TUINT32:
+		// n1 = nl * magic >> w (HMUL)
+		nc = nod(OXXX, N, N);
+		nodconst(nc, nl->type, m.um);
+		n1 = nod(OMUL, nl, nc);
+		typecheck(&n1, Erv);
+		n1->op = OHMUL;
+		if(m.ua) {
+			// Select a Go type with (at least) twice the width.
+			switch(simtype[nl->type->etype]) {
+			default:
+				return;
+			case TUINT8:
+			case TUINT16:
+				twide = types[TUINT32];
+				break;
+			case TUINT32:
+				twide = types[TUINT64];
+				break;
+			case TINT8:
+			case TINT16:
+				twide = types[TINT32];
+				break;
+			case TINT32:
+				twide = types[TINT64];
+				break;
+			}
+
+			// add numerator (might overflow).
+			// n2 = (n1 + nl)
+			n2 = nod(OADD, conv(n1, twide), conv(nl, twide));
+
+			// shift by m.s
+			nc = nod(OXXX, N, N);
+			nodconst(nc, types[TUINT], m.s);
+			n = conv(nod(ORSH, n2, nc), nl->type);
+		} else {
+			// n = n1 >> m.s
+			nc = nod(OXXX, N, N);
+			nodconst(nc, types[TUINT], m.s);
+			n = nod(ORSH, n1, nc);
+		}
+		break;
+
+	case TINT8:
+	case TINT16:
+	case TINT32:
+		// n1 = nl * magic >> w
+		nc = nod(OXXX, N, N);
+		nodconst(nc, nl->type, m.sm);
+		n1 = nod(OMUL, nl, nc);
+		typecheck(&n1, Erv);
+		n1->op = OHMUL;
+		if(m.sm < 0) {
+			// add the numerator.
+			n1 = nod(OADD, n1, nl);
+		}
+		// shift by m.s
+		nc = nod(OXXX, N, N);
+		nodconst(nc, types[TUINT], m.s);
+		n2 = conv(nod(ORSH, n1, nc), nl->type);
+		// add 1 iff n1 is negative.
+		nc = nod(OXXX, N, N);
+		nodconst(nc, types[TUINT], w-1);
+		n3 = nod(ORSH, nl, nc); // n4 = -1 iff n1 is negative.
+		n = nod(OSUB, n2, n3);
+		// apply sign.
+		if(m.sd < 0)
+			n = nod(OMINUS, n, N);
+		break;
+	}
+	goto ret;
+
+longmod:
+	// rewrite as A%B = A - (A/B*B).
+	n1 = nod(ODIV, nl, nr);
+	n2 = nod(OMUL, n1, nr);
+	n = nod(OSUB, nl, n2);
+	goto ret;
+
+ret:
+	typecheck(&n, Erv);
+	walkexpr(&n, init);
+	*np = n;
+}
+
+// return 1 if integer n must be in range [0, max), 0 otherwise
+static int
+bounded(Node *n, int64 max)
+{
+	int64 v;
+	int32 bits;
+	int sign;
+
+	if(n->type == T || !isint[n->type->etype])
+		return 0;
+
+	sign = issigned[n->type->etype];
+	bits = 8*n->type->width;
+
+	if(smallintconst(n)) {
+		v = mpgetfix(n->val.u.xval);
+		return 0 <= v && v < max;
+	}
+
+	switch(n->op) {
+	case OAND:
+		v = -1;
+		if(smallintconst(n->left)) {
+			v = mpgetfix(n->left->val.u.xval);
+		} else if(smallintconst(n->right)) {
+			v = mpgetfix(n->right->val.u.xval);
+		}
+		if(0 <= v && v < max)
+			return 1;
+		break;
+
+	case OMOD:
+		if(!sign && smallintconst(n->right)) {
+			v = mpgetfix(n->right->val.u.xval);
+			if(0 <= v && v <= max)
+				return 1;
+		}
+		break;
+	
+	case ODIV:
+		if(!sign && smallintconst(n->right)) {
+			v = mpgetfix(n->right->val.u.xval);
+			while(bits > 0 && v >= 2) {
+				bits--;
+				v >>= 1;
+			}
+		}
+		break;
+	
+	case ORSH:
+		if(!sign && smallintconst(n->right)) {
+			v = mpgetfix(n->right->val.u.xval);
+			if(v > bits)
+				return 1;
+			bits -= v;
+		}
+		break;
+	}
+	
+	if(!sign && bits <= 62 && (1LL<<bits) <= max)
+		return 1;
+	
+	return 0;
+}
+
+void
+usefield(Node *n)
+{
+	Type *field, *l;
+
+	if(!fieldtrack_enabled)
+		return;
+
+	switch(n->op) {
+	default:
+		fatal("usefield %O", n->op);
+	case ODOT:
+	case ODOTPTR:
+		break;
+	}
+	
+	field = n->paramfld;
+	if(field == T)
+		fatal("usefield %T %S without paramfld", n->left->type, n->right->sym);
+	if(field->note == nil || strstr(field->note->s, "go:\"track\"") == nil)
+		return;
+
+	// dedup on list
+	if(field->lastfn == curfn)
+		return;
+	field->lastfn = curfn;
+	field->outer = n->left->type;
+	if(isptr[field->outer->etype])
+		field->outer = field->outer->type;
+	if(field->outer->sym == S)
+		yyerror("tracked field must be in named struct type");
+	if(!exportname(field->sym->name))
+		yyerror("tracked field must be exported (upper case)");
+
+	l = typ(0);
+	l->type = field;
+	l->down = curfn->paramfld;
+	curfn->paramfld = l;
+}
+
+static int
+candiscardlist(NodeList *l)
+{
+	for(; l; l=l->next)
+		if(!candiscard(l->n))
+			return 0;
+	return 1;
+}
+
+int
+candiscard(Node *n)
+{
+	if(n == N)
+		return 1;
+	
+	switch(n->op) {
+	default:
+		return 0;
+
+	case ONAME:
+	case ONONAME:
+	case OTYPE:
+	case OPACK:
+	case OLITERAL:
+	case OADD:
+	case OSUB:
+	case OOR:
+	case OXOR:
+	case OADDSTR:
+	case OADDR:
+	case OANDAND:
+	case OARRAYBYTESTR:
+	case OARRAYRUNESTR:
+	case OSTRARRAYBYTE:
+	case OSTRARRAYRUNE:
+	case OCAP:
+	case OCMPIFACE:
+	case OCMPSTR:
+	case OCOMPLIT:
+	case OMAPLIT:
+	case OSTRUCTLIT:
+	case OARRAYLIT:
+	case OPTRLIT:
+	case OCONV:
+	case OCONVIFACE:
+	case OCONVNOP:
+	case ODOT:
+	case OEQ:
+	case ONE:
+	case OLT:
+	case OLE:
+	case OGT:
+	case OGE:
+	case OKEY:
+	case OLEN:
+	case OMUL:
+	case OLSH:
+	case ORSH:
+	case OAND:
+	case OANDNOT:
+	case ONEW:
+	case ONOT:
+	case OCOM:
+	case OPLUS:
+	case OMINUS:
+	case OOROR:
+	case OPAREN:
+	case ORUNESTR:
+	case OREAL:
+	case OIMAG:
+	case OCOMPLEX:
+		// Discardable as long as the subpieces are.
+		break;
+
+	case ODIV:
+	case OMOD:
+		// Discardable as long as we know it's not division by zero.
+		if(isconst(n->right, CTINT) && mpcmpfixc(n->right->val.u.xval, 0) != 0)
+			break;
+		if(isconst(n->right, CTFLT) && mpcmpfltc(n->right->val.u.fval, 0) != 0)
+			break;
+		return 0;
+
+	case OMAKECHAN:
+	case OMAKEMAP:
+		// Discardable as long as we know it won't fail because of a bad size.
+		if(isconst(n->left, CTINT) && mpcmpfixc(n->left->val.u.xval, 0) == 0)
+			break;
+		return 0;
+	
+	case OMAKESLICE:
+		// Difficult to tell what sizes are okay.
+		return 0;		
+	}
+	
+	if(!candiscard(n->left) ||
+	   !candiscard(n->right) ||
+	   !candiscard(n->ntest) ||
+	   !candiscard(n->nincr) ||
+	   !candiscardlist(n->ninit) ||
+	   !candiscardlist(n->nbody) ||
+	   !candiscardlist(n->nelse) ||
+	   !candiscardlist(n->list) ||
+	   !candiscardlist(n->rlist)) {
+		return 0;
+	}
+	
+	return 1;
+}
+
+// rewrite
+//	print(x, y, z)
+// into
+//	func(a1, a2, a3) {
+//		print(a1, a2, a3)
+//	}(x, y, z)
+// and same for println.
+static void
+walkprintfunc(Node **np, NodeList **init)
+{
+	Node *n;
+	Node *a, *fn, *t, *oldfn;
+	NodeList *l, *printargs;
+	int num;
+	char buf[100];
+	static int prgen;
+	
+	n = *np;
+
+	if(n->ninit != nil) {
+		walkstmtlist(n->ninit);
+		*init = concat(*init, n->ninit);
+		n->ninit = nil;
+	}
+
+	t = nod(OTFUNC, N, N);
+	num = 0;
+	printargs = nil;
+	for(l=n->list; l != nil; l=l->next) {
+		snprint(buf, sizeof buf, "a%d", num++);
+		a = nod(ODCLFIELD, newname(lookup(buf)), typenod(l->n->type));
+		t->list = list(t->list, a);
+		printargs = list(printargs, a->left);
+	}
+
+	fn = nod(ODCLFUNC, N, N);
+	snprint(buf, sizeof buf, "print·%d", ++prgen);
+	fn->nname = newname(lookup(buf));
+	fn->nname->defn = fn;
+	fn->nname->ntype = t;
+	declare(fn->nname, PFUNC);
+
+	oldfn = curfn;
+	curfn = nil;
+	funchdr(fn);
+	
+	a = nod(n->op, N, N);
+	a->list = printargs;
+	typecheck(&a, Etop);
+	walkstmt(&a);
+	
+	fn->nbody = list1(a);
+
+	funcbody(fn);
+	
+	typecheck(&fn, Etop);
+	typechecklist(fn->nbody, Etop);
+	xtop = list(xtop, fn);
+	curfn = oldfn;
+
+	a = nod(OCALL, N, N);
+	a->left = fn->nname;
+	a->list = n->list;
+	typecheck(&a, Etop);
+	walkexpr(&a, init);
+	*np = a;
+}
diff --git a/src/cmd/gc/y.tab.c b/src/cmd/gc/y.tab.c
new file mode 100644
index 0000000..f464126
--- /dev/null
+++ b/src/cmd/gc/y.tab.c
@@ -0,0 +1,5132 @@
+/* A Bison parser, made by GNU Bison 2.3.  */
+
+/* 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 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, 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
+   under terms of your choice, so long as that work isn't itself a
+   parser generator using the skeleton or a modified version thereof
+   as a parser skeleton.  Alternatively, if you modify or redistribute
+   the parser skeleton itself, you may (at your option) remove this
+   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.  */
+
+/* C LALR(1) parser skeleton written by Richard Stallman, by
+   simplifying the original so-called "semantic" parser.  */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+   infringing on user name space.  This should be done even for local
+   variables, as they might otherwise be expanded by user macros.
+   There are some unavoidable exceptions within include files to
+   define necessary library symbols; they are noted "INFRINGES ON
+   USER NAME SPACE" below.  */
+
+/* Identify Bison output.  */
+#define YYBISON 1
+
+/* Bison version.  */
+#define YYBISON_VERSION "2.3"
+
+/* Skeleton name.  */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers.  */
+#define YYPURE 0
+
+/* Using locations.  */
+#define YYLSP_NEEDED 0
+
+
+
+/* Tokens.  */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+   /* Put the tokens into the symbol table, so that GDB and other debuggers
+      know about them.  */
+   enum yytokentype {
+     LLITERAL = 258,
+     LASOP = 259,
+     LCOLAS = 260,
+     LBREAK = 261,
+     LCASE = 262,
+     LCHAN = 263,
+     LCONST = 264,
+     LCONTINUE = 265,
+     LDDD = 266,
+     LDEFAULT = 267,
+     LDEFER = 268,
+     LELSE = 269,
+     LFALL = 270,
+     LFOR = 271,
+     LFUNC = 272,
+     LGO = 273,
+     LGOTO = 274,
+     LIF = 275,
+     LIMPORT = 276,
+     LINTERFACE = 277,
+     LMAP = 278,
+     LNAME = 279,
+     LPACKAGE = 280,
+     LRANGE = 281,
+     LRETURN = 282,
+     LSELECT = 283,
+     LSTRUCT = 284,
+     LSWITCH = 285,
+     LTYPE = 286,
+     LVAR = 287,
+     LANDAND = 288,
+     LANDNOT = 289,
+     LBODY = 290,
+     LCOMM = 291,
+     LDEC = 292,
+     LEQ = 293,
+     LGE = 294,
+     LGT = 295,
+     LIGNORE = 296,
+     LINC = 297,
+     LLE = 298,
+     LLSH = 299,
+     LLT = 300,
+     LNE = 301,
+     LOROR = 302,
+     LRSH = 303,
+     NotPackage = 304,
+     NotParen = 305,
+     PreferToRightParen = 306
+   };
+#endif
+/* Tokens.  */
+#define LLITERAL 258
+#define LASOP 259
+#define LCOLAS 260
+#define LBREAK 261
+#define LCASE 262
+#define LCHAN 263
+#define LCONST 264
+#define LCONTINUE 265
+#define LDDD 266
+#define LDEFAULT 267
+#define LDEFER 268
+#define LELSE 269
+#define LFALL 270
+#define LFOR 271
+#define LFUNC 272
+#define LGO 273
+#define LGOTO 274
+#define LIF 275
+#define LIMPORT 276
+#define LINTERFACE 277
+#define LMAP 278
+#define LNAME 279
+#define LPACKAGE 280
+#define LRANGE 281
+#define LRETURN 282
+#define LSELECT 283
+#define LSTRUCT 284
+#define LSWITCH 285
+#define LTYPE 286
+#define LVAR 287
+#define LANDAND 288
+#define LANDNOT 289
+#define LBODY 290
+#define LCOMM 291
+#define LDEC 292
+#define LEQ 293
+#define LGE 294
+#define LGT 295
+#define LIGNORE 296
+#define LINC 297
+#define LLE 298
+#define LLSH 299
+#define LLT 300
+#define LNE 301
+#define LOROR 302
+#define LRSH 303
+#define NotPackage 304
+#define NotParen 305
+#define PreferToRightParen 306
+
+
+
+
+/* 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 28 "go.y"
+{
+	Node*		node;
+	NodeList*		list;
+	Type*		type;
+	Sym*		sym;
+	struct	Val	val;
+	int		i;
+}
+/* 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 216 of yacc.c.  */
+#line 229 "y.tab.c"
+
+#ifdef short
+# undef short
+#endif
+
+#ifdef YYTYPE_UINT8
+typedef YYTYPE_UINT8 yytype_uint8;
+#else
+typedef unsigned char yytype_uint8;
+#endif
+
+#ifdef YYTYPE_INT8
+typedef YYTYPE_INT8 yytype_int8;
+#elif (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+typedef signed char yytype_int8;
+#else
+typedef short int yytype_int8;
+#endif
+
+#ifdef YYTYPE_UINT16
+typedef YYTYPE_UINT16 yytype_uint16;
+#else
+typedef unsigned short int yytype_uint16;
+#endif
+
+#ifdef YYTYPE_INT16
+typedef YYTYPE_INT16 yytype_int16;
+#else
+typedef short int yytype_int16;
+#endif
+
+#ifndef YYSIZE_T
+# ifdef __SIZE_TYPE__
+#  define YYSIZE_T __SIZE_TYPE__
+# elif defined size_t
+#  define YYSIZE_T size_t
+# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+#  include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+#  define YYSIZE_T size_t
+# else
+#  define YYSIZE_T unsigned int
+# endif
+#endif
+
+#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
+
+#ifndef YY_
+# if defined YYENABLE_NLS && YYENABLE_NLS
+#  if ENABLE_NLS
+#   include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+#   define YY_(msgid) dgettext ("bison-runtime", msgid)
+#  endif
+# endif
+# ifndef YY_
+#  define YY_(msgid) msgid
+# endif
+#endif
+
+/* Suppress unused-variable warnings by "using" E.  */
+#if ! defined lint || defined __GNUC__
+# define YYUSE(e) ((void) (e))
+#else
+# define YYUSE(e) /* empty */
+#endif
+
+/* Identity function, used to suppress warnings about constant conditions.  */
+#ifndef lint
+# define YYID(n) (n)
+#else
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static int
+YYID (int i)
+#else
+static int
+YYID (i)
+    int i;
+#endif
+{
+  return i;
+}
+#endif
+
+#if ! defined yyoverflow || YYERROR_VERBOSE
+
+/* The parser invokes alloca or malloc; define the necessary symbols.  */
+
+# ifdef YYSTACK_USE_ALLOCA
+#  if YYSTACK_USE_ALLOCA
+#   ifdef __GNUC__
+#    define YYSTACK_ALLOC __builtin_alloca
+#   elif defined __BUILTIN_VA_ARG_INCR
+#    include <alloca.h> /* INFRINGES ON USER NAME SPACE */
+#   elif defined _AIX
+#    define YYSTACK_ALLOC __alloca
+#   elif defined _MSC_VER
+#    include <malloc.h> /* INFRINGES ON USER NAME SPACE */
+#    define alloca _alloca
+#   else
+#    define YYSTACK_ALLOC alloca
+#    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 _STDLIB_H
+#      define _STDLIB_H 1
+#     endif
+#    endif
+#   endif
+#  endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+   /* Pacify GCC's `empty if-body' warning.  */
+#  define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
+#  ifndef YYSTACK_ALLOC_MAXIMUM
+    /* The OS might guarantee only one guard page at the bottom of the stack,
+       and a page size can be as small as 4096 bytes.  So we cannot safely
+       invoke alloca (N) if N exceeds 4096.  Use a slightly smaller number
+       to allow for a few compiler-allocated temporary stack slots.  */
+#   define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
+#  endif
+# else
+#  define YYSTACK_ALLOC YYMALLOC
+#  define YYSTACK_FREE YYFREE
+#  ifndef YYSTACK_ALLOC_MAXIMUM
+#   define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
+#  endif
+#  if (defined __cplusplus && ! defined _STDLIB_H \
+       && ! ((defined YYMALLOC || defined malloc) \
+	     && (defined YYFREE || defined free)))
+#   include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+#   ifndef _STDLIB_H
+#    define _STDLIB_H 1
+#   endif
+#  endif
+#  ifndef YYMALLOC
+#   define YYMALLOC malloc
+#   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 _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+#   endif
+#  endif
+# endif
+#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
+
+
+#if (! defined yyoverflow \
+     && (! defined __cplusplus \
+	 || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member.  */
+union yyalloc
+{
+  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)
+
+/* The size of an array large to enough to hold all stacks, each with
+   N elements.  */
+# define YYSTACK_BYTES(N) \
+     ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
+      + YYSTACK_GAP_MAXIMUM)
+
+/* Copy COUNT objects from FROM to TO.  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)))
+#  else
+#   define YYCOPY(To, From, Count)		\
+      do					\
+	{					\
+	  YYSIZE_T yyi;				\
+	  for (yyi = 0; yyi < (Count); yyi++)	\
+	    (To)[yyi] = (From)[yyi];		\
+	}					\
+      while (YYID (0))
+#  endif
+# endif
+
+/* 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
+/* YYLAST -- Last index in YYTABLE.  */
+#define YYLAST   2201
+
+/* YYNTOKENS -- Number of terminals.  */
+#define YYNTOKENS  76
+/* YYNNTS -- Number of nonterminals.  */
+#define YYNNTS  142
+/* YYNRULES -- Number of rules.  */
+#define YYNRULES  352
+/* YYNRULES -- Number of states.  */
+#define YYNSTATES  669
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX.  */
+#define YYUNDEFTOK  2
+#define YYMAXUTOK   306
+
+#define YYTRANSLATE(YYX)						\
+  ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX.  */
+static const yytype_uint8 yytranslate[] =
+{
+       0,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,    69,     2,     2,    64,    55,    56,     2,
+      59,    60,    53,    49,    75,    50,    63,    54,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,    66,    62,
+       2,    65,     2,    73,    74,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,    71,     2,    72,    52,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,    67,    51,    68,    70,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     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,    57,    58,    61
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+   YYRHS.  */
+static const yytype_uint16 yyprhs[] =
+{
+       0,     0,     3,     8,     9,    13,    14,    18,    19,    23,
+      26,    32,    36,    40,    43,    45,    49,    51,    54,    57,
+      62,    63,    65,    66,    71,    72,    74,    76,    78,    80,
+      83,    89,    93,    96,   102,   110,   114,   117,   123,   127,
+     129,   132,   137,   141,   146,   150,   152,   155,   157,   159,
+     162,   164,   168,   172,   176,   179,   182,   186,   192,   198,
+     201,   202,   207,   208,   212,   213,   216,   217,   222,   227,
+     232,   235,   241,   243,   245,   248,   249,   253,   255,   259,
+     260,   261,   262,   271,   272,   278,   279,   282,   283,   286,
+     287,   288,   296,   297,   303,   305,   309,   313,   317,   321,
+     325,   329,   333,   337,   341,   345,   349,   353,   357,   361,
+     365,   369,   373,   377,   381,   385,   387,   390,   393,   396,
+     399,   402,   405,   408,   411,   415,   421,   428,   430,   432,
+     436,   442,   448,   453,   460,   469,   471,   477,   483,   489,
+     497,   499,   500,   504,   506,   511,   513,   518,   520,   524,
+     526,   528,   530,   532,   534,   536,   538,   539,   541,   543,
+     545,   547,   552,   557,   559,   561,   563,   566,   568,   570,
+     572,   574,   576,   580,   582,   584,   586,   589,   591,   593,
+     595,   597,   601,   603,   605,   607,   609,   611,   613,   615,
+     617,   619,   623,   628,   633,   636,   640,   646,   648,   650,
+     653,   657,   663,   667,   673,   677,   681,   687,   696,   702,
+     711,   717,   718,   722,   723,   725,   729,   731,   736,   739,
+     740,   744,   746,   750,   752,   756,   758,   762,   764,   768,
+     770,   774,   778,   781,   786,   790,   796,   802,   804,   808,
+     810,   813,   815,   819,   824,   826,   829,   832,   834,   836,
+     840,   841,   844,   845,   847,   849,   851,   853,   855,   857,
+     859,   861,   863,   864,   869,   871,   874,   877,   880,   883,
+     886,   889,   891,   895,   897,   901,   903,   907,   909,   913,
+     915,   919,   921,   923,   927,   931,   932,   935,   936,   938,
+     939,   941,   942,   944,   945,   947,   948,   950,   951,   953,
+     954,   956,   957,   959,   960,   962,   967,   972,   978,   985,
+     990,   995,   997,   999,  1001,  1003,  1005,  1007,  1009,  1011,
+    1013,  1017,  1022,  1028,  1033,  1038,  1041,  1044,  1049,  1053,
+    1057,  1063,  1067,  1072,  1076,  1082,  1084,  1085,  1087,  1091,
+    1093,  1095,  1098,  1100,  1102,  1108,  1109,  1112,  1114,  1118,
+    1120,  1124,  1126
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS.  */
+static const yytype_int16 yyrhs[] =
+{
+      77,     0,    -1,    79,    78,    81,   166,    -1,    -1,    25,
+     141,    62,    -1,    -1,    80,    86,    88,    -1,    -1,    81,
+      82,    62,    -1,    21,    83,    -1,    21,    59,    84,   190,
+      60,    -1,    21,    59,    60,    -1,    85,    86,    88,    -1,
+      85,    88,    -1,    83,    -1,    84,    62,    83,    -1,     3,
+      -1,   141,     3,    -1,    63,     3,    -1,    25,    24,    87,
+      62,    -1,    -1,    24,    -1,    -1,    89,   214,    64,    64,
+      -1,    -1,    91,    -1,   158,    -1,   181,    -1,     1,    -1,
+      32,    93,    -1,    32,    59,   167,   190,    60,    -1,    32,
+      59,    60,    -1,    92,    94,    -1,    92,    59,    94,   190,
+      60,    -1,    92,    59,    94,    62,   168,   190,    60,    -1,
+      92,    59,    60,    -1,    31,    97,    -1,    31,    59,   169,
+     190,    60,    -1,    31,    59,    60,    -1,     9,    -1,   185,
+     146,    -1,   185,   146,    65,   186,    -1,   185,    65,   186,
+      -1,   185,   146,    65,   186,    -1,   185,    65,   186,    -1,
+      94,    -1,   185,   146,    -1,   185,    -1,   141,    -1,    96,
+     146,    -1,   126,    -1,   126,     4,   126,    -1,   186,    65,
+     186,    -1,   186,     5,   186,    -1,   126,    42,    -1,   126,
+      37,    -1,     7,   187,    66,    -1,     7,   187,    65,   126,
+      66,    -1,     7,   187,     5,   126,    66,    -1,    12,    66,
+      -1,    -1,    67,   101,   183,    68,    -1,    -1,    99,   103,
+     183,    -1,    -1,   104,   102,    -1,    -1,    35,   106,   183,
+      68,    -1,   186,    65,    26,   126,    -1,   186,     5,    26,
+     126,    -1,    26,   126,    -1,   194,    62,   194,    62,   194,
+      -1,   194,    -1,   107,    -1,   108,   105,    -1,    -1,    16,
+     111,   109,    -1,   194,    -1,   194,    62,   194,    -1,    -1,
+      -1,    -1,    20,   114,   112,   115,   105,   116,   119,   120,
+      -1,    -1,    14,    20,   118,   112,   105,    -1,    -1,   119,
+     117,    -1,    -1,    14,   100,    -1,    -1,    -1,    30,   122,
+     112,   123,    35,   104,    68,    -1,    -1,    28,   125,    35,
+     104,    68,    -1,   127,    -1,   126,    47,   126,    -1,   126,
+      33,   126,    -1,   126,    38,   126,    -1,   126,    46,   126,
+      -1,   126,    45,   126,    -1,   126,    43,   126,    -1,   126,
+      39,   126,    -1,   126,    40,   126,    -1,   126,    49,   126,
+      -1,   126,    50,   126,    -1,   126,    51,   126,    -1,   126,
+      52,   126,    -1,   126,    53,   126,    -1,   126,    54,   126,
+      -1,   126,    55,   126,    -1,   126,    56,   126,    -1,   126,
+      34,   126,    -1,   126,    44,   126,    -1,   126,    48,   126,
+      -1,   126,    36,   126,    -1,   134,    -1,    53,   127,    -1,
+      56,   127,    -1,    49,   127,    -1,    50,   127,    -1,    69,
+     127,    -1,    70,   127,    -1,    52,   127,    -1,    36,   127,
+      -1,   134,    59,    60,    -1,   134,    59,   187,   191,    60,
+      -1,   134,    59,   187,    11,   191,    60,    -1,     3,    -1,
+     143,    -1,   134,    63,   141,    -1,   134,    63,    59,   135,
+      60,    -1,   134,    63,    59,    31,    60,    -1,   134,    71,
+     126,    72,    -1,   134,    71,   192,    66,   192,    72,    -1,
+     134,    71,   192,    66,   192,    66,   192,    72,    -1,   128,
+      -1,   149,    59,   126,   191,    60,    -1,   150,   137,   130,
+     189,    68,    -1,   129,    67,   130,   189,    68,    -1,    59,
+     135,    60,    67,   130,   189,    68,    -1,   165,    -1,    -1,
+     126,    66,   133,    -1,   126,    -1,    67,   130,   189,    68,
+      -1,   126,    -1,    67,   130,   189,    68,    -1,   129,    -1,
+      59,   135,    60,    -1,   126,    -1,   147,    -1,   146,    -1,
+      35,    -1,    67,    -1,   141,    -1,   141,    -1,    -1,   138,
+      -1,    24,    -1,   142,    -1,    73,    -1,    74,     3,    63,
+      24,    -1,    74,     3,    63,    73,    -1,   141,    -1,   138,
+      -1,    11,    -1,    11,   146,    -1,   155,    -1,   161,    -1,
+     153,    -1,   154,    -1,   152,    -1,    59,   146,    60,    -1,
+     155,    -1,   161,    -1,   153,    -1,    53,   147,    -1,   161,
+      -1,   153,    -1,   154,    -1,   152,    -1,    59,   146,    60,
+      -1,   161,    -1,   153,    -1,   153,    -1,   155,    -1,   161,
+      -1,   153,    -1,   154,    -1,   152,    -1,   143,    -1,   143,
+      63,   141,    -1,    71,   192,    72,   146,    -1,    71,    11,
+      72,   146,    -1,     8,   148,    -1,     8,    36,   146,    -1,
+      23,    71,   146,    72,   146,    -1,   156,    -1,   157,    -1,
+      53,   146,    -1,    36,     8,   146,    -1,    29,   137,   170,
+     190,    68,    -1,    29,   137,    68,    -1,    22,   137,   171,
+     190,    68,    -1,    22,   137,    68,    -1,    17,   159,   162,
+      -1,   141,    59,   179,    60,   163,    -1,    59,   179,    60,
+     141,    59,   179,    60,   163,    -1,   200,    59,   195,    60,
+     210,    -1,    59,   215,    60,   141,    59,   195,    60,   210,
+      -1,    17,    59,   179,    60,   163,    -1,    -1,    67,   183,
+      68,    -1,    -1,   151,    -1,    59,   179,    60,    -1,   161,
+      -1,   164,   137,   183,    68,    -1,   164,     1,    -1,    -1,
+     166,    90,    62,    -1,    93,    -1,   167,    62,    93,    -1,
+      95,    -1,   168,    62,    95,    -1,    97,    -1,   169,    62,
+      97,    -1,   172,    -1,   170,    62,   172,    -1,   175,    -1,
+     171,    62,   175,    -1,   184,   146,   198,    -1,   174,   198,
+      -1,    59,   174,    60,   198,    -1,    53,   174,   198,    -1,
+      59,    53,   174,    60,   198,    -1,    53,    59,   174,    60,
+     198,    -1,    24,    -1,    24,    63,   141,    -1,   173,    -1,
+     138,   176,    -1,   173,    -1,    59,   173,    60,    -1,    59,
+     179,    60,   163,    -1,   136,    -1,   141,   136,    -1,   141,
+     145,    -1,   145,    -1,   177,    -1,   178,    75,   177,    -1,
+      -1,   178,   191,    -1,    -1,   100,    -1,    91,    -1,   181,
+      -1,     1,    -1,    98,    -1,   110,    -1,   121,    -1,   124,
+      -1,   113,    -1,    -1,   144,    66,   182,   180,    -1,    15,
+      -1,     6,   140,    -1,    10,   140,    -1,    18,   128,    -1,
+      13,   128,    -1,    19,   138,    -1,    27,   193,    -1,   180,
+      -1,   183,    62,   180,    -1,   138,    -1,   184,    75,   138,
+      -1,   139,    -1,   185,    75,   139,    -1,   126,    -1,   186,
+      75,   126,    -1,   135,    -1,   187,    75,   135,    -1,   131,
+      -1,   132,    -1,   188,    75,   131,    -1,   188,    75,   132,
+      -1,    -1,   188,   191,    -1,    -1,    62,    -1,    -1,    75,
+      -1,    -1,   126,    -1,    -1,   186,    -1,    -1,    98,    -1,
+      -1,   215,    -1,    -1,   216,    -1,    -1,   217,    -1,    -1,
+       3,    -1,    21,    24,     3,    62,    -1,    32,   200,   202,
+      62,    -1,     9,   200,    65,   213,    62,    -1,     9,   200,
+     202,    65,   213,    62,    -1,    31,   201,   202,    62,    -1,
+      17,   160,   162,    62,    -1,   142,    -1,   200,    -1,   204,
+      -1,   205,    -1,   206,    -1,   204,    -1,   206,    -1,   142,
+      -1,    24,    -1,    71,    72,   202,    -1,    71,     3,    72,
+     202,    -1,    23,    71,   202,    72,   202,    -1,    29,    67,
+     196,    68,    -1,    22,    67,   197,    68,    -1,    53,   202,
+      -1,     8,   203,    -1,     8,    59,   205,    60,    -1,     8,
+      36,   202,    -1,    36,     8,   202,    -1,    17,    59,   195,
+      60,   210,    -1,   141,   202,   198,    -1,   141,    11,   202,
+     198,    -1,   141,   202,   198,    -1,   141,    59,   195,    60,
+     210,    -1,   202,    -1,    -1,   211,    -1,    59,   195,    60,
+      -1,   202,    -1,     3,    -1,    50,     3,    -1,   141,    -1,
+     212,    -1,    59,   212,    49,   212,    60,    -1,    -1,   214,
+     199,    -1,   207,    -1,   215,    75,   207,    -1,   208,    -1,
+     216,    62,   208,    -1,   209,    -1,   217,    62,   209,    -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
+static const yytype_uint16 yyrline[] =
+{
+       0,   124,   124,   133,   139,   150,   150,   165,   166,   169,
+     170,   171,   174,   211,   222,   223,   226,   233,   240,   249,
+     263,   264,   271,   271,   284,   288,   289,   293,   298,   304,
+     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,   466,   474,   494,   512,   521,
+     540,   539,   554,   553,   585,   588,   595,   594,   605,   611,
+     618,   625,   636,   642,   645,   653,   652,   663,   669,   681,
+     685,   690,   680,   711,   710,   723,   726,   732,   735,   747,
+     751,   746,   769,   768,   784,   785,   789,   793,   797,   801,
+     805,   809,   813,   817,   821,   825,   829,   833,   837,   841,
+     845,   849,   853,   857,   862,   868,   869,   873,   884,   888,
+     892,   896,   901,   905,   915,   919,   924,   932,   936,   937,
+     948,   952,   956,   960,   964,   972,   973,   979,   986,   992,
+     999,  1002,  1009,  1015,  1032,  1039,  1040,  1047,  1048,  1067,
+    1068,  1071,  1074,  1078,  1089,  1098,  1104,  1107,  1110,  1117,
+    1118,  1124,  1137,  1152,  1160,  1172,  1177,  1183,  1184,  1185,
+    1186,  1187,  1188,  1194,  1195,  1196,  1197,  1203,  1204,  1205,
+    1206,  1207,  1213,  1214,  1217,  1220,  1221,  1222,  1223,  1224,
+    1227,  1228,  1241,  1245,  1250,  1255,  1260,  1264,  1265,  1268,
+    1274,  1281,  1287,  1294,  1300,  1311,  1326,  1355,  1393,  1418,
+    1436,  1445,  1448,  1456,  1460,  1464,  1471,  1477,  1482,  1494,
+    1497,  1508,  1509,  1515,  1516,  1522,  1526,  1532,  1533,  1539,
+    1543,  1549,  1572,  1577,  1583,  1589,  1596,  1605,  1614,  1629,
+    1635,  1640,  1644,  1651,  1664,  1665,  1671,  1677,  1680,  1684,
+    1690,  1693,  1702,  1705,  1706,  1710,  1711,  1717,  1718,  1719,
+    1720,  1721,  1723,  1722,  1737,  1743,  1747,  1751,  1755,  1759,
+    1764,  1783,  1789,  1797,  1801,  1807,  1811,  1817,  1821,  1827,
+    1831,  1840,  1844,  1848,  1852,  1858,  1861,  1869,  1870,  1872,
+    1873,  1876,  1879,  1882,  1885,  1888,  1891,  1894,  1897,  1900,
+    1903,  1906,  1909,  1912,  1915,  1921,  1925,  1929,  1933,  1937,
+    1941,  1961,  1968,  1979,  1980,  1981,  1984,  1985,  1988,  1992,
+    2002,  2006,  2010,  2014,  2018,  2022,  2026,  2032,  2038,  2046,
+    2054,  2060,  2067,  2083,  2105,  2109,  2115,  2118,  2121,  2125,
+    2135,  2139,  2158,  2166,  2167,  2179,  2180,  2183,  2187,  2193,
+    2197,  2203,  2207
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+   First, the terminals, then, starting at YYNTOKENS, nonterminals.  */
+const char *yytname[] =
+{
+  "$end", "error", "$undefined", "LLITERAL", "LASOP", "LCOLAS", "LBREAK",
+  "LCASE", "LCHAN", "LCONST", "LCONTINUE", "LDDD", "LDEFAULT", "LDEFER",
+  "LELSE", "LFALL", "LFOR", "LFUNC", "LGO", "LGOTO", "LIF", "LIMPORT",
+  "LINTERFACE", "LMAP", "LNAME", "LPACKAGE", "LRANGE", "LRETURN",
+  "LSELECT", "LSTRUCT", "LSWITCH", "LTYPE", "LVAR", "LANDAND", "LANDNOT",
+  "LBODY", "LCOMM", "LDEC", "LEQ", "LGE", "LGT", "LIGNORE", "LINC", "LLE",
+  "LLSH", "LLT", "LNE", "LOROR", "LRSH", "'+'", "'-'", "'|'", "'^'", "'*'",
+  "'/'", "'%'", "'&'", "NotPackage", "NotParen", "'('", "')'",
+  "PreferToRightParen", "';'", "'.'", "'$'", "'='", "':'", "'{'", "'}'",
+  "'!'", "'~'", "'['", "']'", "'?'", "'@'", "','", "$accept", "file",
+  "package", "loadsys", "@1", "imports", "import", "import_stmt",
+  "import_stmt_list", "import_here", "import_package", "import_safety",
+  "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",
+  "name_or_type", "lbrace", "new_name", "dcl_name", "onew_name", "sym",
+  "hidden_importsym", "name", "labelname", "dotdotdot", "ntype",
+  "non_expr_type", "non_recvchantype", "convtype", "comptype",
+  "fnret_type", "dotname", "othertype", "ptrtype", "recvchantype",
+  "structtype", "interfacetype", "xfndcl", "fndcl", "hidden_fndcl",
+  "fntype", "fnbody", "fnres", "fnlitdcl", "fnliteral", "xdcl_list",
+  "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",
+  "expr_list", "expr_or_type_list", "keyval_list", "braced_keyval_list",
+  "osemi", "ocomma", "oexpr", "oexpr_list", "osimple_stmt",
+  "ohidden_funarg_list", "ohidden_structdcl_list",
+  "ohidden_interfacedcl_list", "oliteral", "hidden_import",
+  "hidden_pkg_importsym", "hidden_pkgtype", "hidden_type",
+  "hidden_type_non_recv_chan", "hidden_type_misc", "hidden_type_recv_chan",
+  "hidden_type_func", "hidden_funarg", "hidden_structdcl",
+  "hidden_interfacedcl", "ohidden_funres", "hidden_funres",
+  "hidden_literal", "hidden_constant", "hidden_import_list",
+  "hidden_funarg_list", "hidden_structdcl_list",
+  "hidden_interfacedcl_list", 0
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+   token YYLEX-NUM.  */
+static const yytype_uint16 yytoknum[] =
+{
+       0,   256,   257,   258,   259,   260,   261,   262,   263,   264,
+     265,   266,   267,   268,   269,   270,   271,   272,   273,   274,
+     275,   276,   277,   278,   279,   280,   281,   282,   283,   284,
+     285,   286,   287,   288,   289,   290,   291,   292,   293,   294,
+     295,   296,   297,   298,   299,   300,   301,   302,   303,    43,
+      45,   124,    94,    42,    47,    37,    38,   304,   305,    40,
+      41,   306,    59,    46,    36,    61,    58,   123,   125,    33,
+     126,    91,    93,    63,    64,    44
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
+static const yytype_uint8 yyr1[] =
+{
+       0,    76,    77,    78,    78,    80,    79,    81,    81,    82,
+      82,    82,    83,    83,    84,    84,    85,    85,    85,    86,
+      87,    87,    89,    88,    90,    90,    90,    90,    90,    91,
+      91,    91,    91,    91,    91,    91,    91,    91,    91,    92,
+      93,    93,    93,    94,    94,    95,    95,    95,    96,    97,
+      98,    98,    98,    98,    98,    98,    99,    99,    99,    99,
+     101,   100,   103,   102,   104,   104,   106,   105,   107,   107,
+     107,   108,   108,   108,   109,   111,   110,   112,   112,   114,
+     115,   116,   113,   118,   117,   119,   119,   120,   120,   122,
+     123,   121,   125,   124,   126,   126,   126,   126,   126,   126,
+     126,   126,   126,   126,   126,   126,   126,   126,   126,   126,
+     126,   126,   126,   126,   126,   127,   127,   127,   127,   127,
+     127,   127,   127,   127,   128,   128,   128,   129,   129,   129,
+     129,   129,   129,   129,   129,   129,   129,   129,   129,   129,
+     129,   130,   131,   132,   132,   133,   133,   134,   134,   135,
+     135,   136,   137,   137,   138,   139,   140,   140,   141,   141,
+     141,   142,   142,   143,   144,   145,   145,   146,   146,   146,
+     146,   146,   146,   147,   147,   147,   147,   148,   148,   148,
+     148,   148,   149,   149,   150,   151,   151,   151,   151,   151,
+     152,   152,   153,   153,   153,   153,   153,   153,   153,   154,
+     155,   156,   156,   157,   157,   158,   159,   159,   160,   160,
+     161,   162,   162,   163,   163,   163,   164,   165,   165,   166,
+     166,   167,   167,   168,   168,   169,   169,   170,   170,   171,
+     171,   172,   172,   172,   172,   172,   172,   173,   173,   174,
+     175,   175,   175,   176,   177,   177,   177,   177,   178,   178,
+     179,   179,   180,   180,   180,   180,   180,   181,   181,   181,
+     181,   181,   182,   181,   181,   181,   181,   181,   181,   181,
+     181,   183,   183,   184,   184,   185,   185,   186,   186,   187,
+     187,   188,   188,   188,   188,   189,   189,   190,   190,   191,
+     191,   192,   192,   193,   193,   194,   194,   195,   195,   196,
+     196,   197,   197,   198,   198,   199,   199,   199,   199,   199,
+     199,   200,   201,   202,   202,   202,   203,   203,   204,   204,
+     204,   204,   204,   204,   204,   204,   204,   204,   204,   205,
+     206,   207,   207,   208,   209,   209,   210,   210,   211,   211,
+     212,   212,   212,   213,   213,   214,   214,   215,   215,   216,
+     216,   217,   217
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN.  */
+static const yytype_uint8 yyr2[] =
+{
+       0,     2,     4,     0,     3,     0,     3,     0,     3,     2,
+       5,     3,     3,     2,     1,     3,     1,     2,     2,     4,
+       0,     1,     0,     4,     0,     1,     1,     1,     1,     2,
+       5,     3,     2,     5,     7,     3,     2,     5,     3,     1,
+       2,     4,     3,     4,     3,     1,     2,     1,     1,     2,
+       1,     3,     3,     3,     2,     2,     3,     5,     5,     2,
+       0,     4,     0,     3,     0,     2,     0,     4,     4,     4,
+       2,     5,     1,     1,     2,     0,     3,     1,     3,     0,
+       0,     0,     8,     0,     5,     0,     2,     0,     2,     0,
+       0,     7,     0,     5,     1,     3,     3,     3,     3,     3,
+       3,     3,     3,     3,     3,     3,     3,     3,     3,     3,
+       3,     3,     3,     3,     3,     1,     2,     2,     2,     2,
+       2,     2,     2,     2,     3,     5,     6,     1,     1,     3,
+       5,     5,     4,     6,     8,     1,     5,     5,     5,     7,
+       1,     0,     3,     1,     4,     1,     4,     1,     3,     1,
+       1,     1,     1,     1,     1,     1,     0,     1,     1,     1,
+       1,     4,     4,     1,     1,     1,     2,     1,     1,     1,
+       1,     1,     3,     1,     1,     1,     2,     1,     1,     1,
+       1,     3,     1,     1,     1,     1,     1,     1,     1,     1,
+       1,     3,     4,     4,     2,     3,     5,     1,     1,     2,
+       3,     5,     3,     5,     3,     3,     5,     8,     5,     8,
+       5,     0,     3,     0,     1,     3,     1,     4,     2,     0,
+       3,     1,     3,     1,     3,     1,     3,     1,     3,     1,
+       3,     3,     2,     4,     3,     5,     5,     1,     3,     1,
+       2,     1,     3,     4,     1,     2,     2,     1,     1,     3,
+       0,     2,     0,     1,     1,     1,     1,     1,     1,     1,
+       1,     1,     0,     4,     1,     2,     2,     2,     2,     2,
+       2,     1,     3,     1,     3,     1,     3,     1,     3,     1,
+       3,     1,     1,     3,     3,     0,     2,     0,     1,     0,
+       1,     0,     1,     0,     1,     0,     1,     0,     1,     0,
+       1,     0,     1,     0,     1,     4,     4,     5,     6,     4,
+       4,     1,     1,     1,     1,     1,     1,     1,     1,     1,
+       3,     4,     5,     4,     4,     2,     2,     4,     3,     3,
+       5,     3,     4,     3,     5,     1,     0,     1,     3,     1,
+       1,     2,     1,     1,     5,     0,     2,     1,     3,     1,
+       3,     1,     3
+};
+
+/* 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[] =
+{
+       5,     0,     3,     0,     1,     0,     7,     0,    22,   158,
+     160,     0,     0,   159,   219,    20,     6,   345,     0,     4,
+       0,     0,     0,    21,     0,     0,     0,    16,     0,     0,
+       9,    22,     0,     8,    28,   127,   156,     0,    39,   156,
+       0,   264,    75,     0,     0,     0,    79,     0,     0,   293,
+      92,     0,    89,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,   291,     0,    25,     0,   257,   258,
+     261,   259,   260,    50,    94,   135,   147,   115,   164,   163,
+     128,     0,     0,     0,   184,   197,   198,    26,   216,     0,
+     140,    27,     0,    19,     0,     0,     0,     0,     0,     0,
+     346,   161,   162,    11,    14,   287,    18,    22,    13,    17,
+     157,   265,   154,     0,     0,     0,     0,   163,   190,   194,
+     180,   178,   179,   177,   266,   135,     0,   295,   250,     0,
+     211,   135,   269,   295,   152,   153,     0,     0,   277,   294,
+     270,     0,     0,   295,     0,     0,    36,    48,     0,    29,
+     275,   155,     0,   123,   118,   119,   122,   116,   117,     0,
+       0,   149,     0,   150,   175,   173,   174,   120,   121,     0,
+     292,     0,   220,     0,    32,     0,     0,     0,     0,     0,
+      55,     0,     0,     0,    54,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,   141,
+       0,     0,   291,   262,     0,   141,   218,     0,     0,     0,
+       0,   311,     0,     0,   211,     0,     0,   312,     0,     0,
+      23,   288,     0,    12,   250,     0,     0,   195,   171,   169,
+     170,   167,   168,   199,     0,     0,     0,   296,    73,     0,
+      76,     0,    72,   165,   244,   163,   247,   151,   248,   289,
+       0,   250,     0,   205,    80,    77,   158,     0,   204,     0,
+     287,   241,   229,     0,    64,     0,     0,   202,   273,   287,
+     227,   239,   303,     0,    90,    38,   225,   287,    49,    31,
+     221,   287,     0,     0,    40,     0,   176,   148,     0,     0,
+      35,   287,     0,     0,    51,    96,   111,   114,    97,   101,
+     102,   100,   112,    99,    98,    95,   113,   103,   104,   105,
+     106,   107,   108,   109,   110,   285,   124,   279,   289,     0,
+     129,   292,     0,     0,   289,   285,   256,    60,   254,   253,
+     271,   255,     0,    53,    52,   278,     0,     0,     0,     0,
+     319,     0,     0,     0,     0,     0,   318,     0,   313,   314,
+     315,     0,   347,     0,     0,   297,     0,     0,     0,    15,
+      10,     0,     0,     0,   181,   191,    70,    66,    74,     0,
+       0,   295,   166,   245,   246,   290,   251,   213,     0,     0,
+       0,   295,     0,   237,     0,   250,   240,   288,     0,     0,
+       0,     0,   303,     0,     0,   288,     0,   304,   232,     0,
+     303,     0,   288,     0,   288,     0,    42,   276,     0,     0,
+       0,   200,   171,   169,   170,   168,   141,   193,   192,   288,
+       0,    44,     0,   141,   143,   281,   282,   289,     0,   289,
+     290,     0,     0,     0,   132,   291,   263,   290,     0,     0,
+       0,     0,   217,     0,     0,   326,   316,   317,   297,   301,
+       0,   299,     0,   325,   340,     0,     0,   342,   343,     0,
+       0,     0,     0,     0,   303,     0,     0,   310,     0,   298,
+     305,   309,   306,   213,   172,     0,     0,     0,     0,   249,
+     250,   163,   214,   189,   187,   188,   185,   186,   210,   213,
+     212,    81,    78,   238,   242,     0,   230,   203,   196,     0,
+       0,    93,    62,    65,     0,   234,     0,   303,   228,   201,
+     274,   231,    64,   226,    37,   222,    30,    41,     0,   285,
+      45,   223,   287,    47,    33,    43,   285,     0,   290,   286,
+     138,     0,   280,   125,   131,   130,     0,   136,   137,     0,
+     272,   328,     0,     0,   319,     0,   318,     0,   335,   351,
+     302,     0,     0,     0,   349,   300,   329,   341,     0,   307,
+       0,   320,     0,   303,   331,     0,   348,   336,     0,    69,
+      68,   295,     0,   250,   206,    85,   213,     0,    59,     0,
+     303,   303,   233,     0,   172,     0,   288,     0,    46,     0,
+     141,   145,   142,   283,   284,   126,   291,   133,    61,   327,
+     336,   297,   324,     0,     0,   303,   323,     0,     0,   321,
+     308,   332,   297,   297,   339,   208,   337,    67,    71,   215,
+       0,    87,   243,     0,     0,    56,     0,    63,   236,   235,
+      91,   139,   224,    34,   144,   285,     0,   330,     0,   352,
+     322,   333,   350,     0,     0,     0,   213,     0,    86,    82,
+       0,     0,     0,   134,   336,   344,   336,   338,   207,    83,
+      88,    58,    57,   146,   334,   209,   295,     0,    84
+};
+
+/* YYDEFGOTO[NTERM-NUM].  */
+static const yytype_int16 yydefgoto[] =
+{
+      -1,     1,     6,     2,     3,    14,    21,    30,   105,    31,
+       8,    24,    16,    17,    65,   328,    67,   149,   520,   521,
+     145,   146,    68,   502,   329,   440,   503,   579,   390,   368,
+     475,   238,   239,   240,    69,   127,   254,    70,   133,   380,
+     575,   648,   666,   621,   649,    71,   143,   401,    72,   141,
+      73,    74,    75,    76,   315,   425,   426,   592,    77,   317,
+     244,   136,    78,   150,   111,   117,    13,    80,    81,   246,
+     247,   163,   119,    82,    83,   482,   228,    84,   230,   231,
+      85,    86,    87,   130,   214,    88,   253,   488,    89,    90,
+      22,   281,   522,   277,   269,   260,   270,   271,   272,   262,
+     386,   248,   249,   250,   330,   331,   323,   332,   273,   152,
+      92,   318,   427,   428,   222,   376,   171,   140,   255,   468,
+     553,   547,   398,   100,   212,   218,   614,   445,   348,   349,
+     350,   352,   554,   549,   615,   616,   458,   459,    25,   469,
+     555,   550
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+   STATE-NUM.  */
+#define YYPACT_NINF -473
+static const yytype_int16 yypact[] =
+{
+    -473,    65,    22,    49,  -473,   261,  -473,    64,  -473,  -473,
+    -473,    95,    52,  -473,   143,   145,  -473,  -473,   104,  -473,
+      68,   128,  1049,  -473,   142,   305,    16,  -473,    56,   204,
+    -473,    49,   220,  -473,  -473,  -473,   261,   974,  -473,   261,
+     562,  -473,  -473,   288,   562,   261,  -473,    14,   147,  1615,
+    -473,    14,  -473,   395,   401,  1615,  1615,  1615,  1615,  1615,
+    1615,  1658,  1615,  1615,   737,   168,  -473,   414,  -473,  -473,
+    -473,  -473,  -473,   649,  -473,  -473,   165,   122,  -473,   169,
+    -473,   177,   218,    14,   219,  -473,  -473,  -473,   235,    89,
+    -473,  -473,    34,  -473,   206,   124,   286,   206,   206,   260,
+    -473,  -473,  -473,  -473,  -473,   265,  -473,  -473,  -473,  -473,
+    -473,  -473,  -473,   270,  1803,  1803,  1803,  -473,   269,  -473,
+    -473,  -473,  -473,  -473,  -473,    39,   122,   882,  1777,   283,
+     277,   230,  -473,  1615,  -473,  -473,   292,  1803,  2097,   280,
+    -473,   332,   315,  1615,   215,  1803,  -473,  -473,   244,  -473,
+    -473,  -473,   949,  -473,  -473,  -473,  -473,  -473,  -473,  1701,
+    1658,  2097,   298,  -473,     9,  -473,    59,  -473,  -473,   303,
+    2097,   319,  -473,   330,  -473,  1744,  1615,  1615,  1615,  1615,
+    -473,  1615,  1615,  1615,  -473,  1615,  1615,  1615,  1615,  1615,
+    1615,  1615,  1615,  1615,  1615,  1615,  1615,  1615,  1615,  -473,
+    1297,   455,  1615,  -473,  1615,  -473,  -473,  1225,  1615,  1615,
+    1615,  -473,   594,   261,   277,   328,   403,  -473,  1308,  1308,
+    -473,   152,   352,  -473,  1777,   405,  1803,  -473,  -473,  -473,
+    -473,  -473,  -473,  -473,   354,   261,  1615,  -473,  -473,   382,
+    -473,    47,   360,  1803,  -473,  1777,  -473,  -473,  -473,   351,
+     367,  1777,  1225,  -473,  -473,   366,    84,   407,  -473,   374,
+     373,  -473,  -473,   372,  -473,   138,    42,  -473,  -473,   377,
+    -473,  -473,   442,  1769,  -473,  -473,  -473,   384,  -473,  -473,
+    -473,   389,  1615,   261,   391,  1830,  -473,   394,  1803,  1803,
+    -473,   409,  1615,   411,  2097,  1935,  -473,  2121,  1080,  1080,
+    1080,  1080,  -473,  1080,  1080,  2145,  -473,   503,   503,   503,
+     503,  -473,  -473,  -473,  -473,  1352,  -473,  -473,    27,  1407,
+    -473,  1995,   412,  1147,  1962,  1352,  -473,  -473,  -473,  -473,
+    -473,  -473,     7,   280,   280,  2097,   698,   418,   415,   413,
+    -473,   416,   477,  1308,   188,    31,  -473,   425,  -473,  -473,
+    -473,  1897,  -473,   221,   433,   261,   434,   436,   439,  -473,
+    -473,   432,  1803,   452,  -473,  -473,  2097,  -473,  -473,  1462,
+    1517,  1615,  -473,  -473,  -473,  1777,  -473,  1856,   453,    91,
+     382,  1615,   261,   454,   456,  1777,  -473,   475,   451,  1803,
+     133,   407,   442,   407,   460,   326,   462,  -473,  -473,   261,
+     442,   467,   261,   478,   261,   486,   280,  -473,  1615,  1864,
+    1803,  -473,    26,   248,   264,   430,  -473,  -473,  -473,   261,
+     492,   280,  1615,  -473,  2025,  -473,  -473,   485,   493,   487,
+    1658,   504,   506,   508,  -473,  1615,  -473,  -473,   512,   505,
+    1225,  1147,  -473,  1308,   517,  -473,  -473,  -473,   261,  1889,
+    1308,   261,  1308,  -473,  -473,   571,   155,  -473,  -473,   514,
+     509,  1308,   188,  1308,   442,   261,   261,  -473,   518,   507,
+    -473,  -473,  -473,  1856,  -473,  1225,  1615,  1615,   521,  -473,
+    1777,   528,  -473,  -473,  -473,  -473,  -473,  -473,  -473,  1856,
+    -473,  -473,  -473,  -473,  -473,   520,  -473,  -473,  -473,  1658,
+     522,  -473,  -473,  -473,   530,  -473,   532,   442,  -473,  -473,
+    -473,  -473,  -473,  -473,  -473,  -473,  -473,   280,   535,  1352,
+    -473,  -473,   536,  1744,  -473,   280,  1352,  1560,  1352,  -473,
+    -473,   539,  -473,  -473,  -473,  -473,   247,  -473,  -473,   308,
+    -473,  -473,   541,   543,   545,   546,   547,   544,  -473,  -473,
+     551,   548,  1308,   554,  -473,   557,  -473,  -473,   576,  -473,
+    1308,  -473,   564,   442,  -473,   568,  -473,  1923,   318,  2097,
+    2097,  1615,   569,  1777,  -473,  -473,  1856,   156,  -473,  1147,
+     442,   442,  -473,   243,   483,   563,   261,   577,   411,   570,
+    -473,  2097,  -473,  -473,  -473,  -473,  1615,  -473,  -473,  -473,
+    1923,   261,  -473,  1889,  1308,   442,  -473,   261,   155,  -473,
+    -473,  -473,   261,   261,  -473,  -473,  -473,  -473,  -473,  -473,
+     579,   627,  -473,  1615,  1615,  -473,  1658,   580,  -473,  -473,
+    -473,  -473,  -473,  -473,  -473,  1352,   572,  -473,   583,  -473,
+    -473,  -473,  -473,   585,   586,   590,  1856,    77,  -473,  -473,
+    2049,  2073,   584,  -473,  1923,  -473,  1923,  -473,  -473,  -473,
+    -473,  -473,  -473,  -473,  -473,  -473,  1615,   382,  -473
+};
+
+/* YYPGOTO[NTERM-NUM].  */
+static const yytype_int16 yypgoto[] =
+{
+    -473,  -473,  -473,  -473,  -473,  -473,  -473,   -12,  -473,  -473,
+     624,  -473,    -1,  -473,  -473,   635,  -473,  -137,   -48,    74,
+    -473,  -130,  -112,  -473,    11,  -473,  -473,  -473,   149,  -372,
+    -473,  -473,  -473,  -473,  -473,  -473,  -140,  -473,  -473,  -473,
+    -473,  -473,  -473,  -473,  -473,  -473,  -473,  -473,  -473,  -473,
+     662,   448,   257,  -473,  -196,   135,   139,  -473,   262,   -59,
+     424,   -16,    -3,   387,   632,   427,   313,    20,  -473,   428,
+     -89,   524,  -473,  -473,  -473,  -473,   -36,   -37,   -31,   -49,
+    -473,  -473,  -473,  -473,  -473,   -32,   458,  -472,  -473,  -473,
+    -473,  -473,  -473,  -473,  -473,  -473,   279,  -108,  -211,   290,
+    -473,   306,  -473,  -214,  -291,   658,  -473,  -230,  -473,   -63,
+      -6,   191,  -473,  -302,  -219,  -254,  -195,  -473,  -107,  -435,
+    -473,  -473,  -347,  -473,   323,  -473,    72,  -473,   371,   268,
+     380,   242,   102,   110,  -468,  -473,  -438,   255,  -473,   515,
+    -473,  -473
+};
+
+/* 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 zero, do what YYDEFACT says.
+   If YYTABLE_NINF, syntax error.  */
+#define YYTABLE_NINF -278
+static const yytype_int16 yytable[] =
+{
+     121,   120,   162,   274,   175,   123,   122,   322,   491,   325,
+     361,   280,   165,   543,   276,   237,   104,   574,   558,   174,
+     242,   237,   379,   439,   164,   227,   233,   234,   261,   166,
+     108,   237,   436,   110,   460,   142,   110,   378,   429,   208,
+     101,   388,   132,   139,  -184,   505,  -268,     5,   263,   134,
+     396,  -268,   369,   511,   392,   394,   278,   118,   403,    27,
+    -216,  -180,   405,   284,   431,     4,   383,   205,  -183,   441,
+     438,    27,   420,   207,     7,   442,  -184,   229,   229,   229,
+       9,   135,   232,   232,   232,  -180,   293,  -237,    15,   102,
+     206,   229,     9,  -180,  -216,   393,   232,   659,    18,   209,
+     229,  -268,   430,   461,   622,   232,   223,  -268,   229,   210,
+     175,   165,   370,   232,    19,   229,   103,   564,  -182,    29,
+     232,   241,   210,   164,   134,   291,  -216,    28,   166,    10,
+      11,    29,   637,   259,   118,   118,   118,   363,   229,   268,
+     499,    10,    11,   232,   327,   500,  -237,   382,   118,   384,
+     540,   165,  -237,   441,   372,    27,   135,   118,   454,   490,
+     582,   623,   383,   164,    20,   118,   638,    26,   166,    23,
+     643,   495,   118,   529,   658,   531,     9,   644,   645,     9,
+     504,   200,   506,   213,   400,   201,   664,   229,   665,   229,
+      33,   454,   232,   202,   232,   118,   411,   391,    11,   417,
+     418,   501,   333,   334,    93,   455,   229,   106,   229,   359,
+     539,   232,     9,   232,   229,    29,   611,   585,   137,   232,
+     519,   624,   625,   109,   589,    10,    11,   526,    10,    11,
+     172,   626,   199,   628,   629,  -154,   229,  -267,   455,     9,
+     536,   232,  -267,   203,   118,   568,   118,   456,   413,   412,
+     499,   229,   229,   415,   414,   500,   232,   232,   641,   237,
+     433,    10,    11,   118,   478,   118,   572,   515,     9,   237,
+     165,   118,   513,   411,   492,   275,   406,   204,  -183,   261,
+      11,   465,   164,  -178,   347,     9,   421,   166,    10,    11,
+     357,   358,  -267,   118,  -182,   668,   466,   125,  -267,  -179,
+     498,   131,   126,   587,   279,   118,   126,  -178,   118,   118,
+     216,   630,     9,   596,    94,  -178,   256,    10,    11,   597,
+     227,   518,    95,  -179,   220,   229,    96,   221,   486,   224,
+     232,  -179,   235,   652,    10,    11,    97,    98,   229,   256,
+     484,   483,   251,   232,   252,   487,   485,   128,   229,   627,
+     256,   257,   229,   232,     9,   210,   523,   232,   287,   620,
+     258,    10,    11,   333,   334,    10,    11,   264,   265,    99,
+     441,   532,   229,   229,   266,   288,   598,   232,   232,   265,
+     441,   165,   118,   267,   259,   266,   617,   355,    10,    11,
+     290,   289,   268,   164,   635,   118,   510,   118,   166,    10,
+      11,   636,   517,    10,    11,   118,   356,   211,   211,   118,
+     211,   211,   360,   362,   364,   453,   525,   367,   215,     9,
+     217,   219,   371,   464,   486,     9,   375,   377,   381,   118,
+     118,   383,    12,   385,   588,   387,   484,   483,     9,   395,
+     486,   487,   485,   229,   389,   397,   402,    32,   232,    79,
+     165,   404,   484,   483,   144,    32,   408,   487,   485,   237,
+     148,   416,   164,   112,   618,  -177,   112,   166,    10,    11,
+     129,   419,   112,   173,    10,    11,   422,   448,   435,     9,
+     147,   151,   449,   451,   450,   452,   229,    10,    11,  -177,
+     462,   232,   473,   118,   151,   467,   470,  -177,   471,   256,
+     118,   472,   512,   153,   154,   155,   156,   157,   158,   118,
+     167,   168,   474,   489,   319,   541,   494,   382,  -181,   497,
+     507,   548,   551,   523,   556,   346,   667,   486,    10,    11,
+     509,   346,   346,   561,   257,   563,   229,   178,   514,   484,
+     483,   232,  -181,   118,   487,   485,   516,   186,    10,    11,
+    -181,   190,   524,   342,   237,   245,   195,   196,   197,   198,
+     528,   530,   437,   112,   533,    35,   534,   532,   535,   112,
+      37,   147,   537,   538,   557,   151,   559,   165,   567,   113,
+     576,   560,   466,   571,    47,    48,     9,   573,   578,   164,
+     580,    51,   581,   118,   166,   584,   118,   486,   586,   595,
+     151,   599,   336,   600,  -158,   601,  -159,   153,   157,   484,
+     483,   337,   602,   603,   487,   485,   338,   339,   340,   607,
+     604,    61,   606,   341,   605,   608,   610,   612,   320,   619,
+     342,   631,   609,    64,    79,    10,    11,   633,   634,   646,
+     351,   647,   441,   654,   653,   655,   656,   343,    32,   346,
+     657,   245,   663,   176,  -277,   107,   346,    66,   660,   344,
+     632,   583,   365,   593,   346,   345,   118,   594,    11,   373,
+     407,   124,   354,   374,   508,   548,   640,   496,   245,    79,
+      91,   479,   177,   178,   286,   179,   180,   181,   182,   183,
+     577,   184,   185,   186,   187,   188,   189,   190,   191,   192,
+     193,   194,   195,   196,   197,   198,   336,   446,   566,   642,
+     151,   138,   542,   639,  -277,   337,   447,   562,     0,     0,
+     338,   339,   340,   161,  -277,     0,   170,   341,   353,     0,
+       0,     0,     0,     0,   443,     0,     0,     0,     0,     0,
+      35,     0,     0,     0,     0,    37,     0,     0,   169,     0,
+      79,   343,     0,     0,   113,     0,   346,   444,     0,    47,
+      48,     9,   546,   346,     0,   346,    51,     0,     0,   345,
+       0,   457,    11,    55,   346,     0,   346,     0,     0,     0,
+       0,     0,   351,     0,     0,     0,    56,    57,     0,    58,
+      59,     0,     0,    60,     0,     0,    61,     0,     0,     0,
+       0,     0,   245,     0,   481,     0,    62,    63,    64,   493,
+      10,    11,   245,     0,   112,     0,     0,     0,     0,     0,
+       0,     0,   112,     0,     0,     0,   112,     0,     0,   147,
+       0,   151,     0,     0,     0,     0,     0,     0,   294,   295,
+     296,   297,     0,   298,   299,   300,   151,   301,   302,   303,
+     304,   305,   306,   307,   308,   309,   310,   311,   312,   313,
+     314,     0,   161,     0,   321,   346,   324,    79,    79,     0,
+     138,   138,   335,   346,     0,   351,   545,     0,   552,     0,
+     346,     0,     0,   457,     0,    35,     0,     0,     0,   457,
+      37,     0,   565,   351,     0,     0,     0,     0,   366,   113,
+       0,     0,    79,     0,    47,    48,     9,   245,   236,     0,
+       0,    51,     0,   346,     0,     0,   546,   346,    55,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,    56,    57,     0,    58,    59,     0,     0,    60,     0,
+       0,    61,     0,     0,   138,     0,     0,     0,     0,     0,
+       0,    62,    63,    64,   138,    10,    11,    37,     0,     0,
+       0,     0,     0,     0,     0,     0,   113,   346,     0,   346,
+       0,    47,    48,     9,     0,     0,     0,   424,    51,     0,
+       0,   161,    37,     0,     0,   225,     0,   424,     0,     0,
+       0,   113,     0,     0,     0,     0,    47,    48,     9,     0,
+     245,     0,   115,    51,     0,     0,    79,     0,   226,     0,
+     114,     0,     0,   151,   282,     0,     0,     0,     0,     0,
+      64,     0,    10,    11,   283,     0,     0,   115,   351,     0,
+     545,   138,   138,   116,   552,   457,     0,     0,     0,   351,
+     351,     0,     0,     0,     0,    64,     0,    10,    11,    -2,
+      34,     0,    35,     0,     0,    36,     0,    37,    38,    39,
+       0,     0,    40,     0,    41,    42,    43,    44,    45,    46,
+     138,    47,    48,     9,     0,     0,    49,    50,    51,    52,
+      53,    54,     0,     0,   138,    55,     0,     0,     0,     0,
+       0,     0,   161,     0,     0,     0,     0,   170,    56,    57,
+       0,    58,    59,     0,     0,    60,     0,     0,    61,     0,
+       0,   -24,     0,     0,   178,     0,     0,     0,    62,    63,
+      64,     0,    10,    11,   186,     0,     0,     0,   190,   191,
+     192,   193,   194,   195,   196,   197,   198,     0,   569,   570,
+       0,     0,     0,     0,     0,     0,     0,     0,   326,     0,
+      35,     0,     0,    36,  -252,    37,    38,    39,     0,  -252,
+      40,   161,    41,    42,   113,    44,    45,    46,     0,    47,
+      48,     9,     0,     0,    49,    50,    51,    52,    53,    54,
+       0,   424,     0,    55,     0,     0,     0,     0,   424,   591,
+     424,     0,     0,     0,     0,     0,    56,    57,     0,    58,
+      59,     0,     0,    60,     0,     0,    61,     0,     0,  -252,
+       0,     0,     0,     0,   327,  -252,    62,    63,    64,     0,
+      10,    11,     0,     0,     0,     0,   326,     0,    35,     0,
+       0,    36,     0,    37,    38,    39,     0,     0,    40,     0,
+      41,    42,   113,    44,    45,    46,     0,    47,    48,     9,
+       0,     0,    49,    50,    51,    52,    53,    54,   170,     0,
+       0,    55,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,    56,    57,     0,    58,    59,     0,
+       0,    60,     0,     0,    61,   650,   651,  -252,   161,     0,
+       0,     0,   327,  -252,    62,    63,    64,   424,    10,    11,
+      35,     0,     0,     0,     0,    37,     0,     0,     0,     0,
+       0,     0,     0,     0,   113,     0,   336,     0,     0,    47,
+      48,     9,     0,     0,     0,   337,    51,     0,     0,     0,
+     338,   339,   340,   159,     0,     0,     0,   341,     0,     0,
+       0,     0,     0,     0,   342,     0,    56,    57,     0,    58,
+     160,     0,     0,    60,     0,    35,    61,   316,     0,     0,
+      37,   343,     0,     0,     0,     0,    62,    63,    64,   113,
+      10,    11,     0,     0,    47,    48,     9,     0,     0,   345,
+       0,    51,    11,     0,     0,     0,     0,     0,    55,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,    56,    57,     0,    58,    59,     0,     0,    60,     0,
+      35,    61,     0,     0,     0,    37,     0,     0,     0,   423,
+       0,    62,    63,    64,   113,    10,    11,     0,     0,    47,
+      48,     9,     0,     0,     0,     0,    51,     0,   432,     0,
+       0,     0,     0,   159,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,    56,    57,     0,    58,
+     160,     0,     0,    60,     0,    35,    61,     0,     0,     0,
+      37,     0,     0,     0,     0,     0,    62,    63,    64,   113,
+      10,    11,     0,     0,    47,    48,     9,     0,   476,     0,
+       0,    51,     0,     0,     0,     0,     0,     0,    55,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,    56,    57,     0,    58,    59,     0,     0,    60,     0,
+      35,    61,     0,     0,     0,    37,     0,     0,     0,     0,
+       0,    62,    63,    64,   113,    10,    11,     0,     0,    47,
+      48,     9,     0,   477,     0,     0,    51,     0,     0,     0,
+       0,     0,     0,    55,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,    35,     0,     0,    56,    57,    37,    58,
+      59,     0,     0,    60,     0,     0,    61,   113,     0,     0,
+       0,     0,    47,    48,     9,     0,    62,    63,    64,    51,
+      10,    11,     0,     0,     0,     0,    55,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,    56,
+      57,     0,    58,    59,     0,     0,    60,     0,    35,    61,
+       0,     0,     0,    37,     0,     0,     0,   590,     0,    62,
+      63,    64,   113,    10,    11,     0,     0,    47,    48,     9,
+       0,     0,     0,     0,    51,     0,     0,     0,     0,     0,
+       0,    55,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,    35,     0,     0,    56,    57,    37,    58,    59,     0,
+       0,    60,     0,     0,    61,   113,     0,     0,     0,     0,
+      47,    48,     9,     0,    62,    63,    64,    51,    10,    11,
+       0,     0,     0,     0,   159,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,    35,     0,     0,    56,    57,   285,
+      58,   160,     0,     0,    60,     0,     0,    61,   113,     0,
+       0,     0,     0,    47,    48,     9,     0,    62,    63,    64,
+      51,    10,    11,     0,     0,     0,     0,    55,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+      56,    57,    37,    58,    59,     0,     0,    60,     0,     0,
+      61,   113,     0,     0,     0,     0,    47,    48,     9,     0,
+      62,    63,    64,    51,    10,    11,     0,    37,     0,     0,
+     225,     0,     0,     0,     0,    37,   113,     0,   243,     0,
+       0,    47,    48,     9,   113,     0,     0,   115,    51,    47,
+      48,     9,     0,   226,     0,   225,    51,     0,     0,   292,
+       0,    37,     0,   225,     0,    64,     0,    10,    11,   283,
+     113,     0,   115,     0,     0,    47,    48,     9,   226,     0,
+     115,     0,    51,     0,     0,     0,   226,     0,    37,   225,
+      64,     0,    10,    11,   399,     0,     0,   113,    64,     0,
+      10,    11,    47,    48,     9,     0,   115,     0,     0,    51,
+       0,     0,   226,     0,    37,     0,   409,     0,     0,     0,
+       0,     0,   285,   113,    64,     0,    10,    11,    47,    48,
+       9,   113,     0,   115,     0,    51,    47,    48,     9,   410,
+       0,     0,   225,    51,     0,     0,     0,   336,     0,     0,
+     225,    64,     0,    10,    11,   336,   337,     0,   463,   115,
+       0,   338,   339,   544,   337,   480,     0,   115,   341,   338,
+     339,   340,     0,   226,     0,   342,   341,    64,     0,    10,
+      11,   336,     0,   342,     0,    64,     0,    10,    11,     0,
+     337,     0,   343,     0,     0,   338,   339,   340,     0,     0,
+     343,     0,   341,     0,     0,     0,     0,     0,     0,   342,
+     345,     0,    10,    11,     0,     0,     0,     0,   345,   178,
+       0,    11,     0,   181,   182,   183,   343,     0,   185,   186,
+     187,   188,   613,   190,   191,   192,   193,   194,   195,   196,
+     197,   198,     0,     0,   345,   177,   178,    11,   179,     0,
+     181,   182,   183,     0,     0,   185,   186,   187,   188,   189,
+     190,   191,   192,   193,   194,   195,   196,   197,   198,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,   177,   178,
+       0,   179,     0,   181,   182,   183,     0,   437,   185,   186,
+     187,   188,   189,   190,   191,   192,   193,   194,   195,   196,
+     197,   198,     0,     0,     0,     0,     0,     0,   177,   178,
+       0,   179,     0,   181,   182,   183,     0,   434,   185,   186,
+     187,   188,   189,   190,   191,   192,   193,   194,   195,   196,
+     197,   198,   177,   178,     0,   179,     0,   181,   182,   183,
+       0,   527,   185,   186,   187,   188,   189,   190,   191,   192,
+     193,   194,   195,   196,   197,   198,   177,   178,     0,   179,
+       0,   181,   182,   183,     0,   661,   185,   186,   187,   188,
+     189,   190,   191,   192,   193,   194,   195,   196,   197,   198,
+     177,   178,     0,   179,     0,   181,   182,   183,     0,   662,
+     185,   186,   187,   188,   189,   190,   191,   192,   193,   194,
+     195,   196,   197,   198,   177,   178,     0,     0,     0,   181,
+     182,   183,     0,     0,   185,   186,   187,   188,   189,   190,
+     191,   192,   193,   194,   195,   196,   197,   198,   177,   178,
+       0,     0,     0,   181,   182,   183,     0,     0,   185,   186,
+     187,   188,     0,   190,   191,   192,   193,   194,   195,   196,
+     197,   198
+};
+
+static const yytype_int16 yycheck[] =
+{
+      37,    37,    61,   143,    67,    37,    37,   202,   380,   205,
+     224,   148,    61,   448,   144,   127,    28,   489,   456,    67,
+     127,   133,   252,   325,    61,   114,   115,   116,   136,    61,
+      31,   143,   323,    36,     3,    51,    39,   251,    11,     5,
+      24,   260,    45,    49,    35,   392,     7,    25,   137,    35,
+     269,    12,     5,   400,   265,   266,   145,    37,   277,     3,
+       1,    35,   281,   152,   318,     0,    24,    83,    59,    62,
+     324,     3,   291,    89,    25,    68,    67,   114,   115,   116,
+      24,    67,   114,   115,   116,    59,   175,     3,    24,    73,
+       1,   128,    24,    67,    35,    53,   128,    20,     3,    65,
+     137,    62,    75,    72,   576,   137,   107,    68,   145,    75,
+     173,   160,    65,   145,    62,   152,    60,   464,    59,    63,
+     152,   127,    75,   160,    35,   173,    67,    59,   160,    73,
+      74,    63,   600,   136,   114,   115,   116,   226,   175,   142,
+       7,    73,    74,   175,    67,    12,    62,    63,   128,   257,
+     441,   200,    68,    62,   243,     3,    67,   137,     3,    68,
+     507,     5,    24,   200,    21,   145,   601,    63,   200,    24,
+     608,   385,   152,   427,   646,   429,    24,   612,   613,    24,
+     391,    59,   393,    59,   273,    63,   654,   224,   656,   226,
+      62,     3,   224,    71,   226,   175,   285,    59,    74,   288,
+     289,    68,   208,   209,    62,    50,   243,     3,   245,   221,
+     440,   243,    24,   245,   251,    63,   563,   519,    71,   251,
+     416,    65,    66,     3,   526,    73,    74,   423,    73,    74,
+      62,    75,    67,   580,   581,    66,   273,     7,    50,    24,
+     435,   273,    12,    66,   224,   475,   226,    59,   285,   285,
+       7,   288,   289,   285,   285,    12,   288,   289,   605,   371,
+     319,    73,    74,   243,   371,   245,   480,   404,    24,   381,
+     319,   251,   402,   362,   381,    60,   282,    59,    59,   387,
+      74,    60,   319,    35,   212,    24,   292,   319,    73,    74,
+     218,   219,    62,   273,    59,   667,    75,    40,    68,    35,
+     389,    44,    40,   522,    60,   285,    44,    59,   288,   289,
+      24,    68,    24,    66,     9,    67,    24,    73,    74,    72,
+     409,   410,    17,    59,    64,   362,    21,    62,   377,    59,
+     362,    67,    63,   635,    73,    74,    31,    32,   375,    24,
+     377,   377,    59,   375,    67,   377,   377,    59,   385,   579,
+      24,    59,   389,   385,    24,    75,   419,   389,    60,   573,
+      68,    73,    74,   369,   370,    73,    74,    35,    53,    64,
+      62,   430,   409,   410,    59,    72,    68,   409,   410,    53,
+      62,   430,   362,    68,   387,    59,    68,    59,    73,    74,
+      60,    72,   395,   430,   590,   375,   399,   377,   430,    73,
+      74,   596,   408,    73,    74,   385,     3,    94,    95,   389,
+      97,    98,    60,     8,    60,   343,   422,    35,    95,    24,
+      97,    98,    62,   351,   473,    24,    75,    60,    62,   409,
+     410,    24,     5,    59,   523,    62,   473,   473,    24,    62,
+     489,   473,   473,   480,    72,     3,    62,    20,   480,    22,
+     499,    62,   489,   489,    59,    28,    65,   489,   489,   571,
+      59,    67,   499,    36,   571,    35,    39,   499,    73,    74,
+      43,    62,    45,    59,    73,    74,    65,    59,    66,    24,
+      53,    54,    67,    67,    71,     8,   523,    73,    74,    59,
+      65,   523,    60,   473,    67,    62,    62,    67,    62,    24,
+     480,    62,    35,    55,    56,    57,    58,    59,    60,   489,
+      62,    63,    60,    60,    59,   443,    60,    63,    35,    68,
+      60,   449,   450,   586,   452,   212,   666,   576,    73,    74,
+      68,   218,   219,   461,    59,   463,   573,    34,    60,   576,
+     576,   573,    59,   523,   576,   576,    60,    44,    73,    74,
+      67,    48,    60,    36,   666,   128,    53,    54,    55,    56,
+      75,    68,    75,   136,    60,     3,    60,   626,    60,   142,
+       8,   144,    60,    68,     3,   148,    62,   626,    60,    17,
+      60,    72,    75,    62,    22,    23,    24,    59,    66,   626,
+      60,    29,    60,   573,   626,    60,   576,   646,    62,    60,
+     173,    60,     8,    60,    59,    59,    59,   159,   160,   646,
+     646,    17,    68,    62,   646,   646,    22,    23,    24,    62,
+      72,    59,    68,    29,   552,    49,    62,    59,   201,    60,
+      36,    68,   560,    71,   207,    73,    74,    60,    68,    60,
+     213,    14,    62,    60,    72,    60,    60,    53,   221,   336,
+      60,   224,    68,     4,     5,    31,   343,    22,   647,    65,
+     586,   512,   235,   528,   351,    71,   646,   528,    74,   245,
+     283,    39,   214,   245,   395,   603,   604,   387,   251,   252,
+      22,   375,    33,    34,   160,    36,    37,    38,    39,    40,
+     499,    42,    43,    44,    45,    46,    47,    48,    49,    50,
+      51,    52,    53,    54,    55,    56,     8,   336,   466,   607,
+     283,    49,   444,   603,    65,    17,   336,   462,    -1,    -1,
+      22,    23,    24,    61,    75,    -1,    64,    29,   213,    -1,
+      -1,    -1,    -1,    -1,    36,    -1,    -1,    -1,    -1,    -1,
+       3,    -1,    -1,    -1,    -1,     8,    -1,    -1,    11,    -1,
+     323,    53,    -1,    -1,    17,    -1,   443,    59,    -1,    22,
+      23,    24,   449,   450,    -1,   452,    29,    -1,    -1,    71,
+      -1,   344,    74,    36,   461,    -1,   463,    -1,    -1,    -1,
+      -1,    -1,   355,    -1,    -1,    -1,    49,    50,    -1,    52,
+      53,    -1,    -1,    56,    -1,    -1,    59,    -1,    -1,    -1,
+      -1,    -1,   375,    -1,   377,    -1,    69,    70,    71,   382,
+      73,    74,   385,    -1,   387,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,   395,    -1,    -1,    -1,   399,    -1,    -1,   402,
+      -1,   404,    -1,    -1,    -1,    -1,    -1,    -1,   176,   177,
+     178,   179,    -1,   181,   182,   183,   419,   185,   186,   187,
+     188,   189,   190,   191,   192,   193,   194,   195,   196,   197,
+     198,    -1,   200,    -1,   202,   552,   204,   440,   441,    -1,
+     208,   209,   210,   560,    -1,   448,   449,    -1,   451,    -1,
+     567,    -1,    -1,   456,    -1,     3,    -1,    -1,    -1,   462,
+       8,    -1,   465,   466,    -1,    -1,    -1,    -1,   236,    17,
+      -1,    -1,   475,    -1,    22,    23,    24,   480,    26,    -1,
+      -1,    29,    -1,   600,    -1,    -1,   603,   604,    36,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    49,    50,    -1,    52,    53,    -1,    -1,    56,    -1,
+      -1,    59,    -1,    -1,   282,    -1,    -1,    -1,    -1,    -1,
+      -1,    69,    70,    71,   292,    73,    74,     8,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    17,   654,    -1,   656,
+      -1,    22,    23,    24,    -1,    -1,    -1,   315,    29,    -1,
+      -1,   319,     8,    -1,    -1,    36,    -1,   325,    -1,    -1,
+      -1,    17,    -1,    -1,    -1,    -1,    22,    23,    24,    -1,
+     573,    -1,    53,    29,    -1,    -1,   579,    -1,    59,    -1,
+      36,    -1,    -1,   586,    65,    -1,    -1,    -1,    -1,    -1,
+      71,    -1,    73,    74,    75,    -1,    -1,    53,   601,    -1,
+     603,   369,   370,    59,   607,   608,    -1,    -1,    -1,   612,
+     613,    -1,    -1,    -1,    -1,    71,    -1,    73,    74,     0,
+       1,    -1,     3,    -1,    -1,     6,    -1,     8,     9,    10,
+      -1,    -1,    13,    -1,    15,    16,    17,    18,    19,    20,
+     408,    22,    23,    24,    -1,    -1,    27,    28,    29,    30,
+      31,    32,    -1,    -1,   422,    36,    -1,    -1,    -1,    -1,
+      -1,    -1,   430,    -1,    -1,    -1,    -1,   435,    49,    50,
+      -1,    52,    53,    -1,    -1,    56,    -1,    -1,    59,    -1,
+      -1,    62,    -1,    -1,    34,    -1,    -1,    -1,    69,    70,
+      71,    -1,    73,    74,    44,    -1,    -1,    -1,    48,    49,
+      50,    51,    52,    53,    54,    55,    56,    -1,   476,   477,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,     1,    -1,
+       3,    -1,    -1,     6,     7,     8,     9,    10,    -1,    12,
+      13,   499,    15,    16,    17,    18,    19,    20,    -1,    22,
+      23,    24,    -1,    -1,    27,    28,    29,    30,    31,    32,
+      -1,   519,    -1,    36,    -1,    -1,    -1,    -1,   526,   527,
+     528,    -1,    -1,    -1,    -1,    -1,    49,    50,    -1,    52,
+      53,    -1,    -1,    56,    -1,    -1,    59,    -1,    -1,    62,
+      -1,    -1,    -1,    -1,    67,    68,    69,    70,    71,    -1,
+      73,    74,    -1,    -1,    -1,    -1,     1,    -1,     3,    -1,
+      -1,     6,    -1,     8,     9,    10,    -1,    -1,    13,    -1,
+      15,    16,    17,    18,    19,    20,    -1,    22,    23,    24,
+      -1,    -1,    27,    28,    29,    30,    31,    32,   596,    -1,
+      -1,    36,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    49,    50,    -1,    52,    53,    -1,
+      -1,    56,    -1,    -1,    59,   623,   624,    62,   626,    -1,
+      -1,    -1,    67,    68,    69,    70,    71,   635,    73,    74,
+       3,    -1,    -1,    -1,    -1,     8,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    17,    -1,     8,    -1,    -1,    22,
+      23,    24,    -1,    -1,    -1,    17,    29,    -1,    -1,    -1,
+      22,    23,    24,    36,    -1,    -1,    -1,    29,    -1,    -1,
+      -1,    -1,    -1,    -1,    36,    -1,    49,    50,    -1,    52,
+      53,    -1,    -1,    56,    -1,     3,    59,    60,    -1,    -1,
+       8,    53,    -1,    -1,    -1,    -1,    69,    70,    71,    17,
+      73,    74,    -1,    -1,    22,    23,    24,    -1,    -1,    71,
+      -1,    29,    74,    -1,    -1,    -1,    -1,    -1,    36,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    49,    50,    -1,    52,    53,    -1,    -1,    56,    -1,
+       3,    59,    -1,    -1,    -1,     8,    -1,    -1,    -1,    67,
+      -1,    69,    70,    71,    17,    73,    74,    -1,    -1,    22,
+      23,    24,    -1,    -1,    -1,    -1,    29,    -1,    31,    -1,
+      -1,    -1,    -1,    36,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    49,    50,    -1,    52,
+      53,    -1,    -1,    56,    -1,     3,    59,    -1,    -1,    -1,
+       8,    -1,    -1,    -1,    -1,    -1,    69,    70,    71,    17,
+      73,    74,    -1,    -1,    22,    23,    24,    -1,    26,    -1,
+      -1,    29,    -1,    -1,    -1,    -1,    -1,    -1,    36,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    49,    50,    -1,    52,    53,    -1,    -1,    56,    -1,
+       3,    59,    -1,    -1,    -1,     8,    -1,    -1,    -1,    -1,
+      -1,    69,    70,    71,    17,    73,    74,    -1,    -1,    22,
+      23,    24,    -1,    26,    -1,    -1,    29,    -1,    -1,    -1,
+      -1,    -1,    -1,    36,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,     3,    -1,    -1,    49,    50,     8,    52,
+      53,    -1,    -1,    56,    -1,    -1,    59,    17,    -1,    -1,
+      -1,    -1,    22,    23,    24,    -1,    69,    70,    71,    29,
+      73,    74,    -1,    -1,    -1,    -1,    36,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    49,
+      50,    -1,    52,    53,    -1,    -1,    56,    -1,     3,    59,
+      -1,    -1,    -1,     8,    -1,    -1,    -1,    67,    -1,    69,
+      70,    71,    17,    73,    74,    -1,    -1,    22,    23,    24,
+      -1,    -1,    -1,    -1,    29,    -1,    -1,    -1,    -1,    -1,
+      -1,    36,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      -1,     3,    -1,    -1,    49,    50,     8,    52,    53,    -1,
+      -1,    56,    -1,    -1,    59,    17,    -1,    -1,    -1,    -1,
+      22,    23,    24,    -1,    69,    70,    71,    29,    73,    74,
+      -1,    -1,    -1,    -1,    36,    -1,    -1,    -1,    -1,    -1,
+      -1,    -1,    -1,    -1,     3,    -1,    -1,    49,    50,     8,
+      52,    53,    -1,    -1,    56,    -1,    -1,    59,    17,    -1,
+      -1,    -1,    -1,    22,    23,    24,    -1,    69,    70,    71,
+      29,    73,    74,    -1,    -1,    -1,    -1,    36,    -1,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
+      49,    50,     8,    52,    53,    -1,    -1,    56,    -1,    -1,
+      59,    17,    -1,    -1,    -1,    -1,    22,    23,    24,    -1,
+      69,    70,    71,    29,    73,    74,    -1,     8,    -1,    -1,
+      36,    -1,    -1,    -1,    -1,     8,    17,    -1,    11,    -1,
+      -1,    22,    23,    24,    17,    -1,    -1,    53,    29,    22,
+      23,    24,    -1,    59,    -1,    36,    29,    -1,    -1,    65,
+      -1,     8,    -1,    36,    -1,    71,    -1,    73,    74,    75,
+      17,    -1,    53,    -1,    -1,    22,    23,    24,    59,    -1,
+      53,    -1,    29,    -1,    -1,    -1,    59,    -1,     8,    36,
+      71,    -1,    73,    74,    75,    -1,    -1,    17,    71,    -1,
+      73,    74,    22,    23,    24,    -1,    53,    -1,    -1,    29,
+      -1,    -1,    59,    -1,     8,    -1,    36,    -1,    -1,    -1,
+      -1,    -1,     8,    17,    71,    -1,    73,    74,    22,    23,
+      24,    17,    -1,    53,    -1,    29,    22,    23,    24,    59,
+      -1,    -1,    36,    29,    -1,    -1,    -1,     8,    -1,    -1,
+      36,    71,    -1,    73,    74,     8,    17,    -1,    11,    53,
+      -1,    22,    23,    24,    17,    59,    -1,    53,    29,    22,
+      23,    24,    -1,    59,    -1,    36,    29,    71,    -1,    73,
+      74,     8,    -1,    36,    -1,    71,    -1,    73,    74,    -1,
+      17,    -1,    53,    -1,    -1,    22,    23,    24,    -1,    -1,
+      53,    -1,    29,    -1,    -1,    -1,    -1,    -1,    -1,    36,
+      71,    -1,    73,    74,    -1,    -1,    -1,    -1,    71,    34,
+      -1,    74,    -1,    38,    39,    40,    53,    -1,    43,    44,
+      45,    46,    59,    48,    49,    50,    51,    52,    53,    54,
+      55,    56,    -1,    -1,    71,    33,    34,    74,    36,    -1,
+      38,    39,    40,    -1,    -1,    43,    44,    45,    46,    47,
+      48,    49,    50,    51,    52,    53,    54,    55,    56,    -1,
+      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    33,    34,
+      -1,    36,    -1,    38,    39,    40,    -1,    75,    43,    44,
+      45,    46,    47,    48,    49,    50,    51,    52,    53,    54,
+      55,    56,    -1,    -1,    -1,    -1,    -1,    -1,    33,    34,
+      -1,    36,    -1,    38,    39,    40,    -1,    72,    43,    44,
+      45,    46,    47,    48,    49,    50,    51,    52,    53,    54,
+      55,    56,    33,    34,    -1,    36,    -1,    38,    39,    40,
+      -1,    66,    43,    44,    45,    46,    47,    48,    49,    50,
+      51,    52,    53,    54,    55,    56,    33,    34,    -1,    36,
+      -1,    38,    39,    40,    -1,    66,    43,    44,    45,    46,
+      47,    48,    49,    50,    51,    52,    53,    54,    55,    56,
+      33,    34,    -1,    36,    -1,    38,    39,    40,    -1,    66,
+      43,    44,    45,    46,    47,    48,    49,    50,    51,    52,
+      53,    54,    55,    56,    33,    34,    -1,    -1,    -1,    38,
+      39,    40,    -1,    -1,    43,    44,    45,    46,    47,    48,
+      49,    50,    51,    52,    53,    54,    55,    56,    33,    34,
+      -1,    -1,    -1,    38,    39,    40,    -1,    -1,    43,    44,
+      45,    46,    -1,    48,    49,    50,    51,    52,    53,    54,
+      55,    56
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+   symbol of state STATE-NUM.  */
+static const yytype_uint8 yystos[] =
+{
+       0,    77,    79,    80,     0,    25,    78,    25,    86,    24,
+      73,    74,   141,   142,    81,    24,    88,    89,     3,    62,
+      21,    82,   166,    24,    87,   214,    63,     3,    59,    63,
+      83,    85,   141,    62,     1,     3,     6,     8,     9,    10,
+      13,    15,    16,    17,    18,    19,    20,    22,    23,    27,
+      28,    29,    30,    31,    32,    36,    49,    50,    52,    53,
+      56,    59,    69,    70,    71,    90,    91,    92,    98,   110,
+     113,   121,   124,   126,   127,   128,   129,   134,   138,   141,
+     143,   144,   149,   150,   153,   156,   157,   158,   161,   164,
+     165,   181,   186,    62,     9,    17,    21,    31,    32,    64,
+     199,    24,    73,    60,    83,    84,     3,    86,    88,     3,
+     138,   140,   141,    17,    36,    53,    59,   141,   143,   148,
+     152,   153,   154,   161,   140,   128,   134,   111,    59,   141,
+     159,   128,   138,   114,    35,    67,   137,    71,   126,   186,
+     193,   125,   137,   122,    59,    96,    97,   141,    59,    93,
+     139,   141,   185,   127,   127,   127,   127,   127,   127,    36,
+      53,   126,   135,   147,   153,   155,   161,   127,   127,    11,
+     126,   192,    62,    59,    94,   185,     4,    33,    34,    36,
+      37,    38,    39,    40,    42,    43,    44,    45,    46,    47,
+      48,    49,    50,    51,    52,    53,    54,    55,    56,    67,
+      59,    63,    71,    66,    59,   137,     1,   137,     5,    65,
+      75,   142,   200,    59,   160,   200,    24,   200,   201,   200,
+      64,    62,   190,    88,    59,    36,    59,   146,   152,   153,
+     154,   155,   161,   146,   146,    63,    26,    98,   107,   108,
+     109,   186,   194,    11,   136,   141,   145,   146,   177,   178,
+     179,    59,    67,   162,   112,   194,    24,    59,    68,   138,
+     171,   173,   175,   146,    35,    53,    59,    68,   138,   170,
+     172,   173,   174,   184,   112,    60,    97,   169,   146,    60,
+      93,   167,    65,    75,   146,     8,   147,    60,    72,    72,
+      60,    94,    65,   146,   126,   126,   126,   126,   126,   126,
+     126,   126,   126,   126,   126,   126,   126,   126,   126,   126,
+     126,   126,   126,   126,   126,   130,    60,   135,   187,    59,
+     141,   126,   192,   182,   126,   130,     1,    67,    91,   100,
+     180,   181,   183,   186,   186,   126,     8,    17,    22,    23,
+      24,    29,    36,    53,    65,    71,   142,   202,   204,   205,
+     206,   141,   207,   215,   162,    59,     3,   202,   202,    83,
+      60,   179,     8,   146,    60,   141,   126,    35,   105,     5,
+      65,    62,   146,   136,   145,    75,   191,    60,   179,   183,
+     115,    62,    63,    24,   173,    59,   176,    62,   190,    72,
+     104,    59,   174,    53,   174,    62,   190,     3,   198,    75,
+     146,   123,    62,   190,    62,   190,   186,   139,    65,    36,
+      59,   146,   152,   153,   154,   161,    67,   146,   146,    62,
+     190,   186,    65,    67,   126,   131,   132,   188,   189,    11,
+      75,   191,    31,   135,    72,    66,   180,    75,   191,   189,
+     101,    62,    68,    36,    59,   203,   204,   206,    59,    67,
+      71,    67,     8,   202,     3,    50,    59,   141,   212,   213,
+       3,    72,    65,    11,   202,    60,    75,    62,   195,   215,
+      62,    62,    62,    60,    60,   106,    26,    26,   194,   177,
+      59,   141,   151,   152,   153,   154,   155,   161,   163,    60,
+      68,   105,   194,   141,    60,   179,   175,    68,   146,     7,
+      12,    68,    99,   102,   174,   198,   174,    60,   172,    68,
+     138,   198,    35,    97,    60,    93,    60,   186,   146,   130,
+      94,    95,   168,   185,    60,   186,   130,    66,    75,   191,
+      68,   191,   135,    60,    60,    60,   192,    60,    68,   183,
+     180,   202,   205,   195,    24,   141,   142,   197,   202,   209,
+     217,   202,   141,   196,   208,   216,   202,     3,   212,    62,
+      72,   202,   213,   202,   198,   141,   207,    60,   183,   126,
+     126,    62,   179,    59,   163,   116,    60,   187,    66,   103,
+      60,    60,   198,   104,    60,   189,    62,   190,   146,   189,
+      67,   126,   133,   131,   132,    60,    66,    72,    68,    60,
+      60,    59,    68,    62,    72,   202,    68,    62,    49,   202,
+      62,   198,    59,    59,   202,   210,   211,    68,   194,    60,
+     179,   119,   163,     5,    65,    66,    75,   183,   198,   198,
+      68,    68,    95,    60,    68,   130,   192,   210,   195,   209,
+     202,   198,   208,   212,   195,   195,    60,    14,   117,   120,
+     126,   126,   189,    72,    60,    60,    60,    60,   163,    20,
+     100,    66,    66,    68,   210,   210,   118,   112,   105
+};
+
+#define yyerrok		(yyerrstatus = 0)
+#define yyclearin	(yychar = YYEMPTY)
+#define YYEMPTY		(-2)
+#define YYEOF		0
+
+#define YYACCEPT	goto yyacceptlab
+#define YYABORT		goto yyabortlab
+#define YYERROR		goto yyerrorlab
+
+
+/* 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.  */
+
+#define YYFAIL		goto yyerrlab
+
+#define YYRECOVERING()  (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value)					\
+do								\
+  if (yychar == YYEMPTY && yylen == 1)				\
+    {								\
+      yychar = (Token);						\
+      yylval = (Value);						\
+      yytoken = YYTRANSLATE (yychar);				\
+      YYPOPSTACK (1);						\
+      goto yybackup;						\
+    }								\
+  else								\
+    {								\
+      yyerror (YY_("syntax error: cannot back up")); \
+      YYERROR;							\
+    }								\
+while (YYID (0))
+
+
+#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
+
+
+/* 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
+# 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
+
+
+/* YYLEX -- calling `yylex' with the right arguments.  */
+
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (YYLEX_PARAM)
+#else
+# define YYLEX yylex ()
+#endif
+
+/* Enable debugging if requested.  */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+#  include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+#  define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args)			\
+do {						\
+  if (yydebug)					\
+    YYFPRINTF Args;				\
+} while (YYID (0))
+
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)			  \
+do {									  \
+  if (yydebug)								  \
+    {									  \
+      YYFPRINTF (stderr, "%s ", Title);					  \
+      yy_symbol_print (stderr,						  \
+		  Type, Value); \
+      YYFPRINTF (stderr, "\n");						  \
+    }									  \
+} while (YYID (0))
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT.  |
+`--------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_value_print (yyoutput, yytype, yyvaluep)
+    FILE *yyoutput;
+    int yytype;
+    YYSTYPE const * const yyvaluep;
+#endif
+{
+  if (!yyvaluep)
+    return;
+# ifdef YYPRINT
+  if (yytype < YYNTOKENS)
+    YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# else
+  YYUSE (yyoutput);
+# endif
+  switch (yytype)
+    {
+      default:
+	break;
+    }
+}
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT.  |
+`--------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_print (yyoutput, yytype, yyvaluep)
+    FILE *yyoutput;
+    int yytype;
+    YYSTYPE const * const yyvaluep;
+#endif
+{
+  if (yytype < YYNTOKENS)
+    YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+  else
+    YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+  yy_symbol_value_print (yyoutput, yytype, yyvaluep);
+  YYFPRINTF (yyoutput, ")");
+}
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included).                                                   |
+`------------------------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_stack_print (yytype_int16 *bottom, yytype_int16 *top)
+#else
+static void
+yy_stack_print (bottom, top)
+    yytype_int16 *bottom;
+    yytype_int16 *top;
+#endif
+{
+  YYFPRINTF (stderr, "Stack now");
+  for (; bottom <= top; ++bottom)
+    YYFPRINTF (stderr, " %d", *bottom);
+  YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top)				\
+do {								\
+  if (yydebug)							\
+    yy_stack_print ((Bottom), (Top));				\
+} while (YYID (0))
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced.  |
+`------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yy_reduce_print (YYSTYPE *yyvsp, int yyrule)
+#else
+static void
+yy_reduce_print (yyvsp, yyrule)
+    YYSTYPE *yyvsp;
+    int yyrule;
+#endif
+{
+  int yynrhs = yyr2[yyrule];
+  int yyi;
+  unsigned long int yylno = yyrline[yyrule];
+  YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
+	     yyrule - 1, yylno);
+  /* The symbols being reduced.  */
+  for (yyi = 0; yyi < yynrhs; yyi++)
+    {
+      fprintf (stderr, "   $%d = ", yyi + 1);
+      yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
+		       &(yyvsp[(yyi + 1) - (yynrhs)])
+		       		       );
+      fprintf (stderr, "\n");
+    }
+}
+
+# define YY_REDUCE_PRINT(Rule)		\
+do {					\
+  if (yydebug)				\
+    yy_reduce_print (yyvsp, Rule); \
+} while (YYID (0))
+
+/* Nonzero means print parse trace.  It is left uninitialized so that
+   multiple parsers can coexist.  */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks.  */
+#ifndef	YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+   if the built-in stack extension method is used).
+
+   Do not make this value too large; the results are undefined if
+   YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+   evaluated with infinite-precision integer arithmetic.  */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+

+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+#  if defined __GLIBC__ && defined _STRING_H
+#   define yystrlen strlen
+#  else
+/* Return the length of YYSTR.  */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static YYSIZE_T
+yystrlen (const char *yystr)
+#else
+static YYSIZE_T
+yystrlen (yystr)
+    const char *yystr;
+#endif
+{
+  YYSIZE_T yylen;
+  for (yylen = 0; yystr[yylen]; yylen++)
+    continue;
+  return yylen;
+}
+#  endif
+# endif
+
+# ifndef yystpcpy
+#  if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
+#   define yystpcpy stpcpy
+#  else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+   YYDEST.  */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static char *
+yystpcpy (char *yydest, const char *yysrc)
+#else
+static char *
+yystpcpy (yydest, yysrc)
+    char *yydest;
+    const char *yysrc;
+#endif
+{
+  char *yyd = yydest;
+  const char *yys = yysrc;
+
+  while ((*yyd++ = *yys++) != '\0')
+    continue;
+
+  return yyd - 1;
+}
+#  endif
+# endif
+
+# ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+   quotes and backslashes, so that it's suitable for yyerror.  The
+   heuristic is that double-quoting is unnecessary unless the string
+   contains an apostrophe, a comma, or backslash (other than
+   backslash-backslash).  YYSTR is taken from yytname.  If YYRES is
+   null, do not copy; instead, return the length of what the result
+   would have been.  */
+static YYSIZE_T
+yytnamerr (char *yyres, const char *yystr)
+{
+  if (*yystr == '"')
+    {
+      YYSIZE_T yyn = 0;
+      char const *yyp = yystr;
+
+      for (;;)
+	switch (*++yyp)
+	  {
+	  case '\'':
+	  case ',':
+	    goto do_not_strip_quotes;
+
+	  case '\\':
+	    if (*++yyp != '\\')
+	      goto do_not_strip_quotes;
+	    /* Fall through.  */
+	  default:
+	    if (yyres)
+	      yyres[yyn] = *yyp;
+	    yyn++;
+	    break;
+
+	  case '"':
+	    if (yyres)
+	      yyres[yyn] = '\0';
+	    return yyn;
+	  }
+    do_not_strip_quotes: ;
+    }
+
+  if (! yyres)
+    return yystrlen (yystr);
+
+  return yystpcpy (yyres, yystr) - yyres;
+}
+# endif
+
+/* 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)
+{
+  int yyn = yypact[yystate];
+
+  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;
+	  }
+
+      yyf = YY_(yyformat);
+      yysize1 = yysize + yystrlen (yyf);
+      yysize_overflow |= (yysize1 < yysize);
+      yysize = yysize1;
+
+      if (yysize_overflow)
+	return YYSIZE_MAXIMUM;
+
+      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.  |
+`-----------------------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+static void
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yydestruct (yymsg, yytype, yyvaluep)
+    const char *yymsg;
+    int yytype;
+    YYSTYPE *yyvaluep;
+#endif
+{
+  YYUSE (yyvaluep);
+
+  if (!yymsg)
+    yymsg = "Deleting";
+  YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
+  switch (yytype)
+    {
+
+      default:
+	break;
+    }
+}
+

+
+/* 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 look-ahead symbol.  */
+int yychar, yystate;
+
+/* The semantic value of the look-ahead symbol.  */
+YYSTYPE yylval;
+
+/* Number of syntax errors so far.  */
+int yynerrs;
+
+
+
+/*----------.
+| yyparse.  |
+`----------*/
+
+#ifdef YYPARSE_PARAM
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void *YYPARSE_PARAM)
+#else
+int
+yyparse (YYPARSE_PARAM)
+    void *YYPARSE_PARAM;
+#endif
+#else /* ! YYPARSE_PARAM */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+     || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void)
+#else
+int
+yyparse ()
+
+#endif
+#endif
+{
+  
+  int yyn;
+  int yyresult;
+  /* 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];
+  char *yymsg = yymsgbuf;
+  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;
+
+  YYDPRINTF ((stderr, "Starting parse\n"));
+
+  yystate = 0;
+  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;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate.  |
+`------------------------------------------------------------*/
+ yynewstate:
+  /* In all cases, when you get here, the value and location stacks
+     have just been pushed.  So pushing a state here evens the stacks.  */
+  yyssp++;
+
+ yysetstate:
+  *yyssp = yystate;
+
+  if (yyss + yystacksize - 1 <= yyssp)
+    {
+      /* Get the current used size of the three stacks, in elements.  */
+      YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+      {
+	/* Give user a chance to reallocate the stack.  Use copies of
+	   these so that the &'s don't force the real ones into
+	   memory.  */
+	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
+	   be undefined if yyoverflow is a macro.  */
+	yyoverflow (YY_("memory exhausted"),
+		    &yyss1, yysize * sizeof (*yyssp),
+		    &yyvs1, yysize * sizeof (*yyvsp),
+
+		    &yystacksize);
+
+	yyss = yyss1;
+	yyvs = yyvs1;
+      }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+      goto yyexhaustedlab;
+# else
+      /* Extend the stack our own way.  */
+      if (YYMAXDEPTH <= yystacksize)
+	goto yyexhaustedlab;
+      yystacksize *= 2;
+      if (YYMAXDEPTH < yystacksize)
+	yystacksize = YYMAXDEPTH;
+
+      {
+	yytype_int16 *yyss1 = yyss;
+	union yyalloc *yyptr =
+	  (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+	if (! yyptr)
+	  goto yyexhaustedlab;
+	YYSTACK_RELOCATE (yyss);
+	YYSTACK_RELOCATE (yyvs);
+
+#  undef YYSTACK_RELOCATE
+	if (yyss1 != yyssa)
+	  YYSTACK_FREE (yyss1);
+      }
+# endif
+#endif /* no yyoverflow */
+
+      yyssp = yyss + yysize - 1;
+      yyvsp = yyvs + yysize - 1;
+
+
+      YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+		  (unsigned long int) yystacksize));
+
+      if (yyss + yystacksize - 1 <= yyssp)
+	YYABORT;
+    }
+
+  YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+  goto yybackup;
+
+/*-----------.
+| yybackup.  |
+`-----------*/
+yybackup:
+
+  /* Do appropriate processing given the current state.  Read a
+     look-ahead token if we need one and don't already have one.  */
+
+  /* First try to decide what to do without reference to look-ahead token.  */
+  yyn = yypact[yystate];
+  if (yyn == YYPACT_NINF)
+    goto yydefault;
+
+  /* Not known => get a look-ahead token if don't already have one.  */
+
+  /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol.  */
+  if (yychar == YYEMPTY)
+    {
+      YYDPRINTF ((stderr, "Reading a token: "));
+      yychar = YYLEX;
+    }
+
+  if (yychar <= YYEOF)
+    {
+      yychar = yytoken = YYEOF;
+      YYDPRINTF ((stderr, "Now at end of input.\n"));
+    }
+  else
+    {
+      yytoken = YYTRANSLATE (yychar);
+      YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
+    }
+
+  /* If the proper action on seeing token YYTOKEN is to reduce or to
+     detect an error, take that action.  */
+  yyn += yytoken;
+  if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+    goto yydefault;
+  yyn = yytable[yyn];
+  if (yyn <= 0)
+    {
+      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 look-ahead token.  */
+  YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+
+  /* Discard the shifted token unless it is eof.  */
+  if (yychar != YYEOF)
+    yychar = YYEMPTY;
+
+  yystate = yyn;
+  *++yyvsp = yylval;
+
+  goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state.  |
+`-----------------------------------------------------------*/
+yydefault:
+  yyn = yydefact[yystate];
+  if (yyn == 0)
+    goto yyerrlab;
+  goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction.  |
+`-----------------------------*/
+yyreduce:
+  /* yyn is the number of a rule to reduce with.  */
+  yylen = yyr2[yyn];
+
+  /* If YYLEN is nonzero, implement the default value of the action:
+     `$$ = $1'.
+
+     Otherwise, the following line sets YYVAL to garbage.
+     This behavior is undocumented and Bison
+     users should not rely upon it.  Assigning to YYVAL
+     unconditionally makes the parser a bit smaller, and it avoids a
+     GCC warning that YYVAL may be used uninitialized.  */
+  yyval = yyvsp[1-yylen];
+
+
+  YY_REDUCE_PRINT (yyn);
+  switch (yyn)
+    {
+        case 2:
+#line 128 "go.y"
+    {
+		xtop = concat(xtop, (yyvsp[(4) - (4)].list));
+	}
+    break;
+
+  case 3:
+#line 134 "go.y"
+    {
+		prevlineno = lineno;
+		yyerror("package statement must be first");
+		errorexit();
+	}
+    break;
+
+  case 4:
+#line 140 "go.y"
+    {
+		mkpackage((yyvsp[(2) - (3)].sym)->name);
+	}
+    break;
+
+  case 5:
+#line 150 "go.y"
+    {
+		importpkg = runtimepkg;
+
+		if(debug['A'])
+			cannedimports("runtime.builtin", "package runtime\n\n$$\n\n");
+		else
+			cannedimports("runtime.builtin", runtimeimport);
+		curio.importsafe = 1;
+	}
+    break;
+
+  case 6:
+#line 161 "go.y"
+    {
+		importpkg = nil;
+	}
+    break;
+
+  case 12:
+#line 175 "go.y"
+    {
+		Pkg *ipkg;
+		Sym *my;
+		Node *pack;
+		
+		ipkg = importpkg;
+		my = importmyname;
+		importpkg = nil;
+		importmyname = S;
+
+		if(my == nil)
+			my = lookup(ipkg->name);
+
+		pack = nod(OPACK, N, N);
+		pack->sym = my;
+		pack->pkg = ipkg;
+		pack->lineno = (yyvsp[(1) - (3)].i);
+
+		if(my->name[0] == '.') {
+			importdot(ipkg, pack);
+			break;
+		}
+		if(strcmp(my->name, "init") == 0) {
+			yyerror("cannot import package as init - init must be a func");
+			break;
+		}
+		if(my->name[0] == '_' && my->name[1] == '\0')
+			break;
+		if(my->def) {
+			lineno = (yyvsp[(1) - (3)].i);
+			redeclare(my, "as imported package name");
+		}
+		my->def = pack;
+		my->lastlineno = (yyvsp[(1) - (3)].i);
+		my->block = 1;	// at top level
+	}
+    break;
+
+  case 13:
+#line 212 "go.y"
+    {
+		// When an invalid import path is passed to importfile,
+		// it calls yyerror and then sets up a fake import with
+		// no package statement. This allows us to test more
+		// than one invalid import statement in a single file.
+		if(nerrors == 0)
+			fatal("phase error in import");
+	}
+    break;
+
+  case 16:
+#line 227 "go.y"
+    {
+		// import with original name
+		(yyval.i) = parserline();
+		importmyname = S;
+		importfile(&(yyvsp[(1) - (1)].val), (yyval.i));
+	}
+    break;
+
+  case 17:
+#line 234 "go.y"
+    {
+		// import with given name
+		(yyval.i) = parserline();
+		importmyname = (yyvsp[(1) - (2)].sym);
+		importfile(&(yyvsp[(2) - (2)].val), (yyval.i));
+	}
+    break;
+
+  case 18:
+#line 241 "go.y"
+    {
+		// import into my name space
+		(yyval.i) = parserline();
+		importmyname = lookup(".");
+		importfile(&(yyvsp[(2) - (2)].val), (yyval.i));
+	}
+    break;
+
+  case 19:
+#line 250 "go.y"
+    {
+		if(importpkg->name == nil) {
+			importpkg->name = (yyvsp[(2) - (4)].sym)->name;
+			pkglookup((yyvsp[(2) - (4)].sym)->name, nil)->npkg++;
+		} else if(strcmp(importpkg->name, (yyvsp[(2) - (4)].sym)->name) != 0)
+			yyerror("conflicting names %s and %s for package \"%Z\"", importpkg->name, (yyvsp[(2) - (4)].sym)->name, importpkg->path);
+		importpkg->direct = 1;
+		importpkg->safe = curio.importsafe;
+
+		if(safemode && !curio.importsafe)
+			yyerror("cannot import unsafe package \"%Z\"", importpkg->path);
+	}
+    break;
+
+  case 21:
+#line 265 "go.y"
+    {
+		if(strcmp((yyvsp[(1) - (1)].sym)->name, "safe") == 0)
+			curio.importsafe = 1;
+	}
+    break;
+
+  case 22:
+#line 271 "go.y"
+    {
+		defercheckwidth();
+	}
+    break;
+
+  case 23:
+#line 275 "go.y"
+    {
+		resumecheckwidth();
+		unimportfile();
+	}
+    break;
+
+  case 24:
+#line 284 "go.y"
+    {
+		yyerror("empty top-level declaration");
+		(yyval.list) = nil;
+	}
+    break;
+
+  case 26:
+#line 290 "go.y"
+    {
+		(yyval.list) = list1((yyvsp[(1) - (1)].node));
+	}
+    break;
+
+  case 27:
+#line 294 "go.y"
+    {
+		yyerror("non-declaration statement outside function body");
+		(yyval.list) = nil;
+	}
+    break;
+
+  case 28:
+#line 299 "go.y"
+    {
+		(yyval.list) = nil;
+	}
+    break;
+
+  case 29:
+#line 305 "go.y"
+    {
+		(yyval.list) = (yyvsp[(2) - (2)].list);
+	}
+    break;
+
+  case 30:
+#line 309 "go.y"
+    {
+		(yyval.list) = (yyvsp[(3) - (5)].list);
+	}
+    break;
+
+  case 31:
+#line 313 "go.y"
+    {
+		(yyval.list) = nil;
+	}
+    break;
+
+  case 32:
+#line 317 "go.y"
+    {
+		(yyval.list) = (yyvsp[(2) - (2)].list);
+		iota = -100000;
+		lastconst = nil;
+	}
+    break;
+
+  case 33:
+#line 323 "go.y"
+    {
+		(yyval.list) = (yyvsp[(3) - (5)].list);
+		iota = -100000;
+		lastconst = nil;
+	}
+    break;
+
+  case 34:
+#line 329 "go.y"
+    {
+		(yyval.list) = concat((yyvsp[(3) - (7)].list), (yyvsp[(5) - (7)].list));
+		iota = -100000;
+		lastconst = nil;
+	}
+    break;
+
+  case 35:
+#line 335 "go.y"
+    {
+		(yyval.list) = nil;
+		iota = -100000;
+	}
+    break;
+
+  case 36:
+#line 340 "go.y"
+    {
+		(yyval.list) = list1((yyvsp[(2) - (2)].node));
+	}
+    break;
+
+  case 37:
+#line 344 "go.y"
+    {
+		(yyval.list) = (yyvsp[(3) - (5)].list);
+	}
+    break;
+
+  case 38:
+#line 348 "go.y"
+    {
+		(yyval.list) = nil;
+	}
+    break;
+
+  case 39:
+#line 354 "go.y"
+    {
+		iota = 0;
+	}
+    break;
+
+  case 40:
+#line 360 "go.y"
+    {
+		(yyval.list) = variter((yyvsp[(1) - (2)].list), (yyvsp[(2) - (2)].node), nil);
+	}
+    break;
+
+  case 41:
+#line 364 "go.y"
+    {
+		(yyval.list) = variter((yyvsp[(1) - (4)].list), (yyvsp[(2) - (4)].node), (yyvsp[(4) - (4)].list));
+	}
+    break;
+
+  case 42:
+#line 368 "go.y"
+    {
+		(yyval.list) = variter((yyvsp[(1) - (3)].list), nil, (yyvsp[(3) - (3)].list));
+	}
+    break;
+
+  case 43:
+#line 374 "go.y"
+    {
+		(yyval.list) = constiter((yyvsp[(1) - (4)].list), (yyvsp[(2) - (4)].node), (yyvsp[(4) - (4)].list));
+	}
+    break;
+
+  case 44:
+#line 378 "go.y"
+    {
+		(yyval.list) = constiter((yyvsp[(1) - (3)].list), N, (yyvsp[(3) - (3)].list));
+	}
+    break;
+
+  case 46:
+#line 385 "go.y"
+    {
+		(yyval.list) = constiter((yyvsp[(1) - (2)].list), (yyvsp[(2) - (2)].node), nil);
+	}
+    break;
+
+  case 47:
+#line 389 "go.y"
+    {
+		(yyval.list) = constiter((yyvsp[(1) - (1)].list), N, nil);
+	}
+    break;
+
+  case 48:
+#line 395 "go.y"
+    {
+		// different from dclname because the name
+		// becomes visible right here, not at the end
+		// of the declaration.
+		(yyval.node) = typedcl0((yyvsp[(1) - (1)].sym));
+	}
+    break;
+
+  case 49:
+#line 404 "go.y"
+    {
+		(yyval.node) = typedcl1((yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].node), 1);
+	}
+    break;
+
+  case 50:
+#line 410 "go.y"
+    {
+		(yyval.node) = (yyvsp[(1) - (1)].node);
+
+		// These nodes do not carry line numbers.
+		// Since a bare name used as an expression is an error,
+		// introduce a wrapper node to give the correct line.
+		switch((yyval.node)->op) {
+		case ONAME:
+		case ONONAME:
+		case OTYPE:
+		case OPACK:
+		case OLITERAL:
+			(yyval.node) = nod(OPAREN, (yyval.node), N);
+			(yyval.node)->implicit = 1;
+			break;
+		}
+	}
+    break;
+
+  case 51:
+#line 428 "go.y"
+    {
+		(yyval.node) = nod(OASOP, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+		(yyval.node)->etype = (yyvsp[(2) - (3)].i);			// rathole to pass opcode
+	}
+    break;
+
+  case 52:
+#line 433 "go.y"
+    {
+		if((yyvsp[(1) - (3)].list)->next == nil && (yyvsp[(3) - (3)].list)->next == nil) {
+			// simple
+			(yyval.node) = nod(OAS, (yyvsp[(1) - (3)].list)->n, (yyvsp[(3) - (3)].list)->n);
+			break;
+		}
+		// multiple
+		(yyval.node) = nod(OAS2, N, N);
+		(yyval.node)->list = (yyvsp[(1) - (3)].list);
+		(yyval.node)->rlist = (yyvsp[(3) - (3)].list);
+	}
+    break;
+
+  case 53:
+#line 445 "go.y"
+    {
+		if((yyvsp[(3) - (3)].list)->n->op == OTYPESW) {
+			(yyval.node) = nod(OTYPESW, N, (yyvsp[(3) - (3)].list)->n->right);
+			if((yyvsp[(3) - (3)].list)->next != nil)
+				yyerror("expr.(type) must be alone in list");
+			if((yyvsp[(1) - (3)].list)->next != nil)
+				yyerror("argument count mismatch: %d = %d", count((yyvsp[(1) - (3)].list)), 1);
+			else if(((yyvsp[(1) - (3)].list)->n->op != ONAME && (yyvsp[(1) - (3)].list)->n->op != OTYPE && (yyvsp[(1) - (3)].list)->n->op != ONONAME) || isblank((yyvsp[(1) - (3)].list)->n))
+				yyerror("invalid variable name %N in type switch", (yyvsp[(1) - (3)].list)->n);
+			else
+				(yyval.node)->left = dclname((yyvsp[(1) - (3)].list)->n->sym);  // it's a colas, so must not re-use an oldname.
+			break;
+		}
+		(yyval.node) = colas((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].list), (yyvsp[(2) - (3)].i));
+	}
+    break;
+
+  case 54:
+#line 461 "go.y"
+    {
+		(yyval.node) = nod(OASOP, (yyvsp[(1) - (2)].node), nodintconst(1));
+		(yyval.node)->implicit = 1;
+		(yyval.node)->etype = OADD;
+	}
+    break;
+
+  case 55:
+#line 467 "go.y"
+    {
+		(yyval.node) = nod(OASOP, (yyvsp[(1) - (2)].node), nodintconst(1));
+		(yyval.node)->implicit = 1;
+		(yyval.node)->etype = OSUB;
+	}
+    break;
+
+  case 56:
+#line 475 "go.y"
+    {
+		Node *n, *nn;
+
+		// will be converted to OCASE
+		// right will point to next case
+		// done in casebody()
+		markdcl();
+		(yyval.node) = nod(OXCASE, N, N);
+		(yyval.node)->list = (yyvsp[(2) - (3)].list);
+		if(typesw != N && typesw->right != N && (n=typesw->right->left) != N) {
+			// type switch - declare variable
+			nn = newname(n->sym);
+			declare(nn, dclcontext);
+			(yyval.node)->nname = nn;
+
+			// keep track of the instances for reporting unused
+			nn->defn = typesw->right;
+		}
+	}
+    break;
+
+  case 57:
+#line 495 "go.y"
+    {
+		Node *n;
+
+		// will be converted to OCASE
+		// right will point to next case
+		// done in casebody()
+		markdcl();
+		(yyval.node) = nod(OXCASE, N, N);
+		if((yyvsp[(2) - (5)].list)->next == nil)
+			n = nod(OAS, (yyvsp[(2) - (5)].list)->n, (yyvsp[(4) - (5)].node));
+		else {
+			n = nod(OAS2, N, N);
+			n->list = (yyvsp[(2) - (5)].list);
+			n->rlist = list1((yyvsp[(4) - (5)].node));
+		}
+		(yyval.node)->list = list1(n);
+	}
+    break;
+
+  case 58:
+#line 513 "go.y"
+    {
+		// will be converted to OCASE
+		// right will point to next case
+		// done in casebody()
+		markdcl();
+		(yyval.node) = nod(OXCASE, N, N);
+		(yyval.node)->list = list1(colas((yyvsp[(2) - (5)].list), list1((yyvsp[(4) - (5)].node)), (yyvsp[(3) - (5)].i)));
+	}
+    break;
+
+  case 59:
+#line 522 "go.y"
+    {
+		Node *n, *nn;
+
+		markdcl();
+		(yyval.node) = nod(OXCASE, N, N);
+		if(typesw != N && typesw->right != N && (n=typesw->right->left) != N) {
+			// type switch - declare variable
+			nn = newname(n->sym);
+			declare(nn, dclcontext);
+			(yyval.node)->nname = nn;
+
+			// keep track of the instances for reporting unused
+			nn->defn = typesw->right;
+		}
+	}
+    break;
+
+  case 60:
+#line 540 "go.y"
+    {
+		markdcl();
+	}
+    break;
+
+  case 61:
+#line 544 "go.y"
+    {
+		if((yyvsp[(3) - (4)].list) == nil)
+			(yyval.node) = nod(OEMPTY, N, N);
+		else
+			(yyval.node) = liststmt((yyvsp[(3) - (4)].list));
+		popdcl();
+	}
+    break;
+
+  case 62:
+#line 554 "go.y"
+    {
+		// If the last token read by the lexer was consumed
+		// as part of the case, clear it (parser has cleared yychar).
+		// If the last token read by the lexer was the lookahead
+		// leave it alone (parser has it cached in yychar).
+		// This is so that the stmt_list action doesn't look at
+		// the case tokens if the stmt_list is empty.
+		yylast = yychar;
+		(yyvsp[(1) - (1)].node)->xoffset = block;
+	}
+    break;
+
+  case 63:
+#line 565 "go.y"
+    {
+		int last;
+
+		// This is the only place in the language where a statement
+		// list is not allowed to drop the final semicolon, because
+		// it's the only place where a statement list is not followed 
+		// by a closing brace.  Handle the error for pedantry.
+
+		// Find the final token of the statement list.
+		// yylast is lookahead; yyprev is last of stmt_list
+		last = yyprev;
+
+		if(last > 0 && last != ';' && yychar != '}')
+			yyerror("missing statement after label");
+		(yyval.node) = (yyvsp[(1) - (3)].node);
+		(yyval.node)->nbody = (yyvsp[(3) - (3)].list);
+		popdcl();
+	}
+    break;
+
+  case 64:
+#line 585 "go.y"
+    {
+		(yyval.list) = nil;
+	}
+    break;
+
+  case 65:
+#line 589 "go.y"
+    {
+		(yyval.list) = list((yyvsp[(1) - (2)].list), (yyvsp[(2) - (2)].node));
+	}
+    break;
+
+  case 66:
+#line 595 "go.y"
+    {
+		markdcl();
+	}
+    break;
+
+  case 67:
+#line 599 "go.y"
+    {
+		(yyval.list) = (yyvsp[(3) - (4)].list);
+		popdcl();
+	}
+    break;
+
+  case 68:
+#line 606 "go.y"
+    {
+		(yyval.node) = nod(ORANGE, N, (yyvsp[(4) - (4)].node));
+		(yyval.node)->list = (yyvsp[(1) - (4)].list);
+		(yyval.node)->etype = 0;	// := flag
+	}
+    break;
+
+  case 69:
+#line 612 "go.y"
+    {
+		(yyval.node) = nod(ORANGE, N, (yyvsp[(4) - (4)].node));
+		(yyval.node)->list = (yyvsp[(1) - (4)].list);
+		(yyval.node)->colas = 1;
+		colasdefn((yyvsp[(1) - (4)].list), (yyval.node));
+	}
+    break;
+
+  case 70:
+#line 619 "go.y"
+    {
+		(yyval.node) = nod(ORANGE, N, (yyvsp[(2) - (2)].node));
+		(yyval.node)->etype = 0; // := flag
+	}
+    break;
+
+  case 71:
+#line 626 "go.y"
+    {
+		// init ; test ; incr
+		if((yyvsp[(5) - (5)].node) != N && (yyvsp[(5) - (5)].node)->colas != 0)
+			yyerror("cannot declare in the for-increment");
+		(yyval.node) = nod(OFOR, N, N);
+		if((yyvsp[(1) - (5)].node) != N)
+			(yyval.node)->ninit = list1((yyvsp[(1) - (5)].node));
+		(yyval.node)->ntest = (yyvsp[(3) - (5)].node);
+		(yyval.node)->nincr = (yyvsp[(5) - (5)].node);
+	}
+    break;
+
+  case 72:
+#line 637 "go.y"
+    {
+		// normal test
+		(yyval.node) = nod(OFOR, N, N);
+		(yyval.node)->ntest = (yyvsp[(1) - (1)].node);
+	}
+    break;
+
+  case 74:
+#line 646 "go.y"
+    {
+		(yyval.node) = (yyvsp[(1) - (2)].node);
+		(yyval.node)->nbody = concat((yyval.node)->nbody, (yyvsp[(2) - (2)].list));
+	}
+    break;
+
+  case 75:
+#line 653 "go.y"
+    {
+		markdcl();
+	}
+    break;
+
+  case 76:
+#line 657 "go.y"
+    {
+		(yyval.node) = (yyvsp[(3) - (3)].node);
+		popdcl();
+	}
+    break;
+
+  case 77:
+#line 664 "go.y"
+    {
+		// test
+		(yyval.node) = nod(OIF, N, N);
+		(yyval.node)->ntest = (yyvsp[(1) - (1)].node);
+	}
+    break;
+
+  case 78:
+#line 670 "go.y"
+    {
+		// init ; test
+		(yyval.node) = nod(OIF, N, N);
+		if((yyvsp[(1) - (3)].node) != N)
+			(yyval.node)->ninit = list1((yyvsp[(1) - (3)].node));
+		(yyval.node)->ntest = (yyvsp[(3) - (3)].node);
+	}
+    break;
+
+  case 79:
+#line 681 "go.y"
+    {
+		markdcl();
+	}
+    break;
+
+  case 80:
+#line 685 "go.y"
+    {
+		if((yyvsp[(3) - (3)].node)->ntest == N)
+			yyerror("missing condition in if statement");
+	}
+    break;
+
+  case 81:
+#line 690 "go.y"
+    {
+		(yyvsp[(3) - (5)].node)->nbody = (yyvsp[(5) - (5)].list);
+	}
+    break;
+
+  case 82:
+#line 694 "go.y"
+    {
+		Node *n;
+		NodeList *nn;
+
+		(yyval.node) = (yyvsp[(3) - (8)].node);
+		n = (yyvsp[(3) - (8)].node);
+		popdcl();
+		for(nn = concat((yyvsp[(7) - (8)].list), (yyvsp[(8) - (8)].list)); nn; nn = nn->next) {
+			if(nn->n->op == OIF)
+				popdcl();
+			n->nelse = list1(nn->n);
+			n = nn->n;
+		}
+	}
+    break;
+
+  case 83:
+#line 711 "go.y"
+    {
+		markdcl();
+	}
+    break;
+
+  case 84:
+#line 715 "go.y"
+    {
+		if((yyvsp[(4) - (5)].node)->ntest == N)
+			yyerror("missing condition in if statement");
+		(yyvsp[(4) - (5)].node)->nbody = (yyvsp[(5) - (5)].list);
+		(yyval.list) = list1((yyvsp[(4) - (5)].node));
+	}
+    break;
+
+  case 85:
+#line 723 "go.y"
+    {
+		(yyval.list) = nil;
+	}
+    break;
+
+  case 86:
+#line 727 "go.y"
+    {
+		(yyval.list) = concat((yyvsp[(1) - (2)].list), (yyvsp[(2) - (2)].list));
+	}
+    break;
+
+  case 87:
+#line 732 "go.y"
+    {
+		(yyval.list) = nil;
+	}
+    break;
+
+  case 88:
+#line 736 "go.y"
+    {
+		NodeList *node;
+		
+		node = mal(sizeof *node);
+		node->n = (yyvsp[(2) - (2)].node);
+		node->end = node;
+		(yyval.list) = node;
+	}
+    break;
+
+  case 89:
+#line 747 "go.y"
+    {
+		markdcl();
+	}
+    break;
+
+  case 90:
+#line 751 "go.y"
+    {
+		Node *n;
+		n = (yyvsp[(3) - (3)].node)->ntest;
+		if(n != N && n->op != OTYPESW)
+			n = N;
+		typesw = nod(OXXX, typesw, n);
+	}
+    break;
+
+  case 91:
+#line 759 "go.y"
+    {
+		(yyval.node) = (yyvsp[(3) - (7)].node);
+		(yyval.node)->op = OSWITCH;
+		(yyval.node)->list = (yyvsp[(6) - (7)].list);
+		typesw = typesw->left;
+		popdcl();
+	}
+    break;
+
+  case 92:
+#line 769 "go.y"
+    {
+		typesw = nod(OXXX, typesw, N);
+	}
+    break;
+
+  case 93:
+#line 773 "go.y"
+    {
+		(yyval.node) = nod(OSELECT, N, N);
+		(yyval.node)->lineno = typesw->lineno;
+		(yyval.node)->list = (yyvsp[(4) - (5)].list);
+		typesw = typesw->left;
+	}
+    break;
+
+  case 95:
+#line 786 "go.y"
+    {
+		(yyval.node) = nod(OOROR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+	}
+    break;
+
+  case 96:
+#line 790 "go.y"
+    {
+		(yyval.node) = nod(OANDAND, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+	}
+    break;
+
+  case 97:
+#line 794 "go.y"
+    {
+		(yyval.node) = nod(OEQ, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+	}
+    break;
+
+  case 98:
+#line 798 "go.y"
+    {
+		(yyval.node) = nod(ONE, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+	}
+    break;
+
+  case 99:
+#line 802 "go.y"
+    {
+		(yyval.node) = nod(OLT, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+	}
+    break;
+
+  case 100:
+#line 806 "go.y"
+    {
+		(yyval.node) = nod(OLE, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+	}
+    break;
+
+  case 101:
+#line 810 "go.y"
+    {
+		(yyval.node) = nod(OGE, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+	}
+    break;
+
+  case 102:
+#line 814 "go.y"
+    {
+		(yyval.node) = nod(OGT, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+	}
+    break;
+
+  case 103:
+#line 818 "go.y"
+    {
+		(yyval.node) = nod(OADD, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+	}
+    break;
+
+  case 104:
+#line 822 "go.y"
+    {
+		(yyval.node) = nod(OSUB, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+	}
+    break;
+
+  case 105:
+#line 826 "go.y"
+    {
+		(yyval.node) = nod(OOR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+	}
+    break;
+
+  case 106:
+#line 830 "go.y"
+    {
+		(yyval.node) = nod(OXOR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+	}
+    break;
+
+  case 107:
+#line 834 "go.y"
+    {
+		(yyval.node) = nod(OMUL, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+	}
+    break;
+
+  case 108:
+#line 838 "go.y"
+    {
+		(yyval.node) = nod(ODIV, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+	}
+    break;
+
+  case 109:
+#line 842 "go.y"
+    {
+		(yyval.node) = nod(OMOD, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+	}
+    break;
+
+  case 110:
+#line 846 "go.y"
+    {
+		(yyval.node) = nod(OAND, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+	}
+    break;
+
+  case 111:
+#line 850 "go.y"
+    {
+		(yyval.node) = nod(OANDNOT, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+	}
+    break;
+
+  case 112:
+#line 854 "go.y"
+    {
+		(yyval.node) = nod(OLSH, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+	}
+    break;
+
+  case 113:
+#line 858 "go.y"
+    {
+		(yyval.node) = nod(ORSH, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+	}
+    break;
+
+  case 114:
+#line 863 "go.y"
+    {
+		(yyval.node) = nod(OSEND, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+	}
+    break;
+
+  case 116:
+#line 870 "go.y"
+    {
+		(yyval.node) = nod(OIND, (yyvsp[(2) - (2)].node), N);
+	}
+    break;
+
+  case 117:
+#line 874 "go.y"
+    {
+		if((yyvsp[(2) - (2)].node)->op == OCOMPLIT) {
+			// Special case for &T{...}: turn into (*T){...}.
+			(yyval.node) = (yyvsp[(2) - (2)].node);
+			(yyval.node)->right = nod(OIND, (yyval.node)->right, N);
+			(yyval.node)->right->implicit = 1;
+		} else {
+			(yyval.node) = nod(OADDR, (yyvsp[(2) - (2)].node), N);
+		}
+	}
+    break;
+
+  case 118:
+#line 885 "go.y"
+    {
+		(yyval.node) = nod(OPLUS, (yyvsp[(2) - (2)].node), N);
+	}
+    break;
+
+  case 119:
+#line 889 "go.y"
+    {
+		(yyval.node) = nod(OMINUS, (yyvsp[(2) - (2)].node), N);
+	}
+    break;
+
+  case 120:
+#line 893 "go.y"
+    {
+		(yyval.node) = nod(ONOT, (yyvsp[(2) - (2)].node), N);
+	}
+    break;
+
+  case 121:
+#line 897 "go.y"
+    {
+		yyerror("the bitwise complement operator is ^");
+		(yyval.node) = nod(OCOM, (yyvsp[(2) - (2)].node), N);
+	}
+    break;
+
+  case 122:
+#line 902 "go.y"
+    {
+		(yyval.node) = nod(OCOM, (yyvsp[(2) - (2)].node), N);
+	}
+    break;
+
+  case 123:
+#line 906 "go.y"
+    {
+		(yyval.node) = nod(ORECV, (yyvsp[(2) - (2)].node), N);
+	}
+    break;
+
+  case 124:
+#line 916 "go.y"
+    {
+		(yyval.node) = nod(OCALL, (yyvsp[(1) - (3)].node), N);
+	}
+    break;
+
+  case 125:
+#line 920 "go.y"
+    {
+		(yyval.node) = nod(OCALL, (yyvsp[(1) - (5)].node), N);
+		(yyval.node)->list = (yyvsp[(3) - (5)].list);
+	}
+    break;
+
+  case 126:
+#line 925 "go.y"
+    {
+		(yyval.node) = nod(OCALL, (yyvsp[(1) - (6)].node), N);
+		(yyval.node)->list = (yyvsp[(3) - (6)].list);
+		(yyval.node)->isddd = 1;
+	}
+    break;
+
+  case 127:
+#line 933 "go.y"
+    {
+		(yyval.node) = nodlit((yyvsp[(1) - (1)].val));
+	}
+    break;
+
+  case 129:
+#line 938 "go.y"
+    {
+		if((yyvsp[(1) - (3)].node)->op == OPACK) {
+			Sym *s;
+			s = restrictlookup((yyvsp[(3) - (3)].sym)->name, (yyvsp[(1) - (3)].node)->pkg);
+			(yyvsp[(1) - (3)].node)->used = 1;
+			(yyval.node) = oldname(s);
+			break;
+		}
+		(yyval.node) = nod(OXDOT, (yyvsp[(1) - (3)].node), newname((yyvsp[(3) - (3)].sym)));
+	}
+    break;
+
+  case 130:
+#line 949 "go.y"
+    {
+		(yyval.node) = nod(ODOTTYPE, (yyvsp[(1) - (5)].node), (yyvsp[(4) - (5)].node));
+	}
+    break;
+
+  case 131:
+#line 953 "go.y"
+    {
+		(yyval.node) = nod(OTYPESW, N, (yyvsp[(1) - (5)].node));
+	}
+    break;
+
+  case 132:
+#line 957 "go.y"
+    {
+		(yyval.node) = nod(OINDEX, (yyvsp[(1) - (4)].node), (yyvsp[(3) - (4)].node));
+	}
+    break;
+
+  case 133:
+#line 961 "go.y"
+    {
+		(yyval.node) = nod(OSLICE, (yyvsp[(1) - (6)].node), nod(OKEY, (yyvsp[(3) - (6)].node), (yyvsp[(5) - (6)].node)));
+	}
+    break;
+
+  case 134:
+#line 965 "go.y"
+    {
+		if((yyvsp[(5) - (8)].node) == N)
+			yyerror("middle index required in 3-index slice");
+		if((yyvsp[(7) - (8)].node) == N)
+			yyerror("final index required in 3-index slice");
+		(yyval.node) = nod(OSLICE3, (yyvsp[(1) - (8)].node), nod(OKEY, (yyvsp[(3) - (8)].node), nod(OKEY, (yyvsp[(5) - (8)].node), (yyvsp[(7) - (8)].node))));
+	}
+    break;
+
+  case 136:
+#line 974 "go.y"
+    {
+		// conversion
+		(yyval.node) = nod(OCALL, (yyvsp[(1) - (5)].node), N);
+		(yyval.node)->list = list1((yyvsp[(3) - (5)].node));
+	}
+    break;
+
+  case 137:
+#line 980 "go.y"
+    {
+		(yyval.node) = (yyvsp[(3) - (5)].node);
+		(yyval.node)->right = (yyvsp[(1) - (5)].node);
+		(yyval.node)->list = (yyvsp[(4) - (5)].list);
+		fixlbrace((yyvsp[(2) - (5)].i));
+	}
+    break;
+
+  case 138:
+#line 987 "go.y"
+    {
+		(yyval.node) = (yyvsp[(3) - (5)].node);
+		(yyval.node)->right = (yyvsp[(1) - (5)].node);
+		(yyval.node)->list = (yyvsp[(4) - (5)].list);
+	}
+    break;
+
+  case 139:
+#line 993 "go.y"
+    {
+		yyerror("cannot parenthesize type in composite literal");
+		(yyval.node) = (yyvsp[(5) - (7)].node);
+		(yyval.node)->right = (yyvsp[(2) - (7)].node);
+		(yyval.node)->list = (yyvsp[(6) - (7)].list);
+	}
+    break;
+
+  case 141:
+#line 1002 "go.y"
+    {
+		// composite expression.
+		// make node early so we get the right line number.
+		(yyval.node) = nod(OCOMPLIT, N, N);
+	}
+    break;
+
+  case 142:
+#line 1010 "go.y"
+    {
+		(yyval.node) = nod(OKEY, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
+	}
+    break;
+
+  case 143:
+#line 1016 "go.y"
+    {
+		// These nodes do not carry line numbers.
+		// Since a composite literal commonly spans several lines,
+		// the line number on errors may be misleading.
+		// Introduce a wrapper node to give the correct line.
+		(yyval.node) = (yyvsp[(1) - (1)].node);
+		switch((yyval.node)->op) {
+		case ONAME:
+		case ONONAME:
+		case OTYPE:
+		case OPACK:
+		case OLITERAL:
+			(yyval.node) = nod(OPAREN, (yyval.node), N);
+			(yyval.node)->implicit = 1;
+		}
+	}
+    break;
+
+  case 144:
+#line 1033 "go.y"
+    {
+		(yyval.node) = (yyvsp[(2) - (4)].node);
+		(yyval.node)->list = (yyvsp[(3) - (4)].list);
+	}
+    break;
+
+  case 146:
+#line 1041 "go.y"
+    {
+		(yyval.node) = (yyvsp[(2) - (4)].node);
+		(yyval.node)->list = (yyvsp[(3) - (4)].list);
+	}
+    break;
+
+  case 148:
+#line 1049 "go.y"
+    {
+		(yyval.node) = (yyvsp[(2) - (3)].node);
+		
+		// Need to know on lhs of := whether there are ( ).
+		// Don't bother with the OPAREN in other cases:
+		// it's just a waste of memory and time.
+		switch((yyval.node)->op) {
+		case ONAME:
+		case ONONAME:
+		case OPACK:
+		case OTYPE:
+		case OLITERAL:
+		case OTYPESW:
+			(yyval.node) = nod(OPAREN, (yyval.node), N);
+		}
+	}
+    break;
+
+  case 152:
+#line 1075 "go.y"
+    {
+		(yyval.i) = LBODY;
+	}
+    break;
+
+  case 153:
+#line 1079 "go.y"
+    {
+		(yyval.i) = '{';
+	}
+    break;
+
+  case 154:
+#line 1090 "go.y"
+    {
+		if((yyvsp[(1) - (1)].sym) == S)
+			(yyval.node) = N;
+		else
+			(yyval.node) = newname((yyvsp[(1) - (1)].sym));
+	}
+    break;
+
+  case 155:
+#line 1099 "go.y"
+    {
+		(yyval.node) = dclname((yyvsp[(1) - (1)].sym));
+	}
+    break;
+
+  case 156:
+#line 1104 "go.y"
+    {
+		(yyval.node) = N;
+	}
+    break;
+
+  case 158:
+#line 1111 "go.y"
+    {
+		(yyval.sym) = (yyvsp[(1) - (1)].sym);
+		// during imports, unqualified non-exported identifiers are from builtinpkg
+		if(importpkg != nil && !exportname((yyvsp[(1) - (1)].sym)->name))
+			(yyval.sym) = pkglookup((yyvsp[(1) - (1)].sym)->name, builtinpkg);
+	}
+    break;
+
+  case 160:
+#line 1119 "go.y"
+    {
+		(yyval.sym) = S;
+	}
+    break;
+
+  case 161:
+#line 1125 "go.y"
+    {
+		Pkg *p;
+
+		if((yyvsp[(2) - (4)].val).u.sval->len == 0)
+			p = importpkg;
+		else {
+			if(isbadimport((yyvsp[(2) - (4)].val).u.sval))
+				errorexit();
+			p = mkpkg((yyvsp[(2) - (4)].val).u.sval);
+		}
+		(yyval.sym) = pkglookup((yyvsp[(4) - (4)].sym)->name, p);
+	}
+    break;
+
+  case 162:
+#line 1138 "go.y"
+    {
+		Pkg *p;
+
+		if((yyvsp[(2) - (4)].val).u.sval->len == 0)
+			p = importpkg;
+		else {
+			if(isbadimport((yyvsp[(2) - (4)].val).u.sval))
+				errorexit();
+			p = mkpkg((yyvsp[(2) - (4)].val).u.sval);
+		}
+		(yyval.sym) = pkglookup("?", p);
+	}
+    break;
+
+  case 163:
+#line 1153 "go.y"
+    {
+		(yyval.node) = oldname((yyvsp[(1) - (1)].sym));
+		if((yyval.node)->pack != N)
+			(yyval.node)->pack->used = 1;
+	}
+    break;
+
+  case 165:
+#line 1173 "go.y"
+    {
+		yyerror("final argument in variadic function missing type");
+		(yyval.node) = nod(ODDD, typenod(typ(TINTER)), N);
+	}
+    break;
+
+  case 166:
+#line 1178 "go.y"
+    {
+		(yyval.node) = nod(ODDD, (yyvsp[(2) - (2)].node), N);
+	}
+    break;
+
+  case 172:
+#line 1189 "go.y"
+    {
+		(yyval.node) = (yyvsp[(2) - (3)].node);
+	}
+    break;
+
+  case 176:
+#line 1198 "go.y"
+    {
+		(yyval.node) = nod(OIND, (yyvsp[(2) - (2)].node), N);
+	}
+    break;
+
+  case 181:
+#line 1208 "go.y"
+    {
+		(yyval.node) = (yyvsp[(2) - (3)].node);
+	}
+    break;
+
+  case 191:
+#line 1229 "go.y"
+    {
+		if((yyvsp[(1) - (3)].node)->op == OPACK) {
+			Sym *s;
+			s = restrictlookup((yyvsp[(3) - (3)].sym)->name, (yyvsp[(1) - (3)].node)->pkg);
+			(yyvsp[(1) - (3)].node)->used = 1;
+			(yyval.node) = oldname(s);
+			break;
+		}
+		(yyval.node) = nod(OXDOT, (yyvsp[(1) - (3)].node), newname((yyvsp[(3) - (3)].sym)));
+	}
+    break;
+
+  case 192:
+#line 1242 "go.y"
+    {
+		(yyval.node) = nod(OTARRAY, (yyvsp[(2) - (4)].node), (yyvsp[(4) - (4)].node));
+	}
+    break;
+
+  case 193:
+#line 1246 "go.y"
+    {
+		// array literal of nelem
+		(yyval.node) = nod(OTARRAY, nod(ODDD, N, N), (yyvsp[(4) - (4)].node));
+	}
+    break;
+
+  case 194:
+#line 1251 "go.y"
+    {
+		(yyval.node) = nod(OTCHAN, (yyvsp[(2) - (2)].node), N);
+		(yyval.node)->etype = Cboth;
+	}
+    break;
+
+  case 195:
+#line 1256 "go.y"
+    {
+		(yyval.node) = nod(OTCHAN, (yyvsp[(3) - (3)].node), N);
+		(yyval.node)->etype = Csend;
+	}
+    break;
+
+  case 196:
+#line 1261 "go.y"
+    {
+		(yyval.node) = nod(OTMAP, (yyvsp[(3) - (5)].node), (yyvsp[(5) - (5)].node));
+	}
+    break;
+
+  case 199:
+#line 1269 "go.y"
+    {
+		(yyval.node) = nod(OIND, (yyvsp[(2) - (2)].node), N);
+	}
+    break;
+
+  case 200:
+#line 1275 "go.y"
+    {
+		(yyval.node) = nod(OTCHAN, (yyvsp[(3) - (3)].node), N);
+		(yyval.node)->etype = Crecv;
+	}
+    break;
+
+  case 201:
+#line 1282 "go.y"
+    {
+		(yyval.node) = nod(OTSTRUCT, N, N);
+		(yyval.node)->list = (yyvsp[(3) - (5)].list);
+		fixlbrace((yyvsp[(2) - (5)].i));
+	}
+    break;
+
+  case 202:
+#line 1288 "go.y"
+    {
+		(yyval.node) = nod(OTSTRUCT, N, N);
+		fixlbrace((yyvsp[(2) - (3)].i));
+	}
+    break;
+
+  case 203:
+#line 1295 "go.y"
+    {
+		(yyval.node) = nod(OTINTER, N, N);
+		(yyval.node)->list = (yyvsp[(3) - (5)].list);
+		fixlbrace((yyvsp[(2) - (5)].i));
+	}
+    break;
+
+  case 204:
+#line 1301 "go.y"
+    {
+		(yyval.node) = nod(OTINTER, N, N);
+		fixlbrace((yyvsp[(2) - (3)].i));
+	}
+    break;
+
+  case 205:
+#line 1312 "go.y"
+    {
+		(yyval.node) = (yyvsp[(2) - (3)].node);
+		if((yyval.node) == N)
+			break;
+		if(noescape && (yyvsp[(3) - (3)].list) != nil)
+			yyerror("can only use //go:noescape with external func implementations");
+		(yyval.node)->nbody = (yyvsp[(3) - (3)].list);
+		(yyval.node)->endlineno = lineno;
+		(yyval.node)->noescape = noescape;
+		(yyval.node)->nosplit = nosplit;
+		funcbody((yyval.node));
+	}
+    break;
+
+  case 206:
+#line 1327 "go.y"
+    {
+		Node *t;
+
+		(yyval.node) = N;
+		(yyvsp[(3) - (5)].list) = checkarglist((yyvsp[(3) - (5)].list), 1);
+
+		if(strcmp((yyvsp[(1) - (5)].sym)->name, "init") == 0) {
+			(yyvsp[(1) - (5)].sym) = renameinit();
+			if((yyvsp[(3) - (5)].list) != nil || (yyvsp[(5) - (5)].list) != nil)
+				yyerror("func init must have no arguments and no return values");
+		}
+		if(strcmp(localpkg->name, "main") == 0 && strcmp((yyvsp[(1) - (5)].sym)->name, "main") == 0) {
+			if((yyvsp[(3) - (5)].list) != nil || (yyvsp[(5) - (5)].list) != nil)
+				yyerror("func main must have no arguments and no return values");
+		}
+
+		t = nod(OTFUNC, N, N);
+		t->list = (yyvsp[(3) - (5)].list);
+		t->rlist = (yyvsp[(5) - (5)].list);
+
+		(yyval.node) = nod(ODCLFUNC, N, N);
+		(yyval.node)->nname = newname((yyvsp[(1) - (5)].sym));
+		(yyval.node)->nname->defn = (yyval.node);
+		(yyval.node)->nname->ntype = t;		// TODO: check if nname already has an ntype
+		declare((yyval.node)->nname, PFUNC);
+
+		funchdr((yyval.node));
+	}
+    break;
+
+  case 207:
+#line 1356 "go.y"
+    {
+		Node *rcvr, *t;
+
+		(yyval.node) = N;
+		(yyvsp[(2) - (8)].list) = checkarglist((yyvsp[(2) - (8)].list), 0);
+		(yyvsp[(6) - (8)].list) = checkarglist((yyvsp[(6) - (8)].list), 1);
+
+		if((yyvsp[(2) - (8)].list) == nil) {
+			yyerror("method has no receiver");
+			break;
+		}
+		if((yyvsp[(2) - (8)].list)->next != nil) {
+			yyerror("method has multiple receivers");
+			break;
+		}
+		rcvr = (yyvsp[(2) - (8)].list)->n;
+		if(rcvr->op != ODCLFIELD) {
+			yyerror("bad receiver in method");
+			break;
+		}
+
+		t = nod(OTFUNC, rcvr, N);
+		t->list = (yyvsp[(6) - (8)].list);
+		t->rlist = (yyvsp[(8) - (8)].list);
+
+		(yyval.node) = nod(ODCLFUNC, N, N);
+		(yyval.node)->shortname = newname((yyvsp[(4) - (8)].sym));
+		(yyval.node)->nname = methodname1((yyval.node)->shortname, rcvr->right);
+		(yyval.node)->nname->defn = (yyval.node);
+		(yyval.node)->nname->ntype = t;
+		(yyval.node)->nname->nointerface = nointerface;
+		declare((yyval.node)->nname, PFUNC);
+
+		funchdr((yyval.node));
+	}
+    break;
+
+  case 208:
+#line 1394 "go.y"
+    {
+		Sym *s;
+		Type *t;
+
+		(yyval.node) = N;
+
+		s = (yyvsp[(1) - (5)].sym);
+		t = functype(N, (yyvsp[(3) - (5)].list), (yyvsp[(5) - (5)].list));
+
+		importsym(s, ONAME);
+		if(s->def != N && s->def->op == ONAME) {
+			if(eqtype(t, s->def->type)) {
+				dclcontext = PDISCARD;  // since we skip funchdr below
+				break;
+			}
+			yyerror("inconsistent definition for func %S during import\n\t%T\n\t%T", s, s->def->type, t);
+		}
+
+		(yyval.node) = newname(s);
+		(yyval.node)->type = t;
+		declare((yyval.node), PFUNC);
+
+		funchdr((yyval.node));
+	}
+    break;
+
+  case 209:
+#line 1419 "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));
+
+		checkwidth((yyval.node)->type);
+		addmethod((yyvsp[(4) - (8)].sym), (yyval.node)->type, 0, nointerface);
+		nointerface = 0;
+		funchdr((yyval.node));
+		
+		// inl.c's inlnode in on a dotmeth node expects to find the inlineable body as
+		// (dotmeth's type)->nname->inl, and dotmeth's type has been pulled
+		// out by typecheck's lookdot as this $$->ttype.  So by providing
+		// this back link here we avoid special casing there.
+		(yyval.node)->type->nname = (yyval.node);
+	}
+    break;
+
+  case 210:
+#line 1437 "go.y"
+    {
+		(yyvsp[(3) - (5)].list) = checkarglist((yyvsp[(3) - (5)].list), 1);
+		(yyval.node) = nod(OTFUNC, N, N);
+		(yyval.node)->list = (yyvsp[(3) - (5)].list);
+		(yyval.node)->rlist = (yyvsp[(5) - (5)].list);
+	}
+    break;
+
+  case 211:
+#line 1445 "go.y"
+    {
+		(yyval.list) = nil;
+	}
+    break;
+
+  case 212:
+#line 1449 "go.y"
+    {
+		(yyval.list) = (yyvsp[(2) - (3)].list);
+		if((yyval.list) == nil)
+			(yyval.list) = list1(nod(OEMPTY, N, N));
+	}
+    break;
+
+  case 213:
+#line 1457 "go.y"
+    {
+		(yyval.list) = nil;
+	}
+    break;
+
+  case 214:
+#line 1461 "go.y"
+    {
+		(yyval.list) = list1(nod(ODCLFIELD, N, (yyvsp[(1) - (1)].node)));
+	}
+    break;
+
+  case 215:
+#line 1465 "go.y"
+    {
+		(yyvsp[(2) - (3)].list) = checkarglist((yyvsp[(2) - (3)].list), 0);
+		(yyval.list) = (yyvsp[(2) - (3)].list);
+	}
+    break;
+
+  case 216:
+#line 1472 "go.y"
+    {
+		closurehdr((yyvsp[(1) - (1)].node));
+	}
+    break;
+
+  case 217:
+#line 1478 "go.y"
+    {
+		(yyval.node) = closurebody((yyvsp[(3) - (4)].list));
+		fixlbrace((yyvsp[(2) - (4)].i));
+	}
+    break;
+
+  case 218:
+#line 1483 "go.y"
+    {
+		(yyval.node) = closurebody(nil);
+	}
+    break;
+
+  case 219:
+#line 1494 "go.y"
+    {
+		(yyval.list) = nil;
+	}
+    break;
+
+  case 220:
+#line 1498 "go.y"
+    {
+		(yyval.list) = concat((yyvsp[(1) - (3)].list), (yyvsp[(2) - (3)].list));
+		if(nsyntaxerrors == 0)
+			testdclstack();
+		nointerface = 0;
+		noescape = 0;
+		nosplit = 0;
+	}
+    break;
+
+  case 222:
+#line 1510 "go.y"
+    {
+		(yyval.list) = concat((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].list));
+	}
+    break;
+
+  case 224:
+#line 1517 "go.y"
+    {
+		(yyval.list) = concat((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].list));
+	}
+    break;
+
+  case 225:
+#line 1523 "go.y"
+    {
+		(yyval.list) = list1((yyvsp[(1) - (1)].node));
+	}
+    break;
+
+  case 226:
+#line 1527 "go.y"
+    {
+		(yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
+	}
+    break;
+
+  case 228:
+#line 1534 "go.y"
+    {
+		(yyval.list) = concat((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].list));
+	}
+    break;
+
+  case 229:
+#line 1540 "go.y"
+    {
+		(yyval.list) = list1((yyvsp[(1) - (1)].node));
+	}
+    break;
+
+  case 230:
+#line 1544 "go.y"
+    {
+		(yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
+	}
+    break;
+
+  case 231:
+#line 1550 "go.y"
+    {
+		NodeList *l;
+
+		Node *n;
+		l = (yyvsp[(1) - (3)].list);
+		if(l == nil) {
+			// ? symbol, during import (list1(N) == nil)
+			n = (yyvsp[(2) - (3)].node);
+			if(n->op == OIND)
+				n = n->left;
+			n = embedded(n->sym, importpkg);
+			n->right = (yyvsp[(2) - (3)].node);
+			n->val = (yyvsp[(3) - (3)].val);
+			(yyval.list) = list1(n);
+			break;
+		}
+
+		for(l=(yyvsp[(1) - (3)].list); l; l=l->next) {
+			l->n = nod(ODCLFIELD, l->n, (yyvsp[(2) - (3)].node));
+			l->n->val = (yyvsp[(3) - (3)].val);
+		}
+	}
+    break;
+
+  case 232:
+#line 1573 "go.y"
+    {
+		(yyvsp[(1) - (2)].node)->val = (yyvsp[(2) - (2)].val);
+		(yyval.list) = list1((yyvsp[(1) - (2)].node));
+	}
+    break;
+
+  case 233:
+#line 1578 "go.y"
+    {
+		(yyvsp[(2) - (4)].node)->val = (yyvsp[(4) - (4)].val);
+		(yyval.list) = list1((yyvsp[(2) - (4)].node));
+		yyerror("cannot parenthesize embedded type");
+	}
+    break;
+
+  case 234:
+#line 1584 "go.y"
+    {
+		(yyvsp[(2) - (3)].node)->right = nod(OIND, (yyvsp[(2) - (3)].node)->right, N);
+		(yyvsp[(2) - (3)].node)->val = (yyvsp[(3) - (3)].val);
+		(yyval.list) = list1((yyvsp[(2) - (3)].node));
+	}
+    break;
+
+  case 235:
+#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);
+		(yyval.list) = list1((yyvsp[(3) - (5)].node));
+		yyerror("cannot parenthesize embedded type");
+	}
+    break;
+
+  case 236:
+#line 1597 "go.y"
+    {
+		(yyvsp[(3) - (5)].node)->right = nod(OIND, (yyvsp[(3) - (5)].node)->right, N);
+		(yyvsp[(3) - (5)].node)->val = (yyvsp[(5) - (5)].val);
+		(yyval.list) = list1((yyvsp[(3) - (5)].node));
+		yyerror("cannot parenthesize embedded type");
+	}
+    break;
+
+  case 237:
+#line 1606 "go.y"
+    {
+		Node *n;
+
+		(yyval.sym) = (yyvsp[(1) - (1)].sym);
+		n = oldname((yyvsp[(1) - (1)].sym));
+		if(n->pack != N)
+			n->pack->used = 1;
+	}
+    break;
+
+  case 238:
+#line 1615 "go.y"
+    {
+		Pkg *pkg;
+
+		if((yyvsp[(1) - (3)].sym)->def == N || (yyvsp[(1) - (3)].sym)->def->op != OPACK) {
+			yyerror("%S is not a package", (yyvsp[(1) - (3)].sym));
+			pkg = localpkg;
+		} else {
+			(yyvsp[(1) - (3)].sym)->def->used = 1;
+			pkg = (yyvsp[(1) - (3)].sym)->def->pkg;
+		}
+		(yyval.sym) = restrictlookup((yyvsp[(3) - (3)].sym)->name, pkg);
+	}
+    break;
+
+  case 239:
+#line 1630 "go.y"
+    {
+		(yyval.node) = embedded((yyvsp[(1) - (1)].sym), localpkg);
+	}
+    break;
+
+  case 240:
+#line 1636 "go.y"
+    {
+		(yyval.node) = nod(ODCLFIELD, (yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].node));
+		ifacedcl((yyval.node));
+	}
+    break;
+
+  case 241:
+#line 1641 "go.y"
+    {
+		(yyval.node) = nod(ODCLFIELD, N, oldname((yyvsp[(1) - (1)].sym)));
+	}
+    break;
+
+  case 242:
+#line 1645 "go.y"
+    {
+		(yyval.node) = nod(ODCLFIELD, N, oldname((yyvsp[(2) - (3)].sym)));
+		yyerror("cannot parenthesize embedded type");
+	}
+    break;
+
+  case 243:
+#line 1652 "go.y"
+    {
+		// without func keyword
+		(yyvsp[(2) - (4)].list) = checkarglist((yyvsp[(2) - (4)].list), 1);
+		(yyval.node) = nod(OTFUNC, fakethis(), N);
+		(yyval.node)->list = (yyvsp[(2) - (4)].list);
+		(yyval.node)->rlist = (yyvsp[(4) - (4)].list);
+	}
+    break;
+
+  case 245:
+#line 1666 "go.y"
+    {
+		(yyval.node) = nod(ONONAME, N, N);
+		(yyval.node)->sym = (yyvsp[(1) - (2)].sym);
+		(yyval.node) = nod(OKEY, (yyval.node), (yyvsp[(2) - (2)].node));
+	}
+    break;
+
+  case 246:
+#line 1672 "go.y"
+    {
+		(yyval.node) = nod(ONONAME, N, N);
+		(yyval.node)->sym = (yyvsp[(1) - (2)].sym);
+		(yyval.node) = nod(OKEY, (yyval.node), (yyvsp[(2) - (2)].node));
+	}
+    break;
+
+  case 248:
+#line 1681 "go.y"
+    {
+		(yyval.list) = list1((yyvsp[(1) - (1)].node));
+	}
+    break;
+
+  case 249:
+#line 1685 "go.y"
+    {
+		(yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
+	}
+    break;
+
+  case 250:
+#line 1690 "go.y"
+    {
+		(yyval.list) = nil;
+	}
+    break;
+
+  case 251:
+#line 1694 "go.y"
+    {
+		(yyval.list) = (yyvsp[(1) - (2)].list);
+	}
+    break;
+
+  case 252:
+#line 1702 "go.y"
+    {
+		(yyval.node) = N;
+	}
+    break;
+
+  case 254:
+#line 1707 "go.y"
+    {
+		(yyval.node) = liststmt((yyvsp[(1) - (1)].list));
+	}
+    break;
+
+  case 256:
+#line 1712 "go.y"
+    {
+		(yyval.node) = N;
+	}
+    break;
+
+  case 262:
+#line 1723 "go.y"
+    {
+		(yyvsp[(1) - (2)].node) = nod(OLABEL, (yyvsp[(1) - (2)].node), N);
+		(yyvsp[(1) - (2)].node)->sym = dclstack;  // context, for goto restrictions
+	}
+    break;
+
+  case 263:
+#line 1728 "go.y"
+    {
+		NodeList *l;
+
+		(yyvsp[(1) - (4)].node)->defn = (yyvsp[(4) - (4)].node);
+		l = list1((yyvsp[(1) - (4)].node));
+		if((yyvsp[(4) - (4)].node))
+			l = list(l, (yyvsp[(4) - (4)].node));
+		(yyval.node) = liststmt(l);
+	}
+    break;
+
+  case 264:
+#line 1738 "go.y"
+    {
+		// will be converted to OFALL
+		(yyval.node) = nod(OXFALL, N, N);
+		(yyval.node)->xoffset = block;
+	}
+    break;
+
+  case 265:
+#line 1744 "go.y"
+    {
+		(yyval.node) = nod(OBREAK, (yyvsp[(2) - (2)].node), N);
+	}
+    break;
+
+  case 266:
+#line 1748 "go.y"
+    {
+		(yyval.node) = nod(OCONTINUE, (yyvsp[(2) - (2)].node), N);
+	}
+    break;
+
+  case 267:
+#line 1752 "go.y"
+    {
+		(yyval.node) = nod(OPROC, (yyvsp[(2) - (2)].node), N);
+	}
+    break;
+
+  case 268:
+#line 1756 "go.y"
+    {
+		(yyval.node) = nod(ODEFER, (yyvsp[(2) - (2)].node), N);
+	}
+    break;
+
+  case 269:
+#line 1760 "go.y"
+    {
+		(yyval.node) = nod(OGOTO, (yyvsp[(2) - (2)].node), N);
+		(yyval.node)->sym = dclstack;  // context, for goto restrictions
+	}
+    break;
+
+  case 270:
+#line 1765 "go.y"
+    {
+		(yyval.node) = nod(ORETURN, N, N);
+		(yyval.node)->list = (yyvsp[(2) - (2)].list);
+		if((yyval.node)->list == nil && curfn != N) {
+			NodeList *l;
+
+			for(l=curfn->dcl; l; l=l->next) {
+				if(l->n->class == PPARAM)
+					continue;
+				if(l->n->class != PPARAMOUT)
+					break;
+				if(l->n->sym->def != l->n)
+					yyerror("%s is shadowed during return", l->n->sym->name);
+			}
+		}
+	}
+    break;
+
+  case 271:
+#line 1784 "go.y"
+    {
+		(yyval.list) = nil;
+		if((yyvsp[(1) - (1)].node) != N)
+			(yyval.list) = list1((yyvsp[(1) - (1)].node));
+	}
+    break;
+
+  case 272:
+#line 1790 "go.y"
+    {
+		(yyval.list) = (yyvsp[(1) - (3)].list);
+		if((yyvsp[(3) - (3)].node) != N)
+			(yyval.list) = list((yyval.list), (yyvsp[(3) - (3)].node));
+	}
+    break;
+
+  case 273:
+#line 1798 "go.y"
+    {
+		(yyval.list) = list1((yyvsp[(1) - (1)].node));
+	}
+    break;
+
+  case 274:
+#line 1802 "go.y"
+    {
+		(yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
+	}
+    break;
+
+  case 275:
+#line 1808 "go.y"
+    {
+		(yyval.list) = list1((yyvsp[(1) - (1)].node));
+	}
+    break;
+
+  case 276:
+#line 1812 "go.y"
+    {
+		(yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
+	}
+    break;
+
+  case 277:
+#line 1818 "go.y"
+    {
+		(yyval.list) = list1((yyvsp[(1) - (1)].node));
+	}
+    break;
+
+  case 278:
+#line 1822 "go.y"
+    {
+		(yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
+	}
+    break;
+
+  case 279:
+#line 1828 "go.y"
+    {
+		(yyval.list) = list1((yyvsp[(1) - (1)].node));
+	}
+    break;
+
+  case 280:
+#line 1832 "go.y"
+    {
+		(yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
+	}
+    break;
+
+  case 281:
+#line 1841 "go.y"
+    {
+		(yyval.list) = list1((yyvsp[(1) - (1)].node));
+	}
+    break;
+
+  case 282:
+#line 1845 "go.y"
+    {
+		(yyval.list) = list1((yyvsp[(1) - (1)].node));
+	}
+    break;
+
+  case 283:
+#line 1849 "go.y"
+    {
+		(yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
+	}
+    break;
+
+  case 284:
+#line 1853 "go.y"
+    {
+		(yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
+	}
+    break;
+
+  case 285:
+#line 1858 "go.y"
+    {
+		(yyval.list) = nil;
+	}
+    break;
+
+  case 286:
+#line 1862 "go.y"
+    {
+		(yyval.list) = (yyvsp[(1) - (2)].list);
+	}
+    break;
+
+  case 291:
+#line 1876 "go.y"
+    {
+		(yyval.node) = N;
+	}
+    break;
+
+  case 293:
+#line 1882 "go.y"
+    {
+		(yyval.list) = nil;
+	}
+    break;
+
+  case 295:
+#line 1888 "go.y"
+    {
+		(yyval.node) = N;
+	}
+    break;
+
+  case 297:
+#line 1894 "go.y"
+    {
+		(yyval.list) = nil;
+	}
+    break;
+
+  case 299:
+#line 1900 "go.y"
+    {
+		(yyval.list) = nil;
+	}
+    break;
+
+  case 301:
+#line 1906 "go.y"
+    {
+		(yyval.list) = nil;
+	}
+    break;
+
+  case 303:
+#line 1912 "go.y"
+    {
+		(yyval.val).ctype = CTxxx;
+	}
+    break;
+
+  case 305:
+#line 1922 "go.y"
+    {
+		importimport((yyvsp[(2) - (4)].sym), (yyvsp[(3) - (4)].val).u.sval);
+	}
+    break;
+
+  case 306:
+#line 1926 "go.y"
+    {
+		importvar((yyvsp[(2) - (4)].sym), (yyvsp[(3) - (4)].type));
+	}
+    break;
+
+  case 307:
+#line 1930 "go.y"
+    {
+		importconst((yyvsp[(2) - (5)].sym), types[TIDEAL], (yyvsp[(4) - (5)].node));
+	}
+    break;
+
+  case 308:
+#line 1934 "go.y"
+    {
+		importconst((yyvsp[(2) - (6)].sym), (yyvsp[(3) - (6)].type), (yyvsp[(5) - (6)].node));
+	}
+    break;
+
+  case 309:
+#line 1938 "go.y"
+    {
+		importtype((yyvsp[(2) - (4)].type), (yyvsp[(3) - (4)].type));
+	}
+    break;
+
+  case 310:
+#line 1942 "go.y"
+    {
+		if((yyvsp[(2) - (4)].node) == N) {
+			dclcontext = PEXTERN;  // since we skip the funcbody below
+			break;
+		}
+
+		(yyvsp[(2) - (4)].node)->inl = (yyvsp[(3) - (4)].list);
+
+		funcbody((yyvsp[(2) - (4)].node));
+		importlist = list(importlist, (yyvsp[(2) - (4)].node));
+
+		if(debug['E']) {
+			print("import [%Z] func %lN \n", importpkg->path, (yyvsp[(2) - (4)].node));
+			if(debug['m'] > 2 && (yyvsp[(2) - (4)].node)->inl)
+				print("inl body:%+H\n", (yyvsp[(2) - (4)].node)->inl);
+		}
+	}
+    break;
+
+  case 311:
+#line 1962 "go.y"
+    {
+		(yyval.sym) = (yyvsp[(1) - (1)].sym);
+		structpkg = (yyval.sym)->pkg;
+	}
+    break;
+
+  case 312:
+#line 1969 "go.y"
+    {
+		(yyval.type) = pkgtype((yyvsp[(1) - (1)].sym));
+		importsym((yyvsp[(1) - (1)].sym), OTYPE);
+	}
+    break;
+
+  case 318:
+#line 1989 "go.y"
+    {
+		(yyval.type) = pkgtype((yyvsp[(1) - (1)].sym));
+	}
+    break;
+
+  case 319:
+#line 1993 "go.y"
+    {
+		// predefined name like uint8
+		(yyvsp[(1) - (1)].sym) = pkglookup((yyvsp[(1) - (1)].sym)->name, builtinpkg);
+		if((yyvsp[(1) - (1)].sym)->def == N || (yyvsp[(1) - (1)].sym)->def->op != OTYPE) {
+			yyerror("%s is not a type", (yyvsp[(1) - (1)].sym)->name);
+			(yyval.type) = T;
+		} else
+			(yyval.type) = (yyvsp[(1) - (1)].sym)->def->type;
+	}
+    break;
+
+  case 320:
+#line 2003 "go.y"
+    {
+		(yyval.type) = aindex(N, (yyvsp[(3) - (3)].type));
+	}
+    break;
+
+  case 321:
+#line 2007 "go.y"
+    {
+		(yyval.type) = aindex(nodlit((yyvsp[(2) - (4)].val)), (yyvsp[(4) - (4)].type));
+	}
+    break;
+
+  case 322:
+#line 2011 "go.y"
+    {
+		(yyval.type) = maptype((yyvsp[(3) - (5)].type), (yyvsp[(5) - (5)].type));
+	}
+    break;
+
+  case 323:
+#line 2015 "go.y"
+    {
+		(yyval.type) = tostruct((yyvsp[(3) - (4)].list));
+	}
+    break;
+
+  case 324:
+#line 2019 "go.y"
+    {
+		(yyval.type) = tointerface((yyvsp[(3) - (4)].list));
+	}
+    break;
+
+  case 325:
+#line 2023 "go.y"
+    {
+		(yyval.type) = ptrto((yyvsp[(2) - (2)].type));
+	}
+    break;
+
+  case 326:
+#line 2027 "go.y"
+    {
+		(yyval.type) = typ(TCHAN);
+		(yyval.type)->type = (yyvsp[(2) - (2)].type);
+		(yyval.type)->chan = Cboth;
+	}
+    break;
+
+  case 327:
+#line 2033 "go.y"
+    {
+		(yyval.type) = typ(TCHAN);
+		(yyval.type)->type = (yyvsp[(3) - (4)].type);
+		(yyval.type)->chan = Cboth;
+	}
+    break;
+
+  case 328:
+#line 2039 "go.y"
+    {
+		(yyval.type) = typ(TCHAN);
+		(yyval.type)->type = (yyvsp[(3) - (3)].type);
+		(yyval.type)->chan = Csend;
+	}
+    break;
+
+  case 329:
+#line 2047 "go.y"
+    {
+		(yyval.type) = typ(TCHAN);
+		(yyval.type)->type = (yyvsp[(3) - (3)].type);
+		(yyval.type)->chan = Crecv;
+	}
+    break;
+
+  case 330:
+#line 2055 "go.y"
+    {
+		(yyval.type) = functype(nil, (yyvsp[(3) - (5)].list), (yyvsp[(5) - (5)].list));
+	}
+    break;
+
+  case 331:
+#line 2061 "go.y"
+    {
+		(yyval.node) = nod(ODCLFIELD, N, typenod((yyvsp[(2) - (3)].type)));
+		if((yyvsp[(1) - (3)].sym))
+			(yyval.node)->left = newname((yyvsp[(1) - (3)].sym));
+		(yyval.node)->val = (yyvsp[(3) - (3)].val);
+	}
+    break;
+
+  case 332:
+#line 2068 "go.y"
+    {
+		Type *t;
+	
+		t = typ(TARRAY);
+		t->bound = -1;
+		t->type = (yyvsp[(3) - (4)].type);
+
+		(yyval.node) = nod(ODCLFIELD, N, typenod(t));
+		if((yyvsp[(1) - (4)].sym))
+			(yyval.node)->left = newname((yyvsp[(1) - (4)].sym));
+		(yyval.node)->isddd = 1;
+		(yyval.node)->val = (yyvsp[(4) - (4)].val);
+	}
+    break;
+
+  case 333:
+#line 2084 "go.y"
+    {
+		Sym *s;
+		Pkg *p;
+
+		if((yyvsp[(1) - (3)].sym) != S && strcmp((yyvsp[(1) - (3)].sym)->name, "?") != 0) {
+			(yyval.node) = nod(ODCLFIELD, newname((yyvsp[(1) - (3)].sym)), typenod((yyvsp[(2) - (3)].type)));
+			(yyval.node)->val = (yyvsp[(3) - (3)].val);
+		} else {
+			s = (yyvsp[(2) - (3)].type)->sym;
+			if(s == S && isptr[(yyvsp[(2) - (3)].type)->etype])
+				s = (yyvsp[(2) - (3)].type)->type->sym;
+			p = importpkg;
+			if((yyvsp[(1) - (3)].sym) != S)
+				p = (yyvsp[(1) - (3)].sym)->pkg;
+			(yyval.node) = embedded(s, p);
+			(yyval.node)->right = typenod((yyvsp[(2) - (3)].type));
+			(yyval.node)->val = (yyvsp[(3) - (3)].val);
+		}
+	}
+    break;
+
+  case 334:
+#line 2106 "go.y"
+    {
+		(yyval.node) = nod(ODCLFIELD, newname((yyvsp[(1) - (5)].sym)), typenod(functype(fakethis(), (yyvsp[(3) - (5)].list), (yyvsp[(5) - (5)].list))));
+	}
+    break;
+
+  case 335:
+#line 2110 "go.y"
+    {
+		(yyval.node) = nod(ODCLFIELD, N, typenod((yyvsp[(1) - (1)].type)));
+	}
+    break;
+
+  case 336:
+#line 2115 "go.y"
+    {
+		(yyval.list) = nil;
+	}
+    break;
+
+  case 338:
+#line 2122 "go.y"
+    {
+		(yyval.list) = (yyvsp[(2) - (3)].list);
+	}
+    break;
+
+  case 339:
+#line 2126 "go.y"
+    {
+		(yyval.list) = list1(nod(ODCLFIELD, N, typenod((yyvsp[(1) - (1)].type))));
+	}
+    break;
+
+  case 340:
+#line 2136 "go.y"
+    {
+		(yyval.node) = nodlit((yyvsp[(1) - (1)].val));
+	}
+    break;
+
+  case 341:
+#line 2140 "go.y"
+    {
+		(yyval.node) = nodlit((yyvsp[(2) - (2)].val));
+		switch((yyval.node)->val.ctype){
+		case CTINT:
+		case CTRUNE:
+			mpnegfix((yyval.node)->val.u.xval);
+			break;
+		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");
+		}
+	}
+    break;
+
+  case 342:
+#line 2159 "go.y"
+    {
+		(yyval.node) = oldname(pkglookup((yyvsp[(1) - (1)].sym)->name, builtinpkg));
+		if((yyval.node)->op != OLITERAL)
+			yyerror("bad constant %S", (yyval.node)->sym);
+	}
+    break;
+
+  case 344:
+#line 2168 "go.y"
+    {
+		if((yyvsp[(2) - (5)].node)->val.ctype == CTRUNE && (yyvsp[(4) - (5)].node)->val.ctype == CTINT) {
+			(yyval.node) = (yyvsp[(2) - (5)].node);
+			mpaddfixfix((yyvsp[(2) - (5)].node)->val.u.xval, (yyvsp[(4) - (5)].node)->val.u.xval, 0);
+			break;
+		}
+		(yyvsp[(4) - (5)].node)->val.u.cval->real = (yyvsp[(4) - (5)].node)->val.u.cval->imag;
+		mpmovecflt(&(yyvsp[(4) - (5)].node)->val.u.cval->imag, 0.0);
+		(yyval.node) = nodcplxlit((yyvsp[(2) - (5)].node)->val, (yyvsp[(4) - (5)].node)->val);
+	}
+    break;
+
+  case 347:
+#line 2184 "go.y"
+    {
+		(yyval.list) = list1((yyvsp[(1) - (1)].node));
+	}
+    break;
+
+  case 348:
+#line 2188 "go.y"
+    {
+		(yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
+	}
+    break;
+
+  case 349:
+#line 2194 "go.y"
+    {
+		(yyval.list) = list1((yyvsp[(1) - (1)].node));
+	}
+    break;
+
+  case 350:
+#line 2198 "go.y"
+    {
+		(yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
+	}
+    break;
+
+  case 351:
+#line 2204 "go.y"
+    {
+		(yyval.list) = list1((yyvsp[(1) - (1)].node));
+	}
+    break;
+
+  case 352:
+#line 2208 "go.y"
+    {
+		(yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
+	}
+    break;
+
+
+/* Line 1267 of yacc.c.  */
+#line 4907 "y.tab.c"
+      default: break;
+    }
+  YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
+
+  YYPOPSTACK (yylen);
+  yylen = 0;
+  YY_STACK_PRINT (yyss, yyssp);
+
+  *++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.  */
+
+  yyn = yyr1[yyn];
+
+  yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+  if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+    yystate = yytable[yystate];
+  else
+    yystate = yydefgoto[yyn - YYNTOKENS];
+
+  goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+  /* If not already recovering from an error, report this error.  */
+  if (!yyerrstatus)
+    {
+      ++yynerrs;
+#if ! YYERROR_VERBOSE
+      yyerror (YY_("syntax error"));
+#else
+      {
+	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;
+	  }
+      }
+#endif
+    }
+
+
+
+  if (yyerrstatus == 3)
+    {
+      /* If just tried and failed to reuse look-ahead token after an
+	 error, discard it.  */
+
+      if (yychar <= YYEOF)
+	{
+	  /* Return failure if at end of input.  */
+	  if (yychar == YYEOF)
+	    YYABORT;
+	}
+      else
+	{
+	  yydestruct ("Error: discarding",
+		      yytoken, &yylval);
+	  yychar = YYEMPTY;
+	}
+    }
+
+  /* Else will try to reuse look-ahead token after shifting the error
+     token.  */
+  goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR.  |
+`---------------------------------------------------*/
+yyerrorlab:
+
+  /* Pacify compilers like GCC when the user code never invokes
+     YYERROR and the label yyerrorlab therefore never appears in user
+     code.  */
+  if (/*CONSTCOND*/ 0)
+     goto yyerrorlab;
+
+  /* Do not reclaim the symbols of the rule which action triggered
+     this YYERROR.  */
+  YYPOPSTACK (yylen);
+  yylen = 0;
+  YY_STACK_PRINT (yyss, yyssp);
+  yystate = *yyssp;
+  goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR.  |
+`-------------------------------------------------------------*/
+yyerrlab1:
+  yyerrstatus = 3;	/* Each real token shifted decrements this.  */
+
+  for (;;)
+    {
+      yyn = yypact[yystate];
+      if (yyn != YYPACT_NINF)
+	{
+	  yyn += YYTERROR;
+	  if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+	    {
+	      yyn = yytable[yyn];
+	      if (0 < yyn)
+		break;
+	    }
+	}
+
+      /* Pop the current state because it cannot handle the error token.  */
+      if (yyssp == yyss)
+	YYABORT;
+
+
+      yydestruct ("Error: popping",
+		  yystos[yystate], yyvsp);
+      YYPOPSTACK (1);
+      yystate = *yyssp;
+      YY_STACK_PRINT (yyss, yyssp);
+    }
+
+  if (yyn == YYFINAL)
+    YYACCEPT;
+
+  *++yyvsp = yylval;
+
+
+  /* Shift the error token.  */
+  YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+
+  yystate = yyn;
+  goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here.  |
+`-------------------------------------*/
+yyacceptlab:
+  yyresult = 0;
+  goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here.  |
+`-----------------------------------*/
+yyabortlab:
+  yyresult = 1;
+  goto yyreturn;
+
+#ifndef yyoverflow
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here.  |
+`-------------------------------------------------*/
+yyexhaustedlab:
+  yyerror (YY_("memory exhausted"));
+  yyresult = 2;
+  /* Fall through.  */
+#endif
+
+yyreturn:
+  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);
+  YY_STACK_PRINT (yyss, yyssp);
+  while (yyssp != yyss)
+    {
+      yydestruct ("Cleanup: popping",
+		  yystos[*yyssp], yyvsp);
+      YYPOPSTACK (1);
+    }
+#ifndef yyoverflow
+  if (yyss != yyssa)
+    YYSTACK_FREE (yyss);
+#endif
+#if YYERROR_VERBOSE
+  if (yymsg != yymsgbuf)
+    YYSTACK_FREE (yymsg);
+#endif
+  /* Make sure YYID is used.  */
+  return YYID (yyresult);
+}
+
+
+#line 2212 "go.y"
+
+
+static void
+fixlbrace(int lbr)
+{
+	// If the opening brace was an LBODY,
+	// set up for another one now that we're done.
+	// See comment in lex.c about loophack.
+	if(lbr == LBODY)
+		loophack = 1;
+}
+
+
diff --git a/src/cmd/gc/y.tab.h b/src/cmd/gc/y.tab.h
new file mode 100644
index 0000000..d01fbe1
--- /dev/null
+++ b/src/cmd/gc/y.tab.h
@@ -0,0 +1,167 @@
+/* A Bison parser, made by GNU Bison 2.3.  */
+
+/* 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 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, 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
+   under terms of your choice, so long as that work isn't itself a
+   parser generator using the skeleton or a modified version thereof
+   as a parser skeleton.  Alternatively, if you modify or redistribute
+   the parser skeleton itself, you may (at your option) remove this
+   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
+   /* Put the tokens into the symbol table, so that GDB and other debuggers
+      know about them.  */
+   enum yytokentype {
+     LLITERAL = 258,
+     LASOP = 259,
+     LCOLAS = 260,
+     LBREAK = 261,
+     LCASE = 262,
+     LCHAN = 263,
+     LCONST = 264,
+     LCONTINUE = 265,
+     LDDD = 266,
+     LDEFAULT = 267,
+     LDEFER = 268,
+     LELSE = 269,
+     LFALL = 270,
+     LFOR = 271,
+     LFUNC = 272,
+     LGO = 273,
+     LGOTO = 274,
+     LIF = 275,
+     LIMPORT = 276,
+     LINTERFACE = 277,
+     LMAP = 278,
+     LNAME = 279,
+     LPACKAGE = 280,
+     LRANGE = 281,
+     LRETURN = 282,
+     LSELECT = 283,
+     LSTRUCT = 284,
+     LSWITCH = 285,
+     LTYPE = 286,
+     LVAR = 287,
+     LANDAND = 288,
+     LANDNOT = 289,
+     LBODY = 290,
+     LCOMM = 291,
+     LDEC = 292,
+     LEQ = 293,
+     LGE = 294,
+     LGT = 295,
+     LIGNORE = 296,
+     LINC = 297,
+     LLE = 298,
+     LLSH = 299,
+     LLT = 300,
+     LNE = 301,
+     LOROR = 302,
+     LRSH = 303,
+     NotPackage = 304,
+     NotParen = 305,
+     PreferToRightParen = 306
+   };
+#endif
+/* Tokens.  */
+#define LLITERAL 258
+#define LASOP 259
+#define LCOLAS 260
+#define LBREAK 261
+#define LCASE 262
+#define LCHAN 263
+#define LCONST 264
+#define LCONTINUE 265
+#define LDDD 266
+#define LDEFAULT 267
+#define LDEFER 268
+#define LELSE 269
+#define LFALL 270
+#define LFOR 271
+#define LFUNC 272
+#define LGO 273
+#define LGOTO 274
+#define LIF 275
+#define LIMPORT 276
+#define LINTERFACE 277
+#define LMAP 278
+#define LNAME 279
+#define LPACKAGE 280
+#define LRANGE 281
+#define LRETURN 282
+#define LSELECT 283
+#define LSTRUCT 284
+#define LSWITCH 285
+#define LTYPE 286
+#define LVAR 287
+#define LANDAND 288
+#define LANDNOT 289
+#define LBODY 290
+#define LCOMM 291
+#define LDEC 292
+#define LEQ 293
+#define LGE 294
+#define LGT 295
+#define LIGNORE 296
+#define LINC 297
+#define LLE 298
+#define LLSH 299
+#define LLT 300
+#define LNE 301
+#define LOROR 302
+#define LRSH 303
+#define NotPackage 304
+#define NotParen 305
+#define PreferToRightParen 306
+
+
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+#line 28 "go.y"
+{
+	Node*		node;
+	NodeList*		list;
+	Type*		type;
+	Sym*		sym;
+	struct	Val	val;
+	int		i;
+}
+/* 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/gc/yerr.h b/src/cmd/gc/yerr.h
new file mode 100644
index 0000000..d0dd639
--- /dev/null
+++ b/src/cmd/gc/yerr.h
@@ -0,0 +1,79 @@
+// 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.
+
+// Example-based syntax error messages.
+// See bisonerrors, Makefile, go.y.
+
+static struct {
+	int yystate;
+	int yychar;
+	char *msg;
+} yymsg[] = {
+	// Each line of the form % token list
+	// is converted by bisonerrors into the yystate and yychar caused
+	// by that token list.
+
+	{222, ',',
+	"unexpected comma during import block"},
+
+	{32, ';',
+	"missing import path; require quoted string"},
+
+	{380, ';',
+	"missing { after if clause"},
+
+	{401, ';',
+	"missing { after switch clause"},
+
+	{239, ';',
+	"missing { after for clause"},
+
+	{478, LBODY,
+	"missing { after for clause"},
+
+	{22, '{',
+	"unexpected semicolon or newline before {"},
+
+	{145, ';',
+	"unexpected semicolon or newline in type declaration"},
+
+	{37, '}',
+	"unexpected } in channel type"},
+	
+	{37, ')',
+	"unexpected ) in channel type"},
+	
+	{37, ',',
+	"unexpected comma in channel type"},
+
+	{441, LELSE,
+	"unexpected semicolon or newline before else"},
+
+	{259, ',',
+	"name list not allowed in interface type"},
+
+	{239, LVAR,
+	"var declaration not allowed in for initializer"},
+
+	{65, '{',
+	"unexpected { at end of statement"},
+
+	{379, '{',
+	"unexpected { at end of statement"},
+	
+	{126, ';',
+	"argument to go/defer must be function call"},
+	
+	{428, ';',
+	"need trailing comma before newline in composite literal"},
+	
+	{439, ';',
+	"need trailing comma before newline in composite literal"},
+	
+	{113, LNAME,
+	"nested func not allowed"},
+
+	{647, ';',
+	"else must be followed by if or statement block"}
+};
diff --git a/src/cmd/go/bootstrap.go b/src/cmd/go/bootstrap.go
index 1686df7..dc7ed5f 100644
--- a/src/cmd/go/bootstrap.go
+++ b/src/cmd/go/bootstrap.go
@@ -17,19 +17,11 @@ import (
 
 var errHTTP = errors.New("no http in bootstrap go command")
 
-type httpError struct {
-	statusCode int
-}
-
-func (e *httpError) Error() string {
-	panic("unreachable")
-}
-
 func httpGET(url string) ([]byte, error) {
 	return nil, errHTTP
 }
 
-func httpsOrHTTP(importPath string, security securityMode) (string, io.ReadCloser, error) {
+func httpsOrHTTP(importPath string) (string, io.ReadCloser, error) {
 	return "", nil, errHTTP
 }
 
diff --git a/src/cmd/go/build.go b/src/cmd/go/build.go
index b7c7e05..1dd4314 100644
--- a/src/cmd/go/build.go
+++ b/src/cmd/go/build.go
@@ -8,7 +8,6 @@ import (
 	"bufio"
 	"bytes"
 	"container/heap"
-	"debug/elf"
 	"errors"
 	"flag"
 	"fmt"
@@ -35,23 +34,21 @@ var cmdBuild = &Command{
 Build compiles the packages named by the import paths,
 along with their dependencies, but it does not install the results.
 
-If the arguments to build are a list of .go files, build treats
-them as a list of source files specifying a single package.
+If the arguments are a list of .go files, build treats them as a list
+of source files specifying a single package.
 
-When compiling a single main package, build writes
-the resulting executable to an output file named after
-the first source file ('go build ed.go rx.go' writes 'ed' or 'ed.exe')
-or the source code directory ('go build unix/sam' writes 'sam' or 'sam.exe').
-The '.exe' suffix is added when writing a Windows executable.
-
-When compiling multiple packages or a single non-main package,
-build compiles the packages but discards the resulting object,
+When the command line specifies a single main package,
+build writes the resulting executable to output.
+Otherwise build compiles the packages but discards the results,
 serving only as a check that the packages can be built.
 
-The -o flag, only allowed when compiling a single package,
-forces build to write the resulting executable or object
-to the named output file, instead of the default behavior described
-in the last two paragraphs.
+The -o flag specifies the output file name. If not specified, the
+output file name depends on the arguments and derives from the name
+of the package, such as p.a for package p, unless p is 'main'. If
+the package is main and file names are provided, the file name
+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 -i flag installs the packages that are dependencies of the target.
 
@@ -65,8 +62,7 @@ and test commands:
 		print the commands but do not run them.
 	-p n
 		the number of builds that can be run in parallel.
-		The default is the number of CPUs available, except
-		on darwin/arm which defaults to 1.
+		The default is the number of CPUs available.
 	-race
 		enable data race detection.
 		Supported only on linux/amd64, freebsd/amd64, darwin/amd64 and windows/amd64.
@@ -78,54 +74,33 @@ and test commands:
 	-x
 		print the commands.
 
-	-asmflags 'flag list'
-		arguments to pass on each go tool asm invocation.
-	-buildmode mode
-		build mode to use. See 'go help buildmode' for more.
+	-ccflags 'arg list'
+		arguments to pass on each 5c, 6c, or 8c compiler invocation.
 	-compiler name
 		name of compiler to use, as in runtime.Compiler (gccgo or gc).
 	-gccgoflags 'arg list'
 		arguments to pass on each gccgo compiler/linker invocation.
 	-gcflags 'arg list'
-		arguments to pass on each go tool compile invocation.
+		arguments to pass on each 5g, 6g, or 8g compiler invocation.
 	-installsuffix suffix
 		a suffix to use in the name of the package installation directory,
 		in order to keep output separate from default builds.
 		If using the -race flag, the install suffix is automatically set to race
-		or, if set explicitly, has _race appended to it.  Using a -buildmode
-		option that requires non-default compile flags has a similar effect.
+		or, if set explicitly, has _race appended to it.
 	-ldflags 'flag list'
-		arguments to pass on each go tool link invocation.
-	-linkshared
-		link against shared libraries previously created with
-		-buildmode=shared
-	-pkgdir dir
-		install and load all packages from dir instead of the usual locations.
-		For example, when building with a non-standard configuration,
-		use -pkgdir to keep generated packages in a separate location.
+		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.
 		For more information about build tags, see the description of
 		build constraints in the documentation for the go/build package.
-	-toolexec 'cmd args'
-		a program to use to invoke toolchain programs like vet and asm.
-		For example, instead of running asm, the go command will run
-		'cmd args /path/to/asm <arguments for asm>'.
 
 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.
 
 For more about specifying packages, see 'go help packages'.
 For more about where packages and binaries are installed,
-run 'go help gopath'.
-For more about calling between Go and C/C++, run 'go help c'.
-
-Note: Build adheres to certain conventions such as those described
-by 'go help gopath'. Not all projects can follow these conventions,
-however. Installations that have their own conventions or that use
-a separate software build system may choose to use lower-level
-invocations such as 'go tool compile' and 'go tool link' to avoid
-some of the overheads and design decisions of the build tool.
+run 'go help gopath'.  For more about calling between Go and C/C++,
+run 'go help c'.
 
 See also: go install, go get, go clean.
 	`,
@@ -140,17 +115,6 @@ func init() {
 
 	addBuildFlags(cmdBuild)
 	addBuildFlags(cmdInstall)
-
-	if buildContext.GOOS == "darwin" {
-		switch buildContext.GOARCH {
-		case "arm", "arm64":
-			// darwin/arm cannot run multiple tests simultaneously.
-			// Parallelism is limited in go_darwin_arm_exec, but
-			// also needs to be limited here so go test std does not
-			// timeout tests that waiting to run.
-			buildP = 1
-		}
-	}
 }
 
 // Flags set by multiple commands.
@@ -162,19 +126,14 @@ var buildX bool               // -x flag
 var buildI bool               // -i flag
 var buildO = cmdBuild.Flag.String("o", "", "output file")
 var buildWork bool           // -work flag
-var buildAsmflags []string   // -asmflags flag
 var buildGcflags []string    // -gcflags flag
+var buildCcflags []string    // -ccflags flag
 var buildLdflags []string    // -ldflags flag
 var buildGccgoflags []string // -gccgoflags flag
 var buildRace bool           // -race flag
-var buildToolExec []string   // -toolexec flag
-var buildBuildmode string    // -buildmode flag
-var buildLinkshared bool     // -linkshared flag
-var buildPkgdir string       // -pkgdir flag
 
 var buildContext = build.Default
 var buildToolchain toolchain = noToolchain{}
-var ldBuildmode string
 
 // buildCompiler implements flag.Var.
 // It implements Set by updating both
@@ -210,25 +169,21 @@ func init() {
 // 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, "")
 	cmd.Flag.BoolVar(&buildN, "n", false, "")
 	cmd.Flag.IntVar(&buildP, "p", buildP, "")
+	cmd.Flag.StringVar(&buildContext.InstallSuffix, "installsuffix", "", "")
 	cmd.Flag.BoolVar(&buildV, "v", false, "")
 	cmd.Flag.BoolVar(&buildX, "x", false, "")
-
-	cmd.Flag.Var((*stringsFlag)(&buildAsmflags), "asmflags", "")
-	cmd.Flag.Var(buildCompiler{}, "compiler", "")
-	cmd.Flag.StringVar(&buildBuildmode, "buildmode", "default", "")
+	cmd.Flag.BoolVar(&buildWork, "work", false, "")
 	cmd.Flag.Var((*stringsFlag)(&buildGcflags), "gcflags", "")
-	cmd.Flag.Var((*stringsFlag)(&buildGccgoflags), "gccgoflags", "")
-	cmd.Flag.StringVar(&buildContext.InstallSuffix, "installsuffix", "", "")
+	cmd.Flag.Var((*stringsFlag)(&buildCcflags), "ccflags", "")
 	cmd.Flag.Var((*stringsFlag)(&buildLdflags), "ldflags", "")
-	cmd.Flag.BoolVar(&buildLinkshared, "linkshared", false, "")
-	cmd.Flag.StringVar(&buildPkgdir, "pkgdir", "", "")
-	cmd.Flag.BoolVar(&buildRace, "race", false, "")
+	cmd.Flag.Var((*stringsFlag)(&buildGccgoflags), "gccgoflags", "")
 	cmd.Flag.Var((*stringsFlag)(&buildContext.BuildTags), "tags", "")
-	cmd.Flag.Var((*stringsFlag)(&buildToolExec), "toolexec", "")
-	cmd.Flag.BoolVar(&buildWork, "work", false, "")
+	cmd.Flag.Var(buildCompiler{}, "compiler", "")
+	cmd.Flag.BoolVar(&buildRace, "race", false, "")
 }
 
 func addBuildFlagsNX(cmd *Command) {
@@ -303,113 +258,8 @@ func (v *stringsFlag) String() string {
 	return "<stringsFlag>"
 }
 
-func pkgsMain(pkgs []*Package) (res []*Package) {
-	for _, p := range pkgs {
-		if p.Name == "main" {
-			res = append(res, p)
-		}
-	}
-	return res
-}
-
-func pkgsNotMain(pkgs []*Package) (res []*Package) {
-	for _, p := range pkgs {
-		if p.Name != "main" {
-			res = append(res, p)
-		}
-	}
-	return res
-}
-
-var pkgsFilter = func(pkgs []*Package) []*Package { return pkgs }
-
-func buildModeInit() {
-	_, gccgo := buildToolchain.(gccgoToolchain)
-	var codegenArg string
-	platform := goos + "/" + goarch
-	switch buildBuildmode {
-	case "archive":
-		pkgsFilter = pkgsNotMain
-	case "c-archive":
-		pkgsFilter = func(p []*Package) []*Package {
-			if len(p) != 1 || p[0].Name != "main" {
-				fatalf("-buildmode=c-archive requires exactly one main package")
-			}
-			return p
-		}
-		exeSuffix = ".a"
-		ldBuildmode = "c-archive"
-	case "c-shared":
-		pkgsFilter = pkgsMain
-		if gccgo {
-			codegenArg = "-fPIC"
-		} else {
-			switch platform {
-			case "linux/amd64":
-				codegenArg = "-shared"
-			case "linux/arm":
-				buildAsmflags = append(buildAsmflags, "-shared")
-			case "darwin/amd64":
-			case "android/arm":
-			default:
-				fatalf("-buildmode=c-shared not supported on %s\n", platform)
-			}
-		}
-		ldBuildmode = "c-shared"
-	case "default":
-		ldBuildmode = "exe"
-	case "exe":
-		pkgsFilter = pkgsMain
-		ldBuildmode = "exe"
-	case "shared":
-		pkgsFilter = pkgsNotMain
-		if gccgo {
-			codegenArg = "-fPIC"
-		} else {
-			switch platform {
-			case "linux/amd64":
-			default:
-				fatalf("-buildmode=shared not supported on %s\n", platform)
-			}
-			codegenArg = "-dynlink"
-		}
-		if *buildO != "" {
-			fatalf("-buildmode=shared and -o not supported together")
-		}
-		ldBuildmode = "shared"
-	default:
-		fatalf("buildmode=%s not supported", buildBuildmode)
-	}
-	if buildLinkshared {
-		if gccgo {
-			codegenArg = "-fPIC"
-		} else {
-			if platform != "linux/amd64" {
-				fmt.Fprintf(os.Stderr, "go %s: -linkshared is only supported on linux/amd64\n", flag.Args()[0])
-				os.Exit(2)
-			}
-			codegenArg = "-dynlink"
-			// TODO(mwhudson): remove -w when that gets fixed in linker.
-			buildLdflags = append(buildLdflags, "-linkshared", "-w")
-		}
-	}
-	if codegenArg != "" {
-		if gccgo {
-			buildGccgoflags = append(buildGccgoflags, codegenArg)
-		} else {
-			buildAsmflags = append(buildAsmflags, codegenArg)
-			buildGcflags = append(buildGcflags, codegenArg)
-		}
-		if buildContext.InstallSuffix != "" {
-			buildContext.InstallSuffix += "_"
-		}
-		buildContext.InstallSuffix += codegenArg[1:]
-	}
-}
-
 func runBuild(cmd *Command, args []string) {
 	raceInit()
-	buildModeInit()
 	var b builder
 	b.init()
 
@@ -447,21 +297,16 @@ func runBuild(cmd *Command, args []string) {
 			fatalf("no packages to build")
 		}
 		p := pkgs[0]
-		p.target = *buildO
-		p.Stale = true // must build - not up to date
+		p.target = "" // must build - not up to date
 		a := b.action(modeInstall, depMode, p)
+		a.target = *buildO
 		b.do(a)
 		return
 	}
 
-	var a *action
-	if buildBuildmode == "shared" {
-		a = b.libaction(libname(args), pkgsFilter(packages(args)), modeBuild, depMode)
-	} else {
-		a = &action{}
-		for _, p := range pkgsFilter(packages(args)) {
-			a.deps = append(a.deps, b.action(modeBuild, depMode, p))
-		}
+	a := &action{}
+	for _, p := range packages(args) {
+		a.deps = append(a.deps, b.action(modeBuild, depMode, p))
 	}
 	b.do(a)
 }
@@ -480,47 +325,18 @@ See also: go build, go get, go clean.
 	`,
 }
 
-// libname returns the filename to use for the shared library when using
-// -buildmode=shared.  The rules we use are:
-//  1) Drop any trailing "/..."s if present
-//  2) Change / to -
-//  3) Join arguments with ,
-// So std -> libstd.so
-//    a b/... -> liba,b.so
-//    gopkg.in/tomb.v2 -> libgopkg.in-tomb.v2.so
-func libname(args []string) string {
-	var libname string
-	for _, arg := range args {
-		arg = strings.TrimSuffix(arg, "/...")
-		arg = strings.Replace(arg, "/", "-", -1)
-		if libname == "" {
-			libname = arg
-		} else {
-			libname += "," + arg
-		}
-	}
-	// TODO(mwhudson): Needs to change for platforms that use different naming
-	// conventions...
-	return "lib" + libname + ".so"
-}
-
 func runInstall(cmd *Command, args []string) {
 	raceInit()
-	buildModeInit()
-	pkgs := pkgsFilter(packagesForBuild(args))
+	pkgs := packagesForBuild(args)
 
 	for _, p := range pkgs {
 		if p.Target == "" && (!p.Standard || p.ImportPath != "unsafe") {
-			switch {
-			case p.gobinSubdir:
-				errorf("go install: cannot install cross-compiled binaries when GOBIN is set")
-			case p.cmdline:
+			if p.cmdline {
 				errorf("go install: no install location for .go files listed on command line (GOBIN not set)")
-			case p.ConflictDir != "":
+			} else if p.ConflictDir != "" {
 				errorf("go install: no install location for %s: hidden by %s", p.Dir, p.ConflictDir)
-			default:
-				errorf("go install: no install location for directory %s outside GOPATH\n"+
-					"\tFor more details see: go help gopath", p.Dir)
+			} else {
+				errorf("go install: no install location for directory %s outside GOPATH", p.Dir)
 			}
 		}
 	}
@@ -528,68 +344,18 @@ func runInstall(cmd *Command, args []string) {
 
 	var b builder
 	b.init()
-	var a *action
-	if buildBuildmode == "shared" {
-		a = b.libaction(libname(args), pkgs, modeInstall, modeInstall)
-	} else {
-		a = &action{}
-		var tools []*action
-		for _, p := range pkgs {
-			// If p is a tool, delay the installation until the end of the build.
-			// This avoids installing assemblers/compilers that are being executed
-			// by other steps in the build.
-			// cmd/cgo is handled specially in b.action, so that we can
-			// both build and use it in the same 'go install'.
-			action := b.action(modeInstall, modeInstall, p)
-			if goTools[p.ImportPath] == toTool && p.ImportPath != "cmd/cgo" {
-				a.deps = append(a.deps, action.deps...)
-				action.deps = append(action.deps, a)
-				tools = append(tools, action)
-				continue
-			}
-			a.deps = append(a.deps, action)
-		}
-		if len(tools) > 0 {
-			a = &action{
-				deps: tools,
-			}
-		}
+	a := &action{}
+	for _, p := range pkgs {
+		a.deps = append(a.deps, b.action(modeInstall, modeInstall, p))
 	}
 	b.do(a)
-	exitIfErrors()
-
-	// Success. If this command is 'go install' with no arguments
-	// and the current directory (the implicit argument) is a command,
-	// remove any leftover command binary from a previous 'go build'.
-	// The binary is installed; it's not needed here anymore.
-	// And worse it might be a stale copy, which you don't want to find
-	// instead of the installed one if $PATH contains dot.
-	// One way to view this behavior is that it is as if 'go install' first
-	// runs 'go build' and the moves the generated file to the install dir.
-	// See issue 9645.
-	if len(args) == 0 && len(pkgs) == 1 && pkgs[0].Name == "main" {
-		// Compute file 'go build' would have created.
-		// If it exists and is an executable file, remove it.
-		_, targ := filepath.Split(pkgs[0].ImportPath)
-		targ += exeSuffix
-		if filepath.Join(pkgs[0].Dir, targ) != pkgs[0].Target { // maybe $GOBIN is the current directory
-			fi, err := os.Stat(targ)
-			if err == nil {
-				m := fi.Mode()
-				if m.IsRegular() {
-					if m&0111 != 0 || goos == "windows" { // windows never sets executable bit
-						os.Remove(targ)
-					}
-				}
-			}
-		}
-	}
 }
 
 // Global build parameters (used during package load)
 var (
 	goarch    string
 	goos      string
+	archChar  string
 	exeSuffix string
 )
 
@@ -599,6 +365,16 @@ func init() {
 	if goos == "windows" {
 		exeSuffix = ".exe"
 	}
+	var err error
+	archChar, err = build.ArchChar(goarch)
+	if err != nil {
+		if _, isgc := buildToolchain.(gcToolchain); isgc {
+			fatalf("%s", err)
+		}
+		// archChar is only required for gcToolchain, if we're using
+		// another toolchain leave it blank.
+		archChar = ""
+	}
 }
 
 // A builder holds global state about a build.
@@ -645,9 +421,8 @@ type action struct {
 
 // cacheKey is the key for the action cache.
 type cacheKey struct {
-	mode  buildMode
-	p     *Package
-	shlib string
+	mode buildMode
+	p    *Package
 }
 
 // buildMode specifies the build mode:
@@ -722,9 +497,6 @@ func goFilesPackage(gofiles []string) *Package {
 			fatalf("%s is a directory, should be a Go file", file)
 		}
 		dir1, _ := filepath.Split(file)
-		if dir1 == "" {
-			dir1 = "./"
-		}
 		if dir == "" {
 			dir = dir1
 		} else if dir != dir1 {
@@ -761,8 +533,11 @@ func goFilesPackage(gofiles []string) *Package {
 		if gobin != "" {
 			pkg.target = filepath.Join(gobin, exe)
 		}
+	} else {
+		if *buildO == "" {
+			*buildO = pkg.Name + ".a"
+		}
 	}
-
 	pkg.Target = pkg.target
 	pkg.Stale = true
 
@@ -770,88 +545,24 @@ func goFilesPackage(gofiles []string) *Package {
 	return pkg
 }
 
-// readpkglist returns the list of packages that were built into the shared library
-// at shlibpath. For the native toolchain this list is stored, newline separated, in
-// an ELF note with name "Go\x00\x00" and type 1. For GCCGO it is extracted from the
-// .go_export section.
-func readpkglist(shlibpath string) (pkgs []*Package) {
-	var stk importStack
-	if _, gccgo := buildToolchain.(gccgoToolchain); gccgo {
-		f, _ := elf.Open(shlibpath)
-		sect := f.Section(".go_export")
-		data, _ := sect.Data()
-		scanner := bufio.NewScanner(bytes.NewBuffer(data))
-		for scanner.Scan() {
-			t := scanner.Text()
-			if strings.HasPrefix(t, "pkgpath ") {
-				t = strings.TrimPrefix(t, "pkgpath ")
-				t = strings.TrimSuffix(t, ";")
-				pkgs = append(pkgs, loadPackage(t, &stk))
-			}
-		}
-	} else {
-		pkglistbytes, err := readELFNote(shlibpath, "Go\x00\x00", 1)
-		if err != nil {
-			fatalf("readELFNote failed: %v", err)
-		}
-		scanner := bufio.NewScanner(bytes.NewBuffer(pkglistbytes))
-		for scanner.Scan() {
-			t := scanner.Text()
-			pkgs = append(pkgs, loadPackage(t, &stk))
-		}
-	}
-	return
-}
-
 // action returns the action for applying the given operation (mode) to the package.
 // depMode is the action to use when building dependencies.
-// action never looks for p in a shared library.
 func (b *builder) action(mode buildMode, depMode buildMode, p *Package) *action {
-	return b.action1(mode, depMode, p, false)
-}
-
-// action1 returns the action for applying the given operation (mode) to the package.
-// depMode is the action to use when building dependencies.
-// action1 will look for p in a shared library if lookshared is true.
-func (b *builder) action1(mode buildMode, depMode buildMode, p *Package, lookshared bool) *action {
-	shlib := ""
-	if lookshared {
-		shlib = p.Shlib
-	}
-	key := cacheKey{mode, p, shlib}
-
+	key := cacheKey{mode, p}
 	a := b.actionCache[key]
 	if a != nil {
 		return a
 	}
-	if shlib != "" {
-		key2 := cacheKey{modeInstall, nil, shlib}
-		a = b.actionCache[key2]
-		if a != nil {
-			b.actionCache[key] = a
-			return a
-		}
-		pkgs := readpkglist(shlib)
-		a = b.libaction(filepath.Base(shlib), pkgs, modeInstall, depMode)
-		b.actionCache[key2] = a
-		b.actionCache[key] = a
-		return a
-	}
 
 	a = &action{p: p, pkgdir: p.build.PkgRoot}
 	if p.pkgdir != "" { // overrides p.t
 		a.pkgdir = p.pkgdir
 	}
+
 	b.actionCache[key] = a
 
 	for _, p1 := range p.imports {
-		ls := buildLinkshared
-		// If p1 is part of the same shared library as p, we need the action
-		// that builds p here, not the shared libary or we get action loops.
-		if p1.Shlib == p.Shlib {
-			ls = false
-		}
-		a.deps = append(a.deps, b.action1(depMode, depMode, p1, ls))
+		a.deps = append(a.deps, b.action(depMode, depMode, p1))
 	}
 
 	// If we are not doing a cross-build, then record the binary we'll
@@ -860,7 +571,7 @@ func (b *builder) action1(mode buildMode, depMode buildMode, p *Package, looksha
 	// a package is using it.  If this is a cross-build, then the cgo we
 	// are writing is not the cgo we need to use.
 	if goos == runtime.GOOS && goarch == runtime.GOARCH && !buildRace {
-		if (len(p.CgoFiles) > 0 || p.Standard && p.ImportPath == "runtime/cgo") && !buildLinkshared && buildBuildmode != "shared" {
+		if len(p.CgoFiles) > 0 || p.Standard && p.ImportPath == "runtime/cgo" {
 			var stk importStack
 			p1 := loadPackage("cmd/cgo", &stk)
 			if p1.Error != nil {
@@ -907,22 +618,8 @@ func (b *builder) action1(mode buildMode, depMode buildMode, p *Package, looksha
 	switch mode {
 	case modeInstall:
 		a.f = (*builder).install
-		a.deps = []*action{b.action1(modeBuild, depMode, p, lookshared)}
+		a.deps = []*action{b.action(modeBuild, depMode, p)}
 		a.target = a.p.target
-
-		// Install header for cgo in c-archive and c-shared modes.
-		if p.usesCgo() && (buildBuildmode == "c-archive" || buildBuildmode == "c-shared") {
-			ah := &action{
-				p:      a.p,
-				deps:   []*action{a.deps[0]},
-				f:      (*builder).installHeader,
-				pkgdir: a.pkgdir,
-				objdir: a.objdir,
-				target: a.target[:len(a.target)-len(filepath.Ext(a.target))] + ".h",
-			}
-			a.deps = append(a.deps, ah)
-		}
-
 	case modeBuild:
 		a.f = (*builder).build
 		a.target = a.objpkg
@@ -937,13 +634,6 @@ func (b *builder) action1(mode buildMode, depMode buildMode, p *Package, looksha
 			name := "a.out"
 			if p.exeName != "" {
 				name = p.exeName
-			} else if goos == "darwin" && buildBuildmode == "c-shared" && p.target != "" {
-				// On OS X, the linker output name gets recorded in the
-				// shared library's LC_ID_DYLIB load command.
-				// The code invoking the linker knows to pass only the final
-				// path element. Arrange that the path element matches what
-				// we'll install it as; otherwise the library is only loadable as "a.out".
-				_, name = filepath.Split(p.target)
 			}
 			a.target = a.objdir + filepath.Join("exe", name) + exeSuffix
 		}
@@ -952,100 +642,6 @@ func (b *builder) action1(mode buildMode, depMode buildMode, p *Package, looksha
 	return a
 }
 
-func (b *builder) libaction(libname string, pkgs []*Package, mode, depMode buildMode) *action {
-	a := &action{}
-	if mode == modeBuild {
-		a.f = (*builder).linkShared
-		a.target = filepath.Join(b.work, libname)
-		for _, p := range pkgs {
-			if p.target == "" {
-				continue
-			}
-			a.deps = append(a.deps, b.action(depMode, depMode, p))
-		}
-	} else if mode == modeInstall {
-		// Currently build mode shared forces external linking mode, and
-		// external linking mode forces an import of runtime/cgo. So if it
-		// was not passed on the command line and it is not present in
-		// another shared library, add it here.
-		seencgo := false
-		_, gccgo := buildToolchain.(gccgoToolchain)
-		if !gccgo {
-			for _, p := range pkgs {
-				seencgo = seencgo || (p.Standard && p.ImportPath == "runtime/cgo")
-			}
-			if !seencgo {
-				var stk importStack
-				p := loadPackage("runtime/cgo", &stk)
-				if p.Error != nil {
-					fatalf("load runtime/cgo: %v", p.Error)
-				}
-				computeStale(p)
-				// If runtime/cgo is in another shared library, then that's
-				// also the shared library that contains runtime, so
-				// something will depend on it and so runtime/cgo's staleness
-				// will be checked when processing that library.
-				if p.Shlib == "" || p.Shlib == libname {
-					pkgs = append([]*Package{}, pkgs...)
-					pkgs = append(pkgs, p)
-				}
-			}
-		}
-
-		// Figure out where the library will go.
-		var libdir string
-		for _, p := range pkgs {
-			plibdir := p.build.PkgTargetRoot
-			if gccgo {
-				plibdir = filepath.Join(plibdir, "shlibs")
-			}
-			if libdir == "" {
-				libdir = plibdir
-			} else if libdir != plibdir {
-				fatalf("multiple roots %s & %s", libdir, plibdir)
-			}
-		}
-		a.target = filepath.Join(libdir, libname)
-
-		// Now we can check whether we need to rebuild it.
-		stale := false
-		var built time.Time
-		if fi, err := os.Stat(a.target); err == nil {
-			built = fi.ModTime()
-		}
-		for _, p := range pkgs {
-			if p.target == "" {
-				continue
-			}
-			stale = stale || p.Stale
-			lstat, err := os.Stat(p.target)
-			if err != nil || lstat.ModTime().After(built) {
-				stale = true
-			}
-			a.deps = append(a.deps, b.action(depMode, depMode, p))
-		}
-
-		if stale {
-			a.f = (*builder).install
-			buildAction := b.libaction(libname, pkgs, modeBuild, depMode)
-			a.deps = []*action{buildAction}
-			for _, p := range pkgs {
-				if p.target == "" {
-					continue
-				}
-				shlibnameaction := &action{}
-				shlibnameaction.f = (*builder).installShlibname
-				shlibnameaction.target = p.target[:len(p.target)-2] + ".shlibname"
-				a.deps = append(a.deps, shlibnameaction)
-				shlibnameaction.deps = append(shlibnameaction.deps, buildAction)
-			}
-		}
-	} else {
-		fatalf("unregonized mode %v", mode)
-	}
-	return a
-}
-
 // actionList returns the list of actions in the dag rooted at root
 // as visited in a depth-first post-order traversal.
 func actionList(root *action) []*action {
@@ -1066,31 +662,6 @@ func actionList(root *action) []*action {
 	return all
 }
 
-// allArchiveActions returns a list of the archive dependencies of root.
-// This is needed because if package p depends on package q that is in libr.so, the
-// action graph looks like p->libr.so->q and so just scanning through p's
-// dependencies does not find the import dir for q.
-func allArchiveActions(root *action) []*action {
-	seen := map[*action]bool{}
-	r := []*action{}
-	var walk func(*action)
-	walk = func(a *action) {
-		if seen[a] {
-			return
-		}
-		seen[a] = true
-		if strings.HasSuffix(a.target, ".so") || a == root {
-			for _, a1 := range a.deps {
-				walk(a1)
-			}
-		} else if strings.HasSuffix(a.target, ".a") {
-			r = append(r, a)
-		}
-	}
-	walk(root)
-	return r
-}
-
 // do runs the action graph rooted at root.
 func (b *builder) do(root *action) {
 	// Build list of all actions, assigning depth-first post-order priority.
@@ -1211,7 +782,9 @@ func hasString(strings []string, s string) bool {
 func (b *builder) build(a *action) (err error) {
 	// Return an error if the package has CXX files but it's not using
 	// cgo nor SWIG, since the CXX files can only be processed by cgo
-	// and SWIG.
+	// and SWIG (it's possible to have packages with C files without
+	// using cgo, they will get compiled with the plan9 C compiler and
+	// linked with the rest of the package).
 	if len(a.p.CXXFiles) > 0 && !a.p.usesCgo() && !a.p.usesSwig() {
 		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, ","))
@@ -1240,8 +813,7 @@ func (b *builder) build(a *action) (err error) {
 	}
 
 	if a.p.Standard && a.p.ImportPath == "runtime" && buildContext.Compiler == "gc" &&
-		(!hasString(a.p.GoFiles, "zgoos_"+buildContext.GOOS+".go") ||
-			!hasString(a.p.GoFiles, "zgoarch_"+buildContext.GOARCH+".go")) {
+		!hasString(a.p.HFiles, "zasm_"+buildContext.GOOS+"_"+buildContext.GOARCH+".h") {
 		return fmt.Errorf("%s/%s must be bootstrapped using make%v", buildContext.GOOS, buildContext.GOARCH, defaultSuffix())
 	}
 
@@ -1259,35 +831,19 @@ func (b *builder) build(a *action) (err error) {
 		}
 	}
 
-	var gofiles, cgofiles, cfiles, sfiles, cxxfiles, objects, cgoObjects, pcCFLAGS, pcLDFLAGS []string
+	var gofiles, cfiles, sfiles, objects, cgoObjects, pcCFLAGS, pcLDFLAGS []string
 
 	gofiles = append(gofiles, a.p.GoFiles...)
-	cgofiles = append(cgofiles, a.p.CgoFiles...)
 	cfiles = append(cfiles, a.p.CFiles...)
 	sfiles = append(sfiles, a.p.SFiles...)
-	cxxfiles = append(cxxfiles, a.p.CXXFiles...)
 
 	if a.p.usesCgo() || a.p.usesSwig() {
 		if pcCFLAGS, pcLDFLAGS, err = b.getPkgConfigFlags(a.p); err != nil {
 			return
 		}
 	}
-
-	// Run SWIG on each .swig and .swigcxx file.
-	// Each run will generate two files, a .go file and a .c or .cxx file.
-	// The .go file will use import "C" and is to be processed by cgo.
-	if a.p.usesSwig() {
-		outGo, outC, outCXX, err := b.swig(a.p, obj, pcCFLAGS)
-		if err != nil {
-			return err
-		}
-		cgofiles = append(cgofiles, outGo...)
-		cfiles = append(cfiles, outC...)
-		cxxfiles = append(cxxfiles, outCXX...)
-	}
-
 	// Run cgo.
-	if a.p.usesCgo() || a.p.usesSwig() {
+	if a.p.usesCgo() {
 		// In a package using cgo, cgo compiles the C, C++ and assembly files with gcc.
 		// There is one exception: runtime/cgo's job is to bridge the
 		// cgo and non-cgo worlds, so it necessarily has files in both.
@@ -1316,7 +872,31 @@ 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, pcCFLAGS, pcLDFLAGS, cgofiles, gccfiles, cxxfiles, a.p.MFiles)
+		outGo, outObj, err := b.cgo(a.p, cgoExe, obj, pcCFLAGS, pcLDFLAGS, gccfiles, a.p.CXXFiles, a.p.MFiles)
+		if err != nil {
+			return err
+		}
+		cgoObjects = append(cgoObjects, outObj...)
+		gofiles = append(gofiles, outGo...)
+	}
+
+	// Run SWIG.
+	if a.p.usesSwig() {
+		// In a package using SWIG, any .c or .s files are
+		// compiled with gcc.
+		gccfiles := append(cfiles, sfiles...)
+		cxxfiles, mfiles := a.p.CXXFiles, a.p.MFiles
+		cfiles = nil
+		sfiles = nil
+
+		// Don't build c/c++ files twice if cgo is enabled (mainly for pkg-config).
+		if a.p.usesCgo() {
+			cxxfiles = nil
+			gccfiles = nil
+			mfiles = nil
+		}
+
+		outGo, outObj, err := b.swig(a.p, obj, pcCFLAGS, gccfiles, cxxfiles, mfiles)
 		if err != nil {
 			return err
 		}
@@ -1358,10 +938,10 @@ func (b *builder) build(a *action) (err error) {
 	}
 
 	// Prepare Go import path list.
-	inc := b.includeArgs("-I", allArchiveActions(a))
+	inc := b.includeArgs("-I", a.deps)
 
 	// Compile Go.
-	ofile, out, err := buildToolchain.gc(b, a.p, a.objpkg, obj, len(sfiles) > 0, inc, gofiles)
+	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 {
@@ -1386,24 +966,29 @@ 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), 0644, true); 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), 0644, true); 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), 0644, true); err != nil {
+			if err := b.copyFile(a, obj+targ, filepath.Join(a.p.Dir, file), 0644); err != nil {
 				return err
 			}
 		}
 	}
 
+	objExt := archChar
+	if _, ok := buildToolchain.(gccgoToolchain); ok {
+		objExt = "o"
+	}
+
 	for _, file := range cfiles {
-		out := file[:len(file)-len(".c")] + ".o"
+		out := file[:len(file)-len(".c")] + "." + objExt
 		if err := buildToolchain.cc(b, a.p, obj, obj+out, file); err != nil {
 			return err
 		}
@@ -1412,7 +997,7 @@ func (b *builder) build(a *action) (err error) {
 
 	// Assemble .s files.
 	for _, file := range sfiles {
-		out := file[:len(file)-len(".s")] + ".o"
+		out := file[:len(file)-len(".s")] + "." + objExt
 		if err := buildToolchain.asm(b, a.p, obj, obj+out, file); err != nil {
 			return err
 		}
@@ -1422,7 +1007,7 @@ func (b *builder) build(a *action) (err error) {
 	// NOTE(rsc): On Windows, it is critically important that the
 	// gcc-compiled objects (cgoObjects) be listed after the ordinary
 	// objects in the archive.  I do not know why this is.
-	// https://golang.org/issue/2601
+	// http://golang.org/issue/2601
 	objects = append(objects, cgoObjects...)
 
 	// Add system object files.
@@ -1447,7 +1032,7 @@ func (b *builder) build(a *action) (err error) {
 		// linker needs the whole dependency tree.
 		all := actionList(a)
 		all = all[:len(all)-1] // drop a
-		if err := buildToolchain.ld(b, a, a.target, all, a.objpkg, objects); err != nil {
+		if err := buildToolchain.ld(b, a.p, a.target, all, a.objpkg, objects); err != nil {
 			return err
 		}
 	}
@@ -1483,24 +1068,6 @@ func (b *builder) getPkgConfigFlags(p *Package) (cflags, ldflags []string, err e
 	return
 }
 
-func (b *builder) installShlibname(a *action) error {
-	a1 := a.deps[0]
-	err := ioutil.WriteFile(a.target, []byte(filepath.Base(a1.target)+"\n"), 0644)
-	if err != nil {
-		return err
-	}
-	if buildX {
-		b.showcmd("", "echo '%s' > %s # internal", filepath.Base(a1.target), a.target)
-	}
-	return nil
-}
-
-func (b *builder) linkShared(a *action) (err error) {
-	allactions := actionList(a)
-	allactions = allactions[:len(allactions)-1]
-	return buildToolchain.ldShared(b, a.deps, a.target, allactions)
-}
-
 // install is the action for installing a single package or executable.
 func (b *builder) install(a *action) (err error) {
 	defer func() {
@@ -1511,11 +1078,7 @@ func (b *builder) install(a *action) (err error) {
 	a1 := a.deps[0]
 	perm := os.FileMode(0644)
 	if a1.link {
-		switch buildBuildmode {
-		case "c-archive", "c-shared":
-		default:
-			perm = 0755
-		}
+		perm = 0755
 	}
 
 	// make target directory
@@ -1535,7 +1098,7 @@ func (b *builder) install(a *action) (err error) {
 		defer os.Remove(a1.target)
 	}
 
-	return b.moveOrCopyFile(a, a.target, a1.target, perm, false)
+	return b.moveOrCopyFile(a, a.target, a1.target, perm)
 }
 
 // includeArgs returns the -I or -L directory list for access
@@ -1552,9 +1115,6 @@ func (b *builder) includeArgs(flag string, all []*action) []string {
 	// This is the $WORK/my/package/_test directory for the
 	// package being built, so there are few of these.
 	for _, a1 := range all {
-		if a1.p == nil {
-			continue
-		}
 		if dir := a1.pkgdir; dir != a1.p.build.PkgRoot && !incMap[dir] {
 			incMap[dir] = true
 			inc = append(inc, flag, dir)
@@ -1567,12 +1127,17 @@ func (b *builder) includeArgs(flag string, all []*action) []string {
 
 	// Finally, look in the installed package directories for each action.
 	for _, a1 := range all {
-		if a1.p == nil {
-			continue
-		}
 		if dir := a1.pkgdir; dir == a1.p.build.PkgRoot && !incMap[dir] {
 			incMap[dir] = true
-			inc = append(inc, flag, a1.p.build.PkgTargetRoot)
+			if _, ok := buildToolchain.(gccgoToolchain); ok {
+				dir = filepath.Join(dir, "gccgo_"+goos+"_"+goarch)
+			} else {
+				dir = filepath.Join(dir, goos+"_"+goarch)
+				if buildContext.InstallSuffix != "" {
+					dir += "_" + buildContext.InstallSuffix
+				}
+			}
+			inc = append(inc, flag, dir)
 		}
 	}
 
@@ -1580,7 +1145,7 @@ func (b *builder) includeArgs(flag string, all []*action) []string {
 }
 
 // moveOrCopyFile is like 'mv src dst' or 'cp src dst'.
-func (b *builder) moveOrCopyFile(a *action, dst, src string, perm os.FileMode, force bool) error {
+func (b *builder) moveOrCopyFile(a *action, dst, src string, perm os.FileMode) error {
 	if buildN {
 		b.showcmd("", "mv %s %s", src, dst)
 		return nil
@@ -1597,11 +1162,11 @@ func (b *builder) moveOrCopyFile(a *action, dst, src string, perm os.FileMode, f
 		}
 	}
 
-	return b.copyFile(a, dst, src, perm, force)
+	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, force bool) error {
+func (b *builder) copyFile(a *action, dst, src string, perm os.FileMode) error {
 	if buildN || buildX {
 		b.showcmd("", "cp %s %s", src, dst)
 		if buildN {
@@ -1622,7 +1187,7 @@ func (b *builder) copyFile(a *action, dst, src string, perm os.FileMode, force b
 		if fi.IsDir() {
 			return fmt.Errorf("build output %q already exists and is a directory", dst)
 		}
-		if !force && !isObject(dst) {
+		if !isObject(dst) {
 			return fmt.Errorf("build output %q already exists and is not an object file", dst)
 		}
 	}
@@ -1659,30 +1224,10 @@ func (b *builder) copyFile(a *action, dst, src string, perm os.FileMode, force b
 	return nil
 }
 
-// Install the cgo export header file, if there is one.
-func (b *builder) installHeader(a *action) error {
-	src := a.objdir + "_cgo_install.h"
-	if _, err := os.Stat(src); os.IsNotExist(err) {
-		// If the file does not exist, there are no exported
-		// functions, and we do not install anything.
-		return nil
-	}
-
-	dir, _ := filepath.Split(a.target)
-	if dir != "" {
-		if err := b.mkdir(dir); err != nil {
-			return err
-		}
-	}
-
-	return b.moveOrCopyFile(a, a.target, src, 0644, true)
-}
-
 // cover runs, in effect,
 //	go tool cover -mode=b.coverMode -var="varName" -o dst.go src.go
 func (b *builder) cover(a *action, dst, src string, perm os.FileMode, varName string) error {
 	return b.run(a.objdir, "cover "+a.p.ImportPath, nil,
-		buildToolExec,
 		tool("cover"),
 		"-mode", a.p.coverMode,
 		"-var", varName,
@@ -1691,15 +1236,15 @@ func (b *builder) cover(a *action, dst, src string, perm os.FileMode, varName st
 }
 
 var objectMagic = [][]byte{
-	{'!', '<', 'a', 'r', 'c', 'h', '>', '\n'}, // Package archive
-	{'\x7F', 'E', 'L', 'F'},                   // ELF
-	{0xFE, 0xED, 0xFA, 0xCE},                  // Mach-O big-endian 32-bit
-	{0xFE, 0xED, 0xFA, 0xCF},                  // Mach-O big-endian 64-bit
-	{0xCE, 0xFA, 0xED, 0xFE},                  // Mach-O little-endian 32-bit
-	{0xCF, 0xFA, 0xED, 0xFE},                  // Mach-O little-endian 64-bit
-	{0x4d, 0x5a, 0x90, 0x00, 0x03, 0x00},      // PE (Windows) as generated by 6l/8l and gcc
-	{0x00, 0x00, 0x01, 0xEB},                  // Plan 9 i386
-	{0x00, 0x00, 0x8a, 0x97},                  // Plan 9 amd64
+	{'!', '<', 'a', 'r', 'c', 'h', '>', '\n'},        // Package archive
+	{'\x7F', 'E', 'L', 'F'},                          // ELF
+	{0xFE, 0xED, 0xFA, 0xCE},                         // Mach-O big-endian 32-bit
+	{0xFE, 0xED, 0xFA, 0xCF},                         // Mach-O big-endian 64-bit
+	{0xCE, 0xFA, 0xED, 0xFE},                         // Mach-O little-endian 32-bit
+	{0xCF, 0xFA, 0xED, 0xFE},                         // Mach-O little-endian 64-bit
+	{0x4d, 0x5a, 0x90, 0x00, 0x03, 0x00, 0x04, 0x00}, // PE (Windows) as generated by 6l/8l
+	{0x00, 0x00, 0x01, 0xEB},                         // Plan 9 i386
+	{0x00, 0x00, 0x8a, 0x97},                         // Plan 9 amd64
 }
 
 func isObject(s string) bool {
@@ -1880,7 +1425,7 @@ func (b *builder) runOut(dir string, desc string, env []string, cmdargs ...inter
 		cmd.Stdout = &buf
 		cmd.Stderr = &buf
 		cmd.Dir = dir
-		cmd.Env = mergeEnvLists(env, envForDir(cmd.Dir, os.Environ()))
+		cmd.Env = mergeEnvLists(env, envForDir(cmd.Dir))
 		err := cmd.Run()
 
 		// cmd.Run will fail on Unix if some other process has the binary
@@ -1922,7 +1467,7 @@ func (b *builder) runOut(dir string, desc string, env []string, cmdargs ...inter
 		// Sleeping when we observe the race seems to be the most reliable
 		// option we have.
 		//
-		// https://golang.org/issue/3001
+		// http://golang.org/issue/3001
 		//
 		if err != nil && nbusy < 3 && strings.Contains(err.Error(), "text file busy") {
 			time.Sleep(100 * time.Millisecond << uint(nbusy))
@@ -2005,7 +1550,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, archive, obj string, asmhdr bool, 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
@@ -2018,10 +1563,8 @@ type toolchain interface {
 	// an archive from a set of object files.
 	// typically it is run in the object directory.
 	pack(b *builder, p *Package, objDir, afile string, ofiles []string) error
-	// ld runs the linker to create an executable starting at mainpkg.
-	ld(b *builder, root *action, out string, allactions []*action, mainpkg string, ofiles []string) error
-	// ldShared runs the linker to create a shared library containing the pkgs built by toplevelactions
-	ldShared(b *builder, toplevelactions []*action, out string, allactions []*action) error
+	// ld runs the linker to create a package starting at mainpkg.
+	ld(b *builder, p *Package, out string, allactions []*action, mainpkg string, ofiles []string) error
 
 	compiler() string
 	linker() string
@@ -2044,7 +1587,7 @@ func (noToolchain) linker() string {
 	return ""
 }
 
-func (noToolchain) gc(b *builder, p *Package, archive, obj string, asmhdr bool, 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()
 }
 
@@ -2061,11 +1604,7 @@ func (noToolchain) pack(b *builder, p *Package, objDir, afile string, ofiles []s
 	return noCompiler()
 }
 
-func (noToolchain) ld(b *builder, root *action, out string, allactions []*action, mainpkg string, ofiles []string) error {
-	return noCompiler()
-}
-
-func (noToolchain) ldShared(b *builder, toplevelactions []*action, out string, allactions []*action) error {
+func (noToolchain) ld(b *builder, p *Package, out string, allactions []*action, mainpkg string, ofiles []string) error {
 	return noCompiler()
 }
 
@@ -2077,27 +1616,24 @@ func (noToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error
 type gcToolchain struct{}
 
 func (gcToolchain) compiler() string {
-	return tool("compile")
+	return tool(archChar + "g")
 }
 
 func (gcToolchain) linker() string {
-	return tool("link")
+	return tool(archChar + "l")
 }
 
-func (gcToolchain) gc(b *builder, p *Package, archive, obj string, asmhdr bool, importArgs []string, gofiles []string) (ofile string, output []byte, err error) {
+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_.o"
+		out := "_go_." + archChar
 		ofile = obj + out
 	}
 
 	gcargs := []string{"-p", p.ImportPath}
-	if p.Name == "main" {
-		gcargs[1] = "main"
-	}
 	if p.Standard && p.ImportPath == "runtime" {
-		// runtime compiles with a special gc flag to emit
+		// runtime compiles with a special 6g flag to emit
 		// additional reflect type data.
 		gcargs = append(gcargs, "-+")
 	}
@@ -2119,68 +1655,24 @@ func (gcToolchain) gc(b *builder, p *Package, archive, obj string, asmhdr bool,
 	if buildContext.InstallSuffix != "" {
 		gcargs = append(gcargs, "-installsuffix", buildContext.InstallSuffix)
 	}
-	if p.buildID != "" {
-		gcargs = append(gcargs, "-buildid", p.buildID)
-	}
-
-	for _, path := range p.Imports {
-		if i := strings.LastIndex(path, "/vendor/"); i >= 0 {
-			gcargs = append(gcargs, "-importmap", path[i+len("/vendor/"):]+"="+path)
-		} else if strings.HasPrefix(path, "vendor/") {
-			gcargs = append(gcargs, "-importmap", path[len("vendor/"):]+"="+path)
-		}
-	}
 
-	args := []interface{}{buildToolExec, tool("compile"), "-o", ofile, "-trimpath", b.work, 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")
 	}
-	if asmhdr {
-		args = append(args, "-asmhdr", obj+"go_asm.h")
-	}
 	for _, f := range gofiles {
 		args = append(args, mkAbs(p.Dir, f))
 	}
 
-	output, err = b.runOut(p.Dir, p.ImportPath, nil, args...)
+	output, err = b.runOut(p.Dir, p.ImportPath, nil, args)
 	return ofile, output, err
 }
 
 func (gcToolchain) asm(b *builder, p *Package, obj, ofile, sfile string) error {
 	// Add -I pkg/GOOS_GOARCH so #include "textflag.h" works in .s files.
-	inc := filepath.Join(goroot, "pkg", "include")
+	inc := filepath.Join(goroot, "pkg", fmt.Sprintf("%s_%s", goos, goarch))
 	sfile = mkAbs(p.Dir, sfile)
-	args := []interface{}{buildToolExec, tool("asm"), "-o", ofile, "-trimpath", b.work, "-I", obj, "-I", inc, "-D", "GOOS_" + goos, "-D", "GOARCH_" + goarch, buildAsmflags, sfile}
-	if err := b.run(p.Dir, p.ImportPath, nil, args...); err != nil {
-		return err
-	}
-	return nil
-}
-
-// toolVerify checks that the command line args writes the same output file
-// if run using newTool instead.
-// Unused now but kept around for future use.
-func toolVerify(b *builder, p *Package, newTool string, ofile string, args []interface{}) error {
-	newArgs := make([]interface{}, len(args))
-	copy(newArgs, args)
-	newArgs[1] = tool(newTool)
-	newArgs[3] = ofile + ".new" // x.6 becomes x.6.new
-	if err := b.run(p.Dir, p.ImportPath, nil, newArgs...); err != nil {
-		return err
-	}
-	data1, err := ioutil.ReadFile(ofile)
-	if err != nil {
-		return err
-	}
-	data2, err := ioutil.ReadFile(ofile + ".new")
-	if err != nil {
-		return err
-	}
-	if !bytes.Equal(data1, data2) {
-		return fmt.Errorf("%s and %s produced different output files:\n%s\n%s", filepath.Base(args[1].(string)), newTool, strings.Join(stringList(args...), " "), strings.Join(stringList(newArgs...), " "))
-	}
-	os.Remove(ofile + ".new")
-	return nil
+	return b.run(p.Dir, p.ImportPath, nil, tool(archChar+"a"), "-trimpath", b.work, "-I", obj, "-I", inc, "-o", ofile, "-D", "GOOS_"+goos, "-D", "GOARCH_"+goarch, sfile)
 }
 
 func (gcToolchain) pkgpath(basedir string, p *Package) string {
@@ -2219,7 +1711,7 @@ func (gcToolchain) pack(b *builder, p *Package, objDir, afile string, ofiles []s
 
 	// Need actual pack.
 	cmdline[0] = tool("pack")
-	return b.run(p.Dir, p.ImportPath, nil, buildToolExec, cmdline)
+	return b.run(p.Dir, p.ImportPath, nil, cmdline)
 }
 
 func packInternal(b *builder, afile string, ofiles []string) error {
@@ -2272,49 +1764,21 @@ func packInternal(b *builder, afile string, ofiles []string) error {
 	return dst.Close()
 }
 
-// setextld sets the appropriate linker flags for the specified compiler.
-func setextld(ldflags []string, compiler []string) []string {
-	for _, f := range ldflags {
-		if f == "-extld" || strings.HasPrefix(f, "-extld=") {
-			// don't override -extld if supplied
-			return ldflags
-		}
-	}
-	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 ldflags
-}
-
-func (gcToolchain) ld(b *builder, root *action, out string, allactions []*action, mainpkg string, ofiles []string) error {
+func (gcToolchain) ld(b *builder, p *Package, out string, allactions []*action, mainpkg string, ofiles []string) error {
 	importArgs := b.includeArgs("-L", allactions)
-	cxx := len(root.p.CXXFiles) > 0 || len(root.p.SwigCXXFiles) > 0
+	cxx := len(p.CXXFiles) > 0
 	for _, a := range allactions {
-		if a.p != nil && (len(a.p.CXXFiles) > 0 || len(a.p.SwigCXXFiles) > 0) {
+		if a.p != nil && len(a.p.CXXFiles) > 0 {
 			cxx = true
 		}
 	}
-	var ldflags []string
+	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 root.p.omitDWARF {
+	if p.omitDWARF {
 		ldflags = append(ldflags, "-w")
 	}
 
@@ -2322,67 +1786,56 @@ func (gcToolchain) ld(b *builder, root *action, out string, allactions []*action
 	// 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.
-	var compiler []string
-	if cxx {
-		compiler = envList("CXX", defaultCXX)
-	} else {
-		compiler = envList("CC", defaultCC)
-	}
-	ldflags = setextld(ldflags, compiler)
-	ldflags = append(ldflags, "-buildmode="+ldBuildmode)
-	if root.p.buildID != "" {
-		ldflags = append(ldflags, "-buildid="+root.p.buildID)
-	}
-	ldflags = append(ldflags, buildLdflags...)
-
-	// On OS X when using external linking to build a shared library,
-	// the argument passed here to -o ends up recorded in the final
-	// shared library in the LC_ID_DYLIB load command.
-	// To avoid putting the temporary output directory name there
-	// (and making the resulting shared library useless),
-	// run the link in the output directory so that -o can name
-	// just the final path element.
-	dir := "."
-	if goos == "darwin" && buildBuildmode == "c-shared" {
-		dir, out = filepath.Split(out)
-	}
-
-	return b.run(dir, root.p.ImportPath, nil, buildToolExec, tool("link"), "-o", out, importArgs, ldflags, mainpkg)
-}
-
-func (gcToolchain) ldShared(b *builder, toplevelactions []*action, out string, allactions []*action) error {
-	importArgs := b.includeArgs("-L", allactions)
-	ldflags := []string{"-installsuffix", buildContext.InstallSuffix}
-	ldflags = append(ldflags, "-buildmode=shared")
-	ldflags = append(ldflags, buildLdflags...)
-	cxx := false
-	for _, a := range allactions {
-		if a.p != nil && (len(a.p.CXXFiles) > 0 || len(a.p.SwigCXXFiles) > 0) {
-			cxx = true
+	extld := false
+	for _, f := range ldflags {
+		if f == "-extld" || strings.HasPrefix(f, "-extld=") {
+			extld = true
+			break
 		}
 	}
-	// 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.
-	var compiler []string
-	if cxx {
-		compiler = envList("CXX", defaultCXX)
-	} else {
-		compiler = envList("CC", defaultCC)
-	}
-	ldflags = setextld(ldflags, compiler)
-	for _, d := range toplevelactions {
-		if !strings.HasSuffix(d.target, ".a") { // omit unsafe etc and actions for other shared libraries
-			continue
+	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)
+			}
 		}
-		ldflags = append(ldflags, d.p.ImportPath+"="+d.target)
 	}
-	return b.run(".", out, nil, buildToolExec, tool("link"), "-o", out, importArgs, ldflags)
+	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 {
-	return fmt.Errorf("%s: C source files not supported without cgo", mkAbs(p.Dir, cfile))
+	inc := filepath.Join(goroot, "pkg", fmt.Sprintf("%s_%s", goos, goarch))
+	cfile = mkAbs(p.Dir, cfile)
+	warn := []string{"-w"}
+	if p.usesSwig() {
+		// When using SWIG, this compiler is only used to
+		// compile the C files generated by SWIG.
+		// We don't want warnings.
+		// See issue 9065 for details.
+		warn = nil
+	}
+	args := stringList(tool(archChar+"c"), "-F", "-V", warn, "-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)
 }
 
 // The Gccgo toolchain.
@@ -2406,7 +1859,7 @@ func (gccgoToolchain) linker() string {
 	return gccgoBin
 }
 
-func (tools gccgoToolchain) gc(b *builder, p *Package, archive, obj string, asmhdr bool, 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 := "_go_.o"
 	ofile = obj + out
 	gcargs := []string{"-g"}
@@ -2417,7 +1870,7 @@ func (tools gccgoToolchain) gc(b *builder, p *Package, archive, obj string, asmh
 	if p.localPrefix != "" {
 		gcargs = append(gcargs, "-fgo-relative-import-path="+p.localPrefix)
 	}
-	args := stringList(tools.compiler(), importArgs, "-c", gcargs, "-o", ofile, buildGccgoflags)
+	args := stringList(gccgoName, importArgs, "-c", gcargs, "-o", ofile, buildGccgoflags)
 	for _, f := range gofiles {
 		args = append(args, mkAbs(p.Dir, f))
 	}
@@ -2426,15 +1879,14 @@ func (tools gccgoToolchain) gc(b *builder, p *Package, archive, obj string, asmh
 	return ofile, output, err
 }
 
-func (tools gccgoToolchain) asm(b *builder, p *Package, obj, ofile, sfile string) error {
+func (gccgoToolchain) asm(b *builder, p *Package, obj, ofile, sfile string) error {
 	sfile = mkAbs(p.Dir, sfile)
 	defs := []string{"-D", "GOOS_" + goos, "-D", "GOARCH_" + goarch}
 	if pkgpath := gccgoCleanPkgpath(p); pkgpath != "" {
 		defs = append(defs, `-D`, `GOPKGPATH="`+pkgpath+`"`)
 	}
-	defs = tools.maybePIC(defs)
 	defs = append(defs, b.gccArchArgs()...)
-	return b.run(p.Dir, p.ImportPath, nil, tools.compiler(), "-I", obj, "-o", ofile, defs, sfile)
+	return b.run(p.Dir, p.ImportPath, nil, gccgoName, "-I", obj, "-o", ofile, defs, sfile)
 }
 
 func (gccgoToolchain) pkgpath(basedir string, p *Package) string {
@@ -2452,49 +1904,27 @@ func (gccgoToolchain) pack(b *builder, p *Package, objDir, afile string, ofiles
 	return b.run(p.Dir, p.ImportPath, nil, "ar", "cru", mkAbs(objDir, afile), absOfiles)
 }
 
-func (tools gccgoToolchain) ld(b *builder, root *action, out string, allactions []*action, mainpkg string, ofiles []string) error {
+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.
 	apackagesSeen := make(map[*Package]bool)
 	afiles := []string{}
-	shlibs := []string{}
-	xfiles := []string{}
 	ldflags := b.gccArchArgs()
 	cgoldflags := []string{}
 	usesCgo := false
-	cxx := len(root.p.CXXFiles) > 0 || len(root.p.SwigCXXFiles) > 0
-	objc := len(root.p.MFiles) > 0
-
-	actionsSeen := make(map[*action]bool)
-	// Make a pre-order depth-first traversal of the action graph, taking note of
-	// whether a shared library action has been seen on the way to an action (the
-	// construction of the graph means that if any path to a node passes through
-	// a shared library action, they all do).
-	var walk func(a *action, seenShlib bool)
-	walk = func(a *action, seenShlib bool) {
-		if actionsSeen[a] {
-			return
-		}
-		actionsSeen[a] = true
-		if a.p != nil && !seenShlib {
-			if a.p.Standard {
-				return
-			}
-			// We record the target of the first time we see a .a file
-			// for a package to make sure that we prefer the 'install'
-			// rather than the 'build' location (which may not exist any
-			// more). We still need to traverse the dependencies of the
-			// build action though so saying
-			// if apackagesSeen[a.p] { return }
-			// doesn't work.
-			if !apackagesSeen[a.p] {
+	cxx := len(p.CXXFiles) > 0
+	objc := len(p.MFiles) > 0
+
+	// 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 && a.p.external {
-					// external _tests, if present must come before
-					// internal _tests. Store these on a separate list
-					// and place them at the head after this loop.
-					xfiles = append(xfiles, a.target)
-				} else if a.p.fake {
+				if a.p.fake {
 					// move _test files to the top of the link order
 					afiles = append([]string{a.target}, afiles...)
 				} else {
@@ -2502,182 +1932,53 @@ func (tools gccgoToolchain) ld(b *builder, root *action, out string, allactions
 				}
 			}
 		}
-		if strings.HasSuffix(a.target, ".so") {
-			shlibs = append(shlibs, a.target)
-			seenShlib = true
-		}
-		for _, a1 := range a.deps {
-			walk(a1, seenShlib)
-		}
-	}
-	for _, a1 := range root.deps {
-		walk(a1, false)
 	}
-	afiles = append(xfiles, afiles...)
 
 	for _, a := range allactions {
-		// Gather CgoLDFLAGS, but not from standard packages.
-		// The go tool can dig up runtime/cgo from GOROOT and
-		// think that it should use its CgoLDFLAGS, but gccgo
-		// doesn't use runtime/cgo.
-		if a.p == nil {
-			continue
-		}
-		if !a.p.Standard {
+		if a.p != nil {
 			cgoldflags = append(cgoldflags, a.p.CgoLDFLAGS...)
+			if len(a.p.CgoFiles) > 0 {
+				usesCgo = true
+			}
+			if a.p.usesSwig() {
+				usesCgo = true
+			}
+			if len(a.p.CXXFiles) > 0 {
+				cxx = true
+			}
+			if len(a.p.MFiles) > 0 {
+				objc = true
+			}
 		}
-		if len(a.p.CgoFiles) > 0 {
-			usesCgo = true
-		}
-		if a.p.usesSwig() {
-			usesCgo = true
-		}
-		if len(a.p.CXXFiles) > 0 || len(a.p.SwigCXXFiles) > 0 {
-			cxx = true
-		}
-		if len(a.p.MFiles) > 0 {
-			objc = true
-		}
-	}
-
-	switch ldBuildmode {
-	case "c-archive", "c-shared":
-		ldflags = append(ldflags, "-Wl,--whole-archive")
 	}
-
 	ldflags = append(ldflags, afiles...)
-
-	switch ldBuildmode {
-	case "c-archive", "c-shared":
-		ldflags = append(ldflags, "-Wl,--no-whole-archive")
-	}
-
 	ldflags = append(ldflags, cgoldflags...)
 	ldflags = append(ldflags, envList("CGO_LDFLAGS", "")...)
-	ldflags = append(ldflags, root.p.CgoLDFLAGS...)
-
-	ldflags = stringList("-Wl,-(", ldflags, "-Wl,-)")
-
-	for _, shlib := range shlibs {
-		ldflags = append(
-			ldflags,
-			"-L"+filepath.Dir(shlib),
-			"-Wl,-rpath="+filepath.Dir(shlib),
-			"-l"+strings.TrimSuffix(
-				strings.TrimPrefix(filepath.Base(shlib), "lib"),
-				".so"))
-	}
-
-	var realOut string
-	switch ldBuildmode {
-	case "exe":
-		if usesCgo && goos == "linux" {
-			ldflags = append(ldflags, "-Wl,-E")
-		}
-
-	case "c-archive":
-		// Link the Go files into a single .o, and also link
-		// in -lgolibbegin.
-		//
-		// We need to use --whole-archive with -lgolibbegin
-		// because it doesn't define any symbols that will
-		// cause the contents to be pulled in; it's just
-		// initialization code.
-		//
-		// The user remains responsible for linking against
-		// -lgo -lpthread -lm in the final link.  We can't use
-		// -r to pick them up because we can't combine
-		// split-stack and non-split-stack code in a single -r
-		// link, and libgo picks up non-split-stack code from
-		// libffi.
-		ldflags = append(ldflags, "-Wl,-r", "-nostdlib", "-Wl,--whole-archive", "-lgolibbegin", "-Wl,--no-whole-archive")
-
-		// We are creating an object file, so we don't want a build ID.
-		ldflags = b.disableBuildID(ldflags)
-
-		realOut = out
-		out = out + ".o"
-
-	case "c-shared":
-		ldflags = append(ldflags, "-shared", "-nostdlib", "-Wl,--whole-archive", "-lgolibbegin", "-Wl,--no-whole-archive", "-lgo", "-lgcc_s", "-lgcc")
-
-	default:
-		fatalf("-buildmode=%s not supported for gccgo", ldBuildmode)
-	}
-
-	switch ldBuildmode {
-	case "exe", "c-shared":
-		if cxx {
-			ldflags = append(ldflags, "-lstdc++")
-		}
-		if objc {
-			ldflags = append(ldflags, "-lobjc")
-		}
+	ldflags = append(ldflags, p.CgoLDFLAGS...)
+	if usesCgo && goos == "linux" {
+		ldflags = append(ldflags, "-Wl,-E")
 	}
-
-	if err := b.run(".", root.p.ImportPath, nil, tools.linker(), "-o", out, ofiles, ldflags, buildGccgoflags); err != nil {
-		return err
-	}
-
-	switch ldBuildmode {
-	case "c-archive":
-		if err := b.run(".", root.p.ImportPath, nil, "ar", "rc", realOut, out); err != nil {
-			return err
-		}
-	}
-	return nil
-}
-
-func (tools gccgoToolchain) ldShared(b *builder, toplevelactions []*action, out string, allactions []*action) error {
-	args := []string{"-o", out, "-shared", "-nostdlib", "-zdefs", "-Wl,--whole-archive"}
-	for _, a := range toplevelactions {
-		args = append(args, a.target)
-	}
-	args = append(args, "-Wl,--no-whole-archive", "-shared", "-nostdlib", "-lgo", "-lgcc_s", "-lgcc", "-lc")
-	shlibs := []string{}
-	for _, a := range allactions {
-		if strings.HasSuffix(a.target, ".so") {
-			shlibs = append(shlibs, a.target)
-		}
+	if cxx {
+		ldflags = append(ldflags, "-lstdc++")
 	}
-	for _, shlib := range shlibs {
-		args = append(
-			args,
-			"-L"+filepath.Dir(shlib),
-			"-Wl,-rpath="+filepath.Dir(shlib),
-			"-l"+strings.TrimSuffix(
-				strings.TrimPrefix(filepath.Base(shlib), "lib"),
-				".so"))
+	if objc {
+		ldflags = append(ldflags, "-lobjc")
 	}
-	return b.run(".", out, nil, tools.linker(), args, buildGccgoflags)
+	return b.run(".", p.ImportPath, nil, gccgoName, "-o", out, ofiles, "-Wl,-(", ldflags, "-Wl,-)", buildGccgoflags)
 }
 
-func (tools gccgoToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error {
-	inc := filepath.Join(goroot, "pkg", "include")
+func (gccgoToolchain) 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)
 	defs := []string{"-D", "GOOS_" + goos, "-D", "GOARCH_" + goarch}
 	defs = append(defs, b.gccArchArgs()...)
 	if pkgpath := gccgoCleanPkgpath(p); pkgpath != "" {
 		defs = append(defs, `-D`, `GOPKGPATH="`+pkgpath+`"`)
 	}
-	switch goarch {
-	case "386", "amd64":
-		defs = append(defs, "-fsplit-stack")
-	}
-	defs = tools.maybePIC(defs)
 	return b.run(p.Dir, p.ImportPath, nil, envList("CC", defaultCC), "-Wall", "-g",
 		"-I", objdir, "-I", inc, "-o", ofile, defs, "-c", cfile)
 }
 
-// maybePIC adds -fPIC to the list of arguments if needed.
-func (tools gccgoToolchain) maybePIC(args []string) []string {
-	switch buildBuildmode {
-	case "c-shared", "shared":
-		args = append(args, "-fPIC")
-	}
-	return args
-}
-
 func gccgoPkgpath(p *Package) string {
 	if p.build.IsCommand() && !p.forceLibrary {
 		return ""
@@ -2753,7 +2054,7 @@ func (b *builder) ccompile(p *Package, out string, flags []string, file string,
 // gccld runs the gcc linker to create an executable from a set of object files.
 func (b *builder) gccld(p *Package, out string, flags []string, obj []string) error {
 	var cmd []string
-	if len(p.CXXFiles) > 0 || len(p.SwigCXXFiles) > 0 {
+	if len(p.CXXFiles) > 0 {
 		cmd = b.gxxCmd(p.Dir)
 	} else {
 		cmd = b.gccCmd(p.Dir)
@@ -2812,7 +2113,7 @@ func (b *builder) ccompilerCmd(envvar, defcmd, objdir string) []string {
 
 	// 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 https://golang.org/issue/3253.
+	// See http://golang.org/issue/3253.
 	if goos == "darwin" {
 		a = append(a, "-fno-common")
 	}
@@ -2822,12 +2123,12 @@ func (b *builder) ccompilerCmd(envvar, defcmd, objdir string) []string {
 
 // gccArchArgs returns arguments to pass to gcc based on the architecture.
 func (b *builder) gccArchArgs() []string {
-	switch goarch {
-	case "386":
+	switch archChar {
+	case "8":
 		return []string{"-m32"}
-	case "amd64", "amd64p32":
+	case "6":
 		return []string{"-m64"}
-	case "arm":
+	case "5":
 		return []string{"-marm"} // not thumb
 	}
 	return nil
@@ -2865,7 +2166,7 @@ var (
 	cgoLibGccFileOnce sync.Once
 )
 
-func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, cgofiles, gccfiles, gxxfiles, mfiles []string) (outGo, outObj []string, err error) {
+func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, gccfiles, gxxfiles, mfiles []string) (outGo, outObj []string, err error) {
 	cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, cgoLDFLAGS := b.cflags(p, true)
 	_, cgoexeCFLAGS, _, _ := b.cflags(p, false)
 	cgoCPPFLAGS = append(cgoCPPFLAGS, pcCFLAGS...)
@@ -2882,7 +2183,7 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, cgofi
 	// TODO: CGOPKGPATH, CGO_FLAGS?
 	gofiles := []string{obj + "_cgo_gotypes.go"}
 	cfiles := []string{"_cgo_main.c", "_cgo_export.c"}
-	for _, fn := range cgofiles {
+	for _, fn := range p.CgoFiles {
 		f := cgoRe.ReplaceAllString(fn[:len(fn)-2], "_")
 		gofiles = append(gofiles, obj+f+"cgo1.go")
 		cfiles = append(cfiles, f+"cgo2.c")
@@ -2892,6 +2193,8 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, cgofi
 	cgoflags := []string{}
 	// TODO: make cgo not depend on $GOARCH?
 
+	objExt := archChar
+
 	if p.Standard && p.ImportPath == "runtime/cgo" {
 		cgoflags = append(cgoflags, "-import_runtime_cgo=false")
 	}
@@ -2910,38 +2213,23 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, cgofi
 	}
 
 	if _, ok := buildToolchain.(gccgoToolchain); ok {
-		switch goarch {
-		case "386", "amd64":
-			cgoCFLAGS = append(cgoCFLAGS, "-fsplit-stack")
-		}
 		cgoflags = append(cgoflags, "-gccgo")
 		if pkgpath := gccgoPkgpath(p); pkgpath != "" {
 			cgoflags = append(cgoflags, "-gccgopkgpath="+pkgpath)
 		}
+		objExt = "o"
 	}
-
-	switch buildBuildmode {
-	case "c-archive", "c-shared":
-		// Tell cgo that if there are any exported functions
-		// it should generate a header file that C code can
-		// #include.
-		cgoflags = append(cgoflags, "-exportheader="+obj+"_cgo_install.h")
-	}
-
-	if err := b.run(p.Dir, p.ImportPath, cgoenv, buildToolExec, cgoExe, "-objdir", obj, "-importpath", p.ImportPath, cgoflags, "--", cgoCPPFLAGS, cgoexeCFLAGS, 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...)
 
 	// cc _cgo_defun.c
-	_, gccgo := buildToolchain.(gccgoToolchain)
-	if gccgo {
-		defunObj := obj + "_cgo_defun.o"
-		if err := buildToolchain.cc(b, p, obj, defunObj, defunC); err != nil {
-			return nil, nil, err
-		}
-		outObj = append(outObj, defunObj)
+	defunObj := obj + "_cgo_defun." + objExt
+	if err := buildToolchain.cc(b, p, obj, defunObj, defunC); err != nil {
+		return nil, nil, err
 	}
+	outObj = append(outObj, defunObj)
 
 	// gcc
 	var linkobj []string
@@ -3055,15 +2343,20 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, cgofi
 	}
 
 	// cgo -dynimport
-	importGo := obj + "_cgo_import.go"
+	importC := obj + "_cgo_import.c"
 	cgoflags = []string{}
 	if p.Standard && p.ImportPath == "runtime/cgo" {
 		cgoflags = append(cgoflags, "-dynlinker") // record path to dynamic linker
 	}
-	if err := b.run(p.Dir, p.ImportPath, nil, buildToolExec, cgoExe, "-objdir", obj, "-dynpackage", p.Name, "-dynimport", dynobj, "-dynout", importGo, cgoflags); err != nil {
+	if err := b.run(p.Dir, p.ImportPath, nil, cgoExe, "-objdir", obj, "-dynimport", dynobj, "-dynout", importC, cgoflags); err != nil {
+		return nil, nil, err
+	}
+
+	// cc _cgo_import.ARCH
+	importObj := obj + "_cgo_import." + objExt
+	if err := buildToolchain.cc(b, p, obj, importObj, importC); err != nil {
 		return nil, nil, err
 	}
-	outGo = append(outGo, importGo)
 
 	ofile := obj + "_all.o"
 	var gccObjs, nonGccObjs []string
@@ -3076,8 +2369,19 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, cgofi
 	}
 	ldflags := stringList(bareLDFLAGS, "-Wl,-r", "-nostdlib", staticLibs)
 
-	// We are creating an object file, so we don't want a build ID.
-	ldflags = b.disableBuildID(ldflags)
+	// Some systems, such as Ubuntu, always add --build-id to
+	// every link, but we don't want a build ID since we are
+	// producing an object file.  On some of those system a plain
+	// -r (not -Wl,-r) will turn off --build-id, but clang 3.0
+	// doesn't support a plain -r.  I don't know how to turn off
+	// --build-id when using clang other than passing a trailing
+	// --build-id=none.  So that is what we do, but only on
+	// systems likely to support it, which is to say, systems that
+	// normally use gold or the GNU linker.
+	switch goos {
+	case "android", "dragonfly", "linux", "netbsd":
+		ldflags = append(ldflags, "-Wl,--build-id=none")
+	}
 
 	if err := b.gccld(p, ofile, ldflags, gccObjs); err != nil {
 		return nil, nil, err
@@ -3085,8 +2389,8 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, cgofi
 
 	// NOTE(rsc): The importObj is a 5c/6c/8c object and on Windows
 	// must be processed before the gcc-generated objects.
-	// Put it first.  https://golang.org/issue/2601
-	outObj = stringList(nonGccObjs, ofile)
+	// Put it first.  http://golang.org/issue/2601
+	outObj = stringList(importObj, nonGccObjs, ofile)
 
 	return outGo, outObj, nil
 }
@@ -3094,41 +2398,77 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, cgofi
 // 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, pcCFLAGS []string) (outGo, outC, outCXX []string, err error) {
+func (b *builder) swig(p *Package, obj string, pcCFLAGS, gccfiles, gxxfiles, mfiles []string) (outGo, outObj []string, err error) {
+	cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, _ := b.cflags(p, true)
+	cflags := stringList(cgoCPPFLAGS, cgoCFLAGS)
+	cxxflags := stringList(cgoCPPFLAGS, cgoCXXFLAGS)
+
+	for _, file := range gccfiles {
+		ofile := obj + cgoRe.ReplaceAllString(file[:len(file)-1], "_") + "o"
+		if err := b.gcc(p, ofile, cflags, file); err != nil {
+			return nil, nil, err
+		}
+		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, cxxflags, file); err != nil {
+			return nil, nil, err
+		}
+		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, nil, err
+		return nil, nil, err
 	}
 
 	intgosize, err := b.swigIntSize(obj)
 	if err != nil {
-		return nil, nil, nil, err
+		return nil, nil, err
 	}
 
 	for _, f := range p.SwigFiles {
-		goFile, cFile, err := b.swigOne(p, f, obj, pcCFLAGS, false, intgosize)
+		goFile, objFile, gccObjFile, err := b.swigOne(p, f, obj, pcCFLAGS, false, intgosize)
 		if err != nil {
-			return nil, nil, nil, err
+			return nil, nil, err
 		}
 		if goFile != "" {
 			outGo = append(outGo, goFile)
 		}
-		if cFile != "" {
-			outC = append(outC, cFile)
+		if objFile != "" {
+			outObj = append(outObj, objFile)
+		}
+		if gccObjFile != "" {
+			outObj = append(outObj, gccObjFile)
 		}
 	}
 	for _, f := range p.SwigCXXFiles {
-		goFile, cxxFile, err := b.swigOne(p, f, obj, pcCFLAGS, true, intgosize)
+		goFile, objFile, gccObjFile, err := b.swigOne(p, f, obj, pcCFLAGS, true, intgosize)
 		if err != nil {
-			return nil, nil, nil, err
+			return nil, nil, err
 		}
 		if goFile != "" {
 			outGo = append(outGo, goFile)
 		}
-		if cxxFile != "" {
-			outCXX = append(outCXX, cxxFile)
+		if objFile != "" {
+			outObj = append(outObj, objFile)
+		}
+		if gccObjFile != "" {
+			outObj = append(outObj, gccObjFile)
 		}
 	}
-	return outGo, outC, outCXX, nil
+	return outGo, outObj, nil
 }
 
 // Make sure SWIG is new enough.
@@ -3142,51 +2482,20 @@ func (b *builder) swigDoVersionCheck() error {
 	if err != nil {
 		return err
 	}
-	re := regexp.MustCompile(`[vV]ersion +([\d]+)([.][\d]+)?([.][\d]+)?`)
+	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
 	}
-	const errmsg = "must have SWIG version >= 3.0.6"
 	if major < 3 {
-		return errors.New(errmsg)
-	}
-	if major > 3 {
-		// 4.0 or later
-		return nil
+		return errors.New("must have SWIG version >= 3.0")
 	}
-
-	// We have SWIG version 3.x.
-	if len(matches[2]) > 0 {
-		minor, err := strconv.Atoi(string(matches[2][1:]))
-		if err != nil {
-			return nil
-		}
-		if minor > 0 {
-			// 3.1 or later
-			return nil
-		}
-	}
-
-	// We have SWIG version 3.0.x.
-	if len(matches[3]) > 0 {
-		patch, err := strconv.Atoi(string(matches[3][1:]))
-		if err != nil {
-			return nil
-		}
-		if patch < 6 {
-			// Before 3.0.6.
-			return errors.New(errmsg)
-		}
-	}
-
 	return nil
 }
 
@@ -3217,14 +2526,14 @@ func (b *builder) swigIntSize(obj string) (intsize string, err error) {
 
 	p := goFilesPackage(srcs)
 
-	if _, _, e := buildToolchain.gc(b, p, "", obj, false, 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, pcCFLAGS []string, cxx bool, intgosize string) (outGo, outC string, err error) {
+func (b *builder) swigOne(p *Package, file, obj string, pcCFLAGS []string, cxx bool, intgosize string) (outGo, outObj, objGccObj string, err error) {
 	cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, _ := b.cflags(p, true)
 	var cflags []string
 	if cxx {
@@ -3239,6 +2548,7 @@ func (b *builder) swigOne(p *Package, file, obj string, pcCFLAGS []string, cxx b
 	}
 	base := file[:len(file)-n]
 	goFile := base + ".go"
+	cBase := base + "_gc."
 	gccBase := base + "_wrap."
 	gccExt := "c"
 	if cxx {
@@ -3250,7 +2560,6 @@ func (b *builder) swigOne(p *Package, file, obj string, pcCFLAGS []string, cxx b
 	// swig
 	args := []string{
 		"-go",
-		"-cgo",
 		"-intgosize", intgosize,
 		"-module", base,
 		"-o", obj + gccBase + gccExt,
@@ -3273,40 +2582,39 @@ func (b *builder) swigOne(p *Package, file, obj string, pcCFLAGS []string, cxx b
 		args = append(args, "-c++")
 	}
 
-	out, err := b.runOut(p.Dir, p.ImportPath, nil, "swig", args, file)
-	if err != nil {
+	if out, err := b.runOut(p.Dir, p.ImportPath, nil, "swig", args, file); err != nil {
 		if len(out) > 0 {
-			if bytes.Contains(out, []byte("-intgosize")) || bytes.Contains(out, []byte("-cgo")) {
-				return "", "", errors.New("must have SWIG version >= 3.0.6")
+			if bytes.Contains(out, []byte("Unrecognized option -intgosize")) {
+				return "", "", "", errors.New("must have SWIG version >= 3.0")
 			}
-			b.showOutput(p.Dir, p.ImportPath, b.processOutput(out)) // swig error
-			return "", "", errPrintedOutput
+			b.showOutput(p.Dir, p.ImportPath, b.processOutput(out))
+			return "", "", "", errPrintedOutput
 		}
-		return "", "", err
-	}
-	if len(out) > 0 {
-		b.showOutput(p.Dir, p.ImportPath, b.processOutput(out)) // swig warning
+		return "", "", "", err
 	}
 
-	return obj + goFile, obj + gccBase + gccExt, nil
-}
+	var cObj string
+	if !gccgo {
+		// cc
+		cObj = obj + cBase + archChar
+		if err := buildToolchain.cc(b, p, obj, cObj, obj+cBase+"c"); err != nil {
+			return "", "", "", err
+		}
+	}
 
-// disableBuildID adjusts a linker command line to avoid creating a
-// build ID when creating an object file rather than an executable or
-// shared library.  Some systems, such as Ubuntu, always add
-// --build-id to every link, but we don't want a build ID when we are
-// producing an object file.  On some of those system a plain -r (not
-// -Wl,-r) will turn off --build-id, but clang 3.0 doesn't support a
-// plain -r.  I don't know how to turn off --build-id when using clang
-// other than passing a trailing --build-id=none.  So that is what we
-// do, but only on systems likely to support it, which is to say,
-// systems that normally use gold or the GNU linker.
-func (b *builder) disableBuildID(ldflags []string) []string {
-	switch goos {
-	case "android", "dragonfly", "linux", "netbsd":
-		ldflags = append(ldflags, "-Wl,--build-id=none")
+	// gcc
+	gccObj := obj + gccBase + "o"
+	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
+		}
 	}
-	return ldflags
+
+	return obj + goFile, cObj, gccObj, nil
 }
 
 // An actionQueue is a priority queue of actions.
@@ -3342,6 +2650,7 @@ func raceInit() {
 	}
 	buildGcflags = append(buildGcflags, "-race")
 	buildLdflags = append(buildLdflags, "-race")
+	buildCcflags = append(buildCcflags, "-D", "RACE")
 	if buildContext.InstallSuffix != "" {
 		buildContext.InstallSuffix += "_"
 	}
diff --git a/src/cmd/go/doc.go b/src/cmd/go/doc.go
index 4a07dfe..7191ee0 100644
--- a/src/cmd/go/doc.go
+++ b/src/cmd/go/doc.go
@@ -1,103 +1,1131 @@
-// Copyright 2015 The Go Authors.  All rights reserved.
+// 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 main
+// DO NOT EDIT THIS FILE. GENERATED BY mkdoc.sh.
+// Edit the documentation in other files and rerun mkdoc.sh to generate this one.
+
+/*
+Go is a tool for managing Go source code.
+
+Usage:
+
+	go command [arguments]
+
+The commands are:
+
+    build       compile packages and dependencies
+    clean       remove object files
+    env         print Go environment information
+    fix         run go tool fix on packages
+    fmt         run gofmt on package sources
+    generate    generate Go files by processing source
+    get         download and install packages and dependencies
+    install     compile and install packages and dependencies
+    list        list packages
+    run         compile and run Go program
+    test        test packages
+    tool        run specified go tool
+    version     print Go version
+    vet         run go tool vet on packages
+
+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
+    testflag    description of testing flags
+    testfunc    description of testing functions
+
+Use "go help [topic]" for more information about that topic.
+
+
+Compile packages and dependencies
+
+Usage:
+
+	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.
+
+If the arguments are a list of .go files, build treats them as a list
+of source files specifying a single package.
+
+When the command line specifies a single main package,
+build writes the resulting executable to output.
+Otherwise build compiles the packages but discards the results,
+serving only as a check that the packages can be built.
+
+The -o flag specifies the output file name. If not specified, the
+output file name depends on the arguments and derives from the name
+of the package, such as p.a for package p, unless p is 'main'. If
+the package is main and file names are provided, the file name
+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 -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.
+		In Go releases, does not apply to the standard library.
+	-n
+		print the commands but do not run them.
+	-p n
+		the number of builds that can be run in parallel.
+		The default is the number of CPUs available.
+	-race
+		enable data race detection.
+		Supported only on linux/amd64, freebsd/amd64, darwin/amd64 and windows/amd64.
+	-v
+		print the names of packages as they are compiled.
+	-work
+		print the name of the temporary work directory and
+		do not delete it when exiting.
+	-x
+		print the commands.
+
+	-ccflags 'arg list'
+		arguments to pass on each 5c, 6c, or 8c compiler invocation.
+	-compiler name
+		name of compiler to use, as in runtime.Compiler (gccgo or gc).
+	-gccgoflags 'arg list'
+		arguments to pass on each gccgo compiler/linker invocation.
+	-gcflags 'arg list'
+		arguments to pass on each 5g, 6g, or 8g compiler invocation.
+	-installsuffix suffix
+		a suffix to use in the name of the package installation directory,
+		in order to keep output separate from default builds.
+		If using the -race flag, the install suffix is automatically set to race
+		or, if set explicitly, has _race appended to it.
+	-ldflags 'flag list'
+		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.
+		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.
+
+For more about specifying packages, see 'go help packages'.
+For more about where packages and binaries are installed,
+run 'go help gopath'.  For more about calling between Go and C/C++,
+run 'go help c'.
+
+See also: go install, go get, go clean.
+
+
+Remove object files
+
+Usage:
+
+	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,
+so go clean is mainly concerned with object files left by other
+tools or by manual invocations of go build.
+
+Specifically, clean removes the following files from each of the
+source directories corresponding to the import paths:
+
+	_obj/            old object directory, left from Makefiles
+	_test/           old test directory, left from Makefiles
+	_testmain.go     old gotest file, left from Makefiles
+	test.out         old test log, left from Makefiles
+	build.out        old test log, left from Makefiles
+	*.[568ao]        object files, left from Makefiles
+
+	DIR(.exe)        from go build
+	DIR.test(.exe)   from go test -c
+	MAINFILE(.exe)   from go build MAINFILE.go
+	*.so             from SWIG
+
+In the list, DIR represents the final path element of the
+directory, and MAINFILE is the base name of any Go source
+file in the directory that is not included when building
+the package.
+
+The -i flag causes clean to remove the corresponding installed
+archive or binary (what 'go install' would create).
+
+The -n flag causes clean to print the remove commands it would execute,
+but not run them.
+
+The -r flag causes clean to be applied recursively to all the
+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'.
+
+
+Print Go environment information
+
+Usage:
+
+	go env [var ...]
+
+Env prints Go environment information.
+
+By default env prints information as a shell script
+(on Windows, a batch file).  If one or more variable
+names is given as arguments,  env prints the value of
+each named variable on its own line.
+
+
+Run go tool fix on packages
+
+Usage:
+
+	go fix [packages]
+
+Fix runs the Go fix command on the packages named by the import paths.
+
+For more about fix, see 'godoc fix'.
+For more about specifying packages, see 'go help packages'.
+
+To run fix with specific options, run 'go tool fix'.
+
+See also: go fmt, go vet.
+
+
+Run gofmt on package sources
+
+Usage:
+
+	go fmt [-n] [-x] [packages]
+
+Fmt runs the command 'gofmt -l -w' on the packages named
+by the import paths.  It prints the names of the files that are modified.
+
+For more about gofmt, see 'godoc gofmt'.
+For more about specifying packages, see 'go help packages'.
+
+The -n flag prints commands that would be executed.
+The -x flag prints commands as they are executed.
+
+To run gofmt with specific options, run gofmt itself.
+
+See also: go fix, go vet.
+
+
+Generate Go files by processing source
+
+Usage:
+
+	go generate [-run regexp] [file.go... | packages]
+
+Generate runs commands described by directives within existing
+files. Those commands can run any process but the intent is to
+create or update Go source files, for instance by running yacc.
+
+Go generate is never run automatically by go build, go get, go test,
+and so on. It must be run explicitly.
+
+Go generate scans the file for directives, which are lines of
+the form,
+
+	//go:generate command argument...
+
+(note: no leading spaces and no space in "//go") where command
+is the generator to be run, corresponding to an executable file
+that can be run locally. It must either be in the shell path
+(gofmt), a fully qualified path (/usr/you/bin/mytool), or a
+command alias, described below.
+
+Note that go generate does not parse the file, so lines that look
+like directives in comments or multiline strings will be treated
+as directives.
+
+The arguments to the directive are space-separated tokens or
+double-quoted strings passed to the generator as individual
+arguments when it is run.
+
+Quoted strings use Go syntax and are evaluated before execution; a
+quoted string appears as a single argument to the generator.
+
+Go generate sets several variables when it runs the generator:
+
+	$GOARCH
+		The execution architecture (arm, amd64, etc.)
+	$GOOS
+		The execution operating system (linux, windows, etc.)
+	$GOFILE
+		The base name of the file.
+	$GOPACKAGE
+		The name of the package of the file containing the directive.
+
+Other than variable substitution and quoted-string evaluation, no
+special processing such as "globbing" is performed on the command
+line.
+
+As a last step before running the command, any invocations of any
+environment variables with alphanumeric names, such as $GOFILE or
+$HOME, are expanded throughout the command line. The syntax for
+variable expansion is $NAME on all operating systems.  Due to the
+order of evaluation, variables are expanded even inside quoted
+strings. If the variable NAME is not set, $NAME expands to the
+empty string.
+
+A directive of the form,
+
+	//go:generate -command xxx args...
+
+specifies, for the remainder of this source file only, that the
+string xxx represents the command identified by the arguments. This
+can be used to create aliases or to handle multiword generators.
+For example,
+
+	//go:generate -command yacc go tool yacc
+
+specifies that the command "yacc" represents the generator
+"go tool yacc".
+
+Generate processes packages in the order given on the command line,
+one at a time. If the command line lists .go files, they are treated
+as a single package. Within a package, generate processes the
+source files in a package in file name order, one at a time. Within
+a source file, generate runs generators in the order they appear
+in the file, one at a time.
+
+If any generator returns an error exit status, "go generate" skips
+all further processing for that package.
+
+The generator is run in the package's source directory.
+
+Go generate accepts one specific flag:
+
+	-run=""
+		TODO: This flag is unimplemented.
+		if non-empty, specifies a regular expression to
+		select directives whose command matches the expression.
+
+It also accepts the standard build flags -v, -n, and -x.
+The -v flag prints the names of packages and files as they are
+processed.
+The -n flag prints commands that would be executed.
+The -x flag prints commands as they are executed.
+
+For more about specifying packages, see 'go help packages'.
+
+
+Download and install packages and dependencies
+
+Usage:
+
+	go get [-d] [-f] [-fix] [-t] [-u] [build flags] [packages]
+
+Get downloads and installs the packages named by the import paths,
+along with their dependencies.
+
+The -d flag instructs get to stop after downloading the packages; that is,
+it instructs get not to install the packages.
+
+The -f flag, valid only when -u is set, forces get -u not to verify that
+each package has been checked out from the source control repository
+implied by its import path. This can be useful if the source is a local fork
+of the original.
+
+The -fix flag instructs get to run the fix tool on the downloaded packages
+before resolving dependencies or building the code.
+
+The -t flag instructs get to also download the packages required to build
+the tests for the specified packages.
+
+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 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
+rule is that if the local installation is running version "go1", get
+searches for a branch or tag named "go1". If no such version exists it
+retrieves the most recent version of the package.
+
+For more about specifying packages, see 'go help packages'.
+
+For more about how 'go get' finds source code to
+download, see 'go help importpath'.
+
+See also: go build, go install, go clean.
+
+
+Compile and install packages and dependencies
+
+Usage:
+
+	go install [build flags] [packages]
+
+Install compiles and installs the packages named by the import paths,
+along with their dependencies.
+
+For more about the build flags, see 'go help build'.
+For more about specifying packages, see 'go help packages'.
+
+See also: go build, go get, go clean.
+
+
+List packages
+
+Usage:
+
+	go list [-e] [-f format] [-json] [build flags] [packages]
+
+List lists the packages named by the import paths, one per line.
+
+The default output shows the package import path:
+
+    code.google.com/p/google-api-go-client/books/v1
+    code.google.com/p/goauth2/oauth
+    code.google.com/p/sqlite
+
+The -f flag specifies an alternate format for the list, using the
+syntax of package template.  The default output is equivalent to -f
+'{{.ImportPath}}'. The struct being passed to the template is:
+
+    type Package struct {
+        Dir           string // directory containing package sources
+        ImportPath    string // import path of package in dir
+        ImportComment string // path in import comment on package statement
+        Name          string // package name
+        Doc           string // package documentation string
+        Target        string // install path
+        Goroot        bool   // is this package in the Go root?
+        Standard      bool   // is this package part of the standard Go library?
+        Stale         bool   // would 'go install' do anything for this package?
+        Root          string // Go root or Go path dir containing this package
+
+        // Source files
+        GoFiles        []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
+        CgoFiles       []string // .go sources files that import "C"
+        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
+        SwigCXXFiles   []string // .swigcxx files
+        SysoFiles      []string // .syso object files to add to archive
+
+        // Cgo directives
+        CgoCFLAGS    []string // cgo: flags for C compiler
+        CgoCPPFLAGS  []string // cgo: flags for C preprocessor
+        CgoCXXFLAGS  []string // cgo: flags for C++ compiler
+        CgoLDFLAGS   []string // cgo: flags for linker
+        CgoPkgConfig []string // cgo: pkg-config names
+
+        // Dependency information
+        Imports []string // import paths used by this package
+        Deps    []string // all (recursively) imported dependencies
+
+        // Error information
+        Incomplete bool            // this package or a dependency has an error
+        Error      *PackageError   // error loading package
+        DepsErrors []*PackageError // errors loading dependencies
+
+        TestGoFiles  []string // _test.go files in package
+        TestImports  []string // imports from TestGoFiles
+        XTestGoFiles []string // _test.go files outside package
+        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.
+
+The -e flag changes the handling of erroneous packages, those that
+cannot be found or are malformed.  By default, the list command
+prints an error to standard error for each erroneous package and
+omits the packages from consideration during the usual printing.
+With the -e flag, the list command never prints errors to standard
+error and instead processes the erroneous packages with the usual
+printing.  Erroneous packages will have a non-empty ImportPath and
+a non-nil Error field; other information may or may not be missing
+(zeroed).
+
+For more about build flags, see 'go help build'.
+
+For more about specifying packages, see 'go help packages'.
+
+
+Compile and run Go program
+
+Usage:
+
+	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.
+
+
+Test packages
+
+Usage:
+
+	go test [-c] [-i] [build and test flags] [packages] [flags for test binary]
+
+'Go test' automates testing the packages named by the import paths.
+It prints a summary of the test results in the format:
+
+	ok   archive/tar   0.011s
+	FAIL archive/zip   0.022s
+	ok   compress/gzip 0.033s
+	...
+
+followed by detailed output for each failed package.
+
+'Go test' recompiles each package along with any files with names matching
+the file pattern "*_test.go".
+Files whose names begin with "_" (including "_test.go") or "." are ignored.
+These additional files can contain test functions, benchmark functions, and
+example functions.  See 'go help testfunc' for more.
+Each listed package causes the execution of a separate test binary.
+
+Test files that declare a package with the suffix "_test" will be compiled as a
+separate package, and then linked and run with the main test binary.
+
+By default, go test needs no arguments.  It compiles and tests the package
+with source in the current directory, including tests, and runs the tests.
+
+The package is built in a temporary directory so it does not interfere with the
+non-test installation.
+
+In addition to the build flags, the flags handled by 'go test' itself are:
 
-var cmdDoc = &Command{
-	Run:         runDoc,
-	UsageLine:   "doc [-u] [-c] [package|[package.]symbol[.method]]",
-	CustomFlags: true,
-	Short:       "show documentation for package or symbol",
-	Long: `
-Doc prints the documentation comments associated with the item identified by its
-arguments (a package, const, func, type, var, or method) followed by a one-line
-summary of each of the first-level items "under" that item (package-level
-declarations for a package, methods for a type, etc.).
-
-Doc accepts zero, one, or two arguments.
-
-Given no arguments, that is, when run as
-
-	go doc
-
-it prints the package documentation for the package in the current directory.
-If the package is a command (package main), the exported symbols of the package
-are elided from the presentation unless the -cmd flag is provided.
-
-When run with one argument, the argument is treated as a Go-syntax-like
-representation of the item to be documented. What the argument selects depends
-on what is installed in GOROOT and GOPATH, as well as the form of the argument,
-which is schematically one of these:
-
-	go doc <pkg>
-	go doc <sym>[.<method>]
-	go doc [<pkg>].<sym>[.<method>]
-
-The first item in this list matched by the argument is the one whose
-documentation is printed. (See the examples below.) For packages, the order of
-scanning is determined lexically, but the GOROOT tree is always scanned before
-GOPATH.
-
-If there is no package specified or matched, the package in the current
-directory is selected, so "go doc Foo" shows the documentation for symbol Foo in
-the current package.
-
-The package path must be either a qualified path or a proper suffix of a
-path. The go tool's usual package mechanism does not apply: package path
-elements like . and ... are not implemented by go doc.
-
-When run with two arguments, the first must be a full package path (not just a
-suffix), and the second is a symbol or symbol and method; this is similar to the
-syntax accepted by godoc:
-
-	go doc <pkg> <sym>[.<method>]
-
-In all forms, when matching symbols, lower-case letters in the argument match
-either case but upper-case letters match exactly. This means that there may be
-multiple matches of a lower-case argument in a package if different symbols have
-different cases. If this occurs, documentation for all matches is printed.
-
-Examples:
-	go doc
-		Show documentation for current package.
-	go doc Foo
-		Show documentation for Foo in the current package.
-		(Foo starts with a capital letter so it cannot match
-		a package path.)
-	go doc encoding/json
-		Show documentation for the encoding/json package.
-	go doc json
-		Shorthand for encoding/json.
-	go doc json.Number (or go doc json.number)
-		Show documentation and method summary for json.Number.
-	go doc json.Number.Int64 (or go doc json.number.int64)
-		Show documentation for json.Number's Int64 method.
-	go doc cmd/doc
-		Show package docs for the doc command.
-	go doc -cmd cmd/doc
-		Show package docs and exported symbols within the doc command.
-	go doc template.new
-		Show documentation for html/template's New function.
-		(html/template is lexically before text/template)
-	go doc text/template.new # One argument
-		Show documentation for text/template's New function.
-	go doc text/template new # Two arguments
-		Show documentation for text/template's New function.
-
-Flags:
 	-c
-		Respect case when matching symbols.
-	-cmd
-		Treat a command (package main) like a regular package.
-		Otherwise package main's exported symbols are hidden
-		when showing the package's top-level documentation.
-	-u
-		Show documentation for unexported as well as exported
-		symbols and methods.
-`,
-}
-
-func runDoc(cmd *Command, args []string) {
-	run(buildToolExec, tool("doc"), args)
-}
+		Compile the test binary to pkg.test but do not run it
+		(where pkg is the last element of the package's import path).
+		The file name can be changed with the -o flag.
+
+	-exec xprog
+	    Run the test binary using xprog. The behavior is the same as
+	    in 'go run'. See 'go help run' for details.
+
+	-i
+	    Install packages that are dependencies of the test.
+	    Do not run the test.
+
+	-o file
+		Compile the test binary to the named file.
+		The test still runs (unless -c or -i is specified).
+
+
+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.
+
+If the test binary needs any other flags, they should be presented after the
+package names. The go tool treats as a flag the first argument that begins with
+a minus sign that it does not recognize itself; that argument and all subsequent
+arguments are passed as arguments to the test binary.
+
+For more about build flags, see 'go help build'.
+For more about specifying packages, see 'go help packages'.
+
+See also: go build, go vet.
+
+
+Run specified go tool
+
+Usage:
+
+	go tool [-n] command [args...]
+
+Tool runs the go tool command identified by the arguments.
+With no arguments it prints the list of known tools.
+
+The -n flag causes tool to print the command that would be
+executed but not execute it.
+
+For more about each tool command, see 'go tool command -h'.
+
+
+Print Go version
+
+Usage:
+
+	go version
+
+Version prints the Go version, as reported by runtime.Version.
+
+
+Run go tool vet on packages
+
+Usage:
+
+	go vet [-n] [-x] [packages]
+
+Vet runs the Go vet command on the packages named by the import paths.
+
+For more about vet, see 'godoc golang.org/x/tools/cmd/vet'.
+For more about specifying packages, see 'go help packages'.
+
+To run the vet tool with specific options, run 'go tool vet'.
+
+The -n flag prints commands that would be executed.
+The -x flag prints commands as they are executed.
+
+See also: go fmt, go fix.
+
+
+Calling between Go and C
+
+There are two different ways to call between Go and C/C++ code.
+
+The first is the cgo tool, which is part of the Go distribution.  For
+information on how to use it see the cgo documentation (godoc cmd/cgo).
+
+The second is the SWIG program, which is a general tool for
+interfacing between languages.  For information on SWIG see
+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, .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.
+It is implemented by and documented in the go/build package.
+
+The GOPATH environment variable lists places to look for Go code.
+On Unix, the value is a colon-separated string.
+On Windows, the value is a semicolon-separated string.
+On Plan 9, the value is a list.
+
+GOPATH must be set to get, build and install packages outside the
+standard Go tree.
+
+Each directory listed in GOPATH must have a prescribed structure:
+
+The src/ directory holds source code.  The path below 'src'
+determines the import path or executable name.
+
+The pkg/ directory holds installed package objects.
+As in the Go tree, each target operating system and
+architecture pair has its own subdirectory of pkg
+(pkg/GOOS_GOARCH).
+
+If DIR is a directory listed in the GOPATH, a package with
+source in DIR/src/foo/bar can be imported as "foo/bar" and
+has its compiled form installed to "DIR/pkg/GOOS_GOARCH/foo/bar.a".
+
+The bin/ directory holds compiled commands.
+Each command is named for its source directory, but only
+the final element, not the entire path.  That is, the
+command with source in DIR/src/foo/quux is installed into
+DIR/bin/quux, not DIR/bin/foo/quux.  The foo/ is stripped
+so that you can add DIR/bin to your PATH to get at the
+installed commands.  If the GOBIN environment variable is
+set, commands are installed to the directory it names instead
+of DIR/bin.
+
+Here's an example directory layout:
+
+    GOPATH=/home/user/gocode
+
+    /home/user/gocode/
+        src/
+            foo/
+                bar/               (go code in package bar)
+                    x.go
+                quux/              (go code in package main)
+                    y.go
+        bin/
+            quux                   (installed command)
+        pkg/
+            linux_amd64/
+                foo/
+                    bar.a          (installed package object)
+
+Go searches each directory listed in GOPATH to find source code,
+but new packages are always downloaded into the first directory
+in the list.
+
+
+Import path syntax
+
+An import path (see 'go help packages') denotes a package
+stored in the local file system.  In general, an import path denotes
+either a standard package (such as "unicode/utf8") or a package
+found in one of the work spaces (see 'go help gopath').
+
+Relative import paths
+
+An import path beginning with ./ or ../ is called a relative path.
+The toolchain supports relative import paths as a shortcut in two ways.
+
+First, a relative path can be used as a shorthand on the command line.
+If you are working in the directory containing the code imported as
+"unicode" and want to run the tests for "unicode/utf8", you can type
+"go test ./utf8" instead of needing to specify the full path.
+Similarly, in the reverse situation, "go test .." will test "unicode" from
+the "unicode/utf8" directory. Relative patterns are also allowed, like
+"go test ./..." to test all subdirectories. See 'go help packages' for details
+on the pattern syntax.
+
+Second, if you are compiling a Go program not in a work space,
+you can use a relative path in an import statement in that program
+to refer to nearby code also not in a work space.
+This makes it easy to experiment with small multipackage programs
+outside of the usual work spaces, but such programs cannot be
+installed with "go install" (there is no work space in which to install them),
+so they are rebuilt from scratch each time they are built.
+To avoid ambiguity, Go programs cannot use relative import paths
+within a work space.
+
+Remote import paths
+
+Certain import paths also
+describe how to obtain the source code for the package using
+a revision control system.
+
+A few common code hosting sites have special syntax:
+
+	Bitbucket (Git, Mercurial)
+
+		import "bitbucket.org/user/project"
+		import "bitbucket.org/user/project/sub/directory"
+
+	GitHub (Git)
+
+		import "github.com/user/project"
+		import "github.com/user/project/sub/directory"
+
+	Google Code Project Hosting (Git, Mercurial, Subversion)
+
+		import "code.google.com/p/project"
+		import "code.google.com/p/project/sub/directory"
+
+		import "code.google.com/p/project.subrepository"
+		import "code.google.com/p/project.subrepository/sub/directory"
+
+	Launchpad (Bazaar)
+
+		import "launchpad.net/project"
+		import "launchpad.net/project/series"
+		import "launchpad.net/project/series/sub/directory"
+
+		import "launchpad.net/~user/project/branch"
+		import "launchpad.net/~user/project/branch/sub/directory"
+
+	IBM DevOps Services (Git)
+
+		import "hub.jazz.net/git/user/project"
+		import "hub.jazz.net/git/user/project/sub/directory"
+
+For code hosted on other servers, import paths may either be qualified
+with the version control type, or the go tool can dynamically fetch
+the import path over https/http and discover where the code resides
+from a <meta> tag in the HTML.
+
+To declare the code location, an import path of the form
+
+	repository.vcs/path
+
+specifies the given repository, with or without the .vcs suffix,
+using the named version control system, and then the path inside
+that repository.  The supported version control systems are:
+
+	Bazaar      .bzr
+	Git         .git
+	Mercurial   .hg
+	Subversion  .svn
+
+For example,
+
+	import "example.org/user/foo.hg"
+
+denotes the root directory of the Mercurial repository at
+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.org/repo or repo.git.
+
+When a version control system supports multiple protocols,
+each is tried in turn when downloading.  For example, a Git
+download tries git://, then https://, then http://.
+
+If the import path is not a known code hosting site and also lacks a
+version control qualifier, the go tool attempts to fetch the import
+over https/http and looks for a <meta> tag in the document's HTML
+<head>.
+
+The meta tag has the form:
+
+	<meta name="go-import" content="import-prefix vcs repo-root">
+
+The import-prefix is the import path corresponding to the repository
+root. It must be a prefix or an exact match of the package being
+fetched with "go get". If it's not an exact match, another http
+request is made at the prefix to verify the <meta> tags match.
+
+The vcs is one of "git", "hg", "svn", etc,
+
+The repo-root is the root of the version control system
+containing a scheme and not containing a .vcs qualifier.
+
+For example,
+
+	import "example.org/pkg/foo"
+
+will result in the following request(s):
+
+	https://example.org/pkg/foo?go-get=1 (preferred)
+	http://example.org/pkg/foo?go-get=1  (fallback)
+
+If that page contains the meta tag
+
+	<meta name="go-import" content="example.org git https://code.org/r/p/exproj">
+
+the go tool will verify that https://example.org/?go-get=1 contains the
+same meta tag and then git clone https://code.org/r/p/exproj into
+GOPATH/src/example.org.
+
+New downloaded packages are written to the first directory
+listed in the GOPATH environment variable (see 'go help gopath').
+
+The go command attempts to download the version of the
+package appropriate for the Go release being used.
+Run 'go help get' for more.
+
+Import path checking
+
+When the custom import path feature described above redirects to a
+known code hosting site, each of the resulting packages has two possible
+import paths, using the custom domain or the known hosting site.
+
+A package statement is said to have an "import comment" if it is immediately
+followed (before the next newline) by a comment of one of these two forms:
+
+	package math // import "path"
+	package math /* import "path" * /
+
+The go command will refuse to install a package with an import comment
+unless it is being referred to by that import path. In this way, import comments
+let package authors make sure the custom import path is used and not a
+direct path to the underlying code hosting site.
+
+See https://golang.org/s/go14customimport for details.
+
+
+Description of package lists
+
+Many commands apply to a set of packages:
+
+	go action [packages]
+
+Usually, [packages] is a list of import paths.
+
+An import path that is a rooted path or that begins with
+a . or .. element is interpreted as a file system path and
+denotes the package in that directory.
+
+Otherwise, the import path P denotes the package found in
+the directory DIR/src/P for some DIR listed in the GOPATH
+environment variable (see 'go help gopath').
+
+If no import paths are given, the action applies to the
+package in the current directory.
+
+There are three reserved names for paths that should not be used
+for packages to be built with the go tool:
+
+- "main" denotes the top-level package in a stand-alone executable.
+
+- "all" expands to all package directories found in all the GOPATH
+trees. For example, 'go list all' lists all the packages on the local
+system.
+
+- "std" is like all but expands to just the packages in the standard
+Go library.
+
+An import path is a pattern if it includes one or more "..." wildcards,
+each of which can match any string, including the empty string and
+strings containing slashes.  Such a pattern expands to all package
+directories found in the GOPATH trees with names matching the
+patterns.  As a special case, x/... matches x as well as x's subdirectories.
+For example, net/... expands to net and packages in its subdirectories.
+
+An import path can also name a package to be downloaded from
+a remote repository.  Run 'go help importpath' for details.
+
+Every package in a program must have a unique import path.
+By convention, this is arranged by starting each path with a
+unique prefix that belongs to you.  For example, paths used
+internally at Google all begin with 'google', and paths
+denoting remote repositories begin with the path to the code,
+such as 'code.google.com/p/project'.
+
+As a special case, if the package list is a list of .go files from a
+single directory, the command is applied to a single synthesized
+package made up of exactly those files, ignoring any build constraints
+in those files and ignoring any other files in the directory.
+
+Directory and file names that begin with "." or "_" are ignored
+by the go tool, as are directories named "testdata".
+
+
+Description of testing flags
+
+The 'go test' command takes both flags that apply to 'go test' itself
+and flags that apply to the resulting test binary.
+
+Several of the flags control profiling and write an execution profile
+suitable for "go tool pprof"; run "go tool pprof help" for more
+information.  The --alloc_space, --alloc_objects, and --show_bytes
+options of pprof control how the information is presented.
+
+The following flags are recognized by the 'go test' command and
+control the execution of any test:
+
+	-bench regexp
+	    Run benchmarks matching the regular expression.
+	    By default, no benchmarks run. To run all benchmarks,
+	    use '-bench .' or '-bench=.'.
+
+	-benchmem
+	    Print memory allocation statistics for benchmarks.
+
+	-benchtime t
+	    Run enough iterations of each benchmark to take t, specified
+	    as a time.Duration (for example, -benchtime 1h30s).
+	    The default is 1 second (1s).
+
+	-blockprofile block.out
+	    Write a goroutine blocking profile to the specified file
+	    when all tests are complete.
+	    Writes test binary as -c would.
+
+	-blockprofilerate n
+	    Control the detail provided in goroutine blocking profiles by
+	    calling runtime.SetBlockProfileRate with n.
+	    See 'godoc runtime SetBlockProfileRate'.
+	    The profiler aims to sample, on average, one blocking event every
+	    n nanoseconds the program spends blocked.  By default,
+	    if -test.blockprofile is set without this flag, all blocking events
+	    are recorded, equivalent to -test.blockprofilerate=1.
+
+	-cover
+	    Enable coverage analysis.
+
+	-covermode set,count,atomic
+	    Set the mode for coverage analysis for the package[s]
+	    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?
+		atomic: int: count, but correct in multithreaded tests;
+			significantly more expensive.
+	    Sets -cover.
+
+	-coverpkg pkg1,pkg2,pkg3
+	    Apply coverage analysis in each test to the given list of packages.
+	    The default is for each test to analyze only the package being tested.
+	    Packages are specified as import paths.
+	    Sets -cover.
+
+	-coverprofile cover.out
+	    Write a coverage profile to the file after all tests have passed.
+	    Sets -cover.
+
+	-cpu 1,2,4
+	    Specify a list of GOMAXPROCS values for which the tests or
+	    benchmarks should be executed.  The default is the current value
+	    of GOMAXPROCS.
+
+	-cpuprofile cpu.out
+	    Write a CPU profile to the specified file before exiting.
+	    Writes test binary as -c would.
+
+	-memprofile mem.out
+	    Write a memory profile to the file after all tests have passed.
+	    Writes test binary as -c would.
+
+	-memprofilerate n
+	    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 pass --alloc_space flag to the pprof tool.
+
+	-outputdir directory
+	    Place output files from profiling in the specified directory,
+	    by default the directory in which "go test" is running.
+
+	-parallel n
+	    Allow parallel execution of test functions that call t.Parallel.
+	    The value of this flag is the maximum number of tests to run
+	    simultaneously; by default, it is set to the value of GOMAXPROCS.
+
+	-run regexp
+	    Run only those tests and examples matching the regular
+	    expression.
+
+	-short
+	    Tell long-running tests to shorten their run time.
+	    It is off by default but set during all.bash so that installing
+	    the Go tree can run a sanity check but not spend time running
+	    exhaustive tests.
+
+	-timeout t
+	    If a test runs longer than t, panic.
+
+	-v
+	    Verbose output: log all tests as they are run. Also print all
+	    text from Log and Logf calls even if the test succeeds.
+
+The test binary, called pkg.test where pkg is the name of the
+directory containing the package sources, can be invoked directly
+after building it with 'go test -c'. When invoking the test binary
+directly, each of the standard flag names must be prefixed with 'test.',
+as in -test.run=TestMyFunc or -test.v.
+
+When running 'go test', flags not listed above are passed through
+unaltered. For instance, the command
+
+	go test -x -v -cpuprofile=prof.out -dir=testdata -update
+
+will compile the test binary and then run it as
+
+	pkg.test -test.v -test.cpuprofile=prof.out -dir=testdata -update
+
+The test flags that generate profiles (other than for coverage) also
+leave the test binary in pkg.test for use when analyzing the profiles.
+
+Flags not recognized by 'go test' must be placed after any specified packages.
+
+
+Description of testing functions
+
+The 'go test' command expects to find test, benchmark, and example functions
+in the "*_test.go" files corresponding to the package under test.
+
+A test function is one named TestXXX (where XXX is any alphanumeric string
+not starting with a lower case letter) and should have the signature,
+
+	func TestXXX(t *testing.T) { ... }
+
+A benchmark function is one named BenchmarkXXX and should have the signature,
+
+	func BenchmarkXXX(b *testing.B) { ... }
+
+An example function is similar to a test function but, instead of using
+*testing.T to report success or failure, prints output to os.Stdout.
+That output is compared against the function's "Output:" comment, which
+must be the last comment in the function body (see example below). An
+example with no such comment, or with no text after "Output:" is compiled
+but not executed.
+
+Godoc displays the body of ExampleXXX to demonstrate the use
+of the function, constant, or variable XXX.  An example of a method M with
+receiver type T or *T is named ExampleT_M.  There may be multiple examples
+for a given function, constant, or variable, distinguished by a trailing _xxx,
+where xxx is a suffix not beginning with an upper case letter.
+
+Here is an example of an example:
+
+	func ExamplePrintln() {
+		Println("The output of\nthis example.")
+		// Output: The output of
+		// this example.
+	}
+
+The entire test file is presented as the example when it contains a single
+example function, at least one other function, type, variable, or constant
+declaration, and no test or benchmark functions.
+
+See the documentation of the testing package for more information.
+
+
+*/
+package main
diff --git a/src/cmd/go/env.go b/src/cmd/go/env.go
index 600acca..26d37df 100644
--- a/src/cmd/go/env.go
+++ b/src/cmd/go/env.go
@@ -36,6 +36,7 @@ func mkEnv() []envVar {
 	env := []envVar{
 		{"GOARCH", goarch},
 		{"GOBIN", gobin},
+		{"GOCHAR", archChar},
 		{"GOEXE", exeSuffix},
 		{"GOHOSTARCH", runtime.GOARCH},
 		{"GOHOSTOS", runtime.GOOS},
@@ -44,7 +45,6 @@ func mkEnv() []envVar {
 		{"GORACE", os.Getenv("GORACE")},
 		{"GOROOT", goroot},
 		{"GOTOOLDIR", toolDir},
-		{"GO15VENDOREXPERIMENT", os.Getenv("GO15VENDOREXPERIMENT")},
 
 		// disable escape codes in clang errors
 		{"TERM", "dumb"},
diff --git a/src/cmd/go/fix.go b/src/cmd/go/fix.go
index 94fd22e..8736cce 100644
--- a/src/cmd/go/fix.go
+++ b/src/cmd/go/fix.go
@@ -11,7 +11,7 @@ var cmdFix = &Command{
 	Long: `
 Fix runs the Go fix command on the packages named by the import paths.
 
-For more about fix, see 'go doc cmd/fix'.
+For more about fix, see 'godoc fix'.
 For more about specifying packages, see 'go help packages'.
 
 To run fix with specific options, run 'go tool fix'.
@@ -25,6 +25,6 @@ func runFix(cmd *Command, args []string) {
 		// Use pkg.gofiles instead of pkg.Dir so that
 		// the command only applies to this package,
 		// not to packages in subdirectories.
-		run(stringList(buildToolExec, tool("fix"), relPaths(pkg.allgofiles)))
+		run(stringList(tool("fix"), relPaths(pkg.allgofiles)))
 	}
 }
diff --git a/src/cmd/go/fmt.go b/src/cmd/go/fmt.go
index 57c02ad..65dc3ca 100644
--- a/src/cmd/go/fmt.go
+++ b/src/cmd/go/fmt.go
@@ -4,11 +4,6 @@
 
 package main
 
-import (
-	"os"
-	"path/filepath"
-)
-
 func init() {
 	addBuildFlagsNX(cmdFmt)
 }
@@ -21,7 +16,7 @@ var cmdFmt = &Command{
 Fmt runs the command 'gofmt -l -w' on the packages named
 by the import paths.  It prints the names of the files that are modified.
 
-For more about gofmt, see 'go doc cmd/gofmt'.
+For more about gofmt, see 'godoc gofmt'.
 For more about specifying packages, see 'go help packages'.
 
 The -n flag prints commands that would be executed.
@@ -34,31 +29,10 @@ See also: go fix, go vet.
 }
 
 func runFmt(cmd *Command, args []string) {
-	gofmt := gofmtPath()
 	for _, pkg := range packages(args) {
 		// Use pkg.gofiles instead of pkg.Dir so that
 		// the command only applies to this package,
 		// not to packages in subdirectories.
-		run(stringList(gofmt, "-l", "-w", relPaths(pkg.allgofiles)))
+		run(stringList("gofmt", "-l", "-w", relPaths(pkg.allgofiles)))
 	}
 }
-
-func gofmtPath() string {
-	gofmt := "gofmt"
-	if toolIsWindows {
-		gofmt += toolWindowsExtension
-	}
-
-	gofmtPath := filepath.Join(gobin, gofmt)
-	if _, err := os.Stat(gofmtPath); err == nil {
-		return gofmtPath
-	}
-
-	gofmtPath = filepath.Join(goroot, "bin", gofmt)
-	if _, err := os.Stat(gofmtPath); err == nil {
-		return gofmtPath
-	}
-
-	// fallback to looking for gofmt in $PATH
-	return "gofmt"
-}
diff --git a/src/cmd/go/generate.go b/src/cmd/go/generate.go
index efdc229..3c0af87 100644
--- a/src/cmd/go/generate.go
+++ b/src/cmd/go/generate.go
@@ -13,11 +13,11 @@ import (
 	"os"
 	"os/exec"
 	"path/filepath"
-	"regexp"
 	"runtime"
 	"strconv"
 	"strings"
 	"unicode"
+	"unicode/utf8"
 )
 
 var cmdGenerate = &Command{
@@ -62,12 +62,8 @@ Go generate sets several variables when it runs the generator:
 		The execution operating system (linux, windows, etc.)
 	$GOFILE
 		The base name of the file.
-	$GOLINE
-		The line number of the directive in the source file.
 	$GOPACKAGE
 		The name of the package of the file containing the directive.
-	$DOLLAR
-		A dollar sign.
 
 Other than variable substitution and quoted-string evaluation, no
 special processing such as "globbing" is performed on the command
@@ -110,10 +106,9 @@ The generator is run in the package's source directory.
 Go generate accepts one specific flag:
 
 	-run=""
-		if non-empty, specifies a regular expression to select
-		directives whose full original source text (excluding
-		any trailing spaces and final newline) matches the
-		expression.
+		TODO: This flag is unimplemented.
+		if non-empty, specifies a regular expression to
+		select directives whose command matches the expression.
 
 It also accepts the standard build flags -v, -n, and -x.
 The -v flag prints the names of packages and files as they are
@@ -125,10 +120,7 @@ For more about specifying packages, see 'go help packages'.
 	`,
 }
 
-var (
-	generateRunFlag string         // generate -run flag
-	generateRunRE   *regexp.Regexp // compiled expression for -run
-)
+var generateRunFlag string // generate -run flag
 
 func init() {
 	addBuildFlags(cmdGenerate)
@@ -136,13 +128,6 @@ func init() {
 }
 
 func runGenerate(cmd *Command, args []string) {
-	if generateRunFlag != "" {
-		var err error
-		generateRunRE, err = regexp.Compile(generateRunFlag)
-		if err != nil {
-			log.Fatalf("generate: %s", err)
-		}
-	}
 	// Even if the arguments are .go files, this loop suffices.
 	for _, pkg := range packages(args) {
 		for _, file := range pkg.gofiles {
@@ -178,7 +163,7 @@ type Generator struct {
 	file     string // base name of file.
 	pkg      string
 	commands map[string][]string
-	lineNum  int // current line number.
+	lineNum  int
 }
 
 // run runs the generators in the current file.
@@ -236,11 +221,6 @@ func (g *Generator) run() (ok bool) {
 		if !isGoGenerate(buf) {
 			continue
 		}
-		if generateRunFlag != "" {
-			if !generateRunRE.Match(bytes.TrimSpace(buf)) {
-				continue
-			}
-		}
 
 		words := g.split(string(buf))
 		if len(words) == 0 {
@@ -326,7 +306,7 @@ Words:
 	}
 	// Substitute environment variables.
 	for i, word := range words {
-		words[i] = os.Expand(word, g.expandVar)
+		words[i] = g.expandEnv(word)
 	}
 	return words
 }
@@ -342,25 +322,38 @@ func (g *Generator) errorf(format string, args ...interface{}) {
 	panic(stop)
 }
 
-// expandVar expands the $XXX invocation in word. It is called
-// by os.Expand.
-func (g *Generator) expandVar(word string) string {
-	switch word {
-	case "GOARCH":
-		return buildContext.GOARCH
-	case "GOOS":
-		return buildContext.GOOS
-	case "GOFILE":
-		return g.file
-	case "GOLINE":
-		return fmt.Sprint(g.lineNum)
-	case "GOPACKAGE":
-		return g.pkg
-	case "DOLLAR":
-		return "$"
-	default:
-		return os.Getenv(word)
+// expandEnv expands any $XXX invocations in word.
+func (g *Generator) expandEnv(word string) string {
+	if !strings.ContainsRune(word, '$') {
+		return word
+	}
+	var buf bytes.Buffer
+	var w int
+	var r rune
+	for i := 0; i < len(word); i += w {
+		r, w = utf8.DecodeRuneInString(word[i:])
+		if r != '$' {
+			buf.WriteRune(r)
+			continue
+		}
+		w += g.identLength(word[i+w:])
+		envVar := word[i+1 : i+w]
+		var sub string
+		switch envVar {
+		case "GOARCH":
+			sub = runtime.GOARCH
+		case "GOOS":
+			sub = runtime.GOOS
+		case "GOFILE":
+			sub = g.file
+		case "GOPACKAGE":
+			sub = g.pkg
+		default:
+			sub = os.Getenv(envVar)
+		}
+		buf.WriteString(sub)
 	}
+	return buf.String()
 }
 
 // identLength returns the length of the identifier beginning the string.
@@ -402,7 +395,7 @@ func (g *Generator) exec(words []string) {
 		"GOFILE=" + g.file,
 		"GOPACKAGE=" + g.pkg,
 	}
-	cmd.Env = mergeEnvLists(env, origEnv)
+	cmd.Env = mergeEnvLists(env, os.Environ())
 	err := cmd.Run()
 	if err != nil {
 		g.errorf("running %q: %s", words[0], err)
diff --git a/src/cmd/go/generate_test.go b/src/cmd/go/generate_test.go
index 169d71c..2ec5486 100644
--- a/src/cmd/go/generate_test.go
+++ b/src/cmd/go/generate_test.go
@@ -26,7 +26,6 @@ var splitTests = []splitTest{
 	{"$GOPACKAGE", []string{"sys"}},
 	{"a $XXNOTDEFINEDXX b", []string{"a", "", "b"}},
 	{"/$XXNOTDEFINED/", []string{"//"}},
-	{"/$DOLLAR/", []string{"/$/"}},
 	{"yacc -o $GOARCH/yacc_$GOFILE", []string{"go", "tool", "yacc", "-o", runtime.GOARCH + "/yacc_proc.go"}},
 }
 
diff --git a/src/cmd/go/get.go b/src/cmd/go/get.go
index e95201a..50e0ca9 100644
--- a/src/cmd/go/get.go
+++ b/src/cmd/go/get.go
@@ -16,7 +16,7 @@ import (
 )
 
 var cmdGet = &Command{
-	UsageLine: "get [-d] [-f] [-fix] [-insecure] [-t] [-u] [build flags] [packages]",
+	UsageLine: "get [-d] [-f] [-fix] [-t] [-u] [build flags] [packages]",
 	Short:     "download and install packages and dependencies",
 	Long: `
 Get downloads and installs the packages named by the import paths,
@@ -33,9 +33,6 @@ of the original.
 The -fix flag instructs get to run the fix tool on the downloaded packages
 before resolving dependencies or building the code.
 
-The -insecure flag permits fetching from repositories and resolving
-custom domains using insecure schemes such as HTTP. Use with caution.
-
 The -t flag instructs get to also download the packages required to build
 the tests for the specified packages.
 
@@ -51,10 +48,6 @@ rule is that if the local installation is running version "go1", get
 searches for a branch or tag named "go1". If no such version exists it
 retrieves the most recent version of the package.
 
-If the vendoring experiment is enabled (see 'go help gopath'),
-then when go get checks out or updates a Git repository,
-it also updates any git submodules referenced by the repository.
-
 For more about specifying packages, see 'go help packages'.
 
 For more about how 'go get' finds source code to
@@ -69,7 +62,6 @@ var getF = cmdGet.Flag.Bool("f", false, "")
 var getT = cmdGet.Flag.Bool("t", false, "")
 var getU = cmdGet.Flag.Bool("u", false, "")
 var getFix = cmdGet.Flag.Bool("fix", false, "")
-var getInsecure = cmdGet.Flag.Bool("insecure", false, "")
 
 func init() {
 	addBuildFlags(cmdGet)
@@ -81,20 +73,10 @@ func runGet(cmd *Command, args []string) {
 		fatalf("go get: cannot use -f flag without -u")
 	}
 
-	// Disable any prompting for passwords by Git.
-	// Only has an effect for 2.3.0 or later, but avoiding
-	// the prompt in earlier versions is just too hard.
-	// See golang.org/issue/9341.
-	os.Setenv("GIT_TERMINAL_PROMPT", "0")
-
 	// Phase 1.  Download/update.
 	var stk importStack
-	mode := 0
-	if *getT {
-		mode |= getTestDeps
-	}
 	for _, arg := range downloadPaths(args) {
-		download(arg, nil, &stk, mode)
+		download(arg, &stk, *getT)
 	}
 	exitIfErrors()
 
@@ -110,13 +92,12 @@ func runGet(cmd *Command, args []string) {
 	}
 
 	args = importPaths(args)
-	packagesForBuild(args)
 
 	// Phase 3.  Install.
 	if *getD {
 		// Download only.
 		// Check delayed until now so that importPaths
-		// and packagesForBuild have a chance to print errors.
+		// has a chance to print errors.
 		return
 	}
 
@@ -167,30 +148,13 @@ var downloadRootCache = map[string]bool{}
 
 // download runs the download half of the get command
 // for the package named by the argument.
-func download(arg string, parent *Package, stk *importStack, mode int) {
-	load := func(path string, mode int) *Package {
-		if parent == nil {
-			return loadPackage(path, stk)
-		}
-		return loadImport(path, parent.Dir, parent, stk, nil, mode)
-	}
-
-	p := load(arg, mode)
+func download(arg string, stk *importStack, getTestDeps bool) {
+	p := loadPackage(arg, stk)
 	if p.Error != nil && p.Error.hard {
 		errorf("%s", p.Error)
 		return
 	}
 
-	// loadPackage inferred the canonical ImportPath from arg.
-	// Use that in the following to prevent hysteresis effects
-	// in e.g. downloadCache and packageCache.
-	// This allows invocations such as:
-	//   mkdir -p $GOPATH/src/github.com/user
-	//   cd $GOPATH/src/github.com/user
-	//   go get ./foo
-	// see: golang.org/issue/9767
-	arg = p.ImportPath
-
 	// There's nothing to do if this is a package in the standard library.
 	if p.Standard {
 		return
@@ -199,7 +163,7 @@ func download(arg string, parent *Package, stk *importStack, mode int) {
 	// Only process each package once.
 	// (Unless we're fetching test dependencies for this package,
 	// in which case we want to process it again.)
-	if downloadCache[arg] && mode&getTestDeps == 0 {
+	if downloadCache[arg] && !getTestDeps {
 		return
 	}
 	downloadCache[arg] = true
@@ -211,7 +175,7 @@ func download(arg string, parent *Package, stk *importStack, mode int) {
 	// Download if the package is missing, or update if we're using -u.
 	if p.Dir == "" || *getU {
 		// The actual download.
-		stk.push(arg)
+		stk.push(p.ImportPath)
 		err := downloadPackage(p)
 		if err != nil {
 			errorf("%s", &PackageError{ImportStack: stk.copy(), Err: err.Error()})
@@ -219,17 +183,6 @@ func download(arg string, parent *Package, stk *importStack, mode int) {
 			return
 		}
 
-		// Warn that code.google.com is shutting down.  We
-		// issue the warning here because this is where we
-		// have the import stack.
-		if strings.HasPrefix(p.ImportPath, "code.google.com") {
-			fmt.Fprintf(os.Stderr, "warning: code.google.com is shutting down; import path %v will stop working\n", p.ImportPath)
-			if len(*stk) > 1 {
-				fmt.Fprintf(os.Stderr, "warning: package %v\n", strings.Join(*stk, "\n\timports "))
-			}
-		}
-		stk.pop()
-
 		args := []string{arg}
 		// If the argument has a wildcard in it, re-evaluate the wildcard.
 		// We delay this until after reloadPackage so that the old entry
@@ -255,10 +208,9 @@ func download(arg string, parent *Package, stk *importStack, mode int) {
 
 		pkgs = pkgs[:0]
 		for _, arg := range args {
-			// Note: load calls loadPackage or loadImport,
-			// which push arg onto stk already.
-			// Do not push here too, or else stk will say arg imports arg.
-			p := load(arg, mode)
+			stk.push(arg)
+			p := loadPackage(arg, stk)
+			stk.pop()
 			if p.Error != nil {
 				errorf("%s", p.Error)
 				continue
@@ -271,7 +223,7 @@ func download(arg string, parent *Package, stk *importStack, mode int) {
 	// due to wildcard expansion.
 	for _, p := range pkgs {
 		if *getFix {
-			run(buildToolExec, stringList(tool("fix"), relPaths(p.allgofiles)))
+			run(stringList(tool("fix"), relPaths(p.allgofiles)))
 
 			// The imports might have changed, so reload again.
 			p = reloadPackage(arg, stk)
@@ -288,31 +240,18 @@ func download(arg string, parent *Package, stk *importStack, mode int) {
 		}
 
 		// Process dependencies, now that we know what they are.
-		for _, path := range p.Imports {
-			if path == "C" {
-				continue
-			}
+		for _, dep := range p.deps {
 			// Don't get test dependencies recursively.
-			// Imports is already vendor-expanded.
-			download(path, p, stk, 0)
+			download(dep.ImportPath, stk, false)
 		}
-		if mode&getTestDeps != 0 {
+		if getTestDeps {
 			// Process test dependencies when -t is specified.
 			// (Don't get test dependencies for test dependencies.)
-			// We pass useVendor here because p.load does not
-			// vendor-expand TestImports and XTestImports.
-			// The call to loadImport inside download needs to do that.
 			for _, path := range p.TestImports {
-				if path == "C" {
-					continue
-				}
-				download(path, p, stk, useVendor)
+				download(path, stk, false)
 			}
 			for _, path := range p.XTestImports {
-				if path == "C" {
-					continue
-				}
-				download(path, p, stk, useVendor)
+				download(path, stk, false)
 			}
 		}
 
@@ -330,12 +269,6 @@ func downloadPackage(p *Package) error {
 		repo, rootPath string
 		err            error
 	)
-
-	security := secure
-	if *getInsecure {
-		security = insecure
-	}
-
 	if p.build.SrcRoot != "" {
 		// Directory exists.  Look for checkout along path to src.
 		vcs, rootPath, err = vcsForDir(p)
@@ -345,15 +278,10 @@ func downloadPackage(p *Package) error {
 		repo = "<local>" // should be unused; make distinctive
 
 		// Double-check where it came from.
-		if *getU && vcs.remoteRepo != nil {
+		if *getU && vcs.remoteRepo != nil && !*getF {
 			dir := filepath.Join(p.build.SrcRoot, rootPath)
-			remote, err := vcs.remoteRepo(vcs, dir)
-			if err != nil {
-				return err
-			}
-			repo = remote
-			if !*getF {
-				if rr, err := repoRootForImportPath(p.ImportPath, security); err == nil {
+			if remote, err := vcs.remoteRepo(vcs, dir); err == nil {
+				if rr, err := repoRootForImportPath(p.ImportPath); err == nil {
 					repo := rr.repo
 					if rr.vcs.resolveRepo != nil {
 						resolved, err := rr.vcs.resolveRepo(rr.vcs, dir, repo)
@@ -361,7 +289,7 @@ func downloadPackage(p *Package) error {
 							repo = resolved
 						}
 					}
-					if remote != repo && p.ImportComment != "" {
+					if remote != repo {
 						return fmt.Errorf("%s is a custom import path for %s, but %s is checked out from %s", rr.root, repo, dir, remote)
 					}
 				}
@@ -370,15 +298,12 @@ func downloadPackage(p *Package) error {
 	} else {
 		// Analyze the import path to determine the version control system,
 		// repository, and the import path for the root of the repository.
-		rr, err := repoRootForImportPath(p.ImportPath, security)
+		rr, err := repoRootForImportPath(p.ImportPath)
 		if err != nil {
 			return err
 		}
 		vcs, repo, rootPath = rr.vcs, rr.repo, rr.root
 	}
-	if !vcs.isSecure(repo) && !*getInsecure {
-		return fmt.Errorf("cannot download, %v uses insecure protocol", repo)
-	}
 
 	if p.build.SrcRoot == "" {
 		// Package not found.  Put in first directory of $GOPATH.
diff --git a/src/cmd/go/help.go b/src/cmd/go/help.go
index 5dff267..c590fdb 100644
--- a/src/cmd/go/help.go
+++ b/src/cmd/go/help.go
@@ -11,7 +11,7 @@ var helpC = &Command{
 There are two different ways to call between Go and C/C++ code.
 
 The first is the cgo tool, which is part of the Go distribution.  For
-information on how to use it see the cgo documentation (go doc cmd/cgo).
+information on how to use it see the cgo documentation (godoc cmd/cgo).
 
 The second is the SWIG program, which is a general tool for
 interfacing between languages.  For information on SWIG see
@@ -47,7 +47,7 @@ environment variable (see 'go help gopath').
 If no import paths are given, the action applies to the
 package in the current directory.
 
-There are four reserved names for paths that should not be used
+There are three reserved names for paths that should not be used
 for packages to be built with the go tool:
 
 - "main" denotes the top-level package in a stand-alone executable.
@@ -59,9 +59,6 @@ system.
 - "std" is like all but expands to just the packages in the standard
 Go library.
 
-- "cmd" expands to the Go repository's commands and their
-internal libraries.
-
 An import path is a pattern if it includes one or more "..." wildcards,
 each of which can match any string, including the empty string and
 strings containing slashes.  Such a pattern expands to all package
@@ -77,7 +74,7 @@ By convention, this is arranged by starting each path with a
 unique prefix that belongs to you.  For example, paths used
 internally at Google all begin with 'google', and paths
 denoting remote repositories begin with the path to the code,
-such as 'github.com/user/repo'.
+such as 'code.google.com/p/project'.
 
 As a special case, if the package list is a list of .go files from a
 single directory, the command is applied to a single synthesized
@@ -195,7 +192,7 @@ 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
-download tries https://, then git+ssh://.
+download tries git://, then https://, then http://.
 
 If the import path is not a known code hosting site and also lacks a
 version control qualifier, the go tool attempts to fetch the import
@@ -211,10 +208,6 @@ root. It must be a prefix or an exact match of the package being
 fetched with "go get". If it's not an exact match, another http
 request is made at the prefix to verify the <meta> tags match.
 
-The meta tag should appear as early in the file as possible.
-In particular, it should appear before any raw JavaScript or CSS,
-to avoid confusing the go command's restricted parser.
-
 The vcs is one of "git", "hg", "svn", etc,
 
 The repo-root is the root of the version control system
@@ -224,10 +217,10 @@ For example,
 
 	import "example.org/pkg/foo"
 
-will result in the following requests:
+will result in the following request(s):
 
 	https://example.org/pkg/foo?go-get=1 (preferred)
-	http://example.org/pkg/foo?go-get=1  (fallback, only with -insecure)
+	http://example.org/pkg/foo?go-get=1  (fallback)
 
 If that page contains the meta tag
 
@@ -261,11 +254,6 @@ unless it is being referred to by that import path. In this way, import comments
 let package authors make sure the custom import path is used and not a
 direct path to the underlying code hosting site.
 
-If the vendoring experiment is enabled (see 'go help gopath'),
-then import path checking is disabled for code found within vendor trees.
-This makes it possible to copy code into alternate locations in vendor trees
-without needing to update import comments.
-
 See https://golang.org/s/go14customimport for details.
 	`,
 }
@@ -287,10 +275,10 @@ standard Go tree.
 
 Each directory listed in GOPATH must have a prescribed structure:
 
-The src directory holds source code.  The path below src
+The src/ directory holds source code.  The path below 'src'
 determines the import path or executable name.
 
-The pkg directory holds installed package objects.
+The pkg/ directory holds installed package objects.
 As in the Go tree, each target operating system and
 architecture pair has its own subdirectory of pkg
 (pkg/GOOS_GOARCH).
@@ -299,11 +287,11 @@ If DIR is a directory listed in the GOPATH, a package with
 source in DIR/src/foo/bar can be imported as "foo/bar" and
 has its compiled form installed to "DIR/pkg/GOOS_GOARCH/foo/bar.a".
 
-The bin directory holds compiled commands.
+The bin/ directory holds compiled commands.
 Each command is named for its source directory, but only
 the final element, not the entire path.  That is, the
 command with source in DIR/src/foo/quux is installed into
-DIR/bin/quux, not DIR/bin/foo/quux.  The "foo/" prefix is stripped
+DIR/bin/quux, not DIR/bin/foo/quux.  The foo/ is stripped
 so that you can add DIR/bin to your PATH to get at the
 installed commands.  If the GOBIN environment variable is
 set, commands are installed to the directory it names instead
@@ -330,168 +318,6 @@ Here's an example directory layout:
 Go searches each directory listed in GOPATH to find source code,
 but new packages are always downloaded into the first directory
 in the list.
-
-See https://golang.org/doc/code.html for an example.
-
-Internal Directories
-
-Code in or below a directory named "internal" is importable only
-by code in the directory tree rooted at the parent of "internal".
-Here's an extended version of the directory layout above:
-
-    /home/user/gocode/
-        src/
-            crash/
-                bang/              (go code in package bang)
-                    b.go
-            foo/                   (go code in package foo)
-                f.go
-                bar/               (go code in package bar)
-                    x.go
-                internal/
-                    baz/           (go code in package baz)
-                        z.go
-                quux/              (go code in package main)
-                    y.go
-
-
-The code in z.go is imported as "foo/internal/baz", but that
-import statement can only appear in source files in the subtree
-rooted at foo. The source files foo/f.go, foo/bar/x.go, and
-foo/quux/y.go can all import "foo/internal/baz", but the source file
-crash/bang/b.go cannot.
-
-See https://golang.org/s/go14internal for details.
-
-Vendor Directories
-
-Go 1.5 includes experimental support for using local copies
-of external dependencies to satisfy imports of those dependencies,
-often referred to as vendoring. Setting the environment variable
-GO15VENDOREXPERIMENT=1 enables that experimental support.
-
-When the vendor experiment is enabled,
-code below a directory named "vendor" is importable only
-by code in the directory tree rooted at the parent of "vendor",
-and only using an import path that omits the prefix up to and
-including the vendor element.
-
-Here's the example from the previous section,
-but with the "internal" directory renamed to "vendor"
-and a new foo/vendor/crash/bang directory added:
-
-    /home/user/gocode/
-        src/
-            crash/
-                bang/              (go code in package bang)
-                    b.go
-            foo/                   (go code in package foo)
-                f.go
-                bar/               (go code in package bar)
-                    x.go
-                vendor/
-                    crash/
-                        bang/      (go code in package bang)
-                            b.go
-                    baz/           (go code in package baz)
-                        z.go
-                quux/              (go code in package main)
-                    y.go
-
-The same visibility rules apply as for internal, but the code
-in z.go is imported as "baz", not as "foo/vendor/baz".
-
-Code in vendor directories deeper in the source tree shadows
-code in higher directories. Within the subtree rooted at foo, an import
-of "crash/bang" resolves to "foo/vendor/crash/bang", not the
-top-level "crash/bang".
-
-Code in vendor directories is not subject to import path
-checking (see 'go help importpath').
-
-When the vendor experiment is enabled, 'go get' checks out
-submodules when checking out or updating a git repository
-(see 'go help get').
-
-The vendoring semantics are an experiment, and they may change
-in future releases. Once settled, they will be on by default.
-
-See https://golang.org/s/go15vendor for details.
-	`,
-}
-
-var helpEnvironment = &Command{
-	UsageLine: "environment",
-	Short:     "environment variables",
-	Long: `
-
-The go command, and the tools it invokes, examine a few different
-environment variables. For many of these, you can see the default
-value of on your system by running 'go env NAME', where NAME is the
-name of the variable.
-
-General-purpose environment variables:
-
-	GCCGO
-		The gccgo command to run for 'go build -compiler=gccgo'.
-	GOARCH
-		The architecture, or processor, for which to compile code.
-		Examples are amd64, 386, arm, ppc64.
-	GOBIN
-		The directory where 'go install' will install a command.
-	GOOS
-		The operating system for which to compile code.
-		Examples are linux, darwin, windows, netbsd.
-	GOPATH
-		See 'go help gopath'.
-	GORACE
-		Options for the race detector.
-		See https://golang.org/doc/articles/race_detector.html.
-	GOROOT
-		The root of the go tree.
-
-Environment variables for use with cgo:
-
-	CC
-		The command to use to compile C code.
-	CGO_ENABLED
-		Whether the cgo command is supported.  Either 0 or 1.
-	CGO_CFLAGS
-		Flags that cgo will pass to the compiler when compiling
-		C code.
-	CGO_CPPFLAGS
-		Flags that cgo will pass to the compiler when compiling
-		C or C++ code.
-	CGO_CXXFLAGS
-		Flags that cgo will pass to the compiler when compiling
-		C++ code.
-	CGO_LDFLAGS
-		Flags that cgo will pass to the compiler when linking.
-	CXX
-		The command to use to compile C++ code.
-
-Architecture-specific environment variables:
-
-	GOARM
-		For GOARCH=arm, the ARM architecture for which to compile.
-		Valid values are 5, 6, 7.
-	GO386
-		For GOARCH=386, the floating point instruction set.
-		Valid values are 387, sse2.
-
-Special-purpose environment variables:
-
-	GOROOT_FINAL
-		The root of the installed Go tree, when it is
-		installed in a location other than where it is built.
-		File names in stack traces are rewritten from GOROOT to
-		GOROOT_FINAL.
-	GO15VENDOREXPERIMENT
-		Set to 1 to enable the Go 1.5 vendoring experiment.
-	GO_EXTLINK_ENABLED
-		Whether the linker should use external linking mode
-		when using -linkmode=auto with code that uses cgo.
-		Set to 0 to disable external linking mode, 1 to enable it.
 	`,
 }
 
@@ -507,9 +333,10 @@ the extension of the file name. These extensions are:
 		Go source files.
 	.c, .h
 		C source files.
-		If the package uses cgo or SWIG, these will be compiled with the
-		OS-native compiler (typically gcc); otherwise they will
-		trigger an error.
+		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.
@@ -518,9 +345,10 @@ the extension of the file name. These extensions are:
 		compiled with the OS-native compiler.
 	.s, .S
 		Assembler source files.
-		If the package uses cgo or SWIG, these will be assembled with the
+		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 assembler.
+		will be assembled with the Go-specific support assembler,
+		5a, 6a, or 8a, etc., as appropriate.
 	.swig, .swigcxx
 		SWIG definition files.
 	.syso
@@ -532,43 +360,3 @@ at the first item in the file that is not a blank line or //-style
 line comment.
 	`,
 }
-
-var helpBuildmode = &Command{
-	UsageLine: "buildmode",
-	Short:     "description of build modes",
-	Long: `
-The 'go build' and 'go install' commands take a -buildmode argument which
-indicates which kind of object file is to be built. Currently supported values
-are:
-
-	-buildmode=archive
-		Build the listed non-main packages into .a files. Packages named
-		main are ignored.
-
-	-buildmode=c-archive
-		Build the listed main package, plus all packages it imports,
-		into a C archive file. The only callable symbols will be those
-		functions exported using a cgo //export comment. Requires
-		exactly one main package to be listed.
-
-	-buildmode=c-shared
-		Build the listed main packages, plus all packages that they
-		import, into C shared libraries. The only callable symbols will
-		be those functions exported using a cgo //export comment.
-		Non-main packages are ignored.
-
-	-buildmode=default
-		Listed main packages are built into executables and listed
-		non-main packages are built into .a files (the default
-		behavior).
-
-	-buildmode=shared
-		Combine all the listed non-main packages into a single shared
-		library that will be used when building with the -linkshared
-		option. Packages named main are ignored.
-
-	-buildmode=exe
-		Build the listed main packages and everything they import into
-		executables. Packages not named main are ignored.
-`,
-}
diff --git a/src/cmd/go/http.go b/src/cmd/go/http.go
index 7979c41..107b820 100644
--- a/src/cmd/go/http.go
+++ b/src/cmd/go/http.go
@@ -18,25 +18,11 @@ import (
 	"log"
 	"net/http"
 	"net/url"
-	"time"
 )
 
 // httpClient is the default HTTP client, but a variable so it can be
 // changed by tests, without modifying http.DefaultClient.
 var httpClient = http.DefaultClient
-var impatientHTTPClient = &http.Client{
-	Timeout: time.Duration(5 * time.Second),
-}
-
-type httpError struct {
-	status     string
-	statusCode int
-	url        string
-}
-
-func (e *httpError) Error() string {
-	return fmt.Sprintf("%s: %s", e.url, e.status)
-}
 
 // httpGET returns the data from an HTTP GET request for the given URL.
 func httpGET(url string) ([]byte, error) {
@@ -46,9 +32,7 @@ func httpGET(url string) ([]byte, error) {
 	}
 	defer resp.Body.Close()
 	if resp.StatusCode != 200 {
-		err := &httpError{status: resp.Status, statusCode: resp.StatusCode, url: url}
-
-		return nil, err
+		return nil, fmt.Errorf("%s: %s", url, resp.Status)
 	}
 	b, err := ioutil.ReadAll(resp.Body)
 	if err != nil {
@@ -59,7 +43,7 @@ func httpGET(url string) ([]byte, error) {
 
 // httpsOrHTTP returns the body of either the importPath's
 // https resource or, if unavailable, the http resource.
-func httpsOrHTTP(importPath string, security securityMode) (urlStr string, body io.ReadCloser, err error) {
+func httpsOrHTTP(importPath string) (urlStr string, body io.ReadCloser, err error) {
 	fetch := func(scheme string) (urlStr string, res *http.Response, err error) {
 		u, err := url.Parse(scheme + "://" + importPath)
 		if err != nil {
@@ -70,11 +54,7 @@ func httpsOrHTTP(importPath string, security securityMode) (urlStr string, body
 		if buildV {
 			log.Printf("Fetching %s", urlStr)
 		}
-		if security == insecure && scheme == "https" { // fail earlier
-			res, err = impatientHTTPClient.Get(urlStr)
-		} else {
-			res, err = httpClient.Get(urlStr)
-		}
+		res, err = httpClient.Get(urlStr)
 		return
 	}
 	closeBody := func(res *http.Response) {
@@ -92,9 +72,7 @@ func httpsOrHTTP(importPath string, security securityMode) (urlStr string, body
 			}
 		}
 		closeBody(res)
-		if security == insecure {
-			urlStr, res, err = fetch("http")
-		}
+		urlStr, res, err = fetch("http")
 	}
 	if err != nil {
 		closeBody(res)
diff --git a/src/cmd/go/list.go b/src/cmd/go/list.go
index 35c7cc4..fbf9616 100644
--- a/src/cmd/go/list.go
+++ b/src/cmd/go/list.go
@@ -21,10 +21,9 @@ List lists the packages named by the import paths, one per line.
 
 The default output shows the package import path:
 
-    bytes
-    encoding/json
-    github.com/gorilla/mux
-    golang.org/x/net/html
+    code.google.com/p/google-api-go-client/books/v1
+    code.google.com/p/goauth2/oauth
+    code.google.com/p/sqlite
 
 The -f flag specifies an alternate format for the list, using the
 syntax of package template.  The default output is equivalent to -f
@@ -37,7 +36,6 @@ syntax of package template.  The default output is equivalent to -f
         Name          string // package name
         Doc           string // package documentation string
         Target        string // install path
-        Shlib         string // the shared library that contains this package (only set when -linkshared)
         Goroot        bool   // is this package in the Go root?
         Standard      bool   // is this package part of the standard Go library?
         Stale         bool   // would 'go install' do anything for this package?
@@ -128,7 +126,6 @@ var listJson = cmdList.Flag.Bool("json", false, "")
 var nl = []byte{'\n'}
 
 func runList(cmd *Command, args []string) {
-	buildModeInit()
 	out := newTrackingWriter(os.Stdout)
 	defer out.w.Flush()
 
@@ -176,10 +173,6 @@ func runList(cmd *Command, args []string) {
 	}
 
 	for _, pkg := range load(args) {
-		// Show vendor-expanded paths in listing
-		pkg.TestImports = pkg.vendored(pkg.TestImports)
-		pkg.XTestImports = pkg.vendored(pkg.XTestImports)
-
 		do(pkg)
 	}
 }
diff --git a/src/cmd/go/main.go b/src/cmd/go/main.go
index 8ebde89..9691f39 100644
--- a/src/cmd/go/main.go
+++ b/src/cmd/go/main.go
@@ -5,7 +5,6 @@
 package main
 
 import (
-	"bufio"
 	"bytes"
 	"flag"
 	"fmt"
@@ -77,7 +76,6 @@ func (c *Command) Runnable() bool {
 var commands = []*Command{
 	cmdBuild,
 	cmdClean,
-	cmdDoc,
 	cmdEnv,
 	cmdFix,
 	cmdFmt,
@@ -92,10 +90,8 @@ var commands = []*Command{
 	cmdVet,
 
 	helpC,
-	helpBuildmode,
 	helpFileType,
 	helpGopath,
-	helpEnvironment,
 	helpImportPath,
 	helpPackages,
 	helpTestflag,
@@ -113,8 +109,6 @@ func setExitStatus(n int) {
 	exitMu.Unlock()
 }
 
-var origEnv []string
-
 func main() {
 	_ = go11tag
 	flag.Usage = usage
@@ -145,7 +139,7 @@ func main() {
 				fmt.Fprintf(os.Stderr, "go: GOPATH entry cannot start with shell metacharacter '~': %q\n", p)
 				os.Exit(2)
 			}
-			if !filepath.IsAbs(p) {
+			if build.IsLocalImport(p) {
 				fmt.Fprintf(os.Stderr, "go: GOPATH entry is relative; must be absolute path: %q.\nRun 'go help gopath' for usage.\n", p)
 				os.Exit(2)
 			}
@@ -157,20 +151,8 @@ func main() {
 		os.Exit(2)
 	}
 
-	// Set environment (GOOS, GOARCH, etc) explicitly.
-	// In theory all the commands we invoke should have
-	// the same default computation of these as we do,
-	// but in practice there might be skew
-	// This makes sure we all agree.
-	origEnv = os.Environ()
-	for _, env := range mkEnv() {
-		if os.Getenv(env.name) != env.value {
-			os.Setenv(env.name, env.value)
-		}
-	}
-
 	for _, cmd := range commands {
-		if cmd.Name() == args[0] && cmd.Runnable() {
+		if cmd.Name() == args[0] && cmd.Run != nil {
 			cmd.Flag.Usage = func() { cmd.Usage() }
 			if cmd.CustomFlags {
 				args = args[1:]
@@ -197,13 +179,13 @@ Usage:
 
 The commands are:
 {{range .}}{{if .Runnable}}
-	{{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}}
+    {{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}}
 
 Use "go help [command]" for more information about a command.
 
 Additional help topics:
 {{range .}}{{if not .Runnable}}
-	{{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}}
+    {{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}}
 
 Use "go help [topic]" for more information about that topic.
 
@@ -218,8 +200,8 @@ var documentationTemplate = `// Copyright 2011 The Go Authors.  All rights reser
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// DO NOT EDIT THIS FILE. GENERATED BY mkalldocs.sh.
-// Edit the documentation in other files and rerun mkalldocs.sh to generate this one.
+// DO NOT EDIT THIS FILE. GENERATED BY mkdoc.sh.
+// Edit the documentation in other files and rerun mkdoc.sh to generate this one.
 
 /*
 {{range .}}{{if .Short}}{{.Short | capitalize}}
@@ -235,35 +217,12 @@ var documentationTemplate = `// Copyright 2011 The Go Authors.  All rights reser
 package main
 `
 
-// An errWriter wraps a writer, recording whether a write error occurred.
-type errWriter struct {
-	w   io.Writer
-	err error
-}
-
-func (w *errWriter) Write(b []byte) (int, error) {
-	n, err := w.w.Write(b)
-	if err != nil {
-		w.err = err
-	}
-	return n, err
-}
-
 // tmpl executes the given template text on data, writing the result to w.
 func tmpl(w io.Writer, text string, data interface{}) {
 	t := template.New("top")
 	t.Funcs(template.FuncMap{"trim": strings.TrimSpace, "capitalize": capitalize})
 	template.Must(t.Parse(text))
-	ew := &errWriter{w: w}
-	err := t.Execute(ew, data)
-	if ew.err != nil {
-		// I/O error writing. Ignore write on closed pipe.
-		if strings.Contains(ew.err.Error(), "pipe") {
-			os.Exit(1)
-		}
-		fatalf("writing output: %v", ew.err)
-	}
-	if err != nil {
+	if err := t.Execute(w, data); err != nil {
 		panic(err)
 	}
 }
@@ -277,17 +236,13 @@ func capitalize(s string) string {
 }
 
 func printUsage(w io.Writer) {
-	bw := bufio.NewWriter(w)
-	tmpl(bw, usageTemplate, commands)
-	bw.Flush()
+	tmpl(w, usageTemplate, commands)
 }
 
 func usage() {
 	// special case "go test -h"
 	if len(os.Args) > 1 && os.Args[1] == "test" {
-		os.Stdout.WriteString(testUsage + "\n\n" +
-			strings.TrimSpace(testFlag1) + "\n\n" +
-			strings.TrimSpace(testFlag2) + "\n")
+		help([]string{"testflag"})
 		os.Exit(2)
 	}
 	printUsage(os.Stderr)
@@ -353,7 +308,7 @@ func importPathsNoDotExpansion(args []string) []string {
 		} else {
 			a = path.Clean(a)
 		}
-		if a == "all" || a == "std" || a == "cmd" {
+		if a == "all" || a == "std" {
 			out = append(out, allPackages(a)...)
 			continue
 		}
@@ -446,10 +401,11 @@ func runOut(dir string, cmdargs ...interface{}) []byte {
 // The environment is the current process's environment
 // but with an updated $PWD, so that an os.Getwd in the
 // child will be faster.
-func envForDir(dir string, base []string) []string {
+func envForDir(dir string) []string {
+	env := os.Environ()
 	// Internally we only use rooted paths, so dir is rooted.
 	// Even if dir is not rooted, no harm done.
-	return mergeEnvLists([]string{"PWD=" + dir}, base)
+	return mergeEnvLists([]string{"PWD=" + dir}, env)
 }
 
 // mergeEnvLists merges the two environment lists such that
@@ -502,28 +458,6 @@ func hasPathPrefix(s, prefix string) bool {
 	}
 }
 
-// hasFilePathPrefix reports whether the filesystem path s begins with the
-// elements in prefix.
-func hasFilePathPrefix(s, prefix string) bool {
-	sv := strings.ToUpper(filepath.VolumeName(s))
-	pv := strings.ToUpper(filepath.VolumeName(prefix))
-	s = s[len(sv):]
-	prefix = prefix[len(pv):]
-	switch {
-	default:
-		return false
-	case sv != pv:
-		return false
-	case len(s) == len(prefix):
-		return s == prefix
-	case len(s) > len(prefix):
-		if prefix != "" && prefix[len(prefix)-1] == filepath.Separator {
-			return strings.HasPrefix(s, prefix)
-		}
-		return s[len(prefix)] == filepath.Separator && s[:len(prefix)] == prefix
-	}
-}
-
 // treeCanMatchPattern(pattern)(name) reports whether
 // name or children of name can possibly match pattern.
 // Pattern is the same limited glob accepted by matchPattern.
@@ -541,8 +475,8 @@ func treeCanMatchPattern(pattern string) func(name string) bool {
 
 // allPackages returns all the packages that can be found
 // under the $GOPATH directories and $GOROOT matching pattern.
-// The pattern is either "all" (all packages), "std" (standard packages),
-// "cmd" (standard commands), or a path including "...".
+// The pattern is either "all" (all packages), "std" (standard packages)
+// or a path including "...".
 func allPackages(pattern string) []string {
 	pkgs := matchPackages(pattern)
 	if len(pkgs) == 0 {
@@ -554,7 +488,7 @@ func allPackages(pattern string) []string {
 func matchPackages(pattern string) []string {
 	match := func(string) bool { return true }
 	treeCanMatch := func(string) bool { return true }
-	if pattern != "all" && pattern != "std" && pattern != "cmd" {
+	if pattern != "all" && pattern != "std" {
 		match = matchPattern(pattern)
 		treeCanMatch = treeCanMatchPattern(pattern)
 	}
@@ -567,16 +501,47 @@ func matchPackages(pattern string) []string {
 	}
 	var pkgs []string
 
+	// Commands
+	cmd := filepath.Join(goroot, "src/cmd") + string(filepath.Separator)
+	filepath.Walk(cmd, func(path string, fi os.FileInfo, err error) error {
+		if err != nil || !fi.IsDir() || path == cmd {
+			return nil
+		}
+		name := path[len(cmd):]
+		if !treeCanMatch(name) {
+			return filepath.SkipDir
+		}
+		// Commands are all in cmd/, not in subdirectories.
+		if strings.Contains(name, string(filepath.Separator)) {
+			return filepath.SkipDir
+		}
+
+		// We use, e.g., cmd/gofmt as the pseudo import path for gofmt.
+		name = "cmd/" + name
+		if have[name] {
+			return nil
+		}
+		have[name] = true
+		if !match(name) {
+			return nil
+		}
+		_, err = buildContext.ImportDir(path, 0)
+		if err != nil {
+			if _, noGo := err.(*build.NoGoError); !noGo {
+				log.Print(err)
+			}
+			return nil
+		}
+		pkgs = append(pkgs, name)
+		return nil
+	})
+
 	for _, src := range buildContext.SrcDirs() {
-		if (pattern == "std" || pattern == "cmd") && src != gorootSrc {
+		if pattern == "std" && src != gorootSrc {
 			continue
 		}
 		src = filepath.Clean(src) + string(filepath.Separator)
-		root := src
-		if pattern == "cmd" {
-			root += "cmd" + string(filepath.Separator)
-		}
-		filepath.Walk(root, func(path string, fi os.FileInfo, err error) error {
+		filepath.Walk(src, func(path string, fi os.FileInfo, err error) error {
 			if err != nil || !fi.IsDir() || path == src {
 				return nil
 			}
@@ -588,10 +553,7 @@ func matchPackages(pattern string) []string {
 			}
 
 			name := filepath.ToSlash(path[len(src):])
-			if pattern == "std" && (strings.Contains(name, ".") || name == "cmd") {
-				// The name "std" is only the standard library.
-				// If the name has a dot, assume it's a domain name for go get,
-				// and if the name is cmd, it's the root of the command tree.
+			if pattern == "std" && strings.Contains(name, ".") {
 				return filepath.SkipDir
 			}
 			if !treeCanMatch(name) {
@@ -697,7 +659,7 @@ func stringList(args ...interface{}) []string {
 		case string:
 			x = append(x, arg)
 		default:
-			panic("stringList: invalid argument of type " + fmt.Sprintf("%T", arg))
+			panic("stringList: invalid argument")
 		}
 	}
 	return x
diff --git a/src/cmd/go/mkdoc.sh b/src/cmd/go/mkdoc.sh
new file mode 100755
index 0000000..e15e880
--- /dev/null
+++ b/src/cmd/go/mkdoc.sh
@@ -0,0 +1,9 @@
+#!/bin/sh
+# 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.
+
+go install # So the next line will produce updated documentation.
+go help documentation | sed 's; \*/; * /;' >doc.go
+gofmt -w doc.go
+
diff --git a/src/cmd/go/pkg.go b/src/cmd/go/pkg.go
index 61e3d8d..b71feb7 100644
--- a/src/cmd/go/pkg.go
+++ b/src/cmd/go/pkg.go
@@ -6,21 +6,18 @@ package main
 
 import (
 	"bytes"
-	"crypto/sha1"
 	"errors"
 	"fmt"
 	"go/build"
 	"go/scanner"
 	"go/token"
-	"io"
-	"io/ioutil"
 	"os"
 	pathpkg "path"
 	"path/filepath"
 	"runtime"
 	"sort"
-	"strconv"
 	"strings"
+	"time"
 	"unicode"
 )
 
@@ -35,7 +32,6 @@ type Package struct {
 	Name          string `json:",omitempty"` // package name
 	Doc           string `json:",omitempty"` // package documentation string
 	Target        string `json:",omitempty"` // install path
-	Shlib         string `json:",omitempty"` // the shared library that contains this package (only set when -linkshared)
 	Goroot        bool   `json:",omitempty"` // is this package found in the Go root?
 	Standard      bool   `json:",omitempty"` // is this package part of the standard Go library?
 	Stale         bool   `json:",omitempty"` // would 'go install' do anything for this package?
@@ -87,7 +83,6 @@ type Package struct {
 	allgofiles   []string             // gofiles + IgnoredGoFiles, absolute paths
 	target       string               // installed file for this package (may be executable)
 	fake         bool                 // synthesized package
-	external     bool                 // synthesized external test package
 	forceBuild   bool                 // this package must be rebuilt
 	forceLibrary bool                 // this package is a library (even if named "main")
 	cmdline      bool                 // defined by files listed on command line
@@ -97,35 +92,6 @@ type Package struct {
 	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
-	buildID      string               // expected build ID for generated package
-	gobinSubdir  bool                 // install target would be subdir of GOBIN
-}
-
-// vendored returns the vendor-resolved version of imports,
-// which should be p.TestImports or p.XTestImports, NOT p.Imports.
-// The imports in p.TestImports and p.XTestImports are not recursively
-// loaded during the initial load of p, so they list the imports found in
-// the source file, but most processing should be over the vendor-resolved
-// import paths. We do this resolution lazily both to avoid file system work
-// and because the eventual real load of the test imports (during 'go test')
-// can produce better error messages if it starts with the original paths.
-// The initial load of p loads all the non-test imports and rewrites
-// the vendored paths, so nothing should ever call p.vendored(p.Imports).
-func (p *Package) vendored(imports []string) []string {
-	if len(imports) > 0 && len(p.Imports) > 0 && &imports[0] == &p.Imports[0] {
-		panic("internal error: p.vendored(p.Imports) called")
-	}
-	seen := make(map[string]bool)
-	var all []string
-	for _, path := range imports {
-		path, _ = vendoredImportPath(p, path)
-		if !seen[path] {
-			seen[path] = true
-			all = append(all, path)
-		}
-	}
-	sort.Strings(all)
-	return all
 }
 
 // CoverVar holds the name of the generated coverage variables targeting the named file.
@@ -137,13 +103,6 @@ type CoverVar struct {
 func (p *Package) copyBuild(pp *build.Package) {
 	p.build = pp
 
-	if pp.PkgTargetRoot != "" && buildPkgdir != "" {
-		old := pp.PkgTargetRoot
-		pp.PkgRoot = buildPkgdir
-		pp.PkgTargetRoot = buildPkgdir
-		pp.PkgObj = filepath.Join(buildPkgdir, strings.TrimPrefix(pp.PkgObj, old))
-	}
-
 	p.Dir = pp.Dir
 	p.ImportPath = pp.ImportPath
 	p.ImportComment = pp.ImportComment
@@ -217,7 +176,7 @@ func (s *importStack) copy() []string {
 	return append([]string{}, *s...)
 }
 
-// shorterThan reports whether sp is shorter than t.
+// shorterThan returns true if sp is shorter than t.
 // We use this to record the shortest import sequence
 // that leads to a particular package.
 func (sp *importStack) shorterThan(t []string) bool {
@@ -250,12 +209,6 @@ func reloadPackage(arg string, stk *importStack) *Package {
 	return loadPackage(arg, stk)
 }
 
-// The Go 1.5 vendoring experiment is enabled by setting GO15VENDOREXPERIMENT=1.
-// The variable is obnoxiously long so that years from now when people find it in
-// their profiles and wonder what it does, there is some chance that a web search
-// might answer the question.
-var go15VendorExperiment = os.Getenv("GO15VENDOREXPERIMENT") == "1"
-
 // dirToImportPath returns the pseudo-import path we use for a package
 // outside the Go path.  It begins with _/ and then contains the full path
 // to the directory.  If the package lives in c:\home\gopher\my\pkg then
@@ -276,29 +229,11 @@ func makeImportValid(r rune) rune {
 	return r
 }
 
-// Mode flags for loadImport and download (in get.go).
-const (
-	// useVendor means that loadImport should do vendor expansion
-	// (provided the vendoring experiment is enabled).
-	// That is, useVendor means that the import path came from
-	// a source file and has not been vendor-expanded yet.
-	// Every import path should be loaded initially with useVendor,
-	// and then the expanded version (with the /vendor/ in it) gets
-	// recorded as the canonical import path. At that point, future loads
-	// of that package must not pass useVendor, because
-	// disallowVendor will reject direct use of paths containing /vendor/.
-	useVendor = 1 << iota
-
-	// getTestDeps is for download (part of "go get") and indicates
-	// that test dependencies should be fetched too.
-	getTestDeps
-)
-
 // loadImport scans the directory named by path, which must be an import path,
 // but possibly a local import path (an absolute file system path or one beginning
 // with ./ or ../).  A local relative path is interpreted relative to srcDir.
 // It returns a *Package describing the package found in that directory.
-func loadImport(path, srcDir string, parent *Package, stk *importStack, importPos []token.Position, mode int) *Package {
+func loadImport(path string, srcDir string, stk *importStack, importPos []token.Position) *Package {
 	stk.push(path)
 	defer stk.pop()
 
@@ -306,27 +241,15 @@ func loadImport(path, srcDir string, parent *Package, stk *importStack, importPo
 	// For a local import the identifier is the pseudo-import path
 	// we create from the full directory to the package.
 	// Otherwise it is the usual import path.
-	// For vendored imports, it is the expanded form.
 	importPath := path
-	origPath := path
 	isLocal := build.IsLocalImport(path)
-	var vendorSearch []string
 	if isLocal {
 		importPath = dirToImportPath(filepath.Join(srcDir, path))
-	} else if mode&useVendor != 0 {
-		path, vendorSearch = vendoredImportPath(parent, path)
-		importPath = path
 	}
-
 	if p := packageCache[importPath]; p != nil {
 		if perr := disallowInternal(srcDir, p, stk); perr != p {
 			return perr
 		}
-		if mode&useVendor != 0 {
-			if perr := disallowVendor(srcDir, origPath, p, stk); perr != p {
-				return perr
-			}
-		}
 		return reusePackage(p, stk)
 	}
 
@@ -342,33 +265,11 @@ func loadImport(path, srcDir string, parent *Package, stk *importStack, importPo
 	// TODO: After Go 1, decide when to pass build.AllowBinary here.
 	// See issue 3268 for mistakes to avoid.
 	bp, err := buildContext.Import(path, srcDir, build.ImportComment)
-
-	// If we got an error from go/build about package not found,
-	// it contains the directories from $GOROOT and $GOPATH that
-	// were searched. Add to that message the vendor directories
-	// that were searched.
-	if err != nil && len(vendorSearch) > 0 {
-		// NOTE(rsc): The direct text manipulation here is fairly awful,
-		// but it avoids defining new go/build API (an exported error type)
-		// late in the Go 1.5 release cycle. If this turns out to be a more general
-		// problem we could define a real error type when the decision can be
-		// considered more carefully.
-		text := err.Error()
-		if strings.Contains(text, "cannot find package \"") && strings.Contains(text, "\" in any of:\n\t") {
-			old := strings.SplitAfter(text, "\n")
-			lines := []string{old[0]}
-			for _, dir := range vendorSearch {
-				lines = append(lines, "\t"+dir+" (vendor tree)\n")
-			}
-			lines = append(lines, old[1:]...)
-			err = errors.New(strings.Join(lines, ""))
-		}
-	}
 	bp.ImportPath = importPath
 	if gobin != "" {
 		bp.BinDir = gobin
 	}
-	if err == nil && !isLocal && bp.ImportComment != "" && bp.ImportComment != path && (!go15VendorExperiment || !strings.Contains(path, "/vendor/")) {
+	if err == nil && !isLocal && bp.ImportComment != "" && bp.ImportComment != path {
 		err = fmt.Errorf("code in directory %s expects import %q", bp.Dir, bp.ImportComment)
 	}
 	p.load(stk, bp, err)
@@ -381,83 +282,10 @@ func loadImport(path, srcDir string, parent *Package, stk *importStack, importPo
 	if perr := disallowInternal(srcDir, p, stk); perr != p {
 		return perr
 	}
-	if mode&useVendor != 0 {
-		if perr := disallowVendor(srcDir, origPath, p, stk); perr != p {
-			return perr
-		}
-	}
 
 	return p
 }
 
-var isDirCache = map[string]bool{}
-
-func isDir(path string) bool {
-	result, ok := isDirCache[path]
-	if ok {
-		return result
-	}
-
-	fi, err := os.Stat(path)
-	result = err == nil && fi.IsDir()
-	isDirCache[path] = result
-	return result
-}
-
-// vendoredImportPath returns the expansion of path when it appears in parent.
-// If parent is x/y/z, then path might expand to x/y/z/vendor/path, x/y/vendor/path,
-// x/vendor/path, vendor/path, or else stay x/y/z if none of those exist.
-// vendoredImportPath returns the expanded path or, if no expansion is found, the original.
-// If no expansion is found, vendoredImportPath also returns a list of vendor directories
-// it searched along the way, to help prepare a useful error message should path turn
-// out not to exist.
-func vendoredImportPath(parent *Package, path string) (found string, searched []string) {
-	if parent == nil || parent.Root == "" || !go15VendorExperiment {
-		return path, nil
-	}
-	dir := filepath.Clean(parent.Dir)
-	root := filepath.Join(parent.Root, "src")
-	if !hasFilePathPrefix(dir, root) || len(dir) <= len(root) || dir[len(root)] != filepath.Separator {
-		fatalf("invalid vendoredImportPath: dir=%q root=%q separator=%q", dir, root, string(filepath.Separator))
-	}
-	vpath := "vendor/" + path
-	for i := len(dir); i >= len(root); i-- {
-		if i < len(dir) && dir[i] != filepath.Separator {
-			continue
-		}
-		// Note: checking for the vendor directory before checking
-		// for the vendor/path directory helps us hit the
-		// isDir cache more often. It also helps us prepare a more useful
-		// list of places we looked, to report when an import is not found.
-		if !isDir(filepath.Join(dir[:i], "vendor")) {
-			continue
-		}
-		targ := filepath.Join(dir[:i], vpath)
-		if isDir(targ) {
-			// We started with parent's dir c:\gopath\src\foo\bar\baz\quux\xyzzy.
-			// We know the import path for parent's dir.
-			// We chopped off some number of path elements and
-			// added vendor\path to produce c:\gopath\src\foo\bar\baz\vendor\path.
-			// Now we want to know the import path for that directory.
-			// Construct it by chopping the same number of path elements
-			// (actually the same number of bytes) from parent's import path
-			// and then append /vendor/path.
-			chopped := len(dir) - i
-			if chopped == len(parent.ImportPath)+1 {
-				// We walked up from c:\gopath\src\foo\bar
-				// and found c:\gopath\src\vendor\path.
-				// We chopped \foo\bar (length 8) but the import path is "foo/bar" (length 7).
-				// Use "vendor/path" without any prefix.
-				return vpath, nil
-			}
-			return parent.ImportPath[:len(parent.ImportPath)-chopped] + "/" + vpath, nil
-		}
-		// Note the existence of a vendor directory in case path is not found anywhere.
-		searched = append(searched, targ)
-	}
-	return path, searched
-}
-
 // reusePackage reuses package p to satisfy the import at the top
 // of the import stack stk.  If this use causes an import loop,
 // reusePackage updates p's error information to record the loop.
@@ -491,9 +319,11 @@ func disallowInternal(srcDir string, p *Package, stk *importStack) *Package {
 	// An import of a path containing the element “internal”
 	// is disallowed if the importing code is outside the tree
 	// rooted at the parent of the “internal” directory.
+	//
+	// ... For Go 1.4, we will implement the rule first for $GOROOT, but not $GOPATH.
 
-	// There was an error loading the package; stop here.
-	if p.Error != nil {
+	// Only applies to $GOROOT.
+	if !p.Standard {
 		return p
 	}
 
@@ -550,105 +380,6 @@ func findInternal(path string) (index int, ok bool) {
 	return 0, false
 }
 
-// disallowVendor checks that srcDir is allowed to import p as path.
-// If the import is allowed, disallowVendor returns the original package p.
-// If not, it returns a new package containing just an appropriate error.
-func disallowVendor(srcDir, path string, p *Package, stk *importStack) *Package {
-	if !go15VendorExperiment {
-		return p
-	}
-
-	// The stack includes p.ImportPath.
-	// If that's the only thing on the stack, we started
-	// with a name given on the command line, not an
-	// import. Anything listed on the command line is fine.
-	if len(*stk) == 1 {
-		return p
-	}
-
-	if perr := disallowVendorVisibility(srcDir, p, stk); perr != p {
-		return perr
-	}
-
-	// Paths like x/vendor/y must be imported as y, never as x/vendor/y.
-	if i, ok := findVendor(path); ok {
-		perr := *p
-		perr.Error = &PackageError{
-			ImportStack: stk.copy(),
-			Err:         "must be imported as " + path[i+len("vendor/"):],
-		}
-		perr.Incomplete = true
-		return &perr
-	}
-
-	return p
-}
-
-// disallowVendorVisibility checks that srcDir is allowed to import p.
-// The rules are the same as for /internal/ except that a path ending in /vendor
-// is not subject to the rules, only subdirectories of vendor.
-// This allows people to have packages and commands named vendor,
-// for maximal compatibility with existing source trees.
-func disallowVendorVisibility(srcDir string, p *Package, stk *importStack) *Package {
-	// The stack includes p.ImportPath.
-	// If that's the only thing on the stack, we started
-	// with a name given on the command line, not an
-	// import. Anything listed on the command line is fine.
-	if len(*stk) == 1 {
-		return p
-	}
-
-	// Check for "vendor" element.
-	i, ok := findVendor(p.ImportPath)
-	if !ok {
-		return p
-	}
-
-	// Vendor is present.
-	// Map import path back to directory corresponding to parent of vendor.
-	if i > 0 {
-		i-- // rewind over slash in ".../vendor"
-	}
-	truncateTo := i + len(p.Dir) - len(p.ImportPath)
-	if truncateTo < 0 || len(p.Dir) < truncateTo {
-		return p
-	}
-	parent := p.Dir[:truncateTo]
-	if hasPathPrefix(filepath.ToSlash(srcDir), filepath.ToSlash(parent)) {
-		return p
-	}
-
-	// Vendor is present, and srcDir is outside parent's tree. Not allowed.
-	perr := *p
-	perr.Error = &PackageError{
-		ImportStack: stk.copy(),
-		Err:         "use of vendored package not allowed",
-	}
-	perr.Incomplete = true
-	return &perr
-}
-
-// findVendor looks for the last non-terminating "vendor" path element in the given import path.
-// If there isn't one, findVendor returns ok=false.
-// Otherwise, findInternal returns ok=true and the index of the "vendor".
-//
-// Note that terminating "vendor" elements don't count: "x/vendor" is its own package,
-// not the vendored copy of an import "" (the empty import path).
-// This will allow people to have packages or commands named vendor.
-// This may help reduce breakage, or it may just be confusing. We'll see.
-func findVendor(path string) (index int, ok bool) {
-	// Two cases, depending on internal at start of string or not.
-	// The order matters: we must return the index of the final element,
-	// because the final one is where the effective import path starts.
-	switch {
-	case strings.Contains(path, "/vendor/"):
-		return strings.LastIndex(path, "/vendor/") + 1, true
-	case strings.HasPrefix(path, "vendor/"):
-		return 0, true
-	}
-	return 0, false
-}
-
 type targetDir int
 
 const (
@@ -662,23 +393,17 @@ const (
 var goTools = map[string]targetDir{
 	"cmd/addr2line":                        toTool,
 	"cmd/api":                              toTool,
-	"cmd/asm":                              toTool,
-	"cmd/compile":                          toTool,
 	"cmd/cgo":                              toTool,
-	"cmd/cover":                            toTool,
-	"cmd/dist":                             toTool,
-	"cmd/doc":                              toTool,
 	"cmd/fix":                              toTool,
 	"cmd/link":                             toTool,
-	"cmd/newlink":                          toTool,
 	"cmd/nm":                               toTool,
 	"cmd/objdump":                          toTool,
 	"cmd/pack":                             toTool,
 	"cmd/pprof":                            toTool,
-	"cmd/trace":                            toTool,
-	"cmd/vet":                              toTool,
 	"cmd/yacc":                             toTool,
+	"golang.org/x/tools/cmd/cover":         toTool,
 	"golang.org/x/tools/cmd/godoc":         toBin,
+	"golang.org/x/tools/cmd/vet":           toTool,
 	"code.google.com/p/go.tools/cmd/cover": stalePath,
 	"code.google.com/p/go.tools/cmd/godoc": stalePath,
 	"code.google.com/p/go.tools/cmd/vet":   stalePath,
@@ -741,15 +466,7 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
 		return p
 	}
 
-	useBindir := p.Name == "main"
-	if !p.Standard {
-		switch buildBuildmode {
-		case "c-archive", "c-shared":
-			useBindir = false
-		}
-	}
-
-	if useBindir {
+	if p.Name == "main" {
 		// Report an error when the old code.google.com/p/go.tools paths are used.
 		if goTools[p.ImportPath] == stalePath {
 			newPath := strings.Replace(p.ImportPath, "code.google.com/p/go.", "golang.org/x/", 1)
@@ -771,11 +488,6 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
 		} else if p.build.BinDir != "" {
 			// Install to GOBIN or bin of GOPATH entry.
 			p.target = filepath.Join(p.build.BinDir, elem)
-			if !p.Goroot && strings.Contains(elem, "/") && gobin != "" {
-				// Do not create $GOBIN/goos_goarch/elem.
-				p.target = ""
-				p.gobinSubdir = true
-			}
 		}
 		if goTools[p.ImportPath] == toTool {
 			// This is for 'go tool'.
@@ -791,21 +503,6 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
 		p.target = ""
 	} else {
 		p.target = p.build.PkgObj
-		if buildLinkshared {
-			shlibnamefile := p.target[:len(p.target)-2] + ".shlibname"
-			shlib, err := ioutil.ReadFile(shlibnamefile)
-			if err == nil {
-				libname := strings.TrimSpace(string(shlib))
-				if buildContext.Compiler == "gccgo" {
-					p.Shlib = filepath.Join(p.build.PkgTargetRoot, "shlibs", libname)
-				} else {
-					p.Shlib = filepath.Join(p.build.PkgTargetRoot, libname)
-
-				}
-			} else if !os.IsNotExist(err) {
-				fatalf("unexpected error reading %s: %v", shlibnamefile, err)
-			}
-		}
 	}
 
 	importPaths := p.Imports
@@ -819,14 +516,6 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
 	if len(p.CgoFiles) > 0 && (!p.Standard || !cgoSyscallExclude[p.ImportPath]) {
 		importPaths = append(importPaths, "syscall")
 	}
-
-	// Currently build mode c-shared, or -linkshared, forces
-	// external linking mode, and external linking mode forces an
-	// import of runtime/cgo.
-	if p.Name == "main" && !p.Goroot && (buildBuildmode == "c-shared" || buildLinkshared) {
-		importPaths = append(importPaths, "runtime/cgo")
-	}
-
 	// Everything depends on runtime, except runtime and unsafe.
 	if !p.Standard || (p.ImportPath != "runtime" && p.ImportPath != "unsafe") {
 		importPaths = append(importPaths, "runtime")
@@ -835,10 +524,6 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
 		if buildRace && (!p.Standard || !raceExclude[p.ImportPath]) {
 			importPaths = append(importPaths, "runtime/race")
 		}
-		// On ARM with GOARM=5, everything depends on math for the link.
-		if p.Name == "main" && goarch == "arm" {
-			importPaths = append(importPaths, "math")
-		}
 	}
 
 	// Build list of full paths to all Go files in the package,
@@ -896,17 +581,7 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
 		if path == "C" {
 			continue
 		}
-		p1 := loadImport(path, p.Dir, p, stk, p.build.ImportPos[path], useVendor)
-		if p1.Name == "main" {
-			p.Error = &PackageError{
-				ImportStack: stk.copy(),
-				Err:         fmt.Sprintf("import %q is a program, not an importable package", path),
-			}
-			pos := p.build.ImportPos[path]
-			if len(pos) > 0 {
-				p.Error.Pos = pos[0].String()
-			}
-		}
+		p1 := loadImport(path, p.Dir, stk, p.build.ImportPos[path])
 		if p1.local {
 			if !p.local && p.Error == nil {
 				p.Error = &PackageError{
@@ -918,21 +593,13 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
 					p.Error.Pos = pos[0].String()
 				}
 			}
-		}
-		path = p1.ImportPath
-		importPaths[i] = path
-		if i < len(p.Imports) {
-			p.Imports[i] = path
+			path = p1.ImportPath
+			importPaths[i] = path
 		}
 		deps[path] = p1
 		imports = append(imports, p1)
 		for _, dep := range p1.deps {
-			// The same import path could produce an error or not,
-			// depending on what tries to import it.
-			// Prefer to record entries with errors, so we can report them.
-			if deps[dep.ImportPath] == nil || dep.Error != nil {
-				deps[dep.ImportPath] = dep
-			}
+			deps[dep.ImportPath] = dep
 		}
 		if p1.Incomplete {
 			p.Incomplete = true
@@ -962,11 +629,12 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
 	}
 	p.Target = p.target
 
-	// The gc toolchain only permits C source files with cgo.
-	if len(p.CFiles) > 0 && !p.usesCgo() && !p.usesSwig() && buildContext.Compiler == "gc" {
+	// Check for C code compiled with Plan 9 C compiler.
+	// No longer allowed except in runtime and runtime/cgo, for now.
+	if len(p.CFiles) > 0 && !p.usesCgo() && (!p.Standard || p.ImportPath != "runtime") {
 		p.Error = &PackageError{
 			ImportStack: stk.copy(),
-			Err:         fmt.Sprintf("C source files not allowed when not using cgo or SWIG: %s", strings.Join(p.CFiles, " ")),
+			Err:         fmt.Sprintf("C source files not allowed when not using cgo: %s", strings.Join(p.CFiles, " ")),
 		}
 		return p
 	}
@@ -984,7 +652,6 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
 		}
 	}
 
-	computeBuildID(p)
 	return p
 }
 
@@ -1023,8 +690,13 @@ func packageList(roots []*Package) []*Package {
 // computeStale computes the Stale flag in the package dag that starts
 // at the named pkgs (command-line arguments).
 func computeStale(pkgs ...*Package) {
+	topRoot := map[string]bool{}
+	for _, p := range pkgs {
+		topRoot[p.Root] = true
+	}
+
 	for _, p := range packageList(pkgs) {
-		p.Stale = isStale(p)
+		p.Stale = isStale(p, topRoot)
 	}
 }
 
@@ -1034,269 +706,8 @@ func computeStale(pkgs ...*Package) {
 // inspecting the version.
 var isGoRelease = strings.HasPrefix(runtime.Version(), "go1")
 
-// isStale and computeBuildID
-//
-// Theory of Operation
-//
-// There is an installed copy of the package (or binary).
-// Can we reuse the installed copy, or do we need to build a new one?
-//
-// We can use the installed copy if it matches what we'd get
-// by building a new one. The hard part is predicting that without
-// actually running a build.
-//
-// To start, we must know the set of inputs to the build process that can
-// affect the generated output. At a minimum, that includes the source
-// files for the package and also any compiled packages imported by those
-// source files. The *Package has these, and we use them. One might also
-// argue for including in the input set: the build tags, whether the race
-// detector is in use, the target operating system and architecture, the
-// compiler and linker binaries being used, the additional flags being
-// passed to those, the cgo binary being used, the additional flags cgo
-// passes to the host C compiler, the host C compiler being used, the set
-// of host C include files and installed C libraries, and so on.
-// We include some but not all of this information.
-//
-// Once we have decided on a set of inputs, we must next decide how to
-// tell whether the content of that set has changed since the last build
-// of p. If there have been no changes, then we assume a new build would
-// produce the same result and reuse the installed package or binary.
-// But if there have been changes, then we assume a new build might not
-// produce the same result, so we rebuild.
-//
-// There are two common ways to decide whether the content of the set has
-// changed: modification times and content hashes. We use a mixture of both.
-//
-// The use of modification times (mtimes) was pioneered by make:
-// assuming that a file's mtime is an accurate record of when that file was last written,
-// and assuming that the modification time of an installed package or
-// binary is the time that it was built, if the mtimes of the inputs
-// predate the mtime of the installed object, then the build of that
-// object saw those versions of the files, and therefore a rebuild using
-// those same versions would produce the same object. In contrast, if any
-// mtime of an input is newer than the mtime of the installed object, a
-// change has occurred since the build, and the build should be redone.
-//
-// Modification times are attractive because the logic is easy to
-// understand and the file system maintains the mtimes automatically
-// (less work for us). Unfortunately, there are a variety of ways in
-// which the mtime approach fails to detect a change and reuses a stale
-// object file incorrectly. (Making the opposite mistake, rebuilding
-// unnecessarily, is only a performance problem and not a correctness
-// problem, so we ignore that one.)
-//
-// As a warmup, one problem is that to be perfectly precise, we need to
-// compare the input mtimes against the time at the beginning of the
-// build, but the object file time is the time at the end of the build.
-// If an input file changes after being read but before the object is
-// written, the next build will see an object newer than the input and
-// will incorrectly decide that the object is up to date. We make no
-// attempt to detect or solve this problem.
-//
-// Another problem is that due to file system imprecision, an input and
-// output that are actually ordered in time have the same mtime.
-// This typically happens on file systems with 1-second (or, worse,
-// 2-second) mtime granularity and with automated scripts that write an
-// input and then immediately run a build, or vice versa. If an input and
-// an output have the same mtime, the conservative behavior is to treat
-// the output as out-of-date and rebuild. This can cause one or more
-// spurious rebuilds, but only for 1 second, until the object finally has
-// an mtime later than the input.
-//
-// Another problem is that binary distributions often set the mtime on
-// all files to the same time. If the distribution includes both inputs
-// and cached build outputs, the conservative solution to the previous
-// problem will cause unnecessary rebuilds. Worse, in such a binary
-// distribution, those rebuilds might not even have permission to update
-// the cached build output. To avoid these write errors, if an input and
-// output have the same mtime, we assume the output is up-to-date.
-// This is the opposite of what the previous problem would have us do,
-// but binary distributions are more common than instances of the
-// previous problem.
-//
-// A variant of the last problem is that some binary distributions do not
-// set the mtime on all files to the same time. Instead they let the file
-// system record mtimes as the distribution is unpacked. If the outputs
-// are unpacked before the inputs, they'll be older and a build will try
-// to rebuild them. That rebuild might hit the same write errors as in
-// the last scenario. We don't make any attempt to solve this, and we
-// haven't had many reports of it. Perhaps the only time this happens is
-// when people manually unpack the distribution, and most of the time
-// that's done as the same user who will be using it, so an initial
-// rebuild on first use succeeds quietly.
-//
-// More generally, people and programs change mtimes on files. The last
-// few problems were specific examples of this, but it's a general problem.
-// For example, instead of a binary distribution, copying a home
-// directory from one directory or machine to another might copy files
-// but not preserve mtimes. If the inputs are new than the outputs on the
-// first machine but copied first, they end up older than the outputs on
-// the second machine.
-//
-// Because many other build systems have the same sensitivity to mtimes,
-// most programs manipulating source code take pains not to break the
-// mtime assumptions. For example, Git does not set the mtime of files
-// during a checkout operation, even when checking out an old version of
-// the code. This decision was made specifically to work well with
-// mtime-based build systems.
-//
-// The killer problem, though, for mtime-based build systems is that the
-// build only has access to the mtimes of the inputs that still exist.
-// If it is possible to remove an input without changing any other inputs,
-// a later build will think the object is up-to-date when it is not.
-// This happens for Go because a package is made up of all source
-// files in a directory. If a source file is removed, there is no newer
-// mtime available recording that fact. The mtime on the directory could
-// be used, but it also changes when unrelated files are added to or
-// removed from the directory, so including the directory mtime would
-// cause unnecessary rebuilds, possibly many. It would also exacerbate
-// the problems mentioned earlier, since even programs that are careful
-// to maintain mtimes on files rarely maintain mtimes on directories.
-//
-// A variant of the last problem is when the inputs change for other
-// reasons. For example, Go 1.4 and Go 1.5 both install $GOPATH/src/mypkg
-// into the same target, $GOPATH/pkg/$GOOS_$GOARCH/mypkg.a.
-// If Go 1.4 has built mypkg into mypkg.a, a build using Go 1.5 must
-// rebuild mypkg.a, but from mtimes alone mypkg.a looks up-to-date.
-// If Go 1.5 has just been installed, perhaps the compiler will have a
-// newer mtime; since the compiler is considered an input, that would
-// trigger a rebuild. But only once, and only the last Go 1.4 build of
-// mypkg.a happened before Go 1.5 was installed. If a user has the two
-// versions installed in different locations and flips back and forth,
-// mtimes alone cannot tell what to do. Changing the toolchain is
-// changing the set of inputs, without affecting any mtimes.
-//
-// To detect the set of inputs changing, we turn away from mtimes and to
-// an explicit data comparison. Specifically, we build a list of the
-// inputs to the build, compute its SHA1 hash, and record that as the
-// ``build ID'' in the generated object. At the next build, we can
-// recompute the buid ID and compare it to the one in the generated
-// object. If they differ, the list of inputs has changed, so the object
-// is out of date and must be rebuilt.
-//
-// Because this build ID is computed before the build begins, the
-// comparison does not have the race that mtime comparison does.
-//
-// Making the build sensitive to changes in other state is
-// straightforward: include the state in the build ID hash, and if it
-// changes, so does the build ID, triggering a rebuild.
-//
-// To detect changes in toolchain, we include the toolchain version in
-// the build ID hash for package runtime, and then we include the build
-// IDs of all imported packages in the build ID for p.
-//
-// It is natural to think about including build tags in the build ID, but
-// the naive approach of just dumping the tags into the hash would cause
-// spurious rebuilds. For example, 'go install' and 'go install -tags neverusedtag'
-// produce the same binaries (assuming neverusedtag is never used).
-// A more precise approach would be to include only tags that have an
-// effect on the build. But the effect of a tag on the build is to
-// include or exclude a file from the compilation, and that file list is
-// already in the build ID hash. So the build ID is already tag-sensitive
-// in a perfectly precise way. So we do NOT explicitly add build tags to
-// the build ID hash.
-//
-// We do not include as part of the build ID the operating system,
-// architecture, or whether the race detector is enabled, even though all
-// three have an effect on the output, because that information is used
-// to decide the install location. Binaries for linux and binaries for
-// darwin are written to different directory trees; including that
-// information in the build ID is unnecessary (although it would be
-// harmless).
-//
-// TODO(rsc): Investigate the cost of putting source file content into
-// the build ID hash as a replacement for the use of mtimes. Using the
-// file content would avoid all the mtime problems, but it does require
-// reading all the source files, something we avoid today (we read the
-// beginning to find the build tags and the imports, but we stop as soon
-// as we see the import block is over). If the package is stale, the compiler
-// is going to read the files anyway. But if the package is up-to-date, the
-// read is overhead.
-//
-// TODO(rsc): Investigate the complexity of making the build more
-// precise about when individual results are needed. To be fully precise,
-// there are two results of a compilation: the entire .a file used by the link
-// and the subpiece used by later compilations (__.PKGDEF only).
-// If a rebuild is needed but produces the previous __.PKGDEF, then
-// no more recompilation due to the rebuilt package is needed, only
-// relinking. To date, there is nothing in the Go command to express this.
-//
-// Special Cases
-//
-// When the go command makes the wrong build decision and does not
-// rebuild something it should, users fall back to adding the -a flag.
-// Any common use of the -a flag should be considered prima facie evidence
-// that isStale is returning an incorrect false result in some important case.
-// Bugs reported in the behavior of -a itself should prompt the question
-// ``Why is -a being used at all? What bug does that indicate?''
-//
-// There is a long history of changes to isStale to try to make -a into a
-// suitable workaround for bugs in the mtime-based decisions.
-// It is worth recording that history to inform (and, as much as possible, deter) future changes.
-//
-// (1) Before the build IDs were introduced, building with alternate tags
-// would happily reuse installed objects built without those tags.
-// For example, "go build -tags netgo myprog.go" would use the installed
-// copy of package net, even if that copy had been built without netgo.
-// (The netgo tag controls whether package net uses cgo or pure Go for
-// functionality such as name resolution.)
-// Using the installed non-netgo package defeats the purpose.
-//
-// Users worked around this with "go build -tags netgo -a myprog.go".
-//
-// Build IDs have made that workaround unnecessary:
-// "go build -tags netgo myprog.go"
-// cannot use a non-netgo copy of package net.
-//
-// (2) Before the build IDs were introduced, building with different toolchains,
-// especially changing between toolchains, tried to reuse objects stored in
-// $GOPATH/pkg, resulting in link-time errors about object file mismatches.
-//
-// Users worked around this with "go install -a ./...".
-//
-// Build IDs have made that workaround unnecessary:
-// "go install ./..." will rebuild any objects it finds that were built against
-// a different toolchain.
-//
-// (3) The common use of "go install -a ./..." led to reports of problems
-// when the -a forced the rebuild of the standard library, which for some
-// users was not writable. Because we didn't understand that the real
-// problem was the bug -a was working around, we changed -a not to
-// apply to the standard library.
-//
-// (4) The common use of "go build -tags netgo -a myprog.go" broke
-// when we changed -a not to apply to the standard library, because
-// if go build doesn't rebuild package net, it uses the non-netgo version.
-//
-// Users worked around this with "go build -tags netgo -installsuffix barf myprog.go".
-// The -installsuffix here is making the go command look for packages
-// in pkg/$GOOS_$GOARCH_barf instead of pkg/$GOOS_$GOARCH.
-// Since the former presumably doesn't exist, go build decides to rebuild
-// everything, including the standard library. Since go build doesn't
-// install anything it builds, nothing is ever written to pkg/$GOOS_$GOARCH_barf,
-// so repeated invocations continue to work.
-//
-// If the use of -a wasn't a red flag, the use of -installsuffix to point to
-// a non-existent directory in a command that installs nothing should
-// have been.
-//
-// (5) Now that (1) and (2) no longer need -a, we have removed the kludge
-// introduced in (3): once again, -a means ``rebuild everything,'' not
-// ``rebuild everything except the standard library.'' Only Go 1.4 had
-// the restricted meaning.
-//
-// In addition to these cases trying to trigger rebuilds, there are
-// special cases trying NOT to trigger rebuilds. The main one is that for
-// a variety of reasons (see above), the install process for a Go release
-// cannot be relied upon to set the mtimes such that the go command will
-// think the standard library is up to date. So the mtime evidence is
-// ignored for the standard library if we find ourselves in a release
-// version of Go. Build ID-based staleness checks still apply to the
-// standard library, even in release versions. This makes
-// 'go build -tags netgo' work, among other things.
-
 // isStale reports whether package p needs to be rebuilt.
-func isStale(p *Package) bool {
+func isStale(p *Package, topRoot map[string]bool) bool {
 	if p.Standard && (p.ImportPath == "unsafe" || buildContext.Compiler == "gccgo") {
 		// fake, builtin package
 		return false
@@ -1315,68 +726,28 @@ func isStale(p *Package) bool {
 		return false
 	}
 
-	// If the -a flag is given, rebuild everything.
-	if buildA {
-		return true
+	// If we are running a release copy of Go, do not rebuild the standard packages.
+	// They may not be writable anyway, but they are certainly not changing.
+	// This makes 'go build -a' skip the standard packages when using an official release.
+	// See issue 4106 and issue 8290.
+	pkgBuildA := buildA
+	if p.Standard && isGoRelease {
+		pkgBuildA = false
 	}
 
-	// If there's no install target or it's already marked stale, we have to rebuild.
-	if p.target == "" || p.Stale {
+	if pkgBuildA || p.target == "" || p.Stale {
 		return true
 	}
 
 	// Package is stale if completely unbuilt.
-	fi, err := os.Stat(p.target)
-	if err != nil {
-		return true
+	var built time.Time
+	if fi, err := os.Stat(p.target); err == nil {
+		built = fi.ModTime()
 	}
-
-	// Package is stale if the expected build ID differs from the
-	// recorded build ID. This catches changes like a source file
-	// being removed from a package directory. See issue 3895.
-	// It also catches changes in build tags that affect the set of
-	// files being compiled. See issue 9369.
-	// It also catches changes in toolchain, like when flipping between
-	// two versions of Go compiling a single GOPATH.
-	// See issue 8290 and issue 10702.
-	targetBuildID, err := readBuildID(p)
-	if err == nil && targetBuildID != p.buildID {
+	if built.IsZero() {
 		return true
 	}
 
-	// Package is stale if a dependency is.
-	for _, p1 := range p.deps {
-		if p1.Stale {
-			return true
-		}
-	}
-
-	// The checks above are content-based staleness.
-	// We assume they are always accurate.
-	//
-	// The checks below are mtime-based staleness.
-	// We hope they are accurate, but we know that they fail in the case of
-	// prebuilt Go installations that don't preserve the build mtimes
-	// (for example, if the pkg/ mtimes are before the src/ mtimes).
-	// See the large comment above isStale for details.
-
-	// If we are running a release copy of Go and didn't find a content-based
-	// reason to rebuild the standard packages, do not rebuild them.
-	// They may not be writable anyway, but they are certainly not changing.
-	// This makes 'go build' skip the standard packages when
-	// using an official release, even when the mtimes have been changed.
-	// See issue 3036, issue 3149, issue 4106, issue 8290.
-	// (If a change to a release tree must be made by hand, the way to force the
-	// install is to run make.bash, which will remove the old package archives
-	// before rebuilding.)
-	if p.Standard && isGoRelease {
-		return false
-	}
-
-	// Time-based staleness.
-
-	built := fi.ModTime()
-
 	olderThan := func(file string) bool {
 		fi, err := os.Stat(file)
 		return err != nil || fi.ModTime().After(built)
@@ -1384,7 +755,7 @@ func isStale(p *Package) bool {
 
 	// Package is stale if a dependency is, or if a dependency is newer.
 	for _, p1 := range p.deps {
-		if p1.target != "" && olderThan(p1.target) {
+		if p1.Stale || p1.target != "" && olderThan(p1.target) {
 			return true
 		}
 	}
@@ -1396,12 +767,8 @@ func isStale(p *Package) bool {
 	// back-dated, as some binary distributions may do, but it does handle
 	// a very common case.
 	// See issue 3036.
-	// Exclude $GOROOT, under the assumption that people working on
-	// the compiler may want to control when everything gets rebuilt,
-	// and people updating the Go repository will run make.bash or all.bash
-	// and get a full rebuild anyway.
-	// Excluding $GOROOT used to also fix issue 4106, but that's now
-	// taken care of above (at least when the installed Go is a released version).
+	// Assume code in $GOROOT is up to date, since it may not be writeable.
+	// See issue 4106.
 	if p.Root != goroot {
 		if olderThan(buildToolchain.compiler()) {
 			return true
@@ -1411,43 +778,19 @@ func isStale(p *Package) bool {
 		}
 	}
 
-	// Note: Until Go 1.5, we had an additional shortcut here.
-	// We built a list of the workspace roots ($GOROOT, each $GOPATH)
-	// containing targets directly named on the command line,
-	// and if p were not in any of those, it would be treated as up-to-date
-	// as long as it is built. The goal was to avoid rebuilding a system-installed
-	// $GOROOT, unless something from $GOROOT were explicitly named
-	// on the command line (like go install math).
-	// That's now handled by the isGoRelease clause above.
-	// The other effect of the shortcut was to isolate different entries in
-	// $GOPATH from each other. This had the unfortunate effect that
-	// if you had (say), GOPATH listing two entries, one for commands
-	// and one for libraries, and you did a 'git pull' in the library one
-	// and then tried 'go install commands/...', it would build the new libraries
-	// during the first build (because they wouldn't have been installed at all)
-	// but then subsequent builds would not rebuild the libraries, even if the
-	// mtimes indicate they are stale, because the different GOPATH entries
-	// were treated differently. This behavior was confusing when using
-	// non-trivial GOPATHs, which were particularly common with some
-	// code management conventions, like the original godep.
-	// Since the $GOROOT case (the original motivation) is handled separately,
-	// we no longer put a barrier between the different $GOPATH entries.
-	//
-	// One implication of this is that if there is a system directory for
-	// non-standard Go packages that is included in $GOPATH, the mtimes
-	// on those compiled packages must be no earlier than the mtimes
-	// on the source files. Since most distributions use the same mtime
-	// for all files in a tree, they will be unaffected. People using plain
-	// tar x to extract system-installed packages will need to adjust mtimes,
-	// but it's better to force them to get the mtimes right than to ignore
-	// the mtimes and thereby do the wrong thing in common use cases.
-	//
-	// So there is no GOPATH vs GOPATH shortcut here anymore.
-	//
-	// If something needs to come back here, we could try writing a dummy
-	// file with a random name to the $GOPATH/pkg directory (and removing it)
-	// to test for write access, and then skip GOPATH roots we don't have write
-	// access to. But hopefully we can just use the mtimes always.
+	// Have installed copy, probably built using current compilers,
+	// and built after its imported packages.  The only reason now
+	// that we'd have to rebuild it is if the sources were newer than
+	// the package.   If a package p is not in the same tree as any
+	// package named on the command-line, assume it is up-to-date
+	// no matter what the modification times on the source files indicate.
+	// This avoids rebuilding $GOROOT packages when people are
+	// working outside the Go root, and it effectively makes each tree
+	// listed in $GOPATH a separate compilation world.
+	// See issue 3149.
+	if p.Root != "" && !topRoot[p.Root] {
+		return false
+	}
 
 	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 {
@@ -1459,53 +802,6 @@ func isStale(p *Package) bool {
 	return false
 }
 
-// computeBuildID computes the build ID for p, leaving it in p.buildID.
-// Build ID is a hash of the information we want to detect changes in.
-// See the long comment in isStale for details.
-func computeBuildID(p *Package) {
-	h := sha1.New()
-
-	// Include the list of files compiled as part of the package.
-	// This lets us detect removed files. See issue 3895.
-	inputFiles := stringList(
-		p.GoFiles,
-		p.CgoFiles,
-		p.CFiles,
-		p.CXXFiles,
-		p.MFiles,
-		p.HFiles,
-		p.SFiles,
-		p.SysoFiles,
-		p.SwigFiles,
-		p.SwigCXXFiles,
-	)
-	for _, file := range inputFiles {
-		fmt.Fprintf(h, "file %s\n", file)
-	}
-
-	// Include the content of runtime/zversion.go in the hash
-	// for package runtime. This will give package runtime a
-	// different build ID in each Go release.
-	if p.Standard && p.ImportPath == "runtime" {
-		data, _ := ioutil.ReadFile(filepath.Join(p.Dir, "zversion.go"))
-		fmt.Fprintf(h, "zversion %q\n", string(data))
-	}
-
-	// Include the build IDs of any dependencies in the hash.
-	// This, combined with the runtime/zversion content,
-	// will cause packages to have different build IDs when
-	// compiled with different Go releases.
-	// This helps the go command know to recompile when
-	// people use the same GOPATH but switch between
-	// different Go releases. See issue 10702.
-	// This is also a better fix for issue 8290.
-	for _, p1 := range p.deps {
-		fmt.Fprintf(h, "dep %s %s\n", p1.ImportPath, p1.buildID)
-	}
-
-	p.buildID = fmt.Sprintf("%x", h.Sum(nil))
-}
-
 var cwd, _ = os.Getwd()
 
 var cmdCache = map[string]*Package{}
@@ -1568,7 +864,7 @@ func loadPackage(arg string, stk *importStack) *Package {
 		}
 	}
 
-	return loadImport(arg, cwd, nil, stk, nil, 0)
+	return loadImport(arg, cwd, stk, nil)
 }
 
 // packages returns the packages named by the
@@ -1638,23 +934,6 @@ func packagesForBuild(args []string) []*Package {
 		}
 	}
 	exitIfErrors()
-
-	// Check for duplicate loads of the same package.
-	// That should be impossible, but if it does happen then
-	// we end up trying to build the same package twice,
-	// usually in parallel overwriting the same files,
-	// which doesn't work very well.
-	seen := map[string]bool{}
-	reported := map[string]bool{}
-	for _, pkg := range packageList(pkgs) {
-		if seen[pkg.ImportPath] && !reported[pkg.ImportPath] {
-			reported[pkg.ImportPath] = true
-			errorf("internal error: duplicate loads of %s", pkg.ImportPath)
-		}
-		seen[pkg.ImportPath] = true
-	}
-	exitIfErrors()
-
 	return pkgs
 }
 
@@ -1680,170 +959,3 @@ func hasSubdir(root, dir string) (rel string, ok bool) {
 	}
 	return filepath.ToSlash(dir[len(root):]), true
 }
-
-var (
-	errBuildIDToolchain = fmt.Errorf("build ID only supported in gc toolchain")
-	errBuildIDMalformed = fmt.Errorf("malformed object file")
-	errBuildIDUnknown   = fmt.Errorf("lost build ID")
-)
-
-var (
-	bangArch = []byte("!<arch>")
-	pkgdef   = []byte("__.PKGDEF")
-	goobject = []byte("go object ")
-	buildid  = []byte("build id ")
-)
-
-// readBuildID reads the build ID from an archive or binary.
-// It only supports the gc toolchain.
-// Other toolchain maintainers should adjust this function.
-func readBuildID(p *Package) (id string, err error) {
-	if buildToolchain != (gcToolchain{}) {
-		return "", errBuildIDToolchain
-	}
-
-	// For commands, read build ID directly from binary.
-	if p.Name == "main" {
-		return ReadBuildIDFromBinary(p.Target)
-	}
-
-	// Otherwise, we expect to have an archive (.a) file,
-	// and we can read the build ID from the Go export data.
-	if !strings.HasSuffix(p.Target, ".a") {
-		return "", &os.PathError{Op: "parse", Path: p.Target, Err: errBuildIDUnknown}
-	}
-
-	// Read just enough of the target to fetch the build ID.
-	// The archive is expected to look like:
-	//
-	//	!<arch>
-	//	__.PKGDEF       0           0     0     644     7955      `
-	//	go object darwin amd64 devel X:none
-	//	build id "b41e5c45250e25c9fd5e9f9a1de7857ea0d41224"
-	//
-	// The variable-sized strings are GOOS, GOARCH, and the experiment list (X:none).
-	// Reading the first 1024 bytes should be plenty.
-	f, err := os.Open(p.Target)
-	if err != nil {
-		return "", err
-	}
-	data := make([]byte, 1024)
-	n, err := io.ReadFull(f, data)
-	f.Close()
-
-	if err != nil && n == 0 {
-		return "", err
-	}
-
-	bad := func() (string, error) {
-		return "", &os.PathError{Op: "parse", Path: p.Target, Err: errBuildIDMalformed}
-	}
-
-	// Archive header.
-	for i := 0; ; i++ { // returns during i==3
-		j := bytes.IndexByte(data, '\n')
-		if j < 0 {
-			return bad()
-		}
-		line := data[:j]
-		data = data[j+1:]
-		switch i {
-		case 0:
-			if !bytes.Equal(line, bangArch) {
-				return bad()
-			}
-		case 1:
-			if !bytes.HasPrefix(line, pkgdef) {
-				return bad()
-			}
-		case 2:
-			if !bytes.HasPrefix(line, goobject) {
-				return bad()
-			}
-		case 3:
-			if !bytes.HasPrefix(line, buildid) {
-				// Found the object header, just doesn't have a build id line.
-				// Treat as successful, with empty build id.
-				return "", nil
-			}
-			id, err := strconv.Unquote(string(line[len(buildid):]))
-			if err != nil {
-				return bad()
-			}
-			return id, nil
-		}
-	}
-}
-
-var (
-	goBuildPrefix = []byte("\xff Go build ID: \"")
-	goBuildEnd    = []byte("\"\n \xff")
-
-	elfPrefix = []byte("\x7fELF")
-)
-
-// ReadBuildIDFromBinary reads the build ID from a binary.
-//
-// ELF binaries store the build ID in a proper PT_NOTE section.
-//
-// Other binary formats are not so flexible. For those, the linker
-// stores the build ID as non-instruction bytes at the very beginning
-// of the text segment, which should appear near the beginning
-// of the file. This is clumsy but fairly portable. Custom locations
-// can be added for other binary types as needed, like we did for ELF.
-func ReadBuildIDFromBinary(filename string) (id string, err error) {
-	if filename == "" {
-		return "", &os.PathError{Op: "parse", Path: filename, Err: errBuildIDUnknown}
-	}
-
-	// Read the first 16 kB of the binary file.
-	// That should be enough to find the build ID.
-	// In ELF files, the build ID is in the leading headers,
-	// which are typically less than 4 kB, not to mention 16 kB.
-	// On other systems, we're trying to read enough that
-	// we get the beginning of the text segment in the read.
-	// The offset where the text segment begins in a hello
-	// world compiled for each different object format today:
-	//
-	//	Plan 9: 0x20
-	//	Windows: 0x600
-	//	Mach-O: 0x2000
-	//
-	f, err := os.Open(filename)
-	if err != nil {
-		return "", err
-	}
-	defer f.Close()
-
-	data := make([]byte, 16*1024)
-	_, err = io.ReadFull(f, data)
-	if err == io.ErrUnexpectedEOF {
-		err = nil
-	}
-	if err != nil {
-		return "", err
-	}
-
-	if bytes.HasPrefix(data, elfPrefix) {
-		return readELFGoBuildID(filename, f, data)
-	}
-
-	i := bytes.Index(data, goBuildPrefix)
-	if i < 0 {
-		// Missing. Treat as successful but build ID empty.
-		return "", nil
-	}
-
-	j := bytes.Index(data[i+len(goBuildPrefix):], goBuildEnd)
-	if j < 0 {
-		return "", &os.PathError{Op: "parse", Path: filename, Err: errBuildIDMalformed}
-	}
-
-	quoted := data[i+len(goBuildPrefix)-1 : i+len(goBuildPrefix)+j+1]
-	id, err = strconv.Unquote(string(quoted))
-	if err != nil {
-		return "", &os.PathError{Op: "parse", Path: filename, Err: errBuildIDMalformed}
-	}
-
-	return id, nil
-}
diff --git a/src/cmd/go/run.go b/src/cmd/go/run.go
index f6da373..ef8aa95 100644
--- a/src/cmd/go/run.go
+++ b/src/cmd/go/run.go
@@ -37,8 +37,7 @@ 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 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,
@@ -65,7 +64,6 @@ func printStderr(args ...interface{}) (int, error) {
 
 func runRun(cmd *Command, args []string) {
 	raceInit()
-	buildModeInit()
 	var b builder
 	b.init()
 	b.print = printStderr
@@ -138,7 +136,6 @@ func runStdin(cmdline []string) {
 	cmd.Stdin = os.Stdin
 	cmd.Stdout = os.Stdout
 	cmd.Stderr = os.Stderr
-	cmd.Env = origEnv
 	startSigHandlers()
 	if err := cmd.Run(); err != nil {
 		errorf("%v", err)
diff --git a/src/cmd/go/script b/src/cmd/go/script
new file mode 100755
index 0000000..340a7e8
--- /dev/null
+++ b/src/cmd/go/script
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+x() {
+	echo '--- ' "$@"
+	"$@"
+	echo '---'
+	echo
+}
+
+x go help
+x go help build
+x go help clean
+x go help install
+x go help fix
+x go help fmt
+x go help get
+x go help list
+x go help test
+x go help version
+x go help vet
+x go help gopath
+x go help importpath
+x go help remote
diff --git a/src/cmd/go/script.txt b/src/cmd/go/script.txt
new file mode 100644
index 0000000..a672146
--- /dev/null
+++ b/src/cmd/go/script.txt
@@ -0,0 +1,352 @@
+---  go help
+usage: go command [arguments]
+
+go manages Go source code.
+
+The commands are:
+
+    build       compile and install packages and dependencies
+    clean       remove intermediate objects
+    fix         run gofix on packages
+    fmt         run gofmt -w on packages
+    get         download and install packages and dependencies
+    install     install packages and dependencies
+    list        list packages
+    test        test packages
+    version     print Go version
+    vet         run govet on packages
+
+Use "go help [command]" for more information about a command.
+
+Additional help topics:
+
+    gopath      GOPATH environment variable
+    importpath  description of import paths
+    remote      remote import path syntax
+
+Use "go help [topic]" for more information about that topic.
+
+---
+
+---  go help build
+usage: go build [-n] [-v] [importpath...]
+
+Build compiles the packages named by the import paths,
+along with their dependencies, but it does not install the results.
+
+The -n flag prints the commands but does not run them.
+The -v flag prints the commands.
+
+For more about import paths, see 'go help importpath'.
+
+See also: go install, go get, go clean.
+---
+
+---  go help clean
+usage: go clean [-nuke] [importpath...]
+
+Clean removes intermediate object files generated during
+the compilation of the packages named by the import paths,
+but by default it does not remove the installed package binaries.
+
+The -nuke flag causes clean to remove the installed package binaries too.
+
+TODO: Clean does not clean dependencies of the packages.
+
+For more about import paths, see 'go help importpath'.
+---
+
+---  go help install
+usage: go install [-n] [-v] [importpath...]
+
+Install compiles and installs the packages named by the import paths,
+along with their dependencies.
+
+The -n flag prints the commands but does not run them.
+The -v flag prints the commands.
+
+For more about import paths, see 'go help importpath'.
+
+See also: go build, go get, go clean.
+---
+
+---  go help fix
+usage: go fix [importpath...]
+
+Fix runs the gofix command on the packages named by the import paths.
+
+For more about gofix, see 'godoc gofix'.
+For more about import paths, see 'go help importpath'.
+
+To run gofix with specific options, run gofix itself.
+
+See also: go fmt, go vet.
+---
+
+---  go help fmt
+usage: go fmt [importpath...]
+
+Fmt runs the command 'gofmt -w' on the packages named by the import paths.
+
+For more about gofmt, see 'godoc gofmt'.
+For more about import paths, see 'go help importpath'.
+
+To run gofmt with specific options, run gofmt itself.
+
+See also: go fix, go vet.
+---
+
+---  go help get
+usage: go get [importpath...]
+
+Get downloads and installs the packages named by the import paths,
+along with their dependencies.
+
+After downloading the code, 'go get' looks for a tag beginning
+with "go." that corresponds to the local Go version.
+For Go "release.r58" it looks for a tag named "go.r58".
+For "weekly.2011-06-03" it looks for "go.weekly.2011-06-03".
+If the specific "go.X" tag is not found, it uses the latest earlier
+version it can find.  Otherwise, it uses the default version for
+the version control system: HEAD for git, tip for Mercurial,
+and so on.
+
+TODO: Explain versions better.
+
+For more about import paths, see 'go help importpath'.
+
+For more about how 'go get' finds source code to
+download, see 'go help remote'.
+
+See also: go build, go install, go clean.
+---
+
+---  go help list
+usage: go list [-f format] [-json] [importpath...]
+
+List lists the packages named by the import paths.
+
+The default output shows the package name and file system location:
+
+    books /home/you/src/google-api-go-client.googlecode.com/hg/books/v1
+    oauth /home/you/src/goauth2.googlecode.com/hg/oauth
+    sqlite /home/you/src/gosqlite.googlecode.com/hg/sqlite
+
+The -f flag specifies an alternate format for the list,
+using the syntax of package template.  The default output
+is equivalent to -f '{{.Name}} {{.Dir}}'  The struct
+being passed to the template is:
+
+    type Package struct {
+        Name string         // package name
+        Doc string          // package documentation string
+        GoFiles []string    // names of Go source files in package
+        ImportPath string   // import path denoting package
+        Imports []string    // import paths used by this package
+        Deps []string       // all (recursively) imported dependencies
+        Dir string          // directory containing package sources
+        Version string      // version of installed package
+    }
+
+The -json flag causes the package data to be printed in JSON format.
+
+For more about import paths, see 'go help importpath'.
+---
+
+---  go help test
+usage: go test [importpath...]
+
+Test runs gotest to test the packages named by the import paths.
+It prints a summary of the test results in the format:
+
+	test archive/tar
+	FAIL archive/zip
+	test compress/gzip
+	...
+
+followed by gotest output for each failed package.
+
+For more about import paths, see 'go help importpath'.
+
+See also: go build, go compile, go vet.
+---
+
+---  go help version
+usage: go version
+
+Version prints the Go version, as reported by runtime.Version.
+---
+
+---  go help vet
+usage: go vet [importpath...]
+
+Vet runs the govet command on the packages named by the import paths.
+
+For more about govet, see 'godoc govet'.
+For more about import paths, see 'go help importpath'.
+
+To run govet with specific options, run govet itself.
+
+See also: go fmt, go fix.
+---
+
+---  go help gopath
+The GOPATH environment variable lists places to look for Go code.
+On Unix, the value is a colon-separated string.
+On Windows, the value is a semicolon-separated string.
+On Plan 9, the value is a list.
+
+GOPATH must be set to build and install packages outside the
+standard Go tree.
+
+Each directory listed in GOPATH must have a prescribed structure:
+
+The src/ directory holds source code.  The path below 'src'
+determines the import path or executable name.
+
+The pkg/ directory holds installed package objects.
+As in the Go tree, each target operating system and
+architecture pair has its own subdirectory of pkg
+(pkg/GOOS_GOARCH).
+
+If DIR is a directory listed in the GOPATH, a package with
+source in DIR/src/foo/bar can be imported as "foo/bar" and
+has its compiled form installed to "DIR/pkg/GOOS_GOARCH/foo/bar.a".
+
+The bin/ directory holds compiled commands.
+Each command is named for its source directory, but only
+the final element, not the entire path.  That is, the
+command with source in DIR/src/foo/quux is installed into
+DIR/bin/quux, not DIR/bin/foo/quux.  The foo/ is stripped
+so that you can add DIR/bin to your PATH to get at the
+installed commands.
+
+Here's an example directory layout:
+
+    GOPATH=/home/user/gocode
+
+    /home/user/gocode/
+        src/
+            foo/
+                bar/               (go code in package bar)
+                    x.go
+                quux/              (go code in package main)
+                    y.go
+        bin/
+            quux                   (installed command)
+		pkg/
+		    linux_amd64/
+		        foo/
+		            bar.a          (installed package object)
+
+Go searches each directory listed in GOPATH to find source code,
+but new packages are always downloaded into the first directory 
+in the list.
+---
+
+---  go help importpath
+Many commands apply to a set of packages named by import paths:
+
+	go action [importpath...]
+
+An import path that is a rooted path or that begins with
+a . or .. element is interpreted as a file system path and
+denotes the package in that directory.
+
+Otherwise, the import path P denotes the package found in
+the directory DIR/src/P for some DIR listed in the GOPATH
+environment variable (see 'go help gopath'). 
+
+If no import paths are given, the action applies to the
+package in the current directory.
+
+The special import path "all" expands to all package directories
+found in all the GOPATH trees.  For example, 'go list all' 
+lists all the packages on the local system.
+
+An import path can also name a package to be downloaded from
+a remote repository.  Run 'go help remote' for details.
+
+Every package in a program must have a unique import path.
+By convention, this is arranged by starting each path with a
+unique prefix that belongs to you.  For example, paths used
+internally at Google all begin with 'google', and paths
+denoting remote repositories begin with the path to the code,
+such as 'project.googlecode.com/'.
+---
+
+---  go help remote
+An import path (see 'go help importpath') denotes a package
+stored in the local file system.  Certain import paths also
+describe how to obtain the source code for the package using
+a revision control system.
+
+A few common code hosting sites have special syntax:
+
+	BitBucket (Mercurial)
+
+		import "bitbucket.org/user/project"
+		import "bitbucket.org/user/project/sub/directory"
+
+	GitHub (Git)
+
+		import "github.com/user/project"
+		import "github.com/user/project/sub/directory"
+
+	Google Code Project Hosting (Git, Mercurial, Subversion)
+
+		import "project.googlecode.com/git"
+		import "project.googlecode.com/git/sub/directory"
+
+		import "project.googlecode.com/hg"
+		import "project.googlecode.com/hg/sub/directory"
+
+		import "project.googlecode.com/svn/trunk"
+		import "project.googlecode.com/svn/trunk/sub/directory"
+
+	Launchpad (Bazaar)
+
+		import "launchpad.net/project"
+		import "launchpad.net/project/series"
+		import "launchpad.net/project/series/sub/directory"
+
+		import "launchpad.net/~user/project/branch"
+		import "launchpad.net/~user/project/branch/sub/directory"
+
+For code hosted on other servers, an import path of the form
+
+	repository.vcs/path
+
+specifies the given repository, with or without the .vcs suffix,
+using the named version control system, and then the path inside
+that repository.  The supported version control systems are:
+
+	Bazaar      .bzr
+	Git         .git
+	Mercurial   .hg
+	Subversion  .svn
+
+For example,
+
+	import "example.org/user/foo.hg"
+
+denotes the root directory of the Mercurial repository at
+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.
+
+When a version control system supports multiple protocols,
+each is tried in turn when downloading.  For example, a Git
+download tries git://, then https://, then http://.
+
+New downloaded packages are written to the first directory
+listed in the GOPATH environment variable (see 'go help gopath').
+
+The go command attempts to download the version of the
+package appropriate for the Go release being used.
+Run 'go help install' for more.
+---
+
diff --git a/src/cmd/go/test.bash b/src/cmd/go/test.bash
new file mode 100755
index 0000000..e0f066f
--- /dev/null
+++ b/src/cmd/go/test.bash
@@ -0,0 +1,1123 @@
+#!/bin/bash
+# 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.
+
+set -e
+go build -tags testgo -o testgo
+go() {
+	echo TEST ERROR: ran go, not testgo: go "$@" >&2
+	exit 2
+}
+
+started=false
+testdesc=""
+nl="
+"
+TEST() {
+	if $started; then
+		stop
+	fi
+	echo TEST: "$@"
+	testdesc="$@"
+	started=true
+	ok=true
+}
+stop() {
+	if ! $started; then
+		echo TEST ERROR: stop missing start >&2
+		exit 2
+	fi
+	started=false
+	if $ok; then
+		echo PASS
+	else
+		echo FAIL
+		testfail="$testfail	$testdesc$nl"
+		allok=false
+	fi
+}
+
+ok=true
+allok=true
+
+unset GOBIN
+unset GOPATH
+unset GOROOT
+
+TEST 'file:line in error messages'
+# Test that error messages have file:line information at beginning of
+# the line. Also test issue 4917: that the error is on stderr.
+d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
+fn=$d/err.go
+echo "package main" > $fn
+echo 'import "bar"' >> $fn
+./testgo run $fn 2>$d/err.out || true
+if ! grep -q "^$fn:" $d/err.out; then
+	echo "missing file:line in error message"
+	cat $d/err.out
+	ok=false
+fi
+rm -r $d
+
+TEST 'program name in crash messages'
+linker=$(./testgo env GOCHAR)l
+d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
+./testgo build -ldflags -crash_for_testing $(./testgo env GOROOT)/test/helloworld.go 2>$d/err.out || true
+if ! grep -q "/tool/.*/$linker" $d/err.out; then
+	echo "missing linker name in error message"
+	cat $d/err.out
+	ok=false
+fi
+rm -r $d
+
+TEST broken tests without Test functions all fail
+d=$(mktemp -d -t testgoXXX)
+./testgo test ./testdata/src/badtest/... >$d/err 2>&1 || true
+if grep -q '^ok' $d/err; then
+	echo test passed unexpectedly:
+	grep '^ok' $d/err
+	ok=false
+elif ! grep -q 'FAIL.*badtest/badexec' $d/err || ! grep -q 'FAIL.*badtest/badsyntax' $d/err || ! grep -q 'FAIL.*badtest/badvar' $d/err; then
+	echo test did not run everything
+	cat $d/err
+	ok=false
+fi
+rm -rf $d
+
+TEST 'go build -a in dev branch'
+./testgo install math || ok=false # should be up to date already but just in case
+d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
+if ! TESTGO_IS_GO_RELEASE=0 ./testgo build -v -a math 2>$d/err.out; then
+	cat $d/err.out
+	ok=false
+elif ! grep -q runtime $d/err.out; then
+	echo "testgo build -a math in dev branch DID NOT build runtime, but should have"
+	cat $d/err.out
+	ok=false
+fi
+rm -r $d
+
+TEST 'go build -a in release branch'
+./testgo install math || ok=false # should be up to date already but just in case
+d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
+if ! TESTGO_IS_GO_RELEASE=1 ./testgo build -v -a math 2>$d/err.out; then
+	cat $d/err.out
+	ok=false
+elif grep -q runtime $d/err.out; then
+	echo "testgo build -a math in dev branch DID build runtime, but should NOT have"
+	cat $d/err.out
+	ok=false
+fi
+rm -r $d
+
+# Test local (./) imports.
+testlocal() {
+	local="$1"
+	TEST local imports $2 '(easy)'
+	./testgo build -o hello "testdata/$local/easy.go" || ok=false
+	./hello >hello.out || ok=false
+	if ! grep -q '^easysub\.Hello' hello.out; then
+		echo "testdata/$local/easy.go did not generate expected output"
+		cat hello.out
+		ok=false
+	fi
+	
+	TEST local imports $2 '(easysub)'
+	./testgo build -o hello "testdata/$local/easysub/main.go" || ok=false
+	./hello >hello.out || ok=false
+	if ! grep -q '^easysub\.Hello' hello.out; then
+		echo "testdata/$local/easysub/main.go did not generate expected output"
+		cat hello.out
+		ok=false
+	fi
+	
+	TEST local imports $2 '(hard)'
+	./testgo build -o hello "testdata/$local/hard.go" || ok=false
+	./hello >hello.out || ok=false
+	if ! grep -q '^sub\.Hello' hello.out || ! grep -q '^subsub\.Hello' hello.out ; then
+		echo "testdata/$local/hard.go did not generate expected output"
+		cat hello.out
+		ok=false
+	fi
+	
+	rm -f hello.out hello
+	
+	# Test that go install x.go fails.
+	TEST local imports $2 '(go install should fail)'
+	if ./testgo install "testdata/$local/easy.go" >/dev/null 2>&1; then
+		echo "go install testdata/$local/easy.go succeeded"
+		ok=false
+	fi
+}
+
+# Test local imports
+testlocal local ''
+
+# Test local imports again, with bad characters in the directory name.
+bad='#$%:, &()*;<=>?\^{}'
+rm -rf "testdata/$bad"
+cp -R testdata/local "testdata/$bad"
+testlocal "$bad" 'with bad characters in path'
+rm -rf "testdata/$bad"
+
+TEST 'internal packages in $GOROOT are respected'
+if ./testgo build -v ./testdata/testinternal >testdata/std.out 2>&1; then
+	echo "go build ./testdata/testinternal succeeded incorrectly"
+	ok=false
+elif ! grep 'use of internal package not allowed' testdata/std.out >/dev/null; then
+	echo "wrong error message for testdata/testinternal"
+	cat std.out
+	ok=false
+fi
+
+TEST 'internal packages outside $GOROOT are not respected'
+if ! ./testgo build -v ./testdata/testinternal2; then
+	echo "go build ./testdata/testinternal2 failed"
+	ok=false
+fi
+
+# Test that 'go get -u' reports moved packages.
+testmove() {
+	vcs=$1
+	url=$2
+	base=$3
+	config=$4
+
+	TEST go get -u notices $vcs package that moved
+	d=$(mktemp -d -t testgoXXX)
+	mkdir -p $d/src
+	if ! GOPATH=$d ./testgo get -d $url; then
+		echo 'go get -d $url failed'
+		ok=false
+	elif ! GOPATH=$d ./testgo get -d -u $url; then
+		echo 'go get -d -u $url failed'
+		ok=false
+	else
+		set +e
+		case "$vcs" in
+		svn)
+			# SVN doesn't believe in text files so we can't just edit the config.
+			# Check out a different repo into the wrong place.
+			rm -rf $d/src/code.google.com/p/rsc-svn
+			GOPATH=$d ./testgo get -d -u code.google.com/p/rsc-svn2/trunk
+			mv $d/src/code.google.com/p/rsc-svn2 $d/src/code.google.com/p/rsc-svn
+			;;
+		*)
+			echo '1,$s;'"$base"';'"$base"'XXX;
+w
+q' | ed $d/src/$config >/dev/null 2>&1
+		esac
+		set -e
+
+		if GOPATH=$d ./testgo get -d -u $url 2>$d/err; then
+			echo "go get -d -u $url succeeded with wrong remote repo"
+			cat $d/err
+			ok=false
+		elif ! grep 'should be from' $d/err >/dev/null; then
+			echo "go get -d -u $url failed for wrong reason"
+			cat $d/err
+			ok=false
+		fi
+		
+		if GOPATH=$d ./testgo get -d -f -u $url 2>$d/err; then
+			echo "go get -d -u $url succeeded with wrong remote repo"
+			cat $d/err
+			ok=false
+		elif ! egrep -i 'validating server certificate|not found' $d/err >/dev/null; then
+			echo "go get -d -f -u $url failed for wrong reason"
+			cat $d/err
+			ok=false
+		fi
+	fi
+	rm -rf $d
+}
+
+testmove hg rsc.io/x86/x86asm x86 rsc.io/x86/.hg/hgrc
+testmove git rsc.io/pdf pdf rsc.io/pdf/.git/config
+testmove svn code.google.com/p/rsc-svn/trunk - -
+
+export GOPATH=$(pwd)/testdata/importcom
+TEST 'import comment - match'
+if ! ./testgo build ./testdata/importcom/works.go; then
+	echo 'go build ./testdata/importcom/works.go failed'
+	ok=false
+fi
+TEST 'import comment - mismatch'
+if ./testgo build ./testdata/importcom/wrongplace.go 2>testdata/err; then
+	echo 'go build ./testdata/importcom/wrongplace.go suceeded'
+	ok=false
+elif ! grep 'wrongplace expects import "my/x"' testdata/err >/dev/null; then
+	echo 'go build did not mention incorrect import:'
+	cat testdata/err
+	ok=false
+fi
+TEST 'import comment - syntax error'
+if ./testgo build ./testdata/importcom/bad.go 2>testdata/err; then
+	echo 'go build ./testdata/importcom/bad.go suceeded'
+	ok=false
+elif ! grep 'cannot parse import comment' testdata/err >/dev/null; then
+	echo 'go build did not mention syntax error:'
+	cat testdata/err
+	ok=false
+fi
+TEST 'import comment - conflict'
+if ./testgo build ./testdata/importcom/conflict.go 2>testdata/err; then
+	echo 'go build ./testdata/importcom/conflict.go suceeded'
+	ok=false
+elif ! grep 'found import comments' testdata/err >/dev/null; then
+	echo 'go build did not mention comment conflict:'
+	cat testdata/err
+	ok=false
+fi
+rm -f ./testdata/err
+unset GOPATH
+
+export GOPATH=$(pwd)/testdata/src
+TEST disallowed C source files
+export GOPATH=$(pwd)/testdata
+if ./testgo build badc 2>testdata/err; then
+	echo 'go build badc succeeded'
+	ok=false
+elif ! grep 'C source files not allowed' testdata/err >/dev/null; then
+	echo 'go test did not say C source files not allowed:'
+	cat testdata/err
+	ok=false
+fi
+rm -f ./testdata/err
+unset GOPATH
+
+TEST error message for syntax error in test go file says FAIL
+export GOPATH=$(pwd)/testdata
+if ./testgo test syntaxerror 2>testdata/err; then
+	echo 'go test syntaxerror succeeded'
+	ok=false
+elif ! grep FAIL testdata/err >/dev/null; then
+	echo 'go test did not say FAIL:'
+	cat testdata/err
+	ok=false
+fi
+rm -f ./testdata/err
+unset GOPATH
+
+TEST wildcards do not look in useless directories
+export GOPATH=$(pwd)/testdata
+if ./testgo list ... >testdata/err 2>&1; then
+	echo "go list ... succeeded"
+	ok=false
+elif ! grep badpkg testdata/err >/dev/null; then
+	echo "go list ... failure does not mention badpkg"
+	cat testdata/err
+	ok=false
+elif ! ./testgo list m... >testdata/err 2>&1; then
+	echo "go list m... failed"
+	ok=false
+fi
+rm -rf ./testdata/err
+unset GOPATH
+
+# Test tests with relative imports.
+TEST relative imports '(go test)'
+if ! ./testgo test ./testdata/testimport; then
+	echo "go test ./testdata/testimport failed"
+	ok=false
+fi
+
+# Test installation with relative imports.
+TEST relative imports '(go test -i)'
+if ! ./testgo test -i ./testdata/testimport; then
+    echo "go test -i ./testdata/testimport failed"
+    ok=false
+fi
+
+# Test tests with relative imports in packages synthesized
+# from Go files named on the command line.
+TEST relative imports in command-line package
+if ! ./testgo test ./testdata/testimport/*.go; then
+	echo "go test ./testdata/testimport/*.go failed"
+	ok=false
+fi
+
+TEST version control error message includes correct directory
+export GOPATH=$(pwd)/testdata/shadow/root1
+if ./testgo get -u foo 2>testdata/err; then
+	echo "go get -u foo succeeded unexpectedly"
+	ok=false
+elif ! grep testdata/shadow/root1/src/foo testdata/err >/dev/null; then
+	echo "go get -u error does not mention shadow/root1/src/foo:"
+	cat testdata/err
+	ok=false
+fi
+unset GOPATH
+
+TEST go install fails with no buildable files
+export GOPATH=$(pwd)/testdata
+export CGO_ENABLED=0
+if ./testgo install cgotest 2>testdata/err; then
+	echo "go install cgotest succeeded unexpectedly"
+elif ! grep 'no buildable Go source files' testdata/err >/dev/null; then
+	echo "go install cgotest did not report 'no buildable Go source files'"
+	cat testdata/err
+	ok=false
+fi
+unset CGO_ENABLED
+unset GOPATH
+
+# Test that without $GOBIN set, binaries get installed
+# into the GOPATH bin directory.
+TEST install into GOPATH
+rm -rf testdata/bin
+if ! GOPATH=$(pwd)/testdata ./testgo install go-cmd-test; then
+	echo "go install go-cmd-test failed"
+	ok=false
+elif ! test -x testdata/bin/go-cmd-test; then
+	echo "go install go-cmd-test did not write to testdata/bin/go-cmd-test"
+	ok=false
+fi
+
+TEST package main_test imports archive not binary
+export GOBIN=$(pwd)/testdata/bin
+mkdir -p $GOBIN
+export GOPATH=$(pwd)/testdata
+touch ./testdata/src/main_test/m.go
+if ! ./testgo test main_test; then
+	echo "go test main_test failed without install"
+	ok=false
+elif ! ./testgo install main_test; then
+	echo "go test main_test failed"
+	ok=false
+elif [ "$(./testgo list -f '{{.Stale}}' main_test)" != false ]; then
+	echo "after go install, main listed as stale"
+	ok=false
+elif ! ./testgo test main_test; then
+	echo "go test main_test failed after install"
+	ok=false
+fi
+rm -rf $GOBIN
+unset GOBIN
+
+# And with $GOBIN set, binaries get installed to $GOBIN.
+TEST install into GOBIN
+if ! GOBIN=$(pwd)/testdata/bin1 GOPATH=$(pwd)/testdata ./testgo install go-cmd-test; then
+	echo "go install go-cmd-test failed"
+	ok=false
+elif ! test -x testdata/bin1/go-cmd-test; then
+	echo "go install go-cmd-test did not write to testdata/bin1/go-cmd-test"
+	ok=false
+fi
+
+# Without $GOBIN set, installing a program outside $GOPATH should fail
+# (there is nowhere to install it).
+TEST install without destination fails
+if ./testgo install testdata/src/go-cmd-test/helloworld.go 2>testdata/err; then
+	echo "go install testdata/src/go-cmd-test/helloworld.go should have failed, did not"
+	ok=false
+elif ! grep 'no install location for .go files listed on command line' testdata/err; then
+	echo "wrong error:"
+	cat testdata/err
+	ok=false
+fi
+rm -f testdata/err
+
+# With $GOBIN set, should install there.
+TEST install to GOBIN '(command-line package)'
+if ! GOBIN=$(pwd)/testdata/bin1 ./testgo install testdata/src/go-cmd-test/helloworld.go; then
+	echo "go install testdata/src/go-cmd-test/helloworld.go failed"
+	ok=false
+elif ! test -x testdata/bin1/helloworld; then
+	echo "go install testdata/src/go-cmd-test/helloworld.go did not write testdata/bin1/helloworld"
+	ok=false
+fi
+
+TEST godoc installs into GOBIN
+d=$(mktemp -d -t testgoXXX)
+export GOPATH=$d
+mkdir $d/gobin
+GOBIN=$d/gobin ./testgo get golang.org/x/tools/cmd/godoc || ok=false
+if [ ! -x $d/gobin/godoc ]; then
+	echo did not install godoc to '$GOBIN'
+	GOBIN=$d/gobin ./testgo list -f 'Target: {{.Target}}' golang.org/x/tools/cmd/godoc || true
+	ok=false
+fi
+
+TEST godoc installs into GOROOT
+GOROOT=$(./testgo env GOROOT)
+rm -f $GOROOT/bin/godoc
+./testgo install golang.org/x/tools/cmd/godoc || ok=false
+if [ ! -x $GOROOT/bin/godoc ]; then
+	echo did not install godoc to '$GOROOT/bin'
+	./testgo list -f 'Target: {{.Target}}' golang.org/x/tools/cmd/godoc || true
+	ok=false
+fi
+
+TEST cmd/fix installs into tool
+GOOS=$(./testgo env GOOS)
+GOARCH=$(./testgo env GOARCH)
+rm -f $GOROOT/pkg/tool/${GOOS}_${GOARCH}/fix
+./testgo install cmd/fix || ok=false
+if [ ! -x $GOROOT/pkg/tool/${GOOS}_${GOARCH}/fix ]; then
+	echo 'did not install cmd/fix to $GOROOT/pkg/tool'
+	GOBIN=$d/gobin ./testgo list -f 'Target: {{.Target}}' cmd/fix || true
+	ok=false
+fi
+rm -f $GOROOT/pkg/tool/${GOOS}_${GOARCH}/fix
+GOBIN=$d/gobin ./testgo install cmd/fix || ok=false
+if [ ! -x $GOROOT/pkg/tool/${GOOS}_${GOARCH}/fix ]; then
+	echo 'did not install cmd/fix to $GOROOT/pkg/tool with $GOBIN set'
+	GOBIN=$d/gobin ./testgo list -f 'Target: {{.Target}}' cmd/fix || true
+	ok=false
+fi
+
+TEST gopath program installs into GOBIN
+mkdir $d/src/progname
+echo 'package main; func main() {}' >$d/src/progname/p.go
+GOBIN=$d/gobin ./testgo install progname || ok=false
+if [ ! -x $d/gobin/progname ]; then
+	echo 'did not install progname to $GOBIN/progname'
+	./testgo list -f 'Target: {{.Target}}' cmd/api || true
+	ok=false
+fi
+rm -f $d/gobin/progname $d/bin/progname
+
+TEST gopath program installs into GOPATH/bin
+./testgo install progname || ok=false
+if [ ! -x $d/bin/progname ]; then
+	echo 'did not install progname to $GOPATH/bin/progname'
+	./testgo list -f 'Target: {{.Target}}' progname || true
+	ok=false
+fi
+
+unset GOPATH
+rm -rf $d
+
+# Reject relative paths in GOPATH.
+TEST reject relative paths in GOPATH '(command-line package)'
+if GOPATH=. ./testgo build testdata/src/go-cmd-test/helloworld.go; then
+    echo 'GOPATH="." go build should have failed, did not'
+    ok=false
+fi
+
+TEST reject relative paths in GOPATH 
+if GOPATH=:$(pwd)/testdata:. ./testgo build go-cmd-test; then
+    echo 'GOPATH=":$(pwd)/testdata:." go build should have failed, did not'
+    ok=false
+fi
+
+# issue 4104
+TEST go test with package listed multiple times
+if [ $(./testgo test fmt fmt fmt fmt fmt | wc -l) -ne 1 ] ; then
+    echo 'go test fmt fmt fmt fmt fmt tested the same package multiple times'
+    ok=false
+fi
+
+# ensure that output of 'go list' is consistent between runs
+TEST go list is consistent
+./testgo list std > test_std.list || ok=false
+if ! ./testgo list std | cmp -s test_std.list - ; then
+	echo "go list std ordering is inconsistent"
+	ok=false
+fi
+rm -f test_std.list
+
+# issue 4096. Validate the output of unsuccessful go install foo/quxx 
+TEST unsuccessful go install should mention missing package
+if [ $(./testgo install 'foo/quxx' 2>&1 | grep -c 'cannot find package "foo/quxx" in any of') -ne 1 ] ; then
+	echo 'go install foo/quxx expected error: .*cannot find package "foo/quxx" in any of'
+	ok=false
+fi 
+# test GOROOT search failure is reported
+TEST GOROOT search failure reporting
+if [ $(./testgo install 'foo/quxx' 2>&1 | egrep -c 'foo/quxx \(from \$GOROOT\)$') -ne 1 ] ; then
+        echo 'go install foo/quxx expected error: .*foo/quxx (from $GOROOT)'
+        ok=false
+fi
+# test multiple GOPATH entries are reported separately
+TEST multiple GOPATH entries reported separately
+if [ $(GOPATH=$(pwd)/testdata/a:$(pwd)/testdata/b ./testgo install 'foo/quxx' 2>&1 | egrep -c 'testdata/./src/foo/quxx') -ne 2 ] ; then
+        echo 'go install foo/quxx expected error: .*testdata/a/src/foo/quxx (from $GOPATH)\n.*testdata/b/src/foo/quxx'
+        ok=false
+fi
+# test (from $GOPATH) annotation is reported for the first GOPATH entry
+TEST mention GOPATH in first GOPATH entry
+if [ $(GOPATH=$(pwd)/testdata/a:$(pwd)/testdata/b ./testgo install 'foo/quxx' 2>&1 | egrep -c 'testdata/a/src/foo/quxx \(from \$GOPATH\)$') -ne 1 ] ; then
+        echo 'go install foo/quxx expected error: .*testdata/a/src/foo/quxx (from $GOPATH)'
+        ok=false
+fi
+# but not on the second
+TEST but not the second entry
+if [ $(GOPATH=$(pwd)/testdata/a:$(pwd)/testdata/b ./testgo install 'foo/quxx' 2>&1 | egrep -c 'testdata/b/src/foo/quxx$') -ne 1 ] ; then
+        echo 'go install foo/quxx expected error: .*testdata/b/src/foo/quxx'
+        ok=false
+fi
+# test missing GOPATH is reported
+TEST missing GOPATH is reported
+if [ $(GOPATH= ./testgo install 'foo/quxx' 2>&1 | egrep -c '\(\$GOPATH not set\)$') -ne 1 ] ; then
+        echo 'go install foo/quxx expected error: ($GOPATH not set)'
+        ok=false
+fi
+
+# issue 4186. go get cannot be used to download packages to $GOROOT
+# Test that without GOPATH set, go get should fail
+TEST without GOPATH, go get fails
+d=$(mktemp -d -t testgoXXX)
+mkdir -p $d/src
+if GOPATH= GOROOT=$d ./testgo get -d golang.org/x/codereview/cmd/hgpatch ; then 
+	echo 'go get golang.org/x/codereview/cmd/hgpatch should not succeed with $GOPATH unset'
+	ok=false
+fi	
+rm -rf $d
+
+# Test that with GOPATH=$GOROOT, go get should fail
+TEST with GOPATH=GOROOT, go get fails
+d=$(mktemp -d -t testgoXXX)
+mkdir -p $d/src
+if GOPATH=$d GOROOT=$d ./testgo get -d golang.org/x/codereview/cmd/hgpatch ; then
+        echo 'go get golang.org/x/codereview/cmd/hgpatch should not succeed with GOPATH=$GOROOT'
+        ok=false
+fi
+rm -rf $d
+
+TEST ldflags arguments with spaces '(issue 3941)'
+d=$(mktemp -d -t testgoXXX)
+cat >$d/main.go<<EOF
+package main
+var extern string
+func main() {
+	println(extern)
+}
+EOF
+./testgo run -ldflags '-X main.extern "hello world"' $d/main.go 2>hello.out || ok=false
+if ! grep -q '^hello world' hello.out; then
+	echo "ldflags -X main.extern 'hello world' failed. Output:"
+	cat hello.out
+	ok=false
+fi
+rm -rf $d hello.out
+
+TEST go test -cpuprofile leaves binary behind
+./testgo test -cpuprofile strings.prof strings || ok=false
+if [ ! -x strings.test ]; then
+	echo "go test -cpuprofile did not create strings.test"
+	ok=false
+fi
+rm -f strings.prof strings.test
+
+TEST go test -cpuprofile -o controls binary location
+./testgo test -cpuprofile strings.prof -o mystrings.test strings || ok=false
+if [ ! -x mystrings.test ]; then
+	echo "go test -cpuprofile -o mystrings.test did not create mystrings.test"
+	ok=false
+fi
+rm -f strings.prof mystrings.test
+
+TEST go test -c -o controls binary location
+./testgo test -c -o mystrings.test strings || ok=false
+if [ ! -x mystrings.test ]; then
+	echo "go test -c -o mystrings.test did not create mystrings.test"
+	ok=false
+fi
+rm -f mystrings.test
+
+TEST go test -o writes binary
+./testgo test -o mystrings.test strings || ok=false
+if [ ! -x mystrings.test ]; then
+	echo "go test -o mystrings.test did not create mystrings.test"
+	ok=false
+fi
+rm -f mystrings.test
+
+TEST symlinks do not confuse go list '(issue 4568)'
+old=$(pwd)
+tmp=$(cd /tmp && pwd -P)
+d=$(TMPDIR=$tmp mktemp -d -t testgoXXX)
+mkdir -p $d/src
+(
+	ln -s $d $d/src/dir1
+	cd $d/src
+	echo package p >dir1/p.go
+	export GOPATH=$d
+	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
+		$old/testgo list -json . dir1
+		touch $d/failed
+	fi		
+)
+if [ -f $d/failed ]; then
+	ok=false
+fi
+rm -rf $d
+
+TEST 'install with tags (issue 4515)'
+d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
+mkdir -p $d/src/example/a $d/src/example/b $d/bin
+cat >$d/src/example/a/main.go <<EOF
+package main
+func main() {}
+EOF
+cat >$d/src/example/b/main.go <<EOF
+// +build mytag
+
+package main
+func main() {}
+EOF
+GOPATH=$d ./testgo install -tags mytag example/a example/b || ok=false
+if [ ! -x $d/bin/a -o ! -x $d/bin/b ]; then
+	echo go install example/a example/b did not install binaries
+	ok=false
+fi
+rm -f $d/bin/*
+GOPATH=$d ./testgo install -tags mytag example/... || ok=false
+if [ ! -x $d/bin/a -o ! -x $d/bin/b ]; then
+	echo go install example/... did not install binaries
+	ok=false
+fi
+rm -f $d/bin/*go
+export GOPATH=$d
+if [ "$(./testgo list -tags mytag example/b...)" != "example/b" ]; then
+	echo go list example/b did not find example/b
+	ok=false
+fi
+unset GOPATH
+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/pkg,a/Pkg,b}
+cat >$d/src/example/a/a.go <<EOF
+package p
+import (
+	_ "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
+elif ! grep "case-insensitive import collision" $d/out >/dev/null; then
+	echo go list example/a did not report import collision.
+	ok=false
+fi
+cat >$d/src/example/b/file.go <<EOF
+package b
+EOF
+cat >$d/src/example/b/FILE.go <<EOF
+package b
+EOF
+if [ $(ls $d/src/example/b | wc -l) = 2 ]; then
+	# case-sensitive file system, let directory read find both files
+	args="example/b"
+else
+	# case-insensitive file system, list files explicitly on command line.
+	args="$d/src/example/b/file.go $d/src/example/b/FILE.go"
+fi
+if ./testgo list $args 2>$d/out; then
+	echo go list example/b should have failed, did not.
+	ok=false
+elif ! grep "case-insensitive file name collision" $d/out >/dev/null; then
+	echo go list example/b did not report file name collision.
+	ok=false
+fi
+
+TEST go get cover
+./testgo get golang.org/x/tools/cmd/cover || ok=false
+
+unset GOPATH
+rm -rf $d
+
+TEST go get -t "code.google.com/p/go-get-issue-8181/{a,b}"
+d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
+export GOPATH=$d
+if ./testgo get -t code.google.com/p/go-get-issue-8181/{a,b}; then
+	./testgo list ... | grep go.tools/godoc > /dev/null || ok=false
+else
+	ok=false
+fi
+unset GOPATH
+rm -rf $d
+
+TEST shadowing logic
+export GOPATH=$(pwd)/testdata/shadow/root1:$(pwd)/testdata/shadow/root2
+
+# The math in root1 is not "math" because the standard math is.
+set +e
+cdir=$(./testgo list -f '({{.ImportPath}}) ({{.ConflictDir}})' ./testdata/shadow/root1/src/math)
+set -e
+if [ "$cdir" != "(_$(pwd)/testdata/shadow/root1/src/math) ($GOROOT/src/math)" ]; then
+	echo shadowed math is not shadowed: "$cdir"
+	ok=false
+fi
+
+# The foo in root1 is "foo".
+set +e
+cdir=$(./testgo list -f '({{.ImportPath}}) ({{.ConflictDir}})' ./testdata/shadow/root1/src/foo)
+set -e
+if [ "$cdir" != "(foo) ()" ]; then
+	echo unshadowed foo is shadowed: "$cdir"
+	ok=false
+fi
+
+# The foo in root2 is not "foo" because the foo in root1 got there first.
+set +e
+cdir=$(./testgo list -f '({{.ImportPath}}) ({{.ConflictDir}})' ./testdata/shadow/root2/src/foo)
+set -e
+if [ "$cdir" != "(_$(pwd)/testdata/shadow/root2/src/foo) ($(pwd)/testdata/shadow/root1/src/foo)" ]; then
+	echo shadowed foo is not shadowed: "$cdir"
+	ok=false
+fi
+
+# The error for go install should mention the conflicting directory.
+set +e
+err=$(./testgo install ./testdata/shadow/root2/src/foo 2>&1)
+set -e
+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
+
+# Only succeeds if source order is preserved.
+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 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 >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
+d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
+export GOPATH=$d
+mkdir -p $d/src/foo
+echo '
+package foo
+//#include <stdio.h>
+import "C"
+' >$d/src/foo/foo.go
+./testgo build -race foo || ok=false
+rm -rf $d
+unset GOPATH
+
+TEST cgo shows full path names
+d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
+export GOPATH=$d
+mkdir -p $d/src/x/y/dirname
+echo '
+package foo
+import "C"
+func f() {
+' >$d/src/x/y/dirname/foo.go
+if ./testgo build x/y/dirname >$d/err 2>&1; then
+	echo build succeeded unexpectedly.
+	ok=false
+elif ! grep x/y/dirname $d/err >/dev/null; then
+	echo error did not use full path.
+	cat $d/err
+	ok=false
+fi
+rm -rf $d
+unset GOPATH
+
+TEST 'cgo handles -Wl,$ORIGIN'
+d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
+export GOPATH=$d
+mkdir -p $d/src/origin
+echo '
+package origin
+// #cgo !darwin LDFLAGS: -Wl,-rpath -Wl,$ORIGIN
+// void f(void) {}
+import "C"
+
+func f() { C.f() }
+' >$d/src/origin/origin.go
+if ! ./testgo build origin; then
+	echo build failed
+	ok=false
+fi
+rm -rf $d
+unset GOPATH
+
+TEST 'Issue 6480: "go test -c -test.bench=XXX fmt" should not hang'
+if ! ./testgo test -c -test.bench=XXX fmt; then
+	echo build test failed
+	ok=false
+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
+checkbar() {
+	desc="$1"
+	sleep 1
+	touch $d/src/x/y/foo/foo.go
+	if ! ./testgo build -v -i x/y/bar &> $d/err; then
+		echo build -i "$1" failed
+		cat $d/err
+		ok=false
+	elif ! grep x/y/foo $d/err >/dev/null; then
+		echo first build -i "$1" 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 "$1" failed
+		cat $d/err
+		ok=false
+	elif grep x/y/foo $d/err >/dev/null; then
+		echo second build -i "$1" built x/y/foo
+		cat $d/err
+		ok=false
+	fi
+}
+
+echo '
+package bar
+import "x/y/foo"
+func F() { foo.F() }
+' >$d/src/x/y/bar/bar.go
+checkbar pkg
+
+TEST build -i installs dependencies for command
+echo '
+package main
+import "x/y/foo"
+func main() { foo.F() }
+' >$d/src/x/y/bar/bar.go
+checkbar cmd
+
+rm -rf $d bar
+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 || ok=false
+if ! ./testgo test xtestonly >/dev/null; then
+	echo "go test xtestonly failed"
+	ok=false
+fi
+unset GOPATH
+
+TEST 'go test builds an xtest containing only non-runnable examples'
+if ! ./testgo test -v ./testdata/norunexample > testdata/std.out; then
+	echo "go test ./testdata/norunexample failed"
+	ok=false
+elif ! grep 'File with non-runnable example was built.' testdata/std.out > /dev/null; then
+	echo "file with non-runnable example was not built"
+	ok=false
+fi
+
+TEST 'go generate handles simple command'
+if ! ./testgo generate ./testdata/generate/test1.go > testdata/std.out; then
+	echo "go test ./testdata/generate/test1.go failed to run"
+	ok=false
+elif ! grep 'Success' testdata/std.out > /dev/null; then
+	echo "go test ./testdata/generate/test1.go generated wrong output"
+	ok=false
+fi
+
+TEST 'go generate handles command alias'
+if ! ./testgo generate ./testdata/generate/test2.go > testdata/std.out; then
+	echo "go test ./testdata/generate/test2.go failed to run"
+	ok=false
+elif ! grep 'Now is the time for all good men' testdata/std.out > /dev/null; then
+	echo "go test ./testdata/generate/test2.go generated wrong output"
+	ok=false
+fi
+
+TEST 'go generate variable substitution'
+if ! ./testgo generate ./testdata/generate/test3.go > testdata/std.out; then
+	echo "go test ./testdata/generate/test3.go failed to run"
+	ok=false
+elif ! grep "$GOARCH test3.go p xyzp/test3.go/123" testdata/std.out > /dev/null; then
+	echo "go test ./testdata/generate/test3.go generated wrong output"
+	ok=false
+fi
+
+TEST go get works with vanity wildcards
+d=$(mktemp -d -t testgoXXX)
+export GOPATH=$d
+if ! ./testgo get -u rsc.io/pdf/...; then
+	ok=false
+elif [ ! -x $d/bin/pdfpasswd ]; then
+	echo did not build rsc.io/pdf/pdfpasswd
+	ok=false
+fi
+unset GOPATH
+rm -rf $d
+
+TEST go vet with external tests
+d=$(mktemp -d -t testgoXXX)
+export GOPATH=$(pwd)/testdata
+if ./testgo vet vetpkg >$d/err 2>&1; then
+	echo "go vet vetpkg passes incorrectly"
+	ok=false
+elif ! grep -q 'missing argument for Printf' $d/err; then
+	echo "go vet vetpkg did not find missing argument for Printf"
+	cat $d/err
+	ok=false
+fi
+unset GOPATH
+rm -rf $d
+
+# clean up
+if $started; then stop; fi
+rm -rf testdata/bin testdata/bin1
+rm -f testgo
+
+if $allok; then
+	echo PASS
+else
+	echo FAIL:
+	echo "$testfail"
+	exit 1
+fi
diff --git a/src/cmd/go/test.go b/src/cmd/go/test.go
index ba1ab82..c81e406 100644
--- a/src/cmd/go/test.go
+++ b/src/cmd/go/test.go
@@ -33,11 +33,9 @@ func init() {
 	cmdTest.Run = runTest
 }
 
-const testUsage = "test [-c] [-i] [build and test flags] [packages] [flags for test binary]"
-
 var cmdTest = &Command{
 	CustomFlags: true,
-	UsageLine:   testUsage,
+	UsageLine:   "test [-c] [-i] [build and test flags] [packages] [flags for test binary]",
 	Short:       "test packages",
 	Long: `
 'Go test' automates testing the packages named by the import paths.
@@ -66,21 +64,6 @@ with source in the current directory, including tests, and runs the tests.
 The package is built in a temporary directory so it does not interfere with the
 non-test installation.
 
-` + strings.TrimSpace(testFlag1) + ` See 'go help testflag' for details.
-
-If the test binary needs any other flags, they should be presented after the
-package names. The go tool treats as a flag the first argument that begins with
-a minus sign that it does not recognize itself; that argument and all subsequent
-arguments are passed as arguments to the test binary.
-
-For more about build flags, see 'go help build'.
-For more about specifying packages, see 'go help packages'.
-
-See also: go build, go vet.
-`,
-}
-
-const testFlag1 = `
 In addition to the build flags, the flags handled by 'go test' itself are:
 
 	-c
@@ -100,9 +83,21 @@ In addition to the build flags, the flags handled by 'go test' itself are:
 		Compile the test binary to the named file.
 		The test still runs (unless -c or -i is specified).
 
+
 The test binary also accepts flags that control execution of the test; these
-flags are also accessible by 'go test'.
-`
+flags are also accessible by 'go test'.  See 'go help testflag' for details.
+
+If the test binary needs any other flags, they should be presented after the
+package names. The go tool treats as a flag the first argument that begins with
+a minus sign that it does not recognize itself; that argument and all subsequent
+arguments are passed as arguments to the test binary.
+
+For more about build flags, see 'go help build'.
+For more about specifying packages, see 'go help packages'.
+
+See also: go build, go vet.
+`,
+}
 
 var helpTestflag = &Command{
 	UsageLine: "testflag",
@@ -112,18 +107,13 @@ The 'go test' command takes both flags that apply to 'go test' itself
 and flags that apply to the resulting test binary.
 
 Several of the flags control profiling and write an execution profile
-suitable for "go tool pprof"; run "go tool pprof -h" for more
+suitable for "go tool pprof"; run "go tool pprof help" for more
 information.  The --alloc_space, --alloc_objects, and --show_bytes
 options of pprof control how the information is presented.
 
 The following flags are recognized by the 'go test' command and
 control the execution of any test:
 
-	` + strings.TrimSpace(testFlag2) + `
-`,
-}
-
-const testFlag2 = `
 	-bench regexp
 	    Run benchmarks matching the regular expression.
 	    By default, no benchmarks run. To run all benchmarks,
@@ -145,17 +135,12 @@ const testFlag2 = `
 	-blockprofilerate n
 	    Control the detail provided in goroutine blocking profiles by
 	    calling runtime.SetBlockProfileRate with n.
-	    See 'go doc runtime.SetBlockProfileRate'.
+	    See 'godoc runtime SetBlockProfileRate'.
 	    The profiler aims to sample, on average, one blocking event every
 	    n nanoseconds the program spends blocked.  By default,
 	    if -test.blockprofile is set without this flag, all blocking events
 	    are recorded, equivalent to -test.blockprofilerate=1.
 
-	-count n
-	    Run each test and benchmark n times (default 1).
-	    If -cpu is set, run n times for each GOMAXPROCS value.
-	    Examples are always run once.
-
 	-cover
 	    Enable coverage analysis.
 
@@ -195,7 +180,7 @@ const testFlag2 = `
 
 	-memprofilerate n
 	    Enable more precise (and expensive) memory profiles by setting
-	    runtime.MemProfileRate.  See 'go doc runtime.MemProfileRate'.
+	    runtime.MemProfileRate.  See 'godoc runtime MemProfileRate'.
 	    To profile all memory allocations, use -test.memprofilerate=1
 	    and pass --alloc_space flag to the pprof tool.
 
@@ -220,11 +205,6 @@ const testFlag2 = `
 
 	-timeout t
 	    If a test runs longer than t, panic.
-	    The default is 10 minutes (10m).
-
-	-trace trace.out
-	    Write an execution trace to the specified file before exiting.
-	    Writes test binary as -c would.
 
 	-v
 	    Verbose output: log all tests as they are run. Also print all
@@ -249,7 +229,8 @@ The test flags that generate profiles (other than for coverage) also
 leave the test binary in pkg.test for use when analyzing the profiles.
 
 Flags not recognized by 'go test' must be placed after any specified packages.
-`
+`,
+}
 
 var helpTestfunc = &Command{
 	UsageLine: "testfunc",
@@ -329,7 +310,6 @@ func runTest(cmd *Command, args []string) {
 	findExecCmd() // initialize cached result
 
 	raceInit()
-	buildModeInit()
 	pkgs := packagesForBuild(pkgArgs)
 	if len(pkgs) == 0 {
 		fatalf("no packages to test")
@@ -362,11 +342,11 @@ func runTest(cmd *Command, args []string) {
 	// been given on the command line (implicit current directory)
 	// or when benchmarking.
 	// Also stream if we're showing output anyway with a
-	// single package under test or if parallelism is set to 1.
-	// In these cases, streaming the output produces the same result
-	// as not streaming, just more immediately.
+	// single package under test.  In that case, streaming the
+	// output produces the same result as not streaming,
+	// just more immediately.
 	testStreamOutput = len(pkgArgs) == 0 || testBench ||
-		(testShowPass && (len(pkgs) == 1 || buildP == 1))
+		(len(pkgs) <= 1 && testShowPass)
 
 	var b builder
 	b.init()
@@ -384,10 +364,10 @@ func runTest(cmd *Command, args []string) {
 			for _, path := range p.Imports {
 				deps[path] = true
 			}
-			for _, path := range p.vendored(p.TestImports) {
+			for _, path := range p.TestImports {
 				deps[path] = true
 			}
-			for _, path := range p.vendored(p.XTestImports) {
+			for _, path := range p.XTestImports {
 				deps[path] = true
 			}
 		}
@@ -396,7 +376,7 @@ func runTest(cmd *Command, args []string) {
 		if deps["C"] {
 			delete(deps, "C")
 			deps["runtime/cgo"] = true
-			if goos == runtime.GOOS && goarch == runtime.GOARCH && !buildRace {
+			if buildContext.GOOS == runtime.GOOS && buildContext.GOARCH == runtime.GOARCH {
 				deps["cmd/cgo"] = true
 			}
 		}
@@ -445,10 +425,6 @@ func runTest(cmd *Command, args []string) {
 
 		// Mark all the coverage packages for rebuilding with coverage.
 		for _, p := range testCoverPkgs {
-			// There is nothing to cover in package unsafe; it comes from the compiler.
-			if p.ImportPath == "unsafe" {
-				continue
-			}
 			p.Stale = true // rebuild
 			p.fake = true  // do not warn about rebuild
 			p.coverMode = testCoverMode
@@ -583,17 +559,12 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
 	var imports, ximports []*Package
 	var stk importStack
 	stk.push(p.ImportPath + " (test)")
-	for i, path := range p.TestImports {
-		p1 := loadImport(path, p.Dir, p, &stk, p.build.TestImportPos[path], useVendor)
+	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 len(p1.DepsErrors) > 0 {
-			err := p1.DepsErrors[0]
-			err.Pos = "" // show full import stack
-			return nil, nil, nil, err
-		}
-		if contains(p1.Deps, p.ImportPath) || p1.ImportPath == p.ImportPath {
+		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.
@@ -604,28 +575,21 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
 			}
 			return nil, nil, nil, err
 		}
-		p.TestImports[i] = p1.ImportPath
 		imports = append(imports, p1)
 	}
 	stk.pop()
 	stk.push(p.ImportPath + "_test")
 	pxtestNeedsPtest := false
-	for i, path := range p.XTestImports {
-		p1 := loadImport(path, p.Dir, p, &stk, p.build.XTestImportPos[path], useVendor)
+	for _, path := range p.XTestImports {
+		if path == p.ImportPath {
+			pxtestNeedsPtest = true
+			continue
+		}
+		p1 := loadImport(path, p.Dir, &stk, p.build.XTestImportPos[path])
 		if p1.Error != nil {
 			return nil, nil, nil, p1.Error
 		}
-		if len(p1.DepsErrors) > 0 {
-			err := p1.DepsErrors[0]
-			err.Pos = "" // show full import stack
-			return nil, nil, nil, err
-		}
-		if p1.ImportPath == p.ImportPath {
-			pxtestNeedsPtest = true
-		} else {
-			ximports = append(ximports, p1)
-		}
-		p.XTestImports[i] = p1.ImportPath
+		ximports = append(ximports, p1)
 	}
 	stk.pop()
 
@@ -719,11 +683,10 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
 			build: &build.Package{
 				ImportPos: p.build.XTestImportPos,
 			},
-			imports:  ximports,
-			pkgdir:   testDir,
-			fake:     true,
-			external: true,
-			Stale:    true,
+			imports: ximports,
+			pkgdir:  testDir,
+			fake:    true,
+			Stale:   true,
 		}
 		if pxtestNeedsPtest {
 			pxtest.imports = append(pxtest.imports, ptest)
@@ -750,7 +713,7 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
 		if dep == ptest.ImportPath {
 			pmain.imports = append(pmain.imports, ptest)
 		} else {
-			p1 := loadImport(dep, "", nil, &stk, nil, 0)
+			p1 := loadImport(dep, "", &stk, nil)
 			if p1.Error != nil {
 				return nil, nil, nil, p1.Error
 			}
@@ -805,12 +768,6 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
 		recompileForTest(pmain, p, ptest, testDir)
 	}
 
-	if buildContext.GOOS == "darwin" {
-		if buildContext.GOARCH == "arm" || buildContext.GOARCH == "arm64" {
-			t.NeedCgo = true
-		}
-	}
-
 	for _, cp := range pmain.imports {
 		if len(cp.coverVars) > 0 {
 			t.Cover = append(t.Cover, coverInfo{cp, cp.coverVars})
@@ -1027,7 +984,7 @@ func (b *builder) runTest(a *action) error {
 
 	cmd := exec.Command(args[0], args[1:]...)
 	cmd.Dir = a.p.Dir
-	cmd.Env = envForDir(cmd.Dir, origEnv)
+	cmd.Env = envForDir(cmd.Dir)
 	var buf bytes.Buffer
 	if testStreamOutput {
 		cmd.Stdout = os.Stdout
@@ -1246,7 +1203,6 @@ type testFuncs struct {
 	NeedTest    bool
 	ImportXtest bool
 	NeedXtest   bool
-	NeedCgo     bool
 	Cover       []coverInfo
 }
 
@@ -1350,10 +1306,6 @@ import (
 {{range $i, $p := .Cover}}
 	_cover{{$i}} {{$p.Package.ImportPath | printf "%q"}}
 {{end}}
-
-{{if .NeedCgo}}
-	_ "runtime/cgo"
-{{end}}
 )
 
 var tests = []testing.InternalTest{
diff --git a/src/cmd/go/testdata/generate/test3.go b/src/cmd/go/testdata/generate/test3.go
index 3d6a8a5..41ffb7e 100644
--- a/src/cmd/go/testdata/generate/test3.go
+++ b/src/cmd/go/testdata/generate/test3.go
@@ -4,6 +4,6 @@
 
 // Test go generate variable substitution.
 
-//go:generate echo $GOARCH $GOFILE:$GOLINE ${GOPACKAGE}abc xyz$GOPACKAGE/$GOFILE/123
+//go:generate echo $GOARCH $GOFILE $GOPACKAGE xyz$GOPACKAGE/$GOFILE/123
 
 package p
diff --git a/src/cmd/go/testflag.go b/src/cmd/go/testflag.go
index 1f3e3d3..6da74b9 100644
--- a/src/cmd/go/testflag.go
+++ b/src/cmd/go/testflag.go
@@ -5,7 +5,6 @@
 package main
 
 import (
-	"flag"
 	"fmt"
 	"os"
 	"strconv"
@@ -17,11 +16,46 @@ import (
 // our command line are for us, and some are for 6.out, and
 // some are for both.
 
+var usageMessage = `Usage of go test:
+  -c=false: compile but do not run the test binary
+  -file=file_test.go: specify file to use for tests;
+      use multiple times for multiple files
+  -p=n: build and test up to n packages in parallel
+  -x=false: print command lines as they are executed
+
+  // These flags can be passed with or without a "test." prefix: -v or -test.v.
+  -bench="": passes -test.bench to test
+  -benchmem=false: print memory allocation statistics for benchmarks
+  -benchtime=1s: passes -test.benchtime to test
+  -cover=false: enable coverage analysis
+  -covermode="set": specifies mode for coverage analysis
+  -coverpkg="": comma-separated list of packages for coverage analysis
+  -coverprofile="": passes -test.coverprofile to test if -cover
+  -cpu="": passes -test.cpu to test
+  -cpuprofile="": passes -test.cpuprofile to test
+  -memprofile="": passes -test.memprofile to test
+  -memprofilerate=0: passes -test.memprofilerate to test
+  -blockprofile="": pases -test.blockprofile to test
+  -blockprofilerate=0: passes -test.blockprofilerate to test
+  -outputdir=$PWD: passes -test.outputdir to test
+  -parallel=0: passes -test.parallel to test
+  -run="": passes -test.run to test
+  -short=false: passes -test.short to test
+  -timeout=0: passes -test.timeout to test
+  -v=false: passes -test.v to test
+`
+
+// usage prints a usage message and exits.
+func testUsage() {
+	fmt.Fprint(os.Stderr, usageMessage)
+	setExitStatus(2)
+	exit()
+}
+
 // testFlagSpec defines a flag we know about.
 type testFlagSpec struct {
 	name       string
 	boolVar    *bool
-	flagValue  flag.Value
 	passToTest bool // pass to Test
 	multiOK    bool // OK to have multiple instances
 	present    bool // flag has been seen
@@ -31,18 +65,32 @@ type testFlagSpec struct {
 var testFlagDefn = []*testFlagSpec{
 	// local.
 	{name: "c", boolVar: &testC},
-	{name: "i", boolVar: &buildI},
-	{name: "o"},
 	{name: "cover", boolVar: &testCover},
-	{name: "covermode"},
 	{name: "coverpkg"},
+	{name: "o"},
+
+	// build flags.
+	{name: "a", boolVar: &buildA},
+	{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"},
+	{name: "compiler"},
+	{name: "race", boolVar: &buildRace},
+	{name: "installsuffix"},
 
 	// passed to 6.out, adding a "test." prefix to the name if necessary: -v becomes -test.v.
 	{name: "bench", passToTest: true},
 	{name: "benchmem", boolVar: new(bool), passToTest: true},
 	{name: "benchtime", passToTest: true},
-	{name: "count", passToTest: true},
+	{name: "covermode"},
 	{name: "coverprofile", passToTest: true},
 	{name: "cpu", passToTest: true},
 	{name: "cpuprofile", passToTest: true},
@@ -55,26 +103,9 @@ var testFlagDefn = []*testFlagSpec{
 	{name: "run", passToTest: true},
 	{name: "short", boolVar: new(bool), passToTest: true},
 	{name: "timeout", passToTest: true},
-	{name: "trace", passToTest: true},
 	{name: "v", boolVar: &testV, passToTest: true},
 }
 
-// add build flags to testFlagDefn
-func init() {
-	var cmd Command
-	addBuildFlags(&cmd)
-	cmd.Flag.VisitAll(func(f *flag.Flag) {
-		if f.Name == "v" {
-			// test overrides the build -v flag
-			return
-		}
-		testFlagDefn = append(testFlagDefn, &testFlagSpec{
-			name:      f.Name,
-			flagValue: f.Value,
-		})
-	})
-}
-
 // testFlags processes the command line, grabbing -x and -c, rewriting known flags
 // to have "test" before them, and reading the command line for the 6.out.
 // Unfortunately for us, we need to do our own flag processing because go test
@@ -117,55 +148,73 @@ func testFlags(args []string) (packageNames, passToTest []string) {
 			passToTest = append(passToTest, args[i])
 			continue
 		}
-		if f.flagValue != nil {
-			if err := f.flagValue.Set(value); err != nil {
+		var err error
+		switch f.name {
+		// bool flags.
+		case "a", "c", "i", "n", "x", "v", "race", "cover", "work":
+			setBoolFlag(f.boolVar, value)
+		case "o":
+			testO = value
+			testNeedBinary = true
+		case "p":
+			setIntFlag(&buildP, value)
+		case "exec":
+			execCmd, err = splitQuotedFields(value)
+			if err != nil {
 				fatalf("invalid flag argument for -%s: %v", f.name, err)
 			}
-		} else {
-			// Test-only flags.
-			// Arguably should be handled by f.flagValue, but aren't.
-			var err error
-			switch f.name {
-			// bool flags.
-			case "c", "i", "v", "cover":
-				setBoolFlag(f.boolVar, value)
-			case "o":
-				testO = value
-				testNeedBinary = true
-			case "exec":
-				execCmd, err = splitQuotedFields(value)
-				if err != nil {
-					fatalf("invalid flag argument for -%s: %v", f.name, err)
-				}
-			case "bench":
-				// record that we saw the flag; don't care about the value
-				testBench = true
-			case "timeout":
-				testTimeout = value
-			case "blockprofile", "cpuprofile", "memprofile", "trace":
-				testProfile = true
-				testNeedBinary = true
-			case "coverpkg":
-				testCover = true
-				if value == "" {
-					testCoverPaths = nil
-				} else {
-					testCoverPaths = strings.Split(value, ",")
-				}
-			case "coverprofile":
-				testCover = true
-				testProfile = true
-			case "covermode":
-				switch value {
-				case "set", "count", "atomic":
-					testCoverMode = value
-				default:
-					fatalf("invalid flag argument for -covermode: %q", value)
-				}
-				testCover = true
-			case "outputdir":
-				outputDir = value
+		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 {
+				fatalf("invalid flag argument for -%s: %v", f.name, err)
+			}
+		case "ldflags":
+			buildLdflags, err = splitQuotedFields(value)
+			if err != nil {
+				fatalf("invalid flag argument for -%s: %v", f.name, err)
 			}
+		case "gccgoflags":
+			buildGccgoflags, err = splitQuotedFields(value)
+			if err != nil {
+				fatalf("invalid flag argument for -%s: %v", f.name, err)
+			}
+		case "tags":
+			buildContext.BuildTags = strings.Fields(value)
+		case "compiler":
+			buildCompiler{}.Set(value)
+		case "bench":
+			// record that we saw the flag; don't care about the value
+			testBench = true
+		case "timeout":
+			testTimeout = value
+		case "blockprofile", "cpuprofile", "memprofile":
+			testProfile = true
+			testNeedBinary = true
+		case "coverpkg":
+			testCover = true
+			if value == "" {
+				testCoverPaths = nil
+			} else {
+				testCoverPaths = strings.Split(value, ",")
+			}
+		case "coverprofile":
+			testCover = true
+			testProfile = true
+		case "covermode":
+			switch value {
+			case "set", "count", "atomic":
+				testCoverMode = value
+			default:
+				fatalf("invalid flag argument for -cover: %q", value)
+			}
+			testCover = true
+		case "outputdir":
+			outputDir = value
 		}
 		if extraWord {
 			i++
@@ -218,7 +267,7 @@ func testFlag(args []string, i int) (f *testFlagSpec, value string, extra bool)
 	for _, f = range testFlagDefn {
 		if name == f.name {
 			// Booleans are special because they have modes -x, -x=true, -x=false.
-			if f.boolVar != nil || isBoolFlag(f.flagValue) {
+			if f.boolVar != nil {
 				if equals < 0 { // otherwise, it's been set and will be verified in setBoolFlag
 					value = "true"
 				} else {
@@ -245,17 +294,6 @@ func testFlag(args []string, i int) (f *testFlagSpec, value string, extra bool)
 	return
 }
 
-// isBoolFlag reports whether v is a bool flag.
-func isBoolFlag(v flag.Value) bool {
-	vv, ok := v.(interface {
-		IsBoolFlag() bool
-	})
-	if ok {
-		return vv.IsBoolFlag()
-	}
-	return false
-}
-
 // setBoolFlag sets the addressed boolean to the value.
 func setBoolFlag(flag *bool, value string) {
 	x, err := strconv.ParseBool(value)
diff --git a/src/cmd/go/tool.go b/src/cmd/go/tool.go
index 937ca1f..3f11c3e 100644
--- a/src/cmd/go/tool.go
+++ b/src/cmd/go/tool.go
@@ -50,9 +50,6 @@ func tool(toolName string) string {
 	if toolIsWindows {
 		toolPath += toolWindowsExtension
 	}
-	if len(buildToolExec) > 0 {
-		return toolPath
-	}
 	// Give a nice message if there is no tool with that name.
 	if _, err := os.Stat(toolPath); err != nil {
 		if isInGoToolsRepo(toolName) {
@@ -67,6 +64,10 @@ func tool(toolName string) string {
 }
 
 func isInGoToolsRepo(toolName string) bool {
+	switch toolName {
+	case "cover", "vet":
+		return true
+	}
 	return false
 }
 
@@ -91,11 +92,7 @@ func runTool(cmd *Command, args []string) {
 		return
 	}
 	if toolN {
-		cmd := toolPath
-		if len(args) > 1 {
-			cmd += " " + strings.Join(args[1:], " ")
-		}
-		fmt.Printf("%s\n", cmd)
+		fmt.Printf("%s %s\n", toolPath, strings.Join(args[1:], " "))
 		return
 	}
 	toolCmd := &exec.Cmd{
@@ -104,8 +101,6 @@ func runTool(cmd *Command, args []string) {
 		Stdin:  os.Stdin,
 		Stdout: os.Stdout,
 		Stderr: os.Stderr,
-		// Set $GOROOT, mainly for go tool dist.
-		Env: mergeEnvLists([]string{"GOROOT=" + goroot}, os.Environ()),
 	}
 	err := toolCmd.Run()
 	if err != nil {
diff --git a/src/cmd/go/vcs.go b/src/cmd/go/vcs.go
index 28a7540..1cac613 100644
--- a/src/cmd/go/vcs.go
+++ b/src/cmd/go/vcs.go
@@ -9,15 +9,12 @@ import (
 	"encoding/json"
 	"errors"
 	"fmt"
-	"internal/singleflight"
 	"log"
-	"net/url"
 	"os"
 	"os/exec"
 	"path/filepath"
 	"regexp"
 	"strings"
-	"sync"
 )
 
 // A vcsCmd describes how to use a version control system
@@ -26,13 +23,13 @@ type vcsCmd struct {
 	name string
 	cmd  string // name of binary to invoke command
 
-	createCmd   []string // commands to download a fresh copy of a repository
-	downloadCmd []string // commands to download updates into an existing repository
+	createCmd   string // command to download a fresh copy of a repository
+	downloadCmd string // command to download updates into an existing repository
 
 	tagCmd         []tagCmd // commands to list tags
 	tagLookupCmd   []tagCmd // commands to lookup tags before running tagSyncCmd
-	tagSyncCmd     []string // commands to sync to specific tag
-	tagSyncDefault []string // commands to sync to default tag
+	tagSyncCmd     string   // command to sync to specific tag
+	tagSyncDefault string   // command to sync to default tag
 
 	scheme  []string
 	pingCmd string
@@ -41,23 +38,6 @@ type vcsCmd struct {
 	resolveRepo func(v *vcsCmd, rootDir, remoteRepo string) (realRepo string, err error)
 }
 
-var isSecureScheme = map[string]bool{
-	"https":   true,
-	"git+ssh": true,
-	"bzr+ssh": true,
-	"svn+ssh": true,
-	"ssh":     true,
-}
-
-func (v *vcsCmd) isSecure(repo string) bool {
-	u, err := url.Parse(repo)
-	if err != nil {
-		// If repo is not a URL, it's not secure.
-		return false
-	}
-	return isSecureScheme[u.Scheme]
-}
-
 // A tagCmd describes a command to list available tags
 // that can be passed to tagSyncCmd.
 type tagCmd struct {
@@ -89,8 +69,8 @@ var vcsHg = &vcsCmd{
 	name: "Mercurial",
 	cmd:  "hg",
 
-	createCmd:   []string{"clone -U {repo} {dir}"},
-	downloadCmd: []string{"pull"},
+	createCmd:   "clone -U {repo} {dir}",
+	downloadCmd: "pull",
 
 	// We allow both tag and branch names as 'tags'
 	// for selecting a version.  This lets people have
@@ -101,8 +81,8 @@ var vcsHg = &vcsCmd{
 		{"tags", `^(\S+)`},
 		{"branches", `^(\S+)`},
 	},
-	tagSyncCmd:     []string{"update -r {tag}"},
-	tagSyncDefault: []string{"update default"},
+	tagSyncCmd:     "update -r {tag}",
+	tagSyncDefault: "update default",
 
 	scheme:     []string{"https", "http", "ssh"},
 	pingCmd:    "identify {scheme}://{repo}",
@@ -122,8 +102,8 @@ var vcsGit = &vcsCmd{
 	name: "Git",
 	cmd:  "git",
 
-	createCmd:   []string{"clone {repo} {dir}", "--git-dir={dir}/.git submodule update --init --recursive"},
-	downloadCmd: []string{"pull --ff-only", "submodule update --init --recursive"},
+	createCmd:   "clone {repo} {dir}",
+	downloadCmd: "pull --ff-only",
 
 	tagCmd: []tagCmd{
 		// tags/xxx matches a git tag named xxx
@@ -133,64 +113,41 @@ var vcsGit = &vcsCmd{
 	tagLookupCmd: []tagCmd{
 		{"show-ref tags/{tag} origin/{tag}", `((?:tags|origin)/\S+)$`},
 	},
-	tagSyncCmd: []string{"checkout {tag}", "submodule update --init --recursive"},
-	// both createCmd and downloadCmd update the working dir.
-	// No need to do more here. We used to 'checkout master'
-	// but that doesn't work if the default branch is not named master.
-	// See golang.org/issue/9032.
-	tagSyncDefault: []string{"checkout master", "submodule update --init --recursive"},
-
-	scheme:     []string{"git", "https", "http", "git+ssh", "ssh"},
+	tagSyncCmd:     "checkout {tag}",
+	tagSyncDefault: "checkout master",
+
+	scheme:     []string{"git", "https", "http", "git+ssh"},
 	pingCmd:    "ls-remote {scheme}://{repo}",
 	remoteRepo: gitRemoteRepo,
 }
 
-// scpSyntaxRe matches the SCP-like addresses used by Git to access
-// repositories by SSH.
-var scpSyntaxRe = regexp.MustCompile(`^([a-zA-Z0-9_]+)@([a-zA-Z0-9._-]+):(.*)$`)
-
 func gitRemoteRepo(vcsGit *vcsCmd, rootDir string) (remoteRepo string, err error) {
-	cmd := "config remote.origin.url"
-	errParse := errors.New("unable to parse output of git " + cmd)
-	errRemoteOriginNotFound := errors.New("remote origin not found")
-	outb, err := vcsGit.run1(rootDir, cmd, nil, false)
+	outb, err := vcsGit.runOutput(rootDir, "remote -v")
 	if err != nil {
-		// if it doesn't output any message, it means the config argument is correct,
-		// but the config value itself doesn't exist
-		if outb != nil && len(outb) == 0 {
-			return "", errRemoteOriginNotFound
-		}
 		return "", err
 	}
-	out := strings.TrimSpace(string(outb))
-
-	var repoURL *url.URL
-	if m := scpSyntaxRe.FindStringSubmatch(out); m != nil {
-		// Match SCP-like syntax and convert it to a URL.
-		// Eg, "git at github.com:user/repo" becomes
-		// "ssh://git@github.com/user/repo".
-		repoURL = &url.URL{
-			Scheme:  "ssh",
-			User:    url.User(m[1]),
-			Host:    m[2],
-			RawPath: m[3],
-		}
-	} else {
-		repoURL, err = url.Parse(out)
-		if err != nil {
-			return "", err
-		}
-	}
+	out := string(outb)
 
-	// Iterate over insecure schemes too, because this function simply
-	// reports the state of the repo. If we can't see insecure schemes then
-	// we can't report the actual repo URL.
-	for _, s := range vcsGit.scheme {
-		if repoURL.Scheme == s {
-			return repoURL.String(), nil
-		}
+	// Expect:
+	// origin	https://github.com/rsc/pdf (fetch)
+	// origin	https://github.com/rsc/pdf (push)
+	// use first line only.
+
+	if !strings.HasPrefix(out, "origin\t") {
+		return "", fmt.Errorf("unable to parse output of git remote -v")
+	}
+	out = strings.TrimPrefix(out, "origin\t")
+	i := strings.Index(out, "\n")
+	if i < 0 {
+		return "", fmt.Errorf("unable to parse output of git remote -v")
+	}
+	out = out[:i]
+	i = strings.LastIndex(out, " ")
+	if i < 0 {
+		return "", fmt.Errorf("unable to parse output of git remote -v")
 	}
-	return "", errParse
+	out = out[:i]
+	return strings.TrimSpace(string(out)), nil
 }
 
 // vcsBzr describes how to use Bazaar.
@@ -198,15 +155,15 @@ var vcsBzr = &vcsCmd{
 	name: "Bazaar",
 	cmd:  "bzr",
 
-	createCmd: []string{"branch {repo} {dir}"},
+	createCmd: "branch {repo} {dir}",
 
 	// Without --overwrite bzr will not pull tags that changed.
 	// Replace by --overwrite-tags after http://pad.lv/681792 goes in.
-	downloadCmd: []string{"pull --overwrite"},
+	downloadCmd: "pull --overwrite",
 
 	tagCmd:         []tagCmd{{"tags", `^(\S+)`}},
-	tagSyncCmd:     []string{"update -r {tag}"},
-	tagSyncDefault: []string{"update -r revno:-1"},
+	tagSyncCmd:     "update -r {tag}",
+	tagSyncDefault: "update -r revno:-1",
 
 	scheme:      []string{"https", "http", "bzr", "bzr+ssh"},
 	pingCmd:     "info {scheme}://{repo}",
@@ -260,8 +217,8 @@ var vcsSvn = &vcsCmd{
 	name: "Subversion",
 	cmd:  "svn",
 
-	createCmd:   []string{"checkout {repo} {dir}"},
-	downloadCmd: []string{"update"},
+	createCmd:   "checkout {repo} {dir}",
+	downloadCmd: "update",
 
 	// There is no tag command in subversion.
 	// The branch information is all in the path names.
@@ -337,14 +294,14 @@ func (v *vcsCmd) run1(dir string, cmdline string, keyval []string, verbose bool)
 	_, err := exec.LookPath(v.cmd)
 	if err != nil {
 		fmt.Fprintf(os.Stderr,
-			"go: missing %s command. See https://golang.org/s/gogetcmd\n",
+			"go: missing %s command. See http://golang.org/s/gogetcmd\n",
 			v.name)
 		return nil, err
 	}
 
 	cmd := exec.Command(v.cmd, args...)
 	cmd.Dir = dir
-	cmd.Env = envForDir(cmd.Dir, os.Environ())
+	cmd.Env = envForDir(cmd.Dir)
 	if buildX {
 		fmt.Printf("cd %s\n", dir)
 		fmt.Printf("%s %s\n", v.cmd, strings.Join(args, " "))
@@ -359,7 +316,7 @@ func (v *vcsCmd) run1(dir string, cmdline string, keyval []string, verbose bool)
 			fmt.Fprintf(os.Stderr, "# cd %s; %s %s\n", dir, v.cmd, strings.Join(args, " "))
 			os.Stderr.Write(out)
 		}
-		return out, err
+		return nil, err
 	}
 	return out, nil
 }
@@ -372,15 +329,7 @@ func (v *vcsCmd) ping(scheme, repo string) error {
 // create creates a new copy of repo in dir.
 // The parent of dir must exist; dir must not.
 func (v *vcsCmd) create(dir, repo string) error {
-	for _, cmd := range v.createCmd {
-		if !go15VendorExperiment && strings.Contains(cmd, "submodule") {
-			continue
-		}
-		if err := v.run(".", cmd, "dir", dir, "repo", repo); err != nil {
-			return err
-		}
-	}
-	return nil
+	return v.run(".", v.createCmd, "dir", dir, "repo", repo)
 }
 
 // download downloads any new changes for the repo in dir.
@@ -388,15 +337,7 @@ func (v *vcsCmd) download(dir string) error {
 	if err := v.fixDetachedHead(dir); err != nil {
 		return err
 	}
-	for _, cmd := range v.downloadCmd {
-		if !go15VendorExperiment && strings.Contains(cmd, "submodule") {
-			continue
-		}
-		if err := v.run(dir, cmd); err != nil {
-			return err
-		}
-	}
-	return nil
+	return v.run(dir, v.downloadCmd)
 }
 
 // fixDetachedHead switches a Git repository in dir from a detached head to the master branch.
@@ -442,7 +383,7 @@ func (v *vcsCmd) tags(dir string) ([]string, error) {
 // tagSync syncs the repo in dir to the named tag,
 // which either is a tag returned by tags or is v.tagDefault.
 func (v *vcsCmd) tagSync(dir, tag string) error {
-	if v.tagSyncCmd == nil {
+	if v.tagSyncCmd == "" {
 		return nil
 	}
 	if tag != "" {
@@ -459,28 +400,10 @@ func (v *vcsCmd) tagSync(dir, tag string) error {
 			}
 		}
 	}
-
-	if tag == "" && v.tagSyncDefault != nil {
-		for _, cmd := range v.tagSyncDefault {
-			if !go15VendorExperiment && strings.Contains(cmd, "submodule") {
-				continue
-			}
-			if err := v.run(dir, cmd); err != nil {
-				return err
-			}
-		}
-		return nil
-	}
-
-	for _, cmd := range v.tagSyncCmd {
-		if !go15VendorExperiment && strings.Contains(cmd, "submodule") {
-			continue
-		}
-		if err := v.run(dir, cmd, "tag", tag); err != nil {
-			return err
-		}
+	if tag == "" && v.tagSyncDefault != "" {
+		return v.run(dir, v.tagSyncDefault)
 	}
-	return nil
+	return v.run(dir, v.tagSyncCmd, "tag", tag)
 }
 
 // A vcsPath describes how to convert an import path into a
@@ -544,20 +467,10 @@ type repoRoot struct {
 
 var httpPrefixRE = regexp.MustCompile(`^https?:`)
 
-// securityMode specifies whether a function should make network
-// calls using insecure transports (eg, plain text HTTP).
-// The zero value is "secure".
-type securityMode int
-
-const (
-	secure securityMode = iota
-	insecure
-)
-
 // repoRootForImportPath analyzes importPath to determine the
 // version control system, and code repository to use.
-func repoRootForImportPath(importPath string, security securityMode) (*repoRoot, error) {
-	rr, err := repoRootFromVCSPaths(importPath, "", security, vcsPaths)
+func repoRootForImportPath(importPath string) (*repoRoot, error) {
+	rr, err := repoRootForImportPathStatic(importPath, "")
 	if err == errUnknownSite {
 		// If there are wildcards, look up the thing before the wildcard,
 		// hoping it applies to the wildcarded parts too.
@@ -566,7 +479,7 @@ func repoRootForImportPath(importPath string, security securityMode) (*repoRoot,
 		if i := strings.Index(lookup, "/.../"); i >= 0 {
 			lookup = lookup[:i]
 		}
-		rr, err = repoRootForImportDynamic(lookup, security)
+		rr, err = repoRootForImportDynamic(lookup)
 
 		// repoRootForImportDynamic returns error detail
 		// that is irrelevant if the user didn't intend to use a
@@ -579,13 +492,6 @@ func repoRootForImportPath(importPath string, security securityMode) (*repoRoot,
 			err = fmt.Errorf("unrecognized import path %q", importPath)
 		}
 	}
-	if err != nil {
-		rr1, err1 := repoRootFromVCSPaths(importPath, "", security, vcsPathsAfterDynamic)
-		if err1 == nil {
-			rr = rr1
-			err = nil
-		}
-	}
 
 	if err == nil && strings.Contains(importPath, "...") && strings.Contains(rr.root, "...") {
 		// Do not allow wildcards in the repo root.
@@ -597,10 +503,13 @@ func repoRootForImportPath(importPath string, security securityMode) (*repoRoot,
 
 var errUnknownSite = errors.New("dynamic lookup required to find mapping")
 
-// repoRootFromVCSPaths attempts to map importPath to a repoRoot
-// using the mappings defined in vcsPaths.
+// repoRootForImportPathStatic attempts to map importPath to a
+// repoRoot using the commonly-used VCS hosting sites in vcsPaths
+// (github.com/user/dir), or from a fully-qualified importPath already
+// containing its VCS type (foo.com/repo.git/dir)
+//
 // If scheme is non-empty, that scheme is forced.
-func repoRootFromVCSPaths(importPath, scheme string, security securityMode, vcsPaths []*vcsPath) (*repoRoot, error) {
+func repoRootForImportPathStatic(importPath, scheme string) (*repoRoot, error) {
 	// 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 {
@@ -650,9 +559,6 @@ func repoRootFromVCSPaths(importPath, scheme string, security securityMode, vcsP
 				match["repo"] = scheme + "://" + match["repo"]
 			} else {
 				for _, scheme := range vcs.scheme {
-					if security == secure && !isSecureScheme[scheme] {
-						continue
-					}
 					if vcs.ping(scheme, match["repo"]) == nil {
 						match["repo"] = scheme + "://" + match["repo"]
 						break
@@ -673,31 +579,26 @@ func repoRootFromVCSPaths(importPath, scheme string, security securityMode, vcsP
 // repoRootForImportDynamic finds a *repoRoot for a custom domain that's not
 // statically known by repoRootForImportPathStatic.
 //
-// This handles custom import paths like "name.tld/pkg/foo" or just "name.tld".
-func repoRootForImportDynamic(importPath string, security securityMode) (*repoRoot, error) {
+// This handles "vanity import paths" like "name.tld/pkg/foo".
+func repoRootForImportDynamic(importPath string) (*repoRoot, error) {
 	slash := strings.Index(importPath, "/")
 	if slash < 0 {
-		slash = len(importPath)
+		return nil, errors.New("import path does not contain a slash")
 	}
 	host := importPath[:slash]
 	if !strings.Contains(host, ".") {
 		return nil, errors.New("import path does not begin with hostname")
 	}
-	urlStr, body, err := httpsOrHTTP(importPath, security)
+	urlStr, body, err := httpsOrHTTP(importPath)
 	if err != nil {
-		msg := "https fetch: %v"
-		if security == insecure {
-			msg = "http/" + msg
-		}
-		return nil, fmt.Errorf(msg, err)
+		return nil, fmt.Errorf("http/https fetch: %v", err)
 	}
 	defer body.Close()
 	imports, err := parseMetaGoImports(body)
 	if err != nil {
 		return nil, fmt.Errorf("parsing %s: %v", importPath, err)
 	}
-	// Find the matched meta import.
-	mmi, err := matchGoImport(imports, importPath)
+	metaImport, err := matchGoImport(imports, importPath)
 	if err != nil {
 		if err != errNoMatch {
 			return nil, fmt.Errorf("parse %s: %v", urlStr, err)
@@ -705,7 +606,7 @@ func repoRootForImportDynamic(importPath string, security securityMode) (*repoRo
 		return nil, fmt.Errorf("parse %s: no go-import meta tags", urlStr)
 	}
 	if buildV {
-		log.Printf("get %q: found meta tag %#v at %s", importPath, mmi, urlStr)
+		log.Printf("get %q: found meta tag %#v at %s", importPath, metaImport, urlStr)
 	}
 	// If the import was "uni.edu/bob/project", which said the
 	// prefix was "uni.edu" and the RepoRoot was "evilroot.com",
@@ -713,89 +614,42 @@ func repoRootForImportDynamic(importPath string, security securityMode) (*repoRo
 	// "uni.edu" yet (possibly overwriting/preempting another
 	// non-evil student).  Instead, first verify the root and see
 	// if it matches Bob's claim.
-	if mmi.Prefix != importPath {
+	if metaImport.Prefix != importPath {
 		if buildV {
 			log.Printf("get %q: verifying non-authoritative meta tag", importPath)
 		}
 		urlStr0 := urlStr
-		var imports []metaImport
-		urlStr, imports, err = metaImportsForPrefix(mmi.Prefix, security)
+		urlStr, body, err = httpsOrHTTP(metaImport.Prefix)
 		if err != nil {
-			return nil, err
+			return nil, fmt.Errorf("fetch %s: %v", urlStr, err)
+		}
+		imports, err := parseMetaGoImports(body)
+		if err != nil {
+			return nil, fmt.Errorf("parsing %s: %v", importPath, err)
+		}
+		if len(imports) == 0 {
+			return nil, fmt.Errorf("fetch %s: no go-import meta tag", urlStr)
 		}
 		metaImport2, err := matchGoImport(imports, importPath)
-		if err != nil || mmi != metaImport2 {
-			return nil, fmt.Errorf("%s and %s disagree about go-import for %s", urlStr0, urlStr, mmi.Prefix)
+		if err != nil || metaImport != metaImport2 {
+			return nil, fmt.Errorf("%s and %s disagree about go-import for %s", urlStr0, urlStr, metaImport.Prefix)
 		}
 	}
 
-	if !strings.Contains(mmi.RepoRoot, "://") {
-		return nil, fmt.Errorf("%s: invalid repo root %q; no scheme", urlStr, mmi.RepoRoot)
+	if !strings.Contains(metaImport.RepoRoot, "://") {
+		return nil, fmt.Errorf("%s: invalid repo root %q; no scheme", urlStr, metaImport.RepoRoot)
 	}
 	rr := &repoRoot{
-		vcs:  vcsByCmd(mmi.VCS),
-		repo: mmi.RepoRoot,
-		root: mmi.Prefix,
+		vcs:  vcsByCmd(metaImport.VCS),
+		repo: metaImport.RepoRoot,
+		root: metaImport.Prefix,
 	}
 	if rr.vcs == nil {
-		return nil, fmt.Errorf("%s: unknown vcs %q", urlStr, mmi.VCS)
+		return nil, fmt.Errorf("%s: unknown vcs %q", urlStr, metaImport.VCS)
 	}
 	return rr, nil
 }
 
-var fetchGroup singleflight.Group
-var (
-	fetchCacheMu sync.Mutex
-	fetchCache   = map[string]fetchResult{} // key is metaImportsForPrefix's importPrefix
-)
-
-// metaImportsForPrefix takes a package's root import path as declared in a <meta> tag
-// and returns its HTML discovery URL and the parsed metaImport lines
-// found on the page.
-//
-// The importPath is of the form "golang.org/x/tools".
-// It is an error if no imports are found.
-// urlStr will still be valid if err != nil.
-// The returned urlStr will be of the form "https://golang.org/x/tools?go-get=1"
-func metaImportsForPrefix(importPrefix string, security securityMode) (urlStr string, imports []metaImport, err error) {
-	setCache := func(res fetchResult) (fetchResult, error) {
-		fetchCacheMu.Lock()
-		defer fetchCacheMu.Unlock()
-		fetchCache[importPrefix] = res
-		return res, nil
-	}
-
-	resi, _, _ := fetchGroup.Do(importPrefix, func() (resi interface{}, err error) {
-		fetchCacheMu.Lock()
-		if res, ok := fetchCache[importPrefix]; ok {
-			fetchCacheMu.Unlock()
-			return res, nil
-		}
-		fetchCacheMu.Unlock()
-
-		urlStr, body, err := httpsOrHTTP(importPrefix, security)
-		if err != nil {
-			return setCache(fetchResult{urlStr: urlStr, err: fmt.Errorf("fetch %s: %v", urlStr, err)})
-		}
-		imports, err := parseMetaGoImports(body)
-		if err != nil {
-			return setCache(fetchResult{urlStr: urlStr, err: fmt.Errorf("parsing %s: %v", urlStr, err)})
-		}
-		if len(imports) == 0 {
-			err = fmt.Errorf("fetch %s: no go-import meta tag", urlStr)
-		}
-		return setCache(fetchResult{urlStr: urlStr, imports: imports, err: err})
-	})
-	res := resi.(fetchResult)
-	return res.urlStr, res.imports, res.err
-}
-
-type fetchResult struct {
-	urlStr  string // e.g. "https://foo.com/x/bar?go-get=1"
-	imports []metaImport
-	err     error
-}
-
 // metaImport represents the parsed <meta name="go-import"
 // content="prefix vcs reporoot" /> tags from HTML files.
 type metaImport struct {
@@ -835,10 +689,7 @@ func expand(match map[string]string, s string) string {
 	return s
 }
 
-// vcsPaths defines the meaning of import paths referring to
-// commonly-used VCS hosting sites (github.com/user/dir)
-// and import paths referring to a fully-qualified importPath
-// containing a VCS type (foo.com/repo.git/dir)
+// vcsPaths lists the known vcs paths.
 var vcsPaths = []*vcsPath{
 	// Google Code - new syntax
 	{
@@ -871,46 +722,31 @@ var vcsPaths = []*vcsPath{
 		check:  bitbucketVCS,
 	},
 
-	// IBM DevOps Services (JazzHub)
+	// Launchpad
 	{
-		prefix: "hub.jazz.net/git",
-		re:     `^(?P<root>hub.jazz.net/git/[a-z0-9]+/[A-Za-z0-9_.\-]+)(/[A-Za-z0-9_.\-]+)*$`,
-		vcs:    "git",
+		prefix: "launchpad.net/",
+		re:     `^(?P<root>launchpad\.net/((?P<project>[A-Za-z0-9_.\-]+)(?P<series>/[A-Za-z0-9_.\-]+)?|~[A-Za-z0-9_.\-]+/(\+junk|[A-Za-z0-9_.\-]+)/[A-Za-z0-9_.\-]+))(/[A-Za-z0-9_.\-]+)*$`,
+		vcs:    "bzr",
 		repo:   "https://{root}",
-		check:  noVCSSuffix,
+		check:  launchpadVCS,
 	},
 
-	// Git at Apache
+	// IBM DevOps Services (JazzHub)
 	{
-		prefix: "git.apache.org",
-		re:     `^(?P<root>git.apache.org/[a-z0-9_.\-]+\.git)(/[A-Za-z0-9_.\-]+)*$`,
+		prefix: "hub.jazz.net/git",
+		re:     `^(?P<root>hub.jazz.net/git/[a-z0-9]+/[A-Za-z0-9_.\-]+)(/[A-Za-z0-9_.\-]+)*$`,
 		vcs:    "git",
 		repo:   "https://{root}",
+		check:  noVCSSuffix,
 	},
 
 	// General syntax for any server.
-	// Must be last.
 	{
 		re:   `^(?P<root>(?P<repo>([a-z0-9.\-]+\.)+[a-z0-9.\-]+(:[0-9]+)?/[A-Za-z0-9_.\-/]*?)\.(?P<vcs>bzr|git|hg|svn))(/[A-Za-z0-9_.\-]+)*$`,
 		ping: true,
 	},
 }
 
-// vcsPathsAfterDynamic gives additional vcsPaths entries
-// to try after the dynamic HTML check.
-// This gives those sites a chance to introduce <meta> tags
-// as part of a graceful transition away from the hard-coded logic.
-var vcsPathsAfterDynamic = []*vcsPath{
-	// Launchpad. See golang.org/issue/11436.
-	{
-		prefix: "launchpad.net/",
-		re:     `^(?P<root>launchpad\.net/((?P<project>[A-Za-z0-9_.\-]+)(?P<series>/[A-Za-z0-9_.\-]+)?|~[A-Za-z0-9_.\-]+/(\+junk|[A-Za-z0-9_.\-]+)/[A-Za-z0-9_.\-]+))(/[A-Za-z0-9_.\-]+)*$`,
-		vcs:    "bzr",
-		repo:   "https://{root}",
-		check:  launchpadVCS,
-	},
-}
-
 func init() {
 	// fill in cached regexps.
 	// Doing this eagerly discovers invalid regexp syntax
@@ -918,9 +754,6 @@ func init() {
 	for _, srv := range vcsPaths {
 		srv.regexp = regexp.MustCompile(srv.re)
 	}
-	for _, srv := range vcsPathsAfterDynamic {
-		srv.regexp = regexp.MustCompile(srv.re)
-	}
 }
 
 // noVCSSuffix checks that the repository name does not
@@ -988,25 +821,10 @@ func bitbucketVCS(match map[string]string) error {
 	url := expand(match, "https://api.bitbucket.org/1.0/repositories/{bitname}")
 	data, err := httpGET(url)
 	if err != nil {
-		if httpErr, ok := err.(*httpError); ok && httpErr.statusCode == 403 {
-			// this may be a private repository. If so, attempt to determine which
-			// VCS it uses. See issue 5375.
-			root := match["root"]
-			for _, vcs := range []string{"git", "hg"} {
-				if vcsByCmd(vcs).ping("https", root) == nil {
-					resp.SCM = vcs
-					break
-				}
-			}
-		}
-
-		if resp.SCM == "" {
-			return err
-		}
-	} else {
-		if err := json.Unmarshal(data, &resp); err != nil {
-			return fmt.Errorf("decoding %s: %v", url, err)
-		}
+		return err
+	}
+	if err := json.Unmarshal(data, &resp); err != nil {
+		return fmt.Errorf("decoding %s: %v", url, err)
 	}
 
 	if vcsByCmd(resp.SCM) != nil {
diff --git a/src/cmd/go/vcs_test.go b/src/cmd/go/vcs_test.go
index f5d5e4f..14d681b 100644
--- a/src/cmd/go/vcs_test.go
+++ b/src/cmd/go/vcs_test.go
@@ -5,15 +5,20 @@
 package main
 
 import (
-	"internal/testenv"
+	"runtime"
 	"testing"
 )
 
 // Test that RepoRootForImportPath creates the correct RepoRoot for a given importPath.
 // TODO(cmang): Add tests for SVN and BZR.
 func TestRepoRootForImportPath(t *testing.T) {
-	testenv.MustHaveExternalNetwork(t)
-
+	if testing.Short() {
+		t.Skip("skipping test to avoid external network")
+	}
+	switch runtime.GOOS {
+	case "nacl", "android":
+		t.Skipf("no networking available on %s", runtime.GOOS)
+	}
 	tests := []struct {
 		path string
 		want *repoRoot
@@ -96,34 +101,10 @@ func TestRepoRootForImportPath(t *testing.T) {
 			"hub.jazz.net/git/USER/pkgname",
 			nil,
 		},
-		// Spaces are not valid in package name
-		{
-			"git.apache.org/package name/path/to/lib",
-			nil,
-		},
-		// Should have ".git" suffix
-		{
-			"git.apache.org/package-name/path/to/lib",
-			nil,
-		},
-		{
-			"git.apache.org/package-name.git",
-			&repoRoot{
-				vcs:  vcsGit,
-				repo: "https://git.apache.org/package-name.git",
-			},
-		},
-		{
-			"git.apache.org/package-name_2.x.git/path/to/lib",
-			&repoRoot{
-				vcs:  vcsGit,
-				repo: "https://git.apache.org/package-name_2.x.git",
-			},
-		},
 	}
 
 	for _, test := range tests {
-		got, err := repoRootForImportPath(test.path, secure)
+		got, err := repoRootForImportPath(test.path)
 		want := test.want
 
 		if want == nil {
@@ -141,35 +122,3 @@ func TestRepoRootForImportPath(t *testing.T) {
 		}
 	}
 }
-
-func TestIsSecure(t *testing.T) {
-	tests := []struct {
-		vcs    *vcsCmd
-		url    string
-		secure bool
-	}{
-		{vcsGit, "http://example.com/foo.git", false},
-		{vcsGit, "https://example.com/foo.git", true},
-		{vcsBzr, "http://example.com/foo.bzr", false},
-		{vcsBzr, "https://example.com/foo.bzr", true},
-		{vcsSvn, "http://example.com/svn", false},
-		{vcsSvn, "https://example.com/svn", true},
-		{vcsHg, "http://example.com/foo.hg", false},
-		{vcsHg, "https://example.com/foo.hg", true},
-		{vcsGit, "ssh://user@example.com/foo.git", true},
-		{vcsGit, "user at server:path/to/repo.git", false},
-		{vcsGit, "user at server:", false},
-		{vcsGit, "server:repo.git", false},
-		{vcsGit, "server:path/to/repo.git", false},
-		{vcsGit, "example.com:path/to/repo.git", false},
-		{vcsGit, "path/that/contains/a:colon/repo.git", false},
-		{vcsHg, "ssh://user@example.com/path/to/repo.hg", true},
-	}
-
-	for _, test := range tests {
-		secure := test.vcs.isSecure(test.url)
-		if secure != test.secure {
-			t.Errorf("%s isSecure(%q) = %t; want %t", test.vcs, test.url, secure, test.secure)
-		}
-	}
-}
diff --git a/src/cmd/go/vet.go b/src/cmd/go/vet.go
index 81b978e..02ff54b 100644
--- a/src/cmd/go/vet.go
+++ b/src/cmd/go/vet.go
@@ -7,17 +7,17 @@ package main
 import "path/filepath"
 
 func init() {
-	addBuildFlags(cmdVet)
+	addBuildFlagsNX(cmdVet)
 }
 
 var cmdVet = &Command{
 	Run:       runVet,
-	UsageLine: "vet [-n] [-x] [build flags] [packages]",
+	UsageLine: "vet [-n] [-x] [packages]",
 	Short:     "run go tool vet on packages",
 	Long: `
 Vet runs the Go vet command on the packages named by the import paths.
 
-For more about vet, see 'go doc cmd/vet'.
+For more about vet, see 'godoc golang.org/x/tools/cmd/vet'.
 For more about specifying packages, see 'go help packages'.
 
 To run the vet tool with specific options, run 'go tool vet'.
@@ -25,8 +25,6 @@ To run the vet tool with specific options, run 'go tool vet'.
 The -n flag prints commands that would be executed.
 The -x flag prints commands as they are executed.
 
-For more about build flags, see 'go help build'.
-
 See also: go fmt, go fix.
 	`,
 }
@@ -48,5 +46,5 @@ func runVetFiles(p *Package, files []string) {
 	for i := range files {
 		files[i] = filepath.Join(p.Dir, files[i])
 	}
-	run(buildToolExec, tool("vet"), relPaths(files))
+	run(tool("vet"), relPaths(files))
 }
diff --git a/src/cmd/gofmt/doc.go b/src/cmd/gofmt/doc.go
index 9d0cd32..3fc0439 100644
--- a/src/cmd/gofmt/doc.go
+++ b/src/cmd/gofmt/doc.go
@@ -87,13 +87,6 @@ When invoked with -s gofmt will make the following source transformations where
 		for x, _ = range v {...}
 	will be simplified to:
 		for x = range v {...}
-
-	A range of the form:
-		for _ = range v {...}
-	will be simplified to:
-		for range v {...}
-
-This may result in changes that are incompatible with earlier versions of Go.
 */
 package main
 
diff --git a/src/cmd/gofmt/gofmt.go b/src/cmd/gofmt/gofmt.go
index b2805ac..81da21f 100644
--- a/src/cmd/gofmt/gofmt.go
+++ b/src/cmd/gofmt/gofmt.go
@@ -13,7 +13,6 @@ import (
 	"go/printer"
 	"go/scanner"
 	"go/token"
-	"internal/format"
 	"io"
 	"io/ioutil"
 	"os"
@@ -88,7 +87,7 @@ func processFile(filename string, in io.Reader, out io.Writer, stdin bool) error
 		return err
 	}
 
-	file, sourceAdj, indentAdj, err := format.Parse(fileSet, filename, src, stdin)
+	file, sourceAdj, indentAdj, err := parse(fileSet, filename, src, stdin)
 	if err != nil {
 		return err
 	}
@@ -107,7 +106,7 @@ func processFile(filename string, in io.Reader, out io.Writer, stdin bool) error
 		simplify(file)
 	}
 
-	res, err := format.Format(fileSet, file, sourceAdj, indentAdj, src, printer.Config{Mode: printerMode, Tabwidth: tabWidth})
+	res, err := format(fileSet, file, sourceAdj, indentAdj, src, printer.Config{Mode: printerMode, Tabwidth: tabWidth})
 	if err != nil {
 		return err
 	}
@@ -235,3 +234,154 @@ func diff(b1, b2 []byte) (data []byte, err error) {
 	return
 
 }
+
+// ----------------------------------------------------------------------------
+// Support functions
+//
+// The functions parse, format, and isSpace below are identical to the
+// respective functions in src/go/format/format.go - keep them in sync!
+//
+// TODO(gri) Factor out this functionality, eventually.
+
+// parse parses src, which was read from the named file,
+// as a Go source file, declaration, or statement list.
+func parse(fset *token.FileSet, filename string, src []byte, fragmentOk bool) (
+	file *ast.File,
+	sourceAdj func(src []byte, indent int) []byte,
+	indentAdj int,
+	err error,
+) {
+	// Try as whole source file.
+	file, err = parser.ParseFile(fset, filename, src, parserMode)
+	// If there's no error, return.  If the error is that the source file didn't begin with a
+	// package line and source fragments are ok, fall through to
+	// try as a source fragment.  Stop and return on any other error.
+	if err == nil || !fragmentOk || !strings.Contains(err.Error(), "expected 'package'") {
+		return
+	}
+
+	// If this is a declaration list, make it a source file
+	// by inserting a package clause.
+	// Insert using a ;, not a newline, so that the line numbers
+	// in psrc match the ones in src.
+	psrc := append([]byte("package p;"), src...)
+	file, err = parser.ParseFile(fset, filename, psrc, parserMode)
+	if err == nil {
+		sourceAdj = func(src []byte, indent int) []byte {
+			// Remove the package clause.
+			// Gofmt has turned the ; into a \n.
+			src = src[indent+len("package p\n"):]
+			return bytes.TrimSpace(src)
+		}
+		return
+	}
+	// If the error is that the source file didn't begin with a
+	// declaration, fall through to try as a statement list.
+	// Stop and return on any other error.
+	if !strings.Contains(err.Error(), "expected declaration") {
+		return
+	}
+
+	// If this is a statement list, make it a source file
+	// by inserting a package clause and turning the list
+	// into a function body.  This handles expressions too.
+	// Insert using a ;, not a newline, so that the line numbers
+	// in fsrc match the ones in src.
+	fsrc := append(append([]byte("package p; func _() {"), src...), '\n', '}')
+	file, err = parser.ParseFile(fset, filename, fsrc, parserMode)
+	if err == nil {
+		sourceAdj = func(src []byte, indent int) []byte {
+			// Cap adjusted indent to zero.
+			if indent < 0 {
+				indent = 0
+			}
+			// Remove the wrapping.
+			// Gofmt has turned the ; into a \n\n.
+			// There will be two non-blank lines with indent, hence 2*indent.
+			src = src[2*indent+len("package p\n\nfunc _() {"):]
+			src = src[:len(src)-(indent+len("\n}\n"))]
+			return bytes.TrimSpace(src)
+		}
+		// Gofmt has also indented the function body one level.
+		// Adjust that with indentAdj.
+		indentAdj = -1
+	}
+
+	// Succeeded, or out of options.
+	return
+}
+
+// format formats the given package file originally obtained from src
+// and adjusts the result based on the original source via sourceAdj
+// and indentAdj.
+func format(
+	fset *token.FileSet,
+	file *ast.File,
+	sourceAdj func(src []byte, indent int) []byte,
+	indentAdj int,
+	src []byte,
+	cfg printer.Config,
+) ([]byte, error) {
+	if sourceAdj == nil {
+		// Complete source file.
+		var buf bytes.Buffer
+		err := cfg.Fprint(&buf, fset, file)
+		if err != nil {
+			return nil, err
+		}
+		return buf.Bytes(), nil
+	}
+
+	// Partial source file.
+	// Determine and prepend leading space.
+	i, j := 0, 0
+	for j < len(src) && isSpace(src[j]) {
+		if src[j] == '\n' {
+			i = j + 1 // byte offset of last line in leading space
+		}
+		j++
+	}
+	var res []byte
+	res = append(res, src[:i]...)
+
+	// Determine and prepend indentation of first code line.
+	// Spaces are ignored unless there are no tabs,
+	// in which case spaces count as one tab.
+	indent := 0
+	hasSpace := false
+	for _, b := range src[i:j] {
+		switch b {
+		case ' ':
+			hasSpace = true
+		case '\t':
+			indent++
+		}
+	}
+	if indent == 0 && hasSpace {
+		indent = 1
+	}
+	for i := 0; i < indent; i++ {
+		res = append(res, '\t')
+	}
+
+	// Format the source.
+	// Write it without any leading and trailing space.
+	cfg.Indent = indent + indentAdj
+	var buf bytes.Buffer
+	err := cfg.Fprint(&buf, fset, file)
+	if err != nil {
+		return nil, err
+	}
+	res = append(res, sourceAdj(buf.Bytes(), cfg.Indent)...)
+
+	// Determine and append trailing space.
+	i = len(src)
+	for i > 0 && isSpace(src[i-1]) {
+		i--
+	}
+	return append(res, src[i:]...), nil
+}
+
+func isSpace(b byte) bool {
+	return b == ' ' || b == '\t' || b == '\n' || b == '\r'
+}
diff --git a/src/cmd/gofmt/long_test.go b/src/cmd/gofmt/long_test.go
index df9a878..237b860 100644
--- a/src/cmd/gofmt/long_test.go
+++ b/src/cmd/gofmt/long_test.go
@@ -15,7 +15,6 @@ import (
 	"go/ast"
 	"go/printer"
 	"go/token"
-	"internal/format"
 	"io"
 	"os"
 	"path/filepath"
@@ -33,7 +32,7 @@ var (
 )
 
 func gofmt(fset *token.FileSet, filename string, src *bytes.Buffer) error {
-	f, _, _, err := format.Parse(fset, filename, src.Bytes(), false)
+	f, _, _, err := parse(fset, filename, src.Bytes(), false)
 	if err != nil {
 		return err
 	}
@@ -61,7 +60,7 @@ func testFile(t *testing.T, b1, b2 *bytes.Buffer, filename string) {
 
 	// exclude files w/ syntax errors (typically test cases)
 	fset := token.NewFileSet()
-	if _, _, _, err = format.Parse(fset, filename, b1.Bytes(), false); err != nil {
+	if _, _, _, err = parse(fset, filename, b1.Bytes(), false); err != nil {
 		if *verbose {
 			fmt.Fprintf(os.Stderr, "ignoring %s\n", err)
 		}
diff --git a/src/cmd/gofmt/rewrite.go b/src/cmd/gofmt/rewrite.go
index 069f966..d267cfc 100644
--- a/src/cmd/gofmt/rewrite.go
+++ b/src/cmd/gofmt/rewrite.go
@@ -154,7 +154,7 @@ func isWildcard(s string) bool {
 	return size == len(s) && unicode.IsLower(rune)
 }
 
-// match reports whether pattern matches val,
+// match returns true if pattern matches val,
 // recording wildcard submatches in m.
 // If m == nil, match checks whether pattern == val.
 func match(m map[string]reflect.Value, pattern, val reflect.Value) bool {
diff --git a/src/cmd/internal/goobj/read.go b/src/cmd/internal/goobj/read.go
index 1b0c964..79a83e5 100644
--- a/src/cmd/internal/goobj/read.go
+++ b/src/cmd/internal/goobj/read.go
@@ -12,7 +12,6 @@ package goobj
 import (
 	"bufio"
 	"bytes"
-	"cmd/internal/obj"
 	"errors"
 	"fmt"
 	"io"
@@ -32,46 +31,45 @@ const (
 	_ SymKind = iota
 
 	// readonly, executable
-	STEXT      SymKind = obj.STEXT
-	SELFRXSECT SymKind = obj.SELFRXSECT
+	STEXT
+	SELFRXSECT
 
 	// readonly, non-executable
-	STYPE      SymKind = obj.STYPE
-	SSTRING    SymKind = obj.SSTRING
-	SGOSTRING  SymKind = obj.SGOSTRING
-	SGOFUNC    SymKind = obj.SGOFUNC
-	SRODATA    SymKind = obj.SRODATA
-	SFUNCTAB   SymKind = obj.SFUNCTAB
-	STYPELINK  SymKind = obj.STYPELINK
-	SSYMTAB    SymKind = obj.SSYMTAB // TODO: move to unmapped section
-	SPCLNTAB   SymKind = obj.SPCLNTAB
-	SELFROSECT SymKind = obj.SELFROSECT
+	STYPE
+	SSTRING
+	SGOSTRING
+	SGOFUNC
+	SRODATA
+	SFUNCTAB
+	STYPELINK
+	SSYMTAB // TODO: move to unmapped section
+	SPCLNTAB
+	SELFROSECT
 
 	// writable, non-executable
-	SMACHOPLT  SymKind = obj.SMACHOPLT
-	SELFSECT   SymKind = obj.SELFSECT
-	SMACHO     SymKind = obj.SMACHO // Mach-O __nl_symbol_ptr
-	SMACHOGOT  SymKind = obj.SMACHOGOT
-	SWINDOWS   SymKind = obj.SWINDOWS
-	SELFGOT    SymKind = obj.SELFGOT
-	SNOPTRDATA SymKind = obj.SNOPTRDATA
-	SINITARR   SymKind = obj.SINITARR
-	SDATA      SymKind = obj.SDATA
-	SBSS       SymKind = obj.SBSS
-	SNOPTRBSS  SymKind = obj.SNOPTRBSS
-	STLSBSS    SymKind = obj.STLSBSS
+	SMACHOPLT
+	SELFSECT
+	SMACHO // Mach-O __nl_symbol_ptr
+	SMACHOGOT
+	SNOPTRDATA
+	SINITARR
+	SDATA
+	SWINDOWS
+	SBSS
+	SNOPTRBSS
+	STLSBSS
 
 	// not mapped
-	SXREF             SymKind = obj.SXREF
-	SMACHOSYMSTR      SymKind = obj.SMACHOSYMSTR
-	SMACHOSYMTAB      SymKind = obj.SMACHOSYMTAB
-	SMACHOINDIRECTPLT SymKind = obj.SMACHOINDIRECTPLT
-	SMACHOINDIRECTGOT SymKind = obj.SMACHOINDIRECTGOT
-	SFILE             SymKind = obj.SFILE
-	SFILEPATH         SymKind = obj.SFILEPATH
-	SCONST            SymKind = obj.SCONST
-	SDYNIMPORT        SymKind = obj.SDYNIMPORT
-	SHOSTOBJ          SymKind = obj.SHOSTOBJ
+	SXREF
+	SMACHOSYMSTR
+	SMACHOSYMTAB
+	SMACHOINDIRECTPLT
+	SMACHOINDIRECTGOT
+	SFILE
+	SFILEPATH
+	SCONST
+	SDYNIMPORT
+	SHOSTOBJ
 )
 
 var symKindStrings = []string{
diff --git a/src/cmd/internal/objfile/disasm.go b/src/cmd/internal/objfile/disasm.go
index 9838ce2..1a339c3 100644
--- a/src/cmd/internal/objfile/disasm.go
+++ b/src/cmd/internal/objfile/disasm.go
@@ -240,9 +240,9 @@ var disasms = map[string]disasmFunc{
 }
 
 var byteOrders = map[string]binary.ByteOrder{
-	"386":     binary.LittleEndian,
-	"amd64":   binary.LittleEndian,
-	"arm":     binary.LittleEndian,
-	"ppc64":   binary.BigEndian,
-	"ppc64le": binary.LittleEndian,
+	"386":       binary.LittleEndian,
+	"amd64":     binary.LittleEndian,
+	"arm":       binary.LittleEndian,
+	"power64":   binary.BigEndian,
+	"power64le": binary.LittleEndian,
 }
diff --git a/src/cmd/internal/objfile/elf.go b/src/cmd/internal/objfile/elf.go
index 305706d..17755b8 100644
--- a/src/cmd/internal/objfile/elf.go
+++ b/src/cmd/internal/objfile/elf.go
@@ -98,7 +98,7 @@ func (f *elfFile) goarch() string {
 	case elf.EM_ARM:
 		return "arm"
 	case elf.EM_PPC64:
-		return "ppc64"
+		return "power64"
 	}
 	return ""
 }
diff --git a/src/cmd/internal/objfile/macho.go b/src/cmd/internal/objfile/macho.go
index 7371c0d..7dd84a3 100644
--- a/src/cmd/internal/objfile/macho.go
+++ b/src/cmd/internal/objfile/macho.go
@@ -13,8 +13,6 @@ import (
 	"sort"
 )
 
-const stabTypeMask = 0xe0
-
 type machoFile struct {
 	macho *macho.File
 }
@@ -36,19 +34,12 @@ func (f *machoFile) symbols() ([]Sym, error) {
 	// We infer the size of a symbol by looking at where the next symbol begins.
 	var addrs []uint64
 	for _, s := range f.macho.Symtab.Syms {
-		// Skip stab debug info.
-		if s.Type&stabTypeMask == 0 {
-			addrs = append(addrs, s.Value)
-		}
+		addrs = append(addrs, s.Value)
 	}
 	sort.Sort(uint64s(addrs))
 
 	var syms []Sym
 	for _, s := range f.macho.Symtab.Syms {
-		if s.Type&stabTypeMask != 0 {
-			// Skip stab debug info.
-			continue
-		}
 		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) {
@@ -113,7 +104,7 @@ func (f *machoFile) goarch() string {
 	case macho.CpuArm:
 		return "arm"
 	case macho.CpuPpc64:
-		return "ppc64"
+		return "power64"
 	}
 	return ""
 }
diff --git a/src/cmd/internal/rsc.io/arm/armasm/ext_test.go b/src/cmd/internal/rsc.io/arm/armasm/ext_test.go
index aa87cf9..b0bd855 100644
--- a/src/cmd/internal/rsc.io/arm/armasm/ext_test.go
+++ b/src/cmd/internal/rsc.io/arm/armasm/ext_test.go
@@ -216,7 +216,7 @@ func writeInst(generate func(func([]byte))) (file string, f *os.File, size int,
 
 var zeros = []byte{0, 0, 0, 0}
 
-// pad pads the code sequence with pops.
+// pad pads the code sequenc with pops.
 func pad(enc []byte) []byte {
 	if len(enc) < 4 {
 		enc = append(enc[:len(enc):len(enc)], zeros[:4-len(enc)]...)
diff --git a/src/cmd/internal/rsc.io/x86/x86asm/ext_test.go b/src/cmd/internal/rsc.io/x86/x86asm/ext_test.go
index bb56c0d..f65d6b2 100644
--- a/src/cmd/internal/rsc.io/x86/x86asm/ext_test.go
+++ b/src/cmd/internal/rsc.io/x86/x86asm/ext_test.go
@@ -225,7 +225,7 @@ var pops = []byte{
 	0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f,
 }
 
-// pad pads the code sequence with pops.
+// pad pads the code sequenc with pops.
 func pad(enc []byte) []byte {
 	return append(enc[:len(enc):len(enc)], pops...)
 }
diff --git a/src/cmd/ld/data.c b/src/cmd/ld/data.c
new file mode 100644
index 0000000..6184754
--- /dev/null
+++ b/src/cmd/ld/data.c
@@ -0,0 +1,1397 @@
+// Inferno utils/8l/asm.c
+// http://code.google.com/p/inferno-os/source/browse/utils/8l/asm.c
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth 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.
+
+// Data layout and relocation.
+
+#include	"l.h"
+#include	"../ld/lib.h"
+#include	"../ld/elf.h"
+#include	"../ld/macho.h"
+#include	"../ld/pe.h"
+#include	"../../runtime/mgc0.h"
+
+void	dynreloc(void);
+
+/*
+ * divide-and-conquer list-link
+ * sort of LSym* structures.
+ * Used for the data block.
+ */
+int
+datcmp(LSym *s1, LSym *s2)
+{
+	if(s1->type != s2->type)
+		return (int)s1->type - (int)s2->type;
+	if(s1->size != s2->size) {
+		if(s1->size < s2->size)
+			return -1;
+		return +1;
+	}
+	return strcmp(s1->name, s2->name);
+}
+
+LSym*
+listsort(LSym *l, int (*cmp)(LSym*, LSym*), int off)
+{
+	LSym *l1, *l2, *le;
+	#define NEXT(l) (*(LSym**)((char*)(l)+off))
+
+	if(l == 0 || NEXT(l) == 0)
+		return l;
+
+	l1 = l;
+	l2 = l;
+	for(;;) {
+		l2 = NEXT(l2);
+		if(l2 == 0)
+			break;
+		l2 = NEXT(l2);
+		if(l2 == 0)
+			break;
+		l1 = NEXT(l1);
+	}
+
+	l2 = NEXT(l1);
+	NEXT(l1) = 0;
+	l1 = listsort(l, cmp, off);
+	l2 = listsort(l2, cmp, off);
+
+	/* set up lead element */
+	if(cmp(l1, l2) < 0) {
+		l = l1;
+		l1 = NEXT(l1);
+	} else {
+		l = l2;
+		l2 = NEXT(l2);
+	}
+	le = l;
+
+	for(;;) {
+		if(l1 == 0) {
+			while(l2) {
+				NEXT(le) = l2;
+				le = l2;
+				l2 = NEXT(l2);
+			}
+			NEXT(le) = 0;
+			break;
+		}
+		if(l2 == 0) {
+			while(l1) {
+				NEXT(le) = l1;
+				le = l1;
+				l1 = NEXT(l1);
+			}
+			break;
+		}
+		if(cmp(l1, l2) < 0) {
+			NEXT(le) = l1;
+			le = l1;
+			l1 = NEXT(l1);
+		} else {
+			NEXT(le) = l2;
+			le = l2;
+			l2 = NEXT(l2);
+		}
+	}
+	NEXT(le) = 0;
+	return l;
+	
+	#undef NEXT
+}
+
+void
+relocsym(LSym *s)
+{
+	Reloc *r;
+	LSym *rs;
+	int32 i, off, siz, fl;
+	vlong o;
+	uchar *cast;
+
+	ctxt->cursym = s;
+	for(r=s->r; r<s->r+s->nr; r++) {
+		r->done = 1;
+		off = r->off;
+		siz = r->siz;
+		if(off < 0 || off+siz > s->np) {
+			diag("%s: invalid relocation %d+%d not in [%d,%d)", s->name, off, siz, 0, s->np);
+			continue;
+		}
+		if(r->sym != S && ((r->sym->type & (SMASK | SHIDDEN)) == 0 || (r->sym->type & SMASK) == SXREF)) {
+			diag("%s: not defined", r->sym->name);
+			continue;
+		}
+		if(r->type >= 256)
+			continue;
+		if(r->siz == 0) // informational relocation - no work to do
+			continue;
+
+		// 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);
+
+		// Android emulates runtime.tlsg as a regular variable.
+		if (r->type == R_TLS && strcmp(goos, "android") == 0)
+			r->type = R_ADDR;
+
+		switch(r->type) {
+		default:
+			o = 0;
+			if(archreloc(r, s, &o) < 0)
+				diag("unknown reloc %d", r->type);
+			break;
+		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 R_TLS_LE:
+			if(linkmode == LinkExternal && iself && HEADTYPE != Hopenbsd) {
+				r->done = 0;
+				r->sym = ctxt->tlsg;
+				r->xsym = ctxt->tlsg;
+				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->tlsg;
+				r->xsym = ctxt->tlsg;
+				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;
+
+				// set up addend for eventual relocation via outer symbol.
+				rs = r->sym;
+				r->xadd = r->add;
+				while(rs->outer != nil) {
+					r->xadd += symaddr(rs) - symaddr(rs->outer);
+					rs = rs->outer;
+				}
+				if(rs->type != SHOSTOBJ && rs->type != SDYNIMPORT && rs->sect == nil)
+					diag("missing section for %s", rs->name);
+				r->xsym = rs;
+
+				o = r->xadd;
+				if(iself) {
+					if(thechar == '6')
+						o = 0;
+				} else if(HEADTYPE == Hdarwin) {
+					if(rs->type != SHOSTOBJ)
+						o += symaddr(rs);
+				} else {
+					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 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 != ctxt->cursym->sect) {
+				r->done = 0;
+
+				// set up addend for eventual relocation via outer symbol.
+				rs = r->sym;
+				r->xadd = r->add;
+				while(rs->outer != nil) {
+					r->xadd += symaddr(rs) - symaddr(rs->outer);
+					rs = rs->outer;
+				}
+				r->xadd -= r->siz; // relative to address after the relocated chunk
+				if(rs->type != SHOSTOBJ && rs->type != SDYNIMPORT && rs->sect == nil)
+					diag("missing section for %s", rs->name);
+				r->xsym = rs;
+
+				o = r->xadd;
+				if(iself) {
+					if(thechar == '6')
+						o = 0;
+				} else if(HEADTYPE == Hdarwin) {
+					if(r->type == R_CALL) {
+						if(rs->type != SHOSTOBJ)
+							o += symaddr(rs) - rs->sect->vaddr;
+						o -= r->off; // relative to section offset, not symbol
+					} else {
+						o += r->siz;
+					}
+				} else {
+					diag("unhandled pcrel relocation for %s", headstring);
+				}
+				break;
+			}
+			o = 0;
+			if(r->sym)
+				o += symaddr(r->sym);
+			// NOTE: The (int32) cast on the next line works around a bug in Plan 9's 8c
+			// compiler. The expression s->value + r->off + r->siz is int32 + int32 +
+			// uchar, and Plan 9 8c incorrectly treats the expression as type uint32
+			// instead of int32, causing incorrect values when sign extended for adding
+			// to o. The bug only occurs on Plan 9, because this C program is compiled by
+			// the standard host compiler (gcc on most other systems).
+			o += r->add - (s->value + r->off + (int32)r->siz);
+			break;
+		case R_SIZE:
+			o = r->sym->size + r->add;
+			break;
+		}
+//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:
+			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 == R_PCREL || r->type == R_CALL) {
+				if(o != (int32)o)
+					diag("pc-relative relocation address is too big: %#llx", o);
+			} else {
+				if(o != (int32)o && o != (uint32)o)
+					diag("non-pc-relative relocation address is too big: %#llux", o);
+			}
+			fl = o;
+			cast = (uchar*)&fl;
+			for(i=0; i<4; i++)
+				s->p[off+i] = cast[inuxi4[i]];
+			break;
+		case 8:
+			cast = (uchar*)&o;
+			for(i=0; i<8; i++)
+				s->p[off+i] = cast[inuxi8[i]];
+			break;
+		}
+	}
+}
+
+void
+reloc(void)
+{
+	LSym *s;
+
+	if(debug['v'])
+		Bprint(&bso, "%5.2f reloc\n", cputime());
+	Bflush(&bso);
+
+	for(s=ctxt->textp; s!=S; s=s->next)
+		relocsym(s);
+	for(s=datap; s!=S; s=s->next)
+		relocsym(s);
+}
+
+void
+dynrelocsym(LSym *s)
+{
+	Reloc *r;
+
+	if(HEADTYPE == Hwindows) {
+		LSym *rel, *targ;
+
+		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;
+				r->add = targ->plt;
+
+				// jmp *addr
+				if(thechar == '8') {
+					adduint8(ctxt, rel, 0xff);
+					adduint8(ctxt, rel, 0x25);
+					addaddr(ctxt, rel, targ);
+					adduint8(ctxt, rel, 0x90);
+					adduint8(ctxt, rel, 0x90);
+				} else {
+					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;
+				r->add = targ->plt;
+			}
+		}
+		return;
+	}
+
+	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->reachable)
+				diag("internal inconsistency: dynamic symbol %s is not reachable.", r->sym->name);
+			adddynrel(s, r);
+		}
+	}
+}
+
+void
+dynreloc(void)
+{
+	LSym *s;
+
+	// -d suppresses dynamic loader format, so we may as well not
+	// compute these sections or mark their symbols as reachable.
+	if(debug['d'] && HEADTYPE != Hwindows)
+		return;
+	if(debug['v'])
+		Bprint(&bso, "%5.2f reloc\n", cputime());
+	Bflush(&bso);
+
+	for(s=ctxt->textp; s!=S; s=s->next)
+		dynrelocsym(s);
+	for(s=datap; s!=S; s=s->next)
+		dynrelocsym(s);
+	if(iself)
+		elfdynhash();
+}
+
+static void
+blk(LSym *start, int64 addr, int64 size)
+{
+	LSym *sym;
+	int64 eaddr;
+	uchar *p, *ep;
+
+	for(sym = start; sym != nil; sym = sym->next)
+		if(!(sym->type&SSUB) && sym->value >= addr)
+			break;
+
+	eaddr = addr+size;
+	for(; sym != nil; sym = sym->next) {
+		if(sym->type&SSUB)
+			continue;
+		if(sym->value >= eaddr)
+			break;
+		if(sym->value < addr) {
+			diag("phase error: addr=%#llx but sym=%#llx type=%d", (vlong)addr, (vlong)sym->value, sym->type);
+			errorexit();
+		}
+		ctxt->cursym = sym;
+		for(; addr < sym->value; addr++)
+			cput(0);
+		p = sym->p;
+		ep = p + sym->np;
+		while(p < ep)
+			cput(*p++);
+		addr += sym->np;
+		for(; addr < sym->value+sym->size; addr++)
+			cput(0);
+		if(addr != sym->value+sym->size) {
+			diag("phase error: addr=%#llx value+size=%#llx", (vlong)addr, (vlong)sym->value+sym->size);
+			errorexit();
+		}
+	}
+
+	for(; addr < eaddr; addr++)
+		cput(0);
+	cflush();
+}
+
+void
+codeblk(int64 addr, int64 size)
+{
+	LSym *sym;
+	int64 eaddr, n;
+	uchar *q;
+
+	if(debug['a'])
+		Bprint(&bso, "codeblk [%#x,%#x) at offset %#llx\n", addr, addr+size, cpos());
+
+	blk(ctxt->textp, addr, size);
+
+	/* again for printing */
+	if(!debug['a'])
+		return;
+
+	for(sym = ctxt->textp; sym != nil; sym = sym->next) {
+		if(!sym->reachable)
+			continue;
+		if(sym->value >= addr)
+			break;
+	}
+
+	eaddr = addr + size;
+	for(; sym != nil; sym = sym->next) {
+		if(!sym->reachable)
+			continue;
+		if(sym->value >= eaddr)
+			break;
+
+		if(addr < sym->value) {
+			Bprint(&bso, "%-20s %.8llux|", "_", (vlong)addr);
+			for(; addr < sym->value; addr++)
+				Bprint(&bso, " %.2ux", 0);
+			Bprint(&bso, "\n");
+		}
+
+		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) {
+		Bprint(&bso, "%-20s %.8llux|", "_", (vlong)addr);
+		for(; addr < eaddr; addr++)
+			Bprint(&bso, " %.2ux", 0);
+	}
+	Bflush(&bso);
+}
+
+void
+datblk(int64 addr, int64 size)
+{
+	LSym *sym;
+	int64 i, eaddr;
+	uchar *p, *ep;
+	char *typ, *rsname;
+	Reloc *r;
+
+	if(debug['a'])
+		Bprint(&bso, "datblk [%#x,%#x) at offset %#llx\n", addr, addr+size, cpos());
+
+	blk(datap, addr, size);
+
+	/* again for printing */
+	if(!debug['a'])
+		return;
+
+	for(sym = datap; sym != nil; sym = sym->next)
+		if(sym->value >= addr)
+			break;
+
+	eaddr = addr + size;
+	for(; sym != nil; sym = sym->next) {
+		if(sym->value >= eaddr)
+			break;
+		if(addr < sym->value) {
+			Bprint(&bso, "\t%.8ux| 00 ...\n", addr);
+			addr = sym->value;
+		}
+		Bprint(&bso, "%s\n\t%.8ux|", sym->name, (uint)addr);
+		p = sym->p;
+		ep = p + sym->np;
+		while(p < ep) {
+			if(p > sym->p && (int)(p-sym->p)%16 == 0)
+				Bprint(&bso, "\n\t%.8ux|", (uint)(addr+(p-sym->p)));
+			Bprint(&bso, " %.2ux", *p++);
+		}
+		addr += sym->np;
+		for(; addr < sym->value+sym->size; addr++)
+			Bprint(&bso, " %.2ux", 0);
+		Bprint(&bso, "\n");
+		
+		if(linkmode == LinkExternal) {
+			for(i=0; i<sym->nr; i++) {
+				r = &sym->r[i];
+				rsname = "";
+				if(r->sym)
+					rsname = r->sym->name;
+				typ = "?";
+				switch(r->type) {
+				case R_ADDR:
+					typ = "addr";
+					break;
+				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));
+			}
+		}				
+	}
+
+	if(addr < eaddr)
+		Bprint(&bso, "\t%.8ux| 00 ...\n", (uint)addr);
+	Bprint(&bso, "\t%.8ux|\n", (uint)eaddr);
+}
+
+void
+strnput(char *s, int n)
+{
+	for(; n > 0 && *s; s++) {
+		cput(*s);
+		n--;
+	}
+	while(n > 0) {
+		cput(0);
+		n--;
+	}
+}
+
+void
+addstrdata(char *name, char *value)
+{
+	LSym *s, *sp;
+	char *p;
+	uchar reachable;
+
+	p = smprint("%s.str", name);
+	sp = linklookup(ctxt, p, 0);
+	free(p);
+	addstring(sp, value);
+	sp->type = SRODATA;
+
+	s = linklookup(ctxt, name, 0);
+	s->size = 0;
+	s->dupok = 1;
+	reachable = s->reachable;
+	addaddr(ctxt, s, sp);
+	adduintxx(ctxt, s, strlen(value), PtrSize);
+
+	// addstring, addaddr, etc., mark the symbols as reachable.
+	// In this case that is not necessarily true, so stick to what
+	// we know before entering this function.
+	s->reachable = reachable;
+	sp->reachable = reachable;
+}
+
+vlong
+addstring(LSym *s, char *str)
+{
+	int n;
+	int32 r;
+
+	if(s->type == 0)
+		s->type = SNOPTRDATA;
+	s->reachable = 1;
+	r = s->size;
+	n = strlen(str)+1;
+	if(strcmp(s->name, ".shstrtab") == 0)
+		elfsetstring(str, r);
+	symgrow(ctxt, s, r+n);
+	memmove(s->p+r, str, n);
+	s->size += n;
+	return r;
+}
+
+void
+dosymtype(void)
+{
+	LSym *s;
+
+	for(s = ctxt->allsym; s != nil; s = s->allsym) {
+		if(s->np > 0) {
+			if(s->type == SBSS)
+				s->type = SDATA;
+			if(s->type == SNOPTRBSS)
+				s->type = SNOPTRDATA;
+		}
+	}
+}
+
+static int32
+symalign(LSym *s)
+{
+	int32 align;
+
+	if(s->align != 0)
+		return s->align;
+
+	align = MaxAlign;
+	while(align > s->size && align > 1)
+		align >>= 1;
+	if(align < s->align)
+		align = s->align;
+	return align;
+}
+	
+static vlong
+aligndatsize(vlong datsize, LSym *s)
+{
+	return rnd(datsize, symalign(s));
+}
+
+// maxalign returns the maximum required alignment for
+// the list of symbols s; the list stops when s->type exceeds type.
+static int32
+maxalign(LSym *s, int type)
+{
+	int32 align, max;
+	
+	max = 0;
+	for(; s != S && s->type <= type; s = s->next) {
+		align = symalign(s);
+		if(max < align)
+			max = align;
+	}
+	return max;
+}
+
+// Helper object for building GC type programs.
+typedef struct ProgGen ProgGen;
+struct ProgGen
+{
+	LSym*	s;
+	int32	datasize;
+	uint8	data[256/PointersPerByte];
+	vlong	pos;
+};
+
+static void
+proggeninit(ProgGen *g, LSym *s)
+{
+	g->s = s;
+	g->datasize = 0;
+	g->pos = 0;
+	memset(g->data, 0, sizeof(g->data));
+}
+
+static void
+proggenemit(ProgGen *g, uint8 v)
+{
+	adduint8(ctxt, g->s, v);
+}
+
+// Writes insData block from g->data.
+static void
+proggendataflush(ProgGen *g)
+{
+	int32 i, s;
+
+	if(g->datasize == 0)
+		return;
+	proggenemit(g, insData);
+	proggenemit(g, g->datasize);
+	s = (g->datasize + PointersPerByte - 1)/PointersPerByte;
+	for(i = 0; i < s; i++)
+		proggenemit(g, g->data[i]);
+	g->datasize = 0;
+	memset(g->data, 0, sizeof(g->data));
+}
+
+static void
+proggendata(ProgGen *g, uint8 d)
+{
+	g->data[g->datasize/PointersPerByte] |= d << ((g->datasize%PointersPerByte)*BitsPerPointer);
+	g->datasize++;
+	if(g->datasize == 255)
+		proggendataflush(g);
+}
+
+// Skip v bytes due to alignment, etc.
+static void
+proggenskip(ProgGen *g, vlong off, vlong v)
+{
+	vlong i;
+
+	for(i = off; i < off+v; i++) {
+		if((i%PtrSize) == 0)
+			proggendata(g, BitsScalar);
+	}
+}
+
+// Emit insArray instruction.
+static void
+proggenarray(ProgGen *g, vlong len)
+{
+	int32 i;
+
+	proggendataflush(g);
+	proggenemit(g, insArray);
+	for(i = 0; i < PtrSize; i++, len >>= 8)
+		proggenemit(g, len);
+}
+
+static void
+proggenarrayend(ProgGen *g)
+{
+	proggendataflush(g);
+	proggenemit(g, insArrayEnd);
+}
+
+static void
+proggenfini(ProgGen *g, vlong size)
+{
+	proggenskip(g, g->pos, size - g->pos);
+	proggendataflush(g);
+	proggenemit(g, insEnd);
+}
+
+
+// This function generates GC pointer info for global variables.
+static void
+proggenaddsym(ProgGen *g, LSym *s)
+{
+	LSym *gcprog;
+	uint8 *mask;
+	vlong i, size;
+
+	if(s->size == 0)
+		return;
+
+	// Skip alignment hole from the previous symbol.
+	proggenskip(g, g->pos, s->value - g->pos);
+	g->pos += s->value - g->pos;
+
+	// The test for names beginning with . here is meant
+	// to keep .dynamic and .dynsym from turning up as
+	// conservative symbols. They should be marked SELFSECT
+	// and not SDATA, but sometimes that doesn't happen.
+	// Leave debugging the SDATA issue for the Go rewrite.
+
+	if(s->gotype == nil && s->size >= PtrSize && s->name[0] != '.') {
+		// conservative scan
+		diag("missing Go type information for global symbol: %s size %d", s->name, (int)s->size);
+		if((s->size%PtrSize) || (g->pos%PtrSize))
+			diag("proggenaddsym: unaligned conservative symbol %s: size=%lld pos=%lld",
+				s->name, s->size, g->pos);
+		size = (s->size+PtrSize-1)/PtrSize*PtrSize;
+		if(size < 32*PtrSize) {
+			// Emit small symbols as data.
+			for(i = 0; i < size/PtrSize; i++)
+				proggendata(g, BitsPointer);
+		} else {
+			// Emit large symbols as array.
+			proggenarray(g, size/PtrSize);
+			proggendata(g, BitsPointer);
+			proggenarrayend(g);
+		}
+		g->pos = s->value + size;
+	} else if(s->gotype == nil || decodetype_noptr(s->gotype) || s->size < PtrSize || s->name[0] == '.') {
+		// no scan
+		if(s->size < 32*PtrSize) {
+			// Emit small symbols as data.
+			// This case also handles unaligned and tiny symbols, so tread carefully.
+			for(i = s->value; i < s->value+s->size; i++) {
+				if((i%PtrSize) == 0)
+					proggendata(g, BitsScalar);
+			}
+		} else {
+			// Emit large symbols as array.
+			if((s->size%PtrSize) || (g->pos%PtrSize))
+				diag("proggenaddsym: unaligned noscan symbol %s: size=%lld pos=%lld",
+					s->name, s->size, g->pos);
+			proggenarray(g, s->size/PtrSize);
+			proggendata(g, BitsScalar);
+			proggenarrayend(g);
+		}
+		g->pos = s->value + s->size;
+	} else if(decodetype_usegcprog(s->gotype)) {
+		// gc program, copy directly
+		proggendataflush(g);
+		gcprog = decodetype_gcprog(s->gotype);
+		size = decodetype_size(s->gotype);
+		if((size%PtrSize) || (g->pos%PtrSize))
+			diag("proggenaddsym: unaligned gcprog symbol %s: size=%lld pos=%lld",
+				s->name, s->size, g->pos);
+		for(i = 0; i < gcprog->np-1; i++)
+			proggenemit(g, gcprog->p[i]);
+		g->pos = s->value + size;
+	} else {
+		// gc mask, it's small so emit as data
+		mask = decodetype_gcmask(s->gotype);
+		size = decodetype_size(s->gotype);
+		if((size%PtrSize) || (g->pos%PtrSize))
+			diag("proggenaddsym: unaligned gcmask symbol %s: size=%lld pos=%lld",
+				s->name, s->size, g->pos);
+		for(i = 0; i < size; i += PtrSize)
+			proggendata(g, (mask[i/PtrSize/2]>>((i/PtrSize%2)*4+2))&BitsMask);
+		g->pos = s->value + size;
+	}
+}
+
+void
+growdatsize(vlong *datsizep, LSym *s)
+{
+	vlong datsize;
+	
+	datsize = *datsizep;
+	if(s->size < 0)
+		diag("negative size (datsize = %lld, s->size = %lld)", datsize, s->size);
+	if(datsize + s->size < datsize)
+		diag("symbol too large (datsize = %lld, s->size = %lld)", datsize, s->size);
+	*datsizep = datsize + s->size;
+}
+
+void
+dodata(void)
+{
+	int32 n;
+	vlong datsize;
+	Section *sect;
+	Segment *segro;
+	LSym *s, *last, **l;
+	LSym *gcdata, *gcbss;
+	ProgGen gen;
+
+	if(debug['v'])
+		Bprint(&bso, "%5.2f dodata\n", cputime());
+	Bflush(&bso);
+
+	last = nil;
+	datap = nil;
+
+	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
+				last->next = s;
+			s->next = nil;
+			last = s;
+		}
+	}
+
+	for(s = datap; s != nil; s = s->next) {
+		if(s->np > s->size)
+			diag("%s: initialize bounds (%lld < %d)",
+				s->name, (vlong)s->size, s->np);
+	}
+
+
+	/*
+	 * now that we have the datap list, but before we start
+	 * to assign addresses, record all the necessary
+	 * dynamic relocations.  these will grow the relocation
+	 * symbol, which is itself data.
+	 *
+	 * on darwin, we need the symbol table numbers for dynreloc.
+	 */
+	if(HEADTYPE == Hdarwin)
+		machosymorder();
+	dynreloc();
+
+	/* some symbols may no longer belong in datap (Mach-O) */
+	for(l=&datap; (s=*l) != nil; ) {
+		if(s->type <= STEXT || SXREF <= s->type)
+			*l = s->next;
+		else
+			l = &s->next;
+	}
+	*l = nil;
+
+	datap = listsort(datap, datcmp, offsetof(LSym, next));
+
+	/*
+	 * allocate sections.  list is sorted by type,
+	 * so we can just walk it for each piece we want to emit.
+	 * segdata is processed before segtext, because we need
+	 * to see all symbols in the .data and .bss sections in order
+	 * to generate garbage collection information.
+	 */
+
+	/* begin segdata */
+
+	/* skip symbols belonging to segtext */
+	s = datap;
+	for(; s != nil && s->type < SELFSECT; s = s->next)
+		;
+
+	/* writable ELF sections */
+	datsize = 0;
+	for(; s != nil && s->type < SNOPTRDATA; s = s->next) {
+		sect = addsection(&segdata, s->name, 06);
+		sect->align = symalign(s);
+		datsize = rnd(datsize, sect->align);
+		sect->vaddr = datsize;
+		s->sect = sect;
+		s->type = SDATA;
+		s->value = datsize - sect->vaddr;
+		growdatsize(&datsize, s);
+		sect->len = datsize - sect->vaddr;
+	}
+
+	/* pointer-free data */
+	sect = addsection(&segdata, ".noptrdata", 06);
+	sect->align = maxalign(s, SINITARR-1);
+	datsize = rnd(datsize, sect->align);
+	sect->vaddr = datsize;
+	linklookup(ctxt, "runtime.noptrdata", 0)->sect = sect;
+	linklookup(ctxt, "runtime.enoptrdata", 0)->sect = sect;
+	for(; s != nil && s->type < SINITARR; s = s->next) {
+		datsize = aligndatsize(datsize, s);
+		s->sect = sect;
+		s->type = SDATA;
+		s->value = datsize - sect->vaddr;
+		growdatsize(&datsize, s);
+	}
+	sect->len = datsize - sect->vaddr;
+
+	/* shared library initializer */
+	if(flag_shared) {
+		sect = addsection(&segdata, ".init_array", 06);
+		sect->align = maxalign(s, SINITARR);
+		datsize = rnd(datsize, sect->align);
+		sect->vaddr = datsize;
+		for(; s != nil && s->type == SINITARR; s = s->next) {
+			datsize = aligndatsize(datsize, s);
+			s->sect = sect;
+			s->value = datsize - sect->vaddr;
+			growdatsize(&datsize, s);
+		}
+		sect->len = datsize - sect->vaddr;
+	}
+
+	/* data */
+	sect = addsection(&segdata, ".data", 06);
+	sect->align = maxalign(s, SBSS-1);
+	datsize = rnd(datsize, sect->align);
+	sect->vaddr = datsize;
+	linklookup(ctxt, "runtime.data", 0)->sect = sect;
+	linklookup(ctxt, "runtime.edata", 0)->sect = sect;
+	gcdata = linklookup(ctxt, "runtime.gcdata", 0);
+	proggeninit(&gen, gcdata);
+	for(; s != nil && s->type < SBSS; s = s->next) {
+		if(s->type == SINITARR) {
+			ctxt->cursym = s;
+			diag("unexpected symbol type %d", s->type);
+		}
+		s->sect = sect;
+		s->type = SDATA;
+		datsize = aligndatsize(datsize, s);
+		s->value = datsize - sect->vaddr;
+		proggenaddsym(&gen, s);  // gc
+		growdatsize(&datsize, s);
+	}
+	sect->len = datsize - sect->vaddr;
+	proggenfini(&gen, sect->len);  // gc
+
+	/* bss */
+	sect = addsection(&segdata, ".bss", 06);
+	sect->align = maxalign(s, SNOPTRBSS-1);
+	datsize = rnd(datsize, sect->align);
+	sect->vaddr = datsize;
+	linklookup(ctxt, "runtime.bss", 0)->sect = sect;
+	linklookup(ctxt, "runtime.ebss", 0)->sect = sect;
+	gcbss = linklookup(ctxt, "runtime.gcbss", 0);
+	proggeninit(&gen, gcbss);
+	for(; s != nil && s->type < SNOPTRBSS; s = s->next) {
+		s->sect = sect;
+		datsize = aligndatsize(datsize, s);
+		s->value = datsize - sect->vaddr;
+		proggenaddsym(&gen, s);  // gc
+		growdatsize(&datsize, s);
+	}
+	sect->len = datsize - sect->vaddr;
+	proggenfini(&gen, sect->len);  // gc
+
+	/* pointer-free bss */
+	sect = addsection(&segdata, ".noptrbss", 06);
+	sect->align = maxalign(s, SNOPTRBSS);
+	datsize = rnd(datsize, sect->align);
+	sect->vaddr = datsize;
+	linklookup(ctxt, "runtime.noptrbss", 0)->sect = sect;
+	linklookup(ctxt, "runtime.enoptrbss", 0)->sect = sect;
+	for(; s != nil && s->type == SNOPTRBSS; s = s->next) {
+		datsize = aligndatsize(datsize, s);
+		s->sect = sect;
+		s->value = datsize - sect->vaddr;
+		growdatsize(&datsize, s);
+	}
+	sect->len = datsize - sect->vaddr;
+	linklookup(ctxt, "runtime.end", 0)->sect = sect;
+
+	// 6g uses 4-byte relocation offsets, so the entire segment must fit in 32 bits.
+	if(datsize != (uint32)datsize) {
+		diag("data or bss segment too large");
+	}
+	
+	if(iself && linkmode == LinkExternal && s != nil && s->type == STLSBSS && HEADTYPE != Hopenbsd) {
+		sect = addsection(&segdata, ".tbss", 06);
+		sect->align = PtrSize;
+		sect->vaddr = 0;
+		datsize = 0;
+		for(; s != nil && s->type == STLSBSS; s = s->next) {
+			datsize = aligndatsize(datsize, s);
+			s->sect = sect;
+			s->value = datsize - sect->vaddr;
+			growdatsize(&datsize, s);
+		}
+		sect->len = datsize;
+	} else {
+		// Might be internal linking but still using cgo.
+		// In that case, the only possible STLSBSS symbol is runtime.tlsg.
+		// Give it offset 0, because it's the only thing here.
+		if(s != nil && s->type == STLSBSS && strcmp(s->name, "runtime.tlsg") == 0) {
+			s->value = 0;
+			s = s->next;
+		}
+	}
+	
+	if(s != nil) {
+		ctxt->cursym = nil;
+		diag("unexpected symbol type %d for %s", s->type, s->name);
+	}
+
+	/*
+	 * We finished data, begin read-only data.
+	 * Not all systems support a separate read-only non-executable data section.
+	 * ELF systems do.
+	 * OS X and Plan 9 do not.
+	 * Windows PE may, but if so we have not implemented it.
+	 * And if we're using external linking mode, the point is moot,
+	 * since it's not our decision; that code expects the sections in
+	 * segtext.
+	 */
+	if(iself && linkmode == LinkInternal)
+		segro = &segrodata;
+	else
+		segro = &segtext;
+
+	s = datap;
+	
+	datsize = 0;
+	
+	/* read-only executable ELF, Mach-O sections */
+	for(; s != nil && s->type < STYPE; s = s->next) {
+		sect = addsection(&segtext, s->name, 04);
+		sect->align = symalign(s);
+		datsize = rnd(datsize, sect->align);
+		sect->vaddr = datsize;
+		s->sect = sect;
+		s->type = SRODATA;
+		s->value = datsize - sect->vaddr;
+		growdatsize(&datsize, s);
+		sect->len = datsize - sect->vaddr;
+	}
+
+	/* read-only data */
+	sect = addsection(segro, ".rodata", 04);
+	sect->align = maxalign(s, STYPELINK-1);
+	datsize = rnd(datsize, sect->align);
+	sect->vaddr = 0;
+	linklookup(ctxt, "runtime.rodata", 0)->sect = sect;
+	linklookup(ctxt, "runtime.erodata", 0)->sect = sect;
+	for(; s != nil && s->type < STYPELINK; s = s->next) {
+		datsize = aligndatsize(datsize, s);
+		s->sect = sect;
+		s->type = SRODATA;
+		s->value = datsize - sect->vaddr;
+		growdatsize(&datsize, s);
+	}
+	sect->len = datsize - sect->vaddr;
+
+	/* typelink */
+	sect = addsection(segro, ".typelink", 04);
+	sect->align = maxalign(s, STYPELINK);
+	datsize = rnd(datsize, sect->align);
+	sect->vaddr = datsize;
+	linklookup(ctxt, "runtime.typelink", 0)->sect = sect;
+	linklookup(ctxt, "runtime.etypelink", 0)->sect = sect;
+	for(; s != nil && s->type == STYPELINK; s = s->next) {
+		datsize = aligndatsize(datsize, s);
+		s->sect = sect;
+		s->type = SRODATA;
+		s->value = datsize - sect->vaddr;
+		growdatsize(&datsize, s);
+	}
+	sect->len = datsize - sect->vaddr;
+
+	/* gosymtab */
+	sect = addsection(segro, ".gosymtab", 04);
+	sect->align = maxalign(s, SPCLNTAB-1);
+	datsize = rnd(datsize, sect->align);
+	sect->vaddr = datsize;
+	linklookup(ctxt, "runtime.symtab", 0)->sect = sect;
+	linklookup(ctxt, "runtime.esymtab", 0)->sect = sect;
+	for(; s != nil && s->type < SPCLNTAB; s = s->next) {
+		datsize = aligndatsize(datsize, s);
+		s->sect = sect;
+		s->type = SRODATA;
+		s->value = datsize - sect->vaddr;
+		growdatsize(&datsize, s);
+	}
+	sect->len = datsize - sect->vaddr;
+
+	/* gopclntab */
+	sect = addsection(segro, ".gopclntab", 04);
+	sect->align = maxalign(s, SELFROSECT-1);
+	datsize = rnd(datsize, sect->align);
+	sect->vaddr = datsize;
+	linklookup(ctxt, "runtime.pclntab", 0)->sect = sect;
+	linklookup(ctxt, "runtime.epclntab", 0)->sect = sect;
+	for(; s != nil && s->type < SELFROSECT; s = s->next) {
+		datsize = aligndatsize(datsize, s);
+		s->sect = sect;
+		s->type = SRODATA;
+		s->value = datsize - sect->vaddr;
+		growdatsize(&datsize, s);
+	}
+	sect->len = datsize - sect->vaddr;
+
+	/* read-only ELF, Mach-O sections */
+	for(; s != nil && s->type < SELFSECT; s = s->next) {
+		sect = addsection(segro, s->name, 04);
+		sect->align = symalign(s);
+		datsize = rnd(datsize, sect->align);
+		sect->vaddr = datsize;
+		s->sect = sect;
+		s->type = SRODATA;
+		s->value = datsize - sect->vaddr;
+		growdatsize(&datsize, s);
+		sect->len = datsize - sect->vaddr;
+	}
+
+	// 6g uses 4-byte relocation offsets, so the entire segment must fit in 32 bits.
+	if(datsize != (uint32)datsize) {
+		diag("read-only data segment too large");
+	}
+	
+	/* number the sections */
+	n = 1;
+	for(sect = segtext.sect; sect != nil; sect = sect->next)
+		sect->extnum = n++;
+	for(sect = segrodata.sect; sect != nil; sect = sect->next)
+		sect->extnum = n++;
+	for(sect = segdata.sect; sect != nil; sect = sect->next)
+		sect->extnum = n++;
+}
+
+// assign addresses to text
+void
+textaddress(void)
+{
+	uvlong va;
+	Section *sect;
+	LSym *sym, *sub;
+
+	addsection(&segtext, ".text", 05);
+
+	// Assign PCs in text segment.
+	// Could parallelize, by assigning to text
+	// and then letting threads copy down, but probably not worth it.
+	sect = segtext.sect;
+	sect->align = funcalign;
+	linklookup(ctxt, "runtime.text", 0)->sect = sect;
+	linklookup(ctxt, "runtime.etext", 0)->sect = sect;
+	va = INITTEXT;
+	sect->vaddr = va;
+	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
+			va = rnd(va, funcalign);
+		sym->value = 0;
+		for(sub = sym; sub != S; sub = sub->sub)
+			sub->value += va;
+		if(sym->size == 0 && sym->sub != S)
+			ctxt->cursym = sym;
+		va += sym->size;
+	}
+	sect->len = va - sect->vaddr;
+}
+
+// assign addresses
+void
+address(void)
+{
+	Section *s, *text, *data, *rodata, *symtab, *pclntab, *noptr, *bss, *noptrbss;
+	Section *typelink;
+	LSym *sym, *sub;
+	uvlong va;
+	vlong vlen;
+
+	va = INITTEXT;
+	segtext.rwx = 05;
+	segtext.vaddr = va;
+	segtext.fileoff = HEADR;
+	for(s=segtext.sect; s != nil; s=s->next) {
+		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
+		// rodata and executable text.
+		va = rnd(va, INITRND);
+
+		segrodata.rwx = 04;
+		segrodata.vaddr = va;
+		segrodata.fileoff = va - segtext.vaddr + segtext.fileoff;
+		segrodata.filelen = 0;
+		for(s=segrodata.sect; s != nil; s=s->next) {
+			va = rnd(va, s->align);
+			s->vaddr = va;
+			va += s->len;
+		}
+		segrodata.len = va - segrodata.vaddr;
+		segrodata.filelen = segrodata.len;
+	}
+
+	va = rnd(va, INITRND);
+	segdata.rwx = 06;
+	segdata.vaddr = va;
+	segdata.fileoff = va - segtext.vaddr + segtext.fileoff;
+	segdata.filelen = 0;
+	if(HEADTYPE == Hwindows)
+		segdata.fileoff = segtext.fileoff + rnd(segtext.len, PEFILEALIGN);
+	if(HEADTYPE == Hplan9)
+		segdata.fileoff = segtext.fileoff + segtext.filelen;
+	data = nil;
+	noptr = nil;
+	bss = nil;
+	noptrbss = nil;
+	for(s=segdata.sect; s != nil; s=s->next) {
+		vlen = s->len;
+		if(s->next)
+			vlen = s->next->vaddr - s->vaddr;
+		s->vaddr = va;
+		va += vlen;
+		segdata.len = va - segdata.vaddr;
+		if(strcmp(s->name, ".data") == 0)
+			data = s;
+		if(strcmp(s->name, ".noptrdata") == 0)
+			noptr = s;
+		if(strcmp(s->name, ".bss") == 0)
+			bss = s;
+		if(strcmp(s->name, ".noptrbss") == 0)
+			noptrbss = s;
+	}
+	segdata.filelen = bss->vaddr - segdata.vaddr;
+
+	text = segtext.sect;
+	if(segrodata.sect)
+		rodata = segrodata.sect;
+	else
+		rodata = text->next;
+	typelink = rodata->next;
+	symtab = typelink->next;
+	pclntab = symtab->next;
+
+	for(sym = datap; sym != nil; sym = sym->next) {
+		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;
+	}
+
+	xdefine("runtime.text", STEXT, text->vaddr);
+	xdefine("runtime.etext", STEXT, text->vaddr + text->len);
+	xdefine("runtime.rodata", SRODATA, rodata->vaddr);
+	xdefine("runtime.erodata", SRODATA, rodata->vaddr + rodata->len);
+	xdefine("runtime.typelink", SRODATA, typelink->vaddr);
+	xdefine("runtime.etypelink", SRODATA, typelink->vaddr + typelink->len);
+
+	sym = linklookup(ctxt, "runtime.gcdata", 0);
+	xdefine("runtime.egcdata", SRODATA, symaddr(sym) + sym->size);
+	linklookup(ctxt, "runtime.egcdata", 0)->sect = sym->sect;
+
+	sym = linklookup(ctxt, "runtime.gcbss", 0);
+	xdefine("runtime.egcbss", SRODATA, symaddr(sym) + sym->size);
+	linklookup(ctxt, "runtime.egcbss", 0)->sect = sym->sect;
+
+	xdefine("runtime.symtab", SRODATA, symtab->vaddr);
+	xdefine("runtime.esymtab", SRODATA, symtab->vaddr + symtab->len);
+	xdefine("runtime.pclntab", SRODATA, pclntab->vaddr);
+	xdefine("runtime.epclntab", SRODATA, pclntab->vaddr + pclntab->len);
+	xdefine("runtime.noptrdata", SNOPTRDATA, noptr->vaddr);
+	xdefine("runtime.enoptrdata", SNOPTRDATA, noptr->vaddr + noptr->len);
+	xdefine("runtime.bss", SBSS, bss->vaddr);
+	xdefine("runtime.ebss", SBSS, bss->vaddr + bss->len);
+	xdefine("runtime.data", SDATA, data->vaddr);
+	xdefine("runtime.edata", SDATA, data->vaddr + data->len);
+	xdefine("runtime.noptrbss", SNOPTRBSS, noptrbss->vaddr);
+	xdefine("runtime.enoptrbss", SNOPTRBSS, noptrbss->vaddr + noptrbss->len);
+	xdefine("runtime.end", SBSS, segdata.vaddr + segdata.len);
+}
diff --git a/src/cmd/ld/decodesym.c b/src/cmd/ld/decodesym.c
new file mode 100644
index 0000000..037263d
--- /dev/null
+++ b/src/cmd/ld/decodesym.c
@@ -0,0 +1,248 @@
+// 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	"l.h"
+#include	"lib.h"
+#include	"../../runtime/typekind.h"
+
+// Decoding the type.* symbols.	 This has to be in sync with
+// ../../runtime/type.go, or more specificaly, with what
+// ../gc/reflect.c stuffs in these.
+
+static Reloc*
+decode_reloc(LSym *s, int32 off)
+{
+	int i;
+
+	for (i = 0; i < s->nr; i++)
+		if (s->r[i].off == off)
+			return s->r + i;
+	return nil;
+}
+
+static LSym*
+decode_reloc_sym(LSym *s, int32 off)
+{
+	Reloc *r;
+
+	r = decode_reloc(s,off);
+	if (r == nil)
+		return nil;
+	return r->sym;
+}
+
+static uvlong
+decode_inuxi(uchar* p, int sz)
+{
+	uint64 v;
+	uint32 l;
+	uchar *cast, *inuxi;
+	int i;
+
+	v = l = 0;
+	cast = nil;
+	inuxi = nil;
+	switch (sz) {
+	case 2:
+		cast = (uchar*)&l;
+		inuxi = inuxi2;
+		break;
+	case 4:
+		cast = (uchar*)&l;
+		inuxi = inuxi4;
+		break;
+	case 8:
+		cast = (uchar*)&v;
+		inuxi = inuxi8;
+		break;
+	default:
+		diag("dwarf: decode inuxi %d", sz);
+		errorexit();
+	}
+	for (i = 0; i < sz; i++)
+		cast[inuxi[i]] = p[i];
+	if (sz == 8)
+		return v;
+	return l;
+}
+
+static int
+commonsize(void)
+{
+	return 8*PtrSize + 8;
+}
+
+// Type.commonType.kind
+uint8
+decodetype_kind(LSym *s)
+{
+	return s->p[1*PtrSize + 7] & KindMask;	//  0x13 / 0x1f
+}
+
+// Type.commonType.kind
+uint8
+decodetype_noptr(LSym *s)
+{
+	return s->p[1*PtrSize + 7] & KindNoPointers;	//  0x13 / 0x1f
+}
+
+// Type.commonType.kind
+uint8
+decodetype_usegcprog(LSym *s)
+{
+	return s->p[1*PtrSize + 7] & KindGCProg;	//  0x13 / 0x1f
+}
+
+// Type.commonType.size
+vlong
+decodetype_size(LSym *s)
+{
+	return decode_inuxi(s->p, PtrSize);	 // 0x8 / 0x10
+}
+
+// Type.commonType.gc
+LSym*
+decodetype_gcprog(LSym *s)
+{
+	return decode_reloc_sym(s, 1*PtrSize + 8 + 2*PtrSize);
+}
+
+uint8*
+decodetype_gcmask(LSym *s)
+{
+	LSym *mask;
+	
+	mask = decode_reloc_sym(s, 1*PtrSize + 8 + 1*PtrSize);
+	return mask->p;
+}
+
+// Type.ArrayType.elem and Type.SliceType.Elem
+LSym*
+decodetype_arrayelem(LSym *s)
+{
+	return decode_reloc_sym(s, commonsize());	// 0x1c / 0x30
+}
+
+vlong
+decodetype_arraylen(LSym *s)
+{
+	return decode_inuxi(s->p + commonsize()+2*PtrSize, PtrSize);
+}
+
+// Type.PtrType.elem
+LSym*
+decodetype_ptrelem(LSym *s)
+{
+	return decode_reloc_sym(s, commonsize());	// 0x1c / 0x30
+}
+
+// Type.MapType.key, elem
+LSym*
+decodetype_mapkey(LSym *s)
+{
+	return decode_reloc_sym(s, commonsize());	// 0x1c / 0x30
+}
+
+LSym*
+decodetype_mapvalue(LSym *s)
+{
+	return decode_reloc_sym(s, commonsize()+PtrSize);	// 0x20 / 0x38
+}
+
+// Type.ChanType.elem
+LSym*
+decodetype_chanelem(LSym *s)
+{
+	return decode_reloc_sym(s, commonsize());	// 0x1c / 0x30
+}
+
+// Type.FuncType.dotdotdot
+int
+decodetype_funcdotdotdot(LSym *s)
+{
+	return s->p[commonsize()];
+}
+
+// Type.FuncType.in.len
+int
+decodetype_funcincount(LSym *s)
+{
+	return decode_inuxi(s->p + commonsize()+2*PtrSize, IntSize);
+}
+
+int
+decodetype_funcoutcount(LSym *s)
+{
+	return decode_inuxi(s->p + commonsize()+3*PtrSize + 2*IntSize, IntSize);
+}
+
+LSym*
+decodetype_funcintype(LSym *s, int i)
+{
+	Reloc *r;
+
+	r = decode_reloc(s, commonsize() + PtrSize);
+	if (r == nil)
+		return nil;
+	return decode_reloc_sym(r->sym, r->add + i * PtrSize);
+}
+
+LSym*
+decodetype_funcouttype(LSym *s, int i)
+{
+	Reloc *r;
+
+	r = decode_reloc(s, commonsize() + 2*PtrSize + 2*IntSize);
+	if (r == nil)
+		return nil;
+	return decode_reloc_sym(r->sym, r->add + i * PtrSize);
+}
+
+// Type.StructType.fields.Slice::len
+int
+decodetype_structfieldcount(LSym *s)
+{
+	return decode_inuxi(s->p + commonsize() + PtrSize, IntSize);
+}
+
+static int
+structfieldsize(void)
+{
+	return 5*PtrSize;
+}
+
+// Type.StructType.fields[]-> name, typ and offset.
+char*
+decodetype_structfieldname(LSym *s, int i)
+{
+	Reloc *r;
+
+	// go.string."foo"  0x28 / 0x40
+	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
+	if (r == nil)			// shouldn't happen.
+		return nil;
+	return (char*) r->sym->p + r->add;	// the c-string
+}
+
+LSym*
+decodetype_structfieldtype(LSym *s, int i)
+{
+	return decode_reloc_sym(s, commonsize() + PtrSize + 2*IntSize + i*structfieldsize() + 2*PtrSize);
+}
+
+vlong
+decodetype_structfieldoffs(LSym *s, int i)
+{
+	return decode_inuxi(s->p + commonsize() + PtrSize + 2*IntSize + i*structfieldsize() + 4*PtrSize, IntSize);
+}
+
+// InterfaceTYpe.methods.len
+vlong
+decodetype_ifacemethodcount(LSym *s)
+{
+	return decode_inuxi(s->p + commonsize() + PtrSize, IntSize);
+}
diff --git a/src/cmd/ld/doc.go b/src/cmd/ld/doc.go
new file mode 100644
index 0000000..5b5833d
--- /dev/null
+++ b/src/cmd/ld/doc.go
@@ -0,0 +1,100 @@
+// 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
+
+/*
+
+Ld is the portable code for a modified version of the Plan 9 linker.  The original is documented at
+
+	http://plan9.bell-labs.com/magic/man2html/1/8l
+
+It reads object files (.5, .6, or .8 files) and writes a binary named for the
+architecture (5.out, 6.out, 8.out) by default (if $GOOS is windows, a .exe suffix
+will be appended).
+
+Major changes include:
+	- support for ELF, Mach-O and PE binary files
+	- support for segmented stacks (this feature is implemented here, not in the compilers).
+
+Original options are listed on the manual page linked above.
+
+Usage:
+	go tool 6l [flags] mainObj
+Substitute 6l with 8l or 5l as appropriate.
+
+Options new in this version:
+
+	-d
+		Elide the dynamic linking header.  With this option, the binary
+		is statically linked and does not refer to a dynamic linker.  Without this option
+		(the default), the binary's contents are identical but it is loaded with a dynamic
+		linker. This flag cannot be used when $GOOS is windows.
+	-H darwin     (only in 6l/8l)
+		Write Apple Mach-O binaries (default when $GOOS is darwin)
+	-H dragonfly  (only in 6l/8l)
+		Write DragonFly ELF binaries (default when $GOOS is dragonfly)
+	-H linux
+		Write Linux ELF binaries (default when $GOOS is linux)
+	-H freebsd
+		Write FreeBSD ELF binaries (default when $GOOS is freebsd)
+	-H netbsd
+		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)
+		Write Windows PE32+ GUI binaries
+	-I interpreter
+		Set the ELF dynamic linker to use.
+	-L dir1 -L dir2
+		Search for libraries (package files) in dir1, dir2, etc.
+		The default is the single location $GOROOT/pkg/$GOOS_$GOARCH.
+	-r dir1:dir2:...
+		Set the dynamic linker search path when using ELF.
+	-s
+		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 a string variable. The symbol name
+		should be of the form importpath.name, as displayed
+		in the symbol table printed by "go tool nm".
+	-race
+		Link with race detection libraries.
+	-B value
+		Add a NT_GNU_BUILD_ID note when using ELF.  The value
+		should start with 0x and be an even number of hex digits.
+	-Z
+		Zero stack on function entry. This is expensive but it might
+		be useful in cases where you are suffering from false positives
+		during garbage collection and are willing to trade the CPU time
+		for getting rid of the false positives.
+		NOTE: it only eliminates false positives caused by other function
+		calls, not false positives caused by dead temporaries stored in
+		the current function call.
+	-linkmode argument
+		Set the linkmode.  The argument must be one of
+		internal, external, or auto.  The default is auto.
+		This sets the linking mode as described in
+		../cgo/doc.go.
+	-tmpdir dir
+		Set the location to use for any temporary files.  The
+		default is a newly created directory that is removed
+		after the linker completes.  Temporary files are only
+		used in external linking mode.
+	-extld name
+		Set the name of the external linker to use in external
+		linking mode.  The default is "gcc".
+	-extldflags flags
+		Set space-separated trailing flags to pass to the
+		external linker in external linking mode.  The default
+		is to not pass any additional trailing flags.
+*/
+package main
diff --git a/src/cmd/ld/dwarf.c b/src/cmd/ld/dwarf.c
new file mode 100644
index 0000000..dfe515c
--- /dev/null
+++ b/src/cmd/ld/dwarf.c
@@ -0,0 +1,2466 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// TODO/NICETOHAVE:
+//   - eliminate DW_CLS_ if not used
+//   - package info in compilation units
+//   - assign global variables and types to their packages
+//   - gdb uses c syntax, meaning clumsy quoting is needed for go identifiers. eg
+//     ptype struct '[]uint8' and qualifiers need to be quoted away
+//   - lexical scoping is lost, so gdb gets confused as to which 'main.i' you mean.
+//   - file:line info for variables
+//   - make strings a typedef so prettyprinters can see the underlying string type
+//
+#include	"l.h"
+#include	"lib.h"
+#include	"../ld/dwarf.h"
+#include	"../ld/dwarf_defs.h"
+#include	"../ld/elf.h"
+#include	"../ld/macho.h"
+#include	"../ld/pe.h"
+#include	"../../runtime/typekind.h"
+
+/*
+ * Offsets and sizes of the debug_* sections in the cout file.
+ */
+
+static vlong abbrevo;
+static vlong abbrevsize;
+static LSym*  abbrevsym;
+static vlong abbrevsympos;
+static vlong lineo;
+static vlong linesize;
+static LSym*  linesym;
+static vlong linesympos;
+static vlong infoo;	// also the base for DWDie->offs and reference attributes.
+static vlong infosize;
+static LSym*  infosym;
+static vlong infosympos;
+static vlong frameo;
+static vlong framesize;
+static LSym*  framesym;
+static vlong framesympos;
+static vlong pubnameso;
+static vlong pubnamessize;
+static vlong pubtypeso;
+static vlong pubtypessize;
+static vlong arangeso;
+static vlong arangessize;
+static vlong gdbscripto;
+static vlong gdbscriptsize;
+
+static LSym *infosec;
+static vlong inforeloco;
+static vlong inforelocsize;
+
+static LSym *arangessec;
+static vlong arangesreloco;
+static vlong arangesrelocsize;
+
+static LSym *linesec;
+static vlong linereloco;
+static vlong linerelocsize;
+
+static LSym *framesec;
+static vlong framereloco;
+static vlong framerelocsize;
+
+static char  gdbscript[1024];
+
+/*
+ *  Basic I/O
+ */
+
+static void
+addrput(vlong addr)
+{
+	switch(PtrSize) {
+	case 4:
+		LPUT(addr);
+		break;
+	case 8:
+		VPUT(addr);
+		break;
+	}
+}
+
+static int
+uleb128enc(uvlong v, char* dst)
+{
+	uint8 c, len;
+
+	len = 0;
+	do {
+		c = v & 0x7f;
+		v >>= 7;
+		if (v)
+			c |= 0x80;
+		if (dst)
+			*dst++ = c;
+		len++;
+	} while (c & 0x80);
+	return len;
+};
+
+static int
+sleb128enc(vlong v, char *dst)
+{
+	uint8 c, s, len;
+
+	len = 0;
+	do {
+		c = v & 0x7f;
+		s = v & 0x40;
+		v >>= 7;
+		if ((v != -1 || !s) && (v != 0 || s))
+			c |= 0x80;
+		if (dst)
+			*dst++ = c;
+		len++;
+	} while(c & 0x80);
+	return len;
+}
+
+static void
+uleb128put(vlong v)
+{
+	char buf[10];
+	strnput(buf, uleb128enc(v, buf));
+}
+
+static void
+sleb128put(vlong v)
+{
+	char buf[10];
+	strnput(buf, sleb128enc(v, buf));
+}
+
+/*
+ * Defining Abbrevs.  This is hardcoded, and there will be
+ * only a handful of them.  The DWARF spec places no restriction on
+ * the ordering of attributes in the Abbrevs and DIEs, and we will
+ * always write them out in the order of declaration in the abbrev.
+ */
+typedef struct DWAttrForm DWAttrForm;
+struct DWAttrForm {
+	uint16 attr;
+	uint8 form;
+};
+
+// Go-specific type attributes.
+enum {
+	DW_AT_go_kind = 0x2900,
+	DW_AT_go_key = 0x2901,
+	DW_AT_go_elem = 0x2902,
+
+	DW_AT_internal_location = 253,	 // params and locals; not emitted
+};
+
+// Index into the abbrevs table below.
+// Keep in sync with ispubname() and ispubtype() below.
+// ispubtype considers >= NULLTYPE public
+enum
+{
+	DW_ABRV_NULL,
+	DW_ABRV_COMPUNIT,
+	DW_ABRV_FUNCTION,
+	DW_ABRV_VARIABLE,
+	DW_ABRV_AUTO,
+	DW_ABRV_PARAM,
+	DW_ABRV_STRUCTFIELD,
+	DW_ABRV_FUNCTYPEPARAM,
+	DW_ABRV_DOTDOTDOT,
+	DW_ABRV_ARRAYRANGE,
+	DW_ABRV_NULLTYPE,
+	DW_ABRV_BASETYPE,
+	DW_ABRV_ARRAYTYPE,
+	DW_ABRV_CHANTYPE,
+	DW_ABRV_FUNCTYPE,
+	DW_ABRV_IFACETYPE,
+	DW_ABRV_MAPTYPE,
+	DW_ABRV_PTRTYPE,
+	DW_ABRV_BARE_PTRTYPE, // only for void*, no DW_AT_type attr to please gdb 6.
+	DW_ABRV_SLICETYPE,
+	DW_ABRV_STRINGTYPE,
+	DW_ABRV_STRUCTTYPE,
+	DW_ABRV_TYPEDECL,
+	DW_NABRV
+};
+
+typedef struct DWAbbrev DWAbbrev;
+static struct DWAbbrev {
+	uint8 tag;
+	uint8 children;
+	DWAttrForm attr[30];
+} abbrevs[DW_NABRV] = {
+	/* The mandatory DW_ABRV_NULL entry. */
+	{ 0 },
+	/* COMPUNIT */
+	{
+		DW_TAG_compile_unit, DW_CHILDREN_yes,
+		DW_AT_name,	 DW_FORM_string,
+		DW_AT_language,	 DW_FORM_data1,
+		DW_AT_low_pc,	 DW_FORM_addr,
+		DW_AT_high_pc,	 DW_FORM_addr,
+		DW_AT_stmt_list, DW_FORM_data4,
+		0, 0
+	},
+	/* FUNCTION */
+	{
+		DW_TAG_subprogram, DW_CHILDREN_yes,
+		DW_AT_name,	 DW_FORM_string,
+		DW_AT_low_pc,	 DW_FORM_addr,
+		DW_AT_high_pc,	 DW_FORM_addr,
+		DW_AT_external,	 DW_FORM_flag,
+		0, 0
+	},
+	/* VARIABLE */
+	{
+		DW_TAG_variable, DW_CHILDREN_no,
+		DW_AT_name,	 DW_FORM_string,
+		DW_AT_location,	 DW_FORM_block1,
+		DW_AT_type,	 DW_FORM_ref_addr,
+		DW_AT_external,	 DW_FORM_flag,
+		0, 0
+	},
+	/* AUTO */
+	{
+		DW_TAG_variable, DW_CHILDREN_no,
+		DW_AT_name,	 DW_FORM_string,
+		DW_AT_location,	 DW_FORM_block1,
+		DW_AT_type,	 DW_FORM_ref_addr,
+		0, 0
+	},
+	/* PARAM */
+	{
+		DW_TAG_formal_parameter, DW_CHILDREN_no,
+		DW_AT_name,	 DW_FORM_string,
+		DW_AT_location,	 DW_FORM_block1,
+		DW_AT_type,	 DW_FORM_ref_addr,
+		0, 0
+	},
+	/* STRUCTFIELD */
+	{
+		DW_TAG_member,	DW_CHILDREN_no,
+		DW_AT_name,	DW_FORM_string,
+		DW_AT_data_member_location, DW_FORM_block1,
+		DW_AT_type,	 DW_FORM_ref_addr,
+		0, 0
+	},
+	/* FUNCTYPEPARAM */
+	{
+		DW_TAG_formal_parameter, DW_CHILDREN_no,
+		// No name!
+		DW_AT_type,	 DW_FORM_ref_addr,
+		0, 0
+	},
+
+	/* DOTDOTDOT */
+	{
+		DW_TAG_unspecified_parameters, DW_CHILDREN_no,
+		0, 0
+	},
+	/* ARRAYRANGE */
+	{
+		DW_TAG_subrange_type, DW_CHILDREN_no,
+		// No name!
+		DW_AT_type,	 DW_FORM_ref_addr,
+		DW_AT_count, DW_FORM_udata,
+		0, 0
+	},
+
+	// Below here are the types considered public by ispubtype
+	/* NULLTYPE */
+	{
+		DW_TAG_unspecified_type, DW_CHILDREN_no,
+		DW_AT_name,	DW_FORM_string,
+		0, 0
+	},
+	/* BASETYPE */
+	{
+		DW_TAG_base_type, DW_CHILDREN_no,
+		DW_AT_name,	 DW_FORM_string,
+		DW_AT_encoding,	 DW_FORM_data1,
+		DW_AT_byte_size, DW_FORM_data1,
+		DW_AT_go_kind, DW_FORM_data1,
+		0, 0
+	},
+	/* ARRAYTYPE */
+	// child is subrange with upper bound
+	{
+		DW_TAG_array_type, DW_CHILDREN_yes,
+		DW_AT_name,	DW_FORM_string,
+		DW_AT_type,	DW_FORM_ref_addr,
+		DW_AT_byte_size, DW_FORM_udata,
+		DW_AT_go_kind, DW_FORM_data1,
+		0, 0
+	},
+
+	/* CHANTYPE */
+	{
+		DW_TAG_typedef, DW_CHILDREN_no,
+		DW_AT_name,	DW_FORM_string,
+		DW_AT_type,	DW_FORM_ref_addr,
+		DW_AT_go_kind, DW_FORM_data1,
+		DW_AT_go_elem, DW_FORM_ref_addr,
+		0, 0
+	},
+
+	/* FUNCTYPE */
+	{
+		DW_TAG_subroutine_type, DW_CHILDREN_yes,
+		DW_AT_name,	DW_FORM_string,
+//		DW_AT_type,	DW_FORM_ref_addr,
+		DW_AT_go_kind, DW_FORM_data1,
+		0, 0
+	},
+
+	/* IFACETYPE */
+	{
+		DW_TAG_typedef, DW_CHILDREN_yes,
+		DW_AT_name,	 DW_FORM_string,
+		DW_AT_type,	DW_FORM_ref_addr,
+		DW_AT_go_kind, DW_FORM_data1,
+		0, 0
+	},
+
+	/* MAPTYPE */
+	{
+		DW_TAG_typedef, DW_CHILDREN_no,
+		DW_AT_name,	DW_FORM_string,
+		DW_AT_type,	DW_FORM_ref_addr,
+		DW_AT_go_kind, DW_FORM_data1,
+		DW_AT_go_key, DW_FORM_ref_addr,
+		DW_AT_go_elem, DW_FORM_ref_addr,
+		0, 0
+	},
+
+	/* PTRTYPE */
+	{
+		DW_TAG_pointer_type, DW_CHILDREN_no,
+		DW_AT_name,	DW_FORM_string,
+		DW_AT_type,	DW_FORM_ref_addr,
+		DW_AT_go_kind, DW_FORM_data1,
+		0, 0
+	},
+	/* BARE_PTRTYPE */
+	{
+		DW_TAG_pointer_type, DW_CHILDREN_no,
+		DW_AT_name,	DW_FORM_string,
+		0, 0
+	},
+
+	/* SLICETYPE */
+	{
+		DW_TAG_structure_type, DW_CHILDREN_yes,
+		DW_AT_name,	DW_FORM_string,
+		DW_AT_byte_size, DW_FORM_udata,
+		DW_AT_go_kind, DW_FORM_data1,
+		DW_AT_go_elem, DW_FORM_ref_addr,
+		0, 0
+	},
+
+	/* STRINGTYPE */
+	{
+		DW_TAG_structure_type, DW_CHILDREN_yes,
+		DW_AT_name,	DW_FORM_string,
+		DW_AT_byte_size, DW_FORM_udata,
+		DW_AT_go_kind, DW_FORM_data1,
+		0, 0
+	},
+
+	/* STRUCTTYPE */
+	{
+		DW_TAG_structure_type, DW_CHILDREN_yes,
+		DW_AT_name,	DW_FORM_string,
+		DW_AT_byte_size, DW_FORM_udata,
+		DW_AT_go_kind, DW_FORM_data1,
+		0, 0
+	},
+
+	/* TYPEDECL */
+	{
+		DW_TAG_typedef, DW_CHILDREN_no,
+		DW_AT_name,	DW_FORM_string,
+		DW_AT_type,	DW_FORM_ref_addr,
+		0, 0
+	},
+};
+
+static void
+writeabbrev(void)
+{
+	int i, j;
+	DWAttrForm *f;
+
+	abbrevo = cpos();
+	for (i = 1; i < DW_NABRV; i++) {
+		// See section 7.5.3
+		uleb128put(i);
+		uleb128put(abbrevs[i].tag);
+		cput(abbrevs[i].children);
+		for(j=0; j<nelem(abbrevs[i].attr); j++) {
+			f = &abbrevs[i].attr[j];
+			uleb128put(f->attr);
+			uleb128put(f->form);
+			if(f->attr == 0)
+				break;
+		}
+	}
+	cput(0);
+	abbrevsize = cpos() - abbrevo;
+}
+
+/*
+ * Debugging Information Entries and their attributes.
+ */
+
+enum
+{
+	HASHSIZE = 107
+};
+
+static uint32
+hashstr(char* s)
+{
+	uint32 h;
+
+	h = 0;
+	while (*s)
+		h = h+h+h + *s++;
+	return h % HASHSIZE;
+}
+
+// For DW_CLS_string and _block, value should contain the length, and
+// data the data, for _reference, value is 0 and data is a DWDie* to
+// the referenced instance, for all others, value is the whole thing
+// and data is null.
+
+typedef struct DWAttr DWAttr;
+struct DWAttr {
+	DWAttr *link;
+	uint16 atr;  // DW_AT_
+	uint8 cls;  // DW_CLS_
+	vlong value;
+	char *data;
+};
+
+typedef struct DWDie DWDie;
+struct DWDie {
+	int abbrev;
+	DWDie *link;
+	DWDie *child;
+	DWAttr *attr;
+	// offset into .debug_info section, i.e relative to
+	// infoo. only valid after call to putdie()
+	vlong offs;
+	DWDie **hash;  // optional index of children by name, enabled by mkindex()
+	DWDie *hlink;  // bucket chain in parent's index
+};
+
+/*
+ * Root DIEs for compilation units, types and global variables.
+ */
+
+static DWDie dwroot;
+static DWDie dwtypes;
+static DWDie dwglobals;
+
+static DWAttr*
+newattr(DWDie *die, uint16 attr, int cls, vlong value, char *data)
+{
+	DWAttr *a;
+
+	a = mal(sizeof *a);
+	a->link = die->attr;
+	die->attr = a;
+	a->atr = attr;
+	a->cls = cls;
+	a->value = value;
+	a->data = data;
+	return a;
+}
+
+// Each DIE (except the root ones) has at least 1 attribute: its
+// name. getattr moves the desired one to the front so
+// frequently searched ones are found faster.
+static DWAttr*
+getattr(DWDie *die, uint16 attr)
+{
+	DWAttr *a, *b;
+
+	if (die->attr->atr == attr)
+		return die->attr;
+
+	a = die->attr;
+	b = a->link;
+	while (b != nil) {
+		if (b->atr == attr) {
+			a->link = b->link;
+			b->link = die->attr;
+			die->attr = b;
+			return b;
+		}
+		a = b;
+		b = b->link;
+	}
+	return nil;
+}
+
+// Every DIE has at least a DW_AT_name attribute (but it will only be
+// written out if it is listed in the abbrev).	If its parent is
+// keeping an index, the new DIE will be inserted there.
+static DWDie*
+newdie(DWDie *parent, int abbrev, char *name)
+{
+	DWDie *die;
+	int h;
+
+	die = mal(sizeof *die);
+	die->abbrev = abbrev;
+	die->link = parent->child;
+	parent->child = die;
+
+	newattr(die, DW_AT_name, DW_CLS_STRING, strlen(name), name);
+
+	if (parent->hash) {
+		h = hashstr(name);
+		die->hlink = parent->hash[h];
+		parent->hash[h] = die;
+	}
+
+	return die;
+}
+
+static void
+mkindex(DWDie *die)
+{
+	die->hash = mal(HASHSIZE * sizeof(DWDie*));
+}
+
+static DWDie*
+walktypedef(DWDie *die)
+{
+	DWAttr *attr;
+
+	// Resolve typedef if present.
+	if (die->abbrev == DW_ABRV_TYPEDECL) {
+		for (attr = die->attr; attr; attr = attr->link) {
+			if (attr->atr == DW_AT_type && attr->cls == DW_CLS_REFERENCE && attr->data != nil) {
+				return (DWDie*)attr->data;
+			}
+		}
+	}
+	return die;
+}
+
+// Find child by AT_name using hashtable if available or linear scan
+// if not.
+static DWDie*
+find(DWDie *die, char* name)
+{
+	DWDie *a, *b, *die2;
+	int h;
+
+top:
+	if (die->hash == nil) {
+		for (a = die->child; a != nil; a = a->link)
+			if (strcmp(name, getattr(a, DW_AT_name)->data) == 0)
+				return a;
+		goto notfound;
+	}
+
+	h = hashstr(name);
+	a = die->hash[h];
+
+	if (a == nil)
+		goto notfound;
+
+
+	if (strcmp(name, getattr(a, DW_AT_name)->data) == 0)
+		return a;
+
+	// Move found ones to head of the list.
+	b = a->hlink;
+	while (b != nil) {
+		if (strcmp(name, getattr(b, DW_AT_name)->data) == 0) {
+			a->hlink = b->hlink;
+			b->hlink = die->hash[h];
+			die->hash[h] = b;
+			return b;
+		}
+		a = b;
+		b = b->hlink;
+	}
+
+notfound:
+	die2 = walktypedef(die);
+	if(die2 != die) {
+		die = die2;
+		goto top;
+	}
+
+	return nil;
+}
+
+static DWDie*
+find_or_diag(DWDie *die, char* name)
+{
+	DWDie *r;
+	r = find(die, name);
+	if (r == nil) {
+		diag("dwarf find: %s %p has no %s", getattr(die, DW_AT_name)->data, die, name);
+		errorexit();
+	}
+	return r;
+}
+
+static void
+adddwarfrel(LSym* sec, LSym* sym, vlong offsetbase, int siz, vlong addend)
+{
+	Reloc *r;
+
+	r = addrel(sec);
+	r->sym = sym;
+	r->xsym = sym;
+	r->off = cpos() - offsetbase;
+	r->siz = siz;
+	r->type = R_ADDR;
+	r->add = addend;
+	r->xadd = addend;
+	if(iself && thechar == '6')
+		addend = 0;
+	switch(siz) {
+	case 4:
+		LPUT(addend);
+		break;
+	case 8:
+		VPUT(addend);
+		break;
+	default:
+		diag("bad size in adddwarfrel");
+		break;
+	}
+}
+
+static DWAttr*
+newrefattr(DWDie *die, uint16 attr, DWDie* ref)
+{
+	if (ref == nil)
+		return nil;
+	return newattr(die, attr, DW_CLS_REFERENCE, 0, (char*)ref);
+}
+
+static int fwdcount;
+
+static void
+putattr(int abbrev, int form, int cls, vlong value, char *data)
+{
+	vlong off;
+
+	switch(form) {
+	case DW_FORM_addr:	// address
+		if(linkmode == LinkExternal) {
+			value -= ((LSym*)data)->value;
+			adddwarfrel(infosec, (LSym*)data, infoo, PtrSize, value);
+			break;
+		}
+		addrput(value);
+		break;
+
+	case DW_FORM_block1:	// block
+		if(cls == DW_CLS_ADDRESS) {
+			cput(1+PtrSize);
+			cput(DW_OP_addr);
+			if(linkmode == LinkExternal) {
+				value -= ((LSym*)data)->value;
+				adddwarfrel(infosec, (LSym*)data, infoo, PtrSize, value);
+				break;
+			}
+			addrput(value);
+			break;
+		}
+		value &= 0xff;
+		cput(value);
+		while(value--)
+			cput(*data++);
+		break;
+
+	case DW_FORM_block2:	// block
+		value &= 0xffff;
+		WPUT(value);
+		while(value--)
+			cput(*data++);
+		break;
+
+	case DW_FORM_block4:	// block
+		value &= 0xffffffff;
+		LPUT(value);
+		while(value--)
+			cput(*data++);
+		break;
+
+	case DW_FORM_block:	// block
+		uleb128put(value);
+		while(value--)
+			cput(*data++);
+		break;
+
+	case DW_FORM_data1:	// constant
+		cput(value);
+		break;
+
+	case DW_FORM_data2:	// constant
+		WPUT(value);
+		break;
+
+	case DW_FORM_data4:	// constant, {line,loclist,mac,rangelist}ptr
+		if(linkmode == LinkExternal && cls == DW_CLS_PTR) {
+			adddwarfrel(infosec, linesym, infoo, 4, value);
+			break;
+		}
+		LPUT(value);
+		break;
+
+	case DW_FORM_data8:	// constant, {line,loclist,mac,rangelist}ptr
+		VPUT(value);
+		break;
+
+	case DW_FORM_sdata:	// constant
+		sleb128put(value);
+		break;
+
+	case DW_FORM_udata:	// constant
+		uleb128put(value);
+		break;
+
+	case DW_FORM_string:	// string
+		strnput(data, value+1);
+		break;
+
+	case DW_FORM_flag:	// flag
+		cput(value?1:0);
+		break;
+
+	case DW_FORM_ref_addr:	// reference to a DIE in the .info section
+		// In DWARF 2 (which is what we claim to generate),
+		// the ref_addr is the same size as a normal address.
+		// In DWARF 3 it is always 32 bits, unless emitting a large
+		// (> 4 GB of debug info aka "64-bit") unit, which we don't implement.
+		if (data == nil) {
+			diag("dwarf: null reference in %d", abbrev);
+			if(PtrSize == 8)
+				VPUT(0); // invalid dwarf, gdb will complain.
+			else
+				LPUT(0); // invalid dwarf, gdb will complain.
+		} else {
+			off = ((DWDie*)data)->offs;
+			if (off == 0)
+				fwdcount++;
+			if(linkmode == LinkExternal) {
+				adddwarfrel(infosec, infosym, infoo, PtrSize, off);
+				break;
+			}
+			addrput(off);
+		}
+		break;
+
+	case DW_FORM_ref1:	// reference within the compilation unit
+	case DW_FORM_ref2:	// reference
+	case DW_FORM_ref4:	// reference
+	case DW_FORM_ref8:	// reference
+	case DW_FORM_ref_udata:	// reference
+
+	case DW_FORM_strp:	// string
+	case DW_FORM_indirect:	// (see Section 7.5.3)
+	default:
+		diag("dwarf: unsupported attribute form %d / class %d", form, cls);
+		errorexit();
+	}
+}
+
+// Note that we can (and do) add arbitrary attributes to a DIE, but
+// only the ones actually listed in the Abbrev will be written out.
+static void
+putattrs(int abbrev, DWAttr* attr)
+{
+	DWAttrForm* af;
+	DWAttr *ap;
+
+	for(af = abbrevs[abbrev].attr; af->attr; af++) {
+		for(ap=attr; ap; ap=ap->link) {
+			if(ap->atr == af->attr) {
+				putattr(abbrev, af->form,
+					ap->cls,
+					ap->value,
+					ap->data);
+				goto done;
+			}
+		}
+		putattr(abbrev, af->form, 0, 0, nil);
+	done:;
+	}
+}
+
+static void putdie(DWDie* die);
+
+static void
+putdies(DWDie* die)
+{
+	for(; die; die = die->link)
+		putdie(die);
+}
+
+static void
+putdie(DWDie* die)
+{
+	die->offs = cpos() - infoo;
+	uleb128put(die->abbrev);
+	putattrs(die->abbrev, die->attr);
+	if (abbrevs[die->abbrev].children) {
+		putdies(die->child);
+		cput(0);
+	}
+}
+
+static void
+reverselist(DWDie** list)
+{
+	DWDie *curr, *prev;
+
+	curr = *list;
+	prev = nil;
+	while(curr != nil) {
+		DWDie* next = curr->link;
+		curr->link = prev;
+		prev = curr;
+		curr = next;
+	}
+	*list = prev;
+}
+
+static void
+reversetree(DWDie** list)
+{
+	 DWDie *die;
+
+	 reverselist(list);
+	 for (die = *list; die != nil; die = die->link)
+		 if (abbrevs[die->abbrev].children)
+			 reversetree(&die->child);
+}
+
+static void
+newmemberoffsetattr(DWDie *die, int32 offs)
+{
+	char block[10];
+	int i;
+
+	i = 0;
+	block[i++] = DW_OP_plus_uconst;
+	i += uleb128enc(offs, block+i);
+	newattr(die, DW_AT_data_member_location, DW_CLS_BLOCK, i, mal(i));
+	memmove(die->attr->data, block, i);
+}
+
+// GDB doesn't like DW_FORM_addr for DW_AT_location, so emit a
+// location expression that evals to a const.
+static void
+newabslocexprattr(DWDie *die, vlong addr, LSym *sym)
+{
+	newattr(die, DW_AT_location, DW_CLS_ADDRESS, addr, (char*)sym);
+}
+
+static DWDie* defptrto(DWDie *dwtype);	// below
+
+// Lookup predefined types
+static LSym*
+lookup_or_diag(char *n)
+{
+	LSym *s;
+
+	s = linkrlookup(ctxt, n, 0);
+	if (s == nil || s->size == 0) {
+		diag("dwarf: missing type: %s", n);
+		errorexit();
+	}
+	return s;
+}
+
+static void
+dotypedef(DWDie *parent, char *name, DWDie *def)
+{
+	DWDie *die;
+
+	// Only emit typedefs for real names.
+	if(strncmp(name, "map[", 4) == 0)
+		return;
+	if(strncmp(name, "struct {", 8) == 0)
+		return;
+	if(strncmp(name, "chan ", 5) == 0)
+		return;
+	if(*name == '[' || *name == '*')
+		return;
+	if(def == nil)
+		diag("dwarf: bad def in dotypedef");
+
+	// The typedef entry must be created after the def,
+	// so that future lookups will find the typedef instead
+	// of the real definition. This hooks the typedef into any
+	// circular definition loops, so that gdb can understand them.
+	die = newdie(parent, DW_ABRV_TYPEDECL, name);
+	newrefattr(die, DW_AT_type, def);
+}
+
+// Define gotype, for composite ones recurse into constituents.
+static DWDie*
+defgotype(LSym *gotype)
+{
+	DWDie *die, *fld;
+	LSym *s;
+	char *name, *f;
+	uint8 kind;
+	vlong bytesize;
+	int i, nfields;
+
+	if (gotype == nil)
+		return find_or_diag(&dwtypes, "<unspecified>");
+
+	if (strncmp("type.", gotype->name, 5) != 0) {
+		diag("dwarf: type name doesn't start with \".type\": %s", gotype->name);
+		return find_or_diag(&dwtypes, "<unspecified>");
+	}
+	name = gotype->name + 5;  // could also decode from Type.string
+
+	die = find(&dwtypes, name);
+	if (die != nil)
+		return die;
+
+	if (0 && debug['v'] > 2)
+		print("new type: %Y\n", gotype);
+
+	kind = decodetype_kind(gotype);
+	bytesize = decodetype_size(gotype);
+
+	switch (kind) {
+	case KindBool:
+		die = newdie(&dwtypes, DW_ABRV_BASETYPE, name);
+		newattr(die, DW_AT_encoding,  DW_CLS_CONSTANT, DW_ATE_boolean, 0);
+		newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
+		break;
+
+	case KindInt:
+	case KindInt8:
+	case KindInt16:
+	case KindInt32:
+	case KindInt64:
+		die = newdie(&dwtypes, DW_ABRV_BASETYPE, name);
+		newattr(die, DW_AT_encoding,  DW_CLS_CONSTANT, DW_ATE_signed, 0);
+		newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
+		break;
+
+	case KindUint:
+	case KindUint8:
+	case KindUint16:
+	case KindUint32:
+	case KindUint64:
+	case KindUintptr:
+		die = newdie(&dwtypes, DW_ABRV_BASETYPE, name);
+		newattr(die, DW_AT_encoding,  DW_CLS_CONSTANT, DW_ATE_unsigned, 0);
+		newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
+		break;
+
+	case KindFloat32:
+	case KindFloat64:
+		die = newdie(&dwtypes, DW_ABRV_BASETYPE, name);
+		newattr(die, DW_AT_encoding,  DW_CLS_CONSTANT, DW_ATE_float, 0);
+		newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
+		break;
+
+	case KindComplex64:
+	case KindComplex128:
+		die = newdie(&dwtypes, DW_ABRV_BASETYPE, name);
+		newattr(die, DW_AT_encoding,  DW_CLS_CONSTANT, DW_ATE_complex_float, 0);
+		newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
+		break;
+
+	case KindArray:
+		die = newdie(&dwtypes, DW_ABRV_ARRAYTYPE, name);
+		dotypedef(&dwtypes, name, die);
+		newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
+		s = decodetype_arrayelem(gotype);
+		newrefattr(die, DW_AT_type, defgotype(s));
+		fld = newdie(die, DW_ABRV_ARRAYRANGE, "range");
+		// use actual length not upper bound; correct for 0-length arrays.
+		newattr(fld, DW_AT_count, DW_CLS_CONSTANT, decodetype_arraylen(gotype), 0);
+		newrefattr(fld, DW_AT_type, find_or_diag(&dwtypes, "uintptr"));
+		break;
+
+	case KindChan:
+		die = newdie(&dwtypes, DW_ABRV_CHANTYPE, name);
+		newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
+		s = decodetype_chanelem(gotype);
+		newrefattr(die, DW_AT_go_elem, defgotype(s));
+		break;
+
+	case KindFunc:
+		die = newdie(&dwtypes, DW_ABRV_FUNCTYPE, name);
+		dotypedef(&dwtypes, name, die);
+		newrefattr(die, DW_AT_type, find_or_diag(&dwtypes, "void"));
+		nfields = decodetype_funcincount(gotype);
+		for (i = 0; i < nfields; i++) {
+			s = decodetype_funcintype(gotype, i);
+			fld = newdie(die, DW_ABRV_FUNCTYPEPARAM, s->name+5);
+			newrefattr(fld, DW_AT_type, defgotype(s));
+		}
+		if (decodetype_funcdotdotdot(gotype))
+			newdie(die, DW_ABRV_DOTDOTDOT, "...");
+		nfields = decodetype_funcoutcount(gotype);
+		for (i = 0; i < nfields; i++) {
+			s = decodetype_funcouttype(gotype, i);
+			fld = newdie(die, DW_ABRV_FUNCTYPEPARAM, s->name+5);
+			newrefattr(fld, DW_AT_type, defptrto(defgotype(s)));
+		}
+		break;
+
+	case KindInterface:
+		die = newdie(&dwtypes, DW_ABRV_IFACETYPE, name);
+		dotypedef(&dwtypes, name, die);
+		newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
+		nfields = decodetype_ifacemethodcount(gotype);
+		if (nfields == 0)
+			s = lookup_or_diag("type.runtime.eface");
+		else
+			s = lookup_or_diag("type.runtime.iface");
+		newrefattr(die, DW_AT_type, defgotype(s));
+		break;
+
+	case KindMap:
+		die = newdie(&dwtypes, DW_ABRV_MAPTYPE, name);
+		s = decodetype_mapkey(gotype);
+		newrefattr(die, DW_AT_go_key, defgotype(s));
+		s = decodetype_mapvalue(gotype);
+		newrefattr(die, DW_AT_go_elem, defgotype(s));
+		break;
+
+	case KindPtr:
+		die = newdie(&dwtypes, DW_ABRV_PTRTYPE, name);
+		dotypedef(&dwtypes, name, die);
+		s = decodetype_ptrelem(gotype);
+		newrefattr(die, DW_AT_type, defgotype(s));
+		break;
+
+	case KindSlice:
+		die = newdie(&dwtypes, DW_ABRV_SLICETYPE, name);
+		dotypedef(&dwtypes, name, die);
+		newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
+		s = decodetype_arrayelem(gotype);
+		newrefattr(die, DW_AT_go_elem, defgotype(s));
+		break;
+
+	case KindString:
+		die = newdie(&dwtypes, DW_ABRV_STRINGTYPE, name);
+		newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
+		break;
+
+	case KindStruct:
+		die = newdie(&dwtypes, DW_ABRV_STRUCTTYPE, name);
+		dotypedef(&dwtypes, name, die);
+		newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
+		nfields = decodetype_structfieldcount(gotype);
+		for (i = 0; i < nfields; i++) {
+			f = decodetype_structfieldname(gotype, i);
+			s = decodetype_structfieldtype(gotype, i);
+			if (f == nil)
+				f = s->name + 5;	 // skip "type."
+			fld = newdie(die, DW_ABRV_STRUCTFIELD, f);
+			newrefattr(fld, DW_AT_type, defgotype(s));
+			newmemberoffsetattr(fld, decodetype_structfieldoffs(gotype, i));
+		}
+		break;
+
+	case KindUnsafePointer:
+		die = newdie(&dwtypes, DW_ABRV_BARE_PTRTYPE, name);
+		break;
+
+	default:
+		diag("dwarf: definition of unknown kind %d: %s", kind, gotype->name);
+		die = newdie(&dwtypes, DW_ABRV_TYPEDECL, name);
+		newrefattr(die, DW_AT_type, find_or_diag(&dwtypes, "<unspecified>"));
+	}
+
+	newattr(die, DW_AT_go_kind, DW_CLS_CONSTANT, kind, 0);
+
+	return die;
+}
+
+// Find or construct *T given T.
+static DWDie*
+defptrto(DWDie *dwtype)
+{
+	char ptrname[1024];
+	DWDie *die;
+
+	snprint(ptrname, sizeof ptrname, "*%s", getattr(dwtype, DW_AT_name)->data);
+	die = find(&dwtypes, ptrname);
+	if (die == nil) {
+		die = newdie(&dwtypes, DW_ABRV_PTRTYPE,
+			     strcpy(mal(strlen(ptrname)+1), ptrname));
+		newrefattr(die, DW_AT_type, dwtype);
+	}
+	return die;
+}
+
+// Copies src's children into dst. Copies attributes by value.
+// DWAttr.data is copied as pointer only.  If except is one of
+// the top-level children, it will not be copied.
+static void
+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);
+		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
+static void
+substitutetype(DWDie *structdie, char *field, DWDie* dwtype)
+{
+	DWDie *child;
+	DWAttr *a;
+
+	child = find_or_diag(structdie, field);
+	if (child == nil)
+		return;
+
+	a = getattr(child, DW_AT_type);
+	if (a != nil)
+		a->data = (char*) dwtype;
+	else
+		newrefattr(child, DW_AT_type, dwtype);
+}
+
+static void
+synthesizestringtypes(DWDie* die)
+{
+	DWDie *prototype;
+
+	prototype = walktypedef(defgotype(lookup_or_diag("type.runtime._string")));
+	if (prototype == nil)
+		return;
+
+	for (; die != nil; die = die->link) {
+		if (die->abbrev != DW_ABRV_STRINGTYPE)
+			continue;
+		copychildren(die, prototype);
+	}
+}
+
+static void
+synthesizeslicetypes(DWDie *die)
+{
+	DWDie *prototype, *elem;
+
+	prototype = walktypedef(defgotype(lookup_or_diag("type.runtime.slice")));
+	if (prototype == nil)
+		return;
+
+	for (; die != nil; die = die->link) {
+		if (die->abbrev != DW_ABRV_SLICETYPE)
+			continue;
+		copychildren(die, prototype);
+		elem = (DWDie*) getattr(die, DW_AT_go_elem)->data;
+		substitutetype(die, "array", defptrto(elem));
+	}
+}
+
+static char*
+mkinternaltypename(char *base, char *arg1, char *arg2)
+{
+	char buf[1024];
+	char *n;
+
+	if (arg2 == nil)
+		snprint(buf, sizeof buf, "%s<%s>", base, arg1);
+	else
+		snprint(buf, sizeof buf, "%s<%s,%s>", base, arg1, arg2);
+	n = mal(strlen(buf) + 1);
+	memmove(n, buf, strlen(buf));
+	return n;
+}
+
+// synthesizemaptypes is way too closely married to runtime/hashmap.c
+enum {
+	MaxKeySize = 128,
+	MaxValSize = 128,
+	BucketSize = 8,
+};
+
+static void
+synthesizemaptypes(DWDie *die)
+{
+
+	DWDie *hash, *bucket, *dwh, *dwhk, *dwhv, *dwhb, *keytype, *valtype, *fld;
+	int indirect_key, indirect_val;
+	int keysize, valsize;
+	DWAttr *a;
+
+	hash		= walktypedef(defgotype(lookup_or_diag("type.runtime.hmap")));
+	bucket		= walktypedef(defgotype(lookup_or_diag("type.runtime.bmap")));
+
+	if (hash == nil)
+		return;
+
+	for (; die != nil; die = die->link) {
+		if (die->abbrev != DW_ABRV_MAPTYPE)
+			continue;
+
+		keytype = walktypedef((DWDie*) getattr(die, DW_AT_go_key)->data);
+		valtype = walktypedef((DWDie*) getattr(die, DW_AT_go_elem)->data);
+
+		// compute size info like hashmap.c does.
+		a = getattr(keytype, DW_AT_byte_size);
+		keysize = a ? a->value : PtrSize;  // We don't store size with Pointers
+		a = getattr(valtype, DW_AT_byte_size);
+		valsize = a ? a->value : PtrSize;
+		indirect_key = 0;
+		indirect_val = 0;
+		if(keysize > MaxKeySize) {
+			keysize = PtrSize;
+			indirect_key = 1;
+		}
+		if(valsize > MaxValSize) {
+			valsize = PtrSize;
+			indirect_val = 1;
+		}
+
+		// Construct type to represent an array of BucketSize keys
+		dwhk = newdie(&dwtypes, DW_ABRV_ARRAYTYPE,
+			      mkinternaltypename("[]key",
+						 getattr(keytype, DW_AT_name)->data, nil));
+		newattr(dwhk, DW_AT_byte_size, DW_CLS_CONSTANT, BucketSize * keysize, 0);
+		newrefattr(dwhk, DW_AT_type, indirect_key ? defptrto(keytype) : keytype);
+		fld = newdie(dwhk, DW_ABRV_ARRAYRANGE, "size");
+		newattr(fld, DW_AT_count, DW_CLS_CONSTANT, BucketSize, 0);
+		newrefattr(fld, DW_AT_type, find_or_diag(&dwtypes, "uintptr"));
+		
+		// Construct type to represent an array of BucketSize values
+		dwhv = newdie(&dwtypes, DW_ABRV_ARRAYTYPE, 
+			      mkinternaltypename("[]val",
+						 getattr(valtype, DW_AT_name)->data, nil));
+		newattr(dwhv, DW_AT_byte_size, DW_CLS_CONSTANT, BucketSize * valsize, 0);
+		newrefattr(dwhv, DW_AT_type, indirect_val ? defptrto(valtype) : valtype);
+		fld = newdie(dwhv, DW_ABRV_ARRAYRANGE, "size");
+		newattr(fld, DW_AT_count, DW_CLS_CONSTANT, BucketSize, 0);
+		newrefattr(fld, DW_AT_type, find_or_diag(&dwtypes, "uintptr"));
+
+		// Construct bucket<K,V>
+		dwhb = newdie(&dwtypes, DW_ABRV_STRUCTTYPE,
+			      mkinternaltypename("bucket",
+						 getattr(keytype, DW_AT_name)->data,
+						 getattr(valtype, DW_AT_name)->data));
+		// 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);
+		fld = newdie(dwhb, DW_ABRV_STRUCTFIELD, "values");
+		newrefattr(fld, DW_AT_type, dwhv);
+		newmemberoffsetattr(fld, BucketSize + BucketSize * keysize);
+		fld = newdie(dwhb, DW_ABRV_STRUCTFIELD, "overflow");
+		newrefattr(fld, DW_AT_type, defptrto(dwhb));
+		newmemberoffsetattr(fld, BucketSize + BucketSize * (keysize + valsize));
+		if(RegSize > PtrSize) {
+			fld = newdie(dwhb, DW_ABRV_STRUCTFIELD, "pad");
+			newrefattr(fld, DW_AT_type, find_or_diag(&dwtypes, "uintptr"));
+			newmemberoffsetattr(fld, BucketSize + BucketSize * (keysize + valsize) + PtrSize);
+		}
+		newattr(dwhb, DW_AT_byte_size, DW_CLS_CONSTANT, BucketSize + BucketSize * keysize + BucketSize * valsize + RegSize, 0);
+
+		// Construct hash<K,V>
+		dwh = newdie(&dwtypes, DW_ABRV_STRUCTTYPE,
+			mkinternaltypename("hash",
+				getattr(keytype, DW_AT_name)->data,
+				getattr(valtype, DW_AT_name)->data));
+		copychildren(dwh, hash);
+		substitutetype(dwh, "buckets", defptrto(dwhb));
+		substitutetype(dwh, "oldbuckets", defptrto(dwhb));
+		newattr(dwh, DW_AT_byte_size, DW_CLS_CONSTANT,
+			getattr(hash, DW_AT_byte_size)->value, nil);
+
+		// make map type a pointer to hash<K,V>
+		newrefattr(die, DW_AT_type, defptrto(dwh));
+	}
+}
+
+static void
+synthesizechantypes(DWDie *die)
+{
+	DWDie *sudog, *waitq, *hchan,
+		*dws, *dww, *dwh, *elemtype;
+	DWAttr *a;
+	int elemsize, sudogsize;
+
+	sudog = walktypedef(defgotype(lookup_or_diag("type.runtime.sudog")));
+	waitq = walktypedef(defgotype(lookup_or_diag("type.runtime.waitq")));
+	hchan = walktypedef(defgotype(lookup_or_diag("type.runtime.hchan")));
+	if (sudog == nil || waitq == nil || hchan == nil)
+		return;
+
+	sudogsize = getattr(sudog, DW_AT_byte_size)->value;
+
+	for (; die != nil; die = die->link) {
+		if (die->abbrev != DW_ABRV_CHANTYPE)
+			continue;
+		elemtype = (DWDie*) getattr(die, DW_AT_go_elem)->data;
+		a = getattr(elemtype, DW_AT_byte_size);
+		elemsize = a ? a->value : PtrSize;
+
+		// sudog<T>
+		dws = newdie(&dwtypes, DW_ABRV_STRUCTTYPE,
+			mkinternaltypename("sudog",
+				getattr(elemtype, DW_AT_name)->data, nil));
+		copychildren(dws, sudog);
+		substitutetype(dws, "elem", elemtype);
+		newattr(dws, DW_AT_byte_size, DW_CLS_CONSTANT,
+			sudogsize + (elemsize > 8 ? elemsize - 8 : 0), nil);
+
+		// waitq<T>
+		dww = newdie(&dwtypes, DW_ABRV_STRUCTTYPE,
+			mkinternaltypename("waitq", getattr(elemtype, DW_AT_name)->data, nil));
+		copychildren(dww, waitq);
+		substitutetype(dww, "first", defptrto(dws));
+		substitutetype(dww, "last",  defptrto(dws));
+		newattr(dww, DW_AT_byte_size, DW_CLS_CONSTANT,
+			getattr(waitq, DW_AT_byte_size)->value, nil);
+
+		// hchan<T>
+		dwh = newdie(&dwtypes, DW_ABRV_STRUCTTYPE,
+			mkinternaltypename("hchan", getattr(elemtype, DW_AT_name)->data, nil));
+		copychildren(dwh, hchan);
+		substitutetype(dwh, "recvq", dww);
+		substitutetype(dwh, "sendq", dww);
+		newattr(dwh, DW_AT_byte_size, DW_CLS_CONSTANT,
+			getattr(hchan, DW_AT_byte_size)->value, nil);
+
+		newrefattr(die, DW_AT_type, defptrto(dwh));
+	}
+}
+
+// For use with pass.c::genasmsym
+static void
+defdwsymb(LSym* sym, char *s, int t, vlong v, vlong size, int ver, LSym *gotype)
+{
+	DWDie *dv, *dt;
+
+	USED(size);
+	if (strncmp(s, "go.string.", 10) == 0)
+		return;
+
+	if (strncmp(s, "type.", 5) == 0 && strcmp(s, "type.*") != 0 && strncmp(s, "type..", 6) != 0) {
+		defgotype(sym);
+		return;
+	}
+
+	dv = nil;
+
+	switch (t) {
+	default:
+		return;
+	case 'd':
+	case 'b':
+	case 'D':
+	case 'B':
+		dv = newdie(&dwglobals, DW_ABRV_VARIABLE, s);
+		newabslocexprattr(dv, v, sym);
+		if (ver == 0)
+			newattr(dv, DW_AT_external, DW_CLS_FLAG, 1, 0);
+		// fallthrough
+	case 'a':
+	case 'p':
+		dt = defgotype(gotype);
+	}
+
+	if (dv != nil)
+		newrefattr(dv, DW_AT_type, dt);
+}
+
+static void
+movetomodule(DWDie *parent)
+{
+	DWDie *die;
+
+	die = dwroot.child->child;
+	while(die->link != nil)
+		die = die->link;
+	die->link = parent->child;
+}
+
+// If the pcln table contains runtime/string.goc, use that to set gdbscript path.
+static void
+finddebugruntimepath(LSym *s)
+{
+	int i;
+	char *p;
+	LSym *f;
+	
+	if(gdbscript[0] != '\0')
+		return;
+
+	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;
+		}
+	}
+}
+
+/*
+ * Generate short opcodes when possible, long ones when necessary.
+ * See section 6.2.5
+ */
+
+enum {
+	LINE_BASE = -1,
+	LINE_RANGE = 4,
+	OPCODE_BASE = 10
+};
+
+static void
+putpclcdelta(vlong delta_pc, vlong delta_lc)
+{
+	if (LINE_BASE <= delta_lc && delta_lc < LINE_BASE+LINE_RANGE) {
+		vlong opcode = OPCODE_BASE + (delta_lc - LINE_BASE) + (LINE_RANGE * delta_pc);
+		if (OPCODE_BASE <= opcode && opcode < 256) {
+			cput(opcode);
+			return;
+		}
+	}
+
+	if (delta_pc) {
+		cput(DW_LNS_advance_pc);
+		sleb128put(delta_pc);
+	}
+
+	cput(DW_LNS_advance_line);
+	sleb128put(delta_lc);
+	cput(DW_LNS_copy);
+}
+
+static void
+newcfaoffsetattr(DWDie *die, int32 offs)
+{
+	char block[10];
+	int i;
+
+	i = 0;
+
+	block[i++] = DW_OP_call_frame_cfa;
+	if (offs != 0) {
+		block[i++] = DW_OP_consts;
+		i += sleb128enc(offs, block+i);
+		block[i++] = DW_OP_plus;
+	}
+	newattr(die, DW_AT_location, DW_CLS_BLOCK, i, mal(i));
+	memmove(die->attr->data, block, i);
+}
+
+static char*
+mkvarname(char* name, int da)
+{
+	char buf[1024];
+	char *n;
+
+	snprint(buf, sizeof buf, "%s#%d", name, da);
+	n = mal(strlen(buf) + 1);
+	memmove(n, buf, strlen(buf));
+	return n;
+}
+
+/*
+ * Walk prog table, emit line program and build DIE tree.
+ */
+
+// flush previous compilation unit.
+static void
+flushunit(DWDie *dwinfo, vlong pc, LSym *pcsym, vlong unitstart, int32 header_length)
+{
+	vlong here;
+
+	if (dwinfo != nil && pc != 0) {
+		newattr(dwinfo, DW_AT_high_pc, DW_CLS_ADDRESS, pc+1, (char*)pcsym);
+	}
+
+	if (unitstart >= 0) {
+		cput(0);  // start extended opcode
+		uleb128put(1);
+		cput(DW_LNE_end_sequence);
+
+		here = cpos();
+		cseek(unitstart);
+		LPUT(here - unitstart - sizeof(int32));	 // unit_length
+		WPUT(2);  // dwarf version
+		LPUT(header_length); // header length starting here
+		cseek(here);
+	}
+}
+
+static void
+writelines(void)
+{
+	LSym *s, *epcs;
+	Auto *a;
+	vlong unitstart, headerend, offs;
+	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 = linklookup(ctxt, ".dwarfline", 0);
+	linesec->nr = 0;
+
+	unitstart = -1;
+	headerend = -1;
+	epc = 0;
+	epcs = S;
+	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(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->pcln == nil)
+			continue;
+
+		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(epc - s->value >= pcline.nextpc) {
+				pciternext(&pcline);
+				continue;
+			}
+
+			if(file != pcfile.value) {
+				cput(DW_LNS_set_file);
+				uleb128put(pcfile.value);
+				file = pcfile.value;
+			}
+			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;
+		dwfunc->hash = varhash;	 // enable indexing of children by name
+		memset(varhash, 0, sizeof varhash);
+		for(a = s->autom; a; a = a->link) {
+			switch (a->type) {
+			case A_AUTO:
+				dt = DW_ABRV_AUTO;
+				offs = a->aoffset - PtrSize;
+				break;
+			case A_PARAM:
+				dt = DW_ABRV_PARAM;
+				offs = a->aoffset;
+				break;
+			default:
+				continue;
+			}
+			if (strstr(a->asym->name, ".autotmp_"))
+				continue;
+			if (find(dwfunc, a->asym->name) != nil)
+				n = mkvarname(a->asym->name, da);
+			else
+				n = a->asym->name;
+			// Drop the package prefix from locals and arguments.
+			nn = strrchr(n, '.');
+			if (nn)
+				n = nn + 1;
+
+			dwvar = newdie(dwfunc, dt, n);
+			newcfaoffsetattr(dwvar, offs);
+			newrefattr(dwvar, DW_AT_type, defgotype(a->gotype));
+
+			// push dwvar down dwfunc->child to preserve order
+			newattr(dwvar, DW_AT_internal_location, DW_CLS_CONSTANT, offs, nil);
+			dwfunc->child = dwvar->link;  // take dwvar out from the top of the list
+			for (dws = &dwfunc->child; *dws != nil; dws = &(*dws)->link)
+				if (offs > getattr(*dws, DW_AT_internal_location)->value)
+					break;
+			dwvar->link = *dws;
+			*dws = dwvar;
+
+			da++;
+		}
+
+		dwfunc->hash = nil;
+	}
+
+	flushunit(dwinfo, epc, epcs, unitstart, headerend - unitstart - 10);
+	linesize = cpos() - lineo;
+}
+
+/*
+ *  Emit .debug_frame
+ */
+enum
+{
+	CIERESERVE = 16,
+	DATAALIGNMENTFACTOR = -4,	// TODO -PtrSize?
+	FAKERETURNCOLUMN = 16		// TODO gdb6 doesn't like > 15?
+};
+
+static void
+putpccfadelta(vlong deltapc, vlong cfa)
+{
+	cput(DW_CFA_def_cfa_offset_sf);
+	sleb128put(cfa / DATAALIGNMENTFACTOR);
+
+	if (deltapc < 0x40) {
+		cput(DW_CFA_advance_loc + deltapc);
+	} else if (deltapc < 0x100) {
+		cput(DW_CFA_advance_loc1);
+		cput(deltapc);
+	} else if (deltapc < 0x10000) {
+		cput(DW_CFA_advance_loc2);
+		WPUT(deltapc);
+	} else {
+		cput(DW_CFA_advance_loc4);
+		LPUT(deltapc);
+	}
+}
+
+static void
+writeframes(void)
+{
+	LSym *s;
+	vlong fdeo, fdesize, pad;
+	Pciter pcsp;
+	uint32 nextpc;
+
+	if(framesec == S)
+		framesec = linklookup(ctxt, ".dwarfframe", 0);
+	framesec->nr = 0;
+	frameo = cpos();
+
+	// Emit the CIE, Section 6.4.1
+	LPUT(CIERESERVE);	// initial length, must be multiple of PtrSize
+	LPUT(0xffffffff);	// cid.
+	cput(3);		// dwarf version (appendix F)
+	cput(0);		// augmentation ""
+	uleb128put(1);		// code_alignment_factor
+	sleb128put(DATAALIGNMENTFACTOR); // guess
+	uleb128put(FAKERETURNCOLUMN);	// return_address_register
+
+	cput(DW_CFA_def_cfa);
+	uleb128put(DWARFREGSP);	// register SP (**ABI-dependent, defined in l.h)
+	uleb128put(PtrSize);	// offset
+
+	cput(DW_CFA_offset + FAKERETURNCOLUMN);	 // return address
+	uleb128put(-PtrSize / DATAALIGNMENTFACTOR);  // at cfa - x*4
+
+	// 4 is to exclude the length field.
+	pad = CIERESERVE + frameo + 4 - cpos();
+	if (pad < 0) {
+		diag("dwarf: CIERESERVE too small by %lld bytes.", -pad);
+		errorexit();
+	}
+	strnput("", pad);
+
+	for(ctxt->cursym = ctxt->textp; ctxt->cursym != nil; ctxt->cursym = ctxt->cursym->next) {
+		s = ctxt->cursym;
+		if(s->pcln == nil)
+			continue;
+
+		fdeo = cpos();
+		// Emit a FDE, Section 6.4.1, starting wit a placeholder.
+		LPUT(0);	// length, must be multiple of PtrSize
+		LPUT(0);	// Pointer to the CIE above, at offset 0
+		addrput(0);	// initial location
+		addrput(0);	// address range
+
+		for(pciterinit(ctxt, &pcsp, &s->pcln->pcsp); !pcsp.done; pciternext(&pcsp)) {
+			nextpc = pcsp.nextpc;
+			// pciterinit goes up to the end of the function,
+			// but DWARF expects us to stop just before the end.
+			if(nextpc == s->size) {
+				nextpc--;
+				if(nextpc < pcsp.pc)
+					continue;
+			}
+			putpccfadelta(nextpc - pcsp.pc, PtrSize + pcsp.value);
+		}
+
+		fdesize = cpos() - fdeo - 4;	// exclude the length field.
+		pad = rnd(fdesize, PtrSize) - fdesize;
+		strnput("", pad);
+		fdesize += pad;
+
+		// Emit the FDE header for real, Section 6.4.1.
+		cseek(fdeo);
+		LPUT(fdesize);
+		if(linkmode == LinkExternal) {
+			adddwarfrel(framesec, framesym, frameo, 4, 0);
+			adddwarfrel(framesec, s, frameo, PtrSize, 0);
+		}
+		else {
+			LPUT(0);
+			addrput(s->value);
+		}
+		addrput(s->size);
+		cseek(fdeo + 4 + fdesize);
+	}
+
+	cflush();
+	framesize = cpos() - frameo;
+}
+
+/*
+ *  Walk DWarfDebugInfoEntries, and emit .debug_info
+ */
+enum
+{
+	COMPUNITHEADERSIZE = 4+2+4+1
+};
+
+static void
+writeinfo(void)
+{
+	DWDie *compunit;
+	vlong unitstart, here;
+
+	fwdcount = 0;
+	if (infosec == S)
+		infosec = linklookup(ctxt, ".dwarfinfo", 0);
+	infosec->nr = 0;
+
+	if(arangessec == S)
+		arangessec = linklookup(ctxt, ".dwarfaranges", 0);
+	arangessec->nr = 0;
+
+	for (compunit = dwroot.child; compunit; compunit = compunit->link) {
+		unitstart = cpos();
+
+		// Write .debug_info Compilation Unit Header (sec 7.5.1)
+		// Fields marked with (*) must be changed for 64-bit dwarf
+		// This must match COMPUNITHEADERSIZE above.
+		LPUT(0);	// unit_length (*), will be filled in later.
+		WPUT(2);	// dwarf version (appendix F)
+
+		// debug_abbrev_offset (*)
+		if(linkmode == LinkExternal)
+			adddwarfrel(infosec, abbrevsym, infoo, 4, 0);
+		else
+			LPUT(0);
+
+		cput(PtrSize);	// address_size
+
+		putdie(compunit);
+
+		here = cpos();
+		cseek(unitstart);
+		LPUT(here - unitstart - 4);	// exclude the length field.
+		cseek(here);
+	}
+	cflush();
+}
+
+/*
+ *  Emit .debug_pubnames/_types.  _info must have been written before,
+ *  because we need die->offs and infoo/infosize;
+ */
+static int
+ispubname(DWDie *die)
+{
+	DWAttr *a;
+
+	switch(die->abbrev) {
+	case DW_ABRV_FUNCTION:
+	case DW_ABRV_VARIABLE:
+		a = getattr(die, DW_AT_external);
+		return a && a->value;
+	}
+	return 0;
+}
+
+static int
+ispubtype(DWDie *die)
+{
+	return die->abbrev >= DW_ABRV_NULLTYPE;
+}
+
+static vlong
+writepub(int (*ispub)(DWDie*))
+{
+	DWDie *compunit, *die;
+	DWAttr *dwa;
+	vlong unitstart, unitend, sectionstart, here;
+
+	sectionstart = cpos();
+
+	for (compunit = dwroot.child; compunit != nil; compunit = compunit->link) {
+		unitstart = compunit->offs - COMPUNITHEADERSIZE;
+		if (compunit->link != nil)
+			unitend = compunit->link->offs - COMPUNITHEADERSIZE;
+		else
+			unitend = infoo + infosize;
+
+		// Write .debug_pubnames/types	Header (sec 6.1.1)
+		LPUT(0);			// unit_length (*), will be filled in later.
+		WPUT(2);			// dwarf version (appendix F)
+		LPUT(unitstart);		// debug_info_offset (of the Comp unit Header)
+		LPUT(unitend - unitstart);	// debug_info_length
+
+		for (die = compunit->child; die != nil; die = die->link) {
+			if (!ispub(die)) continue;
+			LPUT(die->offs - unitstart);
+			dwa = getattr(die, DW_AT_name);
+			strnput(dwa->data, dwa->value + 1);
+		}
+		LPUT(0);
+
+		here = cpos();
+		cseek(sectionstart);
+		LPUT(here - sectionstart - 4);	// exclude the length field.
+		cseek(here);
+
+	}
+
+	return sectionstart;
+}
+
+/*
+ *  emit .debug_aranges.  _info must have been written before,
+ *  because we need die->offs of dw_globals.
+ */
+static vlong
+writearanges(void)
+{
+	DWDie *compunit;
+	DWAttr *b, *e;
+	int headersize;
+	vlong sectionstart;
+	vlong value;
+
+	sectionstart = cpos();
+	headersize = rnd(4+2+4+1+1, PtrSize);  // don't count unit_length field itself
+
+	for (compunit = dwroot.child; compunit != nil; compunit = compunit->link) {
+		b = getattr(compunit,  DW_AT_low_pc);
+		if (b == nil)
+			continue;
+		e = getattr(compunit,  DW_AT_high_pc);
+		if (e == nil)
+			continue;
+
+		// Write .debug_aranges	 Header + entry	 (sec 6.1.2)
+		LPUT(headersize + 4*PtrSize - 4);	// unit_length (*)
+		WPUT(2);	// dwarf version (appendix F)
+
+		value = compunit->offs - COMPUNITHEADERSIZE;	// debug_info_offset
+		if(linkmode == LinkExternal)
+			adddwarfrel(arangessec, infosym, sectionstart, 4, value);
+		else
+			LPUT(value);
+
+		cput(PtrSize);	// address_size
+		cput(0);	// segment_size
+		strnput("", headersize - (4+2+4+1+1));	// align to PtrSize
+
+		if(linkmode == LinkExternal)
+			adddwarfrel(arangessec, (LSym*)b->data, sectionstart, PtrSize, b->value-((LSym*)b->data)->value);
+		else
+			addrput(b->value);
+
+		addrput(e->value - b->value);
+		addrput(0);
+		addrput(0);
+	}
+	cflush();
+	return sectionstart;
+}
+
+static vlong
+writegdbscript(void)
+{
+	vlong sectionstart;
+
+	sectionstart = cpos();
+
+	if (gdbscript[0]) {
+		cput(1);  // magic 1 byte?
+		strnput(gdbscript, strlen(gdbscript)+1);
+		cflush();
+	}
+	return sectionstart;
+}
+
+static void
+align(vlong size)
+{
+	if(HEADTYPE == Hwindows) // Only Windows PE need section align.
+		strnput("", rnd(size, PEFILEALIGN) - size);
+}
+
+static vlong
+writedwarfreloc(LSym* s)
+{
+	int i;
+	vlong start;
+	Reloc *r;
+	
+	start = cpos();
+	for(r = s->r; r < s->r+s->nr; r++) {
+		if(iself)
+			i = elfreloc1(r, r->off);
+		else if(HEADTYPE == Hdarwin)
+			i = machoreloc1(r, r->off);
+		else
+			i = -1;
+		if(i < 0)
+			diag("unsupported obj reloc %d/%d to %s", r->type, r->siz, r->sym->name);
+	}
+	return start;
+}
+
+/*
+ * This is the main entry point for generating dwarf.  After emitting
+ * the mandatory debug_abbrev section, it calls writelines() to set up
+ * the per-compilation unit part of the DIE tree, while simultaneously
+ * emitting the debug_line section.  When the final tree contains
+ * forward references, it will write the debug_info section in 2
+ * passes.
+ *
+ */
+void
+dwarfemitdebugsections(void)
+{
+	vlong infoe;
+	DWDie* die;
+
+	if(debug['w'])  // disable dwarf
+		return;
+
+	if(linkmode == LinkExternal && !iself)
+		return;
+
+	// For diagnostic messages.
+	newattr(&dwtypes, DW_AT_name, DW_CLS_STRING, strlen("dwtypes"), "dwtypes");
+
+	mkindex(&dwroot);
+	mkindex(&dwtypes);
+	mkindex(&dwglobals);
+
+	// Some types that must exist to define other ones.
+	newdie(&dwtypes, DW_ABRV_NULLTYPE, "<unspecified>");
+	newdie(&dwtypes, DW_ABRV_NULLTYPE, "void");
+	newdie(&dwtypes, DW_ABRV_BARE_PTRTYPE, "unsafe.Pointer");
+
+	die = newdie(&dwtypes, DW_ABRV_BASETYPE, "uintptr");  // needed for array size
+	newattr(die, DW_AT_encoding,  DW_CLS_CONSTANT, DW_ATE_unsigned, 0);
+	newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, PtrSize, 0);
+	newattr(die, DW_AT_go_kind, DW_CLS_CONSTANT, KindUintptr, 0);
+
+	// Needed by the prettyprinter code for interface inspection.
+	defgotype(lookup_or_diag("type.runtime._type"));
+	defgotype(lookup_or_diag("type.runtime.interfacetype"));
+	defgotype(lookup_or_diag("type.runtime.itab"));
+
+	genasmsym(defdwsymb);
+
+	writeabbrev();
+	align(abbrevsize);
+	writelines();
+	align(linesize);
+	writeframes();
+	align(framesize);
+
+	synthesizestringtypes(dwtypes.child);
+	synthesizeslicetypes(dwtypes.child);
+	synthesizemaptypes(dwtypes.child);
+	synthesizechantypes(dwtypes.child);
+
+	reversetree(&dwroot.child);
+	reversetree(&dwtypes.child);
+	reversetree(&dwglobals.child);
+
+	movetomodule(&dwtypes);
+	movetomodule(&dwglobals);
+
+	infoo = cpos();
+	writeinfo();
+	infoe = cpos();
+	pubnameso = infoe;
+	pubtypeso = infoe;
+	arangeso = infoe;
+	gdbscripto = infoe;
+
+	if (fwdcount > 0) {
+		if (debug['v'])
+			Bprint(&bso, "%5.2f dwarf pass 2.\n", cputime());
+		cseek(infoo);
+		writeinfo();
+		if (fwdcount > 0) {
+			diag("dwarf: unresolved references after first dwarf info pass");
+			errorexit();
+		}
+		if (infoe != cpos()) {
+			diag("dwarf: inconsistent second dwarf info pass");
+			errorexit();
+		}
+	}
+	infosize = infoe - infoo;
+	align(infosize);
+
+	pubnameso  = writepub(ispubname);
+	pubnamessize  = cpos() - pubnameso;
+	align(pubnamessize);
+
+	pubtypeso  = writepub(ispubtype);
+	pubtypessize  = cpos() - pubtypeso;
+	align(pubtypessize);
+
+	arangeso   = writearanges();
+	arangessize   = cpos() - arangeso;
+	align(arangessize);
+
+	gdbscripto = writegdbscript();
+	gdbscriptsize = cpos() - gdbscripto;
+	align(gdbscriptsize);
+
+	while(cpos()&7)
+		cput(0);
+	inforeloco = writedwarfreloc(infosec);
+	inforelocsize = cpos() - inforeloco;
+	align(inforelocsize);
+
+	arangesreloco = writedwarfreloc(arangessec);
+	arangesrelocsize = cpos() - arangesreloco;
+	align(arangesrelocsize);
+
+	linereloco = writedwarfreloc(linesec);
+	linerelocsize = cpos() - linereloco;
+	align(linerelocsize);
+
+	framereloco = writedwarfreloc(framesec);
+	framerelocsize = cpos() - framereloco;
+	align(framerelocsize);
+}
+
+/*
+ *  Elf.
+ */
+enum
+{
+	ElfStrDebugAbbrev,
+	ElfStrDebugAranges,
+	ElfStrDebugFrame,
+	ElfStrDebugInfo,
+	ElfStrDebugLine,
+	ElfStrDebugLoc,
+	ElfStrDebugMacinfo,
+	ElfStrDebugPubNames,
+	ElfStrDebugPubTypes,
+	ElfStrDebugRanges,
+	ElfStrDebugStr,
+	ElfStrGDBScripts,
+	ElfStrRelDebugInfo,
+	ElfStrRelDebugAranges,
+	ElfStrRelDebugLine,
+	ElfStrRelDebugFrame,
+	NElfStrDbg
+};
+
+vlong elfstrdbg[NElfStrDbg];
+
+void
+dwarfaddshstrings(LSym *shstrtab)
+{
+	if(debug['w'])  // disable dwarf
+		return;
+
+	elfstrdbg[ElfStrDebugAbbrev]   = addstring(shstrtab, ".debug_abbrev");
+	elfstrdbg[ElfStrDebugAranges]  = addstring(shstrtab, ".debug_aranges");
+	elfstrdbg[ElfStrDebugFrame]    = addstring(shstrtab, ".debug_frame");
+	elfstrdbg[ElfStrDebugInfo]     = addstring(shstrtab, ".debug_info");
+	elfstrdbg[ElfStrDebugLine]     = addstring(shstrtab, ".debug_line");
+	elfstrdbg[ElfStrDebugLoc]      = addstring(shstrtab, ".debug_loc");
+	elfstrdbg[ElfStrDebugMacinfo]  = addstring(shstrtab, ".debug_macinfo");
+	elfstrdbg[ElfStrDebugPubNames] = addstring(shstrtab, ".debug_pubnames");
+	elfstrdbg[ElfStrDebugPubTypes] = addstring(shstrtab, ".debug_pubtypes");
+	elfstrdbg[ElfStrDebugRanges]   = addstring(shstrtab, ".debug_ranges");
+	elfstrdbg[ElfStrDebugStr]      = addstring(shstrtab, ".debug_str");
+	elfstrdbg[ElfStrGDBScripts]    = addstring(shstrtab, ".debug_gdb_scripts");
+	if(linkmode == LinkExternal) {
+		if(thechar == '6') {
+			elfstrdbg[ElfStrRelDebugInfo] = addstring(shstrtab, ".rela.debug_info");
+			elfstrdbg[ElfStrRelDebugAranges] = addstring(shstrtab, ".rela.debug_aranges");
+			elfstrdbg[ElfStrRelDebugLine] = addstring(shstrtab, ".rela.debug_line");
+			elfstrdbg[ElfStrRelDebugFrame] = addstring(shstrtab, ".rela.debug_frame");
+		} else {
+			elfstrdbg[ElfStrRelDebugInfo] = addstring(shstrtab, ".rel.debug_info");
+			elfstrdbg[ElfStrRelDebugAranges] = addstring(shstrtab, ".rel.debug_aranges");
+			elfstrdbg[ElfStrRelDebugLine] = addstring(shstrtab, ".rel.debug_line");
+			elfstrdbg[ElfStrRelDebugFrame] = addstring(shstrtab, ".rel.debug_frame");
+		}
+
+		infosym = linklookup(ctxt, ".debug_info", 0);
+		infosym->hide = 1;
+
+		abbrevsym = linklookup(ctxt, ".debug_abbrev", 0);
+		abbrevsym->hide = 1;
+
+		linesym = linklookup(ctxt, ".debug_line", 0);
+		linesym->hide = 1;
+
+		framesym = linklookup(ctxt, ".debug_frame", 0);
+		framesym->hide = 1;
+	}
+}
+
+// Add section symbols for DWARF debug info.  This is called before
+// dwarfaddelfheaders.
+void
+dwarfaddelfsectionsyms()
+{
+	if(infosym != nil) {
+		infosympos = cpos();
+		putelfsectionsym(infosym, 0);
+	}
+	if(abbrevsym != nil) {
+		abbrevsympos = cpos();
+		putelfsectionsym(abbrevsym, 0);
+	}
+	if(linesym != nil) {
+		linesympos = cpos();
+		putelfsectionsym(linesym, 0);
+	}
+	if(framesym != nil) {
+		framesympos = cpos();
+		putelfsectionsym(framesym, 0);
+	}
+}
+
+static void
+dwarfaddelfrelocheader(int elfstr, ElfShdr *shdata, vlong off, vlong size)
+{
+	ElfShdr *sh;
+
+	sh = newElfShdr(elfstrdbg[elfstr]);
+	if(thechar == '6') {
+		sh->type = SHT_RELA;
+	} else {
+		sh->type = SHT_REL;
+	}
+	sh->entsize = PtrSize*(2+(sh->type==SHT_RELA));
+	sh->link = elfshname(".symtab")->shnum;
+	sh->info = shdata->shnum;
+	sh->off = off;
+	sh->size = size;
+	sh->addralign = PtrSize;
+	
+}
+
+void
+dwarfaddelfheaders(void)
+{
+	ElfShdr *sh, *shinfo, *sharanges, *shline, *shframe;
+
+	if(debug['w'])  // disable dwarf
+		return;
+
+	sh = newElfShdr(elfstrdbg[ElfStrDebugAbbrev]);
+	sh->type = SHT_PROGBITS;
+	sh->off = abbrevo;
+	sh->size = abbrevsize;
+	sh->addralign = 1;
+	if(abbrevsympos > 0)
+		putelfsymshndx(abbrevsympos, sh->shnum);
+
+	sh = newElfShdr(elfstrdbg[ElfStrDebugLine]);
+	sh->type = SHT_PROGBITS;
+	sh->off = lineo;
+	sh->size = linesize;
+	sh->addralign = 1;
+	if(linesympos > 0)
+		putelfsymshndx(linesympos, sh->shnum);
+	shline = sh;
+
+	sh = newElfShdr(elfstrdbg[ElfStrDebugFrame]);
+	sh->type = SHT_PROGBITS;
+	sh->off = frameo;
+	sh->size = framesize;
+	sh->addralign = 1;
+	if(framesympos > 0)
+		putelfsymshndx(framesympos, sh->shnum);
+	shframe = sh;
+
+	sh = newElfShdr(elfstrdbg[ElfStrDebugInfo]);
+	sh->type = SHT_PROGBITS;
+	sh->off = infoo;
+	sh->size = infosize;
+	sh->addralign = 1;
+	if(infosympos > 0)
+		putelfsymshndx(infosympos, sh->shnum);
+	shinfo = sh;
+
+	if (pubnamessize > 0) {
+		sh = newElfShdr(elfstrdbg[ElfStrDebugPubNames]);
+		sh->type = SHT_PROGBITS;
+		sh->off = pubnameso;
+		sh->size = pubnamessize;
+		sh->addralign = 1;
+	}
+
+	if (pubtypessize > 0) {
+		sh = newElfShdr(elfstrdbg[ElfStrDebugPubTypes]);
+		sh->type = SHT_PROGBITS;
+		sh->off = pubtypeso;
+		sh->size = pubtypessize;
+		sh->addralign = 1;
+	}
+
+	sharanges = nil;
+	if (arangessize) {
+		sh = newElfShdr(elfstrdbg[ElfStrDebugAranges]);
+		sh->type = SHT_PROGBITS;
+		sh->off = arangeso;
+		sh->size = arangessize;
+		sh->addralign = 1;
+		sharanges = sh;
+	}
+
+	if (gdbscriptsize) {
+		sh = newElfShdr(elfstrdbg[ElfStrGDBScripts]);
+		sh->type = SHT_PROGBITS;
+		sh->off = gdbscripto;
+		sh->size = gdbscriptsize;
+		sh->addralign = 1;
+	}
+
+	if(inforelocsize)
+		dwarfaddelfrelocheader(ElfStrRelDebugInfo, shinfo, inforeloco, inforelocsize);
+
+	if(arangesrelocsize)
+		dwarfaddelfrelocheader(ElfStrRelDebugAranges, sharanges, arangesreloco, arangesrelocsize);
+
+	if(linerelocsize)
+		dwarfaddelfrelocheader(ElfStrRelDebugLine, shline, linereloco, linerelocsize);
+
+	if(framerelocsize)
+		dwarfaddelfrelocheader(ElfStrRelDebugFrame, shframe, framereloco, framerelocsize);
+}
+
+/*
+ * Macho
+ */
+void
+dwarfaddmachoheaders(void)
+{
+	MachoSect *msect;
+	MachoSeg *ms;
+	vlong fakestart;
+	int nsect;
+
+	if(debug['w'])  // disable dwarf
+		return;
+
+	// Zero vsize segments won't be loaded in memory, even so they
+	// have to be page aligned in the file.
+	fakestart = abbrevo & ~0xfff;
+
+	nsect = 4;
+	if (pubnamessize  > 0)
+		nsect++;
+	if (pubtypessize  > 0)
+		nsect++;
+	if (arangessize	  > 0)
+		nsect++;
+	if (gdbscriptsize > 0)
+		nsect++;
+
+	ms = newMachoSeg("__DWARF", nsect);
+	ms->fileoffset = fakestart;
+	ms->filesize = abbrevo-fakestart;
+	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;
+	}
+
+	if (pubtypessize > 0) {
+		msect = newMachoSect(ms, "__debug_pubtypes", "__DWARF");
+		msect->off = pubtypeso;
+		msect->size = pubtypessize;
+		msect->addr = msect->off + segdata.vaddr - segdata.fileoff;
+		ms->filesize += msect->size;
+	}
+
+	if (arangessize > 0) {
+		msect = newMachoSect(ms, "__debug_aranges", "__DWARF");
+		msect->off = arangeso;
+		msect->size = arangessize;
+		msect->addr = msect->off + segdata.vaddr - segdata.fileoff;
+		ms->filesize += msect->size;
+	}
+
+	// TODO(lvd) fix gdb/python to load MachO (16 char section name limit)
+	if (gdbscriptsize > 0) {
+		msect = newMachoSect(ms, "__debug_gdb_scripts", "__DWARF");
+		msect->off = gdbscripto;
+		msect->size = gdbscriptsize;
+		msect->addr = msect->off + segdata.vaddr - segdata.fileoff;
+		ms->filesize += msect->size;
+	}
+}
+
+/*
+ * Windows PE
+ */
+void
+dwarfaddpeheaders(void)
+{
+	if(debug['w'])  // disable dwarf
+		return;
+
+	newPEDWARFSection(".debug_abbrev", abbrevsize);
+	newPEDWARFSection(".debug_line", linesize);
+	newPEDWARFSection(".debug_frame", framesize);
+	newPEDWARFSection(".debug_info", infosize);
+	newPEDWARFSection(".debug_pubnames", pubnamessize);
+	newPEDWARFSection(".debug_pubtypes", pubtypessize);
+	newPEDWARFSection(".debug_aranges", arangessize);
+	newPEDWARFSection(".debug_gdb_scripts", gdbscriptsize);
+}
diff --git a/src/cmd/ld/dwarf.h b/src/cmd/ld/dwarf.h
new file mode 100644
index 0000000..32db36d
--- /dev/null
+++ b/src/cmd/ld/dwarf.h
@@ -0,0 +1,24 @@
+// 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.
+
+/*
+ * Emit debug_abbrevs, debug_info and debug_line sections to current
+ * offset in cout.
+ */
+void dwarfemitdebugsections(void);
+
+/*
+ * Add the dwarf section names to the ELF
+ * s[ection]h[eader]str[ing]tab.  Prerequisite for
+ * dwarfaddelfheaders().
+ */
+void dwarfaddshstrings(LSym *shstrtab);
+
+/*
+ * Add section headers pointing to the sections emitted in
+ * dwarfemitdebugsections.
+ */
+void dwarfaddelfheaders(void);
+void dwarfaddmachoheaders(void);
+void dwarfaddpeheaders(void);
diff --git a/src/cmd/ld/dwarf_defs.h b/src/cmd/ld/dwarf_defs.h
new file mode 100644
index 0000000..93e99ff
--- /dev/null
+++ b/src/cmd/ld/dwarf_defs.h
@@ -0,0 +1,504 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Cut, pasted, tr-and-awk'ed from tables in
+// http://dwarfstd.org/doc/Dwarf3.pdf
+
+// Table 18
+enum
+{
+	DW_TAG_array_type = 0x01,
+	DW_TAG_class_type = 0x02,
+	DW_TAG_entry_point = 0x03,
+	DW_TAG_enumeration_type = 0x04,
+	DW_TAG_formal_parameter = 0x05,
+	DW_TAG_imported_declaration = 0x08,
+	DW_TAG_label = 0x0a,
+	DW_TAG_lexical_block = 0x0b,
+	DW_TAG_member = 0x0d,
+	DW_TAG_pointer_type = 0x0f,
+	DW_TAG_reference_type = 0x10,
+	DW_TAG_compile_unit = 0x11,
+	DW_TAG_string_type = 0x12,
+	DW_TAG_structure_type = 0x13,
+	DW_TAG_subroutine_type = 0x15,
+	DW_TAG_typedef = 0x16,
+	DW_TAG_union_type = 0x17,
+	DW_TAG_unspecified_parameters = 0x18,
+	DW_TAG_variant = 0x19,
+	DW_TAG_common_block = 0x1a,
+	DW_TAG_common_inclusion = 0x1b,
+	DW_TAG_inheritance = 0x1c,
+	DW_TAG_inlined_subroutine = 0x1d,
+	DW_TAG_module = 0x1e,
+	DW_TAG_ptr_to_member_type = 0x1f,
+	DW_TAG_set_type = 0x20,
+	DW_TAG_subrange_type = 0x21,
+	DW_TAG_with_stmt = 0x22,
+	DW_TAG_access_declaration = 0x23,
+	DW_TAG_base_type = 0x24,
+	DW_TAG_catch_block = 0x25,
+	DW_TAG_const_type = 0x26,
+	DW_TAG_constant = 0x27,
+	DW_TAG_enumerator = 0x28,
+	DW_TAG_file_type = 0x29,
+	DW_TAG_friend = 0x2a,
+	DW_TAG_namelist = 0x2b,
+	DW_TAG_namelist_item = 0x2c,
+	DW_TAG_packed_type = 0x2d,
+	DW_TAG_subprogram = 0x2e,
+	DW_TAG_template_type_parameter = 0x2f,
+	DW_TAG_template_value_parameter = 0x30,
+	DW_TAG_thrown_type = 0x31,
+	DW_TAG_try_block = 0x32,
+	DW_TAG_variant_part = 0x33,
+	DW_TAG_variable = 0x34,
+	DW_TAG_volatile_type = 0x35,
+	// Dwarf3
+	DW_TAG_dwarf_procedure = 0x36,
+	DW_TAG_restrict_type = 0x37,
+	DW_TAG_interface_type = 0x38,
+	DW_TAG_namespace = 0x39,
+	DW_TAG_imported_module = 0x3a,
+	DW_TAG_unspecified_type = 0x3b,
+	DW_TAG_partial_unit = 0x3c,
+	DW_TAG_imported_unit = 0x3d,
+	DW_TAG_condition = 0x3f,
+	DW_TAG_shared_type = 0x40,
+	// Dwarf4
+	DW_TAG_type_unit = 0x41,
+	DW_TAG_rvalue_reference_type = 0x42,
+	DW_TAG_template_alias = 0x43,
+
+	// User defined
+	DW_TAG_lo_user = 0x4080,
+	DW_TAG_hi_user = 0xffff,
+
+};
+
+// Table 19
+enum
+{
+	DW_CHILDREN_no = 0x00,
+	DW_CHILDREN_yes = 0x01,
+};
+
+// Not from the spec, but logicaly belongs here
+enum
+{
+	DW_CLS_ADDRESS = 0x01,
+	DW_CLS_BLOCK,
+	DW_CLS_CONSTANT,
+	DW_CLS_FLAG,
+	DW_CLS_PTR,	// lineptr, loclistptr, macptr, rangelistptr
+	DW_CLS_REFERENCE,
+	DW_CLS_ADDRLOC,
+	DW_CLS_STRING
+};
+
+// Table 20
+enum
+{
+	DW_AT_sibling = 0x01,	// reference
+	DW_AT_location = 0x02,	// block, loclistptr
+	DW_AT_name = 0x03,	// string
+	DW_AT_ordering = 0x09,	// constant
+	DW_AT_byte_size = 0x0b,	// block, constant, reference
+	DW_AT_bit_offset = 0x0c,	// block, constant, reference
+	DW_AT_bit_size = 0x0d,	// block, constant, reference
+	DW_AT_stmt_list = 0x10,	// lineptr
+	DW_AT_low_pc = 0x11,	// address
+	DW_AT_high_pc = 0x12,	// address
+	DW_AT_language = 0x13,	// constant
+	DW_AT_discr = 0x15,	// reference
+	DW_AT_discr_value = 0x16,	// constant
+	DW_AT_visibility = 0x17,	// constant
+	DW_AT_import = 0x18,	// reference
+	DW_AT_string_length = 0x19,	// block, loclistptr
+	DW_AT_common_reference = 0x1a,	// reference
+	DW_AT_comp_dir = 0x1b,	// string
+	DW_AT_const_value = 0x1c,	// block, constant, string
+	DW_AT_containing_type = 0x1d,	// reference
+	DW_AT_default_value = 0x1e,	// reference
+	DW_AT_inline = 0x20,	// constant
+	DW_AT_is_optional = 0x21,	// flag
+	DW_AT_lower_bound = 0x22,	// block, constant, reference
+	DW_AT_producer = 0x25,	// string
+	DW_AT_prototyped = 0x27,	// flag
+	DW_AT_return_addr = 0x2a,	// block, loclistptr
+	DW_AT_start_scope = 0x2c,	// constant
+	DW_AT_bit_stride = 0x2e,	// constant
+	DW_AT_upper_bound = 0x2f,	// block, constant, reference
+	DW_AT_abstract_origin = 0x31,	// reference
+	DW_AT_accessibility = 0x32,	// constant
+	DW_AT_address_class = 0x33,	// constant
+	DW_AT_artificial = 0x34,	// flag
+	DW_AT_base_types = 0x35,	// reference
+	DW_AT_calling_convention = 0x36,	// constant
+	DW_AT_count = 0x37,	// block, constant, reference
+	DW_AT_data_member_location = 0x38,	// block, constant, loclistptr
+	DW_AT_decl_column = 0x39,	// constant
+	DW_AT_decl_file = 0x3a,	// constant
+	DW_AT_decl_line = 0x3b,	// constant
+	DW_AT_declaration = 0x3c,	// flag
+	DW_AT_discr_list = 0x3d,	// block
+	DW_AT_encoding = 0x3e,	// constant
+	DW_AT_external = 0x3f,	// flag
+	DW_AT_frame_base = 0x40,	// block, loclistptr
+	DW_AT_friend = 0x41,	// reference
+	DW_AT_identifier_case = 0x42,	// constant
+	DW_AT_macro_info = 0x43,	// macptr
+	DW_AT_namelist_item = 0x44,	// block
+	DW_AT_priority = 0x45,	// reference
+	DW_AT_segment = 0x46,	// block, loclistptr
+	DW_AT_specification = 0x47,	// reference
+	DW_AT_static_link = 0x48,	// block, loclistptr
+	DW_AT_type = 0x49,	// reference
+	DW_AT_use_location = 0x4a,	// block, loclistptr
+	DW_AT_variable_parameter = 0x4b,	// flag
+	DW_AT_virtuality = 0x4c,	// constant
+	DW_AT_vtable_elem_location = 0x4d,	// block, loclistptr
+	// Dwarf3
+	DW_AT_allocated = 0x4e,	// block, constant, reference
+	DW_AT_associated = 0x4f,	// block, constant, reference
+	DW_AT_data_location = 0x50,	// block
+	DW_AT_byte_stride = 0x51,	// block, constant, reference
+	DW_AT_entry_pc = 0x52,	// address
+	DW_AT_use_UTF8 = 0x53,	// flag
+	DW_AT_extension = 0x54,	// reference
+	DW_AT_ranges = 0x55,	// rangelistptr
+	DW_AT_trampoline = 0x56,	// address, flag, reference, string
+	DW_AT_call_column = 0x57,	// constant
+	DW_AT_call_file = 0x58,	// constant
+	DW_AT_call_line = 0x59,	// constant
+	DW_AT_description = 0x5a,	// string
+	DW_AT_binary_scale = 0x5b,	// constant
+	DW_AT_decimal_scale = 0x5c,	// constant
+	DW_AT_small = 0x5d,	// reference
+	DW_AT_decimal_sign = 0x5e,	// constant
+	DW_AT_digit_count = 0x5f,	// constant
+	DW_AT_picture_string = 0x60,	// string
+	DW_AT_mutable = 0x61,	// flag
+	DW_AT_threads_scaled = 0x62,	// flag
+	DW_AT_explicit = 0x63,	// flag
+	DW_AT_object_pointer = 0x64,	// reference
+	DW_AT_endianity = 0x65,	// constant
+	DW_AT_elemental = 0x66,	// flag
+	DW_AT_pure = 0x67,	// flag
+	DW_AT_recursive = 0x68,	// flag
+
+	DW_AT_lo_user = 0x2000,	// ---
+	DW_AT_hi_user = 0x3fff,	// ---
+
+};
+
+// Table 21
+enum
+{
+	DW_FORM_addr = 0x01,	// address
+	DW_FORM_block2 = 0x03,	// block
+	DW_FORM_block4 = 0x04,	// block
+	DW_FORM_data2 = 0x05,	// constant
+	DW_FORM_data4 = 0x06,	// constant, lineptr, loclistptr, macptr, rangelistptr
+	DW_FORM_data8 = 0x07,	// constant, lineptr, loclistptr, macptr, rangelistptr
+	DW_FORM_string = 0x08,	// string
+	DW_FORM_block = 0x09,	// block
+	DW_FORM_block1 = 0x0a,	// block
+	DW_FORM_data1 = 0x0b,	// constant
+	DW_FORM_flag = 0x0c,	// flag
+	DW_FORM_sdata = 0x0d,	// constant
+	DW_FORM_strp = 0x0e,	// string
+	DW_FORM_udata = 0x0f,	// constant
+	DW_FORM_ref_addr = 0x10,	// reference
+	DW_FORM_ref1 = 0x11,	// reference
+	DW_FORM_ref2 = 0x12,	// reference
+	DW_FORM_ref4 = 0x13,	// reference
+	DW_FORM_ref8 = 0x14,	// reference
+	DW_FORM_ref_udata = 0x15,	// reference
+	DW_FORM_indirect = 0x16,	// (see Section 7.5.3)
+};
+
+// Table 24 (#operands, notes)
+enum
+{
+	DW_OP_addr = 0x03,	// 1 constant address (size target specific)
+	DW_OP_deref = 0x06,	// 0
+	DW_OP_const1u = 0x08,	// 1 1-byte constant
+	DW_OP_const1s = 0x09,	// 1 1-byte constant
+	DW_OP_const2u = 0x0a,	// 1 2-byte constant
+	DW_OP_const2s = 0x0b,	// 1 2-byte constant
+	DW_OP_const4u = 0x0c,	// 1 4-byte constant
+	DW_OP_const4s = 0x0d,	// 1 4-byte constant
+	DW_OP_const8u = 0x0e,	// 1 8-byte constant
+	DW_OP_const8s = 0x0f,	// 1 8-byte constant
+	DW_OP_constu = 0x10,	// 1 ULEB128 constant
+	DW_OP_consts = 0x11,	// 1 SLEB128 constant
+	DW_OP_dup = 0x12,	// 0
+	DW_OP_drop = 0x13,	// 0
+	DW_OP_over = 0x14,	// 0
+	DW_OP_pick = 0x15,	// 1 1-byte stack index
+	DW_OP_swap = 0x16,	// 0
+	DW_OP_rot = 0x17,	// 0
+	DW_OP_xderef = 0x18,	// 0
+	DW_OP_abs = 0x19,	// 0
+	DW_OP_and = 0x1a,	// 0
+	DW_OP_div = 0x1b,	// 0
+	DW_OP_minus = 0x1c,	// 0
+	DW_OP_mod = 0x1d,	// 0
+	DW_OP_mul = 0x1e,	// 0
+	DW_OP_neg = 0x1f,	// 0
+	DW_OP_not = 0x20,	// 0
+	DW_OP_or = 0x21,	// 0
+	DW_OP_plus = 0x22,	// 0
+	DW_OP_plus_uconst = 0x23,	// 1 ULEB128 addend
+	DW_OP_shl = 0x24,	// 0
+	DW_OP_shr = 0x25,	// 0
+	DW_OP_shra = 0x26,	// 0
+	DW_OP_xor = 0x27,	// 0
+	DW_OP_skip = 0x2f,	// 1 signed 2-byte constant
+	DW_OP_bra = 0x28,	// 1 signed 2-byte constant
+	DW_OP_eq = 0x29,	// 0
+	DW_OP_ge = 0x2a,	// 0
+	DW_OP_gt = 0x2b,	// 0
+	DW_OP_le = 0x2c,	// 0
+	DW_OP_lt = 0x2d,	// 0
+	DW_OP_ne = 0x2e,	// 0
+	DW_OP_lit0 = 0x30,	// 0 ...
+	DW_OP_lit31 = 0x4f,	// 0 literals 0..31 = (DW_OP_lit0 +
+	// literal)
+	DW_OP_reg0 = 0x50,	// 0 ..
+	DW_OP_reg31 = 0x6f,	// 0 reg 0..31 = (DW_OP_reg0 + regnum)
+	DW_OP_breg0 = 0x70,	// 1 ...
+	DW_OP_breg31 = 0x8f,	// 1 SLEB128 offset base register 0..31 = (DW_OP_breg0 + regnum)
+	DW_OP_regx = 0x90,	// 1 ULEB128 register
+	DW_OP_fbreg = 0x91,	// 1 SLEB128 offset
+	DW_OP_bregx = 0x92,	// 2 ULEB128 register followed by SLEB128 offset
+	DW_OP_piece = 0x93,	// 1 ULEB128 size of piece addressed
+	DW_OP_deref_size = 0x94,	// 1 1-byte size of data retrieved
+	DW_OP_xderef_size = 0x95,	// 1 1-byte size of data retrieved
+	DW_OP_nop = 0x96,	// 0
+	DW_OP_push_object_address = 0x97,	// 0
+	DW_OP_call2 = 0x98,	// 1 2-byte offset of DIE
+	DW_OP_call4 = 0x99,	// 1 4-byte offset of DIE
+	DW_OP_call_ref = 0x9a,	// 1 4- or 8-byte offset of DIE
+	DW_OP_form_tls_address = 0x9b,	// 0
+	DW_OP_call_frame_cfa = 0x9c,	// 0
+	DW_OP_bit_piece = 0x9d,	// 2
+	DW_OP_lo_user = 0xe0,
+	DW_OP_hi_user = 0xff,
+};
+
+// Table 25
+enum
+{
+	DW_ATE_address = 0x01,
+	DW_ATE_boolean = 0x02,
+	DW_ATE_complex_float = 0x03,
+	DW_ATE_float = 0x04,
+	DW_ATE_signed = 0x05,
+	DW_ATE_signed_char = 0x06,
+	DW_ATE_unsigned = 0x07,
+	DW_ATE_unsigned_char = 0x08,
+	DW_ATE_imaginary_float = 0x09,
+	DW_ATE_packed_decimal = 0x0a,
+	DW_ATE_numeric_string = 0x0b,
+	DW_ATE_edited = 0x0c,
+	DW_ATE_signed_fixed = 0x0d,
+	DW_ATE_unsigned_fixed = 0x0e,
+	DW_ATE_decimal_float = 0x0f,
+	DW_ATE_lo_user = 0x80,
+	DW_ATE_hi_user = 0xff,
+};
+
+// Table 26
+enum
+{
+	DW_DS_unsigned = 0x01,
+	DW_DS_leading_overpunch = 0x02,
+	DW_DS_trailing_overpunch = 0x03,
+	DW_DS_leading_separate = 0x04,
+	DW_DS_trailing_separate = 0x05,
+};
+
+// Table 27
+enum
+{
+	DW_END_default = 0x00,
+	DW_END_big = 0x01,
+	DW_END_little = 0x02,
+	DW_END_lo_user = 0x40,
+	DW_END_hi_user = 0xff,
+};
+
+// Table 28
+enum
+{
+	DW_ACCESS_public = 0x01,
+	DW_ACCESS_protected = 0x02,
+	DW_ACCESS_private = 0x03,
+};
+
+// Table 29
+enum
+{
+	DW_VIS_local = 0x01,
+	DW_VIS_exported = 0x02,
+	DW_VIS_qualified = 0x03,
+};
+
+// Table 30
+enum
+{
+	DW_VIRTUALITY_none = 0x00,
+	DW_VIRTUALITY_virtual = 0x01,
+	DW_VIRTUALITY_pure_virtual = 0x02,
+};
+
+// Table 31
+enum
+{
+	DW_LANG_C89 = 0x0001,
+	DW_LANG_C = 0x0002,
+	DW_LANG_Ada83 = 0x0003,
+	DW_LANG_C_plus_plus = 0x0004,
+	DW_LANG_Cobol74 = 0x0005,
+	DW_LANG_Cobol85 = 0x0006,
+	DW_LANG_Fortran77 = 0x0007,
+	DW_LANG_Fortran90 = 0x0008,
+	DW_LANG_Pascal83 = 0x0009,
+	DW_LANG_Modula2 = 0x000a,
+	// Dwarf3
+	DW_LANG_Java = 0x000b,
+	DW_LANG_C99 = 0x000c,
+	DW_LANG_Ada95 = 0x000d,
+	DW_LANG_Fortran95 = 0x000e,
+	DW_LANG_PLI = 0x000f,
+	DW_LANG_ObjC = 0x0010,
+	DW_LANG_ObjC_plus_plus = 0x0011,
+	DW_LANG_UPC = 0x0012,
+	DW_LANG_D = 0x0013,
+	// Dwarf4
+	DW_LANG_Python = 0x0014,
+	// Dwarf5
+	DW_LANG_Go = 0x0016,
+
+	DW_LANG_lo_user = 0x8000,
+	DW_LANG_hi_user = 0xffff,
+};
+
+// Table 32
+enum
+{
+	DW_ID_case_sensitive = 0x00,
+	DW_ID_up_case = 0x01,
+	DW_ID_down_case = 0x02,
+	DW_ID_case_insensitive = 0x03,
+};
+
+// Table 33
+enum
+{
+	DW_CC_normal = 0x01,
+	DW_CC_program = 0x02,
+	DW_CC_nocall = 0x03,
+	DW_CC_lo_user = 0x40,
+	DW_CC_hi_user = 0xff,
+};
+
+// Table 34
+enum
+{
+	DW_INL_not_inlined = 0x00,
+	DW_INL_inlined = 0x01,
+	DW_INL_declared_not_inlined = 0x02,
+	DW_INL_declared_inlined = 0x03,
+};
+
+// Table 35
+enum
+{
+	DW_ORD_row_major = 0x00,
+	DW_ORD_col_major = 0x01,
+};
+
+// Table 36
+enum
+{
+	DW_DSC_label = 0x00,
+	DW_DSC_range = 0x01,
+};
+
+// Table 37
+enum
+{
+	DW_LNS_copy = 0x01,
+	DW_LNS_advance_pc = 0x02,
+	DW_LNS_advance_line = 0x03,
+	DW_LNS_set_file = 0x04,
+	DW_LNS_set_column = 0x05,
+	DW_LNS_negate_stmt = 0x06,
+	DW_LNS_set_basic_block = 0x07,
+	DW_LNS_const_add_pc = 0x08,
+	DW_LNS_fixed_advance_pc = 0x09,
+	// Dwarf3
+	DW_LNS_set_prologue_end = 0x0a,
+	DW_LNS_set_epilogue_begin = 0x0b,
+	DW_LNS_set_isa = 0x0c,
+};
+
+// Table 38
+enum
+{
+	DW_LNE_end_sequence = 0x01,
+	DW_LNE_set_address = 0x02,
+	DW_LNE_define_file = 0x03,
+	DW_LNE_lo_user = 0x80,
+	DW_LNE_hi_user = 0xff,
+};
+
+// Table 39
+enum
+{
+	DW_MACINFO_define = 0x01,
+	DW_MACINFO_undef = 0x02,
+	DW_MACINFO_start_file = 0x03,
+	DW_MACINFO_end_file = 0x04,
+	DW_MACINFO_vendor_ext = 0xff,
+};
+
+// Table 40.
+enum
+{					// operand,...
+	DW_CFA_nop = 0x00,
+	DW_CFA_set_loc = 0x01,		// address
+	DW_CFA_advance_loc1 = 0x02,	// 1-byte delta
+	DW_CFA_advance_loc2 = 0x03,	// 2-byte delta
+	DW_CFA_advance_loc4 = 0x04,	// 4-byte delta
+	DW_CFA_offset_extended = 0x05,	// ULEB128 register, ULEB128 offset
+	DW_CFA_restore_extended = 0x06, // ULEB128 register
+	DW_CFA_undefined = 0x07,	// ULEB128 register
+	DW_CFA_same_value = 0x08,	// ULEB128 register
+	DW_CFA_register = 0x09,		// ULEB128 register, ULEB128 register
+	DW_CFA_remember_state = 0x0a,
+	DW_CFA_restore_state = 0x0b,
+	DW_CFA_def_cfa = 0x0c,		// ULEB128 register, ULEB128 offset
+	DW_CFA_def_cfa_register = 0x0d,	// ULEB128 register
+	DW_CFA_def_cfa_offset = 0x0e,	// ULEB128 offset
+	DW_CFA_def_cfa_expression = 0x0f, // BLOCK
+	DW_CFA_expression = 0x10,	// ULEB128 register, BLOCK
+	DW_CFA_offset_extended_sf = 0x11, // ULEB128 register, SLEB128 offset
+	DW_CFA_def_cfa_sf = 0x12,	// ULEB128 register, SLEB128 offset
+	DW_CFA_def_cfa_offset_sf = 0x13, // SLEB128 offset
+	DW_CFA_val_offset = 0x14,	// ULEB128, ULEB128
+	DW_CFA_val_offset_sf = 0x15,	// ULEB128, SLEB128
+	DW_CFA_val_expression = 0x16,	// ULEB128, BLOCK
+
+	DW_CFA_lo_user = 0x1c,
+	DW_CFA_hi_user = 0x3f,
+
+	// Opcodes that take an addend operand.
+	DW_CFA_advance_loc = 0x1<<6, // +delta
+	DW_CFA_offset	   = 0x2<<6, // +register (ULEB128 offset)
+	DW_CFA_restore	   = 0x3<<6, // +register
+};
diff --git a/src/cmd/ld/elf.c b/src/cmd/ld/elf.c
new file mode 100644
index 0000000..3196961
--- /dev/null
+++ b/src/cmd/ld/elf.c
@@ -0,0 +1,1526 @@
+// 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	"lib.h"
+#include	"../ld/elf.h"
+
+/*
+ * We use the 64-bit data structures on both 32- and 64-bit machines
+ * in order to write the code just once.  The 64-bit data structure is
+ * written in the 32-bit format on the 32-bit machines.
+ */
+#define	NSECT	48
+
+int	iself;
+
+static	int	elf64;
+static	ElfEhdr	hdr;
+static	ElfPhdr	*phdr[NSECT];
+static	ElfShdr	*shdr[NSECT];
+static	char	*interp;
+
+typedef struct Elfstring Elfstring;
+struct Elfstring
+{
+	char *s;
+	int off;
+};
+
+static Elfstring elfstr[100];
+static int nelfstr;
+
+static char buildinfo[32];
+
+/*
+ Initialize the global variable that describes the ELF header. It will be updated as
+ we write section and prog headers.
+ */
+void
+elfinit(void)
+{
+	iself = 1;
+
+	switch(thechar) {
+	// 64-bit architectures
+	case '6':
+		elf64 = 1;
+		hdr.phoff = ELF64HDRSIZE;	/* Must be be ELF64HDRSIZE: first PHdr must follow ELF header */
+		hdr.shoff = ELF64HDRSIZE;	/* Will move as we add PHeaders */
+		hdr.ehsize = ELF64HDRSIZE;	/* Must be ELF64HDRSIZE */
+		hdr.phentsize = ELF64PHDRSIZE;	/* Must be ELF64PHDRSIZE */
+		hdr.shentsize = ELF64SHDRSIZE;	/* Must be ELF64SHDRSIZE */
+		break;
+
+	// 32-bit architectures
+	case '5':
+		// 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:
+		hdr.phoff = ELF32HDRSIZE;	/* Must be be ELF32HDRSIZE: first PHdr must follow ELF header */
+		hdr.shoff = ELF32HDRSIZE;	/* Will move as we add PHeaders */
+		hdr.ehsize = ELF32HDRSIZE;	/* Must be ELF32HDRSIZE */
+		hdr.phentsize = ELF32PHDRSIZE;	/* Must be ELF32PHDRSIZE */
+		hdr.shentsize = ELF32SHDRSIZE;	/* Must be ELF32SHDRSIZE */
+	}
+}
+
+void
+elf64phdr(ElfPhdr *e)
+{
+	LPUT(e->type);
+	LPUT(e->flags);
+	VPUT(e->off);
+	VPUT(e->vaddr);
+	VPUT(e->paddr);
+	VPUT(e->filesz);
+	VPUT(e->memsz);
+	VPUT(e->align);
+}
+
+void
+elf32phdr(ElfPhdr *e)
+{
+	int frag;
+	
+	if(e->type == PT_LOAD) {
+		// Correct ELF loaders will do this implicitly,
+		// but buggy ELF loaders like the one in some
+		// versions of QEMU won't.
+		frag = e->vaddr&(e->align-1);
+		e->off -= frag;
+		e->vaddr -= frag;
+		e->paddr -= frag;
+		e->filesz += frag;
+		e->memsz += frag;
+	}
+	LPUT(e->type);
+	LPUT(e->off);
+	LPUT(e->vaddr);
+	LPUT(e->paddr);
+	LPUT(e->filesz);
+	LPUT(e->memsz);
+	LPUT(e->flags);
+	LPUT(e->align);
+}
+
+void
+elf64shdr(ElfShdr *e)
+{
+	LPUT(e->name);
+	LPUT(e->type);
+	VPUT(e->flags);
+	VPUT(e->addr);
+	VPUT(e->off);
+	VPUT(e->size);
+	LPUT(e->link);
+	LPUT(e->info);
+	VPUT(e->addralign);
+	VPUT(e->entsize);
+}
+
+void
+elf32shdr(ElfShdr *e)
+{
+	LPUT(e->name);
+	LPUT(e->type);
+	LPUT(e->flags);
+	LPUT(e->addr);
+	LPUT(e->off);
+	LPUT(e->size);
+	LPUT(e->link);
+	LPUT(e->info);
+	LPUT(e->addralign);
+	LPUT(e->entsize);
+}
+
+uint32
+elfwriteshdrs(void)
+{
+	int i;
+
+	if (elf64) {
+		for (i = 0; i < hdr.shnum; i++)
+			elf64shdr(shdr[i]);
+		return hdr.shnum * ELF64SHDRSIZE;
+	}
+	for (i = 0; i < hdr.shnum; i++)
+		elf32shdr(shdr[i]);
+	return hdr.shnum * ELF32SHDRSIZE;
+}
+
+void
+elfsetstring(char *s, int off)
+{
+	if(nelfstr >= nelem(elfstr)) {
+		diag("too many elf strings");
+		errorexit();
+	}
+	elfstr[nelfstr].s = s;
+	elfstr[nelfstr].off = off;
+	nelfstr++;
+}
+
+uint32
+elfwritephdrs(void)
+{
+	int i;
+
+	if (elf64) {
+		for (i = 0; i < hdr.phnum; i++)
+			elf64phdr(phdr[i]);
+		return hdr.phnum * ELF64PHDRSIZE;
+	}
+	for (i = 0; i < hdr.phnum; i++)
+		elf32phdr(phdr[i]);
+	return hdr.phnum * ELF32PHDRSIZE;
+}
+
+ElfPhdr*
+newElfPhdr(void)
+{
+	ElfPhdr *e;
+
+	e = mal(sizeof *e);
+	if (hdr.phnum >= NSECT)
+		diag("too many phdrs");
+	else
+		phdr[hdr.phnum++] = e;
+	if (elf64)
+		hdr.shoff += ELF64PHDRSIZE;
+	else
+		hdr.shoff += ELF32PHDRSIZE;
+	return e;
+}
+
+ElfShdr*
+newElfShdr(vlong name)
+{
+	ElfShdr *e;
+
+	e = mal(sizeof *e);
+	e->name = name;
+	e->shnum = hdr.shnum;
+	if (hdr.shnum >= NSECT) {
+		diag("too many shdrs");
+	} else {
+		shdr[hdr.shnum++] = e;
+	}
+	return e;
+}
+
+ElfEhdr*
+getElfEhdr(void)
+{
+	return &hdr;
+}
+
+uint32
+elf64writehdr(void)
+{
+	int i;
+
+	for (i = 0; i < EI_NIDENT; i++)
+		cput(hdr.ident[i]);
+	WPUT(hdr.type);
+	WPUT(hdr.machine);
+	LPUT(hdr.version);
+	VPUT(hdr.entry);
+	VPUT(hdr.phoff);
+	VPUT(hdr.shoff);
+	LPUT(hdr.flags);
+	WPUT(hdr.ehsize);
+	WPUT(hdr.phentsize);
+	WPUT(hdr.phnum);
+	WPUT(hdr.shentsize);
+	WPUT(hdr.shnum);
+	WPUT(hdr.shstrndx);
+	return ELF64HDRSIZE;
+}
+
+uint32
+elf32writehdr(void)
+{
+	int i;
+
+	for (i = 0; i < EI_NIDENT; i++)
+		cput(hdr.ident[i]);
+	WPUT(hdr.type);
+	WPUT(hdr.machine);
+	LPUT(hdr.version);
+	LPUT(hdr.entry);
+	LPUT(hdr.phoff);
+	LPUT(hdr.shoff);
+	LPUT(hdr.flags);
+	WPUT(hdr.ehsize);
+	WPUT(hdr.phentsize);
+	WPUT(hdr.phnum);
+	WPUT(hdr.shentsize);
+	WPUT(hdr.shnum);
+	WPUT(hdr.shstrndx);
+	return ELF32HDRSIZE;
+}
+
+uint32
+elfwritehdr(void)
+{
+	if(elf64)
+		return elf64writehdr();
+	return elf32writehdr();
+}
+
+/* Taken directly from the definition document for ELF64 */
+uint32
+elfhash(uchar *name)
+{
+	uint32 h = 0, g;
+	while (*name) {
+		h = (h << 4) + *name++;
+		if (g = h & 0xf0000000)
+			h ^= g >> 24;
+		h &= 0x0fffffff;
+	}
+	return h;
+}
+
+void
+elfwritedynent(LSym *s, int tag, uint64 val)
+{
+	if(elf64) {
+		adduint64(ctxt, s, tag);
+		adduint64(ctxt, s, val);
+	} else {
+		adduint32(ctxt, s, tag);
+		adduint32(ctxt, s, val);
+	}
+}
+
+void
+elfwritedynentsym(LSym *s, int tag, LSym *t)
+{
+	if(elf64)
+		adduint64(ctxt, s, tag);
+	else
+		adduint32(ctxt, s, tag);
+	addaddr(ctxt, s, t);
+}
+
+void
+elfwritedynentsymsize(LSym *s, int tag, LSym *t)
+{
+	if(elf64)
+		adduint64(ctxt, s, tag);
+	else
+		adduint32(ctxt, s, tag);
+	addsize(ctxt, s, t);
+}
+
+int
+elfinterp(ElfShdr *sh, uint64 startva, uint64 resoff, char *p)
+{
+	int n;
+
+	interp = p;
+	n = strlen(interp)+1;
+	sh->addr = startva + resoff - n;
+	sh->off = resoff - n;
+	sh->size = n;
+
+	return n;
+}
+
+int
+elfwriteinterp(void)
+{
+	ElfShdr *sh;
+	
+	sh = elfshname(".interp");
+	cseek(sh->off);
+	cwrite(interp, sh->size);
+	return sh->size;
+}
+
+int
+elfnote(ElfShdr *sh, uint64 startva, uint64 resoff, int sz)
+{
+	uint64 n;
+
+	n = sizeof(Elf_Note) + sz + resoff % 4;
+
+	sh->type = SHT_NOTE;
+	sh->flags = SHF_ALLOC;
+	sh->addralign = 4;
+	sh->addr = startva + resoff - n;
+	sh->off = resoff - n;
+	sh->size = n - resoff % 4;
+
+	return n;
+}
+
+ElfShdr *
+elfwritenotehdr(char *str, uint32 namesz, uint32 descsz, uint32 tag)
+{
+	ElfShdr *sh;
+	
+	sh = elfshname(str);
+
+	// Write Elf_Note header.
+	cseek(sh->off);
+	LPUT(namesz);
+	LPUT(descsz);
+	LPUT(tag);
+
+	return sh;
+}
+
+// NetBSD Signature (as per sys/exec_elf.h)
+#define ELF_NOTE_NETBSD_NAMESZ		7
+#define ELF_NOTE_NETBSD_DESCSZ		4
+#define ELF_NOTE_NETBSD_TAG		1
+#define ELF_NOTE_NETBSD_NAME		"NetBSD\0\0"
+#define ELF_NOTE_NETBSD_VERSION		599000000	/* NetBSD 5.99 */
+
+int
+elfnetbsdsig(ElfShdr *sh, uint64 startva, uint64 resoff)
+{
+	int n;
+
+	n = rnd(ELF_NOTE_NETBSD_NAMESZ, 4) + rnd(ELF_NOTE_NETBSD_DESCSZ, 4);
+	return elfnote(sh, startva, resoff, n);
+}
+
+int
+elfwritenetbsdsig(void)
+{
+	ElfShdr *sh;
+
+	// Write Elf_Note header.
+	sh = elfwritenotehdr(".note.netbsd.ident", ELF_NOTE_NETBSD_NAMESZ, ELF_NOTE_NETBSD_DESCSZ, ELF_NOTE_NETBSD_TAG);
+	if(sh == nil)
+		return 0;
+
+	// Followed by NetBSD string and version.
+	cwrite(ELF_NOTE_NETBSD_NAME, ELF_NOTE_NETBSD_NAMESZ + 1);
+	LPUT(ELF_NOTE_NETBSD_VERSION);
+
+	return sh->size;
+}
+
+// OpenBSD Signature
+#define ELF_NOTE_OPENBSD_NAMESZ		8
+#define ELF_NOTE_OPENBSD_DESCSZ		4
+#define ELF_NOTE_OPENBSD_TAG		1
+#define ELF_NOTE_OPENBSD_NAME		"OpenBSD\0"
+#define ELF_NOTE_OPENBSD_VERSION	0
+
+int
+elfopenbsdsig(ElfShdr *sh, uint64 startva, uint64 resoff)
+{
+	int n;
+
+	n = ELF_NOTE_OPENBSD_NAMESZ + ELF_NOTE_OPENBSD_DESCSZ;
+	return elfnote(sh, startva, resoff, n);
+}
+
+int
+elfwriteopenbsdsig(void)
+{
+	ElfShdr *sh;
+
+	// Write Elf_Note header.
+	sh = elfwritenotehdr(".note.openbsd.ident", ELF_NOTE_OPENBSD_NAMESZ, ELF_NOTE_OPENBSD_DESCSZ, ELF_NOTE_OPENBSD_TAG);
+	if(sh == nil)
+		return 0;
+
+	// Followed by OpenBSD string and version.
+	cwrite(ELF_NOTE_OPENBSD_NAME, ELF_NOTE_OPENBSD_NAMESZ);
+	LPUT(ELF_NOTE_OPENBSD_VERSION);
+
+	return sh->size;
+}
+
+void
+addbuildinfo(char *val)
+{
+	char *ov;
+	int i, b, j;
+
+	if(val[0] != '0' || val[1] != 'x') {
+		fprint(2, "%s: -B argument must start with 0x: %s\n", argv0, val);
+		exits("usage");
+	}
+	ov = val;
+	val += 2;
+	i = 0;
+	while(*val != '\0') {
+		if(val[1] == '\0') {
+			fprint(2, "%s: -B argument must have even number of digits: %s\n", argv0, ov);
+			exits("usage");
+		}
+		b = 0;
+		for(j = 0; j < 2; j++, val++) {
+			b *= 16;
+		  	if(*val >= '0' && *val <= '9')
+				b += *val - '0';
+			else if(*val >= 'a' && *val <= 'f')
+				b += *val - 'a' + 10;
+			else if(*val >= 'A' && *val <= 'F')
+				b += *val - 'A' + 10;
+			else {
+				fprint(2, "%s: -B argument contains invalid hex digit %c: %s\n", argv0, *val, ov);
+				exits("usage");
+			}
+		}
+		if(i >= nelem(buildinfo)) {
+			fprint(2, "%s: -B option too long (max %d digits): %s\n", argv0, (int)nelem(buildinfo), ov);
+			exits("usage");
+		}
+		buildinfo[i++] = b;
+	}
+	buildinfolen = i;
+}
+
+// Build info note
+#define ELF_NOTE_BUILDINFO_NAMESZ	4
+#define ELF_NOTE_BUILDINFO_TAG		3
+#define ELF_NOTE_BUILDINFO_NAME		"GNU\0"
+
+int
+elfbuildinfo(ElfShdr *sh, uint64 startva, uint64 resoff)
+{
+	int n;
+
+	n = ELF_NOTE_BUILDINFO_NAMESZ + rnd(buildinfolen, 4);
+	return elfnote(sh, startva, resoff, n);
+}
+
+int
+elfwritebuildinfo(void)
+{
+	ElfShdr *sh;
+
+	sh = elfwritenotehdr(".note.gnu.build-id", ELF_NOTE_BUILDINFO_NAMESZ, buildinfolen, ELF_NOTE_BUILDINFO_TAG);
+	if(sh == nil)
+		return 0;
+
+	cwrite(ELF_NOTE_BUILDINFO_NAME, ELF_NOTE_BUILDINFO_NAMESZ);
+	cwrite(buildinfo, buildinfolen);
+	cwrite("\0\0\0", rnd(buildinfolen, 4) - buildinfolen);
+
+	return sh->size;
+}
+
+extern int nelfsym;
+int elfverneed;
+
+typedef struct Elfaux Elfaux;
+typedef struct Elflib Elflib;
+
+struct Elflib
+{
+	Elflib *next;
+	Elfaux *aux;
+	char *file;
+};
+
+struct Elfaux
+{
+	Elfaux *next;
+	int num;
+	char *vers;
+};
+
+Elfaux*
+addelflib(Elflib **list, char *file, char *vers)
+{
+	Elflib *lib;
+	Elfaux *aux;
+	
+	for(lib=*list; lib; lib=lib->next)
+		if(strcmp(lib->file, file) == 0)
+			goto havelib;
+	lib = mal(sizeof *lib);
+	lib->next = *list;
+	lib->file = file;
+	*list = lib;
+havelib:
+	for(aux=lib->aux; aux; aux=aux->next)
+		if(strcmp(aux->vers, vers) == 0)
+			goto haveaux;
+	aux = mal(sizeof *aux);
+	aux->next = lib->aux;
+	aux->vers = vers;
+	lib->aux = aux;
+haveaux:
+	return aux;
+}
+
+void
+elfdynhash(void)
+{
+	LSym *s, *sy, *dynstr;
+	int i, j, nbucket, b, nfile;
+	uint32 hc, *chain, *buckets;
+	int nsym;
+	char *name;
+	Elfaux **need;
+	Elflib *needlib;
+	Elflib *l;
+	Elfaux *x;
+	
+	if(!iself)
+		return;
+
+	nsym = nelfsym;
+	s = linklookup(ctxt, ".hash", 0);
+	s->type = SELFROSECT;
+	s->reachable = 1;
+
+	i = nsym;
+	nbucket = 1;
+	while(i > 0) {
+		++nbucket;
+		i >>= 1;
+	}
+
+	needlib = nil;
+	need = malloc(nsym * sizeof need[0]);
+	chain = malloc(nsym * sizeof chain[0]);
+	buckets = malloc(nbucket * sizeof buckets[0]);
+	if(need == nil || chain == nil || buckets == 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=ctxt->allsym; sy!=S; sy=sy->allsym) {
+		if (sy->dynid <= 0)
+			continue;
+
+		if(sy->dynimpvers)
+			need[sy->dynid] = addelflib(&needlib, sy->dynimplib, sy->dynimpvers);
+
+		name = sy->extname;
+		hc = elfhash((uchar*)name);
+
+		b = hc % nbucket;
+		chain[sy->dynid] = buckets[b];
+		buckets[b] = sy->dynid;
+	}
+
+	adduint32(ctxt, s, nbucket);
+	adduint32(ctxt, s, nsym);
+	for(i = 0; i<nbucket; i++)
+		adduint32(ctxt, s, buckets[i]);
+	for(i = 0; i<nsym; i++)
+		adduint32(ctxt, s, chain[i]);
+
+	free(chain);
+	free(buckets);
+	
+	// version symbols
+	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(ctxt, s, 1);  // table version
+		j = 0;
+		for(x=l->aux; x; x=x->next)
+			j++;
+		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(ctxt, s, 16+j*16);  // offset from this header to next
+		else
+			adduint32(ctxt, s, 0);
+		
+		for(x=l->aux; x; x=x->next) {
+			x->num = i++;
+			// aux struct
+			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(ctxt, s, 16);  // offset from this aux to next
+			else
+				adduint32(ctxt, s, 0);
+		}
+	}
+
+	// version references
+	s = linklookup(ctxt, ".gnu.version", 0);
+	for(i=0; i<nsym; i++) {
+		if(i == 0)
+			adduint16(ctxt, s, 0); // first entry - no symbol
+		else if(need[i] == nil)
+			adduint16(ctxt, s, 1); // global
+		else
+			adduint16(ctxt, s, need[i]->num);
+	}
+
+	free(need);
+
+	s = linklookup(ctxt, ".dynamic", 0);
+	elfverneed = nfile;
+	if(elfverneed) {
+		elfwritedynentsym(s, DT_VERNEED, linklookup(ctxt, ".gnu.version_r", 0));
+		elfwritedynent(s, DT_VERNEEDNUM, nfile);
+		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);
+}
+
+ElfPhdr*
+elfphload(Segment *seg)
+{
+	ElfPhdr *ph;
+	
+	ph = newElfPhdr();
+	ph->type = PT_LOAD;
+	if(seg->rwx & 4)
+		ph->flags |= PF_R;
+	if(seg->rwx & 2)
+		ph->flags |= PF_W;
+	if(seg->rwx & 1)
+		ph->flags |= PF_X;
+	ph->vaddr = seg->vaddr;
+	ph->paddr = seg->vaddr;
+	ph->memsz = seg->len;
+	ph->off = seg->fileoff;
+	ph->filesz = seg->filelen;
+	ph->align = INITRND;
+	
+	return ph;
+}
+
+ElfShdr*
+elfshname(char *name)
+{
+	int i, off;
+	ElfShdr *sh;
+	
+	for(i=0; i<nelfstr; i++) {
+		if(strcmp(name, elfstr[i].s) == 0) {
+			off = elfstr[i].off;
+			goto found;
+		}
+	}
+	diag("cannot find elf name %s", name);
+	errorexit();
+	return nil;
+
+found:
+	for(i=0; i<hdr.shnum; i++) {
+		sh = shdr[i];
+		if(sh->name == off)
+			return sh;
+	}
+	
+	sh = newElfShdr(off);
+	return sh;
+}
+
+ElfShdr*
+elfshalloc(Section *sect)
+{
+	ElfShdr *sh;
+	
+	sh = elfshname(sect->name);
+	sect->elfsect = sh;
+	return sh;
+}
+
+ElfShdr*
+elfshbits(Section *sect)
+{
+	ElfShdr *sh;
+	
+	sh = elfshalloc(sect);
+	if(sh->type > 0)
+		return sh;
+
+	if(sect->vaddr < sect->seg->vaddr + sect->seg->filelen)
+		sh->type = SHT_PROGBITS;
+	else
+		sh->type = SHT_NOBITS;
+	sh->flags = SHF_ALLOC;
+	if(sect->rwx & 1)
+		sh->flags |= SHF_EXECINSTR;
+	if(sect->rwx & 2)
+		sh->flags |= SHF_WRITE;
+	if(strcmp(sect->name, ".tbss") == 0) {
+		if(strcmp(goos, "android") != 0)
+			sh->flags |= SHF_TLS; // no TLS on android
+		sh->type = SHT_NOBITS;
+	}
+	if(linkmode != LinkExternal)
+		sh->addr = sect->vaddr;
+	sh->addralign = sect->align;
+	sh->size = sect->len;
+	sh->off = sect->seg->fileoff + sect->vaddr - sect->seg->vaddr;
+
+	return sh;
+}
+
+ElfShdr*
+elfshreloc(Section *sect)
+{
+	int typ;
+	ElfShdr *sh;
+	char *prefix;
+	char buf[100];
+	
+	// If main section is SHT_NOBITS, nothing to relocate.
+	// Also nothing to relocate in .shstrtab.
+	if(sect->vaddr >= sect->seg->vaddr + sect->seg->filelen)
+		return nil;
+	if(strcmp(sect->name, ".shstrtab") == 0 || strcmp(sect->name, ".tbss") == 0)
+		return nil;
+
+	if(thechar == '6') {
+		prefix = ".rela";
+		typ = SHT_RELA;
+	} else {
+		prefix = ".rel";
+		typ = SHT_REL;
+	}
+
+	snprint(buf, sizeof buf, "%s%s", prefix, sect->name);
+	sh = elfshname(buf);
+	sh->type = typ;
+	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 = RegSize;
+	return sh;
+}
+
+void
+elfrelocsect(Section *sect, LSym *first)
+{
+	LSym *sym;
+	int32 eaddr;
+	Reloc *r;
+
+	// If main section is SHT_NOBITS, nothing to relocate.
+	// Also nothing to relocate in .shstrtab.
+	if(sect->vaddr >= sect->seg->vaddr + sect->seg->filelen)
+		return;
+	if(strcmp(sect->name, ".shstrtab") == 0)
+		return;
+
+	sect->reloff = cpos();
+	for(sym = first; sym != nil; sym = sym->next) {
+		if(!sym->reachable)
+			continue;
+		if(sym->value >= sect->vaddr)
+			break;
+	}
+	
+	eaddr = sect->vaddr + sect->len;
+	for(; sym != nil; sym = sym->next) {
+		if(!sym->reachable)
+			continue;
+		if(sym->value >= eaddr)
+			break;
+		ctxt->cursym = sym;
+		
+		for(r = sym->r; r < sym->r+sym->nr; r++) {
+			if(r->done)
+				continue;
+			if(r->xsym == nil) {
+				diag("missing xsym in relocation");
+				continue;
+			}
+			if(r->xsym->elfsym == 0)
+				diag("reloc %d to non-elf symbol %s (outer=%s) %d", r->type, r->sym->name, r->xsym->name, r->sym->type);
+			if(elfreloc1(r, sym->value+r->off - sect->vaddr) < 0)
+				diag("unsupported obj reloc %d/%d to %s", r->type, r->siz, r->sym->name);
+		}
+	}
+		
+	sect->rellen = cpos() - sect->reloff;
+}	
+	
+void
+elfemitreloc(void)
+{
+	Section *sect;
+
+	while(cpos()&7)
+		cput(0);
+
+	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)
+		elfrelocsect(sect, datap);	
+	for(sect=segdata.sect; sect!=nil; sect=sect->next)
+		elfrelocsect(sect, datap);	
+}
+
+void
+doelf(void)
+{
+	LSym *s, *shstrtab, *dynstr;
+
+	if(!iself)
+		return;
+
+	/* predefine strings we need for section headers */
+	shstrtab = linklookup(ctxt, ".shstrtab", 0);
+	shstrtab->type = SELFROSECT;
+	shstrtab->reachable = 1;
+
+	addstring(shstrtab, "");
+	addstring(shstrtab, ".text");
+	addstring(shstrtab, ".noptrdata");
+	addstring(shstrtab, ".data");
+	addstring(shstrtab, ".bss");
+	addstring(shstrtab, ".noptrbss");
+	// generate .tbss section (except for OpenBSD where it's not supported)
+	// for dynamic internal linker or external linking, so that various
+	// binutils could correctly calculate PT_TLS size.
+	// see http://golang.org/issue/5200.
+	if(HEADTYPE != Hopenbsd)
+	if(!debug['d'] || linkmode == LinkExternal)
+		addstring(shstrtab, ".tbss");
+	if(HEADTYPE == Hnetbsd)
+		addstring(shstrtab, ".note.netbsd.ident");
+	if(HEADTYPE == Hopenbsd)
+		addstring(shstrtab, ".note.openbsd.ident");
+	if(buildinfolen > 0)
+		addstring(shstrtab, ".note.gnu.build-id");
+	addstring(shstrtab, ".elfdata");
+	addstring(shstrtab, ".rodata");
+	addstring(shstrtab, ".typelink");
+	addstring(shstrtab, ".gosymtab");
+	addstring(shstrtab, ".gopclntab");
+	
+	if(linkmode == LinkExternal) {
+		debug_s = debug['s'];
+		debug['s'] = 0;
+		debug['d'] = 1;
+
+		if(thechar == '6') {
+			addstring(shstrtab, ".rela.text");
+			addstring(shstrtab, ".rela.rodata");
+			addstring(shstrtab, ".rela.typelink");
+			addstring(shstrtab, ".rela.gosymtab");
+			addstring(shstrtab, ".rela.gopclntab");
+			addstring(shstrtab, ".rela.noptrdata");
+			addstring(shstrtab, ".rela.data");
+		} else {
+			addstring(shstrtab, ".rel.text");
+			addstring(shstrtab, ".rel.rodata");
+			addstring(shstrtab, ".rel.typelink");
+			addstring(shstrtab, ".rel.gosymtab");
+			addstring(shstrtab, ".rel.gopclntab");
+			addstring(shstrtab, ".rel.noptrdata");
+			addstring(shstrtab, ".rel.data");
+		}
+		// add a .note.GNU-stack section to mark the stack as non-executable
+		addstring(shstrtab, ".note.GNU-stack");
+	}
+
+	if(flag_shared) {
+		addstring(shstrtab, ".init_array");
+		if(thechar == '6')
+			addstring(shstrtab, ".rela.init_array");
+		else
+			addstring(shstrtab, ".rel.init_array");
+	}
+
+	if(!debug['s']) {
+		addstring(shstrtab, ".symtab");
+		addstring(shstrtab, ".strtab");
+		dwarfaddshstrings(shstrtab);
+	}
+	addstring(shstrtab, ".shstrtab");
+
+	if(!debug['d']) {	/* -d suppresses dynamic loader format */
+		addstring(shstrtab, ".interp");
+		addstring(shstrtab, ".hash");
+		addstring(shstrtab, ".got");
+		addstring(shstrtab, ".got.plt");
+		addstring(shstrtab, ".dynamic");
+		addstring(shstrtab, ".dynsym");
+		addstring(shstrtab, ".dynstr");
+		if(thechar == '6') {
+			addstring(shstrtab, ".rela");
+			addstring(shstrtab, ".rela.plt");
+		} else {
+			addstring(shstrtab, ".rel");
+			addstring(shstrtab, ".rel.plt");
+		}
+		addstring(shstrtab, ".plt");
+		addstring(shstrtab, ".gnu.version");
+		addstring(shstrtab, ".gnu.version_r");
+
+		/* dynamic symbol table - first entry all zeros */
+		s = linklookup(ctxt, ".dynsym", 0);
+		s->type = SELFROSECT;
+		s->reachable = 1;
+		if(thechar == '6')
+			s->size += ELF64SYMSIZE;
+		else
+			s->size += ELF32SYMSIZE;
+
+		/* dynamic string table */
+		s = linklookup(ctxt, ".dynstr", 0);
+		s->type = SELFROSECT;
+		s->reachable = 1;
+		if(s->size == 0)
+			addstring(s, "");
+		dynstr = s;
+
+		/* relocation table */
+		if(thechar == '6')
+			s = linklookup(ctxt, ".rela", 0);
+		else
+			s = linklookup(ctxt, ".rel", 0);
+		s->reachable = 1;
+		s->type = SELFROSECT;
+
+		/* global offset table */
+		s = linklookup(ctxt, ".got", 0);
+		s->reachable = 1;
+		s->type = SELFSECT; // writable
+
+		/* hash */
+		s = linklookup(ctxt, ".hash", 0);
+		s->reachable = 1;
+		s->type = SELFROSECT;
+
+		s = linklookup(ctxt, ".got.plt", 0);
+		s->reachable = 1;
+		s->type = SELFSECT; // writable
+
+		s = linklookup(ctxt, ".plt", 0);
+		s->reachable = 1;
+		s->type = SELFRXSECT;
+		
+		elfsetupplt();
+		
+		if(thechar == '6')
+			s = linklookup(ctxt, ".rela.plt", 0);
+		else
+			s = linklookup(ctxt, ".rel.plt", 0);
+		s->reachable = 1;
+		s->type = SELFROSECT;
+		
+		s = linklookup(ctxt, ".gnu.version", 0);
+		s->reachable = 1;
+		s->type = SELFROSECT;
+		
+		s = linklookup(ctxt, ".gnu.version_r", 0);
+		s->reachable = 1;
+		s->type = SELFROSECT;
+
+		/* define dynamic elf table */
+		s = linklookup(ctxt, ".dynamic", 0);
+		s->reachable = 1;
+		s->type = SELFSECT; // writable
+
+		/*
+		 * .dynamic table
+		 */
+		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, linklookup(ctxt, ".dynstr", 0));
+		elfwritedynentsymsize(s, DT_STRSZ, linklookup(ctxt, ".dynstr", 0));
+		if(thechar == '6') {
+			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, 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, linklookup(ctxt, ".got.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.
+	}
+}
+
+void
+shsym(ElfShdr *sh, LSym *s)
+{
+	vlong addr;
+	addr = symaddr(s);
+	if(sh->flags&SHF_ALLOC)
+		sh->addr = addr;
+	sh->off = datoff(addr);
+	sh->size = s->size;
+}
+
+void
+phsh(ElfPhdr *ph, ElfShdr *sh)
+{
+	ph->vaddr = sh->addr;
+	ph->paddr = ph->vaddr;
+	ph->off = sh->off;
+	ph->filesz = sh->size;
+	ph->memsz = sh->size;
+	ph->align = sh->addralign;
+}
+
+void
+asmbelfsetup(void)
+{
+	Section *sect;
+
+	/* This null SHdr must appear before all others */
+	elfshname("");
+	
+	for(sect=segtext.sect; sect!=nil; sect=sect->next)
+		elfshalloc(sect);
+	for(sect=segrodata.sect; sect!=nil; sect=sect->next)
+		elfshalloc(sect);
+	for(sect=segdata.sect; sect!=nil; sect=sect->next)
+		elfshalloc(sect);
+}
+
+void
+asmbelf(vlong symo)
+{
+	vlong a, o;
+	vlong startva, resoff;
+	ElfEhdr *eh;
+	ElfPhdr *ph, *pph, *pnote;
+	ElfShdr *sh;
+	Section *sect;
+
+	eh = getElfEhdr();
+	switch(thechar) {
+	default:
+		diag("unknown architecture in asmbelf");
+		errorexit();
+	case '5':
+		eh->machine = EM_ARM;
+		break;
+	case '6':
+		eh->machine = EM_X86_64;
+		break;
+	case '8':
+		eh->machine = EM_386;
+		break;
+	}
+
+	startva = INITTEXT - HEADR;
+	resoff = ELFRESERVE;
+	
+	pph = nil;
+	if(linkmode == LinkExternal) {
+		/* skip program headers */
+		eh->phoff = 0;
+		eh->phentsize = 0;
+		goto elfobj;
+	}
+
+	/* program header info */
+	pph = newElfPhdr();
+	pph->type = PT_PHDR;
+	pph->flags = PF_R;
+	pph->off = eh->ehsize;
+	pph->vaddr = INITTEXT - HEADR + pph->off;
+	pph->paddr = INITTEXT - HEADR + pph->off;
+	pph->align = INITRND;
+
+	/*
+	 * 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.
+	 */
+	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 */
+		sh = elfshname(".interp");
+		sh->type = SHT_PROGBITS;
+		sh->flags = SHF_ALLOC;
+		sh->addralign = 1;
+		if(interpreter == nil) {
+			switch(HEADTYPE) {
+			case Hlinux:
+				interpreter = linuxdynld;
+				break;
+			case Hfreebsd:
+				interpreter = freebsddynld;
+				break;
+			case Hnetbsd:
+				interpreter = netbsddynld;
+				break;
+			case Hopenbsd:
+				interpreter = openbsddynld;
+				break;
+			case Hdragonfly:
+				interpreter = dragonflydynld;
+				break;
+			case Hsolaris:
+				interpreter = solarisdynld;
+				break;
+			}
+		}
+		resoff -= elfinterp(sh, startva, resoff, interpreter);
+
+		ph = newElfPhdr();
+		ph->type = PT_INTERP;
+		ph->flags = PF_R;
+		phsh(ph, sh);
+	}
+
+	pnote = nil;
+	if(HEADTYPE == Hnetbsd || HEADTYPE == Hopenbsd) {
+		sh = nil;
+		switch(HEADTYPE) {
+		case Hnetbsd:
+			sh = elfshname(".note.netbsd.ident");
+			resoff -= elfnetbsdsig(sh, startva, resoff);
+			break;
+		case Hopenbsd:
+			sh = elfshname(".note.openbsd.ident");
+			resoff -= elfopenbsdsig(sh, startva, resoff);
+			break;
+		}
+
+		pnote = newElfPhdr();
+		pnote->type = PT_NOTE;
+		pnote->flags = PF_R;
+		phsh(pnote, sh);
+	}
+
+	if(buildinfolen > 0) {
+		sh = elfshname(".note.gnu.build-id");
+		resoff -= elfbuildinfo(sh, startva, resoff);
+
+		if(pnote == nil) {
+			pnote = newElfPhdr();
+			pnote->type = PT_NOTE;
+			pnote->flags = PF_R;
+		}
+		phsh(pnote, sh);
+	}
+
+	// Additions to the reserved area must be above this line.
+	USED(resoff);
+
+	elfphload(&segtext);
+	if(segrodata.sect != nil)
+		elfphload(&segrodata);
+	elfphload(&segdata);
+
+	/* Dynamic linking sections */
+	if(!debug['d']) {	/* -d suppresses dynamic loader format */
+		sh = elfshname(".dynsym");
+		sh->type = SHT_DYNSYM;
+		sh->flags = SHF_ALLOC;
+		if(elf64)
+			sh->entsize = ELF64SYMSIZE;
+		else
+			sh->entsize = ELF32SYMSIZE;
+		sh->addralign = RegSize;
+		sh->link = elfshname(".dynstr")->shnum;
+		// sh->info = index of first non-local symbol (number of local symbols)
+		shsym(sh, linklookup(ctxt, ".dynsym", 0));
+
+		sh = elfshname(".dynstr");
+		sh->type = SHT_STRTAB;
+		sh->flags = SHF_ALLOC;
+		sh->addralign = 1;
+		shsym(sh, linklookup(ctxt, ".dynstr", 0));
+
+		if(elfverneed) {
+			sh = elfshname(".gnu.version");
+			sh->type = SHT_GNU_VERSYM;
+			sh->flags = SHF_ALLOC;
+			sh->addralign = 2;
+			sh->link = elfshname(".dynsym")->shnum;
+			sh->entsize = 2;
+			shsym(sh, linklookup(ctxt, ".gnu.version", 0));
+			
+			sh = elfshname(".gnu.version_r");
+			sh->type = SHT_GNU_VERNEED;
+			sh->flags = SHF_ALLOC;
+			sh->addralign = RegSize;
+			sh->info = elfverneed;
+			sh->link = elfshname(".dynstr")->shnum;
+			shsym(sh, linklookup(ctxt, ".gnu.version_r", 0));
+		}
+
+		switch(eh->machine) {
+		case EM_X86_64:
+			sh = elfshname(".rela.plt");
+			sh->type = SHT_RELA;
+			sh->flags = SHF_ALLOC;
+			sh->entsize = ELF64RELASIZE;
+			sh->addralign = RegSize;
+			sh->link = elfshname(".dynsym")->shnum;
+			sh->info = elfshname(".plt")->shnum;
+			shsym(sh, linklookup(ctxt, ".rela.plt", 0));
+
+			sh = elfshname(".rela");
+			sh->type = SHT_RELA;
+			sh->flags = SHF_ALLOC;
+			sh->entsize = ELF64RELASIZE;
+			sh->addralign = 8;
+			sh->link = elfshname(".dynsym")->shnum;
+			shsym(sh, linklookup(ctxt, ".rela", 0));
+			break;
+		
+		default:
+			sh = elfshname(".rel.plt");
+			sh->type = SHT_REL;
+			sh->flags = SHF_ALLOC;
+			sh->entsize = ELF32RELSIZE;
+			sh->link = elfshname(".dynsym")->shnum;
+			shsym(sh, linklookup(ctxt, ".rel.plt", 0));
+
+			sh = elfshname(".rel");
+			sh->type = SHT_REL;
+			sh->flags = SHF_ALLOC;
+			sh->entsize = ELF32RELSIZE;
+			sh->addralign = 4;
+			sh->link = elfshname(".dynsym")->shnum;
+			shsym(sh, linklookup(ctxt, ".rel", 0));
+			break;
+		}
+
+		sh = elfshname(".plt");
+		sh->type = SHT_PROGBITS;
+		sh->flags = SHF_ALLOC+SHF_EXECINSTR;
+		if(eh->machine == EM_X86_64)
+			sh->entsize = 16;
+		else
+			sh->entsize = 4;
+		sh->addralign = 4;
+		shsym(sh, linklookup(ctxt, ".plt", 0));
+
+		sh = elfshname(".got");
+		sh->type = SHT_PROGBITS;
+		sh->flags = SHF_ALLOC+SHF_WRITE;
+		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 = 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 = RegSize;
+		sh->link = elfshname(".dynsym")->shnum;
+		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*RegSize;
+		sh->addralign = RegSize;
+		sh->link = elfshname(".dynstr")->shnum;
+		shsym(sh, linklookup(ctxt, ".dynamic", 0));
+		ph = newElfPhdr();
+		ph->type = PT_DYNAMIC;
+		ph->flags = PF_R + PF_W;
+		phsh(ph, sh);
+		
+		/*
+		 * Thread-local storage segment (really just size).
+		 */
+		// Do not emit PT_TLS for OpenBSD since ld.so(1) does
+		// not currently support it. This is handled
+		// appropriately in runtime/cgo.
+		if(ctxt->tlsoffset != 0 && HEADTYPE != Hopenbsd) {
+			ph = newElfPhdr();
+			ph->type = PT_TLS;
+			ph->flags = PF_R;
+			ph->memsz = -ctxt->tlsoffset;
+			ph->align = RegSize;
+		}
+	}
+
+	if(HEADTYPE == Hlinux) {
+		ph = newElfPhdr();
+		ph->type = PT_GNU_STACK;
+		ph->flags = PF_W+PF_R;
+		ph->align = RegSize;
+		
+		ph = newElfPhdr();
+		ph->type = PT_PAX_FLAGS;
+		ph->flags = 0x2a00; // mprotect, randexec, emutramp disabled
+		ph->align = RegSize;
+	}
+
+elfobj:
+	sh = elfshname(".shstrtab");
+	sh->type = SHT_STRTAB;
+	sh->addralign = 1;
+	shsym(sh, linklookup(ctxt, ".shstrtab", 0));
+	eh->shstrndx = sh->shnum;
+
+	// put these sections early in the list
+	if(!debug['s']) {
+		elfshname(".symtab");
+		elfshname(".strtab");
+	}
+
+	for(sect=segtext.sect; sect!=nil; sect=sect->next)
+		elfshbits(sect);
+	for(sect=segrodata.sect; sect!=nil; sect=sect->next)
+		elfshbits(sect);
+	for(sect=segdata.sect; sect!=nil; sect=sect->next)
+		elfshbits(sect);
+
+	if(linkmode == LinkExternal) {
+		for(sect=segtext.sect; sect!=nil; sect=sect->next)
+			elfshreloc(sect);
+		for(sect=segrodata.sect; sect!=nil; sect=sect->next)
+			elfshreloc(sect);
+		for(sect=segdata.sect; sect!=nil; sect=sect->next)
+			elfshreloc(sect);
+		// add a .note.GNU-stack section to mark the stack as non-executable
+		sh = elfshname(".note.GNU-stack");
+		sh->type = SHT_PROGBITS;
+		sh->addralign = 1;
+		sh->flags = 0;
+	}
+
+	// generate .tbss section for dynamic internal linking (except for OpenBSD)
+	// external linking generates .tbss in data.c
+	if(linkmode == LinkInternal && !debug['d'] && HEADTYPE != Hopenbsd) {
+		sh = elfshname(".tbss");
+		sh->type = SHT_NOBITS;
+		sh->addralign = RegSize;
+		sh->size = -ctxt->tlsoffset;
+		sh->flags = SHF_ALLOC | SHF_TLS | SHF_WRITE;
+	}
+
+	if(!debug['s']) {
+		sh = elfshname(".symtab");
+		sh->type = SHT_SYMTAB;
+		sh->off = symo;
+		sh->size = symsize;
+		sh->addralign = RegSize;
+		sh->entsize = 8+2*RegSize;
+		sh->link = elfshname(".strtab")->shnum;
+		sh->info = elfglobalsymndx;
+
+		sh = elfshname(".strtab");
+		sh->type = SHT_STRTAB;
+		sh->off = symo+symsize;
+		sh->size = elfstrsize;
+		sh->addralign = 1;
+
+		dwarfaddelfheaders();
+	}
+
+	/* Main header */
+	eh->ident[EI_MAG0] = '\177';
+	eh->ident[EI_MAG1] = 'E';
+	eh->ident[EI_MAG2] = 'L';
+	eh->ident[EI_MAG3] = 'F';
+	if(HEADTYPE == Hfreebsd)
+		eh->ident[EI_OSABI] = ELFOSABI_FREEBSD;
+	else if(HEADTYPE == Hnetbsd)
+		eh->ident[EI_OSABI] = ELFOSABI_NETBSD;
+	else if(HEADTYPE == Hopenbsd)
+		eh->ident[EI_OSABI] = ELFOSABI_OPENBSD;
+	else if(HEADTYPE == Hdragonfly)
+		eh->ident[EI_OSABI] = ELFOSABI_NONE;
+	if(elf64)
+		eh->ident[EI_CLASS] = ELFCLASS64;
+	else
+		eh->ident[EI_CLASS] = ELFCLASS32;
+	eh->ident[EI_DATA] = ELFDATA2LSB;
+	eh->ident[EI_VERSION] = EV_CURRENT;
+
+	if(linkmode == LinkExternal)
+		eh->type = ET_REL;
+	else
+		eh->type = ET_EXEC;
+
+	if(linkmode != LinkExternal)
+		eh->entry = entryvalue();
+
+	eh->version = EV_CURRENT;
+
+	if(pph != nil) {
+		pph->filesz = eh->phnum * eh->phentsize;
+		pph->memsz = pph->filesz;
+	}
+
+	cseek(0);
+	a = 0;
+	a += elfwritehdr();
+	a += elfwritephdrs();
+	a += elfwriteshdrs();
+	if(!debug['d'])
+		a += elfwriteinterp();
+	if(linkmode != LinkExternal) {
+		if(HEADTYPE == Hnetbsd)
+			a += elfwritenetbsdsig();
+		if(HEADTYPE == Hopenbsd)
+			a += elfwriteopenbsdsig();
+		if(buildinfolen > 0)
+			a += elfwritebuildinfo();
+	}
+	if(a > ELFRESERVE)	
+		diag("ELFRESERVE too small: %lld > %d", a, ELFRESERVE);
+}
diff --git a/src/cmd/ld/elf.h b/src/cmd/ld/elf.h
new file mode 100644
index 0000000..e84d996
--- /dev/null
+++ b/src/cmd/ld/elf.h
@@ -0,0 +1,1027 @@
+/*
+ * Derived from:
+ * $FreeBSD: src/sys/sys/elf32.h,v 1.8.14.1 2005/12/30 22:13:58 marcel Exp $
+ * $FreeBSD: src/sys/sys/elf64.h,v 1.10.14.1 2005/12/30 22:13:58 marcel Exp $
+ * $FreeBSD: src/sys/sys/elf_common.h,v 1.15.8.1 2005/12/30 22:13:58 marcel Exp $
+ * $FreeBSD: src/sys/alpha/include/elf.h,v 1.14 2003/09/25 01:10:22 peter Exp $
+ * $FreeBSD: src/sys/amd64/include/elf.h,v 1.18 2004/08/03 08:21:48 dfr Exp $
+ * $FreeBSD: src/sys/arm/include/elf.h,v 1.5.2.1 2006/06/30 21:42:52 cognet Exp $
+ * $FreeBSD: src/sys/i386/include/elf.h,v 1.16 2004/08/02 19:12:17 dfr Exp $
+ * $FreeBSD: src/sys/powerpc/include/elf.h,v 1.7 2004/11/02 09:47:01 ssouhlal Exp $
+ * $FreeBSD: src/sys/sparc64/include/elf.h,v 1.12 2003/09/25 01:10:26 peter Exp $
+ *
+ * Copyright (c) 1996-1998 John D. Polstra.  All rights reserved.
+ * Copyright (c) 2001 David E. O'Brien
+ * Portions Copyright 2009 The Go Authors.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+/*
+ * ELF definitions that are independent of architecture or word size.
+ */
+
+/*
+ * Note header.  The ".note" section contains an array of notes.  Each
+ * begins with this header, aligned to a word boundary.  Immediately
+ * following the note header is n_namesz bytes of name, padded to the
+ * next word boundary.  Then comes n_descsz bytes of descriptor, again
+ * padded to a word boundary.  The values of n_namesz and n_descsz do
+ * not include the padding.
+ */
+
+typedef struct {
+	uint32	n_namesz;	/* Length of name. */
+	uint32	n_descsz;	/* Length of descriptor. */
+	uint32	n_type;		/* Type of this note. */
+} Elf_Note;
+
+/* Indexes into the e_ident array.  Keep synced with
+   http://www.sco.com/developer/gabi/ch4.eheader.html */
+#define EI_MAG0		0	/* Magic number, byte 0. */
+#define EI_MAG1		1	/* Magic number, byte 1. */
+#define EI_MAG2		2	/* Magic number, byte 2. */
+#define EI_MAG3		3	/* Magic number, byte 3. */
+#define EI_CLASS	4	/* Class of machine. */
+#define EI_DATA		5	/* Data format. */
+#define EI_VERSION	6	/* ELF format version. */
+#define EI_OSABI	7	/* Operating system / ABI identification */
+#define EI_ABIVERSION	8	/* ABI version */
+#define OLD_EI_BRAND	8	/* Start of architecture identification. */
+#define EI_PAD		9	/* Start of padding (per SVR4 ABI). */
+#define EI_NIDENT	16	/* Size of e_ident array. */
+
+/* Values for the magic number bytes. */
+#define ELFMAG0		0x7f
+#define ELFMAG1		'E'
+#define ELFMAG2		'L'
+#define ELFMAG3		'F'
+#define ELFMAG		"\177ELF"	/* magic string */
+#define SELFMAG		4		/* magic string size */
+
+/* Values for e_ident[EI_VERSION] and e_version. */
+#define EV_NONE		0
+#define EV_CURRENT	1
+
+/* Values for e_ident[EI_CLASS]. */
+#define ELFCLASSNONE	0	/* Unknown class. */
+#define ELFCLASS32	1	/* 32-bit architecture. */
+#define ELFCLASS64	2	/* 64-bit architecture. */
+
+/* Values for e_ident[EI_DATA]. */
+#define ELFDATANONE	0	/* Unknown data format. */
+#define ELFDATA2LSB	1	/* 2's complement little-endian. */
+#define ELFDATA2MSB	2	/* 2's complement big-endian. */
+
+/* Values for e_ident[EI_OSABI]. */
+#define ELFOSABI_NONE		0	/* UNIX System V ABI */
+#define ELFOSABI_HPUX		1	/* HP-UX operating system */
+#define ELFOSABI_NETBSD		2	/* NetBSD */
+#define ELFOSABI_LINUX		3	/* GNU/Linux */
+#define ELFOSABI_HURD		4	/* GNU/Hurd */
+#define ELFOSABI_86OPEN		5	/* 86Open common IA32 ABI */
+#define ELFOSABI_SOLARIS	6	/* Solaris */
+#define ELFOSABI_AIX		7	/* AIX */
+#define ELFOSABI_IRIX		8	/* IRIX */
+#define ELFOSABI_FREEBSD	9	/* FreeBSD */
+#define ELFOSABI_TRU64		10	/* TRU64 UNIX */
+#define ELFOSABI_MODESTO	11	/* Novell Modesto */
+#define ELFOSABI_OPENBSD	12	/* OpenBSD */
+#define ELFOSABI_OPENVMS	13	/* Open VMS */
+#define ELFOSABI_NSK		14	/* HP Non-Stop Kernel */
+#define ELFOSABI_ARM		97	/* ARM */
+#define ELFOSABI_STANDALONE	255	/* Standalone (embedded) application */
+
+#define ELFOSABI_SYSV		ELFOSABI_NONE	/* symbol used in old spec */
+#define ELFOSABI_MONTEREY	ELFOSABI_AIX	/* Monterey */
+
+/* e_ident */
+#define IS_ELF(ehdr)	((ehdr).e_ident[EI_MAG0] == ELFMAG0 && \
+			 (ehdr).e_ident[EI_MAG1] == ELFMAG1 && \
+			 (ehdr).e_ident[EI_MAG2] == ELFMAG2 && \
+			 (ehdr).e_ident[EI_MAG3] == ELFMAG3)
+
+/* Values for e_type. */
+#define ET_NONE		0	/* Unknown type. */
+#define ET_REL		1	/* Relocatable. */
+#define ET_EXEC		2	/* Executable. */
+#define ET_DYN		3	/* Shared object. */
+#define ET_CORE		4	/* Core file. */
+#define ET_LOOS		0xfe00	/* First operating system specific. */
+#define ET_HIOS		0xfeff	/* Last operating system-specific. */
+#define ET_LOPROC	0xff00	/* First processor-specific. */
+#define ET_HIPROC	0xffff	/* Last processor-specific. */
+
+/* Values for e_machine. */
+#define EM_NONE		0	/* Unknown machine. */
+#define EM_M32		1	/* AT&T WE32100. */
+#define EM_SPARC	2	/* Sun SPARC. */
+#define EM_386		3	/* Intel i386. */
+#define EM_68K		4	/* Motorola 68000. */
+#define EM_88K		5	/* Motorola 88000. */
+#define EM_860		7	/* Intel i860. */
+#define EM_MIPS		8	/* MIPS R3000 Big-Endian only. */
+#define EM_S370		9	/* IBM System/370. */
+#define EM_MIPS_RS3_LE	10	/* MIPS R3000 Little-Endian. */
+#define EM_PARISC	15	/* HP PA-RISC. */
+#define EM_VPP500	17	/* Fujitsu VPP500. */
+#define EM_SPARC32PLUS	18	/* SPARC v8plus. */
+#define EM_960		19	/* Intel 80960. */
+#define EM_PPC		20	/* PowerPC 32-bit. */
+#define EM_PPC64	21	/* PowerPC 64-bit. */
+#define EM_S390		22	/* IBM System/390. */
+#define EM_V800		36	/* NEC V800. */
+#define EM_FR20		37	/* Fujitsu FR20. */
+#define EM_RH32		38	/* TRW RH-32. */
+#define EM_RCE		39	/* Motorola RCE. */
+#define EM_ARM		40	/* ARM. */
+#define EM_SH		42	/* Hitachi SH. */
+#define EM_SPARCV9	43	/* SPARC v9 64-bit. */
+#define EM_TRICORE	44	/* Siemens TriCore embedded processor. */
+#define EM_ARC		45	/* Argonaut RISC Core. */
+#define EM_H8_300	46	/* Hitachi H8/300. */
+#define EM_H8_300H	47	/* Hitachi H8/300H. */
+#define EM_H8S		48	/* Hitachi H8S. */
+#define EM_H8_500	49	/* Hitachi H8/500. */
+#define EM_IA_64	50	/* Intel IA-64 Processor. */
+#define EM_MIPS_X	51	/* Stanford MIPS-X. */
+#define EM_COLDFIRE	52	/* Motorola ColdFire. */
+#define EM_68HC12	53	/* Motorola M68HC12. */
+#define EM_MMA		54	/* Fujitsu MMA. */
+#define EM_PCP		55	/* Siemens PCP. */
+#define EM_NCPU		56	/* Sony nCPU. */
+#define EM_NDR1		57	/* Denso NDR1 microprocessor. */
+#define EM_STARCORE	58	/* Motorola Star*Core processor. */
+#define EM_ME16		59	/* Toyota ME16 processor. */
+#define EM_ST100	60	/* STMicroelectronics ST100 processor. */
+#define EM_TINYJ	61	/* Advanced Logic Corp. TinyJ processor. */
+#define EM_X86_64	62	/* Advanced Micro Devices x86-64 */
+
+/* Non-standard or deprecated. */
+#define EM_486		6	/* Intel i486. */
+#define EM_MIPS_RS4_BE	10	/* MIPS R4000 Big-Endian */
+#define EM_ALPHA_STD	41	/* Digital Alpha (standard value). */
+#define EM_ALPHA	0x9026	/* Alpha (written in the absence of an ABI) */
+
+/* Special section indexes. */
+#define SHN_UNDEF	     0		/* Undefined, missing, irrelevant. */
+#define SHN_LORESERVE	0xff00		/* First of reserved range. */
+#define SHN_LOPROC	0xff00		/* First processor-specific. */
+#define SHN_HIPROC	0xff1f		/* Last processor-specific. */
+#define SHN_LOOS	0xff20		/* First operating system-specific. */
+#define SHN_HIOS	0xff3f		/* Last operating system-specific. */
+#define SHN_ABS		0xfff1		/* Absolute values. */
+#define SHN_COMMON	0xfff2		/* Common data. */
+#define SHN_XINDEX	0xffff		/* Escape -- index stored elsewhere. */
+#define SHN_HIRESERVE	0xffff		/* Last of reserved range. */
+
+/* sh_type */
+#define SHT_NULL		0	/* inactive */
+#define SHT_PROGBITS		1	/* program defined information */
+#define SHT_SYMTAB		2	/* symbol table section */
+#define SHT_STRTAB		3	/* string table section */
+#define SHT_RELA		4	/* relocation section with addends */
+#define SHT_HASH		5	/* symbol hash table section */
+#define SHT_DYNAMIC		6	/* dynamic section */
+#define SHT_NOTE		7	/* note section */
+#define SHT_NOBITS		8	/* no space section */
+#define SHT_REL			9	/* relocation section - no addends */
+#define SHT_SHLIB		10	/* reserved - purpose unknown */
+#define SHT_DYNSYM		11	/* dynamic symbol table section */
+#define SHT_INIT_ARRAY		14	/* Initialization function pointers. */
+#define SHT_FINI_ARRAY		15	/* Termination function pointers. */
+#define SHT_PREINIT_ARRAY	16	/* Pre-initialization function ptrs. */
+#define SHT_GROUP		17	/* Section group. */
+#define SHT_SYMTAB_SHNDX	18	/* Section indexes (see SHN_XINDEX). */
+#define SHT_LOOS	0x60000000	/* First of OS specific semantics */
+#define SHT_HIOS	0x6fffffff	/* Last of OS specific semantics */
+#define SHT_GNU_VERDEF	0x6ffffffd
+#define SHT_GNU_VERNEED	0x6ffffffe
+#define SHT_GNU_VERSYM	0x6fffffff
+#define SHT_LOPROC	0x70000000	/* reserved range for processor */
+#define SHT_HIPROC	0x7fffffff	/* specific section header types */
+#define SHT_LOUSER	0x80000000	/* reserved range for application */
+#define SHT_HIUSER	0xffffffff	/* specific indexes */
+
+/* Flags for sh_flags. */
+#define SHF_WRITE		0x1	/* Section contains writable data. */
+#define SHF_ALLOC		0x2	/* Section occupies memory. */
+#define SHF_EXECINSTR		0x4	/* Section contains instructions. */
+#define SHF_MERGE		0x10	/* Section may be merged. */
+#define SHF_STRINGS		0x20	/* Section contains strings. */
+#define SHF_INFO_LINK		0x40	/* sh_info holds section index. */
+#define SHF_LINK_ORDER		0x80	/* Special ordering requirements. */
+#define SHF_OS_NONCONFORMING	0x100	/* OS-specific processing required. */
+#define SHF_GROUP		0x200	/* Member of section group. */
+#define SHF_TLS			0x400	/* Section contains TLS data. */
+#define SHF_MASKOS	0x0ff00000	/* OS-specific semantics. */
+#define SHF_MASKPROC	0xf0000000	/* Processor-specific semantics. */
+
+/* Values for p_type. */
+#define PT_NULL		0	/* Unused entry. */
+#define PT_LOAD		1	/* Loadable segment. */
+#define PT_DYNAMIC	2	/* Dynamic linking information segment. */
+#define PT_INTERP	3	/* Pathname of interpreter. */
+#define PT_NOTE		4	/* Auxiliary information. */
+#define PT_SHLIB	5	/* Reserved (not used). */
+#define PT_PHDR		6	/* Location of program header itself. */
+#define PT_TLS		7	/* Thread local storage segment */
+#define PT_LOOS		0x60000000	/* First OS-specific. */
+#define PT_HIOS		0x6fffffff	/* Last OS-specific. */
+#define PT_LOPROC	0x70000000	/* First processor-specific type. */
+#define PT_HIPROC	0x7fffffff	/* Last processor-specific type. */
+#define PT_GNU_STACK	0x6474e551
+#define PT_PAX_FLAGS	0x65041580
+
+/* Values for p_flags. */
+#define PF_X		0x1		/* Executable. */
+#define PF_W		0x2		/* Writable. */
+#define PF_R		0x4		/* Readable. */
+#define PF_MASKOS	0x0ff00000	/* Operating system-specific. */
+#define PF_MASKPROC	0xf0000000	/* Processor-specific. */
+
+/* Values for d_tag. */
+#define DT_NULL		0	/* Terminating entry. */
+/* String table offset of a needed shared library. */
+#define DT_NEEDED	1
+#define DT_PLTRELSZ	2	/* Total size in bytes of PLT relocations. */
+#define DT_PLTGOT	3	/* Processor-dependent address. */
+#define DT_HASH		4	/* Address of symbol hash table. */
+#define DT_STRTAB	5	/* Address of string table. */
+#define DT_SYMTAB	6	/* Address of symbol table. */
+#define DT_RELA		7	/* Address of ElfNN_Rela relocations. */
+#define DT_RELASZ	8	/* Total size of ElfNN_Rela relocations. */
+#define DT_RELAENT	9	/* Size of each ElfNN_Rela relocation entry. */
+#define DT_STRSZ	10	/* Size of string table. */
+#define DT_SYMENT	11	/* Size of each symbol table entry. */
+#define DT_INIT		12	/* Address of initialization function. */
+#define DT_FINI		13	/* Address of finalization function. */
+/* String table offset of shared object name. */
+#define DT_SONAME	14
+#define DT_RPATH	15	/* String table offset of library path. [sup] */
+#define DT_SYMBOLIC	16	/* Indicates "symbolic" linking. [sup] */
+#define DT_REL		17	/* Address of ElfNN_Rel relocations. */
+#define DT_RELSZ	18	/* Total size of ElfNN_Rel relocations. */
+#define DT_RELENT	19	/* Size of each ElfNN_Rel relocation. */
+#define DT_PLTREL	20	/* Type of relocation used for PLT. */
+#define DT_DEBUG	21	/* Reserved (not used). */
+/* Indicates there may be relocations in non-writable segments. [sup] */
+#define DT_TEXTREL	22
+#define DT_JMPREL	23	/* Address of PLT relocations. */
+#define	DT_BIND_NOW	24	/* [sup] */
+/* Address of the array of pointers to initialization functions */
+#define	DT_INIT_ARRAY	25
+/* Address of the array of pointers to termination functions */
+#define	DT_FINI_ARRAY	26
+/* Size in bytes of the array of initialization functions. */
+#define	DT_INIT_ARRAYSZ	27
+/* Size in bytes of the array of terminationfunctions. */
+#define	DT_FINI_ARRAYSZ	28
+/* String table offset of a null-terminated library search path string. */
+#define	DT_RUNPATH	29
+#define	DT_FLAGS	30	/* Object specific flag values. */
+/*	Values greater than or equal to DT_ENCODING and less than
+	DT_LOOS follow the rules for the interpretation of the d_un
+	union as follows: even == 'd_ptr', even == 'd_val' or none */
+#define	DT_ENCODING	32
+/* Address of the array of pointers to pre-initialization functions. */
+#define	DT_PREINIT_ARRAY 32
+/* Size in bytes of the array of pre-initialization functions. */
+#define	DT_PREINIT_ARRAYSZ 33
+#define	DT_LOOS		0x6000000d	/* First OS-specific */
+#define	DT_HIOS		0x6ffff000	/* Last OS-specific */
+#define	DT_LOPROC	0x70000000	/* First processor-specific type. */
+#define	DT_HIPROC	0x7fffffff	/* Last processor-specific type. */
+
+#define	DT_VERNEED	0x6ffffffe
+#define	DT_VERNEEDNUM	0x6fffffff
+#define	DT_VERSYM	0x6ffffff0
+
+/* Values for DT_FLAGS */
+/*	Indicates that the object being loaded may make reference to
+	the $ORIGIN substitution string */
+#define	DF_ORIGIN	0x0001
+#define	DF_SYMBOLIC	0x0002	/* Indicates "symbolic" linking. */
+/* Indicates there may be relocations in non-writable segments. */
+#define	DF_TEXTREL	0x0004
+/*	Indicates that the dynamic linker should process all
+	relocations for the object containing this entry before
+	transferring control to the program.  */
+#define	DF_BIND_NOW	0x0008
+/*	Indicates that the shared object or executable contains code
+	using a static thread-local storage scheme.  */
+#define	DF_STATIC_TLS	0x0010
+
+/* Values for n_type.  Used in core files. */
+#define NT_PRSTATUS	1	/* Process status. */
+#define NT_FPREGSET	2	/* Floating point registers. */
+#define NT_PRPSINFO	3	/* Process state info. */
+
+/* Symbol Binding - ELFNN_ST_BIND - st_info */
+#define STB_LOCAL	0	/* Local symbol */
+#define STB_GLOBAL	1	/* Global symbol */
+#define STB_WEAK	2	/* like global - lower precedence */
+#define STB_LOOS	10	/* Reserved range for operating system */
+#define STB_HIOS	12	/*   specific semantics. */
+#define STB_LOPROC	13	/* reserved range for processor */
+#define STB_HIPROC	15	/*   specific semantics. */
+
+/* Symbol type - ELFNN_ST_TYPE - st_info */
+#define STT_NOTYPE	0	/* Unspecified type. */
+#define STT_OBJECT	1	/* Data object. */
+#define STT_FUNC	2	/* Function. */
+#define STT_SECTION	3	/* Section. */
+#define STT_FILE	4	/* Source file. */
+#define STT_COMMON	5	/* Uninitialized common block. */
+#define STT_TLS		6	/* TLS object. */
+#define STT_LOOS	10	/* Reserved range for operating system */
+#define STT_HIOS	12	/*   specific semantics. */
+#define STT_LOPROC	13	/* reserved range for processor */
+#define STT_HIPROC	15	/*   specific semantics. */
+
+/* Symbol visibility - ELFNN_ST_VISIBILITY - st_other */
+#define STV_DEFAULT	0x0	/* Default visibility (see binding). */
+#define STV_INTERNAL	0x1	/* Special meaning in relocatable objects. */
+#define STV_HIDDEN	0x2	/* Not visible. */
+#define STV_PROTECTED	0x3	/* Visible but not preemptible. */
+
+/* Special symbol table indexes. */
+#define STN_UNDEF	0	/* Undefined symbol index. */
+
+/*
+ * ELF definitions common to all 32-bit architectures.
+ */
+
+typedef uint32	Elf32_Addr;
+typedef uint16	Elf32_Half;
+typedef uint32	Elf32_Off;
+typedef int32		Elf32_Sword;
+typedef uint32	Elf32_Word;
+
+typedef Elf32_Word	Elf32_Hashelt;
+
+/* Non-standard class-dependent datatype used for abstraction. */
+typedef Elf32_Word	Elf32_Size;
+typedef Elf32_Sword	Elf32_Ssize;
+
+/*
+ * ELF header.
+ */
+
+typedef struct {
+	unsigned char	ident[EI_NIDENT];	/* File identification. */
+	Elf32_Half	type;		/* File type. */
+	Elf32_Half	machine;	/* Machine architecture. */
+	Elf32_Word	version;	/* ELF format version. */
+	Elf32_Addr	entry;	/* Entry point. */
+	Elf32_Off	phoff;	/* Program header file offset. */
+	Elf32_Off	shoff;	/* Section header file offset. */
+	Elf32_Word	flags;	/* Architecture-specific flags. */
+	Elf32_Half	ehsize;	/* Size of ELF header in bytes. */
+	Elf32_Half	phentsize;	/* Size of program header entry. */
+	Elf32_Half	phnum;	/* Number of program header entries. */
+	Elf32_Half	shentsize;	/* Size of section header entry. */
+	Elf32_Half	shnum;	/* Number of section header entries. */
+	Elf32_Half	shstrndx;	/* Section name strings section. */
+} Elf32_Ehdr;
+
+/*
+ * Section header.
+ */
+
+typedef struct {
+	Elf32_Word	name;	/* Section name (index into the
+					   section header string table). */
+	Elf32_Word	type;	/* Section type. */
+	Elf32_Word	flags;	/* Section flags. */
+	Elf32_Addr	vaddr;	/* Address in memory image. */
+	Elf32_Off	off;	/* Offset in file. */
+	Elf32_Word	size;	/* Size in bytes. */
+	Elf32_Word	link;	/* Index of a related section. */
+	Elf32_Word	info;	/* Depends on section type. */
+	Elf32_Word	addralign;	/* Alignment in bytes. */
+	Elf32_Word	entsize;	/* Size of each entry in section. */
+} Elf32_Shdr;
+
+/*
+ * Program header.
+ */
+
+typedef struct {
+	Elf32_Word	type;		/* Entry type. */
+	Elf32_Off	off;	/* File offset of contents. */
+	Elf32_Addr	vaddr;	/* Virtual address in memory image. */
+	Elf32_Addr	paddr;	/* Physical address (not used). */
+	Elf32_Word	filesz;	/* Size of contents in file. */
+	Elf32_Word	memsz;	/* Size of contents in memory. */
+	Elf32_Word	flags;	/* Access permission flags. */
+	Elf32_Word	align;	/* Alignment in memory and file. */
+} Elf32_Phdr;
+
+/*
+ * Dynamic structure.  The ".dynamic" section contains an array of them.
+ */
+
+typedef struct {
+	Elf32_Sword	d_tag;		/* Entry type. */
+	union {
+		Elf32_Word	d_val;	/* Integer value. */
+		Elf32_Addr	d_ptr;	/* Address value. */
+	} d_un;
+} Elf32_Dyn;
+
+/*
+ * Relocation entries.
+ */
+
+/* Relocations that don't need an addend field. */
+typedef struct {
+	Elf32_Addr	off;	/* Location to be relocated. */
+	Elf32_Word	info;		/* Relocation type and symbol index. */
+} Elf32_Rel;
+
+/* Relocations that need an addend field. */
+typedef struct {
+	Elf32_Addr	off;	/* Location to be relocated. */
+	Elf32_Word	info;		/* Relocation type and symbol index. */
+	Elf32_Sword	addend;	/* Addend. */
+} Elf32_Rela;
+
+/* Macros for accessing the fields of r_info. */
+#define ELF32_R_SYM(info)	((info) >> 8)
+#define ELF32_R_TYPE(info)	((unsigned char)(info))
+
+/* Macro for constructing r_info from field values. */
+#define ELF32_R_INFO(sym, type)	(((sym) << 8) + (unsigned char)(type))
+
+/*
+ * Relocation types.
+ */
+
+#define	R_X86_64_NONE	0	/* No relocation. */
+#define	R_X86_64_64	1	/* Add 64 bit symbol value. */
+#define	R_X86_64_PC32	2	/* PC-relative 32 bit signed sym value. */
+#define	R_X86_64_GOT32	3	/* PC-relative 32 bit GOT offset. */
+#define	R_X86_64_PLT32	4	/* PC-relative 32 bit PLT offset. */
+#define	R_X86_64_COPY	5	/* Copy data from shared object. */
+#define	R_X86_64_GLOB_DAT 6	/* Set GOT entry to data address. */
+#define	R_X86_64_JMP_SLOT 7	/* Set GOT entry to code address. */
+#define	R_X86_64_RELATIVE 8	/* Add load address of shared object. */
+#define	R_X86_64_GOTPCREL 9	/* Add 32 bit signed pcrel offset to GOT. */
+#define	R_X86_64_32	10	/* Add 32 bit zero extended symbol value */
+#define	R_X86_64_32S	11	/* Add 32 bit sign extended symbol value */
+#define	R_X86_64_16	12	/* Add 16 bit zero extended symbol value */
+#define	R_X86_64_PC16	13	/* Add 16 bit signed extended pc relative symbol value */
+#define	R_X86_64_8	14	/* Add 8 bit zero extended symbol value */
+#define	R_X86_64_PC8	15	/* Add 8 bit signed extended pc relative symbol value */
+#define	R_X86_64_DTPMOD64 16	/* ID of module containing symbol */
+#define	R_X86_64_DTPOFF64 17	/* Offset in TLS block */
+#define	R_X86_64_TPOFF64 18	/* Offset in static TLS block */
+#define	R_X86_64_TLSGD	19	/* PC relative offset to GD GOT entry */
+#define	R_X86_64_TLSLD	20	/* PC relative offset to LD GOT entry */
+#define	R_X86_64_DTPOFF32 21	/* Offset in TLS block */
+#define	R_X86_64_GOTTPOFF 22	/* PC relative offset to IE GOT entry */
+#define	R_X86_64_TPOFF32 23	/* Offset in static TLS block */
+
+#define	R_X86_64_COUNT	24	/* Count of defined relocation types. */
+
+
+#define	R_ALPHA_NONE		0	/* No reloc */
+#define	R_ALPHA_REFLONG		1	/* Direct 32 bit */
+#define	R_ALPHA_REFQUAD		2	/* Direct 64 bit */
+#define	R_ALPHA_GPREL32		3	/* GP relative 32 bit */
+#define	R_ALPHA_LITERAL		4	/* GP relative 16 bit w/optimization */
+#define	R_ALPHA_LITUSE		5	/* Optimization hint for LITERAL */
+#define	R_ALPHA_GPDISP		6	/* Add displacement to GP */
+#define	R_ALPHA_BRADDR		7	/* PC+4 relative 23 bit shifted */
+#define	R_ALPHA_HINT		8	/* PC+4 relative 16 bit shifted */
+#define	R_ALPHA_SREL16		9	/* PC relative 16 bit */
+#define	R_ALPHA_SREL32		10	/* PC relative 32 bit */
+#define	R_ALPHA_SREL64		11	/* PC relative 64 bit */
+#define	R_ALPHA_OP_PUSH		12	/* OP stack push */
+#define	R_ALPHA_OP_STORE	13	/* OP stack pop and store */
+#define	R_ALPHA_OP_PSUB		14	/* OP stack subtract */
+#define	R_ALPHA_OP_PRSHIFT	15	/* OP stack right shift */
+#define	R_ALPHA_GPVALUE		16
+#define	R_ALPHA_GPRELHIGH	17
+#define	R_ALPHA_GPRELLOW	18
+#define	R_ALPHA_IMMED_GP_16	19
+#define	R_ALPHA_IMMED_GP_HI32	20
+#define	R_ALPHA_IMMED_SCN_HI32	21
+#define	R_ALPHA_IMMED_BR_HI32	22
+#define	R_ALPHA_IMMED_LO32	23
+#define	R_ALPHA_COPY		24	/* Copy symbol at runtime */
+#define	R_ALPHA_GLOB_DAT	25	/* Create GOT entry */
+#define	R_ALPHA_JMP_SLOT	26	/* Create PLT entry */
+#define	R_ALPHA_RELATIVE	27	/* Adjust by program base */
+
+#define	R_ALPHA_COUNT		28
+
+
+#define	R_ARM_NONE		0	/* No relocation. */
+#define	R_ARM_PC24		1
+#define	R_ARM_ABS32		2
+#define	R_ARM_REL32		3
+#define	R_ARM_PC13		4
+#define	R_ARM_ABS16		5
+#define	R_ARM_ABS12		6
+#define	R_ARM_THM_ABS5		7
+#define	R_ARM_ABS8		8
+#define	R_ARM_SBREL32		9
+#define	R_ARM_THM_PC22		10
+#define	R_ARM_THM_PC8		11
+#define	R_ARM_AMP_VCALL9	12
+#define	R_ARM_SWI24		13
+#define	R_ARM_THM_SWI8		14
+#define	R_ARM_XPC25		15
+#define	R_ARM_THM_XPC22		16
+#define	R_ARM_COPY		20	/* Copy data from shared object. */
+#define	R_ARM_GLOB_DAT		21	/* Set GOT entry to data address. */
+#define	R_ARM_JUMP_SLOT		22	/* Set GOT entry to code address. */
+#define	R_ARM_RELATIVE		23	/* Add load address of shared object. */
+#define	R_ARM_GOTOFF		24	/* Add GOT-relative symbol address. */
+#define	R_ARM_GOTPC		25	/* Add PC-relative GOT table address. */
+#define	R_ARM_GOT32		26	/* Add PC-relative GOT offset. */
+#define	R_ARM_PLT32		27	/* Add PC-relative PLT offset. */
+#define	R_ARM_CALL		28
+#define	R_ARM_JUMP24	29
+#define	R_ARM_V4BX		40
+#define	R_ARM_GOT_PREL		96
+#define	R_ARM_GNU_VTENTRY	100
+#define	R_ARM_GNU_VTINHERIT	101
+#define	R_ARM_TLS_IE32		107
+#define	R_ARM_TLS_LE32		108
+#define	R_ARM_RSBREL32		250
+#define	R_ARM_THM_RPC22		251
+#define	R_ARM_RREL32		252
+#define	R_ARM_RABS32		253
+#define	R_ARM_RPC24		254
+#define	R_ARM_RBASE		255
+
+#define	R_ARM_COUNT		38	/* Count of defined relocation types. */
+
+
+#define	R_386_NONE	0	/* No relocation. */
+#define	R_386_32	1	/* Add symbol value. */
+#define	R_386_PC32	2	/* Add PC-relative symbol value. */
+#define	R_386_GOT32	3	/* Add PC-relative GOT offset. */
+#define	R_386_PLT32	4	/* Add PC-relative PLT offset. */
+#define	R_386_COPY	5	/* Copy data from shared object. */
+#define	R_386_GLOB_DAT	6	/* Set GOT entry to data address. */
+#define	R_386_JMP_SLOT	7	/* Set GOT entry to code address. */
+#define	R_386_RELATIVE	8	/* Add load address of shared object. */
+#define	R_386_GOTOFF	9	/* Add GOT-relative symbol address. */
+#define	R_386_GOTPC	10	/* Add PC-relative GOT table address. */
+#define	R_386_TLS_TPOFF	14	/* Negative offset in static TLS block */
+#define	R_386_TLS_IE	15	/* Absolute address of GOT for -ve static TLS */
+#define	R_386_TLS_GOTIE	16	/* GOT entry for negative static TLS block */
+#define	R_386_TLS_LE	17	/* Negative offset relative to static TLS */
+#define	R_386_TLS_GD	18	/* 32 bit offset to GOT (index,off) pair */
+#define	R_386_TLS_LDM	19	/* 32 bit offset to GOT (index,zero) pair */
+#define	R_386_TLS_GD_32	24	/* 32 bit offset to GOT (index,off) pair */
+#define	R_386_TLS_GD_PUSH 25	/* pushl instruction for Sun ABI GD sequence */
+#define	R_386_TLS_GD_CALL 26	/* call instruction for Sun ABI GD sequence */
+#define	R_386_TLS_GD_POP 27	/* popl instruction for Sun ABI GD sequence */
+#define	R_386_TLS_LDM_32 28	/* 32 bit offset to GOT (index,zero) pair */
+#define	R_386_TLS_LDM_PUSH 29	/* pushl instruction for Sun ABI LD sequence */
+#define	R_386_TLS_LDM_CALL 30	/* call instruction for Sun ABI LD sequence */
+#define	R_386_TLS_LDM_POP 31	/* popl instruction for Sun ABI LD sequence */
+#define	R_386_TLS_LDO_32 32	/* 32 bit offset from start of TLS block */
+#define	R_386_TLS_IE_32	33	/* 32 bit offset to GOT static TLS offset entry */
+#define	R_386_TLS_LE_32	34	/* 32 bit offset within static TLS block */
+#define	R_386_TLS_DTPMOD32 35	/* GOT entry containing TLS index */
+#define	R_386_TLS_DTPOFF32 36	/* GOT entry containing TLS offset */
+#define	R_386_TLS_TPOFF32 37	/* GOT entry of -ve static TLS offset */
+
+#define	R_386_COUNT	38	/* Count of defined relocation types. */
+
+#define	R_PPC_NONE		0	/* No relocation. */
+#define	R_PPC_ADDR32		1
+#define	R_PPC_ADDR24		2
+#define	R_PPC_ADDR16		3
+#define	R_PPC_ADDR16_LO		4
+#define	R_PPC_ADDR16_HI		5
+#define	R_PPC_ADDR16_HA		6
+#define	R_PPC_ADDR14		7
+#define	R_PPC_ADDR14_BRTAKEN	8
+#define	R_PPC_ADDR14_BRNTAKEN	9
+#define	R_PPC_REL24		10
+#define	R_PPC_REL14		11
+#define	R_PPC_REL14_BRTAKEN	12
+#define	R_PPC_REL14_BRNTAKEN	13
+#define	R_PPC_GOT16		14
+#define	R_PPC_GOT16_LO		15
+#define	R_PPC_GOT16_HI		16
+#define	R_PPC_GOT16_HA		17
+#define	R_PPC_PLTREL24		18
+#define	R_PPC_COPY		19
+#define	R_PPC_GLOB_DAT		20
+#define	R_PPC_JMP_SLOT		21
+#define	R_PPC_RELATIVE		22
+#define	R_PPC_LOCAL24PC		23
+#define	R_PPC_UADDR32		24
+#define	R_PPC_UADDR16		25
+#define	R_PPC_REL32		26
+#define	R_PPC_PLT32		27
+#define	R_PPC_PLTREL32		28
+#define	R_PPC_PLT16_LO		29
+#define	R_PPC_PLT16_HI		30
+#define	R_PPC_PLT16_HA		31
+#define	R_PPC_SDAREL16		32
+#define	R_PPC_SECTOFF		33
+#define	R_PPC_SECTOFF_LO	34
+#define	R_PPC_SECTOFF_HI	35
+#define	R_PPC_SECTOFF_HA	36
+
+#define	R_PPC_COUNT		37	/* Count of defined relocation types. */
+
+#define R_PPC_TLS		67
+#define R_PPC_DTPMOD32		68
+#define R_PPC_TPREL16		69
+#define R_PPC_TPREL16_LO	70
+#define R_PPC_TPREL16_HI	71
+#define R_PPC_TPREL16_HA	72
+#define R_PPC_TPREL32		73
+#define R_PPC_DTPREL16		74
+#define R_PPC_DTPREL16_LO	75
+#define R_PPC_DTPREL16_HI	76
+#define R_PPC_DTPREL16_HA	77
+#define R_PPC_DTPREL32		78
+#define R_PPC_GOT_TLSGD16	79
+#define R_PPC_GOT_TLSGD16_LO	80
+#define R_PPC_GOT_TLSGD16_HI	81
+#define R_PPC_GOT_TLSGD16_HA	82
+#define R_PPC_GOT_TLSLD16	83
+#define R_PPC_GOT_TLSLD16_LO	84
+#define R_PPC_GOT_TLSLD16_HI	85
+#define R_PPC_GOT_TLSLD16_HA	86
+#define R_PPC_GOT_TPREL16	87
+#define R_PPC_GOT_TPREL16_LO	88
+#define R_PPC_GOT_TPREL16_HI	89
+#define R_PPC_GOT_TPREL16_HA	90
+
+#define	R_PPC_EMB_NADDR32	101
+#define	R_PPC_EMB_NADDR16	102
+#define	R_PPC_EMB_NADDR16_LO	103
+#define	R_PPC_EMB_NADDR16_HI	104
+#define	R_PPC_EMB_NADDR16_HA	105
+#define	R_PPC_EMB_SDAI16	106
+#define	R_PPC_EMB_SDA2I16	107
+#define	R_PPC_EMB_SDA2REL	108
+#define	R_PPC_EMB_SDA21		109
+#define	R_PPC_EMB_MRKREF	110
+#define	R_PPC_EMB_RELSEC16	111
+#define	R_PPC_EMB_RELST_LO	112
+#define	R_PPC_EMB_RELST_HI	113
+#define	R_PPC_EMB_RELST_HA	114
+#define	R_PPC_EMB_BIT_FLD	115
+#define	R_PPC_EMB_RELSDA	116
+
+					/* Count of defined relocation types. */
+#define	R_PPC_EMB_COUNT		(R_PPC_EMB_RELSDA - R_PPC_EMB_NADDR32 + 1)
+
+
+#define R_SPARC_NONE		0
+#define R_SPARC_8		1
+#define R_SPARC_16		2
+#define R_SPARC_32		3
+#define R_SPARC_DISP8		4
+#define R_SPARC_DISP16		5
+#define R_SPARC_DISP32		6
+#define R_SPARC_WDISP30		7
+#define R_SPARC_WDISP22		8
+#define R_SPARC_HI22		9
+#define R_SPARC_22		10
+#define R_SPARC_13		11
+#define R_SPARC_LO10		12
+#define R_SPARC_GOT10		13
+#define R_SPARC_GOT13		14
+#define R_SPARC_GOT22		15
+#define R_SPARC_PC10		16
+#define R_SPARC_PC22		17
+#define R_SPARC_WPLT30		18
+#define R_SPARC_COPY		19
+#define R_SPARC_GLOB_DAT	20
+#define R_SPARC_JMP_SLOT	21
+#define R_SPARC_RELATIVE	22
+#define R_SPARC_UA32		23
+#define R_SPARC_PLT32		24
+#define R_SPARC_HIPLT22		25
+#define R_SPARC_LOPLT10		26
+#define R_SPARC_PCPLT32		27
+#define R_SPARC_PCPLT22		28
+#define R_SPARC_PCPLT10		29
+#define R_SPARC_10		30
+#define R_SPARC_11		31
+#define R_SPARC_64		32
+#define R_SPARC_OLO10		33
+#define R_SPARC_HH22		34
+#define R_SPARC_HM10		35
+#define R_SPARC_LM22		36
+#define R_SPARC_PC_HH22		37
+#define R_SPARC_PC_HM10		38
+#define R_SPARC_PC_LM22		39
+#define R_SPARC_WDISP16		40
+#define R_SPARC_WDISP19		41
+#define R_SPARC_GLOB_JMP	42
+#define R_SPARC_7		43
+#define R_SPARC_5		44
+#define R_SPARC_6		45
+#define	R_SPARC_DISP64		46
+#define	R_SPARC_PLT64		47
+#define	R_SPARC_HIX22		48
+#define	R_SPARC_LOX10		49
+#define	R_SPARC_H44		50
+#define	R_SPARC_M44		51
+#define	R_SPARC_L44		52
+#define	R_SPARC_REGISTER	53
+#define	R_SPARC_UA64		54
+#define	R_SPARC_UA16		55
+
+
+/*
+ * Magic number for the elf trampoline, chosen wisely to be an immediate
+ * value.
+ */
+#define ARM_MAGIC_TRAMP_NUMBER	0x5c000003
+
+
+/*
+ * Symbol table entries.
+ */
+
+typedef struct {
+	Elf32_Word	name;	/* String table index of name. */
+	Elf32_Addr	value;	/* Symbol value. */
+	Elf32_Word	size;	/* Size of associated object. */
+	unsigned char	info;	/* Type and binding information. */
+	unsigned char	other;	/* Reserved (not used). */
+	Elf32_Half	shndx;	/* Section index of symbol. */
+} Elf32_Sym;
+
+/* Macros for accessing the fields of st_info. */
+#define ELF32_ST_BIND(info)		((info) >> 4)
+#define ELF32_ST_TYPE(info)		((info) & 0xf)
+
+/* Macro for constructing st_info from field values. */
+#define ELF32_ST_INFO(bind, type)	(((bind) << 4) + ((type) & 0xf))
+
+/* Macro for accessing the fields of st_other. */
+#define ELF32_ST_VISIBILITY(oth)	((oth) & 0x3)
+
+/*
+ * ELF definitions common to all 64-bit architectures.
+ */
+
+typedef uint64	Elf64_Addr;
+typedef uint16	Elf64_Half;
+typedef uint64	Elf64_Off;
+typedef int32		Elf64_Sword;
+typedef int64		Elf64_Sxword;
+typedef uint32	Elf64_Word;
+typedef uint64	Elf64_Xword;
+
+/*
+ * Types of dynamic symbol hash table bucket and chain elements.
+ *
+ * This is inconsistent among 64 bit architectures, so a machine dependent
+ * typedef is required.
+ */
+
+#ifdef __alpha__
+typedef Elf64_Off	Elf64_Hashelt;
+#else
+typedef Elf64_Word	Elf64_Hashelt;
+#endif
+
+/* Non-standard class-dependent datatype used for abstraction. */
+typedef Elf64_Xword	Elf64_Size;
+typedef Elf64_Sxword	Elf64_Ssize;
+
+/*
+ * ELF header.
+ */
+
+typedef struct {
+	unsigned char	ident[EI_NIDENT];	/* File identification. */
+	Elf64_Half	type;		/* File type. */
+	Elf64_Half	machine;	/* Machine architecture. */
+	Elf64_Word	version;	/* ELF format version. */
+	Elf64_Addr	entry;	/* Entry point. */
+	Elf64_Off	phoff;	/* Program header file offset. */
+	Elf64_Off	shoff;	/* Section header file offset. */
+	Elf64_Word	flags;	/* Architecture-specific flags. */
+	Elf64_Half	ehsize;	/* Size of ELF header in bytes. */
+	Elf64_Half	phentsize;	/* Size of program header entry. */
+	Elf64_Half	phnum;	/* Number of program header entries. */
+	Elf64_Half	shentsize;	/* Size of section header entry. */
+	Elf64_Half	shnum;	/* Number of section header entries. */
+	Elf64_Half	shstrndx;	/* Section name strings section. */
+} Elf64_Ehdr;
+
+/*
+ * Section header.
+ */
+
+typedef struct Elf64_Shdr Elf64_Shdr;
+struct Elf64_Shdr {
+	Elf64_Word	name;	/* Section name (index into the
+					   section header string table). */
+	Elf64_Word	type;	/* Section type. */
+	Elf64_Xword	flags;	/* Section flags. */
+	Elf64_Addr	addr;	/* Address in memory image. */
+	Elf64_Off	off;	/* Offset in file. */
+	Elf64_Xword	size;	/* Size in bytes. */
+	Elf64_Word	link;	/* Index of a related section. */
+	Elf64_Word	info;	/* Depends on section type. */
+	Elf64_Xword	addralign;	/* Alignment in bytes. */
+	Elf64_Xword	entsize;	/* Size of each entry in section. */
+	
+	int	shnum;  /* section number, not stored on disk */
+	LSym*	secsym; /* section symbol, if needed; not on disk */
+};
+
+/*
+ * Program header.
+ */
+
+typedef struct {
+	Elf64_Word	type;		/* Entry type. */
+	Elf64_Word	flags;	/* Access permission flags. */
+	Elf64_Off	off;	/* File offset of contents. */
+	Elf64_Addr	vaddr;	/* Virtual address in memory image. */
+	Elf64_Addr	paddr;	/* Physical address (not used). */
+	Elf64_Xword	filesz;	/* Size of contents in file. */
+	Elf64_Xword	memsz;	/* Size of contents in memory. */
+	Elf64_Xword	align;	/* Alignment in memory and file. */
+} Elf64_Phdr;
+
+/*
+ * Dynamic structure.  The ".dynamic" section contains an array of them.
+ */
+
+typedef struct {
+	Elf64_Sxword	d_tag;		/* Entry type. */
+	union {
+		Elf64_Xword	d_val;	/* Integer value. */
+		Elf64_Addr	d_ptr;	/* Address value. */
+	} d_un;
+} Elf64_Dyn;
+
+/*
+ * Relocation entries.
+ */
+
+/* Relocations that don't need an addend field. */
+typedef struct {
+	Elf64_Addr	off;	/* Location to be relocated. */
+	Elf64_Xword	info;		/* Relocation type and symbol index. */
+} Elf64_Rel;
+
+/* Relocations that need an addend field. */
+typedef struct {
+	Elf64_Addr	off;	/* Location to be relocated. */
+	Elf64_Xword	info;		/* Relocation type and symbol index. */
+	Elf64_Sxword	addend;	/* Addend. */
+} Elf64_Rela;
+
+/* Macros for accessing the fields of r_info. */
+#define ELF64_R_SYM(info)	((info) >> 32)
+#define ELF64_R_TYPE(info)	((info) & 0xffffffffL)
+
+/* Macro for constructing r_info from field values. */
+#define ELF64_R_INFO(sym, type)	((((uint64)(sym)) << 32) + (((uint64)(type)) & 0xffffffffULL))
+
+/*
+ * Symbol table entries.
+ */
+
+typedef struct {
+	Elf64_Word	name;	/* String table index of name. */
+	unsigned char	info;	/* Type and binding information. */
+	unsigned char	other;	/* Reserved (not used). */
+	Elf64_Half	shndx;	/* Section index of symbol. */
+	Elf64_Addr	value;	/* Symbol value. */
+	Elf64_Xword	size;	/* Size of associated object. */
+} Elf64_Sym;
+
+/* Macros for accessing the fields of st_info. */
+#define ELF64_ST_BIND(info)		((info) >> 4)
+#define ELF64_ST_TYPE(info)		((info) & 0xf)
+
+/* Macro for constructing st_info from field values. */
+#define ELF64_ST_INFO(bind, type)	(((bind) << 4) + ((type) & 0xf))
+
+/* Macro for accessing the fields of st_other. */
+#define ELF64_ST_VISIBILITY(oth)	((oth) & 0x3)
+
+/*
+ * Go linker interface
+ */
+
+#define	ELF64HDRSIZE	64
+#define	ELF64PHDRSIZE	56
+#define	ELF64SHDRSIZE	64
+#define	ELF64RELSIZE	16
+#define	ELF64RELASIZE	24
+#define	ELF64SYMSIZE	sizeof(Elf64_Sym)
+
+#define	ELF32HDRSIZE	sizeof(Elf32_Ehdr)
+#define	ELF32PHDRSIZE	sizeof(Elf32_Phdr)
+#define	ELF32SHDRSIZE	sizeof(Elf32_Shdr)
+#define	ELF32SYMSIZE	sizeof(Elf32_Sym)
+#define	ELF32RELSIZE	8
+
+/*
+ * The interface uses the 64-bit structures always,
+ * to avoid code duplication.  The writers know how to
+ * marshal a 32-bit representation from the 64-bit structure.
+ */
+typedef Elf64_Ehdr ElfEhdr;
+typedef Elf64_Shdr ElfShdr;
+typedef Elf64_Phdr ElfPhdr;
+
+void	elfinit(void);
+ElfEhdr	*getElfEhdr(void);
+ElfShdr	*newElfShdr(vlong);
+ElfPhdr	*newElfPhdr(void);
+uint32	elfwritehdr(void);
+uint32	elfwritephdrs(void);
+uint32	elfwriteshdrs(void);
+void	elfwritedynent(LSym*, int, uint64);
+void	elfwritedynentsym(LSym*, int, LSym*);
+void	elfwritedynentsymsize(LSym*, int, LSym*);
+uint32	elfhash(uchar*);
+uint64	startelf(void);
+uint64	endelf(void);
+extern	int	numelfphdr;
+extern	int	numelfshdr;
+extern	int	iself;
+extern	int	elfverneed;
+int	elfinterp(ElfShdr*, uint64, uint64, char*);
+int	elfwriteinterp(void);
+int	elfnetbsdsig(ElfShdr*, uint64, uint64);
+int	elfwritenetbsdsig(void);
+int	elfopenbsdsig(ElfShdr*, uint64, uint64);
+int	elfwriteopenbsdsig(void);
+void	addbuildinfo(char*);
+int	elfbuildinfo(ElfShdr*, uint64, uint64);
+int	elfwritebuildinfo(void);
+void	elfdynhash(void);
+ElfPhdr* elfphload(Segment*);
+ElfShdr* elfshbits(Section*);
+ElfShdr* elfshalloc(Section*);
+ElfShdr* elfshname(char*);
+ElfShdr* elfshreloc(Section*);
+void	elfsetstring(char*, int);
+void	elfaddverneed(LSym*);
+void	elfemitreloc(void);
+void	shsym(ElfShdr*, LSym*);
+void	phsh(ElfPhdr*, ElfShdr*);
+void	doelf(void);
+void	elfsetupplt(void);
+void	dwarfaddshstrings(LSym*);
+void	dwarfaddelfsectionsyms(void);
+void	dwarfaddelfheaders(void);
+void	asmbelf(vlong symo);
+void	asmbelfsetup(void);
+extern char linuxdynld[];
+extern char freebsddynld[];
+extern char netbsddynld[];
+extern char openbsddynld[];
+extern char dragonflydynld[];
+extern char solarisdynld[];
+int	elfreloc1(Reloc*, vlong sectoff);
+void	putelfsectionsyms(void);
+
+EXTERN	int	elfstrsize;
+EXTERN	char*	elfstrdat;
+EXTERN	int	buildinfolen;
+
+/*
+ * Total amount of space to reserve at the start of the file
+ * for Header, PHeaders, SHeaders, and interp.
+ * May waste some.
+ * On FreeBSD, cannot be larger than a page.
+ */
+#define	ELFRESERVE	3072
diff --git a/src/cmd/ld/go.c b/src/cmd/ld/go.c
new file mode 100644
index 0000000..9c296b7
--- /dev/null
+++ b/src/cmd/ld/go.c
@@ -0,0 +1,861 @@
+// 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	"l.h"
+#include	"../ld/lib.h"
+
+// accumulate all type information from .6 files.
+// check for inconsistencies.
+
+// TODO:
+//	generate debugging section in binary.
+//	once the dust settles, try to move some code to
+//		libmach, so that other linkers and ar can share.
+
+/*
+ *	package import data
+ */
+typedef struct Import Import;
+struct Import
+{
+	Import *hash;	// next in hash table
+	char *prefix;	// "type", "var", "func", "const"
+	char *name;
+	char *def;
+	char *file;
+};
+enum {
+	NIHASH = 1024
+};
+static Import *ihash[NIHASH];
+static int nimport;
+static void imported(char *pkg, char *import);
+
+static int
+hashstr(char *name)
+{
+	uint32 h;
+	char *cp;
+
+	h = 0;
+	for(cp = name; *cp; h += *cp++)
+		h *= 1119;
+	h &= 0xffffff;
+	return h;
+}
+
+static Import *
+ilookup(char *name)
+{
+	int h;
+	Import *x;
+
+	h = hashstr(name) % NIHASH;
+	for(x=ihash[h]; x; x=x->hash)
+		if(x->name[0] == name[0] && strcmp(x->name, name) == 0)
+			return x;
+	x = mal(sizeof *x);
+	x->name = estrdup(name);
+	x->hash = ihash[h];
+	ihash[h] = x;
+	nimport++;
+	return x;
+}
+
+static void loadpkgdata(char*, char*, char*, int);
+static void loadcgo(char*, char*, char*, int);
+static int parsemethod(char**, char*, char**);
+static int parsepkgdata(char*, char*, char**, char*, char**, char**, char**);
+
+void
+ldpkg(Biobuf *f, char *pkg, int64 len, char *filename, int whence)
+{
+	char *data, *p0, *p1, *name;
+
+	if(debug['g'])
+		return;
+
+	if((int)len != len) {
+		fprint(2, "%s: too much pkg data in %s\n", argv0, filename);
+		if(debug['u'])
+			errorexit();
+		return;
+	}
+	data = mal(len+1);
+	if(Bread(f, data, len) != len) {
+		fprint(2, "%s: short pkg read %s\n", argv0, filename);
+		if(debug['u'])
+			errorexit();
+		return;
+	}
+	data[len] = '\0';
+
+	// first \n$$ marks beginning of exports - skip rest of line
+	p0 = strstr(data, "\n$$");
+	if(p0 == nil) {
+		if(debug['u'] && whence != ArchiveObj) {
+			fprint(2, "%s: cannot find export data in %s\n", argv0, filename);
+			errorexit();
+		}
+		return;
+	}
+	p0 += 3;
+	while(*p0 != '\n' && *p0 != '\0')
+		p0++;
+
+	// second marks end of exports / beginning of local data
+	p1 = strstr(p0, "\n$$");
+	if(p1 == nil) {
+		fprint(2, "%s: cannot find end of exports in %s\n", argv0, filename);
+		if(debug['u'])
+			errorexit();
+		return;
+	}
+	while(p0 < p1 && (*p0 == ' ' || *p0 == '\t' || *p0 == '\n'))
+		p0++;
+	if(p0 < p1) {
+		if(strncmp(p0, "package ", 8) != 0) {
+			fprint(2, "%s: bad package section in %s - %s\n", argv0, filename, p0);
+			if(debug['u'])
+				errorexit();
+			return;
+		}
+		p0 += 8;
+		while(p0 < p1 && (*p0 == ' ' || *p0 == '\t' || *p0 == '\n'))
+			p0++;
+		name = p0;
+		while(p0 < p1 && *p0 != ' ' && *p0 != '\t' && *p0 != '\n')
+			p0++;
+		if(debug['u'] && whence != ArchiveObj &&
+		   (p0+6 > p1 || memcmp(p0, " safe\n", 6) != 0)) {
+			fprint(2, "%s: load of unsafe package %s\n", argv0, filename);
+			nerrors++;
+			errorexit();
+		}
+		if(p0 < p1) {
+			if(*p0 == '\n')
+				*p0++ = '\0';
+			else {
+				*p0++ = '\0';
+				while(p0 < p1 && *p0++ != '\n')
+					;
+			}
+		}
+		if(strcmp(pkg, "main") == 0 && strcmp(name, "main") != 0) {
+			fprint(2, "%s: %s: not package main (package %s)\n", argv0, filename, name);
+			nerrors++;
+			errorexit();
+		}
+		loadpkgdata(filename, pkg, p0, p1 - p0);
+	}
+	
+	// __.PKGDEF has no cgo section - those are in the C compiler-generated object files.
+	if(whence == Pkgdef)
+		return;
+
+	// look for cgo section
+	p0 = strstr(p1, "\n$$  // cgo");
+	if(p0 != nil) {
+		p0 = strchr(p0+1, '\n');
+		if(p0 == nil) {
+			fprint(2, "%s: found $$ // cgo but no newline in %s\n", argv0, filename);
+			if(debug['u'])
+				errorexit();
+			return;
+		}
+		p1 = strstr(p0, "\n$$");
+		if(p1 == nil)
+			p1 = strstr(p0, "\n!\n");
+		if(p1 == nil) {
+			fprint(2, "%s: cannot find end of // cgo section in %s\n", argv0, filename);
+			if(debug['u'])
+				errorexit();
+			return;
+		}
+		loadcgo(filename, pkg, p0 + 1, p1 - (p0+1));
+	}
+}
+
+static void
+loadpkgdata(char *file, char *pkg, char *data, int len)
+{
+	char *p, *ep, *prefix, *name, *def;
+	Import *x;
+
+	file = estrdup(file);
+	p = data;
+	ep = data + len;
+	while(parsepkgdata(file, pkg, &p, ep, &prefix, &name, &def) > 0) {
+		x = ilookup(name);
+		if(x->prefix == nil) {
+			x->prefix = prefix;
+			x->def = estrdup(def);
+			x->file = file;
+		} else if(strcmp(x->prefix, prefix) != 0) {
+			fprint(2, "%s: conflicting definitions for %s\n", argv0, name);
+			fprint(2, "%s:\t%s %s ...\n", x->file, x->prefix, name);
+			fprint(2, "%s:\t%s %s ...\n", file, prefix, name);
+			nerrors++;
+		} else if(strcmp(x->def, def) != 0) {
+			fprint(2, "%s: conflicting definitions for %s\n", argv0, name);
+			fprint(2, "%s:\t%s %s %s\n", x->file, x->prefix, name, x->def);
+			fprint(2, "%s:\t%s %s %s\n", file, prefix, name, def);
+			nerrors++;
+		}
+		free(name);
+		free(def);
+	}
+	free(file);
+}
+
+static int
+parsepkgdata(char *file, char *pkg, char **pp, char *ep, char **prefixp, char **namep, char **defp)
+{
+	char *p, *prefix, *name, *def, *edef, *meth;
+	int n, inquote;
+
+	// skip white space
+	p = *pp;
+loop:
+	while(p < ep && (*p == ' ' || *p == '\t' || *p == '\n'))
+		p++;
+	if(p == ep || strncmp(p, "$$\n", 3) == 0)
+		return 0;
+
+	// prefix: (var|type|func|const)
+	prefix = p;
+	if(p + 7 > ep)
+		return -1;
+	if(strncmp(p, "var ", 4) == 0)
+		p += 4;
+	else if(strncmp(p, "type ", 5) == 0)
+		p += 5;
+	else if(strncmp(p, "func ", 5) == 0)
+		p += 5;
+	else if(strncmp(p, "const ", 6) == 0)
+		p += 6;
+	else if(strncmp(p, "import ", 7) == 0) {
+		p += 7;
+		while(p < ep && *p != ' ')
+			p++;
+		p++;
+		name = p;
+		while(p < ep && *p != '\n')
+			p++;
+		if(p >= ep) {
+			fprint(2, "%s: %s: confused in import line\n", argv0, file);
+			nerrors++;
+			return -1;
+		}
+		*p++ = '\0';
+		imported(pkg, name);
+		goto loop;
+	}
+	else {
+		fprint(2, "%s: %s: confused in pkg data near <<%.40s>>\n", argv0, file, prefix);
+		nerrors++;
+		return -1;
+	}
+	p[-1] = '\0';
+
+	// name: a.b followed by space
+	name = p;
+	inquote = 0;
+	while(p < ep) {
+		if (*p == ' ' && !inquote)
+			break;
+
+		if(*p == '\\')
+			p++;
+		else if(*p == '"')
+			inquote = !inquote;
+
+		p++;
+	}
+
+	if(p >= ep)
+		return -1;
+	*p++ = '\0';
+
+	// def: free form to new line
+	def = p;
+	while(p < ep && *p != '\n')
+		p++;
+	if(p >= ep)
+		return -1;
+	edef = p;
+	*p++ = '\0';
+
+	// include methods on successive lines in def of named type
+	while(parsemethod(&p, ep, &meth) > 0) {
+		*edef++ = '\n';	// overwrites '\0'
+		if(edef+1 > meth) {
+			// We want to indent methods with a single \t.
+			// 6g puts at least one char of indent before all method defs,
+			// so there will be room for the \t.  If the method def wasn't
+			// indented we could do something more complicated,
+			// but for now just diagnose the problem and assume
+			// 6g will keep indenting for us.
+			fprint(2, "%s: %s: expected methods to be indented %p %p %.10s\n", argv0,
+				file, edef, meth, meth);
+			nerrors++;
+			return -1;
+		}
+		*edef++ = '\t';
+		n = strlen(meth);
+		memmove(edef, meth, n);
+		edef += n;
+	}
+
+	name = expandpkg(name, pkg);
+	def = expandpkg(def, pkg);
+
+	// done
+	*pp = p;
+	*prefixp = prefix;
+	*namep = name;
+	*defp = def;
+	return 1;
+}
+
+static int
+parsemethod(char **pp, char *ep, char **methp)
+{
+	char *p;
+
+	// skip white space
+	p = *pp;
+	while(p < ep && (*p == ' ' || *p == '\t'))
+		p++;
+	if(p == ep)
+		return 0;
+
+	// might be a comment about the method
+	if(p + 2 < ep && strncmp(p, "//", 2) == 0)
+		goto useline;
+	
+	// if it says "func (", it's a method
+	if(p + 6 < ep && strncmp(p, "func (", 6) == 0)
+		goto useline;
+	return 0;
+
+useline:
+	// definition to end of line
+	*methp = p;
+	while(p < ep && *p != '\n')
+		p++;
+	if(p >= ep) {
+		fprint(2, "%s: lost end of line in method definition\n", argv0);
+		*pp = ep;
+		return -1;
+	}
+	*p++ = '\0';
+	*pp = p;
+	return 1;
+}
+
+static void
+loadcgo(char *file, char *pkg, char *p, int n)
+{
+	char *pend, *next, *p0, *q;
+	char *f[10], *local, *remote, *lib;
+	int nf;
+	LSym *s;
+
+	USED(file);
+	pend = p + n;
+	p0 = nil;
+	for(; p<pend; p=next) {
+		next = strchr(p, '\n');
+		if(next == nil)
+			next = "";
+		else
+			*next++ = '\0';
+
+		free(p0);
+		p0 = estrdup(p); // save for error message
+		nf = tokenize(p, f, nelem(f));
+		
+		if(strcmp(f[0], "cgo_import_dynamic") == 0) {
+			if(nf < 2 || nf > 4)
+				goto err;
+			
+			local = f[1];
+			remote = local;
+			if(nf > 2)
+				remote = f[2];
+			lib = "";
+			if(nf > 3)
+				lib = f[3];
+			
+			if(debug['d']) {
+				fprint(2, "%s: %s: cannot use dynamic imports with -d flag\n", argv0, file);
+				nerrors++;
+				return;
+			}
+		
+			if(strcmp(local, "_") == 0 && strcmp(remote, "_") == 0) {
+				// allow #pragma dynimport _ _ "foo.so"
+				// to force a link of foo.so.
+				havedynamic = 1;
+				adddynlib(lib);
+				continue;
+			}
+
+			local = expandpkg(local, pkg);
+			q = strchr(remote, '#');
+			if(q)
+				*q++ = '\0';
+			s = linklookup(ctxt, local, 0);
+			if(local != f[1])
+				free(local);
+			if(s->type == 0 || s->type == SXREF || s->type == SHOSTOBJ) {
+				s->dynimplib = lib;
+				s->extname = remote;
+				s->dynimpvers = q;
+				if(s->type != SHOSTOBJ)
+					s->type = SDYNIMPORT;
+				havedynamic = 1;
+			}
+			continue;
+		}
+		
+		if(strcmp(f[0], "cgo_import_static") == 0) {
+			if(nf != 2)
+				goto err;
+			local = f[1];
+			s = linklookup(ctxt, local, 0);
+			s->type = SHOSTOBJ;
+			s->size = 0;
+			continue;
+		}
+
+		if(strcmp(f[0], "cgo_export_static") == 0 || strcmp(f[0], "cgo_export_dynamic") == 0) {
+			// TODO: Remove once we know Windows is okay.
+			if(strcmp(f[0], "cgo_export_static") == 0 && HEADTYPE == Hwindows)
+				continue;
+
+			if(nf < 2 || nf > 3)
+				goto err;
+			local = f[1];
+			if(nf > 2)
+				remote = f[2];
+			else
+				remote = local;
+			local = expandpkg(local, pkg);
+			s = linklookup(ctxt, local, 0);
+
+			if(flag_shared && s == linklookup(ctxt, "main", 0))
+				continue;
+
+			// export overrides import, for openbsd/cgo.
+			// see issue 4878.
+			if(s->dynimplib != nil) {
+				s->dynimplib = nil;
+				s->extname = nil;
+				s->dynimpvers = nil;
+				s->type = 0;
+			}
+
+			if(s->cgoexport == 0) {
+				s->extname = remote;
+				if(ndynexp%32 == 0)
+					dynexp = erealloc(dynexp, (ndynexp+32)*sizeof dynexp[0]);
+				dynexp[ndynexp++] = s;
+			} else if(strcmp(s->extname, remote) != 0) {
+				fprint(2, "%s: conflicting cgo_export directives: %s as %s and %s\n", argv0, s->name, s->extname, remote);
+				nerrors++;
+				return;
+			}
+			if(strcmp(f[0], "cgo_export_static") == 0)
+				s->cgoexport |= CgoExportStatic;
+			else
+				s->cgoexport |= CgoExportDynamic;
+			if(local != f[1])
+				free(local);
+			continue;
+		}
+		
+		if(strcmp(f[0], "cgo_dynamic_linker") == 0) {
+			if(nf != 2)
+				goto err;
+			
+			if(!debug['I']) { // not overridden by command line
+				if(interpreter != nil && strcmp(interpreter, f[1]) != 0) {
+					fprint(2, "%s: conflict dynlinker: %s and %s\n", argv0, interpreter, f[1]);
+					nerrors++;
+					return;
+				}
+				free(interpreter);
+				interpreter = estrdup(f[1]);
+			}
+			continue;
+		}
+		
+		if(strcmp(f[0], "cgo_ldflag") == 0) {
+			if(nf != 2)
+				goto err;
+			if(nldflag%32 == 0)
+				ldflag = erealloc(ldflag, (nldflag+32)*sizeof ldflag[0]);
+			ldflag[nldflag++] = estrdup(f[1]);
+			continue;
+		}
+	}
+	free(p0);
+	return;
+
+err:
+	fprint(2, "%s: %s: invalid dynimport line: %s\n", argv0, file, p0);
+	nerrors++;
+}
+
+static LSym *markq;
+static LSym *emarkq;
+
+static void
+mark1(LSym *s, LSym *parent)
+{
+	if(s == S || s->reachable)
+		return;
+	if(strncmp(s->name, "go.weak.", 8) == 0)
+		return;
+	s->reachable = 1;
+	s->reachparent = parent;
+	if(markq == nil)
+		markq = s;
+	else
+		emarkq->queue = s;
+	emarkq = s;
+}
+
+void
+mark(LSym *s)
+{
+	mark1(s, nil);
+}
+
+static void
+markflood(void)
+{
+	Auto *a;
+	LSym *s;
+	int i;
+	
+	for(s=markq; s!=S; s=s->queue) {
+		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(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);
+	}
+}
+
+static char*
+markextra[] =
+{
+	"runtime.morestack",
+	"runtime.morestackx",
+
+	"runtime.morestack00",
+	"runtime.morestack10",
+	"runtime.morestack01",
+	"runtime.morestack11",
+
+	"runtime.morestack8",
+	"runtime.morestack16",
+	"runtime.morestack24",
+	"runtime.morestack32",
+	"runtime.morestack40",
+	"runtime.morestack48",
+	
+	// on arm, lock in the div/mod helpers too
+	"_div",
+	"_divu",
+	"_mod",
+	"_modu",
+};
+
+void
+deadcode(void)
+{
+	int i;
+	LSym *s, *last, *p;
+	Fmt fmt;
+
+	if(debug['v'])
+		Bprint(&bso, "%5.2f deadcode\n", cputime());
+
+	mark(linklookup(ctxt, INITENTRY, 0));
+	for(i=0; i<nelem(markextra); i++)
+		mark(linklookup(ctxt, markextra[i], 0));
+
+	for(i=0; i<ndynexp; i++)
+		mark(dynexp[i]);
+
+	markflood();
+	
+	// keep each beginning with 'typelink.' if the symbol it points at is being kept.
+	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;
+	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)
+			ctxt->textp = s;
+		else
+			last->next = s;
+		last = s;
+	}
+	if(last == nil)
+		ctxt->textp = nil;
+	else
+		last->next = nil;
+	
+	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;
+			s->hide = 1;
+		}
+	
+	// record field tracking references
+	fmtstrinit(&fmt);
+	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;
+			if(s->reachable) {
+				fmtprint(&fmt, "%s", s->name+9);
+				for(p=s->reachparent; p; p=p->reachparent)
+					fmtprint(&fmt, "\t%s", p->name);
+				fmtprint(&fmt, "\n");
+			}
+			s->type = SCONST;
+			s->value = 0;
+		}
+	}
+	if(tracksym == nil)
+		return;
+	s = linklookup(ctxt, tracksym, 0);
+	if(!s->reachable)
+		return;
+	addstrdata(tracksym, fmtstrflush(&fmt));
+}
+
+void
+doweak(void)
+{
+	LSym *s, *t;
+
+	// resolve weak references only if
+	// target symbol will be in binary anyway.
+	for(s = ctxt->allsym; s != S; s = s->allsym) {
+		if(strncmp(s->name, "go.weak.", 8) == 0) {
+			t = linkrlookup(ctxt, s->name+8, s->version);
+			if(t && t->type != 0 && t->reachable) {
+				s->value = t->value;
+				s->type = t->type;
+				s->outer = t;
+			} else {
+				s->type = SCONST;
+				s->value = 0;
+			}
+			continue;
+		}
+	}
+}
+
+void
+addexport(void)
+{
+	int i;
+	
+	if(HEADTYPE == Hdarwin)
+		return;
+
+	for(i=0; i<ndynexp; i++)
+		adddynsym(ctxt, dynexp[i]);
+}
+
+/* %Z from gc, for quoting import paths */
+int
+Zconv(Fmt *fp)
+{
+	Rune r;
+	char *s, *se;
+	int n;
+
+	s = va_arg(fp->args, char*);
+	if(s == nil)
+		return fmtstrcpy(fp, "<nil>");
+
+	se = s + strlen(s);
+
+	// NOTE: Keep in sync with ../gc/go.c:/^Zconv.
+	while(s < se) {
+		n = chartorune(&r, s);
+		s += n;
+		switch(r) {
+		case Runeerror:
+			if(n == 1) {
+				fmtprint(fp, "\\x%02x", (uchar)*(s-1));
+				break;
+			}
+			// fall through
+		default:
+			if(r < ' ') {
+				fmtprint(fp, "\\x%02x", r);
+				break;
+			}
+			fmtrune(fp, r);
+			break;
+		case '\t':
+			fmtstrcpy(fp, "\\t");
+			break;
+		case '\n':
+			fmtstrcpy(fp, "\\n");
+			break;
+		case '\"':
+		case '\\':
+			fmtrune(fp, '\\');
+			fmtrune(fp, r);
+			break;
+		case 0xFEFF: // BOM, basically disallowed in source code
+			fmtstrcpy(fp, "\\uFEFF");
+			break;
+		}
+	}
+	return 0;
+}
+
+
+typedef struct Pkg Pkg;
+struct Pkg
+{
+	uchar mark;
+	uchar checked;
+	Pkg *next;
+	char *path;
+	Pkg **impby;
+	int nimpby;
+	int mimpby;
+	Pkg *all;
+};
+
+static Pkg *phash[1024];
+static Pkg *pkgall;
+
+static Pkg*
+getpkg(char *path)
+{
+	Pkg *p;
+	int h;
+	
+	h = hashstr(path) % nelem(phash);
+	for(p=phash[h]; p; p=p->next)
+		if(strcmp(p->path, path) == 0)
+			return p;
+	p = mal(sizeof *p);
+	p->path = estrdup(path);
+	p->next = phash[h];
+	phash[h] = p;
+	p->all = pkgall;
+	pkgall = p;
+	return p;
+}
+
+static void
+imported(char *pkg, char *import)
+{
+	Pkg *p, *i;
+	
+	// everyone imports runtime, even runtime.
+	if(strcmp(import, "\"runtime\"") == 0)
+		return;
+
+	pkg = smprint("\"%Z\"", pkg);  // turn pkg path into quoted form, freed below
+	p = getpkg(pkg);
+	i = getpkg(import);
+	if(i->nimpby >= i->mimpby) {
+		i->mimpby *= 2;
+		if(i->mimpby == 0)
+			i->mimpby = 16;
+		i->impby = erealloc(i->impby, i->mimpby*sizeof i->impby[0]);
+	}
+	i->impby[i->nimpby++] = p;
+	free(pkg);
+}
+
+static Pkg*
+cycle(Pkg *p)
+{
+	int i;
+	Pkg *bad;
+
+	if(p->checked)
+		return 0;
+
+	if(p->mark) {
+		nerrors++;
+		print("import cycle:\n");
+		print("\t%s\n", p->path);
+		return p;
+	}
+	p->mark = 1;
+	for(i=0; i<p->nimpby; i++) {
+		if((bad = cycle(p->impby[i])) != nil) {
+			p->mark = 0;
+			p->checked = 1;
+			print("\timports %s\n", p->path);
+			if(bad == p)
+				return nil;
+			return bad;
+		}
+	}
+	p->checked = 1;
+	p->mark = 0;
+	return 0;
+}
+
+void
+importcycles(void)
+{
+	Pkg *p;
+	
+	for(p=pkgall; p; p=p->all)
+		cycle(p);
+}
+
+void
+setlinkmode(char *arg)
+{
+	if(strcmp(arg, "internal") == 0)
+		linkmode = LinkInternal;
+	else if(strcmp(arg, "external") == 0)
+		linkmode = LinkExternal;
+	else if(strcmp(arg, "auto") == 0)
+		linkmode = LinkAuto;
+	else {
+		fprint(2, "unknown link mode -linkmode %s\n", arg);
+		errorexit();
+	}
+}
diff --git a/src/cmd/ld/ldelf.c b/src/cmd/ld/ldelf.c
new file mode 100644
index 0000000..dd5fa0d
--- /dev/null
+++ b/src/cmd/ld/ldelf.c
@@ -0,0 +1,905 @@
+/*
+Derived from Plan 9 from User Space's src/libmach/elf.h, elf.c
+http://code.swtch.com/plan9port/src/tip/src/libmach/
+
+	Copyright © 2004 Russ Cox.
+	Portions Copyright © 2008-2010 Google Inc.
+	Portions Copyright © 2010 The Go Authors.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include	"l.h"
+#include	"lib.h"
+#include	"../ld/elf.h"
+
+enum
+{
+	ElfClassNone = 0,
+	ElfClass32,
+	ElfClass64,
+
+	ElfDataNone = 0,
+	ElfDataLsb,
+	ElfDataMsb,
+
+	ElfTypeNone = 0,
+	ElfTypeRelocatable,
+	ElfTypeExecutable,
+	ElfTypeSharedObject,
+	ElfTypeCore,
+	/* 0xFF00 - 0xFFFF reserved for processor-specific types */
+
+	ElfMachNone = 0,
+	ElfMach32100,		/* AT&T WE 32100 */
+	ElfMachSparc,		/* SPARC */
+	ElfMach386,		/* Intel 80386 */
+	ElfMach68000,		/* Motorola 68000 */
+	ElfMach88000,		/* Motorola 88000 */
+	ElfMach486,		/* Intel 80486, no longer used */
+	ElfMach860,		/* Intel 80860 */
+	ElfMachMips,		/* MIPS RS3000 */
+	ElfMachS370,		/* IBM System/370 */
+	ElfMachMipsLe,	/* MIPS RS3000 LE */
+	ElfMachParisc = 15,		/* HP PA RISC */
+	ElfMachVpp500 = 17,	/* Fujitsu VPP500 */
+	ElfMachSparc32Plus,	/* SPARC V8+ */
+	ElfMach960,		/* Intel 80960 */
+	ElfMachPower,		/* PowerPC */
+	ElfMachPower64,	/* PowerPC 64 */
+	ElfMachS390,		/* IBM System/390 */
+	ElfMachV800 = 36,	/* NEC V800 */
+	ElfMachFr20,		/* Fujitsu FR20 */
+	ElfMachRh32,		/* TRW RH-32 */
+	ElfMachRce,		/* Motorola RCE */
+	ElfMachArm,		/* ARM */
+	ElfMachAlpha,		/* Digital Alpha */
+	ElfMachSH,		/* Hitachi SH */
+	ElfMachSparc9,		/* SPARC V9 */
+	ElfMachAmd64 = 62,
+	/* and the list goes on... */
+
+	ElfAbiNone = 0,
+	ElfAbiSystemV = 0,	/* [sic] */
+	ElfAbiHPUX,
+	ElfAbiNetBSD,
+	ElfAbiLinux,
+	ElfAbiSolaris = 6,
+	ElfAbiAix,
+	ElfAbiIrix,
+	ElfAbiFreeBSD,
+	ElfAbiTru64,
+	ElfAbiModesto,
+	ElfAbiOpenBSD,
+	ElfAbiARM = 97,
+	ElfAbiEmbedded = 255,
+
+	/* some of sections 0xFF00 - 0xFFFF reserved for various things */
+	ElfSectNone = 0,
+	ElfSectProgbits,
+	ElfSectSymtab,
+	ElfSectStrtab,
+	ElfSectRela,
+	ElfSectHash,
+	ElfSectDynamic,
+	ElfSectNote,
+	ElfSectNobits,
+	ElfSectRel,
+	ElfSectShlib,
+	ElfSectDynsym,
+
+	ElfSectFlagWrite = 0x1,
+	ElfSectFlagAlloc = 0x2,
+	ElfSectFlagExec = 0x4,
+	/* 0xF0000000 are reserved for processor specific */
+
+	ElfSymBindLocal = 0,
+	ElfSymBindGlobal,
+	ElfSymBindWeak,
+	/* 13-15 reserved */
+
+	ElfSymTypeNone = 0,
+	ElfSymTypeObject,
+	ElfSymTypeFunc,
+	ElfSymTypeSection,
+	ElfSymTypeFile,
+	/* 13-15 reserved */
+
+	ElfSymShnNone = 0,
+	ElfSymShnAbs = 0xFFF1,
+	ElfSymShnCommon = 0xFFF2,
+	/* 0xFF00-0xFF1F reserved for processors */
+	/* 0xFF20-0xFF3F reserved for operating systems */
+
+	ElfProgNone = 0,
+	ElfProgLoad,
+	ElfProgDynamic,
+	ElfProgInterp,
+	ElfProgNote,
+	ElfProgShlib,
+	ElfProgPhdr,
+
+	ElfProgFlagExec = 0x1,
+	ElfProgFlagWrite = 0x2,
+	ElfProgFlagRead = 0x4,
+
+	ElfNotePrStatus = 1,
+	ElfNotePrFpreg = 2,
+	ElfNotePrPsinfo = 3,
+	ElfNotePrTaskstruct = 4,
+	ElfNotePrAuxv = 6,
+	ElfNotePrXfpreg = 0x46e62b7f	/* for gdb/386 */
+};
+
+typedef struct ElfHdrBytes ElfHdrBytes;
+typedef struct ElfSectBytes ElfSectBytes;
+typedef struct ElfProgBytes ElfProgBytes;
+typedef struct ElfSymBytes ElfSymBytes;
+
+typedef struct ElfHdrBytes64 ElfHdrBytes64;
+typedef struct ElfSectBytes64 ElfSectBytes64;
+typedef struct ElfProgBytes64 ElfProgBytes64;
+typedef struct ElfSymBytes64 ElfSymBytes64;
+
+struct ElfHdrBytes
+{
+	uchar	ident[16];
+	uchar	type[2];
+	uchar	machine[2];
+	uchar	version[4];
+	uchar	entry[4];
+	uchar	phoff[4];
+	uchar	shoff[4];
+	uchar	flags[4];
+	uchar	ehsize[2];
+	uchar	phentsize[2];
+	uchar	phnum[2];
+	uchar	shentsize[2];
+	uchar	shnum[2];
+	uchar	shstrndx[2];
+};
+
+struct ElfHdrBytes64
+{
+	uchar	ident[16];
+	uchar	type[2];
+	uchar	machine[2];
+	uchar	version[4];
+	uchar	entry[8];
+	uchar	phoff[8];
+	uchar	shoff[8];
+	uchar	flags[4];
+	uchar	ehsize[2];
+	uchar	phentsize[2];
+	uchar	phnum[2];
+	uchar	shentsize[2];
+	uchar	shnum[2];
+	uchar	shstrndx[2];
+};
+
+struct ElfSectBytes
+{
+	uchar	name[4];
+	uchar	type[4];
+	uchar	flags[4];
+	uchar	addr[4];
+	uchar	off[4];
+	uchar	size[4];
+	uchar	link[4];
+	uchar	info[4];
+	uchar	align[4];
+	uchar	entsize[4];
+};
+
+struct ElfSectBytes64
+{
+	uchar	name[4];
+	uchar	type[4];
+	uchar	flags[8];
+	uchar	addr[8];
+	uchar	off[8];
+	uchar	size[8];
+	uchar	link[4];
+	uchar	info[4];
+	uchar	align[8];
+	uchar	entsize[8];
+};
+
+struct ElfSymBytes
+{
+	uchar	name[4];
+	uchar	value[4];
+	uchar	size[4];
+	uchar	info;	/* top4: bind, bottom4: type */
+	uchar	other;
+	uchar	shndx[2];
+};
+
+struct ElfSymBytes64
+{
+	uchar	name[4];
+	uchar	info;	/* top4: bind, bottom4: type */
+	uchar	other;
+	uchar	shndx[2];
+	uchar	value[8];
+	uchar	size[8];
+};
+
+typedef struct ElfSect ElfSect;
+typedef struct ElfObj ElfObj;
+typedef struct ElfSym ElfSym;
+
+struct ElfSect
+{
+	char		*name;
+	uint32	type;
+	uint64	flags;
+	uint64	addr;
+	uint64	off;
+	uint64	size;
+	uint32	link;
+	uint32	info;
+	uint64	align;
+	uint64	entsize;
+	uchar	*base;
+	LSym	*sym;
+};
+
+struct ElfObj
+{
+	Biobuf	*f;
+	int64	base;	// offset in f where ELF begins
+	int64	len;		// length of ELF
+	int	is64;
+	char	*name;
+
+	Endian	*e;
+	ElfSect	*sect;
+	uint		nsect;
+	char		*shstrtab;
+	int		nsymtab;
+	ElfSect	*symtab;
+	ElfSect	*symstr;
+
+	uint32	type;
+	uint32	machine;
+	uint32	version;
+	uint64	entry;
+	uint64	phoff;
+	uint64	shoff;
+	uint32	flags;
+	uint32	ehsize;
+	uint32	phentsize;
+	uint32	phnum;
+	uint32	shentsize;
+	uint32	shnum;
+	uint32	shstrndx;
+};
+
+struct ElfSym
+{
+	char*	name;
+	uint64	value;
+	uint64	size;
+	uchar	bind;
+	uchar	type;
+	uchar	other;
+	uint16	shndx;
+	LSym*	sym;
+};
+
+uchar ElfMagic[4] = { 0x7F, 'E', 'L', 'F' };
+
+static ElfSect*	section(ElfObj*, char*);
+static int	map(ElfObj*, ElfSect*);
+static int	readsym(ElfObj*, int i, ElfSym*, int);
+static int	reltype(char*, int, uchar*);
+
+int
+valuecmp(LSym *a, LSym *b)
+{
+	if(a->value < b->value)
+		return -1;
+	if(a->value > b->value)
+		return +1;
+	return 0;
+}
+
+void
+ldelf(Biobuf *f, char *pkg, int64 len, char *pn)
+{
+	int32 base;
+	uint64 add, info;
+	char *name;
+	int i, j, rela, is64, n;
+	uchar hdrbuf[64];
+	uchar *p;
+	ElfHdrBytes *hdr;
+	ElfObj *obj;
+	ElfSect *sect, *rsect;
+	ElfSym sym;
+	Endian *e;
+	Reloc *r, *rp;
+	LSym *s;
+	LSym **symbols;
+
+	symbols = nil;
+
+	if(debug['v'])
+		Bprint(&bso, "%5.2f ldelf %s\n", cputime(), pn);
+
+	ctxt->version++;
+	base = Boffset(f);
+
+	if(Bread(f, hdrbuf, sizeof hdrbuf) != sizeof hdrbuf)
+		goto bad;
+	hdr = (ElfHdrBytes*)hdrbuf;
+	if(memcmp(hdr->ident, ElfMagic, 4) != 0)
+		goto bad;
+	switch(hdr->ident[5]) {
+	case ElfDataLsb:
+		e = ≤
+		break;
+	case ElfDataMsb:
+		e = &be;
+		break;
+	default:
+		goto bad;
+	}
+
+	// read header
+	obj = mal(sizeof *obj);
+	obj->e = e;
+	obj->f = f;
+	obj->base = base;
+	obj->len = len;
+	obj->name = pn;
+	
+	is64 = 0;
+	if(hdr->ident[4] == ElfClass64) {
+		ElfHdrBytes64* hdr;
+
+		is64 = 1;
+		hdr = (ElfHdrBytes64*)hdrbuf;
+		obj->type = e->e16(hdr->type);
+		obj->machine = e->e16(hdr->machine);
+		obj->version = e->e32(hdr->version);
+		obj->phoff = e->e64(hdr->phoff);
+		obj->shoff = e->e64(hdr->shoff);
+		obj->flags = e->e32(hdr->flags);
+		obj->ehsize = e->e16(hdr->ehsize);
+		obj->phentsize = e->e16(hdr->phentsize);
+		obj->phnum = e->e16(hdr->phnum);
+		obj->shentsize = e->e16(hdr->shentsize);
+		obj->shnum = e->e16(hdr->shnum);
+		obj->shstrndx = e->e16(hdr->shstrndx);
+	} else {
+		obj->type = e->e16(hdr->type);
+		obj->machine = e->e16(hdr->machine);
+		obj->version = e->e32(hdr->version);
+		obj->entry = e->e32(hdr->entry);
+		obj->phoff = e->e32(hdr->phoff);
+		obj->shoff = e->e32(hdr->shoff);
+		obj->flags = e->e32(hdr->flags);
+		obj->ehsize = e->e16(hdr->ehsize);
+		obj->phentsize = e->e16(hdr->phentsize);
+		obj->phnum = e->e16(hdr->phnum);
+		obj->shentsize = e->e16(hdr->shentsize);
+		obj->shnum = e->e16(hdr->shnum);
+		obj->shstrndx = e->e16(hdr->shstrndx);
+	}
+	obj->is64 = is64;
+	
+	if(hdr->ident[6] != obj->version)
+		goto bad;
+
+	if(e->e16(hdr->type) != ElfTypeRelocatable) {
+		diag("%s: elf but not elf relocatable object", pn);
+		return;
+	}
+
+	switch(thechar) {
+	default:
+		diag("%s: elf %s unimplemented", pn, thestring);
+		return;
+	case '5':
+		if(e != &le || obj->machine != ElfMachArm || hdr->ident[4] != ElfClass32) {
+			diag("%s: elf object but not arm", pn);
+			return;
+		}
+		break;
+	case '6':
+		if(e != &le || obj->machine != ElfMachAmd64 || hdr->ident[4] != ElfClass64) {
+			diag("%s: elf object but not amd64", pn);
+			return;
+		}
+		break;
+	case '8':
+		if(e != &le || obj->machine != ElfMach386 || hdr->ident[4] != ElfClass32) {
+			diag("%s: elf object but not 386", pn);
+			return;
+		}
+		break;
+	}
+
+	// load section list into memory.
+	obj->sect = mal(obj->shnum*sizeof obj->sect[0]);
+	obj->nsect = obj->shnum;
+	for(i=0; i<obj->nsect; i++) {
+		if(Bseek(f, base+obj->shoff+i*obj->shentsize, 0) < 0)
+			goto bad;
+		sect = &obj->sect[i];
+		if(is64) {
+			ElfSectBytes64 b;
+
+			werrstr("short read");
+			if(Bread(f, &b, sizeof b) != sizeof b)
+				goto bad;
+
+			sect->name = (char*)(uintptr)e->e32(b.name);
+			sect->type = e->e32(b.type);
+			sect->flags = e->e64(b.flags);
+			sect->addr = e->e64(b.addr);
+			sect->off = e->e64(b.off);
+			sect->size = e->e64(b.size);
+			sect->link = e->e32(b.link);
+			sect->info = e->e32(b.info);
+			sect->align = e->e64(b.align);
+			sect->entsize = e->e64(b.entsize);
+		} else {
+			ElfSectBytes b;
+
+			werrstr("short read");
+			if(Bread(f, &b, sizeof b) != sizeof b)
+				goto bad;
+		
+			sect->name = (char*)(uintptr)e->e32(b.name);
+			sect->type = e->e32(b.type);
+			sect->flags = e->e32(b.flags);
+			sect->addr = e->e32(b.addr);
+			sect->off = e->e32(b.off);
+			sect->size = e->e32(b.size);
+			sect->link = e->e32(b.link);
+			sect->info = e->e32(b.info);
+			sect->align = e->e32(b.align);
+			sect->entsize = e->e32(b.entsize);
+		}
+	}
+
+	// read section string table and translate names
+	if(obj->shstrndx >= obj->nsect) {
+		werrstr("shstrndx out of range %d >= %d", obj->shstrndx, obj->nsect);
+		goto bad;
+	}
+	sect = &obj->sect[obj->shstrndx];
+	if(map(obj, sect) < 0)
+		goto bad;
+	for(i=0; i<obj->nsect; i++)
+		if(obj->sect[i].name != nil)
+			obj->sect[i].name = (char*)sect->base + (uintptr)obj->sect[i].name;
+	
+	// load string table for symbols into memory.
+	obj->symtab = section(obj, ".symtab");
+	if(obj->symtab == nil) {
+		// our work is done here - no symbols means nothing can refer to this file
+		return;
+	}
+	if(obj->symtab->link <= 0 || obj->symtab->link >= obj->nsect) {
+		diag("%s: elf object has symbol table with invalid string table link", pn);
+		return;
+	}
+	obj->symstr = &obj->sect[obj->symtab->link];
+	if(is64)
+		obj->nsymtab = obj->symtab->size / sizeof(ElfSymBytes64);
+	else
+		obj->nsymtab = obj->symtab->size / sizeof(ElfSymBytes);
+	
+	if(map(obj, obj->symtab) < 0)
+		goto bad;
+	if(map(obj, obj->symstr) < 0)
+		goto bad;
+
+	// load text and data segments into memory.
+	// they are not as small as the section lists, but we'll need
+	// the memory anyway for the symbol images, so we might
+	// as well use one large chunk.
+	
+	// create symbols for mapped sections
+	for(i=0; i<obj->nsect; i++) {
+		sect = &obj->sect[i];
+		if((sect->type != ElfSectProgbits && sect->type != ElfSectNobits) || !(sect->flags&ElfSectFlagAlloc))
+			continue;
+		if(sect->type != ElfSectNobits && map(obj, sect) < 0)
+			goto bad;
+		
+		name = smprint("%s(%s)", pkg, sect->name);
+		s = linklookup(ctxt, name, ctxt->version);
+		free(name);
+		switch((int)sect->flags&(ElfSectFlagAlloc|ElfSectFlagWrite|ElfSectFlagExec)) {
+		default:
+			werrstr("unexpected flags for ELF section %s", sect->name);
+			goto bad;
+		case ElfSectFlagAlloc:
+			s->type = SRODATA;
+			break;
+		case ElfSectFlagAlloc + ElfSectFlagWrite:
+			if(sect->type == ElfSectNobits)
+				s->type = SNOPTRBSS;
+			else
+				s->type = SNOPTRDATA;
+			break;
+		case ElfSectFlagAlloc + ElfSectFlagExec:
+			s->type = STEXT;
+			break;
+		}
+		if(sect->type == ElfSectProgbits) {
+			s->p = sect->base;
+			s->np = sect->size;
+		}
+		s->size = sect->size;
+		s->align = sect->align;
+		sect->sym = s;
+	}
+
+	// enter sub-symbols into symbol table.
+	// symbol 0 is the null symbol.
+	symbols = malloc(obj->nsymtab * sizeof(symbols[0]));
+	if(symbols == nil) {
+		diag("out of memory");
+		errorexit();
+	}
+	for(i=1; i<obj->nsymtab; i++) {
+		if(readsym(obj, i, &sym, 1) < 0)
+			goto bad;
+		symbols[i] = sym.sym;
+		if(sym.type != ElfSymTypeFunc && sym.type != ElfSymTypeObject && sym.type != ElfSymTypeNone)
+			continue;
+		if(sym.shndx == ElfSymShnCommon) {
+			s = sym.sym;
+			if(s->size < sym.size)
+				s->size = sym.size;
+			if(s->type == 0 || s->type == SXREF)
+				s->type = SNOPTRBSS;
+			continue;
+		}
+		if(sym.shndx >= obj->nsect || sym.shndx == 0)
+			continue;
+		// even when we pass needSym == 1 to readsym, it might still return nil to skip some unwanted symbols
+		if(sym.sym == S)
+			continue;
+		sect = obj->sect+sym.shndx;
+		if(sect->sym == nil) {
+			if(strncmp(sym.name, ".Linfo_string", 13) == 0) // clang does this
+				continue;
+			diag("%s: sym#%d: ignoring %s in section %d (type %d)", pn, i, sym.name, sym.shndx, sym.type);
+			continue;
+		}
+		s = sym.sym;
+		if(s->outer != S) {
+			if(s->dupok)
+				continue;
+			diag("%s: duplicate symbol reference: %s in both %s and %s", pn, s->name, s->outer->name, sect->sym->name);
+			errorexit();
+		}
+		s->sub = sect->sym->sub;
+		sect->sym->sub = s;
+		s->type = sect->sym->type | (s->type&~SMASK) | SSUB;
+		if(!(s->cgoexport & CgoExportDynamic))
+			s->dynimplib = nil;  // satisfy dynimport
+		s->value = sym.value;
+		s->size = sym.size;
+		s->outer = sect->sym;
+		if(sect->sym->type == STEXT) {
+			if(s->external && !s->dupok)
+					diag("%s: duplicate definition of %s", pn, s->name);
+			s->external = 1;
+		}
+	}
+	
+	// Sort outer lists by address, adding to textp.
+	// This keeps textp in increasing address order.
+	for(i=0; i<obj->nsect; i++) {
+		s = obj->sect[i].sym;
+		if(s == S)
+			continue;
+		if(s->sub)
+			s->sub = listsort(s->sub, valuecmp, offsetof(LSym, sub));
+		if(s->type == STEXT) {
+			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;
+			for(s = s->sub; s != S; s = s->sub) {
+				if(s->onlist)
+					sysfatal("symbol %s listed multiple times", s->name);
+				s->onlist = 1;
+				ctxt->etextp->next = s;
+				ctxt->etextp = s;
+			}
+		}
+	}
+
+	// load relocations
+	for(i=0; i<obj->nsect; i++) {
+		rsect = &obj->sect[i];
+		if(rsect->type != ElfSectRela && rsect->type != ElfSectRel)
+			continue;
+		if(rsect->info >= obj->nsect || obj->sect[rsect->info].base == nil)
+			continue;
+		sect = &obj->sect[rsect->info];
+		if(map(obj, rsect) < 0)
+			goto bad;
+		rela = rsect->type == ElfSectRela;
+		n = rsect->size/(4+4*is64)/(2+rela);
+		r = mal(n*sizeof r[0]);
+		p = rsect->base;
+		for(j=0; j<n; j++) {
+			add = 0;
+			rp = &r[j];
+			if(is64) {
+				// 64-bit rel/rela
+				rp->off = e->e64(p);
+				p += 8;
+				info = e->e64(p);
+				p += 8;
+				if(rela) {
+					add = e->e64(p);
+					p += 8;
+				}
+			} else {
+				// 32-bit rel/rela
+				rp->off = e->e32(p);
+				p += 4;
+				info = e->e32(p);
+				info = info>>8<<32 | (info&0xff);	// convert to 64-bit info
+				p += 4;
+				if(rela) {
+					add = e->e32(p);
+					p += 4;
+				}
+			}
+			if((info & 0xffffffff) == 0) { // skip R_*_NONE relocation
+				j--;
+				n--;
+				continue;
+			}
+			if((info >> 32) == 0) { // absolute relocation, don't bother reading the null symbol
+				rp->sym = S;
+			} else {
+				if(readsym(obj, info>>32, &sym, 0) < 0)
+					goto bad;
+				sym.sym = symbols[info>>32];
+				if(sym.sym == nil) {
+					werrstr("%s#%d: reloc of invalid sym #%d %s shndx=%d type=%d",
+						sect->sym->name, j, (int)(info>>32), sym.name, sym.shndx, sym.type);
+					goto bad;
+				}
+				rp->sym = sym.sym;
+			}
+			rp->type = reltype(pn, (uint32)info, &rp->siz);
+			if(rela)
+				rp->add = add;
+			else {
+				// load addend from image
+				if(rp->siz == 4)
+					rp->add = e->e32(sect->base+rp->off);
+				else if(rp->siz == 8)
+					rp->add = e->e64(sect->base+rp->off);
+				else
+					diag("invalid rela size %d", rp->siz);
+			}
+			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
+		
+		s = sect->sym;
+		s->r = r;
+		s->nr = n;
+	}
+	free(symbols);
+
+	return;
+
+bad:
+	diag("%s: malformed elf file: %r", pn);
+	free(symbols);
+}
+
+static ElfSect*
+section(ElfObj *obj, char *name)
+{
+	int i;
+	
+	for(i=0; i<obj->nsect; i++)
+		if(obj->sect[i].name && name && strcmp(obj->sect[i].name, name) == 0)
+			return &obj->sect[i];
+	return nil;
+}
+
+static int
+map(ElfObj *obj, ElfSect *sect)
+{
+	if(sect->base != nil)
+		return 0;
+
+	if(sect->off+sect->size > obj->len) {
+		werrstr("elf section past end of file");
+		return -1;
+	}
+
+	sect->base = mal(sect->size);
+	werrstr("short read");
+	if(Bseek(obj->f, obj->base+sect->off, 0) < 0 || Bread(obj->f, sect->base, sect->size) != sect->size)
+		return -1;
+	
+	return 0;
+}
+
+static int
+readsym(ElfObj *obj, int i, ElfSym *sym, int needSym)
+{
+	LSym *s;
+
+	if(i >= obj->nsymtab || i < 0) {
+		werrstr("invalid elf symbol index");
+		return -1;
+	}
+	if(i == 0) {
+		diag("readym: read null symbol!");
+	}
+
+	if(obj->is64) {
+		ElfSymBytes64 *b;
+		
+		b = (ElfSymBytes64*)(obj->symtab->base + i*sizeof *b);
+		sym->name = (char*)obj->symstr->base + obj->e->e32(b->name);
+		sym->value = obj->e->e64(b->value);
+		sym->size = obj->e->e64(b->size);
+		sym->shndx = obj->e->e16(b->shndx);
+		sym->bind = b->info>>4;
+		sym->type = b->info&0xf;
+		sym->other = b->other;
+	} else {
+		ElfSymBytes *b;
+		
+		b = (ElfSymBytes*)(obj->symtab->base + i*sizeof *b);
+		sym->name = (char*)obj->symstr->base + obj->e->e32(b->name);
+		sym->value = obj->e->e32(b->value);
+		sym->size = obj->e->e32(b->size);
+		sym->shndx = obj->e->e16(b->shndx);
+		sym->bind = b->info>>4;
+		sym->type = b->info&0xf;
+		sym->other = b->other;
+	}
+
+	s = nil;
+	if(strcmp(sym->name, "_GLOBAL_OFFSET_TABLE_") == 0)
+		sym->name = ".got";
+	switch(sym->type) {
+	case ElfSymTypeSection:
+		s = obj->sect[sym->shndx].sym;
+		break;
+	case ElfSymTypeObject:
+	case ElfSymTypeFunc:
+	case ElfSymTypeNone:
+		switch(sym->bind) {
+		case ElfSymBindGlobal:
+			if(needSym) {
+				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
+				// workaround that we set dupok.
+				// TODO(minux): correctly handle __i686.get_pc_thunk.bx without
+				// set dupok generally. See http://codereview.appspot.com/5823055/
+				// comment #5 for details.
+				if(s && sym->other == 2) {
+					s->type |= SHIDDEN;
+					s->dupok = 1;
+				}
+			}
+			break;
+		case ElfSymBindLocal:
+			if(!(thechar == '5' && (strncmp(sym->name, "$a", 2) == 0 || strncmp(sym->name, "$d", 2) == 0))) // binutils for arm generate these mapping symbols, ignore these
+				if(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 = linknewsym(ctxt, sym->name, ctxt->version);
+					s->type |= SHIDDEN;
+				}
+			break;
+		case ElfSymBindWeak:
+			if(needSym) {
+				s = linknewsym(ctxt, sym->name, 0);
+				if(sym->other == 2)
+					s->type |= SHIDDEN;
+			}
+			break;
+		default:
+			werrstr("%s: invalid symbol binding %d", sym->name, sym->bind);
+			return -1;
+		}
+		break;
+	}
+	if(s != nil && s->type == 0 && sym->type != ElfSymTypeSection)
+		s->type = SXREF;
+	sym->sym = s;
+
+	return 0;
+}
+
+int
+rbyoff(const void *va, const void *vb)
+{
+	Reloc *a, *b;
+	
+	a = (Reloc*)va;
+	b = (Reloc*)vb;
+	if(a->off < b->off)
+		return -1;
+	if(a->off > b->off)
+		return +1;
+	return 0;
+}
+
+#define R(x, y) ((x)|((y)<<24))
+
+static int
+reltype(char *pn, int elftype, uchar *siz)
+{
+	switch(R(thechar, elftype)) {
+	default:
+		diag("%s: unknown relocation type %d; compiled without -fpic?", pn, elftype);
+	case R('5', R_ARM_ABS32):
+	case R('5', R_ARM_GOT32):
+	case R('5', R_ARM_PLT32):
+	case R('5', R_ARM_GOTOFF):
+	case R('5', R_ARM_GOTPC):
+	case R('5', R_ARM_THM_PC22):
+	case R('5', R_ARM_REL32):
+	case R('5', R_ARM_CALL):
+	case R('5', R_ARM_V4BX):
+	case R('5', R_ARM_GOT_PREL):
+	case R('5', R_ARM_PC24):
+	case R('5', R_ARM_JUMP24):
+	case R('6', R_X86_64_PC32):
+	case R('6', R_X86_64_PLT32):
+	case R('6', R_X86_64_GOTPCREL):
+	case R('8', R_386_32):
+	case R('8', R_386_PC32):
+	case R('8', R_386_GOT32):
+	case R('8', R_386_PLT32):
+	case R('8', R_386_GOTOFF):
+	case R('8', R_386_GOTPC):
+		*siz = 4;
+		break;
+	case R('6', R_X86_64_64):
+		*siz = 8;
+		break;
+	}
+
+	return 256+elftype;
+}
diff --git a/src/cmd/ld/ldmacho.c b/src/cmd/ld/ldmacho.c
new file mode 100644
index 0000000..71cfa63
--- /dev/null
+++ b/src/cmd/ld/ldmacho.c
@@ -0,0 +1,850 @@
+/*
+Derived from Plan 9 from User Space's src/libmach/elf.h, elf.c
+http://code.swtch.com/plan9port/src/tip/src/libmach/
+
+	Copyright © 2004 Russ Cox.
+	Portions Copyright © 2008-2010 Google Inc.
+	Portions Copyright © 2010 The Go Authors.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include	"l.h"
+#include	"lib.h"
+
+enum {
+	MACHO_FAKE_GOTPCREL = 100,	// from macho.h
+	
+	N_EXT = 0x01,
+	N_TYPE = 0x1e,
+	N_STAB = 0xe0,
+};
+
+typedef struct MachoObj MachoObj;
+typedef struct MachoCmd MachoCmd;
+typedef struct MachoSeg MachoSeg;
+typedef struct MachoSect MachoSect;
+typedef struct MachoRel MachoRel;
+typedef struct MachoSymtab MachoSymtab;
+typedef struct MachoSym MachoSym;
+typedef struct MachoDysymtab MachoDysymtab;
+
+enum
+{
+	MachoCpuVax = 1,
+	MachoCpu68000 = 6,
+	MachoCpu386 = 7,
+	MachoCpuAmd64 = 0x1000007,
+	MachoCpuMips = 8,
+	MachoCpu98000 = 10,
+	MachoCpuHppa = 11,
+	MachoCpuArm = 12,
+	MachoCpu88000 = 13,
+	MachoCpuSparc = 14,
+	MachoCpu860 = 15,
+	MachoCpuAlpha = 16,
+	MachoCpuPower = 18,
+
+	MachoCmdSegment = 1,
+	MachoCmdSymtab = 2,
+	MachoCmdSymseg = 3,
+	MachoCmdThread = 4,
+	MachoCmdDysymtab = 11,
+	MachoCmdSegment64 = 25,
+
+	MachoFileObject = 1,
+	MachoFileExecutable = 2,
+	MachoFileFvmlib = 3,
+	MachoFileCore = 4,
+	MachoFilePreload = 5,
+};
+
+struct MachoSeg
+{
+	char name[16+1];
+	uint64 vmaddr;
+	uint64 vmsize;
+	uint32 fileoff;
+	uint32 filesz;
+	uint32 maxprot;
+	uint32 initprot;
+	uint32 nsect;
+	uint32 flags;
+	MachoSect *sect;
+};
+
+struct MachoSect
+{
+	char	name[16+1];
+	char	segname[16+1];
+	uint64 addr;
+	uint64 size;
+	uint32 off;
+	uint32 align;
+	uint32 reloff;
+	uint32 nreloc;
+	uint32 flags;
+	uint32 res1;
+	uint32 res2;
+	LSym *sym;
+	
+	MachoRel *rel;
+};
+
+struct MachoRel
+{
+	uint32 addr;
+	uint32 symnum;
+	uint8 pcrel;
+	uint8 length;
+	uint8 extrn;
+	uint8 type;
+	uint8 scattered;
+	uint32 value;
+};
+
+struct MachoSymtab
+{
+	uint32 symoff;
+	uint32 nsym;
+	uint32 stroff;
+	uint32 strsize;
+	
+	char *str;
+	MachoSym *sym;
+};
+
+struct MachoSym
+{
+	char *name;
+	uint8 type;
+	uint8 sectnum;
+	uint16 desc;
+	char kind;
+	uint64 value;
+	LSym *sym;
+};
+
+struct MachoDysymtab
+{
+	uint32 ilocalsym;
+	uint32 nlocalsym;
+	uint32 iextdefsym;
+	uint32 nextdefsym;
+	uint32 iundefsym;
+	uint32 nundefsym;
+	uint32 tocoff;
+	uint32 ntoc;
+	uint32 modtaboff;
+	uint32 nmodtab;
+	uint32 extrefsymoff;
+	uint32 nextrefsyms;
+	uint32 indirectsymoff;
+	uint32 nindirectsyms;
+	uint32 extreloff;
+	uint32 nextrel;
+	uint32 locreloff;
+	uint32 nlocrel;
+	uint32 *indir;
+};
+
+struct MachoCmd
+{
+	int type;
+	uint32 off;
+	uint32 size;
+	MachoSeg seg;
+	MachoSymtab sym;
+	MachoDysymtab dsym;
+};
+
+struct MachoObj
+{
+	Biobuf	*f;
+	int64	base;	// off in f where Mach-O begins
+	int64	len;		// length of Mach-O
+	int is64;
+	char	*name;
+
+	Endian	*e;
+	uint cputype;
+	uint subcputype;
+	uint32 filetype;
+	uint32 flags;
+	MachoCmd *cmd;
+	uint ncmd;
+};
+
+static int
+unpackcmd(uchar *p, MachoObj *m, MachoCmd *c, uint type, uint sz)
+{
+	uint32 (*e4)(uchar*);
+	uint64 (*e8)(uchar*);
+	MachoSect *s;
+	int i;
+
+	e4 = m->e->e32;
+	e8 = m->e->e64;
+
+	c->type = type;
+	c->size = sz;
+	switch(type){
+	default:
+		return -1;
+	case MachoCmdSegment:
+		if(sz < 56)
+			return -1;
+		strecpy(c->seg.name, c->seg.name+sizeof c->seg.name, (char*)p+8);
+		c->seg.vmaddr = e4(p+24);
+		c->seg.vmsize = e4(p+28);
+		c->seg.fileoff = e4(p+32);
+		c->seg.filesz = e4(p+36);
+		c->seg.maxprot = e4(p+40);
+		c->seg.initprot = e4(p+44);
+		c->seg.nsect = e4(p+48);
+		c->seg.flags = e4(p+52);
+		c->seg.sect = mal(c->seg.nsect * sizeof c->seg.sect[0]);
+		if(sz < 56+c->seg.nsect*68)
+			return -1;
+		p += 56;
+		for(i=0; i<c->seg.nsect; i++) {
+			s = &c->seg.sect[i];
+			strecpy(s->name, s->name+sizeof s->name, (char*)p+0);
+			strecpy(s->segname, s->segname+sizeof s->segname, (char*)p+16);
+			s->addr = e4(p+32);
+			s->size = e4(p+36);
+			s->off = e4(p+40);
+			s->align = e4(p+44);
+			s->reloff = e4(p+48);
+			s->nreloc = e4(p+52);
+			s->flags = e4(p+56);
+			s->res1 = e4(p+60);
+			s->res2 = e4(p+64);
+			p += 68;
+		}
+		break;
+	case MachoCmdSegment64:
+		if(sz < 72)
+			return -1;
+		strecpy(c->seg.name, c->seg.name+sizeof c->seg.name, (char*)p+8);
+		c->seg.vmaddr = e8(p+24);
+		c->seg.vmsize = e8(p+32);
+		c->seg.fileoff = e8(p+40);
+		c->seg.filesz = e8(p+48);
+		c->seg.maxprot = e4(p+56);
+		c->seg.initprot = e4(p+60);
+		c->seg.nsect = e4(p+64);
+		c->seg.flags = e4(p+68);
+		c->seg.sect = mal(c->seg.nsect * sizeof c->seg.sect[0]);
+		if(sz < 72+c->seg.nsect*80)
+			return -1;
+		p += 72;
+		for(i=0; i<c->seg.nsect; i++) {
+			s = &c->seg.sect[i];
+			strecpy(s->name, s->name+sizeof s->name, (char*)p+0);
+			strecpy(s->segname, s->segname+sizeof s->segname, (char*)p+16);
+			s->addr = e8(p+32);
+			s->size = e8(p+40);
+			s->off = e4(p+48);
+			s->align = e4(p+52);
+			s->reloff = e4(p+56);
+			s->nreloc = e4(p+60);
+			s->flags = e4(p+64);
+			s->res1 = e4(p+68);
+			s->res2 = e4(p+72);
+			// p+76 is reserved
+			p += 80;
+		}
+		break;
+	case MachoCmdSymtab:
+		if(sz < 24)
+			return -1;
+		c->sym.symoff = e4(p+8);
+		c->sym.nsym = e4(p+12);
+		c->sym.stroff = e4(p+16);
+		c->sym.strsize = e4(p+20);
+		break;
+	case MachoCmdDysymtab:
+		if(sz < 80)
+			return -1;
+		c->dsym.ilocalsym = e4(p+8);
+		c->dsym.nlocalsym = e4(p+12);
+		c->dsym.iextdefsym = e4(p+16);
+		c->dsym.nextdefsym = e4(p+20);
+		c->dsym.iundefsym = e4(p+24);
+		c->dsym.nundefsym = e4(p+28);
+		c->dsym.tocoff = e4(p+32);
+		c->dsym.ntoc = e4(p+36);
+		c->dsym.modtaboff = e4(p+40);
+		c->dsym.nmodtab = e4(p+44);
+		c->dsym.extrefsymoff = e4(p+48);
+		c->dsym.nextrefsyms = e4(p+52);
+		c->dsym.indirectsymoff = e4(p+56);
+		c->dsym.nindirectsyms = e4(p+60);
+		c->dsym.extreloff = e4(p+64);
+		c->dsym.nextrel = e4(p+68);
+		c->dsym.locreloff = e4(p+72);
+		c->dsym.nlocrel = e4(p+76);
+		break;
+	}
+	return 0;
+}
+
+static int
+macholoadrel(MachoObj *m, MachoSect *sect)
+{
+	MachoRel *rel, *r;
+	uchar *buf, *p;
+	int i, n;
+	uint32 v;
+	
+	if(sect->rel != nil || sect->nreloc == 0)
+		return 0;
+	rel = mal(sect->nreloc * sizeof r[0]);
+	n = sect->nreloc * 8;
+	buf = mal(n);
+	if(Bseek(m->f, m->base + sect->reloff, 0) < 0 || Bread(m->f, buf, n) != n)
+		return -1;
+	for(i=0; i<sect->nreloc; i++) {
+		r = &rel[i];
+		p = buf+i*8;
+		r->addr = m->e->e32(p);
+		
+		// TODO(rsc): Wrong interpretation for big-endian bitfields?
+		if(r->addr & 0x80000000) {
+			// scatterbrained relocation
+			r->scattered = 1;
+			v = r->addr >> 24;
+			r->addr &= 0xFFFFFF;
+			r->type = v & 0xF;
+			v >>= 4;
+			r->length = 1<<(v&3);
+			v >>= 2;
+			r->pcrel = v & 1;
+			r->value = m->e->e32(p+4);
+		} else {
+			v = m->e->e32(p+4);
+			r->symnum = v & 0xFFFFFF;
+			v >>= 24;
+			r->pcrel = v&1;
+			v >>= 1;
+			r->length = 1<<(v&3);
+			v >>= 2;
+			r->extrn = v&1;
+			v >>= 1;
+			r->type = v;
+		}
+	}
+	sect->rel = rel;
+	return 0;
+}
+
+static int
+macholoaddsym(MachoObj *m, MachoDysymtab *d)
+{
+	uchar *p;
+	int i, n;
+	
+	n = d->nindirectsyms;
+	
+	p = mal(n*4);
+	if(Bseek(m->f, m->base + d->indirectsymoff, 0) < 0 || Bread(m->f, p, n*4) != n*4)
+		return -1;
+	
+	d->indir = (uint32*)p;
+	for(i=0; i<n; i++)
+		d->indir[i] = m->e->e32(p+4*i);
+	return 0;
+}
+
+static int 
+macholoadsym(MachoObj *m, MachoSymtab *symtab)
+{
+	char *strbuf;
+	uchar *symbuf, *p;
+	int i, n, symsize;
+	MachoSym *sym, *s;
+	uint32 v;
+
+	if(symtab->sym != nil)
+		return 0;
+
+	strbuf = mal(symtab->strsize);
+	if(Bseek(m->f, m->base + symtab->stroff, 0) < 0 || Bread(m->f, strbuf, symtab->strsize) != symtab->strsize)
+		return -1;
+	
+	symsize = 12;
+	if(m->is64)
+		symsize = 16;
+	n = symtab->nsym * symsize;
+	symbuf = mal(n);
+	if(Bseek(m->f, m->base + symtab->symoff, 0) < 0 || Bread(m->f, symbuf, n) != n)
+		return -1;
+	sym = mal(symtab->nsym * sizeof sym[0]);
+	p = symbuf;
+	for(i=0; i<symtab->nsym; i++) {
+		s = &sym[i];
+		v = m->e->e32(p);
+		if(v >= symtab->strsize)
+			return -1;
+		s->name = strbuf + v;
+		s->type = p[4];
+		s->sectnum = p[5];
+		s->desc = m->e->e16(p+6);
+		if(m->is64)
+			s->value = m->e->e64(p+8);
+		else
+			s->value = m->e->e32(p+8);
+		p += symsize;
+	}
+	symtab->str = strbuf;
+	symtab->sym = sym;
+	return 0;
+}
+
+void
+ldmacho(Biobuf *f, char *pkg, int64 len, char *pn)
+{
+	int i, j, is64;
+	uint64 secaddr;
+	uchar hdr[7*4], *cmdp;
+	uchar tmp[4];
+	uchar *dat;
+	ulong ncmd, cmdsz, ty, sz, off;
+	MachoObj *m;
+	Endian *e;
+	int64 base;
+	MachoSect *sect;
+	MachoRel *rel;
+	LSym *s, *s1, *outer;
+	MachoCmd *c;
+	MachoSymtab *symtab;
+	MachoDysymtab *dsymtab;
+	MachoSym *sym;
+	Reloc *r, *rp;
+	char *name;
+
+	ctxt->version++;
+	base = Boffset(f);
+	if(Bread(f, hdr, sizeof hdr) != sizeof hdr)
+		goto bad;
+
+	if((be.e32(hdr)&~1) == 0xFEEDFACE){
+		e = &be;
+	}else if((le.e32(hdr)&~1) == 0xFEEDFACE){
+		e = ≤
+	}else{
+		werrstr("bad magic - not mach-o file");
+		goto bad;
+	}
+
+	is64 = e->e32(hdr) == 0xFEEDFACF;
+	ncmd = e->e32(hdr+4*4);
+	cmdsz = e->e32(hdr+5*4);
+	if(ncmd > 0x10000 || cmdsz >= 0x01000000){
+		werrstr("implausible mach-o header ncmd=%lud cmdsz=%lud", ncmd, cmdsz);
+		goto bad;
+	}
+	if(is64)
+		Bread(f, tmp, 4);	// skip reserved word in header
+
+	m = mal(sizeof(*m)+ncmd*sizeof(MachoCmd)+cmdsz);
+	m->f = f;
+	m->e = e;
+	m->cputype = e->e32(hdr+1*4);
+	m->subcputype = e->e32(hdr+2*4);
+	m->filetype = e->e32(hdr+3*4);
+	m->ncmd = ncmd;
+	m->flags = e->e32(hdr+6*4);
+	m->is64 = is64;
+	m->base = base;
+	m->len = len;
+	m->name = pn;
+	
+	switch(thechar) {
+	default:
+		diag("%s: mach-o %s unimplemented", pn, thestring);
+		return;
+	case '6':
+		if(e != &le || m->cputype != MachoCpuAmd64) {
+			diag("%s: mach-o object but not amd64", pn);
+			return;
+		}
+		break;
+	case '8':
+		if(e != &le || m->cputype != MachoCpu386) {
+			diag("%s: mach-o object but not 386", pn);
+			return;
+		}
+		break;
+	}
+
+	m->cmd = (MachoCmd*)(m+1);
+	off = sizeof hdr;
+	cmdp = (uchar*)(m->cmd+ncmd);
+	if(Bread(f, cmdp, cmdsz) != cmdsz){
+		werrstr("reading cmds: %r");
+		goto bad;
+	}
+
+	// read and parse load commands
+	c = nil;
+	symtab = nil;
+	dsymtab = nil;
+	USED(dsymtab);
+	for(i=0; i<ncmd; i++){
+		ty = e->e32(cmdp);
+		sz = e->e32(cmdp+4);
+		m->cmd[i].off = off;
+		unpackcmd(cmdp, m, &m->cmd[i], ty, sz);
+		cmdp += sz;
+		off += sz;
+		if(ty == MachoCmdSymtab) {
+			if(symtab != nil) {
+				werrstr("multiple symbol tables");
+				goto bad;
+			}
+			symtab = &m->cmd[i].sym;
+			macholoadsym(m, symtab);
+		}
+		if(ty == MachoCmdDysymtab) {
+			dsymtab = &m->cmd[i].dsym;
+			macholoaddsym(m, dsymtab);
+		}
+		if((is64 && ty == MachoCmdSegment64) || (!is64 && ty == MachoCmdSegment)) {
+			if(c != nil) {
+				werrstr("multiple load commands");
+				goto bad;
+			}
+			c = &m->cmd[i];
+		}
+	}
+
+	// load text and data segments into memory.
+	// they are not as small as the load commands, but we'll need
+	// the memory anyway for the symbol images, so we might
+	// as well use one large chunk.
+	if(c == nil) {
+		werrstr("no load command");
+		goto bad;
+	}
+	if(symtab == nil) {
+		// our work is done here - no symbols means nothing can refer to this file
+		return;
+	}
+
+	if(c->seg.fileoff+c->seg.filesz >= len) {
+		werrstr("load segment out of range");
+		goto bad;
+	}
+
+	dat = mal(c->seg.filesz);
+	if(Bseek(f, m->base + c->seg.fileoff, 0) < 0 || Bread(f, dat, c->seg.filesz) != c->seg.filesz) {
+		werrstr("cannot load object data: %r");
+		goto bad;
+	}
+	
+	for(i=0; i<c->seg.nsect; i++) {
+		sect = &c->seg.sect[i];
+		if(strcmp(sect->segname, "__TEXT") != 0 && strcmp(sect->segname, "__DATA") != 0)
+			continue;
+		if(strcmp(sect->name, "__eh_frame") == 0)
+			continue;
+		name = smprint("%s(%s/%s)", pkg, sect->segname, sect->name);
+		s = linklookup(ctxt, name, ctxt->version);
+		if(s->type != 0) {
+			werrstr("duplicate %s/%s", sect->segname, sect->name);
+			goto bad;
+		}
+		free(name);
+
+		s->np = sect->size;
+		s->size = s->np;
+		if((sect->flags & 0xff) == 1) // S_ZEROFILL
+			s->p = mal(s->size);
+		else {
+			s->p = dat + sect->addr - c->seg.vmaddr;
+		}
+		
+		if(strcmp(sect->segname, "__TEXT") == 0) {
+			if(strcmp(sect->name, "__text") == 0)
+				s->type = STEXT;
+			else
+				s->type = SRODATA;
+		} else {
+			if (strcmp(sect->name, "__bss") == 0) {
+				s->type = SNOPTRBSS;
+				s->np = 0;
+			} else
+				s->type = SNOPTRDATA;
+		}
+		sect->sym = s;
+	}
+	
+	// enter sub-symbols into symbol table.
+	// have to guess sizes from next symbol.
+	for(i=0; i<symtab->nsym; i++) {
+		int v;
+		sym = &symtab->sym[i];
+		if(sym->type&N_STAB)
+			continue;
+		// TODO: check sym->type against outer->type.
+		name = sym->name;
+		if(name[0] == '_' && name[1] != '\0')
+			name++;
+		v = 0;
+		if(!(sym->type&N_EXT))
+			v = ctxt->version;
+		s = linklookup(ctxt, name, v);
+		if(!(sym->type&N_EXT))
+			s->dupok = 1;
+		sym->sym = s;
+		if(sym->sectnum == 0)	// undefined
+			continue;
+		if(sym->sectnum > c->seg.nsect) {
+			werrstr("reference to invalid section %d", sym->sectnum);
+			goto bad;
+		}
+		sect = &c->seg.sect[sym->sectnum-1];
+		outer = sect->sym;
+		if(outer == nil) {
+			werrstr("reference to invalid section %s/%s", sect->segname, sect->name);
+			continue;
+		}
+		if(s->outer != S) {
+			if(s->dupok)
+				continue;
+			diag("%s: duplicate symbol reference: %s in both %s and %s", pn, s->name, s->outer->name, sect->sym->name);
+			errorexit();
+		}
+		s->type = outer->type | SSUB;
+		s->sub = outer->sub;
+		outer->sub = s;
+		s->outer = outer;
+		s->value = sym->value - sect->addr;
+		if(!(s->cgoexport & CgoExportDynamic))
+			s->dynimplib = nil;	// satisfy dynimport
+		if(outer->type == STEXT) {
+			if(s->external && !s->dupok)
+				diag("%s: duplicate definition of %s", pn, s->name);
+			s->external = 1;
+		}
+		sym->sym = s;
+	}
+
+	// Sort outer lists by address, adding to textp.
+	// This keeps textp in increasing address order.
+	for(i=0; i<c->seg.nsect; i++) {
+		sect = &c->seg.sect[i];
+		if((s = sect->sym) == S)
+			continue;
+		if(s->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) {
+				if(s1->sub)
+					s1->size = s1->sub->value - s1->value;
+				else
+					s1->size = s->value + s->size - s1->value;
+			}
+		}
+		if(s->type == STEXT) {
+			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;
+			for(s1 = s->sub; s1 != S; s1 = s1->sub) {
+				if(s1->onlist)
+					sysfatal("symbol %s listed multiple times", s1->name);
+				s1->onlist = 1;
+				ctxt->etextp->next = s1;
+				ctxt->etextp = s1;
+			}
+		}
+	}
+
+	// load relocations
+	for(i=0; i<c->seg.nsect; i++) {
+		sect = &c->seg.sect[i];
+		if((s = sect->sym) == S)
+			continue;
+		macholoadrel(m, sect);
+		if(sect->rel == nil)
+			continue;
+		r = mal(sect->nreloc*sizeof r[0]);
+		rp = r;
+		rel = sect->rel;
+		for(j=0; j<sect->nreloc; j++, rel++) {
+			if(rel->scattered) {
+				int k;
+				MachoSect *ks;
+
+				if(thechar != '8') {
+					// mach-o only uses scattered relocation on 32-bit platforms
+					diag("unexpected scattered relocation");
+					continue;
+				}
+
+				// on 386, rewrite scattered 4/1 relocation and some
+				// scattered 2/1 relocation into the pseudo-pc-relative
+				// reference that it is.
+				// assume that the second in the pair is in this section
+				// and use that as the pc-relative base.
+				if(j+1 >= sect->nreloc) {
+					werrstr("unsupported scattered relocation %d", (int)rel->type);
+					goto bad;
+				}
+				if(!(rel+1)->scattered || (rel+1)->type != 1 ||
+				   (rel->type != 4 && rel->type != 2) ||
+				   (rel+1)->value < sect->addr || (rel+1)->value >= sect->addr+sect->size) {
+					werrstr("unsupported scattered relocation %d/%d", (int)rel->type, (int)(rel+1)->type);
+					goto bad;
+				}
+
+				rp->siz = rel->length;
+				rp->off = rel->addr;
+				
+				// NOTE(rsc): I haven't worked out why (really when)
+				// we should ignore the addend on a
+				// scattered relocation, but it seems that the
+				// common case is we ignore it.
+				// It's likely that this is not strictly correct
+				// and that the math should look something
+				// like the non-scattered case below.
+				rp->add = 0;
+				
+				// want to make it pc-relative aka relative to rp->off+4
+				// but the scatter asks for relative to off = (rel+1)->value - sect->addr.
+				// adjust rp->add accordingly.
+				rp->type = R_PCREL;
+				rp->add += (rp->off+4) - ((rel+1)->value - sect->addr);
+				
+				// now consider the desired symbol.
+				// find the section where it lives.
+				for(k=0; k<c->seg.nsect; k++) {
+					ks = &c->seg.sect[k];
+					if(ks->addr <= rel->value && rel->value < ks->addr+ks->size)
+						goto foundk;
+				}
+				werrstr("unsupported scattered relocation: invalid address %#ux", rel->addr);
+				goto bad;
+			foundk:
+				if(ks->sym != S) {
+					rp->sym = ks->sym;
+					rp->add += rel->value - ks->addr;
+				} else if(strcmp(ks->segname, "__IMPORT") == 0 && strcmp(ks->name, "__pointers") == 0) {
+					// handle reference to __IMPORT/__pointers.
+					// how much worse can this get?
+					// why are we supporting 386 on the mac anyway?
+					rp->type = 512 + MACHO_FAKE_GOTPCREL;
+					// figure out which pointer this is a reference to.
+					k = ks->res1 + (rel->value - ks->addr) / 4;
+					// load indirect table for __pointers
+					// fetch symbol number
+					if(dsymtab == nil || k < 0 || k >= dsymtab->nindirectsyms || dsymtab->indir == nil) {
+						werrstr("invalid scattered relocation: indirect symbol reference out of range");
+						goto bad;
+					}
+					k = dsymtab->indir[k];
+					if(k < 0 || k >= symtab->nsym) {
+						werrstr("invalid scattered relocation: symbol reference out of range");
+						goto bad;
+					}
+					rp->sym = symtab->sym[k].sym;
+				} else {
+					werrstr("unsupported scattered relocation: reference to %s/%s", ks->segname, ks->name);
+					goto bad;
+				}
+				rp++;
+				// skip #1 of 2 rel; continue skips #2 of 2.
+				rel++;
+				j++;
+				continue;
+			}
+
+			rp->siz = rel->length;
+			rp->type = 512 + (rel->type<<1) + rel->pcrel;
+			rp->off = rel->addr;
+
+			// Handle X86_64_RELOC_SIGNED referencing a section (rel->extrn == 0).
+			if (thechar == '6' && rel->extrn == 0 && rel->type == 1) {
+				// Calculate the addend as the offset into the section.
+				//
+				// The rip-relative offset stored in the object file is encoded
+				// as follows:
+				//    
+				//    movsd	0x00000360(%rip),%xmm0
+				//
+				// To get the absolute address of the value this rip-relative address is pointing
+				// to, we must add the address of the next instruction to it. This is done by
+				// taking the address of the relocation and adding 4 to it (since the rip-relative
+				// offset can at most be 32 bits long).  To calculate the offset into the section the
+				// relocation is referencing, we subtract the vaddr of the start of the referenced
+				// section found in the original object file.
+				//
+				// [For future reference, see Darwin's /usr/include/mach-o/x86_64/reloc.h]
+				secaddr = c->seg.sect[rel->symnum-1].addr;
+				rp->add = (int32)e->e32(s->p+rp->off) + rp->off + 4 - secaddr;
+			} else
+				rp->add = (int32)e->e32(s->p+rp->off);
+
+			// For i386 Mach-O PC-relative, the addend is written such that
+			// it *is* the PC being subtracted.  Use that to make
+			// it match our version of PC-relative.
+			if(rel->pcrel && thechar == '8')
+				rp->add += rp->off+rp->siz;
+			if(!rel->extrn) {
+				if(rel->symnum < 1 || rel->symnum > c->seg.nsect) {
+					werrstr("invalid relocation: section reference out of range %d vs %d", rel->symnum, c->seg.nsect);
+					goto bad;
+				}
+				rp->sym = c->seg.sect[rel->symnum-1].sym;
+				if(rp->sym == nil) {
+					werrstr("invalid relocation: %s", c->seg.sect[rel->symnum-1].name);
+					goto bad;
+				}
+				// References to symbols in other sections
+				// include that information in the addend.
+				// We only care about the delta from the 
+				// section base.
+				if(thechar == '8')
+					rp->add -= c->seg.sect[rel->symnum-1].addr;
+			} else {
+				if(rel->symnum >= symtab->nsym) {
+					werrstr("invalid relocation: symbol reference out of range");
+					goto bad;
+				}
+				rp->sym = symtab->sym[rel->symnum].sym;
+			}
+			rp++;
+		}			
+		qsort(r, rp - r, sizeof r[0], rbyoff);
+		s->r = r;
+		s->nr = rp - r;
+	}
+	return;
+
+bad:
+	diag("%s: malformed mach-o file: %r", pn);
+}
diff --git a/src/cmd/ld/ldpe.c b/src/cmd/ld/ldpe.c
new file mode 100644
index 0000000..4f5e51f
--- /dev/null
+++ b/src/cmd/ld/ldpe.c
@@ -0,0 +1,499 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include	"l.h"
+#include	"lib.h"
+#include	"../ld/pe.h"
+
+#define IMAGE_SCN_MEM_DISCARDABLE 0x2000000
+
+#define IMAGE_SYM_UNDEFINED	0
+#define IMAGE_SYM_ABSOLUTE (-1)
+#define IMAGE_SYM_DEBUG	(-2)
+#define IMAGE_SYM_TYPE_NULL 0
+#define IMAGE_SYM_TYPE_VOID 1
+#define IMAGE_SYM_TYPE_CHAR 2
+#define IMAGE_SYM_TYPE_SHORT 3
+#define IMAGE_SYM_TYPE_INT 4
+#define IMAGE_SYM_TYPE_LONG 5
+#define IMAGE_SYM_TYPE_FLOAT 6
+#define IMAGE_SYM_TYPE_DOUBLE 7
+#define IMAGE_SYM_TYPE_STRUCT 8
+#define IMAGE_SYM_TYPE_UNION 9
+#define IMAGE_SYM_TYPE_ENUM 10
+#define IMAGE_SYM_TYPE_MOE 11
+#define IMAGE_SYM_TYPE_BYTE 12
+#define IMAGE_SYM_TYPE_WORD 13
+#define IMAGE_SYM_TYPE_UINT 14
+#define IMAGE_SYM_TYPE_DWORD 15
+#define IMAGE_SYM_TYPE_PCODE 32768
+#define IMAGE_SYM_DTYPE_NULL 0
+#define IMAGE_SYM_DTYPE_POINTER 0x10
+#define IMAGE_SYM_DTYPE_FUNCTION 0x20
+#define IMAGE_SYM_DTYPE_ARRAY 0x30
+#define IMAGE_SYM_CLASS_END_OF_FUNCTION	(-1)
+#define IMAGE_SYM_CLASS_NULL 0
+#define IMAGE_SYM_CLASS_AUTOMATIC 1
+#define IMAGE_SYM_CLASS_EXTERNAL 2
+#define IMAGE_SYM_CLASS_STATIC 3
+#define IMAGE_SYM_CLASS_REGISTER 4
+#define IMAGE_SYM_CLASS_EXTERNAL_DEF 5
+#define IMAGE_SYM_CLASS_LABEL 6
+#define IMAGE_SYM_CLASS_UNDEFINED_LABEL 7
+#define IMAGE_SYM_CLASS_MEMBER_OF_STRUCT 8
+#define IMAGE_SYM_CLASS_ARGUMENT 9
+#define IMAGE_SYM_CLASS_STRUCT_TAG 10
+#define IMAGE_SYM_CLASS_MEMBER_OF_UNION 11
+#define IMAGE_SYM_CLASS_UNION_TAG 12
+#define IMAGE_SYM_CLASS_TYPE_DEFINITION 13
+#define IMAGE_SYM_CLASS_UNDEFINED_STATIC 14
+#define IMAGE_SYM_CLASS_ENUM_TAG 15
+#define IMAGE_SYM_CLASS_MEMBER_OF_ENUM 16
+#define IMAGE_SYM_CLASS_REGISTER_PARAM 17
+#define IMAGE_SYM_CLASS_BIT_FIELD 18
+#define IMAGE_SYM_CLASS_FAR_EXTERNAL 68 /* Not in PECOFF v8 spec */
+#define IMAGE_SYM_CLASS_BLOCK 100
+#define IMAGE_SYM_CLASS_FUNCTION 101
+#define IMAGE_SYM_CLASS_END_OF_STRUCT 102
+#define IMAGE_SYM_CLASS_FILE 103
+#define IMAGE_SYM_CLASS_SECTION 104
+#define IMAGE_SYM_CLASS_WEAK_EXTERNAL 105
+#define IMAGE_SYM_CLASS_CLR_TOKEN 107
+
+#define IMAGE_REL_I386_ABSOLUTE	0x0000
+#define IMAGE_REL_I386_DIR16	0x0001
+#define IMAGE_REL_I386_REL16	0x0002
+#define IMAGE_REL_I386_DIR32	0x0006
+#define IMAGE_REL_I386_DIR32NB	0x0007
+#define IMAGE_REL_I386_SEG12	0x0009
+#define IMAGE_REL_I386_SECTION	0x000A
+#define IMAGE_REL_I386_SECREL	0x000B
+#define IMAGE_REL_I386_TOKEN	0x000C
+#define IMAGE_REL_I386_SECREL7	0x000D
+#define IMAGE_REL_I386_REL32	0x0014
+
+#define IMAGE_REL_AMD64_ABSOLUTE 0x0000
+#define IMAGE_REL_AMD64_ADDR64 0x0001 // R_X86_64_64
+#define IMAGE_REL_AMD64_ADDR32 0x0002 // R_X86_64_PC32
+#define IMAGE_REL_AMD64_ADDR32NB 0x0003
+#define IMAGE_REL_AMD64_REL32 0x0004 
+#define IMAGE_REL_AMD64_REL32_1 0x0005
+#define IMAGE_REL_AMD64_REL32_2 0x0006
+#define IMAGE_REL_AMD64_REL32_3 0x0007
+#define IMAGE_REL_AMD64_REL32_4 0x0008
+#define IMAGE_REL_AMD64_REL32_5 0x0009
+#define IMAGE_REL_AMD64_SECTION 0x000A
+#define IMAGE_REL_AMD64_SECREL 0x000B
+#define IMAGE_REL_AMD64_SECREL7 0x000C
+#define IMAGE_REL_AMD64_TOKEN 0x000D
+#define IMAGE_REL_AMD64_SREL32 0x000E
+#define IMAGE_REL_AMD64_PAIR 0x000F
+#define IMAGE_REL_AMD64_SSPAN32 0x0010
+
+typedef struct PeSym PeSym;
+typedef struct PeSect PeSect;
+typedef struct PeObj PeObj;
+
+struct PeSym {
+	char* name;
+	uint32 value;
+	uint16 sectnum;
+	uint16 type;
+	uint8 sclass;
+	uint8 aux;
+	LSym* sym;
+};
+
+struct PeSect {
+	char* name;
+	uchar* base;
+	uint64 size;
+	LSym* sym;
+	IMAGE_SECTION_HEADER sh;
+};
+
+struct PeObj {
+	Biobuf	*f;
+	char	*name;
+	uint32 base;
+	
+	PeSect	*sect;
+	uint	nsect;
+	PeSym	*pesym;
+	uint npesym;
+	
+	IMAGE_FILE_HEADER fh;
+	char* snames;
+};
+
+static int map(PeObj *obj, PeSect *sect);
+static int issect(PeSym *s);
+static int readsym(PeObj *obj, int i, PeSym **sym);
+
+void
+ldpe(Biobuf *f, char *pkg, int64 len, char *pn)
+{
+	char *name;
+	int32 base;
+	uint32 l;
+	int i, j, numaux;
+	PeObj *obj;
+	PeSect *sect, *rsect;
+	IMAGE_SECTION_HEADER sh;
+	uchar symbuf[18];
+	LSym *s;
+	Reloc *r, *rp;
+	PeSym *sym;
+
+	USED(len);
+	if(debug['v'])
+		Bprint(&bso, "%5.2f ldpe %s\n", cputime(), pn);
+	
+	sect = nil;
+	ctxt->version++;
+	base = Boffset(f);
+	
+	obj = mal(sizeof *obj);
+	obj->f = f;
+	obj->base = base;
+	obj->name = pn;
+	// read header
+	if(Bread(f, &obj->fh, sizeof obj->fh) != sizeof obj->fh)
+		goto bad;
+	// load section list
+	obj->sect = mal(obj->fh.NumberOfSections*sizeof obj->sect[0]);
+	obj->nsect = obj->fh.NumberOfSections;
+	for(i=0; i < obj->fh.NumberOfSections; i++) {
+		if(Bread(f, &obj->sect[i].sh, sizeof sh) != sizeof sh)
+			goto bad;
+		obj->sect[i].size = obj->sect[i].sh.SizeOfRawData;
+		obj->sect[i].name = (char*)obj->sect[i].sh.Name;
+		// TODO return error if found .cormeta
+	}
+	// load string table
+	Bseek(f, base+obj->fh.PointerToSymbolTable+sizeof(symbuf)*obj->fh.NumberOfSymbols, 0);
+	if(Bread(f, symbuf, 4) != 4) 
+		goto bad;
+	l = le32(symbuf);
+	obj->snames = mal(l);
+	Bseek(f, base+obj->fh.PointerToSymbolTable+sizeof(symbuf)*obj->fh.NumberOfSymbols, 0);
+	if(Bread(f, obj->snames, l) != l)
+		goto bad;
+	// rewrite section names if they start with /
+	for(i=0; i < obj->fh.NumberOfSections; i++) {
+		if(obj->sect[i].name == nil)
+			continue;
+		if(obj->sect[i].name[0] != '/')
+			continue;
+		l = atoi(obj->sect[i].name + 1);
+		obj->sect[i].name = (char*)&obj->snames[l];
+	}
+	// read symbols
+	obj->pesym = mal(obj->fh.NumberOfSymbols*sizeof obj->pesym[0]);
+	obj->npesym = obj->fh.NumberOfSymbols;
+	Bseek(f, base+obj->fh.PointerToSymbolTable, 0);
+	for(i=0; i<obj->fh.NumberOfSymbols; i+=numaux+1) {
+		Bseek(f, base+obj->fh.PointerToSymbolTable+sizeof(symbuf)*i, 0);
+		if(Bread(f, symbuf, sizeof symbuf) != sizeof symbuf)
+			goto bad;
+		
+		if((symbuf[0] == 0) && (symbuf[1] == 0) &&
+			 (symbuf[2] == 0) && (symbuf[3] == 0)) {
+			l = le32(&symbuf[4]);
+			obj->pesym[i].name = (char*)&obj->snames[l];
+		} else { // sym name length <= 8
+			obj->pesym[i].name = mal(9);
+			strncpy(obj->pesym[i].name, (char*)symbuf, 8);
+			obj->pesym[i].name[8] = 0;
+		}
+		obj->pesym[i].value = le32(&symbuf[8]);
+		obj->pesym[i].sectnum = le16(&symbuf[12]);
+		obj->pesym[i].sclass = symbuf[16];
+		obj->pesym[i].aux = symbuf[17];
+		obj->pesym[i].type = le16(&symbuf[14]);
+		numaux = obj->pesym[i].aux; 
+		if (numaux < 0) 
+			numaux = 0;
+	}
+	// create symbols for mapped sections
+	for(i=0; i<obj->nsect; i++) {
+		sect = &obj->sect[i];
+		if(sect->sh.Characteristics&IMAGE_SCN_MEM_DISCARDABLE)
+			continue;
+
+		if((sect->sh.Characteristics&(IMAGE_SCN_CNT_CODE|IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_CNT_UNINITIALIZED_DATA)) == 0) {
+			// This has been seen for .idata sections, which we
+			// want to ignore.  See issues 5106 and 5273.
+			continue;
+		}
+
+		if(map(obj, sect) < 0)
+			goto bad;
+		
+		name = smprint("%s(%s)", pkg, sect->name);
+		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)) {
+			case IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_MEM_READ: //.rdata
+				s->type = SRODATA;
+				break;
+			case IMAGE_SCN_CNT_UNINITIALIZED_DATA|IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE: //.bss
+				s->type = SNOPTRBSS;
+				break;
+			case IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE: //.data
+				s->type = SNOPTRDATA;
+				break;
+			case IMAGE_SCN_CNT_CODE|IMAGE_SCN_MEM_EXECUTE|IMAGE_SCN_MEM_READ: //.text
+				s->type = STEXT;
+				break;
+			default:
+				werrstr("unexpected flags %#08ux for PE section %s", sect->sh.Characteristics, sect->name);
+				goto bad;
+		}
+		s->p = sect->base;
+		s->np = sect->size;
+		s->size = sect->size;
+		sect->sym = s;
+		if(strcmp(sect->name, ".rsrc") == 0)
+			setpersrc(sect->sym);
+	}
+	
+	// load relocations
+	for(i=0; i<obj->nsect; i++) {
+		rsect = &obj->sect[i];
+		if(rsect->sym == 0 || rsect->sh.NumberOfRelocations == 0)
+			continue;
+		if(rsect->sh.Characteristics&IMAGE_SCN_MEM_DISCARDABLE)
+			continue;
+		if((sect->sh.Characteristics&(IMAGE_SCN_CNT_CODE|IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_CNT_UNINITIALIZED_DATA)) == 0) {
+			// This has been seen for .idata sections, which we
+			// want to ignore.  See issues 5106 and 5273.
+			continue;
+		}
+		r = mal(rsect->sh.NumberOfRelocations*sizeof r[0]);
+		Bseek(f, obj->base+rsect->sh.PointerToRelocations, 0);
+		for(j=0; j<rsect->sh.NumberOfRelocations; j++) {
+			rp = &r[j];
+			if(Bread(f, symbuf, 10) != 10)
+				goto bad;
+			
+			uint32 rva, symindex;
+			uint16 type;
+			rva = le32(&symbuf[0]);
+			symindex = le32(&symbuf[4]);
+			type = le16(&symbuf[8]);
+			if(readsym(obj, symindex, &sym) < 0)
+				goto bad;
+			if(sym->sym == nil) {
+				werrstr("reloc of invalid sym %s idx=%d type=%d", sym->name, symindex, sym->type);
+				goto bad;
+			}
+			rp->sym = sym->sym;
+			rp->siz = 4;
+			rp->off = rva;
+			switch(type) {
+				default:
+					diag("%s: unknown relocation type %d;", pn, type);
+				case IMAGE_REL_I386_REL32:
+				case IMAGE_REL_AMD64_REL32:
+				case IMAGE_REL_AMD64_ADDR32: // R_X86_64_PC32
+				case IMAGE_REL_AMD64_ADDR32NB:
+					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 = R_ADDR;
+					// load addend from image
+					rp->add = (int32)le32(rsect->base+rp->off);
+					break;
+				case IMAGE_REL_AMD64_ADDR64: // R_X86_64_64
+					rp->siz = 8;
+					rp->type = R_ADDR;
+					// load addend from image
+					rp->add = le64(rsect->base+rp->off);
+					break;
+			}
+			// ld -r could generate multiple section symbols for the
+			// same section but with different values, we have to take
+			// that into account
+			if(issect(&obj->pesym[symindex]))
+				rp->add += obj->pesym[symindex].value;
+		}
+		qsort(r, rsect->sh.NumberOfRelocations, sizeof r[0], rbyoff);
+		
+		s = rsect->sym;
+		s->r = r;
+		s->nr = rsect->sh.NumberOfRelocations;
+	}
+
+	// enter sub-symbols into symbol table.
+	for(i=0; i<obj->npesym; i++) {
+		if(obj->pesym[i].name == 0)
+			continue;
+		if(issect(&obj->pesym[i]))
+			continue;
+		if(obj->pesym[i].sectnum > 0) {
+			sect = &obj->sect[obj->pesym[i].sectnum-1];
+			if(sect->sym == 0)
+				continue;
+		}
+		if(readsym(obj, i, &sym) < 0)
+			goto bad;
+	
+		s = sym->sym;
+		if(sym->sectnum == 0) {// extern
+			if(s->type == SDYNIMPORT)
+				s->plt = -2; // flag for dynimport in PE object files.
+			if (s->type == SXREF && sym->value > 0) {// global data
+				s->type = SNOPTRDATA;
+				s->size = sym->value;
+			}
+			continue;
+		} else if (sym->sectnum > 0) {
+			sect = &obj->sect[sym->sectnum-1];
+			if(sect->sym == 0)
+				diag("%s: %s sym == 0!", pn, s->name);
+		} else {
+			diag("%s: %s sectnum < 0!", pn, s->name);
+		}
+
+		if(sect == nil) 
+			return;
+
+		if(s->outer != S) {
+			if(s->dupok)
+				continue;
+			diag("%s: duplicate symbol reference: %s in both %s and %s", pn, s->name, s->outer->name, sect->sym->name);
+			errorexit();
+		}
+		s->sub = sect->sym->sub;
+		sect->sym->sub = s;
+		s->type = sect->sym->type | SSUB;
+		s->value = sym->value;
+		s->size = 4;
+		s->outer = sect->sym;
+		if(sect->sym->type == STEXT) {
+			if(s->external && !s->dupok)
+				diag("%s: duplicate definition of %s", pn, s->name);
+			s->external = 1;
+		}
+	}
+
+	// Sort outer lists by address, adding to textp.
+	// This keeps textp in increasing address order.
+	for(i=0; i<obj->nsect; i++) {
+		s = obj->sect[i].sym;
+		if(s == S)
+			continue;
+		if(s->sub)
+			s->sub = listsort(s->sub, valuecmp, offsetof(LSym, sub));
+		if(s->type == STEXT) {
+			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;
+			for(s = s->sub; s != S; s = s->sub) {
+				if(s->onlist)
+					sysfatal("symbol %s listed multiple times", s->name);
+				s->onlist = 1;
+				ctxt->etextp->next = s;
+				ctxt->etextp = s;
+			}
+		}
+	}
+
+	return;
+bad:
+	diag("%s: malformed pe file: %r", pn);
+}
+
+static int
+map(PeObj *obj, PeSect *sect)
+{
+	if(sect->base != nil)
+		return 0;
+
+	sect->base = mal(sect->sh.SizeOfRawData);
+	if(sect->sh.PointerToRawData == 0) // .bss doesn't have data in object file
+		return 0;
+	werrstr("short read");
+	if(Bseek(obj->f, obj->base+sect->sh.PointerToRawData, 0) < 0 || 
+			Bread(obj->f, sect->base, sect->sh.SizeOfRawData) != sect->sh.SizeOfRawData)
+		return -1;
+	
+	return 0;
+}
+
+static int
+issect(PeSym *s)
+{
+	return s->sclass == IMAGE_SYM_CLASS_STATIC && s->type == 0 && s->name[0] == '.';
+}
+
+static int
+readsym(PeObj *obj, int i, PeSym **y)
+{
+	LSym *s;
+	PeSym *sym;
+	char *name, *p;
+
+	if(i >= obj->npesym || i < 0) {
+		werrstr("invalid pe symbol index");
+		return -1;
+	}
+
+	sym = &obj->pesym[i];
+	*y = sym;
+	
+	if(issect(sym))
+		name = obj->sect[sym->sectnum-1].sym->name;
+	else {
+		name = sym->name;
+		if(strncmp(name, "__imp_", 6) == 0)
+			name = &name[6]; // __imp_Name => Name
+		if(thechar == '8' && name[0] == '_')
+			name = &name[1]; // _Name => Name
+	}
+	// remove last @XXX
+	p = strchr(name, '@');
+	if(p)
+		*p = 0;
+	
+	switch(sym->type) {
+	default:
+		werrstr("%s: invalid symbol type %d", sym->name, sym->type);
+		return -1;
+	case IMAGE_SYM_DTYPE_FUNCTION:
+	case IMAGE_SYM_DTYPE_NULL:
+		switch(sym->sclass) {
+		case IMAGE_SYM_CLASS_EXTERNAL: //global
+			s = linklookup(ctxt, name, 0);
+			break;
+		case IMAGE_SYM_CLASS_NULL:
+		case IMAGE_SYM_CLASS_STATIC:
+		case IMAGE_SYM_CLASS_LABEL:
+			s = linklookup(ctxt, name, ctxt->version);
+			s->dupok = 1;
+			break;
+		default:
+			werrstr("%s: invalid symbol binding %d", sym->name, sym->sclass);
+			return -1;
+		}
+		break;
+	}
+
+	if(s != nil && s->type == 0 && !(sym->sclass == IMAGE_SYM_CLASS_STATIC && sym->value == 0))
+		s->type = SXREF;
+	if(strncmp(sym->name, "__imp_", 6) == 0)
+		s->got = -2; // flag for __imp_
+	sym->sym = s;
+
+	return 0;
+}
diff --git a/src/cmd/ld/lib.c b/src/cmd/ld/lib.c
new file mode 100644
index 0000000..f889aba
--- /dev/null
+++ b/src/cmd/ld/lib.c
@@ -0,0 +1,1617 @@
+// 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	"l.h"
+#include	"lib.h"
+#include	"../ld/elf.h"
+#include	"../ld/dwarf.h"
+#include	"../../runtime/stack.h"
+#include	"../../runtime/funcdata.h"
+
+#include	<ar.h>
+#if !(defined(_WIN32) || defined(PLAN9))
+#include	<sys/stat.h>
+#endif
+
+enum
+{
+	// Whether to assume that the external linker is "gold"
+	// (http://sourceware.org/ml/binutils/2008-03/msg00162.html).
+	AssumeGoldLinker = 0,
+};
+
+int iconv(Fmt*);
+
+char	symname[]	= SYMDEF;
+char	pkgname[]	= "__.PKGDEF";
+static int	cout = -1;
+
+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.
+static int	externalobj = 0;
+
+static	void	hostlinksetup(void);
+
+char*	goroot;
+char*	goarch;
+char*	goos;
+char*	theline;
+
+void
+Lflag(char *arg)
+{
+	char **p;
+
+	if(ctxt->nlibdir >= ctxt->maxlibdir) {
+		if (ctxt->maxlibdir == 0)
+			ctxt->maxlibdir = 8;
+		else
+			ctxt->maxlibdir *= 2;
+		p = erealloc(ctxt->libdir, ctxt->maxlibdir * sizeof(*p));
+		ctxt->libdir = p;
+	}
+	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
+libinit(void)
+{
+	char *suffix, *suffixsep;
+
+	funcalign = FuncAlign;
+	fmtinstall('i', iconv);
+	fmtinstall('Y', Yconv);
+	fmtinstall('Z', Zconv);
+	mywhatsys();	// get goroot, goarch, goos
+
+	// add goroot to the end of the libdir list.
+	suffix = "";
+	suffixsep = "";
+	if(flag_installsuffix != nil) {
+		suffixsep = "_";
+		suffix = flag_installsuffix;
+	} else if(flag_race) {
+		suffixsep = "_";
+		suffix = "race";
+	}
+	Lflag(smprint("%s/pkg/%s_%s%s%s", goroot, goos, goarch, suffixsep, suffix));
+
+	mayberemoveoutfile();
+	cout = create(outfile, 1, 0775);
+	if(cout < 0) {
+		diag("cannot create %s: %r", outfile);
+		errorexit();
+	}
+
+	if(INITENTRY == nil) {
+		INITENTRY = mal(strlen(goarch)+strlen(goos)+20);
+		if(!flag_shared) {
+			sprint(INITENTRY, "_rt0_%s_%s", goarch, goos);
+		} else {
+			sprint(INITENTRY, "_rt0_%s_%s_lib", goarch, goos);
+		}
+	}
+	linklookup(ctxt, INITENTRY, 0)->type = SXREF;
+}
+
+void
+errorexit(void)
+{
+	if(cout >= 0) {
+		// For rmtemp run at atexit time on Windows.
+		close(cout);
+	}
+	if(nerrors) {
+		if(cout >= 0)
+			mayberemoveoutfile();
+		exits("error");
+	}
+	exits(0);
+}
+
+void
+loadinternal(char *name)
+{
+	char pname[1024];
+	int i, found;
+
+	found = 0;
+	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(ctxt, "internal", "internal", pname, name);
+			found = 1;
+			break;
+		}
+	}
+	if(!found)
+		Bprint(&bso, "warning: unable to find %s.a\n", name);
+}
+
+void
+loadlib(void)
+{
+	int i, w, x;
+	LSym *s, *tlsg;
+	char* cgostrsym;
+
+	if(flag_shared) {
+		s = linklookup(ctxt, "runtime.islibrary", 0);
+		s->dupok = 1;
+		adduint8(ctxt, s, 1);
+	}
+
+	loadinternal("runtime");
+	if(thechar == '5')
+		loadinternal("math");
+	if(flag_race)
+		loadinternal("runtime/race");
+
+	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.
+		s = linklookup(ctxt, "go.importpath.runtime/cgo.", 0);
+		s->type = SDATA;
+		s->dupok = 1;
+		s->reachable = 1;
+
+		// 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) {
+			s = linklookup(ctxt, cgostrsym, 0);
+			s->type = SRODATA;
+			s->reachable = 1;
+			addstrdata(cgostrsym, "runtime/cgo");
+		}
+	}
+
+	if(linkmode == LinkAuto) {
+		if(iscgo && externalobj)
+			linkmode = LinkExternal;
+		else
+			linkmode = LinkInternal;
+
+		// Force external linking for android.
+		if(strcmp(goos, "android") == 0)
+			linkmode = LinkExternal;
+	}
+
+	if(linkmode == LinkInternal) {
+		// Drop all the cgo_import_static declarations.
+		// Turns out we won't be needing them.
+		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,
+				// then we want to make it cgo_import_dynamic
+				// now.
+				if(s->extname != nil && s->dynimplib != nil && s->cgoexport == 0) {
+					s->type = SDYNIMPORT;
+				} else
+					s->type = 0;
+			}
+	}
+	
+	tlsg = linklookup(ctxt, "runtime.tlsg", 0);
+	tlsg->type = STLSBSS;
+	tlsg->size = PtrSize;
+	tlsg->hide = 1;
+	tlsg->reachable = 1;
+	ctxt->tlsg = tlsg;
+
+	// Now that we know the link mode, trim the dynexp list.
+	x = CgoExportDynamic;
+	if(linkmode == LinkExternal)
+		x = CgoExportStatic;
+	w = 0;
+	for(i=0; i<ndynexp; i++)
+		if(dynexp[i]->cgoexport & x)
+			dynexp[w++] = dynexp[i];
+	ndynexp = w;
+	
+	// In internal link mode, read the host object files.
+	if(linkmode == LinkInternal)
+		hostobjs();
+	else
+		hostlinksetup();
+
+	// We've loaded all the code now.
+	// If there are no dynamic libraries needed, gcc disables dynamic linking.
+	// Because of this, glibc's dynamic ELF loader occasionally (like in version 2.13)
+	// assumes that a dynamic binary always refers to at least one dynamic library.
+	// Rather than be a source of test cases for glibc, disable dynamic linking
+	// the same way that gcc would.
+	//
+	// Exception: on OS X, programs such as Shark only work with dynamic
+	// binaries, so leave it enabled on OS X (Mach-O) binaries.
+	// 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();
+}
+
+/*
+ * look for the next file in an archive.
+ * adapted from libmach.
+ */
+static vlong
+nextar(Biobuf *bp, vlong off, struct ar_hdr *a)
+{
+	int r;
+	int32 arsize;
+	char *buf;
+
+	if (off&01)
+		off++;
+	Bseek(bp, off, 0);
+	buf = Brdline(bp, '\n');
+	r = Blinelen(bp);
+	if(buf == nil) {
+		if(r == 0)
+			return 0;
+		return -1;
+	}
+	if(r != SAR_HDR)
+		return -1;
+	memmove(a, buf, SAR_HDR);
+	if(strncmp(a->fmag, ARFMAG, sizeof a->fmag))
+		return -1;
+	arsize = strtol(a->size, 0, 0);
+	if (arsize&1)
+		arsize++;
+	return arsize + r;
+}
+
+void
+objfile(char *file, char *pkg)
+{
+	vlong off, l;
+	Biobuf *f;
+	char magbuf[SARMAG];
+	char pname[150];
+	struct ar_hdr arhdr;
+
+	pkg = smprint("%i", pkg);
+
+	if(debug['v'] > 1)
+		Bprint(&bso, "%5.2f ldobj: %s (%s)\n", cputime(), file, pkg);
+	Bflush(&bso);
+	f = Bopen(file, 0);
+	if(f == nil) {
+		diag("cannot open file: %s", file);
+		errorexit();
+	}
+	l = Bread(f, magbuf, SARMAG);
+	if(l != SARMAG || strncmp(magbuf, ARMAG, SARMAG)){
+		/* load it as a regular file */
+		l = Bseek(f, 0L, 2);
+		Bseek(f, 0L, 0);
+		ldobj(f, pkg, l, file, file, FileObj);
+		Bterm(f);
+		free(pkg);
+		return;
+	}
+	
+	/* skip over optional __.GOSYMDEF and process __.PKGDEF */
+	off = Boffset(f);
+	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)) == 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: cannot find package header", file);
+		goto out;
+	}
+	off += l;
+
+	if(debug['u'])
+		ldpkg(f, pkg, atolwhex(arhdr.size), file, Pkgdef);
+
+	/*
+	 * load all the object files from the archive now.
+	 * this gives us sequential file access and keeps us
+	 * from needing to come back later to pick up more
+	 * objects.  it breaks the usual C archive model, but
+	 * this is Go, not C.  the common case in Go is that
+	 * we need to load all the objects, and then we throw away
+	 * the individual symbols that are unused.
+	 *
+	 * loading every object will also make it possible to
+	 * load foreign objects not referenced by __.GOSYMDEF.
+	 */
+	for(;;) {
+		l = nextar(f, off, &arhdr);
+		if(l == 0)
+			break;
+		if(l < 0) {
+			diag("%s: malformed archive", file);
+			goto out;
+		}
+		off += l;
+
+		l = SARNAME;
+		while(l > 0 && arhdr.name[l-1] == ' ')
+			l--;
+		snprint(pname, sizeof pname, "%s(%.*s)", file, utfnlen(arhdr.name, l), arhdr.name);
+		l = atolwhex(arhdr.size);
+		ldobj(f, pkg, l, pname, file, ArchiveObj);
+	}
+
+out:
+	Bterm(f);
+	free(pkg);
+}
+
+static void
+dowrite(int fd, char *p, int n)
+{
+	int m;
+	
+	while(n > 0) {
+		m = write(fd, p, n);
+		if(m <= 0) {
+			ctxt->cursym = S;
+			diag("write error: %r");
+			errorexit();
+		}
+		n -= m;
+		p += m;
+	}
+}
+
+typedef struct Hostobj Hostobj;
+
+struct Hostobj
+{
+	void (*ld)(Biobuf*, char*, int64, char*);
+	char *pkg;
+	char *pn;
+	char *file;
+	int64 off;
+	int64 len;
+};
+
+Hostobj *hostobj;
+int nhostobj;
+int mhostobj;
+
+// These packages can use internal linking mode.
+// Others trigger external mode.
+const char *internalpkg[] = {
+	"crypto/x509",
+	"net",
+	"os/user",
+	"runtime/cgo",
+	"runtime/race"
+};
+
+void
+ldhostobj(void (*ld)(Biobuf*, char*, int64, char*), Biobuf *f, char *pkg, int64 len, char *pn, char *file)
+{
+	int i, isinternal;
+	Hostobj *h;
+
+	isinternal = 0;
+	for(i=0; i<nelem(internalpkg); i++) {
+		if(strcmp(pkg, internalpkg[i]) == 0) {
+			isinternal = 1;
+			break;
+		}
+	}
+
+	// DragonFly declares errno with __thread, which results in a symbol
+	// type of R_386_TLS_GD or R_X86_64_TLSGD. The Go linker does not
+	// currently know how to handle TLS relocations, hence we have to
+	// force external linking for any libraries that link in code that
+	// uses errno. This can be removed if the Go linker ever supports
+	// these relocation types.
+	if(HEADTYPE == Hdragonfly)
+	if(strcmp(pkg, "net") == 0 || strcmp(pkg, "os/user") == 0)
+		isinternal = 0;
+
+	if(!isinternal)
+		externalobj = 1;
+
+	if(nhostobj >= mhostobj) {
+		if(mhostobj == 0)
+			mhostobj = 16;
+		else
+			mhostobj *= 2;
+		hostobj = erealloc(hostobj, mhostobj*sizeof hostobj[0]);
+	}
+	h = &hostobj[nhostobj++];
+	h->ld = ld;
+	h->pkg = estrdup(pkg);
+	h->pn = estrdup(pn);
+	h->file = estrdup(file);
+	h->off = Boffset(f);
+	h->len = len;
+}
+
+void
+hostobjs(void)
+{
+	int i;
+	Biobuf *f;
+	Hostobj *h;
+	
+	for(i=0; i<nhostobj; i++) {
+		h = &hostobj[i];
+		f = Bopen(h->file, OREAD);
+		if(f == nil) {
+			ctxt->cursym = S;
+			diag("cannot reopen %s: %r", h->pn);
+			errorexit();
+		}
+		Bseek(f, h->off, 0);
+		h->ld(f, h->pkg, h->len, h->pn);
+		Bterm(f);
+	}
+}
+
+// provided by lib9
+int runcmd(char**);
+char* mktempdir(void);
+void removeall(char*);
+
+static void
+rmtemp(void)
+{
+	removeall(tmpdir);
+}
+
+static void
+hostlinksetup(void)
+{
+	char *p;
+
+	if(linkmode != LinkExternal)
+		return;
+
+	// create temporary directory and arrange cleanup
+	if(tmpdir == nil) {
+		tmpdir = mktempdir();
+		atexit(rmtemp);
+	}
+
+	// change our output to temporary object file
+	close(cout);
+	p = smprint("%s/go.o", tmpdir);
+	cout = create(p, 1, 0775);
+	if(cout < 0) {
+		diag("cannot create %s: %r", p);
+		errorexit();
+	}
+	free(p);
+}
+
+void
+hostlink(void)
+{
+	char *p, **argv;
+	int c, i, w, n, argc, len;
+	Hostobj *h;
+	Biobuf *f;
+	static char buf[64<<10];
+
+	if(linkmode != LinkExternal || nerrors > 0)
+		return;
+
+	c = 0;
+	p = extldflags;
+	while(p != nil) {
+		while(*p == ' ')
+			p++;
+		if(*p == '\0')
+			break;
+		c++;
+		p = strchr(p + 1, ' ');
+	}
+
+	argv = malloc((14+nhostobj+nldflag+c)*sizeof argv[0]);
+	argc = 0;
+	if(extld == nil)
+		extld = "gcc";
+	argv[argc++] = extld;
+	switch(thechar){
+	case '8':
+		argv[argc++] = "-m32";
+		break;
+	case '6':
+		argv[argc++] = "-m64";
+		break;
+	case '5':
+		argv[argc++] = "-marm";
+		break;
+	}
+	if(!debug['s'] && !debug_s) {
+		argv[argc++] = "-gdwarf-2"; 
+	} else {
+		argv[argc++] = "-s";
+	}
+	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";
+
+	if(flag_shared) {
+		argv[argc++] = "-Wl,-Bsymbolic";
+		argv[argc++] = "-shared";
+	}
+	argv[argc++] = "-o";
+	argv[argc++] = outfile;
+	
+	if(rpath)
+		argv[argc++] = smprint("-Wl,-rpath,%s", rpath);
+
+	// Force global symbols to be exported for dlopen, etc.
+	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) {
+			ctxt->cursym = S;
+			diag("cannot reopen %s: %r", h->pn);
+			errorexit();
+		}
+		Bseek(f, h->off, 0);
+		p = smprint("%s/%06d.o", tmpdir, i);
+		argv[argc++] = p;
+		w = create(p, 1, 0775);
+		if(w < 0) {
+			ctxt->cursym = S;
+			diag("cannot create %s: %r", p);
+			errorexit();
+		}
+		len = h->len;
+		while(len > 0 && (n = Bread(f, buf, sizeof buf)) > 0){
+			if(n > len)
+				n = len;
+			dowrite(w, buf, n);
+			len -= n;
+		}
+		if(close(w) < 0) {
+			ctxt->cursym = S;
+			diag("cannot write %s: %r", p);
+			errorexit();
+		}
+		Bterm(f);
+	}
+	
+	argv[argc++] = smprint("%s/go.o", tmpdir);
+	for(i=0; i<nldflag; i++)
+		argv[argc++] = ldflag[i];
+
+	p = extldflags;
+	while(p != nil) {
+		while(*p == ' ')
+			*p++ = '\0';
+		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, ' ');
+	}
+
+	argv[argc] = nil;
+
+	quotefmtinstall();
+	if(debug['v']) {
+		Bprint(&bso, "host link:");
+		for(i=0; i<argc; i++)
+			Bprint(&bso, " %q", argv[i]);
+		Bprint(&bso, "\n");
+		Bflush(&bso);
+	}
+
+	if(runcmd(argv) < 0) {
+		ctxt->cursym = S;
+		diag("%s: running %s failed: %r", argv0, argv[0]);
+		errorexit();
+	}
+}
+
+void
+ldobj(Biobuf *f, char *pkg, int64 len, char *pn, char *file, int whence)
+{
+	char *line;
+	int n, c1, c2, c3, c4;
+	uint32 magic;
+	vlong import0, import1, eof;
+	char *t;
+
+	eof = Boffset(f) + len;
+
+	pn = estrdup(pn);
+
+	c1 = BGETC(f);
+	c2 = BGETC(f);
+	c3 = BGETC(f);
+	c4 = BGETC(f);
+	Bungetc(f);
+	Bungetc(f);
+	Bungetc(f);
+	Bungetc(f);
+
+	magic = c1<<24 | c2<<16 | c3<<8 | c4;
+	if(magic == 0x7f454c46) {	// \x7F E L F
+		ldhostobj(ldelf, f, pkg, len, pn, file);
+		return;
+	}
+	if((magic&~1) == 0xfeedface || (magic&~0x01000000) == 0xcefaedfe) {
+		ldhostobj(ldmacho, f, pkg, len, pn, file);
+		return;
+	}
+	if(c1 == 0x4c && c2 == 0x01 || c1 == 0x64 && c2 == 0x86) {
+		ldhostobj(ldpe, f, pkg, len, pn, file);
+		return;
+	}
+
+	/* check the header */
+	line = Brdline(f, '\n');
+	if(line == nil) {
+		if(Blinelen(f) > 0) {
+			diag("%s: not an object file", pn);
+			return;
+		}
+		goto eof;
+	}
+	n = Blinelen(f) - 1;
+	line[n] = '\0';
+	if(strncmp(line, "go object ", 10) != 0) {
+		if(strlen(pn) > 3 && strcmp(pn+strlen(pn)-3, ".go") == 0) {
+			print("%cl: input %s is not .%c file (use %cg to compile .go files)\n", thechar, pn, thechar, thechar);
+			errorexit();
+		}
+		if(strcmp(line, thestring) == 0) {
+			// old header format: just $GOOS
+			diag("%s: stale object file", pn);
+			return;
+		}
+		diag("%s: not an object file", pn);
+		free(pn);
+		return;
+	}
+	
+	// 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';
+		diag("%s: object is [%s] expected [%s]", pn, line+10, t);
+		free(t);
+		free(pn);
+		return;
+	}
+	
+	// Second, check that longer lines match each other exactly,
+	// so that the Go compiler and write additional information
+	// that must be the same from run to run.
+	line[n] = '\0';
+	if(n-10 > strlen(t)) {
+		if(theline == nil)
+			theline = estrdup(line+10);
+		else if(strcmp(theline, line+10) != 0) {
+			line[n] = '\0';
+			diag("%s: object is [%s] expected [%s]", pn, line+10, theline);
+			free(t);
+			free(pn);
+			return;
+		}
+	}
+	free(t);
+	line[n] = '\n';
+
+	/* skip over exports and other info -- ends with \n!\n */
+	import0 = Boffset(f);
+	c1 = '\n';	// the last line ended in \n
+	c2 = BGETC(f);
+	c3 = BGETC(f);
+	while(c1 != '\n' || c2 != '!' || c3 != '\n') {
+		c1 = c2;
+		c2 = c3;
+		c3 = BGETC(f);
+		if(c3 == Beof)
+			goto eof;
+	}
+	import1 = Boffset(f);
+
+	Bseek(f, import0, 0);
+	ldpkg(f, pkg, import1 - import0 - 2, pn, whence);	// -2 for !\n
+	Bseek(f, import1, 0);
+
+	ldobjfile(ctxt, f, pkg, eof - Boffset(f), pn);
+	free(pn);
+	return;
+
+eof:
+	diag("truncated object file: %s", pn);
+	free(pn);
+}
+
+void
+zerosig(char *sp)
+{
+	LSym *s;
+
+	s = linklookup(ctxt, sp, 0);
+	s->sig = 0;
+}
+
+void
+mywhatsys(void)
+{
+	goroot = getgoroot();
+	goos = getgoos();
+	goarch = getgoarch();
+
+	if(strncmp(goarch, thestring, strlen(thestring)) != 0)
+		sysfatal("cannot use %cc with GOARCH=%s", thechar, goarch);
+}
+
+int
+pathchar(void)
+{
+	return '/';
+}
+
+static	uchar*	hunk;
+static	uint32	nhunk;
+#define	NHUNK	(10UL<<20)
+
+void*
+mal(uint32 n)
+{
+	void *v;
+
+	n = (n+7)&~7;
+	if(n > NHUNK) {
+		v = malloc(n);
+		if(v == nil) {
+			diag("out of memory");
+			errorexit();
+		}
+		memset(v, 0, n);
+		return v;
+	}
+	if(n > nhunk) {
+		hunk = malloc(NHUNK);
+		if(hunk == nil) {
+			diag("out of memory");
+			errorexit();
+		}
+		nhunk = NHUNK;
+	}
+
+	v = hunk;
+	nhunk -= n;
+	hunk += n;
+
+	memset(v, 0, n);
+	return v;
+}
+
+void
+unmal(void *v, uint32 n)
+{
+	n = (n+7)&~7;
+	if(hunk - n == v) {
+		hunk -= n;
+		nhunk += n;
+	}
+}
+
+// Copied from ../gc/subr.c:/^pathtoprefix; must stay in sync.
+/*
+ * Convert raw string to the prefix that will be used in the symbol table.
+ * Invalid bytes turn into %xx.	 Right now the only bytes that need
+ * escaping are %, ., and ", but we escape all control characters too.
+ *
+ * If you edit this, edit ../gc/subr.c:/^pathtoprefix too.
+ * If you edit this, edit ../../debug/goobj/read.go:/importPathToPrefix too.
+ */
+static char*
+pathtoprefix(char *s)
+{
+	static char hex[] = "0123456789abcdef";
+	char *p, *r, *w, *l;
+	int n;
+
+	// find first character past the last slash, if any.
+	l = s;
+	for(r=s; *r; r++)
+		if(*r == '/')
+			l = r+1;
+
+	// check for chars that need escaping
+	n = 0;
+	for(r=s; *r; r++)
+		if(*r <= ' ' || (*r == '.' && r >= l) || *r == '%' || *r == '"' || *r >= 0x7f)
+			n++;
+
+	// quick exit
+	if(n == 0)
+		return s;
+
+	// escape
+	p = mal((r-s)+1+2*n);
+	for(r=s, w=p; *r; r++) {
+		if(*r <= ' ' || (*r == '.' && r >= l) || *r == '%' || *r == '"' || *r >= 0x7f) {
+			*w++ = '%';
+			*w++ = hex[(*r>>4)&0xF];
+			*w++ = hex[*r&0xF];
+		} else
+			*w++ = *r;
+	}
+	*w = '\0';
+	return p;
+}
+
+int
+iconv(Fmt *fp)
+{
+	char *p;
+
+	p = va_arg(fp->args, char*);
+	if(p == nil) {
+		fmtstrcpy(fp, "<nil>");
+		return 0;
+	}
+	p = pathtoprefix(p);
+	fmtstrcpy(fp, p);
+	return 0;
+}
+
+Section*
+addsection(Segment *seg, char *name, int rwx)
+{
+	Section **l;
+	Section *sect;
+	
+	for(l=&seg->sect; *l; l=&(*l)->next)
+		;
+	sect = mal(sizeof *sect);
+	sect->rwx = rwx;
+	sect->name = name;
+	sect->seg = seg;
+	sect->align = PtrSize; // everything is at least pointer-aligned
+	*l = sect;
+	return sect;
+}
+
+uint16
+le16(uchar *b)
+{
+	return b[0] | b[1]<<8;
+}
+
+uint32
+le32(uchar *b)
+{
+	return b[0] | b[1]<<8 | b[2]<<16 | (uint32)b[3]<<24;
+}
+
+uint64
+le64(uchar *b)
+{
+	return le32(b) | (uint64)le32(b+4)<<32;
+}
+
+uint16
+be16(uchar *b)
+{
+	return b[0]<<8 | b[1];
+}
+
+uint32
+be32(uchar *b)
+{
+	return (uint32)b[0]<<24 | b[1]<<16 | b[2]<<8 | b[3];
+}
+
+uint64
+be64(uchar *b)
+{
+	return (uvlong)be32(b)<<32 | be32(b+4);
+}
+
+Endian be = { be16, be32, be64 };
+Endian le = { le16, le32, le64 };
+
+typedef struct Chain Chain;
+struct Chain
+{
+	LSym *sym;
+	Chain *up;
+	int limit;  // limit on entry to sym
+};
+
+static int stkcheck(Chain*, int);
+static void stkprint(Chain*, int);
+static void stkbroke(Chain*, int);
+static LSym *morestack;
+static LSym *newstack;
+
+enum
+{
+	HasLinkRegister = (thechar == '5'),
+};
+
+// 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;
+	LSym *s;
+	
+	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;
+
+		if(s->nosplit) {
+		ctxt->cursym = s;
+		ch.sym = s;
+		stkcheck(&ch, 0);
+	}
+	}
+	for(s = ctxt->textp; s != nil; s = s->next) {
+		if(!s->nosplit) {
+		ctxt->cursym = s;
+		ch.sym = s;
+		stkcheck(&ch, 0);
+	}
+}
+}
+
+static int
+stkcheck(Chain *up, int depth)
+{
+	Chain ch, ch1;
+	LSym *s;
+	int limit;
+	Reloc *r, *endr;
+	Pciter pcsp;
+	
+	limit = up->limit;
+	s = up->sym;
+	
+	// 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");
+		stkbroke(up, 0);
+		return -1;
+	}
+
+	if(s->external || s->pcln == nil) {
+		// external function.
+		// should never be called directly.
+		// only diagnose the direct caller.
+		if(depth == 1 && s->type != SXREF)
+			diag("call to external function %s", s->name);
+		return -1;
+	}
+
+	if(limit < 0) {
+		stkbroke(up, limit);
+		return -1;
+	}
+
+	// morestack looks like it calls functions,
+	// but it switches the stack pointer first.
+	if(s == morestack)
+		return 0;
+
+	ch.up = up;
+	
+	// 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;
+		}
+
+		// 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.limit = limit - pcsp.value - callsize();
+				ch.sym = r->sym;
+				if(stkcheck(&ch, depth+1) < 0)
+					return -1;
+
+				// 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.
+				// 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 = ch.limit - callsize(); // for morestack in called prologue
+				ch1.up = &ch;
+				ch1.sym = morestack;
+				if(stkcheck(&ch1, depth+2) < 0)
+					return -1;
+				break;
+			}
+		}
+		}
+		
+	return 0;
+}
+
+static void
+stkbroke(Chain *ch, int limit)
+{
+	diag("nosplit stack overflow");
+	stkprint(ch, limit);
+}
+
+static void
+stkprint(Chain *ch, int limit)
+{
+	char *name;
+
+	if(ch->sym)
+		name = ch->sym->name;
+	else
+		name = "function pointer";
+
+	if(ch->up == nil) {
+		// top of chain.  ch->sym != nil.
+		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);
+	} else {
+		stkprint(ch->up, ch->limit + (!HasLinkRegister)*PtrSize);
+		if(!HasLinkRegister)
+			print("\t%d\ton entry to %s\n", ch->limit, name);
+	}
+	if(ch->limit != limit)
+		print("\t%d\tafter %s uses %d\n", limit, name, ch->limit - limit);
+}
+
+int
+Yconv(Fmt *fp)
+{
+	LSym *s;
+	Fmt fmt;
+	int i;
+	char *str;
+
+	s = va_arg(fp->args, LSym*);
+	if (s == S) {
+		fmtprint(fp, "<nil>");
+	} else {
+		fmtstrinit(&fmt);
+		fmtprint(&fmt, "%s @0x%08llx [%lld]", s->name, (vlong)s->value, (vlong)s->size);
+		for (i = 0; i < s->size; i++) {
+			if (!(i%8)) fmtprint(&fmt,  "\n\t0x%04x ", i);
+			fmtprint(&fmt, "%02x ", s->p[i]);
+		}
+		fmtprint(&fmt, "\n");
+		for (i = 0; i < s->nr; i++) {
+			fmtprint(&fmt, "\t0x%04x[%x] %d %s[%llx]\n",
+			      s->r[i].off,
+			      s->r[i].siz,
+			      s->r[i].type,
+			      s->r[i].sym->name,
+			      (vlong)s->r[i].add);
+		}
+		str = fmtstrflush(&fmt);
+		fmtstrcpy(fp, str);
+		free(str);
+	}
+
+	return 0;
+}
+
+vlong coutpos;
+
+void
+cflush(void)
+{
+	int n;
+
+	if(cbpmax < cbp)
+		cbpmax = cbp;
+	n = cbpmax - buf.cbuf;
+	dowrite(cout, buf.cbuf, n);
+	coutpos += n;
+	cbp = buf.cbuf;
+	cbc = sizeof(buf.cbuf);
+	cbpmax = cbp;
+}
+
+vlong
+cpos(void)
+{
+	return coutpos + cbp - buf.cbuf;
+}
+
+void
+cseek(vlong p)
+{
+	vlong start;
+	int delta;
+
+	if(cbpmax < cbp)
+		cbpmax = cbp;
+	start = coutpos;
+	if(start <= p && p <= start+(cbpmax - buf.cbuf)) {
+//print("cseek %lld in [%lld,%lld] (%lld)\n", p, start, start+sizeof(buf.cbuf), cpos());
+		delta = p - (start + cbp - buf.cbuf);
+		cbp += delta;
+		cbc -= delta;
+//print("now at %lld\n", cpos());
+		return;
+	}
+
+	cflush();
+	seek(cout, p, 0);
+	coutpos = p;
+}
+
+void
+cwrite(void *buf, int n)
+{
+	cflush();
+	if(n <= 0)
+		return;
+	dowrite(cout, buf, n);
+	coutpos += n;
+}
+
+void
+usage(void)
+{
+	fprint(2, "usage: %cl [options] main.%c\n", thechar, thechar);
+	flagprint(2);
+	exits("usage");
+}
+
+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);
+}
+
+void
+setinterp(char *s)
+{
+	debug['I'] = 1; // denote cmdline interpreter override
+	interpreter = s;
+}
+
+void
+doversion(void)
+{
+	print("%cl version %s\n", thechar, getgoversion());
+	errorexit();
+}
+
+void
+genasmsym(void (*put)(LSym*, char*, int, vlong, vlong, int, LSym*))
+{
+	Auto *a;
+	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 = linklookup(ctxt, "runtime.text", 0);
+	if(s->type == STEXT)
+		put(s, s->name, 'T', s->value, s->size, s->version, 0);
+	s = linklookup(ctxt, "runtime.etext", 0);
+	if(s->type == STEXT)
+		put(s, s->name, 'T', s->value, s->size, s->version, 0);
+
+	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) {
+		case SCONST:
+		case SRODATA:
+		case SSYMTAB:
+		case SPCLNTAB:
+		case SDATA:
+		case SNOPTRDATA:
+		case SELFROSECT:
+		case SMACHOGOT:
+		case STYPE:
+		case SSTRING:
+		case SGOSTRING:
+		case SWINDOWS:
+			if(!s->reachable)
+				continue;
+			put(s, s->name, 'D', symaddr(s), s->size, s->version, s->gotype);
+			continue;
+
+		case SBSS:
+		case SNOPTRBSS:
+			if(!s->reachable)
+				continue;
+			if(s->np > 0)
+				diag("%s should not be bss (size=%d type=%d special=%d)", s->name, (int)s->np, s->type, s->special);
+			put(s, s->name, 'B', symaddr(s), s->size, s->version, s->gotype);
+			continue;
+
+		case SFILE:
+			put(nil, s->name, 'f', s->value, 0, s->version, 0);
+			continue;
+		}
+	}
+
+	for(s = 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 != A_AUTO && a->type != A_PARAM)
+				continue;
+			
+			// compute offset relative to FP
+			if(a->type == A_PARAM)
+				off = a->aoffset;
+			else
+				off = a->aoffset - PtrSize;
+			
+			// FP
+			if(off >= 0) {
+				put(nil, a->asym->name, 'p', off, 0, 0, a->gotype);
+				continue;
+			}
+			
+			// SP
+			if(off <= -PtrSize) {
+				put(nil, a->asym->name, 'a', -(off+PtrSize), 0, 0, a->gotype);
+				continue;
+			}
+			
+			// Otherwise, off is addressing the saved program counter.
+			// Something underhanded is going on. Say nothing.
+		}
+	}
+	if(debug['v'] || debug['n'])
+		Bprint(&bso, "%5.2f symsize = %ud\n", cputime(), symsize);
+	Bflush(&bso);
+}
+
+vlong
+symaddr(LSym *s)
+{
+	if(!s->reachable)
+		diag("unreachable symbol in symaddr - %s", s->name);
+	return s->value;
+}
+
+void
+xdefine(char *p, int t, vlong v)
+{
+	LSym *s;
+
+	s = linklookup(ctxt, p, 0);
+	s->type = t;
+	s->value = v;
+	s->reachable = 1;
+	s->special = 1;
+}
+
+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;
+}
+
+vlong
+entryvalue(void)
+{
+	char *a;
+	LSym *s;
+
+	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;
+}
+
+static void
+undefsym(LSym *s)
+{
+	int i;
+	Reloc *r;
+
+	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);
+	}
+}
+
+void
+undef(void)
+{
+	LSym *s;
+	
+	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();
+}
+
+void
+callgraph(void)
+{
+	LSym *s;
+	Reloc *r;
+	int i;
+
+	if(!debug['c'])
+		return;
+
+	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;
+			if((r->type == R_CALL || r->type == R_CALLARM) && r->sym->type == STEXT)
+				Bprint(&bso, "%s calls %s\n", s->name, r->sym->name);
+		}
+	}
+}
+
+void
+diag(char *fmt, ...)
+{
+	char buf[1024], *tn, *sep;
+	va_list arg;
+
+	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();
+	}
+}
+
+void
+checkgo(void)
+{
+	LSym *s;
+	Reloc *r;
+	int i;
+	int changed;
+	
+	if(!debug['C'])
+		return;
+	
+	// TODO(rsc,khr): Eventually we want to get to no Go-called C functions at all,
+	// which would simplify this logic quite a bit.
+
+	// Mark every Go-called C function with cfunc=2, recursively.
+	do {
+		changed = 0;
+		for(s = ctxt->textp; s != nil; s = s->next) {
+			if(s->cfunc == 0 || (s->cfunc == 2 && s->nosplit)) {
+				for(i=0; i<s->nr; i++) {
+					r = &s->r[i];
+					if(r->sym == nil)
+						continue;
+					if((r->type == R_CALL || r->type == R_CALLARM) && r->sym->type == STEXT) {
+						if(r->sym->cfunc == 1) {
+							changed = 1;
+							r->sym->cfunc = 2;
+						}
+					}
+				}
+			}
+		}
+	}while(changed);
+
+	// Complain about Go-called C functions that can split the stack
+	// (that can be preempted for garbage collection or trigger a stack copy).
+	for(s = ctxt->textp; s != nil; s = s->next) {
+		if(s->cfunc == 0 || (s->cfunc == 2 && s->nosplit)) {
+			for(i=0; i<s->nr; i++) {
+				r = &s->r[i];
+				if(r->sym == nil)
+					continue;
+				if((r->type == R_CALL || r->type == R_CALLARM) && r->sym->type == STEXT) {
+					if(s->cfunc == 0 && r->sym->cfunc == 2 && !r->sym->nosplit)
+						print("Go %s calls C %s\n", s->name, r->sym->name);
+					else if(s->cfunc == 2 && s->nosplit && !r->sym->nosplit)
+						print("Go calls C %s calls %s\n", s->name, r->sym->name);
+				}
+			}
+		}
+	}
+}
diff --git a/src/cmd/ld/lib.h b/src/cmd/ld/lib.h
new file mode 100644
index 0000000..067ffa0
--- /dev/null
+++ b/src/cmd/ld/lib.h
@@ -0,0 +1,289 @@
+// Derived from Inferno utils/6l/l.h
+// 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.
+
+// Terrible but standard terminology.
+// A segment describes a block of file to load into memory.
+// A section further describes the pieces of that block for
+// use in debuggers and such.
+
+enum {
+	MAXIO		= 8192,
+};
+
+typedef struct Segment Segment;
+typedef struct Section Section;
+
+struct Segment
+{
+	uchar	rwx;		// permission as usual unix bits (5 = r-x etc)
+	uvlong	vaddr;	// virtual address
+	uvlong	len;		// length in memory
+	uvlong	fileoff;	// file offset
+	uvlong	filelen;	// length on disk
+	Section*	sect;
+};
+
+#pragma incomplete struct Elf64_Shdr
+
+struct Section
+{
+	uchar	rwx;
+	int16	extnum;
+	int32	align;
+	char	*name;
+	uvlong	vaddr;
+	uvlong	len;
+	Section	*next;	// in segment list
+	Segment	*seg;
+	struct Elf64_Shdr *elfsect;
+	uvlong	reloff;
+	uvlong	rellen;
+};
+
+extern	char	symname[];
+
+EXTERN	char*	INITENTRY;
+extern	char*	thestring;
+extern	LinkArch*	thelinkarch;
+EXTERN	char*	outfile;
+EXTERN	int	ndynexp;
+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;
+EXTERN	int	flag_race;
+EXTERN	int flag_shared;
+EXTERN	char*	tracksym;
+EXTERN	char*	interpreter;
+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;
+
+EXTERN	int	linkmode;
+EXTERN	int64	liveness;
+
+// for dynexport field of LSym
+enum
+{
+	CgoExportDynamic = 1<<0,
+	CgoExportStatic = 1<<1,
+};
+
+EXTERN	Segment	segtext;
+EXTERN	Segment	segrodata;
+EXTERN	Segment	segdata;
+EXTERN	Segment	segdwarf;
+
+typedef struct Endian Endian;
+struct Endian
+{
+	uint16	(*e16)(uchar*);
+	uint32	(*e32)(uchar*);
+	uint64	(*e64)(uchar*);
+};
+
+extern Endian be, le;
+
+/* set by call to mywhatsys() */
+extern	char*	goroot;
+extern	char*	goarch;
+extern	char*	goos;
+
+/* whence for ldpkg */
+enum {
+	FileObj = 0,
+	ArchiveObj,
+	Pkgdef
+};
+
+typedef struct Header Header;
+struct Header {
+	char *name;
+	int val;
+};
+
+EXTERN	char*	headstring;
+extern	Header	headers[];
+
+#pragma	varargck	type	"Y"	LSym*
+#pragma	varargck	type	"Z"	char*
+#pragma	varargck	type	"i"	char*
+
+// buffered output
+
+EXTERN	Biobuf	bso;
+
+EXTERN struct
+{
+	char	cbuf[MAXIO];	/* output buffer */
+} buf;
+
+EXTERN	int	cbc;
+EXTERN	char*	cbp;
+EXTERN	char*	cbpmax;
+
+#define	cput(c)\
+	{ *cbp++ = c;\
+	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	checkgo(void);
+void	cflush(void);
+void	codeblk(int64 addr, int64 size);
+vlong	cpos(void);
+void	cseek(vlong p);
+void	cwrite(void *buf, int n);
+void	datblk(int64 addr, int64 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_gcprog(LSym *s);
+uint8*	decodetype_gcmask(LSym *s);
+vlong	decodetype_ifacemethodcount(LSym *s);
+uint8	decodetype_kind(LSym *s);
+uint8	decodetype_noptr(LSym *s);
+uint8	decodetype_usegcprog(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);
+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, ...);
+
+#pragma	varargck	argpos	diag	1
diff --git a/src/cmd/ld/macho.c b/src/cmd/ld/macho.c
new file mode 100644
index 0000000..fe7e10e
--- /dev/null
+++ b/src/cmd/ld/macho.c
@@ -0,0 +1,769 @@
+// 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.
+
+// Mach-O file writing
+// http://developer.apple.com/mac/library/DOCUMENTATION/DeveloperTools/Conceptual/MachORuntime/Reference/reference.html
+
+#include "l.h"
+#include "../ld/dwarf.h"
+#include "../ld/lib.h"
+#include "../ld/macho.h"
+
+static	int	macho64;
+static	MachoHdr	hdr;
+static	MachoLoad	*load;
+static	MachoSeg	seg[16];
+static	int	nload, mload, nseg, ndebug, nsect;
+
+enum
+{
+	SymKindLocal = 0,
+	SymKindExtdef,
+	SymKindUndef,
+	NumSymKind
+};
+
+static	int nkind[NumSymKind];
+static	LSym** sortsym;
+static	int	nsortsym;
+
+// Amount of space left for adding load commands
+// that refer to dynamic libraries.  Because these have
+// to go in the Mach-O header, we can't just pick a
+// "big enough" header size.  The initial header is 
+// one page, the non-dynamic library stuff takes
+// up about 1300 bytes; we overestimate that as 2k.
+static	int	load_budget = INITIAL_MACHO_HEADR - 2*1024;
+
+static	void	machodysymtab(void);
+
+void
+machoinit(void)
+{
+	switch(thechar) {
+	// 64-bit architectures
+	case '6':
+		macho64 = 1;
+		break;
+
+	// 32-bit architectures
+	default:
+		break;
+	}
+}
+
+MachoHdr*
+getMachoHdr(void)
+{
+	return &hdr;
+}
+
+MachoLoad*
+newMachoLoad(uint32 type, uint32 ndata)
+{
+	MachoLoad *l;
+
+	if(nload >= mload) {
+		if(mload == 0)
+			mload = 1;
+		else
+			mload *= 2;
+		load = erealloc(load, mload*sizeof load[0]);
+	}
+
+	if(macho64 && (ndata & 1))
+		ndata++;
+	
+	l = &load[nload++];
+	l->type = type;
+	l->ndata = ndata;
+	l->data = mal(ndata*4);
+	return l;
+}
+
+MachoSeg*
+newMachoSeg(char *name, int msect)
+{
+	MachoSeg *s;
+
+	if(nseg >= nelem(seg)) {
+		diag("too many segs");
+		errorexit();
+	}
+	s = &seg[nseg++];
+	s->name = name;
+	s->msect = msect;
+	s->sect = mal(msect*sizeof s->sect[0]);
+	return s;
+}
+
+MachoSect*
+newMachoSect(MachoSeg *seg, char *name, char *segname)
+{
+	MachoSect *s;
+
+	if(seg->nsect >= seg->msect) {
+		diag("too many sects in segment %s", seg->name);
+		errorexit();
+	}
+	s = &seg->sect[seg->nsect++];
+	s->name = name;
+	s->segname = segname;
+	nsect++;
+	return s;
+}
+
+// Generic linking code.
+
+static char **dylib;
+static int ndylib;
+
+static vlong linkoff;
+
+int
+machowrite(void)
+{
+	vlong o1;
+	int loadsize;
+	int i, j;
+	MachoSeg *s;
+	MachoSect *t;
+	MachoLoad *l;
+
+	o1 = cpos();
+
+	loadsize = 4*4*ndebug;
+	for(i=0; i<nload; i++)
+		loadsize += 4*(load[i].ndata+2);
+	if(macho64) {
+		loadsize += 18*4*nseg;
+		loadsize += 20*4*nsect;
+	} else {
+		loadsize += 14*4*nseg;
+		loadsize += 17*4*nsect;
+	}
+
+	if(macho64)
+		LPUT(0xfeedfacf);
+	else
+		LPUT(0xfeedface);
+	LPUT(hdr.cpu);
+	LPUT(hdr.subcpu);
+	if(linkmode == LinkExternal)
+		LPUT(1);	/* file type - mach object */
+	else
+		LPUT(2);	/* file type - mach executable */
+	LPUT(nload+nseg+ndebug);
+	LPUT(loadsize);
+	LPUT(1);	/* flags - no undefines */
+	if(macho64)
+		LPUT(0);	/* reserved */
+
+	for(i=0; i<nseg; i++) {
+		s = &seg[i];
+		if(macho64) {
+			LPUT(25);	/* segment 64 */
+			LPUT(72+80*s->nsect);
+			strnput(s->name, 16);
+			VPUT(s->vaddr);
+			VPUT(s->vsize);
+			VPUT(s->fileoffset);
+			VPUT(s->filesize);
+			LPUT(s->prot1);
+			LPUT(s->prot2);
+			LPUT(s->nsect);
+			LPUT(s->flag);
+		} else {
+			LPUT(1);	/* segment 32 */
+			LPUT(56+68*s->nsect);
+			strnput(s->name, 16);
+			LPUT(s->vaddr);
+			LPUT(s->vsize);
+			LPUT(s->fileoffset);
+			LPUT(s->filesize);
+			LPUT(s->prot1);
+			LPUT(s->prot2);
+			LPUT(s->nsect);
+			LPUT(s->flag);
+		}
+		for(j=0; j<s->nsect; j++) {
+			t = &s->sect[j];
+			if(macho64) {
+				strnput(t->name, 16);
+				strnput(t->segname, 16);
+				VPUT(t->addr);
+				VPUT(t->size);
+				LPUT(t->off);
+				LPUT(t->align);
+				LPUT(t->reloc);
+				LPUT(t->nreloc);
+				LPUT(t->flag);
+				LPUT(t->res1);	/* reserved */
+				LPUT(t->res2);	/* reserved */
+				LPUT(0);	/* reserved */
+			} else {
+				strnput(t->name, 16);
+				strnput(t->segname, 16);
+				LPUT(t->addr);
+				LPUT(t->size);
+				LPUT(t->off);
+				LPUT(t->align);
+				LPUT(t->reloc);
+				LPUT(t->nreloc);
+				LPUT(t->flag);
+				LPUT(t->res1);	/* reserved */
+				LPUT(t->res2);	/* reserved */
+			}
+		}
+	}
+
+	for(i=0; i<nload; i++) {
+		l = &load[i];
+		LPUT(l->type);
+		LPUT(4*(l->ndata+2));
+		for(j=0; j<l->ndata; j++)
+			LPUT(l->data[j]);
+	}
+
+	return cpos() - o1;
+}
+
+void
+domacho(void)
+{
+	LSym *s;
+
+	if(debug['d'])
+		return;
+
+	// empirically, string table must begin with " \x00".
+	s = linklookup(ctxt, ".machosymstr", 0);
+	s->type = SMACHOSYMSTR;
+	s->reachable = 1;
+	adduint8(ctxt, s, ' ');
+	adduint8(ctxt, s, '\0');
+	
+	s = linklookup(ctxt, ".machosymtab", 0);
+	s->type = SMACHOSYMTAB;
+	s->reachable = 1;
+	
+	if(linkmode != LinkExternal) {
+		s = linklookup(ctxt, ".plt", 0);	// will be __symbol_stub
+		s->type = SMACHOPLT;
+		s->reachable = 1;
+	
+		s = linklookup(ctxt, ".got", 0);	// will be __nl_symbol_ptr
+		s->type = SMACHOGOT;
+		s->reachable = 1;
+		s->align = 4;
+	
+		s = linklookup(ctxt, ".linkedit.plt", 0);	// indirect table for .plt
+		s->type = SMACHOINDIRECTPLT;
+		s->reachable = 1;
+	
+		s = linklookup(ctxt, ".linkedit.got", 0);	// indirect table for .got
+		s->type = SMACHOINDIRECTGOT;
+		s->reachable = 1;
+	}
+}
+
+void
+machoadddynlib(char *lib)
+{
+	// Will need to store the library name rounded up
+	// and 24 bytes of header metadata.  If not enough
+	// space, grab another page of initial space at the
+	// beginning of the output file.
+	load_budget -= (strlen(lib)+7)/8*8 + 24;
+	if(load_budget < 0) {
+		HEADR += 4096;
+		INITTEXT += 4096;
+		load_budget += 4096;
+	}
+
+	if(ndylib%32 == 0)
+		dylib = erealloc(dylib, (ndylib+32)*sizeof dylib[0]);
+	dylib[ndylib++] = lib;
+}
+
+static void
+machoshbits(MachoSeg *mseg, Section *sect, char *segname)
+{
+	MachoSect *msect;
+	char buf[40];
+	char *p;
+	
+	snprint(buf, sizeof buf, "__%s", sect->name+1);
+	for(p=buf; *p; p++)
+		if(*p == '.')
+			*p = '_';
+
+	msect = newMachoSect(mseg, estrdup(buf), segname);
+	if(sect->rellen > 0) {
+		msect->reloc = sect->reloff;
+		msect->nreloc = sect->rellen / 8;
+	}
+
+	while(1<<msect->align < sect->align)
+		msect->align++;
+	msect->addr = sect->vaddr;
+	msect->size = sect->len;
+	
+	if(sect->vaddr < sect->seg->vaddr + sect->seg->filelen) {
+		// data in file
+		if(sect->len > sect->seg->vaddr + sect->seg->filelen - sect->vaddr)
+			diag("macho cannot represent section %s crossing data and bss", sect->name);
+		msect->off = sect->seg->fileoff + sect->vaddr - sect->seg->vaddr;
+	} else {
+		// zero fill
+		msect->off = 0;
+		msect->flag |= 1;
+	}
+
+	if(sect->rwx & 1)
+		msect->flag |= 0x400; /* has instructions */
+	
+	if(strcmp(sect->name, ".plt") == 0) {
+		msect->name = "__symbol_stub1";
+		msect->flag = 0x80000408; /* only instructions, code, symbol stubs */
+		msect->res1 = 0;//nkind[SymKindLocal];
+		msect->res2 = 6;
+	}
+
+	if(strcmp(sect->name, ".got") == 0) {
+		msect->name = "__nl_symbol_ptr";
+		msect->flag = 6;	/* section with nonlazy symbol pointers */
+		msect->res1 = linklookup(ctxt, ".linkedit.plt", 0)->size / 4;	/* offset into indirect symbol table */
+	}
+}
+
+void
+asmbmacho(void)
+{
+	vlong v, w;
+	vlong va;
+	int a, i;
+	MachoHdr *mh;
+	MachoSeg *ms;
+	MachoLoad *ml;
+	Section *sect;
+
+	/* apple MACH */
+	va = INITTEXT - HEADR;
+	mh = getMachoHdr();
+	switch(thechar){
+	default:
+		diag("unknown mach architecture");
+		errorexit();
+	case '6':
+		mh->cpu = MACHO_CPU_AMD64;
+		mh->subcpu = MACHO_SUBCPU_X86;
+		break;
+	case '8':
+		mh->cpu = MACHO_CPU_386;
+		mh->subcpu = MACHO_SUBCPU_X86;
+		break;
+	}
+	
+	ms = nil;
+	if(linkmode == LinkExternal) {
+		/* segment for entire file */
+		ms = newMachoSeg("", 40);
+		ms->fileoffset = segtext.fileoff;
+		ms->filesize = segdata.fileoff + segdata.filelen - segtext.fileoff;
+	}
+
+	/* segment for zero page */
+	if(linkmode != LinkExternal) {
+		ms = newMachoSeg("__PAGEZERO", 0);
+		ms->vsize = va;
+	}
+
+	/* text */
+	v = rnd(HEADR+segtext.len, INITRND);
+	if(linkmode != LinkExternal) {
+		ms = newMachoSeg("__TEXT", 20);
+		ms->vaddr = va;
+		ms->vsize = v;
+		ms->fileoffset = 0;
+		ms->filesize = v;
+		ms->prot1 = 7;
+		ms->prot2 = 5;
+	}
+
+	for(sect=segtext.sect; sect!=nil; sect=sect->next)
+		machoshbits(ms, sect, "__TEXT");
+
+	/* data */
+	if(linkmode != LinkExternal) {
+		w = segdata.len;
+		ms = newMachoSeg("__DATA", 20);
+		ms->vaddr = va+v;
+		ms->vsize = w;
+		ms->fileoffset = v;
+		ms->filesize = segdata.filelen;
+		ms->prot1 = 3;
+		ms->prot2 = 3;
+	}
+
+	for(sect=segdata.sect; sect!=nil; sect=sect->next)
+		machoshbits(ms, sect, "__DATA");
+
+	if(linkmode != LinkExternal) {
+		switch(thechar) {
+		default:
+			diag("unknown macho architecture");
+			errorexit();
+		case '6':
+			ml = newMachoLoad(5, 42+2);	/* unix thread */
+			ml->data[0] = 4;	/* thread type */
+			ml->data[1] = 42;	/* word count */
+			ml->data[2+32] = entryvalue();	/* start pc */
+			ml->data[2+32+1] = entryvalue()>>16>>16;	// hide >>32 for 8l
+			break;
+		case '8':
+			ml = newMachoLoad(5, 16+2);	/* unix thread */
+			ml->data[0] = 1;	/* thread type */
+			ml->data[1] = 16;	/* word count */
+			ml->data[2+10] = entryvalue();	/* start pc */
+			break;
+		}
+	}
+	
+	if(!debug['d']) {
+		LSym *s1, *s2, *s3, *s4;
+
+		// must match domacholink below
+		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);
+			ms->vaddr = va+v+rnd(segdata.len, INITRND);
+			ms->vsize = s1->size + s2->size + s3->size + s4->size;
+			ms->fileoffset = linkoff;
+			ms->filesize = ms->vsize;
+			ms->prot1 = 7;
+			ms->prot2 = 3;
+		}
+
+		ml = newMachoLoad(2, 4);	/* LC_SYMTAB */
+		ml->data[0] = linkoff;	/* symoff */
+		ml->data[1] = nsortsym;	/* nsyms */
+		ml->data[2] = linkoff + s1->size + s2->size + s3->size;	/* stroff */
+		ml->data[3] = s4->size;	/* strsize */
+
+		machodysymtab();
+
+		if(linkmode != LinkExternal) {
+			ml = newMachoLoad(14, 6);	/* LC_LOAD_DYLINKER */
+			ml->data[0] = 12;	/* offset to string */
+			strcpy((char*)&ml->data[1], "/usr/lib/dyld");
+	
+			for(i=0; i<ndylib; i++) {
+				ml = newMachoLoad(12, 4+(strlen(dylib[i])+1+7)/8*2);	/* LC_LOAD_DYLIB */
+				ml->data[0] = 24;	/* offset of string from beginning of load */
+				ml->data[1] = 0;	/* time stamp */
+				ml->data[2] = 0;	/* version */
+				ml->data[3] = 0;	/* compatibility version */
+				strcpy((char*)&ml->data[4], dylib[i]);
+			}
+		}
+	}
+
+	// TODO: dwarf headers go in ms too
+	if(!debug['s'] && linkmode != LinkExternal)
+		dwarfaddmachoheaders();
+
+	a = machowrite();
+	if(a > HEADR)
+		diag("HEADR too small: %d > %d", a, HEADR);
+}
+
+static int
+symkind(LSym *s)
+{
+	if(s->type == SDYNIMPORT)
+		return SymKindUndef;
+	if(s->cgoexport)
+		return SymKindExtdef;
+	return SymKindLocal;
+}
+
+static void
+addsym(LSym *s, char *name, int type, vlong addr, vlong size, int ver, LSym *gotype)
+{
+	USED(name);
+	USED(addr);
+	USED(size);
+	USED(ver);
+	USED(gotype);
+
+	if(s == nil)
+		return;
+
+	switch(type) {
+	default:
+		return;
+	case 'D':
+	case 'B':
+	case 'T':
+		break;
+	}
+	
+	if(sortsym) {
+		sortsym[nsortsym] = s;
+		nkind[symkind(s)]++;
+	}
+	nsortsym++;
+}
+	
+static int
+scmp(const void *p1, const void *p2)
+{
+	LSym *s1, *s2;
+	int k1, k2;
+
+	s1 = *(LSym**)p1;
+	s2 = *(LSym**)p2;
+	
+	k1 = symkind(s1);
+	k2 = symkind(s2);
+	if(k1 != k2)
+		return k1 - k2;
+
+	return strcmp(s1->extname, s2->extname);
+}
+
+static void
+machogenasmsym(void (*put)(LSym*, char*, int, vlong, vlong, int, LSym*))
+{
+	LSym *s;
+
+	genasmsym(put);
+	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);
+}
+			
+void
+machosymorder(void)
+{
+	int i;
+
+	// On Mac OS X Mountain Lion, we must sort exported symbols
+	// So we sort them here and pre-allocate dynid for them
+	// See http://golang.org/issue/4029
+	for(i=0; i<ndynexp; i++)
+		dynexp[i]->reachable = 1;
+	machogenasmsym(addsym);
+	sortsym = mal(nsortsym * sizeof sortsym[0]);
+	nsortsym = 0;
+	machogenasmsym(addsym);
+	qsort(sortsym, nsortsym, sizeof sortsym[0], scmp);
+	for(i=0; i<nsortsym; i++)
+		sortsym[i]->dynid = i;
+}
+
+static void
+machosymtab(void)
+{
+	int i;
+	LSym *symtab, *symstr, *s, *o;
+	char *p;
+
+	symtab = linklookup(ctxt, ".machosymtab", 0);
+	symstr = linklookup(ctxt, ".machosymstr", 0);
+
+	for(i=0; i<nsortsym; i++) {
+		s = sortsym[i];
+		adduint32(ctxt, symtab, symstr->size);
+		
+		// Only add _ to C symbols. Go symbols have dot in the name.
+		if(strstr(s->extname, ".") == nil)
+			adduint8(ctxt, symstr, '_');
+		// replace "·" as ".", because DTrace cannot handle it.
+		if(strstr(s->extname, "·") == nil) {
+			addstring(symstr, s->extname);
+		} else {
+			for(p = s->extname; *p; p++) {
+				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(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(ctxt, symtab, 0x0f);
+			else
+				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(ctxt, symtab, 0);
+			} else
+				adduint8(ctxt, symtab, o->sect->extnum);
+			adduint16(ctxt, symtab, 0); // desc
+			adduintxx(ctxt, symtab, symaddr(s), PtrSize);
+		}
+	}
+}
+
+static void
+machodysymtab(void)
+{
+	int n;
+	MachoLoad *ml;
+	LSym *s1, *s2, *s3;
+
+	ml = newMachoLoad(11, 18);	/* LC_DYSYMTAB */
+
+	n = 0;
+	ml->data[0] = n;	/* ilocalsym */
+	ml->data[1] = nkind[SymKindLocal];	/* nlocalsym */
+	n += nkind[SymKindLocal];
+
+	ml->data[2] = n;	/* iextdefsym */
+	ml->data[3] = nkind[SymKindExtdef];	/* nextdefsym */
+	n += nkind[SymKindExtdef];
+
+	ml->data[4] = n;	/* iundefsym */
+	ml->data[5] = nkind[SymKindUndef];	/* nundefsym */
+
+	ml->data[6] = 0;	/* tocoffset */
+	ml->data[7] = 0;	/* ntoc */
+	ml->data[8] = 0;	/* modtaboff */
+	ml->data[9] = 0;	/* nmodtab */
+	ml->data[10] = 0;	/* extrefsymoff */
+	ml->data[11] = 0;	/* nextrefsyms */
+
+	// must match domacholink below
+	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 */
+
+	ml->data[14] = 0;	/* extreloff */
+	ml->data[15] = 0;	/* nextrel */
+	ml->data[16] = 0;	/* locreloff */
+	ml->data[17] = 0;	/* nlocrel */
+}
+
+vlong
+domacholink(void)
+{
+	int size;
+	LSym *s1, *s2, *s3, *s4;
+
+	machosymtab();
+
+	// write data that will be linkedit section
+	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
+	// to be code signed correctly.
+	//
+	// Apple's codesign_allocate (a helper utility for
+	// the codesign utility) can do this fine itself if
+	// it is run on a dynamic Mach-O binary.  However,
+	// when it is run on a pure (non-cgo) Go binary, where
+	// the linkedit section is mostly empty, it fails to
+	// account for the extra padding that it itself adds
+	// when adding the LC_CODE_SIGNATURE load command
+	// (which must be aligned on a 16-byte boundary).
+	//
+	// By forcing the linkedit section to end on a 16-byte
+	// boundary, codesign_allocate will not need to apply
+	// any alignment padding itself, working around the
+	// issue.
+	while(s4->size%16)
+		adduint8(ctxt, s4, 0);
+	
+	size = s1->size + s2->size + s3->size + s4->size;
+
+	if(size > 0) {
+		linkoff = rnd(HEADR+segtext.len, INITRND) + rnd(segdata.filelen, INITRND) + rnd(segdwarf.filelen, INITRND);
+		cseek(linkoff);
+
+		cwrite(s1->p, s1->size);
+		cwrite(s2->p, s2->size);
+		cwrite(s3->p, s3->size);
+		cwrite(s4->p, s4->size);
+	}
+
+	return rnd(size, INITRND);
+}
+
+
+void
+machorelocsect(Section *sect, LSym *first)
+{
+	LSym *sym;
+	int32 eaddr;
+	Reloc *r;
+
+	// If main section has no bits, nothing to relocate.
+	if(sect->vaddr >= sect->seg->vaddr + sect->seg->filelen)
+		return;
+	
+	sect->reloff = cpos();
+	for(sym = first; sym != nil; sym = sym->next) {
+		if(!sym->reachable)
+			continue;
+		if(sym->value >= sect->vaddr)
+			break;
+	}
+	
+	eaddr = sect->vaddr + sect->len;
+	for(; sym != nil; sym = sym->next) {
+		if(!sym->reachable)
+			continue;
+		if(sym->value >= eaddr)
+			break;
+		ctxt->cursym = sym;
+		
+		for(r = sym->r; r < sym->r+sym->nr; r++) {
+			if(r->done)
+				continue;
+			if(machoreloc1(r, sym->value+r->off - sect->vaddr) < 0)
+				diag("unsupported obj reloc %d/%d to %s", r->type, r->siz, r->sym->name);
+		}
+	}
+		
+	sect->rellen = cpos() - sect->reloff;
+}
+
+void
+machoemitreloc(void)
+{
+	Section *sect;
+
+	while(cpos()&7)
+		cput(0);
+
+	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)
+		machorelocsect(sect, datap);	
+}
diff --git a/src/cmd/ld/macho.h b/src/cmd/ld/macho.h
new file mode 100644
index 0000000..d759f4b
--- /dev/null
+++ b/src/cmd/ld/macho.h
@@ -0,0 +1,91 @@
+// 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.
+
+typedef struct MachoHdr MachoHdr;
+struct MachoHdr {
+	uint32	cpu;
+	uint32	subcpu;
+};
+
+typedef struct MachoSect MachoSect;
+struct MachoSect {
+	char*	name;
+	char*	segname;
+	uint64	addr;
+	uint64	size;
+	uint32	off;
+	uint32	align;
+	uint32	reloc;
+	uint32	nreloc;
+	uint32	flag;
+	uint32	res1;
+	uint32	res2;
+};
+
+typedef struct MachoSeg MachoSeg;
+struct MachoSeg {
+	char*	name;
+	uint64	vsize;
+	uint64	vaddr;
+	uint64	fileoffset;
+	uint64	filesize;
+	uint32	prot1;
+	uint32	prot2;
+	uint32	nsect;
+	uint32	msect;
+	MachoSect	*sect;
+	uint32	flag;
+};
+
+typedef struct MachoLoad MachoLoad;
+struct MachoLoad {
+	uint32	type;
+	uint32	ndata;
+	uint32	*data;
+};
+
+MachoHdr*	getMachoHdr(void);
+MachoSeg*	newMachoSeg(char*, int);
+MachoSect*	newMachoSect(MachoSeg*, char*, char*);
+MachoLoad*	newMachoLoad(uint32, uint32);
+int	machowrite(void);
+void	machoinit(void);
+void	machosymorder(void);
+void	machoemitreloc(void);
+int	machoreloc1(Reloc*, vlong);
+
+/*
+ * Total amount of space to reserve at the start of the file
+ * for Header, PHeaders, and SHeaders.
+ * May waste some.
+ */
+#define	INITIAL_MACHO_HEADR	4*1024
+
+enum {
+	MACHO_CPU_AMD64 = (1<<24)|7,
+	MACHO_CPU_386 = 7,
+	MACHO_SUBCPU_X86 = 3,
+
+	MACHO32SYMSIZE = 12,
+	MACHO64SYMSIZE = 16,
+	
+	MACHO_X86_64_RELOC_UNSIGNED = 0,
+	MACHO_X86_64_RELOC_SIGNED = 1,
+	MACHO_X86_64_RELOC_BRANCH = 2,
+	MACHO_X86_64_RELOC_GOT_LOAD = 3,
+	MACHO_X86_64_RELOC_GOT = 4,
+	MACHO_X86_64_RELOC_SUBTRACTOR = 5,
+	MACHO_X86_64_RELOC_SIGNED_1 = 6,
+	MACHO_X86_64_RELOC_SIGNED_2 = 7,
+	MACHO_X86_64_RELOC_SIGNED_4 = 8,
+	
+	MACHO_GENERIC_RELOC_VANILLA = 0,
+	
+	MACHO_FAKE_GOTPCREL = 100,
+};
+
+void	domacho(void);
+vlong	domacholink(void);
+void	asmbmacho(void);
+void	machoadddynlib(char*);
diff --git a/src/cmd/ld/pcln.c b/src/cmd/ld/pcln.c
new file mode 100644
index 0000000..69671c0
--- /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	"../../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, "runtime.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
new file mode 100644
index 0000000..c26cd52
--- /dev/null
+++ b/src/cmd/ld/pe.c
@@ -0,0 +1,712 @@
+// 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.
+
+// PE (Portable Executable) file writing
+// http://www.microsoft.com/whdc/system/platform/firmware/PECOFF.mspx
+
+#include "l.h"
+#include "../ld/lib.h"
+#include "../ld/pe.h"
+#include "../ld/dwarf.h"
+
+// DOS stub that prints out
+// "This program cannot be run in DOS mode."
+static char dosstub[] =
+{
+	0x4d, 0x5a, 0x90, 0x00, 0x03, 0x00, 0x04, 0x00,
+	0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
+	0x8b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0x40, 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, 0x80, 0x00, 0x00, 0x00,
+	0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd,
+	0x21, 0xb8, 0x01, 0x4c, 0xcd, 0x21, 0x54, 0x68,
+	0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72,
+	0x61, 0x6d, 0x20, 0x63, 0x61, 0x6e, 0x6e, 0x6f,
+	0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6e,
+	0x20, 0x69, 0x6e, 0x20, 0x44, 0x4f, 0x53, 0x20,
+	0x6d, 0x6f, 0x64, 0x65, 0x2e, 0x0d, 0x0d, 0x0a,
+	0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static LSym *rsrcsym;
+
+static char* strtbl;
+static int strtblnextoff;
+static int strtblsize;
+
+int32 PESECTHEADR;
+int32 PEFILEHEADR;
+
+static int pe64;
+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;
+static PE64_IMAGE_OPTIONAL_HEADER oh64;
+static IMAGE_SECTION_HEADER sh[16];
+static IMAGE_DATA_DIRECTORY* dd;
+
+#define	set(n, v)	(pe64 ? (oh64.n = v) : (oh.n = v))
+#define	put(v)		(pe64 ? vputl(v) : lputl(v))
+
+typedef struct Imp Imp;
+struct Imp {
+	LSym* s;
+	uvlong off;
+	Imp* next;
+};
+
+typedef struct Dll Dll;
+struct Dll {
+	char* name;
+	uvlong nameoff;
+	uvlong thunkoff;
+	Imp* ms;
+	Dll* next;
+};
+
+static Dll* dr;
+
+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)
+{
+	IMAGE_SECTION_HEADER *h;
+
+	if(nsect == 16) {
+		diag("too many sections");
+		errorexit();
+	}
+	h = &sh[nsect++];
+	strncpy((char*)h->Name, name, sizeof(h->Name));
+	h->VirtualSize = sectsize;
+	h->VirtualAddress = nextsectoff;
+	nextsectoff = rnd(nextsectoff+sectsize, PESECTALIGN);
+	h->PointerToRawData = nextfileoff;
+	if(filesize > 0) {
+		h->SizeOfRawData = rnd(filesize, PEFILEALIGN);
+		nextfileoff += h->SizeOfRawData;
+	}
+	return h;
+}
+
+static void
+chksectoff(IMAGE_SECTION_HEADER *h, vlong off)
+{
+	if(off != h->PointerToRawData) {
+		diag("%s.PointerToRawData = %#llux, want %#llux", (char *)h->Name, (vlong)h->PointerToRawData, off);
+		errorexit();
+	}
+}
+
+static void
+chksectseg(IMAGE_SECTION_HEADER *h, Segment *s)
+{
+	if(s->vaddr-PEBASE != h->VirtualAddress) {
+		diag("%s.VirtualAddress = %#llux, want %#llux", (char *)h->Name, (vlong)h->VirtualAddress, (vlong)(s->vaddr-PEBASE));
+		errorexit();
+	}
+	if(s->fileoff != h->PointerToRawData) {
+		diag("%s.PointerToRawData = %#llux, want %#llux", (char *)h->Name, (vlong)h->PointerToRawData, (vlong)(s->fileoff));
+		errorexit();
+	}
+}
+
+void
+peinit(void)
+{
+	int32 l;
+
+	switch(thechar) {
+	// 64-bit architectures
+	case '6':
+		pe64 = 1;
+		l = sizeof(oh64);
+		dd = oh64.DataDirectory;
+		break;
+	// 32-bit architectures
+	default:
+		l = sizeof(oh);
+		dd = oh.DataDirectory;
+		break;
+	}
+	
+	PEFILEHEADR = rnd(sizeof(dosstub)+sizeof(fh)+l+sizeof(sh), PEFILEALIGN);
+	PESECTHEADR = rnd(PEFILEHEADR, PESECTALIGN);
+	nextsectoff = PESECTHEADR;
+	nextfileoff = PEFILEHEADR;
+
+	// some mingw libs depend on this symbol, for example, FindPESectionByName
+	xdefine("__image_base__", SDATA, PEBASE);
+	xdefine("_image_base__", SDATA, PEBASE);
+}
+
+static void
+pewrite(void)
+{
+	cseek(0);
+	cwrite(dosstub, sizeof dosstub);
+	strnput("PE", 4);
+	// TODO: This code should not assume that the
+	// memory representation is little-endian or
+	// that the structs are packed identically to
+	// their file representation.
+	cwrite(&fh, sizeof fh);
+	if(pe64)
+		cwrite(&oh64, sizeof oh64);
+	else
+		cwrite(&oh, sizeof oh);
+	cwrite(sh, nsect * sizeof sh[0]);
+}
+
+static void
+strput(char *s)
+{
+	int n;
+
+	for(n=0; *s; n++)
+		cput(*s++);
+	cput('\0');
+	n++;
+	// string must be padded to even size
+	if(n%2)
+		cput('\0');
+}
+
+static Dll* 
+initdynimport(void)
+{
+	Imp *m;
+	Dll *d;
+	LSym *s, *dynamic;
+
+	dr = nil;
+	m = nil;
+	for(s = ctxt->allsym; s != S; s = s->allsym) {
+		if(!s->reachable || s->type != SDYNIMPORT)
+			continue;
+		for(d = dr; d != nil; d = d->next) {
+			if(strcmp(d->name,s->dynimplib) == 0) {
+				m = mal(sizeof *m);
+				break;
+			}
+		}
+		if(d == nil) {
+			d = mal(sizeof *d);
+			d->name = s->dynimplib;
+			d->next = dr;
+			dr = d;
+			m = mal(sizeof *m);
+		}
+		m->s = s;
+		m->next = d->ms;
+		d->ms = m;
+	}
+	
+	dynamic = linklookup(ctxt, ".windynamic", 0);
+	dynamic->reachable = 1;
+	dynamic->type = SWINDOWS;
+	for(d = dr; d != nil; d = d->next) {
+		for(m = d->ms; m != nil; m = m->next) {
+			m->s->type = SWINDOWS | SSUB;
+			m->s->sub = dynamic->sub;
+			dynamic->sub = m->s;
+			m->s->value = dynamic->size;
+			dynamic->size += PtrSize;
+		}
+		dynamic->size += PtrSize;
+	}
+		
+	return dr;
+}
+
+static void
+addimports(IMAGE_SECTION_HEADER *datsect)
+{
+	IMAGE_SECTION_HEADER *isect;
+	uvlong n, oftbase, ftbase;
+	vlong startoff, endoff;
+	Imp *m;
+	Dll *d;
+	LSym* dynamic;
+	
+	startoff = cpos();
+	dynamic = linklookup(ctxt, ".windynamic", 0);
+
+	// skip import descriptor table (will write it later)
+	n = 0;
+	for(d = dr; d != nil; d = d->next)
+		n++;
+	cseek(startoff + sizeof(IMAGE_IMPORT_DESCRIPTOR) * (n + 1));
+
+	// write dll names
+	for(d = dr; d != nil; d = d->next) {
+		d->nameoff = cpos() - startoff;
+		strput(d->name);
+	}
+
+	// write function names
+	for(d = dr; d != nil; d = d->next) {
+		for(m = d->ms; m != nil; m = m->next) {
+			m->off = nextsectoff + cpos() - startoff;
+			wputl(0); // hint
+			strput(m->s->extname);
+		}
+	}
+	
+	// write OriginalFirstThunks
+	oftbase = cpos() - startoff;
+	n = cpos();
+	for(d = dr; d != nil; d = d->next) {
+		d->thunkoff = cpos() - n;
+		for(m = d->ms; m != nil; m = m->next)
+			put(m->off);
+		put(0);
+	}
+
+	// add pe section and pad it at the end
+	n = cpos() - startoff;
+	isect = addpesection(".idata", n, n);
+	isect->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA|
+		IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE;
+	chksectoff(isect, startoff);
+	strnput("", isect->SizeOfRawData - n);
+	endoff = cpos();
+
+	// write FirstThunks (allocated in .data section)
+	ftbase = dynamic->value - datsect->VirtualAddress - PEBASE;
+	cseek(datsect->PointerToRawData + ftbase);
+	for(d = dr; d != nil; d = d->next) {
+		for(m = d->ms; m != nil; m = m->next)
+			put(m->off);
+		put(0);
+	}
+	
+	// finally write import descriptor table
+	cseek(startoff);
+	for(d = dr; d != nil; d = d->next) {
+		lputl(isect->VirtualAddress + oftbase + d->thunkoff);
+		lputl(0);
+		lputl(0);
+		lputl(isect->VirtualAddress + d->nameoff);
+		lputl(datsect->VirtualAddress + ftbase + d->thunkoff);
+	}
+	lputl(0); //end
+	lputl(0);
+	lputl(0);
+	lputl(0);
+	lputl(0);
+	
+	// update data directory
+	dd[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = isect->VirtualAddress;
+	dd[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = isect->VirtualSize;
+	dd[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = dynamic->value - PEBASE;
+	dd[IMAGE_DIRECTORY_ENTRY_IAT].Size = dynamic->size;
+
+	cseek(endoff);
+}
+
+static int
+scmp(const void *p1, const void *p2)
+{
+	LSym *s1, *s2;
+
+	s1 = *(LSym**)p1;
+	s2 = *(LSym**)p2;
+	return strcmp(s1->extname, s2->extname);
+}
+
+static void
+initdynexport(void)
+{
+	LSym *s;
+	
+	nexport = 0;
+	for(s = ctxt->allsym; s != S; s = s->allsym) {
+		if(!s->reachable || !(s->cgoexport & CgoExportDynamic))
+			continue;
+		if(nexport+1 > sizeof(dexport)/sizeof(dexport[0])) {
+			diag("pe dynexport table is full");
+			errorexit();
+		}
+		
+		dexport[nexport] = s;
+		nexport++;
+	}
+	
+	qsort(dexport, nexport, sizeof dexport[0], scmp);
+}
+
+void
+addexports(void)
+{
+	IMAGE_SECTION_HEADER *sect;
+	IMAGE_EXPORT_DIRECTORY e;
+	int size, i, va, va_name, va_addr, va_na, v;
+
+	size = sizeof e + 10*nexport + strlen(outfile) + 1;
+	for(i=0; i<nexport; i++)
+		size += strlen(dexport[i]->extname) + 1;
+	
+	if (nexport == 0)
+		return;
+		
+	sect = addpesection(".edata", size, size);
+	sect->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_MEM_READ;
+	chksectoff(sect, cpos());
+	va = sect->VirtualAddress;
+	dd[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = va;
+	dd[IMAGE_DIRECTORY_ENTRY_EXPORT].Size = sect->VirtualSize;
+
+	va_name = va + sizeof e + nexport*4;
+	va_addr = va + sizeof e;
+	va_na = va + sizeof e + nexport*8;
+
+	e.Characteristics = 0;
+	e.MajorVersion = 0;
+	e.MinorVersion = 0;
+	e.NumberOfFunctions = nexport;
+	e.NumberOfNames = nexport;
+	e.Name = va + sizeof e + nexport*10; // Program names.
+	e.Base = 1;
+	e.AddressOfFunctions = va_addr;
+	e.AddressOfNames = va_name;
+	e.AddressOfNameOrdinals = va_na;
+	// put IMAGE_EXPORT_DIRECTORY
+	for (i=0; i<sizeof(e); i++)
+		cput(((char*)&e)[i]);
+	// put EXPORT Address Table
+	for(i=0; i<nexport; i++)
+		lputl(dexport[i]->value - PEBASE);		
+	// put EXPORT Name Pointer Table
+	v = e.Name + strlen(outfile)+1;
+	for(i=0; i<nexport; i++) {
+		lputl(v);
+		v += strlen(dexport[i]->extname)+1;
+	}
+	// put EXPORT Ordinal Table
+	for(i=0; i<nexport; i++)
+		wputl(i);
+	// put Names
+	strnput(outfile, strlen(outfile)+1);
+	for(i=0; i<nexport; i++)
+		strnput(dexport[i]->extname, strlen(dexport[i]->extname)+1);
+	strnput("", sect->SizeOfRawData - size);
+}
+
+void
+dope(void)
+{
+	LSym *rel;
+
+	/* relocation table */
+	rel = linklookup(ctxt, ".rel", 0);
+	rel->reachable = 1;
+	rel->type = SELFROSECT;
+
+	initdynimport();
+	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 
+ * the string table. 
+ * reference: pecoff_v8.docx Page 24.
+ * <http://www.microsoft.com/whdc/system/platform/firmware/PECOFFdwn.mspx>
+ */
+IMAGE_SECTION_HEADER*
+newPEDWARFSection(char *name, vlong size)
+{
+	IMAGE_SECTION_HEADER *h;
+	char s[8];
+	int off;
+
+	if(size == 0)
+		return nil;
+
+	off = strtbladd(name);
+	sprint(s, "/%d\0", off);
+	h = addpesection(s, size, size);
+	h->Characteristics = IMAGE_SCN_MEM_READ|
+		IMAGE_SCN_MEM_DISCARDABLE;
+
+	return h;
+}
+
+static void
+addsym(LSym *s, char *name, int type, vlong addr, vlong size, int ver, LSym *gotype)
+{
+	COFFSym *cs;
+	USED(name);
+	USED(addr);
+	USED(size);
+	USED(ver);
+	USED(gotype);
+
+	if(s == nil)
+		return;
+
+	if(s->sect == nil)
+		return;
+
+	switch(type) {
+	default:
+		return;
+	case 'D':
+	case 'B':
+	case 'T':
+		break;
+	}
+
+	if(coffsym) {
+		cs = &coffsym[ncoffsym];
+		cs->sym = s;
+		if(strlen(s->name) > 8)
+			cs->strtbloff = strtbladd(s->name);
+		if(s->value >= segdata.vaddr) {
+			cs->value = s->value - segdata.vaddr;
+			cs->sect = datasect;
+		} else if(s->value >= segtext.vaddr) {
+			cs->value = s->value - segtext.vaddr;
+			cs->sect = textsect;
+		} else {
+			cs->value = 0;
+			cs->sect = 0;
+			diag("addsym %#llx", addr);
+		}
+	}
+	ncoffsym++;
+}
+
+static void
+addsymtable(void)
+{
+	IMAGE_SECTION_HEADER *h;
+	int i, size;
+	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<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(strtblnextoff + 4);
+	for (i=0; i<strtblnextoff; i++)
+		cput(strtbl[i]);
+	strnput("", h->SizeOfRawData - size);
+}
+
+void
+setpersrc(LSym *sym)
+{
+	if(rsrcsym != nil)
+		diag("too many .rsrc sections");
+	
+	rsrcsym = sym;
+}
+
+void
+addpersrc(void)
+{
+	IMAGE_SECTION_HEADER *h;
+	uchar *p;
+	uint32 val;
+	Reloc *r;
+
+	if(rsrcsym == nil)
+		return;
+	
+	h = addpesection(".rsrc", rsrcsym->size, rsrcsym->size);
+	h->Characteristics = IMAGE_SCN_MEM_READ|
+		IMAGE_SCN_MEM_WRITE | IMAGE_SCN_CNT_INITIALIZED_DATA;
+	chksectoff(h, cpos());
+	// relocation
+	for(r=rsrcsym->r; r<rsrcsym->r+rsrcsym->nr; r++) {
+		p = rsrcsym->p + r->off;
+		val = h->VirtualAddress + r->add;
+		// 32-bit little-endian
+		p[0] = val;
+		p[1] = val>>8;
+		p[2] = val>>16;
+		p[3] = val>>24;
+	}
+	cwrite(rsrcsym->p, rsrcsym->size);
+	strnput("", h->SizeOfRawData - rsrcsym->size);
+
+	// update data directory
+	dd[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = h->VirtualAddress;
+	dd[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = h->VirtualSize;
+}
+
+void
+asmbpe(void)
+{
+	IMAGE_SECTION_HEADER *t, *d;
+
+	switch(thechar) {
+	default:
+		diag("unknown PE architecture");
+		errorexit();
+	case '6':
+		fh.Machine = IMAGE_FILE_MACHINE_AMD64;
+		break;
+	case '8':
+		fh.Machine = IMAGE_FILE_MACHINE_I386;
+		break;
+	}
+
+	t = addpesection(".text", segtext.len, segtext.len);
+	t->Characteristics = IMAGE_SCN_CNT_CODE|
+		IMAGE_SCN_CNT_INITIALIZED_DATA|
+		IMAGE_SCN_MEM_EXECUTE|IMAGE_SCN_MEM_READ;
+	chksectseg(t, &segtext);
+	textsect = nsect;
+
+	d = addpesection(".data", segdata.len, segdata.filelen);
+	d->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA|
+		IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE;
+	chksectseg(d, &segdata);
+	datasect = nsect;
+
+	if(!debug['s'])
+		dwarfaddpeheaders();
+
+	cseek(nextfileoff);
+	addimports(d);
+	addexports();
+	addsymtable();
+	addpersrc();
+
+	fh.NumberOfSections = nsect;
+	fh.TimeDateStamp = time(0);
+	fh.Characteristics = IMAGE_FILE_RELOCS_STRIPPED|
+		IMAGE_FILE_EXECUTABLE_IMAGE|IMAGE_FILE_DEBUG_STRIPPED;
+	if (pe64) {
+		fh.SizeOfOptionalHeader = sizeof(oh64);
+		fh.Characteristics |= IMAGE_FILE_LARGE_ADDRESS_AWARE;
+		set(Magic, 0x20b);	// PE32+
+	} else {
+		fh.SizeOfOptionalHeader = sizeof(oh);
+		fh.Characteristics |= IMAGE_FILE_32BIT_MACHINE;
+		set(Magic, 0x10b);	// PE32
+		oh.BaseOfData = d->VirtualAddress;
+	}
+	set(MajorLinkerVersion, 3);
+	set(MinorLinkerVersion, 0);
+	set(SizeOfCode, t->SizeOfRawData);
+	set(SizeOfInitializedData, d->SizeOfRawData);
+	set(SizeOfUninitializedData, 0);
+	set(AddressOfEntryPoint, entryvalue()-PEBASE);
+	set(BaseOfCode, t->VirtualAddress);
+	set(ImageBase, PEBASE);
+	set(SectionAlignment, PESECTALIGN);
+	set(FileAlignment, PEFILEALIGN);
+	set(MajorOperatingSystemVersion, 4);
+	set(MinorOperatingSystemVersion, 0);
+	set(MajorImageVersion, 1);
+	set(MinorImageVersion, 0);
+	set(MajorSubsystemVersion, 4);
+	set(MinorSubsystemVersion, 0);
+	set(SizeOfImage, nextsectoff);
+	set(SizeOfHeaders, PEFILEHEADR);
+	if(strcmp(headstring, "windowsgui") == 0)
+		set(Subsystem, IMAGE_SUBSYSTEM_WINDOWS_GUI);
+	else
+		set(Subsystem, IMAGE_SUBSYSTEM_WINDOWS_CUI);
+
+	// Disable stack growth as we don't want Windows to
+	// fiddle with the thread stack limits, which we set
+	// ourselves to circumvent the stack checks in the
+	// Windows exception dispatcher.
+	// Commit size must be strictly less than reserve
+	// size otherwise reserve will be rounded up to a
+	// larger size, as verified with VMMap.
+
+	// Go code would be OK with 64k stacks, but we need larger stacks for cgo.
+	// That default stack reserve size affects only the main thread,
+	// for other threads we specify stack size in runtime explicitly
+	// (runtime knows whether cgo is enabled or not).
+	// If you change stack reserve sizes here,
+	// change STACKSIZE in runtime/cgo/gcc_windows_{386,amd64}.c as well.
+	if(!iscgo) {
+		set(SizeOfStackReserve, 0x00010000);
+		set(SizeOfStackCommit, 0x0000ffff);
+	} else {
+		set(SizeOfStackReserve, pe64 ? 0x00200000 : 0x00100000);
+		// account for 2 guard pages
+		set(SizeOfStackCommit, (pe64 ? 0x00200000 : 0x00100000) - 0x2000);
+	}
+	set(SizeOfHeapReserve, 0x00100000);
+	set(SizeOfHeapCommit, 0x00001000);
+	set(NumberOfRvaAndSizes, 16);
+
+	pewrite();
+}
diff --git a/src/cmd/ld/pe.h b/src/cmd/ld/pe.h
new file mode 100644
index 0000000..03ed8d8
--- /dev/null
+++ b/src/cmd/ld/pe.h
@@ -0,0 +1,179 @@
+// 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.
+
+typedef struct {
+	uint16 Machine;
+	uint16 NumberOfSections;
+	uint32 TimeDateStamp;
+	uint32 PointerToSymbolTable;
+	uint32 NumberOfSymbols;
+	uint16 SizeOfOptionalHeader;
+	uint16 Characteristics;
+} IMAGE_FILE_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 {
+	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 OriginalFirstThunk;
+	uint32 TimeDateStamp;
+	uint32 ForwarderChain;
+	uint32 Name;
+	uint32 FirstThunk;
+} IMAGE_IMPORT_DESCRIPTOR;
+
+typedef struct _IMAGE_EXPORT_DIRECTORY {
+	uint32 Characteristics;
+	uint32 TimeDateStamp;
+	uint16 MajorVersion;
+	uint16 MinorVersion;
+	uint32 Name;
+	uint32 Base;
+	uint32 NumberOfFunctions;
+	uint32 NumberOfNames;
+	uint32 AddressOfFunctions;
+	uint32 AddressOfNames;
+	uint32 AddressOfNameOrdinals;
+} IMAGE_EXPORT_DIRECTORY;
+
+#define PEBASE		0x00400000
+// SectionAlignment must be greater than or equal to FileAlignment.
+// The default is the page size for the architecture.
+#define PESECTALIGN	0x1000
+// FileAlignment should be a power of 2 between 512 and 64 K, inclusive.
+// The default is 512. If the SectionAlignment is less than
+// the architecture's page size, then FileAlignment must match SectionAlignment.
+#define PEFILEALIGN	(2<<8)
+extern	int32	PESECTHEADR;
+extern	int32	PEFILEHEADR;
+
+enum {
+	IMAGE_FILE_MACHINE_I386 = 0x14c,
+	IMAGE_FILE_MACHINE_AMD64 = 0x8664,
+
+	IMAGE_FILE_RELOCS_STRIPPED = 0x0001,
+	IMAGE_FILE_EXECUTABLE_IMAGE = 0x0002,
+	IMAGE_FILE_LARGE_ADDRESS_AWARE = 0x0020,
+	IMAGE_FILE_32BIT_MACHINE = 0x0100,
+	IMAGE_FILE_DEBUG_STRIPPED = 0x0200,
+
+	IMAGE_SCN_CNT_CODE = 0x00000020,
+	IMAGE_SCN_CNT_INITIALIZED_DATA = 0x00000040,
+	IMAGE_SCN_CNT_UNINITIALIZED_DATA = 0x00000080,
+	IMAGE_SCN_MEM_EXECUTE = 0x20000000,
+	IMAGE_SCN_MEM_READ = 0x40000000,
+	IMAGE_SCN_MEM_WRITE = 0x80000000,
+	IMAGE_SCN_MEM_DISCARDABLE = 0x2000000,
+
+	IMAGE_DIRECTORY_ENTRY_EXPORT = 0,
+	IMAGE_DIRECTORY_ENTRY_IMPORT = 1,
+	IMAGE_DIRECTORY_ENTRY_RESOURCE = 2,
+	IMAGE_DIRECTORY_ENTRY_EXCEPTION = 3,
+	IMAGE_DIRECTORY_ENTRY_SECURITY = 4,
+	IMAGE_DIRECTORY_ENTRY_BASERELOC = 5,
+	IMAGE_DIRECTORY_ENTRY_DEBUG = 6,
+	IMAGE_DIRECTORY_ENTRY_COPYRIGHT = 7,
+	IMAGE_DIRECTORY_ENTRY_ARCHITECTURE = 7,
+	IMAGE_DIRECTORY_ENTRY_GLOBALPTR = 8,
+	IMAGE_DIRECTORY_ENTRY_TLS = 9,
+	IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG = 10,
+	IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT = 11,
+	IMAGE_DIRECTORY_ENTRY_IAT = 12,
+	IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT = 13,
+	IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR = 14,
+
+	IMAGE_SUBSYSTEM_WINDOWS_GUI = 2,
+	IMAGE_SUBSYSTEM_WINDOWS_CUI = 3,
+};
+
+void peinit(void);
+void asmbpe(void);
+void dope(void);
+
+IMAGE_SECTION_HEADER* newPEDWARFSection(char *name, vlong size);
+
+// X64
+typedef struct {
+	uint16 Magic;
+	uint8  MajorLinkerVersion;
+	uint8  MinorLinkerVersion;
+	uint32 SizeOfCode;
+	uint32 SizeOfInitializedData;
+	uint32 SizeOfUninitializedData;
+	uint32 AddressOfEntryPoint;
+	uint32 BaseOfCode;
+	uint64 ImageBase;
+	uint32 SectionAlignment;
+	uint32 FileAlignment;
+	uint16 MajorOperatingSystemVersion;
+	uint16 MinorOperatingSystemVersion;
+	uint16 MajorImageVersion;
+	uint16 MinorImageVersion;
+	uint16 MajorSubsystemVersion;
+	uint16 MinorSubsystemVersion;
+	uint32 Win32VersionValue;
+	uint32 SizeOfImage;
+	uint32 SizeOfHeaders;
+	uint32 CheckSum;
+	uint16 Subsystem;
+	uint16 DllCharacteristics;
+	uint64 SizeOfStackReserve;
+	uint64 SizeOfStackCommit;
+	uint64 SizeOfHeapReserve;
+	uint64 SizeOfHeapCommit;
+	uint32 LoaderFlags;
+	uint32 NumberOfRvaAndSizes;
+	IMAGE_DATA_DIRECTORY DataDirectory[16];
+} PE64_IMAGE_OPTIONAL_HEADER;
+
+void setpersrc(LSym *sym);
diff --git a/src/cmd/ld/pobj.c b/src/cmd/ld/pobj.c
new file mode 100644
index 0000000..63460df
--- /dev/null
+++ b/src/cmd/ld/pobj.c
@@ -0,0 +1,207 @@
+// 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[])
+{
+	int i;
+
+	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;
+	
+	// For testing behavior of go command when tools crash.
+	// Undocumented, not in standard flag parser to avoid
+	// exposing in usage message.
+	for(i=1; i<argc; i++)
+		if(strcmp(argv[i], "-crash_for_testing") == 0)
+			*(volatile int*)0 = 0;
+	
+	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);
+	flagcount("C", "check Go calls to C code", &debug['C']);
+	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", "ld: linker to run in external mode", &extld);
+	flagstr("extldflags", "ldflags: flags for external linker", &extldflags);
+	flagcount("f", "ignore version mismatch", &debug['f']);
+	flagcount("g", "disable go package data checks", &debug['g']);
+	flagstr("installsuffix", "suffix: 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", "dir: 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));
+	}
+
+	checkgo();
+	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
new file mode 100644
index 0000000..156270c
--- /dev/null
+++ b/src/cmd/ld/symtab.c
@@ -0,0 +1,441 @@
+// 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.
+
+// Symbol table.
+
+#include	"l.h"
+#include	"../ld/lib.h"
+#include	"../ld/elf.h"
+
+static int maxelfstr;
+
+static int
+putelfstr(char *s)
+{
+	int off, n;
+	char *p, *q;
+
+	if(elfstrsize == 0 && s[0] != 0) {
+		// first entry must be empty string
+		putelfstr("");
+	}
+
+	n = strlen(s)+1;
+	if(elfstrsize+n > maxelfstr) {
+		maxelfstr = 2*(elfstrsize+n+(1<<20));
+		elfstrdat = realloc(elfstrdat, maxelfstr);
+	}
+	off = elfstrsize;
+	elfstrsize += n;
+	memmove(elfstrdat+off, s, n);
+	// 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;
+}
+
+static void
+putelfsyment(int off, vlong addr, vlong size, int info, int shndx, int other)
+{
+	switch(thechar) {
+	case '6':
+		LPUT(off);
+		cput(info);
+		cput(other);
+		WPUT(shndx);
+		VPUT(addr);
+		VPUT(size);
+		symsize += ELF64SYMSIZE;
+		break;
+	default:
+		LPUT(off);
+		LPUT(addr);
+		LPUT(size);
+		cput(info);
+		cput(other);
+		WPUT(shndx);
+		symsize += ELF32SYMSIZE;
+		break;
+	}
+}
+
+static int numelfsym = 1; // 0 is reserved
+static int elfbind;
+
+static void
+putelfsym(LSym *x, char *s, int t, vlong addr, vlong size, int ver, LSym *go)
+{
+	int bind, type, off;
+	LSym *xo;
+
+	USED(go);
+	switch(t) {
+	default:
+		return;
+	case 'T':
+		type = STT_FUNC;
+		break;
+	case 'D':
+		type = STT_OBJECT;
+		break;
+	case 'B':
+		type = STT_OBJECT;
+		break;
+	}
+	xo = x;
+	while(xo->outer != nil)
+		xo = xo->outer;
+	if(xo->sect == nil) {
+		ctxt->cursym = x;
+		diag("missing section in putelfsym");
+		return;
+	}
+	if(xo->sect->elfsect == nil) {
+		ctxt->cursym = x;
+		diag("missing ELF section in putelfsym");
+		return;
+	}
+
+	// One pass for each binding: STB_LOCAL, STB_GLOBAL,
+	// maybe one day STB_WEAK.
+	bind = STB_GLOBAL;
+	if(ver || (x->type & SHIDDEN))
+		bind = STB_LOCAL;
+
+	// In external linking mode, we have to invoke gcc with -rdynamic
+	// to get the exported symbols put into the dynamic symbol table.
+	// To avoid filling the dynamic table with lots of unnecessary symbols,
+	// mark all Go symbols local (not global) in the final executable.
+	if(linkmode == LinkExternal && !(x->cgoexport&CgoExportStatic))
+		bind = STB_LOCAL;
+
+	if(bind != elfbind)
+		return;
+
+	off = putelfstr(s);
+	if(linkmode == LinkExternal)
+		addr -= xo->sect->vaddr;
+	putelfsyment(off, addr, size, (bind<<4)|(type&0xf), xo->sect->elfsect->shnum, (x->type & SHIDDEN) ? 2 : 0);
+	x->elfsym = numelfsym++;
+}
+
+void
+putelfsectionsym(LSym* s, int shndx)
+{
+	putelfsyment(0, 0, 0, (STB_LOCAL<<4)|STT_SECTION, shndx, 0);
+	s->elfsym = numelfsym++;
+}
+
+void
+putelfsymshndx(vlong sympos, int shndx)
+{
+	vlong here;
+
+	here = cpos();
+	switch(thechar) {
+	case '6':
+		cseek(sympos+6);
+		break;
+	default:
+		cseek(sympos+14);
+		break;
+	}
+	WPUT(shndx);
+	cseek(here);
+}
+
+void
+asmelfsym(void)
+{
+	LSym *s;
+	char *name;
+
+	// the first symbol entry is reserved
+	putelfsyment(0, 0, 0, (STB_LOCAL<<4)|STT_NOTYPE, 0, 0);
+
+	dwarfaddelfsectionsyms();
+
+	elfbind = STB_LOCAL;
+	genasmsym(putelfsym);
+	
+	if(linkmode == LinkExternal && HEADTYPE != Hopenbsd) {
+		s = linklookup(ctxt, "runtime.tlsg", 0);
+		if(s->sect == nil) {
+			ctxt->cursym = nil;
+			diag("missing section for %s", s->name);
+			errorexit();
+		}
+		if (strcmp(goos, "android") == 0) {
+			// Android emulates runtime.tlsg as a regular variable.
+			putelfsyment(putelfstr(s->name), 0, s->size, (STB_LOCAL<<4)|STT_OBJECT, s->sect->elfsect->shnum, 0);
+		} else {
+			putelfsyment(putelfstr(s->name), 0, s->size, (STB_LOCAL<<4)|STT_TLS, s->sect->elfsect->shnum, 0);
+		}
+		s->elfsym = numelfsym++;
+	}
+
+	elfbind = STB_GLOBAL;
+	elfglobalsymndx = numelfsym;
+	genasmsym(putelfsym);
+	
+	for(s=ctxt->allsym; s!=S; s=s->allsym) {
+		if(s->type != SHOSTOBJ && !(s->type == SDYNIMPORT && s->reachable))
+			continue;
+		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(LSym *x, char *s, int t, vlong addr, vlong size, int ver, LSym *go)
+{
+	int i, l;
+
+	USED(go);
+	USED(ver);
+	USED(size);
+	USED(x);
+	switch(t) {
+	case 'T':
+	case 'L':
+	case 'D':
+	case 'B':
+		if(ver)
+			t += 'a' - 'A';
+	case 'a':
+	case 'p':
+	case 'f':
+	case 'z':
+	case 'Z':
+	case 'm':
+		l = 4;
+		if(HEADTYPE == Hplan9 && thechar == '6' && !debug['8']) {
+			lputb(addr>>32);
+			l = 8;
+		}
+		lputb(addr);
+		cput(t+0x80); /* 0x80 is variable length */
+
+		if(t == 'z' || t == 'Z') {
+			cput(s[0]);
+			for(i=1; s[i] != 0 || s[i+1] != 0; i += 2) {
+				cput(s[i]);
+				cput(s[i+1]);
+			}
+			cput(0);
+			cput(0);
+			i++;
+		} else {
+			/* skip the '<' in filenames */
+			if(t == 'f')
+				s++;
+			for(i=0; s[i]; i++)
+				cput(s[i]);
+			cput(0);
+		}
+		symsize += l + 1 + i + 1;
+		break;
+	default:
+		return;
+	};
+}
+
+void
+asmplan9sym(void)
+{
+	genasmsym(putplan9sym);
+}
+
+static LSym *symt;
+
+void
+wputl(ushort w)
+{
+	cput(w);
+	cput(w>>8);
+}
+
+void
+wputb(ushort w)
+{
+	cput(w>>8);
+	cput(w);
+}
+
+void
+lputb(int32 l)
+{
+	cput(l>>24);
+	cput(l>>16);
+	cput(l>>8);
+	cput(l);
+}
+
+void
+lputl(int32 l)
+{
+	cput(l);
+	cput(l>>8);
+	cput(l>>16);
+	cput(l>>24);
+}
+
+void
+vputb(uint64 v)
+{
+	lputb(v>>32);
+	lputb(v);
+}
+
+void
+vputl(uint64 v)
+{
+	lputl(v);
+	lputl(v >> 32);
+}
+
+void
+symtab(void)
+{
+	LSym *s, *symtype, *symtypelink, *symgostring, *symgofunc;
+
+	dosymtype();
+
+	// Define these so that they'll get put into the symbol table.
+	// data.c:/^address will provide the actual values.
+	xdefine("runtime.text", STEXT, 0);
+	xdefine("runtime.etext", STEXT, 0);
+	xdefine("runtime.typelink", SRODATA, 0);
+	xdefine("runtime.etypelink", SRODATA, 0);
+	xdefine("runtime.rodata", SRODATA, 0);
+	xdefine("runtime.erodata", SRODATA, 0);
+	xdefine("runtime.noptrdata", SNOPTRDATA, 0);
+	xdefine("runtime.enoptrdata", SNOPTRDATA, 0);
+	xdefine("runtime.data", SDATA, 0);
+	xdefine("runtime.edata", SDATA, 0);
+	xdefine("runtime.bss", SBSS, 0);
+	xdefine("runtime.ebss", SBSS, 0);
+	xdefine("runtime.noptrbss", SNOPTRBSS, 0);
+	xdefine("runtime.enoptrbss", SNOPTRBSS, 0);
+	xdefine("runtime.end", SBSS, 0);
+	xdefine("runtime.epclntab", SRODATA, 0);
+	xdefine("runtime.esymtab", SRODATA, 0);
+
+	// garbage collection symbols
+	s = linklookup(ctxt, "runtime.gcdata", 0);
+	s->type = SRODATA;
+	s->size = 0;
+	s->reachable = 1;
+	xdefine("runtime.egcdata", SRODATA, 0);
+
+	s = linklookup(ctxt, "runtime.gcbss", 0);
+	s->type = SRODATA;
+	s->size = 0;
+	s->reachable = 1;
+	xdefine("runtime.egcbss", SRODATA, 0);
+
+	// pseudo-symbols to mark locations of type, string, and go string data.
+	s = linklookup(ctxt, "type.*", 0);
+	s->type = STYPE;
+	s->size = 0;
+	s->reachable = 1;
+	symtype = s;
+
+	s = linklookup(ctxt, "go.string.*", 0);
+	s->type = SGOSTRING;
+	s->size = 0;
+	s->reachable = 1;
+	symgostring = s;
+	
+	s = linklookup(ctxt, "go.func.*", 0);
+	s->type = SGOFUNC;
+	s->size = 0;
+	s->reachable = 1;
+	symgofunc = s;
+	
+	symtypelink = linklookup(ctxt, "runtime.typelink", 0);
+
+	symt = linklookup(ctxt, "runtime.symtab", 0);
+	symt->type = SSYMTAB;
+	symt->size = 0;
+	symt->reachable = 1;
+
+	// assign specific types so that they sort together.
+	// within a type they sort by size, so the .* symbols
+	// just defined above will be first.
+	// hide the specific symbols.
+	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) {
+			s->type = STYPE;
+			s->hide = 1;
+			s->outer = symtype;
+		}
+		if(strncmp(s->name, "go.typelink.", 12) == 0) {
+			s->type = STYPELINK;
+			s->hide = 1;
+			s->outer = symtypelink;
+		}
+		if(strncmp(s->name, "go.string.", 10) == 0) {
+			s->type = SGOSTRING;
+			s->hide = 1;
+			s->outer = symgostring;
+		}
+		if(strncmp(s->name, "go.func.", 8) == 0) {
+			s->type = SGOFUNC;
+			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);
+		}
+	}
+}
diff --git a/src/cmd/ld/textflag.h b/src/cmd/ld/textflag.h
new file mode 100644
index 0000000..0ee8b5f
--- /dev/null
+++ b/src/cmd/ld/textflag.h
@@ -0,0 +1,36 @@
+// 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 defines flags attached to various functions
+// and data objects.  The compilers, assemblers, and linker must
+// all agree on these values.
+
+// Don't profile the marked routine.  This flag is deprecated.
+#define NOPROF	1
+// It is ok for the linker to get multiple of these symbols.  It will
+// pick one of the duplicates to use.
+#define DUPOK	2
+// Don't insert stack check preamble.
+#define NOSPLIT	4
+// Put this data in a read-only section.
+#define RODATA	8
+// This data contains no pointers.
+#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
+
+/*c2go
+enum
+{
+	NOPROF = 1,
+	DUPOK = 2,
+	NOSPLIT = 4,
+	RODATA = 8,
+	NOPTR = 16,
+	WRAPPER = 32,
+	NEEDCTXT = 64,
+};
+*/
diff --git a/src/cmd/nm/nm_test.go b/src/cmd/nm/nm_test.go
index 602a288..cb555d8 100644
--- a/src/cmd/nm/nm_test.go
+++ b/src/cmd/nm/nm_test.go
@@ -8,7 +8,6 @@ import (
 	"bufio"
 	"bytes"
 	"fmt"
-	"internal/testenv"
 	"io/ioutil"
 	"os"
 	"os/exec"
@@ -56,7 +55,10 @@ func checkSymbols(t *testing.T, nmoutput []byte) {
 }
 
 func TestNM(t *testing.T) {
-	testenv.MustHaveGoBuild(t)
+	switch runtime.GOOS {
+	case "android", "nacl":
+		t.Skipf("skipping on %s", runtime.GOOS)
+	}
 
 	tmpDir, err := ioutil.TempDir("", "TestNM")
 	if err != nil {
diff --git a/src/cmd/objdump/main.go b/src/cmd/objdump/main.go
index 8bf9e4e..708a853 100644
--- a/src/cmd/objdump/main.go
+++ b/src/cmd/objdump/main.go
@@ -80,7 +80,7 @@ func main() {
 
 	dis, err := f.Disasm()
 	if err != nil {
-		log.Fatalf("disassemble %s: %v", flag.Arg(0), err)
+		log.Fatal("disassemble %s: %v", flag.Arg(0), err)
 	}
 
 	switch flag.NArg() {
diff --git a/src/cmd/objdump/objdump_test.go b/src/cmd/objdump/objdump_test.go
index b6c339b..2bb7466 100644
--- a/src/cmd/objdump/objdump_test.go
+++ b/src/cmd/objdump/objdump_test.go
@@ -5,8 +5,6 @@
 package main
 
 import (
-	"go/build"
-	"internal/testenv"
 	"io/ioutil"
 	"os"
 	"os/exec"
@@ -17,7 +15,10 @@ import (
 )
 
 func buildObjdump(t *testing.T) (tmp, exe string) {
-	testenv.MustHaveGoBuild(t)
+	switch runtime.GOOS {
+	case "android", "nacl":
+		t.Skipf("skipping on %s", runtime.GOOS)
+	}
 
 	tmp, err := ioutil.TempDir("", "TestObjDump")
 	if err != nil {
@@ -100,12 +101,6 @@ func testDisasm(t *testing.T, flags ...string) {
 }
 
 func TestDisasm(t *testing.T) {
-	switch runtime.GOARCH {
-	case "ppc64", "ppc64le":
-		t.Skipf("skipping on %s, issue 9039", runtime.GOARCH)
-	case "arm64":
-		t.Skipf("skipping on %s, issue 10106", runtime.GOARCH)
-	}
 	testDisasm(t)
 }
 
@@ -114,18 +109,5 @@ func TestDisasmExtld(t *testing.T) {
 	case "plan9", "windows":
 		t.Skipf("skipping on %s", runtime.GOOS)
 	}
-	switch runtime.GOARCH {
-	case "ppc64", "ppc64le":
-		t.Skipf("skipping on %s, no support for external linking, issue 9038", runtime.GOARCH)
-	case "arm64":
-		t.Skipf("skipping on %s, issue 10106", runtime.GOARCH)
-	}
-	// TODO(jsing): Reenable once openbsd/arm has external linking support.
-	if runtime.GOOS == "openbsd" && runtime.GOARCH == "arm" {
-		t.Skip("skipping on openbsd/arm, no support for external linking, issue 10619")
-	}
-	if !build.Default.CgoEnabled {
-		t.Skip("skipping because cgo is not enabled")
-	}
 	testDisasm(t, "-ldflags=-linkmode=external")
 }
diff --git a/src/cmd/pack/pack.go b/src/cmd/pack/pack.go
index f65ae0c..ffb2d61 100644
--- a/src/cmd/pack/pack.go
+++ b/src/cmd/pack/pack.go
@@ -183,7 +183,7 @@ func existingArchive(name string) bool {
 		if os.IsNotExist(err) {
 			return false
 		}
-		log.Fatalf("cannot open file: %s", err)
+		log.Fatal("cannot open file: %s", err)
 	}
 	checkHeader(fd)
 	fd.Close()
@@ -196,7 +196,7 @@ func checkHeader(fd *os.File) {
 	buf := make([]byte, len(arHeader))
 	_, err := io.ReadFull(fd, buf)
 	if err != nil || string(buf) != arHeader {
-		log.Fatalf("%s is not an archive: bad header", fd.Name())
+		log.Fatal("%s is not an archive: bad header", fd.Name())
 	}
 }
 
diff --git a/src/cmd/pack/pack_test.go b/src/cmd/pack/pack_test.go
index c305a87..cf6121f 100644
--- a/src/cmd/pack/pack_test.go
+++ b/src/cmd/pack/pack_test.go
@@ -8,12 +8,13 @@ import (
 	"bufio"
 	"bytes"
 	"fmt"
-	"internal/testenv"
 	"io"
 	"io/ioutil"
 	"os"
 	"os/exec"
 	"path/filepath"
+	"regexp"
+	"runtime"
 	"testing"
 	"time"
 	"unicode/utf8"
@@ -198,7 +199,10 @@ func TestExtract(t *testing.T) {
 
 // Test that pack-created archives can be understood by the tools.
 func TestHello(t *testing.T) {
-	testenv.MustHaveGoBuild(t)
+	switch runtime.GOOS {
+	case "android", "nacl":
+		t.Skipf("skipping on %s", runtime.GOOS)
+	}
 
 	dir := tmpDir(t)
 	defer os.RemoveAll(dir)
@@ -214,14 +218,16 @@ func TestHello(t *testing.T) {
 		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", "compile", "hello.go")
-	run("./pack", "grc", "hello.a", "hello.o")
-	run("go", "tool", "link", "-o", "a.out", "hello.a")
+	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")
@@ -230,7 +236,10 @@ func TestHello(t *testing.T) {
 
 // Test that pack works with very long lines in PKGDEF.
 func TestLargeDefs(t *testing.T) {
-	testenv.MustHaveGoBuild(t)
+	switch runtime.GOOS {
+	case "android", "nacl":
+		t.Skipf("skipping on %s", runtime.GOOS)
+	}
 
 	dir := tmpDir(t)
 	defer os.RemoveAll(dir)
@@ -249,7 +258,7 @@ func TestLargeDefs(t *testing.T) {
 	}
 
 	printf("package large\n\ntype T struct {\n")
-	for i := 0; i < 1000; i++ {
+	for i := 0; i < 10000; i++ {
 		printf("f%d int `tag:\"", i)
 		for j := 0; j < 100; j++ {
 			printf("t%d=%d,", j, j)
@@ -278,15 +287,17 @@ func TestLargeDefs(t *testing.T) {
 		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", "compile", "large.go")
-	run("./pack", "grc", "large.a", "large.o")
-	run("go", "tool", "compile", "-I", ".", "main.go")
-	run("go", "tool", "link", "-L", ".", "-o", "a.out", "main.o")
+	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")
@@ -304,6 +315,20 @@ func doRun(t *testing.T, dir string, args ...string) string {
 	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{
diff --git a/src/cmd/pprof/doc.go b/src/cmd/pprof/doc.go
index 1e094fe..c6ff11d 100644
--- a/src/cmd/pprof/doc.go
+++ b/src/cmd/pprof/doc.go
@@ -8,5 +8,5 @@
 //
 //	go tool pprof binary profile
 //
-// For more information, see https://blog.golang.org/profiling-go-programs.
+// For more information, see http://blog.golang.org/profiling-go-programs.
 package main
diff --git a/src/cmd/pprof/internal/commands/commands.go b/src/cmd/pprof/internal/commands/commands.go
index 9aeee57..51397a3 100644
--- a/src/cmd/pprof/internal/commands/commands.go
+++ b/src/cmd/pprof/internal/commands/commands.go
@@ -9,12 +9,10 @@ import (
 	"bytes"
 	"fmt"
 	"io"
-	"io/ioutil"
 	"os"
 	"os/exec"
 	"runtime"
 	"strings"
-	"time"
 
 	"cmd/pprof/internal/plugin"
 	"cmd/pprof/internal/report"
@@ -44,7 +42,7 @@ type Completer func(prefix string) string
 type PostProcessor func(input *bytes.Buffer, output io.Writer, ui plugin.UI) error
 
 // PProf returns the basic pprof report-generation commands
-func PProf(c Completer, interactive **bool) Commands {
+func PProf(c Completer, interactive **bool, svgpan **string) Commands {
 	return Commands{
 		// Commands that require no post-processing.
 		"tags":   {nil, report.Tags, nil, false, "Outputs all tags in the profile"},
@@ -68,13 +66,13 @@ func PProf(c Completer, interactive **bool) Commands {
 		"ps":  {c, report.Dot, invokeDot("ps"), false, "Outputs a graph in PS format"},
 
 		// Save SVG output into a file after including svgpan library
-		"svg": {c, report.Dot, saveSVGToFile(), false, "Outputs a graph in SVG format"},
+		"svg": {c, report.Dot, saveSVGToFile(svgpan), false, "Outputs a graph in SVG format"},
 
 		// Visualize postprocessed dot output
 		"eog":    {c, report.Dot, invokeVisualizer(interactive, invokeDot("svg"), "svg", []string{"eog"}), false, "Visualize graph through eog"},
 		"evince": {c, report.Dot, invokeVisualizer(interactive, invokeDot("pdf"), "pdf", []string{"evince"}), false, "Visualize graph through evince"},
 		"gv":     {c, report.Dot, invokeVisualizer(interactive, invokeDot("ps"), "ps", []string{"gv --noantialias"}), false, "Visualize graph through gv"},
-		"web":    {c, report.Dot, invokeVisualizer(interactive, saveSVGToFile(), "svg", browsers()), false, "Visualize graph through web browser"},
+		"web":    {c, report.Dot, invokeVisualizer(interactive, saveSVGToFile(svgpan), "svg", browsers()), false, "Visualize graph through web browser"},
 
 		// Visualize HTML directly generated by report.
 		"weblist": {c, report.WebList, invokeVisualizer(interactive, awayFromTTY("html"), "html", browsers()), true, "Output annotated source in HTML for functions matching regexp or address"},
@@ -84,10 +82,7 @@ func PProf(c Completer, interactive **bool) Commands {
 // browsers returns a list of commands to attempt for web visualization
 // on the current platform
 func browsers() []string {
-	var cmds []string
-	if exe := os.Getenv("BROWSER"); exe != "" {
-		cmds = append(cmds, exe)
-	}
+	cmds := []string{"chrome", "google-chrome", "firefox"}
 	switch runtime.GOOS {
 	case "darwin":
 		cmds = append(cmds, "/usr/bin/open")
@@ -96,7 +91,6 @@ func browsers() []string {
 	default:
 		cmds = append(cmds, "xdg-open")
 	}
-	cmds = append(cmds, "chrome", "google-chrome", "firefox")
 	return cmds
 }
 
@@ -175,38 +169,21 @@ func invokeDot(format string) PostProcessor {
 	}
 }
 
-func saveSVGToFile() PostProcessor {
+func saveSVGToFile(svgpan **string) PostProcessor {
 	generateSVG := invokeDot("svg")
 	divert := awayFromTTY("svg")
 	return func(input *bytes.Buffer, output io.Writer, ui plugin.UI) error {
 		baseSVG := &bytes.Buffer{}
 		generateSVG(input, baseSVG, ui)
 		massaged := &bytes.Buffer{}
-		fmt.Fprint(massaged, svg.Massage(*baseSVG))
+		fmt.Fprint(massaged, svg.Massage(*baseSVG, **svgpan))
 		return divert(massaged, output, ui)
 	}
 }
 
-var vizTmpDir string
-
-func makeVizTmpDir() error {
-	if vizTmpDir != "" {
-		return nil
-	}
-	name, err := ioutil.TempDir("", "pprof-")
-	if err != nil {
-		return err
-	}
-	vizTmpDir = name
-	return nil
-}
-
 func invokeVisualizer(interactive **bool, format PostProcessor, suffix string, visualizers []string) PostProcessor {
 	return func(input *bytes.Buffer, output io.Writer, ui plugin.UI) error {
-		if err := makeVizTmpDir(); err != nil {
-			return err
-		}
-		tempFile, err := tempfile.New(vizTmpDir, "pprof", "."+suffix)
+		tempFile, err := tempfile.New(os.Getenv("PPROF_TMPDIR"), "pprof", "."+suffix)
 		if err != nil {
 			return err
 		}
@@ -225,11 +202,6 @@ func invokeVisualizer(interactive **bool, format PostProcessor, suffix string, v
 			viewer := exec.Command(args[0], append(args[1:], tempFile.Name())...)
 			viewer.Stderr = os.Stderr
 			if err = viewer.Start(); err == nil {
-				// The viewer might just send a message to another program
-				// to open the file. Give that program a little time to open the
-				// file before we remove it.
-				time.Sleep(1 * time.Second)
-
 				if !**interactive {
 					// In command-line mode, wait for the viewer to be closed
 					// before proceeding
diff --git a/src/cmd/pprof/internal/driver/driver.go b/src/cmd/pprof/internal/driver/driver.go
index df6a2d1..68b5d1b 100644
--- a/src/cmd/pprof/internal/driver/driver.go
+++ b/src/cmd/pprof/internal/driver/driver.go
@@ -106,9 +106,7 @@ func PProf(flagset plugin.FlagSet, fetch plugin.Fetcher, sym plugin.Symbolizer,
 		return err
 	}
 
-	if !*f.flagRuntime {
-		prof.RemoveUninteresting()
-	}
+	prof.RemoveUninteresting()
 
 	if *f.flagInteractive {
 		return interactive(prof, obj, ui, f)
@@ -429,6 +427,7 @@ type flags struct {
 	flagCommands      map[string]*bool   // pprof commands without parameters
 	flagParamCommands map[string]*string // pprof commands with parameters
 
+	flagSVGPan *string // URL to fetch the SVG Pan library
 	flagOutput *string // Output file name
 
 	flagCum      *bool // Sort by cumulative data
@@ -446,7 +445,6 @@ type flags struct {
 	flagNodeFraction *float64 // Hide nodes below <f>*total
 	flagEdgeFraction *float64 // Hide edges below <f>*total
 	flagTrim         *bool    // Set to false to ignore NodeCount/*Fraction
-	flagRuntime      *bool    // Show runtime call frames in memory profiles
 	flagFocus        *string  // Restricts to paths going through a node matching regexp
 	flagIgnore       *string  // Skips paths going through any nodes matching regexp
 	flagHide         *string  // Skips sample locations matching regexp
@@ -624,6 +622,7 @@ func getFlags(flag plugin.FlagSet, overrides commands.Commands, ui plugin.UI) (*
 		flagBase:         flag.String("base", "", "Source for base profile for comparison"),
 		flagDropNegative: flag.Bool("drop_negative", false, "Ignore negative differences"),
 
+		flagSVGPan: flag.String("svgpan", "https://www.cyberz.org/projects/SVGPan/SVGPan.js", "URL for SVGPan Library"),
 		// Data sorting criteria.
 		flagCum: flag.Bool("cum", false, "Sort by cumulative data"),
 		// Graph handling options.
@@ -641,7 +640,6 @@ func getFlags(flag plugin.FlagSet, overrides commands.Commands, ui plugin.UI) (*
 		flagNodeFraction: flag.Float64("nodefraction", 0.005, "Hide nodes below <f>*total"),
 		flagEdgeFraction: flag.Float64("edgefraction", 0.001, "Hide edges below <f>*total"),
 		flagTrim:         flag.Bool("trim", true, "Honor nodefraction/edgefraction/nodecount defaults"),
-		flagRuntime:      flag.Bool("runtime", false, "Show runtime call frames in memory profiles"),
 		flagFocus:        flag.String("focus", "", "Restricts to paths going through a node matching regexp"),
 		flagIgnore:       flag.String("ignore", "", "Skips paths going through any nodes matching regexp"),
 		flagHide:         flag.String("hide", "", "Skips nodes matching regexp"),
@@ -668,7 +666,8 @@ func getFlags(flag plugin.FlagSet, overrides commands.Commands, ui plugin.UI) (*
 
 	// Flags used during command processing
 	interactive := &f.flagInteractive
-	f.commands = commands.PProf(functionCompleter, interactive)
+	svgpan := &f.flagSVGPan
+	f.commands = commands.PProf(functionCompleter, interactive, svgpan)
 
 	// Override commands
 	for name, cmd := range overrides {
@@ -878,7 +877,6 @@ var usageMsg = "Output file parameters (for file-based output formats):\n" +
 	"  -contentions      Display number of delays at each region\n" +
 	"  -mean_delay       Display mean delay at each region\n" +
 	"Filtering options:\n" +
-	"  -runtime          Show runtime call frames in memory profiles\n" +
 	"  -focus=r          Restricts to paths going through a node matching regexp\n" +
 	"  -ignore=r         Skips paths going through any nodes matching regexp\n" +
 	"  -tagfocus=r       Restrict to samples tagged with key:value matching regexp\n" +
@@ -888,13 +886,14 @@ var usageMsg = "Output file parameters (for file-based output formats):\n" +
 	"Miscellaneous:\n" +
 	"  -call_tree        Generate a context-sensitive call tree\n" +
 	"  -unit=u           Convert all samples to unit u for display\n" +
+	"  -show_bytes       Display all space in bytes\n" +
 	"  -divide_by=f      Scale all samples by dividing them by f\n" +
 	"  -buildid=id       Override build id for main binary in profile\n" +
 	"  -tools=path       Search path for object-level tools\n" +
 	"  -help             This message"
 
 var usageMsgVars = "Environment Variables:\n" +
-	"   PPROF_TMPDIR       Location for saved profiles (default $HOME/pprof)\n" +
+	"   PPROF_TMPDIR       Location for temporary files (default $HOME/pprof)\n" +
 	"   PPROF_TOOLS        Search path for object-level tools\n" +
 	"   PPROF_BINARY_PATH  Search path for local binary files\n" +
 	"                      default: $HOME/pprof/binaries\n" +
@@ -1010,10 +1009,6 @@ func generate(interactive bool, prof *profile.Profile, obj plugin.ObjTool, ui pl
 		w = outputFile
 	}
 
-	if prof.Empty() {
-		return fmt.Errorf("profile is empty")
-	}
-
 	value, stype, unit := sampleFormat(prof, f)
 	o.SampleType = stype
 	rpt := report.New(prof, *o, value, unit)
diff --git a/src/cmd/pprof/internal/profile/encode.go b/src/cmd/pprof/internal/profile/encode.go
index 9e66998..455aca2 100644
--- a/src/cmd/pprof/internal/profile/encode.go
+++ b/src/cmd/pprof/internal/profile/encode.go
@@ -162,7 +162,7 @@ var profileDecoder = []decoder{
 		pp.Location = append(pp.Location, x)
 		return decodeMessage(b, x)
 	},
-	// repeated Function function = 5
+	// repeasted Function function = 5
 	func(b *buffer, m message) error {
 		x := new(Function)
 		pp := m.(*Profile)
diff --git a/src/cmd/pprof/internal/profile/filter.go b/src/cmd/pprof/internal/profile/filter.go
index 1baa096..903616a 100644
--- a/src/cmd/pprof/internal/profile/filter.go
+++ b/src/cmd/pprof/internal/profile/filter.go
@@ -3,7 +3,6 @@
 // license that can be found in the LICENSE file.
 
 // Implements methods to filter samples from profiles.
-
 package profile
 
 import "regexp"
diff --git a/src/cmd/pprof/internal/profile/legacy_profile.go b/src/cmd/pprof/internal/profile/legacy_profile.go
index e4c92cd..bfc8110 100644
--- a/src/cmd/pprof/internal/profile/legacy_profile.go
+++ b/src/cmd/pprof/internal/profile/legacy_profile.go
@@ -554,10 +554,9 @@ func parseHeap(b []byte) (p *Profile, err error) {
 			}
 		}
 
-		if isSpaceOrComment(l) {
+		if l = strings.TrimSpace(l); l == "" {
 			continue
 		}
-		l = strings.TrimSpace(l)
 
 		if sectionTrigger(l) != unrecognizedSection {
 			break
diff --git a/src/cmd/pprof/internal/profile/profile.go b/src/cmd/pprof/internal/profile/profile.go
index 6d175bf..7ee58ee 100644
--- a/src/cmd/pprof/internal/profile/profile.go
+++ b/src/cmd/pprof/internal/profile/profile.go
@@ -125,11 +125,11 @@ func Parse(r io.Reader) (*Profile, error) {
 
 	var p *Profile
 	if len(orig) >= 2 && orig[0] == 0x1f && orig[1] == 0x8b {
-		gz, err := gzip.NewReader(bytes.NewBuffer(orig))
-		if err != nil {
-			return nil, fmt.Errorf("decompressing profile: %v", err)
+		var data []byte
+
+		if gz, err := gzip.NewReader(bytes.NewBuffer(orig)); err == nil {
+			data, err = ioutil.ReadAll(gz)
 		}
-		data, err := ioutil.ReadAll(gz)
 		if err != nil {
 			return nil, fmt.Errorf("decompressing profile: %v", err)
 		}
@@ -565,8 +565,3 @@ func (p *Profile) Demangle(d Demangler) error {
 	}
 	return nil
 }
-
-// Empty returns true if the profile contains no samples.
-func (p *Profile) Empty() bool {
-	return len(p.Sample) == 0
-}
diff --git a/src/cmd/pprof/internal/report/report.go b/src/cmd/pprof/internal/report/report.go
index 586f41d..e5977fd 100644
--- a/src/cmd/pprof/internal/report/report.go
+++ b/src/cmd/pprof/internal/report/report.go
@@ -1531,7 +1531,7 @@ func memoryLabel(value int64, fromUnit, toUnit string) (v float64, u string, ok
 		output, toUnit = float64(value)/1024, "kB"
 	case "mb", "mbyte", "megabyte":
 		output, toUnit = float64(value)/(1024*1024), "MB"
-	case "gb", "gbyte", "gigabyte":
+	case "gb", "gbyte", "giggabyte":
 		output, toUnit = float64(value)/(1024*1024*1024), "GB"
 	}
 	return output, toUnit, true
diff --git a/src/cmd/pprof/internal/report/source.go b/src/cmd/pprof/internal/report/source.go
index 73ae1b4..57300dd 100644
--- a/src/cmd/pprof/internal/report/source.go
+++ b/src/cmd/pprof/internal/report/source.go
@@ -358,13 +358,9 @@ func getFunctionSource(fun, file string, fns nodes, start, end int) (nodes, stri
 	for {
 		line, err := buf.ReadString('\n')
 		if err != nil {
-			if err != io.EOF {
+			if line == "" || err != io.EOF {
 				return nil, file, err
 			}
-			if line == "" {
-				// end was at or past EOF; that's okay
-				break
-			}
 		}
 		if lineno >= start {
 			flat, cum := sumNodes(lineNodes[lineno])
diff --git a/src/cmd/pprof/internal/svg/svg.go b/src/cmd/pprof/internal/svg/svg.go
index 04f6ff1..aa65a1a 100644
--- a/src/cmd/pprof/internal/svg/svg.go
+++ b/src/cmd/pprof/internal/svg/svg.go
@@ -17,15 +17,18 @@ var (
 	svgClose = regexp.MustCompile(`</svg>`)
 )
 
-// Massage enhances the SVG output from DOT to provide better
+// Massage enhances the SVG output from DOT to provide bettern
 // panning inside a web browser. It uses the SVGPan library, which is
-// included directly.
-func Massage(in bytes.Buffer) string {
+// accessed through the svgPan URL.
+func Massage(in bytes.Buffer, svgPan string) string {
 	svg := string(in.Bytes())
 
 	// Work around for dot bug which misses quoting some ampersands,
 	// resulting on unparsable SVG.
 	svg = strings.Replace(svg, "&;", "&;", -1)
+	if svgPan == "" {
+		return svg
+	}
 
 	//Dot's SVG output is
 	//
@@ -40,7 +43,8 @@ func Massage(in bytes.Buffer) string {
 	//
 	//    <svg width="100%" height="100%"
 	//     xmlns=...>
-	//    <script>...</script>
+	//    <script xlink:href=" ...$svgpan.. "/>
+
 	//    <g id="viewport" transform="translate(0,0)">
 	//    <g id="graph0" transform="...">
 	//    ...
@@ -56,7 +60,7 @@ func Massage(in bytes.Buffer) string {
 
 	if loc := graphId.FindStringIndex(svg); loc != nil {
 		svg = svg[:loc[0]] +
-			`<script type="text/ecmascript"><![CDATA[` + svgPanJS + `]]></script>` +
+			`<script xlink:href="` + svgPan + `"/>` +
 			`<g id="viewport" transform="scale(0.5,0.5) translate(0,0)">` +
 			svg[loc[0]:]
 	}
diff --git a/src/cmd/yacc/doc.go b/src/cmd/yacc/doc.go
index 328d87b..702c9f0 100644
--- a/src/cmd/yacc/doc.go
+++ b/src/cmd/yacc/doc.go
@@ -20,12 +20,12 @@ written in C and documented at
 Adepts of the original yacc will have no trouble adapting to this
 form of the tool.
 
-The directory $GOROOT/src/cmd/yacc/testdata/expr is a yacc program
+The directory $GOROOT/cmd/yacc/testdata/expr is a yacc program
 for a very simple expression parser. See expr.y and main.go in that
 directory for examples of how to write and build yacc programs.
 
-The generated parser is reentrant. The parsing function yyParse expects
-to be given an argument that conforms to the following interface:
+The generated parser is reentrant. Parse expects to be given an
+argument that conforms to the following interface:
 
 	type yyLexer interface {
 		Lex(lval *yySymType) int
@@ -36,27 +36,8 @@ Lex should return the token identifier, and place other token
 information in lval (which replaces the usual yylval).
 Error is equivalent to yyerror in the original yacc.
 
-Code inside the grammar actions may refer to the variable yylex,
-which holds the yyLexer passed to yyParse.
-
-Clients that need to understand more about the parser state can
-create the parser separately from invoking it. The function yyNewParser
-returns a yyParser conforming to the following interface:
-
-	type yyParser interface {
-		Parse(yyLex) int
-		Lookahead() int
-	}
-
-Parse runs the parser; the top-level call yyParse(yylex) is equivalent
-to yyNewParser().Parse(yylex).
-
-Lookahead can be called during grammar actions to read (but not consume)
-the value of the current lookahead token, as returned by yylex.Lex.
-If there is no current lookahead token (because the parser has not called Lex
-or has consumed the token returned by the most recent call to Lex),
-Lookahead returns -1. Calling Lookahead is equivalent to reading
-yychar from within in a grammar action.
+Code inside the parser may refer to the variable yylex,
+which holds the yyLexer passed to Parse.
 
 Multiple grammars compiled into a single program should be placed in
 distinct packages.  If that is impossible, the "-p prefix" flag to
diff --git a/src/cmd/yacc/testdata/expr/expr.y b/src/cmd/yacc/testdata/expr/expr.y
index bb8e9bf..721b1c9 100644
--- a/src/cmd/yacc/testdata/expr/expr.y
+++ b/src/cmd/yacc/testdata/expr/expr.y
@@ -56,29 +56,29 @@ expr:
 	}
 |	'-' expr
 	{
-		$$ = $2.Neg($2)
+		$$.Neg($2)
 	}
 
 expr1:
 	expr2
 |	expr1 '+' expr2
 	{
-		$$ = $1.Add($1, $3)
+		$$.Add($1, $3)
 	}
 |	expr1 '-' expr2
 	{
-		$$ = $1.Sub($1, $3)
+		$$.Sub($1, $3)
 	}
 
 expr2:
 	expr3
 |	expr2 '*' expr3
 	{
-		$$ = $1.Mul($1, $3)
+		$$.Mul($1, $3)
 	}
 |	expr2 '/' expr3
 	{
-		$$ = $1.Quo($1, $3)
+		$$.Quo($1, $3)
 	}
 
 expr3:
diff --git a/src/cmd/yacc/testdata/expr/main.go b/src/cmd/yacc/testdata/expr/main.go
index 37f0023..8d5b691 100644
--- a/src/cmd/yacc/testdata/expr/main.go
+++ b/src/cmd/yacc/testdata/expr/main.go
@@ -11,5 +11,5 @@
 //go:generate yacc -o expr.go -p "expr" expr.y
 
 // Expr is a simple expression evaluator that serves as a working example of
-// how to use Go's yacc implementation.
+// how to use Go's yacc implemenation.
 package main
diff --git a/src/cmd/yacc/yacc.go b/src/cmd/yacc/yacc.go
index 4f83f50..4dba376 100644
--- a/src/cmd/yacc/yacc.go
+++ b/src/cmd/yacc/yacc.go
@@ -128,7 +128,6 @@ const (
 	TYPEDEF
 	TYPENAME
 	UNION
-	ERROR
 )
 
 const ENDFILE = 0
@@ -326,24 +325,8 @@ var resrv = []Resrv{
 	{"type", TYPEDEF},
 	{"union", UNION},
 	{"struct", UNION},
-	{"error", ERROR},
 }
 
-type Error struct {
-	lineno int
-	tokens []string
-	msg    string
-}
-
-var errors []Error
-
-type Row struct {
-	actions       []int
-	defaultAction int
-}
-
-var stateTable []Row
-
 var zznewstate = 0
 
 const EOF = -1
@@ -419,27 +402,6 @@ outer:
 			}
 			start = chfind(1, tokname)
 
-		case ERROR:
-			lno := lineno
-			var tokens []string
-			for {
-				t := gettok()
-				if t == ':' {
-					break
-				}
-				if t != IDENTIFIER && t != IDENTCOLON {
-					errorf("bad syntax in %%error")
-				}
-				tokens = append(tokens, tokname)
-				if t == IDENTCOLON {
-					break
-				}
-			}
-			if gettok() != IDENTIFIER {
-				errorf("bad syntax in %%error")
-			}
-			errors = append(errors, Error{lno, tokens, tokname})
-
 		case TYPEDEF:
 			t = gettok()
 			if t != TYPENAME {
@@ -545,6 +507,29 @@ outer:
 		errorf("unexpected EOF before %%")
 	}
 
+	// put out non-literal terminals
+	for i := TOKSTART; i <= ntokens; i++ {
+		// non-literals
+		if !tokset[i].noconst {
+			fmt.Fprintf(ftable, "const %v = %v\n", tokset[i].name, tokset[i].value)
+		}
+	}
+
+	// put out names of token names
+	ftable.WriteRune('\n')
+	fmt.Fprintf(ftable, "var %sToknames = []string{\n", prefix)
+	for i := TOKSTART; i <= ntokens; i++ {
+		fmt.Fprintf(ftable, "\t\"%v\",\n", tokset[i].name)
+	}
+	fmt.Fprintf(ftable, "}\n")
+
+	// put out names of state names
+	fmt.Fprintf(ftable, "var %sStatenames = []string{", prefix)
+	//	for i:=TOKSTART; i<=ntokens; i++ {
+	//		fmt.Fprintf(ftable, "\t\"%v\",\n", tokset[i].name);
+	//	}
+	fmt.Fprintf(ftable, "}\n")
+
 	fmt.Fprintf(fcode, "switch %snt {\n", prefix)
 
 	moreprod()
@@ -618,7 +603,6 @@ outer:
 			}
 			levprd[nprod] |= ACTFLAG
 			fmt.Fprintf(fcode, "\n\tcase %v:", nprod)
-			fmt.Fprintf(fcode, "\n\t\t%sDollar = %sS[%spt-%v:%spt+1]", prefix, prefix, prefix, mem-1, prefix)
 			cpyact(curprod, mem)
 
 			// action within rule...
@@ -675,6 +659,9 @@ outer:
 			if tempty != nontrst[curprod[0]-NTBASE].value {
 				lerrorf(ruleline, "default action causes potential type clash")
 			}
+			fmt.Fprintf(fcode, "\n\tcase %v:", nprod)
+			fmt.Fprintf(fcode, "\n\t\t%sVAL.%v = %sS[%spt-0].%v",
+				prefix, typeset[tempty], prefix, prefix, typeset[tempty])
 		}
 		moreprod()
 		prdptr[nprod] = make([]int, mem)
@@ -691,31 +678,6 @@ outer:
 
 	fmt.Fprintf(fcode, "\n\t}")
 
-	// put out non-literal terminals
-	for i := TOKSTART; i <= ntokens; i++ {
-		// non-literals
-		if !tokset[i].noconst {
-			fmt.Fprintf(ftable, "const %v = %v\n", tokset[i].name, tokset[i].value)
-		}
-	}
-
-	// put out names of tokens
-	ftable.WriteRune('\n')
-	fmt.Fprintf(ftable, "var %sToknames = [...]string{\n", prefix)
-	for i := 1; i <= ntokens; i++ {
-		fmt.Fprintf(ftable, "\t%q,\n", tokset[i].name)
-	}
-	fmt.Fprintf(ftable, "}\n")
-
-	// put out names of states.
-	// commented out to avoid a huge table just for debugging.
-	// re-enable to have the names in the binary.
-	fmt.Fprintf(ftable, "var %sStatenames = [...]string{", prefix)
-	//	for i:=TOKSTART; i<=ntokens; i++ {
-	//		fmt.Fprintf(ftable, "\t%q,\n", tokset[i].name);
-	//	}
-	fmt.Fprintf(ftable, "}\n")
-
 	ftable.WriteRune('\n')
 	fmt.Fprintf(ftable, "const %sEofCode = 1\n", prefix)
 	fmt.Fprintf(ftable, "const %sErrCode = 2\n", prefix)
@@ -1383,7 +1345,7 @@ loop:
 				ungetrune(finput, c)
 				continue loop
 			}
-			fmt.Fprintf(fcode, "%sDollar[%v]", prefix, j)
+			fmt.Fprintf(fcode, "%sS[%spt-%v]", prefix, prefix, max-j-1)
 
 			// put out the proper tag
 			if ntypes != 0 {
@@ -2193,11 +2155,7 @@ func output() {
 	if !lflag {
 		fmt.Fprintf(ftable, "\n//line yacctab:1")
 	}
-	fmt.Fprintf(ftable, "\nvar %sExca = [...]int{\n", prefix)
-
-	if len(errors) > 0 {
-		stateTable = make([]Row, nstate)
-	}
+	fmt.Fprintf(ftable, "\nvar %sExca = []int{\n", prefix)
 
 	noset := mkset()
 
@@ -2412,15 +2370,6 @@ func wrstate(i int) {
 	var j0, j1, u int
 	var pp, qq int
 
-	if len(errors) > 0 {
-		actions := append([]int(nil), temp1...)
-		defaultAction := ERRCODE
-		if lastred != 0 {
-			defaultAction = -lastred
-		}
-		stateTable[i] = Row{actions, defaultAction}
-	}
-
 	if foutput == nil {
 		return
 	}
@@ -2942,7 +2891,7 @@ func others() {
 	arout("Tok2", temp1, c+1)
 
 	// table 3 has everything else
-	fmt.Fprintf(ftable, "var %sTok3 = [...]int{\n\t", prefix)
+	fmt.Fprintf(ftable, "var %sTok3 = []int{\n\t", prefix)
 	c = 0
 	for i = 1; i <= ntokens; i++ {
 		j = tokset[i].value
@@ -2967,20 +2916,6 @@ func others() {
 	}
 	fmt.Fprintf(ftable, "%d,\n}\n", 0)
 
-	// Custom error messages.
-	fmt.Fprintf(ftable, "\n")
-	fmt.Fprintf(ftable, "var %sErrorMessages = [...]struct {\n", prefix)
-	fmt.Fprintf(ftable, "\tstate int\n")
-	fmt.Fprintf(ftable, "\ttoken int\n")
-	fmt.Fprintf(ftable, "\tmsg   string\n")
-	fmt.Fprintf(ftable, "}{\n")
-	for _, error := range errors {
-		lineno = error.lineno
-		state, token := runMachine(error.tokens)
-		fmt.Fprintf(ftable, "\t{%v, %v, %s},\n", state, token, error.msg)
-	}
-	fmt.Fprintf(ftable, "}\n")
-
 	// copy parser text
 	ch := getrune(finput)
 	for ch != EOF {
@@ -2999,62 +2934,9 @@ func others() {
 	fmt.Fprintf(ftable, "%v", parts[1])
 }
 
-func runMachine(tokens []string) (state, token int) {
-	var stack []int
-	i := 0
-	token = -1
-
-Loop:
-	if token < 0 {
-		token = chfind(2, tokens[i])
-		i++
-	}
-
-	row := stateTable[state]
-
-	c := token
-	if token >= NTBASE {
-		c = token - NTBASE + ntokens
-	}
-	action := row.actions[c]
-	if action == 0 {
-		action = row.defaultAction
-	}
-
-	switch {
-	case action == ACCEPTCODE:
-		errorf("tokens are accepted")
-		return
-	case action == ERRCODE:
-		if token >= NTBASE {
-			errorf("error at non-terminal token %s", symnam(token))
-		}
-		return
-	case action > 0:
-		// Shift to state action.
-		stack = append(stack, state)
-		state = action
-		token = -1
-		goto Loop
-	default:
-		// Reduce by production -action.
-		prod := prdptr[-action]
-		if rhsLen := len(prod) - 2; rhsLen > 0 {
-			n := len(stack) - rhsLen
-			state = stack[n]
-			stack = stack[:n]
-		}
-		if token >= 0 {
-			i--
-		}
-		token = prod[0]
-		goto Loop
-	}
-}
-
 func arout(s string, v []int, n int) {
 	s = prefix + s
-	fmt.Fprintf(ftable, "var %v = [...]int{\n", s)
+	fmt.Fprintf(ftable, "var %v = []int{\n", s)
 	for i := 0; i < n; i++ {
 		if i%10 == 0 {
 			fmt.Fprintf(ftable, "\n\t")
@@ -3315,42 +3197,20 @@ var yaccpar string // will be processed version of yaccpartext: s/$$/prefix/g
 var yaccpartext = `
 /*	parser for yacc output	*/
 
-var (
-	$$Debug        = 0
-	$$ErrorVerbose = false
-)
+var $$Debug = 0
 
 type $$Lexer interface {
 	Lex(lval *$$SymType) int
 	Error(s string)
 }
 
-type $$Parser interface {
-	Parse($$Lexer) int
-	Lookahead() int
-}
-
-type $$ParserImpl struct {
-	lookahead func() int
-}
-
-func (p *$$ParserImpl) Lookahead() int {
-	return p.lookahead()
-}
-
-func $$NewParser() $$Parser {
-	p := &$$ParserImpl{
-		lookahead: func() int { return -1 },
-	}
-	return p
-}
-
 const $$Flag = -1000
 
 func $$Tokname(c int) string {
-	if c >= 1 && c-1 < len($$Toknames) {
-		if $$Toknames[c-1] != "" {
-			return $$Toknames[c-1]
+	// 4 is TOKSTART above
+	if c >= 4 && c-4 < len($$Toknames) {
+		if $$Toknames[c-4] != "" {
+			return $$Toknames[c-4]
 		}
 	}
 	return __yyfmt__.Sprintf("tok-%v", c)
@@ -3365,129 +3225,51 @@ func $$Statname(s int) string {
 	return __yyfmt__.Sprintf("state-%v", s)
 }
 
-func $$ErrorMessage(state, lookAhead int) string {
-	const TOKSTART = 4
-
-	if !$$ErrorVerbose {
-		return "syntax error"
-	}
-
-	for _, e := range $$ErrorMessages {
-		if e.state == state && e.token == lookAhead {
-			return "syntax error: " + e.msg
-		}
-	}
-
-	res := "syntax error: unexpected " + $$Tokname(lookAhead)
-
-	// To match Bison, suggest at most four expected tokens.
-	expected := make([]int, 0, 4)
-
-	// Look for shiftable tokens.
-	base := $$Pact[state]
-	for tok := TOKSTART; tok-1 < len($$Toknames); tok++ {
-		if n := base + tok; n >= 0 && n < $$Last && $$Chk[$$Act[n]] == tok {
-			if len(expected) == cap(expected) {
-				return res
-			}
-			expected = append(expected, tok)
-		}
-	}
-
-	if $$Def[state] == -2 {
-		i := 0
-		for $$Exca[i] != -1 || $$Exca[i+1] != state {
-			i += 2
-		}
-
-		// Look for tokens that we accept or reduce.
-		for i += 2; $$Exca[i] >= 0; i += 2 {
-			tok := $$Exca[i]
-			if tok < TOKSTART || $$Exca[i+1] == 0 {
-				continue
-			}
-			if len(expected) == cap(expected) {
-				return res
-			}
-			expected = append(expected, tok)
-		}
-
-		// If the default action is to accept or reduce, give up.
-		if $$Exca[i+1] != 0 {
-			return res
-		}
-	}
-
-	for i, tok := range expected {
-		if i == 0 {
-			res += ", expecting "
-		} else {
-			res += " or "
-		}
-		res += $$Tokname(tok)
-	}
-	return res
-}
-
-func $$lex1(lex $$Lexer, lval *$$SymType) (char, token int) {
-	token = 0
-	char = lex.Lex(lval)
+func $$lex1(lex $$Lexer, lval *$$SymType) int {
+	c := 0
+	char := lex.Lex(lval)
 	if char <= 0 {
-		token = $$Tok1[0]
+		c = $$Tok1[0]
 		goto out
 	}
 	if char < len($$Tok1) {
-		token = $$Tok1[char]
+		c = $$Tok1[char]
 		goto out
 	}
 	if char >= $$Private {
 		if char < $$Private+len($$Tok2) {
-			token = $$Tok2[char-$$Private]
+			c = $$Tok2[char-$$Private]
 			goto out
 		}
 	}
 	for i := 0; i < len($$Tok3); i += 2 {
-		token = $$Tok3[i+0]
-		if token == char {
-			token = $$Tok3[i+1]
+		c = $$Tok3[i+0]
+		if c == char {
+			c = $$Tok3[i+1]
 			goto out
 		}
 	}
 
 out:
-	if token == 0 {
-		token = $$Tok2[1] /* unknown char */
+	if c == 0 {
+		c = $$Tok2[1] /* unknown char */
 	}
 	if $$Debug >= 3 {
-		__yyfmt__.Printf("lex %s(%d)\n", $$Tokname(token), uint(char))
+		__yyfmt__.Printf("lex %s(%d)\n", $$Tokname(c), uint(char))
 	}
-	return char, token
+	return c
 }
 
 func $$Parse($$lex $$Lexer) int {
-	return $$NewParser().Parse($$lex)
-}
-
-func ($$rcvr *$$ParserImpl) Parse($$lex $$Lexer) int {
 	var $$n int
 	var $$lval $$SymType
 	var $$VAL $$SymType
-	var $$Dollar []$$SymType
-	_ = $$Dollar // silence set and not used
 	$$S := make([]$$SymType, $$MaxDepth)
 
 	Nerrs := 0   /* number of errors */
 	Errflag := 0 /* error recovery flag */
 	$$state := 0
 	$$char := -1
-	$$token := -1 // $$char translated into internal numbering
-	$$rcvr.lookahead = func() int { return $$char }
-	defer func() {
-		// Make sure we report no lookahead when not parsing.
-		$$state = -1
-		$$char = -1
-		$$token = -1
-	}()
 	$$p := -1
 	goto $$stack
 
@@ -3500,7 +3282,7 @@ ret1:
 $$stack:
 	/* put a state and value onto the stack */
 	if $$Debug >= 4 {
-		__yyfmt__.Printf("char %v in %v\n", $$Tokname($$token), $$Statname($$state))
+		__yyfmt__.Printf("char %v in %v\n", $$Tokname($$char), $$Statname($$state))
 	}
 
 	$$p++
@@ -3518,16 +3300,15 @@ $$newstate:
 		goto $$default /* simple state */
 	}
 	if $$char < 0 {
-		$$char, $$token = $$lex1($$lex, &$$lval)
+		$$char = $$lex1($$lex, &$$lval)
 	}
-	$$n += $$token
+	$$n += $$char
 	if $$n < 0 || $$n >= $$Last {
 		goto $$default
 	}
 	$$n = $$Act[$$n]
-	if $$Chk[$$n] == $$token { /* valid shift */
+	if $$Chk[$$n] == $$char { /* valid shift */
 		$$char = -1
-		$$token = -1
 		$$VAL = $$lval
 		$$state = $$n
 		if Errflag > 0 {
@@ -3541,7 +3322,7 @@ $$default:
 	$$n = $$Def[$$state]
 	if $$n == -2 {
 		if $$char < 0 {
-			$$char, $$token = $$lex1($$lex, &$$lval)
+			$$char = $$lex1($$lex, &$$lval)
 		}
 
 		/* look through exception table */
@@ -3554,7 +3335,7 @@ $$default:
 		}
 		for xi += 2; ; xi += 2 {
 			$$n = $$Exca[xi+0]
-			if $$n < 0 || $$n == $$token {
+			if $$n < 0 || $$n == $$char {
 				break
 			}
 		}
@@ -3567,11 +3348,11 @@ $$default:
 		/* error ... attempt to resume parsing */
 		switch Errflag {
 		case 0: /* brand new error */
-			$$lex.Error($$ErrorMessage($$state, $$token))
+			$$lex.Error("syntax error")
 			Nerrs++
 			if $$Debug >= 1 {
 				__yyfmt__.Printf("%s", $$Statname($$state))
-				__yyfmt__.Printf(" saw %s\n", $$Tokname($$token))
+				__yyfmt__.Printf(" saw %s\n", $$Tokname($$char))
 			}
 			fallthrough
 
@@ -3599,13 +3380,12 @@ $$default:
 
 		case 3: /* no shift yet; clobber input char */
 			if $$Debug >= 2 {
-				__yyfmt__.Printf("error recovery discards %s\n", $$Tokname($$token))
+				__yyfmt__.Printf("error recovery discards %s\n", $$Tokname($$char))
 			}
-			if $$token == $$EofCode {
+			if $$char == $$EofCode {
 				goto ret1
 			}
 			$$char = -1
-			$$token = -1
 			goto $$newstate /* try again in the same state */
 		}
 	}
@@ -3620,13 +3400,6 @@ $$default:
 	_ = $$pt // guard against "declared and not used"
 
 	$$p -= $$R2[$$n]
-	// $$p is now the index of $0. Perform the default action. Iff the
-	// reduced production is ε, $1 is possibly out of range.
-	if $$p+1 >= len($$S) {
-		nyys := make([]$$SymType, len($$S)*2)
-		copy(nyys, $$S)
-		$$S = nyys
-	}
 	$$VAL = $$S[$$p+1]
 
 	/* consult goto table to find next state */
diff --git a/src/compress/bzip2/bzip2.go b/src/compress/bzip2/bzip2.go
index 6897957..15575d2 100644
--- a/src/compress/bzip2/bzip2.go
+++ b/src/compress/bzip2/bzip2.go
@@ -353,7 +353,7 @@ func (bz2 *reader) readBlock() (err error) {
 	// variables accumulate the repeat count. See the Wikipedia page for
 	// details.
 	repeat := 0
-	repeatPower := 0
+	repeat_power := 0
 
 	// The `C' array (used by the inverse BWT) needs to be zero initialized.
 	for i := range bz2.c {
@@ -380,10 +380,10 @@ func (bz2 *reader) readBlock() (err error) {
 		if v < 2 {
 			// This is either the RUNA or RUNB symbol.
 			if repeat == 0 {
-				repeatPower = 1
+				repeat_power = 1
 			}
-			repeat += repeatPower << v
-			repeatPower <<= 1
+			repeat += repeat_power << v
+			repeat_power <<= 1
 
 			// This limit of 2 million comes from the bzip2 source
 			// code. It prevents repeat from overflowing.
diff --git a/src/compress/bzip2/bzip2_test.go b/src/compress/bzip2/bzip2_test.go
index 77c50df..fb79d08 100644
--- a/src/compress/bzip2/bzip2_test.go
+++ b/src/compress/bzip2/bzip2_test.go
@@ -200,7 +200,7 @@ func BenchmarkDecodeDigits(b *testing.B) { benchmarkDecode(b, digits) }
 func BenchmarkDecodeTwain(b *testing.B)  { benchmarkDecode(b, twain) }
 
 func TestBufferOverrun(t *testing.T) {
-	// Tests https://golang.org/issue/5747.
+	// Tests https://code.google.com/p/go/issues/detail?id=5747.
 	buffer := bytes.NewReader([]byte(bufferOverrunBase64))
 	decoder := base64.NewDecoder(base64.StdEncoding, buffer)
 	decompressor := NewReader(decoder)
@@ -209,7 +209,7 @@ func TestBufferOverrun(t *testing.T) {
 }
 
 func TestOutOfRangeSelector(t *testing.T) {
-	// Tests https://golang.org/issue/8363.
+	// Tests https://code.google.com/p/go/issues/detail?id=8363.
 	buffer := bytes.NewReader(outOfRangeSelector)
 	decompressor := NewReader(buffer)
 	// This shouldn't panic.
diff --git a/src/compress/flate/deflate.go b/src/compress/flate/deflate.go
index 169a0c7..8c79df0 100644
--- a/src/compress/flate/deflate.go
+++ b/src/compress/flate/deflate.go
@@ -24,7 +24,7 @@ const (
 	maxMatchLength     = 258 // The longest match for the compressor
 	minOffsetSize      = 1   // The shortest offset that makes any sense
 
-	// The maximum number of tokens we put into a single flat block, just to
+	// The maximum number of tokens we put into a single flat block, just too
 	// stop things from getting too large.
 	maxFlateBlockTokens = 1 << 14
 	maxStoreBlockSize   = 65535
diff --git a/src/compress/flate/deflate_test.go b/src/compress/flate/deflate_test.go
index d5d6e73..730234c 100644
--- a/src/compress/flate/deflate_test.go
+++ b/src/compress/flate/deflate_test.go
@@ -407,7 +407,7 @@ func TestWriterDict(t *testing.T) {
 	}
 }
 
-// See https://golang.org/issue/2508
+// See http://code.google.com/p/go/issues/detail?id=2508
 func TestRegression2508(t *testing.T) {
 	if testing.Short() {
 		t.Logf("test disabled with -short")
diff --git a/src/compress/flate/flate_test.go b/src/compress/flate/flate_test.go
index 3f67025..0687663 100644
--- a/src/compress/flate/flate_test.go
+++ b/src/compress/flate/flate_test.go
@@ -10,18 +10,29 @@ package flate
 
 import (
 	"bytes"
-	"encoding/hex"
-	"io/ioutil"
 	"testing"
 )
 
+func TestUncompressedSource(t *testing.T) {
+	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 {
+		t.Fatalf("decoder.Read() = %d, %v, want 1, nil", n, error)
+	}
+	if output[0] != 0x11 {
+		t.Errorf("output[0] = %x, want 0x11", output[0])
+	}
+}
+
 // The following test should not panic.
 func TestIssue5915(t *testing.T) {
 	bits := []int{4, 0, 0, 6, 4, 3, 2, 3, 3, 4, 4, 5, 0, 0, 0, 0, 5, 5, 6,
 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 8, 6, 0, 11, 0, 8, 0, 6, 6, 10, 8}
-	var h huffmanDecoder
-	if h.init(bits) {
+	h := new(huffmanDecoder)
+	ok := h.init(bits)
+	if ok == true {
 		t.Fatalf("Given sequence of bits is bad, and should not succeed.")
 	}
 }
@@ -30,8 +41,9 @@ func TestIssue5915(t *testing.T) {
 func TestIssue5962(t *testing.T) {
 	bits := []int{4, 0, 0, 6, 4, 3, 2, 3, 3, 4, 4, 5, 0, 0, 0, 0,
 		5, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11}
-	var h huffmanDecoder
-	if h.init(bits) {
+	h := new(huffmanDecoder)
+	ok := h.init(bits)
+	if ok == true {
 		t.Fatalf("Given sequence of bits is bad, and should not succeed.")
 	}
 }
@@ -40,7 +52,7 @@ func TestIssue5962(t *testing.T) {
 func TestIssue6255(t *testing.T) {
 	bits1 := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 11}
 	bits2 := []int{11, 13}
-	var h huffmanDecoder
+	h := new(huffmanDecoder)
 	if !h.init(bits1) {
 		t.Fatalf("Given sequence of bits is good and should succeed.")
 	}
@@ -48,213 +60,3 @@ func TestIssue6255(t *testing.T) {
 		t.Fatalf("Given sequence of bits is bad and should not succeed.")
 	}
 }
-
-func TestInvalidEncoding(t *testing.T) {
-	// Initialize Huffman decoder to recognize "0".
-	var h huffmanDecoder
-	if !h.init([]int{1}) {
-		t.Fatal("Failed to initialize Huffman decoder")
-	}
-
-	// Initialize decompressor with invalid Huffman coding.
-	var f decompressor
-	f.r = bytes.NewReader([]byte{0xff})
-
-	_, err := f.huffSym(&h)
-	if err == nil {
-		t.Fatal("Should have rejected invalid bit sequence")
-	}
-}
-
-func TestInvalidBits(t *testing.T) {
-	oversubscribed := []int{1, 2, 3, 4, 4, 5}
-	incomplete := []int{1, 2, 4, 4}
-	var h huffmanDecoder
-	if h.init(oversubscribed) {
-		t.Fatal("Should reject oversubscribed bit-length set")
-	}
-	if h.init(incomplete) {
-		t.Fatal("Should reject incomplete bit-length set")
-	}
-}
-
-func TestStreams(t *testing.T) {
-	// To verify any of these hexstrings as valid or invalid flate streams
-	// according to the C zlib library, you can use the Python wrapper library:
-	// >>> hex_string = "010100feff11"
-	// >>> import zlib
-	// >>> zlib.decompress(hex_string.decode("hex"), -15) # Negative means raw DEFLATE
-	// '\x11'
-
-	testCases := []struct {
-		desc   string // Description of the stream
-		stream string // Hexstring of the input DEFLATE stream
-		want   string // Expected result. Use "fail" to expect failure
-	}{{
-		"degenerate HCLenTree",
-		"05e0010000000000100000000000000000000000000000000000000000000000" +
-			"00000000000000000004",
-		"fail",
-	}, {
-		"complete HCLenTree, empty HLitTree, empty HDistTree",
-		"05e0010400000000000000000000000000000000000000000000000000000000" +
-			"00000000000000000010",
-		"fail",
-	}, {
-		"empty HCLenTree",
-		"05e0010000000000000000000000000000000000000000000000000000000000" +
-			"00000000000000000010",
-		"fail",
-	}, {
-		"complete HCLenTree, complete HLitTree, empty HDistTree, use missing HDist symbol",
-		"000100feff000de0010400000000100000000000000000000000000000000000" +
-			"0000000000000000000000000000002c",
-		"fail",
-	}, {
-		"complete HCLenTree, complete HLitTree, degenerate HDistTree, use missing HDist symbol",
-		"000100feff000de0010000000000000000000000000000000000000000000000" +
-			"00000000000000000610000000004070",
-		"fail",
-	}, {
-		"complete HCLenTree, empty HLitTree, empty HDistTree",
-		"05e0010400000000100400000000000000000000000000000000000000000000" +
-			"0000000000000000000000000008",
-		"fail",
-	}, {
-		"complete HCLenTree, empty HLitTree, degenerate HDistTree",
-		"05e0010400000000100400000000000000000000000000000000000000000000" +
-			"0000000000000000000800000008",
-		"fail",
-	}, {
-		"complete HCLenTree, degenerate HLitTree, degenerate HDistTree, use missing HLit symbol",
-		"05e0010400000000100000000000000000000000000000000000000000000000" +
-			"0000000000000000001c",
-		"fail",
-	}, {
-		"complete HCLenTree, complete HLitTree, too large HDistTree",
-		"edff870500000000200400000000000000000000000000000000000000000000" +
-			"000000000000000000080000000000000004",
-		"fail",
-	}, {
-		"complete HCLenTree, complete HLitTree, empty HDistTree, excessive repeater code",
-		"edfd870500000000200400000000000000000000000000000000000000000000" +
-			"000000000000000000e8b100",
-		"fail",
-	}, {
-		"complete HCLenTree, complete HLitTree, empty HDistTree of normal length 30",
-		"05fd01240000000000f8ffffffffffffffffffffffffffffffffffffffffffff" +
-			"ffffffffffffffffff07000000fe01",
-		"",
-	}, {
-		"complete HCLenTree, complete HLitTree, empty HDistTree of excessive length 31",
-		"05fe01240000000000f8ffffffffffffffffffffffffffffffffffffffffffff" +
-			"ffffffffffffffffff07000000fc03",
-		"fail",
-	}, {
-		"complete HCLenTree, over-subscribed HLitTree, empty HDistTree",
-		"05e001240000000000fcffffffffffffffffffffffffffffffffffffffffffff" +
-			"ffffffffffffffffff07f00f",
-		"fail",
-	}, {
-		"complete HCLenTree, under-subscribed HLitTree, empty HDistTree",
-		"05e001240000000000fcffffffffffffffffffffffffffffffffffffffffffff" +
-			"fffffffffcffffffff07f00f",
-		"fail",
-	}, {
-		"complete HCLenTree, complete HLitTree with single code, empty HDistTree",
-		"05e001240000000000f8ffffffffffffffffffffffffffffffffffffffffffff" +
-			"ffffffffffffffffff07f00f",
-		"01",
-	}, {
-		"complete HCLenTree, complete HLitTree with multiple codes, empty HDistTree",
-		"05e301240000000000f8ffffffffffffffffffffffffffffffffffffffffffff" +
-			"ffffffffffffffffff07807f",
-		"01",
-	}, {
-		"complete HCLenTree, complete HLitTree, degenerate HDistTree, use valid HDist symbol",
-		"000100feff000de0010400000000100000000000000000000000000000000000" +
-			"0000000000000000000000000000003c",
-		"00000000",
-	}, {
-		"complete HCLenTree, degenerate HLitTree, degenerate HDistTree",
-		"05e0010400000000100000000000000000000000000000000000000000000000" +
-			"0000000000000000000c",
-		"",
-	}, {
-		"complete HCLenTree, degenerate HLitTree, empty HDistTree",
-		"05e0010400000000100000000000000000000000000000000000000000000000" +
-			"00000000000000000004",
-		"",
-	}, {
-		"complete HCLenTree, complete HLitTree, empty HDistTree, spanning repeater code",
-		"edfd870500000000200400000000000000000000000000000000000000000000" +
-			"000000000000000000e8b000",
-		"",
-	}, {
-		"complete HCLenTree with length codes, complete HLitTree, empty HDistTree",
-		"ede0010400000000100000000000000000000000000000000000000000000000" +
-			"0000000000000000000400004000",
-		"",
-	}, {
-		"complete HCLenTree, complete HLitTree, degenerate HDistTree, use valid HLit symbol 284 with count 31",
-		"000100feff00ede0010400000000100000000000000000000000000000000000" +
-			"000000000000000000000000000000040000407f00",
-		"0000000000000000000000000000000000000000000000000000000000000000" +
-			"0000000000000000000000000000000000000000000000000000000000000000" +
-			"0000000000000000000000000000000000000000000000000000000000000000" +
-			"0000000000000000000000000000000000000000000000000000000000000000" +
-			"0000000000000000000000000000000000000000000000000000000000000000" +
-			"0000000000000000000000000000000000000000000000000000000000000000" +
-			"0000000000000000000000000000000000000000000000000000000000000000" +
-			"0000000000000000000000000000000000000000000000000000000000000000" +
-			"000000",
-	}, {
-		"complete HCLenTree, complete HLitTree, degenerate HDistTree, use valid HLit and HDist symbols",
-		"0cc2010d00000082b0ac4aff0eb07d27060000ffff",
-		"616263616263",
-	}, {
-		"fixed block, use reserved symbol 287",
-		"33180700",
-		"fail",
-	}, {
-		"raw block",
-		"010100feff11",
-		"11",
-	}, {
-		"issue 10426 - over-subscribed HCLenTree causes a hang",
-		"344c4a4e494d4b070000ff2e2eff2e2e2e2e2eff",
-		"fail",
-	}, {
-		"issue 11030 - empty HDistTree unexpectedly leads to error",
-		"05c0070600000080400fff37a0ca",
-		"",
-	}, {
-		"issue 11033 - empty HDistTree unexpectedly leads to error",
-		"050fb109c020cca5d017dcbca044881ee1034ec149c8980bbc413c2ab35be9dc" +
-			"b1473449922449922411202306ee97b0383a521b4ffdcf3217f9f7d3adb701",
-		"3130303634342068652e706870005d05355f7ed957ff084a90925d19e3ebc6d0" +
-			"c6d7",
-	}}
-
-	for i, tc := range testCases {
-		data, err := hex.DecodeString(tc.stream)
-		if err != nil {
-			t.Fatal(err)
-		}
-		data, err = ioutil.ReadAll(NewReader(bytes.NewReader(data)))
-		if tc.want == "fail" {
-			if err == nil {
-				t.Errorf("#%d (%s): got nil error, want non-nil", i, tc.desc)
-			}
-		} else {
-			if err != nil {
-				t.Errorf("#%d (%s): %v", i, tc.desc, err)
-				continue
-			}
-			if got := hex.EncodeToString(data); got != tc.want {
-				t.Errorf("#%d (%s):\ngot  %q\nwant %q", i, tc.desc, got, tc.want)
-			}
-
-		}
-	}
-}
diff --git a/src/compress/flate/gen.go b/src/compress/flate/gen.go
index 154c89a..6288ecd 100644
--- a/src/compress/flate/gen.go
+++ b/src/compress/flate/gen.go
@@ -45,20 +45,7 @@ type huffmanDecoder struct {
 }
 
 // Initialize Huffman decoding tables from array of code lengths.
-// Following this function, h is guaranteed to be initialized into a complete
-// tree (i.e., neither over-subscribed nor under-subscribed). The exception is a
-// degenerate case where the tree has only a single symbol with length 1. Empty
-// trees are permitted.
 func (h *huffmanDecoder) init(bits []int) bool {
-	// Sanity enables additional runtime tests during Huffman
-	// table construction.  It's intended to be used during
-	// development to supplement the currently ad-hoc unit tests.
-	const sanity = false
-
-	if h.min != 0 {
-		*h = huffmanDecoder{}
-	}
-
 	// Count number of codes of each length,
 	// compute min and max length.
 	var count [maxCodeLen]int
@@ -75,53 +62,37 @@ func (h *huffmanDecoder) init(bits []int) bool {
 		}
 		count[n]++
 	}
-
-	// Empty tree. The decompressor.huffSym function will fail later if the tree
-	// is used. Technically, an empty tree is only valid for the HDIST tree and
-	// not the HCLEN and HLIT tree. However, a stream with an empty HCLEN tree
-	// is guaranteed to fail since it will attempt to use the tree to decode the
-	// codes for the HLIT and HDIST trees. Similarly, an empty HLIT tree is
-	// guaranteed to fail later since the compressed data section must be
-	// composed of at least one symbol (the end-of-block marker).
 	if max == 0 {
-		return true
-	}
-
-	code := 0
-	var nextcode [maxCodeLen]int
-	for i := min; i <= max; i++ {
-		code <<= 1
-		nextcode[i] = code
-		code += count[i]
-	}
-
-	// Check that the coding is complete (i.e., that we've
-	// assigned all 2-to-the-max possible bit sequences).
-	// Exception: To be compatible with zlib, we also need to
-	// accept degenerate single-code codings.  See also
-	// TestDegenerateHuffmanCoding.
-	if code != 1<<uint(max) && !(code == 1 && max == 1) {
 		return false
 	}
 
 	h.min = min
+	var linkBits uint
+	var numLinks int
 	if max > huffmanChunkBits {
-		numLinks := 1 << (uint(max) - huffmanChunkBits)
+		linkBits = uint(max) - huffmanChunkBits
+		numLinks = 1 << linkBits
 		h.linkMask = uint32(numLinks - 1)
-
-		// create link tables
-		link := nextcode[huffmanChunkBits+1] >> 1
-		h.links = make([][]uint32, huffmanNumChunks-link)
-		for j := uint(link); j < huffmanNumChunks; j++ {
-			reverse := int(reverseByte[j>>8]) | int(reverseByte[j&0xff])<<8
-			reverse >>= uint(16 - huffmanChunkBits)
-			off := j - uint(link)
-			if sanity && h.chunks[reverse] != 0 {
-				panic("impossible: overwriting existing chunk")
+	}
+	code := 0
+	var nextcode [maxCodeLen]int
+	for i := min; i <= max; i++ {
+		if i == huffmanChunkBits+1 {
+			// create link tables
+			link := code >> 1
+			h.links = make([][]uint32, huffmanNumChunks-link)
+			for j := uint(link); j < huffmanNumChunks; j++ {
+				reverse := int(reverseByte[j>>8]) | int(reverseByte[j&0xff])<<8
+				reverse >>= uint(16 - huffmanChunkBits)
+				off := j - uint(link)
+				h.chunks[reverse] = uint32(off<<huffmanValueShift + uint(i))
+				h.links[off] = make([]uint32, 1<<linkBits)
 			}
-			h.chunks[reverse] = uint32(off<<huffmanValueShift | (huffmanChunkBits + 1))
-			h.links[off] = make([]uint32, numLinks)
 		}
+		n := count[i]
+		nextcode[i] = code
+		code += n
+		code <<= 1
 	}
 
 	for i, n := range bits {
@@ -134,60 +105,17 @@ func (h *huffmanDecoder) init(bits []int) bool {
 		reverse := int(reverseByte[code>>8]) | int(reverseByte[code&0xff])<<8
 		reverse >>= uint(16 - n)
 		if n <= huffmanChunkBits {
-			for off := reverse; off < len(h.chunks); off += 1 << uint(n) {
-				// We should never need to overwrite
-				// an existing chunk.  Also, 0 is
-				// never a valid chunk, because the
-				// lower 4 "count" bits should be
-				// between 1 and 15.
-				if sanity && h.chunks[off] != 0 {
-					panic("impossible: overwriting existing chunk")
-				}
+			for off := reverse; off < huffmanNumChunks; off += 1 << uint(n) {
 				h.chunks[off] = chunk
 			}
 		} else {
-			j := reverse & (huffmanNumChunks - 1)
-			if sanity && h.chunks[j]&huffmanCountMask != huffmanChunkBits+1 {
-				// Longer codes should have been
-				// associated with a link table above.
-				panic("impossible: not an indirect chunk")
-			}
-			value := h.chunks[j] >> huffmanValueShift
-			linktab := h.links[value]
+			linktab := h.links[h.chunks[reverse&(huffmanNumChunks-1)]>>huffmanValueShift]
 			reverse >>= huffmanChunkBits
-			for off := reverse; off < len(linktab); off += 1 << uint(n-huffmanChunkBits) {
-				if sanity && linktab[off] != 0 {
-					panic("impossible: overwriting existing chunk")
-				}
+			for off := reverse; off < numLinks; off += 1 << uint(n-huffmanChunkBits) {
 				linktab[off] = chunk
 			}
 		}
 	}
-
-	if sanity {
-		// Above we've sanity checked that we never overwrote
-		// an existing entry.  Here we additionally check that
-		// we filled the tables completely.
-		for i, chunk := range h.chunks {
-			if chunk == 0 {
-				// As an exception, in the degenerate
-				// single-code case, we allow odd
-				// chunks to be missing.
-				if code == 1 && i%2 == 1 {
-					continue
-				}
-				panic("impossible: missing chunk")
-			}
-		}
-		for _, linktab := range h.links {
-			for _, chunk := range linktab {
-				if chunk == 0 {
-					panic("impossible: missing chunk")
-				}
-			}
-		}
-	}
-
 	return true
 }
 
@@ -210,9 +138,6 @@ func main() {
 		bits[i] = 8
 	}
 	h.init(bits[:])
-	if h.links != nil {
-		log.Fatal("Unexpected links table in fixed Huffman decoder")
-	}
 
 	var buf bytes.Buffer
 
diff --git a/src/compress/flate/huffman_bit_writer.go b/src/compress/flate/huffman_bit_writer.go
index 6164404..b182a71 100644
--- a/src/compress/flate/huffman_bit_writer.go
+++ b/src/compress/flate/huffman_bit_writer.go
@@ -87,11 +87,11 @@ type huffmanBitWriter struct {
 func newHuffmanBitWriter(w io.Writer) *huffmanBitWriter {
 	return &huffmanBitWriter{
 		w:               w,
-		literalFreq:     make([]int32, maxNumLit),
+		literalFreq:     make([]int32, maxLit),
 		offsetFreq:      make([]int32, offsetCodeCount),
-		codegen:         make([]uint8, maxNumLit+offsetCodeCount+1),
+		codegen:         make([]uint8, maxLit+offsetCodeCount+1),
 		codegenFreq:     make([]int32, codegenCodeCount),
-		literalEncoding: newHuffmanEncoder(maxNumLit),
+		literalEncoding: newHuffmanEncoder(maxLit),
 		offsetEncoding:  newHuffmanEncoder(offsetCodeCount),
 		codegenEncoding: newHuffmanEncoder(codegenCodeCount),
 	}
diff --git a/src/compress/flate/huffman_code.go b/src/compress/flate/huffman_code.go
index 50ec79c..3b9fce4 100644
--- a/src/compress/flate/huffman_code.go
+++ b/src/compress/flate/huffman_code.go
@@ -47,11 +47,11 @@ func newHuffmanEncoder(size int) *huffmanEncoder {
 
 // Generates a HuffmanCode corresponding to the fixed literal table
 func generateFixedLiteralEncoding() *huffmanEncoder {
-	h := newHuffmanEncoder(maxNumLit)
+	h := newHuffmanEncoder(maxLit)
 	codeBits := h.codeBits
 	code := h.code
 	var ch uint16
-	for ch = 0; ch < maxNumLit; ch++ {
+	for ch = 0; ch < maxLit; ch++ {
 		var bits uint16
 		var size uint8
 		switch {
diff --git a/src/compress/flate/inflate.go b/src/compress/flate/inflate.go
index 04372de..76519bb 100644
--- a/src/compress/flate/inflate.go
+++ b/src/compress/flate/inflate.go
@@ -18,12 +18,10 @@ import (
 const (
 	maxCodeLen = 16    // max length of Huffman code
 	maxHist    = 32768 // max history required
-	// The next three numbers come from the RFC section 3.2.7, with the
-	// additional proviso in section 3.2.5 which implies that distance codes
-	// 30 and 31 should never occur in compressed data.
-	maxNumLit  = 286
-	maxNumDist = 30
-	numCodes   = 19 // number of codes in Huffman meta-code
+	// The next three numbers come from the RFC, section 3.2.7.
+	maxLit   = 286
+	maxDist  = 32
+	numCodes = 19 // number of codes in Huffman meta-code
 )
 
 // A CorruptInputError reports the presence of corrupt input at a given offset.
@@ -103,16 +101,7 @@ type huffmanDecoder struct {
 }
 
 // Initialize Huffman decoding tables from array of code lengths.
-// Following this function, h is guaranteed to be initialized into a complete
-// tree (i.e., neither over-subscribed nor under-subscribed). The exception is a
-// degenerate case where the tree has only a single symbol with length 1. Empty
-// trees are permitted.
 func (h *huffmanDecoder) init(bits []int) bool {
-	// Sanity enables additional runtime tests during Huffman
-	// table construction.  It's intended to be used during
-	// development to supplement the currently ad-hoc unit tests.
-	const sanity = false
-
 	if h.min != 0 {
 		*h = huffmanDecoder{}
 	}
@@ -133,53 +122,40 @@ func (h *huffmanDecoder) init(bits []int) bool {
 		}
 		count[n]++
 	}
-
-	// Empty tree. The decompressor.huffSym function will fail later if the tree
-	// is used. Technically, an empty tree is only valid for the HDIST tree and
-	// not the HCLEN and HLIT tree. However, a stream with an empty HCLEN tree
-	// is guaranteed to fail since it will attempt to use the tree to decode the
-	// codes for the HLIT and HDIST trees. Similarly, an empty HLIT tree is
-	// guaranteed to fail later since the compressed data section must be
-	// composed of at least one symbol (the end-of-block marker).
 	if max == 0 {
-		return true
-	}
-
-	code := 0
-	var nextcode [maxCodeLen]int
-	for i := min; i <= max; i++ {
-		code <<= 1
-		nextcode[i] = code
-		code += count[i]
-	}
-
-	// Check that the coding is complete (i.e., that we've
-	// assigned all 2-to-the-max possible bit sequences).
-	// Exception: To be compatible with zlib, we also need to
-	// accept degenerate single-code codings.  See also
-	// TestDegenerateHuffmanCoding.
-	if code != 1<<uint(max) && !(code == 1 && max == 1) {
 		return false
 	}
 
 	h.min = min
+	var linkBits uint
+	var numLinks int
 	if max > huffmanChunkBits {
-		numLinks := 1 << (uint(max) - huffmanChunkBits)
+		linkBits = uint(max) - huffmanChunkBits
+		numLinks = 1 << linkBits
 		h.linkMask = uint32(numLinks - 1)
-
-		// create link tables
-		link := nextcode[huffmanChunkBits+1] >> 1
-		h.links = make([][]uint32, huffmanNumChunks-link)
-		for j := uint(link); j < huffmanNumChunks; j++ {
-			reverse := int(reverseByte[j>>8]) | int(reverseByte[j&0xff])<<8
-			reverse >>= uint(16 - huffmanChunkBits)
-			off := j - uint(link)
-			if sanity && h.chunks[reverse] != 0 {
-				panic("impossible: overwriting existing chunk")
+	}
+	code := 0
+	var nextcode [maxCodeLen]int
+	for i := min; i <= max; i++ {
+		if i == huffmanChunkBits+1 {
+			// create link tables
+			link := code >> 1
+			if huffmanNumChunks < link {
+				return false
+			}
+			h.links = make([][]uint32, huffmanNumChunks-link)
+			for j := uint(link); j < huffmanNumChunks; j++ {
+				reverse := int(reverseByte[j>>8]) | int(reverseByte[j&0xff])<<8
+				reverse >>= uint(16 - huffmanChunkBits)
+				off := j - uint(link)
+				h.chunks[reverse] = uint32(off<<huffmanValueShift + uint(i))
+				h.links[off] = make([]uint32, 1<<linkBits)
 			}
-			h.chunks[reverse] = uint32(off<<huffmanValueShift | (huffmanChunkBits + 1))
-			h.links[off] = make([]uint32, numLinks)
 		}
+		n := count[i]
+		nextcode[i] = code
+		code += n
+		code <<= 1
 	}
 
 	for i, n := range bits {
@@ -192,60 +168,21 @@ func (h *huffmanDecoder) init(bits []int) bool {
 		reverse := int(reverseByte[code>>8]) | int(reverseByte[code&0xff])<<8
 		reverse >>= uint(16 - n)
 		if n <= huffmanChunkBits {
-			for off := reverse; off < len(h.chunks); off += 1 << uint(n) {
-				// We should never need to overwrite
-				// an existing chunk.  Also, 0 is
-				// never a valid chunk, because the
-				// lower 4 "count" bits should be
-				// between 1 and 15.
-				if sanity && h.chunks[off] != 0 {
-					panic("impossible: overwriting existing chunk")
-				}
+			for off := reverse; off < huffmanNumChunks; off += 1 << uint(n) {
 				h.chunks[off] = chunk
 			}
 		} else {
-			j := reverse & (huffmanNumChunks - 1)
-			if sanity && h.chunks[j]&huffmanCountMask != huffmanChunkBits+1 {
-				// Longer codes should have been
-				// associated with a link table above.
-				panic("impossible: not an indirect chunk")
+			value := h.chunks[reverse&(huffmanNumChunks-1)] >> huffmanValueShift
+			if value >= uint32(len(h.links)) {
+				return false
 			}
-			value := h.chunks[j] >> huffmanValueShift
 			linktab := h.links[value]
 			reverse >>= huffmanChunkBits
-			for off := reverse; off < len(linktab); off += 1 << uint(n-huffmanChunkBits) {
-				if sanity && linktab[off] != 0 {
-					panic("impossible: overwriting existing chunk")
-				}
+			for off := reverse; off < numLinks; off += 1 << uint(n-huffmanChunkBits) {
 				linktab[off] = chunk
 			}
 		}
 	}
-
-	if sanity {
-		// Above we've sanity checked that we never overwrote
-		// an existing entry.  Here we additionally check that
-		// we filled the tables completely.
-		for i, chunk := range h.chunks {
-			if chunk == 0 {
-				// As an exception, in the degenerate
-				// single-code case, we allow odd
-				// chunks to be missing.
-				if code == 1 && i%2 == 1 {
-					continue
-				}
-				panic("impossible: missing chunk")
-			}
-		}
-		for _, linktab := range h.links {
-			for _, chunk := range linktab {
-				if chunk == 0 {
-					panic("impossible: missing chunk")
-				}
-			}
-		}
-	}
-
 	return true
 }
 
@@ -272,7 +209,7 @@ type decompressor struct {
 	h1, h2 huffmanDecoder
 
 	// Length arrays used to define Huffman codes.
-	bits     *[maxNumLit + maxNumDist]int
+	bits     *[maxLit + maxDist]int
 	codebits *[numCodes]int
 
 	// Output history, buffer.
@@ -370,14 +307,12 @@ func (f *decompressor) readHuffman() error {
 		}
 	}
 	nlit := int(f.b&0x1F) + 257
-	if nlit > maxNumLit {
+	if nlit > maxLit {
 		return CorruptInputError(f.roffset)
 	}
 	f.b >>= 5
 	ndist := int(f.b&0x1F) + 1
-	if ndist > maxNumDist {
-		return CorruptInputError(f.roffset)
-	}
+	// maxDist is 32, so ndist is always valid.
 	f.b >>= 5
 	nclen := int(f.b&0xF) + 4
 	// numCodes is 19, so nclen is always valid.
@@ -508,12 +443,9 @@ func (f *decompressor) huffmanBlock() {
 		case v < 285:
 			length = v*32 - (281*32 - 131)
 			n = 5
-		case v < maxNumLit:
+		default:
 			length = 258
 			n = 0
-		default:
-			f.err = CorruptInputError(f.roffset)
-			return
 		}
 		if n > 0 {
 			for f.nb < n {
@@ -548,7 +480,10 @@ func (f *decompressor) huffmanBlock() {
 		switch {
 		case dist < 4:
 			dist++
-		case dist < maxNumDist:
+		case dist >= 30:
+			f.err = CorruptInputError(f.roffset)
+			return
+		default:
 			nb := uint(dist-2) >> 1
 			// have 1 bit in bottom of dist, need nb more.
 			extra := (dist & 1) << nb
@@ -562,9 +497,6 @@ func (f *decompressor) huffmanBlock() {
 			f.b >>= nb
 			f.nb -= nb
 			dist = 1<<(nb+1) + 1 + extra
-		default:
-			f.err = CorruptInputError(f.roffset)
-			return
 		}
 
 		// Copy history[-dist:-dist+length] into output.
@@ -711,10 +643,6 @@ func (f *decompressor) moreBits() error {
 
 // Read the next Huffman-encoded symbol from f according to h.
 func (f *decompressor) huffSym(h *huffmanDecoder) (int, error) {
-	// Since a huffmanDecoder can be empty or be composed of a degenerate tree
-	// with single element, huffSym must error on these two edge cases. In both
-	// cases, the chunks slice will be 0 for the invalid sequence, leading it
-	// satisfy the n == 0 check below.
 	n := uint(h.min)
 	for {
 		for f.nb < n {
@@ -727,12 +655,12 @@ func (f *decompressor) huffSym(h *huffmanDecoder) (int, error) {
 		if n > huffmanChunkBits {
 			chunk = h.links[chunk>>huffmanValueShift][(f.b>>huffmanChunkBits)&h.linkMask]
 			n = uint(chunk & huffmanCountMask)
-		}
-		if n <= f.nb {
 			if n == 0 {
 				f.err = CorruptInputError(f.roffset)
 				return 0, f.err
 			}
+		}
+		if n <= f.nb {
 			f.b >>= n
 			f.nb -= n
 			return int(chunk >> huffmanValueShift), nil
@@ -784,7 +712,7 @@ func (f *decompressor) Reset(r io.Reader, dict []byte) error {
 // The ReadCloser returned by NewReader also implements Resetter.
 func NewReader(r io.Reader) io.ReadCloser {
 	var f decompressor
-	f.bits = new([maxNumLit + maxNumDist]int)
+	f.bits = new([maxLit + maxDist]int)
 	f.codebits = new([numCodes]int)
 	f.r = makeReader(r)
 	f.hist = new([maxHist]byte)
@@ -803,7 +731,7 @@ func NewReaderDict(r io.Reader, dict []byte) io.ReadCloser {
 	var f decompressor
 	f.r = makeReader(r)
 	f.hist = new([maxHist]byte)
-	f.bits = new([maxNumLit + maxNumDist]int)
+	f.bits = new([maxLit + maxDist]int)
 	f.codebits = new([numCodes]int)
 	f.step = (*decompressor).nextBlock
 	f.setDict(dict)
diff --git a/src/compress/lzw/reader.go b/src/compress/lzw/reader.go
index 1353831..526620c 100644
--- a/src/compress/lzw/reader.go
+++ b/src/compress/lzw/reader.go
@@ -139,7 +139,6 @@ func (d *decoder) decode() {
 				err = io.ErrUnexpectedEOF
 			}
 			d.err = err
-			d.flush()
 			return
 		}
 		switch {
@@ -191,7 +190,6 @@ func (d *decoder) decode() {
 			}
 		default:
 			d.err = errors.New("lzw: invalid code")
-			d.flush()
 			return
 		}
 		d.last, d.hi = code, d.hi+1
@@ -215,7 +213,7 @@ func (d *decoder) flush() {
 	d.o = 0
 }
 
-var errClosed = errors.New("lzw: reader/writer is closed")
+var errClosed = errors.New("compress/lzw: reader/writer is closed")
 
 func (d *decoder) Close() error {
 	d.err = errClosed // in case any Reads come along
@@ -229,8 +227,7 @@ func (d *decoder) Close() error {
 // 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
-// range [2,8] and is typically 8. It must equal the litWidth
-// used during compression.
+// range [2,8] and is typically 8.
 func NewReader(r io.Reader, order Order, litWidth int) io.ReadCloser {
 	d := new(decoder)
 	switch order {
diff --git a/src/compress/lzw/reader_test.go b/src/compress/lzw/reader_test.go
index c3a5c3a..9006c91 100644
--- a/src/compress/lzw/reader_test.go
+++ b/src/compress/lzw/reader_test.go
@@ -98,20 +98,13 @@ func TestReader(t *testing.T) {
 		defer rc.Close()
 		b.Reset()
 		n, err := io.Copy(&b, rc)
-		s := b.String()
 		if err != nil {
 			if err != tt.err {
 				t.Errorf("%s: io.Copy: %v want %v", tt.desc, err, tt.err)
 			}
-			if err == io.ErrUnexpectedEOF {
-				// Even if the input is truncated, we should still return the
-				// partial decoded result.
-				if n == 0 || !strings.HasPrefix(tt.raw, s) {
-					t.Errorf("got %d bytes (%q), want a non-empty prefix of %q", n, s, tt.raw)
-				}
-			}
 			continue
 		}
+		s := b.String()
 		if s != tt.raw {
 			t.Errorf("%s: got %d-byte %q want %d-byte %q", tt.desc, n, s, len(tt.raw), tt.raw)
 		}
diff --git a/src/compress/lzw/writer.go b/src/compress/lzw/writer.go
index 7367c29..961b25f 100644
--- a/src/compress/lzw/writer.go
+++ b/src/compress/lzw/writer.go
@@ -138,23 +138,16 @@ func (e *encoder) Write(p []byte) (n int, err error) {
 	if len(p) == 0 {
 		return 0, nil
 	}
-	if maxLit := uint8(1<<e.litWidth - 1); maxLit != 0xff {
-		for _, x := range p {
-			if x > maxLit {
-				e.err = errors.New("lzw: input byte too large for the litWidth")
-				return 0, e.err
-			}
-		}
-	}
 	n = len(p)
+	litMask := uint32(1<<e.litWidth - 1)
 	code := e.savedCode
 	if code == invalidCode {
 		// The first code sent is always a literal code.
-		code, p = uint32(p[0]), p[1:]
+		code, p = uint32(p[0])&litMask, p[1:]
 	}
 loop:
 	for _, x := range p {
-		literal := uint32(x)
+		literal := uint32(x) & litMask
 		key := code<<8 | literal
 		// If there is a hash table hit for this key then we continue the loop
 		// and do not emit a code yet.
@@ -237,7 +230,7 @@ func (e *encoder) Close() error {
 // 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
-// range [2,8] and is typically 8. Input bytes must be less than 1<<litWidth.
+// range [2,8] and is typically 8.
 func NewWriter(w io.Writer, order Order, litWidth int) io.WriteCloser {
 	var write func(*encoder, uint32) error
 	switch order {
diff --git a/src/compress/lzw/writer_test.go b/src/compress/lzw/writer_test.go
index c20d058..3e4e6de 100644
--- a/src/compress/lzw/writer_test.go
+++ b/src/compress/lzw/writer_test.go
@@ -104,16 +104,6 @@ func TestWriterReturnValues(t *testing.T) {
 	}
 }
 
-func TestSmallLitWidth(t *testing.T) {
-	w := NewWriter(ioutil.Discard, LSB, 2)
-	if _, err := w.Write([]byte{0x03}); err != nil {
-		t.Fatalf("write a byte < 1<<2: %v", err)
-	}
-	if _, err := w.Write([]byte{0x04}); err == nil {
-		t.Fatal("write a byte >= 1<<2: got nil error, want non-nil")
-	}
-}
-
 func benchmarkEncoder(b *testing.B, n int) {
 	b.StopTimer()
 	b.SetBytes(int64(n))
diff --git a/src/crypto/cipher/cipher.go b/src/crypto/cipher/cipher.go
index 7d27fde..67afdb1 100644
--- a/src/crypto/cipher/cipher.go
+++ b/src/crypto/cipher/cipher.go
@@ -29,9 +29,6 @@ type Block interface {
 type Stream interface {
 	// XORKeyStream XORs each byte in the given slice with a byte from the
 	// cipher's key stream. Dst and src may point to the same memory.
-	// If len(dst) < len(src), XORKeyStream should panic. It is acceptable
-	// to pass a dst bigger than src, and in that case, XORKeyStream will
-	// only update dst[:len(src)] and will not touch the rest of dst.
 	XORKeyStream(dst, src []byte)
 }
 
diff --git a/src/crypto/cipher/gcm.go b/src/crypto/cipher/gcm.go
index bbdf9f5..bdafd85 100644
--- a/src/crypto/cipher/gcm.go
+++ b/src/crypto/cipher/gcm.go
@@ -52,26 +52,14 @@ type gcmFieldElement struct {
 // gcm represents a Galois Counter Mode with a specific key. See
 // http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/gcm-revised-spec.pdf
 type gcm struct {
-	cipher    Block
-	nonceSize int
+	cipher Block
 	// productTable contains the first sixteen powers of the key, H.
-	// However, they are in bit reversed order. See NewGCMWithNonceSize.
+	// However, they are in bit reversed order. See NewGCM.
 	productTable [16]gcmFieldElement
 }
 
-// NewGCM returns the given 128-bit, block cipher wrapped in Galois Counter Mode
-// with the standard nonce length.
+// NewGCM returns the given 128-bit, block cipher wrapped in Galois Counter Mode.
 func NewGCM(cipher Block) (AEAD, error) {
-	return NewGCMWithNonceSize(cipher, gcmStandardNonceSize)
-}
-
-// NewGCMWithNonceSize returns the given 128-bit, block cipher wrapped in Galois
-// Counter Mode, which accepts nonces of the given length.
-//
-// Only use this function if you require compatibility with an existing
-// cryptosystem that uses non-standard nonce lengths. All other users should use
-// NewGCM, which is faster and more resistant to misuse.
-func NewGCMWithNonceSize(cipher Block, size int) (AEAD, error) {
 	if cipher.BlockSize() != gcmBlockSize {
 		return nil, errors.New("cipher: NewGCM requires 128-bit block cipher")
 	}
@@ -79,7 +67,7 @@ func NewGCMWithNonceSize(cipher Block, size int) (AEAD, error) {
 	var key [gcmBlockSize]byte
 	cipher.Encrypt(key[:], key[:])
 
-	g := &gcm{cipher: cipher, nonceSize: size}
+	g := &gcm{cipher: cipher}
 
 	// We precompute 16 multiples of |key|. However, when we do lookups
 	// into this table we'll be using bits from a field element and
@@ -101,13 +89,13 @@ func NewGCMWithNonceSize(cipher Block, size int) (AEAD, error) {
 }
 
 const (
-	gcmBlockSize         = 16
-	gcmTagSize           = 16
-	gcmStandardNonceSize = 12
+	gcmBlockSize = 16
+	gcmTagSize   = 16
+	gcmNonceSize = 12
 )
 
-func (g *gcm) NonceSize() int {
-	return g.nonceSize
+func (*gcm) NonceSize() int {
+	return gcmNonceSize
 }
 
 func (*gcm) Overhead() int {
@@ -115,13 +103,16 @@ func (*gcm) Overhead() int {
 }
 
 func (g *gcm) Seal(dst, nonce, plaintext, data []byte) []byte {
-	if len(nonce) != g.nonceSize {
+	if len(nonce) != gcmNonceSize {
 		panic("cipher: incorrect nonce length given to GCM")
 	}
+
 	ret, out := sliceForAppend(dst, len(plaintext)+gcmTagSize)
 
+	// See GCM spec, section 7.1.
 	var counter, tagMask [gcmBlockSize]byte
-	g.deriveCounter(&counter, nonce)
+	copy(counter[:], nonce)
+	counter[gcmBlockSize-1] = 1
 
 	g.cipher.Encrypt(tagMask[:], counter[:])
 	gcmInc32(&counter)
@@ -135,7 +126,7 @@ func (g *gcm) Seal(dst, nonce, plaintext, data []byte) []byte {
 var errOpen = errors.New("cipher: message authentication failed")
 
 func (g *gcm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) {
-	if len(nonce) != g.nonceSize {
+	if len(nonce) != gcmNonceSize {
 		panic("cipher: incorrect nonce length given to GCM")
 	}
 
@@ -145,8 +136,10 @@ func (g *gcm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) {
 	tag := ciphertext[len(ciphertext)-gcmTagSize:]
 	ciphertext = ciphertext[:len(ciphertext)-gcmTagSize]
 
+	// See GCM spec, section 7.1.
 	var counter, tagMask [gcmBlockSize]byte
-	g.deriveCounter(&counter, nonce)
+	copy(counter[:], nonce)
+	counter[gcmBlockSize-1] = 1
 
 	g.cipher.Encrypt(tagMask[:], counter[:])
 	gcmInc32(&counter)
@@ -205,7 +198,7 @@ var gcmReductionTable = []uint16{
 	0xe100, 0xfd20, 0xd940, 0xc560, 0x9180, 0x8da0, 0xa9c0, 0xb5e0,
 }
 
-// mul sets y to y*H, where H is the GCM key, fixed during NewGCMWithNonceSize.
+// mul sets y to y*H, where H is the GCM key, fixed during NewGCM.
 func (g *gcm) mul(y *gcmFieldElement) {
 	var z gcmFieldElement
 
@@ -226,7 +219,7 @@ func (g *gcm) mul(y *gcmFieldElement) {
 
 			// the values in |table| are ordered for
 			// little-endian bit positions. See the comment
-			// in NewGCMWithNonceSize.
+			// in NewGCM.
 			t := &g.productTable[word&0xf]
 
 			z.low ^= t.low
@@ -308,29 +301,6 @@ func (g *gcm) counterCrypt(out, in []byte, counter *[gcmBlockSize]byte) {
 	}
 }
 
-// deriveCounter computes the initial GCM counter state from the given nonce.
-// See NIST SP 800-38D, section 7.1. This assumes that counter is filled with
-// zeros on entry.
-func (g *gcm) deriveCounter(counter *[gcmBlockSize]byte, nonce []byte) {
-	// GCM has two modes of operation with respect to the initial counter
-	// state: a "fast path" for 96-bit (12-byte) nonces, and a "slow path"
-	// for nonces of other lengths. For a 96-bit nonce, the nonce, along
-	// with a four-byte big-endian counter starting at one, is used
-	// directly as the starting counter. For other nonce sizes, the counter
-	// is computed by passing it through the GHASH function.
-	if len(nonce) == gcmStandardNonceSize {
-		copy(counter[:], nonce)
-		counter[gcmBlockSize-1] = 1
-	} else {
-		var y gcmFieldElement
-		g.update(&y, nonce)
-		y.high ^= uint64(len(nonce)) * 8
-		g.mul(&y)
-		putUint64(counter[:8], y.low)
-		putUint64(counter[8:], y.high)
-	}
-}
-
 // auth calculates GHASH(ciphertext, additionalData), masks the result with
 // tagMask and writes the result to out.
 func (g *gcm) auth(out, ciphertext, additionalData []byte, tagMask *[gcmTagSize]byte) {
diff --git a/src/crypto/cipher/gcm_test.go b/src/crypto/cipher/gcm_test.go
index 81b9aa2..0c502ce 100644
--- a/src/crypto/cipher/gcm_test.go
+++ b/src/crypto/cipher/gcm_test.go
@@ -101,35 +101,6 @@ var aesGCMTests = []struct {
 		"",
 		"b2051c80014f42f08735a7b0cd38e6bcd29962e5f2c13626b85a877101",
 	},
-	// These cases test non-standard nonce sizes.
-	{
-		"1672c3537afa82004c6b8a46f6f0d026",
-		"05",
-		"",
-		"",
-		"8e2ad721f9455f74d8b53d3141f27e8e",
-	},
-	{
-		"9a4fea86a621a91ab371e492457796c0",
-		"75",
-		"ca6131faf0ff210e4e693d6c31c109fc5b6f54224eb120f37de31dc59ec669b6",
-		"4f6e2585c161f05a9ae1f2f894e9f0ab52b45d0f",
-		"5698c0a384241d30004290aac56bb3ece6fe8eacc5c4be98954deb9c3ff6aebf5d50e1af100509e1fba2a5e8a0af9670",
-	},
-	{
-		"d0f1f4defa1e8c08b4b26d576392027c",
-		"42b4f01eb9f5a1ea5b1eb73b0fb0baed54f387ecaa0393c7d7dffc6af50146ecc021abf7eb9038d4303d91f8d741a11743166c0860208bcc02c6258fd9511a2fa626f96d60b72fcff773af4e88e7a923506e4916ecbd814651e9f445adef4ad6a6b6c7290cc13b956130eef5b837c939fcac0cbbcc9656cd75b13823ee5acdac",
-		"",
-		"",
-		"7ab49b57ddf5f62c427950111c5c4f0d",
-	},
-	{
-		"4a0c00a3d284dea9d4bf8b8dde86685e",
-		"f8cbe82588e784bcacbe092cd9089b51e01527297f635bf294b3aa787d91057ef23869789698ac960707857f163ecb242135a228ad93964f5dc4a4d7f88fd7b3b07dd0a5b37f9768fb05a523639f108c34c661498a56879e501a2321c8a4a94d7e1b89db255ac1f685e185263368e99735ebe62a7f2931b47282be8eb165e4d7",
-		"6d4bf87640a6a48a50d28797b7",
-		"8d8c7ffc55086d539b5a8f0d1232654c",
-		"0d803ec309482f35b8e6226f2b56303239298e06b281c2d51aaba3c125",
-	},
 }
 
 func TestAESGCM(t *testing.T) {
@@ -143,7 +114,7 @@ func TestAESGCM(t *testing.T) {
 		nonce, _ := hex.DecodeString(test.nonce)
 		plaintext, _ := hex.DecodeString(test.plaintext)
 		ad, _ := hex.DecodeString(test.ad)
-		aesgcm, err := cipher.NewGCMWithNonceSize(aes, len(nonce))
+		aesgcm, err := cipher.NewGCM(aes)
 		if err != nil {
 			t.Fatal(err)
 		}
diff --git a/src/crypto/crypto.go b/src/crypto/crypto.go
index 184ea9d..59b23e9 100644
--- a/src/crypto/crypto.go
+++ b/src/crypto/crypto.go
@@ -21,40 +21,36 @@ func (h Hash) HashFunc() Hash {
 }
 
 const (
-	MD4        Hash = 1 + iota // import golang.org/x/crypto/md4
-	MD5                        // import crypto/md5
-	SHA1                       // import crypto/sha1
-	SHA224                     // import crypto/sha256
-	SHA256                     // import crypto/sha256
-	SHA384                     // import crypto/sha512
-	SHA512                     // import crypto/sha512
-	MD5SHA1                    // no implementation; MD5+SHA1 used for TLS RSA
-	RIPEMD160                  // import golang.org/x/crypto/ripemd160
-	SHA3_224                   // import golang.org/x/crypto/sha3
-	SHA3_256                   // import golang.org/x/crypto/sha3
-	SHA3_384                   // import golang.org/x/crypto/sha3
-	SHA3_512                   // import golang.org/x/crypto/sha3
-	SHA512_224                 // import crypto/sha512
-	SHA512_256                 // import crypto/sha512
+	MD4       Hash = 1 + iota // import golang.org/x/crypto/md4
+	MD5                       // import crypto/md5
+	SHA1                      // import crypto/sha1
+	SHA224                    // import crypto/sha256
+	SHA256                    // import crypto/sha256
+	SHA384                    // import crypto/sha512
+	SHA512                    // import crypto/sha512
+	MD5SHA1                   // no implementation; MD5+SHA1 used for TLS RSA
+	RIPEMD160                 // import golang.org/x/crypto/ripemd160
+	SHA3_224                  // import golang.org/x/crypto/sha3
+	SHA3_256                  // import golang.org/x/crypto/sha3
+	SHA3_384                  // import golang.org/x/crypto/sha3
+	SHA3_512                  // import golang.org/x/crypto/sha3
 	maxHash
 )
 
 var digestSizes = []uint8{
-	MD4:        16,
-	MD5:        16,
-	SHA1:       20,
-	SHA224:     28,
-	SHA256:     32,
-	SHA384:     48,
-	SHA512:     64,
-	SHA512_224: 28,
-	SHA512_256: 32,
-	SHA3_224:   28,
-	SHA3_256:   32,
-	SHA3_384:   48,
-	SHA3_512:   64,
-	MD5SHA1:    36,
-	RIPEMD160:  20,
+	MD4:       16,
+	MD5:       16,
+	SHA1:      20,
+	SHA224:    28,
+	SHA256:    32,
+	SHA384:    48,
+	SHA512:    64,
+	SHA3_224:  28,
+	SHA3_256:  32,
+	SHA3_384:  48,
+	SHA3_512:  64,
+	MD5SHA1:   36,
+	RIPEMD160: 20,
 }
 
 // Size returns the length, in bytes, of a digest resulting from the given hash
@@ -128,19 +124,3 @@ type SignerOpts interface {
 	// hashing was done.
 	HashFunc() Hash
 }
-
-// Decrypter is an interface for an opaque private key that can be used for
-// asymmetric decryption operations. An example would be an RSA key
-// kept in a hardware module.
-type Decrypter interface {
-	// Public returns the public key corresponding to the opaque,
-	// private key.
-	Public() PublicKey
-
-	// Decrypt decrypts msg. The opts argument should be appropriate for
-	// the primitive used. See the documentation in each implementation for
-	// details.
-	Decrypt(rand io.Reader, msg []byte, opts DecrypterOpts) (plaintext []byte, err error)
-}
-
-type DecrypterOpts interface{}
diff --git a/src/crypto/ecdsa/ecdsa.go b/src/crypto/ecdsa/ecdsa.go
index 8d66477..d613553 100644
--- a/src/crypto/ecdsa/ecdsa.go
+++ b/src/crypto/ecdsa/ecdsa.go
@@ -4,33 +4,22 @@
 
 // Package ecdsa implements the Elliptic Curve Digital Signature Algorithm, as
 // defined in FIPS 186-3.
-//
-// This implementation  derives the nonce from an AES-CTR CSPRNG keyed by
-// ChopMD(256, SHA2-512(priv.D || entropy || hash)). The CSPRNG key is IRO by
-// a result of Coron; the AES-CTR stream is IRO under standard assumptions.
 package ecdsa
 
 // References:
 //   [NSA]: Suite B implementer's guide to FIPS 186-3,
 //     http://www.nsa.gov/ia/_files/ecdsa.pdf
 //   [SECG]: SECG, SEC1
-//     http://www.secg.org/sec1-v2.pdf
+//     http://www.secg.org/download/aid-780/sec1-v2.pdf
 
 import (
 	"crypto"
-	"crypto/aes"
-	"crypto/cipher"
 	"crypto/elliptic"
-	"crypto/sha512"
 	"encoding/asn1"
 	"io"
 	"math/big"
 )
 
-const (
-	aesIV = "IV for ECDSA CTR"
-)
-
 // PublicKey represents an ECDSA public key.
 type PublicKey struct {
 	elliptic.Curve
@@ -134,38 +123,6 @@ func fermatInverse(k, N *big.Int) *big.Int {
 // pair of integers. The security of the private key depends on the entropy of
 // rand.
 func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err error) {
-	// Get max(log2(q) / 2, 256) bits of entropy from rand.
-	entropylen := (priv.Curve.Params().BitSize + 7) / 16
-	if entropylen > 32 {
-		entropylen = 32
-	}
-	entropy := make([]byte, entropylen)
-	_, err = io.ReadFull(rand, entropy)
-	if err != nil {
-		return
-	}
-
-	// Initialize an SHA-512 hash context; digest ...
-	md := sha512.New()
-	md.Write(priv.D.Bytes()) // the private key,
-	md.Write(entropy)        // the entropy,
-	md.Write(hash)           // and the input hash;
-	key := md.Sum(nil)[:32]  // and compute ChopMD-256(SHA-512),
-	// which is an indifferentiable MAC.
-
-	// Create an AES-CTR instance to use as a CSPRNG.
-	block, err := aes.NewCipher(key)
-	if err != nil {
-		return nil, nil, err
-	}
-
-	// Create a CSPRNG that xors a stream of zeros with
-	// the output of the AES-CTR instance.
-	csprng := cipher.StreamReader{
-		R: zeroReader,
-		S: cipher.NewCTR(block, []byte(aesIV)),
-	}
-
 	// See [NSA] 3.4.1
 	c := priv.PublicKey.Curve
 	N := c.Params().N
@@ -173,7 +130,7 @@ func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err err
 	var k, kInv *big.Int
 	for {
 		for {
-			k, err = randFieldElement(c, csprng)
+			k, err = randFieldElement(c, rand)
 			if err != nil {
 				r = nil
 				return
@@ -230,17 +187,3 @@ func Verify(pub *PublicKey, hash []byte, r, s *big.Int) bool {
 	x.Mod(x, N)
 	return x.Cmp(r) == 0
 }
-
-type zr struct {
-	io.Reader
-}
-
-// Read replaces the contents of dst with zeros.
-func (z *zr) Read(dst []byte) (n int, err error) {
-	for i := range dst {
-		dst[i] = 0
-	}
-	return len(dst), nil
-}
-
-var zeroReader = &zr{}
diff --git a/src/crypto/ecdsa/ecdsa_test.go b/src/crypto/ecdsa/ecdsa_test.go
index 169944d..0c06431 100644
--- a/src/crypto/ecdsa/ecdsa_test.go
+++ b/src/crypto/ecdsa/ecdsa_test.go
@@ -72,78 +72,6 @@ func TestSignAndVerify(t *testing.T) {
 	testSignAndVerify(t, elliptic.P521(), "p521")
 }
 
-func testNonceSafety(t *testing.T, c elliptic.Curve, tag string) {
-	priv, _ := GenerateKey(c, rand.Reader)
-
-	hashed := []byte("testing")
-	r0, s0, err := Sign(zeroReader, priv, hashed)
-	if err != nil {
-		t.Errorf("%s: error signing: %s", tag, err)
-		return
-	}
-
-	hashed = []byte("testing...")
-	r1, s1, err := Sign(zeroReader, priv, hashed)
-	if err != nil {
-		t.Errorf("%s: error signing: %s", tag, err)
-		return
-	}
-
-	if s0.Cmp(s1) == 0 {
-		// This should never happen.
-		t.Errorf("%s: the signatures on two different messages were the same")
-	}
-
-	if r0.Cmp(r1) == 0 {
-		t.Errorf("%s: the nonce used for two diferent messages was the same")
-	}
-}
-
-func TestNonceSafety(t *testing.T) {
-	testNonceSafety(t, elliptic.P224(), "p224")
-	if testing.Short() {
-		return
-	}
-	testNonceSafety(t, elliptic.P256(), "p256")
-	testNonceSafety(t, elliptic.P384(), "p384")
-	testNonceSafety(t, elliptic.P521(), "p521")
-}
-
-func testINDCCA(t *testing.T, c elliptic.Curve, tag string) {
-	priv, _ := GenerateKey(c, rand.Reader)
-
-	hashed := []byte("testing")
-	r0, s0, err := Sign(rand.Reader, priv, hashed)
-	if err != nil {
-		t.Errorf("%s: error signing: %s", tag, err)
-		return
-	}
-
-	r1, s1, err := Sign(rand.Reader, priv, hashed)
-	if err != nil {
-		t.Errorf("%s: error signing: %s", tag, err)
-		return
-	}
-
-	if s0.Cmp(s1) == 0 {
-		t.Errorf("%s: two signatures of the same message produced the same result")
-	}
-
-	if r0.Cmp(r1) == 0 {
-		t.Errorf("%s: two signatures of the same message produced the same nonce")
-	}
-}
-
-func TestINDCCA(t *testing.T) {
-	testINDCCA(t, elliptic.P224(), "p224")
-	if testing.Short() {
-		return
-	}
-	testINDCCA(t, elliptic.P256(), "p256")
-	testINDCCA(t, elliptic.P384(), "p384")
-	testINDCCA(t, elliptic.P521(), "p521")
-}
-
 func fromHex(s string) *big.Int {
 	r, ok := new(big.Int).SetString(s, 16)
 	if !ok {
diff --git a/src/crypto/elliptic/elliptic.go b/src/crypto/elliptic/elliptic.go
index e6b59c5..ba673f8 100644
--- a/src/crypto/elliptic/elliptic.go
+++ b/src/crypto/elliptic/elliptic.go
@@ -24,7 +24,7 @@ import (
 type Curve interface {
 	// Params returns the parameters for the curve.
 	Params() *CurveParams
-	// IsOnCurve reports whether the given (x,y) lies on the curve.
+	// IsOnCurve returns true if the given (x,y) lies on the curve.
 	IsOnCurve(x, y *big.Int) bool
 	// Add returns the sum of (x1,y1) and (x2,y2)
 	Add(x1, y1, x2, y2 *big.Int) (x, y *big.Int)
@@ -45,7 +45,6 @@ type CurveParams struct {
 	B       *big.Int // the constant of the curve equation
 	Gx, Gy  *big.Int // (x,y) of the base point
 	BitSize int      // the size of the underlying field
-	Name    string   // the canonical name of the curve
 }
 
 func (curve *CurveParams) Params() *CurveParams {
@@ -308,8 +307,7 @@ func Marshal(curve Curve, x, y *big.Int) []byte {
 	return ret
 }
 
-// Unmarshal converts a point, serialized by Marshal, into an x, y pair.
-// It is an error if the point is not on the curve. On error, x = nil.
+// Unmarshal converts a point, serialized by Marshal, into an x, y pair. On error, x = nil.
 func Unmarshal(curve Curve, data []byte) (x, y *big.Int) {
 	byteLen := (curve.Params().BitSize + 7) >> 3
 	if len(data) != 1+2*byteLen {
@@ -320,9 +318,6 @@ func Unmarshal(curve Curve, data []byte) (x, y *big.Int) {
 	}
 	x = new(big.Int).SetBytes(data[1 : 1+byteLen])
 	y = new(big.Int).SetBytes(data[1+byteLen:])
-	if !curve.IsOnCurve(x, y) {
-		x, y = nil, nil
-	}
 	return
 }
 
@@ -339,7 +334,7 @@ func initAll() {
 
 func initP384() {
 	// See FIPS 186-3, section D.2.4
-	p384 = &CurveParams{Name: "P-384"}
+	p384 = new(CurveParams)
 	p384.P, _ = new(big.Int).SetString("39402006196394479212279040100143613805079739270465446667948293404245721771496870329047266088258938001861606973112319", 10)
 	p384.N, _ = new(big.Int).SetString("39402006196394479212279040100143613805079739270465446667946905279627659399113263569398956308152294913554433653942643", 10)
 	p384.B, _ = new(big.Int).SetString("b3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef", 16)
@@ -350,7 +345,7 @@ func initP384() {
 
 func initP521() {
 	// See FIPS 186-3, section D.2.5
-	p521 = &CurveParams{Name: "P-521"}
+	p521 = new(CurveParams)
 	p521.P, _ = new(big.Int).SetString("6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151", 10)
 	p521.N, _ = new(big.Int).SetString("6864797660130609714981900799081393217269435300143305409394463459185543183397655394245057746333217197532963996371363321113864768612440380340372808892707005449", 10)
 	p521.B, _ = new(big.Int).SetString("051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00", 16)
diff --git a/src/crypto/elliptic/elliptic_test.go b/src/crypto/elliptic/elliptic_test.go
index 7e27913..4dc27c9 100644
--- a/src/crypto/elliptic/elliptic_test.go
+++ b/src/crypto/elliptic/elliptic_test.go
@@ -19,19 +19,6 @@ func TestOnCurve(t *testing.T) {
 	}
 }
 
-func TestOffCurve(t *testing.T) {
-	p224 := P224()
-	x, y := new(big.Int).SetInt64(1), new(big.Int).SetInt64(1)
-	if p224.IsOnCurve(x, y) {
-		t.Errorf("FAIL: point off curve is claimed to be on the curve")
-	}
-	b := Marshal(p224, x, y)
-	x1, y1 := Unmarshal(p224, b)
-	if x1 != nil || y1 != nil {
-		t.Errorf("FAIL: unmarshalling a point not on the curve succeeded")
-	}
-}
-
 type baseMultTest struct {
 	k    string
 	x, y string
diff --git a/src/crypto/elliptic/p224.go b/src/crypto/elliptic/p224.go
index 2d3fac7..1f7ff3f 100644
--- a/src/crypto/elliptic/p224.go
+++ b/src/crypto/elliptic/p224.go
@@ -22,7 +22,7 @@ type p224Curve struct {
 
 func initP224() {
 	// See FIPS 186-3, section D.2.2
-	p224.CurveParams = &CurveParams{Name: "P-224"}
+	p224.CurveParams = new(CurveParams)
 	p224.P, _ = new(big.Int).SetString("26959946667150639794667015087019630673557916260026308143510066298881", 10)
 	p224.N, _ = new(big.Int).SetString("26959946667150639794667015087019625940457807714424391721682722368061", 10)
 	p224.B, _ = new(big.Int).SetString("b4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4", 16)
diff --git a/src/crypto/elliptic/p256.go b/src/crypto/elliptic/p256.go
index 82bc7b3..82be51e 100644
--- a/src/crypto/elliptic/p256.go
+++ b/src/crypto/elliptic/p256.go
@@ -23,7 +23,7 @@ var (
 
 func initP256() {
 	// See FIPS 186-3, section D.2.3
-	p256.CurveParams = &CurveParams{Name: "P-256"}
+	p256.CurveParams = new(CurveParams)
 	p256.P, _ = new(big.Int).SetString("115792089210356248762697446949407573530086143415290314195533631308867097853951", 10)
 	p256.N, _ = new(big.Int).SetString("115792089210356248762697446949407573529996955224135760342422259061068512044369", 10)
 	p256.B, _ = new(big.Int).SetString("5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b", 16)
diff --git a/src/crypto/hmac/hmac.go b/src/crypto/hmac/hmac.go
index e0cc1d6..b6f4919 100644
--- a/src/crypto/hmac/hmac.go
+++ b/src/crypto/hmac/hmac.go
@@ -11,7 +11,7 @@ The receiver verifies the hash by recomputing it using the same key.
 Receivers should be careful to use Equal to compare MACs in order to avoid
 timing side-channels:
 
-	// CheckMAC reports whether messageMAC is a valid HMAC tag for message.
+	// CheckMAC returns true if messageMAC is a valid HMAC tag for message.
 	func CheckMAC(message, messageMAC, key []byte) bool {
 		mac := hmac.New(sha256.New, key)
 		mac.Write(message)
diff --git a/src/crypto/md5/md5block_arm.s b/src/crypto/md5/md5block_arm.s
index f1f0f67..3b26e54 100644
--- a/src/crypto/md5/md5block_arm.s
+++ b/src/crypto/md5/md5block_arm.s
@@ -7,20 +7,20 @@
 #include "textflag.h"
 
 // Register definitions
-#define Rtable	R0	// Pointer to MD5 constants table
-#define Rdata	R1	// Pointer to data to hash
-#define Ra	R2	// MD5 accumulator
-#define Rb	R3	// MD5 accumulator
-#define Rc	R4	// MD5 accumulator
-#define Rd	R5	// MD5 accumulator
-#define Rc0	R6	// MD5 constant
-#define Rc1	R7	// MD5 constant
-#define Rc2	R8	// MD5 constant
+table = 0	// Pointer to MD5 constants table
+data = 1	// Pointer to data to hash
+a = 2		// MD5 accumulator
+b = 3		// MD5 accumulator
+c = 4		// MD5 accumulator
+d = 5		// MD5 accumulator
+c0 = 6		// MD5 constant
+c1 = 7		// MD5 constant
+c2 = 8		// MD5 constant
 // r9, r10 are forbidden
 // r11 is OK provided you check the assembler that no synthetic instructions use it
-#define Rc3	R11	// MD5 constant
-#define Rt0	R12	// temporary
-#define Rt1	R14	// temporary
+c3 = 11		// MD5 constant
+t0 = 12		// temporary
+t1 = 14		// temporary
 
 // func block(dig *digest, p []byte)
 // 0(FP) is *digest
@@ -29,198 +29,198 @@
 //12(FP) is p.cap
 //
 // Stack frame
-#define p_end	end-4(SP)	// pointer to the end of data
-#define p_data	data-8(SP)	// current data pointer
-#define buf	buffer-(8+4*16)(SP)	//16 words temporary buffer
+p_end = -4	// -4(SP) pointer to the end of data
+p_data = -8	// -8(SP) current data pointer
+buf = -8-4*16	//-72(SP) 16 words temporary buffer
 		// 3 words at 4..12(R13) for called routine parameters
 
 TEXT	·block(SB), NOSPLIT, $84-16
-	MOVW	p+4(FP), Rdata	// pointer to the data
-	MOVW	p_len+8(FP), Rt0	// number of bytes
-	ADD	Rdata, Rt0
-	MOVW	Rt0, p_end	// pointer to end of data
+	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
 
 loop:
-	MOVW	Rdata, p_data	// Save Rdata
-	AND.S	$3, Rdata, Rt0	// TST $3, Rdata not working see issue 5921
+	MOVW	R(data), p_data(SP)	// Save R(data)
+	AND.S	$3, R(data), R(t0)	// TST $3, R(data) not working see issue 5921
 	BEQ	aligned			// aligned detected - skip copy
 
 	// Copy the unaligned source data into the aligned temporary buffer
 	// memove(to=4(R13), from=8(R13), n=12(R13)) - Corrupts all registers
-	MOVW	$buf, Rtable	// to
-	MOVW	$64, Rc0		// n
-	MOVM.IB	[Rtable,Rdata,Rc0], (R13)
+	MOVW	$buf(SP), R(table)	// to
+	MOVW	$64, R(c0)		// n
+	MOVM.IB	[R(table),R(data),R(c0)], (R13)
 	BL	runtime·memmove(SB)
 
 	// Point to the local aligned copy of the data
-	MOVW	$buf, Rdata
+	MOVW	$buf(SP), R(data)
 
 aligned:
 	// Point to the table of constants
 	// A PC relative add would be cheaper than this
-	MOVW	$·table(SB), Rtable
+	MOVW	$·table(SB), R(table)
 
 	// Load up initial MD5 accumulator
-	MOVW	dig+0(FP), Rc0
-	MOVM.IA (Rc0), [Ra,Rb,Rc,Rd]
+	MOVW	dig+0(FP), R(c0)
+	MOVM.IA (R(c0)), [R(a),R(b),R(c),R(d)]
 
 // a += (((c^d)&b)^d) + X[index] + const
 // a = a<<shift | a>>(32-shift) + b
-#define ROUND1(Ra, Rb, Rc, Rd, index, shift, Rconst) \
-	EOR	Rc, Rd, Rt0		; \
-	AND	Rb, Rt0			; \
-	EOR	Rd, Rt0			; \
-	MOVW	(index<<2)(Rdata), Rt1	; \
-	ADD	Rt1, Rt0			; \
-	ADD	Rconst, Rt0			; \
-	ADD	Rt0, Ra			; \
-	ADD	Ra@>(32-shift), Rb, Ra	;
-
-	MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3]
-	ROUND1(Ra, Rb, Rc, Rd,  0,	7, Rc0)
-	ROUND1(Rd, Ra, Rb, Rc,  1, 12, Rc1)
-	ROUND1(Rc, Rd, Ra, Rb,  2, 17, Rc2)
-	ROUND1(Rb, Rc, Rd, Ra,  3, 22, Rc3)
-
-	MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3]
-	ROUND1(Ra, Rb, Rc, Rd,  4,	7, Rc0)
-	ROUND1(Rd, Ra, Rb, Rc,  5, 12, Rc1)
-	ROUND1(Rc, Rd, Ra, Rb,  6, 17, Rc2)
-	ROUND1(Rb, Rc, Rd, Ra,  7, 22, Rc3)
-
-	MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3]
-	ROUND1(Ra, Rb, Rc, Rd,  8,	7, Rc0)
-	ROUND1(Rd, Ra, Rb, Rc,  9, 12, Rc1)
-	ROUND1(Rc, Rd, Ra, Rb, 10, 17, Rc2)
-	ROUND1(Rb, Rc, Rd, Ra, 11, 22, Rc3)
-
-	MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3]
-	ROUND1(Ra, Rb, Rc, Rd, 12,	7, Rc0)
-	ROUND1(Rd, Ra, Rb, Rc, 13, 12, Rc1)
-	ROUND1(Rc, Rd, Ra, Rb, 14, 17, Rc2)
-	ROUND1(Rb, Rc, Rd, Ra, 15, 22, Rc3)
+#define ROUND1(a, b, c, d, index, shift, const) \
+	EOR	R(c), R(d), R(t0)		; \
+	AND	R(b), R(t0)			; \
+	EOR	R(d), R(t0)			; \
+	MOVW	(index<<2)(R(data)), R(t1)	; \
+	ADD	R(t1), R(t0)			; \
+	ADD	R(const), R(t0)			; \
+	ADD	R(t0), R(a)			; \
+	ADD	R(a)@>(32-shift), R(b), R(a)	;
+
+	MOVM.IA.W (R(table)), [R(c0),R(c1),R(c2),R(c3)]
+	ROUND1(a, b, c, d,  0,	7, c0)
+	ROUND1(d, a, b, c,  1, 12, c1)
+	ROUND1(c, d, a, b,  2, 17, c2)
+	ROUND1(b, c, d, a,  3, 22, c3)
+
+	MOVM.IA.W (R(table)), [R(c0),R(c1),R(c2),R(c3)]
+	ROUND1(a, b, c, d,  4,	7, c0)
+	ROUND1(d, a, b, c,  5, 12, c1)
+	ROUND1(c, d, a, b,  6, 17, c2)
+	ROUND1(b, c, d, a,  7, 22, c3)
+
+	MOVM.IA.W (R(table)), [R(c0),R(c1),R(c2),R(c3)]
+	ROUND1(a, b, c, d,  8,	7, c0)
+	ROUND1(d, a, b, c,  9, 12, c1)
+	ROUND1(c, d, a, b, 10, 17, c2)
+	ROUND1(b, c, d, a, 11, 22, c3)
+
+	MOVM.IA.W (R(table)), [R(c0),R(c1),R(c2),R(c3)]
+	ROUND1(a, b, c, d, 12,	7, c0)
+	ROUND1(d, a, b, c, 13, 12, c1)
+	ROUND1(c, d, a, b, 14, 17, c2)
+	ROUND1(b, c, d, a, 15, 22, c3)
 
 // a += (((b^c)&d)^c) + X[index] + const
 // a = a<<shift | a>>(32-shift) + b
-#define ROUND2(Ra, Rb, Rc, Rd, index, shift, Rconst) \
-	EOR	Rb, Rc, Rt0		; \
-	AND	Rd, Rt0			; \
-	EOR	Rc, Rt0			; \
-	MOVW	(index<<2)(Rdata), Rt1	; \
-	ADD	Rt1, Rt0			; \
-	ADD	Rconst, Rt0			; \
-	ADD	Rt0, Ra			; \
-	ADD	Ra@>(32-shift), Rb, Ra	;
-
-	MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3]
-	ROUND2(Ra, Rb, Rc, Rd,  1,	5, Rc0)
-	ROUND2(Rd, Ra, Rb, Rc,  6,	9, Rc1)
-	ROUND2(Rc, Rd, Ra, Rb, 11, 14, Rc2)
-	ROUND2(Rb, Rc, Rd, Ra,  0, 20, Rc3)
-
-	MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3]
-	ROUND2(Ra, Rb, Rc, Rd,  5,	5, Rc0)
-	ROUND2(Rd, Ra, Rb, Rc, 10,	9, Rc1)
-	ROUND2(Rc, Rd, Ra, Rb, 15, 14, Rc2)
-	ROUND2(Rb, Rc, Rd, Ra,  4, 20, Rc3)
-
-	MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3]
-	ROUND2(Ra, Rb, Rc, Rd,  9,	5, Rc0)
-	ROUND2(Rd, Ra, Rb, Rc, 14,	9, Rc1)
-	ROUND2(Rc, Rd, Ra, Rb,  3, 14, Rc2)
-	ROUND2(Rb, Rc, Rd, Ra,  8, 20, Rc3)
-
-	MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3]
-	ROUND2(Ra, Rb, Rc, Rd, 13,	5, Rc0)
-	ROUND2(Rd, Ra, Rb, Rc,  2,	9, Rc1)
-	ROUND2(Rc, Rd, Ra, Rb,  7, 14, Rc2)
-	ROUND2(Rb, Rc, Rd, Ra, 12, 20, Rc3)
+#define ROUND2(a, b, c, d, index, shift, const) \
+	EOR	R(b), R(c), R(t0)		; \
+	AND	R(d), R(t0)			; \
+	EOR	R(c), R(t0)			; \
+	MOVW	(index<<2)(R(data)), R(t1)	; \
+	ADD	R(t1), R(t0)			; \
+	ADD	R(const), R(t0)			; \
+	ADD	R(t0), R(a)			; \
+	ADD	R(a)@>(32-shift), R(b), R(a)	;
+
+	MOVM.IA.W (R(table)), [R(c0),R(c1),R(c2),R(c3)]
+	ROUND2(a, b, c, d,  1,	5, c0)
+	ROUND2(d, a, b, c,  6,	9, c1)
+	ROUND2(c, d, a, b, 11, 14, c2)
+	ROUND2(b, c, d, a,  0, 20, c3)
+
+	MOVM.IA.W (R(table)), [R(c0),R(c1),R(c2),R(c3)]
+	ROUND2(a, b, c, d,  5,	5, c0)
+	ROUND2(d, a, b, c, 10,	9, c1)
+	ROUND2(c, d, a, b, 15, 14, c2)
+	ROUND2(b, c, d, a,  4, 20, c3)
+
+	MOVM.IA.W (R(table)), [R(c0),R(c1),R(c2),R(c3)]
+	ROUND2(a, b, c, d,  9,	5, c0)
+	ROUND2(d, a, b, c, 14,	9, c1)
+	ROUND2(c, d, a, b,  3, 14, c2)
+	ROUND2(b, c, d, a,  8, 20, c3)
+
+	MOVM.IA.W (R(table)), [R(c0),R(c1),R(c2),R(c3)]
+	ROUND2(a, b, c, d, 13,	5, c0)
+	ROUND2(d, a, b, c,  2,	9, c1)
+	ROUND2(c, d, a, b,  7, 14, c2)
+	ROUND2(b, c, d, a, 12, 20, c3)
 
 // a += (b^c^d) + X[index] + const
 // a = a<<shift | a>>(32-shift) + b
-#define ROUND3(Ra, Rb, Rc, Rd, index, shift, Rconst) \
-	EOR	Rb, Rc, Rt0		; \
-	EOR	Rd, Rt0			; \
-	MOVW	(index<<2)(Rdata), Rt1	; \
-	ADD	Rt1, Rt0			; \
-	ADD	Rconst, Rt0			; \
-	ADD	Rt0, Ra			; \
-	ADD	Ra@>(32-shift), Rb, Ra	;
-
-	MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3]
-	ROUND3(Ra, Rb, Rc, Rd,  5,	4, Rc0)
-	ROUND3(Rd, Ra, Rb, Rc,  8, 11, Rc1)
-	ROUND3(Rc, Rd, Ra, Rb, 11, 16, Rc2)
-	ROUND3(Rb, Rc, Rd, Ra, 14, 23, Rc3)
-
-	MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3]
-	ROUND3(Ra, Rb, Rc, Rd,  1,	4, Rc0)
-	ROUND3(Rd, Ra, Rb, Rc,  4, 11, Rc1)
-	ROUND3(Rc, Rd, Ra, Rb,  7, 16, Rc2)
-	ROUND3(Rb, Rc, Rd, Ra, 10, 23, Rc3)
-
-	MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3]
-	ROUND3(Ra, Rb, Rc, Rd, 13,	4, Rc0)
-	ROUND3(Rd, Ra, Rb, Rc,  0, 11, Rc1)
-	ROUND3(Rc, Rd, Ra, Rb,  3, 16, Rc2)
-	ROUND3(Rb, Rc, Rd, Ra,  6, 23, Rc3)
-
-	MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3]
-	ROUND3(Ra, Rb, Rc, Rd,  9,	4, Rc0)
-	ROUND3(Rd, Ra, Rb, Rc, 12, 11, Rc1)
-	ROUND3(Rc, Rd, Ra, Rb, 15, 16, Rc2)
-	ROUND3(Rb, Rc, Rd, Ra,  2, 23, Rc3)
+#define ROUND3(a, b, c, d, index, shift, const) \
+	EOR	R(b), R(c), R(t0)		; \
+	EOR	R(d), R(t0)			; \
+	MOVW	(index<<2)(R(data)), R(t1)	; \
+	ADD	R(t1), R(t0)			; \
+	ADD	R(const), R(t0)			; \
+	ADD	R(t0), R(a)			; \
+	ADD	R(a)@>(32-shift), R(b), R(a)	;
+
+	MOVM.IA.W (R(table)), [R(c0),R(c1),R(c2),R(c3)]
+	ROUND3(a, b, c, d,  5,	4, c0)
+	ROUND3(d, a, b, c,  8, 11, c1)
+	ROUND3(c, d, a, b, 11, 16, c2)
+	ROUND3(b, c, d, a, 14, 23, c3)
+
+	MOVM.IA.W (R(table)), [R(c0),R(c1),R(c2),R(c3)]
+	ROUND3(a, b, c, d,  1,	4, c0)
+	ROUND3(d, a, b, c,  4, 11, c1)
+	ROUND3(c, d, a, b,  7, 16, c2)
+	ROUND3(b, c, d, a, 10, 23, c3)
+
+	MOVM.IA.W (R(table)), [R(c0),R(c1),R(c2),R(c3)]
+	ROUND3(a, b, c, d, 13,	4, c0)
+	ROUND3(d, a, b, c,  0, 11, c1)
+	ROUND3(c, d, a, b,  3, 16, c2)
+	ROUND3(b, c, d, a,  6, 23, c3)
+
+	MOVM.IA.W (R(table)), [R(c0),R(c1),R(c2),R(c3)]
+	ROUND3(a, b, c, d,  9,	4, c0)
+	ROUND3(d, a, b, c, 12, 11, c1)
+	ROUND3(c, d, a, b, 15, 16, c2)
+	ROUND3(b, c, d, a,  2, 23, c3)
 
 // a += (c^(b|^d)) + X[index] + const
 // a = a<<shift | a>>(32-shift) + b
-#define ROUND4(Ra, Rb, Rc, Rd, index, shift, Rconst) \
-	MVN	Rd, Rt0			; \
-	ORR	Rb, Rt0			; \
-	EOR	Rc, Rt0			; \
-	MOVW	(index<<2)(Rdata), Rt1	; \
-	ADD	Rt1, Rt0			; \
-	ADD	Rconst, Rt0			; \
-	ADD	Rt0, Ra			; \
-	ADD	Ra@>(32-shift), Rb, Ra	;
-
-	MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3]
-	ROUND4(Ra, Rb, Rc, Rd,  0,	6, Rc0)
-	ROUND4(Rd, Ra, Rb, Rc,  7, 10, Rc1)
-	ROUND4(Rc, Rd, Ra, Rb, 14, 15, Rc2)
-	ROUND4(Rb, Rc, Rd, Ra,  5, 21, Rc3)
-
-	MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3]
-	ROUND4(Ra, Rb, Rc, Rd, 12,	6, Rc0)
-	ROUND4(Rd, Ra, Rb, Rc,  3, 10, Rc1)
-	ROUND4(Rc, Rd, Ra, Rb, 10, 15, Rc2)
-	ROUND4(Rb, Rc, Rd, Ra,  1, 21, Rc3)
-
-	MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3]
-	ROUND4(Ra, Rb, Rc, Rd,  8,	6, Rc0)
-	ROUND4(Rd, Ra, Rb, Rc, 15, 10, Rc1)
-	ROUND4(Rc, Rd, Ra, Rb,  6, 15, Rc2)
-	ROUND4(Rb, Rc, Rd, Ra, 13, 21, Rc3)
-
-	MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3]
-	ROUND4(Ra, Rb, Rc, Rd,  4,	6, Rc0)
-	ROUND4(Rd, Ra, Rb, Rc, 11, 10, Rc1)
-	ROUND4(Rc, Rd, Ra, Rb,  2, 15, Rc2)
-	ROUND4(Rb, Rc, Rd, Ra,  9, 21, Rc3)
-
-	MOVW	dig+0(FP), Rt0
-	MOVM.IA (Rt0), [Rc0,Rc1,Rc2,Rc3]
-
-	ADD	Rc0, Ra
-	ADD	Rc1, Rb
-	ADD	Rc2, Rc
-	ADD	Rc3, Rd
-
-	MOVM.IA [Ra,Rb,Rc,Rd], (Rt0)
-
-	MOVW	p_data, Rdata
-	MOVW	p_end, Rt0
-	ADD	$64, Rdata
-	CMP	Rt0, Rdata
+#define ROUND4(a, b, c, d, index, shift, const) \
+	MVN	R(d), R(t0)			; \
+	ORR	R(b), R(t0)			; \
+	EOR	R(c), R(t0)			; \
+	MOVW	(index<<2)(R(data)), R(t1)	; \
+	ADD	R(t1), R(t0)			; \
+	ADD	R(const), R(t0)			; \
+	ADD	R(t0), R(a)			; \
+	ADD	R(a)@>(32-shift), R(b), R(a)	;
+
+	MOVM.IA.W (R(table)), [R(c0),R(c1),R(c2),R(c3)]
+	ROUND4(a, b, c, d,  0,	6, c0)
+	ROUND4(d, a, b, c,  7, 10, c1)
+	ROUND4(c, d, a, b, 14, 15, c2)
+	ROUND4(b, c, d, a,  5, 21, c3)
+
+	MOVM.IA.W (R(table)), [R(c0),R(c1),R(c2),R(c3)]
+	ROUND4(a, b, c, d, 12,	6, c0)
+	ROUND4(d, a, b, c,  3, 10, c1)
+	ROUND4(c, d, a, b, 10, 15, c2)
+	ROUND4(b, c, d, a,  1, 21, c3)
+
+	MOVM.IA.W (R(table)), [R(c0),R(c1),R(c2),R(c3)]
+	ROUND4(a, b, c, d,  8,	6, c0)
+	ROUND4(d, a, b, c, 15, 10, c1)
+	ROUND4(c, d, a, b,  6, 15, c2)
+	ROUND4(b, c, d, a, 13, 21, c3)
+
+	MOVM.IA.W (R(table)), [R(c0),R(c1),R(c2),R(c3)]
+	ROUND4(a, b, c, d,  4,	6, c0)
+	ROUND4(d, a, b, c, 11, 10, c1)
+	ROUND4(c, d, a, b,  2, 15, c2)
+	ROUND4(b, c, d, a,  9, 21, c3)
+
+	MOVW	dig+0(FP), R(t0)
+	MOVM.IA (R(t0)), [R(c0),R(c1),R(c2),R(c3)]
+
+	ADD	R(c0), R(a)
+	ADD	R(c1), R(b)
+	ADD	R(c2), R(c)
+	ADD	R(c3), R(d)
+
+	MOVM.IA [R(a),R(b),R(c),R(d)], (R(t0))
+
+	MOVW	p_data(SP), R(data)
+	MOVW	p_end(SP), R(t0)
+	ADD	$64, R(data)
+	CMP	R(t0), R(data)
 	BLO	loop
 
 	RET
diff --git a/src/crypto/rand/rand.go b/src/crypto/rand/rand.go
index ee32fa0..4da3adb 100644
--- a/src/crypto/rand/rand.go
+++ b/src/crypto/rand/rand.go
@@ -10,9 +10,7 @@ import "io"
 
 // Reader is a global, shared instance of a cryptographically
 // strong pseudo-random generator.
-//
 // On Unix-like systems, Reader reads from /dev/urandom.
-// On Linux, Reader uses getrandom(2) if available, /dev/urandom otherwise.
 // On Windows systems, Reader uses the CryptGenRandom API.
 var Reader io.Reader
 
diff --git a/src/crypto/rand/rand_linux.go b/src/crypto/rand/rand_linux.go
index 7d6d9e8..8cb59c7 100644
--- a/src/crypto/rand/rand_linux.go
+++ b/src/crypto/rand/rand_linux.go
@@ -5,7 +5,7 @@
 package rand
 
 import (
-	"internal/syscall/unix"
+	"internal/syscall"
 	"sync"
 )
 
@@ -25,7 +25,7 @@ func pickStrategy() {
 	// - the machine has no entropy available (early boot + no hardware
 	//   entropy source?) and we want to avoid blocking later.
 	var buf [1]byte
-	n, err := unix.GetRandom(buf[:], unix.GRND_NONBLOCK)
+	n, err := syscall.GetRandom(buf[:], syscall.GRND_NONBLOCK)
 	useSyscall = n == 1 && err == nil
 }
 
@@ -34,6 +34,6 @@ func getRandomLinux(p []byte) (ok bool) {
 	if !useSyscall {
 		return false
 	}
-	n, err := unix.GetRandom(p, 0)
+	n, err := syscall.GetRandom(p, 0)
 	return n == len(p) && err == nil
 }
diff --git a/src/crypto/rand/rand_unix.go b/src/crypto/rand/rand_unix.go
index 75c36e0..62d0fbd 100644
--- a/src/crypto/rand/rand_unix.go
+++ b/src/crypto/rand/rand_unix.go
@@ -58,28 +58,12 @@ func (r *devReader) Read(b []byte) (n int, err error) {
 		if runtime.GOOS == "plan9" {
 			r.f = f
 		} else {
-			r.f = bufio.NewReader(hideAgainReader{f})
+			r.f = bufio.NewReader(f)
 		}
 	}
 	return r.f.Read(b)
 }
 
-var isEAGAIN func(error) bool // set by eagain.go on unix systems
-
-// hideAgainReader masks EAGAIN reads from /dev/urandom.
-// See golang.org/issue/9205
-type hideAgainReader struct {
-	r io.Reader
-}
-
-func (hr hideAgainReader) Read(p []byte) (n int, err error) {
-	n, err = hr.r.Read(p)
-	if err != nil && isEAGAIN != nil && isEAGAIN(err) {
-		err = nil
-	}
-	return
-}
-
 // Alternate pseudo-random implementation for use on
 // systems without a reliable /dev/urandom.
 
diff --git a/src/crypto/rand/util_test.go b/src/crypto/rand/util_test.go
index 2f7cba8..1e2a4dd 100644
--- a/src/crypto/rand/util_test.go
+++ b/src/crypto/rand/util_test.go
@@ -10,7 +10,7 @@ import (
 	"testing"
 )
 
-// https://golang.org/issue/6849.
+// http://golang.org/issue/6849.
 func TestPrimeSmall(t *testing.T) {
 	for n := 2; n < 10; n++ {
 		p, err := rand.Prime(rand.Reader, n)
diff --git a/src/crypto/rc4/rc4_arm.s b/src/crypto/rc4/rc4_arm.s
index 05e94cb..51be3bf 100644
--- a/src/crypto/rc4/rc4_arm.s
+++ b/src/crypto/rc4/rc4_arm.s
@@ -7,56 +7,56 @@
 #include "textflag.h"
 
 // Registers
-#define Rdst	R0
-#define Rsrc	R1
-#define Rn	R2
-#define Rstate	R3
-#define Rpi	R4
-#define Rpj	R5
-#define Ri	R6
-#define Rj	R7
-#define Rk	R8
-#define Rt	R11
-#define Rt2	R12
+dst = 0
+src = 1
+n = 2
+state = 3
+pi = 4
+pj = 5
+i = 6
+j = 7
+k = 8
+t = 11
+t2 = 12
 
 // func xorKeyStream(dst, src *byte, n int, state *[256]byte, i, j *uint8)
 TEXT ·xorKeyStream(SB),NOSPLIT,$0
-	MOVW dst+0(FP), Rdst
-	MOVW src+4(FP), Rsrc
-	MOVW n+8(FP), Rn
-	MOVW state+12(FP), Rstate
-	MOVW pi+16(FP), Rpi
-	MOVW pj+20(FP), Rpj
-	MOVBU (Rpi), Ri
-	MOVBU (Rpj), Rj
-	MOVW $0, Rk
+	MOVW 0(FP), R(dst)
+	MOVW 4(FP), R(src)
+	MOVW 8(FP), R(n)
+	MOVW 12(FP), R(state)
+	MOVW 16(FP), R(pi)
+	MOVW 20(FP), R(pj)
+	MOVBU (R(pi)), R(i)
+	MOVBU (R(pj)), R(j)
+	MOVW $0, R(k)
 
 loop:
 	// i += 1; j += state[i]
-	ADD $1, Ri
-	AND $0xff, Ri
-	MOVBU Ri<<2(Rstate), Rt
-	ADD Rt, Rj
-	AND $0xff, Rj
+	ADD $1, R(i)
+	AND $0xff, R(i)
+	MOVBU R(i)<<2(R(state)), R(t)
+	ADD R(t), R(j)
+	AND $0xff, R(j)
 
 	// swap state[i] <-> state[j]
-	MOVBU Rj<<2(Rstate), Rt2
-	MOVB Rt2, Ri<<2(Rstate)
-	MOVB Rt, Rj<<2(Rstate)
+	MOVBU R(j)<<2(R(state)), R(t2)
+	MOVB R(t2), R(i)<<2(R(state))
+	MOVB R(t), R(j)<<2(R(state))
 
 	// dst[k] = src[k] ^ state[state[i] + state[j]]
-	ADD Rt2, Rt
-	AND $0xff, Rt
-	MOVBU Rt<<2(Rstate), Rt
-	MOVBU Rk<<0(Rsrc), Rt2
-	EOR Rt, Rt2
-	MOVB Rt2, Rk<<0(Rdst)
-
-	ADD $1, Rk
-	CMP Rk, Rn
+	ADD R(t2), R(t)
+	AND $0xff, R(t)
+	MOVBU R(t)<<2(R(state)), R(t)
+	MOVBU R(k)<<0(R(src)), R(t2)
+	EOR R(t), R(t2)
+	MOVB R(t2), R(k)<<0(R(dst))
+
+	ADD $1, R(k)
+	CMP R(k), R(n)
 	BNE loop
 
 done:
-	MOVB Ri, (Rpi)
-	MOVB Rj, (Rpj)
+	MOVB R(i), (R(pi))
+	MOVB R(j), (R(pj))
 	RET
diff --git a/src/crypto/rsa/pkcs1v15.go b/src/crypto/rsa/pkcs1v15.go
index 34037b0..59e8bb5 100644
--- a/src/crypto/rsa/pkcs1v15.go
+++ b/src/crypto/rsa/pkcs1v15.go
@@ -14,16 +14,6 @@ import (
 
 // This file implements encryption and decryption using PKCS#1 v1.5 padding.
 
-// PKCS1v15DecrypterOpts is for passing options to PKCS#1 v1.5 decryption using
-// the crypto.Decrypter interface.
-type PKCS1v15DecryptOptions struct {
-	// SessionKeyLen is the length of the session key that is being
-	// decrypted. If not zero, then a padding error during decryption will
-	// cause a random plaintext of this length to be returned rather than
-	// an error. These alternatives happen in constant time.
-	SessionKeyLen int
-}
-
 // EncryptPKCS1v15 encrypts the given message with RSA and the padding scheme from PKCS#1 v1.5.
 // The message must be no longer than the length of the public modulus minus 11 bytes.
 // WARNING: use of this function to encrypt plaintexts other than session keys
diff --git a/src/crypto/rsa/pkcs1v15_test.go b/src/crypto/rsa/pkcs1v15_test.go
index 8925375..2dc5dbc 100644
--- a/src/crypto/rsa/pkcs1v15_test.go
+++ b/src/crypto/rsa/pkcs1v15_test.go
@@ -51,25 +51,14 @@ var decryptPKCS1v15Tests = []DecryptPKCS1v15Test{
 }
 
 func TestDecryptPKCS1v15(t *testing.T) {
-	decryptionFuncs := []func([]byte) ([]byte, error){
-		func(ciphertext []byte) (plaintext []byte, err error) {
-			return DecryptPKCS1v15(nil, rsaPrivateKey, ciphertext)
-		},
-		func(ciphertext []byte) (plaintext []byte, err error) {
-			return rsaPrivateKey.Decrypt(nil, ciphertext, nil)
-		},
-	}
-
-	for _, decryptFunc := range decryptionFuncs {
-		for i, test := range decryptPKCS1v15Tests {
-			out, err := decryptFunc(decodeBase64(test.in))
-			if err != nil {
-				t.Errorf("#%d error decrypting", i)
-			}
-			want := []byte(test.out)
-			if !bytes.Equal(out, want) {
-				t.Errorf("#%d got:%#v want:%#v", i, out, want)
-			}
+	for i, test := range decryptPKCS1v15Tests {
+		out, err := DecryptPKCS1v15(nil, rsaPrivateKey, decodeBase64(test.in))
+		if err != nil {
+			t.Errorf("#%d error decrypting", i)
+		}
+		want := []byte(test.out)
+		if !bytes.Equal(out, want) {
+			t.Errorf("#%d got:%#v want:%#v", i, out, want)
 		}
 	}
 }
@@ -149,22 +138,6 @@ func TestEncryptPKCS1v15SessionKey(t *testing.T) {
 	}
 }
 
-func TestEncryptPKCS1v15DecrypterSessionKey(t *testing.T) {
-	for i, test := range decryptPKCS1v15SessionKeyTests {
-		plaintext, err := rsaPrivateKey.Decrypt(rand.Reader, decodeBase64(test.in), &PKCS1v15DecryptOptions{SessionKeyLen: 4})
-		if err != nil {
-			t.Fatalf("#%d: error decrypting: %s", i, err)
-		}
-		if len(plaintext) != 4 {
-			t.Fatalf("#%d: incorrect length plaintext: got %d, want 4", i, len(plaintext))
-		}
-
-		if test.out != "FAIL" && !bytes.Equal(plaintext, []byte(test.out)) {
-			t.Errorf("#%d: incorrect plaintext: got %x, want %x", plaintext, test.out)
-		}
-	}
-}
-
 func TestNonZeroRandomBytes(t *testing.T) {
 	random := rand.Reader
 
diff --git a/src/crypto/rsa/pss.go b/src/crypto/rsa/pss.go
index 0a41814..e9f2908 100644
--- a/src/crypto/rsa/pss.go
+++ b/src/crypto/rsa/pss.go
@@ -255,7 +255,7 @@ func SignPSS(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []byte,
 		saltLength = hash.Size()
 	}
 
-	if opts != nil && opts.Hash != 0 {
+	if opts.Hash != 0 {
 		hash = opts.Hash
 	}
 
diff --git a/src/crypto/rsa/pss_test.go b/src/crypto/rsa/pss_test.go
index cae24e5..32e6fc3 100644
--- a/src/crypto/rsa/pss_test.go
+++ b/src/crypto/rsa/pss_test.go
@@ -189,15 +189,6 @@ func TestPSSOpenSSL(t *testing.T) {
 	}
 }
 
-func TestPSSNilOpts(t *testing.T) {
-	hash := crypto.SHA256
-	h := hash.New()
-	h.Write([]byte("testing"))
-	hashed := h.Sum(nil)
-
-	SignPSS(rand.Reader, rsaPrivateKey, hash, hashed, nil)
-}
-
 func TestPSSSigning(t *testing.T) {
 	var saltLengthCombinations = []struct {
 		signSaltLength, verifySaltLength int
diff --git a/src/crypto/rsa/rsa.go b/src/crypto/rsa/rsa.go
index 1293b78..2702311 100644
--- a/src/crypto/rsa/rsa.go
+++ b/src/crypto/rsa/rsa.go
@@ -24,16 +24,6 @@ type PublicKey struct {
 	E int      // public exponent
 }
 
-// OAEPOptions is an interface for passing options to OAEP decryption using the
-// crypto.Decrypter interface.
-type OAEPOptions struct {
-	// Hash is the hash function that will be used when generating the mask.
-	Hash crypto.Hash
-	// Label is an arbitrary byte string that must be equal to the value
-	// used when encrypting.
-	Label []byte
-}
-
 var (
 	errPublicModulus       = errors.New("crypto/rsa: missing public modulus")
 	errPublicExponentSmall = errors.New("crypto/rsa: public exponent too small")
@@ -87,37 +77,6 @@ func (priv *PrivateKey) Sign(rand io.Reader, msg []byte, opts crypto.SignerOpts)
 	return SignPKCS1v15(rand, priv, opts.HashFunc(), msg)
 }
 
-// Decrypt decrypts ciphertext with priv. If opts is nil or of type
-// *PKCS1v15DecryptOptions then PKCS#1 v1.5 decryption is performed. Otherwise
-// opts must have type *OAEPOptions and OAEP decryption is done.
-func (priv *PrivateKey) Decrypt(rand io.Reader, ciphertext []byte, opts crypto.DecrypterOpts) (plaintext []byte, err error) {
-	if opts == nil {
-		return DecryptPKCS1v15(rand, priv, ciphertext)
-	}
-
-	switch opts := opts.(type) {
-	case *OAEPOptions:
-		return DecryptOAEP(opts.Hash.New(), rand, priv, ciphertext, opts.Label)
-
-	case *PKCS1v15DecryptOptions:
-		if l := opts.SessionKeyLen; l > 0 {
-			plaintext = make([]byte, l)
-			if _, err := io.ReadFull(rand, plaintext); err != nil {
-				return nil, err
-			}
-			if err := DecryptPKCS1v15SessionKey(rand, priv, ciphertext, plaintext); err != nil {
-				return nil, err
-			}
-			return plaintext, nil
-		} else {
-			return DecryptPKCS1v15(rand, priv, ciphertext)
-		}
-
-	default:
-		return nil, errors.New("crypto/rsa: invalid options for Decrypt")
-	}
-}
-
 type PrecomputedValues struct {
 	Dp, Dq *big.Int // D mod (P-1) (or mod Q-1)
 	Qinv   *big.Int // Q^-1 mod P
@@ -129,7 +88,7 @@ type PrecomputedValues struct {
 	CRTValues []CRTValue
 }
 
-// CRTValue contains the precomputed Chinese remainder theorem values.
+// CRTValue contains the precomputed chinese remainder theorem values.
 type CRTValue struct {
 	Exp   *big.Int // D mod (prime-1).
 	Coeff *big.Int // R·Coeff ≡ 1 mod Prime.
@@ -143,13 +102,19 @@ func (priv *PrivateKey) Validate() error {
 		return err
 	}
 
+	// Check that the prime factors are actually prime. Note that this is
+	// just a sanity check. Since the random witnesses chosen by
+	// ProbablyPrime are deterministic, given the candidate number, it's
+	// easy for an attack to generate composites that pass this test.
+	for _, prime := range priv.Primes {
+		if !prime.ProbablyPrime(20) {
+			return errors.New("crypto/rsa: prime factor is composite")
+		}
+	}
+
 	// Check that Πprimes == n.
 	modulus := new(big.Int).Set(bigOne)
 	for _, prime := range priv.Primes {
-		// Any primes ≤ 1 will cause divide-by-zero panics later.
-		if prime.Cmp(bigOne) <= 0 {
-			return errors.New("crypto/rsa: invalid prime value")
-		}
 		modulus.Mul(modulus, prime)
 	}
 	if modulus.Cmp(priv.N) != 0 {
diff --git a/src/crypto/sha1/sha1block_arm.s b/src/crypto/sha1/sha1block_arm.s
index c06d4ba..f11f33d 100644
--- a/src/crypto/sha1/sha1block_arm.s
+++ b/src/crypto/sha1/sha1block_arm.s
@@ -23,20 +23,20 @@
 // the round macros instead of by explicit move instructions.
 
 // Register definitions
-#define Rdata	R0	// Pointer to incoming data
-#define Rconst	R1	// Current constant for SHA round
-#define Ra	R2		// SHA1 accumulator
-#define Rb	R3		// SHA1 accumulator
-#define Rc	R4		// SHA1 accumulator
-#define Rd	R5		// SHA1 accumulator
-#define Re	R6		// SHA1 accumulator
-#define Rt0	R7		// Temporary
-#define Rt1	R8		// Temporary
+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
-#define Rt2	R11		// Temporary
-#define Rctr	R12	// loop counter
-#define Rw	R14		// point to w buffer
+t2 = 11		// Temporary
+ctr = 12	// loop counter
+w = 14		// point to w buffer
 
 // func block(dig *digest, p []byte)
 // 0(FP) is *digest
@@ -45,173 +45,173 @@
 //12(FP) is p.cap
 //
 // Stack frame
-#define p_end	end-4(SP)		// pointer to the end of data
-#define p_data	data-8(SP)	// current data pointer (unused?)
-#define w_buf	buf-(8+4*80)(SP)	//80 words temporary buffer w uint32[80]
-#define saved	abcde-(8+4*80+4*5)(SP)	// saved sha1 registers a,b,c,d,e - these must be last (unused?)
+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(Re) \
-	MOVBU	2(Rdata), Rt0 ; \
-	MOVBU	3(Rdata), Rt1 ; \
-	MOVBU	1(Rdata), Rt2 ; \
-	ORR	Rt0<<8, Rt1, Rt0	    ; \
-	MOVBU.P	4(Rdata), Rt1 ; \
-	ORR	Rt2<<16, Rt0, Rt0	    ; \
-	ORR	Rt1<<24, Rt0, Rt0	    ; \
-	MOVW.P	Rt0, 4(Rw)		    ; \
-	ADD	Rt0, Re, Re
+#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(Re) \
-	MOVW	(-16*4)(Rw), Rt0 ; \
-	MOVW	(-14*4)(Rw), Rt1 ; \
-	MOVW	(-8*4)(Rw), Rt2  ; \
-	EOR	Rt0, Rt1, Rt0  ; \
-	MOVW	(-3*4)(Rw), Rt1  ; \
-	EOR	Rt2, Rt0, Rt0  ; \
-	EOR	Rt0, Rt1, Rt0  ; \
-	MOVW	Rt0@>(32-1), Rt0  ; \
-	MOVW.P	Rt0, 4(Rw)	  ; \
-	ADD	Rt0, Re, Re
+#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(Ra, Rb, Rc, Rd, Re) \
-	MVN	Rb, Rt1	   ; \
-	AND	Rb, Rc, Rt0  ; \
-	AND	Rd, Rt1, Rt1 ; \
-	ORR	Rt0, Rt1, Rt1
+#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(Ra, Rb, Rc, Rd, Re) \
-	EOR	Rb, Rc, Rt1 ; \
-	EOR	Rd, Rt1, Rt1
+#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(Ra, Rb, Rc, Rd, Re) \
-	ORR	Rb, Rc, Rt0  ; \
-	AND	Rb, Rc, Rt1  ; \
-	AND	Rd, Rt0, Rt0 ; \
-	ORR	Rt0, Rt1, Rt1
+#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(Ra, Rb, Rc, Rd, Re) \
-	ADD	Rt1, Re, Re	 ; \
-	MOVW	Rb@>(32-30), Rb	 ; \
-	ADD	Ra@>(32-5), Re, Re ; \
-	ADD	Rconst, Re, Re
-
-#define ROUND1(Ra, Rb, Rc, Rd, Re) \
-	LOAD(Re)		; \
-	FUNC1(Ra, Rb, Rc, Rd, Re)	; \
-	MIX(Ra, Rb, Rc, Rd, Re)
-
-#define ROUND1x(Ra, Rb, Rc, Rd, Re) \
-	SHUFFLE(Re)	; \
-	FUNC1(Ra, Rb, Rc, Rd, Re)	; \
-	MIX(Ra, Rb, Rc, Rd, Re)
-
-#define ROUND2(Ra, Rb, Rc, Rd, Re) \
-	SHUFFLE(Re)	; \
-	FUNC2(Ra, Rb, Rc, Rd, Re)	; \
-	MIX(Ra, Rb, Rc, Rd, Re)
-
-#define ROUND3(Ra, Rb, Rc, Rd, Re) \
-	SHUFFLE(Re)	; \
-	FUNC3(Ra, Rb, Rc, Rd, Re)	; \
-	MIX(Ra, Rb, Rc, Rd, Re)
-
-#define ROUND4(Ra, Rb, Rc, Rd, Re) \
-	SHUFFLE(Re)	; \
-	FUNC4(Ra, Rb, Rc, Rd, Re)	; \
-	MIX(Ra, Rb, Rc, Rd, Re)
+#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), Rdata	// pointer to the data
-	MOVW	p_len+8(FP), Rt0	// number of bytes
-	ADD	Rdata, Rt0
-	MOVW	Rt0, p_end	// pointer to end of data
+	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), Rt0
-	MOVM.IA (Rt0), [Ra,Rb,Rc,Rd,Re]
+	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 [Ra,Rb,Rc,Rd,Re], (R13)
-
-	MOVW	$w_buf, Rw
-	MOVW	$0x5A827999, Rconst
-	MOVW	$3, Rctr
-loop1:	ROUND1(Ra, Rb, Rc, Rd, Re)
-	ROUND1(Re, Ra, Rb, Rc, Rd)
-	ROUND1(Rd, Re, Ra, Rb, Rc)
-	ROUND1(Rc, Rd, Re, Ra, Rb)
-	ROUND1(Rb, Rc, Rd, Re, Ra)
-	SUB.S	$1, Rctr
+	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(Ra, Rb, Rc, Rd, Re)
-	ROUND1x(Re, Ra, Rb, Rc, Rd)
-	ROUND1x(Rd, Re, Ra, Rb, Rc)
-	ROUND1x(Rc, Rd, Re, Ra, Rb)
-	ROUND1x(Rb, Rc, Rd, Re, Ra)
+	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, Rconst
-	MOVW	$4, Rctr
-loop2:	ROUND2(Ra, Rb, Rc, Rd, Re)
-	ROUND2(Re, Ra, Rb, Rc, Rd)
-	ROUND2(Rd, Re, Ra, Rb, Rc)
-	ROUND2(Rc, Rd, Re, Ra, Rb)
-	ROUND2(Rb, Rc, Rd, Re, Ra)
-	SUB.S	$1, Rctr
+	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, Rconst
-	MOVW	$4, Rctr
-loop3:	ROUND3(Ra, Rb, Rc, Rd, Re)
-	ROUND3(Re, Ra, Rb, Rc, Rd)
-	ROUND3(Rd, Re, Ra, Rb, Rc)
-	ROUND3(Rc, Rd, Re, Ra, Rb)
-	ROUND3(Rb, Rc, Rd, Re, Ra)
-	SUB.S	$1, Rctr
+	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, Rconst
-	MOVW	$4, Rctr
-loop4:	ROUND4(Ra, Rb, Rc, Rd, Re)
-	ROUND4(Re, Ra, Rb, Rc, Rd)
-	ROUND4(Rd, Re, Ra, Rb, Rc)
-	ROUND4(Rc, Rd, Re, Ra, Rb)
-	ROUND4(Rb, Rc, Rd, Re, Ra)
-	SUB.S	$1, Rctr
+	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), [Rt0,Rt1,Rt2,Rctr,Rw]
-	ADD	Rt0, Ra
-	ADD	Rt1, Rb
-	ADD	Rt2, Rc
-	ADD	Rctr, Rd
-	ADD	Rw, Re
-
-	MOVW	p_end, Rt0
-	CMP	Rt0, Rdata
+	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), Rt0
-	MOVM.IA [Ra,Rb,Rc,Rd,Re], (Rt0)
+	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/crypto/sha512/sha512.go b/src/crypto/sha512/sha512.go
index e7781fd..bca7a91 100644
--- a/src/crypto/sha512/sha512.go
+++ b/src/crypto/sha512/sha512.go
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// Package sha512 implements the SHA-384, SHA-512, SHA-512/224, and SHA-512/256
-// hash algorithms as defined in FIPS 180-4.
+// Package sha512 implements the SHA384 and SHA512 hash algorithms as defined
+// in FIPS 180-2.
 package sha512
 
 import (
@@ -14,27 +14,16 @@ import (
 func init() {
 	crypto.RegisterHash(crypto.SHA384, New384)
 	crypto.RegisterHash(crypto.SHA512, New)
-	crypto.RegisterHash(crypto.SHA512_224, New512_224)
-	crypto.RegisterHash(crypto.SHA512_256, New512_256)
 }
 
-const (
-	// Size is the size, in bytes, of a SHA-512 checksum.
-	Size = 64
-
-	// Size224 is the size, in bytes, of a SHA-512/224 checksum.
-	Size224 = 28
-
-	// Size256 is the size, in bytes, of a SHA-512/256 checksum.
-	Size256 = 32
+// The size of a SHA512 checksum in bytes.
+const Size = 64
 
-	// Size384 is the size, in bytes, of a SHA-384 checksum.
-	Size384 = 48
+// The size of a SHA384 checksum in bytes.
+const Size384 = 48
 
-	// BlockSize is the block size, in bytes, of the SHA-512/224,
-	// SHA-512/256, SHA-384 and SHA-512 hash functions.
-	BlockSize = 128
-)
+// The blocksize of SHA512 and SHA384 in bytes.
+const BlockSize = 128
 
 const (
 	chunk     = 128
@@ -46,22 +35,6 @@ const (
 	init5     = 0x9b05688c2b3e6c1f
 	init6     = 0x1f83d9abfb41bd6b
 	init7     = 0x5be0cd19137e2179
-	init0_224 = 0x8c3d37c819544da2
-	init1_224 = 0x73e1996689dcd4d6
-	init2_224 = 0x1dfab7ae32ff9c82
-	init3_224 = 0x679dd514582f9fcf
-	init4_224 = 0x0f6d2b697bd44da8
-	init5_224 = 0x77e36f7304c48942
-	init6_224 = 0x3f9d85a86a1d36c8
-	init7_224 = 0x1112e6ad91d692a1
-	init0_256 = 0x22312194fc2bf72c
-	init1_256 = 0x9f555fa3c84c64c2
-	init2_256 = 0x2393b86b6f53b151
-	init3_256 = 0x963877195940eabd
-	init4_256 = 0x96283ee2a88effe3
-	init5_256 = 0xbe5e1e2553863992
-	init6_256 = 0x2b0199fc2c85b8aa
-	init7_256 = 0x0eb72ddc81c52ca2
 	init0_384 = 0xcbbb9d5dc1059ed8
 	init1_384 = 0x629a292a367cd507
 	init2_384 = 0x9159015a3070dd17
@@ -74,43 +47,15 @@ const (
 
 // digest represents the partial evaluation of a checksum.
 type digest struct {
-	h        [8]uint64
-	x        [chunk]byte
-	nx       int
-	len      uint64
-	function crypto.Hash
+	h     [8]uint64
+	x     [chunk]byte
+	nx    int
+	len   uint64
+	is384 bool // mark if this digest is SHA-384
 }
 
 func (d *digest) Reset() {
-	switch d.function {
-	case crypto.SHA384:
-		d.h[0] = init0_384
-		d.h[1] = init1_384
-		d.h[2] = init2_384
-		d.h[3] = init3_384
-		d.h[4] = init4_384
-		d.h[5] = init5_384
-		d.h[6] = init6_384
-		d.h[7] = init7_384
-	case crypto.SHA512_224:
-		d.h[0] = init0_224
-		d.h[1] = init1_224
-		d.h[2] = init2_224
-		d.h[3] = init3_224
-		d.h[4] = init4_224
-		d.h[5] = init5_224
-		d.h[6] = init6_224
-		d.h[7] = init7_224
-	case crypto.SHA512_256:
-		d.h[0] = init0_256
-		d.h[1] = init1_256
-		d.h[2] = init2_256
-		d.h[3] = init3_256
-		d.h[4] = init4_256
-		d.h[5] = init5_256
-		d.h[6] = init6_256
-		d.h[7] = init7_256
-	default:
+	if !d.is384 {
 		d.h[0] = init0
 		d.h[1] = init1
 		d.h[2] = init2
@@ -119,50 +64,40 @@ func (d *digest) Reset() {
 		d.h[5] = init5
 		d.h[6] = init6
 		d.h[7] = init7
+	} else {
+		d.h[0] = init0_384
+		d.h[1] = init1_384
+		d.h[2] = init2_384
+		d.h[3] = init3_384
+		d.h[4] = init4_384
+		d.h[5] = init5_384
+		d.h[6] = init6_384
+		d.h[7] = init7_384
 	}
 	d.nx = 0
 	d.len = 0
 }
 
-// New returns a new hash.Hash computing the SHA-512 checksum.
+// New returns a new hash.Hash computing the SHA512 checksum.
 func New() hash.Hash {
-	d := &digest{function: crypto.SHA512}
-	d.Reset()
-	return d
-}
-
-// New512_224 returns a new hash.Hash computing the SHA-512/224 checksum.
-func New512_224() hash.Hash {
-	d := &digest{function: crypto.SHA512_224}
-	d.Reset()
-	return d
-}
-
-// New512_256 returns a new hash.Hash computing the SHA-512/256 checksum.
-func New512_256() hash.Hash {
-	d := &digest{function: crypto.SHA512_256}
+	d := new(digest)
 	d.Reset()
 	return d
 }
 
-// New384 returns a new hash.Hash computing the SHA-384 checksum.
+// New384 returns a new hash.Hash computing the SHA384 checksum.
 func New384() hash.Hash {
-	d := &digest{function: crypto.SHA384}
+	d := new(digest)
+	d.is384 = true
 	d.Reset()
 	return d
 }
 
 func (d *digest) Size() int {
-	switch d.function {
-	case crypto.SHA512_224:
-		return Size224
-	case crypto.SHA512_256:
-		return Size256
-	case crypto.SHA384:
-		return Size384
-	default:
+	if !d.is384 {
 		return Size
 	}
+	return Size384
 }
 
 func (d *digest) BlockSize() int { return BlockSize }
@@ -195,16 +130,10 @@ func (d0 *digest) Sum(in []byte) []byte {
 	d := new(digest)
 	*d = *d0
 	hash := d.checkSum()
-	switch d.function {
-	case crypto.SHA384:
+	if d.is384 {
 		return append(in, hash[:Size384]...)
-	case crypto.SHA512_224:
-		return append(in, hash[:Size224]...)
-	case crypto.SHA512_256:
-		return append(in, hash[:Size256]...)
-	default:
-		return append(in, hash[:]...)
 	}
+	return append(in, hash[:]...)
 }
 
 func (d *digest) checkSum() [Size]byte {
@@ -230,7 +159,7 @@ func (d *digest) checkSum() [Size]byte {
 	}
 
 	h := d.h[:]
-	if d.function == crypto.SHA384 {
+	if d.is384 {
 		h = d.h[:6]
 	}
 
@@ -251,7 +180,7 @@ func (d *digest) checkSum() [Size]byte {
 
 // Sum512 returns the SHA512 checksum of the data.
 func Sum512(data []byte) [Size]byte {
-	d := digest{function: crypto.SHA512}
+	var d digest
 	d.Reset()
 	d.Write(data)
 	return d.checkSum()
@@ -259,30 +188,11 @@ func Sum512(data []byte) [Size]byte {
 
 // Sum384 returns the SHA384 checksum of the data.
 func Sum384(data []byte) (sum384 [Size384]byte) {
-	d := digest{function: crypto.SHA384}
+	var d digest
+	d.is384 = true
 	d.Reset()
 	d.Write(data)
 	sum := d.checkSum()
 	copy(sum384[:], sum[:Size384])
 	return
 }
-
-// Sum512_224 returns the Sum512/224 checksum of the data.
-func Sum512_224(data []byte) (sum224 [Size224]byte) {
-	d := digest{function: crypto.SHA512_224}
-	d.Reset()
-	d.Write(data)
-	sum := d.checkSum()
-	copy(sum224[:], sum[:Size224])
-	return
-}
-
-// Sum512_256 returns the Sum512/256 checksum of the data.
-func Sum512_256(data []byte) (sum256 [Size256]byte) {
-	d := digest{function: crypto.SHA512_256}
-	d.Reset()
-	d.Write(data)
-	sum := d.checkSum()
-	copy(sum256[:], sum[:Size256])
-	return
-}
diff --git a/src/crypto/sha512/sha512_test.go b/src/crypto/sha512/sha512_test.go
index 04b3d4a..541860f 100644
--- a/src/crypto/sha512/sha512_test.go
+++ b/src/crypto/sha512/sha512_test.go
@@ -2,279 +2,133 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// SHA512 hash algorithm.  See FIPS 180-4.
+// SHA512 hash algorithm.  See FIPS 180-2.
 
 package sha512
 
 import (
-	"encoding/hex"
-	"hash"
+	"fmt"
 	"io"
 	"testing"
 )
 
 type sha512Test struct {
-	in     string
-	out224 string
-	out256 string
-	out384 string
-	out512 string
+	out string
+	in  string
 }
 
 var golden = []sha512Test{
-	{
-		"",
-		"6ed0dd02806fa89e25de060c19d3ac86cabb87d6a0ddd05c333b84f4",
-		"c672b8d1ef56ed28ab87c3622c5114069bdd3ad7b8f9737498d0c01ecef0967a",
-		"38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b",
-		"cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e",
-	},
-	{
-		"a",
-		"d5cdb9ccc769a5121d4175f2bfdd13d6310e0d3d361ea75d82108327",
-		"455e518824bc0601f9fb858ff5c37d417d67c2f8e0df2babe4808858aea830f8",
-		"54a59b9f22b0b80880d8427e548b7c23abd873486e1f035dce9cd697e85175033caa88e6d57bc35efae0b5afd3145f31",
-		"1f40fc92da241694750979ee6cf582f2d5d7d28e18335de05abc54d0560e0f5302860c652bf08d560252aa5e74210546f369fbbbce8c12cfc7957b2652fe9a75",
-	},
-	{
-		"ab",
-		"b35878d07bfedf39fc638af08547eb5d1072d8546319f247b442fbf5",
-		"22d4d37ec6370571af7109fb12eae79673d5f7c83e6e677083faa3cfac3b2c14",
-		"c7be03ba5bcaa384727076db0018e99248e1a6e8bd1b9ef58a9ec9dd4eeebb3f48b836201221175befa74ddc3d35afdd",
-		"2d408a0717ec188158278a796c689044361dc6fdde28d6f04973b80896e1823975cdbf12eb63f9e0591328ee235d80e9b5bf1aa6a44f4617ff3caf6400eb172d",
-	},
-	{
-		"abc",
-		"4634270f707b6a54daae7530460842e20e37ed265ceee9a43e8924aa",
-		"53048e2681941ef99b2e29b76b4c7dabe4c2d0c634fc6d46e0e2f13107e7af23",
-		"cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7",
-		"ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f",
-	},
-	{
-		"abcd",
-		"0c9f157ab030fb06e957c14e3938dc5908962e5dd7b66f04a36fc534",
-		"d2891c7978be0e24948f37caa415b87cb5cbe2b26b7bad9dc6391b8a6f6ddcc9",
-		"1165b3406ff0b52a3d24721f785462ca2276c9f454a116c2b2ba20171a7905ea5a026682eb659c4d5f115c363aa3c79b",
-		"d8022f2060ad6efd297ab73dcc5355c9b214054b0d1776a136a669d26a7d3b14f73aa0d0ebff19ee333368f0164b6419a96da49e3e481753e7e96b716bdccb6f",
-	},
-	{
-		"abcde",
-		"880e79bb0a1d2c9b7528d851edb6b8342c58c831de98123b432a4515",
-		"de8322b46e78b67d4431997070703e9764e03a1237b896fd8b379ed4576e8363",
-		"4c525cbeac729eaf4b4665815bc5db0c84fe6300068a727cf74e2813521565abc0ec57a37ee4d8be89d097c0d2ad52f0",
-		"878ae65a92e86cac011a570d4c30a7eaec442b85ce8eca0c2952b5e3cc0628c2e79d889ad4d5c7c626986d452dd86374b6ffaa7cd8b67665bef2289a5c70b0a1",
-	},
-	{
-		"abcdef",
-		"236c829cfea4fd6d4de61ad15fcf34dca62342adaf9f2001c16f29b8",
-		"e4fdcb11d1ac14e698743acd8805174cea5ddc0d312e3e47f6372032571bad84",
-		"c6a4c65b227e7387b9c3e839d44869c4cfca3ef583dea64117859b808c1e3d8ae689e1e314eeef52a6ffe22681aa11f5",
-		"e32ef19623e8ed9d267f657a81944b3d07adbb768518068e88435745564e8d4150a0a703be2a7d88b61e3d390c2bb97e2d4c311fdc69d6b1267f05f59aa920e7",
-	},
-	{
-		"abcdefg",
-		"4767af672b3ed107f25018dc22d6fa4b07d156e13b720971e2c4f6bf",
-		"a8117f680bdceb5d1443617cbdae9255f6900075422326a972fdd2f65ba9bee3",
-		"9f11fc131123f844c1226f429b6a0a6af0525d9f40f056c7fc16cdf1b06bda08e302554417a59fa7dcf6247421959d22",
-		"d716a4188569b68ab1b6dfac178e570114cdf0ea3a1cc0e31486c3e41241bc6a76424e8c37ab26f096fc85ef9886c8cb634187f4fddff645fb099f1ff54c6b8c",
-	},
-	{
-		"abcdefgh",
-		"792e25e0ae286d123a38950007e037d3122e76c4ee201668c385edab",
-		"a29b9645d2a02a8b582888d044199787220e316bf2e89d1422d3df26bf545bbe",
-		"9000cd7cada59d1d2eb82912f7f24e5e69cc5517f68283b005fa27c285b61e05edf1ad1a8a9bded6fd29eb87d75ad806",
-		"a3a8c81bc97c2560010d7389bc88aac974a104e0e2381220c6e084c4dccd1d2d17d4f86db31c2a851dc80e6681d74733c55dcd03dd96f6062cdda12a291ae6ce",
-	},
-	{
-		"abcdefghi",
-		"56b275d36127dc070cda4019baf2ce2579a25d8c67fa2bc9be61b539",
-		"b955095330f9c8188d11884ec1679dc44c9c5b25ff9bda700416df9cdd39188f",
-		"ef54915b60cf062b8dd0c29ae3cad69abe6310de63ac081f46ef019c5c90897caefd79b796cfa81139788a260ded52df",
-		"f22d51d25292ca1d0f68f69aedc7897019308cc9db46efb75a03dd494fc7f126c010e8ade6a00a0c1a5f1b75d81e0ed5a93ce98dc9b833db7839247b1d9c24fe",
-	},
-	{
-		"abcdefghij",
-		"f809423cbb25e81a2a64aecee2cd5fdc7d91d5db583901fbf1db3116",
-		"550762913d51eefbcd1a55068fcfc9b154fd11c1078b996df0d926ea59d2a68d",
-		"a12070030a02d86b0ddacd0d3a5b598344513d0a051e7355053e556a0055489c1555399b03342845c4adde2dc44ff66c",
-		"ef6b97321f34b1fea2169a7db9e1960b471aa13302a988087357c520be957ca119c3ba68e6b4982c019ec89de3865ccf6a3cda1fe11e59f98d99f1502c8b9745",
-	},
-	{
-		"Discard medicine more than two years old.",
-		"4c46e10b5b72204e509c3c06072cea970bc020cd45a61a0acdfa97ac",
-		"690c8ad3916cefd3ad29226d9875965e3ee9ec0d4482eacc248f2ff4aa0d8e5b",
-		"86f58ec2d74d1b7f8eb0c2ff0967316699639e8d4eb129de54bdf34c96cdbabe200d052149f2dd787f43571ba74670d4",
-		"2210d99af9c8bdecda1b4beff822136753d8342505ddce37f1314e2cdbb488c6016bdaa9bd2ffa513dd5de2e4b50f031393d8ab61f773b0e0130d7381e0f8a1d",
-	},
-	{
-		"He who has a shady past knows that nice guys finish last.",
-		"cb0cef13c1848d91a6d02637c7c520de1914ad4a7aea824671cc328e",
-		"25938ca49f7ef1178ce81620842b65e576245fcaed86026a36b516b80bb86b3b",
-		"ae4a2b639ca9bfa04b1855d5a05fe7f230994f790891c6979103e2605f660c4c1262a48142dcbeb57a1914ba5f7c3fa7",
-		"a687a8985b4d8d0a24f115fe272255c6afaf3909225838546159c1ed685c211a203796ae8ecc4c81a5b6315919b3a64f10713da07e341fcdbb08541bf03066ce",
-	},
-	{
-		"I wouldn't marry him with a ten foot pole.",
-		"6c7bd0f3a6544ea698006c2ea583a85f80ea2913590a186db8bb2f1b",
-		"698e420c3a7038e53d8e73f4be2b02e03b93464ac1a61ebe69f557079921ef65",
-		"40ae213df6436eca952aa6841886fcdb82908ef1576a99c8f49bb9dd5023169f7c53035abdda0b54c302f4974e2105e7",
-		"8ddb0392e818b7d585ab22769a50df660d9f6d559cca3afc5691b8ca91b8451374e42bcdabd64589ed7c91d85f626596228a5c8572677eb98bc6b624befb7af8",
-	},
-	{
-		"Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave",
-		"981323be3eca6ccfa598e58dd74ed8cb05d5f7f6653b7604b684f904",
-		"839b414d7e3900ee243aa3d1f9b6955720e64041f5ab9bedd3eb0a08da5a2ca8",
-		"e7cf8b873c9bc950f06259aa54309f349cefa72c00d597aebf903e6519a50011dfe355afff064a10701c705693848df9",
-		"26ed8f6ca7f8d44b6a8a54ae39640fa8ad5c673f70ee9ce074ba4ef0d483eea00bab2f61d8695d6b34df9c6c48ae36246362200ed820448bdc03a720366a87c6",
-	},
-	{
-		"The days of the digital watch are numbered.  -Tom Stoppard",
-		"e6fbf82df5138bf361e826903cadf0612cb2986649ba47a57e1bca99",
-		"5625ecb9d284e54c00b257b67a8cacb25a78db2845c60ef2d29e43c84f236e8e",
-		"c3d4f0f4047181c7d39d34703365f7bf70207183caf2c2f6145f04da895ef69124d9cdeb635da636c3a474e61024e29b",
-		"e5a14bf044be69615aade89afcf1ab0389d5fc302a884d403579d1386a2400c089b0dbb387ed0f463f9ee342f8244d5a38cfbc0e819da9529fbff78368c9a982",
-	},
-	{
-		"Nepal premier won't resign.",
-		"6ec2cb2ecafc1a9bddaf4caf57344d853e6ded398927d5694fd7714f",
-		"9b81d06bca2f985e6ad3249096ff3c0f2a9ec5bb16ef530d738d19d81e7806f2",
-		"a097aab567e167d5cf93676ed73252a69f9687cb3179bb2d27c9878119e94bf7b7c4b58dc90582edfaf66e11388ed714",
-		"420a1faa48919e14651bed45725abe0f7a58e0f099424c4e5a49194946e38b46c1f8034b18ef169b2e31050d1648e0b982386595f7df47da4b6fd18e55333015",
-	},
-	{
-		"For every action there is an equal and opposite government program.",
-		"7f62f36e716e0badaf4a4658da9d09bea26357a1bc6aeb8cf7c3ae35",
-		"08241df8d91edfcd68bb1a1dada6e0ae1475a5c6e7b8f12d8e24ca43a38240a9",
-		"5026ca45c41fc64712eb65065da92f6467541c78f8966d3fe2c8e3fb769a3ec14215f819654b47bd64f7f0eac17184f3",
-		"d926a863beadb20134db07683535c72007b0e695045876254f341ddcccde132a908c5af57baa6a6a9c63e6649bba0c213dc05fadcf9abccea09f23dcfb637fbe",
-	},
-	{
-		"His money is twice tainted: 'taint yours and 'taint mine.",
-		"45adffcb86a05ee4d91263a6115dda011b805d442c60836963cb8378",
-		"4ff74d9213a8117745f5d37b5353a774ec81c5dfe65c4c8986a56fc01f2c551e",
-		"ac1cc0f5ac8d5f5514a7b738ac322b7fb52a161b449c3672e9b6a6ad1a5e4b26b001cf3bad24c56598676ca17d4b445a",
-		"9a98dd9bb67d0da7bf83da5313dff4fd60a4bac0094f1b05633690ffa7f6d61de9a1d4f8617937d560833a9aaa9ccafe3fd24db418d0e728833545cadd3ad92d",
-	},
-	{
-		"There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977",
-		"51cb518f1f68daa901a3075a0a5e1acc755b4e5c82cb47687537f880",
-		"b5baf747c307f98849ec881cf0d48605ae4edd386372aea9b26e71db517e650b",
-		"722d10c5de371ec0c8c4b5247ac8a5f1d240d68c73f8da13d8b25f0166d6f309bf9561979a111a0049405771d201941a",
-		"d7fde2d2351efade52f4211d3746a0780a26eec3df9b2ed575368a8a1c09ec452402293a8ea4eceb5a4f60064ea29b13cdd86918cd7a4faf366160b009804107",
-	},
-	{
-		"It's a tiny change to the code and not completely disgusting. - Bob Manchek",
-		"3b59c5e64b0da7bfc18d7017bf458d90f2c83601ff1afc6263ac0993",
-		"7eef0538ebd7ecf18611d23b0e1cd26a74d65b929a2e374197dc66e755ca4944",
-		"dc2d3ea18bfa10549c63bf2b75b39b5167a80c12aff0e05443168ea87ff149fb0eda5e0bd234eb5d48c7d02ffc5807f1",
-		"b0f35ffa2697359c33a56f5c0cf715c7aeed96da9905ca2698acadb08fbc9e669bf566b6bd5d61a3e86dc22999bcc9f2224e33d1d4f32a228cf9d0349e2db518",
-	},
-	{
-		"size:  a.out:  bad magic",
-		"6a9525c0fac0f91b489bc4f0f539b9ec4a156a4e98bc15b655c2c881",
-		"d05600964f83f55323104aadab434f32391c029718a7690d08ddb2d7e8708443",
-		"1d67c969e2a945ae5346d2139760261504d4ba164c522443afe19ef3e29b152a4c52445489cfc9d7215e5a450e8e1e4e",
-		"3d2e5f91778c9e66f7e061293aaa8a8fc742dd3b2e4f483772464b1144189b49273e610e5cccd7a81a19ca1fa70f16b10f1a100a4d8c1372336be8484c64b311",
-	},
-	{
-		"The major problem is with sendmail.  -Mark Horton",
-		"a1b2b2905b1527d682049c6a76e35c7d8c72551abfe7833ac1be595f",
-		"53ed5f9b5c0b674ac0f3425d9f9a5d462655b07cc90f5d0f692eec093884a607",
-		"5ff8e075e465646e7b73ef36d812c6e9f7d60fa6ea0e533e5569b4f73cde53cdd2cc787f33540af57cca3fe467d32fe0",
-		"b2f68ff58ac015efb1c94c908b0d8c2bf06f491e4de8e6302c49016f7f8a33eac3e959856c7fddbc464de618701338a4b46f76dbfaf9a1e5262b5f40639771c7",
-	},
-	{
-		"Give me a rock, paper and scissors and I will move the world.  CCFestoon",
-		"76cf045c76a5f2e3d64d56c3cdba6a25479334611bc375460526f8c1",
-		"5a0147685a44eea2435dbd582724efca7637acd9c428e5e1a05115bc3bc2a0e0",
-		"5bd0a997a67c9ae1979a894eb0cde403dde003c9b6f2c03cf21925c42ff4e1176e6df1ca005381612ef18457b9b7ec3b",
-		"d8c92db5fdf52cf8215e4df3b4909d29203ff4d00e9ad0b64a6a4e04dec5e74f62e7c35c7fb881bd5de95442123df8f57a489b0ae616bd326f84d10021121c57",
-	},
-	{
-		"If the enemy is within range, then so are you.",
-		"4473671daeecfdb6f6c5bc06b26374aa5e497cc37119fe14144c430c",
-		"1152c9b27a99dbf4057d21438f4e63dd0cd0977d5ff12317c64d3b97fcac875a",
-		"1eee6da33e7e54fc5be52ae23b94b16ba4d2a947ae4505c6a3edfc7401151ea5205ac01b669b56f27d8ef7f175ed7762",
-		"19a9f8dc0a233e464e8566ad3ca9b91e459a7b8c4780985b015776e1bf239a19bc233d0556343e2b0a9bc220900b4ebf4f8bdf89ff8efeaf79602d6849e6f72e",
-	},
-	{
-		"It's well we cannot hear the screams/That we create in others' dreams.",
-		"6accb6394758523fcd453d47d37ebd10868957a0a9e81c796736abf8",
-		"105e890f5d5cf1748d9a7b4cdaf58b69855779deebc2097747c2210a17b2cb51",
-		"76b06e9dea66bfbb1a96029426dc0dfd7830bd297eb447ff5358d94a87cd00c88b59df2493fef56ecbb5231073892ea9",
-		"00b4c41f307bde87301cdc5b5ab1ae9a592e8ecbb2021dd7bc4b34e2ace60741cc362560bec566ba35178595a91932b8d5357e2c9cec92d393b0fa7831852476",
-	},
-	{
-		"You remind me of a TV show, but that's all right: I watch it anyway.",
-		"6f173f4b6eac7f2a73eaa0833c4563752df2c869dc00b7d30219e12e",
-		"74644ead770da1434365cd912656fe1aca2056d3039d39f10eb1151bddb32cf3",
-		"12acaf21452cff586143e3f5db0bfdf7802c057e1adf2a619031c4e1b0ccc4208cf6cef8fe722bbaa2fb46a30d9135d8",
-		"91eccc3d5375fd026e4d6787874b1dce201cecd8a27dbded5065728cb2d09c58a3d467bb1faf353bf7ba567e005245d5321b55bc344f7c07b91cb6f26c959be7",
-	},
-	{
-		"C is as portable as Stonehedge!!",
-		"db05bf4d0f73325208755f4af96cfac6cb3db5dbfc323d675d68f938",
-		"50a234625de5587581883dad9ef399460928032a5ea6bd005d7dc7b68d8cc3d6",
-		"0fc23d7f4183efd186f0bc4fc5db867e026e2146b06cb3d52f4bdbd57d1740122caa853b41868b197b2ac759db39df88",
-		"fabbbe22180f1f137cfdc9556d2570e775d1ae02a597ded43a72a40f9b485d500043b7be128fb9fcd982b83159a0d99aa855a9e7cc4240c00dc01a9bdf8218d7",
-	},
-	{
-		"Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley",
-		"05ffa71bb02e855de1aaee1777b3bdbaf7507646f19c4c6aa29933d0",
-		"a7a3846005f8a9935a0a2d43e7fd56d95132a9a3609bf3296ef80b8218acffa0",
-		"bc805578a7f85d34a86a32976e1c34fe65cf815186fbef76f46ef99cda10723f971f3f1464d488243f5e29db7488598d",
-		"2ecdec235c1fa4fc2a154d8fba1dddb8a72a1ad73838b51d792331d143f8b96a9f6fcb0f34d7caa351fe6d88771c4f105040e0392f06e0621689d33b2f3ba92e",
-	},
-	{
-		"The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction.  Lewis-Randall Rule",
-		"3ad3c89e15b91e6273534c5d18adadbb528e7b840b288f64e81b8c6d",
-		"688ff03e367680757aa9906cb1e2ad218c51f4526dc0426ea229a5ba9d002c69",
-		"b23918399a12ebf4431559eec3813eaf7412e875fd7464f16d581e473330842d2e96c6be49a7ce3f9bb0b8bc0fcbe0fe",
-		"7ad681f6f96f82f7abfa7ecc0334e8fa16d3dc1cdc45b60b7af43fe4075d2357c0c1d60e98350f1afb1f2fe7a4d7cd2ad55b88e458e06b73c40b437331f5dab4",
-	},
-	{
-		"How can you write a big system without C++?  -Paul Glick",
-		"e3763669d1b760c1be7bfcb6625f92300a8430419d1dbad57ec9f53c",
-		"3fa46d52094b01021cff5af9a438982b887a5793f624c0a6644149b6b7c3f485",
-		"1764b700eb1ead52a2fc33cc28975c2180f1b8faa5038d94cffa8d78154aab16e91dd787e7b0303948ebed62561542c8",
-		"833f9248ab4a3b9e5131f745fda1ffd2dd435b30e965957e78291c7ab73605fd1912b0794e5c233ab0a12d205a39778d19b83515d6a47003f19cdee51d98c7e0",
-	},
+	{"cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e", ""},
+	{"1f40fc92da241694750979ee6cf582f2d5d7d28e18335de05abc54d0560e0f5302860c652bf08d560252aa5e74210546f369fbbbce8c12cfc7957b2652fe9a75", "a"},
+	{"2d408a0717ec188158278a796c689044361dc6fdde28d6f04973b80896e1823975cdbf12eb63f9e0591328ee235d80e9b5bf1aa6a44f4617ff3caf6400eb172d", "ab"},
+	{"ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f", "abc"},
+	{"d8022f2060ad6efd297ab73dcc5355c9b214054b0d1776a136a669d26a7d3b14f73aa0d0ebff19ee333368f0164b6419a96da49e3e481753e7e96b716bdccb6f", "abcd"},
+	{"878ae65a92e86cac011a570d4c30a7eaec442b85ce8eca0c2952b5e3cc0628c2e79d889ad4d5c7c626986d452dd86374b6ffaa7cd8b67665bef2289a5c70b0a1", "abcde"},
+	{"e32ef19623e8ed9d267f657a81944b3d07adbb768518068e88435745564e8d4150a0a703be2a7d88b61e3d390c2bb97e2d4c311fdc69d6b1267f05f59aa920e7", "abcdef"},
+	{"d716a4188569b68ab1b6dfac178e570114cdf0ea3a1cc0e31486c3e41241bc6a76424e8c37ab26f096fc85ef9886c8cb634187f4fddff645fb099f1ff54c6b8c", "abcdefg"},
+	{"a3a8c81bc97c2560010d7389bc88aac974a104e0e2381220c6e084c4dccd1d2d17d4f86db31c2a851dc80e6681d74733c55dcd03dd96f6062cdda12a291ae6ce", "abcdefgh"},
+	{"f22d51d25292ca1d0f68f69aedc7897019308cc9db46efb75a03dd494fc7f126c010e8ade6a00a0c1a5f1b75d81e0ed5a93ce98dc9b833db7839247b1d9c24fe", "abcdefghi"},
+	{"ef6b97321f34b1fea2169a7db9e1960b471aa13302a988087357c520be957ca119c3ba68e6b4982c019ec89de3865ccf6a3cda1fe11e59f98d99f1502c8b9745", "abcdefghij"},
+	{"2210d99af9c8bdecda1b4beff822136753d8342505ddce37f1314e2cdbb488c6016bdaa9bd2ffa513dd5de2e4b50f031393d8ab61f773b0e0130d7381e0f8a1d", "Discard medicine more than two years old."},
+	{"a687a8985b4d8d0a24f115fe272255c6afaf3909225838546159c1ed685c211a203796ae8ecc4c81a5b6315919b3a64f10713da07e341fcdbb08541bf03066ce", "He who has a shady past knows that nice guys finish last."},
+	{"8ddb0392e818b7d585ab22769a50df660d9f6d559cca3afc5691b8ca91b8451374e42bcdabd64589ed7c91d85f626596228a5c8572677eb98bc6b624befb7af8", "I wouldn't marry him with a ten foot pole."},
+	{"26ed8f6ca7f8d44b6a8a54ae39640fa8ad5c673f70ee9ce074ba4ef0d483eea00bab2f61d8695d6b34df9c6c48ae36246362200ed820448bdc03a720366a87c6", "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"},
+	{"e5a14bf044be69615aade89afcf1ab0389d5fc302a884d403579d1386a2400c089b0dbb387ed0f463f9ee342f8244d5a38cfbc0e819da9529fbff78368c9a982", "The days of the digital watch are numbered.  -Tom Stoppard"},
+	{"420a1faa48919e14651bed45725abe0f7a58e0f099424c4e5a49194946e38b46c1f8034b18ef169b2e31050d1648e0b982386595f7df47da4b6fd18e55333015", "Nepal premier won't resign."},
+	{"d926a863beadb20134db07683535c72007b0e695045876254f341ddcccde132a908c5af57baa6a6a9c63e6649bba0c213dc05fadcf9abccea09f23dcfb637fbe", "For every action there is an equal and opposite government program."},
+	{"9a98dd9bb67d0da7bf83da5313dff4fd60a4bac0094f1b05633690ffa7f6d61de9a1d4f8617937d560833a9aaa9ccafe3fd24db418d0e728833545cadd3ad92d", "His money is twice tainted: 'taint yours and 'taint mine."},
+	{"d7fde2d2351efade52f4211d3746a0780a26eec3df9b2ed575368a8a1c09ec452402293a8ea4eceb5a4f60064ea29b13cdd86918cd7a4faf366160b009804107", "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"},
+	{"b0f35ffa2697359c33a56f5c0cf715c7aeed96da9905ca2698acadb08fbc9e669bf566b6bd5d61a3e86dc22999bcc9f2224e33d1d4f32a228cf9d0349e2db518", "It's a tiny change to the code and not completely disgusting. - Bob Manchek"},
+	{"3d2e5f91778c9e66f7e061293aaa8a8fc742dd3b2e4f483772464b1144189b49273e610e5cccd7a81a19ca1fa70f16b10f1a100a4d8c1372336be8484c64b311", "size:  a.out:  bad magic"},
+	{"b2f68ff58ac015efb1c94c908b0d8c2bf06f491e4de8e6302c49016f7f8a33eac3e959856c7fddbc464de618701338a4b46f76dbfaf9a1e5262b5f40639771c7", "The major problem is with sendmail.  -Mark Horton"},
+	{"d8c92db5fdf52cf8215e4df3b4909d29203ff4d00e9ad0b64a6a4e04dec5e74f62e7c35c7fb881bd5de95442123df8f57a489b0ae616bd326f84d10021121c57", "Give me a rock, paper and scissors and I will move the world.  CCFestoon"},
+	{"19a9f8dc0a233e464e8566ad3ca9b91e459a7b8c4780985b015776e1bf239a19bc233d0556343e2b0a9bc220900b4ebf4f8bdf89ff8efeaf79602d6849e6f72e", "If the enemy is within range, then so are you."},
+	{"00b4c41f307bde87301cdc5b5ab1ae9a592e8ecbb2021dd7bc4b34e2ace60741cc362560bec566ba35178595a91932b8d5357e2c9cec92d393b0fa7831852476", "It's well we cannot hear the screams/That we create in others' dreams."},
+	{"91eccc3d5375fd026e4d6787874b1dce201cecd8a27dbded5065728cb2d09c58a3d467bb1faf353bf7ba567e005245d5321b55bc344f7c07b91cb6f26c959be7", "You remind me of a TV show, but that's all right: I watch it anyway."},
+	{"fabbbe22180f1f137cfdc9556d2570e775d1ae02a597ded43a72a40f9b485d500043b7be128fb9fcd982b83159a0d99aa855a9e7cc4240c00dc01a9bdf8218d7", "C is as portable as Stonehedge!!"},
+	{"2ecdec235c1fa4fc2a154d8fba1dddb8a72a1ad73838b51d792331d143f8b96a9f6fcb0f34d7caa351fe6d88771c4f105040e0392f06e0621689d33b2f3ba92e", "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"},
+	{"7ad681f6f96f82f7abfa7ecc0334e8fa16d3dc1cdc45b60b7af43fe4075d2357c0c1d60e98350f1afb1f2fe7a4d7cd2ad55b88e458e06b73c40b437331f5dab4", "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction.  Lewis-Randall Rule"},
+	{"833f9248ab4a3b9e5131f745fda1ffd2dd435b30e965957e78291c7ab73605fd1912b0794e5c233ab0a12d205a39778d19b83515d6a47003f19cdee51d98c7e0", "How can you write a big system without C++?  -Paul Glick"},
 }
 
-func testHash(t *testing.T, name, in, outHex string, oneShotResult []byte, digestFunc hash.Hash) {
-	if calculated := hex.EncodeToString(oneShotResult); calculated != outHex {
-		t.Errorf("one-shot result for %s(%q) = %q, but expected %q", name, in, calculated, outHex)
-		return
-	}
+var golden384 = []sha512Test{
+	{"38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b", ""},
+	{"54a59b9f22b0b80880d8427e548b7c23abd873486e1f035dce9cd697e85175033caa88e6d57bc35efae0b5afd3145f31", "a"},
+	{"c7be03ba5bcaa384727076db0018e99248e1a6e8bd1b9ef58a9ec9dd4eeebb3f48b836201221175befa74ddc3d35afdd", "ab"},
+	{"cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7", "abc"},
+	{"1165b3406ff0b52a3d24721f785462ca2276c9f454a116c2b2ba20171a7905ea5a026682eb659c4d5f115c363aa3c79b", "abcd"},
+	{"4c525cbeac729eaf4b4665815bc5db0c84fe6300068a727cf74e2813521565abc0ec57a37ee4d8be89d097c0d2ad52f0", "abcde"},
+	{"c6a4c65b227e7387b9c3e839d44869c4cfca3ef583dea64117859b808c1e3d8ae689e1e314eeef52a6ffe22681aa11f5", "abcdef"},
+	{"9f11fc131123f844c1226f429b6a0a6af0525d9f40f056c7fc16cdf1b06bda08e302554417a59fa7dcf6247421959d22", "abcdefg"},
+	{"9000cd7cada59d1d2eb82912f7f24e5e69cc5517f68283b005fa27c285b61e05edf1ad1a8a9bded6fd29eb87d75ad806", "abcdefgh"},
+	{"ef54915b60cf062b8dd0c29ae3cad69abe6310de63ac081f46ef019c5c90897caefd79b796cfa81139788a260ded52df", "abcdefghi"},
+	{"a12070030a02d86b0ddacd0d3a5b598344513d0a051e7355053e556a0055489c1555399b03342845c4adde2dc44ff66c", "abcdefghij"},
+	{"86f58ec2d74d1b7f8eb0c2ff0967316699639e8d4eb129de54bdf34c96cdbabe200d052149f2dd787f43571ba74670d4", "Discard medicine more than two years old."},
+	{"ae4a2b639ca9bfa04b1855d5a05fe7f230994f790891c6979103e2605f660c4c1262a48142dcbeb57a1914ba5f7c3fa7", "He who has a shady past knows that nice guys finish last."},
+	{"40ae213df6436eca952aa6841886fcdb82908ef1576a99c8f49bb9dd5023169f7c53035abdda0b54c302f4974e2105e7", "I wouldn't marry him with a ten foot pole."},
+	{"e7cf8b873c9bc950f06259aa54309f349cefa72c00d597aebf903e6519a50011dfe355afff064a10701c705693848df9", "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"},
+	{"c3d4f0f4047181c7d39d34703365f7bf70207183caf2c2f6145f04da895ef69124d9cdeb635da636c3a474e61024e29b", "The days of the digital watch are numbered.  -Tom Stoppard"},
+	{"a097aab567e167d5cf93676ed73252a69f9687cb3179bb2d27c9878119e94bf7b7c4b58dc90582edfaf66e11388ed714", "Nepal premier won't resign."},
+	{"5026ca45c41fc64712eb65065da92f6467541c78f8966d3fe2c8e3fb769a3ec14215f819654b47bd64f7f0eac17184f3", "For every action there is an equal and opposite government program."},
+	{"ac1cc0f5ac8d5f5514a7b738ac322b7fb52a161b449c3672e9b6a6ad1a5e4b26b001cf3bad24c56598676ca17d4b445a", "His money is twice tainted: 'taint yours and 'taint mine."},
+	{"722d10c5de371ec0c8c4b5247ac8a5f1d240d68c73f8da13d8b25f0166d6f309bf9561979a111a0049405771d201941a", "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"},
+	{"dc2d3ea18bfa10549c63bf2b75b39b5167a80c12aff0e05443168ea87ff149fb0eda5e0bd234eb5d48c7d02ffc5807f1", "It's a tiny change to the code and not completely disgusting. - Bob Manchek"},
+	{"1d67c969e2a945ae5346d2139760261504d4ba164c522443afe19ef3e29b152a4c52445489cfc9d7215e5a450e8e1e4e", "size:  a.out:  bad magic"},
+	{"5ff8e075e465646e7b73ef36d812c6e9f7d60fa6ea0e533e5569b4f73cde53cdd2cc787f33540af57cca3fe467d32fe0", "The major problem is with sendmail.  -Mark Horton"},
+	{"5bd0a997a67c9ae1979a894eb0cde403dde003c9b6f2c03cf21925c42ff4e1176e6df1ca005381612ef18457b9b7ec3b", "Give me a rock, paper and scissors and I will move the world.  CCFestoon"},
+	{"1eee6da33e7e54fc5be52ae23b94b16ba4d2a947ae4505c6a3edfc7401151ea5205ac01b669b56f27d8ef7f175ed7762", "If the enemy is within range, then so are you."},
+	{"76b06e9dea66bfbb1a96029426dc0dfd7830bd297eb447ff5358d94a87cd00c88b59df2493fef56ecbb5231073892ea9", "It's well we cannot hear the screams/That we create in others' dreams."},
+	{"12acaf21452cff586143e3f5db0bfdf7802c057e1adf2a619031c4e1b0ccc4208cf6cef8fe722bbaa2fb46a30d9135d8", "You remind me of a TV show, but that's all right: I watch it anyway."},
+	{"0fc23d7f4183efd186f0bc4fc5db867e026e2146b06cb3d52f4bdbd57d1740122caa853b41868b197b2ac759db39df88", "C is as portable as Stonehedge!!"},
+	{"bc805578a7f85d34a86a32976e1c34fe65cf815186fbef76f46ef99cda10723f971f3f1464d488243f5e29db7488598d", "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"},
+	{"b23918399a12ebf4431559eec3813eaf7412e875fd7464f16d581e473330842d2e96c6be49a7ce3f9bb0b8bc0fcbe0fe", "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction.  Lewis-Randall Rule"},
+	{"1764b700eb1ead52a2fc33cc28975c2180f1b8faa5038d94cffa8d78154aab16e91dd787e7b0303948ebed62561542c8", "How can you write a big system without C++?  -Paul Glick"},
+}
 
-	for pass := 0; pass < 3; pass++ {
-		if pass < 2 {
-			io.WriteString(digestFunc, in)
-		} else {
-			io.WriteString(digestFunc, in[:len(in)/2])
-			digestFunc.Sum(nil)
-			io.WriteString(digestFunc, in[len(in)/2:])
+func TestGolden(t *testing.T) {
+	for i := 0; i < len(golden); i++ {
+		g := golden[i]
+		s := fmt.Sprintf("%x", Sum512([]byte(g.in)))
+		if s != g.out {
+			t.Fatalf("Sum512 function: sha512(%s) = %s want %s", g.in, s, g.out)
 		}
-
-		if calculated := hex.EncodeToString(digestFunc.Sum(nil)); calculated != outHex {
-			t.Errorf("%s(%q) = %q (in pass #%d), but expected %q", name, in, calculated, pass, outHex)
+		c := New()
+		for j := 0; j < 3; j++ {
+			if j < 2 {
+				io.WriteString(c, g.in)
+			} else {
+				io.WriteString(c, g.in[0:len(g.in)/2])
+				c.Sum(nil)
+				io.WriteString(c, g.in[len(g.in)/2:])
+			}
+			s := fmt.Sprintf("%x", c.Sum(nil))
+			if s != g.out {
+				t.Fatalf("sha512[%d](%s) = %s want %s", j, g.in, s, g.out)
+			}
+			c.Reset()
 		}
-		digestFunc.Reset()
 	}
-}
-
-func TestGolden(t *testing.T) {
-	for _, test := range golden {
-		in := []byte(test.in)
-
-		sum224 := Sum512_224(in)
-		sum256 := Sum512_256(in)
-		sum384 := Sum384(in)
-		sum512 := Sum512(in)
-		testHash(t, "SHA512/224", test.in, test.out224, sum224[:], New512_224())
-		testHash(t, "SHA512/256", test.in, test.out256, sum256[:], New512_256())
-		testHash(t, "SHA384", test.in, test.out384, sum384[:], New384())
-		testHash(t, "SHA512", test.in, test.out512, sum512[:], New())
+	for i := 0; i < len(golden384); i++ {
+		g := golden384[i]
+		s := fmt.Sprintf("%x", Sum384([]byte(g.in)))
+		if s != g.out {
+			t.Fatalf("Sum384 function: sha384(%s) = %s want %s", g.in, s, g.out)
+		}
+		c := New384()
+		for j := 0; j < 3; j++ {
+			if j < 2 {
+				io.WriteString(c, g.in)
+			} else {
+				io.WriteString(c, g.in[0:len(g.in)/2])
+				c.Sum(nil)
+				io.WriteString(c, g.in[len(g.in)/2:])
+			}
+			s := fmt.Sprintf("%x", c.Sum(nil))
+			if s != g.out {
+				t.Fatalf("sha384[%d](%s) = %s want %s", j, g.in, s, g.out)
+			}
+			c.Reset()
+		}
 	}
 }
 
@@ -287,14 +141,6 @@ func TestSize(t *testing.T) {
 	if got := c.Size(); got != Size384 {
 		t.Errorf("New384.Size = %d; want %d", got, Size384)
 	}
-	c = New512_224()
-	if got := c.Size(); got != Size224 {
-		t.Errorf("New512224.Size = %d; want %d", got, Size224)
-	}
-	c = New512_256()
-	if got := c.Size(); got != Size256 {
-		t.Errorf("New512256.Size = %d; want %d", got, Size256)
-	}
 }
 
 func TestBlockSize(t *testing.T) {
diff --git a/src/crypto/tls/cipher_suites.go b/src/crypto/tls/cipher_suites.go
index a5fed29..226e06d 100644
--- a/src/crypto/tls/cipher_suites.go
+++ b/src/crypto/tls/cipher_suites.go
@@ -48,12 +48,6 @@ const (
 	// suiteTLS12 indicates that the cipher suite should only be advertised
 	// and accepted when using TLS 1.2.
 	suiteTLS12
-	// suiteSHA384 indicates that the cipher suite uses SHA384 as the
-	// handshake hash.
-	suiteSHA384
-	// suiteDefaultOff indicates that this cipher suite is not included by
-	// default.
-	suiteDefaultOff
 )
 
 // A cipherSuite is a specific combination of key agreement, cipher and MAC
@@ -77,15 +71,13 @@ var cipherSuites = []*cipherSuite{
 	// and RC4 comes before AES (because of the Lucky13 attack).
 	{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, ecdheRSAKA, suiteECDHE | suiteTLS12, nil, nil, aeadAESGCM},
 	{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12, nil, nil, aeadAESGCM},
-	{TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, ecdheRSAKA, suiteECDHE | suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM},
-	{TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM},
-	{TLS_ECDHE_RSA_WITH_RC4_128_SHA, 16, 20, 0, ecdheRSAKA, suiteECDHE | suiteDefaultOff, cipherRC4, macSHA1, nil},
-	{TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, 16, 20, 0, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteDefaultOff, cipherRC4, macSHA1, nil},
+	{TLS_ECDHE_RSA_WITH_RC4_128_SHA, 16, 20, 0, ecdheRSAKA, suiteECDHE, cipherRC4, macSHA1, nil},
+	{TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, 16, 20, 0, ecdheECDSAKA, suiteECDHE | suiteECDSA, cipherRC4, macSHA1, nil},
 	{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, 16, 20, 16, ecdheRSAKA, suiteECDHE, cipherAES, macSHA1, nil},
 	{TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, 16, 20, 16, ecdheECDSAKA, suiteECDHE | suiteECDSA, cipherAES, macSHA1, nil},
 	{TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, 32, 20, 16, ecdheRSAKA, suiteECDHE, cipherAES, macSHA1, nil},
 	{TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, 32, 20, 16, ecdheECDSAKA, suiteECDHE | suiteECDSA, cipherAES, macSHA1, nil},
-	{TLS_RSA_WITH_RC4_128_SHA, 16, 20, 0, rsaKA, suiteDefaultOff, cipherRC4, macSHA1, nil},
+	{TLS_RSA_WITH_RC4_128_SHA, 16, 20, 0, rsaKA, 0, cipherRC4, macSHA1, nil},
 	{TLS_RSA_WITH_AES_128_CBC_SHA, 16, 20, 16, rsaKA, 0, cipherAES, macSHA1, nil},
 	{TLS_RSA_WITH_AES_256_CBC_SHA, 32, 20, 16, rsaKA, 0, cipherAES, macSHA1, nil},
 	{TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, ecdheRSAKA, suiteECDHE, cipher3DES, macSHA1, nil},
@@ -275,8 +267,6 @@ const (
 	TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA      uint16 = 0xc014
 	TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256   uint16 = 0xc02f
 	TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 uint16 = 0xc02b
-	TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384   uint16 = 0xc030
-	TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 uint16 = 0xc02c
 
 	// TLS_FALLBACK_SCSV isn't a standard cipher suite but an indicator
 	// that the client is doing version fallback. See
diff --git a/src/crypto/tls/common.go b/src/crypto/tls/common.go
index a3d75d6..776b70c 100644
--- a/src/crypto/tls/common.go
+++ b/src/crypto/tls/common.go
@@ -8,9 +8,7 @@ import (
 	"container/list"
 	"crypto"
 	"crypto/rand"
-	"crypto/sha512"
 	"crypto/x509"
-	"errors"
 	"fmt"
 	"io"
 	"math/big"
@@ -32,7 +30,7 @@ const (
 	recordHeaderLen = 5            // record header length
 	maxHandshake    = 65536        // maximum handshake we support (protocol max is 16 MB)
 
-	minVersion = VersionTLS10
+	minVersion = VersionSSL30
 	maxVersion = VersionTLS12
 )
 
@@ -75,7 +73,6 @@ const (
 	extensionSupportedPoints     uint16 = 11
 	extensionSignatureAlgorithms uint16 = 13
 	extensionALPN                uint16 = 16
-	extensionSCT                 uint16 = 18 // https://tools.ietf.org/html/rfc6962#section-6
 	extensionSessionTicket       uint16 = 35
 	extensionNextProtoNeg        uint16 = 13172 // not IANA assigned
 	extensionRenegotiationInfo   uint16 = 0xff01
@@ -126,7 +123,6 @@ const (
 const (
 	hashSHA1   uint8 = 2
 	hashSHA256 uint8 = 4
-	hashSHA384 uint8 = 5
 )
 
 // Signature algorithms for TLS 1.2 (See RFC 5246, section A.4.1)
@@ -141,31 +137,34 @@ type signatureAndHash struct {
 	hash, signature uint8
 }
 
-// supportedSignatureAlgorithms contains the signature and hash algorithms that
-// the code advertises as supported in a TLS 1.2 ClientHello and in a TLS 1.2
-// CertificateRequest.
-var supportedSignatureAlgorithms = []signatureAndHash{
+// supportedSKXSignatureAlgorithms contains the signature and hash algorithms
+// that the code advertises as supported in a TLS 1.2 ClientHello.
+var supportedSKXSignatureAlgorithms = []signatureAndHash{
 	{hashSHA256, signatureRSA},
 	{hashSHA256, signatureECDSA},
-	{hashSHA384, signatureRSA},
-	{hashSHA384, signatureECDSA},
 	{hashSHA1, signatureRSA},
 	{hashSHA1, signatureECDSA},
 }
 
+// supportedClientCertSignatureAlgorithms contains the signature and hash
+// algorithms that the code advertises as supported in a TLS 1.2
+// CertificateRequest.
+var supportedClientCertSignatureAlgorithms = []signatureAndHash{
+	{hashSHA256, signatureRSA},
+	{hashSHA256, signatureECDSA},
+}
+
 // 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, ...)
-	NegotiatedProtocol          string                // negotiated next protocol (from Config.NextProtos)
-	NegotiatedProtocolIsMutual  bool                  // negotiated protocol was advertised by server
-	ServerName                  string                // server name requested by client, if any (server side only)
-	PeerCertificates            []*x509.Certificate   // certificate chain presented by remote peer
-	VerifiedChains              [][]*x509.Certificate // verified chains built from PeerCertificates
-	SignedCertificateTimestamps [][]byte              // SCTs from the server, if any
-	OCSPResponse                []byte                // stapled OCSP response from server, if any
+	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, ...)
+	NegotiatedProtocol         string                // negotiated next protocol (from Config.NextProtos)
+	NegotiatedProtocolIsMutual bool                  // negotiated protocol was advertised by server
+	ServerName                 string                // server name requested by client, if any (server side only)
+	PeerCertificates           []*x509.Certificate   // certificate chain presented by remote peer
+	VerifiedChains             [][]*x509.Certificate // verified chains built from PeerCertificates
 
 	// TLSUnique contains the "tls-unique" channel binding value (see RFC
 	// 5929, section 3). For resumed sessions this value will be nil
@@ -191,12 +190,11 @@ const (
 // 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
-	verifiedChains     [][]*x509.Certificate // Certificate chains we built for verification
+	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
@@ -267,12 +265,10 @@ type Config struct {
 	NameToCertificate map[string]*Certificate
 
 	// GetCertificate returns a Certificate based on the given
-	// ClientHelloInfo. It will only be called if the client supplies SNI
-	// information or if Certificates is empty.
-	//
-	// If GetCertificate is nil or returns nil, then the certificate is
-	// retrieved from NameToCertificate. If NameToCertificate is nil, the
-	// first element of Certificates will be used.
+	// ClientHelloInfo. If GetCertificate is nil or returns nil, then the
+	// certificate is retrieved from NameToCertificate. If
+	// NameToCertificate is nil, the first element of Certificates will be
+	// used.
 	GetCertificate func(clientHello *ClientHelloInfo) (*Certificate, error)
 
 	// RootCAs defines the set of root certificate authorities
@@ -334,7 +330,7 @@ type Config struct {
 	ClientSessionCache ClientSessionCache
 
 	// MinVersion contains the minimum SSL/TLS version that is acceptable.
-	// If zero, then TLS 1.0 is taken as the minimum.
+	// If zero, then SSLv3 is taken as the minimum.
 	MinVersion uint16
 
 	// MaxVersion contains the maximum SSL/TLS version that is acceptable.
@@ -348,38 +344,6 @@ type Config struct {
 	CurvePreferences []CurveID
 
 	serverInitOnce sync.Once // guards calling (*Config).serverInit
-
-	// mutex protects sessionTicketKeys
-	mutex sync.RWMutex
-	// sessionTicketKeys contains zero or more ticket keys. If the length
-	// is zero, SessionTicketsDisabled must be true. The first key is used
-	// for new tickets and any subsequent keys can be used to decrypt old
-	// tickets.
-	sessionTicketKeys []ticketKey
-}
-
-// ticketKeyNameLen is the number of bytes of identifier that is prepended to
-// an encrypted session ticket in order to identify the key used to encrypt it.
-const ticketKeyNameLen = 16
-
-// ticketKey is the internal representation of a session ticket key.
-type ticketKey struct {
-	// keyName is an opaque byte string that serves to identify the session
-	// ticket key. It's exposed as plaintext in every session ticket.
-	keyName [ticketKeyNameLen]byte
-	aesKey  [16]byte
-	hmacKey [16]byte
-}
-
-// ticketKeyFromBytes converts from the external representation of a session
-// ticket key to a ticketKey. Externally, session ticket keys are 32 random
-// bytes and this function expands that into sufficient name and key material.
-func ticketKeyFromBytes(b [32]byte) (key ticketKey) {
-	hashed := sha512.Sum512(b[:])
-	copy(key.keyName[:], hashed[:ticketKeyNameLen])
-	copy(key.aesKey[:], hashed[ticketKeyNameLen:ticketKeyNameLen+16])
-	copy(key.hmacKey[:], hashed[ticketKeyNameLen+16:ticketKeyNameLen+32])
-	return key
 }
 
 func (c *Config) serverInit() {
@@ -387,51 +351,16 @@ func (c *Config) serverInit() {
 		return
 	}
 
-	alreadySet := false
+	// If the key has already been set then we have nothing to do.
 	for _, b := range c.SessionTicketKey {
 		if b != 0 {
-			alreadySet = true
-			break
-		}
-	}
-
-	if !alreadySet {
-		if _, err := io.ReadFull(c.rand(), c.SessionTicketKey[:]); err != nil {
-			c.SessionTicketsDisabled = true
 			return
 		}
 	}
 
-	c.sessionTicketKeys = []ticketKey{ticketKeyFromBytes(c.SessionTicketKey)}
-}
-
-func (c *Config) ticketKeys() []ticketKey {
-	c.mutex.RLock()
-	// c.sessionTicketKeys is constant once created. SetSessionTicketKeys
-	// will only update it by replacing it with a new value.
-	ret := c.sessionTicketKeys
-	c.mutex.RUnlock()
-	return ret
-}
-
-// SetSessionTicketKeys updates the session ticket keys for a server. The first
-// key will be used when creating new tickets, while all keys can be used for
-// decrypting tickets. It is safe to call this function while the server is
-// running in order to rotate the session ticket keys. The function will panic
-// if keys is empty.
-func (c *Config) SetSessionTicketKeys(keys [][32]byte) {
-	if len(keys) == 0 {
-		panic("tls: keys must have at least one key")
+	if _, err := io.ReadFull(c.rand(), c.SessionTicketKey[:]); err != nil {
+		c.SessionTicketsDisabled = true
 	}
-
-	newKeys := make([]ticketKey, len(keys))
-	for i, bytes := range keys {
-		newKeys[i] = ticketKeyFromBytes(bytes)
-	}
-
-	c.mutex.Lock()
-	c.sessionTicketKeys = newKeys
-	c.mutex.Unlock()
 }
 
 func (c *Config) rand() io.Reader {
@@ -499,18 +428,13 @@ func (c *Config) mutualVersion(vers uint16) (uint16, bool) {
 // getCertificate returns the best certificate for the given ClientHelloInfo,
 // defaulting to the first element of c.Certificates.
 func (c *Config) getCertificate(clientHello *ClientHelloInfo) (*Certificate, error) {
-	if c.GetCertificate != nil &&
-		(len(c.Certificates) == 0 || len(clientHello.ServerName) > 0) {
+	if c.GetCertificate != nil {
 		cert, err := c.GetCertificate(clientHello)
 		if cert != nil || err != nil {
 			return cert, err
 		}
 	}
 
-	if len(c.Certificates) == 0 {
-		return nil, errors.New("crypto/tls: no certificates configured")
-	}
-
 	if len(c.Certificates) == 1 || c.NameToCertificate == nil {
 		// There's only one choice, so no point doing any work.
 		return &c.Certificates[0], nil
@@ -564,17 +488,14 @@ func (c *Config) BuildNameToCertificate() {
 type Certificate struct {
 	Certificate [][]byte
 	// PrivateKey contains the private key corresponding to the public key
-	// in Leaf. For a server, this must implement crypto.Signer and/or
-	// crypto.Decrypter, with an RSA or ECDSA PublicKey. For a client
-	// (performing client authentication), this must be a crypto.Signer
-	// with an RSA or ECDSA PublicKey.
+	// in Leaf. For a server, this must be a *rsa.PrivateKey or
+	// *ecdsa.PrivateKey. For a client doing client authentication, this
+	// can be any type that implements crypto.Signer (which includes RSA
+	// and ECDSA private keys).
 	PrivateKey crypto.PrivateKey
 	// OCSPStaple contains an optional OCSP response which will be served
 	// to clients that request it.
 	OCSPStaple []byte
-	// SignedCertificateTimestamps contains an optional list of Signed
-	// Certificate Timestamps which will be served to clients that request it.
-	SignedCertificateTimestamps [][]byte
 	// Leaf is the parsed form of the leaf certificate, which may be
 	// initialized using x509.ParseCertificate to reduce per-handshake
 	// processing for TLS clients doing client authentication. If nil, the
@@ -689,24 +610,12 @@ func defaultCipherSuites() []uint16 {
 }
 
 func initDefaultCipherSuites() {
-	varDefaultCipherSuites = make([]uint16, 0, len(cipherSuites))
-	for _, suite := range cipherSuites {
-		if suite.flags&suiteDefaultOff != 0 {
-			continue
-		}
-		varDefaultCipherSuites = append(varDefaultCipherSuites, suite.id)
+	varDefaultCipherSuites = make([]uint16, len(cipherSuites))
+	for i, suite := range cipherSuites {
+		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)
 }
-
-func isSupportedSignatureAndHash(sigHash signatureAndHash, sigHashes []signatureAndHash) bool {
-	for _, s := range sigHashes {
-		if s == sigHash {
-			return true
-		}
-	}
-	return false
-}
diff --git a/src/crypto/tls/conn.go b/src/crypto/tls/conn.go
index e3dcf15..ba8e4c2 100644
--- a/src/crypto/tls/conn.go
+++ b/src/crypto/tls/conn.go
@@ -35,8 +35,7 @@ type Conn struct {
 	handshakeComplete bool
 	didResume         bool // whether this connection was a session resumption
 	cipherSuite       uint16
-	ocspResponse      []byte   // stapled OCSP response
-	scts              [][]byte // signed certificate timestamps from server
+	ocspResponse      []byte // stapled OCSP response
 	peerCertificates  []*x509.Certificate
 	// verifiedChains contains the certificate chains that we built, as
 	// opposed to the ones presented by the server.
@@ -571,11 +570,15 @@ Again:
 		return c.in.setErrorLocked(fmt.Errorf("tls: oversized record received with length %d", n))
 	}
 	if !c.haveVers {
-		// First message, be extra suspicious: this might not be a TLS
-		// client. Bail out before reading a full 'body', if possible.
-		// The current max version is 3.3 so if the version is >= 16.0,
+		// First message, be extra suspicious:
+		// this might not be a TLS client.
+		// Bail out before reading a full 'body', if possible.
+		// The current max version is 3.1.
+		// If the version is >= 16.0, it's probably not real.
+		// Similarly, a clientHello message encodes in
+		// well under a kilobyte.  If the length is >= 12 kB,
 		// it's probably not real.
-		if (typ != recordTypeAlert && typ != want) || vers >= 0x1000 {
+		if (typ != recordTypeAlert && typ != want) || vers >= 0x1000 || n >= 0x3000 {
 			c.sendAlert(alertUnexpectedMessage)
 			return c.in.setErrorLocked(fmt.Errorf("tls: first record does not look like a TLS handshake"))
 		}
@@ -923,7 +926,7 @@ func (c *Conn) Read(b []byte) (n int, err error) {
 		// tried to reuse the HTTP connection for a new
 		// request.
 		// See https://codereview.appspot.com/76400046
-		// and https://golang.org/issue/3514
+		// 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 {
@@ -994,8 +997,6 @@ func (c *Conn) ConnectionState() ConnectionState {
 		state.PeerCertificates = c.peerCertificates
 		state.VerifiedChains = c.verifiedChains
 		state.ServerName = c.serverName
-		state.SignedCertificateTimestamps = c.scts
-		state.OCSPResponse = c.ocspResponse
 		if !c.didResume {
 			state.TLSUnique = c.firstFinished[:]
 		}
@@ -1025,8 +1026,5 @@ func (c *Conn) VerifyHostname(host string) error {
 	if !c.handshakeComplete {
 		return errors.New("tls: handshake has not yet been performed")
 	}
-	if len(c.verifiedChains) == 0 {
-		return errors.New("tls: handshake did not verify certificate chain")
-	}
 	return c.peerCertificates[0].VerifyHostname(host)
 }
diff --git a/src/crypto/tls/handshake_client.go b/src/crypto/tls/handshake_client.go
index 0b591d7..7f662e9 100644
--- a/src/crypto/tls/handshake_client.go
+++ b/src/crypto/tls/handshake_client.go
@@ -54,7 +54,6 @@ func (c *Conn) clientHandshake() error {
 		compressionMethods:  []uint8{compressionNone},
 		random:              make([]byte, 32),
 		ocspStapling:        true,
-		scts:                true,
 		serverName:          c.config.ServerName,
 		supportedCurves:     c.config.curvePreferences(),
 		supportedPoints:     []uint8{pointFormatUncompressed},
@@ -89,7 +88,7 @@ NextCipherSuite:
 	}
 
 	if hello.vers >= VersionTLS12 {
-		hello.signatureAndHashes = supportedSignatureAlgorithms
+		hello.signatureAndHashes = supportedSKXSignatureAlgorithms
 	}
 
 	var session *ClientSessionState
@@ -169,26 +168,18 @@ NextCipherSuite:
 		serverHello:  serverHello,
 		hello:        hello,
 		suite:        suite,
-		finishedHash: newFinishedHash(c.vers, suite),
+		finishedHash: newFinishedHash(c.vers),
 		session:      session,
 	}
 
+	hs.finishedHash.Write(hs.hello.marshal())
+	hs.finishedHash.Write(hs.serverHello.marshal())
+
 	isResume, err := hs.processServerHello()
 	if err != nil {
 		return err
 	}
 
-	// No signatures of the handshake are needed in a resumption.
-	// Otherwise, in a full handshake, if we don't have any certificates
-	// configured then we will never send a CertificateVerify message and
-	// thus no signatures are needed in that case either.
-	if isResume || len(c.config.Certificates) == 0 {
-		hs.finishedHash.discardHandshakeBuffer()
-	}
-
-	hs.finishedHash.Write(hs.hello.marshal())
-	hs.finishedHash.Write(hs.serverHello.marshal())
-
 	if isResume {
 		if err := hs.establishKeys(); err != nil {
 			return err
@@ -432,6 +423,7 @@ func (hs *clientHandshakeState) doFullHandshake() error {
 	}
 
 	if chainToSend != nil {
+		var signed []byte
 		certVerify := &certificateVerifyMsg{
 			hasSignatureAndHash: c.vers >= VersionTLS12,
 		}
@@ -441,42 +433,31 @@ func (hs *clientHandshakeState) doFullHandshake() error {
 			c.sendAlert(alertInternalError)
 			return fmt.Errorf("tls: client certificate private key of type %T does not implement crypto.Signer", chainToSend.PrivateKey)
 		}
-
-		var signatureType uint8
 		switch key.Public().(type) {
 		case *ecdsa.PublicKey:
-			signatureType = signatureECDSA
+			digest, hashFunc, hashId := hs.finishedHash.hashForClientCertificate(signatureECDSA)
+			signed, err = key.Sign(c.config.rand(), digest, hashFunc)
+			certVerify.signatureAndHash.signature = signatureECDSA
+			certVerify.signatureAndHash.hash = hashId
 		case *rsa.PublicKey:
-			signatureType = signatureRSA
+			digest, hashFunc, hashId := hs.finishedHash.hashForClientCertificate(signatureRSA)
+			signed, err = key.Sign(c.config.rand(), digest, hashFunc)
+			certVerify.signatureAndHash.signature = signatureRSA
+			certVerify.signatureAndHash.hash = hashId
 		default:
-			c.sendAlert(alertInternalError)
-			return fmt.Errorf("tls: failed to sign handshake with client certificate: unknown client certificate key type: %T", key)
-		}
-
-		certVerify.signatureAndHash, err = hs.finishedHash.selectClientCertSignatureAlgorithm(certReq.signatureAndHashes, signatureType)
-		if err != nil {
-			c.sendAlert(alertInternalError)
-			return err
+			err = fmt.Errorf("tls: unknown client certificate key type: %T", key)
 		}
-		digest, hashFunc, err := hs.finishedHash.hashForClientCertificate(certVerify.signatureAndHash, hs.masterSecret)
 		if err != nil {
 			c.sendAlert(alertInternalError)
-			return err
-		}
-		certVerify.signature, err = key.Sign(c.config.rand(), digest, hashFunc)
-		if err != nil {
-			c.sendAlert(alertInternalError)
-			return err
+			return errors.New("tls: failed to sign handshake with client certificate: " + err.Error())
 		}
+		certVerify.signature = signed
 
 		hs.finishedHash.Write(certVerify.marshal())
 		c.writeRecord(recordTypeHandshake, certVerify.marshal())
 	}
 
-	hs.masterSecret = masterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret, hs.hello.random, hs.serverHello.random)
-
-	hs.finishedHash.discardHandshakeBuffer()
-
+	hs.masterSecret = masterFromPreMasterSecret(c.vers, preMasterSecret, hs.hello.random, hs.serverHello.random)
 	return nil
 }
 
@@ -484,7 +465,7 @@ func (hs *clientHandshakeState) establishKeys() error {
 	c := hs.c
 
 	clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV :=
-		keysFromMasterSecret(c.vers, hs.suite, hs.masterSecret, hs.hello.random, hs.serverHello.random, hs.suite.macLen, hs.suite.keyLen, hs.suite.ivLen)
+		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 {
@@ -541,13 +522,11 @@ func (hs *clientHandshakeState) processServerHello() (bool, error) {
 		c.clientProtocol = hs.serverHello.alpnProtocol
 		c.clientProtocolFallback = false
 	}
-	c.scts = hs.serverHello.scts
 
 	if hs.serverResumedSession() {
 		// Restore masterSecret and peerCerts from previous state
 		hs.masterSecret = hs.session.masterSecret
 		c.peerCertificates = hs.session.serverCertificates
-		c.verifiedChains = hs.session.verifiedChains
 		return true, nil
 	}
 	return false, nil
@@ -605,7 +584,6 @@ func (hs *clientHandshakeState) readSessionTicket() error {
 		cipherSuite:        hs.suite.id,
 		masterSecret:       hs.masterSecret,
 		serverCertificates: c.peerCertificates,
-		verifiedChains:     c.verifiedChains,
 	}
 
 	return nil
diff --git a/src/crypto/tls/handshake_client_test.go b/src/crypto/tls/handshake_client_test.go
index 664fe8d..e5eaa7d 100644
--- a/src/crypto/tls/handshake_client_test.go
+++ b/src/crypto/tls/handshake_client_test.go
@@ -9,8 +9,6 @@ import (
 	"crypto/ecdsa"
 	"crypto/rsa"
 	"crypto/x509"
-	"encoding/base64"
-	"encoding/binary"
 	"encoding/pem"
 	"fmt"
 	"io"
@@ -51,10 +49,6 @@ type clientTest struct {
 	// key, if not nil, contains either a *rsa.PrivateKey or
 	// *ecdsa.PrivateKey which is the private key for the reference server.
 	key interface{}
-	// extensions, if not nil, contains a list of extension data to be returned
-	// from the ServerHello. The data should be in standard TLS format with
-	// a 2-byte uint16 type, 2-byte data length, followed by the extension data.
-	extensions [][]byte
 	// validate, if not nil, is a function that will be called with the
 	// ConnectionState of the resulting connection. It returns a non-nil
 	// error if the ConnectionState is unacceptable.
@@ -117,19 +111,6 @@ func (test *clientTest) connFromCommand() (conn *recordingConn, child *exec.Cmd,
 	const serverPort = 24323
 	command = append(command, "-accept", strconv.Itoa(serverPort))
 
-	if len(test.extensions) > 0 {
-		var serverInfo bytes.Buffer
-		for _, ext := range test.extensions {
-			pem.Encode(&serverInfo, &pem.Block{
-				Type:  fmt.Sprintf("SERVERINFO FOR EXTENSION %d", binary.BigEndian.Uint16(ext)),
-				Bytes: ext,
-			})
-		}
-		serverInfoPath := tempFile(serverInfo.String())
-		defer os.Remove(serverInfoPath)
-		command = append(command, "-serverinfo", serverInfoPath)
-	}
-
 	cmd := exec.Command(command[0], command[1:]...)
 	stdin = blockingSource(make(chan bool))
 	cmd.Stdin = stdin
@@ -146,6 +127,7 @@ func (test *clientTest) connFromCommand() (conn *recordingConn, child *exec.Cmd,
 	// 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,
@@ -155,7 +137,7 @@ func (test *clientTest) connFromCommand() (conn *recordingConn, child *exec.Cmd,
 		}
 		time.Sleep((1 << i) * 5 * time.Millisecond)
 	}
-	if err != nil {
+	if tcpConn == nil {
 		close(stdin)
 		out.WriteTo(os.Stdout)
 		cmd.Process.Kill()
@@ -208,11 +190,11 @@ func (test *clientTest) run(t *testing.T, write bool) {
 	doneChan := make(chan bool)
 	go func() {
 		if _, err := client.Write([]byte("hello\n")); err != nil {
-			t.Errorf("Client.Write failed: %s", err)
+			t.Logf("Client.Write failed: %s", err)
 		}
 		if test.validate != nil {
 			if err := test.validate(client.ConnectionState()); err != nil {
-				t.Errorf("validate callback returned error: %s", err)
+				t.Logf("validate callback returned error: %s", err)
 			}
 		}
 		client.Close()
@@ -329,16 +311,6 @@ func TestHandshakeClientECDHEECDSAAESGCM(t *testing.T) {
 	runClientTestTLS12(t, test)
 }
 
-func TestHandshakeClientAES256GCMSHA384(t *testing.T) {
-	test := &clientTest{
-		name:    "ECDHE-ECDSA-AES256-GCM-SHA384",
-		command: []string{"openssl", "s_server", "-cipher", "ECDHE-ECDSA-AES256-GCM-SHA384"},
-		cert:    testECDSACertificate,
-		key:     testECDSAPrivateKey,
-	}
-	runClientTestTLS12(t, test)
-}
-
 func TestHandshakeClientCertRSA(t *testing.T) {
 	config := *testConfig
 	cert, _ := X509KeyPair([]byte(clientCertificatePEM), []byte(clientKeyPEM))
@@ -363,16 +335,6 @@ func TestHandshakeClientCertRSA(t *testing.T) {
 
 	runClientTestTLS10(t, test)
 	runClientTestTLS12(t, test)
-
-	test = &clientTest{
-		name:    "ClientCert-RSA-AES256-GCM-SHA384",
-		command: []string{"openssl", "s_server", "-cipher", "ECDHE-RSA-AES256-GCM-SHA384", "-verify", "1"},
-		config:  &config,
-		cert:    testRSACertificate,
-		key:     testRSAPrivateKey,
-	}
-
-	runClientTestTLS12(t, test)
 }
 
 func TestHandshakeClientCertECDSA(t *testing.T) {
@@ -406,67 +368,31 @@ func TestClientResumption(t *testing.T) {
 		CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA, TLS_ECDHE_RSA_WITH_RC4_128_SHA},
 		Certificates: testConfig.Certificates,
 	}
-
-	issuer, err := x509.ParseCertificate(testRSACertificateIssuer)
-	if err != nil {
-		panic(err)
-	}
-
-	rootCAs := x509.NewCertPool()
-	rootCAs.AddCert(issuer)
-
 	clientConfig := &Config{
 		CipherSuites:       []uint16{TLS_RSA_WITH_RC4_128_SHA},
+		InsecureSkipVerify: true,
 		ClientSessionCache: NewLRUClientSessionCache(32),
-		RootCAs:            rootCAs,
-		ServerName:         "example.golang",
 	}
 
 	testResumeState := func(test string, didResume bool) {
-		_, hs, err := testHandshake(clientConfig, serverConfig)
+		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)
 		}
-		if didResume && (hs.PeerCertificates == nil || hs.VerifiedChains == nil) {
-			t.Fatalf("expected non-nil certificates after resumption. Got peerCertificates: %#v, verifedCertificates: %#v", hs.PeerCertificates, hs.VerifiedChains)
-		}
-	}
-
-	getTicket := func() []byte {
-		return clientConfig.ClientSessionCache.(*lruSessionCache).q.Front().Value.(*lruSessionCacheEntry).state.sessionTicket
-	}
-	randomKey := func() [32]byte {
-		var k [32]byte
-		if _, err := io.ReadFull(serverConfig.rand(), k[:]); err != nil {
-			t.Fatalf("Failed to read new SessionTicketKey: %s", err)
-		}
-		return k
 	}
 
 	testResumeState("Handshake", false)
-	ticket := getTicket()
 	testResumeState("Resume", true)
-	if !bytes.Equal(ticket, getTicket()) {
-		t.Fatal("first ticket doesn't match ticket after resumption")
-	}
-
-	key2 := randomKey()
-	serverConfig.SetSessionTicketKeys([][32]byte{key2})
 
+	if _, err := io.ReadFull(serverConfig.rand(), serverConfig.SessionTicketKey[:]); err != nil {
+		t.Fatalf("Failed to invalidate SessionTicketKey")
+	}
 	testResumeState("InvalidSessionTicketKey", false)
 	testResumeState("ResumeAfterInvalidSessionTicketKey", true)
 
-	serverConfig.SetSessionTicketKeys([][32]byte{randomKey(), key2})
-	ticket = getTicket()
-	testResumeState("KeyChange", true)
-	if bytes.Equal(ticket, getTicket()) {
-		t.Fatal("new ticket wasn't included while resuming")
-	}
-	testResumeState("KeyChangeFinish", true)
-
 	clientConfig.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_RC4_128_SHA}
 	testResumeState("DifferentCipherSuite", false)
 	testResumeState("DifferentCipherSuiteRecovers", true)
@@ -562,41 +488,3 @@ func TestHandshakeClientALPNNoMatch(t *testing.T) {
 	}
 	runClientTestTLS12(t, test)
 }
-
-// sctsBase64 contains data from `openssl s_client -serverinfo 18 -connect ritter.vg:443`
-const sctsBase64 = "ABIBaQFnAHUApLkJkLQYWBSHuxOizGdwCjw1mAT5G9+443fNDsgN3BAAAAFHl5nuFgAABAMARjBEAiAcS4JdlW5nW9sElUv2zvQyPoZ6ejKrGGB03gjaBZFMLwIgc1Qbbn+hsH0RvObzhS+XZhr3iuQQJY8S9G85D9KeGPAAdgBo9pj4H2SCvjqM7rkoHUz8cVFdZ5PURNEKZ6y7T0/7xAAAAUeX4bVwAAAEAwBHMEUCIDIhFDgG2HIuADBkGuLobU5a4dlCHoJLliWJ1SYT05z6AiEAjxIoZFFPRNWMGGIjskOTMwXzQ1Wh2e7NxXE1kd1J0QsAdgDuS723dc5guuFCaR+r4Z5mow9+X7By2IMAxHuJeqj9ywAAAUhcZIqHAAAEAwBHMEUCICmJ1rBT09LpkbzxtUC+Hi7nXLR0J+2PmwLp+sJMuqK+AiEAr0NkUnEVKVhAkccIFpYDqHOlZaBs [...]
-
-func TestHandshakClientSCTs(t *testing.T) {
-	config := *testConfig
-
-	scts, err := base64.StdEncoding.DecodeString(sctsBase64)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	test := &clientTest{
-		name: "SCT",
-		// Note that this needs OpenSSL 1.0.2 because that is the first
-		// version that supports the -serverinfo flag.
-		command:    []string{"openssl", "s_server"},
-		config:     &config,
-		extensions: [][]byte{scts},
-		validate: func(state ConnectionState) error {
-			expectedSCTs := [][]byte{
-				scts[8:125],
-				scts[127:245],
-				scts[247:],
-			}
-			if n := len(state.SignedCertificateTimestamps); n != len(expectedSCTs) {
-				return fmt.Errorf("Got %d scts, wanted %d", n, len(expectedSCTs))
-			}
-			for i, expected := range expectedSCTs {
-				if sct := state.SignedCertificateTimestamps[i]; !bytes.Equal(sct, expected) {
-					return fmt.Errorf("SCT #%d contained %x, expected %x", i, sct, expected)
-				}
-			}
-			return nil
-		},
-	}
-	runClientTestTLS12(t, test)
-}
diff --git a/src/crypto/tls/handshake_messages.go b/src/crypto/tls/handshake_messages.go
index 799a776..5d14871 100644
--- a/src/crypto/tls/handshake_messages.go
+++ b/src/crypto/tls/handshake_messages.go
@@ -16,7 +16,6 @@ type clientHelloMsg struct {
 	nextProtoNeg        bool
 	serverName          string
 	ocspStapling        bool
-	scts                bool
 	supportedCurves     []CurveID
 	supportedPoints     []uint8
 	ticketSupported     bool
@@ -41,7 +40,6 @@ func (m *clientHelloMsg) equal(i interface{}) bool {
 		m.nextProtoNeg == m1.nextProtoNeg &&
 		m.serverName == m1.serverName &&
 		m.ocspStapling == m1.ocspStapling &&
-		m.scts == m1.scts &&
 		eqCurveIDs(m.supportedCurves, m1.supportedCurves) &&
 		bytes.Equal(m.supportedPoints, m1.supportedPoints) &&
 		m.ticketSupported == m1.ticketSupported &&
@@ -101,9 +99,6 @@ func (m *clientHelloMsg) marshal() []byte {
 		}
 		numExtensions++
 	}
-	if m.scts {
-		numExtensions++
-	}
 	if numExtensions > 0 {
 		extensionsLength += 4 * numExtensions
 		length += 2 + extensionsLength
@@ -276,13 +271,6 @@ func (m *clientHelloMsg) marshal() []byte {
 		lengths[0] = byte(stringsLength >> 8)
 		lengths[1] = byte(stringsLength)
 	}
-	if m.scts {
-		// https://tools.ietf.org/html/rfc6962#section-3.3.1
-		z[0] = byte(extensionSCT >> 8)
-		z[1] = byte(extensionSCT)
-		// zero uint16 for the zero-length extension_data
-		z = z[4:]
-	}
 
 	m.raw = x
 
@@ -338,7 +326,6 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {
 	m.sessionTicket = nil
 	m.signatureAndHashes = nil
 	m.alpnProtocols = nil
-	m.scts = false
 
 	if len(data) == 0 {
 		// ClientHello is optionally followed by extension data
@@ -367,16 +354,12 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {
 
 		switch extension {
 		case extensionServerName:
-			d := data[:length]
-			if len(d) < 2 {
-				return false
-			}
-			namesLen := int(d[0])<<8 | int(d[1])
-			d = d[2:]
-			if len(d) != namesLen {
+			if length < 2 {
 				return false
 			}
-			for len(d) > 0 {
+			numNames := int(data[0])<<8 | int(data[1])
+			d := data[2:]
+			for i := 0; i < numNames; i++ {
 				if len(d) < 3 {
 					return false
 				}
@@ -387,7 +370,7 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {
 					return false
 				}
 				if nameType == 0 {
-					m.serverName = string(d[:nameLen])
+					m.serverName = string(d[0:nameLen])
 					break
 				}
 				d = d[nameLen:]
@@ -447,7 +430,7 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {
 				m.signatureAndHashes[i].signature = d[1]
 				d = d[2:]
 			}
-		case extensionRenegotiationInfo:
+		case extensionRenegotiationInfo + 1:
 			if length != 1 || data[0] != 0 {
 				return false
 			}
@@ -470,11 +453,6 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {
 				m.alpnProtocols = append(m.alpnProtocols, string(d[:stringLen]))
 				d = d[stringLen:]
 			}
-		case extensionSCT:
-			m.scts = true
-			if length != 0 {
-				return false
-			}
 		}
 		data = data[length:]
 	}
@@ -492,7 +470,6 @@ type serverHelloMsg struct {
 	nextProtoNeg        bool
 	nextProtos          []string
 	ocspStapling        bool
-	scts                [][]byte
 	ticketSupported     bool
 	secureRenegotiation bool
 	alpnProtocol        string
@@ -504,15 +481,6 @@ func (m *serverHelloMsg) equal(i interface{}) bool {
 		return false
 	}
 
-	if len(m.scts) != len(m1.scts) {
-		return false
-	}
-	for i, sct := range m.scts {
-		if !bytes.Equal(sct, m1.scts[i]) {
-			return false
-		}
-	}
-
 	return bytes.Equal(m.raw, m1.raw) &&
 		m.vers == m1.vers &&
 		bytes.Equal(m.random, m1.random) &&
@@ -562,14 +530,6 @@ func (m *serverHelloMsg) marshal() []byte {
 		extensionsLength += 2 + 1 + alpnLen
 		numExtensions++
 	}
-	sctLen := 0
-	if len(m.scts) > 0 {
-		for _, sct := range m.scts {
-			sctLen += len(sct) + 2
-		}
-		extensionsLength += 2 + sctLen
-		numExtensions++
-	}
 
 	if numExtensions > 0 {
 		extensionsLength += 4 * numExtensions
@@ -645,23 +605,6 @@ func (m *serverHelloMsg) marshal() []byte {
 		copy(z[7:], []byte(m.alpnProtocol))
 		z = z[7+alpnLen:]
 	}
-	if sctLen > 0 {
-		z[0] = byte(extensionSCT >> 8)
-		z[1] = byte(extensionSCT)
-		l := sctLen + 2
-		z[2] = byte(l >> 8)
-		z[3] = byte(l)
-		z[4] = byte(sctLen >> 8)
-		z[5] = byte(sctLen)
-
-		z = z[6:]
-		for _, sct := range m.scts {
-			z[0] = byte(len(sct) >> 8)
-			z[1] = byte(len(sct))
-			copy(z[2:], sct)
-			z = z[len(sct)+2:]
-		}
-	}
 
 	m.raw = x
 
@@ -691,7 +634,6 @@ func (m *serverHelloMsg) unmarshal(data []byte) bool {
 	m.nextProtoNeg = false
 	m.nextProtos = nil
 	m.ocspStapling = false
-	m.scts = nil
 	m.ticketSupported = false
 	m.alpnProtocol = ""
 
@@ -764,34 +706,6 @@ func (m *serverHelloMsg) unmarshal(data []byte) bool {
 			}
 			d = d[1:]
 			m.alpnProtocol = string(d)
-		case extensionSCT:
-			d := data[:length]
-
-			if len(d) < 2 {
-				return false
-			}
-			l := int(d[0])<<8 | int(d[1])
-			d = d[2:]
-			if len(d) != l {
-				return false
-			}
-			if l == 0 {
-				continue
-			}
-
-			m.scts = make([][]byte, 0, 3)
-			for len(d) != 0 {
-				if len(d) < 2 {
-					return false
-				}
-				sctLen := int(d[0])<<8 | int(d[1])
-				d = d[2:]
-				if len(d) < sctLen {
-					return false
-				}
-				m.scts = append(m.scts, d[:sctLen])
-				d = d[sctLen:]
-			}
 		}
 		data = data[length:]
 	}
diff --git a/src/crypto/tls/handshake_messages_test.go b/src/crypto/tls/handshake_messages_test.go
index 95d825b..a96e95c 100644
--- a/src/crypto/tls/handshake_messages_test.go
+++ b/src/crypto/tls/handshake_messages_test.go
@@ -136,15 +136,12 @@ func (*clientHelloMsg) Generate(rand *rand.Rand, size int) reflect.Value {
 		}
 	}
 	if rand.Intn(10) > 5 {
-		m.signatureAndHashes = supportedSignatureAlgorithms
+		m.signatureAndHashes = supportedSKXSignatureAlgorithms
 	}
 	m.alpnProtocols = make([]string, rand.Intn(5))
 	for i := range m.alpnProtocols {
 		m.alpnProtocols[i] = randomString(rand.Intn(20)+1, rand)
 	}
-	if rand.Intn(10) > 5 {
-		m.scts = true
-	}
 
 	return reflect.ValueOf(m)
 }
@@ -175,14 +172,6 @@ func (*serverHelloMsg) Generate(rand *rand.Rand, size int) reflect.Value {
 	}
 	m.alpnProtocol = randomString(rand.Intn(32)+1, rand)
 
-	if rand.Intn(10) > 5 {
-		numSCTs := rand.Intn(4)
-		m.scts = make([][]byte, numSCTs)
-		for i := range m.scts {
-			m.scts[i] = randomBytes(rand.Intn(500), rand)
-		}
-	}
-
 	return reflect.ValueOf(m)
 }
 
diff --git a/src/crypto/tls/handshake_server.go b/src/crypto/tls/handshake_server.go
index e16cddc..0d90765 100644
--- a/src/crypto/tls/handshake_server.go
+++ b/src/crypto/tls/handshake_server.go
@@ -25,8 +25,6 @@ type serverHandshakeState struct {
 	suite           *cipherSuite
 	ellipticOk      bool
 	ecdsaOk         bool
-	rsaDecryptOk    bool
-	rsaSignOk       bool
 	sessionState    *sessionState
 	finishedHash    finishedHash
 	masterSecret    []byte
@@ -59,14 +57,6 @@ func (c *Conn) serverHandshake() error {
 		if err := hs.establishKeys(); err != nil {
 			return err
 		}
-		// ticketSupported is set in a resumption handshake if the
-		// ticket from the client was encrypted with an old session
-		// ticket key and thus a refreshed ticket should be sent.
-		if hs.hello.ticketSupported {
-			if err := hs.sendSessionTicket(); err != nil {
-				return err
-			}
-		}
 		if err := hs.sendFinished(c.firstFinished[:]); err != nil {
 			return err
 		}
@@ -121,6 +111,9 @@ func (hs *serverHandshakeState) readClientHello() (isResume bool, err error) {
 	}
 	c.haveVers = true
 
+	hs.finishedHash = newFinishedHash(c.vers)
+	hs.finishedHash.Write(hs.clientHello.marshal())
+
 	hs.hello = new(serverHelloMsg)
 
 	supportedCurve := false
@@ -180,47 +173,33 @@ Curves:
 		// Although sending an empty NPN extension is reasonable, Firefox has
 		// had a bug around this. Best to send nothing at all if
 		// config.NextProtos is empty. See
-		// https://golang.org/issue/5445.
+		// https://code.google.com/p/go/issues/detail?id=5445.
 		if hs.clientHello.nextProtoNeg && len(config.NextProtos) > 0 {
 			hs.hello.nextProtoNeg = true
 			hs.hello.nextProtos = config.NextProtos
 		}
 	}
 
-	if hs.cert, err = config.getCertificate(&ClientHelloInfo{
-		CipherSuites:    hs.clientHello.cipherSuites,
-		ServerName:      hs.clientHello.serverName,
-		SupportedCurves: hs.clientHello.supportedCurves,
-		SupportedPoints: hs.clientHello.supportedPoints,
-	}); err != nil {
+	if len(config.Certificates) == 0 {
 		c.sendAlert(alertInternalError)
-		return false, err
-	}
-	if hs.clientHello.scts {
-		hs.hello.scts = hs.cert.SignedCertificateTimestamps
+		return false, errors.New("tls: no certificates configured")
 	}
-
-	if priv, ok := hs.cert.PrivateKey.(crypto.Signer); ok {
-		switch priv.Public().(type) {
-		case *ecdsa.PublicKey:
-			hs.ecdsaOk = true
-		case *rsa.PublicKey:
-			hs.rsaSignOk = true
-		default:
-			c.sendAlert(alertInternalError)
-			return false, fmt.Errorf("crypto/tls: unsupported signing key type (%T)", priv.Public())
+	hs.cert = &config.Certificates[0]
+	if len(hs.clientHello.serverName) > 0 {
+		chi := &ClientHelloInfo{
+			CipherSuites:    hs.clientHello.cipherSuites,
+			ServerName:      hs.clientHello.serverName,
+			SupportedCurves: hs.clientHello.supportedCurves,
+			SupportedPoints: hs.clientHello.supportedPoints,
 		}
-	}
-	if priv, ok := hs.cert.PrivateKey.(crypto.Decrypter); ok {
-		switch priv.Public().(type) {
-		case *rsa.PublicKey:
-			hs.rsaDecryptOk = true
-		default:
+		if hs.cert, err = config.getCertificate(chi); err != nil {
 			c.sendAlert(alertInternalError)
-			return false, fmt.Errorf("crypto/tls: unsupported decryption key type (%T)", priv.Public())
+			return false, err
 		}
 	}
 
+	_, hs.ecdsaOk = hs.cert.PrivateKey.(*ecdsa.PrivateKey)
+
 	if hs.checkForResumption() {
 		return true, nil
 	}
@@ -235,7 +214,7 @@ Curves:
 	}
 
 	for _, id := range preferenceList {
-		if hs.setCipherSuite(id, supportedList, c.vers) {
+		if hs.suite = c.tryCipherSuite(id, supportedList, c.vers, hs.ellipticOk, hs.ecdsaOk); hs.suite != nil {
 			break
 		}
 	}
@@ -249,9 +228,9 @@ Curves:
 	for _, id := range hs.clientHello.cipherSuites {
 		if id == TLS_FALLBACK_SCSV {
 			// The client is doing a fallback connection.
-			if hs.clientHello.vers < c.config.maxVersion() {
+			if hs.clientHello.vers < c.config.MaxVersion {
 				c.sendAlert(alertInappropriateFallback)
-				return false, errors.New("tls: client using inappropriate protocol fallback")
+				return false, errors.New("tls: client using inppropriate protocol fallback")
 			}
 			break
 		}
@@ -260,7 +239,7 @@ Curves:
 	return false, nil
 }
 
-// checkForResumption reports whether we should perform resumption on this connection.
+// checkForResumption returns true if we should perform resumption on this connection.
 func (hs *serverHandshakeState) checkForResumption() bool {
 	c := hs.c
 
@@ -269,8 +248,7 @@ func (hs *serverHandshakeState) checkForResumption() bool {
 	}
 
 	var ok bool
-	var sessionTicket = append([]uint8{}, hs.clientHello.sessionTicket...)
-	if hs.sessionState, ok = c.decryptTicket(sessionTicket); !ok {
+	if hs.sessionState, ok = c.decryptTicket(hs.clientHello.sessionTicket); !ok {
 		return false
 	}
 
@@ -294,7 +272,8 @@ func (hs *serverHandshakeState) checkForResumption() bool {
 	}
 
 	// Check that we also support the ciphersuite from the session.
-	if !hs.setCipherSuite(hs.sessionState.cipherSuite, c.config.cipherSuites(), hs.sessionState.vers) {
+	hs.suite = c.tryCipherSuite(hs.sessionState.cipherSuite, c.config.cipherSuites(), hs.sessionState.vers, hs.ellipticOk, hs.ecdsaOk)
+	if hs.suite == nil {
 		return false
 	}
 
@@ -317,10 +296,6 @@ func (hs *serverHandshakeState) doResumeHandshake() error {
 	// We echo the client's session ID in the ServerHello to let it know
 	// that we're doing a resumption.
 	hs.hello.sessionId = hs.clientHello.sessionId
-	hs.hello.ticketSupported = hs.sessionState.usedOldKey
-	hs.finishedHash = newFinishedHash(c.vers, hs.suite)
-	hs.finishedHash.discardHandshakeBuffer()
-	hs.finishedHash.Write(hs.clientHello.marshal())
 	hs.finishedHash.Write(hs.hello.marshal())
 	c.writeRecord(recordTypeHandshake, hs.hello.marshal())
 
@@ -345,14 +320,6 @@ func (hs *serverHandshakeState) doFullHandshake() error {
 
 	hs.hello.ticketSupported = hs.clientHello.ticketSupported && !config.SessionTicketsDisabled
 	hs.hello.cipherSuite = hs.suite.id
-
-	hs.finishedHash = newFinishedHash(hs.c.vers, hs.suite)
-	if config.ClientAuth == NoClientCert {
-		// No need to keep a full record of the handshake if client
-		// certificates won't be used.
-		hs.finishedHash.discardHandshakeBuffer()
-	}
-	hs.finishedHash.Write(hs.clientHello.marshal())
 	hs.finishedHash.Write(hs.hello.marshal())
 	c.writeRecord(recordTypeHandshake, hs.hello.marshal())
 
@@ -389,7 +356,7 @@ func (hs *serverHandshakeState) doFullHandshake() error {
 		}
 		if c.vers >= VersionTLS12 {
 			certReq.hasSignatureAndHash = true
-			certReq.signatureAndHashes = supportedSignatureAlgorithms
+			certReq.signatureAndHashes = supportedClientCertSignatureAlgorithms
 		}
 
 		// An empty list of certificateAuthorities signals to
@@ -453,13 +420,6 @@ func (hs *serverHandshakeState) doFullHandshake() error {
 	}
 	hs.finishedHash.Write(ckx.marshal())
 
-	preMasterSecret, err := keyAgreement.processClientKeyExchange(config, hs.cert, ckx, c.vers)
-	if err != nil {
-		c.sendAlert(alertHandshakeFailure)
-		return err
-	}
-	hs.masterSecret = masterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret, hs.clientHello.random, hs.hello.random)
-
 	// If we received a client cert in response to our certificate request message,
 	// the client will send us a certificateVerifyMsg immediately after the
 	// clientKeyExchangeMsg.  This message is a digest of all preceding
@@ -477,31 +437,8 @@ func (hs *serverHandshakeState) doFullHandshake() error {
 			return unexpectedMessageError(certVerify, msg)
 		}
 
-		// Determine the signature type.
-		var signatureAndHash signatureAndHash
-		if certVerify.hasSignatureAndHash {
-			signatureAndHash = certVerify.signatureAndHash
-			if !isSupportedSignatureAndHash(signatureAndHash, supportedSignatureAlgorithms) {
-				return errors.New("tls: unsupported hash function for client certificate")
-			}
-		} else {
-			// Before TLS 1.2 the signature algorithm was implicit
-			// from the key type, and only one hash per signature
-			// algorithm was possible. Leave the hash as zero.
-			switch pub.(type) {
-			case *ecdsa.PublicKey:
-				signatureAndHash.signature = signatureECDSA
-			case *rsa.PublicKey:
-				signatureAndHash.signature = signatureRSA
-			}
-		}
-
 		switch key := pub.(type) {
 		case *ecdsa.PublicKey:
-			if signatureAndHash.signature != signatureECDSA {
-				err = errors.New("bad signature type for client's ECDSA certificate")
-				break
-			}
 			ecdsaSig := new(ecdsaSignature)
 			if _, err = asn1.Unmarshal(certVerify.signature, ecdsaSig); err != nil {
 				break
@@ -510,34 +447,29 @@ func (hs *serverHandshakeState) doFullHandshake() error {
 				err = errors.New("ECDSA signature contained zero or negative values")
 				break
 			}
-			var digest []byte
-			if digest, _, err = hs.finishedHash.hashForClientCertificate(signatureAndHash, hs.masterSecret); err != nil {
-				break
-			}
+			digest, _, _ := hs.finishedHash.hashForClientCertificate(signatureECDSA)
 			if !ecdsa.Verify(key, digest, ecdsaSig.R, ecdsaSig.S) {
 				err = errors.New("ECDSA verification failure")
-			}
-		case *rsa.PublicKey:
-			if signatureAndHash.signature != signatureRSA {
-				err = errors.New("bad signature type for client's RSA certificate")
-				break
-			}
-			var digest []byte
-			var hashFunc crypto.Hash
-			if digest, hashFunc, err = hs.finishedHash.hashForClientCertificate(signatureAndHash, hs.masterSecret); err != nil {
 				break
 			}
+		case *rsa.PublicKey:
+			digest, hashFunc, _ := hs.finishedHash.hashForClientCertificate(signatureRSA)
 			err = rsa.VerifyPKCS1v15(key, hashFunc, digest, certVerify.signature)
 		}
 		if err != nil {
 			c.sendAlert(alertBadCertificate)
-			return errors.New("tls: could not validate signature of connection nonces: " + err.Error())
+			return errors.New("could not validate signature of connection nonces: " + err.Error())
 		}
 
 		hs.finishedHash.Write(certVerify.marshal())
 	}
 
-	hs.finishedHash.discardHandshakeBuffer()
+	preMasterSecret, err := keyAgreement.processClientKeyExchange(config, hs.cert, ckx, c.vers)
+	if err != nil {
+		c.sendAlert(alertHandshakeFailure)
+		return err
+	}
+	hs.masterSecret = masterFromPreMasterSecret(c.vers, preMasterSecret, hs.clientHello.random, hs.hello.random)
 
 	return nil
 }
@@ -546,7 +478,7 @@ func (hs *serverHandshakeState) establishKeys() error {
 	c := hs.c
 
 	clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV :=
-		keysFromMasterSecret(c.vers, hs.suite, hs.masterSecret, hs.clientHello.random, hs.hello.random, hs.suite.macLen, hs.suite.keyLen, hs.suite.ivLen)
+		keysFromMasterSecret(c.vers, hs.masterSecret, hs.clientHello.random, hs.hello.random, hs.suite.macLen, hs.suite.keyLen, hs.suite.ivLen)
 
 	var clientCipher, serverCipher interface{}
 	var clientHash, serverHash macFunction
@@ -687,6 +619,18 @@ func (hs *serverHandshakeState) processCertsFromClient(certificates [][]byte) (c
 			return nil, errors.New("tls: failed to verify client's certificate: " + err.Error())
 		}
 
+		ok := false
+		for _, ku := range certs[0].ExtKeyUsage {
+			if ku == x509.ExtKeyUsageClientAuth {
+				ok = true
+				break
+			}
+		}
+		if !ok {
+			c.sendAlert(alertHandshakeFailure)
+			return nil, errors.New("tls: client's certificate's extended key usage doesn't permit it to be used for client authentication")
+		}
+
 		c.verifiedChains = chains
 	}
 
@@ -706,10 +650,9 @@ func (hs *serverHandshakeState) processCertsFromClient(certificates [][]byte) (c
 	return nil, nil
 }
 
-// setCipherSuite sets a cipherSuite with the given id as the serverHandshakeState
-// suite if that cipher suite is acceptable to use.
-// It returns a bool indicating if the suite was set.
-func (hs *serverHandshakeState) setCipherSuite(id uint16, supportedCipherSuites []uint16, version uint16) bool {
+// tryCipherSuite returns a cipherSuite with the given id if that cipher suite
+// is acceptable to use.
+func (c *Conn) tryCipherSuite(id uint16, supportedCipherSuites []uint16, version uint16, ellipticOk, ecdsaOk bool) *cipherSuite {
 	for _, supported := range supportedCipherSuites {
 		if id == supported {
 			var candidate *cipherSuite
@@ -725,26 +668,18 @@ func (hs *serverHandshakeState) setCipherSuite(id uint16, supportedCipherSuites
 			}
 			// Don't select a ciphersuite which we can't
 			// support for this client.
-			if candidate.flags&suiteECDHE != 0 {
-				if !hs.ellipticOk {
-					continue
-				}
-				if candidate.flags&suiteECDSA != 0 {
-					if !hs.ecdsaOk {
-						continue
-					}
-				} else if !hs.rsaSignOk {
-					continue
-				}
-			} else if !hs.rsaDecryptOk {
+			if (candidate.flags&suiteECDHE != 0) && !ellipticOk {
+				continue
+			}
+			if (candidate.flags&suiteECDSA != 0) != ecdsaOk {
 				continue
 			}
 			if version < VersionTLS12 && candidate.flags&suiteTLS12 != 0 {
 				continue
 			}
-			hs.suite = candidate
-			return true
+			return candidate
 		}
 	}
-	return false
+
+	return nil
 }
diff --git a/src/crypto/tls/handshake_server_test.go b/src/crypto/tls/handshake_server_test.go
index 20c2bd6..0338af4 100644
--- a/src/crypto/tls/handshake_server_test.go
+++ b/src/crypto/tls/handshake_server_test.go
@@ -37,15 +37,6 @@ func (zeroSource) Read(b []byte) (n int, err error) {
 
 var testConfig *Config
 
-func allCipherSuites() []uint16 {
-	ids := make([]uint16, len(cipherSuites))
-	for i, suite := range cipherSuites {
-		ids[i] = suite.id
-	}
-
-	return ids
-}
-
 func init() {
 	testConfig = &Config{
 		Time:               func() time.Time { return time.Unix(0, 0) },
@@ -54,7 +45,6 @@ func init() {
 		InsecureSkipVerify: true,
 		MinVersion:         VersionSSL30,
 		MaxVersion:         VersionTLS12,
-		CipherSuites:       allCipherSuites(),
 	}
 	testConfig.Certificates[0].Certificate = [][]byte{testRSACertificate}
 	testConfig.Certificates[0].PrivateKey = testRSAPrivateKey
@@ -63,11 +53,7 @@ func init() {
 	testConfig.BuildNameToCertificate()
 }
 
-func testClientHello(t *testing.T, serverConfig *Config, m handshakeMessage) {
-	testClientHelloFailure(t, serverConfig, m, "")
-}
-
-func testClientHelloFailure(t *testing.T, serverConfig *Config, m handshakeMessage, expectedSubStr string) {
+func testClientHelloFailure(t *testing.T, m handshakeMessage, expectedSubStr string) {
 	// Create in-memory network connection,
 	// send message to server.  Should return
 	// expected error.
@@ -80,26 +66,22 @@ func testClientHelloFailure(t *testing.T, serverConfig *Config, m handshakeMessa
 		cli.writeRecord(recordTypeHandshake, m.marshal())
 		c.Close()
 	}()
-	err := Server(s, serverConfig).Handshake()
+	err := Server(s, testConfig).Handshake()
 	s.Close()
-	if len(expectedSubStr) == 0 {
-		if err != nil && err != io.EOF {
-			t.Errorf("Got error: %s; expected to succeed", err, expectedSubStr)
-		}
-	} else if err == nil || !strings.Contains(err.Error(), expectedSubStr) {
+	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, testConfig, &serverHelloDoneMsg{}, "unexpected handshake message")
+	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, testConfig, &clientHelloMsg{vers: v}, "unsupported, maximum protocol version")
+		testClientHelloFailure(t, &clientHelloMsg{vers: v}, "unsupported, maximum protocol version")
 	}
 }
 
@@ -109,7 +91,7 @@ func TestNoSuiteOverlap(t *testing.T) {
 		cipherSuites:       []uint16{0xff00},
 		compressionMethods: []uint8{0},
 	}
-	testClientHelloFailure(t, testConfig, clientHello, "no cipher suite supported by both client and server")
+	testClientHelloFailure(t, clientHello, "no cipher suite supported by both client and server")
 }
 
 func TestNoCompressionOverlap(t *testing.T) {
@@ -118,117 +100,7 @@ func TestNoCompressionOverlap(t *testing.T) {
 		cipherSuites:       []uint16{TLS_RSA_WITH_RC4_128_SHA},
 		compressionMethods: []uint8{0xff},
 	}
-	testClientHelloFailure(t, testConfig, clientHello, "client does not support uncompressed connections")
-}
-
-func TestNoRC4ByDefault(t *testing.T) {
-	clientHello := &clientHelloMsg{
-		vers:               0x0301,
-		cipherSuites:       []uint16{TLS_RSA_WITH_RC4_128_SHA},
-		compressionMethods: []uint8{0},
-	}
-	serverConfig := *testConfig
-	// Reset the enabled cipher suites to nil in order to test the
-	// defaults.
-	serverConfig.CipherSuites = nil
-	testClientHelloFailure(t, &serverConfig, clientHello, "no cipher suite supported by both client and server")
-}
-
-func TestDontSelectECDSAWithRSAKey(t *testing.T) {
-	// Test that, even when both sides support an ECDSA cipher suite, it
-	// won't be selected if the server's private key doesn't support it.
-	clientHello := &clientHelloMsg{
-		vers:               0x0301,
-		cipherSuites:       []uint16{TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA},
-		compressionMethods: []uint8{0},
-		supportedCurves:    []CurveID{CurveP256},
-		supportedPoints:    []uint8{pointFormatUncompressed},
-	}
-	serverConfig := *testConfig
-	serverConfig.CipherSuites = clientHello.cipherSuites
-	serverConfig.Certificates = make([]Certificate, 1)
-	serverConfig.Certificates[0].Certificate = [][]byte{testECDSACertificate}
-	serverConfig.Certificates[0].PrivateKey = testECDSAPrivateKey
-	serverConfig.BuildNameToCertificate()
-	// First test that it *does* work when the server's key is ECDSA.
-	testClientHello(t, &serverConfig, clientHello)
-
-	// Now test that switching to an RSA key causes the expected error (and
-	// not an internal error about a signing failure).
-	serverConfig.Certificates = testConfig.Certificates
-	testClientHelloFailure(t, &serverConfig, clientHello, "no cipher suite supported by both client and server")
-}
-
-func TestDontSelectRSAWithECDSAKey(t *testing.T) {
-	// Test that, even when both sides support an RSA cipher suite, it
-	// won't be selected if the server's private key doesn't support it.
-	clientHello := &clientHelloMsg{
-		vers:               0x0301,
-		cipherSuites:       []uint16{TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA},
-		compressionMethods: []uint8{0},
-		supportedCurves:    []CurveID{CurveP256},
-		supportedPoints:    []uint8{pointFormatUncompressed},
-	}
-	serverConfig := *testConfig
-	serverConfig.CipherSuites = clientHello.cipherSuites
-	// First test that it *does* work when the server's key is RSA.
-	testClientHello(t, &serverConfig, clientHello)
-
-	// Now test that switching to an ECDSA key causes the expected error
-	// (and not an internal error about a signing failure).
-	serverConfig.Certificates = make([]Certificate, 1)
-	serverConfig.Certificates[0].Certificate = [][]byte{testECDSACertificate}
-	serverConfig.Certificates[0].PrivateKey = testECDSAPrivateKey
-	serverConfig.BuildNameToCertificate()
-	testClientHelloFailure(t, &serverConfig, clientHello, "no cipher suite supported by both client and server")
-}
-
-func TestRenegotiationExtension(t *testing.T) {
-	clientHello := &clientHelloMsg{
-		vers:                VersionTLS12,
-		compressionMethods:  []uint8{compressionNone},
-		random:              make([]byte, 32),
-		secureRenegotiation: true,
-		cipherSuites:        []uint16{TLS_RSA_WITH_RC4_128_SHA},
-	}
-
-	var buf []byte
-	c, s := net.Pipe()
-
-	go func() {
-		cli := Client(c, testConfig)
-		cli.vers = clientHello.vers
-		cli.writeRecord(recordTypeHandshake, clientHello.marshal())
-
-		buf = make([]byte, 1024)
-		n, err := c.Read(buf)
-		if err != nil {
-			t.Fatalf("Server read returned error: %s", err)
-		}
-		buf = buf[:n]
-		c.Close()
-	}()
-
-	Server(s, testConfig).Handshake()
-
-	if len(buf) < 5+4 {
-		t.Fatalf("Server returned short message of length %d", len(buf))
-	}
-	// buf contains a TLS record, with a 5 byte record header and a 4 byte
-	// handshake header. The length of the ServerHello is taken from the
-	// handshake header.
-	serverHelloLen := int(buf[6])<<16 | int(buf[7])<<8 | int(buf[8])
-
-	var serverHello serverHelloMsg
-	// unmarshal expects to be given the handshake header, but
-	// serverHelloLen doesn't include it.
-	if !serverHello.unmarshal(buf[5 : 9+serverHelloLen]) {
-		t.Fatalf("Failed to parse ServerHello")
-	}
-
-	if !serverHello.secureRenegotiation {
-		t.Errorf("Secure renegotiation extension was not echoed.")
-	}
+	testClientHelloFailure(t, clientHello, "client does not support uncompressed connections")
 }
 
 func TestTLS12OnlyCipherSuites(t *testing.T) {
@@ -303,20 +175,19 @@ func TestClose(t *testing.T) {
 	}
 }
 
-func testHandshake(clientConfig, serverConfig *Config) (serverState, clientState ConnectionState, err error) {
+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()
-		clientState = cli.ConnectionState()
 		c.Close()
 		done <- true
 	}()
 	server := Server(s, serverConfig)
 	err = server.Handshake()
 	if err == nil {
-		serverState = server.ConnectionState()
+		state = server.ConnectionState()
 	}
 	s.Close()
 	<-done
@@ -331,7 +202,7 @@ func TestVersion(t *testing.T) {
 	clientConfig := &Config{
 		InsecureSkipVerify: true,
 	}
-	state, _, err := testHandshake(clientConfig, serverConfig)
+	state, err := testHandshake(clientConfig, serverConfig)
 	if err != nil {
 		t.Fatalf("handshake failed: %s", err)
 	}
@@ -350,7 +221,7 @@ func TestCipherSuitePreference(t *testing.T) {
 		CipherSuites:       []uint16{TLS_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_RC4_128_SHA},
 		InsecureSkipVerify: true,
 	}
-	state, _, err := testHandshake(clientConfig, serverConfig)
+	state, err := testHandshake(clientConfig, serverConfig)
 	if err != nil {
 		t.Fatalf("handshake failed: %s", err)
 	}
@@ -360,7 +231,7 @@ func TestCipherSuitePreference(t *testing.T) {
 	}
 
 	serverConfig.PreferServerCipherSuites = true
-	state, _, err = testHandshake(clientConfig, serverConfig)
+	state, err = testHandshake(clientConfig, serverConfig)
 	if err != nil {
 		t.Fatalf("handshake failed: %s", err)
 	}
@@ -369,33 +240,6 @@ func TestCipherSuitePreference(t *testing.T) {
 	}
 }
 
-func TestSCTHandshake(t *testing.T) {
-	expected := [][]byte{[]byte("certificate"), []byte("transparency")}
-	serverConfig := &Config{
-		Certificates: []Certificate{{
-			Certificate:                 [][]byte{testRSACertificate},
-			PrivateKey:                  testRSAPrivateKey,
-			SignedCertificateTimestamps: expected,
-		}},
-	}
-	clientConfig := &Config{
-		InsecureSkipVerify: true,
-	}
-	_, state, err := testHandshake(clientConfig, serverConfig)
-	if err != nil {
-		t.Fatalf("handshake failed: %s", err)
-	}
-	actual := state.SignedCertificateTimestamps
-	if len(actual) != len(expected) {
-		t.Fatalf("got %d scts, want %d", len(actual), len(expected))
-	}
-	for i, sct := range expected {
-		if !bytes.Equal(sct, actual[i]) {
-			t.Fatalf("SCT #%d was %x, but expected %x", i, actual[i], sct)
-		}
-	}
-}
-
 // Note: see comment in handshake_test.go for details of how the reference
 // tests work.
 
@@ -413,6 +257,9 @@ type serverTest struct {
 	expectedPeerCerts []string
 	// config, if not nil, contains a custom Config to use for this test.
 	config *Config
+	// expectAlert, if true, indicates that a fatal alert should be returned
+	// when handshaking with the server.
+	expectAlert bool
 	// expectHandshakeErrorIncluding, when not empty, contains a string
 	// that must be a substring of the error resulting from the handshake.
 	expectHandshakeErrorIncluding string
@@ -537,7 +384,9 @@ func (test *serverTest) run(t *testing.T, write bool) {
 	if !write {
 		flows, err := test.loadData()
 		if err != nil {
-			t.Fatalf("%s: failed to load data from %s", test.name, test.dataPath())
+			if !test.expectAlert {
+				t.Fatalf("%s: failed to load data from %s", test.name, test.dataPath())
+			}
 		}
 		for i, b := range flows {
 			if i%2 == 0 {
@@ -546,11 +395,17 @@ func (test *serverTest) run(t *testing.T, write bool) {
 			}
 			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)
+			if test.expectAlert {
+				if err == nil {
+					t.Fatal("Expected read failure but read succeeded")
+				}
+			} else {
+				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()
@@ -661,14 +516,6 @@ func TestHandshakeServerAESGCM(t *testing.T) {
 	runServerTestTLS12(t, test)
 }
 
-func TestHandshakeServerAES256GCMSHA384(t *testing.T) {
-	test := &serverTest{
-		name:    "RSA-AES256-GCM-SHA384",
-		command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "ECDHE-RSA-AES256-GCM-SHA384"},
-	}
-	runServerTestTLS12(t, test)
-}
-
 func TestHandshakeServerECDHEECDSAAES(t *testing.T) {
 	config := *testConfig
 	config.Certificates = make([]Certificate, 1)
@@ -752,7 +599,7 @@ func TestHandshakeServerSNIGetCertificate(t *testing.T) {
 		return cert, nil
 	}
 	test := &serverTest{
-		name:    "SNI-GetCertificate",
+		name:    "SNI",
 		command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "AES128-SHA", "-servername", "snitest.com"},
 		config:  &config,
 	}
@@ -770,7 +617,7 @@ func TestHandshakeServerSNIGetCertificateNotFound(t *testing.T) {
 		return nil, nil
 	}
 	test := &serverTest{
-		name:    "SNI-GetCertificateNotFound",
+		name:    "SNI",
 		command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "AES128-SHA", "-servername", "snitest.com"},
 		config:  &config,
 	}
@@ -780,50 +627,18 @@ func TestHandshakeServerSNIGetCertificateNotFound(t *testing.T) {
 // TestHandshakeServerSNICertForNameError tests to make sure that errors in
 // GetCertificate result in a tls alert.
 func TestHandshakeServerSNIGetCertificateError(t *testing.T) {
-	const errMsg = "TestHandshakeServerSNIGetCertificateError error"
-
-	serverConfig := *testConfig
-	serverConfig.GetCertificate = func(clientHello *ClientHelloInfo) (*Certificate, error) {
-		return nil, errors.New(errMsg)
-	}
-
-	clientHello := &clientHelloMsg{
-		vers:               0x0301,
-		cipherSuites:       []uint16{TLS_RSA_WITH_RC4_128_SHA},
-		compressionMethods: []uint8{0},
-		serverName:         "test",
-	}
-	testClientHelloFailure(t, &serverConfig, clientHello, errMsg)
-}
-
-// TestHandshakeServerEmptyCertificates tests that GetCertificates is called in
-// the case that Certificates is empty, even without SNI.
-func TestHandshakeServerEmptyCertificates(t *testing.T) {
-	const errMsg = "TestHandshakeServerEmptyCertificates error"
-
-	serverConfig := *testConfig
-	serverConfig.GetCertificate = func(clientHello *ClientHelloInfo) (*Certificate, error) {
-		return nil, errors.New(errMsg)
-	}
-	serverConfig.Certificates = nil
+	config := *testConfig
 
-	clientHello := &clientHelloMsg{
-		vers:               0x0301,
-		cipherSuites:       []uint16{TLS_RSA_WITH_RC4_128_SHA},
-		compressionMethods: []uint8{0},
+	config.GetCertificate = func(clientHello *ClientHelloInfo) (*Certificate, error) {
+		return nil, fmt.Errorf("Test error in GetCertificate")
 	}
-	testClientHelloFailure(t, &serverConfig, clientHello, errMsg)
-
-	// With an empty Certificates and a nil GetCertificate, the server
-	// should always return a “no certificates” error.
-	serverConfig.GetCertificate = nil
-
-	clientHello = &clientHelloMsg{
-		vers:               0x0301,
-		cipherSuites:       []uint16{TLS_RSA_WITH_RC4_128_SHA},
-		compressionMethods: []uint8{0},
+	test := &serverTest{
+		name:        "SNI",
+		command:     []string{"openssl", "s_client", "-no_ticket", "-cipher", "AES128-SHA", "-servername", "snitest.com"},
+		config:      &config,
+		expectAlert: true,
 	}
-	testClientHelloFailure(t, &serverConfig, clientHello, "no certificates")
+	runServerTestTLS12(t, test)
 }
 
 // TestCipherSuiteCertPreferance ensures that we select an RSA ciphersuite with
@@ -901,15 +716,11 @@ func TestResumptionDisabled(t *testing.T) {
 }
 
 func TestFallbackSCSV(t *testing.T) {
-	serverConfig := &Config{
-		Certificates: testConfig.Certificates,
-	}
 	test := &serverTest{
-		name:   "FallbackSCSV",
-		config: serverConfig,
+		name: "FallbackSCSV",
 		// OpenSSL 1.0.1j is needed for the -fallback_scsv option.
 		command: []string{"openssl", "s_client", "-fallback_scsv"},
-		expectHandshakeErrorIncluding: "inappropriate protocol fallback",
+		expectHandshakeErrorIncluding: "inppropriate protocol fallback",
 	}
 	runServerTestTLS11(t, test)
 }
@@ -1029,9 +840,7 @@ func fromHex(s string) []byte {
 	return b
 }
 
-var testRSACertificate = fromHex("30820263308201cca003020102020900a273000c8100cbf3300d06092a864886f70d01010b0500302b31173015060355040a130e476f6f676c652054455354494e473110300e06035504031307476f20526f6f74301e170d3135303130313030303030305a170d3235303130313030303030305a302631173015060355040a130e476f6f676c652054455354494e47310b300906035504031302476f30819f300d06092a864886f70d010101050003818d0030818902818100af8788f6201b95656c14ab4405af3b4514e3b76dfd00634d957ffe6a623586c04af9187cf6aa255e7a643166 [...]
-
-var testRSACertificateIssuer = fromHex("3082024d308201b6a003020102020827326bd913b7c43d300d06092a864886f70d01010b0500302b31173015060355040a130e476f6f676c652054455354494e473110300e06035504031307476f20526f6f74301e170d3135303130313030303030305a170d3235303130313030303030305a302b31173015060355040a130e476f6f676c652054455354494e473110300e06035504031307476f20526f6f7430819f300d06092a864886f70d010101050003818d0030818902818100f0429a7b9f66a222c8453800452db355b34c4409fee09af2510a6589bfa35bdb4d453200d1 [...]
+var testRSACertificate = fromHex("308202b030820219a00302010202090085b0bba48a7fb8ca300d06092a864886f70d01010505003045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c7464301e170d3130303432343039303933385a170d3131303432343039303933385a3045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c746430819f300d06092a864886f70d010101 [...]
 
 var testECDSACertificate = fromHex("3082020030820162020900b8bf2d47a0d2ebf4300906072a8648ce3d04013045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c7464301e170d3132313132323135303633325a170d3232313132303135303633325a3045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c746430819b301006072a8648ce3d020106052b81040023038186 [...]
 
@@ -1039,13 +848,13 @@ var testSNICertificate = fromHex("308201f23082015da003020102020100300b06092a8648
 
 var testRSAPrivateKey = &rsa.PrivateKey{
 	PublicKey: rsa.PublicKey{
-		N: bigFromString("123260960069105588390096594560395120585636206567569540256061833976822892593755073841963170165000086278069699238754008398039246547214989242849418349143232951701395321381739566687846006911427966669790845430647688107009232778985142860108863460556510585049041936029324503323373417214453307648498561956908810892027L"),
+		N: bigFromString("131650079503776001033793877885499001334664249354723305978524647182322416328664556247316495448366990052837680518067798333412266673813370895702118944398081598789828837447552603077848001020611640547221687072142537202428102790818451901395596882588063427854225330436740647715202971973145151161964464812406232198521"),
 		E: 65537,
 	},
-	D: bigFromString("73196363031103823625826315929954946106043759818067219550565550066527203472294428548476778865091068522665312037075674791871635825938217363523103946045078950060973913307430314113074463630778799389010335923241901501086246276485964417618981733827707048660375428006201525399194575538037883519254056917253456403553L"),
+	D: bigFromString("29354450337804273969007277378287027274721892607543397931919078829901848876371746653677097639302788129485893852488285045793268732234230875671682624082413996177431586734171663258657462237320300610850244186316880055243099640544518318093544057213190320837094958164973959123058337475052510833916491060913053867729"),
 	Primes: []*big.Int{
-		bigFromString("11157426355495284553529769521954035649776033703833034489026848970480272318436419662860715175517581249375929775774910501512841707465207184924996975125010787L"),
-		bigFromString("11047436580963564307160117670964629323534448585520694947919342920137706075617545637058809770319843170934495909554506529982972972247390145716507031692656521L"),
+		bigFromString("11969277782311800166562047708379380720136961987713178380670422671426759650127150688426177829077494755200794297055316163155755835813760102405344560929062149"),
+		bigFromString("10998999429884441391899182616418192492905073053684657075974935218461686523870125521822756579792315215543092255516093840728890783887287417039645833477273829"),
 	},
 }
 
diff --git a/src/crypto/tls/key_agreement.go b/src/crypto/tls/key_agreement.go
index 0e6a7c2..0974fc6 100644
--- a/src/crypto/tls/key_agreement.go
+++ b/src/crypto/tls/key_agreement.go
@@ -11,6 +11,7 @@ import (
 	"crypto/md5"
 	"crypto/rsa"
 	"crypto/sha1"
+	"crypto/sha256"
 	"crypto/x509"
 	"encoding/asn1"
 	"errors"
@@ -30,6 +31,12 @@ func (ka rsaKeyAgreement) generateServerKeyExchange(config *Config, cert *Certif
 }
 
 func (ka rsaKeyAgreement) processClientKeyExchange(config *Config, cert *Certificate, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) {
+	preMasterSecret := make([]byte, 48)
+	_, err := io.ReadFull(config.rand(), preMasterSecret[2:])
+	if err != nil {
+		return nil, err
+	}
+
 	if len(ckx.ciphertext) < 2 {
 		return nil, errClientKeyExchange
 	}
@@ -42,12 +49,8 @@ func (ka rsaKeyAgreement) processClientKeyExchange(config *Config, cert *Certifi
 		}
 		ciphertext = ckx.ciphertext[2:]
 	}
-	priv, ok := cert.PrivateKey.(crypto.Decrypter)
-	if !ok {
-		return nil, errors.New("tls: certificate private key does not implement crypto.Decrypter")
-	}
-	// Perform constant time RSA PKCS#1 v1.5 decryption
-	preMasterSecret, err := priv.Decrypt(config.rand(), ciphertext, &rsa.PKCS1v15DecryptOptions{SessionKeyLen: 48})
+
+	err = rsa.DecryptPKCS1v15SessionKey(config.rand(), cert.PrivateKey.(*rsa.PrivateKey), ciphertext, preMasterSecret)
 	if err != nil {
 		return nil, err
 	}
@@ -107,26 +110,30 @@ func md5SHA1Hash(slices [][]byte) []byte {
 	return md5sha1
 }
 
+// sha256Hash implements TLS 1.2's hash function.
+func sha256Hash(slices [][]byte) []byte {
+	h := sha256.New()
+	for _, slice := range slices {
+		h.Write(slice)
+	}
+	return h.Sum(nil)
+}
+
 // hashForServerKeyExchange hashes the given slices and returns their digest
-// and the identifier of the hash function used. The sigAndHash argument is
-// only used for >= TLS 1.2 and precisely identifies the hash function to use.
-func hashForServerKeyExchange(sigAndHash signatureAndHash, version uint16, slices ...[]byte) ([]byte, crypto.Hash, error) {
+// and the identifier of the hash function used. The hashFunc argument is only
+// used for >= TLS 1.2 and precisely identifies the hash function to use.
+func hashForServerKeyExchange(sigType, hashFunc uint8, version uint16, slices ...[]byte) ([]byte, crypto.Hash, error) {
 	if version >= VersionTLS12 {
-		if !isSupportedSignatureAndHash(sigAndHash, supportedSignatureAlgorithms) {
-			return nil, crypto.Hash(0), errors.New("tls: unsupported hash function used by peer")
+		switch hashFunc {
+		case hashSHA256:
+			return sha256Hash(slices), crypto.SHA256, nil
+		case hashSHA1:
+			return sha1Hash(slices), crypto.SHA1, nil
+		default:
+			return nil, crypto.Hash(0), errors.New("tls: unknown hash function used by peer")
 		}
-		hashFunc, err := lookupTLSHash(sigAndHash.hash)
-		if err != nil {
-			return nil, crypto.Hash(0), err
-		}
-		h := hashFunc.New()
-		for _, slice := range slices {
-			h.Write(slice)
-		}
-		digest := h.Sum(nil)
-		return digest, hashFunc, nil
 	}
-	if sigAndHash.signature == signatureECDSA {
+	if sigType == signatureECDSA {
 		return sha1Hash(slices), crypto.SHA1, nil
 	}
 	return md5SHA1Hash(slices), crypto.MD5SHA1, nil
@@ -135,19 +142,20 @@ func hashForServerKeyExchange(sigAndHash signatureAndHash, version uint16, slice
 // pickTLS12HashForSignature returns a TLS 1.2 hash identifier for signing a
 // ServerKeyExchange given the signature type being used and the client's
 // advertised list of supported signature and hash combinations.
-func pickTLS12HashForSignature(sigType uint8, clientList []signatureAndHash) (uint8, error) {
-	if len(clientList) == 0 {
+func pickTLS12HashForSignature(sigType uint8, clientSignatureAndHashes []signatureAndHash) (uint8, error) {
+	if len(clientSignatureAndHashes) == 0 {
 		// If the client didn't specify any signature_algorithms
 		// extension then we can assume that it supports SHA1. See
 		// http://tools.ietf.org/html/rfc5246#section-7.4.1.4.1
 		return hashSHA1, nil
 	}
 
-	for _, sigAndHash := range clientList {
+	for _, sigAndHash := range clientSignatureAndHashes {
 		if sigAndHash.signature != sigType {
 			continue
 		}
-		if isSupportedSignatureAndHash(sigAndHash, supportedSignatureAlgorithms) {
+		switch sigAndHash.hash {
+		case hashSHA1, hashSHA256:
 			return sigAndHash.hash, nil
 		}
 	}
@@ -220,42 +228,41 @@ NextCandidate:
 	serverECDHParams[3] = byte(len(ecdhePublic))
 	copy(serverECDHParams[4:], ecdhePublic)
 
-	sigAndHash := signatureAndHash{signature: ka.sigType}
-
+	var tls12HashId uint8
 	if ka.version >= VersionTLS12 {
-		if sigAndHash.hash, err = pickTLS12HashForSignature(ka.sigType, clientHello.signatureAndHashes); err != nil {
+		if tls12HashId, err = pickTLS12HashForSignature(ka.sigType, clientHello.signatureAndHashes); err != nil {
 			return nil, err
 		}
 	}
 
-	digest, hashFunc, err := hashForServerKeyExchange(sigAndHash, ka.version, clientHello.random, hello.random, serverECDHParams)
+	digest, hashFunc, err := hashForServerKeyExchange(ka.sigType, tls12HashId, ka.version, clientHello.random, hello.random, serverECDHParams)
 	if err != nil {
 		return nil, err
 	}
-
-	priv, ok := cert.PrivateKey.(crypto.Signer)
-	if !ok {
-		return nil, errors.New("tls: certificate private key does not implement crypto.Signer")
-	}
 	var sig []byte
 	switch ka.sigType {
 	case signatureECDSA:
-		_, ok := priv.Public().(*ecdsa.PublicKey)
+		privKey, ok := cert.PrivateKey.(*ecdsa.PrivateKey)
 		if !ok {
-			return nil, errors.New("ECDHE ECDSA requires an ECDSA server key")
+			return nil, errors.New("ECDHE ECDSA requires an ECDSA server private key")
 		}
+		r, s, err := ecdsa.Sign(config.rand(), privKey, digest)
+		if err != nil {
+			return nil, errors.New("failed to sign ECDHE parameters: " + err.Error())
+		}
+		sig, err = asn1.Marshal(ecdsaSignature{r, s})
 	case signatureRSA:
-		_, ok := priv.Public().(*rsa.PublicKey)
+		privKey, ok := cert.PrivateKey.(*rsa.PrivateKey)
 		if !ok {
-			return nil, errors.New("ECDHE RSA requires a RSA server key")
+			return nil, errors.New("ECDHE RSA requires a RSA server private key")
+		}
+		sig, err = rsa.SignPKCS1v15(config.rand(), privKey, hashFunc, digest)
+		if err != nil {
+			return nil, errors.New("failed to sign ECDHE parameters: " + err.Error())
 		}
 	default:
 		return nil, errors.New("unknown ECDHE signature algorithm")
 	}
-	sig, err = priv.Sign(config.rand(), digest, hashFunc)
-	if err != nil {
-		return nil, errors.New("failed to sign ECDHE parameters: " + err.Error())
-	}
 
 	skx := new(serverKeyExchangeMsg)
 	sigAndHashLen := 0
@@ -266,8 +273,8 @@ NextCandidate:
 	copy(skx.key, serverECDHParams)
 	k := skx.key[len(serverECDHParams):]
 	if ka.version >= VersionTLS12 {
-		k[0] = sigAndHash.hash
-		k[1] = sigAndHash.signature
+		k[0] = tls12HashId
+		k[1] = ka.sigType
 		k = k[2:]
 	}
 	k[0] = byte(len(sig) >> 8)
@@ -328,14 +335,15 @@ func (ka *ecdheKeyAgreement) processServerKeyExchange(config *Config, clientHell
 		return errServerKeyExchange
 	}
 
-	sigAndHash := signatureAndHash{signature: ka.sigType}
+	var tls12HashId uint8
 	if ka.version >= VersionTLS12 {
 		// handle SignatureAndHashAlgorithm
-		sigAndHash = signatureAndHash{hash: sig[0], signature: sig[1]}
-		if sigAndHash.signature != ka.sigType {
+		var sigAndHash []uint8
+		sigAndHash, sig = sig[:2], sig[2:]
+		if sigAndHash[1] != ka.sigType {
 			return errServerKeyExchange
 		}
-		sig = sig[2:]
+		tls12HashId = sigAndHash[0]
 		if len(sig) < 2 {
 			return errServerKeyExchange
 		}
@@ -346,7 +354,7 @@ func (ka *ecdheKeyAgreement) processServerKeyExchange(config *Config, clientHell
 	}
 	sig = sig[2:]
 
-	digest, hashFunc, err := hashForServerKeyExchange(sigAndHash, ka.version, clientHello.random, serverHello.random, serverECDHParams)
+	digest, hashFunc, err := hashForServerKeyExchange(ka.sigType, tls12HashId, ka.version, clientHello.random, serverHello.random, serverECDHParams)
 	if err != nil {
 		return err
 	}
diff --git a/src/crypto/tls/prf.go b/src/crypto/tls/prf.go
index 6127c1c..fb8b3ab 100644
--- a/src/crypto/tls/prf.go
+++ b/src/crypto/tls/prf.go
@@ -10,8 +10,6 @@ import (
 	"crypto/md5"
 	"crypto/sha1"
 	"crypto/sha256"
-	"crypto/sha512"
-	"errors"
 	"hash"
 )
 
@@ -67,14 +65,12 @@ func prf10(result, secret, label, seed []byte) {
 }
 
 // prf12 implements the TLS 1.2 pseudo-random function, as defined in RFC 5246, section 5.
-func prf12(hashFunc func() hash.Hash) func(result, secret, label, seed []byte) {
-	return func(result, secret, label, seed []byte) {
-		labelAndSeed := make([]byte, len(label)+len(seed))
-		copy(labelAndSeed, label)
-		copy(labelAndSeed[len(label):], seed)
+func prf12(result, secret, label, seed []byte) {
+	labelAndSeed := make([]byte, len(label)+len(seed))
+	copy(labelAndSeed, label)
+	copy(labelAndSeed[len(label):], seed)
 
-		pHash(result, secret, labelAndSeed, hashFunc)
-	}
+	pHash(result, secret, labelAndSeed, sha256.New)
 }
 
 // prf30 implements the SSL 3.0 pseudo-random function, as defined in
@@ -121,49 +117,41 @@ var keyExpansionLabel = []byte("key expansion")
 var clientFinishedLabel = []byte("client finished")
 var serverFinishedLabel = []byte("server finished")
 
-func prfAndHashForVersion(version uint16, suite *cipherSuite) (func(result, secret, label, seed []byte), crypto.Hash) {
+func prfForVersion(version uint16) func(result, secret, label, seed []byte) {
 	switch version {
 	case VersionSSL30:
-		return prf30, crypto.Hash(0)
+		return prf30
 	case VersionTLS10, VersionTLS11:
-		return prf10, crypto.Hash(0)
+		return prf10
 	case VersionTLS12:
-		if suite.flags&suiteSHA384 != 0 {
-			return prf12(sha512.New384), crypto.SHA384
-		}
-		return prf12(sha256.New), crypto.SHA256
+		return prf12
 	default:
 		panic("unknown version")
 	}
 }
 
-func prfForVersion(version uint16, suite *cipherSuite) func(result, secret, label, seed []byte) {
-	prf, _ := prfAndHashForVersion(version, suite)
-	return prf
-}
-
 // masterFromPreMasterSecret generates the master secret from the pre-master
 // secret. See http://tools.ietf.org/html/rfc5246#section-8.1
-func masterFromPreMasterSecret(version uint16, suite *cipherSuite, preMasterSecret, clientRandom, serverRandom []byte) []byte {
+func masterFromPreMasterSecret(version uint16, preMasterSecret, clientRandom, serverRandom []byte) []byte {
 	var seed [tlsRandomLength * 2]byte
 	copy(seed[0:len(clientRandom)], clientRandom)
 	copy(seed[len(clientRandom):], serverRandom)
 	masterSecret := make([]byte, masterSecretLength)
-	prfForVersion(version, suite)(masterSecret, preMasterSecret, masterSecretLabel, seed[0:])
+	prfForVersion(version)(masterSecret, preMasterSecret, masterSecretLabel, seed[0:])
 	return masterSecret
 }
 
 // keysFromMasterSecret generates the connection keys from the master
 // secret, given the lengths of the MAC key, cipher key and IV, as defined in
 // RFC 2246, section 6.3.
-func keysFromMasterSecret(version uint16, suite *cipherSuite, masterSecret, clientRandom, serverRandom []byte, macLen, keyLen, ivLen int) (clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV []byte) {
+func keysFromMasterSecret(version uint16, masterSecret, clientRandom, serverRandom []byte, macLen, keyLen, ivLen int) (clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV []byte) {
 	var seed [tlsRandomLength * 2]byte
 	copy(seed[0:len(clientRandom)], serverRandom)
 	copy(seed[len(serverRandom):], clientRandom)
 
 	n := 2*macLen + 2*keyLen + 2*ivLen
 	keyMaterial := make([]byte, n)
-	prfForVersion(version, suite)(keyMaterial, masterSecret, keyExpansionLabel, seed[0:])
+	prfForVersion(version)(keyMaterial, masterSecret, keyExpansionLabel, seed[0:])
 	clientMAC = keyMaterial[:macLen]
 	keyMaterial = keyMaterial[macLen:]
 	serverMAC = keyMaterial[:macLen]
@@ -178,33 +166,11 @@ func keysFromMasterSecret(version uint16, suite *cipherSuite, masterSecret, clie
 	return
 }
 
-// lookupTLSHash looks up the corresponding crypto.Hash for a given
-// TLS hash identifier.
-func lookupTLSHash(hash uint8) (crypto.Hash, error) {
-	switch hash {
-	case hashSHA1:
-		return crypto.SHA1, nil
-	case hashSHA256:
-		return crypto.SHA256, nil
-	case hashSHA384:
-		return crypto.SHA384, nil
-	default:
-		return 0, errors.New("tls: unsupported hash algorithm")
-	}
-}
-
-func newFinishedHash(version uint16, cipherSuite *cipherSuite) finishedHash {
-	var buffer []byte
-	if version == VersionSSL30 || version >= VersionTLS12 {
-		buffer = []byte{}
+func newFinishedHash(version uint16) finishedHash {
+	if version >= VersionTLS12 {
+		return finishedHash{sha256.New(), sha256.New(), nil, nil, version}
 	}
-
-	prf, hash := prfAndHashForVersion(version, cipherSuite)
-	if hash != 0 {
-		return finishedHash{hash.New(), hash.New(), nil, nil, buffer, version, prf}
-	}
-
-	return finishedHash{sha1.New(), sha1.New(), md5.New(), md5.New(), buffer, version, prf}
+	return finishedHash{sha1.New(), sha1.New(), md5.New(), md5.New(), version}
 }
 
 // A finishedHash calculates the hash of a set of handshake messages suitable
@@ -217,14 +183,10 @@ type finishedHash struct {
 	clientMD5 hash.Hash
 	serverMD5 hash.Hash
 
-	// In TLS 1.2, a full buffer is sadly required.
-	buffer []byte
-
 	version uint16
-	prf     func(result, secret, label, seed []byte)
 }
 
-func (h *finishedHash) Write(msg []byte) (n int, err error) {
+func (h finishedHash) Write(msg []byte) (n int, err error) {
 	h.client.Write(msg)
 	h.server.Write(msg)
 
@@ -232,29 +194,14 @@ func (h *finishedHash) Write(msg []byte) (n int, err error) {
 		h.clientMD5.Write(msg)
 		h.serverMD5.Write(msg)
 	}
-
-	if h.buffer != nil {
-		h.buffer = append(h.buffer, msg...)
-	}
-
 	return len(msg), nil
 }
 
-func (h finishedHash) Sum() []byte {
-	if h.version >= VersionTLS12 {
-		return h.client.Sum(nil)
-	}
-
-	out := make([]byte, 0, md5.Size+sha1.Size)
-	out = h.clientMD5.Sum(out)
-	return h.client.Sum(out)
-}
-
 // finishedSum30 calculates the contents of the verify_data member of a SSLv3
 // Finished message given the MD5 and SHA1 hashes of a set of handshake
 // messages.
-func finishedSum30(md5, sha1 hash.Hash, masterSecret []byte, magic []byte) []byte {
-	md5.Write(magic)
+func finishedSum30(md5, sha1 hash.Hash, masterSecret []byte, magic [4]byte) []byte {
+	md5.Write(magic[:])
 	md5.Write(masterSecret)
 	md5.Write(ssl30Pad1[:])
 	md5Digest := md5.Sum(nil)
@@ -265,7 +212,7 @@ func finishedSum30(md5, sha1 hash.Hash, masterSecret []byte, magic []byte) []byt
 	md5.Write(md5Digest)
 	md5Digest = md5.Sum(nil)
 
-	sha1.Write(magic)
+	sha1.Write(magic[:])
 	sha1.Write(masterSecret)
 	sha1.Write(ssl30Pad1[:40])
 	sha1Digest := sha1.Sum(nil)
@@ -289,11 +236,19 @@ var ssl3ServerFinishedMagic = [4]byte{0x53, 0x52, 0x56, 0x52}
 // Finished message.
 func (h finishedHash) clientSum(masterSecret []byte) []byte {
 	if h.version == VersionSSL30 {
-		return finishedSum30(h.clientMD5, h.client, masterSecret, ssl3ClientFinishedMagic[:])
+		return finishedSum30(h.clientMD5, h.client, masterSecret, ssl3ClientFinishedMagic)
 	}
 
 	out := make([]byte, finishedVerifyLength)
-	h.prf(out, masterSecret, clientFinishedLabel, h.Sum())
+	if h.version >= VersionTLS12 {
+		seed := h.client.Sum(nil)
+		prf12(out, masterSecret, clientFinishedLabel, seed)
+	} else {
+		seed := make([]byte, 0, md5.Size+sha1.Size)
+		seed = h.clientMD5.Sum(seed)
+		seed = h.client.Sum(seed)
+		prf10(out, masterSecret, clientFinishedLabel, seed)
+	}
 	return out
 }
 
@@ -301,67 +256,36 @@ func (h finishedHash) clientSum(masterSecret []byte) []byte {
 // Finished message.
 func (h finishedHash) serverSum(masterSecret []byte) []byte {
 	if h.version == VersionSSL30 {
-		return finishedSum30(h.serverMD5, h.server, masterSecret, ssl3ServerFinishedMagic[:])
+		return finishedSum30(h.serverMD5, h.server, masterSecret, ssl3ServerFinishedMagic)
 	}
 
 	out := make([]byte, finishedVerifyLength)
-	h.prf(out, masterSecret, serverFinishedLabel, h.Sum())
-	return out
-}
-
-// selectClientCertSignatureAlgorithm returns a signatureAndHash to sign a
-// client's CertificateVerify with, or an error if none can be found.
-func (h finishedHash) selectClientCertSignatureAlgorithm(serverList []signatureAndHash, sigType uint8) (signatureAndHash, error) {
-	if h.version < VersionTLS12 {
-		// Nothing to negotiate before TLS 1.2.
-		return signatureAndHash{signature: sigType}, nil
-	}
-
-	for _, v := range serverList {
-		if v.signature == sigType && isSupportedSignatureAndHash(v, supportedSignatureAlgorithms) {
-			return v, nil
-		}
+	if h.version >= VersionTLS12 {
+		seed := h.server.Sum(nil)
+		prf12(out, masterSecret, serverFinishedLabel, seed)
+	} else {
+		seed := make([]byte, 0, md5.Size+sha1.Size)
+		seed = h.serverMD5.Sum(seed)
+		seed = h.server.Sum(seed)
+		prf10(out, masterSecret, serverFinishedLabel, seed)
 	}
-	return signatureAndHash{}, errors.New("tls: no supported signature algorithm found for signing client certificate")
+	return out
 }
 
 // hashForClientCertificate returns a digest, hash function, and TLS 1.2 hash
 // id suitable for signing by a TLS client certificate.
-func (h finishedHash) hashForClientCertificate(signatureAndHash signatureAndHash, masterSecret []byte) ([]byte, crypto.Hash, error) {
-	if (h.version == VersionSSL30 || h.version >= VersionTLS12) && h.buffer == nil {
-		panic("a handshake hash for a client-certificate was requested after discarding the handshake buffer")
-	}
-
-	if h.version == VersionSSL30 {
-		if signatureAndHash.signature != signatureRSA {
-			return nil, 0, errors.New("tls: unsupported signature type for client certificate")
-		}
-
-		md5Hash := md5.New()
-		md5Hash.Write(h.buffer)
-		sha1Hash := sha1.New()
-		sha1Hash.Write(h.buffer)
-		return finishedSum30(md5Hash, sha1Hash, masterSecret, nil), crypto.MD5SHA1, nil
-	}
+func (h finishedHash) hashForClientCertificate(sigType uint8) ([]byte, crypto.Hash, uint8) {
 	if h.version >= VersionTLS12 {
-		hashAlg, err := lookupTLSHash(signatureAndHash.hash)
-		if err != nil {
-			return nil, 0, err
-		}
-		hash := hashAlg.New()
-		hash.Write(h.buffer)
-		return hash.Sum(nil), hashAlg, nil
+		digest := h.server.Sum(nil)
+		return digest, crypto.SHA256, hashSHA256
 	}
-
-	if signatureAndHash.signature == signatureECDSA {
-		return h.server.Sum(nil), crypto.SHA1, nil
+	if sigType == signatureECDSA {
+		digest := h.server.Sum(nil)
+		return digest, crypto.SHA1, hashSHA1
 	}
 
-	return h.Sum(), crypto.MD5SHA1, nil
-}
-
-// discardHandshakeBuffer is called when there is no more need to
-// buffer the entirety of the handshake messages.
-func (h *finishedHash) discardHandshakeBuffer() {
-	h.buffer = nil
+	digest := make([]byte, 0, 36)
+	digest = h.serverMD5.Sum(digest)
+	digest = h.server.Sum(digest)
+	return digest, crypto.MD5SHA1, 0 /* not specified in TLS 1.2. */
 }
diff --git a/src/crypto/tls/prf_test.go b/src/crypto/tls/prf_test.go
index 0a1b1bc..a9b6c9e 100644
--- a/src/crypto/tls/prf_test.go
+++ b/src/crypto/tls/prf_test.go
@@ -35,7 +35,6 @@ func TestSplitPreMasterSecret(t *testing.T) {
 
 type testKeysFromTest struct {
 	version                    uint16
-	suite                      *cipherSuite
 	preMasterSecret            string
 	clientRandom, serverRandom string
 	masterSecret               string
@@ -50,13 +49,13 @@ func TestKeysFromPreMasterSecret(t *testing.T) {
 		clientRandom, _ := hex.DecodeString(test.clientRandom)
 		serverRandom, _ := hex.DecodeString(test.serverRandom)
 
-		masterSecret := masterFromPreMasterSecret(test.version, test.suite, in, clientRandom, serverRandom)
+		masterSecret := masterFromPreMasterSecret(test.version, in, clientRandom, serverRandom)
 		if s := hex.EncodeToString(masterSecret); s != test.masterSecret {
 			t.Errorf("#%d: bad master secret %s, want %s", i, s, test.masterSecret)
 			continue
 		}
 
-		clientMAC, serverMAC, clientKey, serverKey, _, _ := keysFromMasterSecret(test.version, test.suite, masterSecret, clientRandom, serverRandom, test.macLen, test.keyLen, 0)
+		clientMAC, serverMAC, clientKey, serverKey, _, _ := keysFromMasterSecret(test.version, masterSecret, clientRandom, serverRandom, test.macLen, test.keyLen, 0)
 		clientMACString := hex.EncodeToString(clientMAC)
 		serverMACString := hex.EncodeToString(serverMAC)
 		clientKeyString := hex.EncodeToString(clientKey)
@@ -70,20 +69,10 @@ func TestKeysFromPreMasterSecret(t *testing.T) {
 	}
 }
 
-func cipherSuiteById(id uint16) *cipherSuite {
-	for _, cipherSuite := range cipherSuites {
-		if cipherSuite.id == id {
-			return cipherSuite
-		}
-	}
-	panic("ciphersuite not found")
-}
-
 // These test vectors were generated from GnuTLS using `gnutls-cli --insecure -d 9 `
 var testKeysFromTests = []testKeysFromTest{
 	{
 		VersionTLS10,
-		cipherSuiteById(TLS_RSA_WITH_RC4_128_SHA),
 		"0302cac83ad4b1db3b9ab49ad05957de2a504a634a386fc600889321e1a971f57479466830ac3e6f468e87f5385fa0c5",
 		"4ae66303755184a3917fcb44880605fcc53baa01912b22ed94473fc69cebd558",
 		"4ae663020ec16e6bb5130be918cfcafd4d765979a3136a5d50c593446e4e44db",
@@ -97,7 +86,6 @@ var testKeysFromTests = []testKeysFromTest{
 	},
 	{
 		VersionTLS10,
-		cipherSuiteById(TLS_RSA_WITH_RC4_128_SHA),
 		"03023f7527316bc12cbcd69e4b9e8275d62c028f27e65c745cfcddc7ce01bd3570a111378b63848127f1c36e5f9e4890",
 		"4ae66364b5ea56b20ce4e25555aed2d7e67f42788dd03f3fee4adae0459ab106",
 		"4ae66363ab815cbf6a248b87d6b556184e945e9b97fbdf247858b0bdafacfa1c",
@@ -111,7 +99,6 @@ var testKeysFromTests = []testKeysFromTest{
 	},
 	{
 		VersionTLS10,
-		cipherSuiteById(TLS_RSA_WITH_RC4_128_SHA),
 		"832d515f1d61eebb2be56ba0ef79879efb9b527504abb386fb4310ed5d0e3b1f220d3bb6b455033a2773e6d8bdf951d278a187482b400d45deb88a5d5a6bb7d6a7a1decc04eb9ef0642876cd4a82d374d3b6ff35f0351dc5d411104de431375355addc39bfb1f6329fb163b0bc298d658338930d07d313cd980a7e3d9196cac1",
 		"4ae663b2ee389c0de147c509d8f18f5052afc4aaf9699efe8cb05ece883d3a5e",
 		"4ae664d503fd4cff50cfc1fb8fc606580f87b0fcdac9554ba0e01d785bdf278e",
@@ -125,7 +112,6 @@ var testKeysFromTests = []testKeysFromTest{
 	},
 	{
 		VersionSSL30,
-		cipherSuiteById(TLS_RSA_WITH_RC4_128_SHA),
 		"832d515f1d61eebb2be56ba0ef79879efb9b527504abb386fb4310ed5d0e3b1f220d3bb6b455033a2773e6d8bdf951d278a187482b400d45deb88a5d5a6bb7d6a7a1decc04eb9ef0642876cd4a82d374d3b6ff35f0351dc5d411104de431375355addc39bfb1f6329fb163b0bc298d658338930d07d313cd980a7e3d9196cac1",
 		"4ae663b2ee389c0de147c509d8f18f5052afc4aaf9699efe8cb05ece883d3a5e",
 		"4ae664d503fd4cff50cfc1fb8fc606580f87b0fcdac9554ba0e01d785bdf278e",
diff --git a/src/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-ECDSA b/src/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-ECDSA
index 4bad786..00722cb 100644
--- a/src/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-ECDSA
+++ b/src/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-ECDSA
@@ -1,19 +1,18 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
+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 1e c0 2f  |.............../|
-00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
-00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 36  |...../.5.......6|
-00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
-00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0e 00  |................|
-00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
-00000080  01 00 00 12 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 c0 e1 5c 5b 45  |....Y...U....\[E|
-00000010  70 fc a1 73 44 e7 69 b6  83 a1 71 bc 03 21 2e cc  |p..sD.i...q..!..|
-00000020  21 7a 28 20 82 6b 2f 77  7d 40 c7 20 0d e4 19 db  |!z( .k/w}@. ....|
-00000030  35 cd 75 a4 e7 e5 6c 3e  c9 d5 fe 9d c5 88 78 7b  |5.u...l>......x{|
-00000040  c4 fc 04 9a c1 10 7a 15  d9 e9 4a 95 c0 09 00 00  |......z...J.....|
+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....|
@@ -48,21 +47,21 @@
 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 01  |*............A..|
-00000280  74 83 af 3a 65 7a ad 1a  63 1f 13 82 9d f4 de 06  |t..:ez..c.......|
-00000290  4e 3a 03 81 61 72 ff f8  58 da 7b f5 81 6d 81 57  |N:..ar..X.{..m.W|
-000002a0  d9 d1 b1 6d e3 97 db 86  72 17 15 18 16 d4 ec 04  |...m....r.......|
-000002b0  32 7c 38 90 6b a4 3c e9  35 79 2d 4c 39 5e 2d 00  |2|8.k.<.5y-L9^-.|
-000002c0  8b 30 81 88 02 42 01 44  78 e1 2a bb 95 f7 45 58  |.0...B.Dx.*...EX|
-000002d0  d4 0d b6 e4 4e ff 48 b3  11 14 ee d5 6c bb 5f 0c  |....N.H.....l._.|
-000002e0  90 b6 ef bc 05 77 f6 05  42 b4 d8 a6 70 e6 8c 90  |.....w..B...p...|
-000002f0  f0 4b 3b c9 d3 4e 0c 85  65 b4 e0 fe b5 10 09 9b  |.K;..N..e.......|
-00000300  e1 08 84 ea 93 96 8e a4  02 42 01 c7 15 ee 9d 98  |.........B......|
-00000310  b7 25 eb 07 ff f6 94 7e  e7 9d a5 17 9e 37 93 40  |.%.....~.....7.@|
-00000320  4c 9f eb 6b a3 7a 57 d8  81 c6 d9 09 34 aa 96 8c  |L..k.zW.....4...|
-00000330  4d 28 2e 9f f7 0b 1c 09  e1 d1 d8 48 6e 8a 8e 9c  |M(.........Hn...|
-00000340  01 4c e7 2d 53 8f 8e 71  61 82 ff ff 16 03 01 00  |.L.-S..qa.......|
-00000350  0e 0d 00 00 06 03 01 02  40 00 00 0e 00 00 00     |........ at ......|
+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|
@@ -101,30 +100,30 @@
 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 91 0f  |.h.A.Vk.Z.......|
-00000260  00 00 8d 00 8b 30 81 88  02 42 01 91 2d e9 99 a4  |.....0...B..-...|
-00000270  88 5c 03 9c ea 8b 64 07  f2 c9 e7 ad 5b a3 fb 27  |.\....d.....[..'|
-00000280  fd 19 9b 78 bd 7b 9d 0a  cc 8a 61 c5 83 33 02 29  |...x.{....a..3.)|
-00000290  c3 66 24 9d 5f bc 03 d9  2a 49 aa 59 51 83 49 72  |.f$._...*I.YQ.Ir|
-000002a0  13 be ea 82 5a 5c 09 2f  da 23 bc 18 02 42 01 0d  |....Z\./.#...B..|
-000002b0  a1 15 4d fe 18 ec 90 d5  4e 9a 75 60 05 67 10 5e  |..M.....N.u`.g.^|
-000002c0  3c 34 00 e8 18 33 8f 90  26 2e d3 a9 81 6c 43 17  |<4...3..&....lC.|
-000002d0  80 9e c5 bd 23 c9 24 96  a1 29 23 a4 13 3f ad d2  |....#.$..)#..?..|
-000002e0  45 19 0b 56 56 4b c1 f1  cc 70 c8 af 44 ff 34 96  |E..VVK...p..D.4.|
-000002f0  14 03 01 00 01 01 16 03  01 00 30 c4 0c 67 53 06  |..........0..gS.|
-00000300  49 b3 c9 5c 2e 72 f6 54  ba ad ac a8 80 55 17 01  |I..\.r.T.....U..|
-00000310  5c 44 71 7d ad 15 34 95  9a 7f 7b 95 0e 08 70 ce  |\Dq}..4...{...p.|
-00000320  5a 33 f4 3b 4e 80 06 43  70 93 17                 |Z3.;N..Cp..|
+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 3b ba 6c 73 ec  |..........0;.ls.|
-00000010  11 5b 44 46 1d bb 31 1b  1b e8 d8 51 4f 95 b0 40  |.[DF..1....QO..@|
-00000020  87 49 33 73 40 98 61 1c  94 02 48 9b 80 d3 6c af  |.I3s at .a...H...l.|
-00000030  e2 31 63 11 a7 c8 db ed  7a a4 4d                 |.1c.....z.M|
+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 2e f7 66  f0 ce 50 d7 38 7a d4 fd  |.... ..f..P.8z..|
-00000010  e3 66 b1 76 76 59 ad bc  b0 0a 75 1d f0 92 6e e3  |.f.vvY....u...n.|
-00000020  21 1d 13 dc ad 17 03 01  00 20 f1 b2 0f 3b 26 91  |!........ ...;&.|
-00000030  ed ff 9f fc 41 04 7e 47  17 02 af 0c 2b e8 b7 31  |....A.~G....+..1|
-00000040  ae 29 71 f9 a8 89 84 f3  e8 da 15 03 01 00 20 1f  |.)q........... .|
-00000050  26 64 cf 34 c1 48 6b 79  61 e2 77 57 9d 27 14 45  |&d.4.Hkya.wW.'.E|
-00000060  46 24 ad 2d 35 57 db 2b  32 03 e2 68 b0 1a 5a     |F$.-5W.+2..h..Z|
+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/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-RSA b/src/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-RSA
index 0e420a6..c0be824 100644
--- a/src/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-RSA
+++ b/src/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-RSA
@@ -1,19 +1,18 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
+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 1e c0 2f  |.............../|
-00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
-00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 36  |...../.5.......6|
-00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
-00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0e 00  |................|
-00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
-00000080  01 00 00 12 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 b7 de 52 5a 07  |....Q...M....RZ.|
-00000010  43 b8 72 1d d9 6f 5c a5  70 da ee 27 b7 a9 50 9d  |C.r..o\.p..'..P.|
-00000020  e7 75 ad 61 a5 2f 69 47  2a d8 2e 20 a8 b0 64 6b  |.u.a./iG*.. ..dk|
-00000030  4d 25 ec 50 2b 8e a7 9b  0c f9 f5 3c 62 96 a3 53  |M%.P+......<b..S|
-00000040  a7 4b af 33 1e e7 f8 43  b9 be 6e e7 00 05 00 00  |.K.3...C..n.....|
+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..|
@@ -102,25 +101,25 @@
 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 91 0f  |..C.0oUN.p......|
-000002a0  00 00 8d 00 8b 30 81 88  02 42 00 b5 1a 9d 48 90  |.....0...B....H.|
-000002b0  2f d9 1a 04 66 f7 3b 4d  d7 ae d9 1e dd 3c fa 24  |/...f.;M.....<.$|
-000002c0  0f 24 97 b2 61 46 16 d9  a0 35 f9 f7 54 45 92 fd  |.$..aF...5..TE..|
-000002d0  10 56 ab 26 d7 b5 10 80  8b 88 95 ef c6 73 1c d2  |.V.&.........s..|
-000002e0  ff e9 20 cd 18 a8 40 c4  4d 83 c2 e2 02 42 01 8c  |.. ... at .M....B..|
-000002f0  d2 13 4c cc e5 38 37 17  6c 83 d6 ad c1 dc af ec  |..L..87.l.......|
-00000300  8d 06 75 b8 08 ad 56 4a  8f b9 03 59 80 f8 81 d4  |..u...VJ...Y....|
-00000310  f3 91 89 eb 9c 27 5d e1  dc 6d ef d6 20 da e7 9c  |.....']..m.. ...|
-00000320  71 75 cb 2a f9 e4 05 46  c8 85 ca 7b 9c 97 e8 6d  |qu.*...F...{...m|
-00000330  14 03 01 00 01 01 16 03  01 00 24 9f 67 4e 22 04  |..........$.gN".|
-00000340  10 f4 28 55 3e 50 88 90  61 07 42 29 f5 9b f5 32  |..(U>P..a.B)...2|
-00000350  16 3d ea c1 8f aa a1 4c  b5 72 26 d8 32 cd 50     |.=.....L.r&.2.P|
+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 df 8d f1 07 6d  |..........$....m|
-00000010  63 39 fc ba b1 67 3b 68  85 b9 37 7d d3 67 19 76  |c9...g;h..7}.g.v|
-00000020  34 a4 1b 86 31 bd fe 06  72 00 d8 2b f2 65 3d     |4...1...r..+.e=|
+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 60 cc 81  4f 8b 73 b3 7f 34 bf f1  |.....`..O.s..4..|
-00000010  7c d8 32 0a ef 2a 26 f9  b8 69 84 83 48 21 ee 15  ||.2..*&..i..H!..|
-00000020  03 01 00 16 23 7a 0c 65  3a 66 1a 75 03 e4 85 3f  |....#z.e:f.u...?|
-00000030  83 cd 55 70 99 f4 44 dc  67 ba                    |..Up..D.g.|
+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/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-ECDSA b/src/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-ECDSA
index 7e33edc..3e6dbc2 100644
--- a/src/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-ECDSA
+++ b/src/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-ECDSA
@@ -1,19 +1,18 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
+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 1e c0 2f  |.............../|
-00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
-00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 36  |...../.5.......6|
-00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
-00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0e 00  |................|
-00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
-00000080  01 00 00 12 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 dc a9 22 c2 a2  |....Y...U...."..|
-00000010  05 ba c4 66 9a 71 aa 0f  92 6a fc df b0 29 4d 36  |...f.q...j...)M6|
-00000020  39 2e f8 39 ed 8e f6 7f  8f 17 13 20 f8 9c f3 3d  |9..9....... ...=|
-00000030  0a 41 8f 30 c7 5d cd 17  c5 ad 1c 52 45 a3 47 8c  |.A.0.].....RE.G.|
-00000040  07 4c 48 e1 00 2b 32 38  01 c8 79 b7 c0 09 00 00  |.LH..+28..y.....|
+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....|
@@ -48,21 +47,21 @@
 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 89  |*............A..|
-00000280  95 9a 90 82 59 ab 29 bf  10 06 8c 6c 0d 67 cf b1  |....Y.)....l.g..|
-00000290  66 8b 5e 43 b8 46 56 3a  8d 30 92 35 28 82 f2 38  |f.^C.FV:.0.5(..8|
-000002a0  6e 19 5d 37 f0 ab fc 78  15 6a 6a 73 ca dc a6 f2  |n.]7...x.jjs....|
-000002b0  68 5d b3 ab 6d 68 44 3b  80 d2 d9 cd 78 0a ed 00  |h]..mhD;....x...|
-000002c0  8a 30 81 87 02 42 01 80  63 4a 22 4c 8e 66 4e 25  |.0...B..cJ"L.fN%|
-000002d0  e1 86 27 81 de eb b3 a0  c4 dc dc e2 a0 94 2a b6  |..'...........*.|
-000002e0  b3 e9 e7 42 e1 1d 1a c0  43 8d a1 d6 8d 77 84 06  |...B....C....w..|
-000002f0  ba 95 99 e3 54 80 59 4e  3c fb 0c f3 b7 d3 a8 d2  |....T.YN<.......|
-00000300  ce 49 97 fb e2 79 91 93  02 41 2b 2c b7 9f 81 ea  |.I...y...A+,....|
-00000310  de 17 12 af 4d 20 bc a1  43 1d 60 a0 37 52 a2 7b  |....M ..C.`.7R.{|
-00000320  a8 4c de fd 1d fe 37 3b  00 23 61 ce d2 80 47 43  |.L....7;.#a...GC|
-00000330  b0 3a f3 1f aa c7 07 b1  68 5b d8 f3 03 a9 56 5c  |.:......h[....V\|
-00000340  63 ef 83 1d 9c 9c 8d 29  81 e9 3b 16 03 01 00 0e  |c......)..;.....|
-00000350  0d 00 00 06 03 01 02 40  00 00 0e 00 00 00        |....... at ......|
+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|
@@ -101,29 +100,29 @@
 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 0e 80  9c 3a 6e 40 51 09 39 d4  |.........:n at Q.9.|
-00000260  40 58 10 da 7f 32 12 08  9e f0 4d 9a d7 20 a2 9c  |@X...2....M.. ..|
-00000270  b0 95 3a 33 4e f8 b1 a3  74 62 ab 51 7d 23 d4 32  |..:3N...tb.Q}#.2|
-00000280  a2 af b8 5a 3b b0 23 e4  7a f1 eb 4d b7 bb 23 d5  |...Z;.#.z..M..#.|
-00000290  a9 0d b4 81 d2 b4 45 bd  15 52 ad 58 da 92 a2 c4  |......E..R.X....|
-000002a0  30 66 87 f2 ae c5 e4 8c  fa ba a0 40 76 b8 3f 72  |0f......... at v.?r|
-000002b0  2a d9 95 2a 2d c6 05 3c  1e 2f 11 ef c5 3c 11 e4  |*..*-..<./...<..|
-000002c0  be 5a de 37 43 7f 74 52  6e ee 3c 39 cc f1 14 05  |.Z.7C.tRn.<9....|
-000002d0  2d 91 c2 3d c4 7c 14 03  01 00 01 01 16 03 01 00  |-..=.|..........|
-000002e0  30 cd 3c 92 f8 b9 36 7a  e7 8a fb 0f 2f b8 2c 7b  |0.<...6z..../.,{|
-000002f0  10 59 45 14 0a b0 6a 8c  31 b2 89 5b ac 19 dc 12  |.YE...j.1..[....|
-00000300  73 8c 8c 10 49 5a bf 9f  bc 58 82 32 11 ba c5 38  |s...IZ...X.2...8|
-00000310  ff                                                |.|
+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 da 45 99 fe 52  |..........0.E..R|
-00000010  4f cd d0 e6 30 19 f4 bd  80 6d 5c 8a 72 03 d3 88  |O...0....m\.r...|
-00000020  38 63 e9 c9 39 ee ab 3f  52 26 84 b0 4d cb 5c a4  |8c..9..?R&..M.\.|
-00000030  0d 51 c7 47 48 43 3a bf  89 c7 13                 |.Q.GHC:....|
+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 4d d9 1d  0d 3d 8b 73 91 b9 4e 5e  |.... M...=.s..N^|
-00000010  35 71 4f 67 79 d2 f7 39  35 ea 23 d0 6d 64 de a5  |5qOgy..95.#.md..|
-00000020  59 fb 75 1f c9 17 03 01  00 20 ba bd 3c b4 d7 be  |Y.u...... ..<...|
-00000030  24 64 68 1e 8c b2 bf 6f  78 9f ad 7f fa dd 89 a6  |$dh....ox.......|
-00000040  f9 e7 5e 70 db e9 db 3a  62 b2 15 03 01 00 20 2a  |..^p...:b..... *|
-00000050  82 f4 8b 45 fc 76 35 6c  54 48 62 2f 52 55 f2 d9  |...E.v5lTHb/RU..|
-00000060  99 b2 b5 2d 5f a0 05 ab  f1 93 58 75 4a 87 35     |...-_.....XuJ.5|
+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/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-RSA b/src/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-RSA
index 9b1a553..94e6860 100644
--- a/src/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-RSA
+++ b/src/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-RSA
@@ -1,19 +1,18 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
+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 1e c0 2f  |.............../|
-00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
-00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 36  |...../.5.......6|
-00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
-00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0e 00  |................|
-00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
-00000080  01 00 00 12 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 90 e6 e1 c6 bd  |....Q...M.......|
-00000010  86 08 db 33 94 f3 bd 0b  2d fc e0 ba 89 a7 c5 66  |...3....-......f|
-00000020  a5 19 78 33 2b b9 c4 22  d8 e0 63 20 2e 85 53 25  |..x3+.."..c ..S%|
-00000030  f2 22 e3 ca 79 94 9e 50  00 13 da 9d 21 33 49 27  |."..y..P....!3I'|
-00000040  9b 44 c5 10 bc e8 44 01  04 31 02 81 00 05 00 00  |.D....D..1......|
+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..|
@@ -102,24 +101,24 @@
 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 10 19  57 14 c3 ee 2d da cb de  |........W...-...|
-000002a0  f3 70 c5 62 91 2f ad 62  dd 10 f1 65 20 a2 cf d5  |.p.b./.b...e ...|
-000002b0  cd 6d 5f e4 b3 3e 38 e8  d0 1a f7 f0 e7 7e b6 5d  |.m_..>8......~.]|
-000002c0  c3 6c ad f6 0d 05 1e 41  35 2d 04 15 3c 36 96 00  |.l.....A5-..<6..|
-000002d0  e8 02 b2 01 b8 9f 21 4b  34 85 ef 5e 4c 87 ef 49  |......!K4..^L..I|
-000002e0  df d1 9a b6 b2 bd b8 90  fd 3f 31 93 0c dc c7 18  |.........?1.....|
-000002f0  ff f6 76 bd 5b 74 76 b3  62 87 6a df ff 63 15 d5  |..v.[tv.b.j..c..|
-00000300  94 d5 fe fd 4c 12 df f1  35 07 f1 8a f1 77 7a 35  |....L...5....wz5|
-00000310  cd 99 1d 2a d7 9a 14 03  01 00 01 01 16 03 01 00  |...*............|
-00000320  24 8d db 0c 87 b5 df fd  68 de fe 46 3e e4 41 b5  |$.......h..F>.A.|
-00000330  19 64 68 3c c4 e2 2b 43  50 e4 ee 52 75 34 d3 c1  |.dh<..+CP..Ru4..|
-00000340  51 18 c0 b2 5f                                    |Q..._|
+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 0b a4 04 46 60  |..........$...F`|
-00000010  15 fb 9a 9f 47 51 6d b4  4b c6 e7 2a 1b 98 b4 8a  |....GQm.K..*....|
-00000020  8a 1a 03 cf f4 16 7d 80  70 27 e5 e8 d5 9f ad     |......}.p'.....|
+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 6f 84 50  27 c7 f1 aa b0 04 7d 80  |.....o.P'.....}.|
-00000010  6d a7 20 8a 73 cf d9 de  9a d6 f5 e9 36 13 7c 15  |m. .s.......6.|.|
-00000020  03 01 00 16 e8 0b e0 a6  3b 1e 21 24 65 4e 49 b2  |........;.!$eNI.|
-00000030  2d a3 41 2b 98 23 4e d5  4b fd                    |-.A+.#N.K.|
+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/crypto/tls/testdata/Client-TLSv10-ECDHE-ECDSA-AES b/src/crypto/tls/testdata/Client-TLSv10-ECDHE-ECDSA-AES
index 937c290..30c4c6b 100644
--- a/src/crypto/tls/testdata/Client-TLSv10-ECDHE-ECDSA-AES
+++ b/src/crypto/tls/testdata/Client-TLSv10-ECDHE-ECDSA-AES
@@ -1,19 +1,18 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
+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 1e c0 2f  |.............../|
-00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
-00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 36  |...../.5.......6|
-00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
-00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0e 00  |................|
-00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
-00000080  01 00 00 12 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 f5 8f 8d 8e ca  |....Y...U.......|
-00000010  30 6b fe 63 c9 84 57 c0  f1 c8 a5 d8 10 56 14 62  |0k.c..W......V.b|
-00000020  c8 02 b2 89 21 5c 09 67  86 d8 9b 20 dc 3f 55 54  |....!\.g... .?UT|
-00000030  33 29 47 45 d3 e0 87 1a  4b 1b 75 30 89 e0 4d 01  |3)GE....K.u0..M.|
-00000040  a1 6a 46 f7 8f 23 d6 74  fd 90 2f 53 c0 09 00 00  |.jF..#.t../S....|
+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....|
@@ -48,20 +47,20 @@
 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 22  |*............A."|
-00000280  8a 47 c6 d3 7a c4 30 a4  8e 41 11 ac b3 2d 2f 45  |.G..z.0..A...-/E|
-00000290  61 54 9b 1f 2e 03 5d 50  eb fc 5b 44 a0 a7 48 78  |aT....]P..[D..Hx|
-000002a0  ce 14 d5 39 a7 c4 ed f5  4d 8f da 9d 71 52 69 70  |...9....M...qRip|
-000002b0  7e 52 29 ad 80 8a 19 ad  4c 5d 1c f1 22 7e 1a 00  |~R).....L].."~..|
-000002c0  8a 30 81 87 02 42 00 97  8b 6d f7 87 c1 a9 a6 55  |.0...B...m.....U|
-000002d0  0f 61 c2 f2 e1 05 26 a8  83 16 1c 0b 69 3b 95 57  |.a....&.....i;.W|
-000002e0  76 5b eb 45 7a bd 6a f1  3e a0 93 49 fa 74 32 fd  |v[.Ez.j.>..I.t2.|
-000002f0  dc 20 3a bb e3 ee 6d b8  56 aa e9 d2 7d 6a ec b7  |. :...m.V...}j..|
-00000300  0a bd aa dc d7 b0 69 65  02 41 4d 19 61 16 d8 5f  |......ie.AM.a.._|
-00000310  1d c1 32 25 15 26 eb 88  5b c1 dd 9a 12 40 fa f1  |..2%.&..[.... at ..|
-00000320  81 5e 7d b8 2b 6e 60 63  1a 9e 86 cb d5 64 96 d4  |.^}.+n`c.....d..|
-00000330  75 fc 02 33 e0 66 60 b2  40 47 cf e6 6d 25 9c 83  |u..3.f`. at G..m%..|
-00000340  23 d3 4b e2 eb ac f1 56  44 f8 3f 16 03 01 00 04  |#.K....VD.?.....|
+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..|
@@ -69,20 +68,20 @@
 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 cc 86  f1 7e 6e a8 c9 b5 02 5f  |.....0...~n...._|
-00000060  fb b2 3b ea 74 bf a8 da  e4 6a 69 50 a2 5a 78 4f  |..;.t....jiP.ZxO|
-00000070  35 e1 cc 87 c3 fb 1f 5e  f6 a4 5c 63 cc 59 12 3e  |5......^..\c.Y.>|
-00000080  07 c3 a8 d7 87 ba                                 |......|
+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 e8 b6 20 b9 c1  |..........0.. ..|
-00000010  07 38 38 bb 42 b2 b2 a1  c5 8d 92 62 db 67 ab fc  |.88.B......b.g..|
-00000020  f6 64 3f 71 83 1d a0 86  bb 2d e3 4f 65 d5 44 52  |.d?q.....-.Oe.DR|
-00000030  4d f5 62 80 3c af 95 87  19 7c 20                 |M.b.<....| |
+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 bd 65 61  28 e5 ea 1b 81 db 75 92  |.... .ea(.....u.|
-00000010  ad a7 3b 01 a3 23 0e 3b  60 10 8a 1e 04 91 fb 9e  |..;..#.;`.......|
-00000020  7a cf 1f cf 9c 17 03 01  00 20 87 9c dc ed 0d 08  |z........ ......|
-00000030  56 40 23 8b c5 2c d8 7e  42 82 3c 0a c9 f3 77 6d  |V@#..,.~B.<...wm|
-00000040  8d 9a 30 d1 9c c4 ae 04  fb b7 15 03 01 00 20 f7  |..0........... .|
-00000050  f0 12 0d e5 03 c1 80 4e  7e 21 d7 75 55 1c 91 89  |.......N~!.uU...|
-00000060  e7 e1 45 fc 7d d8 fc b1  d0 e7 dc e2 4c ba f4     |..E.}.......L..|
+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/crypto/tls/testdata/Client-TLSv10-ECDHE-RSA-AES b/src/crypto/tls/testdata/Client-TLSv10-ECDHE-RSA-AES
index f8183f1..868f0ce 100644
--- a/src/crypto/tls/testdata/Client-TLSv10-ECDHE-RSA-AES
+++ b/src/crypto/tls/testdata/Client-TLSv10-ECDHE-RSA-AES
@@ -1,19 +1,18 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
+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 1e c0 2f  |.............../|
-00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
-00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 36  |...../.5.......6|
-00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
-00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0e 00  |................|
-00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
-00000080  01 00 00 12 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 5c 69 d0 60 d6  |....Y...U..\i.`.|
-00000010  b3 f4 23 19 5e 3e 26 d8  29 ea c3 94 e4 ed 51 f6  |..#.^>&.).....Q.|
-00000020  58 a2 e3 9c 79 a1 0b 6d  29 90 32 20 23 5b 47 b1  |X...y..m).2 #[G.|
-00000030  8f 22 bc 06 aa ee f7 c3  97 ca 93 df b1 90 7d b4  |."............}.|
-00000040  8c c0 d9 54 35 ca 5b 11  98 37 84 ea c0 13 00 00  |...T5.[..7......|
+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..............|
@@ -59,40 +58,40 @@
 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 a6  |.............A..|
-00000330  57 60 8d 63 4e 4d 3f 48  e0 5d ad 9a 9c f7 e6 8c  |W`.cNM?H.]......|
-00000340  00 18 9c eb 34 ea f0 5c  d5 77 3f af 81 a9 50 d9  |....4..\.w?...P.|
-00000350  05 cf b9 bf 88 5c 70 29  24 61 6f d8 77 11 21 57  |.....\p)$ao.w.!W|
-00000360  a0 4d e1 4b 8e 55 06 50  7f a2 30 c1 c2 b9 c6 00  |.M.K.U.P..0.....|
-00000370  80 68 7c e4 1a bc a4 1e  16 b9 3e 4a 59 39 a9 54  |.h|.......>JY9.T|
-00000380  6f c7 17 b2 f5 af b5 73  5b db cc 71 f2 1b aa dc  |o......s[..q....|
-00000390  9d 64 3c 0f 82 e6 da 1a  6b 96 19 e2 f0 15 b0 df  |.d<.....k.......|
-000003a0  8a 2d 96 09 63 52 f6 53  ef 12 d4 3b 35 b7 0b 43  |.-..cR.S...;5..C|
-000003b0  2c 6e 58 4c c8 2f b8 55  84 89 c9 39 81 7a 7a 7d  |,nXL./.U...9.zz}|
-000003c0  88 68 db eb d7 81 aa 2e  b2 25 ba 98 6c 46 b7 85  |.h.......%..lF..|
-000003d0  8a 21 17 b9 36 23 c0 84  94 af 3b 9b 04 5d ec 31  |.!..6#....;..].1|
-000003e0  f5 75 84 d8 77 d7 80 37  ae c3 5c 26 41 f6 72 af  |.u..w..7..\&A.r.|
-000003f0  88 16 03 01 00 04 0e 00  00 00                    |..........|
+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 d2 5b  27 5a f5 64 49 31 d5 aa  |.....0.['Z.dI1..|
-00000060  a3 72 ae c9 af 0b aa 75  af ac f3 45 f4 e3 03 fa  |.r.....u...E....|
-00000070  e8 97 88 7b 51 a9 ae 61  40 c8 11 74 3e d8 9a b6  |...{Q..a at ..t>...|
-00000080  e7 6a 5e 71 84 7e                                 |.j^q.~|
+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 8d 63 fc 58 2e  |..........0.c.X.|
-00000010  50 f7 60 2c 9f 5a 8e 58  29 6c a6 3a 8d 2b a7 2b  |P.`,.Z.X)l.:.+.+|
-00000020  1c 12 8a 53 3f d5 60 79  12 c3 78 e3 aa 50 15 45  |...S?.`y..x..P.E|
-00000030  07 da 2d c7 a9 c3 45 07  48 00 78                 |..-...E.H.x|
+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 40 91 8d  e6 95 2f 97 c8 0c 94 5c  |.... @..../....\|
-00000010  46 a7 d3 31 82 3d dc 7e  86 5b dd df 3f 3b 5b 9c  |F..1.=.~.[..?;[.|
-00000020  d5 0d 52 5a 53 17 03 01  00 20 1d 18 da 6b e8 66  |..RZS.... ...k.f|
-00000030  ce 58 18 81 4b 69 8c f6  db 1a ee d0 78 fb f5 68  |.X..Ki......x..h|
-00000040  2c 99 48 47 65 15 2a ae  ff 4e 15 03 01 00 20 68  |,.HGe.*..N.... h|
-00000050  aa 7f 75 33 45 7a 1a 33  18 35 5a 5b 14 b0 f6 83  |..u3Ez.3.5Z[....|
-00000060  97 85 3f b2 dc 78 68 eb  43 ef 92 7f 38 bd f8     |..?..xh.C...8..|
+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/crypto/tls/testdata/Client-TLSv10-RSA-RC4 b/src/crypto/tls/testdata/Client-TLSv10-RSA-RC4
index b5deaeb..395d53b 100644
--- a/src/crypto/tls/testdata/Client-TLSv10-RSA-RC4
+++ b/src/crypto/tls/testdata/Client-TLSv10-RSA-RC4
@@ -1,19 +1,18 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
+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 1e c0 2f  |.............../|
-00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
-00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 36  |...../.5.......6|
-00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
-00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0e 00  |................|
-00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
-00000080  01 00 00 12 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 a9 b0 bf 24 3f  |....Q...M.....$?|
-00000010  98 c6 0f 83 23 2b b6 e4  3f d5 5b 10 9a 6f b8 63  |....#+..?.[..o.c|
-00000020  4c 3c d6 4d 05 c0 08 85  f7 72 72 20 ab 85 8c ff  |L<.M.....rr ....|
-00000030  f7 bb 95 ab 69 37 3d b6  79 cb 46 ad 4e 22 e7 c6  |....i7=.y.F.N"..|
-00000040  a5 9b 72 92 32 ff a5 f7  ed dc 30 41 00 05 00 00  |..r.2.....0A....|
+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..|
@@ -70,15 +69,15 @@
 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 4d 1d  d7 8c d6 c7 65 a6 ce af  |.....$M.....e...|
-000000a0  e7 59 0d 7e dc d9 96 1c  ed 9c 57 94 84 b8 3f b5  |.Y.~......W...?.|
-000000b0  34 e1 61 a5 61 f3 5d 09  bc ff                    |4.a.a.]...|
+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 13 81 89 61 5c  |..........$...a\|
-00000010  fb 0a 9c a1 4b db 94 6b  8b 41 6e 63 d6 aa db 88  |....K..k.Anc....|
-00000020  03 b7 b5 19 b8 12 cf 5e  17 54 79 2f 03 91 7e     |.......^.Ty/..~|
+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 b3 2b da  ce 45 ec b2 9d 3b 18 d9  |......+..E...;..|
-00000010  7a cb 99 ea ff 4d 91 b5  48 df 6f 8b 2f 85 c7 15  |z....M..H.o./...|
-00000020  03 01 00 16 19 1c 72 74  36 cf 22 0f a0 a7 18 96  |......rt6.".....|
-00000030  3a 67 cb 22 16 f1 a8 7b  57 37                    |:g."...{W7|
+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/crypto/tls/testdata/Client-TLSv11-ECDHE-ECDSA-AES b/src/crypto/tls/testdata/Client-TLSv11-ECDHE-ECDSA-AES
index a4a2930..9f941f8 100644
--- a/src/crypto/tls/testdata/Client-TLSv11-ECDHE-ECDSA-AES
+++ b/src/crypto/tls/testdata/Client-TLSv11-ECDHE-ECDSA-AES
@@ -1,19 +1,18 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
+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 1e c0 2f  |.............../|
-00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
-00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 36  |...../.5.......6|
-00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
-00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0e 00  |................|
-00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
-00000080  01 00 00 12 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 5a 52 92 23 05  |....Y...U..ZR.#.|
-00000010  58 68 b2 1e 77 a2 a8 16  e9 88 85 ea 38 b3 63 c2  |Xh..w.......8.c.|
-00000020  40 f8 de 37 3c d4 b9 51  11 2d d1 20 12 fd 95 b3  |@..7<..Q.-. ....|
-00000030  2a 54 40 c0 23 3a 4e 4e  f6 7b f8 77 04 6e e7 d7  |*T at .#:NN.{.w.n..|
-00000040  3b 9a 45 32 e0 af df aa  ff bf 78 8b c0 09 00 00  |;.E2......x.....|
+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....|
@@ -48,21 +47,21 @@
 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 d5 0c 00  00 d1 03 00 17 41 04 c3  |*............A..|
-00000280  55 86 65 95 83 02 4b 69  6e 95 f4 52 46 83 21 86  |U.e...Kin..RF.!.|
-00000290  9e 99 cf 81 d9 b8 20 7a  87 b3 07 48 14 04 20 d9  |...... z...H.. .|
-000002a0  6c 2e 22 5a b5 b4 ef de  15 b3 08 ef 1e 18 ea 67  |l."Z...........g|
-000002b0  eb 45 fd e1 27 43 ed 41  ea 05 7e f3 f9 ee 23 00  |.E..'C.A..~...#.|
-000002c0  8a 30 81 87 02 42 00 b0  9c 06 85 83 b2 bf 42 22  |.0...B........B"|
-000002d0  6e 57 7a 31 fe a9 d9 28  be 0a a9 80 49 a2 14 c1  |nWz1...(....I...|
-000002e0  a9 99 76 b7 f9 76 d0 3c  d3 0c c7 42 34 d7 94 a9  |..v..v.<...B4...|
-000002f0  15 66 7e 6b 83 6e b2 b4  5b 22 c9 4e a0 96 db 2b  |.f~k.n..[".N...+|
-00000300  ad 77 33 1e 4a 5c 2f 2e  02 41 26 0c 1a 5a b4 07  |.w3.J\/..A&..Z..|
-00000310  95 99 ec 0b 5b 2e bb db  0e d5 26 c4 b3 eb c2 30  |....[.....&....0|
-00000320  b0 7b c1 07 97 a0 99 3f  db 4e b0 c4 b8 bb 5e be  |.{.....?.N....^.|
-00000330  2a e4 b3 a4 5c ad d1 d7  7a 2d fb ae 73 ee 0c 1e  |*...\...z-..s...|
-00000340  3b 64 e1 74 14 bc c0 1e  8b f3 26 16 03 02 00 04  |;d.t......&.....|
-00000350  0e 00 00 00                                       |....|
+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.|
@@ -70,21 +69,21 @@
 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 33 07  8a af e1 94 ef f9 08 3a  |......3........:|
-00000070  33 5f b3 e6 42 07 85 af  40 e2 8b 34 53 62 1a 10  |3_..B... at ..4Sb..|
-00000080  bb 08 7e 75 d4 21 12 2d  54 87 33 1c 4e 13 27 72  |..~u.!.-T.3.N.'r|
-00000090  3f 9e 9f cc de 47                                 |?....G|
+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 4f 47 0d 43 54  |.......... at OG.CT|
-00000010  50 69 3a c8 21 a6 6e 28  78 cc 01 b4 5d eb f7 2b  |Pi:.!.n(x...]..+|
-00000020  8b 7e 26 6e cf 56 98 65  ad bf 0f a0 b4 67 13 70  |.~&n.V.e.....g.p|
-00000030  de b5 b5 91 df d6 df 8c  53 c6 54 3d 5d 98 e4 25  |........S.T=]..%|
-00000040  47 a0 0f 91 c7 08 96 17  48 bd 0f                 |G.......H..|
+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 4e fe 12  d7 4b d7 3f 86 5a 2c f6  |.....N...K.?.Z,.|
-00000020  86 03 2a bd 1a 98 d7 bb  9f 59 6c 6d 4d 57 b0 50  |..*......YlmMW.P|
-00000030  d6 97 7e d4 b6 15 03 02  00 30 00 00 00 00 00 00  |..~......0......|
-00000040  00 00 00 00 00 00 00 00  00 00 65 8b b5 ae 86 90  |..........e.....|
-00000050  00 4e 1e 3f bc ac ed 49  f4 5e 73 49 e6 d8 37 83  |.N.?...I.^sI..7.|
-00000060  cf 4f e5 7b 5e c9 1d c8  c9 dc                    |.O.{^.....|
+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/crypto/tls/testdata/Client-TLSv11-ECDHE-RSA-AES b/src/crypto/tls/testdata/Client-TLSv11-ECDHE-RSA-AES
index 103f1d8..fc72339 100644
--- a/src/crypto/tls/testdata/Client-TLSv11-ECDHE-RSA-AES
+++ b/src/crypto/tls/testdata/Client-TLSv11-ECDHE-RSA-AES
@@ -1,19 +1,18 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
+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 1e c0 2f  |.............../|
-00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
-00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 36  |...../.5.......6|
-00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
-00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0e 00  |................|
-00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
-00000080  01 00 00 12 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 e3 ed 49 27 a3  |....Y...U....I'.|
-00000010  28 c5 8c 30 27 c2 ed 57  9b f7 37 a1 6d 2b 88 c2  |(..0'..W..7.m+..|
-00000020  df a7 2d 01 01 00 9a 09  da c2 1f 20 ee 33 87 03  |..-........ .3..|
-00000030  28 93 1c 16 99 5b b1 e0  bf 87 e8 77 4a 72 c9 92  |(....[.....wJr..|
-00000040  8a bc b2 3e 24 e1 f6 e8  f4 3f a2 24 c0 13 00 00  |...>$....?.$....|
+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..............|
@@ -59,20 +58,20 @@
 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 f7  |.............A..|
-00000330  75 c1 b9 58 a0 7d 50 48  e9 85 79 db 89 76 4c d7  |u..X.}PH..y..vL.|
-00000340  84 5b 94 9a 15 d8 92 32  74 d2 3e ce 76 5a bd 0e  |.[.....2t.>.vZ..|
-00000350  24 e7 a6 d0 77 5d 8e 3d  9f 94 7a ea 15 46 3c 5c  |$...w].=..z..F<\|
-00000360  61 28 76 4a ff 81 97 2b  3a 0c b7 aa b4 0e cb 00  |a(vJ...+:.......|
-00000370  80 19 00 a8 fe 0a ea 35  30 51 a3 77 37 08 68 10  |.......50Q.w7.h.|
-00000380  5a e9 07 2d 83 67 77 4c  3a 25 14 1c 5b c1 2e 80  |Z..-.gwL:%..[...|
-00000390  30 6d ba 26 c1 f9 c6 3e  fc 55 34 8c d2 9f 2b a6  |0m.&...>.U4...+.|
-000003a0  46 0c 9d 58 2c 9c 2b ce  6f 03 d7 49 4e df 21 ce  |F..X,.+.o..IN.!.|
-000003b0  3f 8b 19 fe 3e 71 23 51  c3 ec 30 c8 3e 3c 3c 50  |?...>q#Q..0.><<P|
-000003c0  da 08 52 c0 10 9f e3 4a  be e0 97 aa de 5e 13 22  |..R....J.....^."|
-000003d0  b2 77 ee 5d 2d d4 ff fb  7f c3 1e e7 51 fe fc 4b  |.w.]-.......Q..K|
-000003e0  56 5b 8f 50 ad cc 34 7a  a9 dd 24 0a d0 c7 b9 bf  |V[.P..4z..$.....|
-000003f0  1a 16 03 02 00 04 0e 00  00 00                    |..........|
+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.|
@@ -80,21 +79,21 @@
 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 1e 0b  cd 40 fa 0f ed fa 55 74  |......... at ....Ut|
-00000070  4e ad 10 d1 b5 e1 41 8c  c0 93 81 38 f3 83 f1 37  |N.....A....8...7|
-00000080  6a d4 6c ea ba 5b 9e 38  d3 c1 bb 41 45 fb f0 48  |j.l..[.8...AE..H|
-00000090  c1 06 31 64 e0 65                                 |..1d.e|
+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 17 d1 79 f8 e0  |.......... at ..y..|
-00000010  d4 40 15 85 df 4d a6 d5  60 90 1f d6 52 58 e7 ae  |. at ...M..`...RX..|
-00000020  05 eb a2 ea ed c9 be ae  b5 54 39 de 05 66 27 67  |.........T9..f'g|
-00000030  59 07 03 e7 10 f9 3f da  d8 85 8b 2f 7b 33 9f f5  |Y.....?..../{3..|
-00000040  43 50 b9 9c 6e dd 01 ae  d8 c9 1d                 |CP..n......|
+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 65 81 63  71 55 1c 46 8a 60 46 d9  |.....e.cqU.F.`F.|
-00000020  7d 71 a2 62 b8 a8 3b 06  3d a2 f4 53 a4 46 a8 9e  |}q.b..;.=..S.F..|
-00000030  b7 89 8a 42 ce 15 03 02  00 30 00 00 00 00 00 00  |...B.....0......|
-00000040  00 00 00 00 00 00 00 00  00 00 7a 78 a4 e7 2f 40  |..........zx../@|
-00000050  df 42 9b 76 7a 45 0a 86  40 af 3c 40 c6 69 ba e1  |.B.vzE.. at .<@.i..|
-00000060  23 82 fa 44 fd 73 fc 5b  f7 b9                    |#..D.s.[..|
+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/crypto/tls/testdata/Client-TLSv11-RSA-RC4 b/src/crypto/tls/testdata/Client-TLSv11-RSA-RC4
index 729391f..f7be3f7 100644
--- a/src/crypto/tls/testdata/Client-TLSv11-RSA-RC4
+++ b/src/crypto/tls/testdata/Client-TLSv11-RSA-RC4
@@ -1,19 +1,18 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
+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 1e c0 2f  |.............../|
-00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
-00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 36  |...../.5.......6|
-00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
-00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0e 00  |................|
-00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
-00000080  01 00 00 12 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 7e 38 ae 3c 50  |....Q...M..~8.<P|
-00000010  03 96 3d 54 2f cd 86 21  98 7f 87 43 d8 58 aa a3  |..=T/..!...C.X..|
-00000020  d5 9f e7 25 a6 ab 34 7f  10 5f 99 20 56 c5 a8 dd  |...%..4.._. V...|
-00000030  37 17 0d 51 f1 0d c4 4e  76 0f 01 26 56 c9 0c 20  |7..Q...Nv..&V.. |
-00000040  28 ef cd ac 38 ea d3 7f  6f aa 7c b8 00 05 00 00  |(...8...o.|.....|
+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..|
@@ -70,15 +69,15 @@
 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 b9 df  85 a1 6d a7 14 b5 bc f5  |.....$....m.....|
-000000a0  c2 1d 40 fc 1e 19 f2 36  2d ec 6b 59 c5 6d ae c7  |.. at ....6-.kY.m..|
-000000b0  1c ad 7e a3 5b 4d 12 e5  58 5a                    |..~.[M..XZ|
+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 a3 f3 22 a8 32  |..........$..".2|
-00000010  63 c3 88 5c 0f fb 2d 47  21 0d 62 e2 db aa ed ae  |c..\..-G!.b.....|
-00000020  b6 5f e3 c8 98 fc 91 5e  04 83 cf c3 21 17 ce     |._.....^....!..|
+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 f1 e4 46  c7 14 91 4b c6 25 fd aa  |.......F...K.%..|
-00000010  5d dd 3f 61 ac 9c 79 68  bc e6 0f a1 e4 f3 73 15  |].?a..yh......s.|
-00000020  03 02 00 16 6b 8d 23 3c  99 b4 c2 23 3c 27 fd 41  |....k.#<...#<'.A|
-00000030  cc 04 e5 fc e7 f9 d9 81  0a b8                    |..........|
+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/crypto/tls/testdata/Client-TLSv12-ALPN b/src/crypto/tls/testdata/Client-TLSv12-ALPN
index 9ecb065..f09a4f1 100644
--- a/src/crypto/tls/testdata/Client-TLSv12-ALPN
+++ b/src/crypto/tls/testdata/Client-TLSv12-ALPN
@@ -1,20 +1,20 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 99 01 00 00  95 03 03 00 00 00 00 00  |................|
+00000000  16 03 01 00 8d 01 00 00  89 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 00 1e c0 2f  |.............../|
-00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
-00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 4e  |...../.5.......N|
-00000050  33 74 00 00 00 05 00 05  01 00 00 00 00 00 0a 00  |3t..............|
-00000060  08 00 06 00 17 00 18 00  19 00 0b 00 02 01 00 00  |................|
-00000070  0d 00 0e 00 0c 04 01 04  03 05 01 05 03 02 01 02  |................|
-00000080  03 ff 01 00 01 00 00 10  00 10 00 0e 06 70 72 6f  |.............pro|
-00000090  74 6f 32 06 70 72 6f 74  6f 31 00 12 00 00        |to2.proto1....|
+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 46 33 74 00 00  |./.5.......F3t..|
+00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
+00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0a 00  |................|
+00000070  08 04 01 04 03 02 01 02  03 ff 01 00 01 00 00 10  |................|
+00000080  00 10 00 0e 06 70 72 6f  74 6f 32 06 70 72 6f 74  |.....proto2.prot|
+00000090  6f 31                                             |o1|
 >>> Flow 2 (server to client)
-00000000  16 03 03 00 66 02 00 00  62 03 03 56 83 34 0f 9e  |....f...b..V.4..|
-00000010  dd 02 1c 4f 4f 09 d0 2c  df e6 c1 d2 4a c0 6a e7  |...OO..,....J.j.|
-00000020  1e 65 51 c2 42 01 05 70  4a 6c 97 20 0f a8 fb d8  |.eQ.B..pJl. ....|
-00000030  2f 0f 75 21 17 f8 dd 63  28 4a 18 f6 b1 e5 6f 7c  |/.u!...c(J....o||
-00000040  1d 09 d4 13 bf 66 3a bd  c5 48 14 fc c0 2f 00 00  |.....f:..H.../..|
+00000000  16 03 03 00 66 02 00 00  62 03 03 77 a9 7d 9c 4b  |....f...b..w.}.K|
+00000010  69 65 aa dc 95 cb 78 08  3d d2 1a 0a 45 69 23 73  |ie....x.=...Ei#s|
+00000020  4f 41 4f 24 12 2e 57 47  b7 53 64 20 82 9a f8 e7  |OAO$..WG.Sd ....|
+00000030  79 f8 13 2c 9d cd b5 cb  cb 9a 95 56 0e e9 cb a8  |y..,.......V....|
+00000040  e4 a2 8a d6 bc dc fa 25  b3 57 cc cf c0 2f 00 00  |.......%.W.../..|
 00000050  1a ff 01 00 01 00 00 0b  00 04 03 00 01 02 00 10  |................|
 00000060  00 09 00 07 06 70 72 6f  74 6f 31 16 03 03 02 be  |.....proto1.....|
 00000070  0b 00 02 ba 00 02 b7 00  02 b4 30 82 02 b0 30 82  |..........0...0.|
@@ -61,19 +61,19 @@
 00000300  b6 d8 c9 75 90 96 8c 0f  52 98 b5 cd 98 1f 89 20  |...u....R...... |
 00000310  5f f2 a0 1c a3 1b 96 94  dd a9 fd 57 e9 70 e8 26  |_..........W.p.&|
 00000320  6d 71 99 9b 26 6e 38 50  29 6c 90 a7 bd d9 16 03  |mq..&n8P)l......|
-00000330  03 00 cd 0c 00 00 c9 03  00 17 41 04 85 b7 f7 7c  |..........A....||
-00000340  49 4e 97 14 07 51 bc 56  2d 3f cf 1d 29 08 ac 6a  |IN...Q.V-?..)..j|
-00000350  b4 e7 0d 62 d8 fd 4d 03  29 0d f8 6c 36 6f 4d 5f  |...b..M.)..l6oM_|
-00000360  b7 5a 8e 37 3e c2 d9 dc  f4 15 52 e9 87 71 0f e5  |.Z.7>.....R..q..|
-00000370  4e a6 88 0e 54 35 e0 8b  50 91 e1 c4 04 01 00 80  |N...T5..P.......|
-00000380  51 eb f8 d6 52 ba f5 b5  0a 22 5f 91 fe f7 ee 43  |Q...R...."_....C|
-00000390  f8 af 52 b6 27 2c fc 14  e2 fb 41 61 ff 7c b9 be  |..R.',....Aa.|..|
-000003a0  f9 78 be dc 18 32 8c 4d  ef 46 c0 5a a7 91 6a 1b  |.x...2.M.F.Z..j.|
-000003b0  47 78 46 39 47 81 8a 2d  b4 cb fd bb 44 3e a7 b7  |GxF9G..-....D>..|
-000003c0  cc 4e df 17 7b 2b 38 49  fa 9d 9f 4e cd ed f2 16  |.N..{+8I...N....|
-000003d0  03 d9 68 cf c9 5a 08 32  f8 ed 02 30 54 61 f6 c0  |..h..Z.2...0Ta..|
-000003e0  f6 78 bc ad 04 9c 8e 90  7d 3d f5 35 86 aa 6e e9  |.x......}=.5..n.|
-000003f0  a2 9a d3 86 27 9f 2d 6e  ea 6e ad 82 0e aa ef 97  |....'.-n.n......|
+00000330  03 00 cd 0c 00 00 c9 03  00 17 41 04 1b 42 c3 ae  |..........A..B..|
+00000340  44 19 d3 84 7c 6c 98 cb  b9 22 a2 67 63 95 aa cc  |D...|l...".gc...|
+00000350  bd e4 1e f8 08 e6 60 f3  bc 83 9f 81 da 9c 1c 8c  |......`.........|
+00000360  ff 6f f4 3e 1e e5 3b f6  49 61 f9 70 43 7f c1 69  |.o.>..;.Ia.pC..i|
+00000370  de 73 98 4b bd 5c c3 78  24 18 a8 ec 04 01 00 80  |.s.K.\.x$.......|
+00000380  70 d2 5b e1 39 cf 4d 54  de d2 74 4e 5e a8 b3 ca  |p.[.9.MT..tN^...|
+00000390  e1 f2 4e 76 3c 77 8b ef  f7 d1 df b9 ad c1 70 39  |..Nv<w........p9|
+000003a0  c7 a3 1e 0f 7b 6c 78 2e  c1 86 d2 67 36 d8 25 e0  |....{lx....g6.%.|
+000003b0  e8 e5 cc 35 a2 96 a1 b4  b7 06 68 1e aa c7 06 97  |...5......h.....|
+000003c0  b7 c2 83 ce c0 17 dd 4f  9e 6f 7a bd cd c7 6e 7f  |.......O.oz...n.|
+000003d0  cb 80 d1 7d 06 2d f9 f1  fb 5f cc bb d8 62 5b f0  |...}.-..._...b[.|
+000003e0  27 12 57 d5 9b 55 aa 55  4b 9a 5a f6 a5 aa c1 82  |'.W..U.UK.Z.....|
+000003f0  39 11 6b dc 83 7f a8 47  28 5a 0f 3d 3f 0f c2 22  |9.k....G(Z.=?.."|
 00000400  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..|
@@ -81,17 +81,17 @@
 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 47 18  |.....(........G.|
-00000060  39 03 93 d9 5b 27 29 70  52 68 15 79 f2 60 e6 58  |9...[')pRh.y.`.X|
-00000070  d9 98 cd ce a1 8f 4d ee  2c f0 34 9f fa 73        |......M.,.4..s|
+00000050  01 16 03 03 00 28 00 00  00 00 00 00 00 00 35 9d  |.....(........5.|
+00000060  92 e8 bf df 7f a7 77 1b  cf 03 2a bf e2 6c 62 2b  |......w...*..lb+|
+00000070  26 f0 fb 93 d3 df fd 55  84 d3 ed 88 31 cb        |&......U....1.|
 >>> Flow 4 (server to client)
-00000000  14 03 03 00 01 01 16 03  03 00 28 39 76 15 70 f1  |..........(9v.p.|
-00000010  73 c9 9a 1e 76 40 bc de  de 49 be 3e 10 4d 6a 42  |s...v at ...I.>.MjB|
-00000020  1b 9b bd 07 6b 19 ff f9  2c 19 3c c8 e7 06 fa c8  |....k...,.<.....|
-00000030  3d 52 b4                                          |=R.|
+00000000  14 03 03 00 01 01 16 03  03 00 28 c8 c0 78 09 73  |..........(..x.s|
+00000010  58 41 73 66 88 cf db f3  fe c6 57 ab 45 be 2e d8  |XAsf......W.E...|
+00000020  4e e5 ff 42 57 13 74 d2  cc c2 62 07 39 8b 06 46  |N..BW.t...b.9..F|
+00000030  1d 8f 88                                          |...|
 >>> Flow 5 (client to server)
-00000000  17 03 03 00 1e 00 00 00  00 00 00 00 01 14 96 ec  |................|
-00000010  f4 bb ae 45 81 0c 39 10  e2 3a 91 51 04 2c 01 a8  |...E..9..:.Q.,..|
-00000020  8b a3 25 15 03 03 00 1a  00 00 00 00 00 00 00 02  |..%.............|
-00000030  fe 1a 53 01 17 ad a1 30  0a 73 17 9f 39 b4 30 ac  |..S....0.s..9.0.|
-00000040  91 ee                                             |..|
+00000000  17 03 03 00 1e 00 00 00  00 00 00 00 01 10 c3 5f  |..............._|
+00000010  3f c8 92 6c 7a a7 23 05  f3 d8 31 20 01 52 f1 99  |?..lz.#...1 .R..|
+00000020  33 c1 2a 15 03 03 00 1a  00 00 00 00 00 00 00 02  |3.*.............|
+00000030  cc ef eb 78 e4 e1 9d 90  05 6d 95 ac f2 49 ba 8e  |...x.....m...I..|
+00000040  6b 8d                                             |k.|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-ALPN-NoMatch b/src/crypto/tls/testdata/Client-TLSv12-ALPN-NoMatch
index a22ffae..f24a70c 100644
--- a/src/crypto/tls/testdata/Client-TLSv12-ALPN-NoMatch
+++ b/src/crypto/tls/testdata/Client-TLSv12-ALPN-NoMatch
@@ -1,20 +1,19 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 92 01 00 00  8e 03 03 00 00 00 00 00  |................|
+00000000  16 03 01 00 86 01 00 00  82 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 00 1e c0 2f  |.............../|
-00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
-00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 47  |...../.5.......G|
-00000050  33 74 00 00 00 05 00 05  01 00 00 00 00 00 0a 00  |3t..............|
-00000060  08 00 06 00 17 00 18 00  19 00 0b 00 02 01 00 00  |................|
-00000070  0d 00 0e 00 0c 04 01 04  03 05 01 05 03 02 01 02  |................|
-00000080  03 ff 01 00 01 00 00 10  00 09 00 07 06 70 72 6f  |.............pro|
-00000090  74 6f 33 00 12 00 00                              |to3....|
+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 3f 33 74 00 00  |./.5.......?3t..|
+00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
+00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0a 00  |................|
+00000070  08 04 01 04 03 02 01 02  03 ff 01 00 01 00 00 10  |................|
+00000080  00 09 00 07 06 70 72 6f  74 6f 33                 |.....proto3|
 >>> Flow 2 (server to client)
-00000000  16 03 03 00 59 02 00 00  55 03 03 94 d7 79 73 82  |....Y...U....ys.|
-00000010  87 7c 85 6e 8a 1b 7d bf  69 c9 98 0c 44 bd f6 78  |.|.n..}.i...D..x|
-00000020  d2 80 dc d8 7d 80 bb 91  4b d4 ed 20 fe 9f 2f 7b  |....}...K.. ../{|
-00000030  f2 1a 44 36 cd ce af f1  b5 01 8a ac 18 e4 2b 23  |..D6..........+#|
-00000040  a8 ab 1a 32 23 8b 0b e2  81 a8 0a 40 c0 2f 00 00  |...2#...... at ./..|
+00000000  16 03 03 00 59 02 00 00  55 03 03 69 84 d1 d3 44  |....Y...U..i...D|
+00000010  e9 66 08 48 bc 70 d8 ae  40 0b 17 69 e7 27 f6 7a  |.f.H.p.. at ..i.'.z|
+00000020  d5 ee 86 74 54 9e a8 bb  79 76 89 20 57 53 1b 02  |...tT...yv. WS..|
+00000030  5b 70 81 a6 f1 53 bc 9d  b7 42 5e ac 92 93 b5 20  |[p...S...B^.... |
+00000040  8a bb 36 cc 8f cb 7e a0  61 a2 e8 ef c0 2f 00 00  |..6...~.a..../..|
 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..............|
@@ -60,37 +59,37 @@
 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 7d  |.............A.}|
-00000330  75 a5 53 0b a5 4d a6 81  e0 df c4 11 c9 b5 31 ba  |u.S..M........1.|
-00000340  9f 7b 51 04 57 c6 e0 b9  b0 bc 4f bc 71 74 8a 2e  |.{Q.W.....O.qt..|
-00000350  d1 f6 39 36 94 4e c7 d3  a7 1b 2c b5 55 04 71 01  |..96.N....,.U.q.|
-00000360  9e 2b 42 1e 8b a4 40 b2  13 4f 03 1f 51 9e 5c 04  |.+B... at ..O..Q.\.|
-00000370  01 00 80 68 05 c7 4a ca  df 00 85 2b 53 f7 4f c3  |...h..J....+S.O.|
-00000380  b4 0f e8 f7 b8 30 b7 36  56 65 7b 03 6a 72 f1 aa  |.....0.6Ve{.jr..|
-00000390  54 30 90 9e c7 dc fc 03  96 15 70 67 13 12 a4 f4  |T0........pg....|
-000003a0  42 f0 f9 a1 48 c0 44 44  77 0e ea fd cb b5 6e 19  |B...H.DDw.....n.|
-000003b0  89 94 a7 12 67 87 47 19  c3 00 2d c4 9b d4 dc 66  |....g.G...-....f|
-000003c0  fa ca d7 97 79 9b 28 7f  74 d4 37 c0 06 63 d4 9e  |....y.(.t.7..c..|
-000003d0  a1 53 16 5a 8e d7 a5 cc  90 4d 63 f9 0c 18 85 7f  |.S.Z.....Mc.....|
-000003e0  0e 35 3a 49 73 88 82 51  41 e5 2d 58 aa 38 3e bd  |.5:Is..QA.-X.8>.|
-000003f0  3d d8 da 16 03 03 00 04  0e 00 00 00              |=...........|
+00000320  d9 16 03 03 00 cd 0c 00  00 c9 03 00 17 41 04 04  |.............A..|
+00000330  be 27 08 6f 12 83 1b 04  76 fa 5f 16 d6 e3 64 76  |.'.o....v._...dv|
+00000340  ad 0a 77 37 71 64 44 4c  3f 1a be dc 85 ce 46 c8  |..w7qdDL?.....F.|
+00000350  29 a1 e2 24 78 66 1f 35  90 05 46 c0 91 d1 fd dd  |)..$xf.5..F.....|
+00000360  b5 5b 87 d7 6d 9d 77 a7  f7 b3 df 68 27 fd 6d 04  |.[..m.w....h'.m.|
+00000370  01 00 80 7b 9b fd 0d 62  57 07 ef 97 f5 ff a9 00  |...{...bW.......|
+00000380  a0 89 35 5a 8a e6 e7 ae  7b 55 c5 dc 21 64 87 6e  |..5Z....{U..!d.n|
+00000390  0f ab 85 6d 82 e8 83 fd  7d 3b 49 a7 ae 92 5f 6d  |...m....};I..._m|
+000003a0  a3 42 ce ff ef a6 00 6a  33 32 1f 7b eb b7 c2 5c  |.B.....j32.{...\|
+000003b0  2d 38 cf 10 4b 59 69 4d  15 e0 68 49 39 ba cb 2a  |-8..KYiM..hI9..*|
+000003c0  d9 b9 f3 fe 33 01 4f 7e  ac 69 02 35 a5 e0 33 8d  |....3.O~.i.5..3.|
+000003d0  b3 74 34 14 45 9c 89 ad  41 2d d0 27 22 90 58 c6  |.t4.E...A-.'".X.|
+000003e0  e0 2c b4 6e 19 04 e4 46  26 ec 13 35 48 a6 3f 64  |.,.n...F&..5H.?d|
+000003f0  dc 85 2b 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 28 00 00  00 00 00 00 00 00 a8 da  |.....(..........|
-00000060  74 a6 d0 a5 26 86 f3 5f  89 a4 af ac 9c 1a 01 1f  |t...&.._........|
-00000070  89 8a 1c fc cf 68 3e a5  a3 20 1a b3 78 af        |.....h>.. ..x.|
+00000050  01 16 03 03 00 28 00 00  00 00 00 00 00 00 88 0d  |.....(..........|
+00000060  04 8b 8e 93 55 58 d6 75  ca 16 26 42 a3 60 20 67  |....UX.u..&B.` g|
+00000070  84 cf d7 b3 10 fe 63 6c  2f 40 64 0c d6 78        |......cl/@d..x|
 >>> Flow 4 (server to client)
-00000000  14 03 03 00 01 01 16 03  03 00 28 1a f2 a9 e8 71  |..........(....q|
-00000010  b2 a6 ca 36 4a ea 55 f6  20 03 fd f7 90 c3 af 30  |...6J.U. ......0|
-00000020  d3 29 c3 d7 1b d6 4d 3e  61 55 94 0d 4e 3e 83 1a  |.)....M>aU..N>..|
-00000030  97 dd 19                                          |...|
+00000000  14 03 03 00 01 01 16 03  03 00 28 bd 6c 2f 70 b9  |..........(.l/p.|
+00000010  2f 9c 29 70 af 34 49 4c  5b 25 c3 14 b6 6d 28 81  |/.)p.4IL[%...m(.|
+00000020  ff 54 d9 71 8d 2c c7 38  dd 44 27 6b 54 1e 53 7b  |.T.q.,.8.D'kT.S{|
+00000030  22 cb 65                                          |".e|
 >>> Flow 5 (client to server)
-00000000  17 03 03 00 1e 00 00 00  00 00 00 00 01 94 5b 5e  |..............[^|
-00000010  51 a1 52 ee 19 78 78 ef  12 0d 9c 66 bf e2 48 cb  |Q.R..xx....f..H.|
-00000020  f6 00 1e 15 03 03 00 1a  00 00 00 00 00 00 00 02  |................|
-00000030  cd 5d 31 58 d9 5a 12 65  5b c6 7e 4e e2 04 e7 1d  |.]1X.Z.e[.~N....|
-00000040  b1 4c                                             |.L|
+00000000  17 03 03 00 1e 00 00 00  00 00 00 00 01 7f 0d d7  |................|
+00000010  d9 4b 87 7b 36 fb 24 92  69 22 43 50 1e 46 fb c4  |.K.{6.$.i"CP.F..|
+00000020  86 64 6f 15 03 03 00 1a  00 00 00 00 00 00 00 02  |.do.............|
+00000030  37 d5 2d 0a be c5 a8 ae  d4 bd 2b 09 34 18 a0 87  |7.-.......+.4...|
+00000040  08 a6                                             |..|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-ECDSA b/src/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-ECDSA
index 1470ba7..2073270 100644
--- a/src/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-ECDSA
+++ b/src/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-ECDSA
@@ -1,19 +1,18 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
+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 1e c0 2f  |.............../|
-00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
-00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 36  |...../.5.......6|
-00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
-00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0e 00  |................|
-00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
-00000080  01 00 00 12 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 a5 28 60 99 bf  |....Y...U...(`..|
-00000010  c7 54 04 87 60 ad c5 32  f6 bf ed 11 47 de 4d ff  |.T..`..2....G.M.|
-00000020  99 e1 8f 88 f6 af 10 6e  29 74 0a 20 1d 39 cb e0  |.......n)t. .9..|
-00000030  a5 11 fe 8e 23 11 83 c7  a6 53 fc 97 03 9d ff 7c  |....#....S.....||
-00000040  cf 51 ba 41 64 61 38 22  5c c6 4a 04 c0 09 00 00  |.Q.Ada8"\.J.....|
+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....|
@@ -48,23 +47,24 @@
 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 c4  |*............A..|
-00000280  0a 40 05 84 eb 90 3c 13  d0 90 af 69 fa 5c 20 75  |. at ....<....i.\ u|
-00000290  e1 9b f2 30 f7 df cc 75  2c 35 7e 38 16 99 7d 57  |...0...u,5~8..}W|
-000002a0  6d d7 f0 93 2d 1d c8 03  89 6e 52 3b 20 e5 8a 5f  |m...-....nR; .._|
-000002b0  6d ca 6e 6a ca 51 f8 a4  dc 1d ec 3e 73 c9 72 04  |m.nj.Q.....>s.r.|
-000002c0  03 00 8a 30 81 87 02 41  37 bf 0d 1d c1 9a 37 39  |...0...A7.....79|
-000002d0  4d 4a f8 17 50 5d 4c 78  d4 25 99 9d 81 48 98 a8  |MJ..P]Lx.%...H..|
-000002e0  ff 2d 3f 98 4b 9f d8 96  2b fa 37 cc e8 66 25 0e  |.-?.K...+.7..f%.|
-000002f0  d3 5e 53 c5 3b ad 17 3f  21 ce d2 45 d8 93 95 6c  |.^S.;..?!..E...l|
-00000300  25 f9 5a 10 9f 37 c8 14  a6 02 42 00 e6 bd 9a 89  |%.Z..7....B.....|
-00000310  8e 73 40 f4 90 e6 d8 e2  98 51 10 23 fb 98 e5 47  |.s at ......Q.#...G|
-00000320  0c 2a 7a 2f 02 66 a8 20  e4 cb 4f ba 14 1d 9e 3a  |.*z/.f. ..O....:|
-00000330  2f 09 47 44 02 e0 9f 30  21 71 f0 99 09 de 23 d2  |/.GD...0!q....#.|
-00000340  f5 f0 b2 93 70 a3 8f 79  b9 4f 88 0b 35 16 03 03  |....p..y.O..5...|
-00000350  00 2e 0d 00 00 26 03 01  02 40 00 1e 06 01 06 02  |.....&... at ......|
+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 00 00 0e 00 00 00  |................|
+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|
@@ -104,31 +104,31 @@
 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 05 03 00 8a 30  81 87 02 42 00 cc a4 ad  |.......0...B....|
-00000270  0b ff 09 40 8f 2c a6 37  72 1d f7 d2 19 74 85 ad  |... at .,.7r....t..|
-00000280  ac 33 b0 b8 5b 56 39 cf  b0 ef 46 68 94 39 4c d0  |.3..[V9...Fh.9L.|
-00000290  f4 97 32 10 99 36 c5 95  c8 14 23 37 78 46 5c a9  |..2..6....#7xF\.|
-000002a0  20 95 65 47 ff 54 02 f1  aa 1d d7 bc 39 2d 02 41  | .eG.T......9-.A|
-000002b0  2e f9 d6 8c e8 c5 a9 6f  10 4f d6 5f 4e 88 e9 71  |.......o.O._N..q|
-000002c0  23 5b 6f b8 ab 19 d3 dd  ec f3 32 e3 3b fa 41 a2  |#[o.......2.;.A.|
-000002d0  e8 ae dc 27 8d 4e 79 f4  47 ef c9 8f bf 0b 41 3b  |...'.Ny.G.....A;|
-000002e0  94 16 cb 8f 1e b5 f3 4e  6e 42 46 35 1a 0c ca 79  |.......NnBF5...y|
-000002f0  4b 14 03 03 00 01 01 16  03 03 00 40 00 00 00 00  |K.......... at ....|
-00000300  00 00 00 00 00 00 00 00  00 00 00 00 64 1c d9 9f  |............d...|
-00000310  34 ec c2 74 76 7a 9f cf  95 19 be 8d 6a 2f 25 96  |4..tvz......j/%.|
-00000320  df de 18 ca 0e c9 d4 2f  e4 b0 34 10 5b 72 7a 18  |......./..4.[rz.|
-00000330  5c 64 d7 fc 2e 1b 28 10  ae a6 31 e9              |\d....(...1.|
+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 27 6f 24 a3 0c  |..........@'o$..|
-00000010  6d d7 68 4a fb 43 b0 97  02 6c 22 7e 2f a1 f1 7a  |m.hJ.C...l"~/..z|
-00000020  37 bf 38 82 dc a0 83 24  01 4b c0 4f 15 e1 7c 4c  |7.8....$.K.O..|L|
-00000030  d4 cd b8 e2 71 af f5 20  7d f9 4a 48 4b f0 a1 f3  |....q.. }.JHK...|
-00000040  7b 02 29 18 c0 87 a5 dd  c4 73 8e                 |{.)......s.|
+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 bf 7a e1  23 0d d0 13 6e 96 81 6d  |......z.#...n..m|
-00000020  32 56 0f 75 7e 01 88 5f  6d e6 d6 ca ec 3c 17 e9  |2V.u~.._m....<..|
-00000030  44 a9 c0 1c a4 15 03 03  00 30 00 00 00 00 00 00  |D........0......|
-00000040  00 00 00 00 00 00 00 00  00 00 76 be 7a 77 29 01  |..........v.zw).|
-00000050  8e 13 02 66 81 43 a0 55  03 35 22 09 de ea 52 bb  |...f.C.U.5"...R.|
-00000060  51 cc c1 09 0e 9b 4d bd  94 85                    |Q.....M...|
+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/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-RSA b/src/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-RSA
index 95c5782..c3b753a 100644
--- a/src/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-RSA
+++ b/src/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-RSA
@@ -1,19 +1,18 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
+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 1e c0 2f  |.............../|
-00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
-00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 36  |...../.5.......6|
-00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
-00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0e 00  |................|
-00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
-00000080  01 00 00 12 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 79 e8 35 e3 d2  |....Q...M..y.5..|
-00000010  c0 5e 39 d1 46 da 9c 94  56 20 e2 06 d6 9b f6 dd  |.^9.F...V ......|
-00000020  4f 7a c1 e8 34 a1 9f 8b  c2 e1 fb 20 66 9c 5a 9a  |Oz..4...... f.Z.|
-00000030  3d 22 ab 8e d8 81 03 94  68 a0 6c 72 d8 23 0b 4b  |="......h.lr.#.K|
-00000040  fe 9d c7 49 a7 7c bd fa  b5 7a 5e 5b 00 05 00 00  |...I.|...z^[....|
+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..|
@@ -58,10 +57,10 @@
 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 2e 0d 00  |n8P)l...........|
-00000320  00 26 03 01 02 40 00 1e  06 01 06 02 06 03 05 01  |.&... at ..........|
+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 00 00  0e 00 00 00              |............|
+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|
@@ -105,24 +104,24 @@
 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 05 03 00 8a 30  81 87 02 41 19 c7 50 06  |.......0...A..P.|
-000002b0  42 82 f9 e5 ec 0b f7 65  7e b1 19 53 5f 23 ab 19  |B......e~..S_#..|
-000002c0  54 08 ec d2 a7 22 dd 83  7c 97 76 59 a5 6b f4 1d  |T...."..|.vY.k..|
-000002d0  92 86 34 2d ce 71 bb 01  d2 8a 67 0e a8 fb 51 e4  |..4-.q....g...Q.|
-000002e0  69 9c 27 23 74 b9 fd 6f  b6 5e 48 a0 cc 02 42 01  |i.'#t..o.^H...B.|
-000002f0  50 97 b7 95 14 f4 a6 f2  95 63 17 38 59 a1 51 95  |P........c.8Y.Q.|
-00000300  1e bc 99 fb fd 82 8b ab  cb 4d 8e 17 a9 f8 e9 c2  |.........M......|
-00000310  9b 93 15 02 50 e6 c2 05  54 e7 8a ec 6f 93 1f 79  |....P...T...o..y|
-00000320  8d 67 e7 2d d6 65 ab 97  fd be 20 97 bd 6b c4 fc  |.g.-.e.... ..k..|
-00000330  02 14 03 03 00 01 01 16  03 03 00 24 24 df 52 6e  |...........$$.Rn|
-00000340  c1 35 48 fe 60 77 28 69  36 fe 96 a1 72 db a2 f5  |.5H.`w(i6...r...|
-00000350  d0 b7 c3 d9 67 e5 ee f2  d9 18 bf f0 35 80 06 c2  |....g.......5...|
+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 40 5b dc 01 59  |..........$@[..Y|
-00000010  33 6e 61 5a 6d fc c8 a5  f5 00 9b 55 77 c5 e6 f2  |3naZm......Uw...|
-00000020  c6 5c b6 2f 94 3c 72 5b  b5 0c 3e 78 88 e6 44     |.\./.<r[..>x..D|
+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 cd 2f 11  b1 3a e4 1c 31 95 9b c4  |....../..:..1...|
-00000010  37 20 9f 03 d3 45 a4 15  e1 09 1e 0c f6 5d d3 15  |7 ...E.......]..|
-00000020  03 03 00 16 d7 f6 a1 d0  ad 41 69 73 c0 40 22 f2  |.........Ais.@".|
-00000030  5f e8 c3 50 f9 35 fc 59  e0 3a                    |_..P.5.Y.:|
+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/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-ECDSA b/src/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-ECDSA
index 23bf29d..0037af6 100644
--- a/src/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-ECDSA
+++ b/src/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-ECDSA
@@ -1,19 +1,18 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
+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 1e c0 2f  |.............../|
-00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
-00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 36  |...../.5.......6|
-00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
-00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0e 00  |................|
-00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
-00000080  01 00 00 12 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 b3 7f 4e e7 11  |....Y...U....N..|
-00000010  6d bc 56 ec 9c a8 61 08  d6 5a 2a 42 7b f1 94 0a  |m.V...a..Z*B{...|
-00000020  29 35 8b 7e 23 a0 6c 59  23 cf 39 20 84 09 b6 5b  |)5.~#.lY#.9 ...[|
-00000030  2f 46 80 3b 26 92 fd 81  e9 24 8c e2 b8 64 a2 03  |/F.;&....$...d..|
-00000040  3a 68 c3 7b 44 f8 28 41  e2 d3 6c 7c c0 09 00 00  |:h.{D.(A..l|....|
+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....|
@@ -48,23 +47,24 @@
 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 0f  |*............A..|
-00000280  4d b0 41 d4 dc 6b 8a 85  52 eb eb 18 4a 8f a7 e6  |M.A..k..R...J...|
-00000290  24 52 e5 86 be 57 d7 0a  e7 23 84 a8 a9 6c 96 08  |$R...W...#...l..|
-000002a0  4b f7 47 32 79 d9 df 81  f6 05 40 63 3b 14 67 3b  |K.G2y..... at c;.g;|
-000002b0  ea 01 a0 0d 43 1a 36 29  b3 51 7a e4 af 1b 67 04  |....C.6).Qz...g.|
-000002c0  03 00 8a 30 81 87 02 42  01 8e 57 8a b8 b7 5b 2f  |...0...B..W...[/|
-000002d0  9c 31 74 d8 7d 68 d7 6e  83 73 5f fb d0 cd de 66  |.1t.}h.n.s_....f|
-000002e0  60 fa 0a 0a 15 0b 30 3b  08 b6 f1 3e 4f 20 13 62  |`.....0;...>O .b|
-000002f0  b5 ff 86 81 dc 42 a1 4c  af c8 ff b3 24 81 d8 e1  |.....B.L....$...|
-00000300  d1 09 0c 32 11 92 5e dd  3f 87 02 41 76 a7 29 48  |...2..^.?..Av.)H|
-00000310  52 68 1c 72 4d d5 39 bf  fa 61 ec b2 27 ce 10 4e  |Rh.rM.9..a..'..N|
-00000320  86 12 3d 1e 04 9c 11 b7  b4 0c cf 98 9d 01 c3 93  |..=.............|
-00000330  cf 83 9e 92 9a ca fd 8f  b1 9f 1b 20 c4 fb a4 46  |........... ...F|
-00000340  60 fc fd d5 33 b0 8f b5  b5 c8 a4 70 c5 16 03 03  |`...3......p....|
-00000350  00 2e 0d 00 00 26 03 01  02 40 00 1e 06 01 06 02  |.....&... 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 00 00 0e 00 00 00  |................|
+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|
@@ -103,31 +103,31 @@
 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 05 01 00 80  02 19 16 cc 97 ad 70 20  |..............p |
-00000260  bd 64 63 dd b6 81 a0 16  b3 46 4b 42 ff 21 58 2c  |.dc......FKB.!X,|
-00000270  bb 2b 4c e1 4e d7 49 4d  5c 7c 63 32 3e ef e6 ad  |.+L.N.IM\|c2>...|
-00000280  85 3f ab b4 5c 2a 37 76  8b 28 56 08 4f 08 b9 51  |.?..\*7v.(V.O..Q|
-00000290  71 14 07 27 47 45 11 a0  03 cf 72 7d 67 ef 31 8d  |q..'GE....r}g.1.|
-000002a0  e7 db 36 76 b1 b3 f4 bf  aa 6c c4 56 94 35 71 e1  |..6v.....l.V.5q.|
-000002b0  dd 88 6d 15 90 c8 70 ad  d8 95 55 42 9b c1 45 19  |..m...p...UB..E.|
-000002c0  36 ce 87 c6 fd 94 8a d4  98 6e ec 18 d5 da 59 54  |6........n....YT|
-000002d0  80 a7 8c 90 ae 55 20 1c  14 03 03 00 01 01 16 03  |.....U .........|
+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 58 fe bc 5c ba  b2 a9 96 77 2f 95 c9 10  |...X..\....w/...|
-00000300  fd 6d fc 6a 88 8c df 82  c3 a4 3d cc 28 f4 bf 7d  |.m.j......=.(..}|
-00000310  4a f8 3d 97 36 e5 a0 76  92 94 da dd cc f5 e4 0e  |J.=.6..v........|
-00000320  7a c4 2c                                          |z.,|
+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 81 ab 5a 66 a8  |.......... at ..Zf.|
-00000010  0f a5 d3 07 00 66 45 1f  31 a9 ef f7 a0 d9 23 46  |.....fE.1.....#F|
-00000020  f0 3e 50 18 99 e3 5a bd  eb b7 1d 81 d5 95 d5 ee  |.>P...Z.........|
-00000030  21 31 41 4b 19 92 b5 95  36 da 21 c0 4a 2a a0 1c  |!1AK....6.!.J*..|
-00000040  a3 9f 8e a0 6f 9d 37 5e  12 11 03                 |....o.7^...|
+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 a9 51 94  19 72 ab 9f 3e 97 5e 99  |......Q..r..>.^.|
-00000020  2c ec 13 48 3e 10 54 5f  8a 85 88 4d 1a a8 f5 ed  |,..H>.T_...M....|
-00000030  c3 4f a9 59 a3 15 03 03  00 30 00 00 00 00 00 00  |.O.Y.....0......|
-00000040  00 00 00 00 00 00 00 00  00 00 25 00 6d 2f a0 f6  |..........%.m/..|
-00000050  ce 8a 30 ba 53 da 97 c6  11 f3 d2 f3 9e 66 d6 dd  |..0.S........f..|
-00000060  19 f3 ee 07 03 d3 e6 f1  30 32                    |........02|
+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/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-RSA b/src/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-RSA
index ff79aa2..df3eaa4 100644
--- a/src/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-RSA
+++ b/src/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-RSA
@@ -1,19 +1,18 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
+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 1e c0 2f  |.............../|
-00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
-00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 36  |...../.5.......6|
-00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
-00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0e 00  |................|
-00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
-00000080  01 00 00 12 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 b3 b2 22 69 e4  |....Q...M...."i.|
-00000010  1a a1 56 94 26 0c 43 b7  89 0c 34 ce dc 5a c8 ca  |..V.&.C...4..Z..|
-00000020  e2 42 92 5c 75 9a b3 22  22 64 38 20 6d 2c 26 0b  |.B.\u..""d8 m,&.|
-00000030  34 b6 b8 20 36 e2 58 e5  ee 1f e2 9f a0 75 f6 d9  |4.. 6.X......u..|
-00000040  0c e4 39 ce 3c 8e 2e f8  e8 d1 a2 16 00 05 00 00  |..9.<...........|
+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..|
@@ -58,10 +57,10 @@
 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 2e 0d 00  |n8P)l...........|
-00000320  00 26 03 01 02 40 00 1e  06 01 06 02 06 03 05 01  |.&... at ..........|
+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 00 00  0e 00 00 00              |............|
+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|
@@ -104,24 +103,24 @@
 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 05 01 00 80  01 24 8d bb 05 61 2d 29  |.........$...a-)|
-000002a0  12 11 90 f5 57 21 be b7  29 76 55 63 94 8e 7b 4d  |....W!..)vUc..{M|
-000002b0  3b 3d 89 5b 1f b9 e1 8c  36 68 6f 31 21 50 af e4  |;=.[....6ho1!P..|
-000002c0  9f ca a5 68 55 b9 eb 36  75 3a 0c be 11 30 28 c8  |...hU..6u:...0(.|
-000002d0  8b 82 93 9a 71 37 4d 4e  4f d2 0c 2f 13 36 ad c3  |....q7MNO../.6..|
-000002e0  df 8a 1b 59 b2 f9 8b a7  74 63 75 4a f4 9d e0 6b  |...Y....tcuJ...k|
-000002f0  42 02 5a a9 6e a4 a8 24  d3 23 f7 09 ee b0 dc c4  |B.Z.n..$.#......|
-00000300  6f 87 58 72 e7 e3 87 b3  6b 15 ba 7f dd 9b 93 91  |o.Xr....k.......|
-00000310  5b 21 a0 31 31 bd 15 b5  14 03 03 00 01 01 16 03  |[!.11...........|
-00000320  03 00 24 fc 0e 7c e8 3e  8b b5 dc c9 3d 38 61 a1  |..$..|.>....=8a.|
-00000330  24 d6 77 1f 06 1f 30 32  ba dd 05 68 45 f1 4f 0d  |$.w...02...hE.O.|
-00000340  2e 24 09 ad c1 e5 b7                              |.$.....|
+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 d7 b6 b3 0a e6  |..........$.....|
-00000010  86 9a 25 e4 38 de d0 57  ff 93 0b f4 de 76 3d 00  |..%.8..W.....v=.|
-00000020  64 35 cf 70 f6 ea 74 2d  b0 71 2d 92 e2 df eb     |d5.p..t-.q-....|
+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 db bd 43  12 7c b5 83 b5 18 9d 6a  |.......C.|.....j|
-00000010  70 3f 5a eb cb d0 ba d4  03 3e a0 7b 25 f0 41 15  |p?Z......>.{%.A.|
-00000020  03 03 00 16 f8 f2 a3 27  a5 c7 25 d9 6c 08 b1 96  |.......'..%.l...|
-00000030  38 22 38 df 16 fb e2 9f  61 a3                    |8"8.....a.|
+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/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES b/src/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES
index e700e16..7644590 100644
--- a/src/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES
+++ b/src/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES
@@ -1,19 +1,18 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
+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 1e c0 2f  |.............../|
-00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
-00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 36  |...../.5.......6|
-00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
-00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0e 00  |................|
-00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
-00000080  01 00 00 12 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 21 9b eb 15 24  |....Y...U..!...$|
-00000010  46 b6 c1 85 f5 be c5 0d  e2 6b 60 bc ee 73 b1 fb  |F........k`..s..|
-00000020  34 6f f0 b8 f0 9e 1c 26  a4 4b 0f 20 cb 2b 84 a2  |4o.....&.K. .+..|
-00000030  cb a5 48 70 fe 84 25 b0  16 20 14 a1 83 21 fc f9  |..Hp..%.. ...!..|
-00000040  82 fc 9e 1a d1 3b 56 69  ab c5 0e 2c c0 09 00 00  |.....;Vi...,....|
+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....|
@@ -48,21 +47,21 @@
 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 b6  |*............A..|
-00000280  3f 37 33 68 cb 79 c0 86  f4 9d 12 ac c4 9d 8c 9b  |?73h.y..........|
-00000290  59 1c d4 a9 01 9f 2d cb  80 24 02 ec e0 ff d1 8c  |Y.....-..$......|
-000002a0  bd 82 67 3f 47 58 1a 2e  6b 61 f6 8e 4e 27 7f 49  |..g?GX..ka..N'.I|
-000002b0  b5 45 f1 0b 9a 33 ff 53  ac 65 e2 82 7a 18 5c 04  |.E...3.S.e..z.\.|
-000002c0  03 00 8b 30 81 88 02 42  00 e1 2d ff 5d e7 77 f1  |...0...B..-.].w.|
-000002d0  12 d9 e4 c2 4d cd 9c b5  ee e4 fd 21 b2 d8 53 a9  |....M......!..S.|
-000002e0  42 e7 c5 9b 51 c3 59 37  a5 08 d4 e6 29 12 c5 56  |B...Q.Y7....)..V|
-000002f0  b8 fe f0 bb 77 87 a3 ee  09 b0 8c cd 1c 39 9e b5  |....w........9..|
-00000300  d9 15 63 53 cb d7 f1 55  5b 48 02 42 01 19 10 8a  |..cS...U[H.B....|
-00000310  7a ee 95 b1 77 44 d4 a3  bf d1 f3 f1 b0 d8 c7 7e  |z...wD.........~|
-00000320  42 c0 83 04 f5 f7 9c c0  ce 6a 98 47 9d 21 29 84  |B........j.G.!).|
-00000330  c8 be 6b 67 4e fc c6 26  ec 63 df 00 33 e6 d2 f7  |..kgN..&.c..3...|
-00000340  34 93 85 9b 1b 0f e0 89  42 b6 0b 94 1b 80 16 03  |4.......B.......|
-00000350  03 00 04 0e 00 00 00                              |.......|
+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.|
@@ -70,21 +69,21 @@
 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 50 73  9c 9f a8 d7 78 ac 06 14  |......Ps....x...|
-00000070  8f ae fc fb ef 7d 99 db  b7 c9 91 dd f2 fe da 1b  |.....}..........|
-00000080  aa 9e 7d e4 5c 2f 5f dd  74 aa fe 03 51 e7 cd 98  |..}.\/_.t...Q...|
-00000090  e9 21 19 c9 6f 59                                 |.!..oY|
+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 47 18 b5 1b 75  |.......... at G...u|
-00000010  b8 a3 63 ab 77 d3 47 cb  14 26 b4 88 fe 15 db 22  |..c.w.G..&....."|
-00000020  76 3b 25 d3 68 8e f2 a7  d5 03 2b 82 7b b1 0f 10  |v;%.h.....+.{...|
-00000030  49 6a 3d 95 d0 4b 55 0e  14 eb bb a7 34 bb 57 b3  |Ij=..KU.....4.W.|
-00000040  5d fb 7e 15 80 5a fa f3  3a df 90                 |].~..Z..:..|
+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 70 74 e2  60 fc 3a 7a b7 5e 16 07  |.....pt.`.:z.^..|
-00000020  22 92 07 fe 92 53 c4 43  1b 8f 94 07 84 48 2b 50  |"....S.C.....H+P|
-00000030  ab 1d 6d 49 ed 15 03 03  00 30 00 00 00 00 00 00  |..mI.....0......|
-00000040  00 00 00 00 00 00 00 00  00 00 ce a8 ba 91 0b e4  |................|
-00000050  8c 38 23 9b 8b 2c 0a 0c  63 79 61 f4 b6 25 f7 41  |.8#..,..cya..%.A|
-00000060  04 9f b0 8f e0 e5 24 44  2f e9                    |......$D/.|
+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/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES-GCM b/src/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES-GCM
index 607ecdc..fb5af17 100644
--- a/src/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES-GCM
+++ b/src/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES-GCM
@@ -1,19 +1,18 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
+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 1e c0 2f  |.............../|
-00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
-00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 36  |...../.5.......6|
-00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
-00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0e 00  |................|
-00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
-00000080  01 00 00 12 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 91 8a 4f 94 29  |....Y...U....O.)|
-00000010  32 fa 66 7a 7f b8 a7 04  5c 34 b9 7e 12 83 35 1f  |2.fz....\4.~..5.|
-00000020  93 b0 af e0 9f 71 07 5e  2f d7 ca 20 52 dc 0d e7  |.....q.^/.. R...|
-00000030  f8 16 db 90 9a 78 2f 03  0b f0 ae a7 2f c6 b4 4c  |.....x/...../..L|
-00000040  62 e7 de 32 d5 68 61 f3  07 e4 60 d2 c0 2b 00 00  |b..2.ha...`..+..|
+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....|
@@ -48,38 +47,38 @@
 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 26  |*............A.&|
-00000280  c1 67 14 4b 9e b0 45 8c  27 bf a3 a2 78 5b 56 ad  |.g.K..E.'...x[V.|
-00000290  d1 21 56 53 df 86 e9 91  de e3 f9 5d e6 f6 5d 79  |.!VS.......]..]y|
-000002a0  11 8b 60 f9 c2 9a c6 3f  6b 72 cd 7c d7 0e 13 64  |..`....?kr.|...d|
-000002b0  af e8 9f 40 35 e6 fb 04  0c 60 aa 19 61 dd 24 04  |... at 5....`..a.$.|
-000002c0  03 00 8b 30 81 88 02 42  00 9d e1 02 5d 8b b1 45  |...0...B....]..E|
-000002d0  e5 c7 b6 94 27 df 36 31  fd 5e 47 fe c8 0f 5f 17  |....'.61.^G..._.|
-000002e0  b1 92 56 76 29 45 3d 90  be 91 6e 2c a7 b2 e1 33  |..Vv)E=...n,...3|
-000002f0  3b f9 3c bb 80 58 c2 d8  a8 59 82 16 dc 9e dd 60  |;.<..X...Y.....`|
-00000300  ff 82 b9 0c 5a ca ff f3  02 2c 02 42 00 a4 c0 d3  |....Z....,.B....|
-00000310  aa 1d 69 52 c0 06 fa 93  e8 50 da a4 2f 72 c9 4a  |..iR.....P../r.J|
-00000320  2c 43 7f 95 05 f7 7a f3  4a 2e 2d ce 13 be 80 40  |,C....z.J.-....@|
-00000330  a4 3b b2 f0 73 8d f1 d4  7b a3 ff 01 e1 58 71 31  |.;..s...{....Xq1|
-00000340  fc d8 2f b3 ef 62 2e b7  ac f5 c4 bc b8 68 16 03  |../..b.......h..|
-00000350  03 00 04 0e 00 00 00                              |.......|
+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 83 cf  |.....(..........|
-00000060  ef 50 c2 e7 da b9 74 7f  1c e0 b8 fb dc 39 c9 98  |.P....t......9..|
-00000070  0c a3 7d 8c c6 fa 6f f2  ee 44 a0 a0 03 18        |..}...o..D....|
+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 73 c4 48 24 3d  |..........(s.H$=|
-00000010  8f 5f f3 8c fc fd 63 be  64 39 d5 56 67 bd d7 c4  |._....c.d9.Vg...|
-00000020  0d 57 88 1a 45 a6 f3 ad  11 b2 5a 41 58 33 f3 d3  |.W..E.....ZAX3..|
-00000030  58 fa 21                                          |X.!|
+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 65 5e 55  |.............e^U|
-00000010  32 be 00 77 6e 1d 8e 8f  95 33 24 3d 7a c2 b0 3f  |2..wn....3$=z..?|
-00000020  ca aa 97 15 03 03 00 1a  00 00 00 00 00 00 00 02  |................|
-00000030  b2 71 6e 42 6a 0d cf c9  ac 14 a4 b5 9c c9 71 60  |.qnBj.........q`|
-00000040  d7 c2                                             |..|
+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/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-AES b/src/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-AES
index 994ebb1..5336bbb 100644
--- a/src/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-AES
+++ b/src/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-AES
@@ -1,19 +1,18 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
+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 1e c0 2f  |.............../|
-00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
-00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 36  |...../.5.......6|
-00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
-00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0e 00  |................|
-00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
-00000080  01 00 00 12 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 e6 ae 89 0d 22  |....Y...U......"|
-00000010  e5 e0 cd 57 a3 ca 71 4f  17 2f 64 77 f8 30 89 ef  |...W..qO./dw.0..|
-00000020  e8 19 70 ac dd 2c c5 9f  84 7d 1d 20 1c 59 3c fe  |..p..,...}. .Y<.|
-00000030  a9 ec 10 dd 38 3b 43 fe  6b 09 e5 e4 83 d9 7a 78  |....8;C.k.....zx|
-00000040  86 08 33 da 9b e1 09 d8  c9 07 34 19 c0 13 00 00  |..3.......4.....|
+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..............|
@@ -59,20 +58,20 @@
 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 77  |.............A.w|
-00000330  87 a7 ad f6 f8 34 82 05  ef bb 14 6d c7 8b 7b 2a  |.....4.....m..{*|
-00000340  4d ca 41 65 58 3c 83 fa  4d ce 0c 74 46 85 fe 38  |M.AeX<..M..tF..8|
-00000350  95 80 ee 7c c2 bf f2 be  a3 c6 bf f3 aa 07 23 40  |...|..........#@|
-00000360  7e cc 74 4a 4e 2e 69 af  6b e0 42 8a fc 41 be 04  |~.tJN.i.k.B..A..|
-00000370  01 00 80 99 ed a8 3a ef  93 1b 4c 17 80 9e cc eb  |......:...L.....|
-00000380  da 39 fb c8 9a 73 e1 96  20 3e 41 fa 8b 1a b1 68  |.9...s.. >A....h|
-00000390  cd 47 bc 4b 7b 0c 14 da  87 d3 36 09 5e 37 33 88  |.G.K{.....6.^73.|
-000003a0  7f 88 07 87 46 ec e5 72  a8 59 92 07 fa 4d 02 dc  |....F..r.Y...M..|
-000003b0  bf 3a f5 e4 77 0b a6 85  ce 43 ee 1b 90 30 7f ec  |.:..w....C...0..|
-000003c0  88 79 f8 88 59 af 6b 7f  2d 88 de 92 cd c8 36 cf  |.y..Y.k.-.....6.|
-000003d0  ba b9 08 6a c4 3d d7 9a  48 50 e1 67 d0 62 a5 b3  |...j.=..HP.g.b..|
-000003e0  b0 5f 2e 16 ee 4d 7d a2  cf d9 93 19 89 b7 64 0f  |._...M}.......d.|
-000003f0  0f 8e 3d 16 03 03 00 04  0e 00 00 00              |..=.........|
+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.|
@@ -80,21 +79,21 @@
 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 f2 20  58 ec f1 88 a6 26 79 9d  |....... X....&y.|
-00000070  2e 9b 02 b5 5e da e2 c1  c5 8d c8 93 6f 6d 07 4e  |....^.......om.N|
-00000080  fa dd ee cb b1 ae c7 3b  09 b2 cc 64 7a cd 98 91  |.......;...dz...|
-00000090  cb f8 3c 34 3b ed                                 |..<4;.|
+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 4c a1 8d bd 49  |.......... at L...I|
-00000010  33 d3 72 fb 2f 23 7e 11  29 fc d2 ff 9b 67 30 c8  |3.r./#~.)....g0.|
-00000020  be c1 bc 51 6e 92 a5 f4  9d e3 b3 f9 d2 d4 c4 a5  |...Qn...........|
-00000030  83 23 90 b3 17 00 35 18  c5 ef 8b 18 a3 cf ed 9d  |.#....5.........|
-00000040  a9 52 c9 11 0a c9 55 c2  76 df 78                 |.R....U.v.x|
+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 60 40 d0  bf 8f ef 05 2b 89 d7 bb  |.....`@.....+...|
-00000020  27 d0 1f b2 cf c3 ff 8e  be 69 16 a9 b3 03 e8 3c  |'........i.....<|
-00000030  30 1d 58 39 4a 15 03 03  00 30 00 00 00 00 00 00  |0.X9J....0......|
-00000040  00 00 00 00 00 00 00 00  00 00 de 61 51 a1 3c fc  |...........aQ.<.|
-00000050  1c 7b e6 f2 7d e0 aa 80  2d 9c e9 22 09 5c dd 8a  |.{..}...-..".\..|
-00000060  55 cc c4 77 34 97 05 88  98 d3                    |U..w4.....|
+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/crypto/tls/testdata/Client-TLSv12-RSA-RC4 b/src/crypto/tls/testdata/Client-TLSv12-RSA-RC4
index 73e34c0..0377f05 100644
--- a/src/crypto/tls/testdata/Client-TLSv12-RSA-RC4
+++ b/src/crypto/tls/testdata/Client-TLSv12-RSA-RC4
@@ -1,19 +1,18 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
+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 1e c0 2f  |.............../|
-00000030  c0 2b c0 30 c0 2c c0 11  c0 07 c0 13 c0 09 c0 14  |.+.0.,..........|
-00000040  c0 0a 00 05 00 2f 00 35  c0 12 00 0a 01 00 00 36  |...../.5.......6|
-00000050  00 05 00 05 01 00 00 00  00 00 0a 00 08 00 06 00  |................|
-00000060  17 00 18 00 19 00 0b 00  02 01 00 00 0d 00 0e 00  |................|
-00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
-00000080  01 00 00 12 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 e8 ae 4c 97 41  |....Q...M....L.A|
-00000010  78 0f 08 84 d4 4a 80 6d  a2 e1 d0 67 40 8f 01 8b  |x....J.m...g at ...|
-00000020  20 54 cb 28 16 52 04 fd  3c c2 84 20 30 96 f0 51  | T.(.R..<.. 0..Q|
-00000030  72 86 6a d8 47 b9 47 e3  a4 ad 97 77 a9 77 1a f9  |r.j.G.G....w.w..|
-00000040  ba 63 33 32 4f 43 09 1c  e1 bd 1b 3b 00 05 00 00  |.c32OC.....;....|
+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..|
@@ -70,15 +69,15 @@
 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 54 8c  7f 71 03 7c 98 e5 97 65  |.....$T..q.|...e|
-000000a0  51 13 b2 9d 4a b8 c9 c1  e6 11 1b 50 c8 1b c0 46  |Q...J......P...F|
-000000b0  a7 cb 13 97 92 a0 51 d4  a9 e5                    |......Q...|
+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 37 ca ae 55 79  |..........$7..Uy|
-00000010  e7 0a 70 55 1e d1 76 61  57 46 d2 c0 d0 ed 3d 70  |..pU..vaWF....=p|
-00000020  1f 02 f2 06 5b 3e 50 ec  13 4b 67 e2 7c bd 45     |....[>P..Kg.|.E|
+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 c4 13 68  ec e0 38 a1 07 35 da d7  |.......h..8..5..|
-00000010  c4 6b f9 5c ed a7 8a cb  96 7a 22 7c ca a5 30 15  |.k.\.....z"|..0.|
-00000020  03 03 00 16 f7 a7 8d 41  b0 c1 4b 61 60 b0 b2 ed  |.......A..Ka`...|
-00000030  4a ab c3 54 d5 20 eb 67  b7 8f                    |J..T. .g..|
+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/crypto/tls/testdata/Server-SSLv3-RSA-3DES b/src/crypto/tls/testdata/Server-SSLv3-RSA-3DES
index 20520f5..a6c7a41 100644
--- a/src/crypto/tls/testdata/Server-SSLv3-RSA-3DES
+++ b/src/crypto/tls/testdata/Server-SSLv3-RSA-3DES
@@ -1,78 +1,83 @@
 >>> Flow 1 (client to server)
-00000000  16 03 00 00 2f 01 00 00  2b 03 00 10 71 68 59 99  |..../...+...qhY.|
-00000010  9c a6 e7 36 8b 0d 03 be  f5 42 ab 7c d0 3b 76 3e  |...6.....B.|.;v>|
-00000020  46 7c 6c a3 94 09 b7 1b  0e 42 27 00 00 04 00 0a  |F|l......B'.....|
+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 71 0b 00 02 6d 00  |..........q...m.|
-00000040  02 6a 00 02 67 30 82 02  63 30 82 01 cc a0 03 02  |.j..g0..c0......|
-00000050  01 02 02 09 00 a2 73 00  0c 81 00 cb f3 30 0d 06  |......s......0..|
-00000060  09 2a 86 48 86 f7 0d 01  01 0b 05 00 30 2b 31 17  |.*.H........0+1.|
-00000070  30 15 06 03 55 04 0a 13  0e 47 6f 6f 67 6c 65 20  |0...U....Google |
-00000080  54 45 53 54 49 4e 47 31  10 30 0e 06 03 55 04 03  |TESTING1.0...U..|
-00000090  13 07 47 6f 20 52 6f 6f  74 30 1e 17 0d 31 35 30  |..Go Root0...150|
-000000a0  31 30 31 30 30 30 30 30  30 5a 17 0d 32 35 30 31  |101000000Z..2501|
-000000b0  30 31 30 30 30 30 30 30  5a 30 26 31 17 30 15 06  |01000000Z0&1.0..|
-000000c0  03 55 04 0a 13 0e 47 6f  6f 67 6c 65 20 54 45 53  |.U....Google TES|
-000000d0  54 49 4e 47 31 0b 30 09  06 03 55 04 03 13 02 47  |TING1.0...U....G|
-000000e0  6f 30 81 9f 30 0d 06 09  2a 86 48 86 f7 0d 01 01  |o0..0...*.H.....|
-000000f0  01 05 00 03 81 8d 00 30  81 89 02 81 81 00 af 87  |.......0........|
-00000100  88 f6 20 1b 95 65 6c 14  ab 44 05 af 3b 45 14 e3  |.. ..el..D..;E..|
-00000110  b7 6d fd 00 63 4d 95 7f  fe 6a 62 35 86 c0 4a f9  |.m..cM...jb5..J.|
-00000120  18 7c f6 aa 25 5e 7a 64  31 66 00 ba f4 8e 92 af  |.|..%^zd1f......|
-00000130  c7 6b d8 76 d4 f3 5f 41  cb 6e 56 15 97 1b 97 c1  |.k.v.._A.nV.....|
-00000140  3c 12 39 21 66 3d 2b 16  d1 bc db 1c c0 a7 da b7  |<.9!f=+.........|
-00000150  ca ad ba da cb d5 21 50  ec de 8d ab d1 6b 81 4b  |......!P.....k.K|
-00000160  89 02 f3 c4 be c1 6c 89  b1 44 84 bd 21 d1 04 7d  |......l..D..!..}|
-00000170  9d 16 4d f9 82 15 f6 ef  fa d6 09 47 f2 fb 02 03  |..M........G....|
-00000180  01 00 01 a3 81 93 30 81  90 30 0e 06 03 55 1d 0f  |......0..0...U..|
-00000190  01 01 ff 04 04 03 02 05  a0 30 1d 06 03 55 1d 25  |.........0...U.%|
-000001a0  04 16 30 14 06 08 2b 06  01 05 05 07 03 01 06 08  |..0...+.........|
-000001b0  2b 06 01 05 05 07 03 02  30 0c 06 03 55 1d 13 01  |+.......0...U...|
-000001c0  01 ff 04 02 30 00 30 19  06 03 55 1d 0e 04 12 04  |....0.0...U.....|
-000001d0  10 12 50 8d 89 6f 1b d1  dc 54 4d 6e cb 69 5e 06  |..P..o...TMn.i^.|
-000001e0  f4 30 1b 06 03 55 1d 23  04 14 30 12 80 10 bf 3d  |.0...U.#..0....=|
-000001f0  b6 a9 66 f2 b8 40 cf ea  b4 03 78 48 1a 41 30 19  |..f.. at ....xH.A0.|
-00000200  06 03 55 1d 11 04 12 30  10 82 0e 65 78 61 6d 70  |..U....0...examp|
-00000210  6c 65 2e 67 6f 6c 61 6e  67 30 0d 06 09 2a 86 48  |le.golang0...*.H|
-00000220  86 f7 0d 01 01 0b 05 00  03 81 81 00 92 7c af 91  |.............|..|
-00000230  55 12 18 96 59 31 a6 48  40 d5 2d d5 ee bb 02 a0  |U...Y1.H at .-.....|
-00000240  f5 c2 1e 7c 9b b3 30 7d  3c dc 76 da 4f 3d c0 fa  |...|..0}<.v.O=..|
-00000250  ae 2d 33 24 6b 03 7b 1b  67 59 11 21 b5 11 bc 77  |.-3$k.{.gY.!...w|
-00000260  b9 d9 e0 6e a8 2d 2e 35  fa 64 5f 22 3e 63 10 6b  |...n.-.5.d_">c.k|
-00000270  be ff 14 86 6d 0d f0 15  31 a8 14 38 1e 3b 84 87  |....m...1..8.;..|
-00000280  2c cb 98 ed 51 76 b9 b1  4f dd db 9b 84 04 86 40  |,...Qv..O......@|
-00000290  fa 51 dd ba b4 8d eb e3  46 de 46 b9 4f 86 c7 f9  |.Q......F.F.O...|
-000002a0  a4 c2 41 34 ac cc f6 ea  b0 ab 39 18 16 03 00 00  |..A4......9.....|
-000002b0  04 0e 00 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 1b 62 18 c8 60 0b f7  |..........b..`..|
-00000010  4a b8 ec 98 56 eb aa 4b  d9 05 c0 f1 be b9 a5 28  |J...V..K.......(|
-00000020  62 e8 3e 25 08 9f 28 dd  08 1f 04 80 5f 10 81 cf  |b.>%..(....._...|
-00000030  aa 2f 55 cd f1 0f ec 5b  90 0a 1f 49 bc a3 96 38  |./U....[...I...8|
-00000040  c7 32 b6 0a da b3 a5 7a  76 28 82 19 30 f4 6b ae  |.2.....zv(..0.k.|
-00000050  fb 81 cc b4 ad 92 f8 c6  20 da 27 89 45 f4 43 c2  |........ .'.E.C.|
-00000060  16 7e de 29 03 dc 90 dd  3a 23 58 4c 35 be 11 a5  |.~.)....:#XL5...|
-00000070  52 18 79 13 e6 b3 2d e6  8e f5 76 60 0c c1 92 bb  |R.y...-...v`....|
-00000080  07 67 c5 24 12 1b aa d6  53 14 03 00 00 01 01 16  |.g.$....S.......|
-00000090  03 00 00 40 5f 64 da b6  24 19 07 44 32 85 f3 c0  |... at _d..$..D2...|
-000000a0  9b c6 2c ad b1 d1 0f 4b  52 20 2f ea 6f 15 80 44  |..,....KR /.o..D|
-000000b0  78 34 44 02 67 e0 2e b4  b8 df 7b 3f 21 dd 66 9b  |x4D.g.....{?!.f.|
-000000c0  e7 5f 71 ff 5f 30 fb 5b  5a 19 f0 24 f8 21 bc 7c  |._q._0.[Z..$.!.||
-000000d0  00 e1 1f e8                                       |....|
+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 48 01 fc 08 a0  |.......... at H....|
-00000010  fa 0e 63 58 25 18 06 3c  54 5c 60 ce 35 f6 ec b8  |..cX%..<T\`.5...|
-00000020  ed f8 97 c7 b0 5f 96 6b  d1 10 53 e9 23 20 44 56  |....._.k..S.# DV|
-00000030  d7 ee 11 e1 6f b7 1e fb  33 94 7f f0 78 f5 2e 02  |....o...3...x...|
-00000040  37 7a 43 cf e7 c7 52 b3  c6 8d 8e 17 03 00 00 18  |7zC...R.........|
-00000050  f7 3c 05 79 4b 55 8c d7  2c 50 82 f0 61 34 f6 c7  |.<.yKU..,P..a4..|
-00000060  f3 71 e1 76 1d f0 65 b6  17 03 00 00 28 50 ce 6c  |.q.v..e.....(P.l|
-00000070  96 97 70 88 b7 3c 74 a9  cb a3 0e ae 3a 7f 85 99  |..p..<t.....:...|
-00000080  58 36 10 7f 1a e8 f8 7d  83 75 24 7e b1 6a 8e b0  |X6.....}.u$~.j..|
-00000090  f1 cc 06 19 f7 15 03 00  00 18 2c 1d 87 1d ce 08  |..........,.....|
-000000a0  8f 10 09 6e bd fc ad e0  1d a7 47 d5 b9 8f 3e b8  |...n......G...>.|
-000000b0  b3 fa                                             |..|
+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/crypto/tls/testdata/Server-SSLv3-RSA-AES b/src/crypto/tls/testdata/Server-SSLv3-RSA-AES
index e0fe956..4885b26 100644
--- a/src/crypto/tls/testdata/Server-SSLv3-RSA-AES
+++ b/src/crypto/tls/testdata/Server-SSLv3-RSA-AES
@@ -1,79 +1,84 @@
 >>> Flow 1 (client to server)
-00000000  16 03 00 00 2f 01 00 00  2b 03 00 37 cd 49 a6 9f  |..../...+..7.I..|
-00000010  e9 19 6a 39 cd 75 ce 6c  f1 1b 96 d3 d4 f0 33 0c  |..j9.u.l......3.|
-00000020  8f 53 b2 06 c4 0e 39 86  e3 98 7e 00 00 04 00 2f  |.S....9...~..../|
+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 71 0b 00 02 6d 00  |..........q...m.|
-00000040  02 6a 00 02 67 30 82 02  63 30 82 01 cc a0 03 02  |.j..g0..c0......|
-00000050  01 02 02 09 00 a2 73 00  0c 81 00 cb f3 30 0d 06  |......s......0..|
-00000060  09 2a 86 48 86 f7 0d 01  01 0b 05 00 30 2b 31 17  |.*.H........0+1.|
-00000070  30 15 06 03 55 04 0a 13  0e 47 6f 6f 67 6c 65 20  |0...U....Google |
-00000080  54 45 53 54 49 4e 47 31  10 30 0e 06 03 55 04 03  |TESTING1.0...U..|
-00000090  13 07 47 6f 20 52 6f 6f  74 30 1e 17 0d 31 35 30  |..Go Root0...150|
-000000a0  31 30 31 30 30 30 30 30  30 5a 17 0d 32 35 30 31  |101000000Z..2501|
-000000b0  30 31 30 30 30 30 30 30  5a 30 26 31 17 30 15 06  |01000000Z0&1.0..|
-000000c0  03 55 04 0a 13 0e 47 6f  6f 67 6c 65 20 54 45 53  |.U....Google TES|
-000000d0  54 49 4e 47 31 0b 30 09  06 03 55 04 03 13 02 47  |TING1.0...U....G|
-000000e0  6f 30 81 9f 30 0d 06 09  2a 86 48 86 f7 0d 01 01  |o0..0...*.H.....|
-000000f0  01 05 00 03 81 8d 00 30  81 89 02 81 81 00 af 87  |.......0........|
-00000100  88 f6 20 1b 95 65 6c 14  ab 44 05 af 3b 45 14 e3  |.. ..el..D..;E..|
-00000110  b7 6d fd 00 63 4d 95 7f  fe 6a 62 35 86 c0 4a f9  |.m..cM...jb5..J.|
-00000120  18 7c f6 aa 25 5e 7a 64  31 66 00 ba f4 8e 92 af  |.|..%^zd1f......|
-00000130  c7 6b d8 76 d4 f3 5f 41  cb 6e 56 15 97 1b 97 c1  |.k.v.._A.nV.....|
-00000140  3c 12 39 21 66 3d 2b 16  d1 bc db 1c c0 a7 da b7  |<.9!f=+.........|
-00000150  ca ad ba da cb d5 21 50  ec de 8d ab d1 6b 81 4b  |......!P.....k.K|
-00000160  89 02 f3 c4 be c1 6c 89  b1 44 84 bd 21 d1 04 7d  |......l..D..!..}|
-00000170  9d 16 4d f9 82 15 f6 ef  fa d6 09 47 f2 fb 02 03  |..M........G....|
-00000180  01 00 01 a3 81 93 30 81  90 30 0e 06 03 55 1d 0f  |......0..0...U..|
-00000190  01 01 ff 04 04 03 02 05  a0 30 1d 06 03 55 1d 25  |.........0...U.%|
-000001a0  04 16 30 14 06 08 2b 06  01 05 05 07 03 01 06 08  |..0...+.........|
-000001b0  2b 06 01 05 05 07 03 02  30 0c 06 03 55 1d 13 01  |+.......0...U...|
-000001c0  01 ff 04 02 30 00 30 19  06 03 55 1d 0e 04 12 04  |....0.0...U.....|
-000001d0  10 12 50 8d 89 6f 1b d1  dc 54 4d 6e cb 69 5e 06  |..P..o...TMn.i^.|
-000001e0  f4 30 1b 06 03 55 1d 23  04 14 30 12 80 10 bf 3d  |.0...U.#..0....=|
-000001f0  b6 a9 66 f2 b8 40 cf ea  b4 03 78 48 1a 41 30 19  |..f.. at ....xH.A0.|
-00000200  06 03 55 1d 11 04 12 30  10 82 0e 65 78 61 6d 70  |..U....0...examp|
-00000210  6c 65 2e 67 6f 6c 61 6e  67 30 0d 06 09 2a 86 48  |le.golang0...*.H|
-00000220  86 f7 0d 01 01 0b 05 00  03 81 81 00 92 7c af 91  |.............|..|
-00000230  55 12 18 96 59 31 a6 48  40 d5 2d d5 ee bb 02 a0  |U...Y1.H at .-.....|
-00000240  f5 c2 1e 7c 9b b3 30 7d  3c dc 76 da 4f 3d c0 fa  |...|..0}<.v.O=..|
-00000250  ae 2d 33 24 6b 03 7b 1b  67 59 11 21 b5 11 bc 77  |.-3$k.{.gY.!...w|
-00000260  b9 d9 e0 6e a8 2d 2e 35  fa 64 5f 22 3e 63 10 6b  |...n.-.5.d_">c.k|
-00000270  be ff 14 86 6d 0d f0 15  31 a8 14 38 1e 3b 84 87  |....m...1..8.;..|
-00000280  2c cb 98 ed 51 76 b9 b1  4f dd db 9b 84 04 86 40  |,...Qv..O......@|
-00000290  fa 51 dd ba b4 8d eb e3  46 de 46 b9 4f 86 c7 f9  |.Q......F.F.O...|
-000002a0  a4 c2 41 34 ac cc f6 ea  b0 ab 39 18 16 03 00 00  |..A4......9.....|
-000002b0  04 0e 00 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 3f 93 aa 84 d8 ad  |.........M?.....|
-00000010  93 2c 63 02 66 2f 96 88  b8 5c 09 1e 63 e2 e5 96  |.,c.f/...\..c...|
-00000020  26 d8 07 14 86 26 62 f4  0c 04 68 1c bf bb b1 53  |&....&b...h....S|
-00000030  97 96 43 59 4a 57 65 12  88 45 34 2b 86 2b 05 aa  |..CYJWe..E4+.+..|
-00000040  9b 2b b9 aa 13 30 5c 91  c0 9f 03 8a 96 61 dd 87  |.+...0\......a..|
-00000050  ae e3 ad 6a 7b 8a 18 23  67 c9 df ad f2 47 eb 8b  |...j{..#g....G..|
-00000060  7d 24 95 47 f1 4e b5 c6  15 b4 12 2a 42 df b3 99  |}$.G.N.....*B...|
-00000070  d1 b8 60 ce 6a cf 98 c1  13 a1 68 e6 92 ee 92 a2  |..`.j.....h.....|
-00000080  1d 2f 63 66 f3 b9 1b fc  33 14 03 00 00 01 01 16  |./cf....3.......|
-00000090  03 00 00 40 75 48 68 7d  8f f5 5a c0 cb 90 a5 9e  |... at uHh}..Z.....|
-000000a0  94 bb eb 61 b5 36 aa ce  09 7a 11 ba 22 56 2a d7  |...a.6...z.."V*.|
-000000b0  91 a3 99 73 5b c5 b2 b7  b9 92 56 c6 cb fe 13 73  |...s[.....V....s|
-000000c0  28 30 03 26 62 63 7e 8a  d2 58 c8 e7 52 03 26 67  |(0.&bc~..X..R.&g|
-000000d0  48 21 4f 21                                       |H!O!|
+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 84 8f 6e 80 35  |.......... at ..n.5|
-00000010  57 73 64 ef 29 bb 25 ff  5d 9d c7 55 38 b7 18 b3  |Wsd.).%.]..U8...|
-00000020  13 d1 ac 20 e0 1e f8 48  47 7a 40 2d bc a7 f2 af  |... ...HGz at -....|
-00000030  ed a6 26 48 f4 51 b4 b6  56 60 9b c3 d9 43 00 95  |..&H.Q..V`...C..|
-00000040  86 be 6c 4e 49 6b f9 10  99 51 22 17 03 00 00 20  |..lNIk...Q".... |
-00000050  d4 7e dc 50 7b c2 26 ee  79 09 84 9f d7 e0 52 b1  |.~.P{.&.y.....R.|
-00000060  e8 9c 92 30 b7 34 06 c6  e5 86 57 a1 fb 8d 06 d6  |...0.4....W.....|
-00000070  17 03 00 00 30 93 0a 3d  64 26 3d a2 74 bc 8f d1  |....0..=d&=.t...|
-00000080  16 38 d0 6b 62 eb 82 b0  9a 50 68 aa 7e f7 45 32  |.8.kb....Ph.~.E2|
-00000090  43 cb 84 2d 95 39 6c bc  c8 a0 2d aa ea fe f5 84  |C..-.9l...-.....|
-000000a0  c8 e4 8b 93 a1 15 03 00  00 20 03 7b 3e 43 1d 0a  |......... .{>C..|
-000000b0  9b 9b e3 17 0f de be 75  e5 6e 2f 5b e8 8d a8 68  |.......u.n/[...h|
-000000c0  4e f0 82 49 00 dd b6 95  b4 22                    |N..I....."|
+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/crypto/tls/testdata/Server-SSLv3-RSA-RC4 b/src/crypto/tls/testdata/Server-SSLv3-RSA-RC4
index 39124c6..1314b65 100644
--- a/src/crypto/tls/testdata/Server-SSLv3-RSA-RC4
+++ b/src/crypto/tls/testdata/Server-SSLv3-RSA-RC4
@@ -1,74 +1,79 @@
 >>> Flow 1 (client to server)
-00000000  16 03 00 00 2f 01 00 00  2b 03 00 a7 1d 3d ed 0f  |..../...+....=..|
-00000010  2c 7b 1f f1 c8 1c a9 17  ce 69 e2 73 a2 07 d2 91  |,{.......i.s....|
-00000020  e9 27 fa 70 11 6f 18 6d  2a 25 f1 00 00 04 00 05  |.'.p.o.m*%......|
+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 71 0b 00 02 6d 00  |..........q...m.|
-00000040  02 6a 00 02 67 30 82 02  63 30 82 01 cc a0 03 02  |.j..g0..c0......|
-00000050  01 02 02 09 00 a2 73 00  0c 81 00 cb f3 30 0d 06  |......s......0..|
-00000060  09 2a 86 48 86 f7 0d 01  01 0b 05 00 30 2b 31 17  |.*.H........0+1.|
-00000070  30 15 06 03 55 04 0a 13  0e 47 6f 6f 67 6c 65 20  |0...U....Google |
-00000080  54 45 53 54 49 4e 47 31  10 30 0e 06 03 55 04 03  |TESTING1.0...U..|
-00000090  13 07 47 6f 20 52 6f 6f  74 30 1e 17 0d 31 35 30  |..Go Root0...150|
-000000a0  31 30 31 30 30 30 30 30  30 5a 17 0d 32 35 30 31  |101000000Z..2501|
-000000b0  30 31 30 30 30 30 30 30  5a 30 26 31 17 30 15 06  |01000000Z0&1.0..|
-000000c0  03 55 04 0a 13 0e 47 6f  6f 67 6c 65 20 54 45 53  |.U....Google TES|
-000000d0  54 49 4e 47 31 0b 30 09  06 03 55 04 03 13 02 47  |TING1.0...U....G|
-000000e0  6f 30 81 9f 30 0d 06 09  2a 86 48 86 f7 0d 01 01  |o0..0...*.H.....|
-000000f0  01 05 00 03 81 8d 00 30  81 89 02 81 81 00 af 87  |.......0........|
-00000100  88 f6 20 1b 95 65 6c 14  ab 44 05 af 3b 45 14 e3  |.. ..el..D..;E..|
-00000110  b7 6d fd 00 63 4d 95 7f  fe 6a 62 35 86 c0 4a f9  |.m..cM...jb5..J.|
-00000120  18 7c f6 aa 25 5e 7a 64  31 66 00 ba f4 8e 92 af  |.|..%^zd1f......|
-00000130  c7 6b d8 76 d4 f3 5f 41  cb 6e 56 15 97 1b 97 c1  |.k.v.._A.nV.....|
-00000140  3c 12 39 21 66 3d 2b 16  d1 bc db 1c c0 a7 da b7  |<.9!f=+.........|
-00000150  ca ad ba da cb d5 21 50  ec de 8d ab d1 6b 81 4b  |......!P.....k.K|
-00000160  89 02 f3 c4 be c1 6c 89  b1 44 84 bd 21 d1 04 7d  |......l..D..!..}|
-00000170  9d 16 4d f9 82 15 f6 ef  fa d6 09 47 f2 fb 02 03  |..M........G....|
-00000180  01 00 01 a3 81 93 30 81  90 30 0e 06 03 55 1d 0f  |......0..0...U..|
-00000190  01 01 ff 04 04 03 02 05  a0 30 1d 06 03 55 1d 25  |.........0...U.%|
-000001a0  04 16 30 14 06 08 2b 06  01 05 05 07 03 01 06 08  |..0...+.........|
-000001b0  2b 06 01 05 05 07 03 02  30 0c 06 03 55 1d 13 01  |+.......0...U...|
-000001c0  01 ff 04 02 30 00 30 19  06 03 55 1d 0e 04 12 04  |....0.0...U.....|
-000001d0  10 12 50 8d 89 6f 1b d1  dc 54 4d 6e cb 69 5e 06  |..P..o...TMn.i^.|
-000001e0  f4 30 1b 06 03 55 1d 23  04 14 30 12 80 10 bf 3d  |.0...U.#..0....=|
-000001f0  b6 a9 66 f2 b8 40 cf ea  b4 03 78 48 1a 41 30 19  |..f.. at ....xH.A0.|
-00000200  06 03 55 1d 11 04 12 30  10 82 0e 65 78 61 6d 70  |..U....0...examp|
-00000210  6c 65 2e 67 6f 6c 61 6e  67 30 0d 06 09 2a 86 48  |le.golang0...*.H|
-00000220  86 f7 0d 01 01 0b 05 00  03 81 81 00 92 7c af 91  |.............|..|
-00000230  55 12 18 96 59 31 a6 48  40 d5 2d d5 ee bb 02 a0  |U...Y1.H at .-.....|
-00000240  f5 c2 1e 7c 9b b3 30 7d  3c dc 76 da 4f 3d c0 fa  |...|..0}<.v.O=..|
-00000250  ae 2d 33 24 6b 03 7b 1b  67 59 11 21 b5 11 bc 77  |.-3$k.{.gY.!...w|
-00000260  b9 d9 e0 6e a8 2d 2e 35  fa 64 5f 22 3e 63 10 6b  |...n.-.5.d_">c.k|
-00000270  be ff 14 86 6d 0d f0 15  31 a8 14 38 1e 3b 84 87  |....m...1..8.;..|
-00000280  2c cb 98 ed 51 76 b9 b1  4f dd db 9b 84 04 86 40  |,...Qv..O......@|
-00000290  fa 51 dd ba b4 8d eb e3  46 de 46 b9 4f 86 c7 f9  |.Q......F.F.O...|
-000002a0  a4 c2 41 34 ac cc f6 ea  b0 ab 39 18 16 03 00 00  |..A4......9.....|
-000002b0  04 0e 00 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 25 85 a3 22 29 e4 fb  |.........%..")..|
-00000010  53 b9 a3 6b ed 70 2b 35  7f db 08 35 b8 4c 95 cd  |S..k.p+5...5.L..|
-00000020  00 ec 5e a1 2e ba e9 ac  a6 d4 ef ca 74 a0 12 1b  |..^.........t...|
-00000030  a7 ec 76 22 2c 63 71 1a  3a 50 94 ce 96 c4 d7 76  |..v",cq.:P.....v|
-00000040  1f 47 58 c7 57 98 af ea  7e 57 05 68 d3 f9 87 02  |.GX.W...~W.h....|
-00000050  35 72 35 66 08 b4 cf 48  24 15 92 d5 ba 46 8d 60  |5r5f...H$....F.`|
-00000060  5a 53 0b e4 9b 53 44 55  dc 77 d1 e4 e0 25 51 f6  |ZS...SDU.w...%Q.|
-00000070  f1 7c 96 0b 32 d4 8c 04  d3 3d e6 70 c7 d6 60 a7  |.|..2....=.p..`.|
-00000080  ae 69 22 69 41 1a 8d 12  67 14 03 00 00 01 01 16  |.i"iA...g.......|
-00000090  03 00 00 3c 32 dd 86 fd  5b 53 74 ea 01 45 5b 9e  |...<2...[St..E[.|
-000000a0  32 d0 9d 27 e8 ce 4c d5  a1 c2 d3 2e 0a e9 e5 d2  |2..'..L.........|
-000000b0  04 8c 77 a3 ff e9 8b 02  14 16 af 54 db ec c4 98  |..w........T....|
-000000c0  72 50 f7 65 fa eb ac 11  07 81 d7 fa 4e 18 34 bc  |rP.e........N.4.|
+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 29 af 2c 96 3a  |..........<).,.:|
-00000010  be a0 91 a8 e4 66 6b 30  ba e2 80 fc a2 8a 09 b4  |.....fk0........|
-00000020  28 14 3b 36 c2 3b 3e 88  e2 10 da 93 af 71 9a 06  |(.;6.;>......q..|
-00000030  1c 8d 97 04 05 ec e2 69  cf 28 20 0f ec 4c a7 f3  |.......i.( ..L..|
-00000040  18 4e 6b 5b 88 9c a9 17  03 00 00 21 5e 0b b4 2d  |.Nk[.......!^..-|
-00000050  a6 b5 0b 3a 86 de 8a e7  87 f3 4c f6 74 7e 0d 16  |...:......L.t~..|
-00000060  9b fc 0c 42 6b f4 9e 15  8b 6a c5 97 88 15 03 00  |...Bk....j......|
-00000070  00 16 f0 a4 e2 16 bf 81  05 ad 1d f5 1c 89 d9 ab  |................|
-00000080  48 23 ab 96 ea 92 aa cd                           |H#......|
+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/crypto/tls/testdata/Server-TLSv10-ECDHE-ECDSA-AES b/src/crypto/tls/testdata/Server-TLSv10-ECDHE-ECDSA-AES
index f81ffc2..9b8cb4d 100644
--- a/src/crypto/tls/testdata/Server-TLSv10-ECDHE-ECDSA-AES
+++ b/src/crypto/tls/testdata/Server-TLSv10-ECDHE-ECDSA-AES
@@ -1,13 +1,12 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 7d 01 00 00  79 03 01 65 14 3f 40 e4  |....}...y..e.?@.|
-00000010  2f 74 65 7e d0 c8 87 03  59 61 9d c3 84 5e c9 62  |/te~....Ya...^.b|
-00000020  e6 46 b8 0c 4a 5e 3f 33  43 a5 dd 00 00 04 c0 0a  |.F..J^?3C.......|
-00000030  00 ff 02 01 00 00 4b 00  0b 00 04 03 00 01 02 00  |......K.........|
-00000040  0a 00 3a 00 38 00 0e 00  0d 00 19 00 1c 00 0b 00  |..:.8...........|
-00000050  0c 00 1b 00 18 00 09 00  0a 00 1a 00 16 00 17 00  |................|
-00000060  08 00 06 00 07 00 14 00  15 00 04 00 05 00 12 00  |................|
-00000070  13 00 01 00 02 00 03 00  0f 00 10 00 11 00 0f 00  |................|
-00000080  01 01                                             |..|
+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  |................|
@@ -50,36 +49,36 @@
 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 01 3e  |A.Vk.Z...0...B.>|
-000002a0  79 81 6e 89 cd 3e 3f ec  e4 b5 75 17 28 ee fb 09  |y.n..>?...u.(...|
-000002b0  21 19 6f 3c e6 ca 1e f2  18 b6 47 f8 37 05 1c 85  |!.o<......G.7...|
-000002c0  0f a4 b8 6b 40 04 50 77  e3 05 9b 24 b8 93 e8 4d  |...k at .Pw...$...M|
-000002d0  ef 30 cd 51 90 58 a2 49  71 b3 3f b9 46 ab a9 72  |.0.Q.X.Iq.?.F..r|
-000002e0  02 42 01 58 ef 20 c1 0a  33 f8 fd 50 9e 65 f5 ef  |.B.X. ..3..P.e..|
-000002f0  f4 91 49 2d d2 de 66 2b  97 69 7d b1 d0 ef d6 91  |..I-..f+.i}.....|
-00000300  0f fc 57 2b 73 b9 49 01  33 d2 1b 5b 9a 2c 51 35  |..W+s.I.3..[.,Q5|
-00000310  0e eb 38 53 fa 20 07 84  52 b3 43 24 09 5a 32 c0  |..8S. ..R.C$.Z2.|
-00000320  32 17 34 6c 16 03 01 00  04 0e 00 00 00           |2.4l.........|
+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 31 74 f8 f6 18  |....F...BA.1t...|
-00000010  55 6a 9b 3b 78 0a 0e f0  c9 91 aa 8e 77 39 0a 88  |Uj.;x.......w9..|
-00000020  a4 d4 f6 04 9d de 89 18  b6 50 12 72 26 9c 8f e1  |.........P.r&...|
-00000030  f0 b2 e6 df ce 3b 46 be  e9 2a 9a e3 7f d1 d5 92  |.....;F..*......|
-00000040  ff e3 ae 0a 2d a1 3b 07  f6 04 59 14 03 01 00 01  |....-.;...Y.....|
-00000050  01 16 03 01 00 30 02 4f  df 41 30 97 6f f7 18 ca  |.....0.O.A0.o...|
-00000060  05 35 17 a1 a2 a5 71 61  b1 d8 dd 9a c6 f3 54 53  |.5....qa......TS|
-00000070  84 f6 fb 93 1e 0e 9d e7  fe 35 85 9e 73 d0 2e a1  |.........5..s...|
-00000080  a7 63 d9 40 c6 ac                                 |.c. at ..|
+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 07 7e 4e 9c 19  |..........0.~N..|
-00000010  f0 35 cd 02 b7 a6 0a 1a  b1 a8 11 a3 f9 b1 35 7b  |.5............5{|
-00000020  96 7f e6 e1 00 c6 6d 9e  e6 8a bb a2 b8 bd a3 9d  |......m.........|
-00000030  05 22 1b f1 f5 28 4a 00  6e f1 71 17 03 01 00 20  |."...(J.n.q.... |
-00000040  ad c7 4c dc f4 81 1a 39  3d 86 5e 8e f5 0d a3 33  |..L....9=.^....3|
-00000050  88 32 e7 be 8b 6a 8d 44  29 7b 47 fd e5 33 01 1e  |.2...j.D){G..3..|
-00000060  17 03 01 00 30 61 47 ee  ae 89 25 ac 85 3b 8a 84  |....0aG...%..;..|
-00000070  47 61 ea 3e 4c 70 57 07  d6 f1 1c 21 cb 44 7e de  |Ga.>LpW....!.D~.|
-00000080  b5 01 9e fb fe ad bc be  74 c0 65 a0 6b c1 0c 8c  |........t.e.k...|
-00000090  2b 00 24 c6 b7 15 03 01  00 20 b7 8b 6b e5 77 ab  |+.$...... ..k.w.|
-000000a0  f6 50 9e 88 4d 56 a8 25  8d 02 db cb 68 8b 3f 62  |.P..MV.%....h.?b|
-000000b0  be aa 02 24 75 b1 e5 4b  18 c9                    |...$u..K..|
+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/crypto/tls/testdata/Server-TLSv10-RSA-3DES b/src/crypto/tls/testdata/Server-TLSv10-RSA-3DES
index 55cb487..c0e6241 100644
--- a/src/crypto/tls/testdata/Server-TLSv10-RSA-3DES
+++ b/src/crypto/tls/testdata/Server-TLSv10-RSA-3DES
@@ -1,74 +1,79 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 36 01 00 00  32 03 01 35 4a e8 32 84  |....6...2..5J.2.|
-00000010  51 68 04 7e d0 0f 43 94  c7 5d 44 d2 95 a3 12 63  |Qh.~..C..]D....c|
-00000020  77 c5 ce 78 5a 25 a3 81  df c4 6b 00 00 04 00 0a  |w..xZ%....k.....|
+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 71 0b 00 02 6d 00  |..........q...m.|
-00000040  02 6a 00 02 67 30 82 02  63 30 82 01 cc a0 03 02  |.j..g0..c0......|
-00000050  01 02 02 09 00 a2 73 00  0c 81 00 cb f3 30 0d 06  |......s......0..|
-00000060  09 2a 86 48 86 f7 0d 01  01 0b 05 00 30 2b 31 17  |.*.H........0+1.|
-00000070  30 15 06 03 55 04 0a 13  0e 47 6f 6f 67 6c 65 20  |0...U....Google |
-00000080  54 45 53 54 49 4e 47 31  10 30 0e 06 03 55 04 03  |TESTING1.0...U..|
-00000090  13 07 47 6f 20 52 6f 6f  74 30 1e 17 0d 31 35 30  |..Go Root0...150|
-000000a0  31 30 31 30 30 30 30 30  30 5a 17 0d 32 35 30 31  |101000000Z..2501|
-000000b0  30 31 30 30 30 30 30 30  5a 30 26 31 17 30 15 06  |01000000Z0&1.0..|
-000000c0  03 55 04 0a 13 0e 47 6f  6f 67 6c 65 20 54 45 53  |.U....Google TES|
-000000d0  54 49 4e 47 31 0b 30 09  06 03 55 04 03 13 02 47  |TING1.0...U....G|
-000000e0  6f 30 81 9f 30 0d 06 09  2a 86 48 86 f7 0d 01 01  |o0..0...*.H.....|
-000000f0  01 05 00 03 81 8d 00 30  81 89 02 81 81 00 af 87  |.......0........|
-00000100  88 f6 20 1b 95 65 6c 14  ab 44 05 af 3b 45 14 e3  |.. ..el..D..;E..|
-00000110  b7 6d fd 00 63 4d 95 7f  fe 6a 62 35 86 c0 4a f9  |.m..cM...jb5..J.|
-00000120  18 7c f6 aa 25 5e 7a 64  31 66 00 ba f4 8e 92 af  |.|..%^zd1f......|
-00000130  c7 6b d8 76 d4 f3 5f 41  cb 6e 56 15 97 1b 97 c1  |.k.v.._A.nV.....|
-00000140  3c 12 39 21 66 3d 2b 16  d1 bc db 1c c0 a7 da b7  |<.9!f=+.........|
-00000150  ca ad ba da cb d5 21 50  ec de 8d ab d1 6b 81 4b  |......!P.....k.K|
-00000160  89 02 f3 c4 be c1 6c 89  b1 44 84 bd 21 d1 04 7d  |......l..D..!..}|
-00000170  9d 16 4d f9 82 15 f6 ef  fa d6 09 47 f2 fb 02 03  |..M........G....|
-00000180  01 00 01 a3 81 93 30 81  90 30 0e 06 03 55 1d 0f  |......0..0...U..|
-00000190  01 01 ff 04 04 03 02 05  a0 30 1d 06 03 55 1d 25  |.........0...U.%|
-000001a0  04 16 30 14 06 08 2b 06  01 05 05 07 03 01 06 08  |..0...+.........|
-000001b0  2b 06 01 05 05 07 03 02  30 0c 06 03 55 1d 13 01  |+.......0...U...|
-000001c0  01 ff 04 02 30 00 30 19  06 03 55 1d 0e 04 12 04  |....0.0...U.....|
-000001d0  10 12 50 8d 89 6f 1b d1  dc 54 4d 6e cb 69 5e 06  |..P..o...TMn.i^.|
-000001e0  f4 30 1b 06 03 55 1d 23  04 14 30 12 80 10 bf 3d  |.0...U.#..0....=|
-000001f0  b6 a9 66 f2 b8 40 cf ea  b4 03 78 48 1a 41 30 19  |..f.. at ....xH.A0.|
-00000200  06 03 55 1d 11 04 12 30  10 82 0e 65 78 61 6d 70  |..U....0...examp|
-00000210  6c 65 2e 67 6f 6c 61 6e  67 30 0d 06 09 2a 86 48  |le.golang0...*.H|
-00000220  86 f7 0d 01 01 0b 05 00  03 81 81 00 92 7c af 91  |.............|..|
-00000230  55 12 18 96 59 31 a6 48  40 d5 2d d5 ee bb 02 a0  |U...Y1.H at .-.....|
-00000240  f5 c2 1e 7c 9b b3 30 7d  3c dc 76 da 4f 3d c0 fa  |...|..0}<.v.O=..|
-00000250  ae 2d 33 24 6b 03 7b 1b  67 59 11 21 b5 11 bc 77  |.-3$k.{.gY.!...w|
-00000260  b9 d9 e0 6e a8 2d 2e 35  fa 64 5f 22 3e 63 10 6b  |...n.-.5.d_">c.k|
-00000270  be ff 14 86 6d 0d f0 15  31 a8 14 38 1e 3b 84 87  |....m...1..8.;..|
-00000280  2c cb 98 ed 51 76 b9 b1  4f dd db 9b 84 04 86 40  |,...Qv..O......@|
-00000290  fa 51 dd ba b4 8d eb e3  46 de 46 b9 4f 86 c7 f9  |.Q......F.F.O...|
-000002a0  a4 c2 41 34 ac cc f6 ea  b0 ab 39 18 16 03 01 00  |..A4......9.....|
-000002b0  04 0e 00 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 1f 4d 12 64 f2  |............M.d.|
-00000010  72 22 86 4a 16 05 3f d2  1b e5 ed a7 f1 19 c4 6d  |r".J..?........m|
-00000020  1d 3a 5c f6 46 8f b9 4d  9e c4 d4 19 95 0a 63 9f  |.:\.F..M......c.|
-00000030  8a 41 1f fc d5 98 45 ca  69 33 37 64 d5 c8 0e 5a  |.A....E.i37d...Z|
-00000040  12 9f 06 54 8a 61 8b 13  f0 d8 fb b9 97 fb cd 1d  |...T.a..........|
-00000050  bd 6c 88 cc 98 57 c3 66  3a 86 04 c9 b9 21 c6 f2  |.l...W.f:....!..|
-00000060  f3 43 7d 4e bf 28 d5 a2  d7 39 e0 78 cb eb b4 af  |.C}N.(...9.x....|
-00000070  21 0e ae 4c 16 9b b3 49  5f 81 02 55 59 97 d9 d2  |!..L...I_..UY...|
-00000080  c4 e2 4c be 0a a6 41 62  48 1d 66 14 03 01 00 01  |..L...AbH.f.....|
-00000090  01 16 03 01 00 28 9d e0  c3 31 82 c2 48 5d fb 47  |.....(...1..H].G|
-000000a0  85 60 d4 17 d2 4f 4d 3c  64 db e4 49 1f a9 66 93  |.`...OM<d..I..f.|
-000000b0  72 6c 32 06 a5 0c 1f db  64 6d 54 71 fd 30        |rl2.....dmTq.0|
+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 94 66 8f ad 8f  |..........(.f...|
-00000010  9f 00 72 f6 af 51 47 67  63 df 3f dd 17 09 0a c5  |..r..QGgc.?.....|
-00000020  bf f8 4d 66 39 f9 b5 47  01 f8 e8 6d ed b4 17 39  |..Mf9..G...m...9|
-00000030  ff 0a ca 17 03 01 00 18  68 93 94 51 12 b9 17 0b  |........h..Q....|
-00000040  d1 a0 22 fc cc c4 76 1a  1e 02 c6 20 5e 74 83 4c  |.."...v.... ^t.L|
-00000050  17 03 01 00 28 08 bd 86  07 84 90 78 bd 1d 90 ce  |....(......x....|
-00000060  09 80 bb d8 de fd 39 82  4b c4 0d 06 f3 65 f5 5b  |......9.K....e.[|
-00000070  3d c3 fd 69 80 1f 51 ce  1d 98 f1 05 fa 15 03 01  |=..i..Q.........|
-00000080  00 18 ed 48 04 21 85 77  d7 b6 29 e3 25 af ea ec  |...H.!.w..).%...|
-00000090  3e 41 82 a0 ca 7d 44 79  8a 0b                    |>A...}Dy..|
+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/crypto/tls/testdata/Server-TLSv10-RSA-AES b/src/crypto/tls/testdata/Server-TLSv10-RSA-AES
index 4671302..1670997 100644
--- a/src/crypto/tls/testdata/Server-TLSv10-RSA-AES
+++ b/src/crypto/tls/testdata/Server-TLSv10-RSA-AES
@@ -1,77 +1,82 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 36 01 00 00  32 03 01 8c 5a 87 31 6a  |....6...2...Z.1j|
-00000010  8c 7a d5 26 4b 94 17 27  fc a2 c0 5f b5 bc 3f 10  |.z.&K..'..._..?.|
-00000020  80 0e e0 1e 36 80 4b 91  61 77 d4 00 00 04 00 2f  |....6.K.aw...../|
+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 71 0b 00 02 6d 00  |..........q...m.|
-00000040  02 6a 00 02 67 30 82 02  63 30 82 01 cc a0 03 02  |.j..g0..c0......|
-00000050  01 02 02 09 00 a2 73 00  0c 81 00 cb f3 30 0d 06  |......s......0..|
-00000060  09 2a 86 48 86 f7 0d 01  01 0b 05 00 30 2b 31 17  |.*.H........0+1.|
-00000070  30 15 06 03 55 04 0a 13  0e 47 6f 6f 67 6c 65 20  |0...U....Google |
-00000080  54 45 53 54 49 4e 47 31  10 30 0e 06 03 55 04 03  |TESTING1.0...U..|
-00000090  13 07 47 6f 20 52 6f 6f  74 30 1e 17 0d 31 35 30  |..Go Root0...150|
-000000a0  31 30 31 30 30 30 30 30  30 5a 17 0d 32 35 30 31  |101000000Z..2501|
-000000b0  30 31 30 30 30 30 30 30  5a 30 26 31 17 30 15 06  |01000000Z0&1.0..|
-000000c0  03 55 04 0a 13 0e 47 6f  6f 67 6c 65 20 54 45 53  |.U....Google TES|
-000000d0  54 49 4e 47 31 0b 30 09  06 03 55 04 03 13 02 47  |TING1.0...U....G|
-000000e0  6f 30 81 9f 30 0d 06 09  2a 86 48 86 f7 0d 01 01  |o0..0...*.H.....|
-000000f0  01 05 00 03 81 8d 00 30  81 89 02 81 81 00 af 87  |.......0........|
-00000100  88 f6 20 1b 95 65 6c 14  ab 44 05 af 3b 45 14 e3  |.. ..el..D..;E..|
-00000110  b7 6d fd 00 63 4d 95 7f  fe 6a 62 35 86 c0 4a f9  |.m..cM...jb5..J.|
-00000120  18 7c f6 aa 25 5e 7a 64  31 66 00 ba f4 8e 92 af  |.|..%^zd1f......|
-00000130  c7 6b d8 76 d4 f3 5f 41  cb 6e 56 15 97 1b 97 c1  |.k.v.._A.nV.....|
-00000140  3c 12 39 21 66 3d 2b 16  d1 bc db 1c c0 a7 da b7  |<.9!f=+.........|
-00000150  ca ad ba da cb d5 21 50  ec de 8d ab d1 6b 81 4b  |......!P.....k.K|
-00000160  89 02 f3 c4 be c1 6c 89  b1 44 84 bd 21 d1 04 7d  |......l..D..!..}|
-00000170  9d 16 4d f9 82 15 f6 ef  fa d6 09 47 f2 fb 02 03  |..M........G....|
-00000180  01 00 01 a3 81 93 30 81  90 30 0e 06 03 55 1d 0f  |......0..0...U..|
-00000190  01 01 ff 04 04 03 02 05  a0 30 1d 06 03 55 1d 25  |.........0...U.%|
-000001a0  04 16 30 14 06 08 2b 06  01 05 05 07 03 01 06 08  |..0...+.........|
-000001b0  2b 06 01 05 05 07 03 02  30 0c 06 03 55 1d 13 01  |+.......0...U...|
-000001c0  01 ff 04 02 30 00 30 19  06 03 55 1d 0e 04 12 04  |....0.0...U.....|
-000001d0  10 12 50 8d 89 6f 1b d1  dc 54 4d 6e cb 69 5e 06  |..P..o...TMn.i^.|
-000001e0  f4 30 1b 06 03 55 1d 23  04 14 30 12 80 10 bf 3d  |.0...U.#..0....=|
-000001f0  b6 a9 66 f2 b8 40 cf ea  b4 03 78 48 1a 41 30 19  |..f.. at ....xH.A0.|
-00000200  06 03 55 1d 11 04 12 30  10 82 0e 65 78 61 6d 70  |..U....0...examp|
-00000210  6c 65 2e 67 6f 6c 61 6e  67 30 0d 06 09 2a 86 48  |le.golang0...*.H|
-00000220  86 f7 0d 01 01 0b 05 00  03 81 81 00 92 7c af 91  |.............|..|
-00000230  55 12 18 96 59 31 a6 48  40 d5 2d d5 ee bb 02 a0  |U...Y1.H at .-.....|
-00000240  f5 c2 1e 7c 9b b3 30 7d  3c dc 76 da 4f 3d c0 fa  |...|..0}<.v.O=..|
-00000250  ae 2d 33 24 6b 03 7b 1b  67 59 11 21 b5 11 bc 77  |.-3$k.{.gY.!...w|
-00000260  b9 d9 e0 6e a8 2d 2e 35  fa 64 5f 22 3e 63 10 6b  |...n.-.5.d_">c.k|
-00000270  be ff 14 86 6d 0d f0 15  31 a8 14 38 1e 3b 84 87  |....m...1..8.;..|
-00000280  2c cb 98 ed 51 76 b9 b1  4f dd db 9b 84 04 86 40  |,...Qv..O......@|
-00000290  fa 51 dd ba b4 8d eb e3  46 de 46 b9 4f 86 c7 f9  |.Q......F.F.O...|
-000002a0  a4 c2 41 34 ac cc f6 ea  b0 ab 39 18 16 03 01 00  |..A4......9.....|
-000002b0  04 0e 00 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 31 f5 2e e4 c7  |...........1....|
-00000010  f5 76 d6 f7 2d 1b 8d 4d  a9 2a 43 84 b2 0b 08 d6  |.v..-..M.*C.....|
-00000020  4d d9 9a eb 4b 01 49 6e  11 45 43 0d 31 a7 c3 66  |M...K.In.EC.1..f|
-00000030  da 1c 92 68 fb 3d 36 27  94 2f 67 ae 3d 31 a3 8f  |...h.=6'./g.=1..|
-00000040  01 5a d9 17 92 bc 20 7c  cb ae b4 ca 4c ce d4 a9  |.Z.... |....L...|
-00000050  2c 1d fe fc 3c a9 14 31  1d 65 08 d8 6e 8d ac 9d  |,...<..1.e..n...|
-00000060  21 ee 63 4a e2 da 3c 0e  b1 34 8f 6e 20 dd d4 d4  |!.cJ..<..4.n ...|
-00000070  d8 16 27 5d 02 54 e6 ec  5f 43 84 5b 21 24 ef 5d  |..'].T.._C.[!$.]|
-00000080  45 c4 2b 2c 98 7d 50 dc  0b fc 76 14 03 01 00 01  |E.+,.}P...v.....|
-00000090  01 16 03 01 00 30 ef 50  ea 3c e3 b7 a8 5b 9a d2  |.....0.P.<...[..|
-000000a0  11 69 0f d0 5e 79 c8 cb  68 4a ac 16 ef b4 de 1f  |.i..^y..hJ......|
-000000b0  21 0b 8e 91 cb 70 3f 02  bd 45 c1 34 02 e0 66 8a  |!....p?..E.4..f.|
-000000c0  00 ea 6c 5a 96 41                                 |..lZ.A|
+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 99 2c 65 32 5f  |..........0.,e2_|
-00000010  53 37 d8 c2 98 87 f4 68  b6 d7 52 6a 14 c7 df 6e  |S7.....h..Rj...n|
-00000020  bb ce ae 31 d4 04 24 4d  e9 c2 39 7b 68 a7 fa 90  |...1..$M..9{h...|
-00000030  c1 30 14 a2 20 c0 8d e1  2a dc 22 17 03 01 00 20  |.0.. ...*.".... |
-00000040  41 c5 03 05 20 53 e9 fa  0a 26 38 ab 84 6a 5e 36  |A... S...&8..j^6|
-00000050  1b 03 80 2f c3 5c 0b 2c  bd 7f 79 68 bb ab 4d 70  |.../.\.,..yh..Mp|
-00000060  17 03 01 00 30 a1 04 3e  f4 a2 54 7a e7 09 0f 20  |....0..>..Tz... |
-00000070  38 f8 9e bb 1b 61 28 bf  46 e8 75 56 b4 c3 93 b9  |8....a(.F.uV....|
-00000080  8c 18 3e 8e af 9f 59 1a  96 be db 61 80 56 c6 09  |..>...Y....a.V..|
-00000090  3c 21 02 37 d2 15 03 01  00 20 13 d1 81 7d ca 04  |<!.7..... ...}..|
-000000a0  2b c3 fc fa 06 5b b4 98  59 27 0d 07 2a 39 3c 6f  |+....[..Y'..*9<o|
-000000b0  8d 64 83 17 0f ba ec 22  21 36                    |.d....."!6|
+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/crypto/tls/testdata/Server-TLSv10-RSA-RC4 b/src/crypto/tls/testdata/Server-TLSv10-RSA-RC4
index b5cb479..d653561 100644
--- a/src/crypto/tls/testdata/Server-TLSv10-RSA-RC4
+++ b/src/crypto/tls/testdata/Server-TLSv10-RSA-RC4
@@ -1,71 +1,76 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 36 01 00 00  32 03 01 c5 fc 32 c0 09  |....6...2....2..|
-00000010  47 0b a9 f3 72 c9 6c 3a  e0 94 33 48 35 ac b9 3b  |G...r.l:..3H5..;|
-00000020  da 5f 8b 6e 0c 54 c3 16  f0 39 bd 00 00 04 00 05  |._.n.T...9......|
+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 71 0b 00 02 6d 00  |..........q...m.|
-00000040  02 6a 00 02 67 30 82 02  63 30 82 01 cc a0 03 02  |.j..g0..c0......|
-00000050  01 02 02 09 00 a2 73 00  0c 81 00 cb f3 30 0d 06  |......s......0..|
-00000060  09 2a 86 48 86 f7 0d 01  01 0b 05 00 30 2b 31 17  |.*.H........0+1.|
-00000070  30 15 06 03 55 04 0a 13  0e 47 6f 6f 67 6c 65 20  |0...U....Google |
-00000080  54 45 53 54 49 4e 47 31  10 30 0e 06 03 55 04 03  |TESTING1.0...U..|
-00000090  13 07 47 6f 20 52 6f 6f  74 30 1e 17 0d 31 35 30  |..Go Root0...150|
-000000a0  31 30 31 30 30 30 30 30  30 5a 17 0d 32 35 30 31  |101000000Z..2501|
-000000b0  30 31 30 30 30 30 30 30  5a 30 26 31 17 30 15 06  |01000000Z0&1.0..|
-000000c0  03 55 04 0a 13 0e 47 6f  6f 67 6c 65 20 54 45 53  |.U....Google TES|
-000000d0  54 49 4e 47 31 0b 30 09  06 03 55 04 03 13 02 47  |TING1.0...U....G|
-000000e0  6f 30 81 9f 30 0d 06 09  2a 86 48 86 f7 0d 01 01  |o0..0...*.H.....|
-000000f0  01 05 00 03 81 8d 00 30  81 89 02 81 81 00 af 87  |.......0........|
-00000100  88 f6 20 1b 95 65 6c 14  ab 44 05 af 3b 45 14 e3  |.. ..el..D..;E..|
-00000110  b7 6d fd 00 63 4d 95 7f  fe 6a 62 35 86 c0 4a f9  |.m..cM...jb5..J.|
-00000120  18 7c f6 aa 25 5e 7a 64  31 66 00 ba f4 8e 92 af  |.|..%^zd1f......|
-00000130  c7 6b d8 76 d4 f3 5f 41  cb 6e 56 15 97 1b 97 c1  |.k.v.._A.nV.....|
-00000140  3c 12 39 21 66 3d 2b 16  d1 bc db 1c c0 a7 da b7  |<.9!f=+.........|
-00000150  ca ad ba da cb d5 21 50  ec de 8d ab d1 6b 81 4b  |......!P.....k.K|
-00000160  89 02 f3 c4 be c1 6c 89  b1 44 84 bd 21 d1 04 7d  |......l..D..!..}|
-00000170  9d 16 4d f9 82 15 f6 ef  fa d6 09 47 f2 fb 02 03  |..M........G....|
-00000180  01 00 01 a3 81 93 30 81  90 30 0e 06 03 55 1d 0f  |......0..0...U..|
-00000190  01 01 ff 04 04 03 02 05  a0 30 1d 06 03 55 1d 25  |.........0...U.%|
-000001a0  04 16 30 14 06 08 2b 06  01 05 05 07 03 01 06 08  |..0...+.........|
-000001b0  2b 06 01 05 05 07 03 02  30 0c 06 03 55 1d 13 01  |+.......0...U...|
-000001c0  01 ff 04 02 30 00 30 19  06 03 55 1d 0e 04 12 04  |....0.0...U.....|
-000001d0  10 12 50 8d 89 6f 1b d1  dc 54 4d 6e cb 69 5e 06  |..P..o...TMn.i^.|
-000001e0  f4 30 1b 06 03 55 1d 23  04 14 30 12 80 10 bf 3d  |.0...U.#..0....=|
-000001f0  b6 a9 66 f2 b8 40 cf ea  b4 03 78 48 1a 41 30 19  |..f.. at ....xH.A0.|
-00000200  06 03 55 1d 11 04 12 30  10 82 0e 65 78 61 6d 70  |..U....0...examp|
-00000210  6c 65 2e 67 6f 6c 61 6e  67 30 0d 06 09 2a 86 48  |le.golang0...*.H|
-00000220  86 f7 0d 01 01 0b 05 00  03 81 81 00 92 7c af 91  |.............|..|
-00000230  55 12 18 96 59 31 a6 48  40 d5 2d d5 ee bb 02 a0  |U...Y1.H at .-.....|
-00000240  f5 c2 1e 7c 9b b3 30 7d  3c dc 76 da 4f 3d c0 fa  |...|..0}<.v.O=..|
-00000250  ae 2d 33 24 6b 03 7b 1b  67 59 11 21 b5 11 bc 77  |.-3$k.{.gY.!...w|
-00000260  b9 d9 e0 6e a8 2d 2e 35  fa 64 5f 22 3e 63 10 6b  |...n.-.5.d_">c.k|
-00000270  be ff 14 86 6d 0d f0 15  31 a8 14 38 1e 3b 84 87  |....m...1..8.;..|
-00000280  2c cb 98 ed 51 76 b9 b1  4f dd db 9b 84 04 86 40  |,...Qv..O......@|
-00000290  fa 51 dd ba b4 8d eb e3  46 de 46 b9 4f 86 c7 f9  |.Q......F.F.O...|
-000002a0  a4 c2 41 34 ac cc f6 ea  b0 ab 39 18 16 03 01 00  |..A4......9.....|
-000002b0  04 0e 00 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 6a ad 7f e3 26  |...........j...&|
-00000010  71 da 48 af 11 63 de 2e  e8 50 f9 6a be 04 3d 17  |q.H..c...P.j..=.|
-00000020  d1 29 fe 2c 7f b6 26 c1  7e 0b 18 1c 41 62 5c 91  |.).,..&.~...Ab\.|
-00000030  ee 26 9c 92 f5 d1 e9 29  e1 ca a7 01 6a 41 b9 00  |.&.....)....jA..|
-00000040  34 1d 5b c6 28 0e 1a 8f  32 c5 03 e7 a1 8f 89 1b  |4.[.(...2.......|
-00000050  af 13 22 2b 5b e8 76 2d  00 ac da 27 75 95 75 e7  |.."+[.v-...'u.u.|
-00000060  00 00 39 2c bf f2 01 57  e6 29 e3 26 b1 6b ae c5  |..9,...W.).&.k..|
-00000070  8d ce d2 36 b2 94 1f 9c  30 5e b2 16 3d 20 cf 4d  |...6....0^..= .M|
-00000080  88 f5 ac 4c 27 e3 f5 86  ef 9e dc 14 03 01 00 01  |...L'...........|
-00000090  01 16 03 01 00 24 48 d8  80 c4 37 22 31 99 53 30  |.....$H...7"1.S0|
-000000a0  5b 00 07 7e 87 2e 59 9a  d9 0c 42 9e dd ed da 89  |[..~..Y...B.....|
-000000b0  1a 1f cb ab 55 0c ba d9  a9 c0                    |....U.....|
+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 ae 00 c8 14 67  |..........$....g|
-00000010  4b b5 21 96 98 91 d6 27  40 9b 5e a5 86 53 56 f3  |K.!....'@.^..SV.|
-00000020  f6 dc 7e b2 49 78 4b 4d  57 7c 62 a5 f2 16 8f 17  |..~.IxKMW|b.....|
-00000030  03 01 00 21 34 e3 48 58  1c 67 fb 3a 46 28 5d a1  |...!4.HX.g.:F(].|
-00000040  19 66 58 b1 bb fb e7 17  71 07 3f 0a d0 7c c9 24  |.fX.....q.?..|.$|
-00000050  c7 ef 41 af 62 15 03 01  00 16 dd dc 16 dc 16 cc  |..A.b...........|
-00000060  0d f3 2c 29 00 c0 4f 01  68 05 92 a0 f7 ad e2 63  |..,)..O.h......c|
+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/crypto/tls/testdata/Server-TLSv11-RSA-RC4 b/src/crypto/tls/testdata/Server-TLSv11-RSA-RC4
index dc5e765..9237db0 100644
--- a/src/crypto/tls/testdata/Server-TLSv11-RSA-RC4
+++ b/src/crypto/tls/testdata/Server-TLSv11-RSA-RC4
@@ -1,71 +1,76 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 36 01 00 00  32 03 02 ff e1 a1 04 0b  |....6...2.......|
-00000010  c2 dc fb 7d 07 61 44 9b  00 67 fe 38 73 f5 fc 4e  |...}.aD..g.8s..N|
-00000020  35 94 0a d5 c1 d0 e7 54  dc 44 1f 00 00 04 00 05  |5......T.D......|
+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 71 0b 00 02 6d 00  |..........q...m.|
-00000040  02 6a 00 02 67 30 82 02  63 30 82 01 cc a0 03 02  |.j..g0..c0......|
-00000050  01 02 02 09 00 a2 73 00  0c 81 00 cb f3 30 0d 06  |......s......0..|
-00000060  09 2a 86 48 86 f7 0d 01  01 0b 05 00 30 2b 31 17  |.*.H........0+1.|
-00000070  30 15 06 03 55 04 0a 13  0e 47 6f 6f 67 6c 65 20  |0...U....Google |
-00000080  54 45 53 54 49 4e 47 31  10 30 0e 06 03 55 04 03  |TESTING1.0...U..|
-00000090  13 07 47 6f 20 52 6f 6f  74 30 1e 17 0d 31 35 30  |..Go Root0...150|
-000000a0  31 30 31 30 30 30 30 30  30 5a 17 0d 32 35 30 31  |101000000Z..2501|
-000000b0  30 31 30 30 30 30 30 30  5a 30 26 31 17 30 15 06  |01000000Z0&1.0..|
-000000c0  03 55 04 0a 13 0e 47 6f  6f 67 6c 65 20 54 45 53  |.U....Google TES|
-000000d0  54 49 4e 47 31 0b 30 09  06 03 55 04 03 13 02 47  |TING1.0...U....G|
-000000e0  6f 30 81 9f 30 0d 06 09  2a 86 48 86 f7 0d 01 01  |o0..0...*.H.....|
-000000f0  01 05 00 03 81 8d 00 30  81 89 02 81 81 00 af 87  |.......0........|
-00000100  88 f6 20 1b 95 65 6c 14  ab 44 05 af 3b 45 14 e3  |.. ..el..D..;E..|
-00000110  b7 6d fd 00 63 4d 95 7f  fe 6a 62 35 86 c0 4a f9  |.m..cM...jb5..J.|
-00000120  18 7c f6 aa 25 5e 7a 64  31 66 00 ba f4 8e 92 af  |.|..%^zd1f......|
-00000130  c7 6b d8 76 d4 f3 5f 41  cb 6e 56 15 97 1b 97 c1  |.k.v.._A.nV.....|
-00000140  3c 12 39 21 66 3d 2b 16  d1 bc db 1c c0 a7 da b7  |<.9!f=+.........|
-00000150  ca ad ba da cb d5 21 50  ec de 8d ab d1 6b 81 4b  |......!P.....k.K|
-00000160  89 02 f3 c4 be c1 6c 89  b1 44 84 bd 21 d1 04 7d  |......l..D..!..}|
-00000170  9d 16 4d f9 82 15 f6 ef  fa d6 09 47 f2 fb 02 03  |..M........G....|
-00000180  01 00 01 a3 81 93 30 81  90 30 0e 06 03 55 1d 0f  |......0..0...U..|
-00000190  01 01 ff 04 04 03 02 05  a0 30 1d 06 03 55 1d 25  |.........0...U.%|
-000001a0  04 16 30 14 06 08 2b 06  01 05 05 07 03 01 06 08  |..0...+.........|
-000001b0  2b 06 01 05 05 07 03 02  30 0c 06 03 55 1d 13 01  |+.......0...U...|
-000001c0  01 ff 04 02 30 00 30 19  06 03 55 1d 0e 04 12 04  |....0.0...U.....|
-000001d0  10 12 50 8d 89 6f 1b d1  dc 54 4d 6e cb 69 5e 06  |..P..o...TMn.i^.|
-000001e0  f4 30 1b 06 03 55 1d 23  04 14 30 12 80 10 bf 3d  |.0...U.#..0....=|
-000001f0  b6 a9 66 f2 b8 40 cf ea  b4 03 78 48 1a 41 30 19  |..f.. at ....xH.A0.|
-00000200  06 03 55 1d 11 04 12 30  10 82 0e 65 78 61 6d 70  |..U....0...examp|
-00000210  6c 65 2e 67 6f 6c 61 6e  67 30 0d 06 09 2a 86 48  |le.golang0...*.H|
-00000220  86 f7 0d 01 01 0b 05 00  03 81 81 00 92 7c af 91  |.............|..|
-00000230  55 12 18 96 59 31 a6 48  40 d5 2d d5 ee bb 02 a0  |U...Y1.H at .-.....|
-00000240  f5 c2 1e 7c 9b b3 30 7d  3c dc 76 da 4f 3d c0 fa  |...|..0}<.v.O=..|
-00000250  ae 2d 33 24 6b 03 7b 1b  67 59 11 21 b5 11 bc 77  |.-3$k.{.gY.!...w|
-00000260  b9 d9 e0 6e a8 2d 2e 35  fa 64 5f 22 3e 63 10 6b  |...n.-.5.d_">c.k|
-00000270  be ff 14 86 6d 0d f0 15  31 a8 14 38 1e 3b 84 87  |....m...1..8.;..|
-00000280  2c cb 98 ed 51 76 b9 b1  4f dd db 9b 84 04 86 40  |,...Qv..O......@|
-00000290  fa 51 dd ba b4 8d eb e3  46 de 46 b9 4f 86 c7 f9  |.Q......F.F.O...|
-000002a0  a4 c2 41 34 ac cc f6 ea  b0 ab 39 18 16 03 02 00  |..A4......9.....|
-000002b0  04 0e 00 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 4c e0 4d 6a 19  |...........L.Mj.|
-00000010  a2 72 2a 3d 41 14 a7 b3  0a 25 11 bf c9 9f cf 8c  |.r*=A....%......|
-00000020  3c 0b 01 49 aa f1 59 4b  60 ac e5 72 9b ec 20 41  |<..I..YK`..r.. A|
-00000030  2f 7e ef bf e0 fe 13 c0  1d fd 51 c5 08 c6 9a 9e  |/~........Q.....|
-00000040  74 88 c7 e3 36 99 73 fd  00 2d a2 6a bd 25 f2 d7  |t...6.s..-.j.%..|
-00000050  24 fd fd ab 0c e0 18 38  ba 7b f0 c9 c0 58 a6 d0  |$......8.{...X..|
-00000060  4e e2 59 70 aa f4 52 34  12 a0 ec a4 53 1e 8b ee  |N.Yp..R4....S...|
-00000070  3e bf a4 87 da 02 4c 95  bd 10 af e8 88 c9 ce 87  |>.....L.........|
-00000080  3c 9e 91 70 91 a0 85 18  84 e4 e0 14 03 02 00 01  |<..p............|
-00000090  01 16 03 02 00 24 c5 c0  27 71 49 ad ed 37 e6 5d  |.....$..'qI..7.]|
-000000a0  1b 78 3e 74 15 b7 61 e5  f3 af 1e d0 a2 85 b3 13  |.x>t..a.........|
-000000b0  6e 5e 9a c7 3d 47 32 4d  1b 8d                    |n^..=G2M..|
+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 31 22 76 4d 43  |..........$1"vMC|
-00000010  7a 8a 58 2c 7d 1c 41 39  bf 08 7e 82 17 55 52 b3  |z.X,}.A9..~..UR.|
-00000020  81 bd 7a f8 3c bf 9c 2b  f0 9b 3f 65 f5 42 15 17  |..z.<..+..?e.B..|
-00000030  03 02 00 21 b1 cc e5 56  16 70 58 0b 91 3c 8c 46  |...!...V.pX..<.F|
-00000040  0e 3b b6 fe 32 5d 2e b0  8c 6a 1c a0 82 c9 43 81  |.;..2]...j....C.|
-00000050  cf 07 25 47 c9 15 03 02  00 16 53 91 04 70 ba 03  |..%G......S..p..|
-00000060  53 69 57 86 3b 2f 8b 97  37 7c b8 85 46 b6 72 42  |SiW.;/..7|..F.rB|
+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/crypto/tls/testdata/Server-TLSv12-ALPN b/src/crypto/tls/testdata/Server-TLSv12-ALPN
index cbfeb42..106244d 100644
--- a/src/crypto/tls/testdata/Server-TLSv12-ALPN
+++ b/src/crypto/tls/testdata/Server-TLSv12-ALPN
@@ -1,109 +1,122 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 01 4c 01 00 01  48 03 03 44 3b 24 ee 2f  |....L...H..D;$./|
-00000010  63 3d ca bd 3e c5 bf a2  24 f1 59 c3 54 dc f0 43  |c=..>...$.Y.T..C|
-00000020  15 c4 51 f2 29 ea 1b ce  2c fe af 00 00 b6 c0 30  |..Q.)...,......0|
-00000030  c0 2c c0 28 c0 24 c0 14  c0 0a 00 a5 00 a3 00 a1  |.,.(.$..........|
-00000040  00 9f 00 6b 00 6a 00 69  00 68 00 39 00 38 00 37  |...k.j.i.h.9.8.7|
-00000050  00 36 00 88 00 87 00 86  00 85 c0 32 c0 2e c0 2a  |.6.........2...*|
-00000060  c0 26 c0 0f c0 05 00 9d  00 3d 00 35 00 84 c0 2f  |.&.......=.5.../|
-00000070  c0 2b c0 27 c0 23 c0 13  c0 09 00 a4 00 a2 00 a0  |.+.'.#..........|
-00000080  00 9e 00 67 00 40 00 3f  00 3e 00 33 00 32 00 31  |...g. at .?.>.3.2.1|
-00000090  00 30 00 9a 00 99 00 98  00 97 00 45 00 44 00 43  |.0.........E.D.C|
-000000a0  00 42 c0 31 c0 2d c0 29  c0 25 c0 0e c0 04 00 9c  |.B.1.-.).%......|
-000000b0  00 3c 00 2f 00 96 00 41  00 07 c0 11 c0 07 c0 0c  |.<./...A........|
-000000c0  c0 02 00 05 00 04 c0 12  c0 08 00 16 00 13 00 10  |................|
-000000d0  00 0d c0 0d c0 03 00 0a  00 15 00 12 00 0f 00 0c  |................|
-000000e0  00 09 00 ff 01 00 00 69  00 0b 00 04 03 00 01 02  |.......i........|
-000000f0  00 0a 00 1c 00 1a 00 17  00 19 00 1c 00 1b 00 18  |................|
-00000100  00 1a 00 16 00 0e 00 0d  00 0b 00 0c 00 09 00 0a  |................|
-00000110  00 23 00 00 00 0d 00 20  00 1e 06 01 06 02 06 03  |.#..... ........|
-00000120  05 01 05 02 05 03 04 01  04 02 04 03 03 01 03 02  |................|
-00000130  03 03 02 01 02 02 02 03  00 0f 00 01 01 00 10 00  |................|
-00000140  10 00 0e 06 70 72 6f 74  6f 32 06 70 72 6f 74 6f  |....proto2.proto|
-00000150  31                                                |1|
+00000000  16 03 01 01 8a 01 00 01  86 03 03 34 54 69 f3 d7  |...........4Ti..|
+00000010  20 9d 1d 74 db 72 e9 2f  51 7c c2 82 0a 9b cb 6d  | ..t.r./Q|.....m|
+00000020  90 b4 8e a2 1f 2f c7 66  74 8f 33 00 00 d6 c0 30  |...../.ft.3....0|
+00000030  c0 2c c0 28 c0 24 c0 14  c0 0a c0 22 c0 21 c0 20  |.,.(.$.....".!. |
+00000040  00 a5 00 a3 00 a1 00 9f  00 6b 00 6a 00 69 00 68  |.........k.j.i.h|
+00000050  00 39 00 38 00 37 00 36  00 88 00 87 00 86 00 85  |.9.8.7.6........|
+00000060  c0 32 c0 2e c0 2a c0 26  c0 0f c0 05 00 9d 00 3d  |.2...*.&.......=|
+00000070  00 35 00 84 c0 2f c0 2b  c0 27 c0 23 c0 13 c0 09  |.5.../.+.'.#....|
+00000080  c0 1f c0 1e c0 1d 00 a4  00 a2 00 a0 00 9e 00 67  |...............g|
+00000090  00 40 00 3f 00 3e 00 33  00 32 00 31 00 30 00 9a  |. at .?.>.3.2.1.0..|
+000000a0  00 99 00 98 00 97 00 45  00 44 00 43 00 42 c0 31  |.......E.D.C.B.1|
+000000b0  c0 2d c0 29 c0 25 c0 0e  c0 04 00 9c 00 3c 00 2f  |.-.).%.......<./|
+000000c0  00 96 00 41 00 07 c0 11  c0 07 c0 0c c0 02 00 05  |...A............|
+000000d0  00 04 c0 12 c0 08 c0 1c  c0 1b c0 1a 00 16 00 13  |................|
+000000e0  00 10 00 0d c0 0d c0 03  00 0a 00 15 00 12 00 0f  |................|
+000000f0  00 0c 00 09 00 14 00 11  00 0e 00 0b 00 08 00 06  |................|
+00000100  00 03 00 ff 01 00 00 87  00 0b 00 04 03 00 01 02  |................|
+00000110  00 0a 00 3a 00 38 00 0e  00 0d 00 19 00 1c 00 0b  |...:.8..........|
+00000120  00 0c 00 1b 00 18 00 09  00 0a 00 1a 00 16 00 17  |................|
+00000130  00 08 00 06 00 07 00 14  00 15 00 04 00 05 00 12  |................|
+00000140  00 13 00 01 00 02 00 03  00 0f 00 10 00 11 00 23  |...............#|
+00000150  00 00 00 0d 00 20 00 1e  06 01 06 02 06 03 05 01  |..... ..........|
+00000160  05 02 05 03 04 01 04 02  04 03 03 01 03 02 03 03  |................|
+00000170  02 01 02 02 02 03 00 0f  00 01 01 00 10 00 10 00  |................|
+00000180  0e 06 70 72 6f 74 6f 32  06 70 72 6f 74 6f 31     |..proto2.proto1|
 >>> Flow 2 (server to client)
 00000000  16 03 03 00 42 02 00 00  3e 03 03 00 00 00 00 00  |....B...>.......|
 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 30 00 00  |.............0..|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 c0 14 00 00  |................|
 00000030  16 00 23 00 00 ff 01 00  01 00 00 10 00 09 00 07  |..#.............|
-00000040  06 70 72 6f 74 6f 31 16  03 03 02 71 0b 00 02 6d  |.proto1....q...m|
-00000050  00 02 6a 00 02 67 30 82  02 63 30 82 01 cc a0 03  |..j..g0..c0.....|
-00000060  02 01 02 02 09 00 a2 73  00 0c 81 00 cb f3 30 0d  |.......s......0.|
-00000070  06 09 2a 86 48 86 f7 0d  01 01 0b 05 00 30 2b 31  |..*.H........0+1|
-00000080  17 30 15 06 03 55 04 0a  13 0e 47 6f 6f 67 6c 65  |.0...U....Google|
-00000090  20 54 45 53 54 49 4e 47  31 10 30 0e 06 03 55 04  | TESTING1.0...U.|
-000000a0  03 13 07 47 6f 20 52 6f  6f 74 30 1e 17 0d 31 35  |...Go Root0...15|
-000000b0  30 31 30 31 30 30 30 30  30 30 5a 17 0d 32 35 30  |0101000000Z..250|
-000000c0  31 30 31 30 30 30 30 30  30 5a 30 26 31 17 30 15  |101000000Z0&1.0.|
-000000d0  06 03 55 04 0a 13 0e 47  6f 6f 67 6c 65 20 54 45  |..U....Google TE|
-000000e0  53 54 49 4e 47 31 0b 30  09 06 03 55 04 03 13 02  |STING1.0...U....|
-000000f0  47 6f 30 81 9f 30 0d 06  09 2a 86 48 86 f7 0d 01  |Go0..0...*.H....|
-00000100  01 01 05 00 03 81 8d 00  30 81 89 02 81 81 00 af  |........0.......|
-00000110  87 88 f6 20 1b 95 65 6c  14 ab 44 05 af 3b 45 14  |... ..el..D..;E.|
-00000120  e3 b7 6d fd 00 63 4d 95  7f fe 6a 62 35 86 c0 4a  |..m..cM...jb5..J|
-00000130  f9 18 7c f6 aa 25 5e 7a  64 31 66 00 ba f4 8e 92  |..|..%^zd1f.....|
-00000140  af c7 6b d8 76 d4 f3 5f  41 cb 6e 56 15 97 1b 97  |..k.v.._A.nV....|
-00000150  c1 3c 12 39 21 66 3d 2b  16 d1 bc db 1c c0 a7 da  |.<.9!f=+........|
-00000160  b7 ca ad ba da cb d5 21  50 ec de 8d ab d1 6b 81  |.......!P.....k.|
-00000170  4b 89 02 f3 c4 be c1 6c  89 b1 44 84 bd 21 d1 04  |K......l..D..!..|
-00000180  7d 9d 16 4d f9 82 15 f6  ef fa d6 09 47 f2 fb 02  |}..M........G...|
-00000190  03 01 00 01 a3 81 93 30  81 90 30 0e 06 03 55 1d  |.......0..0...U.|
-000001a0  0f 01 01 ff 04 04 03 02  05 a0 30 1d 06 03 55 1d  |..........0...U.|
-000001b0  25 04 16 30 14 06 08 2b  06 01 05 05 07 03 01 06  |%..0...+........|
-000001c0  08 2b 06 01 05 05 07 03  02 30 0c 06 03 55 1d 13  |.+.......0...U..|
-000001d0  01 01 ff 04 02 30 00 30  19 06 03 55 1d 0e 04 12  |.....0.0...U....|
-000001e0  04 10 12 50 8d 89 6f 1b  d1 dc 54 4d 6e cb 69 5e  |...P..o...TMn.i^|
-000001f0  06 f4 30 1b 06 03 55 1d  23 04 14 30 12 80 10 bf  |..0...U.#..0....|
-00000200  3d b6 a9 66 f2 b8 40 cf  ea b4 03 78 48 1a 41 30  |=..f.. at ....xH.A0|
-00000210  19 06 03 55 1d 11 04 12  30 10 82 0e 65 78 61 6d  |...U....0...exam|
-00000220  70 6c 65 2e 67 6f 6c 61  6e 67 30 0d 06 09 2a 86  |ple.golang0...*.|
-00000230  48 86 f7 0d 01 01 0b 05  00 03 81 81 00 92 7c af  |H.............|.|
-00000240  91 55 12 18 96 59 31 a6  48 40 d5 2d d5 ee bb 02  |.U...Y1.H at .-....|
-00000250  a0 f5 c2 1e 7c 9b b3 30  7d 3c dc 76 da 4f 3d c0  |....|..0}<.v.O=.|
-00000260  fa ae 2d 33 24 6b 03 7b  1b 67 59 11 21 b5 11 bc  |..-3$k.{.gY.!...|
-00000270  77 b9 d9 e0 6e a8 2d 2e  35 fa 64 5f 22 3e 63 10  |w...n.-.5.d_">c.|
-00000280  6b be ff 14 86 6d 0d f0  15 31 a8 14 38 1e 3b 84  |k....m...1..8.;.|
-00000290  87 2c cb 98 ed 51 76 b9  b1 4f dd db 9b 84 04 86  |.,...Qv..O......|
-000002a0  40 fa 51 dd ba b4 8d eb  e3 46 de 46 b9 4f 86 c7  |@.Q......F.F.O..|
-000002b0  f9 a4 c2 41 34 ac cc f6  ea b0 ab 39 18 16 03 03  |...A4......9....|
-000002c0  00 cd 0c 00 00 c9 03 00  17 41 04 1e 18 37 ef 0d  |.........A...7..|
-000002d0  19 51 88 35 75 71 b5 e5  54 5b 12 2e 8f 09 67 fd  |.Q.5uq..T[....g.|
-000002e0  a7 24 20 3e b2 56 1c ce  97 28 5e f8 2b 2d 4f 9e  |.$ >.V...(^.+-O.|
-000002f0  f1 07 9f 6c 4b 5b 83 56  e2 32 42 e9 58 b6 d7 49  |...lK[.V.2B.X..I|
-00000300  a6 b5 68 1a 41 03 56 6b  dc 5a 89 05 01 00 80 40  |..h.A.Vk.Z.....@|
-00000310  93 b2 1f 79 3d 56 c0 ae  94 87 c0 a7 28 ef 1d 15  |...y=V......(...|
-00000320  be 4b fb 66 e0 60 2c a3  57 ee 56 7d d6 89 b8 8e  |.K.f.`,.W.V}....|
-00000330  8f 0f 3f 1b c6 9f a4 1d  34 60 b6 9c e9 9b a9 27  |..?.....4`.....'|
-00000340  d0 45 7b 04 71 2d db 9c  67 1b d5 d4 fe 19 69 59  |.E{.q-..g.....iY|
-00000350  71 8a 35 75 33 a8 c9 f2  4d c4 8f 40 17 a7 25 53  |q.5u3...M.. at ..%S|
-00000360  57 c5 cd ee df a9 3b a3  61 ab e2 a2 ca de 5c 08  |W.....;.a.....\.|
-00000370  3d 5b a2 ef cd c8 bc 16  1f 1d 0f 83 9e b7 20 f5  |=[............ .|
-00000380  89 3f 09 ba 2e da 12 34  81 e5 2f 8d 3c 90 89 16  |.?.....4../.<...|
-00000390  03 03 00 04 0e 00 00 00                           |........|
+00000040  06 70 72 6f 74 6f 31 16  03 03 02 be 0b 00 02 ba  |.proto1.........|
+00000050  00 02 b7 00 02 b4 30 82  02 b0 30 82 02 19 a0 03  |......0...0.....|
+00000060  02 01 02 02 09 00 85 b0  bb a4 8a 7f b8 ca 30 0d  |..............0.|
+00000070  06 09 2a 86 48 86 f7 0d  01 01 05 05 00 30 45 31  |..*.H........0E1|
+00000080  0b 30 09 06 03 55 04 06  13 02 41 55 31 13 30 11  |.0...U....AU1.0.|
+00000090  06 03 55 04 08 13 0a 53  6f 6d 65 2d 53 74 61 74  |..U....Some-Stat|
+000000a0  65 31 21 30 1f 06 03 55  04 0a 13 18 49 6e 74 65  |e1!0...U....Inte|
+000000b0  72 6e 65 74 20 57 69 64  67 69 74 73 20 50 74 79  |rnet Widgits Pty|
+000000c0  20 4c 74 64 30 1e 17 0d  31 30 30 34 32 34 30 39  | Ltd0...10042409|
+000000d0  30 39 33 38 5a 17 0d 31  31 30 34 32 34 30 39 30  |0938Z..110424090|
+000000e0  39 33 38 5a 30 45 31 0b  30 09 06 03 55 04 06 13  |938Z0E1.0...U...|
+000000f0  02 41 55 31 13 30 11 06  03 55 04 08 13 0a 53 6f  |.AU1.0...U....So|
+00000100  6d 65 2d 53 74 61 74 65  31 21 30 1f 06 03 55 04  |me-State1!0...U.|
+00000110  0a 13 18 49 6e 74 65 72  6e 65 74 20 57 69 64 67  |...Internet Widg|
+00000120  69 74 73 20 50 74 79 20  4c 74 64 30 81 9f 30 0d  |its Pty Ltd0..0.|
+00000130  06 09 2a 86 48 86 f7 0d  01 01 01 05 00 03 81 8d  |..*.H...........|
+00000140  00 30 81 89 02 81 81 00  bb 79 d6 f5 17 b5 e5 bf  |.0.......y......|
+00000150  46 10 d0 dc 69 be e6 2b  07 43 5a d0 03 2d 8a 7a  |F...i..+.CZ..-.z|
+00000160  43 85 b7 14 52 e7 a5 65  4c 2c 78 b8 23 8c b5 b4  |C...R..eL,x.#...|
+00000170  82 e5 de 1f 95 3b 7e 62  a5 2c a5 33 d6 fe 12 5c  |.....;~b.,.3...\|
+00000180  7a 56 fc f5 06 bf fa 58  7b 26 3f b5 cd 04 d3 d0  |zV.....X{&?.....|
+00000190  c9 21 96 4a c7 f4 54 9f  5a bf ef 42 71 00 fe 18  |.!.J..T.Z..Bq...|
+000001a0  99 07 7f 7e 88 7d 7d f1  04 39 c4 a2 2e db 51 c9  |...~.}}..9....Q.|
+000001b0  7c e3 c0 4c 3b 32 66 01  cf af b1 1d b8 71 9a 1d  ||..L;2f......q..|
+000001c0  db db 89 6b ae da 2d 79  02 03 01 00 01 a3 81 a7  |...k..-y........|
+000001d0  30 81 a4 30 1d 06 03 55  1d 0e 04 16 04 14 b1 ad  |0..0...U........|
+000001e0  e2 85 5a cf cb 28 db 69  ce 23 69 de d3 26 8e 18  |..Z..(.i.#i..&..|
+000001f0  88 39 30 75 06 03 55 1d  23 04 6e 30 6c 80 14 b1  |.90u..U.#.n0l...|
+00000200  ad e2 85 5a cf cb 28 db  69 ce 23 69 de d3 26 8e  |...Z..(.i.#i..&.|
+00000210  18 88 39 a1 49 a4 47 30  45 31 0b 30 09 06 03 55  |..9.I.G0E1.0...U|
+00000220  04 06 13 02 41 55 31 13  30 11 06 03 55 04 08 13  |....AU1.0...U...|
+00000230  0a 53 6f 6d 65 2d 53 74  61 74 65 31 21 30 1f 06  |.Some-State1!0..|
+00000240  03 55 04 0a 13 18 49 6e  74 65 72 6e 65 74 20 57  |.U....Internet W|
+00000250  69 64 67 69 74 73 20 50  74 79 20 4c 74 64 82 09  |idgits Pty Ltd..|
+00000260  00 85 b0 bb a4 8a 7f b8  ca 30 0c 06 03 55 1d 13  |.........0...U..|
+00000270  04 05 30 03 01 01 ff 30  0d 06 09 2a 86 48 86 f7  |..0....0...*.H..|
+00000280  0d 01 01 05 05 00 03 81  81 00 08 6c 45 24 c7 6b  |...........lE$.k|
+00000290  b1 59 ab 0c 52 cc f2 b0  14 d7 87 9d 7a 64 75 b5  |.Y..R.......zdu.|
+000002a0  5a 95 66 e4 c5 2b 8e ae  12 66 1f eb 4f 38 b3 6e  |Z.f..+...f..O8.n|
+000002b0  60 d3 92 fd f7 41 08 b5  25 13 b1 18 7a 24 fb 30  |`....A..%...z$.0|
+000002c0  1d ba ed 98 b9 17 ec e7  d7 31 59 db 95 d3 1d 78  |.........1Y....x|
+000002d0  ea 50 56 5c d5 82 5a 2d  5a 5f 33 c4 b6 d8 c9 75  |.PV\..Z-Z_3....u|
+000002e0  90 96 8c 0f 52 98 b5 cd  98 1f 89 20 5f f2 a0 1c  |....R...... _...|
+000002f0  a3 1b 96 94 dd a9 fd 57  e9 70 e8 26 6d 71 99 9b  |.......W.p.&mq..|
+00000300  26 6e 38 50 29 6c 90 a7  bd d9 16 03 03 00 cd 0c  |&n8P)l..........|
+00000310  00 00 c9 03 00 17 41 04  1e 18 37 ef 0d 19 51 88  |......A...7...Q.|
+00000320  35 75 71 b5 e5 54 5b 12  2e 8f 09 67 fd a7 24 20  |5uq..T[....g..$ |
+00000330  3e b2 56 1c ce 97 28 5e  f8 2b 2d 4f 9e f1 07 9f  |>.V...(^.+-O....|
+00000340  6c 4b 5b 83 56 e2 32 42  e9 58 b6 d7 49 a6 b5 68  |lK[.V.2B.X..I..h|
+00000350  1a 41 03 56 6b dc 5a 89  04 01 00 80 2d a0 6e 47  |.A.Vk.Z.....-.nG|
+00000360  93 a2 19 17 32 f5 42 58  93 f6 4f d4 e9 4d a4 0f  |....2.BX..O..M..|
+00000370  fe 4e d7 2c 62 b6 fb 83  37 a3 09 60 4b 69 e2 4c  |.N.,b...7..`Ki.L|
+00000380  fc b8 4c d1 a6 9a 89 a0  c5 76 f5 62 b7 e8 eb c2  |..L......v.b....|
+00000390  fa 0f 0e 61 86 bc 70 da  13 72 8d 87 94 16 9a 8d  |...a..p..r......|
+000003a0  5f 80 82 92 77 37 4f 9e  55 5d dc 35 42 a3 75 5c  |_...w7O.U].5B.u\|
+000003b0  ec a4 58 78 66 97 97 da  49 67 2e b6 7e 11 de fb  |..Xxf...Ig..~...|
+000003c0  e3 8f e8 bf 1d 91 1e 91  20 1b 2a df c6 58 e4 82  |........ .*..X..|
+000003d0  ce 37 dd 6f a5 ac 51 3d  65 db 3f f5 16 03 03 00  |.7.o..Q=e.?.....|
+000003e0  04 0e 00 00 00                                    |.....|
 >>> Flow 3 (client to server)
-00000000  16 03 03 00 46 10 00 00  42 41 04 8b a2 de a6 1e  |....F...BA......|
-00000010  d9 22 3c 03 4a be 49 2f  40 e3 1e e0 b4 76 7f 78  |."<.J.I/@....v.x|
-00000020  96 22 8d 8d c9 45 3b d8  7a ce e3 16 3d 37 ec 80  |."...E;.z...=7..|
-00000030  aa 3f d5 19 de c1 2c 7b  7f eb 3c fc 5d c3 52 3b  |.?....,{..<.].R;|
-00000040  d4 22 25 1c c7 1f 39 c5  23 bd 73 14 03 03 00 01  |."%...9.#.s.....|
-00000050  01 16 03 03 00 28 c8 53  0a ad c2 f6 7e 18 08 a3  |.....(.S....~...|
-00000060  29 27 20 1c 6c 1d 6c d8  8f 05 31 de e6 ab 7f 22  |)' .l.l...1...."|
-00000070  93 6a fb ef b0 f8 43 a9  d3 4f 9d 04 b5 9a        |.j....C..O....|
+00000000  16 03 03 00 46 10 00 00  42 41 04 f3 fc ea d8 50  |....F...BA.....P|
+00000010  e6 15 b0 e7 11 c7 6d ee  09 ad 80 d5 54 eb 4f 62  |......m.....T.Ob|
+00000020  7d bb a7 2d 28 0c 66 33  42 09 cf 2b 58 f8 58 41  |}..-(.f3B..+X.XA|
+00000030  bd 46 51 0a f0 7d 8c 0c  98 9e 26 77 20 fd 5e c1  |.FQ..}....&w .^.|
+00000040  a9 b3 e5 c3 6c 05 97 e3  81 fd db 14 03 03 00 01  |....l...........|
+00000050  01 16 03 03 00 40 02 2a  28 41 e3 9c 5d 45 d4 45  |..... at .*(A..]E.E|
+00000060  51 8c 7a c0 ba b1 8e a4  84 2c f3 83 cd c4 55 5c  |Q.z......,....U\|
+00000070  d6 5c 6f 72 ab 89 7a c6  d7 9c 2a 54 f0 c4 20 ee  |.\or..z...*T.. .|
+00000080  37 74 9b b6 8c f7 e4 37  2c eb d4 9f 5c 5e 55 a0  |7t.....7,...\^U.|
+00000090  e2 5a fe 1e c8 67                                 |.Z...g|
 >>> Flow 4 (server to client)
-00000000  16 03 03 00 82 04 00 00  7e 00 00 00 00 00 78 50  |........~.....xP|
-00000010  46 ad c1 db a8 38 86 7b  2b bb fd d0 c3 42 3e 00  |F....8.{+....B>.|
-00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 94  |................|
-00000030  6f ec 80 83 61 8e d9 64  ac a2 ee 3b 69 31 79 e1  |o...a..d...;i1y.|
-00000040  53 0a 92 1d aa 23 09 c2  49 02 2d 0d 1d c1 63 d6  |S....#..I.-...c.|
-00000050  21 56 c7 24 02 28 d5 f1  11 b0 e7 1b 4a 7c 55 af  |!V.$.(......J|U.|
-00000060  1b c8 32 4c 5b 33 94 b0  ed b0 2f 52 c4 52 81 ee  |..2L[3..../R.R..|
-00000070  60 6f 66 fb f5 db dd f9  1e 30 11 d4 ca 75 0e 2b  |`of......0...u.+|
-00000080  ff d0 e5 f2 68 a4 e7 14  03 03 00 01 01 16 03 03  |....h...........|
-00000090  00 28 00 00 00 00 00 00  00 00 67 3b 4a ba f3 27  |.(........g;J..'|
-000000a0  c8 45 94 68 36 5a 40 e1  dc 67 9b d4 45 58 e9 24  |.E.h6Z at ..g..EX.$|
-000000b0  31 85 3a f8 5d cb 84 8e  64 05 17 03 03 00 25 00  |1.:.]...d.....%.|
-000000c0  00 00 00 00 00 00 01 35  d9 ba 0a e2 3e fd a2 80  |.......5....>...|
-000000d0  10 0e 38 7b ad 85 85 48  6a 2a ab 2a 46 c3 59 96  |..8{...Hj*.*F.Y.|
-000000e0  fd 75 11 5d 15 03 03 00  1a 00 00 00 00 00 00 00  |.u.]............|
-000000f0  02 0b 4d a5 89 4d 86 47  14 60 27 f8 09 bc c9 4d  |..M..M.G.`'....M|
-00000100  00 31 cb                                          |.1.|
+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 8b c0 ef ba 59 31 75  33 96 f1 f8 c9 e1 ef 30  |.....Y1u3......0|
+00000030  00 a3 a9 1d ab c8 4b 29  94 f2 c8 c8 8d 03 57 ab  |......K)......W.|
+00000040  56 df 0f 4e 0d 30 13 09  c9 e4 fa 51 4e b3 26 ad  |V..N.0.....QN.&.|
+00000050  43 9f ae 62 d5 59 23 05  9b 69 8f 5b a8 ba 39 f1  |C..b.Y#..i.[..9.|
+00000060  90 84 35 bf 8f 8d d5 39  93 98 ee b9 75 03 3f 91  |..5....9....u.?.|
+00000070  e8 56 0b cb 44 a6 7a 14  03 03 00 01 01 16 03 03  |.V..D.z.........|
+00000080  00 40 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |. at ..............|
+00000090  00 00 f9 a0 8e 23 34 f1  61 15 a8 4e ae c4 f3 2a  |.....#4.a..N...*|
+000000a0  a6 f8 ee 1b 65 c4 c0 ff  93 14 74 ed 82 ae 48 a8  |....e.....t...H.|
+000000b0  42 fb a9 24 5d dd fd 98  b8 65 73 03 88 99 e1 ed  |B..$]....es.....|
+000000c0  02 95 17 03 03 00 40 00  00 00 00 00 00 00 00 00  |...... at .........|
+000000d0  00 00 00 00 00 00 00 b9  b3 f5 41 84 3b 2a a9 c3  |..........A.;*..|
+000000e0  9c e3 d4 38 90 76 c1 8c  f0 4f 10 1b 04 b5 07 fe  |...8.v...O......|
+000000f0  79 3d 7b 77 a4 17 0f 4e  df 64 70 70 9e 34 8e b6  |y={w...N.dpp.4..|
+00000100  db b2 b6 fd 41 fe b3 15  03 03 00 30 00 00 00 00  |....A......0....|
+00000110  00 00 00 00 00 00 00 00  00 00 00 00 02 73 de fe  |.............s..|
+00000120  fa 4b 69 6d 30 69 79 96  7e 4f 2f 04 67 36 96 27  |.Kim0iy.~O/.g6.'|
+00000130  67 23 2b dc 7a c4 6c 34  ea fc 79 fd              |g#+.z.l4..y.|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-ALPN-NoMatch b/src/crypto/tls/testdata/Server-TLSv12-ALPN-NoMatch
index af75445..db5881b 100644
--- a/src/crypto/tls/testdata/Server-TLSv12-ALPN-NoMatch
+++ b/src/crypto/tls/testdata/Server-TLSv12-ALPN-NoMatch
@@ -1,108 +1,121 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 01 4c 01 00 01  48 03 03 1d 1a f7 e5 ad  |....L...H.......|
-00000010  a4 5c fd 61 b4 c2 25 33  c7 b9 fc fb 2b a5 4b fe  |.\.a..%3....+.K.|
-00000020  16 84 55 4b 9f 68 73 61  b8 92 4d 00 00 b6 c0 30  |..UK.hsa..M....0|
-00000030  c0 2c c0 28 c0 24 c0 14  c0 0a 00 a5 00 a3 00 a1  |.,.(.$..........|
-00000040  00 9f 00 6b 00 6a 00 69  00 68 00 39 00 38 00 37  |...k.j.i.h.9.8.7|
-00000050  00 36 00 88 00 87 00 86  00 85 c0 32 c0 2e c0 2a  |.6.........2...*|
-00000060  c0 26 c0 0f c0 05 00 9d  00 3d 00 35 00 84 c0 2f  |.&.......=.5.../|
-00000070  c0 2b c0 27 c0 23 c0 13  c0 09 00 a4 00 a2 00 a0  |.+.'.#..........|
-00000080  00 9e 00 67 00 40 00 3f  00 3e 00 33 00 32 00 31  |...g. at .?.>.3.2.1|
-00000090  00 30 00 9a 00 99 00 98  00 97 00 45 00 44 00 43  |.0.........E.D.C|
-000000a0  00 42 c0 31 c0 2d c0 29  c0 25 c0 0e c0 04 00 9c  |.B.1.-.).%......|
-000000b0  00 3c 00 2f 00 96 00 41  00 07 c0 11 c0 07 c0 0c  |.<./...A........|
-000000c0  c0 02 00 05 00 04 c0 12  c0 08 00 16 00 13 00 10  |................|
-000000d0  00 0d c0 0d c0 03 00 0a  00 15 00 12 00 0f 00 0c  |................|
-000000e0  00 09 00 ff 01 00 00 69  00 0b 00 04 03 00 01 02  |.......i........|
-000000f0  00 0a 00 1c 00 1a 00 17  00 19 00 1c 00 1b 00 18  |................|
-00000100  00 1a 00 16 00 0e 00 0d  00 0b 00 0c 00 09 00 0a  |................|
-00000110  00 23 00 00 00 0d 00 20  00 1e 06 01 06 02 06 03  |.#..... ........|
-00000120  05 01 05 02 05 03 04 01  04 02 04 03 03 01 03 02  |................|
-00000130  03 03 02 01 02 02 02 03  00 0f 00 01 01 00 10 00  |................|
-00000140  10 00 0e 06 70 72 6f 74  6f 32 06 70 72 6f 74 6f  |....proto2.proto|
-00000150  31                                                |1|
+00000000  16 03 01 01 8a 01 00 01  86 03 03 0a a8 82 53 61  |..............Sa|
+00000010  68 e0 83 91 71 36 f9 c1  19 ff e8 09 fc 21 9f 03  |h...q6.......!..|
+00000020  31 f3 87 4a 04 8c 3d c2  6e 00 32 00 00 d6 c0 30  |1..J..=.n.2....0|
+00000030  c0 2c c0 28 c0 24 c0 14  c0 0a c0 22 c0 21 c0 20  |.,.(.$.....".!. |
+00000040  00 a5 00 a3 00 a1 00 9f  00 6b 00 6a 00 69 00 68  |.........k.j.i.h|
+00000050  00 39 00 38 00 37 00 36  00 88 00 87 00 86 00 85  |.9.8.7.6........|
+00000060  c0 32 c0 2e c0 2a c0 26  c0 0f c0 05 00 9d 00 3d  |.2...*.&.......=|
+00000070  00 35 00 84 c0 2f c0 2b  c0 27 c0 23 c0 13 c0 09  |.5.../.+.'.#....|
+00000080  c0 1f c0 1e c0 1d 00 a4  00 a2 00 a0 00 9e 00 67  |...............g|
+00000090  00 40 00 3f 00 3e 00 33  00 32 00 31 00 30 00 9a  |. at .?.>.3.2.1.0..|
+000000a0  00 99 00 98 00 97 00 45  00 44 00 43 00 42 c0 31  |.......E.D.C.B.1|
+000000b0  c0 2d c0 29 c0 25 c0 0e  c0 04 00 9c 00 3c 00 2f  |.-.).%.......<./|
+000000c0  00 96 00 41 00 07 c0 11  c0 07 c0 0c c0 02 00 05  |...A............|
+000000d0  00 04 c0 12 c0 08 c0 1c  c0 1b c0 1a 00 16 00 13  |................|
+000000e0  00 10 00 0d c0 0d c0 03  00 0a 00 15 00 12 00 0f  |................|
+000000f0  00 0c 00 09 00 14 00 11  00 0e 00 0b 00 08 00 06  |................|
+00000100  00 03 00 ff 01 00 00 87  00 0b 00 04 03 00 01 02  |................|
+00000110  00 0a 00 3a 00 38 00 0e  00 0d 00 19 00 1c 00 0b  |...:.8..........|
+00000120  00 0c 00 1b 00 18 00 09  00 0a 00 1a 00 16 00 17  |................|
+00000130  00 08 00 06 00 07 00 14  00 15 00 04 00 05 00 12  |................|
+00000140  00 13 00 01 00 02 00 03  00 0f 00 10 00 11 00 23  |...............#|
+00000150  00 00 00 0d 00 20 00 1e  06 01 06 02 06 03 05 01  |..... ..........|
+00000160  05 02 05 03 04 01 04 02  04 03 03 01 03 02 03 03  |................|
+00000170  02 01 02 02 02 03 00 0f  00 01 01 00 10 00 10 00  |................|
+00000180  0e 06 70 72 6f 74 6f 32  06 70 72 6f 74 6f 31     |..proto2.proto1|
 >>> 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 c0 30 00 00  |.............0..|
-00000030  09 00 23 00 00 ff 01 00  01 00 16 03 03 02 71 0b  |..#...........q.|
-00000040  00 02 6d 00 02 6a 00 02  67 30 82 02 63 30 82 01  |..m..j..g0..c0..|
-00000050  cc a0 03 02 01 02 02 09  00 a2 73 00 0c 81 00 cb  |..........s.....|
-00000060  f3 30 0d 06 09 2a 86 48  86 f7 0d 01 01 0b 05 00  |.0...*.H........|
-00000070  30 2b 31 17 30 15 06 03  55 04 0a 13 0e 47 6f 6f  |0+1.0...U....Goo|
-00000080  67 6c 65 20 54 45 53 54  49 4e 47 31 10 30 0e 06  |gle TESTING1.0..|
-00000090  03 55 04 03 13 07 47 6f  20 52 6f 6f 74 30 1e 17  |.U....Go Root0..|
-000000a0  0d 31 35 30 31 30 31 30  30 30 30 30 30 5a 17 0d  |.150101000000Z..|
-000000b0  32 35 30 31 30 31 30 30  30 30 30 30 5a 30 26 31  |250101000000Z0&1|
-000000c0  17 30 15 06 03 55 04 0a  13 0e 47 6f 6f 67 6c 65  |.0...U....Google|
-000000d0  20 54 45 53 54 49 4e 47  31 0b 30 09 06 03 55 04  | TESTING1.0...U.|
-000000e0  03 13 02 47 6f 30 81 9f  30 0d 06 09 2a 86 48 86  |...Go0..0...*.H.|
-000000f0  f7 0d 01 01 01 05 00 03  81 8d 00 30 81 89 02 81  |...........0....|
-00000100  81 00 af 87 88 f6 20 1b  95 65 6c 14 ab 44 05 af  |...... ..el..D..|
-00000110  3b 45 14 e3 b7 6d fd 00  63 4d 95 7f fe 6a 62 35  |;E...m..cM...jb5|
-00000120  86 c0 4a f9 18 7c f6 aa  25 5e 7a 64 31 66 00 ba  |..J..|..%^zd1f..|
-00000130  f4 8e 92 af c7 6b d8 76  d4 f3 5f 41 cb 6e 56 15  |.....k.v.._A.nV.|
-00000140  97 1b 97 c1 3c 12 39 21  66 3d 2b 16 d1 bc db 1c  |....<.9!f=+.....|
-00000150  c0 a7 da b7 ca ad ba da  cb d5 21 50 ec de 8d ab  |..........!P....|
-00000160  d1 6b 81 4b 89 02 f3 c4  be c1 6c 89 b1 44 84 bd  |.k.K......l..D..|
-00000170  21 d1 04 7d 9d 16 4d f9  82 15 f6 ef fa d6 09 47  |!..}..M........G|
-00000180  f2 fb 02 03 01 00 01 a3  81 93 30 81 90 30 0e 06  |..........0..0..|
-00000190  03 55 1d 0f 01 01 ff 04  04 03 02 05 a0 30 1d 06  |.U...........0..|
-000001a0  03 55 1d 25 04 16 30 14  06 08 2b 06 01 05 05 07  |.U.%..0...+.....|
-000001b0  03 01 06 08 2b 06 01 05  05 07 03 02 30 0c 06 03  |....+.......0...|
-000001c0  55 1d 13 01 01 ff 04 02  30 00 30 19 06 03 55 1d  |U.......0.0...U.|
-000001d0  0e 04 12 04 10 12 50 8d  89 6f 1b d1 dc 54 4d 6e  |......P..o...TMn|
-000001e0  cb 69 5e 06 f4 30 1b 06  03 55 1d 23 04 14 30 12  |.i^..0...U.#..0.|
-000001f0  80 10 bf 3d b6 a9 66 f2  b8 40 cf ea b4 03 78 48  |...=..f.. at ....xH|
-00000200  1a 41 30 19 06 03 55 1d  11 04 12 30 10 82 0e 65  |.A0...U....0...e|
-00000210  78 61 6d 70 6c 65 2e 67  6f 6c 61 6e 67 30 0d 06  |xample.golang0..|
-00000220  09 2a 86 48 86 f7 0d 01  01 0b 05 00 03 81 81 00  |.*.H............|
-00000230  92 7c af 91 55 12 18 96  59 31 a6 48 40 d5 2d d5  |.|..U...Y1.H at .-.|
-00000240  ee bb 02 a0 f5 c2 1e 7c  9b b3 30 7d 3c dc 76 da  |.......|..0}<.v.|
-00000250  4f 3d c0 fa ae 2d 33 24  6b 03 7b 1b 67 59 11 21  |O=...-3$k.{.gY.!|
-00000260  b5 11 bc 77 b9 d9 e0 6e  a8 2d 2e 35 fa 64 5f 22  |...w...n.-.5.d_"|
-00000270  3e 63 10 6b be ff 14 86  6d 0d f0 15 31 a8 14 38  |>c.k....m...1..8|
-00000280  1e 3b 84 87 2c cb 98 ed  51 76 b9 b1 4f dd db 9b  |.;..,...Qv..O...|
-00000290  84 04 86 40 fa 51 dd ba  b4 8d eb e3 46 de 46 b9  |... at .Q......F.F.|
-000002a0  4f 86 c7 f9 a4 c2 41 34  ac cc f6 ea b0 ab 39 18  |O.....A4......9.|
-000002b0  16 03 03 00 cd 0c 00 00  c9 03 00 17 41 04 1e 18  |............A...|
-000002c0  37 ef 0d 19 51 88 35 75  71 b5 e5 54 5b 12 2e 8f  |7...Q.5uq..T[...|
-000002d0  09 67 fd a7 24 20 3e b2  56 1c ce 97 28 5e f8 2b  |.g..$ >.V...(^.+|
-000002e0  2d 4f 9e f1 07 9f 6c 4b  5b 83 56 e2 32 42 e9 58  |-O....lK[.V.2B.X|
-000002f0  b6 d7 49 a6 b5 68 1a 41  03 56 6b dc 5a 89 05 01  |..I..h.A.Vk.Z...|
-00000300  00 80 36 d2 96 c8 27 66  d8 bd 6c 28 29 30 b3 be  |..6...'f..l()0..|
-00000310  0a bb b2 fe 9d c3 59 47  34 cf de fe f4 ab 5d 79  |......YG4.....]y|
-00000320  24 a9 9d c9 b5 e9 50 6a  3b 96 e3 29 cb d7 37 06  |$.....Pj;..)..7.|
-00000330  19 08 88 15 29 c2 55 03  62 75 1d 35 c2 8e 25 a2  |....).U.bu.5..%.|
-00000340  86 20 bf 18 46 15 81 f2  74 4b bb dd 3d e3 a5 f6  |. ..F...tK..=...|
-00000350  28 18 41 89 c8 39 13 f9  c0 88 fd cc f0 6e 9e 3d  |(.A..9.......n.=|
-00000360  cb 29 ad 26 5b d1 e6 11  5c 64 7d b6 df d7 39 87  |.).&[...\d}...9.|
-00000370  24 df 9f 62 17 ef f2 b3  3a b3 88 a4 f0 91 ea f2  |$..b....:.......|
-00000380  5d c9 16 03 03 00 04 0e  00 00 00                 |]..........|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 c0 14 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 cd 0c 00 00 c9 03 00  17 41 04 1e 18 37 ef 0d  |.........A...7..|
+00000310  19 51 88 35 75 71 b5 e5  54 5b 12 2e 8f 09 67 fd  |.Q.5uq..T[....g.|
+00000320  a7 24 20 3e b2 56 1c ce  97 28 5e f8 2b 2d 4f 9e  |.$ >.V...(^.+-O.|
+00000330  f1 07 9f 6c 4b 5b 83 56  e2 32 42 e9 58 b6 d7 49  |...lK[.V.2B.X..I|
+00000340  a6 b5 68 1a 41 03 56 6b  dc 5a 89 04 01 00 80 b9  |..h.A.Vk.Z......|
+00000350  0f 79 8a 16 f4 da 8f 27  b4 16 fc c0 51 db ae d1  |.y.....'....Q...|
+00000360  af 79 77 d5 d5 a2 13 05  45 20 cc eb ac ed cb 30  |.yw.....E .....0|
+00000370  32 2e 2c bd fa 1c 4d b5  32 a6 37 43 c8 5c 2d f8  |2.,...M.2.7C.\-.|
+00000380  6e 85 f5 cd 54 92 29 ad  13 7d d5 9e 8c 1d b7 d0  |n...T.)..}......|
+00000390  c1 c7 3d e8 ba 4a 0f 9a  a6 3e 25 5f 27 62 b1 00  |..=..J...>%_'b..|
+000003a0  91 d9 23 48 3f 10 fe c5  e3 07 9a 58 57 6d cc 10  |..#H?......XWm..|
+000003b0  3b f8 1a d5 6e 8b 1f 03  6f 82 84 98 b5 f7 71 5d  |;...n...o.....q]|
+000003c0  c2 ad 60 14 c1 88 07 5a  3d 99 fd a8 c9 9a 03 16  |..`....Z=.......|
+000003d0  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 b0 22 15 73 fc  |....F...BA..".s.|
-00000010  1c fd 24 4a 36 69 8a be  ac bd 72 30 bb 6b e1 9b  |..$J6i....r0.k..|
-00000020  42 e8 56 7a 86 b1 8d cb  9c 3e 2d 63 13 57 a8 13  |B.Vz.....>-c.W..|
-00000030  71 3b a2 01 86 af f8 76  40 0b 44 4f 0a 0f 5a da  |q;.....v at .DO..Z.|
-00000040  31 36 3b 13 c0 10 6c 96  64 a7 24 14 03 03 00 01  |16;...l.d.$.....|
-00000050  01 16 03 03 00 28 10 2d  45 93 5c 37 34 d9 2a a0  |.....(.-E.\74.*.|
-00000060  b6 37 13 bc a6 1f 0c ce  2e 55 c1 ad 36 b8 60 72  |.7.......U..6.`r|
-00000070  81 cb 1a 7a 5b 26 49 ad  77 ef 62 e8 fc 00        |...z[&I.w.b...|
+00000000  16 03 03 00 46 10 00 00  42 41 04 76 aa 4e b9 f9  |....F...BA.v.N..|
+00000010  68 85 81 74 7c d9 f9 64  7f bd 09 83 08 5b 4f 76  |h..t|..d.....[Ov|
+00000020  6e be 79 b6 4e 97 17 63  e4 b5 1c 77 e5 85 76 8a  |n.y.N..c...w..v.|
+00000030  5d 9f f1 21 88 ec f9 a7  7c 41 af f9 c5 fe 11 81  |]..!....|A......|
+00000040  11 51 8e a7 20 33 5f cf  e7 90 90 14 03 03 00 01  |.Q.. 3_.........|
+00000050  01 16 03 03 00 40 44 3e  32 01 71 ac 5a b5 1f 2c  |..... at D>2.q.Z..,|
+00000060  37 d9 4b 70 72 91 89 d4  d7 c2 c3 e7 ff dc 72 2a  |7.Kpr.........r*|
+00000070  ba f5 30 b0 e9 dd 48 10  3d cd 98 48 a3 e3 ca de  |..0...H.=..H....|
+00000080  15 0e 90 8e e5 04 14 74  42 b8 b0 12 cc 68 7b 7d  |.......tB....h{}|
+00000090  6c 43 72 60 05 0d                                 |lCr`..|
 >>> Flow 4 (server to client)
-00000000  16 03 03 00 82 04 00 00  7e 00 00 00 00 00 78 50  |........~.....xP|
-00000010  46 ad c1 db a8 38 86 7b  2b bb fd d0 c3 42 3e 00  |F....8.{+....B>.|
-00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 94  |................|
-00000030  6f ec 80 83 61 05 33 d2  9d 95 89 7b 28 54 50 50  |o...a.3....{(TPP|
-00000040  b3 3c 99 5c 82 ab cf 88  24 e8 48 81 db 4a 22 79  |.<.\....$.H..J"y|
-00000050  0b fa 33 50 ed 82 a1 7c  33 0e f2 ff 6d a7 d6 88  |..3P...|3...m...|
-00000060  29 65 74 e3 27 33 94 97  66 0c 86 ce fc ca 0e 2a  |)et.'3..f......*|
-00000070  96 fa fe 19 a3 01 64 d9  4d 8e 58 95 5b 74 a6 aa  |......d.M.X.[t..|
-00000080  f4 9f c1 34 97 2d e5 14  03 03 00 01 01 16 03 03  |...4.-..........|
-00000090  00 28 00 00 00 00 00 00  00 00 4d 56 6d d5 6f cc  |.(........MVm.o.|
-000000a0  3d d4 85 32 3c 07 ea 3c  52 61 88 8e dd d5 d3 d0  |=..2<..<Ra......|
-000000b0  f9 4e 1b b1 c1 d1 67 cb  1a e8 17 03 03 00 25 00  |.N....g.......%.|
-000000c0  00 00 00 00 00 00 01 c3  43 ab 0c ab 59 30 e9 d4  |........C...Y0..|
-000000d0  eb 65 c2 7f 9a 5a 1e 09  06 a4 9d 69 bb 3f 0b 06  |.e...Z.....i.?..|
-000000e0  87 b8 09 39 15 03 03 00  1a 00 00 00 00 00 00 00  |...9............|
-000000f0  02 c2 6f f4 88 f0 7a 59  a6 49 3e 44 a3 7b 6e 36  |..o...zY.I>D.{n6|
-00000100  ae 66 87                                          |.f.|
+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 8b c0 ef ba 12 45 17  61 24 cd d2 4c 22 bb 3b  |......E.a$..L".;|
+00000030  e3 0e d0 ff 83 e9 7c b7  8f 10 3c 16 1c fc c2 44  |......|...<....D|
+00000040  ef 45 f8 27 30 56 db ea  eb ae f5 b6 17 b2 ef f9  |.E.'0V..........|
+00000050  96 0d 2d db e4 59 23 0a  fc fa e3 13 48 57 e5 b3  |..-..Y#.....HW..|
+00000060  3a d1 f5 5e ca ef d7 3f  7b b5 f4 69 85 c3 bd da  |:..^...?{..i....|
+00000070  fd 9c 50 05 2f 86 ce 14  03 03 00 01 01 16 03 03  |..P./...........|
+00000080  00 40 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |. at ..............|
+00000090  00 00 60 25 1c ed 6f c6  a5 bd b2 29 39 4e 09 d1  |..`%..o....)9N..|
+000000a0  64 cc 75 cd df 91 a8 90  9d 03 aa 92 07 f2 d0 8a  |d.u.............|
+000000b0  60 bb 3e 85 21 22 fe f8  dc 52 3c 4e 82 77 14 14  |`.>.!"...R<N.w..|
+000000c0  0f 1f 17 03 03 00 40 00  00 00 00 00 00 00 00 00  |...... at .........|
+000000d0  00 00 00 00 00 00 00 0b  87 12 62 3e e5 3e 7d 74  |..........b>.>}t|
+000000e0  0d ac c4 a9 df 67 1c 5a  ad 3e 01 34 03 88 2f 39  |.....g.Z.>.4../9|
+000000f0  f7 3c 06 e4 f6 81 43 66  b1 1b ed a5 e5 b6 a8 43  |.<....Cf.......C|
+00000100  7f 36 2f b2 da 45 9a 15  03 03 00 30 00 00 00 00  |.6/..E.....0....|
+00000110  00 00 00 00 00 00 00 00  00 00 00 00 fa 63 4e c5  |.............cN.|
+00000120  77 89 71 56 e3 0a cf 98  da 2f 89 8f 74 8e 76 24  |w.qV...../..t.v$|
+00000130  e2 40 a5 9f 29 1b b2 11  ef 7a 55 7f              |. at ..)....zU.|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceECDSA b/src/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceECDSA
index 344d973..0ab8b8d 100644
--- a/src/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceECDSA
+++ b/src/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceECDSA
@@ -1,98 +1,91 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 01 34 01 00 01  30 03 03 78 08 b2 d4 18  |....4...0..x....|
-00000010  8e b1 6b a2 d2 e0 c6 41  02 c5 93 f1 b9 60 94 e8  |..k....A.....`..|
-00000020  f2 64 6c 97 50 2d 24 a3  cd c0 36 00 00 b6 c0 30  |.dl.P-$...6....0|
-00000030  c0 2c c0 28 c0 24 c0 14  c0 0a 00 a5 00 a3 00 a1  |.,.(.$..........|
-00000040  00 9f 00 6b 00 6a 00 69  00 68 00 39 00 38 00 37  |...k.j.i.h.9.8.7|
-00000050  00 36 00 88 00 87 00 86  00 85 c0 32 c0 2e c0 2a  |.6.........2...*|
-00000060  c0 26 c0 0f c0 05 00 9d  00 3d 00 35 00 84 c0 2f  |.&.......=.5.../|
-00000070  c0 2b c0 27 c0 23 c0 13  c0 09 00 a4 00 a2 00 a0  |.+.'.#..........|
-00000080  00 9e 00 67 00 40 00 3f  00 3e 00 33 00 32 00 31  |...g. at .?.>.3.2.1|
-00000090  00 30 00 9a 00 99 00 98  00 97 00 45 00 44 00 43  |.0.........E.D.C|
-000000a0  00 42 c0 31 c0 2d c0 29  c0 25 c0 0e c0 04 00 9c  |.B.1.-.).%......|
-000000b0  00 3c 00 2f 00 96 00 41  00 07 c0 11 c0 07 c0 0c  |.<./...A........|
-000000c0  c0 02 00 05 00 04 c0 12  c0 08 00 16 00 13 00 10  |................|
-000000d0  00 0d c0 0d c0 03 00 0a  00 15 00 12 00 0f 00 0c  |................|
-000000e0  00 09 00 ff 01 00 00 51  00 0b 00 04 03 00 01 02  |.......Q........|
-000000f0  00 0a 00 1c 00 1a 00 17  00 19 00 1c 00 1b 00 18  |................|
-00000100  00 1a 00 16 00 0e 00 0d  00 0b 00 0c 00 09 00 0a  |................|
-00000110  00 0d 00 20 00 1e 06 01  06 02 06 03 05 01 05 02  |... ............|
-00000120  05 03 04 01 04 02 04 03  03 01 03 02 03 03 02 01  |................|
-00000130  02 02 02 03 00 0f 00 01  01                       |.........|
+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 31 02 00 00  2d 03 03 00 00 00 00 00  |....1...-.......|
+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 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 05  03 00 8b 30 81 88 02 42  |A.Vk.Z.....0...B|
-000002a0  00 91 b4 4a f2 9d 13 a1  6d 3b ee 46 2f 3b 97 50  |...J....m;.F/;.P|
-000002b0  b9 3e 28 7a 51 7a 8b 3b  a6 16 03 d6 1f 92 0a ec  |.>(zQz.;........|
-000002c0  5b 9b b5 48 98 ce d8 22  bd 7d eb cb 14 7b 14 73  |[..H...".}...{.s|
-000002d0  2d 5f 01 8c dc 5a 63 34  92 4e 59 4a 90 f9 b1 c9  |-_...Zc4.NYJ....|
-000002e0  d8 18 02 42 01 89 e4 e4  39 d0 52 d1 70 19 fe d7  |...B....9.R.p...|
-000002f0  c6 70 10 36 94 1e 45 fd  b4 03 37 79 c7 db cf 6d  |.p.6..E...7y...m|
-00000300  33 5d 80 fe 04 de d1 78  bf c4 dd cf 91 82 57 14  |3].....x......W.|
-00000310  14 09 e3 2d dd d2 78 9c  53 cc 1f f7 40 6c 4a 59  |...-..x.S... at lJY|
-00000320  49 a8 a1 06 24 18 16 03  03 00 04 0e 00 00 00     |I...$..........|
+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 66 37 3a ce 68  |....F...BA.f7:.h|
-00000010  23 0f b2 d0 cb 20 24 26  37 d5 84 46 4a 2e 59 80  |#.... $&7..FJ.Y.|
-00000020  87 b3 10 7e 36 fd af 7c  99 07 99 dd 18 af 6d 7c  |...~6..|......m||
-00000030  b5 b2 b7 93 45 95 d9 98  1a 13 5b a2 12 e8 b7 95  |....E.....[.....|
-00000040  ed a1 3a 6d aa 8f fc b6  b5 b4 41 14 03 03 00 01  |..:m......A.....|
-00000050  01 16 03 03 00 40 b0 12  69 00 a4 3a 6d bd 56 40  |..... at ..i..:m.V@|
-00000060  6e 9d 5e a8 1b 0f 59 c5  09 48 b2 07 d8 bc 7b 02  |n.^...Y..H....{.|
-00000070  70 61 f6 1b a9 27 55 8c  16 4d 69 4c ca 31 30 9f  |pa...'U..MiL.10.|
-00000080  d3 62 ba d4 1b 11 ee 0a  a0 f3 61 be c6 64 c3 dc  |.b........a..d..|
-00000090  97 50 47 27 ed 09                                 |.PG'..|
+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 09 34 9a eb 7c  |............4..||
-00000020  6a 6d 6a 02 7b 50 14 b8  f7 b0 93 30 ea 0b 61 4a  |jmj.{P.....0..aJ|
-00000030  0b 75 10 39 41 78 46 9d  ba 8e d3 e9 e4 ab dc 1f  |.u.9AxF.........|
-00000040  c9 43 95 e8 f9 d6 3a d3  5d 7d 09 17 03 03 00 40  |.C....:.]}.....@|
+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  b4 64 88 d5 53 f9 1e 47  d4 d8 c4 fa 0e c2 76 a6  |.d..S..G......v.|
-00000070  ed 5c 17 ba ea 76 72 cb  c5 73 a3 c5 44 21 3c 40  |.\...vr..s..D!<@|
-00000080  33 27 09 37 73 3b 0e a3  7b 95 72 10 8d 74 85 19  |3'.7s;..{.r..t..|
+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 b3 c0 05  e9 ec 05 06 52 ef 09 b7  |............R...|
-000000b0  52 29 04 88 ed 11 bb bd  36 a3 0f ce 2c 55 a2 87  |R)......6...,U..|
-000000c0  7e 2b 0c aa 83                                    |~+...|
+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/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceRSA b/src/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceRSA
index 10624c0..88abb15 100644
--- a/src/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceRSA
+++ b/src/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceRSA
@@ -1,104 +1,101 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 01 34 01 00 01  30 03 03 10 5e c8 3f c6  |....4...0...^.?.|
-00000010  fe 44 c4 f0 13 c5 bd ad  06 21 65 e5 a8 40 b5 1d  |.D.......!e.. at ..|
-00000020  21 07 99 34 5b ef 70 85  29 92 7d 00 00 b6 c0 30  |!..4[.p.).}....0|
-00000030  c0 2c c0 28 c0 24 c0 14  c0 0a 00 a5 00 a3 00 a1  |.,.(.$..........|
-00000040  00 9f 00 6b 00 6a 00 69  00 68 00 39 00 38 00 37  |...k.j.i.h.9.8.7|
-00000050  00 36 00 88 00 87 00 86  00 85 c0 32 c0 2e c0 2a  |.6.........2...*|
-00000060  c0 26 c0 0f c0 05 00 9d  00 3d 00 35 00 84 c0 2f  |.&.......=.5.../|
-00000070  c0 2b c0 27 c0 23 c0 13  c0 09 00 a4 00 a2 00 a0  |.+.'.#..........|
-00000080  00 9e 00 67 00 40 00 3f  00 3e 00 33 00 32 00 31  |...g. at .?.>.3.2.1|
-00000090  00 30 00 9a 00 99 00 98  00 97 00 45 00 44 00 43  |.0.........E.D.C|
-000000a0  00 42 c0 31 c0 2d c0 29  c0 25 c0 0e c0 04 00 9c  |.B.1.-.).%......|
-000000b0  00 3c 00 2f 00 96 00 41  00 07 c0 11 c0 07 c0 0c  |.<./...A........|
-000000c0  c0 02 00 05 00 04 c0 12  c0 08 00 16 00 13 00 10  |................|
-000000d0  00 0d c0 0d c0 03 00 0a  00 15 00 12 00 0f 00 0c  |................|
-000000e0  00 09 00 ff 01 00 00 51  00 0b 00 04 03 00 01 02  |.......Q........|
-000000f0  00 0a 00 1c 00 1a 00 17  00 19 00 1c 00 1b 00 18  |................|
-00000100  00 1a 00 16 00 0e 00 0d  00 0b 00 0c 00 09 00 0a  |................|
-00000110  00 0d 00 20 00 1e 06 01  06 02 06 03 05 01 05 02  |... ............|
-00000120  05 03 04 01 04 02 04 03  03 01 03 02 03 03 02 01  |................|
-00000130  02 02 02 03 00 0f 00 01  01                       |.........|
+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 31 02 00 00  2d 03 03 00 00 00 00 00  |....1...-.......|
+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 00  |................|
-00000030  05 ff 01 00 01 00 16 03  03 02 71 0b 00 02 6d 00  |..........q...m.|
-00000040  02 6a 00 02 67 30 82 02  63 30 82 01 cc a0 03 02  |.j..g0..c0......|
-00000050  01 02 02 09 00 a2 73 00  0c 81 00 cb f3 30 0d 06  |......s......0..|
-00000060  09 2a 86 48 86 f7 0d 01  01 0b 05 00 30 2b 31 17  |.*.H........0+1.|
-00000070  30 15 06 03 55 04 0a 13  0e 47 6f 6f 67 6c 65 20  |0...U....Google |
-00000080  54 45 53 54 49 4e 47 31  10 30 0e 06 03 55 04 03  |TESTING1.0...U..|
-00000090  13 07 47 6f 20 52 6f 6f  74 30 1e 17 0d 31 35 30  |..Go Root0...150|
-000000a0  31 30 31 30 30 30 30 30  30 5a 17 0d 32 35 30 31  |101000000Z..2501|
-000000b0  30 31 30 30 30 30 30 30  5a 30 26 31 17 30 15 06  |01000000Z0&1.0..|
-000000c0  03 55 04 0a 13 0e 47 6f  6f 67 6c 65 20 54 45 53  |.U....Google TES|
-000000d0  54 49 4e 47 31 0b 30 09  06 03 55 04 03 13 02 47  |TING1.0...U....G|
-000000e0  6f 30 81 9f 30 0d 06 09  2a 86 48 86 f7 0d 01 01  |o0..0...*.H.....|
-000000f0  01 05 00 03 81 8d 00 30  81 89 02 81 81 00 af 87  |.......0........|
-00000100  88 f6 20 1b 95 65 6c 14  ab 44 05 af 3b 45 14 e3  |.. ..el..D..;E..|
-00000110  b7 6d fd 00 63 4d 95 7f  fe 6a 62 35 86 c0 4a f9  |.m..cM...jb5..J.|
-00000120  18 7c f6 aa 25 5e 7a 64  31 66 00 ba f4 8e 92 af  |.|..%^zd1f......|
-00000130  c7 6b d8 76 d4 f3 5f 41  cb 6e 56 15 97 1b 97 c1  |.k.v.._A.nV.....|
-00000140  3c 12 39 21 66 3d 2b 16  d1 bc db 1c c0 a7 da b7  |<.9!f=+.........|
-00000150  ca ad ba da cb d5 21 50  ec de 8d ab d1 6b 81 4b  |......!P.....k.K|
-00000160  89 02 f3 c4 be c1 6c 89  b1 44 84 bd 21 d1 04 7d  |......l..D..!..}|
-00000170  9d 16 4d f9 82 15 f6 ef  fa d6 09 47 f2 fb 02 03  |..M........G....|
-00000180  01 00 01 a3 81 93 30 81  90 30 0e 06 03 55 1d 0f  |......0..0...U..|
-00000190  01 01 ff 04 04 03 02 05  a0 30 1d 06 03 55 1d 25  |.........0...U.%|
-000001a0  04 16 30 14 06 08 2b 06  01 05 05 07 03 01 06 08  |..0...+.........|
-000001b0  2b 06 01 05 05 07 03 02  30 0c 06 03 55 1d 13 01  |+.......0...U...|
-000001c0  01 ff 04 02 30 00 30 19  06 03 55 1d 0e 04 12 04  |....0.0...U.....|
-000001d0  10 12 50 8d 89 6f 1b d1  dc 54 4d 6e cb 69 5e 06  |..P..o...TMn.i^.|
-000001e0  f4 30 1b 06 03 55 1d 23  04 14 30 12 80 10 bf 3d  |.0...U.#..0....=|
-000001f0  b6 a9 66 f2 b8 40 cf ea  b4 03 78 48 1a 41 30 19  |..f.. at ....xH.A0.|
-00000200  06 03 55 1d 11 04 12 30  10 82 0e 65 78 61 6d 70  |..U....0...examp|
-00000210  6c 65 2e 67 6f 6c 61 6e  67 30 0d 06 09 2a 86 48  |le.golang0...*.H|
-00000220  86 f7 0d 01 01 0b 05 00  03 81 81 00 92 7c af 91  |.............|..|
-00000230  55 12 18 96 59 31 a6 48  40 d5 2d d5 ee bb 02 a0  |U...Y1.H at .-.....|
-00000240  f5 c2 1e 7c 9b b3 30 7d  3c dc 76 da 4f 3d c0 fa  |...|..0}<.v.O=..|
-00000250  ae 2d 33 24 6b 03 7b 1b  67 59 11 21 b5 11 bc 77  |.-3$k.{.gY.!...w|
-00000260  b9 d9 e0 6e a8 2d 2e 35  fa 64 5f 22 3e 63 10 6b  |...n.-.5.d_">c.k|
-00000270  be ff 14 86 6d 0d f0 15  31 a8 14 38 1e 3b 84 87  |....m...1..8.;..|
-00000280  2c cb 98 ed 51 76 b9 b1  4f dd db 9b 84 04 86 40  |,...Qv..O......@|
-00000290  fa 51 dd ba b4 8d eb e3  46 de 46 b9 4f 86 c7 f9  |.Q......F.F.O...|
-000002a0  a4 c2 41 34 ac cc f6 ea  b0 ab 39 18 16 03 03 00  |..A4......9.....|
-000002b0  cd 0c 00 00 c9 03 00 17  41 04 1e 18 37 ef 0d 19  |........A...7...|
-000002c0  51 88 35 75 71 b5 e5 54  5b 12 2e 8f 09 67 fd a7  |Q.5uq..T[....g..|
-000002d0  24 20 3e b2 56 1c ce 97  28 5e f8 2b 2d 4f 9e f1  |$ >.V...(^.+-O..|
-000002e0  07 9f 6c 4b 5b 83 56 e2  32 42 e9 58 b6 d7 49 a6  |..lK[.V.2B.X..I.|
-000002f0  b5 68 1a 41 03 56 6b dc  5a 89 05 01 00 80 6a 4b  |.h.A.Vk.Z.....jK|
-00000300  b1 7d 23 cd 0e cb 26 02  d4 ee 90 f2 e0 4a 47 3d  |.}#...&......JG=|
-00000310  b3 36 90 8d 01 42 98 92  ad 75 87 71 02 70 02 a8  |.6...B...u.q.p..|
-00000320  0c b0 06 ee bd 6a 1f 3f  6c 4b 4b 6b 75 41 23 b4  |.....j.?lKKkuA#.|
-00000330  f9 c2 a6 60 e2 de 55 b6  d4 85 62 e9 8f 20 70 ed  |...`..U...b.. p.|
-00000340  9a b8 bb dd 1f 19 87 e9  ad b3 30 3f 7c 63 51 f1  |..........0?|cQ.|
-00000350  59 ab d1 a0 a1 80 22 56  ca 68 52 f8 0f 80 c6 a6  |Y....."V.hR.....|
-00000360  9e 12 51 ed 29 d0 6d c2  1a e5 37 dc 76 e3 f3 53  |..Q.).m...7.v..S|
-00000370  1b 07 0b ea a6 11 af dc  54 d3 ee 25 cc 27 16 03  |........T..%.'..|
-00000380  03 00 04 0e 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 2d 4b 0c 6b 65  |....F...BA.-K.ke|
-00000010  82 32 95 8b 77 ec f0 f2  b2 ba d1 38 74 ed 82 49  |.2..w......8t..I|
-00000020  fb ce 8f 66 97 9d b6 97  d8 ae f5 19 af ad 47 b9  |...f..........G.|
-00000030  db 7b d2 c9 4e 10 68 14  ed 23 a5 98 94 f9 2a 00  |.{..N.h..#....*.|
-00000040  b6 44 b3 44 01 29 6c 56  da bb a8 14 03 03 00 01  |.D.D.)lV........|
-00000050  01 16 03 03 00 40 f4 fd  de d6 20 2e 18 80 4e 73  |..... at .... ...Ns|
-00000060  af dd 97 42 08 3b 51 80  e9 26 00 48 6b 8b 21 99  |...B.;Q..&.Hk.!.|
-00000070  a8 60 1f 64 51 d0 5a 90  8b b0 69 b8 6b 29 59 21  |.`.dQ.Z...i.k)Y!|
-00000080  b1 13 19 13 07 01 e1 2c  c3 6b 17 2d 01 a5 be d6  |.......,.k.-....|
-00000090  b0 0d 3d 6a 8c fe                                 |..=j..|
+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 84 e2 7f e3 b4  |................|
-00000020  53 d7 d0 30 c4 e5 ea 09  df ba 33 b0 02 34 eb 2e  |S..0......3..4..|
-00000030  b2 ec 47 0d e7 20 76 12  fa 53 3b 44 86 e1 e1 63  |..G.. v..S;D...c|
-00000040  06 29 57 98 ce 87 18 ad  02 17 01 17 03 03 00 40  |.)W............@|
+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  b0 3a f5 90 90 30 9c b3  39 5b b4 56 f6 b9 30 7e  |.:...0..9[.V..0~|
-00000070  8e a8 2d 60 47 b6 57 8a  20 61 02 f2 8e 43 c2 01  |..-`G.W. a...C..|
-00000080  ee f0 be 5a 93 52 2f ea  03 2a 4f 01 ea 9e 1c a2  |...Z.R/..*O.....|
+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 c0 7e 61  51 a1 76 15 8a 7e 20 5f  |......~aQ.v..~ _|
-000000b0  d4 a4 c6 3e 6c 50 18 c6  63 88 d0 ac 4c fa 31 b3  |...>lP..c...L.1.|
-000000c0  e7 c9 77 11 7a                                    |..w.z|
+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/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndECDSAGiven b/src/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndECDSAGiven
index 56c3c82..547f798 100644
--- a/src/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndECDSAGiven
+++ b/src/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndECDSAGiven
@@ -1,57 +1,62 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 5a 01 00 00  56 03 03 80 13 c8 83 43  |....Z...V......C|
-00000010  94 79 15 01 6e 0a 9f c5  0f e7 f6 d8 b1 94 de b4  |.y..n...........|
-00000020  57 8c 4f a8 08 48 ee 9b  b4 d2 43 00 00 04 00 05  |W.O..H....C.....|
-00000030  00 ff 01 00 00 29 00 0d  00 20 00 1e 06 01 06 02  |.....)... ......|
+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 00 0f 00 01 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 71 0b 00 02 6d 00  |..........q...m.|
-00000040  02 6a 00 02 67 30 82 02  63 30 82 01 cc a0 03 02  |.j..g0..c0......|
-00000050  01 02 02 09 00 a2 73 00  0c 81 00 cb f3 30 0d 06  |......s......0..|
-00000060  09 2a 86 48 86 f7 0d 01  01 0b 05 00 30 2b 31 17  |.*.H........0+1.|
-00000070  30 15 06 03 55 04 0a 13  0e 47 6f 6f 67 6c 65 20  |0...U....Google |
-00000080  54 45 53 54 49 4e 47 31  10 30 0e 06 03 55 04 03  |TESTING1.0...U..|
-00000090  13 07 47 6f 20 52 6f 6f  74 30 1e 17 0d 31 35 30  |..Go Root0...150|
-000000a0  31 30 31 30 30 30 30 30  30 5a 17 0d 32 35 30 31  |101000000Z..2501|
-000000b0  30 31 30 30 30 30 30 30  5a 30 26 31 17 30 15 06  |01000000Z0&1.0..|
-000000c0  03 55 04 0a 13 0e 47 6f  6f 67 6c 65 20 54 45 53  |.U....Google TES|
-000000d0  54 49 4e 47 31 0b 30 09  06 03 55 04 03 13 02 47  |TING1.0...U....G|
-000000e0  6f 30 81 9f 30 0d 06 09  2a 86 48 86 f7 0d 01 01  |o0..0...*.H.....|
-000000f0  01 05 00 03 81 8d 00 30  81 89 02 81 81 00 af 87  |.......0........|
-00000100  88 f6 20 1b 95 65 6c 14  ab 44 05 af 3b 45 14 e3  |.. ..el..D..;E..|
-00000110  b7 6d fd 00 63 4d 95 7f  fe 6a 62 35 86 c0 4a f9  |.m..cM...jb5..J.|
-00000120  18 7c f6 aa 25 5e 7a 64  31 66 00 ba f4 8e 92 af  |.|..%^zd1f......|
-00000130  c7 6b d8 76 d4 f3 5f 41  cb 6e 56 15 97 1b 97 c1  |.k.v.._A.nV.....|
-00000140  3c 12 39 21 66 3d 2b 16  d1 bc db 1c c0 a7 da b7  |<.9!f=+.........|
-00000150  ca ad ba da cb d5 21 50  ec de 8d ab d1 6b 81 4b  |......!P.....k.K|
-00000160  89 02 f3 c4 be c1 6c 89  b1 44 84 bd 21 d1 04 7d  |......l..D..!..}|
-00000170  9d 16 4d f9 82 15 f6 ef  fa d6 09 47 f2 fb 02 03  |..M........G....|
-00000180  01 00 01 a3 81 93 30 81  90 30 0e 06 03 55 1d 0f  |......0..0...U..|
-00000190  01 01 ff 04 04 03 02 05  a0 30 1d 06 03 55 1d 25  |.........0...U.%|
-000001a0  04 16 30 14 06 08 2b 06  01 05 05 07 03 01 06 08  |..0...+.........|
-000001b0  2b 06 01 05 05 07 03 02  30 0c 06 03 55 1d 13 01  |+.......0...U...|
-000001c0  01 ff 04 02 30 00 30 19  06 03 55 1d 0e 04 12 04  |....0.0...U.....|
-000001d0  10 12 50 8d 89 6f 1b d1  dc 54 4d 6e cb 69 5e 06  |..P..o...TMn.i^.|
-000001e0  f4 30 1b 06 03 55 1d 23  04 14 30 12 80 10 bf 3d  |.0...U.#..0....=|
-000001f0  b6 a9 66 f2 b8 40 cf ea  b4 03 78 48 1a 41 30 19  |..f.. at ....xH.A0.|
-00000200  06 03 55 1d 11 04 12 30  10 82 0e 65 78 61 6d 70  |..U....0...examp|
-00000210  6c 65 2e 67 6f 6c 61 6e  67 30 0d 06 09 2a 86 48  |le.golang0...*.H|
-00000220  86 f7 0d 01 01 0b 05 00  03 81 81 00 92 7c af 91  |.............|..|
-00000230  55 12 18 96 59 31 a6 48  40 d5 2d d5 ee bb 02 a0  |U...Y1.H at .-.....|
-00000240  f5 c2 1e 7c 9b b3 30 7d  3c dc 76 da 4f 3d c0 fa  |...|..0}<.v.O=..|
-00000250  ae 2d 33 24 6b 03 7b 1b  67 59 11 21 b5 11 bc 77  |.-3$k.{.gY.!...w|
-00000260  b9 d9 e0 6e a8 2d 2e 35  fa 64 5f 22 3e 63 10 6b  |...n.-.5.d_">c.k|
-00000270  be ff 14 86 6d 0d f0 15  31 a8 14 38 1e 3b 84 87  |....m...1..8.;..|
-00000280  2c cb 98 ed 51 76 b9 b1  4f dd db 9b 84 04 86 40  |,...Qv..O......@|
-00000290  fa 51 dd ba b4 8d eb e3  46 de 46 b9 4f 86 c7 f9  |.Q......F.F.O...|
-000002a0  a4 c2 41 34 ac cc f6 ea  b0 ab 39 18 16 03 03 00  |..A4......9.....|
-000002b0  17 0d 00 00 13 02 01 40  00 0c 04 01 04 03 05 01  |....... at ........|
-000002c0  05 03 02 01 02 03 00 00  16 03 03 00 04 0e 00 00  |................|
-000002d0  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|
@@ -86,32 +91,32 @@
 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 88 00 24 23 a5 c7  |............$#..|
-00000220  03 2d 86 37 91 f1 71 a9  5f fb 97 49 88 04 9b 0e  |.-.7..q._..I....|
-00000230  89 da 65 d0 56 71 e7 76  22 ef 8e 11 0e 6b 50 3d  |..e.Vq.v"....kP=|
-00000240  64 3f f7 9b e4 45 01 d9  12 cb da fe 10 da 4e b5  |d?...E........N.|
-00000250  b8 6a b5 bc 74 19 d3 4f  a9 bb ee 54 37 e4 70 d0  |.j..t..O...T7.p.|
-00000260  b6 e7 35 96 70 fe a5 2b  14 ac fb c6 1a fa 7d 12  |..5.p..+......}.|
-00000270  87 1b 63 9d 72 30 4d 2c  1a c9 29 32 72 b6 13 53  |..c.r0M,..)2r..S|
-00000280  96 05 de 78 bc f0 1a 74  e2 31 b9 ea db 62 62 6e  |...x...t.1...bbn|
-00000290  a0 a6 b2 c0 3e 2a 94 0d  6a f7 16 03 03 00 92 0f  |....>*..j.......|
-000002a0  00 00 8e 04 03 00 8a 30  81 87 02 42 01 71 5b 3b  |.......0...B.q[;|
-000002b0  a3 35 58 c0 b6 08 09 4f  ac af 89 e0 b3 d5 3d 45  |.5X....O......=E|
-000002c0  1f 49 7f 4a c9 bc 9d 0e  50 3a f5 79 bc 54 5d a9  |.I.J....P:.y.T].|
-000002d0  62 ed 85 c5 f3 47 36 03  cc f1 cd 33 c3 70 2a a6  |b....G6....3.p*.|
-000002e0  7c d9 6e 0c db 0d 1b 4f  6a 39 ba 77 bd ea 02 41  ||.n....Oj9.w...A|
-000002f0  00 f2 b7 06 df 2f 81 7e  98 24 46 06 59 4e 86 6a  |...../.~.$F.YN.j|
-00000300  b7 4f b6 4b 95 40 88 f0  8f f8 bd 16 f5 d5 82 7e  |.O.K. at .........~|
-00000310  82 51 6f 05 49 43 59 cd  1d 40 69 67 ff 65 a8 68  |.Qo.ICY.. at ig.e.h|
-00000320  39 2f a1 ad a7 6a ef 5c  d5 69 5e 16 50 bb 2a b2  |9/...j.\.i^.P.*.|
-00000330  2f 14 03 03 00 01 01 16  03 03 00 24 55 f6 74 21  |/..........$U.t!|
-00000340  b4 08 a0 7f a2 dc 86 44  e3 f8 e3 0d e1 d6 5c 1c  |.......D......\.|
-00000350  22 1e 41 2b 30 cc 34 0f  a4 a1 7c a0 27 21 01 e0  |".A+0.4...|.'!..|
+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 6f 6b e7 fb f7  |..........$ok...|
-00000010  52 83 b3 6f ba 1b d7 e8  cb 0a 05 ee 90 04 2b c7  |R..o..........+.|
-00000020  c2 bd 0d 8e ee 42 88 40  ae 01 4a d0 07 4b f4 17  |.....B. at ..J..K..|
-00000030  03 03 00 21 e0 8b bd 80  04 18 9c be 12 07 d4 4d  |...!...........M|
-00000040  58 d9 ec c3 f0 67 b5 b3  d1 78 25 e7 2e dd a0 0a  |X....g...x%.....|
-00000050  ac 0f a1 90 59 15 03 03  00 16 76 30 22 0b 00 83  |....Y.....v0"...|
-00000060  c4 31 29 1c ca 44 cb 9f  0e 48 17 21 43 f6 af 47  |.1)..D...H.!C..G|
+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/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndGiven b/src/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndGiven
index 862e0be..04a5b11 100644
--- a/src/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndGiven
+++ b/src/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndGiven
@@ -1,57 +1,62 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 5a 01 00 00  56 03 03 b0 80 f6 7c 13  |....Z...V.....|.|
-00000010  30 5d 57 f0 11 3b 30 4b  0e 01 50 9a 44 0b 89 6f  |0]W..;0K..P.D..o|
-00000020  b6 f1 a3 34 b4 f1 b9 bf  fe 66 a5 00 00 04 00 05  |...4.....f......|
-00000030  00 ff 01 00 00 29 00 0d  00 20 00 1e 06 01 06 02  |.....)... ......|
+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 00 0f 00 01 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 71 0b 00 02 6d 00  |..........q...m.|
-00000040  02 6a 00 02 67 30 82 02  63 30 82 01 cc a0 03 02  |.j..g0..c0......|
-00000050  01 02 02 09 00 a2 73 00  0c 81 00 cb f3 30 0d 06  |......s......0..|
-00000060  09 2a 86 48 86 f7 0d 01  01 0b 05 00 30 2b 31 17  |.*.H........0+1.|
-00000070  30 15 06 03 55 04 0a 13  0e 47 6f 6f 67 6c 65 20  |0...U....Google |
-00000080  54 45 53 54 49 4e 47 31  10 30 0e 06 03 55 04 03  |TESTING1.0...U..|
-00000090  13 07 47 6f 20 52 6f 6f  74 30 1e 17 0d 31 35 30  |..Go Root0...150|
-000000a0  31 30 31 30 30 30 30 30  30 5a 17 0d 32 35 30 31  |101000000Z..2501|
-000000b0  30 31 30 30 30 30 30 30  5a 30 26 31 17 30 15 06  |01000000Z0&1.0..|
-000000c0  03 55 04 0a 13 0e 47 6f  6f 67 6c 65 20 54 45 53  |.U....Google TES|
-000000d0  54 49 4e 47 31 0b 30 09  06 03 55 04 03 13 02 47  |TING1.0...U....G|
-000000e0  6f 30 81 9f 30 0d 06 09  2a 86 48 86 f7 0d 01 01  |o0..0...*.H.....|
-000000f0  01 05 00 03 81 8d 00 30  81 89 02 81 81 00 af 87  |.......0........|
-00000100  88 f6 20 1b 95 65 6c 14  ab 44 05 af 3b 45 14 e3  |.. ..el..D..;E..|
-00000110  b7 6d fd 00 63 4d 95 7f  fe 6a 62 35 86 c0 4a f9  |.m..cM...jb5..J.|
-00000120  18 7c f6 aa 25 5e 7a 64  31 66 00 ba f4 8e 92 af  |.|..%^zd1f......|
-00000130  c7 6b d8 76 d4 f3 5f 41  cb 6e 56 15 97 1b 97 c1  |.k.v.._A.nV.....|
-00000140  3c 12 39 21 66 3d 2b 16  d1 bc db 1c c0 a7 da b7  |<.9!f=+.........|
-00000150  ca ad ba da cb d5 21 50  ec de 8d ab d1 6b 81 4b  |......!P.....k.K|
-00000160  89 02 f3 c4 be c1 6c 89  b1 44 84 bd 21 d1 04 7d  |......l..D..!..}|
-00000170  9d 16 4d f9 82 15 f6 ef  fa d6 09 47 f2 fb 02 03  |..M........G....|
-00000180  01 00 01 a3 81 93 30 81  90 30 0e 06 03 55 1d 0f  |......0..0...U..|
-00000190  01 01 ff 04 04 03 02 05  a0 30 1d 06 03 55 1d 25  |.........0...U.%|
-000001a0  04 16 30 14 06 08 2b 06  01 05 05 07 03 01 06 08  |..0...+.........|
-000001b0  2b 06 01 05 05 07 03 02  30 0c 06 03 55 1d 13 01  |+.......0...U...|
-000001c0  01 ff 04 02 30 00 30 19  06 03 55 1d 0e 04 12 04  |....0.0...U.....|
-000001d0  10 12 50 8d 89 6f 1b d1  dc 54 4d 6e cb 69 5e 06  |..P..o...TMn.i^.|
-000001e0  f4 30 1b 06 03 55 1d 23  04 14 30 12 80 10 bf 3d  |.0...U.#..0....=|
-000001f0  b6 a9 66 f2 b8 40 cf ea  b4 03 78 48 1a 41 30 19  |..f.. at ....xH.A0.|
-00000200  06 03 55 1d 11 04 12 30  10 82 0e 65 78 61 6d 70  |..U....0...examp|
-00000210  6c 65 2e 67 6f 6c 61 6e  67 30 0d 06 09 2a 86 48  |le.golang0...*.H|
-00000220  86 f7 0d 01 01 0b 05 00  03 81 81 00 92 7c af 91  |.............|..|
-00000230  55 12 18 96 59 31 a6 48  40 d5 2d d5 ee bb 02 a0  |U...Y1.H at .-.....|
-00000240  f5 c2 1e 7c 9b b3 30 7d  3c dc 76 da 4f 3d c0 fa  |...|..0}<.v.O=..|
-00000250  ae 2d 33 24 6b 03 7b 1b  67 59 11 21 b5 11 bc 77  |.-3$k.{.gY.!...w|
-00000260  b9 d9 e0 6e a8 2d 2e 35  fa 64 5f 22 3e 63 10 6b  |...n.-.5.d_">c.k|
-00000270  be ff 14 86 6d 0d f0 15  31 a8 14 38 1e 3b 84 87  |....m...1..8.;..|
-00000280  2c cb 98 ed 51 76 b9 b1  4f dd db 9b 84 04 86 40  |,...Qv..O......@|
-00000290  fa 51 dd ba b4 8d eb e3  46 de 46 b9 4f 86 c7 f9  |.Q......F.F.O...|
-000002a0  a4 c2 41 34 ac cc f6 ea  b0 ab 39 18 16 03 03 00  |..A4......9.....|
-000002b0  17 0d 00 00 13 02 01 40  00 0c 04 01 04 03 05 01  |....... at ........|
-000002c0  05 03 02 01 02 03 00 00  16 03 03 00 04 0e 00 00  |................|
-000002d0  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|
@@ -85,32 +90,32 @@
 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 98 61 16 34 c4  |............a.4.|
-00000210  c6 0a 47 c1 de 87 b1 b7  70 1b 24 8d 7e 35 90 35  |..G.....p.$.~5.5|
-00000220  f7 a5 6f c7 c9 91 ad 46  4c 50 e5 7e 61 7c 49 66  |..o....FLP.~a|If|
-00000230  e9 fe 1e 2c 30 fa 22 03  36 8f 44 27 a7 d2 14 84  |...,0.".6.D'....|
-00000240  d0 1f 21 ca 40 35 d1 7d  31 3f e1 73 de 69 bc da  |..!. at 5.}1?.s.i..|
-00000250  a5 96 8a b5 50 2b 4b 87  5a b3 fb e1 11 0a 29 59  |....P+K.Z.....)Y|
-00000260  13 2e e3 c2 05 d3 23 e8  09 0c 42 f6 8e 26 67 89  |......#...B..&g.|
-00000270  24 0f 08 2f 3d 24 2b 0c  a2 98 38 02 5c 95 9f ce  |$../=$+...8.\...|
-00000280  e3 75 ba 05 b5 f8 f0 07  e9 a1 44 16 03 03 00 88  |.u........D.....|
-00000290  0f 00 00 84 04 01 00 80  04 c0 bc 4b 23 59 ed 26  |...........K#Y.&|
-000002a0  8d 90 35 da 5b 55 88 e7  12 10 7b d7 1c 27 d1 c4  |..5.[U....{..'..|
-000002b0  d8 1b e2 e7 54 ad a4 be  00 6b 5b 61 2d ec 97 0c  |....T....k[a-...|
-000002c0  a5 9b ae ab 13 fa 94 53  1c 65 28 21 7d b5 c5 be  |.......S.e(!}...|
-000002d0  22 62 91 78 fc e3 de 84  5c 4e 0d f5 73 5e 20 49  |"b.x....\N..s^ I|
-000002e0  5a e2 f9 d3 2f 36 23 91  31 5b ee c7 0b 6f b3 35  |Z.../6#.1[...o.5|
-000002f0  2f 8a 51 84 3c fe 78 34  1f 8c 68 d3 fc 4f c6 5e  |/.Q.<.x4..h..O.^|
-00000300  7b fe b2 81 79 91 37 ee  7f f1 9b a4 88 5f 1b 44  |{...y.7......_.D|
-00000310  dc e9 36 bb d1 45 bb 1f  14 03 03 00 01 01 16 03  |..6..E..........|
-00000320  03 00 24 12 e7 8a 31 36  26 9f fe 45 95 cf 41 56  |..$...16&..E..AV|
-00000330  b4 69 ef e4 22 14 5a 4d  c8 79 a7 18 7b 68 a8 02  |.i..".ZM.y..{h..|
-00000340  75 ea 42 fe c4 a1 32                              |u.B...2|
+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 ae 6d 7b ac b6  |..........$.m{..|
-00000010  62 5c 40 65 6b 0e 5c 12  68 61 14 90 54 3e 24 78  |b\@ek.\.ha..T>$x|
-00000020  be 85 17 a0 9b de a0 00  e9 80 1b a9 0f e4 d7 17  |................|
-00000030  03 03 00 21 86 06 17 6b  62 02 a7 a0 71 fe c0 e4  |...!...kb...q...|
-00000040  44 00 54 dd cc a9 70 cf  bc 92 0d 40 07 62 f5 39  |D.T...p.... at .b.9|
-00000050  2a 30 ab 7f cd 15 03 03  00 16 6f 8d c9 d4 62 02  |*0........o...b.|
-00000060  da 64 4c 89 32 86 9f 29  24 05 ed cc 77 9d e5 55  |.dL.2..)$...w..U|
+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/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedNotGiven b/src/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedNotGiven
index 5de6dd8..562fe1a 100644
--- a/src/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedNotGiven
+++ b/src/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedNotGiven
@@ -1,76 +1,81 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 5a 01 00 00  56 03 03 52 b6 c5 b4 e3  |....Z...V..R....|
-00000010  35 ce 4e b2 9c e0 38 09  e7 fe 00 a2 1a 0a 43 eb  |5.N...8.......C.|
-00000020  df 98 6a 34 71 f9 d0 f8  5d e7 5e 00 00 04 00 05  |..j4q...].^.....|
-00000030  00 ff 01 00 00 29 00 0d  00 20 00 1e 06 01 06 02  |.....)... ......|
+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 00 0f 00 01 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 71 0b 00 02 6d 00  |..........q...m.|
-00000040  02 6a 00 02 67 30 82 02  63 30 82 01 cc a0 03 02  |.j..g0..c0......|
-00000050  01 02 02 09 00 a2 73 00  0c 81 00 cb f3 30 0d 06  |......s......0..|
-00000060  09 2a 86 48 86 f7 0d 01  01 0b 05 00 30 2b 31 17  |.*.H........0+1.|
-00000070  30 15 06 03 55 04 0a 13  0e 47 6f 6f 67 6c 65 20  |0...U....Google |
-00000080  54 45 53 54 49 4e 47 31  10 30 0e 06 03 55 04 03  |TESTING1.0...U..|
-00000090  13 07 47 6f 20 52 6f 6f  74 30 1e 17 0d 31 35 30  |..Go Root0...150|
-000000a0  31 30 31 30 30 30 30 30  30 5a 17 0d 32 35 30 31  |101000000Z..2501|
-000000b0  30 31 30 30 30 30 30 30  5a 30 26 31 17 30 15 06  |01000000Z0&1.0..|
-000000c0  03 55 04 0a 13 0e 47 6f  6f 67 6c 65 20 54 45 53  |.U....Google TES|
-000000d0  54 49 4e 47 31 0b 30 09  06 03 55 04 03 13 02 47  |TING1.0...U....G|
-000000e0  6f 30 81 9f 30 0d 06 09  2a 86 48 86 f7 0d 01 01  |o0..0...*.H.....|
-000000f0  01 05 00 03 81 8d 00 30  81 89 02 81 81 00 af 87  |.......0........|
-00000100  88 f6 20 1b 95 65 6c 14  ab 44 05 af 3b 45 14 e3  |.. ..el..D..;E..|
-00000110  b7 6d fd 00 63 4d 95 7f  fe 6a 62 35 86 c0 4a f9  |.m..cM...jb5..J.|
-00000120  18 7c f6 aa 25 5e 7a 64  31 66 00 ba f4 8e 92 af  |.|..%^zd1f......|
-00000130  c7 6b d8 76 d4 f3 5f 41  cb 6e 56 15 97 1b 97 c1  |.k.v.._A.nV.....|
-00000140  3c 12 39 21 66 3d 2b 16  d1 bc db 1c c0 a7 da b7  |<.9!f=+.........|
-00000150  ca ad ba da cb d5 21 50  ec de 8d ab d1 6b 81 4b  |......!P.....k.K|
-00000160  89 02 f3 c4 be c1 6c 89  b1 44 84 bd 21 d1 04 7d  |......l..D..!..}|
-00000170  9d 16 4d f9 82 15 f6 ef  fa d6 09 47 f2 fb 02 03  |..M........G....|
-00000180  01 00 01 a3 81 93 30 81  90 30 0e 06 03 55 1d 0f  |......0..0...U..|
-00000190  01 01 ff 04 04 03 02 05  a0 30 1d 06 03 55 1d 25  |.........0...U.%|
-000001a0  04 16 30 14 06 08 2b 06  01 05 05 07 03 01 06 08  |..0...+.........|
-000001b0  2b 06 01 05 05 07 03 02  30 0c 06 03 55 1d 13 01  |+.......0...U...|
-000001c0  01 ff 04 02 30 00 30 19  06 03 55 1d 0e 04 12 04  |....0.0...U.....|
-000001d0  10 12 50 8d 89 6f 1b d1  dc 54 4d 6e cb 69 5e 06  |..P..o...TMn.i^.|
-000001e0  f4 30 1b 06 03 55 1d 23  04 14 30 12 80 10 bf 3d  |.0...U.#..0....=|
-000001f0  b6 a9 66 f2 b8 40 cf ea  b4 03 78 48 1a 41 30 19  |..f.. at ....xH.A0.|
-00000200  06 03 55 1d 11 04 12 30  10 82 0e 65 78 61 6d 70  |..U....0...examp|
-00000210  6c 65 2e 67 6f 6c 61 6e  67 30 0d 06 09 2a 86 48  |le.golang0...*.H|
-00000220  86 f7 0d 01 01 0b 05 00  03 81 81 00 92 7c af 91  |.............|..|
-00000230  55 12 18 96 59 31 a6 48  40 d5 2d d5 ee bb 02 a0  |U...Y1.H at .-.....|
-00000240  f5 c2 1e 7c 9b b3 30 7d  3c dc 76 da 4f 3d c0 fa  |...|..0}<.v.O=..|
-00000250  ae 2d 33 24 6b 03 7b 1b  67 59 11 21 b5 11 bc 77  |.-3$k.{.gY.!...w|
-00000260  b9 d9 e0 6e a8 2d 2e 35  fa 64 5f 22 3e 63 10 6b  |...n.-.5.d_">c.k|
-00000270  be ff 14 86 6d 0d f0 15  31 a8 14 38 1e 3b 84 87  |....m...1..8.;..|
-00000280  2c cb 98 ed 51 76 b9 b1  4f dd db 9b 84 04 86 40  |,...Qv..O......@|
-00000290  fa 51 dd ba b4 8d eb e3  46 de 46 b9 4f 86 c7 f9  |.Q......F.F.O...|
-000002a0  a4 c2 41 34 ac cc f6 ea  b0 ab 39 18 16 03 03 00  |..A4......9.....|
-000002b0  17 0d 00 00 13 02 01 40  00 0c 04 01 04 03 05 01  |....... at ........|
-000002c0  05 03 02 01 02 03 00 00  16 03 03 00 04 0e 00 00  |................|
-000002d0  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 2e  8e cb 6c f5 db 45 5b f0  |..........l..E[.|
-00000020  67 7d b1 ac 87 c2 d6 e9  ea 37 40 15 2a ea a1 af  |g}.......7 at .*...|
-00000030  ed 71 68 18 9c 6c 84 20  52 3e 38 94 8e d9 cd b3  |.qh..l. R>8.....|
-00000040  15 73 8b db d7 ff 1d 8a  ed a6 f4 00 7d d0 0a 1e  |.s..........}...|
-00000050  9a 1b 5c 59 f6 a0 29 62  03 a1 c6 bf 8a 57 14 06  |..\Y..)b.....W..|
-00000060  9a e8 03 72 bc cd cd 6f  6d e2 ce a8 41 7a f0 65  |...r...om...Az.e|
-00000070  42 0c 7b dd 93 d7 ab 37  f8 2a b3 c4 72 95 61 e1  |B.{....7.*..r.a.|
-00000080  75 98 f5 99 69 ef 0a d0  00 41 0f 05 87 13 d3 7d  |u...i....A.....}|
-00000090  ba 74 34 43 9a 6c d0 14  03 03 00 01 01 16 03 03  |.t4C.l..........|
-000000a0  00 24 87 7e 7d 48 ca 17  9c ad 30 b8 6a 05 2f d3  |.$.~}H....0.j./.|
-000000b0  fc 18 2e df fd f5 0e 38  c3 06 57 4c 27 66 02 af  |.......8..WL'f..|
-000000c0  6d 78 4d 2e b6 dc                                 |mxM...|
+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 cf ee f6 28 ea  |..........$...(.|
-00000010  df e2 7e 9a 75 e0 f9 b4  c4 c2 57 3a 54 26 db 7f  |..~.u.....W:T&..|
-00000020  c4 19 6d b6 d6 c7 b1 05  7f 92 21 9e 51 1a 0a 17  |..m.......!.Q...|
-00000030  03 03 00 21 87 48 77 c4  eb 7c 5d 13 3b f4 8d 08  |...!.Hw..|].;...|
-00000040  f9 35 c3 d2 e5 c0 8c ea  15 c9 2d c5 e0 70 fd 7c  |.5........-..p.||
-00000050  de 93 4f 8c 8d 15 03 03  00 16 d4 8a d5 6a fc db  |..O..........j..|
-00000060  c7 1d 1f 76 64 b9 31 68  72 cc 58 de 9f 2a a6 45  |...vd.1hr.X..*.E|
+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/crypto/tls/testdata/Server-TLSv12-ECDHE-ECDSA-AES b/src/crypto/tls/testdata/Server-TLSv12-ECDHE-ECDSA-AES
index 3b7238a..aacbb86 100644
--- a/src/crypto/tls/testdata/Server-TLSv12-ECDHE-ECDSA-AES
+++ b/src/crypto/tls/testdata/Server-TLSv12-ECDHE-ECDSA-AES
@@ -1,15 +1,15 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 a1 01 00 00  9d 03 03 0f b7 07 5f c7  |.............._.|
-00000010  18 b8 39 6d 92 b3 90 ed  bf 5c 48 7c 6a 56 ee e9  |..9m.....\H|jV..|
-00000020  7a 5b 5f 71 a4 f0 7f 47  57 73 78 00 00 04 c0 0a  |z[_q...GWsx.....|
-00000030  00 ff 02 01 00 00 6f 00  0b 00 04 03 00 01 02 00  |......o.........|
-00000040  0a 00 3a 00 38 00 0e 00  0d 00 19 00 1c 00 0b 00  |..:.8...........|
-00000050  0c 00 1b 00 18 00 09 00  0a 00 1a 00 16 00 17 00  |................|
-00000060  08 00 06 00 07 00 14 00  15 00 04 00 05 00 12 00  |................|
-00000070  13 00 01 00 02 00 03 00  0f 00 10 00 11 00 0d 00  |................|
-00000080  20 00 1e 06 01 06 02 06  03 05 01 05 02 05 03 04  | ...............|
-00000090  01 04 02 04 03 03 01 03  02 03 03 02 01 02 02 02  |................|
-000000a0  03 00 0f 00 01 01                                 |......|
+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  |................|
@@ -52,38 +52,38 @@
 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 05  03 00 8b 30 81 88 02 42  |A.Vk.Z.....0...B|
-000002a0  00 d3 cf 21 cd 3c 2e 11  f5 f8 1d c8 c1 57 4b f8  |...!.<.......WK.|
-000002b0  1a c0 2b 1d 47 0f 2d a5  ac a1 c8 83 5d 76 87 05  |..+.G.-.....]v..|
-000002c0  2b 0d 36 d5 57 9f b9 8a  a0 a2 94 67 6a cd 29 db  |+.6.W......gj.).|
-000002d0  04 b0 6b 06 d9 f7 17 9f  1c 60 92 e7 4e 50 48 7f  |..k......`..NPH.|
-000002e0  dc d0 02 42 01 56 fd 38  bd 05 a5 16 6d 91 d1 ce  |...B.V.8....m...|
-000002f0  bb 8c 45 b2 76 2f 92 9c  8b 94 57 7d de 53 8b 7b  |..E.v/....W}.S.{|
-00000300  80 26 6c 4a 43 4b a6 c9  46 49 08 ab c7 57 f3 d9  |.&lJCK..FI...W..|
-00000310  fa 1d 55 fe 91 de 8a 0d  8b d1 44 96 87 85 cb 02  |..U.......D.....|
-00000320  76 9c 00 ad 5f b8 16 03  03 00 04 0e 00 00 00     |v..._..........|
+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 0b dc ea 22 05  |....F...BA....".|
-00000010  44 c2 09 47 65 31 3b 0b  e1 05 1a 87 8c 2d 3b 56  |D..Ge1;......-;V|
-00000020  49 34 27 3e d6 3b 93 e2  12 7f 5d 7b dc 85 c8 96  |I4'>.;....]{....|
-00000030  4c 8c f9 18 6f 15 cf db  6e 2c 14 6a c9 dd 1c 70  |L...o...n,.j...p|
-00000040  7e 05 c4 17 71 76 df 10  ee 8c b1 14 03 03 00 01  |~...qv..........|
-00000050  01 16 03 03 00 40 ff 12  88 36 3c 00 17 d1 b9 41  |..... at ...6<....A|
-00000060  7a 12 25 94 4c 90 65 62  d8 09 ab f9 b4 ee c3 de  |z.%.L.eb........|
-00000070  46 2f cb ee 18 76 4f 76  8e dd 89 fc 7a 21 3b 5f  |F/...vOv....z!;_|
-00000080  ff ac 1c 03 aa be 96 82  82 ea 2e 22 2a 80 b3 86  |..........."*...|
-00000090  38 e4 4d 90 91 46                                 |8.M..F|
+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 e5 c1 f0 6a db  |..............j.|
-00000020  05 98 ed 33 94 73 7f 13  7f 78 17 7f d1 9e c5 a7  |...3.s...x......|
-00000030  62 7f 85 14 2c 7d b2 8e  ef 75 a9 df 92 cc 22 20  |b...,}...u...." |
-00000040  66 08 85 22 d3 ea 5c 4c  4c c8 d7 17 03 03 00 40  |f.."..\LL......@|
+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  f2 20 07 d2 13 ca ed 01  c9 7b 91 14 01 2c 08 f5  |. .......{...,..|
-00000070  8a 69 94 bc 19 9a d9 65  6b 15 04 b4 45 17 ec 6f  |.i.....ek...E..o|
-00000080  85 de 31 dc a2 de 8b 4d  53 57 66 4a 29 21 5a 20  |..1....MSWfJ)!Z |
+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 55 15 f7  89 8d 75 57 7e 92 db ec  |.....U....uW~...|
-000000b0  32 ec 07 5c 83 32 36 59  61 f1 9d a6 7a eb 76 c1  |2..\.26Ya...z.v.|
-000000c0  c7 96 3f 4d 0a                                    |..?M.|
+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/crypto/tls/testdata/Server-TLSv12-IssueTicket b/src/crypto/tls/testdata/Server-TLSv12-IssueTicket
index 20a0731..e3e62f2 100644
--- a/src/crypto/tls/testdata/Server-TLSv12-IssueTicket
+++ b/src/crypto/tls/testdata/Server-TLSv12-IssueTicket
@@ -1,83 +1,87 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 5e 01 00 00  5a 03 03 f0 0a 06 d0 65  |....^...Z......e|
-00000010  1c c3 90 ac dc 61 42 e5  b8 a9 17 fb e7 c3 1e bd  |.....aB.........|
-00000020  d9 09 5a 63 71 e2 f9 58  db 26 6e 00 00 04 00 05  |..Zcq..X.&n.....|
-00000030  00 ff 01 00 00 2d 00 23  00 00 00 0d 00 20 00 1e  |.....-.#..... ..|
+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 00 0f  |................|
-00000060  00 01 01                                          |...|
+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 71 0b  |..#...........q.|
-00000040  00 02 6d 00 02 6a 00 02  67 30 82 02 63 30 82 01  |..m..j..g0..c0..|
-00000050  cc a0 03 02 01 02 02 09  00 a2 73 00 0c 81 00 cb  |..........s.....|
-00000060  f3 30 0d 06 09 2a 86 48  86 f7 0d 01 01 0b 05 00  |.0...*.H........|
-00000070  30 2b 31 17 30 15 06 03  55 04 0a 13 0e 47 6f 6f  |0+1.0...U....Goo|
-00000080  67 6c 65 20 54 45 53 54  49 4e 47 31 10 30 0e 06  |gle TESTING1.0..|
-00000090  03 55 04 03 13 07 47 6f  20 52 6f 6f 74 30 1e 17  |.U....Go Root0..|
-000000a0  0d 31 35 30 31 30 31 30  30 30 30 30 30 5a 17 0d  |.150101000000Z..|
-000000b0  32 35 30 31 30 31 30 30  30 30 30 30 5a 30 26 31  |250101000000Z0&1|
-000000c0  17 30 15 06 03 55 04 0a  13 0e 47 6f 6f 67 6c 65  |.0...U....Google|
-000000d0  20 54 45 53 54 49 4e 47  31 0b 30 09 06 03 55 04  | TESTING1.0...U.|
-000000e0  03 13 02 47 6f 30 81 9f  30 0d 06 09 2a 86 48 86  |...Go0..0...*.H.|
-000000f0  f7 0d 01 01 01 05 00 03  81 8d 00 30 81 89 02 81  |...........0....|
-00000100  81 00 af 87 88 f6 20 1b  95 65 6c 14 ab 44 05 af  |...... ..el..D..|
-00000110  3b 45 14 e3 b7 6d fd 00  63 4d 95 7f fe 6a 62 35  |;E...m..cM...jb5|
-00000120  86 c0 4a f9 18 7c f6 aa  25 5e 7a 64 31 66 00 ba  |..J..|..%^zd1f..|
-00000130  f4 8e 92 af c7 6b d8 76  d4 f3 5f 41 cb 6e 56 15  |.....k.v.._A.nV.|
-00000140  97 1b 97 c1 3c 12 39 21  66 3d 2b 16 d1 bc db 1c  |....<.9!f=+.....|
-00000150  c0 a7 da b7 ca ad ba da  cb d5 21 50 ec de 8d ab  |..........!P....|
-00000160  d1 6b 81 4b 89 02 f3 c4  be c1 6c 89 b1 44 84 bd  |.k.K......l..D..|
-00000170  21 d1 04 7d 9d 16 4d f9  82 15 f6 ef fa d6 09 47  |!..}..M........G|
-00000180  f2 fb 02 03 01 00 01 a3  81 93 30 81 90 30 0e 06  |..........0..0..|
-00000190  03 55 1d 0f 01 01 ff 04  04 03 02 05 a0 30 1d 06  |.U...........0..|
-000001a0  03 55 1d 25 04 16 30 14  06 08 2b 06 01 05 05 07  |.U.%..0...+.....|
-000001b0  03 01 06 08 2b 06 01 05  05 07 03 02 30 0c 06 03  |....+.......0...|
-000001c0  55 1d 13 01 01 ff 04 02  30 00 30 19 06 03 55 1d  |U.......0.0...U.|
-000001d0  0e 04 12 04 10 12 50 8d  89 6f 1b d1 dc 54 4d 6e  |......P..o...TMn|
-000001e0  cb 69 5e 06 f4 30 1b 06  03 55 1d 23 04 14 30 12  |.i^..0...U.#..0.|
-000001f0  80 10 bf 3d b6 a9 66 f2  b8 40 cf ea b4 03 78 48  |...=..f.. at ....xH|
-00000200  1a 41 30 19 06 03 55 1d  11 04 12 30 10 82 0e 65  |.A0...U....0...e|
-00000210  78 61 6d 70 6c 65 2e 67  6f 6c 61 6e 67 30 0d 06  |xample.golang0..|
-00000220  09 2a 86 48 86 f7 0d 01  01 0b 05 00 03 81 81 00  |.*.H............|
-00000230  92 7c af 91 55 12 18 96  59 31 a6 48 40 d5 2d d5  |.|..U...Y1.H at .-.|
-00000240  ee bb 02 a0 f5 c2 1e 7c  9b b3 30 7d 3c dc 76 da  |.......|..0}<.v.|
-00000250  4f 3d c0 fa ae 2d 33 24  6b 03 7b 1b 67 59 11 21  |O=...-3$k.{.gY.!|
-00000260  b5 11 bc 77 b9 d9 e0 6e  a8 2d 2e 35 fa 64 5f 22  |...w...n.-.5.d_"|
-00000270  3e 63 10 6b be ff 14 86  6d 0d f0 15 31 a8 14 38  |>c.k....m...1..8|
-00000280  1e 3b 84 87 2c cb 98 ed  51 76 b9 b1 4f dd db 9b  |.;..,...Qv..O...|
-00000290  84 04 86 40 fa 51 dd ba  b4 8d eb e3 46 de 46 b9  |... at .Q......F.F.|
-000002a0  4f 86 c7 f9 a4 c2 41 34  ac cc f6 ea b0 ab 39 18  |O.....A4......9.|
-000002b0  16 03 03 00 04 0e 00 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 87 06 ba d7 1f  |................|
-00000010  68 0c f2 a6 51 b4 ae af  8c c5 5d d4 bd f1 82 6d  |h...Q.....]....m|
-00000020  1d dd ce 69 be 07 62 13  af 06 71 3a 47 a9 bd f7  |...i..b...q:G...|
-00000030  bb 27 f0 38 df 88 01 40  29 c9 bb 7b 5d 6d 28 bd  |.'.8...@)..{]m(.|
-00000040  c8 28 e6 6d ff 5c c9 d3  c6 f5 06 17 e5 e5 1c 5b  |.(.m.\.........[|
-00000050  a1 18 7a 34 92 0a 39 20  5a 22 44 6c cc 5c 8c 83  |..z4..9 Z"Dl.\..|
-00000060  d0 19 4c bb 4e dc e2 64  ec b2 b8 3f 18 3f 9d 65  |..L.N..d...?.?.e|
-00000070  5b 89 26 ae f6 fd 54 71  c4 45 e9 56 6a 28 42 a9  |[.&...Tq.E.Vj(B.|
-00000080  5b 9f 12 69 a4 08 83 53  95 04 18 14 03 03 00 01  |[..i...S........|
-00000090  01 16 03 03 00 24 55 80  0f 43 c3 08 45 99 c9 1b  |.....$U..C..E...|
-000000a0  fd fe dd e8 48 f2 89 99  86 ef f7 fd 5f 2a 4b 0b  |....H......._*K.|
-000000b0  33 0e 5f 17 bb b7 a2 3c  9d 30                    |3._....<.0|
+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 82 04 00 00  7e 00 00 00 00 00 78 50  |........~.....xP|
-00000010  46 ad c1 db a8 38 86 7b  2b bb fd d0 c3 42 3e 00  |F....8.{+....B>.|
-00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 94  |................|
-00000030  6f 2c b5 83 61 c4 74 90  94 e5 6c fd 70 64 57 3a  |o,..a.t...l.pdW:|
-00000040  25 78 bf 9f a0 7c 51 bc  2a 69 1e b3 fd 71 34 b7  |%x...|Q.*i...q4.|
-00000050  9a ef cb 49 37 f8 5d 5e  7c cf 6d fc 13 c1 52 79  |...I7.]^|.m...Ry|
-00000060  8e ed c3 84 01 33 94 10  65 34 64 5e b4 9c 07 46  |.....3..e4d^...F|
-00000070  5b 9e d7 5e 55 df fd c0  e9 d2 e8 d3 c6 42 18 ef  |[..^U........B..|
-00000080  a5 6c be e8 d2 49 c6 14  03 03 00 01 01 16 03 03  |.l...I..........|
-00000090  00 24 66 94 4b b5 3f 5d  59 db 36 c1 dd 55 8c ee  |.$f.K.?]Y.6..U..|
-000000a0  de a4 bc d0 12 44 31 3e  e4 e7 4a 51 e3 62 69 ab  |.....D1>..JQ.bi.|
-000000b0  14 78 85 49 a3 97 17 03  03 00 21 dd 96 5d 21 e0  |.x.I......!..]!.|
-000000c0  2e 3d 33 dd 6c df bb 41  d7 bd 50 c7 1c 6f 97 34  |.=3.l..A..P..o.4|
-000000d0  6a 6e d6 1d 27 81 2d f7  fb 32 85 02 15 03 03 00  |jn..'.-..2......|
-000000e0  16 5e 4e 62 15 97 a7 a3  9b 1b 50 44 85 fb 28 66  |.^Nb......PD..(f|
-000000f0  aa 66 54 45 c9 dc 61                              |.fTE..a|
+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/crypto/tls/testdata/Server-TLSv12-IssueTicketPreDisable b/src/crypto/tls/testdata/Server-TLSv12-IssueTicketPreDisable
index a8f7edf..30f0026 100644
--- a/src/crypto/tls/testdata/Server-TLSv12-IssueTicketPreDisable
+++ b/src/crypto/tls/testdata/Server-TLSv12-IssueTicketPreDisable
@@ -1,83 +1,87 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 5e 01 00 00  5a 03 03 62 f6 20 66 23  |....^...Z..b. f#|
-00000010  d5 71 0a c0 57 92 2e 80  b6 06 0c 54 5b 1c 77 a0  |.q..W......T[.w.|
-00000020  ce 0b b2 52 4a b9 f2 c6  97 33 42 00 00 04 00 05  |...RJ....3B.....|
-00000030  00 ff 01 00 00 2d 00 23  00 00 00 0d 00 20 00 1e  |.....-.#..... ..|
+00000000  16 03 01 00 60 01 00 00  5c 03 03 54 23 54 02 17  |....`...\..T#T..|
+00000010  f3 53 13 3d 48 88 c3 19  b9 d1 3d 33 7f f5 99 56  |.S.=H.....=3...V|
+00000020  04 71 1b d9 d5 64 8a 0d  4a 54 00 00 00 04 00 05  |.q...d..JT......|
+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 00 0f  |................|
-00000060  00 01 01                                          |...|
+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 71 0b  |..#...........q.|
-00000040  00 02 6d 00 02 6a 00 02  67 30 82 02 63 30 82 01  |..m..j..g0..c0..|
-00000050  cc a0 03 02 01 02 02 09  00 a2 73 00 0c 81 00 cb  |..........s.....|
-00000060  f3 30 0d 06 09 2a 86 48  86 f7 0d 01 01 0b 05 00  |.0...*.H........|
-00000070  30 2b 31 17 30 15 06 03  55 04 0a 13 0e 47 6f 6f  |0+1.0...U....Goo|
-00000080  67 6c 65 20 54 45 53 54  49 4e 47 31 10 30 0e 06  |gle TESTING1.0..|
-00000090  03 55 04 03 13 07 47 6f  20 52 6f 6f 74 30 1e 17  |.U....Go Root0..|
-000000a0  0d 31 35 30 31 30 31 30  30 30 30 30 30 5a 17 0d  |.150101000000Z..|
-000000b0  32 35 30 31 30 31 30 30  30 30 30 30 5a 30 26 31  |250101000000Z0&1|
-000000c0  17 30 15 06 03 55 04 0a  13 0e 47 6f 6f 67 6c 65  |.0...U....Google|
-000000d0  20 54 45 53 54 49 4e 47  31 0b 30 09 06 03 55 04  | TESTING1.0...U.|
-000000e0  03 13 02 47 6f 30 81 9f  30 0d 06 09 2a 86 48 86  |...Go0..0...*.H.|
-000000f0  f7 0d 01 01 01 05 00 03  81 8d 00 30 81 89 02 81  |...........0....|
-00000100  81 00 af 87 88 f6 20 1b  95 65 6c 14 ab 44 05 af  |...... ..el..D..|
-00000110  3b 45 14 e3 b7 6d fd 00  63 4d 95 7f fe 6a 62 35  |;E...m..cM...jb5|
-00000120  86 c0 4a f9 18 7c f6 aa  25 5e 7a 64 31 66 00 ba  |..J..|..%^zd1f..|
-00000130  f4 8e 92 af c7 6b d8 76  d4 f3 5f 41 cb 6e 56 15  |.....k.v.._A.nV.|
-00000140  97 1b 97 c1 3c 12 39 21  66 3d 2b 16 d1 bc db 1c  |....<.9!f=+.....|
-00000150  c0 a7 da b7 ca ad ba da  cb d5 21 50 ec de 8d ab  |..........!P....|
-00000160  d1 6b 81 4b 89 02 f3 c4  be c1 6c 89 b1 44 84 bd  |.k.K......l..D..|
-00000170  21 d1 04 7d 9d 16 4d f9  82 15 f6 ef fa d6 09 47  |!..}..M........G|
-00000180  f2 fb 02 03 01 00 01 a3  81 93 30 81 90 30 0e 06  |..........0..0..|
-00000190  03 55 1d 0f 01 01 ff 04  04 03 02 05 a0 30 1d 06  |.U...........0..|
-000001a0  03 55 1d 25 04 16 30 14  06 08 2b 06 01 05 05 07  |.U.%..0...+.....|
-000001b0  03 01 06 08 2b 06 01 05  05 07 03 02 30 0c 06 03  |....+.......0...|
-000001c0  55 1d 13 01 01 ff 04 02  30 00 30 19 06 03 55 1d  |U.......0.0...U.|
-000001d0  0e 04 12 04 10 12 50 8d  89 6f 1b d1 dc 54 4d 6e  |......P..o...TMn|
-000001e0  cb 69 5e 06 f4 30 1b 06  03 55 1d 23 04 14 30 12  |.i^..0...U.#..0.|
-000001f0  80 10 bf 3d b6 a9 66 f2  b8 40 cf ea b4 03 78 48  |...=..f.. at ....xH|
-00000200  1a 41 30 19 06 03 55 1d  11 04 12 30 10 82 0e 65  |.A0...U....0...e|
-00000210  78 61 6d 70 6c 65 2e 67  6f 6c 61 6e 67 30 0d 06  |xample.golang0..|
-00000220  09 2a 86 48 86 f7 0d 01  01 0b 05 00 03 81 81 00  |.*.H............|
-00000230  92 7c af 91 55 12 18 96  59 31 a6 48 40 d5 2d d5  |.|..U...Y1.H at .-.|
-00000240  ee bb 02 a0 f5 c2 1e 7c  9b b3 30 7d 3c dc 76 da  |.......|..0}<.v.|
-00000250  4f 3d c0 fa ae 2d 33 24  6b 03 7b 1b 67 59 11 21  |O=...-3$k.{.gY.!|
-00000260  b5 11 bc 77 b9 d9 e0 6e  a8 2d 2e 35 fa 64 5f 22  |...w...n.-.5.d_"|
-00000270  3e 63 10 6b be ff 14 86  6d 0d f0 15 31 a8 14 38  |>c.k....m...1..8|
-00000280  1e 3b 84 87 2c cb 98 ed  51 76 b9 b1 4f dd db 9b  |.;..,...Qv..O...|
-00000290  84 04 86 40 fa 51 dd ba  b4 8d eb e3 46 de 46 b9  |... at .Q......F.F.|
-000002a0  4f 86 c7 f9 a4 c2 41 34  ac cc f6 ea b0 ab 39 18  |O.....A4......9.|
-000002b0  16 03 03 00 04 0e 00 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 5b 43 6f db 52  |...........[Co.R|
-00000010  56 e3 d9 4b 1e c8 95 8b  78 a6 19 00 44 9c 44 b4  |V..K....x...D.D.|
-00000020  f7 fe d4 3f 69 ea 9c 67  d3 48 b8 c5 93 bc 22 f1  |...?i..g.H....".|
-00000030  a9 0e 81 82 d0 cf dc 0b  ea f0 02 67 92 8d 72 40  |...........g..r@|
-00000040  25 bb f3 88 53 c0 2f ba  38 ef da d1 7c 73 84 ec  |%...S./.8...|s..|
-00000050  61 96 b9 d4 93 06 4a 06  7b 6d 40 e7 bb 15 59 6e  |a.....J.{m at ...Yn|
-00000060  ad 31 71 eb cf 84 57 3b  0c ad aa 70 02 63 24 a9  |.1q...W;...p.c$.|
-00000070  7c a1 9a 6d b7 e0 4c d5  67 4c ce 53 9d b6 31 de  ||..m..L.gL.S..1.|
-00000080  69 b9 f5 ca a8 e3 ea d6  f5 a3 f3 14 03 03 00 01  |i...............|
-00000090  01 16 03 03 00 24 66 ae  13 67 70 20 f5 f5 76 03  |.....$f..gp ..v.|
-000000a0  11 6e 32 a6 73 a2 70 42  ab 4f 16 93 d2 fa a1 ac  |.n2.s.pB.O......|
-000000b0  4e b2 08 4a a9 b5 20 aa  80 b6                    |N..J.. ...|
+00000000  16 03 03 00 86 10 00 00  82 00 80 27 e9 a4 f7 e7  |...........'....|
+00000010  df 25 de 84 8c 1f d6 e6  c3 11 28 55 9a c1 91 37  |.%........(U...7|
+00000020  84 f5 ba f8 80 0d ca 50  cb 1e 72 f7 97 6f c2 b2  |.......P..r..o..|
+00000030  04 4d 13 7c e0 6e a0 1f  91 e1 38 1b a2 c0 55 16  |.M.|.n....8...U.|
+00000040  7f 29 fc ed 1c 1a cf 72  14 c3 00 c1 dd 36 36 af  |.).....r.....66.|
+00000050  a6 e4 a8 be ba ec 13 d0  1e d0 1d fd e1 5b 27 fd  |.............['.|
+00000060  9a da 2e 12 c8 b0 b9 c2  b9 76 ec 7f 3c 98 b6 63  |.........v..<..c|
+00000070  bc da f0 07 7a 3d e7 61  f4 2f 12 80 3b f9 3b cc  |....z=.a./..;.;.|
+00000080  05 c8 2f 7e 28 b2 73 bf  97 61 29 14 03 03 00 01  |../~(.s..a).....|
+00000090  01 16 03 03 00 24 17 59  a9 45 53 46 33 96 50 dd  |.....$.Y.ESF3.P.|
+000000a0  3e 23 aa 91 38 f8 56 4a  2f 1a f2 b1 44 9b ce 17  |>#..8.VJ/...D...|
+000000b0  6b 8a 89 76 bc 67 b8 8b  ba 90                    |k..v.g....|
 >>> Flow 4 (server to client)
-00000000  16 03 03 00 82 04 00 00  7e 00 00 00 00 00 78 50  |........~.....xP|
-00000010  46 ad c1 db a8 38 86 7b  2b bb fd d0 c3 42 3e 00  |F....8.{+....B>.|
-00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 94  |................|
-00000030  6f 2c b5 83 61 bd 50 da  49 7f 8b 8f 58 57 00 a1  |o,..a.P.I...XW..|
-00000040  11 0d 4a 9d 8a 39 dd 85  23 c0 eb 9d 1a 45 93 92  |..J..9..#....E..|
-00000050  e7 af 15 a3 a4 48 da f9  a4 d8 8e cb 6c 3d 44 77  |.....H......l=Dw|
-00000060  f9 c4 83 89 85 33 94 c1  c6 20 9a 73 44 83 89 5e  |.....3... .sD..^|
-00000070  59 ee 05 c6 7e 8d e9 7d  7b f8 84 46 b6 7d 43 ec  |Y...~..}{..F.}C.|
-00000080  f1 af 1f 0f 35 b4 1c 14  03 03 00 01 01 16 03 03  |....5...........|
-00000090  00 24 8c 0d bd bc 34 93  ed ad 80 21 6d 08 e4 0e  |.$....4....!m...|
-000000a0  67 4f 99 8d df 2a 2d 4f  13 39 82 be a1 d2 1f 75  |gO...*-O.9.....u|
-000000b0  73 c8 b2 ce 41 0c 17 03  03 00 21 d8 c2 50 d6 11  |s...A.....!..P..|
-000000c0  bc 86 58 68 0e 60 4a 47  a5 d0 12 7e a3 b5 be 64  |..Xh.`JG...~...d|
-000000d0  e6 b1 bc 62 70 85 d4 7c  cd fe 67 cf 15 03 03 00  |...bp..|..g.....|
-000000e0  16 e4 1c d5 f4 f7 d0 f5  b2 b3 2b 3d b0 7d c0 23  |..........+=.}.#|
-000000f0  e2 5c a5 c7 a4 23 fa                              |.\...#.|
+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 2d db 0c  ba 9a d4 20 76 57 c8 ec  |.K...-..... vW..|
+00000030  dc 2d 77 fb fb 3b 93 5f  53 e0 14 4f 90 fb d6 55  |.-w..;._S..O...U|
+00000040  57 8c 8d 0d 25 ea 5d 0d  f2 91 e5 12 22 12 ec 7b  |W...%.]....."..{|
+00000050  5f b6 6e fd 07 59 23 24  fc b1 97 ca ea 56 a5 c2  |_.n..Y#$.....V..|
+00000060  a0 e4 9e 99 64 f2 64 d0  75 7a 46 63 e3 dc 21 ed  |....d.d.uzFc..!.|
+00000070  78 56 e9 e1 ab 66 80 14  03 03 00 01 01 16 03 03  |xV...f..........|
+00000080  00 24 fc 14 68 07 17 1f  df b7 84 cb fd c1 e0 e4  |.$..h...........|
+00000090  f2 1a ea 34 b5 00 7f 70  be c8 1c 0a d6 55 e3 57  |...4...p.....U.W|
+000000a0  50 4e 6d 7d 8a 5d 17 03  03 00 21 24 27 50 40 c1  |PNm}.]....!$'P at .|
+000000b0  c5 bd c7 9f 95 d9 ba 2e  7b 0e db ea a7 31 81 05  |........{....1..|
+000000c0  75 43 b1 63 cf b8 55 92  ef 76 98 a9 15 03 03 00  |uC.c..U..v......|
+000000d0  16 d7 ea 3c 79 e7 a6 2f  61 39 ec 4e 95 86 48 5e  |...<y../a9.N..H^|
+000000e0  75 a0 9e 41 42 89 67                              |u..AB.g|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-RSA-3DES b/src/crypto/tls/testdata/Server-TLSv12-RSA-3DES
index 7457626..5995b33 100644
--- a/src/crypto/tls/testdata/Server-TLSv12-RSA-3DES
+++ b/src/crypto/tls/testdata/Server-TLSv12-RSA-3DES
@@ -1,77 +1,83 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 5a 01 00 00  56 03 03 ac 1d 0b 6e f3  |....Z...V.....n.|
-00000010  25 04 00 97 a0 79 39 c5  ef 95 8b e3 c1 87 0d 1c  |%....y9.........|
-00000020  0b c3 39 3e ff 23 0e 3c  28 8f 75 00 00 04 00 0a  |..9>.#.<(.u.....|
-00000030  00 ff 01 00 00 29 00 0d  00 20 00 1e 06 01 06 02  |.....)... ......|
+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 00 0f 00 01 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 71 0b 00 02 6d 00  |..........q...m.|
-00000040  02 6a 00 02 67 30 82 02  63 30 82 01 cc a0 03 02  |.j..g0..c0......|
-00000050  01 02 02 09 00 a2 73 00  0c 81 00 cb f3 30 0d 06  |......s......0..|
-00000060  09 2a 86 48 86 f7 0d 01  01 0b 05 00 30 2b 31 17  |.*.H........0+1.|
-00000070  30 15 06 03 55 04 0a 13  0e 47 6f 6f 67 6c 65 20  |0...U....Google |
-00000080  54 45 53 54 49 4e 47 31  10 30 0e 06 03 55 04 03  |TESTING1.0...U..|
-00000090  13 07 47 6f 20 52 6f 6f  74 30 1e 17 0d 31 35 30  |..Go Root0...150|
-000000a0  31 30 31 30 30 30 30 30  30 5a 17 0d 32 35 30 31  |101000000Z..2501|
-000000b0  30 31 30 30 30 30 30 30  5a 30 26 31 17 30 15 06  |01000000Z0&1.0..|
-000000c0  03 55 04 0a 13 0e 47 6f  6f 67 6c 65 20 54 45 53  |.U....Google TES|
-000000d0  54 49 4e 47 31 0b 30 09  06 03 55 04 03 13 02 47  |TING1.0...U....G|
-000000e0  6f 30 81 9f 30 0d 06 09  2a 86 48 86 f7 0d 01 01  |o0..0...*.H.....|
-000000f0  01 05 00 03 81 8d 00 30  81 89 02 81 81 00 af 87  |.......0........|
-00000100  88 f6 20 1b 95 65 6c 14  ab 44 05 af 3b 45 14 e3  |.. ..el..D..;E..|
-00000110  b7 6d fd 00 63 4d 95 7f  fe 6a 62 35 86 c0 4a f9  |.m..cM...jb5..J.|
-00000120  18 7c f6 aa 25 5e 7a 64  31 66 00 ba f4 8e 92 af  |.|..%^zd1f......|
-00000130  c7 6b d8 76 d4 f3 5f 41  cb 6e 56 15 97 1b 97 c1  |.k.v.._A.nV.....|
-00000140  3c 12 39 21 66 3d 2b 16  d1 bc db 1c c0 a7 da b7  |<.9!f=+.........|
-00000150  ca ad ba da cb d5 21 50  ec de 8d ab d1 6b 81 4b  |......!P.....k.K|
-00000160  89 02 f3 c4 be c1 6c 89  b1 44 84 bd 21 d1 04 7d  |......l..D..!..}|
-00000170  9d 16 4d f9 82 15 f6 ef  fa d6 09 47 f2 fb 02 03  |..M........G....|
-00000180  01 00 01 a3 81 93 30 81  90 30 0e 06 03 55 1d 0f  |......0..0...U..|
-00000190  01 01 ff 04 04 03 02 05  a0 30 1d 06 03 55 1d 25  |.........0...U.%|
-000001a0  04 16 30 14 06 08 2b 06  01 05 05 07 03 01 06 08  |..0...+.........|
-000001b0  2b 06 01 05 05 07 03 02  30 0c 06 03 55 1d 13 01  |+.......0...U...|
-000001c0  01 ff 04 02 30 00 30 19  06 03 55 1d 0e 04 12 04  |....0.0...U.....|
-000001d0  10 12 50 8d 89 6f 1b d1  dc 54 4d 6e cb 69 5e 06  |..P..o...TMn.i^.|
-000001e0  f4 30 1b 06 03 55 1d 23  04 14 30 12 80 10 bf 3d  |.0...U.#..0....=|
-000001f0  b6 a9 66 f2 b8 40 cf ea  b4 03 78 48 1a 41 30 19  |..f.. at ....xH.A0.|
-00000200  06 03 55 1d 11 04 12 30  10 82 0e 65 78 61 6d 70  |..U....0...examp|
-00000210  6c 65 2e 67 6f 6c 61 6e  67 30 0d 06 09 2a 86 48  |le.golang0...*.H|
-00000220  86 f7 0d 01 01 0b 05 00  03 81 81 00 92 7c af 91  |.............|..|
-00000230  55 12 18 96 59 31 a6 48  40 d5 2d d5 ee bb 02 a0  |U...Y1.H at .-.....|
-00000240  f5 c2 1e 7c 9b b3 30 7d  3c dc 76 da 4f 3d c0 fa  |...|..0}<.v.O=..|
-00000250  ae 2d 33 24 6b 03 7b 1b  67 59 11 21 b5 11 bc 77  |.-3$k.{.gY.!...w|
-00000260  b9 d9 e0 6e a8 2d 2e 35  fa 64 5f 22 3e 63 10 6b  |...n.-.5.d_">c.k|
-00000270  be ff 14 86 6d 0d f0 15  31 a8 14 38 1e 3b 84 87  |....m...1..8.;..|
-00000280  2c cb 98 ed 51 76 b9 b1  4f dd db 9b 84 04 86 40  |,...Qv..O......@|
-00000290  fa 51 dd ba b4 8d eb e3  46 de 46 b9 4f 86 c7 f9  |.Q......F.F.O...|
-000002a0  a4 c2 41 34 ac cc f6 ea  b0 ab 39 18 16 03 03 00  |..A4......9.....|
-000002b0  04 0e 00 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 15 75 c5 63 e0  |............u.c.|
-00000010  c3 a5 89 dd b3 bf 03 1d  bd 62 86 2e 10 98 79 cb  |.........b....y.|
-00000020  40 3d 9b 36 7e 55 65 d7  80 0a c5 24 ff ad 98 d5  |@=.6~Ue....$....|
-00000030  d4 d9 4e 1b ed 50 0a fa  8a 3e f3 01 c4 e3 47 f7  |..N..P...>....G.|
-00000040  bd 81 fc 33 0b 61 6b b5  3f 38 9b 24 cd 7d 46 66  |...3.ak.?8.$.}Ff|
-00000050  18 87 ea 67 04 b7 ad 23  ac 64 4e 21 cd 29 9f 60  |...g...#.dN!.).`|
-00000060  0e c1 ca 3d 25 d6 d5 2b  e2 60 dc b5 57 be c0 b8  |...=%..+.`..W...|
-00000070  b6 35 25 96 5b 36 55 53  86 b7 90 ef 6c bf 45 2a  |.5%.[6US....l.E*|
-00000080  3d a0 af 08 f0 8a 9c d0  d8 6b 88 14 03 03 00 01  |=........k......|
-00000090  01 16 03 03 00 30 c5 0f  b8 12 c6 5a 42 6a d8 3f  |.....0.....ZBj.?|
-000000a0  f5 49 e4 9a 5d b7 93 90  e7 09 1f 68 40 9d 33 a9  |.I..]......h at .3.|
-000000b0  21 fa 9c 12 c7 7c d4 bf  91 c2 f8 ac 27 b9 8b b6  |!....|......'...|
-000000c0  34 6e f3 c0 fb 83                                 |4n....|
+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 c1 a2 65 c1 36  63 85 cd ca 5a eb 50 ab  |.....e.6c...Z.P.|
-00000020  bb ec 43 30 37 8f 71 b9  b7 2d 1b bb a2 88 fa d5  |..C07.q..-......|
-00000030  b4 a5 c5 4b 19 71 53 46  7d bb d0 17 03 03 00 30  |...K.qSF}......0|
-00000040  00 00 00 00 00 00 00 00  6a a1 3d c6 35 a0 58 c4  |........j.=.5.X.|
-00000050  ef 12 f2 59 1e 02 42 33  42 5f fe 87 a2 1a ce b7  |...Y..B3B_......|
-00000060  0d d2 36 7c 7f 1a 4c 79  1f 38 34 58 b3 05 fb 96  |..6|..Ly.84X....|
-00000070  15 03 03 00 20 00 00 00  00 00 00 00 00 a1 89 42  |.... ..........B|
-00000080  bc 58 1f 2f 9b c4 d7 e2  d1 ce 1c c9 e0 a5 47 be  |.X./..........G.|
-00000090  63 0c a4 bf 26                                    |c...&|
+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/crypto/tls/testdata/Server-TLSv12-RSA-AES b/src/crypto/tls/testdata/Server-TLSv12-RSA-AES
index 4ca860d..a152a96 100644
--- a/src/crypto/tls/testdata/Server-TLSv12-RSA-AES
+++ b/src/crypto/tls/testdata/Server-TLSv12-RSA-AES
@@ -1,81 +1,87 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 5a 01 00 00  56 03 03 be 9a 2f 46 66  |....Z...V..../Ff|
-00000010  a3 b3 10 62 63 b6 32 cb  de 1e eb 76 13 50 60 d0  |...bc.2....v.P`.|
-00000020  ee 40 a9 cd 50 ae d8 86  10 37 8b 00 00 04 00 2f  |. at ..P....7...../|
-00000030  00 ff 01 00 00 29 00 0d  00 20 00 1e 06 01 06 02  |.....)... ......|
+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 00 0f 00 01 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 71 0b 00 02 6d 00  |..........q...m.|
-00000040  02 6a 00 02 67 30 82 02  63 30 82 01 cc a0 03 02  |.j..g0..c0......|
-00000050  01 02 02 09 00 a2 73 00  0c 81 00 cb f3 30 0d 06  |......s......0..|
-00000060  09 2a 86 48 86 f7 0d 01  01 0b 05 00 30 2b 31 17  |.*.H........0+1.|
-00000070  30 15 06 03 55 04 0a 13  0e 47 6f 6f 67 6c 65 20  |0...U....Google |
-00000080  54 45 53 54 49 4e 47 31  10 30 0e 06 03 55 04 03  |TESTING1.0...U..|
-00000090  13 07 47 6f 20 52 6f 6f  74 30 1e 17 0d 31 35 30  |..Go Root0...150|
-000000a0  31 30 31 30 30 30 30 30  30 5a 17 0d 32 35 30 31  |101000000Z..2501|
-000000b0  30 31 30 30 30 30 30 30  5a 30 26 31 17 30 15 06  |01000000Z0&1.0..|
-000000c0  03 55 04 0a 13 0e 47 6f  6f 67 6c 65 20 54 45 53  |.U....Google TES|
-000000d0  54 49 4e 47 31 0b 30 09  06 03 55 04 03 13 02 47  |TING1.0...U....G|
-000000e0  6f 30 81 9f 30 0d 06 09  2a 86 48 86 f7 0d 01 01  |o0..0...*.H.....|
-000000f0  01 05 00 03 81 8d 00 30  81 89 02 81 81 00 af 87  |.......0........|
-00000100  88 f6 20 1b 95 65 6c 14  ab 44 05 af 3b 45 14 e3  |.. ..el..D..;E..|
-00000110  b7 6d fd 00 63 4d 95 7f  fe 6a 62 35 86 c0 4a f9  |.m..cM...jb5..J.|
-00000120  18 7c f6 aa 25 5e 7a 64  31 66 00 ba f4 8e 92 af  |.|..%^zd1f......|
-00000130  c7 6b d8 76 d4 f3 5f 41  cb 6e 56 15 97 1b 97 c1  |.k.v.._A.nV.....|
-00000140  3c 12 39 21 66 3d 2b 16  d1 bc db 1c c0 a7 da b7  |<.9!f=+.........|
-00000150  ca ad ba da cb d5 21 50  ec de 8d ab d1 6b 81 4b  |......!P.....k.K|
-00000160  89 02 f3 c4 be c1 6c 89  b1 44 84 bd 21 d1 04 7d  |......l..D..!..}|
-00000170  9d 16 4d f9 82 15 f6 ef  fa d6 09 47 f2 fb 02 03  |..M........G....|
-00000180  01 00 01 a3 81 93 30 81  90 30 0e 06 03 55 1d 0f  |......0..0...U..|
-00000190  01 01 ff 04 04 03 02 05  a0 30 1d 06 03 55 1d 25  |.........0...U.%|
-000001a0  04 16 30 14 06 08 2b 06  01 05 05 07 03 01 06 08  |..0...+.........|
-000001b0  2b 06 01 05 05 07 03 02  30 0c 06 03 55 1d 13 01  |+.......0...U...|
-000001c0  01 ff 04 02 30 00 30 19  06 03 55 1d 0e 04 12 04  |....0.0...U.....|
-000001d0  10 12 50 8d 89 6f 1b d1  dc 54 4d 6e cb 69 5e 06  |..P..o...TMn.i^.|
-000001e0  f4 30 1b 06 03 55 1d 23  04 14 30 12 80 10 bf 3d  |.0...U.#..0....=|
-000001f0  b6 a9 66 f2 b8 40 cf ea  b4 03 78 48 1a 41 30 19  |..f.. at ....xH.A0.|
-00000200  06 03 55 1d 11 04 12 30  10 82 0e 65 78 61 6d 70  |..U....0...examp|
-00000210  6c 65 2e 67 6f 6c 61 6e  67 30 0d 06 09 2a 86 48  |le.golang0...*.H|
-00000220  86 f7 0d 01 01 0b 05 00  03 81 81 00 92 7c af 91  |.............|..|
-00000230  55 12 18 96 59 31 a6 48  40 d5 2d d5 ee bb 02 a0  |U...Y1.H at .-.....|
-00000240  f5 c2 1e 7c 9b b3 30 7d  3c dc 76 da 4f 3d c0 fa  |...|..0}<.v.O=..|
-00000250  ae 2d 33 24 6b 03 7b 1b  67 59 11 21 b5 11 bc 77  |.-3$k.{.gY.!...w|
-00000260  b9 d9 e0 6e a8 2d 2e 35  fa 64 5f 22 3e 63 10 6b  |...n.-.5.d_">c.k|
-00000270  be ff 14 86 6d 0d f0 15  31 a8 14 38 1e 3b 84 87  |....m...1..8.;..|
-00000280  2c cb 98 ed 51 76 b9 b1  4f dd db 9b 84 04 86 40  |,...Qv..O......@|
-00000290  fa 51 dd ba b4 8d eb e3  46 de 46 b9 4f 86 c7 f9  |.Q......F.F.O...|
-000002a0  a4 c2 41 34 ac cc f6 ea  b0 ab 39 18 16 03 03 00  |..A4......9.....|
-000002b0  04 0e 00 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 61 b4 31 93 2b  |...........a.1.+|
-00000010  d5 e8 06 74 b1 f6 d6 5f  a3 92 78 b6 cf bf 7f ea  |...t..._..x.....|
-00000020  a2 07 1e 90 94 68 5b 19  ae d4 e3 11 78 96 58 fd  |.....h[.....x.X.|
-00000030  96 18 f2 09 58 dc 39 a1  d9 9e 83 f0 24 45 6e 6b  |....X.9.....$Enk|
-00000040  e6 5e e7 cb 94 42 00 10  64 d5 d2 bc 80 23 bd fe  |.^...B..d....#..|
-00000050  5c 3e 3a 80 ff 38 b8 dc  ff 25 ba b0 0a cc ef 94  |\>:..8...%......|
-00000060  a1 31 bd 04 93 91 86 6e  8b fd a1 9d 01 ee 91 a6  |.1.....n........|
-00000070  44 8b 21 55 52 67 3e b1  e4 6e bd 1f 07 85 e1 97  |D.!URg>..n......|
-00000080  7f 55 70 00 5f f4 4b e6  50 45 f7 14 03 03 00 01  |.Up._.K.PE......|
-00000090  01 16 03 03 00 40 71 ff  ab 6d 79 3c da dc 5b 34  |..... at q..my<..[4|
-000000a0  48 39 48 08 e3 29 cb 53  21 fd 67 93 0b f8 81 47  |H9H..).S!.g....G|
-000000b0  40 7f 23 50 5f 94 db 2b  7b 7e 9f 0b bf 38 59 d9  |@.#P_..+{~...8Y.|
-000000c0  6b 57 8f 1e 83 eb 93 2c  62 12 31 c6 f5 21 f2 22  |kW.....,b.1..!."|
-000000d0  7a 82 e9 e6 ec 38                                 |z....8|
+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 45 87 33 41 c1  |...........E.3A.|
-00000020  b8 e7 4c 11 1c 1b 7b 55  51 85 06 01 c1 b6 87 6b  |..L...{UQ......k|
-00000030  01 b3 56 c4 5a 37 ea b6  3a c4 b0 da 1b 5c 15 d4  |..V.Z7..:....\..|
-00000040  03 5a 57 e9 9a 56 16 a5  fa 77 1c 17 03 03 00 40  |.ZW..V...w.....@|
+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  6f 2e 7c ba 3d 85 4c 7b  1f 13 a5 d6 97 e6 67 f4  |o.|.=.L{......g.|
-00000070  24 d5 a8 d4 26 41 64 0a  fd b3 2e a0 a2 7a 2b 54  |$...&Ad......z+T|
-00000080  a4 1d 6e fe 4c c4 73 e3  76 d0 3a 60 52 df b0 53  |..n.L.s.v.:`R..S|
+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 8b 0a 6d  14 3b 84 bc 7d c6 8d 9d  |.......m.;..}...|
-000000b0  d5 27 32 84 4b 14 75 42  0f aa 5e 88 ba fa a2 c7  |.'2.K.uB..^.....|
-000000c0  16 93 8a c4 fd                                    |.....|
+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/crypto/tls/testdata/Server-TLSv12-RSA-AES-GCM b/src/crypto/tls/testdata/Server-TLSv12-RSA-AES-GCM
index 7a26ebd..0ddfe02 100644
--- a/src/crypto/tls/testdata/Server-TLSv12-RSA-AES-GCM
+++ b/src/crypto/tls/testdata/Server-TLSv12-RSA-AES-GCM
@@ -1,87 +1,93 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 9a 01 00 00  96 03 03 16 dc f8 f5 3a  |...............:|
-00000010  13 32 e6 1f bd f6 3c 66  b7 4c 67 17 ee b2 2a ba  |.2....<f.Lg...*.|
-00000020  68 5b 8e b1 7c 8f 71 d6  6c 30 e1 00 00 04 c0 2f  |h[..|.q.l0...../|
-00000030  00 ff 01 00 00 69 00 0b  00 04 03 00 01 02 00 0a  |.....i..........|
+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 20 00 1e 06 01 06 02  |......... ......|
+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 00 0f 00 01 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 71 0b 00 02 6d 00  |..........q...m.|
-00000040  02 6a 00 02 67 30 82 02  63 30 82 01 cc a0 03 02  |.j..g0..c0......|
-00000050  01 02 02 09 00 a2 73 00  0c 81 00 cb f3 30 0d 06  |......s......0..|
-00000060  09 2a 86 48 86 f7 0d 01  01 0b 05 00 30 2b 31 17  |.*.H........0+1.|
-00000070  30 15 06 03 55 04 0a 13  0e 47 6f 6f 67 6c 65 20  |0...U....Google |
-00000080  54 45 53 54 49 4e 47 31  10 30 0e 06 03 55 04 03  |TESTING1.0...U..|
-00000090  13 07 47 6f 20 52 6f 6f  74 30 1e 17 0d 31 35 30  |..Go Root0...150|
-000000a0  31 30 31 30 30 30 30 30  30 5a 17 0d 32 35 30 31  |101000000Z..2501|
-000000b0  30 31 30 30 30 30 30 30  5a 30 26 31 17 30 15 06  |01000000Z0&1.0..|
-000000c0  03 55 04 0a 13 0e 47 6f  6f 67 6c 65 20 54 45 53  |.U....Google TES|
-000000d0  54 49 4e 47 31 0b 30 09  06 03 55 04 03 13 02 47  |TING1.0...U....G|
-000000e0  6f 30 81 9f 30 0d 06 09  2a 86 48 86 f7 0d 01 01  |o0..0...*.H.....|
-000000f0  01 05 00 03 81 8d 00 30  81 89 02 81 81 00 af 87  |.......0........|
-00000100  88 f6 20 1b 95 65 6c 14  ab 44 05 af 3b 45 14 e3  |.. ..el..D..;E..|
-00000110  b7 6d fd 00 63 4d 95 7f  fe 6a 62 35 86 c0 4a f9  |.m..cM...jb5..J.|
-00000120  18 7c f6 aa 25 5e 7a 64  31 66 00 ba f4 8e 92 af  |.|..%^zd1f......|
-00000130  c7 6b d8 76 d4 f3 5f 41  cb 6e 56 15 97 1b 97 c1  |.k.v.._A.nV.....|
-00000140  3c 12 39 21 66 3d 2b 16  d1 bc db 1c c0 a7 da b7  |<.9!f=+.........|
-00000150  ca ad ba da cb d5 21 50  ec de 8d ab d1 6b 81 4b  |......!P.....k.K|
-00000160  89 02 f3 c4 be c1 6c 89  b1 44 84 bd 21 d1 04 7d  |......l..D..!..}|
-00000170  9d 16 4d f9 82 15 f6 ef  fa d6 09 47 f2 fb 02 03  |..M........G....|
-00000180  01 00 01 a3 81 93 30 81  90 30 0e 06 03 55 1d 0f  |......0..0...U..|
-00000190  01 01 ff 04 04 03 02 05  a0 30 1d 06 03 55 1d 25  |.........0...U.%|
-000001a0  04 16 30 14 06 08 2b 06  01 05 05 07 03 01 06 08  |..0...+.........|
-000001b0  2b 06 01 05 05 07 03 02  30 0c 06 03 55 1d 13 01  |+.......0...U...|
-000001c0  01 ff 04 02 30 00 30 19  06 03 55 1d 0e 04 12 04  |....0.0...U.....|
-000001d0  10 12 50 8d 89 6f 1b d1  dc 54 4d 6e cb 69 5e 06  |..P..o...TMn.i^.|
-000001e0  f4 30 1b 06 03 55 1d 23  04 14 30 12 80 10 bf 3d  |.0...U.#..0....=|
-000001f0  b6 a9 66 f2 b8 40 cf ea  b4 03 78 48 1a 41 30 19  |..f.. at ....xH.A0.|
-00000200  06 03 55 1d 11 04 12 30  10 82 0e 65 78 61 6d 70  |..U....0...examp|
-00000210  6c 65 2e 67 6f 6c 61 6e  67 30 0d 06 09 2a 86 48  |le.golang0...*.H|
-00000220  86 f7 0d 01 01 0b 05 00  03 81 81 00 92 7c af 91  |.............|..|
-00000230  55 12 18 96 59 31 a6 48  40 d5 2d d5 ee bb 02 a0  |U...Y1.H at .-.....|
-00000240  f5 c2 1e 7c 9b b3 30 7d  3c dc 76 da 4f 3d c0 fa  |...|..0}<.v.O=..|
-00000250  ae 2d 33 24 6b 03 7b 1b  67 59 11 21 b5 11 bc 77  |.-3$k.{.gY.!...w|
-00000260  b9 d9 e0 6e a8 2d 2e 35  fa 64 5f 22 3e 63 10 6b  |...n.-.5.d_">c.k|
-00000270  be ff 14 86 6d 0d f0 15  31 a8 14 38 1e 3b 84 87  |....m...1..8.;..|
-00000280  2c cb 98 ed 51 76 b9 b1  4f dd db 9b 84 04 86 40  |,...Qv..O......@|
-00000290  fa 51 dd ba b4 8d eb e3  46 de 46 b9 4f 86 c7 f9  |.Q......F.F.O...|
-000002a0  a4 c2 41 34 ac cc f6 ea  b0 ab 39 18 16 03 03 00  |..A4......9.....|
-000002b0  cd 0c 00 00 c9 03 00 17  41 04 1e 18 37 ef 0d 19  |........A...7...|
-000002c0  51 88 35 75 71 b5 e5 54  5b 12 2e 8f 09 67 fd a7  |Q.5uq..T[....g..|
-000002d0  24 20 3e b2 56 1c ce 97  28 5e f8 2b 2d 4f 9e f1  |$ >.V...(^.+-O..|
-000002e0  07 9f 6c 4b 5b 83 56 e2  32 42 e9 58 b6 d7 49 a6  |..lK[.V.2B.X..I.|
-000002f0  b5 68 1a 41 03 56 6b dc  5a 89 05 01 00 80 40 b3  |.h.A.Vk.Z..... at .|
-00000300  66 ee 53 3c 80 f4 da d1  de e6 fe 50 c8 89 60 d5  |f.S<.......P..`.|
-00000310  e4 80 73 39 91 79 6c cf  89 bb a5 da e4 c7 e5 0d  |..s9.yl.........|
-00000320  13 a6 76 24 65 1a a2 b8  cb 95 c2 c6 9d 66 74 57  |..v$e........ftW|
-00000330  9e 90 4f 48 77 88 3a b4  f3 fa 88 ab 61 22 d3 40  |..OHw.:.....a".@|
-00000340  08 c4 0a 69 19 ed c3 ea  d8 15 79 12 d5 ac 8d af  |...i......y.....|
-00000350  41 7d 87 4b a9 ff f8 cb  24 55 88 38 34 11 a5 bd  |A}.K....$U.84...|
-00000360  c1 d6 e5 86 d5 64 b5 f2  df c8 03 f2 a2 6b ff f4  |.....d.......k..|
-00000370  a8 38 e0 18 04 d4 cd bd  e0 cc 63 fc 3f 8b 16 03  |.8........c.?...|
-00000380  03 00 04 0e 00 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 de de ff 8c df  |....F...BA......|
-00000010  d8 4c 72 af 29 3c 4d e0  ed 0f 34 cc fd 2d 52 63  |.Lr.)<M...4..-Rc|
-00000020  94 e8 74 f1 0b 18 69 28  ed 1e f7 62 4e 4f 2c 14  |..t...i(...bNO,.|
-00000030  61 4b 9f 55 d8 70 59 8f  4b a8 ab c6 d2 cd aa 59  |aK.U.pY.K......Y|
-00000040  8a ef 9b b3 f6 ba 52 e5  51 bb a1 14 03 03 00 01  |......R.Q.......|
-00000050  01 16 03 03 00 28 44 1c  eb 89 59 bb ad fb 9f 3f  |.....(D...Y....?|
-00000060  56 06 54 ae 27 6d e4 47  3c 0c 60 30 db 0e d6 0e  |V.T.'m.G<.`0....|
-00000070  9d 0d a9 a0 e7 25 26 6e  99 d0 8f e0 1b 9d        |.....%&n......|
+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 92 90 01 f0 70  fa 57 2e 40 d3 4c ef 6a  |.......p.W. at .L.j|
-00000020  03 0c 56 65 f7 c0 3b d0  8a db 48 c9 ae 58 3e 7c  |..Ve..;...H..X>||
-00000030  d1 48 67 17 03 03 00 25  00 00 00 00 00 00 00 01  |.Hg....%........|
-00000040  9e 35 a0 13 73 da 3f 26  ff 1d 90 08 e9 cc 40 7e  |.5..s.?&......@~|
-00000050  82 f3 5e 6e b4 8e 5a 39  7f a4 09 60 b2 15 03 03  |..^n..Z9...`....|
-00000060  00 1a 00 00 00 00 00 00  00 02 04 95 9b 2d 17 1c  |.............-..|
-00000070  6a bc 26 f7 6c 8e f1 c0  0e 82 4a 44              |j.&.l.....JD|
+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/crypto/tls/testdata/Server-TLSv12-RSA-RC4 b/src/crypto/tls/testdata/Server-TLSv12-RSA-RC4
index 13163d6..b703a8f 100644
--- a/src/crypto/tls/testdata/Server-TLSv12-RSA-RC4
+++ b/src/crypto/tls/testdata/Server-TLSv12-RSA-RC4
@@ -1,73 +1,79 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 5a 01 00 00  56 03 03 8a fe f5 09 70  |....Z...V......p|
-00000010  8e 6b e3 2b 12 ff d1 b2  ae 15 bf 47 0e ca 5c b5  |.k.+.......G..\.|
-00000020  bb 0e ad af e5 a6 7e 36  c5 a4 c3 00 00 04 00 05  |......~6........|
-00000030  00 ff 01 00 00 29 00 0d  00 20 00 1e 06 01 06 02  |.....)... ......|
+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 00 0f 00 01 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 71 0b 00 02 6d 00  |..........q...m.|
-00000040  02 6a 00 02 67 30 82 02  63 30 82 01 cc a0 03 02  |.j..g0..c0......|
-00000050  01 02 02 09 00 a2 73 00  0c 81 00 cb f3 30 0d 06  |......s......0..|
-00000060  09 2a 86 48 86 f7 0d 01  01 0b 05 00 30 2b 31 17  |.*.H........0+1.|
-00000070  30 15 06 03 55 04 0a 13  0e 47 6f 6f 67 6c 65 20  |0...U....Google |
-00000080  54 45 53 54 49 4e 47 31  10 30 0e 06 03 55 04 03  |TESTING1.0...U..|
-00000090  13 07 47 6f 20 52 6f 6f  74 30 1e 17 0d 31 35 30  |..Go Root0...150|
-000000a0  31 30 31 30 30 30 30 30  30 5a 17 0d 32 35 30 31  |101000000Z..2501|
-000000b0  30 31 30 30 30 30 30 30  5a 30 26 31 17 30 15 06  |01000000Z0&1.0..|
-000000c0  03 55 04 0a 13 0e 47 6f  6f 67 6c 65 20 54 45 53  |.U....Google TES|
-000000d0  54 49 4e 47 31 0b 30 09  06 03 55 04 03 13 02 47  |TING1.0...U....G|
-000000e0  6f 30 81 9f 30 0d 06 09  2a 86 48 86 f7 0d 01 01  |o0..0...*.H.....|
-000000f0  01 05 00 03 81 8d 00 30  81 89 02 81 81 00 af 87  |.......0........|
-00000100  88 f6 20 1b 95 65 6c 14  ab 44 05 af 3b 45 14 e3  |.. ..el..D..;E..|
-00000110  b7 6d fd 00 63 4d 95 7f  fe 6a 62 35 86 c0 4a f9  |.m..cM...jb5..J.|
-00000120  18 7c f6 aa 25 5e 7a 64  31 66 00 ba f4 8e 92 af  |.|..%^zd1f......|
-00000130  c7 6b d8 76 d4 f3 5f 41  cb 6e 56 15 97 1b 97 c1  |.k.v.._A.nV.....|
-00000140  3c 12 39 21 66 3d 2b 16  d1 bc db 1c c0 a7 da b7  |<.9!f=+.........|
-00000150  ca ad ba da cb d5 21 50  ec de 8d ab d1 6b 81 4b  |......!P.....k.K|
-00000160  89 02 f3 c4 be c1 6c 89  b1 44 84 bd 21 d1 04 7d  |......l..D..!..}|
-00000170  9d 16 4d f9 82 15 f6 ef  fa d6 09 47 f2 fb 02 03  |..M........G....|
-00000180  01 00 01 a3 81 93 30 81  90 30 0e 06 03 55 1d 0f  |......0..0...U..|
-00000190  01 01 ff 04 04 03 02 05  a0 30 1d 06 03 55 1d 25  |.........0...U.%|
-000001a0  04 16 30 14 06 08 2b 06  01 05 05 07 03 01 06 08  |..0...+.........|
-000001b0  2b 06 01 05 05 07 03 02  30 0c 06 03 55 1d 13 01  |+.......0...U...|
-000001c0  01 ff 04 02 30 00 30 19  06 03 55 1d 0e 04 12 04  |....0.0...U.....|
-000001d0  10 12 50 8d 89 6f 1b d1  dc 54 4d 6e cb 69 5e 06  |..P..o...TMn.i^.|
-000001e0  f4 30 1b 06 03 55 1d 23  04 14 30 12 80 10 bf 3d  |.0...U.#..0....=|
-000001f0  b6 a9 66 f2 b8 40 cf ea  b4 03 78 48 1a 41 30 19  |..f.. at ....xH.A0.|
-00000200  06 03 55 1d 11 04 12 30  10 82 0e 65 78 61 6d 70  |..U....0...examp|
-00000210  6c 65 2e 67 6f 6c 61 6e  67 30 0d 06 09 2a 86 48  |le.golang0...*.H|
-00000220  86 f7 0d 01 01 0b 05 00  03 81 81 00 92 7c af 91  |.............|..|
-00000230  55 12 18 96 59 31 a6 48  40 d5 2d d5 ee bb 02 a0  |U...Y1.H at .-.....|
-00000240  f5 c2 1e 7c 9b b3 30 7d  3c dc 76 da 4f 3d c0 fa  |...|..0}<.v.O=..|
-00000250  ae 2d 33 24 6b 03 7b 1b  67 59 11 21 b5 11 bc 77  |.-3$k.{.gY.!...w|
-00000260  b9 d9 e0 6e a8 2d 2e 35  fa 64 5f 22 3e 63 10 6b  |...n.-.5.d_">c.k|
-00000270  be ff 14 86 6d 0d f0 15  31 a8 14 38 1e 3b 84 87  |....m...1..8.;..|
-00000280  2c cb 98 ed 51 76 b9 b1  4f dd db 9b 84 04 86 40  |,...Qv..O......@|
-00000290  fa 51 dd ba b4 8d eb e3  46 de 46 b9 4f 86 c7 f9  |.Q......F.F.O...|
-000002a0  a4 c2 41 34 ac cc f6 ea  b0 ab 39 18 16 03 03 00  |..A4......9.....|
-000002b0  04 0e 00 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 1c f7 2c 18 38  |.............,.8|
-00000010  d9 41 b5 ab b7 35 2b 75  2d 66 ba c8 70 c2 19 1c  |.A...5+u-f..p...|
-00000020  f2 6d d9 a9 a8 40 8e b5  2c 75 99 06 a5 25 be 0d  |.m... at ..,u...%..|
-00000030  b4 b0 9b aa fc 6b 12 a5  b3 e7 02 60 aa 25 e9 7f  |.....k.....`.%..|
-00000040  6b f5 c4 7a 1d 16 a5 d1  76 cc d5 a1 18 68 91 c3  |k..z....v....h..|
-00000050  57 b8 10 f2 b8 81 f3 1b  74 ef 6c 37 3e 81 41 09  |W.......t.l7>.A.|
-00000060  2a c5 15 e6 cc bb 74 4c  01 7a b9 82 5c e2 7f b7  |*.....tL.z..\...|
-00000070  ac 2d 76 30 18 30 c2 19  8c 5f f2 80 41 89 bb 47  |.-v0.0..._..A..G|
-00000080  28 3d 61 cc 3c 06 a8 76  93 57 71 14 03 03 00 01  |(=a.<..v.Wq.....|
-00000090  01 16 03 03 00 24 46 34  1f cc eb 53 c7 d2 04 28  |.....$F4...S...(|
-000000a0  b6 3d 3f 39 06 70 56 b7  db eb 53 9c 66 c3 45 9f  |.=?9.pV...S.f.E.|
-000000b0  69 ca 58 8f e7 ba a7 e6  5a 97                    |i.X.....Z.|
+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 78 c3 02 89 60  |..........$x...`|
-00000010  e7 72 9f 51 87 14 ca 2e  0d 79 98 eb 1e 39 62 f9  |.r.Q.....y...9b.|
-00000020  fc a5 c9 2c f8 0c 04 16  60 70 90 b7 31 f8 30 17  |...,....`p..1.0.|
-00000030  03 03 00 21 6a b7 24 73  a7 0d 17 04 d7 54 a8 ea  |...!j.$s.....T..|
-00000040  28 4e f2 0a ef 87 d5 a9  b8 84 81 46 8e 97 d1 ae  |(N.........F....|
-00000050  3c cc b1 6b 72 15 03 03  00 16 1a bb 2f df ae 3e  |<..kr......./..>|
-00000060  a7 89 69 3e 35 f2 f6 cd  35 60 29 3a 6f be 32 0d  |..i>5...5`):o.2.|
+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/crypto/tls/testdata/Server-TLSv12-Resume b/src/crypto/tls/testdata/Server-TLSv12-Resume
index 8cacd21..c495d4a 100644
--- a/src/crypto/tls/testdata/Server-TLSv12-Resume
+++ b/src/crypto/tls/testdata/Server-TLSv12-Resume
@@ -1,37 +1,36 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 f6 01 00 00  f2 03 03 53 1e 13 2e bd  |...........S....|
-00000010  ad 66 fd 77 1a ad 5f 4d  cb bd 2e ca b5 c2 45 1d  |.f.w.._M......E.|
-00000020  7c 83 9d 62 3e 39 9c ce  78 99 e7 20 b4 06 b0 ec  ||..b>9..x.. ....|
-00000030  cf b7 52 6e 38 10 31 37  b2 e6 58 0f fa e3 b0 cb  |..Rn8.17..X.....|
-00000040  20 a4 d2 4b f3 7d 92 e6  7e 13 37 08 00 04 00 05  | ..K.}..~.7.....|
-00000050  00 ff 01 00 00 a5 00 23  00 78 50 46 ad c1 db a8  |.......#.xPF....|
-00000060  38 86 7b 2b bb fd d0 c3  42 3e 00 00 00 00 00 00  |8.{+....B>......|
-00000070  00 00 00 00 00 00 00 00  00 00 94 6f 2c b5 83 61  |...........o,..a|
-00000080  c4 74 90 94 e5 6c fd 70  64 57 3a 25 78 bf 9f a0  |.t...l.pdW:%x...|
-00000090  7c 51 bc 2a 69 1e b3 fd  71 34 b7 9a ef cb 49 37  ||Q.*i...q4....I7|
-000000a0  f8 5d 5e 7c cf 6d fc 13  c1 52 79 8e ed c3 84 01  |.]^|.m...Ry.....|
-000000b0  33 94 10 65 34 64 5e b4  9c 07 46 5b 9e d7 5e 55  |3..e4d^...F[..^U|
-000000c0  df fd c0 e9 d2 e8 d3 c6  42 18 ef a5 6c be e8 d2  |........B...l...|
-000000d0  49 c6 00 0d 00 20 00 1e  06 01 06 02 06 03 05 01  |I.... ..........|
-000000e0  05 02 05 03 04 01 04 02  04 03 03 01 03 02 03 03  |................|
-000000f0  02 01 02 02 02 03 00 0f  00 01 01                 |...........|
+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 b4 06 b0 ec  |........... ....|
-00000030  cf b7 52 6e 38 10 31 37  b2 e6 58 0f fa e3 b0 cb  |..Rn8.17..X.....|
-00000040  20 a4 d2 4b f3 7d 92 e6  7e 13 37 08 00 05 00 00  | ..K.}..~.7.....|
+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 24 31 13 8c 45 4f 8a  fc 71 50 94 b0 6f 02 5e  |$$1..EO..qP..o.^|
-00000070  da d3 a3 13 8b c8 53 fb  54 8d ef 90 f7 55 b1 be  |......S.T....U..|
-00000080  37 30 05 e5 5d                                    |70..]|
+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 ed dd e4 a5 09  |..........$.....|
-00000010  0d 7c cb e4 90 9c a1 1c  21 f4 13 bd 45 8f f4 d8  |.|......!...E...|
-00000020  7e e2 89 7a 0d f4 75 99  66 8c 05 a3 1a e2 2b     |~..z..u.f.....+|
+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 69 fa 9e  98 fb 7a 95 b1 8e e5 74  |....!i....z....t|
-00000010  03 02 d7 3d 69 c4 b8 c9  5b 49 e3 30 32 e3 c5 6a  |...=i...[I.02..j|
-00000020  fa 20 98 bd 01 ed 15 03  03 00 16 c9 b1 20 1f 30  |. ........... .0|
-00000030  c1 2f 15 75 cd 82 45 de  1a 81 cd dc 10 05 1c 45  |./.u..E........E|
-00000040  dc                                                |.|
+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/crypto/tls/testdata/Server-TLSv12-ResumeDisabled b/src/crypto/tls/testdata/Server-TLSv12-ResumeDisabled
index 912c178..db833f6 100644
--- a/src/crypto/tls/testdata/Server-TLSv12-ResumeDisabled
+++ b/src/crypto/tls/testdata/Server-TLSv12-ResumeDisabled
@@ -1,83 +1,87 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 f6 01 00 00  f2 03 03 aa 0c c2 75 42  |..............uB|
-00000010  62 2a 1d 14 a0 cc a1 e4  a7 19 77 50 80 2b f8 05  |b*........wP.+..|
-00000020  0b fa 60 3a a7 a7 84 d3  e1 68 26 20 68 97 0c ae  |..`:.....h& h...|
-00000030  7b 1d bc 13 14 a8 f6 c1  e1 96 1f 54 18 2c cb 99  |{..........T.,..|
-00000040  17 7d be 45 6a 39 53 c6  50 c7 8c 75 00 04 00 05  |.}.Ej9S.P..u....|
-00000050  00 ff 01 00 00 a5 00 23  00 78 50 46 ad c1 db a8  |.......#.xPF....|
-00000060  38 86 7b 2b bb fd d0 c3  42 3e 00 00 00 00 00 00  |8.{+....B>......|
-00000070  00 00 00 00 00 00 00 00  00 00 94 6f 2c b5 83 61  |...........o,..a|
-00000080  bd 50 da 49 7f 8b 8f 58  57 00 a1 11 0d 4a 9d 8a  |.P.I...XW....J..|
-00000090  39 dd 85 23 c0 eb 9d 1a  45 93 92 e7 af 15 a3 a4  |9..#....E.......|
-000000a0  48 da f9 a4 d8 8e cb 6c  3d 44 77 f9 c4 83 89 85  |H......l=Dw.....|
-000000b0  33 94 c1 c6 20 9a 73 44  83 89 5e 59 ee 05 c6 7e  |3... .sD..^Y...~|
-000000c0  8d e9 7d 7b f8 84 46 b6  7d 43 ec f1 af 1f 0f 35  |..}{..F.}C.....5|
-000000d0  b4 1c 00 0d 00 20 00 1e  06 01 06 02 06 03 05 01  |..... ..........|
-000000e0  05 02 05 03 04 01 04 02  04 03 03 01 03 02 03 03  |................|
-000000f0  02 01 02 02 02 03 00 0f  00 01 01                 |...........|
+00000000  16 03 01 00 e8 01 00 00  e4 03 03 54 23 54 02 a5  |...........T#T..|
+00000010  10 11 0f 6d e5 2d 2f e8  bb 52 b1 38 3f 65 01 43  |...m.-/..R.8?e.C|
+00000020  36 cc 48 f6 09 22 a1 85  20 28 3c 20 35 8b fe 7a  |6.H..".. (< 5..z|
+00000030  41 3b 59 3a 5d b9 b3 21  f0 62 e9 0d 7b af f5 5d  |A;Y:]..!.b..{..]|
+00000040  fa 65 1a 40 c8 ca cd 74  8c ef d2 fb 00 04 00 05  |.e. at ...t........|
+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  2d db 0c ba 9a d4 20 76  57 c8 ec dc 2d 77 fb fb  |-..... vW...-w..|
+00000080  3b 93 5f 53 e0 14 4f 90  fb d6 55 57 8c 8d 0d 25  |;._S..O...UW...%|
+00000090  ea 5d 0d f2 91 e5 12 22  12 ec 7b 5f b6 6e fd 07  |.]....."..{_.n..|
+000000a0  59 23 24 fc b1 97 ca ea  56 a5 c2 a0 e4 9e 99 64  |Y#$.....V......d|
+000000b0  f2 64 d0 75 7a 46 63 e3  dc 21 ed 78 56 e9 e1 ab  |.d.uzFc..!.xV...|
+000000c0  66 80 00 0d 00 22 00 20  06 01 06 02 06 03 05 01  |f....". ........|
+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 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 71 0b 00 02 6d 00  |..........q...m.|
-00000040  02 6a 00 02 67 30 82 02  63 30 82 01 cc a0 03 02  |.j..g0..c0......|
-00000050  01 02 02 09 00 a2 73 00  0c 81 00 cb f3 30 0d 06  |......s......0..|
-00000060  09 2a 86 48 86 f7 0d 01  01 0b 05 00 30 2b 31 17  |.*.H........0+1.|
-00000070  30 15 06 03 55 04 0a 13  0e 47 6f 6f 67 6c 65 20  |0...U....Google |
-00000080  54 45 53 54 49 4e 47 31  10 30 0e 06 03 55 04 03  |TESTING1.0...U..|
-00000090  13 07 47 6f 20 52 6f 6f  74 30 1e 17 0d 31 35 30  |..Go Root0...150|
-000000a0  31 30 31 30 30 30 30 30  30 5a 17 0d 32 35 30 31  |101000000Z..2501|
-000000b0  30 31 30 30 30 30 30 30  5a 30 26 31 17 30 15 06  |01000000Z0&1.0..|
-000000c0  03 55 04 0a 13 0e 47 6f  6f 67 6c 65 20 54 45 53  |.U....Google TES|
-000000d0  54 49 4e 47 31 0b 30 09  06 03 55 04 03 13 02 47  |TING1.0...U....G|
-000000e0  6f 30 81 9f 30 0d 06 09  2a 86 48 86 f7 0d 01 01  |o0..0...*.H.....|
-000000f0  01 05 00 03 81 8d 00 30  81 89 02 81 81 00 af 87  |.......0........|
-00000100  88 f6 20 1b 95 65 6c 14  ab 44 05 af 3b 45 14 e3  |.. ..el..D..;E..|
-00000110  b7 6d fd 00 63 4d 95 7f  fe 6a 62 35 86 c0 4a f9  |.m..cM...jb5..J.|
-00000120  18 7c f6 aa 25 5e 7a 64  31 66 00 ba f4 8e 92 af  |.|..%^zd1f......|
-00000130  c7 6b d8 76 d4 f3 5f 41  cb 6e 56 15 97 1b 97 c1  |.k.v.._A.nV.....|
-00000140  3c 12 39 21 66 3d 2b 16  d1 bc db 1c c0 a7 da b7  |<.9!f=+.........|
-00000150  ca ad ba da cb d5 21 50  ec de 8d ab d1 6b 81 4b  |......!P.....k.K|
-00000160  89 02 f3 c4 be c1 6c 89  b1 44 84 bd 21 d1 04 7d  |......l..D..!..}|
-00000170  9d 16 4d f9 82 15 f6 ef  fa d6 09 47 f2 fb 02 03  |..M........G....|
-00000180  01 00 01 a3 81 93 30 81  90 30 0e 06 03 55 1d 0f  |......0..0...U..|
-00000190  01 01 ff 04 04 03 02 05  a0 30 1d 06 03 55 1d 25  |.........0...U.%|
-000001a0  04 16 30 14 06 08 2b 06  01 05 05 07 03 01 06 08  |..0...+.........|
-000001b0  2b 06 01 05 05 07 03 02  30 0c 06 03 55 1d 13 01  |+.......0...U...|
-000001c0  01 ff 04 02 30 00 30 19  06 03 55 1d 0e 04 12 04  |....0.0...U.....|
-000001d0  10 12 50 8d 89 6f 1b d1  dc 54 4d 6e cb 69 5e 06  |..P..o...TMn.i^.|
-000001e0  f4 30 1b 06 03 55 1d 23  04 14 30 12 80 10 bf 3d  |.0...U.#..0....=|
-000001f0  b6 a9 66 f2 b8 40 cf ea  b4 03 78 48 1a 41 30 19  |..f.. at ....xH.A0.|
-00000200  06 03 55 1d 11 04 12 30  10 82 0e 65 78 61 6d 70  |..U....0...examp|
-00000210  6c 65 2e 67 6f 6c 61 6e  67 30 0d 06 09 2a 86 48  |le.golang0...*.H|
-00000220  86 f7 0d 01 01 0b 05 00  03 81 81 00 92 7c af 91  |.............|..|
-00000230  55 12 18 96 59 31 a6 48  40 d5 2d d5 ee bb 02 a0  |U...Y1.H at .-.....|
-00000240  f5 c2 1e 7c 9b b3 30 7d  3c dc 76 da 4f 3d c0 fa  |...|..0}<.v.O=..|
-00000250  ae 2d 33 24 6b 03 7b 1b  67 59 11 21 b5 11 bc 77  |.-3$k.{.gY.!...w|
-00000260  b9 d9 e0 6e a8 2d 2e 35  fa 64 5f 22 3e 63 10 6b  |...n.-.5.d_">c.k|
-00000270  be ff 14 86 6d 0d f0 15  31 a8 14 38 1e 3b 84 87  |....m...1..8.;..|
-00000280  2c cb 98 ed 51 76 b9 b1  4f dd db 9b 84 04 86 40  |,...Qv..O......@|
-00000290  fa 51 dd ba b4 8d eb e3  46 de 46 b9 4f 86 c7 f9  |.Q......F.F.O...|
-000002a0  a4 c2 41 34 ac cc f6 ea  b0 ab 39 18 16 03 03 00  |..A4......9.....|
-000002b0  04 0e 00 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 ac 10 32 61 b0  |.............2a.|
-00000010  03 e3 1e 2f 89 91 5f d6  4c e0 82 a7 82 41 67 d3  |.../.._.L....Ag.|
-00000020  5f b3 68 2d c0 d1 6f 03  7b 79 94 cc bb 35 6c 8a  |_.h-..o.{y...5l.|
-00000030  bf 1c 83 ff 88 91 5c 04  64 cc a0 df 0b 08 8c 0f  |......\.d.......|
-00000040  72 13 17 9f 27 14 8d 9a  af 17 70 41 44 9f 89 8c  |r...'.....pAD...|
-00000050  fa e4 66 33 4d bd 2f 93  2a 1e 85 a1 af 9e 27 12  |..f3M./.*.....'.|
-00000060  59 a4 13 67 56 85 c2 86  47 f8 c5 49 8f a4 c2 6e  |Y..gV...G..I...n|
-00000070  04 78 0f 11 2b fb 7e 34  b8 eb 25 93 71 ab 9f f5  |.x..+.~4..%.q...|
-00000080  93 df 2b c3 1e 9e 6a 9e  e3 57 aa 14 03 03 00 01  |..+...j..W......|
-00000090  01 16 03 03 00 24 e0 13  15 10 4c db f3 b6 de d2  |.....$....L.....|
-000000a0  68 02 f5 ea 1f 8e 58 70  4a 5a 78 d9 66 c5 74 77  |h.....XpJZx.f.tw|
-000000b0  a0 3a ec d8 b7 42 e3 a5  d4 62                    |.:...B...b|
+00000000  16 03 03 00 86 10 00 00  82 00 80 ae 02 dd 1f 1a  |................|
+00000010  86 83 f5 2f 82 46 4b 29  58 aa a1 b3 56 8b 4e 40  |.../.FK)X...V.N@|
+00000020  ef 23 65 67 ad 48 e5 e1  fd ae dd bf 68 fd bd a6  |.#eg.H......h...|
+00000030  13 a0 7e 05 ab f7 20 e1  6a 4e d1 37 93 08 1d c9  |..~... .jN.7....|
+00000040  37 e0 b5 34 28 bf 20 45  45 da 0f 7e 51 a7 c6 ae  |7..4(. EE..~Q...|
+00000050  61 6c 07 1b 73 ef da 6e  25 c4 ed be e3 3f da ae  |al..s..n%....?..|
+00000060  cd 3c 17 9c 2e ee fb 47  9d b3 a1 b2 c3 5d e0 83  |.<.....G.....]..|
+00000070  74 20 37 2d 72 d6 d0 4d  58 0e 26 1c 50 22 95 08  |t 7-r..MX.&.P"..|
+00000080  7d e0 5f 86 99 9e 2c 2e  a7 a0 7f 14 03 03 00 01  |}._...,.........|
+00000090  01 16 03 03 00 24 a2 ab  41 25 a5 cf 04 18 1d 98  |.....$..A%......|
+000000a0  88 6c 59 21 86 33 54 f4  35 b4 21 6e a5 29 d5 6e  |.lY!.3T.5.!n.).n|
+000000b0  3d 08 72 b0 af 46 b5 8f  6b 86                    |=.r..F..k.|
 >>> Flow 4 (server to client)
-00000000  14 03 03 00 01 01 16 03  03 00 24 e9 c1 1f 5b e6  |..........$...[.|
-00000010  c1 d5 8a 14 eb c6 41 c1  77 6d 59 83 b6 95 34 f9  |......A.wmY...4.|
-00000020  7b a1 c9 9d 58 a5 b2 1b  33 6e 04 ab e0 03 61 17  |{...X...3n....a.|
-00000030  03 03 00 21 67 8b 55 43  d7 a7 05 c9 1f a0 d3 65  |...!g.UC.......e|
-00000040  30 36 07 8f d8 52 7e 40  79 31 2e 1c 1a c2 a6 fe  |06...R~@y1......|
-00000050  e0 39 4d a0 5d 15 03 03  00 16 b8 94 fb 17 e5 1d  |.9M.]...........|
-00000060  2e 28 95 cf 02 85 8e 11  2e 16 b1 53 72 aa a4 94  |.(.........Sr...|
+00000000  14 03 03 00 01 01 16 03  03 00 24 59 20 4d c2 17  |..........$Y M..|
+00000010  8b 3c 9b 33 d9 f9 ef fb  80 18 1f 67 a7 58 12 89  |.<.3.......g.X..|
+00000020  4e 73 0f 2d 7b e6 c4 a6  79 73 01 da 22 e8 54 17  |Ns.-{...ys..".T.|
+00000030  03 03 00 21 36 ca 64 0f  4a 12 a5 50 3d 97 bb 39  |...!6.d.J..P=..9|
+00000040  02 fc ed d1 82 6a 9a 2e  21 79 f6 e1 b3 cc 32 db  |.....j..!y....2.|
+00000050  0f 5d b3 fb a5 15 03 03  00 16 51 f4 be 57 7a df  |.]........Q..Wz.|
+00000060  f1 f2 bd b5 51 5e 45 80  be 0b 9a 0c d1 19 3c 79  |....Q^E.......<y|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-SNI b/src/crypto/tls/testdata/Server-TLSv12-SNI
index aee5742..61b17a1 100644
--- a/src/crypto/tls/testdata/Server-TLSv12-SNI
+++ b/src/crypto/tls/testdata/Server-TLSv12-SNI
@@ -1,12 +1,12 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 6e 01 00 00  6a 03 03 be 99 22 5c d2  |....n...j...."\.|
-00000010  02 c7 a6 be f3 33 7a d4  76 1f cf 1e 39 0b 25 7c  |.....3z.v...9.%||
-00000020  32 70 e4 8c 49 a6 87 b9  c1 2f 6d 00 00 04 00 2f  |2p..I..../m..../|
-00000030  00 ff 01 00 00 3d 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 20 00 1e  |nitest.com... ..|
+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 00 0f  |................|
-00000070  00 01 01                                          |...|
+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  |................|
@@ -46,19 +46,31 @@
 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 6b 03 31 ca a0  |...........k.1..|
-00000010  62 a2 53 11 ce 13 d9 f6  e7 d4 ec 2e c3 0a 38 56  |b.S...........8V|
-00000020  23 22 67 23 c8 8d 16 b4  3c 0b 26 9f 1c 2d 65 13  |#"g#....<.&..-e.|
-00000030  c3 cb 65 69 b0 47 ff 87  e8 02 56 c4 77 8a 40 29  |..ei.G....V.w.@)|
-00000040  82 62 8b 06 61 0a 1c b3  c7 29 b6 aa c9 96 37 18  |.b..a....)....7.|
-00000050  d0 60 66 63 9b 62 4b 30  cc 03 9c 37 05 c6 32 98  |.`fc.bK0...7..2.|
-00000060  cb a0 e2 e4 38 60 d4 93  99 9a fc 03 66 fb b6 ef  |....8`......f...|
-00000070  8a 1e bb ca 13 c5 d9 7a  7c 3b 50 dc d0 ad 00 b5  |.......z|;P.....|
-00000080  2c dc 1a ef c4 5c af d3  4e cd e6 14 03 03 00 01  |,....\..N.......|
-00000090  01 16 03 03 00 40 42 31  83 8a 2c 86 22 c5 df e5  |..... at B1..,."...|
-000000a0  f2 0b f8 0c 2f 1e 82 f4  69 fe 1d bd 4c db f1 80  |..../...i...L...|
-000000b0  68 30 b7 e3 60 76 b3 f1  52 ae d6 e7 b3 cb 4a e0  |h0..`v..R.....J.|
-000000c0  27 0a c1 1a 72 ed 71 ab  0a fc 10 d9 5e 4d fd 10  |'...r.q.....^M..|
-000000d0  04 92 39 78 be 23                                 |..9x.#|
+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  15 03 03 00 02 02 14                              |.......|
+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/crypto/tls/ticket.go b/src/crypto/tls/ticket.go
index 7be50ce..0923027 100644
--- a/src/crypto/tls/ticket.go
+++ b/src/crypto/tls/ticket.go
@@ -22,9 +22,6 @@ type sessionState struct {
 	cipherSuite  uint16
 	masterSecret []byte
 	certificates [][]byte
-	// usedOldKey is true if the ticket from which this session came from
-	// was encrypted with an older key and thus should be refreshed.
-	usedOldKey bool
 }
 
 func (s *sessionState) equal(i interface{}) bool {
@@ -135,23 +132,20 @@ func (s *sessionState) unmarshal(data []byte) bool {
 
 func (c *Conn) encryptTicket(state *sessionState) ([]byte, error) {
 	serialized := state.marshal()
-	encrypted := make([]byte, ticketKeyNameLen+aes.BlockSize+len(serialized)+sha256.Size)
-	keyName := encrypted[:ticketKeyNameLen]
-	iv := encrypted[ticketKeyNameLen : ticketKeyNameLen+aes.BlockSize]
+	encrypted := make([]byte, aes.BlockSize+len(serialized)+sha256.Size)
+	iv := encrypted[:aes.BlockSize]
 	macBytes := encrypted[len(encrypted)-sha256.Size:]
 
 	if _, err := io.ReadFull(c.config.rand(), iv); err != nil {
 		return nil, err
 	}
-	key := c.config.ticketKeys()[0]
-	copy(keyName, key.keyName[:])
-	block, err := aes.NewCipher(key.aesKey[:])
+	block, err := aes.NewCipher(c.config.SessionTicketKey[:16])
 	if err != nil {
 		return nil, errors.New("tls: failed to create cipher while encrypting ticket: " + err.Error())
 	}
-	cipher.NewCTR(block, iv).XORKeyStream(encrypted[ticketKeyNameLen+aes.BlockSize:], serialized)
+	cipher.NewCTR(block, iv).XORKeyStream(encrypted[aes.BlockSize:], serialized)
 
-	mac := hmac.New(sha256.New, key.hmacKey[:])
+	mac := hmac.New(sha256.New, c.config.SessionTicketKey[16:32])
 	mac.Write(encrypted[:len(encrypted)-sha256.Size])
 	mac.Sum(macBytes[:0])
 
@@ -160,29 +154,14 @@ func (c *Conn) encryptTicket(state *sessionState) ([]byte, error) {
 
 func (c *Conn) decryptTicket(encrypted []byte) (*sessionState, bool) {
 	if c.config.SessionTicketsDisabled ||
-		len(encrypted) < ticketKeyNameLen+aes.BlockSize+sha256.Size {
+		len(encrypted) < aes.BlockSize+sha256.Size {
 		return nil, false
 	}
 
-	keyName := encrypted[:ticketKeyNameLen]
-	iv := encrypted[ticketKeyNameLen : ticketKeyNameLen+aes.BlockSize]
+	iv := encrypted[:aes.BlockSize]
 	macBytes := encrypted[len(encrypted)-sha256.Size:]
 
-	keys := c.config.ticketKeys()
-	keyIndex := -1
-	for i, candidateKey := range keys {
-		if bytes.Equal(keyName, candidateKey.keyName[:]) {
-			keyIndex = i
-			break
-		}
-	}
-
-	if keyIndex == -1 {
-		return nil, false
-	}
-	key := &keys[keyIndex]
-
-	mac := hmac.New(sha256.New, key.hmacKey[:])
+	mac := hmac.New(sha256.New, c.config.SessionTicketKey[16:32])
 	mac.Write(encrypted[:len(encrypted)-sha256.Size])
 	expected := mac.Sum(nil)
 
@@ -190,15 +169,15 @@ func (c *Conn) decryptTicket(encrypted []byte) (*sessionState, bool) {
 		return nil, false
 	}
 
-	block, err := aes.NewCipher(key.aesKey[:])
+	block, err := aes.NewCipher(c.config.SessionTicketKey[:16])
 	if err != nil {
 		return nil, false
 	}
-	ciphertext := encrypted[ticketKeyNameLen+aes.BlockSize : len(encrypted)-sha256.Size]
+	ciphertext := encrypted[aes.BlockSize : len(encrypted)-sha256.Size]
 	plaintext := ciphertext
 	cipher.NewCTR(block, iv).XORKeyStream(plaintext, ciphertext)
 
-	state := &sessionState{usedOldKey: keyIndex > 0}
+	state := new(sessionState)
 	ok := state.unmarshal(plaintext)
 	return state, ok
 }
diff --git a/src/crypto/tls/tls.go b/src/crypto/tls/tls.go
index 0b1c377..d50e120 100644
--- a/src/crypto/tls/tls.go
+++ b/src/crypto/tls/tls.go
@@ -167,24 +167,22 @@ func Dial(network, addr string, config *Config) (*Conn, error) {
 
 // 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) (Certificate, error) {
+func LoadX509KeyPair(certFile, keyFile string) (cert Certificate, err error) {
 	certPEMBlock, err := ioutil.ReadFile(certFile)
 	if err != nil {
-		return Certificate{}, err
+		return
 	}
 	keyPEMBlock, err := ioutil.ReadFile(keyFile)
 	if err != nil {
-		return Certificate{}, err
+		return
 	}
 	return X509KeyPair(certPEMBlock, keyPEMBlock)
 }
 
 // X509KeyPair parses a public/private key pair from a pair of
 // PEM encoded data.
-func X509KeyPair(certPEMBlock, keyPEMBlock []byte) (Certificate, error) {
-	var cert Certificate
+func X509KeyPair(certPEMBlock, keyPEMBlock []byte) (cert Certificate, err error) {
 	var certDERBlock *pem.Block
-	fail := func(err error) (Certificate, error) { return Certificate{}, err }
 	for {
 		certDERBlock, certPEMBlock = pem.Decode(certPEMBlock)
 		if certDERBlock == nil {
@@ -196,56 +194,62 @@ func X509KeyPair(certPEMBlock, keyPEMBlock []byte) (Certificate, error) {
 	}
 
 	if len(cert.Certificate) == 0 {
-		return fail(errors.New("crypto/tls: failed to parse certificate PEM data"))
+		err = errors.New("crypto/tls: failed to parse certificate PEM data")
+		return
 	}
 
 	var keyDERBlock *pem.Block
 	for {
 		keyDERBlock, keyPEMBlock = pem.Decode(keyPEMBlock)
 		if keyDERBlock == nil {
-			return fail(errors.New("crypto/tls: failed to parse key PEM data"))
+			err = errors.New("crypto/tls: failed to parse key PEM data")
+			return
 		}
 		if keyDERBlock.Type == "PRIVATE KEY" || strings.HasSuffix(keyDERBlock.Type, " PRIVATE KEY") {
 			break
 		}
 	}
 
-	var err error
 	cert.PrivateKey, err = parsePrivateKey(keyDERBlock.Bytes)
 	if err != nil {
-		return fail(err)
+		return
 	}
 
 	// We don't need to parse the public key for TLS, but we so do anyway
 	// to check that it looks sane and matches the private key.
 	x509Cert, err := x509.ParseCertificate(cert.Certificate[0])
 	if err != nil {
-		return fail(err)
+		return
 	}
 
 	switch pub := x509Cert.PublicKey.(type) {
 	case *rsa.PublicKey:
 		priv, ok := cert.PrivateKey.(*rsa.PrivateKey)
 		if !ok {
-			return fail(errors.New("crypto/tls: private key type does not match public key type"))
+			err = errors.New("crypto/tls: private key type does not match public key type")
+			return
 		}
 		if pub.N.Cmp(priv.N) != 0 {
-			return fail(errors.New("crypto/tls: private key does not match public key"))
+			err = errors.New("crypto/tls: private key does not match public key")
+			return
 		}
 	case *ecdsa.PublicKey:
 		priv, ok := cert.PrivateKey.(*ecdsa.PrivateKey)
 		if !ok {
-			return fail(errors.New("crypto/tls: private key type does not match public key type"))
+			err = errors.New("crypto/tls: private key type does not match public key type")
+			return
 
 		}
 		if pub.X.Cmp(priv.X) != 0 || pub.Y.Cmp(priv.Y) != 0 {
-			return fail(errors.New("crypto/tls: private key does not match public key"))
+			err = errors.New("crypto/tls: private key does not match public key")
+			return
 		}
 	default:
-		return fail(errors.New("crypto/tls: unknown public key algorithm"))
+		err = errors.New("crypto/tls: unknown public key algorithm")
+		return
 	}
 
-	return cert, nil
+	return
 }
 
 // Attempt to parse the given private key DER block. OpenSSL 0.9.8 generates
diff --git a/src/crypto/tls/tls_test.go b/src/crypto/tls/tls_test.go
index c45c103..e82579e 100644
--- a/src/crypto/tls/tls_test.go
+++ b/src/crypto/tls/tls_test.go
@@ -7,7 +7,6 @@ package tls
 import (
 	"bytes"
 	"fmt"
-	"internal/testenv"
 	"io"
 	"net"
 	"strings"
@@ -41,7 +40,7 @@ D2lWusoe2/nEqfDVVWGWlyJ7yOmqaVm/iNUN9B2N2g==
 `
 
 // keyPEM is the same as rsaKeyPEM, but declares itself as just
-// "PRIVATE KEY", not "RSA PRIVATE KEY".  https://golang.org/issue/4477
+// "PRIVATE KEY", not "RSA PRIVATE KEY".  http://golang.org/issue/4477
 var keyPEM = `-----BEGIN PRIVATE KEY-----
 MIIBOwIBAAJBANLJhPHhITqQbPklG3ibCVxwGMRfp/v4XqhfdQHdcVfHap6NQ5Wo
 k/4xIA+ui35/MmNartNuC+BdZ1tMuVCPFZcCAwEAAQJAEJ2N+zsR0Xn8/Q6twa4G
@@ -281,54 +280,3 @@ func TestTLSUniqueMatches(t *testing.T) {
 		t.Error("client and server channel bindings differ when session resumption is used")
 	}
 }
-
-func TestVerifyHostname(t *testing.T) {
-	testenv.MustHaveExternalNetwork(t)
-
-	c, err := Dial("tcp", "www.google.com:https", nil)
-	if err != nil {
-		t.Fatal(err)
-	}
-	if err := c.VerifyHostname("www.google.com"); err != nil {
-		t.Fatalf("verify www.google.com: %v", err)
-	}
-	if err := c.VerifyHostname("www.yahoo.com"); err == nil {
-		t.Fatalf("verify www.yahoo.com succeeded")
-	}
-
-	c, err = Dial("tcp", "www.google.com:https", &Config{InsecureSkipVerify: true})
-	if err != nil {
-		t.Fatal(err)
-	}
-	if err := c.VerifyHostname("www.google.com"); err == nil {
-		t.Fatalf("verify www.google.com succeeded with InsecureSkipVerify=true")
-	}
-	if err := c.VerifyHostname("www.yahoo.com"); err == nil {
-		t.Fatalf("verify www.google.com succeeded with InsecureSkipVerify=true")
-	}
-}
-
-func TestVerifyHostnameResumed(t *testing.T) {
-	testenv.MustHaveExternalNetwork(t)
-
-	config := &Config{
-		ClientSessionCache: NewLRUClientSessionCache(32),
-	}
-	for i := 0; i < 2; i++ {
-		c, err := Dial("tcp", "www.google.com:https", config)
-		if err != nil {
-			t.Fatalf("Dial #%d: %v", i, err)
-		}
-		cs := c.ConnectionState()
-		if i > 0 && !cs.DidResume {
-			t.Fatalf("Subsequent connection unexpectedly didn't resume")
-		}
-		if cs.VerifiedChains == nil {
-			t.Fatalf("Dial #%d: cs.VerifiedChains == nil", i)
-		}
-		if err := c.VerifyHostname("www.google.com"); err != nil {
-			t.Fatalf("verify www.google.com #%d: %v", i, err)
-		}
-		c.Close()
-	}
-}
diff --git a/src/crypto/x509/cert_pool.go b/src/crypto/x509/cert_pool.go
index 2362e84..babe94d 100644
--- a/src/crypto/x509/cert_pool.go
+++ b/src/crypto/x509/cert_pool.go
@@ -77,7 +77,7 @@ func (s *CertPool) AddCert(cert *Certificate) {
 }
 
 // AppendCertsFromPEM attempts to parse a series of PEM encoded certificates.
-// It appends any certificates found to s and reports whether any certificates
+// It appends any certificates found to s and returns true if any certificates
 // were successfully parsed.
 //
 // On many Linux systems, /etc/ssl/cert.pem will contain the system wide set
diff --git a/src/crypto/x509/pem_decrypt.go b/src/crypto/x509/pem_decrypt.go
index 49ceadb..194c81b 100644
--- a/src/crypto/x509/pem_decrypt.go
+++ b/src/crypto/x509/pem_decrypt.go
@@ -108,10 +108,7 @@ var IncorrectPasswordError = errors.New("x509: decryption password incorrect")
 // encrypt it and returns a slice of decrypted DER encoded bytes. It inspects
 // the DEK-Info header to determine the algorithm used for decryption. If no
 // DEK-Info header is present, an error is returned. If an incorrect password
-// is detected an IncorrectPasswordError is returned. Because of deficiencies
-// in the encrypted-PEM format, it's not always possible to detect an incorrect
-// password. In these cases no error will be returned but the decrypted DER
-// bytes will be random noise.
+// is detected an IncorrectPasswordError is returned.
 func DecryptPEMBlock(b *pem.Block, password []byte) ([]byte, error) {
 	dek, ok := b.Headers["DEK-Info"]
 	if !ok {
@@ -144,10 +141,6 @@ func DecryptPEMBlock(b *pem.Block, password []byte) ([]byte, error) {
 		return nil, err
 	}
 
-	if len(b.Bytes)%block.BlockSize() != 0 {
-		return nil, errors.New("x509: encrypted PEM data is not a multiple of the block size")
-	}
-
 	data := make([]byte, len(b.Bytes))
 	dec := cipher.NewCBCDecrypter(block, iv)
 	dec.CryptBlocks(data, b.Bytes)
diff --git a/src/crypto/x509/pem_decrypt_test.go b/src/crypto/x509/pem_decrypt_test.go
index 685d5ee..13e4700 100644
--- a/src/crypto/x509/pem_decrypt_test.go
+++ b/src/crypto/x509/pem_decrypt_test.go
@@ -9,7 +9,6 @@ import (
 	"crypto/rand"
 	"encoding/base64"
 	"encoding/pem"
-	"strings"
 	"testing"
 )
 
@@ -222,26 +221,3 @@ AgkA8SEfu/2i3g0CCQDGNlXbBHX7kQIIK3Ww5o0cYbECCQDCimPb0dYGsQIIeQ7A
 jryIst8=`,
 	},
 }
-
-const incompleteBlockPEM = `
------BEGIN RSA PRIVATE KEY-----
-Proc-Type: 4,ENCRYPTED
-DEK-Info: AES-128-CBC,74611ABC2571AF11B1BF9B69E62C89E7
-
-6L8yXK2MTQUWBk4ZD6OvCiYp+mXyR1594TQ1K38MxGvDw5pwcDME2Lek8RrR5fd40P2XsL2Z4KKt
-ai+OP1BZUetfK6AW4MiqB2FDyIdOAJ8XeWuZy21Wtsh8wPD6yYOFM/w7WZL8weX3Y0TSeG/T
------END RSA PRIVATE KEY-----`
-
-func TestIncompleteBlock(t *testing.T) {
-	// incompleteBlockPEM contains ciphertext that is not a multiple of the
-	// block size. This previously panicked. See #11215.
-	block, _ := pem.Decode([]byte(incompleteBlockPEM))
-	_, err := DecryptPEMBlock(block, []byte("foo"))
-	if err == nil {
-		t.Fatal("Bad PEM data decrypted successfully")
-	}
-	const expectedSubstr = "block size"
-	if e := err.Error(); !strings.Contains(e, expectedSubstr) {
-		t.Fatalf("Expected error containing %q but got: %q", expectedSubstr, e)
-	}
-}
diff --git a/src/crypto/x509/pkix/pkix.go b/src/crypto/x509/pkix/pkix.go
index 5add4e5..8768b78 100644
--- a/src/crypto/x509/pkix/pkix.go
+++ b/src/crypto/x509/pkix/pkix.go
@@ -46,17 +46,14 @@ type Extension struct {
 }
 
 // Name represents an X.509 distinguished name. This only includes the common
-// elements of a DN. When parsing, all elements are stored in Names and
-// non-standard elements can be extracted from there. When marshaling, elements
-// in ExtraNames are appended and override other values with the same OID.
+// elements of a DN.  Additional elements in the name are ignored.
 type Name struct {
 	Country, Organization, OrganizationalUnit []string
 	Locality, Province                        []string
 	StreetAddress, PostalCode                 []string
 	SerialNumber, CommonName                  string
 
-	Names      []AttributeTypeAndValue
-	ExtraNames []AttributeTypeAndValue
+	Names []AttributeTypeAndValue
 }
 
 func (n *Name) FillFromRDNSequence(rdns *RDNSequence) {
@@ -113,8 +110,8 @@ var (
 // and returns the new value. The relativeDistinguishedNameSET contains an
 // attributeTypeAndValue for each of the given values. See RFC 5280, A.1, and
 // search for AttributeTypeAndValue.
-func (n Name) appendRDNs(in RDNSequence, values []string, oid asn1.ObjectIdentifier) RDNSequence {
-	if len(values) == 0 || oidInAttributeTypeAndValue(oid, n.ExtraNames) {
+func appendRDNs(in RDNSequence, values []string, oid asn1.ObjectIdentifier) RDNSequence {
+	if len(values) == 0 {
 		return in
 	}
 
@@ -128,37 +125,23 @@ func (n Name) appendRDNs(in RDNSequence, values []string, oid asn1.ObjectIdentif
 }
 
 func (n Name) ToRDNSequence() (ret RDNSequence) {
-	ret = n.appendRDNs(ret, n.Country, oidCountry)
-	ret = n.appendRDNs(ret, n.Organization, oidOrganization)
-	ret = n.appendRDNs(ret, n.OrganizationalUnit, oidOrganizationalUnit)
-	ret = n.appendRDNs(ret, n.Locality, oidLocality)
-	ret = n.appendRDNs(ret, n.Province, oidProvince)
-	ret = n.appendRDNs(ret, n.StreetAddress, oidStreetAddress)
-	ret = n.appendRDNs(ret, n.PostalCode, oidPostalCode)
+	ret = appendRDNs(ret, n.Country, oidCountry)
+	ret = appendRDNs(ret, n.Organization, oidOrganization)
+	ret = appendRDNs(ret, n.OrganizationalUnit, oidOrganizationalUnit)
+	ret = appendRDNs(ret, n.Locality, oidLocality)
+	ret = appendRDNs(ret, n.Province, oidProvince)
+	ret = appendRDNs(ret, n.StreetAddress, oidStreetAddress)
+	ret = appendRDNs(ret, n.PostalCode, oidPostalCode)
 	if len(n.CommonName) > 0 {
-		ret = n.appendRDNs(ret, []string{n.CommonName}, oidCommonName)
+		ret = appendRDNs(ret, []string{n.CommonName}, oidCommonName)
 	}
 	if len(n.SerialNumber) > 0 {
-		ret = n.appendRDNs(ret, []string{n.SerialNumber}, oidSerialNumber)
-	}
-	for _, atv := range n.ExtraNames {
-		ret = append(ret, []AttributeTypeAndValue{atv})
+		ret = appendRDNs(ret, []string{n.SerialNumber}, oidSerialNumber)
 	}
 
 	return ret
 }
 
-// oidInAttributeTypeAndValue returns whether a type with the given OID exists
-// in atv.
-func oidInAttributeTypeAndValue(oid asn1.ObjectIdentifier, atv []AttributeTypeAndValue) bool {
-	for _, a := range atv {
-		if a.Type.Equal(oid) {
-			return true
-		}
-	}
-	return false
-}
-
 // CertificateList represents the ASN.1 structure of the same name. See RFC
 // 5280, section 5.1. Use Certificate.CheckCRLSignature to verify the
 // signature.
@@ -177,7 +160,7 @@ func (certList *CertificateList) HasExpired(now time.Time) bool {
 // 5280, section 5.1.
 type TBSCertificateList struct {
 	Raw                 asn1.RawContent
-	Version             int `asn1:"optional,default:1"`
+	Version             int `asn1:"optional,default:2"`
 	Signature           AlgorithmIdentifier
 	Issuer              RDNSequence
 	ThisUpdate          time.Time
diff --git a/src/crypto/x509/root_cgo_darwin.go b/src/crypto/x509/root_cgo_darwin.go
index bf4a5cd..bdcc2c1 100644
--- a/src/crypto/x509/root_cgo_darwin.go
+++ b/src/crypto/x509/root_cgo_darwin.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 cgo,!arm,!arm64,!ios
+// +build cgo
 
 package x509
 
diff --git a/src/crypto/x509/root_darwin.go b/src/crypto/x509/root_darwin.go
index 78de56c..2a61d36 100644
--- a/src/crypto/x509/root_darwin.go
+++ b/src/crypto/x509/root_darwin.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.
 
-//go:generate go run root_darwin_arm_gen.go -output root_darwin_armx.go
-
 package x509
 
 import "os/exec"
diff --git a/src/crypto/x509/root_darwin_test.go b/src/crypto/x509/root_darwin_test.go
index cc6d23c..87ea4e3 100644
--- a/src/crypto/x509/root_darwin_test.go
+++ b/src/crypto/x509/root_darwin_test.go
@@ -1,20 +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.
-
 package x509
 
-import (
-	"runtime"
-	"testing"
-)
+import "testing"
 
 func TestSystemRoots(t *testing.T) {
-	switch runtime.GOARCH {
-	case "arm", "arm64":
-		t.Skipf("skipping on %s/%s, no system root", runtime.GOOS, runtime.GOARCH)
-	}
-
 	sysRoots := systemRootsPool()         // actual system roots
 	execRoots, err := execSecurityRoots() // non-cgo roots
 
diff --git a/src/crypto/x509/root_unix.go b/src/crypto/x509/root_unix.go
index 8d3b2fb..f77d6c0 100644
--- a/src/crypto/x509/root_unix.go
+++ b/src/crypto/x509/root_unix.go
@@ -8,10 +8,22 @@ package x509
 
 import "io/ioutil"
 
+// Possible certificate files; stop after finding one.
+var certFiles = []string{
+	"/etc/ssl/certs/ca-certificates.crt",     // Debian/Ubuntu/Gentoo etc.
+	"/etc/pki/tls/certs/ca-bundle.crt",       // Fedora/RHEL
+	"/etc/ssl/ca-bundle.pem",                 // OpenSUSE
+	"/etc/ssl/cert.pem",                      // OpenBSD
+	"/usr/local/share/certs/ca-root-nss.crt", // FreeBSD/DragonFly
+	"/etc/pki/tls/cacert.pem",                // OpenELEC
+	"/etc/certs/ca-certificates.crt",         // Solaris 11.2+
+}
+
 // Possible directories with certificate files; stop after successfully
 // reading at least one file from a directory.
 var certDirectories = []string{
 	"/system/etc/security/cacerts", // Android
+
 }
 
 func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) {
diff --git a/src/crypto/x509/sec1.go b/src/crypto/x509/sec1.go
index c4d7ab6..7de6675 100644
--- a/src/crypto/x509/sec1.go
+++ b/src/crypto/x509/sec1.go
@@ -18,7 +18,7 @@ const ecPrivKeyVersion = 1
 // ecPrivateKey reflects an ASN.1 Elliptic Curve Private Key Structure.
 // References:
 //   RFC5915
-//   SEC1 - http://www.secg.org/sec1-v2.pdf
+//   SEC1 - http://www.secg.org/download/aid-780/sec1-v2.pdf
 // Per RFC5915 the NamedCurveOID is marked as ASN.1 OPTIONAL, however in
 // most cases it is not.
 type ecPrivateKey struct {
diff --git a/src/crypto/x509/verify.go b/src/crypto/x509/verify.go
index 21b870c..ec19814 100644
--- a/src/crypto/x509/verify.go
+++ b/src/crypto/x509/verify.go
@@ -215,10 +215,6 @@ func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err e
 		return c.systemVerify(&opts)
 	}
 
-	if len(c.UnhandledCriticalExtensions) > 0 {
-		return nil, UnhandledCriticalExtension{}
-	}
-
 	if opts.Roots == nil {
 		opts.Roots = systemRootsPool()
 		if opts.Roots == nil {
@@ -327,9 +323,6 @@ nextIntermediate:
 }
 
 func matchHostnames(pattern, host string) bool {
-	host = strings.TrimSuffix(host, ".")
-	pattern = strings.TrimSuffix(pattern, ".")
-
 	if len(pattern) == 0 || len(host) == 0 {
 		return false
 	}
@@ -342,7 +335,7 @@ func matchHostnames(pattern, host string) bool {
 	}
 
 	for i, patternPart := range patternParts {
-		if i == 0 && patternPart == "*" {
+		if patternPart == "*" {
 			continue
 		}
 		if patternPart != hostParts[i] {
diff --git a/src/crypto/x509/verify_test.go b/src/crypto/x509/verify_test.go
index 694c140..96b9d9b 100644
--- a/src/crypto/x509/verify_test.go
+++ b/src/crypto/x509/verify_test.go
@@ -14,8 +14,6 @@ import (
 	"time"
 )
 
-var supportSHA2 = true
-
 type verifyTest struct {
 	leaf                 string
 	intermediates        []string
@@ -25,7 +23,6 @@ type verifyTest struct {
 	systemSkip           bool
 	keyUsages            []ExtKeyUsage
 	testSystemRootsError bool
-	sha2                 bool
 
 	errorCallback  func(*testing.T, int, error) bool
 	expectedChains [][]string
@@ -221,11 +218,6 @@ var verifyTests = []verifyTest{
 		currentTime:   1397502195,
 		dnsName:       "api.moip.com.br",
 
-		// CryptoAPI can find alternative validation paths so we don't
-		// perform this test with system validation.
-		systemSkip: true,
-
-		sha2: true,
 		expectedChains: [][]string{
 			{
 				"api.moip.com.br",
@@ -305,9 +297,6 @@ func testVerify(t *testing.T, useSystemRoots bool) {
 		if runtime.GOOS == "windows" && test.testSystemRootsError {
 			continue
 		}
-		if useSystemRoots && !supportSHA2 && test.sha2 {
-			continue
-		}
 
 		opts := VerifyOptions{
 			Intermediates: NewCertPool(),
diff --git a/src/crypto/x509/x509.go b/src/crypto/x509/x509.go
index be6c013..7a37b98 100644
--- a/src/crypto/x509/x509.go
+++ b/src/crypto/x509/x509.go
@@ -12,7 +12,7 @@ import (
 	"crypto/ecdsa"
 	"crypto/elliptic"
 	"crypto/rsa"
-	_ "crypto/sha1"
+	"crypto/sha1"
 	_ "crypto/sha256"
 	_ "crypto/sha512"
 	"crypto/x509/pkix"
@@ -37,10 +37,8 @@ type pkixPublicKey struct {
 // typically found in PEM blocks with "BEGIN PUBLIC KEY".
 func ParsePKIXPublicKey(derBytes []byte) (pub interface{}, err error) {
 	var pki publicKeyInfo
-	if rest, err := asn1.Unmarshal(derBytes, &pki); err != nil {
-		return nil, err
-	} else if len(rest) != 0 {
-		return nil, errors.New("x509: trailing data after ASN.1 of public-key")
+	if _, err = asn1.Unmarshal(derBytes, &pki); err != nil {
+		return
 	}
 	algo := getPublicKeyAlgorithmFromOID(pki.Algorithm.Algorithm)
 	if algo == UnknownPublicKeyAlgorithm {
@@ -490,16 +488,6 @@ type Certificate struct {
 	// field is not populated when parsing certificates, see Extensions.
 	ExtraExtensions []pkix.Extension
 
-	// UnhandledCriticalExtensions contains a list of extension IDs that
-	// were not (fully) processed when parsing. Verify will fail if this
-	// slice is non-empty, unless verification is delegated to an OS
-	// library which understands all the critical extensions.
-	//
-	// Users can access these extensions using Extensions and can remove
-	// elements from this slice if they believe that they have been
-	// handled.
-	UnhandledCriticalExtensions []asn1.ObjectIdentifier
-
 	ExtKeyUsage        []ExtKeyUsage           // Sequence of extended key usages.
 	UnknownExtKeyUsage []asn1.ObjectIdentifier // Encountered extended key usages unknown to this package.
 
@@ -631,12 +619,6 @@ func (c *Certificate) CheckSignatureFrom(parent *Certificate) (err error) {
 // CheckSignature verifies that signature is a valid signature over signed from
 // c's public key.
 func (c *Certificate) CheckSignature(algo SignatureAlgorithm, signed, signature []byte) (err error) {
-	return checkSignature(algo, signed, signature, c.PublicKey)
-}
-
-// CheckSignature verifies that signature is a valid signature over signed from
-// a crypto.PublicKey.
-func checkSignature(algo SignatureAlgorithm, signed, signature []byte, publicKey crypto.PublicKey) (err error) {
 	var hashType crypto.Hash
 
 	switch algo {
@@ -660,15 +642,13 @@ func checkSignature(algo SignatureAlgorithm, signed, signature []byte, publicKey
 	h.Write(signed)
 	digest := h.Sum(nil)
 
-	switch pub := publicKey.(type) {
+	switch pub := c.PublicKey.(type) {
 	case *rsa.PublicKey:
 		return rsa.VerifyPKCS1v15(pub, hashType, digest, signature)
 	case *dsa.PublicKey:
 		dsaSig := new(dsaSignature)
-		if rest, err := asn1.Unmarshal(signature, dsaSig); err != nil {
+		if _, err := asn1.Unmarshal(signature, dsaSig); err != nil {
 			return err
-		} else if len(rest) != 0 {
-			return errors.New("x509: trailing data after DSA signature")
 		}
 		if dsaSig.R.Sign() <= 0 || dsaSig.S.Sign() <= 0 {
 			return errors.New("x509: DSA signature contained zero or negative values")
@@ -679,10 +659,8 @@ func checkSignature(algo SignatureAlgorithm, signed, signature []byte, publicKey
 		return
 	case *ecdsa.PublicKey:
 		ecdsaSig := new(ecdsaSignature)
-		if rest, err := asn1.Unmarshal(signature, ecdsaSig); err != nil {
+		if _, err := asn1.Unmarshal(signature, ecdsaSig); err != nil {
 			return err
-		} else if len(rest) != 0 {
-			return errors.New("x509: trailing data after ECDSA signature")
 		}
 		if ecdsaSig.R.Sign() <= 0 || ecdsaSig.S.Sign() <= 0 {
 			return errors.New("x509: ECDSA signature contained zero or negative values")
@@ -751,13 +729,10 @@ func parsePublicKey(algo PublicKeyAlgorithm, keyData *publicKeyInfo) (interface{
 	switch algo {
 	case RSA:
 		p := new(rsaPublicKey)
-		rest, err := asn1.Unmarshal(asn1Data, p)
+		_, err := asn1.Unmarshal(asn1Data, p)
 		if err != nil {
 			return nil, err
 		}
-		if len(rest) != 0 {
-			return nil, errors.New("x509: trailing data after RSA public key")
-		}
 
 		if p.N.Sign() <= 0 {
 			return nil, errors.New("x509: RSA modulus is not a positive number")
@@ -773,22 +748,16 @@ func parsePublicKey(algo PublicKeyAlgorithm, keyData *publicKeyInfo) (interface{
 		return pub, nil
 	case DSA:
 		var p *big.Int
-		rest, err := asn1.Unmarshal(asn1Data, &p)
+		_, err := asn1.Unmarshal(asn1Data, &p)
 		if err != nil {
 			return nil, err
 		}
-		if len(rest) != 0 {
-			return nil, errors.New("x509: trailing data after DSA public key")
-		}
 		paramsData := keyData.Algorithm.Parameters.FullBytes
 		params := new(dsaAlgorithmParameters)
-		rest, err = asn1.Unmarshal(paramsData, params)
+		_, err = asn1.Unmarshal(paramsData, params)
 		if err != nil {
 			return nil, err
 		}
-		if len(rest) != 0 {
-			return nil, errors.New("x509: trailing data after DSA parameters")
-		}
 		if p.Sign() <= 0 || params.P.Sign() <= 0 || params.Q.Sign() <= 0 || params.G.Sign() <= 0 {
 			return nil, errors.New("x509: zero or negative DSA parameter")
 		}
@@ -804,13 +773,10 @@ func parsePublicKey(algo PublicKeyAlgorithm, keyData *publicKeyInfo) (interface{
 	case ECDSA:
 		paramsData := keyData.Algorithm.Parameters.FullBytes
 		namedCurveOID := new(asn1.ObjectIdentifier)
-		rest, err := asn1.Unmarshal(paramsData, namedCurveOID)
+		_, err := asn1.Unmarshal(paramsData, namedCurveOID)
 		if err != nil {
 			return nil, err
 		}
-		if len(rest) != 0 {
-			return nil, errors.New("x509: trailing data after ECDSA parameters")
-		}
 		namedCurve := namedCurveFromOID(*namedCurveOID)
 		if namedCurve == nil {
 			return nil, errors.New("x509: unsupported elliptic curve")
@@ -848,11 +814,7 @@ func parseSANExtension(value []byte) (dnsNames, emailAddresses []string, ipAddre
 	//      iPAddress                       [7]     OCTET STRING,
 	//      registeredID                    [8]     OBJECT IDENTIFIER }
 	var seq asn1.RawValue
-	var rest []byte
-	if rest, err = asn1.Unmarshal(value, &seq); err != nil {
-		return
-	} else if len(rest) != 0 {
-		err = errors.New("x509: trailing data after X.509 extension")
+	if _, err = asn1.Unmarshal(value, &seq); err != nil {
 		return
 	}
 	if !seq.IsCompound || seq.Tag != 16 || seq.Class != 0 {
@@ -860,7 +822,7 @@ func parseSANExtension(value []byte) (dnsNames, emailAddresses []string, ipAddre
 		return
 	}
 
-	rest = seq.Bytes
+	rest := seq.Bytes
 	for len(rest) > 0 {
 		var v asn1.RawValue
 		rest, err = asn1.Unmarshal(rest, &v)
@@ -914,15 +876,11 @@ func parseCertificate(in *certificate) (*Certificate, error) {
 	out.SerialNumber = in.TBSCertificate.SerialNumber
 
 	var issuer, subject pkix.RDNSequence
-	if rest, err := asn1.Unmarshal(in.TBSCertificate.Subject.FullBytes, &subject); err != nil {
+	if _, err := asn1.Unmarshal(in.TBSCertificate.Subject.FullBytes, &subject); err != nil {
 		return nil, err
-	} else if len(rest) != 0 {
-		return nil, errors.New("x509: trailing data after X.509 subject")
 	}
-	if rest, err := asn1.Unmarshal(in.TBSCertificate.Issuer.FullBytes, &issuer); err != nil {
+	if _, err := asn1.Unmarshal(in.TBSCertificate.Issuer.FullBytes, &issuer); err != nil {
 		return nil, err
-	} else if len(rest) != 0 {
-		return nil, errors.New("x509: trailing data after X.509 subject")
 	}
 
 	out.Issuer.FillFromRDNSequence(&issuer)
@@ -933,51 +891,47 @@ func parseCertificate(in *certificate) (*Certificate, error) {
 
 	for _, e := range in.TBSCertificate.Extensions {
 		out.Extensions = append(out.Extensions, e)
-		unhandled := false
 
 		if len(e.Id) == 4 && e.Id[0] == 2 && e.Id[1] == 5 && e.Id[2] == 29 {
 			switch e.Id[3] {
 			case 15:
 				// RFC 5280, 4.2.1.3
 				var usageBits asn1.BitString
-				if rest, err := asn1.Unmarshal(e.Value, &usageBits); err != nil {
-					return nil, err
-				} else if len(rest) != 0 {
-					return nil, errors.New("x509: trailing data after X.509 KeyUsage")
-				}
+				_, err := asn1.Unmarshal(e.Value, &usageBits)
 
-				var usage int
-				for i := 0; i < 9; i++ {
-					if usageBits.At(i) != 0 {
-						usage |= 1 << uint(i)
+				if err == nil {
+					var usage int
+					for i := 0; i < 9; i++ {
+						if usageBits.At(i) != 0 {
+							usage |= 1 << uint(i)
+						}
 					}
+					out.KeyUsage = KeyUsage(usage)
+					continue
 				}
-				out.KeyUsage = KeyUsage(usage)
-
 			case 19:
 				// RFC 5280, 4.2.1.9
 				var constraints basicConstraints
-				if rest, err := asn1.Unmarshal(e.Value, &constraints); err != nil {
-					return nil, err
-				} else if len(rest) != 0 {
-					return nil, errors.New("x509: trailing data after X.509 BasicConstraints")
-				}
-
-				out.BasicConstraintsValid = true
-				out.IsCA = constraints.IsCA
-				out.MaxPathLen = constraints.MaxPathLen
-				out.MaxPathLenZero = out.MaxPathLen == 0
+				_, err := asn1.Unmarshal(e.Value, &constraints)
 
+				if err == nil {
+					out.BasicConstraintsValid = true
+					out.IsCA = constraints.IsCA
+					out.MaxPathLen = constraints.MaxPathLen
+					out.MaxPathLenZero = out.MaxPathLen == 0
+					continue
+				}
 			case 17:
 				out.DNSNames, out.EmailAddresses, out.IPAddresses, err = parseSANExtension(e.Value)
 				if err != nil {
 					return nil, err
 				}
 
-				if len(out.DNSNames) == 0 && len(out.EmailAddresses) == 0 && len(out.IPAddresses) == 0 {
-					// If we didn't parse anything then we do the critical check, below.
-					unhandled = true
+				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
+				// fall through to the critical check below.
 
 			case 30:
 				// RFC 5280, 4.2.1.10
@@ -996,10 +950,9 @@ func parseCertificate(in *certificate) (*Certificate, error) {
 				// BaseDistance ::= INTEGER (0..MAX)
 
 				var constraints nameConstraints
-				if rest, err := asn1.Unmarshal(e.Value, &constraints); err != nil {
+				_, err := asn1.Unmarshal(e.Value, &constraints)
+				if err != nil {
 					return nil, err
-				} else if len(rest) != 0 {
-					return nil, errors.New("x509: trailing data after X.509 NameConstraints")
 				}
 
 				if len(constraints.Excluded) > 0 && e.Critical {
@@ -1015,6 +968,7 @@ func parseCertificate(in *certificate) (*Certificate, error) {
 					}
 					out.PermittedDNSDomains = append(out.PermittedDNSDomains, subtree.Name)
 				}
+				continue
 
 			case 31:
 				// RFC 5280, 4.2.1.14
@@ -1031,35 +985,33 @@ func parseCertificate(in *certificate) (*Certificate, error) {
 				//     nameRelativeToCRLIssuer [1]     RelativeDistinguishedName }
 
 				var cdp []distributionPoint
-				if rest, err := asn1.Unmarshal(e.Value, &cdp); err != nil {
+				_, err := asn1.Unmarshal(e.Value, &cdp)
+				if err != nil {
 					return nil, err
-				} else if len(rest) != 0 {
-					return nil, errors.New("x509: trailing data after X.509 CRL distribution point")
 				}
 
 				for _, dp := range cdp {
 					var n asn1.RawValue
-					if _, err := asn1.Unmarshal(dp.DistributionPoint.FullName.Bytes, &n); err != nil {
+					_, err = asn1.Unmarshal(dp.DistributionPoint.FullName.Bytes, &n)
+					if err != nil {
 						return nil, err
 					}
-					// Trailing data after the fullName is
-					// allowed because other elements of
-					// the SEQUENCE can appear.
 
 					if n.Tag == 6 {
 						out.CRLDistributionPoints = append(out.CRLDistributionPoints, string(n.Bytes))
 					}
 				}
+				continue
 
 			case 35:
 				// RFC 5280, 4.2.1.1
 				var a authKeyId
-				if rest, err := asn1.Unmarshal(e.Value, &a); err != nil {
+				_, err = asn1.Unmarshal(e.Value, &a)
+				if err != nil {
 					return nil, err
-				} else if len(rest) != 0 {
-					return nil, errors.New("x509: trailing data after X.509 authority key-id")
 				}
 				out.AuthorityKeyId = a.Id
+				continue
 
 			case 37:
 				// RFC 5280, 4.2.1.12.  Extended Key Usage
@@ -1071,10 +1023,9 @@ func parseCertificate(in *certificate) (*Certificate, error) {
 				// KeyPurposeId ::= OBJECT IDENTIFIER
 
 				var keyUsage []asn1.ObjectIdentifier
-				if rest, err := asn1.Unmarshal(e.Value, &keyUsage); err != nil {
+				_, err = asn1.Unmarshal(e.Value, &keyUsage)
+				if err != nil {
 					return nil, err
-				} else if len(rest) != 0 {
-					return nil, errors.New("x509: trailing data after X.509 ExtendedKeyUsage")
 				}
 
 				for _, u := range keyUsage {
@@ -1085,40 +1036,34 @@ func parseCertificate(in *certificate) (*Certificate, error) {
 					}
 				}
 
+				continue
+
 			case 14:
 				// RFC 5280, 4.2.1.2
 				var keyid []byte
-				if rest, err := asn1.Unmarshal(e.Value, &keyid); err != nil {
+				_, err = asn1.Unmarshal(e.Value, &keyid)
+				if err != nil {
 					return nil, err
-				} else if len(rest) != 0 {
-					return nil, errors.New("x509: trailing data after X.509 authority key-id")
 				}
 				out.SubjectKeyId = keyid
+				continue
 
 			case 32:
 				// RFC 5280 4.2.1.4: Certificate Policies
 				var policies []policyInformation
-				if rest, err := asn1.Unmarshal(e.Value, &policies); err != nil {
+				if _, err = asn1.Unmarshal(e.Value, &policies); err != nil {
 					return nil, err
-				} else if len(rest) != 0 {
-					return nil, errors.New("x509: trailing data after X.509 certificate policies")
 				}
 				out.PolicyIdentifiers = make([]asn1.ObjectIdentifier, len(policies))
 				for i, policy := range policies {
 					out.PolicyIdentifiers[i] = policy.Policy
 				}
-
-			default:
-				// Unknown extensions are recorded if critical.
-				unhandled = true
 			}
 		} else if e.Id.Equal(oidExtensionAuthorityInfoAccess) {
 			// RFC 5280 4.2.2.1: Authority Information Access
 			var aia []authorityInfoAccess
-			if rest, err := asn1.Unmarshal(e.Value, &aia); err != nil {
+			if _, err = asn1.Unmarshal(e.Value, &aia); err != nil {
 				return nil, err
-			} else if len(rest) != 0 {
-				return nil, errors.New("x509: trailing data after X.509 authority information")
 			}
 
 			for _, v := range aia {
@@ -1132,13 +1077,10 @@ func parseCertificate(in *certificate) (*Certificate, error) {
 					out.IssuingCertificateURL = append(out.IssuingCertificateURL, string(v.Location.Bytes))
 				}
 			}
-		} else {
-			// Unknown extensions are recorded if critical.
-			unhandled = true
 		}
 
-		if e.Critical && unhandled {
-			out.UnhandledCriticalExtensions = append(out.UnhandledCriticalExtensions, e.Id)
+		if e.Critical {
+			return out, UnhandledCriticalExtension{}
 		}
 	}
 
@@ -1193,26 +1135,6 @@ func reverseBitsInAByte(in byte) byte {
 	return b3
 }
 
-// asn1BitLength returns the bit-length of bitString by considering the
-// most-significant bit in a byte to be the "first" bit. This convention
-// matches ASN.1, but differs from almost everything else.
-func asn1BitLength(bitString []byte) int {
-	bitLen := len(bitString) * 8
-
-	for i := range bitString {
-		b := bitString[len(bitString)-i-1]
-
-		for bit := uint(0); bit < 8; bit++ {
-			if (b>>bit)&1 == 1 {
-				return bitLen
-			}
-			bitLen--
-		}
-	}
-
-	return 0
-}
-
 var (
 	oidExtensionSubjectKeyId          = []int{2, 5, 29, 14}
 	oidExtensionKeyUsage              = []int{2, 5, 29, 15}
@@ -1281,8 +1203,7 @@ func buildExtensions(template *Certificate) (ret []pkix.Extension, err error) {
 			l = 2
 		}
 
-		bitString := a[:l]
-		ret[n].Value, err = asn1.Marshal(asn1.BitString{Bytes: bitString, BitLength: asn1BitLength(bitString)})
+		ret[n].Value, err = asn1.Marshal(asn1.BitString{Bytes: a[0:l], BitLength: l * 8})
 		if err != nil {
 			return
 		}
@@ -1447,25 +1368,22 @@ func subjectBytes(cert *Certificate) ([]byte, error) {
 	return asn1.Marshal(cert.Subject.ToRDNSequence())
 }
 
-// signingParamsForPublicKey returns the parameters to use for signing with
+// signingParamsForPrivateKey returns the parameters to use for signing with
 // priv. If requestedSigAlgo is not zero then it overrides the default
 // signature algorithm.
-func signingParamsForPublicKey(pub interface{}, requestedSigAlgo SignatureAlgorithm) (hashFunc crypto.Hash, sigAlgo pkix.AlgorithmIdentifier, err error) {
+func signingParamsForPrivateKey(priv interface{}, requestedSigAlgo SignatureAlgorithm) (hashFunc crypto.Hash, sigAlgo pkix.AlgorithmIdentifier, err error) {
 	var pubType PublicKeyAlgorithm
 
-	switch pub := pub.(type) {
-	case *rsa.PublicKey:
+	switch priv := priv.(type) {
+	case *rsa.PrivateKey:
 		pubType = RSA
-		hashFunc = crypto.SHA256
 		sigAlgo.Algorithm = oidSignatureSHA256WithRSA
-		sigAlgo.Parameters = asn1.RawValue{
-			Tag: 5,
-		}
+		hashFunc = crypto.SHA256
 
-	case *ecdsa.PublicKey:
+	case *ecdsa.PrivateKey:
 		pubType = ECDSA
 
-		switch pub.Curve {
+		switch priv.Curve {
 		case elliptic.P224(), elliptic.P256():
 			hashFunc = crypto.SHA256
 			sigAlgo.Algorithm = oidSignatureECDSAWithSHA256
@@ -1480,7 +1398,7 @@ func signingParamsForPublicKey(pub interface{}, requestedSigAlgo SignatureAlgori
 		}
 
 	default:
-		err = errors.New("x509: only RSA and ECDSA keys supported")
+		err = errors.New("x509: only RSA and ECDSA private keys supported")
 	}
 
 	if err != nil {
@@ -1527,15 +1445,10 @@ func signingParamsForPublicKey(pub interface{}, requestedSigAlgo SignatureAlgori
 //
 // The returned slice is the certificate in DER encoding.
 //
-// All keys types that are implemented via crypto.Signer are supported (This
-// includes *rsa.PublicKey and *ecdsa.PublicKey.)
-func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv interface{}) (cert []byte, err error) {
-	key, ok := priv.(crypto.Signer)
-	if !ok {
-		return nil, errors.New("x509: certificate private key does not implement crypto.Signer")
-	}
-
-	hashFunc, signatureAlgorithm, err := signingParamsForPublicKey(key.Public(), template.SignatureAlgorithm)
+// The only supported key types are RSA and ECDSA (*rsa.PublicKey or
+// *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) {
+	hashFunc, signatureAlgorithm, err := signingParamsForPrivateKey(priv, template.SignatureAlgorithm)
 	if err != nil {
 		return nil, err
 	}
@@ -1545,6 +1458,10 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv
 		return nil, err
 	}
 
+	if err != nil {
+		return
+	}
+
 	if len(parent.SubjectKeyId) > 0 {
 		template.AuthorityKeyId = parent.SubjectKeyId
 	}
@@ -1588,17 +1505,30 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv
 	digest := h.Sum(nil)
 
 	var signature []byte
-	signature, err = key.Sign(rand, digest, hashFunc)
+
+	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(certificate{
+	cert, err = asn1.Marshal(certificate{
 		nil,
 		c,
 		signatureAlgorithm,
 		asn1.BitString{Bytes: signature, BitLength: len(signature) * 8},
 	})
+	return
 }
 
 // pemCRLPrefix is the magic string that indicates that we have a PEM encoded
@@ -1625,66 +1555,53 @@ func ParseCRL(crlBytes []byte) (certList *pkix.CertificateList, err error) {
 // ParseDERCRL parses a DER encoded CRL from the given bytes.
 func ParseDERCRL(derBytes []byte) (certList *pkix.CertificateList, err error) {
 	certList = new(pkix.CertificateList)
-	if rest, err := asn1.Unmarshal(derBytes, certList); err != nil {
-		return nil, err
-	} else if len(rest) != 0 {
-		return nil, errors.New("x509: trailing data after CRL")
+	_, err = asn1.Unmarshal(derBytes, certList)
+	if err != nil {
+		certList = nil
 	}
-	return certList, nil
+	return
 }
 
 // CreateCRL returns a DER encoded CRL, signed by this Certificate, that
 // contains the given list of revoked certificates.
+//
+// The only supported key type is RSA (*rsa.PrivateKey for priv).
 func (c *Certificate) CreateCRL(rand io.Reader, priv interface{}, revokedCerts []pkix.RevokedCertificate, now, expiry time.Time) (crlBytes []byte, err error) {
-	key, ok := priv.(crypto.Signer)
+	rsaPriv, ok := priv.(*rsa.PrivateKey)
 	if !ok {
-		return nil, errors.New("x509: certificate private key does not implement crypto.Signer")
+		return nil, errors.New("x509: non-RSA private keys not supported")
 	}
-
-	hashFunc, signatureAlgorithm, err := signingParamsForPublicKey(key.Public(), 0)
-	if err != nil {
-		return nil, err
-	}
-
 	tbsCertList := pkix.TBSCertificateList{
-		Version:             1,
-		Signature:           signatureAlgorithm,
+		Version: 2,
+		Signature: pkix.AlgorithmIdentifier{
+			Algorithm: oidSignatureSHA1WithRSA,
+		},
 		Issuer:              c.Subject.ToRDNSequence(),
 		ThisUpdate:          now.UTC(),
 		NextUpdate:          expiry.UTC(),
 		RevokedCertificates: revokedCerts,
 	}
 
-	// Authority Key Id
-	if len(c.SubjectKeyId) > 0 {
-		var aki pkix.Extension
-		aki.Id = oidExtensionAuthorityKeyId
-		aki.Value, err = asn1.Marshal(authKeyId{Id: c.SubjectKeyId})
-		if err != nil {
-			return
-		}
-		tbsCertList.Extensions = append(tbsCertList.Extensions, aki)
-	}
-
 	tbsCertListContents, err := asn1.Marshal(tbsCertList)
 	if err != nil {
 		return
 	}
 
-	h := hashFunc.New()
+	h := sha1.New()
 	h.Write(tbsCertListContents)
 	digest := h.Sum(nil)
 
-	var signature []byte
-	signature, err = key.Sign(rand, digest, hashFunc)
+	signature, err := rsa.SignPKCS1v15(rand, rsaPriv, crypto.SHA1, digest)
 	if err != nil {
 		return
 	}
 
 	return asn1.Marshal(pkix.CertificateList{
-		TBSCertList:        tbsCertList,
-		SignatureAlgorithm: signatureAlgorithm,
-		SignatureValue:     asn1.BitString{Bytes: signature, BitLength: len(signature) * 8},
+		TBSCertList: tbsCertList,
+		SignatureAlgorithm: pkix.AlgorithmIdentifier{
+			Algorithm: oidSignatureSHA1WithRSA,
+		},
+		SignatureValue: asn1.BitString{Bytes: signature, BitLength: len(signature) * 8},
 	})
 }
 
@@ -1733,11 +1650,11 @@ type CertificateRequest struct {
 // signature requests (see RFC 2986):
 
 type tbsCertificateRequest struct {
-	Raw           asn1.RawContent
-	Version       int
-	Subject       asn1.RawValue
-	PublicKey     publicKeyInfo
-	RawAttributes []asn1.RawValue `asn1:"tag:0"`
+	Raw        asn1.RawContent
+	Version    int
+	Subject    asn1.RawValue
+	PublicKey  publicKeyInfo
+	Attributes []pkix.AttributeTypeAndValueSET `asn1:"tag:0"`
 }
 
 type certificateRequest struct {
@@ -1751,36 +1668,6 @@ type certificateRequest struct {
 // extensions in a CSR.
 var oidExtensionRequest = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 14}
 
-// newRawAttributes converts AttributeTypeAndValueSETs from a template
-// CertificateRequest's Attributes into tbsCertificateRequest RawAttributes.
-func newRawAttributes(attributes []pkix.AttributeTypeAndValueSET) ([]asn1.RawValue, error) {
-	var rawAttributes []asn1.RawValue
-	b, err := asn1.Marshal(attributes)
-	rest, err := asn1.Unmarshal(b, &rawAttributes)
-	if err != nil {
-		return nil, err
-	}
-	if len(rest) != 0 {
-		return nil, errors.New("x509: failed to unmarshall raw CSR Attributes")
-	}
-	return rawAttributes, nil
-}
-
-// parseRawAttributes Unmarshals RawAttributes intos AttributeTypeAndValueSETs.
-func parseRawAttributes(rawAttributes []asn1.RawValue) []pkix.AttributeTypeAndValueSET {
-	var attributes []pkix.AttributeTypeAndValueSET
-	for _, rawAttr := range rawAttributes {
-		var attr pkix.AttributeTypeAndValueSET
-		rest, err := asn1.Unmarshal(rawAttr.FullBytes, &attr)
-		// Ignore attributes that don't parse into pkix.AttributeTypeAndValueSET
-		// (i.e.: challengePassword or unstructuredName).
-		if err == nil && len(rest) == 0 {
-			attributes = append(attributes, attr)
-		}
-	}
-	return attributes
-}
-
 // CreateCertificateRequest creates a new certificate based on a template. The
 // following members of template are used: Subject, Attributes,
 // SignatureAlgorithm, Extensions, DNSNames, EmailAddresses, and IPAddresses.
@@ -1788,24 +1675,26 @@ func parseRawAttributes(rawAttributes []asn1.RawValue) []pkix.AttributeTypeAndVa
 //
 // The returned slice is the certificate request in DER encoding.
 //
-// All keys types that are implemented via crypto.Signer are supported (This
-// includes *rsa.PublicKey and *ecdsa.PublicKey.)
+// 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) {
-	key, ok := priv.(crypto.Signer)
-	if !ok {
-		return nil, errors.New("x509: certificate private key does not implement crypto.Signer")
-	}
-
-	var hashFunc crypto.Hash
-	var sigAlgo pkix.AlgorithmIdentifier
-	hashFunc, sigAlgo, err = signingParamsForPublicKey(key.Public(), template.SignatureAlgorithm)
+	hashFunc, sigAlgo, err := signingParamsForPrivateKey(priv, template.SignatureAlgorithm)
 	if err != nil {
 		return nil, err
 	}
 
 	var publicKeyBytes []byte
 	var publicKeyAlgorithm pkix.AlgorithmIdentifier
-	publicKeyBytes, publicKeyAlgorithm, err = marshalPublicKey(key.Public())
+
+	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
 	}
@@ -1893,11 +1782,6 @@ func CreateCertificateRequest(rand io.Reader, template *CertificateRequest, priv
 		}
 	}
 
-	rawAttributes, err := newRawAttributes(attributes)
-	if err != nil {
-		return
-	}
-
 	tbsCSR := tbsCertificateRequest{
 		Version: 0, // PKCS #10, RFC 2986
 		Subject: asn1.RawValue{FullBytes: asn1Subject},
@@ -1908,7 +1792,7 @@ func CreateCertificateRequest(rand io.Reader, template *CertificateRequest, priv
 				BitLength: len(publicKeyBytes) * 8,
 			},
 		},
-		RawAttributes: rawAttributes,
+		Attributes: attributes,
 	}
 
 	tbsCSRContents, err := asn1.Marshal(tbsCSR)
@@ -1922,7 +1806,18 @@ func CreateCertificateRequest(rand io.Reader, template *CertificateRequest, priv
 	digest := h.Sum(nil)
 
 	var signature []byte
-	signature, err = key.Sign(rand, digest, hashFunc)
+	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
 	}
@@ -1965,7 +1860,7 @@ func parseCertificateRequest(in *certificateRequest) (*CertificateRequest, error
 		PublicKeyAlgorithm: getPublicKeyAlgorithmFromOID(in.TBSCSR.PublicKey.Algorithm.Algorithm),
 
 		Version:    in.TBSCSR.Version,
-		Attributes: parseRawAttributes(in.TBSCSR.RawAttributes),
+		Attributes: in.TBSCSR.Attributes,
 	}
 
 	var err error
@@ -1975,17 +1870,15 @@ func parseCertificateRequest(in *certificateRequest) (*CertificateRequest, error
 	}
 
 	var subject pkix.RDNSequence
-	if rest, err := asn1.Unmarshal(in.TBSCSR.Subject.FullBytes, &subject); err != nil {
+	if _, err := asn1.Unmarshal(in.TBSCSR.Subject.FullBytes, &subject); err != nil {
 		return nil, err
-	} else if len(rest) != 0 {
-		return nil, errors.New("x509: trailing data after X.509 Subject")
 	}
 
 	out.Subject.FillFromRDNSequence(&subject)
 
 	var extensions []pkix.AttributeTypeAndValue
 
-	for _, atvSet := range out.Attributes {
+	for _, atvSet := range in.TBSCSR.Attributes {
 		if !atvSet.Type.Equal(oidExtensionRequest) {
 			continue
 		}
@@ -2021,8 +1914,3 @@ func parseCertificateRequest(in *certificateRequest) (*CertificateRequest, error
 
 	return out, nil
 }
-
-// CheckSignature verifies that the signature on c is a valid signature
-func (c *CertificateRequest) CheckSignature() (err error) {
-	return checkSignature(c.SignatureAlgorithm, c.RawTBSCertificateRequest, c.Signature, c.PublicKey)
-}
diff --git a/src/crypto/x509/x509_test.go b/src/crypto/x509/x509_test.go
index f4f9fa2..4f5173f 100644
--- a/src/crypto/x509/x509_test.go
+++ b/src/crypto/x509/x509_test.go
@@ -18,11 +18,11 @@ import (
 	"encoding/base64"
 	"encoding/hex"
 	"encoding/pem"
-	"internal/testenv"
 	"math/big"
 	"net"
 	"os/exec"
 	"reflect"
+	"runtime"
 	"testing"
 	"time"
 )
@@ -41,13 +41,6 @@ func TestParsePKCS1PrivateKey(t *testing.T) {
 		priv.Primes[1].Cmp(rsaPrivateKey.Primes[1]) != 0 {
 		t.Errorf("got:%+v want:%+v", priv, rsaPrivateKey)
 	}
-
-	// This private key includes an invalid prime that
-	// rsa.PrivateKey.Validate should reject.
-	data := []byte("0\x16\x02\x00\x02\x02\u007f\x00\x02\x0200\x02\x0200\x02\x02\x00\x01\x02\x02\u007f\x00")
-	if _, err := ParsePKCS1PrivateKey(data); err == nil {
-		t.Errorf("parsing invalid private key did not result in an error")
-	}
 }
 
 func TestParsePKIXPublicKey(t *testing.T) {
@@ -169,31 +162,17 @@ var matchHostnamesTests = []matchHostnamesTest{
 	{"a.b.c", "", false},
 	{"example.com", "example.com", true},
 	{"example.com", "www.example.com", false},
-	{"*.example.com", "example.com", false},
 	{"*.example.com", "www.example.com", true},
-	{"*.example.com", "www.example.com.", true},
 	{"*.example.com", "xyz.www.example.com", false},
-	{"*.*.example.com", "xyz.www.example.com", false},
-	{"*.www.*.com", "xyz.www.example.com", false},
-	{"*bar.example.com", "foobar.example.com", false},
-	{"f*.example.com", "foobar.example.com", false},
-	{"", ".", false},
-	{".", "", false},
-	{".", ".", false},
-	{"example.com", "example.com.", true},
-	{"example.com.", "example.com", true},
-	{"example.com.", "example.com.", true},
-	{"*.com.", "example.com.", true},
-	{"*.com.", "example.com", true},
-	{"*.com", "example.com", true},
-	{"*.com", "example.com.", true},
+	{"*.*.example.com", "xyz.www.example.com", true},
+	{"*.www.*.com", "xyz.www.example.com", true},
 }
 
 func TestMatchHostnames(t *testing.T) {
 	for i, test := range matchHostnamesTests {
 		r := matchHostnames(test.pattern, test.host)
 		if r != test.ok {
-			t.Errorf("#%d mismatch got: %t want: %t when matching '%s' against '%s'", i, r, test.ok, test.host, test.pattern)
+			t.Errorf("#%d mismatch got: %t want: %t", i, r, test.ok)
 		}
 	}
 }
@@ -347,18 +326,6 @@ func TestCreateSelfSignedCertificate(t *testing.T) {
 			Subject: pkix.Name{
 				CommonName:   commonName,
 				Organization: []string{"Σ Acme Co"},
-				Country:      []string{"US"},
-				ExtraNames: []pkix.AttributeTypeAndValue{
-					{
-						Type:  []int{2, 5, 4, 42},
-						Value: "Gopher",
-					},
-					// This should override the Country, above.
-					{
-						Type:  []int{2, 5, 4, 6},
-						Value: "NL",
-					},
-				},
 			},
 			NotBefore: time.Unix(1000, 0),
 			NotAfter:  time.Unix(100000, 0),
@@ -424,21 +391,6 @@ func TestCreateSelfSignedCertificate(t *testing.T) {
 			t.Errorf("%s: subject wasn't correctly copied from the template. Got %s, want %s", test.name, cert.Subject.CommonName, commonName)
 		}
 
-		if len(cert.Subject.Country) != 1 || cert.Subject.Country[0] != "NL" {
-			t.Errorf("%s: ExtraNames didn't override Country", test.name)
-		}
-
-		found := false
-		for _, atv := range cert.Subject.Names {
-			if atv.Type.Equal([]int{2, 5, 4, 42}) {
-				found = true
-				break
-			}
-		}
-		if !found {
-			t.Errorf("%s: Names didn't contain oid 2.5.4.42 from ExtraNames", test.name)
-		}
-
 		if cert.Issuer.CommonName != commonName {
 			t.Errorf("%s: issuer wasn't correctly copied from the template. Got %s, want %s", test.name, cert.Issuer.CommonName, commonName)
 		}
@@ -496,74 +448,6 @@ func TestCreateSelfSignedCertificate(t *testing.T) {
 	}
 }
 
-func TestUnknownCriticalExtension(t *testing.T) {
-	priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
-	if err != nil {
-		t.Fatalf("Failed to generate ECDSA key: %s", err)
-	}
-
-	oids := []asn1.ObjectIdentifier{
-		// This OID is in the PKIX arc, but unknown.
-		asn1.ObjectIdentifier{2, 5, 29, 999999},
-		// This is a nonsense, unassigned OID.
-		asn1.ObjectIdentifier{1, 2, 3, 4},
-	}
-
-	for _, oid := range oids {
-		template := Certificate{
-			SerialNumber: big.NewInt(1),
-			Subject: pkix.Name{
-				CommonName: "foo",
-			},
-			NotBefore: time.Unix(1000, 0),
-			NotAfter:  time.Now().AddDate(1, 0, 0),
-
-			BasicConstraintsValid: true,
-			IsCA: true,
-
-			KeyUsage:    KeyUsageCertSign,
-			ExtKeyUsage: []ExtKeyUsage{ExtKeyUsageServerAuth},
-
-			ExtraExtensions: []pkix.Extension{
-				{
-					Id:       oid,
-					Critical: true,
-					Value:    nil,
-				},
-			},
-		}
-
-		derBytes, err := CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)
-		if err != nil {
-			t.Fatalf("failed to create certificate: %s", err)
-		}
-
-		cert, err := ParseCertificate(derBytes)
-		if err != nil {
-			t.Fatalf("Certificate with unknown critical extension was not parsed: %s", err)
-		}
-
-		roots := NewCertPool()
-		roots.AddCert(cert)
-
-		// Setting Roots ensures that Verify won't delegate to the OS
-		// library and thus the correct error should always be
-		// returned.
-		_, err = cert.Verify(VerifyOptions{Roots: roots})
-		if err == nil {
-			t.Fatal("Certificate with unknown critical extension was verified without error")
-		}
-		if _, ok := err.(UnhandledCriticalExtension); !ok {
-			t.Fatalf("Error was %#v, but wanted one of type UnhandledCriticalExtension", err)
-		}
-
-		cert.UnhandledCriticalExtensions = nil
-		if _, err = cert.Verify(VerifyOptions{Roots: roots}); err != nil {
-			t.Errorf("Certificate failed to verify after unhandled critical extensions were cleared: %s", err)
-		}
-	}
-}
-
 // Self-signed certificate using ECDSA with SHA1 & secp256r1
 var ecdsaSHA1CertPem = `
 -----BEGIN CERTIFICATE-----
@@ -855,7 +739,10 @@ func TestParsePEMCRL(t *testing.T) {
 }
 
 func TestImports(t *testing.T) {
-	testenv.MustHaveGoRun(t)
+	switch runtime.GOOS {
+	case "android", "nacl":
+		t.Skipf("skipping on %s", runtime.GOOS)
+	}
 
 	if err := exec.Command("go", "run", "x509_test_import.go").Run(); err != nil {
 		t.Errorf("failed to run x509_test_import.go: %s", err)
@@ -925,12 +812,6 @@ func TestCreateCertificateRequest(t *testing.T) {
 			continue
 		}
 
-		err = out.CheckSignature()
-		if err != nil {
-			t.Errorf("%s: failed to check certificate request signature: %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) {
@@ -1042,36 +923,34 @@ func TestCertificateRequestOverrides(t *testing.T) {
 }
 
 func TestParseCertificateRequest(t *testing.T) {
-	for _, csrBase64 := range csrBase64Array {
-		csrBytes := fromBase64(csrBase64)
-		csr, err := ParseCertificateRequest(csrBytes)
-		if err != nil {
-			t.Fatalf("failed to parse CSR: %s", err)
-		}
+	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.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.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)
-		}
+	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")
+	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")
+	}
 }
 
 func TestMaxPathLen(t *testing.T) {
@@ -1137,42 +1016,12 @@ func TestMaxPathLen(t *testing.T) {
 	}
 }
 
-func TestASN1BitLength(t *testing.T) {
-	tests := []struct {
-		bytes  []byte
-		bitLen int
-	}{
-		{nil, 0},
-		{[]byte{0x00}, 0},
-		{[]byte{0x00, 0x00}, 0},
-		{[]byte{0xf0}, 4},
-		{[]byte{0x88}, 5},
-		{[]byte{0xff}, 8},
-		{[]byte{0xff, 0x80}, 9},
-		{[]byte{0xff, 0x81}, 16},
-	}
-
-	for i, test := range tests {
-		if got := asn1BitLength(test.bytes); got != test.bitLen {
-			t.Errorf("#%d: calculated bit-length of %d for %x, wanted %d", i, got, test.bytes, test.bitLen)
-		}
-	}
-}
-
-// These CSR was generated with OpenSSL:
-//  openssl req -out CSR.csr -new -sha256 -nodes -keyout privateKey.key -config openssl.cnf
+// This CSR was generated with OpenSSL:
+//  openssl req -out CSR.csr -new -newkey rsa:2048 -nodes -keyout privateKey.key -config openssl.cnf
 //
-// With openssl.cnf containing the following sections:
+// 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
-//   [ req_attributes ]
-//   challengePassword = ignored challenge
-//   unstructuredName  = ignored unstructured name
-var csrBase64Array = [...]string{
-	// Just [ v3_req ]
-	"MIIDHDCCAgQCAQAwfjELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEUMBIGA1UEAwwLQ29tbW9uIE5hbWUxITAfBgkqhkiG9w0BCQEWEnRlc3RAZW1haWwuYWRkcmVzczCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK1GY4YFx2ujlZEOJxQVYmsjUnLsd5nFVnNpLE4cV+77sgv9NPNlB8uhn3MXt5leD34rm/2BisCHOifPucYlSrszo2beuKhvwn4+2FxDmWtBEMu/QA16L5IvoOfYZm/gJTsPwKDqvaR0tTU67a9OtxwNTBMI56YKtmwd/o8d3hYv9cg+9ZGAZ/gKONcg/OWYx/XRh6bd0g8DMbCikpWgXKDsvvK1Nk+VtkDO1JxuBaj4Lz/p/MifTfnHoqHxWOWl4EaTs4 [...]
-	// Both [ v3_req ] and [ req_attributes ]
-	"MIIDaTCCAlECAQAwfjELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEUMBIGA1UEAwwLQ29tbW9uIE5hbWUxITAfBgkqhkiG9w0BCQEWEnRlc3RAZW1haWwuYWRkcmVzczCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK1GY4YFx2ujlZEOJxQVYmsjUnLsd5nFVnNpLE4cV+77sgv9NPNlB8uhn3MXt5leD34rm/2BisCHOifPucYlSrszo2beuKhvwn4+2FxDmWtBEMu/QA16L5IvoOfYZm/gJTsPwKDqvaR0tTU67a9OtxwNTBMI56YKtmwd/o8d3hYv9cg+9ZGAZ/gKONcg/OWYx/XRh6bd0g8DMbCikpWgXKDsvvK1Nk+VtkDO1JxuBaj4Lz/p/MifTfnHoqHxWOWl4EaTs4 [...]
-}
+const csrBase64 = "MIIC4zCCAcsCAQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOY+MVedRg2JEnyeLcSzcsMv2VcsTfkB5+Etd6hihAh6MrGezNyASMMKuQN6YhCX1icQDiQtGsDLTtheNnSXK06tAhHjAP/hGlszRJp+5+rP2M58fDBAkUBEhskbCUWwpY14jFtVuGNJ8vF8h8IeczdolvQhX9lVai9G0EUXJMliMKdjA899H0mRs9PzHyidyrXFNiZlQXfD8Kg7gETn2Ny965iyI6ujAIYSCvam6TnxRHYH2MBKyVGvsYGbPYUQJCsgdgyajEg6ekihvQY3SzO1HSAlZAd7d1QYO4VeWJ2mY6Wu3Jpmh+AmG19S9CcHq [...]
diff --git a/src/database/sql/fakedb_test.go b/src/database/sql/fakedb_test.go
index 8cbbb29..a993fd4 100644
--- a/src/database/sql/fakedb_test.go
+++ b/src/database/sql/fakedb_test.go
@@ -89,10 +89,7 @@ type fakeConn struct {
 	stmtsMade   int
 	stmtsClosed int
 	numPrepare  int
-
-	// bad connection tests; see isBad()
-	bad       bool
-	stickyBad bool
+	bad         bool
 }
 
 func (c *fakeConn) incrStat(v *int) {
@@ -246,15 +243,13 @@ func (db *fakeDB) columnType(table, column string) (typ string, ok bool) {
 }
 
 func (c *fakeConn) isBad() bool {
-	if c.stickyBad {
-		return true
-	} else if c.bad {
-		// alternate between bad conn and not bad conn
-		c.db.badConn = !c.db.badConn
-		return c.db.badConn
-	} else {
+	// if not simulating bad conn, do nothing
+	if !c.bad {
 		return false
 	}
+	// alternate between bad conn and not bad conn
+	c.db.badConn = !c.db.badConn
+	return c.db.badConn
 }
 
 func (c *fakeConn) Begin() (driver.Tx, error) {
@@ -471,7 +466,7 @@ func (c *fakeConn) Prepare(query string) (driver.Stmt, error) {
 		panic("nil c.db; conn = " + fmt.Sprintf("%#v", c))
 	}
 
-	if c.stickyBad || (hookPrepareBadConn != nil && hookPrepareBadConn()) {
+	if hookPrepareBadConn != nil && hookPrepareBadConn() {
 		return nil, driver.ErrBadConn
 	}
 
@@ -534,7 +529,7 @@ func (s *fakeStmt) Exec(args []driver.Value) (driver.Result, error) {
 		return nil, errClosed
 	}
 
-	if s.c.stickyBad || (hookExecBadConn != nil && hookExecBadConn()) {
+	if hookExecBadConn != nil && hookExecBadConn() {
 		return nil, driver.ErrBadConn
 	}
 
@@ -618,7 +613,7 @@ func (s *fakeStmt) Query(args []driver.Value) (driver.Rows, error) {
 		return nil, errClosed
 	}
 
-	if s.c.stickyBad || (hookQueryBadConn != nil && hookQueryBadConn()) {
+	if hookQueryBadConn != nil && hookQueryBadConn() {
 		return nil, driver.ErrBadConn
 	}
 
diff --git a/src/database/sql/sql.go b/src/database/sql/sql.go
index aaa4ea2..6e6f246 100644
--- a/src/database/sql/sql.go
+++ b/src/database/sql/sql.go
@@ -6,10 +6,10 @@
 // databases.
 //
 // The sql package must be used in conjunction with a database driver.
-// See https://golang.org/s/sqldrivers for a list of drivers.
+// See http://golang.org/s/sqldrivers for a list of drivers.
 //
 // For more usage examples, see the wiki page at
-// https://golang.org/s/sqlwiki.
+// http://golang.org/s/sqlwiki.
 package sql
 
 import (
@@ -20,20 +20,14 @@ import (
 	"runtime"
 	"sort"
 	"sync"
-	"sync/atomic"
 )
 
-var (
-	driversMu sync.Mutex
-	drivers   = make(map[string]driver.Driver)
-)
+var drivers = make(map[string]driver.Driver)
 
 // Register makes a database driver available by the provided name.
 // If Register is called twice with the same name or if driver is nil,
 // it panics.
 func Register(name string, driver driver.Driver) {
-	driversMu.Lock()
-	defer driversMu.Unlock()
 	if driver == nil {
 		panic("sql: Register driver is nil")
 	}
@@ -44,16 +38,12 @@ func Register(name string, driver driver.Driver) {
 }
 
 func unregisterAllDrivers() {
-	driversMu.Lock()
-	defer driversMu.Unlock()
 	// For tests.
 	drivers = make(map[string]driver.Driver)
 }
 
 // Drivers returns a sorted list of the names of the registered drivers.
 func Drivers() []string {
-	driversMu.Lock()
-	defer driversMu.Unlock()
 	var list []string
 	for name := range drivers {
 		list = append(list, name)
@@ -221,10 +211,6 @@ var ErrNoRows = errors.New("sql: no rows in result set")
 type DB struct {
 	driver driver.Driver
 	dsn    string
-	// numClosed is an atomic counter which represents a total number of
-	// closed connections. Stmt.openStmt checks it before cleaning closed
-	// connections in Stmt.css.
-	numClosed uint64
 
 	mu           sync.Mutex // protects following fields
 	freeConn     []*driverConn
@@ -244,18 +230,6 @@ type DB struct {
 	maxOpen  int                    // <= 0 means unlimited
 }
 
-// connReuseStrategy determines how (*DB).conn returns database connections.
-type connReuseStrategy uint8
-
-const (
-	// alwaysNewConn forces a new connection to the database.
-	alwaysNewConn connReuseStrategy = iota
-	// cachedOrNewConn returns a cached connection, if available, else waits
-	// for one to become available (if MaxOpenConns has been reached) or
-	// creates a new database connection.
-	cachedOrNewConn
-)
-
 // driverConn wraps a driver.Conn with a mutex, to
 // be held during all calls into the Conn. (including any calls onto
 // interfaces returned via that Conn, such as calls on Tx, Stmt,
@@ -272,7 +246,7 @@ type driverConn struct {
 	// guarded by db.mu
 	inUse      bool
 	onPut      []func() // code (with db.mu held) run when conn is next returned
-	dbmuClosed bool     // same as closed, but guarded by db.mu, for removeClosedStmtLocked
+	dbmuClosed bool     // same as closed, but guarded by db.mu, for connIfFree
 }
 
 func (dc *driverConn) releaseConn(err error) {
@@ -355,7 +329,6 @@ func (dc *driverConn) finalClose() error {
 	dc.db.maybeOpenNewConnections()
 	dc.db.mu.Unlock()
 
-	atomic.AddUint64(&dc.db.numClosed, 1)
 	return err
 }
 
@@ -454,7 +427,7 @@ var connectionRequestQueueSize = 1000000
 //
 // Most users will open a database via a driver-specific connection
 // helper function that returns a *DB. No database drivers are included
-// in the Go standard library. See https://golang.org/s/sqldrivers for
+// in the Go standard library. See http://golang.org/s/sqldrivers for
 // a list of third-party drivers.
 //
 // Open may just validate its arguments without creating a connection
@@ -466,9 +439,7 @@ var connectionRequestQueueSize = 1000000
 // function should be called just once. It is rarely necessary to
 // close a DB.
 func Open(driverName, dataSourceName string) (*DB, error) {
-	driversMu.Lock()
 	driveri, ok := drivers[driverName]
-	driversMu.Unlock()
 	if !ok {
 		return nil, fmt.Errorf("sql: unknown driver %q (forgotten import?)", driverName)
 	}
@@ -488,7 +459,7 @@ func (db *DB) Ping() error {
 	// TODO(bradfitz): give drivers an optional hook to implement
 	// this in a more efficient or more reliable way, if they
 	// have one.
-	dc, err := db.conn(cachedOrNewConn)
+	dc, err := db.conn()
 	if err != nil {
 		return err
 	}
@@ -595,22 +566,6 @@ func (db *DB) SetMaxOpenConns(n int) {
 	}
 }
 
-// DBStats contains database statistics.
-type DBStats struct {
-	// OpenConnections is the number of open connections to the database.
-	OpenConnections int
-}
-
-// Stats returns database statistics.
-func (db *DB) Stats() DBStats {
-	db.mu.Lock()
-	stats := DBStats{
-		OpenConnections: db.numOpen,
-	}
-	db.mu.Unlock()
-	return stats
-}
-
 // Assumes db.mu is locked.
 // If there are connRequests and the connection limit hasn't been reached,
 // then tell the connectionOpener to open new connections.
@@ -674,37 +629,36 @@ type connRequest struct {
 
 var errDBClosed = errors.New("sql: database is closed")
 
-// conn returns a newly-opened or cached *driverConn.
-func (db *DB) conn(strategy connReuseStrategy) (*driverConn, error) {
+// conn returns a newly-opened or cached *driverConn
+func (db *DB) conn() (*driverConn, error) {
 	db.mu.Lock()
 	if db.closed {
 		db.mu.Unlock()
 		return nil, errDBClosed
 	}
 
-	// Prefer a free connection, if possible.
-	numFree := len(db.freeConn)
-	if strategy == cachedOrNewConn && numFree > 0 {
-		conn := db.freeConn[0]
-		copy(db.freeConn, db.freeConn[1:])
-		db.freeConn = db.freeConn[:numFree-1]
-		conn.inUse = true
-		db.mu.Unlock()
-		return conn, nil
-	}
-
-	// Out of free connections or we were asked not to use one.  If we're not
-	// allowed to open any more connections, make a request and wait.
-	if db.maxOpen > 0 && db.numOpen >= db.maxOpen {
+	// If db.maxOpen > 0 and the number of open connections is over the limit
+	// and there are no free connection, make a request and wait.
+	if db.maxOpen > 0 && db.numOpen >= db.maxOpen && len(db.freeConn) == 0 {
 		// Make the connRequest channel. It's buffered so that the
 		// connectionOpener doesn't block while waiting for the req to be read.
 		req := make(chan connRequest, 1)
 		db.connRequests = append(db.connRequests, req)
+		db.maybeOpenNewConnections()
 		db.mu.Unlock()
 		ret := <-req
 		return ret.conn, ret.err
 	}
 
+	if c := len(db.freeConn); c > 0 {
+		conn := db.freeConn[0]
+		copy(db.freeConn, db.freeConn[1:])
+		db.freeConn = db.freeConn[:c-1]
+		conn.inUse = true
+		db.mu.Unlock()
+		return conn, nil
+	}
+
 	db.numOpen++ // optimistically
 	db.mu.Unlock()
 	ci, err := db.driver.Open(db.dsn)
@@ -730,6 +684,42 @@ var (
 	errConnBusy   = errors.New("database/sql: internal sentinel error: conn is busy")
 )
 
+// connIfFree returns (wanted, nil) if wanted is still a valid conn and
+// isn't in use.
+//
+// The error is errConnClosed if the connection if the requested connection
+// is invalid because it's been closed.
+//
+// The error is errConnBusy if the connection is in use.
+func (db *DB) connIfFree(wanted *driverConn) (*driverConn, error) {
+	db.mu.Lock()
+	defer db.mu.Unlock()
+	if wanted.dbmuClosed {
+		return nil, errConnClosed
+	}
+	if wanted.inUse {
+		return nil, errConnBusy
+	}
+	idx := -1
+	for ii, v := range db.freeConn {
+		if v == wanted {
+			idx = ii
+			break
+		}
+	}
+	if idx >= 0 {
+		db.freeConn = append(db.freeConn[:idx], db.freeConn[idx+1:]...)
+		wanted.inUse = true
+		return wanted, nil
+	}
+	// TODO(bradfitz): shouldn't get here. After Go 1.1, change this to:
+	// panic("connIfFree call requested a non-closed, non-busy, non-free conn")
+	// Which passes all the tests, but I'm too paranoid to include this
+	// late in Go 1.1.
+	// Instead, treat it like a busy connection:
+	return nil, errConnBusy
+}
+
 // putConnHook is a hook for testing.
 var putConnHook func(*DB, *driverConn)
 
@@ -807,9 +797,6 @@ func (db *DB) putConn(dc *driverConn, err error) {
 // 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.maxOpen > 0 && db.numOpen > db.maxOpen {
-		return false
-	}
 	if c := len(db.connRequests); c > 0 {
 		req := db.connRequests[0]
 		// This copy is O(n) but in practice faster than a linked list.
@@ -833,38 +820,32 @@ func (db *DB) putConnDBLocked(dc *driverConn, err error) bool {
 }
 
 // maxBadConnRetries is the number of maximum retries if the driver returns
-// driver.ErrBadConn to signal a broken connection before forcing a new
-// connection to be opened.
-const maxBadConnRetries = 2
+// 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.
-// The caller must call the statement's Close method
-// when the statement is no longer needed.
 func (db *DB) Prepare(query string) (*Stmt, error) {
 	var stmt *Stmt
 	var err error
 	for i := 0; i < maxBadConnRetries; i++ {
-		stmt, err = db.prepare(query, cachedOrNewConn)
+		stmt, err = db.prepare(query)
 		if err != driver.ErrBadConn {
 			break
 		}
 	}
-	if err == driver.ErrBadConn {
-		return db.prepare(query, alwaysNewConn)
-	}
 	return stmt, err
 }
 
-func (db *DB) prepare(query string, strategy connReuseStrategy) (*Stmt, error) {
+func (db *DB) prepare(query string) (*Stmt, error) {
 	// TODO: check if db.driver supports an optional
 	// driver.Preparer interface and call that instead, if so,
 	// otherwise we make a prepared statement that's bound
 	// to a connection, and to execute this prepared statement
 	// we either need to use this connection (if it's free), else
 	// get a new connection + re-prepare + execute on that one.
-	dc, err := db.conn(strategy)
+	dc, err := db.conn()
 	if err != nil {
 		return nil, err
 	}
@@ -876,10 +857,9 @@ func (db *DB) prepare(query string, strategy connReuseStrategy) (*Stmt, error) {
 		return nil, err
 	}
 	stmt := &Stmt{
-		db:            db,
-		query:         query,
-		css:           []connStmt{{dc, si}},
-		lastNumClosed: atomic.LoadUint64(&db.numClosed),
+		db:    db,
+		query: query,
+		css:   []connStmt{{dc, si}},
 	}
 	db.addDep(stmt, stmt)
 	db.putConn(dc, nil)
@@ -892,19 +872,16 @@ func (db *DB) Exec(query string, args ...interface{}) (Result, error) {
 	var res Result
 	var err error
 	for i := 0; i < maxBadConnRetries; i++ {
-		res, err = db.exec(query, args, cachedOrNewConn)
+		res, err = db.exec(query, args)
 		if err != driver.ErrBadConn {
 			break
 		}
 	}
-	if err == driver.ErrBadConn {
-		return db.exec(query, args, alwaysNewConn)
-	}
 	return res, err
 }
 
-func (db *DB) exec(query string, args []interface{}, strategy connReuseStrategy) (res Result, err error) {
-	dc, err := db.conn(strategy)
+func (db *DB) exec(query string, args []interface{}) (res Result, err error) {
+	dc, err := db.conn()
 	if err != nil {
 		return nil, err
 	}
@@ -944,19 +921,16 @@ func (db *DB) Query(query string, args ...interface{}) (*Rows, error) {
 	var rows *Rows
 	var err error
 	for i := 0; i < maxBadConnRetries; i++ {
-		rows, err = db.query(query, args, cachedOrNewConn)
+		rows, err = db.query(query, args)
 		if err != driver.ErrBadConn {
 			break
 		}
 	}
-	if err == driver.ErrBadConn {
-		return db.query(query, args, alwaysNewConn)
-	}
 	return rows, err
 }
 
-func (db *DB) query(query string, args []interface{}, strategy connReuseStrategy) (*Rows, error) {
-	ci, err := db.conn(strategy)
+func (db *DB) query(query string, args []interface{}) (*Rows, error) {
+	ci, err := db.conn()
 	if err != nil {
 		return nil, err
 	}
@@ -1035,19 +1009,16 @@ func (db *DB) Begin() (*Tx, error) {
 	var tx *Tx
 	var err error
 	for i := 0; i < maxBadConnRetries; i++ {
-		tx, err = db.begin(cachedOrNewConn)
+		tx, err = db.begin()
 		if err != driver.ErrBadConn {
 			break
 		}
 	}
-	if err == driver.ErrBadConn {
-		return db.begin(alwaysNewConn)
-	}
 	return tx, err
 }
 
-func (db *DB) begin(strategy connReuseStrategy) (tx *Tx, err error) {
-	dc, err := db.conn(strategy)
+func (db *DB) begin() (tx *Tx, err error) {
+	dc, err := db.conn()
 	if err != nil {
 		return nil, err
 	}
@@ -1076,10 +1047,6 @@ func (db *DB) Driver() driver.Driver {
 //
 // After a call to Commit or Rollback, all operations on the
 // transaction fail with ErrTxDone.
-//
-// The statements prepared for a transaction by calling
-// the transaction's Prepare or Stmt methods are closed
-// by the call to Commit or Rollback.
 type Tx struct {
 	db *DB
 
@@ -1215,9 +1182,6 @@ func (tx *Tx) Prepare(query string) (*Stmt, error) {
 //  tx, err := db.Begin()
 //  ...
 //  res, err := tx.Stmt(updateMoney).Exec(123.45, 98293203)
-//
-// The returned statement operates within the transaction and can no longer
-// be used once the transaction has been committed or rolled back.
 func (tx *Tx) Stmt(stmt *Stmt) *Stmt {
 	// TODO(bradfitz): optimize this. Currently this re-prepares
 	// each time.  This is fine for now to illustrate the API but
@@ -1309,8 +1273,7 @@ type connStmt struct {
 	si driver.Stmt
 }
 
-// Stmt is a prepared statement.
-// A Stmt is safe for concurrent use by multiple goroutines.
+// Stmt is a prepared statement. Stmt is safe for concurrent use by multiple goroutines.
 type Stmt struct {
 	// Immutable:
 	db        *DB    // where we came from
@@ -1331,10 +1294,6 @@ type Stmt struct {
 	// used if tx == nil and one is found that has idle
 	// connections.  If tx != nil, txsi is always used.
 	css []connStmt
-
-	// lastNumClosed is copied from db.numClosed when Stmt is created
-	// without tx and closed connections in css are removed.
-	lastNumClosed uint64
 }
 
 // Exec executes a prepared statement with the given arguments and
@@ -1388,32 +1347,6 @@ func resultFromStatement(ds driverStmt, args ...interface{}) (Result, error) {
 	return driverResult{ds.Locker, resi}, nil
 }
 
-// removeClosedStmtLocked removes closed conns in s.css.
-//
-// To avoid lock contention on DB.mu, we do it only when
-// s.db.numClosed - s.lastNum is large enough.
-func (s *Stmt) removeClosedStmtLocked() {
-	t := len(s.css)/2 + 1
-	if t > 10 {
-		t = 10
-	}
-	dbClosed := atomic.LoadUint64(&s.db.numClosed)
-	if dbClosed-s.lastNumClosed < uint64(t) {
-		return
-	}
-
-	s.db.mu.Lock()
-	for i := 0; i < len(s.css); i++ {
-		if s.css[i].dc.dbmuClosed {
-			s.css[i] = s.css[len(s.css)-1]
-			s.css = s.css[:len(s.css)-1]
-			i--
-		}
-	}
-	s.db.mu.Unlock()
-	s.lastNumClosed = dbClosed
-}
-
 // connStmt returns a free driver connection on which to execute the
 // statement, a function to call to release the connection, and a
 // statement bound to that connection.
@@ -1440,15 +1373,35 @@ func (s *Stmt) connStmt() (ci *driverConn, releaseConn func(error), si driver.St
 		return ci, releaseConn, s.txsi.si, nil
 	}
 
-	s.removeClosedStmtLocked()
+	for i := 0; i < len(s.css); i++ {
+		v := s.css[i]
+		_, err := s.db.connIfFree(v.dc)
+		if err == nil {
+			s.mu.Unlock()
+			return v.dc, v.dc.releaseConn, v.si, nil
+		}
+		if err == errConnClosed {
+			// Lazily remove dead conn from our freelist.
+			s.css[i] = s.css[len(s.css)-1]
+			s.css = s.css[:len(s.css)-1]
+			i--
+		}
+
+	}
 	s.mu.Unlock()
 
+	// If all connections are busy, either wait for one to become available (if
+	// we've already hit the maximum number of open connections) or create a
+	// new one.
+	//
 	// TODO(bradfitz): or always wait for one? make configurable later?
-	dc, err := s.db.conn(cachedOrNewConn)
+	dc, err := s.db.conn()
 	if err != nil {
 		return nil, nil, nil, err
 	}
 
+	// Do another pass over the list to see whether this statement has
+	// already been prepared on the connection assigned to us.
 	s.mu.Lock()
 	for _, v := range s.css {
 		if v.dc == dc {
diff --git a/src/database/sql/sql_test.go b/src/database/sql/sql_test.go
index 432a641..34efdf2 100644
--- a/src/database/sql/sql_test.go
+++ b/src/database/sql/sql_test.go
@@ -497,7 +497,7 @@ func TestTxStmt(t *testing.T) {
 	}
 }
 
-// Issue: https://golang.org/issue/2784
+// Issue: http://golang.org/issue/2784
 // 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) {
@@ -1070,57 +1070,6 @@ func TestMaxOpenConns(t *testing.T) {
 	}
 }
 
-// Issue 9453: tests that SetMaxOpenConns can be lowered at runtime
-// and affects the subsequent release of connections.
-func TestMaxOpenConnsOnBusy(t *testing.T) {
-	defer setHookpostCloseConn(nil)
-	setHookpostCloseConn(func(_ *fakeConn, err error) {
-		if err != nil {
-			t.Errorf("Error closing fakeConn: %v", err)
-		}
-	})
-
-	db := newTestDB(t, "magicquery")
-	defer closeDB(t, db)
-
-	db.SetMaxOpenConns(3)
-
-	conn0, err := db.conn(cachedOrNewConn)
-	if err != nil {
-		t.Fatalf("db open conn fail: %v", err)
-	}
-
-	conn1, err := db.conn(cachedOrNewConn)
-	if err != nil {
-		t.Fatalf("db open conn fail: %v", err)
-	}
-
-	conn2, err := db.conn(cachedOrNewConn)
-	if err != nil {
-		t.Fatalf("db open conn fail: %v", err)
-	}
-
-	if g, w := db.numOpen, 3; g != w {
-		t.Errorf("free conns = %d; want %d", g, w)
-	}
-
-	db.SetMaxOpenConns(2)
-	if g, w := db.numOpen, 3; g != w {
-		t.Errorf("free conns = %d; want %d", g, w)
-	}
-
-	conn0.releaseConn(nil)
-	conn1.releaseConn(nil)
-	if g, w := db.numOpen, 2; g != w {
-		t.Errorf("free conns = %d; want %d", g, w)
-	}
-
-	conn2.releaseConn(nil)
-	if g, w := db.numOpen, 2; g != w {
-		t.Errorf("free conns = %d; want %d", g, w)
-	}
-}
-
 func TestSingleOpenConn(t *testing.T) {
 	db := newTestDB(t, "people")
 	defer closeDB(t, db)
@@ -1144,26 +1093,6 @@ func TestSingleOpenConn(t *testing.T) {
 	}
 }
 
-func TestStats(t *testing.T) {
-	db := newTestDB(t, "people")
-	stats := db.Stats()
-	if got := stats.OpenConnections; got != 1 {
-		t.Errorf("stats.OpenConnections = %d; want 1", got)
-	}
-
-	tx, err := db.Begin()
-	if err != nil {
-		t.Fatal(err)
-	}
-	tx.Commit()
-
-	closeDB(t, db)
-	stats = db.Stats()
-	if got := stats.OpenConnections; got != 0 {
-		t.Errorf("stats.OpenConnections = %d; want 0", got)
-	}
-}
-
 // golang.org/issue/5323
 func TestStmtCloseDeps(t *testing.T) {
 	if testing.Short() {
@@ -1385,80 +1314,7 @@ func TestStmtCloseOrder(t *testing.T) {
 	}
 }
 
-// Test cases where there's more than maxBadConnRetries bad connections in the
-// pool (issue 8834)
-func TestManyErrBadConn(t *testing.T) {
-	manyErrBadConnSetup := func() *DB {
-		db := newTestDB(t, "people")
-
-		nconn := maxBadConnRetries + 1
-		db.SetMaxIdleConns(nconn)
-		db.SetMaxOpenConns(nconn)
-		// open enough connections
-		func() {
-			for i := 0; i < nconn; i++ {
-				rows, err := db.Query("SELECT|people|age,name|")
-				if err != nil {
-					t.Fatal(err)
-				}
-				defer rows.Close()
-			}
-		}()
-
-		if db.numOpen != nconn {
-			t.Fatalf("unexpected numOpen %d (was expecting %d)", db.numOpen, nconn)
-		} else if len(db.freeConn) != nconn {
-			t.Fatalf("unexpected len(db.freeConn) %d (was expecting %d)", len(db.freeConn), nconn)
-		}
-		for _, conn := range db.freeConn {
-			conn.ci.(*fakeConn).stickyBad = true
-		}
-		return db
-	}
-
-	// Query
-	db := manyErrBadConnSetup()
-	defer closeDB(t, db)
-	rows, err := db.Query("SELECT|people|age,name|")
-	if err != nil {
-		t.Fatal(err)
-	}
-	if err = rows.Close(); err != nil {
-		t.Fatal(err)
-	}
-
-	// Exec
-	db = manyErrBadConnSetup()
-	defer closeDB(t, db)
-	_, err = db.Exec("INSERT|people|name=Julia,age=19")
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	// Begin
-	db = manyErrBadConnSetup()
-	defer closeDB(t, db)
-	tx, err := db.Begin()
-	if err != nil {
-		t.Fatal(err)
-	}
-	if err = tx.Rollback(); err != nil {
-		t.Fatal(err)
-	}
-
-	// Prepare
-	db = manyErrBadConnSetup()
-	defer closeDB(t, db)
-	stmt, err := db.Prepare("SELECT|people|age,name|")
-	if err != nil {
-		t.Fatal(err)
-	}
-	if err = stmt.Close(); err != nil {
-		t.Fatal(err)
-	}
-}
-
-// golang.org/issue/5718
+// golang.org/issue/5781
 func TestErrBadConnReconnect(t *testing.T) {
 	db := newTestDB(t, "foo")
 	defer closeDB(t, db)
@@ -1908,6 +1764,56 @@ func doConcurrentTest(t testing.TB, ct concurrentTest) {
 	wg.Wait()
 }
 
+func manyConcurrentQueries(t testing.TB) {
+	maxProcs, numReqs := 16, 500
+	if testing.Short() {
+		maxProcs, numReqs = 4, 50
+	}
+	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(maxProcs))
+
+	db := newTestDB(t, "people")
+	defer closeDB(t, db)
+
+	stmt, err := db.Prepare("SELECT|people|name|")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer stmt.Close()
+
+	var wg sync.WaitGroup
+	wg.Add(numReqs)
+
+	reqs := make(chan bool)
+	defer close(reqs)
+
+	for i := 0; i < maxProcs*2; i++ {
+		go func() {
+			for range reqs {
+				rows, err := stmt.Query()
+				if err != nil {
+					t.Errorf("error on query:  %v", err)
+					wg.Done()
+					continue
+				}
+
+				var name string
+				for rows.Next() {
+					rows.Scan(&name)
+				}
+				rows.Close()
+
+				wg.Done()
+			}
+		}()
+	}
+
+	for i := 0; i < numReqs; i++ {
+		reqs <- true
+	}
+
+	wg.Wait()
+}
+
 func TestIssue6081(t *testing.T) {
 	db := newTestDB(t, "people")
 	defer closeDB(t, db)
@@ -2079,31 +1985,3 @@ func BenchmarkConcurrentRandom(b *testing.B) {
 		doConcurrentTest(b, ct)
 	}
 }
-
-func BenchmarkManyConcurrentQueries(b *testing.B) {
-	b.ReportAllocs()
-	// To see lock contention in Go 1.4, 16~ cores and 128~ goroutines are required.
-	const parallelism = 16
-
-	db := newTestDB(b, "magicquery")
-	defer closeDB(b, db)
-	db.SetMaxIdleConns(runtime.GOMAXPROCS(0) * parallelism)
-
-	stmt, err := db.Prepare("SELECT|magicquery|op|op=?,millis=?")
-	if err != nil {
-		b.Fatal(err)
-	}
-	defer stmt.Close()
-
-	b.SetParallelism(parallelism)
-	b.RunParallel(func(pb *testing.PB) {
-		for pb.Next() {
-			rows, err := stmt.Query("sleep", 1)
-			if err != nil {
-				b.Error(err)
-				return
-			}
-			rows.Close()
-		}
-	})
-}
diff --git a/src/debug/dwarf/buf.go b/src/debug/dwarf/buf.go
index 2ade0bd..53c46eb 100644
--- a/src/debug/dwarf/buf.go
+++ b/src/debug/dwarf/buf.go
@@ -163,17 +163,6 @@ func (b *buf) addr() uint64 {
 	return 0
 }
 
-func (b *buf) unitLength() (length Offset, dwarf64 bool) {
-	length = Offset(b.uint32())
-	if length == 0xffffffff {
-		dwarf64 = true
-		length = Offset(b.uint64())
-	} else if length >= 0xfffffff0 {
-		b.error("unit length has reserved value")
-	}
-	return
-}
-
 func (b *buf) error(s string) {
 	if b.err == nil {
 		b.data = nil
diff --git a/src/debug/dwarf/const.go b/src/debug/dwarf/const.go
index 2170db1..93c6888 100644
--- a/src/debug/dwarf/const.go
+++ b/src/debug/dwarf/const.go
@@ -452,31 +452,3 @@ const (
 	encUnsignedChar   = 0x08
 	encImaginaryFloat = 0x09
 )
-
-// Statement program standard opcode encodings.
-const (
-	lnsCopy           = 1
-	lnsAdvancePC      = 2
-	lnsAdvanceLine    = 3
-	lnsSetFile        = 4
-	lnsSetColumn      = 5
-	lnsNegateStmt     = 6
-	lnsSetBasicBlock  = 7
-	lnsConstAddPC     = 8
-	lnsFixedAdvancePC = 9
-
-	// DWARF 3
-	lnsSetPrologueEnd   = 10
-	lnsSetEpilogueBegin = 11
-	lnsSetISA           = 12
-)
-
-// Statement program extended opcode encodings.
-const (
-	lneEndSequence = 1
-	lneSetAddress  = 2
-	lneDefineFile  = 3
-
-	// DWARF 4
-	lneSetDiscriminator = 4
-)
diff --git a/src/debug/dwarf/entry.go b/src/debug/dwarf/entry.go
index d607e5b..665c684 100644
--- a/src/debug/dwarf/entry.go
+++ b/src/debug/dwarf/entry.go
@@ -23,9 +23,8 @@ type abbrev struct {
 }
 
 type afield struct {
-	attr  Attr
-	fmt   format
-	class Class
+	attr Attr
+	fmt  format
 }
 
 // a map from entry format ids to their descriptions
@@ -33,7 +32,7 @@ type abbrevTable map[uint32]abbrev
 
 // ParseAbbrev returns the abbreviation table that starts at byte off
 // in the .debug_abbrev section.
-func (d *Data) parseAbbrev(off uint32, vers int) (abbrevTable, error) {
+func (d *Data) parseAbbrev(off uint32) (abbrevTable, error) {
 	if m, ok := d.abbrevCache[off]; ok {
 		return m, nil
 	}
@@ -81,7 +80,6 @@ func (d *Data) parseAbbrev(off uint32, vers int) (abbrevTable, error) {
 		for i := range a.field {
 			a.field[i].attr = Attr(b.uint())
 			a.field[i].fmt = format(b.uint())
-			a.field[i].class = formToClass(a.field[i].fmt, a.field[i].attr, vers, &b)
 		}
 		b.uint()
 		b.uint()
@@ -95,118 +93,6 @@ func (d *Data) parseAbbrev(off uint32, vers int) (abbrevTable, error) {
 	return m, nil
 }
 
-// attrIsExprloc indicates attributes that allow exprloc values that
-// are encoded as block values in DWARF 2 and 3. See DWARF 4, Figure
-// 20.
-var attrIsExprloc = map[Attr]bool{
-	AttrLocation:      true,
-	AttrByteSize:      true,
-	AttrBitOffset:     true,
-	AttrBitSize:       true,
-	AttrStringLength:  true,
-	AttrLowerBound:    true,
-	AttrReturnAddr:    true,
-	AttrStrideSize:    true,
-	AttrUpperBound:    true,
-	AttrCount:         true,
-	AttrDataMemberLoc: true,
-	AttrFrameBase:     true,
-	AttrSegment:       true,
-	AttrStaticLink:    true,
-	AttrUseLocation:   true,
-	AttrVtableElemLoc: true,
-	AttrAllocated:     true,
-	AttrAssociated:    true,
-	AttrDataLocation:  true,
-	AttrStride:        true,
-}
-
-// attrPtrClass indicates the *ptr class of attributes that have
-// encoding formSecOffset in DWARF 4 or formData* in DWARF 2 and 3.
-var attrPtrClass = map[Attr]Class{
-	AttrLocation:      ClassLocListPtr,
-	AttrStmtList:      ClassLinePtr,
-	AttrStringLength:  ClassLocListPtr,
-	AttrReturnAddr:    ClassLocListPtr,
-	AttrStartScope:    ClassRangeListPtr,
-	AttrDataMemberLoc: ClassLocListPtr,
-	AttrFrameBase:     ClassLocListPtr,
-	AttrMacroInfo:     ClassMacPtr,
-	AttrSegment:       ClassLocListPtr,
-	AttrStaticLink:    ClassLocListPtr,
-	AttrUseLocation:   ClassLocListPtr,
-	AttrVtableElemLoc: ClassLocListPtr,
-	AttrRanges:        ClassRangeListPtr,
-}
-
-// formToClass returns the DWARF 4 Class for the given form. If the
-// DWARF version is less then 4, it will disambiguate some forms
-// depending on the attribute.
-func formToClass(form format, attr Attr, vers int, b *buf) Class {
-	switch form {
-	default:
-		b.error("cannot determine class of unknown attribute form")
-		return 0
-
-	case formAddr:
-		return ClassAddress
-
-	case formDwarfBlock1, formDwarfBlock2, formDwarfBlock4, formDwarfBlock:
-		// In DWARF 2 and 3, ClassExprLoc was encoded as a
-		// block. DWARF 4 distinguishes ClassBlock and
-		// ClassExprLoc, but there are no attributes that can
-		// be both, so we also promote ClassBlock values in
-		// DWARF 4 that should be ClassExprLoc in case
-		// producers get this wrong.
-		if attrIsExprloc[attr] {
-			return ClassExprLoc
-		}
-		return ClassBlock
-
-	case formData1, formData2, formData4, formData8, formSdata, formUdata:
-		// In DWARF 2 and 3, ClassPtr was encoded as a
-		// constant. Unlike ClassExprLoc/ClassBlock, some
-		// DWARF 4 attributes need to distinguish Class*Ptr
-		// from ClassConstant, so we only do this promotion
-		// for versions 2 and 3.
-		if class, ok := attrPtrClass[attr]; vers < 4 && ok {
-			return class
-		}
-		return ClassConstant
-
-	case formFlag, formFlagPresent:
-		return ClassFlag
-
-	case formRefAddr, formRef1, formRef2, formRef4, formRef8, formRefUdata:
-		return ClassReference
-
-	case formRefSig8:
-		return ClassReferenceSig
-
-	case formString, formStrp:
-		return ClassString
-
-	case formSecOffset:
-		// DWARF 4 defines four *ptr classes, but doesn't
-		// distinguish them in the encoding. Disambiguate
-		// these classes using the attribute.
-		if class, ok := attrPtrClass[attr]; ok {
-			return class
-		}
-		b.error("cannot determine class of unknown attribute with formSecOffset")
-		return 0
-
-	case formExprloc:
-		return ClassExprLoc
-
-	case formGnuRefAlt:
-		return ClassReferenceAlt
-
-	case formGnuStrpAlt:
-		return ClassStringAlt
-	}
-}
-
 // An entry is a sequence of attribute/value pairs.
 type Entry struct {
 	Offset   Offset // offset of Entry in DWARF info
@@ -216,115 +102,9 @@ type Entry struct {
 }
 
 // A Field is a single attribute/value pair in an Entry.
-//
-// A value can be one of several "attribute classes" defined by DWARF.
-// The Go types corresponding to each class are:
-//
-//    DWARF class       Go type        Class
-//    -----------       -------        -----
-//    address           uint64         ClassAddress
-//    block             []byte         ClassBlock
-//    constant          int64          ClassConstant
-//    flag              bool           ClassFlag
-//    reference
-//      to info         dwarf.Offset   ClassReference
-//      to type unit    uint64         ClassReferenceSig
-//    string            string         ClassString
-//    exprloc           []byte         ClassExprLoc
-//    lineptr           int64          ClassLinePtr
-//    loclistptr        int64          ClassLocListPtr
-//    macptr            int64          ClassMacPtr
-//    rangelistptr      int64          ClassRangeListPtr
 type Field struct {
-	Attr  Attr
-	Val   interface{}
-	Class Class
-}
-
-// A Class is the DWARF 4 class of an attibute value.
-//
-// In general, a given attribute's value may take on one of several
-// possible classes defined by DWARF, each of which leads to a
-// slightly different interpretation of the attribute.
-//
-// DWARF version 4 distinguishes attribute value classes more finely
-// than previous versions of DWARF. The reader will disambiguate
-// coarser classes from earlier versions of DWARF into the appropriate
-// DWARF 4 class. For example, DWARF 2 uses "constant" for constants
-// as well as all types of section offsets, but the reader will
-// canonicalize attributes in DWARF 2 files that refer to section
-// offsets to one of the Class*Ptr classes, even though these classes
-// were only defined in DWARF 3.
-type Class int
-
-const (
-	// ClassAddress represents values of type uint64 that are
-	// addresses on the target machine.
-	ClassAddress Class = 1 + iota
-
-	// ClassBlock represents values of type []byte whose
-	// interpretation depends on the attribute.
-	ClassBlock
-
-	// ClassConstant represents values of type int64 that are
-	// constants. The interpretation of this constant depends on
-	// the attribute.
-	ClassConstant
-
-	// ClassExprLoc represents values of type []byte that contain
-	// an encoded DWARF expression or location description.
-	ClassExprLoc
-
-	// ClassFlag represents values of type bool.
-	ClassFlag
-
-	// ClassLinePtr represents values that are an int64 offset
-	// into the "line" section.
-	ClassLinePtr
-
-	// ClassLocListPtr represents values that are an int64 offset
-	// into the "loclist" section.
-	ClassLocListPtr
-
-	// ClassMacPtr represents values that are an int64 offset into
-	// the "mac" section.
-	ClassMacPtr
-
-	// ClassMacPtr represents values that are an int64 offset into
-	// the "rangelist" section.
-	ClassRangeListPtr
-
-	// ClassReference represents values that are an Offset offset
-	// of an Entry in the info section (for use with Reader.Seek).
-	// The DWARF specification combines ClassReference and
-	// ClassReferenceSig into class "reference".
-	ClassReference
-
-	// ClassReferenceSig represents values that are a uint64 type
-	// signature referencing a type Entry.
-	ClassReferenceSig
-
-	// ClassString represents values that are strings. If the
-	// compilation unit specifies the AttrUseUTF8 flag (strongly
-	// recommended), the string value will be encoded in UTF-8.
-	// Otherwise, the encoding is unspecified.
-	ClassString
-
-	// ClassReferenceAlt represents values of type int64 that are
-	// an offset into the DWARF "info" section of an alternate
-	// object file.
-	ClassReferenceAlt
-
-	// ClassStringAlt represents values of type int64 that are an
-	// offset into the DWARF string section of an alternate object
-	// file.
-	ClassStringAlt
-)
-
-//go:generate stringer -type=Class
-
-func (i Class) GoString() string {
-	return "dwarf." + i.String()
+	Attr Attr
+	Val  interface{}
 }
 
 // Val returns the value associated with attribute Attr in Entry,
@@ -332,21 +112,12 @@ func (i Class) GoString() string {
 //
 // A common idiom is to merge the check for nil return with
 // the check that the value has the expected dynamic type, as in:
-//	v, ok := e.Val(AttrSibling).(int64)
+//	v, ok := e.Val(AttrSibling).(int64);
 //
 func (e *Entry) Val(a Attr) interface{} {
-	if f := e.AttrField(a); f != nil {
-		return f.Val
-	}
-	return nil
-}
-
-// AttrField returns the Field associated with attribute Attr in
-// Entry, or nil if there is no such attribute.
-func (e *Entry) AttrField(a Attr) *Field {
-	for i, f := range e.Field {
+	for _, f := range e.Field {
 		if f.Attr == a {
-			return &e.Field[i]
+			return f.Val
 		}
 	}
 	return nil
@@ -377,7 +148,6 @@ func (b *buf) entry(atab abbrevTable, ubase Offset) *Entry {
 	}
 	for i := range e.Field {
 		e.Field[i].Attr = a.field[i].attr
-		e.Field[i].Class = a.field[i].class
 		fmt := a.field[i].fmt
 		if fmt == formIndirect {
 			fmt = format(b.uint())
@@ -522,12 +292,6 @@ func (d *Data) Reader() *Reader {
 	return r
 }
 
-// AddressSize returns the size in bytes of addresses in the current compilation
-// unit.
-func (r *Reader) AddressSize() int {
-	return r.d.unit[r.unit].asize
-}
-
 // Seek positions the Reader at offset off in the encoded entry stream.
 // Offset 0 can be used to denote the first entry.
 func (r *Reader) Seek(off Offset) {
@@ -544,14 +308,18 @@ func (r *Reader) Seek(off Offset) {
 		return
 	}
 
-	i := d.offsetToUnit(off)
-	if i == -1 {
-		r.err = errors.New("offset out of range")
-		return
+	// TODO(rsc): binary search (maybe a new package)
+	var i int
+	var u *unit
+	for i = range d.unit {
+		u = &d.unit[i]
+		if u.off <= off && off < u.off+Offset(len(u.data)) {
+			r.unit = i
+			r.b = makeBuf(r.d, u, "info", off, u.data[off-u.off:])
+			return
+		}
 	}
-	u := &d.unit[i]
-	r.unit = i
-	r.b = makeBuf(r.d, u, "info", off, u.data[off-u.off:])
+	r.err = errors.New("offset out of range")
 }
 
 // maybeNextUnit advances to the next unit if this one is finished.
diff --git a/src/debug/dwarf/type.go b/src/debug/dwarf/type.go
index a5daa1d..6986b19 100644
--- a/src/debug/dwarf/type.go
+++ b/src/debug/dwarf/type.go
@@ -268,9 +268,6 @@ type typeReader interface {
 	Next() (*Entry, error)
 	clone() typeReader
 	offset() Offset
-	// AddressSize returns the size in bytes of addresses in the current
-	// compilation unit.
-	AddressSize() int
 }
 
 // Type reads the type at off in the DWARF ``info'' section.
@@ -289,7 +286,6 @@ func (d *Data) readType(name string, r typeReader, off Offset, typeCache map[Off
 	if err != nil {
 		return nil, err
 	}
-	addressSize := r.AddressSize()
 	if e == nil || e.Offset != off {
 		return nil, DecodeError{name, off, "no type at offset"}
 	}
@@ -672,12 +668,6 @@ func (d *Data) readType(name string, r typeReader, off Offset, typeCache map[Off
 		b, ok := e.Val(AttrByteSize).(int64)
 		if !ok {
 			b = -1
-			switch t := typ.(type) {
-			case *TypedefType:
-				b = t.Type.Size()
-			case *PtrType:
-				b = int64(addressSize)
-			}
 		}
 		typ.Common().ByteSize = b
 	}
diff --git a/src/debug/dwarf/typeunit.go b/src/debug/dwarf/typeunit.go
index 9cfb4a8..3fd1c99 100644
--- a/src/debug/dwarf/typeunit.go
+++ b/src/debug/dwarf/typeunit.go
@@ -27,15 +27,21 @@ func (d *Data) parseTypes(name string, types []byte) error {
 	b := makeBuf(d, unknownFormat{}, name, 0, types)
 	for len(b.data) > 0 {
 		base := b.off
-		n, dwarf64 := b.unitLength()
-		if n != Offset(uint32(n)) {
-			b.error("type unit length overflow")
-			return b.err
+		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 := int(b.uint16())
+		vers := b.uint16()
 		if vers != 4 {
-			b.error("unsupported DWARF version " + strconv.Itoa(vers))
+			b.error("unsupported DWARF version " + strconv.Itoa(int(vers)))
 			return b.err
 		}
 		var ao uint32
@@ -49,7 +55,7 @@ func (d *Data) parseTypes(name string, types []byte) error {
 			}
 			ao = uint32(ao64)
 		}
-		atable, err := d.parseAbbrev(ao, vers)
+		atable, err := d.parseAbbrev(ao)
 		if err != nil {
 			return err
 		}
@@ -73,7 +79,7 @@ func (d *Data) parseTypes(name string, types []byte) error {
 			unit: unit{
 				base:   base,
 				off:    boff,
-				data:   b.bytes(int(n - (b.off - hdroff))),
+				data:   b.bytes(int(Offset(n) - (b.off - hdroff))),
 				atable: atable,
 				asize:  int(asize),
 				vers:   int(vers),
@@ -129,11 +135,6 @@ func (tur *typeUnitReader) Seek(off Offset) {
 	tur.b = makeBuf(tur.d, tur.tu, tur.tu.name, off, tur.tu.data[doff:])
 }
 
-// AddressSize returns the size in bytes of addresses in the current type unit.
-func (tur *typeUnitReader) AddressSize() int {
-	return tur.tu.unit.asize
-}
-
 // Next reads the next Entry from the type unit.
 func (tur *typeUnitReader) Next() (*Entry, error) {
 	if tur.err != nil {
diff --git a/src/debug/dwarf/unit.go b/src/debug/dwarf/unit.go
index ceb6cdb..0fbc8e0 100644
--- a/src/debug/dwarf/unit.go
+++ b/src/debug/dwarf/unit.go
@@ -4,10 +4,7 @@
 
 package dwarf
 
-import (
-	"sort"
-	"strconv"
-)
+import "strconv"
 
 // DWARF debug info is split into a sequence of compilation units.
 // Each unit has its own abbreviation table and address size.
@@ -41,10 +38,14 @@ func (d *Data) parseUnits() ([]unit, error) {
 	nunit := 0
 	b := makeBuf(d, unknownFormat{}, "info", 0, d.info)
 	for len(b.data) > 0 {
-		len, _ := b.unitLength()
-		if len != Offset(uint32(len)) {
-			b.error("unit length overflow")
-			break
+		len := b.uint32()
+		if len == 0xffffffff {
+			len64 := b.uint64()
+			if len64 != uint64(uint32(len64)) {
+				b.error("unit length overflow")
+				break
+			}
+			len = uint32(len64)
 		}
 		b.skip(int(len))
 		nunit++
@@ -59,15 +60,18 @@ func (d *Data) parseUnits() ([]unit, error) {
 	for i := range units {
 		u := &units[i]
 		u.base = b.off
-		var n Offset
-		n, u.is64 = b.unitLength()
+		n := b.uint32()
+		if n == 0xffffffff {
+			u.is64 = true
+			n = uint32(b.uint64())
+		}
 		vers := b.uint16()
 		if vers != 2 && vers != 3 && vers != 4 {
 			b.error("unsupported DWARF version " + strconv.Itoa(int(vers)))
 			break
 		}
 		u.vers = int(vers)
-		atable, err := d.parseAbbrev(b.uint32(), u.vers)
+		atable, err := d.parseAbbrev(b.uint32())
 		if err != nil {
 			if b.err == nil {
 				b.err = err
@@ -84,20 +88,3 @@ func (d *Data) parseUnits() ([]unit, error) {
 	}
 	return units, nil
 }
-
-// offsetToUnit returns the index of the unit containing offset off.
-// It returns -1 if no unit contains this offset.
-func (d *Data) offsetToUnit(off Offset) int {
-	// Find the unit after off
-	next := sort.Search(len(d.unit), func(i int) bool {
-		return d.unit[i].off > off
-	})
-	if next == 0 {
-		return -1
-	}
-	u := &d.unit[next-1]
-	if u.off <= off && off < u.off+Offset(len(u.data)) {
-		return next - 1
-	}
-	return -1
-}
diff --git a/src/debug/elf/elf.go b/src/debug/elf/elf.go
index 70daeec..cde296c 100644
--- a/src/debug/elf/elf.go
+++ b/src/debug/elf/elf.go
@@ -312,7 +312,7 @@ const (
 	SHN_HIOS      SectionIndex = 0xff3f /* Last operating system-specific. */
 	SHN_ABS       SectionIndex = 0xfff1 /* Absolute values. */
 	SHN_COMMON    SectionIndex = 0xfff2 /* Common data. */
-	SHN_XINDEX    SectionIndex = 0xffff /* Escape; index stored elsewhere. */
+	SHN_XINDEX    SectionIndex = 0xffff /* Escape -- index stored elsewhere. */
 	SHN_HIRESERVE SectionIndex = 0xffff /* Last of reserved range. */
 )
 
@@ -1414,184 +1414,6 @@ var rppcStrings = []intName{
 func (i R_PPC) String() string   { return stringName(uint32(i), rppcStrings, false) }
 func (i R_PPC) GoString() string { return stringName(uint32(i), rppcStrings, true) }
 
-// Relocation types for 64-bit PowerPC or Power Architecture processors.
-type R_PPC64 int
-
-const (
-	R_PPC64_NONE               R_PPC64 = 0
-	R_PPC64_ADDR32             R_PPC64 = 1
-	R_PPC64_ADDR24             R_PPC64 = 2
-	R_PPC64_ADDR16             R_PPC64 = 3
-	R_PPC64_ADDR16_LO          R_PPC64 = 4
-	R_PPC64_ADDR16_HI          R_PPC64 = 5
-	R_PPC64_ADDR16_HA          R_PPC64 = 6
-	R_PPC64_ADDR14             R_PPC64 = 7
-	R_PPC64_ADDR14_BRTAKEN     R_PPC64 = 8
-	R_PPC64_ADDR14_BRNTAKEN    R_PPC64 = 9
-	R_PPC64_REL24              R_PPC64 = 10
-	R_PPC64_REL14              R_PPC64 = 11
-	R_PPC64_REL14_BRTAKEN      R_PPC64 = 12
-	R_PPC64_REL14_BRNTAKEN     R_PPC64 = 13
-	R_PPC64_GOT16              R_PPC64 = 14
-	R_PPC64_GOT16_LO           R_PPC64 = 15
-	R_PPC64_GOT16_HI           R_PPC64 = 16
-	R_PPC64_GOT16_HA           R_PPC64 = 17
-	R_PPC64_JMP_SLOT           R_PPC64 = 21
-	R_PPC64_REL32              R_PPC64 = 26
-	R_PPC64_ADDR64             R_PPC64 = 38
-	R_PPC64_ADDR16_HIGHER      R_PPC64 = 39
-	R_PPC64_ADDR16_HIGHERA     R_PPC64 = 40
-	R_PPC64_ADDR16_HIGHEST     R_PPC64 = 41
-	R_PPC64_ADDR16_HIGHESTA    R_PPC64 = 42
-	R_PPC64_REL64              R_PPC64 = 44
-	R_PPC64_TOC16              R_PPC64 = 47
-	R_PPC64_TOC16_LO           R_PPC64 = 48
-	R_PPC64_TOC16_HI           R_PPC64 = 49
-	R_PPC64_TOC16_HA           R_PPC64 = 50
-	R_PPC64_TOC                R_PPC64 = 51
-	R_PPC64_ADDR16_DS          R_PPC64 = 56
-	R_PPC64_ADDR16_LO_DS       R_PPC64 = 57
-	R_PPC64_GOT16_DS           R_PPC64 = 58
-	R_PPC64_GOT16_LO_DS        R_PPC64 = 59
-	R_PPC64_TOC16_DS           R_PPC64 = 63
-	R_PPC64_TOC16_LO_DS        R_PPC64 = 64
-	R_PPC64_TLS                R_PPC64 = 67
-	R_PPC64_DTPMOD64           R_PPC64 = 68
-	R_PPC64_TPREL16            R_PPC64 = 69
-	R_PPC64_TPREL16_LO         R_PPC64 = 70
-	R_PPC64_TPREL16_HI         R_PPC64 = 71
-	R_PPC64_TPREL16_HA         R_PPC64 = 72
-	R_PPC64_TPREL64            R_PPC64 = 73
-	R_PPC64_DTPREL16           R_PPC64 = 74
-	R_PPC64_DTPREL16_LO        R_PPC64 = 75
-	R_PPC64_DTPREL16_HI        R_PPC64 = 76
-	R_PPC64_DTPREL16_HA        R_PPC64 = 77
-	R_PPC64_DTPREL64           R_PPC64 = 78
-	R_PPC64_GOT_TLSGD16        R_PPC64 = 79
-	R_PPC64_GOT_TLSGD16_LO     R_PPC64 = 80
-	R_PPC64_GOT_TLSGD16_HI     R_PPC64 = 81
-	R_PPC64_GOT_TLSGD16_HA     R_PPC64 = 82
-	R_PPC64_GOT_TLSLD16        R_PPC64 = 83
-	R_PPC64_GOT_TLSLD16_LO     R_PPC64 = 84
-	R_PPC64_GOT_TLSLD16_HI     R_PPC64 = 85
-	R_PPC64_GOT_TLSLD16_HA     R_PPC64 = 86
-	R_PPC64_GOT_TPREL16_DS     R_PPC64 = 87
-	R_PPC64_GOT_TPREL16_LO_DS  R_PPC64 = 88
-	R_PPC64_GOT_TPREL16_HI     R_PPC64 = 89
-	R_PPC64_GOT_TPREL16_HA     R_PPC64 = 90
-	R_PPC64_GOT_DTPREL16_DS    R_PPC64 = 91
-	R_PPC64_GOT_DTPREL16_LO_DS R_PPC64 = 92
-	R_PPC64_GOT_DTPREL16_HI    R_PPC64 = 93
-	R_PPC64_GOT_DTPREL16_HA    R_PPC64 = 94
-	R_PPC64_TPREL16_DS         R_PPC64 = 95
-	R_PPC64_TPREL16_LO_DS      R_PPC64 = 96
-	R_PPC64_TPREL16_HIGHER     R_PPC64 = 97
-	R_PPC64_TPREL16_HIGHERA    R_PPC64 = 98
-	R_PPC64_TPREL16_HIGHEST    R_PPC64 = 99
-	R_PPC64_TPREL16_HIGHESTA   R_PPC64 = 100
-	R_PPC64_DTPREL16_DS        R_PPC64 = 101
-	R_PPC64_DTPREL16_LO_DS     R_PPC64 = 102
-	R_PPC64_DTPREL16_HIGHER    R_PPC64 = 103
-	R_PPC64_DTPREL16_HIGHERA   R_PPC64 = 104
-	R_PPC64_DTPREL16_HIGHEST   R_PPC64 = 105
-	R_PPC64_DTPREL16_HIGHESTA  R_PPC64 = 106
-	R_PPC64_TLSGD              R_PPC64 = 107
-	R_PPC64_TLSLD              R_PPC64 = 108
-	R_PPC64_REL16              R_PPC64 = 249
-	R_PPC64_REL16_LO           R_PPC64 = 250
-	R_PPC64_REL16_HI           R_PPC64 = 251
-	R_PPC64_REL16_HA           R_PPC64 = 252
-)
-
-var rppc64Strings = []intName{
-	{0, "R_PPC64_NONE"},
-	{1, "R_PPC64_ADDR32"},
-	{2, "R_PPC64_ADDR24"},
-	{3, "R_PPC64_ADDR16"},
-	{4, "R_PPC64_ADDR16_LO"},
-	{5, "R_PPC64_ADDR16_HI"},
-	{6, "R_PPC64_ADDR16_HA"},
-	{7, "R_PPC64_ADDR14"},
-	{8, "R_PPC64_ADDR14_BRTAKEN"},
-	{9, "R_PPC64_ADDR14_BRNTAKEN"},
-	{10, "R_PPC64_REL24"},
-	{11, "R_PPC64_REL14"},
-	{12, "R_PPC64_REL14_BRTAKEN"},
-	{13, "R_PPC64_REL14_BRNTAKEN"},
-	{14, "R_PPC64_GOT16"},
-	{15, "R_PPC64_GOT16_LO"},
-	{16, "R_PPC64_GOT16_HI"},
-	{17, "R_PPC64_GOT16_HA"},
-	{21, "R_PPC64_JMP_SLOT"},
-	{26, "R_PPC64_REL32"},
-	{38, "R_PPC64_ADDR64"},
-	{39, "R_PPC64_ADDR16_HIGHER"},
-	{40, "R_PPC64_ADDR16_HIGHERA"},
-	{41, "R_PPC64_ADDR16_HIGHEST"},
-	{42, "R_PPC64_ADDR16_HIGHESTA"},
-	{44, "R_PPC64_REL64"},
-	{47, "R_PPC64_TOC16"},
-	{48, "R_PPC64_TOC16_LO"},
-	{49, "R_PPC64_TOC16_HI"},
-	{50, "R_PPC64_TOC16_HA"},
-	{51, "R_PPC64_TOC"},
-	{56, "R_PPC64_ADDR16_DS"},
-	{57, "R_PPC64_ADDR16_LO_DS"},
-	{58, "R_PPC64_GOT16_DS"},
-	{59, "R_PPC64_GOT16_LO_DS"},
-	{63, "R_PPC64_TOC16_DS"},
-	{64, "R_PPC64_TOC16_LO_DS"},
-	{67, "R_PPC64_TLS"},
-	{68, "R_PPC64_DTPMOD64"},
-	{69, "R_PPC64_TPREL16"},
-	{70, "R_PPC64_TPREL16_LO"},
-	{71, "R_PPC64_TPREL16_HI"},
-	{72, "R_PPC64_TPREL16_HA"},
-	{73, "R_PPC64_TPREL64"},
-	{74, "R_PPC64_DTPREL16"},
-	{75, "R_PPC64_DTPREL16_LO"},
-	{76, "R_PPC64_DTPREL16_HI"},
-	{77, "R_PPC64_DTPREL16_HA"},
-	{78, "R_PPC64_DTPREL64"},
-	{79, "R_PPC64_GOT_TLSGD16"},
-	{80, "R_PPC64_GOT_TLSGD16_LO"},
-	{81, "R_PPC64_GOT_TLSGD16_HI"},
-	{82, "R_PPC64_GOT_TLSGD16_HA"},
-	{83, "R_PPC64_GOT_TLSLD16"},
-	{84, "R_PPC64_GOT_TLSLD16_LO"},
-	{85, "R_PPC64_GOT_TLSLD16_HI"},
-	{86, "R_PPC64_GOT_TLSLD16_HA"},
-	{87, "R_PPC64_GOT_TPREL16_DS"},
-	{88, "R_PPC64_GOT_TPREL16_LO_DS"},
-	{89, "R_PPC64_GOT_TPREL16_HI"},
-	{90, "R_PPC64_GOT_TPREL16_HA"},
-	{91, "R_PPC64_GOT_DTPREL16_DS"},
-	{92, "R_PPC64_GOT_DTPREL16_LO_DS"},
-	{93, "R_PPC64_GOT_DTPREL16_HI"},
-	{94, "R_PPC64_GOT_DTPREL16_HA"},
-	{95, "R_PPC64_TPREL16_DS"},
-	{96, "R_PPC64_TPREL16_LO_DS"},
-	{97, "R_PPC64_TPREL16_HIGHER"},
-	{98, "R_PPC64_TPREL16_HIGHERA"},
-	{99, "R_PPC64_TPREL16_HIGHEST"},
-	{100, "R_PPC64_TPREL16_HIGHESTA"},
-	{101, "R_PPC64_DTPREL16_DS"},
-	{102, "R_PPC64_DTPREL16_LO_DS"},
-	{103, "R_PPC64_DTPREL16_HIGHER"},
-	{104, "R_PPC64_DTPREL16_HIGHERA"},
-	{105, "R_PPC64_DTPREL16_HIGHEST"},
-	{106, "R_PPC64_DTPREL16_HIGHESTA"},
-	{107, "R_PPC64_TLSGD"},
-	{108, "R_PPC64_TLSLD"},
-	{249, "R_PPC64_REL16"},
-	{250, "R_PPC64_REL16_LO"},
-	{251, "R_PPC64_REL16_HI"},
-	{252, "R_PPC64_REL16_HA"},
-}
-
-func (i R_PPC64) String() string   { return stringName(uint32(i), rppc64Strings, false) }
-func (i R_PPC64) GoString() string { return stringName(uint32(i), rppc64Strings, true) }
-
 // Relocation types for SPARC.
 type R_SPARC int
 
diff --git a/src/debug/elf/file.go b/src/debug/elf/file.go
index 4062543..de8a3a2 100644
--- a/src/debug/elf/file.go
+++ b/src/debug/elf/file.go
@@ -13,7 +13,6 @@ import (
 	"fmt"
 	"io"
 	"os"
-	"strings"
 )
 
 // TODO: error reporting detail
@@ -524,22 +523,17 @@ func (f *File) Section(name string) *Section {
 // applyRelocations applies relocations to dst. rels is a relocations section
 // in RELA format.
 func (f *File) applyRelocations(dst []byte, rels []byte) error {
-	switch {
-	case f.Class == ELFCLASS64 && f.Machine == EM_X86_64:
+	if f.Class == ELFCLASS64 && f.Machine == EM_X86_64 {
 		return f.applyRelocationsAMD64(dst, rels)
-	case f.Class == ELFCLASS32 && f.Machine == EM_386:
+	}
+	if f.Class == ELFCLASS32 && f.Machine == EM_386 {
 		return f.applyRelocations386(dst, rels)
-	case f.Class == ELFCLASS32 && f.Machine == EM_ARM:
-		return f.applyRelocationsARM(dst, rels)
-	case f.Class == ELFCLASS64 && f.Machine == EM_AARCH64:
+	}
+	if f.Class == ELFCLASS64 && f.Machine == EM_AARCH64 {
 		return f.applyRelocationsARM64(dst, rels)
-	case f.Class == ELFCLASS32 && f.Machine == EM_PPC:
-		return f.applyRelocationsPPC(dst, rels)
-	case f.Class == ELFCLASS64 && f.Machine == EM_PPC64:
-		return f.applyRelocationsPPC64(dst, rels)
-	default:
-		return errors.New("applyRelocations: not implemented")
 	}
+
+	return errors.New("not implemented")
 }
 
 func (f *File) applyRelocationsAMD64(dst []byte, rels []byte) error {
@@ -628,44 +622,6 @@ func (f *File) applyRelocations386(dst []byte, rels []byte) error {
 	return nil
 }
 
-func (f *File) applyRelocationsARM(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_ARM(rel.Info & 0xff)
-
-		if symNo == 0 || symNo > uint32(len(symbols)) {
-			continue
-		}
-		sym := &symbols[symNo-1]
-
-		switch t {
-		case R_ARM_ABS32:
-			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) applyRelocationsARM64(dst []byte, rels []byte) error {
 	// 24 is the size of Rela64.
 	if len(rels)%24 != 0 {
@@ -715,138 +671,54 @@ func (f *File) applyRelocationsARM64(dst []byte, rels []byte) error {
 	return nil
 }
 
-func (f *File) applyRelocationsPPC(dst []byte, rels []byte) error {
-	// 12 is the size of Rela32.
-	if len(rels)%12 != 0 {
-		return errors.New("length of relocation section is not a multiple of 12")
-	}
-
-	symbols, _, err := f.getSymbols(SHT_SYMTAB)
-	if err != nil {
-		return err
-	}
-
-	b := bytes.NewReader(rels)
-	var rela Rela32
-
-	for b.Len() > 0 {
-		binary.Read(b, f.ByteOrder, &rela)
-		symNo := rela.Info >> 8
-		t := R_PPC(rela.Info & 0xff)
-
-		if symNo == 0 || symNo > uint32(len(symbols)) {
-			continue
-		}
-		sym := &symbols[symNo-1]
-		if SymType(sym.Info&0xf) != STT_SECTION {
-			// We don't handle non-section relocations for now.
-			continue
-		}
-
-		switch t {
-		case R_PPC_ADDR32:
-			if rela.Off+4 >= uint32(len(dst)) || rela.Addend < 0 {
-				continue
-			}
-			f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend))
-		}
-	}
-
-	return nil
-}
-
-func (f *File) applyRelocationsPPC64(dst []byte, rels []byte) error {
-	// 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)
-	if err != nil {
-		return err
-	}
-
-	b := bytes.NewReader(rels)
-	var rela Rela64
-
-	for b.Len() > 0 {
-		binary.Read(b, f.ByteOrder, &rela)
-		symNo := rela.Info >> 32
-		t := R_PPC64(rela.Info & 0xffff)
-
-		if symNo == 0 || symNo > uint64(len(symbols)) {
-			continue
-		}
-		sym := &symbols[symNo-1]
-		if SymType(sym.Info&0xf) != STT_SECTION {
-			// We don't handle non-section relocations for now.
+func (f *File) DWARF() (*dwarf.Data, error) {
+	// There are many other DWARF sections, but these
+	// are the required ones, and the debug/dwarf package
+	// does not use the others, so don't bother loading them.
+	var names = [...]string{"abbrev", "info", "str"}
+	var dat [len(names)][]byte
+	for i, name := range names {
+		name = ".debug_" + name
+		s := f.Section(name)
+		if s == nil {
 			continue
 		}
-
-		switch t {
-		case R_PPC64_ADDR64:
-			if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
-				continue
-			}
-			f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend))
-		case R_PPC64_ADDR32:
-			if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
-				continue
-			}
-			f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend))
-		}
-	}
-
-	return nil
-}
-
-func (f *File) DWARF() (*dwarf.Data, error) {
-	// sectionData gets the data for s, checks its size, and
-	// applies any applicable relations.
-	sectionData := func(i int, s *Section) ([]byte, error) {
 		b, err := s.Data()
 		if err != nil && uint64(len(b)) < s.Size {
 			return nil, err
 		}
+		dat[i] = b
+	}
 
-		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
-			}
+	// If there's a relocation table for .debug_info, we have to process it
+	// now otherwise the data in .debug_info is invalid for x86-64 objects.
+	rela := f.Section(".rela.debug_info")
+	if rela != nil && rela.Type == SHT_RELA && (f.Machine == EM_X86_64 || f.Machine == EM_AARCH64) {
+		data, err := rela.Data()
+		if err != nil {
+			return nil, err
+		}
+		err = f.applyRelocations(dat[1], data)
+		if err != nil {
+			return nil, err
 		}
-		return b, nil
 	}
 
-	// There are many other DWARF sections, but these
-	// are the ones the debug/dwarf package uses.
-	// Don't bother loading others.
-	var dat = map[string][]byte{"abbrev": nil, "info": nil, "str": nil, "line": nil}
-	for i, s := range f.Sections {
-		if !strings.HasPrefix(s.Name, ".debug_") {
-			continue
-		}
-		if _, ok := dat[s.Name[7:]]; !ok {
-			continue
+	// 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
 		}
-		b, err := sectionData(i, s)
+		err = f.applyRelocations(dat[1], data)
 		if err != nil {
 			return nil, err
 		}
-		dat[s.Name[7:]] = b
 	}
 
-	d, err := dwarf.New(dat["abbrev"], nil, nil, dat["info"], dat["line"], nil, nil, dat["str"])
+	abbrev, info, str := dat[0], dat[1], dat[2]
+	d, err := dwarf.New(abbrev, nil, nil, info, nil, nil, nil, str)
 	if err != nil {
 		return nil, err
 	}
@@ -854,11 +726,28 @@ func (f *File) DWARF() (*dwarf.Data, error) {
 	// Look for DWARF4 .debug_types sections.
 	for i, s := range f.Sections {
 		if s.Name == ".debug_types" {
-			b, err := sectionData(i, s)
-			if err != nil {
+			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
diff --git a/src/debug/elf/file_test.go b/src/debug/elf/file_test.go
index 1ad4314..5e5ba52 100644
--- a/src/debug/elf/file_test.go
+++ b/src/debug/elf/file_test.go
@@ -245,62 +245,38 @@ var relocationTests = []relocationTest{
 	{
 		"testdata/go-relocation-test-gcc441-x86-64.obj",
 		[]relocationTestEntry{
-			{0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.4.1", Class: dwarf.ClassString}, {Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant}, {Attr: dwarf.AttrName, Val: "go-relocation-test.c", Class: dwarf.ClassString}, {Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress}, {Attr: dwarf.AttrHighpc, Val: uint6 [...]
+			{0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.4.1"}, {Attr: dwarf.AttrLanguage, Val: int64(1)}, {Attr: dwarf.AttrName, Val: "go-relocation-test.c"}, {Attr: dwarf.AttrCompDir, Val: "/tmp"}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, {Attr: dwarf.AttrHighpc, Val: uint64(0x6)}, {Attr: dwarf.AttrStmtList, Val: int64(0)}}}},
 		},
 	},
 	{
 		"testdata/go-relocation-test-gcc441-x86.obj",
 		[]relocationTestEntry{
-			{0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.4.1", Class: dwarf.ClassString}, {Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant}, {Attr: dwarf.AttrName, Val: "t.c", Class: dwarf.ClassString}, {Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress}, {Attr: dwarf.AttrHighpc, Val: uint64(0x5), Class: dw [...]
+			{0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.4.1"}, {Attr: dwarf.AttrLanguage, Val: int64(1)}, {Attr: dwarf.AttrName, Val: "t.c"}, {Attr: dwarf.AttrCompDir, Val: "/tmp"}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, {Attr: dwarf.AttrHighpc, Val: uint64(0x5)}, {Attr: dwarf.AttrStmtList, Val: int64(0)}}}},
 		},
 	},
 	{
 		"testdata/go-relocation-test-gcc424-x86-64.obj",
 		[]relocationTestEntry{
-			{0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.2.4 (Ubuntu 4.2.4-1ubuntu4)", Class: dwarf.ClassString}, {Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant}, {Attr: dwarf.AttrName, Val: "go-relocation-test-gcc424.c", Class: dwarf.ClassString}, {Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress}, {Att [...]
+			{0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.2.4 (Ubuntu 4.2.4-1ubuntu4)"}, {Attr: dwarf.AttrLanguage, Val: int64(1)}, {Attr: dwarf.AttrName, Val: "go-relocation-test-gcc424.c"}, {Attr: dwarf.AttrCompDir, Val: "/tmp"}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, {Attr: dwarf.AttrHighpc, Val: uint64(0x6)}, {Attr: dwarf.AttrStmtList, Val: int64(0)}}}},
 		},
 	},
 	{
 		"testdata/go-relocation-test-gcc482-aarch64.obj",
 		[]relocationTestEntry{
-			{0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.8.2 -g -fstack-protector", Class: dwarf.ClassString}, {Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant}, {Attr: dwarf.AttrName, Val: "go-relocation-test-gcc482.c", Class: dwarf.ClassString}, {Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress}, {Attr:  [...]
-		},
-	},
-	{
-		"testdata/go-relocation-test-gcc492-arm.obj",
-		[]relocationTestEntry{
-			{0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.9.2 20141224 (prerelease) -march=armv7-a -mfloat-abi=hard -mfpu=vfpv3-d16 -mtls-dialect=gnu -g", Class: dwarf.ClassString}, {Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant}, {Attr: dwarf.AttrName, Val: "go-relocation-test-gcc492.c", Class: dwarf.ClassString}, {Attr: dwarf.AttrCompDir, Val: "/root/go/src/debug/elf/testdata", Class:  [...]
-		},
-	},
-	{
-		"testdata/go-relocation-test-clang-arm.obj",
-		[]relocationTestEntry{
-			{0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{dwarf.Field{Attr: dwarf.AttrProducer, Val: "Debian clang version 3.5.0-10 (tags/RELEASE_350/final) (based on LLVM 3.5.0)", Class: dwarf.ClassString}, dwarf.Field{Attr: dwarf.AttrLanguage, Val: int64(12), Class: dwarf.ClassConstant}, dwarf.Field{Attr: dwarf.AttrName, Val: "hello.c", Class: dwarf.ClassString}, dwarf.Field{Attr: dwarf.AttrStmtList, Val: int64(0x0), Class: dwarf.ClassLinePtr}, dw [...]
-		},
-	},
-	{
-		"testdata/go-relocation-test-gcc5-ppc.obj",
-		[]relocationTestEntry{
-			{0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{dwarf.Field{Attr: dwarf.AttrProducer, Val: "GNU C11 5.0.0 20150116 (experimental) -Asystem=linux -Asystem=unix -Asystem=posix -g", Class: dwarf.ClassString}, dwarf.Field{Attr: dwarf.AttrLanguage, Val: int64(12), Class: dwarf.ClassConstant}, dwarf.Field{Attr: dwarf.AttrName, Val: "go-relocation-test-gcc5-ppc.c", Class: dwarf.ClassString}, dwarf.Field{Attr: dwarf.AttrCompDir, Val: "/tmp", Class [...]
-		},
-	},
-	{
-		"testdata/go-relocation-test-gcc482-ppc64le.obj",
-		[]relocationTestEntry{
-			{0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{dwarf.Field{Attr: dwarf.AttrProducer, Val: "GNU C 4.8.2 -Asystem=linux -Asystem=unix -Asystem=posix -msecure-plt -mtune=power8 -mcpu=power7 -gdwarf-2 -fstack-protector", Class: dwarf.ClassString}, dwarf.Field{Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant}, dwarf.Field{Attr: dwarf.AttrName, Val: "go-relocation-test-gcc482-ppc64le.c", Class: dwarf.ClassString}, dwarf.Field [...]
+			{0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.8.2 -g -fstack-protector"}, {Attr: dwarf.AttrLanguage, Val: int64(1)}, {Attr: dwarf.AttrName, Val: "go-relocation-test-gcc482.c"}, {Attr: dwarf.AttrCompDir, Val: "/tmp"}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, {Attr: dwarf.AttrHighpc, Val: int64(0x24)}, {Attr: dwarf.AttrStmtList, Val: int64(0)}}}},
 		},
 	},
 	{
 		"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)", Class: dwarf.ClassString}, {Attr: dwarf.AttrLanguage, Val: int64(12), Class: dwarf.ClassConstant}, {Attr: dwarf.AttrName, Val: "go-relocation-test-clang.c", Class: dwarf.ClassString}, {Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr}, {Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString}}}},
+			{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", Class: dwarf.ClassString}, {Attr: dwarf.AttrDeclFile, Val: int64(7), Class: dwarf.ClassConstant}, {Attr: dwarf.AttrDeclLine, Val: int64(236), Class: dwarf.ClassConstant}, {Attr: dwarf.AttrType, Val: dwarf.Offset(0xb7f), Class: dwarf.ClassReference}, {Attr: dwarf.AttrDataMemberLoc, Val: []byte{0x23, 0x0}, Class: dwarf.ClassExprLoc}}}},
-			{204, &dwarf.Entry{Offset: 0xc70, Tag: dwarf.TagMember, Children: false, Field: []dwarf.Field{{Attr: dwarf.AttrName, Val: "it_value", Class: dwarf.ClassString}, {Attr: dwarf.AttrDeclFile, Val: int64(7), Class: dwarf.ClassConstant}, {Attr: dwarf.AttrDeclLine, Val: int64(237), Class: dwarf.ClassConstant}, {Attr: dwarf.AttrType, Val: dwarf.Offset(0xb7f), Class: dwarf.ClassReference}, {Attr: dwarf.AttrDataMemberLoc, Val: []byte{0x23, 0x10}, Class: dwarf.ClassExprLoc}}}},
+			{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}}}}},
+			{204, &dwarf.Entry{Offset: 0xc70, Tag: dwarf.TagMember, Children: false, Field: []dwarf.Field{{Attr: dwarf.AttrName, Val: "it_value"}, {Attr: dwarf.AttrDeclFile, Val: int64(7)}, {Attr: dwarf.AttrDeclLine, Val: int64(237)}, {Attr: dwarf.AttrType, Val: dwarf.Offset(0xb7f)}, {Attr: dwarf.AttrDataMemberLoc, Val: []byte{0x23, 0x10}}}}},
 		},
 	},
 }
diff --git a/src/debug/gosym/pclntab_test.go b/src/debug/gosym/pclntab_test.go
index 53f3e95..35502e8 100644
--- a/src/debug/gosym/pclntab_test.go
+++ b/src/debug/gosym/pclntab_test.go
@@ -6,6 +6,7 @@ package gosym
 
 import (
 	"debug/elf"
+	"fmt"
 	"io/ioutil"
 	"os"
 	"os/exec"
@@ -29,6 +30,10 @@ func dotest(self bool) bool {
 	if self && runtime.GOOS != "linux" {
 		return false
 	}
+	// Command below expects "sh", so Unix.
+	if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
+		return false
+	}
 	if pclinetestBinary != "" {
 		return true
 	}
@@ -44,14 +49,9 @@ func dotest(self bool) bool {
 	// the resulting binary looks like it was built from pclinetest.s,
 	// but we have renamed it to keep it away from the go tool.
 	pclinetestBinary = filepath.Join(pclineTempDir, "pclinetest")
-	cmd := exec.Command("go", "tool", "asm", "-o", pclinetestBinary+".o", "pclinetest.asm")
-	cmd.Stdout = os.Stdout
-	cmd.Stderr = os.Stderr
-	if err := cmd.Run(); err != nil {
-		panic(err)
-	}
-	cmd = exec.Command("go", "tool", "link", "-H", "linux", "-E", "main",
-		"-o", pclinetestBinary, pclinetestBinary+".o")
+	command := fmt.Sprintf("go tool 6a -o %s.6 pclinetest.asm && go tool 6l -H linux -E main -o %s %s.6",
+		pclinetestBinary, pclinetestBinary, pclinetestBinary)
+	cmd := exec.Command("sh", "-c", command)
 	cmd.Stdout = os.Stdout
 	cmd.Stderr = os.Stderr
 	if err := cmd.Run(); err != nil {
@@ -84,11 +84,7 @@ func crack(file string, t *testing.T) (*elf.File, *Table) {
 }
 
 func parse(file string, f *elf.File, t *testing.T) (*elf.File, *Table) {
-	s := f.Section(".gosymtab")
-	if s == nil {
-		t.Skip("no .gosymtab section")
-	}
-	symdat, err := s.Data()
+	symdat, err := f.Section(".gosymtab").Data()
 	if err != nil {
 		f.Close()
 		t.Fatalf("reading %s gosymtab: %v", file, err)
diff --git a/src/debug/gosym/symtab.go b/src/debug/gosym/symtab.go
index 46f0783..ee18499 100644
--- a/src/debug/gosym/symtab.go
+++ b/src/debug/gosym/symtab.go
@@ -30,7 +30,7 @@ type Sym struct {
 	Type   byte
 	Name   string
 	GoType uint64
-	// If this symbol is a function symbol, the corresponding Func
+	// If this symbol if a function symbol, the corresponding Func
 	Func *Func
 }
 
diff --git a/src/debug/macho/file.go b/src/debug/macho/file.go
index a7599aa..eefb744 100644
--- a/src/debug/macho/file.go
+++ b/src/debug/macho/file.go
@@ -472,9 +472,9 @@ func (f *File) Section(name string) *Section {
 // DWARF returns the DWARF debug information for the Mach-O file.
 func (f *File) DWARF() (*dwarf.Data, error) {
 	// There are many other DWARF sections, but these
-	// are the ones the debug/dwarf package uses.
-	// Don't bother loading others.
-	var names = [...]string{"abbrev", "info", "line", "str"}
+	// are the required ones, and the debug/dwarf package
+	// does not use the others, so don't bother loading them.
+	var names = [...]string{"abbrev", "info", "str"}
 	var dat [len(names)][]byte
 	for i, name := range names {
 		name = "__debug_" + name
@@ -489,8 +489,8 @@ func (f *File) DWARF() (*dwarf.Data, error) {
 		dat[i] = b
 	}
 
-	abbrev, info, line, str := dat[0], dat[1], dat[2], dat[3]
-	return dwarf.New(abbrev, nil, nil, info, line, nil, nil, str)
+	abbrev, info, str := dat[0], dat[1], dat[2]
+	return dwarf.New(abbrev, nil, nil, info, nil, nil, nil, str)
 }
 
 // ImportedSymbols returns the names of all symbols
diff --git a/src/debug/pe/file.go b/src/debug/pe/file.go
index 3df4ae7..759e567 100644
--- a/src/debug/pe/file.go
+++ b/src/debug/pe/file.go
@@ -296,9 +296,9 @@ func (f *File) Section(name string) *Section {
 
 func (f *File) DWARF() (*dwarf.Data, error) {
 	// There are many other DWARF sections, but these
-	// are the ones the debug/dwarf package uses.
-	// Don't bother loading others.
-	var names = [...]string{"abbrev", "info", "line", "str"}
+	// are the required ones, and the debug/dwarf package
+	// does not use the others, so don't bother loading them.
+	var names = [...]string{"abbrev", "info", "str"}
 	var dat [len(names)][]byte
 	for i, name := range names {
 		name = ".debug_" + name
@@ -310,14 +310,11 @@ func (f *File) DWARF() (*dwarf.Data, error) {
 		if err != nil && uint32(len(b)) < s.Size {
 			return nil, err
 		}
-		if 0 < s.VirtualSize && s.VirtualSize < s.Size {
-			b = b[:s.VirtualSize]
-		}
 		dat[i] = b
 	}
 
-	abbrev, info, line, str := dat[0], dat[1], dat[2], dat[3]
-	return dwarf.New(abbrev, nil, nil, info, line, nil, nil, str)
+	abbrev, info, str := dat[0], dat[1], dat[2]
+	return dwarf.New(abbrev, nil, nil, info, nil, nil, nil, str)
 }
 
 // ImportedSymbols returns the names of all symbols
diff --git a/src/debug/pe/file_test.go b/src/debug/pe/file_test.go
index 316a569..0d73969 100644
--- a/src/debug/pe/file_test.go
+++ b/src/debug/pe/file_test.go
@@ -5,30 +5,24 @@
 package pe
 
 import (
-	"debug/dwarf"
-	"io/ioutil"
-	"os"
-	"os/exec"
-	"path/filepath"
 	"reflect"
-	"runtime"
 	"testing"
 )
 
 type fileTest struct {
-	file           string
-	hdr            FileHeader
-	opthdr         interface{}
-	sections       []*SectionHeader
-	symbols        []*Symbol
-	hasNoDwarfInfo bool
+	file     string
+	hdr      FileHeader
+	opthdr   interface{}
+	sections []*SectionHeader
+	symbols  []*Symbol
 }
 
 var fileTests = []fileTest{
 	{
-		file: "testdata/gcc-386-mingw-obj",
-		hdr:  FileHeader{0x014c, 0x000c, 0x0, 0x64a, 0x1e, 0x0, 0x104},
-		sections: []*SectionHeader{
+		"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},
 			{".bss", 0, 0, 0, 0, 0, 0, 0, 0, 3224371328},
@@ -42,7 +36,7 @@ var fileTests = []fileTest{
 			{".debug_pubtypes", 0, 0, 38, 1370, 1580, 0, 1, 0, 1108344832},
 			{".debug_aranges", 0, 0, 32, 1408, 1590, 0, 2, 0, 1108344832},
 		},
-		symbols: []*Symbol{
+		[]*Symbol{
 			{".file", 0x0, -2, 0x0, 0x67},
 			{"_main", 0x0, 1, 0x20, 0x2},
 			{".text", 0x0, 1, 0x0, 0x3},
@@ -62,9 +56,9 @@ var fileTests = []fileTest{
 		},
 	},
 	{
-		file: "testdata/gcc-386-mingw-exec",
-		hdr:  FileHeader{0x014c, 0x000f, 0x4c6a1b60, 0x3c00, 0x282, 0xe0, 0x107},
-		opthdr: &OptionalHeader32{
+		"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},
@@ -85,7 +79,7 @@ var fileTests = []fileTest{
 				{0x0, 0x0},
 			},
 		},
-		sections: []*SectionHeader{
+		[]*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},
@@ -102,11 +96,13 @@ var fileTests = []fileTest{
 			{".debug_frame", 0x34, 0xe000, 0x200, 0x3800, 0x0, 0x0, 0x0, 0x0, 0x42300000},
 			{".debug_loc", 0x38, 0xf000, 0x200, 0x3a00, 0x0, 0x0, 0x0, 0x0, 0x42100000},
 		},
+		[]*Symbol{},
 	},
 	{
-		file: "testdata/gcc-amd64-mingw-obj",
-		hdr:  FileHeader{0x8664, 0x6, 0x0, 0x198, 0x12, 0x0, 0x4},
-		sections: []*SectionHeader{
+		"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},
@@ -114,7 +110,7 @@ var fileTests = []fileTest{
 			{".xdata", 0x0, 0x0, 0xc, 0x144, 0x0, 0x0, 0x0, 0x0, 0x40300040},
 			{".pdata", 0x0, 0x0, 0xc, 0x150, 0x17a, 0x0, 0x3, 0x0, 0x40300040},
 		},
-		symbols: []*Symbol{
+		[]*Symbol{
 			{".file", 0x0, -2, 0x0, 0x67},
 			{"main", 0x0, 1, 0x20, 0x2},
 			{".text", 0x0, 1, 0x0, 0x3},
@@ -126,12 +122,11 @@ var fileTests = []fileTest{
 			{"__main", 0x0, 0, 0x20, 0x2},
 			{"puts", 0x0, 0, 0x20, 0x2},
 		},
-		hasNoDwarfInfo: true,
 	},
 	{
-		file: "testdata/gcc-amd64-mingw-exec",
-		hdr:  FileHeader{0x8664, 0x11, 0x53e4364f, 0x39600, 0x6fc, 0xf0, 0x27},
-		opthdr: &OptionalHeader64{
+		"testdata/gcc-amd64-mingw-exec",
+		FileHeader{0x8664, 0x11, 0x53e4364f, 0x39600, 0x6fc, 0xf0, 0x27},
+		&OptionalHeader64{
 			0x20b, 0x2, 0x16, 0x6a00, 0x2400, 0x1600, 0x14e0, 0x1000, 0x400000, 0x1000, 0x200, 0x4, 0x0, 0x0, 0x0, 0x5, 0x2, 0x0, 0x45000, 0x600, 0x46f19, 0x3, 0x0, 0x200000, 0x1000, 0x100000, 0x1000, 0x0, 0x10,
 			[16]DataDirectory{
 				{0x0, 0x0},
@@ -151,7 +146,7 @@ var fileTests = []fileTest{
 				{0x0, 0x0},
 				{0x0, 0x0},
 			}},
-		sections: []*SectionHeader{
+		[]*SectionHeader{
 			{".text", 0x6860, 0x1000, 0x6a00, 0x600, 0x0, 0x0, 0x0, 0x0, 0x60500020},
 			{".data", 0xe0, 0x8000, 0x200, 0x7000, 0x0, 0x0, 0x0, 0x0, 0xc0500040},
 			{".rdata", 0x6b0, 0x9000, 0x800, 0x7200, 0x0, 0x0, 0x0, 0x0, 0x40600040},
@@ -170,6 +165,7 @@ var fileTests = []fileTest{
 			{".debug_loc", 0x13240, 0x30000, 0x13400, 0x25600, 0x0, 0x0, 0x0, 0x0, 0x42100040},
 			{".debug_ranges", 0xa70, 0x44000, 0xc00, 0x38a00, 0x0, 0x0, 0x0, 0x0, 0x42100040},
 		},
+		[]*Symbol{},
 	},
 }
 
@@ -235,12 +231,6 @@ func TestOpen(t *testing.T) {
 				t.Errorf("open %s, symbol %d:\n\thave %#v\n\twant %#v\n", tt.file, i, have, want)
 			}
 		}
-		if !tt.hasNoDwarfInfo {
-			_, err = f.DWARF()
-			if err != nil {
-				t.Errorf("fetching %s dwarf details failed: %v", tt.file, err)
-			}
-		}
 	}
 }
 
@@ -251,59 +241,3 @@ func TestOpenFailure(t *testing.T) {
 		t.Errorf("open %s: succeeded unexpectedly", filename)
 	}
 }
-
-func TestDWARF(t *testing.T) {
-	if runtime.GOOS != "windows" {
-		t.Skip("skipping windows only test")
-	}
-
-	tmpdir, err := ioutil.TempDir("", "TestDWARF")
-	if err != nil {
-		t.Fatal("TempDir failed: ", err)
-	}
-	defer os.RemoveAll(tmpdir)
-
-	prog := `
-package main
-func main() {
-}
-`
-	src := filepath.Join(tmpdir, "a.go")
-	exe := filepath.Join(tmpdir, "a.exe")
-	err = ioutil.WriteFile(src, []byte(prog), 0644)
-	output, err := exec.Command("go", "build", "-o", exe, src).CombinedOutput()
-	if err != nil {
-		t.Fatalf("building test executable failed: %s %s", err, output)
-	}
-
-	f, err := Open(exe)
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer f.Close()
-
-	d, err := f.DWARF()
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	// look for main.main
-	r := d.Reader()
-	for {
-		e, err := r.Next()
-		if err != nil {
-			t.Fatal("r.Next:", err)
-		}
-		if e == nil {
-			break
-		}
-		if e.Tag == dwarf.TagSubprogram {
-			for _, f := range e.Field {
-				if f.Attr == dwarf.AttrName && e.Val(dwarf.AttrName) == "main.main" {
-					return
-				}
-			}
-		}
-	}
-	t.Fatal("main.main not found")
-}
diff --git a/src/encoding/asn1/asn1.go b/src/encoding/asn1/asn1.go
index 2ac411a..8b3d1b3 100644
--- a/src/encoding/asn1/asn1.go
+++ b/src/encoding/asn1/asn1.go
@@ -20,13 +20,11 @@ package asn1
 // everything by any means.
 
 import (
-	"errors"
 	"fmt"
 	"math/big"
 	"reflect"
 	"strconv"
 	"time"
-	"unicode/utf8"
 )
 
 // A StructuralError suggests that the ASN.1 data is valid, but the Go type
@@ -289,23 +287,11 @@ func parseBase128Int(bytes []byte, initOffset int) (ret, offset int, err error)
 
 func parseUTCTime(bytes []byte) (ret time.Time, err error) {
 	s := string(bytes)
-
-	formatStr := "0601021504Z0700"
-	ret, err = time.Parse(formatStr, s)
-	if err != nil {
-		formatStr = "060102150405Z0700"
-		ret, err = time.Parse(formatStr, s)
-	}
+	ret, err = time.Parse("0601021504Z0700", s)
 	if err != nil {
-		return
+		ret, err = time.Parse("060102150405Z0700", s)
 	}
-
-	if serialized := ret.Format(formatStr); serialized != s {
-		err = fmt.Errorf("asn1: time did not serialize back to the original value and may be invalid: given %q, but serialized as %q", s, serialized)
-		return
-	}
-
-	if ret.Year() >= 2050 {
+	if err == nil && ret.Year() >= 2050 {
 		// UTCTime only encodes times prior to 2050. See https://tools.ietf.org/html/rfc5280#section-4.1.2.5.1
 		ret = ret.AddDate(-100, 0, 0)
 	}
@@ -316,18 +302,7 @@ func parseUTCTime(bytes []byte) (ret time.Time, err error) {
 // parseGeneralizedTime parses the GeneralizedTime from the given byte slice
 // and returns the resulting time.
 func parseGeneralizedTime(bytes []byte) (ret time.Time, err error) {
-	const formatStr = "20060102150405Z0700"
-	s := string(bytes)
-
-	if ret, err = time.Parse(formatStr, s); err != nil {
-		return
-	}
-
-	if serialized := ret.Format(formatStr); serialized != s {
-		err = fmt.Errorf("asn1: time did not serialize back to the original value and may be invalid: given %q, but serialized as %q", s, serialized)
-	}
-
-	return
+	return time.Parse("20060102150405Z0700", string(bytes))
 }
 
 // PrintableString
@@ -345,7 +320,7 @@ func parsePrintableString(bytes []byte) (ret string, err error) {
 	return
 }
 
-// isPrintable reports whether the given b is in the ASN.1 PrintableString set.
+// isPrintable returns true iff the given b is in the ASN.1 PrintableString set.
 func isPrintable(b byte) bool {
 	return 'a' <= b && b <= 'z' ||
 		'A' <= b && b <= 'Z' ||
@@ -390,9 +365,6 @@ func parseT61String(bytes []byte) (ret string, err error) {
 // parseUTF8String parses a ASN.1 UTF8String (raw UTF-8) from the given byte
 // array and returns it.
 func parseUTF8String(bytes []byte) (ret string, err error) {
-	if !utf8.Valid(bytes) {
-		return "", errors.New("asn1: invalid UTF-8 string")
-	}
 	return string(bytes), nil
 }
 
@@ -417,12 +389,6 @@ type RawContent []byte
 // don't distinguish between ordered and unordered objects in this code.
 func parseTagAndLength(bytes []byte, initOffset int) (ret tagAndLength, offset int, err error) {
 	offset = initOffset
-	// parseTagAndLength should not be called without at least a single
-	// byte to read. Thus this check is for robustness:
-	if offset >= len(bytes) {
-		err = errors.New("asn1: internal error in parseTagAndLength")
-		return
-	}
 	b := bytes[offset]
 	offset++
 	ret.class = int(b >> 6)
@@ -613,8 +579,6 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
 				result, err = parseObjectIdentifier(innerBytes)
 			case tagUTCTime:
 				result, err = parseUTCTime(innerBytes)
-			case tagGeneralizedTime:
-				result, err = parseGeneralizedTime(innerBytes)
 			case tagOctetString:
 				result = innerBytes
 			default:
@@ -645,10 +609,6 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
 		if params.application {
 			expectedClass = classApplication
 		}
-		if offset == len(bytes) {
-			err = StructuralError{"explicit tag has no child"}
-			return
-		}
 		if t.class == expectedClass && t.tag == *params.tag && (t.length == 0 || t.isCompound) {
 			if t.length > 0 {
 				t, offset, err = parseTagAndLength(bytes, offset)
diff --git a/src/encoding/asn1/asn1_test.go b/src/encoding/asn1/asn1_test.go
index 893d080..4e864d0 100644
--- a/src/encoding/asn1/asn1_test.go
+++ b/src/encoding/asn1/asn1_test.go
@@ -9,7 +9,6 @@ import (
 	"fmt"
 	"math/big"
 	"reflect"
-	"strings"
 	"testing"
 	"time"
 )
@@ -259,24 +258,6 @@ var utcTestData = []timeTest{
 	{"91050633444aZ", false, time.Time{}},
 	{"910506334461Z", false, time.Time{}},
 	{"910506334400Za", false, time.Time{}},
-	/* These are invalid times. However, the time package normalises times
-	 * and they were accepted in some versions. See #11134. */
-	{"000100000000Z", false, time.Time{}},
-	{"101302030405Z", false, time.Time{}},
-	{"100002030405Z", false, time.Time{}},
-	{"100100030405Z", false, time.Time{}},
-	{"100132030405Z", false, time.Time{}},
-	{"100231030405Z", false, time.Time{}},
-	{"100102240405Z", false, time.Time{}},
-	{"100102036005Z", false, time.Time{}},
-	{"100102030460Z", false, time.Time{}},
-	{"-100102030410Z", false, time.Time{}},
-	{"10-0102030410Z", false, time.Time{}},
-	{"10-0002030410Z", false, time.Time{}},
-	{"1001-02030410Z", false, time.Time{}},
-	{"100102-030410Z", false, time.Time{}},
-	{"10010203-0410Z", false, time.Time{}},
-	{"1001020304-10Z", false, time.Time{}},
 }
 
 func TestUTCTime(t *testing.T) {
@@ -306,24 +287,6 @@ var generalizedTimeTestData = []timeTest{
 	{"20100102030405", false, time.Time{}},
 	{"20100102030405+0607", true, time.Date(2010, 01, 02, 03, 04, 05, 0, time.FixedZone("", 6*60*60+7*60))},
 	{"20100102030405-0607", true, time.Date(2010, 01, 02, 03, 04, 05, 0, time.FixedZone("", -6*60*60-7*60))},
-	/* These are invalid times. However, the time package normalises times
-	 * and they were accepted in some versions. See #11134. */
-	{"00000100000000Z", false, time.Time{}},
-	{"20101302030405Z", false, time.Time{}},
-	{"20100002030405Z", false, time.Time{}},
-	{"20100100030405Z", false, time.Time{}},
-	{"20100132030405Z", false, time.Time{}},
-	{"20100231030405Z", false, time.Time{}},
-	{"20100102240405Z", false, time.Time{}},
-	{"20100102036005Z", false, time.Time{}},
-	{"20100102030460Z", false, time.Time{}},
-	{"-20100102030410Z", false, time.Time{}},
-	{"2010-0102030410Z", false, time.Time{}},
-	{"2010-0002030410Z", false, time.Time{}},
-	{"201001-02030410Z", false, time.Time{}},
-	{"20100102-030410Z", false, time.Time{}},
-	{"2010010203-0410Z", false, time.Time{}},
-	{"201001020304-10Z", false, time.Time{}},
 }
 
 func TestGeneralizedTime(t *testing.T) {
@@ -334,7 +297,7 @@ func TestGeneralizedTime(t *testing.T) {
 		}
 		if err == nil {
 			if !reflect.DeepEqual(test.out, ret) {
-				t.Errorf("#%d: Bad result: %q → %v (expected %v)", i, test.in, ret, test.out)
+				t.Errorf("#%d: Bad result: %v (expected %v)", i, ret, test.out)
 			}
 		}
 	}
@@ -395,8 +358,6 @@ func newBool(b bool) *bool { return &b }
 var parseFieldParametersTestData []parseFieldParametersTest = []parseFieldParametersTest{
 	{"", fieldParameters{}},
 	{"ia5", fieldParameters{stringType: tagIA5String}},
-	{"generalized", fieldParameters{timeType: tagGeneralizedTime}},
-	{"utc", fieldParameters{timeType: tagUTCTime}},
 	{"printable", fieldParameters{stringType: tagPrintableString}},
 	{"optional", fieldParameters{optional: true}},
 	{"explicit", fieldParameters{explicit: true, tag: new(int)}},
@@ -405,7 +366,7 @@ var parseFieldParametersTestData []parseFieldParametersTest = []parseFieldParame
 	{"default:42", fieldParameters{defaultValue: newInt64(42)}},
 	{"tag:17", fieldParameters{tag: newInt(17)}},
 	{"optional,explicit,default:42,tag:17", fieldParameters{optional: true, explicit: true, defaultValue: newInt64(42), tag: newInt(17)}},
-	{"optional,explicit,default:42,tag:17,rubbish1", fieldParameters{true, true, false, newInt64(42), newInt(17), 0, 0, false, false}},
+	{"optional,explicit,default:42,tag:17,rubbish1", fieldParameters{true, true, false, newInt64(42), newInt(17), 0, false, false}},
 	{"set", fieldParameters{set: true}},
 }
 
@@ -904,39 +865,3 @@ func TestImplicitTaggedTime(t *testing.T) {
 		t.Errorf("Wrong result. Got %v, want %v", result.Time, expected)
 	}
 }
-
-type truncatedExplicitTagTest struct {
-	Test int `asn1:"explicit,tag:0"`
-}
-
-func TestTruncatedExplicitTag(t *testing.T) {
-	// This crashed Unmarshal in the past. See #11154.
-	der := []byte{
-		0x30, // SEQUENCE
-		0x02, // two bytes long
-		0xa0, // context-specific, tag 0
-		0x30, // 48 bytes long
-	}
-
-	var result truncatedExplicitTagTest
-	if _, err := Unmarshal(der, &result); err == nil {
-		t.Error("Unmarshal returned without error")
-	}
-}
-
-type invalidUTF8Test struct {
-	Str string `asn1:"utf8"`
-}
-
-func TestUnmarshalInvalidUTF8(t *testing.T) {
-	data := []byte("0\x05\f\x03a\xc9c")
-	var result invalidUTF8Test
-	_, err := Unmarshal(data, &result)
-
-	const expectedSubstring = "UTF"
-	if err == nil {
-		t.Fatal("Successfully unmarshaled invalid UTF-8 data")
-	} else if !strings.Contains(err.Error(), expectedSubstring) {
-		t.Fatalf("Expected error to mention %q but error was %q", expectedSubstring, err.Error())
-	}
-}
diff --git a/src/encoding/asn1/common.go b/src/encoding/asn1/common.go
index ab85e04..33a117e 100644
--- a/src/encoding/asn1/common.go
+++ b/src/encoding/asn1/common.go
@@ -74,7 +74,6 @@ type fieldParameters struct {
 	defaultValue *int64 // a default value for INTEGER typed fields (maybe nil).
 	tag          *int   // the EXPLICIT or IMPLICIT tag (maybe nil).
 	stringType   int    // the string tag to use when marshaling.
-	timeType     int    // the time tag to use when marshaling.
 	set          bool   // true iff this should be encoded as a SET
 	omitEmpty    bool   // true iff this should be omitted if empty when marshaling.
 
@@ -95,10 +94,6 @@ func parseFieldParameters(str string) (ret fieldParameters) {
 			if ret.tag == nil {
 				ret.tag = new(int)
 			}
-		case part == "generalized":
-			ret.timeType = tagGeneralizedTime
-		case part == "utc":
-			ret.timeType = tagUTCTime
 		case part == "ia5":
 			ret.stringType = tagIA5String
 		case part == "printable":
diff --git a/src/encoding/asn1/marshal.go b/src/encoding/asn1/marshal.go
index 67a019d..b2f104b 100644
--- a/src/encoding/asn1/marshal.go
+++ b/src/encoding/asn1/marshal.go
@@ -18,7 +18,7 @@ import (
 // A forkableWriter is an in-memory buffer that can be
 // 'forked' to create new forkableWriters that bracket the
 // original.  After
-//    pre, post := w.fork()
+//    pre, post := w.fork();
 // the overall sequence of bytes represented is logically w+pre+post.
 type forkableWriter struct {
 	*bytes.Buffer
@@ -410,11 +410,9 @@ func stripTagAndLength(in []byte) []byte {
 
 func marshalBody(out *forkableWriter, value reflect.Value, params fieldParameters) (err error) {
 	switch value.Type() {
-	case flagType:
-		return nil
 	case timeType:
 		t := value.Interface().(time.Time)
-		if params.timeType == tagGeneralizedTime || outsideUTCRange(t) {
+		if outsideUTCRange(t) {
 			return marshalGeneralizedTime(out, t)
 		} else {
 			return marshalUTCTime(out, t)
@@ -554,10 +552,6 @@ func marshalField(out *forkableWriter, v reflect.Value, params fieldParameters)
 	}
 	class := classUniversal
 
-	if params.timeType != 0 && tag != tagUTCTime {
-		return StructuralError{"explicit time type given to non-time member"}
-	}
-
 	if params.stringType != 0 && tag != tagPrintableString {
 		return StructuralError{"explicit string type given to non-string member"}
 	}
@@ -581,7 +575,7 @@ func marshalField(out *forkableWriter, v reflect.Value, params fieldParameters)
 			tag = params.stringType
 		}
 	case tagUTCTime:
-		if params.timeType == tagGeneralizedTime || outsideUTCRange(v.Interface().(time.Time)) {
+		if outsideUTCRange(v.Interface().(time.Time)) {
 			tag = tagGeneralizedTime
 		}
 	}
diff --git a/src/encoding/asn1/marshal_test.go b/src/encoding/asn1/marshal_test.go
index cdca8aa..5b0115f 100644
--- a/src/encoding/asn1/marshal_test.go
+++ b/src/encoding/asn1/marshal_test.go
@@ -42,14 +42,6 @@ type explicitTagTest struct {
 	A int `asn1:"explicit,tag:5"`
 }
 
-type flagTest struct {
-	A Flag `asn1:"tag:0,optional"`
-}
-
-type generalizedTimeTest struct {
-	A time.Time `asn1:"generalized"`
-}
-
 type ia5StringTest struct {
 	A string `asn1:"ia5"`
 }
@@ -100,13 +92,10 @@ var marshalTests = []marshalTest{
 	{[]byte{1, 2, 3}, "0403010203"},
 	{implicitTagTest{64}, "3003850140"},
 	{explicitTagTest{64}, "3005a503020140"},
-	{flagTest{true}, "30028000"},
-	{flagTest{false}, "3000"},
 	{time.Unix(0, 0).UTC(), "170d3730303130313030303030305a"},
 	{time.Unix(1258325776, 0).UTC(), "170d3039313131353232353631365a"},
 	{time.Unix(1258325776, 0).In(PST), "17113039313131353134353631362d30383030"},
 	{farFuture(), "180f32313030303430353132303130315a"},
-	{generalizedTimeTest{time.Unix(1258325776, 0).UTC()}, "3011180f32303039313131353232353631365a"},
 	{BitString{[]byte{0x80}, 1}, "03020780"},
 	{BitString{[]byte{0x81, 0xf0}, 12}, "03030481f0"},
 	{ObjectIdentifier([]int{1, 2, 3, 4}), "06032a0304"},
diff --git a/src/encoding/base64/base64.go b/src/encoding/base64/base64.go
index 3302fb4..ad3abe6 100644
--- a/src/encoding/base64/base64.go
+++ b/src/encoding/base64/base64.go
@@ -6,8 +6,10 @@
 package base64
 
 import (
+	"bytes"
 	"io"
 	"strconv"
+	"strings"
 )
 
 /*
@@ -20,32 +22,18 @@ import (
 // (RFC 1421).  RFC 4648 also defines an alternate encoding, which is
 // the standard encoding with - and _ substituted for + and /.
 type Encoding struct {
-	encode    [64]byte
+	encode    string
 	decodeMap [256]byte
-	padChar   rune
 }
 
-const (
-	StdPadding rune = '=' // Standard padding character
-	NoPadding  rune = -1  // No padding
-)
-
 const encodeStd = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
 const encodeURL = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"
 
-// NewEncoding returns a new padded Encoding defined by the given alphabet,
+// NewEncoding returns a new Encoding defined by the given alphabet,
 // which must be a 64-byte string.
-// The resulting Encoding uses the default padding character ('='),
-// which may be changed or disabled via WithPadding.
 func NewEncoding(encoder string) *Encoding {
-	if len(encoder) != 64 {
-		panic("encoding alphabet is not 64-bytes long")
-	}
-
 	e := new(Encoding)
-	e.padChar = StdPadding
-	copy(e.encode[:], encoder)
-
+	e.encode = encoder
 	for i := 0; i < len(e.decodeMap); i++ {
 		e.decodeMap[i] = 0xFF
 	}
@@ -55,13 +43,6 @@ func NewEncoding(encoder string) *Encoding {
 	return e
 }
 
-// WithPadding creates a new encoding identical to enc except
-// with a specified padding character, or NoPadding to disable padding.
-func (enc Encoding) WithPadding(padding rune) *Encoding {
-	enc.padChar = padding
-	return &enc
-}
-
 // StdEncoding is the standard base64 encoding, as defined in
 // RFC 4648.
 var StdEncoding = NewEncoding(encodeStd)
@@ -70,15 +51,12 @@ var StdEncoding = NewEncoding(encodeStd)
 // It is typically used in URLs and file names.
 var URLEncoding = NewEncoding(encodeURL)
 
-// RawStdEncoding is the standard raw, unpadded base64 encoding,
-// as defined in RFC 4648 section 3.2.
-// This is the same as StdEncoding but omits padding characters.
-var RawStdEncoding = StdEncoding.WithPadding(NoPadding)
-
-// URLEncoding is the unpadded alternate base64 encoding defined in RFC 4648.
-// It is typically used in URLs and file names.
-// This is the same as URLEncoding but omits padding characters.
-var RawURLEncoding = URLEncoding.WithPadding(NoPadding)
+var removeNewlinesMapper = func(r rune) rune {
+	if r == '\r' || r == '\n' {
+		return -1
+	}
+	return r
+}
 
 /*
  * Encoder
@@ -95,45 +73,42 @@ func (enc *Encoding) Encode(dst, src []byte) {
 		return
 	}
 
-	di, si := 0, 0
-	n := (len(src) / 3) * 3
-	for si < n {
-		// Convert 3x 8bit source bytes into 4 bytes
-		val := uint(src[si+0])<<16 | uint(src[si+1])<<8 | uint(src[si+2])
-
-		dst[di+0] = enc.encode[val>>18&0x3F]
-		dst[di+1] = enc.encode[val>>12&0x3F]
-		dst[di+2] = enc.encode[val>>6&0x3F]
-		dst[di+3] = enc.encode[val&0x3F]
-
-		si += 3
-		di += 4
-	}
-
-	remain := len(src) - si
-	if remain == 0 {
-		return
-	}
-	// Add the remaining small block
-	val := uint(src[si+0]) << 16
-	if remain == 2 {
-		val |= uint(src[si+1]) << 8
-	}
-
-	dst[di+0] = enc.encode[val>>18&0x3F]
-	dst[di+1] = enc.encode[val>>12&0x3F]
+	for len(src) > 0 {
+		var b0, b1, b2, b3 byte
 
-	switch remain {
-	case 2:
-		dst[di+2] = enc.encode[val>>6&0x3F]
-		if enc.padChar != NoPadding {
-			dst[di+3] = byte(enc.padChar)
+		// Unpack 4x 6-bit source blocks into a 4 byte
+		// destination quantum
+		switch len(src) {
+		default:
+			b3 = src[2] & 0x3F
+			b2 = src[2] >> 6
+			fallthrough
+		case 2:
+			b2 |= (src[1] << 2) & 0x3F
+			b1 = src[1] >> 4
+			fallthrough
+		case 1:
+			b1 |= (src[0] << 4) & 0x3F
+			b0 = src[0] >> 2
 		}
-	case 1:
-		if enc.padChar != NoPadding {
-			dst[di+2] = byte(enc.padChar)
-			dst[di+3] = byte(enc.padChar)
+
+		// Encode 6-bit blocks using the base64 alphabet
+		dst[0] = enc.encode[b0]
+		dst[1] = enc.encode[b1]
+		dst[2] = enc.encode[b2]
+		dst[3] = enc.encode[b3]
+
+		// Pad the final quantum
+		if len(src) < 3 {
+			dst[3] = '='
+			if len(src) < 2 {
+				dst[2] = '='
+			}
+			break
 		}
+
+		src = src[3:]
+		dst = dst[4:]
 	}
 }
 
@@ -170,8 +145,8 @@ func (e *encoder) Write(p []byte) (n int, err error) {
 		if e.nbuf < 3 {
 			return
 		}
-		e.enc.Encode(e.out[:], e.buf[:])
-		if _, e.err = e.w.Write(e.out[:4]); e.err != nil {
+		e.enc.Encode(e.out[0:], e.buf[0:])
+		if _, e.err = e.w.Write(e.out[0:4]); e.err != nil {
 			return n, e.err
 		}
 		e.nbuf = 0
@@ -184,7 +159,7 @@ func (e *encoder) Write(p []byte) (n int, err error) {
 			nn = len(p)
 			nn -= nn % 3
 		}
-		e.enc.Encode(e.out[:], p[:nn])
+		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
 		}
@@ -206,9 +181,9 @@ func (e *encoder) Write(p []byte) (n int, err error) {
 func (e *encoder) Close() error {
 	// If there's anything left in the buffer, flush it out
 	if e.err == nil && e.nbuf > 0 {
-		e.enc.Encode(e.out[:], e.buf[:e.nbuf])
-		_, e.err = e.w.Write(e.out[:e.enc.EncodedLen(e.nbuf)])
+		e.enc.Encode(e.out[0:], e.buf[0:e.nbuf])
 		e.nbuf = 0
+		_, e.err = e.w.Write(e.out[0:4])
 	}
 	return e.err
 }
@@ -224,12 +199,7 @@ func NewEncoder(enc *Encoding, w io.Writer) io.WriteCloser {
 
 // EncodedLen returns the length in bytes of the base64 encoding
 // of an input buffer of length n.
-func (enc *Encoding) EncodedLen(n int) int {
-	if enc.padChar == NoPadding {
-		return (n*8 + 5) / 6 // minimum # chars at 6 bits per char
-	}
-	return (n + 2) / 3 * 4 // minimum # 4-char quanta, 3 bytes each
-}
+func (enc *Encoding) EncodedLen(n int) int { return (n + 2) / 3 * 4 }
 
 /*
  * Decoder
@@ -242,86 +212,66 @@ func (e CorruptInputError) Error() string {
 }
 
 // decode is like Decode but returns an additional 'end' value, which
-// indicates if end-of-message padding or a partial quantum was encountered
-// and thus any additional data is an error.
+// indicates if end-of-message padding was encountered and thus any
+// additional data is an error. This method assumes that src has been
+// stripped of all supported whitespace ('\r' and '\n').
 func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) {
-	si := 0
-
-	// skip over newlines
-	for si < len(src) && (src[si] == '\n' || src[si] == '\r') {
-		si++
-	}
-
-	for si < len(src) && !end {
+	olen := len(src)
+	for len(src) > 0 && !end {
 		// Decode quantum using the base64 alphabet
 		var dbuf [4]byte
-		dinc, dlen := 3, 4
+		dlen := 4
 
 		for j := range dbuf {
-			if len(src) == si {
-				if enc.padChar != NoPadding || j < 2 {
-					return n, false, CorruptInputError(si - j)
-				}
-				dinc, dlen, end = j-1, j, true
-				break
+			if len(src) == 0 {
+				return n, false, CorruptInputError(olen - len(src) - j)
 			}
-			in := src[si]
-
-			si++
-			// skip over newlines
-			for si < len(src) && (src[si] == '\n' || src[si] == '\r') {
-				si++
-			}
-
-			if rune(in) == enc.padChar {
+			in := src[0]
+			src = src[1:]
+			if in == '=' {
 				// We've reached the end and there's padding
 				switch j {
 				case 0, 1:
 					// incorrect padding
-					return n, false, CorruptInputError(si - 1)
+					return n, false, CorruptInputError(olen - len(src) - 1)
 				case 2:
 					// "==" is expected, the first "=" is already consumed.
-					if si == len(src) {
+					if len(src) == 0 {
 						// not enough padding
-						return n, false, CorruptInputError(len(src))
+						return n, false, CorruptInputError(olen)
 					}
-					if rune(src[si]) != enc.padChar {
+					if src[0] != '=' {
 						// incorrect padding
-						return n, false, CorruptInputError(si - 1)
-					}
-
-					si++
-					// skip over newlines
-					for si < len(src) && (src[si] == '\n' || src[si] == '\r') {
-						si++
+						return n, false, CorruptInputError(olen - len(src) - 1)
 					}
+					src = src[1:]
 				}
-				if si < len(src) {
+				if len(src) > 0 {
 					// trailing garbage
-					err = CorruptInputError(si)
+					err = CorruptInputError(olen - len(src))
 				}
-				dinc, dlen, end = 3, j, true
+				dlen, end = j, true
 				break
 			}
 			dbuf[j] = enc.decodeMap[in]
 			if dbuf[j] == 0xFF {
-				return n, false, CorruptInputError(si - 1)
+				return n, false, CorruptInputError(olen - len(src) - 1)
 			}
 		}
 
-		// Convert 4x 6bit source bytes into 3 bytes
-		val := uint(dbuf[0])<<18 | uint(dbuf[1])<<12 | uint(dbuf[2])<<6 | uint(dbuf[3])
+		// Pack 4x 6-bit source blocks into 3 byte destination
+		// quantum
 		switch dlen {
 		case 4:
-			dst[2] = byte(val >> 0)
+			dst[2] = dbuf[2]<<6 | dbuf[3]
 			fallthrough
 		case 3:
-			dst[1] = byte(val >> 8)
+			dst[1] = dbuf[1]<<4 | dbuf[2]>>2
 			fallthrough
 		case 2:
-			dst[0] = byte(val >> 16)
+			dst[0] = dbuf[0]<<2 | dbuf[1]>>4
 		}
-		dst = dst[dinc:]
+		dst = dst[3:]
 		n += dlen - 1
 	}
 
@@ -334,12 +284,14 @@ func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) {
 // number of bytes successfully written and CorruptInputError.
 // New line characters (\r and \n) are ignored.
 func (enc *Encoding) Decode(dst, src []byte) (n int, err error) {
+	src = bytes.Map(removeNewlinesMapper, src)
 	n, _, err = enc.decode(dst, src)
 	return
 }
 
 // DecodeString returns the bytes represented by the base64 string s.
 func (enc *Encoding) DecodeString(s string) ([]byte, error) {
+	s = strings.Map(removeNewlinesMapper, s)
 	dbuf := make([]byte, enc.DecodedLen(len(s)))
 	n, _, err := enc.decode(dbuf, []byte(s))
 	return dbuf[:n], err
@@ -368,8 +320,6 @@ func (d *decoder) Read(p []byte) (n int, err error) {
 		return n, nil
 	}
 
-	// This code assumes that d.r strips supported whitespace ('\r' and '\n').
-
 	// Read a chunk.
 	nn := len(p) / 3 * 4
 	if nn < 4 {
@@ -388,12 +338,12 @@ func (d *decoder) Read(p []byte) (n int, err error) {
 	nr := d.nbuf / 4 * 4
 	nw := d.nbuf / 4 * 3
 	if nw > len(p) {
-		nw, d.end, d.err = d.enc.decode(d.outbuf[:], d.buf[:nr])
-		d.out = d.outbuf[:nw]
+		nw, d.end, d.err = d.enc.decode(d.outbuf[0:], d.buf[0:nr])
+		d.out = d.outbuf[0:nw]
 		n = copy(p, d.out)
 		d.out = d.out[n:]
 	} else {
-		n, d.end, d.err = d.enc.decode(p, d.buf[:nr])
+		n, d.end, d.err = d.enc.decode(p, d.buf[0:nr])
 	}
 	d.nbuf -= nr
 	for i := 0; i < d.nbuf; i++ {
@@ -414,7 +364,7 @@ func (r *newlineFilteringReader) Read(p []byte) (int, error) {
 	n, err := r.wrapped.Read(p)
 	for n > 0 {
 		offset := 0
-		for i, b := range p[:n] {
+		for i, b := range p[0:n] {
 			if b != '\r' && b != '\n' {
 				if i != offset {
 					p[offset] = b
@@ -438,11 +388,4 @@ func NewDecoder(enc *Encoding, r io.Reader) io.Reader {
 
 // DecodedLen returns the maximum length in bytes of the decoded data
 // corresponding to n bytes of base64-encoded data.
-func (enc *Encoding) DecodedLen(n int) int {
-	if enc.padChar == NoPadding {
-		// Unpadded data may end with partial block of 2-3 characters.
-		return (n*6 + 7) / 8
-	}
-	// Padded base64 should always be a multiple of 4 characters in length.
-	return n / 4 * 3
-}
+func (enc *Encoding) DecodedLen(n int) int { return n / 4 * 3 }
diff --git a/src/encoding/base64/base64_test.go b/src/encoding/base64/base64_test.go
index d144b96..7d199bf 100644
--- a/src/encoding/base64/base64_test.go
+++ b/src/encoding/base64/base64_test.go
@@ -45,48 +45,6 @@ var pairs = []testpair{
 	{"sure.", "c3VyZS4="},
 }
 
-// Do nothing to a reference base64 string (leave in standard format)
-func stdRef(ref string) string {
-	return ref
-}
-
-// Convert a reference string to URL-encoding
-func urlRef(ref string) string {
-	ref = strings.Replace(ref, "+", "-", -1)
-	ref = strings.Replace(ref, "/", "_", -1)
-	return ref
-}
-
-// Convert a reference string to raw, unpadded format
-func rawRef(ref string) string {
-	return strings.TrimRight(ref, "=")
-}
-
-// Both URL and unpadding conversions
-func rawUrlRef(ref string) string {
-	return rawRef(urlRef(ref))
-}
-
-// A nonstandard encoding with a funny padding character, for testing
-var funnyEncoding = NewEncoding(encodeStd).WithPadding(rune('@'))
-
-func funnyRef(ref string) string {
-	return strings.Replace(ref, "=", "@", -1)
-}
-
-type encodingTest struct {
-	enc  *Encoding           // Encoding to test
-	conv func(string) string // Reference string converter
-}
-
-var encodingTests = []encodingTest{
-	encodingTest{StdEncoding, stdRef},
-	encodingTest{URLEncoding, urlRef},
-	encodingTest{RawStdEncoding, rawRef},
-	encodingTest{RawURLEncoding, rawUrlRef},
-	encodingTest{funnyEncoding, funnyRef},
-}
-
 var bigtest = testpair{
 	"Twas brillig, and the slithy toves",
 	"VHdhcyBicmlsbGlnLCBhbmQgdGhlIHNsaXRoeSB0b3Zlcw==",
@@ -102,11 +60,8 @@ func testEqual(t *testing.T, msg string, args ...interface{}) bool {
 
 func TestEncode(t *testing.T) {
 	for _, p := range pairs {
-		for _, tt := range encodingTests {
-			got := tt.enc.EncodeToString([]byte(p.decoded))
-			testEqual(t, "Encode(%q) = %q, want %q", p.decoded,
-				got, tt.conv(p.encoded))
-		}
+		got := StdEncoding.EncodeToString([]byte(p.decoded))
+		testEqual(t, "Encode(%q) = %q, want %q", p.decoded, got, p.encoded)
 	}
 }
 
@@ -142,21 +97,18 @@ func TestEncoderBuffering(t *testing.T) {
 
 func TestDecode(t *testing.T) {
 	for _, p := range pairs {
-		for _, tt := range encodingTests {
-			encoded := tt.conv(p.encoded)
-			dbuf := make([]byte, tt.enc.DecodedLen(len(encoded)))
-			count, end, err := tt.enc.decode(dbuf, []byte(encoded))
-			testEqual(t, "Decode(%q) = error %v, want %v", encoded, err, error(nil))
-			testEqual(t, "Decode(%q) = length %v, want %v", encoded, count, len(p.decoded))
-			if len(encoded) > 0 {
-				testEqual(t, "Decode(%q) = end %v, want %v", encoded, end, len(p.decoded)%3 != 0)
-			}
-			testEqual(t, "Decode(%q) = %q, want %q", encoded, string(dbuf[0:count]), p.decoded)
-
-			dbuf, err = tt.enc.DecodeString(encoded)
-			testEqual(t, "DecodeString(%q) = error %v, want %v", encoded, err, error(nil))
-			testEqual(t, "DecodeString(%q) = %q, want %q", string(dbuf), p.decoded)
+		dbuf := make([]byte, StdEncoding.DecodedLen(len(p.encoded)))
+		count, end, err := StdEncoding.decode(dbuf, []byte(p.encoded))
+		testEqual(t, "Decode(%q) = error %v, want %v", p.encoded, err, error(nil))
+		testEqual(t, "Decode(%q) = length %v, want %v", p.encoded, count, len(p.decoded))
+		if len(p.encoded) > 0 {
+			testEqual(t, "Decode(%q) = end %v, want %v", p.encoded, end, (p.encoded[len(p.encoded)-1] == '='))
 		}
+		testEqual(t, "Decode(%q) = %q, want %q", p.encoded, string(dbuf[0:count]), p.decoded)
+
+		dbuf, err = StdEncoding.DecodeString(p.encoded)
+		testEqual(t, "DecodeString(%q) = error %v, want %v", p.encoded, err, error(nil))
+		testEqual(t, "DecodeString(%q) = %q, want %q", string(dbuf), p.decoded)
 	}
 }
 
diff --git a/src/encoding/binary/binary.go b/src/encoding/binary/binary.go
index 2bbe07c..466bf97 100644
--- a/src/encoding/binary/binary.go
+++ b/src/encoding/binary/binary.go
@@ -13,7 +13,7 @@
 // The varint functions encode and decode single integer values using
 // a variable-length encoding; smaller values require fewer bytes.
 // For a specification, see
-// https://developers.google.com/protocol-buffers/docs/encoding.
+// http://code.google.com/apis/protocolbuffers/docs/encoding.html.
 //
 // This package favors simplicity over efficiency. Clients that require
 // high-performance serialization, especially for large data structures,
@@ -239,62 +239,78 @@ func Write(w io.Writer, order ByteOrder, data interface{}) error {
 		}
 		switch v := data.(type) {
 		case *int8:
+			bs = b[:1]
 			b[0] = byte(*v)
 		case int8:
+			bs = b[:1]
 			b[0] = byte(v)
 		case []int8:
 			for i, x := range v {
 				bs[i] = byte(x)
 			}
 		case *uint8:
+			bs = b[:1]
 			b[0] = *v
 		case uint8:
+			bs = b[:1]
 			b[0] = byte(v)
 		case []uint8:
 			bs = v
 		case *int16:
+			bs = b[:2]
 			order.PutUint16(bs, uint16(*v))
 		case int16:
+			bs = b[:2]
 			order.PutUint16(bs, uint16(v))
 		case []int16:
 			for i, x := range v {
 				order.PutUint16(bs[2*i:], uint16(x))
 			}
 		case *uint16:
+			bs = b[:2]
 			order.PutUint16(bs, *v)
 		case uint16:
+			bs = b[:2]
 			order.PutUint16(bs, v)
 		case []uint16:
 			for i, x := range v {
 				order.PutUint16(bs[2*i:], x)
 			}
 		case *int32:
+			bs = b[:4]
 			order.PutUint32(bs, uint32(*v))
 		case int32:
+			bs = b[:4]
 			order.PutUint32(bs, uint32(v))
 		case []int32:
 			for i, x := range v {
 				order.PutUint32(bs[4*i:], uint32(x))
 			}
 		case *uint32:
+			bs = b[:4]
 			order.PutUint32(bs, *v)
 		case uint32:
+			bs = b[:4]
 			order.PutUint32(bs, v)
 		case []uint32:
 			for i, x := range v {
 				order.PutUint32(bs[4*i:], x)
 			}
 		case *int64:
+			bs = b[:8]
 			order.PutUint64(bs, uint64(*v))
 		case int64:
+			bs = b[:8]
 			order.PutUint64(bs, uint64(v))
 		case []int64:
 			for i, x := range v {
 				order.PutUint64(bs[8*i:], uint64(x))
 			}
 		case *uint64:
+			bs = b[:8]
 			order.PutUint64(bs, *v)
 		case uint64:
+			bs = b[:8]
 			order.PutUint64(bs, v)
 		case []uint64:
 			for i, x := range v {
@@ -589,25 +605,25 @@ func (e *encoder) skip(v reflect.Value) {
 // It returns zero if the type cannot be implemented by the fast path in Read or Write.
 func intDataSize(data interface{}) int {
 	switch data := data.(type) {
-	case int8, uint8, *int8, *uint8:
+	case int8, *int8, *uint8:
 		return 1
 	case []int8:
 		return len(data)
 	case []uint8:
 		return len(data)
-	case int16, uint16, *int16, *uint16:
+	case int16, *int16, *uint16:
 		return 2
 	case []int16:
 		return 2 * len(data)
 	case []uint16:
 		return 2 * len(data)
-	case int32, uint32, *int32, *uint32:
+	case int32, *int32, *uint32:
 		return 4
 	case []int32:
 		return 4 * len(data)
 	case []uint32:
 		return 4 * len(data)
-	case int64, uint64, *int64, *uint64:
+	case int64, *int64, *uint64:
 		return 8
 	case []int64:
 		return 8 * len(data)
diff --git a/src/encoding/csv/reader.go b/src/encoding/csv/reader.go
index 37bf80c..d943295 100644
--- a/src/encoding/csv/reader.go
+++ b/src/encoding/csv/reader.go
@@ -215,7 +215,7 @@ func (r *Reader) parseRecord() (fields []string, err error) {
 	r.column = -1
 
 	// Peek at the first rune.  If it is an error we are done.
-	// If we support comments and it is the comment character
+	// If we are support comments and it is the comment character
 	// then skip to the end of line.
 
 	r1, _, err := r.r.ReadRune()
@@ -232,11 +232,6 @@ func (r *Reader) parseRecord() (fields []string, err error) {
 	for {
 		haveField, delim, err := r.parseField()
 		if haveField {
-			// If FieldsPerRecord is greater then 0 we can assume the final
-			// length of fields to be equal to FieldsPerRecord.
-			if r.FieldsPerRecord > 0 && fields == nil {
-				fields = make([]string, 0, r.FieldsPerRecord)
-			}
 			fields = append(fields, r.field.String())
 		}
 		if delim == '\n' || err == io.EOF {
diff --git a/src/encoding/csv/reader_test.go b/src/encoding/csv/reader_test.go
index be1002d..123df06 100644
--- a/src/encoding/csv/reader_test.go
+++ b/src/encoding/csv/reader_test.go
@@ -87,15 +87,6 @@ field"`,
 		},
 	},
 	{
-		Name:               "BlankLineFieldCount",
-		Input:              "a,b,c\n\nd,e,f\n\n",
-		UseFieldsPerRecord: true,
-		Output: [][]string{
-			{"a", "b", "c"},
-			{"d", "e", "f"},
-		},
-	},
-	{
 		Name:             "TrimSpace",
 		Input:            " a,  b,   c\n",
 		TrimLeadingSpace: true,
@@ -291,25 +282,3 @@ func TestRead(t *testing.T) {
 		}
 	}
 }
-
-func BenchmarkRead(b *testing.B) {
-	data := `x,y,z,w
-x,y,z,
-x,y,,
-x,,,
-,,,
-"x","y","z","w"
-"x","y","z",""
-"x","y","",""
-"x","","",""
-"","","",""
-`
-
-	for i := 0; i < b.N; i++ {
-		_, err := NewReader(strings.NewReader(data)).ReadAll()
-
-		if err != nil {
-			b.Fatalf("could not read data: %s", err)
-		}
-	}
-}
diff --git a/src/encoding/csv/writer.go b/src/encoding/csv/writer.go
index 353d91f..17e7bb7 100644
--- a/src/encoding/csv/writer.go
+++ b/src/encoding/csv/writer.go
@@ -114,7 +114,7 @@ func (w *Writer) WriteAll(records [][]string) (err error) {
 	return w.w.Flush()
 }
 
-// fieldNeedsQuotes reports whether our field must be enclosed in quotes.
+// fieldNeedsQuotes returns true if our field must be enclosed in quotes.
 // Fields with a Comma, fields with a quote or newline, and
 // fields which start with a space must be enclosed in quotes.
 // We used to quote empty strings, but we do not anymore (as of Go 1.4).
@@ -125,7 +125,7 @@ func (w *Writer) WriteAll(records [][]string) (err error) {
 // CSV with quoted empty strings strictly less useful.
 // Not quoting the empty string also makes this package match the behavior
 // of Microsoft Excel and Google Drive.
-// For Postgres, quote the data terminating string `\.`.
+// For Postgres, quote the data termating string `\.`.
 func (w *Writer) fieldNeedsQuotes(field string) bool {
 	if field == "" {
 		return false
diff --git a/src/encoding/gob/codec_test.go b/src/encoding/gob/codec_test.go
index c2583bf..56a7298 100644
--- a/src/encoding/gob/codec_test.go
+++ b/src/encoding/gob/codec_test.go
@@ -1473,22 +1473,3 @@ func TestFuzzOneByte(t *testing.T) {
 		}
 	}
 }
-
-// Don't crash, just give error with invalid type id.
-// Issue 9649.
-func TestErrorInvalidTypeId(t *testing.T) {
-	data := []byte{0x01, 0x00, 0x01, 0x00}
-	d := NewDecoder(bytes.NewReader(data))
-	// When running d.Decode(&foo) the first time the decoder stops
-	// after []byte{0x01, 0x00} and reports an errBadType. Running
-	// d.Decode(&foo) again on exactly the same input sequence should
-	// give another errBadType, but instead caused a panic because
-	// decoderMap wasn't cleaned up properly after the first error.
-	for i := 0; i < 2; i++ {
-		var foo struct{}
-		err := d.Decode(&foo)
-		if err != errBadType {
-			t.Fatal("decode: expected %s, got %s", errBadType, err)
-		}
-	}
-}
diff --git a/src/encoding/gob/decode.go b/src/encoding/gob/decode.go
index e913f15..a5bef93 100644
--- a/src/encoding/gob/decode.go
+++ b/src/encoding/gob/decode.go
@@ -182,17 +182,6 @@ func (state *decoderState) decodeInt() int64 {
 	return int64(x >> 1)
 }
 
-// getLength decodes the next uint and makes sure it is a possible
-// size for a data item that follows, which means it must fit in a
-// non-negative int and fit in the buffer.
-func (state *decoderState) getLength() (int, bool) {
-	n := int(state.decodeUint())
-	if n < 0 || state.b.Len() < n || tooBig <= n {
-		return 0, false
-	}
-	return n, true
-}
-
 // decOp is the signature of a decoding operator for a given type.
 type decOp func(i *decInstr, state *decoderState, v reflect.Value)
 
@@ -374,9 +363,16 @@ func decComplex128(i *decInstr, state *decoderState, value reflect.Value) {
 // describing the data.
 // uint8 slices are encoded as an unsigned count followed by the raw bytes.
 func decUint8Slice(i *decInstr, state *decoderState, value reflect.Value) {
-	n, ok := state.getLength()
-	if !ok {
-		errorf("bad %s slice length: %d", value.Type(), n)
+	u := state.decodeUint()
+	n := int(u)
+	if n < 0 || uint64(n) != u {
+		errorf("length of %s exceeds input size (%d bytes)", value.Type(), u)
+	}
+	if n > state.b.Len() {
+		errorf("%s data too long for buffer: %d", value.Type(), n)
+	}
+	if n > tooBig {
+		errorf("byte slice too big: %d", n)
 	}
 	if value.Cap() < n {
 		value.Set(reflect.MakeSlice(value.Type(), n, n))
@@ -392,9 +388,13 @@ func decUint8Slice(i *decInstr, state *decoderState, value reflect.Value) {
 // describing the data.
 // Strings are encoded as an unsigned count followed by the raw bytes.
 func decString(i *decInstr, state *decoderState, value reflect.Value) {
-	n, ok := state.getLength()
-	if !ok {
-		errorf("bad %s slice length: %d", value.Type(), n)
+	u := state.decodeUint()
+	n := int(u)
+	if n < 0 || uint64(n) != u || n > state.b.Len() {
+		errorf("length of %s exceeds input size (%d bytes)", value.Type(), u)
+	}
+	if n > state.b.Len() {
+		errorf("%s data too long for buffer: %d", value.Type(), n)
 	}
 	// Read the data.
 	data := make([]byte, n)
@@ -406,11 +406,7 @@ func decString(i *decInstr, state *decoderState, value reflect.Value) {
 
 // ignoreUint8Array skips over the data for a byte slice value with no destination.
 func ignoreUint8Array(i *decInstr, state *decoderState, value reflect.Value) {
-	n, ok := state.getLength()
-	if !ok {
-		errorf("slice length too large")
-	}
-	b := make([]byte, n)
+	b := make([]byte, state.decodeUint())
 	state.b.Read(b)
 }
 
@@ -575,9 +571,6 @@ func (dec *Decoder) decodeMap(mtyp reflect.Type, state *decoderState, value refl
 func (dec *Decoder) ignoreArrayHelper(state *decoderState, elemOp decOp, length int) {
 	instr := &decInstr{elemOp, 0, nil, errors.New("no error")}
 	for i := 0; i < length; i++ {
-		if state.b.Len() == 0 {
-			errorf("decoding array or slice: length exceeds input size (%d elements)", length)
-		}
 		elemOp(instr, state, noValue)
 	}
 }
@@ -685,11 +678,7 @@ func (dec *Decoder) decodeInterface(ityp reflect.Type, state *decoderState, valu
 // ignoreInterface discards the data for an interface value with no destination.
 func (dec *Decoder) ignoreInterface(state *decoderState) {
 	// Read the name of the concrete type.
-	n, ok := state.getLength()
-	if !ok {
-		errorf("bad interface encoding: name too large for buffer")
-	}
-	b := make([]byte, n)
+	b := make([]byte, state.decodeUint())
 	_, err := state.b.Read(b)
 	if err != nil {
 		error_(err)
@@ -699,22 +688,14 @@ func (dec *Decoder) ignoreInterface(state *decoderState) {
 		error_(dec.err)
 	}
 	// At this point, the decoder buffer contains a delimited value. Just toss it.
-	n, ok = state.getLength()
-	if !ok {
-		errorf("bad interface encoding: data length too large for buffer")
-	}
-	state.b.Drop(n)
+	state.b.Drop(int(state.decodeUint()))
 }
 
 // decodeGobDecoder decodes something implementing the GobDecoder interface.
 // The data is encoded as a byte slice.
 func (dec *Decoder) decodeGobDecoder(ut *userTypeInfo, state *decoderState, value reflect.Value) {
 	// Read the bytes for the value.
-	n, ok := state.getLength()
-	if !ok {
-		errorf("GobDecoder: length too large for buffer")
-	}
-	b := make([]byte, n)
+	b := make([]byte, state.decodeUint())
 	_, err := state.b.Read(b)
 	if err != nil {
 		error_(err)
@@ -736,11 +717,7 @@ func (dec *Decoder) decodeGobDecoder(ut *userTypeInfo, state *decoderState, valu
 // ignoreGobDecoder discards the data for a GobDecoder value with no destination.
 func (dec *Decoder) ignoreGobDecoder(state *decoderState) {
 	// Read the bytes for the value.
-	n, ok := state.getLength()
-	if !ok {
-		errorf("GobDecoder: length too large for buffer")
-	}
-	b := make([]byte, n)
+	b := make([]byte, state.decodeUint())
 	_, err := state.b.Read(b)
 	if err != nil {
 		error_(err)
@@ -863,22 +840,16 @@ func (dec *Decoder) decOpFor(wireId typeId, rt reflect.Type, name string, inProg
 }
 
 // decIgnoreOpFor returns the decoding op for a field that has no destination.
-func (dec *Decoder) decIgnoreOpFor(wireId typeId, inProgress map[typeId]*decOp) *decOp {
-	// If this type is already in progress, it's a recursive type (e.g. map[string]*T).
-	// Return the pointer to the op we're already building.
-	if opPtr := inProgress[wireId]; opPtr != nil {
-		return opPtr
-	}
+func (dec *Decoder) decIgnoreOpFor(wireId typeId) decOp {
 	op, ok := decIgnoreOpMap[wireId]
 	if !ok {
-		inProgress[wireId] = &op
 		if wireId == tInterface {
 			// Special case because it's a method: the ignored item might
 			// define types and we need to record their state in the decoder.
 			op = func(i *decInstr, state *decoderState, value reflect.Value) {
 				state.dec.ignoreInterface(state)
 			}
-			return &op
+			return op
 		}
 		// Special cases
 		wire := dec.wireType[wireId]
@@ -887,25 +858,25 @@ func (dec *Decoder) decIgnoreOpFor(wireId typeId, inProgress map[typeId]*decOp)
 			errorf("bad data: undefined type %s", wireId.string())
 		case wire.ArrayT != nil:
 			elemId := wire.ArrayT.Elem
-			elemOp := dec.decIgnoreOpFor(elemId, inProgress)
+			elemOp := dec.decIgnoreOpFor(elemId)
 			op = func(i *decInstr, state *decoderState, value reflect.Value) {
-				state.dec.ignoreArray(state, *elemOp, wire.ArrayT.Len)
+				state.dec.ignoreArray(state, elemOp, wire.ArrayT.Len)
 			}
 
 		case wire.MapT != nil:
 			keyId := dec.wireType[wireId].MapT.Key
 			elemId := dec.wireType[wireId].MapT.Elem
-			keyOp := dec.decIgnoreOpFor(keyId, inProgress)
-			elemOp := dec.decIgnoreOpFor(elemId, inProgress)
+			keyOp := dec.decIgnoreOpFor(keyId)
+			elemOp := dec.decIgnoreOpFor(elemId)
 			op = func(i *decInstr, state *decoderState, value reflect.Value) {
-				state.dec.ignoreMap(state, *keyOp, *elemOp)
+				state.dec.ignoreMap(state, keyOp, elemOp)
 			}
 
 		case wire.SliceT != nil:
 			elemId := wire.SliceT.Elem
-			elemOp := dec.decIgnoreOpFor(elemId, inProgress)
+			elemOp := dec.decIgnoreOpFor(elemId)
 			op = func(i *decInstr, state *decoderState, value reflect.Value) {
-				state.dec.ignoreSlice(state, *elemOp)
+				state.dec.ignoreSlice(state, elemOp)
 			}
 
 		case wire.StructT != nil:
@@ -928,7 +899,7 @@ func (dec *Decoder) decIgnoreOpFor(wireId typeId, inProgress map[typeId]*decOp)
 	if op == nil {
 		errorf("bad data: ignore can't handle type %s", wireId.string())
 	}
-	return &op
+	return op
 }
 
 // gobDecodeOpFor returns the op for a type that is known to implement
@@ -1062,9 +1033,9 @@ func (dec *Decoder) compileSingle(remoteId typeId, ut *userTypeInfo) (engine *de
 func (dec *Decoder) compileIgnoreSingle(remoteId typeId) (engine *decEngine, err error) {
 	engine = new(decEngine)
 	engine.instr = make([]decInstr, 1) // one item
-	op := dec.decIgnoreOpFor(remoteId, make(map[typeId]*decOp))
+	op := dec.decIgnoreOpFor(remoteId)
 	ovfl := overflow(dec.typeString(remoteId))
-	engine.instr[0] = decInstr{*op, 0, nil, ovfl}
+	engine.instr[0] = decInstr{op, 0, nil, ovfl}
 	engine.numInstr = 1
 	return
 }
@@ -1072,7 +1043,6 @@ func (dec *Decoder) compileIgnoreSingle(remoteId typeId) (engine *decEngine, err
 // compileDec compiles the decoder engine for a value.  If the value is not a struct,
 // it calls out to compileSingle.
 func (dec *Decoder) compileDec(remoteId typeId, ut *userTypeInfo) (engine *decEngine, err error) {
-	defer catchError(&err)
 	rt := ut.base
 	srt := rt
 	if srt.Kind() != reflect.Struct || ut.externalDec != 0 {
@@ -1107,8 +1077,8 @@ func (dec *Decoder) compileDec(remoteId typeId, ut *userTypeInfo) (engine *decEn
 		localField, present := srt.FieldByName(wireField.Name)
 		// TODO(r): anonymous names
 		if !present || !isExported(wireField.Name) {
-			op := dec.decIgnoreOpFor(wireField.Id, make(map[typeId]*decOp))
-			engine.instr[fieldnum] = decInstr{*op, fieldnum, nil, ovfl}
+			op := dec.decIgnoreOpFor(wireField.Id)
+			engine.instr[fieldnum] = decInstr{op, fieldnum, nil, ovfl}
 			continue
 		}
 		if !dec.compatibleType(localField.Type, wireField.Id, make(map[reflect.Type]typeId)) {
@@ -1146,7 +1116,7 @@ type emptyStruct struct{}
 
 var emptyStructType = reflect.TypeOf(emptyStruct{})
 
-// getIgnoreEnginePtr returns the engine for the specified type when the value is to be discarded.
+// getDecEnginePtr returns the engine for the specified type when the value is to be discarded.
 func (dec *Decoder) getIgnoreEnginePtr(wireId typeId) (enginePtr **decEngine, err error) {
 	var ok bool
 	if enginePtr, ok = dec.ignorerCache[wireId]; !ok {
@@ -1185,9 +1155,8 @@ func (dec *Decoder) decodeValue(wireId typeId, value reflect.Value) {
 	value = decAlloc(value)
 	engine := *enginePtr
 	if st := base; st.Kind() == reflect.Struct && ut.externalDec == 0 {
-		wt := dec.wireType[wireId]
 		if engine.numInstr == 0 && st.NumField() > 0 &&
-			wt != nil && len(wt.StructT.Field) > 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/encoding/gob/doc.go b/src/encoding/gob/doc.go
index 4d3d007..d0acaba 100644
--- a/src/encoding/gob/doc.go
+++ b/src/encoding/gob/doc.go
@@ -6,7 +6,7 @@
 Package gob manages streams of gobs - binary values exchanged between an
 Encoder (transmitter) and a Decoder (receiver).  A typical use is transporting
 arguments and results of remote procedure calls (RPCs) such as those provided by
-package "net/rpc".
+package "rpc".
 
 The implementation compiles a custom codec for each data type in the stream and
 is most efficient when a single Encoder is used to transmit a stream of values,
@@ -83,7 +83,7 @@ allocated. Regardless, the length of the resulting slice reports the number of
 elements decoded.
 
 Functions and channels will not be sent in a gob. Attempting to encode such a value
-at the top level will fail. A struct field of chan or func type is treated exactly
+at top the level will fail. A struct field of chan or func type is treated exactly
 like an unexported field and is ignored.
 
 Gob can encode a value of any type implementing the GobEncoder or
@@ -111,11 +111,11 @@ A signed integer, i, is encoded within an unsigned integer, u.  Within u, bits 1
 upward contain the value; bit 0 says whether they should be complemented upon
 receipt.  The encode algorithm looks like this:
 
-	var u uint
+	uint u;
 	if i < 0 {
-		u = (^uint(i) << 1) | 1 // complement i, bit 0 is 1
+		u = (^i << 1) | 1	// complement i, bit 0 is 1
 	} else {
-		u = (uint(i) << 1) // do not complement i, bit 0 is 0
+		u = (i << 1)	// do not complement i, bit 0 is 0
 	}
 	encodeUnsigned(u)
 
@@ -137,9 +137,9 @@ All other slices and arrays are sent as an unsigned count followed by that many
 elements using the standard gob encoding for their type, recursively.
 
 Maps are sent as an unsigned count followed by that many key, element
-pairs. Empty but non-nil maps are sent, so if the receiver has not allocated
-one already, one will always be allocated on receipt unless the transmitted map
-is nil and not at the top level.
+pairs. Empty but non-nil maps are sent, so if the sender has allocated
+a map, the receiver will allocate a map even if no elements are
+transmitted.
 
 Structs are sent as a sequence of (field number, field value) pairs.  The field
 value is sent using the standard gob encoding for its type, recursively.  If a
@@ -246,7 +246,7 @@ where * signifies zero or more repetitions and the type id of a value must
 be predefined or be defined before the value in the stream.
 
 See "Gobs of data" for a design discussion of the gob wire format:
-https://blog.golang.org/gobs-of-data
+http://golang.org/doc/articles/gobs_of_data.html
 */
 package gob
 
diff --git a/src/encoding/gob/encoder.go b/src/encoding/gob/encoder.go
index 62d0f42..a340e47 100644
--- a/src/encoding/gob/encoder.go
+++ b/src/encoding/gob/encoder.go
@@ -5,7 +5,6 @@
 package gob
 
 import (
-	"errors"
 	"io"
 	"reflect"
 	"sync"
@@ -66,11 +65,6 @@ func (enc *Encoder) writeMessage(w io.Writer, b *encBuffer) {
 	// it by hand.
 	message := b.Bytes()
 	messageLen := len(message) - maxLength
-	// Length cannot be bigger than the decoder can handle.
-	if messageLen >= tooBig {
-		enc.setError(errors.New("gob: encoder: message too big"))
-		return
-	}
 	// Encode the length.
 	enc.countState.b.Reset()
 	enc.countState.encodeUint(uint64(messageLen))
diff --git a/src/encoding/gob/encoder_test.go b/src/encoding/gob/encoder_test.go
index dc65734..0ea4c0e 100644
--- a/src/encoding/gob/encoder_test.go
+++ b/src/encoding/gob/encoder_test.go
@@ -6,8 +6,8 @@ package gob
 
 import (
 	"bytes"
-	"encoding/hex"
 	"fmt"
+	"io"
 	"reflect"
 	"strings"
 	"testing"
@@ -187,6 +187,24 @@ func TestWrongTypeDecoder(t *testing.T) {
 	badTypeCheck(new(ET4), true, "different type of field", t)
 }
 
+func corruptDataCheck(s string, err error, t *testing.T) {
+	b := bytes.NewBufferString(s)
+	dec := NewDecoder(b)
+	err1 := dec.Decode(new(ET2))
+	if err1 != err {
+		t.Errorf("from %q expected error %s; got %s", s, err, err1)
+	}
+}
+
+// Check that we survive bad data.
+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.
 var unsupportedValues = []interface{}{
 	make(chan int),
@@ -527,30 +545,6 @@ func TestDecodeIntoNothing(t *testing.T) {
 	}
 }
 
-func TestIgnoreRecursiveType(t *testing.T) {
-	// It's hard to build a self-contained test for this because
-	// we can't build compatible types in one package with
-	// different items so something is ignored. Here is
-	// some data that represents, according to debug.go:
-	// type definition {
-	//	slice "recursiveSlice" id=106
-	//		elem id=106
-	// }
-	data := []byte{
-		0x1d, 0xff, 0xd3, 0x02, 0x01, 0x01, 0x0e, 0x72,
-		0x65, 0x63, 0x75, 0x72, 0x73, 0x69, 0x76, 0x65,
-		0x53, 0x6c, 0x69, 0x63, 0x65, 0x01, 0xff, 0xd4,
-		0x00, 0x01, 0xff, 0xd4, 0x00, 0x00, 0x07, 0xff,
-		0xd4, 0x00, 0x02, 0x01, 0x00, 0x00,
-	}
-	dec := NewDecoder(bytes.NewReader(data))
-	// Issue 10415: This caused infinite recursion.
-	err := dec.Decode(nil)
-	if err != nil {
-		t.Fatal(err)
-	}
-}
-
 // Another bug from golang-nuts, involving nested interfaces.
 type Bug0Outer struct {
 	Bug0Field interface{}
@@ -957,64 +951,6 @@ func TestErrorForHugeSlice(t *testing.T) {
 		t.Fatal("decode: no error")
 	}
 	if !strings.Contains(err.Error(), "slice too big") {
-		t.Fatalf("decode: expected slice too big error, got %s", err.Error())
-	}
-}
-
-type badDataTest struct {
-	input string      // The input encoded as a hex string.
-	error string      // A substring of the error that should result.
-	data  interface{} // What to decode into.
-}
-
-var badDataTests = []badDataTest{
-	{"", "EOF", nil},
-	{"7F6869", "unexpected EOF", nil},
-	{"036e6f77206973207468652074696d6520666f7220616c6c20676f6f64206d656e", "unknown type id", new(ET2)},
-	{"0424666f6f", "field numbers out of bounds", new(ET2)}, // Issue 6323.
-	{"05100028557b02027f8302", "interface encoding", nil},   // Issue 10270.
-	// Issue 10273.
-	{"130a00fb5dad0bf8ff020263e70002fa28020202a89859", "slice length too large", nil},
-	{"0f1000fb285d003316020735ff023a65c5", "interface encoding", nil},
-	{"03fffb0616fffc00f902ff02ff03bf005d02885802a311a8120228022c028ee7", "GobDecoder", nil},
-	// Issue 10491.
-	{"10fe010f020102fe01100001fe010e000016fe010d030102fe010e00010101015801fe01100000000bfe011000f85555555555555555", "length exceeds input size", nil},
-}
-
-// TestBadData tests that various problems caused by malformed input
-// are caught as errors and do not cause panics.
-func TestBadData(t *testing.T) {
-	for i, test := range badDataTests {
-		data, err := hex.DecodeString(test.input)
-		if err != nil {
-			t.Fatalf("#%d: hex error: %s", i, err)
-		}
-		d := NewDecoder(bytes.NewReader(data))
-		err = d.Decode(test.data)
-		if err == nil {
-			t.Errorf("decode: no error")
-			continue
-		}
-		if !strings.Contains(err.Error(), test.error) {
-			t.Errorf("#%d: decode: expected %q error, got %s", i, test.error, err.Error())
-		}
-	}
-}
-
-// TestHugeWriteFails tests that enormous messages trigger an error.
-func TestHugeWriteFails(t *testing.T) {
-	if testing.Short() {
-		// Requires allocating a monster, so don't do this from all.bash.
-		t.Skip("skipping huge allocation in short mode")
-	}
-	huge := make([]byte, tooBig)
-	huge[0] = 7 // Make sure it's not all zeros.
-	buf := new(bytes.Buffer)
-	err := NewEncoder(buf).Encode(huge)
-	if err == nil {
-		t.Fatalf("expected error for huge slice")
-	}
-	if !strings.Contains(err.Error(), "message too big") {
-		t.Fatalf("expected 'too big' error; got %s\n", err.Error())
+		t.Fatal("decode: expected slice too big error, got %s", err.Error())
 	}
 }
diff --git a/src/encoding/json/bench_test.go b/src/encoding/json/bench_test.go
index ed89d11..29dbc26 100644
--- a/src/encoding/json/bench_test.go
+++ b/src/encoding/json/bench_test.go
@@ -15,7 +15,6 @@ import (
 	"compress/gzip"
 	"io/ioutil"
 	"os"
-	"strings"
 	"testing"
 )
 
@@ -127,28 +126,6 @@ func BenchmarkCodeDecoder(b *testing.B) {
 	b.SetBytes(int64(len(codeJSON)))
 }
 
-func BenchmarkDecoderStream(b *testing.B) {
-	b.StopTimer()
-	var buf bytes.Buffer
-	dec := NewDecoder(&buf)
-	buf.WriteString(`"` + strings.Repeat("x", 1000000) + `"` + "\n\n\n")
-	var x interface{}
-	if err := dec.Decode(&x); err != nil {
-		b.Fatal("Decode:", err)
-	}
-	ones := strings.Repeat(" 1\n", 300000) + "\n\n\n"
-	b.StartTimer()
-	for i := 0; i < b.N; i++ {
-		if i%300000 == 0 {
-			buf.WriteString(ones)
-		}
-		x = nil
-		if err := dec.Decode(&x); err != nil || x != 1.0 {
-			b.Fatalf("Decode: %v after %d", err, i)
-		}
-	}
-}
-
 func BenchmarkCodeUnmarshal(b *testing.B) {
 	if codeJSON == nil {
 		b.StopTimer()
@@ -210,14 +187,3 @@ func BenchmarkUnmarshalInt64(b *testing.B) {
 		}
 	}
 }
-
-func BenchmarkIssue10335(b *testing.B) {
-	b.ReportAllocs()
-	var s struct{}
-	j := []byte(`{"a":{ }}`)
-	for n := 0; n < b.N; n++ {
-		if err := Unmarshal(j, &s); err != nil {
-			b.Fatal(err)
-		}
-	}
-}
diff --git a/src/encoding/json/decode.go b/src/encoding/json/decode.go
index 530e852..705bc2e 100644
--- a/src/encoding/json/decode.go
+++ b/src/encoding/json/decode.go
@@ -48,13 +48,6 @@ import (
 //	map[string]interface{}, for JSON objects
 //	nil for JSON null
 //
-// To unmarshal a JSON array into a slice, Unmarshal resets the slice to nil
-// and then appends each element to the slice.
-//
-// To unmarshal a JSON object into a map, Unmarshal replaces the map
-// with an empty map and then adds key-value pairs from the object to
-// the map.
-//
 // If a JSON value is not appropriate for a given target type,
 // or if a JSON number overflows the target type, Unmarshal
 // skips that field and completes the unmarshalling as best it can.
@@ -97,9 +90,8 @@ type Unmarshaler interface {
 // An UnmarshalTypeError describes a JSON value that was
 // not appropriate for a value of a specific Go type.
 type UnmarshalTypeError struct {
-	Value  string       // description of JSON value - "bool", "array", "number -5"
-	Type   reflect.Type // type of Go value it could not be assigned to
-	Offset int64        // error occurred after reading Offset bytes
+	Value string       // description of JSON value - "bool", "array", "number -5"
+	Type  reflect.Type // type of Go value it could not be assigned to
 }
 
 func (e *UnmarshalTypeError) Error() string {
@@ -385,7 +377,7 @@ func (d *decodeState) array(v reflect.Value) {
 		return
 	}
 	if ut != nil {
-		d.saveError(&UnmarshalTypeError{"array", v.Type(), int64(d.off)})
+		d.saveError(&UnmarshalTypeError{"array", v.Type()})
 		d.off--
 		d.next()
 		return
@@ -404,7 +396,7 @@ func (d *decodeState) array(v reflect.Value) {
 		// Otherwise it's invalid.
 		fallthrough
 	default:
-		d.saveError(&UnmarshalTypeError{"array", v.Type(), int64(d.off)})
+		d.saveError(&UnmarshalTypeError{"array", v.Type()})
 		d.off--
 		d.next()
 		return
@@ -493,7 +485,7 @@ func (d *decodeState) object(v reflect.Value) {
 		return
 	}
 	if ut != nil {
-		d.saveError(&UnmarshalTypeError{"object", v.Type(), int64(d.off)})
+		d.saveError(&UnmarshalTypeError{"object", v.Type()})
 		d.off--
 		d.next() // skip over { } in input
 		return
@@ -512,7 +504,7 @@ func (d *decodeState) object(v reflect.Value) {
 		// map must have string kind
 		t := v.Type()
 		if t.Key().Kind() != reflect.String {
-			d.saveError(&UnmarshalTypeError{"object", v.Type(), int64(d.off)})
+			d.saveError(&UnmarshalTypeError{"object", v.Type()})
 			d.off--
 			d.next() // skip over { } in input
 			return
@@ -523,7 +515,7 @@ func (d *decodeState) object(v reflect.Value) {
 	case reflect.Struct:
 
 	default:
-		d.saveError(&UnmarshalTypeError{"object", v.Type(), int64(d.off)})
+		d.saveError(&UnmarshalTypeError{"object", v.Type()})
 		d.off--
 		d.next() // skip over { } in input
 		return
@@ -607,7 +599,7 @@ func (d *decodeState) object(v reflect.Value) {
 			case string:
 				d.literalStore([]byte(qv), subv, true)
 			default:
-				d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal unquoted value into %v", subv.Type()))
+				d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal unquoted value into %v", item, v.Type()))
 			}
 		} else {
 			d.value(subv)
@@ -654,7 +646,7 @@ func (d *decodeState) convertNumber(s string) (interface{}, error) {
 	}
 	f, err := strconv.ParseFloat(s, 64)
 	if err != nil {
-		return nil, &UnmarshalTypeError{"number " + s, reflect.TypeOf(0.0), int64(d.off)}
+		return nil, &UnmarshalTypeError{"number " + s, reflect.TypeOf(0.0)}
 	}
 	return f, nil
 }
@@ -687,9 +679,8 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
 			if fromQuoted {
 				d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()))
 			} else {
-				d.saveError(&UnmarshalTypeError{"string", v.Type(), int64(d.off)})
+				d.saveError(&UnmarshalTypeError{"string", v.Type()})
 			}
-			return
 		}
 		s, ok := unquoteBytes(item)
 		if !ok {
@@ -722,7 +713,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
 			if fromQuoted {
 				d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()))
 			} else {
-				d.saveError(&UnmarshalTypeError{"bool", v.Type(), int64(d.off)})
+				d.saveError(&UnmarshalTypeError{"bool", v.Type()})
 			}
 		case reflect.Bool:
 			v.SetBool(value)
@@ -730,7 +721,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
 			if v.NumMethod() == 0 {
 				v.Set(reflect.ValueOf(value))
 			} else {
-				d.saveError(&UnmarshalTypeError{"bool", v.Type(), int64(d.off)})
+				d.saveError(&UnmarshalTypeError{"bool", v.Type()})
 			}
 		}
 
@@ -745,10 +736,10 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
 		}
 		switch v.Kind() {
 		default:
-			d.saveError(&UnmarshalTypeError{"string", v.Type(), int64(d.off)})
+			d.saveError(&UnmarshalTypeError{"string", v.Type()})
 		case reflect.Slice:
-			if v.Type().Elem().Kind() != reflect.Uint8 {
-				d.saveError(&UnmarshalTypeError{"string", v.Type(), int64(d.off)})
+			if v.Type() != byteSliceType {
+				d.saveError(&UnmarshalTypeError{"string", v.Type()})
 				break
 			}
 			b := make([]byte, base64.StdEncoding.DecodedLen(len(s)))
@@ -764,7 +755,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
 			if v.NumMethod() == 0 {
 				v.Set(reflect.ValueOf(string(s)))
 			} else {
-				d.saveError(&UnmarshalTypeError{"string", v.Type(), int64(d.off)})
+				d.saveError(&UnmarshalTypeError{"string", v.Type()})
 			}
 		}
 
@@ -786,7 +777,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
 			if fromQuoted {
 				d.error(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()))
 			} else {
-				d.error(&UnmarshalTypeError{"number", v.Type(), int64(d.off)})
+				d.error(&UnmarshalTypeError{"number", v.Type()})
 			}
 		case reflect.Interface:
 			n, err := d.convertNumber(s)
@@ -795,7 +786,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
 				break
 			}
 			if v.NumMethod() != 0 {
-				d.saveError(&UnmarshalTypeError{"number", v.Type(), int64(d.off)})
+				d.saveError(&UnmarshalTypeError{"number", v.Type()})
 				break
 			}
 			v.Set(reflect.ValueOf(n))
@@ -803,7 +794,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
 		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
 			n, err := strconv.ParseInt(s, 10, 64)
 			if err != nil || v.OverflowInt(n) {
-				d.saveError(&UnmarshalTypeError{"number " + s, v.Type(), int64(d.off)})
+				d.saveError(&UnmarshalTypeError{"number " + s, v.Type()})
 				break
 			}
 			v.SetInt(n)
@@ -811,7 +802,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
 		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
 			n, err := strconv.ParseUint(s, 10, 64)
 			if err != nil || v.OverflowUint(n) {
-				d.saveError(&UnmarshalTypeError{"number " + s, v.Type(), int64(d.off)})
+				d.saveError(&UnmarshalTypeError{"number " + s, v.Type()})
 				break
 			}
 			v.SetUint(n)
@@ -819,7 +810,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
 		case reflect.Float32, reflect.Float64:
 			n, err := strconv.ParseFloat(s, v.Type().Bits())
 			if err != nil || v.OverflowFloat(n) {
-				d.saveError(&UnmarshalTypeError{"number " + s, v.Type(), int64(d.off)})
+				d.saveError(&UnmarshalTypeError{"number " + s, v.Type()})
 				break
 			}
 			v.SetFloat(n)
diff --git a/src/encoding/json/decode_test.go b/src/encoding/json/decode_test.go
index 8aa158f..7235969 100644
--- a/src/encoding/json/decode_test.go
+++ b/src/encoding/json/decode_test.go
@@ -9,7 +9,6 @@ import (
 	"encoding"
 	"fmt"
 	"image"
-	"net"
 	"reflect"
 	"strings"
 	"testing"
@@ -217,9 +216,6 @@ type XYZ struct {
 	Z interface{}
 }
 
-func sliceAddr(x []int) *[]int                 { return &x }
-func mapAddr(x map[string]int) *map[string]int { return &x }
-
 var unmarshalTests = []unmarshalTest{
 	// basic types
 	{in: `true`, ptr: new(bool), out: true},
@@ -235,7 +231,7 @@ var unmarshalTests = []unmarshalTest{
 	{in: `"g-clef: \uD834\uDD1E"`, ptr: new(string), out: "g-clef: \U0001D11E"},
 	{in: `"invalid: \uD834x\uDD1E"`, ptr: new(string), out: "invalid: \uFFFDx\uFFFD"},
 	{in: "null", ptr: new(interface{}), out: nil},
-	{in: `{"X": [1,2,3], "Y": 4}`, ptr: new(T), out: T{Y: 4}, err: &UnmarshalTypeError{"array", reflect.TypeOf(""), 7}},
+	{in: `{"X": [1,2,3], "Y": 4}`, ptr: new(T), out: T{Y: 4}, err: &UnmarshalTypeError{"array", reflect.TypeOf("")}},
 	{in: `{"x": 1}`, ptr: new(tx), out: tx{}},
 	{in: `{"F1":1,"F2":2,"F3":3}`, ptr: new(V), out: V{F1: float64(1), F2: int32(2), F3: Number("3")}},
 	{in: `{"F1":1,"F2":2,"F3":3}`, ptr: new(V), out: V{F1: Number("1"), F2: int32(2), F3: Number("3")}, useNumber: true},
@@ -306,12 +302,6 @@ var unmarshalTests = []unmarshalTest{
 	{in: `["X"]`, ptr: &umslicepT, out: &umsliceT},
 	{in: `{"M":"X"}`, ptr: &umstructT, out: umstructT},
 
-	// Overwriting of data.
-	// This is different from package xml, but it's what we've always done.
-	// Now documented and tested.
-	{in: `[2]`, ptr: sliceAddr([]int{1}), out: []int{2}},
-	{in: `{"key": 2}`, ptr: mapAddr(map[string]int{"old": 0, "key": 1}), out: map[string]int{"key": 2}},
-
 	{
 		in: `{
 			"Level0": 1,
@@ -421,7 +411,7 @@ var unmarshalTests = []unmarshalTest{
 	{
 		in:  `{"2009-11-10T23:00:00Z": "hello world"}`,
 		ptr: &map[time.Time]string{},
-		err: &UnmarshalTypeError{"object", reflect.TypeOf(map[time.Time]string{}), 1},
+		err: &UnmarshalTypeError{"object", reflect.TypeOf(map[time.Time]string{})},
 	},
 }
 
@@ -698,7 +688,6 @@ var wrongStringTests = []wrongStringTest{
 	{`{"result":"x"}`, `json: invalid use of ,string struct tag, trying to unmarshal "x" into string`},
 	{`{"result":"foo"}`, `json: invalid use of ,string struct tag, trying to unmarshal "foo" into string`},
 	{`{"result":"123"}`, `json: invalid use of ,string struct tag, trying to unmarshal "123" into string`},
-	{`{"result":123}`, `json: invalid use of ,string struct tag, trying to unmarshal unquoted value into string`},
 }
 
 // If people misuse the ,string modifier, the error message should be
@@ -1096,7 +1085,7 @@ func TestNullString(t *testing.T) {
 	*s.C = 2
 	err := Unmarshal(data, &s)
 	if err != nil {
-		t.Fatalf("Unmarshal: %v", err)
+		t.Fatalf("Unmarshal: %v")
 	}
 	if s.B != 1 || s.C != nil {
 		t.Fatalf("after Unmarshal, s.B=%d, s.C=%p, want 1, nil", s.B, s.C)
@@ -1217,28 +1206,7 @@ func TestStringKind(t *testing.T) {
 	if !reflect.DeepEqual(m1, m2) {
 		t.Error("Items should be equal after encoding and then decoding")
 	}
-}
-
-// Custom types with []byte as underlying type could not be marshalled
-// and then unmarshalled.
-// Issue 8962.
-func TestByteKind(t *testing.T) {
-	type byteKind []byte
 
-	a := byteKind("hello")
-
-	data, err := Marshal(a)
-	if err != nil {
-		t.Error(err)
-	}
-	var b byteKind
-	err = Unmarshal(data, &b)
-	if err != nil {
-		t.Fatal(err)
-	}
-	if !reflect.DeepEqual(a, b) {
-		t.Errorf("expected %v == %v", a, b)
-	}
 }
 
 var decodeTypeErrorTests = []struct {
@@ -1403,51 +1371,3 @@ func TestInvalidUnmarshal(t *testing.T) {
 		}
 	}
 }
-
-var invalidUnmarshalTextTests = []struct {
-	v    interface{}
-	want string
-}{
-	{nil, "json: Unmarshal(nil)"},
-	{struct{}{}, "json: Unmarshal(non-pointer struct {})"},
-	{(*int)(nil), "json: Unmarshal(nil *int)"},
-	{new(net.IP), "json: cannot unmarshal string into Go value of type *net.IP"},
-}
-
-func TestInvalidUnmarshalText(t *testing.T) {
-	buf := []byte(`123`)
-	for _, tt := range invalidUnmarshalTextTests {
-		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)
-		}
-	}
-}
-
-// Test that string option is ignored for invalid types.
-// Issue 9812.
-func TestInvalidStringOption(t *testing.T) {
-	num := 0
-	item := struct {
-		T time.Time         `json:",string"`
-		M map[string]string `json:",string"`
-		S []string          `json:",string"`
-		A [1]string         `json:",string"`
-		I interface{}       `json:",string"`
-		P *int              `json:",string"`
-	}{M: make(map[string]string), S: make([]string, 0), I: num, P: &num}
-
-	data, err := Marshal(item)
-	if err != nil {
-		t.Fatalf("Marshal: %v", err)
-	}
-
-	err = Unmarshal(data, &item)
-	if err != nil {
-		t.Fatalf("Unmarshal: %v", err)
-	}
-}
diff --git a/src/encoding/json/encode.go b/src/encoding/json/encode.go
index 90782de..fca2a09 100644
--- a/src/encoding/json/encode.go
+++ b/src/encoding/json/encode.go
@@ -7,7 +7,7 @@
 // in the documentation for the Marshal and Unmarshal functions.
 //
 // See "JSON and Go" for an introduction to this package:
-// https://golang.org/doc/articles/json_and_go.html
+// http://golang.org/doc/articles/json_and_go.html
 package json
 
 import (
@@ -79,8 +79,8 @@ import (
 //
 // The "string" option signals that a field is stored as JSON inside a
 // JSON-encoded string. It applies only to fields of string, floating point,
-// integer, or boolean types. This extra level of encoding is sometimes used
-// when communicating with JavaScript programs:
+// or integer types. This extra level of encoding is sometimes used when
+// communicating with JavaScript programs:
 //
 //    Int64String int64 `json:",string"`
 //
@@ -113,8 +113,8 @@ import (
 // a JSON tag of "-".
 //
 // Map values encode as JSON objects.
-// The map's key type must be string; the map keys are used as JSON object
-// keys, subject to the UTF-8 coercion described for string values above.
+// The map's key type must be string; the object keys are used directly
+// as map keys.
 //
 // Pointer values encode as the value pointed to.
 // A nil pointer encodes as the null JSON object.
@@ -275,6 +275,8 @@ func (e *encodeState) error(err error) {
 	panic(err)
 }
 
+var byteSliceType = reflect.TypeOf([]byte(nil))
+
 func isEmptyValue(v reflect.Value) bool {
 	switch v.Kind() {
 	case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
@@ -1043,19 +1045,6 @@ func typeFields(t reflect.Type) []field {
 					ft = ft.Elem()
 				}
 
-				// Only strings, floats, integers, and booleans can be quoted.
-				quoted := false
-				if opts.Contains("string") {
-					switch ft.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,
-						reflect.String:
-						quoted = true
-					}
-				}
-
 				// Record found field and index sequence.
 				if name != "" || !sf.Anonymous || ft.Kind() != reflect.Struct {
 					tagged := name != ""
@@ -1068,7 +1057,7 @@ func typeFields(t reflect.Type) []field {
 						index:     index,
 						typ:       ft,
 						omitEmpty: opts.Contains("omitempty"),
-						quoted:    quoted,
+						quoted:    opts.Contains("string"),
 					}))
 					if count[f.typ] > 1 {
 						// If there were multiple instances, add a second,
diff --git a/src/encoding/json/example_test.go b/src/encoding/json/example_test.go
index da08e10..ca4e5ae 100644
--- a/src/encoding/json/example_test.go
+++ b/src/encoding/json/example_test.go
@@ -83,97 +83,6 @@ func ExampleDecoder() {
 	// Ed: Go fmt yourself!
 }
 
-// This example uses a Decoder to decode a stream of distinct JSON values.
-func ExampleDecoder_Token() {
-	const jsonStream = `
-		{"Message": "Hello", "Array": [1, 2, 3], "Null": null, "Number": 1.234}
-	`
-	dec := json.NewDecoder(strings.NewReader(jsonStream))
-	for {
-		t, err := dec.Token()
-		if err == io.EOF {
-			break
-		}
-		if err != nil {
-			log.Fatal(err)
-		}
-		fmt.Printf("%T: %v", t, t)
-		if dec.More() {
-			fmt.Printf(" (more)")
-		}
-		fmt.Printf("\n")
-	}
-	// Output:
-	// json.Delim: { (more)
-	// string: Message (more)
-	// string: Hello (more)
-	// string: Array (more)
-	// json.Delim: [ (more)
-	// float64: 1 (more)
-	// float64: 2 (more)
-	// float64: 3
-	// json.Delim: ] (more)
-	// string: Null (more)
-	// <nil>: <nil> (more)
-	// string: Number (more)
-	// float64: 1.234
-	// json.Delim: }
-}
-
-// This example uses a Decoder to decode a streaming array of JSON objects.
-func ExampleDecoder_Decode_stream() {
-	const jsonStream = `
-		[
-			{"Name": "Ed", "Text": "Knock knock."},
-			{"Name": "Sam", "Text": "Who's there?"},
-			{"Name": "Ed", "Text": "Go fmt."},
-			{"Name": "Sam", "Text": "Go fmt who?"},
-			{"Name": "Ed", "Text": "Go fmt yourself!"}
-		]
-	`
-	type Message struct {
-		Name, Text string
-	}
-	dec := json.NewDecoder(strings.NewReader(jsonStream))
-
-	// read open bracket
-	t, err := dec.Token()
-	if err != nil {
-		log.Fatal(err)
-	}
-	fmt.Printf("%T: %v\n", t, t)
-
-	var m Message
-	// while the array contains values
-	for dec.More() {
-
-		// decode an array value (Message)
-		err := dec.Decode(&m)
-		if err != nil {
-			log.Fatal(err)
-		}
-
-		fmt.Printf("%v: %v\n", m.Name, m.Text)
-	}
-
-	// read closing bracket
-	t, err = dec.Token()
-	if err != nil {
-		log.Fatal(err)
-	}
-	fmt.Printf("%T: %v\n", t, t)
-
-	// Output:
-	// json.Delim: [
-	// Ed: Knock knock.
-	// Sam: Who's there?
-	// Ed: Go fmt.
-	// Sam: Go fmt who?
-	// Ed: Go fmt yourself!
-	// json.Delim: ]
-
-}
-
 // This example uses RawMessage to delay parsing part of a JSON message.
 func ExampleRawMessage() {
 	type Color struct {
diff --git a/src/encoding/json/fold.go b/src/encoding/json/fold.go
index 9e17012..d6f77c9 100644
--- a/src/encoding/json/fold.go
+++ b/src/encoding/json/fold.go
@@ -26,7 +26,7 @@ const (
 // 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 https://play.golang.org/p/tTxjOc0OGo
+// 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.
diff --git a/src/encoding/json/scanner.go b/src/encoding/json/scanner.go
index 38d0b08..a4609c8 100644
--- a/src/encoding/json/scanner.go
+++ b/src/encoding/json/scanner.go
@@ -38,15 +38,8 @@ func nextValue(data []byte, scan *scanner) (value, rest []byte, err error) {
 	scan.reset()
 	for i, c := range data {
 		v := scan.step(scan, int(c))
-		if v >= scanEndObject {
+		if v >= scanEnd {
 			switch v {
-			// probe the scanner with a space to determine whether we will
-			// get scanEnd on the next character. Otherwise, if the next character
-			// is not a space, scanEndTop allocates a needless error.
-			case scanEndObject, scanEndArray:
-				if scan.step(scan, ' ') == scanEnd {
-					return data[:i+1], data[i+1:], nil
-				}
 			case scanError:
 				return nil, nil, scan.err
 			case scanEnd:
diff --git a/src/encoding/json/scanner_test.go b/src/encoding/json/scanner_test.go
index 66383ef..7880342 100644
--- a/src/encoding/json/scanner_test.go
+++ b/src/encoding/json/scanner_test.go
@@ -209,7 +209,6 @@ var benchScan scanner
 
 func BenchmarkSkipValue(b *testing.B) {
 	initBig()
-	b.ResetTimer()
 	for i := 0; i < b.N; i++ {
 		nextValue(jsonBig, &benchScan)
 	}
diff --git a/src/encoding/json/stream.go b/src/encoding/json/stream.go
index dc53bce..9566eca 100644
--- a/src/encoding/json/stream.go
+++ b/src/encoding/json/stream.go
@@ -12,15 +12,11 @@ import (
 
 // A Decoder reads and decodes JSON objects from an input stream.
 type Decoder struct {
-	r     io.Reader
-	buf   []byte
-	d     decodeState
-	scanp int // start of unread data in buf
-	scan  scanner
-	err   error
-
-	tokenState int
-	tokenStack []int
+	r    io.Reader
+	buf  []byte
+	d    decodeState
+	scan scanner
+	err  error
 }
 
 // NewDecoder returns a new decoder that reads from r.
@@ -45,29 +41,20 @@ func (dec *Decoder) Decode(v interface{}) error {
 		return dec.err
 	}
 
-	if err := dec.tokenPrepareForDecode(); err != nil {
-		return err
-	}
-
-	if !dec.tokenValueAllowed() {
-		return &SyntaxError{msg: "not at beginning of value"}
-	}
-
-	// Read whole value into buffer.
 	n, err := dec.readValue()
 	if err != nil {
 		return err
 	}
-	dec.d.init(dec.buf[dec.scanp : dec.scanp+n])
-	dec.scanp += n
 
 	// Don't save err from unmarshal into dec.err:
 	// the connection is still usable since we read a complete JSON
 	// object from it before the error happened.
+	dec.d.init(dec.buf[0:n])
 	err = dec.d.unmarshal(v)
 
-	// fixup token streaming state
-	dec.tokenValueEnd()
+	// Slide rest of data down.
+	rest := copy(dec.buf, dec.buf[n:])
+	dec.buf = dec.buf[0:rest]
 
 	return err
 }
@@ -75,7 +62,7 @@ func (dec *Decoder) Decode(v interface{}) error {
 // Buffered returns a reader of the data remaining in the Decoder's
 // buffer. The reader is valid until the next call to Decode.
 func (dec *Decoder) Buffered() io.Reader {
-	return bytes.NewReader(dec.buf[dec.scanp:])
+	return bytes.NewReader(dec.buf)
 }
 
 // readValue reads a JSON value into dec.buf.
@@ -83,7 +70,7 @@ func (dec *Decoder) Buffered() io.Reader {
 func (dec *Decoder) readValue() (int, error) {
 	dec.scan.reset()
 
-	scanp := dec.scanp
+	scanp := 0
 	var err error
 Input:
 	for {
@@ -124,35 +111,20 @@ Input:
 			return 0, err
 		}
 
-		n := scanp - dec.scanp
-		err = dec.refill()
-		scanp = dec.scanp + n
-	}
-	return scanp - dec.scanp, nil
-}
-
-func (dec *Decoder) refill() error {
-	// Make room to read more into the buffer.
-	// First slide down data already consumed.
-	if dec.scanp > 0 {
-		n := copy(dec.buf, dec.buf[dec.scanp:])
-		dec.buf = dec.buf[:n]
-		dec.scanp = 0
-	}
+		// Make room to read more into the buffer.
+		const minRead = 512
+		if cap(dec.buf)-len(dec.buf) < minRead {
+			newBuf := make([]byte, len(dec.buf), 2*cap(dec.buf)+minRead)
+			copy(newBuf, dec.buf)
+			dec.buf = newBuf
+		}
 
-	// Grow buffer if not large enough.
-	const minRead = 512
-	if cap(dec.buf)-len(dec.buf) < minRead {
-		newBuf := make([]byte, len(dec.buf), 2*cap(dec.buf)+minRead)
-		copy(newBuf, dec.buf)
-		dec.buf = newBuf
+		// Read.  Delay error for next iteration (after scan).
+		var n int
+		n, err = dec.r.Read(dec.buf[len(dec.buf):cap(dec.buf)])
+		dec.buf = dec.buf[0 : len(dec.buf)+n]
 	}
-
-	// Read.  Delay error for next iteration (after scan).
-	n, err := dec.r.Read(dec.buf[len(dec.buf):cap(dec.buf)])
-	dec.buf = dec.buf[0 : len(dec.buf)+n]
-
-	return err
+	return scanp, nil
 }
 
 func nonSpace(b []byte) bool {
@@ -226,255 +198,3 @@ func (m *RawMessage) UnmarshalJSON(data []byte) error {
 
 var _ Marshaler = (*RawMessage)(nil)
 var _ Unmarshaler = (*RawMessage)(nil)
-
-// A Token holds a value of one of these types:
-//
-//	Delim, for the four JSON delimiters [ ] { }
-//	bool, for JSON booleans
-//	float64, for JSON numbers
-//	Number, for JSON numbers
-//	string, for JSON string literals
-//	nil, for JSON null
-//
-type Token interface{}
-
-const (
-	tokenTopValue = iota
-	tokenArrayStart
-	tokenArrayValue
-	tokenArrayComma
-	tokenObjectStart
-	tokenObjectKey
-	tokenObjectColon
-	tokenObjectValue
-	tokenObjectComma
-)
-
-// advance tokenstate from a separator state to a value state
-func (dec *Decoder) tokenPrepareForDecode() error {
-	// Note: Not calling peek before switch, to avoid
-	// putting peek into the standard Decode path.
-	// peek is only called when using the Token API.
-	switch dec.tokenState {
-	case tokenArrayComma:
-		c, err := dec.peek()
-		if err != nil {
-			return err
-		}
-		if c != ',' {
-			return &SyntaxError{"expected comma after array element", 0}
-		}
-		dec.scanp++
-		dec.tokenState = tokenArrayValue
-	case tokenObjectColon:
-		c, err := dec.peek()
-		if err != nil {
-			return err
-		}
-		if c != ':' {
-			return &SyntaxError{"expected colon after object key", 0}
-		}
-		dec.scanp++
-		dec.tokenState = tokenObjectValue
-	}
-	return nil
-}
-
-func (dec *Decoder) tokenValueAllowed() bool {
-	switch dec.tokenState {
-	case tokenTopValue, tokenArrayStart, tokenArrayValue, tokenObjectValue:
-		return true
-	}
-	return false
-}
-
-func (dec *Decoder) tokenValueEnd() {
-	switch dec.tokenState {
-	case tokenArrayStart, tokenArrayValue:
-		dec.tokenState = tokenArrayComma
-	case tokenObjectValue:
-		dec.tokenState = tokenObjectComma
-	}
-}
-
-// A Delim is a JSON array or object delimiter, one of [ ] { or }.
-type Delim rune
-
-func (d Delim) String() string {
-	return string(d)
-}
-
-// Token returns the next JSON token in the input stream.
-// At the end of the input stream, Token returns nil, io.EOF.
-//
-// Token guarantees that the delimiters [ ] { } it returns are
-// properly nested and matched: if Token encounters an unexpected
-// delimiter in the input, it will return an error.
-//
-// The input stream consists of basic JSON values—bool, string,
-// number, and null—along with delimiters [ ] { } of type Delim
-// to mark the start and end of arrays and objects.
-// Commas and colons are elided.
-func (dec *Decoder) Token() (Token, error) {
-	for {
-		c, err := dec.peek()
-		if err != nil {
-			return nil, err
-		}
-		switch c {
-		case '[':
-			if !dec.tokenValueAllowed() {
-				return dec.tokenError(c)
-			}
-			dec.scanp++
-			dec.tokenStack = append(dec.tokenStack, dec.tokenState)
-			dec.tokenState = tokenArrayStart
-			return Delim('['), nil
-
-		case ']':
-			if dec.tokenState != tokenArrayStart && dec.tokenState != tokenArrayComma {
-				return dec.tokenError(c)
-			}
-			dec.scanp++
-			dec.tokenState = dec.tokenStack[len(dec.tokenStack)-1]
-			dec.tokenStack = dec.tokenStack[:len(dec.tokenStack)-1]
-			dec.tokenValueEnd()
-			return Delim(']'), nil
-
-		case '{':
-			if !dec.tokenValueAllowed() {
-				return dec.tokenError(c)
-			}
-			dec.scanp++
-			dec.tokenStack = append(dec.tokenStack, dec.tokenState)
-			dec.tokenState = tokenObjectStart
-			return Delim('{'), nil
-
-		case '}':
-			if dec.tokenState != tokenObjectStart && dec.tokenState != tokenObjectComma {
-				return dec.tokenError(c)
-			}
-			dec.scanp++
-			dec.tokenState = dec.tokenStack[len(dec.tokenStack)-1]
-			dec.tokenStack = dec.tokenStack[:len(dec.tokenStack)-1]
-			dec.tokenValueEnd()
-			return Delim('}'), nil
-
-		case ':':
-			if dec.tokenState != tokenObjectColon {
-				return dec.tokenError(c)
-			}
-			dec.scanp++
-			dec.tokenState = tokenObjectValue
-			continue
-
-		case ',':
-			if dec.tokenState == tokenArrayComma {
-				dec.scanp++
-				dec.tokenState = tokenArrayValue
-				continue
-			}
-			if dec.tokenState == tokenObjectComma {
-				dec.scanp++
-				dec.tokenState = tokenObjectKey
-				continue
-			}
-			return dec.tokenError(c)
-
-		case '"':
-			if dec.tokenState == tokenObjectStart || dec.tokenState == tokenObjectKey {
-				var x string
-				old := dec.tokenState
-				dec.tokenState = tokenTopValue
-				err := dec.Decode(&x)
-				dec.tokenState = old
-				if err != nil {
-					clearOffset(err)
-					return nil, err
-				}
-				dec.tokenState = tokenObjectColon
-				return x, nil
-			}
-			fallthrough
-
-		default:
-			if !dec.tokenValueAllowed() {
-				return dec.tokenError(c)
-			}
-			var x interface{}
-			if err := dec.Decode(&x); err != nil {
-				clearOffset(err)
-				return nil, err
-			}
-			return x, nil
-		}
-	}
-}
-
-func clearOffset(err error) {
-	if s, ok := err.(*SyntaxError); ok {
-		s.Offset = 0
-	}
-}
-
-func (dec *Decoder) tokenError(c byte) (Token, error) {
-	var context string
-	switch dec.tokenState {
-	case tokenTopValue:
-		context = " looking for beginning of value"
-	case tokenArrayStart, tokenArrayValue, tokenObjectValue:
-		context = " looking for beginning of value"
-	case tokenArrayComma:
-		context = " after array element"
-	case tokenObjectKey:
-		context = " looking for beginning of object key string"
-	case tokenObjectColon:
-		context = " after object key"
-	case tokenObjectComma:
-		context = " after object key:value pair"
-	}
-	return nil, &SyntaxError{"invalid character " + quoteChar(int(c)) + " " + context, 0}
-}
-
-// More reports whether there is another element in the
-// current array or object being parsed.
-func (dec *Decoder) More() bool {
-	c, err := dec.peek()
-	return err == nil && c != ']' && c != '}'
-}
-
-func (dec *Decoder) peek() (byte, error) {
-	var err error
-	for {
-		for i := dec.scanp; i < len(dec.buf); i++ {
-			c := dec.buf[i]
-			if isSpace(rune(c)) {
-				continue
-			}
-			dec.scanp = i
-			return c, nil
-		}
-		// buffer has been scanned, now report any error
-		if err != nil {
-			return 0, err
-		}
-		err = dec.refill()
-	}
-}
-
-/*
-TODO
-
-// EncodeToken writes the given JSON token to the stream.
-// It returns an error if the delimiters [ ] { } are not properly used.
-//
-// EncodeToken does not call Flush, because usually it is part of
-// a larger operation such as Encode, and those will call Flush when finished.
-// Callers that create an Encoder and then invoke EncodeToken directly,
-// without using Encode, need to call Flush when finished to ensure that
-// the JSON is written to the underlying writer.
-func (e *Encoder) EncodeToken(t Token) error  {
-	...
-}
-
-*/
diff --git a/src/encoding/json/stream_test.go b/src/encoding/json/stream_test.go
index c2e3040..b562e87 100644
--- a/src/encoding/json/stream_test.go
+++ b/src/encoding/json/stream_test.go
@@ -6,12 +6,8 @@ package json
 
 import (
 	"bytes"
-	"io"
 	"io/ioutil"
-	"log"
 	"net"
-	"net/http"
-	"net/http/httptest"
 	"reflect"
 	"strings"
 	"testing"
@@ -208,147 +204,3 @@ func BenchmarkEncoderEncode(b *testing.B) {
 		}
 	}
 }
-
-type tokenStreamCase struct {
-	json      string
-	expTokens []interface{}
-}
-
-type decodeThis struct {
-	v interface{}
-}
-
-var tokenStreamCases []tokenStreamCase = []tokenStreamCase{
-	// streaming token cases
-	{json: `10`, expTokens: []interface{}{float64(10)}},
-	{json: ` [10] `, expTokens: []interface{}{
-		Delim('['), float64(10), Delim(']')}},
-	{json: ` [false,10,"b"] `, expTokens: []interface{}{
-		Delim('['), false, float64(10), "b", Delim(']')}},
-	{json: `{ "a": 1 }`, expTokens: []interface{}{
-		Delim('{'), "a", float64(1), Delim('}')}},
-	{json: `{"a": 1, "b":"3"}`, expTokens: []interface{}{
-		Delim('{'), "a", float64(1), "b", "3", Delim('}')}},
-	{json: ` [{"a": 1},{"a": 2}] `, expTokens: []interface{}{
-		Delim('['),
-		Delim('{'), "a", float64(1), Delim('}'),
-		Delim('{'), "a", float64(2), Delim('}'),
-		Delim(']')}},
-	{json: `{"obj": {"a": 1}}`, expTokens: []interface{}{
-		Delim('{'), "obj", Delim('{'), "a", float64(1), Delim('}'),
-		Delim('}')}},
-	{json: `{"obj": [{"a": 1}]}`, expTokens: []interface{}{
-		Delim('{'), "obj", Delim('['),
-		Delim('{'), "a", float64(1), Delim('}'),
-		Delim(']'), Delim('}')}},
-
-	// streaming tokens with intermittent Decode()
-	{json: `{ "a": 1 }`, expTokens: []interface{}{
-		Delim('{'), "a",
-		decodeThis{float64(1)},
-		Delim('}')}},
-	{json: ` [ { "a" : 1 } ] `, expTokens: []interface{}{
-		Delim('['),
-		decodeThis{map[string]interface{}{"a": float64(1)}},
-		Delim(']')}},
-	{json: ` [{"a": 1},{"a": 2}] `, expTokens: []interface{}{
-		Delim('['),
-		decodeThis{map[string]interface{}{"a": float64(1)}},
-		decodeThis{map[string]interface{}{"a": float64(2)}},
-		Delim(']')}},
-	{json: `{ "obj" : [ { "a" : 1 } ] }`, expTokens: []interface{}{
-		Delim('{'), "obj", Delim('['),
-		decodeThis{map[string]interface{}{"a": float64(1)}},
-		Delim(']'), Delim('}')}},
-
-	{json: `{"obj": {"a": 1}}`, expTokens: []interface{}{
-		Delim('{'), "obj",
-		decodeThis{map[string]interface{}{"a": float64(1)}},
-		Delim('}')}},
-	{json: `{"obj": [{"a": 1}]}`, expTokens: []interface{}{
-		Delim('{'), "obj",
-		decodeThis{[]interface{}{
-			map[string]interface{}{"a": float64(1)},
-		}},
-		Delim('}')}},
-	{json: ` [{"a": 1} {"a": 2}] `, expTokens: []interface{}{
-		Delim('['),
-		decodeThis{map[string]interface{}{"a": float64(1)}},
-		decodeThis{&SyntaxError{"expected comma after array element", 0}},
-	}},
-	{json: `{ "a" 1 }`, expTokens: []interface{}{
-		Delim('{'), "a",
-		decodeThis{&SyntaxError{"expected colon after object key", 0}},
-	}},
-}
-
-func TestDecodeInStream(t *testing.T) {
-
-	for ci, tcase := range tokenStreamCases {
-
-		dec := NewDecoder(strings.NewReader(tcase.json))
-		for i, etk := range tcase.expTokens {
-
-			var tk interface{}
-			var err error
-
-			if dt, ok := etk.(decodeThis); ok {
-				etk = dt.v
-				err = dec.Decode(&tk)
-			} else {
-				tk, err = dec.Token()
-			}
-			if experr, ok := etk.(error); ok {
-				if err == nil || err.Error() != experr.Error() {
-					t.Errorf("case %v: Expected error %v in %q, but was %v", ci, experr, tcase.json, err)
-				}
-				break
-			} else if err == io.EOF {
-				t.Errorf("case %v: Unexpected EOF in %q", ci, tcase.json)
-				break
-			} else if err != nil {
-				t.Errorf("case %v: Unexpected error '%v' in %q", ci, err, tcase.json)
-				break
-			}
-			if !reflect.DeepEqual(tk, etk) {
-				t.Errorf(`case %v: %q @ %v expected %T(%v) was %T(%v)`, ci, tcase.json, i, etk, etk, tk, tk)
-				break
-			}
-		}
-	}
-
-}
-
-// Test from golang.org/issue/11893
-func TestHTTPDecoding(t *testing.T) {
-	const raw = `{ "foo": "bar" }`
-
-	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
-		w.Write([]byte(raw))
-	}))
-	defer ts.Close()
-	res, err := http.Get(ts.URL)
-	if err != nil {
-		log.Fatalf("GET failed: %v", err)
-	}
-	defer res.Body.Close()
-
-	foo := struct {
-		Foo string
-	}{}
-
-	d := NewDecoder(res.Body)
-	err = d.Decode(&foo)
-	if err != nil {
-		t.Fatalf("Decode: %v", err)
-	}
-	if foo.Foo != "bar" {
-		t.Errorf("decoded %q; want \"bar\"", foo.Foo)
-	}
-
-	// make sure we get the EOF the second time
-	err = d.Decode(&foo)
-	if err != io.EOF {
-		t.Errorf("err = %v; want io.EOF", err)
-	}
-}
diff --git a/src/encoding/json/tagkey_test.go b/src/encoding/json/tagkey_test.go
index 85bb4ba..23e71c7 100644
--- a/src/encoding/json/tagkey_test.go
+++ b/src/encoding/json/tagkey_test.go
@@ -37,11 +37,11 @@ type miscPlaneTag struct {
 }
 
 type percentSlashTag struct {
-	V string `json:"text/html%"` // https://golang.org/issue/2718
+	V string `json:"text/html%"` // http://golang.org/issue/2718
 }
 
 type punctuationTag struct {
-	V string `json:"!#$%&()*+-./:<=>?@[]^_{|}~"` // https://golang.org/issue/3546
+	V string `json:"!#$%&()*+-./:<=>?@[]^_{|}~"` // http://golang.org/issue/3546
 }
 
 type emptyTag struct {
diff --git a/src/encoding/pem/pem.go b/src/encoding/pem/pem.go
index 506196b..8ff7ee8 100644
--- a/src/encoding/pem/pem.go
+++ b/src/encoding/pem/pem.go
@@ -10,10 +10,8 @@ package pem
 import (
 	"bytes"
 	"encoding/base64"
-	"errors"
 	"io"
 	"sort"
-	"strings"
 )
 
 // A Block represents a PEM encoded structure.
@@ -112,37 +110,27 @@ func Decode(data []byte) (p *Block, rest []byte) {
 		}
 
 		// TODO(agl): need to cope with values that spread across lines.
-		key, val := line[:i], line[i+1:]
+		key, val := line[0:i], line[i+1:]
 		key = bytes.TrimSpace(key)
 		val = bytes.TrimSpace(val)
 		p.Headers[string(key)] = string(val)
 		rest = next
 	}
 
-	var endIndex int
-	// If there were no headers, the END line might occur
-	// immediately, without a leading newline.
-	if len(p.Headers) == 0 && bytes.HasPrefix(rest, pemEnd[1:]) {
-		endIndex = 0
-	} else {
-		endIndex = bytes.Index(rest, pemEnd)
-	}
-
-	if endIndex < 0 {
+	i := bytes.Index(rest, pemEnd)
+	if i < 0 {
 		return decodeError(data, rest)
 	}
+	base64Data := removeWhitespace(rest[0:i])
 
-	base64Data := removeWhitespace(rest[:endIndex])
 	p.Bytes = make([]byte, base64.StdEncoding.DecodedLen(len(base64Data)))
 	n, err := base64.StdEncoding.Decode(p.Bytes, base64Data)
 	if err != nil {
 		return decodeError(data, rest)
 	}
-	p.Bytes = p.Bytes[:n]
+	p.Bytes = p.Bytes[0:n]
 
-	// the -1 is because we might have only matched pemEnd without the
-	// leading newline if the PEM block was empty.
-	_, rest = getLine(rest[endIndex+len(pemEnd)-1:])
+	_, rest = getLine(rest[i+len(pemEnd):])
 
 	return
 }
@@ -183,8 +171,6 @@ type lineBreaker struct {
 	out  io.Writer
 }
 
-var nl = []byte{'\n'}
-
 func (l *lineBreaker) Write(b []byte) (n int, err error) {
 	if l.used+len(b) < pemLineLength {
 		copy(l.line[l.used:], b)
@@ -204,7 +190,7 @@ func (l *lineBreaker) Write(b []byte) (n int, err error) {
 		return
 	}
 
-	n, err = l.out.Write(nl)
+	n, err = l.out.Write([]byte{'\n'})
 	if err != nil {
 		return
 	}
@@ -218,7 +204,7 @@ func (l *lineBreaker) Close() (err error) {
 		if err != nil {
 			return
 		}
-		_, err = l.out.Write(nl)
+		_, err = l.out.Write([]byte{'\n'})
 	}
 
 	return
@@ -258,14 +244,11 @@ func Encode(out io.Writer, b *Block) error {
 		// For consistency of output, write other headers sorted by key.
 		sort.Strings(h)
 		for _, k := range h {
-			if strings.Contains(k, ":") {
-				return errors.New("pem: cannot encode a header key that contains a colon")
-			}
 			if err := writeHeader(out, k, b.Headers[k]); err != nil {
 				return err
 			}
 		}
-		if _, err := out.Write(nl); err != nil {
+		if _, err := out.Write([]byte{'\n'}); err != nil {
 			return err
 		}
 	}
diff --git a/src/encoding/pem/pem_test.go b/src/encoding/pem/pem_test.go
index ab656c6..ccce42c 100644
--- a/src/encoding/pem/pem_test.go
+++ b/src/encoding/pem/pem_test.go
@@ -6,11 +6,8 @@ package pem
 
 import (
 	"bytes"
-	"io/ioutil"
 	"reflect"
-	"strings"
 	"testing"
-	"testing/quick"
 )
 
 type GetLineTest struct {
@@ -46,32 +43,6 @@ func TestDecode(t *testing.T) {
 	if !reflect.DeepEqual(result, privateKey) {
 		t.Errorf("#1 got:%#v want:%#v", result, privateKey)
 	}
-
-	isEmpty := func(block *Block) bool {
-		return block != nil && block.Type == "EMPTY" && len(block.Headers) == 0 && len(block.Bytes) == 0
-	}
-	result, remainder = Decode(remainder)
-	if !isEmpty(result) {
-		t.Errorf("#2 should be empty but got:%#v", result)
-	}
-	result, remainder = Decode(remainder)
-	if !isEmpty(result) {
-		t.Errorf("#3 should be empty but got:%#v", result)
-	}
-	result, remainder = Decode(remainder)
-	if !isEmpty(result) {
-		t.Errorf("#4 should be empty but got:%#v", result)
-	}
-
-	result, remainder = Decode(remainder)
-	if result == nil || result.Type != "HEADERS" || len(result.Headers) != 1 {
-		t.Errorf("#5 expected single header block but got :%v", result)
-	}
-
-	if len(remainder) != 0 {
-		t.Errorf("expected nothing remaining of pemData, but found %s", string(remainder))
-	}
-
 	result, _ = Decode([]byte(pemPrivateKey2))
 	if !reflect.DeepEqual(result, privateKey2) {
 		t.Errorf("#2 got:%#v want:%#v", result, privateKey2)
@@ -145,62 +116,6 @@ func TestLineBreaker(t *testing.T) {
 	}
 }
 
-func TestFuzz(t *testing.T) {
-	testRoundtrip := func(block Block) bool {
-		for key := range block.Headers {
-			if strings.Contains(key, ":") {
-				// Keys with colons cannot be encoded.
-				return true
-			}
-		}
-
-		var buf bytes.Buffer
-		err := Encode(&buf, &block)
-		decoded, rest := Decode(buf.Bytes())
-
-		switch {
-		case err != nil:
-			t.Errorf("Encode of %#v resulted in error: %s", &block, err)
-		case !reflect.DeepEqual(&block, decoded):
-			t.Errorf("Encode of %#v decoded as %#v", &block, decoded)
-		case len(rest) != 0:
-			t.Errorf("Encode of %#v decoded correctly, but with %x left over", block, rest)
-		default:
-			return true
-		}
-		return false
-	}
-
-	// Explicitly test the empty block.
-	if !testRoundtrip(Block{
-		Type:    "EMPTY",
-		Headers: make(map[string]string),
-		Bytes:   []byte{},
-	}) {
-		return
-	}
-
-	quick.Check(testRoundtrip, nil)
-}
-
-func BenchmarkEncode(b *testing.B) {
-	data := &Block{Bytes: make([]byte, 65536)}
-	b.SetBytes(int64(len(data.Bytes)))
-	for i := 0; i < b.N; i++ {
-		Encode(ioutil.Discard, data)
-	}
-}
-
-func BenchmarkDecode(b *testing.B) {
-	block := &Block{Bytes: make([]byte, 65536)}
-	data := EncodeToMemory(block)
-	b.SetBytes(int64(len(data)))
-	b.ResetTimer()
-	for i := 0; i < b.N; i++ {
-		Decode(data)
-	}
-}
-
 var pemData = `verify return:0
 -----BEGIN CERTIFICATE-----
 sdlfkjskldfj
@@ -254,32 +169,7 @@ BTiHcL3s3KrJu1vDVrshvxfnz71KTeNnZH8UbOqT5i7fPGyXtY1XJddcbI/Q6tXf
 wHFsZc20TzSdsVLBtwksUacpbDogcEVMctnNrB8FIrB3vZEv9Q0Z1VeY7nmTpF+6
 a+z2P7acL7j6A6Pr3+q8P9CPiPC7zFonVzuVPyB8GchGR2hytyiOVpuD9+k8hcuw
 ZWAaUoVtWIQ52aKS0p19G99hhb+IVANC4akkdHV4SP8i7MVNZhfUmg==
------END RSA PRIVATE KEY-----
-
-
------BEGIN EMPTY-----
------END EMPTY-----
-
------BEGIN EMPTY-----
-
------END EMPTY-----
-
------BEGIN EMPTY-----
-
-
------END EMPTY-----
-
-# This shouldn't be recognised because of the missing newline after the
-headers.
------BEGIN HEADERS-----
-Header: 1
------END HEADERS-----
-
-# This should be valid, however.
------BEGIN HEADERS-----
-Header: 1
-
------END HEADERS-----`
+-----END RSA PRIVATE KEY-----`
 
 var certificate = &Block{Type: "CERTIFICATE",
 	Headers: map[string]string{},
diff --git a/src/encoding/xml/marshal.go b/src/encoding/xml/marshal.go
index 86d1422..8c63420 100644
--- a/src/encoding/xml/marshal.go
+++ b/src/encoding/xml/marshal.go
@@ -173,7 +173,6 @@ func (enc *Encoder) EncodeElement(v interface{}, start StartElement) error {
 }
 
 var (
-	begComment   = []byte("<!--")
 	endComment   = []byte("-->")
 	endProcInst  = []byte("?>")
 	endDirective = []byte(">")
@@ -192,7 +191,6 @@ var (
 // 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) {
 	case StartElement:
@@ -204,7 +202,7 @@ func (enc *Encoder) EncodeToken(t Token) error {
 			return err
 		}
 	case CharData:
-		escapeText(p, t, false)
+		EscapeText(p, t)
 	case Comment:
 		if bytes.Contains(t, endComment) {
 			return fmt.Errorf("xml: EncodeToken of Comment containing --> marker")
@@ -233,59 +231,16 @@ func (enc *Encoder) EncodeToken(t Token) error {
 		}
 		p.WriteString("?>")
 	case Directive:
-		if !isValidDirective(t) {
-			return fmt.Errorf("xml: EncodeToken of Directive containing wrong < or > markers")
+		if bytes.Contains(t, endDirective) {
+			return fmt.Errorf("xml: EncodeToken of Directive containing > marker")
 		}
 		p.WriteString("<!")
 		p.Write(t)
 		p.WriteString(">")
-	default:
-		return fmt.Errorf("xml: EncodeToken of invalid token type")
-
 	}
 	return p.cachedWriteError()
 }
 
-// isValidDirective reports whether dir is a valid directive text,
-// meaning angle brackets are matched, ignoring comments and strings.
-func isValidDirective(dir Directive) bool {
-	var (
-		depth     int
-		inquote   uint8
-		incomment bool
-	)
-	for i, c := range dir {
-		switch {
-		case incomment:
-			if c == '>' {
-				if n := 1 + i - len(endComment); n >= 0 && bytes.Equal(dir[n:i+1], endComment) {
-					incomment = false
-				}
-			}
-			// Just ignore anything in comment
-		case inquote != 0:
-			if c == inquote {
-				inquote = 0
-			}
-			// Just ignore anything within quotes
-		case c == '\'' || c == '"':
-			inquote = c
-		case c == '<':
-			if i+len(begComment) < len(dir) && bytes.Equal(dir[i:i+len(begComment)], begComment) {
-				incomment = true
-			} else {
-				depth++
-			}
-		case c == '>':
-			if depth == 0 {
-				return false
-			}
-			depth--
-		}
-	}
-	return depth == 0 && inquote == 0 && !incomment
-}
-
 // Flush flushes any buffered XML to the underlying writer.
 // See the EncodeToken documentation for details about when it is necessary.
 func (enc *Encoder) Flush() error {
@@ -769,9 +724,6 @@ func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error {
 
 		switch finfo.flags & fMode {
 		case fCharData:
-			if err := s.trim(finfo.parents); err != nil {
-				return err
-			}
 			if vf.CanInterface() && vf.Type().Implements(textMarshalerType) {
 				data, err := vf.Interface().(encoding.TextMarshaler).MarshalText()
 				if err != nil {
@@ -815,9 +767,6 @@ func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error {
 			continue
 
 		case fComment:
-			if err := s.trim(finfo.parents); err != nil {
-				return err
-			}
 			k := vf.Kind()
 			if !(k == reflect.String || k == reflect.Slice && vf.Type().Elem().Kind() == reflect.Uint8) {
 				return fmt.Errorf("xml: bad type for comment field of %s", val.Type())
@@ -945,7 +894,7 @@ func (s *parentStack) trim(parents []string) error {
 			return err
 		}
 	}
-	s.stack = s.stack[:split]
+	s.stack = parents[:split]
 	return nil
 }
 
diff --git a/src/encoding/xml/marshal_test.go b/src/encoding/xml/marshal_test.go
index 66675d7..14f73a7 100644
--- a/src/encoding/xml/marshal_test.go
+++ b/src/encoding/xml/marshal_test.go
@@ -12,7 +12,6 @@ import (
 	"reflect"
 	"strconv"
 	"strings"
-	"sync"
 	"testing"
 	"time"
 )
@@ -340,16 +339,6 @@ type OuterOuterStruct struct {
 	OuterStruct
 }
 
-type NestedAndChardata struct {
-	AB       []string `xml:"A>B"`
-	Chardata string   `xml:",chardata"`
-}
-
-type NestedAndComment struct {
-	AB      []string `xml:"A>B"`
-	Comment string   `xml:",comment"`
-}
-
 func ifaceptr(x interface{}) interface{} {
 	return &x
 }
@@ -628,69 +617,6 @@ var marshalTests = []struct {
 			`</service>`,
 		MarshalOnly: true,
 	},
-	{
-		Value: &struct {
-			XMLName struct{} `xml:"space top"`
-			A       string   `xml:"x>a"`
-			B       string   `xml:"x>b"`
-			C       string   `xml:"space x>c"`
-			C1      string   `xml:"space1 x>c"`
-			D1      string   `xml:"space1 x>d"`
-		}{
-			A:  "a",
-			B:  "b",
-			C:  "c",
-			C1: "c1",
-			D1: "d1",
-		},
-		ExpectXML: `<top xmlns="space">` +
-			`<x><a>a</a><b>b</b><c xmlns="space">c</c>` +
-			`<c xmlns="space1">c1</c>` +
-			`<d xmlns="space1">d1</d>` +
-			`</x>` +
-			`</top>`,
-	},
-	{
-		Value: &struct {
-			XMLName Name
-			A       string `xml:"x>a"`
-			B       string `xml:"x>b"`
-			C       string `xml:"space x>c"`
-			C1      string `xml:"space1 x>c"`
-			D1      string `xml:"space1 x>d"`
-		}{
-			XMLName: Name{
-				Space: "space0",
-				Local: "top",
-			},
-			A:  "a",
-			B:  "b",
-			C:  "c",
-			C1: "c1",
-			D1: "d1",
-		},
-		ExpectXML: `<top xmlns="space0">` +
-			`<x><a>a</a><b>b</b>` +
-			`<c xmlns="space">c</c>` +
-			`<c xmlns="space1">c1</c>` +
-			`<d xmlns="space1">d1</d>` +
-			`</x>` +
-			`</top>`,
-	},
-	{
-		Value: &struct {
-			XMLName struct{} `xml:"top"`
-			B       string   `xml:"space x>b"`
-			B1      string   `xml:"space1 x>b"`
-		}{
-			B:  "b",
-			B1: "b1",
-		},
-		ExpectXML: `<top>` +
-			`<x><b xmlns="space">b</b>` +
-			`<b xmlns="space1">b1</b></x>` +
-			`</top>`,
-	},
 
 	// Test struct embedding
 	{
@@ -998,14 +924,6 @@ var marshalTests = []struct {
 		ExpectXML: `<outer xmlns="testns" int="10"></outer>`,
 		Value:     &OuterOuterStruct{OuterStruct{IntAttr: 10}},
 	},
-	{
-		ExpectXML: `<NestedAndChardata><A><B></B><B></B></A>test</NestedAndChardata>`,
-		Value:     &NestedAndChardata{AB: make([]string, 2), Chardata: "test"},
-	},
-	{
-		ExpectXML: `<NestedAndComment><A><B></B><B></B></A><!--test--></NestedAndComment>`,
-		Value:     &NestedAndComment{AB: make([]string, 2), Comment: "test"},
-	},
 }
 
 func TestMarshal(t *testing.T) {
@@ -1015,7 +933,7 @@ func TestMarshal(t *testing.T) {
 		}
 		data, err := Marshal(test.Value)
 		if err != nil {
-			t.Errorf("#%d: marshal(%#v): %s", idx, test.Value, err)
+			t.Errorf("#%d: Error: %s", idx, err)
 			continue
 		}
 		if got, want := string(data), test.ExpectXML; got != want {
@@ -1119,14 +1037,6 @@ func TestUnmarshal(t *testing.T) {
 		if _, ok := test.Value.(*Plain); ok {
 			continue
 		}
-		if test.ExpectXML == `<top>`+
-			`<x><b xmlns="space">b</b>`+
-			`<b xmlns="space1">b1</b></x>`+
-			`</top>` {
-			// TODO(rogpeppe): re-enable this test in
-			// https://go-review.googlesource.com/#/c/5910/
-			continue
-		}
 
 		vt := reflect.TypeOf(test.Value)
 		dest := reflect.New(vt.Elem()).Interface()
@@ -1238,14 +1148,12 @@ func TestMarshalFlush(t *testing.T) {
 }
 
 func BenchmarkMarshal(b *testing.B) {
-	b.ReportAllocs()
 	for i := 0; i < b.N; i++ {
 		Marshal(atomValue)
 	}
 }
 
 func BenchmarkUnmarshal(b *testing.B) {
-	b.ReportAllocs()
 	xml := []byte(atomXml)
 	for i := 0; i < b.N; i++ {
 		Unmarshal(xml, &Feed{})
@@ -1284,369 +1192,41 @@ func TestStructPointerMarshal(t *testing.T) {
 }
 
 var encodeTokenTests = []struct {
-	desc string
-	toks []Token
+	tok  Token
 	want string
-	err  string
-}{{
-	desc: "start element with name space",
-	toks: []Token{
-		StartElement{Name{"space", "local"}, nil},
-	},
-	want: `<local xmlns="space">`,
-}, {
-	desc: "start element with no name",
-	toks: []Token{
-		StartElement{Name{"space", ""}, nil},
-	},
-	err: "xml: start tag with no name",
-}, {
-	desc: "end element with no name",
-	toks: []Token{
-		EndElement{Name{"space", ""}},
-	},
-	err: "xml: end tag with no name",
-}, {
-	desc: "char data",
-	toks: []Token{
-		CharData("foo"),
-	},
-	want: `foo`,
-}, {
-	desc: "char data with escaped chars",
-	toks: []Token{
-		CharData(" \t\n"),
-	},
-	want: " &#x9;\n",
-}, {
-	desc: "comment",
-	toks: []Token{
-		Comment("foo"),
-	},
-	want: `<!--foo-->`,
-}, {
-	desc: "comment with invalid content",
-	toks: []Token{
-		Comment("foo-->"),
-	},
-	err: "xml: EncodeToken of Comment containing --> marker",
-}, {
-	desc: "proc instruction",
-	toks: []Token{
-		ProcInst{"Target", []byte("Instruction")},
-	},
-	want: `<?Target Instruction?>`,
-}, {
-	desc: "proc instruction with empty target",
-	toks: []Token{
-		ProcInst{"", []byte("Instruction")},
-	},
-	err: "xml: EncodeToken of ProcInst with invalid Target",
-}, {
-	desc: "proc instruction with bad content",
-	toks: []Token{
-		ProcInst{"", []byte("Instruction?>")},
-	},
-	err: "xml: EncodeToken of ProcInst with invalid Target",
-}, {
-	desc: "directive",
-	toks: []Token{
-		Directive("foo"),
-	},
-	want: `<!foo>`,
-}, {
-	desc: "more complex directive",
-	toks: []Token{
-		Directive("DOCTYPE doc [ <!ELEMENT doc '>'> <!-- com>ment --> ]"),
-	},
-	want: `<!DOCTYPE doc [ <!ELEMENT doc '>'> <!-- com>ment --> ]>`,
-}, {
-	desc: "directive instruction with bad name",
-	toks: []Token{
-		Directive("foo>"),
-	},
-	err: "xml: EncodeToken of Directive containing wrong < or > markers",
-}, {
-	desc: "end tag without start tag",
-	toks: []Token{
-		EndElement{Name{"foo", "bar"}},
-	},
-	err: "xml: end tag </bar> without start tag",
-}, {
-	desc: "mismatching end tag local name",
-	toks: []Token{
-		StartElement{Name{"", "foo"}, nil},
-		EndElement{Name{"", "bar"}},
-	},
-	err:  "xml: end tag </bar> does not match start tag <foo>",
-	want: `<foo>`,
-}, {
-	desc: "mismatching end tag namespace",
-	toks: []Token{
-		StartElement{Name{"space", "foo"}, nil},
-		EndElement{Name{"another", "foo"}},
-	},
-	err:  "xml: end tag </foo> in namespace another does not match start tag <foo> in namespace space",
-	want: `<foo xmlns="space">`,
-}, {
-	desc: "start element with explicit namespace",
-	toks: []Token{
-		StartElement{Name{"space", "local"}, []Attr{
-			{Name{"xmlns", "x"}, "space"},
-			{Name{"space", "foo"}, "value"},
-		}},
-	},
-	want: `<local xmlns="space" xmlns:_xmlns="xmlns" _xmlns:x="space" xmlns:space="space" space:foo="value">`,
-}, {
-	desc: "start element with explicit namespace and colliding prefix",
-	toks: []Token{
-		StartElement{Name{"space", "local"}, []Attr{
-			{Name{"xmlns", "x"}, "space"},
-			{Name{"space", "foo"}, "value"},
-			{Name{"x", "bar"}, "other"},
-		}},
-	},
-	want: `<local xmlns="space" xmlns:_xmlns="xmlns" _xmlns:x="space" xmlns:space="space" space:foo="value" xmlns:x="x" x:bar="other">`,
-}, {
-	desc: "start element using previously defined namespace",
-	toks: []Token{
-		StartElement{Name{"", "local"}, []Attr{
-			{Name{"xmlns", "x"}, "space"},
-		}},
-		StartElement{Name{"space", "foo"}, []Attr{
-			{Name{"space", "x"}, "y"},
-		}},
-	},
-	want: `<local xmlns:_xmlns="xmlns" _xmlns:x="space"><foo xmlns="space" xmlns:space="space" space:x="y">`,
-}, {
-	desc: "nested name space with same prefix",
-	toks: []Token{
-		StartElement{Name{"", "foo"}, []Attr{
-			{Name{"xmlns", "x"}, "space1"},
-		}},
-		StartElement{Name{"", "foo"}, []Attr{
-			{Name{"xmlns", "x"}, "space2"},
-		}},
-		StartElement{Name{"", "foo"}, []Attr{
-			{Name{"space1", "a"}, "space1 value"},
-			{Name{"space2", "b"}, "space2 value"},
-		}},
-		EndElement{Name{"", "foo"}},
-		EndElement{Name{"", "foo"}},
-		StartElement{Name{"", "foo"}, []Attr{
-			{Name{"space1", "a"}, "space1 value"},
-			{Name{"space2", "b"}, "space2 value"},
-		}},
-	},
-	want: `<foo xmlns:_xmlns="xmlns" _xmlns:x="space1"><foo _xmlns:x="space2"><foo xmlns:space1="space1" space1:a="space1 value" xmlns:space2="space2" space2:b="space2 value"></foo></foo><foo xmlns:space1="space1" space1:a="space1 value" xmlns:space2="space2" space2:b="space2 value">`,
-}, {
-	desc: "start element defining several prefixes for the same name space",
-	toks: []Token{
-		StartElement{Name{"space", "foo"}, []Attr{
-			{Name{"xmlns", "a"}, "space"},
-			{Name{"xmlns", "b"}, "space"},
-			{Name{"space", "x"}, "value"},
-		}},
-	},
-	want: `<foo xmlns="space" xmlns:_xmlns="xmlns" _xmlns:a="space" _xmlns:b="space" xmlns:space="space" space:x="value">`,
-}, {
-	desc: "nested element redefines name space",
-	toks: []Token{
-		StartElement{Name{"", "foo"}, []Attr{
-			{Name{"xmlns", "x"}, "space"},
-		}},
-		StartElement{Name{"space", "foo"}, []Attr{
-			{Name{"xmlns", "y"}, "space"},
-			{Name{"space", "a"}, "value"},
-		}},
-	},
-	want: `<foo xmlns:_xmlns="xmlns" _xmlns:x="space"><foo xmlns="space" _xmlns:y="space" xmlns:space="space" space:a="value">`,
-}, {
-	desc: "nested element creates alias for default name space",
-	toks: []Token{
-		StartElement{Name{"space", "foo"}, []Attr{
-			{Name{"", "xmlns"}, "space"},
-		}},
-		StartElement{Name{"space", "foo"}, []Attr{
-			{Name{"xmlns", "y"}, "space"},
-			{Name{"space", "a"}, "value"},
-		}},
-	},
-	want: `<foo xmlns="space" xmlns="space"><foo xmlns="space" xmlns:_xmlns="xmlns" _xmlns:y="space" xmlns:space="space" space:a="value">`,
-}, {
-	desc: "nested element defines default name space with existing prefix",
-	toks: []Token{
-		StartElement{Name{"", "foo"}, []Attr{
-			{Name{"xmlns", "x"}, "space"},
-		}},
-		StartElement{Name{"space", "foo"}, []Attr{
-			{Name{"", "xmlns"}, "space"},
-			{Name{"space", "a"}, "value"},
-		}},
-	},
-	want: `<foo xmlns:_xmlns="xmlns" _xmlns:x="space"><foo xmlns="space" xmlns="space" xmlns:space="space" space:a="value">`,
-}, {
-	desc: "nested element uses empty attribute name space when default ns defined",
-	toks: []Token{
-		StartElement{Name{"space", "foo"}, []Attr{
-			{Name{"", "xmlns"}, "space"},
-		}},
-		StartElement{Name{"space", "foo"}, []Attr{
-			{Name{"", "attr"}, "value"},
-		}},
-	},
-	want: `<foo xmlns="space" xmlns="space"><foo xmlns="space" attr="value">`,
-}, {
-	desc: "redefine xmlns",
-	toks: []Token{
-		StartElement{Name{"", "foo"}, []Attr{
-			{Name{"foo", "xmlns"}, "space"},
-		}},
-	},
-	want: `<foo xmlns:foo="foo" foo:xmlns="space">`,
-}, {
-	desc: "xmlns with explicit name space #1",
-	toks: []Token{
-		StartElement{Name{"space", "foo"}, []Attr{
-			{Name{"xml", "xmlns"}, "space"},
-		}},
-	},
-	want: `<foo xmlns="space" xmlns:_xml="xml" _xml:xmlns="space">`,
-}, {
-	desc: "xmlns with explicit name space #2",
-	toks: []Token{
-		StartElement{Name{"space", "foo"}, []Attr{
-			{Name{xmlURL, "xmlns"}, "space"},
-		}},
-	},
-	want: `<foo xmlns="space" xml:xmlns="space">`,
-}, {
-	desc: "empty name space declaration is ignored",
-	toks: []Token{
-		StartElement{Name{"", "foo"}, []Attr{
-			{Name{"xmlns", "foo"}, ""},
-		}},
-	},
-	want: `<foo xmlns:_xmlns="xmlns" _xmlns:foo="">`,
-}, {
-	desc: "attribute with no name is ignored",
-	toks: []Token{
-		StartElement{Name{"", "foo"}, []Attr{
-			{Name{"", ""}, "value"},
-		}},
-	},
-	want: `<foo>`,
-}, {
-	desc: "namespace URL with non-valid name",
-	toks: []Token{
-		StartElement{Name{"/34", "foo"}, []Attr{
-			{Name{"/34", "x"}, "value"},
-		}},
-	},
-	want: `<foo xmlns="/34" xmlns:_="/34" _:x="value">`,
-}, {
-	desc: "nested element resets default namespace to empty",
-	toks: []Token{
-		StartElement{Name{"space", "foo"}, []Attr{
-			{Name{"", "xmlns"}, "space"},
-		}},
-		StartElement{Name{"", "foo"}, []Attr{
-			{Name{"", "xmlns"}, ""},
-			{Name{"", "x"}, "value"},
-			{Name{"space", "x"}, "value"},
-		}},
-	},
-	want: `<foo xmlns="space" xmlns="space"><foo xmlns="" x="value" xmlns:space="space" space:x="value">`,
-}, {
-	desc: "nested element requires empty default name space",
-	toks: []Token{
-		StartElement{Name{"space", "foo"}, []Attr{
-			{Name{"", "xmlns"}, "space"},
-		}},
-		StartElement{Name{"", "foo"}, nil},
-	},
-	want: `<foo xmlns="space" xmlns="space"><foo>`,
-}, {
-	desc: "attribute uses name space from xmlns",
-	toks: []Token{
-		StartElement{Name{"some/space", "foo"}, []Attr{
-			{Name{"", "attr"}, "value"},
-			{Name{"some/space", "other"}, "other value"},
-		}},
-	},
-	want: `<foo xmlns="some/space" attr="value" xmlns:space="some/space" space:other="other value">`,
-}, {
-	desc: "default name space should not be used by attributes",
-	toks: []Token{
-		StartElement{Name{"space", "foo"}, []Attr{
-			{Name{"", "xmlns"}, "space"},
-			{Name{"xmlns", "bar"}, "space"},
-			{Name{"space", "baz"}, "foo"},
-		}},
-		StartElement{Name{"space", "baz"}, nil},
-		EndElement{Name{"space", "baz"}},
-		EndElement{Name{"space", "foo"}},
-	},
-	want: `<foo xmlns="space" xmlns="space" xmlns:_xmlns="xmlns" _xmlns:bar="space" xmlns:space="space" space:baz="foo"><baz xmlns="space"></baz></foo>`,
-}, {
-	desc: "default name space not used by attributes, not explicitly defined",
-	toks: []Token{
-		StartElement{Name{"space", "foo"}, []Attr{
-			{Name{"", "xmlns"}, "space"},
-			{Name{"space", "baz"}, "foo"},
-		}},
-		StartElement{Name{"space", "baz"}, nil},
-		EndElement{Name{"space", "baz"}},
-		EndElement{Name{"space", "foo"}},
-	},
-	want: `<foo xmlns="space" xmlns="space" xmlns:space="space" space:baz="foo"><baz xmlns="space"></baz></foo>`,
-}, {
-	desc: "impossible xmlns declaration",
-	toks: []Token{
-		StartElement{Name{"", "foo"}, []Attr{
-			{Name{"", "xmlns"}, "space"},
-		}},
-		StartElement{Name{"space", "bar"}, []Attr{
-			{Name{"space", "attr"}, "value"},
-		}},
-	},
-	want: `<foo xmlns="space"><bar xmlns="space" xmlns:space="space" space:attr="value">`,
-}}
+	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) {
-loop:
-	for i, tt := range encodeTokenTests {
+	for _, tt := range encodeTokenTests {
 		var buf bytes.Buffer
 		enc := NewEncoder(&buf)
-		var err error
-		for j, tok := range tt.toks {
-			err = enc.EncodeToken(tok)
-			if err != nil && j < len(tt.toks)-1 {
-				t.Errorf("#%d %s token #%d: %v", i, tt.desc, j, err)
-				continue loop
-			}
-		}
-		errorf := func(f string, a ...interface{}) {
-			t.Errorf("#%d %s token #%d:%s", i, tt.desc, len(tt.toks)-1, fmt.Sprintf(f, a...))
-		}
+		err := enc.EncodeToken(tt.tok)
 		switch {
-		case tt.err != "" && err == nil:
-			errorf(" expected error; got none")
-			continue
-		case tt.err == "" && err != nil:
-			errorf(" got error: %v", err)
-			continue
-		case tt.err != "" && err != nil && tt.err != err.Error():
-			errorf(" error mismatch; got %v, want %v", err, tt.err)
-			continue
+		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 {
-			errorf(" %v", err)
-			continue
+			t.Fatalf("enc.EncodeToken: %v", err)
 		}
 		if got := buf.String(); got != tt.want {
-			errorf("\ngot  %v\nwant %v", got, tt.want)
-			continue
+			t.Errorf("enc.EncodeToken = %s; want: %s", got, tt.want)
 		}
 	}
 }
@@ -1684,83 +1264,3 @@ func TestDecodeEncode(t *testing.T) {
 		}
 	}
 }
-
-// Issue 9796. Used to fail with GORACE="halt_on_error=1" -race.
-func TestRace9796(t *testing.T) {
-	type A struct{}
-	type B struct {
-		C []A `xml:"X>Y"`
-	}
-	var wg sync.WaitGroup
-	for i := 0; i < 2; i++ {
-		wg.Add(1)
-		go func() {
-			Marshal(B{[]A{A{}}})
-			wg.Done()
-		}()
-	}
-	wg.Wait()
-}
-
-func TestIsValidDirective(t *testing.T) {
-	testOK := []string{
-		"<>",
-		"< < > >",
-		"<!DOCTYPE '<' '>' '>' <!--nothing-->>",
-		"<!DOCTYPE doc [ <!ELEMENT doc ANY> <!ELEMENT doc ANY> ]>",
-		"<!DOCTYPE doc [ <!ELEMENT doc \"ANY> '<' <!E\" LEMENT '>' doc ANY> ]>",
-		"<!DOCTYPE doc <!-- just>>>> a < comment --> [ <!ITEM anything> ] >",
-	}
-	testKO := []string{
-		"<",
-		">",
-		"<!--",
-		"-->",
-		"< > > < < >",
-		"<!dummy <!-- > -->",
-		"<!DOCTYPE doc '>",
-		"<!DOCTYPE doc '>'",
-		"<!DOCTYPE doc <!--comment>",
-	}
-	for _, s := range testOK {
-		if !isValidDirective(Directive(s)) {
-			t.Errorf("Directive %q is expected to be valid", s)
-		}
-	}
-	for _, s := range testKO {
-		if isValidDirective(Directive(s)) {
-			t.Errorf("Directive %q is expected to be invalid", s)
-		}
-	}
-}
-
-// Issue 11719. EncodeToken used to silently eat tokens with an invalid type.
-func TestSimpleUseOfEncodeToken(t *testing.T) {
-	var buf bytes.Buffer
-	enc := NewEncoder(&buf)
-	if err := enc.EncodeToken(&StartElement{Name: Name{"", "object1"}}); err == nil {
-		t.Errorf("enc.EncodeToken: pointer type should be rejected")
-	}
-	if err := enc.EncodeToken(&EndElement{Name: Name{"", "object1"}}); err == nil {
-		t.Errorf("enc.EncodeToken: pointer type should be rejected")
-	}
-	if err := enc.EncodeToken(StartElement{Name: Name{"", "object2"}}); err != nil {
-		t.Errorf("enc.EncodeToken: StartElement %s", err)
-	}
-	if err := enc.EncodeToken(EndElement{Name: Name{"", "object2"}}); err != nil {
-		t.Errorf("enc.EncodeToken: EndElement %s", err)
-	}
-	if err := enc.EncodeToken(Universe{}); err == nil {
-		t.Errorf("enc.EncodeToken: invalid type not caught")
-	}
-	if err := enc.Flush(); err != nil {
-		t.Errorf("enc.Flush: %s", err)
-	}
-	if buf.Len() == 0 {
-		t.Errorf("enc.EncodeToken: empty buffer")
-	}
-	want := "<object2></object2>"
-	if buf.String() != want {
-		t.Errorf("enc.EncodeToken: expected %q; got %q", want, buf.String())
-	}
-}
diff --git a/src/encoding/xml/read_test.go b/src/encoding/xml/read_test.go
index 7d004dc..01f55d0 100644
--- a/src/encoding/xml/read_test.go
+++ b/src/encoding/xml/read_test.go
@@ -694,7 +694,7 @@ type Pod struct {
 	Pea interface{} `xml:"Pea"`
 }
 
-// https://golang.org/issue/6836
+// https://code.google.com/p/go/issues/detail?id=6836
 func TestUnmarshalIntoInterface(t *testing.T) {
 	pod := new(Pod)
 	pod.Pea = new(Pea)
diff --git a/src/encoding/xml/xml.go b/src/encoding/xml/xml.go
index 0a21c93..8c15b98 100644
--- a/src/encoding/xml/xml.go
+++ b/src/encoding/xml/xml.go
@@ -549,6 +549,7 @@ func (d *Decoder) rawToken() (Token, error) {
 
 	case '?':
 		// <?: Processing instruction.
+		// TODO(rsc): Should parse the <?xml declaration to make sure the version is 1.0.
 		var target string
 		if target, ok = d.name(); !ok {
 			if d.err == nil {
@@ -573,13 +574,7 @@ func (d *Decoder) rawToken() (Token, error) {
 		data = data[0 : len(data)-2] // chop ?>
 
 		if target == "xml" {
-			content := string(data)
-			ver := procInst("version", content)
-			if ver != "" && ver != "1.0" {
-				d.err = fmt.Errorf("xml: unsupported version %q; only version 1.0 is supported", ver)
-				return nil, d.err
-			}
-			enc := procInst("encoding", content)
+			enc := procInstEncoding(string(data))
 			if enc != "" && enc != "utf-8" && enc != "UTF-8" {
 				if d.CharsetReader == nil {
 					d.err = fmt.Errorf("xml: encoding %q declared but Decoder.CharsetReader is nil", enc)
@@ -728,7 +723,7 @@ func (d *Decoder) rawToken() (Token, error) {
 		return nil, d.err
 	}
 
-	attr = []Attr{}
+	attr = make([]Attr, 0, 4)
 	for {
 		d.space()
 		if b, ok = d.mustgetc(); !ok {
@@ -752,11 +747,7 @@ func (d *Decoder) rawToken() (Token, error) {
 
 		n := len(attr)
 		if n >= cap(attr) {
-			nCap := 2 * cap(attr)
-			if nCap == 0 {
-				nCap = 4
-			}
-			nattr := make([]Attr, n, nCap)
+			nattr := make([]Attr, n, 2*cap(attr))
 			copy(nattr, attr)
 			attr = nattr
 		}
@@ -1128,12 +1119,12 @@ func (d *Decoder) name() (s string, ok bool) {
 	}
 
 	// Now we check the characters.
-	b := d.buf.Bytes()
-	if !isName(b) {
-		d.err = d.syntaxError("invalid XML name: " + string(b))
+	s = d.buf.String()
+	if !isName([]byte(s)) {
+		d.err = d.syntaxError("invalid XML name: " + s)
 		return "", false
 	}
-	return string(b), true
+	return s, true
 }
 
 // Read a name and append its bytes to d.buf.
@@ -1841,13 +1832,6 @@ var (
 // EscapeText writes to w the properly escaped XML equivalent
 // of the plain text data s.
 func EscapeText(w io.Writer, s []byte) error {
-	return escapeText(w, s, true)
-}
-
-// escapeText writes to w the properly escaped XML equivalent
-// of the plain text data s. If escapeNewline is true, newline
-// characters will be escaped.
-func escapeText(w io.Writer, s []byte, escapeNewline bool) error {
 	var esc []byte
 	last := 0
 	for i := 0; i < len(s); {
@@ -1867,9 +1851,6 @@ func escapeText(w io.Writer, s []byte, escapeNewline bool) error {
 		case '\t':
 			esc = esc_tab
 		case '\n':
-			if !escapeNewline {
-				continue
-			}
 			esc = esc_nl
 		case '\r':
 			esc = esc_cr
@@ -1940,17 +1921,16 @@ func Escape(w io.Writer, s []byte) {
 	EscapeText(w, s)
 }
 
-// procInst parses the `param="..."` or `param='...'`
+// procInstEncoding parses the `encoding="..."` or `encoding='...'`
 // value out of the provided string, returning "" if not found.
-func procInst(param, s string) string {
+func procInstEncoding(s string) string {
 	// TODO: this parsing is somewhat lame and not exact.
 	// It works for all actual cases, though.
-	param = param + "="
-	idx := strings.Index(s, param)
+	idx := strings.Index(s, "encoding=")
 	if idx == -1 {
 		return ""
 	}
-	v := s[idx+len(param):]
+	v := s[idx+len("encoding="):]
 	if v == "" {
 		return ""
 	}
diff --git a/src/encoding/xml/xml_test.go b/src/encoding/xml/xml_test.go
index 312a7c9..be995c0 100644
--- a/src/encoding/xml/xml_test.go
+++ b/src/encoding/xml/xml_test.go
@@ -657,23 +657,20 @@ type procInstEncodingTest struct {
 }
 
 var procInstTests = []struct {
-	input  string
-	expect [2]string
+	input, expect string
 }{
-	{`version="1.0" encoding="utf-8"`, [2]string{"1.0", "utf-8"}},
-	{`version="1.0" encoding='utf-8'`, [2]string{"1.0", "utf-8"}},
-	{`version="1.0" encoding='utf-8' `, [2]string{"1.0", "utf-8"}},
-	{`version="1.0" encoding=utf-8`, [2]string{"1.0", ""}},
-	{`encoding="FOO" `, [2]string{"", "FOO"}},
+	{`version="1.0" encoding="utf-8"`, "utf-8"},
+	{`version="1.0" encoding='utf-8'`, "utf-8"},
+	{`version="1.0" encoding='utf-8' `, "utf-8"},
+	{`version="1.0" encoding=utf-8`, ""},
+	{`encoding="FOO" `, "FOO"},
 }
 
 func TestProcInstEncoding(t *testing.T) {
 	for _, test := range procInstTests {
-		if got := procInst("version", test.input); got != test.expect[0] {
-			t.Errorf("procInst(version, %q) = %q; want %q", test.input, got, test.expect[0])
-		}
-		if got := procInst("encoding", test.input); got != test.expect[1] {
-			t.Errorf("procInst(encoding, %q) = %q; want %q", test.input, got, test.expect[1])
+		got := procInstEncoding(test.input)
+		if got != test.expect {
+			t.Errorf("procInstEncoding(%q) = %q; want %q", test.input, got, test.expect)
 		}
 	}
 }
diff --git a/src/expvar/expvar.go b/src/expvar/expvar.go
index 24c2d6b..9b6dab4 100644
--- a/src/expvar/expvar.go
+++ b/src/expvar/expvar.go
@@ -26,14 +26,12 @@ import (
 	"encoding/json"
 	"fmt"
 	"log"
-	"math"
 	"net/http"
 	"os"
 	"runtime"
 	"sort"
 	"strconv"
 	"sync"
-	"sync/atomic"
 )
 
 // Var is an abstract type for all exported variables.
@@ -43,47 +41,52 @@ 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 {
-	return strconv.FormatInt(atomic.LoadInt64(&v.i), 10)
+	v.mu.RLock()
+	defer v.mu.RUnlock()
+	return strconv.FormatInt(v.i, 10)
 }
 
 func (v *Int) Add(delta int64) {
-	atomic.AddInt64(&v.i, delta)
+	v.mu.Lock()
+	defer v.mu.Unlock()
+	v.i += delta
 }
 
 func (v *Int) Set(value int64) {
-	atomic.StoreInt64(&v.i, value)
+	v.mu.Lock()
+	defer v.mu.Unlock()
+	v.i = value
 }
 
 // Float is a 64-bit float variable that satisfies the Var interface.
 type Float struct {
-	f uint64
+	mu sync.RWMutex
+	f  float64
 }
 
 func (v *Float) String() string {
-	return strconv.FormatFloat(
-		math.Float64frombits(atomic.LoadUint64(&v.f)), 'g', -1, 64)
+	v.mu.RLock()
+	defer v.mu.RUnlock()
+	return strconv.FormatFloat(v.f, 'g', -1, 64)
 }
 
 // Add adds delta to v.
 func (v *Float) Add(delta float64) {
-	for {
-		cur := atomic.LoadUint64(&v.f)
-		curVal := math.Float64frombits(cur)
-		nxtVal := curVal + delta
-		nxt := math.Float64bits(nxtVal)
-		if atomic.CompareAndSwapUint64(&v.f, cur, nxt) {
-			return
-		}
-	}
+	v.mu.Lock()
+	defer v.mu.Unlock()
+	v.f += delta
 }
 
 // Set sets v to value.
 func (v *Float) Set(value float64) {
-	atomic.StoreUint64(&v.f, math.Float64bits(value))
+	v.mu.Lock()
+	defer v.mu.Unlock()
+	v.f = value
 }
 
 // Map is a string-to-Var map variable that satisfies the Var interface.
diff --git a/src/expvar/expvar_test.go b/src/expvar/expvar_test.go
index 8bc633e..765e3b7 100644
--- a/src/expvar/expvar_test.go
+++ b/src/expvar/expvar_test.go
@@ -7,13 +7,8 @@ package expvar
 import (
 	"bytes"
 	"encoding/json"
-	"math"
-	"net"
 	"net/http/httptest"
-	"runtime"
 	"strconv"
-	"sync"
-	"sync/atomic"
 	"testing"
 )
 
@@ -52,30 +47,6 @@ func TestInt(t *testing.T) {
 	}
 }
 
-func BenchmarkIntAdd(b *testing.B) {
-	var v Int
-
-	b.RunParallel(func(pb *testing.PB) {
-		for pb.Next() {
-			v.Add(1)
-		}
-	})
-}
-
-func BenchmarkIntSet(b *testing.B) {
-	var v Int
-
-	b.RunParallel(func(pb *testing.PB) {
-		for pb.Next() {
-			v.Set(1)
-		}
-	})
-}
-
-func (v *Float) val() float64 {
-	return math.Float64frombits(atomic.LoadUint64(&v.f))
-}
-
 func TestFloat(t *testing.T) {
 	RemoveAll()
 	reqs := NewFloat("requests-float")
@@ -88,8 +59,8 @@ func TestFloat(t *testing.T) {
 
 	reqs.Add(1.5)
 	reqs.Add(1.25)
-	if v := reqs.val(); v != 2.75 {
-		t.Errorf("reqs.val() = %v, want 2.75", v)
+	if reqs.f != 2.75 {
+		t.Errorf("reqs.f = %v, want 2.75", reqs.f)
 	}
 
 	if s := reqs.String(); s != "2.75" {
@@ -97,31 +68,11 @@ func TestFloat(t *testing.T) {
 	}
 
 	reqs.Add(-2)
-	if v := reqs.val(); v != 0.75 {
-		t.Errorf("reqs.val() = %v, want 0.75", v)
+	if reqs.f != 0.75 {
+		t.Errorf("reqs.f = %v, want 0.75", reqs.f)
 	}
 }
 
-func BenchmarkFloatAdd(b *testing.B) {
-	var f Float
-
-	b.RunParallel(func(pb *testing.PB) {
-		for pb.Next() {
-			f.Add(1.0)
-		}
-	})
-}
-
-func BenchmarkFloatSet(b *testing.B) {
-	var f Float
-
-	b.RunParallel(func(pb *testing.PB) {
-		for pb.Next() {
-			f.Set(1.0)
-		}
-	})
-}
-
 func TestString(t *testing.T) {
 	RemoveAll()
 	name := NewString("my-name")
@@ -139,16 +90,6 @@ func TestString(t *testing.T) {
 	}
 }
 
-func BenchmarkStringSet(b *testing.B) {
-	var s String
-
-	b.RunParallel(func(pb *testing.PB) {
-		for pb.Next() {
-			s.Set("red")
-		}
-	})
-}
-
 func TestMapCounter(t *testing.T) {
 	RemoveAll()
 	colors := NewMap("bike-shed-colors")
@@ -163,8 +104,8 @@ func TestMapCounter(t *testing.T) {
 	if x := colors.m["blue"].(*Int).i; x != 4 {
 		t.Errorf("colors.m[\"blue\"] = %v, want 4", x)
 	}
-	if x := colors.m[`green "midori"`].(*Float).val(); x != 4.125 {
-		t.Errorf("colors.m[`green \"midori\"] = %v, want 4.125", 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}',
@@ -189,38 +130,6 @@ func TestMapCounter(t *testing.T) {
 	}
 }
 
-func BenchmarkMapSet(b *testing.B) {
-	m := new(Map).Init()
-
-	v := new(Int)
-
-	b.RunParallel(func(pb *testing.PB) {
-		for pb.Next() {
-			m.Set("red", v)
-		}
-	})
-}
-
-func BenchmarkMapAddSame(b *testing.B) {
-	for i := 0; i < b.N; i++ {
-		m := new(Map).Init()
-		m.Add("red", 1)
-		m.Add("red", 1)
-		m.Add("red", 1)
-		m.Add("red", 1)
-	}
-}
-
-func BenchmarkMapAddDifferent(b *testing.B) {
-	for i := 0; i < b.N; i++ {
-		m := new(Map).Init()
-		m.Add("red", 1)
-		m.Add("blue", 1)
-		m.Add("green", 1)
-		m.Add("yellow", 1)
-	}
-}
-
 func TestFunc(t *testing.T) {
 	RemoveAll()
 	var x interface{} = []string{"a", "b"}
@@ -256,135 +165,3 @@ func TestHandler(t *testing.T) {
 		t.Errorf("HTTP handler wrote:\n%s\nWant:\n%s", got, want)
 	}
 }
-
-func BenchmarkRealworldExpvarUsage(b *testing.B) {
-	var (
-		bytesSent Int
-		bytesRead Int
-	)
-
-	// The benchmark creates GOMAXPROCS client/server pairs.
-	// Each pair creates 4 goroutines: client reader/writer and server reader/writer.
-	// The benchmark stresses concurrent reading and writing to the same connection.
-	// Such pattern is used in net/http and net/rpc.
-
-	b.StopTimer()
-
-	P := runtime.GOMAXPROCS(0)
-	N := b.N / P
-	W := 1000
-
-	// Setup P client/server connections.
-	clients := make([]net.Conn, P)
-	servers := make([]net.Conn, P)
-	ln, err := net.Listen("tcp", "127.0.0.1:0")
-	if err != nil {
-		b.Fatalf("Listen failed: %v", err)
-	}
-	defer ln.Close()
-	done := make(chan bool)
-	go func() {
-		for p := 0; p < P; p++ {
-			s, err := ln.Accept()
-			if err != nil {
-				b.Errorf("Accept failed: %v", err)
-				return
-			}
-			servers[p] = s
-		}
-		done <- true
-	}()
-	for p := 0; p < P; p++ {
-		c, err := net.Dial("tcp", ln.Addr().String())
-		if err != nil {
-			b.Fatalf("Dial failed: %v", err)
-		}
-		clients[p] = c
-	}
-	<-done
-
-	b.StartTimer()
-
-	var wg sync.WaitGroup
-	wg.Add(4 * P)
-	for p := 0; p < P; p++ {
-		// Client writer.
-		go func(c net.Conn) {
-			defer wg.Done()
-			var buf [1]byte
-			for i := 0; i < N; i++ {
-				v := byte(i)
-				for w := 0; w < W; w++ {
-					v *= v
-				}
-				buf[0] = v
-				n, err := c.Write(buf[:])
-				if err != nil {
-					b.Errorf("Write failed: %v", err)
-					return
-				}
-
-				bytesSent.Add(int64(n))
-			}
-		}(clients[p])
-
-		// Pipe between server reader and server writer.
-		pipe := make(chan byte, 128)
-
-		// Server reader.
-		go func(s net.Conn) {
-			defer wg.Done()
-			var buf [1]byte
-			for i := 0; i < N; i++ {
-				n, err := s.Read(buf[:])
-
-				if err != nil {
-					b.Errorf("Read failed: %v", err)
-					return
-				}
-
-				bytesRead.Add(int64(n))
-				pipe <- buf[0]
-			}
-		}(servers[p])
-
-		// Server writer.
-		go func(s net.Conn) {
-			defer wg.Done()
-			var buf [1]byte
-			for i := 0; i < N; i++ {
-				v := <-pipe
-				for w := 0; w < W; w++ {
-					v *= v
-				}
-				buf[0] = v
-				n, err := s.Write(buf[:])
-				if err != nil {
-					b.Errorf("Write failed: %v", err)
-					return
-				}
-
-				bytesSent.Add(int64(n))
-			}
-			s.Close()
-		}(servers[p])
-
-		// Client reader.
-		go func(c net.Conn) {
-			defer wg.Done()
-			var buf [1]byte
-			for i := 0; i < N; i++ {
-				n, err := c.Read(buf[:])
-
-				if err != nil {
-					b.Errorf("Read failed: %v", err)
-					return
-				}
-
-				bytesRead.Add(int64(n))
-			}
-			c.Close()
-		}(clients[p])
-	}
-	wg.Wait()
-}
diff --git a/src/flag/flag.go b/src/flag/flag.go
index 3abc80e..60aef5d 100644
--- a/src/flag/flag.go
+++ b/src/flag/flag.go
@@ -31,7 +31,7 @@
 		fmt.Println("ip has value ", *ip)
 		fmt.Println("flagvar has value ", flagvar)
 
-	After parsing, the arguments following the flags are available as the
+	After parsing, the arguments after the flag are available as the
 	slice flag.Args() or individually as flag.Arg(i).
 	The arguments are indexed from 0 through flag.NArg()-1.
 
@@ -235,8 +235,6 @@ func (d *durationValue) String() string { return (*time.Duration)(d).String() }
 // If a Value has an IsBoolFlag() bool method returning true,
 // the command-line parser makes -name equivalent to -name=true
 // rather than using the next command-line argument.
-//
-// Set is called once, in command line order, for each flag present.
 type Value interface {
 	String() string
 	Set(string) error
@@ -251,14 +249,13 @@ type Getter interface {
 	Get() interface{}
 }
 
-// ErrorHandling defines how FlagSet.Parse behaves if the parse fails.
+// ErrorHandling defines how to handle flag parsing errors.
 type ErrorHandling int
 
-// These constants cause FlagSet.Parse to behave as described if the parse fails.
 const (
-	ContinueOnError ErrorHandling = iota // Return a descriptive error.
-	ExitOnError                          // Call os.Exit(2).
-	PanicOnError                         // Call panic with a descriptive error.
+	ContinueOnError ErrorHandling = iota
+	ExitOnError
+	PanicOnError
 )
 
 // A FlagSet represents a set of defined flags.  The zero value of a FlagSet
@@ -376,110 +373,20 @@ func Set(name, value string) error {
 	return CommandLine.Set(name, value)
 }
 
-// isZeroValue guesses whether the string represents the zero
-// value for a flag. It is not accurate but in practice works OK.
-func isZeroValue(value string) bool {
-	switch value {
-	case "false":
-		return true
-	case "":
-		return true
-	case "0":
-		return true
-	}
-	return false
-}
-
-// UnquoteUsage extracts a back-quoted name from the usage
-// string for a flag and returns it and the un-quoted usage.
-// Given "a `name` to show" it returns ("name", "a name to show").
-// If there are no back quotes, the name is an educated guess of the
-// type of the flag's value, or the empty string if the flag is boolean.
-func UnquoteUsage(flag *Flag) (name string, usage string) {
-	// Look for a back-quoted name, but avoid the strings package.
-	usage = flag.Usage
-	for i := 0; i < len(usage); i++ {
-		if usage[i] == '`' {
-			for j := i + 1; j < len(usage); j++ {
-				if usage[j] == '`' {
-					name = usage[i+1 : j]
-					usage = usage[:i] + name + usage[j+1:]
-					return name, usage
-				}
-			}
-			break // Only one back quote; use type name.
-		}
-	}
-	// No explicit name, so use type if we can find one.
-	name = "value"
-	switch flag.Value.(type) {
-	case boolFlag:
-		name = ""
-	case *durationValue:
-		name = "duration"
-	case *float64Value:
-		name = "float"
-	case *intValue, *int64Value:
-		name = "int"
-	case *stringValue:
-		name = "string"
-	case *uintValue, *uint64Value:
-		name = "uint"
-	}
-	return
-}
-
-// PrintDefaults prints to standard error the default values of all
-// defined command-line flags in the set. See the documentation for
-// the global function PrintDefaults for more information.
+// PrintDefaults prints, to standard error unless configured
+// otherwise, the default values of all defined flags in the set.
 func (f *FlagSet) PrintDefaults() {
 	f.VisitAll(func(flag *Flag) {
-		s := fmt.Sprintf("  -%s", flag.Name) // Two spaces before -; see next two comments.
-		name, usage := UnquoteUsage(flag)
-		if len(name) > 0 {
-			s += " " + name
-		}
-		// Boolean flags of one ASCII letter are so common we
-		// treat them specially, putting their usage on the same line.
-		if len(s) <= 4 { // space, space, '-', 'x'.
-			s += "\t"
-		} else {
-			// Four spaces before the tab triggers good alignment
-			// for both 4- and 8-space tab stops.
-			s += "\n    \t"
+		format := "  -%s=%s: %s\n"
+		if _, ok := flag.Value.(*stringValue); ok {
+			// put quotes on the value
+			format = "  -%s=%q: %s\n"
 		}
-		s += usage
-		if !isZeroValue(flag.DefValue) {
-			if _, ok := flag.Value.(*stringValue); ok {
-				// put quotes on the value
-				s += fmt.Sprintf(" (default %q)", flag.DefValue)
-			} else {
-				s += fmt.Sprintf(" (default %v)", flag.DefValue)
-			}
-		}
-		fmt.Fprint(f.out(), s, "\n")
+		fmt.Fprintf(f.out(), format, flag.Name, flag.DefValue, flag.Usage)
 	})
 }
 
-// PrintDefaults prints, to standard error unless configured otherwise,
-// a usage message showing the default settings of all defined
-// command-line flags.
-// For an integer valued flag x, the default output has the form
-//	-x int
-//		usage-message-for-x (default 7)
-// The usage message will appear on a separate line for anything but
-// a bool flag with a one-byte name. For bool flags, the type is
-// omitted and if the flag name is one byte the usage message appears
-// on the same line. The parenthetical default is omitted if the
-// default is the zero value for the type. The listed type, here int,
-// can be changed by placing a back-quoted name in the flag's usage
-// string; the first such item in the message is taken to be a parameter
-// name to show in the message and the back quotes are stripped from
-// the message when displayed. For instance, given
-//	flag.String("I", "", "search `directory` for include files")
-// the output will be
-//	-I directory
-//		search directory for include files.
+// PrintDefaults prints to standard error the default values of all defined command-line flags.
 func PrintDefaults() {
 	CommandLine.PrintDefaults()
 }
@@ -501,8 +408,6 @@ func defaultUsage(f *FlagSet) {
 // Usage prints to standard error a usage message documenting all defined command-line flags.
 // It is called when an error occurs while parsing flags.
 // The function is a variable that may be changed to point to a custom function.
-// By default it prints a simple header and calls PrintDefaults; for details about the
-// format of the output and how to control it, see the documentation for PrintDefaults.
 var Usage = func() {
 	fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
 	PrintDefaults()
@@ -515,8 +420,7 @@ func (f *FlagSet) NFlag() int { return len(f.actual) }
 func NFlag() int { return len(CommandLine.actual) }
 
 // Arg returns the i'th argument.  Arg(0) is the first remaining argument
-// after flags have been processed. Arg returns an empty string if the
-// requested element does not exist.
+// after flags have been processed.
 func (f *FlagSet) Arg(i int) string {
 	if i < 0 || i >= len(f.args) {
 		return ""
@@ -525,8 +429,7 @@ func (f *FlagSet) Arg(i int) string {
 }
 
 // Arg returns the i'th command-line argument.  Arg(0) is the first remaining argument
-// after flags have been processed. Arg returns an empty string if the
-// requested element does not exist.
+// after flags have been processed.
 func Arg(i int) string {
 	return CommandLine.Arg(i)
 }
@@ -823,27 +726,27 @@ func (f *FlagSet) parseOne() (bool, error) {
 	if len(s) == 0 || s[0] != '-' || len(s) == 1 {
 		return false, nil
 	}
-	numMinuses := 1
+	num_minuses := 1
 	if s[1] == '-' {
-		numMinuses++
+		num_minuses++
 		if len(s) == 2 { // "--" terminates the flags
 			f.args = f.args[1:]
 			return false, nil
 		}
 	}
-	name := s[numMinuses:]
+	name := s[num_minuses:]
 	if len(name) == 0 || name[0] == '-' || name[0] == '=' {
 		return false, f.failf("bad flag syntax: %s", s)
 	}
 
 	// it's a flag. does it have an argument?
 	f.args = f.args[1:]
-	hasValue := false
+	has_value := false
 	value := ""
 	for i := 1; i < len(name); i++ { // equals cannot be first
 		if name[i] == '=' {
 			value = name[i+1:]
-			hasValue = true
+			has_value = true
 			name = name[0:i]
 			break
 		}
@@ -859,23 +762,21 @@ func (f *FlagSet) parseOne() (bool, error) {
 	}
 
 	if fv, ok := flag.Value.(boolFlag); ok && fv.IsBoolFlag() { // special case: doesn't need an arg
-		if hasValue {
+		if has_value {
 			if err := fv.Set(value); err != nil {
 				return false, f.failf("invalid boolean value %q for -%s: %v", value, name, err)
 			}
 		} else {
-			if err := fv.Set("true"); err != nil {
-				return false, f.failf("invalid boolean flag %s: %v", name, err)
-			}
+			fv.Set("true")
 		}
 	} else {
 		// It must have a value, which might be the next argument.
-		if !hasValue && len(f.args) > 0 {
+		if !has_value && len(f.args) > 0 {
 			// value is the next arg
-			hasValue = true
+			has_value = true
 			value, f.args = f.args[0], f.args[1:]
 		}
-		if !hasValue {
+		if !has_value {
 			return false, f.failf("flag needs an argument: -%s", name)
 		}
 		if err := flag.Value.Set(value); err != nil {
@@ -928,7 +829,7 @@ func Parse() {
 	CommandLine.Parse(os.Args[1:])
 }
 
-// Parsed reports whether the command-line flags have been parsed.
+// Parsed returns true if the command-line flags have been parsed.
 func Parsed() bool {
 	return CommandLine.Parsed()
 }
diff --git a/src/flag/flag_test.go b/src/flag/flag_test.go
index e2319ec..8c88c8c 100644
--- a/src/flag/flag_test.go
+++ b/src/flag/flag_test.go
@@ -377,41 +377,3 @@ func TestHelp(t *testing.T) {
 		t.Fatal("help was called; should not have been for defined help flag")
 	}
 }
-
-const defaultOutput = `  -A	for bootstrapping, allow 'any' type
-  -Alongflagname
-    	disable bounds checking
-  -C	a boolean defaulting to true (default true)
-  -D path
-    	set relative path for local imports
-  -F number
-    	a non-zero number (default 2.7)
-  -G float
-    	a float that defaults to zero
-  -N int
-    	a non-zero int (default 27)
-  -Z int
-    	an int that defaults to zero
-  -maxT timeout
-    	set timeout for dial
-`
-
-func TestPrintDefaults(t *testing.T) {
-	fs := NewFlagSet("print defaults test", ContinueOnError)
-	var buf bytes.Buffer
-	fs.SetOutput(&buf)
-	fs.Bool("A", false, "for bootstrapping, allow 'any' type")
-	fs.Bool("Alongflagname", false, "disable bounds checking")
-	fs.Bool("C", true, "a boolean defaulting to true")
-	fs.String("D", "", "set relative `path` for local imports")
-	fs.Float64("F", 2.7, "a non-zero `number`")
-	fs.Float64("G", 0, "a float that defaults to zero")
-	fs.Int("N", 27, "a non-zero int")
-	fs.Int("Z", 0, "an int that defaults to zero")
-	fs.Duration("maxT", 0, "set `timeout` for dial")
-	fs.PrintDefaults()
-	got := buf.String()
-	if got != defaultOutput {
-		t.Errorf("got %q want %q\n", got, defaultOutput)
-	}
-}
diff --git a/src/fmt/doc.go b/src/fmt/doc.go
index ef91368..ee54463 100644
--- a/src/fmt/doc.go
+++ b/src/fmt/doc.go
@@ -40,7 +40,7 @@
 		%F	synonym for %f
 		%g	%e for large exponents, %f otherwise
 		%G	%E for large exponents, %F otherwise
-	String and slice of bytes (treated equivalently with these verbs):
+	String and slice of bytes:
 		%s	the uninterpreted bytes of the string or slice
 		%q	a double-quoted string safely escaped with Go syntax
 		%x	base 16, lower-case, two characters per byte
@@ -66,13 +66,13 @@
 		maps:               map[key1:value1 key2:value2]
 		pointer to above:   &{}, &[], &map[]
 
-	Width is specified by an optional decimal number immediately preceding the verb.
+	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
+		%f:    default width, default precision
 		%9f    width 9, default precision
 		%.2f   default width, precision 2
 		%9.2f  width 9, precision 2
@@ -138,23 +138,20 @@
 	formatting considerations apply for operands that implement
 	certain interfaces. In order of application:
 
-	1. If the operand is a reflect.Value, the concrete value it
-	holds is printed as if it was the operand.
-
-	2. If an operand implements the Formatter interface, it will
+	1. If an operand implements the Formatter interface, it will
 	be invoked. Formatter provides fine control of formatting.
 
-	3. If the %v verb is used with the # flag (%#v) and the operand
+	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 apply:
 
-	4. If an operand implements the error interface, the Error method
+	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).
 
-	5. If an operand implements method String() string, that method
+	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).
 
@@ -164,9 +161,6 @@
 	of strings, and %6.2f will control formatting for each element
 	of a floating-point array.
 
-	However, when printing a byte slice with a string-like verb
-	(%s %q %x %X), it is treated identically to a string, as a single item.
-
 	To avoid recursion in cases such as
 		type X string
 		func (x X) String() string { return Sprintf("<%s>", x) }
@@ -184,8 +178,8 @@
 	However, the notation [n] immediately before the verb indicates that the
 	nth one-indexed argument is to be formatted instead. The same notation
 	before a '*' for a width or precision selects the argument index holding
-	the value. After processing a bracketed expression [n], subsequent verbs
-	will use arguments n+1, n+2, etc. unless otherwise directed.
+	the value. After processing a bracketed expression [n], arguments n+1,
+	n+2, etc. will be processed unless otherwise directed.
 
 	For example,
 		fmt.Sprintf("%[2]d %[1]d\n", 11, 22)
@@ -231,33 +225,18 @@
 		%!s(PANIC=bad)
 
 	The %!s just shows the print verb in use when the failure
-	occurred. If the panic is caused by a nil receiver to an Error
-	or String method, however, the output is the undecorated
-	string, "<nil>".
+	occurred.
 
 	Scanning
 
 	An analogous set of functions scans formatted text to yield
 	values.  Scan, Scanf and Scanln read from os.Stdin; Fscan,
 	Fscanf and Fscanln read from a specified io.Reader; Sscan,
-	Sscanf and Sscanln read from an argument string.
-
-	Scan, Fscan, Sscan treat newlines in the input as spaces.
-
-	Scanln, Fscanln and Sscanln stop scanning at a newline and
-	require that the items be followed by a newline or EOF.
-
-	Scanf, Fscanf and Sscanf require that (after skipping spaces)
-	newlines in the format are matched by newlines in the input
-	and vice versa.  This behavior differs from the corresponding
-	routines in C, which uniformly treat newlines as spaces.
-
-	When scanning with Scanf, Fscanf, and Sscanf, all non-empty
-	runs of space characters (except newline) are equivalent
-	to a single space in both the format and the input.  With
-	that proviso, text in the format string must match the input
-	text; scanning stops if it does not, with the return value
-	of the function indicating the number of arguments scanned.
+	Sscanf and Sscanln read from an argument string.  Scanln,
+	Fscanln and Sscanln stop scanning at a newline and require that
+	the items be followed by one; Scanf, Fscanf and Sscanf require
+	newlines in the input to match newlines in the format; the other
+	routines treat newlines as spaces.
 
 	Scanf, Fscanf, and Sscanf parse the arguments according to a
 	format string, analogous to that of Printf.  For example, %x
@@ -274,18 +253,20 @@
 		Flags # and + are not implemented.
 
 	The familiar base-setting prefixes 0 (octal) and 0x
-	(hexadecimal) are accepted when scanning integers without
-	a format or with the %v verb.
-
-	Width is interpreted in the input text but there is no
-	syntax for scanning with a precision (no %5.2f, just %5f).
-	If width is provided, it applies after leading spaces are
-	trimmed and specifies the maximum number of runes to read
-	to satisfy the verb. For example,
-	   Sscanf(" 1234567 ", "%5s%d", &s, &i)
-	will set s to "12345" and i to 67 while
-	   Sscanf(" 12 34 567 ", "%5s%d", &s, &i)
-	will set s to "12" and i to 34.
+	(hexadecimal) are accepted when scanning integers without a
+	format or with the %v verb.
+
+	Width is interpreted in the input text (%5s means at most
+	five runes of input will be read to scan a string) but there
+	is no syntax for scanning with a precision (no %5.2f, just
+	%5f).
+
+	When scanning with a format, all non-empty runs of space
+	characters (except newline) are equivalent to a single
+	space in both the format and the input.  With that proviso,
+	text in the format string must match the input text; scanning
+	stops if it does not, with the return value of the function
+	indicating the number of arguments scanned.
 
 	In all the scanning functions, a carriage return followed
 	immediately by a newline is treated as a plain newline
diff --git a/src/fmt/fmt_test.go b/src/fmt/fmt_test.go
index 90a4031..ff5fa79 100644
--- a/src/fmt/fmt_test.go
+++ b/src/fmt/fmt_test.go
@@ -9,7 +9,6 @@ import (
 	. "fmt"
 	"io"
 	"math"
-	"reflect"
 	"runtime"
 	"strings"
 	"testing"
@@ -136,33 +135,27 @@ var fmtTests = []struct {
 
 	// basic string
 	{"%s", "abc", "abc"},
-	{"%q", "abc", `"abc"`},
 	{"%x", "abc", "616263"},
-	{"%x", "\xff\xf0\x0f\xff", "fff00fff"},
-	{"%X", "\xff\xf0\x0f\xff", "FFF00FFF"},
 	{"%x", "xyz", "78797a"},
 	{"%X", "xyz", "78797A"},
-	{"% x", "xyz", "78 79 7a"},
-	{"% X", "xyz", "78 79 7A"},
-	{"%#x", "xyz", "0x78797a"},
-	{"%#X", "xyz", "0X78797A"},
-	{"%# x", "xyz", "0x78 0x79 0x7a"},
-	{"%# X", "xyz", "0X78 0X79 0X7A"},
+	{"%q", "abc", `"abc"`},
+	{"%#x", []byte("abc\xff"), "0x616263ff"},
+	{"%#X", []byte("abc\xff"), "0X616263FF"},
+	{"%# x", []byte("abc\xff"), "0x61 0x62 0x63 0xff"},
+	{"%# X", []byte("abc\xff"), "0X61 0X62 0X63 0XFF"},
 
 	// basic bytes
 	{"%s", []byte("abc"), "abc"},
-	{"%q", []byte("abc"), `"abc"`},
 	{"%x", []byte("abc"), "616263"},
-	{"%x", []byte("\xff\xf0\x0f\xff"), "fff00fff"},
-	{"%X", []byte("\xff\xf0\x0f\xff"), "FFF00FFF"},
+	{"% x", []byte("abc\xff"), "61 62 63 ff"},
+	{"%#x", []byte("abc\xff"), "0x616263ff"},
+	{"%#X", []byte("abc\xff"), "0X616263FF"},
+	{"%# x", []byte("abc\xff"), "0x61 0x62 0x63 0xff"},
+	{"%# X", []byte("abc\xff"), "0X61 0X62 0X63 0XFF"},
+	{"% X", []byte("abc\xff"), "61 62 63 FF"},
 	{"%x", []byte("xyz"), "78797a"},
 	{"%X", []byte("xyz"), "78797A"},
-	{"% x", []byte("xyz"), "78 79 7a"},
-	{"% X", []byte("xyz"), "78 79 7A"},
-	{"%#x", []byte("xyz"), "0x78797a"},
-	{"%#X", []byte("xyz"), "0X78797A"},
-	{"%# x", []byte("xyz"), "0x78 0x79 0x7a"},
-	{"%# X", []byte("xyz"), "0X78 0X79 0X7A"},
+	{"%q", []byte("abc"), `"abc"`},
 
 	// escaped strings
 	{"%#q", `abc`, "`abc`"},
@@ -395,8 +388,6 @@ var fmtTests = []struct {
 	{"%v", &slice, "&[1 2 3 4 5]"},
 	{"%v", &islice, "&[1 hello 2.5 <nil>]"},
 	{"%v", &bslice, "&[1 2 3 4 5]"},
-	{"%v", []byte{1}, "[1]"},
-	{"%v", []byte{}, "[]"},
 
 	// complexes with %v
 	{"%v", 1 + 2i, "(1+2i)"},
@@ -450,32 +441,6 @@ var fmtTests = []struct {
 	{"%d", []int{1, 2, 15}, `[1 2 15]`},
 	{"%d", []byte{1, 2, 15}, `[1 2 15]`},
 	{"%q", []string{"a", "b"}, `["a" "b"]`},
-	{"% 02x", []byte{1}, "01"},
-	{"% 02x", []byte{1, 2, 3}, "01 02 03"},
-	// Padding with byte slices.
-	{"%x", []byte{}, ""},
-	{"%02x", []byte{}, "00"},
-	{"% 02x", []byte{}, "00"},
-	{"%08x", []byte{0xab}, "000000ab"},
-	{"% 08x", []byte{0xab}, "000000ab"},
-	{"%08x", []byte{0xab, 0xcd}, "0000abcd"},
-	{"% 08x", []byte{0xab, 0xcd}, "000ab cd"},
-	{"%8x", []byte{0xab}, "      ab"},
-	{"% 8x", []byte{0xab}, "      ab"},
-	{"%8x", []byte{0xab, 0xcd}, "    abcd"},
-	{"% 8x", []byte{0xab, 0xcd}, "   ab cd"},
-	// Same for strings
-	{"%x", "", ""},
-	{"%02x", "", "00"},
-	{"% 02x", "", "00"},
-	{"%08x", "\xab", "000000ab"},
-	{"% 08x", "\xab", "000000ab"},
-	{"%08x", "\xab\xcd", "0000abcd"},
-	{"% 08x", "\xab\xcd", "000ab cd"},
-	{"%8x", "\xab", "      ab"},
-	{"% 8x", "\xab", "      ab"},
-	{"%8x", "\xab\xcd", "    abcd"},
-	{"% 8x", "\xab\xcd", "   ab cd"},
 
 	// renamings
 	{"%v", renamedBool(true), "true"},
@@ -557,8 +522,6 @@ var fmtTests = []struct {
 	{"%s", nil, "%!s(<nil>)"},
 	{"%T", nil, "<nil>"},
 	{"%-1", 100, "%!(NOVERB)%!(EXTRA int=100)"},
-	{"%017091901790959340919092959340919017929593813360", 0, "%!(NOVERB)%!(EXTRA int=0)"},
-	{"%184467440737095516170v", 0, "%!(NOVERB)%!(EXTRA int=0)"},
 
 	// The "<nil>" show up because maps are printed by
 	// first obtaining a list of keys and then looking up
@@ -577,15 +540,6 @@ var fmtTests = []struct {
 	{"%0.100f", 1.0, zeroFill("1.", 100, "")},
 	{"%0.100f", -1.0, zeroFill("-1.", 100, "")},
 
-	// Used to panic: integer function didn't look at f.prec, f.unicode, f.width or sign.
-	{"%#.80x", 42, "0x0000000000000000000000000000000000000000000000000000000000000000000000000000002a"},
-	{"%.80U", 42, "U+0000000000000000000000000000000000000000000000000000000000000000000000000000002A"},
-	{"%#.80U", '日', "U+000000000000000000000000000000000000000000000000000000000000000000000000000065E5 '日'"},
-	{"%.65d", -44, "-00000000000000000000000000000000000000000000000000000000000000044"},
-	{"%+.65d", 44, "+00000000000000000000000000000000000000000000000000000000000000044"},
-	{"% .65d", 44, " 00000000000000000000000000000000000000000000000000000000000000044"},
-	{"%  +.65d", 44, "+00000000000000000000000000000000000000000000000000000000000000044"},
-
 	// Comparison of padding rules with C printf.
 	/*
 		C program:
@@ -711,20 +665,6 @@ var fmtTests = []struct {
 	{"%x", byteFormatterSlice, "61626364"},
 	// This next case seems wrong, but the docs say the Formatter wins here.
 	{"%#v", byteFormatterSlice, "[]fmt_test.byteFormatter{X, X, X, X}"},
-
-	// reflect.Value handled specially in Go 1.5, making it possible to
-	// see inside non-exported fields (which cannot be accessed with Interface()).
-	// Issue 8965.
-	{"%v", reflect.ValueOf(A{}).Field(0).String(), "<int Value>"}, // Equivalent to the old way.
-	{"%v", reflect.ValueOf(A{}).Field(0), "0"},                    // Sees inside the field.
-
-	// verbs apply to the extracted value too.
-	{"%s", reflect.ValueOf("hello"), "hello"},
-	{"%q", reflect.ValueOf("hello"), `"hello"`},
-	{"%#04x", reflect.ValueOf(256), "0x0100"},
-
-	// invalid reflect.Value doesn't crash.
-	{"%v", reflect.Value{}, "<invalid reflect.Value>"},
 }
 
 // zeroFill generates zero-filled strings of the specified width. The length
@@ -851,11 +791,6 @@ var reorderTests = []struct {
 	{"%d %d %d %#[1]o %#o %#o %#o", SE{11, 12, 13}, "11 12 13 013 014 015 %!o(MISSING)"},
 	{"%[5]d %[2]d %d", SE{1, 2, 3}, "%!d(BADINDEX) 2 3"},
 	{"%d %[3]d %d", SE{1, 2}, "1 %!d(BADINDEX) 2"}, // Erroneous index does not affect sequence.
-	{"%.[]", SE{}, "%!](BADINDEX)"},                // Issue 10675
-	{"%.-3d", SE{42}, "%!-(int=42)3d"},             // TODO: Should this set return better error messages?
-	{"%2147483648d", SE{42}, "%!(NOVERB)%!(EXTRA int=42)"},
-	{"%-2147483648d", SE{42}, "%!(NOVERB)%!(EXTRA int=42)"},
-	{"%.2147483648d", SE{42}, "%!(NOVERB)%!(EXTRA int=42)"},
 }
 
 func TestReorder(t *testing.T) {
@@ -934,15 +869,6 @@ func BenchmarkFprintInt(b *testing.B) {
 	}
 }
 
-func BenchmarkFprintfBytes(b *testing.B) {
-	data := []byte(string("0123456789"))
-	var buf bytes.Buffer
-	for i := 0; i < b.N; i++ {
-		buf.Reset()
-		Fprintf(&buf, "%s", data)
-	}
-}
-
 func BenchmarkFprintIntNoAlloc(b *testing.B) {
 	var x interface{} = 123456
 	var buf bytes.Buffer
@@ -977,13 +903,11 @@ var mallocTest = []struct {
 var _ bytes.Buffer
 
 func TestCountMallocs(t *testing.T) {
-	switch {
-	case testing.Short():
+	if testing.Short() {
 		t.Skip("skipping malloc count in short mode")
-	case runtime.GOMAXPROCS(0) > 1:
+	}
+	if runtime.GOMAXPROCS(0) > 1 {
 		t.Skip("skipping; GOMAXPROCS>1")
-	case raceenabled:
-		t.Skip("skipping malloc count under race detector")
 	}
 	for _, mt := range mallocTest {
 		mallocs := testing.AllocsPerRun(100, mt.fn)
@@ -1182,20 +1106,14 @@ var startests = []struct {
 	out string
 }{
 	{"%*d", args(4, 42), "  42"},
-	{"%-*d", args(4, 42), "42  "},
-	{"%*d", args(-4, 42), "42  "},
-	{"%-*d", args(-4, 42), "42  "},
 	{"%.*d", args(4, 42), "0042"},
 	{"%*.*d", args(8, 4, 42), "    0042"},
 	{"%0*d", args(4, 42), "0042"},
+	{"%-*d", args(4, 42), "42  "},
 
 	// erroneous
 	{"%*d", args(nil, 42), "%!(BADWIDTH)42"},
-	{"%*d", args(int(1e7), 42), "%!(BADWIDTH)42"},
-	{"%*d", args(int(-1e7), 42), "%!(BADWIDTH)42"},
 	{"%.*d", args(nil, 42), "%!(BADPREC)42"},
-	{"%.*d", args(-1, 42), "%!(BADPREC)42"},
-	{"%.*d", args(int(1e7), 42), "%!(BADPREC)42"},
 	{"%*d", args(5, "foo"), "%!d(string=  foo)"},
 	{"%*% %d", args(20, 5), "% 5"},
 	{"%*", args(4), "%!(NOVERB)"},
@@ -1313,7 +1231,7 @@ func TestNilDoesNotBecomeTyped(t *testing.T) {
 	type B struct{}
 	var a *A = nil
 	var b B = B{}
-	got := Sprintf("%s %s %s %s %s", nil, a, nil, b, nil) // go vet should complain about this line.
+	got := Sprintf("%s %s %s %s %s", nil, a, nil, b, nil)
 	const expect = "%!s(<nil>) %!s(*fmt_test.A=<nil>) %!s(<nil>) {} %!s(<nil>)"
 	if got != expect {
 		t.Errorf("expected:\n\t%q\ngot:\n\t%q", expect, got)
diff --git a/src/fmt/format.go b/src/fmt/format.go
index 517b18f..4d97d14 100644
--- a/src/fmt/format.go
+++ b/src/fmt/format.go
@@ -162,35 +162,24 @@ func (f *fmt) integer(a int64, base uint64, signedness bool, digits string) {
 		return
 	}
 
-	negative := signedness == signed && a < 0
-	if negative {
-		a = -a
-	}
-
 	var buf []byte = f.intbuf[0:]
-	if f.widPresent || f.precPresent || f.plus || f.space {
-		width := f.wid + f.prec // Only one will be set, both are positive; this provides the maximum.
+	if f.widPresent {
+		width := f.wid
 		if base == 16 && f.sharp {
 			// Also adds "0x".
 			width += 2
 		}
-		if f.unicode {
-			// Also adds "U+".
-			width += 2
-			if f.uniQuote {
-				// Also adds " 'x'".
-				width += 1 + 1 + utf8.UTFMax + 1
-			}
-		}
-		if negative || f.plus || f.space {
-			width++
-		}
 		if width > nByte {
 			// We're going to need a bigger boat.
 			buf = make([]byte, width)
 		}
 	}
 
+	negative := signedness == signed && a < 0
+	if negative {
+		a = -a
+	}
+
 	// two ways to ask for extra leading zero digits: %.3d or %03d.
 	// apparently the first cancels the second.
 	prec := 0
diff --git a/src/fmt/print.go b/src/fmt/print.go
index 8d3e97c..59a30d2 100644
--- a/src/fmt/print.go
+++ b/src/fmt/print.go
@@ -285,22 +285,12 @@ func getField(v reflect.Value, i int) reflect.Value {
 	return val
 }
 
-// tooLarge reports whether the magnitude of the integer is
-// too large to be used as a formatting width or precision.
-func tooLarge(x int) bool {
-	const max int = 1e6
-	return x > max || x < -max
-}
-
 // parsenum converts ASCII to integer.  num is 0 (and isnum is false) if no number present.
 func parsenum(s string, start, end int) (num int, isnum bool, newi int) {
 	if start >= end {
 		return 0, false, end
 	}
 	for newi = start; newi < end && '0' <= s[newi] && s[newi] <= '9'; newi++ {
-		if tooLarge(num) {
-			return 0, false, end // Overflow; crazy long number most likely.
-		}
 		num = num*10 + int(s[newi]-'0')
 		isnum = true
 	}
@@ -799,8 +789,6 @@ func (p *pp) printArg(arg interface{}, verb rune, depth int) (wasString bool) {
 	case []byte:
 		p.fmtBytes(f, verb, nil, depth)
 		wasString = verb == 's'
-	case reflect.Value:
-		return p.printReflectValue(f, verb, depth)
 	default:
 		// If the type is not simple, it might have methods.
 		if handled := p.handleMethods(verb, depth); handled {
@@ -857,8 +845,6 @@ func (p *pp) printReflectValue(value reflect.Value, verb rune, depth int) (wasSt
 	p.value = value
 BigSwitch:
 	switch f := value; f.Kind() {
-	case reflect.Invalid:
-		p.buf.WriteString("<invalid reflect.Value>")
 	case reflect.Bool:
 		p.fmtBool(f.Bool(), verb)
 	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
@@ -1030,10 +1016,6 @@ func intFromArg(a []interface{}, argNum int) (num int, isInt bool, newArgNum int
 	if argNum < len(a) {
 		num, isInt = a[argNum].(int)
 		newArgNum = argNum + 1
-		if tooLarge(num) {
-			num = 0
-			isInt = false
-		}
 	}
 	return
 }
@@ -1045,11 +1027,6 @@ func intFromArg(a []interface{}, argNum int) (num int, isInt bool, newArgNum int
 // up to the closing paren, if present, and whether the number parsed
 // ok. The bytes to consume will be 1 if no closing paren is present.
 func parseArgNumber(format string) (index int, wid int, ok bool) {
-	// There must be at least 3 bytes: [n].
-	if len(format) < 3 {
-		return 0, 1, false
-	}
-
 	// Find closing bracket.
 	for i := 1; i < len(format); i++ {
 		if format[i] == ']' {
@@ -1076,7 +1053,7 @@ func (p *pp) argNumber(argNum int, format string, i int, numArgs int) (newArgNum
 		return index, i + wid, true
 	}
 	p.goodArgNum = false
-	return argNum, i + wid, ok
+	return argNum, i + wid, true
 }
 
 func (p *pp) doPrintf(format string, a []interface{}) {
@@ -1128,17 +1105,9 @@ func (p *pp) doPrintf(format string, a []interface{}) {
 		if i < end && format[i] == '*' {
 			i++
 			p.fmt.wid, p.fmt.widPresent, argNum = intFromArg(a, argNum)
-
 			if !p.fmt.widPresent {
 				p.buf.Write(badWidthBytes)
 			}
-
-			// We have a negative width, so take its value and ensure
-			// that the minus flag is set
-			if p.fmt.wid < 0 {
-				p.fmt.wid = -p.fmt.wid
-				p.fmt.minus = true
-			}
 			afterIndex = false
 		} else {
 			p.fmt.wid, p.fmt.widPresent, i = parsenum(format, i, end)
@@ -1154,14 +1123,9 @@ func (p *pp) doPrintf(format string, a []interface{}) {
 				p.goodArgNum = false
 			}
 			argNum, i, afterIndex = p.argNumber(argNum, format, i, len(a))
-			if i < end && format[i] == '*' {
+			if format[i] == '*' {
 				i++
 				p.fmt.prec, p.fmt.precPresent, argNum = intFromArg(a, argNum)
-				// Negative precision arguments don't make sense
-				if p.fmt.prec < 0 {
-					p.fmt.prec = 0
-					p.fmt.precPresent = false
-				}
 				if !p.fmt.precPresent {
 					p.buf.Write(badPrecBytes)
 				}
diff --git a/src/fmt/scan.go b/src/fmt/scan.go
index 5b9b516..d7befea 100644
--- a/src/fmt/scan.go
+++ b/src/fmt/scan.go
@@ -34,16 +34,16 @@ type ScanState interface {
 	ReadRune() (r rune, size int, err error)
 	// UnreadRune causes the next call to ReadRune to return the same rune.
 	UnreadRune() error
-	// SkipSpace skips space in the input. Newlines are treated appropriately
-	// for the operation being performed; see the package documentation
-	// for more information.
+	// SkipSpace skips space in the input. Newlines are treated as space
+	// unless the scan operation is Scanln, Fscanln or Sscanln, in which case
+	// a newline is treated as EOF.
 	SkipSpace()
 	// Token skips space in the input if skipSpace is true, then returns the
 	// run of Unicode code points c satisfying f(c).  If f is nil,
 	// !unicode.IsSpace(c) is used; that is, the token will hold non-space
-	// characters.  Newlines are treated appropriately for the operation being
-	// performed; see the package documentation for more information.
-	// The returned slice points to shared data that may be overwritten
+	// characters.  Newlines are treated as space unless the scan operation
+	// is Scanln, Fscanln or Sscanln, in which case a newline is treated as
+	// EOF.  The returned slice points to shared data that may be overwritten
 	// by the next call to Token, a call to a Scan function using the ScanState
 	// as input, or when the calling Scan method returns.
 	Token(skipSpace bool, f func(rune) bool) (token []byte, err error)
@@ -81,8 +81,6 @@ func Scanln(a ...interface{}) (n int, err error) {
 // Scanf scans text read from standard input, storing successive
 // space-separated values into successive arguments as determined by
 // the format.  It returns the number of items successfully scanned.
-// If that is less than the number of arguments, err will report why.
-// Newlines in the input must match newlines in the format.
 func Scanf(format string, a ...interface{}) (n int, err error) {
 	return Fscanf(os.Stdin, format, a...)
 }
@@ -115,7 +113,6 @@ func Sscanln(str string, a ...interface{}) (n int, err error) {
 // Sscanf scans the argument string, storing successive space-separated
 // values into successive arguments as determined by the format.  It
 // returns the number of items successfully parsed.
-// Newlines in the input must match newlines in the format.
 func Sscanf(str string, format string, a ...interface{}) (n int, err error) {
 	return Fscanf((*stringReader)(&str), format, a...)
 }
@@ -143,7 +140,6 @@ func Fscanln(r io.Reader, a ...interface{}) (n int, err error) {
 // Fscanf scans text read from r, storing successive space-separated
 // values into successive arguments as determined by the format.  It
 // returns the number of items successfully parsed.
-// Newlines in the input must match newlines in the format.
 func Fscanf(r io.Reader, format string, a ...interface{}) (n int, err error) {
 	s, old := newScanState(r, false, false)
 	n, err = s.doScanf(format, a)
@@ -391,6 +387,17 @@ var ssFree = sync.Pool{
 
 // newScanState allocates a new ss struct or grab a cached one.
 func newScanState(r io.Reader, nlIsSpace, nlIsEnd bool) (s *ss, old ssave) {
+	// If the reader is a *ss, then we've got a recursive
+	// call to Scan, so re-use the scan state.
+	s, ok := r.(*ss)
+	if ok {
+		old = s.ssave
+		s.limit = s.argLimit
+		s.nlIsEnd = nlIsEnd || s.nlIsEnd
+		s.nlIsSpace = nlIsSpace
+		return
+	}
+
 	s = ssFree.Get().(*ss)
 	if rr, ok := r.(io.RuneReader); ok {
 		s.rr = rr
@@ -868,39 +875,34 @@ func (s *ss) quotedString() string {
 	return ""
 }
 
-// hexDigit returns the value of the hexadecimal digit.
-func hexDigit(d rune) (int, bool) {
+// hexDigit returns the value of the hexadecimal digit
+func (s *ss) hexDigit(d rune) int {
 	digit := int(d)
 	switch digit {
 	case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
-		return digit - '0', true
+		return digit - '0'
 	case 'a', 'b', 'c', 'd', 'e', 'f':
-		return 10 + digit - 'a', true
+		return 10 + digit - 'a'
 	case 'A', 'B', 'C', 'D', 'E', 'F':
-		return 10 + digit - 'A', true
+		return 10 + digit - 'A'
 	}
-	return -1, false
+	s.errorString("illegal hex digit")
+	return 0
 }
 
 // hexByte returns the next hex-encoded (two-character) byte from the input.
-// It returns ok==false if the next bytes in the input do not encode a hex byte.
-// If the first byte is hex and the second is not, processing stops.
+// There must be either two hexadecimal digits or a space character in the input.
 func (s *ss) hexByte() (b byte, ok bool) {
 	rune1 := s.getRune()
 	if rune1 == eof {
 		return
 	}
-	value1, ok := hexDigit(rune1)
-	if !ok {
+	if isSpace(rune1) {
 		s.UnreadRune()
 		return
 	}
-	value2, ok := hexDigit(s.mustReadRune())
-	if !ok {
-		s.errorString("illegal hex digit")
-		return
-	}
-	return byte(value1<<4 | value2), true
+	rune2 := s.mustReadRune()
+	return byte(s.hexDigit(rune1)<<4 | s.hexDigit(rune2)), true
 }
 
 // hexString returns the space-delimited hexpair-encoded string.
@@ -1048,8 +1050,8 @@ func (s *ss) doScan(a []interface{}) (numProcessed int, err error) {
 		s.scanOne('v', arg)
 		numProcessed++
 	}
-	// Check for newline (or EOF) if required (Scanln etc.).
-	if s.nlIsEnd {
+	// Check for newline if required.
+	if !s.nlIsSpace {
 		for {
 			r := s.getRune()
 			if r == '\n' || r == eof {
@@ -1065,13 +1067,12 @@ func (s *ss) doScan(a []interface{}) (numProcessed int, err error) {
 }
 
 // advance determines whether the next characters in the input match
-// those of the format. It returns the number of bytes (sic) consumed
-// in the format. All runs of space characters in either input or
-// format behave as a single space. Newlines are special, though:
-// newlines in the format must match those in the input and vice versa.
-// This routine also handles the %% case. If the return value is zero,
-// either format starts with a % (with no following %) or the input
-// is empty. If it is negative, the input did not match the string.
+// those of the format.  It returns the number of bytes (sic) consumed
+// in the format. Newlines included, all runs of space characters in
+// either input or format behave as a single space. This routine also
+// handles the %% case.  If the return value is zero, either format
+// starts with a % (with no following %) or the input is empty.
+// If it is negative, the input did not match the string.
 func (s *ss) advance(format string) (i int) {
 	for i < len(format) {
 		fmtc, w := utf8.DecodeRuneInString(format[i:])
@@ -1084,45 +1085,24 @@ func (s *ss) advance(format string) (i int) {
 			i += w // skip the first %
 		}
 		sawSpace := false
-		wasNewline := false
-		// Skip spaces in format but absorb at most one newline.
 		for isSpace(fmtc) && i < len(format) {
-			if fmtc == '\n' {
-				if wasNewline { // Already saw one; stop here.
-					break
-				}
-				wasNewline = true
-			}
 			sawSpace = true
 			i += w
 			fmtc, w = utf8.DecodeRuneInString(format[i:])
 		}
 		if sawSpace {
-			// There was space in the format, so there should be space
+			// There was space in the format, so there should be space (EOF)
 			// in the input.
 			inputc := s.getRune()
-			if inputc == eof {
+			if inputc == eof || inputc == '\n' {
+				// If we've reached a newline, stop now; don't read ahead.
 				return
 			}
 			if !isSpace(inputc) {
-				// Space in format but not in input.
+				// Space in format but not in input: error
 				s.errorString("expected space in input to match format")
 			}
-			// Skip spaces but stop at newline.
-			for inputc != '\n' && isSpace(inputc) {
-				inputc = s.getRune()
-			}
-			if inputc == '\n' {
-				if !wasNewline {
-					s.errorString("newline in input does not match format")
-				}
-				// We've reached a newline, stop now; don't read further.
-				return
-			}
-			s.UnreadRune()
-			if wasNewline {
-				s.errorString("newline in format does not match input")
-			}
+			s.skipSpace(true)
 			continue
 		}
 		inputc := s.mustReadRune()
@@ -1164,7 +1144,6 @@ func (s *ss) doScanf(format string, a []interface{}) (numProcessed int, err erro
 		if !widPresent {
 			s.maxWid = hugeWid
 		}
-		s.SkipSpace()
 		s.argLimit = s.limit
 		if f := s.count + s.maxWid; f < s.argLimit {
 			s.argLimit = f
diff --git a/src/fmt/scan_test.go b/src/fmt/scan_test.go
index a378436..541e12d 100644
--- a/src/fmt/scan_test.go
+++ b/src/fmt/scan_test.go
@@ -340,8 +340,6 @@ var multiTests = []ScanfMultiTest{
 	{"%6vX=%3fY", "3+2iX=2.5Y", args(&c, &f), args((3 + 2i), 2.5), ""},
 	{"%d%s", "123abc", args(&i, &s), args(123, "abc"), ""},
 	{"%c%c%c", "2\u50c2X", args(&r1, &r2, &r3), args('2', '\u50c2', 'X'), ""},
-	{"%5s%d", " 1234567 ", args(&s, &i), args("12345", 67), ""},
-	{"%5s%d", " 12 34 567 ", args(&s, &i), args("12", 34), ""},
 
 	// Custom scanners.
 	{"%e%f", "eefffff", args(&x, &y), args(Xs("ee"), Xs("fffff")), ""},
@@ -866,7 +864,7 @@ func TestScanStateCount(t *testing.T) {
 		t.Fatal(err)
 	}
 	if n != 3 {
-		t.Fatalf("expected 3 items consumed, got %d", n)
+		t.Fatalf("expected 3 items consumed, got %d")
 	}
 	if a.rune != '1' || b.rune != '2' || c.rune != '➂' {
 		t.Errorf("bad scan rune: %q %q %q should be '1' '2' '➂'", a.rune, b.rune, c.rune)
@@ -992,167 +990,3 @@ func BenchmarkScanRecursiveInt(b *testing.B) {
 		b.StopTimer()
 	}
 }
-
-// Issue 9124.
-// %x on bytes couldn't handle non-space bytes terminating the scan.
-func TestHexBytes(t *testing.T) {
-	var a, b []byte
-	n, err := Sscanf("00010203", "%x", &a)
-	if n != 1 || err != nil {
-		t.Errorf("simple: got count, err = %d, %v; expected 1, nil", n, err)
-	}
-	check := func(msg string, x []byte) {
-		if len(x) != 4 {
-			t.Errorf("%s: bad length %d", msg, len(x))
-		}
-		for i, b := range x {
-			if int(b) != i {
-				t.Errorf("%s: bad x[%d] = %x", msg, i, x[i])
-			}
-		}
-	}
-	check("simple", a)
-	a = nil
-
-	n, err = Sscanf("00010203 00010203", "%x %x", &a, &b)
-	if n != 2 || err != nil {
-		t.Errorf("simple pair: got count, err = %d, %v; expected 2, nil", n, err)
-	}
-	check("simple pair a", a)
-	check("simple pair b", b)
-	a = nil
-	b = nil
-
-	n, err = Sscanf("00010203:", "%x", &a)
-	if n != 1 || err != nil {
-		t.Errorf("colon: got count, err = %d, %v; expected 1, nil", n, err)
-	}
-	check("colon", a)
-	a = nil
-
-	n, err = Sscanf("00010203:00010203", "%x:%x", &a, &b)
-	if n != 2 || err != nil {
-		t.Errorf("colon pair: got count, err = %d, %v; expected 2, nil", n, err)
-	}
-	check("colon pair a", a)
-	check("colon pair b", b)
-	a = nil
-	b = nil
-
-	// This one fails because there is a hex byte after the data,
-	// that is, an odd number of hex input bytes.
-	n, err = Sscanf("000102034:", "%x", &a)
-	if n != 0 || err == nil {
-		t.Errorf("odd count: got count, err = %d, %v; expected 0, error", n, err)
-	}
-}
-
-func TestScanNewlinesAreSpaces(t *testing.T) {
-	var a, b int
-	var tests = []struct {
-		name  string
-		text  string
-		count int
-	}{
-		{"newlines", "1\n2\n", 2},
-		{"no final newline", "1\n2", 2},
-		{"newlines with spaces ", "1  \n  2  \n", 2},
-		{"no final newline with spaces", "1  \n  2", 2},
-	}
-	for _, test := range tests {
-		n, err := Sscan(test.text, &a, &b)
-		if n != test.count {
-			t.Errorf("%s: expected to scan %d item(s), scanned %d", test.name, test.count, n)
-		}
-		if err != nil {
-			t.Errorf("%s: unexpected error: %s", test.name, err)
-		}
-	}
-}
-
-func TestScanlnNewlinesTerminate(t *testing.T) {
-	var a, b int
-	var tests = []struct {
-		name  string
-		text  string
-		count int
-		ok    bool
-	}{
-		{"one line one item", "1\n", 1, false},
-		{"one line two items with spaces ", "   1 2    \n", 2, true},
-		{"one line two items no newline", "   1 2", 2, true},
-		{"two lines two items", "1\n2\n", 1, false},
-	}
-	for _, test := range tests {
-		n, err := Sscanln(test.text, &a, &b)
-		if n != test.count {
-			t.Errorf("%s: expected to scan %d item(s), scanned %d", test.name, test.count, n)
-		}
-		if test.ok && err != nil {
-			t.Errorf("%s: unexpected error: %s", test.name, err)
-		}
-		if !test.ok && err == nil {
-			t.Errorf("%s: expected error; got none", test.name)
-		}
-	}
-}
-
-func TestScanfNewlineMatchFormat(t *testing.T) {
-	var a, b int
-	var tests = []struct {
-		name   string
-		text   string
-		format string
-		count  int
-		ok     bool
-	}{
-		{"newline in both", "1\n2", "%d\n%d\n", 2, true},
-		{"newline in input", "1\n2", "%d %d", 1, false},
-		{"space-newline in input", "1 \n2", "%d %d", 1, false},
-		{"newline in format", "1 2", "%d\n%d", 1, false},
-		{"space-newline in format", "1 2", "%d \n%d", 1, false},
-		{"space-newline in both", "1 \n2", "%d \n%d", 2, true},
-		{"extra space in format", "1\n2", "%d\n %d", 2, true},
-		{"two extra spaces in format", "1\n2", "%d \n %d", 2, true},
-	}
-	for _, test := range tests {
-		n, err := Sscanf(test.text, test.format, &a, &b)
-		if n != test.count {
-			t.Errorf("%s: expected to scan %d item(s), scanned %d", test.name, test.count, n)
-		}
-		if test.ok && err != nil {
-			t.Errorf("%s: unexpected error: %s", test.name, err)
-		}
-		if !test.ok && err == nil {
-			t.Errorf("%s: expected error; got none", test.name)
-		}
-	}
-}
-
-// Test for issue 12090: Was unreading at EOF, double-scanning a byte.
-
-type hexBytes [2]byte
-
-func (h *hexBytes) Scan(ss ScanState, verb rune) error {
-	var b []byte
-	_, err := Fscanf(ss, "%4x", &b)
-	if err != nil {
-		panic(err) // Really shouldn't happen.
-	}
-	copy((*h)[:], b)
-	return err
-}
-
-func TestHexByte(t *testing.T) {
-	var h hexBytes
-	n, err := Sscanln("0123\n", &h)
-	if err != nil {
-		t.Fatal(err)
-	}
-	if n != 1 {
-		t.Fatalf("expected 1 item; scanned %d", n)
-	}
-	if h[0] != 0x01 || h[1] != 0x23 {
-		t.Fatalf("expected 0123 got %x", h)
-	}
-}
diff --git a/src/go/ast/ast.go b/src/go/ast/ast.go
index 5ab4283..312e3d1 100644
--- a/src/go/ast/ast.go
+++ b/src/go/ast/ast.go
@@ -486,7 +486,7 @@ func (x *MapType) End() token.Pos       { return x.Value.End() }
 func (x *ChanType) End() token.Pos      { return x.Value.End() }
 
 // exprNode() ensures that only expression/type nodes can be
-// assigned to an Expr.
+// assigned to an ExprNode.
 //
 func (*BadExpr) exprNode()        {}
 func (*Ident) exprNode()          {}
@@ -562,11 +562,10 @@ type (
 
 	// An EmptyStmt node represents an empty statement.
 	// The "position" of the empty statement is the position
-	// of the immediately following (explicit or implicit) semicolon.
+	// of the immediately preceding semicolon.
 	//
 	EmptyStmt struct {
-		Semicolon token.Pos // position of following ";"
-		Implicit  bool      // if set, ";" was omitted in the source
+		Semicolon token.Pos // position of preceding ";"
 	}
 
 	// A LabeledStmt node represents a labeled statement.
@@ -735,9 +734,6 @@ func (s *RangeStmt) Pos() token.Pos      { return s.For }
 func (s *BadStmt) End() token.Pos  { return s.To }
 func (s *DeclStmt) End() token.Pos { return s.Decl.End() }
 func (s *EmptyStmt) End() token.Pos {
-	if s.Implicit {
-		return s.Semicolon
-	}
 	return s.Semicolon + 1 /* len(";") */
 }
 func (s *LabeledStmt) End() token.Pos { return s.Stmt.End() }
@@ -787,7 +783,7 @@ func (s *ForStmt) End() token.Pos    { return s.Body.End() }
 func (s *RangeStmt) End() token.Pos  { return s.Body.End() }
 
 // stmtNode() ensures that only statement nodes can be
-// assigned to a Stmt.
+// assigned to a StmtNode.
 //
 func (*BadStmt) stmtNode()        {}
 func (*DeclStmt) stmtNode()       {}
@@ -951,7 +947,7 @@ func (d *FuncDecl) End() token.Pos {
 }
 
 // declNode() ensures that only declaration nodes can be
-// assigned to a Decl.
+// assigned to a DeclNode.
 //
 func (*BadDecl) declNode()  {}
 func (*GenDecl) declNode()  {}
diff --git a/src/go/ast/filter.go b/src/go/ast/filter.go
index bb57116..fc3eeb4 100644
--- a/src/go/ast/filter.go
+++ b/src/go/ast/filter.go
@@ -23,7 +23,8 @@ func exportFilter(name string) bool {
 // body) are removed. Non-exported fields and methods of exported types are
 // stripped. The File.Comments list is not changed.
 //
-// FileExports reports whether there are exported declarations.
+// FileExports returns true if there are exported declarations;
+// it returns false otherwise.
 //
 func FileExports(src *File) bool {
 	return filterFile(src, exportFilter, true)
@@ -33,7 +34,7 @@ func FileExports(src *File) bool {
 // only exported nodes remain. The pkg.Files list is not changed, so that
 // file names and top-level package comments don't get lost.
 //
-// PackageExports reports whether there are exported declarations;
+// PackageExports returns true if there are exported declarations;
 // it returns false otherwise.
 //
 func PackageExports(pkg *Package) bool {
@@ -198,8 +199,8 @@ func filterSpecList(list []Spec, f Filter, export bool) []Spec {
 // all names (including struct field and interface method names, but
 // not from parameter lists) that don't pass through the filter f.
 //
-// FilterDecl reports whether there are any declared names left after
-// filtering.
+// FilterDecl returns true if there are any declared names left after
+// filtering; it returns false otherwise.
 //
 func FilterDecl(decl Decl, f Filter) bool {
 	return filterDecl(decl, f, false)
@@ -220,11 +221,11 @@ func filterDecl(decl Decl, f Filter, export bool) bool {
 // names from top-level declarations (including struct field and
 // interface method names, but not from parameter lists) that don't
 // pass through the filter f. If the declaration is empty afterwards,
-// the declaration is removed from the AST. Import declarations are
-// always removed. The File.Comments list is not changed.
+// the declaration is removed from the AST. The File.Comments list
+// is not changed.
 //
-// FilterFile reports whether there are any top-level declarations
-// left after filtering.
+// FilterFile returns true if there are any top-level declarations
+// left after filtering; it returns false otherwise.
 //
 func FilterFile(src *File, f Filter) bool {
 	return filterFile(src, f, false)
@@ -250,8 +251,8 @@ func filterFile(src *File, f Filter, export bool) bool {
 // changed, so that file names and top-level package comments don't get
 // lost.
 //
-// FilterPackage reports whether there are any top-level declarations
-// left after filtering.
+// FilterPackage returns true if there are any top-level declarations
+// left after filtering; it returns false otherwise.
 //
 func FilterPackage(pkg *Package, f Filter) bool {
 	return filterPackage(pkg, f, false)
diff --git a/src/go/ast/scope.go b/src/go/ast/scope.go
index 1ce5e2e..df1529d 100644
--- a/src/go/ast/scope.go
+++ b/src/go/ast/scope.go
@@ -38,7 +38,7 @@ func (s *Scope) Lookup(name string) *Object {
 // Insert attempts to insert a named object obj into the scope s.
 // If the scope already contains an object alt with the same name,
 // Insert leaves the scope unchanged and returns alt. Otherwise
-// it inserts obj and returns nil.
+// it inserts obj and returns nil."
 //
 func (s *Scope) Insert(obj *Object) (alt *Object) {
 	if alt = s.Objects[obj.Name]; alt == nil {
diff --git a/src/go/ast/walk.go b/src/go/ast/walk.go
index 8ca2195..73ac386 100644
--- a/src/go/ast/walk.go
+++ b/src/go/ast/walk.go
@@ -361,7 +361,8 @@ func Walk(v Visitor, node Node) {
 		}
 
 	default:
-		panic(fmt.Sprintf("ast.Walk: unexpected node type %T", n))
+		fmt.Printf("ast.Walk: unexpected node type %T", n)
+		panic("ast.Walk")
 	}
 
 	v.Visit(nil)
@@ -378,8 +379,7 @@ func (f inspector) Visit(node Node) Visitor {
 
 // Inspect traverses an AST in depth-first order: It starts by calling
 // f(node); node must not be nil. If f returns true, Inspect invokes f
-// recursively for each of the non-nil children of node, followed by a
-// call of f(nil).
+// for all the non-nil children of node, recursively.
 //
 func Inspect(node Node, f func(Node) bool) {
 	Walk(inspector(f), node)
diff --git a/src/go/build/build.go b/src/go/build/build.go
index 496fe11..311ecb0 100644
--- a/src/go/build/build.go
+++ b/src/go/build/build.go
@@ -256,12 +256,10 @@ func (ctxt *Context) SrcDirs() []string {
 // if set, or else the compiled code's GOARCH, GOOS, and GOROOT.
 var Default Context = defaultContext()
 
-// Also known to cmd/dist/build.go.
 var cgoEnabled = map[string]bool{
 	"darwin/386":      true,
 	"darwin/amd64":    true,
-	"darwin/arm":      true,
-	"darwin/arm64":    true,
+	"dragonfly/386":   true,
 	"dragonfly/amd64": true,
 	"freebsd/386":     true,
 	"freebsd/amd64":   true,
@@ -269,8 +267,6 @@ var cgoEnabled = map[string]bool{
 	"linux/386":       true,
 	"linux/amd64":     true,
 	"linux/arm":       true,
-	"linux/arm64":     true,
-	"linux/ppc64le":   true,
 	"android/386":     true,
 	"android/amd64":   true,
 	"android/arm":     true,
@@ -279,7 +275,6 @@ var cgoEnabled = map[string]bool{
 	"netbsd/arm":      true,
 	"openbsd/386":     true,
 	"openbsd/amd64":   true,
-	"solaris/amd64":   true,
 	"windows/386":     true,
 	"windows/amd64":   true,
 }
@@ -298,7 +293,11 @@ func defaultContext() Context {
 	// in all releases >= Go 1.x. Code that requires Go 1.x or later should
 	// 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".
-	c.ReleaseTags = []string{"go1.1", "go1.2", "go1.3", "go1.4", "go1.5"}
+	//
+	// When we reach Go 1.5 the line will read
+	//	c.ReleaseTags = []string{"go1.1", "go1.2", "go1.3", "go1.4", "go1.5"}
+	// and so on.
+	c.ReleaseTags = []string{"go1.1", "go1.2", "go1.3", "go1.4"}
 
 	switch os.Getenv("CGO_ENABLED") {
 	case "1":
@@ -355,7 +354,6 @@ type Package struct {
 	Root          string   // root of Go tree where this package lives
 	SrcRoot       string   // package source root directory ("" if unknown)
 	PkgRoot       string   // package install root directory ("" if unknown)
-	PkgTargetRoot string   // architecture dependent install root directory ("" if unknown)
 	BinDir        string   // command install directory ("" if unknown)
 	Goroot        bool     // package found in Go root
 	PkgObj        string   // installed .a file
@@ -464,21 +462,18 @@ func (ctxt *Context) Import(path string, srcDir string, mode ImportMode) (*Packa
 		return p, fmt.Errorf("import %q: invalid import path", path)
 	}
 
-	var pkgtargetroot string
 	var pkga string
 	var pkgerr error
-	suffix := ""
-	if ctxt.InstallSuffix != "" {
-		suffix = "_" + ctxt.InstallSuffix
-	}
 	switch ctxt.Compiler {
 	case "gccgo":
-		pkgtargetroot = "pkg/gccgo_" + ctxt.GOOS + "_" + ctxt.GOARCH + suffix
 		dir, elem := pathpkg.Split(p.ImportPath)
-		pkga = pkgtargetroot + "/" + dir + "lib" + elem + ".a"
+		pkga = "pkg/gccgo_" + ctxt.GOOS + "_" + ctxt.GOARCH + "/" + dir + "lib" + elem + ".a"
 	case "gc":
-		pkgtargetroot = "pkg/" + ctxt.GOOS + "_" + ctxt.GOARCH + suffix
-		pkga = pkgtargetroot + "/" + p.ImportPath + ".a"
+		suffix := ""
+		if ctxt.InstallSuffix != "" {
+			suffix = "_" + ctxt.InstallSuffix
+		}
+		pkga = "pkg/" + ctxt.GOOS + "_" + ctxt.GOARCH + suffix + "/" + p.ImportPath + ".a"
 	default:
 		// Save error for end of function.
 		pkgerr = fmt.Errorf("import %q: unknown compiler %q", path, ctxt.Compiler)
@@ -494,13 +489,9 @@ func (ctxt *Context) Import(path string, srcDir string, mode ImportMode) (*Packa
 			p.Dir = ctxt.joinPath(srcDir, path)
 		}
 		// Determine canonical import path, if any.
-		// Exclude results where the import path would include /testdata/.
-		inTestdata := func(sub string) bool {
-			return strings.Contains(sub, "/testdata/") || strings.HasSuffix(sub, "/testdata") || strings.HasPrefix(sub, "testdata/") || sub == "testdata"
-		}
 		if ctxt.GOROOT != "" {
 			root := ctxt.joinPath(ctxt.GOROOT, "src")
-			if sub, ok := ctxt.hasSubdir(root, p.Dir); ok && !inTestdata(sub) {
+			if sub, ok := ctxt.hasSubdir(root, p.Dir); ok {
 				p.Goroot = true
 				p.ImportPath = sub
 				p.Root = ctxt.GOROOT
@@ -510,7 +501,7 @@ func (ctxt *Context) Import(path string, srcDir string, mode ImportMode) (*Packa
 		all := ctxt.gopath()
 		for i, root := range all {
 			rootsrc := ctxt.joinPath(root, "src")
-			if sub, ok := ctxt.hasSubdir(rootsrc, p.Dir); ok && !inTestdata(sub) {
+			if sub, ok := ctxt.hasSubdir(rootsrc, p.Dir); ok {
 				// We found a potential import path for dir,
 				// but check that using it wouldn't find something
 				// else first.
@@ -599,7 +590,6 @@ Found:
 		p.PkgRoot = ctxt.joinPath(p.Root, "pkg")
 		p.BinDir = ctxt.joinPath(p.Root, "bin")
 		if pkga != "" {
-			p.PkgTargetRoot = ctxt.joinPath(p.Root, pkgtargetroot)
 			p.PkgObj = ctxt.joinPath(p.Root, pkga)
 		}
 	}
@@ -698,11 +688,7 @@ Found:
 			p.Name = pkg
 			firstFile = name
 		} else if pkg != p.Name {
-			return p, &MultiplePackageError{
-				Dir:      p.Dir,
-				Packages: []string{p.Name, pkg},
-				Files:    []string{firstFile, name},
-			}
+			return p, &MultiplePackageError{p.Dir, []string{firstFile, name}, []string{p.Name, pkg}}
 		}
 		if pf.Doc != nil && p.Doc == "" {
 			p.Doc = doc.Synopsis(pf.Doc.Text())
@@ -969,7 +955,7 @@ func (ctxt *Context) matchFile(dir, name string, returnImports bool, allTags map
 	}
 
 	if strings.HasSuffix(filename, ".go") {
-		data, err = readImports(f, false, nil)
+		data, err = readImports(f, false)
 	} else {
 		data, err = readComments(f)
 	}
@@ -1082,6 +1068,9 @@ func (ctxt *Context) shouldBuild(content []byte, allTags map[string]bool) bool {
 // saveCgo saves the information from the #cgo lines in the import "C" comment.
 // These lines set CFLAGS, CPPFLAGS, CXXFLAGS and LDFLAGS and pkg-config directives
 // that affect the way cgo's C code is built.
+//
+// TODO(rsc): This duplicates code in cgo.
+// Once the dust settles, remove this code from cgo.
 func (ctxt *Context) saveCgo(filename string, di *Package, cg *ast.CommentGroup) error {
 	text := cg.Text()
 	for _, line := range strings.Split(text, "\n") {
@@ -1127,12 +1116,10 @@ func (ctxt *Context) saveCgo(filename string, di *Package, cg *ast.CommentGroup)
 		if err != nil {
 			return fmt.Errorf("%s: invalid #cgo line: %s", filename, orig)
 		}
-		for i, arg := range args {
-			arg = expandSrcDir(arg, di.Dir)
+		for _, arg := range args {
 			if !safeCgoName(arg) {
 				return fmt.Errorf("%s: malformed #cgo argument: %s", filename, arg)
 			}
-			args[i] = arg
 		}
 
 		switch verb {
@@ -1153,14 +1140,6 @@ func (ctxt *Context) saveCgo(filename string, di *Package, cg *ast.CommentGroup)
 	return nil
 }
 
-func expandSrcDir(str string, srcdir string) string {
-	// "\" delimited paths cause safeCgoName to fail
-	// so convert native paths with a different delimeter
-	// to "/" before starting (eg: on windows)
-	srcdir = filepath.ToSlash(srcdir)
-	return strings.Replace(str, "${SRCDIR}", srcdir, -1)
-}
-
 // NOTE: $ is not safe for the shell, but it is allowed here because of linker options like -Wl,$ORIGIN.
 // We never pass these arguments to a shell (just to programs we construct argv for), so this should be okay.
 // See golang.org/issue/6038.
@@ -1239,7 +1218,7 @@ func splitQuoted(s string) (r []string, err error) {
 	return args, err
 }
 
-// match reports whether the name is one of:
+// match returns true if the name is one of:
 //
 //	$GOOS
 //	$GOARCH
@@ -1330,7 +1309,7 @@ func (ctxt *Context) goodOSArchFile(name string, allTags map[string]bool) bool {
 	// build tag "linux" in that file. For Go 1.4 and beyond, we require this
 	// auto-tagging to apply only to files with a non-empty prefix, so
 	// "foo_linux.go" is tagged but "linux.go" is not. This allows new operating
-	// systems, such as android, to arrive without breaking existing code with
+	// sytems, such as android, to arrive without breaking existing code with
 	// innocuous source code in "android.go". The easiest fix: cut everything
 	// in the name before the initial _.
 	i := strings.Index(name, "_")
@@ -1397,11 +1376,16 @@ func IsLocalImport(path string) bool {
 		strings.HasPrefix(path, "./") || strings.HasPrefix(path, "../")
 }
 
-// ArchChar returns "?" and an error.
-// In earlier versions of Go, the returned string was used to derive
-// the compiler and linker tool names, the default object file suffix,
-// and the default linker output name. As of Go 1.5, those strings
-// no longer vary by architecture; they are compile, link, .o, and a.out, respectively.
+// ArchChar returns the architecture character for the given goarch.
+// For example, ArchChar("amd64") returns "6".
 func ArchChar(goarch string) (string, error) {
-	return "?", errors.New("architecture letter no longer used")
+	switch goarch {
+	case "386":
+		return "8", nil
+	case "amd64", "amd64p32":
+		return "6", nil
+	case "arm":
+		return "5", nil
+	}
+	return "", errors.New("unsupported GOARCH " + goarch)
 }
diff --git a/src/go/build/build_test.go b/src/go/build/build_test.go
index 92c3fe3..a40def0 100644
--- a/src/go/build/build_test.go
+++ b/src/go/build/build_test.go
@@ -94,28 +94,12 @@ func TestEmptyFolderImport(t *testing.T) {
 
 func TestMultiplePackageImport(t *testing.T) {
 	_, err := Import(".", "testdata/multi", 0)
-	mpe, ok := err.(*MultiplePackageError)
-	if !ok {
+	if _, ok := err.(*MultiplePackageError); !ok {
 		t.Fatal(`Import("testdata/multi") did not return MultiplePackageError.`)
 	}
-	want := &MultiplePackageError{
-		Dir:      filepath.FromSlash("testdata/multi"),
-		Packages: []string{"main", "test_package"},
-		Files:    []string{"file.go", "file_appengine.go"},
-	}
-	if !reflect.DeepEqual(mpe, want) {
-		t.Errorf("got %#v; want %#v", mpe, want)
-	}
 }
 
 func TestLocalDirectory(t *testing.T) {
-	if runtime.GOOS == "darwin" {
-		switch runtime.GOARCH {
-		case "arm", "arm64":
-			t.Skipf("skipping on %s/%s, no valid GOROOT", runtime.GOOS, runtime.GOARCH)
-		}
-	}
-
 	cwd, err := os.Getwd()
 	if err != nil {
 		t.Fatal(err)
@@ -230,13 +214,6 @@ func TestMatchFile(t *testing.T) {
 }
 
 func TestImportCmd(t *testing.T) {
-	if runtime.GOOS == "darwin" {
-		switch runtime.GOARCH {
-		case "arm", "arm64":
-			t.Skipf("skipping on %s/%s, no valid GOROOT", runtime.GOOS, runtime.GOARCH)
-		}
-	}
-
 	p, err := Import("cmd/internal/objfile", "", 0)
 	if err != nil {
 		t.Fatal(err)
@@ -245,33 +222,3 @@ func TestImportCmd(t *testing.T) {
 		t.Fatalf("Import cmd/internal/objfile returned Dir=%q, want %q", filepath.ToSlash(p.Dir), ".../src/cmd/internal/objfile")
 	}
 }
-
-var (
-	expandSrcDirPath = filepath.Join(string(filepath.Separator)+"projects", "src", "add")
-)
-
-var expandSrcDirTests = []struct {
-	input, expected string
-}{
-	{"-L ${SRCDIR}/libs -ladd", "-L /projects/src/add/libs -ladd"},
-	{"${SRCDIR}/add_linux_386.a -pthread -lstdc++", "/projects/src/add/add_linux_386.a -pthread -lstdc++"},
-	{"Nothing to expand here!", "Nothing to expand here!"},
-	{"$", "$"},
-	{"$$", "$$"},
-	{"${", "${"},
-	{"$}", "$}"},
-	{"$FOO ${BAR}", "$FOO ${BAR}"},
-	{"Find me the $SRCDIRECTORY.", "Find me the $SRCDIRECTORY."},
-	{"$SRCDIR is missing braces", "$SRCDIR is missing braces"},
-}
-
-func TestExpandSrcDir(t *testing.T) {
-	for _, test := range expandSrcDirTests {
-		output := expandSrcDir(test.input, expandSrcDirPath)
-		if output != test.expected {
-			t.Errorf("%q expands to %q with SRCDIR=%q when %q is expected", test.input, output, expandSrcDirPath, test.expected)
-		} else {
-			t.Logf("%q expands to %q with SRCDIR=%q", test.input, output, expandSrcDirPath)
-		}
-	}
-}
diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go
index 7cea949..b74595e 100644
--- a/src/go/build/deps_test.go
+++ b/src/go/build/deps_test.go
@@ -8,15 +8,8 @@
 package build
 
 import (
-	"bytes"
-	"fmt"
-	"io/ioutil"
-	"os"
-	"path/filepath"
 	"runtime"
 	"sort"
-	"strconv"
-	"strings"
 	"testing"
 )
 
@@ -128,12 +121,9 @@ var pkgDeps = map[string][]string{
 	// End of linear dependency definitions.
 
 	// Operating system access.
-	"syscall":                           {"L0", "unicode/utf16"},
-	"internal/syscall/unix":             {"L0", "syscall"},
-	"internal/syscall/windows":          {"L0", "syscall"},
-	"internal/syscall/windows/registry": {"L0", "syscall", "unicode/utf16"},
-	"time":          {"L0", "syscall", "internal/syscall/windows/registry"},
-	"os":            {"L1", "os", "syscall", "time", "internal/syscall/windows"},
+	"syscall":       {"L0", "unicode/utf16"},
+	"time":          {"L0", "syscall"},
+	"os":            {"L1", "os", "syscall", "time"},
 	"path/filepath": {"L2", "os", "syscall"},
 	"io/ioutil":     {"L2", "os", "path/filepath", "time"},
 	"os/exec":       {"L2", "os", "path/filepath", "syscall"},
@@ -158,13 +148,11 @@ var pkgDeps = map[string][]string{
 	"regexp/syntax":  {"L2"},
 	"runtime/debug":  {"L2", "fmt", "io/ioutil", "os", "time"},
 	"runtime/pprof":  {"L2", "fmt", "text/tabwriter"},
-	"runtime/trace":  {"L0"},
 	"text/tabwriter": {"L2"},
 
-	"testing":          {"L2", "flag", "fmt", "os", "runtime/pprof", "runtime/trace", "time"},
-	"testing/iotest":   {"L2", "log"},
-	"testing/quick":    {"L2", "flag", "fmt", "reflect"},
-	"internal/testenv": {"L2", "os", "testing"},
+	"testing":        {"L2", "flag", "fmt", "os", "runtime/pprof", "time"},
+	"testing/iotest": {"L2", "log"},
+	"testing/quick":  {"L2", "flag", "fmt", "reflect"},
 
 	// L4 is defined as L3+fmt+log+time, because in general once
 	// you're using L3 packages, use of fmt, log, or time is not a big deal.
@@ -192,60 +180,43 @@ var pkgDeps = map[string][]string{
 		"go/token",
 	},
 
-	"go/format":       {"L4", "GOPARSER", "internal/format"},
-	"internal/format": {"L4", "GOPARSER"},
-
-	// Go type checking.
-	"go/constant":               {"L4", "go/token", "math/big"},
-	"go/importer":               {"L4", "go/internal/gcimporter", "go/internal/gccgoimporter", "go/types"},
-	"go/internal/gcimporter":    {"L4", "OS", "go/build", "go/constant", "go/token", "go/types", "text/scanner"},
-	"go/internal/gccgoimporter": {"L4", "OS", "debug/elf", "go/constant", "go/token", "go/types", "text/scanner"},
-	"go/types":                  {"L4", "GOPARSER", "container/heap", "go/constant"},
-
 	// One of a kind.
-	"archive/tar":              {"L4", "OS", "syscall"},
-	"archive/zip":              {"L4", "OS", "compress/flate"},
-	"container/heap":           {"sort"},
-	"compress/bzip2":           {"L4"},
-	"compress/flate":           {"L4"},
-	"compress/gzip":            {"L4", "compress/flate"},
-	"compress/lzw":             {"L4"},
-	"compress/zlib":            {"L4", "compress/flate"},
-	"database/sql":             {"L4", "container/list", "database/sql/driver"},
-	"database/sql/driver":      {"L4", "time"},
-	"debug/dwarf":              {"L4"},
-	"debug/elf":                {"L4", "OS", "debug/dwarf"},
-	"debug/gosym":              {"L4"},
-	"debug/macho":              {"L4", "OS", "debug/dwarf"},
-	"debug/pe":                 {"L4", "OS", "debug/dwarf"},
-	"debug/plan9obj":           {"L4", "OS"},
-	"encoding":                 {"L4"},
-	"encoding/ascii85":         {"L4"},
-	"encoding/asn1":            {"L4", "math/big"},
-	"encoding/csv":             {"L4"},
-	"encoding/gob":             {"L4", "OS", "encoding"},
-	"encoding/hex":             {"L4"},
-	"encoding/json":            {"L4", "encoding"},
-	"encoding/pem":             {"L4"},
-	"encoding/xml":             {"L4", "encoding"},
-	"flag":                     {"L4", "OS"},
-	"go/build":                 {"L4", "OS", "GOPARSER"},
-	"html":                     {"L4"},
-	"image/draw":               {"L4", "image/internal/imageutil"},
-	"image/gif":                {"L4", "compress/lzw", "image/color/palette", "image/draw"},
-	"image/internal/imageutil": {"L4"},
-	"image/jpeg":               {"L4", "image/internal/imageutil"},
-	"image/png":                {"L4", "compress/zlib"},
-	"index/suffixarray":        {"L4", "regexp"},
-	"internal/singleflight":    {"sync"},
-	"internal/trace":           {"L4", "OS"},
-	"math/big":                 {"L4"},
-	"mime":                     {"L4", "OS", "syscall", "internal/syscall/windows/registry"},
-	"mime/quotedprintable":     {"L4"},
-	"net/internal/socktest":    {"L4", "OS", "syscall"},
-	"net/url":                  {"L4"},
-	"text/scanner":             {"L4", "OS"},
-	"text/template/parse":      {"L4"},
+	"archive/tar":         {"L4", "OS", "syscall"},
+	"archive/zip":         {"L4", "OS", "compress/flate"},
+	"compress/bzip2":      {"L4"},
+	"compress/flate":      {"L4"},
+	"compress/gzip":       {"L4", "compress/flate"},
+	"compress/lzw":        {"L4"},
+	"compress/zlib":       {"L4", "compress/flate"},
+	"database/sql":        {"L4", "container/list", "database/sql/driver"},
+	"database/sql/driver": {"L4", "time"},
+	"debug/dwarf":         {"L4"},
+	"debug/elf":           {"L4", "OS", "debug/dwarf"},
+	"debug/gosym":         {"L4"},
+	"debug/macho":         {"L4", "OS", "debug/dwarf"},
+	"debug/pe":            {"L4", "OS", "debug/dwarf"},
+	"encoding":            {"L4"},
+	"encoding/ascii85":    {"L4"},
+	"encoding/asn1":       {"L4", "math/big"},
+	"encoding/csv":        {"L4"},
+	"encoding/gob":        {"L4", "OS", "encoding"},
+	"encoding/hex":        {"L4"},
+	"encoding/json":       {"L4", "encoding"},
+	"encoding/pem":        {"L4"},
+	"encoding/xml":        {"L4", "encoding"},
+	"flag":                {"L4", "OS"},
+	"go/build":            {"L4", "OS", "GOPARSER"},
+	"html":                {"L4"},
+	"image/draw":          {"L4"},
+	"image/gif":           {"L4", "compress/lzw", "image/color/palette", "image/draw"},
+	"image/jpeg":          {"L4"},
+	"image/png":           {"L4", "compress/zlib"},
+	"index/suffixarray":   {"L4", "regexp"},
+	"math/big":            {"L4"},
+	"mime":                {"L4", "OS", "syscall"},
+	"net/url":             {"L4"},
+	"text/scanner":        {"L4", "OS"},
+	"text/template/parse": {"L4"},
 
 	"html/template": {
 		"L4", "OS", "encoding/json", "html", "text/template",
@@ -263,16 +234,13 @@ var pkgDeps = map[string][]string{
 	// that shows up in programs that use cgo.
 	"C": {},
 
-	// Race detector uses cgo.
-	"runtime/race": {"C"},
-
 	// Plan 9 alone needs io/ioutil and os.
 	"os/user": {"L4", "CGO", "io/ioutil", "os", "syscall"},
 
 	// Basic networking.
 	// Because net must be used by any package that wants to
 	// do networking portably, it must have a small dependency set: just L1+basic os.
-	"net": {"L1", "CGO", "os", "syscall", "time", "internal/syscall/windows", "internal/singleflight"},
+	"net": {"L1", "CGO", "os", "syscall", "time"},
 
 	// NET enables use of basic network-related packages.
 	"NET": {
@@ -284,7 +252,7 @@ var pkgDeps = map[string][]string{
 
 	// Uses of networking.
 	"log/syslog":    {"L4", "OS", "net"},
-	"net/mail":      {"L4", "NET", "OS", "mime"},
+	"net/mail":      {"L4", "NET", "OS"},
 	"net/textproto": {"L4", "OS", "net"},
 
 	// Core crypto.
@@ -311,7 +279,7 @@ var pkgDeps = map[string][]string{
 	// Random byte, number generation.
 	// This would be part of core crypto except that it imports
 	// math/big, which imports fmt.
-	"crypto/rand": {"L4", "CRYPTO", "OS", "math/big", "syscall", "internal/syscall/unix"},
+	"crypto/rand": {"L4", "CRYPTO", "OS", "math/big", "syscall", "internal/syscall"},
 
 	// Mathematical crypto: dependencies on fmt (L4) and math/big.
 	// We could avoid some of the fmt, but math/big imports fmt anyway.
@@ -343,7 +311,7 @@ var pkgDeps = map[string][]string{
 	"crypto/x509/pkix": {"L4", "CRYPTO-MATH"},
 
 	// Simple net+crypto-aware packages.
-	"mime/multipart": {"L4", "OS", "mime", "crypto/rand", "net/textproto", "mime/quotedprintable"},
+	"mime/multipart": {"L4", "OS", "mime", "crypto/rand", "net/textproto"},
 	"net/smtp":       {"L4", "CRYPTO", "NET", "crypto/tls"},
 
 	// HTTP, kingpin of dependencies.
@@ -352,18 +320,16 @@ var pkgDeps = map[string][]string{
 		"compress/gzip", "crypto/tls", "mime/multipart", "runtime/debug",
 		"net/http/internal",
 	},
-	"net/http/internal": {"L4"},
 
 	// HTTP-using packages.
-	"expvar":             {"L4", "OS", "encoding/json", "net/http"},
-	"net/http/cgi":       {"L4", "NET", "OS", "crypto/tls", "net/http", "regexp"},
-	"net/http/cookiejar": {"L4", "NET", "net/http"},
-	"net/http/fcgi":      {"L4", "NET", "OS", "net/http", "net/http/cgi"},
-	"net/http/httptest":  {"L4", "NET", "OS", "crypto/tls", "flag", "net/http"},
-	"net/http/httputil":  {"L4", "NET", "OS", "net/http", "net/http/internal"},
-	"net/http/pprof":     {"L4", "OS", "html/template", "net/http", "runtime/pprof", "runtime/trace"},
-	"net/rpc":            {"L4", "NET", "encoding/gob", "html/template", "net/http"},
-	"net/rpc/jsonrpc":    {"L4", "NET", "encoding/json", "net/rpc"},
+	"expvar":            {"L4", "OS", "encoding/json", "net/http"},
+	"net/http/cgi":      {"L4", "NET", "OS", "crypto/tls", "net/http", "regexp"},
+	"net/http/fcgi":     {"L4", "NET", "OS", "net/http", "net/http/cgi"},
+	"net/http/httptest": {"L4", "NET", "OS", "crypto/tls", "flag", "net/http"},
+	"net/http/httputil": {"L4", "NET", "OS", "net/http", "net/http/internal"},
+	"net/http/pprof":    {"L4", "OS", "html/template", "net/http", "runtime/pprof"},
+	"net/rpc":           {"L4", "NET", "encoding/gob", "html/template", "net/http"},
+	"net/rpc/jsonrpc":   {"L4", "NET", "encoding/json", "net/rpc"},
 }
 
 // isMacro reports whether p is a package dependency macro
@@ -409,112 +375,69 @@ var allowedErrors = map[osPkg]bool{
 	osPkg{"plan9", "log/syslog"}:   true,
 }
 
-// listStdPkgs returns the same list of packages as "go list std".
-func listStdPkgs(goroot string) ([]string, error) {
-	// Based on cmd/go's matchPackages function.
-	var pkgs []string
-
-	src := filepath.Join(goroot, "src") + string(filepath.Separator)
-	walkFn := func(path string, fi os.FileInfo, err error) error {
-		if err != nil || !fi.IsDir() || path == src {
-			return nil
-		}
-
-		base := filepath.Base(path)
-		if strings.HasPrefix(base, ".") || strings.HasPrefix(base, "_") || base == "testdata" {
-			return filepath.SkipDir
-		}
-
-		name := filepath.ToSlash(path[len(src):])
-		if name == "builtin" || name == "cmd" || strings.Contains(name, ".") {
-			return filepath.SkipDir
-		}
-
-		pkgs = append(pkgs, name)
-		return nil
-	}
-	if err := filepath.Walk(src, walkFn); err != nil {
-		return nil, err
-	}
-	return pkgs, nil
-}
-
 func TestDependencies(t *testing.T) {
-	iOS := runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64")
-	if runtime.GOOS == "nacl" || iOS {
-		// Tests run in a limited file system and we do not
+	if runtime.GOOS == "nacl" {
+		// NaCl tests run in a limited file system and we do not
 		// provide access to every source file.
-		t.Skipf("skipping on %s/%s, missing full GOROOT", runtime.GOOS, runtime.GOARCH)
+		t.Skip("skipping on NaCl")
 	}
+	var all []string
 
-	ctxt := Default
-	all, err := listStdPkgs(ctxt.GOROOT)
-	if err != nil {
-		t.Fatal(err)
+	for k := range pkgDeps {
+		all = append(all, k)
 	}
 	sort.Strings(all)
 
+	ctxt := Default
 	test := func(mustImport bool) {
 		for _, pkg := range all {
-			imports, err := findImports(pkg)
+			if isMacro(pkg) {
+				continue
+			}
+			if pkg == "runtime/cgo" && !ctxt.CgoEnabled {
+				continue
+			}
+			p, err := ctxt.Import(pkg, "", 0)
 			if err != nil {
-				t.Error(err)
+				if allowedErrors[osPkg{ctxt.GOOS, pkg}] {
+					continue
+				}
+				if !ctxt.CgoEnabled && pkg == "runtime/cgo" {
+					continue
+				}
+				// Some of the combinations we try might not
+				// be reasonable (like arm,plan9,cgo), so ignore
+				// errors for the auto-generated combinations.
+				if !mustImport {
+					continue
+				}
+				t.Errorf("%s/%s/cgo=%v %v", ctxt.GOOS, ctxt.GOARCH, ctxt.CgoEnabled, err)
 				continue
 			}
 			ok := allowed(pkg)
 			var bad []string
-			for _, imp := range imports {
+			for _, imp := range p.Imports {
 				if !ok[imp] {
 					bad = append(bad, imp)
 				}
 			}
 			if bad != nil {
-				t.Errorf("unexpected dependency: %s imports %v", pkg, bad)
+				t.Errorf("%s/%s/cgo=%v unexpected dependency: %s imports %v", ctxt.GOOS, ctxt.GOARCH, ctxt.CgoEnabled, pkg, bad)
 			}
 		}
 	}
 	test(true)
-}
-
-var buildIgnore = []byte("\n// +build ignore")
 
-func findImports(pkg string) ([]string, error) {
-	dir := filepath.Join(Default.GOROOT, "src", pkg)
-	files, err := ioutil.ReadDir(dir)
-	if err != nil {
-		return nil, err
+	if testing.Short() {
+		t.Logf("skipping other systems")
+		return
 	}
-	var imports []string
-	var haveImport = map[string]bool{}
-	for _, file := range files {
-		name := file.Name()
-		if !strings.HasSuffix(name, ".go") || strings.HasSuffix(name, "_test.go") {
-			continue
-		}
-		f, err := os.Open(filepath.Join(dir, name))
-		if err != nil {
-			return nil, err
-		}
-		var imp []string
-		data, err := readImports(f, false, &imp)
-		f.Close()
-		if err != nil {
-			return nil, fmt.Errorf("reading %v: %v", name, err)
-		}
-		if bytes.Contains(data, buildIgnore) {
-			continue
-		}
-		for _, quoted := range imp {
-			path, err := strconv.Unquote(quoted)
-			if err != nil {
-				continue
-			}
-			if !haveImport[path] {
-				haveImport[path] = true
-				imports = append(imports, path)
+
+	for _, ctxt.GOOS = range geese {
+		for _, ctxt.GOARCH = range goarches {
+			for _, ctxt.CgoEnabled = range bools {
+				test(false)
 			}
 		}
 	}
-	sort.Strings(imports)
-	return imports, nil
 }
diff --git a/src/go/build/doc.go b/src/go/build/doc.go
index 233f8b9..75a827b 100644
--- a/src/go/build/doc.go
+++ b/src/go/build/doc.go
@@ -101,7 +101,6 @@
 //	- "go1.2", from Go version 1.2 onward
 //	- "go1.3", from Go version 1.3 onward
 //	- "go1.4", from Go version 1.4 onward
-//	- "go1.5", from Go version 1.5 onward
 //	- any additional words listed in ctxt.BuildTags
 //
 // If a file's name, after stripping the extension and a possible _test suffix,
@@ -112,7 +111,7 @@
 // (example: source_windows_amd64.go) where GOOS and GOARCH represent
 // any known operating system and architecture values respectively, then
 // the file is considered to have an implicit build constraint requiring
-// those terms (in addition to any explicit constraints in the file).
+// those terms.
 //
 // To keep a file from being considered for the build:
 //
diff --git a/src/go/build/read.go b/src/go/build/read.go
index 1049ac5..c8079df 100644
--- a/src/go/build/read.go
+++ b/src/go/build/read.go
@@ -146,15 +146,11 @@ func (r *importReader) readIdent() {
 
 // readString reads a quoted string literal from the input.
 // If an identifier is not present, readString records a syntax error.
-func (r *importReader) readString(save *[]string) {
+func (r *importReader) readString() {
 	switch r.nextByte(true) {
 	case '`':
-		start := len(r.buf) - 1
 		for r.err == nil {
 			if r.nextByte(false) == '`' {
-				if save != nil {
-					*save = append(*save, string(r.buf[start:]))
-				}
 				break
 			}
 			if r.eof {
@@ -162,13 +158,9 @@ func (r *importReader) readString(save *[]string) {
 			}
 		}
 	case '"':
-		start := len(r.buf) - 1
 		for r.err == nil {
 			c := r.nextByte(false)
 			if c == '"' {
-				if save != nil {
-					*save = append(*save, string(r.buf[start:]))
-				}
 				break
 			}
 			if r.eof || c == '\n' {
@@ -185,14 +177,14 @@ func (r *importReader) readString(save *[]string) {
 
 // readImport reads an import clause - optional identifier followed by quoted string -
 // from the input.
-func (r *importReader) readImport(imports *[]string) {
+func (r *importReader) readImport() {
 	c := r.peekByte(true)
 	if c == '.' {
 		r.peek = 0
 	} else if isIdent(c) {
 		r.readIdent()
 	}
-	r.readString(imports)
+	r.readString()
 }
 
 // readComments is like ioutil.ReadAll, except that it only reads the leading
@@ -209,7 +201,7 @@ func readComments(f io.Reader) ([]byte, error) {
 
 // readImports is like ioutil.ReadAll, except that it expects a Go file as input
 // and stops reading the input once the imports have completed.
-func readImports(f io.Reader, reportSyntaxError bool, imports *[]string) ([]byte, error) {
+func readImports(f io.Reader, reportSyntaxError bool) ([]byte, error) {
 	r := &importReader{b: bufio.NewReader(f)}
 
 	r.readKeyword("package")
@@ -219,11 +211,11 @@ func readImports(f io.Reader, reportSyntaxError bool, imports *[]string) ([]byte
 		if r.peekByte(true) == '(' {
 			r.nextByte(false)
 			for r.peekByte(true) != ')' && r.err == nil {
-				r.readImport(imports)
+				r.readImport()
 			}
 			r.nextByte(false)
 		} else {
-			r.readImport(imports)
+			r.readImport()
 		}
 	}
 
diff --git a/src/go/build/read_test.go b/src/go/build/read_test.go
index 326960b..2dcc120 100644
--- a/src/go/build/read_test.go
+++ b/src/go/build/read_test.go
@@ -131,7 +131,7 @@ func testRead(t *testing.T, tests []readTest, read func(io.Reader) ([]byte, erro
 }
 
 func TestReadImports(t *testing.T) {
-	testRead(t, readImportsTests, func(r io.Reader) ([]byte, error) { return readImports(r, true, nil) })
+	testRead(t, readImportsTests, func(r io.Reader) ([]byte, error) { return readImports(r, true) })
 }
 
 func TestReadComments(t *testing.T) {
@@ -207,7 +207,7 @@ var readFailuresTests = []readTest{
 
 func TestReadFailures(t *testing.T) {
 	// Errors should be reported (true arg to readImports).
-	testRead(t, readFailuresTests, func(r io.Reader) ([]byte, error) { return readImports(r, true, nil) })
+	testRead(t, readFailuresTests, func(r io.Reader) ([]byte, error) { return readImports(r, true) })
 }
 
 func TestReadFailuresIgnored(t *testing.T) {
@@ -222,5 +222,5 @@ func TestReadFailuresIgnored(t *testing.T) {
 			tt.err = ""
 		}
 	}
-	testRead(t, tests, func(r io.Reader) ([]byte, error) { return readImports(r, false, nil) })
+	testRead(t, tests, func(r io.Reader) ([]byte, error) { return readImports(r, false) })
 }
diff --git a/src/go/build/syslist.go b/src/go/build/syslist.go
index 7adb0ca..965f873 100644
--- a/src/go/build/syslist.go
+++ b/src/go/build/syslist.go
@@ -5,4 +5,4 @@
 package build
 
 const goosList = "android darwin dragonfly freebsd linux nacl netbsd openbsd plan9 solaris windows "
-const goarchList = "386 amd64 amd64p32 arm armbe arm64 arm64be ppc64 ppc64le mips mipsle mips64 mips64le mips64p32 mips64p32le ppc s390 s390x sparc sparc64 "
+const goarchList = "386 amd64 amd64p32 arm "
diff --git a/src/go/doc/doc.go b/src/go/doc/doc.go
index 3c3e28d..4264940 100644
--- a/src/go/doc/doc.go
+++ b/src/go/doc/doc.go
@@ -18,8 +18,7 @@ type Package struct {
 	Imports    []string
 	Filenames  []string
 	Notes      map[string][]*Note
-
-	// Deprecated: For backward compatibility Bugs is still populated,
+	// DEPRECATED. For backward compatibility Bugs is still populated,
 	// but all new code should use Notes instead.
 	Bugs []string
 
diff --git a/src/go/doc/exports.go b/src/go/doc/exports.go
index 4a12b1e..1d3b466 100644
--- a/src/go/doc/exports.go
+++ b/src/go/doc/exports.go
@@ -12,12 +12,13 @@ import (
 )
 
 // filterIdentList removes unexported names from list in place
-// and returns the resulting list.
+// and returns the resulting list. If blankOk is set, blank
+// identifiers are considered exported names.
 //
-func filterIdentList(list []*ast.Ident) []*ast.Ident {
+func filterIdentList(list []*ast.Ident, blankOk bool) []*ast.Ident {
 	j := 0
 	for _, x := range list {
-		if ast.IsExported(x.Name) {
+		if ast.IsExported(x.Name) || (blankOk && x.Name == "_") {
 			list[j] = x
 			j++
 		}
@@ -25,17 +26,6 @@ func filterIdentList(list []*ast.Ident) []*ast.Ident {
 	return list[0:j]
 }
 
-// hasExportedName reports whether list contains any exported names.
-//
-func hasExportedName(list []*ast.Ident) bool {
-	for _, x := range list {
-		if x.IsExported() {
-			return true
-		}
-	}
-	return false
-}
-
 // removeErrorField removes anonymous fields named "error" from an interface.
 // This is called when "error" has been determined to be a local name,
 // not the predeclared type.
@@ -63,7 +53,7 @@ func removeErrorField(ityp *ast.InterfaceType) {
 }
 
 // filterFieldList removes unexported fields (field names) from the field list
-// in place and reports whether fields were removed. Anonymous fields are
+// in place and returns true if fields were removed. Anonymous fields are
 // recorded with the parent type. filterType is called with the types of
 // all remaining fields.
 //
@@ -88,7 +78,7 @@ func (r *reader) filterFieldList(parent *namedType, fields *ast.FieldList, ityp
 				r.remember(ityp)
 			}
 		} else {
-			field.Names = filterIdentList(field.Names)
+			field.Names = filterIdentList(field.Names, false)
 			if len(field.Names) < n {
 				removedFields = true
 			}
@@ -156,7 +146,9 @@ func (r *reader) filterSpec(spec ast.Spec, tok token.Token) bool {
 		// always keep imports so we can collect them
 		return true
 	case *ast.ValueSpec:
-		s.Names = filterIdentList(s.Names)
+		// special case: consider blank constants as exported
+		// (work-around for issue 5397)
+		s.Names = filterIdentList(s.Names, tok == token.CONST)
 		if len(s.Names) > 0 {
 			r.filterType(nil, s.Type)
 			return true
@@ -173,46 +165,7 @@ func (r *reader) filterSpec(spec ast.Spec, tok token.Token) bool {
 	return false
 }
 
-// copyConstType returns a copy of typ with position pos.
-// typ must be a valid constant type.
-// In practice, only (possibly qualified) identifiers are possible.
-//
-func copyConstType(typ ast.Expr, pos token.Pos) ast.Expr {
-	switch typ := typ.(type) {
-	case *ast.Ident:
-		return &ast.Ident{Name: typ.Name, NamePos: pos}
-	case *ast.SelectorExpr:
-		if id, ok := typ.X.(*ast.Ident); ok {
-			// presumably a qualified identifier
-			return &ast.SelectorExpr{
-				Sel: ast.NewIdent(typ.Sel.Name),
-				X:   &ast.Ident{Name: id.Name, NamePos: pos},
-			}
-		}
-	}
-	return nil // shouldn't happen, but be conservative and don't panic
-}
-
 func (r *reader) filterSpecList(list []ast.Spec, tok token.Token) []ast.Spec {
-	if tok == token.CONST {
-		// Propagate any type information that would get lost otherwise
-		// when unexported constants are filtered.
-		var prevType ast.Expr
-		for _, spec := range list {
-			spec := spec.(*ast.ValueSpec)
-			if spec.Type == nil && prevType != nil {
-				// provide current spec with an explicit type
-				spec.Type = copyConstType(prevType, spec.Pos())
-			}
-			if hasExportedName(spec.Names) {
-				// exported names are preserved so there's no need to propagate the type
-				prevType = nil
-			} else {
-				prevType = spec.Type
-			}
-		}
-	}
-
 	j := 0
 	for _, s := range list {
 		if r.filterSpec(s, tok) {
diff --git a/src/go/doc/testdata/blank.0.golden b/src/go/doc/testdata/blank.0.golden
index c2987cf..dae3ab2 100644
--- a/src/go/doc/testdata/blank.0.golden
+++ b/src/go/doc/testdata/blank.0.golden
@@ -4,33 +4,14 @@ PACKAGE blank
 IMPORTPATH
 	testdata/blank
 
-IMPORTS
-	os
-
 FILENAMES
 	testdata/blank.go
 
 CONSTANTS
-	// T constants counting from unexported constants. 
-	const (
-		C1	T
-		C2
-	
-		C3
-	
-		C4	int
-	)
-
-	// Constants with an imported type that needs to be propagated. 
-	const (
-		Default		os.FileMode	= 0644
-		Useless				= 0312
-		WideOpen			= 0777
-	)
-
 	// Package constants. 
 	const (
-		I1	int
+		_	int	= iota
+		I1
 		I2
 	)
 
@@ -47,9 +28,10 @@ TYPES
 	// 
 	type T int
 
-	// T constants counting from a blank constant. 
+	// T constants. 
 	const (
-		T1	T
+		_	T	= iota
+		T1
 		T2
 	)
 
diff --git a/src/go/doc/testdata/blank.1.golden b/src/go/doc/testdata/blank.1.golden
index ee5054a..333d7e5 100644
--- a/src/go/doc/testdata/blank.1.golden
+++ b/src/go/doc/testdata/blank.1.golden
@@ -4,25 +4,10 @@ PACKAGE blank
 IMPORTPATH
 	testdata/blank
 
-IMPORTS
-	os
-
 FILENAMES
 	testdata/blank.go
 
 CONSTANTS
-	// T constants counting from unexported constants. 
-	const (
-		tweedledee	T	= iota
-		tweedledum
-		C1
-		C2
-		alice
-		C3
-		redQueen	int	= iota
-		C4
-	)
-
 	// Package constants. 
 	const (
 		_	int	= iota
@@ -30,20 +15,6 @@ CONSTANTS
 		I2
 	)
 
-	// Constants with an imported type that needs to be propagated. 
-	const (
-		zero		os.FileMode	= 0
-		Default				= 0644
-		Useless				= 0312
-		WideOpen			= 0777
-	)
-
-	// Unexported constants counting from blank iota. See issue 9615. 
-	const (
-		_	= iota
-		one	= iota + 1
-	)
-
 
 VARIABLES
 	// 
@@ -66,7 +37,7 @@ TYPES
 	// 
 	type T int
 
-	// T constants counting from a blank constant. 
+	// T constants. 
 	const (
 		_	T	= iota
 		T1
diff --git a/src/go/doc/testdata/blank.2.golden b/src/go/doc/testdata/blank.2.golden
index c2987cf..dae3ab2 100644
--- a/src/go/doc/testdata/blank.2.golden
+++ b/src/go/doc/testdata/blank.2.golden
@@ -4,33 +4,14 @@ PACKAGE blank
 IMPORTPATH
 	testdata/blank
 
-IMPORTS
-	os
-
 FILENAMES
 	testdata/blank.go
 
 CONSTANTS
-	// T constants counting from unexported constants. 
-	const (
-		C1	T
-		C2
-	
-		C3
-	
-		C4	int
-	)
-
-	// Constants with an imported type that needs to be propagated. 
-	const (
-		Default		os.FileMode	= 0644
-		Useless				= 0312
-		WideOpen			= 0777
-	)
-
 	// Package constants. 
 	const (
-		I1	int
+		_	int	= iota
+		I1
 		I2
 	)
 
@@ -47,9 +28,10 @@ TYPES
 	// 
 	type T int
 
-	// T constants counting from a blank constant. 
+	// T constants. 
 	const (
-		T1	T
+		_	T	= iota
+		T1
 		T2
 	)
 
diff --git a/src/go/doc/testdata/blank.go b/src/go/doc/testdata/blank.go
index 419a78f..f812c77 100644
--- a/src/go/doc/testdata/blank.go
+++ b/src/go/doc/testdata/blank.go
@@ -6,37 +6,15 @@
 // See issue 5397.
 package blank
 
-import "os"
-
 type T int
 
-// T constants counting from a blank constant.
+// T constants.
 const (
 	_ T = iota
 	T1
 	T2
 )
 
-// T constants counting from unexported constants.
-const (
-	tweedledee T = iota
-	tweedledum
-	C1
-	C2
-	alice
-	C3
-	redQueen int = iota
-	C4
-)
-
-// Constants with an imported type that needs to be propagated.
-const (
-	zero     os.FileMode = 0
-	Default              = 0644
-	Useless              = 0312
-	WideOpen             = 0777
-)
-
 // Package constants.
 const (
 	_ int = iota
@@ -44,13 +22,6 @@ const (
 	I2
 )
 
-// Unexported constants counting from blank iota.
-// See issue 9615.
-const (
-	_   = iota
-	one = iota + 1
-)
-
 // Blanks not in doc output:
 
 // S has a padding field.
diff --git a/src/go/format/format.go b/src/go/format/format.go
index 1adfd7d..668a42d 100644
--- a/src/go/format/format.go
+++ b/src/go/format/format.go
@@ -12,8 +12,8 @@ import (
 	"go/parser"
 	"go/printer"
 	"go/token"
-	"internal/format"
 	"io"
+	"strings"
 )
 
 var config = printer.Config{Mode: printer.UseSpaces | printer.TabIndent, Tabwidth: 8}
@@ -82,7 +82,7 @@ func Node(dst io.Writer, fset *token.FileSet, node interface{}) error {
 //
 func Source(src []byte) ([]byte, error) {
 	fset := token.NewFileSet()
-	file, sourceAdj, indentAdj, err := format.Parse(fset, "", src, true)
+	file, sourceAdj, indentAdj, err := parse(fset, "", src, true)
 	if err != nil {
 		return nil, err
 	}
@@ -93,7 +93,7 @@ func Source(src []byte) ([]byte, error) {
 		ast.SortImports(fset, file)
 	}
 
-	return format.Format(fset, file, sourceAdj, indentAdj, src, config)
+	return format(fset, file, sourceAdj, indentAdj, src, config)
 }
 
 func hasUnsortedImports(file *ast.File) bool {
@@ -113,3 +113,154 @@ func hasUnsortedImports(file *ast.File) bool {
 	}
 	return false
 }
+
+// ----------------------------------------------------------------------------
+// Support functions
+//
+// The functions parse, format, and isSpace below are identical to the
+// respective functions in cmd/gofmt/gofmt.go - keep them in sync!
+//
+// TODO(gri) Factor out this functionality, eventually.
+
+// parse parses src, which was read from the named file,
+// as a Go source file, declaration, or statement list.
+func parse(fset *token.FileSet, filename string, src []byte, fragmentOk bool) (
+	file *ast.File,
+	sourceAdj func(src []byte, indent int) []byte,
+	indentAdj int,
+	err error,
+) {
+	// Try as whole source file.
+	file, err = parser.ParseFile(fset, filename, src, parserMode)
+	// If there's no error, return.  If the error is that the source file didn't begin with a
+	// package line and source fragments are ok, fall through to
+	// try as a source fragment.  Stop and return on any other error.
+	if err == nil || !fragmentOk || !strings.Contains(err.Error(), "expected 'package'") {
+		return
+	}
+
+	// If this is a declaration list, make it a source file
+	// by inserting a package clause.
+	// Insert using a ;, not a newline, so that the line numbers
+	// in psrc match the ones in src.
+	psrc := append([]byte("package p;"), src...)
+	file, err = parser.ParseFile(fset, filename, psrc, parserMode)
+	if err == nil {
+		sourceAdj = func(src []byte, indent int) []byte {
+			// Remove the package clause.
+			// Gofmt has turned the ; into a \n.
+			src = src[indent+len("package p\n"):]
+			return bytes.TrimSpace(src)
+		}
+		return
+	}
+	// If the error is that the source file didn't begin with a
+	// declaration, fall through to try as a statement list.
+	// Stop and return on any other error.
+	if !strings.Contains(err.Error(), "expected declaration") {
+		return
+	}
+
+	// If this is a statement list, make it a source file
+	// by inserting a package clause and turning the list
+	// into a function body.  This handles expressions too.
+	// Insert using a ;, not a newline, so that the line numbers
+	// in fsrc match the ones in src.
+	fsrc := append(append([]byte("package p; func _() {"), src...), '\n', '}')
+	file, err = parser.ParseFile(fset, filename, fsrc, parserMode)
+	if err == nil {
+		sourceAdj = func(src []byte, indent int) []byte {
+			// Cap adjusted indent to zero.
+			if indent < 0 {
+				indent = 0
+			}
+			// Remove the wrapping.
+			// Gofmt has turned the ; into a \n\n.
+			// There will be two non-blank lines with indent, hence 2*indent.
+			src = src[2*indent+len("package p\n\nfunc _() {"):]
+			src = src[:len(src)-(indent+len("\n}\n"))]
+			return bytes.TrimSpace(src)
+		}
+		// Gofmt has also indented the function body one level.
+		// Adjust that with indentAdj.
+		indentAdj = -1
+	}
+
+	// Succeeded, or out of options.
+	return
+}
+
+// format formats the given package file originally obtained from src
+// and adjusts the result based on the original source via sourceAdj
+// and indentAdj.
+func format(
+	fset *token.FileSet,
+	file *ast.File,
+	sourceAdj func(src []byte, indent int) []byte,
+	indentAdj int,
+	src []byte,
+	cfg printer.Config,
+) ([]byte, error) {
+	if sourceAdj == nil {
+		// Complete source file.
+		var buf bytes.Buffer
+		err := cfg.Fprint(&buf, fset, file)
+		if err != nil {
+			return nil, err
+		}
+		return buf.Bytes(), nil
+	}
+
+	// Partial source file.
+	// Determine and prepend leading space.
+	i, j := 0, 0
+	for j < len(src) && isSpace(src[j]) {
+		if src[j] == '\n' {
+			i = j + 1 // byte offset of last line in leading space
+		}
+		j++
+	}
+	var res []byte
+	res = append(res, src[:i]...)
+
+	// Determine and prepend indentation of first code line.
+	// Spaces are ignored unless there are no tabs,
+	// in which case spaces count as one tab.
+	indent := 0
+	hasSpace := false
+	for _, b := range src[i:j] {
+		switch b {
+		case ' ':
+			hasSpace = true
+		case '\t':
+			indent++
+		}
+	}
+	if indent == 0 && hasSpace {
+		indent = 1
+	}
+	for i := 0; i < indent; i++ {
+		res = append(res, '\t')
+	}
+
+	// Format the source.
+	// Write it without any leading and trailing space.
+	cfg.Indent = indent + indentAdj
+	var buf bytes.Buffer
+	err := cfg.Fprint(&buf, fset, file)
+	if err != nil {
+		return nil, err
+	}
+	res = append(res, sourceAdj(buf.Bytes(), cfg.Indent)...)
+
+	// Determine and append trailing space.
+	i = len(src)
+	for i > 0 && isSpace(src[i-1]) {
+		i--
+	}
+	return append(res, src[i:]...), nil
+}
+
+func isSpace(b byte) bool {
+	return b == ' ' || b == '\t' || b == '\n' || b == '\r'
+}
diff --git a/src/go/format/format_test.go b/src/go/format/format_test.go
index 000c611..d7846be 100644
--- a/src/go/format/format_test.go
+++ b/src/go/format/format_test.go
@@ -91,11 +91,7 @@ var tests = []string{
 	"\n\t\t\n\n\t\t\tx := 0\n\t\t\tconst s = `\n\t\tfoo\n`\n\n\n", // no indentation removed inside raw strings
 
 	// comments
-	"i := 5 /* Comment */",         // Issue 5551.
-	"\ta()\n//line :1",             // Issue 11276.
-	"\t//xxx\n\ta()\n//line :2",    // Issue 11276.
-	"\ta() //line :1\n\tb()\n",     // Issue 11276.
-	"x := 0\n//line :1\n//line :2", // Issue 11276.
+	"i := 5 /* Comment */", // Issue 5551.
 
 	// erroneous programs
 	"ERROR1 + 2 +",
diff --git a/src/go/parser/error_test.go b/src/go/parser/error_test.go
index 1a08d5a..48fb53e 100644
--- a/src/go/parser/error_test.go
+++ b/src/go/parser/error_test.go
@@ -34,9 +34,11 @@ import (
 
 const testdata = "testdata"
 
+var fsetErrs = token.NewFileSet()
+
 // getFile assumes that each filename occurs at most once
-func getFile(fset *token.FileSet, filename string) (file *token.File) {
-	fset.Iterate(func(f *token.File) bool {
+func getFile(filename string) (file *token.File) {
+	fsetErrs.Iterate(func(f *token.File) bool {
 		if f.Name() == filename {
 			if file != nil {
 				panic(filename + " used multiple times")
@@ -48,8 +50,8 @@ func getFile(fset *token.FileSet, filename string) (file *token.File) {
 	return file
 }
 
-func getPos(fset *token.FileSet, filename string, offset int) token.Pos {
-	if f := getFile(fset, filename); f != nil {
+func getPos(filename string, offset int) token.Pos {
+	if f := getFile(filename); f != nil {
 		return f.Pos(offset)
 	}
 	return token.NoPos
@@ -66,14 +68,14 @@ 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.
 //
-func expectedErrors(t *testing.T, fset *token.FileSet, filename string, src []byte) map[token.Pos]string {
+func expectedErrors(t *testing.T, filename string, src []byte) map[token.Pos]string {
 	errors := make(map[token.Pos]string)
 
 	var s scanner.Scanner
 	// file was parsed already - do not add it again to the file
 	// set otherwise the position information returned here will
 	// not match the position information collected by the parser
-	s.Init(getFile(fset, filename), src, nil, scanner.ScanComments)
+	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
 
@@ -107,11 +109,11 @@ func expectedErrors(t *testing.T, fset *token.FileSet, filename string, src []by
 // compareErrors compares the map of expected error messages with the list
 // of found errors and reports discrepancies.
 //
-func compareErrors(t *testing.T, fset *token.FileSet, expected map[token.Pos]string, found scanner.ErrorList) {
+func compareErrors(t *testing.T, expected map[token.Pos]string, found scanner.ErrorList) {
 	for _, error := range found {
 		// error.Pos is a token.Position, but we want
 		// a token.Pos so we can do a map lookup
-		pos := getPos(fset, error.Pos.Filename, error.Pos.Offset)
+		pos := getPos(error.Pos.Filename, error.Pos.Offset)
 		if msg, found := expected[pos]; found {
 			// we expect a message at pos; check if it matches
 			rx, err := regexp.Compile(msg)
@@ -138,7 +140,7 @@ func compareErrors(t *testing.T, fset *token.FileSet, expected map[token.Pos]str
 	if len(expected) > 0 {
 		t.Errorf("%d errors not reported:", len(expected))
 		for pos, msg := range expected {
-			t.Errorf("%s: %s\n", fset.Position(pos), msg)
+			t.Errorf("%s: %s\n", fsetErrs.Position(pos), msg)
 		}
 	}
 }
@@ -150,8 +152,7 @@ func checkErrors(t *testing.T, filename string, input interface{}) {
 		return
 	}
 
-	fset := token.NewFileSet()
-	_, err = ParseFile(fset, filename, src, DeclarationErrors|AllErrors)
+	_, err = ParseFile(fsetErrs, filename, src, DeclarationErrors|AllErrors)
 	found, ok := err.(scanner.ErrorList)
 	if err != nil && !ok {
 		t.Error(err)
@@ -161,10 +162,10 @@ func checkErrors(t *testing.T, filename string, input interface{}) {
 
 	// we are expecting the following errors
 	// (collect these after parsing a file so that it is found in the file set)
-	expected := expectedErrors(t, fset, filename, src)
+	expected := expectedErrors(t, filename, src)
 
 	// verify errors returned by the parser
-	compareErrors(t, fset, expected, found)
+	compareErrors(t, expected, found)
 }
 
 func TestErrors(t *testing.T) {
diff --git a/src/go/parser/interface.go b/src/go/parser/interface.go
index c6fd932..4910305 100644
--- a/src/go/parser/interface.go
+++ b/src/go/parser/interface.go
@@ -91,10 +91,7 @@ func ParseFile(fset *token.FileSet, filename string, src interface{}, mode Mode)
 	var p parser
 	defer func() {
 		if e := recover(); e != nil {
-			// resume same panic if it's not a bailout
-			if _, ok := e.(bailout); !ok {
-				panic(e)
-			}
+			_ = e.(bailout) // re-panics if it's not a bailout
 		}
 
 		// set result values
@@ -167,31 +164,14 @@ func ParseDir(fset *token.FileSet, path string, filter func(os.FileInfo) bool, m
 	return
 }
 
-// ParseExprFrom is a convenience function for parsing an expression.
-// The arguments have the same meaning as for Parse, but the source must
-// be a valid Go (type or value) expression.
+// ParseExpr is a convenience function for obtaining the AST of an expression x.
+// The position information recorded in the AST is undefined. The filename used
+// in error messages is the empty string.
 //
-func ParseExprFrom(fset *token.FileSet, filename string, src interface{}, mode Mode) (ast.Expr, error) {
-	// get source
-	text, err := readSource(filename, src)
-	if err != nil {
-		return nil, err
-	}
-
+func ParseExpr(x string) (ast.Expr, error) {
 	var p parser
-	defer func() {
-		if e := recover(); e != nil {
-			// resume same panic if it's not a bailout
-			if _, ok := e.(bailout); !ok {
-				panic(e)
-			}
-		}
-		p.errors.Sort()
-		err = p.errors.Err()
-	}()
+	p.init(token.NewFileSet(), "", []byte(x), 0)
 
-	// parse expr
-	p.init(fset, filename, text, mode)
 	// Set up pkg-level scopes to avoid nil-pointer errors.
 	// This is not needed for a correct expression x as the
 	// parser will be ok with a nil topScope, but be cautious
@@ -216,11 +196,3 @@ func ParseExprFrom(fset *token.FileSet, filename string, src interface{}, mode M
 
 	return e, nil
 }
-
-// ParseExpr is a convenience function for obtaining the AST of an expression x.
-// The position information recorded in the AST is undefined. The filename used
-// in error messages is the empty string.
-//
-func ParseExpr(x string) (ast.Expr, error) {
-	return ParseExprFrom(token.NewFileSet(), "", []byte(x), 0)
-}
diff --git a/src/go/parser/parser.go b/src/go/parser/parser.go
index e82c0bd..4a005d8 100644
--- a/src/go/parser/parser.go
+++ b/src/go/parser/parser.go
@@ -7,13 +7,6 @@
 // output is an abstract syntax tree (AST) representing the Go source. The
 // parser is invoked through one of the Parse* functions.
 //
-// The parser accepts a larger language than is syntactically permitted by
-// the Go spec, for simplicity, and for improved robustness in the presence
-// of syntax errors. For instance, in method declarations, the receiver is
-// treated like an ordinary parameter list and thus may contain multiple
-// entries where the spec permits exactly one. Consequently, the corresponding
-// field in the AST (ast.FuncDecl.Recv) field is not restricted to one entry.
-//
 package parser
 
 import (
@@ -419,17 +412,14 @@ func (p *parser) expectSemi() {
 	}
 }
 
-func (p *parser) atComma(context string, follow token.Token) bool {
+func (p *parser) atComma(context string) bool {
 	if p.tok == token.COMMA {
 		return true
 	}
-	if p.tok != follow {
-		msg := "missing ','"
-		if p.tok == token.SEMICOLON && p.lit == "\n" {
-			msg += " before newline"
-		}
-		p.error(p.pos, msg+" in "+context)
-		return true // "insert" comma and continue
+	if p.tok == token.SEMICOLON && p.lit == "\n" {
+		p.error(p.pos, "missing ',' before newline in "+context)
+		return true // "insert" the comma and continue
+
 	}
 	return false
 }
@@ -835,7 +825,7 @@ func (p *parser) parseParameterList(scope *ast.Scope, ellipsisOk bool) (params [
 		// parameter or result variable is the function body.
 		p.declare(field, nil, scope, ast.Var, idents...)
 		p.resolve(typ)
-		if !p.atComma("parameter list", token.RPAREN) {
+		if !p.atComma("parameter list") {
 			return
 		}
 		p.next()
@@ -848,7 +838,7 @@ func (p *parser) parseParameterList(scope *ast.Scope, ellipsisOk bool) (params [
 			// parameter or result variable is the function body.
 			p.declare(field, nil, scope, ast.Var, idents...)
 			p.resolve(typ)
-			if !p.atComma("parameter list", token.RPAREN) {
+			if !p.atComma("parameter list") {
 				break
 			}
 			p.next()
@@ -1258,7 +1248,7 @@ func (p *parser) parseCallOrConversion(fun ast.Expr) *ast.CallExpr {
 			ellipsis = p.pos
 			p.next()
 		}
-		if !p.atComma("argument list", token.RPAREN) {
+		if !p.atComma("argument list") {
 			break
 		}
 		p.next()
@@ -1269,7 +1259,7 @@ func (p *parser) parseCallOrConversion(fun ast.Expr) *ast.CallExpr {
 	return &ast.CallExpr{Fun: fun, Lparen: lparen, Args: list, Ellipsis: ellipsis, Rparen: rparen}
 }
 
-func (p *parser) parseValue(keyOk bool) ast.Expr {
+func (p *parser) parseElement(keyOk bool) ast.Expr {
 	if p.trace {
 		defer un(trace(p, "Element"))
 	}
@@ -1297,30 +1287,16 @@ func (p *parser) parseValue(keyOk bool) ast.Expr {
 	x := p.checkExpr(p.parseExpr(keyOk))
 	if keyOk {
 		if p.tok == token.COLON {
+			colon := p.pos
+			p.next()
 			// Try to resolve the key but don't collect it
 			// as unresolved identifier if it fails so that
 			// we don't get (possibly false) errors about
 			// undeclared names.
 			p.tryResolve(x, false)
-		} else {
-			// not a key
-			p.resolve(x)
+			return &ast.KeyValueExpr{Key: x, Colon: colon, Value: p.parseElement(false)}
 		}
-	}
-
-	return x
-}
-
-func (p *parser) parseElement() ast.Expr {
-	if p.trace {
-		defer un(trace(p, "Element"))
-	}
-
-	x := p.parseValue(true)
-	if p.tok == token.COLON {
-		colon := p.pos
-		p.next()
-		x = &ast.KeyValueExpr{Key: x, Colon: colon, Value: p.parseValue(false)}
+		p.resolve(x) // not a key
 	}
 
 	return x
@@ -1332,8 +1308,8 @@ func (p *parser) parseElementList() (list []ast.Expr) {
 	}
 
 	for p.tok != token.RBRACE && p.tok != token.EOF {
-		list = append(list, p.parseElement())
-		if !p.atComma("composite literal", token.RBRACE) {
+		list = append(list, p.parseElement(true))
+		if !p.atComma("composite literal") {
 			break
 		}
 		p.next()
@@ -1389,7 +1365,7 @@ func (p *parser) checkExpr(x ast.Expr) ast.Expr {
 	return x
 }
 
-// isTypeName reports whether x is a (qualified) TypeName.
+// isTypeName returns true iff x is a (qualified) TypeName.
 func isTypeName(x ast.Expr) bool {
 	switch t := x.(type) {
 	case *ast.BadExpr:
@@ -1403,7 +1379,7 @@ func isTypeName(x ast.Expr) bool {
 	return true
 }
 
-// isLiteralType reports whether x is a legal composite literal type.
+// isLiteralType returns true iff x is a legal composite literal type.
 func isLiteralType(x ast.Expr) bool {
 	switch t := x.(type) {
 	case *ast.BadExpr:
@@ -1479,8 +1455,7 @@ L:
 				pos := p.pos
 				p.errorExpected(pos, "selector or type assertion")
 				p.next() // make progress
-				sel := &ast.Ident{NamePos: pos, Name: "_"}
-				x = &ast.SelectorExpr{X: x, Sel: sel}
+				x = &ast.BadExpr{From: pos, To: p.pos}
 			}
 		case token.LBRACK:
 			if lhs {
@@ -2148,7 +2123,7 @@ func (p *parser) parseStmt() (s ast.Stmt) {
 	case
 		// tokens that may start an expression
 		token.IDENT, token.INT, token.FLOAT, token.IMAG, token.CHAR, token.STRING, token.FUNC, token.LPAREN, // operands
-		token.LBRACK, token.STRUCT, token.MAP, token.CHAN, token.INTERFACE, // composite types
+		token.LBRACK, token.STRUCT, // composite types
 		token.ADD, token.SUB, token.MUL, token.AND, token.XOR, token.ARROW, token.NOT: // unary operators
 		s, _ = p.parseSimpleStmt(labelOk)
 		// because of the required look-ahead, labeled statements are
@@ -2177,14 +2152,11 @@ func (p *parser) parseStmt() (s ast.Stmt) {
 	case token.FOR:
 		s = p.parseForStmt()
 	case token.SEMICOLON:
-		// Is it ever possible to have an implicit semicolon
-		// producing an empty statement in a valid program?
-		// (handle correctly anyway)
-		s = &ast.EmptyStmt{Semicolon: p.pos, Implicit: p.lit == "\n"}
+		s = &ast.EmptyStmt{Semicolon: p.pos}
 		p.next()
 	case token.RBRACE:
 		// a semicolon may be omitted before a closing "}"
-		s = &ast.EmptyStmt{Semicolon: p.pos, Implicit: true}
+		s = &ast.EmptyStmt{Semicolon: p.pos}
 	default:
 		// no statement found
 		pos := p.pos
@@ -2256,7 +2228,6 @@ func (p *parser) parseValueSpec(doc *ast.CommentGroup, keyword token.Token, iota
 		defer un(trace(p, keyword.String()+"Spec"))
 	}
 
-	pos := p.pos
 	idents := p.parseIdentList()
 	typ := p.tryType()
 	var values []ast.Expr
@@ -2267,17 +2238,6 @@ func (p *parser) parseValueSpec(doc *ast.CommentGroup, keyword token.Token, iota
 	}
 	p.expectSemi() // call before accessing p.linecomment
 
-	switch keyword {
-	case token.VAR:
-		if typ == nil && values == nil {
-			p.error(pos, "missing variable type or initialization")
-		}
-	case token.CONST:
-		if values == nil && (iota == 0 || typ != nil) {
-			p.error(pos, "missing constant value")
-		}
-	}
-
 	// Go spec: The scope of a constant or variable identifier declared inside
 	// a function begins at the end of the ConstSpec or VarSpec and ends at
 	// the end of the innermost containing block.
diff --git a/src/go/parser/parser_test.go b/src/go/parser/parser_test.go
index c7bb36d..85065fd 100644
--- a/src/go/parser/parser_test.go
+++ b/src/go/parser/parser_test.go
@@ -14,6 +14,8 @@ import (
 	"testing"
 )
 
+var fset = token.NewFileSet()
+
 var validFiles = []string{
 	"parser.go",
 	"parser_test.go",
@@ -23,7 +25,7 @@ var validFiles = []string{
 
 func TestParse(t *testing.T) {
 	for _, filename := range validFiles {
-		_, err := ParseFile(token.NewFileSet(), filename, nil, DeclarationErrors)
+		_, err := ParseFile(fset, filename, nil, DeclarationErrors)
 		if err != nil {
 			t.Fatalf("ParseFile(%s): %v", filename, err)
 		}
@@ -44,7 +46,7 @@ func dirFilter(f os.FileInfo) bool { return nameFilter(f.Name()) }
 
 func TestParseDir(t *testing.T) {
 	path := "."
-	pkgs, err := ParseDir(token.NewFileSet(), path, dirFilter, 0)
+	pkgs, err := ParseDir(fset, path, dirFilter, 0)
 	if err != nil {
 		t.Fatalf("ParseDir(%s): %v", path, err)
 	}
@@ -129,7 +131,7 @@ func TestParseExpr(t *testing.T) {
 }
 
 func TestColonEqualsScope(t *testing.T) {
-	f, err := ParseFile(token.NewFileSet(), "", `package p; func f() { x, y, z := x, y, z }`, 0)
+	f, err := ParseFile(fset, "", `package p; func f() { x, y, z := x, y, z }`, 0)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -151,7 +153,7 @@ func TestColonEqualsScope(t *testing.T) {
 }
 
 func TestVarScope(t *testing.T) {
-	f, err := ParseFile(token.NewFileSet(), "", `package p; func f() { var x, y, z = x, y, z }`, 0)
+	f, err := ParseFile(fset, "", `package p; func f() { var x, y, z = x, y, z }`, 0)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -181,7 +183,7 @@ var x int
 func f() { L: }
 `
 
-	f, err := ParseFile(token.NewFileSet(), "", src, 0)
+	f, err := ParseFile(fset, "", src, 0)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -219,7 +221,7 @@ func f() { L: }
 }
 
 func TestUnresolved(t *testing.T) {
-	f, err := ParseFile(token.NewFileSet(), "", `
+	f, err := ParseFile(fset, "", `
 package p
 //
 func f1a(int)
@@ -314,7 +316,7 @@ var imports = map[string]bool{
 func TestImports(t *testing.T) {
 	for path, isValid := range imports {
 		src := fmt.Sprintf("package p; import %s", path)
-		_, err := ParseFile(token.NewFileSet(), "", src, 0)
+		_, err := ParseFile(fset, "", src, 0)
 		switch {
 		case err != nil && isValid:
 			t.Errorf("ParseFile(%s): got %v; expected no error", src, err)
@@ -325,7 +327,7 @@ func TestImports(t *testing.T) {
 }
 
 func TestCommentGroups(t *testing.T) {
-	f, err := ParseFile(token.NewFileSet(), "", `
+	f, err := ParseFile(fset, "", `
 package p /* 1a */ /* 1b */      /* 1c */ // 1d
 /* 2a
 */
@@ -419,7 +421,7 @@ func checkFieldComments(t *testing.T, file *ast.File, fieldname, lead, line stri
 }
 
 func TestLeadAndLineComments(t *testing.T) {
-	f, err := ParseFile(token.NewFileSet(), "", `
+	f, err := ParseFile(fset, "", `
 package p
 type T struct {
 	/* F1 lead comment */
@@ -445,89 +447,3 @@ type T struct {
 		t.Error("not expected to find T.f3")
 	}
 }
-
-// TestIssue9979 verifies that empty statements are contained within their enclosing blocks.
-func TestIssue9979(t *testing.T) {
-	for _, src := range []string{
-		"package p; func f() {;}",
-		"package p; func f() {L:}",
-		"package p; func f() {L:;}",
-		"package p; func f() {L:\n}",
-		"package p; func f() {L:\n;}",
-		"package p; func f() { ; }",
-		"package p; func f() { L: }",
-		"package p; func f() { L: ; }",
-		"package p; func f() { L: \n}",
-		"package p; func f() { L: \n; }",
-	} {
-		fset := token.NewFileSet()
-		f, err := ParseFile(fset, "", src, 0)
-		if err != nil {
-			t.Fatal(err)
-		}
-
-		var pos, end token.Pos
-		ast.Inspect(f, func(x ast.Node) bool {
-			switch s := x.(type) {
-			case *ast.BlockStmt:
-				pos, end = s.Pos()+1, s.End()-1 // exclude "{", "}"
-			case *ast.LabeledStmt:
-				pos, end = s.Pos()+2, s.End() // exclude "L:"
-			case *ast.EmptyStmt:
-				// check containment
-				if s.Pos() < pos || s.End() > end {
-					t.Errorf("%s: %T[%d, %d] not inside [%d, %d]", src, s, s.Pos(), s.End(), pos, end)
-				}
-				// check semicolon
-				offs := fset.Position(s.Pos()).Offset
-				if ch := src[offs]; ch != ';' != s.Implicit {
-					want := "want ';'"
-					if s.Implicit {
-						want = "but ';' is implicit"
-					}
-					t.Errorf("%s: found %q at offset %d; %s", src, ch, offs, want)
-				}
-			}
-			return true
-		})
-	}
-}
-
-// TestIncompleteSelection ensures that an incomplete selector
-// expression is parsed as a (blank) *ast.SelectorExpr, not a
-// *ast.BadExpr.
-func TestIncompleteSelection(t *testing.T) {
-	for _, src := range []string{
-		"package p; var _ = fmt.",             // at EOF
-		"package p; var _ = fmt.\ntype X int", // not at EOF
-	} {
-		fset := token.NewFileSet()
-		f, err := ParseFile(fset, "", src, 0)
-		if err == nil {
-			t.Errorf("ParseFile(%s) succeeded unexpectedly", src)
-			continue
-		}
-
-		const wantErr = "expected selector or type assertion"
-		if !strings.Contains(err.Error(), wantErr) {
-			t.Errorf("ParseFile returned wrong error %q, want %q", err, wantErr)
-		}
-
-		var sel *ast.SelectorExpr
-		ast.Inspect(f, func(n ast.Node) bool {
-			if n, ok := n.(*ast.SelectorExpr); ok {
-				sel = n
-			}
-			return true
-		})
-		if sel == nil {
-			t.Error("found no *ast.SelectorExpr")
-			continue
-		}
-		const wantSel = "&{fmt _}"
-		if fmt.Sprint(sel) != wantSel {
-			t.Errorf("found selector %s, want %s", sel, wantSel)
-			continue
-		}
-	}
-}
diff --git a/src/go/parser/short_test.go b/src/go/parser/short_test.go
index ef2ffad..05e44de 100644
--- a/src/go/parser/short_test.go
+++ b/src/go/parser/short_test.go
@@ -40,12 +40,6 @@ var valids = []string{
 	`package p; func (*(T),) m() {}`,
 	`package p; func _(x []int) { for range x {} }`,
 	`package p; func _() { if [T{}.n]int{} {} }`,
-	`package p; func _() { map[int]int{}[0]++; map[int]int{}[0] += 1 }`,
-	`package p; func _(x interface{f()}) { interface{f()}(x).f() }`,
-	`package p; func _(x chan int) { chan int(x) <- 0 }`,
-	`package p; const (x = 0; y; z)`, // issue 9639
-	`package p; var _ = map[P]int{P{}:0, {}:1}`,
-	`package p; var _ = map[*P]int{&P{}:0, {}:1}`,
 }
 
 func TestValid(t *testing.T) {
@@ -99,13 +93,8 @@ var invalids = []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 "missing ','" */ (){}) } } }`,
-	`package p; func f(x func(), u v func /* ERROR "missing ','" */ ()){}`,
-	`package p; func f() (a b string /* ERROR "missing ','" */ , ok bool)`,           // issue 8656
-	`package p; var x /* ERROR "missing variable type or initialization" */ , y, z;`, // issue 9639
-	`package p; const x /* ERROR "missing constant value" */ ;`,                      // issue 9639
-	`package p; const x /* ERROR "missing constant value" */ int;`,                   // issue 9639
-	`package p; const (x = 0; y; z /* ERROR "missing constant value" */ int);`,       // issue 9639
+	`package p; func f() { go func() { func() { f(x func /* ERROR "expected '\)'" */ (){}) } } }`,
+	`package p; func f() (a b string /* ERROR "expected '\)'" */ , ok bool) // issue 8656`,
 }
 
 func TestInvalid(t *testing.T) {
diff --git a/src/go/parser/testdata/issue3106.src b/src/go/parser/testdata/issue3106.src
index 2db10be..82796c8 100644
--- a/src/go/parser/testdata/issue3106.src
+++ b/src/go/parser/testdata/issue3106.src
@@ -19,7 +19,7 @@ func f() {
 				time.Sleep(1e8)
 				m.Lock()
 				defer
-				if /* ERROR "expected ';', found 'if'" */ percent == 100 {
+				if /* ERROR "expected operand, found 'if'" */ percent == 100 {
 					m.Unlock()
 					break
 				}
diff --git a/src/go/printer/nodes.go b/src/go/printer/nodes.go
index fe04705..d5a6934 100644
--- a/src/go/printer/nodes.go
+++ b/src/go/printer/nodes.go
@@ -12,9 +12,6 @@ import (
 	"bytes"
 	"go/ast"
 	"go/token"
-	"strconv"
-	"strings"
-	"unicode"
 	"unicode/utf8"
 )
 
@@ -1337,49 +1334,6 @@ func (p *printer) valueSpec(s *ast.ValueSpec, keepType bool) {
 	}
 }
 
-func sanitizeImportPath(lit *ast.BasicLit) *ast.BasicLit {
-	// Note: An unmodified AST generated by go/parser will already
-	// contain a backward- or double-quoted path string that does
-	// not contain any invalid characters, and most of the work
-	// here is not needed. However, a modified or generated AST
-	// may possibly contain non-canonical paths. Do the work in
-	// all cases since it's not too hard and not speed-critical.
-
-	// if we don't have a proper string, be conservative and return whatever we have
-	if lit.Kind != token.STRING {
-		return lit
-	}
-	s, err := strconv.Unquote(lit.Value)
-	if err != nil {
-		return lit
-	}
-
-	// if the string is an invalid path, return whatever we have
-	//
-	// spec: "Implementation restriction: A compiler may restrict
-	// ImportPaths to non-empty strings using only characters belonging
-	// to Unicode's L, M, N, P, and S general categories (the Graphic
-	// characters without spaces) and may also exclude the characters
-	// !"#$%&'()*,:;<=>?[\]^`{|} and the Unicode replacement character
-	// U+FFFD."
-	if s == "" {
-		return lit
-	}
-	const illegalChars = `!"#$%&'()*,:;<=>?[\]^{|}` + "`\uFFFD"
-	for _, r := range s {
-		if !unicode.IsGraphic(r) || unicode.IsSpace(r) || strings.ContainsRune(illegalChars, r) {
-			return lit
-		}
-	}
-
-	// otherwise, return the double-quoted path
-	s = strconv.Quote(s)
-	if s == lit.Value {
-		return lit // nothing wrong with lit
-	}
-	return &ast.BasicLit{ValuePos: lit.ValuePos, Kind: token.STRING, Value: s}
-}
-
 // The parameter n is the number of specs in the group. If doIndent is set,
 // multi-line identifier lists in the spec are indented when the first
 // linebreak is encountered.
@@ -1392,7 +1346,7 @@ func (p *printer) spec(spec ast.Spec, n int, doIndent bool) {
 			p.expr(s.Name)
 			p.print(blank)
 		}
-		p.expr(sanitizeImportPath(s.Path))
+		p.expr(s.Path)
 		p.setComment(s.Comment)
 		p.print(s.EndPos)
 
diff --git a/src/go/printer/printer.go b/src/go/printer/printer.go
index f9343d3..280c697 100644
--- a/src/go/printer/printer.go
+++ b/src/go/printer/printer.go
@@ -144,7 +144,7 @@ func (p *printer) nextComment() {
 	p.commentOffset = infinity
 }
 
-// commentBefore reports whether the current comment group occurs
+// 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.
 //
@@ -496,33 +496,29 @@ func stripCommonPrefix(lines []string) {
 	// Compute maximum common white prefix of all but the first,
 	// last, and blank lines, and replace blank lines with empty
 	// lines (the first line starts with /* and has no prefix).
-	// In cases where only the first and last lines are not blank,
-	// such as two-line comments, or comments where all inner lines
-	// are blank, consider the last line for the prefix computation
-	// since otherwise the prefix would be empty.
+	// In case of two-line comments, consider the last line for
+	// the prefix computation since otherwise the prefix would
+	// be empty.
 	//
 	// Note that the first and last line are never empty (they
 	// contain the opening /* and closing */ respectively) and
 	// thus they can be ignored by the blank line check.
-	prefix := ""
-	prefixSet := false
+	var prefix string
 	if len(lines) > 2 {
+		first := true
 		for i, line := range lines[1 : len(lines)-1] {
-			if isBlank(line) {
+			switch {
+			case isBlank(line):
 				lines[1+i] = "" // range starts with lines[1]
-			} else {
-				if !prefixSet {
-					prefix = line
-					prefixSet = true
-				}
+			case first:
+				prefix = commonPrefix(line, line)
+				first = false
+			default:
 				prefix = commonPrefix(prefix, line)
 			}
-
 		}
-	}
-	// If we don't have a prefix yet, consider the last line.
-	if !prefixSet {
-		line := lines[len(lines)-1]
+	} else { // len(lines) == 2, lines cannot be blank (contain /* and */)
+		line := lines[1]
 		prefix = commonPrefix(line, line)
 	}
 
diff --git a/src/go/printer/testdata/comments.golden b/src/go/printer/testdata/comments.golden
index 849fa62..b1af795 100644
--- a/src/go/printer/testdata/comments.golden
+++ b/src/go/printer/testdata/comments.golden
@@ -413,68 +413,6 @@ func _() {
 		aligned line */
 }
 
-// Issue 9751.
-func _() {
-	/*a string
-
-	b string*/
-
-	/*A string
-
-
-
-	Z string*/
-
-	/*a string
-
-	b string
-
-	c string*/
-
-	{
-		/*a string
-		b string*/
-
-		/*a string
-
-		b string*/
-
-		/*a string
-
-		b string
-
-		c string*/
-	}
-
-	{
-		/*a string
-		b string*/
-
-		/*a string
-
-		b string*/
-
-		/*a string
-
-		b string
-
-		c string*/
-	}
-
-	/*
-	 */
-
-	/*
-
-	 */
-
-	/*
-
-	 * line
-
-	 */
-}
-
 /*
  * line
  * of
diff --git a/src/go/printer/testdata/comments.input b/src/go/printer/testdata/comments.input
index 30cd23c..983e2b2 100644
--- a/src/go/printer/testdata/comments.input
+++ b/src/go/printer/testdata/comments.input
@@ -418,68 +418,6 @@ func _() {
 		aligned line */
 }
 
-// Issue 9751.
-func _() {
-	/*a string
-
-	b string*/
-
-	/*A string
-
-
-
-	Z string*/
-
-	/*a string
-
-	b string
-
-	c string*/
-
-	{
-		/*a string
-b string*/
-
-		/*a string
-
-b string*/
-
-		/*a string
-
-b string
-
-c string*/
-	}
-
-	{
-		/*a string
-				b string*/
-
-		/*a string
-
-				b string*/
-
-		/*a string
-
-				b string
-
-				c string*/
-	}
-
-	/*
-	*/
-
-	/*
-
-	*/
-
-	/*
-
-	 * line
-
-	*/
-}
-
 /*
  * line
  * of
diff --git a/src/go/printer/testdata/declarations.golden b/src/go/printer/testdata/declarations.golden
index 82f5e0f..9acd41b 100644
--- a/src/go/printer/testdata/declarations.golden
+++ b/src/go/printer/testdata/declarations.golden
@@ -110,15 +110,6 @@ import (
 	"package_dddd"	// comment
 )
 
-// print import paths as double-quoted strings
-// (we would like more test cases but the go/parser
-// already excludes most incorrect paths, and we don't
-// bother setting up test-ASTs manually)
-import (
-	"fmt"
-	"math"
-)
-
 // at least one empty line between declarations of different kind
 import _ "io"
 
diff --git a/src/go/printer/testdata/declarations.input b/src/go/printer/testdata/declarations.input
index a0a3783..45beec2 100644
--- a/src/go/printer/testdata/declarations.input
+++ b/src/go/printer/testdata/declarations.input
@@ -111,15 +111,6 @@ import (
 	"package_dddd" // comment
 )
 
-// print import paths as double-quoted strings
-// (we would like more test cases but the go/parser
-// already excludes most incorrect paths, and we don't
-// bother setting up test-ASTs manually)
-import (
-	`fmt`
-	"math"
-)
-
 // at least one empty line between declarations of different kind
 import _ "io"
 var _ int
diff --git a/src/go/printer/testdata/parser.go b/src/go/printer/testdata/parser.go
index 44dfa19..dba8bbd 100644
--- a/src/go/printer/testdata/parser.go
+++ b/src/go/printer/testdata/parser.go
@@ -1165,7 +1165,7 @@ func (p *parser) checkExpr(x ast.Expr) ast.Expr {
 	return x
 }
 
-// isTypeName reports whether x is a (qualified) TypeName.
+// isTypeName returns true iff x is a (qualified) TypeName.
 func isTypeName(x ast.Expr) bool {
 	switch t := x.(type) {
 	case *ast.BadExpr:
@@ -1179,7 +1179,7 @@ func isTypeName(x ast.Expr) bool {
 	return true
 }
 
-// isLiteralType reports whether x is a legal composite literal type.
+// isLiteralType returns true iff x is a legal composite literal type.
 func isLiteralType(x ast.Expr) bool {
 	switch t := x.(type) {
 	case *ast.BadExpr:
diff --git a/src/go/scanner/errors.go b/src/go/scanner/errors.go
index bf7bfa3..22de69c 100644
--- a/src/go/scanner/errors.go
+++ b/src/go/scanner/errors.go
@@ -54,16 +54,18 @@ func (p ErrorList) Less(i, j int) bool {
 	// Note that it is not sufficient to simply compare file offsets because
 	// the offsets do not reflect modified line information (through //line
 	// comments).
-	if e.Filename != f.Filename {
-		return e.Filename < f.Filename
+	if e.Filename < f.Filename {
+		return true
 	}
-	if e.Line != f.Line {
-		return e.Line < f.Line
-	}
-	if e.Column != f.Column {
-		return e.Column < f.Column
+	if e.Filename == f.Filename {
+		if e.Line < f.Line {
+			return true
+		}
+		if e.Line == f.Line {
+			return e.Column < f.Column
+		}
 	}
-	return p[i].Msg < p[j].Msg
+	return false
 }
 
 // Sort sorts an ErrorList. *Error entries are sorted by position,
diff --git a/src/go/scanner/scanner.go b/src/go/scanner/scanner.go
index e9476c4..cec82ea 100644
--- a/src/go/scanner/scanner.go
+++ b/src/go/scanner/scanner.go
@@ -706,14 +706,13 @@ scanAgain:
 					s.insertSemi = false // newline consumed
 					return pos, token.SEMICOLON, "\n"
 				}
-				comment := s.scanComment()
+				lit = s.scanComment()
 				if s.mode&ScanComments == 0 {
 					// skip comment
 					s.insertSemi = false // newline consumed
 					goto scanAgain
 				}
 				tok = token.COMMENT
-				lit = comment
 			} else {
 				tok = s.switch2(token.QUO, token.QUO_ASSIGN)
 			}
diff --git a/src/go/scanner/scanner_test.go b/src/go/scanner/scanner_test.go
index 0d21905..fc450d8 100644
--- a/src/go/scanner/scanner_test.go
+++ b/src/go/scanner/scanner_test.go
@@ -734,41 +734,6 @@ func TestScanErrors(t *testing.T) {
 	}
 }
 
-// Verify that no comments show up as literal values when skipping comments.
-func TestIssue10213(t *testing.T) {
-	var src = `
-		var (
-			A = 1 // foo
-		)
-
-		var (
-			B = 2
-			// foo
-		)
-
-		var C = 3 // foo
-
-		var D = 4
-		// foo
-
-		func anycode() {
-		// foo
-		}
-	`
-	var s Scanner
-	s.Init(fset.AddFile("", fset.Base(), len(src)), []byte(src), nil, 0)
-	for {
-		pos, tok, lit := s.Scan()
-		class := tokenclass(tok)
-		if lit != "" && class != keyword && class != literal && tok != token.SEMICOLON {
-			t.Errorf("%s: tok = %s, lit = %q", fset.Position(pos), tok, lit)
-		}
-		if tok <= token.EOF {
-			break
-		}
-	}
-}
-
 func BenchmarkScan(b *testing.B) {
 	b.StopTimer()
 	fset := token.NewFileSet()
diff --git a/src/go/token/position.go b/src/go/token/position.go
index 3375177..82d90ee 100644
--- a/src/go/token/position.go
+++ b/src/go/token/position.go
@@ -21,10 +21,10 @@ type Position struct {
 	Filename string // filename, if any
 	Offset   int    // offset, starting at 0
 	Line     int    // line number, starting at 1
-	Column   int    // column number, starting at 1 (byte count)
+	Column   int    // column number, starting at 1 (character count)
 }
 
-// IsValid reports whether the position is valid.
+// IsValid returns true if the position is valid.
 func (pos *Position) IsValid() bool { return pos.Line > 0 }
 
 // String returns a string in one of several forms:
@@ -56,8 +56,8 @@ func (pos Position) String() string {
 // where base and size are specified when adding the file to the file set via
 // AddFile.
 //
-// To create the Pos value for a specific source offset (measured in bytes),
-// first add the respective file to the current file set using FileSet.AddFile
+// To create the Pos value for a specific source offset, first add
+// the respective file to the current file set (via FileSet.AddFile)
 // and then call File.Pos(offset) for that file. Given a Pos value p
 // for a specific file set fset, the corresponding Position value is
 // obtained by calling fset.Position(p).
@@ -77,7 +77,7 @@ type Pos int
 //
 const NoPos Pos = 0
 
-// IsValid reports whether the position is valid.
+// IsValid returns true if the position is valid.
 func (p Pos) IsValid() bool {
 	return p != NoPos
 }
@@ -157,7 +157,7 @@ func (f *File) MergeLine(line int) {
 	f.lines = f.lines[:len(f.lines)-1]
 }
 
-// SetLines sets the line offsets for a file and reports whether it succeeded.
+// SetLines sets the line offsets for a file and returns true if successful.
 // The line offsets are the offsets of the first character of each line;
 // for instance for the content "ab\nc\n" the line offsets are {0, 3}.
 // An empty file has an empty line offset table.
diff --git a/src/hash/crc32/crc32.go b/src/hash/crc32/crc32.go
index 234d929..6a6b947 100644
--- a/src/hash/crc32/crc32.go
+++ b/src/hash/crc32/crc32.go
@@ -5,11 +5,6 @@
 // Package crc32 implements the 32-bit cyclic redundancy check, or CRC-32,
 // checksum. See http://en.wikipedia.org/wiki/Cyclic_redundancy_check for
 // information.
-//
-// Polynomials are represented in LSB-first form also known as reversed representation.
-//
-// See http://en.wikipedia.org/wiki/Mathematics_of_cyclic_redundancy_checks#Reversed_representations_and_reciprocal_polynomials
-// for information.
 package crc32
 
 import (
@@ -54,13 +49,6 @@ func castagnoliInit() {
 // IEEETable is the table for the IEEE polynomial.
 var IEEETable = makeTable(IEEE)
 
-// slicing8Table is array of 8 Tables
-type slicing8Table [8]Table
-
-// iEEETable8 is the slicing8Table for IEEE
-var iEEETable8 *slicing8Table
-var iEEETable8Once sync.Once
-
 // MakeTable returns the Table constructed from the specified polynomial.
 func MakeTable(poly uint32) *Table {
 	switch poly {
@@ -90,20 +78,6 @@ func makeTable(poly uint32) *Table {
 	return t
 }
 
-// makeTable8 returns slicing8Table constructed from the specified polynomial.
-func makeTable8(poly uint32) *slicing8Table {
-	t := new(slicing8Table)
-	t[0] = *makeTable(poly)
-	for i := 0; i < 256; i++ {
-		crc := t[0][i]
-		for j := 1; j < 8; j++ {
-			crc = t[0][crc&0xFF] ^ (crc >> 8)
-			t[j][i] = crc
-		}
-	}
-	return t
-}
-
 // digest represents the partial evaluation of a checksum.
 type digest struct {
 	crc uint32
@@ -132,32 +106,11 @@ func update(crc uint32, tab *Table, p []byte) uint32 {
 	return ^crc
 }
 
-// updateSlicingBy8 updates CRC using Slicing-by-8
-func updateSlicingBy8(crc uint32, tab *slicing8Table, p []byte) uint32 {
-	crc = ^crc
-	for len(p) > 8 {
-		crc ^= uint32(p[0]) | uint32(p[1])<<8 | uint32(p[2])<<16 | uint32(p[3])<<24
-		crc = tab[0][p[7]] ^ tab[1][p[6]] ^ tab[2][p[5]] ^ tab[3][p[4]] ^
-			tab[4][crc>>24] ^ tab[5][(crc>>16)&0xFF] ^
-			tab[6][(crc>>8)&0xFF] ^ tab[7][crc&0xFF]
-		p = p[8:]
-	}
-	crc = ^crc
-	return update(crc, &tab[0], p)
-}
-
 // Update returns the result of adding the bytes in p to the crc.
 func Update(crc uint32, tab *Table, p []byte) uint32 {
 	if tab == castagnoliTable {
 		return updateCastagnoli(crc, p)
 	}
-	// only use slicing-by-8 when input is larger than 4KB
-	if tab == IEEETable && len(p) >= 4096 {
-		iEEETable8Once.Do(func() {
-			iEEETable8 = makeTable8(IEEE)
-		})
-		return updateSlicingBy8(crc, iEEETable8, p)
-	}
 	return update(crc, tab, p)
 }
 
@@ -179,4 +132,4 @@ func Checksum(data []byte, tab *Table) uint32 { return Update(0, tab, data) }
 
 // ChecksumIEEE returns the CRC-32 checksum of data
 // using the IEEE polynomial.
-func ChecksumIEEE(data []byte) uint32 { return Update(0, IEEETable, data) }
+func ChecksumIEEE(data []byte) uint32 { return update(0, IEEETable, data) }
diff --git a/src/hash/crc32/crc32_generic.go b/src/hash/crc32/crc32_generic.go
index 416c1b7..c3fdcd6 100644
--- a/src/hash/crc32/crc32_generic.go
+++ b/src/hash/crc32/crc32_generic.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 386 arm arm64 ppc64 ppc64le
+// +build 386 arm
 
 package crc32
 
diff --git a/src/hash/crc32/crc32_test.go b/src/hash/crc32/crc32_test.go
index 1ca3ac2..75dc26e 100644
--- a/src/hash/crc32/crc32_test.go
+++ b/src/hash/crc32/crc32_test.go
@@ -81,7 +81,7 @@ func TestGolden(t *testing.T) {
 	}
 }
 
-func BenchmarkIEEECrc1KB(b *testing.B) {
+func BenchmarkCrc32KB(b *testing.B) {
 	b.SetBytes(1024)
 	data := make([]byte, 1024)
 	for i := range data {
@@ -97,37 +97,3 @@ func BenchmarkIEEECrc1KB(b *testing.B) {
 		h.Sum(in)
 	}
 }
-
-func BenchmarkIEEECrc4KB(b *testing.B) {
-	b.SetBytes(4096)
-	data := make([]byte, 4096)
-	for i := range data {
-		data[i] = byte(i)
-	}
-	h := NewIEEE()
-	in := make([]byte, 0, h.Size())
-
-	b.ResetTimer()
-	for i := 0; i < b.N; i++ {
-		h.Reset()
-		h.Write(data)
-		h.Sum(in)
-	}
-}
-
-func BenchmarkCastagnoliCrc1KB(b *testing.B) {
-	b.SetBytes(1024)
-	data := make([]byte, 1024)
-	for i := range data {
-		data[i] = byte(i)
-	}
-	h := New(MakeTable(Castagnoli))
-	in := make([]byte, 0, h.Size())
-
-	b.ResetTimer()
-	for i := 0; i < b.N; i++ {
-		h.Reset()
-		h.Write(data)
-		h.Sum(in)
-	}
-}
diff --git a/src/html/escape.go b/src/html/escape.go
index f50a4b9..dd5dfa7 100644
--- a/src/html/escape.go
+++ b/src/html/escape.go
@@ -6,6 +6,7 @@
 package html
 
 import (
+	"bytes"
 	"strings"
 	"unicode/utf8"
 )
@@ -186,20 +187,52 @@ func unescape(b []byte) []byte {
 	return b
 }
 
-var htmlEscaper = strings.NewReplacer(
-	`&`, "&",
-	`'`, "'", // "'" is shorter than "'" and apos was not in HTML until HTML5.
-	`<`, "<",
-	`>`, ">",
-	`"`, """, // """ is shorter than """.
-)
+const escapedChars = `&'<>"`
+
+func escape(w writer, s string) error {
+	i := strings.IndexAny(s, escapedChars)
+	for i != -1 {
+		if _, err := w.WriteString(s[:i]); err != nil {
+			return err
+		}
+		var esc string
+		switch s[i] {
+		case '&':
+			esc = "&"
+		case '\'':
+			// "'" is shorter than "'" and apos was not in HTML until HTML5.
+			esc = "'"
+		case '<':
+			esc = "<"
+		case '>':
+			esc = ">"
+		case '"':
+			// """ is shorter than """.
+			esc = """
+		default:
+			panic("unrecognized escape character")
+		}
+		s = s[i+1:]
+		if _, err := w.WriteString(esc); err != nil {
+			return err
+		}
+		i = strings.IndexAny(s, escapedChars)
+	}
+	_, err := w.WriteString(s)
+	return err
+}
 
 // EscapeString escapes special characters like "<" to become "<". It
 // escapes only five such characters: <, >, &, ' and ".
 // UnescapeString(EscapeString(s)) == s always holds, but the converse isn't
 // always true.
 func EscapeString(s string) string {
-	return htmlEscaper.Replace(s)
+	if strings.IndexAny(s, escapedChars) == -1 {
+		return s
+	}
+	var buf bytes.Buffer
+	escape(&buf, s)
+	return buf.String()
 }
 
 // UnescapeString unescapes entities like "<" to become "<". It unescapes a
@@ -208,8 +241,10 @@ func EscapeString(s string) string {
 // UnescapeString(EscapeString(s)) == s always holds, but the converse isn't
 // always true.
 func UnescapeString(s string) string {
-	if !strings.Contains(s, "&") {
-		return s
+	for _, c := range s {
+		if c == '&' {
+			return string(unescape([]byte(s)))
+		}
 	}
-	return string(unescape([]byte(s)))
+	return s
 }
diff --git a/src/html/escape_test.go b/src/html/escape_test.go
index 3702626..2d7ad8a 100644
--- a/src/html/escape_test.go
+++ b/src/html/escape_test.go
@@ -4,10 +4,7 @@
 
 package html
 
-import (
-	"strings"
-	"testing"
-)
+import "testing"
 
 type unescapeTest struct {
 	// A short description of the test case.
@@ -116,38 +113,3 @@ func TestUnescapeEscape(t *testing.T) {
 		}
 	}
 }
-
-var (
-	benchEscapeData = strings.Repeat("AAAAA < BBBBB > CCCCC & DDDDD ' EEEEE \" ", 100)
-	benchEscapeNone = strings.Repeat("AAAAA x BBBBB x CCCCC x DDDDD x EEEEE x ", 100)
-)
-
-func BenchmarkEscape(b *testing.B) {
-	n := 0
-	for i := 0; i < b.N; i++ {
-		n += len(EscapeString(benchEscapeData))
-	}
-}
-
-func BenchmarkEscapeNone(b *testing.B) {
-	n := 0
-	for i := 0; i < b.N; i++ {
-		n += len(EscapeString(benchEscapeNone))
-	}
-}
-
-func BenchmarkUnescape(b *testing.B) {
-	s := EscapeString(benchEscapeData)
-	n := 0
-	for i := 0; i < b.N; i++ {
-		n += len(UnescapeString(s))
-	}
-}
-
-func BenchmarkUnescapeNone(b *testing.B) {
-	s := EscapeString(benchEscapeNone)
-	n := 0
-	for i := 0; i < b.N; i++ {
-		n += len(UnescapeString(s))
-	}
-}
diff --git a/src/html/template/clone_test.go b/src/html/template/clone_test.go
index c89d22a..e11bff2 100644
--- a/src/html/template/clone_test.go
+++ b/src/html/template/clone_test.go
@@ -142,7 +142,7 @@ func TestTemplates(t *testing.T) {
 	}
 }
 
-// This used to crash; https://golang.org/issue/3281
+// This used to crash; http://golang.org/issue/3281
 func TestCloneCrash(t *testing.T) {
 	t1 := New("all")
 	Must(t1.New("t1").Parse(`{{define "foo"}}foo{{end}}`))
@@ -166,7 +166,7 @@ func TestCloneThenParse(t *testing.T) {
 	}
 }
 
-// https://golang.org/issue/5980
+// https://code.google.com/p/go/issues/detail?id=5980
 func TestFuncMapWorksAfterClone(t *testing.T) {
 	funcs := FuncMap{"customFunc": func() (string, error) {
 		return "", errors.New("issue5980")
diff --git a/src/html/template/content_test.go b/src/html/template/content_test.go
index e698328..5f3ffe2 100644
--- a/src/html/template/content_test.go
+++ b/src/html/template/content_test.go
@@ -260,7 +260,7 @@ func TestStringer(t *testing.T) {
 	}
 }
 
-// https://golang.org/issue/5982
+// https://code.google.com/p/go/issues/detail?id=5982
 func TestEscapingNilNonemptyInterfaces(t *testing.T) {
 	tmpl := Must(New("x").Parse("{{.E}}"))
 
diff --git a/src/html/template/css.go b/src/html/template/css.go
index 3184648..634f183 100644
--- a/src/html/template/css.go
+++ b/src/html/template/css.go
@@ -157,20 +157,56 @@ func isCSSSpace(b byte) bool {
 func cssEscaper(args ...interface{}) string {
 	s, _ := stringify(args...)
 	var b bytes.Buffer
-	r, w, written := rune(0), 0, 0
-	for i := 0; i < len(s); i += w {
-		// See comment in htmlEscaper.
-		r, w = utf8.DecodeRuneInString(s[i:])
+	written := 0
+	for i, r := range s {
 		var repl string
-		switch {
-		case int(r) < len(cssReplacementTable) && cssReplacementTable[r] != "":
-			repl = cssReplacementTable[r]
+		switch r {
+		case 0:
+			repl = `\0`
+		case '\t':
+			repl = `\9`
+		case '\n':
+			repl = `\a`
+		case '\f':
+			repl = `\c`
+		case '\r':
+			repl = `\d`
+		// Encode HTML specials as hex so the output can be embedded
+		// in HTML attributes without further encoding.
+		case '"':
+			repl = `\22`
+		case '&':
+			repl = `\26`
+		case '\'':
+			repl = `\27`
+		case '(':
+			repl = `\28`
+		case ')':
+			repl = `\29`
+		case '+':
+			repl = `\2b`
+		case '/':
+			repl = `\2f`
+		case ':':
+			repl = `\3a`
+		case ';':
+			repl = `\3b`
+		case '<':
+			repl = `\3c`
+		case '>':
+			repl = `\3e`
+		case '\\':
+			repl = `\\`
+		case '{':
+			repl = `\7b`
+		case '}':
+			repl = `\7d`
 		default:
 			continue
 		}
 		b.WriteString(s[written:i])
 		b.WriteString(repl)
-		written = i + w
+		written = i + utf8.RuneLen(r)
 		if repl != `\\` && (written == len(s) || isHex(s[written]) || isCSSSpace(s[written])) {
 			b.WriteByte(' ')
 		}
@@ -182,30 +218,6 @@ func cssEscaper(args ...interface{}) string {
 	return b.String()
 }
 
-var cssReplacementTable = []string{
-	0:    `\0`,
-	'\t': `\9`,
-	'\n': `\a`,
-	'\f': `\c`,
-	'\r': `\d`,
-	// Encode HTML specials as hex so the output can be embedded
-	// in HTML attributes without further encoding.
-	'"':  `\22`,
-	'&':  `\26`,
-	'\'': `\27`,
-	'(':  `\28`,
-	')':  `\29`,
-	'+':  `\2b`,
-	'/':  `\2f`,
-	':':  `\3a`,
-	';':  `\3b`,
-	'<':  `\3c`,
-	'>':  `\3e`,
-	'\\': `\\`,
-	'{':  `\7b`,
-	'}':  `\7d`,
-}
-
 var expressionBytes = []byte("expression")
 var mozBindingBytes = []byte("mozbinding")
 
diff --git a/src/html/template/doc.go b/src/html/template/doc.go
index 1827403..d422ada 100644
--- a/src/html/template/doc.go
+++ b/src/html/template/doc.go
@@ -151,7 +151,7 @@ The template
 
 can be invoked with
 
-  tmpl.Execute(out, template.HTML(`<b>World</b>`))
+  tmpl.Execute(out, HTML(`<b>World</b>`))
 
 to produce
 
diff --git a/src/html/template/escape.go b/src/html/template/escape.go
index 3c18340..ee01fb1 100644
--- a/src/html/template/escape.go
+++ b/src/html/template/escape.go
@@ -205,17 +205,15 @@ func (e *escaper) escapeAction(c context, n *parse.ActionNode) context {
 }
 
 // allIdents returns the names of the identifiers under the Ident field of the node,
-// which might be a singleton (Identifier) or a slice (Field or Chain).
+// 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
-	case *parse.ChainNode:
-		return node.Field
 	}
-	return nil
+	panic("unidentified node type in allIdents")
 }
 
 // ensurePipelineContains ensures that the pipeline has commands with
@@ -299,9 +297,9 @@ var redundantFuncs = map[string]map[string]bool{
 // unless it is redundant with the last command.
 func appendCmd(cmds []*parse.CommandNode, cmd *parse.CommandNode) []*parse.CommandNode {
 	if n := len(cmds); n != 0 {
-		last, okLast := cmds[n-1].Args[0].(*parse.IdentifierNode)
-		next, okNext := cmd.Args[0].(*parse.IdentifierNode)
-		if okLast && okNext && redundantFuncs[last.Ident][next.Ident] {
+		last, ok := cmds[n-1].Args[0].(*parse.IdentifierNode)
+		next, _ := cmd.Args[0].(*parse.IdentifierNode)
+		if ok && redundantFuncs[last.Ident][next.Ident] {
 			return cmds
 		}
 	}
diff --git a/src/html/template/escape_test.go b/src/html/template/escape_test.go
index bea2d13..ef7b877 100644
--- a/src/html/template/escape_test.go
+++ b/src/html/template/escape_test.go
@@ -1547,28 +1547,6 @@ func TestEnsurePipelineContains(t *testing.T) {
 			"($).X | urlquery | html | print",
 			[]string{"urlquery", "html"},
 		},
-		{
-			"{{.X | print 2 | .f 3}}",
-			".X | print 2 | .f 3 | urlquery | html",
-			[]string{"urlquery", "html"},
-		},
-		{
-			"{{.X | html | print 2 | .f 3}}",
-			".X | urlquery | html | print 2 | .f 3",
-			[]string{"urlquery", "html"},
-		},
-		{
-			// covering issue 10801
-			"{{.X | js.x }}",
-			".X | js.x | urlquery | html",
-			[]string{"urlquery", "html"},
-		},
-		{
-			// covering issue 10801
-			"{{.X | (print 12 | js).x }}",
-			".X | (print 12 | js).x | urlquery | html",
-			[]string{"urlquery", "html"},
-		},
 	}
 	for i, test := range tests {
 		tmpl := template.Must(template.New("test").Parse(test.input))
@@ -1586,28 +1564,6 @@ func TestEnsurePipelineContains(t *testing.T) {
 	}
 }
 
-func TestEscapeMalformedPipelines(t *testing.T) {
-	tests := []string{
-		"{{ 0 | $ }}",
-		"{{ 0 | $ | urlquery }}",
-		"{{ 0 | $ | urlquery | html }}",
-		"{{ 0 | (nil) }}",
-		"{{ 0 | (nil) | html }}",
-		"{{ 0 | (nil) | html | urlquery }}",
-	}
-	for _, test := range tests {
-		var b bytes.Buffer
-		tmpl, err := New("test").Parse(test)
-		if err != nil {
-			t.Errorf("failed to parse set: %q", err)
-		}
-		err = tmpl.Execute(&b, nil)
-		if err == nil {
-			t.Errorf("Expected error for %q", test)
-		}
-	}
-}
-
 func TestEscapeErrorsNotIgnorable(t *testing.T) {
 	var b bytes.Buffer
 	tmpl, _ := New("dangerous").Parse("<a")
@@ -1730,21 +1686,6 @@ func TestPipeToMethodIsEscaped(t *testing.T) {
 	}
 }
 
-// Unlike text/template, html/template crashed if given an incomplete
-// template, that is, a template that had been named but not given any content.
-// This is issue #10204.
-func TestErrorOnUndefined(t *testing.T) {
-	tmpl := New("undefined")
-
-	err := tmpl.Execute(nil, nil)
-	if err == nil {
-		t.Error("expected error")
-	}
-	if !strings.Contains(err.Error(), "incomplete") {
-		t.Errorf("expected error about incomplete template; got %s", err)
-	}
-}
-
 func BenchmarkEscapedExecute(b *testing.B) {
 	tmpl := Must(New("t").Parse(`<a onclick="alert('{{.}}')">{{.}}</a>`))
 	var buf bytes.Buffer
diff --git a/src/html/template/html.go b/src/html/template/html.go
index de4aa4a..9c069ef 100644
--- a/src/html/template/html.go
+++ b/src/html/template/html.go
@@ -138,24 +138,21 @@ var htmlNospaceNormReplacementTable = []string{
 // and when badRunes is true, certain bad runes are allowed through unescaped.
 func htmlReplacer(s string, replacementTable []string, badRunes bool) string {
 	written, b := 0, new(bytes.Buffer)
-	r, w := rune(0), 0
-	for i := 0; i < len(s); i += w {
-		// Cannot use 'for range s' because we need to preserve the width
-		// of the runes in the input. If we see a decoding error, the input
-		// width will not be utf8.Runelen(r) and we will overrun the buffer.
-		r, w = utf8.DecodeRuneInString(s[i:])
+	for i, r := range s {
 		if int(r) < len(replacementTable) {
 			if repl := replacementTable[r]; len(repl) != 0 {
 				b.WriteString(s[written:i])
 				b.WriteString(repl)
-				written = i + w
+				// Valid as long as replacementTable doesn't
+				// include anything above 0x7f.
+				written = i + utf8.RuneLen(r)
 			}
 		} else if badRunes {
 			// No-op.
 			// IE does not allow these ranges in unquoted attrs.
 		} else if 0xfdd0 <= r && r <= 0xfdef || 0xfff0 <= r && r <= 0xffff {
 			fmt.Fprintf(b, "%s&#x%x;", s[written:i], r)
-			written = i + w
+			written = i + utf8.RuneLen(r)
 		}
 	}
 	if written == 0 {
diff --git a/src/html/template/html_test.go b/src/html/template/html_test.go
index f04ee04..b9b9703 100644
--- a/src/html/template/html_test.go
+++ b/src/html/template/html_test.go
@@ -19,8 +19,7 @@ func TestHTMLNospaceEscaper(t *testing.T) {
 		`PQRSTUVWXYZ[\]^_` +
 		"`abcdefghijklmno" +
 		"pqrstuvwxyz{|}~\x7f" +
-		"\u00A0\u0100\u2028\u2029\ufeff\ufdec\U0001D11E" +
-		"erroneous\x960") // keep at the end
+		"\u00A0\u0100\u2028\u2029\ufeff\ufdec\U0001D11E")
 
 	want := ("&#xfffd;\x01\x02\x03\x04\x05\x06\x07" +
 		"\x08	

\x0E\x0F" +
@@ -32,16 +31,14 @@ func TestHTMLNospaceEscaper(t *testing.T) {
 		`PQRSTUVWXYZ[\]^_` +
 		``abcdefghijklmno` +
 		`pqrstuvwxyz{|}~` + "\u007f" +
-		"\u00A0\u0100\u2028\u2029\ufeff&#xfdec;\U0001D11E" +
-		"erroneous&#xfffd;0") // keep at the end
+		"\u00A0\u0100\u2028\u2029\ufeff&#xfdec;\U0001D11E")
 
 	got := htmlNospaceEscaper(input)
 	if got != want {
 		t.Errorf("encode: want\n\t%q\nbut got\n\t%q", want, got)
 	}
 
-	r := strings.NewReplacer("\x00", "\ufffd", "\x96", "\ufffd")
-	got, want = html.UnescapeString(got), r.Replace(input)
+	got, want = html.UnescapeString(got), strings.Replace(input, "\x00", "\ufffd", 1)
 	if want != got {
 		t.Errorf("decode: want\n\t%q\nbut got\n\t%q", want, got)
 	}
diff --git a/src/html/template/js.go b/src/html/template/js.go
index f6d166b..999a61e 100644
--- a/src/html/template/js.go
+++ b/src/html/template/js.go
@@ -246,10 +246,8 @@ func jsRegexpEscaper(args ...interface{}) string {
 // `\u2029`.
 func replace(s string, replacementTable []string) string {
 	var b bytes.Buffer
-	r, w, written := rune(0), 0, 0
-	for i := 0; i < len(s); i += w {
-		// See comment in htmlEscaper.
-		r, w = utf8.DecodeRuneInString(s[i:])
+	written := 0
+	for i, r := range s {
 		var repl string
 		switch {
 		case int(r) < len(replacementTable) && replacementTable[r] != "":
@@ -263,7 +261,7 @@ func replace(s string, replacementTable []string) string {
 		}
 		b.WriteString(s[written:i])
 		b.WriteString(repl)
-		written = i + w
+		written = i + utf8.RuneLen(r)
 	}
 	if written == 0 {
 		return s
diff --git a/src/html/template/template.go b/src/html/template/template.go
index bb9140a..ce61701 100644
--- a/src/html/template/template.go
+++ b/src/html/template/template.go
@@ -51,37 +51,11 @@ func (t *Template) Templates() []*Template {
 	return m
 }
 
-// Option sets options for the template. Options are described by
-// strings, either a simple string or "key=value". There can be at
-// most one equals sign in an option string. If the option string
-// is unrecognized or otherwise invalid, Option panics.
-//
-// Known options:
-//
-// missingkey: Control the behavior during execution if a map is
-// indexed with a key that is not present in the map.
-//	"missingkey=default" or "missingkey=invalid"
-//		The default behavior: Do nothing and continue execution.
-//		If printed, the result of the index operation is the string
-//		"<no value>".
-//	"missingkey=zero"
-//		The operation returns the zero value for the map type's element.
-//	"missingkey=error"
-//		Execution stops immediately with an error.
-//
-func (t *Template) Option(opt ...string) *Template {
-	t.text.Option(opt...)
-	return t
-}
-
 // escape escapes all associated templates.
 func (t *Template) escape() error {
 	t.nameSpace.mu.Lock()
 	defer t.nameSpace.mu.Unlock()
 	if t.escapeErr == nil {
-		if t.Tree == nil {
-			return fmt.Errorf("template: %q is an incomplete or empty template%s", t.Name(), t.text.DefinedTemplates())
-		}
 		if err := escapeTemplate(t, t.text.Root, t.Name()); err != nil {
 			return err
 		}
diff --git a/src/html/template/transition.go b/src/html/template/transition.go
index d2e0287..b486fcd 100644
--- a/src/html/template/transition.go
+++ b/src/html/template/transition.go
@@ -183,54 +183,24 @@ func tHTMLCmt(c context, s []byte) (context, int) {
 
 // specialTagEndMarkers maps element types to the character sequence that
 // case-insensitively signals the end of the special tag body.
-var specialTagEndMarkers = [...][]byte{
-	elementScript:   []byte("script"),
-	elementStyle:    []byte("style"),
-	elementTextarea: []byte("textarea"),
-	elementTitle:    []byte("title"),
+var specialTagEndMarkers = [...]string{
+	elementScript:   "</script",
+	elementStyle:    "</style",
+	elementTextarea: "</textarea",
+	elementTitle:    "</title",
 }
 
-var (
-	specialTagEndPrefix = []byte("</")
-	tagEndSeparators    = []byte("> \t\n\f/")
-)
-
 // tSpecialTagEnd is the context transition function for raw text and RCDATA
 // element states.
 func tSpecialTagEnd(c context, s []byte) (context, int) {
 	if c.element != elementNone {
-		if i := indexTagEnd(s, specialTagEndMarkers[c.element]); i != -1 {
+		if i := strings.Index(strings.ToLower(string(s)), specialTagEndMarkers[c.element]); i != -1 {
 			return context{}, i
 		}
 	}
 	return c, len(s)
 }
 
-// indexTagEnd finds the index of a special tag end in a case insensitive way, or returns -1
-func indexTagEnd(s []byte, tag []byte) int {
-	res := 0
-	plen := len(specialTagEndPrefix)
-	for len(s) > 0 {
-		// Try to find the tag end prefix first
-		i := bytes.Index(s, specialTagEndPrefix)
-		if i == -1 {
-			return i
-		}
-		s = s[i+plen:]
-		// Try to match the actual tag if there is still space for it
-		if len(tag) <= len(s) && bytes.EqualFold(tag, s[:len(tag)]) {
-			s = s[len(tag):]
-			// Check the tag is followed by a proper separator
-			if len(s) > 0 && bytes.IndexByte(tagEndSeparators, s[0]) != -1 {
-				return res + i
-			}
-			res += len(tag)
-		}
-		res += i + plen
-	}
-	return -1
-}
-
 // tAttr is the context transition function for the attribute state.
 func tAttr(c context, s []byte) (context, int) {
 	return c, len(s)
diff --git a/src/image/color/color.go b/src/image/color/color.go
index cae059b..ff596a7 100644
--- a/src/image/color/color.go
+++ b/src/image/color/color.go
@@ -9,20 +9,14 @@ package color
 // The conversion may be lossy.
 type Color interface {
 	// RGBA returns the alpha-premultiplied red, green, blue and alpha values
-	// for the color. Each value ranges within [0, 0xffff], but is represented
-	// by a uint32 so that multiplying by a blend factor up to 0xffff will not
+	// for the color. Each value ranges within [0, 0xFFFF], but is represented
+	// by a uint32 so that multiplying by a blend factor up to 0xFFFF will not
 	// overflow.
-	//
-	// An alpha-premultiplied color component c has been scaled by alpha (a),
-	// so has valid values 0 <= c <= a.
 	RGBA() (r, g, b, a uint32)
 }
 
-// RGBA represents a traditional 32-bit alpha-premultiplied color, having 8
-// bits for each of red, green, blue and alpha.
-//
-// An alpha-premultiplied color component C has been scaled by alpha (A), so
-// has valid values 0 <= C <= A.
+// RGBA represents a traditional 32-bit alpha-premultiplied color,
+// having 8 bits for each of red, green, blue and alpha.
 type RGBA struct {
 	R, G, B, A uint8
 }
@@ -39,11 +33,8 @@ func (c RGBA) RGBA() (r, g, b, a uint32) {
 	return
 }
 
-// RGBA64 represents a 64-bit alpha-premultiplied color, having 16 bits for
-// each of red, green, blue and alpha.
-//
-// An alpha-premultiplied color component C has been scaled by alpha (A), so
-// has valid values 0 <= C <= A.
+// RGBA64 represents a 64-bit alpha-premultiplied color,
+// having 16 bits for each of red, green, blue and alpha.
 type RGBA64 struct {
 	R, G, B, A uint16
 }
@@ -271,39 +262,32 @@ func (p Palette) Convert(c Color) Color {
 }
 
 // Index returns the index of the palette color closest to c in Euclidean
-// R,G,B,A space.
+// R,G,B space.
 func (p Palette) Index(c Color) int {
 	// A batch version of this computation is in image/draw/draw.go.
 
-	cr, cg, cb, ca := c.RGBA()
-	ret, bestSum := 0, uint32(1<<32-1)
+	cr, cg, cb, _ := c.RGBA()
+	ret, bestSSD := 0, uint32(1<<32-1)
 	for i, v := range p {
-		vr, vg, vb, va := v.RGBA()
-		sum := sqDiff(cr, vr) + sqDiff(cg, vg) + sqDiff(cb, vb) + sqDiff(ca, va)
-		if sum < bestSum {
-			if sum == 0 {
+		vr, vg, vb, _ := v.RGBA()
+		// We shift by 1 bit to avoid potential uint32 overflow in
+		// sum-squared-difference.
+		delta := (int32(cr) - int32(vr)) >> 1
+		ssd := uint32(delta * delta)
+		delta = (int32(cg) - int32(vg)) >> 1
+		ssd += uint32(delta * delta)
+		delta = (int32(cb) - int32(vb)) >> 1
+		ssd += uint32(delta * delta)
+		if ssd < bestSSD {
+			if ssd == 0 {
 				return i
 			}
-			ret, bestSum = i, sum
+			ret, bestSSD = i, ssd
 		}
 	}
 	return ret
 }
 
-// sqDiff returns the squared-difference of x and y, shifted by 2 so that
-// adding four of those won't overflow a uint32.
-//
-// x and y are both assumed to be in the range [0, 0xffff].
-func sqDiff(x, y uint32) uint32 {
-	var d uint32
-	if x > y {
-		d = x - y
-	} else {
-		d = y - x
-	}
-	return (d * d) >> 2
-}
-
 // Standard colors.
 var (
 	Black       = Gray16{0}
diff --git a/src/image/color/ycbcr.go b/src/image/color/ycbcr.go
index 4bcb07d..4c2f29e 100644
--- a/src/image/color/ycbcr.go
+++ b/src/image/color/ycbcr.go
@@ -11,27 +11,26 @@ func RGBToYCbCr(r, g, b uint8) (uint8, uint8, uint8) {
 	//	Cb = -0.1687*R - 0.3313*G + 0.5000*B + 128
 	//	Cr =  0.5000*R - 0.4187*G - 0.0813*B + 128
 	// http://www.w3.org/Graphics/JPEG/jfif3.pdf says Y but means Y'.
-
-	r1 := int32(r)
-	g1 := int32(g)
-	b1 := int32(b)
+	r1 := int(r)
+	g1 := int(g)
+	b1 := int(b)
 	yy := (19595*r1 + 38470*g1 + 7471*b1 + 1<<15) >> 16
 	cb := (-11056*r1 - 21712*g1 + 32768*b1 + 257<<15) >> 16
 	cr := (32768*r1 - 27440*g1 - 5328*b1 + 257<<15) >> 16
 	if yy < 0 {
 		yy = 0
-	} else if yy > 0xff {
-		yy = 0xff
+	} else if yy > 255 {
+		yy = 255
 	}
 	if cb < 0 {
 		cb = 0
-	} else if cb > 0xff {
-		cb = 0xff
+	} else if cb > 255 {
+		cb = 255
 	}
 	if cr < 0 {
 		cr = 0
-	} else if cr > 0xff {
-		cr = 0xff
+	} else if cr > 255 {
+		cr = 255
 	}
 	return uint8(yy), uint8(cb), uint8(cr)
 }
@@ -43,27 +42,26 @@ func YCbCrToRGB(y, cb, cr uint8) (uint8, uint8, uint8) {
 	//	G = Y' - 0.34414*(Cb-128) - 0.71414*(Cr-128)
 	//	B = Y' + 1.77200*(Cb-128)
 	// http://www.w3.org/Graphics/JPEG/jfif3.pdf says Y but means Y'.
-
-	yy1 := int32(y) * 0x10100 // Convert 0x12 to 0x121200.
-	cb1 := int32(cb) - 128
-	cr1 := int32(cr) - 128
+	yy1 := int(y)<<16 + 1<<15
+	cb1 := int(cb) - 128
+	cr1 := int(cr) - 128
 	r := (yy1 + 91881*cr1) >> 16
 	g := (yy1 - 22554*cb1 - 46802*cr1) >> 16
 	b := (yy1 + 116130*cb1) >> 16
 	if r < 0 {
 		r = 0
-	} else if r > 0xff {
-		r = 0xff
+	} else if r > 255 {
+		r = 255
 	}
 	if g < 0 {
 		g = 0
-	} else if g > 0xff {
-		g = 0xff
+	} else if g > 255 {
+		g = 255
 	}
 	if b < 0 {
 		b = 0
-	} else if b > 0xff {
-		b = 0xff
+	} else if b > 255 {
+		b = 255
 	}
 	return uint8(r), uint8(g), uint8(b)
 }
@@ -84,45 +82,8 @@ type YCbCr struct {
 }
 
 func (c YCbCr) RGBA() (uint32, uint32, uint32, uint32) {
-	// This code is a copy of the YCbCrToRGB function above, except that it
-	// returns values in the range [0, 0xffff] instead of [0, 0xff]. There is a
-	// subtle difference between doing this and having YCbCr satisfy the Color
-	// interface by first converting to an RGBA. The latter loses some
-	// information by going to and from 8 bits per channel.
-	//
-	// For example, this code:
-	//	const y, cb, cr = 0x7f, 0x7f, 0x7f
-	//	r, g, b := color.YCbCrToRGB(y, cb, cr)
-	//	r0, g0, b0, _ := color.YCbCr{y, cb, cr}.RGBA()
-	//	r1, g1, b1, _ := color.RGBA{r, g, b, 0xff}.RGBA()
-	//	fmt.Printf("0x%04x 0x%04x 0x%04x\n", r0, g0, b0)
-	//	fmt.Printf("0x%04x 0x%04x 0x%04x\n", r1, g1, b1)
-	// prints:
-	//	0x7e18 0x808e 0x7db9
-	//	0x7e7e 0x8080 0x7d7d
-
-	yy1 := int32(c.Y) * 0x10100 // Convert 0x12 to 0x121200.
-	cb1 := int32(c.Cb) - 128
-	cr1 := int32(c.Cr) - 128
-	r := (yy1 + 91881*cr1) >> 8
-	g := (yy1 - 22554*cb1 - 46802*cr1) >> 8
-	b := (yy1 + 116130*cb1) >> 8
-	if r < 0 {
-		r = 0
-	} else if r > 0xffff {
-		r = 0xffff
-	}
-	if g < 0 {
-		g = 0
-	} else if g > 0xffff {
-		g = 0xffff
-	}
-	if b < 0 {
-		b = 0
-	} else if b > 0xffff {
-		b = 0xffff
-	}
-	return uint32(r), uint32(g), uint32(b), 0xffff
+	r, g, b := YCbCrToRGB(c.Y, c.Cb, c.Cr)
+	return uint32(r) * 0x101, uint32(g) * 0x101, uint32(b) * 0x101, 0xffff
 }
 
 // YCbCrModel is the Model for Y'CbCr colors.
@@ -136,64 +97,3 @@ func yCbCrModel(c Color) Color {
 	y, u, v := RGBToYCbCr(uint8(r>>8), uint8(g>>8), uint8(b>>8))
 	return YCbCr{y, u, v}
 }
-
-// RGBToCMYK converts an RGB triple to a CMYK quadruple.
-func RGBToCMYK(r, g, b uint8) (uint8, uint8, uint8, uint8) {
-	rr := uint32(r)
-	gg := uint32(g)
-	bb := uint32(b)
-	w := rr
-	if w < gg {
-		w = gg
-	}
-	if w < bb {
-		w = bb
-	}
-	if w == 0 {
-		return 0, 0, 0, 0xff
-	}
-	c := (w - rr) * 0xff / w
-	m := (w - gg) * 0xff / w
-	y := (w - bb) * 0xff / w
-	return uint8(c), uint8(m), uint8(y), uint8(0xff - w)
-}
-
-// CMYKToRGB converts a CMYK quadruple to an RGB triple.
-func CMYKToRGB(c, m, y, k uint8) (uint8, uint8, uint8) {
-	w := uint32(0xffff - uint32(k)*0x101)
-	r := uint32(0xffff-uint32(c)*0x101) * w / 0xffff
-	g := uint32(0xffff-uint32(m)*0x101) * w / 0xffff
-	b := uint32(0xffff-uint32(y)*0x101) * w / 0xffff
-	return uint8(r >> 8), uint8(g >> 8), uint8(b >> 8)
-}
-
-// CMYK represents a fully opaque CMYK color, having 8 bits for each of cyan,
-// magenta, yellow and black.
-//
-// It is not associated with any particular color profile.
-type CMYK struct {
-	C, M, Y, K uint8
-}
-
-func (c CMYK) RGBA() (uint32, uint32, uint32, uint32) {
-	// This code is a copy of the CMYKToRGB function above, except that it
-	// returns values in the range [0, 0xffff] instead of [0, 0xff].
-
-	w := uint32(0xffff - uint32(c.K)*0x101)
-	r := uint32(0xffff-uint32(c.C)*0x101) * w / 0xffff
-	g := uint32(0xffff-uint32(c.M)*0x101) * w / 0xffff
-	b := uint32(0xffff-uint32(c.Y)*0x101) * w / 0xffff
-	return uint32(r), uint32(g), uint32(b), 0xffff
-}
-
-// CMYKModel is the Model for CMYK colors.
-var CMYKModel Model = ModelFunc(cmykModel)
-
-func cmykModel(c Color) Color {
-	if _, ok := c.(CMYK); ok {
-		return c
-	}
-	r, g, b, _ := c.RGBA()
-	cc, mm, yy, kk := RGBToCMYK(uint8(r>>8), uint8(g>>8), uint8(b>>8))
-	return CMYK{cc, mm, yy, kk}
-}
diff --git a/src/image/color/ycbcr_test.go b/src/image/color/ycbcr_test.go
index 5da49d3..92a0e6f 100644
--- a/src/image/color/ycbcr_test.go
+++ b/src/image/color/ycbcr_test.go
@@ -5,7 +5,6 @@
 package color
 
 import (
-	"fmt"
 	"testing"
 )
 
@@ -16,134 +15,19 @@ func delta(x, y uint8) uint8 {
 	return y - x
 }
 
-func eq(c0, c1 Color) error {
-	r0, g0, b0, a0 := c0.RGBA()
-	r1, g1, b1, a1 := c1.RGBA()
-	if r0 != r1 || g0 != g1 || b0 != b1 || a0 != a1 {
-		return fmt.Errorf("got  0x%04x 0x%04x 0x%04x 0x%04x\nwant 0x%04x 0x%04x 0x%04x 0x%04x",
-			r0, g0, b0, a0, r1, g1, b1, a1)
-	}
-	return nil
-}
-
-// TestYCbCrRoundtrip tests that a subset of RGB space can be converted to YCbCr
-// and back to within 2/256 tolerance.
-func TestYCbCrRoundtrip(t *testing.T) {
-	for r := 0; r < 256; r += 7 {
-		for g := 0; g < 256; g += 5 {
-			for b := 0; b < 256; b += 3 {
+// Test that a subset of RGB space can be converted to YCbCr and back to within
+// 1/256 tolerance.
+func TestRoundtrip(t *testing.T) {
+	for r := 0; r < 255; r += 7 {
+		for g := 0; g < 255; g += 5 {
+			for b := 0; b < 255; b += 3 {
 				r0, g0, b0 := uint8(r), uint8(g), uint8(b)
 				y, cb, cr := RGBToYCbCr(r0, g0, b0)
 				r1, g1, b1 := YCbCrToRGB(y, cb, cr)
-				if delta(r0, r1) > 2 || delta(g0, g1) > 2 || delta(b0, b1) > 2 {
-					t.Fatalf("\nr0, g0, b0 = %d, %d, %d\ny,  cb, cr = %d, %d, %d\nr1, g1, b1 = %d, %d, %d",
-						r0, g0, b0, y, cb, cr, r1, g1, b1)
-				}
-			}
-		}
-	}
-}
-
-// TestYCbCrToRGBConsistency tests that calling the RGBA method (16 bit color)
-// then truncating to 8 bits is equivalent to calling the YCbCrToRGB function (8
-// bit color).
-func TestYCbCrToRGBConsistency(t *testing.T) {
-	for y := 0; y < 256; y += 7 {
-		for cb := 0; cb < 256; cb += 5 {
-			for cr := 0; cr < 256; cr += 3 {
-				x := YCbCr{uint8(y), uint8(cb), uint8(cr)}
-				r0, g0, b0, _ := x.RGBA()
-				r1, g1, b1 := uint8(r0>>8), uint8(g0>>8), uint8(b0>>8)
-				r2, g2, b2 := YCbCrToRGB(x.Y, x.Cb, x.Cr)
-				if r1 != r2 || g1 != g2 || b1 != b2 {
-					t.Fatalf("y, cb, cr = %d, %d, %d\nr1, g1, b1 = %d, %d, %d\nr2, g2, b2 = %d, %d, %d",
-						y, cb, cr, r1, g1, b1, r2, g2, b2)
-				}
-			}
-		}
-	}
-}
-
-// TestYCbCrGray tests that YCbCr colors are a superset of Gray colors.
-func TestYCbCrGray(t *testing.T) {
-	for i := 0; i < 256; i++ {
-		if err := eq(YCbCr{uint8(i), 0x80, 0x80}, Gray{uint8(i)}); err != nil {
-			t.Errorf("i=0x%02x:\n%v", i, err)
-		}
-	}
-}
-
-// TestCMYKRoundtrip tests that a subset of RGB space can be converted to CMYK
-// and back to within 1/256 tolerance.
-func TestCMYKRoundtrip(t *testing.T) {
-	for r := 0; r < 256; r += 7 {
-		for g := 0; g < 256; g += 5 {
-			for b := 0; b < 256; b += 3 {
-				r0, g0, b0 := uint8(r), uint8(g), uint8(b)
-				c, m, y, k := RGBToCMYK(r0, g0, b0)
-				r1, g1, b1 := CMYKToRGB(c, m, y, k)
 				if delta(r0, r1) > 1 || delta(g0, g1) > 1 || delta(b0, b1) > 1 {
-					t.Fatalf("\nr0, g0, b0 = %d, %d, %d\nc, m, y, k = %d, %d, %d, %d\nr1, g1, b1 = %d, %d, %d",
-						r0, g0, b0, c, m, y, k, r1, g1, b1)
+					t.Fatalf("r0, g0, b0 = %d, %d, %d   r1, g1, b1 = %d, %d, %d", r0, g0, b0, r1, g1, b1)
 				}
 			}
 		}
 	}
 }
-
-// TestCMYKToRGBConsistency tests that calling the RGBA method (16 bit color)
-// then truncating to 8 bits is equivalent to calling the CMYKToRGB function (8
-// bit color).
-func TestCMYKToRGBConsistency(t *testing.T) {
-	for c := 0; c < 256; c += 7 {
-		for m := 0; m < 256; m += 5 {
-			for y := 0; y < 256; y += 3 {
-				for k := 0; k < 256; k += 11 {
-					x := CMYK{uint8(c), uint8(m), uint8(y), uint8(k)}
-					r0, g0, b0, _ := x.RGBA()
-					r1, g1, b1 := uint8(r0>>8), uint8(g0>>8), uint8(b0>>8)
-					r2, g2, b2 := CMYKToRGB(x.C, x.M, x.Y, x.K)
-					if r1 != r2 || g1 != g2 || b1 != b2 {
-						t.Fatalf("c, m, y, k = %d, %d, %d, %d\nr1, g1, b1 = %d, %d, %d\nr2, g2, b2 = %d, %d, %d",
-							c, m, y, k, r1, g1, b1, r2, g2, b2)
-					}
-				}
-			}
-		}
-	}
-}
-
-// TestCMYKGray tests that CMYK colors are a superset of Gray colors.
-func TestCMYKGray(t *testing.T) {
-	for i := 0; i < 256; i++ {
-		if err := eq(CMYK{0x00, 0x00, 0x00, uint8(255 - i)}, Gray{uint8(i)}); err != nil {
-			t.Errorf("i=0x%02x:\n%v", i, err)
-		}
-	}
-}
-
-func TestPalette(t *testing.T) {
-	p := Palette{
-		RGBA{0xff, 0xff, 0xff, 0xff},
-		RGBA{0x80, 0x00, 0x00, 0xff},
-		RGBA{0x7f, 0x00, 0x00, 0x7f},
-		RGBA{0x00, 0x00, 0x00, 0x7f},
-		RGBA{0x00, 0x00, 0x00, 0x00},
-		RGBA{0x40, 0x40, 0x40, 0x40},
-	}
-	// Check that, for a Palette with no repeated colors, the closest color to
-	// each element is itself.
-	for i, c := range p {
-		j := p.Index(c)
-		if i != j {
-			t.Errorf("Index(%v): got %d (color = %v), want %d", c, j, p[j], i)
-		}
-	}
-	// Check that finding the closest color considers alpha, not just red,
-	// green and blue.
-	got := p.Convert(RGBA{0x80, 0x00, 0x00, 0x80})
-	want := RGBA{0x7f, 0x00, 0x00, 0x7f}
-	if got != want {
-		t.Errorf("got %v, want %v", got, want)
-	}
-}
diff --git a/src/image/decode_example_test.go b/src/image/decode_example_test.go
index 81fa037..21e90fe 100644
--- a/src/image/decode_example_test.go
+++ b/src/image/decode_example_test.go
@@ -61,22 +61,22 @@ func Example() {
 	}
 	// Output:
 	// bin               red  green   blue  alpha
-	// 0x0000-0x0fff:    364    790   7242      0
-	// 0x1000-0x1fff:    645   2967   1039      0
-	// 0x2000-0x2fff:   1072   2299    979      0
-	// 0x3000-0x3fff:    820   2266    980      0
-	// 0x4000-0x4fff:    537   1305    541      0
-	// 0x5000-0x5fff:    319    962    261      0
-	// 0x6000-0x6fff:    322    375    177      0
-	// 0x7000-0x7fff:    601    279    214      0
-	// 0x8000-0x8fff:   3478    227    273      0
-	// 0x9000-0x9fff:   2260    234    329      0
-	// 0xa000-0xafff:    921    282    373      0
-	// 0xb000-0xbfff:    321    335    397      0
-	// 0xc000-0xcfff:    229    388    298      0
-	// 0xd000-0xdfff:    260    414    277      0
-	// 0xe000-0xefff:    516    428    298      0
-	// 0xf000-0xffff:   2785   1899   1772  15450
+	// 0x0000-0x0fff:    353    759   7228      0
+	// 0x1000-0x1fff:    629   2944   1036      0
+	// 0x2000-0x2fff:   1075   2319    984      0
+	// 0x3000-0x3fff:    838   2291    988      0
+	// 0x4000-0x4fff:    540   1302    542      0
+	// 0x5000-0x5fff:    319    971    263      0
+	// 0x6000-0x6fff:    316    377    178      0
+	// 0x7000-0x7fff:    581    280    216      0
+	// 0x8000-0x8fff:   3457    228    274      0
+	// 0x9000-0x9fff:   2294    237    334      0
+	// 0xa000-0xafff:    938    283    370      0
+	// 0xb000-0xbfff:    322    338    401      0
+	// 0xc000-0xcfff:    229    386    295      0
+	// 0xd000-0xdfff:    263    416    281      0
+	// 0xe000-0xefff:    538    433    312      0
+	// 0xf000-0xffff:   2758   1886   1748  15450
 }
 
 const data = `
diff --git a/src/image/decode_test.go b/src/image/decode_test.go
index d16ef8a..8dee57e 100644
--- a/src/image/decode_test.go
+++ b/src/image/decode_test.go
@@ -6,7 +6,6 @@ package image_test
 
 import (
 	"bufio"
-	"fmt"
 	"image"
 	"image/color"
 	"os"
@@ -33,9 +32,6 @@ var imageTests = []imageTest{
 	// JPEG is a lossy format and hence needs a non-zero tolerance.
 	{"testdata/video-001.png", "testdata/video-001.jpeg", 8 << 8},
 	{"testdata/video-001.png", "testdata/video-001.progressive.jpeg", 8 << 8},
-	{"testdata/video-001.221212.png", "testdata/video-001.221212.jpeg", 8 << 8},
-	{"testdata/video-001.cmyk.png", "testdata/video-001.cmyk.jpeg", 8 << 8},
-	{"testdata/video-001.rgb.png", "testdata/video-001.rgb.jpeg", 8 << 8},
 	// Grayscale images.
 	{"testdata/video-005.gray.png", "testdata/video-005.gray.jpeg", 8 << 8},
 	{"testdata/video-005.gray.png", "testdata/video-005.gray.png", 0},
@@ -78,11 +74,6 @@ func withinTolerance(c0, c1 color.Color, tolerance int) bool {
 }
 
 func TestDecode(t *testing.T) {
-	rgba := func(c color.Color) string {
-		r, g, b, a := c.RGBA()
-		return fmt.Sprintf("rgba = 0x%04x, 0x%04x, 0x%04x, 0x%04x for %T%v", r, g, b, a, c, c)
-	}
-
 	golden := make(map[string]image.Image)
 loop:
 	for _, it := range imageTests {
@@ -103,14 +94,13 @@ loop:
 		}
 		b := g.Bounds()
 		if !b.Eq(m.Bounds()) {
-			t.Errorf("%s: got bounds %v want %v", it.filename, m.Bounds(), b)
+			t.Errorf("%s: want bounds %v got %v", it.filename, b, m.Bounds())
 			continue loop
 		}
 		for y := b.Min.Y; y < b.Max.Y; y++ {
 			for x := b.Min.X; x < b.Max.X; x++ {
 				if !withinTolerance(g.At(x, y), m.At(x, y), it.tolerance) {
-					t.Errorf("%s: at (%d, %d):\ngot  %v\nwant %v",
-						it.filename, x, y, rgba(m.At(x, y)), rgba(g.At(x, y)))
+					t.Errorf("%s: at (%d, %d), want %v got %v", it.filename, x, y, g.At(x, y), m.At(x, y))
 					continue loop
 				}
 			}
diff --git a/src/image/draw/bench_test.go b/src/image/draw/bench_test.go
index 7b89f95..cc62e25 100644
--- a/src/image/draw/bench_test.go
+++ b/src/image/draw/bench_test.go
@@ -7,7 +7,6 @@ package draw
 import (
 	"image"
 	"image/color"
-	"reflect"
 	"testing"
 )
 
@@ -16,11 +15,6 @@ const (
 	srcw, srch = 400, 300
 )
 
-var palette = color.Palette{
-	color.Black,
-	color.White,
-}
-
 // bench benchmarks drawing src and mask images onto a dst image with the
 // given op and the color models to create those images from.
 // The created images' pixels are initialized to non-zero values.
@@ -56,48 +50,13 @@ func bench(b *testing.B, dcm, scm, mcm color.Model, op Op) {
 		}
 		dst = dst1
 	default:
-		// The == operator isn't defined on a color.Palette (a slice), so we
-		// use reflection.
-		if reflect.DeepEqual(dcm, palette) {
-			dst1 := image.NewPaletted(image.Rect(0, 0, dstw, dsth), palette)
-			for y := 0; y < dsth; y++ {
-				for x := 0; x < dstw; x++ {
-					dst1.SetColorIndex(x, y, uint8(x^y)&1)
-				}
-			}
-			dst = dst1
-		} else {
-			b.Fatal("unknown destination color model", dcm)
-		}
+		b.Fatal("unknown destination color model", dcm)
 	}
 
 	var src image.Image
 	switch scm {
 	case nil:
 		src = &image.Uniform{C: color.RGBA{0x11, 0x22, 0x33, 0xff}}
-	case color.CMYKModel:
-		src1 := image.NewCMYK(image.Rect(0, 0, srcw, srch))
-		for y := 0; y < srch; y++ {
-			for x := 0; x < srcw; x++ {
-				src1.SetCMYK(x, y, color.CMYK{
-					uint8(13 * x % 0x100),
-					uint8(11 * y % 0x100),
-					uint8((11*x + 13*y) % 0x100),
-					uint8((31*x + 37*y) % 0x100),
-				})
-			}
-		}
-		src = src1
-	case color.GrayModel:
-		src1 := image.NewGray(image.Rect(0, 0, srcw, srch))
-		for y := 0; y < srch; y++ {
-			for x := 0; x < srcw; x++ {
-				src1.SetGray(x, y, color.Gray{
-					uint8((11*x + 13*y) % 0x100),
-				})
-			}
-		}
-		src = src1
 	case color.RGBAModel:
 		src1 := image.NewRGBA(image.Rect(0, 0, srcw, srch))
 		for y := 0; y < srch; y++ {
@@ -220,14 +179,6 @@ func BenchmarkYCbCr(b *testing.B) {
 	bench(b, color.RGBAModel, color.YCbCrModel, nil, Over)
 }
 
-func BenchmarkGray(b *testing.B) {
-	bench(b, color.RGBAModel, color.GrayModel, nil, Over)
-}
-
-func BenchmarkCMYK(b *testing.B) {
-	bench(b, color.RGBAModel, color.CMYKModel, nil, Over)
-}
-
 func BenchmarkGlyphOver(b *testing.B) {
 	bench(b, color.RGBAModel, nil, color.AlphaModel, Over)
 }
@@ -236,10 +187,6 @@ func BenchmarkRGBA(b *testing.B) {
 	bench(b, color.RGBAModel, color.RGBA64Model, nil, Src)
 }
 
-func BenchmarkPaletted(b *testing.B) {
-	bench(b, palette, color.RGBAModel, nil, Src)
-}
-
 // The BenchmarkGenericFoo functions exercise the generic, slow-path code.
 
 func BenchmarkGenericOver(b *testing.B) {
diff --git a/src/image/draw/clip_test.go b/src/image/draw/clip_test.go
index 0abf53e..65381f7 100644
--- a/src/image/draw/clip_test.go
+++ b/src/image/draw/clip_test.go
@@ -139,19 +139,7 @@ var clipTests = []clipTest{
 		image.Pt(20, 0),
 		image.Pt(20, 0),
 	},
-	{
-		"clip sr and mr",
-		image.Rect(0, 0, 100, 100),
-		image.Rect(0, 0, 100, 100),
-		image.Rect(23, 23, 55, 86),
-		image.Rect(44, 44, 87, 58),
-		image.Pt(10, 10),
-		image.Pt(11, 11),
-		false,
-		image.Rect(33, 33, 45, 47),
-		image.Pt(43, 43),
-		image.Pt(44, 44),
-	},
+	// TODO(nigeltao): write more tests.
 }
 
 func TestClip(t *testing.T) {
@@ -161,12 +149,12 @@ func TestClip(t *testing.T) {
 	for _, c := range clipTests {
 		dst := dst0.SubImage(c.dr).(*image.RGBA)
 		src := src0.SubImage(c.sr).(*image.RGBA)
-		r, sp, mp := c.r, c.sp, c.mp
-		if c.nilMask {
-			clip(dst, &r, src, &sp, nil, nil)
-		} else {
-			clip(dst, &r, src, &sp, mask0.SubImage(c.mr), &mp)
+		var mask image.Image
+		if !c.nilMask {
+			mask = mask0.SubImage(c.mr)
 		}
+		r, sp, mp := c.r, c.sp, c.mp
+		clip(dst, &r, src, &sp, mask, &mp)
 
 		// Check that the actual results equal the expected results.
 		if !c.r0.Eq(r) {
@@ -185,17 +173,17 @@ func TestClip(t *testing.T) {
 		}
 
 		// Check that the clipped rectangle is contained by the dst / src / mask
-		// rectangles, in their respective coordinate spaces.
+		// rectangles, in their respective co-ordinate spaces.
 		if !r.In(c.dr) {
 			t.Errorf("%s: c.dr %v does not contain r %v", c.desc, c.dr, r)
 		}
-		// sr is r translated into src's coordinate space.
+		// sr is r translated into src's co-ordinate space.
 		sr := r.Add(c.sp.Sub(c.dr.Min))
 		if !sr.In(c.sr) {
 			t.Errorf("%s: c.sr %v does not contain sr %v", c.desc, c.sr, sr)
 		}
 		if !c.nilMask {
-			// mr is r translated into mask's coordinate space.
+			// mr is r translated into mask's co-ordinate space.
 			mr := r.Add(c.mp.Sub(c.dr.Min))
 			if !mr.In(c.mr) {
 				t.Errorf("%s: c.mr %v does not contain mr %v", c.desc, c.mr, mr)
diff --git a/src/image/draw/draw.go b/src/image/draw/draw.go
index 9419d5e..661230e 100644
--- a/src/image/draw/draw.go
+++ b/src/image/draw/draw.go
@@ -5,13 +5,12 @@
 // Package draw provides image composition functions.
 //
 // See "The Go image/draw package" for an introduction to this package:
-// https://golang.org/doc/articles/image_draw.html
+// http://golang.org/doc/articles/image_draw.html
 package draw
 
 import (
 	"image"
 	"image/color"
-	"image/internal/imageutil"
 )
 
 // m is the maximum color value returned by image.Color.RGBA.
@@ -68,7 +67,7 @@ func (floydSteinberg) Draw(dst Image, r image.Rectangle, src image.Image, sp ima
 }
 
 // clip clips r against each image's bounds (after translating into the
-// destination image's coordinate space) and shifts the points sp and mp by
+// destination image's co-ordinate space) and shifts the points sp and mp by
 // the same amount as the change in r.Min.
 func clip(dst Image, r *image.Rectangle, src image.Image, sp *image.Point, mask image.Image, mp *image.Point) {
 	orig := r.Min
@@ -82,12 +81,10 @@ func clip(dst Image, r *image.Rectangle, src image.Image, sp *image.Point, mask
 	if dx == 0 && dy == 0 {
 		return
 	}
-	sp.X += dx
-	sp.Y += dy
-	if mp != nil {
-		mp.X += dx
-		mp.Y += dy
-	}
+	(*sp).X += dx
+	(*sp).Y += dy
+	(*mp).X += dx
+	(*mp).Y += dy
 }
 
 func processBackward(dst Image, r image.Rectangle, src image.Image, sp image.Point) bool {
@@ -125,19 +122,9 @@ func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mas
 					drawNRGBAOver(dst0, r, src0, sp)
 					return
 				case *image.YCbCr:
-					// An image.YCbCr is always fully opaque, and so if the
-					// mask is nil (i.e. fully opaque) then the op is
-					// effectively always Src. Similarly for image.Gray and
-					// image.CMYK.
-					if imageutil.DrawYCbCr(dst0, r, src0, sp) {
+					if drawYCbCr(dst0, r, src0, sp) {
 						return
 					}
-				case *image.Gray:
-					drawGray(dst0, r, src0, sp)
-					return
-				case *image.CMYK:
-					drawCMYK(dst0, r, src0, sp)
-					return
 				}
 			} else if mask0, ok := mask.(*image.Alpha); ok {
 				switch src0 := src.(type) {
@@ -159,15 +146,9 @@ func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mas
 					drawNRGBASrc(dst0, r, src0, sp)
 					return
 				case *image.YCbCr:
-					if imageutil.DrawYCbCr(dst0, r, src0, sp) {
+					if drawYCbCr(dst0, r, src0, sp) {
 						return
 					}
-				case *image.Gray:
-					drawGray(dst0, r, src0, sp)
-					return
-				case *image.CMYK:
-					drawCMYK(dst0, r, src0, sp)
-					return
 				}
 			}
 		}
@@ -176,7 +157,6 @@ func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mas
 	case *image.Paletted:
 		if op == Src && mask == nil && !processBackward(dst, r, src, sp) {
 			drawPaletted(dst0, r, src, sp, false)
-			return
 		}
 	}
 
@@ -257,20 +237,16 @@ func drawFillOver(dst *image.RGBA, r image.Rectangle, src *image.Uniform) {
 
 func drawFillSrc(dst *image.RGBA, r image.Rectangle, src *image.Uniform) {
 	sr, sg, sb, sa := src.RGBA()
-	sr8 := uint8(sr >> 8)
-	sg8 := uint8(sg >> 8)
-	sb8 := uint8(sb >> 8)
-	sa8 := uint8(sa >> 8)
 	// The built-in copy function is faster than a straightforward for loop to fill the destination with
 	// the color, but copy requires a slice source. We therefore use a for loop to fill the first row, and
 	// then use the first row as the slice source for the remaining rows.
 	i0 := dst.PixOffset(r.Min.X, r.Min.Y)
 	i1 := i0 + r.Dx()*4
 	for i := i0; i < i1; i += 4 {
-		dst.Pix[i+0] = sr8
-		dst.Pix[i+1] = sg8
-		dst.Pix[i+2] = sb8
-		dst.Pix[i+3] = sa8
+		dst.Pix[i+0] = uint8(sr >> 8)
+		dst.Pix[i+1] = uint8(sg >> 8)
+		dst.Pix[i+2] = uint8(sb >> 8)
+		dst.Pix[i+3] = uint8(sa >> 8)
 	}
 	firstRow := dst.Pix[i0:i1]
 	for y := r.Min.Y + 1; y < r.Max.Y; y++ {
@@ -337,11 +313,9 @@ func drawCopySrc(dst *image.RGBA, r image.Rectangle, src *image.RGBA, sp image.P
 		ddelta = dst.Stride
 		sdelta = src.Stride
 	} else {
-		// If the source start point is higher than the destination start
-		// point, then we compose the rows in bottom-up order instead of
-		// top-down. Unlike the drawCopyOver function, we don't have to check
-		// the x coordinates because the built-in copy function can handle
-		// overlapping slices.
+		// If the source start point is higher than the destination start point, then we compose the rows
+		// in bottom-up order instead of top-down. Unlike the drawCopyOver function, we don't have to
+		// check the x co-ordinates because the built-in copy function can handle overlapping slices.
 		d0 += (dy - 1) * dst.Stride
 		s0 += (dy - 1) * src.Stride
 		ddelta = -dst.Stride
@@ -416,46 +390,72 @@ func drawNRGBASrc(dst *image.RGBA, r image.Rectangle, src *image.NRGBA, sp image
 	}
 }
 
-func drawGray(dst *image.RGBA, r image.Rectangle, src *image.Gray, sp image.Point) {
-	i0 := (r.Min.X - dst.Rect.Min.X) * 4
-	i1 := (r.Max.X - dst.Rect.Min.X) * 4
-	si0 := (sp.X - src.Rect.Min.X) * 1
-	yMax := r.Max.Y - dst.Rect.Min.Y
-
-	y := r.Min.Y - dst.Rect.Min.Y
-	sy := sp.Y - src.Rect.Min.Y
-	for ; y != yMax; y, sy = y+1, sy+1 {
-		dpix := dst.Pix[y*dst.Stride:]
-		spix := src.Pix[sy*src.Stride:]
-
-		for i, si := i0, si0; i < i1; i, si = i+4, si+1 {
-			p := spix[si]
-			dpix[i+0] = p
-			dpix[i+1] = p
-			dpix[i+2] = p
-			dpix[i+3] = 255
+func drawYCbCr(dst *image.RGBA, r image.Rectangle, src *image.YCbCr, sp image.Point) (ok bool) {
+	// An image.YCbCr is always fully opaque, and so if the mask is implicitly nil
+	// (i.e. fully opaque) then the op is effectively always Src.
+	x0 := (r.Min.X - dst.Rect.Min.X) * 4
+	x1 := (r.Max.X - dst.Rect.Min.X) * 4
+	y0 := r.Min.Y - dst.Rect.Min.Y
+	y1 := r.Max.Y - dst.Rect.Min.Y
+	switch src.SubsampleRatio {
+	case image.YCbCrSubsampleRatio444:
+		for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 {
+			dpix := dst.Pix[y*dst.Stride:]
+			yi := (sy-src.Rect.Min.Y)*src.YStride + (sp.X - src.Rect.Min.X)
+			ci := (sy-src.Rect.Min.Y)*src.CStride + (sp.X - src.Rect.Min.X)
+			for x := x0; x != x1; x, yi, ci = x+4, yi+1, ci+1 {
+				rr, gg, bb := color.YCbCrToRGB(src.Y[yi], src.Cb[ci], src.Cr[ci])
+				dpix[x+0] = rr
+				dpix[x+1] = gg
+				dpix[x+2] = bb
+				dpix[x+3] = 255
+			}
 		}
-	}
-}
-
-func drawCMYK(dst *image.RGBA, r image.Rectangle, src *image.CMYK, sp image.Point) {
-	i0 := (r.Min.X - dst.Rect.Min.X) * 4
-	i1 := (r.Max.X - dst.Rect.Min.X) * 4
-	si0 := (sp.X - src.Rect.Min.X) * 4
-	yMax := r.Max.Y - dst.Rect.Min.Y
-
-	y := r.Min.Y - dst.Rect.Min.Y
-	sy := sp.Y - src.Rect.Min.Y
-	for ; y != yMax; y, sy = y+1, sy+1 {
-		dpix := dst.Pix[y*dst.Stride:]
-		spix := src.Pix[sy*src.Stride:]
-
-		for i, si := i0, si0; i < i1; i, si = i+4, si+4 {
-			dpix[i+0], dpix[i+1], dpix[i+2] =
-				color.CMYKToRGB(spix[si+0], spix[si+1], spix[si+2], spix[si+3])
-			dpix[i+3] = 255
+	case image.YCbCrSubsampleRatio422:
+		for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 {
+			dpix := dst.Pix[y*dst.Stride:]
+			yi := (sy-src.Rect.Min.Y)*src.YStride + (sp.X - src.Rect.Min.X)
+			ciBase := (sy-src.Rect.Min.Y)*src.CStride - src.Rect.Min.X/2
+			for x, sx := x0, sp.X; x != x1; x, sx, yi = x+4, sx+1, yi+1 {
+				ci := ciBase + sx/2
+				rr, gg, bb := color.YCbCrToRGB(src.Y[yi], src.Cb[ci], src.Cr[ci])
+				dpix[x+0] = rr
+				dpix[x+1] = gg
+				dpix[x+2] = bb
+				dpix[x+3] = 255
+			}
+		}
+	case image.YCbCrSubsampleRatio420:
+		for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 {
+			dpix := dst.Pix[y*dst.Stride:]
+			yi := (sy-src.Rect.Min.Y)*src.YStride + (sp.X - src.Rect.Min.X)
+			ciBase := (sy/2-src.Rect.Min.Y/2)*src.CStride - src.Rect.Min.X/2
+			for x, sx := x0, sp.X; x != x1; x, sx, yi = x+4, sx+1, yi+1 {
+				ci := ciBase + sx/2
+				rr, gg, bb := color.YCbCrToRGB(src.Y[yi], src.Cb[ci], src.Cr[ci])
+				dpix[x+0] = rr
+				dpix[x+1] = gg
+				dpix[x+2] = bb
+				dpix[x+3] = 255
+			}
+		}
+	case image.YCbCrSubsampleRatio440:
+		for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 {
+			dpix := dst.Pix[y*dst.Stride:]
+			yi := (sy-src.Rect.Min.Y)*src.YStride + (sp.X - src.Rect.Min.X)
+			ci := (sy/2-src.Rect.Min.Y/2)*src.CStride + (sp.X - src.Rect.Min.X)
+			for x := x0; x != x1; x, yi, ci = x+4, yi+1, ci+1 {
+				rr, gg, bb := color.YCbCrToRGB(src.Y[yi], src.Cb[ci], src.Cr[ci])
+				dpix[x+0] = rr
+				dpix[x+1] = gg
+				dpix[x+2] = bb
+				dpix[x+3] = 255
+			}
 		}
+	default:
+		return false
 	}
+	return true
 }
 
 func drawGlyphOver(dst *image.RGBA, r image.Rectangle, src *image.Uniform, mask *image.Alpha, mp image.Point) {
@@ -555,20 +555,6 @@ func clamp(i int32) int32 {
 	return i
 }
 
-// sqDiff returns the squared-difference of x and y, shifted by 2 so that
-// adding four of those won't overflow a uint32.
-//
-// x and y are both assumed to be in the range [0, 0xffff].
-func sqDiff(x, y int32) uint32 {
-	var d uint32
-	if x > y {
-		d = uint32(x - y)
-	} else {
-		d = uint32(y - x)
-	}
-	return (d * d) >> 2
-}
-
 func drawPaletted(dst Image, r image.Rectangle, src image.Image, sp image.Point, floydSteinberg bool) {
 	// TODO(nigeltao): handle the case where the dst and src overlap.
 	// Does it even make sense to try and do Floyd-Steinberg whilst
@@ -578,15 +564,14 @@ func drawPaletted(dst Image, r image.Rectangle, src image.Image, sp image.Point,
 	// dst.At. The dst.Set equivalent is a batch version of the algorithm
 	// used by color.Palette's Index method in image/color/color.go, plus
 	// optional Floyd-Steinberg error diffusion.
-	palette, pix, stride := [][4]int32(nil), []byte(nil), 0
+	palette, pix, stride := [][3]int32(nil), []byte(nil), 0
 	if p, ok := dst.(*image.Paletted); ok {
-		palette = make([][4]int32, len(p.Palette))
+		palette = make([][3]int32, len(p.Palette))
 		for i, col := range p.Palette {
-			r, g, b, a := col.RGBA()
+			r, g, b, _ := col.RGBA()
 			palette[i][0] = int32(r)
 			palette[i][1] = int32(g)
 			palette[i][2] = int32(b)
-			palette[i][3] = int32(a)
 		}
 		pix, stride = p.Pix[p.PixOffset(r.Min.X, r.Min.Y):], p.Stride
 	}
@@ -594,10 +579,10 @@ func drawPaletted(dst Image, r image.Rectangle, src image.Image, sp image.Point,
 	// quantErrorCurr and quantErrorNext are the Floyd-Steinberg quantization
 	// errors that have been propagated to the pixels in the current and next
 	// rows. The +2 simplifies calculation near the edges.
-	var quantErrorCurr, quantErrorNext [][4]int32
+	var quantErrorCurr, quantErrorNext [][3]int32
 	if floydSteinberg {
-		quantErrorCurr = make([][4]int32, r.Dx()+2)
-		quantErrorNext = make([][4]int32, r.Dx()+2)
+		quantErrorCurr = make([][3]int32, r.Dx()+2)
+		quantErrorNext = make([][3]int32, r.Dx()+2)
 	}
 
 	// Loop over each source pixel.
@@ -606,25 +591,30 @@ func drawPaletted(dst Image, r image.Rectangle, src image.Image, sp image.Point,
 		for x := 0; x != r.Dx(); x++ {
 			// er, eg and eb are the pixel's R,G,B values plus the
 			// optional Floyd-Steinberg error.
-			sr, sg, sb, sa := src.At(sp.X+x, sp.Y+y).RGBA()
-			er, eg, eb, ea := int32(sr), int32(sg), int32(sb), int32(sa)
+			sr, sg, sb, _ := src.At(sp.X+x, sp.Y+y).RGBA()
+			er, eg, eb := int32(sr), int32(sg), int32(sb)
 			if floydSteinberg {
 				er = clamp(er + quantErrorCurr[x+1][0]/16)
 				eg = clamp(eg + quantErrorCurr[x+1][1]/16)
 				eb = clamp(eb + quantErrorCurr[x+1][2]/16)
-				ea = clamp(ea + quantErrorCurr[x+1][3]/16)
 			}
 
 			if palette != nil {
-				// Find the closest palette color in Euclidean R,G,B,A space:
-				// the one that minimizes sum-squared-difference.
+				// Find the closest palette color in Euclidean R,G,B space: the
+				// one that minimizes sum-squared-difference. We shift by 1 bit
+				// to avoid potential uint32 overflow in sum-squared-difference.
 				// TODO(nigeltao): consider smarter algorithms.
-				bestIndex, bestSum := 0, uint32(1<<32-1)
+				bestIndex, bestSSD := 0, uint32(1<<32-1)
 				for index, p := range palette {
-					sum := sqDiff(er, p[0]) + sqDiff(eg, p[1]) + sqDiff(eb, p[2]) + sqDiff(ea, p[3])
-					if sum < bestSum {
-						bestIndex, bestSum = index, sum
-						if sum == 0 {
+					delta := (er - p[0]) >> 1
+					ssd := uint32(delta * delta)
+					delta = (eg - p[1]) >> 1
+					ssd += uint32(delta * delta)
+					delta = (eb - p[2]) >> 1
+					ssd += uint32(delta * delta)
+					if ssd < bestSSD {
+						bestIndex, bestSSD = index, ssd
+						if ssd == 0 {
 							break
 						}
 					}
@@ -637,13 +627,11 @@ func drawPaletted(dst Image, r image.Rectangle, src image.Image, sp image.Point,
 				er -= int32(palette[bestIndex][0])
 				eg -= int32(palette[bestIndex][1])
 				eb -= int32(palette[bestIndex][2])
-				ea -= int32(palette[bestIndex][3])
 
 			} else {
 				out.R = uint16(er)
 				out.G = uint16(eg)
 				out.B = uint16(eb)
-				out.A = uint16(ea)
 				// The third argument is &out instead of out (and out is
 				// declared outside of the inner loop) to avoid the implicit
 				// conversion to color.Color here allocating memory in the
@@ -653,37 +641,32 @@ func drawPaletted(dst Image, r image.Rectangle, src image.Image, sp image.Point,
 				if !floydSteinberg {
 					continue
 				}
-				sr, sg, sb, sa = dst.At(r.Min.X+x, r.Min.Y+y).RGBA()
+				sr, sg, sb, _ = dst.At(r.Min.X+x, r.Min.Y+y).RGBA()
 				er -= int32(sr)
 				eg -= int32(sg)
 				eb -= int32(sb)
-				ea -= int32(sa)
 			}
 
 			// Propagate the Floyd-Steinberg quantization error.
 			quantErrorNext[x+0][0] += er * 3
 			quantErrorNext[x+0][1] += eg * 3
 			quantErrorNext[x+0][2] += eb * 3
-			quantErrorNext[x+0][3] += ea * 3
 			quantErrorNext[x+1][0] += er * 5
 			quantErrorNext[x+1][1] += eg * 5
 			quantErrorNext[x+1][2] += eb * 5
-			quantErrorNext[x+1][3] += ea * 5
 			quantErrorNext[x+2][0] += er * 1
 			quantErrorNext[x+2][1] += eg * 1
 			quantErrorNext[x+2][2] += eb * 1
-			quantErrorNext[x+2][3] += ea * 1
 			quantErrorCurr[x+2][0] += er * 7
 			quantErrorCurr[x+2][1] += eg * 7
 			quantErrorCurr[x+2][2] += eb * 7
-			quantErrorCurr[x+2][3] += ea * 7
 		}
 
 		// Recycle the quantization error buffers.
 		if floydSteinberg {
 			quantErrorCurr, quantErrorNext = quantErrorNext, quantErrorCurr
 			for i := range quantErrorNext {
-				quantErrorNext[i] = [4]int32{}
+				quantErrorNext[i] = [3]int32{}
 			}
 		}
 	}
diff --git a/src/image/draw/draw_test.go b/src/image/draw/draw_test.go
index a58f0f4..0dd7fbd 100644
--- a/src/image/draw/draw_test.go
+++ b/src/image/draw/draw_test.go
@@ -74,26 +74,6 @@ func vgradCr() image.Image {
 	return m
 }
 
-func vgradGray() image.Image {
-	m := image.NewGray(image.Rect(0, 0, 16, 16))
-	for y := 0; y < 16; y++ {
-		for x := 0; x < 16; x++ {
-			m.Set(x, y, color.Gray{uint8(y * 0x11)})
-		}
-	}
-	return m
-}
-
-func vgradMagenta() image.Image {
-	m := image.NewCMYK(image.Rect(0, 0, 16, 16))
-	for y := 0; y < 16; y++ {
-		for x := 0; x < 16; x++ {
-			m.Set(x, y, color.CMYK{0, uint8(y * 0x11), 0, 0x3f})
-		}
-	}
-	return m
-}
-
 func hgradRed(alpha int) Image {
 	m := image.NewRGBA(image.Rect(0, 0, 16, 16))
 	for y := 0; y < 16; y++ {
@@ -167,26 +147,6 @@ var drawTests = []drawTest{
 	{"ycbcrAlphaSrc", vgradCr(), fillAlpha(192), Src, color.RGBA{8, 28, 0, 192}},
 	{"ycbcrNil", vgradCr(), nil, Over, color.RGBA{11, 38, 0, 255}},
 	{"ycbcrNilSrc", vgradCr(), nil, Src, color.RGBA{11, 38, 0, 255}},
-	// Uniform mask (100%, 75%, nil) and variable Gray source.
-	// At (x, y) == (8, 8):
-	// The destination pixel is {136, 0, 0, 255}.
-	// The source pixel is {136} in Gray-space, which is {136, 136, 136, 255} in RGBA-space.
-	{"gray", vgradGray(), fillAlpha(255), Over, color.RGBA{136, 136, 136, 255}},
-	{"graySrc", vgradGray(), fillAlpha(255), Src, color.RGBA{136, 136, 136, 255}},
-	{"grayAlpha", vgradGray(), fillAlpha(192), Over, color.RGBA{136, 102, 102, 255}},
-	{"grayAlphaSrc", vgradGray(), fillAlpha(192), Src, color.RGBA{102, 102, 102, 192}},
-	{"grayNil", vgradGray(), nil, Over, color.RGBA{136, 136, 136, 255}},
-	{"grayNilSrc", vgradGray(), nil, Src, color.RGBA{136, 136, 136, 255}},
-	// Uniform mask (100%, 75%, nil) and variable CMYK source.
-	// At (x, y) == (8, 8):
-	// The destination pixel is {136, 0, 0, 255}.
-	// The source pixel is {0, 136, 0, 63} in CMYK-space, which is {192, 89, 192} in RGB-space.
-	{"cmyk", vgradMagenta(), fillAlpha(255), Over, color.RGBA{192, 89, 192, 255}},
-	{"cmykSrc", vgradMagenta(), fillAlpha(255), Src, color.RGBA{192, 89, 192, 255}},
-	{"cmykAlpha", vgradMagenta(), fillAlpha(192), Over, color.RGBA{178, 67, 145, 255}},
-	{"cmykAlphaSrc", vgradMagenta(), fillAlpha(192), Src, color.RGBA{145, 67, 145, 192}},
-	{"cmykNil", vgradMagenta(), nil, Over, color.RGBA{192, 89, 192, 255}},
-	{"cmykNilSrc", vgradMagenta(), nil, Src, color.RGBA{192, 89, 192, 255}},
 	// Variable mask and variable source.
 	// At (x, y) == (8, 8):
 	// The destination pixel is {136, 0, 0, 255}.
diff --git a/src/image/geom.go b/src/image/geom.go
index e1cd4dc..6ebaf67 100644
--- a/src/image/geom.go
+++ b/src/image/geom.go
@@ -5,7 +5,6 @@
 package image
 
 import (
-	"image/color"
 	"strconv"
 )
 
@@ -63,7 +62,7 @@ func (p Point) Mod(r Rectangle) Point {
 
 // Eq reports whether p and q are equal.
 func (p Point) Eq(q Point) bool {
-	return p == q
+	return p.X == q.X && p.Y == q.Y
 }
 
 // ZP is the zero Point.
@@ -78,10 +77,6 @@ func Pt(X, Y int) Point {
 // It is well-formed if Min.X <= Max.X and likewise for Y. Points are always
 // well-formed. A rectangle's methods always return well-formed outputs for
 // well-formed inputs.
-//
-// A Rectangle is also an Image whose bounds are the rectangle itself. At
-// returns color.Opaque for points in the rectangle and color.Transparent
-// otherwise.
 type Rectangle struct {
 	Min, Max Point
 }
@@ -169,12 +164,6 @@ func (r Rectangle) Intersect(s Rectangle) Rectangle {
 
 // Union returns the smallest rectangle that contains both r and s.
 func (r Rectangle) Union(s Rectangle) Rectangle {
-	if r.Empty() {
-		return s
-	}
-	if s.Empty() {
-		return r
-	}
 	if r.Min.X > s.Min.X {
 		r.Min.X = s.Min.X
 	}
@@ -195,16 +184,15 @@ func (r Rectangle) Empty() bool {
 	return r.Min.X >= r.Max.X || r.Min.Y >= r.Max.Y
 }
 
-// Eq reports whether r and s contain the same set of points. All empty
-// rectangles are considered equal.
+// Eq reports whether r and s are equal.
 func (r Rectangle) Eq(s Rectangle) bool {
-	return r == s || r.Empty() && s.Empty()
+	return r.Min.X == s.Min.X && r.Min.Y == s.Min.Y &&
+		r.Max.X == s.Max.X && r.Max.Y == s.Max.Y
 }
 
 // Overlaps reports whether r and s have a non-empty intersection.
 func (r Rectangle) Overlaps(s Rectangle) bool {
-	return !r.Empty() && !s.Empty() &&
-		r.Min.X < s.Max.X && s.Min.X < r.Max.X &&
+	return r.Min.X < s.Max.X && s.Min.X < r.Max.X &&
 		r.Min.Y < s.Max.Y && s.Min.Y < r.Max.Y
 }
 
@@ -231,30 +219,10 @@ func (r Rectangle) Canon() Rectangle {
 	return r
 }
 
-// At implements the Image interface.
-func (r Rectangle) At(x, y int) color.Color {
-	if (Point{x, y}).In(r) {
-		return color.Opaque
-	}
-	return color.Transparent
-}
-
-// Bounds implements the Image interface.
-func (r Rectangle) Bounds() Rectangle {
-	return r
-}
-
-// ColorModel implements the Image interface.
-func (r Rectangle) ColorModel() color.Model {
-	return color.Alpha16Model
-}
-
 // ZR is the zero Rectangle.
 var ZR Rectangle
 
-// Rect is shorthand for Rectangle{Pt(x0, y0), Pt(x1, y1)}. The returned
-// rectangle has minimum and maximum coordinates swapped if necessary so that
-// it is well-formed.
+// Rect is shorthand for Rectangle{Pt(x0, y0), Pt(x1, y1)}.
 func Rect(x0, y0, x1, y1 int) Rectangle {
 	if x0 > x1 {
 		x0, x1 = x1, x0
diff --git a/src/image/gif/reader.go b/src/image/gif/reader.go
index 6a13312..5a863e2 100644
--- a/src/image/gif/reader.go
+++ b/src/image/gif/reader.go
@@ -32,20 +32,15 @@ type reader interface {
 // Masks etc.
 const (
 	// Fields.
-	fColorTable         = 1 << 7
-	fInterlace          = 1 << 6
-	fColorTableBitsMask = 7
+	fColorMapFollows = 1 << 7
+
+	// Image fields.
+	ifLocalColorTable = 1 << 7
+	ifInterlace       = 1 << 6
+	ifPixelSizeMask   = 7
 
 	// Graphic control flags.
 	gcTransparentColorSet = 1 << 0
-	gcDisposalMethodMask  = 7 << 2
-)
-
-// Disposal Methods.
-const (
-	DisposalNone       = 0x01
-	DisposalBackground = 0x02
-	DisposalPrevious   = 0x03
 )
 
 // Section indicators.
@@ -71,10 +66,14 @@ type decoder struct {
 	vers            string
 	width           int
 	height          int
+	flags           byte
+	headerFields    byte
+	backgroundIndex byte
 	loopCount       int
 	delayTime       int
-	backgroundIndex byte
-	disposalMethod  byte
+
+	// Unused from header.
+	aspect byte
 
 	// From image descriptor.
 	imageFields byte
@@ -84,13 +83,13 @@ type decoder struct {
 	hasTransparentIndex bool
 
 	// Computed.
-	globalColorTable color.Palette
+	pixelSize      uint
+	globalColorMap color.Palette
 
 	// Used when decoding.
-	delay    []int
-	disposal []byte
-	image    []*image.Paletted
-	tmp      [1024]byte // must be at least 768 so we can read color table
+	delay []int
+	image []*image.Paletted
+	tmp   [1024]byte // must be at least 768 so we can read color map
 }
 
 // blockReader parses the block structure of GIF image data, which
@@ -123,7 +122,7 @@ func (b *blockReader) Read(p []byte) (int, error) {
 			b.err = io.EOF
 			return 0, b.err
 		}
-		b.slice = b.tmp[:blockLen]
+		b.slice = b.tmp[0:blockLen]
 		if _, b.err = io.ReadFull(b.r, b.slice); b.err != nil {
 			return 0, b.err
 		}
@@ -150,6 +149,12 @@ func (d *decoder) decode(r io.Reader, configOnly bool) error {
 		return nil
 	}
 
+	if d.headerFields&fColorMapFollows != 0 {
+		if d.globalColorMap, err = d.readColorMap(); err != nil {
+			return err
+		}
+	}
+
 	for {
 		c, err := d.r.ReadByte()
 		if err != nil {
@@ -166,22 +171,19 @@ func (d *decoder) decode(r io.Reader, configOnly bool) error {
 			if err != nil {
 				return err
 			}
-			useLocalColorTable := d.imageFields&fColorTable != 0
-			if useLocalColorTable {
-				m.Palette, err = d.readColorTable(d.imageFields)
+			useLocalColorMap := d.imageFields&fColorMapFollows != 0
+			if useLocalColorMap {
+				m.Palette, err = d.readColorMap()
 				if err != nil {
 					return err
 				}
 			} else {
-				if d.globalColorTable == nil {
-					return errors.New("gif: no color table")
-				}
-				m.Palette = d.globalColorTable
+				m.Palette = d.globalColorMap
 			}
 			if d.hasTransparentIndex && int(d.transparentIndex) < len(m.Palette) {
-				if !useLocalColorTable {
-					// Clone the global color table.
-					m.Palette = append(color.Palette(nil), d.globalColorTable...)
+				if !useLocalColorMap {
+					// Clone the global color map.
+					m.Palette = append(color.Palette(nil), d.globalColorMap...)
 				}
 				m.Palette[d.transparentIndex] = color.RGBA{}
 			}
@@ -202,18 +204,9 @@ func (d *decoder) decode(r io.Reader, configOnly bool) error {
 				}
 				return errNotEnough
 			}
-			// Both lzwr and br should be exhausted. Reading from them should
-			// yield (0, io.EOF).
-			//
-			// The spec (Appendix F - Compression), says that "An End of
-			// Information code... must be the last code output by the encoder
-			// for an image". In practice, though, giflib (a widely used C
-			// library) does not enforce this, so we also accept lzwr returning
-			// io.ErrUnexpectedEOF (meaning that the encoded stream hit io.EOF
-			// before the LZW decoder saw an explict end code), provided that
-			// the io.ReadFull call above successfully read len(m.Pix) bytes.
-			// See https://golang.org/issue/9856 for an example GIF.
-			if n, err := lzwr.Read(d.tmp[:1]); n != 0 || (err != io.EOF && err != io.ErrUnexpectedEOF) {
+			// Both lzwr and br should be exhausted. Reading from them
+			// should yield (0, io.EOF).
+			if n, err := lzwr.Read(d.tmp[:1]); n != 0 || err != io.EOF {
 				if err != nil {
 					return err
 				}
@@ -236,13 +229,12 @@ func (d *decoder) decode(r io.Reader, configOnly bool) error {
 			}
 
 			// Undo the interlacing if necessary.
-			if d.imageFields&fInterlace != 0 {
+			if d.imageFields&ifInterlace != 0 {
 				uninterlace(m)
 			}
 
 			d.image = append(d.image, m)
 			d.delay = append(d.delay, d.delayTime)
-			d.disposal = append(d.disposal, d.disposalMethod)
 			// 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.
@@ -262,39 +254,44 @@ func (d *decoder) decode(r io.Reader, configOnly bool) error {
 }
 
 func (d *decoder) readHeaderAndScreenDescriptor() error {
-	_, err := io.ReadFull(d.r, d.tmp[:13])
+	_, err := io.ReadFull(d.r, d.tmp[0:13])
 	if err != nil {
 		return err
 	}
-	d.vers = string(d.tmp[:6])
+	d.vers = string(d.tmp[0:6])
 	if d.vers != "GIF87a" && d.vers != "GIF89a" {
 		return fmt.Errorf("gif: can't recognize format %s", d.vers)
 	}
 	d.width = int(d.tmp[6]) + int(d.tmp[7])<<8
 	d.height = int(d.tmp[8]) + int(d.tmp[9])<<8
-	if fields := d.tmp[10]; fields&fColorTable != 0 {
-		d.backgroundIndex = d.tmp[11]
-		// readColorTable overwrites the contents of d.tmp, but that's OK.
-		if d.globalColorTable, err = d.readColorTable(fields); err != nil {
-			return err
-		}
-	}
-	// d.tmp[12] is the Pixel Aspect Ratio, which is ignored.
+	d.headerFields = d.tmp[10]
+	d.backgroundIndex = d.tmp[11]
+	d.aspect = d.tmp[12]
+	d.loopCount = -1
+	d.pixelSize = uint(d.headerFields&7) + 1
 	return nil
 }
 
-func (d *decoder) readColorTable(fields byte) (color.Palette, error) {
-	n := 1 << (1 + uint(fields&fColorTableBitsMask))
-	_, err := io.ReadFull(d.r, d.tmp[:3*n])
+func (d *decoder) readColorMap() (color.Palette, error) {
+	if d.pixelSize > 8 {
+		return nil, fmt.Errorf("gif: can't handle %d bits per pixel", d.pixelSize)
+	}
+	numColors := 1 << d.pixelSize
+	if d.imageFields&ifLocalColorTable != 0 {
+		numColors = 1 << ((d.imageFields & ifPixelSizeMask) + 1)
+	}
+	numValues := 3 * numColors
+	_, err := io.ReadFull(d.r, d.tmp[0:numValues])
 	if err != nil {
-		return nil, fmt.Errorf("gif: short read on color table: %s", err)
+		return nil, fmt.Errorf("gif: short read on color map: %s", err)
 	}
-	j, p := 0, make(color.Palette, n)
-	for i := range p {
-		p[i] = color.RGBA{d.tmp[j+0], d.tmp[j+1], d.tmp[j+2], 0xFF}
+	colorMap := make(color.Palette, numColors)
+	j := 0
+	for i := range colorMap {
+		colorMap[i] = color.RGBA{d.tmp[j+0], d.tmp[j+1], d.tmp[j+2], 0xFF}
 		j += 3
 	}
-	return p, nil
+	return colorMap, nil
 }
 
 func (d *decoder) readExtension() error {
@@ -321,7 +318,7 @@ func (d *decoder) readExtension() error {
 		return fmt.Errorf("gif: unknown extension 0x%.2x", extension)
 	}
 	if size > 0 {
-		if _, err := io.ReadFull(d.r, d.tmp[:size]); err != nil {
+		if _, err := io.ReadFull(d.r, d.tmp[0:size]); err != nil {
 			return err
 		}
 	}
@@ -346,13 +343,12 @@ func (d *decoder) readExtension() error {
 }
 
 func (d *decoder) readGraphicControl() error {
-	if _, err := io.ReadFull(d.r, d.tmp[:6]); err != nil {
+	if _, err := io.ReadFull(d.r, d.tmp[0:6]); err != nil {
 		return fmt.Errorf("gif: can't read graphic control: %s", err)
 	}
-	flags := d.tmp[1]
-	d.disposalMethod = (flags & gcDisposalMethodMask) >> 2
+	d.flags = d.tmp[1]
 	d.delayTime = int(d.tmp[2]) | int(d.tmp[3])<<8
-	if flags&gcTransparentColorSet != 0 {
+	if d.flags&gcTransparentColorSet != 0 {
 		d.transparentIndex = d.tmp[4]
 		d.hasTransparentIndex = true
 	}
@@ -360,7 +356,7 @@ func (d *decoder) readGraphicControl() error {
 }
 
 func (d *decoder) newImageFromDescriptor() (*image.Paletted, error) {
-	if _, err := io.ReadFull(d.r, d.tmp[:9]); err != nil {
+	if _, err := io.ReadFull(d.r, d.tmp[0:9]); err != nil {
 		return nil, fmt.Errorf("gif: can't read image descriptor: %s", err)
 	}
 	left := int(d.tmp[0]) + int(d.tmp[1])<<8
@@ -384,7 +380,7 @@ func (d *decoder) readBlock() (int, error) {
 	if n == 0 || err != nil {
 		return 0, err
 	}
-	return io.ReadFull(d.r, d.tmp[:n])
+	return io.ReadFull(d.r, d.tmp[0:n])
 }
 
 // interlaceScan defines the ordering for a pass of the interlace algorithm.
@@ -433,24 +429,6 @@ type GIF struct {
 	Image     []*image.Paletted // The successive images.
 	Delay     []int             // The successive delay times, one per frame, in 100ths of a second.
 	LoopCount int               // The loop count.
-	// Disposal is the successive disposal methods, one per frame. For
-	// backwards compatibility, a nil Disposal is valid to pass to EncodeAll,
-	// and implies that each frame's disposal method is 0 (no disposal
-	// specified).
-	Disposal []byte
-	// Config is the global color table (palette), width and height. A nil or
-	// empty-color.Palette Config.ColorModel means that each frame has its own
-	// color table and there is no global color table. Each frame's bounds must
-	// be within the rectangle defined by the two points (0, 0) and
-	// (Config.Width, Config.Height).
-	//
-	// For backwards compatibility, a zero-valued Config is valid to pass to
-	// EncodeAll, and implies that the overall GIF's width and height equals
-	// the first frame's bounds' Rectangle.Max point.
-	Config image.Config
-	// BackgroundIndex is the background index in the global color table, for
-	// use with the DisposalBackground disposal method.
-	BackgroundIndex byte
 }
 
 // DecodeAll reads a GIF image from r and returns the sequential frames
@@ -464,13 +442,6 @@ func DecodeAll(r io.Reader) (*GIF, error) {
 		Image:     d.image,
 		LoopCount: d.loopCount,
 		Delay:     d.delay,
-		Disposal:  d.disposal,
-		Config: image.Config{
-			ColorModel: d.globalColorTable,
-			Width:      d.width,
-			Height:     d.height,
-		},
-		BackgroundIndex: d.backgroundIndex,
 	}
 	return gif, nil
 }
@@ -483,7 +454,7 @@ func DecodeConfig(r io.Reader) (image.Config, error) {
 		return image.Config{}, err
 	}
 	return image.Config{
-		ColorModel: d.globalColorTable,
+		ColorModel: d.globalColorMap,
 		Width:      d.width,
 		Height:     d.height,
 	}, nil
diff --git a/src/image/gif/reader_test.go b/src/image/gif/reader_test.go
index c294195..7b6f504 100644
--- a/src/image/gif/reader_test.go
+++ b/src/image/gif/reader_test.go
@@ -17,8 +17,8 @@ import (
 const (
 	headerStr = "GIF89a" +
 		"\x02\x00\x01\x00" + // width=2, height=1
-		"\x80\x00\x00" // headerFields=(a color table of 2 pixels), backgroundIndex, aspect
-	paletteStr = "\x10\x20\x30\x40\x50\x60" // the color table, also known as a palette
+		"\x80\x00\x00" // headerFields=(a color map of 2 pixels), backgroundIndex, aspect
+	paletteStr = "\x10\x20\x30\x40\x50\x60" // the color map, also known as a palette
 	trailerStr = "\x3b"
 )
 
@@ -141,7 +141,7 @@ var testGIF = []byte{
 	'G', 'I', 'F', '8', '9', 'a',
 	1, 0, 1, 0, // w=1, h=1 (6)
 	128, 0, 0, // headerFields, bg, aspect (10)
-	0, 0, 0, 1, 1, 1, // color table and graphics control (13)
+	0, 0, 0, 1, 1, 1, // color map and graphics control (13)
 	0x21, 0xf9, 0x04, 0x00, 0x00, 0x00, 0xff, 0x00, // (19)
 	// frame 1 (0,0 - 1,1)
 	0x2c,
@@ -200,26 +200,22 @@ func TestNoPalette(t *testing.T) {
 	b.WriteString("\x2c\x00\x00\x00\x00\x02\x00\x01\x00\x00\x02")
 
 	// Encode the pixels: neither is in range, because there is no palette.
-	pix := []byte{0, 3}
+	pix := []byte{0, 128}
 	enc := &bytes.Buffer{}
 	w := lzw.NewWriter(enc, lzw.LSB, 2)
-	if _, err := w.Write(pix); err != nil {
-		t.Fatalf("Write: %v", err)
-	}
-	if err := w.Close(); err != nil {
-		t.Fatalf("Close: %v", err)
-	}
+	w.Write(pix)
+	w.Close()
 	b.WriteByte(byte(len(enc.Bytes())))
 	b.Write(enc.Bytes())
 	b.WriteByte(0x00) // An empty block signifies the end of the image data.
 
 	b.WriteString(trailerStr)
 
-	try(t, b.Bytes(), "gif: no color table")
+	try(t, b.Bytes(), "gif: invalid pixel value")
 }
 
 func TestPixelOutsidePaletteRange(t *testing.T) {
-	for _, pval := range []byte{0, 1, 2, 3} {
+	for _, pval := range []byte{0, 1, 2, 3, 255} {
 		b := &bytes.Buffer{}
 
 		// Manufacture a GIF with a 2 color palette.
@@ -233,12 +229,8 @@ func TestPixelOutsidePaletteRange(t *testing.T) {
 		pix := []byte{pval, pval}
 		enc := &bytes.Buffer{}
 		w := lzw.NewWriter(enc, lzw.LSB, 2)
-		if _, err := w.Write(pix); err != nil {
-			t.Fatalf("Write: %v", err)
-		}
-		if err := w.Close(); err != nil {
-			t.Fatalf("Close: %v", err)
-		}
+		w.Write(pix)
+		w.Close()
 		b.WriteByte(byte(len(enc.Bytes())))
 		b.Write(enc.Bytes())
 		b.WriteByte(0x00) // An empty block signifies the end of the image data.
@@ -253,24 +245,3 @@ func TestPixelOutsidePaletteRange(t *testing.T) {
 		try(t, b.Bytes(), want)
 	}
 }
-
-func TestLoopCount(t *testing.T) {
-	data := []byte("GIF89a000\x00000,0\x00\x00\x00\n\x00" +
-		"\n\x00\x80000000\x02\b\xf01u\xb9\xfdal\x05\x00;")
-	img, err := DecodeAll(bytes.NewReader(data))
-	if err != nil {
-		t.Fatal("DecodeAll:", err)
-	}
-	w := new(bytes.Buffer)
-	err = EncodeAll(w, img)
-	if err != nil {
-		t.Fatal("EncodeAll:", err)
-	}
-	img1, err := DecodeAll(w)
-	if err != nil {
-		t.Fatal("DecodeAll:", err)
-	}
-	if img.LoopCount != img1.LoopCount {
-		t.Errorf("loop count mismatch: %d vs %d", img.LoopCount, img1.LoopCount)
-	}
-}
diff --git a/src/image/gif/writer.go b/src/image/gif/writer.go
index dd31790..49abde7 100644
--- a/src/image/gif/writer.go
+++ b/src/image/gif/writer.go
@@ -6,7 +6,6 @@ package gif
 
 import (
 	"bufio"
-	"bytes"
 	"compress/lzw"
 	"errors"
 	"image"
@@ -53,13 +52,9 @@ type encoder struct {
 	w   writer
 	err error
 	// g is a reference to the data that is being encoded.
-	g GIF
-	// globalCT is the size in bytes of the global color table.
-	globalCT int
-	// buf is a scratch buffer. It must be at least 256 for the blockWriter.
-	buf              [256]byte
-	globalColorTable [3 * 256]byte
-	localColorTable  [3 * 256]byte
+	g *GIF
+	// buf is a scratch buffer. It must be at least 768 so we can write the color map.
+	buf [1024]byte
 }
 
 // blockWriter writes the block structure of GIF image data, which
@@ -121,27 +116,18 @@ func (e *encoder) writeHeader() {
 		return
 	}
 
+	pm := e.g.Image[0]
 	// Logical screen width and height.
-	writeUint16(e.buf[0:2], uint16(e.g.Config.Width))
-	writeUint16(e.buf[2:4], uint16(e.g.Config.Height))
+	writeUint16(e.buf[0:2], uint16(pm.Bounds().Dx()))
+	writeUint16(e.buf[2:4], uint16(pm.Bounds().Dy()))
 	e.write(e.buf[:4])
 
-	if p, ok := e.g.Config.ColorModel.(color.Palette); ok && len(p) > 0 {
-		paddedSize := log2(len(p)) // Size of Global Color Table: 2^(1+n).
-		e.buf[0] = fColorTable | uint8(paddedSize)
-		e.buf[1] = e.g.BackgroundIndex
-		e.buf[2] = 0x00 // Pixel Aspect Ratio.
-		e.write(e.buf[:3])
-		e.globalCT = encodeColorTable(e.globalColorTable[:], p, paddedSize)
-		e.write(e.globalColorTable[:e.globalCT])
-	} else {
-		// All frames have a local color table, so a global color table
-		// is not needed.
-		e.buf[0] = 0x00
-		e.buf[1] = 0x00 // Background Color Index.
-		e.buf[2] = 0x00 // Pixel Aspect Ratio.
-		e.write(e.buf[:3])
-	}
+	// All frames have a local color table, so a global color table
+	// is not needed.
+	e.buf[0] = 0x00
+	e.buf[1] = 0x00 // Background Color Index.
+	e.buf[2] = 0x00 // Pixel Aspect Ratio.
+	e.write(e.buf[:3])
 
 	// Add animation info if necessary.
 	if len(e.g.Image) > 1 {
@@ -161,25 +147,28 @@ func (e *encoder) writeHeader() {
 	}
 }
 
-func encodeColorTable(dst []byte, p color.Palette, size int) int {
-	n := log2Lookup[size]
-	for i := 0; i < n; i++ {
+func (e *encoder) writeColorTable(p color.Palette, size int) {
+	if e.err != nil {
+		return
+	}
+
+	for i := 0; i < log2Lookup[size]; i++ {
 		if i < len(p) {
 			r, g, b, _ := p[i].RGBA()
-			dst[3*i+0] = uint8(r >> 8)
-			dst[3*i+1] = uint8(g >> 8)
-			dst[3*i+2] = uint8(b >> 8)
+			e.buf[3*i+0] = uint8(r >> 8)
+			e.buf[3*i+1] = uint8(g >> 8)
+			e.buf[3*i+2] = uint8(b >> 8)
 		} else {
 			// Pad with black.
-			dst[3*i+0] = 0x00
-			dst[3*i+1] = 0x00
-			dst[3*i+2] = 0x00
+			e.buf[3*i+0] = 0x00
+			e.buf[3*i+1] = 0x00
+			e.buf[3*i+2] = 0x00
 		}
 	}
-	return 3 * n
+	e.write(e.buf[:3*log2Lookup[size]])
 }
 
-func (e *encoder) writeImageBlock(pm *image.Paletted, delay int, disposal byte) {
+func (e *encoder) writeImageBlock(pm *image.Paletted, delay int) {
 	if e.err != nil {
 		return
 	}
@@ -190,14 +179,10 @@ func (e *encoder) writeImageBlock(pm *image.Paletted, delay int, disposal byte)
 	}
 
 	b := pm.Bounds()
-	if b.Min.X < 0 || b.Max.X >= 1<<16 || b.Min.Y < 0 || b.Max.Y >= 1<<16 {
+	if b.Dx() >= 1<<16 || b.Dy() >= 1<<16 || b.Min.X < 0 || b.Min.X >= 1<<16 || b.Min.Y < 0 || b.Min.Y >= 1<<16 {
 		e.err = errors.New("gif: image block is too large to encode")
 		return
 	}
-	if !b.In(image.Rectangle{Max: image.Point{e.g.Config.Width, e.g.Config.Height}}) {
-		e.err = errors.New("gif: image block is out of bounds")
-		return
-	}
 
 	transparentIndex := -1
 	for i, c := range pm.Palette {
@@ -207,14 +192,14 @@ func (e *encoder) writeImageBlock(pm *image.Paletted, delay int, disposal byte)
 		}
 	}
 
-	if delay > 0 || disposal != 0 || transparentIndex != -1 {
+	if delay > 0 || transparentIndex != -1 {
 		e.buf[0] = sExtension  // Extension Introducer.
 		e.buf[1] = gcLabel     // Graphic Control Label.
 		e.buf[2] = gcBlockSize // Block Size.
 		if transparentIndex != -1 {
-			e.buf[3] = 0x01 | disposal<<2
+			e.buf[3] = 0x01
 		} else {
-			e.buf[3] = 0x00 | disposal<<2
+			e.buf[3] = 0x00
 		}
 		writeUint16(e.buf[4:6], uint16(delay)) // Delay Time (1/100ths of a second)
 
@@ -235,15 +220,11 @@ func (e *encoder) writeImageBlock(pm *image.Paletted, delay int, disposal byte)
 	e.write(e.buf[:9])
 
 	paddedSize := log2(len(pm.Palette)) // Size of Local Color Table: 2^(1+n).
-	ct := encodeColorTable(e.localColorTable[:], pm.Palette, paddedSize)
-	if ct != e.globalCT || !bytes.Equal(e.globalColorTable[:ct], e.localColorTable[:ct]) {
-		// Use a local color table.
-		e.writeByte(fColorTable | uint8(paddedSize))
-		e.write(e.localColorTable[:ct])
-	} else {
-		// Use the global color table.
-		e.writeByte(0)
-	}
+	// Interlacing is not supported.
+	e.writeByte(0x80 | uint8(paddedSize))
+
+	// Local Color Table.
+	e.writeColorTable(pm.Palette, paddedSize)
 
 	litWidth := paddedSize + 1
 	if litWidth < 2 {
@@ -300,23 +281,7 @@ func EncodeAll(w io.Writer, g *GIF) error {
 		g.LoopCount = 0
 	}
 
-	e := encoder{g: *g}
-	// The GIF.Disposal, GIF.Config and GIF.BackgroundIndex fields were added
-	// in Go 1.5. Valid Go 1.4 code, such as when the Disposal field is omitted
-	// in a GIF struct literal, should still produce valid GIFs.
-	if e.g.Disposal != nil && len(e.g.Image) != len(e.g.Disposal) {
-		return errors.New("gif: mismatched image and disposal lengths")
-	}
-	if e.g.Config == (image.Config{}) {
-		p := g.Image[0].Bounds().Max
-		e.g.Config.Width = p.X
-		e.g.Config.Height = p.Y
-	} else if e.g.Config.ColorModel != nil {
-		if _, ok := e.g.Config.ColorModel.(color.Palette); !ok {
-			return errors.New("gif: GIF color model must be a color.Palette")
-		}
-	}
-
+	e := encoder{g: g}
 	if ww, ok := w.(writer); ok {
 		e.w = ww
 	} else {
@@ -325,11 +290,7 @@ func EncodeAll(w io.Writer, g *GIF) error {
 
 	e.writeHeader()
 	for i, pm := range g.Image {
-		disposal := uint8(0)
-		if g.Disposal != nil {
-			disposal = g.Disposal[i]
-		}
-		e.writeImageBlock(pm, g.Delay[i], disposal)
+		e.writeImageBlock(pm, g.Delay[i])
 	}
 	e.writeByte(sTrailer)
 	e.flush()
@@ -365,22 +326,8 @@ func Encode(w io.Writer, m image.Image, o *Options) error {
 		opts.Drawer.Draw(pm, b, m, image.ZP)
 	}
 
-	// When calling Encode instead of EncodeAll, the single-frame image is
-	// translated such that its top-left corner is (0, 0), so that the single
-	// frame completely fills the overall GIF's bounds.
-	if pm.Rect.Min != (image.Point{}) {
-		dup := *pm
-		dup.Rect = dup.Rect.Sub(dup.Rect.Min)
-		pm = &dup
-	}
-
 	return EncodeAll(w, &GIF{
 		Image: []*image.Paletted{pm},
 		Delay: []int{0},
-		Config: image.Config{
-			ColorModel: pm.Palette,
-			Width:      b.Dx(),
-			Height:     b.Dy(),
-		},
 	})
 }
diff --git a/src/image/gif/writer_test.go b/src/image/gif/writer_test.go
index db61a5c..93306ff 100644
--- a/src/image/gif/writer_test.go
+++ b/src/image/gif/writer_test.go
@@ -8,12 +8,10 @@ import (
 	"bytes"
 	"image"
 	"image/color"
-	"image/color/palette"
 	_ "image/png"
 	"io/ioutil"
 	"math/rand"
 	"os"
-	"reflect"
 	"testing"
 )
 
@@ -127,317 +125,55 @@ func TestSubImage(t *testing.T) {
 	}
 }
 
-// palettesEqual reports whether two color.Palette values are equal, ignoring
-// any trailing opaque-black palette entries.
-func palettesEqual(p, q color.Palette) bool {
-	n := len(p)
-	if n > len(q) {
-		n = len(q)
-	}
-	for i := 0; i < n; i++ {
-		if p[i] != q[i] {
-			return false
-		}
-	}
-	for i := n; i < len(p); i++ {
-		r, g, b, a := p[i].RGBA()
-		if r != 0 || g != 0 || b != 0 || a != 0xffff {
-			return false
-		}
-	}
-	for i := n; i < len(q); i++ {
-		r, g, b, a := q[i].RGBA()
-		if r != 0 || g != 0 || b != 0 || a != 0xffff {
-			return false
-		}
-	}
-	return true
-}
-
 var frames = []string{
 	"../testdata/video-001.gif",
 	"../testdata/video-005.gray.gif",
 }
 
-func testEncodeAll(t *testing.T, go1Dot5Fields bool, useGlobalColorModel bool) {
-	const width, height = 150, 103
-
+func TestEncodeAll(t *testing.T) {
 	g0 := &GIF{
 		Image:     make([]*image.Paletted, len(frames)),
 		Delay:     make([]int, len(frames)),
 		LoopCount: 5,
 	}
 	for i, f := range frames {
-		g, err := readGIF(f)
+		m, err := readGIF(f)
 		if err != nil {
 			t.Fatal(f, err)
 		}
-		m := g.Image[0]
-		if m.Bounds().Dx() != width || m.Bounds().Dy() != height {
-			t.Fatalf("frame %d had unexpected bounds: got %v, want width/height = %d/%d",
-				i, m.Bounds(), width, height)
-		}
-		g0.Image[i] = m
+		g0.Image[i] = m.Image[0]
 	}
-	// The GIF.Disposal, GIF.Config and GIF.BackgroundIndex fields were added
-	// in Go 1.5. Valid Go 1.4 or earlier code should still produce valid GIFs.
-	//
-	// On the following line, color.Model is an interface type, and
-	// color.Palette is a concrete (slice) type.
-	globalColorModel, backgroundIndex := color.Model(color.Palette(nil)), uint8(0)
-	if useGlobalColorModel {
-		globalColorModel, backgroundIndex = color.Palette(palette.WebSafe), uint8(1)
-	}
-	if go1Dot5Fields {
-		g0.Disposal = make([]byte, len(g0.Image))
-		for i := range g0.Disposal {
-			g0.Disposal[i] = DisposalNone
-		}
-		g0.Config = image.Config{
-			ColorModel: globalColorModel,
-			Width:      width,
-			Height:     height,
-		}
-		g0.BackgroundIndex = backgroundIndex
-	}
-
 	var buf bytes.Buffer
 	if err := EncodeAll(&buf, g0); err != nil {
 		t.Fatal("EncodeAll:", err)
 	}
-	encoded := buf.Bytes()
-	config, err := DecodeConfig(bytes.NewReader(encoded))
-	if err != nil {
-		t.Fatal("DecodeConfig:", err)
-	}
-	g1, err := DecodeAll(bytes.NewReader(encoded))
+	g1, err := DecodeAll(&buf)
 	if err != nil {
 		t.Fatal("DecodeAll:", err)
 	}
-
-	if !reflect.DeepEqual(config, g1.Config) {
-		t.Errorf("DecodeConfig inconsistent with DecodeAll")
-	}
-	if !palettesEqual(g1.Config.ColorModel.(color.Palette), globalColorModel.(color.Palette)) {
-		t.Errorf("unexpected global color model")
-	}
-	if w, h := g1.Config.Width, g1.Config.Height; w != width || h != height {
-		t.Errorf("got config width * height = %d * %d, want %d * %d", w, h, width, height)
-	}
-
 	if g0.LoopCount != g1.LoopCount {
 		t.Errorf("loop counts differ: %d and %d", g0.LoopCount, g1.LoopCount)
 	}
-	if backgroundIndex != g1.BackgroundIndex {
-		t.Errorf("background indexes differ: %d and %d", backgroundIndex, g1.BackgroundIndex)
-	}
-	if len(g0.Image) != len(g1.Image) {
-		t.Fatalf("image lengths differ: %d and %d", len(g0.Image), len(g1.Image))
-	}
-	if len(g1.Image) != len(g1.Delay) {
-		t.Fatalf("image and delay lengths differ: %d and %d", len(g1.Image), len(g1.Delay))
-	}
-	if len(g1.Image) != len(g1.Disposal) {
-		t.Fatalf("image and disposal lengths differ: %d and %d", len(g1.Image), len(g1.Disposal))
-	}
-
 	for i := range g0.Image {
 		m0, m1 := g0.Image[i], g1.Image[i]
 		if m0.Bounds() != m1.Bounds() {
-			t.Errorf("frame %d: bounds differ: %v and %v", i, m0.Bounds(), m1.Bounds())
+			t.Errorf("%s, bounds differ: %v and %v", frames[i], m0.Bounds(), m1.Bounds())
 		}
 		d0, d1 := g0.Delay[i], g1.Delay[i]
 		if d0 != d1 {
-			t.Errorf("frame %d: delay values differ: %d and %d", i, d0, d1)
-		}
-		p0, p1 := uint8(0), g1.Disposal[i]
-		if go1Dot5Fields {
-			p0 = DisposalNone
-		}
-		if p0 != p1 {
-			t.Errorf("frame %d: disposal values differ: %d and %d", i, p0, p1)
+			t.Errorf("%s: delay values differ: %d and %d", frames[i], d0, d1)
 		}
 	}
-}
-
-func TestEncodeAllGo1Dot4(t *testing.T)                 { testEncodeAll(t, false, false) }
-func TestEncodeAllGo1Dot5(t *testing.T)                 { testEncodeAll(t, true, false) }
-func TestEncodeAllGo1Dot5GlobalColorModel(t *testing.T) { testEncodeAll(t, true, true) }
-
-func TestEncodeMismatchDelay(t *testing.T) {
-	images := make([]*image.Paletted, 2)
-	for i := range images {
-		images[i] = image.NewPaletted(image.Rect(0, 0, 5, 5), palette.Plan9)
-	}
-
-	g0 := &GIF{
-		Image: images,
-		Delay: make([]int, 1),
-	}
-	if err := EncodeAll(ioutil.Discard, g0); err == nil {
-		t.Error("expected error from mismatched delay and image slice lengths")
-	}
 
-	g1 := &GIF{
-		Image:    images,
-		Delay:    make([]int, len(images)),
-		Disposal: make([]byte, 1),
-	}
-	for i := range g1.Disposal {
-		g1.Disposal[i] = DisposalNone
-	}
+	g1.Delay = make([]int, 1)
 	if err := EncodeAll(ioutil.Discard, g1); err == nil {
-		t.Error("expected error from mismatched disposal and image slice lengths")
+		t.Error("expected error from mismatched delay and image slice lengths")
 	}
-}
-
-func TestEncodeZeroGIF(t *testing.T) {
 	if err := EncodeAll(ioutil.Discard, &GIF{}); err == nil {
 		t.Error("expected error from providing empty gif")
 	}
 }
 
-func TestEncodeAllFramesOutOfBounds(t *testing.T) {
-	images := []*image.Paletted{
-		image.NewPaletted(image.Rect(0, 0, 5, 5), palette.Plan9),
-		image.NewPaletted(image.Rect(2, 2, 8, 8), palette.Plan9),
-		image.NewPaletted(image.Rect(3, 3, 4, 4), palette.Plan9),
-	}
-	for _, upperBound := range []int{6, 10} {
-		g := &GIF{
-			Image:    images,
-			Delay:    make([]int, len(images)),
-			Disposal: make([]byte, len(images)),
-			Config: image.Config{
-				Width:  upperBound,
-				Height: upperBound,
-			},
-		}
-		err := EncodeAll(ioutil.Discard, g)
-		if upperBound >= 8 {
-			if err != nil {
-				t.Errorf("upperBound=%d: %v", upperBound, err)
-			}
-		} else {
-			if err == nil {
-				t.Errorf("upperBound=%d: got nil error, want non-nil", upperBound)
-			}
-		}
-	}
-}
-
-func TestEncodeNonZeroMinPoint(t *testing.T) {
-	points := []image.Point{
-		image.Point{-8, -9},
-		image.Point{-4, -4},
-		image.Point{-3, +3},
-		image.Point{+0, +0},
-		image.Point{+2, +2},
-	}
-	for _, p := range points {
-		src := image.NewPaletted(image.Rectangle{Min: p, Max: p.Add(image.Point{6, 6})}, palette.Plan9)
-		var buf bytes.Buffer
-		if err := Encode(&buf, src, nil); err != nil {
-			t.Errorf("p=%v: Encode: %v", p, err)
-			continue
-		}
-		m, err := Decode(&buf)
-		if err != nil {
-			t.Errorf("p=%v: Decode: %v", p, err)
-			continue
-		}
-		if got, want := m.Bounds(), image.Rect(0, 0, 6, 6); got != want {
-			t.Errorf("p=%v: got %v, want %v", p, got, want)
-		}
-	}
-}
-
-func TestEncodeImplicitConfigSize(t *testing.T) {
-	// For backwards compatibility for Go 1.4 and earlier code, the Config
-	// field is optional, and if zero, the width and height is implied by the
-	// first (and in this case only) frame's width and height.
-	//
-	// A Config only specifies a width and height (two integers) while an
-	// image.Image's Bounds method returns an image.Rectangle (four integers).
-	// For a gif.GIF, the overall bounds' top-left point is always implicitly
-	// (0, 0), and any frame whose bounds have a negative X or Y will be
-	// outside those overall bounds, so encoding should fail.
-	for _, lowerBound := range []int{-1, 0, 1} {
-		images := []*image.Paletted{
-			image.NewPaletted(image.Rect(lowerBound, lowerBound, 4, 4), palette.Plan9),
-		}
-		g := &GIF{
-			Image: images,
-			Delay: make([]int, len(images)),
-		}
-		err := EncodeAll(ioutil.Discard, g)
-		if lowerBound >= 0 {
-			if err != nil {
-				t.Errorf("lowerBound=%d: %v", lowerBound, err)
-			}
-		} else {
-			if err == nil {
-				t.Errorf("lowerBound=%d: got nil error, want non-nil", lowerBound)
-			}
-		}
-	}
-}
-
-func TestEncodePalettes(t *testing.T) {
-	const w, h = 5, 5
-	pals := []color.Palette{{
-		color.RGBA{0x00, 0x00, 0x00, 0xff},
-		color.RGBA{0x01, 0x00, 0x00, 0xff},
-		color.RGBA{0x02, 0x00, 0x00, 0xff},
-	}, {
-		color.RGBA{0x00, 0x00, 0x00, 0xff},
-		color.RGBA{0x00, 0x01, 0x00, 0xff},
-	}, {
-		color.RGBA{0x00, 0x00, 0x03, 0xff},
-		color.RGBA{0x00, 0x00, 0x02, 0xff},
-		color.RGBA{0x00, 0x00, 0x01, 0xff},
-		color.RGBA{0x00, 0x00, 0x00, 0xff},
-	}, {
-		color.RGBA{0x10, 0x07, 0xf0, 0xff},
-		color.RGBA{0x20, 0x07, 0xf0, 0xff},
-		color.RGBA{0x30, 0x07, 0xf0, 0xff},
-		color.RGBA{0x40, 0x07, 0xf0, 0xff},
-		color.RGBA{0x50, 0x07, 0xf0, 0xff},
-	}}
-	g0 := &GIF{
-		Image: []*image.Paletted{
-			image.NewPaletted(image.Rect(0, 0, w, h), pals[0]),
-			image.NewPaletted(image.Rect(0, 0, w, h), pals[1]),
-			image.NewPaletted(image.Rect(0, 0, w, h), pals[2]),
-			image.NewPaletted(image.Rect(0, 0, w, h), pals[3]),
-		},
-		Delay:    make([]int, len(pals)),
-		Disposal: make([]byte, len(pals)),
-		Config: image.Config{
-			ColorModel: pals[2],
-			Width:      w,
-			Height:     h,
-		},
-	}
-
-	var buf bytes.Buffer
-	if err := EncodeAll(&buf, g0); err != nil {
-		t.Fatalf("EncodeAll: %v", err)
-	}
-	g1, err := DecodeAll(&buf)
-	if err != nil {
-		t.Fatalf("DecodeAll: %v", err)
-	}
-	if len(g0.Image) != len(g1.Image) {
-		t.Fatalf("image lengths differ: %d and %d", len(g0.Image), len(g1.Image))
-	}
-	for i, m := range g1.Image {
-		if got, want := m.Palette, pals[i]; !palettesEqual(got, want) {
-			t.Errorf("frame %d:\ngot  %v\nwant %v", i, got, want)
-		}
-	}
-}
-
 func BenchmarkEncode(b *testing.B) {
 	b.StopTimer()
 
diff --git a/src/image/image.go b/src/image/image.go
index 20b64d7..6b8e5c4 100644
--- a/src/image/image.go
+++ b/src/image/image.go
@@ -18,7 +18,7 @@
 // initialization side effects.
 //
 // See "The Go image package" for more details:
-// https://golang.org/doc/articles/image_package.html
+// http://golang.org/doc/articles/image_package.html
 package image
 
 import (
@@ -46,9 +46,9 @@ type Image interface {
 }
 
 // PalettedImage is an image whose colors may come from a limited palette.
-// If m is a PalettedImage and m.ColorModel() returns a color.Palette p,
+// If m is a PalettedImage and m.ColorModel() returns a PalettedColorModel p,
 // then m.At(x, y) should be equivalent to p[m.ColorIndexAt(x, y)]. If m's
-// color model is not a color.Palette, then ColorIndexAt's behavior is
+// color model is not a PalettedColorModel, then ColorIndexAt's behavior is
 // undefined.
 type PalettedImage interface {
 	// ColorIndexAt returns the palette index of the pixel at (x, y).
@@ -570,7 +570,7 @@ func NewAlpha(r Rectangle) *Alpha {
 	return &Alpha{pix, 1 * w, r}
 }
 
-// Alpha16 is an in-memory image whose At method returns color.Alpha16 values.
+// Alpha16 is an in-memory image whose At method returns color.Alpha64 values.
 type Alpha16 struct {
 	// Pix holds the image's pixels, as alpha values in big-endian format. The pixel at
 	// (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*2].
@@ -826,92 +826,6 @@ func NewGray16(r Rectangle) *Gray16 {
 	return &Gray16{pix, 2 * w, r}
 }
 
-// CMYK is an in-memory image whose At method returns color.CMYK values.
-type CMYK struct {
-	// Pix holds the image's pixels, in C, M, Y, K order. The pixel at
-	// (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*4].
-	Pix []uint8
-	// Stride is the Pix stride (in bytes) between vertically adjacent pixels.
-	Stride int
-	// Rect is the image's bounds.
-	Rect Rectangle
-}
-
-func (p *CMYK) ColorModel() color.Model { return color.CMYKModel }
-
-func (p *CMYK) Bounds() Rectangle { return p.Rect }
-
-func (p *CMYK) At(x, y int) color.Color {
-	return p.CMYKAt(x, y)
-}
-
-func (p *CMYK) CMYKAt(x, y int) color.CMYK {
-	if !(Point{x, y}.In(p.Rect)) {
-		return color.CMYK{}
-	}
-	i := p.PixOffset(x, y)
-	return color.CMYK{p.Pix[i+0], p.Pix[i+1], p.Pix[i+2], p.Pix[i+3]}
-}
-
-// PixOffset returns the index of the first element of Pix that corresponds to
-// the pixel at (x, y).
-func (p *CMYK) PixOffset(x, y int) int {
-	return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
-}
-
-func (p *CMYK) Set(x, y int, c color.Color) {
-	if !(Point{x, y}.In(p.Rect)) {
-		return
-	}
-	i := p.PixOffset(x, y)
-	c1 := color.CMYKModel.Convert(c).(color.CMYK)
-	p.Pix[i+0] = c1.C
-	p.Pix[i+1] = c1.M
-	p.Pix[i+2] = c1.Y
-	p.Pix[i+3] = c1.K
-}
-
-func (p *CMYK) SetCMYK(x, y int, c color.CMYK) {
-	if !(Point{x, y}.In(p.Rect)) {
-		return
-	}
-	i := p.PixOffset(x, y)
-	p.Pix[i+0] = c.C
-	p.Pix[i+1] = c.M
-	p.Pix[i+2] = c.Y
-	p.Pix[i+3] = c.K
-}
-
-// SubImage returns an image representing the portion of the image p visible
-// through r. The returned value shares pixels with the original image.
-func (p *CMYK) SubImage(r Rectangle) Image {
-	r = r.Intersect(p.Rect)
-	// If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
-	// either r1 or r2 if the intersection is empty. Without explicitly checking for
-	// this, the Pix[i:] expression below can panic.
-	if r.Empty() {
-		return &CMYK{}
-	}
-	i := p.PixOffset(r.Min.X, r.Min.Y)
-	return &CMYK{
-		Pix:    p.Pix[i:],
-		Stride: p.Stride,
-		Rect:   r,
-	}
-}
-
-// Opaque scans the entire image and reports whether it is fully opaque.
-func (p *CMYK) Opaque() bool {
-	return true
-}
-
-// NewCMYK returns a new CMYK with the given bounds.
-func NewCMYK(r Rectangle) *CMYK {
-	w, h := r.Dx(), r.Dy()
-	buf := make([]uint8, 4*w*h)
-	return &CMYK{buf, 4 * w, r}
-}
-
 // Paletted is an in-memory image of uint8 indices into a given palette.
 type Paletted struct {
 	// Pix holds the image's pixels, as palette indices. The pixel at
diff --git a/src/image/jpeg/huffman.go b/src/image/jpeg/huffman.go
index 4f8fe8e..d4ff4cf 100644
--- a/src/image/jpeg/huffman.go
+++ b/src/image/jpeg/huffman.go
@@ -187,9 +187,7 @@ func (d *decoder) decodeHuffman(h *huffman) (uint8, error) {
 			// There are no more bytes of data in this segment, but we may still
 			// be able to read the next symbol out of the previously read bits.
 			// First, undo the readByte that the ensureNBits call made.
-			if d.bytes.nUnreadable != 0 {
-				d.unreadByteStuffedByte()
-			}
+			d.unreadByteStuffedByte()
 			goto slowPath
 		}
 	}
diff --git a/src/image/jpeg/reader.go b/src/image/jpeg/reader.go
index adf97ab..6d8b1d1 100644
--- a/src/image/jpeg/reader.go
+++ b/src/image/jpeg/reader.go
@@ -10,7 +10,6 @@ package jpeg
 import (
 	"image"
 	"image/color"
-	"image/internal/imageutil"
 	"io"
 )
 
@@ -27,8 +26,6 @@ type UnsupportedError string
 
 func (e UnsupportedError) Error() string { return "unsupported JPEG feature: " + string(e) }
 
-var errUnsupportedSubsamplingRatio = UnsupportedError("luma/chroma subsampling ratio")
-
 // Component specification, specified in section B.2.2.
 type component struct {
 	h  int   // Horizontal sampling factor.
@@ -44,35 +41,32 @@ const (
 	maxTh   = 3
 	maxTq   = 3
 
-	maxComponents = 4
-)
+	// A grayscale JPEG image has only a Y component.
+	nGrayComponent = 1
+	// A color JPEG image has Y, Cb and Cr components.
+	nColorComponent = 3
 
-const (
-	sof0Marker = 0xc0 // Start Of Frame (Baseline).
-	sof1Marker = 0xc1 // Start Of Frame (Extended Sequential).
-	sof2Marker = 0xc2 // Start Of Frame (Progressive).
-	dhtMarker  = 0xc4 // Define Huffman Table.
-	rst0Marker = 0xd0 // ReSTart (0).
-	rst7Marker = 0xd7 // ReSTart (7).
-	soiMarker  = 0xd8 // Start Of Image.
-	eoiMarker  = 0xd9 // End Of Image.
-	sosMarker  = 0xda // Start Of Scan.
-	dqtMarker  = 0xdb // Define Quantization Table.
-	driMarker  = 0xdd // Define Restart Interval.
-	comMarker  = 0xfe // COMment.
-	// "APPlication specific" markers aren't part of the JPEG spec per se,
-	// but in practice, their use is described at
-	// http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/JPEG.html
-	app0Marker  = 0xe0
-	app14Marker = 0xee
-	app15Marker = 0xef
+	// We only support 4:4:4, 4:4:0, 4:2:2 and 4:2:0 downsampling, and therefore the
+	// number of luma samples per chroma sample is at most 2 in the horizontal
+	// and 2 in the vertical direction.
+	maxH = 2
+	maxV = 2
 )
 
-// See http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/JPEG.html#Adobe
 const (
-	adobeTransformUnknown = 0
-	adobeTransformYCbCr   = 1
-	adobeTransformYCbCrK  = 2
+	soiMarker   = 0xd8 // Start Of Image.
+	eoiMarker   = 0xd9 // End Of Image.
+	sof0Marker  = 0xc0 // Start Of Frame (Baseline).
+	sof2Marker  = 0xc2 // Start Of Frame (Progressive).
+	dhtMarker   = 0xc4 // Define Huffman Table.
+	dqtMarker   = 0xdb // Define Quantization Table.
+	sosMarker   = 0xda // Start Of Scan.
+	driMarker   = 0xdd // Define Restart Interval.
+	rst0Marker  = 0xd0 // ReSTart (0).
+	rst7Marker  = 0xd7 // ReSTart (7).
+	app0Marker  = 0xe0 // APPlication specific (0).
+	app15Marker = 0xef // APPlication specific (15).
+	comMarker   = 0xfe // COMment.
 )
 
 // unzig maps from the zig-zag ordering to the natural ordering. For example,
@@ -89,7 +83,7 @@ var unzig = [blockSize]int{
 	53, 60, 61, 54, 47, 55, 62, 63,
 }
 
-// Deprecated: Reader is deprecated.
+// Reader is deprecated.
 type Reader interface {
 	io.ByteReader
 	io.Reader
@@ -120,25 +114,17 @@ type decoder struct {
 		nUnreadable int
 	}
 	width, height int
-
-	img1        *image.Gray
-	img3        *image.YCbCr
-	blackPix    []byte
-	blackStride int
-
-	ri                  int // Restart Interval.
-	nComp               int
-	progressive         bool
-	jfif                bool
-	adobeTransformValid bool
-	adobeTransform      uint8
-	eobRun              uint16 // End-of-Band run, specified in section G.1.2.2.
-
-	comp       [maxComponents]component
-	progCoeffs [maxComponents][]block // Saved state between progressive-mode scans.
-	huff       [maxTc + 1][maxTh + 1]huffman
-	quant      [maxTq + 1]block // Quantization tables, in zig-zag order.
-	tmp        [2 * blockSize]byte
+	img1          *image.Gray
+	img3          *image.YCbCr
+	ri            int // Restart Interval.
+	nComp         int
+	progressive   bool
+	eobRun        uint16 // End-of-Band run, specified in section G.1.2.2.
+	comp          [nColorComponent]component
+	progCoeffs    [nColorComponent][]block // Saved state between progressive-mode scans.
+	huff          [maxTc + 1][maxTh + 1]huffman
+	quant         [maxTq + 1]block // Quantization tables, in zig-zag order.
+	tmp           [blockSize + 1]byte
 }
 
 // fill fills up the d.bytes.buf buffer from the underlying io.Reader. It
@@ -169,6 +155,9 @@ func (d *decoder) fill() error {
 // sometimes overshoot and read one or two too many bytes. Two-byte overshoot
 // can happen when expecting to read a 0xff 0x00 byte-stuffed byte.
 func (d *decoder) unreadByteStuffedByte() {
+	if d.bytes.nUnreadable == 0 {
+		panic("jpeg: unreadByteStuffedByte call cannot be fulfilled")
+	}
 	d.bytes.i -= d.bytes.nUnreadable
 	d.bytes.nUnreadable = 0
 	if d.bits.n >= 8 {
@@ -214,19 +203,18 @@ func (d *decoder) readByteStuffedByte() (x byte, err error) {
 		return 0xff, nil
 	}
 
-	d.bytes.nUnreadable = 0
-
 	x, err = d.readByte()
 	if err != nil {
 		return 0, err
 	}
-	d.bytes.nUnreadable = 1
 	if x != 0xff {
+		d.bytes.nUnreadable = 1
 		return x, nil
 	}
 
 	x, err = d.readByte()
 	if err != nil {
+		d.bytes.nUnreadable = 1
 		return 0, err
 	}
 	d.bytes.nUnreadable = 2
@@ -296,18 +284,13 @@ func (d *decoder) ignore(n int) error {
 
 // Specified in section B.2.2.
 func (d *decoder) processSOF(n int) error {
-	if d.nComp != 0 {
-		return FormatError("multiple SOF markers")
-	}
 	switch n {
-	case 6 + 3*1: // Grayscale image.
-		d.nComp = 1
-	case 6 + 3*3: // YCbCr or RGB image.
-		d.nComp = 3
-	case 6 + 3*4: // YCbCrK or CMYK image.
-		d.nComp = 4
+	case 6 + 3*nGrayComponent:
+		d.nComp = nGrayComponent
+	case 6 + 3*nColorComponent:
+		d.nComp = nColorComponent
 	default:
-		return UnsupportedError("number of components")
+		return UnsupportedError("SOF has wrong length")
 	}
 	if err := d.readFull(d.tmp[:n]); err != nil {
 		return err
@@ -319,34 +302,12 @@ func (d *decoder) processSOF(n int) error {
 	d.height = int(d.tmp[1])<<8 + int(d.tmp[2])
 	d.width = int(d.tmp[3])<<8 + int(d.tmp[4])
 	if int(d.tmp[5]) != d.nComp {
-		return FormatError("SOF has wrong length")
+		return UnsupportedError("SOF has wrong number of image components")
 	}
-
 	for i := 0; i < d.nComp; i++ {
 		d.comp[i].c = d.tmp[6+3*i]
-		// Section B.2.2 states that "the value of C_i shall be different from
-		// the values of C_1 through C_(i-1)".
-		for j := 0; j < i; j++ {
-			if d.comp[i].c == d.comp[j].c {
-				return FormatError("repeated component identifier")
-			}
-		}
-
 		d.comp[i].tq = d.tmp[8+3*i]
-		if d.comp[i].tq > maxTq {
-			return FormatError("bad Tq value")
-		}
-
-		hv := d.tmp[7+3*i]
-		h, v := int(hv>>4), int(hv&0x0f)
-		if h < 1 || 4 < h || v < 1 || 4 < v {
-			return FormatError("luma/chroma subsampling ratio")
-		}
-		if h == 3 || v == 3 {
-			return errUnsupportedSubsamplingRatio
-		}
-		switch d.nComp {
-		case 1:
+		if d.nComp == nGrayComponent {
 			// If a JPEG image has only one component, section A.2 says "this data
 			// is non-interleaved by definition" and section A.2.2 says "[in this
 			// case...] the order of data units within a scan shall be left-to-right
@@ -358,104 +319,45 @@ func (d *decoder) processSOF(n int) error {
 			// always 1. The component's (h, v) is effectively always (1, 1): even if
 			// the nominal (h, v) is (2, 1), a 20x5 image is encoded in three 8x8
 			// MCUs, not two 16x8 MCUs.
-			h, v = 1, 1
-
-		case 3:
-			// For YCbCr images, we only support 4:4:4, 4:4:0, 4:2:2, 4:2:0,
-			// 4:1:1 or 4:1:0 chroma subsampling ratios. This implies that the
-			// (h, v) values for the Y component are either (1, 1), (1, 2),
-			// (2, 1), (2, 2), (4, 1) or (4, 2), and the Y component's values
-			// must be a multiple of the Cb and Cr component's values. We also
-			// assume that the two chroma components have the same subsampling
-			// ratio.
-			switch i {
-			case 0: // Y.
-				// We have already verified, above, that h and v are both
-				// either 1, 2 or 4, so invalid (h, v) combinations are those
-				// with v == 4.
-				if v == 4 {
-					return errUnsupportedSubsamplingRatio
-				}
-			case 1: // Cb.
-				if d.comp[0].h%h != 0 || d.comp[0].v%v != 0 {
-					return errUnsupportedSubsamplingRatio
-				}
-			case 2: // Cr.
-				if d.comp[1].h != h || d.comp[1].v != v {
-					return errUnsupportedSubsamplingRatio
-				}
-			}
-
-		case 4:
-			// For 4-component images (either CMYK or YCbCrK), we only support two
-			// hv vectors: [0x11 0x11 0x11 0x11] and [0x22 0x11 0x11 0x22].
-			// Theoretically, 4-component JPEG images could mix and match hv values
-			// but in practice, those two combinations are the only ones in use,
-			// and it simplifies the applyBlack code below if we can assume that:
-			//	- for CMYK, the C and K channels have full samples, and if the M
-			//	  and Y channels subsample, they subsample both horizontally and
-			//	  vertically.
-			//	- for YCbCrK, the Y and K channels have full samples.
-			switch i {
-			case 0:
-				if hv != 0x11 && hv != 0x22 {
-					return errUnsupportedSubsamplingRatio
-				}
-			case 1, 2:
-				if hv != 0x11 {
-					return errUnsupportedSubsamplingRatio
-				}
-			case 3:
-				if d.comp[0].h != h || d.comp[0].v != v {
-					return errUnsupportedSubsamplingRatio
-				}
+			d.comp[i].h = 1
+			d.comp[i].v = 1
+			continue
+		}
+		hv := d.tmp[7+3*i]
+		d.comp[i].h = int(hv >> 4)
+		d.comp[i].v = int(hv & 0x0f)
+		// For color images, we only support 4:4:4, 4:4:0, 4:2:2 or 4:2:0 chroma
+		// downsampling ratios. This implies that the (h, v) values for the Y
+		// component are either (1, 1), (1, 2), (2, 1) or (2, 2), and the (h, v)
+		// values for the Cr and Cb components must be (1, 1).
+		if i == 0 {
+			if hv != 0x11 && hv != 0x21 && hv != 0x22 && hv != 0x12 {
+				return UnsupportedError("luma/chroma downsample ratio")
 			}
+		} else if hv != 0x11 {
+			return UnsupportedError("luma/chroma downsample ratio")
 		}
-
-		d.comp[i].h = h
-		d.comp[i].v = v
 	}
 	return nil
 }
 
 // Specified in section B.2.4.1.
 func (d *decoder) processDQT(n int) error {
-loop:
-	for n > 0 {
-		n--
-		x, err := d.readByte()
-		if err != nil {
+	const qtLength = 1 + blockSize
+	for ; n >= qtLength; n -= qtLength {
+		if err := d.readFull(d.tmp[:qtLength]); err != nil {
 			return err
 		}
-		tq := x & 0x0f
+		pq := d.tmp[0] >> 4
+		if pq != 0 {
+			return UnsupportedError("bad Pq value")
+		}
+		tq := d.tmp[0] & 0x0f
 		if tq > maxTq {
 			return FormatError("bad Tq value")
 		}
-		switch x >> 4 {
-		default:
-			return FormatError("bad Pq value")
-		case 0:
-			if n < blockSize {
-				break loop
-			}
-			n -= blockSize
-			if err := d.readFull(d.tmp[:blockSize]); err != nil {
-				return err
-			}
-			for i := range d.quant[tq] {
-				d.quant[tq][i] = int32(d.tmp[i])
-			}
-		case 1:
-			if n < 2*blockSize {
-				break loop
-			}
-			n -= 2 * blockSize
-			if err := d.readFull(d.tmp[:2*blockSize]); err != nil {
-				return err
-			}
-			for i := range d.quant[tq] {
-				d.quant[tq][i] = int32(d.tmp[2*i])<<8 | int32(d.tmp[2*i+1])
-			}
+		for i := range d.quant[tq] {
+			d.quant[tq][i] = int32(d.tmp[i+1])
 		}
 	}
 	if n != 0 {
@@ -476,43 +378,6 @@ func (d *decoder) processDRI(n int) error {
 	return nil
 }
 
-func (d *decoder) processApp0Marker(n int) error {
-	if n < 5 {
-		return d.ignore(n)
-	}
-	if err := d.readFull(d.tmp[:5]); err != nil {
-		return err
-	}
-	n -= 5
-
-	d.jfif = d.tmp[0] == 'J' && d.tmp[1] == 'F' && d.tmp[2] == 'I' && d.tmp[3] == 'F' && d.tmp[4] == '\x00'
-
-	if n > 0 {
-		return d.ignore(n)
-	}
-	return nil
-}
-
-func (d *decoder) processApp14Marker(n int) error {
-	if n < 12 {
-		return d.ignore(n)
-	}
-	if err := d.readFull(d.tmp[:12]); err != nil {
-		return err
-	}
-	n -= 12
-
-	if d.tmp[0] == 'A' && d.tmp[1] == 'd' && d.tmp[2] == 'o' && d.tmp[3] == 'b' && d.tmp[4] == 'e' {
-		d.adobeTransformValid = true
-		d.adobeTransform = d.tmp[11]
-	}
-
-	if n > 0 {
-		return d.ignore(n)
-	}
-	return nil
-}
-
 // decode reads a JPEG image from r and returns it as an image.Image.
 func (d *decoder) decode(r io.Reader, configOnly bool) (image.Image, error) {
 	d.r = r
@@ -594,48 +459,25 @@ func (d *decoder) decode(r io.Reader, configOnly bool) (image.Image, error) {
 			return nil, FormatError("short segment length")
 		}
 
-		switch marker {
-		case sof0Marker, sof1Marker, sof2Marker:
+		switch {
+		case marker == sof0Marker || marker == sof2Marker: // Start Of Frame.
 			d.progressive = marker == sof2Marker
 			err = d.processSOF(n)
-			if configOnly && d.jfif {
-				return nil, err
-			}
-		case dhtMarker:
 			if configOnly {
-				err = d.ignore(n)
-			} else {
-				err = d.processDHT(n)
-			}
-		case dqtMarker:
-			if configOnly {
-				err = d.ignore(n)
-			} else {
-				err = d.processDQT(n)
-			}
-		case sosMarker:
-			if configOnly {
-				return nil, nil
+				return nil, err
 			}
+		case marker == dhtMarker: // Define Huffman Table.
+			err = d.processDHT(n)
+		case marker == dqtMarker: // Define Quantization Table.
+			err = d.processDQT(n)
+		case marker == sosMarker: // Start Of Scan.
 			err = d.processSOS(n)
-		case driMarker:
-			if configOnly {
-				err = d.ignore(n)
-			} else {
-				err = d.processDRI(n)
-			}
-		case app0Marker:
-			err = d.processApp0Marker(n)
-		case app14Marker:
-			err = d.processApp14Marker(n)
+		case marker == driMarker: // Define Restart Interval.
+			err = d.processDRI(n)
+		case app0Marker <= marker && marker <= app15Marker || marker == comMarker: // APPlication specific, or COMment.
+			err = d.ignore(n)
 		default:
-			if app0Marker <= marker && marker <= app15Marker || marker == comMarker {
-				err = d.ignore(n)
-			} else if marker < 0xc0 { // See Table B.1 "Marker code assignments".
-				err = FormatError("unknown marker")
-			} else {
-				err = UnsupportedError("unknown marker")
-			}
+			err = UnsupportedError("unknown marker")
 		}
 		if err != nil {
 			return nil, err
@@ -645,118 +487,11 @@ func (d *decoder) decode(r io.Reader, configOnly bool) (image.Image, error) {
 		return d.img1, nil
 	}
 	if d.img3 != nil {
-		if d.blackPix != nil {
-			return d.applyBlack()
-		} else if d.isRGB() {
-			return d.convertToRGB()
-		}
 		return d.img3, nil
 	}
 	return nil, FormatError("missing SOS marker")
 }
 
-// applyBlack combines d.img3 and d.blackPix into a CMYK image. The formula
-// used depends on whether the JPEG image is stored as CMYK or YCbCrK,
-// indicated by the APP14 (Adobe) metadata.
-//
-// Adobe CMYK JPEG images are inverted, where 255 means no ink instead of full
-// ink, so we apply "v = 255 - v" at various points. Note that a double
-// inversion is a no-op, so inversions might be implicit in the code below.
-func (d *decoder) applyBlack() (image.Image, error) {
-	if !d.adobeTransformValid {
-		return nil, UnsupportedError("unknown color model: 4-component JPEG doesn't have Adobe APP14 metadata")
-	}
-
-	// If the 4-component JPEG image isn't explicitly marked as "Unknown (RGB
-	// or CMYK)" as per
-	// http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/JPEG.html#Adobe
-	// we assume that it is YCbCrK. This matches libjpeg's jdapimin.c.
-	if d.adobeTransform != adobeTransformUnknown {
-		// Convert the YCbCr part of the YCbCrK to RGB, invert the RGB to get
-		// CMY, and patch in the original K. The RGB to CMY inversion cancels
-		// out the 'Adobe inversion' described in the applyBlack doc comment
-		// above, so in practice, only the fourth channel (black) is inverted.
-		bounds := d.img3.Bounds()
-		img := image.NewRGBA(bounds)
-		imageutil.DrawYCbCr(img, bounds, d.img3, bounds.Min)
-		for iBase, y := 0, bounds.Min.Y; y < bounds.Max.Y; iBase, y = iBase+img.Stride, y+1 {
-			for i, x := iBase+3, bounds.Min.X; x < bounds.Max.X; i, x = i+4, x+1 {
-				img.Pix[i] = 255 - d.blackPix[(y-bounds.Min.Y)*d.blackStride+(x-bounds.Min.X)]
-			}
-		}
-		return &image.CMYK{
-			Pix:    img.Pix,
-			Stride: img.Stride,
-			Rect:   img.Rect,
-		}, nil
-	}
-
-	// The first three channels (cyan, magenta, yellow) of the CMYK
-	// were decoded into d.img3, but each channel was decoded into a separate
-	// []byte slice, and some channels may be subsampled. We interleave the
-	// separate channels into an image.CMYK's single []byte slice containing 4
-	// contiguous bytes per pixel.
-	bounds := d.img3.Bounds()
-	img := image.NewCMYK(bounds)
-
-	translations := [4]struct {
-		src    []byte
-		stride int
-	}{
-		{d.img3.Y, d.img3.YStride},
-		{d.img3.Cb, d.img3.CStride},
-		{d.img3.Cr, d.img3.CStride},
-		{d.blackPix, d.blackStride},
-	}
-	for t, translation := range translations {
-		subsample := d.comp[t].h != d.comp[0].h || d.comp[t].v != d.comp[0].v
-		for iBase, y := 0, bounds.Min.Y; y < bounds.Max.Y; iBase, y = iBase+img.Stride, y+1 {
-			sy := y - bounds.Min.Y
-			if subsample {
-				sy /= 2
-			}
-			for i, x := iBase+t, bounds.Min.X; x < bounds.Max.X; i, x = i+4, x+1 {
-				sx := x - bounds.Min.X
-				if subsample {
-					sx /= 2
-				}
-				img.Pix[i] = 255 - translation.src[sy*translation.stride+sx]
-			}
-		}
-	}
-	return img, nil
-}
-
-func (d *decoder) isRGB() bool {
-	if d.jfif {
-		return false
-	}
-	if d.adobeTransformValid && d.adobeTransform == adobeTransformUnknown {
-		// http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/JPEG.html#Adobe
-		// says that 0 means Unknown (and in practice RGB) and 1 means YCbCr.
-		return true
-	}
-	return d.comp[0].c == 'R' && d.comp[1].c == 'G' && d.comp[2].c == 'B'
-}
-
-func (d *decoder) convertToRGB() (image.Image, error) {
-	cScale := d.comp[0].h / d.comp[1].h
-	bounds := d.img3.Bounds()
-	img := image.NewRGBA(bounds)
-	for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
-		po := img.PixOffset(bounds.Min.X, y)
-		yo := d.img3.YOffset(bounds.Min.X, y)
-		co := d.img3.COffset(bounds.Min.X, y)
-		for i, iMax := 0, bounds.Max.X-bounds.Min.X; i < iMax; i++ {
-			img.Pix[po+4*i+0] = d.img3.Y[yo+i]
-			img.Pix[po+4*i+1] = d.img3.Cb[co+i/cScale]
-			img.Pix[po+4*i+2] = d.img3.Cr[co+i/cScale]
-			img.Pix[po+4*i+3] = 255
-		}
-	}
-	return img, nil
-}
-
 // Decode reads a JPEG image from r and returns it as an image.Image.
 func Decode(r io.Reader) (image.Image, error) {
 	var d decoder
@@ -771,25 +506,15 @@ func DecodeConfig(r io.Reader) (image.Config, error) {
 		return image.Config{}, err
 	}
 	switch d.nComp {
-	case 1:
+	case nGrayComponent:
 		return image.Config{
 			ColorModel: color.GrayModel,
 			Width:      d.width,
 			Height:     d.height,
 		}, nil
-	case 3:
-		cm := color.YCbCrModel
-		if d.isRGB() {
-			cm = color.RGBAModel
-		}
-		return image.Config{
-			ColorModel: cm,
-			Width:      d.width,
-			Height:     d.height,
-		}, nil
-	case 4:
+	case nColorComponent:
 		return image.Config{
-			ColorModel: color.CMYKModel,
+			ColorModel: color.YCbCrModel,
 			Width:      d.width,
 			Height:     d.height,
 		}, nil
diff --git a/src/image/jpeg/reader_test.go b/src/image/jpeg/reader_test.go
index 7737615..4de2e8e 100644
--- a/src/image/jpeg/reader_test.go
+++ b/src/image/jpeg/reader_test.go
@@ -15,7 +15,6 @@ import (
 	"os"
 	"strings"
 	"testing"
-	"time"
 )
 
 // TestDecodeProgressive tests that decoding the baseline and progressive
@@ -24,8 +23,6 @@ import (
 func TestDecodeProgressive(t *testing.T) {
 	testCases := []string{
 		"../testdata/video-001",
-		"../testdata/video-001.q50.410",
-		"../testdata/video-001.q50.411",
 		"../testdata/video-001.q50.420",
 		"../testdata/video-001.q50.422",
 		"../testdata/video-001.q50.440",
@@ -187,81 +184,6 @@ func pixString(pix []byte, stride, x, y int) string {
 	return s.String()
 }
 
-func TestTruncatedSOSDataDoesntPanic(t *testing.T) {
-	b, err := ioutil.ReadFile("../testdata/video-005.gray.q50.jpeg")
-	if err != nil {
-		t.Fatal(err)
-	}
-	sosMarker := []byte{0xff, 0xda}
-	i := bytes.Index(b, sosMarker)
-	if i < 0 {
-		t.Fatal("SOS marker not found")
-	}
-	i += len(sosMarker)
-	j := i + 10
-	if j > len(b) {
-		j = len(b)
-	}
-	for ; i < j; i++ {
-		Decode(bytes.NewReader(b[:i]))
-	}
-}
-
-func TestLargeImageWithShortData(t *testing.T) {
-	// This input is an invalid JPEG image, based on the fuzzer-generated image
-	// in issue 10413. It is only 504 bytes, and shouldn't take long for Decode
-	// to return an error. The Start Of Frame marker gives the image dimensions
-	// as 8192 wide and 8192 high, so even if an unreadByteStuffedByte bug
-	// doesn't technically lead to an infinite loop, such a bug can still cause
-	// an unreasonably long loop for such a short input.
-	const input = "" +
-		"\xff\xd8\xff\xe0\x00\x10\x4a\x46\x49\x46\x00\x01\x01\x00\x00\x01" +
-		"\x00\x01\x00\x00\xff\xdb\x00\x43\x00\x10\x0b\x0c\x0e\x0c\x0a\x10" +
-		"\x0e\x89\x0e\x12\x11\x10\x13\x18\xff\xd8\xff\xe0\x00\x10\x4a\x46" +
-		"\x49\x46\x00\x01\x01\x00\x00\x01\x00\x01\x00\x00\xff\xdb\x00\x43" +
-		"\x00\x10\x0b\x0c\x0e\x0c\x0a\x10\x0e\x0d\x0e\x12\x11\x10\x13\x18" +
-		"\x28\x1a\x18\x16\x16\x18\x31\x23\x25\x1d\x28\x3a\x33\x3d\x3c\x39" +
-		"\x33\x38\x37\x40\x48\x5c\x4e\x40\x44\x57\x45\x37\x38\x50\x6d\x51" +
-		"\x57\x5f\x62\x67\x68\x67\x3e\x4d\x71\x79\x70\x64\x78\x5c\x65\x67" +
-		"\x63\xff\xc0\x00\x0b\x08\x20\x00\x20\x00\x01\x01\x11\x00\xff\xc4" +
-		"\x00\x1f\x00\x00\x01\x05\x01\x01\x01\x01\x01\x01\x00\x00\x00\x00" +
-		"\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\xff" +
-		"\xc4\x00\xb5\x10\x00\x02\x01\x03\x03\x02\x04\x03\x05\x05\x04\x04" +
-		"\x00\x00\x01\x7d\x01\x02\x03\x00\x04\x11\x05\x12\x21\x31\x01\x06" +
-		"\x13\x51\x61\x07\x22\x71\x14\x32\x81\x91\xa1\x08\x23\xd8\xff\xdd" +
-		"\x42\xb1\xc1\x15\x52\xd1\xf0\x24\x33\x62\x72\x82\x09\x0a\x16\x17" +
-		"\x18\x19\x1a\x25\x26\x27\x28\x29\x2a\x34\x35\x36\x37\x38\x39\x3a" +
-		"\x43\x44\x45\x46\x47\x48\x49\x4a\x53\x54\x55\x56\x57\x58\x59\x5a" +
-		"\x00\x63\x64\x65\x66\x67\x68\x69\x6a\x73\x74\x75\x76\x77\x78\x79" +
-		"\x7a\x83\x84\x85\x86\x87\x88\x89\x8a\x92\x93\x94\x95\x96\x97\x98" +
-		"\x99\x9a\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xb2\xb3\xb4\xb5\xb6" +
-		"\xb7\xb8\xb9\xba\xc2\xc3\xc4\xc5\xc6\xc7\xff\xd8\xff\xe0\x00\x10" +
-		"\x4a\x46\x49\x46\x00\x01\x01\x00\x00\x01\x00\x01\x00\x00\xff\xdb" +
-		"\x00\x43\x00\x10\x0b\x0c\x0e\x0c\x0a\x10\x0e\x0d\x0e\x12\x11\x10" +
-		"\x13\x18\x28\x1a\x18\x16\x16\x18\x31\x23\x25\x1d\xc8\xc9\xca\xd2" +
-		"\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8" +
-		"\xe9\xea\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xff\xda\x00\x08" +
-		"\x01\x01\x00\x00\x3f\x00\xb9\xeb\x50\xb0\xdb\xc8\xa8\xe4\x63\x80" +
-		"\xdd\x31\xd6\x9d\xbb\xf2\xc5\x42\x1f\x6c\x6f\xf4\x34\xdd\x3c\xfc" +
-		"\xac\xe7\x3d\x80\xa9\xcc\x87\x34\xb3\x37\xfa\x2b\x9f\x6a\xad\x63" +
-		"\x20\x36\x9f\x78\x64\x75\xe6\xab\x7d\xb2\xde\x29\x70\xd3\x20\x27" +
-		"\xde\xaf\xa4\xf0\xca\x9f\x24\xa8\xdf\x46\xa8\x24\x84\x96\xe3\x77" +
-		"\xf9\x2e\xe0\x0a\x62\x7f\xdf\xd9"
-	c := make(chan error, 1)
-	go func() {
-		_, err := Decode(strings.NewReader(input))
-		c <- err
-	}()
-	select {
-	case err := <-c:
-		if err == nil {
-			t.Fatalf("got nil error, want non-nil")
-		}
-	case <-time.After(3 * time.Second):
-		t.Fatalf("timed out")
-	}
-}
-
 func TestExtraneousData(t *testing.T) {
 	// Encode a 1x1 red image.
 	src := image.NewRGBA(image.Rect(0, 0, 1, 1))
diff --git a/src/image/jpeg/scan.go b/src/image/jpeg/scan.go
index 99734c0..2bd1d9d 100644
--- a/src/image/jpeg/scan.go
+++ b/src/image/jpeg/scan.go
@@ -9,42 +9,27 @@ import (
 )
 
 // makeImg allocates and initializes the destination image.
-func (d *decoder) makeImg(mxx, myy int) {
-	if d.nComp == 1 {
+func (d *decoder) makeImg(h0, v0, mxx, myy int) {
+	if d.nComp == nGrayComponent {
 		m := image.NewGray(image.Rect(0, 0, 8*mxx, 8*myy))
 		d.img1 = m.SubImage(image.Rect(0, 0, d.width, d.height)).(*image.Gray)
 		return
 	}
-
-	h0 := d.comp[0].h
-	v0 := d.comp[0].v
-	hRatio := h0 / d.comp[1].h
-	vRatio := v0 / d.comp[1].v
 	var subsampleRatio image.YCbCrSubsampleRatio
-	switch hRatio<<4 | vRatio {
-	case 0x11:
+	switch {
+	case h0 == 1 && v0 == 1:
 		subsampleRatio = image.YCbCrSubsampleRatio444
-	case 0x12:
+	case h0 == 1 && v0 == 2:
 		subsampleRatio = image.YCbCrSubsampleRatio440
-	case 0x21:
+	case h0 == 2 && v0 == 1:
 		subsampleRatio = image.YCbCrSubsampleRatio422
-	case 0x22:
+	case h0 == 2 && v0 == 2:
 		subsampleRatio = image.YCbCrSubsampleRatio420
-	case 0x41:
-		subsampleRatio = image.YCbCrSubsampleRatio411
-	case 0x42:
-		subsampleRatio = image.YCbCrSubsampleRatio410
 	default:
 		panic("unreachable")
 	}
 	m := image.NewYCbCr(image.Rect(0, 0, 8*h0*mxx, 8*v0*myy), subsampleRatio)
 	d.img3 = m.SubImage(image.Rect(0, 0, d.width, d.height)).(*image.YCbCr)
-
-	if d.nComp == 4 {
-		h3, v3 := d.comp[3].h, d.comp[3].v
-		d.blackPix = make([]byte, 8*h3*mxx*8*v3*myy)
-		d.blackStride = 8 * h3 * mxx
-	}
 }
 
 // Specified in section B.2.3.
@@ -62,16 +47,15 @@ func (d *decoder) processSOS(n int) error {
 	if n != 4+2*nComp {
 		return FormatError("SOS length inconsistent with number of components")
 	}
-	var scan [maxComponents]struct {
+	var scan [nColorComponent]struct {
 		compIndex uint8
 		td        uint8 // DC table selector.
 		ta        uint8 // AC table selector.
 	}
-	totalHV := 0
 	for i := 0; i < nComp; i++ {
 		cs := d.tmp[1+2*i] // Component selector.
 		compIndex := -1
-		for j, comp := range d.comp[:d.nComp] {
+		for j, comp := range d.comp {
 			if cs == comp.c {
 				compIndex = j
 			}
@@ -80,18 +64,6 @@ func (d *decoder) processSOS(n int) error {
 			return FormatError("unknown component selector")
 		}
 		scan[i].compIndex = uint8(compIndex)
-		// Section B.2.3 states that "the value of Cs_j shall be different from
-		// the values of Cs_1 through Cs_(j-1)". Since we have previously
-		// verified that a frame's component identifiers (C_i values in section
-		// B.2.2) are unique, it suffices to check that the implicit indexes
-		// into d.comp are unique.
-		for j := 0; j < i; j++ {
-			if scan[i].compIndex == scan[j].compIndex {
-				return FormatError("repeated component selector")
-			}
-		}
-		totalHV += d.comp[compIndex].h * d.comp[compIndex].v
-
 		scan[i].td = d.tmp[2+2*i] >> 4
 		if scan[i].td > maxTh {
 			return FormatError("bad Td value")
@@ -101,11 +73,6 @@ func (d *decoder) processSOS(n int) error {
 			return FormatError("bad Ta value")
 		}
 	}
-	// Section B.2.3 states that if there is more than one component then the
-	// total H*V values in a scan must be <= 10.
-	if d.nComp > 1 && totalHV > 10 {
-		return FormatError("total sampling factors too large")
-	}
 
 	// zigStart and zigEnd are the spectral selection bounds.
 	// ah and al are the successive approximation high and low values.
@@ -145,7 +112,7 @@ func (d *decoder) processSOS(n int) error {
 	mxx := (d.width + 8*h0 - 1) / (8 * h0)
 	myy := (d.height + 8*v0 - 1) / (8 * v0)
 	if d.img1 == nil && d.img3 == nil {
-		d.makeImg(mxx, myy)
+		d.makeImg(h0, v0, mxx, myy)
 	}
 	if d.progressive {
 		for i := 0; i < nComp; i++ {
@@ -161,9 +128,11 @@ func (d *decoder) processSOS(n int) error {
 	var (
 		// b is the decoded coefficients, in natural (not zig-zag) order.
 		b  block
-		dc [maxComponents]int32
-		// bx and by are the location of the current block, in units of 8x8
-		// blocks: the third block in the first row has (bx, by) = (2, 0).
+		dc [nColorComponent]int32
+		// bx and by are the location of the current (in terms of 8x8 blocks).
+		// For example, with 4:2:0 chroma subsampling, the block whose top left
+		// pixel co-ordinates are (16, 8) is the third block in the first row:
+		// bx is 2 and by is 0, even though the pixel is in the second MCU.
 		bx, by     int
 		blockCount int
 	)
@@ -171,10 +140,8 @@ func (d *decoder) processSOS(n int) error {
 		for mx := 0; mx < mxx; mx++ {
 			for i := 0; i < nComp; i++ {
 				compIndex := scan[i].compIndex
-				hi := d.comp[compIndex].h
-				vi := d.comp[compIndex].v
 				qt := &d.quant[d.comp[compIndex].tq]
-				for j := 0; j < hi*vi; j++ {
+				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.
 					//
@@ -201,10 +168,15 @@ func (d *decoder) processSOS(n int) error {
 					//	0 1 2
 					//	3 4 5
 					if nComp != 1 {
-						bx = hi*mx + j%hi
-						by = vi*my + j/hi
+						bx, by = d.comp[compIndex].h*mx, d.comp[compIndex].v*my
+						if h0 == 1 {
+							by += j
+						} else {
+							bx += j % 2
+							by += j / 2
+						}
 					} else {
-						q := mxx * hi
+						q := mxx * d.comp[compIndex].h
 						bx = blockCount % q
 						by = blockCount / q
 						blockCount++
@@ -215,7 +187,7 @@ func (d *decoder) processSOS(n int) error {
 
 					// Load the previous partially decoded coefficients, if applicable.
 					if d.progressive {
-						b = d.progCoeffs[compIndex][by*mxx*hi+bx]
+						b = d.progCoeffs[compIndex][by*mxx*d.comp[compIndex].h+bx]
 					} else {
 						b = block{}
 					}
@@ -288,7 +260,7 @@ func (d *decoder) processSOS(n int) error {
 					if d.progressive {
 						if zigEnd != blockSize-1 || al != 0 {
 							// We haven't completely decoded this 8x8 block. Save the coefficients.
-							d.progCoeffs[compIndex][by*mxx*hi+bx] = b
+							d.progCoeffs[compIndex][by*mxx*d.comp[compIndex].h+bx] = b
 							// At this point, we could execute the rest of the loop body to dequantize and
 							// perform the inverse DCT, to save early stages of a progressive image to the
 							// *image.YCbCr buffers (the whole point of progressive encoding), but in Go,
@@ -304,7 +276,7 @@ func (d *decoder) processSOS(n int) error {
 					}
 					idct(&b)
 					dst, stride := []byte(nil), 0
-					if d.nComp == 1 {
+					if d.nComp == nGrayComponent {
 						dst, stride = d.img1.Pix[8*(by*d.img1.Stride+bx):], d.img1.Stride
 					} else {
 						switch compIndex {
@@ -314,8 +286,6 @@ func (d *decoder) processSOS(n int) error {
 							dst, stride = d.img3.Cb[8*(by*d.img3.CStride+bx):], d.img3.CStride
 						case 2:
 							dst, stride = d.img3.Cr[8*(by*d.img3.CStride+bx):], d.img3.CStride
-						case 3:
-							dst, stride = d.blackPix[8*(by*d.blackStride+bx):], d.blackStride
 						default:
 							return UnsupportedError("too many components")
 						}
@@ -355,7 +325,7 @@ func (d *decoder) processSOS(n int) error {
 				// Reset the Huffman decoder.
 				d.bits = bits{}
 				// Reset the DC components, as per section F.2.1.3.1.
-				dc = [maxComponents]int32{}
+				dc = [nColorComponent]int32{}
 				// Reset the progressive decoder state, as per section G.1.2.2.
 				d.eobRun = 0
 			}
diff --git a/src/image/png/reader.go b/src/image/png/reader.go
index bbd6f75..0a40ca1 100644
--- a/src/image/png/reader.go
+++ b/src/image/png/reader.go
@@ -47,10 +47,6 @@ const (
 	cbTCA16
 )
 
-func cbPaletted(cb int) bool {
-	return cbP1 <= cb && cb <= cbP8
-}
-
 // Filter type, as per the PNG spec.
 const (
 	ftNone    = 0
@@ -85,16 +81,15 @@ var interlacing = []interlaceScan{
 }
 
 // Decoding stage.
-// The PNG specification says that the IHDR, PLTE (if present), tRNS (if
-// present), IDAT and IEND chunks must appear in that order. There may be
-// multiple IDAT chunks, and IDAT chunks must be sequential (i.e. they may not
-// have any other chunks between them).
+// The PNG specification says that the IHDR, PLTE (if present), IDAT and IEND
+// chunks must appear in that order. There may be multiple IDAT chunks, and
+// IDAT chunks must be sequential (i.e. they may not have any other chunks
+// between them).
 // http://www.w3.org/TR/PNG/#5ChunkOrdering
 const (
 	dsStart = iota
 	dsSeenIHDR
 	dsSeenPLTE
-	dsSeentRNS
 	dsSeenIDAT
 	dsSeenIEND
 )
@@ -326,23 +321,15 @@ func (d *decoder) decode() (image.Image, error) {
 	var img image.Image
 	if d.interlace == itNone {
 		img, err = d.readImagePass(r, 0, false)
-		if err != nil {
-			return nil, err
-		}
 	} else if d.interlace == itAdam7 {
 		// Allocate a blank image of the full size.
 		img, err = d.readImagePass(nil, 0, true)
-		if err != nil {
-			return nil, err
-		}
 		for pass := 0; pass < 7; pass++ {
 			imagePass, err := d.readImagePass(r, pass, false)
 			if err != nil {
 				return nil, err
 			}
-			if imagePass != nil {
-				d.mergePassInto(img, imagePass, pass)
-			}
+			d.mergePassInto(img, imagePass, pass)
 		}
 	}
 
@@ -384,12 +371,6 @@ func (d *decoder) readImagePass(r io.Reader, pass int, allocateOnly bool) (image
 		// Add the multiplication factor and subtract one, effectively rounding up.
 		width = (width - p.xOffset + p.xFactor - 1) / p.xFactor
 		height = (height - p.yOffset + p.yFactor - 1) / p.yFactor
-		// A PNG image can't have zero width or height, but for an interlaced
-		// image, an individual pass might have zero width or height. If so, we
-		// shouldn't even read a per-row filter type byte, so return early.
-		if width == 0 || height == 0 {
-			return nil, nil
-		}
 	}
 	switch d.cb {
 	case cbG1, cbG2, cbG4, cbG8:
@@ -444,9 +425,6 @@ func (d *decoder) readImagePass(r io.Reader, pass int, allocateOnly bool) (image
 		// Read the decompressed bytes.
 		_, err := io.ReadFull(r, cr)
 		if err != nil {
-			if err == io.EOF || err == io.ErrUnexpectedEOF {
-				return nil, FormatError("not enough pixel data")
-			}
 			return nil, err
 		}
 
@@ -465,9 +443,6 @@ func (d *decoder) readImagePass(r io.Reader, pass int, allocateOnly bool) (image
 				cdat[i] += p
 			}
 		case ftAverage:
-			// The first column has no column to the left of it, so it is a
-			// special case. We know that the first column exists because we
-			// check above that width != 0, and so len(cdat) != 0.
 			for i := 0; i < bytesPerPixel; i++ {
 				cdat[i] += pdat[i] / 2
 			}
@@ -712,10 +687,9 @@ func (d *decoder) parseChunk() error {
 		if d.stage != dsSeenPLTE {
 			return chunkOrderError
 		}
-		d.stage = dsSeentRNS
 		return d.parsetRNS(length)
 	case "IDAT":
-		if d.stage < dsSeenIHDR || d.stage > dsSeenIDAT || (d.stage == dsSeenIHDR && cbPaletted(d.cb)) {
+		if d.stage < dsSeenIHDR || d.stage > dsSeenIDAT || (d.cb == cbP8 && d.stage == dsSeenIHDR) {
 			return chunkOrderError
 		}
 		d.stage = dsSeenIDAT
@@ -805,7 +779,7 @@ func DecodeConfig(r io.Reader) (image.Config, error) {
 			}
 			return image.Config{}, err
 		}
-		paletted := cbPaletted(d.cb)
+		paletted := d.cb == cbP8 || d.cb == cbP4 || d.cb == cbP2 || d.cb == cbP1
 		if d.stage == dsSeenIHDR && !paletted {
 			break
 		}
diff --git a/src/image/png/reader_test.go b/src/image/png/reader_test.go
index f89e7ef..ce772eb 100644
--- a/src/image/png/reader_test.go
+++ b/src/image/png/reader_test.go
@@ -6,14 +6,12 @@ package png
 
 import (
 	"bufio"
-	"bytes"
 	"fmt"
 	"image"
 	"image/color"
 	"io"
 	"io/ioutil"
 	"os"
-	"reflect"
 	"strings"
 	"testing"
 )
@@ -321,93 +319,6 @@ func TestPalettedDecodeConfig(t *testing.T) {
 	}
 }
 
-func TestInterlaced(t *testing.T) {
-	a, err := readPNG("testdata/gray-gradient.png")
-	if err != nil {
-		t.Fatal(err)
-	}
-	b, err := readPNG("testdata/gray-gradient.interlaced.png")
-	if err != nil {
-		t.Fatal(err)
-	}
-	if !reflect.DeepEqual(a, b) {
-		t.Fatalf("decodings differ:\nnon-interlaced:\n%#v\ninterlaced:\n%#v", a, b)
-	}
-}
-
-func TestIncompleteIDATOnRowBoundary(t *testing.T) {
-	// The following is an invalid 1x2 grayscale PNG image. The header is OK,
-	// but the zlib-compressed IDAT payload contains two bytes "\x02\x00",
-	// which is only one row of data (the leading "\x02" is a row filter).
-	const (
-		ihdr = "\x00\x00\x00\x0dIHDR\x00\x00\x00\x01\x00\x00\x00\x02\x08\x00\x00\x00\x00\xbc\xea\xe9\xfb"
-		idat = "\x00\x00\x00\x0eIDAT\x78\x9c\x62\x62\x00\x04\x00\x00\xff\xff\x00\x06\x00\x03\xfa\xd0\x59\xae"
-		iend = "\x00\x00\x00\x00IEND\xae\x42\x60\x82"
-	)
-	_, err := Decode(strings.NewReader(pngHeader + ihdr + idat + iend))
-	if err == nil {
-		t.Fatal("got nil error, want non-nil")
-	}
-}
-
-func TestMultipletRNSChunks(t *testing.T) {
-	/*
-		The following is a valid 1x1 paletted PNG image with a 1-element palette
-		containing color.NRGBA{0xff, 0x00, 0x00, 0x7f}:
-			0000000: 8950 4e47 0d0a 1a0a 0000 000d 4948 4452  .PNG........IHDR
-			0000010: 0000 0001 0000 0001 0803 0000 0028 cb34  .............(.4
-			0000020: bb00 0000 0350 4c54 45ff 0000 19e2 0937  .....PLTE......7
-			0000030: 0000 0001 7452 4e53 7f80 5cb4 cb00 0000  ....tRNS..\.....
-			0000040: 0e49 4441 5478 9c62 6200 0400 00ff ff00  .IDATx.bb.......
-			0000050: 0600 03fa d059 ae00 0000 0049 454e 44ae  .....Y.....IEND.
-			0000060: 4260 82                                  B`.
-		Dropping the tRNS chunk makes that color's alpha 0xff instead of 0x7f.
-	*/
-	const (
-		ihdr = "\x00\x00\x00\x0dIHDR\x00\x00\x00\x01\x00\x00\x00\x01\x08\x03\x00\x00\x00\x28\xcb\x34\xbb"
-		plte = "\x00\x00\x00\x03PLTE\xff\x00\x00\x19\xe2\x09\x37"
-		trns = "\x00\x00\x00\x01tRNS\x7f\x80\x5c\xb4\xcb"
-		idat = "\x00\x00\x00\x0eIDAT\x78\x9c\x62\x62\x00\x04\x00\x00\xff\xff\x00\x06\x00\x03\xfa\xd0\x59\xae"
-		iend = "\x00\x00\x00\x00IEND\xae\x42\x60\x82"
-	)
-	for i := 0; i < 4; i++ {
-		var b []byte
-		b = append(b, pngHeader...)
-		b = append(b, ihdr...)
-		b = append(b, plte...)
-		for j := 0; j < i; j++ {
-			b = append(b, trns...)
-		}
-		b = append(b, idat...)
-		b = append(b, iend...)
-
-		var want color.Color
-		m, err := Decode(bytes.NewReader(b))
-		switch i {
-		case 0:
-			if err != nil {
-				t.Errorf("%d tRNS chunks: %v", i, err)
-				continue
-			}
-			want = color.RGBA{0xff, 0x00, 0x00, 0xff}
-		case 1:
-			if err != nil {
-				t.Errorf("%d tRNS chunks: %v", i, err)
-				continue
-			}
-			want = color.NRGBA{0xff, 0x00, 0x00, 0x7f}
-		default:
-			if err == nil {
-				t.Errorf("%d tRNS chunks: got nil error, want non-nil", i)
-			}
-			continue
-		}
-		if got := m.At(0, 0); got != want {
-			t.Errorf("%d tRNS chunks: got %T %v, want %T %v", i, got, got, want, want)
-		}
-	}
-}
-
 func benchmarkDecode(b *testing.B, filename string, bytesPerPixel int) {
 	b.StopTimer()
 	data, err := ioutil.ReadFile(filename)
diff --git a/src/image/ycbcr.go b/src/image/ycbcr.go
index 93c354b..7c773f2 100644
--- a/src/image/ycbcr.go
+++ b/src/image/ycbcr.go
@@ -16,8 +16,6 @@ const (
 	YCbCrSubsampleRatio422
 	YCbCrSubsampleRatio420
 	YCbCrSubsampleRatio440
-	YCbCrSubsampleRatio411
-	YCbCrSubsampleRatio410
 )
 
 func (s YCbCrSubsampleRatio) String() string {
@@ -30,10 +28,6 @@ func (s YCbCrSubsampleRatio) String() string {
 		return "YCbCrSubsampleRatio420"
 	case YCbCrSubsampleRatio440:
 		return "YCbCrSubsampleRatio440"
-	case YCbCrSubsampleRatio411:
-		return "YCbCrSubsampleRatio411"
-	case YCbCrSubsampleRatio410:
-		return "YCbCrSubsampleRatio410"
 	}
 	return "YCbCrSubsampleRatioUnknown"
 }
@@ -49,8 +43,6 @@ func (s YCbCrSubsampleRatio) String() string {
 //	For 4:2:2, CStride == YStride/2 && len(Cb) == len(Cr) == len(Y)/2.
 //	For 4:2:0, CStride == YStride/2 && len(Cb) == len(Cr) == len(Y)/4.
 //	For 4:4:0, CStride == YStride/1 && len(Cb) == len(Cr) == len(Y)/2.
-//	For 4:1:1, CStride == YStride/4 && len(Cb) == len(Cr) == len(Y)/4.
-//	For 4:1:0, CStride == YStride/4 && len(Cb) == len(Cr) == len(Y)/8.
 type YCbCr struct {
 	Y, Cb, Cr      []uint8
 	YStride        int
@@ -100,10 +92,6 @@ func (p *YCbCr) COffset(x, y int) int {
 		return (y/2-p.Rect.Min.Y/2)*p.CStride + (x/2 - p.Rect.Min.X/2)
 	case YCbCrSubsampleRatio440:
 		return (y/2-p.Rect.Min.Y/2)*p.CStride + (x - p.Rect.Min.X)
-	case YCbCrSubsampleRatio411:
-		return (y-p.Rect.Min.Y)*p.CStride + (x/4 - p.Rect.Min.X/4)
-	case YCbCrSubsampleRatio410:
-		return (y/2-p.Rect.Min.Y/2)*p.CStride + (x/4 - p.Rect.Min.X/4)
 	}
 	// Default to 4:4:4 subsampling.
 	return (y-p.Rect.Min.Y)*p.CStride + (x - p.Rect.Min.X)
@@ -151,25 +139,16 @@ func NewYCbCr(r Rectangle, subsampleRatio YCbCrSubsampleRatio) *YCbCr {
 	case YCbCrSubsampleRatio440:
 		cw = w
 		ch = (r.Max.Y+1)/2 - r.Min.Y/2
-	case YCbCrSubsampleRatio411:
-		cw = (r.Max.X+3)/4 - r.Min.X/4
-		ch = h
-	case YCbCrSubsampleRatio410:
-		cw = (r.Max.X+3)/4 - r.Min.X/4
-		ch = (r.Max.Y+1)/2 - r.Min.Y/2
 	default:
 		// Default to 4:4:4 subsampling.
 		cw = w
 		ch = h
 	}
-	i0 := w*h + 0*cw*ch
-	i1 := w*h + 1*cw*ch
-	i2 := w*h + 2*cw*ch
-	b := make([]byte, i2)
+	b := make([]byte, w*h+2*cw*ch)
 	return &YCbCr{
-		Y:              b[:i0:i0],
-		Cb:             b[i0:i1:i1],
-		Cr:             b[i1:i2:i2],
+		Y:              b[:w*h],
+		Cb:             b[w*h+0*cw*ch : w*h+1*cw*ch],
+		Cr:             b[w*h+1*cw*ch : w*h+2*cw*ch],
 		SubsampleRatio: subsampleRatio,
 		YStride:        w,
 		CStride:        cw,
diff --git a/src/image/ycbcr_test.go b/src/image/ycbcr_test.go
index 4996bc8..a5f4482 100644
--- a/src/image/ycbcr_test.go
+++ b/src/image/ycbcr_test.go
@@ -37,8 +37,6 @@ func TestYCbCr(t *testing.T) {
 		YCbCrSubsampleRatio422,
 		YCbCrSubsampleRatio420,
 		YCbCrSubsampleRatio440,
-		YCbCrSubsampleRatio411,
-		YCbCrSubsampleRatio410,
 	}
 	deltas := []Point{
 		Pt(0, 0),
@@ -107,27 +105,3 @@ func testYCbCr(t *testing.T, r Rectangle, subsampleRatio YCbCrSubsampleRatio, de
 		}
 	}
 }
-
-func TestYCbCrSlicesDontOverlap(t *testing.T) {
-	m := NewYCbCr(Rect(0, 0, 8, 8), YCbCrSubsampleRatio420)
-	names := []string{"Y", "Cb", "Cr"}
-	slices := [][]byte{
-		m.Y[:cap(m.Y)],
-		m.Cb[:cap(m.Cb)],
-		m.Cr[:cap(m.Cr)],
-	}
-	for i, slice := range slices {
-		want := uint8(10 + i)
-		for j := range slice {
-			slice[j] = want
-		}
-	}
-	for i, slice := range slices {
-		want := uint8(10 + i)
-		for j, got := range slice {
-			if got != want {
-				t.Fatalf("m.%s[%d]: got %d, want %d", names[i], j, got, want)
-			}
-		}
-	}
-}
diff --git a/src/internal/syscall/getrandom_linux.go b/src/internal/syscall/getrandom_linux.go
new file mode 100644
index 0000000..944bab3
--- /dev/null
+++ b/src/internal/syscall/getrandom_linux.go
@@ -0,0 +1,56 @@
+// 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 (
+	"runtime"
+	"sync/atomic"
+	stdsyscall "syscall"
+	"unsafe"
+)
+
+var randomTrap = map[string]uintptr{
+	"386":   355,
+	"amd64": 318,
+	"arm":   384,
+}[runtime.GOARCH]
+
+var randomUnsupported int32 // atomic
+
+// GetRandomFlag is a flag supported by the getrandom system call.
+type GetRandomFlag uintptr
+
+const (
+	// GRND_NONBLOCK means return EAGAIN rather than blocking.
+	GRND_NONBLOCK GetRandomFlag = 0x0001
+
+	// GRND_RANDOM means use the /dev/random pool instead of /dev/urandom.
+	GRND_RANDOM GetRandomFlag = 0x0002
+)
+
+// GetRandom calls the Linux getrandom system call.
+// See https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=c6e9d6f38894798696f23c8084ca7edbf16ee895
+func GetRandom(p []byte, flags GetRandomFlag) (n int, err error) {
+	if randomTrap == 0 {
+		return 0, stdsyscall.ENOSYS
+	}
+	if len(p) == 0 {
+		return 0, nil
+	}
+	if atomic.LoadInt32(&randomUnsupported) != 0 {
+		return 0, stdsyscall.ENOSYS
+	}
+	r1, _, errno := stdsyscall.Syscall(randomTrap,
+		uintptr(unsafe.Pointer(&p[0])),
+		uintptr(len(p)),
+		uintptr(flags))
+	if errno != 0 {
+		if errno == stdsyscall.ENOSYS {
+			atomic.StoreInt32(&randomUnsupported, 1)
+		}
+		return 0, errno
+	}
+	return int(r1), nil
+}
diff --git a/src/io/io.go b/src/io/io.go
index 8851eaf..7507a84 100644
--- a/src/io/io.go
+++ b/src/io/io.go
@@ -54,7 +54,7 @@ var ErrNoProgress = errors.New("multiple Read calls return no data or error")
 // An instance of this general case is that a Reader returning
 // a non-zero number of bytes at the end of the input stream may
 // return either err == EOF or err == nil.  The next Read should
-// return 0, EOF.
+// return 0, EOF regardless.
 //
 // Callers should always process the n > 0 bytes returned before
 // considering the error err.  Doing so correctly handles I/O errors
@@ -273,8 +273,8 @@ type stringWriter interface {
 	WriteString(s string) (n int, err error)
 }
 
-// WriteString writes the contents of the string s to w, which accepts a slice of bytes.
-// If w implements a WriteString method, it is invoked directly.
+// WriteString writes the contents of the string s to w, which accepts an array of bytes.
+// If w already implements a WriteString method, it is invoked directly.
 func WriteString(w Writer, s string) (n int, err error) {
 	if sw, ok := w.(stringWriter); ok {
 		return sw.WriteString(s)
@@ -348,23 +348,6 @@ func CopyN(dst Writer, src Reader, n int64) (written int64, err error) {
 // Otherwise, if dst implements the ReaderFrom interface,
 // the copy is implemented by calling dst.ReadFrom(src).
 func Copy(dst Writer, src Reader) (written int64, err error) {
-	return copyBuffer(dst, src, nil)
-}
-
-// CopyBuffer is identical to Copy except that it stages through the
-// provided buffer (if one is required) rather than allocating a
-// temporary one. If buf is nil, one is allocated; otherwise if it has
-// zero length, CopyBuffer panics.
-func CopyBuffer(dst Writer, src Reader, buf []byte) (written int64, err error) {
-	if buf != nil && len(buf) == 0 {
-		panic("empty buffer in io.CopyBuffer")
-	}
-	return copyBuffer(dst, src, buf)
-}
-
-// copyBuffer is the actual implementation of Copy and CopyBuffer.
-// if buf is nil, one is allocated.
-func copyBuffer(dst Writer, src Reader, buf []byte) (written int64, err error) {
 	// If the reader has a WriteTo method, use it to do the copy.
 	// Avoids an allocation and a copy.
 	if wt, ok := src.(WriterTo); ok {
@@ -374,9 +357,7 @@ func copyBuffer(dst Writer, src Reader, buf []byte) (written int64, err error) {
 	if rt, ok := dst.(ReaderFrom); ok {
 		return rt.ReadFrom(src)
 	}
-	if buf == nil {
-		buf = make([]byte, 32*1024)
-	}
+	buf := make([]byte, 32*1024)
 	for {
 		nr, er := src.Read(buf)
 		if nr > 0 {
diff --git a/src/io/io_test.go b/src/io/io_test.go
index e892574..57db1fb 100644
--- a/src/io/io_test.go
+++ b/src/io/io_test.go
@@ -20,7 +20,7 @@ type Buffer struct {
 	WriterTo   // conflicts with and hides bytes.Buffer's WriterTo.
 }
 
-// Simple tests, primarily to verify the ReadFrom and WriteTo callouts inside Copy, CopyBuffer and CopyN.
+// Simple tests, primarily to verify the ReadFrom and WriteTo callouts inside Copy and CopyN.
 
 func TestCopy(t *testing.T) {
 	rb := new(Buffer)
@@ -32,26 +32,6 @@ func TestCopy(t *testing.T) {
 	}
 }
 
-func TestCopyBuffer(t *testing.T) {
-	rb := new(Buffer)
-	wb := new(Buffer)
-	rb.WriteString("hello, world.")
-	CopyBuffer(wb, rb, make([]byte, 1)) // Tiny buffer to keep it honest.
-	if wb.String() != "hello, world." {
-		t.Errorf("CopyBuffer did not work properly")
-	}
-}
-
-func TestCopyBufferNil(t *testing.T) {
-	rb := new(Buffer)
-	wb := new(Buffer)
-	rb.WriteString("hello, world.")
-	CopyBuffer(wb, rb, nil) // Should allocate a buffer.
-	if wb.String() != "hello, world." {
-		t.Errorf("CopyBuffer did not work properly")
-	}
-}
-
 func TestCopyReadFrom(t *testing.T) {
 	rb := new(Buffer)
 	wb := new(bytes.Buffer) // implements ReadFrom.
@@ -98,34 +78,6 @@ func TestCopyPriority(t *testing.T) {
 	}
 }
 
-type zeroErrReader struct {
-	err error
-}
-
-func (r zeroErrReader) Read(p []byte) (int, error) {
-	return copy(p, []byte{0}), r.err
-}
-
-type errWriter struct {
-	err error
-}
-
-func (w errWriter) Write([]byte) (int, error) {
-	return 0, w.err
-}
-
-// In case a Read results in an error with non-zero bytes read, and
-// the subsequent Write also results in an error, the error from Write
-// is returned, as it is the one that prevented progressing further.
-func TestCopyReadErrWriteErr(t *testing.T) {
-	er, ew := errors.New("readError"), errors.New("writeError")
-	r, w := zeroErrReader{err: er}, errWriter{err: ew}
-	n, err := Copy(w, r)
-	if n != 0 || err != ew {
-		t.Errorf("Copy(zeroErrReader, errWriter) = %d, %v; want 0, writeError", n, err)
-	}
-}
-
 func TestCopyN(t *testing.T) {
 	rb := new(Buffer)
 	wb := new(Buffer)
diff --git a/src/io/ioutil/tempfile.go b/src/io/ioutil/tempfile.go
index 61d4a7a..4a06e97 100644
--- a/src/io/ioutil/tempfile.go
+++ b/src/io/ioutil/tempfile.go
@@ -55,9 +55,7 @@ func TempFile(dir, prefix string) (f *os.File, err error) {
 		f, err = os.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0600)
 		if os.IsExist(err) {
 			if nconflict++; nconflict > 10 {
-				randmu.Lock()
 				rand = reseed()
-				randmu.Unlock()
 			}
 			continue
 		}
@@ -84,9 +82,7 @@ func TempDir(dir, prefix string) (name string, err error) {
 		err = os.Mkdir(try, 0700)
 		if os.IsExist(err) {
 			if nconflict++; nconflict > 10 {
-				randmu.Lock()
 				rand = reseed()
-				randmu.Unlock()
 			}
 			continue
 		}
diff --git a/src/io/pipe.go b/src/io/pipe.go
index 179515e..f65354a 100644
--- a/src/io/pipe.go
+++ b/src/io/pipe.go
@@ -168,10 +168,7 @@ func (w *PipeWriter) Close() error {
 }
 
 // CloseWithError closes the writer; subsequent reads from the
-// read half of the pipe will return no bytes and the error err,
-// or EOF if err is nil.
-//
-// CloseWithError always returns nil.
+// read half of the pipe will return no bytes and the error err.
 func (w *PipeWriter) CloseWithError(err error) error {
 	w.p.wclose(err)
 	return nil
diff --git a/src/lib9/Makefile b/src/lib9/Makefile
new file mode 100644
index 0000000..62aba5d
--- /dev/null
+++ b/src/lib9/Makefile
@@ -0,0 +1,5 @@
+# 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/lib9/_exits.c b/src/lib9/_exits.c
new file mode 100644
index 0000000..af55181
--- /dev/null
+++ b/src/lib9/_exits.c
@@ -0,0 +1,37 @@
+// +build !plan9
+
+/*
+Plan 9 from User Space src/lib9/_exits.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/_exits.c
+
+Copyright 2001-2007 Russ Cox.  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>
+
+void
+_exits(char *s)
+{
+	if(s == 0 || *s == 0)
+		_exit(0);
+	_exit(exitcode(s));
+}
diff --git a/src/lib9/_p9dir.c b/src/lib9/_p9dir.c
new file mode 100644
index 0000000..6b5a04e
--- /dev/null
+++ b/src/lib9/_p9dir.c
@@ -0,0 +1,184 @@
+// +build !plan9
+
+/*
+Plan 9 from User Space src/lib9/_p9dir.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/_p9dir.c
+
+Copyright 2001-2007 Russ Cox.  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>
+#define NOPLAN9DEFINES
+#include <libc.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+
+/*
+ * Caching the last group and passwd looked up is
+ * a significant win (stupidly enough) on most systems.
+ * It's not safe for threaded programs, but neither is using
+ * getpwnam in the first place, so I'm not too worried.
+ */
+int
+_p9dir(struct stat *lst, struct stat *st, char *name, Dir *d, char **str, char *estr)
+{
+	char *s;
+	char tmp[20];
+	int sz, fd;
+
+#ifdef _WIN32
+	USED(lst);
+#endif
+	fd = -1;
+	USED(fd);
+	sz = 0;
+	if(d)
+		memset(d, 0, sizeof *d);
+
+	/* name */
+	s = strrchr(name, '/');
+	if(s)
+		s++;
+	if(!s || !*s)
+		s = name;
+	if(*s == '/')
+		s++;
+	if(*s == 0)
+		s = "/";
+	if(d){
+		if(*str + strlen(s)+1 > estr)
+			d->name = "oops";
+		else{
+			strcpy(*str, s);
+			d->name = *str;
+			*str += strlen(*str)+1;
+		}
+	}
+	sz += (int)strlen(s)+1;
+
+	/* user */
+	snprint(tmp, sizeof tmp, "%d", (int)st->st_uid);
+	s = tmp;
+	sz += (int)strlen(s)+1;
+	if(d){
+		if(*str+strlen(s)+1 > estr)
+			d->uid = "oops";
+		else{
+			strcpy(*str, s);
+			d->uid = *str;
+			*str += strlen(*str)+1;
+		}
+	}
+
+	/* group */
+	snprint(tmp, sizeof tmp, "%d", (int)st->st_gid);
+	s = tmp;
+	sz += (int)strlen(s)+1;
+	if(d){
+		if(*str + strlen(s)+1 > estr)
+			d->gid = "oops";
+		else{
+			strcpy(*str, s);
+			d->gid = *str;
+			*str += strlen(*str)+1;
+		}
+	}
+
+	if(d){
+		d->type = 'M';
+
+		d->muid = "";
+		d->qid.path = ((uvlong)st->st_dev<<32) | st->st_ino;
+#ifdef _HAVESTGEN
+		d->qid.vers = st->st_gen;
+#endif
+		if(d->qid.vers == 0)
+			d->qid.vers = (ulong)(st->st_mtime + st->st_ctime);
+		d->mode = st->st_mode&0777;
+		d->atime = (ulong)st->st_atime;
+		d->mtime = (ulong)st->st_mtime;
+		d->length = st->st_size;
+
+		if(S_ISDIR(st->st_mode)){
+			d->length = 0;
+			d->mode |= DMDIR;
+			d->qid.type = QTDIR;
+		}
+#ifdef S_ISLNK
+		if(S_ISLNK(lst->st_mode))	/* yes, lst not st */
+			d->mode |= DMSYMLINK;
+#endif
+		if(S_ISFIFO(st->st_mode))
+			d->mode |= DMNAMEDPIPE;
+#ifdef S_ISSOCK
+		if(S_ISSOCK(st->st_mode))
+			d->mode |= DMSOCKET;
+#endif
+		if(S_ISBLK(st->st_mode)){
+			d->mode |= DMDEVICE;
+			d->qid.path = ('b'<<16)|st->st_rdev;
+		}
+		if(S_ISCHR(st->st_mode)){
+			d->mode |= DMDEVICE;
+			d->qid.path = ('c'<<16)|st->st_rdev;
+		}
+		/* fetch real size for disks */
+		if(S_ISBLK(st->st_mode) && (fd = open(name, O_RDONLY)) >= 0){
+			d->length = 0;
+			close(fd);
+		}
+#if defined(DIOCGMEDIASIZE)
+		if(isdisk(st)){
+			int fd;
+			off_t mediasize;
+
+			if((fd = open(name, O_RDONLY)) >= 0){
+				if(ioctl(fd, DIOCGMEDIASIZE, &mediasize) >= 0)
+					d->length = mediasize;
+				close(fd);
+			}
+		}
+#elif defined(_HAVEDISKLABEL)
+		if(isdisk(st)){
+			int fd, n;
+			struct disklabel lab;
+
+			if((fd = open(name, O_RDONLY)) < 0)
+				goto nosize;
+			if(ioctl(fd, DIOCGDINFO, &lab) < 0)
+				goto nosize;
+			n = minor(st->st_rdev)&7;
+			if(n >= lab.d_npartitions)
+				goto nosize;
+
+			d->length = (vlong)(lab.d_partitions[n].p_size) * lab.d_secsize;
+
+		nosize:
+			if(fd >= 0)
+				close(fd);
+		}
+#endif
+	}
+
+	return sz;
+}
+
diff --git a/src/lib9/atoi.c b/src/lib9/atoi.c
new file mode 100644
index 0000000..5b002df
--- /dev/null
+++ b/src/lib9/atoi.c
@@ -0,0 +1,47 @@
+// +build !plan9
+
+/*
+Plan 9 from User Space src/lib9/ato*.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/atoi.c
+
+Copyright 2001-2007 Russ Cox.  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>
+
+int
+atoi(char *s)
+{
+	return (int)strtol(s, 0, 0);
+}
+
+long
+atol(char *s)
+{
+	return strtol(s, 0, 0);
+}
+
+vlong
+atoll(char *s)
+{
+	return strtoll(s, 0, 0);
+}
diff --git a/src/lib9/await.c b/src/lib9/await.c
new file mode 100644
index 0000000..dfb155b
--- /dev/null
+++ b/src/lib9/await.c
@@ -0,0 +1,182 @@
+// +build !plan9
+// +build !windows
+
+/*
+Plan 9 from User Space src/lib9/await.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/await.c
+
+Copyright 2001-2007 Russ Cox.  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.
+*/
+
+#define NOPLAN9DEFINES
+#include <u.h>
+#include <libc.h>
+
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+#ifndef WCOREDUMP	/* not on Mac OS X Tiger */
+#define WCOREDUMP(status) 0
+#endif
+
+static struct {
+	int sig;
+	char *str;
+} tab[] = {
+	SIGHUP,		"hangup",
+	SIGINT,		"interrupt",
+	SIGQUIT,		"quit",
+	SIGILL,		"sys: illegal instruction",
+	SIGTRAP,		"sys: breakpoint",
+	SIGABRT,		"sys: abort",
+#ifdef SIGEMT
+	SIGEMT,		"sys: emulate instruction executed",
+#endif
+	SIGFPE,		"sys: fp: trap",
+	SIGKILL,		"sys: kill",
+	SIGBUS,		"sys: bus error",
+	SIGSEGV,		"sys: segmentation violation",
+	SIGALRM,		"alarm",
+	SIGTERM,		"kill",
+	SIGURG,		"sys: urgent condition on socket",
+	SIGSTOP,		"sys: stop",
+	SIGTSTP,		"sys: tstp",
+	SIGCONT,		"sys: cont",
+	SIGCHLD,		"sys: child",
+	SIGTTIN,		"sys: ttin",
+	SIGTTOU,		"sys: ttou",
+#ifdef SIGIO	/* not on Mac OS X Tiger */
+	SIGIO,		"sys: i/o possible on fd",
+#endif
+	SIGXCPU,		"sys: cpu time limit exceeded",
+	SIGXFSZ,		"sys: file size limit exceeded",
+	SIGVTALRM,	"sys: virtual time alarm",
+	SIGPROF,		"sys: profiling timer alarm",
+#ifdef SIGWINCH	/* not on Mac OS X Tiger */
+	SIGWINCH,	"sys: window size change",
+#endif
+#ifdef SIGINFO
+	SIGINFO,		"sys: status request",
+#endif
+	SIGUSR1,		"sys: usr1",
+	SIGUSR2,		"sys: usr2",
+	SIGPIPE,		"sys: write on closed pipe",
+};
+
+char*
+_p9sigstr(int sig, char *tmp)
+{
+	int i;
+
+	for(i=0; i<nelem(tab); i++)
+		if(tab[i].sig == sig)
+			return tab[i].str;
+	if(tmp == nil)
+		return nil;
+	sprint(tmp, "sys: signal %d", sig);
+	return tmp;
+}
+
+int
+_p9strsig(char *s)
+{
+	int i;
+
+	for(i=0; i<nelem(tab); i++)
+		if(strcmp(s, tab[i].str) == 0)
+			return tab[i].sig;
+	return 0;
+}
+
+static Waitmsg*
+_wait(int pid4, int opt)
+{
+	int pid, status, cd;
+	struct rusage ru;
+	char tmp[64];
+	ulong u, s;
+	Waitmsg *w;
+
+	w = malloc(sizeof *w + 200);
+	if(w == nil)
+		return nil;
+	memset(w, 0, sizeof *w);
+	w->msg = (char*)&w[1];
+
+	for(;;){
+		/* On Linux, pid==-1 means anyone; on SunOS, it's pid==0. */
+		if(pid4 == -1)
+			pid = wait3(&status, opt, &ru);
+		else
+			pid = wait4(pid4, &status, opt, &ru);
+		if(pid <= 0) {
+			free(w);
+			return nil;
+		}
+		u = (ulong)(ru.ru_utime.tv_sec*1000+((ru.ru_utime.tv_usec+500)/1000));
+		s = (ulong)(ru.ru_stime.tv_sec*1000+((ru.ru_stime.tv_usec+500)/1000));
+		w->pid = pid;
+		w->time[0] = u;
+		w->time[1] = s;
+		w->time[2] = u+s;
+		if(WIFEXITED(status)){
+			if(status)
+				sprint(w->msg, "%d", status);
+			return w;
+		}
+		if(WIFSIGNALED(status)){
+			cd = WCOREDUMP(status);
+			sprint(w->msg, "signal: %s", _p9sigstr(WTERMSIG(status), tmp));
+			if(cd)
+				strcat(w->msg, " (core dumped)");
+			return w;
+		}
+	}
+}
+
+Waitmsg*
+p9wait(void)
+{
+	return _wait(-1, 0);
+}
+
+Waitmsg*
+p9waitfor(int pid)
+{
+	return _wait(pid, 0);
+}
+
+Waitmsg*
+p9waitnohang(void)
+{
+	return _wait(-1, WNOHANG);
+}
+
+int
+p9waitpid(void)
+{
+	int status;
+	return wait(&status);
+}
diff --git a/src/lib9/cleanname.c b/src/lib9/cleanname.c
new file mode 100644
index 0000000..cb8fce6
--- /dev/null
+++ b/src/lib9/cleanname.c
@@ -0,0 +1,80 @@
+// +build !plan9
+
+/*
+Inferno libkern/cleanname.c
+http://code.google.com/p/inferno-os/source/browse/libkern/cleanname.c
+
+	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+	Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).  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>
+
+/*
+ * In place, rewrite name to compress multiple /, eliminate ., and process ..
+ */
+#define SEP(x)	((x)=='/' || (x) == 0)
+char*
+cleanname(char *name)
+{
+	char *p, *q, *dotdot;
+	int rooted;
+
+	rooted = name[0] == '/';
+
+	/*
+	 * invariants:
+	 *	p points at beginning of path element we're considering.
+	 *	q points just past the last path element we wrote (no slash).
+	 *	dotdot points just past the point where .. cannot backtrack
+	 *		any further (no slash).
+	 */
+	p = q = dotdot = name+rooted;
+	while(*p) {
+		if(p[0] == '/')	/* null element */
+			p++;
+		else if(p[0] == '.' && SEP(p[1]))
+			p += 1;	/* don't count the separator in case it is nul */
+		else if(p[0] == '.' && p[1] == '.' && SEP(p[2])) {
+			p += 2;
+			if(q > dotdot) {	/* can backtrack */
+				while(--q > dotdot && *q != '/')
+					;
+			} else if(!rooted) {	/* /.. is / but ./../ is .. */
+				if(q != name)
+					*q++ = '/';
+				*q++ = '.';
+				*q++ = '.';
+				dotdot = q;
+			}
+		} else {	/* real path element */
+			if(q != name+rooted)
+				*q++ = '/';
+			while((*q = *p) != '/' && *q != 0)
+				p++, q++;
+		}
+	}
+	if(q == name)	/* empty string is really ``.'' */
+		*q++ = '.';
+	*q = '\0';
+	return name;
+}
diff --git a/src/lib9/create.c b/src/lib9/create.c
new file mode 100644
index 0000000..4ac7f7d
--- /dev/null
+++ b/src/lib9/create.c
@@ -0,0 +1,85 @@
+// +build !plan9
+
+/*
+Plan 9 from User Space src/lib9/create.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/create.c
+
+Copyright 2001-2007 Russ Cox.  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 _GNU_SOURCE	/* for Linux O_DIRECT */
+#include <u.h>
+#define NOPLAN9DEFINES
+#include <sys/file.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <libc.h>
+#include <sys/stat.h>
+#ifndef O_DIRECT
+#define O_DIRECT 0
+#endif
+
+int
+p9create(char *path, int mode, ulong perm)
+{
+	int fd, umode, rclose;
+
+	rclose = mode&ORCLOSE;
+	mode &= ~ORCLOSE;
+
+	/* XXX should get mode mask right? */
+	fd = -1;
+	if(perm&DMDIR){
+		if(mode != OREAD){
+			werrstr("bad mode in directory create");
+			goto out;
+		}
+		if(mkdir(path, perm&0777) < 0)
+			goto out;
+		fd = open(path, O_RDONLY);
+	}else{
+		umode = (mode&3)|O_CREAT|O_TRUNC;
+		mode &= ~(3|OTRUNC);
+		if(mode&ODIRECT){
+			umode |= O_DIRECT;
+			mode &= ~ODIRECT;
+		}
+		if(mode&OEXCL){
+			umode |= O_EXCL;
+			mode &= ~OEXCL;
+		}
+		if(mode&OAPPEND){
+			umode |= O_APPEND;
+			mode &= ~OAPPEND;
+		}
+		if(mode){
+			werrstr("unsupported mode in create");
+			goto out;
+		}
+		umode |= O_BINARY;
+		fd = open(path, umode, perm);
+	}
+out:
+	if(fd >= 0){
+		if(rclose)
+			remove(path);
+	}
+	return fd;
+}
diff --git a/src/lib9/ctime.c b/src/lib9/ctime.c
new file mode 100644
index 0000000..e16ad4a
--- /dev/null
+++ b/src/lib9/ctime.c
@@ -0,0 +1,30 @@
+// 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 !plan9
+
+#define NOPLAN9DEFINES
+#include <u.h>
+#include <libc.h>
+
+char*
+p9ctime(long t)
+{
+	static char buf[100];
+	time_t tt;
+	struct tm *tm;
+	
+	tt = t;
+	tm = localtime(&tt);
+	snprint(buf, sizeof buf, "%3.3s %3.3s %02d %02d:%02d:%02d %3.3s %d\n",
+		&"SunMonTueWedThuFriSat"[tm->tm_wday*3],
+		&"JanFebMarAprMayJunJulAugSepOctNovDec"[tm->tm_mon*3],
+		tm->tm_mday,
+		tm->tm_hour,
+		tm->tm_min,
+		tm->tm_sec,
+		"XXX",  // tm_zone is unavailable on windows, and no one cares
+		tm->tm_year + 1900);
+	return buf;
+}
diff --git a/src/lib9/dirfstat.c b/src/lib9/dirfstat.c
new file mode 100644
index 0000000..c092a2a
--- /dev/null
+++ b/src/lib9/dirfstat.c
@@ -0,0 +1,56 @@
+// +build !plan9
+
+/*
+Plan 9 from User Space src/lib9/dirfstat.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/dirfstat.c
+
+Copyright 2001-2007 Russ Cox.  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>
+#define NOPLAN9DEFINES
+#include <libc.h>
+
+#include <sys/stat.h>
+
+extern int _p9dir(struct stat*, struct stat*, char*, Dir*, char**, char*);
+
+Dir*
+dirfstat(int fd)
+{
+	struct stat st;
+	int nstr;
+	Dir *d;
+	char *str, tmp[100];
+
+	if(fstat(fd, &st) < 0)
+		return nil;
+
+	snprint(tmp, sizeof tmp, "/dev/fd/%d", fd);
+	nstr = _p9dir(&st, &st, tmp, nil, nil, nil);
+	d = malloc(sizeof(Dir)+(size_t)nstr);
+	if(d == nil)
+		return nil;
+	memset(d, 0, sizeof(Dir)+(size_t)nstr);
+	str = (char*)&d[1];
+	_p9dir(&st, &st, tmp, d, &str, str+nstr);
+	return d;
+}
+
diff --git a/src/lib9/dirfwstat.c b/src/lib9/dirfwstat.c
new file mode 100644
index 0000000..4666e21
--- /dev/null
+++ b/src/lib9/dirfwstat.c
@@ -0,0 +1,84 @@
+// +build !plan9
+
+/*
+Plan 9 from User Space src/lib9/dirfwstat.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/dirfwstat.c
+
+Copyright 2001-2007 Russ Cox.  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 NOPLAN9DEFINES
+#include <u.h>
+#include <libc.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+
+#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__OpenBSD__) || defined(__linux__)
+/* do nothing -- futimes exists and is fine */
+
+#elif defined(__SunOS5_9__)
+/* use futimesat */
+static int
+futimes(int fd, struct timeval *tv)
+{
+	return futimesat(fd, 0, tv);
+}
+
+#else
+/* provide dummy */
+/* rename just in case -- linux provides an unusable one */
+#undef futimes
+#define futimes myfutimes
+static int
+futimes(int fd, struct timeval *tv)
+{
+	USED(fd);
+	USED(tv);
+	werrstr("futimes not available");
+	return -1;
+}
+
+#endif
+
+int
+dirfwstat(int fd, Dir *dir)
+{
+	int ret;
+	struct timeval tv[2];
+
+	ret = 0;
+#ifndef _WIN32
+	if(~dir->mode != 0){
+		if(fchmod(fd, (mode_t)dir->mode) < 0)
+			ret = -1;
+	}
+#endif
+	if(~dir->mtime != 0){
+		tv[0].tv_sec = (time_t)dir->mtime;
+		tv[0].tv_usec = 0;
+		tv[1].tv_sec = (time_t)dir->mtime;
+		tv[1].tv_usec = 0;
+		if(futimes(fd, tv) < 0)
+			ret = -1;
+	}
+	return ret;
+}
+
diff --git a/src/lib9/dirstat.c b/src/lib9/dirstat.c
new file mode 100644
index 0000000..33f0d7c
--- /dev/null
+++ b/src/lib9/dirstat.c
@@ -0,0 +1,65 @@
+// +build !plan9
+
+/*
+Plan 9 from User Space src/lib9/dirstat.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/dirstat.c
+
+Copyright 2001-2007 Russ Cox.  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>
+#define NOPLAN9DEFINES
+#include <libc.h>
+
+#include <sys/stat.h>
+
+extern int _p9dir(struct stat*, struct stat*, char*, Dir*, char**, char*);
+
+Dir*
+dirstat(char *file)
+{
+	struct stat lst;
+	struct stat st;
+	int nstr;
+	Dir *d;
+	char *str;
+
+#ifdef _WIN32
+	if(stat(file, &st) < 0)
+		return nil;
+	lst = st;
+#else
+	if(lstat(file, &lst) < 0)
+		return nil;
+	st = lst;
+	if((lst.st_mode&S_IFMT) == S_IFLNK)
+		stat(file, &st);
+#endif
+
+	nstr = _p9dir(&lst, &st, file, nil, nil, nil);
+	d = malloc(sizeof(Dir)+(size_t)nstr);
+	if(d == nil)
+		return nil;
+	memset(d, 0, sizeof(Dir)+(size_t)nstr);
+	str = (char*)&d[1];
+	_p9dir(&lst, &st, file, d, &str, str+nstr);
+	return d;
+}
+
diff --git a/src/lib9/dirwstat.c b/src/lib9/dirwstat.c
new file mode 100644
index 0000000..22e25ff
--- /dev/null
+++ b/src/lib9/dirwstat.c
@@ -0,0 +1,45 @@
+// +build !plan9
+
+/*
+Plan 9 from User Space src/lib9/dirwstat.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/dirwstat.c
+
+Copyright 2001-2007 Russ Cox.  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>
+#define NOPLAN9DEFINES
+#include <libc.h>
+#include <sys/time.h>
+#include <utime.h>
+
+int
+dirwstat(char *file, Dir *dir)
+{
+	struct utimbuf ub;
+
+	/* BUG handle more */
+	if(~dir->mtime == 0)
+		return 0;
+
+	ub.actime = (time_t)dir->mtime;
+	ub.modtime = (time_t)dir->mtime;
+	return utime(file, &ub);
+}
diff --git a/src/lib9/dup.c b/src/lib9/dup.c
new file mode 100644
index 0000000..5cac831
--- /dev/null
+++ b/src/lib9/dup.c
@@ -0,0 +1,38 @@
+// +build !plan9
+
+/*
+Plan 9 from User Space src/lib9/dup.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/dup.c
+
+Copyright 2001-2007 Russ Cox.  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>
+
+#undef dup
+
+int
+p9dup(int old, int new)
+{
+	if(new == -1)
+		return dup(old);
+	return dup2(old, new);
+}
diff --git a/src/lib9/errstr.c b/src/lib9/errstr.c
new file mode 100644
index 0000000..9d91975
--- /dev/null
+++ b/src/lib9/errstr.c
@@ -0,0 +1,107 @@
+// +build !plan9
+
+/*
+Plan 9 from User Space src/lib9/errstr.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/errstr.c
+
+Copyright 2001-2007 Russ Cox.  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.
+*/
+
+/*
+ * We assume there's only one error buffer for the whole system.
+ * If you use ffork, you need to provide a _syserrstr.  Since most
+ * people will use libthread (which provides a _syserrstr), this is
+ * okay.
+ */
+
+#include <u.h>
+#include <errno.h>
+#include <libc.h>
+
+enum
+{
+	EPLAN9 = 0x19283745
+};
+
+char *(*_syserrstr)(void);
+static char xsyserr[ERRMAX];
+static char*
+getsyserr(void)
+{
+	char *s;
+
+	s = nil;
+	if(_syserrstr)
+		s = (*_syserrstr)();
+	if(s == nil)
+		s = xsyserr;
+	return s;
+}
+
+int
+errstr(char *err, uint n)
+{
+	char tmp[ERRMAX];
+	char *syserr;
+
+	strecpy(tmp, tmp+ERRMAX, err);
+	rerrstr(err, n);
+	syserr = getsyserr();
+	strecpy(syserr, syserr+ERRMAX, tmp);
+	errno = EPLAN9;
+	return 0;
+}
+
+void
+rerrstr(char *err, uint n)
+{
+	char *syserr;
+
+	syserr = getsyserr();
+	if(errno == EINTR)
+		strcpy(syserr, "interrupted");
+	else if(errno != EPLAN9)
+		strcpy(syserr, strerror(errno));
+	strecpy(err, err+n, syserr);
+}
+
+/* replaces __errfmt in libfmt */
+
+int
+__errfmt(Fmt *f)
+{
+	if(errno == EPLAN9)
+		return fmtstrcpy(f, getsyserr());
+	return fmtstrcpy(f, strerror(errno));
+}
+
+void
+werrstr(char *fmt, ...)
+{
+	va_list arg;
+	char buf[ERRMAX];
+
+	va_start(arg, fmt);
+	vseprint(buf, buf+ERRMAX, fmt, arg);
+	va_end(arg);
+	errstr(buf, ERRMAX);
+}
+
diff --git a/src/lib9/exec.c b/src/lib9/exec.c
new file mode 100644
index 0000000..8e5fc57
--- /dev/null
+++ b/src/lib9/exec.c
@@ -0,0 +1,35 @@
+// +build !plan9
+
+/*
+Plan 9 from User Space src/lib9/exec.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/exec.c
+
+Copyright 2001-2007 Russ Cox.  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>
+
+int
+exec(char *prog, char *argv[])
+{
+	/* to mimic plan 9 should be just exec, but execvp is a better fit for unix */
+	return execvp(prog, argv);
+}
diff --git a/src/lib9/execl.c b/src/lib9/execl.c
new file mode 100644
index 0000000..fd4d23d
--- /dev/null
+++ b/src/lib9/execl.c
@@ -0,0 +1,55 @@
+// +build !plan9
+
+/*
+Plan 9 from User Space src/lib9/execl.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/execl.c
+
+Copyright 2001-2007 Russ Cox.  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>
+
+int
+execl(char *prog, ...)
+{
+	int i;
+	va_list arg;
+	char **argv;
+
+	va_start(arg, prog);
+	for(i=0; va_arg(arg, char*) != nil; i++)
+		;
+	va_end(arg);
+
+	argv = malloc((size_t)(i+1)*sizeof(char*));
+	if(argv == nil)
+		return -1;
+
+	va_start(arg, prog);
+	for(i=0; (argv[i] = va_arg(arg, char*)) != nil; i++)
+		;
+	va_end(arg);
+
+	exec(prog, argv);
+	free(argv);
+	return -1;
+}
+
diff --git a/src/lib9/exitcode.c b/src/lib9/exitcode.c
new file mode 100644
index 0000000..fc86344
--- /dev/null
+++ b/src/lib9/exitcode.c
@@ -0,0 +1,37 @@
+// +build !plan9
+
+/*
+Plan 9 from User Space src/lib9/exitcode.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/exitcode.c
+
+Copyright 2001-2007 Russ Cox.  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>
+
+int
+exitcode(char *s)
+{
+	USED(s);
+	return 1;
+}
+
diff --git a/src/lib9/exits.c b/src/lib9/exits.c
new file mode 100644
index 0000000..0be7cb9
--- /dev/null
+++ b/src/lib9/exits.c
@@ -0,0 +1,36 @@
+// +build !plan9
+
+/*
+Plan 9 from User Space src/lib9/_exits.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/_exits.c
+
+Copyright 2001-2007 Russ Cox.  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>
+
+void
+exits(char *s)
+{
+	if(s == 0 || *s == 0)
+		exit(0);
+	exit(exitcode(s));
+}
diff --git a/src/lib9/flag.c b/src/lib9/flag.c
new file mode 100644
index 0000000..db46b98
--- /dev/null
+++ b/src/lib9/flag.c
@@ -0,0 +1,307 @@
+// 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 <u.h>
+#include <libc.h>
+
+// Flag hash.
+typedef struct Flag Flag;
+
+struct Flag
+{
+	char *name;
+	int namelen;
+	char *desc;
+	int iscount;
+	void (*set)(char*, void*);
+	void (*set2)(char*, char*, void*);
+	void *arg;
+	Flag *next;
+	Flag *allnext;
+};
+
+static Flag *curflag;
+
+static Flag *fhash[512];
+static Flag *first, *last;
+
+char *argv0;
+
+/*
+ * Mac OS can't deal with files that only declare data.
+ * ARGBEGIN mentions this function so that this file gets pulled in.
+ */
+void __fixargv0(void) { }
+
+// FNV-1 hash. http://isthe.com/chongo/tech/comp/fnv/
+static uint32
+fnv(char *p, int n)
+{
+	uint32 h;
+	
+	h = 2166136261U;
+	while(n-- > 0)
+		h = (h*16777619) ^ (uchar)*p++;
+	return h;
+}
+
+static Flag*
+lookflag(char *name, int namelen, int creat)
+{
+	uint32 h;
+	Flag *f;
+
+	h = fnv(name, namelen) & (nelem(fhash)-1);
+	for(f=fhash[h]; f; f=f->next) {
+		if(f->namelen == namelen && memcmp(f->name, name, (size_t)namelen) == 0) {
+			if(creat)
+				sysfatal("multiple definitions of flag -%s", name);
+			return f;
+		}
+	}
+	
+	if(!creat)
+		return nil;
+
+	f = malloc(sizeof *f);
+	if(f == nil)
+		sysfatal("out of memory");
+	memset(f, 0, sizeof *f);
+	f->name = name;
+	f->namelen = namelen;
+	f->next = fhash[h];
+	if(first == nil)
+		first = f;
+	else
+		last->allnext = f;
+	last = f;
+	fhash[h] = f;
+	return f;
+}
+
+static void
+count(char *arg, void *p)
+{
+	int *ip;
+	
+	ip = p;
+	if(arg != nil)
+		*ip = atoi(arg);
+	else
+		(*ip)++;
+}
+
+void
+flagcount(char *name, char *desc, int *p)
+{
+	Flag *f;
+	
+	f = lookflag(name, (int)strlen(name), 1);
+	f->desc = desc;
+	f->iscount = 1;
+	f->set = count;
+	f->arg = p;
+}
+
+static void
+atollwhex(char *s, void *p)
+{
+	char *t;
+
+	*(int64*)p = strtoll(s, &t, 0);
+	if(*s == '\0' || *t != '\0')
+		sysfatal("invalid numeric argument -%s=%s", curflag->name, s);
+}
+
+void
+flagint64(char *name, char *desc, int64 *p)
+{
+	Flag *f;
+	
+	f = lookflag(name, (int)strlen(name), 1);
+	f->desc = desc;
+	f->set = atollwhex;
+	f->arg = p;
+}
+
+static void
+atolwhex(char *s, void *p)
+{
+	char *t;
+
+	*(int32*)p = (int32)strtol(s, &t, 0);
+	if(*s == '\0' || *t != '\0')
+		sysfatal("invalid numeric argument -%s=%s", curflag->name, s);
+}
+
+void
+flagint32(char *name, char *desc, int32 *p)
+{
+	Flag *f;
+	
+	f = lookflag(name, (int)strlen(name), 1);
+	f->desc = desc;
+	f->set = atolwhex;
+	f->arg = p;
+}
+
+static void
+string(char *s, void *p)
+{
+	*(char**)p = s;
+}
+
+void
+flagstr(char *name, char *desc, char **p)
+{
+
+	Flag *f;
+	
+	f = lookflag(name, (int)strlen(name), 1);
+	f->desc = desc;
+	f->set = string;
+	f->arg = p;
+}	
+
+static void
+fn0(char *s, void *p)
+{
+	USED(s);
+	((void(*)(void))p)();
+}
+
+void
+flagfn0(char *name, char *desc, void (*fn)(void))
+{
+	Flag *f;
+	
+	f = lookflag(name, (int)strlen(name), 1);
+	f->desc = desc;
+	f->set = fn0;
+	f->arg = fn;
+	f->iscount = 1;
+}
+
+static void
+fn1(char *s, void *p)
+{
+	((void(*)(char*))p)(s);
+}
+
+void
+flagfn1(char *name, char *desc, void (*fn)(char*))
+{
+	Flag *f;
+	
+	f = lookflag(name, (int)strlen(name), 1);
+	f->desc = desc;
+	f->set = fn1;
+	f->arg = fn;
+}
+
+static void
+fn2(char *s, char *t, void *p)
+{
+	((void(*)(char*, char*))p)(s, t);
+}
+
+void
+flagfn2(char *name, char *desc, void (*fn)(char*, char*))
+{
+	Flag *f;
+	
+	f = lookflag(name, (int)strlen(name), 1);
+	f->desc = desc;
+	f->set2 = fn2;
+	f->arg = fn;
+}
+
+void
+flagparse(int *argcp, char ***argvp, void (*usage)(void))
+{
+	int argc;
+	char **argv, *p, *q;
+	char *name;
+	int namelen;
+	Flag *f;
+	
+	argc = *argcp;
+	argv = *argvp;
+
+	argv0 = argv[0];
+	argc--;
+	argv++;
+	
+	while(argc > 0) {
+		p = *argv;
+		// stop before non-flag or -
+		if(*p != '-' || p[1] == '\0')
+			break;
+		argc--;
+		argv++;
+		// stop after --
+		if(p[1] == '-' && p[2] == '\0') {
+			break;
+		}
+		
+		// turn --foo into -foo
+		if(p[1] == '-' && p[2] != '-')
+			p++;
+		
+		// allow -flag=arg if present
+		name = p+1;
+		q = strchr(name, '=');
+		if(q != nil)
+			namelen = (int)(q++ - name);
+		else
+			namelen = (int)strlen(name);
+		f = lookflag(name, namelen, 0);
+		if(f == nil) {
+			if(strcmp(p, "-h") == 0 || strcmp(p, "-help") == 0 || strcmp(p, "-?") == 0)
+				usage();
+			sysfatal("unknown flag %s", p);
+		}
+		curflag = f;
+
+		// otherwise consume next argument if non-boolean
+		if(!f->iscount && q == nil) {
+			if(argc-- == 0)
+				sysfatal("missing argument to flag %s", p);
+			q = *argv++;
+		}
+		
+		// and another if we need two
+		if(f->set2 != nil) {
+			if(argc-- == 0)
+				sysfatal("missing second argument to flag %s", p);
+			f->set2(q, *argv++, f->arg);
+			continue;
+		}
+
+		f->set(q, f->arg);			
+	}
+	
+	*argcp = argc;
+	*argvp = argv;		
+}
+
+void
+flagprint(int fd)
+{
+	Flag *f;
+	char *p, *q;
+	
+	for(f=first; f; f=f->allnext) {
+		p = f->desc;
+		if(p == nil || *p == '\0') // undocumented flag
+			continue;
+		q = strstr(p, ": ");
+		if(q)
+			fprint(fd, "  -%s %.*s\n    \t%s\n", f->name, utfnlen(p, q-p), p, q+2);
+		else if(f->namelen > 1)
+			fprint(fd, "  -%s\n    \t%s\n", f->name, p);
+		else
+			fprint(fd, "  -%s\t%s\n", f->name, p);
+	}
+}
diff --git a/src/lib9/fmt/charstod.c b/src/lib9/fmt/charstod.c
new file mode 100644
index 0000000..b8096e8
--- /dev/null
+++ b/src/lib9/fmt/charstod.c
@@ -0,0 +1,88 @@
+/*
+ * 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"
+
+/*
+ * Reads a floating-point number by interpreting successive characters
+ * returned by (*f)(vp).  The last call it makes to f terminates the
+ * scan, so is not a character in the number.  It may therefore be
+ * necessary to back up the input stream up one byte after calling charstod.
+ */
+
+double
+fmtcharstod(int(*f)(void*), void *vp)
+{
+	double num, dem;
+	int neg, eneg, dig, exp, c;
+
+	num = 0;
+	neg = 0;
+	dig = 0;
+	exp = 0;
+	eneg = 0;
+
+	c = (*f)(vp);
+	while(c == ' ' || c == '\t')
+		c = (*f)(vp);
+	if(c == '-' || c == '+'){
+		if(c == '-')
+			neg = 1;
+		c = (*f)(vp);
+	}
+	while(c >= '0' && c <= '9'){
+		num = num*10 + c-'0';
+		c = (*f)(vp);
+	}
+	if(c == '.')
+		c = (*f)(vp);
+	while(c >= '0' && c <= '9'){
+		num = num*10 + c-'0';
+		dig++;
+		c = (*f)(vp);
+	}
+	if(c == 'e' || c == 'E'){
+		c = (*f)(vp);
+		if(c == '-' || c == '+'){
+			if(c == '-'){
+				dig = -dig;
+				eneg = 1;
+			}
+			c = (*f)(vp);
+		}
+		while(c >= '0' && c <= '9'){
+			exp = exp*10 + c-'0';
+			c = (*f)(vp);
+		}
+	}
+	exp -= dig;
+	if(exp < 0){
+		exp = -exp;
+		eneg = !eneg;
+	}
+	dem = __fmtpow10(exp);
+	if(eneg)
+		num /= dem;
+	else
+		num *= dem;
+	if(neg)
+		return -num;
+	return num;
+}
diff --git a/src/lib9/fmt/dofmt.c b/src/lib9/fmt/dofmt.c
new file mode 100644
index 0000000..3b9dc36
--- /dev/null
+++ b/src/lib9/fmt/dofmt.c
@@ -0,0 +1,624 @@
+/*
+ * 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"
+
+/* format the output into f->to and return the number of characters fmted  */
+int
+dofmt(Fmt *f, char *fmt)
+{
+	Rune rune, *rt, *rs;
+	Rune r;
+	char *t, *s;
+	int n, nfmt;
+
+	nfmt = f->nfmt;
+	for(;;){
+		if(f->runes){
+			rt = (Rune*)f->to;
+			rs = (Rune*)f->stop;
+			while((r = (Rune)*(uchar*)fmt) && r != '%'){
+				if(r < Runeself)
+					fmt++;
+				else{
+					fmt += chartorune(&rune, fmt);
+					r = rune;
+				}
+				FMTRCHAR(f, rt, rs, r);
+			}
+			fmt++;
+			f->nfmt += (int)(rt - (Rune *)f->to);
+			f->to = rt;
+			if(!r)
+				return f->nfmt - nfmt;
+			f->stop = rs;
+		}else{
+			t = (char*)f->to;
+			s = (char*)f->stop;
+			while((r = (Rune)*(uchar*)fmt) && r != '%'){
+				if(r < Runeself){
+					FMTCHAR(f, t, s, r);
+					fmt++;
+				}else{
+					n = chartorune(&rune, fmt);
+					if(t + n > s){
+						t = (char*)__fmtflush(f, t, n);
+						if(t != nil)
+							s = (char*)f->stop;
+						else
+							return -1;
+					}
+					while(n--)
+						*t++ = *fmt++;
+				}
+			}
+			fmt++;
+			f->nfmt += (int)(t - (char *)f->to);
+			f->to = t;
+			if(!r)
+				return f->nfmt - nfmt;
+			f->stop = s;
+		}
+
+		fmt = (char*)__fmtdispatch(f, fmt, 0);
+		if(fmt == nil)
+			return -1;
+	}
+}
+
+void *
+__fmtflush(Fmt *f, void *t, int len)
+{
+	if(f->runes)
+		f->nfmt += (int)((Rune*)t - (Rune*)f->to);
+	else
+		f->nfmt += (int)((char*)t - (char *)f->to);
+	f->to = t;
+	if(f->flush == 0 || (*f->flush)(f) == 0 || (char*)f->to + len > (char*)f->stop){
+		f->stop = f->to;
+		return nil;
+	}
+	return f->to;
+}
+
+/*
+ * put a formatted block of memory sz bytes long of n runes into the output buffer,
+ * left/right justified in a field of at least f->width characters (if FmtWidth is set)
+ */
+int
+__fmtpad(Fmt *f, int n)
+{
+	char *t, *s;
+	int i;
+
+	t = (char*)f->to;
+	s = (char*)f->stop;
+	for(i = 0; i < n; i++)
+		FMTCHAR(f, t, s, ' ');
+	f->nfmt += (int)(t - (char *)f->to);
+	f->to = t;
+	return 0;
+}
+
+int
+__rfmtpad(Fmt *f, int n)
+{
+	Rune *t, *s;
+	int i;
+
+	t = (Rune*)f->to;
+	s = (Rune*)f->stop;
+	for(i = 0; i < n; i++)
+		FMTRCHAR(f, t, s, ' ');
+	f->nfmt += (int)(t - (Rune *)f->to);
+	f->to = t;
+	return 0;
+}
+
+int
+__fmtcpy(Fmt *f, const void *vm, int n, int sz)
+{
+	Rune *rt, *rs, r;
+	char *t, *s, *m, *me;
+	ulong fl;
+	int nc, w;
+
+	m = (char*)vm;
+	me = m + sz;
+	fl = f->flags;
+	w = 0;
+	if(fl & FmtWidth)
+		w = f->width;
+	if((fl & FmtPrec) && n > f->prec)
+		n = f->prec;
+	if(f->runes){
+		if(!(fl & FmtLeft) && __rfmtpad(f, w - n) < 0)
+			return -1;
+		rt = (Rune*)f->to;
+		rs = (Rune*)f->stop;
+		for(nc = n; nc > 0; nc--){
+			r = *(uchar*)m;
+			if(r < Runeself)
+				m++;
+			else if((me - m) >= UTFmax || fullrune(m, (int)(me-m)))
+				m += chartorune(&r, m);
+			else
+				break;
+			FMTRCHAR(f, rt, rs, r);
+		}
+		f->nfmt += (int)(rt - (Rune *)f->to);
+		f->to = rt;
+		if(fl & FmtLeft && __rfmtpad(f, w - n) < 0)
+			return -1;
+	}else{
+		if(!(fl & FmtLeft) && __fmtpad(f, w - n) < 0)
+			return -1;
+		t = (char*)f->to;
+		s = (char*)f->stop;
+		for(nc = n; nc > 0; nc--){
+			r = *(uchar*)m;
+			if(r < Runeself)
+				m++;
+			else if((me - m) >= UTFmax || fullrune(m, (int)(me-m)))
+				m += chartorune(&r, m);
+			else
+				break;
+			FMTRUNE(f, t, s, r);
+		}
+		f->nfmt += (int)(t - (char *)f->to);
+		f->to = t;
+		if(fl & FmtLeft && __fmtpad(f, w - n) < 0)
+			return -1;
+	}
+	return 0;
+}
+
+int
+__fmtrcpy(Fmt *f, const void *vm, int n)
+{
+	Rune r, *m, *me, *rt, *rs;
+	char *t, *s;
+	ulong fl;
+	int w;
+
+	m = (Rune*)vm;
+	fl = f->flags;
+	w = 0;
+	if(fl & FmtWidth)
+		w = f->width;
+	if((fl & FmtPrec) && n > f->prec)
+		n = f->prec;
+	if(f->runes){
+		if(!(fl & FmtLeft) && __rfmtpad(f, w - n) < 0)
+			return -1;
+		rt = (Rune*)f->to;
+		rs = (Rune*)f->stop;
+		for(me = m + n; m < me; m++)
+			FMTRCHAR(f, rt, rs, *m);
+		f->nfmt += (int)(rt - (Rune *)f->to);
+		f->to = rt;
+		if(fl & FmtLeft && __rfmtpad(f, w - n) < 0)
+			return -1;
+	}else{
+		if(!(fl & FmtLeft) && __fmtpad(f, w - n) < 0)
+			return -1;
+		t = (char*)f->to;
+		s = (char*)f->stop;
+		for(me = m + n; m < me; m++){
+			r = *m;
+			FMTRUNE(f, t, s, r);
+		}
+		f->nfmt += (int)(t - (char *)f->to);
+		f->to = t;
+		if(fl & FmtLeft && __fmtpad(f, w - n) < 0)
+			return -1;
+	}
+	return 0;
+}
+
+/* fmt out one character */
+int
+__charfmt(Fmt *f)
+{
+	char x[1];
+
+	x[0] = (char)va_arg(f->args, int);
+	f->prec = 1;
+	return __fmtcpy(f, (const char*)x, 1, 1);
+}
+
+/* fmt out one rune */
+int
+__runefmt(Fmt *f)
+{
+	Rune x[1];
+
+	x[0] = (Rune)va_arg(f->args, int);
+	return __fmtrcpy(f, (const void*)x, 1);
+}
+
+/* public helper routine: fmt out a null terminated string already in hand */
+int
+fmtstrcpy(Fmt *f, char *s)
+{
+	int i, j;
+
+	if(!s)
+		return __fmtcpy(f, "<nil>", 5, 5);
+	/* if precision is specified, make sure we don't wander off the end */
+	if(f->flags & FmtPrec){
+#ifdef PLAN9PORT
+		Rune r;
+		i = 0;
+		for(j=0; j<f->prec && s[i]; j++)
+			i += chartorune(&r, s+i);
+#else
+		/* ANSI requires precision in bytes, not Runes */
+		for(i=0; i<f->prec; i++)
+			if(s[i] == 0)
+				break;
+		j = utfnlen(s, i);	/* won't print partial at end */
+#endif
+		return __fmtcpy(f, s, j, i);
+	}
+	return __fmtcpy(f, s, utflen(s), (int)strlen(s));
+}
+
+/* fmt out a null terminated utf string */
+int
+__strfmt(Fmt *f)
+{
+	char *s;
+
+	s = va_arg(f->args, char *);
+	return fmtstrcpy(f, s);
+}
+
+/* public helper routine: fmt out a null terminated rune string already in hand */
+int
+fmtrunestrcpy(Fmt *f, Rune *s)
+{
+	Rune *e;
+	int n, p;
+
+	if(!s)
+		return __fmtcpy(f, "<nil>", 5, 5);
+	/* if precision is specified, make sure we don't wander off the end */
+	if(f->flags & FmtPrec){
+		p = f->prec;
+		for(n = 0; n < p; n++)
+			if(s[n] == 0)
+				break;
+	}else{
+		for(e = s; *e; e++)
+			;
+		n = (int)(e - s);
+	}
+	return __fmtrcpy(f, s, n);
+}
+
+/* fmt out a null terminated rune string */
+int
+__runesfmt(Fmt *f)
+{
+	Rune *s;
+
+	s = va_arg(f->args, Rune *);
+	return fmtrunestrcpy(f, s);
+}
+
+/* fmt a % */
+int
+__percentfmt(Fmt *f)
+{
+	Rune x[1];
+
+	x[0] = f->r;
+	f->prec = 1;
+	return __fmtrcpy(f, (const void*)x, 1);
+}
+
+/* fmt an integer */
+int
+__ifmt(Fmt *f)
+{
+	char buf[140], *p, *conv;
+	/* 140: for 64 bits of binary + 3-byte sep every 4 digits */
+	uvlong vu;
+	ulong fl, u;
+	int neg, base, i, n, w, isv;
+	int ndig, len, excess, bytelen;
+	char *grouping;
+	char *thousands;
+
+	neg = 0;
+	fl = f->flags;
+	isv = 0;
+	vu = 0;
+	u = 0;
+#ifndef PLAN9PORT
+	/*
+	 * Unsigned verbs for ANSI C
+	 */
+	switch(f->r){
+	case 'o':
+	case 'p':
+	case 'u':
+	case 'x':
+	case 'X':
+		fl |= FmtUnsigned;
+		fl &= ~(FmtSign|FmtSpace);
+		break;
+	}
+#endif
+	if(f->r == 'p'){
+		u = (uintptr)va_arg(f->args, void*);
+		f->r = 'x';
+		fl |= FmtUnsigned;
+	}else if(fl & FmtVLong){
+		isv = 1;
+		if(fl & FmtUnsigned)
+			vu = va_arg(f->args, uvlong);
+		else
+			vu = (uvlong)va_arg(f->args, vlong);
+	}else if(fl & FmtLong){
+		if(fl & FmtUnsigned)
+			u = va_arg(f->args, ulong);
+		else
+			u = (ulong)va_arg(f->args, long);
+	}else if(fl & FmtByte){
+		if(fl & FmtUnsigned)
+			u = (uchar)va_arg(f->args, int);
+		else
+			u = (ulong)(char)va_arg(f->args, int);
+	}else if(fl & FmtShort){
+		if(fl & FmtUnsigned)
+			u = (ushort)va_arg(f->args, int);
+		else
+			u = (ulong)(short)va_arg(f->args, int);
+	}else{
+		if(fl & FmtUnsigned)
+			u = va_arg(f->args, uint);
+		else
+			u = (ulong)va_arg(f->args, int);
+	}
+	conv = "0123456789abcdef";
+	grouping = "\4";	/* for hex, octal etc. (undefined by spec but nice) */
+	thousands = f->thousands;
+	switch(f->r){
+	case 'd':
+	case 'i':
+	case 'u':
+		base = 10;
+		grouping = f->grouping;
+		break;
+	case 'X':
+		conv = "0123456789ABCDEF";
+		/* fall through */
+	case 'x':
+		base = 16;
+		thousands = ":";
+		break;
+	case 'b':
+		base = 2;
+		thousands = ":";
+		break;
+	case 'o':
+		base = 8;
+		break;
+	default:
+		return -1;
+	}
+	if(!(fl & FmtUnsigned)){
+		if(isv && (vlong)vu < 0){
+			vu = (uvlong)-(vlong)vu;
+			neg = 1;
+		}else if(!isv && (long)u < 0){
+			u = (ulong)-(long)u;
+			neg = 1;
+		}
+	}
+	p = buf + sizeof buf - 1;
+	n = 0;	/* in runes */
+	excess = 0;	/* number of bytes > number runes */
+	ndig = 0;
+	len = utflen(thousands);
+	bytelen = (int)strlen(thousands);
+	if(isv){
+		while(vu){
+			i = (int)(vu % (uvlong)base);
+			vu /= (uvlong)base;
+			if((fl & FmtComma) && n % 4 == 3){
+				*p-- = ',';
+				n++;
+			}
+			if((fl & FmtApost) && __needsep(&ndig, &grouping)){
+				n += len;
+				excess += bytelen - len;
+				p -= bytelen;
+				memmove(p+1, thousands, (size_t)bytelen);
+			}
+			*p-- = conv[i];
+			n++;
+		}
+	}else{
+		while(u){
+			i = (int)(u % (ulong)base);
+			u /= (ulong)base;
+			if((fl & FmtComma) && n % 4 == 3){
+				*p-- = ',';
+				n++;
+			}
+			if((fl & FmtApost) && __needsep(&ndig, &grouping)){
+				n += len;
+				excess += bytelen - len;
+				p -= bytelen;
+				memmove(p+1, thousands, (size_t)bytelen);
+			}
+			*p-- = conv[i];
+			n++;
+		}
+	}
+	if(n == 0){
+		/*
+		 * "The result of converting a zero value with
+		 * a precision of zero is no characters."  - ANSI
+		 *
+		 * "For o conversion, # increases the precision, if and only if
+		 * necessary, to force the first digit of the result to be a zero
+		 * (if the value and precision are both 0, a single 0 is printed)." - ANSI
+		 */
+		if(!(fl & FmtPrec) || f->prec != 0 || (f->r == 'o' && (fl & FmtSharp))){
+			*p-- = '0';
+			n = 1;
+			if(fl & FmtApost)
+				__needsep(&ndig, &grouping);
+		}
+	}
+	for(w = f->prec; n < w && p > buf+3; n++){
+		if((fl & FmtApost) && __needsep(&ndig, &grouping)){
+			n += len;
+			excess += bytelen - len;
+			p -= bytelen;
+			memmove(p+1, thousands, (size_t)bytelen);
+		}
+		*p-- = '0';
+	}
+	if(neg || (fl & (FmtSign|FmtSpace)))
+		n++;
+	if(fl & FmtSharp){
+		if(base == 16)
+			n += 2;
+		else if(base == 8){
+			if(p[1] == '0')
+				fl &= ~(ulong)FmtSharp;
+			else
+				n++;
+		}
+	}
+	if((fl & FmtZero) && !(fl & (FmtLeft|FmtPrec))){
+		w = 0;
+		if(fl & FmtWidth)
+			w = f->width;
+		for(; n < w && p > buf+3; n++){
+			if((fl & FmtApost) && __needsep(&ndig, &grouping)){
+				n += len;
+				excess += bytelen - len;
+				p -= bytelen;
+				memmove(p+1, thousands, (size_t)bytelen);
+			}
+			*p-- = '0';
+		}
+		f->flags &= ~(ulong)FmtWidth;
+	}
+	if(fl & FmtSharp){
+		if(base == 16)
+			*p-- = (char)f->r;
+		if(base == 16 || base == 8)
+			*p-- = '0';
+	}
+	if(neg)
+		*p-- = '-';
+	else if(fl & FmtSign)
+		*p-- = '+';
+	else if(fl & FmtSpace)
+		*p-- = ' ';
+	f->flags &= ~(ulong)FmtPrec;
+	return __fmtcpy(f, p + 1, n, n + excess);
+}
+
+int
+__countfmt(Fmt *f)
+{
+	void *p;
+	ulong fl;
+
+	fl = f->flags;
+	p = va_arg(f->args, void*);
+	if(fl & FmtVLong){
+		*(vlong*)p = f->nfmt;
+	}else if(fl & FmtLong){
+		*(long*)p = f->nfmt;
+	}else if(fl & FmtByte){
+		*(char*)p = (char)f->nfmt;
+	}else if(fl & FmtShort){
+		*(short*)p = (short)f->nfmt;
+	}else{
+		*(int*)p = f->nfmt;
+	}
+	return 0;
+}
+
+int
+__flagfmt(Fmt *f)
+{
+	switch(f->r){
+	case ',':
+		f->flags |= FmtComma;
+		break;
+	case '-':
+		f->flags |= FmtLeft;
+		break;
+	case '+':
+		f->flags |= FmtSign;
+		break;
+	case '#':
+		f->flags |= FmtSharp;
+		break;
+	case '\'':
+		f->flags |= FmtApost;
+		break;
+	case ' ':
+		f->flags |= FmtSpace;
+		break;
+	case 'u':
+		f->flags |= FmtUnsigned;
+		break;
+	case 'h':
+		if(f->flags & FmtShort)
+			f->flags |= FmtByte;
+		f->flags |= FmtShort;
+		break;
+	case 'L':
+		f->flags |= FmtLDouble;
+		break;
+	case 'l':
+		if(f->flags & FmtLong)
+			f->flags |= FmtVLong;
+		f->flags |= FmtLong;
+		break;
+	}
+	return 1;
+}
+
+/* default error format */
+int
+__badfmt(Fmt *f)
+{
+	char x[2+UTFmax];
+	int n;
+
+	x[0] = '%';
+	n = 1 + runetochar(x+1, &f->r);
+	x[n++] = '%';
+	f->prec = n;
+	__fmtcpy(f, (const void*)x, n, n);
+	return 0;
+}
diff --git a/src/lib9/fmt/dorfmt.c b/src/lib9/fmt/dorfmt.c
new file mode 100644
index 0000000..f760d47
--- /dev/null
+++ b/src/lib9/fmt/dorfmt.c
@@ -0,0 +1,64 @@
+/*
+ * 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"
+
+/* format the output into f->to and return the number of characters fmted  */
+
+/* BUG: THIS FILE IS NOT UPDATED TO THE  NEW SPEC */
+int
+dorfmt(Fmt *f, const Rune *fmt)
+{
+	Rune *rt, *rs;
+	Rune r;
+	char *t, *s;
+	int nfmt;
+
+	nfmt = f->nfmt;
+	for(;;){
+		if(f->runes){
+			rt = (Rune*)f->to;
+			rs = (Rune*)f->stop;
+			while((r = *fmt++) && r != '%'){
+				FMTRCHAR(f, rt, rs, r);
+			}
+			f->nfmt += (int)(rt - (Rune *)f->to);
+			f->to = rt;
+			if(!r)
+				return f->nfmt - nfmt;
+			f->stop = rs;
+		}else{
+			t = (char*)f->to;
+			s = (char*)f->stop;
+			while((r = *fmt++) && r != '%'){
+				FMTRUNE(f, t, f->stop, r);
+			}
+			f->nfmt += (int)(t - (char *)f->to);
+			f->to = t;
+			if(!r)
+				return f->nfmt - nfmt;
+			f->stop = s;
+		}
+
+		fmt = (Rune*)__fmtdispatch(f, (Rune*)fmt, 1);
+		if(fmt == nil)
+			return -1;
+	}
+}
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
new file mode 100644
index 0000000..6fe8192
--- /dev/null
+++ b/src/lib9/fmt/fltfmt.c
@@ -0,0 +1,683 @@
+/*
+ * 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.
+ */
+
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
+#include <u.h>
+#include <errno.h>
+#include <libc.h>
+#include "fmtdef.h"
+
+enum
+{
+	FDIGIT	= 30,
+	FDEFLT	= 6,
+	NSIGNIF	= 17
+};
+
+/*
+ * first few powers of 10, enough for about 1/2 of the
+ * total space for doubles.
+ */
+static double pows10[] =
+{
+	  1e0,   1e1,   1e2,   1e3,   1e4,   1e5,   1e6,   1e7,   1e8,   1e9,
+	 1e10,  1e11,  1e12,  1e13,  1e14,  1e15,  1e16,  1e17,  1e18,  1e19,
+	 1e20,  1e21,  1e22,  1e23,  1e24,  1e25,  1e26,  1e27,  1e28,  1e29,
+	 1e30,  1e31,  1e32,  1e33,  1e34,  1e35,  1e36,  1e37,  1e38,  1e39,
+	 1e40,  1e41,  1e42,  1e43,  1e44,  1e45,  1e46,  1e47,  1e48,  1e49,
+	 1e50,  1e51,  1e52,  1e53,  1e54,  1e55,  1e56,  1e57,  1e58,  1e59,
+	 1e60,  1e61,  1e62,  1e63,  1e64,  1e65,  1e66,  1e67,  1e68,  1e69,
+	 1e70,  1e71,  1e72,  1e73,  1e74,  1e75,  1e76,  1e77,  1e78,  1e79,
+	 1e80,  1e81,  1e82,  1e83,  1e84,  1e85,  1e86,  1e87,  1e88,  1e89,
+	 1e90,  1e91,  1e92,  1e93,  1e94,  1e95,  1e96,  1e97,  1e98,  1e99,
+	1e100, 1e101, 1e102, 1e103, 1e104, 1e105, 1e106, 1e107, 1e108, 1e109,
+	1e110, 1e111, 1e112, 1e113, 1e114, 1e115, 1e116, 1e117, 1e118, 1e119,
+	1e120, 1e121, 1e122, 1e123, 1e124, 1e125, 1e126, 1e127, 1e128, 1e129,
+	1e130, 1e131, 1e132, 1e133, 1e134, 1e135, 1e136, 1e137, 1e138, 1e139,
+	1e140, 1e141, 1e142, 1e143, 1e144, 1e145, 1e146, 1e147, 1e148, 1e149,
+	1e150, 1e151, 1e152, 1e153, 1e154, 1e155, 1e156, 1e157, 1e158, 1e159,
+};
+
+#undef	pow10
+#define	npows10 ((int)(sizeof(pows10)/sizeof(pows10[0])))
+#define	pow10(x)  fmtpow10(x)
+
+static double
+pow10(int n)
+{
+	double d;
+	int neg;
+
+	neg = 0;
+	if(n < 0){
+		neg = 1;
+		n = -n;
+	}
+
+	if(n < npows10)
+		d = pows10[n];
+	else{
+		d = pows10[npows10-1];
+		for(;;){
+			n -= npows10 - 1;
+			if(n < npows10){
+				d *= pows10[n];
+				break;
+			}
+			d *= pows10[npows10 - 1];
+		}
+	}
+	if(neg)
+		return 1./d;
+	return d;
+}
+
+/*
+ * add 1 to the decimal integer string a of length n.
+ * if 99999 overflows into 10000, return 1 to tell caller
+ * to move the virtual decimal point.
+ */
+static int
+xadd1(char *a, int n)
+{
+	char *b;
+	int c;
+
+	if(n < 0 || n > NSIGNIF)
+		return 0;
+	for(b = a+n-1; b >= a; b--) {
+		c = *b + 1;
+		if(c <= '9') {
+			*b = (char)c;
+			return 0;
+		}
+		*b = '0';
+	}
+	/*
+	 * need to overflow adding digit.
+	 * shift number down and insert 1 at beginning.
+	 * decimal is known to be 0s or we wouldn't
+	 * have gotten this far.  (e.g., 99999+1 => 00000)
+	 */
+	a[0] = '1';
+	return 1;
+}
+
+/*
+ * subtract 1 from the decimal integer string a.
+ * if 10000 underflows into 09999, make it 99999
+ * and return 1 to tell caller to move the virtual
+ * decimal point.  this way, xsub1 is inverse of xadd1.
+ */
+static int
+xsub1(char *a, int n)
+{
+	char *b;
+	int c;
+
+	if(n < 0 || n > NSIGNIF)
+		return 0;
+	for(b = a+n-1; b >= a; b--) {
+		c = *b - 1;
+		if(c >= '0') {
+			if(c == '0' && b == a) {
+				/*
+				 * just zeroed the top digit; shift everyone up.
+				 * decimal is known to be 9s or we wouldn't
+				 * have gotten this far.  (e.g., 10000-1 => 09999)
+				 */
+				*b = '9';
+				return 1;
+			}
+			*b = (char)c;
+			return 0;
+		}
+		*b = '9';
+	}
+	/*
+	 * can't get here.  the number a is always normalized
+	 * so that it has a nonzero first digit.
+	 */
+	abort();
+	return 0;
+}
+
+/*
+ * format exponent like sprintf(p, "e%+02d", e)
+ */
+static void
+xfmtexp(char *p, int e, int ucase)
+{
+	char se[9];
+	int i;
+
+	*p++ = ucase ? 'E' : 'e';
+	if(e < 0) {
+		*p++ = '-';
+		e = -e;
+	} else
+		*p++ = '+';
+	i = 0;
+	while(e) {
+		se[i++] = (char)(e % 10 + '0');
+		e /= 10;
+	}
+	while(i < 2)
+		se[i++] = '0';
+	while(i > 0)
+		*p++ = se[--i];
+	*p = '\0';
+}
+
+/*
+ * compute decimal integer m, exp such that:
+ *	f = m*10^exp
+ *	m is as short as possible with losing exactness
+ * assumes special cases (NaN, +Inf, -Inf) have been handled.
+ */
+static void
+xdtoa(double f, char *s, int *exp, int *neg, int *ns)
+{
+	int d, e2, e, ee, i, ndigit;
+	int oerrno;
+	char c;
+	char tmp[NSIGNIF+10];
+	double g;
+
+	oerrno = errno; /* in case strtod smashes errno */
+
+	/*
+	 * make f non-negative.
+	 */
+	*neg = 0;
+	if(f < 0) {
+		f = -f;
+		*neg = 1;
+	}
+
+	/*
+	 * must handle zero specially.
+	 */
+	if(f == 0){
+		*exp = 0;
+		s[0] = '0';
+		s[1] = '\0';
+		*ns = 1;
+		return;
+	}
+
+	/*
+	 * find g,e such that f = g*10^e.
+	 * guess 10-exponent using 2-exponent, then fine tune.
+	 */
+	frexp(f, &e2);
+	e = (int)(e2 * .301029995664);
+	g = f * pow10(-e);
+	while(g < 1) {
+		e--;
+		g = f * pow10(-e);
+	}
+	while(g >= 10) {
+		e++;
+		g = f * pow10(-e);
+	}
+
+	/*
+	 * convert NSIGNIF digits as a first approximation.
+	 */
+	for(i=0; i<NSIGNIF; i++) {
+		d = (int)g;
+		s[i] = (char)(d+'0');
+		g = (g-d) * 10;
+	}
+	s[i] = 0;
+
+	/*
+	 * adjust e because s is 314159... not 3.14159...
+	 */
+	e -= NSIGNIF-1;
+	xfmtexp(s+NSIGNIF, e, 0);
+
+	/*
+	 * adjust conversion until strtod(s) == f exactly.
+	 */
+	for(i=0; i<10; i++) {
+		g = strtod(s, nil);
+		if(f > g) {
+			if(xadd1(s, NSIGNIF)) {
+				/* gained a digit */
+				e--;
+				xfmtexp(s+NSIGNIF, e, 0);
+			}
+			continue;
+		}
+		if(f < g) {
+			if(xsub1(s, NSIGNIF)) {
+				/* lost a digit */
+				e++;
+				xfmtexp(s+NSIGNIF, e, 0);
+			}
+			continue;
+		}
+		break;
+	}
+
+	/*
+	 * play with the decimal to try to simplify.
+	 */
+
+	/*
+	 * bump last few digits up to 9 if we can
+	 */
+	for(i=NSIGNIF-1; i>=NSIGNIF-3; i--) {
+		c = s[i];
+		if(c != '9') {
+			s[i] = '9';
+			g = strtod(s, nil);
+			if(g != f) {
+				s[i] = c;
+				break;
+			}
+		}
+	}
+
+	/*
+	 * add 1 in hopes of turning 9s to 0s
+	 */
+	if(s[NSIGNIF-1] == '9') {
+		strcpy(tmp, s);
+		ee = e;
+		if(xadd1(tmp, NSIGNIF)) {
+			ee--;
+			xfmtexp(tmp+NSIGNIF, ee, 0);
+		}
+		g = strtod(tmp, nil);
+		if(g == f) {
+			strcpy(s, tmp);
+			e = ee;
+		}
+	}
+
+	/*
+	 * bump last few digits down to 0 as we can.
+	 */
+	for(i=NSIGNIF-1; i>=NSIGNIF-3; i--) {
+		c = s[i];
+		if(c != '0') {
+			s[i] = '0';
+			g = strtod(s, nil);
+			if(g != f) {
+				s[i] = c;
+				break;
+			}
+		}
+	}
+
+	/*
+	 * remove trailing zeros.
+	 */
+	ndigit = NSIGNIF;
+	while(ndigit > 1 && s[ndigit-1] == '0'){
+		e++;
+		--ndigit;
+	}
+	s[ndigit] = 0;
+	*exp = e;
+	*ns = ndigit;
+	errno = oerrno;
+}
+
+#ifdef PLAN9PORT
+static char *special[] = { "NaN", "NaN", "+Inf", "+Inf", "-Inf", "-Inf" };
+#else
+static char *special[] = { "nan", "NAN", "inf", "INF", "-inf", "-INF" };
+#endif
+
+int
+__efgfmt(Fmt *fmt)
+{
+	char buf[NSIGNIF+10], *dot, *digits, *p, *s, suf[10], *t;
+	double f;
+	int c, chr, dotwid, e, exp, ndigits, neg, newndigits;
+	int pad, point, prec, realchr, sign, sufwid, ucase, wid, z1, z2;
+	ulong fl;
+	Rune r, *rs, *rt;
+
+	if(fmt->flags&FmtLong)
+		f = (double)va_arg(fmt->args, long double);
+	else
+		f = va_arg(fmt->args, double);
+
+	/*
+	 * extract formatting flags
+	 */
+	fl = fmt->flags;
+	fmt->flags = 0;
+	prec = FDEFLT;
+	if(fl & FmtPrec)
+		prec = fmt->prec;
+	chr = (int)fmt->r;
+	ucase = 0;
+	switch(chr) {
+	case 'A':
+	case 'E':
+	case 'F':
+	case 'G':
+		chr += 'a'-'A';
+		ucase = 1;
+		break;
+	}
+
+	/*
+	 * pick off special numbers.
+	 */
+	if(__isNaN(f)) {
+		s = special[0+ucase];
+	special:
+		fmt->flags = fl & (FmtWidth|FmtLeft);
+		return __fmtcpy(fmt, s, (int)strlen(s), (int)strlen(s));
+	}
+	if(__isInf(f, 1)) {
+		s = special[2+ucase];
+		goto special;
+	}
+	if(__isInf(f, -1)) {
+		s = special[4+ucase];
+		goto special;
+	}
+
+	/*
+	 * get exact representation.
+	 */
+	digits = buf;
+	xdtoa(f, digits, &exp, &neg, &ndigits);
+
+	/*
+	 * get locale's decimal point.
+	 */
+	dot = fmt->decimal;
+	if(dot == nil)
+		dot = ".";
+	dotwid = utflen(dot);
+
+	/*
+	 * now the formatting fun begins.
+	 * compute parameters for actual fmt:
+	 *
+	 *	pad: number of spaces to insert before/after field.
+	 *	z1: number of zeros to insert before digits
+	 *	z2: number of zeros to insert after digits
+	 *	point: number of digits to print before decimal point
+	 *	ndigits: number of digits to use from digits[]
+	 *	suf: trailing suffix, like "e-5"
+	 */
+	realchr = chr;
+	switch(chr){
+	case 'g':
+		/*
+		 * convert to at most prec significant digits. (prec=0 means 1)
+		 */
+		if(prec == 0)
+			prec = 1;
+		if(ndigits > prec) {
+			if(digits[prec] >= '5' && xadd1(digits, prec))
+				exp++;
+			exp += ndigits-prec;
+			ndigits = prec;
+		}
+
+		/*
+		 * extra rules for %g (implemented below):
+		 *	trailing zeros removed after decimal unless FmtSharp.
+		 *	decimal point only if digit follows.
+		 */
+
+		/* fall through to %e */
+	default:
+	case 'e':
+		/*
+		 * one significant digit before decimal, no leading zeros.
+		 */
+		point = 1;
+		z1 = 0;
+
+		/*
+		 * decimal point is after ndigits digits right now.
+		 * slide to be after first.
+		 */
+		e  = exp + (ndigits-1);
+
+		/*
+		 * if this is %g, check exponent and convert prec
+		 */
+		if(realchr == 'g') {
+			if(-4 <= e && e < prec)
+				goto casef;
+			prec--;	/* one digit before decimal; rest after */
+		}
+
+		/*
+		 * compute trailing zero padding or truncate digits.
+		 */
+		if(1+prec >= ndigits)
+			z2 = 1+prec - ndigits;
+		else {
+			/*
+			 * truncate digits
+			 */
+			assert(realchr != 'g');
+			newndigits = 1+prec;
+			if(digits[newndigits] >= '5' && xadd1(digits, newndigits)) {
+				/*
+				 * had 999e4, now have 100e5
+				 */
+				e++;
+			}
+			ndigits = newndigits;
+			z2 = 0;
+		}
+		xfmtexp(suf, e, ucase);
+		sufwid = (int)strlen(suf);
+		break;
+
+	casef:
+	case 'f':
+		/*
+		 * determine where digits go with respect to decimal point
+		 */
+		if(ndigits+exp > 0) {
+			point = ndigits+exp;
+			z1 = 0;
+		} else {
+			point = 1;
+			z1 = 1 + -(ndigits+exp);
+		}
+
+		/*
+		 * %g specifies prec = number of significant digits
+		 * convert to number of digits after decimal point
+		 */
+		if(realchr == 'g')
+			prec += z1 - point;
+
+		/*
+		 * compute trailing zero padding or truncate digits.
+		 */
+		if(point+prec >= z1+ndigits)
+			z2 = point+prec - (z1+ndigits);
+		else {
+			/*
+			 * truncate digits
+			 */
+			assert(realchr != 'g');
+			newndigits = point+prec - z1;
+			if(newndigits < 0) {
+				z1 += newndigits;
+				newndigits = 0;
+			} else if(newndigits == 0) {
+				/* perhaps round up */
+				if(digits[0] >= '5'){
+					digits[0] = '1';
+					newndigits = 1;
+					goto newdigit;
+				}
+			} else if(digits[newndigits] >= '5' && xadd1(digits, newndigits)) {
+				/*
+				 * digits was 999, is now 100; make it 1000
+				 */
+				digits[newndigits++] = '0';
+			newdigit:
+				/*
+				 * account for new digit
+				 */
+				if(z1)	/* 0.099 => 0.100 or 0.99 => 1.00*/
+					z1--;
+				else	/* 9.99 => 10.00 */
+					point++;
+			}
+			z2 = 0;
+			ndigits = newndigits;
+		}
+		sufwid = 0;
+		break;
+	}
+
+	/*
+	 * if %g is given without FmtSharp, remove trailing zeros.
+	 * must do after truncation, so that e.g. print %.3g 1.001
+	 * produces 1, not 1.00.  sorry, but them's the rules.
+	 */
+	if(realchr == 'g' && !(fl & FmtSharp)) {
+		if(z1+ndigits+z2 >= point) {
+			if(z1+ndigits < point)
+				z2 = point - (z1+ndigits);
+			else{
+				z2 = 0;
+				while(z1+ndigits > point && digits[ndigits-1] == '0')
+					ndigits--;
+			}
+		}
+	}
+
+	/*
+	 * compute width of all digits and decimal point and suffix if any
+	 */
+	wid = z1+ndigits+z2;
+	if(wid > point)
+		wid += dotwid;
+	else if(wid == point){
+		if(fl & FmtSharp)
+			wid += dotwid;
+		else
+			point++;	/* do not print any decimal point */
+	}
+	wid += sufwid;
+
+	/*
+	 * determine sign
+	 */
+	sign = 0;
+	if(neg)
+		sign = '-';
+	else if(fl & FmtSign)
+		sign = '+';
+	else if(fl & FmtSpace)
+		sign = ' ';
+	if(sign)
+		wid++;
+
+	/*
+	 * compute padding
+	 */
+	pad = 0;
+	if((fl & FmtWidth) && fmt->width > wid)
+		pad = fmt->width - wid;
+	if(pad && !(fl & FmtLeft) && (fl & FmtZero)){
+		z1 += pad;
+		point += pad;
+		pad = 0;
+	}
+
+	/*
+	 * format the actual field.  too bad about doing this twice.
+	 */
+	if(fmt->runes){
+		if(pad && !(fl & FmtLeft) && __rfmtpad(fmt, pad) < 0)
+			return -1;
+		rt = (Rune*)fmt->to;
+		rs = (Rune*)fmt->stop;
+		if(sign)
+			FMTRCHAR(fmt, rt, rs, sign);
+		while(z1>0 || ndigits>0 || z2>0) {
+			if(z1 > 0){
+				z1--;
+				c = '0';
+			}else if(ndigits > 0){
+				ndigits--;
+				c = *digits++;
+			}else{
+				z2--;
+				c = '0';
+			}
+			FMTRCHAR(fmt, rt, rs, c);
+			if(--point == 0) {
+				for(p = dot; *p; ){
+					p += chartorune(&r, p);
+					FMTRCHAR(fmt, rt, rs, r);
+				}
+			}
+		}
+		fmt->nfmt += (int)(rt - (Rune*)fmt->to);
+		fmt->to = rt;
+		if(sufwid && __fmtcpy(fmt, suf, sufwid, sufwid) < 0)
+			return -1;
+		if(pad && (fl & FmtLeft) && __rfmtpad(fmt, pad) < 0)
+			return -1;
+	}else{
+		if(pad && !(fl & FmtLeft) && __fmtpad(fmt, pad) < 0)
+			return -1;
+		t = (char*)fmt->to;
+		s = (char*)fmt->stop;
+		if(sign)
+			FMTCHAR(fmt, t, s, sign);
+		while(z1>0 || ndigits>0 || z2>0) {
+			if(z1 > 0){
+				z1--;
+				c = '0';
+			}else if(ndigits > 0){
+				ndigits--;
+				c = *digits++;
+			}else{
+				z2--;
+				c = '0';
+			}
+			FMTCHAR(fmt, t, s, c);
+			if(--point == 0)
+				for(p=dot; *p; p++)
+					FMTCHAR(fmt, t, s, *p);
+		}
+		fmt->nfmt += (int)(t - (char*)fmt->to);
+		fmt->to = t;
+		if(sufwid && __fmtcpy(fmt, suf, sufwid, sufwid) < 0)
+			return -1;
+		if(pad && (fl & FmtLeft) && __fmtpad(fmt, pad) < 0)
+			return -1;
+	}
+	return 0;
+}
+
diff --git a/src/lib9/fmt/fmt.c b/src/lib9/fmt/fmt.c
new file mode 100644
index 0000000..7e57677
--- /dev/null
+++ b/src/lib9/fmt/fmt.c
@@ -0,0 +1,235 @@
+/*
+ * 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"
+
+enum
+{
+	Maxfmt = 64
+};
+
+typedef struct Convfmt Convfmt;
+struct Convfmt
+{
+	int	c;
+	volatile	Fmts	fmt;	/* for spin lock in fmtfmt; avoids race due to write order */
+};
+
+static struct
+{
+	/* lock by calling __fmtlock, __fmtunlock */
+	int	nfmt;
+	Convfmt	fmt[Maxfmt];
+} fmtalloc;
+
+static Convfmt knownfmt[] = {
+	' ',	__flagfmt,
+	'#',	__flagfmt,
+	'%',	__percentfmt,
+	'\'',	__flagfmt,
+	'+',	__flagfmt,
+	',',	__flagfmt,
+	'-',	__flagfmt,
+	'C',	__runefmt,	/* Plan 9 addition */
+	'E',	__efgfmt,
+#ifndef PLAN9PORT
+	'F',	__efgfmt,	/* ANSI only */
+#endif
+	'G',	__efgfmt,
+#ifndef PLAN9PORT
+	'L',	__flagfmt,	/* ANSI only */
+#endif
+	'S',	__runesfmt,	/* Plan 9 addition */
+	'X',	__ifmt,
+	'b',	__ifmt,		/* Plan 9 addition */
+	'c',	__charfmt,
+	'd',	__ifmt,
+	'e',	__efgfmt,
+	'f',	__efgfmt,
+	'g',	__efgfmt,
+	'h',	__flagfmt,
+#ifndef PLAN9PORT
+	'i',	__ifmt,		/* ANSI only */
+#endif
+	'l',	__flagfmt,
+	'n',	__countfmt,
+	'o',	__ifmt,
+	'p',	__ifmt,
+	'r',	__errfmt,
+	's',	__strfmt,
+#ifdef PLAN9PORT
+	'u',	__flagfmt,
+#else
+	'u',	__ifmt,
+#endif
+	'x',	__ifmt,
+	0,	nil,
+};
+
+
+int	(*fmtdoquote)(int);
+
+/*
+ * __fmtlock() must be set
+ */
+static int
+__fmtinstall(int c, Fmts f)
+{
+	Convfmt *p, *ep;
+
+	if(c<=0 || c>=65536)
+		return -1;
+	if(!f)
+		f = __badfmt;
+
+	ep = &fmtalloc.fmt[fmtalloc.nfmt];
+	for(p=fmtalloc.fmt; p<ep; p++)
+		if(p->c == c)
+			break;
+
+	if(p == &fmtalloc.fmt[Maxfmt])
+		return -1;
+
+	p->fmt = f;
+	if(p == ep){	/* installing a new format character */
+		fmtalloc.nfmt++;
+		p->c = c;
+	}
+
+	return 0;
+}
+
+int
+fmtinstall(int c, int (*f)(Fmt*))
+{
+	int ret;
+
+	__fmtlock();
+	ret = __fmtinstall(c, f);
+	__fmtunlock();
+	return ret;
+}
+
+static Fmts
+fmtfmt(int c)
+{
+	Convfmt *p, *ep;
+
+	ep = &fmtalloc.fmt[fmtalloc.nfmt];
+	for(p=fmtalloc.fmt; p<ep; p++)
+		if(p->c == c){
+			while(p->fmt == nil)	/* loop until value is updated */
+				;
+			return p->fmt;
+		}
+
+	/* is this a predefined format char? */
+	__fmtlock();
+	for(p=knownfmt; p->c; p++)
+		if(p->c == c){
+			__fmtinstall(p->c, p->fmt);
+			__fmtunlock();
+			return p->fmt;
+		}
+	__fmtunlock();
+
+	return __badfmt;
+}
+
+void*
+__fmtdispatch(Fmt *f, void *fmt, int isrunes)
+{
+	Rune rune, r;
+	int i, n;
+
+	f->flags = 0;
+	f->width = f->prec = 0;
+
+	for(;;){
+		if(isrunes){
+			r = *(Rune*)fmt;
+			fmt = (Rune*)fmt + 1;
+		}else{
+			fmt = (char*)fmt + chartorune(&rune, (char*)fmt);
+			r = rune;
+		}
+		f->r = r;
+		switch(r){
+		case '\0':
+			return nil;
+		case '.':
+			f->flags |= FmtWidth|FmtPrec;
+			continue;
+		case '0':
+			if(!(f->flags & FmtWidth)){
+				f->flags |= FmtZero;
+				continue;
+			}
+			/* fall through */
+		case '1': case '2': case '3': case '4':
+		case '5': case '6': case '7': case '8': case '9':
+			i = 0;
+			while(r >= '0' && r <= '9'){
+				i = i * 10 + (int)r - '0';
+				if(isrunes){
+					r = *(Rune*)fmt;
+					fmt = (Rune*)fmt + 1;
+				}else{
+					r = (Rune)*(char*)fmt;
+					fmt = (char*)fmt + 1;
+				}
+			}
+			if(isrunes)
+				fmt = (Rune*)fmt - 1;
+			else
+				fmt = (char*)fmt - 1;
+		numflag:
+			if(f->flags & FmtWidth){
+				f->flags |= FmtPrec;
+				f->prec = i;
+			}else{
+				f->flags |= FmtWidth;
+				f->width = i;
+			}
+			continue;
+		case '*':
+			i = va_arg(f->args, int);
+			if(i < 0){
+				/*
+				 * negative precision =>
+				 * ignore the precision.
+				 */
+				if(f->flags & FmtPrec){
+					f->flags &= ~(ulong)FmtPrec;
+					f->prec = 0;
+					continue;
+				}
+				i = -i;
+				f->flags |= FmtLeft;
+			}
+			goto numflag;
+		}
+		n = (*fmtfmt((int)r))(f);
+		if(n < 0)
+			return nil;
+		if(n == 0)
+			return fmt;
+	}
+}
diff --git a/src/lib9/fmt/fmtdef.h b/src/lib9/fmt/fmtdef.h
new file mode 100644
index 0000000..4bbd9f5
--- /dev/null
+++ b/src/lib9/fmt/fmtdef.h
@@ -0,0 +1,119 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *
+ *     Copyright (c) 2002-2006 by Lucent Technologies.
+ * 
+ * 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.
+ */
+
+/*
+ * dofmt -- format to a buffer
+ * the number of characters formatted is returned,
+ * or -1 if there was an error.
+ * if the buffer is ever filled, flush is called.
+ * it should reset the buffer and return whether formatting should continue.
+ */
+
+typedef int (*Fmts)(Fmt*);
+
+typedef struct Quoteinfo Quoteinfo;
+struct Quoteinfo
+{
+	int	quoted;		/* if set, string must be quoted */
+	int	nrunesin;	/* number of input runes that can be accepted */
+	int	nbytesin;	/* number of input bytes that can be accepted */
+	int	nrunesout;	/* number of runes that will be generated */
+	int	nbytesout;	/* number of bytes that will be generated */
+};
+
+/* Edit .+1,/^$/ |cfn |grep -v static | grep __ */
+double       __Inf(int sign);
+double       __NaN(void);
+int          __badfmt(Fmt *f);
+int          __charfmt(Fmt *f);
+int          __countfmt(Fmt *f);
+int          __efgfmt(Fmt *fmt);
+int          __errfmt(Fmt *f);
+int          __flagfmt(Fmt *f);
+int          __fmtFdFlush(Fmt *f);
+int          __fmtcpy(Fmt *f, const void *vm, int n, int sz);
+void*        __fmtdispatch(Fmt *f, void *fmt, int isrunes);
+void *       __fmtflush(Fmt *f, void *t, int len);
+void         __fmtlock(void);
+int          __fmtpad(Fmt *f, int n);
+double       __fmtpow10(int n);
+int          __fmtrcpy(Fmt *f, const void *vm, int n);
+void         __fmtunlock(void);
+int          __ifmt(Fmt *f);
+int          __isInf(double d, int sign);
+int          __isNaN(double d);
+int          __needsep(int*, char**);
+int          __needsquotes(char *s, int *quotelenp);
+int          __percentfmt(Fmt *f);
+void         __quotesetup(char *s, Rune *r, int nin, int nout, Quoteinfo *q, int sharp, int runesout);
+int          __quotestrfmt(int runesin, Fmt *f);
+int          __rfmtpad(Fmt *f, int n);
+int          __runefmt(Fmt *f);
+int          __runeneedsquotes(Rune *r, int *quotelenp);
+int          __runesfmt(Fmt *f);
+int          __strfmt(Fmt *f);
+
+#define FMTCHAR(f, t, s, c)\
+	do{\
+	if(t + 1 > (char*)s){\
+		t = (char*)__fmtflush(f, t, 1);\
+		if(t != nil)\
+			s = (char*)f->stop;\
+		else\
+			return -1;\
+	}\
+	*t++ = (char)c;\
+	}while(0)
+
+#define FMTRCHAR(f, t, s, c)\
+	do{\
+	if(t + 1 > (Rune*)s){\
+		t = (Rune*)__fmtflush(f, t, sizeof(Rune));\
+		if(t != nil)\
+			s = (Rune*)f->stop;\
+		else\
+			return -1;\
+	}\
+	*t++ = (Rune)c;\
+	}while(0)
+
+#define FMTRUNE(f, t, s, r)\
+	do{\
+	Rune _rune;\
+	int _runelen;\
+	if(t + UTFmax > (char*)s && t + (_runelen = runelen(r)) > (char*)s){\
+		t = (char*)__fmtflush(f, t, _runelen);\
+		if(t != nil)\
+			s = (char*)f->stop;\
+		else\
+			return -1;\
+	}\
+	if(r < Runeself)\
+		*t++ = (char)r;\
+	else{\
+		_rune = r;\
+		t += runetochar(t, &_rune);\
+	}\
+	}while(0)
+
+#ifdef va_copy
+#	define VA_COPY(a,b) va_copy(a,b)
+#	define VA_END(a) va_end(a)
+#else
+#	define VA_COPY(a,b) (a) = (b)
+#	define VA_END(a)
+#endif
+
diff --git a/src/lib9/fmt/fmtfd.c b/src/lib9/fmt/fmtfd.c
new file mode 100644
index 0000000..dde05b7
--- /dev/null
+++ b/src/lib9/fmt/fmtfd.c
@@ -0,0 +1,51 @@
+/*
+ * 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"
+
+/*
+ * public routine for final flush of a formatting buffer
+ * to a file descriptor; returns total char count.
+ */
+int
+fmtfdflush(Fmt *f)
+{
+	if(__fmtFdFlush(f) <= 0)
+		return -1;
+	return f->nfmt;
+}
+
+/*
+ * initialize an output buffer for buffered printing
+ */
+int
+fmtfdinit(Fmt *f, int fd, char *buf, int size)
+{
+	f->runes = 0;
+	f->start = buf;
+	f->to = buf;
+	f->stop = buf + size;
+	f->flush = __fmtFdFlush;
+	f->farg = (void*)(uintptr)fd;
+	f->flags = 0;
+	f->nfmt = 0;
+	fmtlocaleinit(f, nil, nil, nil);
+	return 0;
+}
diff --git a/src/lib9/fmt/fmtfdflush.c b/src/lib9/fmt/fmtfdflush.c
new file mode 100644
index 0000000..401acbe
--- /dev/null
+++ b/src/lib9/fmt/fmtfdflush.c
@@ -0,0 +1,37 @@
+/*
+ * 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"
+
+/*
+ * generic routine for flushing a formatting buffer
+ * to a file descriptor
+ */
+int
+__fmtFdFlush(Fmt *f)
+{
+	int n;
+
+	n = (int)((char*)f->to - (char*)f->start);
+	if(n && (int)write((int)(uintptr)f->farg, f->start, (size_t)n) != n)
+		return 0;
+	f->to = f->start;
+	return 1;
+}
diff --git a/src/lib9/fmt/fmtlocale.c b/src/lib9/fmt/fmtlocale.c
new file mode 100644
index 0000000..64ed10f
--- /dev/null
+++ b/src/lib9/fmt/fmtlocale.c
@@ -0,0 +1,69 @@
+/*
+ * 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"
+
+/*
+ * Fill in the internationalization stuff in the State structure.
+ * For nil arguments, provide the sensible defaults:
+ *	decimal is a period
+ *	thousands separator is a comma
+ *	thousands are marked every three digits
+ */
+void
+fmtlocaleinit(Fmt *f, char *decimal, char *thousands, char *grouping)
+{
+	if(decimal == nil || decimal[0] == '\0')
+		decimal = ".";
+	if(thousands == nil)
+		thousands = ",";
+	if(grouping == nil)
+		grouping = "\3";
+	f->decimal = decimal;
+	f->thousands = thousands;
+	f->grouping = grouping;
+}
+
+/*
+ * We are about to emit a digit in e.g. %'d.  If that digit would
+ * overflow a thousands (e.g.) grouping, tell the caller to emit
+ * the thousands separator.  Always advance the digit counter
+ * and pointer into the grouping descriptor.
+ */
+int
+__needsep(int *ndig, char **grouping)
+{
+	int group;
+
+	(*ndig)++;
+	group = *(unsigned char*)*grouping;
+	/* CHAR_MAX means no further grouping. \0 means we got the empty string */
+	if(group == 0xFF || group == 0x7f || group == 0x00)
+		return 0;
+	if(*ndig > group){
+		/* if we're at end of string, continue with this grouping; else advance */
+		if((*grouping)[1] != '\0')
+			(*grouping)++;
+		*ndig = 1;
+		return 1;
+	}
+	return 0;
+}
+
diff --git a/src/lib9/fmt/fmtlock.c b/src/lib9/fmt/fmtlock.c
new file mode 100644
index 0000000..297acd8
--- /dev/null
+++ b/src/lib9/fmt/fmtlock.c
@@ -0,0 +1,31 @@
+/*
+ * 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"
+
+void
+__fmtlock(void)
+{
+}
+
+void
+__fmtunlock(void)
+{
+}
diff --git a/src/lib9/fmt/fmtnull.c b/src/lib9/fmt/fmtnull.c
new file mode 100644
index 0000000..b8caacb
--- /dev/null
+++ b/src/lib9/fmt/fmtnull.c
@@ -0,0 +1,48 @@
+/*
+ * 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"
+
+/*
+ * Absorb output without using resources.
+ */
+static Rune nullbuf[32];
+
+static int
+__fmtnullflush(Fmt *f)
+{
+	f->to = nullbuf;
+	f->nfmt = 0;
+	return 0;
+}
+
+int
+fmtnullinit(Fmt *f)
+{
+	memset(f, 0, sizeof *f);
+	f->runes = 1;
+	f->start = nullbuf;
+	f->to = nullbuf;
+	f->stop = nullbuf+nelem(nullbuf);
+	f->flush = __fmtnullflush;
+	fmtlocaleinit(f, nil, nil, nil);
+	return 0;
+}
+
diff --git a/src/lib9/fmt/fmtprint.c b/src/lib9/fmt/fmtprint.c
new file mode 100644
index 0000000..6848ab4
--- /dev/null
+++ b/src/lib9/fmt/fmtprint.c
@@ -0,0 +1,39 @@
+/*
+ * 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"
+
+/*
+ * Format a string into the output buffer.
+ * Designed for formats which themselves call fmt.
+ * Flags, precision and width are preserved.
+ */
+int
+fmtprint(Fmt *f, char *fmt, ...)
+{
+	int n;
+	va_list va;
+
+	va_start(va, fmt);
+	n = fmtvprint(f, fmt, va);
+	va_end(va);
+	return n;
+}
+
diff --git a/src/lib9/fmt/fmtquote.c b/src/lib9/fmt/fmtquote.c
new file mode 100644
index 0000000..93b2abb
--- /dev/null
+++ b/src/lib9/fmt/fmtquote.c
@@ -0,0 +1,274 @@
+/*
+ * 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"
+
+/*
+ * How many bytes of output UTF will be produced by quoting (if necessary) this string?
+ * How many runes? How much of the input will be consumed?
+ * The parameter q is filled in by __quotesetup.
+ * The string may be UTF or Runes (s or r).
+ * Return count does not include NUL.
+ * Terminate the scan at the first of:
+ *	NUL in input
+ *	count exceeded in input
+ *	count exceeded on output
+ * *ninp is set to number of input bytes accepted.
+ * nin may be <0 initially, to avoid checking input by count.
+ */
+void
+__quotesetup(char *s, Rune *r, int nin, int nout, Quoteinfo *q, int sharp, int runesout)
+{
+	int w;
+	Rune c;
+
+	q->quoted = 0;
+	q->nbytesout = 0;
+	q->nrunesout = 0;
+	q->nbytesin = 0;
+	q->nrunesin = 0;
+	if(sharp || nin==0 || (s && *s=='\0') || (r && *r=='\0')){
+		if(nout < 2)
+			return;
+		q->quoted = 1;
+		q->nbytesout = 2;
+		q->nrunesout = 2;
+	}
+	for(; nin!=0; nin--){
+		if(s)
+			w = chartorune(&c, s);
+		else{
+			c = *r;
+			w = runelen(c);
+		}
+
+		if(c == '\0')
+			break;
+		if(runesout){
+			if(q->nrunesout+1 > nout)
+				break;
+		}else{
+			if(q->nbytesout+w > nout)
+				break;
+		}
+
+		if((c <= L' ') || (c == L'\'') || (fmtdoquote!=nil && fmtdoquote((int)c))){
+			if(!q->quoted){
+				if(runesout){
+					if(1+q->nrunesout+1+1 > nout)	/* no room for quotes */
+						break;
+				}else{
+					if(1+q->nbytesout+w+1 > nout)	/* no room for quotes */
+						break;
+				}
+				q->nrunesout += 2;	/* include quotes */
+				q->nbytesout += 2;	/* include quotes */
+				q->quoted = 1;
+			}
+			if(c == '\'')	{
+				if(runesout){
+					if(1+q->nrunesout+1 > nout)	/* no room for quotes */
+						break;
+				}else{
+					if(1+q->nbytesout+w > nout)	/* no room for quotes */
+						break;
+				}
+				q->nbytesout++;
+				q->nrunesout++;	/* quotes reproduce as two characters */
+			}
+		}
+
+		/* advance input */
+		if(s)
+			s += w;
+		else
+			r++;
+		q->nbytesin += w;
+		q->nrunesin++;
+
+		/* advance output */
+		q->nbytesout += w;
+		q->nrunesout++;
+
+#ifndef PLAN9PORT
+		/* ANSI requires precision in bytes, not Runes. */
+		nin-= w-1;	/* and then n-- in the loop */
+#endif
+	}
+}
+
+static int
+qstrfmt(char *sin, Rune *rin, Quoteinfo *q, Fmt *f)
+{
+	Rune r, *rm, *rme;
+	char *t, *s, *m, *me;
+	Rune *rt, *rs;
+	ulong fl;
+	int nc, w;
+
+	m = sin;
+	me = m + q->nbytesin;
+	rm = rin;
+	rme = rm + q->nrunesin;
+
+	fl = f->flags;
+	w = 0;
+	if(fl & FmtWidth)
+		w = f->width;
+	if(f->runes){
+		if(!(fl & FmtLeft) && __rfmtpad(f, w - q->nrunesout) < 0)
+			return -1;
+	}else{
+		if(!(fl & FmtLeft) && __fmtpad(f, w - q->nbytesout) < 0)
+			return -1;
+	}
+	t = (char*)f->to;
+	s = (char*)f->stop;
+	rt = (Rune*)f->to;
+	rs = (Rune*)f->stop;
+	if(f->runes)
+		FMTRCHAR(f, rt, rs, '\'');
+	else
+		FMTRUNE(f, t, s, '\'');
+	for(nc = q->nrunesin; nc > 0; nc--){
+		if(sin){
+			r = *(uchar*)m;
+			if(r < Runeself)
+				m++;
+			else if((me - m) >= UTFmax || fullrune(m, (int)(me-m)))
+				m += chartorune(&r, m);
+			else
+				break;
+		}else{
+			if(rm >= rme)
+				break;
+			r = *(uchar*)rm++;
+		}
+		if(f->runes){
+			FMTRCHAR(f, rt, rs, r);
+			if(r == '\'')
+				FMTRCHAR(f, rt, rs, r);
+		}else{
+			FMTRUNE(f, t, s, r);
+			if(r == '\'')
+				FMTRUNE(f, t, s, r);
+		}
+	}
+
+	if(f->runes){
+		FMTRCHAR(f, rt, rs, '\'');
+		USED(rs);
+		f->nfmt += (int)(rt - (Rune *)f->to);
+		f->to = rt;
+		if(fl & FmtLeft && __rfmtpad(f, w - q->nrunesout) < 0)
+			return -1;
+	}else{
+		FMTRUNE(f, t, s, '\'');
+		USED(s);
+		f->nfmt += (int)(t - (char *)f->to);
+		f->to = t;
+		if(fl & FmtLeft && __fmtpad(f, w - q->nbytesout) < 0)
+			return -1;
+	}
+	return 0;
+}
+
+int
+__quotestrfmt(int runesin, Fmt *f)
+{
+	int nin, outlen;
+	Rune *r;
+	char *s;
+	Quoteinfo q;
+
+	nin = -1;
+	if(f->flags&FmtPrec)
+		nin = f->prec;
+	if(runesin){
+		r = va_arg(f->args, Rune *);
+		s = nil;
+	}else{
+		s = va_arg(f->args, char *);
+		r = nil;
+	}
+	if(!s && !r)
+		return __fmtcpy(f, (void*)"<nil>", 5, 5);
+
+	if(f->flush)
+		outlen = 0x7FFFFFFF;	/* if we can flush, no output limit */
+	else if(f->runes)
+		outlen = (int)((Rune*)f->stop - (Rune*)f->to);
+	else
+		outlen = (int)((char*)f->stop - (char*)f->to);
+
+	__quotesetup(s, r, nin, outlen, &q, f->flags&FmtSharp, f->runes);
+/*print("bytes in %d bytes out %d runes in %d runesout %d\n", q.nbytesin, q.nbytesout, q.nrunesin, q.nrunesout); */
+
+	if(runesin){
+		if(!q.quoted)
+			return __fmtrcpy(f, r, q.nrunesin);
+		return qstrfmt(nil, r, &q, f);
+	}
+
+	if(!q.quoted)
+		return __fmtcpy(f, s, q.nrunesin, q.nbytesin);
+	return qstrfmt(s, nil, &q, f);
+}
+
+int
+quotestrfmt(Fmt *f)
+{
+	return __quotestrfmt(0, f);
+}
+
+int
+quoterunestrfmt(Fmt *f)
+{
+	return __quotestrfmt(1, f);
+}
+
+void
+quotefmtinstall(void)
+{
+	fmtinstall('q', quotestrfmt);
+	fmtinstall('Q', quoterunestrfmt);
+}
+
+int
+__needsquotes(char *s, int *quotelenp)
+{
+	Quoteinfo q;
+
+	__quotesetup(s, nil, -1, 0x7FFFFFFF, &q, 0, 0);
+	*quotelenp = q.nbytesout;
+
+	return q.quoted;
+}
+
+int
+__runeneedsquotes(Rune *r, int *quotelenp)
+{
+	Quoteinfo q;
+
+	__quotesetup(nil, r, -1, 0x7FFFFFFF, &q, 0, 0);
+	*quotelenp = q.nrunesout;
+
+	return q.quoted;
+}
diff --git a/src/lib9/fmt/fmtrune.c b/src/lib9/fmt/fmtrune.c
new file mode 100644
index 0000000..2bc8d28
--- /dev/null
+++ b/src/lib9/fmt/fmtrune.c
@@ -0,0 +1,43 @@
+/*
+ * 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
+fmtrune(Fmt *f, int r)
+{
+	Rune *rt;
+	char *t;
+	int n;
+
+	if(f->runes){
+		rt = (Rune*)f->to;
+		FMTRCHAR(f, rt, f->stop, r);
+		f->to = rt;
+		n = 1;
+	}else{
+		t = (char*)f->to;
+		FMTRUNE(f, t, f->stop, (Rune)r);
+		n = (int)(t - (char*)f->to);
+		f->to = t;
+	}
+	f->nfmt += n;
+	return 0;
+}
diff --git a/src/lib9/fmt/fmtstr.c b/src/lib9/fmt/fmtstr.c
new file mode 100644
index 0000000..a6ca772
--- /dev/null
+++ b/src/lib9/fmt/fmtstr.c
@@ -0,0 +1,31 @@
+/*
+ * 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"
+
+char*
+fmtstrflush(Fmt *f)
+{
+	if(f->start == nil)
+		return nil;
+	*(char*)f->to = '\0';
+	f->to = f->start;
+	return (char*)f->start;
+}
diff --git a/src/lib9/fmt/fmtvprint.c b/src/lib9/fmt/fmtvprint.c
new file mode 100644
index 0000000..f18d27b
--- /dev/null
+++ b/src/lib9/fmt/fmtvprint.c
@@ -0,0 +1,52 @@
+/*
+ * 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"
+
+
+/*
+ * Format a string into the output buffer.
+ * Designed for formats which themselves call fmt.
+ * Flags, precision and width are preserved.
+ */
+int
+fmtvprint(Fmt *f, char *fmt, va_list args)
+{
+	va_list va;
+	int n, w, p;
+	unsigned long fl;
+
+	w = f->width;
+	p = f->prec;
+	fl = f->flags;
+	VA_COPY(va, f->args);
+	VA_END(f->args);
+	VA_COPY(f->args, args);
+	n = dofmt(f, fmt);
+	VA_END(f->args);
+	VA_COPY(f->args, va);
+	VA_END(va);
+	f->width = w;
+	f->prec = p;
+	f->flags = fl;
+	if(n >= 0)
+		return 0;
+	return n;
+}
diff --git a/src/lib9/fmt/fprint.c b/src/lib9/fmt/fprint.c
new file mode 100644
index 0000000..70cb138
--- /dev/null
+++ b/src/lib9/fmt/fprint.c
@@ -0,0 +1,33 @@
+/*
+ * 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
+fprint(int fd, char *fmt, ...)
+{
+	int n;
+	va_list args;
+
+	va_start(args, fmt);
+	n = vfprint(fd, fmt, args);
+	va_end(args);
+	return n;
+}
diff --git a/src/lib9/fmt/nan64.c b/src/lib9/fmt/nan64.c
new file mode 100644
index 0000000..1ea7027
--- /dev/null
+++ b/src/lib9/fmt/nan64.c
@@ -0,0 +1,93 @@
+/*
+ * 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.
+ */
+
+/*
+ * 64-bit IEEE not-a-number routines.
+ * This is big/little-endian portable assuming that
+ * the 64-bit doubles and 64-bit integers have the
+ * same byte ordering.
+ */
+
+#include <u.h>
+#include <libc.h>
+#include "fmtdef.h"
+
+static uvlong uvnan    = ((uvlong)0x7FF00000<<32)|0x00000001;
+static uvlong uvinf    = ((uvlong)0x7FF00000<<32)|0x00000000;
+static uvlong uvneginf = ((uvlong)0xFFF00000<<32)|0x00000000;
+
+/* gcc sees through the obvious casts. */
+static uvlong
+d2u(double d)
+{
+	union {
+		uvlong v;
+		double d;
+	} u;
+	assert(sizeof(u.d) == sizeof(u.v));
+	u.d = d;
+	return u.v;
+}
+
+static double
+u2d(uvlong v)
+{
+	union {
+		uvlong v;
+		double d;
+	} u;
+	assert(sizeof(u.d) == sizeof(u.v));
+	u.v = v;
+	return u.d;
+}
+
+double
+__NaN(void)
+{
+	return u2d(uvnan);
+}
+
+int
+__isNaN(double d)
+{
+	uvlong x;
+
+	x = d2u(d);
+	/* IEEE 754: exponent bits 0x7FF and non-zero mantissa */
+	return (x&uvinf) == uvinf && (x&~uvneginf) != 0;
+}
+
+double
+__Inf(int sign)
+{
+	return u2d(sign < 0 ? uvneginf : uvinf);
+}
+
+int
+__isInf(double d, int sign)
+{
+	uvlong x;
+
+	x = d2u(d);
+	if(sign == 0)
+		return x==uvinf || x==uvneginf;
+	else if(sign > 0)
+		return x==uvinf;
+	else
+		return x==uvneginf;
+}
diff --git a/src/lib9/fmt/pow10.c b/src/lib9/fmt/pow10.c
new file mode 100644
index 0000000..e146884
--- /dev/null
+++ b/src/lib9/fmt/pow10.c
@@ -0,0 +1,60 @@
+/*
+ * 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"
+
+/*
+ * this table might overflow 127-bit exponent representations.
+ * in that case, truncate it after 1.0e38.
+ * it is important to get all one can from this
+ * routine since it is used in atof to scale numbers.
+ * the presumption is that C converts fp numbers better
+ * than multipication of lower powers of 10.
+ */
+
+static
+double	tab[] =
+{
+	1.0e0, 1.0e1, 1.0e2, 1.0e3, 1.0e4, 1.0e5, 1.0e6, 1.0e7, 1.0e8, 1.0e9,
+	1.0e10,1.0e11,1.0e12,1.0e13,1.0e14,1.0e15,1.0e16,1.0e17,1.0e18,1.0e19,
+	1.0e20,1.0e21,1.0e22,1.0e23,1.0e24,1.0e25,1.0e26,1.0e27,1.0e28,1.0e29,
+	1.0e30,1.0e31,1.0e32,1.0e33,1.0e34,1.0e35,1.0e36,1.0e37,1.0e38,1.0e39,
+	1.0e40,1.0e41,1.0e42,1.0e43,1.0e44,1.0e45,1.0e46,1.0e47,1.0e48,1.0e49,
+	1.0e50,1.0e51,1.0e52,1.0e53,1.0e54,1.0e55,1.0e56,1.0e57,1.0e58,1.0e59,
+	1.0e60,1.0e61,1.0e62,1.0e63,1.0e64,1.0e65,1.0e66,1.0e67,1.0e68,1.0e69,
+};
+
+double
+__fmtpow10(int n)
+{
+	int m;
+
+	if(n < 0) {
+		n = -n;
+		if(n < (int)(sizeof(tab)/sizeof(tab[0])))
+			return 1/tab[n];
+		m = n/2;
+		return __fmtpow10(-m) * __fmtpow10(m-n);
+	}
+	if(n < (int)(sizeof(tab)/sizeof(tab[0])))
+		return tab[n];
+	m = n/2;
+	return __fmtpow10(m) * __fmtpow10(n-m);
+}
diff --git a/src/lib9/fmt/print.c b/src/lib9/fmt/print.c
new file mode 100644
index 0000000..5c39457
--- /dev/null
+++ b/src/lib9/fmt/print.c
@@ -0,0 +1,33 @@
+/*
+ * 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
+print(char *fmt, ...)
+{
+	int n;
+	va_list args;
+
+	va_start(args, fmt);
+	n = vfprint(1, fmt, args);
+	va_end(args);
+	return n;
+}
diff --git a/src/lib9/fmt/seprint.c b/src/lib9/fmt/seprint.c
new file mode 100644
index 0000000..88779d9
--- /dev/null
+++ b/src/lib9/fmt/seprint.c
@@ -0,0 +1,33 @@
+/*
+ * 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"
+
+char*
+seprint(char *buf, char *e, char *fmt, ...)
+{
+	char *p;
+	va_list args;
+
+	va_start(args, fmt);
+	p = vseprint(buf, e, fmt, args);
+	va_end(args);
+	return p;
+}
diff --git a/src/lib9/fmt/smprint.c b/src/lib9/fmt/smprint.c
new file mode 100644
index 0000000..c13ffd7
--- /dev/null
+++ b/src/lib9/fmt/smprint.c
@@ -0,0 +1,33 @@
+/*
+ * 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"
+
+char*
+smprint(char *fmt, ...)
+{
+	va_list args;
+	char *p;
+
+	va_start(args, fmt);
+	p = vsmprint(fmt, args);
+	va_end(args);
+	return p;
+}
diff --git a/src/lib9/fmt/snprint.c b/src/lib9/fmt/snprint.c
new file mode 100644
index 0000000..372399c
--- /dev/null
+++ b/src/lib9/fmt/snprint.c
@@ -0,0 +1,34 @@
+/*
+ * 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
+snprint(char *buf, int len, char *fmt, ...)
+{
+	int n;
+	va_list args;
+
+	va_start(args, fmt);
+	n = vsnprint(buf, len, fmt, args);
+	va_end(args);
+	return n;
+}
+
diff --git a/src/lib9/fmt/sprint.c b/src/lib9/fmt/sprint.c
new file mode 100644
index 0000000..02655ad
--- /dev/null
+++ b/src/lib9/fmt/sprint.c
@@ -0,0 +1,45 @@
+/*
+ * 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
+sprint(char *buf, char *fmt, ...)
+{
+	int n;
+	uint len;
+	va_list args;
+
+	len = 1<<30;  /* big number, but sprint is deprecated anyway */
+	/*
+	 * on PowerPC, the stack is near the top of memory, so
+	 * we must be sure not to overflow a 32-bit pointer.
+	 *
+	 * careful!  gcc-4.2 assumes buf+len < buf can never be true and
+	 * optimizes the test away.  casting to uintptr works around this bug.
+	 */
+	if((uintptr)buf+len < (uintptr)buf)
+		len = (uint)-(uintptr)buf-1;
+
+	va_start(args, fmt);
+	n = (int)vsnprint(buf, (int)len, fmt, args);
+	va_end(args);
+	return n;
+}
diff --git a/src/lib9/fmt/strtod.c b/src/lib9/fmt/strtod.c
new file mode 100644
index 0000000..ec185d2
--- /dev/null
+++ b/src/lib9/fmt/strtod.c
@@ -0,0 +1,533 @@
+/*
+ * 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 <errno.h>
+#include <libc.h>
+#include "fmtdef.h"
+
+static ulong
+umuldiv(ulong a, ulong b, ulong c)
+{
+	double d;
+
+	d = ((double)a * (double)b) / (double)c;
+	if(d >= 4294967295.)
+		d = 4294967295.;
+	return (ulong)d;
+}
+
+/*
+ * This routine will convert to arbitrary precision
+ * floating point entirely in multi-precision fixed.
+ * The answer is the closest floating point number to
+ * the given decimal number. Exactly half way are
+ * rounded ala ieee rules.
+ * Method is to scale input decimal between .500 and .999...
+ * with external power of 2, then binary search for the
+ * closest mantissa to this decimal number.
+ * Nmant is is the required precision. (53 for ieee dp)
+ * Nbits is the max number of bits/word. (must be <= 28)
+ * Prec is calculated - the number of words of fixed mantissa.
+ */
+enum
+{
+	Nbits	= 28,				/* bits safely represented in a ulong */
+	Nmant	= 53,				/* bits of precision required */
+	Prec	= (Nmant+Nbits+1)/Nbits,	/* words of Nbits each to represent mantissa */
+	Sigbit	= 1<<(Prec*Nbits-Nmant),	/* first significant bit of Prec-th word */
+	Ndig	= 1500,
+	One	= (ulong)(1<<Nbits),
+	Half	= (ulong)(One>>1),
+	Maxe	= 310,
+
+	Fsign	= 1<<0,		/* found - */
+	Fesign	= 1<<1,		/* found e- */
+	Fdpoint	= 1<<2,		/* found . */
+
+	S0	= 0,		/* _		_S0	+S1	#S2	.S3 */
+	S1,			/* _+		#S2	.S3 */
+	S2,			/* _+#		#S2	.S4	eS5 */
+	S3,			/* _+.		#S4 */
+	S4,			/* _+#.#	#S4	eS5 */
+	S5,			/* _+#.#e	+S6	#S7 */
+	S6,			/* _+#.#e+	#S7 */
+	S7			/* _+#.#e+#	#S7 */
+};
+
+static	int	xcmp(char*, char*);
+static	int	fpcmp(char*, ulong*);
+static	void	frnorm(ulong*);
+static	void	divascii(char*, int*, int*, int*);
+static	void	mulascii(char*, int*, int*, int*);
+
+typedef	struct	Tab	Tab;
+struct	Tab
+{
+	int	bp;
+	int	siz;
+	char*	cmp;
+};
+
+double
+fmtstrtod(const char *as, char **aas)
+{
+	int na, ex, dp, bp, c, i, flag, state;
+	ulong low[Prec], hig[Prec], mid[Prec];
+	double d;
+	char *s, a[Ndig];
+
+	flag = 0;	/* Fsign, Fesign, Fdpoint */
+	na = 0;		/* number of digits of a[] */
+	dp = 0;		/* na of decimal point */
+	ex = 0;		/* exonent */
+
+	state = S0;
+	for(s=(char*)as;; s++) {
+		c = *s;
+		if(c >= '0' && c <= '9') {
+			switch(state) {
+			case S0:
+			case S1:
+			case S2:
+				state = S2;
+				break;
+			case S3:
+			case S4:
+				state = S4;
+				break;
+
+			case S5:
+			case S6:
+			case S7:
+				state = S7;
+				ex = ex*10 + (c-'0');
+				continue;
+			}
+			if(na == 0 && c == '0') {
+				dp--;
+				continue;
+			}
+			if(na < Ndig-50)
+				a[na++] = (char)c;
+			continue;
+		}
+		switch(c) {
+		case '\t':
+		case '\n':
+		case '\v':
+		case '\f':
+		case '\r':
+		case ' ':
+			if(state == S0)
+				continue;
+			break;
+		case '-':
+			if(state == S0)
+				flag |= Fsign;
+			else
+				flag |= Fesign;
+		case '+':
+			if(state == S0)
+				state = S1;
+			else
+			if(state == S5)
+				state = S6;
+			else
+				break;	/* syntax */
+			continue;
+		case '.':
+			flag |= Fdpoint;
+			dp = na;
+			if(state == S0 || state == S1) {
+				state = S3;
+				continue;
+			}
+			if(state == S2) {
+				state = S4;
+				continue;
+			}
+			break;
+		case 'e':
+		case 'E':
+			if(state == S2 || state == S4) {
+				state = S5;
+				continue;
+			}
+			break;
+		}
+		break;
+	}
+
+	/*
+	 * clean up return char-pointer
+	 */
+	switch(state) {
+	case S0:
+		if(xcmp(s, "nan") == 0) {
+			if(aas != nil)
+				*aas = s+3;
+			goto retnan;
+		}
+	case S1:
+		if(xcmp(s, "infinity") == 0) {
+			if(aas != nil)
+				*aas = s+8;
+			goto retinf;
+		}
+		if(xcmp(s, "inf") == 0) {
+			if(aas != nil)
+				*aas = s+3;
+			goto retinf;
+		}
+	case S3:
+		if(aas != nil)
+			*aas = (char*)as;
+		goto ret0;	/* no digits found */
+	case S6:
+		s--;		/* back over +- */
+	case S5:
+		s--;		/* back over e */
+		break;
+	}
+	if(aas != nil)
+		*aas = s;
+
+	if(flag & Fdpoint)
+	while(na > 0 && a[na-1] == '0')
+		na--;
+	if(na == 0)
+		goto ret0;	/* zero */
+	a[na] = 0;
+	if(!(flag & Fdpoint))
+		dp = na;
+	if(flag & Fesign)
+		ex = -ex;
+	dp += ex;
+	if(dp < -Maxe){
+		errno = ERANGE;
+		goto ret0;	/* underflow by exp */
+	} else
+	if(dp > +Maxe)
+		goto retinf;	/* overflow by exp */
+
+	/*
+	 * normalize the decimal ascii number
+	 * to range .[5-9][0-9]* e0
+	 */
+	bp = 0;		/* binary exponent */
+	while(dp > 0)
+		divascii(a, &na, &dp, &bp);
+	while(dp < 0 || a[0] < '5')
+		mulascii(a, &na, &dp, &bp);
+
+	/* close approx by naive conversion */
+	mid[0] = 0;
+	mid[1] = 1;
+	for(i=0; (c=a[i]) != '\0'; i++) {
+		mid[0] = mid[0]*10 + (ulong)(c-'0');
+		mid[1] = mid[1]*10;
+		if(i >= 8)
+			break;
+	}
+	low[0] = umuldiv(mid[0], One, mid[1]);
+	hig[0] = umuldiv(mid[0]+1, One, mid[1]);
+	for(i=1; i<Prec; i++) {
+		low[i] = 0;
+		hig[i] = One-1;
+	}
+
+	/* binary search for closest mantissa */
+	for(;;) {
+		/* mid = (hig + low) / 2 */
+		c = 0;
+		for(i=0; i<Prec; i++) {
+			mid[i] = hig[i] + low[i];
+			if(c)
+				mid[i] += One;
+			c = mid[i] & 1;
+			mid[i] >>= 1;
+		}
+		frnorm(mid);
+
+		/* compare */
+		c = fpcmp(a, mid);
+		if(c > 0) {
+			c = 1;
+			for(i=0; i<Prec; i++)
+				if(low[i] != mid[i]) {
+					c = 0;
+					low[i] = mid[i];
+				}
+			if(c)
+				break;	/* between mid and hig */
+			continue;
+		}
+		if(c < 0) {
+			for(i=0; i<Prec; i++)
+				hig[i] = mid[i];
+			continue;
+		}
+
+		/* only hard part is if even/odd roundings wants to go up */
+		c = mid[Prec-1] & (Sigbit-1);
+		if(c == Sigbit/2 && (mid[Prec-1]&Sigbit) == 0)
+			mid[Prec-1] -= (ulong)c;
+		break;	/* exactly mid */
+	}
+
+	/* normal rounding applies */
+	c = mid[Prec-1] & (Sigbit-1);
+	mid[Prec-1] -= (ulong)c;
+	if(c >= Sigbit/2) {
+		mid[Prec-1] += Sigbit;
+		frnorm(mid);
+	}
+	goto out;
+
+ret0:
+	return 0;
+
+retnan:
+	return __NaN();
+
+retinf:
+	/*
+	 * Unix strtod requires these.  Plan 9 would return Inf(0) or Inf(-1). */
+	errno = ERANGE;
+	if(flag & Fsign)
+		return -HUGE_VAL;
+	return HUGE_VAL;
+
+out:
+	d = 0;
+	for(i=0; i<Prec; i++)
+		d = d*One + (double)mid[i];
+	if(flag & Fsign)
+		d = -d;
+	d = ldexp(d, bp - Prec*Nbits);
+	if(d == 0){	/* underflow */
+		errno = ERANGE;
+	}
+	return d;
+}
+
+static void
+frnorm(ulong *f)
+{
+	int i;
+	ulong c;
+
+	c = 0;
+	for(i=Prec-1; i>0; i--) {
+		f[i] += c;
+		c = f[i] >> Nbits;
+		f[i] &= One-1;
+	}
+	f[0] += c;
+}
+
+static int
+fpcmp(char *a, ulong* f)
+{
+	ulong tf[Prec];
+	int i, d, c;
+
+	for(i=0; i<Prec; i++)
+		tf[i] = f[i];
+
+	for(;;) {
+		/* tf *= 10 */
+		for(i=0; i<Prec; i++)
+			tf[i] = tf[i]*10;
+		frnorm(tf);
+		d = (int)(tf[0] >> Nbits) + '0';
+		tf[0] &= One-1;
+
+		/* compare next digit */
+		c = *a;
+		if(c == 0) {
+			if('0' < d)
+				return -1;
+			if(tf[0] != 0)
+				goto cont;
+			for(i=1; i<Prec; i++)
+				if(tf[i] != 0)
+					goto cont;
+			return 0;
+		}
+		if(c > d)
+			return +1;
+		if(c < d)
+			return -1;
+		a++;
+	cont:;
+	}
+}
+
+static void
+divby(char *a, int *na, int b)
+{
+	int n, c;
+	char *p;
+
+	p = a;
+	n = 0;
+	while(n>>b == 0) {
+		c = *a++;
+		if(c == 0) {
+			while(n) {
+				c = n*10;
+				if(c>>b)
+					break;
+				n = c;
+			}
+			goto xx;
+		}
+		n = n*10 + c-'0';
+		(*na)--;
+	}
+	for(;;) {
+		c = n>>b;
+		n -= c<<b;
+		*p++ = (char)(c + '0');
+		c = *a++;
+		if(c == 0)
+			break;
+		n = n*10 + c-'0';
+	}
+	(*na)++;
+xx:
+	while(n) {
+		n = n*10;
+		c = n>>b;
+		n -= c<<b;
+		*p++ = (char)(c + '0');
+		(*na)++;
+	}
+	*p = 0;
+}
+
+static	Tab	tab1[] =
+{
+	 1,  0, "",
+	 3,  1, "7",
+	 6,  2, "63",
+	 9,  3, "511",
+	13,  4, "8191",
+	16,  5, "65535",
+	19,  6, "524287",
+	23,  7, "8388607",
+	26,  8, "67108863",
+	27,  9, "134217727",
+};
+
+static void
+divascii(char *a, int *na, int *dp, int *bp)
+{
+	int b, d;
+	Tab *t;
+
+	d = *dp;
+	if(d >= (int)(nelem(tab1)))
+		d = (int)(nelem(tab1))-1;
+	t = tab1 + d;
+	b = t->bp;
+	if(memcmp(a, t->cmp, (size_t)t->siz) > 0)
+		d--;
+	*dp -= d;
+	*bp += b;
+	divby(a, na, b);
+}
+
+static void
+mulby(char *a, char *p, char *q, int b)
+{
+	int n, c;
+
+	n = 0;
+	*p = 0;
+	for(;;) {
+		q--;
+		if(q < a)
+			break;
+		c = *q - '0';
+		c = (c<<b) + n;
+		n = c/10;
+		c -= n*10;
+		p--;
+		*p = (char)(c + '0');
+	}
+	while(n) {
+		c = n;
+		n = c/10;
+		c -= n*10;
+		p--;
+		*p = (char)(c + '0');
+	}
+}
+
+static	Tab	tab2[] =
+{
+	 1,  1, "",				/* dp = 0-0 */
+	 3,  3, "125",
+	 6,  5, "15625",
+	 9,  7, "1953125",
+	13, 10, "1220703125",
+	16, 12, "152587890625",
+	19, 14, "19073486328125",
+	23, 17, "11920928955078125",
+	26, 19, "1490116119384765625",
+	27, 19, "7450580596923828125",		/* dp 8-9 */
+};
+
+static void
+mulascii(char *a, int *na, int *dp, int *bp)
+{
+	char *p;
+	int d, b;
+	Tab *t;
+
+	d = -*dp;
+	if(d >= (int)(nelem(tab2)))
+		d = (int)(nelem(tab2))-1;
+	t = tab2 + d;
+	b = t->bp;
+	if(memcmp(a, t->cmp, (size_t)t->siz) < 0)
+		d--;
+	p = a + *na;
+	*bp -= b;
+	*dp += d;
+	*na += d;
+	mulby(a, p+d, p, b);
+}
+
+static int
+xcmp(char *a, char *b)
+{
+	int c1, c2;
+
+	while((c1 = *b++) != '\0') {
+		c2 = *a++;
+		if(isupper(c2))
+			c2 = tolower(c2);
+		if(c1 != c2)
+			return 1;
+	}
+	return 0;
+}
diff --git a/src/lib9/fmt/test.c b/src/lib9/fmt/test.c
new file mode 100644
index 0000000..d82ff78
--- /dev/null
+++ b/src/lib9/fmt/test.c
@@ -0,0 +1,67 @@
+// +build ignore
+
+/*
+ * 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
+main(int argc, char *argv[])
+{
+	quotefmtinstall();
+	print("hello world\n");
+	print("x: %x\n", 0x87654321);
+	print("u: %u\n", 0x87654321);
+	print("d: %d\n", 0x87654321);
+	print("s: %s\n", "hi there");
+	print("q: %q\n", "hi i'm here");
+	print("c: %c\n", '!');
+	print("g: %g %g %g\n", 3.14159, 3.14159e10, 3.14159e-10);
+	print("e: %e %e %e\n", 3.14159, 3.14159e10, 3.14159e-10);
+	print("f: %f %f %f\n", 3.14159, 3.14159e10, 3.14159e-10);
+	print("smiley: %C\n", (Rune)0x263a);
+	print("%g %.18g\n", 2e25, 2e25);
+	print("%2.18g\n", 1.0);
+	print("%2.18f\n", 1.0);
+	print("%f\n", 3.1415927/4);
+	print("%d\n", 23);
+	print("%i\n", 23);
+	print("%0.10d\n", 12345);
+
+	/* test %4$d formats */
+	print("%3$d %4$06d %2$d %1$d\n", 444, 333, 111, 222);
+	print("%3$d %4$06d %2$d %1$d\n", 444, 333, 111, 222);
+	print("%3$d %4$*5$06d %2$d %1$d\n", 444, 333, 111, 222, 20);
+	print("%3$hd %4$*5$06d %2$d %1$d\n", 444, 333, (short)111, 222, 20);
+	print("%3$lld %4$*5$06d %2$d %1$d\n", 444, 333, 111LL, 222, 20);
+
+	/* test %'d formats */
+	print("%'d %'d %'d\n", 1, 2222, 33333333);
+	print("%'019d\n", 0);
+	print("%08d %08d %08d\n", 1, 2222, 33333333);
+	print("%'08d %'08d %'08d\n", 1, 2222, 33333333);
+	print("%'x %'X %'b\n", 0x11111111, 0xabcd1234, 12345);
+	print("%'lld %'lld %'lld\n", 1LL, 222222222LL, 3333333333333LL);
+	print("%019lld %019lld %019lld\n", 1LL, 222222222LL, 3333333333333LL);
+	print("%'019lld %'019lld %'019lld\n", 1LL, 222222222LL, 3333333333333LL);
+	print("%'020lld %'020lld %'020lld\n", 1LL, 222222222LL, 3333333333333LL);
+	print("%'llx %'llX %'llb\n", 0x111111111111LL, 0xabcd12345678LL, 112342345LL);
+	return 0;
+}
diff --git a/src/lib9/fmt/vfprint.c b/src/lib9/fmt/vfprint.c
new file mode 100644
index 0000000..a23c5a0
--- /dev/null
+++ b/src/lib9/fmt/vfprint.c
@@ -0,0 +1,37 @@
+/*
+ * 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
+vfprint(int fd, char *fmt, va_list args)
+{
+	Fmt f;
+	char buf[256];
+	int n;
+
+	fmtfdinit(&f, fd, buf, sizeof(buf));
+	VA_COPY(f.args,args);
+	n = dofmt(&f, fmt);
+	VA_END(f.args);
+	if(n > 0 && __fmtFdFlush(&f) == 0)
+		return -1;
+	return n;
+}
diff --git a/src/lib9/fmt/vseprint.c b/src/lib9/fmt/vseprint.c
new file mode 100644
index 0000000..c9fbfb9
--- /dev/null
+++ b/src/lib9/fmt/vseprint.c
@@ -0,0 +1,44 @@
+/*
+ * 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"
+
+char*
+vseprint(char *buf, char *e, char *fmt, va_list args)
+{
+	Fmt f;
+
+	if(e <= buf)
+		return nil;
+	f.runes = 0;
+	f.start = buf;
+	f.to = buf;
+	f.stop = e - 1;
+	f.flush = 0;
+	f.farg = nil;
+	f.nfmt = 0;
+	VA_COPY(f.args,args);
+	fmtlocaleinit(&f, nil, nil, nil);
+	dofmt(&f, fmt);
+	VA_END(f.args);
+	*(char*)f.to = '\0';
+	return (char*)f.to;
+}
+
diff --git a/src/lib9/fmt/vsmprint.c b/src/lib9/fmt/vsmprint.c
new file mode 100644
index 0000000..46086f9
--- /dev/null
+++ b/src/lib9/fmt/vsmprint.c
@@ -0,0 +1,87 @@
+/*
+ * 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"
+
+static int
+fmtStrFlush(Fmt *f)
+{
+	char *s;
+	int n;
+
+	if(f->start == nil)
+		return 0;
+	n = (int)(uintptr)f->farg;
+	n *= 2;
+	s = (char*)f->start;
+	f->start = realloc(s, (size_t)n);
+	if(f->start == nil){
+		f->farg = nil;
+		f->to = nil;
+		f->stop = nil;
+		free(s);
+		return 0;
+	}
+	f->farg = (void*)(uintptr)n;
+	f->to = (char*)f->start + ((char*)f->to - s);
+	f->stop = (char*)f->start + n - 1;
+	return 1;
+}
+
+int
+fmtstrinit(Fmt *f)
+{
+	int n;
+
+	memset(f, 0, sizeof *f);
+	f->runes = 0;
+	n = 32;
+	f->start = malloc((size_t)n);
+	if(f->start == nil)
+		return -1;
+	f->to = f->start;
+	f->stop = (char*)f->start + n - 1;
+	f->flush = fmtStrFlush;
+	f->farg = (void*)(uintptr)n;
+	f->nfmt = 0;
+	fmtlocaleinit(f, nil, nil, nil);
+	return 0;
+}
+
+/*
+ * print into an allocated string buffer
+ */
+char*
+vsmprint(char *fmt, va_list args)
+{
+	Fmt f;
+	int n;
+
+	if(fmtstrinit(&f) < 0)
+		return nil;
+	VA_COPY(f.args,args);
+	n = dofmt(&f, fmt);
+	VA_END(f.args);
+	if(n < 0){
+		free(f.start);
+		return nil;
+	}
+	return fmtstrflush(&f);
+}
diff --git a/src/lib9/fmt/vsnprint.c b/src/lib9/fmt/vsnprint.c
new file mode 100644
index 0000000..6b38772
--- /dev/null
+++ b/src/lib9/fmt/vsnprint.c
@@ -0,0 +1,43 @@
+/*
+ * 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
+vsnprint(char *buf, int len, char *fmt, va_list args)
+{
+	Fmt f;
+
+	if(len <= 0)
+		return -1;
+	f.runes = 0;
+	f.start = buf;
+	f.to = buf;
+	f.stop = buf + len - 1;
+	f.flush = 0;
+	f.farg = nil;
+	f.nfmt = 0;
+	VA_COPY(f.args,args);
+	fmtlocaleinit(&f, nil, nil, nil);
+	dofmt(&f, fmt);
+	VA_END(f.args);
+	*(char*)f.to = '\0';
+	return (int)((char*)f.to - buf);
+}
diff --git a/src/lib9/fmtlock2.c b/src/lib9/fmtlock2.c
new file mode 100644
index 0000000..a0e2636
--- /dev/null
+++ b/src/lib9/fmtlock2.c
@@ -0,0 +1,40 @@
+// +build !plan9
+
+/*
+Plan 9 from User Space src/lib9/fmtlock2.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/fmtlock2.c
+
+Copyright 2001-2007 Russ Cox.  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 <u.h>
+#include <libc.h>
+
+void
+__fmtlock(void)
+{
+}
+
+void
+__fmtunlock(void)
+{
+}
diff --git a/src/lib9/getenv.c b/src/lib9/getenv.c
new file mode 100644
index 0000000..2454b6b
--- /dev/null
+++ b/src/lib9/getenv.c
@@ -0,0 +1,52 @@
+// +build !plan9
+
+/*
+Plan 9 from User Space src/lib9/getenv.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/getenv.c
+
+Copyright 2001-2007 Russ Cox.  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>
+#define NOPLAN9DEFINES
+#include <libc.h>
+
+char*
+p9getenv(char *s)
+{
+	char *t;
+
+	t = getenv(s);
+	if(t == 0)
+		return 0;
+	return strdup(t);
+}
+
+int
+p9putenv(char *s, char *v)
+{
+	char *t;
+
+	t = smprint("%s=%s", s, v);
+	if(t == nil)
+		return -1;
+	putenv(t);
+	return 0;
+}
diff --git a/src/lib9/getfields.c b/src/lib9/getfields.c
new file mode 100644
index 0000000..0af8388
--- /dev/null
+++ b/src/lib9/getfields.c
@@ -0,0 +1,63 @@
+/*
+Inferno libkern/getfields.c
+http://code.google.com/p/inferno-os/source/browse/libkern/getfields.c
+
+	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+	Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).  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>
+
+int
+getfields(char *str, char **args, int max, int mflag, char *set)
+{
+	Rune r;
+	int nr, intok, narg;
+
+	if(max <= 0)
+		return 0;
+
+	narg = 0;
+	args[narg] = str;
+	if(!mflag)
+		narg++;
+	intok = 0;
+	for(;; str += nr) {
+		nr = chartorune(&r, str);
+		if(r == 0)
+			break;
+		if(utfrune(set, r)) {
+			if(narg >= max)
+				break;
+			*str = 0;
+			intok = 0;
+			args[narg] = str + nr;
+			if(!mflag)
+				narg++;
+		} else {
+			if(!intok && mflag)
+				narg++;
+			intok = 1;
+		}
+	}
+	return narg;
+}
diff --git a/src/lib9/getwd.c b/src/lib9/getwd.c
new file mode 100644
index 0000000..03a8ff1
--- /dev/null
+++ b/src/lib9/getwd.c
@@ -0,0 +1,56 @@
+// +build !plan9
+
+/*
+Plan 9 from User Space src/lib9/getwd.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/getwd.c
+
+Copyright 2001-2007 Russ Cox.  All Rights Reserved.
+Portions Copyright 2011 The Go Authors.  All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+#include <u.h>
+#include <errno.h>
+#include <sys/stat.h>
+#define NOPLAN9DEFINES
+#include <libc.h>
+
+char*
+p9getwd(char *s, int ns)
+{
+	char *pwd;
+	struct stat st1, st2;
+
+	// Clumsy but widespread kludge:
+	// if $PWD is set and matches ".", use it.
+	// Matches glibc's get_current_dir_name and Go's os.Getwd.
+	pwd = getenv("PWD");  // note: getenv, not p9getenv, so no free
+	if(pwd != nil && pwd[0] &&
+			stat(pwd, &st1) >= 0 && stat(".", &st2) >= 0 &&
+			st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino) {
+		if(strlen(pwd) >= ns) {
+			errno = ERANGE;
+			return nil;
+		}
+		strcpy(s, pwd);
+		return s;
+	}
+
+	return getcwd(s, (size_t)ns);
+}
diff --git a/src/lib9/goos.c b/src/lib9/goos.c
new file mode 100644
index 0000000..2d4a800
--- /dev/null
+++ b/src/lib9/goos.c
@@ -0,0 +1,59 @@
+// 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 <u.h>
+#include <libc.h>
+
+static char*
+defgetenv(char *name, char *def)
+{
+	char *p;
+	
+	p = getenv(name);
+	if(p == nil || p[0] == '\0')
+		p = def;
+	return p;
+}
+
+char*
+getgoos(void)
+{
+	return defgetenv("GOOS", GOOS);
+}
+
+char*
+getgoarch(void)
+{
+	return defgetenv("GOARCH", GOARCH);
+}
+
+char*
+getgoroot(void)
+{
+	return defgetenv("GOROOT", GOROOT);
+}
+
+char*
+getgoversion(void)
+{
+	return GOVERSION;
+}
+
+char*
+getgoarm(void)
+{
+	return defgetenv("GOARM", GOARM);
+}
+
+char*
+getgo386(void)
+{
+	return defgetenv("GO386", GO386);
+}
+
+char *
+getgoextlinkenabled(void)
+{
+	return GO_EXTLINK_ENABLED;
+}
diff --git a/src/lib9/jmp.c b/src/lib9/jmp.c
new file mode 100644
index 0000000..733ed70
--- /dev/null
+++ b/src/lib9/jmp.c
@@ -0,0 +1,45 @@
+// +build !plan9
+// +build !windows
+
+/*
+Plan 9 from User Space src/lib9/jmp.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/jmp.c
+
+Copyright 2001-2007 Russ Cox.  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>
+#define NOPLAN9DEFINES
+#include <libc.h>
+
+void
+p9longjmp(p9jmp_buf buf, int val)
+{
+	siglongjmp((void*)buf, val);
+}
+
+void
+p9notejmp(void *x, p9jmp_buf buf, int val)
+{
+	USED(x);
+	siglongjmp((void*)buf, val);
+}
+
diff --git a/src/lib9/main.c b/src/lib9/main.c
new file mode 100644
index 0000000..088b095
--- /dev/null
+++ b/src/lib9/main.c
@@ -0,0 +1,60 @@
+// +build !plan9
+
+/*
+Plan 9 from User Space src/lib9/main.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/main.c
+
+Copyright 2001-2007 Russ Cox.  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>
+#define NOPLAN9DEFINES
+#include <libc.h>
+
+#ifdef WIN32
+#include <windows.h>
+
+static void
+crashhandler(int sig)
+{
+	USED(sig);
+	fprint(2, "%s: internal fatal error.\n", argv0);
+	exit(1);
+}
+#endif
+
+extern void p9main(int, char**);
+
+int
+main(int argc, char **argv)
+{
+#ifdef WIN32
+	signal(SIGSEGV, crashhandler);
+	signal(SIGBUS, crashhandler);
+	// don't display the crash dialog
+	DWORD mode = SetErrorMode(SEM_NOGPFAULTERRORBOX);
+	SetErrorMode(mode | SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX);
+#endif
+	argv0 = argv[0];
+	p9main(argc, argv);
+	exits("main");
+	return 99;
+}
diff --git a/src/lib9/nan.c b/src/lib9/nan.c
new file mode 100644
index 0000000..f17b441
--- /dev/null
+++ b/src/lib9/nan.c
@@ -0,0 +1,54 @@
+// +build !plan9
+
+/*
+Plan 9 from User Space src/lib9/nan.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/nan.c
+
+Copyright 2001-2007 Russ Cox.  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 "fmt/fmtdef.h"
+
+double
+NaN(void)
+{
+	return __NaN();
+}
+
+double
+Inf(int sign)
+{
+	return __Inf(sign);
+}
+
+int
+isNaN(double x)
+{
+	return __isNaN(x);
+}
+
+int
+isInf(double x, int sign)
+{
+	return __isInf(x, sign);
+}
diff --git a/src/lib9/notify.c b/src/lib9/notify.c
new file mode 100644
index 0000000..7843d34
--- /dev/null
+++ b/src/lib9/notify.c
@@ -0,0 +1,300 @@
+// +build !plan9
+// +build !windows
+
+/*
+Plan 9 from User Space src/lib9/notify.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/notify.c
+
+Copyright 2001-2007 Russ Cox.  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.
+*/
+
+/*
+ * Signal handling for Plan 9 programs.
+ * We stubbornly use the strings from Plan 9 instead
+ * of the enumerated Unix constants.
+ * There are some weird translations.  In particular,
+ * a "kill" note is the same as SIGTERM in Unix.
+ * There is no equivalent note to Unix's SIGKILL, since
+ * it's not a deliverable signal anyway.
+ *
+ * We do not handle SIGABRT or SIGSEGV, mainly because
+ * the thread library queues its notes for later, and we want
+ * to dump core with the state at time of delivery.
+ *
+ * We have to add some extra entry points to provide the
+ * ability to tweak which signals are deliverable and which
+ * are acted upon.  Notifydisable and notifyenable play with
+ * the process signal mask.  Notifyignore enables the signal
+ * but will not call notifyf when it comes in.  This is occasionally
+ * useful.
+ */
+
+#include <u.h>
+#include <signal.h>
+#define NOPLAN9DEFINES
+#include <libc.h>
+
+extern char *_p9sigstr(int, char*);
+extern int _p9strsig(char*);
+
+typedef struct Sig Sig;
+struct Sig
+{
+	int sig;			/* signal number */
+	int flags;
+};
+
+enum
+{
+	Restart = 1<<0,
+	Ignore = 1<<1
+};
+
+static Sig sigs[] = {
+	SIGHUP,		0,
+	SIGINT,		0,
+	SIGQUIT,		0,
+	SIGILL,		0,
+	SIGTRAP,		0,
+/*	SIGABRT, 		0, 	*/
+#ifdef SIGEMT
+	SIGEMT,		0,
+#endif
+	SIGFPE,		0,
+	SIGBUS,		0,
+/*	SIGSEGV, 		0, 	*/
+	SIGCHLD,		Restart|Ignore,
+	SIGSYS,		0,
+	SIGPIPE,		Ignore,
+	SIGALRM,		0,
+	SIGTERM,		0,
+	SIGTSTP,		Restart|Ignore,
+/*	SIGTTIN,		Restart|Ignore, */
+/*	SIGTTOU,		Restart|Ignore, */
+	SIGXCPU,		0,
+	SIGXFSZ,		0,
+	SIGVTALRM,	0,
+	SIGUSR1,		0,
+	SIGUSR2,		0,
+#ifdef SIGWINCH
+	SIGWINCH,	Restart|Ignore,
+#endif
+#ifdef SIGINFO
+	SIGINFO,		Restart|Ignore,
+#endif
+};
+
+static Sig*
+findsig(int s)
+{
+	int i;
+
+	for(i=0; i<nelem(sigs); i++)
+		if(sigs[i].sig == s)
+			return &sigs[i];
+	return nil;
+}
+
+/*
+ * The thread library initializes _notejmpbuf to its own
+ * routine which provides a per-pthread jump buffer.
+ * If we're not using the thread library, we assume we are
+ * single-threaded.
+ */
+typedef struct Jmp Jmp;
+struct Jmp
+{
+	p9jmp_buf b;
+};
+
+static Jmp onejmp;
+
+static Jmp*
+getonejmp(void)
+{
+	return &onejmp;
+}
+
+Jmp *(*_notejmpbuf)(void) = getonejmp;
+static void noteinit(void);
+
+/*
+ * Actual signal handler.
+ */
+
+static void (*notifyf)(void*, char*);	/* Plan 9 handler */
+
+static void
+signotify(int sig)
+{
+	char tmp[64];
+	Jmp *j;
+	Sig *s;
+
+	j = (*_notejmpbuf)();
+	switch(p9setjmp(j->b)){
+	case 0:
+		if(notifyf)
+			(*notifyf)(nil, _p9sigstr(sig, tmp));
+		/* fall through */
+	case 1:	/* noted(NDFLT) */
+		if(0)print("DEFAULT %d\n", sig);
+		s = findsig(sig);
+		if(s && (s->flags&Ignore))
+			return;
+		signal(sig, SIG_DFL);
+		raise(sig);
+		_exit(1);
+	case 2:	/* noted(NCONT) */
+		if(0)print("HANDLED %d\n", sig);
+		return;
+	}
+}
+
+static void
+signonotify(int sig)
+{
+	USED(sig);
+}
+
+int
+noted(int v)
+{
+	p9longjmp((*_notejmpbuf)()->b, v==NCONT ? 2 : 1);
+	abort();
+	return 0;
+}
+
+int
+notify(void (*f)(void*, char*))
+{
+	static int init;
+
+	notifyf = f;
+	if(!init){
+		init = 1;
+		noteinit();
+	}
+	return 0;
+}
+
+/*
+ * Nonsense about enabling and disabling signals.
+ */
+typedef void Sighandler(int);
+static Sighandler*
+handler(int s)
+{
+	struct sigaction sa;
+
+	sigaction(s, nil, &sa);
+	return sa.sa_handler;
+}
+
+static int
+notesetenable(int sig, int enabled)
+{
+	sigset_t mask, omask;
+
+	if(sig == 0)
+		return -1;
+
+	sigemptyset(&mask);
+	sigaddset(&mask, sig);
+	sigprocmask(enabled ? SIG_UNBLOCK : SIG_BLOCK, &mask, &omask);
+	return !sigismember(&omask, sig);
+}
+
+int
+noteenable(char *msg)
+{
+	return notesetenable(_p9strsig(msg), 1);
+}
+
+int
+notedisable(char *msg)
+{
+	return notesetenable(_p9strsig(msg), 0);
+}
+
+static int
+notifyseton(int s, int on)
+{
+	Sig *sig;
+	struct sigaction sa, osa;
+
+	sig = findsig(s);
+	if(sig == nil)
+		return -1;
+	memset(&sa, 0, sizeof sa);
+	sa.sa_handler = on ? signotify : signonotify;
+	if(sig->flags&Restart)
+		sa.sa_flags |= SA_RESTART;
+
+	/*
+	 * We can't allow signals within signals because there's
+	 * only one jump buffer.
+	 */
+	sigfillset(&sa.sa_mask);
+
+	/*
+	 * Install handler.
+	 */
+	sigaction(sig->sig, &sa, &osa);
+	return osa.sa_handler == signotify;
+}
+
+int
+notifyon(char *msg)
+{
+	return notifyseton(_p9strsig(msg), 1);
+}
+
+int
+notifyoff(char *msg)
+{
+	return notifyseton(_p9strsig(msg), 0);
+}
+
+/*
+ * Initialization follows sigs table.
+ */
+static void
+noteinit(void)
+{
+	int i;
+	Sig *sig;
+
+	for(i=0; i<nelem(sigs); i++){
+		sig = &sigs[i];
+		/*
+		 * If someone has already installed a handler,
+		 * It's probably some ld preload nonsense,
+		 * like pct (a SIGVTALRM-based profiler).
+		 * Or maybe someone has already called notifyon/notifyoff.
+		 * Leave it alone.
+		 */
+		if(handler(sig->sig) != SIG_DFL)
+			continue;
+		notifyseton(sig->sig, 1);
+	}
+}
+
diff --git a/src/lib9/nulldir.c b/src/lib9/nulldir.c
new file mode 100644
index 0000000..2157ff3
--- /dev/null
+++ b/src/lib9/nulldir.c
@@ -0,0 +1,37 @@
+// +build !plan9
+
+/*
+Inferno lib9/nulldir.c
+http://code.google.com/p/inferno-os/source/browse/lib9/nulldir.c
+
+	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+	Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).  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>
+
+void
+nulldir(Dir *d)
+{
+	memset(d, ~0, sizeof(Dir));
+	d->name = d->uid = d->gid = d->muid = "";
+}
diff --git a/src/lib9/open.c b/src/lib9/open.c
new file mode 100644
index 0000000..7f53c8e
--- /dev/null
+++ b/src/lib9/open.c
@@ -0,0 +1,70 @@
+// +build !plan9
+
+/*
+Plan 9 from User Space src/lib9/open.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/open.c
+
+Copyright 2001-2007 Russ Cox.  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 _GNU_SOURCE	/* for Linux O_DIRECT */
+#include <u.h>
+#define NOPLAN9DEFINES
+#include <sys/file.h>
+#include <libc.h>
+#ifndef O_DIRECT
+#define O_DIRECT 0
+#endif
+
+int
+p9open(char *name, int mode)
+{
+	int rclose;
+	int fd, umode, rdwr;
+
+	rdwr = mode&3;
+	umode = rdwr;
+	rclose = mode&ORCLOSE;
+	mode &= ~(3|ORCLOSE);
+	if(mode&OTRUNC){
+		umode |= O_TRUNC;
+		mode ^= OTRUNC;
+	}
+	if(mode&ODIRECT){
+		umode |= O_DIRECT;
+		mode ^= ODIRECT;
+	}
+	if(mode&OAPPEND){
+		umode |= O_APPEND;
+		mode ^= OAPPEND;
+	}
+	if(mode){
+		werrstr("mode 0x%x not supported", mode);
+		return -1;
+	}
+	umode |= O_BINARY;
+	fd = open(name, umode);
+	if(fd >= 0){
+		if(rclose)
+			remove(name);
+	}
+	return fd;
+}
diff --git a/src/lib9/readn.c b/src/lib9/readn.c
new file mode 100644
index 0000000..7dfe9e5
--- /dev/null
+++ b/src/lib9/readn.c
@@ -0,0 +1,50 @@
+// +build !plan9
+
+/*
+Inferno lib9/readn.c
+http://code.google.com/p/inferno-os/source/browse/lib9/readn.c
+
+	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+	Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).  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>
+
+long
+readn(int f, void *av, long n)
+{
+	char *a;
+	long m, t;
+
+	a = av;
+	t = 0;
+	while(t < n){
+		m = read(f, a+t, (size_t)(n-t));
+		if(m <= 0){
+			if(t == 0)
+				return m;
+			break;
+		}
+		t += m;
+	}
+	return t;
+}
diff --git a/src/lib9/rfork.c b/src/lib9/rfork.c
new file mode 100644
index 0000000..23b3ee6
--- /dev/null
+++ b/src/lib9/rfork.c
@@ -0,0 +1,156 @@
+// +build !plan9
+// +build !windows
+
+/*
+Plan 9 from User Space src/lib9/rfork.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/rfork.c
+
+Copyright 2001-2007 Russ Cox.  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/wait.h>
+#include <signal.h>
+#include <libc.h>
+#undef rfork
+
+static void
+nop(int x)
+{
+	USED(x);
+}
+
+int
+p9rfork(int flags)
+{
+	int pid, status;
+	int p[2];
+	int n;
+	char buf[128], *q;
+	extern char **environ;
+
+	if((flags&(RFPROC|RFFDG|RFMEM)) == (RFPROC|RFFDG)){
+		/* check other flags before we commit */
+		flags &= ~(RFPROC|RFFDG|RFENVG);
+		n = (flags & ~(RFNOTEG|RFNAMEG|RFNOWAIT|RFCENVG));
+		if(n){
+			werrstr("unknown flags %08ux in rfork", n);
+			return -1;
+		}
+		if(flags&RFNOWAIT){
+			/*
+			 * BUG - should put the signal handler back after we
+			 * finish, but I just don't care.  If a program calls with
+			 * NOWAIT once, they're not likely to want child notes
+			 * after that.
+			 */
+			signal(SIGCHLD, nop);
+			if(pipe(p) < 0)
+				return -1;
+		}
+		pid = fork();
+		if(pid == -1)
+			return -1;
+		if(flags&RFNOWAIT){
+			flags &= ~RFNOWAIT;
+			if(pid){
+				/*
+				 * Parent - wait for child to fork wait-free child.
+				 * Then read pid from pipe.  Assume pipe buffer can absorb the write.
+				 */
+				close(p[1]);
+				status = 0;
+				if(wait4(pid, &status, 0, 0) < 0){
+					werrstr("pipe dance - wait4 - %r");
+					close(p[0]);
+					return -1;
+				}
+				n = (int)readn(p[0], buf, sizeof buf-1);
+				close(p[0]);
+				if(!WIFEXITED(status) || WEXITSTATUS(status)!=0 || n <= 0){
+					if(!WIFEXITED(status))
+						werrstr("pipe dance - !exited 0x%ux", status);
+					else if(WEXITSTATUS(status) != 0)
+						werrstr("pipe dance - non-zero status 0x%ux", status);
+					else if(n < 0)
+						werrstr("pipe dance - pipe read error - %r");
+					else if(n == 0)
+						werrstr("pipe dance - pipe read eof");
+					else
+						werrstr("pipe dance - unknown failure");
+					return -1;
+				}
+				buf[n] = 0;
+				if(buf[0] == 'x'){
+					werrstr("%s", buf+2);
+					return -1;
+				}
+				pid = (int)strtol(buf, &q, 0);
+			}else{
+				/*
+				 * Child - fork a new child whose wait message can't
+				 * get back to the parent because we're going to exit!
+				 */
+				signal(SIGCHLD, SIG_IGN);
+				close(p[0]);
+				pid = fork();
+				if(pid){
+					/* Child parent - send status over pipe and exit. */
+					if(pid > 0)
+						fprint(p[1], "%d", pid);
+					else
+						fprint(p[1], "x %r");
+					close(p[1]);
+					_exit(0);
+				}else{
+					/* Child child - close pipe. */
+					close(p[1]);
+				}
+			}
+		}
+		if(pid != 0)
+			return pid;
+		if(flags&RFCENVG)
+			if(environ)
+				*environ = nil;
+	}
+	if(flags&RFPROC){
+		werrstr("cannot use rfork for shared memory -- use libthread");
+		return -1;
+	}
+	if(flags&RFNAMEG){
+		/* XXX set $NAMESPACE to a new directory */
+		flags &= ~RFNAMEG;
+	}
+	if(flags&RFNOTEG){
+		setpgid(0, getpid());
+		flags &= ~RFNOTEG;
+	}
+	if(flags&RFNOWAIT){
+		werrstr("cannot use RFNOWAIT without RFPROC");
+		return -1;
+	}
+	if(flags){
+		werrstr("unknown flags %08ux in rfork", flags);
+		return -1;
+	}
+	return 0;
+}
diff --git a/src/lib9/run_plan9.c b/src/lib9/run_plan9.c
new file mode 100644
index 0000000..2993262
--- /dev/null
+++ b/src/lib9/run_plan9.c
@@ -0,0 +1,40 @@
+// 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 plan9
+
+#include <u.h>
+#include <libc.h>
+
+int
+runcmd(char **argv)
+{
+	int pid;
+	Waitmsg *w;
+	
+	switch(pid = fork()) {
+	case -1:
+		return -1;
+	case 0:
+		exec(argv[0], argv);
+		fprint(2, "exec %s: %r\n", argv[0]);
+		exits("exec");
+	}
+	
+	w = wait();
+	if(w == nil)
+		return -1;
+	if(w->pid != pid) {
+		werrstr("unexpected pid in wait");
+		free(w);
+		return -1;
+	}
+	if(w->msg[0]) {
+		werrstr("unsuccessful exit status: %s", w->msg);
+		free(w);
+		return -1;
+	}
+	free(w);
+	return 0;
+}
diff --git a/src/lib9/run_unix.c b/src/lib9/run_unix.c
new file mode 100644
index 0000000..1acaefe
--- /dev/null
+++ b/src/lib9/run_unix.c
@@ -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.
+
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+
+#include <u.h>
+#include <errno.h>
+#include <sys/wait.h>
+#define NOPLAN9DEFINES
+#include <libc.h>
+
+int
+runcmd(char **argv)
+{
+	int pid, pid1, status;
+	
+	switch(pid = fork()) {
+	case -1:
+		return -1;
+	case 0:
+		execvp(argv[0], argv);
+		fprint(2, "exec %s: %r\n", argv[0]);
+		_exit(1);
+	}
+	
+	while((pid1 = wait(&status)) < 0) {
+		if(errno != EINTR) {
+			werrstr("waitpid: %r");
+			return -1;
+		}
+	}
+	if(pid1 != pid) {
+		werrstr("unexpected pid in wait");
+		return -1;
+	}
+	if(!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
+		werrstr("unsuccessful exit status %#x", status);
+		return -1;
+	}
+	return 0;
+}
+
diff --git a/src/lib9/run_windows.c b/src/lib9/run_windows.c
new file mode 100644
index 0000000..87875b4
--- /dev/null
+++ b/src/lib9/run_windows.c
@@ -0,0 +1,83 @@
+// 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 <windows.h>
+#define NOPLAN9DEFINES
+#include <libc.h>
+#include "win.h"
+
+int
+runcmd(char **argv)
+{
+	// Mostly copied from ../cmd/dist/windows.c.
+	// If there's a bug here, fix the logic there too.
+	int i, j, nslash;
+	Fmt fmt;
+	char *q;
+	WinRune *r;
+	STARTUPINFOW si;
+	PROCESS_INFORMATION pi;
+	DWORD code;
+
+	fmtstrinit(&fmt);
+	for(i=0; argv[i]; i++) {
+		if(i > 0)
+			fmtprint(&fmt, " ");
+		q = argv[i];
+		if(strstr(q, " ") || strstr(q, "\t") || strstr(q, "\"") || strstr(q, "\\\\") || (strlen(q) > 0 && q[strlen(q)-1] == '\\')) {
+			fmtprint(&fmt, "\"");
+			nslash = 0;
+			for(; *q; q++) {
+				if(*q == '\\') {
+					nslash++;
+					continue;
+				}
+				if(*q == '"') {
+					for(j=0; j<2*nslash+1; j++)
+						fmtprint(&fmt, "\\");
+					nslash = 0;
+				}
+				for(j=0; j<nslash; j++)
+					fmtprint(&fmt, "\\");
+				nslash = 0;
+				fmtprint(&fmt, "\"");
+			}
+			for(j=0; j<2*nslash; j++)
+				fmtprint(&fmt, "\\");
+			fmtprint(&fmt, "\"");
+		} else {
+			fmtprint(&fmt, "%s", q);
+		}
+	}
+	
+	q = fmtstrflush(&fmt);
+	r = torune(q);
+	free(q);
+
+	memset(&si, 0, sizeof si);
+	si.cb = sizeof si;
+	si.dwFlags = STARTF_USESTDHANDLES;
+	si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
+	si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
+
+	if(!CreateProcessW(nil, r, nil, nil, TRUE, 0, nil, nil, &si, &pi)) {
+		free(r);
+		return -1;
+	}
+
+	free(r);
+	if(WaitForMultipleObjects(1, &pi.hProcess, FALSE, INFINITE) != 0)
+		return -1;
+	i = GetExitCodeProcess(pi.hProcess, &code);
+	CloseHandle(pi.hProcess);
+	CloseHandle(pi.hThread);
+	if(!i)
+		return -1;
+	if(code != 0) {
+		werrstr("unsuccessful exit status: %d", (int)code);
+		return -1;
+	}
+	return 0;
+}
diff --git a/src/lib9/seek.c b/src/lib9/seek.c
new file mode 100644
index 0000000..0a0706c
--- /dev/null
+++ b/src/lib9/seek.c
@@ -0,0 +1,35 @@
+// +build !plan9
+
+/*
+Plan 9 from User Space src/lib9/seek.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/seek.c
+
+Copyright 2001-2007 Russ Cox.  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>
+
+vlong
+seek(int fd, vlong offset, int whence)
+{
+	return lseek(fd, offset, whence);
+}
diff --git a/src/lib9/strecpy.c b/src/lib9/strecpy.c
new file mode 100644
index 0000000..4b2b92b
--- /dev/null
+++ b/src/lib9/strecpy.c
@@ -0,0 +1,45 @@
+// +build !plan9
+
+/*
+Inferno lib9/strecpy.c
+http://code.google.com/p/inferno-os/source/browse/lib9/strecpy.c
+
+	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+	Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).  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>
+
+char*
+strecpy(char *to, char *e, char *from)
+{
+	if(to >= e)
+		return to;
+	to = memccpy(to, from, '\0', (size_t)(e - to));
+	if(to == nil){
+		to = e - 1;
+		*to = '\0';
+	}else{
+		to--;
+	}
+	return to;
+}
diff --git a/src/lib9/sysfatal.c b/src/lib9/sysfatal.c
new file mode 100644
index 0000000..9789061
--- /dev/null
+++ b/src/lib9/sysfatal.c
@@ -0,0 +1,49 @@
+// +build !plan9
+
+/*
+Plan 9 from User Space src/lib9/sysfatal.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/sysfatal.c
+
+Copyright 2001-2007 Russ Cox.  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>
+
+void (*_sysfatal)(char*, ...);
+
+void
+sysfatal(char *fmt, ...)
+{
+	char buf[256];
+	va_list arg;
+
+	va_start(arg, fmt);
+	if(_sysfatal)
+		(*_sysfatal)(fmt, arg);
+	vseprint(buf, buf+sizeof buf, fmt, arg);
+	va_end(arg);
+
+	__fixargv0();
+	fprint(2, "%s: %s\n", argv0 ? argv0 : "<prog>", buf);
+	exits("fatal");
+}
+
diff --git a/src/lib9/tempdir_plan9.c b/src/lib9/tempdir_plan9.c
new file mode 100644
index 0000000..80d7ddb
--- /dev/null
+++ b/src/lib9/tempdir_plan9.c
@@ -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.
+
+// +build plan9
+
+#include <u.h>
+#include <libc.h>
+
+char*
+mktempdir(void)
+{
+	char *p;
+	int fd, i;
+	
+	p = smprint("/tmp/go-link-XXXXXX");
+	for(i=0; i<1000; i++) {
+		sprint(p, "/tmp/go-link-%06x", nrand((1<<24)-1));
+		fd = create(p, OREAD|OEXCL, 0700|DMDIR);
+		if(fd >= 0) {
+			close(fd);
+			return p;
+		}
+	}
+	free(p);
+	return nil;
+}
+
+void
+removeall(char *p)
+{
+	int fd, n, i;
+	Dir *d;
+	char *q;
+	
+	if(remove(p) >= 0)
+		return;
+	if((d = dirstat(p)) == nil)
+		return;
+	if(!(d->mode & DMDIR)) {
+		free(d);
+		return;
+	}
+	free(d);
+	
+	if((fd = open(p, OREAD)) < 0)
+		return;
+	n = dirreadall(fd, &d);
+	close(fd);
+	for(i=0; i<n; i++) {
+		q = smprint("%s/%s", p, d[i].name);
+		removeall(q);
+		free(q);
+	}
+	free(d);
+}
diff --git a/src/lib9/tempdir_unix.c b/src/lib9/tempdir_unix.c
new file mode 100644
index 0000000..269d538
--- /dev/null
+++ b/src/lib9/tempdir_unix.c
@@ -0,0 +1,52 @@
+// 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
+
+#include <u.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#define NOPLAN9DEFINES
+#include <libc.h>
+
+char*
+mktempdir(void)
+{
+	char *tmp, *p;
+	
+	tmp = getenv("TMPDIR");
+	if(tmp == nil || strlen(tmp) == 0)
+		tmp = "/var/tmp";
+	p = smprint("%s/go-link-XXXXXX", tmp);
+	if(mkdtemp(p) == nil)
+		return nil;
+	return p;
+}
+
+void
+removeall(char *p)
+{
+	DIR *d;
+	struct dirent *dp;
+	char *q;
+	struct stat st;
+
+	if(stat(p, &st) < 0)
+		return;
+	if(!S_ISDIR(st.st_mode)) {
+		unlink(p);
+		return;
+	}
+
+	d = opendir(p);
+	while((dp = readdir(d)) != nil) {
+		if(strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0)
+			continue;
+		q = smprint("%s/%s", p, dp->d_name);
+		removeall(q);
+		free(q);
+	}
+	closedir(d);
+	rmdir(p);
+}
diff --git a/src/lib9/tempdir_windows.c b/src/lib9/tempdir_windows.c
new file mode 100644
index 0000000..4c3df7c
--- /dev/null
+++ b/src/lib9/tempdir_windows.c
@@ -0,0 +1,113 @@
+// 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 <windows.h>
+#include <libc.h>
+#include "win.h"
+
+char*
+toutf(WinRune *r)
+{
+	Rune *r1;
+	int i, n;
+	char *p;
+	
+	n = 0;
+	while(r[n] != '\0')
+		n++;
+	n++;
+	r1 = malloc(n*sizeof r1[0]);
+	for(i=0; i<n; i++)
+		r1[i] = r[i];
+	p = smprint("%S", r1);
+	free(r1);
+	return p;
+}
+
+WinRune*
+torune(char *p)
+{
+	int i, n;
+	Rune rr;
+	WinRune *r;
+	
+	n = utflen(p);
+	r = malloc((n+1)*sizeof r[0]);
+	for(i=0; i<n; i++) {
+		p += chartorune(&rr, p);
+		r[i] = rr;
+	}
+	r[n] = '\0';
+	return r;
+}
+
+char*
+mktempdir(void)
+{
+	WinRune buf[1024];
+	WinRune tmp[MAX_PATH];
+	WinRune golink[] = {'g', 'o', 'l', 'i', 'n', 'k', '\0'};
+	int n;
+	
+	n = GetTempPathW(nelem(buf), buf);
+	if(n <= 0)
+		return nil;
+	buf[n] = '\0';
+	
+	if(GetTempFileNameW(buf, golink, 0, tmp) == 0)
+		return nil;
+	DeleteFileW(tmp);
+	if(!CreateDirectoryW(tmp, nil))
+		return nil;
+	
+	return toutf(tmp);
+}
+
+void
+removeall(char *p)
+{
+	WinRune *r, *r1;
+	DWORD attr;
+	char *q, *qt, *elem;
+	HANDLE h;
+	WIN32_FIND_DATAW data;
+	
+	r = torune(p);
+	attr = GetFileAttributesW(r);
+	if(attr == INVALID_FILE_ATTRIBUTES || !(attr & FILE_ATTRIBUTE_DIRECTORY)) {
+		DeleteFileW(r);
+		free(r);
+		return;
+	}
+
+	q = smprint("%s\\*", p);
+	r1 = torune(q);
+	free(q);
+	h = FindFirstFileW(r1, &data);
+	if(h == INVALID_HANDLE_VALUE)
+		goto done;
+	do{
+		q = toutf(data.cFileName);
+		elem = strrchr(q, '\\');
+		if(elem != nil)
+			elem++;
+		else
+			elem = q;
+		if(strcmp(elem, ".") == 0 || strcmp(elem, "..") == 0) {
+			free(q);
+			continue;
+		}
+		qt = smprint("%s\\%s", p, q);
+		free(q);
+		removeall(qt);
+		free(qt);
+	}while(FindNextFileW(h, &data));
+	FindClose(h);
+
+done:
+	free(r1);
+	RemoveDirectoryW(r);
+	free(r);
+}
diff --git a/src/lib9/time.c b/src/lib9/time.c
new file mode 100644
index 0000000..e1b87a7
--- /dev/null
+++ b/src/lib9/time.c
@@ -0,0 +1,68 @@
+// +build !plan9
+
+/*
+Plan 9 from User Space src/lib9/time.c
+http://code.swtch.com/plan9port/src/tip/src/lib9/time.c
+
+Copyright 2001-2007 Russ Cox.  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/time.h>
+#include <time.h>
+#ifndef _WIN32
+#include <sys/resource.h>
+#endif
+#define NOPLAN9DEFINES
+#include <libc.h>
+
+long
+p9times(long *t)
+{
+#ifdef _WIN32
+	memset(t, 0, 4*sizeof(long));
+#else
+	struct rusage ru, cru;
+
+	if(getrusage(0, &ru) < 0 || getrusage(-1, &cru) < 0)
+		return -1;
+
+	t[0] = ru.ru_utime.tv_sec*1000 + ru.ru_utime.tv_usec/1000;
+	t[1] = ru.ru_stime.tv_sec*1000 + ru.ru_stime.tv_usec/1000;
+	t[2] = cru.ru_utime.tv_sec*1000 + cru.ru_utime.tv_usec/1000;
+	t[3] = cru.ru_stime.tv_sec*1000 + cru.ru_stime.tv_usec/1000;
+#endif
+
+	/* BUG */
+	return t[0]+t[1]+t[2]+t[3];
+}
+
+double
+p9cputime(void)
+{
+	long t[4];
+	double d;
+
+	if(p9times(t) < 0)
+		return -1.0;
+
+	d = (double)t[0]+(double)t[1]+(double)t[2]+(double)t[3];
+	return d/1000.0;
+}
diff --git a/src/lib9/tokenize.c b/src/lib9/tokenize.c
new file mode 100644
index 0000000..a095fcd
--- /dev/null
+++ b/src/lib9/tokenize.c
@@ -0,0 +1,135 @@
+// +build !plan9
+
+/*
+Inferno lib9/tokenize.c
+http://code.google.com/p/inferno-os/source/browse/lib9/tokenize.c
+
+	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+	Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).  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>
+
+static char qsep[] = " \t\r\n";
+
+static char*
+qtoken(char *s, char *sep)
+{
+	int quoting;
+	char *t;
+
+	quoting = 0;
+	t = s;	/* s is output string, t is input string */
+	while(*t!='\0' && (quoting || utfrune(sep, (Rune)*t)==nil)){
+		if(*t != '\''){
+			*s++ = *t++;
+			continue;
+		}
+		/* *t is a quote */
+		if(!quoting){
+			quoting = 1;
+			t++;
+			continue;
+		}
+		/* quoting and we're on a quote */
+		if(t[1] != '\''){
+			/* end of quoted section; absorb closing quote */
+			t++;
+			quoting = 0;
+			continue;
+		}
+		/* doubled quote; fold one quote into two */
+		t++;
+		*s++ = *t++;
+	}
+	if(*s != '\0'){
+		*s = '\0';
+		if(t == s)
+			t++;
+	}
+	return t;
+}
+
+static char*
+etoken(char *t, char *sep)
+{
+	int quoting;
+
+	/* move to end of next token */
+	quoting = 0;
+	while(*t!='\0' && (quoting || utfrune(sep, (Rune)*t)==nil)){
+		if(*t != '\''){
+			t++;
+			continue;
+		}
+		/* *t is a quote */
+		if(!quoting){
+			quoting = 1;
+			t++;
+			continue;
+		}
+		/* quoting and we're on a quote */
+		if(t[1] != '\''){
+			/* end of quoted section; absorb closing quote */
+			t++;
+			quoting = 0;
+			continue;
+		}
+		/* doubled quote; fold one quote into two */
+		t += 2;
+	}
+	return t;
+}
+
+int
+gettokens(char *s, char **args, int maxargs, char *sep)
+{
+	int nargs;
+
+	for(nargs=0; nargs<maxargs; nargs++){
+		while(*s!='\0' && utfrune(sep, (Rune)*s)!=nil)
+			*s++ = '\0';
+		if(*s == '\0')
+			break;
+		args[nargs] = s;
+		s = etoken(s, sep);
+	}
+
+	return nargs;
+}
+
+int
+tokenize(char *s, char **args, int maxargs)
+{
+	int nargs;
+
+	for(nargs=0; nargs<maxargs; nargs++){
+		while(*s!='\0' && utfrune(qsep, (Rune)*s)!=nil)
+			s++;
+		if(*s == '\0')
+			break;
+		args[nargs] = s;
+		s = qtoken(s, qsep);
+	}
+
+	return nargs;
+}
diff --git a/src/lib9/utf/Makefile b/src/lib9/utf/Makefile
new file mode 100644
index 0000000..fe6f635
--- /dev/null
+++ b/src/lib9/utf/Makefile
@@ -0,0 +1,30 @@
+# Copyright 2010 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+# The library is built by the Makefile in the parent directory.
+# This Makefile only builds mkrunetype.
+# GOROOT, GOOS, and GOARCH must be set explicitly.
+
+TARG=mkrunetype
+
+UnicodeData-%.txt:
+	curl http://www.unicode.org/Public/$*/ucd/UnicodeData.txt >_$@
+	mv _$@ $@
+
+mkrunetype: mkrunetype.c
+	cc -I../../../include -o mkrunetype -L$(GOROOT)/pkg/obj/$(GOOS)_$(GOARCH)/ mkrunetype.c -l9
+
+runetypebody-%.h: mkrunetype UnicodeData-%.txt
+	mkrunetype -p UnicodeData-$*.txt >_$@
+	mv _$@ $@
+
+CLEANFILES+=UnicodeData.txt
+
+UNICODE_VERSION=6.3.0
+
+test: mkrunetype UnicodeData-$(UNICODE_VERSION).txt
+	mkrunetype -c UnicodeData-$(UNICODE_VERSION).txt
+
+clean:
+	rm -f UnicodeData.txt mkrunetype
diff --git a/src/lib9/utf/mkrunetype.c b/src/lib9/utf/mkrunetype.c
new file mode 100644
index 0000000..01eb6b6
--- /dev/null
+++ b/src/lib9/utf/mkrunetype.c
@@ -0,0 +1,734 @@
+// 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
+
+/*
+ * make is(upper|lower|title|space|alpha)rune and
+ * to(upper|lower|title)rune from a UnicodeData.txt file.
+ * these can be found at unicode.org
+ *
+ * with -c, runs a check of the existing runetype functions vs.
+ * those extracted from UnicodeData.
+ *
+ * with -p, generates tables for pairs of chars, as well as for ranges
+ * and singletons.
+ *
+ * UnicodeData defines 4 fields of interest:
+ * 1) a category
+ * 2) an upper case mapping
+ * 3) a lower case mapping
+ * 4) a title case mapping
+ *
+ * toupper, tolower, and totitle are defined directly from the mapping.
+ *
+ * isalpharune(c) is true iff c is a "letter" category
+ * isupperrune(c) is true iff c is the target of toupperrune,
+ *	or is in the uppercase letter category
+ * similarly for islowerrune and istitlerune.
+ * isspacerune is true for space category chars, "C" locale white space chars,
+ *	and two additions:
+ *	0085	"next line" control char
+ *	feff]	"zero-width non-break space"
+ * isdigitrune is true iff c is a numeric-digit category.
+ */
+
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+#include "utf.h"
+#include "utfdef.h"
+
+enum {
+	/*
+	 * fields in the unicode data file
+	 */
+	FIELD_CODE,
+	FIELD_NAME,
+	FIELD_CATEGORY,
+	FIELD_COMBINING,
+	FIELD_BIDIR,
+	FIELD_DECOMP,
+	FIELD_DECIMAL_DIG,
+	FIELD_DIG,
+	FIELD_NUMERIC_VAL,
+	FIELD_MIRRORED,
+	FIELD_UNICODE_1_NAME,
+	FIELD_COMMENT,
+	FIELD_UPPER,
+	FIELD_LOWER,
+	FIELD_TITLE,
+	NFIELDS,
+
+	MAX_LINE	= 1024,
+
+	TO_OFFSET	= 1 << 20,
+
+	NRUNES		= 1 << 21,
+};
+
+#define TO_DELTA(xmapped,x)	(TO_OFFSET + (xmapped) - (x))
+
+static char	myisspace[NRUNES];
+static char	myisalpha[NRUNES];
+static char	myisdigit[NRUNES];
+static char	myisupper[NRUNES];
+static char	myislower[NRUNES];
+static char	myistitle[NRUNES];
+
+static int	mytoupper[NRUNES];
+static int	mytolower[NRUNES];
+static int	mytotitle[NRUNES];
+
+static void	check(void);
+static void	mktables(char *src, int usepairs);
+static void	fatal(const char *fmt, ...);
+static int	mygetfields(char **fields, int nfields, char *str, const char *delim);
+static int	getunicodeline(FILE *in, char **fields, char *buf);
+static int	getcode(char *s);
+
+static void
+usage(void)
+{
+	fprintf(stderr, "usage: mktables [-cp] <UnicodeData.txt>\n");
+	exit(1);
+}
+
+void
+main(int argc, char *argv[])
+{
+	FILE *in;
+	char buf[MAX_LINE], buf2[MAX_LINE];
+	char *fields[NFIELDS + 1], *fields2[NFIELDS + 1];
+	char *p;
+	int i, code, last, docheck, usepairs;
+
+	docheck = 0;
+	usepairs = 0;
+	ARGBEGIN{
+	case 'c':
+		docheck = 1;
+		break;
+	case 'p':
+		usepairs = 1;
+		break;
+	default:
+		usage();
+	}ARGEND
+
+	if(argc != 1){
+		usage();
+	}
+
+	in = fopen(argv[0], "r");
+	if(in == NULL){
+		fatal("can't open %s", argv[0]);
+	}
+
+	for(i = 0; i < NRUNES; i++){
+		mytoupper[i] = i;
+		mytolower[i] = i;
+		mytotitle[i] = i;
+	}
+
+	/*
+	 * make sure isspace has all of the "C" locale whitespace chars
+	 */
+	myisspace['\t'] = 1;
+	myisspace['\n'] = 1;
+	myisspace['\r'] = 1;
+	myisspace['\f'] = 1;
+	myisspace['\v'] = 1;
+
+	/*
+	 * a couple of other exceptions
+	 */
+	myisspace[0x85] = 1;	/* control char, "next line" */
+	myisspace[0xfeff] = 1;	/* zero-width non-break space */
+
+	last = -1;
+	while(getunicodeline(in, fields, buf)){
+		code = getcode(fields[FIELD_CODE]);
+		if (code >= NRUNES)
+			fatal("code-point value too big: %x", code);
+		if(code <= last)
+			fatal("bad code sequence: %x then %x", last, code);
+		last = code;
+
+		/*
+		 * check for ranges
+		 */
+		p = fields[FIELD_CATEGORY];
+		if(strstr(fields[FIELD_NAME], ", First>") != NULL){
+			if(!getunicodeline(in, fields2, buf2))
+				fatal("range start at eof");
+			if (strstr(fields2[FIELD_NAME], ", Last>") == NULL)
+				fatal("range start not followed by range end");
+			last = getcode(fields2[FIELD_CODE]);
+			if(last <= code)
+				fatal("range out of sequence: %x then %x", code, last);
+			if(strcmp(p, fields2[FIELD_CATEGORY]) != 0)
+				fatal("range with mismatched category");
+		}
+
+		/*
+		 * set properties and conversions
+		 */
+		for (; code <= last; code++){
+			if(p[0] == 'L')
+				myisalpha[code] = 1;
+			if(p[0] == 'Z')
+				myisspace[code] = 1;
+
+			if(strcmp(p, "Lu") == 0)
+				myisupper[code] = 1;
+			if(strcmp(p, "Ll") == 0)
+				myislower[code] = 1;
+
+			if(strcmp(p, "Lt") == 0)
+				myistitle[code] = 1;
+
+			if(strcmp(p, "Nd") == 0)
+				myisdigit[code] = 1;
+
+			/*
+			 * when finding conversions, also need to mark
+			 * upper/lower case, since some chars, like
+			 * "III" (0x2162), aren't defined as letters but have a
+			 * lower case mapping ("iii" (0x2172)).
+			 */
+			if(fields[FIELD_UPPER][0] != '\0'){
+				mytoupper[code] = getcode(fields[FIELD_UPPER]);
+			}
+			if(fields[FIELD_LOWER][0] != '\0'){
+				mytolower[code] = getcode(fields[FIELD_LOWER]);
+			}
+			if(fields[FIELD_TITLE][0] != '\0'){
+				mytotitle[code] = getcode(fields[FIELD_TITLE]);
+			}
+		}
+	}
+
+	fclose(in);
+
+	/*
+	 * check for codes with no totitle mapping but a toupper mapping.
+	 * these appear in UnicodeData-2.0.14.txt, but are almost certainly
+	 * erroneous.
+	 */
+	for(i = 0; i < NRUNES; i++){
+		if(mytotitle[i] == i
+		&& mytoupper[i] != i
+		&& !myistitle[i])
+			fprintf(stderr, "warning: code=%.4x not istitle, totitle is same, toupper=%.4x\n", i, mytoupper[i]);
+	}
+
+	/*
+	 * make sure isupper[c] is true if for some x toupper[x]  == c
+	 * ditto for islower and istitle
+	 */
+	for(i = 0; i < NRUNES; i++) {
+		if(mytoupper[i] != i)
+			myisupper[mytoupper[i]] = 1;
+		if(mytolower[i] != i)
+			myislower[mytolower[i]] = 1;
+		if(mytotitle[i] != i)
+			myistitle[mytotitle[i]] = 1;
+	}
+
+	if(docheck){
+		check();
+	}else{
+		mktables(argv[0], usepairs);
+	}
+	exit(0);
+}
+
+/*
+ * generate a properties array for ranges, clearing those cases covered.
+ * if force, generate one-entry ranges for singletons.
+ */
+static int
+mkisrange(const char* label, char* prop, int force)
+{
+	int start, stop, some;
+
+	/*
+	 * first, the ranges
+	 */
+	some = 0;
+	for(start = 0; start < NRUNES; ) {
+		if(!prop[start]){
+			start++;
+			continue;
+		}
+
+		for(stop = start + 1; stop < NRUNES; stop++){
+			if(!prop[stop]){
+				break;
+			}
+			prop[stop] = 0;
+		}
+		if(force || stop != start + 1){
+			if(!some){
+				printf("static Rune __is%sr[] = {\n", label);
+				some = 1;
+			}
+			prop[start] = 0;
+			printf("\t0x%.4x, 0x%.4x,\n", start, stop - 1);
+		}
+
+		start = stop;
+	}
+	if(some)
+		printf("};\n\n");
+	return some;
+}
+
+/*
+ * generate a mapping array for pairs with a skip between,
+ * clearing those entries covered.
+ */
+static int
+mkispair(const char *label, char *prop)
+{
+	int start, stop, some;
+
+	some = 0;
+	for(start = 0; start + 2 < NRUNES; ) {
+		if(!prop[start]){
+			start++;
+			continue;
+		}
+
+		for(stop = start + 2; stop < NRUNES; stop += 2){
+			if(!prop[stop]){
+				break;
+			}
+			prop[stop] = 0;
+		}
+		if(stop != start + 2){
+			if(!some){
+				printf("static Rune __is%sp[] = {\n", label);
+				some = 1;
+			}
+			prop[start] = 0;
+			printf("\t0x%.4x, 0x%.4x,\n", start, stop - 2);
+		}
+
+		start = stop;
+	}
+	if(some)
+		printf("};\n\n");
+	return some;
+}
+
+/*
+ * generate a properties array for singletons, clearing those cases covered.
+ */
+static int
+mkissingle(const char *label, char *prop)
+{
+	int start, some;
+
+	some = 0;
+	for(start = 0; start < NRUNES; start++) {
+		if(!prop[start]){
+			continue;
+		}
+
+		if(!some){
+			printf("static Rune __is%ss[] = {\n", label);
+			some = 1;
+		}
+		prop[start] = 0;
+		printf("\t0x%.4x,\n", start);
+	}
+	if(some)
+		printf("};\n\n");
+	return some;
+}
+
+/*
+ * generate tables and a function for is<label>rune
+ */
+static void
+mkis(const char* label, char* prop, int usepairs)
+{
+	int isr, isp, iss;
+
+	isr = mkisrange(label, prop, 0);
+	isp = 0;
+	if(usepairs)
+		isp = mkispair(label, prop);
+	iss = mkissingle(label, prop);
+
+	printf(
+		"int\n"
+		"is%srune(Rune c)\n"
+		"{\n"
+		"	Rune *p;\n"
+		"\n",
+		label);
+
+	if(isr)
+		printf(
+			"	p = rbsearch(c, __is%sr, nelem(__is%sr)/2, 2);\n"
+			"	if(p && c >= p[0] && c <= p[1])\n"
+			"		return 1;\n",
+			label, label);
+
+	if(isp)
+		printf(
+			"	p = rbsearch(c, __is%sp, nelem(__is%sp)/2, 2);\n"
+			"	if(p && c >= p[0] && c <= p[1] && !((c - p[0]) & 1))\n"
+			"		return 1;\n",
+			label, label);
+
+	if(iss)
+		printf(
+			"	p = rbsearch(c, __is%ss, nelem(__is%ss), 1);\n"
+			"	if(p && c == p[0])\n"
+			"		return 1;\n",
+			label, label);
+
+
+	printf(
+		"	return 0;\n"
+		"}\n"
+		"\n"
+	);
+}
+
+/*
+ * generate a mapping array for ranges, clearing those entries covered.
+ * if force, generate one-entry ranges for singletons.
+ */
+static int
+mktorange(const char* label, int* map, int force)
+{
+	int start, stop, delta, some;
+
+	some = 0;
+	for(start = 0; start < NRUNES; ) {
+		if(map[start] == start){
+			start++;
+			continue;
+		}
+
+		delta = TO_DELTA(map[start], start);
+		if(delta != (Rune)delta)
+			fatal("bad map delta %d", delta);
+		for(stop = start + 1; stop < NRUNES; stop++){
+			if(TO_DELTA(map[stop], stop) != delta){
+				break;
+			}
+			map[stop] = stop;
+		}
+		if(stop != start + 1){
+			if(!some){
+				printf("static Rune __to%sr[] = {\n", label);
+				some = 1;
+			}
+			map[start] = start;
+			printf("\t0x%.4x, 0x%.4x, %d,\n", start, stop - 1, delta);
+		}
+
+		start = stop;
+	}
+	if(some)
+		printf("};\n\n");
+	return some;
+}
+
+/*
+ * generate a mapping array for pairs with a skip between,
+ * clearing those entries covered.
+ */
+static int
+mktopair(const char* label, int* map)
+{
+	int start, stop, delta, some;
+
+	some = 0;
+	for(start = 0; start + 2 < NRUNES; ) {
+		if(map[start] == start){
+			start++;
+			continue;
+		}
+
+		delta = TO_DELTA(map[start], start);
+		if(delta != (Rune)delta)
+			fatal("bad map delta %d", delta);
+		for(stop = start + 2; stop < NRUNES; stop += 2){
+			if(TO_DELTA(map[stop], stop) != delta){
+				break;
+			}
+			map[stop] = stop;
+		}
+		if(stop != start + 2){
+			if(!some){
+				printf("static Rune __to%sp[] = {\n", label);
+				some = 1;
+			}
+			map[start] = start;
+			printf("\t0x%.4x, 0x%.4x, %d,\n", start, stop - 2, delta);
+		}
+
+		start = stop;
+	}
+	if(some)
+		printf("};\n\n");
+	return some;
+}
+
+/*
+ * generate a mapping array for singletons, clearing those entries covered.
+ */
+static int
+mktosingle(const char* label, int* map)
+{
+	int start, delta, some;
+
+	some = 0;
+	for(start = 0; start < NRUNES; start++) {
+		if(map[start] == start){
+			continue;
+		}
+
+		delta = TO_DELTA(map[start], start);
+		if(delta != (Rune)delta)
+			fatal("bad map delta %d", delta);
+		if(!some){
+			printf("static Rune __to%ss[] = {\n", label);
+			some = 1;
+		}
+		map[start] = start;
+		printf("\t0x%.4x, %d,\n", start, delta);
+	}
+	if(some)
+		printf("};\n\n");
+	return some;
+}
+
+/*
+ * generate tables and a function for to<label>rune
+ */
+static void
+mkto(const char* label, int* map, int usepairs)
+{
+	int tor, top, tos;
+
+	tor = mktorange(label, map, 0);
+	top = 0;
+	if(usepairs)
+		top = mktopair(label, map);
+	tos = mktosingle(label, map);
+
+	printf(
+		"Rune\n"
+		"to%srune(Rune c)\n"
+		"{\n"
+		"	Rune *p;\n"
+		"\n",
+		label);
+
+	if(tor)
+		printf(
+			"	p = rbsearch(c, __to%sr, nelem(__to%sr)/3, 3);\n"
+			"	if(p && c >= p[0] && c <= p[1])\n"
+			"		return c + p[2] - %d;\n",
+			label, label, TO_OFFSET);
+
+	if(top)
+		printf(
+			"	p = rbsearch(c, __to%sp, nelem(__to%sp)/3, 3);\n"
+			"	if(p && c >= p[0] && c <= p[1] && !((c - p[0]) & 1))\n"
+			"		return c + p[2] - %d;\n",
+			label, label, TO_OFFSET);
+
+	if(tos)
+		printf(
+			"	p = rbsearch(c, __to%ss, nelem(__to%ss)/2, 2);\n"
+			"	if(p && c == p[0])\n"
+			"		return c + p[1] - %d;\n",
+			label, label, TO_OFFSET);
+
+
+	printf(
+		"	return c;\n"
+		"}\n"
+		"\n"
+	);
+}
+
+// Make only range tables and a function for is<label>rune.
+static void
+mkisronly(const char* label, char* prop)
+{
+	mkisrange(label, prop, 1);
+	printf(
+		"int\n"
+		"is%srune(Rune c)\n"
+		"{\n"
+		"	Rune *p;\n"
+		"\n"
+		"	p = rbsearch(c, __is%sr, nelem(__is%sr)/2, 2);\n"
+		"	if(p && c >= p[0] && c <= p[1])\n"
+		"		return 1;\n"
+		"	return 0;\n"
+		"}\n"
+		"\n",
+	        label, label, label);
+}
+
+/*
+ * generate the body of runetype.
+ * assumes there is a function Rune* rbsearch(Rune c, Rune *t, int n, int ne);
+ */
+static void
+mktables(char *src, int usepairs)
+{
+	printf("/* generated automatically by mkrunetype.c from %s */\n\n", src);
+
+	/*
+	 * we special case the space and digit tables, since they are assumed
+	 * to be small with several ranges.
+	 */
+	mkisronly("space", myisspace);
+	mkisronly("digit", myisdigit);
+
+	mkis("alpha", myisalpha, 0);
+	mkis("upper", myisupper, usepairs);
+	mkis("lower", myislower, usepairs);
+	mkis("title", myistitle, usepairs);
+
+	mkto("upper", mytoupper, usepairs);
+	mkto("lower", mytolower, usepairs);
+	mkto("title", mytotitle, usepairs);
+}
+
+/*
+ * find differences between the newly generated tables and current runetypes.
+ */
+static void
+check(void)
+{
+	int i;
+
+	for(i = 0; i < NRUNES; i++){
+		if(isdigitrune(i) != myisdigit[i])
+			fprintf(stderr, "isdigit diff at %x: runetype=%x, unicode=%x\n",
+				i, isdigitrune(i), myisdigit[i]);
+
+		if(isspacerune(i) != myisspace[i])
+			fprintf(stderr, "isspace diff at %x: runetype=%x, unicode=%x\n",
+				i, isspacerune(i), myisspace[i]);
+
+		if(isupperrune(i) != myisupper[i])
+			fprintf(stderr, "isupper diff at %x: runetype=%x, unicode=%x\n",
+				i, isupperrune(i), myisupper[i]);
+
+		if(islowerrune(i) != myislower[i])
+			fprintf(stderr, "islower diff at %x: runetype=%x, unicode=%x\n",
+				i, islowerrune(i), myislower[i]);
+
+		if(isalpharune(i) != myisalpha[i])
+			fprintf(stderr, "isalpha diff at %x: runetype=%x, unicode=%x\n",
+				i, isalpharune(i), myisalpha[i]);
+
+		if(toupperrune(i) != mytoupper[i])
+			fprintf(stderr, "toupper diff at %x: runetype=%x, unicode=%x\n",
+				i, toupperrune(i), mytoupper[i]);
+
+		if(tolowerrune(i) != mytolower[i])
+			fprintf(stderr, "tolower diff at %x: runetype=%x, unicode=%x\n",
+				i, tolowerrune(i), mytolower[i]);
+
+		if(istitlerune(i) != myistitle[i])
+			fprintf(stderr, "istitle diff at %x: runetype=%x, unicode=%x\n",
+				i, istitlerune(i), myistitle[i]);
+
+		if(totitlerune(i) != mytotitle[i])
+			fprintf(stderr, "totitle diff at %x: runetype=%x, unicode=%x\n",
+				i, totitlerune(i), mytotitle[i]);
+
+
+	}
+}
+
+static int
+mygetfields(char **fields, int nfields, char *str, const char *delim)
+{
+	int nf;
+
+	fields[0] = str;
+	nf = 1;
+	if(nf >= nfields)
+		return nf;
+
+	for(; *str; str++){
+		if(strchr(delim, *str) != NULL){
+			*str = '\0';
+			fields[nf++] = str + 1;
+			if(nf >= nfields)
+				break;
+		}
+	}
+	return nf;
+}
+
+static int
+getunicodeline(FILE *in, char **fields, char *buf)
+{
+	char *p;
+
+	if(fgets(buf, MAX_LINE, in) == NULL)
+		return 0;
+
+	p = strchr(buf, '\n');
+	if (p == NULL)
+		fatal("line too long");
+	*p = '\0';
+
+	if (mygetfields(fields, NFIELDS + 1, buf, ";") != NFIELDS)
+		fatal("bad number of fields");
+
+	return 1;
+}
+
+static int
+getcode(char *s)
+{
+	int i, code;
+
+	code = 0;
+	i = 0;
+	/* Parse a hex number */
+	while(s[i]) {
+		code <<= 4;
+		if(s[i] >= '0' && s[i] <= '9')
+			code += s[i] - '0';
+		else if(s[i] >= 'A' && s[i] <= 'F')
+			code += s[i] - 'A' + 10;
+		else
+			fatal("bad code char '%c'", s[i]);
+		i++;
+	}
+	return code;
+}
+
+static void
+fatal(const char *fmt, ...)
+{
+	va_list arg;
+
+	fprintf(stderr, "%s: fatal error: ", argv0);
+	va_start(arg, fmt);
+	vfprintf(stderr, fmt, arg);
+	va_end(arg);
+	fprintf(stderr, "\n");
+
+	exit(1);
+}
diff --git a/src/lib9/utf/rune.c b/src/lib9/utf/rune.c
new file mode 100644
index 0000000..99f03ea
--- /dev/null
+++ b/src/lib9/utf/rune.c
@@ -0,0 +1,358 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ *              Portions Copyright (c) 2009 The Go Authors.  All rights reserved.
+ * 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 MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include "utf.h"
+#include "utfdef.h"
+
+enum
+{
+	Bit1	= 7,
+	Bitx	= 6,
+	Bit2	= 5,
+	Bit3	= 4,
+	Bit4	= 3,
+	Bit5	= 2,
+
+	T1	= ((1<<(Bit1+1))-1) ^ 0xFF,	/* 0000 0000 */
+	Tx	= ((1<<(Bitx+1))-1) ^ 0xFF,	/* 1000 0000 */
+	T2	= ((1<<(Bit2+1))-1) ^ 0xFF,	/* 1100 0000 */
+	T3	= ((1<<(Bit3+1))-1) ^ 0xFF,	/* 1110 0000 */
+	T4	= ((1<<(Bit4+1))-1) ^ 0xFF,	/* 1111 0000 */
+	T5	= ((1<<(Bit5+1))-1) ^ 0xFF,	/* 1111 1000 */
+
+	Rune1	= (1<<(Bit1+0*Bitx))-1,		/* 0000 0000 0111 1111 */
+	Rune2	= (1<<(Bit2+1*Bitx))-1,		/* 0000 0111 1111 1111 */
+	Rune3	= (1<<(Bit3+2*Bitx))-1,		/* 1111 1111 1111 1111 */
+	Rune4	= (1<<(Bit4+3*Bitx))-1,		/* 0001 1111 1111 1111 1111 1111 */
+
+	Maskx	= (1<<Bitx)-1,			/* 0011 1111 */
+	Testx	= Maskx ^ 0xFF,			/* 1100 0000 */
+
+	SurrogateMin	= 0xD800,
+	SurrogateMax	= 0xDFFF,
+
+	Bad	= Runeerror,
+};
+
+/*
+ * Modified by Wei-Hwa Huang, Google Inc., on 2004-09-24
+ * This is a slower but "safe" version of the old chartorune
+ * that works on strings that are not necessarily null-terminated.
+ *
+ * If you know for sure that your string is null-terminated,
+ * chartorune will be a bit faster.
+ *
+ * It is guaranteed not to attempt to access "length"
+ * past the incoming pointer.  This is to avoid
+ * possible access violations.  If the string appears to be
+ * well-formed but incomplete (i.e., to get the whole Rune
+ * we'd need to read past str+length) then we'll set the Rune
+ * to Bad and return 0.
+ *
+ * Note that if we have decoding problems for other
+ * reasons, we return 1 instead of 0.
+ */
+int
+charntorune(Rune *rune, const char *str, int length)
+{
+	int c, c1, c2, c3;
+	long l;
+
+	/* When we're not allowed to read anything */
+	if(length <= 0) {
+		goto badlen;
+	}
+
+	/*
+	 * one character sequence (7-bit value)
+	 *	00000-0007F => T1
+	 */
+	c = *(uchar*)str;
+	if(c < Tx) {
+		*rune = (Rune)c;
+		return 1;
+	}
+
+	// If we can't read more than one character we must stop
+	if(length <= 1) {
+		goto badlen;
+	}
+
+	/*
+	 * two character sequence (11-bit value)
+	 *	0080-07FF => T2 Tx
+	 */
+	c1 = *(uchar*)(str+1) ^ Tx;
+	if(c1 & Testx)
+		goto bad;
+	if(c < T3) {
+		if(c < T2)
+			goto bad;
+		l = ((c << Bitx) | c1) & Rune2;
+		if(l <= Rune1)
+			goto bad;
+		*rune = (Rune)l;
+		return 2;
+	}
+
+	// If we can't read more than two characters we must stop
+	if(length <= 2) {
+		goto badlen;
+	}
+
+	/*
+	 * three character sequence (16-bit value)
+	 *	0800-FFFF => T3 Tx Tx
+	 */
+	c2 = *(uchar*)(str+2) ^ Tx;
+	if(c2 & Testx)
+		goto bad;
+	if(c < T4) {
+		l = ((((c << Bitx) | c1) << Bitx) | c2) & Rune3;
+		if(l <= Rune2)
+			goto bad;
+		if (SurrogateMin <= l && l <= SurrogateMax)
+			goto bad;
+		*rune = (Rune)l;
+		return 3;
+	}
+
+	if (length <= 3)
+		goto badlen;
+
+	/*
+	 * four character sequence (21-bit value)
+	 *	10000-1FFFFF => T4 Tx Tx Tx
+	 */
+	c3 = *(uchar*)(str+3) ^ Tx;
+	if (c3 & Testx)
+		goto bad;
+	if (c < T5) {
+		l = ((((((c << Bitx) | c1) << Bitx) | c2) << Bitx) | c3) & Rune4;
+		if (l <= Rune3 || l > Runemax)
+			goto bad;
+		*rune = (Rune)l;
+		return 4;
+	}
+
+	// Support for 5-byte or longer UTF-8 would go here, but
+	// since we don't have that, we'll just fall through to bad.
+
+	/*
+	 * bad decoding
+	 */
+bad:
+	*rune = Bad;
+	return 1;
+badlen:
+	*rune = Bad;
+	return 0;
+
+}
+
+
+/*
+ * This is the older "unsafe" version, which works fine on
+ * null-terminated strings.
+ */
+int
+chartorune(Rune *rune, const char *str)
+{
+	int c, c1, c2, c3;
+	long l;
+
+	/*
+	 * one character sequence
+	 *	00000-0007F => T1
+	 */
+	c = *(uchar*)str;
+	if(c < Tx) {
+		*rune = (Rune)c;
+		return 1;
+	}
+
+	/*
+	 * two character sequence
+	 *	0080-07FF => T2 Tx
+	 */
+	c1 = *(uchar*)(str+1) ^ Tx;
+	if(c1 & Testx)
+		goto bad;
+	if(c < T3) {
+		if(c < T2)
+			goto bad;
+		l = ((c << Bitx) | c1) & Rune2;
+		if(l <= Rune1)
+			goto bad;
+		*rune = (Rune)l;
+		return 2;
+	}
+
+	/*
+	 * three character sequence
+	 *	0800-FFFF => T3 Tx Tx
+	 */
+	c2 = *(uchar*)(str+2) ^ Tx;
+	if(c2 & Testx)
+		goto bad;
+	if(c < T4) {
+		l = ((((c << Bitx) | c1) << Bitx) | c2) & Rune3;
+		if(l <= Rune2)
+			goto bad;
+		if (SurrogateMin <= l && l <= SurrogateMax)
+			goto bad;
+		*rune = (Rune)l;
+		return 3;
+	}
+
+	/*
+	 * four character sequence (21-bit value)
+	 *	10000-1FFFFF => T4 Tx Tx Tx
+	 */
+	c3 = *(uchar*)(str+3) ^ Tx;
+	if (c3 & Testx)
+		goto bad;
+	if (c < T5) {
+		l = ((((((c << Bitx) | c1) << Bitx) | c2) << Bitx) | c3) & Rune4;
+		if (l <= Rune3 || l > Runemax)
+			goto bad;
+		*rune = (Rune)l;
+		return 4;
+	}
+
+	/*
+	 * Support for 5-byte or longer UTF-8 would go here, but
+	 * since we don't have that, we'll just fall through to bad.
+	 */
+
+	/*
+	 * bad decoding
+	 */
+bad:
+	*rune = Bad;
+	return 1;
+}
+
+int
+isvalidcharntorune(const char* str, int length, Rune* rune, int* consumed)
+{
+	*consumed = charntorune(rune, str, length);
+	return *rune != Runeerror || *consumed == 3;
+}
+
+int
+runetochar(char *str, const Rune *rune)
+{
+	/* Runes are signed, so convert to unsigned for range check. */
+	unsigned long c;
+
+	/*
+	 * one character sequence
+	 *	00000-0007F => 00-7F
+	 */
+	c = *rune;
+	if(c <= Rune1) {
+		str[0] = (char)c;
+		return 1;
+	}
+
+	/*
+	 * two character sequence
+	 *	0080-07FF => T2 Tx
+	 */
+	if(c <= Rune2) {
+		str[0] = (char)(T2 | (c >> 1*Bitx));
+		str[1] = (char)(Tx | (c & Maskx));
+		return 2;
+	}
+
+	/*
+	 * If the Rune is out of range or a surrogate half, convert it to the error rune.
+	 * Do this test here because the error rune encodes to three bytes.
+	 * Doing it earlier would duplicate work, since an out of range
+	 * Rune wouldn't have fit in one or two bytes.
+	 */
+	if (c > Runemax)
+		c = Runeerror;
+	if (SurrogateMin <= c && c <= SurrogateMax)
+		c = Runeerror;
+
+	/*
+	 * three character sequence
+	 *	0800-FFFF => T3 Tx Tx
+	 */
+	if (c <= Rune3) {
+		str[0] = (char)(T3 |  (c >> 2*Bitx));
+		str[1] = (char)(Tx | ((c >> 1*Bitx) & Maskx));
+		str[2] = (char)(Tx |  (c & Maskx));
+		return 3;
+	}
+
+	/*
+	 * four character sequence (21-bit value)
+	 *     10000-1FFFFF => T4 Tx Tx Tx
+	 */
+	str[0] = (char)(T4 | (c >> 3*Bitx));
+	str[1] = (char)(Tx | ((c >> 2*Bitx) & Maskx));
+	str[2] = (char)(Tx | ((c >> 1*Bitx) & Maskx));
+	str[3] = (char)(Tx | (c & Maskx));
+	return 4;
+}
+
+int
+runelen(Rune rune)
+{
+	char str[10];
+
+	return runetochar(str, &rune);
+}
+
+int
+runenlen(const Rune *r, int nrune)
+{
+	int nb, c;
+
+	nb = 0;
+	while(nrune--) {
+		c = (int)*r++;
+		if (c <= Rune1)
+			nb++;
+		else if (c <= Rune2)
+			nb += 2;
+		else if (c <= Rune3)
+			nb += 3;
+		else /* assert(c <= Rune4) */
+			nb += 4;
+	}
+	return nb;
+}
+
+int
+fullrune(const char *str, int n)
+{
+	if (n > 0) {
+		int c = *(uchar*)str;
+		if (c < Tx)
+			return 1;
+		if (n > 1) {
+			if (c < T3)
+				return 1;
+			if (n > 2) {
+				if (c < T4 || n > 3)
+					return 1;
+			}
+		}
+	}
+	return 0;
+}
diff --git a/src/lib9/utf/runetype.c b/src/lib9/utf/runetype.c
new file mode 100644
index 0000000..ed775af
--- /dev/null
+++ b/src/lib9/utf/runetype.c
@@ -0,0 +1,38 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * 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 MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include "utf.h"
+#include "utfdef.h"
+
+static
+Rune*
+rbsearch(Rune c, Rune *t, int n, int ne)
+{
+	Rune *p;
+	int m;
+
+	while(n > 1) {
+		m = n >> 1;
+		p = t + m*ne;
+		if(c >= p[0]) {
+			t = p;
+			n = n-m;
+		} else
+			n = m;
+	}
+	if(n && c >= t[0])
+		return t;
+	return 0;
+}
+
+#include "runetypebody-6.3.0.h"
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/utf.h b/src/lib9/utf/utf.h
new file mode 100644
index 0000000..72d01ed
--- /dev/null
+++ b/src/lib9/utf/utf.h
@@ -0,0 +1,240 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 1998-2002 by Lucent Technologies.
+ *              Portions Copyright (c) 2009 The Go Authors.  All rights reserved.
+ * 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 MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+#ifndef _UTFH_
+#define _UTFH_ 1
+
+typedef unsigned int Rune;	/* Code-point values in Unicode 4.0 are 21 bits wide.*/
+
+enum
+{
+  UTFmax	= 4,		/* maximum bytes per rune */
+  Runesync	= 0x80,		/* cannot represent part of a UTF sequence (<) */
+  Runeself	= 0x80,		/* rune and UTF sequences are the same (<) */
+  Runeerror	= 0xFFFD,	/* decoding error in UTF */
+  Runemax	= 0x10FFFF,	/* maximum rune value */
+};
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+/*
+ * rune routines
+ */
+
+/*
+ * These routines were written by Rob Pike and Ken Thompson
+ * and first appeared in Plan 9.
+ * SEE ALSO
+ * utf (7)
+ * tcs (1)
+*/
+
+// runetochar copies (encodes) one rune, pointed to by r, to at most
+// UTFmax bytes starting at s and returns the number of bytes generated.
+
+int runetochar(char* s, const Rune* r);
+
+
+// chartorune copies (decodes) at most UTFmax bytes starting at s to
+// one rune, pointed to by r, and returns the number of bytes consumed.
+// If the input is not exactly in UTF format, chartorune will set *r
+// to Runeerror and return 1.
+//
+// Note: There is no special case for a "null-terminated" string. A
+// string whose first byte has the value 0 is the UTF8 encoding of the
+// Unicode value 0 (i.e., ASCII NULL). A byte value of 0 is illegal
+// anywhere else in a UTF sequence.
+
+int chartorune(Rune* r, const char* s);
+
+
+// charntorune is like chartorune, except that it will access at most
+// n bytes of s.  If the UTF sequence is incomplete within n bytes,
+// charntorune will set *r to Runeerror and return 0. If it is complete
+// but not in UTF format, it will set *r to Runeerror and return 1.
+//
+// Added 2004-09-24 by Wei-Hwa Huang
+
+int charntorune(Rune* r, const char* s, int n);
+
+// isvalidcharntorune(str, n, r, consumed)
+// is a convenience function that calls "*consumed = charntorune(r, str, n)"
+// and returns an int (logically boolean) indicating whether the first
+// n bytes of str was a valid and complete UTF sequence.
+
+int isvalidcharntorune(const char* str, int n, Rune* r, int* consumed);
+
+// runelen returns the number of bytes required to convert r into UTF.
+
+int runelen(Rune r);
+
+
+// runenlen returns the number of bytes required to convert the n
+// runes pointed to by r into UTF.
+
+int runenlen(const Rune* r, int n);
+
+
+// fullrune returns 1 if the string s of length n is long enough to be
+// decoded by chartorune, and 0 otherwise. This does not guarantee
+// that the string contains a legal UTF encoding. This routine is used
+// by programs that obtain input one byte at a time and need to know
+// when a full rune has arrived.
+
+int fullrune(const char* s, int n);
+
+// The following routines are analogous to the corresponding string
+// routines with "utf" substituted for "str", and "rune" substituted
+// for "chr".
+
+// utflen returns the number of runes that are represented by the UTF
+// string s. (cf. strlen)
+
+int utflen(const char* s);
+
+
+// utfnlen returns the number of complete runes that are represented
+// by the first n bytes of the UTF string s. If the last few bytes of
+// the string contain an incompletely coded rune, utfnlen will not
+// count them; in this way, it differs from utflen, which includes
+// every byte of the string. (cf. strnlen)
+
+int utfnlen(const char* s, long n);
+
+
+// utfrune returns a pointer to the first occurrence of rune r in the
+// UTF string s, or 0 if r does not occur in the string.  The NULL
+// byte terminating a string is considered to be part of the string s.
+// (cf. strchr)
+
+/*const*/ char* utfrune(const char* s, Rune r);
+
+
+// utfrrune returns a pointer to the last occurrence of rune r in the
+// UTF string s, or 0 if r does not occur in the string.  The NULL
+// byte terminating a string is considered to be part of the string s.
+// (cf. strrchr)
+
+/*const*/ char* utfrrune(const char* s, Rune r);
+
+
+// utfutf returns a pointer to the first occurrence of the UTF string
+// s2 as a UTF substring of s1, or 0 if there is none. If s2 is the
+// null string, utfutf returns s1. (cf. strstr)
+
+const char* utfutf(const char* s1, const char* s2);
+
+
+// utfecpy copies UTF sequences until a null sequence has been copied,
+// but writes no sequences beyond es1.  If any sequences are copied,
+// s1 is terminated by a null sequence, and a pointer to that sequence
+// is returned.  Otherwise, the original s1 is returned. (cf. strecpy)
+
+char* utfecpy(char *s1, char *es1, const char *s2);
+
+
+
+// These functions are rune-string analogues of the corresponding
+// functions in strcat (3).
+//
+// These routines first appeared in Plan 9.
+// SEE ALSO
+// memmove (3)
+// rune (3)
+// strcat (2)
+//
+// BUGS: The outcome of overlapping moves varies among implementations.
+
+Rune* runestrcat(Rune* s1, const Rune* s2);
+Rune* runestrncat(Rune* s1, const Rune* s2, long n);
+
+const Rune* runestrchr(const Rune* s, Rune c);
+
+int runestrcmp(const Rune* s1, const Rune* s2);
+int runestrncmp(const Rune* s1, const Rune* s2, long n);
+
+Rune* runestrcpy(Rune* s1, const Rune* s2);
+Rune* runestrncpy(Rune* s1, const Rune* s2, long n);
+Rune* runestrecpy(Rune* s1, Rune* es1, const Rune* s2);
+
+Rune* runestrdup(const Rune* s);
+
+const Rune* runestrrchr(const Rune* s, Rune c);
+long runestrlen(const Rune* s);
+const Rune* runestrstr(const Rune* s1, const Rune* s2);
+
+
+
+// The following routines test types and modify cases for Unicode
+// characters.  Unicode defines some characters as letters and
+// specifies three cases: upper, lower, and title.  Mappings among the
+// cases are also defined, although they are not exhaustive: some
+// upper case letters have no lower case mapping, and so on.  Unicode
+// also defines several character properties, a subset of which are
+// checked by these routines.  These routines are based on Unicode
+// version 3.0.0.
+//
+// NOTE: The routines are implemented in C, so the boolean functions
+// (e.g., isupperrune) return 0 for false and 1 for true.
+//
+//
+// toupperrune, tolowerrune, and totitlerune are the Unicode case
+// mappings. These routines return the character unchanged if it has
+// no defined mapping.
+
+Rune toupperrune(Rune r);
+Rune tolowerrune(Rune r);
+Rune totitlerune(Rune r);
+
+
+// isupperrune tests for upper case characters, including Unicode
+// upper case letters and targets of the toupper mapping. islowerrune
+// and istitlerune are defined analogously.
+
+int isupperrune(Rune r);
+int islowerrune(Rune r);
+int istitlerune(Rune r);
+
+
+// isalpharune tests for Unicode letters; this includes ideographs in
+// addition to alphabetic characters.
+
+int isalpharune(Rune r);
+
+
+// isdigitrune tests for digits. Non-digit numbers, such as Roman
+// numerals, are not included.
+
+int isdigitrune(Rune r);
+
+
+// isspacerune tests for whitespace characters, including "C" locale
+// whitespace, Unicode defined whitespace, and the "zero-width
+// non-break space" character.
+
+int isspacerune(Rune r);
+
+
+// (The comments in this file were copied from the manpage files rune.3,
+// isalpharune.3, and runestrcat.3. Some formatting changes were also made
+// to conform to Google style. /JRM 11/11/05)
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif
diff --git a/src/lib9/utf/utfdef.h b/src/lib9/utf/utfdef.h
new file mode 100644
index 0000000..4bbdfc6
--- /dev/null
+++ b/src/lib9/utf/utfdef.h
@@ -0,0 +1,27 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 1998-2002 by Lucent Technologies.
+ * 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 MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+#define uchar _utfuchar
+#define ushort _utfushort
+#define uint _utfuint
+#define ulong _utfulong
+#define vlong _utfvlong
+#define uvlong _utfuvlong
+
+typedef unsigned char		uchar;
+typedef unsigned short		ushort;
+typedef unsigned int		uint;
+typedef unsigned long		ulong;
+
+#define nelem(x) (sizeof(x)/sizeof((x)[0]))
diff --git a/src/lib9/utf/utfecpy.c b/src/lib9/utf/utfecpy.c
new file mode 100644
index 0000000..8540664
--- /dev/null
+++ b/src/lib9/utf/utfecpy.c
@@ -0,0 +1,36 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * 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 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 "utf.h"
+#include "utfdef.h"
+
+char*
+utfecpy(char *to, char *e, const char *from)
+{
+	char *end;
+
+	if(to >= e)
+		return to;
+	end = memccpy(to, from, '\0', (size_t)(e - to));
+	if(end == nil){
+		end = e-1;
+		while(end>to && (*--end&0xC0)==0x80)
+			;
+		*end = '\0';
+	}else{
+		end--;
+	}
+	return end;
+}
diff --git a/src/lib9/utf/utflen.c b/src/lib9/utf/utflen.c
new file mode 100644
index 0000000..9b96185
--- /dev/null
+++ b/src/lib9/utf/utflen.c
@@ -0,0 +1,35 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * 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 MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include "utf.h"
+#include "utfdef.h"
+
+int
+utflen(const char *s)
+{
+	int c;
+	int n;
+	Rune rune;
+
+	n = 0;
+	for(;;) {
+		c = *(uchar*)s;
+		if(c < Runeself) {
+			if(c == 0)
+				return n;
+			s++;
+		} else
+			s += chartorune(&rune, s);
+		n++;
+	}
+}
diff --git a/src/lib9/utf/utfnlen.c b/src/lib9/utf/utfnlen.c
new file mode 100644
index 0000000..d6ef5fa
--- /dev/null
+++ b/src/lib9/utf/utfnlen.c
@@ -0,0 +1,39 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * 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 MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+#include "utf.h"
+#include "utfdef.h"
+
+int
+utfnlen(const char *s, long m)
+{
+	int c;
+	int n;
+	Rune rune;
+	const char *es;
+
+	es = s + m;
+	for(n = 0; s < es; n++) {
+		c = *(uchar*)s;
+		if(c < Runeself){
+			if(c == '\0')
+				break;
+			s++;
+			continue;
+		}
+		if(!fullrune(s, (int)(es-s)))
+			break;
+		s += chartorune(&rune, s);
+	}
+	return n;
+}
diff --git a/src/lib9/utf/utfrrune.c b/src/lib9/utf/utfrrune.c
new file mode 100644
index 0000000..b1ea93b
--- /dev/null
+++ b/src/lib9/utf/utfrrune.c
@@ -0,0 +1,46 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * 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 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 "utf.h"
+#include "utfdef.h"
+
+/* const - removed for go code */
+char*
+utfrrune(const char *s, Rune c)
+{
+	long c1;
+	Rune r;
+	const char *s1;
+
+	if(c < Runesync)		/* not part of utf sequence */
+		return strrchr(s, (char)c);
+
+	s1 = 0;
+	for(;;) {
+		c1 = *(uchar*)s;
+		if(c1 < Runeself) {	/* one byte rune */
+			if(c1 == 0)
+				return (char*)s1;
+			if(c1 == c)
+				s1 = s;
+			s++;
+			continue;
+		}
+		c1 = chartorune(&r, s);
+		if(r == c)
+			s1 = s;
+		s += c1;
+	}
+}
diff --git a/src/lib9/utf/utfrune.c b/src/lib9/utf/utfrune.c
new file mode 100644
index 0000000..44675c9
--- /dev/null
+++ b/src/lib9/utf/utfrune.c
@@ -0,0 +1,45 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * 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 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 "utf.h"
+#include "utfdef.h"
+
+/* const - removed for go code */
+char*
+utfrune(const char *s, Rune c)
+{
+	long c1;
+	Rune r;
+	int n;
+
+	if(c < Runesync)		/* not part of utf sequence */
+		return strchr(s, (char)c);
+
+	for(;;) {
+		c1 = *(uchar*)s;
+		if(c1 < Runeself) {	/* one byte rune */
+			if(c1 == 0)
+				return 0;
+			if(c1 == c)
+				return (char*)s;
+			s++;
+			continue;
+		}
+		n = chartorune(&r, s);
+		if(r == c)
+			return (char*)s;
+		s += n;
+	}
+}
diff --git a/src/lib9/utf/utfutf.c b/src/lib9/utf/utfutf.c
new file mode 100644
index 0000000..05335b2
--- /dev/null
+++ b/src/lib9/utf/utfutf.c
@@ -0,0 +1,43 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ *              Copyright (c) 2002 by Lucent Technologies.
+ * 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 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 "utf.h"
+#include "utfdef.h"
+
+
+/*
+ * Return pointer to first occurrence of s2 in s1,
+ * 0 if none
+ */
+const
+char*
+utfutf(const char *s1, const char *s2)
+{
+	const char *p;
+	long f, n1;
+	size_t n2;
+	Rune r;
+
+	n1 = chartorune(&r, s2);
+	f = r;
+	if(f <= Runesync)		/* represents self */
+		return strstr(s1, s2);
+
+	n2 = strlen(s2);
+	for(p=s1; (p=utfrune(p, r)) != 0; p+=n1)
+		if(strncmp(p, s2, n2) == 0)
+			return p;
+	return 0;
+}
diff --git a/src/lib9/win.h b/src/lib9/win.h
new file mode 100644
index 0000000..d9df319
--- /dev/null
+++ b/src/lib9/win.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.
+
+typedef unsigned short WinRune;
+
+WinRune* torune(char*);
+char *toutf(WinRune*);
diff --git a/src/lib9/windows.c b/src/lib9/windows.c
new file mode 100644
index 0000000..082f339
--- /dev/null
+++ b/src/lib9/windows.c
@@ -0,0 +1,31 @@
+// 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>
+
+int
+fork(void)
+{
+	return -1;
+}
+
+int
+p9rfork(int flags)
+{
+	USED(flags);
+	return -1;
+}
+
+Waitmsg*
+p9wait(void)
+{
+	return 0;
+}
+
+int
+p9waitpid(void)
+{
+	return -1;
+}
diff --git a/src/libbio/Makefile b/src/libbio/Makefile
new file mode 100644
index 0000000..62aba5d
--- /dev/null
+++ b/src/libbio/Makefile
@@ -0,0 +1,5 @@
+# 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/libbio/bbuffered.c b/src/libbio/bbuffered.c
new file mode 100644
index 0000000..2ddb29b
--- /dev/null
+++ b/src/libbio/bbuffered.c
@@ -0,0 +1,46 @@
+/*
+http://code.google.com/p/inferno-os/source/browse/libbio/bbuffered.c
+
+	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+	Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).  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>
+
+int
+Bbuffered(Biobuf *bp)
+{
+	switch(bp->state) {
+	case Bracteof:
+	case Bractive:
+		return -bp->icount;
+
+	case Bwactive:
+		return bp->bsize + bp->ocount;
+
+	case Binactive:
+		return 0;
+	}
+	fprint(2, "Bbuffered: unknown state %d\n", bp->state);
+	return 0;
+}
diff --git a/src/libbio/bfildes.c b/src/libbio/bfildes.c
new file mode 100644
index 0000000..aef1f70
--- /dev/null
+++ b/src/libbio/bfildes.c
@@ -0,0 +1,35 @@
+/*
+http://code.google.com/p/inferno-os/source/browse/libbio/bfildes.c
+
+	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+	Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).  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>
+
+int
+Bfildes(Biobuf *bp)
+{
+
+	return bp->fid;
+}
diff --git a/src/libbio/bflush.c b/src/libbio/bflush.c
new file mode 100644
index 0000000..ea7ae2c
--- /dev/null
+++ b/src/libbio/bflush.c
@@ -0,0 +1,59 @@
+/*
+http://code.google.com/p/inferno-os/source/browse/libbio/bflush.c
+
+	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+	Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).  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>
+
+int
+Bflush(Biobuf *bp)
+{
+	int n, c;
+
+	switch(bp->state) {
+	case Bwactive:
+		n = bp->bsize+bp->ocount;
+		if(n == 0)
+			return 0;
+		c = (int)write(bp->fid, bp->bbuf, (size_t)n);
+		if(n == c) {
+			bp->offset += n;
+			bp->ocount = -bp->bsize;
+			return 0;
+		}
+		bp->state = Binactive;
+		bp->ocount = 0;
+		break;
+
+	case Bracteof:
+		bp->state = Bractive;
+
+	case Bractive:
+		bp->icount = 0;
+		bp->gbuf = bp->ebuf;
+		return 0;
+	}
+	return Beof;
+}
diff --git a/src/libbio/bgetc.c b/src/libbio/bgetc.c
new file mode 100644
index 0000000..ceb5cb1
--- /dev/null
+++ b/src/libbio/bgetc.c
@@ -0,0 +1,99 @@
+/*
+http://code.google.com/p/inferno-os/source/browse/libbio/bgetc.c
+
+	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+	Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).  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>
+
+int
+Bgetc(Biobuf *bp)
+{
+	int i;
+
+loop:
+	i = bp->icount;
+	if(i != 0) {
+		bp->icount = i+1;
+		return bp->ebuf[i];
+	}
+	if(bp->state != Bractive) {
+		if(bp->state == Bracteof)
+			bp->state = Bractive;
+		return Beof;
+	}
+	/*
+	 * get next buffer, try to keep Bungetsize
+	 * characters pre-catenated from the previous
+	 * buffer to allow that many ungets.
+	 */
+	memmove(bp->bbuf-Bungetsize, bp->ebuf-Bungetsize, Bungetsize);
+	i = (int)read(bp->fid, bp->bbuf, (size_t)bp->bsize);
+	bp->gbuf = bp->bbuf;
+	if(i <= 0) {
+		bp->state = Bracteof;
+		if(i < 0)
+			bp->state = Binactive;
+		return Beof;
+	}
+	if(i < bp->bsize) {
+		memmove(bp->ebuf-i-Bungetsize, bp->bbuf-Bungetsize, (size_t)(i+Bungetsize));
+		bp->gbuf = bp->ebuf-i;
+	}
+	bp->icount = -i;
+	bp->offset += i;
+	goto loop;
+}
+
+int
+Bgetle2(Biobuf *bp)
+{
+	int l, h;
+
+	l = Bgetc(bp);
+	h = Bgetc(bp);
+	return l|(h<<8);
+}
+
+int
+Bgetle4(Biobuf *bp)
+{
+	int l, h;
+
+	l = Bgetle2(bp);
+	h = Bgetle2(bp);
+	return (int)((uint32)l|((uint32)h<<16));
+}
+
+int
+Bungetc(Biobuf *bp)
+{
+
+	if(bp->state == Bracteof)
+		bp->state = Bractive;
+	if(bp->state != Bractive)
+		return Beof;
+	bp->icount--;
+	return 1;
+}
diff --git a/src/libbio/bgetd.c b/src/libbio/bgetd.c
new file mode 100644
index 0000000..12d2c5b
--- /dev/null
+++ b/src/libbio/bgetd.c
@@ -0,0 +1,62 @@
+/*
+http://code.google.com/p/inferno-os/source/browse/libbio/bgetd.c
+
+	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+	Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).  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>
+
+struct	bgetd
+{
+	Biobuf*	b;
+	int		eof;
+};
+
+static int
+Bgetdf(void *vp)
+{
+	int c;
+	struct bgetd *bg = vp;
+
+	c = BGETC(bg->b);
+	if(c == Beof)
+		bg->eof = 1;
+	return c;
+}
+
+int
+Bgetd(Biobuf *bp, double *dp)
+{
+	double d;
+	struct bgetd b;
+
+	b.b = bp;
+	b.eof = 0;
+	d = fmtcharstod(Bgetdf, &b);
+	if(b.eof)
+		return -1;
+	Bungetc(bp);
+	*dp = d;
+	return 1;
+}
diff --git a/src/libbio/bgetrune.c b/src/libbio/bgetrune.c
new file mode 100644
index 0000000..b5db391
--- /dev/null
+++ b/src/libbio/bgetrune.c
@@ -0,0 +1,72 @@
+/*
+http://code.google.com/p/inferno-os/source/browse/libbio/bgetrune.c
+
+	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+	Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).  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>
+
+long
+Bgetrune(Biobuf *bp)
+{
+	int c, i;
+	Rune rune;
+	char str[UTFmax];
+
+	c = BGETC(bp);
+	if(c < Runeself) {		/* one char */
+		bp->runesize = 1;
+		return c;
+	}
+	str[0] = (char)c;
+
+	for(i=1;;) {
+		c = BGETC(bp);
+		if(c < 0)
+			return c;
+		str[i++] = (char)c;
+
+		if(fullrune(str, i)) {
+			bp->runesize = chartorune(&rune, str);
+			while(i > bp->runesize) {
+				Bungetc(bp);
+				i--;
+			}
+			return rune;
+		}
+	}
+}
+
+int
+Bungetrune(Biobuf *bp)
+{
+
+	if(bp->state == Bracteof)
+		bp->state = Bractive;
+	if(bp->state != Bractive)
+		return Beof;
+	bp->icount -= bp->runesize;
+	bp->runesize = 0;
+	return 1;
+}
diff --git a/src/libbio/binit.c b/src/libbio/binit.c
new file mode 100644
index 0000000..a7ade50
--- /dev/null
+++ b/src/libbio/binit.c
@@ -0,0 +1,179 @@
+/*
+http://code.google.com/p/inferno-os/source/browse/libbio/binit.c
+
+	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+	Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).  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>
+
+enum
+{
+	MAXBUFS	= 20
+};
+
+static	Biobuf*	wbufs[MAXBUFS];
+static	int		atexitflag;
+
+static
+void
+batexit(void)
+{
+	Biobuf *bp;
+	int i;
+
+	for(i=0; i<MAXBUFS; i++) {
+		bp = wbufs[i];
+		if(bp != 0) {
+			wbufs[i] = 0;
+			Bflush(bp);
+		}
+	}
+}
+
+static
+void
+deinstall(Biobuf *bp)
+{
+	int i;
+
+	for(i=0; i<MAXBUFS; i++)
+		if(wbufs[i] == bp)
+			wbufs[i] = 0;
+}
+
+static
+void
+install(Biobuf *bp)
+{
+	int i;
+
+	deinstall(bp);
+	for(i=0; i<MAXBUFS; i++)
+		if(wbufs[i] == 0) {
+			wbufs[i] = bp;
+			break;
+		}
+	if(atexitflag == 0) {
+		atexitflag = 1;
+		atexit(batexit);
+	}
+}
+
+int
+Binits(Biobuf *bp, int f, int mode, unsigned char *p, int size)
+{
+
+	p += Bungetsize;	/* make room for Bungets */
+	size -= Bungetsize;
+
+	switch(mode&~(ORCLOSE|OTRUNC)) {
+	default:
+		fprint(2, "Bopen: unknown mode %d\n", mode);
+		return Beof;
+
+	case OREAD:
+		bp->state = Bractive;
+		bp->ocount = 0;
+		break;
+
+	case OWRITE:
+		install(bp);
+		bp->state = Bwactive;
+		bp->ocount = -size;
+		break;
+	}
+	bp->bbuf = p;
+	bp->ebuf = p+size;
+	bp->bsize = size;
+	bp->icount = 0;
+	bp->gbuf = bp->ebuf;
+	bp->fid = f;
+	bp->flag = 0;
+	bp->rdline = 0;
+	bp->offset = 0;
+	bp->runesize = 0;
+	return 0;
+}
+
+
+int
+Binit(Biobuf *bp, int f, int mode)
+{
+	return Binits(bp, f, mode, bp->b, sizeof(bp->b));
+}
+
+Biobuf*
+Bfdopen(int f, int mode)
+{
+	Biobuf *bp;
+
+	bp = malloc(sizeof(Biobuf));
+	if(bp == 0)
+		return 0;
+	Binits(bp, f, mode, bp->b, sizeof(bp->b));
+	bp->flag = Bmagic;
+	return bp;
+}
+
+Biobuf*
+Bopen(char *name, int mode)
+{
+	Biobuf *bp;
+	int f;
+
+	switch(mode&~(ORCLOSE|OTRUNC)) {
+	default:
+		fprint(2, "Bopen: unknown mode %d\n", mode);
+		return 0;
+
+	case OREAD:
+		f = open(name, OREAD);
+		if(f < 0)
+			return 0;
+		break;
+
+	case OWRITE:
+		f = create(name, OWRITE|OTRUNC, 0666);
+		if(f < 0)
+			return 0;
+	}
+	bp = Bfdopen(f, mode);
+	if(bp == 0)
+		close(f);
+	return bp;
+}
+
+int
+Bterm(Biobuf *bp)
+{
+
+	deinstall(bp);
+	Bflush(bp);
+	if(bp->flag == Bmagic) {
+		bp->flag = 0;
+		close(bp->fid);
+		free(bp);
+	}
+	return 0;
+}
diff --git a/src/libbio/boffset.c b/src/libbio/boffset.c
new file mode 100644
index 0000000..15dd609
--- /dev/null
+++ b/src/libbio/boffset.c
@@ -0,0 +1,51 @@
+/*
+http://code.google.com/p/inferno-os/source/browse/libbio/boffset.c
+
+	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+	Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).  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>
+
+vlong
+Boffset(Biobuf *bp)
+{
+	vlong n;
+
+	switch(bp->state) {
+	default:
+		fprint(2, "Boffset: unknown state %d\n", bp->state);
+		n = Beof;
+		break;
+
+	case Bracteof:
+	case Bractive:
+		n = bp->offset + bp->icount;
+		break;
+
+	case Bwactive:
+		n = bp->offset + (bp->bsize + bp->ocount);
+		break;
+	}
+	return n;
+}
diff --git a/src/libbio/bprint.c b/src/libbio/bprint.c
new file mode 100644
index 0000000..301dc0c
--- /dev/null
+++ b/src/libbio/bprint.c
@@ -0,0 +1,82 @@
+/*
+http://code.google.com/p/inferno-os/source/browse/libbio/bprint.c
+
+	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+	Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).  All rights reserved.
+	Revisions Copyright © 2010 Google Inc.  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>
+
+int
+Bprint(Biobuf *bp, char *fmt, ...)
+{
+	int n;
+	va_list arg;
+
+	va_start(arg, fmt);
+	n = Bvprint(bp, fmt, arg);
+	va_end(arg);
+	return n;
+}
+
+static int
+bflush(Fmt *f)
+{
+	Biobuf *bp;
+	
+	if(f->stop == nil)
+		return 0;
+
+	bp = f->farg;
+	bp->ocount = (int)((char*)f->to - (char*)f->stop);
+	if(Bflush(bp) < 0) {
+		f->stop = nil;
+		f->to = nil;
+		return 0;
+	}
+	f->to = (char*)f->stop + bp->ocount;
+	
+	return 1;
+}
+
+int
+Bvprint(Biobuf *bp, char *fmt, va_list arg)
+{
+	int n;
+	Fmt f;
+	
+	memset(&f, 0, sizeof f);
+	fmtlocaleinit(&f, nil, nil, nil);
+	f.stop = bp->ebuf;
+	f.to = (char*)f.stop + bp->ocount;
+	f.flush = bflush;
+	f.farg = bp;
+
+	n = fmtvprint(&f, fmt, arg);
+
+	if(f.stop != nil)
+		bp->ocount = (int)((char*)f.to - (char*)f.stop);
+
+	return n;
+}
diff --git a/src/libbio/bputc.c b/src/libbio/bputc.c
new file mode 100644
index 0000000..07b4789
--- /dev/null
+++ b/src/libbio/bputc.c
@@ -0,0 +1,60 @@
+/*
+http://code.google.com/p/inferno-os/source/browse/libbio/bputc.c
+
+	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+	Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).  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>
+
+int
+Bputc(Biobuf *bp, int c)
+{
+	int i;
+
+	for(;;) {
+		i = bp->ocount;
+		if(i) {
+			bp->ebuf[i++] = (unsigned char)c;
+			bp->ocount = i;
+			return 0;
+		}
+		if(Bflush(bp) == Beof)
+			break;
+	}
+	return Beof;
+}
+
+int
+Bputle2(Biobuf *bp, int c)
+{
+	Bputc(bp, c);
+	return Bputc(bp, c>>8);
+}
+
+int
+Bputle4(Biobuf *bp, int c)
+{
+	Bputle2(bp, c);
+	return Bputle2(bp, c>>16);
+}
diff --git a/src/libbio/bputrune.c b/src/libbio/bputrune.c
new file mode 100644
index 0000000..f207795
--- /dev/null
+++ b/src/libbio/bputrune.c
@@ -0,0 +1,49 @@
+/*
+http://code.google.com/p/inferno-os/source/browse/libbio/bputrune.c
+
+	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+	Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).  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>
+
+int
+Bputrune(Biobuf *bp, long c)
+{
+	Rune rune;
+	char str[UTFmax];
+	int n;
+
+	rune = (Rune)c;
+	if(rune < Runeself) {
+		n = BPUTC(bp, (int)rune);
+		USED(n);
+		return 1;
+	}
+	n = runetochar(str, &rune);
+	if(n == 0)
+		return Bbad;
+	if(Bwrite(bp, str, n) != n)
+		return Beof;
+	return n;
+}
diff --git a/src/libbio/brdline.c b/src/libbio/brdline.c
new file mode 100644
index 0000000..1c3093e
--- /dev/null
+++ b/src/libbio/brdline.c
@@ -0,0 +1,120 @@
+/*
+http://code.google.com/p/inferno-os/source/browse/libbio/brdline.c
+
+	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+	Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).  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>
+
+void*
+Brdline(Biobuf *bp, int delim)
+{
+	char *ip, *ep;
+	int i, j;
+
+	i = -bp->icount;
+	if(i == 0) {
+		/*
+		 * eof or other error
+		 */
+		if(bp->state != Bractive) {
+			if(bp->state == Bracteof)
+				bp->state = Bractive;
+			bp->rdline = 0;
+			bp->gbuf = bp->ebuf;
+			return 0;
+		}
+	}
+
+	/*
+	 * first try in remainder of buffer (gbuf doesn't change)
+	 */
+	ip = (char*)bp->ebuf - i;
+	ep = memchr(ip, delim, (size_t)i);
+	if(ep) {
+		j = (int)((ep - ip) + 1);
+		bp->rdline = j;
+		bp->icount += j;
+		return ip;
+	}
+
+	/*
+	 * copy data to beginning of buffer
+	 */
+	if(i < bp->bsize)
+		memmove(bp->bbuf, ip, (size_t)i);
+	bp->gbuf = bp->bbuf;
+
+	/*
+	 * append to buffer looking for the delim
+	 */
+	ip = (char*)bp->bbuf + i;
+	while(i < bp->bsize) {
+		j = (int)read(bp->fid, ip, (size_t)(bp->bsize-i));
+		if(j <= 0) {
+			/*
+			 * end of file with no delim
+			 */
+			memmove(bp->ebuf-i, bp->bbuf, (size_t)i);
+			bp->rdline = i;
+			bp->icount = -i;
+			bp->gbuf = bp->ebuf-i;
+			return 0;
+		}
+		bp->offset += j;
+		i += j;
+		ep = memchr(ip, delim, (size_t)j);
+		if(ep) {
+			/*
+			 * found in new piece
+			 * copy back up and reset everything
+			 */
+			ip = (char*)bp->ebuf - i;
+			if(i < bp->bsize){
+				memmove(ip, bp->bbuf, (size_t)i);
+				bp->gbuf = (unsigned char*)ip;
+			}
+			j = (int)((ep - (char*)bp->bbuf) + 1);
+			bp->rdline = j;
+			bp->icount = j - i;
+			return ip;
+		}
+		ip += j;
+	}
+
+	/*
+	 * full buffer without finding
+	 */
+	bp->rdline = bp->bsize;
+	bp->icount = -bp->bsize;
+	bp->gbuf = bp->bbuf;
+	return 0;
+}
+
+int
+Blinelen(Biobuf *bp)
+{
+
+	return bp->rdline;
+}
diff --git a/src/libbio/brdstr.c b/src/libbio/brdstr.c
new file mode 100644
index 0000000..6a90cf6
--- /dev/null
+++ b/src/libbio/brdstr.c
@@ -0,0 +1,60 @@
+/*
+	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>
+
+char*
+Brdstr(Biobuf *bp, int delim, int nulldelim)
+{
+	char *p, *q, *nq;
+	int n, linelen;
+
+	q = nil;
+	n = 0;
+	for(;;) {
+		p = Brdline(bp, delim);
+		linelen = Blinelen(bp);
+		if(n == 0 && linelen == 0)
+			return nil;
+		nq = realloc(q, (size_t)(n+linelen+1));
+		if(nq == nil) {
+			free(q);
+			return nil;
+		}
+		q = nq;
+		if(p != nil) {
+			memmove(q+n, p, (size_t)linelen);
+			n += linelen;
+			if(nulldelim)
+				q[n-1] = '\0';
+			break;
+		}
+		if(linelen == 0)
+			break;
+		Bread(bp, q+n, linelen);
+		n += linelen;
+	}
+	q[n] = '\0';
+	return q;
+}
diff --git a/src/libbio/bread.c b/src/libbio/bread.c
new file mode 100644
index 0000000..343a0bf
--- /dev/null
+++ b/src/libbio/bread.c
@@ -0,0 +1,71 @@
+/*
+http://code.google.com/p/inferno-os/source/browse/libbio/bread.c
+
+	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+	Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).  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>
+
+long
+Bread(Biobuf *bp, void *ap, long count)
+{
+	long c;
+	unsigned char *p;
+	int i, n, ic;
+
+	p = ap;
+	c = count;
+	ic = bp->icount;
+
+	while(c > 0) {
+		n = -ic;
+		if(n > c)
+			n = (int)c;
+		if(n == 0) {
+			if(bp->state != Bractive)
+				break;
+			i = (int)read(bp->fid, bp->bbuf, (size_t)bp->bsize);
+			if(i <= 0) {
+				bp->state = Bracteof;
+				if(i < 0)
+					bp->state = Binactive;
+				break;
+			}
+			bp->gbuf = bp->bbuf;
+			bp->offset += i;
+			if(i < bp->bsize) {
+				memmove(bp->ebuf-i, bp->bbuf, (size_t)i);
+				bp->gbuf = bp->ebuf-i;
+			}
+			ic = -i;
+			continue;
+		}
+		memmove(p, bp->ebuf+ic, (size_t)n);
+		c -= n;
+		ic += n;
+		p += n;
+	}
+	bp->icount = ic;
+	return count-c;
+}
diff --git a/src/libbio/bseek.c b/src/libbio/bseek.c
new file mode 100644
index 0000000..5289585
--- /dev/null
+++ b/src/libbio/bseek.c
@@ -0,0 +1,93 @@
+/*
+http://code.google.com/p/inferno-os/source/browse/libbio/bseek.c
+
+	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+	Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).  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>
+
+vlong
+Bseek(Biobuf *bp, vlong offset, int base)
+{
+	vlong n, d;
+	int bufsz;
+
+#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();
+	}
+#endif
+
+	switch(bp->state) {
+	default:
+		fprint(2, "Bseek: unknown state %d\n", bp->state);
+		return Beof;
+
+	case Bracteof:
+		bp->state = Bractive;
+		bp->icount = 0;
+		bp->gbuf = bp->ebuf;
+
+	case Bractive:
+		n = offset;
+		if(base == 1) {
+			n += Boffset(bp);
+			base = 0;
+		}
+
+		/*
+		 * try to seek within buffer
+		 */
+		if(base == 0) {
+			d = n - Boffset(bp);
+			bufsz = (int)(bp->ebuf - bp->gbuf);
+			if(-bufsz <= d && d <= bufsz){
+				bp->icount += (int)d;
+				if(d >= 0) {
+					if(bp->icount <= 0)
+						return n;
+				} else {
+					if(bp->ebuf - bp->gbuf >= -bp->icount)
+						return n;
+				}
+			}
+		}
+
+		/*
+		 * reset the buffer
+		 */
+		n = lseek(bp->fid, n, base);
+		bp->icount = 0;
+		bp->gbuf = bp->ebuf;
+		break;
+
+	case Bwactive:
+		Bflush(bp);
+		n = lseek(bp->fid, offset, base);
+		break;
+	}
+	bp->offset = n;
+	return n;
+}
diff --git a/src/libbio/bwrite.c b/src/libbio/bwrite.c
new file mode 100644
index 0000000..8b9943a
--- /dev/null
+++ b/src/libbio/bwrite.c
@@ -0,0 +1,64 @@
+/*
+http://code.google.com/p/inferno-os/source/browse/libbio/bwrite.c
+
+	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+	Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).  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>
+
+long
+Bwrite(Biobuf *bp, void *ap, long count)
+{
+	long c;
+	unsigned char *p;
+	int i, n, oc;
+
+	p = ap;
+	c = count;
+	oc = bp->ocount;
+
+	while(c > 0) {
+		n = -oc;
+		if(n > c)
+			n = (int)c;
+		if(n == 0) {
+			if(bp->state != Bwactive)
+				return Beof;
+			i = (int)write(bp->fid, bp->bbuf, (size_t)bp->bsize);
+			if(i != bp->bsize) {
+				bp->state = Binactive;
+				return Beof;
+			}
+			bp->offset += i;
+			oc = -bp->bsize;
+			continue;
+		}
+		memmove(bp->ebuf+oc, p, (size_t)n);
+		oc += n;
+		c -= n;
+		p += n;
+	}
+	bp->ocount = oc;
+	return count-c;
+}
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..96df9f7
--- /dev/null
+++ b/src/liblink/asm5.c
@@ -0,0 +1,2696 @@
+// 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 "../runtime/stack.h"
+
+typedef	struct	Optab	Optab;
+typedef	struct	Oprang	Oprang;
+typedef	uchar	Opcross[32][2][32];
+
+struct	Optab
+{
+	uchar	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,
+};
+
+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 },
+	{ ANOP,		C_NONE,	C_NONE,	C_NONE,		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
+
+	{ ADATABUNDLE,	C_NONE, C_NONE, C_NONE,		100, 4, 0 },
+	{ ADATABUNDLEEND,	C_NONE, C_NONE, C_NONE,		100, 0, 0 },
+
+	{ 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 int	asmoutnacl(Link*, int32, 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	Oprang	oprange[ALAST];
+static	uchar	xcmp[C_GOK+1][C_GOK+1];
+
+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 LSym *deferreturn;
+
+static void
+nocache(Prog *p)
+{
+	p->optab = 0;
+	p->from.class = 0;
+	p->to.class = 0;
+}
+
+/* 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*);
+
+// asmoutnacl assembles the instruction p. It replaces asmout for NaCl.
+// It returns the total number of bytes put in out, and it can change
+// p->pc if extra padding is necessary.
+// In rare cases, asmoutnacl might split p into two instructions.
+// origPC is the PC for this Prog (no padding is taken into account).
+static int
+asmoutnacl(Link *ctxt, int32 origPC, Prog *p, Optab *o, int32 *out)
+{
+	int size, reg;
+	Prog *q;
+	Addr *a, *a2;
+
+	size = o->size;
+
+	// instruction specific
+	switch(p->as) {
+	default:
+		if(out != nil)
+			asmout(ctxt, p, o, out);
+		break;
+	case ADATABUNDLE: // align to 16-byte boundary
+	case ADATABUNDLEEND: // zero width instruction, just to align next instruction to 16-byte boundary
+		p->pc = (p->pc+15) & ~15;
+		if(out != nil)
+			asmout(ctxt, p, o, out);
+		break;
+	case AUNDEF:
+	case APLD:
+		size = 4;
+		if(out != nil) {
+			switch(p->as) {
+			case AUNDEF:
+				out[0] = 0xe7fedef0; // NACL_INSTR_ARM_ABORT_NOW (UDF #0xEDE0)
+				break;
+			case APLD:
+				out[0] = 0xe1a01001; // (MOVW R1, R1)
+				break;
+			}
+		}
+		break;
+	case AB:
+	case ABL:
+		if(p->to.type != D_OREG) {
+			if(out != nil)
+				asmout(ctxt, p, o, out);
+		} else {
+			if(p->to.offset != 0 || size != 4 || p->to.reg >= 16 || p->to.reg < 0)
+				ctxt->diag("unsupported instruction: %P", p);
+			if((p->pc&15) == 12)
+				p->pc += 4;
+			if(out != nil) {
+				out[0] = ((p->scond&C_SCOND)<<28) | 0x03c0013f | (p->to.reg << 12) | (p->to.reg << 16); // BIC $0xc000000f, Rx
+				if(p->as == AB)
+					out[1] = ((p->scond&C_SCOND)<<28) | 0x012fff10 | p->to.reg; // BX Rx
+				else // ABL
+					out[1] = ((p->scond&C_SCOND)<<28) | 0x012fff30 | p->to.reg; // BLX Rx
+			}
+			size = 8;
+		}
+		// align the last instruction (the actual BL) to the last instruction in a bundle
+		if(p->as == ABL) {
+			if(deferreturn == nil)
+				deferreturn = linklookup(ctxt, "runtime.deferreturn", 0);
+			if(p->to.sym == deferreturn)
+				p->pc = ((origPC+15) & ~15) + 16 - size;
+			else
+				p->pc += (16 - ((p->pc+size)&15)) & 15;
+		}
+		break;
+	case ALDREX:
+	case ALDREXD:
+	case AMOVB:
+	case AMOVBS:
+	case AMOVBU:
+	case AMOVD:
+	case AMOVF:
+	case AMOVH:
+	case AMOVHS:
+	case AMOVHU:
+	case AMOVM:
+	case AMOVW:
+	case ASTREX:
+	case ASTREXD:
+		if(p->to.type == D_REG && p->to.reg == 15 && p->from.reg == 13) { // MOVW.W x(R13), PC
+			if(out != nil)
+				asmout(ctxt, p, o, out);
+			if(size == 4) {
+				if(out != nil) {
+					// Note: 5c and 5g reg.c know that DIV/MOD smashes R12
+					// so that this return instruction expansion is valid.
+					out[0] = out[0] & ~0x3000; // change PC to R12
+					out[1] = ((p->scond&C_SCOND)<<28) | 0x03ccc13f; // BIC $0xc000000f, R12
+					out[2] = ((p->scond&C_SCOND)<<28) | 0x012fff1c; // BX R12
+				}
+				size += 8;
+				if(((p->pc+size) & 15) == 4)
+					p->pc += 4;
+				break;
+			} else {
+				// if the instruction used more than 4 bytes, then it must have used a very large
+				// offset to update R13, so we need to additionally mask R13.
+				if(out != nil) {
+					out[size/4-1] &= ~0x3000; // change PC to R12
+					out[size/4] = ((p->scond&C_SCOND)<<28) | 0x03cdd103; // BIC $0xc0000000, R13
+					out[size/4+1] = ((p->scond&C_SCOND)<<28) | 0x03ccc13f; // BIC $0xc000000f, R12
+					out[size/4+2] = ((p->scond&C_SCOND)<<28) | 0x012fff1c; // BX R12
+				}
+				// p->pc+size is only ok at 4 or 12 mod 16.
+				if((p->pc+size)%8 == 0)
+					p->pc += 4;
+				size += 12;
+				break;
+			}
+		}
+
+		if(p->to.type == D_REG && p->to.reg == 15)
+			ctxt->diag("unsupported instruction (move to another register and use indirect jump instead): %P", p);
+
+		if(p->to.type == D_OREG && p->to.reg == 13 && (p->scond & C_WBIT) && size > 4) {
+			// function prolog with very large frame size: MOVW.W R14,-100004(R13)
+			// split it into two instructions:
+			// 	ADD $-100004, R13
+			// 	MOVW R14, 0(R13)
+			q = ctxt->arch->prg();
+			p->scond &= ~C_WBIT;
+			*q = *p;
+			a = &p->to;
+			if(p->to.type == D_OREG)
+				a2 = &q->to;
+			else
+				a2 = &q->from;
+			nocache(q);
+			nocache(p);
+			// insert q after p
+			q->link = p->link;
+			p->link = q;
+			q->pcond = nil;
+			// make p into ADD $X, R13
+			p->as = AADD;
+			p->from = *a;
+			p->from.reg = NREG;
+			p->from.type = D_CONST;
+			p->to = zprg.to;
+			p->to.type = D_REG;
+			p->to.reg = 13;
+			// make q into p but load/store from 0(R13)
+			q->spadj = 0;
+			*a2 = zprg.from;
+			a2->type = D_OREG;
+			a2->reg = 13;
+			a2->sym = nil;
+			a2->offset = 0;
+			size = oplook(ctxt, p)->size;
+			break;
+		}
+
+		if((p->to.type == D_OREG && p->to.reg != 13 && p->to.reg != 9) || // MOVW Rx, X(Ry), y != 13 && y != 9
+		   (p->from.type == D_OREG && p->from.reg != 13 && p->from.reg != 9)) { // MOVW X(Rx), Ry, x != 13 && x != 9
+			if(p->to.type == D_OREG)
+				a = &p->to;
+			else
+				a = &p->from;
+			reg = a->reg;
+			if(size == 4) {
+				// if addr.reg == NREG, then it is probably load from x(FP) with small x, no need to modify.
+				if(reg == NREG) {
+					if(out != nil)
+						asmout(ctxt, p, o, out);
+				} else {
+					if(out != nil)
+						out[0] = ((p->scond&C_SCOND)<<28) | 0x03c00103 | (reg << 16) | (reg << 12); // BIC $0xc0000000, Rx
+					if((p->pc&15) == 12)
+						p->pc += 4;
+					size += 4;
+					if(out != nil)
+						asmout(ctxt, p, o, &out[1]);
+				}
+				break;
+			} else {
+				// if a load/store instruction takes more than 1 word to implement, then
+				// we need to seperate the instruction into two:
+				// 1. explicitly load the address into R11.
+				// 2. load/store from R11.
+				// This won't handle .W/.P, so we should reject such code.
+				if(p->scond & (C_PBIT|C_WBIT))
+					ctxt->diag("unsupported instruction (.P/.W): %P", p);
+				q = ctxt->arch->prg();
+				*q = *p;
+				if(p->to.type == D_OREG)
+					a2 = &q->to;
+				else
+					a2 = &q->from;
+				nocache(q);
+				nocache(p);
+				// insert q after p
+				q->link = p->link;
+				p->link = q;
+				q->pcond = nil;
+				// make p into MOVW $X(R), R11
+				p->as = AMOVW;
+				p->from = *a;
+				p->from.type = D_CONST;
+				p->to = zprg.to;
+				p->to.type = D_REG;
+				p->to.reg = 11;
+				// make q into p but load/store from 0(R11)
+				*a2 = zprg.from;
+				a2->type = D_OREG;
+				a2->reg = 11;
+				a2->sym = nil;
+				a2->offset = 0;
+				size = oplook(ctxt, p)->size;
+				break;
+			}
+		} else if(out != nil)
+			asmout(ctxt, p, o, out);
+		break;
+	}
+
+	// destination register specific
+	if(p->to.type == D_REG) {
+		switch(p->to.reg) {
+		case 9:
+			ctxt->diag("invalid instruction, cannot write to R9: %P", p);
+			break;
+		case 13:
+			if(out != nil)
+				out[size/4] = 0xe3cdd103; // BIC $0xc0000000, R13
+			if(((p->pc+size) & 15) == 0)
+				p->pc += 4;
+			size += 4;
+			break;
+		}
+	}
+	return size;
+}
+
+void
+span5(Link *ctxt, LSym *cursym)
+{
+	Prog *p, *op;
+	Optab *o;
+	int m, bflag, i, v, times;
+	int32 c, opc, out[6+3];
+	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 || ctxt->blitrl != nil; op = p, p = p->link) {
+		if(p == nil) {
+		       	if(checkpool(ctxt, op, 0)) {
+				p = op;
+				continue;
+			}
+			// can't happen: blitrl is not nil, but checkpool didn't flushpool
+			ctxt->diag("internal inconsistency");
+			break;
+		}
+		ctxt->curp = p;
+		p->pc = c;
+		o = oplook(ctxt, p);
+		if(ctxt->headtype != Hnacl) {
+			m = o->size;
+		} else {
+			m = asmoutnacl(ctxt, c, p, o, nil);
+			c = p->pc; // asmoutnacl might change pc for alignment
+			o = oplook(ctxt, p); // asmoutnacl might change p in rare cases
+		}
+		if(m % 4 != 0 || p->pc % 4 != 0) {
+			ctxt->diag("!pc invalid: %P size=%d", p, m);
+		}
+		// 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 = op;
+				continue;
+			}
+		}
+		if(m == 0 && (p->as != AFUNCDATA && p->as != APCDATA && p->as != ADATABUNDLEEND && p->as != ANOP)) {
+			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;
+	}
+	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.
+	 */
+	times = 0;
+	do {
+		if(ctxt->debugvlog)
+			Bprint(ctxt->bso, "%5.2f span1\n", cputime());
+		bflag = 0;
+		c = 0;
+		times++;
+		cursym->text->pc = 0; // force re-layout the code.
+		for(p = cursym->text; p != nil; p = p->link) {
+			ctxt->curp = p;
+			o = oplook(ctxt,p);
+			if(c > p->pc)
+				p->pc = c;
+/* 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;
+				}
+			}
+ */
+			opc = p->pc;
+			if(ctxt->headtype != Hnacl)
+				m = o->size;
+			else
+				m = asmoutnacl(ctxt, c, p, o, nil);
+			if(p->pc != opc) {
+				bflag = 1;
+				//print("%P pc changed %d to %d in iter. %d\n", p, opc, (int32)p->pc, times);
+			}
+			c = p->pc + m;
+			if(m % 4 != 0 || p->pc % 4 != 0) {
+				ctxt->diag("pc invalid: %P size=%d", p, m);
+			}
+			if(m/4 > nelem(out))
+				ctxt->diag("instruction size too large: %d > %d", m/4, nelem(out));
+			if(m == 0 && (p->as != AFUNCDATA && p->as != APCDATA && p->as != ADATABUNDLEEND && p->as != ANOP)) {
+				if(p->as == ATEXT) {
+					ctxt->autosize = p->to.offset + 4;
+					continue;
+				}
+				ctxt->diag("zero-width instruction\n%P", p);
+				continue;
+			}
+		}
+		cursym->size = c;
+	} while(bflag);
+	if(c % 4 != 0) {
+		ctxt->diag("sym->size=%d, invalid", c);
+	}
+
+	/*
+	 * 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->tlsg == nil)
+		ctxt->tlsg = linklookup(ctxt, "runtime.tlsg", 0);
+
+	p = cursym->text;
+	ctxt->autosize = p->to.offset + 4;
+	symgrow(ctxt, cursym, cursym->size);
+
+	bp = cursym->p;
+	c = p->pc; // even p->link might need extra padding
+	for(p = p->link; p != nil; p = p->link) {
+		ctxt->pc = p->pc;
+		ctxt->curp = p;
+		o = oplook(ctxt, p);
+		opc = p->pc;
+		if(ctxt->headtype != Hnacl) {
+			asmout(ctxt, p, o, out);
+			m = o->size;
+		} else {
+			m = asmoutnacl(ctxt, c, p, o, out);
+			if(opc != p->pc)
+				ctxt->diag("asmoutnacl broken: pc changed (%d->%d) in last stage: %P", opc, (int32)p->pc, p);
+		}
+		if(m % 4 != 0 || p->pc % 4 != 0) {
+			ctxt->diag("final stage: pc invalid: %P size=%d", p, m);
+		}
+		if(c > p->pc)
+			ctxt->diag("PC padding invalid: want %#lld, has %#d: %P", p->pc, c, p);
+		while(c != p->pc) {
+			// emit 0xe1a00000 (MOVW R0, R0)
+			*bp++ = 0x00;
+			*bp++ = 0x00;
+			*bp++ = 0xa0;
+			*bp++ = 0xe1;
+			c += 4;
+		}
+		for(i=0; i<m/4; i++) {
+			v = out[i];
+			*bp++ = v;
+			*bp++ = v>>8;
+			*bp++ = v>>16;
+			*bp++ = v>>24;
+		}
+		c += m;
+	}
+}
+
+/*
+ * 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 >= 0xff0 || immaddr((p->pc+sz+4)+4+(12+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+(12+pool.size)-pool.start < 2048)) // 12 take into account the maximum nacl literal pool alignment padding size
+			return 0;
+		if(ctxt->headtype == Hnacl && pool.size % 16 != 0) {
+			// if pool is not multiple of 16 bytes, add an alignment marker
+			q = ctxt->arch->prg();
+			q->as = ADATABUNDLEEND;
+			ctxt->elitrl->link = q;
+			ctxt->elitrl = q;
+		}
+		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.offset = a->offset;
+		t.to.sym = a->sym;
+		t.to.type = a->type;
+		t.to.name = a->name;
+		
+		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;
+			}
+	}
+
+	if(ctxt->headtype == Hnacl && pool.size%16 == 0) {
+		// start a new data bundle
+		q = ctxt->arch->prg();
+		*q = zprg;
+		q->as = ADATABUNDLE;
+		q->pc = pool.size;
+		pool.size += 4;
+		if(ctxt->blitrl == nil) {
+			ctxt->blitrl = q;
+			pool.start = p->pc;
+		} else {
+			ctxt->elitrl->link = q;
+		}
+		ctxt->elitrl = q;
+	}
+
+	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 aconsize(Link *ctxt);
+
+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");
+				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)
+				return aconsize(ctxt);
+
+			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;
+			return aconsize(ctxt);
+
+		case D_PARAM:
+			ctxt->instoffset = ctxt->autosize + a->offset + 4L;
+			return aconsize(ctxt);
+		}
+		return C_GOK;
+
+	case D_BRANCH:
+		return C_SBRA;
+	}
+	return C_GOK;
+}
+
+static int
+aconsize(Link *ctxt)
+{
+	int t;
+
+	t = immrot(ctxt->instoffset);
+	if(t)
+		return C_RACON;
+	return C_LACON;
+}
+
+static void
+prasm(Prog *p)
+{
+	print("%P\n", p);
+}
+
+static Optab*
+oplook(Link *ctxt, Prog *p)
+{
+	int a1, a2, a3, r;
+	uchar *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) {
+		o = oprange[r].stop; /* just generate an error */
+	}
+	if(0 /*debug['O']*/) {
+		print("oplook %A %^ %^ %^\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",
+		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:
+		case ANOP:
+		case ADATABUNDLE:
+		case ADATABUNDLEEND:
+			break;
+		}
+	}
+}
+
+static int32 mov(Link*, Prog*);
+
+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 */
+		o1 = mov(ctxt, p);
+		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.tlsg 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->tlsg) {
+				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:
+	case 39:
+		switch(o->type) {
+		case 38:	/* movm $con,oreg -> stm */
+			o1 = (0x4 << 25);
+			o1 |= p->from.offset & 0xffff;
+			o1 |= p->to.reg << 16;
+			aclass(ctxt, &p->to);
+			break;
+	
+		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);
+			break;
+		}
+		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");
+			o1 = mov(ctxt, p);
+			break;
+		}
+		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");
+			o1 = mov(ctxt, p);
+			break;
+		}
+		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;
+	case 100:
+		// DATABUNDLE: BKPT $0x5be0, signify the start of NaCl data bundle;
+		// DATABUNDLEEND: zero width alignment marker
+		if(p->as == ADATABUNDLE)
+			o1 = 0xe125be70;
+		break;
+	}
+	
+	out[0] = o1;
+	out[1] = o2;
+	out[2] = o3;
+	out[3] = o4;
+	out[4] = o5;
+	out[5] = o6;
+	return;
+}
+
+static int32
+mov(Link *ctxt, Prog *p)
+{
+	int32 o1;
+	int rt, r;
+
+	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);
+	return o1;
+}
+
+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..428eb94
--- /dev/null
+++ b/src/liblink/asm6.c
@@ -0,0 +1,3611 @@
+// 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 "../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
+};
+
+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 uchar 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.
+ */
+static 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,	Pm, {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, {0x9b,(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*);
+
+// isextern reports whether s describes an external symbol that must avoid pc-relative addressing.
+// This happens on systems like Solaris that call .so functions instead of system calls.
+// It does not seem to be necessary for any other systems. This is probably working
+// around a Solaris-specific bug that should be fixed differently, but we don't know
+// what that bug is. And this does fix it.
+static int
+isextern(LSym *s)
+{
+	// All the Solaris dynamic imports from libc.so begin with "libc·", which
+	// the compiler rewrites to "libc." by the time liblink gets it.
+	return strncmp(s->name, "libc.", 5) == 0;
+}
+
+// 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 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(a->sym != nil && isextern(a->sym))
+						return Yi32;
+					return Yiauto; // use pc-relative addressing
+				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;
+
+	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");
+		}
+		if(isextern(s)) {
+			r->siz = 4;
+			r->type = R_ADDR;
+		} else {
+			r->siz = 4;
+			r->type = R_PCREL;
+		}
+		r->off = -1;	// caller must fill in
+		r->sym = s;
+		r->add = v;
+		v = 0;
+		if(s->type == STLSBSS) {
+			r->xadd = r->add - r->siz;
+			r->type = R_TLS;
+			r->xsym = s;
+		}
+		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_EXTERN:
+			case D_STATIC:
+				if(!isextern(a->sym))
+					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((a->sym == nil || !isextern(a->sym)) && 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, uint8 *t)
+{
+	if(a->index == D_NONE && (a->type >= D_AX && a->type <= D_R15)) {
+		a->type = D_AL + (a->type-D_AX);
+		*t = 0;
+	}
+}
+
+enum {
+	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->and[ctxt->andptr - ctxt->and - 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 Zcallindreg:
+		r = addrel(ctxt->cursym);
+		r->off = p->pc;
+		r->type = R_CALLIND;
+		r->siz = 0;
+		// fallthrough
+	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->rexflag &= ~Pw;
+		*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 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 Hplan9:
+			if(ctxt->plan9privates == nil)
+				ctxt->plan9privates = linklookup(ctxt, "_privates", 0);
+			memset(&pp.from, 0, sizeof pp.from);
+			pp.from.type = D_EXTERN;
+			pp.from.sym = ctxt->plan9privates;
+			pp.from.offset = 0;
+			pp.from.index = D_NONE;
+			ctxt->rexflag |= Pw;
+			*ctxt->andptr++ = 0x8B;
+			asmand(ctxt, &pp.from, &p->to);
+			break;
+
+		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 i, 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(i=ctxt->cursym->nr-1; i>=0; i--) {
+		r = ctxt->cursym->r+i;
+		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..b6627d5
--- /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 "../runtime/stack.h"
+
+enum
+{
+	MaxAlign = 32,	// max data alignment
+	FuncAlign = 16
+};
+
+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	int	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, {0x9b,(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;
+}
+
+enum
+{
+	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->and[ctxt->andptr - ctxt->and - 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 Zcallindreg:
+		r = addrel(ctxt->cursym);
+		r->off = p->pc;
+		r->type = R_CALLIND;
+		r->siz = 0;
+		// fallthrough
+	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 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->plan9privates == nil)
+				ctxt->plan9privates = linklookup(ctxt, "_privates", 0);
+			memset(&pp.from, 0, sizeof pp.from);
+			pp.from.type = D_EXTERN;
+			pp.from.sym = ctxt->plan9privates;
+			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..e5efa2e
--- /dev/null
+++ b/src/liblink/data.c
@@ -0,0 +1,372 @@
+// 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);
+	if(ctxt->enforce_data_order && off < s->np)
+		ctxt->diag("data out of order (already have %d)\n%P", p);
+	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..6d0fe4a
--- /dev/null
+++ b/src/liblink/ld.c
@@ -0,0 +1,276 @@
+// 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(LinkArch *arch)
+{
+	int i, c;
+
+	if(arch->endian != BigEndian && arch->endian != LittleEndian)
+		sysfatal("unknown endian (%#x) for arch %s", arch->endian, arch->name);
+
+	for(i=0; i<4; i++) {
+		c = find1(arch->endian, i+1);
+		if(arch->endian == LittleEndian) {
+			if(i < 2)
+				inuxi2[i] = c;
+			if(i < 1)
+				inuxi1[i] = c;
+		} else {
+			if(i >= 2)
+				inuxi2[i-2] = c;
+			if(i >= 3)
+				inuxi1[i-3] = 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;
+		if(c == i) {
+			fnuxi8[i] = c;
+			fnuxi8[i+4] = c+4;
+		} else {
+			fnuxi8[i] = c+4;
+			fnuxi8[i+4] = c;
+		}
+	}
+}
+
+uchar	fnuxi8[8];
+uchar	fnuxi4[4];
+uchar	inuxi1[1];
+uchar	inuxi2[2];
+uchar	inuxi4[4];
+uchar	inuxi8[8];
+
+enum
+{
+	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..a91df55
--- /dev/null
+++ b/src/liblink/list5.c
@@ -0,0 +1,373 @@
+// 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);
+static int	DRconv(Fmt*);
+
+#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 liblink internal use
+	fmtinstall('^', DRconv);
+
+	// 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
+DRconv(Fmt *fp)
+{
+	char *s;
+	int a;
+
+	a = va_arg(fp->args, int);
+	s = "C_??";
+	if(a >= C_NONE && a <= C_NCLASS)
+		s = cnames5[a];
+	return fmtstrcpy(fp, s);
+}
+
+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..0635fdf
--- /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);
+}
+
+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",
+
+	"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..63d96b9
--- /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);
+}
+
+static 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..d7f2714
--- /dev/null
+++ b/src/liblink/obj5.c
@@ -0,0 +1,1094 @@
+// 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 "../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;
+	static 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:
+		// Treat MRC 15, 0, <reg>, C13, C0, 3 specially.
+		if((p->to.offset & 0xffff0fff) == 0xee1d0f70) {
+			// Because the instruction might be rewriten to a BL which returns in R0
+			// the register must be zero.
+		       	if ((p->to.offset & 0xf000) != 0)
+				ctxt->diag("%L: TLS MRC instruction must write to R0 as it might get translated into a BL instruction", p->lineno);
+
+			if(ctxt->goarm < 7) {
+				// Replace it with BL runtime.read_tls_fallback(SB) for ARM CPUs that lack the tls extension.
+				if(tlsfallback == nil)
+					tlsfallback = linklookup(ctxt, "runtime.read_tls_fallback", 0);
+				// MOVW	LR, R11
+				p->as = AMOVW;
+				p->from.type = D_REG;
+				p->from.reg = REGLINK;
+				p->to.type = D_REG;
+				p->to.reg = REGTMP;
+
+				// BL	runtime.read_tls_fallback(SB)
+				p = appendp(ctxt, p);
+				p->as = ABL;
+				p->to.type = D_BRANCH;
+				p->to.sym = tlsfallback;
+				p->to.offset = 0;
+
+				// MOVW	R11, LR
+				p = appendp(ctxt, p);
+				p->as = AMOVW;
+				p->from.type = D_REG;
+				p->from.reg = REGTMP;
+				p->to.type = D_REG;
+				p->to.reg = REGLINK;
+				break;
+			}
+		}
+		// 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.tlsg with an address to a GOT entry containing the 
+		// offset. Rewrite $runtime.tlsg(SB) to runtime.tlsg(SB) to
+		// compensate.
+		if(ctxt->tlsg == nil)
+			ctxt->tlsg = linklookup(ctxt, "runtime.tlsg", 0);
+
+		if(p->from.type == D_CONST && p->from.name == D_EXTERN && p->from.sym == ctxt->tlsg)
+			p->from.type = D_OREG;
+		if(p->to.type == D_CONST && p->to.name == D_EXTERN && p->to.sym == ctxt->tlsg)
+			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, *p1, *p2, *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) {
+				// if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
+				//
+				//	MOVW g_panic(g), R1
+				//	CMP $0, R1
+				//	B.EQ end
+				//	MOVW panic_argp(R1), R2
+				//	ADD $(autosize+4), R13, R3
+				//	CMP R2, R3
+				//	B.NE end
+				//	ADD $4, R13, R4
+				//	MOVW R4, panic_argp(R1)
+				// end:
+				//	NOP
+				//
+				// The NOP is needed to give the jumps somewhere to land.
+				// It is a liblink NOP, not an ARM NOP: it encodes to 0 instruction bytes.
+
+				p = appendp(ctxt, p);
+				p->as = AMOVW;
+				p->from.type = D_OREG;
+				p->from.reg = REGG;
+				p->from.offset = 4*ctxt->arch->ptrsize; // G.panic
+				p->to.type = D_REG;
+				p->to.reg = 1;
+			
+				p = appendp(ctxt, p);
+				p->as = ACMP;
+				p->from.type = D_CONST;
+				p->from.offset = 0;
+				p->reg = 1;
+			
+				p = appendp(ctxt, p);
+				p->as = ABEQ;
+				p->to.type = D_BRANCH;
+				p1 = p;
+				
+				p = appendp(ctxt, p);
+				p->as = AMOVW;
+				p->from.type = D_OREG;
+				p->from.reg = 1;
+				p->from.offset = 0; // Panic.argp
+				p->to.type = D_REG;
+				p->to.reg = 2;
+			
+				p = appendp(ctxt, p);
+				p->as = AADD;
+				p->from.type = D_CONST;
+				p->from.offset = autosize+4;
+				p->reg = 13;
+				p->to.type = D_REG;
+				p->to.reg = 3;
+
+				p = appendp(ctxt, p);
+				p->as = ACMP;
+				p->from.type = D_REG;
+				p->from.reg = 2;
+				p->reg = 3;
+
+				p = appendp(ctxt, p);
+				p->as = ABNE;
+				p->to.type = D_BRANCH;
+				p2 = p;
+			
+				p = appendp(ctxt, p);
+				p->as = AADD;
+				p->from.type = D_CONST;
+				p->from.offset = 4;
+				p->reg = 13;
+				p->to.type = D_REG;
+				p->to.reg = 4;
+
+				p = appendp(ctxt, p);
+				p->as = AMOVW;
+				p->from.type = D_REG;
+				p->from.reg = 4;
+				p->to.type = D_OREG;
+				p->to.reg = 1;
+				p->to.offset = 0; // Panic.argp
+
+				p = appendp(ctxt, p);
+				p->as = ANOP;
+				p1->pcond = p;
+				p2->pcond = p;
+			}
+			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;
+				}
+			}
+
+			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;
+		}
+		continue;
+
+	notsoft:
+		wasfloat = 0;
+	}
+}
+
+static Prog*
+stacksplit(Link *ctxt, Prog *p, int32 framesize, int noctxt)
+{
+	// MOVW			g_stackguard(g), R1
+	p = appendp(ctxt, p);
+	p->as = AMOVW;
+	p->from.type = D_OREG;
+	p->from.reg = REGG;
+	p->from.offset = 2*ctxt->arch->ptrsize;	// G.stackguard0
+	if(ctxt->cursym->cfunc)
+		p->from.offset = 3*ctxt->arch->ptrsize;	// G.stackguard1
+	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	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;
+	if(ctxt->cursym->cfunc)
+		p->to.sym = linklookup(ctxt, "runtime.morestackc", 0);
+	else
+		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',
+	.endian = LittleEndian,
+
+	.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,
+	.D_OREG = D_OREG,
+
+	.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..2acfd2f
--- /dev/null
+++ b/src/liblink/obj6.c
@@ -0,0 +1,1094 @@
+// 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 "../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 Hplan9:
+	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 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, *p1, *p2;
+	int32 autoffset, deltasp;
+	int a, pcsize;
+	vlong textstksiz, textarg;
+
+	if(ctxt->tlsg == nil)
+		ctxt->tlsg = linklookup(ctxt, "runtime.tlsg", 0);
+	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->plan9privates == nil)
+		ctxt->plan9privates = linklookup(ctxt, "_privates", 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) {
+		// if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
+		//
+		//	MOVQ g_panic(CX), BX
+		//	TESTQ BX, BX
+		//	JEQ end
+		//	LEAQ (autoffset+8)(SP), DI
+		//	CMPQ panic_argp(BX), DI
+		//	JNE end
+		//	MOVQ SP, panic_argp(BX)
+		// end:
+		//	NOP
+		//
+		// The NOP is needed to give the jumps somewhere to land.
+		// It is a liblink NOP, not an x86 NOP: it encodes to 0 instruction bytes.
+
+		p = appendp(ctxt, p);
+		p->as = AMOVQ;
+		p->from.type = D_INDIR+D_CX;
+		p->from.offset = 4*ctxt->arch->ptrsize; // G.panic
+		p->to.type = D_BX;
+		if(ctxt->headtype == Hnacl) {
+			p->as = AMOVL;
+			p->from.type = D_INDIR+D_R15;
+			p->from.scale = 1;
+			p->from.index = D_CX;
+		}
+
+		p = appendp(ctxt, p);
+		p->as = ATESTQ;
+		p->from.type = D_BX;
+		p->to.type = D_BX;
+		if(ctxt->headtype == Hnacl)
+			p->as = ATESTL;
+
+		p = appendp(ctxt, p);
+		p->as = AJEQ;
+		p->to.type = D_BRANCH;
+		p1 = p;
+
+		p = appendp(ctxt, p);
+		p->as = ALEAQ;
+		p->from.type = D_INDIR+D_SP;
+		p->from.offset = autoffset+8;
+		p->to.type = D_DI;
+		if(ctxt->headtype == Hnacl)
+			p->as = ALEAL;
+
+		p = appendp(ctxt, p);
+		p->as = ACMPQ;
+		p->from.type = D_INDIR+D_BX;
+		p->from.offset = 0; // Panic.argp
+		p->to.type = D_DI;
+		if(ctxt->headtype == Hnacl) {
+			p->as = ACMPL;
+			p->from.type = D_INDIR+D_R15;
+			p->from.scale = 1;
+			p->from.index = D_BX;
+		}
+
+		p = appendp(ctxt, p);
+		p->as = AJNE;
+		p->to.type = D_BRANCH;
+		p2 = p;
+
+		p = appendp(ctxt, p);
+		p->as = AMOVQ;
+		p->from.type = D_SP;
+		p->to.type = D_INDIR+D_BX;
+		p->to.offset = 0; // Panic.argp
+		if(ctxt->headtype == Hnacl) {
+			p->as = AMOVL;
+			p->to.type = D_INDIR+D_R15;
+			p->to.scale = 1;
+			p->to.index = D_BX;
+		}
+
+		p = appendp(ctxt, p);
+		p->as = ANOP;
+		p1->pcond = p;
+		p2->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(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;
+	int cmp, lea, mov, sub;
+
+	USED(textarg);
+	cmp = ACMPQ;
+	lea = ALEAQ;
+	mov = AMOVQ;
+	sub = ASUBQ;
+
+	if(ctxt->headtype == Hnacl) {
+		cmp = ACMPL;
+		lea = ALEAL;
+		mov = AMOVL;
+		sub = ASUBL;
+	}
+
+	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);
+		p->to.offset = 2*ctxt->arch->ptrsize;	// G.stackguard0
+		if(ctxt->cursym->cfunc)
+			p->to.offset = 3*ctxt->arch->ptrsize;	// G.stackguard1
+	} 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);
+		p->to.offset = 2*ctxt->arch->ptrsize;	// G.stackguard0
+		if(ctxt->cursym->cfunc)
+			p->to.offset = 3*ctxt->arch->ptrsize;	// G.stackguard1
+	} 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 = 2*ctxt->arch->ptrsize;	// G.stackguard0
+		if(ctxt->cursym->cfunc)
+			p->from.offset = 3*ctxt->arch->ptrsize;	// G.stackguard1
+		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;
+
+	p = appendp(ctxt, p);
+	p->as = ACALL;
+	p->to.type = D_BRANCH;
+	if(ctxt->cursym->cfunc)
+		p->to.sym = linklookup(ctxt, "runtime.morestackc", 0);
+	else
+		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 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;
+	int 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',
+	.endian = LittleEndian,
+
+	.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',
+	.endian = LittleEndian,
+
+	.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..f54153a
--- /dev/null
+++ b/src/liblink/obj8.c
@@ -0,0 +1,882 @@
+// 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 "../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, *p1, *p2;
+	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->plan9privates == nil)
+		ctxt->plan9privates = linklookup(ctxt, "_privates", 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) {
+		// if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
+		//
+		//	MOVL g_panic(CX), BX
+		//	TESTL BX, BX
+		//	JEQ end
+		//	LEAL (autoffset+4)(SP), DI
+		//	CMPL panic_argp(BX), DI
+		//	JNE end
+		//	MOVL SP, panic_argp(BX)
+		// end:
+		//	NOP
+		//
+		// The NOP is needed to give the jumps somewhere to land.
+		// It is a liblink NOP, not an x86 NOP: it encodes to 0 instruction bytes.
+
+		p = appendp(ctxt, p);
+		p->as = AMOVL;
+		p->from.type = D_INDIR+D_CX;
+		p->from.offset = 4*ctxt->arch->ptrsize; // G.panic
+		p->to.type = D_BX;
+
+		p = appendp(ctxt, p);
+		p->as = ATESTL;
+		p->from.type = D_BX;
+		p->to.type = D_BX;
+
+		p = appendp(ctxt, p);
+		p->as = AJEQ;
+		p->to.type = D_BRANCH;
+		p1 = p;
+
+		p = appendp(ctxt, p);
+		p->as = ALEAL;
+		p->from.type = D_INDIR+D_SP;
+		p->from.offset = autoffset+4;
+		p->to.type = D_DI;
+
+		p = appendp(ctxt, p);
+		p->as = ACMPL;
+		p->from.type = D_INDIR+D_BX;
+		p->from.offset = 0; // Panic.argp
+		p->to.type = D_DI;
+
+		p = appendp(ctxt, p);
+		p->as = AJNE;
+		p->to.type = D_BRANCH;
+		p2 = p;
+
+		p = appendp(ctxt, p);
+		p->as = AMOVL;
+		p->from.type = D_SP;
+		p->to.type = D_INDIR+D_BX;
+		p->to.offset = 0; // Panic.argp
+
+		p = appendp(ctxt, p);
+		p->as = ANOP;
+		p1->pcond = p;
+		p2->pcond = p;
+	}
+	
+	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(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;
+
+	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;
+		p->to.offset = 2*ctxt->arch->ptrsize;	// G.stackguard0
+		if(ctxt->cursym->cfunc)
+			p->to.offset = 3*ctxt->arch->ptrsize;	// G.stackguard1
+	} 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;
+		p->to.offset = 2*ctxt->arch->ptrsize;	// G.stackguard0
+		if(ctxt->cursym->cfunc)
+			p->to.offset = 3*ctxt->arch->ptrsize;	// G.stackguard1
+	} 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->from.offset = 2*ctxt->arch->ptrsize;	// G.stackguard0
+		if(ctxt->cursym->cfunc)
+			p->from.offset = 3*ctxt->arch->ptrsize;	// G.stackguard1
+		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);
+	p->as = ACALL;
+	p->to.type = D_BRANCH;
+	if(ctxt->cursym->cfunc)
+		p->to.sym = linklookup(ctxt, "runtime.morestackc", 0);
+	else
+		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;
+	int 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',
+	.endian = LittleEndian,
+
+	.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..b2478ec
--- /dev/null
+++ b/src/liblink/objfile.c
@@ -0,0 +1,790 @@
+// 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]
+//	- flags [int]
+//		1 dupok
+//	- 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]
+//	- flags [int]
+//		1 leaf
+//		2 C function
+//	- 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"
+#include "../runtime/funcdata.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, found;
+	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;
+				flag = ctxt->arch->textflag(p);
+				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;
+				flag = ctxt->arch->textflag(p);
+				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(p->as == ctxt->arch->AFUNCDATA) {
+				// Rewrite reference to go_args_stackmap(SB) to the Go-provided declaration information.
+				if(curtext == nil) // func _() {}
+					continue;
+				if(strcmp(p->to.sym->name, "go_args_stackmap") == 0) {
+					if(p->from.type != ctxt->arch->D_CONST || p->from.offset != FUNCDATA_ArgsPointerMaps)
+						ctxt->diag("FUNCDATA use of go_args_stackmap(SB) without FUNCDATA_ArgsPointerMaps");
+					p->to.sym = linklookup(ctxt, smprint("%s.args_stackmap", curtext->name), curtext->version);
+				}
+			}
+			
+			if(curtext == nil)
+				continue;
+			s = curtext;
+			s->etext->link = p;
+			s->etext = p;
+		}
+	}
+	
+	// Add reference to Go arguments for C or assembly functions without them.
+	for(s = text; s != nil; s = s->next) {
+		if(strncmp(s->name, "\"\".", 3) != 0)
+			continue;
+		found = 0;
+		for(p = s->text; p != nil; p = p->link) {
+			if(p->as == ctxt->arch->AFUNCDATA && p->from.type == ctxt->arch->D_CONST && p->from.offset == FUNCDATA_ArgsPointerMaps) {
+				found = 1;
+				break;
+			}
+		}
+		if(!found) {
+			p = appendp(ctxt, s->text);
+			p->as = ctxt->arch->AFUNCDATA;
+			p->from.type = ctxt->arch->D_CONST;
+			p->from.offset = FUNCDATA_ArgsPointerMaps;
+			if(ctxt->arch->thechar == '6' || ctxt->arch->thechar == '8')
+				p->to.type = ctxt->arch->D_EXTERN;
+			else {
+				p->to.type = ctxt->arch->D_OREG;
+				p->to.name = ctxt->arch->D_EXTERN;
+			}
+			p->to.sym = linklookup(ctxt, smprint("%s.args_stackmap", s->name), s->version);
+		}
+	}
+
+	// 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->cfunc)
+			Bprint(ctxt->bso, "cfunc ");
+		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 | s->cfunc<<1);
+		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, *typ;
+	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);
+	dupok &= 1;
+	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;
+	typ = rdsym(ctxt, f, pkg);
+	if(typ != nil) // if bss sym defined multiple times, take type from any one def
+		s->gotype = typ;
+	if(dup != nil && typ != nil)
+		dup->gotype = typ;
+	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);
+		v = rdint(f);
+		s->leaf = v&1;
+		s->cfunc = v&2;
+		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->cfunc)
+			Bprint(ctxt->bso, "cfunc ");
+		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..f0ee1dc
--- /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) == 0) 
+			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..bd85518
--- /dev/null
+++ b/src/liblink/sym.c
@@ -0,0 +1,268 @@
+// 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[] = {
+	{"android",	Hlinux},
+	{"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(arch);
+	
+	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:
+	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;
+		case '5':
+			ctxt->tlsoffset = 0;
+			break;
+		}
+		break;
+
+	case Hdarwin:
+		/*
+		 * OS X system constants - offset from 0(GS) to our TLS.
+		 * Explained in ../../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;
+
+	s = malloc(sizeof(*s));
+	memset(s, 0, sizeof(*s));
+
+	s->dynid = -1;
+	s->plt = -1;
+	s->got = -1;
+	s->name = estrdup(symb);
+	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/log/log.go b/src/log/log.go
index 4cfe550..d37e437 100644
--- a/src/log/log.go
+++ b/src/log/log.go
@@ -23,21 +23,15 @@ import (
 
 // These flags define which text to prefix to each log entry generated by the Logger.
 const (
-	// Bits or'ed together to control what's printed.
-	// There is no control over the order they appear (the order listed
-	// here) or the format they present (as described in the comments).
-	// The prefix is followed by a colon only when Llongfile or Lshortfile
-	// is specified.
-	// For example, flags Ldate | Ltime (or LstdFlags) produce,
-	//	2009/01/23 01:23:23 message
-	// while flags Ldate | Ltime | Lmicroseconds | Llongfile produce,
+	// Bits or'ed together to control what's printed. There is no control over the
+	// order they appear (the order listed here) or the format they present (as
+	// described in the comments).  A colon appears after these items:
 	//	2009/01/23 01:23:23.123123 /a/b/c/d.go:23: message
-	Ldate         = 1 << iota     // the date in the local time zone: 2009/01/23
-	Ltime                         // the time in the local time zone: 01:23:23
+	Ldate         = 1 << iota     // the date: 2009/01/23
+	Ltime                         // the time: 01:23:23
 	Lmicroseconds                 // microsecond resolution: 01:23:23.123123.  assumes Ltime.
 	Llongfile                     // full file name and line number: /a/b/c/d.go:23
 	Lshortfile                    // final file name element and line number: d.go:23. overrides Llongfile
-	LUTC                          // if Ldate or Ltime is set, use UTC rather than the local time zone
 	LstdFlags     = Ldate | Ltime // initial values for the standard logger
 )
 
@@ -61,37 +55,30 @@ func New(out io.Writer, prefix string, flag int) *Logger {
 	return &Logger{out: out, prefix: prefix, flag: flag}
 }
 
-// SetOutput sets the output destination for the logger.
-func (l *Logger) SetOutput(w io.Writer) {
-	l.mu.Lock()
-	defer l.mu.Unlock()
-	l.out = w
-}
-
 var std = New(os.Stderr, "", LstdFlags)
 
 // Cheap integer to fixed-width decimal ASCII.  Give a negative width to avoid zero-padding.
+// Knows the buffer has capacity.
 func itoa(buf *[]byte, i int, wid int) {
+	var u uint = uint(i)
+	if u == 0 && wid <= 1 {
+		*buf = append(*buf, '0')
+		return
+	}
+
 	// Assemble decimal in reverse order.
-	var b [20]byte
-	bp := len(b) - 1
-	for i >= 10 || wid > 1 {
-		wid--
-		q := i / 10
-		b[bp] = byte('0' + i - q*10)
+	var b [32]byte
+	bp := len(b)
+	for ; u > 0 || wid > 0; u /= 10 {
 		bp--
-		i = q
+		wid--
+		b[bp] = byte(u%10) + '0'
 	}
-	// i < 10
-	b[bp] = byte('0' + i)
 	*buf = append(*buf, b[bp:]...)
 }
 
 func (l *Logger) formatHeader(buf *[]byte, t time.Time, file string, line int) {
 	*buf = append(*buf, l.prefix...)
-	if l.flag&LUTC != 0 {
-		t = t.UTC()
-	}
 	if l.flag&(Ldate|Ltime|Lmicroseconds) != 0 {
 		if l.flag&Ldate != 0 {
 			year, month, day := t.Date()
@@ -160,7 +147,7 @@ func (l *Logger) Output(calldepth int, s string) error {
 	l.buf = l.buf[:0]
 	l.formatHeader(&l.buf, now, file, line)
 	l.buf = append(l.buf, s...)
-	if len(s) == 0 || s[len(s)-1] != '\n' {
+	if len(s) > 0 && s[len(s)-1] != '\n' {
 		l.buf = append(l.buf, '\n')
 	}
 	_, err := l.out.Write(l.buf)
@@ -333,14 +320,3 @@ func Panicln(v ...interface{}) {
 	std.Output(2, s)
 	panic(s)
 }
-
-// Output writes the output for a logging event.  The string s contains
-// the text to print after the prefix specified by the flags of the
-// Logger.  A newline is appended if the last character of s is not
-// already a newline.  Calldepth is the count of the number of
-// frames to skip when computing the file name and line number
-// if Llongfile or Lshortfile is set; a value of 1 will print the details
-// for the caller of Output.
-func Output(calldepth int, s string) error {
-	return std.Output(calldepth+1, s) // +1 for this frame.
-}
diff --git a/src/log/log_test.go b/src/log/log_test.go
index dd16c9d..158c3d9 100644
--- a/src/log/log_test.go
+++ b/src/log/log_test.go
@@ -8,19 +8,16 @@ package log
 
 import (
 	"bytes"
-	"fmt"
 	"os"
 	"regexp"
-	"strings"
 	"testing"
-	"time"
 )
 
 const (
 	Rdate         = `[0-9][0-9][0-9][0-9]/[0-9][0-9]/[0-9][0-9]`
 	Rtime         = `[0-9][0-9]:[0-9][0-9]:[0-9][0-9]`
 	Rmicroseconds = `\.[0-9][0-9][0-9][0-9][0-9][0-9]`
-	Rline         = `(57|59):` // must update if the calls to l.Printf / l.Print below move
+	Rline         = `(54|56):` // must update if the calls to l.Printf / l.Print below move
 	Rlongfile     = `.*/[A-Za-z0-9_\-]+\.go:` + Rline
 	Rshortfile    = `[A-Za-z0-9_\-]+\.go:` + Rline
 )
@@ -120,65 +117,3 @@ func TestFlagAndPrefixSetting(t *testing.T) {
 		t.Error("message did not match pattern")
 	}
 }
-
-func TestUTCFlag(t *testing.T) {
-	var b bytes.Buffer
-	l := New(&b, "Test:", LstdFlags)
-	l.SetFlags(Ldate | Ltime | LUTC)
-	// Verify a log message looks right in the right time zone. Quantize to the second only.
-	now := time.Now().UTC()
-	l.Print("hello")
-	want := fmt.Sprintf("Test:%d/%.2d/%.2d %.2d:%.2d:%.2d hello\n",
-		now.Year(), now.Month(), now.Day(), now.Hour(), now.Minute(), now.Second())
-	got := b.String()
-	if got == want {
-		return
-	}
-	// It's possible we crossed a second boundary between getting now and logging,
-	// so add a second and try again. This should very nearly always work.
-	now = now.Add(time.Second)
-	want = fmt.Sprintf("Test:%d/%.2d/%.2d %.2d:%.2d:%.2d hello\n",
-		now.Year(), now.Month(), now.Day(), now.Hour(), now.Minute(), now.Second())
-	if got == want {
-		return
-	}
-	t.Errorf("got %q; want %q", got, want)
-}
-
-func TestEmptyPrintCreatesLine(t *testing.T) {
-	var b bytes.Buffer
-	l := New(&b, "Header:", LstdFlags)
-	l.Print()
-	l.Println("non-empty")
-	output := b.String()
-	if n := strings.Count(output, "Header"); n != 2 {
-		t.Errorf("expected 2 headers, got %d", n)
-	}
-	if n := strings.Count(output, "\n"); n != 2 {
-		t.Errorf("expected 2 lines, got %d", n)
-	}
-}
-
-func BenchmarkItoa(b *testing.B) {
-	dst := make([]byte, 0, 64)
-	for i := 0; i < b.N; i++ {
-		dst = dst[0:0]
-		itoa(&dst, 2015, 4)   // year
-		itoa(&dst, 1, 2)      // month
-		itoa(&dst, 30, 2)     // day
-		itoa(&dst, 12, 2)     // hour
-		itoa(&dst, 56, 2)     // minute
-		itoa(&dst, 0, 2)      // second
-		itoa(&dst, 987654, 6) // microsecond
-	}
-}
-
-func BenchmarkPrintln(b *testing.B) {
-	const testString = "test"
-	var buf bytes.Buffer
-	l := New(&buf, "", LstdFlags)
-	for i := 0; i < b.N; i++ {
-		buf.Reset()
-		l.Println(testString)
-	}
-}
diff --git a/src/log/syslog/syslog.go b/src/log/syslog/syslog.go
index 4bf4476..5e09599 100644
--- a/src/log/syslog/syslog.go
+++ b/src/log/syslog/syslog.go
@@ -4,6 +4,13 @@
 
 // +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
+// domain sockets, UDP or TCP.
+//
+// Only one call to Dial is necessary. On write failures,
+// the syslog client will attempt to reconnect to the server
+// and write again.
 package syslog
 
 import (
diff --git a/src/log/syslog/syslog_plan9.go b/src/log/syslog/syslog_plan9.go
new file mode 100644
index 0000000..0c05f6f
--- /dev/null
+++ b/src/log/syslog/syslog_plan9.go
@@ -0,0 +1,8 @@
+// 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 syslog provides a simple interface to the system log service.
+package syslog
+
+// BUG(akumar): This package is not implemented on Plan 9 yet.
diff --git a/src/log/syslog/syslog_test.go b/src/log/syslog/syslog_test.go
index 85aec53..6a863fe 100644
--- a/src/log/syslog/syslog_test.go
+++ b/src/log/syslog/syslog_test.go
@@ -14,7 +14,6 @@ import (
 	"log"
 	"net"
 	"os"
-	"runtime"
 	"sync"
 	"testing"
 	"time"
@@ -121,13 +120,6 @@ func TestWithSimulated(t *testing.T) {
 	msg := "Test 123"
 	transport := []string{"unix", "unixgram", "udp", "tcp"}
 
-	if runtime.GOOS == "darwin" {
-		switch runtime.GOARCH {
-		case "arm", "arm64":
-			transport = []string{"udp", "tcp"}
-		}
-	}
-
 	for _, tr := range transport {
 		done := make(chan string)
 		addr, sock, srvWG := startServer(tr, "", done)
@@ -150,13 +142,6 @@ func TestWithSimulated(t *testing.T) {
 }
 
 func TestFlap(t *testing.T) {
-	if runtime.GOOS == "darwin" {
-		switch runtime.GOARCH {
-		case "arm", "arm64":
-			t.Skipf("skipping on %s/%s", runtime.GOOS, runtime.GOARCH)
-		}
-	}
-
 	net := "unix"
 	done := make(chan string)
 	addr, sock, srvWG := startServer(net, "", done)
@@ -321,17 +306,9 @@ func TestConcurrentReconnect(t *testing.T) {
 	const N = 10
 	const M = 100
 	net := "unix"
-	if runtime.GOOS == "darwin" {
-		switch runtime.GOARCH {
-		case "arm", "arm64":
-			net = "tcp"
-		}
-	}
 	done := make(chan string, N*M)
 	addr, sock, srvWG := startServer(net, "", done)
-	if net == "unix" {
-		defer os.Remove(addr)
-	}
+	defer os.Remove(addr)
 
 	// count all the messages arriving
 	count := make(chan int)
diff --git a/src/log/syslog/syslog_windows.go b/src/log/syslog/syslog_windows.go
new file mode 100644
index 0000000..8d99e2e
--- /dev/null
+++ b/src/log/syslog/syslog_windows.go
@@ -0,0 +1,8 @@
+// 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 syslog provides a simple interface to the system log service.
+package syslog
+
+// BUG(brainman): This package is not implemented on Windows yet.
diff --git a/src/make.bash b/src/make.bash
index f17648a..fbc6f5d 100755
--- a/src/make.bash
+++ b/src/make.bash
@@ -3,8 +3,6 @@
 # Use of this source code is governed by a BSD-style
 # license that can be found in the LICENSE file.
 
-# See golang.org/s/go15bootstrap for an overview of the build process.
-
 # Environment variables that control make.bash:
 #
 # GOROOT_FINAL: The expected final Go root, baked into binaries.
@@ -19,12 +17,15 @@
 #
 # GOOS: The target operating system for installed packages and tools.
 #
-# GO_GCFLAGS: Additional go tool compile arguments to use when
+# GO_GCFLAGS: Additional 5g/6g/8g arguments to use when
 # building the packages and commands.
 #
-# GO_LDFLAGS: Additional go tool link arguments to use when
+# GO_LDFLAGS: Additional 5l/6l/8l arguments to use when
 # building the commands.
 #
+# GO_CCFLAGS: Additional 5c/6c/8c arguments to use when
+# building.
+#
 # CGO_ENABLED: Controls cgo usage during the build. Set it to 1
 # to include all cgo related files, .c and .go file with "cgo"
 # build directive, in the build. Set it to 0 to ignore them.
@@ -109,16 +110,26 @@ rm -f ./runtime/runtime_defs.go
 
 # Finally!  Run the build.
 
-echo '##### Building Go bootstrap tool.'
+echo '# Building C bootstrap tool.'
 echo cmd/dist
 export GOROOT="$(cd .. && pwd)"
-GOROOT_BOOTSTRAP=${GOROOT_BOOTSTRAP:-$HOME/go1.4}
-if [ ! -x "$GOROOT_BOOTSTRAP/bin/go" ]; then
-	echo "ERROR: Cannot find $GOROOT_BOOTSTRAP/bin/go." >&2
-	echo "Set \$GOROOT_BOOTSTRAP to a working Go tree >= Go 1.4." >&2
+GOROOT_FINAL="${GOROOT_FINAL:-$GOROOT}"
+DEFGOROOT='-DGOROOT_FINAL="'"$GOROOT_FINAL"'"'
+
+mflag=""
+case "$GOHOSTARCH" in
+386) mflag=-m32;;
+amd64) mflag=-m64;;
+esac
+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
-rm -f cmd/dist/dist
-GOROOT="$GOROOT_BOOTSTRAP" GOOS="" GOARCH="" "$GOROOT_BOOTSTRAP/bin/go" build -o cmd/dist/dist ./cmd/dist
+${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.
 eval $(./cmd/dist/dist env -p || echo FAIL=true)
@@ -138,6 +149,7 @@ if [ "$1" = "--dist-tool" ]; then
 	exit 0
 fi
 
+echo "# Building compilers and Go bootstrap tool for host, $GOHOSTOS/$GOHOSTARCH."
 buildall="-a"
 if [ "$1" = "--no-clean" ]; then
 	buildall=""
@@ -146,19 +158,20 @@ 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.
 mv cmd/dist/dist "$GOTOOLDIR"/dist
+"$GOTOOLDIR"/go_bootstrap clean -i std
 echo
 
 if [ "$GOHOSTARCH" != "$GOARCH" -o "$GOHOSTOS" != "$GOOS" ]; then
-	echo "##### Building packages and commands for host, $GOHOSTOS/$GOHOSTARCH."
+	echo "# Building packages and commands for host, $GOHOSTOS/$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 -gcflags "$GO_GCFLAGS" -ldflags "$GO_LDFLAGS" -v std cmd
+		"$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."
-CC=$CC_FOR_TARGET "$GOTOOLDIR"/go_bootstrap install $GO_FLAGS -gcflags "$GO_GCFLAGS" -ldflags "$GO_LDFLAGS" -v std cmd
+echo "# Building packages and commands for $GOOS/$GOARCH."
+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.bat b/src/make.bat
index 0efdcc5..fff1eb6 100644
--- a/src/make.bat
+++ b/src/make.bat
@@ -16,21 +16,15 @@
 ::
 :: GOOS: The target operating system for installed packages and tools.
 ::
-:: GO_GCFLAGS: Additional go tool compile arguments to use when
+:: GO_GCFLAGS: Additional 5g/6g/8g arguments to use when
 :: building the packages and commands.
 ::
-:: GO_LDFLAGS: Additional go tool link arguments to use when
+:: GO_LDFLAGS: Additional 5l/6l/8l arguments to use when
 :: building the commands.
 ::
 :: CGO_ENABLED: Controls cgo usage during the build. Set it to 1
 :: to include all cgo related files, .c and .go file with "cgo"
 :: build directive, in the build. Set it to 0 to ignore them.
-::
-:: CC: Command line to run to compile C code for GOHOSTARCH.
-:: Default is "gcc".
-::
-:: CC_FOR_TARGET: Command line to run compile C code for GOARCH.
-:: This is used by cgo. Default is CC.
 
 @echo off
 
@@ -51,24 +45,24 @@ goto fail
 :: Clean old generated file that will cause problems in the build.
 del /F ".\pkg\runtime\runtime_defs.go" 2>NUL
 
-:: Set GOROOT for build.
+:: Grab default GOROOT_FINAL and set GOROOT for build.
+:: The expression %VAR:\=\\% means to take %VAR%
+:: and apply the substitution \ = \\, escaping the
+:: backslashes.  Then we wrap that in quotes to create
+:: a C string.
 cd ..
 set GOROOT=%CD%
 cd src
+if "x%GOROOT_FINAL%"=="x" set GOROOT_FINAL=%GOROOT%
+set DEFGOROOT=-DGOROOT_FINAL="\"%GOROOT_FINAL:\=\\%\""
 
-echo ##### Building Go bootstrap tool.
+echo # Building C bootstrap tool.
 echo cmd/dist
 if not exist ..\bin\tool mkdir ..\bin\tool
-if "x%GOROOT_BOOTSTRAP%"=="x" set GOROOT_BOOTSTRAP=%HOMEDRIVE%%HOMEPATH%\Go1.4
-if not exist "%GOROOT_BOOTSTRAP%\bin\go.exe" goto bootstrapfail
-setlocal
-set GOROOT=%GOROOT_BOOTSTRAP%
-set GOOS=
-set GOARCH=
-"%GOROOT_BOOTSTRAP%\bin\go" build -o cmd\dist\dist.exe .\cmd\dist
-endlocal
+:: Windows has no glob expansion, so spell out cmd/dist/*.c.
+gcc -O2 -Wall -Werror -o cmd/dist/dist.exe -Icmd/dist %DEFGOROOT% cmd/dist/buf.c cmd/dist/build.c cmd/dist/buildgc.c cmd/dist/buildgo.c cmd/dist/buildruntime.c cmd/dist/main.c cmd/dist/windows.c cmd/dist/arm.c
 if errorlevel 1 goto fail
-.\cmd\dist\dist env -w -p >env.bat
+.\cmd\dist\dist env -wp >env.bat
 if errorlevel 1 goto fail
 call env.bat
 del env.bat
@@ -77,12 +71,14 @@ echo.
 if x%1==x--dist-tool goto copydist
 if x%2==x--dist-tool goto copydist
 
+echo # Building compilers and Go bootstrap tool.
 set buildall=-a
 if x%1==x--no-clean set buildall=
 .\cmd\dist\dist bootstrap %buildall% -v
 if errorlevel 1 goto fail
 :: Delay move of dist tool to now, because bootstrap cleared tool directory.
 move .\cmd\dist\dist.exe "%GOTOOLDIR%\dist.exe"
+"%GOTOOLDIR%\go_bootstrap" clean -i std
 echo.
 
 if not %GOHOSTARCH% == %GOARCH% goto localbuild
@@ -90,23 +86,18 @@ if not %GOHOSTOS% == %GOOS% goto localbuild
 goto mainbuild
 
 :localbuild
-echo ##### Building packages and commands for host, %GOHOSTOS%/%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.
+echo # Building tools for local system. %GOHOSTOS%/%GOHOSTARCH%
 setlocal
 set GOOS=%GOHOSTOS%
 set GOARCH=%GOHOSTARCH%
-"%GOTOOLDIR%\go_bootstrap" install -gcflags "%GO_GCFLAGS%" -ldflags "%GO_LDFLAGS%" -v std cmd
+"%GOTOOLDIR%\go_bootstrap" install -gcflags "%GO_GCFLAGS%" -ldflags "%GO_LDFLAGS%" -v std
 endlocal
 if errorlevel 1 goto fail
 echo.
 
 :mainbuild
-echo ##### Building packages and commands for %GOOS%/%GOARCH%.
-setlocal
-set CC=%CC_FOR_TARGET%
-"%GOTOOLDIR%\go_bootstrap" install -gcflags "%GO_GCFLAGS%" -ldflags "%GO_LDFLAGS%" -a -v std cmd
-endlocal
+echo # Building packages and commands.
+"%GOTOOLDIR%\go_bootstrap" install -gcflags "%GO_GCFLAGS%" -ldflags "%GO_LDFLAGS%" -a -v std
 if errorlevel 1 goto fail
 del "%GOTOOLDIR%\go_bootstrap.exe"
 echo.
@@ -122,10 +113,6 @@ mkdir "%GOTOOLDIR%" 2>NUL
 copy cmd\dist\dist.exe "%GOTOOLDIR%\"
 goto end
 
-:bootstrapfail
-echo ERROR: Cannot find %GOROOT_BOOTSTRAP%\bin\go.exe
-echo "Set GOROOT_BOOTSTRAP to a working Go tree >= Go 1.4."
-
 :fail
 set GOBUILDFAIL=1
 if x%GOBUILDEXIT%==x1 exit %GOBUILDFAIL%
diff --git a/src/make.rc b/src/make.rc
index 6016204..7a62d6a 100755
--- a/src/make.rc
+++ b/src/make.rc
@@ -3,8 +3,6 @@
 # Use of this source code is governed by a BSD-style
 # license that can be found in the LICENSE file.
 
-# See golang.org/s/go15bootstrap for an overview of the build process.
-
 # Environment variables that control make.rc:
 #
 # GOROOT_FINAL: The expected final Go root, baked into binaries.
@@ -19,12 +17,15 @@
 #
 # GOOS: The target operating system for installed packages and tools.
 #
-# GO_GCFLAGS: Additional go tool compile arguments to use when
+# GO_GCFLAGS: Additional 5g/6g/8g arguments to use when
 # building the packages and commands.
 #
-# GO_LDFLAGS: Additional go tool link arguments to use when
+# GO_LDFLAGS: Additional 5l/6l/8l arguments to use when
 # building the commands.
 #
+# GO_CCFLAGS: Additional 5c/6c/8c arguments to use when
+# building.
+#
 # CGO_ENABLED: Controls cgo usage during the build. Set it to 1
 # to include all cgo related files, .c and .go file with "cgo"
 # build directive, in the build. Set it to 0 to ignore them.
@@ -35,24 +36,26 @@ 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 ./runtime/runtime_defs.go
 
 # Determine the host compiler toolchain.
 eval `{grep '^(CC|LD|O)=' /$objtype/mkfile}
 
-echo '##### Building Go bootstrap tool.'
+echo '# Building C bootstrap tool.'
 echo cmd/dist
 GOROOT = `{cd .. && pwd}
-if(! ~ $#GOROOT_BOOTSTRAP 1)
-	GOROOT_BOOTSTRAP = $home/go1.4
-if(! test -x $GOROOT_BOOTSTRAP/bin/go){
-	echo 'ERROR: Cannot find '$GOROOT_BOOTSTRAP'/bin/go.' >[1=2]
-	echo 'Set $GOROOT_BOOTSTRAP to a working Go tree >= Go 1.4.' >[1=2]
-	exit bootstrap
-}
-rm -f cmd/dist/dist
-GOROOT=$GOROOT_BOOTSTRAP GOOS='' GOARCH='' $GOROOT_BOOTSTRAP/bin/go build -o cmd/dist/dist ./cmd/dist
+if(! ~ $#GOROOT_FINAL 1)
+	GOROOT_FINAL = $GOROOT
+DEFGOROOT='-DGOROOT_FINAL="'$GOROOT_FINAL'"'
+
+for(i in cmd/dist/*.c)
+	$CC -FTVwp+ -DPLAN9 $DEFGOROOT $i
+$LD -o cmd/dist/dist *.$O
+rm *.$O
 
 eval `{./cmd/dist/dist env -9}
 echo
@@ -66,12 +69,14 @@ if(~ $1 --dist-tool){
 	exit
 }
 
+echo '# Building compilers and Go bootstrap tool for host,' $GOHOSTOS/$GOHOSTARCH^.
 buildall = -a
 if(~ $1 --no-clean)
 	buildall = ()
 ./cmd/dist/dist bootstrap $buildall -v # builds go_bootstrap
 # Delay move of dist tool to now, because bootstrap may clear tool directory.
 mv cmd/dist/dist $GOTOOLDIR/dist
+$GOTOOLDIR/go_bootstrap clean -i std
 echo
 
 # Run only one process at a time on 9vx.
@@ -79,14 +84,14 @@ if(~ $sysname vx32)
 	pflag = (-p 1)
 
 if(! ~ $GOHOSTARCH $GOARCH || ! ~ $GOHOSTOS $GOOS){
-	echo '##### Building packages and commands for host,' $GOHOSTOS/$GOHOSTARCH^.
+	echo '# Building packages and commands for host,' $GOHOSTOS/$GOHOSTARCH^.
 	GOOS=$GOHOSTOS GOARCH=$GOHOSTARCH \
-		$GOTOOLDIR/go_bootstrap install -gcflags $"GO_GCFLAGS -ldflags $"GO_LDFLAGS -v $pflag std cmd
+		$GOTOOLDIR/go_bootstrap install -ccflags $"GO_CCFLAGS -gcflags $"GO_GCFLAGS -ldflags $"GO_LDFLAGS -v $pflag std
 	echo
 }
 
-echo '##### Building packages and commands for' $GOOS/$GOARCH^.
-$GOTOOLDIR/go_bootstrap install -gcflags $"GO_GCFLAGS -ldflags $"GO_LDFLAGS -v $pflag std cmd
+echo '# Building packages and commands for' $GOOS/$GOARCH^.
+$GOTOOLDIR/go_bootstrap install -ccflags $"GO_CCFLAGS -gcflags $"GO_GCFLAGS -ldflags $"GO_LDFLAGS -v $pflag std
 echo
 
 rm -f $GOTOOLDIR/go_bootstrap
diff --git a/src/math/all_test.go b/src/math/all_test.go
index e18e45e..763efb2 100644
--- a/src/math/all_test.go
+++ b/src/math/all_test.go
@@ -946,20 +946,16 @@ var expSC = []float64{
 
 var vfexpm1SC = []float64{
 	Inf(-1),
-	-710,
 	Copysign(0, -1),
 	0,
-	710,
 	Inf(1),
 	NaN(),
 }
 var expm1SC = []float64{
 	-1,
-	-1,
 	Copysign(0, -1),
 	0,
 	Inf(1),
-	Inf(1),
 	NaN(),
 }
 
@@ -995,24 +991,6 @@ var vffdimSC = [][2]float64{
 	{NaN(), Inf(1)},
 	{NaN(), NaN()},
 }
-var nan = Float64frombits(0xFFF8000000000000) // SSE2 DIVSD 0/0
-var vffdim2SC = [][2]float64{
-	{Inf(-1), Inf(-1)},
-	{Inf(-1), Inf(1)},
-	{Inf(-1), nan},
-	{Copysign(0, -1), Copysign(0, -1)},
-	{Copysign(0, -1), 0},
-	{0, Copysign(0, -1)},
-	{0, 0},
-	{Inf(1), Inf(-1)},
-	{Inf(1), Inf(1)},
-	{Inf(1), nan},
-	{nan, Inf(-1)},
-	{nan, Copysign(0, -1)},
-	{nan, 0},
-	{nan, Inf(1)},
-	{nan, nan},
-}
 var fdimSC = []float64{
 	NaN(),
 	0,
@@ -1730,10 +1708,8 @@ func tolerance(a, b, e float64) bool {
 		d = -d
 	}
 
-	// note: b is correct (expected) value, a is actual value.
-	// make error tolerance a fraction of b, not a.
-	if b != 0 {
-		e = e * b
+	if a != 0 {
+		e = e * a
 		if e < 0 {
 			e = -e
 		}
@@ -2039,11 +2015,6 @@ func TestDim(t *testing.T) {
 			t.Errorf("Dim(%g, %g) = %g, want %g", vffdimSC[i][0], vffdimSC[i][1], f, fdimSC[i])
 		}
 	}
-	for i := 0; i < len(vffdim2SC); i++ {
-		if f := Dim(vffdim2SC[i][0], vffdim2SC[i][1]); !alike(fdimSC[i], f) {
-			t.Errorf("Dim(%g, %g) = %g, want %g", vffdim2SC[i][0], vffdim2SC[i][1], f, fdimSC[i])
-		}
-	}
 }
 
 func TestFloor(t *testing.T) {
@@ -2070,11 +2041,6 @@ func TestMax(t *testing.T) {
 			t.Errorf("Max(%g, %g) = %g, want %g", vffdimSC[i][0], vffdimSC[i][1], f, fmaxSC[i])
 		}
 	}
-	for i := 0; i < len(vffdim2SC); i++ {
-		if f := Max(vffdim2SC[i][0], vffdim2SC[i][1]); !alike(fmaxSC[i], f) {
-			t.Errorf("Max(%g, %g) = %g, want %g", vffdim2SC[i][0], vffdim2SC[i][1], f, fmaxSC[i])
-		}
-	}
 }
 
 func TestMin(t *testing.T) {
@@ -2088,11 +2054,6 @@ func TestMin(t *testing.T) {
 			t.Errorf("Min(%g, %g) = %g, want %g", vffdimSC[i][0], vffdimSC[i][1], f, fminSC[i])
 		}
 	}
-	for i := 0; i < len(vffdim2SC); i++ {
-		if f := Min(vffdim2SC[i][0], vffdim2SC[i][1]); !alike(fminSC[i], f) {
-			t.Errorf("Min(%g, %g) = %g, want %g", vffdim2SC[i][0], vffdim2SC[i][1], f, fminSC[i])
-		}
-	}
 }
 
 func TestMod(t *testing.T) {
@@ -2645,7 +2606,7 @@ func TestLargeTan(t *testing.T) {
 
 // Check that math constants are accepted by compiler
 // and have right value (assumes strconv.ParseFloat works).
-// https://golang.org/issue/201
+// http://code.google.com/p/go/issues/detail?id=201
 
 type floatTest struct {
 	val  interface{}
@@ -2983,56 +2944,15 @@ func BenchmarkSinh(b *testing.B) {
 	}
 }
 
-var Global float64
-
 func BenchmarkSqrt(b *testing.B) {
-	x, y := 0.0, 10.0
-	for i := 0; i < b.N; i++ {
-		x += Sqrt(y)
-	}
-	Global = x
-}
-
-func BenchmarkSqrtIndirect(b *testing.B) {
-	x, y := 0.0, 10.0
-	f := Sqrt
 	for i := 0; i < b.N; i++ {
-		x += f(y)
+		Sqrt(10)
 	}
-	Global = x
 }
 
 func BenchmarkSqrtGo(b *testing.B) {
-	x, y := 0.0, 10.0
-	for i := 0; i < b.N; i++ {
-		x += SqrtGo(y)
-	}
-	Global = x
-}
-
-func isPrime(i int) bool {
-	// Yes, this is a dumb way to write this code,
-	// but calling Sqrt repeatedly in this way demonstrates
-	// the benefit of using a direct SQRT instruction on systems
-	// that have one, whereas the obvious loop seems not to
-	// demonstrate such a benefit.
-	for j := 2; float64(j) <= Sqrt(float64(i)); j++ {
-		if i%j == 0 {
-			return false
-		}
-	}
-	return true
-}
-
-func BenchmarkSqrtPrime(b *testing.B) {
-	any := false
 	for i := 0; i < b.N; i++ {
-		if isPrime(100003) {
-			any = true
-		}
-	}
-	if any {
-		Global = 1
+		SqrtGo(10)
 	}
 }
 
diff --git a/src/math/big/arith.go b/src/math/big/arith.go
index d7ea838..3d5a868 100644
--- a/src/math/big/arith.go
+++ b/src/math/big/arith.go
@@ -70,7 +70,7 @@ func mulWW_g(x, y Word) (z1, z0 Word) {
 
 // z1<<_W + z0 = x*y + c
 func mulAddWWW_g(x, y, c Word) (z1, z0 Word) {
-	z1, zz0 := mulWW_g(x, y)
+	z1, zz0 := mulWW(x, y)
 	if z0 = zz0 + c; z0 < zz0 {
 		z1++
 	}
@@ -107,26 +107,11 @@ func log2(x Word) int {
 	return bitLen(x) - 1
 }
 
-// nlz returns the number of leading zeros in x.
-func nlz(x Word) uint {
+// Number of leading zeros in x.
+func leadingZeros(x Word) uint {
 	return uint(_W - bitLen(x))
 }
 
-// nlz64 returns the number of leading zeros in x.
-func nlz64(x uint64) uint {
-	switch _W {
-	case 32:
-		w := x >> 32
-		if w == 0 {
-			return 32 + nlz(Word(x))
-		}
-		return nlz(Word(w))
-	case 64:
-		return nlz(Word(x))
-	}
-	panic("unreachable")
-}
-
 // q = (u1<<_W + u0 - r)/y
 // Adapted from Warren, Hacker's Delight, p. 152.
 func divWW_g(u1, u0, v Word) (q, r Word) {
@@ -134,7 +119,7 @@ func divWW_g(u1, u0, v Word) (q, r Word) {
 		return 1<<_W - 1, 1<<_W - 1
 	}
 
-	s := nlz(v)
+	s := leadingZeros(v)
 	v <<= s
 
 	vn1 := v >> _W2
@@ -169,81 +154,32 @@ func divWW_g(u1, u0, v Word) (q, r Word) {
 	return q1*_B2 + q0, (un21*_B2 + un0 - q0*v) >> s
 }
 
-// Keep for performance debugging.
-// Using addWW_g is likely slower.
-const use_addWW_g = false
-
-// The resulting carry c is either 0 or 1.
 func addVV_g(z, x, y []Word) (c Word) {
-	if use_addWW_g {
-		for i := range z {
-			c, z[i] = addWW_g(x[i], y[i], c)
-		}
-		return
-	}
-
-	for i, xi := range x[:len(z)] {
-		yi := y[i]
-		zi := xi + yi + c
-		z[i] = zi
-		// see "Hacker's Delight", section 2-12 (overflow detection)
-		c = (xi&yi | (xi|yi)&^zi) >> (_W - 1)
+	for i := range z {
+		c, z[i] = addWW_g(x[i], y[i], c)
 	}
 	return
 }
 
-// The resulting carry c is either 0 or 1.
 func subVV_g(z, x, y []Word) (c Word) {
-	if use_addWW_g {
-		for i := range z {
-			c, z[i] = subWW_g(x[i], y[i], c)
-		}
-		return
-	}
-
-	for i, xi := range x[:len(z)] {
-		yi := y[i]
-		zi := xi - yi - c
-		z[i] = zi
-		// see "Hacker's Delight", section 2-12 (overflow detection)
-		c = (yi&^xi | (yi|^xi)&zi) >> (_W - 1)
+	for i := range z {
+		c, z[i] = subWW_g(x[i], y[i], c)
 	}
 	return
 }
 
-// The resulting carry c is either 0 or 1.
 func addVW_g(z, x []Word, y Word) (c Word) {
-	if use_addWW_g {
-		c = y
-		for i := range z {
-			c, z[i] = addWW_g(x[i], c, 0)
-		}
-		return
-	}
-
 	c = y
-	for i, xi := range x[:len(z)] {
-		zi := xi + c
-		z[i] = zi
-		c = xi &^ zi >> (_W - 1)
+	for i := range z {
+		c, z[i] = addWW_g(x[i], c, 0)
 	}
 	return
 }
 
 func subVW_g(z, x []Word, y Word) (c Word) {
-	if use_addWW_g {
-		c = y
-		for i := range z {
-			c, z[i] = subWW_g(x[i], c, 0)
-		}
-		return
-	}
-
 	c = y
-	for i, xi := range x[:len(z)] {
-		zi := xi - c
-		z[i] = zi
-		c = (zi &^ xi) >> (_W - 1)
+	for i := range z {
+		c, z[i] = subWW_g(x[i], c, 0)
 	}
 	return
 }
@@ -286,7 +222,6 @@ func mulAddVWW_g(z, x []Word, y, r Word) (c Word) {
 	return
 }
 
-// TODO(gri) Remove use of addWW_g here and then we can remove addWW_g and subWW_g.
 func addMulVVW_g(z, x []Word, y Word) (c Word) {
 	for i := range z {
 		z1, z0 := mulAddWWW_g(x[i], y, z[i])
diff --git a/src/math/big/arith_386.s b/src/math/big/arith_386.s
index 7c8ab8f..1b47c89 100644
--- a/src/math/big/arith_386.s
+++ b/src/math/big/arith_386.s
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build !math_big_pure_go
-
 #include "textflag.h"
 
 // This file provides fast assembly versions for the elementary
@@ -39,16 +37,15 @@ TEXT ·addVV(SB),NOSPLIT,$0
 	JMP E1
 
 L1:	MOVL (SI)(BX*4), AX
-	ADDL DX, DX		// restore CF
+	RCRL $1, DX
 	ADCL (CX)(BX*4), AX
-	SBBL DX, DX		// save CF
+	RCLL $1, DX
 	MOVL AX, (DI)(BX*4)
 	ADDL $1, BX		// i++
 
 E1:	CMPL BX, BP		// i < n
 	JL L1
 
-	NEGL DX
 	MOVL DX, c+36(FP)
 	RET
 
@@ -65,16 +62,15 @@ TEXT ·subVV(SB),NOSPLIT,$0
 	JMP E2
 
 L2:	MOVL (SI)(BX*4), AX
-	ADDL DX, DX		// restore CF
+	RCRL $1, DX
 	SBBL (CX)(BX*4), AX
-	SBBL DX, DX		// save CF
+	RCLL $1, DX
 	MOVL AX, (DI)(BX*4)
 	ADDL $1, BX		// i++
 
 E2:	CMPL BX, BP		// i < n
 	JL L2
 
-	NEGL DX
 	MOVL DX, c+36(FP)
 	RET
 
@@ -90,8 +86,8 @@ TEXT ·addVW(SB),NOSPLIT,$0
 
 L3:	ADDL (SI)(BX*4), AX
 	MOVL AX, (DI)(BX*4)
-	SBBL AX, AX		// save CF
-	NEGL AX
+	RCLL $1, AX
+	ANDL $1, AX
 	ADDL $1, BX		// i++
 
 E3:	CMPL BX, BP		// i < n
@@ -110,11 +106,11 @@ TEXT ·subVW(SB),NOSPLIT,$0
 	MOVL $0, BX		// i = 0
 	JMP E4
 
-L4:	MOVL (SI)(BX*4), DX
+L4:	MOVL (SI)(BX*4), DX	// TODO(gri) is there a reverse SUBL?
 	SUBL AX, DX
 	MOVL DX, (DI)(BX*4)
-	SBBL AX, AX		// save CF
-	NEGL AX
+	RCLL $1, AX
+	ANDL $1, AX
 	ADDL $1, BX		// i++
 
 E4:	CMPL BX, BP		// i < n
diff --git a/src/math/big/arith_amd64.s b/src/math/big/arith_amd64.s
index b69a2c6..56c4cb0 100644
--- a/src/math/big/arith_amd64.s
+++ b/src/math/big/arith_amd64.s
@@ -2,13 +2,21 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build !math_big_pure_go
-
 #include "textflag.h"
 
 // This file provides fast assembly versions for the elementary
 // arithmetic operations on vectors implemented in arith.go.
 
+// Literal instruction for MOVQ $0, CX.
+// (MOVQ $0, reg is translated to XORQ reg, reg and clears CF.)
+#define ZERO_CX BYTE $0x48; \
+		BYTE $0xc7; \
+		BYTE $0xc1; \
+		BYTE $0x00; \
+		BYTE $0x00; \
+		BYTE $0x00; \
+		BYTE $0x00
+
 // func mulWW(x, y Word) (z1, z0 Word)
 TEXT ·mulWW(SB),NOSPLIT,$0
 	MOVQ x+0(FP), AX
@@ -27,11 +35,6 @@ TEXT ·divWW(SB),NOSPLIT,$0
 	MOVQ DX, r+32(FP)
 	RET
 
-// The carry bit is saved with SBBQ Rx, Rx: if the carry was set, Rx is -1, otherwise it is 0.
-// It is restored with ADDQ Rx, Rx: if Rx was -1 the carry is set, otherwise it is cleared.
-// This is faster than using rotate instructions.
-//
-// CAUTION: Note that MOVQ $0, Rx is translated to XORQ Rx, Rx which clears the carry bit!
 
 // func addVV(z, x, y []Word) (c Word)
 TEXT ·addVV(SB),NOSPLIT,$0
@@ -49,7 +52,7 @@ TEXT ·addVV(SB),NOSPLIT,$0
 
 U1:	// n >= 0
 	// regular loop body unrolled 4x
-	ADDQ CX, CX		// restore CF
+	RCRQ $1, CX		// CF = c
 	MOVQ 0(R8)(SI*8), R11
 	MOVQ 8(R8)(SI*8), R12
 	MOVQ 16(R8)(SI*8), R13
@@ -62,7 +65,7 @@ U1:	// n >= 0
 	MOVQ R12, 8(R10)(SI*8)
 	MOVQ R13, 16(R10)(SI*8)
 	MOVQ R14, 24(R10)(SI*8)
-	SBBQ CX, CX		// save CF
+	RCLQ $1, CX		// c = CF
 
 	ADDQ $4, SI		// i += 4
 	SUBQ $4, DI		// n -= 4
@@ -72,18 +75,17 @@ V1:	ADDQ $4, DI		// n += 4
 	JLE E1			// if n <= 0 goto E1
 
 L1:	// n > 0
-	ADDQ CX, CX		// restore CF
+	RCRQ $1, CX		// CF = c
 	MOVQ 0(R8)(SI*8), R11
 	ADCQ 0(R9)(SI*8), R11
 	MOVQ R11, 0(R10)(SI*8)
-	SBBQ CX, CX		// save CF
+	RCLQ $1, CX		// c = CF
 
 	ADDQ $1, SI		// i++
 	SUBQ $1, DI		// n--
 	JG L1			// if n > 0 goto L1
 
-E1:	NEGQ CX
-	MOVQ CX, c+72(FP)	// return c
+E1:	MOVQ CX, c+72(FP)	// return c
 	RET
 
 
@@ -104,7 +106,7 @@ TEXT ·subVV(SB),NOSPLIT,$0
 
 U2:	// n >= 0
 	// regular loop body unrolled 4x
-	ADDQ CX, CX		// restore CF
+	RCRQ $1, CX		// CF = c
 	MOVQ 0(R8)(SI*8), R11
 	MOVQ 8(R8)(SI*8), R12
 	MOVQ 16(R8)(SI*8), R13
@@ -117,7 +119,7 @@ U2:	// n >= 0
 	MOVQ R12, 8(R10)(SI*8)
 	MOVQ R13, 16(R10)(SI*8)
 	MOVQ R14, 24(R10)(SI*8)
-	SBBQ CX, CX		// save CF
+	RCLQ $1, CX		// c = CF
 
 	ADDQ $4, SI		// i += 4
 	SUBQ $4, DI		// n -= 4
@@ -127,18 +129,17 @@ V2:	ADDQ $4, DI		// n += 4
 	JLE E2			// if n <= 0 goto E2
 
 L2:	// n > 0
-	ADDQ CX, CX		// restore CF
+	RCRQ $1, CX		// CF = c
 	MOVQ 0(R8)(SI*8), R11
 	SBBQ 0(R9)(SI*8), R11
 	MOVQ R11, 0(R10)(SI*8)
-	SBBQ CX, CX		// save CF
+	RCLQ $1, CX		// c = CF
 
 	ADDQ $1, SI		// i++
 	SUBQ $1, DI		// n--
 	JG L2			// if n > 0 goto L2
 
-E2:	NEGQ CX
-	MOVQ CX, c+72(FP)	// return c
+E2:	MOVQ CX, c+72(FP)	// return c
 	RET
 
 
@@ -162,11 +163,11 @@ U3:	// n >= 0
 	MOVQ 16(R8)(SI*8), R13
 	MOVQ 24(R8)(SI*8), R14
 	ADDQ CX, R11
+	ZERO_CX
 	ADCQ $0, R12
 	ADCQ $0, R13
 	ADCQ $0, R14
-	SBBQ CX, CX		// save CF
-	NEGQ CX
+	SETCS CX		// c = CF
 	MOVQ R11, 0(R10)(SI*8)
 	MOVQ R12, 8(R10)(SI*8)
 	MOVQ R13, 16(R10)(SI*8)
@@ -182,8 +183,8 @@ V3:	ADDQ $4, DI		// n += 4
 L3:	// n > 0
 	ADDQ 0(R8)(SI*8), CX
 	MOVQ CX, 0(R10)(SI*8)
-	SBBQ CX, CX		// save CF
-	NEGQ CX
+	ZERO_CX
+	RCLQ $1, CX		// c = CF
 
 	ADDQ $1, SI		// i++
 	SUBQ $1, DI		// n--
@@ -200,7 +201,7 @@ TEXT ·subVW(SB),NOSPLIT,$0
 	MOVQ x+24(FP), R8
 	MOVQ y+48(FP), CX	// c = y
 	MOVQ z+0(FP), R10
-
+	
 	MOVQ $0, SI		// i = 0
 
 	// s/JL/JMP/ below to disable the unrolled loop
@@ -214,11 +215,11 @@ U4:	// n >= 0
 	MOVQ 16(R8)(SI*8), R13
 	MOVQ 24(R8)(SI*8), R14
 	SUBQ CX, R11
+	ZERO_CX
 	SBBQ $0, R12
 	SBBQ $0, R13
 	SBBQ $0, R14
-	SBBQ CX, CX		// save CF
-	NEGQ CX
+	SETCS CX		// c = CF
 	MOVQ R11, 0(R10)(SI*8)
 	MOVQ R12, 8(R10)(SI*8)
 	MOVQ R13, 16(R10)(SI*8)
@@ -235,8 +236,8 @@ L4:	// n > 0
 	MOVQ 0(R8)(SI*8), R11
 	SUBQ CX, R11
 	MOVQ R11, 0(R10)(SI*8)
-	SBBQ CX, CX		// save CF
-	NEGQ CX
+	ZERO_CX
+	RCLQ $1, CX		// c = CF
 
 	ADDQ $1, SI		// i++
 	SUBQ $1, DI		// n--
@@ -305,7 +306,7 @@ L9:	MOVQ AX, DX		// w = w1
 	SHRQ CX, DX:AX		// w>>s | w1<<ŝ
 	MOVQ DX, (R10)(BX*8)	// z[i] = w>>s | w1<<ŝ
 	ADDQ $1, BX		// i++
-
+	
 E9:	CMPQ BX, R11
 	JL L9			// i < n-1
 
@@ -351,34 +352,6 @@ TEXT ·addMulVVW(SB),NOSPLIT,$0
 	MOVQ z_len+8(FP), R11
 	MOVQ $0, BX		// i = 0
 	MOVQ $0, CX		// c = 0
-	MOVQ R11, R12
-	ANDQ $-2, R12
-	CMPQ R11, $2
-	JAE A6
-	JMP E6
-
-A6:
-	MOVQ (R8)(BX*8), AX
-	MULQ R9
-	ADDQ (R10)(BX*8), AX
-	ADCQ $0, DX
-	ADDQ CX, AX
-	ADCQ $0, DX
-	MOVQ DX, CX
-	MOVQ AX, (R10)(BX*8)
-
-	MOVQ (8)(R8)(BX*8), AX
-	MULQ R9
-	ADDQ (8)(R10)(BX*8), AX
-	ADCQ $0, DX
-	ADDQ CX, AX
-	ADCQ $0, DX
-	MOVQ DX, CX
-	MOVQ AX, (8)(R10)(BX*8)
-
-	ADDQ $2, BX
-	CMPQ BX, R12
-	JL A6
 	JMP E6
 
 L6:	MOVQ (R8)(BX*8), AX
diff --git a/src/math/big/arith_amd64p32.s b/src/math/big/arith_amd64p32.s
index 8610e90..908dbbd 100644
--- a/src/math/big/arith_amd64p32.s
+++ b/src/math/big/arith_amd64p32.s
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build !math_big_pure_go
-
 #include "textflag.h"
 
 TEXT ·mulWW(SB),NOSPLIT,$0
diff --git a/src/math/big/arith_arm.s b/src/math/big/arith_arm.s
index 69590ff..a4c51c2 100644
--- a/src/math/big/arith_arm.s
+++ b/src/math/big/arith_arm.s
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build !math_big_pure_go
-
 #include "textflag.h"
 
 // This file provides fast assembly versions for the elementary
diff --git a/src/math/big/arith_decl.go b/src/math/big/arith_decl.go
index 1707aa4..068cc8d 100644
--- a/src/math/big/arith_decl.go
+++ b/src/math/big/arith_decl.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.
 
-// +build !math_big_pure_go
-
 package big
 
 // implemented in arith_$GOARCH.s
diff --git a/src/math/big/arith_test.go b/src/math/big/arith_test.go
index f46a494..3615a65 100644
--- a/src/math/big/arith_test.go
+++ b/src/math/big/arith_test.go
@@ -155,7 +155,6 @@ var sumVW = []argVW{
 	{nat{1}, nat{1}, 0, 0},
 	{nat{0}, nat{_M}, 1, 1},
 	{nat{0, 0, 0, 0}, nat{_M, _M, _M, _M}, 1, 1},
-	{nat{585}, nat{314}, 271, 0},
 }
 
 var prodVW = []argVW{
@@ -255,7 +254,7 @@ func benchmarkFunVW(b *testing.B, f funVW, n int) {
 	x := rndV(n)
 	y := rndW()
 	z := make([]Word, n)
-	b.SetBytes(int64(n * _S))
+	b.SetBytes(int64(n * _W))
 	b.ResetTimer()
 	for i := 0; i < b.N; i++ {
 		f(z, x, y)
diff --git a/src/math/big/example_test.go b/src/math/big/example_test.go
index ac79552..078be47 100644
--- a/src/math/big/example_test.go
+++ b/src/math/big/example_test.go
@@ -7,7 +7,6 @@ package big_test
 import (
 	"fmt"
 	"log"
-	"math"
 	"math/big"
 )
 
@@ -50,79 +49,3 @@ func ExampleInt_Scan() {
 	}
 	// Output: 18446744073709551617
 }
-
-// This example demonstrates how to use big.Int to compute the smallest
-// Fibonacci number with 100 decimal digits and to test whether it is prime.
-func Example_fibonacci() {
-	// Initialize two big ints with the first two numbers in the sequence.
-	a := big.NewInt(0)
-	b := big.NewInt(1)
-
-	// Initialize limit as 10^99, the smallest integer with 100 digits.
-	var limit big.Int
-	limit.Exp(big.NewInt(10), big.NewInt(99), nil)
-
-	// Loop while a is smaller than 1e100.
-	for a.Cmp(&limit) < 0 {
-		// Compute the next Fibonacci number, storing it in a.
-		a.Add(a, b)
-		// Swap a and b so that b is the next number in the sequence.
-		a, b = b, a
-	}
-	fmt.Println(a) // 100-digit Fibonacci number
-
-	// Test a for primality.
-	// (ProbablyPrimes' argument sets the number of Miller-Rabin
-	// rounds to be performed. 20 is a good value.)
-	fmt.Println(a.ProbablyPrime(20))
-
-	// Output:
-	// 1344719667586153181419716641724567886890850696275767987106294472017884974410332069524504824747437757
-	// false
-}
-
-// This example shows how to use big.Float to compute the square root of 2 with
-// a precision of 200 bits, and how to print the result as a decimal number.
-func Example_sqrt2() {
-	// We'll do computations with 200 bits of precision in the mantissa.
-	const prec = 200
-
-	// Compute the square root of 2 using Newton's Method. We start with
-	// an initial estimate for sqrt(2), and then iterate:
-	//     x_{n+1} = 1/2 * ( x_n + (2.0 / x_n) )
-
-	// Since Newton's Method doubles the number of correct digits at each
-	// iteration, we need at least log_2(prec) steps.
-	steps := int(math.Log2(prec))
-
-	// Initialize values we need for the computation.
-	two := new(big.Float).SetPrec(prec).SetInt64(2)
-	half := new(big.Float).SetPrec(prec).SetFloat64(0.5)
-
-	// Use 1 as the initial estimate.
-	x := new(big.Float).SetPrec(prec).SetInt64(1)
-
-	// We use t as a temporary variable. There's no need to set its precision
-	// since big.Float values with unset (== 0) precision automatically assume
-	// the largest precision of the arguments when used as the result (receiver)
-	// of a big.Float operation.
-	t := new(big.Float)
-
-	// Iterate.
-	for i := 0; i <= steps; i++ {
-		t.Quo(two, x)  // t = 2.0 / x_n
-		t.Add(x, t)    // t = x_n + (2.0 / x_n)
-		x.Mul(half, t) // x_{n+1} = 0.5 * t
-	}
-
-	// We can use the usual fmt.Printf verbs since big.Float implements fmt.Formatter
-	fmt.Printf("sqrt(2) = %.50f\n", x)
-
-	// Print the error between 2 and x*x.
-	t.Mul(x, x) // t = x*x
-	fmt.Printf("error = %e\n", t.Sub(two, t))
-
-	// Output:
-	// sqrt(2) = 1.41421356237309504880168872420969807856967187537695
-	// error = 0.000000e+00
-}
diff --git a/src/math/big/int.go b/src/math/big/int.go
index 65334e0..ade5c2f 100644
--- a/src/math/big/int.go
+++ b/src/math/big/int.go
@@ -7,6 +7,7 @@
 package big
 
 import (
+	"errors"
 	"fmt"
 	"io"
 	"math/rand"
@@ -183,10 +184,6 @@ func (z *Int) MulRange(a, b int64) *Int {
 
 // Binomial sets z to the binomial coefficient of (n, k) and returns z.
 func (z *Int) Binomial(n, k int64) *Int {
-	// reduce the number of multiplications by reducing k
-	if n/2 < k && k <= n {
-		k = n - k // Binomial(n, k) == Binomial(n, n-k)
-	}
 	var a, b Int
 	a.MulRange(n-k+1, n)
 	b.MulRange(1, k)
@@ -324,6 +321,195 @@ func (x *Int) Cmp(y *Int) (r int) {
 	return
 }
 
+func (x *Int) String() string {
+	switch {
+	case x == nil:
+		return "<nil>"
+	case x.neg:
+		return "-" + x.abs.decimalString()
+	}
+	return x.abs.decimalString()
+}
+
+func charset(ch rune) string {
+	switch ch {
+	case 'b':
+		return lowercaseDigits[0:2]
+	case 'o':
+		return lowercaseDigits[0:8]
+	case 'd', 's', 'v':
+		return lowercaseDigits[0:10]
+	case 'x':
+		return lowercaseDigits[0:16]
+	case 'X':
+		return uppercaseDigits[0:16]
+	}
+	return "" // unknown format
+}
+
+// write count copies of text to s
+func writeMultiple(s fmt.State, text string, count int) {
+	if len(text) > 0 {
+		b := []byte(text)
+		for ; count > 0; count-- {
+			s.Write(b)
+		}
+	}
+}
+
+// Format is a support routine for fmt.Formatter. It accepts
+// the formats 'b' (binary), 'o' (octal), 'd' (decimal), 'x'
+// (lowercase hexadecimal), and 'X' (uppercase hexadecimal).
+// Also supported are the full suite of package fmt's format
+// verbs for integral types, including '+', '-', and ' '
+// for sign control, '#' for leading zero in octal and for
+// hexadecimal, a leading "0x" or "0X" for "%#x" and "%#X"
+// respectively, specification of minimum digits precision,
+// output field width, space or zero padding, and left or
+// right justification.
+//
+func (x *Int) Format(s fmt.State, ch rune) {
+	cs := charset(ch)
+
+	// special cases
+	switch {
+	case cs == "":
+		// unknown format
+		fmt.Fprintf(s, "%%!%c(big.Int=%s)", ch, x.String())
+		return
+	case x == nil:
+		fmt.Fprint(s, "<nil>")
+		return
+	}
+
+	// determine sign character
+	sign := ""
+	switch {
+	case x.neg:
+		sign = "-"
+	case s.Flag('+'): // supersedes ' ' when both specified
+		sign = "+"
+	case s.Flag(' '):
+		sign = " "
+	}
+
+	// determine prefix characters for indicating output base
+	prefix := ""
+	if s.Flag('#') {
+		switch ch {
+		case 'o': // octal
+			prefix = "0"
+		case 'x': // hexadecimal
+			prefix = "0x"
+		case 'X':
+			prefix = "0X"
+		}
+	}
+
+	// determine digits with base set by len(cs) and digit characters from cs
+	digits := x.abs.string(cs)
+
+	// number of characters for the three classes of number padding
+	var left int   // space characters to left of digits for right justification ("%8d")
+	var zeroes int // zero characters (actually cs[0]) as left-most digits ("%.8d")
+	var right int  // space characters to right of digits for left justification ("%-8d")
+
+	// determine number padding from precision: the least number of digits to output
+	precision, precisionSet := s.Precision()
+	if precisionSet {
+		switch {
+		case len(digits) < precision:
+			zeroes = precision - len(digits) // count of zero padding
+		case digits == "0" && precision == 0:
+			return // print nothing if zero value (x == 0) and zero precision ("." or ".0")
+		}
+	}
+
+	// determine field pad from width: the least number of characters to output
+	length := len(sign) + len(prefix) + zeroes + len(digits)
+	if width, widthSet := s.Width(); widthSet && length < width { // pad as specified
+		switch d := width - length; {
+		case s.Flag('-'):
+			// pad on the right with spaces; supersedes '0' when both specified
+			right = d
+		case s.Flag('0') && !precisionSet:
+			// pad with zeroes unless precision also specified
+			zeroes = d
+		default:
+			// pad on the left with spaces
+			left = d
+		}
+	}
+
+	// print number as [left pad][sign][prefix][zero pad][digits][right pad]
+	writeMultiple(s, " ", left)
+	writeMultiple(s, sign, 1)
+	writeMultiple(s, prefix, 1)
+	writeMultiple(s, "0", zeroes)
+	writeMultiple(s, digits, 1)
+	writeMultiple(s, " ", right)
+}
+
+// scan sets z to the integer value corresponding to the longest possible prefix
+// read from r representing a signed integer number in a given conversion base.
+// It returns z, the actual conversion base used, and an error, if any. In the
+// error case, the value of z is undefined but the returned value is nil. The
+// syntax follows the syntax of integer literals in Go.
+//
+// The base argument must be 0 or a value from 2 through MaxBase. If the base
+// is 0, the string prefix determines the actual conversion base. A prefix of
+// ``0x'' or ``0X'' selects base 16; the ``0'' prefix selects base 8, and a
+// ``0b'' or ``0B'' prefix selects base 2. Otherwise the selected base is 10.
+//
+func (z *Int) scan(r io.RuneScanner, base int) (*Int, int, error) {
+	// determine sign
+	ch, _, err := r.ReadRune()
+	if err != nil {
+		return nil, 0, err
+	}
+	neg := false
+	switch ch {
+	case '-':
+		neg = true
+	case '+': // nothing to do
+	default:
+		r.UnreadRune()
+	}
+
+	// determine mantissa
+	z.abs, base, err = z.abs.scan(r, base)
+	if err != nil {
+		return nil, base, err
+	}
+	z.neg = len(z.abs) > 0 && neg // 0 has no sign
+
+	return z, base, nil
+}
+
+// Scan is a support routine for fmt.Scanner; it sets z to the value of
+// the scanned number. It accepts the formats 'b' (binary), 'o' (octal),
+// 'd' (decimal), 'x' (lowercase hexadecimal), and 'X' (uppercase hexadecimal).
+func (z *Int) Scan(s fmt.ScanState, ch rune) error {
+	s.SkipSpace() // skip leading space characters
+	base := 0
+	switch ch {
+	case 'b':
+		base = 2
+	case 'o':
+		base = 8
+	case 'd':
+		base = 10
+	case 'x', 'X':
+		base = 16
+	case 's', 'v':
+		// let scan determine the base
+	default:
+		return errors.New("Int.Scan: invalid verb")
+	}
+	_, _, err := z.scan(s, base)
+	return err
+}
+
 // low32 returns the least significant 32 bits of z.
 func low32(z nat) uint32 {
 	if len(z) == 0 {
@@ -364,7 +550,7 @@ func (x *Int) Uint64() uint64 {
 // and returns z and a boolean indicating success. If SetString fails,
 // the value of z is undefined but the returned value is nil.
 //
-// The base argument must be 0 or a value between 2 and MaxBase. If the base
+// The base argument must be 0 or a value from 2 through MaxBase. If the base
 // is 0, the string prefix determines the actual conversion base. A prefix of
 // ``0x'' or ``0X'' selects base 16; the ``0'' prefix selects base 8, and a
 // ``0b'' or ``0B'' prefix selects base 2. Otherwise the selected base is 10.
@@ -375,7 +561,7 @@ func (z *Int) SetString(s string, base int) (*Int, bool) {
 	if err != nil {
 		return nil, false
 	}
-	_, err = r.ReadByte()
+	_, _, err = r.ReadRune()
 	if err != io.EOF {
 		return nil, false
 	}
@@ -500,17 +686,15 @@ func (z *Int) binaryGCD(a, b *Int) *Int {
 	// use one Euclidean iteration to ensure that u and v are approx. the same size
 	switch {
 	case len(a.abs) > len(b.abs):
-		// must set v before u since u may be alias for a or b (was issue #11284)
-		v.Rem(a, b)
 		u.Set(b)
+		v.Rem(a, b)
 	case len(a.abs) < len(b.abs):
-		v.Rem(b, a)
 		u.Set(a)
+		v.Rem(b, a)
 	default:
-		v.Set(b)
 		u.Set(a)
+		v.Set(b)
 	}
-	// a, b must not be used anymore (may be aliases with u)
 
 	// v might be 0 now
 	if len(v.abs) == 0 {
@@ -552,11 +736,8 @@ func (z *Int) binaryGCD(a, b *Int) *Int {
 
 // ProbablyPrime performs n Miller-Rabin tests to check whether x is prime.
 // If it returns true, x is prime with probability 1 - 1/4^n.
-// If it returns false, x is not prime. n must be > 0.
+// If it returns false, x is not prime.
 func (x *Int) ProbablyPrime(n int) bool {
-	if n <= 0 {
-		panic("non-positive n for ProbablyPrime")
-	}
 	return !x.neg && x.abs.probablyPrime(n)
 }
 
@@ -585,124 +766,6 @@ func (z *Int) ModInverse(g, n *Int) *Int {
 	return z
 }
 
-// Jacobi returns the Jacobi symbol (x/y), either +1, -1, or 0.
-// The y argument must be an odd integer.
-func Jacobi(x, y *Int) int {
-	if len(y.abs) == 0 || y.abs[0]&1 == 0 {
-		panic(fmt.Sprintf("big: invalid 2nd argument to Int.Jacobi: need odd integer but got %s", y))
-	}
-
-	// We use the formulation described in chapter 2, section 2.4,
-	// "The Yacas Book of Algorithms":
-	// http://yacas.sourceforge.net/Algo.book.pdf
-
-	var a, b, c Int
-	a.Set(x)
-	b.Set(y)
-	j := 1
-
-	if b.neg {
-		if a.neg {
-			j = -1
-		}
-		b.neg = false
-	}
-
-	for {
-		if b.Cmp(intOne) == 0 {
-			return j
-		}
-		if len(a.abs) == 0 {
-			return 0
-		}
-		a.Mod(&a, &b)
-		if len(a.abs) == 0 {
-			return 0
-		}
-		// a > 0
-
-		// handle factors of 2 in 'a'
-		s := a.abs.trailingZeroBits()
-		if s&1 != 0 {
-			bmod8 := b.abs[0] & 7
-			if bmod8 == 3 || bmod8 == 5 {
-				j = -j
-			}
-		}
-		c.Rsh(&a, s) // a = 2^s*c
-
-		// swap numerator and denominator
-		if b.abs[0]&3 == 3 && c.abs[0]&3 == 3 {
-			j = -j
-		}
-		a.Set(&b)
-		b.Set(&c)
-	}
-}
-
-// ModSqrt sets z to a square root of x mod p if such a square root exists, and
-// returns z. The modulus p must be an odd prime. If x is not a square mod p,
-// ModSqrt leaves z unchanged and returns nil. This function panics if p is
-// not an odd integer.
-func (z *Int) ModSqrt(x, p *Int) *Int {
-	switch Jacobi(x, p) {
-	case -1:
-		return nil // x is not a square mod p
-	case 0:
-		return z.SetInt64(0) // sqrt(0) mod p = 0
-	case 1:
-		break
-	}
-	if x.neg || x.Cmp(p) >= 0 { // ensure 0 <= x < p
-		x = new(Int).Mod(x, p)
-	}
-
-	// Break p-1 into s*2^e such that s is odd.
-	var s Int
-	s.Sub(p, intOne)
-	e := s.abs.trailingZeroBits()
-	s.Rsh(&s, e)
-
-	// find some non-square n
-	var n Int
-	n.SetInt64(2)
-	for Jacobi(&n, p) != -1 {
-		n.Add(&n, intOne)
-	}
-
-	// Core of the Tonelli-Shanks algorithm. Follows the description in
-	// section 6 of "Square roots from 1; 24, 51, 10 to Dan Shanks" by Ezra
-	// Brown:
-	// https://www.maa.org/sites/default/files/pdf/upload_library/22/Polya/07468342.di020786.02p0470a.pdf
-	var y, b, g, t Int
-	y.Add(&s, intOne)
-	y.Rsh(&y, 1)
-	y.Exp(x, &y, p)  // y = x^((s+1)/2)
-	b.Exp(x, &s, p)  // b = x^s
-	g.Exp(&n, &s, p) // g = n^s
-	r := e
-	for {
-		// find the least m such that ord_p(b) = 2^m
-		var m uint
-		t.Set(&b)
-		for t.Cmp(intOne) != 0 {
-			t.Mul(&t, &t).Mod(&t, p)
-			m++
-		}
-
-		if m == 0 {
-			return z.Set(&y)
-		}
-
-		t.SetInt64(0).SetBit(&t, int(r-m-1), 1).Exp(&g, &t, p)
-		// t = g^(2^(r-m-1)) mod p
-		g.Mul(&t, &t).Mod(&g, p) // g = g^(2^(r-m)) mod p
-		y.Mul(&y, &t).Mod(&y, p)
-		b.Mul(&b, &g).Mod(&b, p)
-		r = m
-	}
-}
-
 // Lsh sets z = x << n and returns z.
 func (z *Int) Lsh(x *Int, n uint) *Int {
 	z.abs = z.abs.shl(x.abs, n)
@@ -932,7 +995,7 @@ func (z *Int) GobDecode(buf []byte) error {
 	}
 	b := buf[0]
 	if b>>1 != intGobVersion {
-		return fmt.Errorf("Int.GobDecode: encoding version %d not supported", b>>1)
+		return errors.New(fmt.Sprintf("Int.GobDecode: encoding version %d not supported", b>>1))
 	}
 	z.neg = b&1 != 0
 	z.abs = z.abs.setBytes(buf[1:])
diff --git a/src/math/big/int_test.go b/src/math/big/int_test.go
index 88c8c2b..2d762db 100644
--- a/src/math/big/int_test.go
+++ b/src/math/big/int_test.go
@@ -219,42 +219,334 @@ func TestMulRangeZ(t *testing.T) {
 	}
 }
 
-func TestBinomial(t *testing.T) {
-	var z Int
-	for _, test := range []struct {
-		n, k int64
-		want string
-	}{
-		{0, 0, "1"},
-		{0, 1, "0"},
-		{1, 0, "1"},
-		{1, 1, "1"},
-		{1, 10, "0"},
-		{4, 0, "1"},
-		{4, 1, "4"},
-		{4, 2, "6"},
-		{4, 3, "4"},
-		{4, 4, "1"},
-		{10, 1, "10"},
-		{10, 9, "10"},
-		{10, 5, "252"},
-		{11, 5, "462"},
-		{11, 6, "462"},
-		{100, 10, "17310309456440"},
-		{100, 90, "17310309456440"},
-		{1000, 10, "263409560461970212832400"},
-		{1000, 990, "263409560461970212832400"},
-	} {
-		if got := z.Binomial(test.n, test.k).String(); got != test.want {
-			t.Errorf("Binomial(%d, %d) = %s; want %s", test.n, test.k, got, test.want)
-		}
-	}
-}
-
-func BenchmarkBinomial(b *testing.B) {
-	var z Int
-	for i := b.N - 1; i >= 0; i-- {
-		z.Binomial(1000, 990)
+var stringTests = []struct {
+	in   string
+	out  string
+	base int
+	val  int64
+	ok   bool
+}{
+	{in: "", ok: false},
+	{in: "a", ok: false},
+	{in: "z", ok: false},
+	{in: "+", ok: false},
+	{in: "-", ok: false},
+	{in: "0b", ok: false},
+	{in: "0x", ok: false},
+	{in: "2", base: 2, ok: false},
+	{in: "0b2", base: 0, ok: false},
+	{in: "08", ok: false},
+	{in: "8", base: 8, ok: false},
+	{in: "0xg", base: 0, ok: false},
+	{in: "g", base: 16, ok: false},
+	{"0", "0", 0, 0, true},
+	{"0", "0", 10, 0, true},
+	{"0", "0", 16, 0, true},
+	{"+0", "0", 0, 0, true},
+	{"-0", "0", 0, 0, true},
+	{"10", "10", 0, 10, true},
+	{"10", "10", 10, 10, true},
+	{"10", "10", 16, 16, true},
+	{"-10", "-10", 16, -16, true},
+	{"+10", "10", 16, 16, true},
+	{"0x10", "16", 0, 16, true},
+	{in: "0x10", base: 16, ok: false},
+	{"-0x10", "-16", 0, -16, true},
+	{"+0x10", "16", 0, 16, true},
+	{"00", "0", 0, 0, true},
+	{"0", "0", 8, 0, true},
+	{"07", "7", 0, 7, true},
+	{"7", "7", 8, 7, true},
+	{"023", "19", 0, 19, true},
+	{"23", "23", 8, 19, true},
+	{"cafebabe", "cafebabe", 16, 0xcafebabe, true},
+	{"0b0", "0", 0, 0, true},
+	{"-111", "-111", 2, -7, true},
+	{"-0b111", "-7", 0, -7, true},
+	{"0b1001010111", "599", 0, 0x257, true},
+	{"1001010111", "1001010111", 2, 0x257, true},
+}
+
+func format(base int) string {
+	switch base {
+	case 2:
+		return "%b"
+	case 8:
+		return "%o"
+	case 16:
+		return "%x"
+	}
+	return "%d"
+}
+
+func TestGetString(t *testing.T) {
+	z := new(Int)
+	for i, test := range stringTests {
+		if !test.ok {
+			continue
+		}
+		z.SetInt64(test.val)
+
+		if test.base == 10 {
+			s := z.String()
+			if s != test.out {
+				t.Errorf("#%da got %s; want %s", i, s, test.out)
+			}
+		}
+
+		s := fmt.Sprintf(format(test.base), z)
+		if s != test.out {
+			t.Errorf("#%db got %s; want %s", i, s, test.out)
+		}
+	}
+}
+
+func TestSetString(t *testing.T) {
+	tmp := new(Int)
+	for i, test := range stringTests {
+		// initialize to a non-zero value so that issues with parsing
+		// 0 are detected
+		tmp.SetInt64(1234567890)
+		n1, ok1 := new(Int).SetString(test.in, test.base)
+		n2, ok2 := tmp.SetString(test.in, test.base)
+		expected := NewInt(test.val)
+		if ok1 != test.ok || ok2 != test.ok {
+			t.Errorf("#%d (input '%s') ok incorrect (should be %t)", i, test.in, test.ok)
+			continue
+		}
+		if !ok1 {
+			if n1 != nil {
+				t.Errorf("#%d (input '%s') n1 != nil", i, test.in)
+			}
+			continue
+		}
+		if !ok2 {
+			if n2 != nil {
+				t.Errorf("#%d (input '%s') n2 != nil", i, test.in)
+			}
+			continue
+		}
+
+		if ok1 && !isNormalized(n1) {
+			t.Errorf("#%d (input '%s'): %v is not normalized", i, test.in, *n1)
+		}
+		if ok2 && !isNormalized(n2) {
+			t.Errorf("#%d (input '%s'): %v is not normalized", i, test.in, *n2)
+		}
+
+		if n1.Cmp(expected) != 0 {
+			t.Errorf("#%d (input '%s') got: %s want: %d", i, test.in, n1, test.val)
+		}
+		if n2.Cmp(expected) != 0 {
+			t.Errorf("#%d (input '%s') got: %s want: %d", i, test.in, n2, test.val)
+		}
+	}
+}
+
+var formatTests = []struct {
+	input  string
+	format string
+	output string
+}{
+	{"<nil>", "%x", "<nil>"},
+	{"<nil>", "%#x", "<nil>"},
+	{"<nil>", "%#y", "%!y(big.Int=<nil>)"},
+
+	{"10", "%b", "1010"},
+	{"10", "%o", "12"},
+	{"10", "%d", "10"},
+	{"10", "%v", "10"},
+	{"10", "%x", "a"},
+	{"10", "%X", "A"},
+	{"-10", "%X", "-A"},
+	{"10", "%y", "%!y(big.Int=10)"},
+	{"-10", "%y", "%!y(big.Int=-10)"},
+
+	{"10", "%#b", "1010"},
+	{"10", "%#o", "012"},
+	{"10", "%#d", "10"},
+	{"10", "%#v", "10"},
+	{"10", "%#x", "0xa"},
+	{"10", "%#X", "0XA"},
+	{"-10", "%#X", "-0XA"},
+	{"10", "%#y", "%!y(big.Int=10)"},
+	{"-10", "%#y", "%!y(big.Int=-10)"},
+
+	{"1234", "%d", "1234"},
+	{"1234", "%3d", "1234"},
+	{"1234", "%4d", "1234"},
+	{"-1234", "%d", "-1234"},
+	{"1234", "% 5d", " 1234"},
+	{"1234", "%+5d", "+1234"},
+	{"1234", "%-5d", "1234 "},
+	{"1234", "%x", "4d2"},
+	{"1234", "%X", "4D2"},
+	{"-1234", "%3x", "-4d2"},
+	{"-1234", "%4x", "-4d2"},
+	{"-1234", "%5x", " -4d2"},
+	{"-1234", "%-5x", "-4d2 "},
+	{"1234", "%03d", "1234"},
+	{"1234", "%04d", "1234"},
+	{"1234", "%05d", "01234"},
+	{"1234", "%06d", "001234"},
+	{"-1234", "%06d", "-01234"},
+	{"1234", "%+06d", "+01234"},
+	{"1234", "% 06d", " 01234"},
+	{"1234", "%-6d", "1234  "},
+	{"1234", "%-06d", "1234  "},
+	{"-1234", "%-06d", "-1234 "},
+
+	{"1234", "%.3d", "1234"},
+	{"1234", "%.4d", "1234"},
+	{"1234", "%.5d", "01234"},
+	{"1234", "%.6d", "001234"},
+	{"-1234", "%.3d", "-1234"},
+	{"-1234", "%.4d", "-1234"},
+	{"-1234", "%.5d", "-01234"},
+	{"-1234", "%.6d", "-001234"},
+
+	{"1234", "%8.3d", "    1234"},
+	{"1234", "%8.4d", "    1234"},
+	{"1234", "%8.5d", "   01234"},
+	{"1234", "%8.6d", "  001234"},
+	{"-1234", "%8.3d", "   -1234"},
+	{"-1234", "%8.4d", "   -1234"},
+	{"-1234", "%8.5d", "  -01234"},
+	{"-1234", "%8.6d", " -001234"},
+
+	{"1234", "%+8.3d", "   +1234"},
+	{"1234", "%+8.4d", "   +1234"},
+	{"1234", "%+8.5d", "  +01234"},
+	{"1234", "%+8.6d", " +001234"},
+	{"-1234", "%+8.3d", "   -1234"},
+	{"-1234", "%+8.4d", "   -1234"},
+	{"-1234", "%+8.5d", "  -01234"},
+	{"-1234", "%+8.6d", " -001234"},
+
+	{"1234", "% 8.3d", "    1234"},
+	{"1234", "% 8.4d", "    1234"},
+	{"1234", "% 8.5d", "   01234"},
+	{"1234", "% 8.6d", "  001234"},
+	{"-1234", "% 8.3d", "   -1234"},
+	{"-1234", "% 8.4d", "   -1234"},
+	{"-1234", "% 8.5d", "  -01234"},
+	{"-1234", "% 8.6d", " -001234"},
+
+	{"1234", "%.3x", "4d2"},
+	{"1234", "%.4x", "04d2"},
+	{"1234", "%.5x", "004d2"},
+	{"1234", "%.6x", "0004d2"},
+	{"-1234", "%.3x", "-4d2"},
+	{"-1234", "%.4x", "-04d2"},
+	{"-1234", "%.5x", "-004d2"},
+	{"-1234", "%.6x", "-0004d2"},
+
+	{"1234", "%8.3x", "     4d2"},
+	{"1234", "%8.4x", "    04d2"},
+	{"1234", "%8.5x", "   004d2"},
+	{"1234", "%8.6x", "  0004d2"},
+	{"-1234", "%8.3x", "    -4d2"},
+	{"-1234", "%8.4x", "   -04d2"},
+	{"-1234", "%8.5x", "  -004d2"},
+	{"-1234", "%8.6x", " -0004d2"},
+
+	{"1234", "%+8.3x", "    +4d2"},
+	{"1234", "%+8.4x", "   +04d2"},
+	{"1234", "%+8.5x", "  +004d2"},
+	{"1234", "%+8.6x", " +0004d2"},
+	{"-1234", "%+8.3x", "    -4d2"},
+	{"-1234", "%+8.4x", "   -04d2"},
+	{"-1234", "%+8.5x", "  -004d2"},
+	{"-1234", "%+8.6x", " -0004d2"},
+
+	{"1234", "% 8.3x", "     4d2"},
+	{"1234", "% 8.4x", "    04d2"},
+	{"1234", "% 8.5x", "   004d2"},
+	{"1234", "% 8.6x", "  0004d2"},
+	{"1234", "% 8.7x", " 00004d2"},
+	{"1234", "% 8.8x", " 000004d2"},
+	{"-1234", "% 8.3x", "    -4d2"},
+	{"-1234", "% 8.4x", "   -04d2"},
+	{"-1234", "% 8.5x", "  -004d2"},
+	{"-1234", "% 8.6x", " -0004d2"},
+	{"-1234", "% 8.7x", "-00004d2"},
+	{"-1234", "% 8.8x", "-000004d2"},
+
+	{"1234", "%-8.3d", "1234    "},
+	{"1234", "%-8.4d", "1234    "},
+	{"1234", "%-8.5d", "01234   "},
+	{"1234", "%-8.6d", "001234  "},
+	{"1234", "%-8.7d", "0001234 "},
+	{"1234", "%-8.8d", "00001234"},
+	{"-1234", "%-8.3d", "-1234   "},
+	{"-1234", "%-8.4d", "-1234   "},
+	{"-1234", "%-8.5d", "-01234  "},
+	{"-1234", "%-8.6d", "-001234 "},
+	{"-1234", "%-8.7d", "-0001234"},
+	{"-1234", "%-8.8d", "-00001234"},
+
+	{"16777215", "%b", "111111111111111111111111"}, // 2**24 - 1
+
+	{"0", "%.d", ""},
+	{"0", "%.0d", ""},
+	{"0", "%3.d", ""},
+}
+
+func TestFormat(t *testing.T) {
+	for i, test := range formatTests {
+		var x *Int
+		if test.input != "<nil>" {
+			var ok bool
+			x, ok = new(Int).SetString(test.input, 0)
+			if !ok {
+				t.Errorf("#%d failed reading input %s", i, test.input)
+			}
+		}
+		output := fmt.Sprintf(test.format, x)
+		if output != test.output {
+			t.Errorf("#%d got %q; want %q, {%q, %q, %q}", i, output, test.output, test.input, test.format, test.output)
+		}
+	}
+}
+
+var scanTests = []struct {
+	input     string
+	format    string
+	output    string
+	remaining int
+}{
+	{"1010", "%b", "10", 0},
+	{"0b1010", "%v", "10", 0},
+	{"12", "%o", "10", 0},
+	{"012", "%v", "10", 0},
+	{"10", "%d", "10", 0},
+	{"10", "%v", "10", 0},
+	{"a", "%x", "10", 0},
+	{"0xa", "%v", "10", 0},
+	{"A", "%X", "10", 0},
+	{"-A", "%X", "-10", 0},
+	{"+0b1011001", "%v", "89", 0},
+	{"0xA", "%v", "10", 0},
+	{"0 ", "%v", "0", 1},
+	{"2+3", "%v", "2", 2},
+	{"0XABC 12", "%v", "2748", 3},
+}
+
+func TestScan(t *testing.T) {
+	var buf bytes.Buffer
+	for i, test := range scanTests {
+		x := new(Int)
+		buf.Reset()
+		buf.WriteString(test.input)
+		if _, err := fmt.Fscanf(&buf, test.format, x); err != nil {
+			t.Errorf("#%d error: %s", i, err)
+		}
+		if x.String() != test.output {
+			t.Errorf("#%d got %s; want %s", i, x.String(), test.output)
+		}
+		if buf.Len() != test.remaining {
+			t.Errorf("#%d got %d bytes remaining; want %d", i, buf.Len(), test.remaining)
+		}
 	}
 }
 
@@ -329,42 +621,6 @@ func TestDivisionSigns(t *testing.T) {
 	}
 }
 
-func norm(x nat) nat {
-	i := len(x)
-	for i > 0 && x[i-1] == 0 {
-		i--
-	}
-	return x[:i]
-}
-
-func TestBits(t *testing.T) {
-	for _, test := range []nat{
-		nil,
-		{0},
-		{1},
-		{0, 1, 2, 3, 4},
-		{4, 3, 2, 1, 0},
-		{4, 3, 2, 1, 0, 0, 0, 0},
-	} {
-		var z Int
-		z.neg = true
-		got := z.SetBits(test)
-		want := norm(test)
-		if got.abs.cmp(want) != 0 {
-			t.Errorf("SetBits(%v) = %v; want %v", test, got.abs, want)
-		}
-
-		if got.neg {
-			t.Errorf("SetBits(%v): got negative result", test)
-		}
-
-		bits := nat(z.Bits())
-		if bits.cmp(want) != 0 {
-			t.Errorf("%v.Bits() = %v; want %v", z.abs, bits, want)
-		}
-	}
-}
-
 func checkSetBytes(b []byte) bool {
 	hex1 := hex.EncodeToString(new(Int).SetBytes(b).Bytes())
 	hex2 := hex.EncodeToString(b)
@@ -392,7 +648,7 @@ func checkBytes(b []byte) bool {
 }
 
 func TestBytes(t *testing.T) {
-	if err := quick.Check(checkBytes, nil); err != nil {
+	if err := quick.Check(checkSetBytes, nil); err != nil {
 		t.Error(err)
 	}
 }
@@ -525,7 +781,6 @@ var expTests = []struct {
 	{"1234", "-1", "1", "0"},
 
 	// misc
-	{"5", "1", "3", "2"},
 	{"5", "-7", "", "1"},
 	{"-5", "-7", "", "1"},
 	{"5", "0", "", "1"},
@@ -662,21 +917,6 @@ func testGcd(t *testing.T, d, x, y, a, b *Int) {
 	if D.Cmp(d) != 0 {
 		t.Errorf("binaryGcd(%s, %s): got d = %s, want %s", a, b, D, d)
 	}
-
-	// check results in presence of aliasing (issue #11284)
-	a2 := new(Int).Set(a)
-	b2 := new(Int).Set(b)
-	a2.binaryGCD(a2, b2) // result is same as 1st argument
-	if a2.Cmp(d) != 0 {
-		t.Errorf("binaryGcd(%s, %s): got d = %s, want %s", a, b, a2, d)
-	}
-
-	a2 = new(Int).Set(a)
-	b2 = new(Int).Set(b)
-	b2.binaryGCD(a2, b2) // result is same as 2nd argument
-	if b2.Cmp(d) != 0 {
-		t.Errorf("binaryGcd(%s, %s): got d = %s, want %s", a, b, b2, d)
-	}
 }
 
 func TestGcd(t *testing.T) {
@@ -708,7 +948,7 @@ var primes = []string{
 	"10953742525620032441",
 	"17908251027575790097",
 
-	// https://golang.org/issue/638
+	// http://code.google.com/p/go/issues/detail?id=638
 	"18699199384836356663",
 
 	"98920366548084643601728869055592650835572950932266967461790948584315647051443",
@@ -719,18 +959,9 @@ var primes = []string{
 	"230975859993204150666423538988557839555560243929065415434980904258310530753006723857139742334640122533598517597674807096648905501653461687601339782814316124971547968912893214002992086353183070342498989426570593",
 	"5521712099665906221540423207019333379125265462121169655563495403888449493493629943498064604536961775110765377745550377067893607246020694972959780839151452457728855382113555867743022746090187341871655890805971735385789993",
 	"203956878356401977405765866929034577280193993314348263094772646453283062722701277632936616063144088173312372882677123879538709400158306567338328279154499698366071906766440037074217117805690872792848149112022286332144876183376326512083574821647933992961249917319836219304274280243803104015000563790123",
-
-	// ECC primes: http://tools.ietf.org/html/draft-ladd-safecurves-02
-	"3618502788666131106986593281521497120414687020801267626233049500247285301239",                                                                                  // Curve1174: 2^251-9
-	"57896044618658097711785492504343953926634992332820282019728792003956564819949",                                                                                 // Curve25519: 2^255-19
-	"9850501549098619803069760025035903451269934817616361666987073351061430442874302652853566563721228910201656997576599",                                           // E-382: 2^382-105
-	"42307582002575910332922579714097346549017899709713998034217522897561970639123926132812109468141778230245837569601494931472367",                                 // Curve41417: 2^414-17
-	"6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151", // E-521: 2^521-1
 }
 
 var composites = []string{
-	"0",
-	"1",
 	"21284175091214687912771199898307297748211672914763848041968395774954376176754",
 	"6084766654921918907427900243509372380954290099172559290432744450051395395951",
 	"84594350493221918389213352992032324280367711247940675652888030554255915464401",
@@ -758,21 +989,6 @@ func TestProbablyPrime(t *testing.T) {
 			break
 		}
 	}
-
-	// check that ProbablyPrime panics if n <= 0
-	c := NewInt(11) // a prime
-	for _, n := range []int{-1, 0, 1} {
-		func() {
-			defer func() {
-				if n <= 0 && recover() == nil {
-					t.Fatalf("expected panic from ProbablyPrime(%d)", n)
-				}
-			}()
-			if !c.ProbablyPrime(n) {
-				t.Fatalf("%v should be a prime", c)
-			}
-		}()
-	}
 }
 
 type intShiftTest struct {
@@ -1271,136 +1487,6 @@ func TestModInverse(t *testing.T) {
 	}
 }
 
-// testModSqrt is a helper for TestModSqrt,
-// which checks that ModSqrt can compute a square-root of elt^2.
-func testModSqrt(t *testing.T, elt, mod, sq, sqrt *Int) bool {
-	var sqChk, sqrtChk, sqrtsq Int
-	sq.Mul(elt, elt)
-	sq.Mod(sq, mod)
-	z := sqrt.ModSqrt(sq, mod)
-	if z != sqrt {
-		t.Errorf("ModSqrt returned wrong value %s", z)
-	}
-
-	// test ModSqrt arguments outside the range [0,mod)
-	sqChk.Add(sq, mod)
-	z = sqrtChk.ModSqrt(&sqChk, mod)
-	if z != &sqrtChk || z.Cmp(sqrt) != 0 {
-		t.Errorf("ModSqrt returned inconsistent value %s", z)
-	}
-	sqChk.Sub(sq, mod)
-	z = sqrtChk.ModSqrt(&sqChk, mod)
-	if z != &sqrtChk || z.Cmp(sqrt) != 0 {
-		t.Errorf("ModSqrt returned inconsistent value %s", z)
-	}
-
-	// make sure we actually got a square root
-	if sqrt.Cmp(elt) == 0 {
-		return true // we found the "desired" square root
-	}
-	sqrtsq.Mul(sqrt, sqrt) // make sure we found the "other" one
-	sqrtsq.Mod(&sqrtsq, mod)
-	return sq.Cmp(&sqrtsq) == 0
-}
-
-func TestModSqrt(t *testing.T) {
-	var elt, mod, modx4, sq, sqrt Int
-	r := rand.New(rand.NewSource(9))
-	for i, s := range primes[1:] { // skip 2, use only odd primes
-		mod.SetString(s, 10)
-		modx4.Lsh(&mod, 2)
-
-		// test a few random elements per prime
-		for x := 1; x < 5; x++ {
-			elt.Rand(r, &modx4)
-			elt.Sub(&elt, &mod) // test range [-mod, 3*mod)
-			if !testModSqrt(t, &elt, &mod, &sq, &sqrt) {
-				t.Errorf("#%d: failed (sqrt(e) = %s)", i, &sqrt)
-			}
-		}
-	}
-
-	// exhaustive test for small values
-	for n := 3; n < 100; n++ {
-		mod.SetInt64(int64(n))
-		if !mod.ProbablyPrime(10) {
-			continue
-		}
-		isSquare := make([]bool, n)
-
-		// test all the squares
-		for x := 1; x < n; x++ {
-			elt.SetInt64(int64(x))
-			if !testModSqrt(t, &elt, &mod, &sq, &sqrt) {
-				t.Errorf("#%d: failed (sqrt(%d,%d) = %s)", x, &elt, &mod, &sqrt)
-			}
-			isSquare[sq.Uint64()] = true
-		}
-
-		// test all non-squares
-		for x := 1; x < n; x++ {
-			sq.SetInt64(int64(x))
-			z := sqrt.ModSqrt(&sq, &mod)
-			if !isSquare[x] && z != nil {
-				t.Errorf("#%d: failed (sqrt(%d,%d) = nil)", x, &sqrt, &mod)
-			}
-		}
-	}
-}
-
-func TestJacobi(t *testing.T) {
-	testCases := []struct {
-		x, y   int64
-		result int
-	}{
-		{0, 1, 1},
-		{0, -1, 1},
-		{1, 1, 1},
-		{1, -1, 1},
-		{0, 5, 0},
-		{1, 5, 1},
-		{2, 5, -1},
-		{-2, 5, -1},
-		{2, -5, -1},
-		{-2, -5, 1},
-		{3, 5, -1},
-		{5, 5, 0},
-		{-5, 5, 0},
-		{6, 5, 1},
-		{6, -5, 1},
-		{-6, 5, 1},
-		{-6, -5, -1},
-	}
-
-	var x, y Int
-
-	for i, test := range testCases {
-		x.SetInt64(test.x)
-		y.SetInt64(test.y)
-		expected := test.result
-		actual := Jacobi(&x, &y)
-		if actual != expected {
-			t.Errorf("#%d: Jacobi(%d, %d) = %d, but expected %d", i, test.x, test.y, actual, expected)
-		}
-	}
-}
-
-func TestJacobiPanic(t *testing.T) {
-	const failureMsg = "test failure"
-	defer func() {
-		msg := recover()
-		if msg == nil || msg == failureMsg {
-			panic(msg)
-		}
-		t.Log(msg)
-	}()
-	x := NewInt(1)
-	y := NewInt(2)
-	// Jacobi should panic when the second argument is even.
-	Jacobi(x, y)
-	panic(failureMsg)
-}
-
 var encodingTests = []string{
 	"-539345864568634858364538753846587364875430589374589",
 	"-678645873",
diff --git a/src/math/big/nat.go b/src/math/big/nat.go
index 6545bc1..16a87f5 100644
--- a/src/math/big/nat.go
+++ b/src/math/big/nat.go
@@ -5,22 +5,18 @@
 // Package big implements multi-precision arithmetic (big numbers).
 // The following numeric types are supported:
 //
-//   Int    signed integers
-//   Rat    rational numbers
-//   Float  floating-point numbers
+//	- Int	signed integers
+//	- Rat	rational numbers
 //
 // Methods are typically of the form:
 //
-//   func (z *T) Unary(x *T) *T        // z = op x
-//   func (z *T) Binary(x, y *T) *T    // z = x op y
-//   func (x *T) M() T1                // v = x.M()
+//	func (z *Int) Op(x, y *Int) *Int	(similar for *Rat)
 //
-// with T one of Int, Rat, or Float. For unary and binary operations, the
-// result is the receiver (usually named z in that case); if it is one of
-// the operands x or y it may be overwritten (and its memory reused).
+// and implement operations z = x Op y with the result as receiver; if it
+// is one of the operands it may be overwritten (and its memory reused).
 // To enable chaining of operations, the result is also returned. Methods
-// returning a result other than *Int, *Rat, or *Float take an operand as
-// the receiver (usually named x in that case).
+// returning a result other than *Int or *Rat take one of the operands as
+// the receiver.
 //
 package big
 
@@ -28,7 +24,13 @@ package big
 // These are the building blocks for the operations on signed integers
 // and rationals.
 
-import "math/rand"
+import (
+	"errors"
+	"io"
+	"math"
+	"math/rand"
+	"sync"
+)
 
 // An unsigned integer x of the form
 //
@@ -66,7 +68,7 @@ func (z nat) norm() nat {
 
 func (z nat) make(n int) nat {
 	if n <= cap(z) {
-		return z[:n] // reuse z
+		return z[0:n] // reuse z
 	}
 	// Choosing a good value for e has significant performance impact
 	// because it increases the chance that a value can be reused.
@@ -76,7 +78,7 @@ func (z nat) make(n int) nat {
 
 func (z nat) setWord(x Word) nat {
 	if x == 0 {
-		return z[:0]
+		return z.make(0)
 	}
 	z = z.make(1)
 	z[0] = x
@@ -120,7 +122,7 @@ func (z nat) add(x, y nat) nat {
 		return z.add(y, x)
 	case m == 0:
 		// n == 0 because m >= n; result is 0
-		return z[:0]
+		return z.make(0)
 	case n == 0:
 		// result is x
 		return z.set(x)
@@ -146,7 +148,7 @@ func (z nat) sub(x, y nat) nat {
 		panic("underflow")
 	case m == 0:
 		// n == 0 because m >= n; result is 0
-		return z[:0]
+		return z.make(0)
 	case n == 0:
 		// result is x
 		return z.set(x)
@@ -216,34 +218,6 @@ func basicMul(z, x, y nat) {
 	}
 }
 
-// montgomery computes x*y*2^(-n*_W) mod m,
-// assuming k = -1/m mod 2^_W.
-// z is used for storing the result which is returned;
-// z must not alias x, y or m.
-func (z nat) montgomery(x, y, m nat, k Word, n int) nat {
-	var c1, c2 Word
-	z = z.make(n)
-	z.clear()
-	for i := 0; i < n; i++ {
-		d := y[i]
-		c1 += addMulVVW(z, x, d)
-		t := z[0] * k
-		c2 = addMulVVW(z, m, t)
-
-		copy(z, z[1:])
-		z[n-1] = c1 + c2
-		if z[n-1] < c1 {
-			c1 = 1
-		} else {
-			c1 = 0
-		}
-	}
-	if c1 != 0 {
-		subVV(z, z, m)
-	}
-	return z
-}
-
 // Fast version of z[0:n+n>>1].add(z[0:n+n>>1], x[0:n]) w/o bounds checks.
 // Factored out for readability - do not use outside karatsuba.
 func karatsubaAdd(z, x nat, n int) {
@@ -363,7 +337,7 @@ func karatsuba(z, x, y nat) {
 	}
 }
 
-// alias reports whether x and y share the same base array.
+// alias returns true if x and y share the same base array.
 func alias(x, y nat) bool {
 	return cap(x) > 0 && cap(y) > 0 && &x[0:cap(x)][cap(x)-1] == &y[0:cap(y)][cap(y)-1]
 }
@@ -410,7 +384,7 @@ func (z nat) mul(x, y nat) nat {
 	case m < n:
 		return z.mul(y, x)
 	case m == 0 || n == 0:
-		return z[:0]
+		return z.make(0)
 	case n == 1:
 		return z.mulAddWW(x, y[0], 0)
 	}
@@ -514,7 +488,7 @@ func (z nat) divW(x nat, y Word) (q nat, r Word) {
 		q = z.set(x) // result is x
 		return
 	case m == 0:
-		q = z[:0] // result is 0
+		q = z.make(0) // result is 0
 		return
 	}
 	// m > 0
@@ -530,7 +504,7 @@ func (z nat) div(z2, u, v nat) (q, r nat) {
 	}
 
 	if u.cmp(v) < 0 {
-		q = z[:0]
+		q = z.make(0)
 		r = z2.set(u)
 		return
 	}
@@ -569,10 +543,10 @@ func (z nat) divLarge(u, uIn, v nat) (q, r nat) {
 		u = nil // u is an alias for uIn or v - cannot reuse
 	}
 	u = u.make(len(uIn) + 1)
-	u.clear() // TODO(gri) no need to clear if we allocated a new u
+	u.clear()
 
 	// D1.
-	shift := nlz(v[n-1])
+	shift := leadingZeros(v[n-1])
 	if shift > 0 {
 		// do not modify v, it may be used by another goroutine simultaneously
 		v1 := make(nat, n)
@@ -632,6 +606,385 @@ func (x nat) bitLen() int {
 	return 0
 }
 
+// MaxBase is the largest number base accepted for string conversions.
+const MaxBase = 'z' - 'a' + 10 + 1 // = hexValue('z') + 1
+
+func hexValue(ch rune) Word {
+	d := int(MaxBase + 1) // illegal base
+	switch {
+	case '0' <= ch && ch <= '9':
+		d = int(ch - '0')
+	case 'a' <= ch && ch <= 'z':
+		d = int(ch - 'a' + 10)
+	case 'A' <= ch && ch <= 'Z':
+		d = int(ch - 'A' + 10)
+	}
+	return Word(d)
+}
+
+// scan sets z to the natural number corresponding to the longest possible prefix
+// read from r representing an unsigned integer in a given conversion base.
+// It returns z, the actual conversion base used, and an error, if any. In the
+// error case, the value of z is undefined. The syntax follows the syntax of
+// unsigned integer literals in Go.
+//
+// The base argument must be 0 or a value from 2 through MaxBase. If the base
+// is 0, the string prefix determines the actual conversion base. A prefix of
+// ``0x'' or ``0X'' selects base 16; the ``0'' prefix selects base 8, and a
+// ``0b'' or ``0B'' prefix selects base 2. Otherwise the selected base is 10.
+//
+func (z nat) scan(r io.RuneScanner, base int) (nat, int, error) {
+	// reject illegal bases
+	if base < 0 || base == 1 || MaxBase < base {
+		return z, 0, errors.New("illegal number base")
+	}
+
+	// one char look-ahead
+	ch, _, err := r.ReadRune()
+	if err != nil {
+		return z, 0, err
+	}
+
+	// determine base if necessary
+	b := Word(base)
+	if base == 0 {
+		b = 10
+		if ch == '0' {
+			switch ch, _, err = r.ReadRune(); err {
+			case nil:
+				b = 8
+				switch ch {
+				case 'x', 'X':
+					b = 16
+				case 'b', 'B':
+					b = 2
+				}
+				if b == 2 || b == 16 {
+					if ch, _, err = r.ReadRune(); err != nil {
+						return z, 0, err
+					}
+				}
+			case io.EOF:
+				return z.make(0), 10, nil
+			default:
+				return z, 10, err
+			}
+		}
+	}
+
+	// convert string
+	// - group as many digits d as possible together into a "super-digit" dd with "super-base" bb
+	// - only when bb does not fit into a word anymore, do a full number mulAddWW using bb and dd
+	z = z.make(0)
+	bb := Word(1)
+	dd := Word(0)
+	for max := _M / b; ; {
+		d := hexValue(ch)
+		if d >= b {
+			r.UnreadRune() // ch does not belong to number anymore
+			break
+		}
+
+		if bb <= max {
+			bb *= b
+			dd = dd*b + d
+		} else {
+			// bb * b would overflow
+			z = z.mulAddWW(z, bb, dd)
+			bb = b
+			dd = d
+		}
+
+		if ch, _, err = r.ReadRune(); err != nil {
+			if err != io.EOF {
+				return z, int(b), err
+			}
+			break
+		}
+	}
+
+	switch {
+	case bb > 1:
+		// there was at least one mantissa digit
+		z = z.mulAddWW(z, bb, dd)
+	case base == 0 && b == 8:
+		// there was only the octal prefix 0 (possibly followed by digits > 7);
+		// return base 10, not 8
+		return z, 10, nil
+	case base != 0 || b != 8:
+		// there was neither a mantissa digit nor the octal prefix 0
+		return z, int(b), errors.New("syntax error scanning number")
+	}
+
+	return z.norm(), int(b), nil
+}
+
+// Character sets for string conversion.
+const (
+	lowercaseDigits = "0123456789abcdefghijklmnopqrstuvwxyz"
+	uppercaseDigits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+)
+
+// decimalString returns a decimal representation of x.
+// It calls x.string with the charset "0123456789".
+func (x nat) decimalString() string {
+	return x.string(lowercaseDigits[0:10])
+}
+
+// string converts x to a string using digits from a charset; a digit with
+// value d is represented by charset[d]. The conversion base is determined
+// by len(charset), which must be >= 2 and <= 256.
+func (x nat) string(charset string) string {
+	b := Word(len(charset))
+
+	// special cases
+	switch {
+	case b < 2 || MaxBase > 256:
+		panic("illegal base")
+	case len(x) == 0:
+		return string(charset[0])
+	}
+
+	// allocate buffer for conversion
+	i := int(float64(x.bitLen())/math.Log2(float64(b))) + 1 // off by one at most
+	s := make([]byte, i)
+
+	// convert power of two and non power of two bases separately
+	if b == b&-b {
+		// shift is base-b digit size in bits
+		shift := trailingZeroBits(b) // shift > 0 because b >= 2
+		mask := Word(1)<<shift - 1
+		w := x[0]
+		nbits := uint(_W) // number of unprocessed bits in w
+
+		// convert less-significant words
+		for k := 1; k < len(x); k++ {
+			// convert full digits
+			for nbits >= shift {
+				i--
+				s[i] = charset[w&mask]
+				w >>= shift
+				nbits -= shift
+			}
+
+			// convert any partial leading digit and advance to next word
+			if nbits == 0 {
+				// no partial digit remaining, just advance
+				w = x[k]
+				nbits = _W
+			} else {
+				// partial digit in current (k-1) and next (k) word
+				w |= x[k] << nbits
+				i--
+				s[i] = charset[w&mask]
+
+				// advance
+				w = x[k] >> (shift - nbits)
+				nbits = _W - (shift - nbits)
+			}
+		}
+
+		// convert digits of most-significant word (omit leading zeros)
+		for nbits >= 0 && w != 0 {
+			i--
+			s[i] = charset[w&mask]
+			w >>= shift
+			nbits -= shift
+		}
+
+	} else {
+		// determine "big base"; i.e., the largest possible value bb
+		// that is a power of base b and still fits into a Word
+		// (as in 10^19 for 19 decimal digits in a 64bit Word)
+		bb := b      // big base is b**ndigits
+		ndigits := 1 // number of base b digits
+		for max := Word(_M / b); bb <= max; bb *= b {
+			ndigits++ // maximize ndigits where bb = b**ndigits, bb <= _M
+		}
+
+		// construct table of successive squares of bb*leafSize to use in subdivisions
+		// result (table != nil) <=> (len(x) > leafSize > 0)
+		table := divisors(len(x), b, ndigits, bb)
+
+		// preserve x, create local copy for use by convertWords
+		q := nat(nil).set(x)
+
+		// convert q to string s in base b
+		q.convertWords(s, charset, b, ndigits, bb, table)
+
+		// strip leading zeros
+		// (x != 0; thus s must contain at least one non-zero digit
+		// and the loop will terminate)
+		i = 0
+		for zero := charset[0]; s[i] == zero; {
+			i++
+		}
+	}
+
+	return string(s[i:])
+}
+
+// Convert words of q to base b digits in s. If q is large, it is recursively "split in half"
+// by nat/nat division using tabulated divisors. Otherwise, it is converted iteratively using
+// repeated nat/Word division.
+//
+// The iterative method processes n Words by n divW() calls, each of which visits every Word in the
+// incrementally shortened q for a total of n + (n-1) + (n-2) ... + 2 + 1, or n(n+1)/2 divW()'s.
+// Recursive conversion divides q by its approximate square root, yielding two parts, each half
+// the size of q. Using the iterative method on both halves means 2 * (n/2)(n/2 + 1)/2 divW()'s
+// plus the expensive long div(). Asymptotically, the ratio is favorable at 1/2 the divW()'s, and
+// is made better by splitting the subblocks recursively. Best is to split blocks until one more
+// split would take longer (because of the nat/nat div()) than the twice as many divW()'s of the
+// iterative approach. This threshold is represented by leafSize. Benchmarking of leafSize in the
+// range 2..64 shows that values of 8 and 16 work well, with a 4x speedup at medium lengths and
+// ~30x for 20000 digits. Use nat_test.go's BenchmarkLeafSize tests to optimize leafSize for
+// specific hardware.
+//
+func (q nat) convertWords(s []byte, charset string, b Word, ndigits int, bb Word, table []divisor) {
+	// split larger blocks recursively
+	if table != nil {
+		// len(q) > leafSize > 0
+		var r nat
+		index := len(table) - 1
+		for len(q) > leafSize {
+			// find divisor close to sqrt(q) if possible, but in any case < q
+			maxLength := q.bitLen()     // ~= log2 q, or at of least largest possible q of this bit length
+			minLength := maxLength >> 1 // ~= log2 sqrt(q)
+			for index > 0 && table[index-1].nbits > minLength {
+				index-- // desired
+			}
+			if table[index].nbits >= maxLength && table[index].bbb.cmp(q) >= 0 {
+				index--
+				if index < 0 {
+					panic("internal inconsistency")
+				}
+			}
+
+			// split q into the two digit number (q'*bbb + r) to form independent subblocks
+			q, r = q.div(r, q, table[index].bbb)
+
+			// convert subblocks and collect results in s[:h] and s[h:]
+			h := len(s) - table[index].ndigits
+			r.convertWords(s[h:], charset, b, ndigits, bb, table[0:index])
+			s = s[:h] // == q.convertWords(s, charset, b, ndigits, bb, table[0:index+1])
+		}
+	}
+
+	// having split any large blocks now process the remaining (small) block iteratively
+	i := len(s)
+	var r Word
+	if b == 10 {
+		// hard-coding for 10 here speeds this up by 1.25x (allows for / and % by constants)
+		for len(q) > 0 {
+			// extract least significant, base bb "digit"
+			q, r = q.divW(q, bb)
+			for j := 0; j < ndigits && i > 0; j++ {
+				i--
+				// avoid % computation since r%10 == r - int(r/10)*10;
+				// this appears to be faster for BenchmarkString10000Base10
+				// and smaller strings (but a bit slower for larger ones)
+				t := r / 10
+				s[i] = charset[r-t<<3-t-t] // TODO(gri) replace w/ t*10 once compiler produces better code
+				r = t
+			}
+		}
+	} else {
+		for len(q) > 0 {
+			// extract least significant, base bb "digit"
+			q, r = q.divW(q, bb)
+			for j := 0; j < ndigits && i > 0; j++ {
+				i--
+				s[i] = charset[r%b]
+				r /= b
+			}
+		}
+	}
+
+	// prepend high-order zeroes
+	zero := charset[0]
+	for i > 0 { // while need more leading zeroes
+		i--
+		s[i] = zero
+	}
+}
+
+// Split blocks greater than leafSize Words (or set to 0 to disable recursive conversion)
+// Benchmark and configure leafSize using: go test -bench="Leaf"
+//   8 and 16 effective on 3.0 GHz Xeon "Clovertown" CPU (128 byte cache lines)
+//   8 and 16 effective on 2.66 GHz Core 2 Duo "Penryn" CPU
+var leafSize int = 8 // number of Word-size binary values treat as a monolithic block
+
+type divisor struct {
+	bbb     nat // divisor
+	nbits   int // bit length of divisor (discounting leading zeroes) ~= log2(bbb)
+	ndigits int // digit length of divisor in terms of output base digits
+}
+
+var cacheBase10 struct {
+	sync.Mutex
+	table [64]divisor // cached divisors for base 10
+}
+
+// expWW computes x**y
+func (z nat) expWW(x, y Word) nat {
+	return z.expNN(nat(nil).setWord(x), nat(nil).setWord(y), nil)
+}
+
+// construct table of powers of bb*leafSize to use in subdivisions
+func divisors(m int, b Word, ndigits int, bb Word) []divisor {
+	// only compute table when recursive conversion is enabled and x is large
+	if leafSize == 0 || m <= leafSize {
+		return nil
+	}
+
+	// determine k where (bb**leafSize)**(2**k) >= sqrt(x)
+	k := 1
+	for words := leafSize; words < m>>1 && k < len(cacheBase10.table); words <<= 1 {
+		k++
+	}
+
+	// reuse and extend existing table of divisors or create new table as appropriate
+	var table []divisor // for b == 10, table overlaps with cacheBase10.table
+	if b == 10 {
+		cacheBase10.Lock()
+		table = cacheBase10.table[0:k] // reuse old table for this conversion
+	} else {
+		table = make([]divisor, k) // create new table for this conversion
+	}
+
+	// extend table
+	if table[k-1].ndigits == 0 {
+		// add new entries as needed
+		var larger nat
+		for i := 0; i < k; i++ {
+			if table[i].ndigits == 0 {
+				if i == 0 {
+					table[0].bbb = nat(nil).expWW(bb, Word(leafSize))
+					table[0].ndigits = ndigits * leafSize
+				} else {
+					table[i].bbb = nat(nil).mul(table[i-1].bbb, table[i-1].bbb)
+					table[i].ndigits = 2 * table[i-1].ndigits
+				}
+
+				// optimization: exploit aggregated extra bits in macro blocks
+				larger = nat(nil).set(table[i].bbb)
+				for mulAddVWW(larger, larger, b, 0) == 0 {
+					table[i].bbb = table[i].bbb.set(larger)
+					table[i].ndigits++
+				}
+
+				table[i].nbits = table[i].bbb.bitLen()
+			}
+		}
+	}
+
+	if b == 10 {
+		cacheBase10.Unlock()
+	}
+
+	return table
+}
+
 const deBruijn32 = 0x077CB531
 
 var deBruijn32Lookup = []byte{
@@ -688,7 +1041,7 @@ func (x nat) trailingZeroBits() uint {
 func (z nat) shl(x nat, s uint) nat {
 	m := len(x)
 	if m == 0 {
-		return z[:0]
+		return z.make(0)
 	}
 	// m > 0
 
@@ -705,7 +1058,7 @@ func (z nat) shr(x nat, s uint) nat {
 	m := len(x)
 	n := m - int(s/_W)
 	if n <= 0 {
-		return z[:0]
+		return z.make(0)
 	}
 	// n > 0
 
@@ -744,36 +1097,12 @@ func (z nat) setBit(x nat, i uint, b uint) nat {
 	panic("set bit is not 0 or 1")
 }
 
-// bit returns the value of the i'th bit, with lsb == bit 0.
-func (x nat) bit(i uint) uint {
-	j := i / _W
-	if j >= uint(len(x)) {
+func (z nat) bit(i uint) uint {
+	j := int(i / _W)
+	if j >= len(z) {
 		return 0
 	}
-	// 0 <= j < len(x)
-	return uint(x[j] >> (i % _W) & 1)
-}
-
-// sticky returns 1 if there's a 1 bit within the
-// i least significant bits, otherwise it returns 0.
-func (x nat) sticky(i uint) uint {
-	j := i / _W
-	if j >= uint(len(x)) {
-		if len(x) == 0 {
-			return 0
-		}
-		return 1
-	}
-	// 0 <= j < len(x)
-	for _, x := range x[:j] {
-		if x != 0 {
-			return 1
-		}
-	}
-	if x[j]<<(_W-i%_W) != 0 {
-		return 1
-	}
-	return 0
+	return uint(z[j] >> (i % _W) & 1)
 }
 
 func (z nat) and(x, y nat) nat {
@@ -847,7 +1176,7 @@ func (z nat) xor(x, y nat) nat {
 	return z.norm()
 }
 
-// greaterThan reports whether (x1<<_W + x2) > (y1<<_W + y2)
+// greaterThan returns true iff (x1<<_W + x2) > (y1<<_W + y2)
 func greaterThan(x1, x2, y1, y2 Word) bool {
 	return x1 > y1 || x1 == y1 && x2 > y2
 }
@@ -916,13 +1245,6 @@ func (z nat) expNN(x, y, m nat) nat {
 	}
 	// y > 0
 
-	// x**1 mod m == x mod m
-	if len(y) == 1 && y[0] == 1 && len(m) != 0 {
-		_, z = z.div(z, x, m)
-		return z
-	}
-	// y > 1
-
 	if len(m) != 0 {
 		// We likely end up being as long as the modulus.
 		z = z.make(len(m))
@@ -933,16 +1255,13 @@ func (z nat) expNN(x, y, m nat) nat {
 	// 4-bit, windowed exponentiation. This involves precomputing 14 values
 	// (x^2...x^15) but then reduces the number of multiply-reduces by a
 	// third. Even for a 32-bit exponent, this reduces the number of
-	// operations. Uses Montgomery method for odd moduli.
+	// operations.
 	if len(x) > 1 && len(y) > 1 && len(m) > 0 {
-		if m[0]&1 == 1 {
-			return z.expNNMontgomery(x, y, m)
-		}
 		return z.expNNWindowed(x, y, m)
 	}
 
 	v := y[len(y)-1] // v > 0 because y is normalized and y > 0
-	shift := nlz(v) + 1
+	shift := leadingZeros(v) + 1
 	v <<= shift
 	var q nat
 
@@ -1060,87 +1379,6 @@ func (z nat) expNNWindowed(x, y, m nat) nat {
 	return z.norm()
 }
 
-// expNNMontgomery calculates x**y mod m using a fixed, 4-bit window.
-// Uses Montgomery representation.
-func (z nat) expNNMontgomery(x, y, m nat) nat {
-	var zz, one, rr, RR nat
-
-	numWords := len(m)
-
-	// We want the lengths of x and m to be equal.
-	if len(x) > numWords {
-		_, rr = rr.div(rr, x, m)
-	} else if len(x) < numWords {
-		rr = rr.make(numWords)
-		rr.clear()
-		for i := range x {
-			rr[i] = x[i]
-		}
-	} else {
-		rr = x
-	}
-	x = rr
-
-	// Ideally the precomputations would be performed outside, and reused
-	// k0 = -mˆ-1 mod 2ˆ_W. Algorithm from: Dumas, J.G. "On Newton–Raphson
-	// Iteration for Multiplicative Inverses Modulo Prime Powers".
-	k0 := 2 - m[0]
-	t := m[0] - 1
-	for i := 1; i < _W; i <<= 1 {
-		t *= t
-		k0 *= (t + 1)
-	}
-	k0 = -k0
-
-	// RR = 2ˆ(2*_W*len(m)) mod m
-	RR = RR.setWord(1)
-	zz = zz.shl(RR, uint(2*numWords*_W))
-	_, RR = RR.div(RR, zz, m)
-	if len(RR) < numWords {
-		zz = zz.make(numWords)
-		copy(zz, RR)
-		RR = zz
-	}
-	// one = 1, with equal length to that of m
-	one = one.make(numWords)
-	one.clear()
-	one[0] = 1
-
-	const n = 4
-	// powers[i] contains x^i
-	var powers [1 << n]nat
-	powers[0] = powers[0].montgomery(one, RR, m, k0, numWords)
-	powers[1] = powers[1].montgomery(x, RR, m, k0, numWords)
-	for i := 2; i < 1<<n; i++ {
-		powers[i] = powers[i].montgomery(powers[i-1], powers[1], m, k0, numWords)
-	}
-
-	// initialize z = 1 (Montgomery 1)
-	z = z.make(numWords)
-	copy(z, powers[0])
-
-	zz = zz.make(numWords)
-
-	// same windowed exponent, but with Montgomery multiplications
-	for i := len(y) - 1; i >= 0; i-- {
-		yi := y[i]
-		for j := 0; j < _W; j += n {
-			if i != len(y)-1 || j != 0 {
-				zz = zz.montgomery(z, z, m, k0, numWords)
-				z = z.montgomery(zz, zz, m, k0, numWords)
-				zz = zz.montgomery(z, z, m, k0, numWords)
-				z = z.montgomery(zz, zz, m, k0, numWords)
-			}
-			zz = zz.montgomery(z, powers[yi>>(_W-n)], m, k0, numWords)
-			z, zz = zz, z
-			yi <<= n
-		}
-	}
-	// convert to regular number
-	zz = zz.montgomery(z, one, m, k0, numWords)
-	return zz.norm()
-}
-
 // probablyPrime performs reps Miller-Rabin tests to check whether n is prime.
 // If it returns true, n is prime with probability 1 - 1/4^reps.
 // If it returns false, n is not prime.
@@ -1166,10 +1404,6 @@ func (n nat) probablyPrime(reps int) bool {
 		}
 	}
 
-	if n[0]&1 == 0 {
-		return false // n is even
-	}
-
 	const primesProduct32 = 0xC0CFD797         // Π {p ∈ primes, 2 < p <= 29}
 	const primesProduct64 = 0xE221F97C30E94E1D // Π {p ∈ primes, 2 < p <= 53}
 
diff --git a/src/math/big/nat_test.go b/src/math/big/nat_test.go
index 7ac3cb8..a2ae533 100644
--- a/src/math/big/nat_test.go
+++ b/src/math/big/nat_test.go
@@ -5,6 +5,7 @@
 package big
 
 import (
+	"io"
 	"runtime"
 	"strings"
 	"testing"
@@ -87,7 +88,7 @@ var prodNN = []argNN{
 }
 
 func natFromString(s string) nat {
-	x, _, _, err := nat(nil).scan(strings.NewReader(s), 0, false)
+	x, _, err := nat(nil).scan(strings.NewReader(s), 0)
 	if err != nil {
 		panic(err)
 	}
@@ -205,11 +206,398 @@ func BenchmarkMul(b *testing.B) {
 	}
 }
 
-func TestNLZ(t *testing.T) {
+func toString(x nat, charset string) string {
+	base := len(charset)
+
+	// special cases
+	switch {
+	case base < 2:
+		panic("illegal base")
+	case len(x) == 0:
+		return string(charset[0])
+	}
+
+	// allocate buffer for conversion
+	i := x.bitLen()/log2(Word(base)) + 1 // +1: round up
+	s := make([]byte, i)
+
+	// don't destroy x
+	q := nat(nil).set(x)
+
+	// convert
+	for len(q) > 0 {
+		i--
+		var r Word
+		q, r = q.divW(q, Word(base))
+		s[i] = charset[r]
+	}
+
+	return string(s[i:])
+}
+
+var strTests = []struct {
+	x nat    // nat value to be converted
+	c string // conversion charset
+	s string // expected result
+}{
+	{nil, "01", "0"},
+	{nat{1}, "01", "1"},
+	{nat{0xc5}, "01", "11000101"},
+	{nat{03271}, lowercaseDigits[0:8], "3271"},
+	{nat{10}, lowercaseDigits[0:10], "10"},
+	{nat{1234567890}, uppercaseDigits[0:10], "1234567890"},
+	{nat{0xdeadbeef}, lowercaseDigits[0:16], "deadbeef"},
+	{nat{0xdeadbeef}, uppercaseDigits[0:16], "DEADBEEF"},
+	{nat{0x229be7}, lowercaseDigits[0:17], "1a2b3c"},
+	{nat{0x309663e6}, uppercaseDigits[0:32], "O9COV6"},
+}
+
+func TestString(t *testing.T) {
+	for _, a := range strTests {
+		s := a.x.string(a.c)
+		if s != a.s {
+			t.Errorf("string%+v\n\tgot s = %s; want %s", a, s, a.s)
+		}
+
+		x, b, err := nat(nil).scan(strings.NewReader(a.s), len(a.c))
+		if x.cmp(a.x) != 0 {
+			t.Errorf("scan%+v\n\tgot z = %v; want %v", a, x, a.x)
+		}
+		if b != len(a.c) {
+			t.Errorf("scan%+v\n\tgot b = %d; want %d", a, b, len(a.c))
+		}
+		if err != nil {
+			t.Errorf("scan%+v\n\tgot error = %s", a, err)
+		}
+	}
+}
+
+var natScanTests = []struct {
+	s    string // string to be scanned
+	base int    // input base
+	x    nat    // expected nat
+	b    int    // expected base
+	ok   bool   // expected success
+	next rune   // next character (or 0, if at EOF)
+}{
+	// error: illegal base
+	{base: -1},
+	{base: 1},
+	{base: 37},
+
+	// error: no mantissa
+	{},
+	{s: "?"},
+	{base: 10},
+	{base: 36},
+	{s: "?", base: 10},
+	{s: "0x"},
+	{s: "345", base: 2},
+
+	// no errors
+	{"0", 0, nil, 10, true, 0},
+	{"0", 10, nil, 10, true, 0},
+	{"0", 36, nil, 36, true, 0},
+	{"1", 0, nat{1}, 10, true, 0},
+	{"1", 10, nat{1}, 10, true, 0},
+	{"0 ", 0, nil, 10, true, ' '},
+	{"08", 0, nil, 10, true, '8'},
+	{"018", 0, nat{1}, 8, true, '8'},
+	{"0b1", 0, nat{1}, 2, true, 0},
+	{"0b11000101", 0, nat{0xc5}, 2, true, 0},
+	{"03271", 0, nat{03271}, 8, true, 0},
+	{"10ab", 0, nat{10}, 10, true, 'a'},
+	{"1234567890", 0, nat{1234567890}, 10, true, 0},
+	{"xyz", 36, nat{(33*36+34)*36 + 35}, 36, true, 0},
+	{"xyz?", 36, nat{(33*36+34)*36 + 35}, 36, true, '?'},
+	{"0x", 16, nil, 16, true, 'x'},
+	{"0xdeadbeef", 0, nat{0xdeadbeef}, 16, true, 0},
+	{"0XDEADBEEF", 0, nat{0xdeadbeef}, 16, true, 0},
+}
+
+func TestScanBase(t *testing.T) {
+	for _, a := range natScanTests {
+		r := strings.NewReader(a.s)
+		x, b, err := nat(nil).scan(r, a.base)
+		if err == nil && !a.ok {
+			t.Errorf("scan%+v\n\texpected error", a)
+		}
+		if err != nil {
+			if a.ok {
+				t.Errorf("scan%+v\n\tgot error = %s", a, err)
+			}
+			continue
+		}
+		if x.cmp(a.x) != 0 {
+			t.Errorf("scan%+v\n\tgot z = %v; want %v", a, x, a.x)
+		}
+		if b != a.b {
+			t.Errorf("scan%+v\n\tgot b = %d; want %d", a, b, a.base)
+		}
+		next, _, err := r.ReadRune()
+		if err == io.EOF {
+			next = 0
+			err = nil
+		}
+		if err == nil && next != a.next {
+			t.Errorf("scan%+v\n\tgot next = %q; want %q", a, next, a.next)
+		}
+	}
+}
+
+var pi = "3" +
+	"14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214808651" +
+	"32823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461" +
+	"28475648233786783165271201909145648566923460348610454326648213393607260249141273724587006606315588174881520920" +
+	"96282925409171536436789259036001133053054882046652138414695194151160943305727036575959195309218611738193261179" +
+	"31051185480744623799627495673518857527248912279381830119491298336733624406566430860213949463952247371907021798" +
+	"60943702770539217176293176752384674818467669405132000568127145263560827785771342757789609173637178721468440901" +
+	"22495343014654958537105079227968925892354201995611212902196086403441815981362977477130996051870721134999999837" +
+	"29780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083" +
+	"81420617177669147303598253490428755468731159562863882353787593751957781857780532171226806613001927876611195909" +
+	"21642019893809525720106548586327886593615338182796823030195203530185296899577362259941389124972177528347913151" +
+	"55748572424541506959508295331168617278558890750983817546374649393192550604009277016711390098488240128583616035" +
+	"63707660104710181942955596198946767837449448255379774726847104047534646208046684259069491293313677028989152104" +
+	"75216205696602405803815019351125338243003558764024749647326391419927260426992279678235478163600934172164121992" +
+	"45863150302861829745557067498385054945885869269956909272107975093029553211653449872027559602364806654991198818" +
+	"34797753566369807426542527862551818417574672890977772793800081647060016145249192173217214772350141441973568548" +
+	"16136115735255213347574184946843852332390739414333454776241686251898356948556209921922218427255025425688767179" +
+	"04946016534668049886272327917860857843838279679766814541009538837863609506800642251252051173929848960841284886" +
+	"26945604241965285022210661186306744278622039194945047123713786960956364371917287467764657573962413890865832645" +
+	"99581339047802759009946576407895126946839835259570982582262052248940772671947826848260147699090264013639443745" +
+	"53050682034962524517493996514314298091906592509372216964615157098583874105978859597729754989301617539284681382" +
+	"68683868942774155991855925245953959431049972524680845987273644695848653836736222626099124608051243884390451244" +
+	"13654976278079771569143599770012961608944169486855584840635342207222582848864815845602850601684273945226746767" +
+	"88952521385225499546667278239864565961163548862305774564980355936345681743241125150760694794510965960940252288" +
+	"79710893145669136867228748940560101503308617928680920874760917824938589009714909675985261365549781893129784821" +
+	"68299894872265880485756401427047755513237964145152374623436454285844479526586782105114135473573952311342716610" +
+	"21359695362314429524849371871101457654035902799344037420073105785390621983874478084784896833214457138687519435" +
+	"06430218453191048481005370614680674919278191197939952061419663428754440643745123718192179998391015919561814675" +
+	"14269123974894090718649423196156794520809514655022523160388193014209376213785595663893778708303906979207734672" +
+	"21825625996615014215030680384477345492026054146659252014974428507325186660021324340881907104863317346496514539" +
+	"05796268561005508106658796998163574736384052571459102897064140110971206280439039759515677157700420337869936007" +
+	"23055876317635942187312514712053292819182618612586732157919841484882916447060957527069572209175671167229109816" +
+	"90915280173506712748583222871835209353965725121083579151369882091444210067510334671103141267111369908658516398" +
+	"31501970165151168517143765761835155650884909989859982387345528331635507647918535893226185489632132933089857064" +
+	"20467525907091548141654985946163718027098199430992448895757128289059232332609729971208443357326548938239119325" +
+	"97463667305836041428138830320382490375898524374417029132765618093773444030707469211201913020330380197621101100" +
+	"44929321516084244485963766983895228684783123552658213144957685726243344189303968642624341077322697802807318915" +
+	"44110104468232527162010526522721116603966655730925471105578537634668206531098965269186205647693125705863566201" +
+	"85581007293606598764861179104533488503461136576867532494416680396265797877185560845529654126654085306143444318" +
+	"58676975145661406800700237877659134401712749470420562230538994561314071127000407854733269939081454664645880797" +
+	"27082668306343285878569830523580893306575740679545716377525420211495576158140025012622859413021647155097925923" +
+	"09907965473761255176567513575178296664547791745011299614890304639947132962107340437518957359614589019389713111" +
+	"79042978285647503203198691514028708085990480109412147221317947647772622414254854540332157185306142288137585043" +
+	"06332175182979866223717215916077166925474873898665494945011465406284336639379003976926567214638530673609657120" +
+	"91807638327166416274888800786925602902284721040317211860820419000422966171196377921337575114959501566049631862" +
+	"94726547364252308177036751590673502350728354056704038674351362222477158915049530984448933309634087807693259939" +
+	"78054193414473774418426312986080998886874132604721569516239658645730216315981931951673538129741677294786724229" +
+	"24654366800980676928238280689964004824354037014163149658979409243237896907069779422362508221688957383798623001" +
+	"59377647165122893578601588161755782973523344604281512627203734314653197777416031990665541876397929334419521541" +
+	"34189948544473456738316249934191318148092777710386387734317720754565453220777092120190516609628049092636019759" +
+	"88281613323166636528619326686336062735676303544776280350450777235547105859548702790814356240145171806246436267" +
+	"94561275318134078330336254232783944975382437205835311477119926063813346776879695970309833913077109870408591337"
+
+// Test case for BenchmarkScanPi.
+func TestScanPi(t *testing.T) {
+	var x nat
+	z, _, err := x.scan(strings.NewReader(pi), 10)
+	if err != nil {
+		t.Errorf("scanning pi: %s", err)
+	}
+	if s := z.decimalString(); s != pi {
+		t.Errorf("scanning pi: got %s", s)
+	}
+}
+
+func TestScanPiParallel(t *testing.T) {
+	const n = 2
+	c := make(chan int)
+	for i := 0; i < n; i++ {
+		go func() {
+			TestScanPi(t)
+			c <- 0
+		}()
+	}
+	for i := 0; i < n; i++ {
+		<-c
+	}
+}
+
+func BenchmarkScanPi(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		var x nat
+		x.scan(strings.NewReader(pi), 10)
+	}
+}
+
+func BenchmarkStringPiParallel(b *testing.B) {
+	var x nat
+	x, _, _ = x.scan(strings.NewReader(pi), 0)
+	if x.decimalString() != pi {
+		panic("benchmark incorrect: conversion failed")
+	}
+	b.RunParallel(func(pb *testing.PB) {
+		for pb.Next() {
+			x.decimalString()
+		}
+	})
+}
+
+func BenchmarkScan10Base2(b *testing.B)     { ScanHelper(b, 2, 10, 10) }
+func BenchmarkScan100Base2(b *testing.B)    { ScanHelper(b, 2, 10, 100) }
+func BenchmarkScan1000Base2(b *testing.B)   { ScanHelper(b, 2, 10, 1000) }
+func BenchmarkScan10000Base2(b *testing.B)  { ScanHelper(b, 2, 10, 10000) }
+func BenchmarkScan100000Base2(b *testing.B) { ScanHelper(b, 2, 10, 100000) }
+
+func BenchmarkScan10Base8(b *testing.B)     { ScanHelper(b, 8, 10, 10) }
+func BenchmarkScan100Base8(b *testing.B)    { ScanHelper(b, 8, 10, 100) }
+func BenchmarkScan1000Base8(b *testing.B)   { ScanHelper(b, 8, 10, 1000) }
+func BenchmarkScan10000Base8(b *testing.B)  { ScanHelper(b, 8, 10, 10000) }
+func BenchmarkScan100000Base8(b *testing.B) { ScanHelper(b, 8, 10, 100000) }
+
+func BenchmarkScan10Base10(b *testing.B)     { ScanHelper(b, 10, 10, 10) }
+func BenchmarkScan100Base10(b *testing.B)    { ScanHelper(b, 10, 10, 100) }
+func BenchmarkScan1000Base10(b *testing.B)   { ScanHelper(b, 10, 10, 1000) }
+func BenchmarkScan10000Base10(b *testing.B)  { ScanHelper(b, 10, 10, 10000) }
+func BenchmarkScan100000Base10(b *testing.B) { ScanHelper(b, 10, 10, 100000) }
+
+func BenchmarkScan10Base16(b *testing.B)     { ScanHelper(b, 16, 10, 10) }
+func BenchmarkScan100Base16(b *testing.B)    { ScanHelper(b, 16, 10, 100) }
+func BenchmarkScan1000Base16(b *testing.B)   { ScanHelper(b, 16, 10, 1000) }
+func BenchmarkScan10000Base16(b *testing.B)  { ScanHelper(b, 16, 10, 10000) }
+func BenchmarkScan100000Base16(b *testing.B) { ScanHelper(b, 16, 10, 100000) }
+
+func ScanHelper(b *testing.B, base int, x, y Word) {
+	b.StopTimer()
+	var z nat
+	z = z.expWW(x, y)
+
+	var s string
+	s = z.string(lowercaseDigits[0:base])
+	if t := toString(z, lowercaseDigits[0:base]); t != s {
+		b.Fatalf("scanning: got %s; want %s", s, t)
+	}
+	b.StartTimer()
+
+	for i := 0; i < b.N; i++ {
+		z.scan(strings.NewReader(s), base)
+	}
+}
+
+func BenchmarkString10Base2(b *testing.B)     { StringHelper(b, 2, 10, 10) }
+func BenchmarkString100Base2(b *testing.B)    { StringHelper(b, 2, 10, 100) }
+func BenchmarkString1000Base2(b *testing.B)   { StringHelper(b, 2, 10, 1000) }
+func BenchmarkString10000Base2(b *testing.B)  { StringHelper(b, 2, 10, 10000) }
+func BenchmarkString100000Base2(b *testing.B) { StringHelper(b, 2, 10, 100000) }
+
+func BenchmarkString10Base8(b *testing.B)     { StringHelper(b, 8, 10, 10) }
+func BenchmarkString100Base8(b *testing.B)    { StringHelper(b, 8, 10, 100) }
+func BenchmarkString1000Base8(b *testing.B)   { StringHelper(b, 8, 10, 1000) }
+func BenchmarkString10000Base8(b *testing.B)  { StringHelper(b, 8, 10, 10000) }
+func BenchmarkString100000Base8(b *testing.B) { StringHelper(b, 8, 10, 100000) }
+
+func BenchmarkString10Base10(b *testing.B)     { StringHelper(b, 10, 10, 10) }
+func BenchmarkString100Base10(b *testing.B)    { StringHelper(b, 10, 10, 100) }
+func BenchmarkString1000Base10(b *testing.B)   { StringHelper(b, 10, 10, 1000) }
+func BenchmarkString10000Base10(b *testing.B)  { StringHelper(b, 10, 10, 10000) }
+func BenchmarkString100000Base10(b *testing.B) { StringHelper(b, 10, 10, 100000) }
+
+func BenchmarkString10Base16(b *testing.B)     { StringHelper(b, 16, 10, 10) }
+func BenchmarkString100Base16(b *testing.B)    { StringHelper(b, 16, 10, 100) }
+func BenchmarkString1000Base16(b *testing.B)   { StringHelper(b, 16, 10, 1000) }
+func BenchmarkString10000Base16(b *testing.B)  { StringHelper(b, 16, 10, 10000) }
+func BenchmarkString100000Base16(b *testing.B) { StringHelper(b, 16, 10, 100000) }
+
+func StringHelper(b *testing.B, base int, x, y Word) {
+	b.StopTimer()
+	var z nat
+	z = z.expWW(x, y)
+	z.string(lowercaseDigits[0:base]) // warm divisor cache
+	b.StartTimer()
+
+	for i := 0; i < b.N; i++ {
+		_ = z.string(lowercaseDigits[0:base])
+	}
+}
+
+func BenchmarkLeafSize0(b *testing.B)  { LeafSizeHelper(b, 10, 0) } // test without splitting
+func BenchmarkLeafSize1(b *testing.B)  { LeafSizeHelper(b, 10, 1) }
+func BenchmarkLeafSize2(b *testing.B)  { LeafSizeHelper(b, 10, 2) }
+func BenchmarkLeafSize3(b *testing.B)  { LeafSizeHelper(b, 10, 3) }
+func BenchmarkLeafSize4(b *testing.B)  { LeafSizeHelper(b, 10, 4) }
+func BenchmarkLeafSize5(b *testing.B)  { LeafSizeHelper(b, 10, 5) }
+func BenchmarkLeafSize6(b *testing.B)  { LeafSizeHelper(b, 10, 6) }
+func BenchmarkLeafSize7(b *testing.B)  { LeafSizeHelper(b, 10, 7) }
+func BenchmarkLeafSize8(b *testing.B)  { LeafSizeHelper(b, 10, 8) }
+func BenchmarkLeafSize9(b *testing.B)  { LeafSizeHelper(b, 10, 9) }
+func BenchmarkLeafSize10(b *testing.B) { LeafSizeHelper(b, 10, 10) }
+func BenchmarkLeafSize11(b *testing.B) { LeafSizeHelper(b, 10, 11) }
+func BenchmarkLeafSize12(b *testing.B) { LeafSizeHelper(b, 10, 12) }
+func BenchmarkLeafSize13(b *testing.B) { LeafSizeHelper(b, 10, 13) }
+func BenchmarkLeafSize14(b *testing.B) { LeafSizeHelper(b, 10, 14) }
+func BenchmarkLeafSize15(b *testing.B) { LeafSizeHelper(b, 10, 15) }
+func BenchmarkLeafSize16(b *testing.B) { LeafSizeHelper(b, 10, 16) }
+func BenchmarkLeafSize32(b *testing.B) { LeafSizeHelper(b, 10, 32) } // try some large lengths
+func BenchmarkLeafSize64(b *testing.B) { LeafSizeHelper(b, 10, 64) }
+
+func LeafSizeHelper(b *testing.B, base Word, size int) {
+	b.StopTimer()
+	originalLeafSize := leafSize
+	resetTable(cacheBase10.table[:])
+	leafSize = size
+	b.StartTimer()
+
+	for d := 1; d <= 10000; d *= 10 {
+		b.StopTimer()
+		var z nat
+		z = z.expWW(base, Word(d))            // build target number
+		_ = z.string(lowercaseDigits[0:base]) // warm divisor cache
+		b.StartTimer()
+
+		for i := 0; i < b.N; i++ {
+			_ = z.string(lowercaseDigits[0:base])
+		}
+	}
+
+	b.StopTimer()
+	resetTable(cacheBase10.table[:])
+	leafSize = originalLeafSize
+	b.StartTimer()
+}
+
+func resetTable(table []divisor) {
+	if table != nil && table[0].bbb != nil {
+		for i := 0; i < len(table); i++ {
+			table[i].bbb = nil
+			table[i].nbits = 0
+			table[i].ndigits = 0
+		}
+	}
+}
+
+func TestStringPowers(t *testing.T) {
+	var b, p Word
+	for b = 2; b <= 16; b++ {
+		for p = 0; p <= 512; p++ {
+			x := nat(nil).expWW(b, p)
+			xs := x.string(lowercaseDigits[0:b])
+			xs2 := toString(x, lowercaseDigits[0:b])
+			if xs != xs2 {
+				t.Errorf("failed at %d ** %d in base %d: %s != %s", b, p, b, xs, xs2)
+			}
+		}
+		if b >= 3 && testing.Short() {
+			break
+		}
+	}
+}
+
+func TestLeadingZeros(t *testing.T) {
 	var x Word = _B >> 1
 	for i := 0; i <= _W; i++ {
-		if int(nlz(x)) != i {
-			t.Errorf("failed at %x: got %d want %d", x, nlz(x), i)
+		if int(leadingZeros(x)) != i {
+			t.Errorf("failed at %x: got %d want %d", x, leadingZeros(x), i)
 		}
 		x >>= 1
 	}
@@ -303,96 +691,25 @@ func TestModW(t *testing.T) {
 }
 
 func TestTrailingZeroBits(t *testing.T) {
-	// test 0 case explicitly
-	if n := trailingZeroBits(0); n != 0 {
-		t.Errorf("got trailingZeroBits(0) = %d; want 0", n)
-	}
-
 	x := Word(1)
-	for i := uint(0); i < _W; i++ {
+	for i := uint(0); i <= _W; i++ {
 		n := trailingZeroBits(x)
-		if n != i {
+		if n != i%_W {
 			t.Errorf("got trailingZeroBits(%#x) = %d; want %d", x, n, i%_W)
 		}
 		x <<= 1
 	}
 
-	// test 0 case explicitly
-	if n := nat(nil).trailingZeroBits(); n != 0 {
-		t.Errorf("got nat(nil).trailingZeroBits() = %d; want 0", n)
-	}
-
 	y := nat(nil).set(natOne)
 	for i := uint(0); i <= 3*_W; i++ {
 		n := y.trailingZeroBits()
 		if n != i {
-			t.Errorf("got 0x%s.trailingZeroBits() = %d; want %d", y.hexString(), n, i)
+			t.Errorf("got 0x%s.trailingZeroBits() = %d; want %d", y.string(lowercaseDigits[0:16]), n, i)
 		}
 		y = y.shl(y, 1)
 	}
 }
 
-var montgomeryTests = []struct {
-	x, y, m      string
-	k0           uint64
-	out32, out64 string
-}{
-	{
-		"0xffffffffffffffffffffffffffffffffffffffffffffffffe",
-		"0xffffffffffffffffffffffffffffffffffffffffffffffffe",
-		"0xfffffffffffffffffffffffffffffffffffffffffffffffff",
-		0x0000000000000000,
-		"0xffffffffffffffffffffffffffffffffffffffffff",
-		"0xffffffffffffffffffffffffffffffffff",
-	},
-	{
-		"0x0000000080000000",
-		"0x00000000ffffffff",
-		"0x0000000010000001",
-		0xff0000000fffffff,
-		"0x0000000088000000",
-		"0x0000000007800001",
-	},
-	{
-		"0xffffffffffffffffffffffffffffffff00000000000022222223333333333444444444",
-		"0xffffffffffffffffffffffffffffffff999999999999999aaabbbbbbbbcccccccccccc",
-		"0x33377fffffffffffffffffffffffffffffffffffffffffffff0000000000022222eee1",
-		0xdecc8f1249812adf,
-		"0x22bb05b6d95eaaeca2bb7c05e51f807bce9064b5fbad177161695e4558f9474e91cd79",
-		"0x14beb58d230f85b6d95eaaeca2bb7c05e51f807bce9064b5fb45669afa695f228e48cd",
-	},
-	{
-		"0x10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffff00000000000022222223333333333444444444",
-		"0x10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffff999999999999999aaabbbbbbbbcccccccccccc",
-		"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff33377fffffffffffffffffffffffffffffffffffffffffffff0000000000022222eee1",
-		0xdecc8f1249812adf,
-		"0x5c0d52f451aec609b15da8e5e5626c4eaa88723bdeac9d25ca9b961269400410ca208a16af9c2fb07d7a11c7772cba02c22f9711078d51a3797eb18e691295293284d988e349fa6deba46b25a4ecd9f715",
-		"0x92fcad4b5c0d52f451aec609b15da8e5e5626c4eaa88723bdeac9d25ca9b961269400410ca208a16af9c2fb07d799c32fe2f3cc5422f9711078d51a3797eb18e691295293284d8f5e69caf6decddfe1df6",
-	},
-}
-
-func TestMontgomery(t *testing.T) {
-	for i, test := range montgomeryTests {
-		x := natFromString(test.x)
-		y := natFromString(test.y)
-		m := natFromString(test.m)
-
-		var out nat
-		if _W == 32 {
-			out = natFromString(test.out32)
-		} else {
-			out = natFromString(test.out64)
-		}
-
-		k0 := Word(test.k0 & _M) // mask k0 to ensure that it fits for 32-bit systems.
-		z := nat(nil).montgomery(x, y, m, k0, len(m))
-		z = z.norm()
-		if z.cmp(out) != 0 {
-			t.Errorf("#%d got %s want %s", i, z.decimalString(), out.decimalString())
-		}
-	}
-}
-
 var expNNTests = []struct {
 	x, y, m string
 	out     string
@@ -418,13 +735,14 @@ var expNNTests = []struct {
 
 func TestExpNN(t *testing.T) {
 	for i, test := range expNNTests {
-		x := natFromString(test.x)
-		y := natFromString(test.y)
-		out := natFromString(test.out)
+		x, _, _ := nat(nil).scan(strings.NewReader(test.x), 0)
+		y, _, _ := nat(nil).scan(strings.NewReader(test.y), 0)
+		out, _, _ := nat(nil).scan(strings.NewReader(test.out), 0)
 
 		var m nat
+
 		if len(test.m) > 0 {
-			m = natFromString(test.m)
+			m, _, _ = nat(nil).scan(strings.NewReader(test.m), 0)
 		}
 
 		z := nat(nil).expNN(x, y, m)
@@ -451,129 +769,3 @@ func BenchmarkExp3Power0x10000(b *testing.B)  { ExpHelper(b, 3, 0x10000) }
 func BenchmarkExp3Power0x40000(b *testing.B)  { ExpHelper(b, 3, 0x40000) }
 func BenchmarkExp3Power0x100000(b *testing.B) { ExpHelper(b, 3, 0x100000) }
 func BenchmarkExp3Power0x400000(b *testing.B) { ExpHelper(b, 3, 0x400000) }
-
-func fibo(n int) nat {
-	switch n {
-	case 0:
-		return nil
-	case 1:
-		return nat{1}
-	}
-	f0 := fibo(0)
-	f1 := fibo(1)
-	var f2 nat
-	for i := 1; i < n; i++ {
-		f2 = f2.add(f0, f1)
-		f0, f1, f2 = f1, f2, f0
-	}
-	return f1
-}
-
-var fiboNums = []string{
-	"0",
-	"55",
-	"6765",
-	"832040",
-	"102334155",
-	"12586269025",
-	"1548008755920",
-	"190392490709135",
-	"23416728348467685",
-	"2880067194370816120",
-	"354224848179261915075",
-}
-
-func TestFibo(t *testing.T) {
-	for i, want := range fiboNums {
-		n := i * 10
-		got := fibo(n).decimalString()
-		if got != want {
-			t.Errorf("fibo(%d) failed: got %s want %s", n, got, want)
-		}
-	}
-}
-
-func BenchmarkFibo(b *testing.B) {
-	for i := 0; i < b.N; i++ {
-		fibo(1e0)
-		fibo(1e1)
-		fibo(1e2)
-		fibo(1e3)
-		fibo(1e4)
-		fibo(1e5)
-	}
-}
-
-var bitTests = []struct {
-	x    string
-	i    uint
-	want uint
-}{
-	{"0", 0, 0},
-	{"0", 1, 0},
-	{"0", 1000, 0},
-
-	{"0x1", 0, 1},
-	{"0x10", 0, 0},
-	{"0x10", 3, 0},
-	{"0x10", 4, 1},
-	{"0x10", 5, 0},
-
-	{"0x8000000000000000", 62, 0},
-	{"0x8000000000000000", 63, 1},
-	{"0x8000000000000000", 64, 0},
-
-	{"0x3" + strings.Repeat("0", 32), 127, 0},
-	{"0x3" + strings.Repeat("0", 32), 128, 1},
-	{"0x3" + strings.Repeat("0", 32), 129, 1},
-	{"0x3" + strings.Repeat("0", 32), 130, 0},
-}
-
-func TestBit(t *testing.T) {
-	for i, test := range bitTests {
-		x := natFromString(test.x)
-		if got := x.bit(test.i); got != test.want {
-			t.Errorf("#%d: %s.bit(%d) = %v; want %v", i, test.x, test.i, got, test.want)
-		}
-	}
-}
-
-var stickyTests = []struct {
-	x    string
-	i    uint
-	want uint
-}{
-	{"0", 0, 0},
-	{"0", 1, 0},
-	{"0", 1000, 0},
-
-	{"0x1", 0, 0},
-	{"0x1", 1, 1},
-
-	{"0x1350", 0, 0},
-	{"0x1350", 4, 0},
-	{"0x1350", 5, 1},
-
-	{"0x8000000000000000", 63, 0},
-	{"0x8000000000000000", 64, 1},
-
-	{"0x1" + strings.Repeat("0", 100), 400, 0},
-	{"0x1" + strings.Repeat("0", 100), 401, 1},
-}
-
-func TestSticky(t *testing.T) {
-	for i, test := range stickyTests {
-		x := natFromString(test.x)
-		if got := x.sticky(test.i); got != test.want {
-			t.Errorf("#%d: %s.sticky(%d) = %v; want %v", i, test.x, test.i, got, test.want)
-		}
-		if test.want == 1 {
-			// all subsequent i's should also return 1
-			for d := uint(1); d <= 3; d++ {
-				if got := x.sticky(test.i + d); got != 1 {
-					t.Errorf("#%d: %s.sticky(%d) = %v; want %v", i, test.x, test.i+d, got, 1)
-				}
-			}
-		}
-	}
-}
diff --git a/src/math/big/rat.go b/src/math/big/rat.go
index fb16f18..c5339fe 100644
--- a/src/math/big/rat.go
+++ b/src/math/big/rat.go
@@ -11,6 +11,7 @@ import (
 	"errors"
 	"fmt"
 	"math"
+	"strings"
 )
 
 // A Rat represents a quotient a/b of arbitrary precision.
@@ -323,14 +324,14 @@ func (z *Rat) SetFrac64(a, b int64) *Rat {
 // SetInt sets z to x (by making a copy of x) and returns z.
 func (z *Rat) SetInt(x *Int) *Rat {
 	z.a.Set(x)
-	z.b.abs = z.b.abs[:0]
+	z.b.abs = z.b.abs.make(0)
 	return z
 }
 
 // SetInt64 sets z to x and returns z.
 func (z *Rat) SetInt64(x int64) *Rat {
 	z.a.SetInt64(x)
-	z.b.abs = z.b.abs[:0]
+	z.b.abs = z.b.abs.make(0)
 	return z
 }
 
@@ -369,7 +370,7 @@ func (z *Rat) Inv(x *Rat) *Rat {
 	}
 	b := z.a.abs
 	if b.cmp(natOne) == 0 {
-		b = b[:0] // normalize denominator
+		b = b.make(0) // normalize denominator
 	}
 	z.a.abs, z.b.abs = a, b // sign doesn't change
 	return z
@@ -385,7 +386,7 @@ func (x *Rat) Sign() int {
 	return x.a.Sign()
 }
 
-// IsInt reports whether the denominator of x is 1.
+// IsInt returns true if the denominator of x is 1.
 func (x *Rat) IsInt() bool {
 	return len(x.b.abs) == 0 || x.b.abs.cmp(natOne) == 0
 }
@@ -414,12 +415,12 @@ func (z *Rat) norm() *Rat {
 	case len(z.a.abs) == 0:
 		// z == 0 - normalize sign and denominator
 		z.a.neg = false
-		z.b.abs = z.b.abs[:0]
+		z.b.abs = z.b.abs.make(0)
 	case len(z.b.abs) == 0:
 		// z is normalized int - nothing to do
 	case z.b.abs.cmp(natOne) == 0:
 		// z is int - normalize denominator
-		z.b.abs = z.b.abs[:0]
+		z.b.abs = z.b.abs.make(0)
 	default:
 		neg := z.a.neg
 		z.a.neg = false
@@ -429,7 +430,7 @@ func (z *Rat) norm() *Rat {
 			z.b.abs, _ = z.b.abs.div(nil, z.b.abs, f.abs)
 			if z.b.abs.cmp(natOne) == 0 {
 				// z is int - normalize denominator
-				z.b.abs = z.b.abs[:0]
+				z.b.abs = z.b.abs.make(0)
 			}
 		}
 		z.a.neg = neg
@@ -511,6 +512,151 @@ func (z *Rat) Quo(x, y *Rat) *Rat {
 	return z.norm()
 }
 
+func ratTok(ch rune) bool {
+	return strings.IndexRune("+-/0123456789.eE", ch) >= 0
+}
+
+// Scan is a support routine for fmt.Scanner. It accepts the formats
+// 'e', 'E', 'f', 'F', 'g', 'G', and 'v'. All formats are equivalent.
+func (z *Rat) Scan(s fmt.ScanState, ch rune) error {
+	tok, err := s.Token(true, ratTok)
+	if err != nil {
+		return err
+	}
+	if strings.IndexRune("efgEFGv", ch) < 0 {
+		return errors.New("Rat.Scan: invalid verb")
+	}
+	if _, ok := z.SetString(string(tok)); !ok {
+		return errors.New("Rat.Scan: invalid syntax")
+	}
+	return nil
+}
+
+// SetString sets z to the value of s and returns z and a boolean indicating
+// success. s can be given as a fraction "a/b" or as a floating-point number
+// optionally followed by an exponent. If the operation failed, the value of
+// z is undefined but the returned value is nil.
+func (z *Rat) SetString(s string) (*Rat, bool) {
+	if len(s) == 0 {
+		return nil, false
+	}
+
+	// check for a quotient
+	sep := strings.Index(s, "/")
+	if sep >= 0 {
+		if _, ok := z.a.SetString(s[0:sep], 10); !ok {
+			return nil, false
+		}
+		s = s[sep+1:]
+		var err error
+		if z.b.abs, _, err = z.b.abs.scan(strings.NewReader(s), 10); err != nil {
+			return nil, false
+		}
+		if len(z.b.abs) == 0 {
+			return nil, false
+		}
+		return z.norm(), true
+	}
+
+	// check for a decimal point
+	sep = strings.Index(s, ".")
+	// check for an exponent
+	e := strings.IndexAny(s, "eE")
+	var exp Int
+	if e >= 0 {
+		if e < sep {
+			// The E must come after the decimal point.
+			return nil, false
+		}
+		if _, ok := exp.SetString(s[e+1:], 10); !ok {
+			return nil, false
+		}
+		s = s[0:e]
+	}
+	if sep >= 0 {
+		s = s[0:sep] + s[sep+1:]
+		exp.Sub(&exp, NewInt(int64(len(s)-sep)))
+	}
+
+	if _, ok := z.a.SetString(s, 10); !ok {
+		return nil, false
+	}
+	powTen := nat(nil).expNN(natTen, exp.abs, nil)
+	if exp.neg {
+		z.b.abs = powTen
+		z.norm()
+	} else {
+		z.a.abs = z.a.abs.mul(z.a.abs, powTen)
+		z.b.abs = z.b.abs.make(0)
+	}
+
+	return z, true
+}
+
+// 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 {
+		s = "/" + x.b.abs.decimalString()
+	}
+	return x.a.String() + s
+}
+
+// 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() {
+		return x.a.String()
+	}
+	return x.String()
+}
+
+// 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() {
+		s := x.a.String()
+		if prec > 0 {
+			s += "." + strings.Repeat("0", prec)
+		}
+		return s
+	}
+	// x.b.abs != 0
+
+	q, r := nat(nil).div(nat(nil), x.a.abs, x.b.abs)
+
+	p := natOne
+	if prec > 0 {
+		p = nat(nil).expNN(natTen, nat(nil).setUint64(uint64(prec)), nil)
+	}
+
+	r = r.mul(r, p)
+	r, r2 := r.div(nat(nil), r, x.b.abs)
+
+	// see if we need to round up
+	r2 = r2.add(r2, r2)
+	if x.b.abs.cmp(r2) <= 0 {
+		r = r.add(r, natOne)
+		if r.cmp(p) >= 0 {
+			q = nat(nil).add(q, natOne)
+			r = nat(nil).sub(r, p)
+		}
+	}
+
+	s := q.decimalString()
+	if x.a.neg {
+		s = "-" + s
+	}
+
+	if prec > 0 {
+		rs := r.decimalString()
+		leadingZeros := prec - len(rs)
+		s += "." + strings.Repeat("0", leadingZeros) + rs
+	}
+
+	return s
+}
+
 // Gob codec version. Permits backward-compatible changes to the encoding.
 const ratGobVersion byte = 1
 
@@ -521,7 +667,7 @@ func (x *Rat) GobEncode() ([]byte, error) {
 	}
 	buf := make([]byte, 1+4+(len(x.a.abs)+len(x.b.abs))*_S) // extra bytes for version and sign bit (1), and numerator length (4)
 	i := x.b.abs.bytes(buf)
-	j := x.a.abs.bytes(buf[:i])
+	j := x.a.abs.bytes(buf[0:i])
 	n := i - j
 	if int(uint32(n)) != n {
 		// this should never happen
@@ -546,7 +692,7 @@ func (z *Rat) GobDecode(buf []byte) error {
 	}
 	b := buf[0]
 	if b>>1 != ratGobVersion {
-		return fmt.Errorf("Rat.GobDecode: encoding version %d not supported", b>>1)
+		return errors.New(fmt.Sprintf("Rat.GobDecode: encoding version %d not supported", b>>1))
 	}
 	const j = 1 + 4
 	i := j + binary.BigEndian.Uint32(buf[j-4:j])
diff --git a/src/math/big/rat_test.go b/src/math/big/rat_test.go
index 012d0c4..5dbbb35 100644
--- a/src/math/big/rat_test.go
+++ b/src/math/big/rat_test.go
@@ -9,7 +9,10 @@ import (
 	"encoding/gob"
 	"encoding/json"
 	"encoding/xml"
+	"fmt"
 	"math"
+	"strconv"
+	"strings"
 	"testing"
 )
 
@@ -53,6 +56,112 @@ func TestZeroRat(t *testing.T) {
 	z.Quo(&x, &y)
 }
 
+var setStringTests = []struct {
+	in, out string
+	ok      bool
+}{
+	{"0", "0", true},
+	{"-0", "0", true},
+	{"1", "1", true},
+	{"-1", "-1", true},
+	{"1.", "1", true},
+	{"1e0", "1", true},
+	{"1.e1", "10", true},
+	{in: "1e", ok: false},
+	{in: "1.e", ok: false},
+	{in: "1e+14e-5", ok: false},
+	{in: "1e4.5", ok: false},
+	{in: "r", ok: false},
+	{in: "a/b", ok: false},
+	{in: "a.b", ok: false},
+	{"-0.1", "-1/10", true},
+	{"-.1", "-1/10", true},
+	{"2/4", "1/2", true},
+	{".25", "1/4", true},
+	{"-1/5", "-1/5", true},
+	{"8129567.7690E14", "812956776900000000000", true},
+	{"78189e+4", "781890000", true},
+	{"553019.8935e+8", "55301989350000", true},
+	{"98765432109876543210987654321e-10", "98765432109876543210987654321/10000000000", true},
+	{"9877861857500000E-7", "3951144743/4", true},
+	{"2169378.417e-3", "2169378417/1000000", true},
+	{"884243222337379604041632732738665534", "884243222337379604041632732738665534", true},
+	{"53/70893980658822810696", "53/70893980658822810696", true},
+	{"106/141787961317645621392", "53/70893980658822810696", true},
+	{"204211327800791583.81095", "4084226556015831676219/20000", true},
+	{in: "1/0", ok: false},
+}
+
+func TestRatSetString(t *testing.T) {
+	for i, test := range setStringTests {
+		x, ok := new(Rat).SetString(test.in)
+
+		if ok {
+			if !test.ok {
+				t.Errorf("#%d SetString(%q) expected failure", i, test.in)
+			} else if x.RatString() != test.out {
+				t.Errorf("#%d SetString(%q) got %s want %s", i, test.in, x.RatString(), test.out)
+			}
+		} else if x != nil {
+			t.Errorf("#%d SetString(%q) got %p want nil", i, test.in, x)
+		}
+	}
+}
+
+func TestRatScan(t *testing.T) {
+	var buf bytes.Buffer
+	for i, test := range setStringTests {
+		x := new(Rat)
+		buf.Reset()
+		buf.WriteString(test.in)
+
+		_, err := fmt.Fscanf(&buf, "%v", x)
+		if err == nil != test.ok {
+			if test.ok {
+				t.Errorf("#%d error: %s", i, err)
+			} else {
+				t.Errorf("#%d expected error", i)
+			}
+			continue
+		}
+		if err == nil && x.RatString() != test.out {
+			t.Errorf("#%d got %s want %s", i, x.RatString(), test.out)
+		}
+	}
+}
+
+var floatStringTests = []struct {
+	in   string
+	prec int
+	out  string
+}{
+	{"0", 0, "0"},
+	{"0", 4, "0.0000"},
+	{"1", 0, "1"},
+	{"1", 2, "1.00"},
+	{"-1", 0, "-1"},
+	{".25", 2, "0.25"},
+	{".25", 1, "0.3"},
+	{".25", 3, "0.250"},
+	{"-1/3", 3, "-0.333"},
+	{"-2/3", 4, "-0.6667"},
+	{"0.96", 1, "1.0"},
+	{"0.999", 2, "1.00"},
+	{"0.9", 0, "1"},
+	{".25", -1, "0"},
+	{".55", -1, "1"},
+}
+
+func TestFloatString(t *testing.T) {
+	for i, test := range floatStringTests {
+		x, _ := new(Rat).SetString(test.in)
+
+		if x.FloatString(test.prec) != test.out {
+			t.Errorf("#%d got %s want %s", i, x.FloatString(test.prec), test.out)
+		}
+	}
+}
+
 func TestRatSign(t *testing.T) {
 	zero := NewRat(0, 1)
 	for _, a := range setStringTests {
@@ -483,6 +592,321 @@ func TestIssue3521(t *testing.T) {
 	}
 }
 
+// Test inputs to Rat.SetString.  The prefix "long:" causes the test
+// to be skipped in --test.short mode.  (The threshold is about 500us.)
+var float64inputs = []string{
+	// Constants plundered from strconv/testfp.txt.
+
+	// Table 1: Stress Inputs for Conversion to 53-bit Binary, < 1/2 ULP
+	"5e+125",
+	"69e+267",
+	"999e-026",
+	"7861e-034",
+	"75569e-254",
+	"928609e-261",
+	"9210917e+080",
+	"84863171e+114",
+	"653777767e+273",
+	"5232604057e-298",
+	"27235667517e-109",
+	"653532977297e-123",
+	"3142213164987e-294",
+	"46202199371337e-072",
+	"231010996856685e-073",
+	"9324754620109615e+212",
+	"78459735791271921e+049",
+	"272104041512242479e+200",
+	"6802601037806061975e+198",
+	"20505426358836677347e-221",
+	"836168422905420598437e-234",
+	"4891559871276714924261e+222",
+
+	// Table 2: Stress Inputs for Conversion to 53-bit Binary, > 1/2 ULP
+	"9e-265",
+	"85e-037",
+	"623e+100",
+	"3571e+263",
+	"81661e+153",
+	"920657e-023",
+	"4603285e-024",
+	"87575437e-309",
+	"245540327e+122",
+	"6138508175e+120",
+	"83356057653e+193",
+	"619534293513e+124",
+	"2335141086879e+218",
+	"36167929443327e-159",
+	"609610927149051e-255",
+	"3743626360493413e-165",
+	"94080055902682397e-242",
+	"899810892172646163e+283",
+	"7120190517612959703e+120",
+	"25188282901709339043e-252",
+	"308984926168550152811e-052",
+	"6372891218502368041059e+064",
+
+	// Table 14: Stress Inputs for Conversion to 24-bit Binary, <1/2 ULP
+	"5e-20",
+	"67e+14",
+	"985e+15",
+	"7693e-42",
+	"55895e-16",
+	"996622e-44",
+	"7038531e-32",
+	"60419369e-46",
+	"702990899e-20",
+	"6930161142e-48",
+	"25933168707e+13",
+	"596428896559e+20",
+
+	// Table 15: Stress Inputs for Conversion to 24-bit Binary, >1/2 ULP
+	"3e-23",
+	"57e+18",
+	"789e-35",
+	"2539e-18",
+	"76173e+28",
+	"887745e-11",
+	"5382571e-37",
+	"82381273e-35",
+	"750486563e-38",
+	"3752432815e-39",
+	"75224575729e-45",
+	"459926601011e+15",
+
+	// Constants plundered from strconv/atof_test.go.
+
+	"0",
+	"1",
+	"+1",
+	"1e23",
+	"1E23",
+	"100000000000000000000000",
+	"1e-100",
+	"123456700",
+	"99999999999999974834176",
+	"100000000000000000000001",
+	"100000000000000008388608",
+	"100000000000000016777215",
+	"100000000000000016777216",
+	"-1",
+	"-0.1",
+	"-0", // NB: exception made for this input
+	"1e-20",
+	"625e-3",
+
+	// largest float64
+	"1.7976931348623157e308",
+	"-1.7976931348623157e308",
+	// next float64 - too large
+	"1.7976931348623159e308",
+	"-1.7976931348623159e308",
+	// the border is ...158079
+	// borderline - okay
+	"1.7976931348623158e308",
+	"-1.7976931348623158e308",
+	// borderline - too large
+	"1.797693134862315808e308",
+	"-1.797693134862315808e308",
+
+	// a little too large
+	"1e308",
+	"2e308",
+	"1e309",
+
+	// way too large
+	"1e310",
+	"-1e310",
+	"1e400",
+	"-1e400",
+	"long:1e400000",
+	"long:-1e400000",
+
+	// denormalized
+	"1e-305",
+	"1e-306",
+	"1e-307",
+	"1e-308",
+	"1e-309",
+	"1e-310",
+	"1e-322",
+	// smallest denormal
+	"5e-324",
+	"4e-324",
+	"3e-324",
+	// too small
+	"2e-324",
+	// way too small
+	"1e-350",
+	"long:1e-400000",
+	// way too small, negative
+	"-1e-350",
+	"long:-1e-400000",
+
+	// try to overflow exponent
+	// [Disabled: too slow and memory-hungry with rationals.]
+	// "1e-4294967296",
+	// "1e+4294967296",
+	// "1e-18446744073709551616",
+	// "1e+18446744073709551616",
+
+	// http://www.exploringbinary.com/java-hangs-when-converting-2-2250738585072012e-308/
+	"2.2250738585072012e-308",
+	// http://www.exploringbinary.com/php-hangs-on-numeric-value-2-2250738585072011e-308/
+	"2.2250738585072011e-308",
+
+	// A very large number (initially wrongly parsed by the fast algorithm).
+	"4.630813248087435e+307",
+
+	// A different kind of very large number.
+	"22.222222222222222",
+	"long:2." + strings.Repeat("2", 4000) + "e+1",
+
+	// Exactly halfway between 1 and math.Nextafter(1, 2).
+	// Round to even (down).
+	"1.00000000000000011102230246251565404236316680908203125",
+	// Slightly lower; still round down.
+	"1.00000000000000011102230246251565404236316680908203124",
+	// Slightly higher; round up.
+	"1.00000000000000011102230246251565404236316680908203126",
+	// Slightly higher, but you have to read all the way to the end.
+	"long:1.00000000000000011102230246251565404236316680908203125" + strings.Repeat("0", 10000) + "1",
+
+	// Smallest denormal, 2^(-1022-52)
+	"4.940656458412465441765687928682213723651e-324",
+	// Half of smallest denormal, 2^(-1022-53)
+	"2.470328229206232720882843964341106861825e-324",
+	// A little more than the exact half of smallest denormal
+	// 2^-1075 + 2^-1100.  (Rounds to 1p-1074.)
+	"2.470328302827751011111470718709768633275e-324",
+	// The exact halfway between smallest normal and largest denormal:
+	// 2^-1022 - 2^-1075.  (Rounds to 2^-1022.)
+	"2.225073858507201136057409796709131975935e-308",
+
+	"1152921504606846975",  //   1<<60 - 1
+	"-1152921504606846975", // -(1<<60 - 1)
+	"1152921504606846977",  //   1<<60 + 1
+	"-1152921504606846977", // -(1<<60 + 1)
+
+	"1/3",
+}
+
+// isFinite reports whether f represents a finite rational value.
+// It is equivalent to !math.IsNan(f) && !math.IsInf(f, 0).
+func isFinite(f float64) bool {
+	return math.Abs(f) <= math.MaxFloat64
+}
+
+func TestFloat32SpecialCases(t *testing.T) {
+	for _, input := range float64inputs {
+		if strings.HasPrefix(input, "long:") {
+			if testing.Short() {
+				continue
+			}
+			input = input[len("long:"):]
+		}
+
+		r, ok := new(Rat).SetString(input)
+		if !ok {
+			t.Errorf("Rat.SetString(%q) failed", input)
+			continue
+		}
+		f, exact := r.Float32()
+
+		// 1. Check string -> Rat -> float32 conversions are
+		// consistent with strconv.ParseFloat.
+		// Skip this check if the input uses "a/b" rational syntax.
+		if !strings.Contains(input, "/") {
+			e64, _ := strconv.ParseFloat(input, 32)
+			e := float32(e64)
+
+			// Careful: negative Rats too small for
+			// float64 become -0, but Rat obviously cannot
+			// preserve the sign from SetString("-0").
+			switch {
+			case math.Float32bits(e) == math.Float32bits(f):
+				// Ok: bitwise equal.
+			case f == 0 && r.Num().BitLen() == 0:
+				// Ok: Rat(0) is equivalent to both +/- float64(0).
+			default:
+				t.Errorf("strconv.ParseFloat(%q) = %g (%b), want %g (%b); delta = %g", input, e, e, f, f, f-e)
+			}
+		}
+
+		if !isFinite(float64(f)) {
+			continue
+		}
+
+		// 2. Check f is best approximation to r.
+		if !checkIsBestApprox32(t, f, r) {
+			// Append context information.
+			t.Errorf("(input was %q)", input)
+		}
+
+		// 3. Check f->R->f roundtrip is non-lossy.
+		checkNonLossyRoundtrip32(t, f)
+
+		// 4. Check exactness using slow algorithm.
+		if wasExact := new(Rat).SetFloat64(float64(f)).Cmp(r) == 0; wasExact != exact {
+			t.Errorf("Rat.SetString(%q).Float32().exact = %t, want %t", input, exact, wasExact)
+		}
+	}
+}
+
+func TestFloat64SpecialCases(t *testing.T) {
+	for _, input := range float64inputs {
+		if strings.HasPrefix(input, "long:") {
+			if testing.Short() {
+				continue
+			}
+			input = input[len("long:"):]
+		}
+
+		r, ok := new(Rat).SetString(input)
+		if !ok {
+			t.Errorf("Rat.SetString(%q) failed", input)
+			continue
+		}
+		f, exact := r.Float64()
+
+		// 1. Check string -> Rat -> float64 conversions are
+		// consistent with strconv.ParseFloat.
+		// Skip this check if the input uses "a/b" rational syntax.
+		if !strings.Contains(input, "/") {
+			e, _ := strconv.ParseFloat(input, 64)
+
+			// Careful: negative Rats too small for
+			// float64 become -0, but Rat obviously cannot
+			// preserve the sign from SetString("-0").
+			switch {
+			case math.Float64bits(e) == math.Float64bits(f):
+				// Ok: bitwise equal.
+			case f == 0 && r.Num().BitLen() == 0:
+				// Ok: Rat(0) is equivalent to both +/- float64(0).
+			default:
+				t.Errorf("strconv.ParseFloat(%q) = %g (%b), want %g (%b); delta = %g", input, e, e, f, f, f-e)
+			}
+		}
+
+		if !isFinite(f) {
+			continue
+		}
+
+		// 2. Check f is best approximation to r.
+		if !checkIsBestApprox64(t, f, r) {
+			// Append context information.
+			t.Errorf("(input was %q)", input)
+		}
+
+		// 3. Check f->R->f roundtrip is non-lossy.
+		checkNonLossyRoundtrip64(t, f)
+
+		// 4. Check exactness using slow algorithm.
+		if wasExact := new(Rat).SetFloat64(f).Cmp(r) == 0; wasExact != exact {
+			t.Errorf("Rat.SetString(%q).Float64().exact = %t, want %t", input, exact, wasExact)
+		}
+	}
+}
+
 func TestFloat32Distribution(t *testing.T) {
 	// Generate a distribution of (sign, mantissa, exp) values
 	// broader than the float32 range, and check Rat.Float32()
diff --git a/src/math/cbrt.go b/src/math/cbrt.go
index f009faf..272e309 100644
--- a/src/math/cbrt.go
+++ b/src/math/cbrt.go
@@ -4,17 +4,13 @@
 
 package math
 
-// The go code is a modified version of the original C code from
-// http://www.netlib.org/fdlibm/s_cbrt.c and came with this notice.
-//
-// ====================================================
-// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
-//
-// Developed at SunSoft, a Sun Microsystems, Inc. business.
-// Permission to use, copy, modify, and distribute this
-// software is freely granted, provided that this notice
-// is preserved.
-// ====================================================
+/*
+	The algorithm is based in part on "Optimal Partitioning of
+	Newton's Method for Calculating Roots", by Gunter Meinardus
+	and G. D. Taylor, Mathematics of Computation © 1980 American
+	Mathematical Society.
+	(http://www.jstor.org/stable/2006387?seq=9, accessed 11-Feb-2010)
+*/
 
 // Cbrt returns the cube root of x.
 //
@@ -24,54 +20,57 @@ package math
 //	Cbrt(NaN) = NaN
 func Cbrt(x float64) float64 {
 	const (
-		B1             = 715094163                   // (682-0.03306235651)*2**20
-		B2             = 696219795                   // (664-0.03306235651)*2**20
-		C              = 5.42857142857142815906e-01  // 19/35     = 0x3FE15F15F15F15F1
-		D              = -7.05306122448979611050e-01 // -864/1225 = 0xBFE691DE2532C834
-		E              = 1.41428571428571436819e+00  // 99/70     = 0x3FF6A0EA0EA0EA0F
-		F              = 1.60714285714285720630e+00  // 45/28     = 0x3FF9B6DB6DB6DB6E
-		G              = 3.57142857142857150787e-01  // 5/14      = 0x3FD6DB6DB6DB6DB7
-		SmallestNormal = 2.22507385850720138309e-308 // 2**-1022  = 0x0010000000000000
+		A1 = 1.662848358e-01
+		A2 = 1.096040958e+00
+		A3 = 4.105032829e-01
+		A4 = 5.649335816e-01
+		B1 = 2.639607233e-01
+		B2 = 8.699282849e-01
+		B3 = 1.629083358e-01
+		B4 = 2.824667908e-01
+		C1 = 4.190115298e-01
+		C2 = 6.904625373e-01
+		C3 = 6.46502159e-02
+		C4 = 1.412333954e-01
 	)
 	// special cases
 	switch {
 	case x == 0 || IsNaN(x) || IsInf(x, 0):
 		return x
 	}
-
 	sign := false
 	if x < 0 {
 		x = -x
 		sign = true
 	}
-
-	// rough cbrt to 5 bits
-	t := Float64frombits(Float64bits(x)/3 + B1<<32)
-	if x < SmallestNormal {
-		// subnormal number
-		t = float64(1 << 54) // set t= 2**54
-		t *= x
-		t = Float64frombits(Float64bits(t)/3 + B2<<32)
+	// Reduce argument and estimate cube root
+	f, e := Frexp(x) // 0.5 <= f < 1.0
+	m := e % 3
+	if m > 0 {
+		m -= 3
+		e -= m // e is multiple of 3
 	}
+	switch m {
+	case 0: // 0.5 <= f < 1.0
+		f = A1*f + A2 - A3/(A4+f)
+	case -1:
+		f *= 0.5 // 0.25 <= f < 0.5
+		f = B1*f + B2 - B3/(B4+f)
+	default: // m == -2
+		f *= 0.25 // 0.125 <= f < 0.25
+		f = C1*f + C2 - C3/(C4+f)
+	}
+	y := Ldexp(f, e/3) // e/3 = exponent of cube root
 
-	// new cbrt to 23 bits
-	r := t * t / x
-	s := C + r*t
-	t *= G + F/(s+E+D/s)
-
-	// chop to 22 bits, make larger than cbrt(x)
-	t = Float64frombits(Float64bits(t)&(0xFFFFFFFFC<<28) + 1<<30)
-
-	// one step newton iteration to 53 bits with error less than 0.667ulps
-	s = t * t // t*t is exact
-	r = x / s
-	w := t + t
-	r = (r - t) / (w + r) // r-s is exact
-	t = t + t*r
-
-	// restore the sign bit
+	// Iterate
+	s := y * y * y
+	t := s + x
+	y *= (t + x) / (s + t)
+	// Reiterate
+	s = (y*y*y - x) / x
+	y -= y * (((14.0/81.0)*s-(2.0/9.0))*s + (1.0 / 3.0)) * s
 	if sign {
-		t = -t
+		y = -y
 	}
-	return t
+	return y
 }
diff --git a/src/math/const.go b/src/math/const.go
index b440538..f1247c3 100644
--- a/src/math/const.go
+++ b/src/math/const.go
@@ -6,19 +6,20 @@
 package math
 
 // Mathematical constants.
+// Reference: http://oeis.org/Axxxxxx
 const (
-	E   = 2.71828182845904523536028747135266249775724709369995957496696763 // http://oeis.org/A001113
-	Pi  = 3.14159265358979323846264338327950288419716939937510582097494459 // http://oeis.org/A000796
-	Phi = 1.61803398874989484820458683436563811772030917980576286213544862 // http://oeis.org/A001622
+	E   = 2.71828182845904523536028747135266249775724709369995957496696763 // A001113
+	Pi  = 3.14159265358979323846264338327950288419716939937510582097494459 // A000796
+	Phi = 1.61803398874989484820458683436563811772030917980576286213544862 // A001622
 
-	Sqrt2   = 1.41421356237309504880168872420969807856967187537694807317667974 // http://oeis.org/A002193
-	SqrtE   = 1.64872127070012814684865078781416357165377610071014801157507931 // http://oeis.org/A019774
-	SqrtPi  = 1.77245385090551602729816748334114518279754945612238712821380779 // http://oeis.org/A002161
-	SqrtPhi = 1.27201964951406896425242246173749149171560804184009624861664038 // http://oeis.org/A139339
+	Sqrt2   = 1.41421356237309504880168872420969807856967187537694807317667974 // A002193
+	SqrtE   = 1.64872127070012814684865078781416357165377610071014801157507931 // A019774
+	SqrtPi  = 1.77245385090551602729816748334114518279754945612238712821380779 // A002161
+	SqrtPhi = 1.27201964951406896425242246173749149171560804184009624861664038 // A139339
 
-	Ln2    = 0.693147180559945309417232121458176568075500134360255254120680009 // http://oeis.org/A002162
+	Ln2    = 0.693147180559945309417232121458176568075500134360255254120680009 // A002162
 	Log2E  = 1 / Ln2
-	Ln10   = 2.30258509299404568401799145468436420760110148862877297603332790 // http://oeis.org/A002392
+	Ln10   = 2.30258509299404568401799145468436420760110148862877297603332790 // A002392
 	Log10E = 1 / Ln10
 )
 
diff --git a/src/math/dim_amd64.s b/src/math/dim_amd64.s
index 8e6aaad..622cc3f 100644
--- a/src/math/dim_amd64.s
+++ b/src/math/dim_amd64.s
@@ -26,13 +26,13 @@ dim2:	// (-Inf, -Inf) special case
 	JEQ     bothInf
 dim3:	// (NaN, x) or (x, NaN)
 	MOVQ    $~(1<<63), DX
-	MOVQ    $PosInf, AX
+	MOVQ    $NaN, AX
 	ANDQ    DX, BX // x = |x|
 	CMPQ    AX, BX
-	JLT     isDimNaN
+	JLE     isDimNaN
 	ANDQ    DX, CX // y = |y|
 	CMPQ    AX, CX
-	JLT     isDimNaN
+	JLE     isDimNaN
 
 	MOVSD x+0(FP), X0
 	SUBSD y+8(FP), X0
@@ -41,8 +41,8 @@ dim3:	// (NaN, x) or (x, NaN)
 	MOVSD X0, ret+16(FP)
 	RET
 bothInf: // Dim(-Inf, -Inf) or Dim(+Inf, +Inf)
-isDimNaN:
 	MOVQ    $NaN, AX
+isDimNaN:
 	MOVQ    AX, ret+16(FP)
 	RET
 
@@ -58,15 +58,15 @@ TEXT ·Max(SB),NOSPLIT,$0
 	JEQ     isPosInf
 	// NaN special cases
 	MOVQ    $~(1<<63), DX // bit mask
-	MOVQ    $PosInf, AX
+	MOVQ    $NaN, AX
 	MOVQ    R8, BX
 	ANDQ    DX, BX // x = |x|
 	CMPQ    AX, BX
-	JLT     isMaxNaN
+	JLE     isMaxNaN
 	MOVQ    R9, CX
 	ANDQ    DX, CX // y = |y|
 	CMPQ    AX, CX
-	JLT     isMaxNaN
+	JLE     isMaxNaN
 	// ±0 special cases
 	ORQ     CX, BX
 	JEQ     isMaxZero
@@ -77,7 +77,6 @@ TEXT ·Max(SB),NOSPLIT,$0
 	MOVSD   X0, ret+16(FP)
 	RET
 isMaxNaN: // return NaN
-	MOVQ	$NaN, AX
 isPosInf: // return +Inf
 	MOVQ    AX, ret+16(FP)
 	RET
@@ -90,6 +89,16 @@ isMaxZero:
 	MOVQ    R9, ret+16(FP) // return other 0
 	RET
 
+/*
+	MOVQ    $0, AX
+	CMPQ    AX, R8
+	JNE     +3(PC)
+	MOVQ    R8, ret+16(FP) // return 0
+	RET
+	MOVQ    R9, ret+16(FP) // return other 0
+	RET
+*/
+
 // func Min(x, y float64) float64
 TEXT ·Min(SB),NOSPLIT,$0
 	// -Inf special cases
@@ -102,15 +111,15 @@ TEXT ·Min(SB),NOSPLIT,$0
 	JEQ     isNegInf
 	// NaN special cases
 	MOVQ    $~(1<<63), DX
-	MOVQ    $PosInf, AX
+	MOVQ    $NaN, AX
 	MOVQ    R8, BX
 	ANDQ    DX, BX // x = |x|
 	CMPQ    AX, BX
-	JLT     isMinNaN
+	JLE     isMinNaN
 	MOVQ    R9, CX
 	ANDQ    DX, CX // y = |y|
 	CMPQ    AX, CX
-	JLT     isMinNaN
+	JLE     isMinNaN
 	// ±0 special cases
 	ORQ     CX, BX
 	JEQ     isMinZero
@@ -121,7 +130,6 @@ TEXT ·Min(SB),NOSPLIT,$0
 	MOVSD X0, ret+16(FP)
 	RET
 isMinNaN: // return NaN
-	MOVQ	$NaN, AX
 isNegInf: // return -Inf
 	MOVQ    AX, ret+16(FP)
 	RET
diff --git a/src/math/expm1.go b/src/math/expm1.go
index 064e131..8f56e15 100644
--- a/src/math/expm1.go
+++ b/src/math/expm1.go
@@ -158,11 +158,11 @@ func expm1(x float64) float64 {
 
 	// filter out huge argument
 	if absx >= Ln2X56 { // if |x| >= 56 * ln2
-		if sign {
-			return -1 // x < -56*ln2, return -1
-		}
 		if absx >= Othreshold { // if |x| >= 709.78...
-			return Inf(1)
+			return Inf(1) // overflow
+		}
+		if sign {
+			return -1 // x < -56*ln2, return -1.0
 		}
 	}
 
diff --git a/src/math/log10.go b/src/math/log10.go
index ccd079d..95cfbf4 100644
--- a/src/math/log10.go
+++ b/src/math/log10.go
@@ -18,10 +18,5 @@ func Log2(x float64) float64
 
 func log2(x float64) float64 {
 	frac, exp := Frexp(x)
-	// Make sure exact powers of two give an exact answer.
-	// Don't depend on Log(0.5)*(1/Ln2)+exp being exactly exp-1.
-	if frac == 0.5 {
-		return float64(exp - 1)
-	}
 	return Log(frac)*(1/Ln2) + float64(exp)
 }
diff --git a/src/math/nextafter.go b/src/math/nextafter.go
index 9088e4d..bbb1399 100644
--- a/src/math/nextafter.go
+++ b/src/math/nextafter.go
@@ -5,11 +5,10 @@
 package math
 
 // Nextafter32 returns the next representable float32 value after x towards y.
-//
-// Special cases are:
+// Special cases:
 //	Nextafter32(x, x)   = x
-//	Nextafter32(NaN, y) = NaN
-//	Nextafter32(x, NaN) = NaN
+//      Nextafter32(NaN, y) = NaN
+//      Nextafter32(x, NaN) = NaN
 func Nextafter32(x, y float32) (r float32) {
 	switch {
 	case IsNaN(float64(x)) || IsNaN(float64(y)): // special case
@@ -27,11 +26,10 @@ func Nextafter32(x, y float32) (r float32) {
 }
 
 // Nextafter returns the next representable float64 value after x towards y.
-//
-// Special cases are:
-//	Nextafter(x, x)   = x
-//	Nextafter(NaN, y) = NaN
-//	Nextafter(x, NaN) = NaN
+// Special cases:
+//	Nextafter64(x, x)   = x
+//      Nextafter64(NaN, y) = NaN
+//      Nextafter64(x, NaN) = NaN
 func Nextafter(x, y float64) (r float64) {
 	switch {
 	case IsNaN(x) || IsNaN(y): // special case
diff --git a/src/math/rand/example_test.go b/src/math/rand/example_test.go
index e6cd4f7..f429914 100644
--- a/src/math/rand/example_test.go
+++ b/src/math/rand/example_test.go
@@ -72,7 +72,7 @@ func Example_rand() {
 	// depending on the size of 'int'.
 	show("Int31", r.Int31(), r.Int31(), r.Int31())
 	show("Int63", r.Int63(), r.Int63(), r.Int63())
-	show("Uint32", r.Uint32(), r.Uint32(), r.Uint32())
+	show("Uint32", r.Int63(), r.Int63(), r.Int63())
 
 	// Intn, Int31n, and Int63n limit their output to be < n.
 	// They do so more carefully than using r.Int()%n.
@@ -89,7 +89,7 @@ func Example_rand() {
 	// NormFloat64 0.17233959114940064 1.577014951434847   0.04259129641113857
 	// Int31       1501292890          1486668269          182840835
 	// Int63       3546343826724305832 5724354148158589552 5239846799706671610
-	// Uint32      2760229429          296659907           1922395059
+	// Uint32      5927547564735367388 637072299495207830  4128311955958246186
 	// Intn(10)    1                   2                   5
 	// Int31n(10)  4                   7                   8
 	// Int63n(10)  7                   6                   3
diff --git a/src/math/rand/rand.go b/src/math/rand/rand.go
index 6360128..3ffb5c4 100644
--- a/src/math/rand/rand.go
+++ b/src/math/rand/rand.go
@@ -9,9 +9,6 @@
 // sequence of values each time a program is run. Use the Seed function to
 // initialize the default Source if different behavior is required for each run.
 // The default Source is safe for concurrent use by multiple goroutines.
-//
-// For random numbers suitable for security-sensitive work, see the crypto/rand
-// package.
 package rand
 
 import "sync"
diff --git a/src/math/rand/rand_test.go b/src/math/rand/rand_test.go
index c61494f..ab0dc49 100644
--- a/src/math/rand/rand_test.go
+++ b/src/math/rand/rand_test.go
@@ -8,8 +8,6 @@ import (
 	"errors"
 	"fmt"
 	"math"
-	"os"
-	"runtime"
 	"testing"
 )
 
@@ -324,17 +322,10 @@ func TestExpTables(t *testing.T) {
 	}
 }
 
+// For issue 6721, the problem came after 7533753 calls, so check 10e6.
 func TestFloat32(t *testing.T) {
-	// For issue 6721, the problem came after 7533753 calls, so check 10e6.
-	num := int(10e6)
-	// But ARM5 floating point emulation is slow (Issue 10749), so
-	// do less for that builder:
-	if testing.Short() && runtime.GOARCH == "arm" && os.Getenv("GOARM") == "5" {
-		num /= 100 // 1.72 seconds instead of 172 seconds
-	}
-
 	r := New(NewSource(1))
-	for ct := 0; ct < num; ct++ {
+	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)
diff --git a/src/math/rand/zipf.go b/src/math/rand/zipf.go
index f04c814..8db2c6f 100644
--- a/src/math/rand/zipf.go
+++ b/src/math/rand/zipf.go
@@ -32,10 +32,8 @@ func (z *Zipf) hinv(x float64) float64 {
 	return math.Exp(z.oneminusQinv*math.Log(z.oneminusQ*x)) - z.v
 }
 
-// NewZipf returns a Zipf variate generator.
-// The generator generates values k ∈ [0, imax]
-// such that P(k) is proportional to (v + k) ** (-s).
-// Requirements: s > 1 and v >= 1.
+// NewZipf returns a Zipf generating variates p(k) on [0, imax]
+// proportional to (v+k)**(-s) where s>1 and k>=0, and v>=1.
 func NewZipf(r *Rand, s float64, v float64, imax uint64) *Zipf {
 	z := new(Zipf)
 	if s <= 1.0 || v < 1 {
diff --git a/src/math/sqrt.go b/src/math/sqrt.go
index 23cf299..fdc8699 100644
--- a/src/math/sqrt.go
+++ b/src/math/sqrt.go
@@ -91,11 +91,6 @@ package math
 //	Sqrt(NaN) = NaN
 func Sqrt(x float64) float64
 
-// Note: Sqrt is implemented in assembly on some systems.
-// Others have assembly stubs that jump to func sqrt below.
-// On systems where Sqrt is a single instruction, the compiler
-// may turn a direct call into a direct use of that instruction instead.
-
 func sqrt(x float64) float64 {
 	// special cases
 	switch {
diff --git a/src/mime/grammar.go b/src/mime/grammar.go
index 31b66e8..2347324 100644
--- a/src/mime/grammar.go
+++ b/src/mime/grammar.go
@@ -8,13 +8,13 @@ import (
 	"strings"
 )
 
-// isTSpecial reports whether rune is in 'tspecials' as defined by RFC
+// isTSpecial returns true if rune is in 'tspecials' as defined by RFC
 // 1521 and RFC 2045.
 func isTSpecial(r rune) bool {
 	return strings.IndexRune(`()<>@,;:\"/[]?=`, r) != -1
 }
 
-// isTokenChar reports whether rune is in 'token' as defined by RFC
+// isTokenChar returns true if rune is in 'token' as defined by RFC
 // 1521 and RFC 2045.
 func isTokenChar(r rune) bool {
 	// token := 1*<any (US-ASCII) CHAR except SPACE, CTLs,
@@ -22,7 +22,7 @@ func isTokenChar(r rune) bool {
 	return r > 0x20 && r < 0x7f && !isTSpecial(r)
 }
 
-// isToken reports whether s is a 'token' as defined by RFC 1521
+// isToken returns true if s is a 'token' as defined by RFC 1521
 // and RFC 2045.
 func isToken(s string) bool {
 	if s == "" {
diff --git a/src/mime/multipart/multipart.go b/src/mime/multipart/multipart.go
index 6f65a55..01a667d 100644
--- a/src/mime/multipart/multipart.go
+++ b/src/mime/multipart/multipart.go
@@ -19,7 +19,6 @@ import (
 	"io"
 	"io/ioutil"
 	"mime"
-	"mime/quotedprintable"
 	"net/textproto"
 )
 
@@ -112,7 +111,7 @@ func newPart(mr *Reader) (*Part, error) {
 	const cte = "Content-Transfer-Encoding"
 	if bp.Header.Get(cte) == "quoted-printable" {
 		bp.Header.Del(cte)
-		bp.r = quotedprintable.NewReader(bp.r)
+		bp.r = newQuotedPrintableReader(bp.r)
 	}
 	return bp, nil
 }
@@ -165,18 +164,16 @@ func (pr partReader) Read(d []byte) (n int, err error) {
 	if peek == nil {
 		panic("nil peek buf")
 	}
+
 	// Search the peek buffer for "\r\n--boundary". If found,
 	// consume everything up to the boundary. If not, consume only
 	// as much of the peek buffer as cannot hold the boundary
 	// string.
 	nCopy := 0
 	foundBoundary := false
-	if idx, isEnd := p.mr.peekBufferSeparatorIndex(peek); idx != -1 {
+	if idx := bytes.Index(peek, p.mr.nlDashBoundary); idx != -1 {
 		nCopy = idx
-		foundBoundary = isEnd
-		if !isEnd && nCopy == 0 {
-			nCopy = 1 // make some progress.
-		}
+		foundBoundary = true
 	} else if safeCount := len(peek) - len(p.mr.nlDashBoundary); safeCount > 0 {
 		nCopy = safeCount
 	} else if unexpectedEOF {
@@ -340,33 +337,6 @@ func (mr *Reader) peekBufferIsEmptyPart(peek []byte) bool {
 	return bytes.HasPrefix(rest, mr.nl)
 }
 
-// peekBufferSeparatorIndex returns the index of mr.nlDashBoundary in
-// peek and whether it is a real boundary (and not a prefix of an
-// unrelated separator). To be the end, the peek buffer must contain a
-// newline after the boundary.
-func (mr *Reader) peekBufferSeparatorIndex(peek []byte) (idx int, isEnd bool) {
-	idx = bytes.Index(peek, mr.nlDashBoundary)
-	if idx == -1 {
-		return
-	}
-	peek = peek[idx+len(mr.nlDashBoundary):]
-	if len(peek) > 1 && peek[0] == '-' && peek[1] == '-' {
-		return idx, true
-	}
-	peek = skipLWSPChar(peek)
-	// Don't have a complete line after the peek.
-	if bytes.IndexByte(peek, '\n') == -1 {
-		return -1, false
-	}
-	if len(peek) > 0 && peek[0] == '\n' {
-		return idx, true
-	}
-	if len(peek) > 1 && peek[0] == '\r' && peek[1] == '\n' {
-		return idx, true
-	}
-	return idx, false
-}
-
 // skipLWSPChar returns b with leading spaces and tabs removed.
 // RFC 822 defines:
 //    LWSP-char = SPACE / HTAB
diff --git a/src/mime/multipart/multipart_test.go b/src/mime/multipart/multipart_test.go
index 30452d1..d662e83 100644
--- a/src/mime/multipart/multipart_test.go
+++ b/src/mime/multipart/multipart_test.go
@@ -351,7 +351,7 @@ func TestLineContinuation(t *testing.T) {
 }
 
 func TestQuotedPrintableEncoding(t *testing.T) {
-	// From https://golang.org/issue/4411
+	// From http://golang.org/issue/4411
 	body := "--0016e68ee29c5d515f04cedf6733\r\nContent-Type: text/plain; charset=ISO-8859-1\r\nContent-Disposition: form-data; name=text\r\nContent-Transfer-Encoding: quoted-printable\r\n\r\nwords words words words words words words words words words words words wor=\r\nds words words words words words words words words words words words words =\r\nwords words words words words words words words words words words words wor=\r\nds words words words words words words words words words words w [...]
 	r := NewReader(strings.NewReader(body), "0016e68ee29c5d515f04cedf6733")
 	part, err := r.NextPart()
@@ -565,58 +565,6 @@ foo: bar
 		},
 	},
 
-	// Issue 10616; minimal
-	{
-		name: "issue 10616 minimal",
-		sep:  "sep",
-		in: "--sep \r\nFoo: bar\r\n\r\n" +
-			"a\r\n" +
-			"--sep_alt\r\n" +
-			"b\r\n" +
-			"\r\n--sep--",
-		want: []headerBody{
-			{textproto.MIMEHeader{"Foo": {"bar"}}, "a\r\n--sep_alt\r\nb\r\n"},
-		},
-	},
-
-	// Issue 10616; full example from bug.
-	{
-		name: "nested separator prefix is outer separator",
-		sep:  "----=_NextPart_4c2fbafd7ec4c8bf08034fe724b608d9",
-		in: strings.Replace(`------=_NextPart_4c2fbafd7ec4c8bf08034fe724b608d9
-Content-Type: multipart/alternative; boundary="----=_NextPart_4c2fbafd7ec4c8bf08034fe724b608d9_alt"
-
-------=_NextPart_4c2fbafd7ec4c8bf08034fe724b608d9_alt
-Content-Type: text/plain; charset="utf-8"
-Content-Transfer-Encoding: 8bit
-
-This is a multi-part message in MIME format.
-
-------=_NextPart_4c2fbafd7ec4c8bf08034fe724b608d9_alt
-Content-Type: text/html; charset="utf-8"
-Content-Transfer-Encoding: 8bit
-
-html things
-------=_NextPart_4c2fbafd7ec4c8bf08034fe724b608d9_alt--
-------=_NextPart_4c2fbafd7ec4c8bf08034fe724b608d9--`, "\n", "\r\n", -1),
-		want: []headerBody{
-			{textproto.MIMEHeader{"Content-Type": {`multipart/alternative; boundary="----=_NextPart_4c2fbafd7ec4c8bf08034fe724b608d9_alt"`}},
-				strings.Replace(`------=_NextPart_4c2fbafd7ec4c8bf08034fe724b608d9_alt
-Content-Type: text/plain; charset="utf-8"
-Content-Transfer-Encoding: 8bit
-
-This is a multi-part message in MIME format.
-
-------=_NextPart_4c2fbafd7ec4c8bf08034fe724b608d9_alt
-Content-Type: text/html; charset="utf-8"
-Content-Transfer-Encoding: 8bit
-
-html things
-------=_NextPart_4c2fbafd7ec4c8bf08034fe724b608d9_alt--`, "\n", "\r\n", -1),
-			},
-		},
-	},
-
 	roundTripParseTest(),
 }
 
diff --git a/src/mime/multipart/quotedprintable.go b/src/mime/multipart/quotedprintable.go
new file mode 100644
index 0000000..9ff4ee7
--- /dev/null
+++ b/src/mime/multipart/quotedprintable.go
@@ -0,0 +1,118 @@
+// 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.
+
+// The file define a quoted-printable decoder, as specified in RFC 2045.
+// Deviations:
+// 1. in addition to "=\r\n", "=\n" is also treated as soft line break.
+// 2. it will pass through a '\r' or '\n' not preceded by '=', consistent
+//    with other broken QP encoders & decoders.
+
+package multipart
+
+import (
+	"bufio"
+	"bytes"
+	"fmt"
+	"io"
+)
+
+type qpReader struct {
+	br   *bufio.Reader
+	rerr error  // last read error
+	line []byte // to be consumed before more of br
+}
+
+func newQuotedPrintableReader(r io.Reader) io.Reader {
+	return &qpReader{
+		br: bufio.NewReader(r),
+	}
+}
+
+func fromHex(b byte) (byte, error) {
+	switch {
+	case b >= '0' && b <= '9':
+		return b - '0', nil
+	case b >= 'A' && b <= 'F':
+		return b - 'A' + 10, nil
+	}
+	return 0, fmt.Errorf("multipart: invalid quoted-printable hex byte 0x%02x", b)
+}
+
+func (q *qpReader) readHexByte(v []byte) (b byte, err error) {
+	if len(v) < 2 {
+		return 0, io.ErrUnexpectedEOF
+	}
+	var hb, lb byte
+	if hb, err = fromHex(v[0]); err != nil {
+		return 0, err
+	}
+	if lb, err = fromHex(v[1]); err != nil {
+		return 0, err
+	}
+	return hb<<4 | lb, nil
+}
+
+func isQPDiscardWhitespace(r rune) bool {
+	switch r {
+	case '\n', '\r', ' ', '\t':
+		return true
+	}
+	return false
+}
+
+var (
+	crlf       = []byte("\r\n")
+	lf         = []byte("\n")
+	softSuffix = []byte("=")
+)
+
+func (q *qpReader) Read(p []byte) (n int, err error) {
+	for len(p) > 0 {
+		if len(q.line) == 0 {
+			if q.rerr != nil {
+				return n, q.rerr
+			}
+			q.line, q.rerr = q.br.ReadSlice('\n')
+
+			// Does the line end in CRLF instead of just LF?
+			hasLF := bytes.HasSuffix(q.line, lf)
+			hasCR := bytes.HasSuffix(q.line, crlf)
+			wholeLine := q.line
+			q.line = bytes.TrimRightFunc(wholeLine, isQPDiscardWhitespace)
+			if bytes.HasSuffix(q.line, softSuffix) {
+				rightStripped := wholeLine[len(q.line):]
+				q.line = q.line[:len(q.line)-1]
+				if !bytes.HasPrefix(rightStripped, lf) && !bytes.HasPrefix(rightStripped, crlf) {
+					q.rerr = fmt.Errorf("multipart: invalid bytes after =: %q", rightStripped)
+				}
+			} else if hasLF {
+				if hasCR {
+					q.line = append(q.line, '\r', '\n')
+				} else {
+					q.line = append(q.line, '\n')
+				}
+			}
+			continue
+		}
+		b := q.line[0]
+
+		switch {
+		case b == '=':
+			b, err = q.readHexByte(q.line[1:])
+			if err != nil {
+				return n, err
+			}
+			q.line = q.line[2:] // 2 of the 3; other 1 is done below
+		case b == '\t' || b == '\r' || b == '\n':
+			break
+		case b < ' ' || b > '~':
+			return n, fmt.Errorf("multipart: invalid unescaped byte 0x%02x in quoted-printable body", b)
+		}
+		p[0] = b
+		p = p[1:]
+		q.line = q.line[1:]
+		n++
+	}
+	return n, nil
+}
diff --git a/src/mime/multipart/quotedprintable_test.go b/src/mime/multipart/quotedprintable_test.go
new file mode 100644
index 0000000..c4de3eb
--- /dev/null
+++ b/src/mime/multipart/quotedprintable_test.go
@@ -0,0 +1,204 @@
+// 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 multipart
+
+import (
+	"bufio"
+	"bytes"
+	"errors"
+	"flag"
+	"fmt"
+	"io"
+	"os/exec"
+	"regexp"
+	"sort"
+	"strings"
+	"testing"
+	"time"
+)
+
+func TestQuotedPrintable(t *testing.T) {
+	tests := []struct {
+		in, want string
+		err      interface{}
+	}{
+		{in: "", want: ""},
+		{in: "foo bar", want: "foo bar"},
+		{in: "foo bar=3D", want: "foo bar="},
+		{in: "foo bar=\n", want: "foo bar"},
+		{in: "foo bar\n", want: "foo bar\n"}, // somewhat lax.
+		{in: "foo bar=0", want: "foo bar", err: io.ErrUnexpectedEOF},
+		{in: "foo bar=ab", want: "foo bar", err: "multipart: invalid quoted-printable hex byte 0x61"},
+		{in: "foo bar=0D=0A", want: "foo bar\r\n"},
+		{in: " A B        \r\n C ", want: " A B\r\n C"},
+		{in: " A B =\r\n C ", want: " A B  C"},
+		{in: " A B =\n C ", want: " A B  C"}, // lax. treating LF as CRLF
+		{in: "foo=\nbar", want: "foobar"},
+		{in: "foo\x00bar", want: "foo", err: "multipart: invalid unescaped byte 0x00 in quoted-printable body"},
+		{in: "foo bar\xff", want: "foo bar", err: "multipart: invalid unescaped byte 0xff in quoted-printable body"},
+
+		// Equal sign.
+		{in: "=3D30\n", want: "=30\n"},
+		{in: "=00=FF0=\n", want: "\x00\xff0"},
+
+		// Trailing whitespace
+		{in: "foo  \n", want: "foo\n"},
+		{in: "foo  \n\nfoo =\n\nfoo=20\n\n", want: "foo\n\nfoo \nfoo \n\n"},
+
+		// Tests that we allow bare \n and \r through, despite it being strictly
+		// not permitted per RFC 2045, Section 6.7 Page 22 bullet (4).
+		{in: "foo\nbar", want: "foo\nbar"},
+		{in: "foo\rbar", want: "foo\rbar"},
+		{in: "foo\r\nbar", want: "foo\r\nbar"},
+
+		// Different types of soft line-breaks.
+		{in: "foo=\r\nbar", want: "foobar"},
+		{in: "foo=\nbar", want: "foobar"},
+		{in: "foo=\rbar", want: "foo", err: "multipart: invalid quoted-printable hex byte 0x0d"},
+		{in: "foo=\r\r\r \nbar", want: "foo", err: `multipart: invalid bytes after =: "\r\r\r \n"`},
+
+		// Example from RFC 2045:
+		{in: "Now's the time =\n" + "for all folk to come=\n" + " to the aid of their country.",
+			want: "Now's the time for all folk to come to the aid of their country."},
+	}
+	for _, tt := range tests {
+		var buf bytes.Buffer
+		_, err := io.Copy(&buf, newQuotedPrintableReader(strings.NewReader(tt.in)))
+		if got := buf.String(); got != tt.want {
+			t.Errorf("for %q, got %q; want %q", tt.in, got, tt.want)
+		}
+		switch verr := tt.err.(type) {
+		case nil:
+			if err != nil {
+				t.Errorf("for %q, got unexpected error: %v", tt.in, err)
+			}
+		case string:
+			if got := fmt.Sprint(err); got != verr {
+				t.Errorf("for %q, got error %q; want %q", tt.in, got, verr)
+			}
+		case error:
+			if err != verr {
+				t.Errorf("for %q, got error %q; want %q", tt.in, err, verr)
+			}
+		}
+	}
+
+}
+
+func everySequence(base, alpha string, length int, fn func(string)) {
+	if len(base) == length {
+		fn(base)
+		return
+	}
+	for i := 0; i < len(alpha); i++ {
+		everySequence(base+alpha[i:i+1], alpha, length, fn)
+	}
+}
+
+var useQprint = flag.Bool("qprint", false, "Compare against the 'qprint' program.")
+
+var badSoftRx = regexp.MustCompile(`=([^\r\n]+?\n)|([^\r\n]+$)|(\r$)|(\r[^\n]+\n)|( \r\n)`)
+
+func TestQPExhaustive(t *testing.T) {
+	if *useQprint {
+		_, err := exec.LookPath("qprint")
+		if err != nil {
+			t.Fatalf("Error looking for qprint: %v", err)
+		}
+	}
+
+	var buf bytes.Buffer
+	res := make(map[string]int)
+	everySequence("", "0A \r\n=", 6, func(s string) {
+		if strings.HasSuffix(s, "=") || strings.Contains(s, "==") {
+			return
+		}
+		buf.Reset()
+		_, err := io.Copy(&buf, newQuotedPrintableReader(strings.NewReader(s)))
+		if err != nil {
+			errStr := err.Error()
+			if strings.Contains(errStr, "invalid bytes after =:") {
+				errStr = "invalid bytes after ="
+			}
+			res[errStr]++
+			if strings.Contains(errStr, "invalid quoted-printable hex byte ") {
+				if strings.HasSuffix(errStr, "0x20") && (strings.Contains(s, "=0 ") || strings.Contains(s, "=A ") || strings.Contains(s, "= ")) {
+					return
+				}
+				if strings.HasSuffix(errStr, "0x3d") && (strings.Contains(s, "=0=") || strings.Contains(s, "=A=")) {
+					return
+				}
+				if strings.HasSuffix(errStr, "0x0a") || strings.HasSuffix(errStr, "0x0d") {
+					// bunch of cases; since whitespace at the end of a line before \n is removed.
+					return
+				}
+			}
+			if strings.Contains(errStr, "unexpected EOF") {
+				return
+			}
+			if errStr == "invalid bytes after =" && badSoftRx.MatchString(s) {
+				return
+			}
+			t.Errorf("decode(%q) = %v", s, err)
+			return
+		}
+		if *useQprint {
+			cmd := exec.Command("qprint", "-d")
+			cmd.Stdin = strings.NewReader(s)
+			stderr, err := cmd.StderrPipe()
+			if err != nil {
+				panic(err)
+			}
+			qpres := make(chan interface{}, 2)
+			go func() {
+				br := bufio.NewReader(stderr)
+				s, _ := br.ReadString('\n')
+				if s != "" {
+					qpres <- errors.New(s)
+					if cmd.Process != nil {
+						// It can get stuck on invalid input, like:
+						// echo -n "0000= " | qprint -d
+						cmd.Process.Kill()
+					}
+				}
+			}()
+			go func() {
+				want, err := cmd.Output()
+				if err == nil {
+					qpres <- want
+				}
+			}()
+			select {
+			case got := <-qpres:
+				if want, ok := got.([]byte); ok {
+					if string(want) != buf.String() {
+						t.Errorf("go decode(%q) = %q; qprint = %q", s, want, buf.String())
+					}
+				} else {
+					t.Logf("qprint -d(%q) = %v", s, got)
+				}
+			case <-time.After(5 * time.Second):
+				t.Logf("qprint timeout on %q", s)
+			}
+		}
+		res["OK"]++
+	})
+	var outcomes []string
+	for k, v := range res {
+		outcomes = append(outcomes, fmt.Sprintf("%v: %d", k, v))
+	}
+	sort.Strings(outcomes)
+	got := strings.Join(outcomes, "\n")
+	want := `OK: 21576
+invalid bytes after =: 3397
+multipart: invalid quoted-printable hex byte 0x0a: 1400
+multipart: invalid quoted-printable hex byte 0x0d: 2700
+multipart: invalid quoted-printable hex byte 0x20: 2490
+multipart: invalid quoted-printable hex byte 0x3d: 440
+unexpected EOF: 3122`
+	if got != want {
+		t.Errorf("Got:\n%s\nWant:\n%s", got, want)
+	}
+}
diff --git a/src/mime/multipart/writer.go b/src/mime/multipart/writer.go
index 8096093..e13a956 100644
--- a/src/mime/multipart/writer.go
+++ b/src/mime/multipart/writer.go
@@ -39,8 +39,7 @@ func (w *Writer) Boundary() string {
 // boundary separator with an explicit value.
 //
 // SetBoundary must be called before any parts are created, may only
-// contain certain ASCII characters, and must be non-empty and
-// at most 69 bytes long.
+// contain certain ASCII characters, and must be 1-69 bytes long.
 func (w *Writer) SetBoundary(boundary string) error {
 	if w.lastpart != nil {
 		return errors.New("mime: SetBoundary called after write")
diff --git a/src/mime/type.go b/src/mime/type.go
index d369259..ffda1f0 100644
--- a/src/mime/type.go
+++ b/src/mime/type.go
@@ -12,75 +12,34 @@ import (
 )
 
 var (
-	mimeLock       sync.RWMutex      // guards following 3 maps
-	mimeTypes      map[string]string // ".Z" => "application/x-compress"
-	mimeTypesLower map[string]string // ".z" => "application/x-compress"
-
-	// extensions maps from MIME type to list of lowercase file
-	// extensions: "image/jpeg" => [".jpg", ".jpeg"]
-	extensions map[string][]string
-)
-
-// setMimeTypes is used by initMime's non-test path, and by tests.
-// The two maps must not be the same, or nil.
-func setMimeTypes(lowerExt, mixExt map[string]string) {
-	if lowerExt == nil || mixExt == nil {
-		panic("nil map")
+	mimeLock       sync.RWMutex
+	mimeTypesLower = map[string]string{
+		".css":  "text/css; charset=utf-8",
+		".gif":  "image/gif",
+		".htm":  "text/html; charset=utf-8",
+		".html": "text/html; charset=utf-8",
+		".jpg":  "image/jpeg",
+		".js":   "application/x-javascript",
+		".pdf":  "application/pdf",
+		".png":  "image/png",
+		".xml":  "text/xml; charset=utf-8",
 	}
-	mimeTypesLower = lowerExt
-	mimeTypes = mixExt
-	extensions = invert(lowerExt)
-}
-
-var builtinTypesLower = map[string]string{
-	".css":  "text/css; charset=utf-8",
-	".gif":  "image/gif",
-	".htm":  "text/html; charset=utf-8",
-	".html": "text/html; charset=utf-8",
-	".jpg":  "image/jpeg",
-	".js":   "application/x-javascript",
-	".pdf":  "application/pdf",
-	".png":  "image/png",
-	".svg":  "image/svg+xml",
-	".xml":  "text/xml; charset=utf-8",
-}
+	mimeTypes = clone(mimeTypesLower)
+)
 
 func clone(m map[string]string) map[string]string {
 	m2 := make(map[string]string, len(m))
 	for k, v := range m {
 		m2[k] = v
 		if strings.ToLower(k) != k {
-			panic("keys in builtinTypesLower must be lowercase")
+			panic("keys in mimeTypesLower must be lowercase")
 		}
 	}
 	return m2
 }
 
-func invert(m map[string]string) map[string][]string {
-	m2 := make(map[string][]string, len(m))
-	for k, v := range m {
-		justType, _, err := ParseMediaType(v)
-		if err != nil {
-			panic(err)
-		}
-		m2[justType] = append(m2[justType], k)
-	}
-	return m2
-}
-
 var once sync.Once // guards initMime
 
-var testInitMime, osInitMime func()
-
-func initMime() {
-	if fn := testInitMime; fn != nil {
-		fn()
-	} else {
-		setMimeTypes(builtinTypesLower, clone(builtinTypesLower))
-		osInitMime()
-	}
-}
-
 // TypeByExtension returns the MIME type associated with the file extension ext.
 // The extension ext should begin with a leading dot, as in ".html".
 // When ext has no associated type, TypeByExtension returns "".
@@ -104,7 +63,8 @@ func TypeByExtension(ext string) string {
 	defer mimeLock.RUnlock()
 
 	// Case-sensitive lookup.
-	if v := mimeTypes[ext]; v != "" {
+	v := mimeTypes[ext]
+	if v != "" {
 		return v
 	}
 
@@ -131,39 +91,19 @@ func TypeByExtension(ext string) string {
 	return mimeTypesLower[string(lower)]
 }
 
-// ExtensionsByType returns the extensions known to be associated with the MIME
-// type typ. The returned extensions will each begin with a leading dot, as in
-// ".html". When typ has no associated extensions, ExtensionsByType returns an
-// nil slice.
-func ExtensionsByType(typ string) ([]string, error) {
-	justType, _, err := ParseMediaType(typ)
-	if err != nil {
-		return nil, err
-	}
-
-	once.Do(initMime)
-	mimeLock.RLock()
-	defer mimeLock.RUnlock()
-	s, ok := extensions[justType]
-	if !ok {
-		return nil, nil
-	}
-	return append([]string{}, s...), nil
-}
-
 // AddExtensionType sets the MIME type associated with
 // the extension ext to typ. The extension should begin with
 // a leading dot, as in ".html".
 func AddExtensionType(ext, typ string) error {
 	if !strings.HasPrefix(ext, ".") {
-		return fmt.Errorf("mime: extension %q missing leading dot", ext)
+		return fmt.Errorf(`mime: extension %q misses dot`, ext)
 	}
 	once.Do(initMime)
 	return setExtensionType(ext, typ)
 }
 
 func setExtensionType(extension, mimeType string) error {
-	justType, param, err := ParseMediaType(mimeType)
+	_, param, err := ParseMediaType(mimeType)
 	if err != nil {
 		return err
 	}
@@ -174,14 +114,8 @@ func setExtensionType(extension, mimeType string) error {
 	extLower := strings.ToLower(extension)
 
 	mimeLock.Lock()
-	defer mimeLock.Unlock()
 	mimeTypes[extension] = mimeType
 	mimeTypesLower[extLower] = mimeType
-	for _, v := range extensions[justType] {
-		if v == extLower {
-			return nil
-		}
-	}
-	extensions[justType] = append(extensions[justType], extLower)
+	mimeLock.Unlock()
 	return nil
 }
diff --git a/src/mime/type_plan9.go b/src/mime/type_plan9.go
index c3ba186..8cbf677 100644
--- a/src/mime/type_plan9.go
+++ b/src/mime/type_plan9.go
@@ -10,29 +10,10 @@ import (
 	"strings"
 )
 
-func init() {
-	osInitMime = initMimePlan9
-}
-
-func initMimePlan9() {
-	for _, filename := range typeFiles {
-		loadMimeFile(filename)
-	}
-}
-
 var typeFiles = []string{
 	"/sys/lib/mimetypes",
 }
 
-func initMimeForTests() map[string]string {
-	typeFiles = []string{"testdata/test.types.plan9"}
-	return map[string]string{
-		".t1":  "application/test",
-		".t2":  "text/test; charset=utf-8",
-		".pNg": "image/png",
-	}
-}
-
 func loadMimeFile(filename string) {
 	f, err := os.Open(filename)
 	if err != nil {
@@ -55,3 +36,18 @@ func loadMimeFile(filename string) {
 		panic(err)
 	}
 }
+
+func initMime() {
+	for _, filename := range typeFiles {
+		loadMimeFile(filename)
+	}
+}
+
+func initMimeForTests() map[string]string {
+	typeFiles = []string{"testdata/test.types.plan9"}
+	return map[string]string{
+		".t1":  "application/test",
+		".t2":  "text/test; charset=utf-8",
+		".pNg": "image/png",
+	}
+}
diff --git a/src/mime/type_test.go b/src/mime/type_test.go
index c6c1491..d2d254a 100644
--- a/src/mime/type_test.go
+++ b/src/mime/type_test.go
@@ -5,41 +5,12 @@
 package mime
 
 import (
-	"reflect"
-	"strings"
-	"sync"
 	"testing"
 )
 
-func setMimeInit(fn func()) (cleanup func()) {
-	once = sync.Once{}
-	testInitMime = fn
-	return func() { testInitMime = nil }
-}
-
-func clearMimeTypes() {
-	setMimeTypes(map[string]string{}, map[string]string{})
-}
-
-func setType(ext, typ string) {
-	if !strings.HasPrefix(ext, ".") {
-		panic("missing leading dot")
-	}
-	if err := setExtensionType(ext, typ); err != nil {
-		panic("bad test data: " + err.Error())
-	}
-}
+var typeTests = initMimeForTests()
 
 func TestTypeByExtension(t *testing.T) {
-	once = sync.Once{}
-	// initMimeForTests returns the platform-specific extension =>
-	// type tests. On Unix and Plan 9, this also tests the parsing
-	// of MIME text files (in testdata/*). On Windows, we test the
-	// real registry on the machine and assume that ".png" exists
-	// there, which empirically it always has, for all versions of
-	// Windows.
-	typeTests := initMimeForTests()
-
 	for ext, want := range typeTests {
 		val := TypeByExtension(ext)
 		if val != want {
@@ -48,41 +19,15 @@ func TestTypeByExtension(t *testing.T) {
 	}
 }
 
-func TestTypeByExtension_LocalData(t *testing.T) {
-	cleanup := setMimeInit(func() {
-		clearMimeTypes()
-		setType(".foo", "x/foo")
-		setType(".bar", "x/bar")
-		setType(".Bar", "x/bar; capital=1")
-	})
-	defer cleanup()
-
-	tests := map[string]string{
-		".foo":          "x/foo",
-		".bar":          "x/bar",
-		".Bar":          "x/bar; capital=1",
-		".sdlkfjskdlfj": "",
-		".t1":           "", // testdata shouldn't be used
-	}
-
-	for ext, want := range tests {
-		val := TypeByExtension(ext)
-		if val != want {
-			t.Errorf("TypeByExtension(%q) = %q, want %q", ext, val, want)
-		}
-	}
-}
-
 func TestTypeByExtensionCase(t *testing.T) {
 	const custom = "test/test; charset=iso-8859-1"
 	const caps = "test/test; WAS=ALLCAPS"
-
-	cleanup := setMimeInit(func() {
-		clearMimeTypes()
-		setType(".TEST", caps)
-		setType(".tesT", custom)
-	})
-	defer cleanup()
+	if err := AddExtensionType(".TEST", caps); err != nil {
+		t.Fatalf("error %s for AddExtension(%s)", err, custom)
+	}
+	if err := AddExtensionType(".tesT", custom); err != nil {
+		t.Fatalf("error %s for AddExtension(%s)", err, custom)
+	}
 
 	// case-sensitive lookup
 	if got := TypeByExtension(".tesT"); got != custom {
@@ -98,47 +43,6 @@ func TestTypeByExtensionCase(t *testing.T) {
 	}
 }
 
-func TestExtensionsByType(t *testing.T) {
-	cleanup := setMimeInit(func() {
-		clearMimeTypes()
-		setType(".gif", "image/gif")
-		setType(".a", "foo/letter")
-		setType(".b", "foo/letter")
-		setType(".B", "foo/letter")
-		setType(".PNG", "image/png")
-	})
-	defer cleanup()
-
-	tests := []struct {
-		typ     string
-		want    []string
-		wantErr string
-	}{
-		{typ: "image/gif", want: []string{".gif"}},
-		{typ: "image/png", want: []string{".png"}}, // lowercase
-		{typ: "foo/letter", want: []string{".a", ".b"}},
-		{typ: "x/unknown", want: nil},
-	}
-
-	for _, tt := range tests {
-		got, err := ExtensionsByType(tt.typ)
-		if err != nil && tt.wantErr != "" && strings.Contains(err.Error(), tt.wantErr) {
-			continue
-		}
-		if err != nil {
-			t.Errorf("ExtensionsByType(%q) error: %v", tt.typ, err)
-			continue
-		}
-		if tt.wantErr != "" {
-			t.Errorf("ExtensionsByType(%q) = %q, %v; want error substring %q", tt.typ, got, err, tt.wantErr)
-			continue
-		}
-		if !reflect.DeepEqual(got, tt.want) {
-			t.Errorf("ExtensionsByType(%q) = %q; want %q", tt.typ, got, tt.want)
-		}
-	}
-}
-
 func TestLookupMallocs(t *testing.T) {
 	n := testing.AllocsPerRun(10000, func() {
 		TypeByExtension(".html")
diff --git a/src/mime/type_unix.go b/src/mime/type_unix.go
index bb06a77..3e404cf 100644
--- a/src/mime/type_unix.go
+++ b/src/mime/type_unix.go
@@ -12,10 +12,6 @@ import (
 	"strings"
 )
 
-func init() {
-	osInitMime = initMimeUnix
-}
-
 var typeFiles = []string{
 	"/etc/mime.types",
 	"/etc/apache2/mime.types",
@@ -48,7 +44,7 @@ func loadMimeFile(filename string) {
 	}
 }
 
-func initMimeUnix() {
+func initMime() {
 	for _, filename := range typeFiles {
 		loadMimeFile(filename)
 	}
diff --git a/src/mime/type_windows.go b/src/mime/type_windows.go
index 97b9aeb..ae758d7 100644
--- a/src/mime/type_windows.go
+++ b/src/mime/type_windows.go
@@ -5,32 +5,54 @@
 package mime
 
 import (
-	"internal/syscall/windows/registry"
+	"syscall"
+	"unsafe"
 )
 
-func init() {
-	osInitMime = initMimeWindows
-}
-
-func initMimeWindows() {
-	names, err := registry.CLASSES_ROOT.ReadSubKeyNames(-1)
-	if err != nil {
+func initMime() {
+	var root syscall.Handle
+	rootpathp, _ := syscall.UTF16PtrFromString(`\`)
+	if syscall.RegOpenKeyEx(syscall.HKEY_CLASSES_ROOT, rootpathp,
+		0, syscall.KEY_READ, &root) != nil {
+		return
+	}
+	defer syscall.RegCloseKey(root)
+	var count uint32
+	if syscall.RegQueryInfoKey(root, nil, nil, nil, &count, nil, nil, nil, nil, nil, nil, nil) != nil {
 		return
 	}
-	for _, name := range names {
-		if len(name) < 2 || name[0] != '.' { // looking for extensions only
+	var buf [1 << 10]uint16
+	for i := uint32(0); i < count; i++ {
+		n := uint32(len(buf))
+		if syscall.RegEnumKeyEx(root, i, &buf[0], &n, nil, nil, nil, nil) != nil {
+			continue
+		}
+		ext := syscall.UTF16ToString(buf[:])
+		if len(ext) < 2 || ext[0] != '.' { // looking for extensions only
+			continue
+		}
+		var h syscall.Handle
+		extpathp, _ := syscall.UTF16PtrFromString(`\` + ext)
+		if syscall.RegOpenKeyEx(
+			syscall.HKEY_CLASSES_ROOT, extpathp,
+			0, syscall.KEY_READ, &h) != nil {
 			continue
 		}
-		k, err := registry.OpenKey(registry.CLASSES_ROOT, name, registry.READ)
-		if err != nil {
+		var typ uint32
+		n = uint32(len(buf) * 2) // api expects array of bytes, not uint16
+		contenttypep, _ := syscall.UTF16PtrFromString("Content Type")
+		if syscall.RegQueryValueEx(
+			h, contenttypep,
+			nil, &typ, (*byte)(unsafe.Pointer(&buf[0])), &n) != nil {
+			syscall.RegCloseKey(h)
 			continue
 		}
-		v, _, err := k.GetStringValue("Content Type")
-		k.Close()
-		if err != nil {
+		syscall.RegCloseKey(h)
+		if typ != syscall.REG_SZ { // null terminated strings only
 			continue
 		}
-		setExtensionType(name, v)
+		mimeType := syscall.UTF16ToString(buf[:])
+		setExtensionType(ext, mimeType)
 	}
 }
 
diff --git a/src/nacltest.bash b/src/nacltest.bash
index 049aad2..6220d39 100755
--- a/src/nacltest.bash
+++ b/src/nacltest.bash
@@ -59,24 +59,22 @@ if ! which go_nacl_${naclGOARCH}_exec >/dev/null; then
 	exit 1
 fi
 
+# Run host build to get toolchain for running zip generator.
 unset GOOS GOARCH
 if [ ! -f make.bash ]; then
-	echo 'nacltest.bash must be run from $GOROOT/src' 1>&2
+	echo 'nacl.bash must be run from $GOROOT/src' 1>&2
 	exit 1
 fi
+GOOS=$GOHOSTOS GOARCH=$GOHOSTARCH ./make.bash
 
 # the builder might have set GOROOT_FINAL.
 export GOROOT=$(pwd)/..
 
 # Build zip file embedded in package syscall.
-echo "##### Building fake file system zip for nacl"
+gobin=${GOBIN:-$(pwd)/../bin}
 rm -f syscall/fstest_nacl.go
-GOROOT_BOOTSTRAP=${GOROOT_BOOTSTRAP:-$HOME/go1.4}
-gobin=$GOROOT_BOOTSTRAP/bin
-GOROOT=$GOROOT_BOOTSTRAP $gobin/go run ../misc/nacl/mkzip.go -p syscall -r .. ../misc/nacl/testzip.proto syscall/fstest_nacl.go
+GOOS=$GOHOSTOS GOARCH=$GOHOSTARCH $gobin/go run ../misc/nacl/mkzip.go -p syscall -r .. ../misc/nacl/testzip.proto syscall/fstest_nacl.go
 
 # Run standard build and tests.
 export PATH=$(pwd)/../misc/nacl:$PATH
-GOOS=nacl GOARCH=$naclGOARCH ./all.bash
-
-rm -f syscall/fstest_nacl.go
+GOOS=nacl GOARCH=$naclGOARCH ./all.bash --no-clean
diff --git a/src/net/cgo_android.go b/src/net/cgo_android.go
index fe9925b..3819ce5 100644
--- a/src/net/cgo_android.go
+++ b/src/net/cgo_android.go
@@ -9,4 +9,6 @@ package net
 //#include <netdb.h>
 import "C"
 
-const cgoAddrInfoFlags = C.AI_CANONNAME
+func cgoAddrInfoFlags() C.int {
+	return C.AI_CANONNAME
+}
diff --git a/src/net/cgo_bsd.go b/src/net/cgo_bsd.go
index c5ec9dd..3090d30 100644
--- a/src/net/cgo_bsd.go
+++ b/src/net/cgo_bsd.go
@@ -2,8 +2,8 @@
 // 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
+// +build !netgo
+// +build darwin dragonfly freebsd solaris
 
 package net
 
@@ -12,4 +12,6 @@ package net
 */
 import "C"
 
-const cgoAddrInfoFlags = (C.AI_CANONNAME | C.AI_V4MAPPED | C.AI_ALL) & C.AI_MASK
+func cgoAddrInfoFlags() C.int {
+	return (C.AI_CANONNAME | C.AI_V4MAPPED | C.AI_ALL) & C.AI_MASK
+}
diff --git a/src/net/cgo_linux.go b/src/net/cgo_linux.go
index 9a5f898..4ef2d0c 100644
--- a/src/net/cgo_linux.go
+++ b/src/net/cgo_linux.go
@@ -11,10 +11,12 @@ package net
 */
 import "C"
 
-// NOTE(rsc): In theory there are approximately balanced
-// arguments for and against including AI_ADDRCONFIG
-// in the flags (it includes IPv4 results only on IPv4 systems,
-// and similarly for IPv6), but in practice setting it causes
-// getaddrinfo to return the wrong canonical name on Linux.
-// So definitely leave it out.
-const cgoAddrInfoFlags = C.AI_CANONNAME | C.AI_V4MAPPED | C.AI_ALL
+func cgoAddrInfoFlags() C.int {
+	// NOTE(rsc): In theory there are approximately balanced
+	// arguments for and against including AI_ADDRCONFIG
+	// in the flags (it includes IPv4 results only on IPv4 systems,
+	// and similarly for IPv6), but in practice setting it causes
+	// getaddrinfo to return the wrong canonical name on Linux.
+	// So definitely leave it out.
+	return C.AI_CANONNAME | C.AI_V4MAPPED | C.AI_ALL
+}
diff --git a/src/net/cgo_netbsd.go b/src/net/cgo_netbsd.go
index 1830913..09c5ad2 100644
--- a/src/net/cgo_netbsd.go
+++ b/src/net/cgo_netbsd.go
@@ -11,4 +11,6 @@ package net
 */
 import "C"
 
-const cgoAddrInfoFlags = C.AI_CANONNAME
+func cgoAddrInfoFlags() C.int {
+	return C.AI_CANONNAME
+}
diff --git a/src/net/cgo_openbsd.go b/src/net/cgo_openbsd.go
index 1830913..09c5ad2 100644
--- a/src/net/cgo_openbsd.go
+++ b/src/net/cgo_openbsd.go
@@ -11,4 +11,6 @@ package net
 */
 import "C"
 
-const cgoAddrInfoFlags = C.AI_CANONNAME
+func cgoAddrInfoFlags() C.int {
+	return C.AI_CANONNAME
+}
diff --git a/src/net/cgo_stub.go b/src/net/cgo_stub.go
index b86ff7d..f533c14 100644
--- a/src/net/cgo_stub.go
+++ b/src/net/cgo_stub.go
@@ -4,15 +4,9 @@
 
 // +build !cgo netgo
 
-package net
-
-func init() { netGo = true }
+// Stub cgo routines for systems that do not use cgo to do network lookups.
 
-type addrinfoErrno int
-
-func (eai addrinfoErrno) Error() string   { return "<nil>" }
-func (eai addrinfoErrno) Temporary() bool { return false }
-func (eai addrinfoErrno) Timeout() bool   { return false }
+package net
 
 func cgoLookupHost(name string) (addrs []string, err error, completed bool) {
 	return nil, nil, false
@@ -22,14 +16,10 @@ func cgoLookupPort(network, service string) (port int, err error, completed bool
 	return 0, nil, false
 }
 
-func cgoLookupIP(name string) (addrs []IPAddr, err error, completed bool) {
+func cgoLookupIP(name string) (addrs []IP, err error, completed bool) {
 	return nil, nil, false
 }
 
 func cgoLookupCNAME(name string) (cname string, err error, completed bool) {
 	return "", nil, false
 }
-
-func cgoLookupPTR(addr string) (ptrs []string, err error, completed bool) {
-	return nil, nil, false
-}
diff --git a/src/net/cgo_unix.go b/src/net/cgo_unix.go
index cb89d65..1f366ee 100644
--- a/src/net/cgo_unix.go
+++ b/src/net/cgo_unix.go
@@ -2,8 +2,8 @@
 // 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
+// +build !netgo
+// +build darwin dragonfly freebsd linux netbsd openbsd
 
 package net
 
@@ -23,30 +23,24 @@ import (
 	"unsafe"
 )
 
-// An addrinfoErrno represents a getaddrinfo, getnameinfo-specific
-// error number. It's a signed number and a zero value is a non-error
-// by convention.
-type addrinfoErrno int
-
-func (eai addrinfoErrno) Error() string   { return C.GoString(C.gai_strerror(C.int(eai))) }
-func (eai addrinfoErrno) Temporary() bool { return eai == C.EAI_AGAIN }
-func (eai addrinfoErrno) Timeout() bool   { return false }
-
-func cgoLookupHost(name string) (hosts []string, err error, completed bool) {
-	addrs, err, completed := cgoLookupIP(name)
-	for _, addr := range addrs {
-		hosts = append(hosts, addr.String())
+func cgoLookupHost(name string) (addrs []string, err error, completed bool) {
+	ip, err, completed := cgoLookupIP(name)
+	for _, p := range ip {
+		addrs = append(addrs, p.String())
 	}
 	return
 }
 
-func cgoLookupPort(network, service string) (port int, err error, completed bool) {
+func cgoLookupPort(net, service string) (port int, err error, completed bool) {
 	acquireThread()
 	defer releaseThread()
 
+	var res *C.struct_addrinfo
 	var hints C.struct_addrinfo
-	switch network {
-	case "": // no hints
+
+	switch net {
+	case "":
+		// no hints
 	case "tcp", "tcp4", "tcp6":
 		hints.ai_socktype = C.SOCK_STREAM
 		hints.ai_protocol = C.IPPROTO_TCP
@@ -54,10 +48,10 @@ func cgoLookupPort(network, service string) (port int, err error, completed bool
 		hints.ai_socktype = C.SOCK_DGRAM
 		hints.ai_protocol = C.IPPROTO_UDP
 	default:
-		return 0, &DNSError{Err: "unknown network", Name: network + "/" + service}, true
+		return 0, UnknownNetworkError(net), true
 	}
-	if len(network) >= 4 {
-		switch network[3] {
+	if len(net) >= 4 {
+		switch net[3] {
 		case '4':
 			hints.ai_family = C.AF_INET
 		case '6':
@@ -66,52 +60,45 @@ func cgoLookupPort(network, service string) (port int, err error, completed bool
 	}
 
 	s := C.CString(service)
-	var res *C.struct_addrinfo
 	defer C.free(unsafe.Pointer(s))
-	gerrno, err := C.getaddrinfo(nil, s, &hints, &res)
-	if gerrno != 0 {
-		switch gerrno {
-		case C.EAI_SYSTEM:
-			if err == nil { // see golang.org/issue/6232
-				err = syscall.EMFILE
+	if C.getaddrinfo(nil, s, &hints, &res) == 0 {
+		defer C.freeaddrinfo(res)
+		for r := res; r != nil; r = r.ai_next {
+			switch r.ai_family {
+			default:
+				continue
+			case C.AF_INET:
+				sa := (*syscall.RawSockaddrInet4)(unsafe.Pointer(r.ai_addr))
+				p := (*[2]byte)(unsafe.Pointer(&sa.Port))
+				return int(p[0])<<8 | int(p[1]), nil, true
+			case C.AF_INET6:
+				sa := (*syscall.RawSockaddrInet6)(unsafe.Pointer(r.ai_addr))
+				p := (*[2]byte)(unsafe.Pointer(&sa.Port))
+				return int(p[0])<<8 | int(p[1]), nil, true
 			}
-		default:
-			err = addrinfoErrno(gerrno)
 		}
-		return 0, &DNSError{Err: err.Error(), Name: network + "/" + service}, true
 	}
-	defer C.freeaddrinfo(res)
-
-	for r := res; r != nil; r = r.ai_next {
-		switch r.ai_family {
-		case C.AF_INET:
-			sa := (*syscall.RawSockaddrInet4)(unsafe.Pointer(r.ai_addr))
-			p := (*[2]byte)(unsafe.Pointer(&sa.Port))
-			return int(p[0])<<8 | int(p[1]), nil, true
-		case C.AF_INET6:
-			sa := (*syscall.RawSockaddrInet6)(unsafe.Pointer(r.ai_addr))
-			p := (*[2]byte)(unsafe.Pointer(&sa.Port))
-			return int(p[0])<<8 | int(p[1]), nil, true
-		}
-	}
-	return 0, &DNSError{Err: "unknown port", Name: network + "/" + service}, true
+	return 0, &AddrError{"unknown port", net + "/" + service}, true
 }
 
-func cgoLookupIPCNAME(name string) (addrs []IPAddr, cname string, err error, completed bool) {
+func cgoLookupIPCNAME(name string) (addrs []IP, cname string, err error, completed bool) {
 	acquireThread()
 	defer releaseThread()
 
+	var res *C.struct_addrinfo
 	var hints C.struct_addrinfo
-	hints.ai_flags = cgoAddrInfoFlags
+
+	hints.ai_flags = cgoAddrInfoFlags()
 	hints.ai_socktype = C.SOCK_STREAM
 
 	h := C.CString(name)
 	defer C.free(unsafe.Pointer(h))
-	var res *C.struct_addrinfo
 	gerrno, err := C.getaddrinfo(h, nil, &hints, &res)
 	if gerrno != 0 {
-		switch gerrno {
-		case C.EAI_SYSTEM:
+		var str string
+		if gerrno == C.EAI_NONAME {
+			str = noSuchHost
+		} else if gerrno == C.EAI_SYSTEM {
 			if err == nil {
 				// err should not be nil, but sometimes getaddrinfo returns
 				// gerrno == C.EAI_SYSTEM with err == nil on Linux.
@@ -122,15 +109,13 @@ func cgoLookupIPCNAME(name string) (addrs []IPAddr, cname string, err error, com
 				// comes up again. golang.org/issue/6232.
 				err = syscall.EMFILE
 			}
-		case C.EAI_NONAME:
-			err = errNoSuchHost
-		default:
-			err = addrinfoErrno(gerrno)
+			str = err.Error()
+		} else {
+			str = C.GoString(C.gai_strerror(gerrno))
 		}
-		return nil, "", &DNSError{Err: err.Error(), Name: name}, true
+		return nil, "", &DNSError{Err: str, Name: name}, true
 	}
 	defer C.freeaddrinfo(res)
-
 	if res != nil {
 		cname = C.GoString(res.ai_canonname)
 		if cname == "" {
@@ -146,20 +131,20 @@ func cgoLookupIPCNAME(name string) (addrs []IPAddr, cname string, err error, com
 			continue
 		}
 		switch r.ai_family {
+		default:
+			continue
 		case C.AF_INET:
 			sa := (*syscall.RawSockaddrInet4)(unsafe.Pointer(r.ai_addr))
-			addr := IPAddr{IP: copyIP(sa.Addr[:])}
-			addrs = append(addrs, addr)
+			addrs = append(addrs, copyIP(sa.Addr[:]))
 		case C.AF_INET6:
 			sa := (*syscall.RawSockaddrInet6)(unsafe.Pointer(r.ai_addr))
-			addr := IPAddr{IP: copyIP(sa.Addr[:]), Zone: zoneToString(int(sa.Scope_id))}
-			addrs = append(addrs, addr)
+			addrs = append(addrs, copyIP(sa.Addr[:]))
 		}
 	}
 	return addrs, cname, nil, true
 }
 
-func cgoLookupIP(name string) (addrs []IPAddr, err error, completed bool) {
+func cgoLookupIP(name string) (addrs []IP, err error, completed bool) {
 	addrs, _, err, completed = cgoLookupIPCNAME(name)
 	return
 }
@@ -169,77 +154,6 @@ func cgoLookupCNAME(name string) (cname string, err error, completed bool) {
 	return
 }
 
-// These are roughly enough for the following:
-//
-// Source		Encoding			Maximum length of single name entry
-// Unicast DNS		ASCII or			<=253 + a NUL terminator
-//			Unicode in RFC 5892		252 * total number of labels + delimiters + a NUL terminator
-// Multicast DNS	UTF-8 in RFC 5198 or		<=253 + a NUL terminator
-//			the same as unicast DNS ASCII	<=253 + a NUL terminator
-// Local database	various				depends on implementation
-const (
-	nameinfoLen    = 64
-	maxNameinfoLen = 4096
-)
-
-func cgoLookupPTR(addr string) ([]string, error, bool) {
-	acquireThread()
-	defer releaseThread()
-
-	ip := ParseIP(addr)
-	if ip == nil {
-		return nil, &DNSError{Err: "invalid address", Name: addr}, true
-	}
-	sa, salen := cgoSockaddr(ip)
-	if sa == nil {
-		return nil, &DNSError{Err: "invalid address " + ip.String(), Name: addr}, true
-	}
-	var err error
-	var b []byte
-	var gerrno int
-	for l := nameinfoLen; l <= maxNameinfoLen; l *= 2 {
-		b = make([]byte, l)
-		gerrno, err = cgoNameinfoPTR(b, sa, salen)
-		if gerrno == 0 || gerrno != C.EAI_OVERFLOW {
-			break
-		}
-	}
-	if gerrno != 0 {
-		switch gerrno {
-		case C.EAI_SYSTEM:
-			if err == nil { // see golang.org/issue/6232
-				err = syscall.EMFILE
-			}
-		default:
-			err = addrinfoErrno(gerrno)
-		}
-		return nil, &DNSError{Err: err.Error(), Name: addr}, true
-	}
-
-	for i := 0; i < len(b); i++ {
-		if b[i] == 0 {
-			b = b[:i]
-			break
-		}
-	}
-	// Add trailing dot to match pure Go reverse resolver
-	// and all other lookup routines. See golang.org/issue/12189.
-	if len(b) > 0 && b[len(b)-1] != '.' {
-		b = append(b, '.')
-	}
-	return []string{string(b)}, nil, true
-}
-
-func cgoSockaddr(ip IP) (*C.struct_sockaddr, C.socklen_t) {
-	if ip4 := ip.To4(); ip4 != nil {
-		return cgoSockaddrInet4(ip4), C.socklen_t(syscall.SizeofSockaddrInet4)
-	}
-	if ip6 := ip.To16(); ip6 != nil {
-		return cgoSockaddrInet6(ip6), C.socklen_t(syscall.SizeofSockaddrInet6)
-	}
-	return nil, 0
-}
-
 func copyIP(x IP) IP {
 	if len(x) < 16 {
 		return x.To16()
diff --git a/src/net/cgo_unix_test.go b/src/net/cgo_unix_test.go
index 4d5ab23..33566ce 100644
--- a/src/net/cgo_unix_test.go
+++ b/src/net/cgo_unix_test.go
@@ -3,7 +3,7 @@
 // license that can be found in the LICENSE file.
 
 // +build cgo,!netgo
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build darwin dragonfly freebsd linux netbsd openbsd
 
 package net
 
@@ -16,9 +16,9 @@ func TestCgoLookupIP(t *testing.T) {
 		t.Errorf("cgoLookupIP must not be a placeholder")
 	}
 	if err != nil {
-		t.Error(err)
+		t.Errorf("cgoLookupIP failed: %v", err)
 	}
 	if _, err := goLookupIP(host); err != nil {
-		t.Error(err)
+		t.Errorf("goLookupIP failed: %v", err)
 	}
 }
diff --git a/src/net/conn_test.go b/src/net/conn_test.go
index 6995c11..9c9d1a8 100644
--- a/src/net/conn_test.go
+++ b/src/net/conn_test.go
@@ -8,58 +8,117 @@
 package net
 
 import (
+	"os"
+	"runtime"
 	"testing"
 	"time"
 )
 
+var connTests = []struct {
+	net  string
+	addr string
+}{
+	{"tcp", "127.0.0.1:0"},
+	{"unix", testUnixAddr()},
+	{"unixpacket", testUnixAddr()},
+}
+
 // someTimeout is used just to test that net.Conn implementations
 // don't explode when their SetFooDeadline methods are called.
 // It isn't actually used for testing timeouts.
 const someTimeout = 10 * time.Second
 
 func TestConnAndListener(t *testing.T) {
-	for i, network := range []string{"tcp", "unix", "unixpacket"} {
-		if !testableNetwork(network) {
-			t.Logf("skipping %s test", network)
-			continue
+	for _, tt := range connTests {
+		switch tt.net {
+		case "unix":
+			switch runtime.GOOS {
+			case "nacl", "plan9", "windows":
+				continue
+			}
+		case "unixpacket":
+			switch runtime.GOOS {
+			case "android", "darwin", "nacl", "openbsd", "plan9", "windows":
+				continue
+			case "freebsd": // FreeBSD 8 doesn't support unixpacket
+				continue
+			}
 		}
 
-		ls, err := newLocalServer(network)
+		ln, err := Listen(tt.net, tt.addr)
 		if err != nil {
-			t.Fatal(err)
+			t.Fatalf("Listen failed: %v", err)
 		}
-		defer ls.teardown()
-		ch := make(chan error, 1)
-		handler := func(ls *localServer, ln Listener) { transponder(ln, ch) }
-		if err := ls.buildup(handler); err != nil {
-			t.Fatal(err)
-		}
-		if ls.Listener.Addr().Network() != network {
-			t.Fatalf("got %s; want %s", ls.Listener.Addr().Network(), network)
+		defer func(ln Listener, net, addr string) {
+			ln.Close()
+			switch net {
+			case "unix", "unixpacket":
+				os.Remove(addr)
+			}
+		}(ln, tt.net, tt.addr)
+		if ln.Addr().Network() != tt.net {
+			t.Fatalf("got %v; expected %v", ln.Addr().Network(), tt.net)
 		}
 
-		c, err := Dial(ls.Listener.Addr().Network(), ls.Listener.Addr().String())
+		done := make(chan int)
+		go transponder(t, ln, done)
+
+		c, err := Dial(tt.net, ln.Addr().String())
 		if err != nil {
-			t.Fatal(err)
+			t.Fatalf("Dial failed: %v", err)
 		}
 		defer c.Close()
-		if c.LocalAddr().Network() != network || c.LocalAddr().Network() != network {
-			t.Fatalf("got %s->%s; want %s->%s", c.LocalAddr().Network(), c.RemoteAddr().Network(), network, network)
+		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))
 
-		if _, err := c.Write([]byte("CONN AND LISTENER TEST")); err != nil {
-			t.Fatal(err)
+		if _, err := c.Write([]byte("CONN TEST")); err != nil {
+			t.Fatalf("Conn.Write failed: %v", err)
 		}
 		rb := make([]byte, 128)
 		if _, err := c.Read(rb); err != nil {
-			t.Fatal(err)
+			t.Fatalf("Conn.Read failed: %v", err)
 		}
 
-		for err := range ch {
-			t.Errorf("#%d: %v", i, err)
-		}
+		<-done
+	}
+}
+
+func transponder(t *testing.T, ln Listener, done chan<- int) {
+	defer func() { done <- 1 }()
+
+	switch ln := ln.(type) {
+	case *TCPListener:
+		ln.SetDeadline(time.Now().Add(someTimeout))
+	case *UnixListener:
+		ln.SetDeadline(time.Now().Add(someTimeout))
+	}
+	c, err := ln.Accept()
+	if err != nil {
+		t.Errorf("Listener.Accept failed: %v", err)
+		return
+	}
+	defer c.Close()
+	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))
+
+	b := make([]byte, 128)
+	n, err := c.Read(b)
+	if err != nil {
+		t.Errorf("Conn.Read failed: %v", err)
+		return
+	}
+	if _, err := c.Write(b[:n]); err != nil {
+		t.Errorf("Conn.Write failed: %v", err)
+		return
 	}
 }
diff --git a/src/net/dial.go b/src/net/dial.go
index cb4ec21..e6f0436 100644
--- a/src/net/dial.go
+++ b/src/net/dial.go
@@ -21,9 +21,6 @@ type Dialer struct {
 	//
 	// The default is no timeout.
 	//
-	// When dialing a name with multiple IP addresses, the timeout
-	// may be divided between them.
-	//
 	// With or without a timeout, the operating system may impose
 	// its own earlier timeout. For instance, TCP timeouts are
 	// often around 3 minutes.
@@ -41,17 +38,13 @@ type Dialer struct {
 	// If nil, a local address is automatically chosen.
 	LocalAddr Addr
 
-	// DualStack enables RFC 6555-compliant "Happy Eyeballs" dialing
-	// when the network is "tcp" and the destination is a host name
-	// with both IPv4 and IPv6 addresses. This allows a client to
-	// tolerate networks where one address family is silently broken.
+	// DualStack allows a single dial to attempt to establish
+	// multiple IPv4 and IPv6 connections and to return the first
+	// established connection when the network is "tcp" and the
+	// destination is a host name that has multiple address family
+	// DNS records.
 	DualStack bool
 
-	// FallbackDelay specifies the length of time to wait before
-	// spawning a fallback connection, when DualStack is enabled.
-	// If zero, a default delay of 300ms is used.
-	FallbackDelay time.Duration
-
 	// KeepAlive specifies the keep-alive period for an active
 	// network connection.
 	// If zero, keep-alives are not enabled. Network protocols
@@ -61,11 +54,11 @@ type Dialer struct {
 
 // Return either now+Timeout or Deadline, whichever comes first.
 // Or zero, if neither is set.
-func (d *Dialer) deadline(now time.Time) time.Time {
+func (d *Dialer) deadline() time.Time {
 	if d.Timeout == 0 {
 		return d.Deadline
 	}
-	timeoutDeadline := now.Add(d.Timeout)
+	timeoutDeadline := time.Now().Add(d.Timeout)
 	if d.Deadline.IsZero() || timeoutDeadline.Before(d.Deadline) {
 		return timeoutDeadline
 	} else {
@@ -73,38 +66,6 @@ func (d *Dialer) deadline(now time.Time) time.Time {
 	}
 }
 
-// partialDeadline returns the deadline to use for a single address,
-// when multiple addresses are pending.
-func partialDeadline(now, deadline time.Time, addrsRemaining int) (time.Time, error) {
-	if deadline.IsZero() {
-		return deadline, nil
-	}
-	timeRemaining := deadline.Sub(now)
-	if timeRemaining <= 0 {
-		return time.Time{}, errTimeout
-	}
-	// Tentatively allocate equal time to each remaining address.
-	timeout := timeRemaining / time.Duration(addrsRemaining)
-	// If the time per address is too short, steal from the end of the list.
-	const saneMinimum = 2 * time.Second
-	if timeout < saneMinimum {
-		if timeRemaining < saneMinimum {
-			timeout = timeRemaining
-		} else {
-			timeout = saneMinimum
-		}
-	}
-	return now.Add(timeout), nil
-}
-
-func (d *Dialer) fallbackDelay() time.Duration {
-	if d.FallbackDelay > 0 {
-		return d.FallbackDelay
-	} else {
-		return 300 * time.Millisecond
-	}
-}
-
 func parseNetwork(net string) (afnet string, proto int, err error) {
 	i := last(net, ':')
 	if i < 0 { // no colon
@@ -134,7 +95,7 @@ func parseNetwork(net string) (afnet string, proto int, err error) {
 	return "", 0, UnknownNetworkError(net)
 }
 
-func resolveAddrList(op, net, addr string, deadline time.Time) (addrList, error) {
+func resolveAddr(op, net, addr string, deadline time.Time) (netaddr, error) {
 	afnet, _, err := parseNetwork(net)
 	if err != nil {
 		return nil, err
@@ -144,13 +105,9 @@ func resolveAddrList(op, net, addr string, deadline time.Time) (addrList, error)
 	}
 	switch afnet {
 	case "unix", "unixgram", "unixpacket":
-		addr, err := ResolveUnixAddr(afnet, addr)
-		if err != nil {
-			return nil, err
-		}
-		return addrList{addr}, nil
+		return ResolveUnixAddr(afnet, addr)
 	}
-	return internetAddrList(afnet, addr, deadline)
+	return resolveInternetAddr(afnet, addr, deadline)
 }
 
 // Dial connects to the address on the named network.
@@ -193,186 +150,100 @@ func DialTimeout(network, address string, timeout time.Duration) (Conn, error) {
 	return d.Dial(network, address)
 }
 
-// dialContext holds common state for all dial operations.
-type dialContext struct {
-	Dialer
-	network, address string
-	finalDeadline    time.Time
-}
-
 // Dial connects to the address on the named network.
 //
 // See func Dial for a description of the network and address
 // parameters.
 func (d *Dialer) Dial(network, address string) (Conn, error) {
-	finalDeadline := d.deadline(time.Now())
-	addrs, err := resolveAddrList("dial", network, address, finalDeadline)
+	ra, err := resolveAddr("dial", network, address, d.deadline())
 	if err != nil {
-		return nil, &OpError{Op: "dial", Net: network, Source: nil, Addr: nil, Err: err}
-	}
-
-	ctx := &dialContext{
-		Dialer:        *d,
-		network:       network,
-		address:       address,
-		finalDeadline: finalDeadline,
+		return nil, &OpError{Op: "dial", Net: network, Addr: nil, Err: err}
 	}
-
-	var primaries, fallbacks addrList
-	if d.DualStack && network == "tcp" {
-		primaries, fallbacks = addrs.partition(isIPv4)
-	} else {
-		primaries = addrs
+	dialer := func(deadline time.Time) (Conn, error) {
+		return dialSingle(network, address, d.LocalAddr, ra.toAddr(), deadline)
 	}
-
-	var c Conn
-	if len(fallbacks) == 0 {
-		// dialParallel can accept an empty fallbacks list,
-		// but this shortcut avoids the goroutine/channel overhead.
-		c, err = dialSerial(ctx, primaries, nil)
-	} else {
-		c, err = dialParallel(ctx, primaries, fallbacks)
+	if ras, ok := ra.(addrList); ok && d.DualStack && network == "tcp" {
+		dialer = func(deadline time.Time) (Conn, error) {
+			return dialMulti(network, address, d.LocalAddr, ras, deadline)
+		}
 	}
-
+	c, err := dial(network, ra.toAddr(), dialer, d.deadline())
 	if d.KeepAlive > 0 && err == nil {
 		if tc, ok := c.(*TCPConn); ok {
-			setKeepAlive(tc.fd, true)
-			setKeepAlivePeriod(tc.fd, d.KeepAlive)
+			tc.SetKeepAlive(true)
+			tc.SetKeepAlivePeriod(d.KeepAlive)
 			testHookSetKeepAlive()
 		}
 	}
 	return c, err
 }
 
-// dialParallel races two copies of dialSerial, giving the first a
-// head start. It returns the first established connection and
-// closes the others. Otherwise it returns an error from the first
-// primary address.
-func dialParallel(ctx *dialContext, primaries, fallbacks addrList) (Conn, error) {
-	results := make(chan dialResult) // unbuffered, so dialSerialAsync can detect race loss & cleanup
-	cancel := make(chan struct{})
-	defer close(cancel)
-
-	// Spawn the primary racer.
-	go dialSerialAsync(ctx, primaries, nil, cancel, results)
-
-	// Spawn the fallback racer.
-	fallbackTimer := time.NewTimer(ctx.fallbackDelay())
-	go dialSerialAsync(ctx, fallbacks, fallbackTimer, cancel, results)
+var testHookSetKeepAlive = func() {} // changed by dial_test.go
 
-	var primaryErr error
-	for nracers := 2; nracers > 0; nracers-- {
-		res := <-results
-		// If we're still waiting for a connection, then hasten the delay.
-		// Otherwise, disable the Timer and let cancel take over.
-		if fallbackTimer.Stop() && res.error != nil {
-			fallbackTimer.Reset(0)
-		}
-		if res.error == nil {
-			return res.Conn, nil
-		}
-		if res.primary {
-			primaryErr = res.error
-		}
-	}
-	return nil, primaryErr
-}
-
-type dialResult struct {
-	Conn
-	error
-	primary bool
-}
-
-// dialSerialAsync runs dialSerial after some delay, and returns the
-// resulting connection through a channel. When racing two connections,
-// the primary goroutine uses a nil timer to omit the delay.
-func dialSerialAsync(ctx *dialContext, ras addrList, timer *time.Timer, cancel <-chan struct{}, results chan<- dialResult) {
-	if timer != nil {
-		// We're in the fallback goroutine; sleep before connecting.
-		select {
-		case <-timer.C:
-		case <-cancel:
-			return
-		}
+// 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
+// error on the last attempt.
+func dialMulti(net, addr string, la Addr, ras addrList, deadline time.Time) (Conn, error) {
+	type racer struct {
+		Conn
+		error
 	}
-	c, err := dialSerial(ctx, ras, cancel)
-	select {
-	case results <- dialResult{c, err, timer == nil}:
-		// We won the race.
-	case <-cancel:
-		// The other goroutine won the race.
-		if c != nil {
-			c.Close()
-		}
-	}
-}
-
-// dialSerial connects to a list of addresses in sequence, returning
-// either the first successful connection, or the first error.
-func dialSerial(ctx *dialContext, ras addrList, cancel <-chan struct{}) (Conn, error) {
-	var firstErr error // The error from the first address is most relevant.
-
-	for i, ra := range ras {
-		select {
-		case <-cancel:
-			return nil, &OpError{Op: "dial", Net: ctx.network, Source: ctx.LocalAddr, Addr: ra, Err: errCanceled}
-		default:
-		}
-
-		partialDeadline, err := partialDeadline(time.Now(), ctx.finalDeadline, len(ras)-i)
-		if err != nil {
-			// Ran out of time.
-			if firstErr == nil {
-				firstErr = &OpError{Op: "dial", Net: ctx.network, Source: ctx.LocalAddr, Addr: ra, Err: err}
+	// Sig controls the flow of dial results on lane. It passes a
+	// token to the next racer and also indicates the end of flow
+	// by using closed channel.
+	sig := make(chan bool, 1)
+	lane := make(chan racer, 1)
+	for _, ra := range ras {
+		go func(ra Addr) {
+			c, err := dialSingle(net, addr, la, ra, deadline)
+			if _, ok := <-sig; ok {
+				lane <- racer{c, err}
+			} else if err == nil {
+				// We have to return the resources
+				// that belong to the other
+				// connections here for avoiding
+				// unnecessary resource starvation.
+				c.Close()
 			}
-			break
-		}
-
-		// dialTCP does not support cancelation (see golang.org/issue/11225),
-		// so if cancel fires, we'll continue trying to connect until the next
-		// timeout, or return a spurious connection for the caller to close.
-		dialer := func(d time.Time) (Conn, error) {
-			return dialSingle(ctx, ra, d)
-		}
-		c, err := dial(ctx.network, ra, dialer, partialDeadline)
-		if err == nil {
-			return c, nil
-		}
-		if firstErr == nil {
-			firstErr = err
-		}
+		}(ra.toAddr())
 	}
-
-	if firstErr == nil {
-		firstErr = &OpError{Op: "dial", Net: ctx.network, Source: nil, Addr: nil, Err: errMissingAddress}
+	defer close(sig)
+	lastErr := errTimeout
+	nracers := len(ras)
+	for nracers > 0 {
+		sig <- true
+		racer := <-lane
+		if racer.error == nil {
+			return racer.Conn, nil
+		}
+		lastErr = racer.error
+		nracers--
 	}
-	return nil, firstErr
+	return nil, lastErr
 }
 
 // dialSingle attempts to establish and returns a single connection to
-// the destination address. This must be called through the OS-specific
-// dial function, because some OSes don't implement the deadline feature.
-func dialSingle(ctx *dialContext, ra Addr, deadline time.Time) (c Conn, err error) {
-	la := ctx.LocalAddr
+// the destination address.
+func dialSingle(net, addr string, la, ra Addr, deadline time.Time) (c Conn, err error) {
 	if la != nil && la.Network() != ra.Network() {
-		return nil, &OpError{Op: "dial", Net: ctx.network, Source: la, Addr: ra, Err: errors.New("mismatched local address type " + la.Network())}
+		return nil, &OpError{Op: "dial", Net: net, Addr: ra, Err: errors.New("mismatched local address type " + la.Network())}
 	}
 	switch ra := ra.(type) {
 	case *TCPAddr:
 		la, _ := la.(*TCPAddr)
-		c, err = testHookDialTCP(ctx.network, la, ra, deadline)
+		c, err = dialTCP(net, la, ra, deadline)
 	case *UDPAddr:
 		la, _ := la.(*UDPAddr)
-		c, err = dialUDP(ctx.network, la, ra, deadline)
+		c, err = dialUDP(net, la, ra, deadline)
 	case *IPAddr:
 		la, _ := la.(*IPAddr)
-		c, err = dialIP(ctx.network, la, ra, deadline)
+		c, err = dialIP(net, la, ra, deadline)
 	case *UnixAddr:
 		la, _ := la.(*UnixAddr)
-		c, err = dialUnix(ctx.network, la, ra, deadline)
+		c, err = dialUnix(net, la, ra, deadline)
 	default:
-		return nil, &OpError{Op: "dial", Net: ctx.network, Source: la, Addr: ra, Err: &AddrError{Err: "unexpected address type", Addr: ctx.address}}
+		return nil, &OpError{Op: "dial", Net: net, Addr: ra, Err: &AddrError{Err: "unexpected address type", Addr: addr}}
 	}
 	if err != nil {
 		return nil, err // c is non-nil interface containing nil pointer
@@ -385,18 +256,18 @@ func dialSingle(ctx *dialContext, ra Addr, deadline time.Time) (c Conn, err erro
 // "tcp6", "unix" or "unixpacket".
 // See Dial for the syntax of laddr.
 func Listen(net, laddr string) (Listener, error) {
-	addrs, err := resolveAddrList("listen", net, laddr, noDeadline)
+	la, err := resolveAddr("listen", net, laddr, noDeadline)
 	if err != nil {
-		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: nil, Err: err}
+		return nil, &OpError{Op: "listen", Net: net, Addr: nil, Err: err}
 	}
 	var l Listener
-	switch la := addrs.first(isIPv4).(type) {
+	switch la := la.toAddr().(type) {
 	case *TCPAddr:
 		l, err = ListenTCP(net, la)
 	case *UnixAddr:
 		l, err = ListenUnix(net, la)
 	default:
-		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: la, Err: &AddrError{Err: "unexpected address type", Addr: laddr}}
+		return nil, &OpError{Op: "listen", Net: net, Addr: la, Err: &AddrError{Err: "unexpected address type", Addr: laddr}}
 	}
 	if err != nil {
 		return nil, err // l is non-nil interface containing nil pointer
@@ -409,12 +280,12 @@ func Listen(net, laddr string) (Listener, error) {
 // "udp6", "ip", "ip4", "ip6" or "unixgram".
 // See Dial for the syntax of laddr.
 func ListenPacket(net, laddr string) (PacketConn, error) {
-	addrs, err := resolveAddrList("listen", net, laddr, noDeadline)
+	la, err := resolveAddr("listen", net, laddr, noDeadline)
 	if err != nil {
-		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: nil, Err: err}
+		return nil, &OpError{Op: "listen", Net: net, Addr: nil, Err: err}
 	}
 	var l PacketConn
-	switch la := addrs.first(isIPv4).(type) {
+	switch la := la.toAddr().(type) {
 	case *UDPAddr:
 		l, err = ListenUDP(net, la)
 	case *IPAddr:
@@ -422,7 +293,7 @@ func ListenPacket(net, laddr string) (PacketConn, error) {
 	case *UnixAddr:
 		l, err = ListenUnixgram(net, la)
 	default:
-		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: la, Err: &AddrError{Err: "unexpected address type", Addr: laddr}}
+		return nil, &OpError{Op: "listen", Net: net, Addr: la, Err: &AddrError{Err: "unexpected address type", Addr: laddr}}
 	}
 	if err != nil {
 		return nil, err // l is non-nil interface containing nil pointer
diff --git a/src/net/dial_gen.go b/src/net/dial_gen.go
index a628f71..ada6233 100644
--- a/src/net/dial_gen.go
+++ b/src/net/dial_gen.go
@@ -6,18 +6,22 @@
 
 package net
 
-import "time"
+import (
+	"time"
+)
+
+var testingIssue5349 bool // used during tests
 
 // dialChannel is the simple pure-Go implementation of dial, still
 // used on operating systems where the deadline hasn't been pushed
 // down into the pollserver. (Plan 9 and some old versions of Windows)
 func dialChannel(net string, ra Addr, dialer func(time.Time) (Conn, error), deadline time.Time) (Conn, error) {
-	if deadline.IsZero() {
-		return dialer(noDeadline)
+	var timeout time.Duration
+	if !deadline.IsZero() {
+		timeout = deadline.Sub(time.Now())
 	}
-	timeout := deadline.Sub(time.Now())
 	if timeout <= 0 {
-		return nil, &OpError{Op: "dial", Net: net, Source: nil, Addr: ra, Err: errTimeout}
+		return dialer(noDeadline)
 	}
 	t := time.NewTimer(timeout)
 	defer t.Stop()
@@ -27,13 +31,15 @@ func dialChannel(net string, ra Addr, dialer func(time.Time) (Conn, error), dead
 	}
 	ch := make(chan racer, 1)
 	go func() {
-		testHookDialChannel()
+		if testingIssue5349 {
+			time.Sleep(time.Millisecond)
+		}
 		c, err := dialer(noDeadline)
 		ch <- racer{c, err}
 	}()
 	select {
 	case <-t.C:
-		return nil, &OpError{Op: "dial", Net: net, Source: nil, Addr: ra, Err: errTimeout}
+		return nil, &OpError{Op: "dial", Net: net, Addr: ra, Err: errTimeout}
 	case racer := <-ch:
 		return racer.Conn, racer.error
 	}
diff --git a/src/net/dial_gen_test.go b/src/net/dial_gen_test.go
new file mode 100644
index 0000000..c857acd
--- /dev/null
+++ b/src/net/dial_gen_test.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 windows plan9
+
+package net
+
+func init() {
+	testingIssue5349 = true
+}
diff --git a/src/net/dial_test.go b/src/net/dial_test.go
index ed6d7cc..42898d6 100644
--- a/src/net/dial_test.go
+++ b/src/net/dial_test.go
@@ -5,50 +5,111 @@
 package net
 
 import (
+	"bytes"
+	"flag"
+	"fmt"
 	"io"
-	"net/internal/socktest"
+	"os"
+	"os/exec"
+	"reflect"
+	"regexp"
 	"runtime"
+	"strconv"
 	"sync"
 	"testing"
 	"time"
 )
 
-var prohibitionaryDialArgTests = []struct {
-	network string
-	address string
-}{
-	{"tcp6", "127.0.0.1"},
-	{"tcp6", "::ffff:127.0.0.1"},
-}
-
-func TestProhibitionaryDialArg(t *testing.T) {
-	switch runtime.GOOS {
-	case "plan9":
-		t.Skipf("not supported on %s", runtime.GOOS)
-	}
-	if testing.Short() || !*testExternal {
-		t.Skip("avoid external network")
-	}
-	if !supportsIPv4map {
-		t.Skip("mapping ipv4 address inside ipv6 address not supported")
+func newLocalListener(t *testing.T) Listener {
+	ln, err := Listen("tcp", "127.0.0.1:0")
+	if err != nil {
+		ln, err = Listen("tcp6", "[::1]:0")
 	}
-
-	ln, err := Listen("tcp", "[::]:0")
 	if err != nil {
 		t.Fatal(err)
 	}
+	return ln
+}
+
+func TestDialTimeout(t *testing.T) {
+	origBacklog := listenerBacklog
+	defer func() {
+		listenerBacklog = origBacklog
+	}()
+	listenerBacklog = 1
+
+	ln := newLocalListener(t)
 	defer ln.Close()
 
-	_, port, err := SplitHostPort(ln.Addr().String())
-	if err != nil {
-		t.Fatal(err)
-	}
+	errc := make(chan error)
 
-	for i, tt := range prohibitionaryDialArgTests {
-		c, err := Dial(tt.network, JoinHostPort(tt.address, port))
-		if err == nil {
-			c.Close()
-			t.Errorf("#%d: %v", i, err)
+	numConns := listenerBacklog + 100
+
+	// TODO(bradfitz): It's hard to test this in a portable
+	// way. This is unfortunate, but works for now.
+	switch runtime.GOOS {
+	case "linux":
+		// The kernel will start accepting TCP connections before userspace
+		// gets a chance to not accept them, so fire off a bunch to fill up
+		// the kernel's backlog.  Then we test we get a failure after that.
+		for i := 0; i < numConns; i++ {
+			go func() {
+				_, err := DialTimeout("tcp", ln.Addr().String(), 200*time.Millisecond)
+				errc <- err
+			}()
+		}
+	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.
+		// Same for windows.
+		//
+		// Use an IANA reserved port (49151) instead of 80, because
+		// on our 386 builder, this Dial succeeds, connecting
+		// to an IIS web server somewhere.  The data center
+		// or VM or firewall must be stealing the TCP connection.
+		//
+		// IANA Service Name and Transport Protocol Port Number Registry
+		// <http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xml>
+		go func() {
+			c, err := DialTimeout("tcp", "127.0.71.111:49151", 200*time.Millisecond)
+			if err == nil {
+				err = fmt.Errorf("unexpected: connected to %s!", c.RemoteAddr())
+				c.Close()
+			}
+			errc <- err
+		}()
+	default:
+		// TODO(bradfitz):
+		// OpenBSD may have a reject route to 127/8 except 127.0.0.1/32
+		// by default. FreeBSD likely works, but is untested.
+		// TODO(rsc):
+		// The timeout never happens on Windows.  Why?  Issue 3016.
+		t.Skipf("skipping test on %q; untested.", runtime.GOOS)
+	}
+
+	connected := 0
+	for {
+		select {
+		case <-time.After(15 * time.Second):
+			t.Fatal("too slow")
+		case err := <-errc:
+			if err == nil {
+				connected++
+				if connected == numConns {
+					t.Fatal("all connections connected; expected some to time out")
+				}
+			} else {
+				terr, ok := err.(timeout)
+				if !ok {
+					t.Fatalf("got error %q; want error with timeout interface", err)
+				}
+				if !terr.Timeout() {
+					t.Fatalf("got error %q; not a timeout", err)
+				}
+				// Pass. We saw a timeout error.
+				return
+			}
 		}
 	}
 }
@@ -56,7 +117,7 @@ func TestProhibitionaryDialArg(t *testing.T) {
 func TestSelfConnect(t *testing.T) {
 	if runtime.GOOS == "windows" {
 		// TODO(brainman): do not know why it hangs.
-		t.Skip("known-broken test on windows")
+		t.Skip("skipping known-broken test on windows")
 	}
 
 	// Test that Dial does not honor self-connects.
@@ -99,518 +160,303 @@ func TestSelfConnect(t *testing.T) {
 	}
 }
 
-func TestDialTimeoutFDLeak(t *testing.T) {
-	switch runtime.GOOS {
-	case "plan9":
-		t.Skipf("%s does not have full support of socktest", runtime.GOOS)
-	}
+var runErrorTest = flag.Bool("run_error_test", false, "let TestDialError check for dns errors")
 
-	const T = 100 * time.Millisecond
-
-	switch runtime.GOOS {
-	case "plan9", "windows":
-		origTestHookDialChannel := testHookDialChannel
-		testHookDialChannel = func() { time.Sleep(2 * T) }
-		defer func() { testHookDialChannel = origTestHookDialChannel }()
-		if runtime.GOOS == "plan9" {
-			break
-		}
-		fallthrough
-	default:
-		sw.Set(socktest.FilterConnect, func(so *socktest.Status) (socktest.AfterFilter, error) {
-			time.Sleep(2 * T)
-			return nil, errTimeout
-		})
-		defer sw.Set(socktest.FilterConnect, nil)
-	}
-
-	// Avoid tracking open-close jitterbugs between netFD and
-	// socket that leads to confusion of information inside
-	// socktest.Switch.
-	// It may happen when the Dial call bumps against TCP
-	// simultaneous open. See selfConnect in tcpsock_posix.go.
-	defer func() {
-		sw.Set(socktest.FilterClose, nil)
-		forceCloseSockets()
-	}()
-	var mu sync.Mutex
-	var attempts int
-	sw.Set(socktest.FilterClose, func(so *socktest.Status) (socktest.AfterFilter, error) {
-		mu.Lock()
-		attempts++
-		mu.Unlock()
-		return nil, errTimedout
-	})
+type DialErrorTest struct {
+	Net     string
+	Raddr   string
+	Pattern string
+}
 
-	const N = 100
-	var wg sync.WaitGroup
-	wg.Add(N)
-	for i := 0; i < N; i++ {
-		go func() {
-			defer wg.Done()
-			// This dial never starts to send any SYN
-			// segment because of above socket filter and
-			// test hook.
-			c, err := DialTimeout("tcp", "127.0.0.1:0", T)
-			if err == nil {
-				t.Errorf("unexpectedly established: tcp:%s->%s", c.LocalAddr(), c.RemoteAddr())
-				c.Close()
-			}
-		}()
-	}
-	wg.Wait()
-	if attempts < N {
-		t.Errorf("got %d; want >= %d", attempts, N)
-	}
+var dialErrorTests = []DialErrorTest{
+	{
+		"datakit", "mh/astro/r70",
+		"dial datakit mh/astro/r70: unknown network datakit",
+	},
+	{
+		"tcp", "127.0.0.1:☺",
+		"dial tcp 127.0.0.1:☺: unknown port tcp/☺",
+	},
+	{
+		"tcp", "no-such-name.google.com.:80",
+		"dial tcp no-such-name.google.com.:80: lookup no-such-name.google.com.( on .*)?: no (.*)",
+	},
+	{
+		"tcp", "no-such-name.no-such-top-level-domain.:80",
+		"dial tcp no-such-name.no-such-top-level-domain.:80: lookup no-such-name.no-such-top-level-domain.( on .*)?: no (.*)",
+	},
+	{
+		"tcp", "no-such-name:80",
+		`dial tcp no-such-name:80: lookup no-such-name\.(.*\.)?( on .*)?: no (.*)`,
+	},
+	{
+		"tcp", "mh/astro/r70:http",
+		"dial tcp mh/astro/r70:http: lookup mh/astro/r70: invalid domain name",
+	},
+	{
+		"unix", "/etc/file-not-found",
+		"dial unix /etc/file-not-found: no such file or directory",
+	},
+	{
+		"unix", "/etc/",
+		"dial unix /etc/: (permission denied|socket operation on non-socket|connection refused)",
+	},
+	{
+		"unixpacket", "/etc/file-not-found",
+		"dial unixpacket /etc/file-not-found: no such file or directory",
+	},
+	{
+		"unixpacket", "/etc/",
+		"dial unixpacket /etc/: (permission denied|socket operation on non-socket|connection refused)",
+	},
 }
 
-func TestDialerDualStackFDLeak(t *testing.T) {
-	switch runtime.GOOS {
-	case "plan9":
-		t.Skipf("%s does not have full support of socktest", runtime.GOOS)
-	case "windows":
-		t.Skipf("not implemented a way to cancel dial racers in TCP SYN-SENT state on %s", runtime.GOOS)
-	}
-	if !supportsIPv4 || !supportsIPv6 {
-		t.Skip("both IPv4 and IPv6 are required")
-	}
+var duplicateErrorPattern = `dial (.*) dial (.*)`
 
-	origTestHookLookupIP := testHookLookupIP
-	defer func() { testHookLookupIP = origTestHookLookupIP }()
-	testHookLookupIP = lookupLocalhost
-	handler := func(dss *dualStackServer, ln Listener) {
-		for {
-			c, err := ln.Accept()
-			if err != nil {
-				return
-			}
-			c.Close()
-		}
+func TestDialError(t *testing.T) {
+	if !*runErrorTest {
+		t.Logf("test disabled; use -run_error_test to enable")
+		return
 	}
-	dss, err := newDualStackServer([]streamListener{
-		{network: "tcp4", address: "127.0.0.1"},
-		{network: "tcp6", address: "::1"},
-	})
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer dss.teardown()
-	if err := dss.buildup(handler); err != nil {
-		t.Fatal(err)
-	}
-
-	before := sw.Sockets()
-	const T = 100 * time.Millisecond
-	const N = 10
-	var wg sync.WaitGroup
-	wg.Add(N)
-	d := &Dialer{DualStack: true, Timeout: T}
-	for i := 0; i < N; i++ {
-		go func() {
-			defer wg.Done()
-			c, err := d.Dial("tcp", JoinHostPort("localhost", dss.port))
-			if err != nil {
-				t.Error(err)
-				return
-			}
+	for i, tt := range dialErrorTests {
+		c, err := Dial(tt.Net, tt.Raddr)
+		if c != nil {
 			c.Close()
-		}()
-	}
-	wg.Wait()
-	time.Sleep(2 * T) // wait for the dial racers to stop
-	after := sw.Sockets()
-	if len(after) != len(before) {
-		t.Errorf("got %d; want %d", len(after), len(before))
+		}
+		if err == nil {
+			t.Errorf("#%d: nil error, want match for %#q", i, tt.Pattern)
+			continue
+		}
+		s := err.Error()
+		match, _ := regexp.MatchString(tt.Pattern, s)
+		if !match {
+			t.Errorf("#%d: %q, want match for %#q", i, s, tt.Pattern)
+		}
+		match, _ = regexp.MatchString(duplicateErrorPattern, s)
+		if match {
+			t.Errorf("#%d: %q, duplicate error return from Dial", i, s)
+		}
 	}
 }
 
-// Define a pair of blackholed (IPv4, IPv6) addresses, for which dialTCP is
-// expected to hang until the timeout elapses. These addresses are reserved
-// for benchmarking by RFC 6890.
-const (
-	slowDst4    = "192.18.0.254"
-	slowDst6    = "2001:2::254"
-	slowTimeout = 1 * time.Second
-)
-
-// In some environments, the slow IPs may be explicitly unreachable, and fail
-// more quickly than expected. This test hook prevents dialTCP from returning
-// before the deadline.
-func slowDialTCP(net string, laddr, raddr *TCPAddr, deadline time.Time) (*TCPConn, error) {
-	c, err := dialTCP(net, laddr, raddr, deadline)
-	if ParseIP(slowDst4).Equal(raddr.IP) || ParseIP(slowDst6).Equal(raddr.IP) {
-		time.Sleep(deadline.Sub(time.Now()))
-	}
-	return c, err
+var invalidDialAndListenArgTests = []struct {
+	net  string
+	addr string
+	err  error
+}{
+	{"foo", "bar", &OpError{Op: "dial", Net: "foo", Addr: nil, Err: UnknownNetworkError("foo")}},
+	{"baz", "", &OpError{Op: "listen", Net: "baz", Addr: nil, Err: UnknownNetworkError("baz")}},
+	{"tcp", "", &OpError{Op: "dial", Net: "tcp", Addr: nil, Err: errMissingAddress}},
 }
 
-func dialClosedPort() (actual, expected time.Duration) {
-	// Estimate the expected time for this platform.
-	// On Windows, dialing a closed port takes roughly 1 second,
-	// but other platforms should be instantaneous.
-	if runtime.GOOS == "windows" {
-		expected = 1500 * time.Millisecond
-	} else {
-		expected = 95 * time.Millisecond
-	}
-
-	l, err := Listen("tcp", "127.0.0.1:0")
-	if err != nil {
-		return 999 * time.Hour, expected
-	}
-	addr := l.Addr().String()
-	l.Close()
-	// On OpenBSD, interference from TestSelfConnect is mysteriously
-	// causing the first attempt to hang for a few seconds, so we throw
-	// away the first result and keep the second.
-	for i := 1; ; i++ {
-		startTime := time.Now()
-		c, err := Dial("tcp", addr)
-		if err == nil {
-			c.Close()
+func TestInvalidDialAndListenArgs(t *testing.T) {
+	for _, tt := range invalidDialAndListenArgTests {
+		var err error
+		switch tt.err.(*OpError).Op {
+		case "dial":
+			_, err = Dial(tt.net, tt.addr)
+		case "listen":
+			_, err = Listen(tt.net, tt.addr)
 		}
-		elapsed := time.Now().Sub(startTime)
-		if i == 2 {
-			return elapsed, expected
+		if !reflect.DeepEqual(tt.err, err) {
+			t.Fatalf("got %#v; expected %#v", err, tt.err)
 		}
 	}
 }
 
-func TestDialParallel(t *testing.T) {
-	if testing.Short() || !*testExternal {
-		t.Skip("avoid external network")
-	}
-	if !supportsIPv4 || !supportsIPv6 {
-		t.Skip("both IPv4 and IPv6 are required")
-	}
-
-	closedPortDelay, expectClosedPortDelay := dialClosedPort()
-	if closedPortDelay > expectClosedPortDelay {
-		t.Errorf("got %v; want <= %v", closedPortDelay, expectClosedPortDelay)
+func TestDialTimeoutFDLeak(t *testing.T) {
+	if runtime.GOOS != "linux" {
+		// TODO(bradfitz): test on other platforms
+		t.Skipf("skipping test on %q", runtime.GOOS)
 	}
 
-	const instant time.Duration = 0
-	const fallbackDelay = 200 * time.Millisecond
+	ln := newLocalListener(t)
+	defer ln.Close()
 
-	// Some cases will run quickly when "connection refused" is fast,
-	// or trigger the fallbackDelay on Windows.  This value holds the
-	// lesser of the two delays.
-	var closedPortOrFallbackDelay time.Duration
-	if closedPortDelay < fallbackDelay {
-		closedPortOrFallbackDelay = closedPortDelay
-	} else {
-		closedPortOrFallbackDelay = fallbackDelay
+	type connErr struct {
+		conn Conn
+		err  error
 	}
-
-	origTestHookDialTCP := testHookDialTCP
-	defer func() { testHookDialTCP = origTestHookDialTCP }()
-	testHookDialTCP = slowDialTCP
-
-	nCopies := func(s string, n int) []string {
-		out := make([]string, n)
-		for i := 0; i < n; i++ {
-			out[i] = s
-		}
-		return out
-	}
-
-	var testCases = []struct {
-		primaries       []string
-		fallbacks       []string
-		teardownNetwork string
-		expectOk        bool
-		expectElapsed   time.Duration
-	}{
-		// These should just work on the first try.
-		{[]string{"127.0.0.1"}, []string{}, "", true, instant},
-		{[]string{"::1"}, []string{}, "", true, instant},
-		{[]string{"127.0.0.1", "::1"}, []string{slowDst6}, "tcp6", true, instant},
-		{[]string{"::1", "127.0.0.1"}, []string{slowDst4}, "tcp4", true, instant},
-		// Primary is slow; fallback should kick in.
-		{[]string{slowDst4}, []string{"::1"}, "", true, fallbackDelay},
-		// Skip a "connection refused" in the primary thread.
-		{[]string{"127.0.0.1", "::1"}, []string{}, "tcp4", true, closedPortDelay},
-		{[]string{"::1", "127.0.0.1"}, []string{}, "tcp6", true, closedPortDelay},
-		// Skip a "connection refused" in the fallback thread.
-		{[]string{slowDst4, slowDst6}, []string{"::1", "127.0.0.1"}, "tcp6", true, fallbackDelay + closedPortDelay},
-		// Primary refused, fallback without delay.
-		{[]string{"127.0.0.1"}, []string{"::1"}, "tcp4", true, closedPortOrFallbackDelay},
-		{[]string{"::1"}, []string{"127.0.0.1"}, "tcp6", true, closedPortOrFallbackDelay},
-		// Everything is refused.
-		{[]string{"127.0.0.1"}, []string{}, "tcp4", false, closedPortDelay},
-		// Nothing to do; fail instantly.
-		{[]string{}, []string{}, "", false, instant},
-		// Connecting to tons of addresses should not trip the deadline.
-		{nCopies("::1", 1000), []string{}, "", true, instant},
-	}
-
-	handler := func(dss *dualStackServer, ln Listener) {
-		for {
-			c, err := ln.Accept()
-			if err != nil {
-				return
-			}
-			c.Close()
-		}
+	dials := listenerBacklog + 100
+	// used to be listenerBacklog + 5, but was found to be unreliable, issue 4384.
+	maxGoodConnect := listenerBacklog + runtime.NumCPU()*10
+	resc := make(chan connErr)
+	for i := 0; i < dials; i++ {
+		go func() {
+			conn, err := DialTimeout("tcp", ln.Addr().String(), 500*time.Millisecond)
+			resc <- connErr{conn, err}
+		}()
 	}
 
-	// Convert a list of IP strings into TCPAddrs.
-	makeAddrs := func(ips []string, port string) addrList {
-		var out addrList
-		for _, ip := range ips {
-			addr, err := ResolveTCPAddr("tcp", JoinHostPort(ip, port))
-			if err != nil {
-				t.Fatal(err)
+	var firstErr string
+	var ngood int
+	var toClose []io.Closer
+	for i := 0; i < dials; i++ {
+		ce := <-resc
+		if ce.err == nil {
+			ngood++
+			if ngood > maxGoodConnect {
+				t.Errorf("%d good connects; expected at most %d", ngood, maxGoodConnect)
 			}
-			out = append(out, addr)
+			toClose = append(toClose, ce.conn)
+			continue
 		}
-		return out
-	}
-
-	for i, tt := range testCases {
-		dss, err := newDualStackServer([]streamListener{
-			{network: "tcp4", address: "127.0.0.1"},
-			{network: "tcp6", address: "::1"},
-		})
-		if err != nil {
-			t.Fatal(err)
+		err := ce.err
+		if firstErr == "" {
+			firstErr = err.Error()
+		} else if err.Error() != firstErr {
+			t.Fatalf("inconsistent error messages: first was %q, then later %q", firstErr, err)
 		}
-		defer dss.teardown()
-		if err := dss.buildup(handler); err != nil {
-			t.Fatal(err)
-		}
-		if tt.teardownNetwork != "" {
-			// Destroy one of the listening sockets, creating an unreachable port.
-			dss.teardownNetwork(tt.teardownNetwork)
-		}
-
-		primaries := makeAddrs(tt.primaries, dss.port)
-		fallbacks := makeAddrs(tt.fallbacks, dss.port)
-		d := Dialer{
-			FallbackDelay: fallbackDelay,
-			Timeout:       slowTimeout,
-		}
-		ctx := &dialContext{
-			Dialer:        d,
-			network:       "tcp",
-			address:       "?",
-			finalDeadline: d.deadline(time.Now()),
-		}
-		startTime := time.Now()
-		c, err := dialParallel(ctx, primaries, fallbacks)
-		elapsed := time.Now().Sub(startTime)
-
-		if c != nil {
-			c.Close()
-		}
-
-		if tt.expectOk && err != nil {
-			t.Errorf("#%d: got %v; want nil", i, err)
-		} else if !tt.expectOk && err == nil {
-			t.Errorf("#%d: got nil; want non-nil", i)
-		}
-
-		expectElapsedMin := tt.expectElapsed - 95*time.Millisecond
-		expectElapsedMax := tt.expectElapsed + 95*time.Millisecond
-		if !(elapsed >= expectElapsedMin) {
-			t.Errorf("#%d: got %v; want >= %v", i, elapsed, expectElapsedMin)
-		} else if !(elapsed <= expectElapsedMax) {
-			t.Errorf("#%d: got %v; want <= %v", i, elapsed, expectElapsedMax)
+	}
+	for _, c := range toClose {
+		c.Close()
+	}
+	for i := 0; i < 100; i++ {
+		if got := numFD(); got < dials {
+			// Test passes.
+			return
 		}
+		time.Sleep(10 * time.Millisecond)
 	}
-	// Wait for any slowDst4/slowDst6 connections to timeout.
-	time.Sleep(slowTimeout * 3 / 2)
-}
-
-func lookupSlowFast(fn func(string) ([]IPAddr, error), host string) ([]IPAddr, error) {
-	switch host {
-	case "slow6loopback4":
-		// Returns a slow IPv6 address, and a local IPv4 address.
-		return []IPAddr{
-			{IP: ParseIP(slowDst6)},
-			{IP: ParseIP("127.0.0.1")},
-		}, nil
-	default:
-		return fn(host)
+	if got := numFD(); got >= dials {
+		t.Errorf("num fds after %d timeouts = %d; want <%d", dials, got, dials)
 	}
 }
 
-func TestDialerFallbackDelay(t *testing.T) {
-	if testing.Short() || !*testExternal {
-		t.Skip("avoid external network")
+func numTCP() (ntcp, nopen, nclose int, err error) {
+	lsof, err := exec.Command("lsof", "-n", "-p", strconv.Itoa(os.Getpid())).Output()
+	if err != nil {
+		return 0, 0, 0, err
 	}
-	if !supportsIPv4 || !supportsIPv6 {
-		t.Skip("both IPv4 and IPv6 are required")
+	ntcp += bytes.Count(lsof, []byte("TCP"))
+	for _, state := range []string{"LISTEN", "SYN_SENT", "SYN_RECEIVED", "ESTABLISHED"} {
+		nopen += bytes.Count(lsof, []byte(state))
 	}
+	for _, state := range []string{"CLOSED", "CLOSE_WAIT", "LAST_ACK", "FIN_WAIT_1", "FIN_WAIT_2", "CLOSING", "TIME_WAIT"} {
+		nclose += bytes.Count(lsof, []byte(state))
+	}
+	return ntcp, nopen, nclose, nil
+}
 
-	origTestHookLookupIP := testHookLookupIP
-	defer func() { testHookLookupIP = origTestHookLookupIP }()
-	testHookLookupIP = lookupSlowFast
-
-	origTestHookDialTCP := testHookDialTCP
-	defer func() { testHookDialTCP = origTestHookDialTCP }()
-	testHookDialTCP = slowDialTCP
+func TestDialMultiFDLeak(t *testing.T) {
+	t.Skip("flaky test - golang.org/issue/8764")
 
-	var testCases = []struct {
-		dualstack     bool
-		delay         time.Duration
-		expectElapsed time.Duration
-	}{
-		// Use a very brief delay, which should fallback immediately.
-		{true, 1 * time.Nanosecond, 0},
-		// Use a 200ms explicit timeout.
-		{true, 200 * time.Millisecond, 200 * time.Millisecond},
-		// The default is 300ms.
-		{true, 0, 300 * time.Millisecond},
-		// This case is last, in order to wait for hanging slowDst6 connections.
-		{false, 0, slowTimeout},
+	if !supportsIPv4 || !supportsIPv6 {
+		t.Skip("neither ipv4 nor ipv6 is supported")
 	}
 
-	handler := func(dss *dualStackServer, ln Listener) {
+	halfDeadServer := func(dss *dualStackServer, ln Listener) {
 		for {
-			c, err := ln.Accept()
-			if err != nil {
+			if c, err := ln.Accept(); err != nil {
 				return
+			} else {
+				// It just keeps established
+				// connections like a half-dead server
+				// does.
+				dss.putConn(c)
 			}
-			c.Close()
 		}
 	}
 	dss, err := newDualStackServer([]streamListener{
-		{network: "tcp", address: "127.0.0.1"},
+		{net: "tcp4", addr: "127.0.0.1"},
+		{net: "tcp6", addr: "[::1]"},
 	})
 	if err != nil {
-		t.Fatal(err)
+		t.Fatalf("newDualStackServer failed: %v", err)
 	}
 	defer dss.teardown()
-	if err := dss.buildup(handler); err != nil {
-		t.Fatal(err)
+	if err := dss.buildup(halfDeadServer); err != nil {
+		t.Fatalf("dualStackServer.buildup failed: %v", err)
 	}
 
-	for i, tt := range testCases {
-		d := &Dialer{DualStack: tt.dualstack, FallbackDelay: tt.delay, Timeout: slowTimeout}
-
-		startTime := time.Now()
-		c, err := d.Dial("tcp", JoinHostPort("slow6loopback4", dss.port))
-		elapsed := time.Now().Sub(startTime)
-		if err == nil {
-			c.Close()
-		} else if tt.dualstack {
-			t.Error(err)
-		}
-		expectMin := tt.expectElapsed - 1*time.Millisecond
-		expectMax := tt.expectElapsed + 95*time.Millisecond
-		if !(elapsed >= expectMin) {
-			t.Errorf("#%d: got %v; want >= %v", i, elapsed, expectMin)
-		}
-		if !(elapsed <= expectMax) {
-			t.Errorf("#%d: got %v; want <= %v", i, elapsed, expectMax)
-		}
-	}
-}
-
-func TestDialSerialAsyncSpuriousConnection(t *testing.T) {
-	ln, err := newLocalListener("tcp")
+	_, before, _, err := numTCP()
 	if err != nil {
-		t.Fatal(err)
+		t.Skipf("skipping test; error finding or running lsof: %v", err)
 	}
-	defer ln.Close()
 
-	d := Dialer{}
-	ctx := &dialContext{
-		Dialer:        d,
-		network:       "tcp",
-		address:       "?",
-		finalDeadline: d.deadline(time.Now()),
+	var wg sync.WaitGroup
+	portnum, _, _ := dtoi(dss.port, 0)
+	ras := addrList{
+		// Losers that will fail to connect, see RFC 6890.
+		&TCPAddr{IP: IPv4(198, 18, 0, 254), Port: portnum},
+		&TCPAddr{IP: ParseIP("2001:2::254"), Port: portnum},
+
+		// Winner candidates of this race.
+		&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: portnum},
+		&TCPAddr{IP: IPv6loopback, Port: portnum},
+
+		// Losers that will have established connections.
+		&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: portnum},
+		&TCPAddr{IP: IPv6loopback, Port: portnum},
+	}
+	const T1 = 10 * time.Millisecond
+	const T2 = 2 * T1
+	const N = 10
+	for i := 0; i < N; i++ {
+		wg.Add(1)
+		go func() {
+			defer wg.Done()
+			if c, err := dialMulti("tcp", "fast failover test", nil, ras, time.Now().Add(T1)); err == nil {
+				c.Close()
+			}
+		}()
 	}
+	wg.Wait()
+	time.Sleep(T2)
 
-	results := make(chan dialResult)
-	cancel := make(chan struct{})
-
-	// Spawn a connection in the background.
-	go dialSerialAsync(ctx, addrList{ln.Addr()}, nil, cancel, results)
-
-	// Receive it at the server.
-	c, err := ln.Accept()
+	ntcp, after, nclose, err := numTCP()
 	if err != nil {
-		t.Fatal(err)
+		t.Skipf("skipping test; error finding or running lsof: %v", err)
 	}
-	defer c.Close()
+	t.Logf("tcp sessions: %v, open sessions: %v, closing sessions: %v", ntcp, after, nclose)
 
-	// Tell dialSerialAsync that someone else won the race.
-	close(cancel)
-
-	// The connection should close itself, without sending data.
-	c.SetReadDeadline(time.Now().Add(1 * time.Second))
-	var b [1]byte
-	if _, err := c.Read(b[:]); err != io.EOF {
-		t.Errorf("got %v; want %v", err, io.EOF)
+	if after != before {
+		t.Fatalf("got %v open sessions; expected %v", after, before)
 	}
 }
 
-func TestDialerPartialDeadline(t *testing.T) {
-	now := time.Date(2000, time.January, 1, 0, 0, 0, 0, time.UTC)
-	var testCases = []struct {
-		now            time.Time
-		deadline       time.Time
-		addrs          int
-		expectDeadline time.Time
-		expectErr      error
-	}{
-		// Regular division.
-		{now, now.Add(12 * time.Second), 1, now.Add(12 * time.Second), nil},
-		{now, now.Add(12 * time.Second), 2, now.Add(6 * time.Second), nil},
-		{now, now.Add(12 * time.Second), 3, now.Add(4 * time.Second), nil},
-		// Bump against the 2-second sane minimum.
-		{now, now.Add(12 * time.Second), 999, now.Add(2 * time.Second), nil},
-		// Total available is now below the sane minimum.
-		{now, now.Add(1900 * time.Millisecond), 999, now.Add(1900 * time.Millisecond), nil},
-		// Null deadline.
-		{now, noDeadline, 1, noDeadline, nil},
-		// Step the clock forward and cross the deadline.
-		{now.Add(-1 * time.Millisecond), now, 1, now, nil},
-		{now.Add(0 * time.Millisecond), now, 1, noDeadline, errTimeout},
-		{now.Add(1 * time.Millisecond), now, 1, noDeadline, errTimeout},
-	}
-	for i, tt := range testCases {
-		deadline, err := partialDeadline(tt.now, tt.deadline, tt.addrs)
-		if err != tt.expectErr {
-			t.Errorf("#%d: got %v; want %v", i, err, tt.expectErr)
+func numFD() int {
+	if runtime.GOOS == "linux" {
+		f, err := os.Open("/proc/self/fd")
+		if err != nil {
+			panic(err)
 		}
-		if deadline != tt.expectDeadline {
-			t.Errorf("#%d: got %v; want %v", i, deadline, tt.expectDeadline)
+		defer f.Close()
+		names, err := f.Readdirnames(0)
+		if err != nil {
+			panic(err)
 		}
+		return len(names)
 	}
+	// All tests using this should be skipped anyway, but:
+	panic("numFDs not implemented on " + runtime.GOOS)
 }
 
-func TestDialerLocalAddr(t *testing.T) {
+func TestDialer(t *testing.T) {
+	ln, err := Listen("tcp4", "127.0.0.1:0")
+	if err != nil {
+		t.Fatalf("Listen failed: %v", err)
+	}
+	defer ln.Close()
 	ch := make(chan error, 1)
-	handler := func(ls *localServer, ln Listener) {
+	go func() {
 		c, err := ln.Accept()
 		if err != nil {
-			ch <- err
+			ch <- fmt.Errorf("Accept failed: %v", err)
 			return
 		}
 		defer c.Close()
 		ch <- nil
-	}
-	ls, err := newLocalServer("tcp")
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer ls.teardown()
-	if err := ls.buildup(handler); err != nil {
-		t.Fatal(err)
-	}
+	}()
 
-	laddr, err := ResolveTCPAddr(ls.Listener.Addr().Network(), ls.Listener.Addr().String())
+	laddr, err := ResolveTCPAddr("tcp4", "127.0.0.1:0")
 	if err != nil {
-		t.Fatal(err)
+		t.Fatalf("ResolveTCPAddr failed: %v", err)
 	}
-	laddr.Port = 0
 	d := &Dialer{LocalAddr: laddr}
-	c, err := d.Dial(ls.Listener.Addr().Network(), ls.Addr().String())
+	c, err := d.Dial("tcp4", ln.Addr().String())
 	if err != nil {
-		t.Fatal(err)
+		t.Fatalf("Dial failed: %v", err)
 	}
 	defer c.Close()
 	c.Read(make([]byte, 1))
@@ -620,64 +466,61 @@ func TestDialerLocalAddr(t *testing.T) {
 	}
 }
 
-func TestDialerDualStack(t *testing.T) {
-	if !supportsIPv4 || !supportsIPv6 {
-		t.Skip("both IPv4 and IPv6 are required")
+func TestDialDualStackLocalhost(t *testing.T) {
+	switch runtime.GOOS {
+	case "nacl":
+		t.Skipf("skipping test on %q", runtime.GOOS)
 	}
 
-	closedPortDelay, expectClosedPortDelay := dialClosedPort()
-	if closedPortDelay > expectClosedPortDelay {
-		t.Errorf("got %v; want <= %v", closedPortDelay, expectClosedPortDelay)
+	if ips, err := LookupIP("localhost"); err != nil {
+		t.Fatalf("LookupIP failed: %v", err)
+	} else if len(ips) < 2 || !supportsIPv4 || !supportsIPv6 {
+		t.Skip("localhost doesn't have a pair of different address family IP addresses")
 	}
 
-	origTestHookLookupIP := testHookLookupIP
-	defer func() { testHookLookupIP = origTestHookLookupIP }()
-	testHookLookupIP = lookupLocalhost
-	handler := func(dss *dualStackServer, ln Listener) {
+	touchAndByeServer := func(dss *dualStackServer, ln Listener) {
 		for {
-			c, err := ln.Accept()
-			if err != nil {
+			if c, err := ln.Accept(); err != nil {
 				return
+			} else {
+				c.Close()
 			}
-			c.Close()
 		}
 	}
+	dss, err := newDualStackServer([]streamListener{
+		{net: "tcp4", addr: "127.0.0.1"},
+		{net: "tcp6", addr: "[::1]"},
+	})
+	if err != nil {
+		t.Fatalf("newDualStackServer failed: %v", err)
+	}
+	defer dss.teardown()
+	if err := dss.buildup(touchAndByeServer); err != nil {
+		t.Fatalf("dualStackServer.buildup failed: %v", err)
+	}
 
-	var timeout = 100*time.Millisecond + closedPortDelay
-	for _, dualstack := range []bool{false, true} {
-		dss, err := newDualStackServer([]streamListener{
-			{network: "tcp4", address: "127.0.0.1"},
-			{network: "tcp6", address: "::1"},
-		})
-		if err != nil {
-			t.Fatal(err)
-		}
-		defer dss.teardown()
-		if err := dss.buildup(handler); err != nil {
-			t.Fatal(err)
-		}
-
-		d := &Dialer{DualStack: dualstack, Timeout: timeout}
-		for range dss.lns {
-			c, err := d.Dial("tcp", JoinHostPort("localhost", dss.port))
-			if err != nil {
-				t.Error(err)
-				continue
-			}
-			switch addr := c.LocalAddr().(*TCPAddr); {
-			case addr.IP.To4() != nil:
+	d := &Dialer{DualStack: true}
+	for range dss.lns {
+		if c, err := d.Dial("tcp", "localhost:"+dss.port); err != nil {
+			t.Errorf("Dial failed: %v", err)
+		} else {
+			if addr := c.LocalAddr().(*TCPAddr); addr.IP.To4() != nil {
 				dss.teardownNetwork("tcp4")
-			case addr.IP.To16() != nil && addr.IP.To4() == nil:
+			} else if addr.IP.To16() != nil && addr.IP.To4() == nil {
 				dss.teardownNetwork("tcp6")
 			}
 			c.Close()
 		}
 	}
-	time.Sleep(timeout * 3 / 2) // wait for the dial racers to stop
 }
 
 func TestDialerKeepAlive(t *testing.T) {
-	handler := func(ls *localServer, ln Listener) {
+	ln := newLocalListener(t)
+	defer ln.Close()
+	defer func() {
+		testHookSetKeepAlive = func() {}
+	}()
+	go func() {
 		for {
 			c, err := ln.Accept()
 			if err != nil {
@@ -685,17 +528,7 @@ func TestDialerKeepAlive(t *testing.T) {
 			}
 			c.Close()
 		}
-	}
-	ls, err := newLocalServer("tcp")
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer ls.teardown()
-	if err := ls.buildup(handler); err != nil {
-		t.Fatal(err)
-	}
-	defer func() { testHookSetKeepAlive = func() {} }()
-
+	}()
 	for _, keepAlive := range []bool{false, true} {
 		got := false
 		testHookSetKeepAlive = func() { got = true }
@@ -703,7 +536,7 @@ func TestDialerKeepAlive(t *testing.T) {
 		if keepAlive {
 			d.KeepAlive = 30 * time.Second
 		}
-		c, err := d.Dial("tcp", ls.Listener.Addr().String())
+		c, err := d.Dial("tcp", ln.Addr().String())
 		if err != nil {
 			t.Fatal(err)
 		}
diff --git a/src/net/dialgoogle_test.go b/src/net/dialgoogle_test.go
new file mode 100644
index 0000000..df5895a
--- /dev/null
+++ b/src/net/dialgoogle_test.go
@@ -0,0 +1,209 @@
+// 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"
+	"io"
+	"strings"
+	"syscall"
+	"testing"
+)
+
+// If an IPv6 tunnel is running, we can try dialing a real IPv6 address.
+var testIPv6 = flag.Bool("ipv6", false, "assume ipv6 tunnel is present")
+
+func TestResolveGoogle(t *testing.T) {
+	if testing.Short() || !*testExternal {
+		t.Skip("skipping test to avoid external network")
+	}
+
+	for _, network := range []string{"tcp", "tcp4", "tcp6"} {
+		addr, err := ResolveTCPAddr(network, "www.google.com:http")
+		if err != nil {
+			if (network == "tcp" || network == "tcp4") && !supportsIPv4 {
+				t.Logf("ipv4 is not supported: %v", err)
+			} else if network == "tcp6" && !supportsIPv6 {
+				t.Logf("ipv6 is not supported: %v", err)
+			} else {
+				t.Errorf("ResolveTCPAddr failed: %v", err)
+			}
+			continue
+		}
+		if (network == "tcp" || network == "tcp4") && addr.IP.To4() == nil {
+			t.Errorf("got %v; expected an IPv4 address on %v", addr, network)
+		} else if network == "tcp6" && (addr.IP.To16() == nil || addr.IP.To4() != nil) {
+			t.Errorf("got %v; expected an IPv6 address on %v", addr, network)
+		}
+	}
+}
+
+func TestDialGoogle(t *testing.T) {
+	if testing.Short() || !*testExternal {
+		t.Skip("skipping test to avoid external network")
+	}
+
+	d := &Dialer{DualStack: true}
+	for _, network := range []string{"tcp", "tcp4", "tcp6"} {
+		if network == "tcp" && !supportsIPv4 && !supportsIPv6 {
+			t.Logf("skipping test; both ipv4 and ipv6 are not supported")
+			continue
+		} else if network == "tcp4" && !supportsIPv4 {
+			t.Logf("skipping test; ipv4 is not supported")
+			continue
+		} else if network == "tcp6" && !supportsIPv6 {
+			t.Logf("skipping test; ipv6 is not supported")
+			continue
+		} else if network == "tcp6" && !*testIPv6 {
+			t.Logf("test disabled; use -ipv6 to enable")
+			continue
+		}
+		if c, err := d.Dial(network, "www.google.com:http"); err != nil {
+			t.Errorf("Dial failed: %v", err)
+		} else {
+			c.Close()
+		}
+	}
+}
+
+// fd is already connected to the destination, port 80.
+// Run an HTTP request to fetch the appropriate page.
+func fetchGoogle(t *testing.T, fd Conn, network, addr string) {
+	req := []byte("GET /robots.txt HTTP/1.0\r\nHost: www.google.com\r\n\r\n")
+	n, err := fd.Write(req)
+
+	buf := make([]byte, 1000)
+	n, err = io.ReadFull(fd, buf)
+
+	if n < 1000 {
+		t.Errorf("fetchGoogle: short HTTP read from %s %s - %v", network, addr, err)
+		return
+	}
+}
+
+func doDial(t *testing.T, network, addr string) {
+	fd, err := Dial(network, addr)
+	if err != nil {
+		t.Errorf("Dial(%q, %q, %q) = _, %v", network, "", addr, err)
+		return
+	}
+	fetchGoogle(t, fd, network, addr)
+	fd.Close()
+}
+
+var googleaddrsipv4 = []string{
+	"%d.%d.%d.%d:80",
+	"www.google.com:80",
+	"%d.%d.%d.%d:http",
+	"www.google.com:http",
+	"%03d.%03d.%03d.%03d:0080",
+	"[::ffff:%d.%d.%d.%d]:80",
+	"[::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::ffff:%d.%d.%d.%d]:80",
+}
+
+func TestDialGoogleIPv4(t *testing.T) {
+	if testing.Short() || !*testExternal {
+		t.Skip("skipping test to avoid external network")
+	}
+
+	// Insert an actual IPv4 address for google.com
+	// into the table.
+	addrs, err := LookupIP("www.google.com")
+	if err != nil {
+		t.Fatalf("lookup www.google.com: %v", err)
+	}
+	var ip IP
+	for _, addr := range addrs {
+		if x := addr.To4(); x != nil {
+			ip = x
+			break
+		}
+	}
+	if ip == nil {
+		t.Fatalf("no IPv4 addresses for www.google.com")
+	}
+
+	for i, s := range googleaddrsipv4 {
+		if strings.Contains(s, "%") {
+			googleaddrsipv4[i] = fmt.Sprintf(s, ip[0], ip[1], ip[2], ip[3])
+		}
+	}
+
+	for i := 0; i < len(googleaddrsipv4); i++ {
+		addr := googleaddrsipv4[i]
+		if addr == "" {
+			continue
+		}
+		t.Logf("-- %s --", addr)
+		doDial(t, "tcp", addr)
+		if addr[0] != '[' {
+			doDial(t, "tcp4", addr)
+			if supportsIPv6 {
+				// make sure syscall.SocketDisableIPv6 flag works.
+				syscall.SocketDisableIPv6 = true
+				doDial(t, "tcp", addr)
+				doDial(t, "tcp4", addr)
+				syscall.SocketDisableIPv6 = false
+			}
+		}
+	}
+}
+
+var googleaddrsipv6 = []string{
+	"[%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:80",
+	"ipv6.google.com:80",
+	"[%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:http",
+	"ipv6.google.com:http",
+}
+
+func TestDialGoogleIPv6(t *testing.T) {
+	if testing.Short() || !*testExternal {
+		t.Skip("skipping test to avoid external network")
+	}
+	// Only run tcp6 if the kernel will take it.
+	if !supportsIPv6 {
+		t.Skip("skipping test; ipv6 is not supported")
+	}
+	if !*testIPv6 {
+		t.Skip("test disabled; use -ipv6 to enable")
+	}
+
+	// Insert an actual IPv6 address for ipv6.google.com
+	// into the table.
+	addrs, err := LookupIP("ipv6.google.com")
+	if err != nil {
+		t.Fatalf("lookup ipv6.google.com: %v", err)
+	}
+	var ip IP
+	for _, addr := range addrs {
+		if x := addr.To16(); x != nil {
+			ip = x
+			break
+		}
+	}
+	if ip == nil {
+		t.Fatalf("no IPv6 addresses for ipv6.google.com")
+	}
+
+	for i, s := range googleaddrsipv6 {
+		if strings.Contains(s, "%") {
+			googleaddrsipv6[i] = fmt.Sprintf(s, ip[0], ip[1], ip[2], ip[3], ip[4], ip[5], ip[6], ip[7], ip[8], ip[9], ip[10], ip[11], ip[12], ip[13], ip[14], ip[15])
+		}
+	}
+
+	for i := 0; i < len(googleaddrsipv6); i++ {
+		addr := googleaddrsipv6[i]
+		if addr == "" {
+			continue
+		}
+		t.Logf("-- %s --", addr)
+		doDial(t, "tcp", addr)
+		doDial(t, "tcp6", addr)
+	}
+}
diff --git a/src/net/dnsclient.go b/src/net/dnsclient.go
index ce48521..e8014e4 100644
--- a/src/net/dnsclient.go
+++ b/src/net/dnsclient.go
@@ -9,6 +9,31 @@ import (
 	"sort"
 )
 
+// DNSError represents a DNS lookup error.
+type DNSError struct {
+	Err       string // description of the error
+	Name      string // name looked for
+	Server    string // server used
+	IsTimeout bool
+}
+
+func (e *DNSError) Error() string {
+	if e == nil {
+		return "<nil>"
+	}
+	s := "lookup " + e.Name
+	if e.Server != "" {
+		s += " on " + e.Server
+	}
+	s += ": " + e.Err
+	return s
+}
+
+func (e *DNSError) Timeout() bool   { return e.IsTimeout }
+func (e *DNSError) Temporary() bool { return e.IsTimeout }
+
+const noSuchHost = "no such host"
+
 // reverseaddr returns the in-addr.arpa. or ip6.arpa. hostname of the IP
 // address addr suitable for rDNS (PTR) record lookup or an error if it fails
 // to parse the IP address.
@@ -18,7 +43,8 @@ func reverseaddr(addr string) (arpa string, err error) {
 		return "", &DNSError{Err: "unrecognized address", Name: addr}
 	}
 	if ip.To4() != nil {
-		return uitoa(uint(ip[15])) + "." + uitoa(uint(ip[14])) + "." + uitoa(uint(ip[13])) + "." + uitoa(uint(ip[12])) + ".in-addr.arpa.", nil
+		return itoa(int(ip[15])) + "." + itoa(int(ip[14])) + "." + itoa(int(ip[13])) + "." +
+			itoa(int(ip[12])) + ".in-addr.arpa.", nil
 	}
 	// Must be IPv6
 	buf := make([]byte, 0, len(ip)*4+len("ip6.arpa."))
@@ -41,7 +67,7 @@ func answer(name, server string, dns *dnsMsg, qtype uint16) (cname string, addrs
 	addrs = make([]dnsRR, 0, len(dns.answer))
 
 	if dns.rcode == dnsRcodeNameError && dns.recursion_available {
-		return "", nil, &DNSError{Err: errNoSuchHost.Error(), Name: name, Server: server}
+		return "", nil, &DNSError{Err: noSuchHost, Name: name}
 	}
 	if dns.rcode != dnsRcodeSuccess {
 		// None of the error codes make sense
@@ -68,7 +94,7 @@ Cname:
 				continue
 			}
 			h := rr.Header()
-			if h.Class == dnsClassINET && equalASCIILabel(h.Name, name) {
+			if h.Class == dnsClassINET && h.Name == name {
 				switch h.Rrtype {
 				case qtype:
 					addrs = append(addrs, rr)
@@ -80,7 +106,7 @@ Cname:
 			}
 		}
 		if len(addrs) == 0 {
-			return "", nil, &DNSError{Err: errNoSuchHost.Error(), Name: name, Server: server}
+			return "", nil, &DNSError{Err: noSuchHost, Name: name, Server: server}
 		}
 		return name, addrs, nil
 	}
@@ -88,26 +114,6 @@ Cname:
 	return "", nil, &DNSError{Err: "too many redirects", Name: name, Server: server}
 }
 
-func equalASCIILabel(x, y string) bool {
-	if len(x) != len(y) {
-		return false
-	}
-	for i := 0; i < len(x); i++ {
-		a := x[i]
-		b := y[i]
-		if 'A' <= a && a <= 'Z' {
-			a += 0x20
-		}
-		if 'A' <= b && b <= 'Z' {
-			b += 0x20
-		}
-		if a != b {
-			return false
-		}
-	}
-	return true
-}
-
 func isDomainName(s string) bool {
 	// See RFC 1035, RFC 3696.
 	if len(s) == 0 {
@@ -168,10 +174,13 @@ type SRV struct {
 type byPriorityWeight []*SRV
 
 func (s byPriorityWeight) Len() int { return len(s) }
+
+func (s byPriorityWeight) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
+
 func (s byPriorityWeight) Less(i, j int) bool {
-	return s[i].Priority < s[j].Priority || (s[i].Priority == s[j].Priority && s[i].Weight < s[j].Weight)
+	return s[i].Priority < s[j].Priority ||
+		(s[i].Priority == s[j].Priority && s[i].Weight < s[j].Weight)
 }
-func (s byPriorityWeight) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
 
 // shuffleByWeight shuffles SRV records by weight using the algorithm
 // described in RFC 2782.
@@ -219,9 +228,11 @@ type MX struct {
 // byPref implements sort.Interface to sort MX records by preference
 type byPref []*MX
 
-func (s byPref) Len() int           { return len(s) }
+func (s byPref) Len() int { return len(s) }
+
 func (s byPref) Less(i, j int) bool { return s[i].Pref < s[j].Pref }
-func (s byPref) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
+
+func (s byPref) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
 
 // sort reorders MX records as specified in RFC 5321.
 func (s byPref) sort() {
diff --git a/src/net/dnsclient_test.go b/src/net/dnsclient_test.go
index 3ab2b83..435eb35 100644
--- a/src/net/dnsclient_test.go
+++ b/src/net/dnsclient_test.go
@@ -47,7 +47,7 @@ func testUniformity(t *testing.T, size int, margin float64) {
 	checkDistribution(t, data, margin)
 }
 
-func TestDNSSRVUniformity(t *testing.T) {
+func TestUniformity(t *testing.T) {
 	testUniformity(t, 2, 0.05)
 	testUniformity(t, 3, 0.10)
 	testUniformity(t, 10, 0.20)
diff --git a/src/net/dnsclient_unix.go b/src/net/dnsclient_unix.go
index c03c1b1..7511083 100644
--- a/src/net/dnsclient_unix.go
+++ b/src/net/dnsclient_unix.go
@@ -20,7 +20,6 @@ import (
 	"io"
 	"math/rand"
 	"os"
-	"strconv"
 	"sync"
 	"time"
 )
@@ -185,9 +184,9 @@ func tryOneName(cfg *dnsConfig, name string, qtype uint16) (string, []dnsRR, err
 				}
 				continue
 			}
-			cname, rrs, err := answer(name, server, msg, qtype)
-			if err == nil || msg.rcode == dnsRcodeSuccess || msg.rcode == dnsRcodeNameError && msg.recursion_available {
-				return cname, rrs, err
+			cname, addrs, err := answer(name, server, msg, qtype)
+			if err == nil || err.(*DNSError).Err == noSuchHost {
+				return cname, addrs, err
 			}
 			lastErr = err
 		}
@@ -195,188 +194,144 @@ func tryOneName(cfg *dnsConfig, name string, qtype uint16) (string, []dnsRR, err
 	return "", nil, lastErr
 }
 
-// addrRecordList converts and returns a list of IP addresses from DNS
-// address records (both A and AAAA). Other record types are ignored.
-func addrRecordList(rrs []dnsRR) []IPAddr {
-	addrs := make([]IPAddr, 0, 4)
-	for _, rr := range rrs {
-		switch rr := rr.(type) {
-		case *dnsRR_A:
-			addrs = append(addrs, IPAddr{IP: IPv4(byte(rr.A>>24), byte(rr.A>>16), byte(rr.A>>8), byte(rr.A))})
-		case *dnsRR_AAAA:
-			ip := make(IP, IPv6len)
-			copy(ip, rr.AAAA[:])
-			addrs = append(addrs, IPAddr{IP: ip})
-		}
+func convertRR_A(records []dnsRR) []IP {
+	addrs := make([]IP, len(records))
+	for i, rr := range records {
+		a := rr.(*dnsRR_A).A
+		addrs[i] = IPv4(byte(a>>24), byte(a>>16), byte(a>>8), byte(a))
 	}
 	return addrs
 }
 
-// A resolverConfig represents a DNS stub resolver configuration.
-type resolverConfig struct {
-	initOnce sync.Once // guards init of resolverConfig
-
-	// ch is used as a semaphore that only allows one lookup at a
-	// time to recheck resolv.conf.
-	ch          chan struct{} // guards lastChecked and modTime
-	lastChecked time.Time     // last time resolv.conf was checked
-	modTime     time.Time     // time of resolv.conf modification
-
-	mu        sync.RWMutex // protects dnsConfig
-	dnsConfig *dnsConfig   // parsed resolv.conf structure used in lookups
+func convertRR_AAAA(records []dnsRR) []IP {
+	addrs := make([]IP, len(records))
+	for i, rr := range records {
+		a := make(IP, IPv6len)
+		copy(a, rr.(*dnsRR_AAAA).AAAA[:])
+		addrs[i] = a
+	}
+	return addrs
 }
 
-var resolvConf resolverConfig
+var cfg struct {
+	ch        chan struct{}
+	mu        sync.RWMutex // protects dnsConfig and dnserr
+	dnsConfig *dnsConfig
+	dnserr    error
+}
+var onceLoadConfig sync.Once
 
-// init initializes conf and is only called via conf.initOnce.
-func (conf *resolverConfig) init() {
-	// Set dnsConfig, modTime, and lastChecked so we don't parse
-	// resolv.conf twice the first time.
-	conf.dnsConfig = systemConf().resolv
-	if conf.dnsConfig == nil {
-		conf.dnsConfig = dnsReadConfig("/etc/resolv.conf")
-	}
+// Assume dns config file is /etc/resolv.conf here
+func loadDefaultConfig() {
+	loadConfig("/etc/resolv.conf", 5*time.Second, nil)
+}
 
-	if fi, err := os.Stat("/etc/resolv.conf"); err == nil {
-		conf.modTime = fi.ModTime()
-	}
-	conf.lastChecked = time.Now()
+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:
+			}
 
-	// Prepare ch so that only one update of resolverConfig may
-	// run at once.
-	conf.ch = make(chan struct{}, 1)
+			// 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()
+		}
+	}()
 }
 
-// tryUpdate tries to update conf with the named resolv.conf file.
-// The name variable only exists for testing. It is otherwise always
-// "/etc/resolv.conf".
-func (conf *resolverConfig) tryUpdate(name string) {
-	conf.initOnce.Do(conf.init)
+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(loadDefaultConfig)
 
-	// Ensure only one update at a time checks resolv.conf.
-	if !conf.tryAcquireSema() {
-		return
+	select {
+	case cfg.ch <- struct{}{}:
+	default:
 	}
-	defer conf.releaseSema()
 
-	now := time.Now()
-	if conf.lastChecked.After(now.Add(-5 * time.Second)) {
+	cfg.mu.RLock()
+	defer cfg.mu.RUnlock()
+
+	if cfg.dnserr != nil || cfg.dnsConfig == nil {
+		err = cfg.dnserr
 		return
 	}
-	conf.lastChecked = now
-
-	if fi, err := os.Stat(name); err == nil {
-		if fi.ModTime().Equal(conf.modTime) {
-			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.dnsConfig.ndots {
+		rname := name
+		if !rooted {
+			rname += "."
 		}
-		conf.modTime = fi.ModTime()
-	} else {
-		// If modTime wasn't set prior, assume nothing has changed.
-		if conf.modTime.IsZero() {
+		// Can try as ordinary name.
+		cname, addrs, err = tryOneName(cfg.dnsConfig, rname, qtype)
+		if rooted || err == nil {
 			return
 		}
-		conf.modTime = time.Time{}
 	}
 
-	dnsConf := dnsReadConfig(name)
-	conf.mu.Lock()
-	conf.dnsConfig = dnsConf
-	conf.mu.Unlock()
-}
-
-func (conf *resolverConfig) tryAcquireSema() bool {
-	select {
-	case conf.ch <- struct{}{}:
-		return true
-	default:
-		return false
+	// Otherwise, try suffixes.
+	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.dnsConfig, rname, qtype)
+		if err == nil {
+			return
+		}
 	}
-}
 
-func (conf *resolverConfig) releaseSema() {
-	<-conf.ch
-}
-
-func lookup(name string, qtype uint16) (cname string, rrs []dnsRR, err error) {
-	if !isDomainName(name) {
-		return "", nil, &DNSError{Err: "invalid domain name", Name: name}
-	}
-	resolvConf.tryUpdate("/etc/resolv.conf")
-	resolvConf.mu.RLock()
-	conf := resolvConf.dnsConfig
-	resolvConf.mu.RUnlock()
-	for _, fqdn := range conf.nameList(name) {
-		cname, rrs, err = tryOneName(conf, fqdn, qtype)
+	// Last ditch effort: try unsuffixed only if we haven't already,
+	// that is, name is not rooted and has less than ndots dots.
+	if count(name, '.') < cfg.dnsConfig.ndots {
+		cname, addrs, err = tryOneName(cfg.dnsConfig, name+".", qtype)
 		if err == nil {
-			break
+			return
 		}
 	}
-	if err, ok := err.(*DNSError); ok {
+
+	if e, ok := err.(*DNSError); ok {
 		// Show original name passed to lookup, not suffixed one.
 		// In general we might have tried many suffixes; showing
 		// just one is misleading. See also golang.org/issue/6324.
-		err.Name = name
+		e.Name = name
 	}
 	return
 }
 
-// nameList returns a list of names for sequential DNS queries.
-func (conf *dnsConfig) nameList(name string) []string {
-	// If name is rooted (trailing dot), try only that name.
-	rooted := len(name) > 0 && name[len(name)-1] == '.'
-	if rooted {
-		return []string{name}
-	}
-	// Build list of search choices.
-	names := make([]string, 0, 1+len(conf.search))
-	// If name has enough dots, try unsuffixed first.
-	if count(name, '.') >= conf.ndots {
-		names = append(names, name+".")
-	}
-	// Try suffixes.
-	for _, suffix := range conf.search {
-		suffixed := name + "." + suffix
-		if suffixed[len(suffixed)-1] != '.' {
-			suffixed += "."
-		}
-		names = append(names, suffixed)
-	}
-	// Try unsuffixed, if not tried first above.
-	if count(name, '.') < conf.ndots {
-		names = append(names, name+".")
-	}
-	return names
-}
-
-// hostLookupOrder specifies the order of LookupHost lookup strategies.
-// It is basically a simplified representation of nsswitch.conf.
-// "files" means /etc/hosts.
-type hostLookupOrder int
-
-const (
-	// hostLookupCgo means defer to cgo.
-	hostLookupCgo      hostLookupOrder = iota
-	hostLookupFilesDNS                 // files first
-	hostLookupDNSFiles                 // dns first
-	hostLookupFiles                    // only files
-	hostLookupDNS                      // only DNS
-)
-
-var lookupOrderName = map[hostLookupOrder]string{
-	hostLookupCgo:      "cgo",
-	hostLookupFilesDNS: "files,dns",
-	hostLookupDNSFiles: "dns,files",
-	hostLookupFiles:    "files",
-	hostLookupDNS:      "dns",
-}
-
-func (o hostLookupOrder) String() string {
-	if s, ok := lookupOrderName[o]; ok {
-		return s
-	}
-	return "hostLookupOrder=" + strconv.Itoa(int(o)) + "??"
-}
-
 // goLookupHost is the native Go implementation of LookupHost.
 // Used only if cgoLookupHost refuses to handle the request
 // (that is, only if cgoLookupHost is the stub in cgo_stub.go).
@@ -384,18 +339,12 @@ func (o hostLookupOrder) String() string {
 // depending on our lookup code, so that Go and C get the same
 // answers.
 func goLookupHost(name string) (addrs []string, err error) {
-	return goLookupHostOrder(name, hostLookupFilesDNS)
-}
-
-func goLookupHostOrder(name string, order hostLookupOrder) (addrs []string, err error) {
-	if order == hostLookupFilesDNS || order == hostLookupFiles {
-		// Use entries from /etc/hosts if they match.
-		addrs = lookupStaticHost(name)
-		if len(addrs) > 0 || order == hostLookupFiles {
-			return
-		}
+	// Use entries from /etc/hosts if they match.
+	addrs = lookupStaticHost(name)
+	if len(addrs) > 0 {
+		return
 	}
-	ips, err := goLookupIPOrder(name, order)
+	ips, err := goLookupIP(name)
 	if err != nil {
 		return
 	}
@@ -406,79 +355,54 @@ func goLookupHostOrder(name string, order hostLookupOrder) (addrs []string, err
 	return
 }
 
-// lookup entries from /etc/hosts
-func goLookupIPFiles(name string) (addrs []IPAddr) {
-	for _, haddr := range lookupStaticHost(name) {
-		haddr, zone := splitHostZone(haddr)
-		if ip := ParseIP(haddr); ip != nil {
-			addr := IPAddr{IP: ip, Zone: zone}
-			addrs = append(addrs, addr)
-		}
-	}
-	sortByRFC6724(addrs)
-	return
-}
-
 // goLookupIP is the native Go implementation of LookupIP.
-// The libc versions are in cgo_*.go.
-func goLookupIP(name string) (addrs []IPAddr, err error) {
-	return goLookupIPOrder(name, hostLookupFilesDNS)
-}
-
-func goLookupIPOrder(name string, order hostLookupOrder) (addrs []IPAddr, err error) {
-	if order == hostLookupFilesDNS || order == hostLookupFiles {
-		addrs = goLookupIPFiles(name)
-		if len(addrs) > 0 || order == hostLookupFiles {
-			return addrs, nil
+// Used only if cgoLookupIP refuses to handle the request
+// (that is, only if cgoLookupIP is the stub in cgo_stub.go).
+// Normally we let cgo use the C library resolver instead of
+// depending on our lookup code, so that Go and C get the same
+// answers.
+func goLookupIP(name string) (addrs []IP, err error) {
+	// Use entries from /etc/hosts if possible.
+	haddrs := lookupStaticHost(name)
+	if len(haddrs) > 0 {
+		for _, haddr := range haddrs {
+			if ip := ParseIP(haddr); ip != nil {
+				addrs = append(addrs, ip)
+			}
+		}
+		if len(addrs) > 0 {
+			return
 		}
 	}
-	if !isDomainName(name) {
-		return nil, &DNSError{Err: "invalid domain name", Name: name}
-	}
-	resolvConf.tryUpdate("/etc/resolv.conf")
-	resolvConf.mu.RLock()
-	conf := resolvConf.dnsConfig
-	resolvConf.mu.RUnlock()
 	type racer struct {
-		rrs []dnsRR
+		qtype uint16
+		rrs   []dnsRR
 		error
 	}
 	lane := make(chan racer, 1)
 	qtypes := [...]uint16{dnsTypeA, dnsTypeAAAA}
+	for _, qtype := range qtypes {
+		go func(qtype uint16) {
+			_, rrs, err := lookup(name, qtype)
+			lane <- racer{qtype, rrs, err}
+		}(qtype)
+	}
 	var lastErr error
-	for _, fqdn := range conf.nameList(name) {
-		for _, qtype := range qtypes {
-			go func(qtype uint16) {
-				_, rrs, err := tryOneName(conf, fqdn, qtype)
-				lane <- racer{rrs, err}
-			}(qtype)
-		}
-		for range qtypes {
-			racer := <-lane
-			if racer.error != nil {
-				lastErr = racer.error
-				continue
-			}
-			addrs = append(addrs, addrRecordList(racer.rrs)...)
+	for range qtypes {
+		racer := <-lane
+		if racer.error != nil {
+			lastErr = racer.error
+			continue
 		}
-		if len(addrs) > 0 {
-			break
+		switch racer.qtype {
+		case dnsTypeA:
+			addrs = append(addrs, convertRR_A(racer.rrs)...)
+		case dnsTypeAAAA:
+			addrs = append(addrs, convertRR_AAAA(racer.rrs)...)
 		}
 	}
-	if lastErr, ok := lastErr.(*DNSError); ok {
-		// Show original name passed to lookup, not suffixed one.
-		// In general we might have tried many suffixes; showing
-		// just one is misleading. See also golang.org/issue/6324.
-		lastErr.Name = name
-	}
-	sortByRFC6724(addrs)
-	if len(addrs) == 0 {
-		if lastErr != nil {
-			return nil, lastErr
-		}
-		if order == hostLookupDNSFiles {
-			addrs = goLookupIPFiles(name)
-		}
+	if len(addrs) == 0 && lastErr != nil {
+		return nil, lastErr
 	}
 	return addrs, nil
 }
@@ -490,35 +414,10 @@ func goLookupIPOrder(name string, order hostLookupOrder) (addrs []IPAddr, err er
 // depending on our lookup code, so that Go and C get the same
 // answers.
 func goLookupCNAME(name string) (cname string, err error) {
-	_, rrs, err := lookup(name, dnsTypeCNAME)
+	_, rr, err := lookup(name, dnsTypeCNAME)
 	if err != nil {
 		return
 	}
-	cname = rrs[0].(*dnsRR_CNAME).Cname
+	cname = rr[0].(*dnsRR_CNAME).Cname
 	return
 }
-
-// goLookupPTR is the native Go implementation of LookupAddr.
-// Used only if cgoLookupPTR refuses to handle the request (that is,
-// only if cgoLookupPTR is the stub in cgo_stub.go).
-// Normally we let cgo use the C library resolver instead of depending
-// on our lookup code, so that Go and C get the same answers.
-func goLookupPTR(addr string) ([]string, error) {
-	names := lookupStaticAddr(addr)
-	if len(names) > 0 {
-		return names, nil
-	}
-	arpa, err := reverseaddr(addr)
-	if err != nil {
-		return nil, err
-	}
-	_, rrs, err := lookup(arpa, dnsTypePTR)
-	if err != nil {
-		return nil, err
-	}
-	ptrs := make([]string, len(rrs))
-	for i, rr := range rrs {
-		ptrs[i] = rr.(*dnsRR_PTR).Ptr
-	}
-	return ptrs, nil
-}
diff --git a/src/net/dnsclient_unix_test.go b/src/net/dnsclient_unix_test.go
index a999f8f..1167c26 100644
--- a/src/net/dnsclient_unix_test.go
+++ b/src/net/dnsclient_unix_test.go
@@ -7,13 +7,11 @@
 package net
 
 import (
-	"fmt"
+	"io"
 	"io/ioutil"
 	"os"
 	"path"
 	"reflect"
-	"strings"
-	"sync"
 	"testing"
 	"time"
 )
@@ -33,7 +31,7 @@ var dnsTransportFallbackTests = []struct {
 
 func TestDNSTransportFallback(t *testing.T) {
 	if testing.Short() || !*testExternal {
-		t.Skip("avoid external network")
+		t.Skip("skipping test to avoid external network")
 	}
 
 	for _, tt := range dnsTransportFallbackTests {
@@ -59,13 +57,13 @@ var specialDomainNameTests = []struct {
 	qtype uint16
 	rcode int
 }{
-	// Name resolution APIs and libraries should not recognize the
+	// Name resoltion APIs and libraries should not recongnize the
 	// followings as special.
 	{"1.0.168.192.in-addr.arpa.", dnsTypePTR, dnsRcodeNameError},
 	{"test.", dnsTypeALL, dnsRcodeNameError},
 	{"example.com.", dnsTypeALL, dnsRcodeSuccess},
 
-	// Name resolution APIs and libraries should recognize the
+	// Name resoltion APIs and libraries should recongnize the
 	// followings as special and should not send any queries.
 	// Though, we test those names here for verifying nagative
 	// answers at DNS query-response interaction level.
@@ -75,7 +73,7 @@ var specialDomainNameTests = []struct {
 
 func TestSpecialDomainName(t *testing.T) {
 	if testing.Short() || !*testExternal {
-		t.Skip("avoid external network")
+		t.Skip("skipping test to avoid external network")
 	}
 
 	server := "8.8.8.8:53"
@@ -95,323 +93,154 @@ func TestSpecialDomainName(t *testing.T) {
 }
 
 type resolvConfTest struct {
-	dir  string
-	path string
-	*resolverConfig
+	*testing.T
+	dir     string
+	path    string
+	started bool
+	quitc   chan chan struct{}
 }
 
-func newResolvConfTest() (*resolvConfTest, error) {
-	dir, err := ioutil.TempDir("", "go-resolvconftest")
+func newResolvConfTest(t *testing.T) *resolvConfTest {
+	dir, err := ioutil.TempDir("", "resolvConfTest")
 	if err != nil {
-		return nil, err
+		t.Fatalf("could not create temp dir: %v", err)
 	}
-	conf := &resolvConfTest{
-		dir:            dir,
-		path:           path.Join(dir, "resolv.conf"),
-		resolverConfig: &resolvConf,
+
+	// Disable the default loadConfig
+	onceLoadConfig.Do(func() {})
+
+	r := &resolvConfTest{
+		T:     t,
+		dir:   dir,
+		path:  path.Join(dir, "resolv.conf"),
+		quitc: make(chan chan struct{}),
 	}
-	conf.initOnce.Do(conf.init)
-	return conf, nil
+
+	return r
 }
 
-func (conf *resolvConfTest) writeAndUpdate(lines []string) error {
-	f, err := os.OpenFile(conf.path, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0600)
+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 {
-		return err
+		r.Fatalf("failed to create temp file %s: %v", r.path, err)
 	}
-	if _, err := f.WriteString(strings.Join(lines, "\n")); err != nil {
+	if _, err := io.WriteString(f, s); err != nil {
 		f.Close()
-		return err
+		r.Fatalf("failed to write temp file: %v", err)
 	}
 	f.Close()
-	if err := conf.forceUpdate(conf.path); err != nil {
-		return err
-	}
-	return nil
-}
 
-func (conf *resolvConfTest) forceUpdate(name string) error {
-	dnsConf := dnsReadConfig(name)
-	conf.mu.Lock()
-	conf.dnsConfig = dnsConf
-	conf.mu.Unlock()
-	for i := 0; i < 5; i++ {
-		if conf.tryAcquireSema() {
-			conf.lastChecked = time.Time{}
-			conf.releaseSema()
-			return nil
-		}
+	if r.started {
+		cfg.ch <- struct{}{} // fill buffer
+		cfg.ch <- struct{}{} // wait for reload to begin
+		cfg.ch <- struct{}{} // wait for reload to complete
 	}
-	return fmt.Errorf("tryAcquireSema for %s failed", name)
 }
 
-func (conf *resolvConfTest) servers() []string {
-	conf.mu.RLock()
-	servers := conf.dnsConfig.servers
-	conf.mu.RUnlock()
-	return servers
-}
-
-func (conf *resolvConfTest) teardown() error {
-	err := conf.forceUpdate("/etc/resolv.conf")
-	os.RemoveAll(conf.dir)
-	return err
+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)
+	}
 }
 
-var updateResolvConfTests = []struct {
-	name    string   // query name
-	lines   []string // resolver configuration lines
-	servers []string // expected name servers
-}{
-	{
-		name:    "golang.org",
-		lines:   []string{"nameserver 8.8.8.8"},
-		servers: []string{"8.8.8.8"},
-	},
-	{
-		name:    "",
-		lines:   nil, // an empty resolv.conf should use defaultNS as name servers
-		servers: defaultNS,
-	},
-	{
-		name:    "www.example.com",
-		lines:   []string{"nameserver 8.8.4.4"},
-		servers: []string{"8.8.4.4"},
-	},
+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 TestUpdateResolvConf(t *testing.T) {
+func TestReloadResolvConfFail(t *testing.T) {
 	if testing.Short() || !*testExternal {
-		t.Skip("avoid external network")
+		t.Skip("skipping test to avoid external network")
 	}
 
-	conf, err := newResolvConfTest()
-	if err != nil {
-		t.Fatal(err)
+	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")
 	}
-	defer conf.teardown()
 
-	for i, tt := range updateResolvConfTests {
-		if err := conf.writeAndUpdate(tt.lines); err != nil {
-			t.Error(err)
-			continue
-		}
-		if tt.name != "" {
-			var wg sync.WaitGroup
-			const N = 10
-			wg.Add(N)
-			for j := 0; j < N; j++ {
-				go func(name string) {
-					defer wg.Done()
-					ips, err := goLookupIP(name)
-					if err != nil {
-						t.Error(err)
-						return
-					}
-					if len(ips) == 0 {
-						t.Errorf("no records for %s", name)
-						return
-					}
-				}(tt.name)
-			}
-			wg.Wait()
-		}
-		servers := conf.servers()
-		if !reflect.DeepEqual(servers, tt.servers) {
-			t.Errorf("#%d: got %v; want %v", i, servers, tt.servers)
-			continue
-		}
+	r.SetConf("nameserver 8.8.8.8")
+	if _, err := goLookupIP("golang.org"); err != nil {
+		t.Fatalf("goLookupIP(missing; good) failed: %v", err)
 	}
-}
 
-var goLookupIPWithResolverConfigTests = []struct {
-	name  string
-	lines []string // resolver configuration lines
-	error
-	a, aaaa bool // whether response contains A, AAAA-record
-}{
-	// no records, transport timeout
-	{
-		"jgahvsekduiv9bw4b3qhn4ykdfgj0493iohkrjfhdvhjiu4j",
-		[]string{
-			"options timeout:1 attempts:1",
-			"nameserver 255.255.255.255", // please forgive us for abuse of limited broadcast address
-		},
-		&DNSError{Name: "jgahvsekduiv9bw4b3qhn4ykdfgj0493iohkrjfhdvhjiu4j", Server: "255.255.255.255:53", IsTimeout: true},
-		false, false,
-	},
-
-	// no records, non-existent domain
-	{
-		"jgahvsekduiv9bw4b3qhn4ykdfgj0493iohkrjfhdvhjiu4j",
-		[]string{
-			"options timeout:3 attempts:1",
-			"nameserver 8.8.8.8",
-		},
-		&DNSError{Name: "jgahvsekduiv9bw4b3qhn4ykdfgj0493iohkrjfhdvhjiu4j", Server: "8.8.8.8:53", IsTimeout: false},
-		false, false,
-	},
-
-	// a few A records, no AAAA records
-	{
-		"ipv4.google.com.",
-		[]string{
-			"nameserver 8.8.8.8",
-			"nameserver 2001:4860:4860::8888",
-		},
-		nil,
-		true, false,
-	},
-	{
-		"ipv4.google.com",
-		[]string{
-			"domain golang.org",
-			"nameserver 2001:4860:4860::8888",
-			"nameserver 8.8.8.8",
-		},
-		nil,
-		true, false,
-	},
-	{
-		"ipv4.google.com",
-		[]string{
-			"search x.golang.org y.golang.org",
-			"nameserver 2001:4860:4860::8888",
-			"nameserver 8.8.8.8",
-		},
-		nil,
-		true, false,
-	},
-
-	// no A records, a few AAAA records
-	{
-		"ipv6.google.com.",
-		[]string{
-			"nameserver 2001:4860:4860::8888",
-			"nameserver 8.8.8.8",
-		},
-		nil,
-		false, true,
-	},
-	{
-		"ipv6.google.com",
-		[]string{
-			"domain golang.org",
-			"nameserver 8.8.8.8",
-			"nameserver 2001:4860:4860::8888",
-		},
-		nil,
-		false, true,
-	},
-	{
-		"ipv6.google.com",
-		[]string{
-			"search x.golang.org y.golang.org",
-			"nameserver 8.8.8.8",
-			"nameserver 2001:4860:4860::8888",
-		},
-		nil,
-		false, true,
-	},
-
-	// both A and AAAA records
-	{
-		"hostname.as112.net", // see RFC 7534
-		[]string{
-			"domain golang.org",
-			"nameserver 2001:4860:4860::8888",
-			"nameserver 8.8.8.8",
-		},
-		nil,
-		true, true,
-	},
-	{
-		"hostname.as112.net", // see RFC 7534
-		[]string{
-			"search x.golang.org y.golang.org",
-			"nameserver 2001:4860:4860::8888",
-			"nameserver 8.8.8.8",
-		},
-		nil,
-		true, true,
-	},
+	// 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 TestGoLookupIPWithResolverConfig(t *testing.T) {
+func TestReloadResolvConfChange(t *testing.T) {
 	if testing.Short() || !*testExternal {
-		t.Skip("avoid external network")
+		t.Skip("skipping test to avoid external network")
 	}
 
-	conf, err := newResolvConfTest()
-	if err != nil {
-		t.Fatal(err)
+	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)
 	}
-	defer conf.teardown()
+	r.WantServers([]string{"8.8.8.8"})
 
-	for _, tt := range goLookupIPWithResolverConfigTests {
-		if err := conf.writeAndUpdate(tt.lines); err != nil {
-			t.Error(err)
-			continue
-		}
-		conf.tryUpdate(conf.path)
-		addrs, err := goLookupIP(tt.name)
-		if err != nil {
-			if err, ok := err.(*DNSError); !ok || (err.Name != tt.error.(*DNSError).Name || err.Server != tt.error.(*DNSError).Server || err.IsTimeout != tt.error.(*DNSError).IsTimeout) {
-				t.Errorf("got %v; want %v", err, tt.error)
-			}
-			continue
-		}
-		if len(addrs) == 0 {
-			t.Errorf("no records for %s", tt.name)
-		}
-		if !tt.a && !tt.aaaa && len(addrs) > 0 {
-			t.Errorf("unexpected %v for %s", addrs, tt.name)
-		}
-		for _, addr := range addrs {
-			if !tt.a && addr.IP.To4() != nil {
-				t.Errorf("got %v; must not be IPv4 address", addr)
-			}
-			if !tt.aaaa && addr.IP.To16() != nil && addr.IP.To4() == nil {
-				t.Errorf("got %v; must not be IPv6 address", addr)
-			}
-		}
+	// 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"})
 }
 
 func BenchmarkGoLookupIP(b *testing.B) {
-	testHookUninstaller.Do(uninstallTestHooks)
-
 	for i := 0; i < b.N; i++ {
 		goLookupIP("www.example.com")
 	}
 }
 
 func BenchmarkGoLookupIPNoSuchHost(b *testing.B) {
-	testHookUninstaller.Do(uninstallTestHooks)
-
 	for i := 0; i < b.N; i++ {
 		goLookupIP("some.nonexistent")
 	}
 }
 
 func BenchmarkGoLookupIPWithBrokenNameServer(b *testing.B) {
-	testHookUninstaller.Do(uninstallTestHooks)
-
-	conf, err := newResolvConfTest()
-	if err != nil {
-		b.Fatal(err)
-	}
-	defer conf.teardown()
-
-	lines := []string{
-		"nameserver 203.0.113.254", // use TEST-NET-3 block, see RFC 5737
-		"nameserver 8.8.8.8",
-	}
-	if err := conf.writeAndUpdate(lines); err != nil {
-		b.Fatal(err)
-	}
-
+	onceLoadConfig.Do(loadDefaultConfig)
+	if cfg.dnserr != nil || cfg.dnsConfig == nil {
+		b.Fatalf("loadConfig failed: %v", cfg.dnserr)
+	}
+	// This looks ugly but it's safe as long as benchmarks are run
+	// sequentially in package testing.
+	orig := cfg.dnsConfig
+	cfg.dnsConfig.servers = append([]string{"203.0.113.254"}, cfg.dnsConfig.servers...) // use TEST-NET-3 block, see RFC 5737
 	for i := 0; i < b.N; i++ {
 		goLookupIP("www.example.com")
 	}
+	cfg.dnsConfig = orig
 }
diff --git a/src/net/dnsconfig_unix.go b/src/net/dnsconfig_unix.go
index 6073fdb..66ab7c4 100644
--- a/src/net/dnsconfig_unix.go
+++ b/src/net/dnsconfig_unix.go
@@ -8,41 +8,30 @@
 
 package net
 
-var defaultNS = []string{"127.0.0.1", "::1"}
-
 type dnsConfig struct {
-	servers    []string // servers to use
-	search     []string // suffixes to append to local name
-	ndots      int      // number of dots in name to trigger absolute lookup
-	timeout    int      // seconds before giving up on packet
-	attempts   int      // lost packets before giving up on server
-	rotate     bool     // round robin among servers
-	unknownOpt bool     // anything unknown was encountered
-	lookup     []string // OpenBSD top-level database "lookup" order
-	err        error    // any error that occurs during open of resolv.conf
+	servers  []string // servers to use
+	search   []string // suffixes to append to local name
+	ndots    int      // number of dots in name to trigger absolute lookup
+	timeout  int      // seconds before giving up on packet
+	attempts int      // lost packets before giving up on server
+	rotate   bool     // round robin among servers
 }
 
 // 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.
-func dnsReadConfig(filename string) *dnsConfig {
+func dnsReadConfig(filename string) (*dnsConfig, error) {
+	file, err := open(filename)
+	if err != nil {
+		return nil, &DNSConfigError{err}
+	}
+	defer file.close()
 	conf := &dnsConfig{
 		ndots:    1,
 		timeout:  5,
 		attempts: 2,
 	}
-	file, err := open(filename)
-	if err != nil {
-		conf.servers = defaultNS
-		conf.err = err
-		return conf
-	}
-	defer file.close()
 	for line, ok := file.readLine(); ok; line, ok = file.readLine() {
-		if len(line) > 0 && (line[0] == ';' || line[0] == '#') {
-			// comment.
-			continue
-		}
 		f := getFields(line)
 		if len(f) < 1 {
 			continue
@@ -72,7 +61,8 @@ func dnsReadConfig(filename string) *dnsConfig {
 			}
 
 		case "options": // magic options
-			for _, s := range f[1:] {
+			for i := 1; i < len(f); i++ {
+				s := f[i]
 				switch {
 				case hasPrefix(s, "ndots:"):
 					n, _, _ := dtoi(s, 6)
@@ -94,25 +84,11 @@ func dnsReadConfig(filename string) *dnsConfig {
 					conf.attempts = n
 				case s == "rotate":
 					conf.rotate = true
-				default:
-					conf.unknownOpt = true
 				}
 			}
-
-		case "lookup":
-			// OpenBSD option:
-			// http://www.openbsd.org/cgi-bin/man.cgi/OpenBSD-current/man5/resolv.conf.5
-			// "the legal space-separated values are: bind, file, yp"
-			conf.lookup = f[1:]
-
-		default:
-			conf.unknownOpt = true
 		}
 	}
-	if len(conf.servers) == 0 {
-		conf.servers = defaultNS
-	}
-	return conf
+	return conf, nil
 }
 
 func hasPrefix(s, prefix string) bool {
diff --git a/src/net/dnsconfig_unix_test.go b/src/net/dnsconfig_unix_test.go
index c8eed61..94fb0c3 100644
--- a/src/net/dnsconfig_unix_test.go
+++ b/src/net/dnsconfig_unix_test.go
@@ -7,30 +7,28 @@
 package net
 
 import (
-	"os"
 	"reflect"
 	"testing"
 )
 
 var dnsReadConfigTests = []struct {
 	name string
-	want *dnsConfig
+	conf dnsConfig
 }{
 	{
 		name: "testdata/resolv.conf",
-		want: &dnsConfig{
-			servers:    []string{"8.8.8.8", "2001:4860:4860::8888", "fe80::1%lo0"},
-			search:     []string{"localdomain"},
-			ndots:      5,
-			timeout:    10,
-			attempts:   3,
-			rotate:     true,
-			unknownOpt: true, // the "options attempts 3" line
+		conf: dnsConfig{
+			servers:  []string{"8.8.8.8", "2001:4860:4860::8888", "fe80::1%lo0"},
+			search:   []string{"localdomain"},
+			ndots:    5,
+			timeout:  10,
+			attempts: 3,
+			rotate:   true,
 		},
 	},
 	{
 		name: "testdata/domain-resolv.conf",
-		want: &dnsConfig{
+		conf: dnsConfig{
 			servers:  []string{"8.8.8.8"},
 			search:   []string{"localdomain"},
 			ndots:    1,
@@ -40,7 +38,7 @@ var dnsReadConfigTests = []struct {
 	},
 	{
 		name: "testdata/search-resolv.conf",
-		want: &dnsConfig{
+		conf: dnsConfig{
 			servers:  []string{"8.8.8.8"},
 			search:   []string{"test", "invalid"},
 			ndots:    1,
@@ -50,51 +48,22 @@ var dnsReadConfigTests = []struct {
 	},
 	{
 		name: "testdata/empty-resolv.conf",
-		want: &dnsConfig{
-			servers:  defaultNS,
-			ndots:    1,
-			timeout:  5,
-			attempts: 2,
-		},
-	},
-	{
-		name: "testdata/openbsd-resolv.conf",
-		want: &dnsConfig{
+		conf: dnsConfig{
 			ndots:    1,
 			timeout:  5,
 			attempts: 2,
-			lookup:   []string{"file", "bind"},
-			servers:  []string{"169.254.169.254", "10.240.0.1"},
-			search:   []string{"c.symbolic-datum-552.internal."},
 		},
 	},
 }
 
 func TestDNSReadConfig(t *testing.T) {
 	for _, tt := range dnsReadConfigTests {
-		conf := dnsReadConfig(tt.name)
-		if conf.err != nil {
-			t.Fatal(conf.err)
+		conf, err := dnsReadConfig(tt.name)
+		if err != nil {
+			t.Fatal(err)
 		}
-		if !reflect.DeepEqual(conf, tt.want) {
-			t.Errorf("%s:\ngot: %+v\nwant: %+v", tt.name, conf, tt.want)
+		if !reflect.DeepEqual(conf, &tt.conf) {
+			t.Errorf("got %v; want %v", conf, &tt.conf)
 		}
 	}
 }
-
-func TestDNSReadMissingFile(t *testing.T) {
-	conf := dnsReadConfig("a-nonexistent-file")
-	if !os.IsNotExist(conf.err) {
-		t.Errorf("missing resolv.conf:\ngot: %v\nwant: %v", conf.err, os.ErrNotExist)
-	}
-	conf.err = nil
-	want := &dnsConfig{
-		servers:  defaultNS,
-		ndots:    1,
-		timeout:  5,
-		attempts: 2,
-	}
-	if !reflect.DeepEqual(conf, want) {
-		t.Errorf("missing resolv.conf:\ngot: %+v\nwant: %+v", conf, want)
-	}
-}
diff --git a/src/net/dnsmsg.go b/src/net/dnsmsg.go
index 6ecaa94..161afb2 100644
--- a/src/net/dnsmsg.go
+++ b/src/net/dnsmsg.go
@@ -306,23 +306,7 @@ func (rr *dnsRR_TXT) Header() *dnsRR_Header {
 }
 
 func (rr *dnsRR_TXT) Walk(f func(v interface{}, name, tag string) bool) bool {
-	if !rr.Hdr.Walk(f) {
-		return false
-	}
-	var n uint16 = 0
-	for n < rr.Hdr.Rdlength {
-		var txt string
-		if !f(&txt, "Txt", "") {
-			return false
-		}
-		// more bytes than rr.Hdr.Rdlength said there woudld be
-		if rr.Hdr.Rdlength-n < uint16(len(txt))+1 {
-			return false
-		}
-		n += uint16(len(txt)) + 1
-		rr.Txt += txt
-	}
-	return true
+	return rr.Hdr.Walk(f) && f(&rr.Txt, "Txt", "")
 }
 
 type dnsRR_SRV struct {
diff --git a/src/net/dnsmsg_test.go b/src/net/dnsmsg_test.go
index 1078d77..c39dbdb 100644
--- a/src/net/dnsmsg_test.go
+++ b/src/net/dnsmsg_test.go
@@ -18,7 +18,7 @@ func TestDNSParseSRVReply(t *testing.T) {
 	msg := new(dnsMsg)
 	ok := msg.Unpack(data)
 	if !ok {
-		t.Fatal("unpacking packet failed")
+		t.Fatalf("unpacking packet failed")
 	}
 	msg.String() // exercise this code path
 	if g, e := len(msg.answer), 5; g != e {
@@ -32,19 +32,13 @@ func TestDNSParseSRVReply(t *testing.T) {
 			t.Errorf("answer[%d] = %T; want *dnsRR_SRV", idx, rr)
 		}
 	}
-	for _, name := range [...]string{
-		"_xmpp-server._tcp.google.com.",
-		"_XMPP-Server._TCP.Google.COM.",
-		"_XMPP-SERVER._TCP.GOOGLE.COM.",
-	} {
-		_, addrs, err := answer(name, "foo:53", msg, uint16(dnsTypeSRV))
-		if err != nil {
-			t.Error(err)
-		}
-		if g, e := len(addrs), 5; g != e {
-			t.Errorf("len(addrs) = %d; want %d", g, e)
-			t.Logf("addrs = %#v", addrs)
-		}
+	_, addrs, err := answer("_xmpp-server._tcp.google.com.", "foo:53", msg, uint16(dnsTypeSRV))
+	if err != nil {
+		t.Fatalf("answer: %v", err)
+	}
+	if g, e := len(addrs), 5; g != e {
+		t.Errorf("len(addrs) = %d; want %d", g, e)
+		t.Logf("addrs = %#v", addrs)
 	}
 	// repack and unpack.
 	data2, ok := msg.Pack()
@@ -52,9 +46,9 @@ func TestDNSParseSRVReply(t *testing.T) {
 	msg2.Unpack(data2)
 	switch {
 	case !ok:
-		t.Error("failed to repack message")
+		t.Errorf("failed to repack message")
 	case !reflect.DeepEqual(msg, msg2):
-		t.Error("repacked message differs from original")
+		t.Errorf("repacked message differs from original")
 	}
 }
 
@@ -66,7 +60,7 @@ func TestDNSParseCorruptSRVReply(t *testing.T) {
 	msg := new(dnsMsg)
 	ok := msg.Unpack(data)
 	if !ok {
-		t.Fatal("unpacking packet failed")
+		t.Fatalf("unpacking packet failed")
 	}
 	msg.String() // exercise this code path
 	if g, e := len(msg.answer), 5; g != e {
@@ -96,93 +90,6 @@ func TestDNSParseCorruptSRVReply(t *testing.T) {
 	}
 }
 
-func TestDNSParseTXTReply(t *testing.T) {
-	expectedTxt1 := "v=spf1 redirect=_spf.google.com"
-	expectedTxt2 := "v=spf1 ip4:69.63.179.25 ip4:69.63.178.128/25 ip4:69.63.184.0/25 " +
-		"ip4:66.220.144.128/25 ip4:66.220.155.0/24 " +
-		"ip4:69.171.232.0/25 ip4:66.220.157.0/25 " +
-		"ip4:69.171.244.0/24 mx -all"
-
-	replies := []string{dnsTXTReply1, dnsTXTReply2}
-	expectedTxts := []string{expectedTxt1, expectedTxt2}
-
-	for i := range replies {
-		data, err := hex.DecodeString(replies[i])
-		if err != nil {
-			t.Fatal(err)
-		}
-
-		msg := new(dnsMsg)
-		ok := msg.Unpack(data)
-		if !ok {
-			t.Errorf("test %d: unpacking packet failed", i)
-			continue
-		}
-
-		if len(msg.answer) != 1 {
-			t.Errorf("test %d: len(rr.answer) = %d; want 1", i, len(msg.answer))
-			continue
-		}
-
-		rr := msg.answer[0]
-		rrTXT, ok := rr.(*dnsRR_TXT)
-		if !ok {
-			t.Errorf("test %d: answer[0] = %T; want *dnsRR_TXT", i, rr)
-			continue
-		}
-
-		if rrTXT.Txt != expectedTxts[i] {
-			t.Errorf("test %d: Txt = %s; want %s", i, rrTXT.Txt, expectedTxts[i])
-		}
-	}
-}
-
-func TestDNSParseTXTCorruptDataLengthReply(t *testing.T) {
-	replies := []string{dnsTXTCorruptDataLengthReply1, dnsTXTCorruptDataLengthReply2}
-
-	for i := range replies {
-		data, err := hex.DecodeString(replies[i])
-		if err != nil {
-			t.Fatal(err)
-		}
-
-		msg := new(dnsMsg)
-		ok := msg.Unpack(data)
-		if ok {
-			t.Errorf("test %d: expected to fail on unpacking corrupt packet", i)
-		}
-	}
-}
-
-func TestDNSParseTXTCorruptTXTLengthReply(t *testing.T) {
-	replies := []string{dnsTXTCorruptTXTLengthReply1, dnsTXTCorruptTXTLengthReply2}
-
-	for i := range replies {
-		data, err := hex.DecodeString(replies[i])
-		if err != nil {
-			t.Fatal(err)
-		}
-
-		msg := new(dnsMsg)
-		ok := msg.Unpack(data)
-		// Unpacking should succeed, but we should just get the header.
-		if !ok {
-			t.Errorf("test %d: unpacking packet failed", i)
-			continue
-		}
-
-		if len(msg.answer) != 1 {
-			t.Errorf("test %d: len(rr.answer) = %d; want 1", i, len(msg.answer))
-			continue
-		}
-
-		rr := msg.answer[0]
-		if _, justHeader := rr.(*dnsRR_Header); !justHeader {
-			t.Errorf("test %d: rr = %T; expected *dnsRR_Header", i, rr)
-		}
-	}
-}
-
 // Valid DNS SRV reply
 const dnsSRVReply = "0901818000010005000000000c5f786d70702d736572766572045f74637006676f6f67" +
 	"6c6503636f6d0000210001c00c002100010000012c00210014000014950c786d70702d" +
@@ -204,63 +111,3 @@ const dnsSRVCorruptReply = "0901818000010005000000000c5f786d70702d73657276657204
 	"6503636f6d00c00c002100010000012c00200005000014950b786d70702d7365727665" +
 	"72016c06676f6f676c6503636f6d00c00c002100010000012c00FF0014000014950c78" +
 	"6d70702d73657276657231016c06676f6f676c6503636f6d00"
-
-// TXT reply with one <character-string>
-const dnsTXTReply1 = "b3458180000100010004000505676d61696c03636f6d0000100001c00c001000010000012c00" +
-	"201f763d737066312072656469726563743d5f7370662e676f6f676c652e636f6dc00" +
-	"c0002000100025d4c000d036e733406676f6f676c65c012c00c0002000100025d4c00" +
-	"06036e7331c057c00c0002000100025d4c0006036e7333c057c00c0002000100025d4" +
-	"c0006036e7332c057c06c00010001000248b50004d8ef200ac09000010001000248b5" +
-	"0004d8ef220ac07e00010001000248b50004d8ef240ac05300010001000248b50004d" +
-	"8ef260a0000291000000000000000"
-
-// TXT reply with more than one <character-string>.
-// See https://tools.ietf.org/html/rfc1035#section-3.3.14
-const dnsTXTReply2 = "a0a381800001000100020002045f7370660866616365626f6f6b03636f6d0000100001c00c0010000" +
-	"100000e1000af7f763d73706631206970343a36392e36332e3137392e3235206970343a36392e" +
-	"36332e3137382e3132382f3235206970343a36392e36332e3138342e302f3235206970343a363" +
-	"62e3232302e3134342e3132382f3235206970343a36362e3232302e3135352e302f3234206970" +
-	"343a36392e3137312e3233322e302f323520692e70343a36362e3232302e3135372e302f32352" +
-	"06970343a36392e3137312e3234342e302f3234206d78202d616c6cc0110002000100025d1500" +
-	"070161026e73c011c0110002000100025d1500040162c0ecc0ea0001000100025d15000445abe" +
-	"f0cc0fd0001000100025d15000445abff0c"
-
-// DataLength field should be sum of all TXT fields. In this case it's less.
-const dnsTXTCorruptDataLengthReply1 = "a0a381800001000100020002045f7370660866616365626f6f6b03636f6d0000100001c00c0010000" +
-	"100000e1000967f763d73706631206970343a36392e36332e3137392e3235206970343a36392e" +
-	"36332e3137382e3132382f3235206970343a36392e36332e3138342e302f3235206970343a363" +
-	"62e3232302e3134342e3132382f3235206970343a36362e3232302e3135352e302f3234206970" +
-	"343a36392e3137312e3233322e302f323520692e70343a36362e3232302e3135372e302f32352" +
-	"06970343a36392e3137312e3234342e302f3234206d78202d616c6cc0110002000100025d1500" +
-	"070161026e73c011c0110002000100025d1500040162c0ecc0ea0001000100025d15000445abe" +
-	"f0cc0fd0001000100025d15000445abff0c"
-
-// Same as above but DataLength is more than sum of TXT fields.
-const dnsTXTCorruptDataLengthReply2 = "a0a381800001000100020002045f7370660866616365626f6f6b03636f6d0000100001c00c0010000" +
-	"100000e1001227f763d73706631206970343a36392e36332e3137392e3235206970343a36392e" +
-	"36332e3137382e3132382f3235206970343a36392e36332e3138342e302f3235206970343a363" +
-	"62e3232302e3134342e3132382f3235206970343a36362e3232302e3135352e302f3234206970" +
-	"343a36392e3137312e3233322e302f323520692e70343a36362e3232302e3135372e302f32352" +
-	"06970343a36392e3137312e3234342e302f3234206d78202d616c6cc0110002000100025d1500" +
-	"070161026e73c011c0110002000100025d1500040162c0ecc0ea0001000100025d15000445abe" +
-	"f0cc0fd0001000100025d15000445abff0c"
-
-// TXT Length field is less than actual length.
-const dnsTXTCorruptTXTLengthReply1 = "a0a381800001000100020002045f7370660866616365626f6f6b03636f6d0000100001c00c0010000" +
-	"100000e1000af7f763d73706631206970343a36392e36332e3137392e3235206970343a36392e" +
-	"36332e3137382e3132382f3235206970343a36392e36332e3138342e302f3235206970343a363" +
-	"62e3232302e3134342e3132382f3235206970343a36362e3232302e3135352e302f3234206970" +
-	"343a36392e3137312e3233322e302f323520691470343a36362e3232302e3135372e302f32352" +
-	"06970343a36392e3137312e3234342e302f3234206d78202d616c6cc0110002000100025d1500" +
-	"070161026e73c011c0110002000100025d1500040162c0ecc0ea0001000100025d15000445abe" +
-	"f0cc0fd0001000100025d15000445abff0c"
-
-// TXT Length field is more than actual length.
-const dnsTXTCorruptTXTLengthReply2 = "a0a381800001000100020002045f7370660866616365626f6f6b03636f6d0000100001c00c0010000" +
-	"100000e1000af7f763d73706631206970343a36392e36332e3137392e3235206970343a36392e" +
-	"36332e3137382e3132382f3235206970343a36392e36332e3138342e302f3235206970343a363" +
-	"62e3232302e3134342e3132382f3235206970343a36362e3232302e3135352e302f3234206970" +
-	"343a36392e3137312e3233322e302f323520693370343a36362e3232302e3135372e302f32352" +
-	"06970343a36392e3137312e3234342e302f3234206d78202d616c6cc0110002000100025d1500" +
-	"070161026e73c011c0110002000100025d1500040162c0ecc0ea0001000100025d15000445abe" +
-	"f0cc0fd0001000100025d15000445abff0c"
diff --git a/src/net/dnsname_test.go b/src/net/dnsname_test.go
index be07dc6..57dd25f 100644
--- a/src/net/dnsname_test.go
+++ b/src/net/dnsname_test.go
@@ -9,12 +9,12 @@ import (
 	"testing"
 )
 
-type dnsNameTest struct {
+type testCase struct {
 	name   string
 	result bool
 }
 
-var dnsNameTests = []dnsNameTest{
+var tests = []testCase{
 	// RFC2181, section 11.
 	{"_xmpp-server._tcp.google.com", true},
 	{"foo.com", true},
@@ -30,7 +30,7 @@ var dnsNameTests = []dnsNameTest{
 	{"b.com.", true},
 }
 
-func emitDNSNameTest(ch chan<- dnsNameTest) {
+func getTestCases(ch chan<- testCase) {
 	defer close(ch)
 	var char59 = ""
 	var char63 = ""
@@ -41,36 +41,35 @@ func emitDNSNameTest(ch chan<- dnsNameTest) {
 	char63 = char59 + "aaaa"
 	char64 = char63 + "a"
 
-	for _, tc := range dnsNameTests {
+	for _, tc := range tests {
 		ch <- tc
 	}
 
-	ch <- dnsNameTest{char63 + ".com", true}
-	ch <- dnsNameTest{char64 + ".com", false}
+	ch <- testCase{char63 + ".com", true}
+	ch <- testCase{char64 + ".com", false}
 	// 255 char name is fine:
-	ch <- dnsNameTest{char59 + "." + char63 + "." + char63 + "." +
+	ch <- testCase{char59 + "." + char63 + "." + char63 + "." +
 		char63 + ".com",
 		true}
 	// 256 char name is bad:
-	ch <- dnsNameTest{char59 + "a." + char63 + "." + char63 + "." +
+	ch <- testCase{char59 + "a." + char63 + "." + char63 + "." +
 		char63 + ".com",
 		false}
 }
 
-func TestDNSName(t *testing.T) {
-	ch := make(chan dnsNameTest)
-	go emitDNSNameTest(ch)
+func TestDNSNames(t *testing.T) {
+	ch := make(chan testCase)
+	go getTestCases(ch)
 	for tc := range ch {
 		if isDomainName(tc.name) != tc.result {
-			t.Errorf("isDomainName(%q) = %v; want %v", tc.name, !tc.result, tc.result)
+			t.Errorf("isDomainName(%v) failed: Should be %v",
+				tc.name, tc.result)
 		}
 	}
 }
 
-func BenchmarkDNSName(b *testing.B) {
-	testHookUninstaller.Do(uninstallTestHooks)
-
-	benchmarks := append(dnsNameTests, []dnsNameTest{
+func BenchmarkDNSNames(b *testing.B) {
+	benchmarks := append(tests, []testCase{
 		{strings.Repeat("a", 63), true},
 		{strings.Repeat("a", 64), false},
 	}...)
diff --git a/src/net/fd_plan9.go b/src/net/fd_plan9.go
index 32766f5..5fe8eff 100644
--- a/src/net/fd_plan9.go
+++ b/src/net/fd_plan9.go
@@ -11,13 +11,13 @@ import (
 	"time"
 )
 
-// Network file descriptor.
+// Network file descritor.
 type netFD struct {
 	// locking/lifetime of sysfd + serialize access to Read and Write methods
 	fdmu fdMutex
 
 	// immutable until Close
-	net          string
+	proto        string
 	n            string
 	dir          string
 	ctl, data    *os.File
@@ -38,8 +38,8 @@ func dial(net string, ra Addr, dialer func(time.Time) (Conn, error), deadline ti
 	return dialChannel(net, ra, dialer, deadline)
 }
 
-func newFD(net, name string, ctl, data *os.File, laddr, raddr Addr) (*netFD, error) {
-	return &netFD{net: net, n: name, dir: netdir + "/" + net + "/" + name, ctl: ctl, data: data, laddr: laddr, raddr: raddr}, nil
+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 {
@@ -55,7 +55,7 @@ func (fd *netFD) name() string {
 	if fd.raddr != nil {
 		rs = fd.raddr.String()
 	}
-	return fd.net + ":" + ls + "->" + rs
+	return fd.proto + ":" + ls + "->" + rs
 }
 
 func (fd *netFD) ok() bool { return fd != nil && fd.ctl != nil }
@@ -132,7 +132,7 @@ func (fd *netFD) Read(b []byte) (n int, err error) {
 	}
 	defer fd.readUnlock()
 	n, err = fd.data.Read(b)
-	if fd.net == "udp" && err == io.EOF {
+	if fd.proto == "udp" && err == io.EOF {
 		n = 0
 		err = nil
 	}
@@ -202,7 +202,7 @@ func (fd *netFD) file(f *os.File, s string) (*os.File, error) {
 	dfd, err := syscall.Dup(int(f.Fd()), -1)
 	syscall.ForkLock.RUnlock()
 	if err != nil {
-		return nil, os.NewSyscallError("dup", err)
+		return nil, &OpError{"dup", s, fd.laddr, err}
 	}
 	return os.NewFile(uintptr(dfd), s), nil
 }
@@ -226,3 +226,7 @@ func setReadBuffer(fd *netFD, bytes int) error {
 func setWriteBuffer(fd *netFD, bytes int) error {
 	return syscall.EPLAN9
 }
+
+func skipRawSocketTests() (skip bool, skipmsg string, err error) {
+	return true, "skipping test on plan9", nil
+}
diff --git a/src/net/fd_poll_nacl.go b/src/net/fd_poll_nacl.go
index cdf14e3..a3701f8 100644
--- a/src/net/fd_poll_nacl.go
+++ b/src/net/fd_poll_nacl.go
@@ -18,11 +18,18 @@ func (pd *pollDesc) Init(fd *netFD) error { pd.fd = fd; return nil }
 
 func (pd *pollDesc) Close() {}
 
-func (pd *pollDesc) Evict() {
+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 {
diff --git a/src/net/fd_poll_runtime.go b/src/net/fd_poll_runtime.go
index 8522cce..2bddc83 100644
--- a/src/net/fd_poll_runtime.go
+++ b/src/net/fd_poll_runtime.go
@@ -48,12 +48,23 @@ func (pd *pollDesc) Close() {
 	pd.runtimeCtx = 0
 }
 
+func (pd *pollDesc) Lock() {
+}
+
+func (pd *pollDesc) Unlock() {
+}
+
+func (pd *pollDesc) Wakeup() {
+}
+
 // Evict evicts fd from the pending list, unblocking any I/O running on fd.
-func (pd *pollDesc) Evict() {
+// Return value is whether the pollServer should be woken up.
+func (pd *pollDesc) Evict() bool {
 	if pd.runtimeCtx == 0 {
-		return
+		return false
 	}
 	runtime_pollUnblock(pd.runtimeCtx)
+	return false
 }
 
 func (pd *pollDesc) Prepare(mode int) error {
diff --git a/src/net/fd_unix.go b/src/net/fd_unix.go
index 6463b0d..7fa43f6 100644
--- a/src/net/fd_unix.go
+++ b/src/net/fd_unix.go
@@ -72,7 +72,7 @@ func (fd *netFD) connect(la, ra syscall.Sockaddr, deadline time.Time) error {
 	// Do not need to call fd.writeLock here,
 	// because fd is not yet accessible to user,
 	// so no concurrent operations are possible.
-	switch err := connectFunc(fd.sysfd, ra); err {
+	switch err := syscall.Connect(fd.sysfd, ra); err {
 	case syscall.EINPROGRESS, syscall.EALREADY, syscall.EINTR:
 	case nil, syscall.EISCONN:
 		if !deadline.IsZero() && deadline.Before(time.Now()) {
@@ -87,13 +87,13 @@ func (fd *netFD) connect(la, ra syscall.Sockaddr, deadline time.Time) error {
 		// 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 https://golang.org/issue/6828.
+		// case in C see http://golang.org/issue/6828.
 		if runtime.GOOS == "solaris" {
 			return nil
 		}
 		fallthrough
 	default:
-		return os.NewSyscallError("connect", err)
+		return err
 	}
 	if err := fd.init(); err != nil {
 		return err
@@ -114,25 +114,25 @@ func (fd *netFD) connect(la, ra syscall.Sockaddr, deadline time.Time) error {
 		if err := fd.pd.WaitWrite(); err != nil {
 			return err
 		}
-		nerr, err := getsockoptIntFunc(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_ERROR)
+		nerr, err := syscall.GetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_ERROR)
 		if err != nil {
-			return os.NewSyscallError("getsockopt", err)
+			return err
 		}
 		switch err := syscall.Errno(nerr); err {
 		case syscall.EINPROGRESS, syscall.EALREADY, syscall.EINTR:
 		case syscall.Errno(0), syscall.EISCONN:
 			return nil
 		default:
-			return os.NewSyscallError("getsockopt", err)
+			return err
 		}
 	}
 }
 
 func (fd *netFD) destroy() {
 	// Poller may want to unregister fd in readiness notification mechanism,
-	// so this must be executed before closeFunc.
+	// so this must be executed before closesocket.
 	fd.pd.Close()
-	closeFunc(fd.sysfd)
+	closesocket(fd.sysfd)
 	fd.sysfd = -1
 	runtime.SetFinalizer(fd, nil)
 }
@@ -187,7 +187,9 @@ func (fd *netFD) writeUnlock() {
 }
 
 func (fd *netFD) Close() error {
+	fd.pd.Lock() // needed for both fd.incref(true) and pollDesc.Evict
 	if !fd.fdmu.IncrefAndClose() {
+		fd.pd.Unlock()
 		return errClosing
 	}
 	// Unblock any I/O.  Once it all unblocks and returns,
@@ -195,8 +197,12 @@ func (fd *netFD) Close() error {
 	// the final decref will close fd.sysfd.  This should happen
 	// fairly quickly, since all the I/O is non-blocking, and any
 	// attempts to block in the pollDesc will return errClosing.
-	fd.pd.Evict()
+	doWakeup := fd.pd.Evict()
+	fd.pd.Unlock()
 	fd.decref()
+	if doWakeup {
+		fd.pd.Wakeup()
+	}
 	return nil
 }
 
@@ -205,7 +211,11 @@ func (fd *netFD) shutdown(how int) error {
 		return err
 	}
 	defer fd.decref()
-	return os.NewSyscallError("shutdown", syscall.Shutdown(fd.sysfd, how))
+	err := syscall.Shutdown(fd.sysfd, how)
+	if err != nil {
+		return &OpError{"shutdown", fd.net, fd.laddr, err}
+	}
+	return nil
 }
 
 func (fd *netFD) closeRead() error {
@@ -222,10 +232,10 @@ func (fd *netFD) Read(p []byte) (n int, err error) {
 	}
 	defer fd.readUnlock()
 	if err := fd.pd.PrepareRead(); err != nil {
-		return 0, err
+		return 0, &OpError{"read", fd.net, fd.raddr, err}
 	}
 	for {
-		n, err = syscall.Read(fd.sysfd, p)
+		n, err = syscall.Read(int(fd.sysfd), p)
 		if err != nil {
 			n = 0
 			if err == syscall.EAGAIN {
@@ -234,11 +244,11 @@ func (fd *netFD) Read(p []byte) (n int, err error) {
 				}
 			}
 		}
-		err = fd.eofError(n, err)
+		err = chkReadErr(n, err, fd)
 		break
 	}
-	if _, ok := err.(syscall.Errno); ok {
-		err = os.NewSyscallError("read", err)
+	if err != nil && err != io.EOF {
+		err = &OpError{"read", fd.net, fd.raddr, err}
 	}
 	return
 }
@@ -249,7 +259,7 @@ func (fd *netFD) readFrom(p []byte) (n int, sa syscall.Sockaddr, err error) {
 	}
 	defer fd.readUnlock()
 	if err := fd.pd.PrepareRead(); err != nil {
-		return 0, nil, err
+		return 0, nil, &OpError{"read", fd.net, fd.laddr, err}
 	}
 	for {
 		n, sa, err = syscall.Recvfrom(fd.sysfd, p, 0)
@@ -261,11 +271,11 @@ func (fd *netFD) readFrom(p []byte) (n int, sa syscall.Sockaddr, err error) {
 				}
 			}
 		}
-		err = fd.eofError(n, err)
+		err = chkReadErr(n, err, fd)
 		break
 	}
-	if _, ok := err.(syscall.Errno); ok {
-		err = os.NewSyscallError("recvfrom", err)
+	if err != nil && err != io.EOF {
+		err = &OpError{"read", fd.net, fd.laddr, err}
 	}
 	return
 }
@@ -276,7 +286,7 @@ func (fd *netFD) readMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.S
 	}
 	defer fd.readUnlock()
 	if err := fd.pd.PrepareRead(); err != nil {
-		return 0, 0, 0, nil, err
+		return 0, 0, 0, nil, &OpError{"read", fd.net, fd.laddr, err}
 	}
 	for {
 		n, oobn, flags, sa, err = syscall.Recvmsg(fd.sysfd, p, oob, 0)
@@ -288,26 +298,33 @@ func (fd *netFD) readMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.S
 				}
 			}
 		}
-		err = fd.eofError(n, err)
+		err = chkReadErr(n, err, fd)
 		break
 	}
-	if _, ok := err.(syscall.Errno); ok {
-		err = os.NewSyscallError("recvmsg", err)
+	if err != nil && err != io.EOF {
+		err = &OpError{"read", fd.net, fd.laddr, err}
 	}
 	return
 }
 
+func chkReadErr(n int, err error, fd *netFD) error {
+	if n == 0 && err == nil && fd.sotype != syscall.SOCK_DGRAM && fd.sotype != syscall.SOCK_RAW {
+		return io.EOF
+	}
+	return err
+}
+
 func (fd *netFD) Write(p []byte) (nn int, err error) {
 	if err := fd.writeLock(); err != nil {
 		return 0, err
 	}
 	defer fd.writeUnlock()
 	if err := fd.pd.PrepareWrite(); err != nil {
-		return 0, err
+		return 0, &OpError{"write", fd.net, fd.raddr, err}
 	}
 	for {
 		var n int
-		n, err = syscall.Write(fd.sysfd, p[nn:])
+		n, err = syscall.Write(int(fd.sysfd), p[nn:])
 		if n > 0 {
 			nn += n
 		}
@@ -320,6 +337,7 @@ func (fd *netFD) Write(p []byte) (nn int, err error) {
 			}
 		}
 		if err != nil {
+			n = 0
 			break
 		}
 		if n == 0 {
@@ -327,8 +345,8 @@ func (fd *netFD) Write(p []byte) (nn int, err error) {
 			break
 		}
 	}
-	if _, ok := err.(syscall.Errno); ok {
-		err = os.NewSyscallError("write", err)
+	if err != nil {
+		err = &OpError{"write", fd.net, fd.raddr, err}
 	}
 	return nn, err
 }
@@ -339,7 +357,7 @@ func (fd *netFD) writeTo(p []byte, sa syscall.Sockaddr) (n int, err error) {
 	}
 	defer fd.writeUnlock()
 	if err := fd.pd.PrepareWrite(); err != nil {
-		return 0, err
+		return 0, &OpError{"write", fd.net, fd.raddr, err}
 	}
 	for {
 		err = syscall.Sendto(fd.sysfd, p, 0, sa)
@@ -352,9 +370,8 @@ func (fd *netFD) writeTo(p []byte, sa syscall.Sockaddr) (n int, err error) {
 	}
 	if err == nil {
 		n = len(p)
-	}
-	if _, ok := err.(syscall.Errno); ok {
-		err = os.NewSyscallError("sendto", err)
+	} else {
+		err = &OpError{"write", fd.net, fd.raddr, err}
 	}
 	return
 }
@@ -365,7 +382,7 @@ func (fd *netFD) writeMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oob
 	}
 	defer fd.writeUnlock()
 	if err := fd.pd.PrepareWrite(); err != nil {
-		return 0, 0, err
+		return 0, 0, &OpError{"write", fd.net, fd.raddr, err}
 	}
 	for {
 		n, err = syscall.SendmsgN(fd.sysfd, p, oob, sa, 0)
@@ -378,9 +395,8 @@ func (fd *netFD) writeMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oob
 	}
 	if err == nil {
 		oobn = len(oob)
-	}
-	if _, ok := err.(syscall.Errno); ok {
-		err = os.NewSyscallError("sendmsg", err)
+	} else {
+		err = &OpError{"write", fd.net, fd.raddr, err}
 	}
 	return
 }
@@ -394,34 +410,27 @@ func (fd *netFD) accept() (netfd *netFD, err error) {
 	var s int
 	var rsa syscall.Sockaddr
 	if err = fd.pd.PrepareRead(); err != nil {
-		return nil, err
+		return nil, &OpError{"accept", fd.net, fd.laddr, err}
 	}
 	for {
 		s, rsa, err = accept(fd.sysfd)
 		if err != nil {
-			nerr, ok := err.(*os.SyscallError)
-			if !ok {
-				return nil, err
-			}
-			switch nerr.Err {
-			case syscall.EAGAIN:
+			if err == syscall.EAGAIN {
 				if err = fd.pd.WaitRead(); err == nil {
 					continue
 				}
-			case syscall.ECONNABORTED:
-				// This means that a socket on the
-				// listen queue was closed before we
-				// Accept()ed it; it's a silly error,
-				// so try again.
+			} else if err == syscall.ECONNABORTED {
+				// This means that a socket on the listen queue was closed
+				// before we Accept()ed it; it's a silly error, so try again.
 				continue
 			}
-			return nil, err
+			return nil, &OpError{"accept", fd.net, fd.laddr, err}
 		}
 		break
 	}
 
 	if netfd, err = newFD(s, fd.family, fd.sotype, fd.net); err != nil {
-		closeFunc(s)
+		closesocket(s)
 		return nil, err
 	}
 	if err = netfd.init(); err != nil {
@@ -461,7 +470,7 @@ func dupCloseOnExec(fd int) (newfd int, err error) {
 			// from now on.
 			atomic.StoreInt32(&tryDupCloexec, 0)
 		default:
-			return -1, os.NewSyscallError("fcntl", e1)
+			return -1, e1
 		}
 	}
 	return dupCloseOnExecOld(fd)
@@ -474,7 +483,7 @@ func dupCloseOnExecOld(fd int) (newfd int, err error) {
 	defer syscall.ForkLock.RUnlock()
 	newfd, err = syscall.Dup(fd)
 	if err != nil {
-		return -1, os.NewSyscallError("dup", err)
+		return -1, err
 	}
 	syscall.CloseOnExec(newfd)
 	return
@@ -483,7 +492,7 @@ 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 {
-		return nil, err
+		return nil, &OpError{"dup", fd.net, fd.laddr, err}
 	}
 
 	// We want blocking mode for the new fd, hence the double negative.
@@ -491,8 +500,19 @@ func (fd *netFD) dup() (f *os.File, err error) {
 	// I/O will block the thread instead of letting us use the epoll server.
 	// Everything will still work, just with more threads.
 	if err = syscall.SetNonblock(ns, false); err != nil {
-		return nil, os.NewSyscallError("setnonblock", err)
+		return nil, &OpError{"setnonblock", fd.net, fd.laddr, err}
 	}
 
 	return os.NewFile(uintptr(ns), fd.name()), nil
 }
+
+func closesocket(s int) error {
+	return syscall.Close(s)
+}
+
+func skipRawSocketTests() (skip bool, skipmsg string, err error) {
+	if os.Getuid() != 0 {
+		return true, "skipping test; must be root", nil
+	}
+	return false, "", nil
+}
diff --git a/src/net/fd_unix_test.go b/src/net/fd_unix_test.go
new file mode 100644
index 0000000..fe8e8ff
--- /dev/null
+++ b/src/net/fd_unix_test.go
@@ -0,0 +1,58 @@
+// 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 darwin dragonfly freebsd linux netbsd openbsd solaris
+
+package net
+
+import (
+	"io"
+	"syscall"
+	"testing"
+)
+
+var chkReadErrTests = []struct {
+	n        int
+	err      error
+	fd       *netFD
+	expected error
+}{
+
+	{100, nil, &netFD{sotype: syscall.SOCK_STREAM}, nil},
+	{100, io.EOF, &netFD{sotype: syscall.SOCK_STREAM}, io.EOF},
+	{100, errClosing, &netFD{sotype: syscall.SOCK_STREAM}, errClosing},
+	{0, nil, &netFD{sotype: syscall.SOCK_STREAM}, io.EOF},
+	{0, io.EOF, &netFD{sotype: syscall.SOCK_STREAM}, io.EOF},
+	{0, errClosing, &netFD{sotype: syscall.SOCK_STREAM}, errClosing},
+
+	{100, nil, &netFD{sotype: syscall.SOCK_DGRAM}, nil},
+	{100, io.EOF, &netFD{sotype: syscall.SOCK_DGRAM}, io.EOF},
+	{100, errClosing, &netFD{sotype: syscall.SOCK_DGRAM}, errClosing},
+	{0, nil, &netFD{sotype: syscall.SOCK_DGRAM}, nil},
+	{0, io.EOF, &netFD{sotype: syscall.SOCK_DGRAM}, io.EOF},
+	{0, errClosing, &netFD{sotype: syscall.SOCK_DGRAM}, errClosing},
+
+	{100, nil, &netFD{sotype: syscall.SOCK_SEQPACKET}, nil},
+	{100, io.EOF, &netFD{sotype: syscall.SOCK_SEQPACKET}, io.EOF},
+	{100, errClosing, &netFD{sotype: syscall.SOCK_SEQPACKET}, errClosing},
+	{0, nil, &netFD{sotype: syscall.SOCK_SEQPACKET}, io.EOF},
+	{0, io.EOF, &netFD{sotype: syscall.SOCK_SEQPACKET}, io.EOF},
+	{0, errClosing, &netFD{sotype: syscall.SOCK_SEQPACKET}, errClosing},
+
+	{100, nil, &netFD{sotype: syscall.SOCK_RAW}, nil},
+	{100, io.EOF, &netFD{sotype: syscall.SOCK_RAW}, io.EOF},
+	{100, errClosing, &netFD{sotype: syscall.SOCK_RAW}, errClosing},
+	{0, nil, &netFD{sotype: syscall.SOCK_RAW}, nil},
+	{0, io.EOF, &netFD{sotype: syscall.SOCK_RAW}, io.EOF},
+	{0, errClosing, &netFD{sotype: syscall.SOCK_RAW}, errClosing},
+}
+
+func TestChkReadErr(t *testing.T) {
+	for _, tt := range chkReadErrTests {
+		actual := chkReadErr(tt.n, tt.err, tt.fd)
+		if actual != tt.expected {
+			t.Errorf("chkReadError(%v, %v, %v): expected %v, actual %v", tt.n, tt.err, tt.fd.sotype, tt.expected, actual)
+		}
+	}
+}
diff --git a/src/net/fd_windows.go b/src/net/fd_windows.go
index 205daff..f3a534a 100644
--- a/src/net/fd_windows.go
+++ b/src/net/fd_windows.go
@@ -5,6 +5,8 @@
 package net
 
 import (
+	"errors"
+	"io"
 	"os"
 	"runtime"
 	"sync"
@@ -38,7 +40,7 @@ func sysInit() {
 	var d syscall.WSAData
 	e := syscall.WSAStartup(uint32(0x202), &d)
 	if e != nil {
-		initErr = os.NewSyscallError("wsastartup", e)
+		initErr = os.NewSyscallError("WSAStartup", e)
 	}
 	canCancelIO = syscall.LoadCancelIoEx() == nil
 	if syscall.LoadGetAddrInfo() == nil {
@@ -68,6 +70,10 @@ func sysInit() {
 	}
 }
 
+func closesocket(s syscall.Handle) error {
+	return syscall.Closesocket(s)
+}
+
 func canUseConnectEx(net string) bool {
 	switch net {
 	case "udp", "udp4", "udp6", "ip", "ip4", "ip6":
@@ -153,7 +159,7 @@ func (s *ioSrv) ExecIO(o *operation, name string, submit func(o *operation) erro
 	// Notify runtime netpoll about starting IO.
 	err := fd.pd.Prepare(int(o.mode))
 	if err != nil {
-		return 0, err
+		return 0, &OpError{name, fd.net, fd.laddr, err}
 	}
 	// Start IO.
 	if canCancelIO {
@@ -176,7 +182,7 @@ func (s *ioSrv) ExecIO(o *operation, name string, submit func(o *operation) erro
 		// IO started, and we have to wait for its completion.
 		err = nil
 	default:
-		return 0, err
+		return 0, &OpError{name, fd.net, fd.laddr, err}
 	}
 	// Wait for our request to complete.
 	err = fd.pd.Wait(int(o.mode))
@@ -184,7 +190,7 @@ func (s *ioSrv) ExecIO(o *operation, name string, submit func(o *operation) erro
 		// All is good. Extract our IO results and return.
 		if o.errno != 0 {
 			err = syscall.Errno(o.errno)
-			return 0, err
+			return 0, &OpError{name, fd.net, fd.laddr, err}
 		}
 		return int(o.qty), nil
 	}
@@ -215,7 +221,7 @@ func (s *ioSrv) ExecIO(o *operation, name string, submit func(o *operation) erro
 		if err == syscall.ERROR_OPERATION_ABORTED { // IO Canceled
 			err = netpollErr
 		}
-		return 0, err
+		return 0, &OpError{name, fd.net, fd.laddr, err}
 	}
 	// We issued cancellation request. But, it seems, IO operation succeeded
 	// before cancellation request run. We need to treat IO operation as
@@ -297,7 +303,7 @@ func (fd *netFD) init() error {
 		size := uint32(unsafe.Sizeof(flag))
 		err := syscall.WSAIoctl(fd.sysfd, syscall.SIO_UDP_CONNRESET, (*byte)(unsafe.Pointer(&flag)), size, nil, 0, &ret, nil, 0)
 		if err != nil {
-			return os.NewSyscallError("wsaioctl", err)
+			return os.NewSyscallError("WSAIoctl", err)
 		}
 	}
 	fd.rop.mode = 'r'
@@ -331,7 +337,7 @@ func (fd *netFD) connect(la, ra syscall.Sockaddr, deadline time.Time) error {
 		defer fd.setWriteDeadline(noDeadline)
 	}
 	if !canUseConnectEx(fd.net) {
-		return os.NewSyscallError("connect", connectFunc(fd.sysfd, ra))
+		return syscall.Connect(fd.sysfd, ra)
 	}
 	// ConnectEx windows API requires an unconnected, previously bound socket.
 	if la == nil {
@@ -344,23 +350,20 @@ func (fd *netFD) connect(la, ra syscall.Sockaddr, deadline time.Time) error {
 			panic("unexpected type in connect")
 		}
 		if err := syscall.Bind(fd.sysfd, la); err != nil {
-			return os.NewSyscallError("bind", err)
+			return err
 		}
 	}
 	// Call ConnectEx API.
 	o := &fd.wop
 	o.sa = ra
 	_, err := wsrv.ExecIO(o, "ConnectEx", func(o *operation) error {
-		return connectExFunc(o.fd.sysfd, o.sa, nil, 0, nil, &o.o)
+		return syscall.ConnectEx(o.fd.sysfd, o.sa, nil, 0, nil, &o.o)
 	})
 	if err != nil {
-		if _, ok := err.(syscall.Errno); ok {
-			err = os.NewSyscallError("connectex", err)
-		}
 		return err
 	}
 	// Refresh socket properties.
-	return os.NewSyscallError("setsockopt", syscall.Setsockopt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_UPDATE_CONNECT_CONTEXT, (*byte)(unsafe.Pointer(&fd.sysfd)), int32(unsafe.Sizeof(fd.sysfd))))
+	return syscall.Setsockopt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_UPDATE_CONNECT_CONTEXT, (*byte)(unsafe.Pointer(&fd.sysfd)), int32(unsafe.Sizeof(fd.sysfd)))
 }
 
 func (fd *netFD) destroy() {
@@ -368,9 +371,9 @@ func (fd *netFD) destroy() {
 		return
 	}
 	// Poller may want to unregister fd in readiness notification mechanism,
-	// so this must be executed before closeFunc.
+	// so this must be executed before closesocket.
 	fd.pd.Close()
-	closeFunc(fd.sysfd)
+	closesocket(fd.sysfd)
 	fd.sysfd = syscall.InvalidHandle
 	// no need for a finalizer anymore
 	runtime.SetFinalizer(fd, nil)
@@ -440,7 +443,11 @@ func (fd *netFD) shutdown(how int) error {
 		return err
 	}
 	defer fd.decref()
-	return syscall.Shutdown(fd.sysfd, how)
+	err := syscall.Shutdown(fd.sysfd, how)
+	if err != nil {
+		return &OpError{"shutdown", fd.net, fd.laddr, err}
+	}
+	return nil
 }
 
 func (fd *netFD) closeRead() error {
@@ -461,17 +468,16 @@ func (fd *netFD) Read(buf []byte) (int, error) {
 	n, err := rsrv.ExecIO(o, "WSARecv", func(o *operation) error {
 		return syscall.WSARecv(o.fd.sysfd, &o.buf, 1, &o.qty, &o.flags, &o.o, nil)
 	})
+	if err == nil && n == 0 {
+		err = io.EOF
+	}
 	if raceenabled {
 		raceAcquire(unsafe.Pointer(&ioSync))
 	}
-	err = fd.eofError(n, err)
-	if _, ok := err.(syscall.Errno); ok {
-		err = os.NewSyscallError("wsarecv", err)
-	}
 	return n, err
 }
 
-func (fd *netFD) readFrom(buf []byte) (int, syscall.Sockaddr, error) {
+func (fd *netFD) readFrom(buf []byte) (n int, sa syscall.Sockaddr, err error) {
 	if len(buf) == 0 {
 		return 0, nil, nil
 	}
@@ -481,22 +487,18 @@ func (fd *netFD) readFrom(buf []byte) (int, syscall.Sockaddr, error) {
 	defer fd.readUnlock()
 	o := &fd.rop
 	o.InitBuf(buf)
-	n, err := rsrv.ExecIO(o, "WSARecvFrom", func(o *operation) error {
+	n, err = rsrv.ExecIO(o, "WSARecvFrom", func(o *operation) error {
 		if o.rsa == nil {
 			o.rsa = new(syscall.RawSockaddrAny)
 		}
 		o.rsan = int32(unsafe.Sizeof(*o.rsa))
 		return syscall.WSARecvFrom(o.fd.sysfd, &o.buf, 1, &o.qty, &o.flags, o.rsa, &o.rsan, &o.o, nil)
 	})
-	err = fd.eofError(n, err)
-	if _, ok := err.(syscall.Errno); ok {
-		err = os.NewSyscallError("wsarecvfrom", err)
-	}
 	if err != nil {
-		return n, nil, err
+		return 0, nil, err
 	}
-	sa, _ := o.rsa.Sockaddr()
-	return n, sa, nil
+	sa, _ = o.rsa.Sockaddr()
+	return
 }
 
 func (fd *netFD) Write(buf []byte) (int, error) {
@@ -509,13 +511,9 @@ func (fd *netFD) Write(buf []byte) (int, error) {
 	}
 	o := &fd.wop
 	o.InitBuf(buf)
-	n, err := wsrv.ExecIO(o, "WSASend", func(o *operation) error {
+	return wsrv.ExecIO(o, "WSASend", func(o *operation) error {
 		return syscall.WSASend(o.fd.sysfd, &o.buf, 1, &o.qty, 0, &o.o, nil)
 	})
-	if _, ok := err.(syscall.Errno); ok {
-		err = os.NewSyscallError("wsasend", err)
-	}
-	return n, err
 }
 
 func (fd *netFD) writeTo(buf []byte, sa syscall.Sockaddr) (int, error) {
@@ -529,27 +527,23 @@ func (fd *netFD) writeTo(buf []byte, sa syscall.Sockaddr) (int, error) {
 	o := &fd.wop
 	o.InitBuf(buf)
 	o.sa = sa
-	n, err := wsrv.ExecIO(o, "WSASendto", func(o *operation) error {
+	return wsrv.ExecIO(o, "WSASendto", func(o *operation) error {
 		return syscall.WSASendto(o.fd.sysfd, &o.buf, 1, &o.qty, 0, o.sa, &o.o, nil)
 	})
-	if _, ok := err.(syscall.Errno); ok {
-		err = os.NewSyscallError("wsasendto", err)
-	}
-	return n, err
 }
 
 func (fd *netFD) acceptOne(rawsa []syscall.RawSockaddrAny, o *operation) (*netFD, error) {
 	// Get new socket.
 	s, err := sysSocket(fd.family, fd.sotype, 0)
 	if err != nil {
-		return nil, err
+		return nil, &OpError{"socket", fd.net, fd.laddr, err}
 	}
 
 	// Associate our new socket with IOCP.
 	netfd, err := newFD(s, fd.family, fd.sotype, fd.net)
 	if err != nil {
-		closeFunc(s)
-		return nil, err
+		closesocket(s)
+		return nil, &OpError{"accept", fd.net, fd.laddr, err}
 	}
 	if err := netfd.init(); err != nil {
 		fd.Close()
@@ -564,9 +558,6 @@ func (fd *netFD) acceptOne(rawsa []syscall.RawSockaddrAny, o *operation) (*netFD
 	})
 	if err != nil {
 		netfd.Close()
-		if _, ok := err.(syscall.Errno); ok {
-			err = os.NewSyscallError("acceptex", err)
-		}
 		return nil, err
 	}
 
@@ -574,7 +565,7 @@ func (fd *netFD) acceptOne(rawsa []syscall.RawSockaddrAny, o *operation) (*netFD
 	err = syscall.Setsockopt(s, syscall.SOL_SOCKET, syscall.SO_UPDATE_ACCEPT_CONTEXT, (*byte)(unsafe.Pointer(&fd.sysfd)), int32(unsafe.Sizeof(fd.sysfd)))
 	if err != nil {
 		netfd.Close()
-		return nil, os.NewSyscallError("setsockopt", err)
+		return nil, &OpError{"Setsockopt", fd.net, fd.laddr, err}
 	}
 
 	return netfd, nil
@@ -600,11 +591,11 @@ func (fd *netFD) accept() (*netFD, error) {
 		// before AcceptEx could complete. These errors relate to new
 		// connection, not to AcceptEx, so ignore broken connection and
 		// try AcceptEx again for more connections.
-		nerr, ok := err.(*os.SyscallError)
+		operr, ok := err.(*OpError)
 		if !ok {
 			return nil, err
 		}
-		errno, ok := nerr.Err.(syscall.Errno)
+		errno, ok := operr.Err.(syscall.Errno)
 		if !ok {
 			return nil, err
 		}
@@ -628,17 +619,38 @@ func (fd *netFD) accept() (*netFD, error) {
 	return netfd, nil
 }
 
+func skipRawSocketTests() (skip bool, skipmsg string, err error) {
+	// From http://msdn.microsoft.com/en-us/library/windows/desktop/ms740548.aspx:
+	// Note: To use a socket of type SOCK_RAW requires administrative privileges.
+	// Users running Winsock applications that use raw sockets must be a member of
+	// the Administrators group on the local computer, otherwise raw socket calls
+	// will fail with an error code of WSAEACCES. On Windows Vista and later, access
+	// for raw sockets is enforced at socket creation. In earlier versions of Windows,
+	// access for raw sockets is enforced during other socket operations.
+	s, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_RAW, 0)
+	if err == syscall.WSAEACCES {
+		return true, "skipping test; no access to raw socket allowed", nil
+	}
+	if err != nil {
+		return true, "", err
+	}
+	defer syscall.Closesocket(s)
+	return false, "", nil
+}
+
 // Unimplemented functions.
 
 func (fd *netFD) dup() (*os.File, error) {
 	// TODO: Implement this
-	return nil, syscall.EWINDOWS
+	return nil, os.NewSyscallError("dup", syscall.EWINDOWS)
 }
 
+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) {
-	return 0, 0, 0, nil, syscall.EWINDOWS
+	return 0, 0, 0, nil, errNoSupport
 }
 
 func (fd *netFD) writeMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oobn int, err error) {
-	return 0, 0, syscall.EWINDOWS
+	return 0, 0, errNoSupport
 }
diff --git a/src/net/file_plan9.go b/src/net/file_plan9.go
index 892775a..068f088 100644
--- a/src/net/file_plan9.go
+++ b/src/net/file_plan9.go
@@ -86,7 +86,7 @@ func newFileFD(f *os.File) (net *netFD, err error) {
 	return newFD(comp[1], name, ctl, nil, laddr, nil)
 }
 
-func fileConn(f *os.File) (Conn, error) {
+func newFileConn(f *os.File) (c Conn, err error) {
 	fd, err := newFileFD(f)
 	if err != nil {
 		return nil, err
@@ -109,7 +109,7 @@ func fileConn(f *os.File) (Conn, error) {
 	return nil, syscall.EPLAN9
 }
 
-func fileListener(f *os.File) (Listener, error) {
+func newFileListener(f *os.File) (l Listener, err error) {
 	fd, err := newFileFD(f)
 	if err != nil {
 		return nil, err
@@ -132,6 +132,26 @@ func fileListener(f *os.File) (Listener, error) {
 	return &TCPListener{fd}, nil
 }
 
-func filePacketConn(f *os.File) (PacketConn, error) {
+// FileConn returns a copy of the network connection corresponding to
+// the open file f.  It is the caller's responsibility to close f when
+// finished.  Closing c does not affect f, and closing f does not
+// affect c.
+func FileConn(f *os.File) (c Conn, err error) {
+	return newFileConn(f)
+}
+
+// FileListener returns a copy of the network listener corresponding
+// to the open file f.  It is the caller's responsibility to close l
+// when finished.  Closing l does not affect f, and closing f does not
+// affect l.
+func FileListener(f *os.File) (l Listener, err error) {
+	return newFileListener(f)
+}
+
+// FilePacketConn returns a copy of the packet network connection
+// corresponding to the open file f.  It is the caller's
+// responsibility to close f when finished.  Closing c does not affect
+// f, and closing f does not affect c.
+func FilePacketConn(f *os.File) (c PacketConn, err error) {
 	return nil, syscall.EPLAN9
 }
diff --git a/src/net/file_stub.go b/src/net/file_stub.go
index 0f7460c..4281072 100644
--- a/src/net/file_stub.go
+++ b/src/net/file_stub.go
@@ -11,6 +11,28 @@ import (
 	"syscall"
 )
 
-func fileConn(f *os.File) (Conn, error)             { return nil, syscall.ENOPROTOOPT }
-func fileListener(f *os.File) (Listener, error)     { return nil, syscall.ENOPROTOOPT }
-func filePacketConn(f *os.File) (PacketConn, error) { return nil, syscall.ENOPROTOOPT }
+// FileConn returns a copy of the network connection corresponding to
+// the open file f.  It is the caller's responsibility to close f when
+// finished.  Closing c does not affect f, and closing f does not
+// affect c.
+func FileConn(f *os.File) (c Conn, err error) {
+	return nil, syscall.ENOPROTOOPT
+
+}
+
+// FileListener returns a copy of the network listener corresponding
+// to the open file f.  It is the caller's responsibility to close l
+// when finished.  Closing l does not affect f, and closing f does not
+// affect l.
+func FileListener(f *os.File) (l Listener, err error) {
+	return nil, syscall.ENOPROTOOPT
+
+}
+
+// FilePacketConn returns a copy of the packet network connection
+// corresponding to the open file f.  It is the caller's
+// responsibility to close f when finished.  Closing c does not affect
+// f, and closing f does not affect c.
+func FilePacketConn(f *os.File) (c PacketConn, err error) {
+	return nil, syscall.ENOPROTOOPT
+}
diff --git a/src/net/file_test.go b/src/net/file_test.go
index 003dbb2..6fab06a 100644
--- a/src/net/file_test.go
+++ b/src/net/file_test.go
@@ -27,69 +27,77 @@ type connFile interface {
 }
 
 func testFileListener(t *testing.T, net, laddr string) {
+	switch net {
+	case "tcp", "tcp4", "tcp6":
+		laddr += ":0" // any available port
+	}
 	l, err := Listen(net, laddr)
 	if err != nil {
-		t.Fatal(err)
+		t.Fatalf("Listen failed: %v", err)
 	}
 	defer l.Close()
 	lf := l.(listenerFile)
 	f, err := lf.File()
 	if err != nil {
-		t.Fatal(err)
+		t.Fatalf("File failed: %v", err)
 	}
 	c, err := FileListener(f)
 	if err != nil {
-		t.Fatal(err)
+		t.Fatalf("FileListener failed: %v", err)
 	}
 	if !reflect.DeepEqual(l.Addr(), c.Addr()) {
-		t.Fatalf("got %#v; want%#v", l.Addr(), c.Addr())
+		t.Fatalf("Addrs not equal: %#v != %#v", l.Addr(), c.Addr())
 	}
 	if err := c.Close(); err != nil {
-		t.Fatal(err)
+		t.Fatalf("Close failed: %v", err)
 	}
 	if err := f.Close(); err != nil {
-		t.Fatal(err)
+		t.Fatalf("Close failed: %v", err)
 	}
 }
 
 var fileListenerTests = []struct {
 	net   string
 	laddr string
+	ipv6  bool // test with underlying AF_INET6 socket
+	linux bool // test with abstract unix domain socket, a Linux-ism
 }{
-	{net: "tcp", laddr: ":0"},
-	{net: "tcp", laddr: "0.0.0.0:0"},
-	{net: "tcp", laddr: "[::ffff:0.0.0.0]:0"},
-	{net: "tcp", laddr: "[::]:0"},
+	{net: "tcp", laddr: ""},
+	{net: "tcp", laddr: "0.0.0.0"},
+	{net: "tcp", laddr: "[::ffff:0.0.0.0]"},
+	{net: "tcp", laddr: "[::]", ipv6: true},
 
-	{net: "tcp", laddr: "127.0.0.1:0"},
-	{net: "tcp", laddr: "[::ffff:127.0.0.1]:0"},
-	{net: "tcp", laddr: "[::1]:0"},
+	{net: "tcp", laddr: "127.0.0.1"},
+	{net: "tcp", laddr: "[::ffff:127.0.0.1]"},
+	{net: "tcp", laddr: "[::1]", ipv6: true},
 
-	{net: "tcp4", laddr: ":0"},
-	{net: "tcp4", laddr: "0.0.0.0:0"},
-	{net: "tcp4", laddr: "[::ffff:0.0.0.0]:0"},
+	{net: "tcp4", laddr: ""},
+	{net: "tcp4", laddr: "0.0.0.0"},
+	{net: "tcp4", laddr: "[::ffff:0.0.0.0]"},
 
-	{net: "tcp4", laddr: "127.0.0.1:0"},
-	{net: "tcp4", laddr: "[::ffff:127.0.0.1]:0"},
+	{net: "tcp4", laddr: "127.0.0.1"},
+	{net: "tcp4", laddr: "[::ffff:127.0.0.1]"},
 
-	{net: "tcp6", laddr: ":0"},
-	{net: "tcp6", laddr: "[::]:0"},
+	{net: "tcp6", laddr: "", ipv6: true},
+	{net: "tcp6", laddr: "[::]", ipv6: true},
 
-	{net: "tcp6", laddr: "[::1]:0"},
+	{net: "tcp6", laddr: "[::1]", ipv6: true},
 
-	{net: "unix", laddr: "@gotest/net"},
-	{net: "unixpacket", laddr: "@gotest/net"},
+	{net: "unix", laddr: "@gotest/net", linux: true},
+	{net: "unixpacket", laddr: "@gotest/net", linux: true},
 }
 
 func TestFileListener(t *testing.T) {
 	switch runtime.GOOS {
 	case "nacl", "windows":
-		t.Skipf("not supported on %s", runtime.GOOS)
+		t.Skipf("skipping test on %q", runtime.GOOS)
 	}
 
 	for _, tt := range fileListenerTests {
-		if !testableListenArgs(tt.net, tt.laddr, "") {
-			t.Logf("skipping %s test", tt.net+" "+tt.laddr)
+		if skipServerTest(tt.net, "unix", tt.laddr, tt.ipv6, false, tt.linux) {
+			continue
+		}
+		if skipServerTest(tt.net, "unixpacket", tt.laddr, tt.ipv6, false, tt.linux) {
 			continue
 		}
 		testFileListener(t, tt.net, tt.laddr)
@@ -99,78 +107,86 @@ func TestFileListener(t *testing.T) {
 func testFilePacketConn(t *testing.T, pcf packetConnFile, listen bool) {
 	f, err := pcf.File()
 	if err != nil {
-		t.Fatal(err)
+		t.Fatalf("File failed: %v", err)
 	}
 	c, err := FilePacketConn(f)
 	if err != nil {
-		t.Fatal(err)
+		t.Fatalf("FilePacketConn failed: %v", err)
 	}
 	if !reflect.DeepEqual(pcf.LocalAddr(), c.LocalAddr()) {
-		t.Fatalf("got %#v; want %#v", pcf.LocalAddr(), c.LocalAddr())
+		t.Fatalf("LocalAddrs not equal: %#v != %#v", pcf.LocalAddr(), c.LocalAddr())
 	}
 	if listen {
 		if _, err := c.WriteTo([]byte{}, c.LocalAddr()); err != nil {
-			t.Fatal(err)
+			t.Fatalf("WriteTo failed: %v", err)
 		}
 	}
 	if err := c.Close(); err != nil {
-		t.Fatal(err)
+		t.Fatalf("Close failed: %v", err)
 	}
 	if err := f.Close(); err != nil {
-		t.Fatal(err)
+		t.Fatalf("Close failed: %v", err)
 	}
 }
 
 func testFilePacketConnListen(t *testing.T, net, laddr string) {
+	switch net {
+	case "udp", "udp4", "udp6":
+		laddr += ":0" // any available port
+	}
 	l, err := ListenPacket(net, laddr)
 	if err != nil {
-		t.Fatal(err)
+		t.Fatalf("ListenPacket failed: %v", err)
 	}
 	testFilePacketConn(t, l.(packetConnFile), true)
 	if err := l.Close(); err != nil {
-		t.Fatal(err)
+		t.Fatalf("Close failed: %v", err)
 	}
 }
 
 func testFilePacketConnDial(t *testing.T, net, raddr string) {
+	switch net {
+	case "udp", "udp4", "udp6":
+		raddr += ":12345"
+	}
 	c, err := Dial(net, raddr)
 	if err != nil {
-		t.Fatal(err)
+		t.Fatalf("Dial failed: %v", err)
 	}
 	testFilePacketConn(t, c.(packetConnFile), false)
 	if err := c.Close(); err != nil {
-		t.Fatal(err)
+		t.Fatalf("Close failed: %v", err)
 	}
 }
 
 var filePacketConnTests = []struct {
-	net  string
-	addr string
+	net   string
+	addr  string
+	ipv6  bool // test with underlying AF_INET6 socket
+	linux bool // test with abstract unix domain socket, a Linux-ism
 }{
-	{net: "udp", addr: "127.0.0.1:0"},
-	{net: "udp", addr: "[::ffff:127.0.0.1]:0"},
-	{net: "udp", addr: "[::1]:0"},
+	{net: "udp", addr: "127.0.0.1"},
+	{net: "udp", addr: "[::ffff:127.0.0.1]"},
+	{net: "udp", addr: "[::1]", ipv6: true},
 
-	{net: "udp4", addr: "127.0.0.1:0"},
-	{net: "udp4", addr: "[::ffff:127.0.0.1]:0"},
+	{net: "udp4", addr: "127.0.0.1"},
+	{net: "udp4", addr: "[::ffff:127.0.0.1]"},
 
-	{net: "udp6", addr: "[::1]:0"},
+	{net: "udp6", addr: "[::1]", ipv6: true},
 
-	// TODO(mikioh,bradfitz): reenable once 10730 is fixed
-	// {net: "ip4:icmp", addr: "127.0.0.1"},
+	{net: "ip4:icmp", addr: "127.0.0.1"},
 
-	{net: "unixgram", addr: "@gotest3/net"},
+	{net: "unixgram", addr: "@gotest3/net", linux: true},
 }
 
 func TestFilePacketConn(t *testing.T) {
 	switch runtime.GOOS {
 	case "nacl", "plan9", "windows":
-		t.Skipf("not supported on %s", runtime.GOOS)
+		t.Skipf("skipping test on %q", runtime.GOOS)
 	}
 
 	for _, tt := range filePacketConnTests {
-		if !testableListenArgs(tt.net, tt.addr, "") {
-			t.Logf("skipping %s test", tt.net+" "+tt.addr)
+		if skipServerTest(tt.net, "unixgram", tt.addr, tt.ipv6, false, tt.linux) {
 			continue
 		}
 		if os.Getuid() != 0 && tt.net == "ip4:icmp" {
@@ -178,16 +194,12 @@ func TestFilePacketConn(t *testing.T) {
 			continue
 		}
 		testFilePacketConnListen(t, tt.net, tt.addr)
-		switch tt.net {
-		case "udp", "udp4", "udp6":
-			host, _, err := SplitHostPort(tt.addr)
-			if err != nil {
-				t.Error(err)
-				continue
+		switch tt.addr {
+		case "", "0.0.0.0", "[::ffff:0.0.0.0]", "[::]":
+		default:
+			if tt.net != "unixgram" {
+				testFilePacketConnDial(t, tt.net, tt.addr)
 			}
-			testFilePacketConnDial(t, tt.net, JoinHostPort(host, "12345"))
-		case "ip4:icmp":
-			testFilePacketConnDial(t, tt.net, tt.addr)
 		}
 	}
 }
diff --git a/src/net/file_unix.go b/src/net/file_unix.go
index 5b24c7d..214a419 100644
--- a/src/net/file_unix.go
+++ b/src/net/file_unix.go
@@ -11,59 +11,75 @@ import (
 	"syscall"
 )
 
-func dupSocket(f *os.File) (int, error) {
-	s, err := dupCloseOnExec(int(f.Fd()))
+func newFileFD(f *os.File) (*netFD, error) {
+	fd, err := dupCloseOnExec(int(f.Fd()))
 	if err != nil {
-		return -1, err
-	}
-	if err := syscall.SetNonblock(s, true); err != nil {
-		closeFunc(s)
-		return -1, os.NewSyscallError("setnonblock", err)
+		return nil, os.NewSyscallError("dup", err)
 	}
-	return s, nil
-}
 
-func newFileFD(f *os.File) (*netFD, error) {
-	s, err := dupSocket(f)
-	if err != nil {
+	if err = syscall.SetNonblock(fd, true); err != nil {
+		closesocket(fd)
 		return nil, err
 	}
-	family := syscall.AF_UNSPEC
-	sotype, err := syscall.GetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_TYPE)
+
+	sotype, err := syscall.GetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_TYPE)
 	if err != nil {
-		closeFunc(s)
+		closesocket(fd)
 		return nil, os.NewSyscallError("getsockopt", err)
 	}
-	lsa, _ := syscall.Getsockname(s)
-	rsa, _ := syscall.Getpeername(s)
+
+	family := syscall.AF_UNSPEC
+	toAddr := sockaddrToTCP
+	lsa, _ := syscall.Getsockname(fd)
 	switch lsa.(type) {
+	default:
+		closesocket(fd)
+		return nil, syscall.EINVAL
 	case *syscall.SockaddrInet4:
 		family = syscall.AF_INET
+		if sotype == syscall.SOCK_DGRAM {
+			toAddr = sockaddrToUDP
+		} else if sotype == syscall.SOCK_RAW {
+			toAddr = sockaddrToIP
+		}
 	case *syscall.SockaddrInet6:
 		family = syscall.AF_INET6
+		if sotype == syscall.SOCK_DGRAM {
+			toAddr = sockaddrToUDP
+		} else if sotype == syscall.SOCK_RAW {
+			toAddr = sockaddrToIP
+		}
 	case *syscall.SockaddrUnix:
 		family = syscall.AF_UNIX
-	default:
-		closeFunc(s)
-		return nil, syscall.EPROTONOSUPPORT
+		toAddr = sockaddrToUnix
+		if sotype == syscall.SOCK_DGRAM {
+			toAddr = sockaddrToUnixgram
+		} else if sotype == syscall.SOCK_SEQPACKET {
+			toAddr = sockaddrToUnixpacket
+		}
 	}
-	fd, err := newFD(s, family, sotype, "")
+	laddr := toAddr(lsa)
+	rsa, _ := syscall.Getpeername(fd)
+	raddr := toAddr(rsa)
+
+	netfd, err := newFD(fd, family, sotype, laddr.Network())
 	if err != nil {
-		closeFunc(s)
+		closesocket(fd)
 		return nil, err
 	}
-	laddr := fd.addrFunc()(lsa)
-	raddr := fd.addrFunc()(rsa)
-	fd.net = laddr.Network()
-	if err := fd.init(); err != nil {
-		fd.Close()
+	if err := netfd.init(); err != nil {
+		netfd.Close()
 		return nil, err
 	}
-	fd.setAddr(laddr, raddr)
-	return fd, nil
+	netfd.setAddr(laddr, raddr)
+	return netfd, nil
 }
 
-func fileConn(f *os.File) (Conn, error) {
+// FileConn returns a copy of the network connection corresponding to
+// the open file f.  It is the caller's responsibility to close f when
+// finished.  Closing c does not affect f, and closing f does not
+// affect c.
+func FileConn(f *os.File) (c Conn, err error) {
 	fd, err := newFileFD(f)
 	if err != nil {
 		return nil, err
@@ -82,7 +98,11 @@ func fileConn(f *os.File) (Conn, error) {
 	return nil, syscall.EINVAL
 }
 
-func fileListener(f *os.File) (Listener, error) {
+// FileListener returns a copy of the network listener corresponding
+// to the open file f.  It is the caller's responsibility to close l
+// when finished.  Closing l does not affect f, and closing f does not
+// affect l.
+func FileListener(f *os.File) (l Listener, err error) {
 	fd, err := newFileFD(f)
 	if err != nil {
 		return nil, err
@@ -97,7 +117,11 @@ func fileListener(f *os.File) (Listener, error) {
 	return nil, syscall.EINVAL
 }
 
-func filePacketConn(f *os.File) (PacketConn, error) {
+// FilePacketConn returns a copy of the packet network connection
+// corresponding to the open file f.  It is the caller's
+// responsibility to close f when finished.  Closing c does not affect
+// f, and closing f does not affect c.
+func FilePacketConn(f *os.File) (c PacketConn, err error) {
 	fd, err := newFileFD(f)
 	if err != nil {
 		return nil, err
diff --git a/src/net/file_windows.go b/src/net/file_windows.go
index 241fa17..ca2b9b2 100644
--- a/src/net/file_windows.go
+++ b/src/net/file_windows.go
@@ -9,17 +9,29 @@ import (
 	"syscall"
 )
 
-func fileConn(f *os.File) (Conn, error) {
+// FileConn returns a copy of the network connection corresponding to
+// the open file f.  It is the caller's responsibility to close f when
+// finished.  Closing c does not affect f, and closing f does not
+// affect c.
+func FileConn(f *os.File) (c Conn, err error) {
 	// TODO: Implement this
-	return nil, syscall.EWINDOWS
+	return nil, os.NewSyscallError("FileConn", syscall.EWINDOWS)
 }
 
-func fileListener(f *os.File) (Listener, error) {
+// FileListener returns a copy of the network listener corresponding
+// to the open file f.  It is the caller's responsibility to close l
+// when finished.  Closing l does not affect f, and closing f does not
+// affect l.
+func FileListener(f *os.File) (l Listener, err error) {
 	// TODO: Implement this
-	return nil, syscall.EWINDOWS
+	return nil, os.NewSyscallError("FileListener", syscall.EWINDOWS)
 }
 
-func filePacketConn(f *os.File) (PacketConn, error) {
+// FilePacketConn returns a copy of the packet network connection
+// corresponding to the open file f.  It is the caller's
+// responsibility to close f when finished.  Closing c does not affect
+// f, and closing f does not affect c.
+func FilePacketConn(f *os.File) (c PacketConn, err error) {
 	// TODO: Implement this
-	return nil, syscall.EWINDOWS
+	return nil, os.NewSyscallError("FilePacketConn", syscall.EWINDOWS)
 }
diff --git a/src/net/hosts.go b/src/net/hosts.go
index 27958c7..9400503 100644
--- a/src/net/hosts.go
+++ b/src/net/hosts.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.
 
+// Read static host/IP entries from /etc/hosts.
+
 package net
 
 import (
@@ -11,21 +13,8 @@ import (
 
 const cacheMaxAge = 5 * time.Minute
 
-func parseLiteralIP(addr string) string {
-	var ip IP
-	var zone string
-	ip = parseIPv4(addr)
-	if ip == nil {
-		ip, zone = parseIPv6(addr, true)
-	}
-	if ip == nil {
-		return ""
-	}
-	if zone == "" {
-		return ip.String()
-	}
-	return ip.String() + "%" + zone
-}
+// hostsPath points to the file with static IP/address entries.
+var hostsPath = "/etc/hosts"
 
 // Simple cache.
 var hosts struct {
@@ -38,7 +27,7 @@ var hosts struct {
 
 func readHosts() {
 	now := time.Now()
-	hp := testHookHostsPath
+	hp := hostsPath
 	if len(hosts.byName) == 0 || now.After(hosts.expire) || hosts.path != hp {
 		hs := make(map[string][]string)
 		is := make(map[string][]string)
@@ -52,17 +41,13 @@ func readHosts() {
 				line = line[0:i]
 			}
 			f := getFields(line)
-			if len(f) < 2 {
-				continue
-			}
-			addr := parseLiteralIP(f[0])
-			if addr == "" {
+			if len(f) < 2 || ParseIP(f[0]) == nil {
 				continue
 			}
 			for i := 1; i < len(f); i++ {
 				h := f[i]
-				hs[h] = append(hs[h], addr)
-				is[addr] = append(is[addr], h)
+				hs[h] = append(hs[h], f[0])
+				is[f[0]] = append(is[f[0]], h)
 			}
 		}
 		// Update the data cache.
@@ -92,10 +77,6 @@ func lookupStaticAddr(addr string) []string {
 	hosts.Lock()
 	defer hosts.Unlock()
 	readHosts()
-	addr = parseLiteralIP(addr)
-	if addr == "" {
-		return nil
-	}
 	if len(hosts.byAddr) != 0 {
 		if hosts, ok := hosts.byAddr[addr]; ok {
 			return hosts
diff --git a/src/net/hosts_test.go b/src/net/hosts_test.go
index aca64c3..2fe358e 100644
--- a/src/net/hosts_test.go
+++ b/src/net/hosts_test.go
@@ -5,116 +5,77 @@
 package net
 
 import (
-	"reflect"
+	"sort"
 	"testing"
 )
 
-type staticHostEntry struct {
-	in  string
-	out []string
+type hostTest struct {
+	host string
+	ips  []IP
 }
 
-var lookupStaticHostTests = []struct {
-	name string
-	ents []staticHostEntry
-}{
-	{
-		"testdata/hosts",
-		[]staticHostEntry{
-			{"odin", []string{"127.0.0.2", "127.0.0.3", "::2"}},
-			{"thor", []string{"127.1.1.1"}},
-			{"ullr", []string{"127.1.1.2"}},
-			{"ullrhost", []string{"127.1.1.2"}},
-			{"localhost", []string{"fe80::1%lo0"}},
-		},
-	},
-	{
-		"testdata/singleline-hosts", // see golang.org/issue/6646
-		[]staticHostEntry{
-			{"odin", []string{"127.0.0.2"}},
-		},
-	},
-	{
-		"testdata/ipv4-hosts", // see golang.org/issue/8996
-		[]staticHostEntry{
-			{"localhost", []string{"127.0.0.1", "127.0.0.2", "127.0.0.3"}},
-			{"localhost.localdomain", []string{"127.0.0.3"}},
-		},
-	},
-	{
-		"testdata/ipv6-hosts", // see golang.org/issue/8996
-		[]staticHostEntry{
-			{"localhost", []string{"::1", "fe80::1", "fe80::2%lo0", "fe80::3%lo0"}},
-			{"localhost.localdomain", []string{"fe80::3%lo0"}},
-		},
-	},
+var hosttests = []hostTest{
+	{"odin", []IP{
+		IPv4(127, 0, 0, 2),
+		IPv4(127, 0, 0, 3),
+		ParseIP("::2"),
+	}},
+	{"thor", []IP{
+		IPv4(127, 1, 1, 1),
+	}},
+	{"loki", []IP{}},
+	{"ullr", []IP{
+		IPv4(127, 1, 1, 2),
+	}},
+	{"ullrhost", []IP{
+		IPv4(127, 1, 1, 2),
+	}},
 }
 
 func TestLookupStaticHost(t *testing.T) {
-	defer func(orig string) { testHookHostsPath = orig }(testHookHostsPath)
-
-	for _, tt := range lookupStaticHostTests {
-		testHookHostsPath = tt.name
-		for _, ent := range tt.ents {
-			addrs := lookupStaticHost(ent.in)
-			if !reflect.DeepEqual(addrs, ent.out) {
-				t.Errorf("%s, lookupStaticHost(%s) = %v; want %v", tt.name, ent.in, addrs, ent.out)
+	p := hostsPath
+	hostsPath = "testdata/hosts"
+	for i := 0; i < len(hosttests); i++ {
+		tt := hosttests[i]
+		ips := lookupStaticHost(tt.host)
+		if len(ips) != len(tt.ips) {
+			t.Errorf("# of hosts = %v; want %v",
+				len(ips), len(tt.ips))
+			continue
+		}
+		for k, v := range ips {
+			if tt.ips[k].String() != v {
+				t.Errorf("lookupStaticHost(%q) = %v; want %v",
+					tt.host, v, tt.ips[k])
 			}
 		}
 	}
+	hostsPath = p
 }
 
-var lookupStaticAddrTests = []struct {
-	name string
-	ents []staticHostEntry
-}{
-	{
-		"testdata/hosts",
-		[]staticHostEntry{
-			{"255.255.255.255", []string{"broadcasthost"}},
-			{"127.0.0.2", []string{"odin"}},
-			{"127.0.0.3", []string{"odin"}},
-			{"::2", []string{"odin"}},
-			{"127.1.1.1", []string{"thor"}},
-			{"127.1.1.2", []string{"ullr", "ullrhost"}},
-			{"fe80::1%lo0", []string{"localhost"}},
-		},
-	},
-	{
-		"testdata/singleline-hosts", // see golang.org/issue/6646
-		[]staticHostEntry{
-			{"127.0.0.2", []string{"odin"}},
-		},
-	},
-	{
-		"testdata/ipv4-hosts", // see golang.org/issue/8996
-		[]staticHostEntry{
-			{"127.0.0.1", []string{"localhost"}},
-			{"127.0.0.2", []string{"localhost"}},
-			{"127.0.0.3", []string{"localhost", "localhost.localdomain"}},
-		},
-	},
-	{
-		"testdata/ipv6-hosts", // see golang.org/issue/8996
-		[]staticHostEntry{
-			{"::1", []string{"localhost"}},
-			{"fe80::1", []string{"localhost"}},
-			{"fe80::2%lo0", []string{"localhost"}},
-			{"fe80::3%lo0", []string{"localhost", "localhost.localdomain"}},
-		},
-	},
-}
+// https://code.google.com/p/go/issues/detail?id=6646
+func TestSingleLineHostsFile(t *testing.T) {
+	p := hostsPath
+	hostsPath = "testdata/hosts_singleline"
 
-func TestLookupStaticAddr(t *testing.T) {
-	defer func(orig string) { testHookHostsPath = orig }(testHookHostsPath)
+	ips := lookupStaticHost("odin")
+	if len(ips) != 1 || ips[0] != "127.0.0.2" {
+		t.Errorf("lookupStaticHost = %v, want %v", ips, []string{"127.0.0.2"})
+	}
 
-	for _, tt := range lookupStaticAddrTests {
-		testHookHostsPath = tt.name
-		for _, ent := range tt.ents {
-			hosts := lookupStaticAddr(ent.in)
-			if !reflect.DeepEqual(hosts, ent.out) {
-				t.Errorf("%s, lookupStaticAddr(%s) = %v; want %v", tt.name, ent.in, hosts, ent.out)
-			}
+	hostsPath = p
+}
+
+func TestLookupHost(t *testing.T) {
+	// Can't depend on this to return anything in particular,
+	// but if it does return something, make sure it doesn't
+	// duplicate addresses (a common bug due to the way
+	// getaddrinfo works).
+	addrs, _ := LookupHost("localhost")
+	sort.Strings(addrs)
+	for i := 0; i+1 < len(addrs); i++ {
+		if addrs[i] == addrs[i+1] {
+			t.Fatalf("LookupHost(\"localhost\") = %v, has duplicate addresses", addrs)
 		}
 	}
 }
diff --git a/src/net/http/cgi/child.go b/src/net/http/cgi/child.go
index ec10108..45fc2e5 100644
--- a/src/net/http/cgi/child.go
+++ b/src/net/http/cgi/child.go
@@ -132,9 +132,9 @@ func RequestFromMap(params map[string]string) (*http.Request, error) {
 	}
 
 	// Request.RemoteAddr has its port set by Go's standard http
-	// server, so we do here too.
-	remotePort, _ := strconv.Atoi(params["REMOTE_PORT"]) // zero if unset or invalid
-	r.RemoteAddr = net.JoinHostPort(params["REMOTE_ADDR"], strconv.Itoa(remotePort))
+	// server, so we do here too. We don't have one, though, so we
+	// use a dummy one.
+	r.RemoteAddr = net.JoinHostPort(params["REMOTE_ADDR"], "0")
 
 	return r, nil
 }
diff --git a/src/net/http/cgi/child_test.go b/src/net/http/cgi/child_test.go
index 14e0af4..075d841 100644
--- a/src/net/http/cgi/child_test.go
+++ b/src/net/http/cgi/child_test.go
@@ -22,7 +22,6 @@ func TestRequest(t *testing.T) {
 		"CONTENT_LENGTH":  "123",
 		"CONTENT_TYPE":    "text/xml",
 		"REMOTE_ADDR":     "5.6.7.8",
-		"REMOTE_PORT":     "54321",
 	}
 	req, err := RequestFromMap(env)
 	if err != nil {
@@ -61,7 +60,7 @@ func TestRequest(t *testing.T) {
 	if req.TLS != nil {
 		t.Errorf("expected nil TLS")
 	}
-	if e, g := "5.6.7.8:54321", req.RemoteAddr; e != g {
+	if e, g := "5.6.7.8:0", req.RemoteAddr; e != g {
 		t.Errorf("RemoteAddr: got %q; want %q", g, e)
 	}
 }
@@ -130,21 +129,3 @@ func TestRequestWithoutRequestURI(t *testing.T) {
 		t.Errorf("URL = %q; want %q", g, e)
 	}
 }
-
-func TestRequestWithoutRemotePort(t *testing.T) {
-	env := map[string]string{
-		"SERVER_PROTOCOL": "HTTP/1.1",
-		"HTTP_HOST":       "example.com",
-		"REQUEST_METHOD":  "GET",
-		"REQUEST_URI":     "/path?a=b",
-		"CONTENT_LENGTH":  "123",
-		"REMOTE_ADDR":     "5.6.7.8",
-	}
-	req, err := RequestFromMap(env)
-	if err != nil {
-		t.Fatalf("RequestFromMap: %v", err)
-	}
-	if e, g := "5.6.7.8:0", req.RemoteAddr; e != g {
-		t.Errorf("RemoteAddr: got %q; want %q", g, e)
-	}
-}
diff --git a/src/net/http/cgi/host.go b/src/net/http/cgi/host.go
index 4efbe7a..ec95a97 100644
--- a/src/net/http/cgi/host.go
+++ b/src/net/http/cgi/host.go
@@ -19,7 +19,6 @@ import (
 	"fmt"
 	"io"
 	"log"
-	"net"
 	"net/http"
 	"os"
 	"os/exec"
@@ -129,16 +128,11 @@ func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
 		"PATH_INFO=" + pathInfo,
 		"SCRIPT_NAME=" + root,
 		"SCRIPT_FILENAME=" + h.Path,
+		"REMOTE_ADDR=" + req.RemoteAddr,
+		"REMOTE_HOST=" + req.RemoteAddr,
 		"SERVER_PORT=" + port,
 	}
 
-	if remoteIP, remotePort, err := net.SplitHostPort(req.RemoteAddr); err == nil {
-		env = append(env, "REMOTE_ADDR="+remoteIP, "REMOTE_HOST="+remoteIP, "REMOTE_PORT="+remotePort)
-	} else {
-		// could not parse ip:port, let's use whole RemoteAddr and leave REMOTE_PORT undefined
-		env = append(env, "REMOTE_ADDR="+req.RemoteAddr, "REMOTE_HOST="+req.RemoteAddr)
-	}
-
 	if req.TLS != nil {
 		env = append(env, "HTTPS=on")
 	}
diff --git a/src/net/http/cgi/host_test.go b/src/net/http/cgi/host_test.go
index 4aa67e4..8c16e68 100644
--- a/src/net/http/cgi/host_test.go
+++ b/src/net/http/cgi/host_test.go
@@ -29,7 +29,7 @@ func newRequest(httpreq string) *http.Request {
 	if err != nil {
 		panic("cgi: bogus http request in test: " + httpreq)
 	}
-	req.RemoteAddr = "1.2.3.4:1234"
+	req.RemoteAddr = "1.2.3.4"
 	return req
 }
 
@@ -37,11 +37,7 @@ func runCgiTest(t *testing.T, h *Handler, httpreq string, expectedMap map[string
 	rw := httptest.NewRecorder()
 	req := newRequest(httpreq)
 	h.ServeHTTP(rw, req)
-	runResponseChecks(t, rw, expectedMap)
-	return rw
-}
 
-func runResponseChecks(t *testing.T, rw *httptest.ResponseRecorder, expectedMap map[string]string) {
 	// Make a map to hold the test map that the CGI returns.
 	m := make(map[string]string)
 	m["_body"] = rw.Body.String()
@@ -79,6 +75,7 @@ readlines:
 			t.Errorf("for key %q got %q; expected %q", key, got, expected)
 		}
 	}
+	return rw
 }
 
 var cgiTested, cgiWorks bool
@@ -111,7 +108,6 @@ func TestCGIBasicGet(t *testing.T) {
 		"env-QUERY_STRING":      "foo=bar&a=b",
 		"env-REMOTE_ADDR":       "1.2.3.4",
 		"env-REMOTE_HOST":       "1.2.3.4",
-		"env-REMOTE_PORT":       "1234",
 		"env-REQUEST_METHOD":    "GET",
 		"env-REQUEST_URI":       "/test.cgi?foo=bar&a=b",
 		"env-SCRIPT_FILENAME":   "testdata/test.cgi",
@@ -130,39 +126,6 @@ func TestCGIBasicGet(t *testing.T) {
 	}
 }
 
-func TestCGIEnvIPv6(t *testing.T) {
-	check(t)
-	h := &Handler{
-		Path: "testdata/test.cgi",
-		Root: "/test.cgi",
-	}
-	expectedMap := map[string]string{
-		"test":                  "Hello CGI",
-		"param-a":               "b",
-		"param-foo":             "bar",
-		"env-GATEWAY_INTERFACE": "CGI/1.1",
-		"env-HTTP_HOST":         "example.com",
-		"env-PATH_INFO":         "",
-		"env-QUERY_STRING":      "foo=bar&a=b",
-		"env-REMOTE_ADDR":       "2000::3000",
-		"env-REMOTE_HOST":       "2000::3000",
-		"env-REMOTE_PORT":       "12345",
-		"env-REQUEST_METHOD":    "GET",
-		"env-REQUEST_URI":       "/test.cgi?foo=bar&a=b",
-		"env-SCRIPT_FILENAME":   "testdata/test.cgi",
-		"env-SCRIPT_NAME":       "/test.cgi",
-		"env-SERVER_NAME":       "example.com",
-		"env-SERVER_PORT":       "80",
-		"env-SERVER_SOFTWARE":   "go",
-	}
-
-	rw := httptest.NewRecorder()
-	req := newRequest("GET /test.cgi?foo=bar&a=b HTTP/1.0\nHost: example.com\n\n")
-	req.RemoteAddr = "[2000::3000]:12345"
-	h.ServeHTTP(rw, req)
-	runResponseChecks(t, rw, expectedMap)
-}
-
 func TestCGIBasicGetAbsPath(t *testing.T) {
 	check(t)
 	pwd, err := os.Getwd()
@@ -326,7 +289,7 @@ func TestInternalRedirect(t *testing.T) {
 	}
 	expectedMap := map[string]string{
 		"basepath":   "/foo",
-		"remoteaddr": "1.2.3.4:1234",
+		"remoteaddr": "1.2.3.4",
 	}
 	runCgiTest(t, h, "GET /test.cgi?loc=/foo HTTP/1.0\nHost: example.com\n\n", expectedMap)
 }
diff --git a/src/net/http/cgi/matryoshka_test.go b/src/net/http/cgi/matryoshka_test.go
index 32d59c0..18c4803 100644
--- a/src/net/http/cgi/matryoshka_test.go
+++ b/src/net/http/cgi/matryoshka_test.go
@@ -12,11 +12,11 @@ import (
 	"bytes"
 	"errors"
 	"fmt"
-	"internal/testenv"
 	"io"
 	"net/http"
 	"net/http/httptest"
 	"os"
+	"runtime"
 	"testing"
 	"time"
 )
@@ -24,7 +24,9 @@ import (
 // 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) {
-	testenv.MustHaveExec(t)
+	if runtime.GOOS == "nacl" {
+		t.Skip("skipping on nacl")
+	}
 
 	h := &Handler{
 		Path: os.Args[0],
@@ -41,7 +43,6 @@ func TestHostingOurselves(t *testing.T) {
 		"env-QUERY_STRING":      "foo=bar&a=b",
 		"env-REMOTE_ADDR":       "1.2.3.4",
 		"env-REMOTE_HOST":       "1.2.3.4",
-		"env-REMOTE_PORT":       "1234",
 		"env-REQUEST_METHOD":    "GET",
 		"env-REQUEST_URI":       "/test.go?foo=bar&a=b",
 		"env-SCRIPT_FILENAME":   os.Args[0],
@@ -91,7 +92,9 @@ func (w *limitWriter) Write(p []byte) (n int, err error) {
 // If there's an error copying the child's output to the parent, test
 // that we kill the child.
 func TestKillChildAfterCopyError(t *testing.T) {
-	testenv.MustHaveExec(t)
+	if runtime.GOOS == "nacl" {
+		t.Skip("skipping on nacl")
+	}
 
 	defer func() { testHookStartProcess = nil }()
 	proc := make(chan *os.Process, 1)
@@ -136,7 +139,9 @@ func TestKillChildAfterCopyError(t *testing.T) {
 // Test that a child handler writing only headers works.
 // golang.org/issue/7196
 func TestChildOnlyHeaders(t *testing.T) {
-	testenv.MustHaveExec(t)
+	if runtime.GOOS == "nacl" {
+		t.Skip("skipping on nacl")
+	}
 
 	h := &Handler{
 		Path: os.Args[0],
diff --git a/src/net/http/cgi/testdata/test.cgi b/src/net/http/cgi/testdata/test.cgi
index ec7ee6f..3214df6 100755
--- a/src/net/http/cgi/testdata/test.cgi
+++ b/src/net/http/cgi/testdata/test.cgi
@@ -45,7 +45,7 @@ foreach my $k (sort keys %ENV) {
 
 # NOTE: msys perl returns /c/go/src/... not C:\go\....
 my $dir = getcwd();
-if ($^O eq 'MSWin32' || $^O eq 'msys' || $^O eq 'cygwin') {
+if ($^O eq 'MSWin32' || $^O eq 'msys') {
     if ($dir =~ /^.:/) {
         $dir =~ s!/!\\!g;
     } else {
diff --git a/src/net/http/client.go b/src/net/http/client.go
index 7f2fbb4..ce884d1 100644
--- a/src/net/http/client.go
+++ b/src/net/http/client.go
@@ -19,7 +19,6 @@ import (
 	"net/url"
 	"strings"
 	"sync"
-	"sync/atomic"
 	"time"
 )
 
@@ -212,7 +211,7 @@ func send(req *Request, t RoundTripper) (resp *Response, err error) {
 		req.Header = make(Header)
 	}
 
-	if u := req.URL.User; u != nil && req.Header.Get("Authorization") == "" {
+	if u := req.URL.User; u != nil {
 		username := u.Username()
 		password, _ := u.Password()
 		req.Header.Set("Authorization", "Basic "+basicAuth(username, password))
@@ -257,9 +256,8 @@ func shouldRedirectPost(statusCode int) bool {
 	return false
 }
 
-// Get issues a GET to the specified URL. If the response is one of
-// the following redirect codes, Get follows the redirect, up to a
-// maximum of 10 redirects:
+// Get issues a GET to the specified URL.  If the response is one of the following
+// redirect codes, Get follows the redirect, up to a maximum of 10 redirects:
 //
 //    301 (Moved Permanently)
 //    302 (Found)
@@ -274,16 +272,13 @@ func shouldRedirectPost(statusCode int) bool {
 // Caller should close resp.Body when done reading from it.
 //
 // Get is a wrapper around DefaultClient.Get.
-//
-// To make a request with custom headers, use NewRequest and
-// DefaultClient.Do.
 func Get(url string) (resp *Response, err error) {
 	return DefaultClient.Get(url)
 }
 
-// Get issues a GET to the specified URL. If the response is one of the
+// Get issues a GET to the specified URL.  If the response is one of the
 // following redirect codes, Get follows the redirect after calling the
-// Client's CheckRedirect function:
+// Client's CheckRedirect function.
 //
 //    301 (Moved Permanently)
 //    302 (Found)
@@ -296,8 +291,6 @@ func Get(url string) (resp *Response, err error) {
 //
 // When err is nil, resp always contains a non-nil resp.Body.
 // Caller should close resp.Body when done reading from it.
-//
-// To make a request with custom headers, use NewRequest and Client.Do.
 func (c *Client) Get(url string) (resp *Response, err error) {
 	req, err := NewRequest("GET", url, nil)
 	if err != nil {
@@ -306,8 +299,6 @@ func (c *Client) Get(url string) (resp *Response, err error) {
 	return c.doFollowingRedirects(req, shouldRedirectGet)
 }
 
-func alwaysFalse() bool { return false }
-
 func (c *Client) doFollowingRedirects(ireq *Request, shouldRedirect func(int) bool) (resp *Response, err error) {
 	var base *url.URL
 	redirectChecker := c.CheckRedirect
@@ -325,10 +316,7 @@ func (c *Client) doFollowingRedirects(ireq *Request, shouldRedirect func(int) bo
 	req := ireq
 
 	var timer *time.Timer
-	var atomicWasCanceled int32 // atomic bool (1 or 0)
-	var wasCanceled = alwaysFalse
 	if c.Timeout > 0 {
-		wasCanceled = func() bool { return atomic.LoadInt32(&atomicWasCanceled) != 0 }
 		type canceler interface {
 			CancelRequest(*Request)
 		}
@@ -337,7 +325,6 @@ func (c *Client) doFollowingRedirects(ireq *Request, shouldRedirect func(int) bo
 			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() {
-			atomic.StoreInt32(&atomicWasCanceled, 1)
 			reqmu.Lock()
 			defer reqmu.Unlock()
 			tr.CancelRequest(req)
@@ -378,12 +365,6 @@ func (c *Client) doFollowingRedirects(ireq *Request, shouldRedirect func(int) bo
 
 		urlStr = req.URL.String()
 		if resp, err = c.send(req); err != nil {
-			if wasCanceled() {
-				err = &httpError{
-					err:     err.Error() + " (Client.Timeout exceeded while awaiting headers)",
-					timeout: true,
-				}
-			}
 			break
 		}
 
@@ -396,7 +377,7 @@ func (c *Client) doFollowingRedirects(ireq *Request, shouldRedirect func(int) bo
 			}
 			resp.Body.Close()
 			if urlStr = resp.Header.Get("Location"); urlStr == "" {
-				err = fmt.Errorf("%d response missing Location header", resp.StatusCode)
+				err = errors.New(fmt.Sprintf("%d response missing Location header", resp.StatusCode))
 				break
 			}
 			base = req.URL
@@ -404,11 +385,7 @@ func (c *Client) doFollowingRedirects(ireq *Request, shouldRedirect func(int) bo
 			continue
 		}
 		if timer != nil {
-			resp.Body = &cancelTimerBody{
-				t:              timer,
-				rc:             resp.Body,
-				reqWasCanceled: wasCanceled,
-			}
+			resp.Body = &cancelTimerBody{timer, resp.Body}
 		}
 		return resp, nil
 	}
@@ -423,7 +400,7 @@ func (c *Client) doFollowingRedirects(ireq *Request, shouldRedirect func(int) bo
 	if redirectFailed {
 		// Special case for Go 1 compatibility: return both the response
 		// and an error if the CheckRedirect function failed.
-		// See https://golang.org/issue/3795
+		// See http://golang.org/issue/3795
 		return resp, urlErr
 	}
 
@@ -444,12 +421,7 @@ func defaultCheckRedirect(req *Request, via []*Request) error {
 //
 // Caller should close resp.Body when done reading from it.
 //
-// If the provided body is an io.Closer, it is closed after the
-// request.
-//
-// Post is a wrapper around DefaultClient.Post.
-//
-// To set custom headers, use NewRequest and DefaultClient.Do.
+// Post is a wrapper around DefaultClient.Post
 func Post(url string, bodyType string, body io.Reader) (resp *Response, err error) {
 	return DefaultClient.Post(url, bodyType, body)
 }
@@ -458,10 +430,8 @@ 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 an io.Closer, it is closed after the
+// If the provided body is also an io.Closer, it is closed after the
 // request.
-//
-// To set custom headers, use NewRequest and Client.Do.
 func (c *Client) Post(url string, bodyType string, body io.Reader) (resp *Response, err error) {
 	req, err := NewRequest("POST", url, body)
 	if err != nil {
@@ -474,22 +444,16 @@ func (c *Client) Post(url string, bodyType string, body io.Reader) (resp *Respon
 // PostForm issues a POST to the specified URL, with data's keys and
 // values URL-encoded as the request body.
 //
-// The Content-Type header is set to application/x-www-form-urlencoded.
-// To set other headers, use NewRequest and DefaultClient.Do.
-//
 // When err is nil, resp always contains a non-nil resp.Body.
 // Caller should close resp.Body when done reading from it.
 //
-// PostForm is a wrapper around DefaultClient.PostForm.
+// PostForm is a wrapper around DefaultClient.PostForm
 func PostForm(url string, data url.Values) (resp *Response, err error) {
 	return DefaultClient.PostForm(url, data)
 }
 
 // PostForm issues a POST to the specified URL,
-// with data's keys and values URL-encoded as the request body.
-//
-// The Content-Type header is set to application/x-www-form-urlencoded.
-// To set other headers, use NewRequest and DefaultClient.Do.
+// with data's keys and values urlencoded as the request body.
 //
 // When err is nil, resp always contains a non-nil resp.Body.
 // Caller should close resp.Body when done reading from it.
@@ -497,9 +461,9 @@ func (c *Client) PostForm(url string, data url.Values) (resp *Response, err erro
 	return c.Post(url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode()))
 }
 
-// Head issues a HEAD to the specified URL.  If the response is one of
-// the following redirect codes, Head follows the redirect, up to a
-// maximum of 10 redirects:
+// Head issues a HEAD to the specified URL.  If the response is one of the
+// following redirect codes, Head follows the redirect after calling the
+// Client's CheckRedirect function.
 //
 //    301 (Moved Permanently)
 //    302 (Found)
@@ -513,7 +477,7 @@ func Head(url string) (resp *Response, err error) {
 
 // Head issues a HEAD to the specified URL.  If the response is one of the
 // following redirect codes, Head follows the redirect after calling the
-// Client's CheckRedirect function:
+// Client's CheckRedirect function.
 //
 //    301 (Moved Permanently)
 //    302 (Found)
@@ -527,25 +491,15 @@ func (c *Client) Head(url string) (resp *Response, err error) {
 	return c.doFollowingRedirects(req, shouldRedirectGet)
 }
 
-// cancelTimerBody is an io.ReadCloser that wraps rc with two features:
-// 1) on Read EOF or Close, the timer t is Stopped,
-// 2) On Read failure, if reqWasCanceled is true, the error is wrapped and
-//    marked as net.Error that hit its timeout.
 type cancelTimerBody struct {
-	t              *time.Timer
-	rc             io.ReadCloser
-	reqWasCanceled func() bool
+	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()
-	} else if err != nil && b.reqWasCanceled() {
-		return n, &httpError{
-			err:     err.Error() + " (Client.Timeout exceeded while reading body)",
-			timeout: true,
-		}
 	}
 	return
 }
diff --git a/src/net/http/client_test.go b/src/net/http/client_test.go
index 7b524d3..56b6563 100644
--- a/src/net/http/client_test.go
+++ b/src/net/http/client_test.go
@@ -258,7 +258,7 @@ func TestClientRedirects(t *testing.T) {
 		t.Errorf("with redirects forbidden, expected a *url.Error with our 'no redirects allowed' error inside; got %#v (%q)", err, err)
 	}
 	if res == nil {
-		t.Fatalf("Expected a non-nil Response on CheckRedirect failure (https://golang.org/issue/3795)")
+		t.Fatalf("Expected a non-nil Response on CheckRedirect failure (http://golang.org/issue/3795)")
 	}
 	res.Body.Close()
 	if res.Header.Get("Location") == "" {
@@ -334,7 +334,6 @@ var echoCookiesRedirectHandler = HandlerFunc(func(w ResponseWriter, r *Request)
 })
 
 func TestClientSendsCookieFromJar(t *testing.T) {
-	defer afterTest(t)
 	tr := &recordingTransport{}
 	client := &Client{Transport: tr}
 	client.Jar = &TestJar{perURL: make(map[string][]*Cookie)}
@@ -427,7 +426,7 @@ func TestJarCalls(t *testing.T) {
 	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
 		pathSuffix := r.RequestURI[1:]
 		if r.RequestURI == "/nosetcookie" {
-			return // don't set cookies for this path
+			return // dont set cookies for this path
 		}
 		SetCookie(w, &Cookie{Name: "name" + pathSuffix, Value: "val" + pathSuffix})
 		if r.RequestURI == "/" {
@@ -739,7 +738,7 @@ func TestResponseSetsTLSConnectionState(t *testing.T) {
 	}
 }
 
-// Verify Response.ContentLength is populated. https://golang.org/issue/4126
+// Verify Response.ContentLength is populated. http://golang.org/issue/4126
 func TestClientHeadContentLength(t *testing.T) {
 	defer afterTest(t)
 	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
@@ -843,47 +842,6 @@ func TestBasicAuth(t *testing.T) {
 	}
 }
 
-func TestBasicAuthHeadersPreserved(t *testing.T) {
-	defer afterTest(t)
-	tr := &recordingTransport{}
-	client := &Client{Transport: tr}
-
-	// If Authorization header is provided, username in URL should not override it
-	url := "http://My%20User@dummy.faketld/"
-	req, err := NewRequest("GET", url, nil)
-	if err != nil {
-		t.Fatal(err)
-	}
-	req.SetBasicAuth("My User", "My Pass")
-	expected := "My User:My Pass"
-	client.Do(req)
-
-	if tr.req.Method != "GET" {
-		t.Errorf("got method %q, want %q", tr.req.Method, "GET")
-	}
-	if tr.req.URL.String() != url {
-		t.Errorf("got URL %q, want %q", tr.req.URL.String(), url)
-	}
-	if tr.req.Header == nil {
-		t.Fatalf("expected non-nil request Header")
-	}
-	auth := tr.req.Header.Get("Authorization")
-	if strings.HasPrefix(auth, "Basic ") {
-		encoded := auth[6:]
-		decoded, err := base64.StdEncoding.DecodeString(encoded)
-		if err != nil {
-			t.Fatal(err)
-		}
-		s := string(decoded)
-		if expected != s {
-			t.Errorf("Invalid Authorization header. Got %q, wanted %q", s, expected)
-		}
-	} else {
-		t.Errorf("Invalid auth %q", auth)
-	}
-
-}
-
 func TestClientTimeout(t *testing.T) {
 	if testing.Short() {
 		t.Skip("skipping in short mode")
@@ -941,64 +899,14 @@ func TestClientTimeout(t *testing.T) {
 	select {
 	case err := <-errc:
 		if err == nil {
-			t.Fatal("expected error from ReadAll")
-		}
-		ne, ok := err.(net.Error)
-		if !ok {
-			t.Errorf("error value from ReadAll was %T; expected some net.Error", err)
-		} else if !ne.Timeout() {
-			t.Errorf("net.Error.Timeout = false; want true")
-		}
-		if got := ne.Error(); !strings.Contains(got, "Client.Timeout exceeded") {
-			t.Errorf("error string = %q; missing timeout substring", got)
+			t.Error("expected error from ReadAll")
 		}
+		// Expected error.
 	case <-time.After(failTime):
 		t.Errorf("timeout after %v waiting for timeout of %v", failTime, timeout)
 	}
 }
 
-// Client.Timeout firing before getting to the body
-func TestClientTimeout_Headers(t *testing.T) {
-	if testing.Short() {
-		t.Skip("skipping in short mode")
-	}
-	defer afterTest(t)
-	donec := make(chan bool)
-	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
-		<-donec
-	}))
-	defer ts.Close()
-	// Note that we use a channel send here and not a close.
-	// The race detector doesn't know that we're waiting for a timeout
-	// and thinks that the waitgroup inside httptest.Server is added to concurrently
-	// with us closing it. If we timed out immediately, we could close the testserver
-	// before we entered the handler. We're not timing out immediately and there's
-	// no way we would be done before we entered the handler, but the race detector
-	// doesn't know this, so synchronize explicitly.
-	defer func() { donec <- true }()
-
-	c := &Client{Timeout: 500 * time.Millisecond}
-
-	_, err := c.Get(ts.URL)
-	if err == nil {
-		t.Fatal("got response from Get; expected error")
-	}
-	ue, ok := err.(*url.Error)
-	if !ok {
-		t.Fatalf("Got error of type %T; want *url.Error", err)
-	}
-	ne, ok := ue.Err.(net.Error)
-	if !ok {
-		t.Fatalf("Got url.Error.Err of type %T; want some net.Error", err)
-	}
-	if !ne.Timeout() {
-		t.Error("net.Error.Timeout = false; want true")
-	}
-	if got := ne.Error(); !strings.Contains(got, "Client.Timeout exceeded") {
-		t.Errorf("error string = %q; missing timeout substring", got)
-	}
-}
-
 func TestClientRedirectEatsBody(t *testing.T) {
 	defer afterTest(t)
 	saw := make(chan string, 2)
@@ -1076,12 +984,24 @@ func TestClientTrailers(t *testing.T) {
 				r.Trailer.Get("Client-Trailer-B"))
 		}
 
-		// How handlers set Trailers: declare it ahead of time
-		// with the Trailer header, and then mutate the
-		// Header() of those values later, after the response
-		// has been written (we wrote to w above).
-		w.Header().Set("Server-Trailer-A", "valuea")
-		w.Header().Set("Server-Trailer-C", "valuec") // skipping 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()
 
diff --git a/src/net/http/cookie.go b/src/net/http/cookie.go
index 648709d..a0d0fdb 100644
--- a/src/net/http/cookie.go
+++ b/src/net/http/cookie.go
@@ -14,18 +14,19 @@ import (
 	"time"
 )
 
+// This implementation is done according to RFC 6265:
+//
+//    http://tools.ietf.org/html/rfc6265
+
 // A Cookie represents an HTTP cookie as sent in the Set-Cookie header of an
 // HTTP response or the Cookie header of an HTTP request.
-//
-// See http://tools.ietf.org/html/rfc6265 for details.
 type Cookie struct {
-	Name  string
-	Value string
-
-	Path       string    // optional
-	Domain     string    // optional
-	Expires    time.Time // optional
-	RawExpires string    // for reading cookies only
+	Name       string
+	Value      string
+	Path       string
+	Domain     string
+	Expires    time.Time
+	RawExpires string
 
 	// MaxAge=0 means no 'Max-Age' attribute specified.
 	// MaxAge<0 means delete cookie now, equivalently 'Max-Age: 0'
@@ -125,22 +126,14 @@ func readSetCookies(h Header) []*Cookie {
 }
 
 // SetCookie adds a Set-Cookie header to the provided ResponseWriter's headers.
-// The provided cookie must have a valid Name. Invalid cookies may be
-// silently dropped.
 func SetCookie(w ResponseWriter, cookie *Cookie) {
-	if v := cookie.String(); v != "" {
-		w.Header().Add("Set-Cookie", v)
-	}
+	w.Header().Add("Set-Cookie", cookie.String())
 }
 
 // String returns the serialization of the cookie for use in a Cookie
 // header (if only Name and Value are set) or a Set-Cookie response
 // header (if other fields are set).
-// If c is nil or c.Name is invalid, the empty string is returned.
 func (c *Cookie) String() string {
-	if c == nil || !isCookieNameValid(c.Name) {
-		return ""
-	}
 	var b bytes.Buffer
 	fmt.Fprintf(&b, "%s=%s", sanitizeCookieName(c.Name), sanitizeCookieValue(c.Value))
 	if len(c.Path) > 0 {
@@ -163,7 +156,7 @@ func (c *Cookie) String() string {
 		}
 	}
 	if c.Expires.Unix() > 0 {
-		fmt.Fprintf(&b, "; Expires=%s", c.Expires.UTC().Format(TimeFormat))
+		fmt.Fprintf(&b, "; Expires=%s", c.Expires.UTC().Format(time.RFC1123))
 	}
 	if c.MaxAge > 0 {
 		fmt.Fprintf(&b, "; Max-Age=%d", c.MaxAge)
@@ -304,7 +297,7 @@ func sanitizeCookieName(n string) string {
 // 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 https://golang.org/issue/7243 for the discussion.
+// See http://golang.org/issue/7243 for the discussion.
 func sanitizeCookieValue(v string) string {
 	v = sanitizeOrWarn("Cookie.Value", validCookieValueByte, v)
 	if len(v) == 0 {
@@ -366,8 +359,5 @@ func parseCookieValue(raw string, allowDoubleQuote bool) (string, bool) {
 }
 
 func isCookieNameValid(raw string) bool {
-	if raw == "" {
-		return false
-	}
 	return strings.IndexFunc(raw, isNotToken) < 0
 }
diff --git a/src/net/http/cookie_test.go b/src/net/http/cookie_test.go
index d474f31..98dc2fa 100644
--- a/src/net/http/cookie_test.go
+++ b/src/net/http/cookie_test.go
@@ -52,10 +52,6 @@ var writeSetCookiesTests = []struct {
 		&Cookie{Name: "cookie-8", Value: "eight", Domain: "::1"},
 		"cookie-8=eight",
 	},
-	{
-		&Cookie{Name: "cookie-9", Value: "expiring", Expires: time.Unix(1257894000, 0)},
-		"cookie-9=expiring; Expires=Tue, 10 Nov 2009 23:00:00 GMT",
-	},
 	// The "special" cookies have values containing commas or spaces which
 	// are disallowed by RFC 6265 but are common in the wild.
 	{
@@ -94,18 +90,6 @@ var writeSetCookiesTests = []struct {
 		&Cookie{Name: "empty-value", Value: ""},
 		`empty-value=`,
 	},
-	{
-		nil,
-		``,
-	},
-	{
-		&Cookie{Name: ""},
-		``,
-	},
-	{
-		&Cookie{Name: "\t"},
-		``,
-	},
 }
 
 func TestWriteSetCookies(t *testing.T) {
@@ -365,7 +349,7 @@ func TestSetCookieDoubleQuotes(t *testing.T) {
 		{Name: "quoted3", Value: "both"},
 	}
 	if len(got) != len(want) {
-		t.Fatalf("got %d cookies, want %d", len(got), len(want))
+		t.Fatal("got %d cookies, want %d", len(got), len(want))
 	}
 	for i, w := range want {
 		g := got[i]
diff --git a/src/net/http/example_test.go b/src/net/http/example_test.go
index 1774795..88b97d9 100644
--- a/src/net/http/example_test.go
+++ b/src/net/http/example_test.go
@@ -6,7 +6,6 @@ package http_test
 
 import (
 	"fmt"
-	"io"
 	"io/ioutil"
 	"log"
 	"net/http"
@@ -87,25 +86,3 @@ func ExampleServeMux_Handle() {
 		fmt.Fprintf(w, "Welcome to the home page!")
 	})
 }
-
-// HTTP Trailers are a set of key/value pairs like headers that come
-// after the HTTP response, instead of before.
-func ExampleResponseWriter_trailers() {
-	mux := http.NewServeMux()
-	mux.HandleFunc("/sendstrailers", func(w http.ResponseWriter, req *http.Request) {
-		// Before any call to WriteHeader or Write, declare
-		// the trailers you will set during the HTTP
-		// response. These three headers are actually sent in
-		// the trailer.
-		w.Header().Set("Trailer", "AtEnd1, AtEnd2")
-		w.Header().Add("Trailer", "AtEnd3")
-
-		w.Header().Set("Content-Type", "text/plain; charset=utf-8") // normal header
-		w.WriteHeader(http.StatusOK)
-
-		w.Header().Set("AtEnd1", "value 1")
-		io.WriteString(w, "This HTTP response has both headers before this text and trailers at the end.\n")
-		w.Header().Set("AtEnd2", "value 2")
-		w.Header().Set("AtEnd3", "value 3") // These will appear as trailers.
-	})
-}
diff --git a/src/net/http/export_test.go b/src/net/http/export_test.go
index 0457be5..87b6c07 100644
--- a/src/net/http/export_test.go
+++ b/src/net/http/export_test.go
@@ -10,17 +10,9 @@ package http
 import (
 	"net"
 	"net/url"
-	"sync"
 	"time"
 )
 
-func init() {
-	// We only want to pay for this cost during testing.
-	// When not under test, these values are always nil
-	// and never assigned to.
-	testHookMu = new(sync.Mutex)
-}
-
 func NewLoggingConn(baseName string, c net.Conn) net.Conn {
 	return newLoggingConn(baseName, c)
 }
@@ -86,20 +78,6 @@ func (t *Transport) PutIdleTestConn() bool {
 	})
 }
 
-func SetInstallConnClosedHook(f func()) {
-	testHookPersistConnClosedGotRes = f
-}
-
-func SetEnterRoundTripHook(f func()) {
-	testHookEnterRoundTrip = f
-}
-
-func SetReadLoopBeforeNextReadHook(f func()) {
-	testHookMu.Lock()
-	defer testHookMu.Unlock()
-	testHookReadLoopBeforeNextRead = f
-}
-
 func NewTestTimeoutHandler(handler Handler, ch <-chan time.Time) Handler {
 	f := func() <-chan time.Time {
 		return ch
@@ -128,5 +106,3 @@ func SetPendingDialHooks(before, after func()) {
 var ExportServerNewConn = (*Server).newConn
 
 var ExportCloseWriteAndWait = (*conn).closeWriteAndWait
-
-var ExportErrRequestCanceled = errRequestCanceled
diff --git a/src/net/http/fcgi/child.go b/src/net/http/fcgi/child.go
index da824ed..a3beaa3 100644
--- a/src/net/http/fcgi/child.go
+++ b/src/net/http/fcgi/child.go
@@ -144,7 +144,6 @@ func newChild(rwc io.ReadWriteCloser, handler http.Handler) *child {
 
 func (c *child) serve() {
 	defer c.conn.Close()
-	defer c.cleanUp()
 	var rec record
 	for {
 		if err := rec.read(c.conn.rwc); err != nil {
@@ -160,14 +159,6 @@ var errCloseConn = errors.New("fcgi: connection should be closed")
 
 var emptyBody = ioutil.NopCloser(strings.NewReader(""))
 
-// ErrRequestAborted is returned by Read when a handler attempts to read the
-// body of a request that has been aborted by the web server.
-var ErrRequestAborted = errors.New("fcgi: request aborted by web server")
-
-// ErrConnClosed is returned by Read when a handler attempts to read the body of
-// a request after the connection to the web server has been closed.
-var ErrConnClosed = errors.New("fcgi: connection to web server closed")
-
 func (c *child) handleRecord(rec *record) error {
 	c.mu.Lock()
 	req, ok := c.requests[rec.h.Id]
@@ -236,13 +227,11 @@ func (c *child) handleRecord(rec *record) error {
 		// If the filter role is implemented, read the data stream here.
 		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.pw != nil {
-			req.pw.CloseWithError(ErrRequestAborted)
-		}
 		if !req.keepConn {
 			// connection will close upon return
 			return errCloseConn
@@ -288,18 +277,6 @@ func (c *child) serveRequest(req *request, body io.ReadCloser) {
 	}
 }
 
-func (c *child) cleanUp() {
-	c.mu.Lock()
-	defer c.mu.Unlock()
-	for _, req := range c.requests {
-		if req.pw != nil {
-			// race with call to Close in c.serveRequest doesn't matter because
-			// Pipe(Reader|Writer).Close are idempotent
-			req.pw.CloseWithError(ErrConnClosed)
-		}
-	}
-}
-
 // Serve accepts incoming FastCGI connections on the listener l, creating a new
 // goroutine for each. The goroutine reads requests and then calls handler
 // to reply to them.
diff --git a/src/net/http/fcgi/fcgi_test.go b/src/net/http/fcgi/fcgi_test.go
index de0f7f8..6c7e1a9 100644
--- a/src/net/http/fcgi/fcgi_test.go
+++ b/src/net/http/fcgi/fcgi_test.go
@@ -8,8 +8,6 @@ import (
 	"bytes"
 	"errors"
 	"io"
-	"io/ioutil"
-	"net/http"
 	"testing"
 )
 
@@ -150,107 +148,3 @@ func TestGetValues(t *testing.T) {
 		t.Errorf(" got: %q\nwant: %q\n", got, want)
 	}
 }
-
-func nameValuePair11(nameData, valueData string) []byte {
-	return bytes.Join(
-		[][]byte{
-			{byte(len(nameData)), byte(len(valueData))},
-			[]byte(nameData),
-			[]byte(valueData),
-		},
-		nil,
-	)
-}
-
-func makeRecord(
-	recordType recType,
-	requestId uint16,
-	contentData []byte,
-) []byte {
-	requestIdB1 := byte(requestId >> 8)
-	requestIdB0 := byte(requestId)
-
-	contentLength := len(contentData)
-	contentLengthB1 := byte(contentLength >> 8)
-	contentLengthB0 := byte(contentLength)
-	return bytes.Join([][]byte{
-		{1, byte(recordType), requestIdB1, requestIdB0, contentLengthB1,
-			contentLengthB0, 0, 0},
-		contentData,
-	},
-		nil)
-}
-
-// a series of FastCGI records that start a request and begin sending the
-// request body
-var streamBeginTypeStdin = bytes.Join([][]byte{
-	// set up request 1
-	makeRecord(typeBeginRequest, 1,
-		[]byte{0, byte(roleResponder), 0, 0, 0, 0, 0, 0}),
-	// add required parameters to request 1
-	makeRecord(typeParams, 1, nameValuePair11("REQUEST_METHOD", "GET")),
-	makeRecord(typeParams, 1, nameValuePair11("SERVER_PROTOCOL", "HTTP/1.1")),
-	makeRecord(typeParams, 1, nil),
-	// begin sending body of request 1
-	makeRecord(typeStdin, 1, []byte("0123456789abcdef")),
-},
-	nil)
-
-var cleanUpTests = []struct {
-	input []byte
-	err   error
-}{
-	// confirm that child.handleRecord closes req.pw after aborting req
-	{
-		bytes.Join([][]byte{
-			streamBeginTypeStdin,
-			makeRecord(typeAbortRequest, 1, nil),
-		},
-			nil),
-		ErrRequestAborted,
-	},
-	// confirm that child.serve closes all pipes after error reading record
-	{
-		bytes.Join([][]byte{
-			streamBeginTypeStdin,
-			nil,
-		},
-			nil),
-		ErrConnClosed,
-	},
-}
-
-type nopWriteCloser struct {
-	io.ReadWriter
-}
-
-func (nopWriteCloser) Close() error {
-	return nil
-}
-
-// Test that child.serve closes the bodies of aborted requests and closes the
-// bodies of all requests before returning. Causes deadlock if either condition
-// isn't met. See issue 6934.
-func TestChildServeCleansUp(t *testing.T) {
-	for _, tt := range cleanUpTests {
-		input := make([]byte, len(tt.input))
-		copy(input, tt.input)
-		rc := nopWriteCloser{bytes.NewBuffer(input)}
-		done := make(chan bool)
-		c := newChild(rc, http.HandlerFunc(func(
-			w http.ResponseWriter,
-			r *http.Request,
-		) {
-			// block on reading body of request
-			_, err := io.Copy(ioutil.Discard, r.Body)
-			if err != tt.err {
-				t.Errorf("Expected %#v, got %#v", tt.err, err)
-			}
-			// not reached if body of request isn't closed
-			done <- true
-		}))
-		go c.serve()
-		// wait for body of request to be closed or all goroutines to block
-		<-done
-	}
-}
diff --git a/src/net/http/fs.go b/src/net/http/fs.go
index 7572023..e322f71 100644
--- a/src/net/http/fs.go
+++ b/src/net/http/fs.go
@@ -102,10 +102,10 @@ func dirList(w ResponseWriter, f File) {
 // The name is otherwise unused; in particular it can be empty and is
 // never sent in the response.
 //
-// If modtime is not the zero time or Unix epoch, ServeContent
-// includes it in a Last-Modified header in the response.  If the
-// request includes an If-Modified-Since header, ServeContent uses
-// modtime to decide whether the content needs to be sent at all.
+// If modtime is not the zero time, ServeContent includes it in a
+// Last-Modified header in the response.  If the request includes an
+// If-Modified-Since header, ServeContent uses modtime to decide
+// whether the content needs to be sent at all.
 //
 // The content's Seek method must work: ServeContent uses
 // a seek to the end of the content to determine its size.
@@ -258,15 +258,10 @@ func serveContent(w ResponseWriter, r *Request, name string, modtime time.Time,
 	}
 }
 
-var unixEpochTime = time.Unix(0, 0)
-
 // modtime is the modification time of the resource to be served, or IsZero().
 // return value is whether this request is now complete.
 func checkLastModified(w ResponseWriter, r *Request, modtime time.Time) bool {
-	if modtime.IsZero() || modtime.Equal(unixEpochTime) {
-		// If the file doesn't have a modtime (IsZero), or the modtime
-		// is obviously garbage (Unix time == 0), then ignore modtimes
-		// and don't process the If-Modified-Since header.
+	if modtime.IsZero() {
 		return false
 	}
 
@@ -358,16 +353,16 @@ func serveFile(w ResponseWriter, r *Request, fs FileSystem, name string, redirec
 
 	f, err := fs.Open(name)
 	if err != nil {
-		msg, code := toHTTPError(err)
-		Error(w, msg, code)
+		// TODO expose actual error?
+		NotFound(w, r)
 		return
 	}
 	defer f.Close()
 
 	d, err1 := f.Stat()
 	if err1 != nil {
-		msg, code := toHTTPError(err)
-		Error(w, msg, code)
+		// TODO expose actual error?
+		NotFound(w, r)
 		return
 	}
 
@@ -417,22 +412,6 @@ func serveFile(w ResponseWriter, r *Request, fs FileSystem, name string, redirec
 	serveContent(w, r, d.Name(), d.ModTime(), sizeFunc, f)
 }
 
-// toHTTPError returns a non-specific HTTP error message and status code
-// for a given non-nil error value. It's important that toHTTPError does not
-// actually return err.Error(), since msg and httpStatus are returned to users,
-// and historically Go's ServeContent always returned just "404 Not Found" for
-// all errors. We don't want to start leaking information in error messages.
-func toHTTPError(err error) (msg string, httpStatus int) {
-	if os.IsNotExist(err) {
-		return "404 page not found", StatusNotFound
-	}
-	if os.IsPermission(err) {
-		return "403 Forbidden", StatusForbidden
-	}
-	// Default:
-	return "500 Internal Server Error", StatusInternalServerError
-}
-
 // localRedirect gives a Moved Permanently response.
 // It does not convert relative paths to absolute paths like Redirect does.
 func localRedirect(w ResponseWriter, r *Request, newPath string) {
@@ -443,13 +422,7 @@ func localRedirect(w ResponseWriter, r *Request, newPath string) {
 	w.WriteHeader(StatusMovedPermanently)
 }
 
-// ServeFile replies to the request with the contents of the named
-// file or directory.
-//
-// As a special case, ServeFile redirects any request where r.URL.Path
-// ends in "/index.html" to the same path, without the final
-// "index.html". To avoid such redirects either modify the path or
-// use ServeContent.
+// ServeFile replies to the request with the contents of the named file or directory.
 func ServeFile(w ResponseWriter, r *Request, name string) {
 	dir, file := filepath.Split(name)
 	serveFile(w, r, Dir(dir), file, false)
@@ -466,10 +439,6 @@ type fileHandler struct {
 // use http.Dir:
 //
 //     http.Handle("/", http.FileServer(http.Dir("/tmp")))
-//
-// As a special case, the returned file server redirects any request
-// ending in "/index.html" to the same path, without the final
-// "index.html".
 func FileServer(root FileSystem) Handler {
 	return &fileHandler{root}
 }
@@ -534,7 +503,7 @@ func parseRange(s string, size int64) ([]httpRange, error) {
 			r.length = size - r.start
 		} else {
 			i, err := strconv.ParseInt(start, 10, 64)
-			if err != nil || i >= size || i < 0 {
+			if err != nil || i > size || i < 0 {
 				return nil, errors.New("invalid range")
 			}
 			r.start = i
diff --git a/src/net/http/fs_test.go b/src/net/http/fs_test.go
index 794dabc..8770d9b 100644
--- a/src/net/http/fs_test.go
+++ b/src/net/http/fs_test.go
@@ -50,23 +50,15 @@ var ServeFileRangeTests = []struct {
 	{r: "bytes=2-", code: StatusPartialContent, ranges: []wantRange{{2, testFileLen}}},
 	{r: "bytes=-5", code: StatusPartialContent, ranges: []wantRange{{testFileLen - 5, testFileLen}}},
 	{r: "bytes=3-7", code: StatusPartialContent, ranges: []wantRange{{3, 8}}},
+	{r: "bytes=20-", code: StatusRequestedRangeNotSatisfiable},
 	{r: "bytes=0-0,-2", code: StatusPartialContent, ranges: []wantRange{{0, 1}, {testFileLen - 2, testFileLen}}},
 	{r: "bytes=0-1,5-8", code: StatusPartialContent, ranges: []wantRange{{0, 2}, {5, 9}}},
 	{r: "bytes=0-1,5-", code: StatusPartialContent, ranges: []wantRange{{0, 2}, {5, testFileLen}}},
 	{r: "bytes=5-1000", code: StatusPartialContent, ranges: []wantRange{{5, testFileLen}}},
 	{r: "bytes=0-,1-,2-,3-,4-", code: StatusOK}, // ignore wasteful range request
-	{r: "bytes=0-9", code: StatusPartialContent, ranges: []wantRange{{0, testFileLen - 1}}},
-	{r: "bytes=0-10", code: StatusPartialContent, ranges: []wantRange{{0, testFileLen}}},
-	{r: "bytes=0-11", code: StatusPartialContent, ranges: []wantRange{{0, testFileLen}}},
-	{r: "bytes=10-11", code: StatusPartialContent, ranges: []wantRange{{testFileLen - 1, testFileLen}}},
-	{r: "bytes=10-", code: StatusPartialContent, ranges: []wantRange{{testFileLen - 1, testFileLen}}},
-	{r: "bytes=11-", code: StatusRequestedRangeNotSatisfiable},
-	{r: "bytes=11-12", code: StatusRequestedRangeNotSatisfiable},
-	{r: "bytes=12-12", code: StatusRequestedRangeNotSatisfiable},
-	{r: "bytes=11-100", code: StatusRequestedRangeNotSatisfiable},
-	{r: "bytes=12-100", code: StatusRequestedRangeNotSatisfiable},
-	{r: "bytes=100-", code: StatusRequestedRangeNotSatisfiable},
-	{r: "bytes=100-1000", code: StatusRequestedRangeNotSatisfiable},
+	{r: "bytes=0-" + itoa(testFileLen-2), code: StatusPartialContent, ranges: []wantRange{{0, testFileLen - 1}}},
+	{r: "bytes=0-" + itoa(testFileLen-1), code: StatusPartialContent, ranges: []wantRange{{0, testFileLen}}},
+	{r: "bytes=0-" + itoa(testFileLen), code: StatusPartialContent, ranges: []wantRange{{0, testFileLen}}},
 }
 
 func TestServeFile(t *testing.T) {
@@ -497,7 +489,6 @@ type fakeFileInfo struct {
 	modtime  time.Time
 	ents     []*fakeFileInfo
 	contents string
-	err      error
 }
 
 func (f *fakeFileInfo) Name() string       { return f.basename }
@@ -550,9 +541,6 @@ func (fs fakeFS) Open(name string) (File, error) {
 	if !ok {
 		return nil, os.ErrNotExist
 	}
-	if f.err != nil {
-		return nil, f.err
-	}
 	return &fakeFile{ReadSeeker: strings.NewReader(f.contents), fi: f, path: name}, nil
 }
 
@@ -755,12 +743,6 @@ func TestServeContent(t *testing.T) {
 			wantContentType: "text/css; charset=utf-8",
 			wantLastMod:     "Wed, 25 Jun 2014 17:12:18 GMT",
 		},
-		"unix_zero_modtime": {
-			content:         strings.NewReader("<html>foo"),
-			modtime:         time.Unix(0, 0),
-			wantStatus:      StatusOK,
-			wantContentType: "text/html; charset=utf-8",
-		},
 	}
 	for testName, tt := range tests {
 		var content io.ReadSeeker
@@ -807,31 +789,6 @@ func TestServeContent(t *testing.T) {
 	}
 }
 
-func TestServeContentErrorMessages(t *testing.T) {
-	defer afterTest(t)
-	fs := fakeFS{
-		"/500": &fakeFileInfo{
-			err: errors.New("random error"),
-		},
-		"/403": &fakeFileInfo{
-			err: &os.PathError{Err: os.ErrPermission},
-		},
-	}
-	ts := httptest.NewServer(FileServer(fs))
-	defer ts.Close()
-	for _, code := range []int{403, 404, 500} {
-		res, err := DefaultClient.Get(fmt.Sprintf("%s/%d", ts.URL, code))
-		if err != nil {
-			t.Errorf("Error fetching /%d: %v", code, err)
-			continue
-		}
-		if res.StatusCode != code {
-			t.Errorf("For /%d, status code = %d; want %d", code, res.StatusCode, code)
-		}
-		res.Body.Close()
-	}
-}
-
 // verifies that sendfile is being used on Linux
 func TestLinuxSendfile(t *testing.T) {
 	defer afterTest(t)
diff --git a/src/net/http/header.go b/src/net/http/header.go
index d847b13..153b943 100644
--- a/src/net/http/header.go
+++ b/src/net/http/header.go
@@ -168,8 +168,6 @@ func (h Header) WriteSubset(w io.Writer, exclude map[string]bool) error {
 // letter and any letter following a hyphen to upper case;
 // the rest are converted to lowercase.  For example, the
 // canonical key for "accept-encoding" is "Accept-Encoding".
-// If s contains a space or invalid header field bytes, it is
-// returned without modifications.
 func CanonicalHeaderKey(s string) string { return textproto.CanonicalMIMEHeaderKey(s) }
 
 // hasToken reports whether token appears with v, ASCII
diff --git a/src/net/http/httptest/server.go b/src/net/http/httptest/server.go
index 96eb0ef..789e7bf 100644
--- a/src/net/http/httptest/server.go
+++ b/src/net/http/httptest/server.go
@@ -204,35 +204,25 @@ func (h *waitGroupHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 // "127.0.0.1" and "[::1]", expiring at the last second of 2049 (the end
 // of ASN.1 time).
 // generated from src/crypto/tls:
-// go run generate_cert.go  --rsa-bits 1024 --host 127.0.0.1,::1,example.com --ca --start-date "Jan 1 00:00:00 1970" --duration=1000000h
+// 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-----
-MIICEzCCAXygAwIBAgIQMIMChMLGrR+QvmQvpwAU6zANBgkqhkiG9w0BAQsFADAS
-MRAwDgYDVQQKEwdBY21lIENvMCAXDTcwMDEwMTAwMDAwMFoYDzIwODQwMTI5MTYw
-MDAwWjASMRAwDgYDVQQKEwdBY21lIENvMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB
-iQKBgQDuLnQAI3mDgey3VBzWnB2L39JUU4txjeVE6myuDqkM/uGlfjb9SjY1bIw4
-iA5sBBZzHi3z0h1YV8QPuxEbi4nW91IJm2gsvvZhIrCHS3l6afab4pZBl2+XsDul
-rKBxKKtD1rGxlG4LjncdabFn9gvLZad2bSysqz/qTAUStTvqJQIDAQABo2gwZjAO
-BgNVHQ8BAf8EBAMCAqQwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDwYDVR0TAQH/BAUw
-AwEB/zAuBgNVHREEJzAlggtleGFtcGxlLmNvbYcEfwAAAYcQAAAAAAAAAAAAAAAA
-AAAAATANBgkqhkiG9w0BAQsFAAOBgQCEcetwO59EWk7WiJsG4x8SY+UIAA+flUI9
-tyC4lNhbcF2Idq9greZwbYCqTTTr2XiRNSMLCOjKyI7ukPoPjo16ocHj+P3vZGfs
-h1fIw3cSS2OolhloGw/XM6RWPWtPAlGykKLciQrBru5NAPvCMsb/I1DAceTiotQM
-fblo6RBxUQ==
+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-----
-MIICXgIBAAKBgQDuLnQAI3mDgey3VBzWnB2L39JUU4txjeVE6myuDqkM/uGlfjb9
-SjY1bIw4iA5sBBZzHi3z0h1YV8QPuxEbi4nW91IJm2gsvvZhIrCHS3l6afab4pZB
-l2+XsDulrKBxKKtD1rGxlG4LjncdabFn9gvLZad2bSysqz/qTAUStTvqJQIDAQAB
-AoGAGRzwwir7XvBOAy5tM/uV6e+Zf6anZzus1s1Y1ClbjbE6HXbnWWF/wbZGOpet
-3Zm4vD6MXc7jpTLryzTQIvVdfQbRc6+MUVeLKwZatTXtdZrhu+Jk7hx0nTPy8Jcb
-uJqFk541aEw+mMogY/xEcfbWd6IOkp+4xqjlFLBEDytgbIECQQDvH/E6nk+hgN4H
-qzzVtxxr397vWrjrIgPbJpQvBsafG7b0dA4AFjwVbFLmQcj2PprIMmPcQrooz8vp
-jy4SHEg1AkEA/v13/5M47K9vCxmb8QeD/asydfsgS5TeuNi8DoUBEmiSJwma7FXY
-fFUtxuvL7XvjwjN5B30pNEbc6Iuyt7y4MQJBAIt21su4b3sjXNueLKH85Q+phy2U
-fQtuUE9txblTu14q3N7gHRZB4ZMhFYyDy8CKrN2cPg/Fvyt0Xlp/DoCzjA0CQQDU
-y2ptGsuSmgUtWj3NM9xuwYPm+Z/F84K6+ARYiZ6PYj013sovGKUFfYAqVXVlxtIX
-qyUBnu3X9ps8ZfjLZO7BAkEAlT4R5Yl6cGhaJQYZHOde3JEMhNRcVFMO8dJDaFeo
-f9Oeos0UUothgiDktdQHxdNEwLjQf7lJJBzV+5OtwswCWA==
+MIIBPAIBAAJBAN55NcYKZeInyTuhcCwFMhDHCmwaIUSdtXdcbItRB/yfXGBhiex0
+0IaLXQnSU+QZPRZWYqeTEbFSgihqi1PUDy8CAwEAAQJBAQdUx66rfh8sYsgfdcvV
+NoafYpnEcB5s4m/vSVe6SU7dCK6eYec9f9wpT353ljhDUHq3EbmE4foNzJngh35d
+AekCIQDhRQG5Li0Wj8TM4obOnnXUXf1jRv0UkzE9AHWLG5q3AwIhAPzSjpYUDjVW
+MCUXgckTpKCuGwbJk7424Nb8bLzf3kllAiA5mUBgjfr/WtFSJdWcPQ4Zt9KTMNKD
+EUO0ukpTwEIl6wIhAMbGqZK3zAAFdq8DD2jPx+UJXnh0rnOkZBzDtJ6/iN69AiEA
+1Aq8MJgTaYsDQWyU/hDq5YkDJc9e9DSCvUIzqxQWMQE=
 -----END RSA PRIVATE KEY-----`)
diff --git a/src/net/http/httputil/dump.go b/src/net/http/httputil/dump.go
index ca2d1cd..ac8f103 100644
--- a/src/net/http/httputil/dump.go
+++ b/src/net/http/httputil/dump.go
@@ -98,14 +98,6 @@ func DumpRequestOut(req *http.Request, body bool) ([]byte, error) {
 	defer pr.Close()
 	defer pw.Close()
 	dr := &delegateReader{c: make(chan io.Reader)}
-
-	t := &http.Transport{
-		Dial: func(net, addr string) (net.Conn, error) {
-			return &dumpConn{io.MultiWriter(&buf, pw), dr}, nil
-		},
-	}
-	defer t.CloseIdleConnections()
-
 	// Wait for the request before replying with a dummy response:
 	go func() {
 		req, err := http.ReadRequest(bufio.NewReader(pr))
@@ -115,9 +107,16 @@ func DumpRequestOut(req *http.Request, body bool) ([]byte, error) {
 			io.Copy(ioutil.Discard, req.Body)
 			req.Body.Close()
 		}
-		dr.c <- strings.NewReader("HTTP/1.1 204 No Content\r\nConnection: close\r\n\r\n")
+		dr.c <- strings.NewReader("HTTP/1.1 204 No Content\r\n\r\n")
 	}()
 
+	t := &http.Transport{
+		DisableKeepAlives: true,
+		Dial: func(net, addr string) (net.Conn, error) {
+			return &dumpConn{io.MultiWriter(&buf, pw), dr}, nil
+		},
+	}
+
 	_, err := t.RoundTrip(reqSend)
 
 	req.Body = save
diff --git a/src/net/http/httputil/dump_test.go b/src/net/http/httputil/dump_test.go
index ae67e98..024ee5a 100644
--- a/src/net/http/httputil/dump_test.go
+++ b/src/net/http/httputil/dump_test.go
@@ -71,7 +71,7 @@ var dumpTests = []dumpTest{
 
 		WantDumpOut: "GET /foo HTTP/1.1\r\n" +
 			"Host: example.com\r\n" +
-			"User-Agent: Go-http-client/1.1\r\n" +
+			"User-Agent: Go 1.1 package http\r\n" +
 			"Accept-Encoding: gzip\r\n\r\n",
 	},
 
@@ -83,7 +83,7 @@ var dumpTests = []dumpTest{
 
 		WantDumpOut: "GET /foo HTTP/1.1\r\n" +
 			"Host: example.com\r\n" +
-			"User-Agent: Go-http-client/1.1\r\n" +
+			"User-Agent: Go 1.1 package http\r\n" +
 			"Accept-Encoding: gzip\r\n\r\n",
 	},
 
@@ -105,7 +105,7 @@ var dumpTests = []dumpTest{
 
 		WantDumpOut: "POST / HTTP/1.1\r\n" +
 			"Host: post.tld\r\n" +
-			"User-Agent: Go-http-client/1.1\r\n" +
+			"User-Agent: Go 1.1 package http\r\n" +
 			"Content-Length: 6\r\n" +
 			"Accept-Encoding: gzip\r\n\r\n",
 
@@ -130,7 +130,7 @@ var dumpTests = []dumpTest{
 
 		WantDumpOut: "POST / HTTP/1.1\r\n" +
 			"Host: post.tld\r\n" +
-			"User-Agent: Go-http-client/1.1\r\n" +
+			"User-Agent: Go 1.1 package http\r\n" +
 			"Content-Length: 8193\r\n" +
 			"Accept-Encoding: gzip\r\n\r\n" +
 			strings.Repeat("a", 8193),
diff --git a/src/net/http/httputil/reverseproxy.go b/src/net/http/httputil/reverseproxy.go
index 3b7a184..ab46370 100644
--- a/src/net/http/httputil/reverseproxy.go
+++ b/src/net/http/httputil/reverseproxy.go
@@ -100,24 +100,6 @@ var hopHeaders = []string{
 	"Upgrade",
 }
 
-type requestCanceler interface {
-	CancelRequest(*http.Request)
-}
-
-type runOnFirstRead struct {
-	io.Reader
-
-	fn func() // Run before first Read, then set to nil
-}
-
-func (c *runOnFirstRead) Read(bs []byte) (int, error) {
-	if c.fn != nil {
-		c.fn()
-		c.fn = nil
-	}
-	return c.Reader.Read(bs)
-}
-
 func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
 	transport := p.Transport
 	if transport == nil {
@@ -127,34 +109,6 @@ func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
 	outreq := new(http.Request)
 	*outreq = *req // includes shallow copies of maps, but okay
 
-	if closeNotifier, ok := rw.(http.CloseNotifier); ok {
-		if requestCanceler, ok := transport.(requestCanceler); ok {
-			reqDone := make(chan struct{})
-			defer close(reqDone)
-
-			clientGone := closeNotifier.CloseNotify()
-
-			outreq.Body = struct {
-				io.Reader
-				io.Closer
-			}{
-				Reader: &runOnFirstRead{
-					Reader: outreq.Body,
-					fn: func() {
-						go func() {
-							select {
-							case <-clientGone:
-								requestCanceler.CancelRequest(outreq)
-							case <-reqDone:
-							}
-						}()
-					},
-				},
-				Closer: outreq.Body,
-			}
-		}
-	}
-
 	p.Director(outreq)
 	outreq.Proto = "HTTP/1.1"
 	outreq.ProtoMajor = 1
@@ -194,6 +148,7 @@ func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
 		rw.WriteHeader(http.StatusInternalServerError)
 		return
 	}
+	defer res.Body.Close()
 
 	for _, h := range hopHeaders {
 		res.Header.Del(h)
@@ -201,28 +156,8 @@ func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
 
 	copyHeader(rw.Header(), res.Header)
 
-	// The "Trailer" header isn't included in the Transport's response,
-	// at least for *http.Transport. Build it up from Trailer.
-	if len(res.Trailer) > 0 {
-		var trailerKeys []string
-		for k := range res.Trailer {
-			trailerKeys = append(trailerKeys, k)
-		}
-		rw.Header().Add("Trailer", strings.Join(trailerKeys, ", "))
-	}
-
 	rw.WriteHeader(res.StatusCode)
-	if len(res.Trailer) > 0 {
-		// Force chunking if we saw a response trailer.
-		// This prevents net/http from calculating the length for short
-		// bodies and adding a Content-Length.
-		if fl, ok := rw.(http.Flusher); ok {
-			fl.Flush()
-		}
-	}
 	p.copyResponse(rw, res.Body)
-	res.Body.Close() // close now, instead of defer, to populate res.Trailer
-	copyHeader(rw.Header(), res.Trailer)
 }
 
 func (p *ReverseProxy) copyResponse(dst io.Writer, src io.Reader) {
diff --git a/src/net/http/httputil/reverseproxy_test.go b/src/net/http/httputil/reverseproxy_test.go
index 25947e6..e9539b4 100644
--- a/src/net/http/httputil/reverseproxy_test.go
+++ b/src/net/http/httputil/reverseproxy_test.go
@@ -8,12 +8,9 @@ package httputil
 
 import (
 	"io/ioutil"
-	"log"
 	"net/http"
 	"net/http/httptest"
 	"net/url"
-	"reflect"
-	"runtime"
 	"strings"
 	"testing"
 	"time"
@@ -44,7 +41,6 @@ func TestReverseProxy(t *testing.T) {
 		if g, e := r.Host, "some-name"; g != e {
 			t.Errorf("backend got Host header %q, want %q", g, e)
 		}
-		w.Header().Set("Trailer", "X-Trailer")
 		w.Header().Set("X-Foo", "bar")
 		w.Header().Set("Upgrade", "foo")
 		w.Header().Set(fakeHopHeader, "foo")
@@ -53,7 +49,6 @@ func TestReverseProxy(t *testing.T) {
 		http.SetCookie(w, &http.Cookie{Name: "flavor", Value: "chocolateChip"})
 		w.WriteHeader(backendStatus)
 		w.Write([]byte(backendResponse))
-		w.Header().Set("X-Trailer", "trailer_value")
 	}))
 	defer backend.Close()
 	backendURL, err := url.Parse(backend.URL)
@@ -88,9 +83,6 @@ func TestReverseProxy(t *testing.T) {
 	if g, e := len(res.Header["Set-Cookie"]), 1; g != e {
 		t.Fatalf("got %d SetCookies, want %d", g, e)
 	}
-	if g, e := res.Trailer, (http.Header{"X-Trailer": nil}); !reflect.DeepEqual(g, e) {
-		t.Errorf("before reading body, Trailer = %#v; want %#v", g, e)
-	}
 	if cookie := res.Cookies()[0]; cookie.Name != "flavor" {
 		t.Errorf("unexpected cookie %q", cookie.Name)
 	}
@@ -98,10 +90,6 @@ func TestReverseProxy(t *testing.T) {
 	if g, e := string(bodyBytes), backendResponse; g != e {
 		t.Errorf("got body %q; expected %q", g, e)
 	}
-	if g, e := res.Trailer.Get("X-Trailer"), "trailer_value"; g != e {
-		t.Errorf("Trailer(X-Trailer) = %q ; want %q", g, e)
-	}
-
 }
 
 func TestXForwardedFor(t *testing.T) {
@@ -223,61 +211,3 @@ func TestReverseProxyFlushInterval(t *testing.T) {
 		t.Error("maxLatencyWriter flushLoop() never exited")
 	}
 }
-
-func TestReverseProxyCancellation(t *testing.T) {
-	if runtime.GOOS == "plan9" {
-		t.Skip("skipping test; see https://golang.org/issue/9554")
-	}
-	const backendResponse = "I am the backend"
-
-	reqInFlight := make(chan struct{})
-	backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
-		close(reqInFlight)
-
-		select {
-		case <-time.After(10 * time.Second):
-			// Note: this should only happen in broken implementations, and the
-			// closenotify case should be instantaneous.
-			t.Log("Failed to close backend connection")
-			t.Fail()
-		case <-w.(http.CloseNotifier).CloseNotify():
-		}
-
-		w.WriteHeader(http.StatusOK)
-		w.Write([]byte(backendResponse))
-	}))
-
-	defer backend.Close()
-
-	backend.Config.ErrorLog = log.New(ioutil.Discard, "", 0)
-
-	backendURL, err := url.Parse(backend.URL)
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	proxyHandler := NewSingleHostReverseProxy(backendURL)
-
-	// Discards errors of the form:
-	// http: proxy error: read tcp 127.0.0.1:44643: use of closed network connection
-	proxyHandler.ErrorLog = log.New(ioutil.Discard, "", 0)
-
-	frontend := httptest.NewServer(proxyHandler)
-	defer frontend.Close()
-
-	getReq, _ := http.NewRequest("GET", frontend.URL, nil)
-	go func() {
-		<-reqInFlight
-		http.DefaultTransport.(*http.Transport).CancelRequest(getReq)
-	}()
-	res, err := http.DefaultClient.Do(getReq)
-	if res != nil {
-		t.Fatal("Non-nil response")
-	}
-	if err == nil {
-		// This should be an error like:
-		// Get http://127.0.0.1:58079: read tcp 127.0.0.1:58079:
-		//    use of closed network connection
-		t.Fatal("DefaultClient.Do() returned nil error")
-	}
-}
diff --git a/src/net/http/internal/chunked.go b/src/net/http/internal/chunked.go
index 6d7c698..9294deb 100644
--- a/src/net/http/internal/chunked.go
+++ b/src/net/http/internal/chunked.go
@@ -173,12 +173,8 @@ func (cw *chunkedWriter) Write(data []byte) (n int, err error) {
 		err = io.ErrShortWrite
 		return
 	}
-	if _, err = io.WriteString(cw.Wire, "\r\n"); err != nil {
-		return
-	}
-	if bw, ok := cw.Wire.(*FlushAfterChunkWriter); ok {
-		err = bw.Flush()
-	}
+	_, err = io.WriteString(cw.Wire, "\r\n")
+
 	return
 }
 
@@ -187,15 +183,6 @@ func (cw *chunkedWriter) Close() error {
 	return err
 }
 
-// FlushAfterChunkWriter signals from the caller of NewChunkedWriter
-// that each chunk should be followed by a flush. It is used by the
-// http.Transport code to keep the buffering behavior for headers and
-// trailers, but flush out chunks aggressively in the middle for
-// request bodies which may be generated slowly. See Issue 6574.
-type FlushAfterChunkWriter struct {
-	*bufio.Writer
-}
-
 func parseHexUint(v []byte) (n uint64, err error) {
 	for _, b := range v {
 		n <<= 4
diff --git a/src/net/http/lex.go b/src/net/http/lex.go
index 50b14f8..cb33318 100644
--- a/src/net/http/lex.go
+++ b/src/net/http/lex.go
@@ -4,11 +4,6 @@
 
 package http
 
-import (
-	"strings"
-	"unicode/utf8"
-)
-
 // This file deals with lexical matters of HTTP
 
 var isTokenTable = [127]bool{
@@ -99,71 +94,3 @@ func isToken(r rune) bool {
 func isNotToken(r rune) bool {
 	return !isToken(r)
 }
-
-// headerValuesContainsToken reports whether any string in values
-// contains the provided token, ASCII case-insensitively.
-func headerValuesContainsToken(values []string, token string) bool {
-	for _, v := range values {
-		if headerValueContainsToken(v, token) {
-			return true
-		}
-	}
-	return false
-}
-
-// isOWS reports whether b is an optional whitespace byte, as defined
-// by RFC 7230 section 3.2.3.
-func isOWS(b byte) bool { return b == ' ' || b == '\t' }
-
-// trimOWS returns x with all optional whitespace removes from the
-// beginning and end.
-func trimOWS(x string) string {
-	// TODO: consider using strings.Trim(x, " \t") instead,
-	// if and when it's fast enough. See issue 10292.
-	// But this ASCII-only code will probably always beat UTF-8
-	// aware code.
-	for len(x) > 0 && isOWS(x[0]) {
-		x = x[1:]
-	}
-	for len(x) > 0 && isOWS(x[len(x)-1]) {
-		x = x[:len(x)-1]
-	}
-	return x
-}
-
-// headerValueContainsToken reports whether v (assumed to be a
-// 0#element, in the ABNF extension described in RFC 7230 section 7)
-// contains token amongst its comma-separated tokens, ASCII
-// case-insensitively.
-func headerValueContainsToken(v string, token string) bool {
-	v = trimOWS(v)
-	if comma := strings.IndexByte(v, ','); comma != -1 {
-		return tokenEqual(trimOWS(v[:comma]), token) || headerValueContainsToken(v[comma+1:], token)
-	}
-	return tokenEqual(v, token)
-}
-
-// lowerASCII returns the ASCII lowercase version of b.
-func lowerASCII(b byte) byte {
-	if 'A' <= b && b <= 'Z' {
-		return b + ('a' - 'A')
-	}
-	return b
-}
-
-// tokenEqual reports whether t1 and t2 are equal, ASCII case-insensitively.
-func tokenEqual(t1, t2 string) bool {
-	if len(t1) != len(t2) {
-		return false
-	}
-	for i, b := range t1 {
-		if b >= utf8.RuneSelf {
-			// No UTF-8 or non-ASCII allowed in tokens.
-			return false
-		}
-		if lowerASCII(byte(b)) != lowerASCII(t2[i]) {
-			return false
-		}
-	}
-	return true
-}
diff --git a/src/net/http/lex_test.go b/src/net/http/lex_test.go
index 986fda1..6d9d294 100644
--- a/src/net/http/lex_test.go
+++ b/src/net/http/lex_test.go
@@ -29,73 +29,3 @@ func TestIsToken(t *testing.T) {
 		}
 	}
 }
-
-func TestHeaderValuesContainsToken(t *testing.T) {
-	tests := []struct {
-		vals  []string
-		token string
-		want  bool
-	}{
-		{
-			vals:  []string{"foo"},
-			token: "foo",
-			want:  true,
-		},
-		{
-			vals:  []string{"bar", "foo"},
-			token: "foo",
-			want:  true,
-		},
-		{
-			vals:  []string{"foo"},
-			token: "FOO",
-			want:  true,
-		},
-		{
-			vals:  []string{"foo"},
-			token: "bar",
-			want:  false,
-		},
-		{
-			vals:  []string{" foo "},
-			token: "FOO",
-			want:  true,
-		},
-		{
-			vals:  []string{"foo,bar"},
-			token: "FOO",
-			want:  true,
-		},
-		{
-			vals:  []string{"bar,foo,bar"},
-			token: "FOO",
-			want:  true,
-		},
-		{
-			vals:  []string{"bar , foo"},
-			token: "FOO",
-			want:  true,
-		},
-		{
-			vals:  []string{"foo ,bar "},
-			token: "FOO",
-			want:  true,
-		},
-		{
-			vals:  []string{"bar, foo ,bar"},
-			token: "FOO",
-			want:  true,
-		},
-		{
-			vals:  []string{"bar , foo"},
-			token: "FOO",
-			want:  true,
-		},
-	}
-	for _, tt := range tests {
-		got := headerValuesContainsToken(tt.vals, tt.token)
-		if got != tt.want {
-			t.Errorf("headerValuesContainsToken(%q, %q) = %v; want %v", tt.vals, tt.token, got, tt.want)
-		}
-	}
-}
diff --git a/src/net/http/main_test.go b/src/net/http/main_test.go
index 12eea6f..b8c71fd 100644
--- a/src/net/http/main_test.go
+++ b/src/net/http/main_test.go
@@ -56,21 +56,17 @@ func goroutineLeaked() bool {
 		// not counting goroutines for leakage in -short mode
 		return false
 	}
+	gs := interestingGoroutines()
 
-	var stackCount map[string]int
-	for i := 0; i < 5; i++ {
-		n := 0
-		stackCount = make(map[string]int)
-		gs := interestingGoroutines()
-		for _, g := range gs {
-			stackCount[g]++
-			n++
-		}
-		if n == 0 {
-			return false
-		}
-		// Wait for goroutines to schedule and die off:
-		time.Sleep(100 * time.Millisecond)
+	n := 0
+	stackCount := make(map[string]int)
+	for _, g := range gs {
+		stackCount[g]++
+		n++
+	}
+
+	if n == 0 {
+		return false
 	}
 	fmt.Fprintf(os.Stderr, "Too many goroutines running after net/http test(s).\n")
 	for stack, count := range stackCount {
@@ -79,7 +75,7 @@ func goroutineLeaked() bool {
 	return true
 }
 
-func afterTest(t testing.TB) {
+func afterTest(t *testing.T) {
 	http.DefaultTransport.(*http.Transport).CloseIdleConnections()
 	if testing.Short() {
 		return
diff --git a/src/net/http/npn_test.go b/src/net/http/npn_test.go
index e2e911d..98b8930 100644
--- a/src/net/http/npn_test.go
+++ b/src/net/http/npn_test.go
@@ -6,7 +6,6 @@ package http_test
 
 import (
 	"bufio"
-	"bytes"
 	"crypto/tls"
 	"fmt"
 	"io"
@@ -18,7 +17,6 @@ import (
 )
 
 func TestNextProtoUpgrade(t *testing.T) {
-	defer afterTest(t)
 	ts := httptest.NewUnstartedServer(HandlerFunc(func(w ResponseWriter, r *Request) {
 		fmt.Fprintf(w, "path=%s,proto=", r.URL.Path)
 		if r.TLS != nil {
@@ -40,12 +38,12 @@ func TestNextProtoUpgrade(t *testing.T) {
 	ts.StartTLS()
 	defer ts.Close()
 
+	tr := newTLSTransport(t, ts)
+	defer tr.CloseIdleConnections()
+	c := &Client{Transport: tr}
+
 	// Normal request, without NPN.
 	{
-		tr := newTLSTransport(t, ts)
-		defer tr.CloseIdleConnections()
-		c := &Client{Transport: tr}
-
 		res, err := c.Get(ts.URL)
 		if err != nil {
 			t.Fatal(err)
@@ -62,17 +60,11 @@ func TestNextProtoUpgrade(t *testing.T) {
 	// Request to an advertised but unhandled NPN protocol.
 	// Server will hang up.
 	{
-		tr := newTLSTransport(t, ts)
+		tr.CloseIdleConnections()
 		tr.TLSClientConfig.NextProtos = []string{"unhandled-proto"}
-		defer tr.CloseIdleConnections()
-		c := &Client{Transport: tr}
-
-		res, err := c.Get(ts.URL)
+		_, err := c.Get(ts.URL)
 		if err == nil {
-			defer res.Body.Close()
-			var buf bytes.Buffer
-			res.Write(&buf)
-			t.Errorf("expected error on unhandled-proto request; got: %s", buf.Bytes())
+			t.Errorf("expected error on unhandled-proto request")
 		}
 	}
 
diff --git a/src/net/http/pprof/pprof.go b/src/net/http/pprof/pprof.go
index fd9154a..a23f1bc 100644
--- a/src/net/http/pprof/pprof.go
+++ b/src/net/http/pprof/pprof.go
@@ -34,16 +34,12 @@
 //
 //	go tool pprof http://localhost:6060/debug/pprof/block
 //
-// Or to collect a 5-second execution trace:
-//
-//	wget http://localhost:6060/debug/pprof/trace?seconds=5
-//
 // To view all available profiles, open http://localhost:6060/debug/pprof/
 // in your browser.
 //
 // For a study of the facility in action, visit
 //
-//	https://blog.golang.org/2011/06/profiling-go-programs.html
+//	http://blog.golang.org/2011/06/profiling-go-programs.html
 //
 package pprof
 
@@ -58,7 +54,6 @@ import (
 	"os"
 	"runtime"
 	"runtime/pprof"
-	"runtime/trace"
 	"strconv"
 	"strings"
 	"time"
@@ -69,7 +64,6 @@ func init() {
 	http.Handle("/debug/pprof/cmdline", http.HandlerFunc(Cmdline))
 	http.Handle("/debug/pprof/profile", http.HandlerFunc(Profile))
 	http.Handle("/debug/pprof/symbol", http.HandlerFunc(Symbol))
-	http.Handle("/debug/pprof/trace", http.HandlerFunc(Trace))
 }
 
 // Cmdline responds with the running program's
@@ -104,30 +98,6 @@ func Profile(w http.ResponseWriter, r *http.Request) {
 	pprof.StopCPUProfile()
 }
 
-// Trace responds with the execution trace in binary form.
-// Tracing lasts for duration specified in seconds GET parameter, or for 1 second if not specified.
-// The package initialization registers it as /debug/pprof/trace.
-func Trace(w http.ResponseWriter, r *http.Request) {
-	sec, _ := strconv.ParseInt(r.FormValue("seconds"), 10, 64)
-	if sec == 0 {
-		sec = 1
-	}
-
-	// Set Content Type assuming trace.Start will work,
-	// because if it does it starts writing.
-	w.Header().Set("Content-Type", "application/octet-stream")
-	if err := trace.Start(w); err != nil {
-		// trace.Start failed, so no writes yet.
-		// Can change header back to text content and send error code.
-		w.Header().Set("Content-Type", "text/plain; charset=utf-8")
-		w.WriteHeader(http.StatusInternalServerError)
-		fmt.Fprintf(w, "Could not enable tracing: %s\n", err)
-		return
-	}
-	time.Sleep(time.Duration(sec) * time.Second)
-	trace.Stop()
-}
-
 // Symbol looks up the program counters listed in the request,
 // responding with a table mapping program counters to function names.
 // The package initialization registers it as /debug/pprof/symbol.
@@ -223,17 +193,17 @@ var indexTmpl = template.Must(template.New("index").Parse(`<html>
 <head>
 <title>/debug/pprof/</title>
 </head>
-<body>
 /debug/pprof/<br>
 <br>
+<body>
 profiles:<br>
 <table>
 {{range .}}
-<tr><td align=right>{{.Count}}<td><a href="{{.Name}}?debug=1">{{.Name}}</a>
+<tr><td align=right>{{.Count}}<td><a href="/debug/pprof/{{.Name}}?debug=1">{{.Name}}</a>
 {{end}}
 </table>
 <br>
-<a href="goroutine?debug=2">full goroutine stack dump</a><br>
+<a href="/debug/pprof/goroutine?debug=2">full goroutine stack dump</a><br>
 </body>
 </html>
 `))
diff --git a/src/net/http/proxy_test.go b/src/net/http/proxy_test.go
index 823d144..b6aed37 100644
--- a/src/net/http/proxy_test.go
+++ b/src/net/http/proxy_test.go
@@ -18,7 +18,7 @@ var UseProxyTests = []struct {
 	match bool
 }{
 	// Never proxy localhost:
-	{"localhost", false},
+	{"localhost:80", false},
 	{"127.0.0.1", false},
 	{"127.0.0.2", false},
 	{"[::1]", false},
diff --git a/src/net/http/readrequest_test.go b/src/net/http/readrequest_test.go
index 60e2be4..e930d99 100644
--- a/src/net/http/readrequest_test.go
+++ b/src/net/http/readrequest_test.go
@@ -9,7 +9,6 @@ import (
 	"bytes"
 	"fmt"
 	"io"
-	"io/ioutil"
 	"net/url"
 	"reflect"
 	"strings"
@@ -178,36 +177,6 @@ var reqTests = []reqTest{
 		noError,
 	},
 
-	// Tests chunked body and a bogus Content-Length which should be deleted.
-	{
-		"POST / HTTP/1.1\r\n" +
-			"Host: foo.com\r\n" +
-			"Transfer-Encoding: chunked\r\n" +
-			"Content-Length: 9999\r\n\r\n" + // to be removed.
-			"3\r\nfoo\r\n" +
-			"3\r\nbar\r\n" +
-			"0\r\n" +
-			"\r\n",
-		&Request{
-			Method: "POST",
-			URL: &url.URL{
-				Path: "/",
-			},
-			TransferEncoding: []string{"chunked"},
-			Proto:            "HTTP/1.1",
-			ProtoMajor:       1,
-			ProtoMinor:       1,
-			Header:           Header{},
-			ContentLength:    -1,
-			Host:             "foo.com",
-			RequestURI:       "/",
-		},
-
-		"foobar",
-		noTrailer,
-		noError,
-	},
-
 	// CONNECT request with domain name:
 	{
 		"CONNECT www.google.com:443 HTTP/1.1\r\n\r\n",
@@ -354,32 +323,6 @@ var reqTests = []reqTest{
 		noTrailer,
 		noError,
 	},
-
-	// HEAD with Content-Length 0. Make sure this is permitted,
-	// since I think we used to send it.
-	{
-		"HEAD / HTTP/1.1\r\nHost: issue8261.com\r\nConnection: close\r\nContent-Length: 0\r\n\r\n",
-		&Request{
-			Method: "HEAD",
-			URL: &url.URL{
-				Path: "/",
-			},
-			Header: Header{
-				"Connection":     []string{"close"},
-				"Content-Length": []string{"0"},
-			},
-			Host:       "issue8261.com",
-			Proto:      "HTTP/1.1",
-			ProtoMajor: 1,
-			ProtoMinor: 1,
-			Close:      true,
-			RequestURI: "/",
-		},
-
-		noBody,
-		noTrailer,
-		noError,
-	},
 }
 
 func TestReadRequest(t *testing.T) {
@@ -413,34 +356,3 @@ func TestReadRequest(t *testing.T) {
 		}
 	}
 }
-
-// reqBytes treats req as a request (with \n delimiters) and returns it with \r\n delimiters,
-// ending in \r\n\r\n
-func reqBytes(req string) []byte {
-	return []byte(strings.Replace(strings.TrimSpace(req), "\n", "\r\n", -1) + "\r\n\r\n")
-}
-
-var badRequestTests = []struct {
-	name string
-	req  []byte
-}{
-	{"bad_connect_host", reqBytes("CONNECT []%20%48%54%54%50%2f%31%2e%31%0a%4d%79%48%65%61%64%65%72%3a%20%31%32%33%0a%0a HTTP/1.0")},
-	{"smuggle_two_contentlen", reqBytes(`POST / HTTP/1.1
-Content-Length: 3
-Content-Length: 4
-
-abc`)},
-	{"smuggle_content_len_head", reqBytes(`HEAD / HTTP/1.1
-Host: foo
-Content-Length: 5`)},
-}
-
-func TestReadRequest_Bad(t *testing.T) {
-	for _, tt := range badRequestTests {
-		got, err := ReadRequest(bufio.NewReader(bytes.NewReader(tt.req)))
-		if err == nil {
-			all, err := ioutil.ReadAll(got.Body)
-			t.Errorf("%s: got unexpected request = %#v\n  Body = %q, %v", tt.name, got, all, err)
-		}
-	}
-}
diff --git a/src/net/http/request.go b/src/net/http/request.go
index 31fe45a..487eebc 100644
--- a/src/net/http/request.go
+++ b/src/net/http/request.go
@@ -25,6 +25,9 @@ import (
 )
 
 const (
+	maxValueLength   = 4096
+	maxHeaderLines   = 1024
+	chunkSize        = 4 << 10  // 4 KB chunks
 	defaultMaxMemory = 32 << 20 // 32 MB
 )
 
@@ -169,9 +172,8 @@ type Request struct {
 	// The HTTP client ignores Form and uses Body instead.
 	Form url.Values
 
-	// PostForm contains the parsed form data from POST, PATCH,
-	// or PUT body parameters.
-	//
+	// PostForm contains the parsed form data from POST or PUT
+	// body parameters.
 	// This field is only available after ParseForm is called.
 	// The HTTP client ignores PostForm and uses Body instead.
 	PostForm url.Values
@@ -224,13 +226,6 @@ type Request struct {
 	// otherwise it leaves the field nil.
 	// This field is ignored by the HTTP client.
 	TLS *tls.ConnectionState
-
-	// Cancel is an optional channel whose closure indicates that the client
-	// request should be regarded as canceled. Not all implementations of
-	// RoundTripper may support Cancel.
-	//
-	// For server requests, this field is not applicable.
-	Cancel <-chan struct{}
 }
 
 // ProtoAtLeast reports whether the HTTP protocol used
@@ -250,7 +245,6 @@ func (r *Request) Cookies() []*Cookie {
 	return readCookies(r.Header, "")
 }
 
-// ErrNoCookie is returned by Request's Cookie method when a cookie is not found.
 var ErrNoCookie = errors.New("http: named cookie not present")
 
 // Cookie returns the named cookie provided in the request or
@@ -335,12 +329,13 @@ func valueOrDefault(value, def string) string {
 }
 
 // NOTE: This is not intended to reflect the actual Go version being used.
-// It was changed at the time of Go 1.1 release because the former User-Agent
-// had ended up on a blacklist for some intrusion detection systems.
+// It was changed from "Go http package" to "Go 1.1 package http" at the
+// time of the Go 1.1 release because the former User-Agent had ended up
+// on a blacklist for some intrusion detection systems.
 // See https://codereview.appspot.com/7532043.
-const defaultUserAgent = "Go-http-client/1.1"
+const defaultUserAgent = "Go 1.1 package http"
 
-// Write writes an HTTP/1.1 request, which is the header and body, in wire format.
+// Write writes an HTTP/1.1 request -- header and body -- in wire format.
 // This method consults the following fields of the request:
 //	Host
 //	URL
@@ -369,23 +364,14 @@ func (r *Request) WriteProxy(w io.Writer) error {
 
 // extraHeaders may be nil
 func (req *Request) write(w io.Writer, usingProxy bool, extraHeaders Header) error {
-	// Find the target host. Prefer the Host: header, but if that
-	// is not given, use the host from the request URL.
-	//
-	// Clean the host, in case it arrives with unexpected stuff in it.
-	host := cleanHost(req.Host)
+	host := req.Host
 	if host == "" {
 		if req.URL == nil {
 			return errors.New("http: Request.Write on Request with no Host or URL set")
 		}
-		host = cleanHost(req.URL.Host)
+		host = req.URL.Host
 	}
 
-	// According to RFC 6874, an HTTP client, proxy, or other
-	// intermediary must remove any IPv6 zone identifier attached
-	// to an outgoing URI.
-	host = removeZone(host)
-
 	ruri := req.URL.RequestURI()
 	if usingProxy && req.URL.Scheme != "" && req.URL.Opaque == "" {
 		ruri = req.URL.Scheme + "://" + host + ruri
@@ -470,39 +456,6 @@ func (req *Request) write(w io.Writer, usingProxy bool, extraHeaders Header) err
 	return nil
 }
 
-// cleanHost strips anything after '/' or ' '.
-// Ideally we'd clean the Host header according to the spec:
-//   https://tools.ietf.org/html/rfc7230#section-5.4 (Host = uri-host [ ":" port ]")
-//   https://tools.ietf.org/html/rfc7230#section-2.7 (uri-host -> rfc3986's host)
-//   https://tools.ietf.org/html/rfc3986#section-3.2.2 (definition of host)
-// But practically, what we are trying to avoid is the situation in
-// issue 11206, where a malformed Host header used in the proxy context
-// would create a bad request. So it is enough to just truncate at the
-// first offending character.
-func cleanHost(in string) string {
-	if i := strings.IndexAny(in, " /"); i != -1 {
-		return in[:i]
-	}
-	return in
-}
-
-// removeZone removes IPv6 zone identifer from host.
-// E.g., "[fe80::1%en0]:8080" to "[fe80::1]:8080"
-func removeZone(host string) string {
-	if !strings.HasPrefix(host, "[") {
-		return host
-	}
-	i := strings.LastIndex(host, "]")
-	if i < 0 {
-		return host
-	}
-	j := strings.LastIndex(host[:i], "%")
-	if j < 0 {
-		return host
-	}
-	return host[:j] + host[i:]
-}
-
 // ParseHTTPVersion parses a HTTP version string.
 // "HTTP/1.0" returns (1, 0, true).
 func ParseHTTPVersion(vers string) (major, minor int, ok bool) {
@@ -536,13 +489,6 @@ func ParseHTTPVersion(vers string) (major, minor int, ok bool) {
 // If the provided body is also an io.Closer, the returned
 // Request.Body is set to body and will be closed by the Client
 // methods Do, Post, and PostForm, and Transport.RoundTrip.
-//
-// NewRequest returns a Request suitable for use with Client.Do or
-// Transport.RoundTrip.
-// To create a request for use with testing a Server Handler use either
-// ReadRequest or manually update the Request fields. See the Request
-// type's documentation for the difference between inbound and outbound
-// request fields.
 func NewRequest(method, urlStr string, body io.Reader) (*Request, error) {
 	u, err := url.Parse(urlStr)
 	if err != nil {
@@ -590,11 +536,10 @@ func (r *Request) BasicAuth() (username, password string, ok bool) {
 // parseBasicAuth parses an HTTP Basic Authentication string.
 // "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==" returns ("Aladdin", "open sesame", true).
 func parseBasicAuth(auth string) (username, password string, ok bool) {
-	const prefix = "Basic "
-	if !strings.HasPrefix(auth, prefix) {
+	if !strings.HasPrefix(auth, "Basic ") {
 		return
 	}
-	c, err := base64.StdEncoding.DecodeString(auth[len(prefix):])
+	c, err := base64.StdEncoding.DecodeString(strings.TrimPrefix(auth, "Basic "))
 	if err != nil {
 		return
 	}
@@ -642,7 +587,7 @@ func putTextprotoReader(r *textproto.Reader) {
 	textprotoReaderPool.Put(r)
 }
 
-// ReadRequest reads and parses an incoming request from b.
+// ReadRequest reads and parses a request from b.
 func ReadRequest(b *bufio.Reader) (req *Request, err error) {
 
 	tp := newTextprotoReader(b)
@@ -715,20 +660,19 @@ func ReadRequest(b *bufio.Reader) (req *Request, err error) {
 
 	fixPragmaCacheControl(req.Header)
 
-	req.Close = shouldClose(req.ProtoMajor, req.ProtoMinor, req.Header, false)
-
 	err = readTransfer(req, b)
 	if err != nil {
 		return nil, err
 	}
 
+	req.Close = shouldClose(req.ProtoMajor, req.ProtoMinor, req.Header, false)
 	return req, nil
 }
 
 // MaxBytesReader is similar to io.LimitReader but is intended for
 // limiting the size of incoming request bodies. In contrast to
 // io.LimitReader, MaxBytesReader's result is a ReadCloser, returns a
-// non-EOF error for a Read beyond the limit, and closes the
+// non-EOF error for a Read beyond the limit, and Closes the
 // underlying reader when its Close method is called.
 //
 // MaxBytesReader prevents clients from accidentally or maliciously
@@ -742,52 +686,23 @@ type maxBytesReader struct {
 	r       io.ReadCloser // underlying reader
 	n       int64         // max bytes remaining
 	stopped bool
-	sawEOF  bool
-}
-
-func (l *maxBytesReader) tooLarge() (n int, err error) {
-	if !l.stopped {
-		l.stopped = true
-		if res, ok := l.w.(*response); ok {
-			res.requestTooLarge()
-		}
-	}
-	return 0, errors.New("http: request body too large")
 }
 
 func (l *maxBytesReader) Read(p []byte) (n int, err error) {
-	toRead := l.n
-	if l.n == 0 {
-		if l.sawEOF {
-			return l.tooLarge()
+	if l.n <= 0 {
+		if !l.stopped {
+			l.stopped = true
+			if res, ok := l.w.(*response); ok {
+				res.requestTooLarge()
+			}
 		}
-		// The underlying io.Reader may not return (0, io.EOF)
-		// at EOF if the requested size is 0, so read 1 byte
-		// instead. The io.Reader docs are a bit ambiguous
-		// about the return value of Read when 0 bytes are
-		// requested, and {bytes,strings}.Reader gets it wrong
-		// too (it returns (0, nil) even at EOF).
-		toRead = 1
+		return 0, errors.New("http: request body too large")
 	}
-	if int64(len(p)) > toRead {
-		p = p[:toRead]
+	if int64(len(p)) > l.n {
+		p = p[:l.n]
 	}
 	n, err = l.r.Read(p)
-	if err == io.EOF {
-		l.sawEOF = true
-	}
-	if l.n == 0 {
-		// If we had zero bytes to read remaining (but hadn't seen EOF)
-		// and we get a byte here, that means we went over our limit.
-		if n > 0 {
-			return l.tooLarge()
-		}
-		return 0, err
-	}
 	l.n -= int64(n)
-	if l.n < 0 {
-		l.n = 0
-	}
 	return
 }
 
@@ -937,7 +852,6 @@ func (r *Request) ParseMultipartForm(maxMemory int64) error {
 // POST and PUT body parameters take precedence over URL query string values.
 // FormValue calls ParseMultipartForm and ParseForm if necessary and ignores
 // any errors returned by these functions.
-// If key is not present, FormValue returns the empty string.
 // To access multiple values of the same key, call ParseForm and
 // then inspect Request.Form directly.
 func (r *Request) FormValue(key string) string {
@@ -954,7 +868,6 @@ func (r *Request) FormValue(key string) string {
 // or PUT request body. URL query parameters are ignored.
 // PostFormValue calls ParseMultipartForm and ParseForm if necessary and ignores
 // any errors returned by these functions.
-// If key is not present, PostFormValue returns the empty string.
 func (r *Request) PostFormValue(key string) string {
 	if r.PostForm == nil {
 		r.ParseMultipartForm(defaultMaxMemory)
diff --git a/src/net/http/request_test.go b/src/net/http/request_test.go
index 627620c..759ea4e 100644
--- a/src/net/http/request_test.go
+++ b/src/net/http/request_test.go
@@ -178,7 +178,6 @@ func TestParseMultipartForm(t *testing.T) {
 }
 
 func TestRedirect(t *testing.T) {
-	defer afterTest(t)
 	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
 		switch r.URL.Path {
 		case "/":
@@ -327,31 +326,13 @@ func TestReadRequestErrors(t *testing.T) {
 	}
 }
 
-var newRequestHostTests = []struct {
-	in, out string
-}{
-	{"http://www.example.com/", "www.example.com"},
-	{"http://www.example.com:8080/", "www.example.com:8080"},
-
-	{"http://192.168.0.1/", "192.168.0.1"},
-	{"http://192.168.0.1:8080/", "192.168.0.1:8080"},
-
-	{"http://[fe80::1]/", "[fe80::1]"},
-	{"http://[fe80::1]:8080/", "[fe80::1]:8080"},
-	{"http://[fe80::1%25en0]/", "[fe80::1%en0]"},
-	{"http://[fe80::1%25en0]:8080/", "[fe80::1%en0]:8080"},
-}
-
 func TestNewRequestHost(t *testing.T) {
-	for i, tt := range newRequestHostTests {
-		req, err := NewRequest("GET", tt.in, nil)
-		if err != nil {
-			t.Errorf("#%v: %v", i, err)
-			continue
-		}
-		if req.Host != tt.out {
-			t.Errorf("got %q; want %q", req.Host, tt.out)
-		}
+	req, err := NewRequest("GET", "http://localhost:1234/", nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if req.Host != "localhost:1234" {
+		t.Errorf("Host = %q; want localhost:1234", req.Host)
 	}
 }
 
@@ -421,6 +402,8 @@ type getBasicAuthTest struct {
 	ok                 bool
 }
 
+type parseBasicAuthTest getBasicAuthTest
+
 type basicAuthCredentialsTest struct {
 	username, password string
 }
@@ -513,82 +496,6 @@ func TestRequestWriteBufferedWriter(t *testing.T) {
 	}
 }
 
-func TestRequestBadHost(t *testing.T) {
-	got := []string{}
-	req, err := NewRequest("GET", "http://foo.com with spaces/after", nil)
-	if err != nil {
-		t.Fatal(err)
-	}
-	req.Write(logWrites{t, &got})
-	want := []string{
-		"GET /after HTTP/1.1\r\n",
-		"Host: foo.com\r\n",
-		"User-Agent: " + DefaultUserAgent + "\r\n",
-		"\r\n",
-	}
-	if !reflect.DeepEqual(got, want) {
-		t.Errorf("Writes = %q\n  Want = %q", got, want)
-	}
-}
-
-func TestStarRequest(t *testing.T) {
-	req, err := ReadRequest(bufio.NewReader(strings.NewReader("M-SEARCH * HTTP/1.1\r\n\r\n")))
-	if err != nil {
-		return
-	}
-	var out bytes.Buffer
-	if err := req.Write(&out); err != nil {
-		t.Fatal(err)
-	}
-	back, err := ReadRequest(bufio.NewReader(&out))
-	if err != nil {
-		t.Fatal(err)
-	}
-	// Ignore the Headers (the User-Agent breaks the deep equal,
-	// but we don't care about it)
-	req.Header = nil
-	back.Header = nil
-	if !reflect.DeepEqual(req, back) {
-		t.Errorf("Original request doesn't match Request read back.")
-		t.Logf("Original: %#v", req)
-		t.Logf("Original.URL: %#v", req.URL)
-		t.Logf("Wrote: %s", out.Bytes())
-		t.Logf("Read back (doesn't match Original): %#v", back)
-	}
-}
-
-type responseWriterJustWriter struct {
-	io.Writer
-}
-
-func (responseWriterJustWriter) Header() Header  { panic("should not be called") }
-func (responseWriterJustWriter) WriteHeader(int) { panic("should not be called") }
-
-// delayedEOFReader never returns (n > 0, io.EOF), instead putting
-// off the io.EOF until a subsequent Read call.
-type delayedEOFReader struct {
-	r io.Reader
-}
-
-func (dr delayedEOFReader) Read(p []byte) (n int, err error) {
-	n, err = dr.r.Read(p)
-	if n > 0 && err == io.EOF {
-		err = nil
-	}
-	return
-}
-
-func TestIssue10884_MaxBytesEOF(t *testing.T) {
-	dst := ioutil.Discard
-	_, err := io.Copy(dst, MaxBytesReader(
-		responseWriterJustWriter{dst},
-		ioutil.NopCloser(delayedEOFReader{strings.NewReader("12345")}),
-		5))
-	if err != nil {
-		t.Fatal(err)
-	}
-}
-
 func testMissingFile(t *testing.T, req *Request) {
 	f, fh, err := req.FormFile("missing")
 	if f != nil {
diff --git a/src/net/http/requestwrite_test.go b/src/net/http/requestwrite_test.go
index cfb95b0..7a6bd58 100644
--- a/src/net/http/requestwrite_test.go
+++ b/src/net/http/requestwrite_test.go
@@ -93,13 +93,13 @@ var reqWriteTests = []reqWriteTest{
 
 		WantWrite: "GET /search HTTP/1.1\r\n" +
 			"Host: www.google.com\r\n" +
-			"User-Agent: Go-http-client/1.1\r\n" +
+			"User-Agent: Go 1.1 package http\r\n" +
 			"Transfer-Encoding: chunked\r\n\r\n" +
 			chunk("abcdef") + chunk(""),
 
 		WantProxy: "GET http://www.google.com/search HTTP/1.1\r\n" +
 			"Host: www.google.com\r\n" +
-			"User-Agent: Go-http-client/1.1\r\n" +
+			"User-Agent: Go 1.1 package http\r\n" +
 			"Transfer-Encoding: chunked\r\n\r\n" +
 			chunk("abcdef") + chunk(""),
 	},
@@ -123,14 +123,14 @@ var reqWriteTests = []reqWriteTest{
 
 		WantWrite: "POST /search HTTP/1.1\r\n" +
 			"Host: www.google.com\r\n" +
-			"User-Agent: Go-http-client/1.1\r\n" +
+			"User-Agent: Go 1.1 package http\r\n" +
 			"Connection: close\r\n" +
 			"Transfer-Encoding: chunked\r\n\r\n" +
 			chunk("abcdef") + chunk(""),
 
 		WantProxy: "POST http://www.google.com/search HTTP/1.1\r\n" +
 			"Host: www.google.com\r\n" +
-			"User-Agent: Go-http-client/1.1\r\n" +
+			"User-Agent: Go 1.1 package http\r\n" +
 			"Connection: close\r\n" +
 			"Transfer-Encoding: chunked\r\n\r\n" +
 			chunk("abcdef") + chunk(""),
@@ -156,7 +156,7 @@ var reqWriteTests = []reqWriteTest{
 
 		WantWrite: "POST /search HTTP/1.1\r\n" +
 			"Host: www.google.com\r\n" +
-			"User-Agent: Go-http-client/1.1\r\n" +
+			"User-Agent: Go 1.1 package http\r\n" +
 			"Connection: close\r\n" +
 			"Content-Length: 6\r\n" +
 			"\r\n" +
@@ -164,7 +164,7 @@ var reqWriteTests = []reqWriteTest{
 
 		WantProxy: "POST http://www.google.com/search HTTP/1.1\r\n" +
 			"Host: www.google.com\r\n" +
-			"User-Agent: Go-http-client/1.1\r\n" +
+			"User-Agent: Go 1.1 package http\r\n" +
 			"Connection: close\r\n" +
 			"Content-Length: 6\r\n" +
 			"\r\n" +
@@ -187,14 +187,14 @@ var reqWriteTests = []reqWriteTest{
 
 		WantWrite: "POST / HTTP/1.1\r\n" +
 			"Host: example.com\r\n" +
-			"User-Agent: Go-http-client/1.1\r\n" +
+			"User-Agent: Go 1.1 package http\r\n" +
 			"Content-Length: 6\r\n" +
 			"\r\n" +
 			"abcdef",
 
 		WantProxy: "POST http://example.com/ HTTP/1.1\r\n" +
 			"Host: example.com\r\n" +
-			"User-Agent: Go-http-client/1.1\r\n" +
+			"User-Agent: Go 1.1 package http\r\n" +
 			"Content-Length: 6\r\n" +
 			"\r\n" +
 			"abcdef",
@@ -210,7 +210,7 @@ var reqWriteTests = []reqWriteTest{
 
 		WantWrite: "GET /search HTTP/1.1\r\n" +
 			"Host: www.google.com\r\n" +
-			"User-Agent: Go-http-client/1.1\r\n" +
+			"User-Agent: Go 1.1 package http\r\n" +
 			"\r\n",
 	},
 
@@ -232,13 +232,13 @@ var reqWriteTests = []reqWriteTest{
 		// Also, nginx expects it for POST and PUT.
 		WantWrite: "POST / HTTP/1.1\r\n" +
 			"Host: example.com\r\n" +
-			"User-Agent: Go-http-client/1.1\r\n" +
+			"User-Agent: Go 1.1 package http\r\n" +
 			"Content-Length: 0\r\n" +
 			"\r\n",
 
 		WantProxy: "POST / HTTP/1.1\r\n" +
 			"Host: example.com\r\n" +
-			"User-Agent: Go-http-client/1.1\r\n" +
+			"User-Agent: Go 1.1 package http\r\n" +
 			"Content-Length: 0\r\n" +
 			"\r\n",
 	},
@@ -258,13 +258,13 @@ var reqWriteTests = []reqWriteTest{
 
 		WantWrite: "POST / HTTP/1.1\r\n" +
 			"Host: example.com\r\n" +
-			"User-Agent: Go-http-client/1.1\r\n" +
+			"User-Agent: Go 1.1 package http\r\n" +
 			"Transfer-Encoding: chunked\r\n\r\n" +
 			chunk("x") + chunk(""),
 
 		WantProxy: "POST / HTTP/1.1\r\n" +
 			"Host: example.com\r\n" +
-			"User-Agent: Go-http-client/1.1\r\n" +
+			"User-Agent: Go 1.1 package http\r\n" +
 			"Transfer-Encoding: chunked\r\n\r\n" +
 			chunk("x") + chunk(""),
 	},
@@ -365,7 +365,7 @@ var reqWriteTests = []reqWriteTest{
 
 		WantWrite: "GET /foo HTTP/1.1\r\n" +
 			"Host: \r\n" +
-			"User-Agent: Go-http-client/1.1\r\n" +
+			"User-Agent: Go 1.1 package http\r\n" +
 			"X-Foo: X-Bar\r\n\r\n",
 	},
 
@@ -391,7 +391,7 @@ var reqWriteTests = []reqWriteTest{
 
 		WantWrite: "GET /search HTTP/1.1\r\n" +
 			"Host: \r\n" +
-			"User-Agent: Go-http-client/1.1\r\n\r\n",
+			"User-Agent: Go 1.1 package http\r\n\r\n",
 	},
 
 	// Opaque test #1 from golang.org/issue/4860
@@ -410,7 +410,7 @@ var reqWriteTests = []reqWriteTest{
 
 		WantWrite: "GET /%2F/%2F/ HTTP/1.1\r\n" +
 			"Host: www.google.com\r\n" +
-			"User-Agent: Go-http-client/1.1\r\n\r\n",
+			"User-Agent: Go 1.1 package http\r\n\r\n",
 	},
 
 	// Opaque test #2 from golang.org/issue/4860
@@ -429,7 +429,7 @@ var reqWriteTests = []reqWriteTest{
 
 		WantWrite: "GET http://y.google.com/%2F/%2F/ HTTP/1.1\r\n" +
 			"Host: x.google.com\r\n" +
-			"User-Agent: Go-http-client/1.1\r\n\r\n",
+			"User-Agent: Go 1.1 package http\r\n\r\n",
 	},
 
 	// Testing custom case in header keys. Issue 5022.
@@ -451,41 +451,10 @@ var reqWriteTests = []reqWriteTest{
 
 		WantWrite: "GET / HTTP/1.1\r\n" +
 			"Host: www.google.com\r\n" +
-			"User-Agent: Go-http-client/1.1\r\n" +
+			"User-Agent: Go 1.1 package http\r\n" +
 			"ALL-CAPS: x\r\n" +
 			"\r\n",
 	},
-
-	// Request with host header field; IPv6 address with zone identifier
-	{
-		Req: Request{
-			Method: "GET",
-			URL: &url.URL{
-				Host: "[fe80::1%en0]",
-			},
-		},
-
-		WantWrite: "GET / HTTP/1.1\r\n" +
-			"Host: [fe80::1]\r\n" +
-			"User-Agent: Go-http-client/1.1\r\n" +
-			"\r\n",
-	},
-
-	// Request with optional host header field; IPv6 address with zone identifier
-	{
-		Req: Request{
-			Method: "GET",
-			URL: &url.URL{
-				Host: "www.example.com",
-			},
-			Host: "[fe80::1%en0]:8080",
-		},
-
-		WantWrite: "GET / HTTP/1.1\r\n" +
-			"Host: [fe80::1]:8080\r\n" +
-			"User-Agent: Go-http-client/1.1\r\n" +
-			"\r\n",
-	},
 }
 
 func TestRequestWrite(t *testing.T) {
@@ -569,7 +538,7 @@ func TestRequestWriteClosesBody(t *testing.T) {
 	}
 	expected := "POST / HTTP/1.1\r\n" +
 		"Host: foo.com\r\n" +
-		"User-Agent: Go-http-client/1.1\r\n" +
+		"User-Agent: Go 1.1 package http\r\n" +
 		"Transfer-Encoding: chunked\r\n\r\n" +
 		// TODO: currently we don't buffer before chunking, so we get a
 		// single "m" chunk before the other chunks, as this was the 1-byte
diff --git a/src/net/http/response.go b/src/net/http/response.go
index 76b8538..5d2c390 100644
--- a/src/net/http/response.go
+++ b/src/net/http/response.go
@@ -48,10 +48,7 @@ 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-length body. It is the caller's responsibility to
-	// close Body. The default HTTP client's Transport does not
-	// attempt to reuse HTTP/1.0 or HTTP/1.1 TCP connections
-	// ("keep-alive") unless the Body is read to completion and is
-	// closed.
+	// close Body.
 	//
 	// The Body is automatically dechunked if the server replied
 	// with a "chunked" Transfer-Encoding.
@@ -93,8 +90,6 @@ func (r *Response) Cookies() []*Cookie {
 	return readSetCookies(r.Header)
 }
 
-// ErrNoLocation is returned by Response's Location method
-// when no Location header is present.
 var ErrNoLocation = errors.New("http: no Location header in response")
 
 // Location returns the URL of the response's "Location" header,
@@ -191,10 +186,8 @@ func (r *Response) ProtoAtLeast(major, minor int) bool {
 		r.ProtoMajor == major && r.ProtoMinor >= minor
 }
 
-// Write writes r to w in the HTTP/1.n server response format,
-// including the status line, headers, body, and optional trailer.
-//
-// This method consults the following fields of the response r:
+// Writes the response (header, body and trailer) in wire format. This method
+// consults the following fields of the response:
 //
 //  StatusCode
 //  ProtoMajor
@@ -206,7 +199,7 @@ func (r *Response) ProtoAtLeast(major, minor int) bool {
 //  ContentLength
 //  Header, values for non-canonical keys will have unpredictable behavior
 //
-// The Response Body is closed after it is sent.
+// Body is closed after it is sent.
 func (r *Response) Write(w io.Writer) error {
 	// Status line
 	text := r.Status
diff --git a/src/net/http/response_test.go b/src/net/http/response_test.go
index 421cf55..06e940d 100644
--- a/src/net/http/response_test.go
+++ b/src/net/http/response_test.go
@@ -405,57 +405,6 @@ some body`,
 
 		"foobar",
 	},
-
-	// Both keep-alive and close, on the same Connection line. (Issue 8840)
-	{
-		"HTTP/1.1 200 OK\r\n" +
-			"Content-Length: 256\r\n" +
-			"Connection: keep-alive, close\r\n" +
-			"\r\n",
-
-		Response{
-			Status:     "200 OK",
-			StatusCode: 200,
-			Proto:      "HTTP/1.1",
-			ProtoMajor: 1,
-			ProtoMinor: 1,
-			Request:    dummyReq("HEAD"),
-			Header: Header{
-				"Content-Length": {"256"},
-			},
-			TransferEncoding: nil,
-			Close:            true,
-			ContentLength:    256,
-		},
-
-		"",
-	},
-
-	// Both keep-alive and close, on different Connection lines. (Issue 8840)
-	{
-		"HTTP/1.1 200 OK\r\n" +
-			"Content-Length: 256\r\n" +
-			"Connection: keep-alive\r\n" +
-			"Connection: close\r\n" +
-			"\r\n",
-
-		Response{
-			Status:     "200 OK",
-			StatusCode: 200,
-			Proto:      "HTTP/1.1",
-			ProtoMajor: 1,
-			ProtoMinor: 1,
-			Request:    dummyReq("HEAD"),
-			Header: Header{
-				"Content-Length": {"256"},
-			},
-			TransferEncoding: nil,
-			Close:            true,
-			ContentLength:    256,
-		},
-
-		"",
-	},
 }
 
 func TestReadResponse(t *testing.T) {
diff --git a/src/net/http/responsewrite_test.go b/src/net/http/responsewrite_test.go
index 5b8d47a..585b13b 100644
--- a/src/net/http/responsewrite_test.go
+++ b/src/net/http/responsewrite_test.go
@@ -207,21 +207,6 @@ func TestResponseWrite(t *testing.T) {
 			},
 			"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n",
 		},
-
-		// When a response to a POST has Content-Length: -1, make sure we don't
-		// write the Content-Length as -1.
-		{
-			Response{
-				StatusCode:    StatusOK,
-				ProtoMajor:    1,
-				ProtoMinor:    1,
-				Request:       &Request{Method: "POST"},
-				Header:        Header{},
-				ContentLength: -1,
-				Body:          ioutil.NopCloser(strings.NewReader("abcdef")),
-			},
-			"HTTP/1.1 200 OK\r\nConnection: close\r\n\r\nabcdef",
-		},
 	}
 
 	for i := range respWriteTests {
diff --git a/src/net/http/serve_test.go b/src/net/http/serve_test.go
index d51417e..5e0a005 100644
--- a/src/net/http/serve_test.go
+++ b/src/net/http/serve_test.go
@@ -20,7 +20,6 @@ import (
 	. "net/http"
 	"net/http/httptest"
 	"net/http/httputil"
-	"net/http/internal"
 	"net/url"
 	"os"
 	"os/exec"
@@ -147,7 +146,6 @@ func (ht handlerTest) rawResponse(req string) string {
 }
 
 func TestConsumingBodyOnNextConn(t *testing.T) {
-	defer afterTest(t)
 	conn := new(testConn)
 	for i := 0; i < 2; i++ {
 		conn.readBuf.Write([]byte(
@@ -207,7 +205,6 @@ var handlers = []struct {
 }{
 	{"/", "Default"},
 	{"/someDir/", "someDir"},
-	{"/#/", "hash"},
 	{"someHost.com/someDir/", "someHost.com/someDir"},
 }
 
@@ -216,14 +213,12 @@ var vtests = []struct {
 	expected string
 }{
 	{"http://localhost/someDir/apage", "someDir"},
-	{"http://localhost/%23/apage", "hash"},
 	{"http://localhost/otherDir/apage", "Default"},
 	{"http://someHost.com/someDir/apage", "someHost.com/someDir"},
 	{"http://otherHost.com/someDir/apage", "someDir"},
 	{"http://otherHost.com/aDir/apage", "Default"},
 	// redirections for trees
 	{"http://localhost/someDir", "/someDir/"},
-	{"http://localhost/%23", "/%23/"},
 	{"http://someHost.com/someDir", "/someDir/"},
 }
 
@@ -421,7 +416,7 @@ func TestServeMuxHandlerRedirects(t *testing.T) {
 	}
 }
 
-// Tests for https://golang.org/issue/900
+// Tests for http://code.google.com/p/go/issues/detail?id=900
 func TestMuxRedirectLeadingSlashes(t *testing.T) {
 	paths := []string{"//foo.txt", "///foo.txt", "/../../foo.txt"}
 	for _, path := range paths {
@@ -448,7 +443,7 @@ func TestMuxRedirectLeadingSlashes(t *testing.T) {
 
 func TestServerTimeouts(t *testing.T) {
 	if runtime.GOOS == "plan9" {
-		t.Skip("skipping test; see https://golang.org/issue/7237")
+		t.Skip("skipping test; see http://golang.org/issue/7237")
 	}
 	defer afterTest(t)
 	reqNum := 0
@@ -527,7 +522,7 @@ func TestServerTimeouts(t *testing.T) {
 // request) that will never happen.
 func TestOnlyWriteTimeout(t *testing.T) {
 	if runtime.GOOS == "plan9" {
-		t.Skip("skipping test; see https://golang.org/issue/7237")
+		t.Skip("skipping test; see http://golang.org/issue/7237")
 	}
 	defer afterTest(t)
 	var conn net.Conn
@@ -882,7 +877,7 @@ func TestHeadResponses(t *testing.T) {
 
 func TestTLSHandshakeTimeout(t *testing.T) {
 	if runtime.GOOS == "plan9" {
-		t.Skip("skipping test; see https://golang.org/issue/7237")
+		t.Skip("skipping test; see http://golang.org/issue/7237")
 	}
 	defer afterTest(t)
 	ts := httptest.NewUnstartedServer(HandlerFunc(func(w ResponseWriter, r *Request) {}))
@@ -1110,7 +1105,6 @@ func TestServerExpect(t *testing.T) {
 // Under a ~256KB (maxPostHandlerReadBytes) threshold, the server
 // should consume client request bodies that a handler didn't read.
 func TestServerUnreadRequestBodyLittle(t *testing.T) {
-	defer afterTest(t)
 	conn := new(testConn)
 	body := strings.Repeat("x", 100<<10)
 	conn.readBuf.Write([]byte(fmt.Sprintf(
@@ -1172,365 +1166,6 @@ func TestServerUnreadRequestBodyLarge(t *testing.T) {
 	}
 }
 
-type handlerBodyCloseTest struct {
-	bodySize     int
-	bodyChunked  bool
-	reqConnClose bool
-
-	wantEOFSearch bool // should Handler's Body.Close do Reads, looking for EOF?
-	wantNextReq   bool // should it find the next request on the same conn?
-}
-
-func (t handlerBodyCloseTest) connectionHeader() string {
-	if t.reqConnClose {
-		return "Connection: close\r\n"
-	}
-	return ""
-}
-
-var handlerBodyCloseTests = [...]handlerBodyCloseTest{
-	// Small enough to slurp past to the next request +
-	// has Content-Length.
-	0: {
-		bodySize:      20 << 10,
-		bodyChunked:   false,
-		reqConnClose:  false,
-		wantEOFSearch: true,
-		wantNextReq:   true,
-	},
-
-	// Small enough to slurp past to the next request +
-	// is chunked.
-	1: {
-		bodySize:      20 << 10,
-		bodyChunked:   true,
-		reqConnClose:  false,
-		wantEOFSearch: true,
-		wantNextReq:   true,
-	},
-
-	// Small enough to slurp past to the next request +
-	// has Content-Length +
-	// declares Connection: close (so pointless to read more).
-	2: {
-		bodySize:      20 << 10,
-		bodyChunked:   false,
-		reqConnClose:  true,
-		wantEOFSearch: false,
-		wantNextReq:   false,
-	},
-
-	// Small enough to slurp past to the next request +
-	// declares Connection: close,
-	// but chunked, so it might have trailers.
-	// TODO: maybe skip this search if no trailers were declared
-	// in the headers.
-	3: {
-		bodySize:      20 << 10,
-		bodyChunked:   true,
-		reqConnClose:  true,
-		wantEOFSearch: true,
-		wantNextReq:   false,
-	},
-
-	// Big with Content-Length, so give up immediately if we know it's too big.
-	4: {
-		bodySize:      1 << 20,
-		bodyChunked:   false, // has a Content-Length
-		reqConnClose:  false,
-		wantEOFSearch: false,
-		wantNextReq:   false,
-	},
-
-	// Big chunked, so read a bit before giving up.
-	5: {
-		bodySize:      1 << 20,
-		bodyChunked:   true,
-		reqConnClose:  false,
-		wantEOFSearch: true,
-		wantNextReq:   false,
-	},
-
-	// Big with Connection: close, but chunked, so search for trailers.
-	// TODO: maybe skip this search if no trailers were declared
-	// in the headers.
-	6: {
-		bodySize:      1 << 20,
-		bodyChunked:   true,
-		reqConnClose:  true,
-		wantEOFSearch: true,
-		wantNextReq:   false,
-	},
-
-	// Big with Connection: close, so don't do any reads on Close.
-	// With Content-Length.
-	7: {
-		bodySize:      1 << 20,
-		bodyChunked:   false,
-		reqConnClose:  true,
-		wantEOFSearch: false,
-		wantNextReq:   false,
-	},
-}
-
-func TestHandlerBodyClose(t *testing.T) {
-	for i, tt := range handlerBodyCloseTests {
-		testHandlerBodyClose(t, i, tt)
-	}
-}
-
-func testHandlerBodyClose(t *testing.T, i int, tt handlerBodyCloseTest) {
-	conn := new(testConn)
-	body := strings.Repeat("x", tt.bodySize)
-	if tt.bodyChunked {
-		conn.readBuf.WriteString("POST / HTTP/1.1\r\n" +
-			"Host: test\r\n" +
-			tt.connectionHeader() +
-			"Transfer-Encoding: chunked\r\n" +
-			"\r\n")
-		cw := internal.NewChunkedWriter(&conn.readBuf)
-		io.WriteString(cw, body)
-		cw.Close()
-		conn.readBuf.WriteString("\r\n")
-	} else {
-		conn.readBuf.Write([]byte(fmt.Sprintf(
-			"POST / HTTP/1.1\r\n"+
-				"Host: test\r\n"+
-				tt.connectionHeader()+
-				"Content-Length: %d\r\n"+
-				"\r\n", len(body))))
-		conn.readBuf.Write([]byte(body))
-	}
-	if !tt.reqConnClose {
-		conn.readBuf.WriteString("GET / HTTP/1.1\r\nHost: test\r\n\r\n")
-	}
-	conn.closec = make(chan bool, 1)
-
-	ls := &oneConnListener{conn}
-	var numReqs int
-	var size0, size1 int
-	go Serve(ls, HandlerFunc(func(rw ResponseWriter, req *Request) {
-		numReqs++
-		if numReqs == 1 {
-			size0 = conn.readBuf.Len()
-			req.Body.Close()
-			size1 = conn.readBuf.Len()
-		}
-	}))
-	<-conn.closec
-	if numReqs < 1 || numReqs > 2 {
-		t.Fatalf("%d. bug in test. unexpected number of requests = %d", i, numReqs)
-	}
-	didSearch := size0 != size1
-	if didSearch != tt.wantEOFSearch {
-		t.Errorf("%d. did EOF search = %v; want %v (size went from %d to %d)", i, didSearch, !didSearch, size0, size1)
-	}
-	if tt.wantNextReq && numReqs != 2 {
-		t.Errorf("%d. numReq = %d; want 2", i, numReqs)
-	}
-}
-
-// testHandlerBodyConsumer represents a function injected into a test handler to
-// vary work done on a request Body.
-type testHandlerBodyConsumer struct {
-	name string
-	f    func(io.ReadCloser)
-}
-
-var testHandlerBodyConsumers = []testHandlerBodyConsumer{
-	{"nil", func(io.ReadCloser) {}},
-	{"close", func(r io.ReadCloser) { r.Close() }},
-	{"discard", func(r io.ReadCloser) { io.Copy(ioutil.Discard, r) }},
-}
-
-func TestRequestBodyReadErrorClosesConnection(t *testing.T) {
-	defer afterTest(t)
-	for _, handler := range testHandlerBodyConsumers {
-		conn := new(testConn)
-		conn.readBuf.WriteString("POST /public HTTP/1.1\r\n" +
-			"Host: test\r\n" +
-			"Transfer-Encoding: chunked\r\n" +
-			"\r\n" +
-			"hax\r\n" + // Invalid chunked encoding
-			"GET /secret HTTP/1.1\r\n" +
-			"Host: test\r\n" +
-			"\r\n")
-
-		conn.closec = make(chan bool, 1)
-		ls := &oneConnListener{conn}
-		var numReqs int
-		go Serve(ls, HandlerFunc(func(_ ResponseWriter, req *Request) {
-			numReqs++
-			if strings.Contains(req.URL.Path, "secret") {
-				t.Error("Request for /secret encountered, should not have happened.")
-			}
-			handler.f(req.Body)
-		}))
-		<-conn.closec
-		if numReqs != 1 {
-			t.Errorf("Handler %v: got %d reqs; want 1", handler.name, numReqs)
-		}
-	}
-}
-
-func TestInvalidTrailerClosesConnection(t *testing.T) {
-	defer afterTest(t)
-	for _, handler := range testHandlerBodyConsumers {
-		conn := new(testConn)
-		conn.readBuf.WriteString("POST /public HTTP/1.1\r\n" +
-			"Host: test\r\n" +
-			"Trailer: hack\r\n" +
-			"Transfer-Encoding: chunked\r\n" +
-			"\r\n" +
-			"3\r\n" +
-			"hax\r\n" +
-			"0\r\n" +
-			"I'm not a valid trailer\r\n" +
-			"GET /secret HTTP/1.1\r\n" +
-			"Host: test\r\n" +
-			"\r\n")
-
-		conn.closec = make(chan bool, 1)
-		ln := &oneConnListener{conn}
-		var numReqs int
-		go Serve(ln, HandlerFunc(func(_ ResponseWriter, req *Request) {
-			numReqs++
-			if strings.Contains(req.URL.Path, "secret") {
-				t.Errorf("Handler %s, Request for /secret encountered, should not have happened.", handler.name)
-			}
-			handler.f(req.Body)
-		}))
-		<-conn.closec
-		if numReqs != 1 {
-			t.Errorf("Handler %s: got %d reqs; want 1", handler.name, numReqs)
-		}
-	}
-}
-
-// slowTestConn is a net.Conn that provides a means to simulate parts of a
-// request being received piecemeal. Deadlines can be set and enforced in both
-// Read and Write.
-type slowTestConn struct {
-	// over multiple calls to Read, time.Durations are slept, strings are read.
-	script []interface{}
-	closec chan bool
-	rd, wd time.Time // read, write deadline
-	noopConn
-}
-
-func (c *slowTestConn) SetDeadline(t time.Time) error {
-	c.SetReadDeadline(t)
-	c.SetWriteDeadline(t)
-	return nil
-}
-
-func (c *slowTestConn) SetReadDeadline(t time.Time) error {
-	c.rd = t
-	return nil
-}
-
-func (c *slowTestConn) SetWriteDeadline(t time.Time) error {
-	c.wd = t
-	return nil
-}
-
-func (c *slowTestConn) Read(b []byte) (n int, err error) {
-restart:
-	if !c.rd.IsZero() && time.Now().After(c.rd) {
-		return 0, syscall.ETIMEDOUT
-	}
-	if len(c.script) == 0 {
-		return 0, io.EOF
-	}
-
-	switch cue := c.script[0].(type) {
-	case time.Duration:
-		if !c.rd.IsZero() {
-			// If the deadline falls in the middle of our sleep window, deduct
-			// part of the sleep, then return a timeout.
-			if remaining := c.rd.Sub(time.Now()); remaining < cue {
-				c.script[0] = cue - remaining
-				time.Sleep(remaining)
-				return 0, syscall.ETIMEDOUT
-			}
-		}
-		c.script = c.script[1:]
-		time.Sleep(cue)
-		goto restart
-
-	case string:
-		n = copy(b, cue)
-		// If cue is too big for the buffer, leave the end for the next Read.
-		if len(cue) > n {
-			c.script[0] = cue[n:]
-		} else {
-			c.script = c.script[1:]
-		}
-
-	default:
-		panic("unknown cue in slowTestConn script")
-	}
-
-	return
-}
-
-func (c *slowTestConn) Close() error {
-	select {
-	case c.closec <- true:
-	default:
-	}
-	return nil
-}
-
-func (c *slowTestConn) Write(b []byte) (int, error) {
-	if !c.wd.IsZero() && time.Now().After(c.wd) {
-		return 0, syscall.ETIMEDOUT
-	}
-	return len(b), nil
-}
-
-func TestRequestBodyTimeoutClosesConnection(t *testing.T) {
-	if testing.Short() {
-		t.Skip("skipping in -short mode")
-	}
-	defer afterTest(t)
-	for _, handler := range testHandlerBodyConsumers {
-		conn := &slowTestConn{
-			script: []interface{}{
-				"POST /public HTTP/1.1\r\n" +
-					"Host: test\r\n" +
-					"Content-Length: 10000\r\n" +
-					"\r\n",
-				"foo bar baz",
-				600 * time.Millisecond, // Request deadline should hit here
-				"GET /secret HTTP/1.1\r\n" +
-					"Host: test\r\n" +
-					"\r\n",
-			},
-			closec: make(chan bool, 1),
-		}
-		ls := &oneConnListener{conn}
-
-		var numReqs int
-		s := Server{
-			Handler: HandlerFunc(func(_ ResponseWriter, req *Request) {
-				numReqs++
-				if strings.Contains(req.URL.Path, "secret") {
-					t.Error("Request for /secret encountered, should not have happened.")
-				}
-				handler.f(req.Body)
-			}),
-			ReadTimeout: 400 * time.Millisecond,
-		}
-		go s.Serve(ls)
-		<-conn.closec
-
-		if numReqs != 1 {
-			t.Errorf("Handler %v: got %d reqs; want 1", handler.name, numReqs)
-		}
-	}
-}
-
 func TestTimeoutHandler(t *testing.T) {
 	defer afterTest(t)
 	sendHi := make(chan bool, 1)
@@ -1816,23 +1451,19 @@ func testHandlerPanic(t *testing.T, withHijack bool, panicValue interface{}) {
 	}
 }
 
-func TestServerNoDate(t *testing.T)        { testServerNoHeader(t, "Date") }
-func TestServerNoContentType(t *testing.T) { testServerNoHeader(t, "Content-Type") }
-
-func testServerNoHeader(t *testing.T, header string) {
+func TestNoDate(t *testing.T) {
 	defer afterTest(t)
 	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
-		w.Header()[header] = nil
-		io.WriteString(w, "<html>foo</html>") // non-empty
+		w.Header()["Date"] = nil
 	}))
 	defer ts.Close()
 	res, err := Get(ts.URL)
 	if err != nil {
 		t.Fatal(err)
 	}
-	res.Body.Close()
-	if got, ok := res.Header[header]; ok {
-		t.Fatalf("Expected no %s header; got %q", header, got)
+	_, present := res.Header["Date"]
+	if present {
+		t.Fatalf("Expected no Date header; got %v", res.Header["Date"])
 	}
 }
 
@@ -1946,7 +1577,7 @@ func TestRequestBodyLimit(t *testing.T) {
 // 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 https://golang.org/issue/7237")
+		t.Skip("skipping test; see http://golang.org/issue/7237")
 	}
 	defer afterTest(t)
 	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {}))
@@ -2001,7 +1632,7 @@ func TestServerBufferedChunking(t *testing.T) {
 // Tests that the server flushes its response headers out when it's
 // ignoring the response body and waits a bit before forcefully
 // closing the TCP connection, causing the client to get a RST.
-// See https://golang.org/issue/3595
+// See http://golang.org/issue/3595
 func TestServerGracefulClose(t *testing.T) {
 	defer afterTest(t)
 	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
@@ -2493,7 +2124,7 @@ func TestDoubleHijack(t *testing.T) {
 	<-conn.closec
 }
 
-// https://golang.org/issue/5955
+// 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;
 // not sending Connection: close is just a minor wire
@@ -2657,13 +2288,17 @@ func TestTransportAndServerSharedBodyRace(t *testing.T) {
 
 	unblockBackend := make(chan bool)
 	backend := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, req *Request) {
-		io.CopyN(rw, req.Body, bodySize)
+		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
+		}
 		req2, _ := NewRequest("POST", backend.URL, req.Body)
 		req2.ContentLength = bodySize
 
@@ -2672,7 +2307,7 @@ func TestTransportAndServerSharedBodyRace(t *testing.T) {
 			t.Errorf("Proxy outbound request: %v", err)
 			return
 		}
-		_, err = io.CopyN(ioutil.Discard, bresp.Body, bodySize/2)
+		_, err = io.CopyN(ioutil.Discard, bresp.Body, bodySize/4)
 		if err != nil {
 			t.Errorf("Proxy copy error: %v", err)
 			return
@@ -2686,7 +2321,6 @@ func TestTransportAndServerSharedBodyRace(t *testing.T) {
 	}))
 	defer proxy.Close()
 
-	defer close(unblockBackend)
 	req, _ := NewRequest("POST", proxy.URL, io.LimitReader(neverEnding('a'), bodySize))
 	res, err := DefaultClient.Do(req)
 	if err != nil {
@@ -2695,12 +2329,8 @@ func TestTransportAndServerSharedBodyRace(t *testing.T) {
 
 	// Cleanup, so we don't leak goroutines.
 	res.Body.Close()
-	select {
-	case res := <-backendRespc:
-		res.Body.Close()
-	default:
-		// We failed earlier. (e.g. on DefaultClient.Do(req2))
-	}
+	close(unblockBackend)
+	(<-backendRespc).Body.Close()
 }
 
 // Test that a hanging Request.Body.Read from another goroutine can't
@@ -2754,24 +2384,18 @@ func TestRequestBodyCloseDoesntBlock(t *testing.T) {
 	}
 }
 
-// test that ResponseWriter implements io.stringWriter.
-func TestResponseWriterWriteString(t *testing.T) {
-	okc := make(chan bool, 1)
+func TestResponseWriterWriteStringAllocs(t *testing.T) {
 	ht := newHandlerTest(HandlerFunc(func(w ResponseWriter, r *Request) {
-		type stringWriter interface {
-			WriteString(s string) (n int, err error)
+		if r.URL.Path == "/s" {
+			io.WriteString(w, "Hello world")
+		} else {
+			w.Write([]byte("Hello world"))
 		}
-		_, ok := w.(stringWriter)
-		okc <- ok
 	}))
-	ht.rawResponse("GET / HTTP/1.0")
-	select {
-	case ok := <-okc:
-		if !ok {
-			t.Error("ResponseWriter did not implement io.stringWriter")
-		}
-	default:
-		t.Error("handler was never called")
+	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)
 	}
 }
 
@@ -3132,134 +2756,6 @@ func TestServerKeepAliveAfterWriteError(t *testing.T) {
 	}
 }
 
-// Issue 9987: shouldn't add automatic Content-Length (or
-// Content-Type) if a Transfer-Encoding was set by the handler.
-func TestNoContentLengthIfTransferEncoding(t *testing.T) {
-	defer afterTest(t)
-	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
-		w.Header().Set("Transfer-Encoding", "foo")
-		io.WriteString(w, "<html>")
-	}))
-	defer ts.Close()
-	c, err := net.Dial("tcp", ts.Listener.Addr().String())
-	if err != nil {
-		t.Fatalf("Dial: %v", err)
-	}
-	defer c.Close()
-	if _, err := io.WriteString(c, "GET / HTTP/1.1\r\nHost: foo\r\n\r\n"); err != nil {
-		t.Fatal(err)
-	}
-	bs := bufio.NewScanner(c)
-	var got bytes.Buffer
-	for bs.Scan() {
-		if strings.TrimSpace(bs.Text()) == "" {
-			break
-		}
-		got.WriteString(bs.Text())
-		got.WriteByte('\n')
-	}
-	if err := bs.Err(); err != nil {
-		t.Fatal(err)
-	}
-	if strings.Contains(got.String(), "Content-Length") {
-		t.Errorf("Unexpected Content-Length in response headers: %s", got.String())
-	}
-	if strings.Contains(got.String(), "Content-Type") {
-		t.Errorf("Unexpected Content-Type in response headers: %s", got.String())
-	}
-}
-
-// tolerate extra CRLF(s) before Request-Line on subsequent requests on a conn
-// Issue 10876.
-func TestTolerateCRLFBeforeRequestLine(t *testing.T) {
-	req := []byte("POST / HTTP/1.1\r\nHost: golang.org\r\nContent-Length: 3\r\n\r\nABC" +
-		"\r\n\r\n" + // <-- this stuff is bogus, but we'll ignore it
-		"GET / HTTP/1.1\r\nHost: golang.org\r\n\r\n")
-	var buf bytes.Buffer
-	conn := &rwTestConn{
-		Reader: bytes.NewReader(req),
-		Writer: &buf,
-		closec: make(chan bool, 1),
-	}
-	ln := &oneConnListener{conn: conn}
-	numReq := 0
-	go Serve(ln, HandlerFunc(func(rw ResponseWriter, r *Request) {
-		numReq++
-	}))
-	<-conn.closec
-	if numReq != 2 {
-		t.Errorf("num requests = %d; want 2", numReq)
-		t.Logf("Res: %s", buf.Bytes())
-	}
-}
-
-func TestIssue11549_Expect100(t *testing.T) {
-	req := reqBytes(`PUT /readbody HTTP/1.1
-User-Agent: PycURL/7.22.0
-Host: 127.0.0.1:9000
-Accept: */*
-Expect: 100-continue
-Content-Length: 10
-
-HelloWorldPUT /noreadbody HTTP/1.1
-User-Agent: PycURL/7.22.0
-Host: 127.0.0.1:9000
-Accept: */*
-Expect: 100-continue
-Content-Length: 10
-
-GET /should-be-ignored HTTP/1.1
-Host: foo
-
-`)
-	var buf bytes.Buffer
-	conn := &rwTestConn{
-		Reader: bytes.NewReader(req),
-		Writer: &buf,
-		closec: make(chan bool, 1),
-	}
-	ln := &oneConnListener{conn: conn}
-	numReq := 0
-	go Serve(ln, HandlerFunc(func(w ResponseWriter, r *Request) {
-		numReq++
-		if r.URL.Path == "/readbody" {
-			ioutil.ReadAll(r.Body)
-		}
-		io.WriteString(w, "Hello world!")
-	}))
-	<-conn.closec
-	if numReq != 2 {
-		t.Errorf("num requests = %d; want 2", numReq)
-	}
-	if !strings.Contains(buf.String(), "Connection: close\r\n") {
-		t.Errorf("expected 'Connection: close' in response; got: %s", buf.String())
-	}
-}
-
-// If a Handler finishes and there's an unread request body,
-// verify the server try to do implicit read on it before replying.
-func TestHandlerFinishSkipBigContentLengthRead(t *testing.T) {
-	conn := &testConn{closec: make(chan bool)}
-	conn.readBuf.Write([]byte(fmt.Sprintf(
-		"POST / HTTP/1.1\r\n" +
-			"Host: test\r\n" +
-			"Content-Length: 9999999999\r\n" +
-			"\r\n" + strings.Repeat("a", 1<<20))))
-
-	ls := &oneConnListener{conn}
-	var inHandlerLen int
-	go Serve(ls, HandlerFunc(func(rw ResponseWriter, req *Request) {
-		inHandlerLen = conn.readBuf.Len()
-		rw.WriteHeader(404)
-	}))
-	<-conn.closec
-	afterHandlerLen := conn.readBuf.Len()
-
-	if afterHandlerLen != inHandlerLen {
-		t.Errorf("unexpected implicit read. Read buffer went from %d -> %d", inHandlerLen, afterHandlerLen)
-	}
-}
-
 func BenchmarkClientServer(b *testing.B) {
 	b.ReportAllocs()
 	b.StopTimer()
@@ -3389,7 +2885,7 @@ func BenchmarkServer(b *testing.B) {
 	defer ts.Close()
 	b.StartTimer()
 
-	cmd := exec.Command(os.Args[0], "-test.run=XXXX", "-test.bench=BenchmarkServer$")
+	cmd := exec.Command(os.Args[0], "-test.run=XXXX", "-test.bench=BenchmarkServer")
 	cmd.Env = append([]string{
 		fmt.Sprintf("TEST_BENCH_CLIENT_N=%d", b.N),
 		fmt.Sprintf("TEST_BENCH_SERVER_URL=%s", ts.URL),
@@ -3400,95 +2896,6 @@ func BenchmarkServer(b *testing.B) {
 	}
 }
 
-// getNoBody wraps Get but closes any Response.Body before returning the response.
-func getNoBody(urlStr string) (*Response, error) {
-	res, err := Get(urlStr)
-	if err != nil {
-		return nil, err
-	}
-	res.Body.Close()
-	return res, nil
-}
-
-// A benchmark for profiling the client without the HTTP server code.
-// The server code runs in a subprocess.
-func BenchmarkClient(b *testing.B) {
-	b.ReportAllocs()
-	b.StopTimer()
-	defer afterTest(b)
-
-	port := os.Getenv("TEST_BENCH_SERVER_PORT") // can be set by user
-	if port == "" {
-		port = "39207"
-	}
-	var data = []byte("Hello world.\n")
-	if server := os.Getenv("TEST_BENCH_SERVER"); server != "" {
-		// Server process mode.
-		HandleFunc("/", func(w ResponseWriter, r *Request) {
-			r.ParseForm()
-			if r.Form.Get("stop") != "" {
-				os.Exit(0)
-			}
-			w.Header().Set("Content-Type", "text/html; charset=utf-8")
-			w.Write(data)
-		})
-		log.Fatal(ListenAndServe("localhost:"+port, nil))
-	}
-
-	// Start server process.
-	cmd := exec.Command(os.Args[0], "-test.run=XXXX", "-test.bench=BenchmarkClient$")
-	cmd.Env = append(os.Environ(), "TEST_BENCH_SERVER=yes")
-	if err := cmd.Start(); err != nil {
-		b.Fatalf("subprocess failed to start: %v", err)
-	}
-	defer cmd.Process.Kill()
-	done := make(chan error)
-	go func() {
-		done <- cmd.Wait()
-	}()
-
-	// Wait for the server process to respond.
-	url := "http://localhost:" + port + "/"
-	for i := 0; i < 100; i++ {
-		time.Sleep(50 * time.Millisecond)
-		if _, err := getNoBody(url); err == nil {
-			break
-		}
-		if i == 99 {
-			b.Fatalf("subprocess does not respond")
-		}
-	}
-
-	// Do b.N requests to the server.
-	b.StartTimer()
-	for i := 0; i < b.N; i++ {
-		res, err := Get(url)
-		if err != nil {
-			b.Fatalf("Get: %v", err)
-		}
-		body, err := ioutil.ReadAll(res.Body)
-		res.Body.Close()
-		if err != nil {
-			b.Fatalf("ReadAll: %v", err)
-		}
-		if bytes.Compare(body, data) != 0 {
-			b.Fatalf("Got body: %q", body)
-		}
-	}
-	b.StopTimer()
-
-	// Instruct server process to stop.
-	getNoBody(url + "?stop=yes")
-	select {
-	case err := <-done:
-		if err != nil {
-			b.Fatalf("subprocess failed: %v", err)
-		}
-	case <-time.After(5 * time.Second):
-		b.Fatalf("subprocess did not stop")
-	}
-}
-
 func BenchmarkServerFakeConnNoKeepAlive(b *testing.B) {
 	b.ReportAllocs()
 	req := reqBytes(`GET / HTTP/1.0
diff --git a/src/net/http/server.go b/src/net/http/server.go
index a3e4355..008d5aa 100644
--- a/src/net/http/server.go
+++ b/src/net/http/server.go
@@ -15,7 +15,6 @@ import (
 	"io/ioutil"
 	"log"
 	"net"
-	"net/textproto"
 	"net/url"
 	"os"
 	"path"
@@ -56,12 +55,9 @@ type Handler interface {
 // A ResponseWriter interface is used by an HTTP handler to
 // construct an HTTP response.
 type ResponseWriter interface {
-	// Header returns the header map that will be sent by
-	// WriteHeader. Changing the header after a call to
-	// WriteHeader (or Write) has no effect unless the modified
-	// headers were declared as trailers by setting the
-	// "Trailer" header before the call to WriteHeader (see example).
-	// To suppress implicit response headers, set their value to nil.
+	// Header returns the header map that will be sent by WriteHeader.
+	// Changing the header after a call to WriteHeader (or Write) has
+	// no effect.
 	Header() Header
 
 	// Write writes the data to the connection as part of an HTTP reply.
@@ -97,14 +93,8 @@ type Hijacker interface {
 	// Hijack lets the caller take over the connection.
 	// After a call to Hijack(), the HTTP server library
 	// will not do anything else with the connection.
-	//
 	// It becomes the caller's responsibility to manage
 	// and close the connection.
-	//
-	// The returned net.Conn may have read or write deadlines
-	// already set, depending on the configuration of the
-	// Server. It is the caller's responsibility to set
-	// or clear those deadlines as needed.
 	Hijack() (net.Conn, *bufio.ReadWriter, error)
 }
 
@@ -130,7 +120,6 @@ type conn struct {
 	lr         *io.LimitedReader    // io.LimitReader(sr)
 	buf        *bufio.ReadWriter    // buffered(lr,rwc), reading from bufio->limitReader->sr->rwc
 	tlsState   *tls.ConnectionState // or nil when not using TLS
-	lastMethod string               // method of previous request, or ""
 
 	mu           sync.Mutex // guards the following
 	clientGone   bool       // if client has disconnected mid-request
@@ -199,14 +188,20 @@ func (c *conn) noteClientGone() {
 	c.clientGone = true
 }
 
+// A switchReader can have its Reader changed at runtime.
+// It's not safe for concurrent Reads and switches.
+type switchReader struct {
+	io.Reader
+}
+
 // A switchWriter can have its Writer changed at runtime.
 // It's not safe for concurrent Writes and switches.
 type switchWriter struct {
 	io.Writer
 }
 
-// A liveSwitchReader can have its Reader changed at runtime. It's
-// safe for concurrent reads and switches, if its mutex is held.
+// A liveSwitchReader is a switchReader that's safe for concurrent
+// reads and switches, if its mutex is held.
 type liveSwitchReader struct {
 	sync.Mutex
 	r io.Reader
@@ -293,21 +288,10 @@ func (cw *chunkWriter) close() {
 		cw.writeHeader(nil)
 	}
 	if cw.chunking {
-		bw := cw.res.conn.buf // conn's bufio writer
-		// zero chunk to mark EOF
-		bw.WriteString("0\r\n")
-		if len(cw.res.trailers) > 0 {
-			trailers := make(Header)
-			for _, h := range cw.res.trailers {
-				if vv := cw.res.handlerHeader[h]; len(vv) > 0 {
-					trailers[h] = vv
-				}
-			}
-			trailers.Write(bw) // the writer handles noting errors
-		}
-		// final blank line after the trailers (whether
-		// present or not)
-		bw.WriteString("\r\n")
+		// zero EOF chunk, trailer key/value pairs (currently
+		// unsupported in Go's server), followed by a blank
+		// line.
+		cw.res.conn.buf.WriteString("0\r\n\r\n")
 	}
 }
 
@@ -348,12 +332,6 @@ type response struct {
 	// input from it.
 	requestBodyLimitHit bool
 
-	// trailers are the headers to be sent after the handler
-	// finishes writing the body.  This field is initialized from
-	// the Trailer response header when the response header is
-	// written.
-	trailers []string
-
 	handlerDone bool // set true when the handler exits
 
 	// Buffers for Date and Content-Length
@@ -361,19 +339,6 @@ type response struct {
 	clenBuf [10]byte
 }
 
-// declareTrailer is called for each Trailer header when the
-// response header is written. It notes that a header will need to be
-// written in the trailers at the end of the response.
-func (w *response) declareTrailer(k string) {
-	k = CanonicalHeaderKey(k)
-	switch k {
-	case "Transfer-Encoding", "Content-Length", "Trailer":
-		// Forbidden by RFC 2616 14.40.
-		return
-	}
-	w.trailers = append(w.trailers, k)
-}
-
 // requestTooLarge is called by maxBytesReader when too much input has
 // been read from the client.
 func (w *response) requestTooLarge() {
@@ -473,7 +438,7 @@ func (srv *Server) newConn(rwc net.Conn) (c *conn, err error) {
 	if debugServerConnections {
 		c.rwc = newLoggingConn("server", c.rwc)
 	}
-	c.sr.r = c.rwc
+	c.sr = liveSwitchReader{r: c.rwc}
 	c.lr = io.LimitReader(&c.sr, noLimit).(*io.LimitedReader)
 	br := newBufioReader(c.lr)
 	bw := newBufioWriterSize(checkConnErrorWriter{c}, 4<<10)
@@ -503,8 +468,6 @@ func newBufioReader(r io.Reader) *bufio.Reader {
 		br.Reset(r)
 		return br
 	}
-	// Note: if this reader size is every changed, update
-	// TestHandlerBodyClose's assumptions.
 	return bufio.NewReader(r)
 }
 
@@ -554,7 +517,6 @@ type expectContinueReader struct {
 	resp       *response
 	readCloser io.ReadCloser
 	closed     bool
-	sawEOF     bool
 }
 
 func (ecr *expectContinueReader) Read(p []byte) (n int, err error) {
@@ -566,11 +528,7 @@ func (ecr *expectContinueReader) Read(p []byte) (n int, err error) {
 		ecr.resp.conn.buf.WriteString("HTTP/1.1 100 Continue\r\n\r\n")
 		ecr.resp.conn.buf.Flush()
 	}
-	n, err = ecr.readCloser.Read(p)
-	if err == io.EOF {
-		ecr.sawEOF = true
-	}
-	return
+	return ecr.readCloser.Read(p)
 }
 
 func (ecr *expectContinueReader) Close() error {
@@ -624,11 +582,6 @@ func (c *conn) readRequest() (w *response, err error) {
 	}
 
 	c.lr.N = c.server.initialLimitedReaderSize()
-	if c.lastMethod == "POST" {
-		// RFC 2616 section 4.1 tolerance for old buggy clients.
-		peek, _ := c.buf.Reader.Peek(4) // ReadRequest will get err below
-		c.buf.Reader.Discard(numLeadingCRorLF(peek))
-	}
 	var req *Request
 	if req, err = ReadRequest(c.buf.Reader); err != nil {
 		if c.lr.N == 0 {
@@ -637,13 +590,9 @@ func (c *conn) readRequest() (w *response, err error) {
 		return nil, err
 	}
 	c.lr.N = noLimit
-	c.lastMethod = req.Method
 
 	req.RemoteAddr = c.remoteAddr
 	req.TLS = c.tlsState
-	if body, ok := req.Body.(*body); ok {
-		body.doEarlyClose = true
-	}
 
 	w = &response{
 		conn:          c,
@@ -798,15 +747,6 @@ func (cw *chunkWriter) writeHeader(p []byte) {
 	}
 	var setHeader extraHeader
 
-	trailers := false
-	for _, v := range cw.header["Trailer"] {
-		trailers = true
-		foreachHeaderElement(v, cw.res.declareTrailer)
-	}
-
-	te := header.get("Transfer-Encoding")
-	hasTE := te != ""
-
 	// If the handler is done but never sent a Content-Length
 	// response header and this is our first (and last) write, set
 	// it, even to zero. This helps HTTP/1.0 clients keep their
@@ -819,9 +759,7 @@ 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.
-	// Further, we don't send an automatic Content-Length if they
-	// set a Transfer-Encoding, because they're generally incompatible.
-	if w.handlerDone && !trailers && !hasTE && bodyAllowedForStatus(w.status) && 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)
 	}
@@ -851,78 +789,21 @@ func (cw *chunkWriter) writeHeader(p []byte) {
 		w.closeAfterReply = true
 	}
 
-	// If the client wanted a 100-continue but we never sent it to
-	// them (or, more strictly: we never finished reading their
-	// request body), don't reuse this connection because it's now
-	// in an unknown state: we might be sending this response at
-	// the same time the client is now sending its request body
-	// after a timeout.  (Some HTTP clients send Expect:
-	// 100-continue but knowing that some servers don't support
-	// it, the clients set a timer and send the body later anyway)
-	// If we haven't seen EOF, we can't skip over the unread body
-	// because we don't know if the next bytes on the wire will be
-	// the body-following-the-timer or the subsequent request.
-	// See Issue 11549.
-	if ecr, ok := w.req.Body.(*expectContinueReader); ok && !ecr.sawEOF {
-		w.closeAfterReply = true
-	}
-
 	// Per RFC 2616, we should consume the request body before
 	// replying, if the handler hasn't already done so.  But we
 	// don't want to do an unbounded amount of reading here for
 	// DoS reasons, so we only try up to a threshold.
 	if w.req.ContentLength != 0 && !w.closeAfterReply {
-		var discard, tooBig bool
-
-		switch bdy := w.req.Body.(type) {
-		case *expectContinueReader:
-			if bdy.resp.wroteContinue {
-				discard = true
-			}
-		case *body:
-			bdy.mu.Lock()
-			switch {
-			case bdy.closed:
-				if !bdy.sawEOF {
-					// Body was closed in handler with non-EOF error.
-					w.closeAfterReply = true
-				}
-			case bdy.unreadDataSizeLocked() >= maxPostHandlerReadBytes:
-				tooBig = true
-			default:
-				discard = true
+		ecr, isExpecter := w.req.Body.(*expectContinueReader)
+		if !isExpecter || ecr.resp.wroteContinue {
+			n, _ := io.CopyN(ioutil.Discard, w.req.Body, maxPostHandlerReadBytes+1)
+			if n >= maxPostHandlerReadBytes {
+				w.requestTooLarge()
+				delHeader("Connection")
+				setHeader.connection = "close"
+			} else {
+				w.req.Body.Close()
 			}
-			bdy.mu.Unlock()
-		default:
-			discard = true
-		}
-
-		if discard {
-			_, err := io.CopyN(ioutil.Discard, w.req.Body, maxPostHandlerReadBytes+1)
-			switch err {
-			case nil:
-				// There must be even more data left over.
-				tooBig = true
-			case ErrBodyReadAfterClose:
-				// Body was already consumed and closed.
-			case io.EOF:
-				// The remaining body was just consumed, close it.
-				err = w.req.Body.Close()
-				if err != nil {
-					w.closeAfterReply = true
-				}
-			default:
-				// Some other kind of error occured, like a read timeout, or
-				// corrupt chunked encoding. In any case, whatever remains
-				// on the wire must not be parsed as another HTTP request.
-				w.closeAfterReply = true
-			}
-		}
-
-		if tooBig {
-			w.requestTooLarge()
-			delHeader("Connection")
-			setHeader.connection = "close"
 		}
 	}
 
@@ -930,7 +811,7 @@ func (cw *chunkWriter) writeHeader(p []byte) {
 	if bodyAllowedForStatus(code) {
 		// If no content type, apply sniffing algorithm to body.
 		_, haveType := header["Content-Type"]
-		if !haveType && !hasTE {
+		if !haveType {
 			setHeader.contentType = DetectContentType(p)
 		}
 	} else {
@@ -943,6 +824,8 @@ func (cw *chunkWriter) writeHeader(p []byte) {
 		setHeader.date = appendTime(cw.res.dateBuf[:0], time.Now())
 	}
 
+	te := header.get("Transfer-Encoding")
+	hasTE := te != ""
 	if hasCL && hasTE && te != "identity" {
 		// TODO: return an error if WriteHeader gets a return parameter
 		// For now just ignore the Content-Length.
@@ -1002,24 +885,6 @@ func (cw *chunkWriter) writeHeader(p []byte) {
 	w.conn.buf.Write(crlf)
 }
 
-// foreachHeaderElement splits v according to the "#rule" construction
-// in RFC 2616 section 2.1 and calls fn for each non-empty element.
-func foreachHeaderElement(v string, fn func(string)) {
-	v = textproto.TrimString(v)
-	if v == "" {
-		return
-	}
-	if !strings.Contains(v, ",") {
-		fn(v)
-		return
-	}
-	for _, f := range strings.Split(v, ",") {
-		if f = textproto.TrimString(f); f != "" {
-			fn(f)
-		}
-	}
-}
-
 // statusLines is a cache of Status-Line strings, keyed by code (for
 // HTTP/1.1) or negative code (for HTTP/1.0). This is faster than a
 // map keyed by struct of two fields. This map's max size is bounded
@@ -1065,7 +930,7 @@ func statusLine(req *Request, code int) string {
 	return line
 }
 
-// bodyAllowed reports whether a Write is allowed for this response type.
+// bodyAllowed returns true if a Write is allowed for this response type.
 // It's illegal to call this before the header has been flushed.
 func (w *response) bodyAllowed() bool {
 	if !w.wroteHeader {
@@ -1162,39 +1027,17 @@ func (w *response) finishRequest() {
 	if w.req.MultipartForm != nil {
 		w.req.MultipartForm.RemoveAll()
 	}
-}
-
-// shouldReuseConnection reports whether the underlying TCP connection can be reused.
-// It must only be called after the handler is done executing.
-func (w *response) shouldReuseConnection() bool {
-	if w.closeAfterReply {
-		// The request or something set while executing the
-		// handler indicated we shouldn't reuse this
-		// connection.
-		return false
-	}
 
 	if w.req.Method != "HEAD" && w.contentLength != -1 && w.bodyAllowed() && w.contentLength != w.written {
 		// Did not write enough. Avoid getting out of sync.
-		return false
+		w.closeAfterReply = true
 	}
 
 	// There was some error writing to the underlying connection
 	// during the request, so don't re-use this conn.
 	if w.conn.werr != nil {
-		return false
-	}
-
-	if w.closedRequestBodyEarly() {
-		return false
+		w.closeAfterReply = true
 	}
-
-	return true
-}
-
-func (w *response) closedRequestBodyEarly() bool {
-	body, ok := w.req.Body.(*body)
-	return ok && body.didEarlyClose()
 }
 
 func (w *response) Flush() {
@@ -1250,7 +1093,7 @@ var _ closeWriter = (*net.TCPConn)(nil)
 // pause for a bit, hoping the client processes it before any
 // subsequent RST.
 //
-// See https://golang.org/issue/3595
+// See http://golang.org/issue/3595
 func (c *conn) closeWriteAndWait() {
 	c.finalFlush()
 	if tcp, ok := c.rwc.(closeWriter); ok {
@@ -1363,8 +1206,8 @@ func (c *conn) serve() {
 			return
 		}
 		w.finishRequest()
-		if !w.shouldReuseConnection() {
-			if w.requestBodyLimitHit || w.closedRequestBodyEarly() {
+		if w.closeAfterReply {
+			if w.requestBodyLimitHit {
 				c.closeWriteAndWait()
 			}
 			break
@@ -1428,7 +1271,6 @@ func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
 // The error message should be plain text.
 func Error(w ResponseWriter, error string, code int) {
 	w.Header().Set("Content-Type", "text/plain; charset=utf-8")
-	w.Header().Set("X-Content-Type-Options", "nosniff")
 	w.WriteHeader(code)
 	fmt.Fprintln(w, error)
 }
@@ -1734,8 +1576,7 @@ func (mux *ServeMux) Handle(pattern string, handler Handler) {
 			// strings.Index can't be -1.
 			path = pattern[strings.Index(pattern, "/"):]
 		}
-		url := &url.URL{Path: path}
-		mux.m[pattern[0:n-1]] = muxEntry{h: RedirectHandler(url.String(), StatusMovedPermanently), pattern: pattern}
+		mux.m[pattern[0:n-1]] = muxEntry{h: RedirectHandler(path, StatusMovedPermanently), pattern: pattern}
 	}
 }
 
@@ -1919,11 +1760,11 @@ func (s *Server) doKeepAlives() bool {
 // By default, keep-alives are always enabled. Only very
 // resource-constrained environments or servers in the process of
 // shutting down should disable them.
-func (srv *Server) SetKeepAlivesEnabled(v bool) {
+func (s *Server) SetKeepAlivesEnabled(v bool) {
 	if v {
-		atomic.StoreInt32(&srv.disableKeepAlives, 0)
+		atomic.StoreInt32(&s.disableKeepAlives, 0)
 	} else {
-		atomic.StoreInt32(&srv.disableKeepAlives, 1)
+		atomic.StoreInt32(&s.disableKeepAlives, 1)
 	}
 }
 
@@ -1971,7 +1812,7 @@ func ListenAndServe(addr string, handler Handler) error {
 // expects HTTPS connections. Additionally, files containing a certificate and
 // matching private key for the server must be provided. If the certificate
 // is signed by a certificate authority, the certFile should be the concatenation
-// of the server's certificate, any intermediates, and the CA's certificate.
+// of the server's certificate followed by the CA's certificate.
 //
 // A trivial example server is:
 //
@@ -2003,11 +1844,10 @@ func ListenAndServeTLS(addr string, certFile string, keyFile string, handler Han
 // ListenAndServeTLS listens on the TCP network address srv.Addr and
 // then calls Serve to handle requests on incoming TLS connections.
 //
-// Filenames containing a certificate and matching private key for the
-// server must be provided if the Server's TLSConfig.Certificates is
-// not populated. If the certificate is signed by a certificate
-// authority, the certFile should be the concatenation of the server's
-// certificate, any intermediates, and the CA's certificate.
+// Filenames containing a certificate and matching private key for
+// the server must be provided. If the certificate is signed by a
+// certificate authority, the certFile should be the concatenation
+// of the server's certificate followed by the CA's certificate.
 //
 // If srv.Addr is blank, ":https" is used.
 func (srv *Server) ListenAndServeTLS(certFile, keyFile string) error {
@@ -2015,18 +1855,19 @@ func (srv *Server) ListenAndServeTLS(certFile, keyFile string) error {
 	if addr == "" {
 		addr = ":https"
 	}
-	config := cloneTLSConfig(srv.TLSConfig)
+	config := &tls.Config{}
+	if srv.TLSConfig != nil {
+		*config = *srv.TLSConfig
+	}
 	if config.NextProtos == nil {
 		config.NextProtos = []string{"http/1.1"}
 	}
 
-	if len(config.Certificates) == 0 || certFile != "" || keyFile != "" {
-		var err error
-		config.Certificates = make([]tls.Certificate, 1)
-		config.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile)
-		if err != nil {
-			return err
-		}
+	var err error
+	config.Certificates = make([]tls.Certificate, 1)
+	config.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile)
+	if err != nil {
+		return err
 	}
 
 	ln, err := net.Listen("tcp", addr)
@@ -2253,15 +2094,3 @@ func (w checkConnErrorWriter) Write(p []byte) (n int, err error) {
 	}
 	return
 }
-
-func numLeadingCRorLF(v []byte) (n int) {
-	for _, b := range v {
-		if b == '\r' || b == '\n' {
-			n++
-			continue
-		}
-		break
-	}
-	return
-
-}
diff --git a/src/net/http/sniff.go b/src/net/http/sniff.go
index 3be8c86..68f519b 100644
--- a/src/net/http/sniff.go
+++ b/src/net/http/sniff.go
@@ -38,11 +38,7 @@ func DetectContentType(data []byte) string {
 }
 
 func isWS(b byte) bool {
-	switch b {
-	case '\t', '\n', '\x0c', '\r', ' ':
-		return true
-	}
-	return false
+	return bytes.IndexByte([]byte("\t\n\x0C\r "), b) != -1
 }
 
 type sniffSig interface {
@@ -165,8 +161,6 @@ func (h htmlSig) match(data []byte, firstNonWS int) string {
 	return "text/html; charset=utf-8"
 }
 
-var mp4ftype = []byte("ftyp")
-
 type mp4Sig int
 
 func (mp4Sig) match(data []byte, firstNonWS int) string {
@@ -178,7 +172,7 @@ func (mp4Sig) match(data []byte, firstNonWS int) string {
 	if boxSize%4 != 0 || len(data) < boxSize {
 		return ""
 	}
-	if !bytes.Equal(data[4:8], mp4ftype) {
+	if !bytes.Equal(data[4:8], []byte("ftyp")) {
 		return ""
 	}
 	for st := 8; st < boxSize; st += 4 {
diff --git a/src/net/http/transfer.go b/src/net/http/transfer.go
index a8736b2..5205003 100644
--- a/src/net/http/transfer.go
+++ b/src/net/http/transfer.go
@@ -27,7 +27,7 @@ type errorReader struct {
 	err error
 }
 
-func (r errorReader) Read(p []byte) (n int, err error) {
+func (r *errorReader) Read(p []byte) (n int, err error) {
 	return 0, r.err
 }
 
@@ -43,7 +43,6 @@ type transferWriter struct {
 	Close            bool
 	TransferEncoding []string
 	Trailer          Header
-	IsResponse       bool
 }
 
 func newTransferWriter(r interface{}) (t *transferWriter, err error) {
@@ -71,7 +70,7 @@ func newTransferWriter(r interface{}) (t *transferWriter, err error) {
 				n, rerr := io.ReadFull(t.Body, buf[:])
 				if rerr != nil && rerr != io.EOF {
 					t.ContentLength = -1
-					t.Body = errorReader{rerr}
+					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.
@@ -90,7 +89,6 @@ func newTransferWriter(r interface{}) (t *transferWriter, err error) {
 			}
 		}
 	case *Response:
-		t.IsResponse = true
 		if rr.Request != nil {
 			t.Method = rr.Request.Method
 		}
@@ -140,17 +138,11 @@ func (t *transferWriter) shouldSendContentLength() bool {
 	if t.ContentLength > 0 {
 		return true
 	}
-	if t.ContentLength < 0 {
-		return false
-	}
 	// Many servers expect a Content-Length for these methods
 	if t.Method == "POST" || t.Method == "PUT" {
 		return true
 	}
 	if t.ContentLength == 0 && isIdentity(t.TransferEncoding) {
-		if t.Method == "GET" || t.Method == "HEAD" {
-			return false
-		}
 		return true
 	}
 
@@ -211,9 +203,6 @@ func (t *transferWriter) WriteBody(w io.Writer) error {
 	// Write body
 	if t.Body != nil {
 		if chunked(t.TransferEncoding) {
-			if bw, ok := w.(*bufio.Writer); ok && !t.IsResponse {
-				w = &internal.FlushAfterChunkWriter{bw}
-			}
 			cw := internal.NewChunkedWriter(w)
 			_, err = io.Copy(cw, t.Body)
 			if err == nil {
@@ -243,6 +232,7 @@ func (t *transferWriter) WriteBody(w io.Writer) error {
 			t.ContentLength, ncopy)
 	}
 
+	// TODO(petar): Place trailer writer code here.
 	if chunked(t.TransferEncoding) {
 		// Write Trailer header
 		if t.Trailer != nil {
@@ -320,13 +310,11 @@ func readTransfer(msg interface{}, r *bufio.Reader) (err error) {
 		}
 	case *Request:
 		t.Header = rr.Header
-		t.RequestMethod = rr.Method
 		t.ProtoMajor = rr.ProtoMajor
 		t.ProtoMinor = rr.ProtoMinor
 		// Transfer semantics for Requests are exactly like those for
 		// Responses with status code 200, responding to a GET method
 		t.StatusCode = 200
-		t.Close = rr.Close
 	default:
 		panic("unexpected type")
 	}
@@ -337,7 +325,7 @@ func readTransfer(msg interface{}, r *bufio.Reader) (err error) {
 	}
 
 	// Transfer encoding, content length
-	t.TransferEncoding, err = fixTransferEncoding(isResponse, t.RequestMethod, t.Header)
+	t.TransferEncoding, err = fixTransferEncoding(t.RequestMethod, t.Header)
 	if err != nil {
 		return err
 	}
@@ -425,11 +413,12 @@ func chunked(te []string) bool { return len(te) > 0 && te[0] == "chunked" }
 func isIdentity(te []string) bool { return len(te) == 1 && te[0] == "identity" }
 
 // Sanitize transfer encoding
-func fixTransferEncoding(isResponse bool, requestMethod string, header Header) ([]string, error) {
+func fixTransferEncoding(requestMethod string, header Header) ([]string, error) {
 	raw, present := header["Transfer-Encoding"]
 	if !present {
 		return nil, nil
 	}
+
 	delete(header, "Transfer-Encoding")
 
 	encodings := strings.Split(raw[0], ",")
@@ -454,22 +443,9 @@ func fixTransferEncoding(isResponse bool, requestMethod string, header Header) (
 		return nil, &badStringError{"too many transfer encodings", strings.Join(te, ",")}
 	}
 	if len(te) > 0 {
-		// RFC 7230 3.3.2 says "A sender MUST NOT send a
-		// Content-Length header field in any message that
-		// contains a Transfer-Encoding header field."
-		//
-		// but also:
-		// "If a message is received with both a
-		// Transfer-Encoding and a Content-Length header
-		// field, the Transfer-Encoding overrides the
-		// Content-Length. Such a message might indicate an
-		// attempt to perform request smuggling (Section 9.5)
-		// or response splitting (Section 9.4) and ought to be
-		// handled as an error. A sender MUST remove the
-		// received Content-Length field prior to forwarding
-		// such a message downstream."
-		//
-		// Reportedly, these appear in the wild.
+		// Chunked encoding trumps Content-Length. See RFC 2616
+		// Section 4.4. Currently len(te) > 0 implies chunked
+		// encoding.
 		delete(header, "Content-Length")
 		return te, nil
 	}
@@ -481,17 +457,9 @@ func fixTransferEncoding(isResponse bool, requestMethod string, header Header) (
 // function is not a method, because ultimately it should be shared by
 // ReadResponse and ReadRequest.
 func fixLength(isResponse bool, status int, requestMethod string, header Header, te []string) (int64, error) {
-	contentLens := header["Content-Length"]
-	isRequest := !isResponse
+
 	// Logic based on response type or status
 	if noBodyExpected(requestMethod) {
-		// For HTTP requests, as part of hardening against request
-		// smuggling (RFC 7230), don't allow a Content-Length header for
-		// methods which don't permit bodies. As an exception, allow
-		// exactly one Content-Length header if its value is "0".
-		if isRequest && len(contentLens) > 0 && !(len(contentLens) == 1 && contentLens[0] == "0") {
-			return 0, fmt.Errorf("http: method cannot contain a Content-Length; got %q", contentLens)
-		}
 		return 0, nil
 	}
 	if status/100 == 1 {
@@ -502,21 +470,13 @@ func fixLength(isResponse bool, status int, requestMethod string, header Header,
 		return 0, nil
 	}
 
-	if len(contentLens) > 1 {
-		// harden against HTTP request smuggling. See RFC 7230.
-		return 0, errors.New("http: message cannot contain multiple Content-Length headers")
-	}
-
 	// Logic based on Transfer-Encoding
 	if chunked(te) {
 		return -1, nil
 	}
 
 	// Logic based on Content-Length
-	var cl string
-	if len(contentLens) == 1 {
-		cl = strings.TrimSpace(contentLens[0])
-	}
+	cl := strings.TrimSpace(header.get("Content-Length"))
 	if cl != "" {
 		n, err := parseContentLength(cl)
 		if err != nil {
@@ -527,14 +487,11 @@ func fixLength(isResponse bool, status int, requestMethod string, header Header,
 		header.Del("Content-Length")
 	}
 
-	if !isResponse {
-		// RFC 2616 neither explicitly permits nor forbids an
+	if !isResponse && requestMethod == "GET" {
+		// RFC 2616 doesn't explicitly permit nor forbid an
 		// entity-body on a GET request so we permit one if
 		// declared, but we default to 0 here (not -1 below)
 		// if there's no mention of a body.
-		// Likewise, all other request methods are assumed to have
-		// no body if neither Transfer-Encoding chunked nor a
-		// Content-Length are set.
 		return 0, nil
 	}
 
@@ -549,13 +506,14 @@ func shouldClose(major, minor int, header Header, removeCloseHeader bool) bool {
 	if major < 1 {
 		return true
 	} else if major == 1 && minor == 0 {
-		vv := header["Connection"]
-		if headerValuesContainsToken(vv, "close") || !headerValuesContainsToken(vv, "keep-alive") {
+		if !strings.Contains(strings.ToLower(header.get("Connection")), "keep-alive") {
 			return true
 		}
 		return false
 	} else {
-		if headerValuesContainsToken(header["Connection"], "close") {
+		// TODO: Should split on commas, toss surrounding white space,
+		// and check each field.
+		if strings.ToLower(header.get("Connection")) == "close" {
 			if removeCloseHeader {
 				header.Del("Connection")
 			}
@@ -597,16 +555,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 {
-	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?
-	doEarlyClose bool          // whether Close should stop early
-
-	mu         sync.Mutex // guards closed, and calls to Read and Close
-	sawEOF     bool
-	closed     bool
-	earlyClose bool // Close called and we didn't read to the end of src
+	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?
+
+	mu     sync.Mutex // guards closed, and calls to Read and Close
+	closed bool
 }
 
 // ErrBodyReadAfterClose is returned when reading a Request or Response
@@ -626,23 +581,13 @@ func (b *body) Read(p []byte) (n int, err error) {
 
 // Must hold b.mu.
 func (b *body) readLocked(p []byte) (n int, err error) {
-	if b.sawEOF {
-		return 0, io.EOF
-	}
 	n, err = b.src.Read(p)
 
 	if err == io.EOF {
-		b.sawEOF = true
 		// Chunked case. Read the trailer.
 		if b.hdr != nil {
 			if e := b.readTrailer(); e != nil {
 				err = e
-				// Something went wrong in the trailer, we must not allow any
-				// further reads of any kind to succeed from body, nor any
-				// subsequent requests on the server connection. See
-				// golang.org/issue/12027
-				b.sawEOF = false
-				b.closed = true
 			}
 			b.hdr = nil
 		} else {
@@ -662,7 +607,6 @@ func (b *body) readLocked(p []byte) (n int, err error) {
 	if err == nil && n > 0 {
 		if lr, ok := b.src.(*io.LimitedReader); ok && lr.N == 0 {
 			err = io.EOF
-			b.sawEOF = true
 		}
 	}
 
@@ -695,7 +639,8 @@ func (b *body) readTrailer() error {
 	// The common case, since nobody uses trailers.
 	buf, err := b.r.Peek(2)
 	if bytes.Equal(buf, singleCRLF) {
-		b.r.Discard(2)
+		b.r.ReadByte()
+		b.r.ReadByte()
 		return nil
 	}
 	if len(buf) < 2 {
@@ -743,16 +688,6 @@ func mergeSetHeader(dst *Header, src Header) {
 	}
 }
 
-// unreadDataSizeLocked returns the number of bytes of unread input.
-// It returns -1 if unknown.
-// b.mu must be held.
-func (b *body) unreadDataSizeLocked() int64 {
-	if lr, ok := b.src.(*io.LimitedReader); ok {
-		return lr.N
-	}
-	return -1
-}
-
 func (b *body) Close() error {
 	b.mu.Lock()
 	defer b.mu.Unlock()
@@ -761,30 +696,9 @@ func (b *body) Close() error {
 	}
 	var err error
 	switch {
-	case b.sawEOF:
-		// Already saw EOF, so no need going to look for it.
 	case b.hdr == nil && b.closing:
 		// no trailer and closing the connection next.
 		// no point in reading to EOF.
-	case b.doEarlyClose:
-		// Read up to maxPostHandlerReadBytes bytes of the body, looking for
-		// for EOF (and trailers), so we can re-use this connection.
-		if lr, ok := b.src.(*io.LimitedReader); ok && lr.N > maxPostHandlerReadBytes {
-			// There was a declared Content-Length, and we have more bytes remaining
-			// than our maxPostHandlerReadBytes tolerance. So, give up.
-			b.earlyClose = true
-		} else {
-			var n int64
-			// Consume the body, or, which will also lead to us reading
-			// the trailer headers after the body, if present.
-			n, err = io.CopyN(ioutil.Discard, bodyLocked{b}, maxPostHandlerReadBytes)
-			if err == io.EOF {
-				err = nil
-			}
-			if n == maxPostHandlerReadBytes {
-				b.earlyClose = true
-			}
-		}
 	default:
 		// Fully consume the body, which will also lead to us reading
 		// the trailer headers after the body, if present.
@@ -794,12 +708,6 @@ func (b *body) Close() error {
 	return err
 }
 
-func (b *body) didEarlyClose() bool {
-	b.mu.Lock()
-	defer b.mu.Unlock()
-	return b.earlyClose
-}
-
 // bodyLocked is a io.Reader reading from a *body when its mutex is
 // already held.
 type bodyLocked struct {
diff --git a/src/net/http/transport.go b/src/net/http/transport.go
index 70d1864..782f7cd 100644
--- a/src/net/http/transport.go
+++ b/src/net/http/transport.go
@@ -274,12 +274,11 @@ func (t *Transport) CloseIdleConnections() {
 	}
 }
 
-// CancelRequest cancels an in-flight request by closing its connection.
-// CancelRequest should only be called after RoundTrip has returned.
+// CancelRequest cancels an in-flight request by closing its
+// connection.
 func (t *Transport) CancelRequest(req *Request) {
 	t.reqMu.Lock()
 	cancel := t.reqCanceler[req]
-	delete(t.reqCanceler, req)
 	t.reqMu.Unlock()
 	if cancel != nil {
 		cancel()
@@ -475,25 +474,6 @@ func (t *Transport) setReqCanceler(r *Request, fn func()) {
 	}
 }
 
-// replaceReqCanceler replaces an existing cancel function. If there is no cancel function
-// for the request, we don't set the function and return false.
-// Since CancelRequest will clear the canceler, we can use the return value to detect if
-// the request was canceled since the last setReqCancel call.
-func (t *Transport) replaceReqCanceler(r *Request, fn func()) bool {
-	t.reqMu.Lock()
-	defer t.reqMu.Unlock()
-	_, ok := t.reqCanceler[r]
-	if !ok {
-		return false
-	}
-	if fn != nil {
-		t.reqCanceler[r] = fn
-	} else {
-		delete(t.reqCanceler, r)
-	}
-	return true
-}
-
 func (t *Transport) dial(network, addr string) (c net.Conn, err error) {
 	if t.Dial != nil {
 		return t.Dial(network, addr)
@@ -510,10 +490,6 @@ var prePendingDial, postPendingDial func()
 // is ready to write requests to.
 func (t *Transport) getConn(req *Request, cm connectMethod) (*persistConn, error) {
 	if pc := t.getIdleConn(cm); pc != nil {
-		// set request canceler to some non-nil function so we
-		// can detect whether it was cleared between now and when
-		// we enter roundTrip
-		t.setReqCanceler(req, func() {})
 		return pc, nil
 	}
 
@@ -523,11 +499,6 @@ func (t *Transport) getConn(req *Request, cm connectMethod) (*persistConn, error
 	}
 	dialc := make(chan dialRes)
 
-	// Copy these hooks so we don't race on the postPendingDial in
-	// the goroutine we launch. Issue 11136.
-	prePendingDial := prePendingDial
-	postPendingDial := postPendingDial
-
 	handlePendingDial := func() {
 		if prePendingDial != nil {
 			prePendingDial()
@@ -563,9 +534,6 @@ func (t *Transport) getConn(req *Request, cm connectMethod) (*persistConn, error
 		// when it finishes:
 		handlePendingDial()
 		return pc, nil
-	case <-req.Cancel:
-		handlePendingDial()
-		return nil, errors.New("net/http: request canceled while waiting for connection")
 	case <-cancelc:
 		handlePendingDial()
 		return nil, errors.New("net/http: request canceled while waiting for connection")
@@ -645,9 +613,16 @@ func (t *Transport) dialConn(cm connectMethod) (*persistConn, error) {
 
 	if cm.targetScheme == "https" && !tlsDial {
 		// Initiate TLS and check remote host name against certificate.
-		cfg := cloneTLSClientConfig(t.TLSClientConfig)
-		if cfg.ServerName == "" {
-			cfg.ServerName = cm.tlsHost()
+		cfg := t.TLSClientConfig
+		if cfg == nil || cfg.ServerName == "" {
+			host := cm.tlsHost()
+			if cfg == nil {
+				cfg = &tls.Config{ServerName: host}
+			} else {
+				clone := *cfg // shallow clone
+				clone.ServerName = host
+				cfg = &clone
+			}
 		}
 		plainConn := pconn.conn
 		tlsConn := tls.Client(plainConn, cfg)
@@ -687,7 +662,7 @@ func (t *Transport) dialConn(cm connectMethod) (*persistConn, error) {
 	return pconn, nil
 }
 
-// useProxy reports whether requests to addr should use a proxy,
+// useProxy returns true if requests to addr should use a proxy,
 // according to the NO_PROXY or no_proxy environment variable.
 // addr is always a canonicalAddr with a host and port.
 func useProxy(addr string) bool {
@@ -830,7 +805,6 @@ type persistConn struct {
 	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.
-	canceled             bool // whether this conn was broken due a CancelRequest
 	// mutateHeaderFunc is an optional func to modify extra
 	// headers on each outbound request before it's written. (the
 	// original Request given to RoundTrip is not modified)
@@ -845,33 +819,25 @@ func (pc *persistConn) isBroken() bool {
 	return b
 }
 
-// isCanceled reports whether this connection was closed due to CancelRequest.
-func (pc *persistConn) isCanceled() bool {
-	pc.lk.Lock()
-	defer pc.lk.Unlock()
-	return pc.canceled
-}
-
 func (pc *persistConn) cancelRequest() {
-	pc.lk.Lock()
-	defer pc.lk.Unlock()
-	pc.canceled = true
-	pc.closeLocked()
+	pc.conn.Close()
 }
 
-func (pc *persistConn) readLoop() {
-	// eofc is used to block http.Handler goroutines reading from Response.Body
-	// at EOF until this goroutines has (potentially) added the connection
-	// back to the idle pool.
-	eofc := make(chan struct{})
-	defer close(eofc) // unblock reader on errors
+var remoteSideClosedFunc func(error) bool // or nil to use default
 
-	// Read this once, before loop starts. (to avoid races in tests)
-	testHookMu.Lock()
-	testHookReadLoopBeforeNextRead := testHookReadLoopBeforeNextRead
-	testHookMu.Unlock()
+func remoteSideClosed(err error) bool {
+	if err == io.EOF {
+		return true
+	}
+	if remoteSideClosedFunc != nil {
+		return remoteSideClosedFunc(err)
+	}
+	return false
+}
 
+func (pc *persistConn) readLoop() {
 	alive := true
+
 	for alive {
 		pb, err := pc.br.Peek(1)
 
@@ -929,79 +895,49 @@ func (pc *persistConn) readLoop() {
 			alive = false
 		}
 
-		var waitForBodyRead chan bool // channel is nil when there's no body
+		var waitForBodyRead chan bool
 		if hasBody {
 			waitForBodyRead = make(chan bool, 2)
 			resp.Body.(*bodyEOFSignal).earlyCloseFn = func() error {
+				// Sending false here sets alive to
+				// false and closes the connection
+				// below.
 				waitForBodyRead <- false
 				return nil
 			}
-			resp.Body.(*bodyEOFSignal).fn = func(err error) error {
-				isEOF := err == io.EOF
-				waitForBodyRead <- isEOF
-				if isEOF {
-					<-eofc // see comment at top
-				} else if err != nil && pc.isCanceled() {
-					return errRequestCanceled
-				}
-				return err
+			resp.Body.(*bodyEOFSignal).fn = func(err error) {
+				waitForBodyRead <- alive &&
+					err == nil &&
+					!pc.sawEOF &&
+					pc.wroteRequest() &&
+					pc.t.putIdleConn(pc)
 			}
-		} else {
-			// Before send on rc.ch, as client might re-use the
-			// same *Request pointer, and we don't want to set this
-			// on t from this persistConn while the Transport
-			// potentially spins up a different persistConn for the
-			// caller's subsequent request.
-			pc.t.setReqCanceler(rc.req, nil)
 		}
 
-		pc.lk.Lock()
-		pc.numExpectedResponses--
-		pc.lk.Unlock()
+		if alive && !hasBody {
+			alive = !pc.sawEOF &&
+				pc.wroteRequest() &&
+				pc.t.putIdleConn(pc)
+		}
 
-		// The connection might be going away when we put the
-		// idleConn below. When that happens, we close the response channel to signal
-		// to roundTrip that the connection is gone. roundTrip waits for
-		// both closing and a response in a select, so it might choose
-		// the close channel, rather than the response.
-		// We send the response first so that roundTrip can check
-		// if there is a pending one with a non-blocking select
-		// on the response channel before erroring out.
 		rc.ch <- responseAndError{resp, err}
 
-		if hasBody {
-			// To avoid a race, wait for the just-returned
-			// response body to be fully consumed before peek on
-			// the underlying bufio reader.
+		// Wait for the just-returned response body to be fully consumed
+		// before we race and peek on the underlying bufio reader.
+		if waitForBodyRead != nil {
 			select {
-			case <-rc.req.Cancel:
-				alive = false
-				pc.t.CancelRequest(rc.req)
-			case bodyEOF := <-waitForBodyRead:
-				pc.t.setReqCanceler(rc.req, nil) // before pc might return to idle pool
-				alive = alive &&
-					bodyEOF &&
-					!pc.sawEOF &&
-					pc.wroteRequest() &&
-					pc.t.putIdleConn(pc)
-				if bodyEOF {
-					eofc <- struct{}{}
-				}
+			case alive = <-waitForBodyRead:
 			case <-pc.closech:
 				alive = false
 			}
-		} else {
-			alive = alive &&
-				!pc.sawEOF &&
-				pc.wroteRequest() &&
-				pc.t.putIdleConn(pc)
 		}
 
-		if hook := testHookReadLoopBeforeNextRead; hook != nil {
-			hook()
+		pc.t.setReqCanceler(rc.req, nil)
+
+		if !alive {
+			pc.close()
 		}
 	}
-	pc.close()
 }
 
 func (pc *persistConn) writeLoop() {
@@ -1091,24 +1027,9 @@ 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"}
-var errRequestCanceled = errors.New("net/http: request canceled")
-
-// nil except for tests
-var (
-	testHookPersistConnClosedGotRes func()
-	testHookEnterRoundTrip          func()
-	testHookMu                      sync.Locker = fakeLocker{} // guards following
-	testHookReadLoopBeforeNextRead  func()
-)
 
 func (pc *persistConn) roundTrip(req *transportRequest) (resp *Response, err error) {
-	if hook := testHookEnterRoundTrip; hook != nil {
-		hook()
-	}
-	if !pc.t.replaceReqCanceler(req.Request, pc.cancelRequest) {
-		pc.t.putIdleConn(pc)
-		return nil, errRequestCanceled
-	}
+	pc.t.setReqCanceler(req.Request, pc.cancelRequest)
 	pc.lk.Lock()
 	pc.numExpectedResponses++
 	headerFn := pc.mutateHeaderFunc
@@ -1134,19 +1055,15 @@ func (pc *persistConn) roundTrip(req *transportRequest) (resp *Response, err err
 		// Note that we don't request this for HEAD requests,
 		// due to a bug in nginx:
 		//   http://trac.nginx.org/nginx/ticket/358
-		//   https://golang.org/issue/5522
+		//   http://golang.org/issue/5522
 		//
 		// We don't request gzip if the request is for a range, since
 		// auto-decoding a portion of a gzipped document will just fail
-		// anyway. See https://golang.org/issue/8923
+		// anyway. See http://golang.org/issue/8923
 		requestedGzip = true
 		req.extraHeaders().Set("Accept-Encoding", "gzip")
 	}
 
-	if pc.t.DisableKeepAlives {
-		req.extraHeaders().Set("Connection", "close")
-	}
-
 	// Write the request concurrently with waiting for a response,
 	// in case the server decides to reply before reading our full
 	// request body.
@@ -1157,57 +1074,38 @@ func (pc *persistConn) roundTrip(req *transportRequest) (resp *Response, err err
 	pc.reqch <- requestAndChan{req.Request, resc, requestedGzip}
 
 	var re responseAndError
+	var pconnDeadCh = pc.closech
+	var failTicker <-chan time.Time
 	var respHeaderTimer <-chan time.Time
-	cancelChan := req.Request.Cancel
 WaitResponse:
 	for {
 		select {
 		case err := <-writeErrCh:
-			if isNetWriteError(err) {
-				// Issue 11745. If we failed to write the request
-				// body, it's possible the server just heard enough
-				// and already wrote to us. Prioritize the server's
-				// response over returning a body write error.
-				select {
-				case re = <-resc:
-					pc.close()
-					break WaitResponse
-				case <-time.After(50 * time.Millisecond):
-					// Fall through.
-				}
-			}
 			if err != nil {
 				re = responseAndError{nil, err}
 				pc.close()
 				break WaitResponse
 			}
 			if d := pc.t.ResponseHeaderTimeout; d > 0 {
-				timer := time.NewTimer(d)
-				defer timer.Stop() // prevent leaks
-				respHeaderTimer = timer.C
+				respHeaderTimer = time.After(d)
 			}
-		case <-pc.closech:
+		case <-pconnDeadCh:
 			// The persist connection is dead. This shouldn't
 			// usually happen (only with Connection: close responses
 			// with no response bodies), but if it does happen it
 			// means either a) the remote server hung up on us
 			// prematurely, or b) the readLoop sent us a response &
 			// closed its closech at roughly the same time, and we
-			// selected this case first. If we got a response, readLoop makes sure
-			// to send it before it puts the conn and closes the channel.
-			// That way, we can fetch the response, if there is one,
-			// with a non-blocking receive.
-			select {
-			case re = <-resc:
-				if fn := testHookPersistConnClosedGotRes; fn != nil {
-					fn()
-				}
-			default:
-				re = responseAndError{err: errClosed}
-				if pc.isCanceled() {
-					re = responseAndError{err: errRequestCanceled}
-				}
-			}
+			// selected this case first, in which case a response
+			// might still be coming soon.
+			//
+			// We can't avoid the select race in b) by using a unbuffered
+			// resc channel instead, because then goroutines can
+			// leak if we exit due to other errors.
+			pconnDeadCh = nil                               // avoid spinning
+			failTicker = time.After(100 * time.Millisecond) // arbitrary time to wait for resc
+		case <-failTicker:
+			re = responseAndError{err: errClosed}
 			break WaitResponse
 		case <-respHeaderTimer:
 			pc.close()
@@ -1215,12 +1113,13 @@ WaitResponse:
 			break WaitResponse
 		case re = <-resc:
 			break WaitResponse
-		case <-cancelChan:
-			pc.t.CancelRequest(req.Request)
-			cancelChan = nil
 		}
 	}
 
+	pc.lk.Lock()
+	pc.numExpectedResponses--
+	pc.lk.Unlock()
+
 	if re.err != nil {
 		pc.t.setReqCanceler(req.Request, nil)
 	}
@@ -1268,18 +1167,16 @@ func canonicalAddr(url *url.URL) string {
 
 // bodyEOFSignal wraps a ReadCloser but runs fn (if non-nil) at most
 // once, right before its final (error-producing) Read or Close call
-// returns. fn should return the new error to return from Read or Close.
-//
-// If earlyCloseFn is non-nil and Close is called before io.EOF is
-// seen, earlyCloseFn is called instead of fn, and its return value is
-// the return value from Close.
+// returns. If earlyCloseFn is non-nil and Close is called before
+// io.EOF is seen, earlyCloseFn is called instead of fn, and its
+// return value is the return value from Close.
 type bodyEOFSignal struct {
 	body         io.ReadCloser
-	mu           sync.Mutex        // guards following 4 fields
-	closed       bool              // whether Close has been called
-	rerr         error             // sticky Read error
-	fn           func(error) error // err will be nil on Read io.EOF
-	earlyCloseFn func() error      // optional alt Close func used if io.EOF not seen
+	mu           sync.Mutex   // guards following 4 fields
+	closed       bool         // whether Close has been called
+	rerr         error        // sticky Read error
+	fn           func(error)  // error will be nil on Read io.EOF
+	earlyCloseFn func() error // optional alt Close func used if io.EOF not seen
 }
 
 func (es *bodyEOFSignal) Read(p []byte) (n int, err error) {
@@ -1300,7 +1197,7 @@ func (es *bodyEOFSignal) Read(p []byte) (n int, err error) {
 		if es.rerr == nil {
 			es.rerr = err
 		}
-		err = es.condfn(err)
+		es.condfn(err)
 	}
 	return
 }
@@ -1316,17 +1213,20 @@ func (es *bodyEOFSignal) Close() error {
 		return es.earlyCloseFn()
 	}
 	err := es.body.Close()
-	return es.condfn(err)
+	es.condfn(err)
+	return err
 }
 
 // caller must hold es.mu.
-func (es *bodyEOFSignal) condfn(err error) error {
+func (es *bodyEOFSignal) condfn(err error) {
 	if es.fn == nil {
-		return err
+		return
+	}
+	if err == io.EOF {
+		err = nil
 	}
-	err = es.fn(err)
+	es.fn(err)
 	es.fn = nil
-	return err
 }
 
 // gzipReader wraps a response body so it can lazily
@@ -1373,89 +1273,3 @@ func (nr noteEOFReader) Read(p []byte) (n int, err error) {
 	}
 	return
 }
-
-// fakeLocker is a sync.Locker which does nothing. It's used to guard
-// test-only fields when not under test, to avoid runtime atomic
-// overhead.
-type fakeLocker struct{}
-
-func (fakeLocker) Lock()   {}
-func (fakeLocker) Unlock() {}
-
-func isNetWriteError(err error) bool {
-	switch e := err.(type) {
-	case *url.Error:
-		return isNetWriteError(e.Err)
-	case *net.OpError:
-		return e.Op == "write"
-	default:
-		return false
-	}
-}
-
-// cloneTLSConfig returns a shallow clone of the exported
-// fields of cfg, ignoring the unexported sync.Once, which
-// contains a mutex and must not be copied.
-//
-// The cfg must not be in active use by tls.Server, or else
-// there can still be a race with tls.Server updating SessionTicketKey
-// and our copying it, and also a race with the server setting
-// SessionTicketsDisabled=false on failure to set the random
-// ticket key.
-//
-// If cfg is nil, a new zero tls.Config is returned.
-func cloneTLSConfig(cfg *tls.Config) *tls.Config {
-	if cfg == nil {
-		return &tls.Config{}
-	}
-	return &tls.Config{
-		Rand:                     cfg.Rand,
-		Time:                     cfg.Time,
-		Certificates:             cfg.Certificates,
-		NameToCertificate:        cfg.NameToCertificate,
-		GetCertificate:           cfg.GetCertificate,
-		RootCAs:                  cfg.RootCAs,
-		NextProtos:               cfg.NextProtos,
-		ServerName:               cfg.ServerName,
-		ClientAuth:               cfg.ClientAuth,
-		ClientCAs:                cfg.ClientCAs,
-		InsecureSkipVerify:       cfg.InsecureSkipVerify,
-		CipherSuites:             cfg.CipherSuites,
-		PreferServerCipherSuites: cfg.PreferServerCipherSuites,
-		SessionTicketsDisabled:   cfg.SessionTicketsDisabled,
-		SessionTicketKey:         cfg.SessionTicketKey,
-		ClientSessionCache:       cfg.ClientSessionCache,
-		MinVersion:               cfg.MinVersion,
-		MaxVersion:               cfg.MaxVersion,
-		CurvePreferences:         cfg.CurvePreferences,
-	}
-}
-
-// cloneTLSClientConfig is like cloneTLSConfig but omits
-// the fields SessionTicketsDisabled and SessionTicketKey.
-// This makes it safe to call cloneTLSClientConfig on a config
-// in active use by a server.
-func cloneTLSClientConfig(cfg *tls.Config) *tls.Config {
-	if cfg == nil {
-		return &tls.Config{}
-	}
-	return &tls.Config{
-		Rand:                     cfg.Rand,
-		Time:                     cfg.Time,
-		Certificates:             cfg.Certificates,
-		NameToCertificate:        cfg.NameToCertificate,
-		GetCertificate:           cfg.GetCertificate,
-		RootCAs:                  cfg.RootCAs,
-		NextProtos:               cfg.NextProtos,
-		ServerName:               cfg.ServerName,
-		ClientAuth:               cfg.ClientAuth,
-		ClientCAs:                cfg.ClientCAs,
-		InsecureSkipVerify:       cfg.InsecureSkipVerify,
-		CipherSuites:             cfg.CipherSuites,
-		PreferServerCipherSuites: cfg.PreferServerCipherSuites,
-		ClientSessionCache:       cfg.ClientSessionCache,
-		MinVersion:               cfg.MinVersion,
-		MaxVersion:               cfg.MaxVersion,
-		CurvePreferences:         cfg.CurvePreferences,
-	}
-}
diff --git a/src/net/http/transport_test.go b/src/net/http/transport_test.go
index c21d4af..defa633 100644
--- a/src/net/http/transport_test.go
+++ b/src/net/http/transport_test.go
@@ -18,11 +18,11 @@ import (
 	"io/ioutil"
 	"log"
 	"net"
+	"net/http"
 	. "net/http"
 	"net/http/httptest"
 	"net/url"
 	"os"
-	"reflect"
 	"runtime"
 	"strconv"
 	"strings"
@@ -39,7 +39,6 @@ var hostPortHandler = HandlerFunc(func(w ResponseWriter, r *Request) {
 	if r.FormValue("close") == "true" {
 		w.Header().Set("Connection", "close")
 	}
-	w.Header().Set("X-Saw-Close", fmt.Sprint(r.Close))
 	w.Write([]byte(r.RemoteAddr))
 })
 
@@ -229,10 +228,6 @@ func TestTransportConnectionCloseOnRequest(t *testing.T) {
 			if err != nil {
 				t.Fatalf("error in connectionClose=%v, req #%d, Do: %v", connectionClose, n, err)
 			}
-			if got, want := res.Header.Get("X-Saw-Close"), fmt.Sprint(connectionClose); got != want {
-				t.Errorf("For connectionClose = %v; handler's X-Saw-Close was %v; want %v",
-					connectionClose, got, !connectionClose)
-			}
 			body, err := ioutil.ReadAll(res.Body)
 			if err != nil {
 				t.Fatalf("error in connectionClose=%v, req #%d, ReadAll: %v", connectionClose, n, err)
@@ -254,27 +249,6 @@ func TestTransportConnectionCloseOnRequest(t *testing.T) {
 	connSet.check(t)
 }
 
-// if the Transport's DisableKeepAlives is set, all requests should
-// send Connection: close.
-func TestTransportConnectionCloseOnRequestDisableKeepAlive(t *testing.T) {
-	defer afterTest(t)
-	ts := httptest.NewServer(hostPortHandler)
-	defer ts.Close()
-
-	tr := &Transport{
-		DisableKeepAlives: true,
-	}
-	c := &Client{Transport: tr}
-	res, err := c.Get(ts.URL)
-	if err != nil {
-		t.Fatal(err)
-	}
-	res.Body.Close()
-	if res.Header.Get("X-Saw-Close") != "true" {
-		t.Errorf("handler didn't see Connection: close ")
-	}
-}
-
 func TestTransportIdleCacheKeys(t *testing.T) {
 	defer afterTest(t)
 	ts := httptest.NewServer(hostPortHandler)
@@ -319,7 +293,7 @@ func TestTransportReadToEndReusesConn(t *testing.T) {
 		addrSeen[r.RemoteAddr]++
 		if r.URL.Path == "/chunked/" {
 			w.WriteHeader(200)
-			w.(Flusher).Flush()
+			w.(http.Flusher).Flush()
 		} else {
 			w.Header().Set("Content-Type", strconv.Itoa(len(msg)))
 			w.WriteHeader(200)
@@ -334,7 +308,7 @@ func TestTransportReadToEndReusesConn(t *testing.T) {
 		wantLen := []int{len(msg), -1}[pi]
 		addrSeen = make(map[string]int)
 		for i := 0; i < 3; i++ {
-			res, err := Get(ts.URL + path)
+			res, err := http.Get(ts.URL + path)
 			if err != nil {
 				t.Errorf("Get %s: %v", path, err)
 				continue
@@ -485,7 +459,7 @@ func TestTransportServerClosingUnexpectedly(t *testing.T) {
 	}
 }
 
-// Test for https://golang.org/issue/2616 (appropriate issue number)
+// Test for http://golang.org/issue/2616 (appropriate issue number)
 // This fails pretty reliably with GOMAXPROCS=100 or something high.
 func TestStressSurpriseServerCloses(t *testing.T) {
 	defer afterTest(t)
@@ -505,17 +479,12 @@ func TestStressSurpriseServerCloses(t *testing.T) {
 
 	tr := &Transport{DisableKeepAlives: false}
 	c := &Client{Transport: tr}
-	defer tr.CloseIdleConnections()
 
 	// Do a bunch of traffic from different goroutines. Send to activityc
 	// after each request completes, regardless of whether it failed.
-	// If these are too high, OS X exhausts its ephemeral ports
-	// and hangs waiting for them to transition TCP states. That's
-	// not what we want to test.  TODO(bradfitz): use an io.Pipe
-	// dialer for this test instead?
 	const (
-		numClients    = 20
-		reqsPerClient = 25
+		numClients    = 50
+		reqsPerClient = 250
 	)
 	activityc := make(chan bool)
 	for i := 0; i < numClients; i++ {
@@ -598,22 +567,11 @@ func TestTransportHeadChunkedResponse(t *testing.T) {
 	tr := &Transport{DisableKeepAlives: false}
 	c := &Client{Transport: tr}
 
-	// Ensure that we wait for the readLoop to complete before
-	// calling Head again
-	didRead := make(chan bool)
-	SetReadLoopBeforeNextReadHook(func() { didRead <- true })
-	defer SetReadLoopBeforeNextReadHook(nil)
-
 	res1, err := c.Head(ts.URL)
-	<-didRead
-
 	if err != nil {
 		t.Fatalf("request 1 error: %v", err)
 	}
-
 	res2, err := c.Head(ts.URL)
-	<-didRead
-
 	if err != nil {
 		t.Fatalf("request 2 error: %v", err)
 	}
@@ -875,7 +833,7 @@ func TestTransportGzipShort(t *testing.T) {
 // 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 https://golang.org/issue/7237")
+		t.Skip("skipping test; see http://golang.org/issue/7237")
 	}
 	defer afterTest(t)
 	gotReqCh := make(chan bool)
@@ -944,7 +902,7 @@ func TestTransportPersistConnLeak(t *testing.T) {
 // request.ContentLength is explicitly short
 func TestTransportPersistConnLeakShortBody(t *testing.T) {
 	if runtime.GOOS == "plan9" {
-		t.Skip("skipping test; see https://golang.org/issue/7237")
+		t.Skip("skipping test; see http://golang.org/issue/7237")
 	}
 	defer afterTest(t)
 	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
@@ -983,7 +941,7 @@ func TestTransportPersistConnLeakShortBody(t *testing.T) {
 	}
 }
 
-// This used to crash; https://golang.org/issue/3266
+// This used to crash; http://golang.org/issue/3266
 func TestTransportIdleConnCrash(t *testing.T) {
 	defer afterTest(t)
 	tr := &Transport{}
@@ -1065,7 +1023,7 @@ func TestIssue3595(t *testing.T) {
 	}
 }
 
-// From https://golang.org/issue/4454 ,
+// From http://golang.org/issue/4454 ,
 // "client fails to handle requests with no body and chunked encoding"
 func TestChunkedNoContent(t *testing.T) {
 	defer afterTest(t)
@@ -1152,7 +1110,7 @@ func TestTransportConcurrency(t *testing.T) {
 
 func TestIssue4191_InfiniteGetTimeout(t *testing.T) {
 	if runtime.GOOS == "plan9" {
-		t.Skip("skipping test; see https://golang.org/issue/7237")
+		t.Skip("skipping test; see http://golang.org/issue/7237")
 	}
 	defer afterTest(t)
 	const debug = false
@@ -1216,7 +1174,7 @@ func TestIssue4191_InfiniteGetTimeout(t *testing.T) {
 
 func TestIssue4191_InfiniteGetToPutTimeout(t *testing.T) {
 	if runtime.GOOS == "plan9" {
-		t.Skip("skipping test; see https://golang.org/issue/7237")
+		t.Skip("skipping test; see http://golang.org/issue/7237")
 	}
 	defer afterTest(t)
 	const debug = false
@@ -1387,8 +1345,8 @@ func TestTransportCancelRequest(t *testing.T) {
 	body, err := ioutil.ReadAll(res.Body)
 	d := time.Since(t0)
 
-	if err != ExportErrRequestCanceled {
-		t.Errorf("Body.Read error = %v; want errRequestCanceled", err)
+	if err == nil {
+		t.Error("expected an error reading the body")
 	}
 	if string(body) != "Hello" {
 		t.Errorf("Body = %q; want Hello", body)
@@ -1398,7 +1356,7 @@ func TestTransportCancelRequest(t *testing.T) {
 	}
 	// Verify no outstanding requests after readLoop/writeLoop
 	// goroutines shut down.
-	for tries := 5; tries > 0; tries-- {
+	for tries := 3; tries > 0; tries-- {
 		n := tr.NumPendingRequestsForTesting()
 		if n == 0 {
 			break
@@ -1447,7 +1405,6 @@ func TestTransportCancelRequestInDial(t *testing.T) {
 
 	eventLog.Printf("canceling")
 	tr.CancelRequest(req)
-	tr.CancelRequest(req) // used to panic on second call
 
 	select {
 	case <-gotres:
@@ -1465,135 +1422,6 @@ Get = Get http://something.no-network.tld/: net/http: request canceled while wai
 	}
 }
 
-func TestCancelRequestWithChannel(t *testing.T) {
-	defer afterTest(t)
-	if testing.Short() {
-		t.Skip("skipping test in -short mode")
-	}
-	unblockc := make(chan bool)
-	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
-		fmt.Fprintf(w, "Hello")
-		w.(Flusher).Flush() // send headers and some body
-		<-unblockc
-	}))
-	defer ts.Close()
-	defer close(unblockc)
-
-	tr := &Transport{}
-	defer tr.CloseIdleConnections()
-	c := &Client{Transport: tr}
-
-	req, _ := NewRequest("GET", ts.URL, nil)
-	ch := make(chan struct{})
-	req.Cancel = ch
-
-	res, err := c.Do(req)
-	if err != nil {
-		t.Fatal(err)
-	}
-	go func() {
-		time.Sleep(1 * time.Second)
-		close(ch)
-	}()
-	t0 := time.Now()
-	body, err := ioutil.ReadAll(res.Body)
-	d := time.Since(t0)
-
-	if err != ExportErrRequestCanceled {
-		t.Errorf("Body.Read error = %v; want errRequestCanceled", err)
-	}
-	if string(body) != "Hello" {
-		t.Errorf("Body = %q; want Hello", body)
-	}
-	if d < 500*time.Millisecond {
-		t.Errorf("expected ~1 second delay; got %v", d)
-	}
-	// Verify no outstanding requests after readLoop/writeLoop
-	// goroutines shut down.
-	for tries := 5; tries > 0; tries-- {
-		n := tr.NumPendingRequestsForTesting()
-		if n == 0 {
-			break
-		}
-		time.Sleep(100 * time.Millisecond)
-		if tries == 1 {
-			t.Errorf("pending requests = %d; want 0", n)
-		}
-	}
-}
-
-func TestCancelRequestWithChannelBeforeDo(t *testing.T) {
-	defer afterTest(t)
-	unblockc := make(chan bool)
-	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
-		<-unblockc
-	}))
-	defer ts.Close()
-	defer close(unblockc)
-
-	// Don't interfere with the next test on plan9.
-	// Cf. https://golang.org/issues/11476
-	if runtime.GOOS == "plan9" {
-		defer time.Sleep(500 * time.Millisecond)
-	}
-
-	tr := &Transport{}
-	defer tr.CloseIdleConnections()
-	c := &Client{Transport: tr}
-
-	req, _ := NewRequest("GET", ts.URL, nil)
-	ch := make(chan struct{})
-	req.Cancel = ch
-	close(ch)
-
-	_, err := c.Do(req)
-	if err == nil || !strings.Contains(err.Error(), "canceled") {
-		t.Errorf("Do error = %v; want cancelation", err)
-	}
-}
-
-// Issue 11020. The returned error message should be errRequestCanceled
-func TestTransportCancelBeforeResponseHeaders(t *testing.T) {
-	t.Skip("Skipping flaky test; see Issue 11894")
-	defer afterTest(t)
-
-	serverConnCh := make(chan net.Conn, 1)
-	tr := &Transport{
-		Dial: func(network, addr string) (net.Conn, error) {
-			cc, sc := net.Pipe()
-			serverConnCh <- sc
-			return cc, nil
-		},
-	}
-	defer tr.CloseIdleConnections()
-	errc := make(chan error, 1)
-	req, _ := NewRequest("GET", "http://example.com/", nil)
-	go func() {
-		_, err := tr.RoundTrip(req)
-		errc <- err
-	}()
-
-	sc := <-serverConnCh
-	verb := make([]byte, 3)
-	if _, err := io.ReadFull(sc, verb); err != nil {
-		t.Errorf("Error reading HTTP verb from server: %v", err)
-	}
-	if string(verb) != "GET" {
-		t.Errorf("server received %q; want GET", verb)
-	}
-	defer sc.Close()
-
-	tr.CancelRequest(req)
-
-	err := <-errc
-	if err == nil {
-		t.Fatalf("unexpected success from RoundTrip")
-	}
-	if err != ExportErrRequestCanceled {
-		t.Errorf("RoundTrip error = %v; want ExportErrRequestCanceled", err)
-	}
-}
-
 // 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.
@@ -1967,11 +1795,6 @@ func TestIdleConnChannelLeak(t *testing.T) {
 	}))
 	defer ts.Close()
 
-	const nReqs = 5
-	didRead := make(chan bool, nReqs)
-	SetReadLoopBeforeNextReadHook(func() { didRead <- true })
-	defer SetReadLoopBeforeNextReadHook(nil)
-
 	tr := &Transport{
 		Dial: func(netw, addr string) (net.Conn, error) {
 			return net.Dial(netw, ts.Listener.Addr().String())
@@ -1984,28 +1807,12 @@ func TestIdleConnChannelLeak(t *testing.T) {
 	// First, without keep-alives.
 	for _, disableKeep := range []bool{true, false} {
 		tr.DisableKeepAlives = disableKeep
-		for i := 0; i < nReqs; i++ {
+		for i := 0; i < 5; i++ {
 			_, err := c.Get(fmt.Sprintf("http://foo-host-%d.tld/", i))
 			if err != nil {
 				t.Fatal(err)
 			}
-			// Note: no res.Body.Close is needed here, since the
-			// response Content-Length is zero. Perhaps the test
-			// should be more explicit and use a HEAD, but tests
-			// elsewhere guarantee that zero byte responses generate
-			// a "Content-Length: 0" instead of chunking.
-		}
-
-		// At this point, each of the 5 Transport.readLoop goroutines
-		// are scheduling noting that there are no response bodies (see
-		// earlier comment), and are then calling putIdleConn, which
-		// decrements this count. Usually that happens quickly, which is
-		// why this test has seemed to work for ages. But it's still
-		// racey: we have wait for them to finish first. See Issue 10427
-		for i := 0; i < nReqs; i++ {
-			<-didRead
 		}
-
 		if got := tr.IdleConnChMapSizeForTesting(); got != 0 {
 			t.Fatalf("ForDisableKeepAlives = %v, map size = %d; want 0", disableKeep, got)
 		}
@@ -2017,7 +1824,7 @@ func TestIdleConnChannelLeak(t *testing.T) {
 // then closes it.
 func TestTransportClosesRequestBody(t *testing.T) {
 	defer afterTest(t)
-	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+	ts := httptest.NewServer(http.HandlerFunc(func(w ResponseWriter, r *Request) {
 		io.Copy(ioutil.Discard, r.Body)
 	}))
 	defer ts.Close()
@@ -2253,38 +2060,6 @@ func TestTransportNoReuseAfterEarlyResponse(t *testing.T) {
 	}
 }
 
-// Tests that we don't leak Transport persistConn.readLoop goroutines
-// when a server hangs up immediately after saying it would keep-alive.
-func TestTransportIssue10457(t *testing.T) {
-	defer afterTest(t) // used to fail in goroutine leak check
-	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
-		// Send a response with no body, keep-alive
-		// (implicit), and then lie and immediately close the
-		// connection. This forces the Transport's readLoop to
-		// immediately Peek an io.EOF and get to the point
-		// that used to hang.
-		conn, _, _ := w.(Hijacker).Hijack()
-		conn.Write([]byte("HTTP/1.1 200 OK\r\nFoo: Bar\r\nContent-Length: 0\r\n\r\n")) // keep-alive
-		conn.Close()
-	}))
-	defer ts.Close()
-	tr := &Transport{}
-	defer tr.CloseIdleConnections()
-	cl := &Client{Transport: tr}
-	res, err := cl.Get(ts.URL)
-	if err != nil {
-		t.Fatalf("Get: %v", err)
-	}
-	defer res.Body.Close()
-
-	// Just a sanity check that we at least get the response. The real
-	// test here is that the "defer afterTest" above doesn't find any
-	// leaked goroutines.
-	if got, want := res.Header.Get("Foo"), "Bar"; got != want {
-		t.Errorf("Foo header = %q; want %q", got, want)
-	}
-}
-
 type errorReader struct {
 	err error
 }
@@ -2298,7 +2073,7 @@ func (f closerFunc) Close() error { return f() }
 // Issue 6981
 func TestTransportClosesBodyOnError(t *testing.T) {
 	if runtime.GOOS == "plan9" {
-		t.Skip("skipping test; see https://golang.org/issue/7782")
+		t.Skip("skipping test; see http://golang.org/issue/7782")
 	}
 	defer afterTest(t)
 	readBody := make(chan error, 1)
@@ -2387,13 +2162,13 @@ func TestTransportDialTLS(t *testing.T) {
 // Test for issue 8755
 // Ensure that if a proxy returns an error, it is exposed by RoundTrip
 func TestRoundTripReturnsProxyError(t *testing.T) {
-	badProxy := func(*Request) (*url.URL, error) {
+	badProxy := func(*http.Request) (*url.URL, error) {
 		return nil, errors.New("errorMessage")
 	}
 
 	tr := &Transport{Proxy: badProxy}
 
-	req, _ := NewRequest("GET", "http://example.com", nil)
+	req, _ := http.NewRequest("GET", "http://example.com", nil)
 
 	_, err := tr.RoundTrip(req)
 
@@ -2474,268 +2249,7 @@ func TestTransportRangeAndGzip(t *testing.T) {
 	res.Body.Close()
 }
 
-// Previously, we used to handle a logical race within RoundTrip by waiting for 100ms
-// in the case of an error. Changing the order of the channel operations got rid of this
-// race.
-//
-// In order to test that the channel op reordering works, we install a hook into the
-// roundTrip function which gets called if we saw the connection go away and
-// we subsequently received a response.
-func TestTransportResponseCloseRace(t *testing.T) {
-	if testing.Short() {
-		t.Skip("skipping in short mode")
-	}
-	defer afterTest(t)
-
-	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
-	}))
-	defer ts.Close()
-	sawRace := false
-	SetInstallConnClosedHook(func() {
-		sawRace = true
-	})
-	defer SetInstallConnClosedHook(nil)
-	tr := &Transport{
-		DisableKeepAlives: true,
-	}
-	req, err := NewRequest("GET", ts.URL, nil)
-	if err != nil {
-		t.Fatal(err)
-	}
-	// selects are not deterministic, so do this a bunch
-	// and see if we handle the logical race at least once.
-	for i := 0; i < 10000; i++ {
-		resp, err := tr.RoundTrip(req)
-		if err != nil {
-			t.Fatalf("unexpected error: %s", err)
-			continue
-		}
-		resp.Body.Close()
-		if sawRace {
-			break
-		}
-	}
-	if !sawRace {
-		t.Errorf("didn't see response/connection going away race")
-	}
-}
-
-// Test for issue 10474
-func TestTransportResponseCancelRace(t *testing.T) {
-	defer afterTest(t)
-
-	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
-		// important that this response has a body.
-		var b [1024]byte
-		w.Write(b[:])
-	}))
-	defer ts.Close()
-
-	tr := &Transport{}
-	defer tr.CloseIdleConnections()
-
-	req, err := NewRequest("GET", ts.URL, nil)
-	if err != nil {
-		t.Fatal(err)
-	}
-	res, err := tr.RoundTrip(req)
-	if err != nil {
-		t.Fatal(err)
-	}
-	// If we do an early close, Transport just throws the connection away and
-	// doesn't reuse it. In order to trigger the bug, it has to reuse the connection
-	// so read the body
-	if _, err := io.Copy(ioutil.Discard, res.Body); err != nil {
-		t.Fatal(err)
-	}
-
-	req2, err := NewRequest("GET", ts.URL, nil)
-	if err != nil {
-		t.Fatal(err)
-	}
-	tr.CancelRequest(req)
-	res, err = tr.RoundTrip(req2)
-	if err != nil {
-		t.Fatal(err)
-	}
-	res.Body.Close()
-}
-
-func TestTransportDialCancelRace(t *testing.T) {
-	defer afterTest(t)
-
-	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {}))
-	defer ts.Close()
-
-	tr := &Transport{}
-	defer tr.CloseIdleConnections()
-
-	req, err := NewRequest("GET", ts.URL, nil)
-	if err != nil {
-		t.Fatal(err)
-	}
-	SetEnterRoundTripHook(func() {
-		tr.CancelRequest(req)
-	})
-	defer SetEnterRoundTripHook(nil)
-	res, err := tr.RoundTrip(req)
-	if err != ExportErrRequestCanceled {
-		t.Errorf("expected canceled request error; got %v", err)
-		if err == nil {
-			res.Body.Close()
-		}
-	}
-}
-
-// logWritesConn is a net.Conn that logs each Write call to writes
-// and then proxies to w.
-// It proxies Read calls to a reader it receives from rch.
-type logWritesConn struct {
-	net.Conn // nil. crash on use.
-
-	w io.Writer
-
-	rch <-chan io.Reader
-	r   io.Reader // nil until received by rch
-
-	mu     sync.Mutex
-	writes []string
-}
-
-func (c *logWritesConn) Write(p []byte) (n int, err error) {
-	c.mu.Lock()
-	defer c.mu.Unlock()
-	c.writes = append(c.writes, string(p))
-	return c.w.Write(p)
-}
-
-func (c *logWritesConn) Read(p []byte) (n int, err error) {
-	if c.r == nil {
-		c.r = <-c.rch
-	}
-	return c.r.Read(p)
-}
-
-func (c *logWritesConn) Close() error { return nil }
-
-// Issue 6574
-func TestTransportFlushesBodyChunks(t *testing.T) {
-	defer afterTest(t)
-	resBody := make(chan io.Reader, 1)
-	connr, connw := io.Pipe() // connection pipe pair
-	lw := &logWritesConn{
-		rch: resBody,
-		w:   connw,
-	}
-	tr := &Transport{
-		Dial: func(network, addr string) (net.Conn, error) {
-			return lw, nil
-		},
-	}
-	bodyr, bodyw := io.Pipe() // body pipe pair
-	go func() {
-		defer bodyw.Close()
-		for i := 0; i < 3; i++ {
-			fmt.Fprintf(bodyw, "num%d\n", i)
-		}
-	}()
-	resc := make(chan *Response)
-	go func() {
-		req, _ := NewRequest("POST", "http://localhost:8080", bodyr)
-		req.Header.Set("User-Agent", "x") // known value for test
-		res, err := tr.RoundTrip(req)
-		if err != nil {
-			t.Error("RoundTrip: %v", err)
-			close(resc)
-			return
-		}
-		resc <- res
-
-	}()
-	// Fully consume the request before checking the Write log vs. want.
-	req, err := ReadRequest(bufio.NewReader(connr))
-	if err != nil {
-		t.Fatal(err)
-	}
-	io.Copy(ioutil.Discard, req.Body)
-
-	// Unblock the transport's roundTrip goroutine.
-	resBody <- strings.NewReader("HTTP/1.1 204 No Content\r\nConnection: close\r\n\r\n")
-	res, ok := <-resc
-	if !ok {
-		return
-	}
-	defer res.Body.Close()
-
-	want := []string{
-		// Because Request.ContentLength = 0, the body is sniffed for 1 byte to determine whether there's content.
-		// That explains the initial "num0" being split into "n" and "um0".
-		// The first byte is included with the request headers Write. Perhaps in the future
-		// we will want to flush the headers out early if the first byte of the request body is
-		// taking a long time to arrive. But not yet.
-		"POST / HTTP/1.1\r\nHost: localhost:8080\r\nUser-Agent: x\r\nTransfer-Encoding: chunked\r\nAccept-Encoding: gzip\r\n\r\n" +
-			"1\r\nn\r\n",
-		"4\r\num0\n\r\n",
-		"5\r\nnum1\n\r\n",
-		"5\r\nnum2\n\r\n",
-		"0\r\n\r\n",
-	}
-	if !reflect.DeepEqual(lw.writes, want) {
-		t.Errorf("Writes differed.\n Got: %q\nWant: %q\n", lw.writes, want)
-	}
-}
-
-// Issue 11745.
-func TestTransportPrefersResponseOverWriteError(t *testing.T) {
-	if testing.Short() {
-		t.Skip("skipping in short mode")
-	}
-	defer afterTest(t)
-	const contentLengthLimit = 1024 * 1024 // 1MB
-	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
-		if r.ContentLength >= contentLengthLimit {
-			w.WriteHeader(StatusBadRequest)
-			r.Body.Close()
-			return
-		}
-		w.WriteHeader(StatusOK)
-	}))
-	defer ts.Close()
-
-	fail := 0
-	count := 100
-	bigBody := strings.Repeat("a", contentLengthLimit*2)
-	for i := 0; i < count; i++ {
-		req, err := NewRequest("PUT", ts.URL, strings.NewReader(bigBody))
-		if err != nil {
-			t.Fatal(err)
-		}
-		tr := new(Transport)
-		defer tr.CloseIdleConnections()
-		client := &Client{Transport: tr}
-		resp, err := client.Do(req)
-		if err != nil {
-			fail++
-			t.Logf("%d = %#v", i, err)
-			if ue, ok := err.(*url.Error); ok {
-				t.Logf("urlErr = %#v", ue.Err)
-				if ne, ok := ue.Err.(*net.OpError); ok {
-					t.Logf("netOpError = %#v", ne.Err)
-				}
-			}
-		} else {
-			resp.Body.Close()
-			if resp.StatusCode != 400 {
-				t.Errorf("Expected status code 400, got %v", resp.Status)
-			}
-		}
-	}
-	if fail > 0 {
-		t.Errorf("Failed %v out of %v\n", fail, count)
-	}
-}
-
-func wantBody(res *Response, err error, want string) error {
+func wantBody(res *http.Response, err error, want string) error {
 	if err != nil {
 		return err
 	}
diff --git a/src/net/interface.go b/src/net/interface.go
index 9c7b5da..2e9f1eb 100644
--- a/src/net/interface.go
+++ b/src/net/interface.go
@@ -62,61 +62,41 @@ func (f Flags) String() string {
 // Addrs returns interface addresses for a specific interface.
 func (ifi *Interface) Addrs() ([]Addr, error) {
 	if ifi == nil {
-		return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: errInvalidInterface}
+		return nil, errInvalidInterface
 	}
-	ifat, err := interfaceAddrTable(ifi)
-	if err != nil {
-		err = &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err}
-	}
-	return ifat, err
+	return interfaceAddrTable(ifi)
 }
 
 // MulticastAddrs returns multicast, joined group addresses for
 // a specific interface.
 func (ifi *Interface) MulticastAddrs() ([]Addr, error) {
 	if ifi == nil {
-		return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: errInvalidInterface}
-	}
-	ifat, err := interfaceMulticastAddrTable(ifi)
-	if err != nil {
-		err = &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err}
+		return nil, errInvalidInterface
 	}
-	return ifat, err
+	return interfaceMulticastAddrTable(ifi)
 }
 
 // Interfaces returns a list of the system's network interfaces.
 func Interfaces() ([]Interface, error) {
-	ift, err := interfaceTable(0)
-	if err != nil {
-		err = &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err}
-	}
-	return ift, err
+	return interfaceTable(0)
 }
 
 // InterfaceAddrs returns a list of the system's network interface
 // addresses.
 func InterfaceAddrs() ([]Addr, error) {
-	ifat, err := interfaceAddrTable(nil)
-	if err != nil {
-		err = &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err}
-	}
-	return ifat, err
+	return interfaceAddrTable(nil)
 }
 
 // InterfaceByIndex returns the interface specified by index.
 func InterfaceByIndex(index int) (*Interface, error) {
 	if index <= 0 {
-		return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: errInvalidInterfaceIndex}
+		return nil, errInvalidInterfaceIndex
 	}
 	ift, err := interfaceTable(index)
 	if err != nil {
-		return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err}
+		return nil, err
 	}
-	ifi, err := interfaceByIndex(ift, index)
-	if err != nil {
-		err = &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err}
-	}
-	return ifi, err
+	return interfaceByIndex(ift, index)
 }
 
 func interfaceByIndex(ift []Interface, index int) (*Interface, error) {
@@ -131,16 +111,16 @@ func interfaceByIndex(ift []Interface, index int) (*Interface, error) {
 // InterfaceByName returns the interface specified by name.
 func InterfaceByName(name string) (*Interface, error) {
 	if name == "" {
-		return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: errInvalidInterfaceName}
+		return nil, errInvalidInterfaceName
 	}
 	ift, err := interfaceTable(0)
 	if err != nil {
-		return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err}
+		return nil, err
 	}
 	for _, ifi := range ift {
 		if name == ifi.Name {
 			return &ifi, nil
 		}
 	}
-	return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: errNoSuchInterface}
+	return nil, errNoSuchInterface
 }
diff --git a/src/net/interface_bsd.go b/src/net/interface_bsd.go
index 208f37f..1677557 100644
--- a/src/net/interface_bsd.go
+++ b/src/net/interface_bsd.go
@@ -18,11 +18,11 @@ import (
 func interfaceTable(ifindex int) ([]Interface, error) {
 	tab, err := syscall.RouteRIB(syscall.NET_RT_IFLIST, ifindex)
 	if err != nil {
-		return nil, os.NewSyscallError("routerib", err)
+		return nil, os.NewSyscallError("route rib", err)
 	}
 	msgs, err := syscall.ParseRoutingMessage(tab)
 	if err != nil {
-		return nil, os.NewSyscallError("parseroutingmessage", err)
+		return nil, os.NewSyscallError("route message", err)
 	}
 	return parseInterfaceTable(ifindex, msgs)
 }
@@ -51,25 +51,27 @@ loop:
 func newLink(m *syscall.InterfaceMessage) (*Interface, error) {
 	sas, err := syscall.ParseRoutingSockaddr(m)
 	if err != nil {
-		return nil, os.NewSyscallError("parseroutingsockaddr", err)
+		return nil, os.NewSyscallError("route sockaddr", err)
 	}
 	ifi := &Interface{Index: int(m.Header.Index), Flags: linkFlags(m.Header.Flags)}
-	sa, _ := sas[syscall.RTAX_IFP].(*syscall.SockaddrDatalink)
-	if sa != nil {
-		// NOTE: SockaddrDatalink.Data is minimum work area,
-		// can be larger.
-		m.Data = m.Data[unsafe.Offsetof(sa.Data):]
-		var name [syscall.IFNAMSIZ]byte
-		for i := 0; i < int(sa.Nlen); i++ {
-			name[i] = byte(m.Data[i])
-		}
-		ifi.Name = string(name[:sa.Nlen])
-		ifi.MTU = int(m.Header.Data.Mtu)
-		addr := make([]byte, sa.Alen)
-		for i := 0; i < int(sa.Alen); i++ {
-			addr[i] = byte(m.Data[int(sa.Nlen)+i])
+	for _, sa := range sas {
+		switch sa := sa.(type) {
+		case *syscall.SockaddrDatalink:
+			// NOTE: SockaddrDatalink.Data is minimum work area,
+			// can be larger.
+			m.Data = m.Data[unsafe.Offsetof(sa.Data):]
+			var name [syscall.IFNAMSIZ]byte
+			for i := 0; i < int(sa.Nlen); i++ {
+				name[i] = byte(m.Data[i])
+			}
+			ifi.Name = string(name[:sa.Nlen])
+			ifi.MTU = int(m.Header.Data.Mtu)
+			addr := make([]byte, sa.Alen)
+			for i := 0; i < int(sa.Alen); i++ {
+				addr[i] = byte(m.Data[int(sa.Nlen)+i])
+			}
+			ifi.HardwareAddr = addr[:sa.Alen]
 		}
-		ifi.HardwareAddr = addr[:sa.Alen]
 	}
 	return ifi, nil
 }
@@ -104,11 +106,11 @@ func interfaceAddrTable(ifi *Interface) ([]Addr, error) {
 	}
 	tab, err := syscall.RouteRIB(syscall.NET_RT_IFLIST, index)
 	if err != nil {
-		return nil, os.NewSyscallError("routerib", err)
+		return nil, os.NewSyscallError("route rib", err)
 	}
 	msgs, err := syscall.ParseRoutingMessage(tab)
 	if err != nil {
-		return nil, os.NewSyscallError("parseroutingmessage", err)
+		return nil, os.NewSyscallError("route message", err)
 	}
 	var ift []Interface
 	if index == 0 {
@@ -142,34 +144,39 @@ func interfaceAddrTable(ifi *Interface) ([]Addr, error) {
 	return ifat, nil
 }
 
-func newAddr(ifi *Interface, m *syscall.InterfaceAddrMessage) (*IPNet, error) {
+func newAddr(ifi *Interface, m *syscall.InterfaceAddrMessage) (Addr, error) {
 	sas, err := syscall.ParseRoutingSockaddr(m)
 	if err != nil {
-		return nil, os.NewSyscallError("parseroutingsockaddr", err)
+		return nil, os.NewSyscallError("route sockaddr", err)
 	}
 	ifa := &IPNet{}
-	switch sa := sas[syscall.RTAX_NETMASK].(type) {
-	case *syscall.SockaddrInet4:
-		ifa.Mask = IPv4Mask(sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3])
-	case *syscall.SockaddrInet6:
-		ifa.Mask = make(IPMask, IPv6len)
-		copy(ifa.Mask, sa.Addr[:])
-	}
-	switch sa := sas[syscall.RTAX_IFA].(type) {
-	case *syscall.SockaddrInet4:
-		ifa.IP = IPv4(sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3])
-	case *syscall.SockaddrInet6:
-		ifa.IP = make(IP, IPv6len)
-		copy(ifa.IP, sa.Addr[:])
-		// NOTE: KAME based IPv6 protcol stack usually embeds
-		// the interface index in the interface-local or
-		// link-local address as the kernel-internal form.
-		if ifa.IP.IsLinkLocalUnicast() {
-			ifa.IP[2], ifa.IP[3] = 0, 0
+	for i, sa := range sas {
+		switch sa := sa.(type) {
+		case *syscall.SockaddrInet4:
+			switch i {
+			case 0:
+				ifa.Mask = IPv4Mask(sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3])
+			case 1:
+				ifa.IP = IPv4(sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3])
+			}
+		case *syscall.SockaddrInet6:
+			switch i {
+			case 0:
+				ifa.Mask = make(IPMask, IPv6len)
+				copy(ifa.Mask, sa.Addr[:])
+			case 1:
+				ifa.IP = make(IP, IPv6len)
+				copy(ifa.IP, sa.Addr[:])
+				// NOTE: KAME based IPv6 protcol stack usually embeds
+				// the interface index in the interface-local or link-
+				// local address as the kernel-internal form.
+				if ifa.IP.IsLinkLocalUnicast() {
+					ifa.IP[2], ifa.IP[3] = 0, 0
+				}
+			}
+		default: // Sockaddrs contain syscall.SockaddrDatalink on NetBSD
+			return nil, nil
 		}
 	}
-	if ifa.IP == nil || ifa.Mask == nil {
-		return nil, nil // Sockaddrs contain syscall.SockaddrDatalink on NetBSD
-	}
 	return ifa, nil
 }
diff --git a/src/net/interface_bsd_test.go b/src/net/interface_bsd_test.go
index 43ccc89..88daf73 100644
--- a/src/net/interface_bsd_test.go
+++ b/src/net/interface_bsd_test.go
@@ -28,8 +28,10 @@ func (ti *testInterface) setBroadcast(suffix int) error {
 	return nil
 }
 
-func (ti *testInterface) setPointToPoint(suffix int) error {
+func (ti *testInterface) setPointToPoint(suffix int, local, remote string) error {
 	ti.name = fmt.Sprintf("gif%d", suffix)
+	ti.local = local
+	ti.remote = remote
 	xname, err := exec.LookPath("ifconfig")
 	if err != nil {
 		return err
diff --git a/src/net/interface_darwin.go b/src/net/interface_darwin.go
index b7a3338..ad0937d 100644
--- a/src/net/interface_darwin.go
+++ b/src/net/interface_darwin.go
@@ -14,11 +14,11 @@ import (
 func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) {
 	tab, err := syscall.RouteRIB(syscall.NET_RT_IFLIST2, ifi.Index)
 	if err != nil {
-		return nil, os.NewSyscallError("routerib", err)
+		return nil, os.NewSyscallError("route rib", err)
 	}
 	msgs, err := syscall.ParseRoutingMessage(tab)
 	if err != nil {
-		return nil, os.NewSyscallError("parseroutingmessage", err)
+		return nil, os.NewSyscallError("route message", err)
 	}
 	var ifmat []Addr
 	for _, m := range msgs {
@@ -29,34 +29,35 @@ func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) {
 				if err != nil {
 					return nil, err
 				}
-				if ifma != nil {
-					ifmat = append(ifmat, ifma)
-				}
+				ifmat = append(ifmat, ifma...)
 			}
 		}
 	}
 	return ifmat, nil
 }
 
-func newMulticastAddr(ifi *Interface, m *syscall.InterfaceMulticastAddrMessage) (*IPAddr, error) {
+func newMulticastAddr(ifi *Interface, m *syscall.InterfaceMulticastAddrMessage) ([]Addr, error) {
 	sas, err := syscall.ParseRoutingSockaddr(m)
 	if err != nil {
-		return nil, os.NewSyscallError("parseroutingsockaddr", err)
+		return nil, os.NewSyscallError("route sockaddr", err)
 	}
-	switch sa := sas[syscall.RTAX_IFA].(type) {
-	case *syscall.SockaddrInet4:
-		return &IPAddr{IP: IPv4(sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3])}, nil
-	case *syscall.SockaddrInet6:
-		ifma := IPAddr{IP: make(IP, IPv6len)}
-		copy(ifma.IP, sa.Addr[:])
-		// NOTE: KAME based IPv6 protcol stack usually embeds
-		// the interface index in the interface-local or
-		// link-local address as the kernel-internal form.
-		if ifma.IP.IsInterfaceLocalMulticast() || ifma.IP.IsLinkLocalMulticast() {
-			ifma.IP[2], ifma.IP[3] = 0, 0
+	var ifmat []Addr
+	for _, sa := range sas {
+		switch sa := sa.(type) {
+		case *syscall.SockaddrInet4:
+			ifma := &IPAddr{IP: IPv4(sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3])}
+			ifmat = append(ifmat, ifma.toAddr())
+		case *syscall.SockaddrInet6:
+			ifma := &IPAddr{IP: make(IP, IPv6len)}
+			copy(ifma.IP, sa.Addr[:])
+			// NOTE: KAME based IPv6 protocol stack usually embeds
+			// the interface index in the interface-local or link-
+			// local address as the kernel-internal form.
+			if ifma.IP.IsInterfaceLocalMulticast() || ifma.IP.IsLinkLocalMulticast() {
+				ifma.IP[2], ifma.IP[3] = 0, 0
+			}
+			ifmat = append(ifmat, ifma.toAddr())
 		}
-		return &ifma, nil
-	default:
-		return nil, nil
 	}
+	return ifmat, nil
 }
diff --git a/src/net/interface_freebsd.go b/src/net/interface_freebsd.go
index c42d90b..5df7679 100644
--- a/src/net/interface_freebsd.go
+++ b/src/net/interface_freebsd.go
@@ -14,11 +14,11 @@ import (
 func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) {
 	tab, err := syscall.RouteRIB(syscall.NET_RT_IFMALIST, ifi.Index)
 	if err != nil {
-		return nil, os.NewSyscallError("routerib", err)
+		return nil, os.NewSyscallError("route rib", err)
 	}
 	msgs, err := syscall.ParseRoutingMessage(tab)
 	if err != nil {
-		return nil, os.NewSyscallError("parseroutingmessage", err)
+		return nil, os.NewSyscallError("route message", err)
 	}
 	var ifmat []Addr
 	for _, m := range msgs {
@@ -29,34 +29,35 @@ func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) {
 				if err != nil {
 					return nil, err
 				}
-				if ifma != nil {
-					ifmat = append(ifmat, ifma)
-				}
+				ifmat = append(ifmat, ifma...)
 			}
 		}
 	}
 	return ifmat, nil
 }
 
-func newMulticastAddr(ifi *Interface, m *syscall.InterfaceMulticastAddrMessage) (*IPAddr, error) {
+func newMulticastAddr(ifi *Interface, m *syscall.InterfaceMulticastAddrMessage) ([]Addr, error) {
 	sas, err := syscall.ParseRoutingSockaddr(m)
 	if err != nil {
-		return nil, os.NewSyscallError("parseroutingsockaddr", err)
+		return nil, os.NewSyscallError("route sockaddr", err)
 	}
-	switch sa := sas[syscall.RTAX_IFA].(type) {
-	case *syscall.SockaddrInet4:
-		return &IPAddr{IP: IPv4(sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3])}, nil
-	case *syscall.SockaddrInet6:
-		ifma := IPAddr{IP: make(IP, IPv6len)}
-		copy(ifma.IP, sa.Addr[:])
-		// NOTE: KAME based IPv6 protcol stack usually embeds
-		// the interface index in the interface-local or
-		// link-local address as the kernel-internal form.
-		if ifma.IP.IsInterfaceLocalMulticast() || ifma.IP.IsLinkLocalMulticast() {
-			ifma.IP[2], ifma.IP[3] = 0, 0
+	var ifmat []Addr
+	for _, sa := range sas {
+		switch sa := sa.(type) {
+		case *syscall.SockaddrInet4:
+			ifma := &IPAddr{IP: IPv4(sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3])}
+			ifmat = append(ifmat, ifma.toAddr())
+		case *syscall.SockaddrInet6:
+			ifma := &IPAddr{IP: make(IP, IPv6len)}
+			copy(ifma.IP, sa.Addr[:])
+			// NOTE: KAME based IPv6 protocol stack usually embeds
+			// the interface index in the interface-local or link-
+			// local address as the kernel-internal form.
+			if ifma.IP.IsInterfaceLocalMulticast() || ifma.IP.IsLinkLocalMulticast() {
+				ifma.IP[2], ifma.IP[3] = 0, 0
+			}
+			ifmat = append(ifmat, ifma.toAddr())
 		}
-		return &ifma, nil
-	default:
-		return nil, nil
 	}
+	return ifmat, nil
 }
diff --git a/src/net/interface_linux.go b/src/net/interface_linux.go
index ef20429..1115d0f 100644
--- a/src/net/interface_linux.go
+++ b/src/net/interface_linux.go
@@ -16,11 +16,11 @@ import (
 func interfaceTable(ifindex int) ([]Interface, error) {
 	tab, err := syscall.NetlinkRIB(syscall.RTM_GETLINK, syscall.AF_UNSPEC)
 	if err != nil {
-		return nil, os.NewSyscallError("netlinkrib", err)
+		return nil, os.NewSyscallError("netlink rib", err)
 	}
 	msgs, err := syscall.ParseNetlinkMessage(tab)
 	if err != nil {
-		return nil, os.NewSyscallError("parsenetlinkmessage", err)
+		return nil, os.NewSyscallError("netlink message", err)
 	}
 	var ift []Interface
 loop:
@@ -33,7 +33,7 @@ loop:
 			if ifindex == 0 || ifindex == int(ifim.Index) {
 				attrs, err := syscall.ParseNetlinkRouteAttr(&m)
 				if err != nil {
-					return nil, os.NewSyscallError("parsenetlinkrouteattr", err)
+					return nil, os.NewSyscallError("netlink routeattr", err)
 				}
 				ift = append(ift, *newLink(ifim, attrs))
 				if ifindex == int(ifim.Index) {
@@ -120,11 +120,11 @@ func linkFlags(rawFlags uint32) Flags {
 func interfaceAddrTable(ifi *Interface) ([]Addr, error) {
 	tab, err := syscall.NetlinkRIB(syscall.RTM_GETADDR, syscall.AF_UNSPEC)
 	if err != nil {
-		return nil, os.NewSyscallError("netlinkrib", err)
+		return nil, os.NewSyscallError("netlink rib", err)
 	}
 	msgs, err := syscall.ParseNetlinkMessage(tab)
 	if err != nil {
-		return nil, os.NewSyscallError("parsenetlinkmessage", err)
+		return nil, os.NewSyscallError("netlink message", err)
 	}
 	var ift []Interface
 	if ifi == nil {
@@ -160,7 +160,7 @@ loop:
 				}
 				attrs, err := syscall.ParseNetlinkRouteAttr(&m)
 				if err != nil {
-					return nil, os.NewSyscallError("parsenetlinkrouteattr", err)
+					return nil, os.NewSyscallError("netlink routeattr", err)
 				}
 				ifa := newAddr(ifi, ifam, attrs)
 				if ifa != nil {
@@ -176,15 +176,17 @@ func newAddr(ifi *Interface, ifam *syscall.IfAddrmsg, attrs []syscall.NetlinkRou
 	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.
-	for _, a := range attrs {
-		if a.Attr.Type == syscall.IFA_LOCAL {
-			ipPointToPoint = true
-			break
+	// 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 {
+		if ipPointToPoint && a.Attr.Type == syscall.IFA_ADDRESS || !ipPointToPoint && a.Attr.Type == syscall.IFA_LOCAL {
 			continue
 		}
 		switch ifam.Family {
@@ -236,8 +238,8 @@ func parseProcNetIGMP(path string, ifi *Interface) []Addr {
 					b[i/2], _ = xtoi2(f[0][i:i+2], 0)
 				}
 				i := *(*uint32)(unsafe.Pointer(&b[:4][0]))
-				ifma := &IPAddr{IP: IPv4(byte(i>>24), byte(i>>16), byte(i>>8), byte(i))}
-				ifmat = append(ifmat, ifma)
+				ifma := IPAddr{IP: IPv4(byte(i>>24), byte(i>>16), byte(i>>8), byte(i))}
+				ifmat = append(ifmat, ifma.toAddr())
 			}
 		}
 	}
@@ -261,8 +263,8 @@ func parseProcNetIGMP6(path string, ifi *Interface) []Addr {
 			for i := 0; i+1 < len(f[2]); i += 2 {
 				b[i/2], _ = xtoi2(f[2][i:i+2], 0)
 			}
-			ifma := &IPAddr{IP: IP{b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7], b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15]}}
-			ifmat = append(ifmat, ifma)
+			ifma := IPAddr{IP: IP{b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7], b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15]}}
+			ifmat = append(ifmat, ifma.toAddr())
 		}
 	}
 	return ifmat
diff --git a/src/net/interface_linux_test.go b/src/net/interface_linux_test.go
index 6251b26..d8800bd 100644
--- a/src/net/interface_linux_test.go
+++ b/src/net/interface_linux_test.go
@@ -20,14 +20,6 @@ func (ti *testInterface) setBroadcast(suffix int) error {
 		Path: xname,
 		Args: []string{"ip", "link", "add", ti.name, "type", "dummy"},
 	})
-	ti.setupCmds = append(ti.setupCmds, &exec.Cmd{
-		Path: xname,
-		Args: []string{"ip", "address", "add", ti.local, "peer", ti.remote, "dev", ti.name},
-	})
-	ti.teardownCmds = append(ti.teardownCmds, &exec.Cmd{
-		Path: xname,
-		Args: []string{"ip", "address", "del", ti.local, "peer", ti.remote, "dev", ti.name},
-	})
 	ti.teardownCmds = append(ti.teardownCmds, &exec.Cmd{
 		Path: xname,
 		Args: []string{"ip", "link", "delete", ti.name, "type", "dummy"},
@@ -35,27 +27,29 @@ func (ti *testInterface) setBroadcast(suffix int) error {
 	return nil
 }
 
-func (ti *testInterface) setPointToPoint(suffix int) error {
+func (ti *testInterface) setPointToPoint(suffix int, local, remote string) error {
 	ti.name = fmt.Sprintf("gotest%d", suffix)
+	ti.local = local
+	ti.remote = remote
 	xname, err := exec.LookPath("ip")
 	if err != nil {
 		return err
 	}
 	ti.setupCmds = append(ti.setupCmds, &exec.Cmd{
 		Path: xname,
-		Args: []string{"ip", "tunnel", "add", ti.name, "mode", "gre", "local", ti.local, "remote", ti.remote},
-	})
-	ti.setupCmds = append(ti.setupCmds, &exec.Cmd{
-		Path: xname,
-		Args: []string{"ip", "address", "add", ti.local, "peer", ti.remote, "dev", ti.name},
+		Args: []string{"ip", "tunnel", "add", ti.name, "mode", "gre", "local", local, "remote", remote},
 	})
 	ti.teardownCmds = append(ti.teardownCmds, &exec.Cmd{
 		Path: xname,
-		Args: []string{"ip", "address", "del", ti.local, "peer", ti.remote, "dev", ti.name},
+		Args: []string{"ip", "tunnel", "del", ti.name, "mode", "gre", "local", local, "remote", remote},
 	})
-	ti.teardownCmds = append(ti.teardownCmds, &exec.Cmd{
+	xname, err = exec.LookPath("ifconfig")
+	if err != nil {
+		return err
+	}
+	ti.setupCmds = append(ti.setupCmds, &exec.Cmd{
 		Path: xname,
-		Args: []string{"ip", "tunnel", "del", ti.name, "mode", "gre", "local", ti.local, "remote", ti.remote},
+		Args: []string{"ifconfig", ti.name, "inet", local, "dstaddr", remote},
 	})
 	return nil
 }
@@ -84,7 +78,7 @@ var (
 func TestParseProcNet(t *testing.T) {
 	defer func() {
 		if p := recover(); p != nil {
-			t.Fatalf("panicked: %v", p)
+			t.Fatalf("parseProcNetIGMP or parseProtNetIGMP6 panicked: %v", p)
 		}
 	}()
 
@@ -94,7 +88,7 @@ func TestParseProcNet(t *testing.T) {
 		ifmat4 = append(ifmat4, ifmat...)
 	}
 	if len(ifmat4) != numOfTestIPv4MCAddrs {
-		t.Fatalf("got %d; want %d", len(ifmat4), numOfTestIPv4MCAddrs)
+		t.Fatalf("parseProcNetIGMP returns %v addresses, expected %v", len(ifmat4), numOfTestIPv4MCAddrs)
 	}
 
 	var ifmat6 []Addr
@@ -103,6 +97,6 @@ func TestParseProcNet(t *testing.T) {
 		ifmat6 = append(ifmat6, ifmat...)
 	}
 	if len(ifmat6) != numOfTestIPv6MCAddrs {
-		t.Fatalf("got %d; want %d", len(ifmat6), numOfTestIPv6MCAddrs)
+		t.Fatalf("parseProcNetIGMP6 returns %v addresses, expected %v", len(ifmat6), numOfTestIPv6MCAddrs)
 	}
 }
diff --git a/src/net/interface_test.go b/src/net/interface_test.go
index 567d18d..efabb5f 100644
--- a/src/net/interface_test.go
+++ b/src/net/interface_test.go
@@ -6,7 +6,6 @@ package net
 
 import (
 	"reflect"
-	"runtime"
 	"testing"
 )
 
@@ -38,7 +37,12 @@ func ipv6LinkLocalUnicastAddr(ifi *Interface) string {
 		return ""
 	}
 	for _, ifa := range ifat {
-		if ifa, ok := ifa.(*IPNet); ok {
+		switch ifa := ifa.(type) {
+		case *IPAddr:
+			if ifa.IP.To4() == nil && ifa.IP.IsLinkLocalUnicast() {
+				return ifa.IP.String()
+			}
+		case *IPNet:
 			if ifa.IP.To4() == nil && ifa.IP.IsLinkLocalUnicast() {
 				return ifa.IP.String()
 			}
@@ -47,259 +51,161 @@ func ipv6LinkLocalUnicastAddr(ifi *Interface) string {
 	return ""
 }
 
-type routeStats struct {
-	loop  int // # of active loopback interfaces
-	other int // # of active other interfaces
-
-	uni4, uni6     int // # of active connected unicast, anycast routes
-	multi4, multi6 int // # of active connected multicast route clones
-}
-
 func TestInterfaces(t *testing.T) {
 	ift, err := Interfaces()
 	if err != nil {
-		t.Fatal(err)
+		t.Fatalf("Interfaces failed: %v", err)
 	}
-	var stats routeStats
+	t.Logf("table: len/cap = %v/%v", len(ift), cap(ift))
+
 	for _, ifi := range ift {
 		ifxi, err := InterfaceByIndex(ifi.Index)
 		if err != nil {
-			t.Fatal(err)
+			t.Fatalf("InterfaceByIndex(%v) failed: %v", ifi.Index, err)
 		}
 		if !reflect.DeepEqual(ifxi, &ifi) {
-			t.Errorf("got %v; want %v", ifxi, ifi)
+			t.Fatalf("InterfaceByIndex(%v) = %v, want %v", ifi.Index, ifxi, ifi)
 		}
 		ifxn, err := InterfaceByName(ifi.Name)
 		if err != nil {
-			t.Fatal(err)
+			t.Fatalf("InterfaceByName(%q) failed: %v", ifi.Name, err)
 		}
 		if !reflect.DeepEqual(ifxn, &ifi) {
-			t.Errorf("got %v; want %v", ifxn, ifi)
+			t.Fatalf("InterfaceByName(%q) = %v, want %v", ifi.Name, ifxn, ifi)
 		}
 		t.Logf("%q: flags %q, ifindex %v, mtu %v", ifi.Name, ifi.Flags.String(), ifi.Index, ifi.MTU)
-		t.Logf("hardware address %q", ifi.HardwareAddr.String())
-		if ifi.Flags&FlagUp != 0 {
-			if ifi.Flags&FlagLoopback != 0 {
-				stats.loop++
-			} else {
-				stats.other++
-			}
-		}
-		n4, n6 := testInterfaceAddrs(t, &ifi)
-		stats.uni4 += n4
-		stats.uni6 += n6
-		n4, n6 = testInterfaceMulticastAddrs(t, &ifi)
-		stats.multi4 += n4
-		stats.multi6 += n6
-	}
-	switch runtime.GOOS {
-	case "nacl", "plan9", "solaris":
-	default:
-		// Test the existence of connected unicast routes for
-		// IPv4.
-		if supportsIPv4 && stats.loop+stats.other > 0 && stats.uni4 == 0 {
-			t.Errorf("num IPv4 unicast routes = 0; want >0; summary: %+v", stats)
-		}
-		// Test the existence of connected unicast routes for
-		// IPv6. We can assume the existence of ::1/128 when
-		// at least one looopback interface is installed.
-		if supportsIPv6 && stats.loop > 0 && stats.uni6 == 0 {
-			t.Errorf("num IPv6 unicast routes = 0; want >0; summary: %+v", stats)
-		}
-	}
-	switch runtime.GOOS {
-	case "dragonfly", "nacl", "netbsd", "openbsd", "plan9", "solaris":
-	default:
-		// Test the existence of connected multicast route
-		// clones for IPv4. Unlike IPv6, IPv4 multicast
-		// capability is not a mandatory feature, and so this
-		// test is disabled.
-		//if supportsIPv4 && stats.loop > 0 && stats.uni4 > 1 && stats.multi4 == 0 {
-		//	t.Errorf("num IPv4 multicast route clones = 0; want >0; summary: %+v", stats)
-		//}
-		// Test the existence of connected multicast route
-		// clones for IPv6. Some platform never uses loopback
-		// interface as the nexthop for multicast routing.
-		// We can assume the existence of connected multicast
-		// route clones when at least two connected unicast
-		// routes, ::1/128 and other, are installed.
-		if supportsIPv6 && stats.loop > 0 && stats.uni6 > 1 && stats.multi6 == 0 {
-			t.Errorf("num IPv6 multicast route clones = 0; want >0; summary: %+v", stats)
-		}
+		t.Logf("\thardware address %q", ifi.HardwareAddr.String())
+		testInterfaceAddrs(t, &ifi)
+		testInterfaceMulticastAddrs(t, &ifi)
 	}
 }
 
 func TestInterfaceAddrs(t *testing.T) {
-	ift, err := Interfaces()
-	if err != nil {
-		t.Fatal(err)
-	}
-	var stats routeStats
-	for _, ifi := range ift {
-		if ifi.Flags&FlagUp != 0 {
-			if ifi.Flags&FlagLoopback != 0 {
-				stats.loop++
-			} else {
-				stats.other++
-			}
-		}
-	}
 	ifat, err := InterfaceAddrs()
 	if err != nil {
-		t.Fatal(err)
-	}
-	stats.uni4, stats.uni6 = testAddrs(t, ifat)
-	// Test the existence of connected unicast routes for IPv4.
-	if supportsIPv4 && stats.loop+stats.other > 0 && stats.uni4 == 0 {
-		t.Errorf("num IPv4 unicast routes = 0; want >0; summary: %+v", stats)
-	}
-	// Test the existence of connected unicast routes for IPv6.
-	// We can assume the existence of ::1/128 when at least one
-	// looopback interface is installed.
-	if supportsIPv6 && stats.loop > 0 && stats.uni6 == 0 {
-		t.Errorf("num IPv6 unicast routes = 0; want >0; summary: %+v", stats)
+		t.Fatalf("InterfaceAddrs failed: %v", err)
 	}
+	t.Logf("table: len/cap = %v/%v", len(ifat), cap(ifat))
+	testAddrs(t, ifat)
 }
 
-func testInterfaceAddrs(t *testing.T, ifi *Interface) (naf4, naf6 int) {
+func testInterfaceAddrs(t *testing.T, ifi *Interface) {
 	ifat, err := ifi.Addrs()
 	if err != nil {
-		t.Fatal(err)
+		t.Fatalf("Interface.Addrs failed: %v", err)
 	}
-	return testAddrs(t, ifat)
+	testAddrs(t, ifat)
 }
 
-func testInterfaceMulticastAddrs(t *testing.T, ifi *Interface) (nmaf4, nmaf6 int) {
+func testInterfaceMulticastAddrs(t *testing.T, ifi *Interface) {
 	ifmat, err := ifi.MulticastAddrs()
 	if err != nil {
-		t.Fatal(err)
+		t.Fatalf("Interface.MulticastAddrs failed: %v", err)
 	}
-	return testMulticastAddrs(t, ifmat)
+	testMulticastAddrs(t, ifmat)
 }
 
-func testAddrs(t *testing.T, ifat []Addr) (naf4, naf6 int) {
+func testAddrs(t *testing.T, ifat []Addr) {
 	for _, ifa := range ifat {
 		switch ifa := ifa.(type) {
-		case *IPNet:
-			if ifa == nil || ifa.IP == nil || ifa.IP.IsUnspecified() || ifa.IP.IsMulticast() || ifa.Mask == nil {
-				t.Errorf("unexpected value: %#v", ifa)
-				continue
+		case *IPAddr:
+			if ifa == nil || ifa.IP == nil {
+				t.Errorf("\tunexpected value: %v, %v", ifa, ifa.IP)
+			} else {
+				t.Logf("\tinterface address %q", ifa.String())
 			}
-			prefixLen, maxPrefixLen := ifa.Mask.Size()
-			if ifa.IP.To4() != nil {
-				if 0 >= prefixLen || prefixLen > 8*IPv4len || maxPrefixLen != 8*IPv4len {
-					t.Errorf("unexpected prefix length: %v/%v", prefixLen, maxPrefixLen)
-					continue
-				}
-				naf4++
-			} else if ifa.IP.To16() != nil {
-				if 0 >= prefixLen || prefixLen > 8*IPv6len || maxPrefixLen != 8*IPv6len {
-					t.Errorf("unexpected prefix length: %v/%v", prefixLen, maxPrefixLen)
-					continue
+		case *IPNet:
+			if ifa == nil || ifa.IP == nil || ifa.Mask == nil {
+				t.Errorf("\tunexpected value: %v, %v, %v", ifa, ifa.IP, ifa.Mask)
+			} else {
+				_, prefixLen := ifa.Mask.Size()
+				if ifa.IP.To4() != nil && prefixLen != 8*IPv4len || ifa.IP.To16() != nil && ifa.IP.To4() == nil && prefixLen != 8*IPv6len {
+					t.Errorf("\tunexpected value: %v, %v, %v, %v", ifa, ifa.IP, ifa.Mask, prefixLen)
+				} else {
+					t.Logf("\tinterface address %q", ifa.String())
 				}
-				naf6++
 			}
-			t.Logf("interface address %q", ifa.String())
 		default:
-			t.Errorf("unexpected type: %T", ifa)
+			t.Errorf("\tunexpected type: %T", ifa)
 		}
 	}
-	return
 }
 
-func testMulticastAddrs(t *testing.T, ifmat []Addr) (nmaf4, nmaf6 int) {
+func testMulticastAddrs(t *testing.T, ifmat []Addr) {
 	for _, ifma := range ifmat {
 		switch ifma := ifma.(type) {
 		case *IPAddr:
-			if ifma == nil || ifma.IP == nil || ifma.IP.IsUnspecified() || !ifma.IP.IsMulticast() {
-				t.Errorf("unexpected value: %#v", ifma)
-				continue
-			}
-			if ifma.IP.To4() != nil {
-				nmaf4++
-			} else if ifma.IP.To16() != nil {
-				nmaf6++
+			if ifma == nil {
+				t.Errorf("\tunexpected value: %v", ifma)
+			} else {
+				t.Logf("\tjoined group address %q", ifma.String())
 			}
-			t.Logf("joined group address %q", ifma.String())
 		default:
-			t.Errorf("unexpected type: %T", ifma)
+			t.Errorf("\tunexpected type: %T", ifma)
 		}
 	}
-	return
 }
 
 func BenchmarkInterfaces(b *testing.B) {
-	testHookUninstaller.Do(uninstallTestHooks)
-
 	for i := 0; i < b.N; i++ {
 		if _, err := Interfaces(); err != nil {
-			b.Fatal(err)
+			b.Fatalf("Interfaces failed: %v", err)
 		}
 	}
 }
 
 func BenchmarkInterfaceByIndex(b *testing.B) {
-	testHookUninstaller.Do(uninstallTestHooks)
-
 	ifi := loopbackInterface()
 	if ifi == nil {
 		b.Skip("loopback interface not found")
 	}
 	for i := 0; i < b.N; i++ {
 		if _, err := InterfaceByIndex(ifi.Index); err != nil {
-			b.Fatal(err)
+			b.Fatalf("InterfaceByIndex failed: %v", err)
 		}
 	}
 }
 
 func BenchmarkInterfaceByName(b *testing.B) {
-	testHookUninstaller.Do(uninstallTestHooks)
-
 	ifi := loopbackInterface()
 	if ifi == nil {
 		b.Skip("loopback interface not found")
 	}
 	for i := 0; i < b.N; i++ {
 		if _, err := InterfaceByName(ifi.Name); err != nil {
-			b.Fatal(err)
+			b.Fatalf("InterfaceByName failed: %v", err)
 		}
 	}
 }
 
 func BenchmarkInterfaceAddrs(b *testing.B) {
-	testHookUninstaller.Do(uninstallTestHooks)
-
 	for i := 0; i < b.N; i++ {
 		if _, err := InterfaceAddrs(); err != nil {
-			b.Fatal(err)
+			b.Fatalf("InterfaceAddrs failed: %v", err)
 		}
 	}
 }
 
 func BenchmarkInterfacesAndAddrs(b *testing.B) {
-	testHookUninstaller.Do(uninstallTestHooks)
-
 	ifi := loopbackInterface()
 	if ifi == nil {
 		b.Skip("loopback interface not found")
 	}
 	for i := 0; i < b.N; i++ {
 		if _, err := ifi.Addrs(); err != nil {
-			b.Fatal(err)
+			b.Fatalf("Interface.Addrs failed: %v", err)
 		}
 	}
 }
 
 func BenchmarkInterfacesAndMulticastAddrs(b *testing.B) {
-	testHookUninstaller.Do(uninstallTestHooks)
-
 	ifi := loopbackInterface()
 	if ifi == nil {
 		b.Skip("loopback interface not found")
 	}
 	for i := 0; i < b.N; i++ {
 		if _, err := ifi.MulticastAddrs(); err != nil {
-			b.Fatal(err)
+			b.Fatalf("Interface.MulticastAddrs failed: %v", err)
 		}
 	}
 }
diff --git a/src/net/interface_unix_test.go b/src/net/interface_unix_test.go
index 93b3b79..01f609f 100644
--- a/src/net/interface_unix_test.go
+++ b/src/net/interface_unix_test.go
@@ -42,50 +42,50 @@ func (ti *testInterface) teardown() error {
 
 func TestPointToPointInterface(t *testing.T) {
 	if testing.Short() {
-		t.Skip("avoid external network")
+		t.Skip("skipping test in short mode")
 	}
-	if runtime.GOOS == "darwin" {
-		t.Skipf("not supported on %s", runtime.GOOS)
+	switch {
+	case runtime.GOOS == "darwin":
+		t.Skipf("skipping read test on %q", runtime.GOOS)
 	}
 	if os.Getuid() != 0 {
-		t.Skip("must be root")
+		t.Skip("skipping test; must be root")
 	}
 
 	local, remote := "169.254.0.1", "169.254.0.254"
 	ip := ParseIP(remote)
 	for i := 0; i < 3; i++ {
-		ti := &testInterface{local: local, remote: remote}
-		if err := ti.setPointToPoint(5963 + i); err != nil {
+		ti := &testInterface{}
+		if err := ti.setPointToPoint(5963+i, local, remote); err != nil {
 			t.Skipf("test requries external command: %v", err)
 		}
 		if err := ti.setup(); err != nil {
-			t.Fatal(err)
+			t.Fatalf("testInterface.setup failed: %v", err)
 		} else {
 			time.Sleep(3 * time.Millisecond)
 		}
 		ift, err := Interfaces()
 		if err != nil {
 			ti.teardown()
-			t.Fatal(err)
+			t.Fatalf("Interfaces failed: %v", err)
 		}
 		for _, ifi := range ift {
-			if ti.name != ifi.Name {
-				continue
-			}
-			ifat, err := ifi.Addrs()
-			if err != nil {
-				ti.teardown()
-				t.Fatal(err)
-			}
-			for _, ifa := range ifat {
-				if ip.Equal(ifa.(*IPNet).IP) {
+			if ti.name == ifi.Name {
+				ifat, err := ifi.Addrs()
+				if err != nil {
 					ti.teardown()
-					t.Fatalf("got %v", ifa)
+					t.Fatalf("Interface.Addrs failed: %v", err)
+				}
+				for _, ifa := range ifat {
+					if ip.Equal(ifa.(*IPNet).IP) {
+						ti.teardown()
+						t.Fatalf("got %v; want %v", ip, local)
+					}
 				}
 			}
 		}
 		if err := ti.teardown(); err != nil {
-			t.Fatal(err)
+			t.Fatalf("testInterface.teardown failed: %v", err)
 		} else {
 			time.Sleep(3 * time.Millisecond)
 		}
@@ -94,32 +94,30 @@ func TestPointToPointInterface(t *testing.T) {
 
 func TestInterfaceArrivalAndDeparture(t *testing.T) {
 	if testing.Short() {
-		t.Skip("avoid external network")
+		t.Skip("skipping test in short mode")
 	}
 	if os.Getuid() != 0 {
-		t.Skip("must be root")
+		t.Skip("skipping test; must be root")
 	}
 
-	local, remote := "169.254.0.1", "169.254.0.254"
-	ip := ParseIP(remote)
 	for i := 0; i < 3; i++ {
 		ift1, err := Interfaces()
 		if err != nil {
-			t.Fatal(err)
+			t.Fatalf("Interfaces failed: %v", err)
 		}
-		ti := &testInterface{local: local, remote: remote}
+		ti := &testInterface{}
 		if err := ti.setBroadcast(5682 + i); err != nil {
 			t.Skipf("test requires external command: %v", err)
 		}
 		if err := ti.setup(); err != nil {
-			t.Fatal(err)
+			t.Fatalf("testInterface.setup failed: %v", err)
 		} else {
 			time.Sleep(3 * time.Millisecond)
 		}
 		ift2, err := Interfaces()
 		if err != nil {
 			ti.teardown()
-			t.Fatal(err)
+			t.Fatalf("Interfaces failed: %v", err)
 		}
 		if len(ift2) <= len(ift1) {
 			for _, ifi := range ift1 {
@@ -131,30 +129,14 @@ func TestInterfaceArrivalAndDeparture(t *testing.T) {
 			ti.teardown()
 			t.Fatalf("got %v; want gt %v", len(ift2), len(ift1))
 		}
-		for _, ifi := range ift2 {
-			if ti.name != ifi.Name {
-				continue
-			}
-			ifat, err := ifi.Addrs()
-			if err != nil {
-				ti.teardown()
-				t.Fatal(err)
-			}
-			for _, ifa := range ifat {
-				if ip.Equal(ifa.(*IPNet).IP) {
-					ti.teardown()
-					t.Fatalf("got %v", ifa)
-				}
-			}
-		}
 		if err := ti.teardown(); err != nil {
-			t.Fatal(err)
+			t.Fatalf("testInterface.teardown failed: %v", err)
 		} else {
 			time.Sleep(3 * time.Millisecond)
 		}
 		ift3, err := Interfaces()
 		if err != nil {
-			t.Fatal(err)
+			t.Fatalf("Interfaces failed: %v", err)
 		}
 		if len(ift3) >= len(ift2) {
 			for _, ifi := range ift2 {
diff --git a/src/net/interface_windows.go b/src/net/interface_windows.go
index e25c1ed..0759dc2 100644
--- a/src/net/interface_windows.go
+++ b/src/net/interface_windows.go
@@ -5,139 +5,123 @@
 package net
 
 import (
-	"internal/syscall/windows"
 	"os"
 	"syscall"
 	"unsafe"
 )
 
-func getAdapters() (*windows.IpAdapterAddresses, error) {
-	block := uint32(unsafe.Sizeof(windows.IpAdapterAddresses{}))
-
-	// pre-allocate a 15KB working buffer pointed to by the AdapterAddresses
-	// parameter.
-	// https://msdn.microsoft.com/en-us/library/windows/desktop/aa365915(v=vs.85).aspx
-	size := uint32(15000)
-
-	var addrs []windows.IpAdapterAddresses
-	for {
-		addrs = make([]windows.IpAdapterAddresses, size/block+1)
-		err := windows.GetAdaptersAddresses(syscall.AF_UNSPEC, windows.GAA_FLAG_INCLUDE_PREFIX, 0, &addrs[0], &size)
-		if err == nil {
-			break
-		}
-		if err.(syscall.Errno) != syscall.ERROR_BUFFER_OVERFLOW {
-			return nil, os.NewSyscallError("getadaptersaddresses", err)
-		}
+func bytePtrToString(p *uint8) string {
+	a := (*[10000]uint8)(unsafe.Pointer(p))
+	i := 0
+	for a[i] != 0 {
+		i++
 	}
-	return &addrs[0], nil
+	return string(a[:i])
 }
 
-func getInterfaceInfos() ([]syscall.InterfaceInfo, error) {
-	s, err := sysSocket(syscall.AF_INET, syscall.SOCK_DGRAM, syscall.IPPROTO_UDP)
-	if err != nil {
-		return nil, err
+func getAdapterList() (*syscall.IpAdapterInfo, error) {
+	b := make([]byte, 1000)
+	l := uint32(len(b))
+	a := (*syscall.IpAdapterInfo)(unsafe.Pointer(&b[0]))
+	// TODO(mikio): GetAdaptersInfo returns IP_ADAPTER_INFO that
+	// contains IPv4 address list only. We should use another API
+	// for fetching IPv6 stuff from the kernel.
+	err := syscall.GetAdaptersInfo(a, &l)
+	if err == syscall.ERROR_BUFFER_OVERFLOW {
+		b = make([]byte, l)
+		a = (*syscall.IpAdapterInfo)(unsafe.Pointer(&b[0]))
+		err = syscall.GetAdaptersInfo(a, &l)
 	}
-	defer closeFunc(s)
-
-	iia := [20]syscall.InterfaceInfo{}
-	ret := uint32(0)
-	size := uint32(unsafe.Sizeof(iia))
-	err = syscall.WSAIoctl(s, syscall.SIO_GET_INTERFACE_LIST, nil, 0, (*byte)(unsafe.Pointer(&iia[0])), size, &ret, nil, 0)
 	if err != nil {
-		return nil, os.NewSyscallError("wsaioctl", err)
+		return nil, os.NewSyscallError("GetAdaptersInfo", err)
 	}
-	iilen := ret / uint32(unsafe.Sizeof(iia[0]))
-	return iia[:iilen-1], nil
+	return a, nil
 }
 
-func bytesEqualIP(a []byte, b []int8) bool {
-	for i := 0; i < len(a); i++ {
-		if a[i] != byte(b[i]) {
-			return false
-		}
+func getInterfaceList() ([]syscall.InterfaceInfo, error) {
+	s, err := sysSocket(syscall.AF_INET, syscall.SOCK_DGRAM, syscall.IPPROTO_UDP)
+	if err != nil {
+		return nil, os.NewSyscallError("Socket", err)
 	}
-	return true
-}
+	defer syscall.Closesocket(s)
 
-func findInterfaceInfo(iis []syscall.InterfaceInfo, paddr *windows.IpAdapterAddresses) *syscall.InterfaceInfo {
-	for _, ii := range iis {
-		iaddr := (*syscall.RawSockaddr)(unsafe.Pointer(&ii.Address))
-		puni := paddr.FirstUnicastAddress
-		for ; puni != nil; puni = puni.Next {
-			if iaddr.Family == puni.Address.Sockaddr.Addr.Family {
-				switch iaddr.Family {
-				case syscall.AF_INET:
-					a := (*syscall.RawSockaddrInet4)(unsafe.Pointer(&ii.Address)).Addr
-					if bytesEqualIP(a[:], puni.Address.Sockaddr.Addr.Data[2:]) {
-						return &ii
-					}
-				case syscall.AF_INET6:
-					a := (*syscall.RawSockaddrInet6)(unsafe.Pointer(&ii.Address)).Addr
-					if bytesEqualIP(a[:], puni.Address.Sockaddr.Addr.Data[2:]) {
-						return &ii
-					}
-				default:
-					continue
-				}
-			}
-		}
+	ii := [20]syscall.InterfaceInfo{}
+	ret := uint32(0)
+	size := uint32(unsafe.Sizeof(ii))
+	err = syscall.WSAIoctl(s, syscall.SIO_GET_INTERFACE_LIST, nil, 0, (*byte)(unsafe.Pointer(&ii[0])), size, &ret, nil, 0)
+	if err != nil {
+		return nil, os.NewSyscallError("WSAIoctl", err)
 	}
-	return nil
+	c := ret / uint32(unsafe.Sizeof(ii[0]))
+	return ii[:c-1], nil
 }
 
 // If the ifindex is zero, interfaceTable returns mappings of all
 // network interfaces.  Otherwise it returns a mapping of a specific
 // interface.
 func interfaceTable(ifindex int) ([]Interface, error) {
-	paddr, err := getAdapters()
+	ai, err := getAdapterList()
 	if err != nil {
 		return nil, err
 	}
 
-	iis, err := getInterfaceInfos()
+	ii, err := getInterfaceList()
 	if err != nil {
 		return nil, err
 	}
 
 	var ift []Interface
-	for ; paddr != nil; paddr = paddr.Next {
-		index := paddr.IfIndex
-		if paddr.Ipv6IfIndex != 0 {
-			index = paddr.Ipv6IfIndex
-		}
+	for ; ai != nil; ai = ai.Next {
+		index := ai.Index
 		if ifindex == 0 || ifindex == int(index) {
-			ii := findInterfaceInfo(iis, paddr)
-			if ii == nil {
-				continue
-			}
 			var flags Flags
-			if paddr.Flags&windows.IfOperStatusUp != 0 {
-				flags |= FlagUp
-			}
-			if paddr.IfType&windows.IF_TYPE_SOFTWARE_LOOPBACK != 0 {
-				flags |= FlagLoopback
-			}
-			if ii.Flags&syscall.IFF_BROADCAST != 0 {
-				flags |= FlagBroadcast
-			}
-			if ii.Flags&syscall.IFF_POINTTOPOINT != 0 {
-				flags |= FlagPointToPoint
+
+			row := syscall.MibIfRow{Index: index}
+			e := syscall.GetIfEntry(&row)
+			if e != nil {
+				return nil, os.NewSyscallError("GetIfEntry", e)
 			}
-			if ii.Flags&syscall.IFF_MULTICAST != 0 {
-				flags |= FlagMulticast
+
+			for _, ii := range ii {
+				ip := (*syscall.RawSockaddrInet4)(unsafe.Pointer(&ii.Address)).Addr
+				ipv4 := IPv4(ip[0], ip[1], ip[2], ip[3])
+				ipl := &ai.IpAddressList
+				for ipl != nil {
+					ips := bytePtrToString(&ipl.IpAddress.String[0])
+					if ipv4.Equal(parseIPv4(ips)) {
+						break
+					}
+					ipl = ipl.Next
+				}
+				if ipl == nil {
+					continue
+				}
+				if ii.Flags&syscall.IFF_UP != 0 {
+					flags |= FlagUp
+				}
+				if ii.Flags&syscall.IFF_LOOPBACK != 0 {
+					flags |= FlagLoopback
+				}
+				if ii.Flags&syscall.IFF_BROADCAST != 0 {
+					flags |= FlagBroadcast
+				}
+				if ii.Flags&syscall.IFF_POINTTOPOINT != 0 {
+					flags |= FlagPointToPoint
+				}
+				if ii.Flags&syscall.IFF_MULTICAST != 0 {
+					flags |= FlagMulticast
+				}
 			}
+
+			name := bytePtrToString(&ai.AdapterName[0])
+
 			ifi := Interface{
 				Index:        int(index),
-				MTU:          int(paddr.Mtu),
-				Name:         syscall.UTF16ToString((*(*[10000]uint16)(unsafe.Pointer(paddr.FriendlyName)))[:]),
-				HardwareAddr: HardwareAddr(paddr.PhysicalAddress[:]),
-				Flags:        flags,
-			}
+				MTU:          int(row.Mtu),
+				Name:         name,
+				HardwareAddr: HardwareAddr(row.PhysAddr[:row.PhysAddrLen]),
+				Flags:        flags}
 			ift = append(ift, ifi)
-			if ifindex == int(ifi.Index) {
-				break
-			}
 		}
 	}
 	return ift, nil
@@ -147,86 +131,28 @@ func interfaceTable(ifindex int) ([]Interface, error) {
 // network interfaces.  Otherwise it returns addresses for a specific
 // interface.
 func interfaceAddrTable(ifi *Interface) ([]Addr, error) {
-	paddr, err := getAdapters()
+	ai, err := getAdapterList()
 	if err != nil {
 		return nil, err
 	}
 
 	var ifat []Addr
-	for ; paddr != nil; paddr = paddr.Next {
-		index := paddr.IfIndex
-		if paddr.Ipv6IfIndex != 0 {
-			index = paddr.Ipv6IfIndex
-		}
+	for ; ai != nil; ai = ai.Next {
+		index := ai.Index
 		if ifi == nil || ifi.Index == int(index) {
-			puni := paddr.FirstUnicastAddress
-			for ; puni != nil; puni = puni.Next {
-				if sa, err := puni.Address.Sockaddr.Sockaddr(); err == nil {
-					switch sav := sa.(type) {
-					case *syscall.SockaddrInet4:
-						ifa := &IPNet{IP: make(IP, IPv4len), Mask: CIDRMask(int(puni.Address.SockaddrLength), 8*IPv4len)}
-						copy(ifa.IP, sav.Addr[:])
-						ifat = append(ifat, ifa)
-					case *syscall.SockaddrInet6:
-						ifa := &IPNet{IP: make(IP, IPv6len), Mask: CIDRMask(int(puni.Address.SockaddrLength), 8*IPv6len)}
-						copy(ifa.IP, sav.Addr[:])
-						ifat = append(ifat, ifa)
-					}
-				}
-			}
-			pany := paddr.FirstAnycastAddress
-			for ; pany != nil; pany = pany.Next {
-				if sa, err := pany.Address.Sockaddr.Sockaddr(); err == nil {
-					switch sav := sa.(type) {
-					case *syscall.SockaddrInet4:
-						ifa := &IPNet{IP: make(IP, IPv4len), Mask: CIDRMask(int(pany.Address.SockaddrLength), 8*IPv4len)}
-						copy(ifa.IP, sav.Addr[:])
-						ifat = append(ifat, ifa)
-					case *syscall.SockaddrInet6:
-						ifa := &IPNet{IP: make(IP, IPv6len), Mask: CIDRMask(int(pany.Address.SockaddrLength), 8*IPv6len)}
-						copy(ifa.IP, sav.Addr[:])
-						ifat = append(ifat, ifa)
-					}
-				}
+			ipl := &ai.IpAddressList
+			for ; ipl != nil; ipl = ipl.Next {
+				ifa := IPAddr{IP: parseIPv4(bytePtrToString(&ipl.IpAddress.String[0]))}
+				ifat = append(ifat, ifa.toAddr())
 			}
 		}
 	}
-
 	return ifat, nil
 }
 
 // interfaceMulticastAddrTable returns addresses for a specific
 // interface.
 func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) {
-	paddr, err := getAdapters()
-	if err != nil {
-		return nil, err
-	}
-
-	var ifat []Addr
-	for ; paddr != nil; paddr = paddr.Next {
-		index := paddr.IfIndex
-		if paddr.Ipv6IfIndex != 0 {
-			index = paddr.Ipv6IfIndex
-		}
-		if ifi == nil || ifi.Index == int(index) {
-			pmul := paddr.FirstMulticastAddress
-			for ; pmul != nil; pmul = pmul.Next {
-				if sa, err := pmul.Address.Sockaddr.Sockaddr(); err == nil {
-					switch sav := sa.(type) {
-					case *syscall.SockaddrInet4:
-						ifa := &IPAddr{IP: make(IP, IPv4len)}
-						copy(ifa.IP, sav.Addr[:])
-						ifat = append(ifat, ifa)
-					case *syscall.SockaddrInet6:
-						ifa := &IPAddr{IP: make(IP, IPv6len)}
-						copy(ifa.IP, sav.Addr[:])
-						ifat = append(ifat, ifa)
-					}
-				}
-			}
-		}
-	}
-
-	return ifat, nil
+	// TODO(mikio): Implement this like other platforms.
+	return nil, nil
 }
diff --git a/src/net/ip.go b/src/net/ip.go
index cc004d6..4a93e97 100644
--- a/src/net/ip.go
+++ b/src/net/ip.go
@@ -12,6 +12,8 @@
 
 package net
 
+import "errors"
+
 // IP address lengths (bytes).
 const (
 	IPv4len = 4
@@ -106,57 +108,58 @@ var (
 	IPv6linklocalallrouters    = IP{0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x02}
 )
 
-// IsUnspecified reports whether ip is an unspecified address.
+// IsUnspecified returns true if ip is an unspecified address.
 func (ip IP) IsUnspecified() bool {
-	return ip.Equal(IPv4zero) || ip.Equal(IPv6unspecified)
+	if ip.Equal(IPv4zero) || ip.Equal(IPv6unspecified) {
+		return true
+	}
+	return false
 }
 
-// IsLoopback reports whether ip is a loopback address.
+// IsLoopback returns true if ip is a loopback address.
 func (ip IP) IsLoopback() bool {
-	if ip4 := ip.To4(); ip4 != nil {
-		return ip4[0] == 127
+	if ip4 := ip.To4(); ip4 != nil && ip4[0] == 127 {
+		return true
 	}
 	return ip.Equal(IPv6loopback)
 }
 
-// IsMulticast reports whether ip is a multicast address.
+// IsMulticast returns true if ip is a multicast address.
 func (ip IP) IsMulticast() bool {
-	if ip4 := ip.To4(); ip4 != nil {
-		return ip4[0]&0xf0 == 0xe0
+	if ip4 := ip.To4(); ip4 != nil && ip4[0]&0xf0 == 0xe0 {
+		return true
 	}
-	return len(ip) == IPv6len && ip[0] == 0xff
+	return ip[0] == 0xff
 }
 
-// IsInterfaceLocalMulticast reports whether ip is
+// IsInterfaceLinkLocalMulticast returns true if ip is
 // an interface-local multicast address.
 func (ip IP) IsInterfaceLocalMulticast() bool {
 	return len(ip) == IPv6len && ip[0] == 0xff && ip[1]&0x0f == 0x01
 }
 
-// IsLinkLocalMulticast reports whether ip is a link-local
+// IsLinkLocalMulticast returns true if ip is a link-local
 // multicast address.
 func (ip IP) IsLinkLocalMulticast() bool {
-	if ip4 := ip.To4(); ip4 != nil {
-		return ip4[0] == 224 && ip4[1] == 0 && ip4[2] == 0
+	if ip4 := ip.To4(); ip4 != nil && ip4[0] == 224 && ip4[1] == 0 && ip4[2] == 0 {
+		return true
 	}
-	return len(ip) == IPv6len && ip[0] == 0xff && ip[1]&0x0f == 0x02
+	return ip[0] == 0xff && ip[1]&0x0f == 0x02
 }
 
-// IsLinkLocalUnicast reports whether ip is a link-local
+// IsLinkLocalUnicast returns true if ip is a link-local
 // unicast address.
 func (ip IP) IsLinkLocalUnicast() bool {
-	if ip4 := ip.To4(); ip4 != nil {
-		return ip4[0] == 169 && ip4[1] == 254
+	if ip4 := ip.To4(); ip4 != nil && ip4[0] == 169 && ip4[1] == 254 {
+		return true
 	}
-	return len(ip) == IPv6len && ip[0] == 0xfe && ip[1]&0xc0 == 0x80
+	return ip[0] == 0xfe && ip[1]&0xc0 == 0x80
 }
 
-// IsGlobalUnicast reports whether ip is a global unicast
+// IsGlobalUnicast returns true if ip is a global unicast
 // address.
 func (ip IP) IsGlobalUnicast() bool {
-	return (len(ip) == IPv4len || len(ip) == IPv6len) &&
-		!ip.Equal(IPv4bcast) &&
-		!ip.IsUnspecified() &&
+	return !ip.IsUnspecified() &&
 		!ip.IsLoopback() &&
 		!ip.IsMulticast() &&
 		!ip.IsLinkLocalUnicast()
@@ -264,10 +267,10 @@ func (ip IP) String() string {
 
 	// If IPv4, use dotted notation.
 	if p4 := p.To4(); len(p4) == IPv4len {
-		return uitoa(uint(p4[0])) + "." +
-			uitoa(uint(p4[1])) + "." +
-			uitoa(uint(p4[2])) + "." +
-			uitoa(uint(p4[3]))
+		return itod(uint(p4[0])) + "." +
+			itod(uint(p4[1])) + "." +
+			itod(uint(p4[2])) + "." +
+			itod(uint(p4[3]))
 	}
 	if len(p) != IPv6len {
 		return "?"
@@ -328,7 +331,7 @@ func (ip IP) MarshalText() ([]byte, error) {
 		return []byte(""), nil
 	}
 	if len(ip) != IPv4len && len(ip) != IPv6len {
-		return nil, &AddrError{Err: "invalid IP address", Addr: ip.String()}
+		return nil, errors.New("invalid IP address")
 	}
 	return []byte(ip.String()), nil
 }
@@ -343,13 +346,13 @@ func (ip *IP) UnmarshalText(text []byte) error {
 	s := string(text)
 	x := ParseIP(s)
 	if x == nil {
-		return &ParseError{Type: "IP address", Text: s}
+		return &ParseError{"IP address", s}
 	}
 	*ip = x
 	return nil
 }
 
-// Equal reports whether ip and x are the same IP address.
+// Equal returns true if ip and x are the same IP address.
 // An IPv4 address and that same address in IPv6 form are
 // considered to be equal.
 func (ip IP) Equal(x IP) bool {
@@ -488,7 +491,7 @@ func (n *IPNet) String() string {
 	if l == -1 {
 		return nn.String() + "/" + m.String()
 	}
-	return nn.String() + "/" + uitoa(uint(l))
+	return nn.String() + "/" + itod(uint(l))
 }
 
 // Parse IPv4 address (d.d.d.d).
@@ -630,6 +633,16 @@ func parseIPv6(s string, zoneAllowed bool) (ip IP, zone string) {
 	return ip, zone
 }
 
+// A ParseError represents a malformed text string and the type of string that was expected.
+type ParseError struct {
+	Type string
+	Text string
+}
+
+func (e *ParseError) Error() string {
+	return "invalid " + e.Type + ": " + e.Text
+}
+
 // ParseIP parses s as an IP address, returning the result.
 // The string s can be in dotted decimal ("74.125.19.99")
 // or IPv6 ("2001:4860:0:2001::68") form.
@@ -658,7 +671,7 @@ func ParseIP(s string) IP {
 func ParseCIDR(s string) (IP, *IPNet, error) {
 	i := byteIndex(s, '/')
 	if i < 0 {
-		return nil, nil, &ParseError{Type: "CIDR address", Text: s}
+		return nil, nil, &ParseError{"CIDR address", s}
 	}
 	addr, mask := s[:i], s[i+1:]
 	iplen := IPv4len
@@ -669,7 +682,7 @@ func ParseCIDR(s string) (IP, *IPNet, error) {
 	}
 	n, i, ok := dtoi(mask, 0)
 	if ip == nil || !ok || i != len(mask) || n < 0 || n > 8*iplen {
-		return nil, nil, &ParseError{Type: "CIDR address", Text: s}
+		return nil, nil, &ParseError{"CIDR address", s}
 	}
 	m := CIDRMask(n, 8*iplen)
 	return ip, &IPNet{IP: ip.Mask(m), Mask: m}, nil
diff --git a/src/net/ip_test.go b/src/net/ip_test.go
index 3d95a73..485ff51 100644
--- a/src/net/ip_test.go
+++ b/src/net/ip_test.go
@@ -16,20 +16,12 @@ var parseIPTests = []struct {
 }{
 	{"127.0.1.2", IPv4(127, 0, 1, 2)},
 	{"127.0.0.1", IPv4(127, 0, 0, 1)},
-	{"127.001.002.003", IPv4(127, 1, 2, 3)},
-	{"::ffff:127.1.2.3", IPv4(127, 1, 2, 3)},
-	{"::ffff:127.001.002.003", IPv4(127, 1, 2, 3)},
-	{"::ffff:7f01:0203", IPv4(127, 1, 2, 3)},
-	{"0:0:0:0:0000:ffff:127.1.2.3", IPv4(127, 1, 2, 3)},
-	{"0:0:0:0:000000:ffff:127.1.2.3", IPv4(127, 1, 2, 3)},
-	{"0:0:0:0::ffff:127.1.2.3", IPv4(127, 1, 2, 3)},
-
-	{"2001:4860:0:2001::68", IP{0x20, 0x01, 0x48, 0x60, 0, 0, 0x20, 0x01, 0, 0, 0, 0, 0, 0, 0x00, 0x68}},
-	{"2001:4860:0000:2001:0000:0000:0000:0068", IP{0x20, 0x01, 0x48, 0x60, 0, 0, 0x20, 0x01, 0, 0, 0, 0, 0, 0, 0x00, 0x68}},
-
 	{"127.0.0.256", nil},
 	{"abc", nil},
 	{"123:", nil},
+	{"::ffff:127.0.0.1", IPv4(127, 0, 0, 1)},
+	{"2001:4860:0:2001::68", IP{0x20, 0x01, 0x48, 0x60, 0, 0, 0x20, 0x01, 0, 0, 0, 0, 0, 0, 0x00, 0x68}},
+	{"::ffff:4a7d:1363", IPv4(74, 125, 19, 99)},
 	{"fe80::1%lo0", nil},
 	{"fe80::1%911", nil},
 	{"", nil},
@@ -52,52 +44,7 @@ func TestParseIP(t *testing.T) {
 	}
 }
 
-func TestLookupWithIP(t *testing.T) {
-	_, err := LookupIP("")
-	if err == nil {
-		t.Errorf(`LookupIP("") succeeded, should fail`)
-	}
-	_, err = LookupHost("")
-	if err == nil {
-		t.Errorf(`LookupIP("") succeeded, should fail`)
-	}
-
-	// Test that LookupHost and LookupIP, which normally
-	// expect host names, work with IP addresses.
-	for _, tt := range parseIPTests {
-		if tt.out != nil {
-			addrs, err := LookupHost(tt.in)
-			if len(addrs) != 1 || addrs[0] != tt.in || err != nil {
-				t.Errorf("LookupHost(%q) = %v, %v, want %v, nil", tt.in, addrs, err, []string{tt.in})
-			}
-		} else if !testing.Short() {
-			// We can't control what the host resolver does; if it can resolve, say,
-			// 127.0.0.256 or fe80::1%911 or a host named 'abc', who are we to judge?
-			// Warn about these discrepancies but don't fail the test.
-			addrs, err := LookupHost(tt.in)
-			if err == nil {
-				t.Logf("warning: LookupHost(%q) = %v, want error", tt.in, addrs)
-			}
-		}
-
-		if tt.out != nil {
-			ips, err := LookupIP(tt.in)
-			if len(ips) != 1 || !reflect.DeepEqual(ips[0], tt.out) || err != nil {
-				t.Errorf("LookupIP(%q) = %v, %v, want %v, nil", tt.in, ips, err, []IP{tt.out})
-			}
-		} else if !testing.Short() {
-			ips, err := LookupIP(tt.in)
-			// We can't control what the host resolver does. See above.
-			if err == nil {
-				t.Logf("warning: LookupIP(%q) = %v, want error", tt.in, ips)
-			}
-		}
-	}
-}
-
 func BenchmarkParseIP(b *testing.B) {
-	testHookUninstaller.Do(uninstallTestHooks)
-
 	for i := 0; i < b.N; i++ {
 		for _, tt := range parseIPTests {
 			ParseIP(tt.in)
@@ -153,8 +100,6 @@ func TestIPString(t *testing.T) {
 }
 
 func BenchmarkIPString(b *testing.B) {
-	testHookUninstaller.Do(uninstallTestHooks)
-
 	for i := 0; i < b.N; i++ {
 		for _, tt := range ipStringTests {
 			if tt.in != nil {
@@ -205,8 +150,6 @@ func TestIPMaskString(t *testing.T) {
 }
 
 func BenchmarkIPMaskString(b *testing.B) {
-	testHookUninstaller.Do(uninstallTestHooks)
-
 	for i := 0; i < b.N; i++ {
 		for _, tt := range ipMaskStringTests {
 			tt.in.String()
@@ -237,10 +180,10 @@ var parseCIDRTests = []struct {
 	{"abcd:2345::/24", ParseIP("abcd:2345::"), &IPNet{IP: ParseIP("abcd:2300::"), Mask: IPMask(ParseIP("ffff:ff00::"))}, nil},
 	{"2001:DB8::/48", ParseIP("2001:DB8::"), &IPNet{IP: ParseIP("2001:DB8::"), Mask: IPMask(ParseIP("ffff:ffff:ffff::"))}, nil},
 	{"2001:DB8::1/48", ParseIP("2001:DB8::1"), &IPNet{IP: ParseIP("2001:DB8::"), Mask: IPMask(ParseIP("ffff:ffff:ffff::"))}, nil},
-	{"192.168.1.1/255.255.255.0", nil, nil, &ParseError{Type: "CIDR address", Text: "192.168.1.1/255.255.255.0"}},
-	{"192.168.1.1/35", nil, nil, &ParseError{Type: "CIDR address", Text: "192.168.1.1/35"}},
-	{"2001:db8::1/-1", nil, nil, &ParseError{Type: "CIDR address", Text: "2001:db8::1/-1"}},
-	{"", nil, nil, &ParseError{Type: "CIDR address", Text: ""}},
+	{"192.168.1.1/255.255.255.0", nil, nil, &ParseError{"CIDR address", "192.168.1.1/255.255.255.0"}},
+	{"192.168.1.1/35", nil, nil, &ParseError{"CIDR address", "192.168.1.1/35"}},
+	{"2001:db8::1/-1", nil, nil, &ParseError{"CIDR address", "2001:db8::1/-1"}},
+	{"", nil, nil, &ParseError{"CIDR address", ""}},
 }
 
 func TestParseCIDR(t *testing.T) {
@@ -482,44 +425,31 @@ var ipAddrScopeTests = []struct {
 	{IP.IsUnspecified, IPv4(127, 0, 0, 1), false},
 	{IP.IsUnspecified, IPv6unspecified, true},
 	{IP.IsUnspecified, IPv6interfacelocalallnodes, false},
-	{IP.IsUnspecified, nil, false},
 	{IP.IsLoopback, IPv4(127, 0, 0, 1), true},
 	{IP.IsLoopback, IPv4(127, 255, 255, 254), true},
 	{IP.IsLoopback, IPv4(128, 1, 2, 3), false},
 	{IP.IsLoopback, IPv6loopback, true},
 	{IP.IsLoopback, IPv6linklocalallrouters, false},
-	{IP.IsLoopback, nil, false},
 	{IP.IsMulticast, IPv4(224, 0, 0, 0), true},
 	{IP.IsMulticast, IPv4(239, 0, 0, 0), true},
 	{IP.IsMulticast, IPv4(240, 0, 0, 0), false},
 	{IP.IsMulticast, IPv6linklocalallnodes, true},
 	{IP.IsMulticast, IP{0xff, 0x05, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, true},
 	{IP.IsMulticast, IP{0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, false},
-	{IP.IsMulticast, nil, false},
-	{IP.IsInterfaceLocalMulticast, IPv4(224, 0, 0, 0), false},
-	{IP.IsInterfaceLocalMulticast, IPv4(0xff, 0x01, 0, 0), false},
-	{IP.IsInterfaceLocalMulticast, IPv6interfacelocalallnodes, true},
-	{IP.IsInterfaceLocalMulticast, nil, false},
 	{IP.IsLinkLocalMulticast, IPv4(224, 0, 0, 0), true},
 	{IP.IsLinkLocalMulticast, IPv4(239, 0, 0, 0), false},
-	{IP.IsLinkLocalMulticast, IPv4(0xff, 0x02, 0, 0), false},
 	{IP.IsLinkLocalMulticast, IPv6linklocalallrouters, true},
 	{IP.IsLinkLocalMulticast, IP{0xff, 0x05, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, false},
-	{IP.IsLinkLocalMulticast, nil, false},
 	{IP.IsLinkLocalUnicast, IPv4(169, 254, 0, 0), true},
 	{IP.IsLinkLocalUnicast, IPv4(169, 255, 0, 0), false},
-	{IP.IsLinkLocalUnicast, IPv4(0xfe, 0x80, 0, 0), false},
 	{IP.IsLinkLocalUnicast, IP{0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, true},
 	{IP.IsLinkLocalUnicast, IP{0xfe, 0xc0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, false},
-	{IP.IsLinkLocalUnicast, nil, false},
 	{IP.IsGlobalUnicast, IPv4(240, 0, 0, 0), true},
 	{IP.IsGlobalUnicast, IPv4(232, 0, 0, 0), false},
 	{IP.IsGlobalUnicast, IPv4(169, 254, 0, 0), false},
-	{IP.IsGlobalUnicast, IPv4bcast, false},
 	{IP.IsGlobalUnicast, IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0x1, 0x23, 0, 0x12, 0, 0x1}, true},
 	{IP.IsGlobalUnicast, IP{0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, false},
 	{IP.IsGlobalUnicast, IP{0xff, 0x05, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, false},
-	{IP.IsGlobalUnicast, nil, false},
 }
 
 func name(f interface{}) string {
@@ -531,12 +461,5 @@ func TestIPAddrScope(t *testing.T) {
 		if ok := tt.scope(tt.in); ok != tt.ok {
 			t.Errorf("%s(%q) = %v, want %v", name(tt.scope), tt.in, ok, tt.ok)
 		}
-		ip := tt.in.To4()
-		if ip == nil {
-			continue
-		}
-		if ok := tt.scope(ip); ok != tt.ok {
-			t.Errorf("%s(%q) = %v, want %v", name(tt.scope), ip, ok, tt.ok)
-		}
 	}
 }
diff --git a/src/net/ipraw_test.go b/src/net/ipraw_test.go
index 5d86a9d..92dc8dc 100644
--- a/src/net/ipraw_test.go
+++ b/src/net/ipraw_test.go
@@ -5,18 +5,17 @@
 package net
 
 import (
+	"bytes"
+	"fmt"
+	"os"
 	"reflect"
+	"runtime"
 	"testing"
+	"time"
 )
 
-// The full stack test cases for IPConn have been moved to the
-// following:
-//	golang.org/x/net/ipv4
-//	golang.org/x/net/ipv6
-//	golang.org/x/net/icmp
-
 type resolveIPAddrTest struct {
-	network       string
+	net           string
 	litAddrOrName string
 	addr          *IPAddr
 	err           error
@@ -38,41 +37,210 @@ var resolveIPAddrTests = []resolveIPAddrTest{
 	{"", "127.0.0.1", &IPAddr{IP: IPv4(127, 0, 0, 1)}, nil}, // Go 1.0 behavior
 	{"", "::1", &IPAddr{IP: ParseIP("::1")}, nil},           // Go 1.0 behavior
 
-	{"ip4:icmp", "", &IPAddr{}, nil},
-
 	{"l2tp", "127.0.0.1", nil, UnknownNetworkError("l2tp")},
 	{"l2tp:gre", "127.0.0.1", nil, UnknownNetworkError("l2tp:gre")},
 	{"tcp", "1.2.3.4:123", nil, UnknownNetworkError("tcp")},
 }
 
-func TestResolveIPAddr(t *testing.T) {
-	if !testableNetwork("ip+nopriv") {
-		t.Skip("ip+nopriv test")
+func init() {
+	if ifi := loopbackInterface(); ifi != nil {
+		index := fmt.Sprintf("%v", ifi.Index)
+		resolveIPAddrTests = append(resolveIPAddrTests, []resolveIPAddrTest{
+			{"ip6", "fe80::1%" + ifi.Name, &IPAddr{IP: ParseIP("fe80::1"), Zone: zoneToString(ifi.Index)}, nil},
+			{"ip6", "fe80::1%" + index, &IPAddr{IP: ParseIP("fe80::1"), Zone: index}, nil},
+		}...)
+	}
+	if ips, err := LookupIP("localhost"); err == nil && len(ips) > 1 && supportsIPv4 && supportsIPv6 {
+		resolveIPAddrTests = append(resolveIPAddrTests, []resolveIPAddrTest{
+			{"ip", "localhost", &IPAddr{IP: IPv4(127, 0, 0, 1)}, nil},
+			{"ip4", "localhost", &IPAddr{IP: IPv4(127, 0, 0, 1)}, nil},
+			{"ip6", "localhost", &IPAddr{IP: IPv6loopback}, nil},
+		}...)
+	}
+}
+
+func skipRawSocketTest(t *testing.T) (skip bool, skipmsg string) {
+	skip, skipmsg, err := skipRawSocketTests()
+	if err != nil {
+		t.Fatal(err)
 	}
+	return skip, skipmsg
+}
 
-	origTestHookLookupIP := testHookLookupIP
-	defer func() { testHookLookupIP = origTestHookLookupIP }()
-	testHookLookupIP = lookupLocalhost
+func TestResolveIPAddr(t *testing.T) {
+	switch runtime.GOOS {
+	case "nacl":
+		t.Skipf("skipping test on %q", runtime.GOOS)
+	}
 
-	for i, tt := range resolveIPAddrTests {
-		addr, err := ResolveIPAddr(tt.network, tt.litAddrOrName)
+	for _, tt := range resolveIPAddrTests {
+		addr, err := ResolveIPAddr(tt.net, tt.litAddrOrName)
 		if err != tt.err {
-			t.Errorf("#%d: %v", i, err)
+			t.Fatalf("ResolveIPAddr(%v, %v) failed: %v", tt.net, tt.litAddrOrName, err)
 		} else if !reflect.DeepEqual(addr, tt.addr) {
-			t.Errorf("#%d: got %#v; want %#v", i, addr, tt.addr)
+			t.Fatalf("got %#v; expected %#v", addr, tt.addr)
 		}
+	}
+}
+
+var icmpEchoTests = []struct {
+	net   string
+	laddr string
+	raddr string
+}{
+	{"ip4:icmp", "0.0.0.0", "127.0.0.1"},
+	{"ip6:ipv6-icmp", "::", "::1"},
+}
+
+func TestConnICMPEcho(t *testing.T) {
+	if skip, skipmsg := skipRawSocketTest(t); skip {
+		t.Skip(skipmsg)
+	}
+
+	for i, tt := range icmpEchoTests {
+		net, _, err := parseNetwork(tt.net)
 		if err != nil {
+			t.Fatalf("parseNetwork failed: %v", err)
+		}
+		if net == "ip6" && !supportsIPv6 {
 			continue
 		}
-		rtaddr, err := ResolveIPAddr(addr.Network(), addr.String())
+
+		c, err := Dial(tt.net, tt.raddr)
+		if err != nil {
+			t.Fatalf("Dial failed: %v", err)
+		}
+		c.SetDeadline(time.Now().Add(100 * time.Millisecond))
+		defer c.Close()
+
+		typ := icmpv4EchoRequest
+		if net == "ip6" {
+			typ = icmpv6EchoRequest
+		}
+		xid, xseq := os.Getpid()&0xffff, i+1
+		wb, err := (&icmpMessage{
+			Type: typ, Code: 0,
+			Body: &icmpEcho{
+				ID: xid, Seq: xseq,
+				Data: bytes.Repeat([]byte("Go Go Gadget Ping!!!"), 3),
+			},
+		}).Marshal()
 		if err != nil {
-			t.Errorf("#%d: %v", i, err)
-		} else if !reflect.DeepEqual(rtaddr, addr) {
-			t.Errorf("#%d: got %#v; want %#v", i, rtaddr, addr)
+			t.Fatalf("icmpMessage.Marshal failed: %v", err)
+		}
+		if _, err := c.Write(wb); err != nil {
+			t.Fatalf("Conn.Write failed: %v", err)
+		}
+		var m *icmpMessage
+		rb := make([]byte, 20+len(wb))
+		for {
+			if _, err := c.Read(rb); err != nil {
+				t.Fatalf("Conn.Read failed: %v", err)
+			}
+			if net == "ip4" {
+				rb = ipv4Payload(rb)
+			}
+			if m, err = parseICMPMessage(rb); err != nil {
+				t.Fatalf("parseICMPMessage failed: %v", err)
+			}
+			switch m.Type {
+			case icmpv4EchoRequest, icmpv6EchoRequest:
+				continue
+			}
+			break
+		}
+		switch p := m.Body.(type) {
+		case *icmpEcho:
+			if p.ID != xid || p.Seq != xseq {
+				t.Fatalf("got id=%v, seqnum=%v; expected id=%v, seqnum=%v", p.ID, p.Seq, xid, xseq)
+			}
+		default:
+			t.Fatalf("got type=%v, code=%v; expected type=%v, code=%v", m.Type, m.Code, typ, 0)
 		}
 	}
 }
 
+func TestPacketConnICMPEcho(t *testing.T) {
+	if skip, skipmsg := skipRawSocketTest(t); skip {
+		t.Skip(skipmsg)
+	}
+
+	for i, tt := range icmpEchoTests {
+		net, _, err := parseNetwork(tt.net)
+		if err != nil {
+			t.Fatalf("parseNetwork failed: %v", err)
+		}
+		if net == "ip6" && !supportsIPv6 {
+			continue
+		}
+
+		c, err := ListenPacket(tt.net, tt.laddr)
+		if err != nil {
+			t.Fatalf("ListenPacket failed: %v", err)
+		}
+		c.SetDeadline(time.Now().Add(100 * time.Millisecond))
+		defer c.Close()
+
+		ra, err := ResolveIPAddr(tt.net, tt.raddr)
+		if err != nil {
+			t.Fatalf("ResolveIPAddr failed: %v", err)
+		}
+		typ := icmpv4EchoRequest
+		if net == "ip6" {
+			typ = icmpv6EchoRequest
+		}
+		xid, xseq := os.Getpid()&0xffff, i+1
+		wb, err := (&icmpMessage{
+			Type: typ, Code: 0,
+			Body: &icmpEcho{
+				ID: xid, Seq: xseq,
+				Data: bytes.Repeat([]byte("Go Go Gadget Ping!!!"), 3),
+			},
+		}).Marshal()
+		if err != nil {
+			t.Fatalf("icmpMessage.Marshal failed: %v", err)
+		}
+		if _, err := c.WriteTo(wb, ra); err != nil {
+			t.Fatalf("PacketConn.WriteTo failed: %v", err)
+		}
+		var m *icmpMessage
+		rb := make([]byte, 20+len(wb))
+		for {
+			if _, _, err := c.ReadFrom(rb); err != nil {
+				t.Fatalf("PacketConn.ReadFrom failed: %v", err)
+			}
+			// See BUG section.
+			//if net == "ip4" {
+			//	rb = ipv4Payload(rb)
+			//}
+			if m, err = parseICMPMessage(rb); err != nil {
+				t.Fatalf("parseICMPMessage failed: %v", err)
+			}
+			switch m.Type {
+			case icmpv4EchoRequest, icmpv6EchoRequest:
+				continue
+			}
+			break
+		}
+		switch p := m.Body.(type) {
+		case *icmpEcho:
+			if p.ID != xid || p.Seq != xseq {
+				t.Fatalf("got id=%v, seqnum=%v; expected id=%v, seqnum=%v", p.ID, p.Seq, xid, xseq)
+			}
+		default:
+			t.Fatalf("got type=%v, code=%v; expected type=%v, code=%v", m.Type, m.Code, typ, 0)
+		}
+	}
+}
+
+func ipv4Payload(b []byte) []byte {
+	if len(b) < 20 {
+		return b
+	}
+	hdrlen := int(b[0]&0x0f) << 2
+	return b[hdrlen:]
+}
+
 var ipConnLocalNameTests = []struct {
 	net   string
 	laddr *IPAddr
@@ -83,34 +251,44 @@ var ipConnLocalNameTests = []struct {
 }
 
 func TestIPConnLocalName(t *testing.T) {
-	for _, tt := range ipConnLocalNameTests {
-		if !testableNetwork(tt.net) {
-			t.Logf("skipping %s test", tt.net)
-			continue
+	switch runtime.GOOS {
+	case "nacl", "plan9", "windows":
+		t.Skipf("skipping test on %q", runtime.GOOS)
+	default:
+		if os.Getuid() != 0 {
+			t.Skip("skipping test; must be root")
 		}
+	}
+
+	for _, tt := range ipConnLocalNameTests {
 		c, err := ListenIP(tt.net, tt.laddr)
 		if err != nil {
-			t.Fatal(err)
+			t.Fatalf("ListenIP failed: %v", err)
 		}
 		defer c.Close()
 		if la := c.LocalAddr(); la == nil {
-			t.Fatal("should not fail")
+			t.Fatal("IPConn.LocalAddr failed")
 		}
 	}
 }
 
 func TestIPConnRemoteName(t *testing.T) {
-	if !testableNetwork("ip:tcp") {
-		t.Skip("ip:tcp test")
+	switch runtime.GOOS {
+	case "plan9", "windows":
+		t.Skipf("skipping test on %q", runtime.GOOS)
+	default:
+		if os.Getuid() != 0 {
+			t.Skip("skipping test; must be root")
+		}
 	}
 
 	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.Fatal(err)
+		t.Fatalf("DialIP failed: %v", err)
 	}
 	defer c.Close()
 	if !reflect.DeepEqual(raddr, c.RemoteAddr()) {
-		t.Fatalf("got %#v; want %#v", c.RemoteAddr(), raddr)
+		t.Fatalf("got %#v, expected %#v", c.RemoteAddr(), raddr)
 	}
 }
diff --git a/src/net/iprawsock.go b/src/net/iprawsock.go
index f02df7f..5cc3613 100644
--- a/src/net/iprawsock.go
+++ b/src/net/iprawsock.go
@@ -17,21 +17,13 @@ func (a *IPAddr) String() string {
 	if a == nil {
 		return "<nil>"
 	}
-	ip := ipEmptyString(a.IP)
 	if a.Zone != "" {
-		return ip + "%" + a.Zone
+		return a.IP.String() + "%" + a.Zone
 	}
-	return ip
+	return a.IP.String()
 }
 
-func (a *IPAddr) isWildcard() bool {
-	if a == nil || a.IP == nil {
-		return true
-	}
-	return a.IP.IsUnspecified()
-}
-
-func (a *IPAddr) opAddr() Addr {
+func (a *IPAddr) toAddr() Addr {
 	if a == nil {
 		return nil
 	}
@@ -54,9 +46,9 @@ func ResolveIPAddr(net, addr string) (*IPAddr, error) {
 	default:
 		return nil, UnknownNetworkError(net)
 	}
-	addrs, err := internetAddrList(afnet, addr, noDeadline)
+	a, err := resolveInternetAddr(afnet, addr, noDeadline)
 	if err != nil {
 		return nil, err
 	}
-	return addrs.first(isIPv4).(*IPAddr), nil
+	return a.toAddr().(*IPAddr), nil
 }
diff --git a/src/net/iprawsock_plan9.go b/src/net/iprawsock_plan9.go
index b027adc..e62d116 100644
--- a/src/net/iprawsock_plan9.go
+++ b/src/net/iprawsock_plan9.go
@@ -23,12 +23,12 @@ type IPConn struct {
 // Timeout() == true after a fixed time limit; see SetDeadline and
 // SetReadDeadline.
 func (c *IPConn) ReadFromIP(b []byte) (int, *IPAddr, error) {
-	return 0, nil, &OpError{Op: "read", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: syscall.EPLAN9}
+	return 0, nil, syscall.EPLAN9
 }
 
 // ReadFrom implements the PacketConn ReadFrom method.
 func (c *IPConn) ReadFrom(b []byte) (int, Addr, error) {
-	return 0, nil, &OpError{Op: "read", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: syscall.EPLAN9}
+	return 0, nil, syscall.EPLAN9
 }
 
 // ReadMsgIP reads a packet from c, copying the payload into b and the
@@ -36,7 +36,7 @@ func (c *IPConn) ReadFrom(b []byte) (int, Addr, error) {
 // bytes copied into b, the number of bytes copied into oob, the flags
 // that were set on the packet and the source address of the packet.
 func (c *IPConn) ReadMsgIP(b, oob []byte) (n, oobn, flags int, addr *IPAddr, err error) {
-	return 0, 0, 0, nil, &OpError{Op: "read", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: syscall.EPLAN9}
+	return 0, 0, 0, nil, syscall.EPLAN9
 }
 
 // WriteToIP writes an IP packet to addr via c, copying the payload
@@ -47,19 +47,19 @@ func (c *IPConn) ReadMsgIP(b, oob []byte) (n, oobn, flags int, addr *IPAddr, err
 // SetWriteDeadline.  On packet-oriented connections, write timeouts
 // are rare.
 func (c *IPConn) WriteToIP(b []byte, addr *IPAddr) (int, error) {
-	return 0, &OpError{Op: "write", Net: c.fd.dir, Source: c.fd.laddr, Addr: addr.opAddr(), Err: syscall.EPLAN9}
+	return 0, syscall.EPLAN9
 }
 
 // WriteTo implements the PacketConn WriteTo method.
 func (c *IPConn) WriteTo(b []byte, addr Addr) (int, error) {
-	return 0, &OpError{Op: "write", Net: c.fd.dir, Source: c.fd.laddr, Addr: addr, Err: syscall.EPLAN9}
+	return 0, syscall.EPLAN9
 }
 
 // WriteMsgIP writes a packet to addr via c, copying the payload from
 // b and the associated out-of-band data from oob.  It returns the
 // number of payload and out-of-band bytes written.
 func (c *IPConn) WriteMsgIP(b, oob []byte, addr *IPAddr) (n, oobn int, err error) {
-	return 0, 0, &OpError{Op: "write", Net: c.fd.dir, Source: c.fd.laddr, Addr: addr.opAddr(), Err: syscall.EPLAN9}
+	return 0, 0, syscall.EPLAN9
 }
 
 // DialIP connects to the remote address raddr on the network protocol
@@ -70,7 +70,7 @@ func DialIP(netProto string, laddr, raddr *IPAddr) (*IPConn, error) {
 }
 
 func dialIP(netProto string, laddr, raddr *IPAddr, deadline time.Time) (*IPConn, error) {
-	return nil, &OpError{Op: "dial", Net: netProto, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: syscall.EPLAN9}
+	return nil, syscall.EPLAN9
 }
 
 // ListenIP listens for incoming IP packets addressed to the local
@@ -78,5 +78,5 @@ func dialIP(netProto string, laddr, raddr *IPAddr, deadline time.Time) (*IPConn,
 // methods can be used to receive and send IP packets with per-packet
 // addressing.
 func ListenIP(netProto string, laddr *IPAddr) (*IPConn, error) {
-	return nil, &OpError{Op: "listen", Net: netProto, Source: nil, Addr: laddr.opAddr(), Err: syscall.EPLAN9}
+	return nil, syscall.EPLAN9
 }
diff --git a/src/net/iprawsock_posix.go b/src/net/iprawsock_posix.go
index 9417606..99b081b 100644
--- a/src/net/iprawsock_posix.go
+++ b/src/net/iprawsock_posix.go
@@ -43,6 +43,13 @@ func (a *IPAddr) family() int {
 	return syscall.AF_INET6
 }
 
+func (a *IPAddr) isWildcard() bool {
+	if a == nil || a.IP == nil {
+		return true
+	}
+	return a.IP.IsUnspecified()
+}
+
 func (a *IPAddr) sockaddr(family int) (syscall.Sockaddr, error) {
 	if a == nil {
 		return nil, nil
@@ -76,41 +83,24 @@ func (c *IPConn) ReadFromIP(b []byte) (int, *IPAddr, error) {
 	switch sa := sa.(type) {
 	case *syscall.SockaddrInet4:
 		addr = &IPAddr{IP: sa.Addr[0:]}
-		n = stripIPv4Header(n, b)
+		if len(b) >= IPv4len { // discard ipv4 header
+			hsize := (int(b[0]) & 0xf) * 4
+			copy(b, b[hsize:])
+			n -= hsize
+		}
 	case *syscall.SockaddrInet6:
 		addr = &IPAddr{IP: sa.Addr[0:], Zone: zoneToString(int(sa.ZoneId))}
 	}
-	if err != nil {
-		err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
-	}
 	return n, addr, err
 }
 
-func stripIPv4Header(n int, b []byte) int {
-	if len(b) < 20 {
-		return n
-	}
-	l := int(b[0]&0x0f) << 2
-	if 20 > l || l > len(b) {
-		return n
-	}
-	if b[0]>>4 != 4 {
-		return n
-	}
-	copy(b, b[l:])
-	return n - l
-}
-
 // ReadFrom implements the PacketConn ReadFrom method.
 func (c *IPConn) ReadFrom(b []byte) (int, Addr, error) {
 	if !c.ok() {
 		return 0, nil, syscall.EINVAL
 	}
 	n, addr, err := c.ReadFromIP(b)
-	if addr == nil {
-		return n, nil, err
-	}
-	return n, addr, err
+	return n, addr.toAddr(), err
 }
 
 // ReadMsgIP reads a packet from c, copying the payload into b and the
@@ -129,9 +119,6 @@ func (c *IPConn) ReadMsgIP(b, oob []byte) (n, oobn, flags int, addr *IPAddr, err
 	case *syscall.SockaddrInet6:
 		addr = &IPAddr{IP: sa.Addr[0:], Zone: zoneToString(int(sa.ZoneId))}
 	}
-	if err != nil {
-		err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
-	}
 	return
 }
 
@@ -147,20 +134,16 @@ func (c *IPConn) WriteToIP(b []byte, addr *IPAddr) (int, error) {
 		return 0, syscall.EINVAL
 	}
 	if c.fd.isConnected {
-		return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: ErrWriteToConnected}
+		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, Source: c.fd.laddr, Addr: nil, Err: errMissingAddress}
+		return 0, &OpError{Op: "write", Net: c.fd.net, Addr: nil, Err: errMissingAddress}
 	}
 	sa, err := addr.sockaddr(c.fd.family)
 	if err != nil {
-		return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err}
-	}
-	n, err := c.fd.writeTo(b, sa)
-	if err != nil {
-		err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err}
+		return 0, &OpError{"write", c.fd.net, addr, err}
 	}
-	return n, err
+	return c.fd.writeTo(b, sa)
 }
 
 // WriteTo implements the PacketConn WriteTo method.
@@ -170,7 +153,7 @@ func (c *IPConn) WriteTo(b []byte, addr Addr) (int, error) {
 	}
 	a, ok := addr.(*IPAddr)
 	if !ok {
-		return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr, Err: syscall.EINVAL}
+		return 0, &OpError{"write", c.fd.net, addr, syscall.EINVAL}
 	}
 	return c.WriteToIP(b, a)
 }
@@ -183,21 +166,16 @@ func (c *IPConn) WriteMsgIP(b, oob []byte, addr *IPAddr) (n, oobn int, err error
 		return 0, 0, syscall.EINVAL
 	}
 	if c.fd.isConnected {
-		return 0, 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: ErrWriteToConnected}
+		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, Source: c.fd.laddr, Addr: nil, Err: errMissingAddress}
+		return 0, 0, &OpError{Op: "write", Net: c.fd.net, Addr: nil, Err: errMissingAddress}
 	}
-	var sa syscall.Sockaddr
-	sa, err = addr.sockaddr(c.fd.family)
-	if err != nil {
-		return 0, 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err}
-	}
-	n, oobn, err = c.fd.writeMsg(b, oob, sa)
+	sa, err := addr.sockaddr(c.fd.family)
 	if err != nil {
-		err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err}
+		return 0, 0, &OpError{"write", c.fd.net, addr, err}
 	}
-	return
+	return c.fd.writeMsg(b, oob, sa)
 }
 
 // DialIP connects to the remote address raddr on the network protocol
@@ -210,19 +188,19 @@ func DialIP(netProto string, laddr, raddr *IPAddr) (*IPConn, error) {
 func dialIP(netProto string, laddr, raddr *IPAddr, deadline time.Time) (*IPConn, error) {
 	net, proto, err := parseNetwork(netProto)
 	if err != nil {
-		return nil, &OpError{Op: "dial", Net: netProto, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: err}
+		return nil, &OpError{Op: "dial", Net: netProto, Addr: raddr, Err: err}
 	}
 	switch net {
 	case "ip", "ip4", "ip6":
 	default:
-		return nil, &OpError{Op: "dial", Net: netProto, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: UnknownNetworkError(netProto)}
+		return nil, &OpError{Op: "dial", Net: netProto, Addr: raddr, Err: UnknownNetworkError(netProto)}
 	}
 	if raddr == nil {
-		return nil, &OpError{Op: "dial", Net: netProto, Source: laddr.opAddr(), Addr: nil, Err: errMissingAddress}
+		return nil, &OpError{Op: "dial", Net: netProto, Addr: nil, Err: errMissingAddress}
 	}
 	fd, err := internetSocket(net, laddr, raddr, deadline, syscall.SOCK_RAW, proto, "dial")
 	if err != nil {
-		return nil, &OpError{Op: "dial", Net: netProto, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: err}
+		return nil, &OpError{Op: "dial", Net: netProto, Addr: raddr, Err: err}
 	}
 	return newIPConn(fd), nil
 }
@@ -234,16 +212,16 @@ func dialIP(netProto string, laddr, raddr *IPAddr, deadline time.Time) (*IPConn,
 func ListenIP(netProto string, laddr *IPAddr) (*IPConn, error) {
 	net, proto, err := parseNetwork(netProto)
 	if err != nil {
-		return nil, &OpError{Op: "listen", Net: netProto, Source: nil, Addr: laddr.opAddr(), Err: err}
+		return nil, &OpError{Op: "dial", Net: netProto, Addr: laddr, Err: err}
 	}
 	switch net {
 	case "ip", "ip4", "ip6":
 	default:
-		return nil, &OpError{Op: "listen", Net: netProto, Source: nil, Addr: laddr.opAddr(), Err: UnknownNetworkError(netProto)}
+		return nil, &OpError{Op: "listen", Net: netProto, Addr: laddr, Err: UnknownNetworkError(netProto)}
 	}
 	fd, err := internetSocket(net, laddr, nil, noDeadline, syscall.SOCK_RAW, proto, "listen")
 	if err != nil {
-		return nil, &OpError{Op: "listen", Net: netProto, Source: nil, Addr: laddr.opAddr(), Err: err}
+		return nil, &OpError{Op: "listen", Net: netProto, Addr: laddr, Err: err}
 	}
 	return newIPConn(fd), nil
 }
diff --git a/src/net/ipsock.go b/src/net/ipsock.go
index 6e75c33..dda8578 100644
--- a/src/net/ipsock.go
+++ b/src/net/ipsock.go
@@ -26,82 +26,113 @@ var (
 	supportsIPv4map bool
 )
 
-// An addrList represents a list of network endpoint addresses.
-type addrList []Addr
-
-// isIPv4 returns true if the Addr contains an IPv4 address.
-func isIPv4(addr Addr) bool {
-	switch addr := addr.(type) {
-	case *TCPAddr:
-		return addr.IP.To4() != nil
-	case *UDPAddr:
-		return addr.IP.To4() != nil
-	case *IPAddr:
-		return addr.IP.To4() != nil
-	}
-	return false
+func init() {
+	sysInit()
+	supportsIPv4 = probeIPv4Stack()
+	supportsIPv6, supportsIPv4map = probeIPv6Stack()
 }
 
-// first returns the first address which satisfies strategy, or if
-// none do, then the first address of any kind.
-func (addrs addrList) first(strategy func(Addr) bool) Addr {
-	for _, addr := range addrs {
-		if strategy(addr) {
-			return addr
-		}
-	}
-	return addrs[0]
+// A netaddr represents a network endpoint address or a list of
+// network endpoint addresses.
+type netaddr interface {
+	// toAddr returns the address represented in Addr interface.
+	// It returns a nil interface when the address is nil.
+	toAddr() Addr
 }
 
-// partition divides an address list into two categories, using a
-// strategy function to assign a boolean label to each address.
-// The first address, and any with a matching label, are returned as
-// primaries, while addresses with the opposite label are returned
-// as fallbacks. For non-empty inputs, primaries is guaranteed to be
-// non-empty.
-func (addrs addrList) partition(strategy func(Addr) bool) (primaries, fallbacks addrList) {
-	var primaryLabel bool
-	for i, addr := range addrs {
-		label := strategy(addr)
-		if i == 0 || label == primaryLabel {
-			primaryLabel = label
-			primaries = append(primaries, addr)
-		} else {
-			fallbacks = append(fallbacks, addr)
-		}
+// An addrList represents a list of network endpoint addresses.
+type addrList []netaddr
+
+func (al addrList) toAddr() Addr {
+	switch len(al) {
+	case 0:
+		return nil
+	case 1:
+		return al[0].toAddr()
+	default:
+		// For now, we'll roughly pick first one without
+		// considering dealing with any preferences such as
+		// DNS TTL, transport path quality, network routing
+		// information.
+		return al[0].toAddr()
 	}
-	return
 }
 
 var errNoSuitableAddress = errors.New("no suitable address found")
 
-// filterAddrList applies a filter to a list of IP addresses,
-// yielding a list of Addr objects. Known filters are nil, ipv4only,
-// and ipv6only. It returns every address when the filter is nil.
-// The result contains at least one address when error is nil.
-func filterAddrList(filter func(IPAddr) bool, ips []IPAddr, inetaddr func(IPAddr) Addr) (addrList, error) {
-	var addrs addrList
+// firstFavoriteAddr returns an address or a list of addresses that
+// implement the netaddr interface. Known filters are nil, ipv4only
+// and ipv6only. It returns any address when filter is nil. The result
+// contains at least one address when error is nil.
+func firstFavoriteAddr(filter func(IP) IP, ips []IP, inetaddr func(IP) netaddr) (netaddr, error) {
+	if filter != nil {
+		return firstSupportedAddr(filter, ips, inetaddr)
+	}
+	var (
+		ipv4, ipv6, swap bool
+		list             addrList
+	)
 	for _, ip := range ips {
-		if filter == nil || filter(ip) {
-			addrs = append(addrs, inetaddr(ip))
+		// We'll take any IP address, but since the dialing
+		// code does not yet try multiple addresses
+		// effectively, prefer to use an IPv4 address if
+		// possible. This is especially relevant if localhost
+		// resolves to [ipv6-localhost, ipv4-localhost]. Too
+		// much code assumes localhost == ipv4-localhost.
+		if ip4 := ipv4only(ip); ip4 != nil && !ipv4 {
+			list = append(list, inetaddr(ip4))
+			ipv4 = true
+			if ipv6 {
+				swap = true
+			}
+		} else if ip6 := ipv6only(ip); ip6 != nil && !ipv6 {
+			list = append(list, inetaddr(ip6))
+			ipv6 = true
+		}
+		if ipv4 && ipv6 {
+			if swap {
+				list[0], list[1] = list[1], list[0]
+			}
+			break
 		}
 	}
-	if len(addrs) == 0 {
+	switch len(list) {
+	case 0:
 		return nil, errNoSuitableAddress
+	case 1:
+		return list[0], nil
+	default:
+		return list, nil
+	}
+}
+
+func firstSupportedAddr(filter func(IP) IP, ips []IP, inetaddr func(IP) netaddr) (netaddr, error) {
+	for _, ip := range ips {
+		if ip := filter(ip); ip != nil {
+			return inetaddr(ip), nil
+		}
 	}
-	return addrs, nil
+	return nil, errNoSuitableAddress
 }
 
-// ipv4only reports whether the kernel supports IPv4 addressing mode
-// and addr is an IPv4 address.
-func ipv4only(addr IPAddr) bool {
-	return supportsIPv4 && addr.IP.To4() != nil
+// ipv4only returns IPv4 addresses that we can use with the kernel's
+// IPv4 addressing modes. If ip is an IPv4 address, ipv4only returns ip.
+// Otherwise it returns nil.
+func ipv4only(ip IP) IP {
+	if supportsIPv4 && ip.To4() != nil {
+		return ip
+	}
+	return nil
 }
 
-// ipv6only reports whether the kernel supports IPv6 addressing mode
-// and addr is an IPv6 address except IPv4-mapped IPv6 address.
-func ipv6only(addr IPAddr) bool {
-	return supportsIPv6 && len(addr.IP) == IPv6len && addr.IP.To4() == nil
+// ipv6only returns IPv6 addresses that we can use with the kernel's
+// IPv6 addressing modes.  It returns IPv4-mapped IPv6 addresses as
+// nils and returns other IPv6 address types as IPv6 addresses.
+func ipv6only(ip IP) IP {
+	if supportsIPv6 && len(ip) == IPv6len && ip.To4() == nil {
+		return ip
+	}
+	return nil
 }
 
 // SplitHostPort splits a network address of the form "host:port",
@@ -122,7 +153,7 @@ func SplitHostPort(hostport string) (host, port string, err error) {
 		// Expect the first ']' just before the last ':'.
 		end := byteIndex(hostport, ']')
 		if end < 0 {
-			err = &AddrError{Err: "missing ']' in address", Addr: hostport}
+			err = &AddrError{"missing ']' in address", hostport}
 			return
 		}
 		switch end + 1 {
@@ -151,11 +182,11 @@ func SplitHostPort(hostport string) (host, port string, err error) {
 		}
 	}
 	if byteIndex(hostport[j:], '[') >= 0 {
-		err = &AddrError{Err: "unexpected '[' in address", Addr: hostport}
+		err = &AddrError{"unexpected '[' in address", hostport}
 		return
 	}
 	if byteIndex(hostport[k:], ']') >= 0 {
-		err = &AddrError{Err: "unexpected ']' in address", Addr: hostport}
+		err = &AddrError{"unexpected ']' in address", hostport}
 		return
 	}
 
@@ -163,15 +194,15 @@ func SplitHostPort(hostport string) (host, port string, err error) {
 	return
 
 missingPort:
-	err = &AddrError{Err: "missing port in address", Addr: hostport}
+	err = &AddrError{"missing port in address", hostport}
 	return
 
 tooManyColons:
-	err = &AddrError{Err: "too many colons in address", Addr: hostport}
+	err = &AddrError{"too many colons in address", hostport}
 	return
 
 missingBrackets:
-	err = &AddrError{Err: "missing brackets in address", Addr: hostport}
+	err = &AddrError{"missing brackets in address", hostport}
 	return
 }
 
@@ -197,15 +228,17 @@ func JoinHostPort(host, port string) string {
 	return host + ":" + port
 }
 
-// internetAddrList resolves addr, which may be a literal IP
-// address or a DNS name, and returns a list of internet protocol
-// family addresses. The result contains at least one address when
-// error is nil.
-func internetAddrList(net, addr string, deadline time.Time) (addrList, error) {
+// resolveInternetAddr resolves addr that is either a literal IP
+// 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
+// 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 (
-		err        error
-		host, port string
-		portnum    int
+		err              error
+		host, port, zone string
+		portnum          int
 	)
 	switch net {
 	case "tcp", "tcp4", "tcp6", "udp", "udp4", "udp6":
@@ -224,43 +257,43 @@ func internetAddrList(net, addr string, deadline time.Time) (addrList, error) {
 	default:
 		return nil, UnknownNetworkError(net)
 	}
-	inetaddr := func(ip IPAddr) Addr {
+	inetaddr := func(ip IP) netaddr {
 		switch net {
 		case "tcp", "tcp4", "tcp6":
-			return &TCPAddr{IP: ip.IP, Port: portnum, Zone: ip.Zone}
+			return &TCPAddr{IP: ip, Port: portnum, Zone: zone}
 		case "udp", "udp4", "udp6":
-			return &UDPAddr{IP: ip.IP, Port: portnum, Zone: ip.Zone}
+			return &UDPAddr{IP: ip, Port: portnum, Zone: zone}
 		case "ip", "ip4", "ip6":
-			return &IPAddr{IP: ip.IP, Zone: ip.Zone}
+			return &IPAddr{IP: ip, Zone: zone}
 		default:
 			panic("unexpected network: " + net)
 		}
 	}
 	if host == "" {
-		return addrList{inetaddr(IPAddr{})}, nil
+		return inetaddr(nil), nil
 	}
 	// Try as a literal IP address.
 	var ip IP
 	if ip = parseIPv4(host); ip != nil {
-		return addrList{inetaddr(IPAddr{IP: ip})}, nil
+		return inetaddr(ip), nil
 	}
-	var zone string
 	if ip, zone = parseIPv6(host, true); ip != nil {
-		return addrList{inetaddr(IPAddr{IP: ip, Zone: zone})}, nil
+		return inetaddr(ip), nil
 	}
 	// Try as a DNS name.
+	host, zone = splitHostZone(host)
 	ips, err := lookupIPDeadline(host, deadline)
 	if err != nil {
 		return nil, err
 	}
-	var filter func(IPAddr) bool
+	var filter func(IP) IP
 	if net != "" && net[len(net)-1] == '4' {
 		filter = ipv4only
 	}
-	if net != "" && net[len(net)-1] == '6' {
+	if net != "" && net[len(net)-1] == '6' || zone != "" {
 		filter = ipv6only
 	}
-	return filterAddrList(filter, ips, inetaddr)
+	return firstFavoriteAddr(filter, ips, inetaddr)
 }
 
 func zoneToString(zone int) string {
@@ -270,7 +303,7 @@ func zoneToString(zone int) string {
 	if ifi, err := InterfaceByIndex(zone); err == nil {
 		return ifi.Name
 	}
-	return uitoa(uint(zone))
+	return itod(uint(zone))
 }
 
 func zoneToInt(zone string) int {
diff --git a/src/net/ipsock_plan9.go b/src/net/ipsock_plan9.go
index 9da6ec3..94ceea3 100644
--- a/src/net/ipsock_plan9.go
+++ b/src/net/ipsock_plan9.go
@@ -7,6 +7,7 @@
 package net
 
 import (
+	"errors"
 	"os"
 	"syscall"
 )
@@ -59,15 +60,15 @@ func parsePlan9Addr(s string) (ip IP, iport int, err error) {
 	if i >= 0 {
 		addr = ParseIP(s[:i])
 		if addr == nil {
-			return nil, 0, &ParseError{Type: "IP address", Text: s}
+			return nil, 0, errors.New("parsing IP failed")
 		}
 	}
 	p, _, ok := dtoi(s[i+1:], 0)
 	if !ok {
-		return nil, 0, &ParseError{Type: "port", Text: s}
+		return nil, 0, errors.New("parsing port failed")
 	}
 	if p < 0 || p > 0xFFFF {
-		return nil, 0, &AddrError{Err: "invalid port", Addr: string(p)}
+		return nil, 0, &AddrError{"invalid port", string(p)}
 	}
 	return addr, p, nil
 }
@@ -94,7 +95,7 @@ func readPlan9Addr(proto, filename string) (addr Addr, err error) {
 	case "udp":
 		addr = &UDPAddr{IP: ip, Port: port}
 	default:
-		return nil, UnknownNetworkError(proto)
+		return nil, errors.New("unknown protocol " + proto)
 	}
 	return addr, nil
 }
@@ -140,24 +141,6 @@ func netErr(e error) {
 	if !ok {
 		return
 	}
-	nonNilInterface := func(a Addr) bool {
-		switch a := a.(type) {
-		case *TCPAddr:
-			return a == nil
-		case *UDPAddr:
-			return a == nil
-		case *IPAddr:
-			return a == nil
-		default:
-			return false
-		}
-	}
-	if nonNilInterface(oe.Source) {
-		oe.Source = nil
-	}
-	if nonNilInterface(oe.Addr) {
-		oe.Addr = nil
-	}
 	if pe, ok := oe.Err.(*os.PathError); ok {
 		if _, ok = pe.Err.(syscall.ErrorString); ok {
 			oe.Err = pe.Err
@@ -169,23 +152,23 @@ func dialPlan9(net string, laddr, raddr Addr) (fd *netFD, err error) {
 	defer func() { netErr(err) }()
 	f, dest, proto, name, err := startPlan9(net, raddr)
 	if err != nil {
-		return nil, &OpError{Op: "dial", Net: net, Source: laddr, Addr: raddr, Err: err}
+		return nil, &OpError{"dial", net, raddr, err}
 	}
 	_, err = f.WriteString("connect " + dest)
 	if err != nil {
 		f.Close()
-		return nil, &OpError{Op: "dial", Net: f.Name(), Source: laddr, Addr: raddr, Err: err}
+		return nil, &OpError{"dial", f.Name(), raddr, err}
 	}
 	data, err := os.OpenFile(netdir+"/"+proto+"/"+name+"/data", os.O_RDWR, 0)
 	if err != nil {
 		f.Close()
-		return nil, &OpError{Op: "dial", Net: net, Source: laddr, Addr: raddr, Err: err}
+		return nil, &OpError{"dial", net, raddr, err}
 	}
 	laddr, err = readPlan9Addr(proto, netdir+"/"+proto+"/"+name+"/local")
 	if err != nil {
 		data.Close()
 		f.Close()
-		return nil, &OpError{Op: "dial", Net: proto, Source: laddr, Addr: raddr, Err: err}
+		return nil, &OpError{"dial", proto, raddr, err}
 	}
 	return newFD(proto, name, f, data, laddr, raddr)
 }
@@ -194,52 +177,52 @@ func listenPlan9(net string, laddr Addr) (fd *netFD, err error) {
 	defer func() { netErr(err) }()
 	f, dest, proto, name, err := startPlan9(net, laddr)
 	if err != nil {
-		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr, Err: err}
+		return nil, &OpError{"listen", net, laddr, err}
 	}
 	_, err = f.WriteString("announce " + dest)
 	if err != nil {
 		f.Close()
-		return nil, &OpError{Op: "announce", Net: proto, Source: nil, Addr: laddr, Err: err}
+		return nil, &OpError{"announce", proto, laddr, err}
 	}
 	laddr, err = readPlan9Addr(proto, netdir+"/"+proto+"/"+name+"/local")
 	if err != nil {
 		f.Close()
-		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr, Err: err}
+		return nil, &OpError{Op: "listen", Net: net, Err: err}
 	}
 	return newFD(proto, name, f, nil, laddr, nil)
 }
 
-func (fd *netFD) netFD() (*netFD, error) {
-	return newFD(fd.net, fd.n, fd.ctl, fd.data, fd.laddr, fd.raddr)
+func (l *netFD) netFD() (*netFD, error) {
+	return newFD(l.proto, l.n, l.ctl, l.data, l.laddr, l.raddr)
 }
 
-func (fd *netFD) acceptPlan9() (nfd *netFD, err error) {
+func (l *netFD) acceptPlan9() (fd *netFD, err error) {
 	defer func() { netErr(err) }()
-	if err := fd.readLock(); err != nil {
+	if err := l.readLock(); err != nil {
 		return nil, err
 	}
-	defer fd.readUnlock()
-	f, err := os.Open(fd.dir + "/listen")
+	defer l.readUnlock()
+	f, err := os.Open(l.dir + "/listen")
 	if err != nil {
-		return nil, &OpError{Op: "accept", Net: fd.dir + "/listen", Source: nil, Addr: fd.laddr, Err: err}
+		return nil, &OpError{"accept", l.dir + "/listen", l.laddr, err}
 	}
 	var buf [16]byte
 	n, err := f.Read(buf[:])
 	if err != nil {
 		f.Close()
-		return nil, &OpError{Op: "accept", Net: fd.dir + "/listen", Source: nil, Addr: fd.laddr, Err: err}
+		return nil, &OpError{"accept", l.dir + "/listen", l.laddr, err}
 	}
 	name := string(buf[:n])
-	data, err := os.OpenFile(netdir+"/"+fd.net+"/"+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{Op: "accept", Net: fd.net, Source: nil, Addr: fd.laddr, Err: err}
+		return nil, &OpError{"accept", l.proto, l.laddr, err}
 	}
-	raddr, err := readPlan9Addr(fd.net, netdir+"/"+fd.net+"/"+name+"/remote")
+	raddr, err := readPlan9Addr(l.proto, netdir+"/"+l.proto+"/"+name+"/remote")
 	if err != nil {
 		data.Close()
 		f.Close()
-		return nil, &OpError{Op: "accept", Net: fd.net, Source: nil, Addr: fd.laddr, Err: err}
+		return nil, &OpError{"accept", l.proto, l.laddr, err}
 	}
-	return newFD(fd.net, name, f, data, fd.laddr, raddr)
+	return newFD(l.proto, name, f, data, l.laddr, raddr)
 }
diff --git a/src/net/ipsock_posix.go b/src/net/ipsock_posix.go
index 83eaf85..f9ebe40 100644
--- a/src/net/ipsock_posix.go
+++ b/src/net/ipsock_posix.go
@@ -9,25 +9,17 @@
 package net
 
 import (
-	"runtime"
 	"syscall"
 	"time"
 )
 
-// BUG(rsc,mikio): On DragonFly BSD and OpenBSD, listening on the
-// "tcp" and "udp" networks does not listen for both IPv4 and IPv6
-// connections. This is due to the fact that IPv4 traffic will not be
-// routed to an IPv6 socket - two separate sockets are required if
-// both address families are to be supported.
-// See inet6(4) for details.
-
 func probeIPv4Stack() bool {
-	s, err := socketFunc(syscall.AF_INET, syscall.SOCK_STREAM, syscall.IPPROTO_TCP)
+	s, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_STREAM, syscall.IPPROTO_TCP)
 	switch err {
 	case syscall.EAFNOSUPPORT, syscall.EPROTONOSUPPORT:
 		return false
 	case nil:
-		closeFunc(s)
+		closesocket(s)
 	}
 	return true
 }
@@ -49,35 +41,20 @@ func probeIPv6Stack() (supportsIPv6, supportsIPv4map bool) {
 	var probes = []struct {
 		laddr TCPAddr
 		value int
+		ok    bool
 	}{
 		// IPv6 communication capability
 		{laddr: TCPAddr{IP: ParseIP("::1")}, value: 1},
 		// IPv6 IPv4-mapped address communication capability
 		{laddr: TCPAddr{IP: IPv4(127, 0, 0, 1)}, value: 0},
 	}
-	var supps [2]bool
-	switch runtime.GOOS {
-	case "dragonfly", "openbsd":
-		// Some released versions of DragonFly BSD pretend to
-		// accept IPV6_V6ONLY=0 successfully, but the state
-		// still stays IPV6_V6ONLY=1. Eventually DragonFly BSD
-		// stops preteding, but the transition period would
-		// cause unpredictable behavior and we need to avoid
-		// it.
-		//
-		// OpenBSD also doesn't support IPV6_V6ONLY=0 but it
-		// never pretends to accept IPV6_V6OLY=0. It always
-		// returns an error and we don't need to probe the
-		// capability.
-		probes = probes[:1]
-	}
 
 	for i := range probes {
-		s, err := socketFunc(syscall.AF_INET6, syscall.SOCK_STREAM, syscall.IPPROTO_TCP)
+		s, err := syscall.Socket(syscall.AF_INET6, syscall.SOCK_STREAM, syscall.IPPROTO_TCP)
 		if err != nil {
 			continue
 		}
-		defer closeFunc(s)
+		defer closesocket(s)
 		syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, probes[i].value)
 		sa, err := probes[i].laddr.sockaddr(syscall.AF_INET6)
 		if err != nil {
@@ -86,10 +63,10 @@ func probeIPv6Stack() (supportsIPv6, supportsIPv4map bool) {
 		if err := syscall.Bind(s, sa); err != nil {
 			continue
 		}
-		supps[i] = true
+		probes[i].ok = true
 	}
 
-	return supps[0], supps[1]
+	return probes[0].ok, probes[1].ok
 }
 
 // favoriteAddrFamily returns the appropriate address family to
@@ -167,7 +144,7 @@ func ipToSockaddr(family int, ip IP, port int, zone string) (syscall.Sockaddr, e
 			ip = IPv4zero
 		}
 		if ip = ip.To4(); ip == nil {
-			return nil, &AddrError{Err: "non-IPv4 address", Addr: ip.String()}
+			return nil, InvalidAddrError("non-IPv4 address")
 		}
 		sa := new(syscall.SockaddrInet4)
 		for i := 0; i < IPv4len; i++ {
@@ -186,7 +163,7 @@ func ipToSockaddr(family int, ip IP, port int, zone string) (syscall.Sockaddr, e
 			ip = IPv6zero
 		}
 		if ip = ip.To16(); ip == nil {
-			return nil, &AddrError{Err: "non-IPv6 address", Addr: ip.String()}
+			return nil, InvalidAddrError("non-IPv6 address")
 		}
 		sa := new(syscall.SockaddrInet6)
 		for i := 0; i < IPv6len; i++ {
@@ -196,5 +173,5 @@ func ipToSockaddr(family int, ip IP, port int, zone string) (syscall.Sockaddr, e
 		sa.ZoneId = uint32(zoneToInt(zone))
 		return sa, nil
 	}
-	return nil, &AddrError{Err: "invalid address family", Addr: ip.String()}
+	return nil, InvalidAddrError("unexpected socket family")
 }
diff --git a/src/net/ipsock_test.go b/src/net/ipsock_test.go
index b36557a..9ecaaec 100644
--- a/src/net/ipsock_test.go
+++ b/src/net/ipsock_test.go
@@ -9,274 +9,185 @@ import (
 	"testing"
 )
 
-var testInetaddr = func(ip IPAddr) Addr { return &TCPAddr{IP: ip.IP, Port: 5682, Zone: ip.Zone} }
+var testInetaddr = func(ip IP) netaddr { return &TCPAddr{IP: ip, Port: 5682} }
 
-var addrListTests = []struct {
-	filter    func(IPAddr) bool
-	ips       []IPAddr
-	inetaddr  func(IPAddr) Addr
-	first     Addr
-	primaries addrList
-	fallbacks addrList
-	err       error
+var firstFavoriteAddrTests = []struct {
+	filter   func(IP) IP
+	ips      []IP
+	inetaddr func(IP) netaddr
+	addr     netaddr
+	err      error
 }{
 	{
 		nil,
-		[]IPAddr{
-			{IP: IPv4(127, 0, 0, 1)},
-			{IP: IPv6loopback},
+		[]IP{
+			IPv4(127, 0, 0, 1),
+			IPv6loopback,
 		},
 		testInetaddr,
-		&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
-		addrList{&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682}},
-		addrList{&TCPAddr{IP: IPv6loopback, Port: 5682}},
+		addrList{
+			&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
+			&TCPAddr{IP: IPv6loopback, Port: 5682},
+		},
 		nil,
 	},
 	{
 		nil,
-		[]IPAddr{
-			{IP: IPv6loopback},
-			{IP: IPv4(127, 0, 0, 1)},
+		[]IP{
+			IPv6loopback,
+			IPv4(127, 0, 0, 1),
 		},
 		testInetaddr,
-		&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
-		addrList{&TCPAddr{IP: IPv6loopback, Port: 5682}},
-		addrList{&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682}},
+		addrList{
+			&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
+			&TCPAddr{IP: IPv6loopback, Port: 5682},
+		},
 		nil,
 	},
 	{
 		nil,
-		[]IPAddr{
-			{IP: IPv4(127, 0, 0, 1)},
-			{IP: IPv4(192, 168, 0, 1)},
+		[]IP{
+			IPv4(127, 0, 0, 1),
+			IPv4(192, 168, 0, 1),
 		},
 		testInetaddr,
 		&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
-		addrList{
-			&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
-			&TCPAddr{IP: IPv4(192, 168, 0, 1), Port: 5682},
-		},
-		nil,
 		nil,
 	},
 	{
 		nil,
-		[]IPAddr{
-			{IP: IPv6loopback},
-			{IP: ParseIP("fe80::1"), Zone: "eth0"},
+		[]IP{
+			IPv6loopback,
+			ParseIP("fe80::1"),
 		},
 		testInetaddr,
 		&TCPAddr{IP: IPv6loopback, Port: 5682},
-		addrList{
-			&TCPAddr{IP: IPv6loopback, Port: 5682},
-			&TCPAddr{IP: ParseIP("fe80::1"), Port: 5682, Zone: "eth0"},
-		},
-		nil,
 		nil,
 	},
 	{
 		nil,
-		[]IPAddr{
-			{IP: IPv4(127, 0, 0, 1)},
-			{IP: IPv4(192, 168, 0, 1)},
-			{IP: IPv6loopback},
-			{IP: ParseIP("fe80::1"), Zone: "eth0"},
+		[]IP{
+			IPv4(127, 0, 0, 1),
+			IPv4(192, 168, 0, 1),
+			IPv6loopback,
+			ParseIP("fe80::1"),
 		},
 		testInetaddr,
-		&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
 		addrList{
 			&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
-			&TCPAddr{IP: IPv4(192, 168, 0, 1), Port: 5682},
-		},
-		addrList{
 			&TCPAddr{IP: IPv6loopback, Port: 5682},
-			&TCPAddr{IP: ParseIP("fe80::1"), Port: 5682, Zone: "eth0"},
 		},
 		nil,
 	},
 	{
 		nil,
-		[]IPAddr{
-			{IP: IPv6loopback},
-			{IP: ParseIP("fe80::1"), Zone: "eth0"},
-			{IP: IPv4(127, 0, 0, 1)},
-			{IP: IPv4(192, 168, 0, 1)},
+		[]IP{
+			IPv6loopback,
+			ParseIP("fe80::1"),
+			IPv4(127, 0, 0, 1),
+			IPv4(192, 168, 0, 1),
 		},
 		testInetaddr,
-		&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
-		addrList{
-			&TCPAddr{IP: IPv6loopback, Port: 5682},
-			&TCPAddr{IP: ParseIP("fe80::1"), Port: 5682, Zone: "eth0"},
-		},
 		addrList{
 			&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
-			&TCPAddr{IP: IPv4(192, 168, 0, 1), Port: 5682},
+			&TCPAddr{IP: IPv6loopback, Port: 5682},
 		},
 		nil,
 	},
 	{
 		nil,
-		[]IPAddr{
-			{IP: IPv4(127, 0, 0, 1)},
-			{IP: IPv6loopback},
-			{IP: IPv4(192, 168, 0, 1)},
-			{IP: ParseIP("fe80::1"), Zone: "eth0"},
+		[]IP{
+			IPv4(127, 0, 0, 1),
+			IPv6loopback,
+			IPv4(192, 168, 0, 1),
+			ParseIP("fe80::1"),
 		},
 		testInetaddr,
-		&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
 		addrList{
 			&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
-			&TCPAddr{IP: IPv4(192, 168, 0, 1), Port: 5682},
-		},
-		addrList{
 			&TCPAddr{IP: IPv6loopback, Port: 5682},
-			&TCPAddr{IP: ParseIP("fe80::1"), Port: 5682, Zone: "eth0"},
 		},
 		nil,
 	},
 	{
 		nil,
-		[]IPAddr{
-			{IP: IPv6loopback},
-			{IP: IPv4(127, 0, 0, 1)},
-			{IP: ParseIP("fe80::1"), Zone: "eth0"},
-			{IP: IPv4(192, 168, 0, 1)},
+		[]IP{
+			IPv6loopback,
+			IPv4(127, 0, 0, 1),
+			ParseIP("fe80::1"),
+			IPv4(192, 168, 0, 1),
 		},
 		testInetaddr,
-		&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
-		addrList{
-			&TCPAddr{IP: IPv6loopback, Port: 5682},
-			&TCPAddr{IP: ParseIP("fe80::1"), Port: 5682, Zone: "eth0"},
-		},
 		addrList{
 			&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
-			&TCPAddr{IP: IPv4(192, 168, 0, 1), Port: 5682},
+			&TCPAddr{IP: IPv6loopback, Port: 5682},
 		},
 		nil,
 	},
 
 	{
 		ipv4only,
-		[]IPAddr{
-			{IP: IPv4(127, 0, 0, 1)},
-			{IP: IPv6loopback},
+		[]IP{
+			IPv4(127, 0, 0, 1),
+			IPv6loopback,
 		},
 		testInetaddr,
 		&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
-		addrList{&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682}},
-		nil,
 		nil,
 	},
 	{
 		ipv4only,
-		[]IPAddr{
-			{IP: IPv6loopback},
-			{IP: IPv4(127, 0, 0, 1)},
+		[]IP{
+			IPv6loopback,
+			IPv4(127, 0, 0, 1),
 		},
 		testInetaddr,
 		&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
-		addrList{&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682}},
-		nil,
 		nil,
 	},
 
 	{
 		ipv6only,
-		[]IPAddr{
-			{IP: IPv4(127, 0, 0, 1)},
-			{IP: IPv6loopback},
+		[]IP{
+			IPv4(127, 0, 0, 1),
+			IPv6loopback,
 		},
 		testInetaddr,
 		&TCPAddr{IP: IPv6loopback, Port: 5682},
-		addrList{&TCPAddr{IP: IPv6loopback, Port: 5682}},
-		nil,
 		nil,
 	},
 	{
 		ipv6only,
-		[]IPAddr{
-			{IP: IPv6loopback},
-			{IP: IPv4(127, 0, 0, 1)},
+		[]IP{
+			IPv6loopback,
+			IPv4(127, 0, 0, 1),
 		},
 		testInetaddr,
 		&TCPAddr{IP: IPv6loopback, Port: 5682},
-		addrList{&TCPAddr{IP: IPv6loopback, Port: 5682}},
-		nil,
 		nil,
 	},
 
-	{nil, nil, testInetaddr, nil, nil, nil, errNoSuitableAddress},
+	{nil, nil, testInetaddr, nil, errNoSuitableAddress},
 
-	{ipv4only, nil, testInetaddr, nil, nil, nil, errNoSuitableAddress},
-	{ipv4only, []IPAddr{{IP: IPv6loopback}}, testInetaddr, nil, nil, nil, errNoSuitableAddress},
+	{ipv4only, nil, testInetaddr, nil, errNoSuitableAddress},
+	{ipv4only, []IP{IPv6loopback}, testInetaddr, nil, errNoSuitableAddress},
 
-	{ipv6only, nil, testInetaddr, nil, nil, nil, errNoSuitableAddress},
-	{ipv6only, []IPAddr{{IP: IPv4(127, 0, 0, 1)}}, testInetaddr, nil, nil, nil, errNoSuitableAddress},
+	{ipv6only, nil, testInetaddr, nil, errNoSuitableAddress},
+	{ipv6only, []IP{IPv4(127, 0, 0, 1)}, testInetaddr, nil, errNoSuitableAddress},
 }
 
-func TestAddrList(t *testing.T) {
+func TestFirstFavoriteAddr(t *testing.T) {
 	if !supportsIPv4 || !supportsIPv6 {
-		t.Skip("both IPv4 and IPv6 are required")
+		t.Skip("ipv4 or ipv6 is not supported")
 	}
 
-	for i, tt := range addrListTests {
-		addrs, err := filterAddrList(tt.filter, tt.ips, tt.inetaddr)
+	for i, tt := range firstFavoriteAddrTests {
+		addr, err := firstFavoriteAddr(tt.filter, tt.ips, tt.inetaddr)
 		if err != tt.err {
-			t.Errorf("#%v: got %v; want %v", i, err, tt.err)
-		}
-		if tt.err != nil {
-			if len(addrs) != 0 {
-				t.Errorf("#%v: got %v; want 0", i, len(addrs))
-			}
-			continue
-		}
-		first := addrs.first(isIPv4)
-		if !reflect.DeepEqual(first, tt.first) {
-			t.Errorf("#%v: got %v; want %v", i, first, tt.first)
-		}
-		primaries, fallbacks := addrs.partition(isIPv4)
-		if !reflect.DeepEqual(primaries, tt.primaries) {
-			t.Errorf("#%v: got %v; want %v", i, primaries, tt.primaries)
-		}
-		if !reflect.DeepEqual(fallbacks, tt.fallbacks) {
-			t.Errorf("#%v: got %v; want %v", i, fallbacks, tt.fallbacks)
+			t.Errorf("#%v: got %v; expected %v", i, err, tt.err)
 		}
-		expectedLen := len(primaries) + len(fallbacks)
-		if len(addrs) != expectedLen {
-			t.Errorf("#%v: got %v; want %v", i, len(addrs), expectedLen)
-		}
-	}
-}
-
-func TestAddrListPartition(t *testing.T) {
-	addrs := addrList{
-		&IPAddr{IP: ParseIP("fe80::"), Zone: "eth0"},
-		&IPAddr{IP: ParseIP("fe80::1"), Zone: "eth0"},
-		&IPAddr{IP: ParseIP("fe80::2"), Zone: "eth0"},
-	}
-	cases := []struct {
-		lastByte  byte
-		primaries addrList
-		fallbacks addrList
-	}{
-		{0, addrList{addrs[0]}, addrList{addrs[1], addrs[2]}},
-		{1, addrList{addrs[0], addrs[2]}, addrList{addrs[1]}},
-		{2, addrList{addrs[0], addrs[1]}, addrList{addrs[2]}},
-		{3, addrList{addrs[0], addrs[1], addrs[2]}, nil},
-	}
-	for i, tt := range cases {
-		// Inverting the function's output should not affect the outcome.
-		for _, invert := range []bool{false, true} {
-			primaries, fallbacks := addrs.partition(func(a Addr) bool {
-				ip := a.(*IPAddr).IP
-				return (ip[len(ip)-1] == tt.lastByte) != invert
-			})
-			if !reflect.DeepEqual(primaries, tt.primaries) {
-				t.Errorf("#%v: got %v; want %v", i, primaries, tt.primaries)
-			}
-			if !reflect.DeepEqual(fallbacks, tt.fallbacks) {
-				t.Errorf("#%v: got %v; want %v", i, fallbacks, tt.fallbacks)
-			}
+		if !reflect.DeepEqual(addr, tt.addr) {
+			t.Errorf("#%v: got %v; expected %v", i, addr, tt.addr)
 		}
 	}
 }
diff --git a/src/net/lookup.go b/src/net/lookup.go
index a7ceee8..aeffe6c 100644
--- a/src/net/lookup.go
+++ b/src/net/lookup.go
@@ -4,10 +4,7 @@
 
 package net
 
-import (
-	"internal/singleflight"
-	"time"
-)
+import "time"
 
 // protocols contains minimal mappings between internet protocol
 // names and numbers for platforms that don't have a complete list of
@@ -25,60 +22,36 @@ var protocols = map[string]int{
 // LookupHost looks up the given host using the local resolver.
 // It returns an array of that host's addresses.
 func LookupHost(host string) (addrs []string, err error) {
-	// Make sure that no matter what we do later, host=="" is rejected.
-	// ParseIP, for example, does accept empty strings.
-	if host == "" {
-		return nil, &DNSError{Err: errNoSuchHost.Error(), Name: host}
-	}
-	if ip := ParseIP(host); ip != nil {
-		return []string{host}, nil
-	}
 	return lookupHost(host)
 }
 
 // LookupIP looks up host using the local resolver.
 // It returns an array of that host's IPv4 and IPv6 addresses.
-func LookupIP(host string) (ips []IP, err error) {
-	// Make sure that no matter what we do later, host=="" is rejected.
-	// ParseIP, for example, does accept empty strings.
-	if host == "" {
-		return nil, &DNSError{Err: errNoSuchHost.Error(), Name: host}
-	}
-	if ip := ParseIP(host); ip != nil {
-		return []IP{ip}, nil
-	}
-	addrs, err := lookupIPMerge(host)
-	if err != nil {
-		return
-	}
-	ips = make([]IP, len(addrs))
-	for i, addr := range addrs {
-		ips[i] = addr.IP
-	}
-	return
+func LookupIP(host string) (addrs []IP, err error) {
+	return lookupIPMerge(host)
 }
 
-var lookupGroup singleflight.Group
+var lookupGroup singleflight
 
 // lookupIPMerge wraps lookupIP, but makes sure that for any given
 // host, only one lookup is in-flight at a time. The returned memory
 // is always owned by the caller.
-func lookupIPMerge(host string) (addrs []IPAddr, err error) {
+func lookupIPMerge(host string) (addrs []IP, err error) {
 	addrsi, err, shared := lookupGroup.Do(host, func() (interface{}, error) {
-		return testHookLookupIP(lookupIP, host)
+		return lookupIP(host)
 	})
 	return lookupIPReturn(addrsi, err, shared)
 }
 
 // lookupIPReturn turns the return values from singleflight.Do into
 // the return values from LookupIP.
-func lookupIPReturn(addrsi interface{}, err error, shared bool) ([]IPAddr, error) {
+func lookupIPReturn(addrsi interface{}, err error, shared bool) ([]IP, error) {
 	if err != nil {
 		return nil, err
 	}
-	addrs := addrsi.([]IPAddr)
+	addrs := addrsi.([]IP)
 	if shared {
-		clone := make([]IPAddr, len(addrs))
+		clone := make([]IP, len(addrs))
 		copy(clone, addrs)
 		addrs = clone
 	}
@@ -86,7 +59,7 @@ func lookupIPReturn(addrsi interface{}, err error, shared bool) ([]IPAddr, error
 }
 
 // lookupIPDeadline looks up a hostname with a deadline.
-func lookupIPDeadline(host string, deadline time.Time) (addrs []IPAddr, err error) {
+func lookupIPDeadline(host string, deadline time.Time) (addrs []IP, err error) {
 	if deadline.IsZero() {
 		return lookupIPMerge(host)
 	}
@@ -103,7 +76,7 @@ func lookupIPDeadline(host string, deadline time.Time) (addrs []IPAddr, err erro
 	defer t.Stop()
 
 	ch := lookupGroup.DoChan(host, func() (interface{}, error) {
-		return testHookLookupIP(lookupIP, host)
+		return lookupIP(host)
 	})
 
 	select {
@@ -117,7 +90,7 @@ func lookupIPDeadline(host string, deadline time.Time) (addrs []IPAddr, err erro
 		return nil, errTimeout
 
 	case r := <-ch:
-		return lookupIPReturn(r.Val, r.Err, r.Shared)
+		return lookupIPReturn(r.v, r.err, r.shared)
 	}
 }
 
@@ -148,22 +121,22 @@ func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err err
 }
 
 // LookupMX returns the DNS MX records for the given domain name sorted by preference.
-func LookupMX(name string) (mxs []*MX, err error) {
+func LookupMX(name string) (mx []*MX, err error) {
 	return lookupMX(name)
 }
 
 // LookupNS returns the DNS NS records for the given domain name.
-func LookupNS(name string) (nss []*NS, err error) {
+func LookupNS(name string) (ns []*NS, err error) {
 	return lookupNS(name)
 }
 
 // LookupTXT returns the DNS TXT records for the given domain name.
-func LookupTXT(name string) (txts []string, err error) {
+func LookupTXT(name string) (txt []string, err error) {
 	return lookupTXT(name)
 }
 
 // LookupAddr performs a reverse lookup for the given address, returning a list
 // of names mapping to that address.
-func LookupAddr(addr string) (names []string, err error) {
+func LookupAddr(addr string) (name []string, err error) {
 	return lookupAddr(addr)
 }
diff --git a/src/net/lookup_plan9.go b/src/net/lookup_plan9.go
index c627464..b80ac10 100644
--- a/src/net/lookup_plan9.go
+++ b/src/net/lookup_plan9.go
@@ -101,18 +101,19 @@ func lookupProtocol(name string) (proto int, err error) {
 	if err != nil {
 		return 0, err
 	}
+	unknownProtoError := errors.New("unknown IP protocol specified: " + name)
 	if len(lines) == 0 {
-		return 0, UnknownNetworkError(name)
+		return 0, unknownProtoError
 	}
 	f := getFields(lines[0])
 	if len(f) < 2 {
-		return 0, UnknownNetworkError(name)
+		return 0, unknownProtoError
 	}
 	s := f[1]
 	if n, _, ok := dtoi(s, byteIndex(s, '=')+1); ok {
 		return n, nil
 	}
-	return 0, UnknownNetworkError(name)
+	return 0, unknownProtoError
 }
 
 func lookupHost(host string) (addrs []string, err error) {
@@ -146,16 +147,14 @@ loop:
 	return
 }
 
-func lookupIP(host string) (addrs []IPAddr, err error) {
-	lits, err := LookupHost(host)
+func lookupIP(host string) (ips []IP, err error) {
+	addrs, err := LookupHost(host)
 	if err != nil {
 		return
 	}
-	for _, lit := range lits {
-		host, zone := splitHostZone(lit)
-		if ip := ParseIP(host); ip != nil {
-			addr := IPAddr{IP: ip, Zone: zone}
-			addrs = append(addrs, addr)
+	for _, addr := range addrs {
+		if ip := ParseIP(addr); ip != nil {
+			ips = append(ips, ip)
 		}
 	}
 	return
@@ -172,7 +171,7 @@ func lookupPort(network, service string) (port int, err error) {
 	if err != nil {
 		return
 	}
-	unknownPortError := &AddrError{Err: "unknown port", Addr: network + "/" + service}
+	unknownPortError := &AddrError{"unknown port", network + "/" + service}
 	if len(lines) == 0 {
 		return 0, unknownPortError
 	}
diff --git a/src/net/lookup_stub.go b/src/net/lookup_stub.go
index 5636198..502aafb 100644
--- a/src/net/lookup_stub.go
+++ b/src/net/lookup_stub.go
@@ -16,7 +16,7 @@ func lookupHost(host string) (addrs []string, err error) {
 	return nil, syscall.ENOPROTOOPT
 }
 
-func lookupIP(host string) (addrs []IPAddr, err error) {
+func lookupIP(host string) (ips []IP, err error) {
 	return nil, syscall.ENOPROTOOPT
 }
 
diff --git a/src/net/lookup_test.go b/src/net/lookup_test.go
index 86957b5..057e132 100644
--- a/src/net/lookup_test.go
+++ b/src/net/lookup_test.go
@@ -2,34 +2,18 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+// TODO It would be nice to use a mock DNS server, to eliminate
+// external dependencies.
+
 package net
 
 import (
-	"bytes"
-	"fmt"
+	"flag"
 	"strings"
 	"testing"
-	"time"
 )
 
-func lookupLocalhost(fn func(string) ([]IPAddr, error), host string) ([]IPAddr, error) {
-	switch host {
-	case "localhost":
-		return []IPAddr{
-			{IP: IPv4(127, 0, 0, 1)},
-			{IP: IPv6loopback},
-		}, nil
-	default:
-		return fn(host)
-	}
-}
-
-// The Lookup APIs use various sources such as local database, DNS or
-// mDNS, and may use platform-dependent DNS stub resolver if possible.
-// The APIs accept any of forms for a query; host name in various
-// encodings, UTF-8 encoded net name, domain name, FQDN or absolute
-// FQDN, but the result would be one of the forms and it depends on
-// the circumstances.
+var testExternal = flag.Bool("external", true, "allow use of external networks during long test")
 
 var lookupGoogleSRVTests = []struct {
 	service, proto, name string
@@ -37,30 +21,17 @@ var lookupGoogleSRVTests = []struct {
 }{
 	{
 		"xmpp-server", "tcp", "google.com",
-		"google.com", "google.com",
-	},
-	{
-		"xmpp-server", "tcp", "google.com.",
-		"google.com", "google.com",
-	},
-
-	// non-standard back door
-	{
-		"", "", "_xmpp-server._tcp.google.com",
-		"google.com", "google.com",
+		".google.com", ".google.com",
 	},
 	{
-		"", "", "_xmpp-server._tcp.google.com.",
-		"google.com", "google.com",
+		"", "", "_xmpp-server._tcp.google.com", // non-standard back door
+		".google.com", ".google.com",
 	},
 }
 
 func TestLookupGoogleSRV(t *testing.T) {
 	if testing.Short() || !*testExternal {
-		t.Skip("avoid external network")
-	}
-	if !supportsIPv4 || !*testIPv4 {
-		t.Skip("IPv4 is required")
+		t.Skip("skipping test to avoid external network")
 	}
 
 	for _, tt := range lookupGoogleSRVTests {
@@ -71,128 +42,90 @@ func TestLookupGoogleSRV(t *testing.T) {
 		if len(srvs) == 0 {
 			t.Error("got no record")
 		}
-		if !strings.HasSuffix(cname, tt.cname) && !strings.HasSuffix(cname, tt.cname+".") {
-			t.Errorf("got %s; want %s", cname, tt.cname)
+		if !strings.Contains(cname, tt.cname) {
+			t.Errorf("got %q; want %q", cname, tt.cname)
 		}
 		for _, srv := range srvs {
-			if !strings.HasSuffix(srv.Target, tt.target) && !strings.HasSuffix(srv.Target, tt.target+".") {
-				t.Errorf("got %v; want a record containing %s", srv, tt.target)
+			if !strings.Contains(srv.Target, tt.target) {
+				t.Errorf("got %v; want a record containing %q", srv, tt.target)
 			}
 		}
 	}
 }
 
-var lookupGmailMXTests = []struct {
-	name, host string
-}{
-	{"gmail.com", "google.com"},
-	{"gmail.com.", "google.com"},
-}
-
 func TestLookupGmailMX(t *testing.T) {
 	if testing.Short() || !*testExternal {
-		t.Skip("avoid external network")
-	}
-	if !supportsIPv4 || !*testIPv4 {
-		t.Skip("IPv4 is required")
+		t.Skip("skipping test to avoid external network")
 	}
 
-	for _, tt := range lookupGmailMXTests {
-		mxs, err := LookupMX(tt.name)
-		if err != nil {
-			t.Fatal(err)
-		}
-		if len(mxs) == 0 {
-			t.Error("got no record")
-		}
-		for _, mx := range mxs {
-			if !strings.HasSuffix(mx.Host, tt.host) && !strings.HasSuffix(mx.Host, tt.host+".") {
-				t.Errorf("got %v; want a record containing %s", mx, tt.host)
-			}
+	mxs, err := LookupMX("gmail.com")
+	if err != nil {
+		t.Fatal(err)
+	}
+	if len(mxs) == 0 {
+		t.Error("got no record")
+	}
+	for _, mx := range mxs {
+		if !strings.Contains(mx.Host, ".google.com") {
+			t.Errorf("got %v; want a record containing .google.com.", mx)
 		}
 	}
 }
 
-var lookupGmailNSTests = []struct {
-	name, host string
-}{
-	{"gmail.com", "google.com"},
-	{"gmail.com.", "google.com"},
-}
-
 func TestLookupGmailNS(t *testing.T) {
 	if testing.Short() || !*testExternal {
-		t.Skip("avoid external network")
-	}
-	if !supportsIPv4 || !*testIPv4 {
-		t.Skip("IPv4 is required")
+		t.Skip("skipping test to avoid external network")
 	}
 
-	for _, tt := range lookupGmailNSTests {
-		nss, err := LookupNS(tt.name)
-		if err != nil {
-			t.Fatal(err)
-		}
-		if len(nss) == 0 {
-			t.Error("got no record")
-		}
-		for _, ns := range nss {
-			if !strings.HasSuffix(ns.Host, tt.host) && !strings.HasSuffix(ns.Host, tt.host+".") {
-				t.Errorf("got %v; want a record containing %s", ns, tt.host)
-			}
+	nss, err := LookupNS("gmail.com")
+	if err != nil {
+		t.Fatal(err)
+	}
+	if len(nss) == 0 {
+		t.Error("got no record")
+	}
+	for _, ns := range nss {
+		if !strings.Contains(ns.Host, ".google.com") {
+			t.Errorf("got %v; want a record containing .google.com.", ns)
 		}
 	}
 }
 
-var lookupGmailTXTTests = []struct {
-	name, txt, host string
-}{
-	{"gmail.com", "spf", "google.com"},
-	{"gmail.com.", "spf", "google.com"},
-}
-
 func TestLookupGmailTXT(t *testing.T) {
 	if testing.Short() || !*testExternal {
-		t.Skip("avoid external network")
-	}
-	if !supportsIPv4 || !*testIPv4 {
-		t.Skip("IPv4 is required")
+		t.Skip("skipping test to avoid external network")
 	}
 
-	for _, tt := range lookupGmailTXTTests {
-		txts, err := LookupTXT(tt.name)
-		if err != nil {
-			t.Fatal(err)
-		}
-		if len(txts) == 0 {
-			t.Error("got no record")
-		}
-		for _, txt := range txts {
-			if !strings.Contains(txt, tt.txt) || (!strings.HasSuffix(txt, tt.host) && !strings.HasSuffix(txt, tt.host+".")) {
-				t.Errorf("got %s; want a record containing %s, %s", txt, tt.txt, tt.host)
-			}
+	txts, err := LookupTXT("gmail.com")
+	if err != nil {
+		t.Fatal(err)
+	}
+	if len(txts) == 0 {
+		t.Error("got no record")
+	}
+	for _, txt := range txts {
+		if !strings.Contains(txt, "spf") {
+			t.Errorf("got %q; want a spf record", txt)
 		}
 	}
 }
 
-var lookupGooglePublicDNSAddrTests = []struct {
-	addr, name string
+var lookupGooglePublicDNSAddrs = []struct {
+	addr string
+	name string
 }{
-	{"8.8.8.8", ".google.com"},
-	{"8.8.4.4", ".google.com"},
-	{"2001:4860:4860::8888", ".google.com"},
-	{"2001:4860:4860::8844", ".google.com"},
+	{"8.8.8.8", ".google.com."},
+	{"8.8.4.4", ".google.com."},
+	{"2001:4860:4860::8888", ".google.com."},
+	{"2001:4860:4860::8844", ".google.com."},
 }
 
 func TestLookupGooglePublicDNSAddr(t *testing.T) {
 	if testing.Short() || !*testExternal {
-		t.Skip("avoid external network")
-	}
-	if !supportsIPv4 || !supportsIPv6 || !*testIPv4 || !*testIPv6 {
-		t.Skip("both IPv4 and IPv6 are required")
+		t.Skip("skipping test to avoid external network")
 	}
 
-	for _, tt := range lookupGooglePublicDNSAddrTests {
+	for _, tt := range lookupGooglePublicDNSAddrs {
 		names, err := LookupAddr(tt.addr)
 		if err != nil {
 			t.Fatal(err)
@@ -201,97 +134,61 @@ func TestLookupGooglePublicDNSAddr(t *testing.T) {
 			t.Error("got no record")
 		}
 		for _, name := range names {
-			if !strings.HasSuffix(name, tt.name) && !strings.HasSuffix(name, tt.name+".") {
-				t.Errorf("got %s; want a record containing %s", name, tt.name)
+			if !strings.HasSuffix(name, tt.name) {
+				t.Errorf("got %q; want a record containing %q", name, tt.name)
 			}
 		}
 	}
 }
 
-var lookupIANACNAMETests = []struct {
-	name, cname string
-}{
-	{"www.iana.org", "icann.org"},
-	{"www.iana.org.", "icann.org"},
-}
-
 func TestLookupIANACNAME(t *testing.T) {
 	if testing.Short() || !*testExternal {
-		t.Skip("avoid external network")
-	}
-	if !supportsIPv4 || !*testIPv4 {
-		t.Skip("IPv4 is required")
+		t.Skip("skipping test to avoid external network")
 	}
 
-	for _, tt := range lookupIANACNAMETests {
-		cname, err := LookupCNAME(tt.name)
-		if err != nil {
-			t.Fatal(err)
-		}
-		if !strings.HasSuffix(cname, tt.cname) && !strings.HasSuffix(cname, tt.cname+".") {
-			t.Errorf("got %s; want a record containing %s", cname, tt.cname)
-		}
+	cname, err := LookupCNAME("www.iana.org")
+	if err != nil {
+		t.Fatal(err)
+	}
+	if !strings.HasSuffix(cname, ".icann.org.") {
+		t.Errorf("got %q; want a record containing .icann.org.", cname)
 	}
-}
-
-var lookupGoogleHostTests = []struct {
-	name string
-}{
-	{"google.com"},
-	{"google.com."},
 }
 
 func TestLookupGoogleHost(t *testing.T) {
 	if testing.Short() || !*testExternal {
-		t.Skip("avoid external network")
-	}
-	if !supportsIPv4 || !*testIPv4 {
-		t.Skip("IPv4 is required")
+		t.Skip("skipping test to avoid external network")
 	}
 
-	for _, tt := range lookupGoogleHostTests {
-		addrs, err := LookupHost(tt.name)
-		if err != nil {
-			t.Fatal(err)
-		}
-		if len(addrs) == 0 {
-			t.Error("got no record")
-		}
-		for _, addr := range addrs {
-			if ParseIP(addr) == nil {
-				t.Errorf("got %q; want a literal IP address", addr)
-			}
+	addrs, err := LookupHost("google.com")
+	if err != nil {
+		t.Fatal(err)
+	}
+	if len(addrs) == 0 {
+		t.Error("got no record")
+	}
+	for _, addr := range addrs {
+		if ParseIP(addr) == nil {
+			t.Errorf("got %q; want a literal ip address", addr)
 		}
 	}
 }
 
-var lookupGoogleIPTests = []struct {
-	name string
-}{
-	{"google.com"},
-	{"google.com."},
-}
-
 func TestLookupGoogleIP(t *testing.T) {
 	if testing.Short() || !*testExternal {
-		t.Skip("avoid external network")
-	}
-	if !supportsIPv4 || !*testIPv4 {
-		t.Skip("IPv4 is required")
+		t.Skip("skipping test to avoid external network")
 	}
 
-	for _, tt := range lookupGoogleIPTests {
-		ips, err := LookupIP(tt.name)
-		if err != nil {
-			t.Fatal(err)
-		}
-		if len(ips) == 0 {
-			t.Error("got no record")
-		}
-		for _, ip := range ips {
-			if ip.To4() == nil && ip.To16() == nil {
-				t.Errorf("got %v; want an IP address", ip)
-			}
+	ips, err := LookupIP("google.com")
+	if err != nil {
+		t.Fatal(err)
+	}
+	if len(ips) == 0 {
+		t.Error("got no record")
+	}
+	for _, ip := range ips {
+		if ip.To4() == nil && ip.To16() == nil {
+			t.Errorf("got %v; want an ip address", ip)
 		}
 	}
 }
@@ -332,172 +229,3 @@ func TestReverseAddress(t *testing.T) {
 		}
 	}
 }
-
-func TestLookupIPDeadline(t *testing.T) {
-	if !*testDNSFlood {
-		t.Skip("test disabled; use -dnsflood to enable")
-	}
-
-	const N = 5000
-	const timeout = 3 * time.Second
-	c := make(chan error, 2*N)
-	for i := 0; i < N; i++ {
-		name := fmt.Sprintf("%d.net-test.golang.org", i)
-		go func() {
-			_, err := lookupIPDeadline(name, time.Now().Add(timeout/2))
-			c <- err
-		}()
-		go func() {
-			_, err := lookupIPDeadline(name, time.Now().Add(timeout))
-			c <- err
-		}()
-	}
-	qstats := struct {
-		succeeded, failed         int
-		timeout, temporary, other int
-		unknown                   int
-	}{}
-	deadline := time.After(timeout + time.Second)
-	for i := 0; i < 2*N; i++ {
-		select {
-		case <-deadline:
-			t.Fatal("deadline exceeded")
-		case err := <-c:
-			switch err := err.(type) {
-			case nil:
-				qstats.succeeded++
-			case Error:
-				qstats.failed++
-				if err.Timeout() {
-					qstats.timeout++
-				}
-				if err.Temporary() {
-					qstats.temporary++
-				}
-				if !err.Timeout() && !err.Temporary() {
-					qstats.other++
-				}
-			default:
-				qstats.failed++
-				qstats.unknown++
-			}
-		}
-	}
-
-	// A high volume of DNS queries for sub-domain of golang.org
-	// would be coordinated by authoritative or recursive server,
-	// or stub resolver which implements query-response rate
-	// limitation, so we can expect some query successes and more
-	// failures including timeout, temporary and other here.
-	// As a rule, unknown must not be shown but it might possibly
-	// happen due to issue 4856 for now.
-	t.Logf("%v succeeded, %v failed (%v timeout, %v temporary, %v other, %v unknown)", qstats.succeeded, qstats.failed, qstats.timeout, qstats.temporary, qstats.other, qstats.unknown)
-}
-
-func TestLookupDots(t *testing.T) {
-	if testing.Short() || !*testExternal {
-		t.Skipf("skipping external network test")
-	}
-
-	fixup := forceGoDNS()
-	defer fixup()
-	testDots(t, "go")
-
-	if forceCgoDNS() {
-		testDots(t, "cgo")
-	}
-}
-
-func testDots(t *testing.T, mode string) {
-	names, err := LookupAddr("8.8.8.8") // Google dns server
-	if err != nil {
-		t.Errorf("LookupAddr(8.8.8.8): %v (mode=%v)", err, mode)
-	} else {
-		for _, name := range names {
-			if !strings.HasSuffix(name, ".google.com.") {
-				t.Errorf("LookupAddr(8.8.8.8) = %v, want names ending in .google.com. with trailing dot (mode=%v)", names, mode)
-				break
-			}
-		}
-	}
-
-	cname, err := LookupCNAME("www.mit.edu")
-	if err != nil || !strings.HasSuffix(cname, ".") {
-		t.Errorf("LookupCNAME(www.mit.edu) = %v, %v, want cname ending in . with trailing dot (mode=%v)", cname, err, mode)
-	}
-
-	mxs, err := LookupMX("google.com")
-	if err != nil {
-		t.Errorf("LookupMX(google.com): %v (mode=%v)", err, mode)
-	} else {
-		for _, mx := range mxs {
-			if !strings.HasSuffix(mx.Host, ".google.com.") {
-				t.Errorf("LookupMX(google.com) = %v, want names ending in .google.com. with trailing dot (mode=%v)", mxString(mxs), mode)
-				break
-			}
-		}
-	}
-
-	nss, err := LookupNS("google.com")
-	if err != nil {
-		t.Errorf("LookupNS(google.com): %v (mode=%v)", err, mode)
-	} else {
-		for _, ns := range nss {
-			if !strings.HasSuffix(ns.Host, ".google.com.") {
-				t.Errorf("LookupNS(google.com) = %v, want names ending in .google.com. with trailing dot (mode=%v)", nsString(nss), mode)
-				break
-			}
-		}
-	}
-
-	cname, srvs, err := LookupSRV("xmpp-server", "tcp", "google.com")
-	if err != nil {
-		t.Errorf("LookupSRV(xmpp-server, tcp, google.com): %v (mode=%v)", err, mode)
-	} else {
-		if !strings.HasSuffix(cname, ".google.com.") {
-			t.Errorf("LookupSRV(xmpp-server, tcp, google.com) returned cname=%v, want name ending in .google.com. with trailing dot (mode=%v)", cname, mode)
-		}
-		for _, srv := range srvs {
-			if !strings.HasSuffix(srv.Target, ".google.com.") {
-				t.Errorf("LookupSRV(xmpp-server, tcp, google.com) returned addrs=%v, want names ending in .google.com. with trailing dot (mode=%v)", srvString(srvs), mode)
-				break
-			}
-		}
-	}
-}
-
-func mxString(mxs []*MX) string {
-	var buf bytes.Buffer
-	sep := ""
-	fmt.Fprintf(&buf, "[")
-	for _, mx := range mxs {
-		fmt.Fprintf(&buf, "%s%s:%d", sep, mx.Host, mx.Pref)
-		sep = " "
-	}
-	fmt.Fprintf(&buf, "]")
-	return buf.String()
-}
-
-func nsString(nss []*NS) string {
-	var buf bytes.Buffer
-	sep := ""
-	fmt.Fprintf(&buf, "[")
-	for _, ns := range nss {
-		fmt.Fprintf(&buf, "%s%s", sep, ns.Host)
-		sep = " "
-	}
-	fmt.Fprintf(&buf, "]")
-	return buf.String()
-}
-
-func srvString(srvs []*SRV) string {
-	var buf bytes.Buffer
-	sep := ""
-	fmt.Fprintf(&buf, "[")
-	for _, srv := range srvs {
-		fmt.Fprintf(&buf, "%s%s:%d:%d:%d", sep, srv.Target, srv.Port, srv.Priority, srv.Weight)
-		sep = " "
-	}
-	fmt.Fprintf(&buf, "]")
-	return buf.String()
-}
diff --git a/src/net/lookup_unix.go b/src/net/lookup_unix.go
index a64da8b..a545784 100644
--- a/src/net/lookup_unix.go
+++ b/src/net/lookup_unix.go
@@ -6,7 +6,10 @@
 
 package net
 
-import "sync"
+import (
+	"errors"
+	"sync"
+)
 
 var onceReadProtocols sync.Once
 
@@ -40,120 +43,126 @@ func readProtocols() {
 
 // lookupProtocol looks up IP protocol name in /etc/protocols and
 // returns correspondent protocol number.
-func lookupProtocol(name string) (int, error) {
+func lookupProtocol(name string) (proto int, err error) {
 	onceReadProtocols.Do(readProtocols)
 	proto, found := protocols[name]
 	if !found {
-		return 0, &AddrError{Err: "unknown IP protocol specified", Addr: name}
+		return 0, errors.New("unknown IP protocol specified: " + name)
 	}
-	return proto, nil
+	return
 }
 
 func lookupHost(host string) (addrs []string, err error) {
-	order := systemConf().hostLookupOrder(host)
-	if order == hostLookupCgo {
-		if addrs, err, ok := cgoLookupHost(host); ok {
-			return addrs, err
-		}
-		// cgo not available (or netgo); fall back to Go's DNS resolver
-		order = hostLookupFilesDNS
+	addrs, err, ok := cgoLookupHost(host)
+	if !ok {
+		addrs, err = goLookupHost(host)
 	}
-	return goLookupHostOrder(host, order)
+	return
 }
 
-func lookupIP(host string) (addrs []IPAddr, err error) {
-	order := systemConf().hostLookupOrder(host)
-	if order == hostLookupCgo {
-		if addrs, err, ok := cgoLookupIP(host); ok {
-			return addrs, err
-		}
-		// cgo not available (or netgo); fall back to Go's DNS resolver
-		order = hostLookupFilesDNS
+func lookupIP(host string) (addrs []IP, err error) {
+	addrs, err, ok := cgoLookupIP(host)
+	if !ok {
+		addrs, err = goLookupIP(host)
 	}
-	return goLookupIPOrder(host, order)
+	return
 }
 
-func lookupPort(network, service string) (int, error) {
-	if systemConf().canUseCgo() {
-		if port, err, ok := cgoLookupPort(network, service); ok {
-			return port, err
-		}
+func lookupPort(network, service string) (port int, err error) {
+	port, err, ok := cgoLookupPort(network, service)
+	if !ok {
+		port, err = goLookupPort(network, service)
 	}
-	return goLookupPort(network, service)
+	return
 }
 
-func lookupCNAME(name string) (string, error) {
-	if systemConf().canUseCgo() {
-		if cname, err, ok := cgoLookupCNAME(name); ok {
-			return cname, err
-		}
+func lookupCNAME(name string) (cname string, err error) {
+	cname, err, ok := cgoLookupCNAME(name)
+	if !ok {
+		cname, err = goLookupCNAME(name)
 	}
-	return goLookupCNAME(name)
+	return
 }
 
-func lookupSRV(service, proto, name string) (string, []*SRV, error) {
+func lookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) {
 	var target string
 	if service == "" && proto == "" {
 		target = name
 	} else {
 		target = "_" + service + "._" + proto + "." + name
 	}
-	cname, rrs, err := lookup(target, dnsTypeSRV)
+	var records []dnsRR
+	cname, records, err = lookup(target, dnsTypeSRV)
 	if err != nil {
-		return "", nil, err
+		return
 	}
-	srvs := make([]*SRV, len(rrs))
-	for i, rr := range rrs {
-		rr := rr.(*dnsRR_SRV)
-		srvs[i] = &SRV{Target: rr.Target, Port: rr.Port, Priority: rr.Priority, Weight: rr.Weight}
+	addrs = make([]*SRV, len(records))
+	for i, rr := range records {
+		r := rr.(*dnsRR_SRV)
+		addrs[i] = &SRV{r.Target, r.Port, r.Priority, r.Weight}
 	}
-	byPriorityWeight(srvs).sort()
-	return cname, srvs, nil
+	byPriorityWeight(addrs).sort()
+	return
 }
 
-func lookupMX(name string) ([]*MX, error) {
-	_, rrs, err := lookup(name, dnsTypeMX)
+func lookupMX(name string) (mx []*MX, err error) {
+	_, records, err := lookup(name, dnsTypeMX)
 	if err != nil {
-		return nil, err
+		return
 	}
-	mxs := make([]*MX, len(rrs))
-	for i, rr := range rrs {
-		rr := rr.(*dnsRR_MX)
-		mxs[i] = &MX{Host: rr.Mx, Pref: rr.Pref}
+	mx = make([]*MX, len(records))
+	for i, rr := range records {
+		r := rr.(*dnsRR_MX)
+		mx[i] = &MX{r.Mx, r.Pref}
 	}
-	byPref(mxs).sort()
-	return mxs, nil
+	byPref(mx).sort()
+	return
 }
 
-func lookupNS(name string) ([]*NS, error) {
-	_, rrs, err := lookup(name, dnsTypeNS)
+func lookupNS(name string) (ns []*NS, err error) {
+	_, records, err := lookup(name, dnsTypeNS)
 	if err != nil {
-		return nil, err
+		return
 	}
-	nss := make([]*NS, len(rrs))
-	for i, rr := range rrs {
-		nss[i] = &NS{Host: rr.(*dnsRR_NS).Ns}
+	ns = make([]*NS, len(records))
+	for i, r := range records {
+		r := r.(*dnsRR_NS)
+		ns[i] = &NS{r.Ns}
 	}
-	return nss, nil
+	return
 }
 
-func lookupTXT(name string) ([]string, error) {
-	_, rrs, err := lookup(name, dnsTypeTXT)
+func lookupTXT(name string) (txt []string, err error) {
+	_, records, err := lookup(name, dnsTypeTXT)
 	if err != nil {
-		return nil, err
+		return
 	}
-	txts := make([]string, len(rrs))
-	for i, rr := range rrs {
-		txts[i] = rr.(*dnsRR_TXT).Txt
+	txt = make([]string, len(records))
+	for i, r := range records {
+		txt[i] = r.(*dnsRR_TXT).Txt
 	}
-	return txts, nil
+	return
 }
 
-func lookupAddr(addr string) ([]string, error) {
-	if systemConf().canUseCgo() {
-		if ptrs, err, ok := cgoLookupPTR(addr); ok {
-			return ptrs, err
-		}
+func lookupAddr(addr string) (name []string, err error) {
+	name = lookupStaticAddr(addr)
+	if len(name) > 0 {
+		return
+	}
+	var arpa string
+	arpa, err = reverseaddr(addr)
+	if err != nil {
+		return
+	}
+	var records []dnsRR
+	_, records, err = lookup(arpa, dnsTypePTR)
+	if err != nil {
+		return
+	}
+	name = make([]string, len(records))
+	for i := range records {
+		r := records[i].(*dnsRR_PTR)
+		name[i] = r.Ptr
 	}
-	return goLookupPTR(addr)
+	return
 }
diff --git a/src/net/lookup_windows.go b/src/net/lookup_windows.go
index 1b6d392..6a925b0 100644
--- a/src/net/lookup_windows.go
+++ b/src/net/lookup_windows.go
@@ -19,13 +19,13 @@ var (
 func getprotobyname(name string) (proto int, err error) {
 	p, err := syscall.GetProtoByName(name)
 	if err != nil {
-		return 0, os.NewSyscallError("getorotobyname", err)
+		return 0, os.NewSyscallError("GetProtoByName", err)
 	}
 	return int(p.Proto), nil
 }
 
 // lookupProtocol looks up IP protocol name and returns correspondent protocol number.
-func lookupProtocol(name string) (int, error) {
+func lookupProtocol(name string) (proto int, err error) {
 	// GetProtoByName return value is stored in thread local storage.
 	// Start new os thread before the call to prevent races.
 	type result struct {
@@ -46,48 +46,47 @@ func lookupProtocol(name string) (int, error) {
 		if proto, ok := protocols[name]; ok {
 			return proto, nil
 		}
-		r.err = &DNSError{Err: r.err.Error(), Name: name}
 	}
 	return r.proto, r.err
 }
 
-func lookupHost(name string) ([]string, error) {
+func lookupHost(name string) (addrs []string, err error) {
 	ips, err := LookupIP(name)
 	if err != nil {
-		return nil, err
+		return
 	}
-	addrs := make([]string, 0, len(ips))
+	addrs = make([]string, 0, len(ips))
 	for _, ip := range ips {
 		addrs = append(addrs, ip.String())
 	}
-	return addrs, nil
+	return
 }
 
-func gethostbyname(name string) (addrs []IPAddr, err error) {
+func gethostbyname(name string) (addrs []IP, err error) {
 	// caller already acquired thread
 	h, err := syscall.GetHostByName(name)
 	if err != nil {
-		return nil, os.NewSyscallError("gethostbyname", err)
+		return nil, os.NewSyscallError("GetHostByName", err)
 	}
 	switch h.AddrType {
 	case syscall.AF_INET:
 		i := 0
-		addrs = make([]IPAddr, 100) // plenty of room to grow
+		addrs = make([]IP, 100) // plenty of room to grow
 		for p := (*[100](*[4]byte))(unsafe.Pointer(h.AddrList)); i < cap(addrs) && p[i] != nil; i++ {
-			addrs[i] = IPAddr{IP: IPv4(p[i][0], p[i][1], p[i][2], p[i][3])}
+			addrs[i] = IPv4(p[i][0], p[i][1], p[i][2], p[i][3])
 		}
 		addrs = addrs[0:i]
 	default: // TODO(vcc): Implement non IPv4 address lookups.
-		return nil, syscall.EWINDOWS
+		return nil, os.NewSyscallError("LookupIP", syscall.EWINDOWS)
 	}
 	return addrs, nil
 }
 
-func oldLookupIP(name string) ([]IPAddr, error) {
+func oldLookupIP(name string) (addrs []IP, err error) {
 	// GetHostByName return value is stored in thread local storage.
 	// Start new os thread before the call to prevent races.
 	type result struct {
-		addrs []IPAddr
+		addrs []IP
 		err   error
 	}
 	ch := make(chan result)
@@ -100,13 +99,10 @@ func oldLookupIP(name string) ([]IPAddr, error) {
 		ch <- result{addrs: addrs, err: err}
 	}()
 	r := <-ch
-	if r.err != nil {
-		r.err = &DNSError{Err: r.err.Error(), Name: name}
-	}
 	return r.addrs, r.err
 }
 
-func newLookupIP(name string) ([]IPAddr, error) {
+func newLookupIP(name string) (addrs []IP, err error) {
 	acquireThread()
 	defer releaseThread()
 	hints := syscall.AddrinfoW{
@@ -117,28 +113,27 @@ func newLookupIP(name string) ([]IPAddr, error) {
 	var result *syscall.AddrinfoW
 	e := syscall.GetAddrInfoW(syscall.StringToUTF16Ptr(name), nil, &hints, &result)
 	if e != nil {
-		return nil, &DNSError{Err: os.NewSyscallError("getaddrinfow", e).Error(), Name: name}
+		return nil, os.NewSyscallError("GetAddrInfoW", e)
 	}
 	defer syscall.FreeAddrInfoW(result)
-	addrs := make([]IPAddr, 0, 5)
+	addrs = make([]IP, 0, 5)
 	for ; result != nil; result = result.Next {
 		addr := unsafe.Pointer(result.Addr)
 		switch result.Family {
 		case syscall.AF_INET:
 			a := (*syscall.RawSockaddrInet4)(addr).Addr
-			addrs = append(addrs, IPAddr{IP: IPv4(a[0], a[1], a[2], a[3])})
+			addrs = append(addrs, IPv4(a[0], a[1], a[2], a[3]))
 		case syscall.AF_INET6:
 			a := (*syscall.RawSockaddrInet6)(addr).Addr
-			zone := zoneToString(int((*syscall.RawSockaddrInet6)(addr).Scope_id))
-			addrs = append(addrs, IPAddr{IP: IP{a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15]}, Zone: zone})
+			addrs = append(addrs, IP{a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15]})
 		default:
-			return nil, &DNSError{Err: syscall.EWINDOWS.Error(), Name: name}
+			return nil, os.NewSyscallError("LookupIP", syscall.EWINDOWS)
 		}
 	}
 	return addrs, nil
 }
 
-func getservbyname(network, service string) (int, error) {
+func getservbyname(network, service string) (port int, err error) {
 	acquireThread()
 	defer releaseThread()
 	switch network {
@@ -149,12 +144,12 @@ func getservbyname(network, service string) (int, error) {
 	}
 	s, err := syscall.GetServByName(service, network)
 	if err != nil {
-		return 0, os.NewSyscallError("getservbyname", err)
+		return 0, os.NewSyscallError("GetServByName", err)
 	}
 	return int(syscall.Ntohs(s.Port)), nil
 }
 
-func oldLookupPort(network, service string) (int, error) {
+func oldLookupPort(network, service string) (port int, err error) {
 	// GetServByName return value is stored in thread local storage.
 	// Start new os thread before the call to prevent races.
 	type result struct {
@@ -171,13 +166,10 @@ func oldLookupPort(network, service string) (int, error) {
 		ch <- result{port: port, err: err}
 	}()
 	r := <-ch
-	if r.err != nil {
-		r.err = &DNSError{Err: r.err.Error(), Name: network + "/" + service}
-	}
 	return r.port, r.err
 }
 
-func newLookupPort(network, service string) (int, error) {
+func newLookupPort(network, service string) (port int, err error) {
 	acquireThread()
 	defer releaseThread()
 	var stype int32
@@ -195,11 +187,11 @@ func newLookupPort(network, service string) (int, error) {
 	var result *syscall.AddrinfoW
 	e := syscall.GetAddrInfoW(nil, syscall.StringToUTF16Ptr(service), &hints, &result)
 	if e != nil {
-		return 0, &DNSError{Err: os.NewSyscallError("getaddrinfow", e).Error(), Name: network + "/" + service}
+		return 0, os.NewSyscallError("GetAddrInfoW", e)
 	}
 	defer syscall.FreeAddrInfoW(result)
 	if result == nil {
-		return 0, &DNSError{Err: syscall.EINVAL.Error(), Name: network + "/" + service}
+		return 0, os.NewSyscallError("LookupPort", syscall.EINVAL)
 	}
 	addr := unsafe.Pointer(result.Addr)
 	switch result.Family {
@@ -210,10 +202,10 @@ func newLookupPort(network, service string) (int, error) {
 		a := (*syscall.RawSockaddrInet6)(addr)
 		return int(syscall.Ntohs(a.Port)), nil
 	}
-	return 0, &DNSError{Err: syscall.EINVAL.Error(), Name: network + "/" + service}
+	return 0, os.NewSyscallError("LookupPort", syscall.EINVAL)
 }
 
-func lookupCNAME(name string) (string, error) {
+func lookupCNAME(name string) (cname string, err error) {
 	acquireThread()
 	defer releaseThread()
 	var r *syscall.DNSRecord
@@ -227,16 +219,16 @@ func lookupCNAME(name string) (string, error) {
 		return name, nil
 	}
 	if e != nil {
-		return "", &DNSError{Err: os.NewSyscallError("dnsquery", e).Error(), Name: name}
+		return "", os.NewSyscallError("LookupCNAME", e)
 	}
 	defer syscall.DnsRecordListFree(r, 1)
 
 	resolved := resolveCNAME(syscall.StringToUTF16Ptr(name), r)
-	cname := syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(resolved))[:]) + "."
-	return cname, nil
+	cname = syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(resolved))[:]) + "."
+	return
 }
 
-func lookupSRV(service, proto, name string) (string, []*SRV, error) {
+func lookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) {
 	acquireThread()
 	defer releaseThread()
 	var target string
@@ -248,78 +240,78 @@ func lookupSRV(service, proto, name string) (string, []*SRV, error) {
 	var r *syscall.DNSRecord
 	e := syscall.DnsQuery(target, syscall.DNS_TYPE_SRV, 0, nil, &r, nil)
 	if e != nil {
-		return "", nil, &DNSError{Err: os.NewSyscallError("dnsquery", e).Error(), Name: target}
+		return "", nil, os.NewSyscallError("LookupSRV", e)
 	}
 	defer syscall.DnsRecordListFree(r, 1)
 
-	srvs := make([]*SRV, 0, 10)
+	addrs = make([]*SRV, 0, 10)
 	for _, p := range validRecs(r, syscall.DNS_TYPE_SRV, target) {
 		v := (*syscall.DNSSRVData)(unsafe.Pointer(&p.Data[0]))
-		srvs = append(srvs, &SRV{syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.Target))[:]), v.Port, v.Priority, v.Weight})
+		addrs = append(addrs, &SRV{syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.Target))[:]), v.Port, v.Priority, v.Weight})
 	}
-	byPriorityWeight(srvs).sort()
-	return name, srvs, nil
+	byPriorityWeight(addrs).sort()
+	return name, addrs, nil
 }
 
-func lookupMX(name string) ([]*MX, error) {
+func lookupMX(name string) (mx []*MX, err error) {
 	acquireThread()
 	defer releaseThread()
 	var r *syscall.DNSRecord
 	e := syscall.DnsQuery(name, syscall.DNS_TYPE_MX, 0, nil, &r, nil)
 	if e != nil {
-		return nil, &DNSError{Err: os.NewSyscallError("dnsquery", e).Error(), Name: name}
+		return nil, os.NewSyscallError("LookupMX", e)
 	}
 	defer syscall.DnsRecordListFree(r, 1)
 
-	mxs := make([]*MX, 0, 10)
+	mx = make([]*MX, 0, 10)
 	for _, p := range validRecs(r, syscall.DNS_TYPE_MX, name) {
 		v := (*syscall.DNSMXData)(unsafe.Pointer(&p.Data[0]))
-		mxs = append(mxs, &MX{syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.NameExchange))[:]) + ".", v.Preference})
+		mx = append(mx, &MX{syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.NameExchange))[:]) + ".", v.Preference})
 	}
-	byPref(mxs).sort()
-	return mxs, nil
+	byPref(mx).sort()
+	return mx, nil
 }
 
-func lookupNS(name string) ([]*NS, error) {
+func lookupNS(name string) (ns []*NS, err error) {
 	acquireThread()
 	defer releaseThread()
 	var r *syscall.DNSRecord
 	e := syscall.DnsQuery(name, syscall.DNS_TYPE_NS, 0, nil, &r, nil)
 	if e != nil {
-		return nil, &DNSError{Err: os.NewSyscallError("dnsquery", e).Error(), Name: name}
+		return nil, os.NewSyscallError("LookupNS", e)
 	}
 	defer syscall.DnsRecordListFree(r, 1)
 
-	nss := make([]*NS, 0, 10)
+	ns = make([]*NS, 0, 10)
 	for _, p := range validRecs(r, syscall.DNS_TYPE_NS, name) {
 		v := (*syscall.DNSPTRData)(unsafe.Pointer(&p.Data[0]))
-		nss = append(nss, &NS{syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.Host))[:]) + "."})
+		ns = append(ns, &NS{syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.Host))[:]) + "."})
 	}
-	return nss, nil
+	return ns, nil
 }
 
-func lookupTXT(name string) ([]string, error) {
+func lookupTXT(name string) (txt []string, err error) {
 	acquireThread()
 	defer releaseThread()
 	var r *syscall.DNSRecord
 	e := syscall.DnsQuery(name, syscall.DNS_TYPE_TEXT, 0, nil, &r, nil)
 	if e != nil {
-		return nil, &DNSError{Err: os.NewSyscallError("dnsquery", e).Error(), Name: name}
+		return nil, os.NewSyscallError("LookupTXT", e)
 	}
 	defer syscall.DnsRecordListFree(r, 1)
 
-	txts := make([]string, 0, 10)
+	txt = make([]string, 0, 10)
 	for _, p := range validRecs(r, syscall.DNS_TYPE_TEXT, name) {
 		d := (*syscall.DNSTXTData)(unsafe.Pointer(&p.Data[0]))
 		for _, v := range (*[1 << 10]*uint16)(unsafe.Pointer(&(d.StringArray[0])))[:d.StringCount] {
 			s := syscall.UTF16ToString((*[1 << 20]uint16)(unsafe.Pointer(v))[:])
-			txts = append(txts, s)
+			txt = append(txt, s)
 		}
 	}
-	return txts, nil
+	return
 }
 
-func lookupAddr(addr string) ([]string, error) {
+func lookupAddr(addr string) (name []string, err error) {
 	acquireThread()
 	defer releaseThread()
 	arpa, err := reverseaddr(addr)
@@ -329,16 +321,16 @@ func lookupAddr(addr string) ([]string, error) {
 	var r *syscall.DNSRecord
 	e := syscall.DnsQuery(arpa, syscall.DNS_TYPE_PTR, 0, nil, &r, nil)
 	if e != nil {
-		return nil, &DNSError{Err: os.NewSyscallError("dnsquery", e).Error(), Name: addr}
+		return nil, os.NewSyscallError("LookupAddr", e)
 	}
 	defer syscall.DnsRecordListFree(r, 1)
 
-	ptrs := make([]string, 0, 10)
+	name = make([]string, 0, 10)
 	for _, p := range validRecs(r, syscall.DNS_TYPE_PTR, arpa) {
 		v := (*syscall.DNSPTRData)(unsafe.Pointer(&p.Data[0]))
-		ptrs = append(ptrs, syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.Host))[:]))
+		name = append(name, syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.Host))[:]))
 	}
-	return ptrs, nil
+	return name, nil
 }
 
 const dnsSectionMask = 0x0003
diff --git a/src/net/lookup_windows_test.go b/src/net/lookup_windows_test.go
index 3f64d8c..7495b5b 100644
--- a/src/net/lookup_windows_test.go
+++ b/src/net/lookup_windows_test.go
@@ -26,13 +26,12 @@ func toJson(v interface{}) string {
 
 func TestLookupMX(t *testing.T) {
 	if testing.Short() || !*testExternal {
-		t.Skip("avoid external network")
+		t.Skip("skipping test to avoid external network")
 	}
-
 	for _, server := range nslookupTestServers {
 		mx, err := LookupMX(server)
 		if err != nil {
-			t.Error(err)
+			t.Errorf("failed %s: %s", server, err)
 			continue
 		}
 		if len(mx) == 0 {
@@ -53,9 +52,8 @@ func TestLookupMX(t *testing.T) {
 
 func TestLookupCNAME(t *testing.T) {
 	if testing.Short() || !*testExternal {
-		t.Skip("avoid external network")
+		t.Skip("skipping test to avoid external network")
 	}
-
 	for _, server := range nslookupTestServers {
 		cname, err := LookupCNAME(server)
 		if err != nil {
@@ -78,9 +76,8 @@ func TestLookupCNAME(t *testing.T) {
 
 func TestLookupNS(t *testing.T) {
 	if testing.Short() || !*testExternal {
-		t.Skip("avoid external network")
+		t.Skip("skipping test to avoid external network")
 	}
-
 	for _, server := range nslookupTestServers {
 		ns, err := LookupNS(server)
 		if err != nil {
@@ -106,9 +103,8 @@ func TestLookupNS(t *testing.T) {
 
 func TestLookupTXT(t *testing.T) {
 	if testing.Short() || !*testExternal {
-		t.Skip("avoid external network")
+		t.Skip("skipping test to avoid external network")
 	}
-
 	for _, server := range nslookupTestServers {
 		txt, err := LookupTXT(server)
 		if err != nil {
diff --git a/src/net/mac.go b/src/net/mac.go
index 8594a91..d616b1f 100644
--- a/src/net/mac.go
+++ b/src/net/mac.go
@@ -2,8 +2,12 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+// MAC address manipulations
+
 package net
 
+import "errors"
+
 const hexDigit = "0123456789abcdef"
 
 // A HardwareAddr represents a physical hardware address.
@@ -78,5 +82,5 @@ func ParseMAC(s string) (hw HardwareAddr, err error) {
 	return hw, nil
 
 error:
-	return nil, &AddrError{Err: "invalid MAC address", Addr: s}
+	return nil, errors.New("invalid MAC address: " + s)
 }
diff --git a/src/net/mac_test.go b/src/net/mac_test.go
index 0af0c01..8f9dc66 100644
--- a/src/net/mac_test.go
+++ b/src/net/mac_test.go
@@ -10,7 +10,7 @@ import (
 	"testing"
 )
 
-var parseMACTests = []struct {
+var mactests = []struct {
 	in  string
 	out HardwareAddr
 	err string
@@ -36,18 +36,19 @@ var parseMACTests = []struct {
 	{"0123.4567.89AB.CDEF", HardwareAddr{1, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}, ""},
 }
 
-func TestParseMAC(t *testing.T) {
-	match := func(err error, s string) bool {
-		if s == "" {
-			return err == nil
-		}
-		return err != nil && strings.Contains(err.Error(), s)
+func match(err error, s string) bool {
+	if s == "" {
+		return err == nil
 	}
+	return err != nil && strings.Contains(err.Error(), s)
+}
 
-	for i, tt := range parseMACTests {
+func TestMACParseString(t *testing.T) {
+	for i, tt := range mactests {
 		out, err := ParseMAC(tt.in)
 		if !reflect.DeepEqual(out, tt.out) || !match(err, tt.err) {
-			t.Errorf("ParseMAC(%q) = %v, %v, want %v, %v", tt.in, out, err, tt.out, tt.err)
+			t.Errorf("ParseMAC(%q) = %v, %v, want %v, %v", tt.in, out, err, tt.out,
+				tt.err)
 		}
 		if tt.err == "" {
 			// Verify that serialization works too, and that it round-trips.
diff --git a/src/net/mail/message.go b/src/net/mail/message.go
index 266ac50..19aa888 100644
--- a/src/net/mail/message.go
+++ b/src/net/mail/message.go
@@ -18,14 +18,17 @@ package mail
 import (
 	"bufio"
 	"bytes"
+	"encoding/base64"
 	"errors"
 	"fmt"
 	"io"
+	"io/ioutil"
 	"log"
-	"mime"
 	"net/textproto"
+	"strconv"
 	"strings"
 	"time"
+	"unicode"
 )
 
 var debug = debugT(false)
@@ -138,79 +141,22 @@ type Address struct {
 
 // Parses a single RFC 5322 address, e.g. "Barry Gibbs <bg at example.com>"
 func ParseAddress(address string) (*Address, error) {
-	return (&addrParser{s: address}).parseAddress()
+	return newAddrParser(address).parseAddress()
 }
 
 // ParseAddressList parses the given string as a list of addresses.
 func ParseAddressList(list string) ([]*Address, error) {
-	return (&addrParser{s: list}).parseAddressList()
-}
-
-// An AddressParser is an RFC 5322 address parser.
-type AddressParser struct {
-	// WordDecoder optionally specifies a decoder for RFC 2047 encoded-words.
-	WordDecoder *mime.WordDecoder
-}
-
-// Parse parses a single RFC 5322 address of the
-// form "Gogh Fir <gf at example.com>" or "foo at example.com".
-func (p *AddressParser) Parse(address string) (*Address, error) {
-	return (&addrParser{s: address, dec: p.WordDecoder}).parseAddress()
-}
-
-// ParseList parses the given string as a list of comma-separated addresses
-// of the form "Gogh Fir <gf at example.com>" or "foo at example.com".
-func (p *AddressParser) ParseList(list string) ([]*Address, error) {
-	return (&addrParser{s: list, dec: p.WordDecoder}).parseAddressList()
+	return newAddrParser(list).parseAddressList()
 }
 
 // String formats the address as a valid RFC 5322 address.
 // If the address's name contains non-ASCII characters
 // the name will be rendered according to RFC 2047.
 func (a *Address) String() string {
-
-	// Format address local at domain
-	at := strings.LastIndex(a.Address, "@")
-	var local, domain string
-	if at < 0 {
-		// This is a malformed address ("@" is required in addr-spec);
-		// treat the whole address as local-part.
-		local = a.Address
-	} else {
-		local, domain = a.Address[:at], a.Address[at+1:]
-	}
-
-	// Add quotes if needed
-	// TODO: rendering quoted local part and rendering printable name
-	//       should be merged in helper function.
-	quoteLocal := false
-	for i := 0; i < len(local); i++ {
-		ch := local[i]
-		if isAtext(ch, false) {
-			continue
-		}
-		if ch == '.' {
-			// Dots are okay if they are surrounded by atext.
-			// We only need to check that the previous byte is
-			// not a dot, and this isn't the end of the string.
-			if i > 0 && local[i-1] != '.' && i < len(local)-1 {
-				continue
-			}
-		}
-		quoteLocal = true
-		break
-	}
-	if quoteLocal {
-		local = quoteString(local)
-
-	}
-
-	s := "<" + local + "@" + domain + ">"
-
+	s := "<" + a.Address + ">"
 	if a.Name == "" {
 		return s
 	}
-
 	// If every character is printable ASCII, quoting is simple.
 	allPrintable := true
 	for i := 0; i < len(a.Name); i++ {
@@ -234,12 +180,28 @@ func (a *Address) String() string {
 		return b.String()
 	}
 
-	return mime.QEncoding.Encode("utf-8", a.Name) + " " + s
+	// UTF-8 "Q" encoding
+	b := bytes.NewBufferString("=?utf-8?q?")
+	for i := 0; i < len(a.Name); i++ {
+		switch c := a.Name[i]; {
+		case c == ' ':
+			b.WriteByte('_')
+		case isVchar(c) && c != '=' && c != '?' && c != '_':
+			b.WriteByte(c)
+		default:
+			fmt.Fprintf(b, "=%02X", c)
+		}
+	}
+	b.WriteString("?= ")
+	b.WriteString(s)
+	return b.String()
 }
 
-type addrParser struct {
-	s   string
-	dec *mime.WordDecoder // may be nil
+type addrParser []byte
+
+func newAddrParser(s string) *addrParser {
+	p := addrParser(s)
+	return &p
 }
 
 func (p *addrParser) parseAddressList() ([]*Address, error) {
@@ -265,7 +227,7 @@ func (p *addrParser) parseAddressList() ([]*Address, error) {
 
 // parseAddress parses a single RFC 5322 address at the start of p.
 func (p *addrParser) parseAddress() (addr *Address, err error) {
-	debug.Printf("parseAddress: %q", p.s)
+	debug.Printf("parseAddress: %q", *p)
 	p.skipSpace()
 	if p.empty() {
 		return nil, errors.New("mail: no address")
@@ -284,7 +246,7 @@ func (p *addrParser) parseAddress() (addr *Address, err error) {
 		}, err
 	}
 	debug.Printf("parseAddress: not an addr-spec: %v", err)
-	debug.Printf("parseAddress: state is now %q", p.s)
+	debug.Printf("parseAddress: state is now %q", *p)
 
 	// display-name
 	var displayName string
@@ -318,7 +280,7 @@ func (p *addrParser) parseAddress() (addr *Address, err error) {
 
 // consumeAddrSpec parses a single RFC 5322 addr-spec at the start of p.
 func (p *addrParser) consumeAddrSpec() (spec string, err error) {
-	debug.Printf("consumeAddrSpec: %q", p.s)
+	debug.Printf("consumeAddrSpec: %q", *p)
 
 	orig := *p
 	defer func() {
@@ -340,7 +302,7 @@ func (p *addrParser) consumeAddrSpec() (spec string, err error) {
 	} else {
 		// dot-atom
 		debug.Printf("consumeAddrSpec: parsing dot-atom")
-		localPart, err = p.consumeAtom(true, false)
+		localPart, err = p.consumeAtom(true)
 	}
 	if err != nil {
 		debug.Printf("consumeAddrSpec: failed: %v", err)
@@ -358,7 +320,7 @@ func (p *addrParser) consumeAddrSpec() (spec string, err error) {
 		return "", errors.New("mail: no domain in addr-spec")
 	}
 	// TODO(dsymonds): Handle domain-literal
-	domain, err = p.consumeAtom(true, false)
+	domain, err = p.consumeAtom(true)
 	if err != nil {
 		return "", err
 	}
@@ -368,7 +330,7 @@ func (p *addrParser) consumeAddrSpec() (spec string, err error) {
 
 // consumePhrase parses the RFC 5322 phrase at the start of p.
 func (p *addrParser) consumePhrase() (phrase string, err error) {
-	debug.Printf("consumePhrase: [%s]", p.s)
+	debug.Printf("consumePhrase: [%s]", *p)
 	// phrase = 1*word
 	var words []string
 	for {
@@ -385,11 +347,12 @@ func (p *addrParser) consumePhrase() (phrase string, err error) {
 			// atom
 			// We actually parse dot-atom here to be more permissive
 			// than what RFC 5322 specifies.
-			word, err = p.consumeAtom(true, true)
+			word, err = p.consumeAtom(true)
 		}
 
-		if err == nil {
-			word, err = p.decodeRFC2047Word(word)
+		// RFC 2047 encoded-word starts with =?, ends with ?=, and has two other ?s.
+		if err == nil && strings.HasPrefix(word, "=?") && strings.HasSuffix(word, "?=") && strings.Count(word, "?") == 4 {
+			word, err = decodeRFC2047Word(word)
 		}
 
 		if err != nil {
@@ -417,16 +380,16 @@ Loop:
 		if i >= p.len() {
 			return "", errors.New("mail: unclosed quoted-string")
 		}
-		switch c := p.s[i]; {
+		switch c := (*p)[i]; {
 		case c == '"':
 			break Loop
 		case c == '\\':
 			if i+1 == p.len() {
 				return "", errors.New("mail: unclosed quoted-string")
 			}
-			qsb = append(qsb, p.s[i+1])
+			qsb = append(qsb, (*p)[i+1])
 			i += 2
-		case isQtext(c), c == ' ':
+		case isQtext(c), c == ' ' || c == '\t':
 			// qtext (printable US-ASCII excluding " and \), or
 			// FWS (almost; we're ignoring CRLF)
 			qsb = append(qsb, c)
@@ -435,36 +398,20 @@ Loop:
 			return "", fmt.Errorf("mail: bad character in quoted-string: %q", c)
 		}
 	}
-	p.s = p.s[i+1:]
-	if len(qsb) == 0 {
-		return "", errors.New("mail: empty quoted-string")
-	}
+	*p = (*p)[i+1:]
 	return string(qsb), nil
 }
 
 // consumeAtom parses an RFC 5322 atom at the start of p.
 // If dot is true, consumeAtom parses an RFC 5322 dot-atom instead.
-// If permissive is true, consumeAtom will not fail on
-// leading/trailing/double dots in the atom (see golang.org/issue/4938).
-func (p *addrParser) consumeAtom(dot bool, permissive bool) (atom string, err error) {
+func (p *addrParser) consumeAtom(dot bool) (atom string, err error) {
 	if !isAtext(p.peek(), false) {
 		return "", errors.New("mail: invalid string")
 	}
 	i := 1
-	for ; i < p.len() && isAtext(p.s[i], dot); i++ {
-	}
-	atom, p.s = string(p.s[:i]), p.s[i:]
-	if !permissive {
-		if strings.HasPrefix(atom, ".") {
-			return "", errors.New("mail: leading dot in atom")
-		}
-		if strings.Contains(atom, "..") {
-			return "", errors.New("mail: double dot in atom")
-		}
-		if strings.HasSuffix(atom, ".") {
-			return "", errors.New("mail: trailing dot in atom")
-		}
+	for ; i < p.len() && isAtext((*p)[i], dot); i++ {
 	}
+	atom, *p = string((*p)[:i]), (*p)[i:]
 	return atom, nil
 }
 
@@ -472,17 +419,17 @@ func (p *addrParser) consume(c byte) bool {
 	if p.empty() || p.peek() != c {
 		return false
 	}
-	p.s = p.s[1:]
+	*p = (*p)[1:]
 	return true
 }
 
 // skipSpace skips the leading space and tab characters.
 func (p *addrParser) skipSpace() {
-	p.s = strings.TrimLeft(p.s, " \t")
+	*p = bytes.TrimLeft(*p, " \t")
 }
 
 func (p *addrParser) peek() byte {
-	return p.s[0]
+	return (*p)[0]
 }
 
 func (p *addrParser) empty() bool {
@@ -490,37 +437,87 @@ func (p *addrParser) empty() bool {
 }
 
 func (p *addrParser) len() int {
-	return len(p.s)
+	return len(*p)
 }
 
-func (p *addrParser) decodeRFC2047Word(s string) (string, error) {
-	if p.dec != nil {
-		return p.dec.DecodeHeader(s)
+func decodeRFC2047Word(s string) (string, error) {
+	fields := strings.Split(s, "?")
+	if len(fields) != 5 || fields[0] != "=" || fields[4] != "=" {
+		return "", errors.New("address not RFC 2047 encoded")
+	}
+	charset, enc := strings.ToLower(fields[1]), strings.ToLower(fields[2])
+	if charset != "us-ascii" && charset != "iso-8859-1" && charset != "utf-8" {
+		return "", fmt.Errorf("charset not supported: %q", charset)
 	}
 
-	dec, err := rfc2047Decoder.Decode(s)
-	if err == nil {
-		return dec, nil
+	in := bytes.NewBufferString(fields[3])
+	var r io.Reader
+	switch enc {
+	case "b":
+		r = base64.NewDecoder(base64.StdEncoding, in)
+	case "q":
+		r = qDecoder{r: in}
+	default:
+		return "", fmt.Errorf("RFC 2047 encoding not supported: %q", enc)
 	}
 
-	if _, ok := err.(charsetError); ok {
-		return s, err
+	dec, err := ioutil.ReadAll(r)
+	if err != nil {
+		return "", err
 	}
 
-	// Ignore invalid RFC 2047 encoded-word errors.
-	return s, nil
+	switch charset {
+	case "us-ascii":
+		b := new(bytes.Buffer)
+		for _, c := range dec {
+			if c >= 0x80 {
+				b.WriteRune(unicode.ReplacementChar)
+			} else {
+				b.WriteRune(rune(c))
+			}
+		}
+		return b.String(), nil
+	case "iso-8859-1":
+		b := new(bytes.Buffer)
+		for _, c := range dec {
+			b.WriteRune(rune(c))
+		}
+		return b.String(), nil
+	case "utf-8":
+		return string(dec), nil
+	}
+	panic("unreachable")
 }
 
-var rfc2047Decoder = mime.WordDecoder{
-	CharsetReader: func(charset string, input io.Reader) (io.Reader, error) {
-		return nil, charsetError(charset)
-	},
+type qDecoder struct {
+	r       io.Reader
+	scratch [2]byte
 }
 
-type charsetError string
-
-func (e charsetError) Error() string {
-	return fmt.Sprintf("charset not supported: %q", string(e))
+func (qd qDecoder) Read(p []byte) (n int, err error) {
+	// This method writes at most one byte into p.
+	if len(p) == 0 {
+		return 0, nil
+	}
+	if _, err := qd.r.Read(qd.scratch[:1]); err != nil {
+		return 0, err
+	}
+	switch c := qd.scratch[0]; {
+	case c == '=':
+		if _, err := io.ReadFull(qd.r, qd.scratch[:2]); err != nil {
+			return 0, err
+		}
+		x, err := strconv.ParseInt(string(qd.scratch[:2]), 16, 64)
+		if err != nil {
+			return 0, fmt.Errorf("mail: invalid RFC 2047 encoding: %q", qd.scratch[:2])
+		}
+		p[0] = byte(x)
+	case c == '_':
+		p[0] = ' '
+	default:
+		p[0] = c
+	}
+	return 1, nil
 }
 
 var atextChars = []byte("ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
@@ -528,7 +525,7 @@ var atextChars = []byte("ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
 	"0123456789" +
 	"!#$%&'*+-/=?^_`{|}~")
 
-// isAtext reports whether c is an RFC 5322 atext character.
+// isAtext returns true if c is an RFC 5322 atext character.
 // If dot is true, period is included.
 func isAtext(c byte, dot bool) bool {
 	if dot && c == '.' {
@@ -537,7 +534,7 @@ func isAtext(c byte, dot bool) bool {
 	return bytes.IndexByte(atextChars, c) >= 0
 }
 
-// isQtext reports whether c is an RFC 5322 qtext character.
+// isQtext returns true if c is an RFC 5322 qtext character.
 func isQtext(c byte) bool {
 	// Printable US-ASCII, excluding backslash or quote.
 	if c == '\\' || c == '"' {
@@ -546,30 +543,13 @@ func isQtext(c byte) bool {
 	return '!' <= c && c <= '~'
 }
 
-// quoteString renders a string as a RFC5322 quoted-string.
-func quoteString(s string) string {
-	var buf bytes.Buffer
-	buf.WriteByte('"')
-	for _, c := range s {
-		ch := byte(c)
-		if isQtext(ch) || isWSP(ch) {
-			buf.WriteByte(ch)
-		} else if isVchar(ch) {
-			buf.WriteByte('\\')
-			buf.WriteByte(ch)
-		}
-	}
-	buf.WriteByte('"')
-	return buf.String()
-}
-
-// isVchar reports whether c is an RFC 5322 VCHAR character.
+// isVchar returns true if c is an RFC 5322 VCHAR character.
 func isVchar(c byte) bool {
 	// Visible (printing) characters.
 	return '!' <= c && c <= '~'
 }
 
-// isWSP reports whether c is a WSP (white space).
+// 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/net/mail/message_test.go b/src/net/mail/message_test.go
index 1b42274..6ba48be 100644
--- a/src/net/mail/message_test.go
+++ b/src/net/mail/message_test.go
@@ -6,9 +6,7 @@ package mail
 
 import (
 	"bytes"
-	"io"
 	"io/ioutil"
-	"mime"
 	"reflect"
 	"strings"
 	"testing"
@@ -280,175 +278,6 @@ func TestAddressParsing(t *testing.T) {
 	}
 }
 
-func TestAddressParser(t *testing.T) {
-	tests := []struct {
-		addrsStr string
-		exp      []*Address
-	}{
-		// Bare address
-		{
-			`jdoe at machine.example`,
-			[]*Address{{
-				Address: "jdoe at machine.example",
-			}},
-		},
-		// RFC 5322, Appendix A.1.1
-		{
-			`John Doe <jdoe at machine.example>`,
-			[]*Address{{
-				Name:    "John Doe",
-				Address: "jdoe at machine.example",
-			}},
-		},
-		// RFC 5322, Appendix A.1.2
-		{
-			`"Joe Q. Public" <john.q.public at example.com>`,
-			[]*Address{{
-				Name:    "Joe Q. Public",
-				Address: "john.q.public at example.com",
-			}},
-		},
-		{
-			`Mary Smith <mary at x.test>, jdoe at example.org, Who? <one at y.test>`,
-			[]*Address{
-				{
-					Name:    "Mary Smith",
-					Address: "mary at x.test",
-				},
-				{
-					Address: "jdoe at example.org",
-				},
-				{
-					Name:    "Who?",
-					Address: "one at y.test",
-				},
-			},
-		},
-		{
-			`<boss at nil.test>, "Giant; \"Big\" Box" <sysservices at example.net>`,
-			[]*Address{
-				{
-					Address: "boss at nil.test",
-				},
-				{
-					Name:    `Giant; "Big" Box`,
-					Address: "sysservices at example.net",
-				},
-			},
-		},
-		// RFC 2047 "Q"-encoded ISO-8859-1 address.
-		{
-			`=?iso-8859-1?q?J=F6rg_Doe?= <joerg at example.com>`,
-			[]*Address{
-				{
-					Name:    `Jörg Doe`,
-					Address: "joerg at example.com",
-				},
-			},
-		},
-		// RFC 2047 "Q"-encoded US-ASCII address. Dumb but legal.
-		{
-			`=?us-ascii?q?J=6Frg_Doe?= <joerg at example.com>`,
-			[]*Address{
-				{
-					Name:    `Jorg Doe`,
-					Address: "joerg at example.com",
-				},
-			},
-		},
-		// RFC 2047 "Q"-encoded ISO-8859-15 address.
-		{
-			`=?ISO-8859-15?Q?J=F6rg_Doe?= <joerg at example.com>`,
-			[]*Address{
-				{
-					Name:    `Jörg Doe`,
-					Address: "joerg at example.com",
-				},
-			},
-		},
-		// RFC 2047 "B"-encoded windows-1252 address.
-		{
-			`=?windows-1252?q?Andr=E9?= Pirard <PIRARD at vm1.ulg.ac.be>`,
-			[]*Address{
-				{
-					Name:    `André Pirard`,
-					Address: "PIRARD at vm1.ulg.ac.be",
-				},
-			},
-		},
-		// Custom example of RFC 2047 "B"-encoded ISO-8859-15 address.
-		{
-			`=?ISO-8859-15?B?SvZyZw==?= <joerg at example.com>`,
-			[]*Address{
-				{
-					Name:    `Jörg`,
-					Address: "joerg at example.com",
-				},
-			},
-		},
-		// Custom example of RFC 2047 "B"-encoded UTF-8 address.
-		{
-			`=?UTF-8?B?SsO2cmc=?= <joerg at example.com>`,
-			[]*Address{
-				{
-					Name:    `Jörg`,
-					Address: "joerg at example.com",
-				},
-			},
-		},
-		// Custom example with "." in name. For issue 4938
-		{
-			`Asem H. <noreply at example.com>`,
-			[]*Address{
-				{
-					Name:    `Asem H.`,
-					Address: "noreply at example.com",
-				},
-			},
-		},
-	}
-
-	ap := AddressParser{WordDecoder: &mime.WordDecoder{
-		CharsetReader: func(charset string, input io.Reader) (io.Reader, error) {
-			in, err := ioutil.ReadAll(input)
-			if err != nil {
-				return nil, err
-			}
-
-			switch charset {
-			case "iso-8859-15":
-				in = bytes.Replace(in, []byte("\xf6"), []byte("ö"), -1)
-			case "windows-1252":
-				in = bytes.Replace(in, []byte("\xe9"), []byte("é"), -1)
-			}
-
-			return bytes.NewReader(in), nil
-		},
-	}}
-
-	for _, test := range tests {
-		if len(test.exp) == 1 {
-			addr, err := ap.Parse(test.addrsStr)
-			if err != nil {
-				t.Errorf("Failed parsing (single) %q: %v", test.addrsStr, err)
-				continue
-			}
-			if !reflect.DeepEqual([]*Address{addr}, test.exp) {
-				t.Errorf("Parse (single) of %q: got %+v, want %+v", test.addrsStr, addr, test.exp)
-			}
-		}
-
-		addrs, err := ap.ParseList(test.addrsStr)
-		if err != nil {
-			t.Errorf("Failed parsing (list) %q: %v", test.addrsStr, err)
-			continue
-		}
-		if !reflect.DeepEqual(addrs, test.exp) {
-			t.Errorf("Parse (list) of %q: got %+v, want %+v", test.addrsStr, addrs, test.exp)
-		}
-	}
-}
-
 func TestAddressFormatting(t *testing.T) {
 	tests := []struct {
 		addr *Address
@@ -458,14 +287,6 @@ func TestAddressFormatting(t *testing.T) {
 			&Address{Address: "bob at example.com"},
 			"<bob at example.com>",
 		},
-		{ // quoted local parts: RFC 5322, 3.4.1. and 3.2.4.
-			&Address{Address: `my at idiot@address at example.com`},
-			`<"my at idiot@address"@example.com>`,
-		},
-		{ // quoted local parts
-			&Address{Address: ` @example.com`},
-			`<" "@example.com>`,
-		},
 		{
 			&Address{Name: "Bob", Address: "bob at example.com"},
 			`"Bob" <bob at example.com>`,
@@ -483,14 +304,6 @@ func TestAddressFormatting(t *testing.T) {
 			&Address{Name: "Böb Jacöb", Address: "bob at example.com"},
 			`=?utf-8?q?B=C3=B6b_Jac=C3=B6b?= <bob at example.com>`,
 		},
-		{ // https://golang.org/issue/12098
-			&Address{Name: "Rob", Address: ""},
-			`"Rob" <@>`,
-		},
-		{ // https://golang.org/issue/12098
-			&Address{Name: "Rob", Address: "@"},
-			`"Rob" <@>`,
-		},
 	}
 	for _, test := range tests {
 		s := test.addr.String()
@@ -499,90 +312,3 @@ func TestAddressFormatting(t *testing.T) {
 		}
 	}
 }
-
-// Check if all valid addresses can be parsed, formatted and parsed again
-func TestAddressParsingAndFormatting(t *testing.T) {
-
-	// Should pass
-	tests := []string{
-		`<Bob at example.com>`,
-		`<bob.bob at example.com>`,
-		`<".bob"@example.com>`,
-		`<" "@example.com>`,
-		`<some.mail-with-dash at example.com>`,
-		`<"dot.and space"@example.com>`,
-		`<"very.unusual. at .unusual.com"@example.com>`,
-		`<admin at mailserver1>`,
-		`<postmaster at localhost>`,
-		"<#!$%&'*+-/=?^_`{}|~@example.org>",
-		`<"very.(),:;<>[]\".VERY.\"very@\\ \"very\".unusual"@strange.example.com>`, // escaped quotes
-		`<"()<>[]:,;@\\\"!#$%&'*+-/=?^_{}| ~.a"@example.org>`,                      // escaped backslashes
-		`<"Abc\\@def"@example.com>`,
-		`<"Joe\\Blow"@example.com>`,
-		`<test1/test2=test3 at example.com>`,
-		`<def!xyz%abc at example.com>`,
-		`<_somename at example.com>`,
-		`<joe at uk>`,
-		`<~@example.com>`,
-		`<"..."@test.com>`,
-		`<"john..doe"@example.com>`,
-		`<"john.doe."@example.com>`,
-		`<".john.doe"@example.com>`,
-		`<"."@example.com>`,
-		`<".."@example.com>`,
-		`<"0:"@0>`,
-	}
-
-	for _, test := range tests {
-		addr, err := ParseAddress(test)
-		if err != nil {
-			t.Errorf("Couldn't parse address %s: %s", test, err.Error())
-			continue
-		}
-		str := addr.String()
-		addr, err = ParseAddress(str)
-		if err != nil {
-			t.Errorf("ParseAddr(%q) error: %v", test, err)
-			continue
-		}
-
-		if addr.String() != test {
-			t.Errorf("String() round-trip = %q; want %q", addr, test)
-			continue
-		}
-
-	}
-
-	// Should fail
-	badTests := []string{
-		`<Abc.example.com>`,
-		`<A at b@c at example.com>`,
-		`<a"b(c)d,e:f;g<h>i[j\k]l at example.com>`,
-		`<just"not"right at example.com>`,
-		`<this is"not\allowed at example.com>`,
-		`<this\ still\"not\\allowed at example.com>`,
-		`<john..doe at example.com>`,
-		`<john.doe at example..com>`,
-		`<john.doe at example..com>`,
-		`<john.doe. at example.com>`,
-		`<john.doe. at .example.com>`,
-		`<.john.doe at example.com>`,
-		`<@example.com>`,
-		`<. at example.com>`,
-		`<test at .>`,
-		`< @example.com>`,
-		`<""test""blah""@example.com>`,
-		`<""@0>`,
-		"<\"\t0\"@0>",
-	}
-
-	for _, test := range badTests {
-		_, err := ParseAddress(test)
-		if err == nil {
-			t.Errorf("Should have failed to parse address: %s", test)
-			continue
-		}
-
-	}
-
-}
diff --git a/src/net/mockicmp_test.go b/src/net/mockicmp_test.go
new file mode 100644
index 0000000..e742365
--- /dev/null
+++ b/src/net/mockicmp_test.go
@@ -0,0 +1,116 @@
+// 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 "errors"
+
+const (
+	icmpv4EchoRequest = 8
+	icmpv4EchoReply   = 0
+	icmpv6EchoRequest = 128
+	icmpv6EchoReply   = 129
+)
+
+// icmpMessage represents an ICMP message.
+type icmpMessage struct {
+	Type     int             // type
+	Code     int             // code
+	Checksum int             // checksum
+	Body     icmpMessageBody // body
+}
+
+// icmpMessageBody represents an ICMP message body.
+type icmpMessageBody interface {
+	Len() int
+	Marshal() ([]byte, error)
+}
+
+// Marshal returns the binary enconding of the ICMP echo request or
+// reply message m.
+func (m *icmpMessage) Marshal() ([]byte, error) {
+	b := []byte{byte(m.Type), byte(m.Code), 0, 0}
+	if m.Body != nil && m.Body.Len() != 0 {
+		mb, err := m.Body.Marshal()
+		if err != nil {
+			return nil, err
+		}
+		b = append(b, mb...)
+	}
+	switch m.Type {
+	case icmpv6EchoRequest, icmpv6EchoReply:
+		return b, nil
+	}
+	csumcv := len(b) - 1 // checksum coverage
+	s := uint32(0)
+	for i := 0; i < csumcv; i += 2 {
+		s += uint32(b[i+1])<<8 | uint32(b[i])
+	}
+	if csumcv&1 == 0 {
+		s += uint32(b[csumcv])
+	}
+	s = s>>16 + s&0xffff
+	s = s + s>>16
+	// Place checksum back in header; using ^= avoids the
+	// assumption the checksum bytes are zero.
+	b[2] ^= byte(^s)
+	b[3] ^= byte(^s >> 8)
+	return b, nil
+}
+
+// parseICMPMessage parses b as an ICMP message.
+func parseICMPMessage(b []byte) (*icmpMessage, error) {
+	msglen := len(b)
+	if msglen < 4 {
+		return nil, errors.New("message too short")
+	}
+	m := &icmpMessage{Type: int(b[0]), Code: int(b[1]), Checksum: int(b[2])<<8 | int(b[3])}
+	if msglen > 4 {
+		var err error
+		switch m.Type {
+		case icmpv4EchoRequest, icmpv4EchoReply, icmpv6EchoRequest, icmpv6EchoReply:
+			m.Body, err = parseICMPEcho(b[4:])
+			if err != nil {
+				return nil, err
+			}
+		}
+	}
+	return m, nil
+}
+
+// imcpEcho represenets an ICMP echo request or reply message body.
+type icmpEcho struct {
+	ID   int    // identifier
+	Seq  int    // sequence number
+	Data []byte // data
+}
+
+func (p *icmpEcho) Len() int {
+	if p == nil {
+		return 0
+	}
+	return 4 + len(p.Data)
+}
+
+// Marshal returns the binary enconding of the ICMP echo request or
+// reply message body p.
+func (p *icmpEcho) Marshal() ([]byte, error) {
+	b := make([]byte, 4+len(p.Data))
+	b[0], b[1] = byte(p.ID>>8), byte(p.ID)
+	b[2], b[3] = byte(p.Seq>>8), byte(p.Seq)
+	copy(b[4:], p.Data)
+	return b, nil
+}
+
+// parseICMPEcho parses b as an ICMP echo request or reply message
+// body.
+func parseICMPEcho(b []byte) (*icmpEcho, error) {
+	bodylen := len(b)
+	p := &icmpEcho{ID: int(b[0])<<8 | int(b[1]), Seq: int(b[2])<<8 | int(b[3])}
+	if bodylen > 4 {
+		p.Data = make([]byte, bodylen-4)
+		copy(p.Data, b[4:])
+	}
+	return p, nil
+}
diff --git a/src/net/mockserver_test.go b/src/net/mockserver_test.go
index dd6f4df..68ded5d 100644
--- a/src/net/mockserver_test.go
+++ b/src/net/mockserver_test.go
@@ -4,123 +4,11 @@
 
 package net
 
-import (
-	"errors"
-	"fmt"
-	"io/ioutil"
-	"os"
-	"sync"
-	"testing"
-	"time"
-)
-
-// testUnixAddr uses ioutil.TempFile to get a name that is unique.
-// It also uses /tmp directory in case it is prohibited to create UNIX
-// sockets in TMPDIR.
-func testUnixAddr() string {
-	f, err := ioutil.TempFile("", "go-nettest")
-	if err != nil {
-		panic(err)
-	}
-	addr := f.Name()
-	f.Close()
-	os.Remove(addr)
-	return addr
-}
-
-func newLocalListener(network string) (Listener, error) {
-	switch network {
-	case "tcp", "tcp4", "tcp6":
-		if supportsIPv4 {
-			return Listen("tcp4", "127.0.0.1:0")
-		}
-		if supportsIPv6 {
-			return Listen("tcp6", "[::1]:0")
-		}
-	case "unix", "unixpacket":
-		return Listen(network, testUnixAddr())
-	}
-	return nil, fmt.Errorf("%s is not supported", network)
-}
-
-func newDualStackListener() (lns []*TCPListener, err error) {
-	var args = []struct {
-		network string
-		TCPAddr
-	}{
-		{"tcp4", TCPAddr{IP: IPv4(127, 0, 0, 1)}},
-		{"tcp6", TCPAddr{IP: IPv6loopback}},
-	}
-	for i := 0; i < 64; i++ {
-		var port int
-		var lns []*TCPListener
-		for _, arg := range args {
-			arg.TCPAddr.Port = port
-			ln, err := ListenTCP(arg.network, &arg.TCPAddr)
-			if err != nil {
-				continue
-			}
-			port = ln.Addr().(*TCPAddr).Port
-			lns = append(lns, ln)
-		}
-		if len(lns) != len(args) {
-			for _, ln := range lns {
-				ln.Close()
-			}
-			continue
-		}
-		return lns, nil
-	}
-	return nil, errors.New("no dualstack port available")
-}
-
-type localServer struct {
-	lnmu sync.RWMutex
-	Listener
-	done chan bool // signal that indicates server stopped
-}
-
-func (ls *localServer) buildup(handler func(*localServer, Listener)) error {
-	go func() {
-		handler(ls, ls.Listener)
-		close(ls.done)
-	}()
-	return nil
-}
-
-func (ls *localServer) teardown() error {
-	ls.lnmu.Lock()
-	if ls.Listener != nil {
-		network := ls.Listener.Addr().Network()
-		address := ls.Listener.Addr().String()
-		ls.Listener.Close()
-		<-ls.done
-		ls.Listener = nil
-		switch network {
-		case "unix", "unixpacket":
-			os.Remove(address)
-		}
-	}
-	ls.lnmu.Unlock()
-	return nil
-}
-
-func newLocalServer(network string) (*localServer, error) {
-	ln, err := newLocalListener(network)
-	if err != nil {
-		return nil, err
-	}
-	return &localServer{Listener: ln, done: make(chan bool)}, nil
-}
+import "sync"
 
 type streamListener struct {
-	network, address string
-	Listener
-	done chan bool // signal that indicates server stopped
-}
-
-func (sl *streamListener) newLocalServer() (*localServer, error) {
-	return &localServer{Listener: sl.Listener, done: make(chan bool)}, nil
+	net, addr string
+	ln        Listener
 }
 
 type dualStackServer struct {
@@ -132,12 +20,9 @@ type dualStackServer struct {
 	cs  []Conn // established connections at the passive open side
 }
 
-func (dss *dualStackServer) buildup(handler func(*dualStackServer, Listener)) error {
+func (dss *dualStackServer) buildup(server func(*dualStackServer, Listener)) error {
 	for i := range dss.lns {
-		go func(i int) {
-			handler(dss, dss.lns[i].Listener)
-			close(dss.lns[i].done)
-		}(i)
+		go server(dss, dss.lns[i].ln)
 	}
 	return nil
 }
@@ -149,13 +34,12 @@ func (dss *dualStackServer) putConn(c Conn) error {
 	return nil
 }
 
-func (dss *dualStackServer) teardownNetwork(network string) error {
+func (dss *dualStackServer) teardownNetwork(net string) error {
 	dss.lnmu.Lock()
 	for i := range dss.lns {
-		if network == dss.lns[i].network && dss.lns[i].Listener != nil {
-			dss.lns[i].Listener.Close()
-			<-dss.lns[i].done
-			dss.lns[i].Listener = nil
+		if net == dss.lns[i].net && dss.lns[i].ln != nil {
+			dss.lns[i].ln.Close()
+			dss.lns[i].ln = nil
 		}
 	}
 	dss.lnmu.Unlock()
@@ -165,18 +49,15 @@ func (dss *dualStackServer) teardownNetwork(network string) error {
 func (dss *dualStackServer) teardown() error {
 	dss.lnmu.Lock()
 	for i := range dss.lns {
-		if dss.lns[i].Listener != nil {
-			dss.lns[i].Listener.Close()
-			<-dss.lns[i].done
+		if dss.lns[i].ln != nil {
+			dss.lns[i].ln.Close()
 		}
 	}
-	dss.lns = dss.lns[:0]
 	dss.lnmu.Unlock()
 	dss.cmu.Lock()
 	for _, c := range dss.cs {
 		c.Close()
 	}
-	dss.cs = dss.cs[:0]
 	dss.cmu.Unlock()
 	return nil
 }
@@ -184,333 +65,18 @@ func (dss *dualStackServer) teardown() error {
 func newDualStackServer(lns []streamListener) (*dualStackServer, error) {
 	dss := &dualStackServer{lns: lns, port: "0"}
 	for i := range dss.lns {
-		ln, err := Listen(dss.lns[i].network, JoinHostPort(dss.lns[i].address, dss.port))
+		ln, err := Listen(dss.lns[i].net, dss.lns[i].addr+":"+dss.port)
 		if err != nil {
-			for _, ln := range dss.lns[:i] {
-				ln.Listener.Close()
-			}
+			dss.teardown()
 			return nil, err
 		}
-		dss.lns[i].Listener = ln
-		dss.lns[i].done = make(chan bool)
+		dss.lns[i].ln = ln
 		if dss.port == "0" {
 			if _, dss.port, err = SplitHostPort(ln.Addr().String()); err != nil {
-				for _, ln := range dss.lns {
-					ln.Listener.Close()
-				}
+				dss.teardown()
 				return nil, err
 			}
 		}
 	}
 	return dss, nil
 }
-
-func transponder(ln Listener, ch chan<- error) {
-	defer close(ch)
-
-	switch ln := ln.(type) {
-	case *TCPListener:
-		ln.SetDeadline(time.Now().Add(someTimeout))
-	case *UnixListener:
-		ln.SetDeadline(time.Now().Add(someTimeout))
-	}
-	c, err := ln.Accept()
-	if err != nil {
-		if perr := parseAcceptError(err); perr != nil {
-			ch <- perr
-		}
-		ch <- err
-		return
-	}
-	defer c.Close()
-
-	network := ln.Addr().Network()
-	if c.LocalAddr().Network() != network || c.LocalAddr().Network() != network {
-		ch <- fmt.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))
-
-	b := make([]byte, 256)
-	n, err := c.Read(b)
-	if err != nil {
-		if perr := parseReadError(err); perr != nil {
-			ch <- perr
-		}
-		ch <- err
-		return
-	}
-	if _, err := c.Write(b[:n]); err != nil {
-		if perr := parseWriteError(err); perr != nil {
-			ch <- perr
-		}
-		ch <- err
-		return
-	}
-}
-
-func transceiver(c Conn, wb []byte, ch chan<- error) {
-	defer close(ch)
-
-	c.SetDeadline(time.Now().Add(someTimeout))
-	c.SetReadDeadline(time.Now().Add(someTimeout))
-	c.SetWriteDeadline(time.Now().Add(someTimeout))
-
-	n, err := c.Write(wb)
-	if err != nil {
-		if perr := parseWriteError(err); perr != nil {
-			ch <- perr
-		}
-		ch <- err
-		return
-	}
-	if n != len(wb) {
-		ch <- fmt.Errorf("wrote %d; want %d", n, len(wb))
-	}
-	rb := make([]byte, len(wb))
-	n, err = c.Read(rb)
-	if err != nil {
-		if perr := parseReadError(err); perr != nil {
-			ch <- perr
-		}
-		ch <- err
-		return
-	}
-	if n != len(wb) {
-		ch <- fmt.Errorf("read %d; want %d", n, len(wb))
-	}
-}
-
-func timeoutReceiver(c Conn, d, min, max time.Duration, ch chan<- error) {
-	var err error
-	defer func() { ch <- err }()
-
-	t0 := time.Now()
-	if err = c.SetReadDeadline(time.Now().Add(d)); err != nil {
-		return
-	}
-	b := make([]byte, 256)
-	var n int
-	n, err = c.Read(b)
-	t1 := time.Now()
-	if n != 0 || err == nil || !err.(Error).Timeout() {
-		err = fmt.Errorf("Read did not return (0, timeout): (%d, %v)", n, err)
-		return
-	}
-	if dt := t1.Sub(t0); min > dt || dt > max && !testing.Short() {
-		err = fmt.Errorf("Read took %s; expected %s", dt, d)
-		return
-	}
-}
-
-func timeoutTransmitter(c Conn, d, min, max time.Duration, ch chan<- error) {
-	var err error
-	defer func() { ch <- err }()
-
-	t0 := time.Now()
-	if err = c.SetWriteDeadline(time.Now().Add(d)); err != nil {
-		return
-	}
-	var n int
-	for {
-		n, err = c.Write([]byte("TIMEOUT TRANSMITTER"))
-		if err != nil {
-			break
-		}
-	}
-	t1 := time.Now()
-	if err == nil || !err.(Error).Timeout() {
-		err = fmt.Errorf("Write did not return (any, timeout): (%d, %v)", n, err)
-		return
-	}
-	if dt := t1.Sub(t0); min > dt || dt > max && !testing.Short() {
-		err = fmt.Errorf("Write took %s; expected %s", dt, d)
-		return
-	}
-}
-
-func newLocalPacketListener(network string) (PacketConn, error) {
-	switch network {
-	case "udp", "udp4", "udp6":
-		if supportsIPv4 {
-			return ListenPacket("udp4", "127.0.0.1:0")
-		}
-		if supportsIPv6 {
-			return ListenPacket("udp6", "[::1]:0")
-		}
-	case "unixgram":
-		return ListenPacket(network, testUnixAddr())
-	}
-	return nil, fmt.Errorf("%s is not supported", network)
-}
-
-func newDualStackPacketListener() (cs []*UDPConn, err error) {
-	var args = []struct {
-		network string
-		UDPAddr
-	}{
-		{"udp4", UDPAddr{IP: IPv4(127, 0, 0, 1)}},
-		{"udp6", UDPAddr{IP: IPv6loopback}},
-	}
-	for i := 0; i < 64; i++ {
-		var port int
-		var cs []*UDPConn
-		for _, arg := range args {
-			arg.UDPAddr.Port = port
-			c, err := ListenUDP(arg.network, &arg.UDPAddr)
-			if err != nil {
-				continue
-			}
-			port = c.LocalAddr().(*UDPAddr).Port
-			cs = append(cs, c)
-		}
-		if len(cs) != len(args) {
-			for _, c := range cs {
-				c.Close()
-			}
-			continue
-		}
-		return cs, nil
-	}
-	return nil, errors.New("no dualstack port available")
-}
-
-type localPacketServer struct {
-	pcmu sync.RWMutex
-	PacketConn
-	done chan bool // signal that indicates server stopped
-}
-
-func (ls *localPacketServer) buildup(handler func(*localPacketServer, PacketConn)) error {
-	go func() {
-		handler(ls, ls.PacketConn)
-		close(ls.done)
-	}()
-	return nil
-}
-
-func (ls *localPacketServer) teardown() error {
-	ls.pcmu.Lock()
-	if ls.PacketConn != nil {
-		network := ls.PacketConn.LocalAddr().Network()
-		address := ls.PacketConn.LocalAddr().String()
-		ls.PacketConn.Close()
-		<-ls.done
-		ls.PacketConn = nil
-		switch network {
-		case "unixgram":
-			os.Remove(address)
-		}
-	}
-	ls.pcmu.Unlock()
-	return nil
-}
-
-func newLocalPacketServer(network string) (*localPacketServer, error) {
-	c, err := newLocalPacketListener(network)
-	if err != nil {
-		return nil, err
-	}
-	return &localPacketServer{PacketConn: c, done: make(chan bool)}, nil
-}
-
-type packetListener struct {
-	PacketConn
-}
-
-func (pl *packetListener) newLocalServer() (*localPacketServer, error) {
-	return &localPacketServer{PacketConn: pl.PacketConn, done: make(chan bool)}, nil
-}
-
-func packetTransponder(c PacketConn, ch chan<- error) {
-	defer close(ch)
-
-	c.SetDeadline(time.Now().Add(someTimeout))
-	c.SetReadDeadline(time.Now().Add(someTimeout))
-	c.SetWriteDeadline(time.Now().Add(someTimeout))
-
-	b := make([]byte, 256)
-	n, peer, err := c.ReadFrom(b)
-	if err != nil {
-		if perr := parseReadError(err); perr != nil {
-			ch <- perr
-		}
-		ch <- err
-		return
-	}
-	if peer == nil { // for connected-mode sockets
-		switch c.LocalAddr().Network() {
-		case "udp":
-			peer, err = ResolveUDPAddr("udp", string(b[:n]))
-		case "unixgram":
-			peer, err = ResolveUnixAddr("unixgram", string(b[:n]))
-		}
-		if err != nil {
-			ch <- err
-			return
-		}
-	}
-	if _, err := c.WriteTo(b[:n], peer); err != nil {
-		if perr := parseWriteError(err); perr != nil {
-			ch <- perr
-		}
-		ch <- err
-		return
-	}
-}
-
-func packetTransceiver(c PacketConn, wb []byte, dst Addr, ch chan<- error) {
-	defer close(ch)
-
-	c.SetDeadline(time.Now().Add(someTimeout))
-	c.SetReadDeadline(time.Now().Add(someTimeout))
-	c.SetWriteDeadline(time.Now().Add(someTimeout))
-
-	n, err := c.WriteTo(wb, dst)
-	if err != nil {
-		if perr := parseWriteError(err); perr != nil {
-			ch <- perr
-		}
-		ch <- err
-		return
-	}
-	if n != len(wb) {
-		ch <- fmt.Errorf("wrote %d; want %d", n, len(wb))
-	}
-	rb := make([]byte, len(wb))
-	n, _, err = c.ReadFrom(rb)
-	if err != nil {
-		if perr := parseReadError(err); perr != nil {
-			ch <- perr
-		}
-		ch <- err
-		return
-	}
-	if n != len(wb) {
-		ch <- fmt.Errorf("read %d; want %d", n, len(wb))
-	}
-}
-
-func timeoutPacketReceiver(c PacketConn, d, min, max time.Duration, ch chan<- error) {
-	var err error
-	defer func() { ch <- err }()
-
-	t0 := time.Now()
-	if err = c.SetReadDeadline(time.Now().Add(d)); err != nil {
-		return
-	}
-	b := make([]byte, 256)
-	var n int
-	n, _, err = c.ReadFrom(b)
-	t1 := time.Now()
-	if n != 0 || err == nil || !err.(Error).Timeout() {
-		err = fmt.Errorf("ReadFrom did not return (0, timeout): (%d, %v)", n, err)
-		return
-	}
-	if dt := t1.Sub(t0); min > dt || dt > max && !testing.Short() {
-		err = fmt.Errorf("ReadFrom took %s; expected %s", dt, d)
-		return
-	}
-}
diff --git a/src/net/multicast_test.go b/src/net/multicast_test.go
new file mode 100644
index 0000000..5f253f4
--- /dev/null
+++ b/src/net/multicast_test.go
@@ -0,0 +1,188 @@
+// 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 net
+
+import (
+	"fmt"
+	"os"
+	"runtime"
+	"testing"
+)
+
+var ipv4MulticastListenerTests = []struct {
+	net   string
+	gaddr *UDPAddr // see RFC 4727
+}{
+	{"udp", &UDPAddr{IP: IPv4(224, 0, 0, 254), Port: 12345}},
+
+	{"udp4", &UDPAddr{IP: IPv4(224, 0, 0, 254), Port: 12345}},
+}
+
+// TestIPv4MulticastListener tests both single and double listen to a
+// test listener with same address family, same group address and same
+// port.
+func TestIPv4MulticastListener(t *testing.T) {
+	switch runtime.GOOS {
+	case "android", "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) {
+		for _, c := range cs {
+			if c != nil {
+				c.Close()
+			}
+		}
+	}
+
+	for _, ifi := range []*Interface{loopbackInterface(), nil} {
+		// Note that multicast interface assignment by system
+		// is not recommended because it usually relies on
+		// routing stuff for finding out an appropriate
+		// nexthop containing both network and link layer
+		// adjacencies.
+		if ifi == nil && !*testExternal {
+			continue
+		}
+		for _, tt := range ipv4MulticastListenerTests {
+			var err error
+			cs := make([]*UDPConn, 2)
+			if cs[0], err = ListenMulticastUDP(tt.net, ifi, tt.gaddr); err != nil {
+				t.Fatalf("First ListenMulticastUDP on %v failed: %v", ifi, err)
+			}
+			if err := checkMulticastListener(cs[0], tt.gaddr.IP); err != nil {
+				closer(cs)
+				t.Fatal(err)
+			}
+			if cs[1], err = ListenMulticastUDP(tt.net, ifi, tt.gaddr); err != nil {
+				closer(cs)
+				t.Fatalf("Second ListenMulticastUDP on %v failed: %v", ifi, err)
+			}
+			if err := checkMulticastListener(cs[1], tt.gaddr.IP); err != nil {
+				closer(cs)
+				t.Fatal(err)
+			}
+			closer(cs)
+		}
+	}
+}
+
+var ipv6MulticastListenerTests = []struct {
+	net   string
+	gaddr *UDPAddr // see RFC 4727
+}{
+	{"udp", &UDPAddr{IP: ParseIP("ff01::114"), Port: 12345}},
+	{"udp", &UDPAddr{IP: ParseIP("ff02::114"), Port: 12345}},
+	{"udp", &UDPAddr{IP: ParseIP("ff04::114"), Port: 12345}},
+	{"udp", &UDPAddr{IP: ParseIP("ff05::114"), Port: 12345}},
+	{"udp", &UDPAddr{IP: ParseIP("ff08::114"), Port: 12345}},
+	{"udp", &UDPAddr{IP: ParseIP("ff0e::114"), Port: 12345}},
+
+	{"udp6", &UDPAddr{IP: ParseIP("ff01::114"), Port: 12345}},
+	{"udp6", &UDPAddr{IP: ParseIP("ff02::114"), Port: 12345}},
+	{"udp6", &UDPAddr{IP: ParseIP("ff04::114"), Port: 12345}},
+	{"udp6", &UDPAddr{IP: ParseIP("ff05::114"), Port: 12345}},
+	{"udp6", &UDPAddr{IP: ParseIP("ff08::114"), Port: 12345}},
+	{"udp6", &UDPAddr{IP: ParseIP("ff0e::114"), Port: 12345}},
+}
+
+// TestIPv6MulticastListener tests both single and double listen to a
+// test listener with same address family, same group address and same
+// port.
+func TestIPv6MulticastListener(t *testing.T) {
+	switch runtime.GOOS {
+	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")
+	}
+	if os.Getuid() != 0 {
+		t.Skip("skipping test; must be root")
+	}
+
+	closer := func(cs []*UDPConn) {
+		for _, c := range cs {
+			if c != nil {
+				c.Close()
+			}
+		}
+	}
+
+	for _, ifi := range []*Interface{loopbackInterface(), nil} {
+		// Note that multicast interface assignment by system
+		// is not recommended because it usually relies on
+		// routing stuff for finding out an appropriate
+		// nexthop containing both network and link layer
+		// adjacencies.
+		if ifi == nil && (!*testExternal || !*testIPv6) {
+			continue
+		}
+		for _, tt := range ipv6MulticastListenerTests {
+			var err error
+			cs := make([]*UDPConn, 2)
+			if cs[0], err = ListenMulticastUDP(tt.net, ifi, tt.gaddr); err != nil {
+				t.Fatalf("First ListenMulticastUDP on %v failed: %v", ifi, err)
+			}
+			if err := checkMulticastListener(cs[0], tt.gaddr.IP); err != nil {
+				closer(cs)
+				t.Fatal(err)
+			}
+			if cs[1], err = ListenMulticastUDP(tt.net, ifi, tt.gaddr); err != nil {
+				closer(cs)
+				t.Fatalf("Second ListenMulticastUDP on %v failed: %v", ifi, err)
+			}
+			if err := checkMulticastListener(cs[1], tt.gaddr.IP); err != nil {
+				closer(cs)
+				t.Fatal(err)
+			}
+			closer(cs)
+		}
+	}
+}
+
+func checkMulticastListener(c *UDPConn, ip IP) error {
+	if ok, err := multicastRIBContains(ip); err != nil {
+		return err
+	} else if !ok {
+		return fmt.Errorf("%q not found in multicast RIB", ip.String())
+	}
+	la := c.LocalAddr()
+	if la, ok := la.(*UDPAddr); !ok || la.Port == 0 {
+		return fmt.Errorf("got %v; expected a proper address with non-zero port number", la)
+	}
+	return nil
+}
+
+func multicastRIBContains(ip IP) (bool, error) {
+	switch runtime.GOOS {
+	case "dragonfly", "netbsd", "openbsd", "plan9", "solaris", "windows":
+		return true, nil // not implemented yet
+	case "linux":
+		if runtime.GOARCH == "arm" || runtime.GOARCH == "alpha" {
+			return true, nil // not implemented yet
+		}
+	}
+	ift, err := Interfaces()
+	if err != nil {
+		return false, err
+	}
+	for _, ifi := range ift {
+		ifmat, err := ifi.MulticastAddrs()
+		if err != nil {
+			return false, err
+		}
+		for _, ifma := range ifmat {
+			if ifma.(*IPAddr).IP.Equal(ip) {
+				return true, nil
+			}
+		}
+	}
+	return false, nil
+}
diff --git a/src/net/net.go b/src/net/net.go
index 6e84c3a..cb31af5 100644
--- a/src/net/net.go
+++ b/src/net/net.go
@@ -35,49 +35,12 @@ The Listen function creates servers:
 		}
 		go handleConnection(conn)
 	}
-
-Name Resolution
-
-The method for resolving domain names, whether indirectly with functions like Dial
-or directly with functions like LookupHost and LookupAddr, varies by operating system.
-
-On Unix systems, the resolver has two options for resolving names.
-It can use a pure Go resolver that sends DNS requests directly to the servers
-listed in /etc/resolv.conf, or it can use a cgo-based resolver that calls C
-library routines such as getaddrinfo and getnameinfo.
-
-By default the pure Go resolver is used, because a blocked DNS request consumes
-only a goroutine, while a blocked C call consumes an operating system thread.
-When cgo is available, the cgo-based resolver is used instead under a variety of
-conditions: on systems that do not let programs make direct DNS requests (OS X),
-when the LOCALDOMAIN environment variable is present (even if empty),
-when the RES_OPTIONS or HOSTALIASES environment variable is non-empty,
-when the ASR_CONFIG environment variable is non-empty (OpenBSD only),
-when /etc/resolv.conf or /etc/nsswitch.conf specify the use of features that the
-Go resolver does not implement, and when the name being looked up ends in .local
-or is an mDNS name.
-
-The resolver decision can be overridden by setting the netdns value of the
-GODEBUG environment variable (see package runtime) to go or cgo, as in:
-
-	export GODEBUG=netdns=go    # force pure Go resolver
-	export GODEBUG=netdns=cgo   # force cgo resolver
-
-The decision can also be forced while building the Go source tree
-by setting the netgo or netcgo build tag.
-
-A numeric netdns setting, as in GODEBUG=netdns=1, causes the resolver
-to print debugging information about its decisions.
-To force a particular resolver while also printing debugging information,
-join the two settings by a plus sign, as in GODEBUG=netdns=go+1.
-
-On Plan 9, the resolver always accesses /net/cs and /net/dns.
-
-On Windows, the resolver always uses C library functions, such as GetAddrInfo and DnsQuery.
-
 */
 package net
 
+// TODO(rsc):
+//	support for raw ethernet sockets
+
 import (
 	"errors"
 	"io"
@@ -86,20 +49,6 @@ import (
 	"time"
 )
 
-// netGo and netCgo contain the state of the build tags used
-// to build this binary, and whether cgo is available.
-// conf.go mirrors these into conf for easier testing.
-var (
-	netGo  bool // set true in cgo_stub.go for build tag "netgo" (or no cgo)
-	netCgo bool // set true in conf_netcgo.go for build tag "netcgo"
-)
-
-func init() {
-	sysInit()
-	supportsIPv4 = probeIPv4Stack()
-	supportsIPv6, supportsIPv4map = probeIPv6Stack()
-}
-
 // Addr represents a network end point address.
 type Addr interface {
 	Network() string // name of the network
@@ -169,11 +118,7 @@ func (c *conn) Read(b []byte) (int, error) {
 	if !c.ok() {
 		return 0, syscall.EINVAL
 	}
-	n, err := c.fd.Read(b)
-	if err != nil && err != io.EOF {
-		err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
-	}
-	return n, err
+	return c.fd.Read(b)
 }
 
 // Write implements the Conn Write method.
@@ -181,11 +126,7 @@ func (c *conn) Write(b []byte) (int, error) {
 	if !c.ok() {
 		return 0, syscall.EINVAL
 	}
-	n, err := c.fd.Write(b)
-	if err != nil {
-		err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
-	}
-	return n, err
+	return c.fd.Write(b)
 }
 
 // Close closes the connection.
@@ -193,16 +134,10 @@ func (c *conn) Close() error {
 	if !c.ok() {
 		return syscall.EINVAL
 	}
-	err := c.fd.Close()
-	if err != nil {
-		err = &OpError{Op: "close", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
-	}
-	return err
+	return c.fd.Close()
 }
 
 // LocalAddr returns the local network address.
-// The Addr returned is shared by all invocations of LocalAddr, so
-// do not modify it.
 func (c *conn) LocalAddr() Addr {
 	if !c.ok() {
 		return nil
@@ -211,8 +146,6 @@ func (c *conn) LocalAddr() Addr {
 }
 
 // RemoteAddr returns the remote network address.
-// The Addr returned is shared by all invocations of RemoteAddr, so
-// do not modify it.
 func (c *conn) RemoteAddr() Addr {
 	if !c.ok() {
 		return nil
@@ -225,10 +158,7 @@ func (c *conn) SetDeadline(t time.Time) error {
 	if !c.ok() {
 		return syscall.EINVAL
 	}
-	if err := c.fd.setDeadline(t); err != nil {
-		return &OpError{Op: "set", Net: c.fd.net, Source: nil, Addr: c.fd.laddr, Err: err}
-	}
-	return nil
+	return c.fd.setDeadline(t)
 }
 
 // SetReadDeadline implements the Conn SetReadDeadline method.
@@ -236,10 +166,7 @@ func (c *conn) SetReadDeadline(t time.Time) error {
 	if !c.ok() {
 		return syscall.EINVAL
 	}
-	if err := c.fd.setReadDeadline(t); err != nil {
-		return &OpError{Op: "set", Net: c.fd.net, Source: nil, Addr: c.fd.laddr, Err: err}
-	}
-	return nil
+	return c.fd.setReadDeadline(t)
 }
 
 // SetWriteDeadline implements the Conn SetWriteDeadline method.
@@ -247,10 +174,7 @@ func (c *conn) SetWriteDeadline(t time.Time) error {
 	if !c.ok() {
 		return syscall.EINVAL
 	}
-	if err := c.fd.setWriteDeadline(t); err != nil {
-		return &OpError{Op: "set", Net: c.fd.net, Source: nil, Addr: c.fd.laddr, Err: err}
-	}
-	return nil
+	return c.fd.setWriteDeadline(t)
 }
 
 // SetReadBuffer sets the size of the operating system's
@@ -259,10 +183,7 @@ func (c *conn) SetReadBuffer(bytes int) error {
 	if !c.ok() {
 		return syscall.EINVAL
 	}
-	if err := setReadBuffer(c.fd, bytes); err != nil {
-		return &OpError{Op: "set", Net: c.fd.net, Source: nil, Addr: c.fd.laddr, Err: err}
-	}
-	return nil
+	return setReadBuffer(c.fd, bytes)
 }
 
 // SetWriteBuffer sets the size of the operating system's
@@ -271,10 +192,7 @@ func (c *conn) SetWriteBuffer(bytes int) error {
 	if !c.ok() {
 		return syscall.EINVAL
 	}
-	if err := setWriteBuffer(c.fd, bytes); err != nil {
-		return &OpError{Op: "set", Net: c.fd.net, Source: nil, Addr: c.fd.laddr, Err: err}
-	}
-	return nil
+	return setWriteBuffer(c.fd, bytes)
 }
 
 // File sets the underlying os.File to blocking mode and returns a copy.
@@ -284,12 +202,13 @@ func (c *conn) SetWriteBuffer(bytes int) error {
 // The returned os.File's file descriptor is different from the connection's.
 // Attempting to change properties of the original using this duplicate
 // may or may not have the desired effect.
-func (c *conn) File() (f *os.File, err error) {
-	f, err = c.fd.dup()
-	if err != nil {
-		err = &OpError{Op: "file", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
-	}
-	return
+func (c *conn) File() (f *os.File, err error) { return c.fd.dup() }
+
+// An Error represents a network error.
+type Error interface {
+	error
+	Timeout() bool   // Is the error a timeout?
+	Temporary() bool // Is the error temporary?
 }
 
 // PacketConn is a generic packet-oriented network connection.
@@ -355,13 +274,6 @@ type Listener interface {
 	Addr() Addr
 }
 
-// An Error represents a network error.
-type Error interface {
-	error
-	Timeout() bool   // Is the error a timeout?
-	Temporary() bool // Is the error temporary?
-}
-
 // Various errors contained in OpError.
 var (
 	// For connection setup and write operations.
@@ -369,7 +281,6 @@ var (
 
 	// For both read and write operations.
 	errTimeout          error = &timeoutError{}
-	errCanceled               = errors.New("operation was canceled")
 	errClosing                = errors.New("use of closed network connection")
 	ErrWriteToConnected       = errors.New("use of WriteTo with pre-connected connection")
 )
@@ -386,17 +297,7 @@ type OpError struct {
 	// such as "tcp" or "udp6".
 	Net string
 
-	// For operations involving a remote network connection, like
-	// Dial, Read, or Write, Source is the corresponding local
-	// network address.
-	Source Addr
-
-	// Addr is the network address for which this error occurred.
-	// For local operations, like Listen or SetDeadline, Addr is
-	// the address of the local endpoint being manipulated.
-	// For operations involving a remote network connection, like
-	// Dial, Read, or Write, Addr is the remote address of that
-	// connection.
+	// Addr is the network address on which this error occurred.
 	Addr Addr
 
 	// Err is the error that occurred during the operation.
@@ -411,21 +312,22 @@ func (e *OpError) Error() string {
 	if e.Net != "" {
 		s += " " + e.Net
 	}
-	if e.Source != nil {
-		s += " " + e.Source.String()
-	}
 	if e.Addr != nil {
-		if e.Source != nil {
-			s += "->"
-		} else {
-			s += " "
-		}
-		s += e.Addr.String()
+		s += " " + e.Addr.String()
 	}
 	s += ": " + e.Err.Error()
 	return s
 }
 
+type temporary interface {
+	Temporary() bool
+}
+
+func (e *OpError) Temporary() bool {
+	t, ok := e.Err.(temporary)
+	return ok && t.Temporary()
+}
+
 var noDeadline = time.Time{}
 
 type timeout interface {
@@ -433,45 +335,16 @@ type timeout interface {
 }
 
 func (e *OpError) Timeout() bool {
-	if ne, ok := e.Err.(*os.SyscallError); ok {
-		t, ok := ne.Err.(timeout)
-		return ok && t.Timeout()
-	}
 	t, ok := e.Err.(timeout)
 	return ok && t.Timeout()
 }
 
-type temporary interface {
-	Temporary() bool
-}
-
-func (e *OpError) Temporary() bool {
-	if ne, ok := e.Err.(*os.SyscallError); ok {
-		t, ok := ne.Err.(temporary)
-		return ok && t.Temporary()
-	}
-	t, ok := e.Err.(temporary)
-	return ok && t.Temporary()
-}
-
 type timeoutError struct{}
 
 func (e *timeoutError) Error() string   { return "i/o timeout" }
 func (e *timeoutError) Timeout() bool   { return true }
 func (e *timeoutError) Temporary() bool { return true }
 
-// A ParseError is the error type of literal network address parsers.
-type ParseError struct {
-	// Type is the type of string that was expected, such as
-	// "IP address", "CIDR address".
-	Type string
-
-	// Text is the malformed text string.
-	Text string
-}
-
-func (e *ParseError) Error() string { return "invalid " + e.Type + ": " + e.Text }
-
 type AddrError struct {
 	Err  string
 	Addr string
@@ -488,14 +361,19 @@ func (e *AddrError) Error() string {
 	return s
 }
 
-func (e *AddrError) Timeout() bool   { return false }
-func (e *AddrError) Temporary() bool { return false }
+func (e *AddrError) Temporary() bool {
+	return false
+}
+
+func (e *AddrError) Timeout() bool {
+	return false
+}
 
 type UnknownNetworkError string
 
 func (e UnknownNetworkError) Error() string   { return "unknown network " + string(e) }
-func (e UnknownNetworkError) Timeout() bool   { return false }
 func (e UnknownNetworkError) Temporary() bool { return false }
+func (e UnknownNetworkError) Timeout() bool   { return false }
 
 type InvalidAddrError string
 
@@ -504,49 +382,16 @@ func (e InvalidAddrError) Timeout() bool   { return false }
 func (e InvalidAddrError) Temporary() bool { return false }
 
 // DNSConfigError represents an error reading the machine's DNS configuration.
-// (No longer used; kept for compatibility.)
 type DNSConfigError struct {
 	Err error
 }
 
-func (e *DNSConfigError) Error() string   { return "error reading DNS config: " + e.Err.Error() }
-func (e *DNSConfigError) Timeout() bool   { return false }
-func (e *DNSConfigError) Temporary() bool { return false }
-
-// Various errors contained in DNSError.
-var (
-	errNoSuchHost = errors.New("no such host")
-)
-
-// DNSError represents a DNS lookup error.
-type DNSError struct {
-	Err       string // description of the error
-	Name      string // name looked for
-	Server    string // server used
-	IsTimeout bool   // if true, timed out; not all timeouts set this
-}
-
-func (e *DNSError) Error() string {
-	if e == nil {
-		return "<nil>"
-	}
-	s := "lookup " + e.Name
-	if e.Server != "" {
-		s += " on " + e.Server
-	}
-	s += ": " + e.Err
-	return s
+func (e *DNSConfigError) Error() string {
+	return "error reading DNS config: " + e.Err.Error()
 }
 
-// Timeout reports whether the DNS lookup is known to have timed out.
-// This is not always known; a DNS lookup may fail due to a timeout
-// and return a DNSError for which Timeout returns false.
-func (e *DNSError) Timeout() bool { return e.IsTimeout }
-
-// Temporary reports whether the DNS error is known to be temporary.
-// This is not always known; a DNS lookup may fail due to a temporary
-// error and return a DNSError for which Temporary returns false.
-func (e *DNSError) Temporary() bool { return e.IsTimeout }
+func (e *DNSConfigError) Timeout() bool   { return false }
+func (e *DNSConfigError) Temporary() bool { return false }
 
 type writerOnly struct {
 	io.Writer
@@ -567,6 +412,10 @@ func genericReadFrom(w io.Writer, r io.Reader) (n int64, err error) {
 
 var threadLimit = make(chan struct{}, 500)
 
+// Using send for acquire is fine here because we are not using this
+// to protect any memory. All we care about is the number of goroutines
+// making calls at a time.
+
 func acquireThread() {
 	threadLimit <- struct{}{}
 }
diff --git a/src/net/net_test.go b/src/net/net_test.go
index 3907ce4..bfed4d6 100644
--- a/src/net/net_test.go
+++ b/src/net/net_test.go
@@ -6,251 +6,258 @@ package net
 
 import (
 	"io"
+	"io/ioutil"
 	"os"
 	"runtime"
 	"testing"
+	"time"
 )
 
-func TestCloseRead(t *testing.T) {
-	switch runtime.GOOS {
-	case "nacl", "plan9":
-		t.Skipf("not supported on %s", runtime.GOOS)
+func TestShutdown(t *testing.T) {
+	if runtime.GOOS == "plan9" {
+		t.Skipf("skipping test on %q", runtime.GOOS)
 	}
-
-	for _, network := range []string{"tcp", "unix", "unixpacket"} {
-		if !testableNetwork(network) {
-			t.Logf("skipping %s test", network)
-			continue
+	ln, err := Listen("tcp", "127.0.0.1:0")
+	if err != nil {
+		if ln, err = Listen("tcp6", "[::1]:0"); err != nil {
+			t.Fatalf("ListenTCP on :0: %v", err)
 		}
+	}
 
-		ln, err := newLocalListener(network)
-		if err != nil {
-			t.Fatal(err)
-		}
-		switch network {
-		case "unix", "unixpacket":
-			defer os.Remove(ln.Addr().String())
-		}
+	go func() {
 		defer ln.Close()
-
-		c, err := Dial(ln.Addr().Network(), ln.Addr().String())
+		c, err := ln.Accept()
 		if err != nil {
-			t.Fatal(err)
+			t.Errorf("Accept: %v", err)
+			return
 		}
-		switch network {
-		case "unix", "unixpacket":
-			defer os.Remove(c.LocalAddr().String())
+		var buf [10]byte
+		n, err := c.Read(buf[:])
+		if n != 0 || err != io.EOF {
+			t.Errorf("server Read = %d, %v; want 0, io.EOF", n, err)
+			return
 		}
-		defer c.Close()
+		c.Write([]byte("response"))
+		c.Close()
+	}()
 
-		switch c := c.(type) {
-		case *TCPConn:
-			err = c.CloseRead()
-		case *UnixConn:
-			err = c.CloseRead()
-		}
-		if err != nil {
-			if perr := parseCloseError(err); perr != nil {
-				t.Error(perr)
-			}
-			t.Fatal(err)
-		}
-		var b [1]byte
-		n, err := c.Read(b[:])
-		if n != 0 || err == nil {
-			t.Fatalf("got (%d, %v); want (0, error)", n, err)
-		}
+	c, err := Dial("tcp", ln.Addr().String())
+	if err != nil {
+		t.Fatalf("Dial: %v", err)
+	}
+	defer c.Close()
+
+	err = c.(*TCPConn).CloseWrite()
+	if err != nil {
+		t.Fatalf("CloseWrite: %v", err)
+	}
+	var buf [10]byte
+	n, err := c.Read(buf[:])
+	if err != nil {
+		t.Fatalf("client Read: %d, %v", n, err)
+	}
+	got := string(buf[:n])
+	if got != "response" {
+		t.Errorf("read = %q, want \"response\"", got)
 	}
 }
 
-func TestCloseWrite(t *testing.T) {
+func TestShutdownUnix(t *testing.T) {
 	switch runtime.GOOS {
-	case "nacl", "plan9":
-		t.Skipf("not supported on %s", runtime.GOOS)
+	case "nacl", "plan9", "windows":
+		t.Skipf("skipping test on %q", runtime.GOOS)
 	}
+	f, err := ioutil.TempFile("", "go_net_unixtest")
+	if err != nil {
+		t.Fatalf("TempFile: %s", err)
+	}
+	f.Close()
+	tmpname := f.Name()
+	os.Remove(tmpname)
+	ln, err := Listen("unix", tmpname)
+	if err != nil {
+		t.Fatalf("ListenUnix on %s: %s", tmpname, err)
+	}
+	defer func() {
+		ln.Close()
+		os.Remove(tmpname)
+	}()
 
-	handler := func(ls *localServer, ln Listener) {
+	go func() {
 		c, err := ln.Accept()
 		if err != nil {
-			t.Error(err)
+			t.Errorf("Accept: %v", err)
 			return
 		}
-		defer c.Close()
-
-		var b [1]byte
-		n, err := c.Read(b[:])
+		var buf [10]byte
+		n, err := c.Read(buf[:])
 		if n != 0 || err != io.EOF {
-			t.Errorf("got (%d, %v); want (0, io.EOF)", n, err)
-			return
-		}
-		switch c := c.(type) {
-		case *TCPConn:
-			err = c.CloseWrite()
-		case *UnixConn:
-			err = c.CloseWrite()
-		}
-		if err != nil {
-			if perr := parseCloseError(err); perr != nil {
-				t.Error(perr)
-			}
-			t.Error(err)
-			return
-		}
-		n, err = c.Write(b[:])
-		if err == nil {
-			t.Errorf("got (%d, %v); want (any, error)", n, err)
+			t.Errorf("server Read = %d, %v; want 0, io.EOF", n, err)
 			return
 		}
+		c.Write([]byte("response"))
+		c.Close()
+	}()
+
+	c, err := Dial("unix", tmpname)
+	if err != nil {
+		t.Fatalf("Dial: %v", err)
 	}
+	defer c.Close()
 
-	for _, network := range []string{"tcp", "unix", "unixpacket"} {
-		if !testableNetwork(network) {
-			t.Logf("skipping %s test", network)
-			continue
-		}
+	err = c.(*UnixConn).CloseWrite()
+	if err != nil {
+		t.Fatalf("CloseWrite: %v", err)
+	}
+	var buf [10]byte
+	n, err := c.Read(buf[:])
+	if err != nil {
+		t.Fatalf("client Read: %d, %v", n, err)
+	}
+	got := string(buf[:n])
+	if got != "response" {
+		t.Errorf("read = %q, want \"response\"", got)
+	}
+}
 
-		ls, err := newLocalServer(network)
-		if err != nil {
-			t.Fatal(err)
-		}
-		defer ls.teardown()
-		if err := ls.buildup(handler); err != nil {
-			t.Fatal(err)
-		}
+func TestTCPListenClose(t *testing.T) {
+	ln, err := Listen("tcp", "127.0.0.1:0")
+	if err != nil {
+		t.Fatalf("Listen failed: %v", err)
+	}
 
-		c, err := Dial(ls.Listener.Addr().Network(), ls.Listener.Addr().String())
-		if err != nil {
-			t.Fatal(err)
-		}
-		switch network {
-		case "unix", "unixpacket":
-			defer os.Remove(c.LocalAddr().String())
-		}
-		defer c.Close()
+	done := make(chan bool, 1)
+	go func() {
+		time.Sleep(100 * time.Millisecond)
+		ln.Close()
+	}()
+	go func() {
+		c, err := ln.Accept()
+		if err == nil {
+			c.Close()
+			t.Error("Accept succeeded")
+		} else {
+			t.Logf("Accept timeout error: %s (any error is fine)", err)
+		}
+		done <- true
+	}()
+	select {
+	case <-done:
+	case <-time.After(2 * time.Second):
+		t.Fatal("timeout waiting for TCP close")
+	}
+}
 
-		switch c := c.(type) {
-		case *TCPConn:
-			err = c.CloseWrite()
-		case *UnixConn:
-			err = c.CloseWrite()
-		}
-		if err != nil {
-			if perr := parseCloseError(err); perr != nil {
-				t.Error(perr)
-			}
-			t.Fatal(err)
-		}
-		var b [1]byte
-		n, err := c.Read(b[:])
-		if n != 0 || err != io.EOF {
-			t.Fatalf("got (%d, %v); want (0, io.EOF)", n, err)
-		}
-		n, err = c.Write(b[:])
+func TestUDPListenClose(t *testing.T) {
+	switch runtime.GOOS {
+	case "plan9":
+		t.Skipf("skipping test on %q", runtime.GOOS)
+	}
+	ln, err := ListenPacket("udp", "127.0.0.1:0")
+	if err != nil {
+		t.Fatalf("Listen failed: %v", err)
+	}
+
+	buf := make([]byte, 1000)
+	done := make(chan bool, 1)
+	go func() {
+		time.Sleep(100 * time.Millisecond)
+		ln.Close()
+	}()
+	go func() {
+		_, _, err = ln.ReadFrom(buf)
 		if err == nil {
-			t.Fatalf("got (%d, %v); want (any, error)", n, err)
-		}
+			t.Error("ReadFrom succeeded")
+		} else {
+			t.Logf("ReadFrom timeout error: %s (any error is fine)", err)
+		}
+		done <- true
+	}()
+	select {
+	case <-done:
+	case <-time.After(2 * time.Second):
+		t.Fatal("timeout waiting for UDP close")
 	}
 }
 
-func TestConnClose(t *testing.T) {
-	for _, network := range []string{"tcp", "unix", "unixpacket"} {
-		if !testableNetwork(network) {
-			t.Logf("skipping %s test", network)
-			continue
-		}
+func TestTCPClose(t *testing.T) {
+	switch runtime.GOOS {
+	case "plan9":
+		t.Skipf("skipping test on %q", runtime.GOOS)
+	}
+	l, err := Listen("tcp", "127.0.0.1:0")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer l.Close()
 
-		ln, err := newLocalListener(network)
-		if err != nil {
-			t.Fatal(err)
-		}
-		switch network {
-		case "unix", "unixpacket":
-			defer os.Remove(ln.Addr().String())
-		}
-		defer ln.Close()
+	read := func(r io.Reader) error {
+		var m [1]byte
+		_, err := r.Read(m[:])
+		return err
+	}
 
-		c, err := Dial(ln.Addr().Network(), ln.Addr().String())
+	go func() {
+		c, err := Dial("tcp", l.Addr().String())
 		if err != nil {
-			t.Fatal(err)
-		}
-		switch network {
-		case "unix", "unixpacket":
-			defer os.Remove(c.LocalAddr().String())
+			t.Errorf("Dial: %v", err)
+			return
 		}
-		defer c.Close()
 
-		if err := c.Close(); err != nil {
-			if perr := parseCloseError(err); perr != nil {
-				t.Error(perr)
-			}
-			t.Fatal(err)
-		}
-		var b [1]byte
-		n, err := c.Read(b[:])
-		if n != 0 || err == nil {
-			t.Fatalf("got (%d, %v); want (0, error)", n, err)
-		}
-	}
-}
+		go read(c)
 
-func TestListenerClose(t *testing.T) {
-	for _, network := range []string{"tcp", "unix", "unixpacket"} {
-		if !testableNetwork(network) {
-			t.Logf("skipping %s test", network)
-			continue
-		}
+		time.Sleep(10 * time.Millisecond)
+		c.Close()
+	}()
 
-		ln, err := newLocalListener(network)
-		if err != nil {
-			t.Fatal(err)
-		}
-		switch network {
-		case "unix", "unixpacket":
-			defer os.Remove(ln.Addr().String())
-		}
-		defer ln.Close()
+	c, err := l.Accept()
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer c.Close()
 
-		if err := ln.Close(); err != nil {
-			if perr := parseCloseError(err); perr != nil {
-				t.Error(perr)
-			}
-			t.Fatal(err)
-		}
-		c, err := ln.Accept()
-		if err == nil {
-			c.Close()
-			t.Fatal("should fail")
-		}
+	for err == nil {
+		err = read(c)
+	}
+	if err != nil && err != io.EOF {
+		t.Fatal(err)
 	}
 }
 
-func TestPacketConnClose(t *testing.T) {
-	for _, network := range []string{"udp", "unixgram"} {
-		if !testableNetwork(network) {
-			t.Logf("skipping %s test", network)
-			continue
-		}
+func TestErrorNil(t *testing.T) {
+	c, err := Dial("tcp", "127.0.0.1:65535")
+	if err == nil {
+		t.Fatal("Dial 127.0.0.1:65535 succeeded")
+	}
+	if c != nil {
+		t.Fatalf("Dial returned non-nil interface %T(%v) with err != nil", c, c)
+	}
 
-		c, err := newLocalPacketListener(network)
-		if err != nil {
-			t.Fatal(err)
-		}
-		switch network {
-		case "unixgram":
-			defer os.Remove(c.LocalAddr().String())
-		}
-		defer c.Close()
+	// Make Listen fail by relistening on the same address.
+	l, err := Listen("tcp", "127.0.0.1:0")
+	if err != nil {
+		t.Fatalf("Listen 127.0.0.1:0: %v", err)
+	}
+	defer l.Close()
+	l1, err := Listen("tcp", l.Addr().String())
+	if err == nil {
+		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)
+	}
 
-		if err := c.Close(); err != nil {
-			if perr := parseCloseError(err); perr != nil {
-				t.Error(perr)
-			}
-			t.Fatal(err)
-		}
-		var b [1]byte
-		n, _, err := c.ReadFrom(b[:])
-		if n != 0 || err == nil {
-			t.Fatalf("got (%d, %v); want (0, error)", n, err)
-		}
+	// Make ListenPacket fail by relistening on the same address.
+	lp, err := ListenPacket("udp", "127.0.0.1:0")
+	if err != nil {
+		t.Fatalf("Listen 127.0.0.1:0: %v", err)
+	}
+	defer lp.Close()
+	lp1, err := ListenPacket("udp", lp.LocalAddr().String())
+	if err == nil {
+		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/net/net_windows_test.go b/src/net/net_windows_test.go
index da03e10..750a430 100644
--- a/src/net/net_windows_test.go
+++ b/src/net/net_windows_test.go
@@ -15,31 +15,18 @@ import (
 	"time"
 )
 
-func toErrno(err error) (syscall.Errno, bool) {
-	operr, ok := err.(*OpError)
-	if !ok {
-		return 0, false
-	}
-	syserr, ok := operr.Err.(*os.SyscallError)
-	if !ok {
-		return 0, false
-	}
-	errno, ok := syserr.Err.(syscall.Errno)
-	if !ok {
-		return 0, false
-	}
-	return errno, true
-}
-
-// TestAcceptIgnoreSomeErrors tests that windows TCPListener.AcceptTCP
-// handles broken connections. It verifies that broken connections do
-// not affect future connections.
 func TestAcceptIgnoreSomeErrors(t *testing.T) {
-	recv := func(ln Listener, ignoreSomeReadErrors bool) (string, error) {
+	t.Skip("skipping temporarily, see issue 8662")
+
+	recv := func(ln Listener) (string, error) {
 		c, err := ln.Accept()
 		if err != nil {
 			// Display windows errno in error message.
-			errno, ok := toErrno(err)
+			operr, ok := err.(*OpError)
+			if !ok {
+				return "", err
+			}
+			errno, ok := operr.Err.(syscall.Errno)
 			if !ok {
 				return "", err
 			}
@@ -49,14 +36,10 @@ func TestAcceptIgnoreSomeErrors(t *testing.T) {
 
 		b := make([]byte, 100)
 		n, err := c.Read(b)
-		if err == nil || err == io.EOF {
-			return string(b[:n]), nil
-		}
-		errno, ok := toErrno(err)
-		if ok && ignoreSomeReadErrors && (errno == syscall.ERROR_NETNAME_DELETED || errno == syscall.WSAECONNRESET) {
-			return "", nil
+		if err != nil && err != io.EOF {
+			return "", err
 		}
-		return "", err
+		return string(b[:n]), nil
 	}
 
 	send := func(addr string, data string) error {
@@ -81,7 +64,7 @@ func TestAcceptIgnoreSomeErrors(t *testing.T) {
 		// In child process.
 		c, err := Dial("tcp", envaddr)
 		if err != nil {
-			t.Fatal(err)
+			t.Fatalf("Dial failed: %v", err)
 		}
 		fmt.Printf("sleeping\n")
 		time.Sleep(time.Minute) // process will be killed here
@@ -90,7 +73,7 @@ func TestAcceptIgnoreSomeErrors(t *testing.T) {
 
 	ln, err := Listen("tcp", "127.0.0.1:0")
 	if err != nil {
-		t.Fatal(err)
+		t.Fatalf("Listen failed: %v", err)
 	}
 	defer ln.Close()
 
@@ -140,13 +123,13 @@ func TestAcceptIgnoreSomeErrors(t *testing.T) {
 	}()
 
 	// Receive first or second connection.
-	s, err := recv(ln, true)
+	s, err := recv(ln)
 	if err != nil {
 		t.Fatalf("recv failed: %v", err)
 	}
 	switch s {
 	case "":
-		// First connection data is received, let's get second connection data.
+		// First connection data is received, lets get second connection data.
 	case "abc":
 		// First connection is lost forever, but that is ok.
 		return
@@ -155,7 +138,7 @@ func TestAcceptIgnoreSomeErrors(t *testing.T) {
 	}
 
 	// Get second connection data.
-	s, err = recv(ln, false)
+	s, err = recv(ln)
 	if err != nil {
 		t.Fatalf("recv failed: %v", err)
 	}
diff --git a/src/net/netgo_unix_test.go b/src/net/netgo_unix_test.go
index 1d950d6..9fb2a56 100644
--- a/src/net/netgo_unix_test.go
+++ b/src/net/netgo_unix_test.go
@@ -16,9 +16,9 @@ func TestGoLookupIP(t *testing.T) {
 		t.Errorf("cgoLookupIP must be a placeholder")
 	}
 	if err != nil {
-		t.Error(err)
+		t.Errorf("cgoLookupIP failed: %v", err)
 	}
 	if _, err := goLookupIP(host); err != nil {
-		t.Error(err)
+		t.Errorf("goLookupIP failed: %v", err)
 	}
 }
diff --git a/src/net/packetconn_test.go b/src/net/packetconn_test.go
index 7f3ea8a..b6e4e76 100644
--- a/src/net/packetconn_test.go
+++ b/src/net/packetconn_test.go
@@ -9,21 +9,49 @@ package net
 
 import (
 	"os"
+	"runtime"
+	"strings"
 	"testing"
 	"time"
 )
 
-// The full stack test cases for IPConn have been moved to the
-// following:
-//	golang.org/x/net/ipv4
-//	golang.org/x/net/ipv6
-//	golang.org/x/net/icmp
-
-func packetConnTestData(t *testing.T, network string) ([]byte, func()) {
-	if !testableNetwork(network) {
-		return nil, func() { t.Logf("skipping %s test", network) }
+func packetConnTestData(t *testing.T, net string, i int) ([]byte, func()) {
+	switch net {
+	case "udp":
+		return []byte("UDP PACKETCONN TEST"), nil
+	case "ip":
+		if skip, skipmsg := skipRawSocketTest(t); skip {
+			return nil, func() {
+				t.Logf(skipmsg)
+			}
+		}
+		b, err := (&icmpMessage{
+			Type: icmpv4EchoRequest, Code: 0,
+			Body: &icmpEcho{
+				ID: os.Getpid() & 0xffff, Seq: i + 1,
+				Data: []byte("IP PACKETCONN TEST"),
+			},
+		}).Marshal()
+		if err != nil {
+			return nil, func() {
+				t.Fatalf("icmpMessage.Marshal failed: %v", err)
+			}
+		}
+		return b, nil
+	case "unixgram":
+		switch runtime.GOOS {
+		case "nacl", "plan9", "windows":
+			return nil, func() {
+				t.Logf("skipping %q test on %q", net, runtime.GOOS)
+			}
+		default:
+			return []byte("UNIXGRAM PACKETCONN TEST"), nil
+		}
+	default:
+		return nil, func() {
+			t.Logf("skipping %q test", net)
+		}
 	}
-	return []byte("PACKETCONN TEST"), nil
 }
 
 var packetConnTests = []struct {
@@ -32,6 +60,7 @@ var packetConnTests = []struct {
 	addr2 string
 }{
 	{"udp", "127.0.0.1:0", "127.0.0.1:0"},
+	{"ip:icmp", "127.0.0.1", "127.0.0.1"},
 	{"unixgram", testUnixAddr(), testUnixAddr()},
 }
 
@@ -45,8 +74,9 @@ func TestPacketConn(t *testing.T) {
 		}
 	}
 
-	for _, tt := range packetConnTests {
-		wb, skipOrFatalFn := packetConnTestData(t, tt.net)
+	for i, tt := range packetConnTests {
+		netstr := strings.Split(tt.net, ":")
+		wb, skipOrFatalFn := packetConnTestData(t, netstr[0], i)
 		if skipOrFatalFn != nil {
 			skipOrFatalFn()
 			continue
@@ -54,37 +84,37 @@ func TestPacketConn(t *testing.T) {
 
 		c1, err := ListenPacket(tt.net, tt.addr1)
 		if err != nil {
-			t.Fatal(err)
+			t.Fatalf("ListenPacket failed: %v", err)
 		}
-		defer closer(c1, tt.net, tt.addr1, tt.addr2)
+		defer closer(c1, netstr[0], tt.addr1, tt.addr2)
 		c1.LocalAddr()
-		c1.SetDeadline(time.Now().Add(500 * time.Millisecond))
-		c1.SetReadDeadline(time.Now().Add(500 * time.Millisecond))
-		c1.SetWriteDeadline(time.Now().Add(500 * time.Millisecond))
+		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, tt.addr2)
 		if err != nil {
-			t.Fatal(err)
+			t.Fatalf("ListenPacket failed: %v", err)
 		}
-		defer closer(c2, tt.net, tt.addr1, tt.addr2)
+		defer closer(c2, netstr[0], tt.addr1, tt.addr2)
 		c2.LocalAddr()
-		c2.SetDeadline(time.Now().Add(500 * time.Millisecond))
-		c2.SetReadDeadline(time.Now().Add(500 * time.Millisecond))
-		c2.SetWriteDeadline(time.Now().Add(500 * time.Millisecond))
-		rb2 := make([]byte, 128)
+		c2.SetDeadline(time.Now().Add(100 * time.Millisecond))
+		c2.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
+		c2.SetWriteDeadline(time.Now().Add(100 * time.Millisecond))
 
 		if _, err := c1.WriteTo(wb, c2.LocalAddr()); err != nil {
-			t.Fatal(err)
+			t.Fatalf("PacketConn.WriteTo failed: %v", err)
 		}
+		rb2 := make([]byte, 128)
 		if _, _, err := c2.ReadFrom(rb2); err != nil {
-			t.Fatal(err)
+			t.Fatalf("PacketConn.ReadFrom failed: %v", err)
 		}
 		if _, err := c2.WriteTo(wb, c1.LocalAddr()); err != nil {
-			t.Fatal(err)
+			t.Fatalf("PacketConn.WriteTo failed: %v", err)
 		}
 		rb1 := make([]byte, 128)
 		if _, _, err := c1.ReadFrom(rb1); err != nil {
-			t.Fatal(err)
+			t.Fatalf("PacketConn.ReadFrom failed: %v", err)
 		}
 	}
 }
@@ -99,9 +129,10 @@ func TestConnAndPacketConn(t *testing.T) {
 		}
 	}
 
-	for _, tt := range packetConnTests {
+	for i, tt := range packetConnTests {
 		var wb []byte
-		wb, skipOrFatalFn := packetConnTestData(t, tt.net)
+		netstr := strings.Split(tt.net, ":")
+		wb, skipOrFatalFn := packetConnTestData(t, netstr[0], i)
 		if skipOrFatalFn != nil {
 			skipOrFatalFn()
 			continue
@@ -109,45 +140,47 @@ func TestConnAndPacketConn(t *testing.T) {
 
 		c1, err := ListenPacket(tt.net, tt.addr1)
 		if err != nil {
-			t.Fatal(err)
+			t.Fatalf("ListenPacket failed: %v", err)
 		}
-		defer closer(c1, tt.net, tt.addr1, tt.addr2)
+		defer closer(c1, netstr[0], tt.addr1, tt.addr2)
 		c1.LocalAddr()
-		c1.SetDeadline(time.Now().Add(500 * time.Millisecond))
-		c1.SetReadDeadline(time.Now().Add(500 * time.Millisecond))
-		c1.SetWriteDeadline(time.Now().Add(500 * time.Millisecond))
+		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 := Dial(tt.net, c1.LocalAddr().String())
 		if err != nil {
-			t.Fatal(err)
+			t.Fatalf("Dial failed: %v", err)
 		}
 		defer c2.Close()
 		c2.LocalAddr()
 		c2.RemoteAddr()
-		c2.SetDeadline(time.Now().Add(500 * time.Millisecond))
-		c2.SetReadDeadline(time.Now().Add(500 * time.Millisecond))
-		c2.SetWriteDeadline(time.Now().Add(500 * time.Millisecond))
+		c2.SetDeadline(time.Now().Add(100 * time.Millisecond))
+		c2.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
+		c2.SetWriteDeadline(time.Now().Add(100 * time.Millisecond))
 
 		if _, err := c2.Write(wb); err != nil {
-			t.Fatal(err)
+			t.Fatalf("Conn.Write failed: %v", err)
 		}
 		rb1 := make([]byte, 128)
 		if _, _, err := c1.ReadFrom(rb1); err != nil {
-			t.Fatal(err)
+			t.Fatalf("PacketConn.ReadFrom failed: %v", err)
 		}
 		var dst Addr
-		switch tt.net {
+		switch netstr[0] {
+		case "ip":
+			dst = &IPAddr{IP: IPv4(127, 0, 0, 1)}
 		case "unixgram":
 			continue
 		default:
 			dst = c2.LocalAddr()
 		}
 		if _, err := c1.WriteTo(wb, dst); err != nil {
-			t.Fatal(err)
+			t.Fatalf("PacketConn.WriteTo failed: %v", err)
 		}
 		rb2 := make([]byte, 128)
 		if _, err := c2.Read(rb2); err != nil {
-			t.Fatal(err)
+			t.Fatalf("Conn.Read failed: %v", err)
 		}
 	}
 }
diff --git a/src/net/parse.go b/src/net/parse.go
index c72e1c2..e1d0130 100644
--- a/src/net/parse.go
+++ b/src/net/parse.go
@@ -171,30 +171,43 @@ func xtoi2(s string, e byte) (byte, bool) {
 	return byte(n), ok && ei == 2
 }
 
-// Convert integer to decimal string.
-func itoa(val int) string {
-	if val < 0 {
-		return "-" + uitoa(uint(-val))
-	}
-	return uitoa(uint(val))
-}
-
-// Convert unsigned integer to decimal string.
-func uitoa(val uint) string {
-	if val == 0 { // avoid string allocation
+// Integer to decimal.
+func itoa(i int) string {
+	var buf [30]byte
+	n := len(buf)
+	neg := false
+	if i < 0 {
+		i = -i
+		neg = true
+	}
+	ui := uint(i)
+	for ui > 0 || n == len(buf) {
+		n--
+		buf[n] = byte('0' + ui%10)
+		ui /= 10
+	}
+	if neg {
+		n--
+		buf[n] = '-'
+	}
+	return string(buf[n:])
+}
+
+// Convert i to decimal string.
+func itod(i uint) string {
+	if i == 0 {
 		return "0"
 	}
-	var buf [20]byte // big enough for 64bit value base 10
-	i := len(buf) - 1
-	for val >= 10 {
-		q := val / 10
-		buf[i] = byte('0' + val - q*10)
-		i--
-		val = q
+
+	// Assemble decimal in reverse order.
+	var b [32]byte
+	bp := len(b)
+	for ; i > 0; i /= 10 {
+		bp--
+		b[bp] = byte(i%10) + '0'
 	}
-	// val < 10
-	buf[i] = byte('0' + val)
-	return string(buf[i:])
+
+	return string(b[bp:])
 }
 
 // Convert i to a hexadecimal string. Leading zeros are not printed.
@@ -232,155 +245,3 @@ func last(s string, b byte) int {
 	}
 	return i
 }
-
-// lowerASCIIBytes makes x ASCII lowercase in-place.
-func lowerASCIIBytes(x []byte) {
-	for i, b := range x {
-		if 'A' <= b && b <= 'Z' {
-			x[i] += 'a' - 'A'
-		}
-	}
-}
-
-// lowerASCII returns the ASCII lowercase version of b.
-func lowerASCII(b byte) byte {
-	if 'A' <= b && b <= 'Z' {
-		return b + ('a' - 'A')
-	}
-	return b
-}
-
-// trimSpace returns x without any leading or trailing ASCII whitespace.
-func trimSpace(x []byte) []byte {
-	for len(x) > 0 && isSpace(x[0]) {
-		x = x[1:]
-	}
-	for len(x) > 0 && isSpace(x[len(x)-1]) {
-		x = x[:len(x)-1]
-	}
-	return x
-}
-
-// isSpace reports whether b is an ASCII space character.
-func isSpace(b byte) bool {
-	return b == ' ' || b == '\t' || b == '\n' || b == '\r'
-}
-
-// removeComment returns line, removing any '#' byte and any following
-// bytes.
-func removeComment(line []byte) []byte {
-	if i := bytesIndexByte(line, '#'); i != -1 {
-		return line[:i]
-	}
-	return line
-}
-
-// foreachLine runs fn on each line of x.
-// Each line (except for possibly the last) ends in '\n'.
-// It returns the first non-nil error returned by fn.
-func foreachLine(x []byte, fn func(line []byte) error) error {
-	for len(x) > 0 {
-		nl := bytesIndexByte(x, '\n')
-		if nl == -1 {
-			return fn(x)
-		}
-		line := x[:nl+1]
-		x = x[nl+1:]
-		if err := fn(line); err != nil {
-			return err
-		}
-	}
-	return nil
-}
-
-// foreachField runs fn on each non-empty run of non-space bytes in x.
-// It returns the first non-nil error returned by fn.
-func foreachField(x []byte, fn func(field []byte) error) error {
-	x = trimSpace(x)
-	for len(x) > 0 {
-		sp := bytesIndexByte(x, ' ')
-		if sp == -1 {
-			return fn(x)
-		}
-		if field := trimSpace(x[:sp]); len(field) > 0 {
-			if err := fn(field); err != nil {
-				return err
-			}
-		}
-		x = trimSpace(x[sp+1:])
-	}
-	return nil
-}
-
-// bytesIndexByte is bytes.IndexByte. It returns the index of the
-// first instance of c in s, or -1 if c is not present in s.
-func bytesIndexByte(s []byte, c byte) int {
-	for i, b := range s {
-		if b == c {
-			return i
-		}
-	}
-	return -1
-}
-
-// stringsHasSuffix is strings.HasSuffix. It reports whether s ends in
-// suffix.
-func stringsHasSuffix(s, suffix string) bool {
-	return len(s) >= len(suffix) && s[len(s)-len(suffix):] == suffix
-}
-
-// stringsHasSuffixFold reports whether s ends in suffix,
-// ASCII-case-insensitively.
-func stringsHasSuffixFold(s, suffix string) bool {
-	if len(suffix) > len(s) {
-		return false
-	}
-	for i := 0; i < len(suffix); i++ {
-		if lowerASCII(suffix[i]) != lowerASCII(s[len(s)-len(suffix)+i]) {
-			return false
-		}
-	}
-	return true
-}
-
-// stringsHasPrefix is strings.HasPrefix. It reports whether s begins with prefix.
-func stringsHasPrefix(s, prefix string) bool {
-	return len(s) >= len(prefix) && s[:len(prefix)] == prefix
-}
-
-func readFull(r io.Reader) (all []byte, err error) {
-	buf := make([]byte, 1024)
-	for {
-		n, err := r.Read(buf)
-		all = append(all, buf[:n]...)
-		if err == io.EOF {
-			return all, nil
-		}
-		if err != nil {
-			return nil, err
-		}
-	}
-}
-
-// goDebugString returns the value of the named GODEBUG key.
-// GODEBUG is of the form "key=val,key2=val2"
-func goDebugString(key string) string {
-	s := os.Getenv("GODEBUG")
-	for i := 0; i < len(s)-len(key)-1; i++ {
-		if i > 0 && s[i-1] != ',' {
-			continue
-		}
-		afterKey := s[i+len(key):]
-		if afterKey[0] != '=' || s[i:i+len(key)] != key {
-			continue
-		}
-		val := afterKey[1:]
-		for i, b := range val {
-			if b == ',' {
-				return val[:i]
-			}
-		}
-		return val
-	}
-	return ""
-}
diff --git a/src/net/parse_test.go b/src/net/parse_test.go
index 0f048fc..7b213b7 100644
--- a/src/net/parse_test.go
+++ b/src/net/parse_test.go
@@ -15,20 +15,20 @@ func TestReadLine(t *testing.T) {
 	// /etc/services file does not exist on android, plan9, windows.
 	switch runtime.GOOS {
 	case "android", "plan9", "windows":
-		t.Skipf("not supported on %s", runtime.GOOS)
+		t.Skipf("skipping test on %q", runtime.GOOS)
 	}
 	filename := "/etc/services" // a nice big file
 
 	fd, err := os.Open(filename)
 	if err != nil {
-		t.Fatal(err)
+		t.Fatalf("open %s: %v", filename, err)
 	}
 	defer fd.Close()
 	br := bufio.NewReader(fd)
 
 	file, err := open(filename)
 	if file == nil {
-		t.Fatal(err)
+		t.Fatalf("net.open(%s) = nil", filename)
 	}
 	defer file.close()
 
@@ -41,7 +41,8 @@ func TestReadLine(t *testing.T) {
 		}
 		line, ok := file.readLine()
 		if (berr != nil) != !ok || bline != line {
-			t.Fatalf("%s:%d (#%d)\nbufio => %q, %v\nnet => %q, %v", filename, lineno, byteno, bline, berr, line, ok)
+			t.Fatalf("%s:%d (#%d)\nbufio => %q, %v\nnet => %q, %v",
+				filename, lineno, byteno, bline, berr, line, ok)
 		}
 		if !ok {
 			break
@@ -50,30 +51,3 @@ func TestReadLine(t *testing.T) {
 		byteno += len(line) + 1
 	}
 }
-
-func TestGoDebugString(t *testing.T) {
-	defer os.Setenv("GODEBUG", os.Getenv("GODEBUG"))
-	tests := []struct {
-		godebug string
-		key     string
-		want    string
-	}{
-		{"", "foo", ""},
-		{"foo=", "foo", ""},
-		{"foo=bar", "foo", "bar"},
-		{"foo=bar,", "foo", "bar"},
-		{"foo,foo=bar,", "foo", "bar"},
-		{"foo1=bar,foo=bar,", "foo", "bar"},
-		{"foo=bar,foo=bar,", "foo", "bar"},
-		{"foo=", "foo", ""},
-		{"foo", "foo", ""},
-		{",foo", "foo", ""},
-		{"foo=bar,baz", "loooooooong", ""},
-	}
-	for _, tt := range tests {
-		os.Setenv("GODEBUG", tt.godebug)
-		if got := goDebugString(tt.key); got != tt.want {
-			t.Errorf("for %q, goDebugString(%q) = %q; want %q", tt.godebug, tt.key, got, tt.want)
-		}
-	}
-}
diff --git a/src/net/pipe.go b/src/net/pipe.go
index 5fc830b..f1a2eca 100644
--- a/src/net/pipe.go
+++ b/src/net/pipe.go
@@ -55,13 +55,13 @@ func (p *pipe) RemoteAddr() Addr {
 }
 
 func (p *pipe) SetDeadline(t time.Time) error {
-	return &OpError{Op: "set", Net: "pipe", Source: nil, Addr: nil, Err: errors.New("deadline not supported")}
+	return errors.New("net.Pipe does not support deadlines")
 }
 
 func (p *pipe) SetReadDeadline(t time.Time) error {
-	return &OpError{Op: "set", Net: "pipe", Source: nil, Addr: nil, Err: errors.New("deadline not supported")}
+	return errors.New("net.Pipe does not support deadlines")
 }
 
 func (p *pipe) SetWriteDeadline(t time.Time) error {
-	return &OpError{Op: "set", Net: "pipe", Source: nil, Addr: nil, Err: errors.New("deadline not supported")}
+	return errors.New("net.Pipe does not support deadlines")
 }
diff --git a/src/net/pipe_test.go b/src/net/pipe_test.go
index 60c3920..afe4f24 100644
--- a/src/net/pipe_test.go
+++ b/src/net/pipe_test.go
@@ -10,10 +10,10 @@ import (
 	"testing"
 )
 
-func checkPipeWrite(t *testing.T, w io.Writer, data []byte, c chan int) {
+func checkWrite(t *testing.T, w io.Writer, data []byte, c chan int) {
 	n, err := w.Write(data)
 	if err != nil {
-		t.Error(err)
+		t.Errorf("write: %v", err)
 	}
 	if n != len(data) {
 		t.Errorf("short write: %d != %d", n, len(data))
@@ -21,11 +21,11 @@ func checkPipeWrite(t *testing.T, w io.Writer, data []byte, c chan int) {
 	c <- 0
 }
 
-func checkPipeRead(t *testing.T, r io.Reader, data []byte, wantErr error) {
+func checkRead(t *testing.T, r io.Reader, data []byte, wantErr error) {
 	buf := make([]byte, len(data)+10)
 	n, err := r.Read(buf)
 	if err != wantErr {
-		t.Error(err)
+		t.Errorf("read: %v", err)
 		return
 	}
 	if n != len(data) || !bytes.Equal(buf[0:n], data) {
@@ -34,22 +34,23 @@ func checkPipeRead(t *testing.T, r io.Reader, data []byte, wantErr error) {
 	}
 }
 
-// TestPipe tests a simple read/write/close sequence.
+// Test a simple read/write/close sequence.
 // Assumes that the underlying io.Pipe implementation
 // is solid and we're just testing the net wrapping.
+
 func TestPipe(t *testing.T) {
 	c := make(chan int)
 	cli, srv := Pipe()
-	go checkPipeWrite(t, cli, []byte("hello, world"), c)
-	checkPipeRead(t, srv, []byte("hello, world"), nil)
+	go checkWrite(t, cli, []byte("hello, world"), c)
+	checkRead(t, srv, []byte("hello, world"), nil)
 	<-c
-	go checkPipeWrite(t, srv, []byte("line 2"), c)
-	checkPipeRead(t, cli, []byte("line 2"), nil)
+	go checkWrite(t, srv, []byte("line 2"), c)
+	checkRead(t, cli, []byte("line 2"), nil)
 	<-c
-	go checkPipeWrite(t, cli, []byte("a third line"), c)
-	checkPipeRead(t, srv, []byte("a third line"), nil)
+	go checkWrite(t, cli, []byte("a third line"), c)
+	checkRead(t, srv, []byte("a third line"), nil)
 	<-c
 	go srv.Close()
-	checkPipeRead(t, cli, nil, io.EOF)
+	checkRead(t, cli, nil, io.EOF)
 	cli.Close()
 }
diff --git a/src/net/port.go b/src/net/port.go
index a2a5387..c24f4ed 100644
--- a/src/net/port.go
+++ b/src/net/port.go
@@ -18,7 +18,7 @@ func parsePort(net, port string) (int, error) {
 		}
 	}
 	if p < 0 || p > 0xFFFF {
-		return 0, &AddrError{Err: "invalid port", Addr: port}
+		return 0, &AddrError{"invalid port", port}
 	}
 	return p, nil
 }
diff --git a/src/net/port_test.go b/src/net/port_test.go
index 2dacd97..4811ade 100644
--- a/src/net/port_test.go
+++ b/src/net/port_test.go
@@ -9,12 +9,14 @@ import (
 	"testing"
 )
 
-var portTests = []struct {
-	network string
-	name    string
-	port    int
-	ok      bool
-}{
+type portTest struct {
+	netw string
+	name string
+	port int
+	ok   bool
+}
+
+var porttests = []portTest{
 	{"tcp", "echo", 7, true},
 	{"tcp", "discard", 9, true},
 	{"tcp", "systat", 11, true},
@@ -44,12 +46,14 @@ var portTests = []struct {
 func TestLookupPort(t *testing.T) {
 	switch runtime.GOOS {
 	case "nacl":
-		t.Skipf("not supported on %s", runtime.GOOS)
+		t.Skipf("skipping test on %q", runtime.GOOS)
 	}
 
-	for _, tt := range portTests {
-		if port, err := LookupPort(tt.network, tt.name); port != tt.port || (err == nil) != tt.ok {
-			t.Errorf("LookupPort(%q, %q) = %v, %v; want %v", tt.network, tt.name, port, err, tt.port)
+	for i := 0; i < len(porttests); i++ {
+		tt := porttests[i]
+		if port, err := LookupPort(tt.netw, tt.name); port != tt.port || (err == nil) != tt.ok {
+			t.Errorf("LookupPort(%q, %q) = %v, %v; want %v",
+				tt.netw, tt.name, port, err, tt.port)
 		}
 	}
 }
diff --git a/src/net/port_unix.go b/src/net/port_unix.go
index badf8ab..348c771 100644
--- a/src/net/port_unix.go
+++ b/src/net/port_unix.go
@@ -69,5 +69,5 @@ func goLookupPort(network, service string) (port int, err error) {
 			return
 		}
 	}
-	return 0, &AddrError{Err: "unknown port", Addr: network + "/" + service}
+	return 0, &AddrError{"unknown port", network + "/" + service}
 }
diff --git a/src/net/protoconn_test.go b/src/net/protoconn_test.go
index c6ef23b..12856b6 100644
--- a/src/net/protoconn_test.go
+++ b/src/net/protoconn_test.go
@@ -8,31 +8,49 @@
 package net
 
 import (
+	"io/ioutil"
 	"os"
 	"runtime"
 	"testing"
 	"time"
 )
 
-// The full stack test cases for IPConn have been moved to the
-// following:
-//	golang.org/x/net/ipv4
-//	golang.org/x/net/ipv6
-//	golang.org/x/net/icmp
+// testUnixAddr uses ioutil.TempFile to get a name that is unique. It
+// also uses /tmp directory in case it is prohibited to create UNIX
+// sockets in TMPDIR.
+func testUnixAddr() string {
+	f, err := ioutil.TempFile("", "nettest")
+	if err != nil {
+		panic(err)
+	}
+	addr := f.Name()
+	f.Close()
+	os.Remove(addr)
+	return addr
+}
+
+var condFatalf = func() func(*testing.T, string, ...interface{}) {
+	// A few APIs are not implemented yet on both Plan 9 and Windows.
+	switch runtime.GOOS {
+	case "plan9", "windows":
+		return (*testing.T).Logf
+	}
+	return (*testing.T).Fatalf
+}()
 
 func TestTCPListenerSpecificMethods(t *testing.T) {
 	switch runtime.GOOS {
 	case "plan9":
-		t.Skipf("not supported on %s", runtime.GOOS)
+		t.Skipf("skipping test on %q", runtime.GOOS)
 	}
 
 	la, err := ResolveTCPAddr("tcp4", "127.0.0.1:0")
 	if err != nil {
-		t.Fatal(err)
+		t.Fatalf("ResolveTCPAddr failed: %v", err)
 	}
 	ln, err := ListenTCP("tcp4", la)
 	if err != nil {
-		t.Fatal(err)
+		t.Fatalf("ListenTCP failed: %v", err)
 	}
 	defer ln.Close()
 	ln.Addr()
@@ -40,21 +58,21 @@ func TestTCPListenerSpecificMethods(t *testing.T) {
 
 	if c, err := ln.Accept(); err != nil {
 		if !err.(Error).Timeout() {
-			t.Fatal(err)
+			t.Fatalf("TCPListener.Accept failed: %v", err)
 		}
 	} else {
 		c.Close()
 	}
 	if c, err := ln.AcceptTCP(); err != nil {
 		if !err.(Error).Timeout() {
-			t.Fatal(err)
+			t.Fatalf("TCPListener.AcceptTCP failed: %v", err)
 		}
 	} else {
 		c.Close()
 	}
 
 	if f, err := ln.File(); err != nil {
-		condFatalf(t, "%v", err)
+		condFatalf(t, "TCPListener.File failed: %v", err)
 	} else {
 		f.Close()
 	}
@@ -63,30 +81,25 @@ func TestTCPListenerSpecificMethods(t *testing.T) {
 func TestTCPConnSpecificMethods(t *testing.T) {
 	la, err := ResolveTCPAddr("tcp4", "127.0.0.1:0")
 	if err != nil {
-		t.Fatal(err)
+		t.Fatalf("ResolveTCPAddr failed: %v", err)
 	}
 	ln, err := ListenTCP("tcp4", la)
 	if err != nil {
-		t.Fatal(err)
-	}
-	ch := make(chan error, 1)
-	handler := func(ls *localServer, ln Listener) { transponder(ls.Listener, ch) }
-	ls, err := (&streamListener{Listener: ln}).newLocalServer()
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer ls.teardown()
-	if err := ls.buildup(handler); err != nil {
-		t.Fatal(err)
+		t.Fatalf("ListenTCP failed: %v", err)
 	}
+	defer ln.Close()
+	ln.Addr()
 
-	ra, err := ResolveTCPAddr("tcp4", ls.Listener.Addr().String())
+	done := make(chan int)
+	go transponder(t, ln, done)
+
+	ra, err := ResolveTCPAddr("tcp4", ln.Addr().String())
 	if err != nil {
-		t.Fatal(err)
+		t.Fatalf("ResolveTCPAddr failed: %v", err)
 	}
 	c, err := DialTCP("tcp4", nil, ra)
 	if err != nil {
-		t.Fatal(err)
+		t.Fatalf("DialTCP failed: %v", err)
 	}
 	defer c.Close()
 	c.SetKeepAlive(false)
@@ -100,26 +113,24 @@ func TestTCPConnSpecificMethods(t *testing.T) {
 	c.SetWriteDeadline(time.Now().Add(someTimeout))
 
 	if _, err := c.Write([]byte("TCPCONN TEST")); err != nil {
-		t.Fatal(err)
+		t.Fatalf("TCPConn.Write failed: %v", err)
 	}
 	rb := make([]byte, 128)
 	if _, err := c.Read(rb); err != nil {
-		t.Fatal(err)
+		t.Fatalf("TCPConn.Read failed: %v", err)
 	}
 
-	for err := range ch {
-		t.Error(err)
-	}
+	<-done
 }
 
 func TestUDPConnSpecificMethods(t *testing.T) {
 	la, err := ResolveUDPAddr("udp4", "127.0.0.1:0")
 	if err != nil {
-		t.Fatal(err)
+		t.Fatalf("ResolveUDPAddr failed: %v", err)
 	}
 	c, err := ListenUDP("udp4", la)
 	if err != nil {
-		t.Fatal(err)
+		t.Fatalf("ListenUDP failed: %v", err)
 	}
 	defer c.Close()
 	c.LocalAddr()
@@ -133,27 +144,27 @@ func TestUDPConnSpecificMethods(t *testing.T) {
 	wb := []byte("UDPCONN TEST")
 	rb := make([]byte, 128)
 	if _, err := c.WriteToUDP(wb, c.LocalAddr().(*UDPAddr)); err != nil {
-		t.Fatal(err)
+		t.Fatalf("UDPConn.WriteToUDP failed: %v", err)
 	}
 	if _, _, err := c.ReadFromUDP(rb); err != nil {
-		t.Fatal(err)
+		t.Fatalf("UDPConn.ReadFromUDP failed: %v", err)
 	}
 	if _, _, err := c.WriteMsgUDP(wb, nil, c.LocalAddr().(*UDPAddr)); err != nil {
-		condFatalf(t, "%v", err)
+		condFatalf(t, "UDPConn.WriteMsgUDP failed: %v", err)
 	}
 	if _, _, _, _, err := c.ReadMsgUDP(rb, nil); err != nil {
-		condFatalf(t, "%v", err)
+		condFatalf(t, "UDPConn.ReadMsgUDP failed: %v", err)
 	}
 
 	if f, err := c.File(); err != nil {
-		condFatalf(t, "%v", err)
+		condFatalf(t, "UDPConn.File failed: %v", err)
 	} else {
 		f.Close()
 	}
 
 	defer func() {
 		if p := recover(); p != nil {
-			t.Fatalf("panicked: %v", p)
+			t.Fatalf("UDPConn.WriteToUDP or WriteMsgUDP panicked: %v", p)
 		}
 	}()
 
@@ -162,17 +173,17 @@ func TestUDPConnSpecificMethods(t *testing.T) {
 }
 
 func TestIPConnSpecificMethods(t *testing.T) {
-	if os.Getuid() != 0 {
-		t.Skip("must be root")
+	if skip, skipmsg := skipRawSocketTest(t); skip {
+		t.Skip(skipmsg)
 	}
 
 	la, err := ResolveIPAddr("ip4", "127.0.0.1")
 	if err != nil {
-		t.Fatal(err)
+		t.Fatalf("ResolveIPAddr failed: %v", err)
 	}
 	c, err := ListenIP("ip4:icmp", la)
 	if err != nil {
-		t.Fatal(err)
+		t.Fatalf("ListenIP failed: %v", err)
 	}
 	defer c.Close()
 	c.LocalAddr()
@@ -183,36 +194,60 @@ func TestIPConnSpecificMethods(t *testing.T) {
 	c.SetReadBuffer(2048)
 	c.SetWriteBuffer(2048)
 
+	wb, err := (&icmpMessage{
+		Type: icmpv4EchoRequest, Code: 0,
+		Body: &icmpEcho{
+			ID: os.Getpid() & 0xffff, Seq: 1,
+			Data: []byte("IPCONN TEST "),
+		},
+	}).Marshal()
+	if err != nil {
+		t.Fatalf("icmpMessage.Marshal failed: %v", err)
+	}
+	rb := make([]byte, 20+len(wb))
+	if _, err := c.WriteToIP(wb, c.LocalAddr().(*IPAddr)); err != nil {
+		t.Fatalf("IPConn.WriteToIP failed: %v", err)
+	}
+	if _, _, err := c.ReadFromIP(rb); err != nil {
+		t.Fatalf("IPConn.ReadFromIP failed: %v", err)
+	}
+	if _, _, err := c.WriteMsgIP(wb, nil, c.LocalAddr().(*IPAddr)); err != nil {
+		condFatalf(t, "IPConn.WriteMsgIP failed: %v", err)
+	}
+	if _, _, _, _, err := c.ReadMsgIP(rb, nil); err != nil {
+		condFatalf(t, "IPConn.ReadMsgIP failed: %v", err)
+	}
+
 	if f, err := c.File(); err != nil {
-		condFatalf(t, "%v", err)
+		condFatalf(t, "IPConn.File failed: %v", err)
 	} else {
 		f.Close()
 	}
 
 	defer func() {
 		if p := recover(); p != nil {
-			t.Fatalf("panicked: %v", p)
+			t.Fatalf("IPConn.WriteToIP or WriteMsgIP panicked: %v", p)
 		}
 	}()
 
-	wb := []byte("IPCONN TEST")
 	c.WriteToIP(wb, nil)
 	c.WriteMsgIP(wb, nil, nil)
 }
 
 func TestUnixListenerSpecificMethods(t *testing.T) {
-	if !testableNetwork("unix") {
-		t.Skip("unix test")
+	switch runtime.GOOS {
+	case "nacl", "plan9", "windows":
+		t.Skipf("skipping test on %q", runtime.GOOS)
 	}
 
 	addr := testUnixAddr()
 	la, err := ResolveUnixAddr("unix", addr)
 	if err != nil {
-		t.Fatal(err)
+		t.Fatalf("ResolveUnixAddr failed: %v", err)
 	}
 	ln, err := ListenUnix("unix", la)
 	if err != nil {
-		t.Fatal(err)
+		t.Fatalf("ListenUnix failed: %v", err)
 	}
 	defer ln.Close()
 	defer os.Remove(addr)
@@ -221,40 +256,41 @@ func TestUnixListenerSpecificMethods(t *testing.T) {
 
 	if c, err := ln.Accept(); err != nil {
 		if !err.(Error).Timeout() {
-			t.Fatal(err)
+			t.Fatalf("UnixListener.Accept failed: %v", err)
 		}
 	} else {
 		c.Close()
 	}
 	if c, err := ln.AcceptUnix(); err != nil {
 		if !err.(Error).Timeout() {
-			t.Fatal(err)
+			t.Fatalf("UnixListener.AcceptUnix failed: %v", err)
 		}
 	} else {
 		c.Close()
 	}
 
 	if f, err := ln.File(); err != nil {
-		t.Fatal(err)
+		t.Fatalf("UnixListener.File failed: %v", err)
 	} else {
 		f.Close()
 	}
 }
 
 func TestUnixConnSpecificMethods(t *testing.T) {
-	if !testableNetwork("unixgram") {
-		t.Skip("unixgram test")
+	switch runtime.GOOS {
+	case "nacl", "plan9", "windows":
+		t.Skipf("skipping test on %q", runtime.GOOS)
 	}
 
 	addr1, addr2, addr3 := testUnixAddr(), testUnixAddr(), testUnixAddr()
 
 	a1, err := ResolveUnixAddr("unixgram", addr1)
 	if err != nil {
-		t.Fatal(err)
+		t.Fatalf("ResolveUnixAddr failed: %v", err)
 	}
 	c1, err := DialUnix("unixgram", a1, nil)
 	if err != nil {
-		t.Fatal(err)
+		t.Fatalf("DialUnix failed: %v", err)
 	}
 	defer c1.Close()
 	defer os.Remove(addr1)
@@ -268,11 +304,11 @@ func TestUnixConnSpecificMethods(t *testing.T) {
 
 	a2, err := ResolveUnixAddr("unixgram", addr2)
 	if err != nil {
-		t.Fatal(err)
+		t.Fatalf("ResolveUnixAddr failed: %v", err)
 	}
 	c2, err := DialUnix("unixgram", a2, nil)
 	if err != nil {
-		t.Fatal(err)
+		t.Fatalf("DialUnix failed: %v", err)
 	}
 	defer c2.Close()
 	defer os.Remove(addr2)
@@ -286,11 +322,11 @@ func TestUnixConnSpecificMethods(t *testing.T) {
 
 	a3, err := ResolveUnixAddr("unixgram", addr3)
 	if err != nil {
-		t.Fatal(err)
+		t.Fatalf("ResolveUnixAddr failed: %v", err)
 	}
 	c3, err := ListenUnixgram("unixgram", a3)
 	if err != nil {
-		t.Fatal(err)
+		t.Fatalf("ListenUnixgram failed: %v", err)
 	}
 	defer c3.Close()
 	defer os.Remove(addr3)
@@ -307,39 +343,39 @@ func TestUnixConnSpecificMethods(t *testing.T) {
 	rb2 := make([]byte, 128)
 	rb3 := make([]byte, 128)
 	if _, _, err := c1.WriteMsgUnix(wb, nil, a2); err != nil {
-		t.Fatal(err)
+		t.Fatalf("UnixConn.WriteMsgUnix failed: %v", err)
 	}
 	if _, _, _, _, err := c2.ReadMsgUnix(rb2, nil); err != nil {
-		t.Fatal(err)
+		t.Fatalf("UnixConn.ReadMsgUnix failed: %v", err)
 	}
 	if _, err := c2.WriteToUnix(wb, a1); err != nil {
-		t.Fatal(err)
+		t.Fatalf("UnixConn.WriteToUnix failed: %v", err)
 	}
 	if _, _, err := c1.ReadFromUnix(rb1); err != nil {
-		t.Fatal(err)
+		t.Fatalf("UnixConn.ReadFromUnix failed: %v", err)
 	}
 	if _, err := c3.WriteToUnix(wb, a1); err != nil {
-		t.Fatal(err)
+		t.Fatalf("UnixConn.WriteToUnix failed: %v", err)
 	}
 	if _, _, err := c1.ReadFromUnix(rb1); err != nil {
-		t.Fatal(err)
+		t.Fatalf("UnixConn.ReadFromUnix failed: %v", err)
 	}
 	if _, err := c2.WriteToUnix(wb, a3); err != nil {
-		t.Fatal(err)
+		t.Fatalf("UnixConn.WriteToUnix failed: %v", err)
 	}
 	if _, _, err := c3.ReadFromUnix(rb3); err != nil {
-		t.Fatal(err)
+		t.Fatalf("UnixConn.ReadFromUnix failed: %v", err)
 	}
 
 	if f, err := c1.File(); err != nil {
-		t.Fatal(err)
+		t.Fatalf("UnixConn.File failed: %v", err)
 	} else {
 		f.Close()
 	}
 
 	defer func() {
 		if p := recover(); p != nil {
-			t.Fatalf("panicked: %v", p)
+			t.Fatalf("UnixConn.WriteToUnix or WriteMsgUnix panicked: %v", p)
 		}
 	}()
 
diff --git a/src/net/rpc/client_test.go b/src/net/rpc/client_test.go
index ba11ff8..5dd111b 100644
--- a/src/net/rpc/client_test.go
+++ b/src/net/rpc/client_test.go
@@ -54,7 +54,7 @@ func (s *S) Recv(nul *struct{}, reply *R) error {
 
 func TestGobError(t *testing.T) {
 	if runtime.GOOS == "plan9" {
-		t.Skip("skipping test; see https://golang.org/issue/8908")
+		t.Skip("skipping test; see http://golang.org/issue/8908")
 	}
 	defer func() {
 		err := recover()
diff --git a/src/net/rpc/server.go b/src/net/rpc/server.go
index 6e6e881..83728d5 100644
--- a/src/net/rpc/server.go
+++ b/src/net/rpc/server.go
@@ -13,7 +13,6 @@
 	Only methods that satisfy these criteria will be made available for remote access;
 	other methods will be ignored:
 
-		- the method's type is exported.
 		- the method is exported.
 		- the method has two arguments, both exported (or builtin) types.
 		- the method's second argument is a pointer.
@@ -217,7 +216,7 @@ 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 of exported type
+//	- exported method
 //	- two arguments, both of exported type
 //	- the second argument is a pointer
 //	- one return value, of type error
diff --git a/src/net/sendfile_dragonfly.go b/src/net/sendfile_dragonfly.go
index a9cf3fe..bc88fd3 100644
--- a/src/net/sendfile_dragonfly.go
+++ b/src/net/sendfile_dragonfly.go
@@ -91,16 +91,13 @@ func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) {
 		if err1 != nil {
 			// This includes syscall.ENOSYS (no kernel
 			// support) and syscall.EINVAL (fd types which
-			// don't implement sendfile)
-			err = err1
+			// don't implement sendfile together)
+			err = &OpError{"sendfile", c.net, c.raddr, err1}
 			break
 		}
 	}
 	if lr != nil {
 		lr.N = remain
 	}
-	if err != nil {
-		err = os.NewSyscallError("sendfile", err)
-	}
 	return written, err, written > 0
 }
diff --git a/src/net/sendfile_freebsd.go b/src/net/sendfile_freebsd.go
index d0bf603..ffc1472 100644
--- a/src/net/sendfile_freebsd.go
+++ b/src/net/sendfile_freebsd.go
@@ -91,16 +91,13 @@ func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) {
 		if err1 != nil {
 			// This includes syscall.ENOSYS (no kernel
 			// support) and syscall.EINVAL (fd types which
-			// don't implement sendfile)
-			err = err1
+			// don't implement sendfile together)
+			err = &OpError{"sendfile", c.net, c.raddr, err1}
 			break
 		}
 	}
 	if lr != nil {
 		lr.N = remain
 	}
-	if err != nil {
-		err = os.NewSyscallError("sendfile", err)
-	}
 	return written, err, written > 0
 }
diff --git a/src/net/sendfile_linux.go b/src/net/sendfile_linux.go
index 5ca41c3..5e11763 100644
--- a/src/net/sendfile_linux.go
+++ b/src/net/sendfile_linux.go
@@ -64,16 +64,13 @@ func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) {
 		if err1 != nil {
 			// This includes syscall.ENOSYS (no kernel
 			// support) and syscall.EINVAL (fd types which
-			// don't implement sendfile)
-			err = err1
+			// don't implement sendfile together)
+			err = &OpError{"sendfile", c.net, c.raddr, err1}
 			break
 		}
 	}
 	if lr != nil {
 		lr.N = remain
 	}
-	if err != nil {
-		err = os.NewSyscallError("sendfile", err)
-	}
 	return written, err, written > 0
 }
diff --git a/src/net/sendfile_stub.go b/src/net/sendfile_stub.go
index a0760b4..03426ef 100644
--- a/src/net/sendfile_stub.go
+++ b/src/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 nacl netbsd openbsd
+// +build darwin nacl netbsd openbsd solaris
 
 package net
 
diff --git a/src/net/sendfile_windows.go b/src/net/sendfile_windows.go
index f3f3b54..b128ba2 100644
--- a/src/net/sendfile_windows.go
+++ b/src/net/sendfile_windows.go
@@ -46,7 +46,7 @@ func sendFile(fd *netFD, r io.Reader) (written int64, err error, handled bool) {
 		return syscall.TransmitFile(o.fd.sysfd, o.handle, o.qty, 0, &o.o, nil, syscall.TF_WRITE_BEHIND)
 	})
 	if err != nil {
-		return 0, os.NewSyscallError("transmitfile", err), false
+		return 0, err, false
 	}
 	if lr != nil {
 		lr.N -= int64(done)
diff --git a/src/net/server_test.go b/src/net/server_test.go
index fe0006b..6a2bb92 100644
--- a/src/net/server_test.go
+++ b/src/net/server_test.go
@@ -5,384 +5,457 @@
 package net
 
 import (
+	"flag"
+	"io"
 	"os"
+	"runtime"
 	"testing"
+	"time"
 )
 
-var tcpServerTests = []struct {
-	snet, saddr string // server endpoint
-	tnet, taddr string // target endpoint for client
+func skipServerTest(net, unixsotype, addr string, ipv6, ipv4map, linuxOnly bool) bool {
+	switch runtime.GOOS {
+	case "linux":
+	case "nacl", "plan9", "windows":
+		// "unix" sockets are not supported on Windows and Plan 9.
+		if net == unixsotype {
+			return true
+		}
+	default:
+		if net == unixsotype && linuxOnly {
+			return true
+		}
+	}
+	switch addr {
+	case "", "0.0.0.0", "[::ffff:0.0.0.0]", "[::]":
+		if testing.Short() || !*testExternal {
+			return true
+		}
+	}
+	if ipv6 && !supportsIPv6 {
+		return true
+	}
+	if ipv4map && !supportsIPv4map {
+		return true
+	}
+	return false
+}
+
+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
+	linuxOnly bool // test with abstract unix domain socket, a Linux-ism
 }{
-	{snet: "tcp", saddr: ":0", tnet: "tcp", taddr: "127.0.0.1"},
-	{snet: "tcp", saddr: "0.0.0.0:0", tnet: "tcp", taddr: "127.0.0.1"},
-	{snet: "tcp", saddr: "[::ffff:0.0.0.0]:0", tnet: "tcp", taddr: "127.0.0.1"},
-	{snet: "tcp", saddr: "[::]:0", tnet: "tcp", taddr: "::1"},
+	{snet: "tcp", saddr: "", cnet: "tcp", caddr: "127.0.0.1"},
+	{snet: "tcp", saddr: "0.0.0.0", cnet: "tcp", caddr: "127.0.0.1"},
+	{snet: "tcp", saddr: "[::ffff:0.0.0.0]", cnet: "tcp", caddr: "127.0.0.1"},
+	{snet: "tcp", saddr: "[::]", cnet: "tcp", caddr: "[::1]", ipv6: true},
 
-	{snet: "tcp", saddr: ":0", tnet: "tcp", taddr: "::1"},
-	{snet: "tcp", saddr: "0.0.0.0:0", tnet: "tcp", taddr: "::1"},
-	{snet: "tcp", saddr: "[::ffff:0.0.0.0]:0", tnet: "tcp", taddr: "::1"},
-	{snet: "tcp", saddr: "[::]:0", tnet: "tcp", taddr: "127.0.0.1"},
+	{snet: "tcp", saddr: "", cnet: "tcp", caddr: "[::1]", ipv4map: true},
+	{snet: "tcp", saddr: "0.0.0.0", cnet: "tcp", caddr: "[::1]", ipv4map: true},
+	{snet: "tcp", saddr: "[::ffff:0.0.0.0]", cnet: "tcp", caddr: "[::1]", ipv4map: true},
+	{snet: "tcp", saddr: "[::]", cnet: "tcp", caddr: "127.0.0.1", ipv4map: true},
 
-	{snet: "tcp", saddr: ":0", tnet: "tcp4", taddr: "127.0.0.1"},
-	{snet: "tcp", saddr: "0.0.0.0:0", tnet: "tcp4", taddr: "127.0.0.1"},
-	{snet: "tcp", saddr: "[::ffff:0.0.0.0]:0", tnet: "tcp4", taddr: "127.0.0.1"},
-	{snet: "tcp", saddr: "[::]:0", tnet: "tcp6", taddr: "::1"},
+	{snet: "tcp", saddr: "", cnet: "tcp4", caddr: "127.0.0.1"},
+	{snet: "tcp", saddr: "0.0.0.0", cnet: "tcp4", caddr: "127.0.0.1"},
+	{snet: "tcp", saddr: "[::ffff:0.0.0.0]", cnet: "tcp4", caddr: "127.0.0.1"},
+	{snet: "tcp", saddr: "[::]", cnet: "tcp6", caddr: "[::1]", ipv6: true},
 
-	{snet: "tcp", saddr: ":0", tnet: "tcp6", taddr: "::1"},
-	{snet: "tcp", saddr: "0.0.0.0:0", tnet: "tcp6", taddr: "::1"},
-	{snet: "tcp", saddr: "[::ffff:0.0.0.0]:0", tnet: "tcp6", taddr: "::1"},
-	{snet: "tcp", saddr: "[::]:0", tnet: "tcp4", taddr: "127.0.0.1"},
+	{snet: "tcp", saddr: "", cnet: "tcp6", caddr: "[::1]", ipv4map: true},
+	{snet: "tcp", saddr: "0.0.0.0", cnet: "tcp6", caddr: "[::1]", ipv4map: true},
+	{snet: "tcp", saddr: "[::ffff:0.0.0.0]", cnet: "tcp6", caddr: "[::1]", ipv4map: true},
+	{snet: "tcp", saddr: "[::]", cnet: "tcp4", caddr: "127.0.0.1", ipv4map: true},
 
-	{snet: "tcp", saddr: "127.0.0.1:0", tnet: "tcp", taddr: "127.0.0.1"},
-	{snet: "tcp", saddr: "[::ffff:127.0.0.1]:0", tnet: "tcp", taddr: "127.0.0.1"},
-	{snet: "tcp", saddr: "[::1]:0", tnet: "tcp", taddr: "::1"},
+	{snet: "tcp", saddr: "127.0.0.1", cnet: "tcp", caddr: "127.0.0.1"},
+	{snet: "tcp", saddr: "[::ffff:127.0.0.1]", cnet: "tcp", caddr: "127.0.0.1"},
+	{snet: "tcp", saddr: "[::1]", cnet: "tcp", caddr: "[::1]", ipv6: true},
 
-	{snet: "tcp4", saddr: ":0", tnet: "tcp4", taddr: "127.0.0.1"},
-	{snet: "tcp4", saddr: "0.0.0.0:0", tnet: "tcp4", taddr: "127.0.0.1"},
-	{snet: "tcp4", saddr: "[::ffff:0.0.0.0]:0", tnet: "tcp4", taddr: "127.0.0.1"},
+	{snet: "tcp4", saddr: "", cnet: "tcp4", caddr: "127.0.0.1"},
+	{snet: "tcp4", saddr: "0.0.0.0", cnet: "tcp4", caddr: "127.0.0.1"},
+	{snet: "tcp4", saddr: "[::ffff:0.0.0.0]", cnet: "tcp4", caddr: "127.0.0.1"},
 
-	{snet: "tcp4", saddr: "127.0.0.1:0", tnet: "tcp4", taddr: "127.0.0.1"},
+	{snet: "tcp4", saddr: "127.0.0.1", cnet: "tcp4", caddr: "127.0.0.1"},
 
-	{snet: "tcp6", saddr: ":0", tnet: "tcp6", taddr: "::1"},
-	{snet: "tcp6", saddr: "[::]:0", tnet: "tcp6", taddr: "::1"},
+	{snet: "tcp6", saddr: "", cnet: "tcp6", caddr: "[::1]", ipv6: true},
+	{snet: "tcp6", saddr: "[::]", cnet: "tcp6", caddr: "[::1]", ipv6: true},
 
-	{snet: "tcp6", saddr: "[::1]:0", tnet: "tcp6", taddr: "::1"},
-}
+	{snet: "tcp6", saddr: "[::1]", cnet: "tcp6", caddr: "[::1]", ipv6: true},
 
-// TestTCPServer tests concurrent accept-read-write servers.
-func TestTCPServer(t *testing.T) {
-	const N = 3
+	{snet: "unix", saddr: testUnixAddr(), cnet: "unix", caddr: testUnixAddr()},
+	{snet: "unix", saddr: "@gotest2/net", cnet: "unix", caddr: "@gotest2/net.local", linuxOnly: true},
+}
 
-	for i, tt := range tcpServerTests {
-		if !testableListenArgs(tt.snet, tt.saddr, tt.taddr) {
-			t.Logf("skipping %s test", tt.snet+" "+tt.saddr+"->"+tt.taddr)
+func TestStreamConnServer(t *testing.T) {
+	for _, tt := range streamConnServerTests {
+		if skipServerTest(tt.snet, "unix", tt.saddr, tt.ipv6, tt.ipv4map, tt.linuxOnly) {
 			continue
 		}
 
-		ln, err := Listen(tt.snet, tt.saddr)
-		if err != nil {
-			if perr := parseDialError(err); perr != nil {
-				t.Error(perr)
-			}
-			t.Fatal(err)
+		listening := make(chan string)
+		done := make(chan int)
+		switch tt.snet {
+		case "tcp", "tcp4", "tcp6":
+			tt.saddr += ":0"
+		case "unix":
+			os.Remove(tt.saddr)
+			os.Remove(tt.caddr)
 		}
 
-		var lss []*localServer
-		var tpchs []chan error
-		defer func() {
-			for _, ls := range lss {
-				ls.teardown()
-			}
-		}()
-		for i := 0; i < N; i++ {
-			ls, err := (&streamListener{Listener: ln}).newLocalServer()
-			if err != nil {
-				t.Fatal(err)
-			}
-			lss = append(lss, ls)
-			tpchs = append(tpchs, make(chan error, 1))
-		}
-		for i := 0; i < N; i++ {
-			ch := tpchs[i]
-			handler := func(ls *localServer, ln Listener) { transponder(ln, ch) }
-			if err := lss[i].buildup(handler); err != nil {
-				t.Fatal(err)
-			}
-		}
+		go runStreamConnServer(t, tt.snet, tt.saddr, listening, done)
+		taddr := <-listening // wait for server to start
 
-		var trchs []chan error
-		for i := 0; i < N; i++ {
-			_, port, err := SplitHostPort(lss[i].Listener.Addr().String())
-			if err != nil {
-				t.Fatal(err)
-			}
-			d := Dialer{Timeout: someTimeout}
-			c, err := d.Dial(tt.tnet, JoinHostPort(tt.taddr, port))
+		switch tt.cnet {
+		case "tcp", "tcp4", "tcp6":
+			_, port, err := SplitHostPort(taddr)
 			if err != nil {
-				if perr := parseDialError(err); perr != nil {
-					t.Error(perr)
-				}
-				t.Fatal(err)
+				t.Fatalf("SplitHostPort(%q) failed: %v", taddr, err)
 			}
-			defer c.Close()
-			trchs = append(trchs, make(chan error, 1))
-			go transceiver(c, []byte("TCP SERVER TEST"), trchs[i])
+			taddr = tt.caddr + ":" + port
 		}
 
-		for _, ch := range trchs {
-			for err := range ch {
-				t.Errorf("#%d: %v", i, err)
-			}
-		}
-		for _, ch := range tpchs {
-			for err := range ch {
-				t.Errorf("#%d: %v", i, err)
-			}
+		runStreamConnClient(t, tt.cnet, taddr, tt.empty)
+		<-done // make sure server stopped
+
+		switch tt.snet {
+		case "unix":
+			os.Remove(tt.saddr)
+			os.Remove(tt.caddr)
 		}
 	}
 }
 
-var unixAndUnixpacketServerTests = []struct {
-	network, address string
+var seqpacketConnServerTests = []struct {
+	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
 }{
-	{"unix", testUnixAddr()},
-	{"unix", "@nettest/go/unix"},
-
-	{"unixpacket", testUnixAddr()},
-	{"unixpacket", "@nettest/go/unixpacket"},
+	{net: "unixpacket", saddr: testUnixAddr(), caddr: testUnixAddr()},
+	{net: "unixpacket", saddr: "@gotest4/net", caddr: "@gotest4/net.local", linuxOnly: true},
 }
 
-// TestUnixAndUnixpacketServer tests concurrent accept-read-write
-// servers
-func TestUnixAndUnixpacketServer(t *testing.T) {
-	const N = 3
+func TestSeqpacketConnServer(t *testing.T) {
+	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 i, tt := range unixAndUnixpacketServerTests {
-		if !testableListenArgs(tt.network, tt.address, "") {
-			t.Logf("skipping %s test", tt.network+" "+tt.address)
+	for _, tt := range seqpacketConnServerTests {
+		if runtime.GOOS != "linux" && tt.linuxOnly {
 			continue
 		}
-
-		ln, err := Listen(tt.network, tt.address)
-		if err != nil {
-			if perr := parseDialError(err); perr != nil {
-				t.Error(perr)
-			}
-			t.Fatal(err)
+		listening := make(chan string)
+		done := make(chan int)
+		switch tt.net {
+		case "unixpacket":
+			os.Remove(tt.saddr)
+			os.Remove(tt.caddr)
 		}
 
-		var lss []*localServer
-		var tpchs []chan error
-		defer func() {
-			for _, ls := range lss {
-				ls.teardown()
-			}
-		}()
-		for i := 0; i < N; i++ {
-			ls, err := (&streamListener{Listener: ln}).newLocalServer()
-			if err != nil {
-				t.Fatal(err)
-			}
-			lss = append(lss, ls)
-			tpchs = append(tpchs, make(chan error, 1))
-		}
-		for i := 0; i < N; i++ {
-			ch := tpchs[i]
-			handler := func(ls *localServer, ln Listener) { transponder(ln, ch) }
-			if err := lss[i].buildup(handler); err != nil {
-				t.Fatal(err)
-			}
-		}
+		go runStreamConnServer(t, tt.net, tt.saddr, listening, done)
+		taddr := <-listening // wait for server to start
 
-		var trchs []chan error
-		for i := 0; i < N; i++ {
-			d := Dialer{Timeout: someTimeout}
-			c, err := d.Dial(lss[i].Listener.Addr().Network(), lss[i].Listener.Addr().String())
-			if err != nil {
-				if perr := parseDialError(err); perr != nil {
-					t.Error(perr)
-				}
-				t.Fatal(err)
-			}
-			defer os.Remove(c.LocalAddr().String())
-			defer c.Close()
-			trchs = append(trchs, make(chan error, 1))
-			go transceiver(c, []byte("UNIX AND UNIXPACKET SERVER TEST"), trchs[i])
+		runStreamConnClient(t, tt.net, taddr, tt.empty)
+		<-done // make sure server stopped
+
+		switch tt.net {
+		case "unixpacket":
+			os.Remove(tt.saddr)
+			os.Remove(tt.caddr)
 		}
+	}
+}
 
-		for _, ch := range trchs {
-			for err := range ch {
-				t.Errorf("#%d: %v", i, err)
+func runStreamConnServer(t *testing.T, net, laddr string, listening chan<- string, done chan<- int) {
+	defer close(done)
+	l, err := Listen(net, laddr)
+	if err != nil {
+		t.Errorf("Listen(%q, %q) failed: %v", net, laddr, err)
+		listening <- "<nil>"
+		return
+	}
+	defer l.Close()
+	listening <- l.Addr().String()
+
+	echo := func(rw io.ReadWriter, done chan<- int) {
+		buf := make([]byte, 1024)
+		for {
+			n, err := rw.Read(buf[0:])
+			if err != nil || n == 0 || string(buf[:n]) == "END" {
+				break
 			}
+			rw.Write(buf[0:n])
 		}
-		for _, ch := range tpchs {
-			for err := range ch {
-				t.Errorf("#%d: %v", i, err)
-			}
+		close(done)
+	}
+
+run:
+	for {
+		c, err := l.Accept()
+		if err != nil {
+			t.Logf("Accept failed: %v", err)
+			continue run
 		}
+		echodone := make(chan int)
+		go echo(c, echodone)
+		<-echodone // make sure echo stopped
+		c.Close()
+		break run
 	}
 }
 
-var udpServerTests = []struct {
-	snet, saddr string // server endpoint
-	tnet, taddr string // target endpoint for client
-	dial        bool   // test with Dial
+func runStreamConnClient(t *testing.T, net, taddr string, isEmpty bool) {
+	c, err := Dial(net, taddr)
+	if err != nil {
+		t.Fatalf("Dial(%q, %q) failed: %v", net, taddr, err)
+	}
+	defer c.Close()
+	c.SetReadDeadline(time.Now().Add(1 * time.Second))
+
+	var wb []byte
+	if !isEmpty {
+		wb = []byte("StreamConnClient by Dial\n")
+	}
+	if n, err := c.Write(wb); err != nil || n != len(wb) {
+		t.Fatalf("Write failed: %v, %v; want %v, <nil>", n, err, len(wb))
+	}
+
+	rb := make([]byte, 1024)
+	if n, err := c.Read(rb[0:]); err != nil || n != len(wb) {
+		t.Fatalf("Read failed: %v, %v; want %v, <nil>", n, err, len(wb))
+	}
+
+	// Send explicit ending for unixpacket.
+	// Older Linux kernels do not stop reads on close.
+	switch net {
+	case "unixpacket":
+		c.Write([]byte("END"))
+	}
+}
+
+// Do not test empty datagrams by default.
+// It causes unexplained timeouts on some systems,
+// including Snow Leopard.  I think that the kernel
+// doesn't quite expect them.
+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
+	linuxOnly bool // test with abstract unix domain socket, a Linux-ism
 }{
-	{snet: "udp", saddr: ":0", tnet: "udp", taddr: "127.0.0.1"},
-	{snet: "udp", saddr: "0.0.0.0:0", tnet: "udp", taddr: "127.0.0.1"},
-	{snet: "udp", saddr: "[::ffff:0.0.0.0]:0", tnet: "udp", taddr: "127.0.0.1"},
-	{snet: "udp", saddr: "[::]:0", tnet: "udp", taddr: "::1"},
+	{snet: "udp", saddr: "", cnet: "udp", caddr: "127.0.0.1"},
+	{snet: "udp", saddr: "0.0.0.0", cnet: "udp", caddr: "127.0.0.1"},
+	{snet: "udp", saddr: "[::ffff:0.0.0.0]", cnet: "udp", caddr: "127.0.0.1"},
+	{snet: "udp", saddr: "[::]", cnet: "udp", caddr: "[::1]", ipv6: true},
+
+	{snet: "udp", saddr: "", cnet: "udp", caddr: "[::1]", ipv4map: true},
+	{snet: "udp", saddr: "0.0.0.0", cnet: "udp", caddr: "[::1]", ipv4map: true},
+	{snet: "udp", saddr: "[::ffff:0.0.0.0]", cnet: "udp", caddr: "[::1]", ipv4map: true},
+	{snet: "udp", saddr: "[::]", cnet: "udp", caddr: "127.0.0.1", ipv4map: true},
 
-	{snet: "udp", saddr: ":0", tnet: "udp", taddr: "::1"},
-	{snet: "udp", saddr: "0.0.0.0:0", tnet: "udp", taddr: "::1"},
-	{snet: "udp", saddr: "[::ffff:0.0.0.0]:0", tnet: "udp", taddr: "::1"},
-	{snet: "udp", saddr: "[::]:0", tnet: "udp", taddr: "127.0.0.1"},
+	{snet: "udp", saddr: "", cnet: "udp4", caddr: "127.0.0.1"},
+	{snet: "udp", saddr: "0.0.0.0", cnet: "udp4", caddr: "127.0.0.1"},
+	{snet: "udp", saddr: "[::ffff:0.0.0.0]", cnet: "udp4", caddr: "127.0.0.1"},
+	{snet: "udp", saddr: "[::]", cnet: "udp6", caddr: "[::1]", ipv6: true},
 
-	{snet: "udp", saddr: ":0", tnet: "udp4", taddr: "127.0.0.1"},
-	{snet: "udp", saddr: "0.0.0.0:0", tnet: "udp4", taddr: "127.0.0.1"},
-	{snet: "udp", saddr: "[::ffff:0.0.0.0]:0", tnet: "udp4", taddr: "127.0.0.1"},
-	{snet: "udp", saddr: "[::]:0", tnet: "udp6", taddr: "::1"},
+	{snet: "udp", saddr: "", cnet: "udp6", caddr: "[::1]", ipv4map: true},
+	{snet: "udp", saddr: "0.0.0.0", cnet: "udp6", caddr: "[::1]", ipv4map: true},
+	{snet: "udp", saddr: "[::ffff:0.0.0.0]", cnet: "udp6", caddr: "[::1]", ipv4map: true},
+	{snet: "udp", saddr: "[::]", cnet: "udp4", caddr: "127.0.0.1", ipv4map: true},
 
-	{snet: "udp", saddr: ":0", tnet: "udp6", taddr: "::1"},
-	{snet: "udp", saddr: "0.0.0.0:0", tnet: "udp6", taddr: "::1"},
-	{snet: "udp", saddr: "[::ffff:0.0.0.0]:0", tnet: "udp6", taddr: "::1"},
-	{snet: "udp", saddr: "[::]:0", tnet: "udp4", taddr: "127.0.0.1"},
+	{snet: "udp", saddr: "127.0.0.1", cnet: "udp", caddr: "127.0.0.1"},
+	{snet: "udp", saddr: "[::ffff:127.0.0.1]", cnet: "udp", caddr: "127.0.0.1"},
+	{snet: "udp", saddr: "[::1]", cnet: "udp", caddr: "[::1]", ipv6: true},
 
-	{snet: "udp", saddr: "127.0.0.1:0", tnet: "udp", taddr: "127.0.0.1"},
-	{snet: "udp", saddr: "[::ffff:127.0.0.1]:0", tnet: "udp", taddr: "127.0.0.1"},
-	{snet: "udp", saddr: "[::1]:0", tnet: "udp", taddr: "::1"},
+	{snet: "udp4", saddr: "", cnet: "udp4", caddr: "127.0.0.1"},
+	{snet: "udp4", saddr: "0.0.0.0", cnet: "udp4", caddr: "127.0.0.1"},
+	{snet: "udp4", saddr: "[::ffff:0.0.0.0]", cnet: "udp4", caddr: "127.0.0.1"},
 
-	{snet: "udp4", saddr: ":0", tnet: "udp4", taddr: "127.0.0.1"},
-	{snet: "udp4", saddr: "0.0.0.0:0", tnet: "udp4", taddr: "127.0.0.1"},
-	{snet: "udp4", saddr: "[::ffff:0.0.0.0]:0", tnet: "udp4", taddr: "127.0.0.1"},
+	{snet: "udp4", saddr: "127.0.0.1", cnet: "udp4", caddr: "127.0.0.1"},
 
-	{snet: "udp4", saddr: "127.0.0.1:0", tnet: "udp4", taddr: "127.0.0.1"},
+	{snet: "udp6", saddr: "", cnet: "udp6", caddr: "[::1]", ipv6: true},
+	{snet: "udp6", saddr: "[::]", cnet: "udp6", caddr: "[::1]", ipv6: true},
 
-	{snet: "udp6", saddr: ":0", tnet: "udp6", taddr: "::1"},
-	{snet: "udp6", saddr: "[::]:0", tnet: "udp6", taddr: "::1"},
+	{snet: "udp6", saddr: "[::1]", cnet: "udp6", caddr: "[::1]", ipv6: true},
 
-	{snet: "udp6", saddr: "[::1]:0", tnet: "udp6", taddr: "::1"},
+	{snet: "udp", saddr: "127.0.0.1", cnet: "udp", caddr: "127.0.0.1", dial: true},
+	{snet: "udp", saddr: "127.0.0.1", cnet: "udp", caddr: "127.0.0.1", empty: true},
+	{snet: "udp", saddr: "127.0.0.1", cnet: "udp", caddr: "127.0.0.1", dial: true, empty: true},
 
-	{snet: "udp", saddr: "127.0.0.1:0", tnet: "udp", taddr: "127.0.0.1", dial: true},
+	{snet: "udp", saddr: "[::1]", cnet: "udp", caddr: "[::1]", ipv6: true, dial: true},
+	{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: "udp", saddr: "[::1]:0", tnet: "udp", taddr: "::1", dial: 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", linuxOnly: true},
 }
 
-func TestUDPServer(t *testing.T) {
-	for i, tt := range udpServerTests {
-		if !testableListenArgs(tt.snet, tt.saddr, tt.taddr) {
-			t.Logf("skipping %s test", tt.snet+" "+tt.saddr+"->"+tt.taddr)
+func TestDatagramPacketConnServer(t *testing.T) {
+	if !*testDatagram {
+		return
+	}
+
+	for _, tt := range datagramPacketConnServerTests {
+		if skipServerTest(tt.snet, "unixgram", tt.saddr, tt.ipv6, tt.ipv4map, tt.linuxOnly) {
 			continue
 		}
 
-		c1, err := ListenPacket(tt.snet, tt.saddr)
-		if err != nil {
-			if perr := parseDialError(err); perr != nil {
-				t.Error(perr)
-			}
-			t.Fatal(err)
+		listening := make(chan string)
+		done := make(chan int)
+		switch tt.snet {
+		case "udp", "udp4", "udp6":
+			tt.saddr += ":0"
+		case "unixgram":
+			os.Remove(tt.saddr)
+			os.Remove(tt.caddr)
 		}
 
-		ls, err := (&packetListener{PacketConn: c1}).newLocalServer()
-		if err != nil {
-			t.Fatal(err)
-		}
-		defer ls.teardown()
-		tpch := make(chan error, 1)
-		handler := func(ls *localPacketServer, c PacketConn) { packetTransponder(c, tpch) }
-		if err := ls.buildup(handler); err != nil {
-			t.Fatal(err)
-		}
+		go runDatagramPacketConnServer(t, tt.snet, tt.saddr, listening, done)
+		taddr := <-listening // wait for server to start
 
-		trch := make(chan error, 1)
-		_, port, err := SplitHostPort(ls.PacketConn.LocalAddr().String())
-		if err != nil {
-			t.Fatal(err)
-		}
-		if tt.dial {
-			d := Dialer{Timeout: someTimeout}
-			c2, err := d.Dial(tt.tnet, JoinHostPort(tt.taddr, port))
+		switch tt.cnet {
+		case "udp", "udp4", "udp6":
+			_, port, err := SplitHostPort(taddr)
 			if err != nil {
-				if perr := parseDialError(err); perr != nil {
-					t.Error(perr)
-				}
-				t.Fatal(err)
+				t.Fatalf("SplitHostPort(%q) failed: %v", taddr, err)
 			}
-			defer c2.Close()
-			go transceiver(c2, []byte("UDP SERVER TEST"), trch)
+			taddr = tt.caddr + ":" + port
+			tt.caddr += ":0"
+		}
+		if tt.dial {
+			runDatagramConnClient(t, tt.cnet, tt.caddr, taddr, tt.empty)
 		} else {
-			c2, err := ListenPacket(tt.tnet, JoinHostPort(tt.taddr, "0"))
-			if err != nil {
-				if perr := parseDialError(err); perr != nil {
-					t.Error(perr)
-				}
-				t.Fatal(err)
-			}
-			defer c2.Close()
-			dst, err := ResolveUDPAddr(tt.tnet, JoinHostPort(tt.taddr, port))
-			if err != nil {
-				t.Fatal(err)
-			}
-			go packetTransceiver(c2, []byte("UDP SERVER TEST"), dst, trch)
+			runDatagramPacketConnClient(t, tt.cnet, tt.caddr, taddr, tt.empty)
 		}
+		<-done // tell server to stop
+		<-done // make sure server stopped
 
-		for err := range trch {
-			t.Errorf("#%d: %v", i, err)
-		}
-		for err := range tpch {
-			t.Errorf("#%d: %v", i, err)
+		switch tt.snet {
+		case "unixgram":
+			os.Remove(tt.saddr)
+			os.Remove(tt.caddr)
 		}
 	}
 }
 
-var unixgramServerTests = []struct {
-	saddr string // server endpoint
-	caddr string // client endpoint
-	dial  bool   // test with Dial
-}{
-	{saddr: testUnixAddr(), caddr: testUnixAddr()},
-	{saddr: testUnixAddr(), caddr: testUnixAddr(), dial: true},
-
-	{saddr: "@nettest/go/unixgram/server", caddr: "@nettest/go/unixgram/client"},
-}
-
-func TestUnixgramServer(t *testing.T) {
-	for i, tt := range unixgramServerTests {
-		if !testableListenArgs("unixgram", tt.saddr, "") {
-			t.Logf("skipping %s test", "unixgram "+tt.saddr+"->"+tt.caddr)
-			continue
+func runDatagramPacketConnServer(t *testing.T, net, laddr string, listening chan<- string, done chan<- int) {
+	c, err := ListenPacket(net, laddr)
+	if err != nil {
+		t.Errorf("ListenPacket(%q, %q) failed: %v", net, laddr, err)
+		listening <- "<nil>"
+		done <- 1
+		return
+	}
+	defer c.Close()
+	listening <- c.LocalAddr().String()
+
+	buf := make([]byte, 1024)
+run:
+	for {
+		c.SetReadDeadline(time.Now().Add(10 * time.Millisecond))
+		n, ra, err := c.ReadFrom(buf[0:])
+		if nerr, ok := err.(Error); ok && nerr.Timeout() {
+			select {
+			case done <- 1:
+				break run
+			default:
+				continue run
+			}
 		}
-
-		c1, err := ListenPacket("unixgram", tt.saddr)
 		if err != nil {
-			if perr := parseDialError(err); perr != nil {
-				t.Error(perr)
-			}
-			t.Fatal(err)
+			break run
 		}
+		if _, err = c.WriteTo(buf[0:n], ra); err != nil {
+			t.Errorf("WriteTo(%v) failed: %v", ra, err)
+			break run
+		}
+	}
+	done <- 1
+}
 
-		ls, err := (&packetListener{PacketConn: c1}).newLocalServer()
+func runDatagramConnClient(t *testing.T, net, laddr, taddr string, isEmpty bool) {
+	var c Conn
+	var err error
+	switch net {
+	case "udp", "udp4", "udp6":
+		c, err = Dial(net, taddr)
 		if err != nil {
-			t.Fatal(err)
+			t.Fatalf("Dial(%q, %q) failed: %v", net, taddr, err)
 		}
-		defer ls.teardown()
-		tpch := make(chan error, 1)
-		handler := func(ls *localPacketServer, c PacketConn) { packetTransponder(c, tpch) }
-		if err := ls.buildup(handler); err != nil {
-			t.Fatal(err)
+	case "unixgram":
+		c, err = DialUnix(net, &UnixAddr{Name: laddr, Net: net}, &UnixAddr{Name: taddr, Net: net})
+		if err != nil {
+			t.Fatalf("DialUnix(%q, {%q, %q}) failed: %v", net, laddr, taddr, err)
 		}
+	}
+	defer c.Close()
+	c.SetReadDeadline(time.Now().Add(1 * time.Second))
 
-		trch := make(chan error, 1)
-		if tt.dial {
-			d := Dialer{Timeout: someTimeout, LocalAddr: &UnixAddr{Net: "unixgram", Name: tt.caddr}}
-			c2, err := d.Dial("unixgram", ls.PacketConn.LocalAddr().String())
-			if err != nil {
-				if perr := parseDialError(err); perr != nil {
-					t.Error(perr)
-				}
-				t.Fatal(err)
-			}
-			defer os.Remove(c2.LocalAddr().String())
-			defer c2.Close()
-			go transceiver(c2, []byte(c2.LocalAddr().String()), trch)
-		} else {
-			c2, err := ListenPacket("unixgram", tt.caddr)
-			if err != nil {
-				if perr := parseDialError(err); perr != nil {
-					t.Error(perr)
-				}
-				t.Fatal(err)
-			}
-			defer os.Remove(c2.LocalAddr().String())
-			defer c2.Close()
-			go packetTransceiver(c2, []byte("UNIXGRAM SERVER TEST"), ls.PacketConn.LocalAddr(), trch)
-		}
+	var wb []byte
+	if !isEmpty {
+		wb = []byte("DatagramConnClient by Dial\n")
+	}
+	if n, err := c.Write(wb[0:]); err != nil || n != len(wb) {
+		t.Fatalf("Write failed: %v, %v; want %v, <nil>", n, err, len(wb))
+	}
 
-		for err := range trch {
-			t.Errorf("#%d: %v", i, err)
+	rb := make([]byte, 1024)
+	if n, err := c.Read(rb[0:]); err != nil || n != len(wb) {
+		t.Fatalf("Read failed: %v, %v; want %v, <nil>", n, err, len(wb))
+	}
+}
+
+func runDatagramPacketConnClient(t *testing.T, net, laddr, taddr string, isEmpty bool) {
+	var ra Addr
+	var err error
+	switch net {
+	case "udp", "udp4", "udp6":
+		ra, err = ResolveUDPAddr(net, taddr)
+		if err != nil {
+			t.Fatalf("ResolveUDPAddr(%q, %q) failed: %v", net, taddr, err)
 		}
-		for err := range tpch {
-			t.Errorf("#%d: %v", i, err)
+	case "unixgram":
+		ra, err = ResolveUnixAddr(net, taddr)
+		if err != nil {
+			t.Fatalf("ResolveUxixAddr(%q, %q) failed: %v", net, taddr, err)
 		}
 	}
+	c, err := ListenPacket(net, laddr)
+	if err != nil {
+		t.Fatalf("ListenPacket(%q, %q) faild: %v", net, laddr, err)
+	}
+	defer c.Close()
+	c.SetReadDeadline(time.Now().Add(1 * time.Second))
+
+	var wb []byte
+	if !isEmpty {
+		wb = []byte("DatagramPacketConnClient by ListenPacket\n")
+	}
+	if n, err := c.WriteTo(wb[0:], ra); err != nil || n != len(wb) {
+		t.Fatalf("WriteTo(%v) failed: %v, %v; want %v, <nil>", ra, n, err, len(wb))
+	}
+
+	rb := make([]byte, 1024)
+	if n, _, err := c.ReadFrom(rb[0:]); err != nil || n != len(wb) {
+		t.Fatalf("ReadFrom failed: %v, %v; want %v, <nil>", n, err, len(wb))
+	}
 }
diff --git a/src/net/singleflight.go b/src/net/singleflight.go
new file mode 100644
index 0000000..bf599f0
--- /dev/null
+++ b/src/net/singleflight.go
@@ -0,0 +1,109 @@
+// 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 "sync"
+
+// call is an in-flight or completed singleflight.Do call
+type call struct {
+	wg sync.WaitGroup
+
+	// These fields are written once before the WaitGroup is done
+	// and are only read after the WaitGroup is done.
+	val interface{}
+	err error
+
+	// These fields are read and written with the singleflight
+	// mutex held before the WaitGroup is done, and are read but
+	// not written after the WaitGroup is done.
+	dups  int
+	chans []chan<- singleflightResult
+}
+
+// singleflight represents a class of work and forms a namespace in
+// which units of work can be executed with duplicate suppression.
+type singleflight struct {
+	mu sync.Mutex       // protects m
+	m  map[string]*call // lazily initialized
+}
+
+// singleflightResult holds the results of Do, so they can be passed
+// on a channel.
+type singleflightResult struct {
+	v      interface{}
+	err    error
+	shared bool
+}
+
+// Do executes and returns the results of the given function, making
+// sure that only one execution is in-flight for a given key at a
+// time. If a duplicate comes in, the duplicate caller waits for the
+// original to complete and receives the same results.
+// The return value shared indicates whether v was given to multiple callers.
+func (g *singleflight) Do(key string, fn func() (interface{}, error)) (v interface{}, err error, shared bool) {
+	g.mu.Lock()
+	if g.m == nil {
+		g.m = make(map[string]*call)
+	}
+	if c, ok := g.m[key]; ok {
+		c.dups++
+		g.mu.Unlock()
+		c.wg.Wait()
+		return c.val, c.err, true
+	}
+	c := new(call)
+	c.wg.Add(1)
+	g.m[key] = c
+	g.mu.Unlock()
+
+	g.doCall(c, key, fn)
+	return c.val, c.err, c.dups > 0
+}
+
+// DoChan is like Do but returns a channel that will receive the
+// results when they are ready.
+func (g *singleflight) DoChan(key string, fn func() (interface{}, error)) <-chan singleflightResult {
+	ch := make(chan singleflightResult, 1)
+	g.mu.Lock()
+	if g.m == nil {
+		g.m = make(map[string]*call)
+	}
+	if c, ok := g.m[key]; ok {
+		c.dups++
+		c.chans = append(c.chans, ch)
+		g.mu.Unlock()
+		return ch
+	}
+	c := &call{chans: []chan<- singleflightResult{ch}}
+	c.wg.Add(1)
+	g.m[key] = c
+	g.mu.Unlock()
+
+	go g.doCall(c, key, fn)
+
+	return ch
+}
+
+// doCall handles the single call for a key.
+func (g *singleflight) doCall(c *call, key string, fn func() (interface{}, error)) {
+	c.val, c.err = fn()
+	c.wg.Done()
+
+	g.mu.Lock()
+	delete(g.m, key)
+	for _, ch := range c.chans {
+		ch <- singleflightResult{c.val, c.err, c.dups > 0}
+	}
+	g.mu.Unlock()
+}
+
+// Forget tells the singleflight to forget about a key.  Future calls
+// to Do for this key will call the function rather than waiting for
+// an earlier call to complete.
+func (g *singleflight) Forget(key string) {
+	g.mu.Lock()
+	delete(g.m, key)
+	g.mu.Unlock()
+}
diff --git a/src/net/smtp/example_test.go b/src/net/smtp/example_test.go
index 16419f4..d551e36 100644
--- a/src/net/smtp/example_test.go
+++ b/src/net/smtp/example_test.go
@@ -46,36 +46,14 @@ func Example() {
 	}
 }
 
-// variables to make ExamplePlainAuth compile, without adding
-// unnecessary noise there.
-var (
-	from       = "gopher at example.net"
-	msg        = []byte("dummy message")
-	recipients = []string{"foo at example.com"}
-)
-
 func ExamplePlainAuth() {
-	// hostname is used by PlainAuth to validate the TLS certificate.
-	hostname := "mail.example.com"
-	auth := smtp.PlainAuth("", "user at example.com", "password", hostname)
-
-	err := smtp.SendMail(hostname+":25", auth, from, recipients, msg)
-	if err != nil {
-		log.Fatal(err)
-	}
-}
-
-func ExampleSendMail() {
 	// 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("To: recipient at example.net\r\n" +
-		"Subject: discount Gophers!\r\n" +
-		"\r\n" +
-		"This is the email body.\r\n")
+	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/net/smtp/smtp.go b/src/net/smtp/smtp.go
index 0988350..87dea44 100644
--- a/src/net/smtp/smtp.go
+++ b/src/net/smtp/smtp.go
@@ -41,7 +41,7 @@ type Client struct {
 }
 
 // Dial returns a new Client connected to an SMTP server at addr.
-// The addr must include a port, as in "mail.example.com:smtp".
+// The addr must include a port number.
 func Dial(addr string) (*Client, error) {
 	conn, err := net.Dial("tcp", addr)
 	if err != nil {
@@ -157,17 +157,6 @@ func (c *Client) StartTLS(config *tls.Config) error {
 	return c.ehlo()
 }
 
-// TLSConnectionState returns the client's TLS connection state.
-// The return values are their zero values if StartTLS did
-// not succeed.
-func (c *Client) TLSConnectionState() (state tls.ConnectionState, ok bool) {
-	tc, ok := c.conn.(*tls.Conn)
-	if !ok {
-		return
-	}
-	return tc.ConnectionState(), true
-}
-
 // Verify checks the validity of an email address on the server.
 // If Verify returns nil, the address is valid. A non-nil return
 // does not necessarily indicate an invalid address. Many servers
@@ -264,9 +253,9 @@ func (d *dataCloser) Close() error {
 }
 
 // Data issues a DATA command to the server and returns a writer that
-// can be used to write the mail headers and body. The caller should
-// close the writer before calling any more methods on c.  A call to
-// Data must be preceded by one or more calls to Rcpt.
+// can be used to write the data. The caller should close the writer
+// before calling any more methods on c.
+// A call to Data must be preceded by one or more calls to Rcpt.
 func (c *Client) Data() (io.WriteCloser, error) {
 	_, _, err := c.cmd(354, "DATA")
 	if err != nil {
@@ -281,22 +270,6 @@ var testHookStartTLS func(*tls.Config) // nil, except for tests
 // possible, authenticates with the optional mechanism a if possible,
 // and then sends an email from address from, to addresses to, with
 // message msg.
-// The addr must include a port, as in "mail.example.com:smtp".
-//
-// The addresses in the to parameter are the SMTP RCPT addresses.
-//
-// The msg parameter should be an RFC 822-style email with headers
-// first, a blank line, and then the message body. The lines of msg
-// should be CRLF terminated.  The msg headers should usually include
-// fields such as "From", "To", "Subject", and "Cc".  Sending "Bcc"
-// messages is accomplished by including an email address in the to
-// parameter but not including it in the msg headers.
-//
-// The SendMail function and the the net/smtp package are low-level
-// mechanisms and provide no support for DKIM signing, MIME
-// attachments (see the mime/multipart package), or other mail
-// functionality. Higher-level packages exist outside of the standard
-// library.
 func SendMail(addr string, a Auth, from string, to []string, msg []byte) error {
 	c, err := Dial(addr)
 	if err != nil {
diff --git a/src/net/smtp/smtp_test.go b/src/net/smtp/smtp_test.go
index 3ae0d5b..5c659e8 100644
--- a/src/net/smtp/smtp_test.go
+++ b/src/net/smtp/smtp_test.go
@@ -571,50 +571,6 @@ func TestTLSClient(t *testing.T) {
 	}
 }
 
-func TestTLSConnState(t *testing.T) {
-	ln := newLocalListener(t)
-	defer ln.Close()
-	clientDone := make(chan bool)
-	serverDone := make(chan bool)
-	go func() {
-		defer close(serverDone)
-		c, err := ln.Accept()
-		if err != nil {
-			t.Errorf("Server accept: %v", err)
-			return
-		}
-		defer c.Close()
-		if err := serverHandle(c, t); err != nil {
-			t.Errorf("server error: %v", err)
-		}
-	}()
-	go func() {
-		defer close(clientDone)
-		c, err := Dial(ln.Addr().String())
-		if err != nil {
-			t.Errorf("Client dial: %v", err)
-			return
-		}
-		defer c.Quit()
-		cfg := &tls.Config{ServerName: "example.com"}
-		testHookStartTLS(cfg) // set the RootCAs
-		if err := c.StartTLS(cfg); err != nil {
-			t.Errorf("StartTLS: %v", err)
-			return
-		}
-		cs, ok := c.TLSConnectionState()
-		if !ok {
-			t.Errorf("TLSConnectionState returned ok == false; want true")
-			return
-		}
-		if cs.Version == 0 || !cs.HandshakeComplete {
-			t.Errorf("ConnectionState = %#v; expect non-zero Version and HandshakeComplete", cs)
-		}
-	}()
-	<-clientDone
-	<-serverDone
-}
-
 func newLocalListener(t *testing.T) net.Listener {
 	ln, err := net.Listen("tcp", "127.0.0.1:0")
 	if err != nil {
diff --git a/src/net/sock_cloexec.go b/src/net/sock_cloexec.go
index 616a101..dec8185 100644
--- a/src/net/sock_cloexec.go
+++ b/src/net/sock_cloexec.go
@@ -9,41 +9,34 @@
 
 package net
 
-import (
-	"os"
-	"syscall"
-)
+import "syscall"
 
 // Wrapper around the socket system call that marks the returned file
 // descriptor as nonblocking and close-on-exec.
 func sysSocket(family, sotype, proto int) (int, error) {
-	s, err := socketFunc(family, sotype|syscall.SOCK_NONBLOCK|syscall.SOCK_CLOEXEC, proto)
+	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.
-	switch err {
-	case nil:
-		return s, nil
-	default:
-		return -1, os.NewSyscallError("socket", err)
-	case syscall.EPROTONOSUPPORT, syscall.EINVAL:
+	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 = socketFunc(family, sotype, proto)
+	s, err = syscall.Socket(family, sotype, proto)
 	if err == nil {
 		syscall.CloseOnExec(s)
 	}
 	syscall.ForkLock.RUnlock()
 	if err != nil {
-		return -1, os.NewSyscallError("socket", err)
+		return -1, err
 	}
 	if err = syscall.SetNonblock(s, true); err != nil {
-		closeFunc(s)
-		return -1, os.NewSyscallError("setnonblock", err)
+		syscall.Close(s)
+		return -1, err
 	}
 	return s, nil
 }
@@ -51,16 +44,14 @@ func sysSocket(family, sotype, proto int) (int, error) {
 // Wrapper around the accept system call that marks the returned file
 // descriptor as nonblocking and close-on-exec.
 func accept(s int) (int, syscall.Sockaddr, error) {
-	ns, sa, err := accept4Func(s, syscall.SOCK_NONBLOCK|syscall.SOCK_CLOEXEC)
+	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 {
-	case nil:
-		return ns, sa, nil
-	default: // errors other than the ones listed
-		return -1, sa, os.NewSyscallError("accept4", 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
@@ -72,16 +63,16 @@ func accept(s 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.
-	ns, sa, err = acceptFunc(s)
+	ns, sa, err = syscall.Accept(s)
 	if err == nil {
 		syscall.CloseOnExec(ns)
 	}
 	if err != nil {
-		return -1, nil, os.NewSyscallError("accept", err)
+		return -1, nil, err
 	}
 	if err = syscall.SetNonblock(ns, true); err != nil {
-		closeFunc(ns)
-		return -1, nil, os.NewSyscallError("setnonblock", err)
+		syscall.Close(ns)
+		return -1, nil, err
 	}
 	return ns, sa, nil
 }
diff --git a/src/net/sock_posix.go b/src/net/sock_posix.go
index 4d2cfde..3f956df 100644
--- a/src/net/sock_posix.go
+++ b/src/net/sock_posix.go
@@ -17,6 +17,8 @@ import (
 type sockaddr interface {
 	Addr
 
+	netaddr
+
 	// family returns the platform-dependent address family
 	// identifier.
 	family() int
@@ -40,11 +42,11 @@ func socket(net string, family, sotype, proto int, ipv6only bool, laddr, raddr s
 		return nil, err
 	}
 	if err = setDefaultSockopts(s, family, sotype, ipv6only); err != nil {
-		closeFunc(s)
+		closesocket(s)
 		return nil, err
 	}
 	if fd, err = newFD(s, family, sotype, net); err != nil {
-		closeFunc(s)
+		closesocket(s)
 		return nil, err
 	}
 
@@ -52,7 +54,7 @@ func socket(net string, family, sotype, proto int, ipv6only bool, laddr, raddr s
 	// following applications:
 	//
 	// - An endpoint holder that opens a passive stream
-	//   connection, known as a stream listener
+	//   connenction, known as a stream listener
 	//
 	// - An endpoint holder that opens a destination-unspecific
 	//   datagram connection, known as a datagram listener
@@ -163,7 +165,7 @@ func (fd *netFD) listenStream(laddr sockaddr, backlog int) error {
 			return os.NewSyscallError("bind", err)
 		}
 	}
-	if err := listenFunc(fd.sysfd, backlog); err != nil {
+	if err := syscall.Listen(fd.sysfd, backlog); err != nil {
 		return os.NewSyscallError("listen", err)
 	}
 	if err := fd.init(); err != nil {
diff --git a/src/net/sock_windows.go b/src/net/sock_windows.go
index 888e70b..6ccde3a 100644
--- a/src/net/sock_windows.go
+++ b/src/net/sock_windows.go
@@ -4,10 +4,7 @@
 
 package net
 
-import (
-	"os"
-	"syscall"
-)
+import "syscall"
 
 func maxListenerBacklog() int {
 	// TODO: Implement this
@@ -15,16 +12,13 @@ func maxListenerBacklog() int {
 	return syscall.SOMAXCONN
 }
 
-func sysSocket(family, sotype, proto int) (syscall.Handle, error) {
+func sysSocket(f, t, p int) (syscall.Handle, error) {
 	// See ../syscall/exec_unix.go for description of ForkLock.
 	syscall.ForkLock.RLock()
-	s, err := socketFunc(family, sotype, proto)
+	s, err := syscall.Socket(f, t, p)
 	if err == nil {
 		syscall.CloseOnExec(s)
 	}
 	syscall.ForkLock.RUnlock()
-	if err != nil {
-		return syscall.InvalidHandle, os.NewSyscallError("socket", err)
-	}
-	return s, nil
+	return s, err
 }
diff --git a/src/net/sockopt_bsd.go b/src/net/sockopt_bsd.go
index 1b4a586..00e4dbf 100644
--- a/src/net/sockopt_bsd.go
+++ b/src/net/sockopt_bsd.go
@@ -25,7 +25,7 @@ func setDefaultSockopts(s, family, sotype int, ipv6only bool) error {
 			syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_PORTRANGE, syscall.IPV6_PORTRANGE_HIGH)
 		}
 	}
-	if supportsIPv4map && family == syscall.AF_INET6 && sotype != syscall.SOCK_RAW {
+	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
 		// never admit this option.
diff --git a/src/net/sys_cloexec.go b/src/net/sys_cloexec.go
index ba266e6..898fb7c 100644
--- a/src/net/sys_cloexec.go
+++ b/src/net/sys_cloexec.go
@@ -9,27 +9,24 @@
 
 package net
 
-import (
-	"os"
-	"syscall"
-)
+import "syscall"
 
 // Wrapper around the socket system call that marks the returned file
 // descriptor as nonblocking and close-on-exec.
 func sysSocket(family, sotype, proto int) (int, error) {
 	// See ../syscall/exec_unix.go for description of ForkLock.
 	syscall.ForkLock.RLock()
-	s, err := socketFunc(family, sotype, proto)
+	s, err := syscall.Socket(family, sotype, proto)
 	if err == nil {
 		syscall.CloseOnExec(s)
 	}
 	syscall.ForkLock.RUnlock()
 	if err != nil {
-		return -1, os.NewSyscallError("socket", err)
+		return -1, err
 	}
 	if err = syscall.SetNonblock(s, true); err != nil {
-		closeFunc(s)
-		return -1, os.NewSyscallError("setnonblock", err)
+		syscall.Close(s)
+		return -1, err
 	}
 	return s, nil
 }
@@ -42,16 +39,16 @@ func accept(s 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.
-	ns, sa, err := acceptFunc(s)
+	ns, sa, err := syscall.Accept(s)
 	if err == nil {
 		syscall.CloseOnExec(ns)
 	}
 	if err != nil {
-		return -1, nil, os.NewSyscallError("accept", err)
+		return -1, nil, err
 	}
 	if err = syscall.SetNonblock(ns, true); err != nil {
-		closeFunc(ns)
-		return -1, nil, os.NewSyscallError("setnonblock", err)
+		syscall.Close(ns)
+		return -1, nil, err
 	}
 	return ns, sa, nil
 }
diff --git a/src/net/tcp_test.go b/src/net/tcp_test.go
index 2191c91..c04198e 100644
--- a/src/net/tcp_test.go
+++ b/src/net/tcp_test.go
@@ -5,6 +5,7 @@
 package net
 
 import (
+	"fmt"
 	"io"
 	"reflect"
 	"runtime"
@@ -58,8 +59,6 @@ func BenchmarkTCP6PersistentTimeout(b *testing.B) {
 }
 
 func benchmarkTCP(b *testing.B, persistent, timeout bool, laddr string) {
-	testHookUninstaller.Do(uninstallTestHooks)
-
 	const msgLen = 512
 	conns := b.N
 	numConcurrent := runtime.GOMAXPROCS(-1) * 2
@@ -77,7 +76,7 @@ func benchmarkTCP(b *testing.B, persistent, timeout bool, laddr string) {
 	sendMsg := func(c Conn, buf []byte) bool {
 		n, err := c.Write(buf)
 		if n != len(buf) || err != nil {
-			b.Log(err)
+			b.Logf("Write failed: %v", err)
 			return false
 		}
 		return true
@@ -87,7 +86,7 @@ func benchmarkTCP(b *testing.B, persistent, timeout bool, laddr string) {
 			n, err := c.Read(buf)
 			read += n
 			if err != nil {
-				b.Log(err)
+				b.Logf("Read failed: %v", err)
 				return false
 			}
 		}
@@ -95,7 +94,7 @@ func benchmarkTCP(b *testing.B, persistent, timeout bool, laddr string) {
 	}
 	ln, err := Listen("tcp", laddr)
 	if err != nil {
-		b.Fatal(err)
+		b.Fatalf("Listen failed: %v", err)
 	}
 	defer ln.Close()
 	serverSem := make(chan bool, numConcurrent)
@@ -135,7 +134,7 @@ func benchmarkTCP(b *testing.B, persistent, timeout bool, laddr string) {
 			}()
 			c, err := Dial("tcp", ln.Addr().String())
 			if err != nil {
-				b.Log(err)
+				b.Logf("Dial failed: %v", err)
 				return
 			}
 			defer c.Close()
@@ -168,8 +167,6 @@ func BenchmarkTCP6ConcurrentReadWrite(b *testing.B) {
 }
 
 func benchmarkTCPConcurrentReadWrite(b *testing.B, laddr string) {
-	testHookUninstaller.Do(uninstallTestHooks)
-
 	// The benchmark creates GOMAXPROCS client/server pairs.
 	// Each pair creates 4 goroutines: client reader/writer and server reader/writer.
 	// The benchmark stresses concurrent reading and writing to the same connection.
@@ -186,7 +183,7 @@ func benchmarkTCPConcurrentReadWrite(b *testing.B, laddr string) {
 	servers := make([]Conn, P)
 	ln, err := Listen("tcp", laddr)
 	if err != nil {
-		b.Fatal(err)
+		b.Fatalf("Listen failed: %v", err)
 	}
 	defer ln.Close()
 	done := make(chan bool)
@@ -194,7 +191,7 @@ func benchmarkTCPConcurrentReadWrite(b *testing.B, laddr string) {
 		for p := 0; p < P; p++ {
 			s, err := ln.Accept()
 			if err != nil {
-				b.Error(err)
+				b.Errorf("Accept failed: %v", err)
 				return
 			}
 			servers[p] = s
@@ -204,7 +201,7 @@ func benchmarkTCPConcurrentReadWrite(b *testing.B, laddr string) {
 	for p := 0; p < P; p++ {
 		c, err := Dial("tcp", ln.Addr().String())
 		if err != nil {
-			b.Fatal(err)
+			b.Fatalf("Dial failed: %v", err)
 		}
 		clients[p] = c
 	}
@@ -227,7 +224,7 @@ func benchmarkTCPConcurrentReadWrite(b *testing.B, laddr string) {
 				buf[0] = v
 				_, err := c.Write(buf[:])
 				if err != nil {
-					b.Error(err)
+					b.Errorf("Write failed: %v", err)
 					return
 				}
 			}
@@ -243,7 +240,7 @@ func benchmarkTCPConcurrentReadWrite(b *testing.B, laddr string) {
 			for i := 0; i < N; i++ {
 				_, err := s.Read(buf[:])
 				if err != nil {
-					b.Error(err)
+					b.Errorf("Read failed: %v", err)
 					return
 				}
 				pipe <- buf[0]
@@ -262,7 +259,7 @@ func benchmarkTCPConcurrentReadWrite(b *testing.B, laddr string) {
 				buf[0] = v
 				_, err := s.Write(buf[:])
 				if err != nil {
-					b.Error(err)
+					b.Errorf("Write failed: %v", err)
 					return
 				}
 			}
@@ -276,7 +273,7 @@ func benchmarkTCPConcurrentReadWrite(b *testing.B, laddr string) {
 			for i := 0; i < N; i++ {
 				_, err := c.Read(buf[:])
 				if err != nil {
-					b.Error(err)
+					b.Errorf("Read failed: %v", err)
 					return
 				}
 			}
@@ -287,7 +284,7 @@ func benchmarkTCPConcurrentReadWrite(b *testing.B, laddr string) {
 }
 
 type resolveTCPAddrTest struct {
-	network       string
+	net           string
 	litAddrOrName string
 	addr          *TCPAddr
 	err           error
@@ -297,8 +294,8 @@ var resolveTCPAddrTests = []resolveTCPAddrTest{
 	{"tcp", "127.0.0.1:0", &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 0}, nil},
 	{"tcp4", "127.0.0.1:65535", &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 65535}, nil},
 
-	{"tcp", "[::1]:0", &TCPAddr{IP: ParseIP("::1"), Port: 0}, nil},
-	{"tcp6", "[::1]:65535", &TCPAddr{IP: ParseIP("::1"), Port: 65535}, nil},
+	{"tcp", "[::1]:1", &TCPAddr{IP: ParseIP("::1"), Port: 1}, nil},
+	{"tcp6", "[::1]:65534", &TCPAddr{IP: ParseIP("::1"), Port: 65534}, nil},
 
 	{"tcp", "[::1%en0]:1", &TCPAddr{IP: ParseIP("::1"), Port: 1, Zone: "en0"}, nil},
 	{"tcp6", "[::1%911]:2", &TCPAddr{IP: ParseIP("::1"), Port: 2, Zone: "911"}, nil},
@@ -311,26 +308,41 @@ var resolveTCPAddrTests = []resolveTCPAddrTest{
 	{"http", "127.0.0.1:0", nil, UnknownNetworkError("http")},
 }
 
-func TestResolveTCPAddr(t *testing.T) {
-	origTestHookLookupIP := testHookLookupIP
-	defer func() { testHookLookupIP = origTestHookLookupIP }()
-	testHookLookupIP = lookupLocalhost
+func init() {
+	if ifi := loopbackInterface(); ifi != nil {
+		index := fmt.Sprintf("%v", ifi.Index)
+		resolveTCPAddrTests = append(resolveTCPAddrTests, []resolveTCPAddrTest{
+			{"tcp6", "[fe80::1%" + ifi.Name + "]:3", &TCPAddr{IP: ParseIP("fe80::1"), Port: 3, Zone: zoneToString(ifi.Index)}, nil},
+			{"tcp6", "[fe80::1%" + index + "]:4", &TCPAddr{IP: ParseIP("fe80::1"), Port: 4, Zone: index}, nil},
+		}...)
+	}
+	if ips, err := LookupIP("localhost"); err == nil && len(ips) > 1 && supportsIPv4 && supportsIPv6 {
+		resolveTCPAddrTests = append(resolveTCPAddrTests, []resolveTCPAddrTest{
+			{"tcp", "localhost:5", &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5}, nil},
+			{"tcp4", "localhost:6", &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 6}, nil},
+			{"tcp6", "localhost:7", &TCPAddr{IP: IPv6loopback, Port: 7}, nil},
+		}...)
+	}
+}
 
-	for i, tt := range resolveTCPAddrTests {
-		addr, err := ResolveTCPAddr(tt.network, tt.litAddrOrName)
+func TestResolveTCPAddr(t *testing.T) {
+	for _, tt := range resolveTCPAddrTests {
+		addr, err := ResolveTCPAddr(tt.net, tt.litAddrOrName)
 		if err != tt.err {
-			t.Errorf("#%d: %v", i, err)
-		} else if !reflect.DeepEqual(addr, tt.addr) {
-			t.Errorf("#%d: got %#v; want %#v", i, addr, tt.addr)
+			t.Fatalf("ResolveTCPAddr(%q, %q) failed: %v", tt.net, tt.litAddrOrName, err)
 		}
-		if err != nil {
-			continue
+		if !reflect.DeepEqual(addr, tt.addr) {
+			t.Fatalf("ResolveTCPAddr(%q, %q) = %#v, want %#v", tt.net, tt.litAddrOrName, addr, tt.addr)
 		}
-		rtaddr, err := ResolveTCPAddr(addr.Network(), addr.String())
-		if err != nil {
-			t.Errorf("#%d: %v", i, err)
-		} else if !reflect.DeepEqual(rtaddr, addr) {
-			t.Errorf("#%d: got %#v; want %#v", i, rtaddr, addr)
+		if err == nil {
+			str := addr.String()
+			addr1, err := ResolveTCPAddr(tt.net, str)
+			if err != nil {
+				t.Fatalf("ResolveTCPAddr(%q, %q) [from %q]: %v", tt.net, str, tt.litAddrOrName, err)
+			}
+			if !reflect.DeepEqual(addr1, addr) {
+				t.Fatalf("ResolveTCPAddr(%q, %q) [from %q] = %#v, want %#v", tt.net, str, tt.litAddrOrName, addr1, addr)
+			}
 		}
 	}
 }
@@ -346,13 +358,13 @@ var tcpListenerNameTests = []struct {
 
 func TestTCPListenerName(t *testing.T) {
 	if testing.Short() || !*testExternal {
-		t.Skip("avoid external network")
+		t.Skip("skipping test to avoid external network")
 	}
 
 	for _, tt := range tcpListenerNameTests {
 		ln, err := ListenTCP(tt.net, tt.laddr)
 		if err != nil {
-			t.Fatal(err)
+			t.Fatalf("ListenTCP failed: %v", err)
 		}
 		defer ln.Close()
 		la := ln.Addr()
@@ -364,37 +376,59 @@ func TestTCPListenerName(t *testing.T) {
 
 func TestIPv6LinkLocalUnicastTCP(t *testing.T) {
 	if testing.Short() || !*testExternal {
-		t.Skip("avoid external network")
+		t.Skip("skipping test to avoid external network")
 	}
 	if !supportsIPv6 {
-		t.Skip("IPv6 is not supported")
+		t.Skip("ipv6 is not supported")
+	}
+	ifi := loopbackInterface()
+	if ifi == nil {
+		t.Skip("loopback interface not found")
+	}
+	laddr := ipv6LinkLocalUnicastAddr(ifi)
+	if laddr == "" {
+		t.Skip("ipv6 unicast address on loopback not found")
 	}
 
-	for i, tt := range ipv6LinkLocalUnicastTCPTests {
-		ln, err := Listen(tt.network, tt.address)
+	type test struct {
+		net, addr  string
+		nameLookup bool
+	}
+	var tests = []test{
+		{"tcp", "[" + laddr + "%" + ifi.Name + "]:0", false},
+		{"tcp6", "[" + laddr + "%" + ifi.Name + "]:0", false},
+	}
+	switch runtime.GOOS {
+	case "darwin", "freebsd", "openbsd", "netbsd":
+		tests = append(tests, []test{
+			{"tcp", "[localhost%" + ifi.Name + "]:0", true},
+			{"tcp6", "[localhost%" + ifi.Name + "]:0", true},
+		}...)
+	case "linux":
+		tests = append(tests, []test{
+			{"tcp", "[ip6-localhost%" + ifi.Name + "]:0", true},
+			{"tcp6", "[ip6-localhost%" + ifi.Name + "]:0", true},
+		}...)
+	}
+	for _, tt := range tests {
+		ln, err := Listen(tt.net, tt.addr)
 		if err != nil {
 			// It might return "LookupHost returned no
 			// suitable address" error on some platforms.
-			t.Log(err)
+			t.Logf("Listen failed: %v", err)
 			continue
 		}
-		ls, err := (&streamListener{Listener: ln}).newLocalServer()
-		if err != nil {
-			t.Fatal(err)
-		}
-		defer ls.teardown()
-		ch := make(chan error, 1)
-		handler := func(ls *localServer, ln Listener) { transponder(ln, ch) }
-		if err := ls.buildup(handler); err != nil {
-			t.Fatal(err)
-		}
+		defer ln.Close()
 		if la, ok := ln.Addr().(*TCPAddr); !ok || !tt.nameLookup && la.Zone == "" {
 			t.Fatalf("got %v; expected a proper address with zone identifier", la)
 		}
 
-		c, err := Dial(tt.network, ls.Listener.Addr().String())
+		done := make(chan int)
+		go transponder(t, ln, done)
+
+		c, err := Dial(tt.net, ln.Addr().String())
 		if err != nil {
-			t.Fatal(err)
+			t.Fatalf("Dial failed: %v", err)
 		}
 		defer c.Close()
 		if la, ok := c.LocalAddr().(*TCPAddr); !ok || !tt.nameLookup && la.Zone == "" {
@@ -405,16 +439,14 @@ func TestIPv6LinkLocalUnicastTCP(t *testing.T) {
 		}
 
 		if _, err := c.Write([]byte("TCP OVER IPV6 LINKLOCAL TEST")); err != nil {
-			t.Fatal(err)
+			t.Fatalf("Conn.Write failed: %v", err)
 		}
 		b := make([]byte, 32)
 		if _, err := c.Read(b); err != nil {
-			t.Fatal(err)
+			t.Fatalf("Conn.Read failed: %v", err)
 		}
 
-		for err := range ch {
-			t.Errorf("#%d: %v", i, err)
-		}
+		<-done
 	}
 }
 
@@ -422,7 +454,7 @@ func TestTCPConcurrentAccept(t *testing.T) {
 	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4))
 	ln, err := Listen("tcp", "127.0.0.1:0")
 	if err != nil {
-		t.Fatal(err)
+		t.Fatalf("Listen failed: %v", err)
 	}
 	const N = 10
 	var wg sync.WaitGroup
@@ -460,19 +492,13 @@ func TestTCPConcurrentAccept(t *testing.T) {
 	}
 }
 
-func TestTCPReadWriteAllocs(t *testing.T) {
-	switch runtime.GOOS {
-	case "nacl", "windows":
-		// NaCl needs to allocate pseudo file descriptor
-		// stuff. See syscall/fd_nacl.go.
-		// Windows uses closures and channels for IO
-		// completion port-based netpoll. See fd_windows.go.
-		t.Skipf("not supported on %s", runtime.GOOS)
+func TestTCPReadWriteMallocs(t *testing.T) {
+	if testing.Short() {
+		t.Skip("skipping malloc count in short mode")
 	}
-
 	ln, err := Listen("tcp", "127.0.0.1:0")
 	if err != nil {
-		t.Fatal(err)
+		t.Fatalf("Listen failed: %v", err)
 	}
 	defer ln.Close()
 	var server Conn
@@ -484,26 +510,25 @@ func TestTCPReadWriteAllocs(t *testing.T) {
 	}()
 	client, err := Dial("tcp", ln.Addr().String())
 	if err != nil {
-		t.Fatal(err)
+		t.Fatalf("Dial failed: %v", err)
 	}
-	defer client.Close()
 	if err := <-errc; err != nil {
-		t.Fatal(err)
+		t.Fatalf("Accept failed: %v", err)
 	}
 	defer server.Close()
 	var buf [128]byte
-	allocs := testing.AllocsPerRun(1000, func() {
+	mallocs := testing.AllocsPerRun(1000, func() {
 		_, err := server.Write(buf[:])
 		if err != nil {
-			t.Fatal(err)
+			t.Fatalf("Write failed: %v", err)
 		}
 		_, err = io.ReadFull(client, buf[:])
 		if err != nil {
-			t.Fatal(err)
+			t.Fatalf("Read failed: %v", err)
 		}
 	})
-	if allocs > 0 {
-		t.Fatalf("got %v; want 0", allocs)
+	if mallocs > 0 {
+		t.Fatalf("Got %v allocs, want 0", mallocs)
 	}
 }
 
@@ -518,7 +543,7 @@ func TestTCPStress(t *testing.T) {
 	sendMsg := func(c Conn, buf []byte) bool {
 		n, err := c.Write(buf)
 		if n != len(buf) || err != nil {
-			t.Log(err)
+			t.Logf("Write failed: %v", err)
 			return false
 		}
 		return true
@@ -528,7 +553,7 @@ func TestTCPStress(t *testing.T) {
 			n, err := c.Read(buf)
 			read += n
 			if err != nil {
-				t.Log(err)
+				t.Logf("Read failed: %v", err)
 				return false
 			}
 		}
@@ -537,7 +562,7 @@ func TestTCPStress(t *testing.T) {
 
 	ln, err := Listen("tcp", "127.0.0.1:0")
 	if err != nil {
-		t.Fatal(err)
+		t.Fatalf("Listen failed: %v", err)
 	}
 	defer ln.Close()
 	// Acceptor.
@@ -568,7 +593,7 @@ func TestTCPStress(t *testing.T) {
 			}()
 			c, err := Dial("tcp", ln.Addr().String())
 			if err != nil {
-				t.Log(err)
+				t.Logf("Dial failed: %v", err)
 				return
 			}
 			defer c.Close()
diff --git a/src/net/tcpsock.go b/src/net/tcpsock.go
index 8765aff..f3dfbd2 100644
--- a/src/net/tcpsock.go
+++ b/src/net/tcpsock.go
@@ -25,14 +25,7 @@ func (a *TCPAddr) String() string {
 	return JoinHostPort(ip, itoa(a.Port))
 }
 
-func (a *TCPAddr) isWildcard() bool {
-	if a == nil || a.IP == nil {
-		return true
-	}
-	return a.IP.IsUnspecified()
-}
-
-func (a *TCPAddr) opAddr() Addr {
+func (a *TCPAddr) toAddr() Addr {
 	if a == nil {
 		return nil
 	}
@@ -53,9 +46,9 @@ func ResolveTCPAddr(net, addr string) (*TCPAddr, error) {
 	default:
 		return nil, UnknownNetworkError(net)
 	}
-	addrs, err := internetAddrList(net, addr, noDeadline)
+	a, err := resolveInternetAddr(net, addr, noDeadline)
 	if err != nil {
 		return nil, err
 	}
-	return addrs.first(isIPv4).(*TCPAddr), nil
+	return a.toAddr().(*TCPAddr), nil
 }
diff --git a/src/net/tcpsock_plan9.go b/src/net/tcpsock_plan9.go
index 9f23703..52019d7 100644
--- a/src/net/tcpsock_plan9.go
+++ b/src/net/tcpsock_plan9.go
@@ -23,11 +23,7 @@ func newTCPConn(fd *netFD) *TCPConn {
 
 // ReadFrom implements the io.ReaderFrom ReadFrom method.
 func (c *TCPConn) ReadFrom(r io.Reader) (int64, error) {
-	n, err := genericReadFrom(c, r)
-	if err != nil && err != io.EOF {
-		err = &OpError{Op: "read", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
-	}
-	return n, err
+	return genericReadFrom(c, r)
 }
 
 // CloseRead shuts down the reading side of the TCP connection.
@@ -36,11 +32,7 @@ func (c *TCPConn) CloseRead() error {
 	if !c.ok() {
 		return syscall.EINVAL
 	}
-	err := c.fd.closeRead()
-	if err != nil {
-		err = &OpError{Op: "close", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
-	}
-	return err
+	return c.fd.closeRead()
 }
 
 // CloseWrite shuts down the writing side of the TCP connection.
@@ -49,11 +41,7 @@ func (c *TCPConn) CloseWrite() error {
 	if !c.ok() {
 		return syscall.EINVAL
 	}
-	err := c.fd.closeWrite()
-	if err != nil {
-		err = &OpError{Op: "close", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
-	}
-	return err
+	return c.fd.closeWrite()
 }
 
 // SetLinger sets the behavior of Close on a connection which still
@@ -69,7 +57,7 @@ func (c *TCPConn) CloseWrite() error {
 // some operating systems after sec seconds have elapsed any remaining
 // unsent data may be discarded.
 func (c *TCPConn) SetLinger(sec int) error {
-	return &OpError{Op: "set", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: syscall.EPLAN9}
+	return syscall.EPLAN9
 }
 
 // SetKeepAlive sets whether the operating system should send
@@ -78,10 +66,7 @@ func (c *TCPConn) SetKeepAlive(keepalive bool) error {
 	if !c.ok() {
 		return syscall.EPLAN9
 	}
-	if err := setKeepAlive(c.fd, keepalive); err != nil {
-		return &OpError{Op: "set", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
-	}
-	return nil
+	return setKeepAlive(c.fd, keepalive)
 }
 
 // SetKeepAlivePeriod sets period between keep alives.
@@ -89,10 +74,7 @@ func (c *TCPConn) SetKeepAlivePeriod(d time.Duration) error {
 	if !c.ok() {
 		return syscall.EPLAN9
 	}
-	if err := setKeepAlivePeriod(c.fd, d); err != nil {
-		return &OpError{Op: "set", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
-	}
-	return nil
+	return setKeepAlivePeriod(c.fd, d)
 }
 
 // SetNoDelay controls whether the operating system should delay
@@ -100,7 +82,7 @@ func (c *TCPConn) SetKeepAlivePeriod(d time.Duration) error {
 // algorithm).  The default is true (no delay), meaning that data is
 // sent as soon as possible after a Write.
 func (c *TCPConn) SetNoDelay(noDelay bool) error {
-	return &OpError{Op: "set", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: syscall.EPLAN9}
+	return syscall.EPLAN9
 }
 
 // DialTCP connects to the remote address raddr on the network net,
@@ -117,10 +99,10 @@ func dialTCP(net string, laddr, raddr *TCPAddr, deadline time.Time) (*TCPConn, e
 	switch net {
 	case "tcp", "tcp4", "tcp6":
 	default:
-		return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: UnknownNetworkError(net)}
+		return nil, &OpError{"dial", net, raddr, UnknownNetworkError(net)}
 	}
 	if raddr == nil {
-		return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: nil, Err: errMissingAddress}
+		return nil, &OpError{"dial", net, nil, errMissingAddress}
 	}
 	fd, err := dialPlan9(net, laddr, raddr)
 	if err != nil {
@@ -169,18 +151,12 @@ func (l *TCPListener) Close() error {
 	}
 	if _, err := l.fd.ctl.WriteString("hangup"); err != nil {
 		l.fd.ctl.Close()
-		return &OpError{Op: "close", Net: l.fd.dir, Source: nil, Addr: l.fd.laddr, Err: err}
+		return &OpError{"close", l.fd.ctl.Name(), l.fd.laddr, err}
 	}
-	err := l.fd.ctl.Close()
-	if err != nil {
-		err = &OpError{Op: "close", Net: l.fd.dir, Source: nil, Addr: l.fd.laddr, Err: err}
-	}
-	return err
+	return l.fd.ctl.Close()
 }
 
 // Addr returns the listener's network address, a *TCPAddr.
-// The Addr returned is shared by all invocations of Addr, so
-// do not modify it.
 func (l *TCPListener) Addr() Addr { return l.fd.laddr }
 
 // SetDeadline sets the deadline associated with the listener.
@@ -189,10 +165,7 @@ func (l *TCPListener) SetDeadline(t time.Time) error {
 	if l == nil || l.fd == nil || l.fd.ctl == nil {
 		return syscall.EINVAL
 	}
-	if err := l.fd.setDeadline(t); err != nil {
-		return &OpError{Op: "set", Net: l.fd.dir, Source: nil, Addr: l.fd.laddr, Err: err}
-	}
-	return nil
+	return l.fd.setDeadline(t)
 }
 
 // File returns a copy of the underlying os.File, set to blocking
@@ -202,13 +175,7 @@ func (l *TCPListener) SetDeadline(t time.Time) error {
 // The returned os.File's file descriptor is different from the
 // connection's.  Attempting to change properties of the original
 // using this duplicate may or may not have the desired effect.
-func (l *TCPListener) File() (f *os.File, err error) {
-	f, err = l.dup()
-	if err != nil {
-		err = &OpError{Op: "file", Net: l.fd.dir, Source: nil, Addr: l.fd.laddr, Err: err}
-	}
-	return
-}
+func (l *TCPListener) File() (f *os.File, err error) { return l.dup() }
 
 // ListenTCP announces on the TCP address laddr and returns a TCP
 // listener.  Net must be "tcp", "tcp4", or "tcp6".  If laddr has a
@@ -218,7 +185,7 @@ func ListenTCP(net string, laddr *TCPAddr) (*TCPListener, error) {
 	switch net {
 	case "tcp", "tcp4", "tcp6":
 	default:
-		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: UnknownNetworkError(net)}
+		return nil, &OpError{"listen", net, laddr, UnknownNetworkError(net)}
 	}
 	if laddr == nil {
 		laddr = &TCPAddr{}
diff --git a/src/net/tcpsock_posix.go b/src/net/tcpsock_posix.go
index 7e49b76..dd78aef 100644
--- a/src/net/tcpsock_posix.go
+++ b/src/net/tcpsock_posix.go
@@ -13,6 +13,11 @@ import (
 	"time"
 )
 
+// BUG(rsc): On OpenBSD, listening on the "tcp" network does not listen for
+// both IPv4 and IPv6 connections. This is due to the fact that IPv4 traffic
+// will not be routed to an IPv6 socket - two separate sockets are required
+// if both AFs are to be supported. See inet6(4) on OpenBSD for details.
+
 func sockaddrToTCP(sa syscall.Sockaddr) Addr {
 	switch sa := sa.(type) {
 	case *syscall.SockaddrInet4:
@@ -33,6 +38,13 @@ func (a *TCPAddr) family() int {
 	return syscall.AF_INET6
 }
 
+func (a *TCPAddr) isWildcard() bool {
+	if a == nil || a.IP == nil {
+		return true
+	}
+	return a.IP.IsUnspecified()
+}
+
 func (a *TCPAddr) sockaddr(family int) (syscall.Sockaddr, error) {
 	if a == nil {
 		return nil, nil
@@ -48,23 +60,16 @@ type TCPConn struct {
 
 func newTCPConn(fd *netFD) *TCPConn {
 	c := &TCPConn{conn{fd}}
-	setNoDelay(c.fd, true)
+	c.SetNoDelay(true)
 	return c
 }
 
 // ReadFrom implements the io.ReaderFrom ReadFrom method.
 func (c *TCPConn) ReadFrom(r io.Reader) (int64, error) {
 	if n, err, handled := sendFile(c.fd, r); handled {
-		if err != nil && err != io.EOF {
-			err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
-		}
 		return n, err
 	}
-	n, err := genericReadFrom(c, r)
-	if err != nil && err != io.EOF {
-		err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
-	}
-	return n, err
+	return genericReadFrom(c, r)
 }
 
 // CloseRead shuts down the reading side of the TCP connection.
@@ -73,11 +78,7 @@ func (c *TCPConn) CloseRead() error {
 	if !c.ok() {
 		return syscall.EINVAL
 	}
-	err := c.fd.closeRead()
-	if err != nil {
-		err = &OpError{Op: "close", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
-	}
-	return err
+	return c.fd.closeRead()
 }
 
 // CloseWrite shuts down the writing side of the TCP connection.
@@ -86,11 +87,7 @@ func (c *TCPConn) CloseWrite() error {
 	if !c.ok() {
 		return syscall.EINVAL
 	}
-	err := c.fd.closeWrite()
-	if err != nil {
-		err = &OpError{Op: "close", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
-	}
-	return err
+	return c.fd.closeWrite()
 }
 
 // SetLinger sets the behavior of Close on a connection which still
@@ -109,10 +106,7 @@ func (c *TCPConn) SetLinger(sec int) error {
 	if !c.ok() {
 		return syscall.EINVAL
 	}
-	if err := setLinger(c.fd, sec); err != nil {
-		return &OpError{Op: "set", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
-	}
-	return nil
+	return setLinger(c.fd, sec)
 }
 
 // SetKeepAlive sets whether the operating system should send
@@ -121,10 +115,7 @@ func (c *TCPConn) SetKeepAlive(keepalive bool) error {
 	if !c.ok() {
 		return syscall.EINVAL
 	}
-	if err := setKeepAlive(c.fd, keepalive); err != nil {
-		return &OpError{Op: "set", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
-	}
-	return nil
+	return setKeepAlive(c.fd, keepalive)
 }
 
 // SetKeepAlivePeriod sets period between keep alives.
@@ -132,10 +123,7 @@ func (c *TCPConn) SetKeepAlivePeriod(d time.Duration) error {
 	if !c.ok() {
 		return syscall.EINVAL
 	}
-	if err := setKeepAlivePeriod(c.fd, d); err != nil {
-		return &OpError{Op: "set", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
-	}
-	return nil
+	return setKeepAlivePeriod(c.fd, d)
 }
 
 // SetNoDelay controls whether the operating system should delay
@@ -146,10 +134,7 @@ func (c *TCPConn) SetNoDelay(noDelay bool) error {
 	if !c.ok() {
 		return syscall.EINVAL
 	}
-	if err := setNoDelay(c.fd, noDelay); err != nil {
-		return &OpError{Op: "set", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
-	}
-	return nil
+	return setNoDelay(c.fd, noDelay)
 }
 
 // DialTCP connects to the remote address raddr on the network net,
@@ -159,10 +144,10 @@ func DialTCP(net string, laddr, raddr *TCPAddr) (*TCPConn, error) {
 	switch net {
 	case "tcp", "tcp4", "tcp6":
 	default:
-		return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: UnknownNetworkError(net)}
+		return nil, &OpError{Op: "dial", Net: net, Addr: raddr, Err: UnknownNetworkError(net)}
 	}
 	if raddr == nil {
-		return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: nil, Err: errMissingAddress}
+		return nil, &OpError{Op: "dial", Net: net, Addr: nil, Err: errMissingAddress}
 	}
 	return dialTCP(net, laddr, raddr, noDeadline)
 }
@@ -185,7 +170,7 @@ func dialTCP(net string, laddr, raddr *TCPAddr, deadline time.Time) (*TCPConn, e
 	// see this happen, rather than expose the buggy effect to users, we
 	// close the fd and try again.  If it happens twice more, we relent and
 	// use the result.  See also:
-	//	https://golang.org/issue/2690
+	//	http://golang.org/issue/2690
 	//	http://stackoverflow.com/questions/4949858/
 	//
 	// The opposite can also happen: if we ask the kernel to pick an appropriate
@@ -202,7 +187,7 @@ func dialTCP(net string, laddr, raddr *TCPAddr, deadline time.Time) (*TCPConn, e
 	}
 
 	if err != nil {
-		return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: err}
+		return nil, &OpError{Op: "dial", Net: net, Addr: raddr, Err: err}
 	}
 	return newTCPConn(fd), nil
 }
@@ -230,13 +215,8 @@ func selfConnect(fd *netFD, err error) bool {
 }
 
 func spuriousENOTAVAIL(err error) bool {
-	if op, ok := err.(*OpError); ok {
-		err = op.Err
-	}
-	if sys, ok := err.(*os.SyscallError); ok {
-		err = sys.Err
-	}
-	return err == syscall.EADDRNOTAVAIL
+	e, ok := err.(*OpError)
+	return ok && e.Err == syscall.EADDRNOTAVAIL
 }
 
 // TCPListener is a TCP network listener.  Clients should typically
@@ -253,7 +233,7 @@ func (l *TCPListener) AcceptTCP() (*TCPConn, error) {
 	}
 	fd, err := l.fd.accept()
 	if err != nil {
-		return nil, &OpError{Op: "accept", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
+		return nil, err
 	}
 	return newTCPConn(fd), nil
 }
@@ -274,16 +254,10 @@ func (l *TCPListener) Close() error {
 	if l == nil || l.fd == nil {
 		return syscall.EINVAL
 	}
-	err := l.fd.Close()
-	if err != nil {
-		err = &OpError{Op: "close", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
-	}
-	return err
+	return l.fd.Close()
 }
 
 // Addr returns the listener's network address, a *TCPAddr.
-// The Addr returned is shared by all invocations of Addr, so
-// do not modify it.
 func (l *TCPListener) Addr() Addr { return l.fd.laddr }
 
 // SetDeadline sets the deadline associated with the listener.
@@ -292,10 +266,7 @@ func (l *TCPListener) SetDeadline(t time.Time) error {
 	if l == nil || l.fd == nil {
 		return syscall.EINVAL
 	}
-	if err := l.fd.setDeadline(t); err != nil {
-		return &OpError{Op: "set", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
-	}
-	return nil
+	return l.fd.setDeadline(t)
 }
 
 // File returns a copy of the underlying os.File, set to blocking
@@ -305,13 +276,7 @@ func (l *TCPListener) SetDeadline(t time.Time) error {
 // The returned os.File's file descriptor is different from the
 // connection's.  Attempting to change properties of the original
 // using this duplicate may or may not have the desired effect.
-func (l *TCPListener) File() (f *os.File, err error) {
-	f, err = l.fd.dup()
-	if err != nil {
-		err = &OpError{Op: "file", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
-	}
-	return
-}
+func (l *TCPListener) File() (f *os.File, err error) { return l.fd.dup() }
 
 // ListenTCP announces on the TCP address laddr and returns a TCP
 // listener.  Net must be "tcp", "tcp4", or "tcp6".  If laddr has a
@@ -321,14 +286,14 @@ func ListenTCP(net string, laddr *TCPAddr) (*TCPListener, error) {
 	switch net {
 	case "tcp", "tcp4", "tcp6":
 	default:
-		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: UnknownNetworkError(net)}
+		return nil, &OpError{Op: "listen", Net: net, Addr: laddr, Err: UnknownNetworkError(net)}
 	}
 	if laddr == nil {
 		laddr = &TCPAddr{}
 	}
 	fd, err := internetSocket(net, laddr, nil, noDeadline, syscall.SOCK_STREAM, 0, "listen")
 	if err != nil {
-		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr, Err: err}
+		return nil, &OpError{Op: "listen", Net: net, Addr: laddr, Err: err}
 	}
 	return &TCPListener{fd}, nil
 }
diff --git a/src/net/tcpsockopt_plan9.go b/src/net/tcpsockopt_plan9.go
index 9abe186..0e7a664 100644
--- a/src/net/tcpsockopt_plan9.go
+++ b/src/net/tcpsockopt_plan9.go
@@ -7,13 +7,12 @@
 package net
 
 import (
-	"strconv"
 	"time"
 )
 
 // Set keep alive period.
 func setKeepAlivePeriod(fd *netFD, d time.Duration) error {
-	cmd := "keepalive " + strconv.Itoa(int(d/time.Millisecond))
+	cmd := "keepalive " + string(int64(d/time.Millisecond))
 	_, e := fd.ctl.WriteAt([]byte(cmd), 0)
 	return e
 }
diff --git a/src/net/tcpsockopt_unix.go b/src/net/tcpsockopt_unix.go
index c8970d1..c9f604c 100644
--- a/src/net/tcpsockopt_unix.go
+++ b/src/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 freebsd linux netbsd
+// +build freebsd linux netbsd solaris
 
 package net
 
diff --git a/src/net/tcpsockopt_windows.go b/src/net/tcpsockopt_windows.go
index ae2d7c8..091f523 100644
--- a/src/net/tcpsockopt_windows.go
+++ b/src/net/tcpsockopt_windows.go
@@ -28,5 +28,5 @@ func setKeepAlivePeriod(fd *netFD, d time.Duration) error {
 	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)
+	return os.NewSyscallError("WSAIoctl", err)
 }
diff --git a/src/net/testdata/hosts_singleline b/src/net/testdata/hosts_singleline
new file mode 100644
index 0000000..5f5f74a
--- /dev/null
+++ b/src/net/testdata/hosts_singleline
@@ -0,0 +1 @@
+127.0.0.2	odin
\ No newline at end of file
diff --git a/src/net/textproto/reader.go b/src/net/textproto/reader.go
index 91303fe..eea9207 100644
--- a/src/net/textproto/reader.go
+++ b/src/net/textproto/reader.go
@@ -13,6 +13,10 @@ import (
 	"strings"
 )
 
+// BUG(rsc): To let callers manage exposure to denial of service
+// attacks, Reader should allow them to set and reset a limit on
+// the number of bytes read from the connection.
+
 // A Reader implements convenience methods for reading requests
 // or responses from a text protocol network connection.
 type Reader struct {
@@ -22,10 +26,6 @@ type Reader struct {
 }
 
 // NewReader returns a new Reader reading from r.
-//
-// To avoid denial of service attacks, the provided bufio.Reader
-// should be reading from an io.LimitReader or similar Reader to bound
-// the size of responses.
 func NewReader(r *bufio.Reader) *Reader {
 	return &Reader{R: r}
 }
@@ -485,13 +485,6 @@ func (r *Reader) ReadMIMEHeader() (MIMEHeader, error) {
 		}
 		key := canonicalMIMEHeaderKey(kv[:endKey])
 
-		// As per RFC 7230 field-name is a token, tokens consist of one or more chars.
-		// We could return a ProtocolError here, but better to be liberal in what we
-		// accept, so if we get an empty key, skip it.
-		if key == "" {
-			continue
-		}
-
 		// Skip initial spaces in value.
 		i++ // skip colon
 		for i < len(kv) && (kv[i] == ' ' || kv[i] == '\t') {
@@ -547,16 +540,11 @@ func (r *Reader) upcomingHeaderNewlines() (n int) {
 // the rest are converted to lowercase.  For example, the
 // canonical key for "accept-encoding" is "Accept-Encoding".
 // MIME header keys are assumed to be ASCII only.
-// If s contains a space or invalid header field bytes, it is
-// returned without modifications.
 func CanonicalMIMEHeaderKey(s string) string {
 	// Quick check for canonical encoding.
 	upper := true
 	for i := 0; i < len(s); i++ {
 		c := s[i]
-		if !validHeaderFieldByte(c) {
-			return s
-		}
 		if upper && 'a' <= c && c <= 'z' {
 			return canonicalMIMEHeaderKey([]byte(s))
 		}
@@ -570,44 +558,19 @@ func CanonicalMIMEHeaderKey(s string) string {
 
 const toLower = 'a' - 'A'
 
-// validHeaderFieldByte reports whether b is a valid byte in a header
-// field key. This is actually stricter than RFC 7230, which says:
-//   tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "." /
-//           "^" / "_" / "`" / "|" / "~" / DIGIT / ALPHA
-//   token = 1*tchar
-// TODO: revisit in Go 1.6+ and possibly expand this. But note that many
-// servers have historically dropped '_' to prevent ambiguities when mapping
-// to CGI environment variables.
-func validHeaderFieldByte(b byte) bool {
-	return ('A' <= b && b <= 'Z') ||
-		('a' <= b && b <= 'z') ||
-		('0' <= b && b <= '9') ||
-		b == '-'
-}
-
 // canonicalMIMEHeaderKey is like CanonicalMIMEHeaderKey but is
 // allowed to mutate the provided byte slice before returning the
 // string.
-//
-// For invalid inputs (if a contains spaces or non-token bytes), a
-// is unchanged and a string copy is returned.
 func canonicalMIMEHeaderKey(a []byte) string {
-	// See if a looks like a header key. If not, return it unchanged.
-	for _, c := range a {
-		if validHeaderFieldByte(c) {
-			continue
-		}
-		// Don't canonicalize.
-		return string(a)
-	}
-
 	upper := true
 	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.
-		if upper && 'a' <= c && c <= 'z' {
+		if c == ' ' {
+			c = '-'
+		} else if upper && 'a' <= c && c <= 'z' {
 			c -= toLower
 		} else if !upper && 'A' <= c && c <= 'Z' {
 			c += toLower
diff --git a/src/net/textproto/reader_test.go b/src/net/textproto/reader_test.go
index 8fce7dd..cbc0ed1 100644
--- a/src/net/textproto/reader_test.go
+++ b/src/net/textproto/reader_test.go
@@ -24,14 +24,11 @@ var canonicalHeaderKeyTests = []canonicalHeaderKeyTest{
 	{"uSER-aGENT", "User-Agent"},
 	{"user-agent", "User-Agent"},
 	{"USER-AGENT", "User-Agent"},
-
-	// Non-ASCII or anything with spaces or non-token chars is unchanged:
-	{"üser-agenT", "üser-agenT"},
-	{"a B", "a B"},
+	{"üser-agenT", "üser-Agent"}, // non-ASCII unchanged
 
 	// This caused a panic due to mishandling of a space:
-	{"C Ontent-Transfer-Encoding", "C Ontent-Transfer-Encoding"},
-	{"foo bar", "foo bar"},
+	{"C Ontent-Transfer-Encoding", "C-Ontent-Transfer-Encoding"},
+	{"foo bar", "Foo-Bar"},
 }
 
 func TestCanonicalMIMEHeaderKey(t *testing.T) {
@@ -156,15 +153,6 @@ func TestReadMIMEHeaderSingle(t *testing.T) {
 	}
 }
 
-func TestReadMIMEHeaderNoKey(t *testing.T) {
-	r := reader(": bar\ntest-1: 1\n\n")
-	m, err := r.ReadMIMEHeader()
-	want := MIMEHeader{"Test-1": {"1"}}
-	if !reflect.DeepEqual(m, want) || err != nil {
-		t.Fatalf("ReadMIMEHeader: %v, %v; want %v", m, err, want)
-	}
-}
-
 func TestLargeReadMIMEHeader(t *testing.T) {
 	data := make([]byte, 16*1024)
 	for i := 0; i < len(data); i++ {
@@ -197,7 +185,7 @@ func TestReadMIMEHeaderNonCompliant(t *testing.T) {
 		"Foo":              {"bar"},
 		"Content-Language": {"en"},
 		"Sid":              {"0"},
-		"Audio Mode":       {"None"},
+		"Audio-Mode":       {"None"},
 		"Privilege":        {"127"},
 	}
 	if !reflect.DeepEqual(m, want) || err != nil {
diff --git a/src/net/timeout_test.go b/src/net/timeout_test.go
index ca94e24..9ef0c4d 100644
--- a/src/net/timeout_test.go
+++ b/src/net/timeout_test.go
@@ -8,788 +8,448 @@ import (
 	"fmt"
 	"io"
 	"io/ioutil"
-	"net/internal/socktest"
 	"runtime"
-	"sync"
 	"testing"
 	"time"
 )
 
-var dialTimeoutTests = []struct {
-	timeout time.Duration
-	delta   time.Duration // for deadline
-
-	guard time.Duration
-	max   time.Duration
-}{
-	// Tests that dial timeouts, deadlines in the past work.
-	{-5 * time.Second, 0, -5 * time.Second, 100 * time.Millisecond},
-	{0, -5 * time.Second, -5 * time.Second, 100 * time.Millisecond},
-	{-5 * time.Second, 5 * time.Second, -5 * time.Second, 100 * time.Millisecond}, // timeout over deadline
-
-	{50 * time.Millisecond, 0, 100 * time.Millisecond, time.Second},
-	{0, 50 * time.Millisecond, 100 * time.Millisecond, time.Second},
-	{50 * time.Millisecond, 5 * time.Second, 100 * time.Millisecond, time.Second}, // timeout over deadline
+func isTimeout(err error) bool {
+	e, ok := err.(Error)
+	return ok && e.Timeout()
 }
 
-func TestDialTimeout(t *testing.T) {
-	origTestHookDialChannel := testHookDialChannel
-	defer func() { testHookDialChannel = origTestHookDialChannel }()
-	defer sw.Set(socktest.FilterConnect, nil)
-
-	// Avoid tracking open-close jitterbugs between netFD and
-	// socket that leads to confusion of information inside
-	// socktest.Switch.
-	// It may happen when the Dial call bumps against TCP
-	// simultaneous open. See selfConnect in tcpsock_posix.go.
-	defer func() {
-		sw.Set(socktest.FilterClose, nil)
-		forceCloseSockets()
-	}()
-	sw.Set(socktest.FilterClose, func(so *socktest.Status) (socktest.AfterFilter, error) {
-		return nil, errTimedout
-	})
-
-	for i, tt := range dialTimeoutTests {
-		switch runtime.GOOS {
-		case "plan9", "windows":
-			testHookDialChannel = func() { time.Sleep(tt.guard) }
-			if runtime.GOOS == "plan9" {
-				break
-			}
-			fallthrough
-		default:
-			sw.Set(socktest.FilterConnect, func(so *socktest.Status) (socktest.AfterFilter, error) {
-				time.Sleep(tt.guard)
-				return nil, errTimedout
-			})
-		}
-
-		ch := make(chan error)
-		d := Dialer{Timeout: tt.timeout}
-		if tt.delta != 0 {
-			d.Deadline = time.Now().Add(tt.delta)
-		}
-		max := time.NewTimer(tt.max)
-		defer max.Stop()
-		go func() {
-			// This dial never starts to send any TCP SYN
-			// segment because of above socket filter and
-			// test hook.
-			c, err := d.Dial("tcp", "127.0.0.1:0")
-			if err == nil {
-				err = fmt.Errorf("unexpectedly established: tcp:%s->%s", c.LocalAddr(), c.RemoteAddr())
-				c.Close()
-			}
-			ch <- err
-		}()
-
-		select {
-		case <-max.C:
-			t.Fatalf("#%d: Dial didn't return in an expected time", i)
-		case err := <-ch:
-			if perr := parseDialError(err); perr != nil {
-				t.Errorf("#%d: %v", i, perr)
-			}
-			if nerr, ok := err.(Error); !ok || !nerr.Timeout() {
-				t.Fatalf("#%d: %v", i, err)
-			}
-		}
-	}
-}
-
-var acceptTimeoutTests = []struct {
-	timeout time.Duration
-	xerrs   [2]error // expected errors in transition
-}{
-	// Tests that accept deadlines in the past work, even if
-	// there's incoming connections available.
-	{-5 * time.Second, [2]error{errTimeout, errTimeout}},
-
-	{50 * time.Millisecond, [2]error{nil, errTimeout}},
+type copyRes struct {
+	n   int64
+	err error
+	d   time.Duration
 }
 
 func TestAcceptTimeout(t *testing.T) {
 	switch runtime.GOOS {
 	case "plan9":
-		t.Skipf("not supported on %s", runtime.GOOS)
+		t.Skipf("skipping test on %q", runtime.GOOS)
 	}
 
-	ln, err := newLocalListener("tcp")
-	if err != nil {
-		t.Fatal(err)
-	}
+	ln := newLocalListener(t).(*TCPListener)
 	defer ln.Close()
-
-	for i, tt := range acceptTimeoutTests {
-		if tt.timeout < 0 {
-			go func() {
-				c, err := Dial(ln.Addr().Network(), ln.Addr().String())
-				if err != nil {
-					t.Error(err)
-					return
-				}
-				var b [1]byte
-				c.Read(b[:])
-				c.Close()
-			}()
-		}
-
-		if err := ln.(*TCPListener).SetDeadline(time.Now().Add(tt.timeout)); err != nil {
-			t.Fatalf("$%d: %v", i, err)
-		}
-		for j, xerr := range tt.xerrs {
-			for {
-				c, err := ln.Accept()
-				if xerr != nil {
-					if perr := parseAcceptError(err); perr != nil {
-						t.Errorf("#%d/%d: %v", i, j, perr)
-					}
-					if nerr, ok := err.(Error); !ok || !nerr.Timeout() {
-						t.Fatalf("#%d/%d: %v", i, j, err)
-					}
-				}
-				if err == nil {
-					c.Close()
-					time.Sleep(tt.timeout / 3)
-					continue
-				}
-				break
-			}
-		}
+	ln.SetDeadline(time.Now().Add(-1 * time.Second))
+	if _, err := ln.Accept(); !isTimeout(err) {
+		t.Fatalf("Accept: expected err %v, got %v", errTimeout, err)
 	}
-}
-
-func TestAcceptTimeoutMustReturn(t *testing.T) {
-	switch runtime.GOOS {
-	case "plan9":
-		t.Skipf("not supported on %s", runtime.GOOS)
+	if _, err := ln.Accept(); !isTimeout(err) {
+		t.Fatalf("Accept: expected err %v, got %v", errTimeout, err)
 	}
-
-	ln, err := newLocalListener("tcp")
-	if err != nil {
-		t.Fatal(err)
+	ln.SetDeadline(time.Now().Add(100 * time.Millisecond))
+	if _, err := ln.Accept(); !isTimeout(err) {
+		t.Fatalf("Accept: expected err %v, got %v", errTimeout, err)
 	}
-	defer ln.Close()
-
-	max := time.NewTimer(time.Second)
-	defer max.Stop()
-	ch := make(chan error)
+	if _, err := ln.Accept(); !isTimeout(err) {
+		t.Fatalf("Accept: expected err %v, got %v", errTimeout, err)
+	}
+	ln.SetDeadline(noDeadline)
+	errc := make(chan error)
 	go func() {
-		if err := ln.(*TCPListener).SetDeadline(noDeadline); err != nil {
-			t.Error(err)
-		}
-		if err := ln.(*TCPListener).SetDeadline(time.Now().Add(10 * time.Millisecond)); err != nil {
-			t.Error(err)
-		}
-		c, err := ln.Accept()
-		if err == nil {
-			c.Close()
-		}
-		ch <- err
+		_, err := ln.Accept()
+		errc <- err
 	}()
-
+	time.Sleep(100 * time.Millisecond)
 	select {
-	case <-max.C:
-		ln.Close()
-		<-ch // wait for tester goroutine to stop
-		t.Fatal("Accept didn't return in an expected time")
-	case err := <-ch:
-		if perr := parseAcceptError(err); perr != nil {
-			t.Error(perr)
+	case err := <-errc:
+		t.Fatalf("Expected Accept() to not return, but it returned with %v\n", err)
+	default:
+	}
+	ln.Close()
+	switch nerr := <-errc; err := nerr.(type) {
+	case *OpError:
+		if err.Err != errClosing {
+			t.Fatalf("Accept: expected err %v, got %v", errClosing, err)
 		}
-		if nerr, ok := err.(Error); !ok || !nerr.Timeout() {
-			t.Fatal(err)
+	default:
+		if err != errClosing {
+			t.Fatalf("Accept: expected err %v, got %v", errClosing, err)
 		}
 	}
 }
 
-func TestAcceptTimeoutMustNotReturn(t *testing.T) {
+func TestReadTimeout(t *testing.T) {
 	switch runtime.GOOS {
 	case "plan9":
-		t.Skipf("not supported on %s", runtime.GOOS)
+		t.Skipf("skipping test on %q", runtime.GOOS)
 	}
 
-	ln, err := newLocalListener("tcp")
+	ln := newLocalListener(t)
+	defer ln.Close()
+	c, err := DialTCP("tcp", nil, ln.Addr().(*TCPAddr))
 	if err != nil {
-		t.Fatal(err)
+		t.Fatalf("Connect: %v", err)
 	}
-	defer ln.Close()
-
-	max := time.NewTimer(100 * time.Millisecond)
-	defer max.Stop()
-	ch := make(chan error)
+	defer c.Close()
+	c.SetDeadline(time.Now().Add(time.Hour))
+	c.SetReadDeadline(time.Now().Add(-1 * time.Second))
+	buf := make([]byte, 1)
+	if _, err = c.Read(buf); !isTimeout(err) {
+		t.Fatalf("Read: expected err %v, got %v", errTimeout, err)
+	}
+	if _, err = c.Read(buf); !isTimeout(err) {
+		t.Fatalf("Read: expected err %v, got %v", errTimeout, err)
+	}
+	c.SetDeadline(time.Now().Add(100 * time.Millisecond))
+	if _, err = c.Read(buf); !isTimeout(err) {
+		t.Fatalf("Read: expected err %v, got %v", errTimeout, err)
+	}
+	if _, err = c.Read(buf); !isTimeout(err) {
+		t.Fatalf("Read: expected err %v, got %v", errTimeout, err)
+	}
+	c.SetReadDeadline(noDeadline)
+	c.SetWriteDeadline(time.Now().Add(-1 * time.Second))
+	errc := make(chan error)
 	go func() {
-		if err := ln.(*TCPListener).SetDeadline(time.Now().Add(-5 * time.Second)); err != nil {
-			t.Error(err)
-		}
-		if err := ln.(*TCPListener).SetDeadline(noDeadline); err != nil {
-			t.Error(err)
-		}
-		_, err := ln.Accept()
-		ch <- err
+		_, err := c.Read(buf)
+		errc <- err
 	}()
-
+	time.Sleep(100 * time.Millisecond)
 	select {
-	case err := <-ch:
-		if perr := parseAcceptError(err); perr != nil {
-			t.Error(perr)
+	case err := <-errc:
+		t.Fatalf("Expected Read() to not return, but it returned with %v\n", err)
+	default:
+	}
+	c.Close()
+	switch nerr := <-errc; err := nerr.(type) {
+	case *OpError:
+		if err.Err != errClosing {
+			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)
 		}
-		t.Fatalf("expected Accept to not return, but it returned with %v", err)
-	case <-max.C:
-		ln.Close()
-		<-ch // wait for tester goroutine to stop
 	}
 }
 
-var readTimeoutTests = []struct {
-	timeout time.Duration
-	xerrs   [2]error // expected errors in transition
-}{
-	// Tests that read deadlines work, even if there's data ready
-	// to be read.
-	{-5 * time.Second, [2]error{errTimeout, errTimeout}},
-
-	{50 * time.Millisecond, [2]error{nil, errTimeout}},
-}
-
-func TestReadTimeout(t *testing.T) {
+func TestWriteTimeout(t *testing.T) {
 	switch runtime.GOOS {
 	case "plan9":
-		t.Skipf("not supported on %s", runtime.GOOS)
+		t.Skipf("skipping test on %q", runtime.GOOS)
 	}
 
-	handler := func(ls *localServer, ln Listener) {
-		c, err := ln.Accept()
-		if err != nil {
-			t.Error(err)
-			return
-		}
-		c.Write([]byte("READ TIMEOUT TEST"))
-		defer c.Close()
-	}
-	ls, err := newLocalServer("tcp")
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer ls.teardown()
-	if err := ls.buildup(handler); err != nil {
-		t.Fatal(err)
-	}
-
-	c, err := Dial(ls.Listener.Addr().Network(), ls.Listener.Addr().String())
+	ln := newLocalListener(t)
+	defer ln.Close()
+	c, err := DialTCP("tcp", nil, ln.Addr().(*TCPAddr))
 	if err != nil {
-		t.Fatal(err)
+		t.Fatalf("Connect: %v", err)
 	}
 	defer c.Close()
-
-	for i, tt := range readTimeoutTests {
-		if err := c.SetReadDeadline(time.Now().Add(tt.timeout)); err != nil {
-			t.Fatalf("#%d: %v", i, err)
-		}
-		var b [1]byte
-		for j, xerr := range tt.xerrs {
-			for {
-				n, err := c.Read(b[:])
-				if xerr != nil {
-					if perr := parseReadError(err); perr != nil {
-						t.Errorf("#%d/%d: %v", i, j, perr)
-					}
-					if nerr, ok := err.(Error); !ok || !nerr.Timeout() {
-						t.Fatalf("#%d/%d: %v", i, j, err)
-					}
-				}
-				if err == nil {
-					time.Sleep(tt.timeout / 3)
-					continue
-				}
-				if n != 0 {
-					t.Fatalf("#%d/%d: read %d; want 0", i, j, n)
+	c.SetDeadline(time.Now().Add(time.Hour))
+	c.SetWriteDeadline(time.Now().Add(-1 * time.Second))
+	buf := make([]byte, 4096)
+	writeUntilTimeout := func() {
+		for {
+			_, err := c.Write(buf)
+			if err != nil {
+				if isTimeout(err) {
+					return
 				}
-				break
+				t.Fatalf("Write: expected err %v, got %v", errTimeout, err)
 			}
 		}
 	}
-}
-
-func TestReadTimeoutMustNotReturn(t *testing.T) {
-	switch runtime.GOOS {
-	case "plan9":
-		t.Skipf("not supported on %s", runtime.GOOS)
+	writeUntilTimeout()
+	c.SetDeadline(time.Now().Add(10 * time.Millisecond))
+	writeUntilTimeout()
+	writeUntilTimeout()
+	c.SetWriteDeadline(noDeadline)
+	c.SetReadDeadline(time.Now().Add(-1 * time.Second))
+	errc := make(chan error)
+	go func() {
+		for {
+			_, err := c.Write(buf)
+			if err != nil {
+				errc <- err
+			}
+		}
+	}()
+	time.Sleep(100 * time.Millisecond)
+	select {
+	case err := <-errc:
+		t.Fatalf("Expected Write() to not return, but it returned with %v\n", err)
+	default:
 	}
-
-	ln, err := newLocalListener("tcp")
-	if err != nil {
-		t.Fatal(err)
+	c.Close()
+	switch nerr := <-errc; err := nerr.(type) {
+	case *OpError:
+		if err.Err != errClosing {
+			t.Fatalf("Write: expected err %v, got %v", errClosing, err)
+		}
+	default:
+		if err != errClosing {
+			t.Fatalf("Write: expected err %v, got %v", errClosing, err)
+		}
 	}
-	defer ln.Close()
+}
 
-	c, err := Dial(ln.Addr().Network(), ln.Addr().String())
+func testTimeout(t *testing.T, net, addr string, readFrom bool) {
+	c, err := Dial(net, addr)
 	if err != nil {
-		t.Fatal(err)
+		t.Errorf("Dial(%q, %q) failed: %v", net, addr, err)
+		return
 	}
 	defer c.Close()
+	what := "Read"
+	if readFrom {
+		what = "ReadFrom"
+	}
 
-	max := time.NewTimer(100 * time.Millisecond)
-	defer max.Stop()
-	ch := make(chan error)
+	errc := make(chan error, 1)
 	go func() {
-		if err := c.SetDeadline(time.Now().Add(-5 * time.Second)); err != nil {
-			t.Error(err)
-		}
-		if err := c.SetWriteDeadline(time.Now().Add(-5 * time.Second)); err != nil {
-			t.Error(err)
+		t0 := time.Now()
+		c.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
+		var b [100]byte
+		var n int
+		var err error
+		if readFrom {
+			n, _, err = c.(PacketConn).ReadFrom(b[0:])
+		} else {
+			n, err = c.Read(b[0:])
+		}
+		t1 := time.Now()
+		if n != 0 || err == nil || !err.(Error).Timeout() {
+			errc <- fmt.Errorf("%s(%q, %q) did not return 0, timeout: %v, %v", what, net, addr, n, err)
+			return
 		}
-		if err := c.SetReadDeadline(noDeadline); err != nil {
-			t.Error(err)
+		if dt := t1.Sub(t0); dt < 50*time.Millisecond || !testing.Short() && dt > 250*time.Millisecond {
+			errc <- fmt.Errorf("%s(%q, %q) took %s, expected 0.1s", what, net, addr, dt)
+			return
 		}
-		var b [1]byte
-		_, err := c.Read(b[:])
-		ch <- err
+		errc <- nil
 	}()
-
 	select {
-	case err := <-ch:
-		if perr := parseReadError(err); perr != nil {
-			t.Error(perr)
-		}
-		t.Fatalf("expected Read to not return, but it returned with %v", err)
-	case <-max.C:
-		c.Close()
-		err := <-ch // wait for tester goroutine to stop
-		if perr := parseReadError(err); perr != nil {
-			t.Error(perr)
-		}
-		if err == io.EOF && runtime.GOOS == "nacl" { // see golang.org/issue/8044
-			return
-		}
-		if nerr, ok := err.(Error); !ok || nerr.Timeout() || nerr.Temporary() {
-			t.Fatal(err)
+	case err := <-errc:
+		if err != nil {
+			t.Error(err)
 		}
+	case <-time.After(1 * time.Second):
+		t.Errorf("%s(%q, %q) took over 1 second, expected 0.1s", what, net, addr)
 	}
 }
 
-var readFromTimeoutTests = []struct {
-	timeout time.Duration
-	xerrs   [2]error // expected errors in transition
-}{
-	// Tests that read deadlines work, even if there's data ready
-	// to be read.
-	{-5 * time.Second, [2]error{errTimeout, errTimeout}},
-
-	{50 * time.Millisecond, [2]error{nil, errTimeout}},
-}
-
-func TestReadFromTimeout(t *testing.T) {
+func TestTimeoutUDP(t *testing.T) {
 	switch runtime.GOOS {
-	case "nacl", "plan9":
-		t.Skipf("not supported on %s", runtime.GOOS) // see golang.org/issue/8916
-	}
-
-	ch := make(chan Addr)
-	defer close(ch)
-	handler := func(ls *localPacketServer, c PacketConn) {
-		if dst, ok := <-ch; ok {
-			c.WriteTo([]byte("READFROM TIMEOUT TEST"), dst)
-		}
-	}
-	ls, err := newLocalPacketServer("udp")
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer ls.teardown()
-	if err := ls.buildup(handler); err != nil {
-		t.Fatal(err)
-	}
-
-	host, _, err := SplitHostPort(ls.PacketConn.LocalAddr().String())
-	if err != nil {
-		t.Fatal(err)
-	}
-	c, err := ListenPacket(ls.PacketConn.LocalAddr().Network(), JoinHostPort(host, "0"))
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer c.Close()
-	ch <- c.LocalAddr()
-
-	for i, tt := range readFromTimeoutTests {
-		if err := c.SetReadDeadline(time.Now().Add(tt.timeout)); err != nil {
-			t.Fatalf("#%d: %v", i, err)
-		}
-		var b [1]byte
-		for j, xerr := range tt.xerrs {
-			for {
-				n, _, err := c.ReadFrom(b[:])
-				if xerr != nil {
-					if perr := parseReadError(err); perr != nil {
-						t.Errorf("#%d/%d: %v", i, j, perr)
-					}
-					if nerr, ok := err.(Error); !ok || !nerr.Timeout() {
-						t.Fatalf("#%d/%d: %v", i, j, err)
-					}
-				}
-				if err == nil {
-					time.Sleep(tt.timeout / 3)
-					continue
-				}
-				if n != 0 {
-					t.Fatalf("#%d/%d: read %d; want 0", i, j, n)
-				}
-				break
-			}
-		}
+	case "plan9":
+		t.Skipf("skipping test on %q", runtime.GOOS)
 	}
-}
 
-var writeTimeoutTests = []struct {
-	timeout time.Duration
-	xerrs   [2]error // expected errors in transition
-}{
-	// Tests that write deadlines work, even if there's buffer
-	// space available to write.
-	{-5 * time.Second, [2]error{errTimeout, errTimeout}},
+	// set up a listener that won't talk back
+	listening := make(chan string)
+	done := make(chan int)
+	go runDatagramPacketConnServer(t, "udp", "127.0.0.1:0", listening, done)
+	addr := <-listening
 
-	{10 * time.Millisecond, [2]error{nil, errTimeout}},
+	testTimeout(t, "udp", addr, false)
+	testTimeout(t, "udp", addr, true)
+	<-done
 }
 
-func TestWriteTimeout(t *testing.T) {
+func TestTimeoutTCP(t *testing.T) {
 	switch runtime.GOOS {
 	case "plan9":
-		t.Skipf("not supported on %s", runtime.GOOS)
-	}
-
-	ln, err := newLocalListener("tcp")
-	if err != nil {
-		t.Fatal(err)
+		t.Skipf("skipping test on %q", runtime.GOOS)
 	}
-	defer ln.Close()
 
-	for i, tt := range writeTimeoutTests {
-		c, err := Dial(ln.Addr().Network(), ln.Addr().String())
-		if err != nil {
-			t.Fatal(err)
-		}
-		defer c.Close()
+	// set up a listener that won't talk back
+	listening := make(chan string)
+	done := make(chan int)
+	go runStreamConnServer(t, "tcp", "127.0.0.1:0", listening, done)
+	addr := <-listening
 
-		if err := c.SetWriteDeadline(time.Now().Add(tt.timeout)); err != nil {
-			t.Fatalf("#%d: %v", i, err)
-		}
-		for j, xerr := range tt.xerrs {
-			for {
-				n, err := c.Write([]byte("WRITE TIMEOUT TEST"))
-				if xerr != nil {
-					if perr := parseWriteError(err); perr != nil {
-						t.Errorf("#%d/%d: %v", i, j, perr)
-					}
-					if nerr, ok := err.(Error); !ok || !nerr.Timeout() {
-						t.Fatalf("#%d/%d: %v", i, j, err)
-					}
-				}
-				if err == nil {
-					time.Sleep(tt.timeout / 3)
-					continue
-				}
-				if n != 0 {
-					t.Fatalf("#%d/%d: wrote %d; want 0", i, j, n)
-				}
-				break
-			}
-		}
-	}
+	testTimeout(t, "tcp", addr, false)
+	<-done
 }
 
-func TestWriteTimeoutMustNotReturn(t *testing.T) {
+func TestDeadlineReset(t *testing.T) {
 	switch runtime.GOOS {
 	case "plan9":
-		t.Skipf("not supported on %s", runtime.GOOS)
+		t.Skipf("skipping test on %q", runtime.GOOS)
 	}
-
-	ln, err := newLocalListener("tcp")
+	ln, err := Listen("tcp", "127.0.0.1:0")
 	if err != nil {
 		t.Fatal(err)
 	}
 	defer ln.Close()
-
-	c, err := Dial(ln.Addr().Network(), ln.Addr().String())
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer c.Close()
-
-	max := time.NewTimer(100 * time.Millisecond)
-	defer max.Stop()
-	ch := make(chan error)
+	tl := ln.(*TCPListener)
+	tl.SetDeadline(time.Now().Add(1 * time.Minute))
+	tl.SetDeadline(noDeadline) // reset it
+	errc := make(chan error, 1)
 	go func() {
-		if err := c.SetDeadline(time.Now().Add(-5 * time.Second)); err != nil {
-			t.Error(err)
-		}
-		if err := c.SetReadDeadline(time.Now().Add(-5 * time.Second)); err != nil {
-			t.Error(err)
-		}
-		if err := c.SetWriteDeadline(noDeadline); err != nil {
-			t.Error(err)
-		}
-		var b [1]byte
-		for {
-			if _, err := c.Write(b[:]); err != nil {
-				ch <- err
-				break
-			}
-		}
+		_, err := ln.Accept()
+		errc <- err
 	}()
-
 	select {
-	case err := <-ch:
-		if perr := parseWriteError(err); perr != nil {
-			t.Error(perr)
-		}
-		t.Fatalf("expected Write to not return, but it returned with %v", err)
-	case <-max.C:
-		c.Close()
-		err := <-ch // wait for tester goroutine to stop
-		if perr := parseWriteError(err); perr != nil {
-			t.Error(perr)
-		}
-		if nerr, ok := err.(Error); !ok || nerr.Timeout() || nerr.Temporary() {
-			t.Fatal(err)
-		}
+	case <-time.After(50 * time.Millisecond):
+		// Pass.
+	case err := <-errc:
+		// Accept should never return; we never
+		// connected to it.
+		t.Errorf("unexpected return from Accept; err=%v", err)
 	}
 }
 
-var writeToTimeoutTests = []struct {
-	timeout time.Duration
-	xerrs   [2]error // expected errors in transition
-}{
-	// Tests that write deadlines work, even if there's buffer
-	// space available to write.
-	{-5 * time.Second, [2]error{errTimeout, errTimeout}},
-
-	{10 * time.Millisecond, [2]error{nil, errTimeout}},
-}
-
-func TestWriteToTimeout(t *testing.T) {
-	switch runtime.GOOS {
-	case "nacl", "plan9":
-		t.Skipf("not supported on %s", runtime.GOOS)
-	}
-
-	c1, err := newLocalPacketListener("udp")
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer c1.Close()
-
-	host, _, err := SplitHostPort(c1.LocalAddr().String())
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	for i, tt := range writeToTimeoutTests {
-		c2, err := ListenPacket(c1.LocalAddr().Network(), JoinHostPort(host, "0"))
-		if err != nil {
-			t.Fatal(err)
-		}
-		defer c2.Close()
-
-		if err := c2.SetWriteDeadline(time.Now().Add(tt.timeout)); err != nil {
-			t.Fatalf("#%d: %v", i, err)
-		}
-		for j, xerr := range tt.xerrs {
-			for {
-				n, err := c2.WriteTo([]byte("WRITETO TIMEOUT TEST"), c1.LocalAddr())
-				if xerr != nil {
-					if perr := parseWriteError(err); perr != nil {
-						t.Errorf("#%d/%d: %v", i, j, perr)
-					}
-					if nerr, ok := err.(Error); !ok || !nerr.Timeout() {
-						t.Fatalf("#%d/%d: %v", i, j, err)
-					}
-				}
-				if err == nil {
-					time.Sleep(tt.timeout / 3)
-					continue
-				}
-				if n != 0 {
-					t.Fatalf("#%d/%d: wrote %d; want 0", i, j, n)
-				}
-				break
-			}
-		}
-	}
-}
-
-func TestReadTimeoutFluctuation(t *testing.T) {
+func TestTimeoutAccept(t *testing.T) {
 	switch runtime.GOOS {
 	case "plan9":
-		t.Skipf("not supported on %s", runtime.GOOS)
+		t.Skipf("skipping test on %q", runtime.GOOS)
 	}
-
-	ln, err := newLocalListener("tcp")
+	ln, err := Listen("tcp", "127.0.0.1:0")
 	if err != nil {
 		t.Fatal(err)
 	}
 	defer ln.Close()
-
-	c, err := Dial(ln.Addr().Network(), ln.Addr().String())
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer c.Close()
-
-	max := time.NewTimer(time.Second)
-	defer max.Stop()
-	ch := make(chan error)
-	go timeoutReceiver(c, 100*time.Millisecond, 50*time.Millisecond, 250*time.Millisecond, ch)
-
+	tl := ln.(*TCPListener)
+	tl.SetDeadline(time.Now().Add(100 * time.Millisecond))
+	errc := make(chan error, 1)
+	go func() {
+		_, err := ln.Accept()
+		errc <- err
+	}()
 	select {
-	case <-max.C:
-		t.Fatal("Read took over 1s; expected 0.1s")
-	case err := <-ch:
-		if perr := parseReadError(err); perr != nil {
-			t.Error(perr)
-		}
-		if nerr, ok := err.(Error); !ok || !nerr.Timeout() {
-			t.Fatal(err)
-		}
+	case <-time.After(1 * time.Second):
+		// Accept shouldn't block indefinitely
+		t.Errorf("Accept didn't return in an expected time")
+	case <-errc:
+		// Pass.
 	}
 }
 
-func TestReadFromTimeoutFluctuation(t *testing.T) {
+func TestReadWriteDeadline(t *testing.T) {
 	switch runtime.GOOS {
 	case "plan9":
-		t.Skipf("not supported on %s", runtime.GOOS)
+		t.Skipf("skipping test on %q", runtime.GOOS)
 	}
 
-	c1, err := newLocalPacketListener("udp")
-	if err != nil {
-		t.Fatal(err)
+	const (
+		readTimeout  = 50 * time.Millisecond
+		writeTimeout = 250 * time.Millisecond
+	)
+	checkTimeout := func(command string, start time.Time, should time.Duration) {
+		is := time.Now().Sub(start)
+		d := is - should
+		if d < -30*time.Millisecond || !testing.Short() && 150*time.Millisecond < d {
+			t.Errorf("%s timeout test failed: is=%v should=%v\n", command, is, should)
+		}
 	}
-	defer c1.Close()
 
-	c2, err := Dial(c1.LocalAddr().Network(), c1.LocalAddr().String())
+	ln, err := Listen("tcp", "127.0.0.1:0")
 	if err != nil {
-		t.Fatal(err)
+		t.Fatalf("ListenTCP on :0: %v", err)
 	}
-	defer c2.Close()
+	defer ln.Close()
 
-	max := time.NewTimer(time.Second)
-	defer max.Stop()
-	ch := make(chan error)
-	go timeoutPacketReceiver(c2.(PacketConn), 100*time.Millisecond, 50*time.Millisecond, 250*time.Millisecond, ch)
+	lnquit := make(chan bool)
 
-	select {
-	case <-max.C:
-		t.Fatal("ReadFrom took over 1s; expected 0.1s")
-	case err := <-ch:
-		if perr := parseReadError(err); perr != nil {
-			t.Error(perr)
-		}
-		if nerr, ok := err.(Error); !ok || !nerr.Timeout() {
-			t.Fatal(err)
+	go func() {
+		c, err := ln.Accept()
+		if err != nil {
+			t.Errorf("Accept: %v", err)
+			return
 		}
-	}
-}
+		defer c.Close()
+		lnquit <- true
+	}()
 
-func TestWriteTimeoutFluctuation(t *testing.T) {
-	switch runtime.GOOS {
-	case "plan9":
-		t.Skipf("not supported on %s", runtime.GOOS)
+	c, err := Dial("tcp", ln.Addr().String())
+	if err != nil {
+		t.Fatalf("Dial: %v", err)
 	}
+	defer c.Close()
 
-	ln, err := newLocalListener("tcp")
+	start := time.Now()
+	err = c.SetReadDeadline(start.Add(readTimeout))
 	if err != nil {
-		t.Fatal(err)
+		t.Fatalf("SetReadDeadline: %v", err)
 	}
-	defer ln.Close()
-
-	c, err := Dial(ln.Addr().Network(), ln.Addr().String())
+	err = c.SetWriteDeadline(start.Add(writeTimeout))
 	if err != nil {
-		t.Fatal(err)
+		t.Fatalf("SetWriteDeadline: %v", err)
 	}
-	defer c.Close()
 
-	d := time.Second
-	if runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64") {
-		d = 3 * time.Second // see golang.org/issue/10775
-	}
-	max := time.NewTimer(d)
-	defer max.Stop()
-	ch := make(chan error)
-	go timeoutTransmitter(c, 100*time.Millisecond, 50*time.Millisecond, 250*time.Millisecond, ch)
+	quit := make(chan bool)
 
-	select {
-	case <-max.C:
-		t.Fatalf("Write took over %v; expected 0.1s", d)
-	case err := <-ch:
-		if perr := parseWriteError(err); perr != nil {
-			t.Error(perr)
-		}
-		if nerr, ok := err.(Error); !ok || !nerr.Timeout() {
-			t.Fatal(err)
+	go func() {
+		var buf [10]byte
+		_, err := c.Read(buf[:])
+		if err == nil {
+			t.Errorf("Read should not succeed")
 		}
-	}
-}
+		checkTimeout("Read", start, readTimeout)
+		quit <- true
+	}()
 
-func TestVariousDeadlines1Proc(t *testing.T) {
-	testVariousDeadlines(t, 1)
-}
+	go func() {
+		var buf [10000]byte
+		for {
+			_, err := c.Write(buf[:])
+			if err != nil {
+				break
+			}
+		}
+		checkTimeout("Write", start, writeTimeout)
+		quit <- true
+	}()
 
-func TestVariousDeadlines4Proc(t *testing.T) {
-	testVariousDeadlines(t, 4)
+	<-quit
+	<-quit
+	<-lnquit
 }
 
 type neverEnding byte
 
-func (b neverEnding) Read(p []byte) (int, error) {
+func (b neverEnding) Read(p []byte) (n int, err error) {
 	for i := range p {
 		p[i] = byte(b)
 	}
 	return len(p), nil
 }
 
+func TestVariousDeadlines1Proc(t *testing.T) {
+	testVariousDeadlines(t, 1)
+}
+
+func TestVariousDeadlines4Proc(t *testing.T) {
+	testVariousDeadlines(t, 4)
+}
+
 func testVariousDeadlines(t *testing.T, maxProcs int) {
 	switch runtime.GOOS {
 	case "plan9":
-		t.Skipf("not supported on %s", runtime.GOOS)
+		t.Skipf("skipping test on %q", runtime.GOOS)
 	}
 
 	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(maxProcs))
+	ln := newLocalListener(t)
+	defer ln.Close()
+	acceptc := make(chan error, 1)
 
-	type result struct {
-		n   int64
-		err error
-		d   time.Duration
-	}
-
-	ch := make(chan error, 1)
-	pasvch := make(chan result)
-	handler := func(ls *localServer, ln Listener) {
+	// The server, with no timeouts of its own, sending bytes to clients
+	// as fast as it can.
+	servec := make(chan copyRes)
+	go func() {
 		for {
 			c, err := ln.Accept()
 			if err != nil {
-				ch <- err
+				acceptc <- err
 				return
 			}
-			// The server, with no timeouts of its own,
-			// sending bytes to clients as fast as it can.
 			go func() {
 				t0 := time.Now()
 				n, err := io.Copy(c, neverEnding('a'))
-				dt := time.Since(t0)
+				d := time.Since(t0)
 				c.Close()
-				pasvch <- result{n, err, dt}
+				servec <- copyRes{n, err, d}
 			}()
 		}
-	}
-	ls, err := newLocalServer("tcp")
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer ls.teardown()
-	if err := ls.buildup(handler); err != nil {
-		t.Fatal(err)
-	}
+	}()
 
 	for _, timeout := range []time.Duration{
 		1 * time.Nanosecond,
@@ -823,188 +483,265 @@ func testVariousDeadlines(t *testing.T, maxProcs int) {
 			name := fmt.Sprintf("%v run %d/%d", timeout, run+1, numRuns)
 			t.Log(name)
 
-			c, err := Dial(ls.Listener.Addr().Network(), ls.Listener.Addr().String())
+			c, err := Dial("tcp", ln.Addr().String())
 			if err != nil {
-				t.Fatal(err)
+				t.Fatalf("Dial: %v", err)
 			}
-
-			tooLong := 5 * time.Second
-			max := time.NewTimer(tooLong)
-			defer max.Stop()
-			actvch := make(chan result)
+			clientc := make(chan copyRes)
 			go func() {
 				t0 := time.Now()
-				if err := c.SetDeadline(t0.Add(timeout)); err != nil {
-					t.Error(err)
-				}
+				c.SetDeadline(t0.Add(timeout))
 				n, err := io.Copy(ioutil.Discard, c)
-				dt := time.Since(t0)
+				d := time.Since(t0)
 				c.Close()
-				actvch <- result{n, err, dt}
+				clientc <- copyRes{n, err, d}
 			}()
 
+			tooLong := 5 * time.Second
 			select {
-			case res := <-actvch:
-				if nerr, ok := res.err.(Error); ok && nerr.Timeout() {
+			case res := <-clientc:
+				if isTimeout(res.err) {
 					t.Logf("for %v, good client timeout after %v, reading %d bytes", name, res.d, res.n)
 				} else {
-					t.Fatalf("for %v, client Copy = %d, %v; want timeout", name, res.n, res.err)
+					t.Fatalf("for %v: client Copy = %d, %v (want timeout)", name, res.n, res.err)
 				}
-			case <-max.C:
-				t.Fatalf("for %v, timeout (%v) waiting for client to timeout (%v) reading", name, tooLong, timeout)
+			case <-time.After(tooLong):
+				t.Fatalf("for %v: timeout (%v) waiting for client to timeout (%v) reading", name, tooLong, timeout)
 			}
 
 			select {
-			case res := <-pasvch:
-				t.Logf("for %v, server in %v wrote %d: %v", name, res.d, res.n, res.err)
-			case err := <-ch:
-				t.Fatalf("for %v, Accept = %v", name, err)
-			case <-max.C:
+			case res := <-servec:
+				t.Logf("for %v: server in %v wrote %d, %v", name, res.d, res.n, res.err)
+			case err := <-acceptc:
+				t.Fatalf("for %v: server Accept = %v", name, err)
+			case <-time.After(tooLong):
 				t.Fatalf("for %v, timeout waiting for server to finish writing", name)
 			}
 		}
 	}
 }
 
-// TestReadWriteProlongedTimeout tests concurrent deadline
-// modification. Known to cause data races in the past.
-func TestReadWriteProlongedTimeout(t *testing.T) {
+// TestReadDeadlineDataAvailable tests that read deadlines work, even
+// if there's data ready to be read.
+func TestReadDeadlineDataAvailable(t *testing.T) {
 	switch runtime.GOOS {
 	case "plan9":
-		t.Skipf("not supported on %s", runtime.GOOS)
+		t.Skipf("skipping test on %q", runtime.GOOS)
 	}
 
-	handler := func(ls *localServer, ln Listener) {
+	ln := newLocalListener(t)
+	defer ln.Close()
+
+	servec := make(chan copyRes)
+	const msg = "data client shouldn't read, even though it'll be waiting"
+	go func() {
 		c, err := ln.Accept()
 		if err != nil {
-			t.Error(err)
+			t.Errorf("Accept: %v", err)
 			return
 		}
 		defer c.Close()
+		n, err := c.Write([]byte(msg))
+		servec <- copyRes{n: int64(n), err: err}
+	}()
 
-		var wg sync.WaitGroup
-		wg.Add(2)
-		go func() {
-			defer wg.Done()
-			var b [1]byte
-			for {
-				if err := c.SetReadDeadline(time.Now().Add(time.Hour)); err != nil {
-					if perr := parseCommonError(err); perr != nil {
-						t.Error(perr)
-					}
-					t.Error(err)
-					return
-				}
-				if _, err := c.Read(b[:]); err != nil {
-					if perr := parseReadError(err); perr != nil {
-						t.Error(perr)
-					}
-					return
-				}
-			}
-		}()
-		go func() {
-			defer wg.Done()
-			var b [1]byte
-			for {
-				if err := c.SetWriteDeadline(time.Now().Add(time.Hour)); err != nil {
-					if perr := parseCommonError(err); perr != nil {
-						t.Error(perr)
-					}
-					t.Error(err)
-					return
-				}
-				if _, err := c.Write(b[:]); err != nil {
-					if perr := parseWriteError(err); perr != nil {
-						t.Error(perr)
-					}
-					return
-				}
-			}
-		}()
-		wg.Wait()
-	}
-	ls, err := newLocalServer("tcp")
+	c, err := Dial("tcp", ln.Addr().String())
 	if err != nil {
-		t.Fatal(err)
+		t.Fatalf("Dial: %v", err)
 	}
-	defer ls.teardown()
-	if err := ls.buildup(handler); err != nil {
-		t.Fatal(err)
+	defer c.Close()
+	if res := <-servec; res.err != nil || res.n != int64(len(msg)) {
+		t.Fatalf("unexpected server Write: n=%d, err=%v; want n=%d, err=nil", res.n, res.err, len(msg))
 	}
+	c.SetReadDeadline(time.Now().Add(-5 * time.Second)) // in the psat.
+	buf := make([]byte, len(msg)/2)
+	n, err := c.Read(buf)
+	if n > 0 || !isTimeout(err) {
+		t.Fatalf("client read = %d (%q) err=%v; want 0, timeout", n, buf[:n], err)
+	}
+}
+
+// TestWriteDeadlineBufferAvailable tests that write deadlines work, even
+// if there's buffer space available to write.
+func TestWriteDeadlineBufferAvailable(t *testing.T) {
+	switch runtime.GOOS {
+	case "plan9":
+		t.Skipf("skipping test on %q", runtime.GOOS)
+	}
+
+	ln := newLocalListener(t)
+	defer ln.Close()
 
-	c, err := Dial(ls.Listener.Addr().Network(), ls.Listener.Addr().String())
+	servec := make(chan copyRes)
+	go func() {
+		c, err := ln.Accept()
+		if err != nil {
+			t.Errorf("Accept: %v", err)
+			return
+		}
+		defer c.Close()
+		c.SetWriteDeadline(time.Now().Add(-5 * time.Second)) // in the past
+		n, err := c.Write([]byte{'x'})
+		servec <- copyRes{n: int64(n), err: err}
+	}()
+
+	c, err := Dial("tcp", ln.Addr().String())
 	if err != nil {
-		t.Fatal(err)
+		t.Fatalf("Dial: %v", err)
 	}
 	defer c.Close()
-
-	var b [1]byte
-	for i := 0; i < 1000; i++ {
-		c.Write(b[:])
-		c.Read(b[:])
+	res := <-servec
+	if res.n != 0 {
+		t.Errorf("Write = %d; want 0", res.n)
+	}
+	if !isTimeout(res.err) {
+		t.Errorf("Write error = %v; want timeout", res.err)
 	}
 }
 
-func TestReadWriteDeadlineRace(t *testing.T) {
+// TestAcceptDeadlineConnectionAvailable tests that accept deadlines work, even
+// if there's incoming connections available.
+func TestAcceptDeadlineConnectionAvailable(t *testing.T) {
 	switch runtime.GOOS {
-	case "nacl", "plan9":
-		t.Skipf("not supported on %s", runtime.GOOS)
+	case "plan9":
+		t.Skipf("skipping test on %q", runtime.GOOS)
 	}
 
-	N := 1000
-	if testing.Short() {
-		N = 50
+	ln := newLocalListener(t).(*TCPListener)
+	defer ln.Close()
+
+	go func() {
+		c, err := Dial("tcp", ln.Addr().String())
+		if err != nil {
+			t.Errorf("Dial: %v", err)
+			return
+		}
+		defer c.Close()
+		var buf [1]byte
+		c.Read(buf[:]) // block until the connection or listener is closed
+	}()
+	time.Sleep(10 * time.Millisecond)
+	ln.SetDeadline(time.Now().Add(-5 * time.Second)) // in the past
+	c, err := ln.Accept()
+	if err == nil {
+		defer c.Close()
 	}
-	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4))
+	if !isTimeout(err) {
+		t.Fatalf("Accept: got %v; want timeout", err)
+	}
+}
 
-	ln, err := newLocalListener("tcp")
-	if err != nil {
-		t.Fatal(err)
+// TestConnectDeadlineInThePast tests that connect deadlines work, even
+// if the connection can be established w/o blocking.
+func TestConnectDeadlineInThePast(t *testing.T) {
+	switch runtime.GOOS {
+	case "plan9":
+		t.Skipf("skipping test on %q", runtime.GOOS)
 	}
+
+	ln := newLocalListener(t).(*TCPListener)
 	defer ln.Close()
 
-	c, err := Dial(ln.Addr().Network(), ln.Addr().String())
-	if err != nil {
-		t.Fatal(err)
+	go func() {
+		c, err := ln.Accept()
+		if err == nil {
+			defer c.Close()
+		}
+	}()
+	time.Sleep(10 * time.Millisecond)
+	c, err := DialTimeout("tcp", ln.Addr().String(), -5*time.Second) // in the past
+	if err == nil {
+		defer c.Close()
 	}
-	defer c.Close()
+	if !isTimeout(err) {
+		t.Fatalf("DialTimeout: got %v; want timeout", err)
+	}
+}
 
-	var wg sync.WaitGroup
-	wg.Add(3)
+// TestProlongTimeout tests concurrent deadline modification.
+// Known to cause data races in the past.
+func TestProlongTimeout(t *testing.T) {
+	switch runtime.GOOS {
+	case "plan9":
+		t.Skipf("skipping test on %q", runtime.GOOS)
+	}
+
+	ln := newLocalListener(t)
+	defer ln.Close()
+	connected := make(chan bool)
 	go func() {
-		defer wg.Done()
-		tic := time.NewTicker(2 * time.Microsecond)
-		defer tic.Stop()
-		for i := 0; i < N; i++ {
-			if err := c.SetReadDeadline(time.Now().Add(2 * time.Microsecond)); err != nil {
-				if perr := parseCommonError(err); perr != nil {
-					t.Error(perr)
+		s, err := ln.Accept()
+		connected <- true
+		if err != nil {
+			t.Errorf("ln.Accept: %v", err)
+			return
+		}
+		defer s.Close()
+		s.SetDeadline(time.Now().Add(time.Hour))
+		go func() {
+			var buf [4096]byte
+			for {
+				_, err := s.Write(buf[:])
+				if err != nil {
+					break
 				}
-				break
+				s.SetDeadline(time.Now().Add(time.Hour))
 			}
-			if err := c.SetWriteDeadline(time.Now().Add(2 * time.Microsecond)); err != nil {
-				if perr := parseCommonError(err); perr != nil {
-					t.Error(perr)
-				}
+		}()
+		buf := make([]byte, 1)
+		for {
+			_, err := s.Read(buf)
+			if err != nil {
 				break
 			}
-			<-tic.C
-		}
-	}()
-	go func() {
-		defer wg.Done()
-		var b [1]byte
-		for i := 0; i < N; i++ {
-			c.Read(b[:]) // ignore possible timeout errors
+			s.SetDeadline(time.Now().Add(time.Hour))
 		}
 	}()
+	c, err := Dial("tcp", ln.Addr().String())
+	if err != nil {
+		t.Fatalf("DialTCP: %v", err)
+	}
+	defer c.Close()
+	<-connected
+	for i := 0; i < 1024; i++ {
+		var buf [1]byte
+		c.Write(buf[:])
+	}
+}
+
+func TestDeadlineRace(t *testing.T) {
+	switch runtime.GOOS {
+	case "nacl", "plan9":
+		t.Skipf("skipping test on %q", runtime.GOOS)
+	}
+
+	N := 1000
+	if testing.Short() {
+		N = 50
+	}
+	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4))
+	ln := newLocalListener(t)
+	defer ln.Close()
+	c, err := Dial("tcp", ln.Addr().String())
+	if err != nil {
+		t.Fatalf("Dial: %v", err)
+	}
+	defer c.Close()
+	done := make(chan bool)
 	go func() {
-		defer wg.Done()
-		var b [1]byte
+		t := time.NewTicker(2 * time.Microsecond).C
 		for i := 0; i < N; i++ {
-			c.Write(b[:]) // ignore possible timeout errors
+			if err := c.SetDeadline(time.Now().Add(2 * time.Microsecond)); err != nil {
+				break
+			}
+			<-t
 		}
+		done <- true
 	}()
-	wg.Wait() // wait for tester goroutine to stop
+	var buf [1]byte
+	for i := 0; i < N; i++ {
+		c.Read(buf[:]) // ignore possible timeout errors
+	}
+	c.Close()
+	<-done
 }
diff --git a/src/net/udp_test.go b/src/net/udp_test.go
index b25f96a..125bbca 100644
--- a/src/net/udp_test.go
+++ b/src/net/udp_test.go
@@ -7,164 +7,149 @@ package net
 import (
 	"reflect"
 	"runtime"
+	"strings"
 	"testing"
 	"time"
 )
 
-type resolveUDPAddrTest struct {
-	network       string
-	litAddrOrName string
-	addr          *UDPAddr
-	err           error
+func TestResolveUDPAddr(t *testing.T) {
+	for _, tt := range resolveTCPAddrTests {
+		net := strings.Replace(tt.net, "tcp", "udp", -1)
+		addr, err := ResolveUDPAddr(net, tt.litAddrOrName)
+		if err != tt.err {
+			t.Fatalf("ResolveUDPAddr(%q, %q) failed: %v", net, tt.litAddrOrName, err)
+		}
+		if !reflect.DeepEqual(addr, (*UDPAddr)(tt.addr)) {
+			t.Fatalf("ResolveUDPAddr(%q, %q) = %#v, want %#v", net, tt.litAddrOrName, addr, tt.addr)
+		}
+		if err == nil {
+			str := addr.String()
+			addr1, err := ResolveUDPAddr(net, str)
+			if err != nil {
+				t.Fatalf("ResolveUDPAddr(%q, %q) [from %q]: %v", net, str, tt.litAddrOrName, err)
+			}
+			if !reflect.DeepEqual(addr1, addr) {
+				t.Fatalf("ResolveUDPAddr(%q, %q) [from %q] = %#v, want %#v", net, str, tt.litAddrOrName, addr1, addr)
+			}
+		}
+	}
 }
 
-var resolveUDPAddrTests = []resolveUDPAddrTest{
-	{"udp", "127.0.0.1:0", &UDPAddr{IP: IPv4(127, 0, 0, 1), Port: 0}, nil},
-	{"udp4", "127.0.0.1:65535", &UDPAddr{IP: IPv4(127, 0, 0, 1), Port: 65535}, nil},
-
-	{"udp", "[::1]:0", &UDPAddr{IP: ParseIP("::1"), Port: 0}, nil},
-	{"udp6", "[::1]:65535", &UDPAddr{IP: ParseIP("::1"), Port: 65535}, nil},
-
-	{"udp", "[::1%en0]:1", &UDPAddr{IP: ParseIP("::1"), Port: 1, Zone: "en0"}, nil},
-	{"udp6", "[::1%911]:2", &UDPAddr{IP: ParseIP("::1"), Port: 2, Zone: "911"}, nil},
+func TestReadFromUDP(t *testing.T) {
+	switch runtime.GOOS {
+	case "nacl", "plan9":
+		t.Skipf("skipping test on %q, see issue 8916", runtime.GOOS)
+	}
 
-	{"", "127.0.0.1:0", &UDPAddr{IP: IPv4(127, 0, 0, 1), Port: 0}, nil}, // Go 1.0 behavior
-	{"", "[::1]:0", &UDPAddr{IP: ParseIP("::1"), Port: 0}, nil},         // Go 1.0 behavior
+	ra, err := ResolveUDPAddr("udp", "127.0.0.1:7")
+	if err != nil {
+		t.Fatal(err)
+	}
 
-	{"udp", ":12345", &UDPAddr{Port: 12345}, nil},
+	la, err := ResolveUDPAddr("udp", "127.0.0.1:0")
+	if err != nil {
+		t.Fatal(err)
+	}
 
-	{"http", "127.0.0.1:0", nil, UnknownNetworkError("http")},
-}
+	c, err := ListenUDP("udp", la)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer c.Close()
 
-func TestResolveUDPAddr(t *testing.T) {
-	origTestHookLookupIP := testHookLookupIP
-	defer func() { testHookLookupIP = origTestHookLookupIP }()
-	testHookLookupIP = lookupLocalhost
+	_, err = c.WriteToUDP([]byte("a"), ra)
+	if err != nil {
+		t.Fatal(err)
+	}
 
-	for i, tt := range resolveUDPAddrTests {
-		addr, err := ResolveUDPAddr(tt.network, tt.litAddrOrName)
-		if err != tt.err {
-			t.Errorf("#%d: %v", i, err)
-		} else if !reflect.DeepEqual(addr, tt.addr) {
-			t.Errorf("#%d: got %#v; want %#v", i, addr, tt.addr)
-		}
-		if err != nil {
-			continue
-		}
-		rtaddr, err := ResolveUDPAddr(addr.Network(), addr.String())
-		if err != nil {
-			t.Errorf("#%d: %v", i, err)
-		} else if !reflect.DeepEqual(rtaddr, addr) {
-			t.Errorf("#%d: got %#v; want %#v", i, rtaddr, addr)
-		}
+	err = c.SetDeadline(time.Now().Add(100 * time.Millisecond))
+	if err != nil {
+		t.Fatal(err)
+	}
+	b := make([]byte, 1)
+	_, _, err = c.ReadFromUDP(b)
+	if err == nil {
+		t.Fatal("ReadFromUDP should fail")
+	} else if !isTimeout(err) {
+		t.Fatal(err)
 	}
 }
 
 func TestWriteToUDP(t *testing.T) {
 	switch runtime.GOOS {
 	case "plan9":
-		t.Skipf("not supported on %s", runtime.GOOS)
+		t.Skipf("skipping test on %q", runtime.GOOS)
 	}
 
-	c, err := ListenPacket("udp", "127.0.0.1:0")
+	l, err := ListenPacket("udp", "127.0.0.1:0")
 	if err != nil {
-		t.Fatal(err)
+		t.Fatalf("Listen failed: %v", err)
 	}
-	defer c.Close()
+	defer l.Close()
 
-	testWriteToConn(t, c.LocalAddr().String())
-	testWriteToPacketConn(t, c.LocalAddr().String())
+	testWriteToConn(t, l.LocalAddr().String())
+	testWriteToPacketConn(t, l.LocalAddr().String())
 }
 
 func testWriteToConn(t *testing.T, raddr string) {
 	c, err := Dial("udp", raddr)
 	if err != nil {
-		t.Fatal(err)
+		t.Fatalf("Dial failed: %v", err)
 	}
 	defer c.Close()
 
 	ra, err := ResolveUDPAddr("udp", raddr)
 	if err != nil {
-		t.Fatal(err)
+		t.Fatalf("ResolveUDPAddr failed: %v", err)
 	}
 
-	b := []byte("CONNECTED-MODE SOCKET")
-	_, err = c.(*UDPConn).WriteToUDP(b, ra)
+	_, err = c.(*UDPConn).WriteToUDP([]byte("Connection-oriented mode socket"), ra)
 	if err == nil {
-		t.Fatal("should fail")
+		t.Fatal("WriteToUDP should fail")
 	}
 	if err != nil && err.(*OpError).Err != ErrWriteToConnected {
-		t.Fatalf("should fail as ErrWriteToConnected: %v", err)
+		t.Fatalf("WriteToUDP should fail as ErrWriteToConnected: %v", err)
 	}
-	_, err = c.(*UDPConn).WriteTo(b, ra)
+
+	_, err = c.(*UDPConn).WriteTo([]byte("Connection-oriented mode socket"), ra)
 	if err == nil {
-		t.Fatal("should fail")
+		t.Fatal("WriteTo should fail")
 	}
 	if err != nil && err.(*OpError).Err != ErrWriteToConnected {
-		t.Fatalf("should fail as ErrWriteToConnected: %v", err)
+		t.Fatalf("WriteTo should fail as ErrWriteToConnected: %v", err)
 	}
-	_, err = c.Write(b)
+
+	_, err = c.Write([]byte("Connection-oriented mode socket"))
 	if err != nil {
-		t.Fatal(err)
-	}
-	_, _, err = c.(*UDPConn).WriteMsgUDP(b, nil, ra)
-	if err == nil {
-		t.Fatal("should fail")
-	}
-	if err != nil && err.(*OpError).Err != ErrWriteToConnected {
-		t.Fatalf("should fail as ErrWriteToConnected: %v", err)
-	}
-	_, _, err = c.(*UDPConn).WriteMsgUDP(b, nil, nil)
-	switch runtime.GOOS {
-	case "nacl", "windows": // see golang.org/issue/9252
-		t.Skipf("not implemented yet on %s", runtime.GOOS)
-	default:
-		if err != nil {
-			t.Fatal(err)
-		}
+		t.Fatalf("Write failed: %v", err)
 	}
 }
 
 func testWriteToPacketConn(t *testing.T, raddr string) {
 	c, err := ListenPacket("udp", "127.0.0.1:0")
 	if err != nil {
-		t.Fatal(err)
+		t.Fatalf("ListenPacket failed: %v", err)
 	}
 	defer c.Close()
 
 	ra, err := ResolveUDPAddr("udp", raddr)
 	if err != nil {
-		t.Fatal(err)
+		t.Fatalf("ResolveUDPAddr failed: %v", err)
 	}
 
-	b := []byte("UNCONNECTED-MODE SOCKET")
-	_, err = c.(*UDPConn).WriteToUDP(b, ra)
+	_, err = c.(*UDPConn).WriteToUDP([]byte("Connection-less mode socket"), ra)
 	if err != nil {
-		t.Fatal(err)
+		t.Fatalf("WriteToUDP failed: %v", err)
 	}
-	_, err = c.WriteTo(b, ra)
+
+	_, err = c.WriteTo([]byte("Connection-less mode socket"), ra)
 	if err != nil {
-		t.Fatal(err)
-	}
-	_, err = c.(*UDPConn).Write(b)
-	if err == nil {
-		t.Fatal("should fail")
+		t.Fatalf("WriteTo failed: %v", err)
 	}
-	_, _, err = c.(*UDPConn).WriteMsgUDP(b, nil, nil)
+
+	_, err = c.(*UDPConn).Write([]byte("Connection-less mode socket"))
 	if err == nil {
-		t.Fatal("should fail")
-	}
-	if err != nil && err.(*OpError).Err != errMissingAddress {
-		t.Fatalf("should fail as errMissingAddress: %v", err)
-	}
-	_, _, err = c.(*UDPConn).WriteMsgUDP(b, nil, ra)
-	switch runtime.GOOS {
-	case "nacl", "windows": // see golang.org/issue/9252
-		t.Skipf("not implemented yet on %s", runtime.GOOS)
-	default:
-		if err != nil {
-			t.Fatal(err)
-		}
+		t.Fatal("Write should fail")
 	}
 }
 
@@ -179,13 +164,13 @@ var udpConnLocalNameTests = []struct {
 
 func TestUDPConnLocalName(t *testing.T) {
 	if testing.Short() || !*testExternal {
-		t.Skip("avoid external network")
+		t.Skip("skipping test to avoid external network")
 	}
 
 	for _, tt := range udpConnLocalNameTests {
 		c, err := ListenUDP(tt.net, tt.laddr)
 		if err != nil {
-			t.Fatal(err)
+			t.Fatalf("ListenUDP failed: %v", err)
 		}
 		defer c.Close()
 		la := c.LocalAddr()
@@ -199,7 +184,7 @@ func TestUDPConnLocalAndRemoteNames(t *testing.T) {
 	for _, laddr := range []string{"", "127.0.0.1:0"} {
 		c1, err := ListenPacket("udp", "127.0.0.1:0")
 		if err != nil {
-			t.Fatal(err)
+			t.Fatalf("ListenUDP failed: %v", err)
 		}
 		defer c1.Close()
 
@@ -207,12 +192,12 @@ func TestUDPConnLocalAndRemoteNames(t *testing.T) {
 		if laddr != "" {
 			var err error
 			if la, err = ResolveUDPAddr("udp", laddr); err != nil {
-				t.Fatal(err)
+				t.Fatalf("ResolveUDPAddr failed: %v", err)
 			}
 		}
 		c2, err := DialUDP("udp", la, c1.LocalAddr().(*UDPAddr))
 		if err != nil {
-			t.Fatal(err)
+			t.Fatalf("DialUDP failed: %v", err)
 		}
 		defer c2.Close()
 
@@ -235,37 +220,60 @@ func TestUDPConnLocalAndRemoteNames(t *testing.T) {
 
 func TestIPv6LinkLocalUnicastUDP(t *testing.T) {
 	if testing.Short() || !*testExternal {
-		t.Skip("avoid external network")
+		t.Skip("skipping test to avoid external network")
 	}
 	if !supportsIPv6 {
-		t.Skip("IPv6 is not supported")
+		t.Skip("ipv6 is not supported")
+	}
+	ifi := loopbackInterface()
+	if ifi == nil {
+		t.Skip("loopback interface not found")
+	}
+	laddr := ipv6LinkLocalUnicastAddr(ifi)
+	if laddr == "" {
+		t.Skip("ipv6 unicast address on loopback not found")
 	}
 
-	for i, tt := range ipv6LinkLocalUnicastUDPTests {
-		c1, err := ListenPacket(tt.network, tt.address)
+	type test struct {
+		net, addr  string
+		nameLookup bool
+	}
+	var tests = []test{
+		{"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{
+			{"udp", "[localhost%" + ifi.Name + "]:0", true},
+			{"udp6", "[localhost%" + ifi.Name + "]:0", true},
+		}...)
+	case "linux":
+		tests = append(tests, []test{
+			{"udp", "[ip6-localhost%" + ifi.Name + "]:0", true},
+			{"udp6", "[ip6-localhost%" + ifi.Name + "]:0", true},
+		}...)
+	}
+	for _, tt := range tests {
+		c1, err := ListenPacket(tt.net, tt.addr)
 		if err != nil {
 			// It might return "LookupHost returned no
 			// suitable address" error on some platforms.
-			t.Log(err)
+			t.Logf("ListenPacket failed: %v", err)
 			continue
 		}
-		ls, err := (&packetListener{PacketConn: c1}).newLocalServer()
-		if err != nil {
-			t.Fatal(err)
-		}
-		defer ls.teardown()
-		ch := make(chan error, 1)
-		handler := func(ls *localPacketServer, c PacketConn) { packetTransponder(c, ch) }
-		if err := ls.buildup(handler); err != nil {
-			t.Fatal(err)
-		}
+		defer c1.Close()
 		if la, ok := c1.LocalAddr().(*UDPAddr); !ok || !tt.nameLookup && la.Zone == "" {
 			t.Fatalf("got %v; expected a proper address with zone identifier", la)
 		}
 
-		c2, err := Dial(tt.network, ls.PacketConn.LocalAddr().String())
+		c2, err := Dial(tt.net, c1.LocalAddr().String())
 		if err != nil {
-			t.Fatal(err)
+			t.Fatalf("Dial failed: %v", err)
 		}
 		defer c2.Close()
 		if la, ok := c2.LocalAddr().(*UDPAddr); !ok || !tt.nameLookup && la.Zone == "" {
@@ -276,88 +284,14 @@ func TestIPv6LinkLocalUnicastUDP(t *testing.T) {
 		}
 
 		if _, err := c2.Write([]byte("UDP OVER IPV6 LINKLOCAL TEST")); err != nil {
-			t.Fatal(err)
+			t.Fatalf("Conn.Write failed: %v", err)
 		}
 		b := make([]byte, 32)
-		if _, err := c2.Read(b); err != nil {
-			t.Fatal(err)
-		}
-
-		for err := range ch {
-			t.Errorf("#%d: %v", i, err)
-		}
-	}
-}
-
-func TestUDPZeroBytePayload(t *testing.T) {
-	switch runtime.GOOS {
-	case "nacl", "plan9":
-		t.Skipf("not supported on %s", runtime.GOOS)
-	}
-
-	c, err := newLocalPacketListener("udp")
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer c.Close()
-
-	for _, genericRead := range []bool{false, true} {
-		n, err := c.WriteTo(nil, c.LocalAddr())
-		if err != nil {
-			t.Fatal(err)
-		}
-		if n != 0 {
-			t.Errorf("got %d; want 0", n)
-		}
-		c.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
-		var b [1]byte
-		if genericRead {
-			_, err = c.(Conn).Read(b[:])
+		if _, from, err := c1.ReadFrom(b); err != nil {
+			t.Fatalf("PacketConn.ReadFrom failed: %v", err)
 		} else {
-			_, _, err = c.ReadFrom(b[:])
-		}
-		switch err {
-		case nil: // ReadFrom succeeds
-		default: // Read may timeout, it depends on the platform
-			if nerr, ok := err.(Error); !ok || !nerr.Timeout() {
-				t.Fatal(err)
-			}
-		}
-	}
-}
-
-func TestUDPZeroByteBuffer(t *testing.T) {
-	switch runtime.GOOS {
-	case "nacl", "plan9":
-		t.Skipf("not supported on %s", runtime.GOOS)
-	}
-
-	c, err := newLocalPacketListener("udp")
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer c.Close()
-
-	b := []byte("UDP ZERO BYTE BUFFER TEST")
-	for _, genericRead := range []bool{false, true} {
-		n, err := c.WriteTo(b, c.LocalAddr())
-		if err != nil {
-			t.Fatal(err)
-		}
-		if n != len(b) {
-			t.Errorf("got %d; want %d", n, len(b))
-		}
-		c.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
-		if genericRead {
-			_, err = c.(Conn).Read(nil)
-		} else {
-			_, _, err = c.ReadFrom(nil)
-		}
-		switch err {
-		case nil: // ReadFrom succeeds
-		default: // Read may timeout, it depends on the platform
-			if nerr, ok := err.(Error); (!ok || !nerr.Timeout()) && runtime.GOOS != "windows" { // Windows retruns WSAEMSGSIZ
-				t.Fatal(err)
+			if ra, ok := from.(*UDPAddr); !ok || !tt.nameLookup && ra.Zone == "" {
+				t.Fatalf("got %v; expected a proper address with zone identifier", ra)
 			}
 		}
 	}
diff --git a/src/net/udpsock.go b/src/net/udpsock.go
index 9292133..4c99ae4 100644
--- a/src/net/udpsock.go
+++ b/src/net/udpsock.go
@@ -25,14 +25,7 @@ func (a *UDPAddr) String() string {
 	return JoinHostPort(ip, itoa(a.Port))
 }
 
-func (a *UDPAddr) isWildcard() bool {
-	if a == nil || a.IP == nil {
-		return true
-	}
-	return a.IP.IsUnspecified()
-}
-
-func (a *UDPAddr) opAddr() Addr {
+func (a *UDPAddr) toAddr() Addr {
 	if a == nil {
 		return nil
 	}
@@ -53,9 +46,9 @@ func ResolveUDPAddr(net, addr string) (*UDPAddr, error) {
 	default:
 		return nil, UnknownNetworkError(net)
 	}
-	addrs, err := internetAddrList(net, addr, noDeadline)
+	a, err := resolveInternetAddr(net, addr, noDeadline)
 	if err != nil {
 		return nil, err
 	}
-	return addrs.first(isIPv4).(*UDPAddr), nil
+	return a.toAddr().(*UDPAddr), nil
 }
diff --git a/src/net/udpsock_plan9.go b/src/net/udpsock_plan9.go
index 1ba57a2..510ac5e 100644
--- a/src/net/udpsock_plan9.go
+++ b/src/net/udpsock_plan9.go
@@ -33,10 +33,10 @@ func (c *UDPConn) ReadFromUDP(b []byte) (n int, addr *UDPAddr, err error) {
 	buf := make([]byte, udpHeaderSize+len(b))
 	m, err := c.fd.data.Read(buf)
 	if err != nil {
-		return 0, nil, &OpError{Op: "read", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+		return
 	}
 	if m < udpHeaderSize {
-		return 0, nil, &OpError{Op: "read", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: errors.New("short read reading UDP header")}
+		return 0, nil, errors.New("short read reading UDP header")
 	}
 	buf = buf[:m]
 
@@ -59,7 +59,7 @@ func (c *UDPConn) ReadFrom(b []byte) (int, Addr, error) {
 // flags that were set on the packet and the source address of the
 // packet.
 func (c *UDPConn) ReadMsgUDP(b, oob []byte) (n, oobn, flags int, addr *UDPAddr, err error) {
-	return 0, 0, 0, nil, &OpError{Op: "read", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: syscall.EPLAN9}
+	return 0, 0, 0, nil, syscall.EPLAN9
 }
 
 // WriteToUDP writes a UDP packet to addr via c, copying the payload
@@ -74,7 +74,7 @@ func (c *UDPConn) WriteToUDP(b []byte, addr *UDPAddr) (int, error) {
 		return 0, syscall.EINVAL
 	}
 	if addr == nil {
-		return 0, &OpError{Op: "write", Net: c.fd.dir, Source: c.fd.laddr, Addr: nil, Err: errMissingAddress}
+		return 0, &OpError{Op: "write", Net: c.fd.dir, Addr: nil, Err: errMissingAddress}
 	}
 	h := new(udpHeader)
 	h.raddr = addr.IP.To16()
@@ -86,10 +86,7 @@ func (c *UDPConn) WriteToUDP(b []byte, addr *UDPAddr) (int, error) {
 	buf := make([]byte, udpHeaderSize+len(b))
 	i := copy(buf, h.Bytes())
 	copy(buf[i:], b)
-	if _, err := c.fd.data.Write(buf); err != nil {
-		return 0, &OpError{Op: "write", Net: c.fd.dir, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err}
-	}
-	return len(b), nil
+	return c.fd.data.Write(buf)
 }
 
 // WriteTo implements the PacketConn WriteTo method.
@@ -99,18 +96,16 @@ func (c *UDPConn) WriteTo(b []byte, addr Addr) (int, error) {
 	}
 	a, ok := addr.(*UDPAddr)
 	if !ok {
-		return 0, &OpError{Op: "write", Net: c.fd.dir, Source: c.fd.laddr, Addr: addr, Err: syscall.EINVAL}
+		return 0, &OpError{"write", c.fd.dir, addr, syscall.EINVAL}
 	}
 	return c.WriteToUDP(b, a)
 }
 
-// WriteMsgUDP writes a packet to addr via c if c isn't connected, or
-// to c's remote destination address if c is connected (in which case
-// addr must be nil).  The payload is copied from b and the associated
-// out-of-band data is copied from oob.  It returns the number of
-// payload and out-of-band bytes written.
+// WriteMsgUDP writes a packet to addr via c, copying the payload from
+// b and the associated out-of-band data from oob.  It returns the
+// number of payload and out-of-band bytes written.
 func (c *UDPConn) WriteMsgUDP(b, oob []byte, addr *UDPAddr) (n, oobn int, err error) {
-	return 0, 0, &OpError{Op: "write", Net: c.fd.dir, Source: c.fd.laddr, Addr: addr.opAddr(), Err: syscall.EPLAN9}
+	return 0, 0, syscall.EPLAN9
 }
 
 // DialUDP connects to the remote address raddr on the network net,
@@ -127,10 +122,10 @@ func dialUDP(net string, laddr, raddr *UDPAddr, deadline time.Time) (*UDPConn, e
 	switch net {
 	case "udp", "udp4", "udp6":
 	default:
-		return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: UnknownNetworkError(net)}
+		return nil, UnknownNetworkError(net)
 	}
 	if raddr == nil {
-		return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: nil, Err: errMissingAddress}
+		return nil, &OpError{"dial", net, nil, errMissingAddress}
 	}
 	fd, err := dialPlan9(net, laddr, raddr)
 	if err != nil {
@@ -178,7 +173,7 @@ func ListenUDP(net string, laddr *UDPAddr) (*UDPConn, error) {
 	switch net {
 	case "udp", "udp4", "udp6":
 	default:
-		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: UnknownNetworkError(net)}
+		return nil, UnknownNetworkError(net)
 	}
 	if laddr == nil {
 		laddr = &UDPAddr{}
@@ -189,27 +184,20 @@ func ListenUDP(net string, laddr *UDPAddr) (*UDPConn, error) {
 	}
 	_, err = l.ctl.WriteString("headers")
 	if err != nil {
-		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr, Err: err}
+		return nil, err
 	}
 	l.data, err = os.OpenFile(l.dir+"/data", os.O_RDWR, 0)
 	if err != nil {
-		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr, Err: err}
+		return nil, err
 	}
 	fd, err := l.netFD()
 	return newUDPConn(fd), err
 }
 
 // ListenMulticastUDP listens for incoming multicast UDP packets
-// addressed to the group address gaddr on the interface ifi.
-// Network must be "udp", "udp4" or "udp6".
-// ListenMulticastUDP uses the system-assigned multicast interface
-// when ifi is nil, although this is not recommended because the
-// assignment depends on platforms and sometimes it might require
-// routing configuration.
-//
-// ListenMulticastUDP is just for convenience of simple, small
-// applications. There are golang.org/x/net/ipv4 and
-// golang.org/x/net/ipv6 packages for general purpose uses.
-func ListenMulticastUDP(network string, ifi *Interface, gaddr *UDPAddr) (*UDPConn, error) {
-	return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: gaddr.opAddr(), Err: syscall.EPLAN9}
+// addressed to the group address gaddr on ifi, which specifies the
+// interface to join.  ListenMulticastUDP uses default multicast
+// interface if ifi is nil.
+func ListenMulticastUDP(net string, ifi *Interface, gaddr *UDPAddr) (*UDPConn, error) {
+	return nil, syscall.EPLAN9
 }
diff --git a/src/net/udpsock_posix.go b/src/net/udpsock_posix.go
index 61868c4..a053336 100644
--- a/src/net/udpsock_posix.go
+++ b/src/net/udpsock_posix.go
@@ -31,6 +31,13 @@ func (a *UDPAddr) family() int {
 	return syscall.AF_INET6
 }
 
+func (a *UDPAddr) isWildcard() bool {
+	if a == nil || a.IP == nil {
+		return true
+	}
+	return a.IP.IsUnspecified()
+}
+
 func (a *UDPAddr) sockaddr(family int) (syscall.Sockaddr, error) {
 	if a == nil {
 		return nil, nil
@@ -53,11 +60,10 @@ func newUDPConn(fd *netFD) *UDPConn { return &UDPConn{conn{fd}} }
 // ReadFromUDP can be made to time out and return an error with
 // Timeout() == true after a fixed time limit; see SetDeadline and
 // SetReadDeadline.
-func (c *UDPConn) ReadFromUDP(b []byte) (int, *UDPAddr, error) {
+func (c *UDPConn) ReadFromUDP(b []byte) (n int, addr *UDPAddr, err error) {
 	if !c.ok() {
 		return 0, nil, syscall.EINVAL
 	}
-	var addr *UDPAddr
 	n, sa, err := c.fd.readFrom(b)
 	switch sa := sa.(type) {
 	case *syscall.SockaddrInet4:
@@ -65,10 +71,7 @@ func (c *UDPConn) ReadFromUDP(b []byte) (int, *UDPAddr, error) {
 	case *syscall.SockaddrInet6:
 		addr = &UDPAddr{IP: sa.Addr[0:], Port: sa.Port, Zone: zoneToString(int(sa.ZoneId))}
 	}
-	if err != nil {
-		err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
-	}
-	return n, addr, err
+	return
 }
 
 // ReadFrom implements the PacketConn ReadFrom method.
@@ -77,10 +80,7 @@ func (c *UDPConn) ReadFrom(b []byte) (int, Addr, error) {
 		return 0, nil, syscall.EINVAL
 	}
 	n, addr, err := c.ReadFromUDP(b)
-	if addr == nil {
-		return n, nil, err
-	}
-	return n, addr, err
+	return n, addr.toAddr(), err
 }
 
 // ReadMsgUDP reads a packet from c, copying the payload into b and
@@ -100,9 +100,6 @@ func (c *UDPConn) ReadMsgUDP(b, oob []byte) (n, oobn, flags int, addr *UDPAddr,
 	case *syscall.SockaddrInet6:
 		addr = &UDPAddr{IP: sa.Addr[0:], Port: sa.Port, Zone: zoneToString(int(sa.ZoneId))}
 	}
-	if err != nil {
-		err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
-	}
 	return
 }
 
@@ -118,20 +115,16 @@ func (c *UDPConn) WriteToUDP(b []byte, addr *UDPAddr) (int, error) {
 		return 0, syscall.EINVAL
 	}
 	if c.fd.isConnected {
-		return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: ErrWriteToConnected}
+		return 0, &OpError{"write", c.fd.net, addr, ErrWriteToConnected}
 	}
 	if addr == nil {
-		return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: nil, Err: errMissingAddress}
+		return 0, &OpError{Op: "write", Net: c.fd.net, Addr: nil, Err: errMissingAddress}
 	}
 	sa, err := addr.sockaddr(c.fd.family)
 	if err != nil {
-		return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err}
+		return 0, &OpError{"write", c.fd.net, addr, err}
 	}
-	n, err := c.fd.writeTo(b, sa)
-	if err != nil {
-		err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err}
-	}
-	return n, err
+	return c.fd.writeTo(b, sa)
 }
 
 // WriteTo implements the PacketConn WriteTo method.
@@ -141,36 +134,29 @@ func (c *UDPConn) WriteTo(b []byte, addr Addr) (int, error) {
 	}
 	a, ok := addr.(*UDPAddr)
 	if !ok {
-		return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr, Err: syscall.EINVAL}
+		return 0, &OpError{"write", c.fd.net, addr, syscall.EINVAL}
 	}
 	return c.WriteToUDP(b, a)
 }
 
-// WriteMsgUDP writes a packet to addr via c if c isn't connected, or
-// to c's remote destination address if c is connected (in which case
-// addr must be nil).  The payload is copied from b and the associated
-// out-of-band data is copied from oob.  It returns the number of
-// payload and out-of-band bytes written.
+// WriteMsgUDP writes a packet to addr via c, copying the payload from
+// b and the associated out-of-band data from oob.  It returns the
+// number of payload and out-of-band bytes written.
 func (c *UDPConn) WriteMsgUDP(b, oob []byte, addr *UDPAddr) (n, oobn int, err error) {
 	if !c.ok() {
 		return 0, 0, syscall.EINVAL
 	}
-	if c.fd.isConnected && addr != nil {
-		return 0, 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: ErrWriteToConnected}
-	}
-	if !c.fd.isConnected && addr == nil {
-		return 0, 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: errMissingAddress}
+	if c.fd.isConnected {
+		return 0, 0, &OpError{"write", c.fd.net, addr, ErrWriteToConnected}
 	}
-	var sa syscall.Sockaddr
-	sa, err = addr.sockaddr(c.fd.family)
-	if err != nil {
-		return 0, 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err}
+	if addr == nil {
+		return 0, 0, &OpError{Op: "write", Net: c.fd.net, Addr: nil, Err: errMissingAddress}
 	}
-	n, oobn, err = c.fd.writeMsg(b, oob, sa)
+	sa, err := addr.sockaddr(c.fd.family)
 	if err != nil {
-		err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err}
+		return 0, 0, &OpError{"write", c.fd.net, addr, err}
 	}
-	return
+	return c.fd.writeMsg(b, oob, sa)
 }
 
 // DialUDP connects to the remote address raddr on the network net,
@@ -180,10 +166,10 @@ func DialUDP(net string, laddr, raddr *UDPAddr) (*UDPConn, error) {
 	switch net {
 	case "udp", "udp4", "udp6":
 	default:
-		return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: UnknownNetworkError(net)}
+		return nil, &OpError{Op: "dial", Net: net, Addr: raddr, Err: UnknownNetworkError(net)}
 	}
 	if raddr == nil {
-		return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: nil, Err: errMissingAddress}
+		return nil, &OpError{Op: "dial", Net: net, Addr: nil, Err: errMissingAddress}
 	}
 	return dialUDP(net, laddr, raddr, noDeadline)
 }
@@ -191,7 +177,7 @@ func DialUDP(net string, laddr, raddr *UDPAddr) (*UDPConn, error) {
 func dialUDP(net string, laddr, raddr *UDPAddr, deadline time.Time) (*UDPConn, error) {
 	fd, err := internetSocket(net, laddr, raddr, deadline, syscall.SOCK_DGRAM, 0, "dial")
 	if err != nil {
-		return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: err}
+		return nil, &OpError{Op: "dial", Net: net, Addr: raddr, Err: err}
 	}
 	return newUDPConn(fd), nil
 }
@@ -207,52 +193,45 @@ func ListenUDP(net string, laddr *UDPAddr) (*UDPConn, error) {
 	switch net {
 	case "udp", "udp4", "udp6":
 	default:
-		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: UnknownNetworkError(net)}
+		return nil, &OpError{Op: "listen", Net: net, Addr: laddr, Err: UnknownNetworkError(net)}
 	}
 	if laddr == nil {
 		laddr = &UDPAddr{}
 	}
 	fd, err := internetSocket(net, laddr, nil, noDeadline, syscall.SOCK_DGRAM, 0, "listen")
 	if err != nil {
-		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr, Err: err}
+		return nil, &OpError{Op: "listen", Net: net, Addr: laddr, Err: err}
 	}
 	return newUDPConn(fd), nil
 }
 
 // ListenMulticastUDP listens for incoming multicast UDP packets
-// addressed to the group address gaddr on the interface ifi.
-// Network must be "udp", "udp4" or "udp6".
-// ListenMulticastUDP uses the system-assigned multicast interface
-// when ifi is nil, although this is not recommended because the
-// assignment depends on platforms and sometimes it might require
-// routing configuration.
-//
-// ListenMulticastUDP is just for convenience of simple, small
-// applications. There are golang.org/x/net/ipv4 and
-// golang.org/x/net/ipv6 packages for general purpose uses.
-func ListenMulticastUDP(network string, ifi *Interface, gaddr *UDPAddr) (*UDPConn, error) {
-	switch network {
+// addressed to the group address gaddr on ifi, which specifies the
+// interface to join.  ListenMulticastUDP uses default multicast
+// interface if ifi is nil.
+func ListenMulticastUDP(net string, ifi *Interface, gaddr *UDPAddr) (*UDPConn, error) {
+	switch net {
 	case "udp", "udp4", "udp6":
 	default:
-		return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: gaddr.opAddr(), Err: UnknownNetworkError(network)}
+		return nil, &OpError{Op: "listen", Net: net, Addr: gaddr, Err: UnknownNetworkError(net)}
 	}
 	if gaddr == nil || gaddr.IP == nil {
-		return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: gaddr.opAddr(), Err: errMissingAddress}
+		return nil, &OpError{Op: "listen", Net: net, Addr: nil, Err: errMissingAddress}
 	}
-	fd, err := internetSocket(network, gaddr, nil, noDeadline, syscall.SOCK_DGRAM, 0, "listen")
+	fd, err := internetSocket(net, gaddr, nil, noDeadline, syscall.SOCK_DGRAM, 0, "listen")
 	if err != nil {
-		return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: gaddr, Err: err}
+		return nil, &OpError{Op: "listen", Net: net, Addr: gaddr, Err: err}
 	}
 	c := newUDPConn(fd)
 	if ip4 := gaddr.IP.To4(); ip4 != nil {
 		if err := listenIPv4MulticastUDP(c, ifi, ip4); err != nil {
 			c.Close()
-			return nil, &OpError{Op: "listen", Net: network, Source: c.fd.laddr, Addr: &IPAddr{IP: ip4}, Err: err}
+			return nil, &OpError{Op: "listen", Net: net, Addr: &IPAddr{IP: ip4}, Err: err}
 		}
 	} else {
 		if err := listenIPv6MulticastUDP(c, ifi, gaddr.IP); err != nil {
 			c.Close()
-			return nil, &OpError{Op: "listen", Net: network, Source: c.fd.laddr, Addr: &IPAddr{IP: gaddr.IP}, Err: err}
+			return nil, &OpError{Op: "listen", Net: net, Addr: &IPAddr{IP: gaddr.IP}, Err: err}
 		}
 	}
 	return c, nil
diff --git a/src/net/unicast_posix_test.go b/src/net/unicast_posix_test.go
new file mode 100644
index 0000000..ab7ef40
--- /dev/null
+++ b/src/net/unicast_posix_test.go
@@ -0,0 +1,469 @@
+// 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 !plan9
+
+package net
+
+import (
+	"runtime"
+	"syscall"
+	"testing"
+)
+
+var listenerTests = []struct {
+	net      string
+	laddr    string
+	ipv6     bool // test with underlying AF_INET6 socket
+	wildcard bool // test with wildcard address
+}{
+	{net: "tcp", laddr: "", wildcard: true},
+	{net: "tcp", laddr: "0.0.0.0", wildcard: true},
+	{net: "tcp", laddr: "[::ffff:0.0.0.0]", wildcard: true},
+	{net: "tcp", laddr: "[::]", ipv6: true, wildcard: true},
+
+	{net: "tcp", laddr: "127.0.0.1"},
+	{net: "tcp", laddr: "[::ffff:127.0.0.1]"},
+	{net: "tcp", laddr: "[::1]", ipv6: true},
+
+	{net: "tcp4", laddr: "", wildcard: true},
+	{net: "tcp4", laddr: "0.0.0.0", wildcard: true},
+	{net: "tcp4", laddr: "[::ffff:0.0.0.0]", wildcard: true},
+
+	{net: "tcp4", laddr: "127.0.0.1"},
+	{net: "tcp4", laddr: "[::ffff:127.0.0.1]"},
+
+	{net: "tcp6", laddr: "", ipv6: true, wildcard: true},
+	{net: "tcp6", laddr: "[::]", ipv6: true, wildcard: true},
+
+	{net: "tcp6", laddr: "[::1]", ipv6: true},
+}
+
+// TestTCPListener tests both single and double listen to a test
+// listener with same address family, same listening address and
+// same port.
+func TestTCPListener(t *testing.T) {
+	switch runtime.GOOS {
+	case "plan9":
+		t.Skipf("skipping test on %q", runtime.GOOS)
+	}
+
+	for _, tt := range listenerTests {
+		if tt.wildcard && (testing.Short() || !*testExternal) {
+			continue
+		}
+		if tt.ipv6 && !supportsIPv6 {
+			continue
+		}
+		l1, port := usableListenPort(t, tt.net, tt.laddr)
+		checkFirstListener(t, tt.net, tt.laddr+":"+port, l1)
+		l2, err := Listen(tt.net, tt.laddr+":"+port)
+		checkSecondListener(t, tt.net, tt.laddr+":"+port, err, l2)
+		l1.Close()
+	}
+}
+
+// TestUDPListener tests both single and double listen to a test
+// listener with same address family, same listening address and
+// same port.
+func TestUDPListener(t *testing.T) {
+	switch runtime.GOOS {
+	case "plan9":
+		t.Skipf("skipping test on %q", runtime.GOOS)
+	}
+
+	toudpnet := func(net string) string {
+		switch net {
+		case "tcp":
+			return "udp"
+		case "tcp4":
+			return "udp4"
+		case "tcp6":
+			return "udp6"
+		}
+		return "<nil>"
+	}
+
+	for _, tt := range listenerTests {
+		if tt.wildcard && (testing.Short() || !*testExternal) {
+			continue
+		}
+		if tt.ipv6 && !supportsIPv6 {
+			continue
+		}
+		tt.net = toudpnet(tt.net)
+		l1, port := usableListenPacketPort(t, tt.net, tt.laddr)
+		checkFirstListener(t, tt.net, tt.laddr+":"+port, l1)
+		l2, err := ListenPacket(tt.net, tt.laddr+":"+port)
+		checkSecondListener(t, tt.net, tt.laddr+":"+port, err, l2)
+		l1.Close()
+	}
+}
+
+var dualStackListenerTests = []struct {
+	net1     string // first listener
+	laddr1   string
+	net2     string // second listener
+	laddr2   string
+	wildcard bool  // test with wildcard address
+	xerr     error // expected error value, nil or other
+}{
+	// Test cases and expected results for the attemping 2nd listen on the same port
+	// 1st listen                2nd listen                 darwin  freebsd  linux  openbsd
+	// ------------------------------------------------------------------------------------
+	// "tcp"  ""                 "tcp"  ""                    -        -       -       -
+	// "tcp"  ""                 "tcp"  "0.0.0.0"             -        -       -       -
+	// "tcp"  "0.0.0.0"          "tcp"  ""                    -        -       -       -
+	// ------------------------------------------------------------------------------------
+	// "tcp"  ""                 "tcp"  "[::]"                -        -       -       ok
+	// "tcp"  "[::]"             "tcp"  ""                    -        -       -       ok
+	// "tcp"  "0.0.0.0"          "tcp"  "[::]"                -        -       -       ok
+	// "tcp"  "[::]"             "tcp"  "0.0.0.0"             -        -       -       ok
+	// "tcp"  "[::ffff:0.0.0.0]" "tcp"  "[::]"                -        -       -       ok
+	// "tcp"  "[::]"             "tcp"  "[::ffff:0.0.0.0]"    -        -       -       ok
+	// ------------------------------------------------------------------------------------
+	// "tcp4" ""                 "tcp6" ""                    ok       ok      ok      ok
+	// "tcp6" ""                 "tcp4" ""                    ok       ok      ok      ok
+	// "tcp4" "0.0.0.0"          "tcp6" "[::]"                ok       ok      ok      ok
+	// "tcp6" "[::]"             "tcp4" "0.0.0.0"             ok       ok      ok      ok
+	// ------------------------------------------------------------------------------------
+	// "tcp"  "127.0.0.1"        "tcp"  "[::1]"               ok       ok      ok      ok
+	// "tcp"  "[::1]"            "tcp"  "127.0.0.1"           ok       ok      ok      ok
+	// "tcp4" "127.0.0.1"        "tcp6" "[::1]"               ok       ok      ok      ok
+	// "tcp6" "[::1]"            "tcp4" "127.0.0.1"           ok       ok      ok      ok
+	//
+	// Platform default configurations:
+	// darwin, kernel version 11.3.0
+	//	net.inet6.ip6.v6only=0 (overridable by sysctl or IPV6_V6ONLY option)
+	// freebsd, kernel version 8.2
+	//	net.inet6.ip6.v6only=1 (overridable by sysctl or IPV6_V6ONLY option)
+	// linux, kernel version 3.0.0
+	//	net.ipv6.bindv6only=0 (overridable by sysctl or IPV6_V6ONLY option)
+	// openbsd, kernel version 5.0
+	//	net.inet6.ip6.v6only=1 (overriding is prohibited)
+
+	{net1: "tcp", laddr1: "", net2: "tcp", laddr2: "", wildcard: true, xerr: syscall.EADDRINUSE},
+	{net1: "tcp", laddr1: "", net2: "tcp", laddr2: "0.0.0.0", wildcard: true, xerr: syscall.EADDRINUSE},
+	{net1: "tcp", laddr1: "0.0.0.0", net2: "tcp", laddr2: "", wildcard: true, xerr: syscall.EADDRINUSE},
+
+	{net1: "tcp", laddr1: "", net2: "tcp", laddr2: "[::]", wildcard: true, xerr: syscall.EADDRINUSE},
+	{net1: "tcp", laddr1: "[::]", net2: "tcp", laddr2: "", wildcard: true, xerr: syscall.EADDRINUSE},
+	{net1: "tcp", laddr1: "0.0.0.0", net2: "tcp", laddr2: "[::]", wildcard: true, xerr: syscall.EADDRINUSE},
+	{net1: "tcp", laddr1: "[::]", net2: "tcp", laddr2: "0.0.0.0", wildcard: true, xerr: syscall.EADDRINUSE},
+	{net1: "tcp", laddr1: "[::ffff:0.0.0.0]", net2: "tcp", laddr2: "[::]", wildcard: true, xerr: syscall.EADDRINUSE},
+	{net1: "tcp", laddr1: "[::]", net2: "tcp", laddr2: "[::ffff:0.0.0.0]", wildcard: true, xerr: syscall.EADDRINUSE},
+
+	{net1: "tcp4", laddr1: "", net2: "tcp6", laddr2: "", wildcard: true},
+	{net1: "tcp6", laddr1: "", net2: "tcp4", laddr2: "", wildcard: true},
+	{net1: "tcp4", laddr1: "0.0.0.0", net2: "tcp6", laddr2: "[::]", wildcard: true},
+	{net1: "tcp6", laddr1: "[::]", net2: "tcp4", laddr2: "0.0.0.0", wildcard: true},
+
+	{net1: "tcp", laddr1: "127.0.0.1", net2: "tcp", laddr2: "[::1]"},
+	{net1: "tcp", laddr1: "[::1]", net2: "tcp", laddr2: "127.0.0.1"},
+	{net1: "tcp4", laddr1: "127.0.0.1", net2: "tcp6", laddr2: "[::1]"},
+	{net1: "tcp6", laddr1: "[::1]", net2: "tcp4", laddr2: "127.0.0.1"},
+}
+
+// TestDualStackTCPListener tests both single and double listen
+// 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)
+	}
+	if !supportsIPv6 {
+		t.Skip("ipv6 is not supported")
+	}
+
+	for _, tt := range dualStackListenerTests {
+		if tt.wildcard && !*testExternal {
+			continue
+		}
+		switch runtime.GOOS {
+		case "openbsd":
+			if tt.wildcard && differentWildcardAddr(tt.laddr1, tt.laddr2) {
+				tt.xerr = nil
+			}
+		}
+		l1, port := usableListenPort(t, tt.net1, tt.laddr1)
+		laddr := tt.laddr1 + ":" + port
+		checkFirstListener(t, tt.net1, laddr, l1)
+		laddr = tt.laddr2 + ":" + port
+		l2, err := Listen(tt.net2, laddr)
+		checkDualStackSecondListener(t, tt.net2, laddr, tt.xerr, err, l2)
+		l1.Close()
+	}
+}
+
+// TestDualStackUDPListener tests both single and double listen
+// to a test listener with various address families, differnet
+// listening address and same port.
+func TestDualStackUDPListener(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)
+	}
+	if !supportsIPv6 {
+		t.Skip("ipv6 is not supported")
+	}
+
+	toudpnet := func(net string) string {
+		switch net {
+		case "tcp":
+			return "udp"
+		case "tcp4":
+			return "udp4"
+		case "tcp6":
+			return "udp6"
+		}
+		return "<nil>"
+	}
+
+	for _, tt := range dualStackListenerTests {
+		if tt.wildcard && (testing.Short() || !*testExternal) {
+			continue
+		}
+		tt.net1 = toudpnet(tt.net1)
+		tt.net2 = toudpnet(tt.net2)
+		switch runtime.GOOS {
+		case "openbsd":
+			if tt.wildcard && differentWildcardAddr(tt.laddr1, tt.laddr2) {
+				tt.xerr = nil
+			}
+		}
+		l1, port := usableListenPacketPort(t, tt.net1, tt.laddr1)
+		laddr := tt.laddr1 + ":" + port
+		checkFirstListener(t, tt.net1, laddr, l1)
+		laddr = tt.laddr2 + ":" + port
+		l2, err := ListenPacket(tt.net2, laddr)
+		checkDualStackSecondListener(t, tt.net2, laddr, tt.xerr, err, l2)
+		l1.Close()
+	}
+}
+
+func usableListenPort(t *testing.T, net, laddr string) (l Listener, port string) {
+	var nladdr string
+	var err error
+	switch net {
+	default:
+		panic("usableListenPort net=" + net)
+	case "tcp", "tcp4", "tcp6":
+		l, err = Listen(net, laddr+":0")
+		if err != nil {
+			t.Fatalf("Probe Listen(%q, %q) failed: %v", net, laddr, err)
+		}
+		nladdr = l.(*TCPListener).Addr().String()
+	}
+	_, port, err = SplitHostPort(nladdr)
+	if err != nil {
+		t.Fatalf("SplitHostPort failed: %v", err)
+	}
+	return l, port
+}
+
+func usableListenPacketPort(t *testing.T, net, laddr string) (l PacketConn, port string) {
+	var nladdr string
+	var err error
+	switch net {
+	default:
+		panic("usableListenPacketPort net=" + net)
+	case "udp", "udp4", "udp6":
+		l, err = ListenPacket(net, laddr+":0")
+		if err != nil {
+			t.Fatalf("Probe ListenPacket(%q, %q) failed: %v", net, laddr, err)
+		}
+		nladdr = l.(*UDPConn).LocalAddr().String()
+	}
+	_, port, err = SplitHostPort(nladdr)
+	if err != nil {
+		t.Fatalf("SplitHostPort failed: %v", err)
+	}
+	return l, port
+}
+
+func differentWildcardAddr(i, j string) bool {
+	if (i == "" || i == "0.0.0.0" || i == "::ffff:0.0.0.0") && (j == "" || j == "0.0.0.0" || j == "::ffff:0.0.0.0") {
+		return false
+	}
+	if i == "[::]" && j == "[::]" {
+		return false
+	}
+	return true
+}
+
+func checkFirstListener(t *testing.T, net, laddr string, l interface{}) {
+	switch net {
+	case "tcp":
+		fd := l.(*TCPListener).fd
+		checkDualStackAddrFamily(t, net, laddr, fd)
+	case "tcp4":
+		fd := l.(*TCPListener).fd
+		if fd.family != syscall.AF_INET {
+			t.Fatalf("First Listen(%q, %q) returns address family %v, expected %v", net, laddr, fd.family, syscall.AF_INET)
+		}
+	case "tcp6":
+		fd := l.(*TCPListener).fd
+		if fd.family != syscall.AF_INET6 {
+			t.Fatalf("First Listen(%q, %q) returns address family %v, expected %v", net, laddr, fd.family, syscall.AF_INET6)
+		}
+	case "udp":
+		fd := l.(*UDPConn).fd
+		checkDualStackAddrFamily(t, net, laddr, fd)
+	case "udp4":
+		fd := l.(*UDPConn).fd
+		if fd.family != syscall.AF_INET {
+			t.Fatalf("First ListenPacket(%q, %q) returns address family %v, expected %v", net, laddr, fd.family, syscall.AF_INET)
+		}
+	case "udp6":
+		fd := l.(*UDPConn).fd
+		if fd.family != syscall.AF_INET6 {
+			t.Fatalf("First ListenPacket(%q, %q) returns address family %v, expected %v", net, laddr, fd.family, syscall.AF_INET6)
+		}
+	default:
+		t.Fatalf("Unexpected network: %q", net)
+	}
+}
+
+func checkSecondListener(t *testing.T, net, laddr string, err error, l interface{}) {
+	switch net {
+	case "tcp", "tcp4", "tcp6":
+		if err == nil {
+			l.(*TCPListener).Close()
+			t.Fatalf("Second Listen(%q, %q) should fail", net, laddr)
+		}
+	case "udp", "udp4", "udp6":
+		if err == nil {
+			l.(*UDPConn).Close()
+			t.Fatalf("Second ListenPacket(%q, %q) should fail", net, laddr)
+		}
+	default:
+		t.Fatalf("Unexpected network: %q", net)
+	}
+}
+
+func checkDualStackSecondListener(t *testing.T, net, laddr string, xerr, err error, l interface{}) {
+	switch net {
+	case "tcp", "tcp4", "tcp6":
+		if xerr == nil && err != nil || xerr != nil && err == nil {
+			t.Fatalf("Second Listen(%q, %q) returns %v, expected %v", net, laddr, err, xerr)
+		}
+		if err == nil {
+			l.(*TCPListener).Close()
+		}
+	case "udp", "udp4", "udp6":
+		if xerr == nil && err != nil || xerr != nil && err == nil {
+			t.Fatalf("Second ListenPacket(%q, %q) returns %v, expected %v", net, laddr, err, xerr)
+		}
+		if err == nil {
+			l.(*UDPConn).Close()
+		}
+	default:
+		t.Fatalf("Unexpected network: %q", net)
+	}
+}
+
+func checkDualStackAddrFamily(t *testing.T, net, laddr string, fd *netFD) {
+	switch a := fd.laddr.(type) {
+	case *TCPAddr:
+		// If a node under test supports both IPv6 capability
+		// and IPv6 IPv4-mapping capability, we can assume
+		// that the node listens on a wildcard address with an
+		// AF_INET6 socket.
+		if supportsIPv4map && fd.laddr.(*TCPAddr).isWildcard() {
+			if fd.family != syscall.AF_INET6 {
+				t.Fatalf("Listen(%q, %q) returns address family %v, expected %v", net, laddr, fd.family, syscall.AF_INET6)
+			}
+		} else {
+			if fd.family != a.family() {
+				t.Fatalf("Listen(%q, %q) returns address family %v, expected %v", net, laddr, fd.family, a.family())
+			}
+		}
+	case *UDPAddr:
+		// If a node under test supports both IPv6 capability
+		// and IPv6 IPv4-mapping capability, we can assume
+		// that the node listens on a wildcard address with an
+		// AF_INET6 socket.
+		if supportsIPv4map && fd.laddr.(*UDPAddr).isWildcard() {
+			if fd.family != syscall.AF_INET6 {
+				t.Fatalf("ListenPacket(%q, %q) returns address family %v, expected %v", net, laddr, fd.family, syscall.AF_INET6)
+			}
+		} else {
+			if fd.family != a.family() {
+				t.Fatalf("ListenPacket(%q, %q) returns address family %v, expected %v", net, laddr, fd.family, a.family())
+			}
+		}
+	default:
+		t.Fatalf("Unexpected protocol address type: %T", a)
+	}
+}
+
+var prohibitionaryDialArgTests = []struct {
+	net  string
+	addr string
+}{
+	{"tcp6", "127.0.0.1"},
+	{"tcp6", "[::ffff:127.0.0.1]"},
+}
+
+func TestProhibitionaryDialArgs(t *testing.T) {
+	switch runtime.GOOS {
+	case "plan9":
+		t.Skipf("skipping test on %q", runtime.GOOS)
+	}
+	// This test requires both IPv6 and IPv6 IPv4-mapping functionality.
+	if !supportsIPv4map || testing.Short() || !*testExternal {
+		return
+	}
+
+	l, port := usableListenPort(t, "tcp", "[::]")
+	defer l.Close()
+
+	for _, tt := range prohibitionaryDialArgTests {
+		c, err := Dial(tt.net, tt.addr+":"+port)
+		if err == nil {
+			c.Close()
+			t.Fatalf("Dial(%q, %q) should fail", tt.net, tt.addr)
+		}
+	}
+}
+
+func TestWildWildcardListener(t *testing.T) {
+	switch runtime.GOOS {
+	case "plan9":
+		t.Skipf("skipping test on %q", runtime.GOOS)
+	}
+
+	if testing.Short() || !*testExternal {
+		t.Skip("skipping test to avoid external network")
+	}
+
+	defer func() {
+		if p := recover(); p != nil {
+			t.Fatalf("Listen, ListenPacket or protocol-specific Listen panicked: %v", p)
+		}
+	}()
+
+	if ln, err := Listen("tcp", ""); err == nil {
+		ln.Close()
+	}
+	if ln, err := ListenPacket("udp", ""); err == nil {
+		ln.Close()
+	}
+	if ln, err := ListenTCP("tcp", nil); err == nil {
+		ln.Close()
+	}
+	if ln, err := ListenUDP("udp", nil); err == nil {
+		ln.Close()
+	}
+	if ln, err := ListenIP("ip:icmp", nil); err == nil {
+		ln.Close()
+	}
+}
diff --git a/src/net/unix_test.go b/src/net/unix_test.go
index 358ff31..1cdff39 100644
--- a/src/net/unix_test.go
+++ b/src/net/unix_test.go
@@ -17,18 +17,14 @@ import (
 )
 
 func TestReadUnixgramWithUnnamedSocket(t *testing.T) {
-	if !testableNetwork("unixgram") {
-		t.Skip("unixgram test")
-	}
-
 	addr := testUnixAddr()
 	la, err := ResolveUnixAddr("unixgram", addr)
 	if err != nil {
-		t.Fatal(err)
+		t.Fatalf("ResolveUnixAddr failed: %v", err)
 	}
 	c, err := ListenUnixgram("unixgram", la)
 	if err != nil {
-		t.Fatal(err)
+		t.Fatalf("ListenUnixgram failed: %v", err)
 	}
 	defer func() {
 		c.Close()
@@ -41,13 +37,13 @@ func TestReadUnixgramWithUnnamedSocket(t *testing.T) {
 		defer func() { off <- true }()
 		s, err := syscall.Socket(syscall.AF_UNIX, syscall.SOCK_DGRAM, 0)
 		if err != nil {
-			t.Error(err)
+			t.Errorf("syscall.Socket failed: %v", err)
 			return
 		}
 		defer syscall.Close(s)
 		rsa := &syscall.SockaddrUnix{Name: addr}
 		if err := syscall.Sendto(s, data[:], 0, rsa); err != nil {
-			t.Error(err)
+			t.Errorf("syscall.Sendto failed: %v", err)
 			return
 		}
 	}()
@@ -57,123 +53,69 @@ func TestReadUnixgramWithUnnamedSocket(t *testing.T) {
 	c.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
 	n, from, err := c.ReadFrom(b)
 	if err != nil {
-		t.Fatal(err)
+		t.Fatalf("UnixConn.ReadFrom failed: %v", err)
 	}
 	if from != nil {
-		t.Fatalf("unexpected peer address: %v", from)
+		t.Fatalf("neighbor address is %v", from)
 	}
 	if !bytes.Equal(b[:n], data[:]) {
-		t.Fatalf("got %v; want %v", b[:n], data[:])
+		t.Fatalf("got %v, want %v", b[:n], data[:])
 	}
 }
 
-func TestUnixgramZeroBytePayload(t *testing.T) {
-	if !testableNetwork("unixgram") {
-		t.Skip("unixgram test")
-	}
+func TestReadUnixgramWithZeroBytesBuffer(t *testing.T) {
+	// issue 4352: Recvfrom failed with "address family not
+	// supported by protocol family" if zero-length buffer provided
 
-	c1, err := newLocalPacketListener("unixgram")
+	addr := testUnixAddr()
+	la, err := ResolveUnixAddr("unixgram", addr)
 	if err != nil {
-		t.Fatal(err)
+		t.Fatalf("ResolveUnixAddr failed: %v", err)
 	}
-	defer os.Remove(c1.LocalAddr().String())
-	defer c1.Close()
-
-	c2, err := Dial("unixgram", c1.LocalAddr().String())
+	c, err := ListenUnixgram("unixgram", la)
 	if err != nil {
-		t.Fatal(err)
+		t.Fatalf("ListenUnixgram failed: %v", err)
 	}
-	defer os.Remove(c2.LocalAddr().String())
-	defer c2.Close()
+	defer func() {
+		c.Close()
+		os.Remove(addr)
+	}()
 
-	for _, genericRead := range []bool{false, true} {
-		n, err := c2.Write(nil)
+	off := make(chan bool)
+	go func() {
+		defer func() { off <- true }()
+		c, err := DialUnix("unixgram", nil, la)
 		if err != nil {
-			t.Fatal(err)
-		}
-		if n != 0 {
-			t.Errorf("got %d; want 0", n)
-		}
-		c1.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
-		var b [1]byte
-		var peer Addr
-		if genericRead {
-			_, err = c1.(Conn).Read(b[:])
-		} else {
-			_, peer, err = c1.ReadFrom(b[:])
+			t.Errorf("DialUnix failed: %v", err)
+			return
 		}
-		switch err {
-		case nil: // ReadFrom succeeds
-			if peer != nil { // peer is connected-mode
-				t.Fatalf("unexpected peer address: %v", peer)
-			}
-		default: // Read may timeout, it depends on the platform
-			if nerr, ok := err.(Error); !ok || !nerr.Timeout() {
-				t.Fatal(err)
-			}
+		defer c.Close()
+		if _, err := c.Write([]byte{1, 2, 3, 4, 5}); err != nil {
+			t.Errorf("UnixConn.Write failed: %v", err)
+			return
 		}
-	}
-}
-
-func TestUnixgramZeroByteBuffer(t *testing.T) {
-	if !testableNetwork("unixgram") {
-		t.Skip("unixgram test")
-	}
-	// issue 4352: Recvfrom failed with "address family not
-	// supported by protocol family" if zero-length buffer provided
-
-	c1, err := newLocalPacketListener("unixgram")
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer os.Remove(c1.LocalAddr().String())
-	defer c1.Close()
+	}()
 
-	c2, err := Dial("unixgram", c1.LocalAddr().String())
+	<-off
+	c.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
+	_, from, err := c.ReadFrom(nil)
 	if err != nil {
-		t.Fatal(err)
+		t.Fatalf("UnixConn.ReadFrom failed: %v", err)
 	}
-	defer os.Remove(c2.LocalAddr().String())
-	defer c2.Close()
-
-	b := []byte("UNIXGRAM ZERO BYTE BUFFER TEST")
-	for _, genericRead := range []bool{false, true} {
-		n, err := c2.Write(b)
-		if err != nil {
-			t.Fatal(err)
-		}
-		if n != len(b) {
-			t.Errorf("got %d; want %d", n, len(b))
-		}
-		c1.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
-		var peer Addr
-		if genericRead {
-			_, err = c1.(Conn).Read(nil)
-		} else {
-			_, peer, err = c1.ReadFrom(nil)
-		}
-		switch err {
-		case nil: // ReadFrom succeeds
-			if peer != nil { // peer is connected-mode
-				t.Fatalf("unexpected peer address: %v", peer)
-			}
-		default: // Read may timeout, it depends on the platform
-			if nerr, ok := err.(Error); !ok || !nerr.Timeout() {
-				t.Fatal(err)
-			}
-		}
+	if from != nil {
+		t.Fatalf("neighbor address is %v", from)
 	}
 }
 
 func TestUnixgramAutobind(t *testing.T) {
 	if runtime.GOOS != "linux" {
-		t.Skip("autobind is linux only")
+		t.Skip("skipping: autobind is linux only")
 	}
 
 	laddr := &UnixAddr{Name: "", Net: "unixgram"}
 	c1, err := ListenUnixgram("unixgram", laddr)
 	if err != nil {
-		t.Fatal(err)
+		t.Fatalf("ListenUnixgram failed: %v", err)
 	}
 	defer c1.Close()
 
@@ -188,7 +130,7 @@ func TestUnixgramAutobind(t *testing.T) {
 
 	c2, err := DialUnix("unixgram", nil, autoAddr)
 	if err != nil {
-		t.Fatal(err)
+		t.Fatalf("DialUnix failed: %v", err)
 	}
 	defer c2.Close()
 
@@ -199,30 +141,25 @@ func TestUnixgramAutobind(t *testing.T) {
 
 func TestUnixAutobindClose(t *testing.T) {
 	if runtime.GOOS != "linux" {
-		t.Skip("autobind is linux only")
+		t.Skip("skipping: autobind is linux only")
 	}
-
 	laddr := &UnixAddr{Name: "", Net: "unix"}
 	ln, err := ListenUnix("unix", laddr)
 	if err != nil {
-		t.Fatal(err)
+		t.Fatalf("ListenUnix failed: %v", err)
 	}
 	ln.Close()
 }
 
 func TestUnixgramWrite(t *testing.T) {
-	if !testableNetwork("unixgram") {
-		t.Skip("unixgram test")
-	}
-
 	addr := testUnixAddr()
 	laddr, err := ResolveUnixAddr("unixgram", addr)
 	if err != nil {
-		t.Fatal(err)
+		t.Fatalf("ResolveUnixAddr failed: %v", err)
 	}
 	c, err := ListenPacket("unixgram", addr)
 	if err != nil {
-		t.Fatal(err)
+		t.Fatalf("ListenPacket failed: %v", err)
 	}
 	defer os.Remove(addr)
 	defer c.Close()
@@ -234,28 +171,27 @@ func TestUnixgramWrite(t *testing.T) {
 func testUnixgramWriteConn(t *testing.T, raddr *UnixAddr) {
 	c, err := Dial("unixgram", raddr.String())
 	if err != nil {
-		t.Fatal(err)
+		t.Fatalf("Dial failed: %v", err)
 	}
 	defer c.Close()
 
-	b := []byte("CONNECTED-MODE SOCKET")
-	if _, err := c.(*UnixConn).WriteToUnix(b, raddr); err == nil {
-		t.Fatal("should fail")
+	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("should fail as ErrWriteToConnected: %v", err)
+		t.Fatalf("WriteToUnix should fail as ErrWriteToConnected: %v", err)
 	}
-	if _, err = c.(*UnixConn).WriteTo(b, raddr); err == nil {
-		t.Fatal("should fail")
+	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("should fail as ErrWriteToConnected: %v", err)
+		t.Fatalf("WriteTo should fail as ErrWriteToConnected: %v", err)
 	}
-	if _, _, err = c.(*UnixConn).WriteMsgUnix(b, nil, raddr); err == nil {
-		t.Fatal("should fail")
+	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("should fail as ErrWriteToConnected: %v", err)
+		t.Fatalf("WriteMsgUnix should fail as ErrWriteToConnected: %v", err)
 	}
-	if _, err := c.Write(b); err != nil {
-		t.Fatal(err)
+	if _, err := c.Write([]byte("Connection-oriented mode socket")); err != nil {
+		t.Fatalf("Write failed: %v", err)
 	}
 }
 
@@ -263,59 +199,52 @@ func testUnixgramWritePacketConn(t *testing.T, raddr *UnixAddr) {
 	addr := testUnixAddr()
 	c, err := ListenPacket("unixgram", addr)
 	if err != nil {
-		t.Fatal(err)
+		t.Fatalf("ListenPacket failed: %v", err)
 	}
 	defer os.Remove(addr)
 	defer c.Close()
 
-	b := []byte("UNCONNECTED-MODE SOCKET")
-	if _, err := c.(*UnixConn).WriteToUnix(b, raddr); err != nil {
-		t.Fatal(err)
+	if _, err := c.(*UnixConn).WriteToUnix([]byte("Connectionless mode socket"), raddr); err != nil {
+		t.Fatalf("WriteToUnix failed: %v", err)
 	}
-	if _, err := c.WriteTo(b, raddr); err != nil {
-		t.Fatal(err)
+	if _, err := c.WriteTo([]byte("Connectionless mode socket"), raddr); err != nil {
+		t.Fatalf("WriteTo failed: %v", err)
 	}
-	if _, _, err := c.(*UnixConn).WriteMsgUnix(b, nil, raddr); err != nil {
-		t.Fatal(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(b); err == nil {
-		t.Fatal("should fail")
+	if _, err := c.(*UnixConn).Write([]byte("Connectionless mode socket")); err == nil {
+		t.Fatal("Write should fail")
 	}
 }
 
 func TestUnixConnLocalAndRemoteNames(t *testing.T) {
-	if !testableNetwork("unix") {
-		t.Skip("unix test")
-	}
-
-	handler := func(ls *localServer, ln Listener) {}
 	for _, laddr := range []string{"", testUnixAddr()} {
 		laddr := laddr
 		taddr := testUnixAddr()
 		ta, err := ResolveUnixAddr("unix", taddr)
 		if err != nil {
-			t.Fatal(err)
+			t.Fatalf("ResolveUnixAddr failed: %v", err)
 		}
 		ln, err := ListenUnix("unix", ta)
 		if err != nil {
-			t.Fatal(err)
-		}
-		ls, err := (&streamListener{Listener: ln}).newLocalServer()
-		if err != nil {
-			t.Fatal(err)
-		}
-		defer ls.teardown()
-		if err := ls.buildup(handler); err != nil {
-			t.Fatal(err)
+			t.Fatalf("ListenUnix failed: %v", err)
 		}
+		defer func() {
+			ln.Close()
+			os.Remove(taddr)
+		}()
+
+		done := make(chan int)
+		go transponder(t, ln, done)
 
 		la, err := ResolveUnixAddr("unix", laddr)
 		if err != nil {
-			t.Fatal(err)
+			t.Fatalf("ResolveUnixAddr failed: %v", err)
 		}
 		c, err := DialUnix("unix", la, ta)
 		if err != nil {
-			t.Fatal(err)
+			t.Fatalf("DialUnix failed: %v", err)
 		}
 		defer func() {
 			c.Close()
@@ -324,7 +253,7 @@ func TestUnixConnLocalAndRemoteNames(t *testing.T) {
 			}
 		}()
 		if _, err := c.Write([]byte("UNIXCONN LOCAL AND REMOTE NAME TEST")); err != nil {
-			t.Fatal(err)
+			t.Fatalf("UnixConn.Write failed: %v", err)
 		}
 
 		switch runtime.GOOS {
@@ -343,24 +272,22 @@ func TestUnixConnLocalAndRemoteNames(t *testing.T) {
 				t.Fatalf("got %#v, expected %#v", ca.got, ca.want)
 			}
 		}
+
+		<-done
 	}
 }
 
 func TestUnixgramConnLocalAndRemoteNames(t *testing.T) {
-	if !testableNetwork("unixgram") {
-		t.Skip("unixgram test")
-	}
-
 	for _, laddr := range []string{"", testUnixAddr()} {
 		laddr := laddr
 		taddr := testUnixAddr()
 		ta, err := ResolveUnixAddr("unixgram", taddr)
 		if err != nil {
-			t.Fatal(err)
+			t.Fatalf("ResolveUnixAddr failed: %v", err)
 		}
 		c1, err := ListenUnixgram("unixgram", ta)
 		if err != nil {
-			t.Fatal(err)
+			t.Fatalf("ListenUnixgram failed: %v", err)
 		}
 		defer func() {
 			c1.Close()
@@ -370,12 +297,12 @@ func TestUnixgramConnLocalAndRemoteNames(t *testing.T) {
 		var la *UnixAddr
 		if laddr != "" {
 			if la, err = ResolveUnixAddr("unixgram", laddr); err != nil {
-				t.Fatal(err)
+				t.Fatalf("ResolveUnixAddr failed: %v", err)
 			}
 		}
 		c2, err := DialUnix("unixgram", la, ta)
 		if err != nil {
-			t.Fatal(err)
+			t.Fatalf("DialUnix failed: %v", err)
 		}
 		defer func() {
 			c2.Close()
@@ -399,33 +326,8 @@ func TestUnixgramConnLocalAndRemoteNames(t *testing.T) {
 		}
 		for _, ca := range connAddrs {
 			if !reflect.DeepEqual(ca.got, ca.want) {
-				t.Fatalf("got %#v; want %#v", ca.got, ca.want)
+				t.Fatalf("got %#v, expected %#v", ca.got, ca.want)
 			}
 		}
 	}
 }
-
-// forceGoDNS forces the resolver configuration to use the pure Go resolver
-// and returns a fixup function to restore the old settings.
-func forceGoDNS() func() {
-	c := systemConf()
-	oldGo := c.netGo
-	oldCgo := c.netCgo
-	fixup := func() {
-		c.netGo = oldGo
-		c.netCgo = oldCgo
-	}
-	c.netGo = true
-	c.netCgo = false
-	return fixup
-}
-
-// forceCgoDNS forces the resolver configuration to use the cgo resolver
-// and returns true to indicate that it did so.
-// (On non-Unix systems forceCgoDNS returns false.)
-func forceCgoDNS() bool {
-	c := systemConf()
-	c.netGo = false
-	c.netCgo = true
-	return true
-}
diff --git a/src/net/unixsock.go b/src/net/unixsock.go
index eb91d0d..8595584 100644
--- a/src/net/unixsock.go
+++ b/src/net/unixsock.go
@@ -23,11 +23,7 @@ func (a *UnixAddr) String() string {
 	return a.Name
 }
 
-func (a *UnixAddr) isWildcard() bool {
-	return a == nil || a.Name == ""
-}
-
-func (a *UnixAddr) opAddr() Addr {
+func (a *UnixAddr) toAddr() Addr {
 	if a == nil {
 		return nil
 	}
diff --git a/src/net/unixsock_plan9.go b/src/net/unixsock_plan9.go
index 84b6b60..c60c1d8 100644
--- a/src/net/unixsock_plan9.go
+++ b/src/net/unixsock_plan9.go
@@ -24,12 +24,12 @@ type UnixConn struct {
 // Timeout() == true after a fixed time limit; see SetDeadline and
 // SetReadDeadline.
 func (c *UnixConn) ReadFromUnix(b []byte) (int, *UnixAddr, error) {
-	return 0, nil, &OpError{Op: "read", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: syscall.EPLAN9}
+	return 0, nil, syscall.EPLAN9
 }
 
 // ReadFrom implements the PacketConn ReadFrom method.
 func (c *UnixConn) ReadFrom(b []byte) (int, Addr, error) {
-	return 0, nil, &OpError{Op: "read", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: syscall.EPLAN9}
+	return 0, nil, syscall.EPLAN9
 }
 
 // ReadMsgUnix reads a packet from c, copying the payload into b and
@@ -37,7 +37,7 @@ func (c *UnixConn) ReadFrom(b []byte) (int, Addr, error) {
 // bytes copied into b, the number of bytes copied into oob, the flags
 // that were set on the packet, and the source address of the packet.
 func (c *UnixConn) ReadMsgUnix(b, oob []byte) (n, oobn, flags int, addr *UnixAddr, err error) {
-	return 0, 0, 0, nil, &OpError{Op: "read", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: syscall.EPLAN9}
+	return 0, 0, 0, nil, syscall.EPLAN9
 }
 
 // WriteToUnix writes a packet to addr via c, copying the payload from b.
@@ -47,31 +47,31 @@ func (c *UnixConn) ReadMsgUnix(b, oob []byte) (n, oobn, flags int, addr *UnixAdd
 // SetWriteDeadline.  On packet-oriented connections, write timeouts
 // are rare.
 func (c *UnixConn) WriteToUnix(b []byte, addr *UnixAddr) (int, error) {
-	return 0, &OpError{Op: "write", Net: c.fd.dir, Source: c.fd.laddr, Addr: addr.opAddr(), Err: syscall.EPLAN9}
+	return 0, syscall.EPLAN9
 }
 
 // WriteTo implements the PacketConn WriteTo method.
 func (c *UnixConn) WriteTo(b []byte, addr Addr) (int, error) {
-	return 0, &OpError{Op: "write", Net: c.fd.dir, Source: c.fd.laddr, Addr: addr, Err: syscall.EPLAN9}
+	return 0, syscall.EPLAN9
 }
 
 // WriteMsgUnix writes a packet to addr via c, copying the payload
 // from b and the associated out-of-band data from oob.  It returns
 // the number of payload and out-of-band bytes written.
 func (c *UnixConn) WriteMsgUnix(b, oob []byte, addr *UnixAddr) (n, oobn int, err error) {
-	return 0, 0, &OpError{Op: "write", Net: c.fd.dir, Source: c.fd.laddr, Addr: addr.opAddr(), Err: syscall.EPLAN9}
+	return 0, 0, syscall.EPLAN9
 }
 
 // CloseRead shuts down the reading side of the Unix domain connection.
 // Most callers should just use Close.
 func (c *UnixConn) CloseRead() error {
-	return &OpError{Op: "close", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: syscall.EPLAN9}
+	return syscall.EPLAN9
 }
 
 // CloseWrite shuts down the writing side of the Unix domain connection.
 // Most callers should just use Close.
 func (c *UnixConn) CloseWrite() error {
-	return &OpError{Op: "close", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: syscall.EPLAN9}
+	return syscall.EPLAN9
 }
 
 // DialUnix connects to the remote address raddr on the network net,
@@ -82,49 +82,45 @@ func DialUnix(net string, laddr, raddr *UnixAddr) (*UnixConn, error) {
 }
 
 func dialUnix(net string, laddr, raddr *UnixAddr, deadline time.Time) (*UnixConn, error) {
-	return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: syscall.EPLAN9}
+	return nil, syscall.EPLAN9
 }
 
 // UnixListener is a Unix domain socket listener.  Clients should
 // typically use variables of type Listener instead of assuming Unix
 // domain sockets.
-type UnixListener struct {
-	fd *netFD
-}
+type UnixListener struct{}
 
 // ListenUnix announces on the Unix domain socket laddr and returns a
 // Unix listener.  The network net must be "unix" or "unixpacket".
 func ListenUnix(net string, laddr *UnixAddr) (*UnixListener, error) {
-	return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: syscall.EPLAN9}
+	return nil, syscall.EPLAN9
 }
 
 // AcceptUnix accepts the next incoming call and returns the new
 // connection.
 func (l *UnixListener) AcceptUnix() (*UnixConn, error) {
-	return nil, &OpError{Op: "accept", Net: l.fd.dir, Source: nil, Addr: l.fd.laddr, Err: syscall.EPLAN9}
+	return nil, syscall.EPLAN9
 }
 
 // Accept implements the Accept method in the Listener interface; it
 // waits for the next call and returns a generic Conn.
 func (l *UnixListener) Accept() (Conn, error) {
-	return nil, &OpError{Op: "accept", Net: l.fd.dir, Source: nil, Addr: l.fd.laddr, Err: syscall.EPLAN9}
+	return nil, syscall.EPLAN9
 }
 
 // Close stops listening on the Unix address.  Already accepted
 // connections are not closed.
 func (l *UnixListener) Close() error {
-	return &OpError{Op: "close", Net: l.fd.dir, Source: nil, Addr: l.fd.laddr, Err: syscall.EPLAN9}
+	return syscall.EPLAN9
 }
 
 // Addr returns the listener's network address.
-// The Addr returned is shared by all invocations of Addr, so
-// do not modify it.
 func (l *UnixListener) Addr() Addr { return nil }
 
 // SetDeadline sets the deadline associated with the listener.
 // A zero time value disables the deadline.
 func (l *UnixListener) SetDeadline(t time.Time) error {
-	return &OpError{Op: "set", Net: l.fd.dir, Source: nil, Addr: l.fd.laddr, Err: syscall.EPLAN9}
+	return syscall.EPLAN9
 }
 
 // File returns a copy of the underlying os.File, set to blocking
@@ -135,7 +131,7 @@ func (l *UnixListener) SetDeadline(t time.Time) error {
 // connection's.  Attempting to change properties of the original
 // using this duplicate may or may not have the desired effect.
 func (l *UnixListener) File() (*os.File, error) {
-	return nil, &OpError{Op: "file", Net: l.fd.dir, Source: nil, Addr: l.fd.laddr, Err: syscall.EPLAN9}
+	return nil, syscall.EPLAN9
 }
 
 // ListenUnixgram listens for incoming Unix datagram packets addressed
@@ -143,5 +139,5 @@ func (l *UnixListener) File() (*os.File, error) {
 // The returned connection's ReadFrom and WriteTo methods can be used
 // to receive and send packets with per-packet addressing.
 func ListenUnixgram(net string, laddr *UnixAddr) (*UnixConn, error) {
-	return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: syscall.EPLAN9}
+	return nil, syscall.EPLAN9
 }
diff --git a/src/net/unixsock_posix.go b/src/net/unixsock_posix.go
index 351d9b3..3c2e78b 100644
--- a/src/net/unixsock_posix.go
+++ b/src/net/unixsock_posix.go
@@ -87,6 +87,10 @@ func (a *UnixAddr) family() int {
 	return syscall.AF_UNIX
 }
 
+func (a *UnixAddr) isWildcard() bool {
+	return a == nil || a.Name == ""
+}
+
 func (a *UnixAddr) sockaddr(family int) (syscall.Sockaddr, error) {
 	if a == nil {
 		return nil, nil
@@ -109,11 +113,10 @@ func newUnixConn(fd *netFD) *UnixConn { return &UnixConn{conn{fd}} }
 // ReadFromUnix can be made to time out and return an error with
 // Timeout() == true after a fixed time limit; see SetDeadline and
 // SetReadDeadline.
-func (c *UnixConn) ReadFromUnix(b []byte) (int, *UnixAddr, error) {
+func (c *UnixConn) ReadFromUnix(b []byte) (n int, addr *UnixAddr, err error) {
 	if !c.ok() {
 		return 0, nil, syscall.EINVAL
 	}
-	var addr *UnixAddr
 	n, sa, err := c.fd.readFrom(b)
 	switch sa := sa.(type) {
 	case *syscall.SockaddrUnix:
@@ -121,10 +124,7 @@ func (c *UnixConn) ReadFromUnix(b []byte) (int, *UnixAddr, error) {
 			addr = &UnixAddr{Name: sa.Name, Net: sotypeToNet(c.fd.sotype)}
 		}
 	}
-	if err != nil {
-		err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
-	}
-	return n, addr, err
+	return
 }
 
 // ReadFrom implements the PacketConn ReadFrom method.
@@ -133,10 +133,7 @@ func (c *UnixConn) ReadFrom(b []byte) (int, Addr, error) {
 		return 0, nil, syscall.EINVAL
 	}
 	n, addr, err := c.ReadFromUnix(b)
-	if addr == nil {
-		return n, nil, err
-	}
-	return n, addr, err
+	return n, addr.toAddr(), err
 }
 
 // ReadMsgUnix reads a packet from c, copying the payload into b and
@@ -154,9 +151,6 @@ func (c *UnixConn) ReadMsgUnix(b, oob []byte) (n, oobn, flags int, addr *UnixAdd
 			addr = &UnixAddr{Name: sa.Name, Net: sotypeToNet(c.fd.sotype)}
 		}
 	}
-	if err != nil {
-		err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
-	}
 	return
 }
 
@@ -166,25 +160,21 @@ func (c *UnixConn) ReadMsgUnix(b, oob []byte) (n, oobn, flags int, addr *UnixAdd
 // Timeout() == true after a fixed time limit; see SetDeadline and
 // SetWriteDeadline.  On packet-oriented connections, write timeouts
 // are rare.
-func (c *UnixConn) WriteToUnix(b []byte, addr *UnixAddr) (int, error) {
+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, Source: c.fd.laddr, Addr: addr.opAddr(), Err: ErrWriteToConnected}
+		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, Source: c.fd.laddr, Addr: nil, Err: errMissingAddress}
+		return 0, &OpError{Op: "write", Net: c.fd.net, Addr: nil, Err: errMissingAddress}
 	}
 	if addr.Net != sotypeToNet(c.fd.sotype) {
-		return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: syscall.EAFNOSUPPORT}
+		return 0, syscall.EAFNOSUPPORT
 	}
 	sa := &syscall.SockaddrUnix{Name: addr.Name}
-	n, err := c.fd.writeTo(b, sa)
-	if err != nil {
-		err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err}
-	}
-	return n, err
+	return c.fd.writeTo(b, sa)
 }
 
 // WriteTo implements the PacketConn WriteTo method.
@@ -194,7 +184,7 @@ func (c *UnixConn) WriteTo(b []byte, addr Addr) (n int, err error) {
 	}
 	a, ok := addr.(*UnixAddr)
 	if !ok {
-		return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr, Err: syscall.EINVAL}
+		return 0, &OpError{"write", c.fd.net, addr, syscall.EINVAL}
 	}
 	return c.WriteToUnix(b, a)
 }
@@ -207,20 +197,16 @@ func (c *UnixConn) WriteMsgUnix(b, oob []byte, addr *UnixAddr) (n, oobn int, err
 		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, Source: c.fd.laddr, Addr: addr.opAddr(), Err: ErrWriteToConnected}
+		return 0, 0, &OpError{Op: "write", Net: c.fd.net, Addr: addr, Err: ErrWriteToConnected}
 	}
-	var sa syscall.Sockaddr
 	if addr != nil {
 		if addr.Net != sotypeToNet(c.fd.sotype) {
-			return 0, 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: syscall.EAFNOSUPPORT}
+			return 0, 0, syscall.EAFNOSUPPORT
 		}
-		sa = &syscall.SockaddrUnix{Name: addr.Name}
+		sa := &syscall.SockaddrUnix{Name: addr.Name}
+		return c.fd.writeMsg(b, oob, sa)
 	}
-	n, oobn, err = c.fd.writeMsg(b, oob, sa)
-	if err != nil {
-		err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err}
-	}
-	return
+	return c.fd.writeMsg(b, oob, nil)
 }
 
 // CloseRead shuts down the reading side of the Unix domain connection.
@@ -229,11 +215,7 @@ func (c *UnixConn) CloseRead() error {
 	if !c.ok() {
 		return syscall.EINVAL
 	}
-	err := c.fd.closeRead()
-	if err != nil {
-		err = &OpError{Op: "close", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
-	}
-	return err
+	return c.fd.closeRead()
 }
 
 // CloseWrite shuts down the writing side of the Unix domain connection.
@@ -242,11 +224,7 @@ func (c *UnixConn) CloseWrite() error {
 	if !c.ok() {
 		return syscall.EINVAL
 	}
-	err := c.fd.closeWrite()
-	if err != nil {
-		err = &OpError{Op: "close", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
-	}
-	return err
+	return c.fd.closeWrite()
 }
 
 // DialUnix connects to the remote address raddr on the network net,
@@ -256,7 +234,7 @@ func DialUnix(net string, laddr, raddr *UnixAddr) (*UnixConn, error) {
 	switch net {
 	case "unix", "unixgram", "unixpacket":
 	default:
-		return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: UnknownNetworkError(net)}
+		return nil, &OpError{Op: "dial", Net: net, Addr: raddr, Err: UnknownNetworkError(net)}
 	}
 	return dialUnix(net, laddr, raddr, noDeadline)
 }
@@ -264,7 +242,7 @@ func DialUnix(net string, laddr, raddr *UnixAddr) (*UnixConn, error) {
 func dialUnix(net string, laddr, raddr *UnixAddr, deadline time.Time) (*UnixConn, error) {
 	fd, err := unixSocket(net, laddr, raddr, "dial", deadline)
 	if err != nil {
-		return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: err}
+		return nil, &OpError{Op: "dial", Net: net, Addr: raddr, Err: err}
 	}
 	return newUnixConn(fd), nil
 }
@@ -283,16 +261,16 @@ func ListenUnix(net string, laddr *UnixAddr) (*UnixListener, error) {
 	switch net {
 	case "unix", "unixpacket":
 	default:
-		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: UnknownNetworkError(net)}
+		return nil, &OpError{Op: "listen", Net: net, Addr: laddr, Err: UnknownNetworkError(net)}
 	}
 	if laddr == nil {
-		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: errMissingAddress}
+		return nil, &OpError{Op: "listen", Net: net, Addr: nil, Err: errMissingAddress}
 	}
 	fd, err := unixSocket(net, laddr, nil, "listen", noDeadline)
 	if err != nil {
-		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: err}
+		return nil, &OpError{Op: "listen", Net: net, Addr: laddr, Err: err}
 	}
-	return &UnixListener{fd: fd, path: fd.laddr.String()}, nil
+	return &UnixListener{fd, fd.laddr.String()}, nil
 }
 
 // AcceptUnix accepts the next incoming call and returns the new
@@ -303,9 +281,10 @@ func (l *UnixListener) AcceptUnix() (*UnixConn, error) {
 	}
 	fd, err := l.fd.accept()
 	if err != nil {
-		return nil, &OpError{Op: "accept", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
+		return nil, err
 	}
-	return newUnixConn(fd), nil
+	c := newUnixConn(fd)
+	return c, nil
 }
 
 // Accept implements the Accept method in the Listener interface; it
@@ -338,28 +317,19 @@ func (l *UnixListener) Close() error {
 	if l.path[0] != '@' {
 		syscall.Unlink(l.path)
 	}
-	err := l.fd.Close()
-	if err != nil {
-		err = &OpError{Op: "close", Net: l.fd.net, Source: l.fd.laddr, Addr: l.fd.raddr, Err: err}
-	}
-	return err
+	return l.fd.Close()
 }
 
 // Addr returns the listener's network address.
-// The Addr returned is shared by all invocations of Addr, so
-// do not modify it.
 func (l *UnixListener) Addr() Addr { return l.fd.laddr }
 
 // SetDeadline sets the deadline associated with the listener.
 // A zero time value disables the deadline.
-func (l *UnixListener) SetDeadline(t time.Time) error {
+func (l *UnixListener) SetDeadline(t time.Time) (err error) {
 	if l == nil || l.fd == nil {
 		return syscall.EINVAL
 	}
-	if err := l.fd.setDeadline(t); err != nil {
-		return &OpError{Op: "set", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
-	}
-	return nil
+	return l.fd.setDeadline(t)
 }
 
 // File returns a copy of the underlying os.File, set to blocking
@@ -369,13 +339,7 @@ func (l *UnixListener) SetDeadline(t time.Time) error {
 // The returned os.File's file descriptor is different from the
 // connection's.  Attempting to change properties of the original
 // using this duplicate may or may not have the desired effect.
-func (l *UnixListener) File() (f *os.File, err error) {
-	f, err = l.fd.dup()
-	if err != nil {
-		err = &OpError{Op: "file", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
-	}
-	return
-}
+func (l *UnixListener) File() (f *os.File, err error) { return l.fd.dup() }
 
 // ListenUnixgram listens for incoming Unix datagram packets addressed
 // to the local address laddr.  The network net must be "unixgram".
@@ -385,14 +349,14 @@ func ListenUnixgram(net string, laddr *UnixAddr) (*UnixConn, error) {
 	switch net {
 	case "unixgram":
 	default:
-		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: UnknownNetworkError(net)}
+		return nil, &OpError{Op: "listen", Net: net, Addr: laddr, Err: UnknownNetworkError(net)}
 	}
 	if laddr == nil {
-		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: nil, Err: errMissingAddress}
+		return nil, &OpError{Op: "listen", Net: net, Addr: nil, Err: errMissingAddress}
 	}
 	fd, err := unixSocket(net, laddr, nil, "listen", noDeadline)
 	if err != nil {
-		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: err}
+		return nil, &OpError{Op: "listen", Net: net, Addr: laddr, Err: err}
 	}
 	return newUnixConn(fd), nil
 }
diff --git a/src/net/url/example_test.go b/src/net/url/example_test.go
index 645de2e..e55c1aa 100644
--- a/src/net/url/example_test.go
+++ b/src/net/url/example_test.go
@@ -43,26 +43,11 @@ func ExampleURL() {
 	// Output: https://google.com/search?q=golang
 }
 
-func ExampleURL_roundtrip() {
-	// Parse + String preserve the original encoding.
-	u, err := url.Parse("https://example.com/foo%2fbar")
-	if err != nil {
-		log.Fatal(err)
-	}
-	fmt.Println(u.Path)
-	fmt.Println(u.RawPath)
-	fmt.Println(u.String())
-	// Output:
-	// /foo/bar
-	// /foo%2fbar
-	// https://example.com/foo%2fbar
-}
-
 func ExampleURL_opaque() {
 	// Sending a literal '%' in an HTTP request's Path
 	req := &http.Request{
 		Method: "GET",
-		Host:   "example.com", // takes precedence over URL.Host
+		Host:   "example.com", // takes precendence over URL.Host
 		URL: &url.URL{
 			Host:   "ignored",
 			Scheme: "https",
@@ -84,17 +69,3 @@ func ExampleURL_opaque() {
 	// Accept-Encoding: gzip
 	//
 }
-
-func ExampleURL_ResolveReference() {
-	u, err := url.Parse("../../..//search?q=dotnet")
-	if err != nil {
-		log.Fatal(err)
-	}
-	base, err := url.Parse("http://example.com/directory/")
-	if err != nil {
-		log.Fatal(err)
-	}
-	fmt.Println(base.ResolveReference(u))
-	// Output:
-	// http://example.com/search?q=dotnet
-}
diff --git a/src/net/url/url.go b/src/net/url/url.go
index 8ffad66..f167408 100644
--- a/src/net/url/url.go
+++ b/src/net/url/url.go
@@ -9,7 +9,6 @@ package url
 import (
 	"bytes"
 	"errors"
-	"fmt"
 	"sort"
 	"strconv"
 	"strings"
@@ -52,7 +51,6 @@ type encoding int
 
 const (
 	encodePath encoding = 1 + iota
-	encodeHost
 	encodeUserPassword
 	encodeQueryComponent
 	encodeFragment
@@ -66,27 +64,12 @@ func (e EscapeError) Error() string {
 
 // Return true if the specified character should be escaped when
 // appearing in a URL string, according to RFC 3986.
-//
-// Please be informed that for now shouldEscape does not check all
-// reserved characters correctly. See golang.org/issue/5684.
 func shouldEscape(c byte, mode encoding) bool {
 	// §2.3 Unreserved characters (alphanum)
 	if 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || '0' <= c && c <= '9' {
 		return false
 	}
 
-	if mode == encodeHost {
-		// §3.2.2 Host allows
-		//	sub-delims = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "="
-		// as part of reg-name.
-		// We add : because we include :port as part of host.
-		// We add [ ] because we include [ipv6]:port as part of host
-		switch c {
-		case '!', '$', '&', '\'', '(', ')', '*', '+', ',', ';', '=', ':', '[', ']':
-			return false
-		}
-	}
-
 	switch c {
 	case '-', '_', '.', '~': // §2.3 Unreserved characters (mark)
 		return false
@@ -144,7 +127,7 @@ func unescape(s string, mode encoding) (string, error) {
 			if i+2 >= len(s) || !ishex(s[i+1]) || !ishex(s[i+2]) {
 				s = s[i:]
 				if len(s) > 3 {
-					s = s[:3]
+					s = s[0:3]
 				}
 				return "", EscapeError(s)
 			}
@@ -241,24 +224,16 @@ func escape(s string, mode encoding) string {
 // Note that the Path field is stored in decoded form: /%47%6f%2f becomes /Go/.
 // A consequence is that it is impossible to tell which slashes in the Path were
 // slashes in the raw URL and which were %2f. This distinction is rarely important,
-// but when it is, code must not use Path directly.
-//
-// Go 1.5 introduced the RawPath field to hold the encoded form of Path.
-// The Parse function sets both Path and RawPath in the URL it returns,
-// and URL's String method uses RawPath if it is a valid encoding of Path,
-// by calling the EncodedPath method.
-//
-// In earlier versions of Go, the more indirect workarounds were that an
-// HTTP server could consult req.RequestURI and an HTTP client could
-// construct a URL struct directly and set the Opaque field instead of Path.
-// These still work as well.
+// but when it is a client must use other routines to parse the raw URL or construct
+// the parsed URL. For example, an HTTP server can consult req.RequestURI, and
+// an HTTP client can use URL{Host: "example.com", Opaque: "//example.com/Go%2f"}
+// instead of URL{Host: "example.com", Path: "/Go/"}.
 type URL struct {
 	Scheme   string
 	Opaque   string    // encoded opaque data
 	User     *Userinfo // username and password information
 	Host     string    // host or host:port
 	Path     string
-	RawPath  string // encoded path hint (Go 1.5 and later only; see EscapedPath method)
 	RawQuery string // encoded query values, without '?'
 	Fragment string // fragment for references, without '#'
 }
@@ -330,7 +305,7 @@ func getscheme(rawurl string) (scheme, path string, err error) {
 			if i == 0 {
 				return "", "", errors.New("missing protocol scheme")
 			}
-			return rawurl[:i], rawurl[i+1:], nil
+			return rawurl[0:i], rawurl[i+1:], nil
 		default:
 			// we have encountered an invalid character,
 			// so there is no valid scheme
@@ -349,9 +324,9 @@ func split(s string, c string, cutc bool) (string, string) {
 		return s, ""
 	}
 	if cutc {
-		return s[:i], s[i+len(c):]
+		return s[0:i], s[i+len(c):]
 	}
-	return s[:i], s[i:]
+	return s[0:i], s[i:]
 }
 
 // Parse parses rawurl into a URL structure.
@@ -426,17 +401,14 @@ func parse(rawurl string, viaRequest bool) (url *URL, err error) {
 		if err != nil {
 			goto Error
 		}
+		if strings.Contains(url.Host, "%") {
+			err = errors.New("hexadecimal escape in host")
+			goto Error
+		}
 	}
 	if url.Path, err = unescape(rest, encodePath); err != nil {
 		goto Error
 	}
-	// RawPath is a hint as to the encoding of Path to use
-	// in url.EncodedPath. If that method already gets the
-	// right answer without RawPath, leave it empty.
-	// This will help make sure that people don't rely on it in general.
-	if url.EscapedPath() != rest && validEncodedPath(rest) {
-		url.RawPath = rest
-	}
 	return url, nil
 
 Error:
@@ -446,157 +418,36 @@ Error:
 func parseAuthority(authority string) (user *Userinfo, host string, err error) {
 	i := strings.LastIndex(authority, "@")
 	if i < 0 {
-		host, err = parseHost(authority)
-	} else {
-		host, err = parseHost(authority[i+1:])
-	}
-	if err != nil {
-		return nil, "", err
-	}
-	if i < 0 {
-		return nil, host, nil
+		host = authority
+		return
 	}
-	userinfo := authority[:i]
+	userinfo, host := authority[:i], authority[i+1:]
 	if strings.Index(userinfo, ":") < 0 {
 		if userinfo, err = unescape(userinfo, encodeUserPassword); err != nil {
-			return nil, "", err
+			return
 		}
 		user = User(userinfo)
 	} else {
 		username, password := split(userinfo, ":", true)
 		if username, err = unescape(username, encodeUserPassword); err != nil {
-			return nil, "", err
+			return
 		}
 		if password, err = unescape(password, encodeUserPassword); err != nil {
-			return nil, "", err
+			return
 		}
 		user = UserPassword(username, password)
 	}
-	return user, host, nil
-}
-
-// parseHost parses host as an authority without user
-// information. That is, as host[:port].
-func parseHost(host string) (string, error) {
-	litOrName := host
-	if strings.HasPrefix(host, "[") {
-		// Parse an IP-Literal in RFC 3986 and RFC 6874.
-		// E.g., "[fe80::1], "[fe80::1%25en0]"
-		//
-		// RFC 4007 defines "%" as a delimiter character in
-		// the textual representation of IPv6 addresses.
-		// Per RFC 6874, in URIs that "%" is encoded as "%25".
-		i := strings.LastIndex(host, "]")
-		if i < 0 {
-			return "", errors.New("missing ']' in host")
-		}
-		colonPort := host[i+1:]
-		if !validOptionalPort(colonPort) {
-			return "", fmt.Errorf("invalid port %q after host", colonPort)
-		}
-		// Parse a host subcomponent without a ZoneID in RFC
-		// 6874 because the ZoneID is allowed to use the
-		// percent encoded form.
-		j := strings.Index(host[:i], "%25")
-		if j < 0 {
-			litOrName = host[1:i]
-		} else {
-			litOrName = host[1:j]
-		}
-	}
-
-	// A URI containing an IP-Literal without a ZoneID or
-	// IPv4address in RFC 3986 and RFC 6847 must not be
-	// percent-encoded.
-	//
-	// A URI containing a DNS registered name in RFC 3986 is
-	// allowed to be percent-encoded, though we don't use it for
-	// now to avoid messing up with the gap between allowed
-	// characters in URI and allowed characters in DNS.
-	// See golang.org/issue/7991.
-	if strings.Contains(litOrName, "%") {
-		return "", errors.New("percent-encoded characters in host")
-	}
-	var err error
-	if host, err = unescape(host, encodeHost); err != nil {
-		return "", err
-	}
-	return host, nil
-}
-
-// EscapedPath returns the escaped form of u.Path.
-// In general there are multiple possible escaped forms of any path.
-// EscapedPath returns u.RawPath when it is a valid escaping of u.Path.
-// Otherwise EscapedPath ignores u.RawPath and computes an escaped
-// form on its own.
-// The String and RequestURI methods use EscapedPath to construct
-// their results.
-// In general, code should call EscapedPath instead of
-// reading u.RawPath directly.
-func (u *URL) EscapedPath() string {
-	if u.RawPath != "" && validEncodedPath(u.RawPath) {
-		p, err := unescape(u.RawPath, encodePath)
-		if err == nil && p == u.Path {
-			return u.RawPath
-		}
-	}
-	if u.Path == "*" {
-		return "*" // don't escape (Issue 11202)
-	}
-	return escape(u.Path, encodePath)
-}
-
-// validEncodedPath reports whether s is a valid encoded path.
-// It must not contain any bytes that require escaping during path encoding.
-func validEncodedPath(s string) bool {
-	for i := 0; i < len(s); i++ {
-		// RFC 3986, Appendix A.
-		// pchar = unreserved / pct-encoded / sub-delims / ":" / "@".
-		// shouldEscape is not quite compliant with the RFC,
-		// so we check the sub-delims ourselves and let
-		// shouldEscape handle the others.
-		switch s[i] {
-		case '!', '$', '&', '\'', '(', ')', '*', '+', ',', ';', '=', ':', '@':
-			// ok
-		case '[', ']':
-			// ok - not specified in RFC 3986 but left alone by modern browsers
-		case '%':
-			// ok - percent encoded, will decode
-		default:
-			if shouldEscape(s[i], encodePath) {
-				return false
-			}
-		}
-	}
-	return true
-}
-
-// validOptionalPort reports whether port is either an empty string
-// or matches /^:\d+$/
-func validOptionalPort(port string) bool {
-	if port == "" {
-		return true
-	}
-	if port[0] != ':' || len(port) == 1 {
-		return false
-	}
-	for _, b := range port[1:] {
-		if b < '0' || b > '9' {
-			return false
-		}
-	}
-	return true
+	return
 }
 
 // String reassembles the URL into a valid URL string.
 // The general form of the result is one of:
 //
-//	scheme:opaque?query#fragment
+//	scheme:opaque
 //	scheme://userinfo@host/path?query#fragment
 //
 // If u.Opaque is non-empty, String uses the first form;
 // otherwise it uses the second form.
-// To obtain the path, String uses u.EncodedPath().
 //
 // In the second form, the following rules apply:
 //	- if u.Scheme is empty, scheme: is omitted.
@@ -624,14 +475,13 @@ func (u *URL) String() string {
 				buf.WriteByte('@')
 			}
 			if h := u.Host; h != "" {
-				buf.WriteString(escape(h, encodeHost))
+				buf.WriteString(h)
 			}
 		}
-		path := u.EscapedPath()
-		if path != "" && path[0] != '/' && u.Host != "" {
+		if u.Path != "" && u.Path[0] != '/' && u.Host != "" {
 			buf.WriteByte('/')
 		}
-		buf.WriteString(path)
+		buf.WriteString(escape(u.Path, encodePath))
 	}
 	if u.RawQuery != "" {
 		buf.WriteByte('?')
@@ -789,7 +639,7 @@ func resolvePath(base, ref string) string {
 	return "/" + strings.TrimLeft(strings.Join(dst, "/"), "/")
 }
 
-// IsAbs reports whether the URL is absolute.
+// IsAbs returns true if the URL is absolute.
 func (u *URL) IsAbs() bool {
 	return u.Scheme != ""
 }
@@ -853,7 +703,7 @@ func (u *URL) Query() Values {
 func (u *URL) RequestURI() string {
 	result := u.Opaque
 	if result == "" {
-		result = u.EscapedPath()
+		result = escape(u.Path, encodePath)
 		if result == "" {
 			result = "/"
 		}
diff --git a/src/net/url/url_test.go b/src/net/url/url_test.go
index ff6e9e4..d8b19d8 100644
--- a/src/net/url/url_test.go
+++ b/src/net/url/url_test.go
@@ -13,7 +13,7 @@ import (
 
 type URLTest struct {
 	in        string
-	out       *URL   // expected parse; RawPath="" means same as Path
+	out       *URL
 	roundtrip string // expected result of reserializing the URL; empty means same as "in".
 }
 
@@ -41,12 +41,11 @@ var urltests = []URLTest{
 	{
 		"http://www.google.com/file%20one%26two",
 		&URL{
-			Scheme:  "http",
-			Host:    "www.google.com",
-			Path:    "/file one&two",
-			RawPath: "/file%20one%26two",
+			Scheme: "http",
+			Host:   "www.google.com",
+			Path:   "/file one&two",
 		},
-		"",
+		"http://www.google.com/file%20one&two",
 	},
 	// user
 	{
@@ -290,140 +289,6 @@ var urltests = []URLTest{
 		},
 		"",
 	},
-	// host subcomponent; IPv4 address in RFC 3986
-	{
-		"http://192.168.0.1/",
-		&URL{
-			Scheme: "http",
-			Host:   "192.168.0.1",
-			Path:   "/",
-		},
-		"",
-	},
-	// host and port subcomponents; IPv4 address in RFC 3986
-	{
-		"http://192.168.0.1:8080/",
-		&URL{
-			Scheme: "http",
-			Host:   "192.168.0.1:8080",
-			Path:   "/",
-		},
-		"",
-	},
-	// host subcomponent; IPv6 address in RFC 3986
-	{
-		"http://[fe80::1]/",
-		&URL{
-			Scheme: "http",
-			Host:   "[fe80::1]",
-			Path:   "/",
-		},
-		"",
-	},
-	// host and port subcomponents; IPv6 address in RFC 3986
-	{
-		"http://[fe80::1]:8080/",
-		&URL{
-			Scheme: "http",
-			Host:   "[fe80::1]:8080",
-			Path:   "/",
-		},
-		"",
-	},
-	// host subcomponent; IPv6 address with zone identifier in RFC 6847
-	{
-		"http://[fe80::1%25en0]/", // alphanum zone identifier
-		&URL{
-			Scheme: "http",
-			Host:   "[fe80::1%en0]",
-			Path:   "/",
-		},
-		"",
-	},
-	// host and port subcomponents; IPv6 address with zone identifier in RFC 6847
-	{
-		"http://[fe80::1%25en0]:8080/", // alphanum zone identifier
-		&URL{
-			Scheme: "http",
-			Host:   "[fe80::1%en0]:8080",
-			Path:   "/",
-		},
-		"",
-	},
-	// host subcomponent; IPv6 address with zone identifier in RFC 6847
-	{
-		"http://[fe80::1%25%65%6e%301-._~]/", // percent-encoded+unreserved zone identifier
-		&URL{
-			Scheme: "http",
-			Host:   "[fe80::1%en01-._~]",
-			Path:   "/",
-		},
-		"http://[fe80::1%25en01-._~]/",
-	},
-	// host and port subcomponents; IPv6 address with zone identifier in RFC 6847
-	{
-		"http://[fe80::1%25%65%6e%301-._~]:8080/", // percent-encoded+unreserved zone identifier
-		&URL{
-			Scheme: "http",
-			Host:   "[fe80::1%en01-._~]:8080",
-			Path:   "/",
-		},
-		"http://[fe80::1%25en01-._~]:8080/",
-	},
-	// alternate escapings of path survive round trip
-	{
-		"http://rest.rsc.io/foo%2fbar/baz%2Fquux?alt=media",
-		&URL{
-			Scheme:   "http",
-			Host:     "rest.rsc.io",
-			Path:     "/foo/bar/baz/quux",
-			RawPath:  "/foo%2fbar/baz%2Fquux",
-			RawQuery: "alt=media",
-		},
-		"",
-	},
-	// issue 12036
-	{
-		"mysql://a,b,c/bar",
-		&URL{
-			Scheme: "mysql",
-			Host:   "a,b,c",
-			Path:   "/bar",
-		},
-		"",
-	},
-	// worst case host, still round trips
-	{
-		"scheme://!$&'()*+,;=hello!:port/path",
-		&URL{
-			Scheme: "scheme",
-			Host:   "!$&'()*+,;=hello!:port",
-			Path:   "/path",
-		},
-		"",
-	},
-	// worst case path, still round trips
-	{
-		"http://host/!$&'()*+,;=:@[hello]",
-		&URL{
-			Scheme:  "http",
-			Host:    "host",
-			Path:    "/!$&'()*+,;=:@[hello]",
-			RawPath: "/!$&'()*+,;=:@[hello]",
-		},
-		"",
-	},
-	// golang.org/issue/5684
-	{
-		"http://example.com/oid/[order_id]",
-		&URL{
-			Scheme:  "http",
-			Host:    "example.com",
-			Path:    "/oid/[order_id]",
-			RawPath: "/oid/[order_id]",
-		},
-		"",
-	},
 }
 
 // more useful string for debugging than fmt's struct printer
@@ -435,8 +300,8 @@ func ufmt(u *URL) string {
 			pass = p
 		}
 	}
-	return fmt.Sprintf("opaque=%q, scheme=%q, user=%#v, pass=%#v, host=%q, path=%q, rawpath=%q, rawq=%q, frag=%q",
-		u.Opaque, u.Scheme, user, pass, u.Host, u.Path, u.RawPath, u.RawQuery, u.Fragment)
+	return fmt.Sprintf("opaque=%q, scheme=%q, user=%#v, pass=%#v, host=%q, path=%q, rawq=%q, frag=%q",
+		u.Opaque, u.Scheme, user, pass, u.Host, u.Path, u.RawQuery, u.Fragment)
 }
 
 func DoTest(t *testing.T, parse func(string) (*URL, error), name string, tests []URLTest) {
@@ -493,33 +358,9 @@ var parseRequestURLTests = []struct {
 	{"/", true},
 	{pathThatLooksSchemeRelative, true},
 	{"//not.a.user@%66%6f%6f.com/just/a/path/also", true},
-	{"*", true},
-	{"http://192.168.0.1/", true},
-	{"http://192.168.0.1:8080/", true},
-	{"http://[fe80::1]/", true},
-	{"http://[fe80::1]:8080/", true},
-
-	// Tests exercising RFC 6874 compliance:
-	{"http://[fe80::1%25en0]/", true},                 // with alphanum zone identifier
-	{"http://[fe80::1%25en0]:8080/", true},            // with alphanum zone identifier
-	{"http://[fe80::1%25%65%6e%301-._~]/", true},      // with percent-encoded+unreserved zone identifier
-	{"http://[fe80::1%25%65%6e%301-._~]:8080/", true}, // with percent-encoded+unreserved zone identifier
-
 	{"foo.html", false},
 	{"../dir/", false},
-	{"http://192.168.0.%31/", false},
-	{"http://192.168.0.%31:8080/", false},
-	{"http://[fe80::%31]/", false},
-	{"http://[fe80::%31]:8080/", false},
-	{"http://[fe80::%31%25en0]/", false},
-	{"http://[fe80::%31%25en0]:8080/", false},
-
-	// These two cases are valid as textual representations as
-	// described in RFC 4007, but are not valid as address
-	// literals with IPv6 zone identifiers in URIs as described in
-	// RFC 6874.
-	{"http://[fe80::1%en0]/", false},
-	{"http://[fe80::1%en0]:8080/", false},
+	{"*", true},
 }
 
 func TestParseRequestURI(t *testing.T) {
@@ -1028,25 +869,6 @@ var requritests = []RequestURITest{
 		},
 		"http://other.example.com/%2F/%2F/",
 	},
-	// better fix for issue 4860
-	{
-		&URL{
-			Scheme:  "http",
-			Host:    "example.com",
-			Path:    "/////",
-			RawPath: "/%2F/%2F/",
-		},
-		"/%2F/%2F/",
-	},
-	{
-		&URL{
-			Scheme:  "http",
-			Host:    "example.com",
-			Path:    "/////",
-			RawPath: "/WRONG/", // ignored because doesn't match Path
-		},
-		"/////",
-	},
 	{
 		&URL{
 			Scheme:   "http",
@@ -1058,26 +880,6 @@ var requritests = []RequestURITest{
 	},
 	{
 		&URL{
-			Scheme:   "http",
-			Host:     "example.com",
-			Path:     "/a b",
-			RawPath:  "/a b", // ignored because invalid
-			RawQuery: "q=go+language",
-		},
-		"/a%20b?q=go+language",
-	},
-	{
-		&URL{
-			Scheme:   "http",
-			Host:     "example.com",
-			Path:     "/a?b",
-			RawPath:  "/a?b", // ignored because invalid
-			RawQuery: "q=go+language",
-		},
-		"/a%3Fb?q=go+language",
-	},
-	{
-		&URL{
 			Scheme: "myschema",
 			Opaque: "opaque",
 		},
@@ -1112,54 +914,6 @@ func TestParseFailure(t *testing.T) {
 	}
 }
 
-func TestParseAuthority(t *testing.T) {
-	tests := []struct {
-		in      string
-		wantErr bool
-	}{
-		{"http://[::1]", false},
-		{"http://[::1]:80", false},
-		{"http://[::1]:namedport", true}, // rfc3986 3.2.3
-		{"http://[::1]/", false},
-		{"http://[::1]a", true},
-		{"http://[::1]%23", true},
-		{"http://[::1%25en0]", false},     // valid zone id
-		{"http://[::1]:", true},           // colon, but no port
-		{"http://[::1]:%38%30", true},     // no hex in port
-		{"http://[::1%25%10]", false},     // TODO: reject the %10 after the valid zone %25 separator?
-		{"http://[%10::1]", true},         // no %xx escapes in IP address
-		{"http://[::1]/%48", false},       // %xx in path is fine
-		{"http://%41:8080/", true},        // TODO: arguably we should accept reg-name with %xx
-		{"mysql://x@y(z:123)/foo", false}, // golang.org/issue/12023
-		{"mysql://x@y(1.2.3.4:123)/foo", false},
-		{"mysql://x@y([2001:db8::1]:123)/foo", false},
-		{"http://[]%20%48%54%54%50%2f%31%2e%31%0a%4d%79%48%65%61%64%65%72%3a%20%31%32%33%0a%0a/", true}, // golang.org/issue/11208
-	}
-	for _, tt := range tests {
-		u, err := Parse(tt.in)
-		if tt.wantErr {
-			if err == nil {
-				t.Errorf("Parse(%q) = %#v; want an error", tt.in, u)
-			}
-			continue
-		}
-		if err != nil {
-			t.Logf("Parse(%q) = %v; want no error", tt.in, err)
-		}
-	}
-}
-
-// Issue 11202
-func TestStarRequest(t *testing.T) {
-	u, err := Parse("*")
-	if err != nil {
-		t.Fatal(err)
-	}
-	if got, want := u.RequestURI(), "*"; got != want {
-		t.Errorf("RequestURI = %q; want %q", got, want)
-	}
-}
-
 type shouldEscapeTest struct {
 	in     byte
 	mode   encoding
@@ -1172,7 +926,6 @@ var shouldEscapeTests = []shouldEscapeTest{
 	{'a', encodeUserPassword, false},
 	{'a', encodeQueryComponent, false},
 	{'a', encodeFragment, false},
-	{'a', encodeHost, false},
 	{'z', encodePath, false},
 	{'A', encodePath, false},
 	{'Z', encodePath, false},
@@ -1197,29 +950,6 @@ var shouldEscapeTests = []shouldEscapeTest{
 	{',', encodeUserPassword, false},
 	{';', encodeUserPassword, false},
 	{'=', encodeUserPassword, false},
-
-	// Host (IP address, IPv6 address, registered name, port suffix; §3.2.2)
-	{'!', encodeHost, false},
-	{'$', encodeHost, false},
-	{'&', encodeHost, false},
-	{'\'', encodeHost, false},
-	{'(', encodeHost, false},
-	{')', encodeHost, false},
-	{'*', encodeHost, false},
-	{'+', encodeHost, false},
-	{',', encodeHost, false},
-	{';', encodeHost, false},
-	{'=', encodeHost, false},
-	{':', encodeHost, false},
-	{'[', encodeHost, false},
-	{']', encodeHost, false},
-	{'0', encodeHost, false},
-	{'9', encodeHost, false},
-	{'A', encodeHost, false},
-	{'z', encodeHost, false},
-	{'_', encodeHost, false},
-	{'-', encodeHost, false},
-	{'.', encodeHost, false},
 }
 
 func TestShouldEscape(t *testing.T) {
diff --git a/src/net/z_last_test.go b/src/net/z_last_test.go
new file mode 100644
index 0000000..716c103
--- /dev/null
+++ b/src/net/z_last_test.go
@@ -0,0 +1,99 @@
+// 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"
+	"time"
+)
+
+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.
+}
+
+func TestLookupIPDeadline(t *testing.T) {
+	if !*testDNSFlood {
+		t.Skip("test disabled; use -dnsflood to enable")
+	}
+
+	const N = 5000
+	const timeout = 3 * time.Second
+	c := make(chan error, 2*N)
+	for i := 0; i < N; i++ {
+		name := fmt.Sprintf("%d.net-test.golang.org", i)
+		go func() {
+			_, err := lookupIPDeadline(name, time.Now().Add(timeout/2))
+			c <- err
+		}()
+		go func() {
+			_, err := lookupIPDeadline(name, time.Now().Add(timeout))
+			c <- err
+		}()
+	}
+	qstats := struct {
+		succeeded, failed         int
+		timeout, temporary, other int
+		unknown                   int
+	}{}
+	deadline := time.After(timeout + time.Second)
+	for i := 0; i < 2*N; i++ {
+		select {
+		case <-deadline:
+			t.Fatal("deadline exceeded")
+		case err := <-c:
+			switch err := err.(type) {
+			case nil:
+				qstats.succeeded++
+			case Error:
+				qstats.failed++
+				if err.Timeout() {
+					qstats.timeout++
+				}
+				if err.Temporary() {
+					qstats.temporary++
+				}
+				if !err.Timeout() && !err.Temporary() {
+					qstats.other++
+				}
+			default:
+				qstats.failed++
+				qstats.unknown++
+			}
+		}
+	}
+
+	// A high volume of DNS queries for sub-domain of golang.org
+	// would be coordinated by authoritative or recursive server,
+	// or stub resolver which implements query-response rate
+	// limitation, so we can expect some query successes and more
+	// failures including timeout, temporary and other here.
+	// As a rule, unknown must not be shown but it might possibly
+	// happen due to issue 4856 for now.
+	t.Logf("%v succeeded, %v failed (%v timeout, %v temporary, %v other, %v unknown)", qstats.succeeded, qstats.failed, qstats.timeout, qstats.temporary, qstats.other, qstats.unknown)
+}
diff --git a/src/os/env.go b/src/os/env.go
index a4ede15..d0494a4 100644
--- a/src/os/env.go
+++ b/src/os/env.go
@@ -33,7 +33,7 @@ func ExpandEnv(s string) string {
 	return Expand(s, Getenv)
 }
 
-// isShellSpecialVar reports whether the character identifies a special
+// isSpellSpecialVar reports whether the character identifies a special
 // shell variable such as $*.
 func isShellSpecialVar(c uint8) bool {
 	switch c {
@@ -48,7 +48,7 @@ func isAlphaNum(c uint8) bool {
 	return c == '_' || '0' <= c && c <= '9' || 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z'
 }
 
-// getShellName returns the name that begins the string and the number of bytes
+// getName returns the name that begins the string and the number of bytes
 // consumed to extract it.  If the name is enclosed in {}, it's part of a ${}
 // expansion and two more bytes are needed than the length of the name.
 func getShellName(s string) (string, int) {
@@ -81,15 +81,6 @@ func Getenv(key string) string {
 	return v
 }
 
-// LookupEnv retrieves the value of the environment variable named
-// by the key. If the variable is present in the environment the
-// value (which may be empty) is returned and the boolean is true.
-// Otherwise the returned value will be empty and the boolean will
-// be false.
-func LookupEnv(key string) (string, bool) {
-	return syscall.Getenv(key)
-}
-
 // Setenv sets the value of the environment variable named by the key.
 // It returns an error, if any.
 func Setenv(key, value string) error {
diff --git a/src/os/env_test.go b/src/os/env_test.go
index d1074cd..e618067 100644
--- a/src/os/env_test.go
+++ b/src/os/env_test.go
@@ -94,20 +94,3 @@ func TestUnsetenv(t *testing.T) {
 		t.Fatal("Unsetenv didn't clear TestUnsetenv")
 	}
 }
-
-func TestLookupEnv(t *testing.T) {
-	const smallpox = "SMALLPOX"      // No one has smallpox.
-	value, ok := LookupEnv(smallpox) // Should not exist.
-	if ok || value != "" {
-		t.Fatalf("%s=%q", smallpox, value)
-	}
-	defer Unsetenv(smallpox)
-	err := Setenv(smallpox, "virus")
-	if err != nil {
-		t.Fatalf("failed to release smallpox virus")
-	}
-	value, ok = LookupEnv(smallpox)
-	if !ok {
-		t.Errorf("smallpox release failed; world remains safe but LookupEnv is broken")
-	}
-}
diff --git a/src/os/error_windows_test.go b/src/os/error_windows_test.go
new file mode 100644
index 0000000..3e6504f
--- /dev/null
+++ b/src/os/error_windows_test.go
@@ -0,0 +1,47 @@
+// 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 os_test
+
+import (
+	"io/ioutil"
+	"os"
+	"path/filepath"
+	"testing"
+)
+
+func TestErrIsExistAfterRename(t *testing.T) {
+	dir, err := ioutil.TempDir("", "go-build")
+	if err != nil {
+		t.Fatalf("Create temp directory: %v", err)
+	}
+	defer os.RemoveAll(dir)
+
+	src := filepath.Join(dir, "src")
+	dest := filepath.Join(dir, "dest")
+
+	f, err := os.Create(src)
+	if err != nil {
+		t.Fatalf("Create file %v: %v", src, err)
+	}
+	f.Close()
+	err = os.Rename(src, dest)
+	if err != nil {
+		t.Fatalf("Rename %v to %v: %v", src, dest, err)
+	}
+
+	f, err = os.Create(src)
+	if err != nil {
+		t.Fatalf("Create file %v: %v", src, err)
+	}
+	f.Close()
+	err = os.Rename(src, dest)
+	if err == nil {
+		t.Fatal("Rename should have failed")
+	}
+	if s := checkErrorPredicate("os.IsExist", os.IsExist, err); s != "" {
+		t.Fatal(s)
+		return
+	}
+}
diff --git a/src/os/exec.go b/src/os/exec.go
index 15e95b9..5aea309 100644
--- a/src/os/exec.go
+++ b/src/os/exec.go
@@ -13,8 +13,8 @@ import (
 // Process stores the information about a process created by StartProcess.
 type Process struct {
 	Pid    int
-	handle uintptr // handle is accessed atomically on Windows
-	isdone uint32  // process has been successfully waited on, non zero if true
+	handle uintptr
+	isdone uint32 // process has been successfully waited on, non zero if true
 }
 
 func newProcess(pid int, handle uintptr) *Process {
diff --git a/src/os/exec/exec.go b/src/os/exec/exec.go
index 8a84e26..72b4905 100644
--- a/src/os/exec/exec.go
+++ b/src/os/exec/exec.go
@@ -32,9 +32,6 @@ func (e *Error) Error() string {
 }
 
 // Cmd represents an external command being prepared or run.
-//
-// A Cmd cannot be reused after calling its Run, Output or CombinedOutput
-// methods.
 type Cmd struct {
 	// Path is the path of the command to run.
 	//
@@ -83,8 +80,8 @@ type Cmd struct {
 	// new process. It does not include standard input, standard output, or
 	// standard error. If non-nil, entry i becomes file descriptor 3+i.
 	//
-	// BUG(rsc): On OS X 10.6, child processes may sometimes inherit unwanted fds.
-	// https://golang.org/issue/2603
+	// BUG: on OS X 10.6, child processes may sometimes inherit unwanted fds.
+	// http://golang.org/issue/2603
 	ExtraFiles []*os.File
 
 	// SysProcAttr holds optional, operating system-specific attributes.
@@ -157,11 +154,6 @@ func (c *Cmd) argv() []string {
 	return []string{c.Path}
 }
 
-// skipStdinCopyError optionally specifies a function which reports
-// whether the provided the stdin copy error should be ignored.
-// It is non-nil everywhere but Plan 9, which lacks EPIPE. See exec_posix.go.
-var skipStdinCopyError func(error) bool
-
 func (c *Cmd) stdin() (f *os.File, err error) {
 	if c.Stdin == nil {
 		f, err = os.Open(os.DevNull)
@@ -185,9 +177,6 @@ func (c *Cmd) stdin() (f *os.File, err error) {
 	c.closeAfterWait = append(c.closeAfterWait, pw)
 	c.goroutine = append(c.goroutine, func() error {
 		_, err := io.Copy(pw, c.Stdin)
-		if skip := skipStdinCopyError; skip != nil && skip(err) {
-			err = nil
-		}
 		if err1 := pw.Close(); err == nil {
 			err = err1
 		}
@@ -230,7 +219,6 @@ func (c *Cmd) writerDescriptor(w io.Writer) (f *os.File, err error) {
 	c.closeAfterWait = append(c.closeAfterWait, pr)
 	c.goroutine = append(c.goroutine, func() error {
 		_, err := io.Copy(w, pr)
-		pr.Close() // in case io.Copy stopped due to write error
 		return err
 	})
 	return pw, nil
@@ -364,10 +352,6 @@ func (e *ExitError) Error() string {
 // error is of type *ExitError. Other error types may be
 // returned for I/O problems.
 //
-// If c.Stdin is not an *os.File, Wait also waits for the I/O loop
-// copying from c.Stdin into the process's standard input
-// to complete.
-//
 // Wait releases any resources associated with the Cmd.
 func (c *Cmd) Wait() error {
 	if c.Process == nil {
diff --git a/src/os/exec/exec_test.go b/src/os/exec/exec_test.go
index 28be21c..197d3e8 100644
--- a/src/os/exec/exec_test.go
+++ b/src/os/exec/exec_test.go
@@ -11,7 +11,6 @@ import (
 	"bufio"
 	"bytes"
 	"fmt"
-	"internal/testenv"
 	"io"
 	"io/ioutil"
 	"log"
@@ -29,8 +28,9 @@ import (
 )
 
 func helperCommand(t *testing.T, s ...string) *exec.Cmd {
-	testenv.MustHaveExec(t)
-
+	if runtime.GOOS == "nacl" {
+		t.Skip("skipping on nacl")
+	}
 	cs := []string{"-test.run=TestHelperProcess", "--"}
 	cs = append(cs, s...)
 	cmd := exec.Command(os.Args[0], cs...)
@@ -49,8 +49,6 @@ func TestEcho(t *testing.T) {
 }
 
 func TestCommandRelativeName(t *testing.T) {
-	testenv.MustHaveExec(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"
@@ -248,12 +246,6 @@ func TestPipeLookPathLeak(t *testing.T) {
 }
 
 func numOpenFDS(t *testing.T) (n int, lsof []byte) {
-	if runtime.GOOS == "android" {
-		// Android's stock lsof does not obey the -p option,
-		// so extra filtering is needed. (golang.org/issue/10206)
-		return numOpenFDsAndroid(t)
-	}
-
 	lsof, err := exec.Command("lsof", "-b", "-n", "-p", strconv.Itoa(os.Getpid())).Output()
 	if err != nil {
 		t.Skip("skipping test; error finding or running lsof")
@@ -261,45 +253,6 @@ func numOpenFDS(t *testing.T) (n int, lsof []byte) {
 	return bytes.Count(lsof, []byte("\n")), lsof
 }
 
-func numOpenFDsAndroid(t *testing.T) (n int, lsof []byte) {
-	raw, err := exec.Command("lsof").Output()
-	if err != nil {
-		t.Skip("skipping test; error finding or running lsof")
-	}
-
-	// First find the PID column index by parsing the first line, and
-	// select lines containing pid in the column.
-	pid := []byte(strconv.Itoa(os.Getpid()))
-	pidCol := -1
-
-	s := bufio.NewScanner(bytes.NewReader(raw))
-	for s.Scan() {
-		line := s.Bytes()
-		fields := bytes.Fields(line)
-		if pidCol < 0 {
-			for i, v := range fields {
-				if bytes.Equal(v, []byte("PID")) {
-					pidCol = i
-					break
-				}
-			}
-			lsof = append(lsof, line...)
-			continue
-		}
-		if bytes.Equal(fields[pidCol], pid) {
-			lsof = append(lsof, '\n')
-			lsof = append(lsof, line...)
-		}
-	}
-	if pidCol < 0 {
-		t.Fatal("error processing lsof output: unexpected header format")
-	}
-	if err := s.Err(); err != nil {
-		t.Fatalf("error processing lsof output: %v", err)
-	}
-	return bytes.Count(lsof, []byte("\n")), lsof
-}
-
 var testedAlreadyLeaked = false
 
 // basefds returns the number of expected file descriptors
@@ -318,15 +271,15 @@ func closeUnexpectedFds(t *testing.T, m string) {
 }
 
 func TestExtraFilesFDShuffle(t *testing.T) {
-	t.Skip("flaky test; see https://golang.org/issue/5780")
+	t.Skip("flaky test; see http://golang.org/issue/5780")
 	switch runtime.GOOS {
 	case "darwin":
-		// TODO(cnicolaou): https://golang.org/issue/2603
+		// TODO(cnicolaou): http://golang.org/issue/2603
 		// leads to leaked file descriptors in this test when it's
 		// run from a builder.
 		closeUnexpectedFds(t, "TestExtraFilesFDShuffle")
 	case "netbsd":
-		// https://golang.org/issue/3955
+		// http://golang.org/issue/3955
 		closeUnexpectedFds(t, "TestExtraFilesFDShuffle")
 	case "windows":
 		t.Skip("no operating system support; skipping")
@@ -422,9 +375,8 @@ func TestExtraFilesFDShuffle(t *testing.T) {
 }
 
 func TestExtraFiles(t *testing.T) {
-	testenv.MustHaveExec(t)
-
-	if runtime.GOOS == "windows" {
+	switch runtime.GOOS {
+	case "nacl", "windows":
 		t.Skipf("skipping test on %q", runtime.GOOS)
 	}
 
@@ -652,21 +604,21 @@ func TestHelperProcess(*testing.T) {
 			// file descriptors...
 		case "darwin":
 			// TODO(bradfitz): broken? Sometimes.
-			// https://golang.org/issue/2603
+			// http://golang.org/issue/2603
 			// Skip this additional part of the test for now.
 		case "netbsd":
 			// TODO(jsing): This currently fails on NetBSD due to
 			// the cloned file descriptors that result from opening
 			// /dev/urandom.
-			// https://golang.org/issue/3955
+			// http://golang.org/issue/3955
 		case "plan9":
 			// TODO(0intro): Determine why Plan 9 is leaking
 			// file descriptors.
-			// https://golang.org/issue/7118
+			// 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: https://golang.org/issue/2603
+			// see: http://golang.org/issue/2603
 		default:
 			// Now verify that there are no other open fds.
 			var files []*os.File
@@ -765,54 +717,3 @@ func TestHelperProcess(*testing.T) {
 		os.Exit(2)
 	}
 }
-
-// Issue 9173: ignore stdin pipe writes if the program completes successfully.
-func TestIgnorePipeErrorOnSuccess(t *testing.T) {
-	testenv.MustHaveExec(t)
-
-	// We really only care about testing this on Unixy things.
-	if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
-		t.Skipf("skipping test on %q", runtime.GOOS)
-	}
-
-	cmd := helperCommand(t, "echo", "foo")
-	var out bytes.Buffer
-	cmd.Stdin = strings.NewReader(strings.Repeat("x", 10<<20))
-	cmd.Stdout = &out
-	if err := cmd.Run(); err != nil {
-		t.Fatal(err)
-	}
-	if got, want := out.String(), "foo\n"; got != want {
-		t.Errorf("output = %q; want %q", got, want)
-	}
-}
-
-type badWriter struct{}
-
-func (w *badWriter) Write(data []byte) (int, error) {
-	return 0, io.ErrUnexpectedEOF
-}
-
-func TestClosePipeOnCopyError(t *testing.T) {
-	testenv.MustHaveExec(t)
-
-	if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
-		t.Skipf("skipping test on %s - no yes command", runtime.GOOS)
-	}
-	cmd := exec.Command("yes")
-	cmd.Stdout = new(badWriter)
-	c := make(chan int, 1)
-	go func() {
-		err := cmd.Run()
-		if err == nil {
-			t.Errorf("yes completed successfully")
-		}
-		c <- 1
-	}()
-	select {
-	case <-c:
-		// ok
-	case <-time.After(5 * time.Second):
-		t.Fatalf("yes got stuck writing to bad writer")
-	}
-}
diff --git a/src/os/exec/lp_windows_test.go b/src/os/exec/lp_windows_test.go
index 8e1d423..72df03e 100644
--- a/src/os/exec/lp_windows_test.go
+++ b/src/os/exec/lp_windows_test.go
@@ -422,7 +422,7 @@ var commandTests = []commandTest{
 	},
 	// tests commands, like `a.exe`, with c.Dir set
 	{
-		// should not find a.exe in p, because LookPath(`a.exe`) will fail
+		// should not find a.exe in p, becasue LookPath(`a.exe`) will fail
 		files: []string{`p\a.exe`},
 		dir:   `p`,
 		arg0:  `a.exe`,
diff --git a/src/os/exec_posix.go b/src/os/exec_posix.go
index 94dd04b..fb9d291 100644
--- a/src/os/exec_posix.go
+++ b/src/os/exec_posix.go
@@ -81,6 +81,33 @@ func (p *ProcessState) sysUsage() interface{} {
 	return p.rusage
 }
 
+// Convert i to decimal string.
+func itod(i int) string {
+	if i == 0 {
+		return "0"
+	}
+
+	u := uint64(i)
+	if i < 0 {
+		u = -u
+	}
+
+	// Assemble decimal in reverse order.
+	var b [32]byte
+	bp := len(b)
+	for ; u > 0; u /= 10 {
+		bp--
+		b[bp] = byte(u%10) + '0'
+	}
+
+	if i < 0 {
+		bp--
+		b[bp] = '-'
+	}
+
+	return string(b[bp:])
+}
+
 func (p *ProcessState) String() string {
 	if p == nil {
 		return "<nil>"
@@ -89,13 +116,13 @@ func (p *ProcessState) String() string {
 	res := ""
 	switch {
 	case status.Exited():
-		res = "exit status " + itoa(status.ExitStatus())
+		res = "exit status " + itod(status.ExitStatus())
 	case status.Signaled():
 		res = "signal: " + status.Signal().String()
 	case status.Stopped():
 		res = "stop signal: " + status.StopSignal().String()
 		if status.StopSignal() == syscall.SIGTRAP && status.TrapCause() != 0 {
-			res += " (trap " + itoa(status.TrapCause()) + ")"
+			res += " (trap " + itod(status.TrapCause()) + ")"
 		}
 	case status.Continued():
 		res = "continued"
diff --git a/src/os/exec_windows.go b/src/os/exec_windows.go
index 3264271..393393b 100644
--- a/src/os/exec_windows.go
+++ b/src/os/exec_windows.go
@@ -7,15 +7,13 @@ package os
 import (
 	"errors"
 	"runtime"
-	"sync/atomic"
 	"syscall"
 	"time"
 	"unsafe"
 )
 
 func (p *Process) wait() (ps *ProcessState, err error) {
-	handle := atomic.LoadUintptr(&p.handle)
-	s, e := syscall.WaitForSingleObject(syscall.Handle(handle), syscall.INFINITE)
+	s, e := syscall.WaitForSingleObject(syscall.Handle(p.handle), syscall.INFINITE)
 	switch s {
 	case syscall.WAIT_OBJECT_0:
 		break
@@ -25,12 +23,12 @@ func (p *Process) wait() (ps *ProcessState, err error) {
 		return nil, errors.New("os: unexpected result from WaitForSingleObject")
 	}
 	var ec uint32
-	e = syscall.GetExitCodeProcess(syscall.Handle(handle), &ec)
+	e = syscall.GetExitCodeProcess(syscall.Handle(p.handle), &ec)
 	if e != nil {
 		return nil, NewSyscallError("GetExitCodeProcess", e)
 	}
 	var u syscall.Rusage
-	e = syscall.GetProcessTimes(syscall.Handle(handle), &u.CreationTime, &u.ExitTime, &u.KernelTime, &u.UserTime)
+	e = syscall.GetProcessTimes(syscall.Handle(p.handle), &u.CreationTime, &u.ExitTime, &u.KernelTime, &u.UserTime)
 	if e != nil {
 		return nil, NewSyscallError("GetProcessTimes", e)
 	}
@@ -55,8 +53,7 @@ func terminateProcess(pid, exitcode int) error {
 }
 
 func (p *Process) signal(sig Signal) error {
-	handle := atomic.LoadUintptr(&p.handle)
-	if handle == uintptr(syscall.InvalidHandle) {
+	if p.handle == uintptr(syscall.InvalidHandle) {
 		return syscall.EINVAL
 	}
 	if p.done() {
@@ -70,15 +67,14 @@ func (p *Process) signal(sig Signal) error {
 }
 
 func (p *Process) release() error {
-	handle := atomic.LoadUintptr(&p.handle)
-	if handle == uintptr(syscall.InvalidHandle) {
+	if p.handle == uintptr(syscall.InvalidHandle) {
 		return syscall.EINVAL
 	}
-	e := syscall.CloseHandle(syscall.Handle(handle))
+	e := syscall.CloseHandle(syscall.Handle(p.handle))
 	if e != nil {
 		return NewSyscallError("CloseHandle", e)
 	}
-	atomic.StoreUintptr(&p.handle, uintptr(syscall.InvalidHandle))
+	p.handle = uintptr(syscall.InvalidHandle)
 	// no need for a finalizer anymore
 	runtime.SetFinalizer(p, nil)
 	return nil
diff --git a/src/os/file.go b/src/os/file.go
index 8c0e3ff..e12428c 100644
--- a/src/os/file.go
+++ b/src/os/file.go
@@ -192,7 +192,7 @@ func (f *File) Seek(offset int64, whence int) (ret int64, err error) {
 
 // WriteString is like Write, but writes the contents of string s rather than
 // a slice of bytes.
-func (f *File) WriteString(s string) (n int, err error) {
+func (f *File) WriteString(s string) (ret int, err error) {
 	if f == nil {
 		return 0, ErrInvalid
 	}
@@ -203,16 +203,9 @@ func (f *File) WriteString(s string) (n int, err error) {
 // If there is an error, it will be of type *PathError.
 func Mkdir(name string, perm FileMode) error {
 	e := syscall.Mkdir(name, syscallMode(perm))
-
 	if e != nil {
 		return &PathError{"mkdir", name, e}
 	}
-
-	// mkdir(2) itself won't handle the sticky bit on *BSD and Solaris
-	if !supportsCreateWithStickyBit && perm&ModeSticky != 0 {
-		Chmod(name, perm)
-	}
-
 	return nil
 }
 
@@ -242,16 +235,16 @@ func (f *File) Chdir() error {
 // the returned file can be used for reading; the associated file
 // descriptor has mode O_RDONLY.
 // If there is an error, it will be of type *PathError.
-func Open(name string) (*File, error) {
+func Open(name string) (file *File, err error) {
 	return OpenFile(name, O_RDONLY, 0)
 }
 
-// Create creates the named file with mode 0666 (before umask), truncating
-// it if it already exists. If successful, methods on the returned
+// Create creates the named file mode 0666 (before umask), truncating
+// it if it already exists.  If successful, methods on the returned
 // File can be used for I/O; the associated file descriptor has mode
 // O_RDWR.
 // If there is an error, it will be of type *PathError.
-func Create(name string) (*File, error) {
+func Create(name string) (file *File, err error) {
 	return OpenFile(name, O_RDWR|O_CREATE|O_TRUNC, 0666)
 }
 
@@ -259,7 +252,6 @@ func Create(name string) (*File, error) {
 var lstat = Lstat
 
 // Rename renames (moves) a file. OS-specific restrictions might apply.
-// If there is an error, it will be of type *LinkError.
 func Rename(oldpath, newpath string) error {
 	return rename(oldpath, newpath)
 }
diff --git a/src/os/file_plan9.go b/src/os/file_plan9.go
index 085ebc4..132594e 100644
--- a/src/os/file_plan9.go
+++ b/src/os/file_plan9.go
@@ -79,7 +79,7 @@ func syscallMode(i FileMode) (o uint32) {
 // (O_RDONLY etc.) and perm, (0666 etc.) if applicable.  If successful,
 // methods on the returned File can be used for I/O.
 // If there is an error, it will be of type *PathError.
-func OpenFile(name string, flag int, perm FileMode) (*File, error) {
+func OpenFile(name string, flag int, perm FileMode) (file *File, err error) {
 	var (
 		fd     int
 		e      error
@@ -159,7 +159,7 @@ func (file *file) close() error {
 
 // Stat returns the FileInfo structure describing file.
 // If there is an error, it will be of type *PathError.
-func (f *File) Stat() (FileInfo, error) {
+func (f *File) Stat() (fi FileInfo, err error) {
 	if f == nil {
 		return nil, ErrInvalid
 	}
@@ -224,7 +224,7 @@ func (f *File) Chmod(mode FileMode) error {
 // Sync commits the current contents of the file to stable storage.
 // Typically, this means flushing the file system's in-memory copy
 // of recently written data to disk.
-func (f *File) Sync() error {
+func (f *File) Sync() (err error) {
 	if f == nil {
 		return ErrInvalid
 	}
@@ -319,7 +319,7 @@ func hasPrefix(s, prefix string) bool {
 	return len(s) >= len(prefix) && s[0:len(prefix)] == prefix
 }
 
-// LastIndexByte from the strings package.
+// 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 {
diff --git a/src/os/file_posix.go b/src/os/file_posix.go
index 6d8076f..fbb3b5e 100644
--- a/src/os/file_posix.go
+++ b/src/os/file_posix.go
@@ -28,6 +28,14 @@ func Readlink(name string) (string, error) {
 	}
 }
 
+func rename(oldname, newname string) error {
+	e := syscall.Rename(oldname, newname)
+	if e != nil {
+		return &LinkError{"rename", oldname, newname, e}
+	}
+	return nil
+}
+
 // syscallMode returns the syscall-specific mode bits from Go's portable mode bits.
 func syscallMode(i FileMode) (o uint32) {
 	o |= uint32(i.Perm())
@@ -114,7 +122,7 @@ func (f *File) Truncate(size int64) error {
 // Sync commits the current contents of the file to stable storage.
 // Typically, this means flushing the file system's in-memory copy
 // of recently written data to disk.
-func (f *File) Sync() error {
+func (f *File) Sync() (err error) {
 	if f == nil {
 		return ErrInvalid
 	}
diff --git a/src/os/file_unix.go b/src/os/file_unix.go
index 0677707..ff4fc7d 100644
--- a/src/os/file_unix.go
+++ b/src/os/file_unix.go
@@ -12,14 +12,6 @@ import (
 	"syscall"
 )
 
-func rename(oldname, newname string) error {
-	e := syscall.Rename(oldname, newname)
-	if e != nil {
-		return &LinkError{"rename", oldname, newname, e}
-	}
-	return nil
-}
-
 // File represents an open file descriptor.
 type File struct {
 	*file
@@ -82,24 +74,12 @@ const DevNull = "/dev/null"
 // (O_RDONLY etc.) and perm, (0666 etc.) if applicable.  If successful,
 // methods on the returned File can be used for I/O.
 // If there is an error, it will be of type *PathError.
-func OpenFile(name string, flag int, perm FileMode) (*File, error) {
-	chmod := false
-	if !supportsCreateWithStickyBit && flag&O_CREATE != 0 && perm&ModeSticky != 0 {
-		if _, err := Stat(name); IsNotExist(err) {
-			chmod = true
-		}
-	}
-
+func OpenFile(name string, flag int, perm FileMode) (file *File, err error) {
 	r, e := syscall.Open(name, flag|syscall.O_CLOEXEC, syscallMode(perm))
 	if e != nil {
 		return nil, &PathError{"open", name, e}
 	}
 
-	// open(2) itself won't handle the sticky bit on *BSD and Solaris
-	if chmod {
-		Chmod(name, perm)
-	}
-
 	// There's a race here with fork/exec, which we are
 	// content to live with.  See ../syscall/exec_unix.go.
 	if !supportsCloseOnExec {
@@ -135,12 +115,12 @@ func (file *file) close() error {
 
 // Stat returns the FileInfo structure describing file.
 // If there is an error, it will be of type *PathError.
-func (f *File) Stat() (FileInfo, error) {
+func (f *File) Stat() (fi FileInfo, err error) {
 	if f == nil {
 		return nil, ErrInvalid
 	}
 	var stat syscall.Stat_t
-	err := syscall.Fstat(f.fd, &stat)
+	err = syscall.Fstat(f.fd, &stat)
 	if err != nil {
 		return nil, &PathError{"stat", f.name, err}
 	}
@@ -149,9 +129,9 @@ func (f *File) Stat() (FileInfo, error) {
 
 // Stat returns a FileInfo describing the named file.
 // If there is an error, it will be of type *PathError.
-func Stat(name string) (FileInfo, error) {
+func Stat(name string) (fi FileInfo, err error) {
 	var stat syscall.Stat_t
-	err := syscall.Stat(name, &stat)
+	err = syscall.Stat(name, &stat)
 	if err != nil {
 		return nil, &PathError{"stat", name, err}
 	}
@@ -162,9 +142,9 @@ func Stat(name string) (FileInfo, error) {
 // If the file is a symbolic link, the returned FileInfo
 // describes the symbolic link.  Lstat makes no attempt to follow the link.
 // If there is an error, it will be of type *PathError.
-func Lstat(name string) (FileInfo, error) {
+func Lstat(name string) (fi FileInfo, err error) {
 	var stat syscall.Stat_t
-	err := syscall.Lstat(name, &stat)
+	err = syscall.Lstat(name, &stat)
 	if err != nil {
 		return nil, &PathError{"lstat", name, err}
 	}
diff --git a/src/os/file_windows.go b/src/os/file_windows.go
index 89b1d27..2a90a50 100644
--- a/src/os/file_windows.go
+++ b/src/os/file_windows.go
@@ -5,7 +5,6 @@
 package os
 
 import (
-	"internal/syscall/windows"
 	"io"
 	"runtime"
 	"sync"
@@ -134,7 +133,7 @@ func openDir(name string) (file *File, err error) {
 // (O_RDONLY etc.) and perm, (0666 etc.) if applicable.  If successful,
 // methods on the returned File can be used for I/O.
 // If there is an error, it will be of type *PathError.
-func OpenFile(name string, flag int, perm FileMode) (*File, error) {
+func OpenFile(name string, flag int, perm FileMode) (file *File, err error) {
 	if name == "" {
 		return nil, &PathError{"open", name, syscall.ENOENT}
 	}
@@ -461,14 +460,6 @@ func Remove(name string) error {
 	return &PathError{"remove", name, e}
 }
 
-func rename(oldname, newname string) error {
-	e := windows.Rename(oldname, newname)
-	if e != nil {
-		return &LinkError{"rename", oldname, newname, e}
-	}
-	return nil
-}
-
 // Pipe returns a connected pair of Files; reads from r return bytes written to w.
 // It returns the files and an error, if any.
 func Pipe() (r *File, w *File, err error) {
@@ -490,18 +481,20 @@ func Pipe() (r *File, w *File, err error) {
 
 // TempDir returns the default directory to use for temporary files.
 func TempDir() string {
-	n := uint32(syscall.MAX_PATH)
-	for {
-		b := make([]uint16, n)
-		n, _ = syscall.GetTempPath(uint32(len(b)), &b[0])
-		if n > uint32(len(b)) {
-			continue
+	const pathSep = '\\'
+	dirw := make([]uint16, syscall.MAX_PATH)
+	n, _ := syscall.GetTempPath(uint32(len(dirw)), &dirw[0])
+	if n > uint32(len(dirw)) {
+		dirw = make([]uint16, n)
+		n, _ = syscall.GetTempPath(uint32(len(dirw)), &dirw[0])
+		if n > uint32(len(dirw)) {
+			n = 0
 		}
-		if n > 0 && b[n-1] == '\\' {
-			n--
-		}
-		return string(utf16.Decode(b[:n]))
 	}
+	if n > 0 && dirw[n-1] == pathSep {
+		n--
+	}
+	return string(utf16.Decode(dirw[0:n]))
 }
 
 // Link creates newname as a hard link to the oldname file.
@@ -515,8 +508,9 @@ func Link(oldname, newname string) error {
 	if err != nil {
 		return &LinkError{"link", oldname, newname, err}
 	}
-	err = syscall.CreateHardLink(n, o, 0)
-	if err != nil {
+
+	e := syscall.CreateHardLink(n, o, 0)
+	if e != nil {
 		return &LinkError{"link", oldname, newname, err}
 	}
 	return nil
diff --git a/src/os/os_test.go b/src/os/os_test.go
index 6b72674..a30a2b0 100644
--- a/src/os/os_test.go
+++ b/src/os/os_test.go
@@ -9,7 +9,6 @@ import (
 	"errors"
 	"flag"
 	"fmt"
-	"internal/testenv"
 	"io"
 	"io/ioutil"
 	. "os"
@@ -22,6 +21,7 @@ import (
 	"sync"
 	"syscall"
 	"testing"
+	"text/template"
 	"time"
 )
 
@@ -43,33 +43,18 @@ type sysDir struct {
 	files []string
 }
 
-var sysdir = func() *sysDir {
+var sysdir = func() (sd *sysDir) {
 	switch runtime.GOOS {
 	case "android":
-		return &sysDir{
+		sd = &sysDir{
 			"/system/etc",
 			[]string{
 				"audio_policy.conf",
 				"system_fonts.xml",
 			},
 		}
-	case "darwin":
-		switch runtime.GOARCH {
-		case "arm", "arm64":
-			wd, err := syscall.Getwd()
-			if err != nil {
-				wd = err.Error()
-			}
-			return &sysDir{
-				filepath.Join(wd, "..", ".."),
-				[]string{
-					"ResourceRules.plist",
-					"Info.plist",
-				},
-			}
-		}
 	case "windows":
-		return &sysDir{
+		sd = &sysDir{
 			Getenv("SystemRoot") + "\\system32\\drivers\\etc",
 			[]string{
 				"networks",
@@ -78,22 +63,24 @@ var sysdir = func() *sysDir {
 			},
 		}
 	case "plan9":
-		return &sysDir{
+		sd = &sysDir{
 			"/lib/ndb",
 			[]string{
 				"common",
 				"local",
 			},
 		}
+	default:
+		sd = &sysDir{
+			"/etc",
+			[]string{
+				"group",
+				"hosts",
+				"passwd",
+			},
+		}
 	}
-	return &sysDir{
-		"/etc",
-		[]string{
-			"group",
-			"hosts",
-			"passwd",
-		},
-	}
+	return
 }()
 
 func size(name string, t *testing.T) int64 {
@@ -127,22 +114,15 @@ func equal(name1, name2 string) (r bool) {
 	return
 }
 
-// localTmp returns a local temporary directory not on NFS.
-func localTmp() string {
-	switch runtime.GOOS {
-	case "android", "windows":
-		return TempDir()
-	case "darwin":
-		switch runtime.GOARCH {
-		case "arm", "arm64":
-			return TempDir()
-		}
-	}
-	return "/tmp"
-}
-
 func newFile(testName string, t *testing.T) (f *File) {
-	f, err := ioutil.TempFile(localTmp(), "_Go_"+testName)
+	// Use a local file system, not NFS.
+	// On Unix, override $TMPDIR in case the user
+	// has it set to an NFS-mounted directory.
+	dir := ""
+	if runtime.GOOS != "android" && runtime.GOOS != "windows" {
+		dir = "/tmp"
+	}
+	f, err := ioutil.TempFile(dir, "_Go_"+testName)
 	if err != nil {
 		t.Fatalf("TempFile %s: %s", testName, err)
 	}
@@ -150,7 +130,14 @@ func newFile(testName string, t *testing.T) (f *File) {
 }
 
 func newDir(testName string, t *testing.T) (name string) {
-	name, err := ioutil.TempDir(localTmp(), "_Go_"+testName)
+	// Use a local file system, not NFS.
+	// On Unix, override $TMPDIR in case the user
+	// has it set to an NFS-mounted directory.
+	dir := ""
+	if runtime.GOOS != "android" && runtime.GOOS != "windows" {
+		dir = "/tmp"
+	}
+	name, err := ioutil.TempDir(dir, "_Go_"+testName)
 	if err != nil {
 		t.Fatalf("TempDir %s: %s", testName, err)
 	}
@@ -325,15 +312,6 @@ func TestReaddirnamesOneAtATime(t *testing.T) {
 	switch runtime.GOOS {
 	case "android":
 		dir = "/system/bin"
-	case "darwin":
-		switch runtime.GOARCH {
-		case "arm", "arm64":
-			wd, err := Getwd()
-			if err != nil {
-				t.Fatal(err)
-			}
-			dir = wd
-		}
 	case "plan9":
 		dir = "/bin"
 	case "windows":
@@ -513,35 +491,11 @@ func TestReaddirStatFailures(t *testing.T) {
 	}
 }
 
-// Readdir on a regular file should fail.
-func TestReaddirOfFile(t *testing.T) {
-	f, err := ioutil.TempFile("", "_Go_ReaddirOfFile")
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer Remove(f.Name())
-	f.Write([]byte("foo"))
-	f.Close()
-	reg, err := Open(f.Name())
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer reg.Close()
-
-	names, err := reg.Readdirnames(-1)
-	if err == nil {
-		t.Error("Readdirnames succeeded; want non-nil error")
-	}
-	if len(names) > 0 {
-		t.Errorf("unexpected dir names in regular file: %q", names)
-	}
-}
-
 func TestHardLink(t *testing.T) {
+	// Hardlinks are not supported under windows or Plan 9.
 	if runtime.GOOS == "plan9" {
-		t.Skip("skipping on plan9, hardlinks not supported")
+		return
 	}
-	defer chtmpdir(t)()
 	from, to := "hardlinktestfrom", "hardlinktestto"
 	Remove(from) // Just in case.
 	file, err := Create(to)
@@ -556,14 +510,6 @@ func TestHardLink(t *testing.T) {
 	if err != nil {
 		t.Fatalf("link %q, %q failed: %v", to, from, err)
 	}
-
-	none := "hardlinktestnone"
-	err = Link(none, none)
-	// Check the returned error is well-formed.
-	if lerr, ok := err.(*LinkError); !ok || lerr.Error() == "" {
-		t.Errorf("link %q, %q failed to return a valid error", none, none)
-	}
-
 	defer Remove(from)
 	tostat, err := Stat(to)
 	if err != nil {
@@ -578,31 +524,6 @@ func TestHardLink(t *testing.T) {
 	}
 }
 
-// chtmpdir changes the working directory to a new temporary directory and
-// provides a cleanup function. Used when PWD is read-only.
-func chtmpdir(t *testing.T) func() {
-	if runtime.GOOS != "darwin" || (runtime.GOARCH != "arm" && runtime.GOARCH != "arm64") {
-		return func() {} // only needed on darwin/arm{,64}
-	}
-	oldwd, err := Getwd()
-	if err != nil {
-		t.Fatalf("chtmpdir: %v", err)
-	}
-	d, err := ioutil.TempDir("", "test")
-	if err != nil {
-		t.Fatalf("chtmpdir: %v", err)
-	}
-	if err := Chdir(d); err != nil {
-		t.Fatalf("chtmpdir: %v", err)
-	}
-	return func() {
-		if err := Chdir(oldwd); err != nil {
-			t.Fatalf("chtmpdir: %v", err)
-		}
-		RemoveAll(d)
-	}
-}
-
 func TestSymlink(t *testing.T) {
 	switch runtime.GOOS {
 	case "android", "nacl", "plan9":
@@ -612,7 +533,6 @@ func TestSymlink(t *testing.T) {
 			t.Skipf("skipping on %s", runtime.GOOS)
 		}
 	}
-	defer chtmpdir(t)()
 	from, to := "symlinktestfrom", "symlinktestto"
 	Remove(from) // Just in case.
 	file, err := Create(to)
@@ -679,7 +599,6 @@ func TestLongSymlink(t *testing.T) {
 			t.Skipf("skipping on %s", runtime.GOOS)
 		}
 	}
-	defer chtmpdir(t)()
 	s := "0123456789abcdef"
 	// Long, but not too long: a common limit is 255.
 	s = s + s + s + s + s + s + s + s + s + s + s + s + s + s + s
@@ -700,18 +619,14 @@ func TestLongSymlink(t *testing.T) {
 }
 
 func TestRename(t *testing.T) {
-	defer chtmpdir(t)()
 	from, to := "renamefrom", "renameto"
-	// Ensure we are not testing the overwrite case here.
-	Remove(from)
-	Remove(to)
-
+	Remove(to) // Just in case.
 	file, err := Create(from)
 	if err != nil {
-		t.Fatalf("open %q failed: %v", from, err)
+		t.Fatalf("open %q failed: %v", to, err)
 	}
 	if err = file.Close(); err != nil {
-		t.Errorf("close %q failed: %v", from, err)
+		t.Errorf("close %q failed: %v", to, err)
 	}
 	err = Rename(from, to)
 	if err != nil {
@@ -724,79 +639,6 @@ func TestRename(t *testing.T) {
 	}
 }
 
-func TestRenameOverwriteDest(t *testing.T) {
-	if runtime.GOOS == "plan9" {
-		t.Skip("skipping on plan9")
-	}
-	defer chtmpdir(t)()
-	from, to := "renamefrom", "renameto"
-	// Just in case.
-	Remove(from)
-	Remove(to)
-
-	toData := []byte("to")
-	fromData := []byte("from")
-
-	err := ioutil.WriteFile(to, toData, 0777)
-	if err != nil {
-		t.Fatalf("write file %q failed: %v", to, err)
-	}
-
-	err = ioutil.WriteFile(from, fromData, 0777)
-	if err != nil {
-		t.Fatalf("write file %q failed: %v", from, err)
-	}
-	err = Rename(from, to)
-	if err != nil {
-		t.Fatalf("rename %q, %q failed: %v", to, from, err)
-	}
-	defer Remove(to)
-
-	_, err = Stat(from)
-	if err == nil {
-		t.Errorf("from file %q still exists", from)
-	}
-	if err != nil && !IsNotExist(err) {
-		t.Fatalf("stat from: %v", err)
-	}
-	toFi, err := Stat(to)
-	if err != nil {
-		t.Fatalf("stat %q failed: %v", to, err)
-	}
-	if toFi.Size() != int64(len(fromData)) {
-		t.Errorf(`"to" size = %d; want %d (old "from" size)`, toFi.Size(), len(fromData))
-	}
-}
-
-func TestRenameFailed(t *testing.T) {
-	defer chtmpdir(t)()
-	from, to := "renamefrom", "renameto"
-	// Ensure we are not testing the overwrite case here.
-	Remove(from)
-	Remove(to)
-
-	err := Rename(from, to)
-	switch err := err.(type) {
-	case *LinkError:
-		if err.Op != "rename" {
-			t.Errorf("rename %q, %q: err.Op: want %q, got %q", from, to, "rename", err.Op)
-		}
-		if err.Old != from {
-			t.Errorf("rename %q, %q: err.Old: want %q, got %q", from, to, from, err.Old)
-		}
-		if err.New != to {
-			t.Errorf("rename %q, %q: err.New: want %q, got %q", from, to, to, err.New)
-		}
-	case nil:
-		t.Errorf("rename %q, %q: expected error, got nil", from, to)
-
-		// cleanup whatever was placed in "renameto"
-		Remove(to)
-	default:
-		t.Errorf("rename %q, %q: expected %T, got %T %v", from, to, new(LinkError), err, err)
-	}
-}
-
 func exec(t *testing.T, dir, cmd string, args []string, expect string) {
 	r, w, err := Pipe()
 	if err != nil {
@@ -824,18 +666,18 @@ func exec(t *testing.T, dir, cmd string, args []string, expect string) {
 }
 
 func TestStartProcess(t *testing.T) {
-	testenv.MustHaveExec(t)
+	switch runtime.GOOS {
+	case "android", "nacl":
+		t.Skipf("skipping on %s", runtime.GOOS)
+	}
 
 	var dir, cmd string
 	var args []string
-	switch runtime.GOOS {
-	case "android":
-		t.Skip("android doesn't have /bin/pwd")
-	case "windows":
+	if runtime.GOOS == "windows" {
 		cmd = Getenv("COMSPEC")
 		dir = Getenv("SystemRoot")
 		args = []string{"/c", "cd"}
-	default:
+	} else {
 		cmd = "/bin/pwd"
 		dir = "/"
 		args = []string{}
@@ -1007,19 +849,6 @@ func TestChdirAndGetwd(t *testing.T) {
 		dirs = []string{"/", "/system/bin"}
 	case "plan9":
 		dirs = []string{"/", "/usr"}
-	case "darwin":
-		switch runtime.GOARCH {
-		case "arm", "arm64":
-			d1, err := ioutil.TempDir("", "d1")
-			if err != nil {
-				t.Fatalf("TempDir: %v", err)
-			}
-			d2, err := ioutil.TempDir("", "d2")
-			if err != nil {
-				t.Fatalf("TempDir: %v", err)
-			}
-			dirs = []string{d1, d2}
-		}
 	}
 	oldwd := Getenv("PWD")
 	for mode := 0; mode < 2; mode++ {
@@ -1065,64 +894,6 @@ func TestChdirAndGetwd(t *testing.T) {
 	fd.Close()
 }
 
-// Test that Chdir+Getwd is program-wide.
-func TestProgWideChdir(t *testing.T) {
-	const N = 10
-	c := make(chan bool)
-	cpwd := make(chan string)
-	for i := 0; i < N; i++ {
-		go func(i int) {
-			// Lock half the goroutines in their own operating system
-			// thread to exercise more scheduler possibilities.
-			if i%2 == 1 {
-				// On Plan 9, after calling LockOSThread, the goroutines
-				// run on different processes which don't share the working
-				// directory. This used to be an issue because Go expects
-				// the working directory to be program-wide.
-				// See issue 9428.
-				runtime.LockOSThread()
-			}
-			<-c
-			pwd, err := Getwd()
-			if err != nil {
-				t.Errorf("Getwd on goroutine %d: %v", i, err)
-				return
-			}
-			cpwd <- pwd
-		}(i)
-	}
-	oldwd, err := Getwd()
-	if err != nil {
-		t.Fatalf("Getwd: %v", err)
-	}
-	d, err := ioutil.TempDir("", "test")
-	if err != nil {
-		t.Fatalf("TempDir: %v", err)
-	}
-	defer func() {
-		if err := Chdir(oldwd); err != nil {
-			t.Fatalf("Chdir: %v", err)
-		}
-		RemoveAll(d)
-	}()
-	if err := Chdir(d); err != nil {
-		t.Fatalf("Chdir: %v", err)
-	}
-	// OS X sets TMPDIR to a symbolic link.
-	// So we resolve our working directory again before the test.
-	d, err = Getwd()
-	if err != nil {
-		t.Fatalf("Getwd: %v", err)
-	}
-	close(c)
-	for i := 0; i < N; i++ {
-		pwd := <-cpwd
-		if pwd != d {
-			t.Errorf("Getwd returned %q; want %q", pwd, d)
-		}
-	}
-}
-
 func TestSeek(t *testing.T) {
 	f := newFile("TestSeek", t)
 	defer Remove(f.Name())
@@ -1151,7 +922,7 @@ func TestSeek(t *testing.T) {
 		if off != tt.out || err != nil {
 			if e, ok := err.(*PathError); ok && e.Err == syscall.EINVAL && tt.out > 1<<32 {
 				// Reiserfs rejects the big seeks.
-				// https://golang.org/issue/91
+				// http://code.google.com/p/go/issues/detail?id=91
 				break
 			}
 			t.Errorf("#%d: Seek(%v, %v) = %v, %v want %v, nil", i, tt.in, tt.whence, off, err, tt.out)
@@ -1264,35 +1035,14 @@ func run(t *testing.T, cmd []string) string {
 	return output
 }
 
-func testWindowsHostname(t *testing.T) {
-	hostname, err := Hostname()
-	if err != nil {
-		t.Fatal(err)
-	}
-	cmd := osexec.Command("hostname")
-	out, err := cmd.CombinedOutput()
-	if err != nil {
-		t.Fatalf("Failed to execute hostname command: %v %s", err, out)
-	}
-	want := strings.Trim(string(out), "\r\n")
-	if hostname != want {
-		t.Fatalf("Hostname() = %q, want %q", hostname, want)
-	}
-}
-
 func TestHostname(t *testing.T) {
 	// There is no other way to fetch hostname on windows, but via winapi.
 	// On Plan 9 it can be taken from #c/sysname as Hostname() does.
 	switch runtime.GOOS {
-	case "android", "plan9":
-		t.Skipf("%s doesn't have /bin/hostname", runtime.GOOS)
-	case "windows":
-		testWindowsHostname(t)
-		return
+	case "android", "nacl", "plan9", "windows":
+		t.Skipf("skipping on %s", runtime.GOOS)
 	}
 
-	testenv.MustHaveExec(t)
-
 	// Check internal Hostname() against the output of /bin/hostname.
 	// Allow that the internal Hostname returns a Fully Qualified Domain Name
 	// and the /bin/hostname only returns the first component
@@ -1367,7 +1117,6 @@ func writeFile(t *testing.T, fname string, flag int, text string) string {
 }
 
 func TestAppend(t *testing.T) {
-	defer chtmpdir(t)()
 	const f = "append.txt"
 	defer Remove(f)
 	s := writeFile(t, f, O_CREATE|O_TRUNC|O_RDWR, "new")
@@ -1431,7 +1180,6 @@ func TestNilProcessStateString(t *testing.T) {
 }
 
 func TestSameFile(t *testing.T) {
-	defer chtmpdir(t)()
 	fa, err := Create("a")
 	if err != nil {
 		t.Fatalf("Create(a): %v", err)
@@ -1551,11 +1299,44 @@ func TestReadAtEOF(t *testing.T) {
 }
 
 func testKillProcess(t *testing.T, processKiller func(p *Process)) {
-	testenv.MustHaveExec(t)
+	switch runtime.GOOS {
+	case "android", "nacl":
+		t.Skipf("skipping on %s", runtime.GOOS)
+	}
+
+	dir, err := ioutil.TempDir("", "go-build")
+	if err != nil {
+		t.Fatalf("Failed to create temp directory: %v", err)
+	}
+	defer RemoveAll(dir)
+
+	src := filepath.Join(dir, "main.go")
+	f, err := Create(src)
+	if err != nil {
+		t.Fatalf("Failed to create %v: %v", src, err)
+	}
+	st := template.Must(template.New("source").Parse(`
+package main
+import "time"
+func main() {
+	time.Sleep(time.Second)
+}
+`))
+	err = st.Execute(f, nil)
+	if err != nil {
+		f.Close()
+		t.Fatalf("Failed to execute template: %v", err)
+	}
+	f.Close()
+
+	exe := filepath.Join(dir, "main.exe")
+	output, err := osexec.Command("go", "build", "-o", exe, src).CombinedOutput()
+	if err != nil {
+		t.Fatalf("Failed to build exe %v: %v %v", exe, err, string(output))
+	}
 
-	// Re-exec the test binary itself to emulate "sleep 1".
-	cmd := osexec.Command(Args[0], "-test.run", "TestSleep")
-	err := cmd.Start()
+	cmd := osexec.Command(exe)
+	err = cmd.Start()
 	if err != nil {
 		t.Fatalf("Failed to start test process: %v", err)
 	}
@@ -1569,15 +1350,6 @@ func testKillProcess(t *testing.T, processKiller func(p *Process)) {
 	}
 }
 
-// TestSleep emulates "sleep 1". It is a helper for testKillProcess, so we
-// don't have to rely on an external "sleep" command being available.
-func TestSleep(t *testing.T) {
-	if testing.Short() {
-		t.Skip("Skipping in short mode")
-	}
-	time.Sleep(time.Second)
-}
-
 func TestKillStartProcess(t *testing.T) {
 	testKillProcess(t, func(p *Process) {
 		err := p.Kill()
@@ -1588,13 +1360,14 @@ func TestKillStartProcess(t *testing.T) {
 }
 
 func TestGetppid(t *testing.T) {
-	if runtime.GOOS == "plan9" {
+	switch runtime.GOOS {
+	case "nacl":
+		t.Skip("skipping on nacl")
+	case "plan9":
 		// TODO: golang.org/issue/8206
 		t.Skipf("skipping test on plan9; see issue 8206")
 	}
 
-	testenv.MustHaveExec(t)
-
 	if Getenv("GO_WANT_HELPER_PROCESS") == "1" {
 		fmt.Print(Getppid())
 		Exit(0)
diff --git a/src/os/os_unix_test.go b/src/os/os_unix_test.go
index 2adc3b5..21d40cc 100644
--- a/src/os/os_unix_test.go
+++ b/src/os/os_unix_test.go
@@ -13,10 +13,6 @@ import (
 	"testing"
 )
 
-func init() {
-	isReadonlyError = func(err error) bool { return err == syscall.EROFS }
-}
-
 func checkUidGid(t *testing.T, path string, uid, gid int) {
 	dir, err := Stat(path)
 	if err != nil {
@@ -32,10 +28,10 @@ func checkUidGid(t *testing.T, path string, uid, gid int) {
 }
 
 func TestChown(t *testing.T) {
-	// Chown is not supported under windows or Plan 9.
+	// Chown is not supported under windows os Plan 9.
 	// Plan9 provides a native ChownPlan9 version instead.
 	if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
-		t.Skipf("%s does not support syscall.Chown", runtime.GOOS)
+		return
 	}
 	// Use TempDir() to make sure we're on a local file system,
 	// so that the group ids returned by Getgroups will be allowed
@@ -78,109 +74,3 @@ func TestChown(t *testing.T) {
 		checkUidGid(t, f.Name(), int(sys.Uid), gid)
 	}
 }
-
-func TestFileChown(t *testing.T) {
-	// Fchown is not supported under windows or Plan 9.
-	if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
-		t.Skipf("%s does not support syscall.Fchown", runtime.GOOS)
-	}
-	// Use TempDir() to make sure we're on a local file system,
-	// so that the group ids returned by Getgroups will be allowed
-	// on the file.  On NFS, the Getgroups groups are
-	// basically useless.
-	f := newFile("TestFileChown", t)
-	defer Remove(f.Name())
-	defer f.Close()
-	dir, err := f.Stat()
-	if err != nil {
-		t.Fatalf("stat %s: %s", f.Name(), err)
-	}
-
-	// Can't change uid unless root, but can try
-	// changing the group id.  First try our current group.
-	gid := Getgid()
-	t.Log("gid:", gid)
-	if err = f.Chown(-1, gid); err != nil {
-		t.Fatalf("fchown %s -1 %d: %s", f.Name(), gid, err)
-	}
-	sys := dir.Sys().(*syscall.Stat_t)
-	checkUidGid(t, f.Name(), int(sys.Uid), gid)
-
-	// Then try all the auxiliary groups.
-	groups, err := Getgroups()
-	if err != nil {
-		t.Fatalf("getgroups: %s", err)
-	}
-	t.Log("groups: ", groups)
-	for _, g := range groups {
-		if err = f.Chown(-1, g); err != nil {
-			t.Fatalf("fchown %s -1 %d: %s", f.Name(), g, err)
-		}
-		checkUidGid(t, f.Name(), int(sys.Uid), g)
-
-		// change back to gid to test fd.Chown
-		if err = f.Chown(-1, gid); err != nil {
-			t.Fatalf("fchown %s -1 %d: %s", f.Name(), gid, err)
-		}
-		checkUidGid(t, f.Name(), int(sys.Uid), gid)
-	}
-}
-
-func TestLchown(t *testing.T) {
-	// Lchown is not supported under windows or Plan 9.
-	if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
-		t.Skipf("%s does not support syscall.Lchown", runtime.GOOS)
-	}
-	// Use TempDir() to make sure we're on a local file system,
-	// so that the group ids returned by Getgroups will be allowed
-	// on the file.  On NFS, the Getgroups groups are
-	// basically useless.
-	f := newFile("TestLchown", t)
-	defer Remove(f.Name())
-	defer f.Close()
-	dir, err := f.Stat()
-	if err != nil {
-		t.Fatalf("stat %s: %s", f.Name(), err)
-	}
-
-	linkname := f.Name() + "2"
-	if err := Link(f.Name(), linkname); err != nil {
-		t.Fatalf("link %s -> %s: %v", f.Name(), linkname, err)
-	}
-	defer Remove(linkname)
-
-	f2, err := Open(linkname)
-	if err != nil {
-		t.Fatalf("open %s: %v", linkname, err)
-	}
-	defer f2.Close()
-
-	// Can't change uid unless root, but can try
-	// changing the group id.  First try our current group.
-	gid := Getgid()
-	t.Log("gid:", gid)
-	if err = Lchown(linkname, -1, gid); err != nil {
-		t.Fatalf("lchown %s -1 %d: %s", linkname, gid, err)
-	}
-	sys := dir.Sys().(*syscall.Stat_t)
-	checkUidGid(t, linkname, int(sys.Uid), gid)
-
-	// Then try all the auxiliary groups.
-	groups, err := Getgroups()
-	if err != nil {
-		t.Fatalf("getgroups: %s", err)
-	}
-	t.Log("groups: ", groups)
-	for _, g := range groups {
-		if err = Lchown(linkname, -1, g); err != nil {
-			t.Fatalf("lchown %s -1 %d: %s", linkname, g, err)
-		}
-		checkUidGid(t, linkname, int(sys.Uid), g)
-
-		// change back to gid to test fd.Chown
-		if err = f2.Chown(-1, gid); err != nil {
-			t.Fatalf("fchown %s -1 %d: %s", linkname, gid, err)
-		}
-		checkUidGid(t, linkname, int(sys.Uid), gid)
-	}
-}
diff --git a/src/os/os_windows_test.go b/src/os/os_windows_test.go
index ee19b2b..fd96713 100644
--- a/src/os/os_windows_test.go
+++ b/src/os/os_windows_test.go
@@ -3,15 +3,11 @@ package os_test
 import (
 	"io/ioutil"
 	"os"
-	osexec "os/exec"
 	"path/filepath"
-	"strings"
 	"syscall"
 	"testing"
 )
 
-var supportJunctionLinks = true
-
 func init() {
 	tmpdir, err := ioutil.TempDir("", "symtest")
 	if err != nil {
@@ -20,18 +16,14 @@ func init() {
 	defer os.RemoveAll(tmpdir)
 
 	err = os.Symlink("target", filepath.Join(tmpdir, "symlink"))
-	if err != nil {
-		err = err.(*os.LinkError).Err
-		switch err {
-		case syscall.EWINDOWS, syscall.ERROR_PRIVILEGE_NOT_HELD:
-			supportsSymlinks = false
-		}
+	if err == nil {
+		return
 	}
-	defer os.Remove("target")
 
-	b, _ := osexec.Command("cmd", "/c", "mklink", "/?").Output()
-	if !strings.Contains(string(b), " /J ") {
-		supportJunctionLinks = false
+	err = err.(*os.LinkError).Err
+	switch err {
+	case syscall.EWINDOWS, syscall.ERROR_PRIVILEGE_NOT_HELD:
+		supportsSymlinks = false
 	}
 }
 
@@ -87,42 +79,3 @@ func TestSameWindowsFile(t *testing.T) {
 		t.Errorf("files should be same")
 	}
 }
-
-func TestStatJunctionLink(t *testing.T) {
-	if !supportJunctionLinks {
-		t.Skip("skipping because junction links are not supported")
-	}
-
-	dir, err := ioutil.TempDir("", "go-build")
-	if err != nil {
-		t.Fatalf("failed to create temp directory: %v", err)
-	}
-	defer os.RemoveAll(dir)
-
-	link := filepath.Join(filepath.Dir(dir), filepath.Base(dir)+"-link")
-
-	output, err := osexec.Command("cmd", "/c", "mklink", "/J", link, dir).CombinedOutput()
-	if err != nil {
-		t.Fatalf("failed to run mklink %v %v: %v %q", link, dir, err, output)
-	}
-	defer os.Remove(link)
-
-	fi, err := os.Stat(link)
-	if err != nil {
-		t.Fatalf("failed to stat link %v: %v", link, err)
-	}
-	expected := filepath.Base(dir)
-	got := fi.Name()
-	if !fi.IsDir() || expected != got {
-		t.Fatalf("link should point to %v but points to %v instead", expected, got)
-	}
-}
-
-func TestStartProcessAttr(t *testing.T) {
-	p, err := os.StartProcess(os.Getenv("COMSPEC"), []string{"/c", "cd"}, new(os.ProcAttr))
-	if err != nil {
-		return
-	}
-	defer p.Wait()
-	t.Fatalf("StartProcess expected to fail, but succeeded.")
-}
diff --git a/src/os/path_plan9.go b/src/os/path_plan9.go
index b09b53a..64bad50 100644
--- a/src/os/path_plan9.go
+++ b/src/os/path_plan9.go
@@ -9,7 +9,7 @@ const (
 	PathListSeparator = '\000' // OS-specific path list separator
 )
 
-// IsPathSeparator reports whether c is a directory separator character.
+// IsPathSeparator returns true if c is a directory separator character.
 func IsPathSeparator(c uint8) bool {
 	return PathSeparator == c
 }
diff --git a/src/os/path_test.go b/src/os/path_test.go
index f985381..6f24a43 100644
--- a/src/os/path_test.go
+++ b/src/os/path_test.go
@@ -13,8 +13,6 @@ import (
 	"testing"
 )
 
-var isReadonlyError = func(error) bool { return false }
-
 func TestMkdirAll(t *testing.T) {
 	tmpDir := TempDir()
 	path := tmpDir + "/_TestMkdirAll_/dir/./dir2"
@@ -207,22 +205,16 @@ func TestMkdirAllAtSlash(t *testing.T) {
 	switch runtime.GOOS {
 	case "android", "plan9", "windows":
 		t.Skipf("skipping on %s", runtime.GOOS)
-	case "darwin":
-		switch runtime.GOARCH {
-		case "arm", "arm64":
-			t.Skipf("skipping on darwin/%s, mkdir returns EPERM", runtime.GOARCH)
-		}
 	}
 	RemoveAll("/_go_os_test")
-	const dir = "/_go_os_test/dir"
-	err := MkdirAll(dir, 0777)
+	err := MkdirAll("/_go_os_test/dir", 0777)
 	if err != nil {
 		pathErr, ok := err.(*PathError)
 		// common for users not to be able to write to /
-		if ok && (pathErr.Err == syscall.EACCES || isReadonlyError(pathErr.Err)) {
-			t.Skipf("could not create %v: %v", dir, err)
+		if ok && pathErr.Err == syscall.EACCES {
+			return
 		}
-		t.Fatalf(`MkdirAll "/_go_os_test/dir": %v, %s`, err, pathErr.Err)
+		t.Fatalf(`MkdirAll "/_go_os_test/dir": %v`, err)
 	}
 	RemoveAll("/_go_os_test")
 }
diff --git a/src/os/path_unix.go b/src/os/path_unix.go
index 36f8e61..0211107 100644
--- a/src/os/path_unix.go
+++ b/src/os/path_unix.go
@@ -11,7 +11,7 @@ const (
 	PathListSeparator = ':' // OS-specific path list separator
 )
 
-// IsPathSeparator reports whether c is a directory separator character.
+// IsPathSeparator returns true if c is a directory separator character.
 func IsPathSeparator(c uint8) bool {
 	return PathSeparator == c
 }
diff --git a/src/os/path_windows.go b/src/os/path_windows.go
index c96f137..61f2ca5 100644
--- a/src/os/path_windows.go
+++ b/src/os/path_windows.go
@@ -9,7 +9,7 @@ const (
 	PathListSeparator = ';'  // OS-specific path list separator
 )
 
-// IsPathSeparator reports whether c is a directory separator character.
+// IsPathSeparator returns true if c is a directory separator character.
 func IsPathSeparator(c uint8) bool {
 	// NOTE: Windows accept / as path separator.
 	return c == '\\' || c == '/'
diff --git a/src/os/proc.go b/src/os/proc.go
index 33a8b26..774f099 100644
--- a/src/os/proc.go
+++ b/src/os/proc.go
@@ -44,14 +44,6 @@ func Getgroups() ([]int, error) {
 
 // Exit causes the current program to exit with the given status code.
 // Conventionally, code zero indicates success, non-zero an error.
-// The program terminates immediately; deferred functions are not run.
-func Exit(code int) {
-	if code == 0 {
-		// Give race detector a chance to fail the program.
-		// Racy programs do not have the right to finish successfully.
-		runtime_beforeExit()
-	}
-	syscall.Exit(code)
-}
-
-func runtime_beforeExit() // implemented in runtime
+// The program terminates immediately; deferred functions are
+// not run.
+func Exit(code int) { syscall.Exit(code) }
diff --git a/src/os/signal/sig.s b/src/os/signal/sig.s
index 7fa6c92..d54c284 100644
--- a/src/os/signal/sig.s
+++ b/src/os/signal/sig.s
@@ -4,19 +4,13 @@
 
 // Assembly to get into package runtime without using exported symbols.
 
-// +build amd64 amd64p32 arm arm64 386 ppc64 ppc64le
+// +build amd64 amd64p32 arm 386
 
 #include "textflag.h"
 
 #ifdef GOARCH_arm
 #define JMP B
 #endif
-#ifdef GOARCH_ppc64
-#define JMP BR
-#endif
-#ifdef GOARCH_ppc64le
-#define JMP BR
-#endif
 
 TEXT ·signal_disable(SB),NOSPLIT,$0
 	JMP runtime·signal_disable(SB)
@@ -24,9 +18,6 @@ TEXT ·signal_disable(SB),NOSPLIT,$0
 TEXT ·signal_enable(SB),NOSPLIT,$0
 	JMP runtime·signal_enable(SB)
 
-TEXT ·signal_ignore(SB),NOSPLIT,$0
-	JMP runtime·signal_ignore(SB)
-
 TEXT ·signal_recv(SB),NOSPLIT,$0
 	JMP runtime·signal_recv(SB)
 
diff --git a/src/os/signal/signal.go b/src/os/signal/signal.go
index 1625786..3004275 100644
--- a/src/os/signal/signal.go
+++ b/src/os/signal/signal.go
@@ -5,6 +5,8 @@
 // Package signal implements access to incoming signals.
 package signal
 
+// BUG(rsc): This package is not yet implemented on Plan 9.
+
 import (
 	"os"
 	"sync"
@@ -28,55 +30,9 @@ func (h *handler) set(sig int) {
 	h.mask[sig/32] |= 1 << uint(sig&31)
 }
 
-func (h *handler) clear(sig int) {
-	h.mask[sig/32] &^= 1 << uint(sig&31)
-}
-
-// Stop relaying the signals, sigs, to any channels previously registered to
-// receive them and either reset the signal handlers to their original values
-// (action=disableSignal) or ignore the signals (action=ignoreSignal).
-func cancel(sigs []os.Signal, action func(int)) {
-	handlers.Lock()
-	defer handlers.Unlock()
-
-	remove := func(n int) {
-		var zerohandler handler
-
-		for c, h := range handlers.m {
-			if h.want(n) {
-				handlers.ref[n]--
-				h.clear(n)
-				if h.mask == zerohandler.mask {
-					delete(handlers.m, c)
-				}
-			}
-		}
-
-		action(n)
-	}
-
-	if len(sigs) == 0 {
-		for n := 0; n < numSig; n++ {
-			remove(n)
-		}
-	} else {
-		for _, s := range sigs {
-			remove(signum(s))
-		}
-	}
-}
-
-// Ignore causes the provided signals to be ignored. If they are received by
-// the program, nothing will happen. Ignore undoes the effect of any prior
-// calls to Notify for the provided signals.
-// If no signals are provided, all incoming signals will be ignored.
-func Ignore(sig ...os.Signal) {
-	cancel(sig, ignoreSignal)
-}
-
 // Notify causes package signal to relay incoming signals to c.
-// If no signals are provided, all incoming signals will be relayed to c.
-// Otherwise, just the provided signals will.
+// If no signals are listed, all incoming signals will be relayed to c.
+// Otherwise, just the listed signals will.
 //
 // Package signal will not block sending to c: the caller must ensure
 // that c has sufficient buffer space to keep up with the expected
@@ -131,13 +87,6 @@ func Notify(c chan<- os.Signal, sig ...os.Signal) {
 	}
 }
 
-// Reset undoes the effect of any prior calls to Notify for the provided
-// signals.
-// If no signals are provided, all signal handlers will be reset.
-func Reset(sig ...os.Signal) {
-	cancel(sig, disableSignal)
-}
-
 // Stop causes package signal to stop relaying incoming signals to c.
 // It undoes the effect of all prior calls to Notify using c.
 // When Stop returns, it is guaranteed that c will receive no more signals.
diff --git a/src/os/signal/signal_stub.go b/src/os/signal/signal_stub.go
new file mode 100644
index 0000000..d0a6935
--- /dev/null
+++ b/src/os/signal/signal_stub.go
@@ -0,0 +1,17 @@
+// 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 plan9
+
+package signal
+
+import "os"
+
+const numSig = 0
+
+func signum(sig os.Signal) int { return -1 }
+
+func disableSignal(int) {}
+
+func enableSignal(int) {}
diff --git a/src/os/signal/signal_test.go b/src/os/signal/signal_test.go
index a71633c..22337a7 100644
--- a/src/os/signal/signal_test.go
+++ b/src/os/signal/signal_test.go
@@ -109,72 +109,6 @@ func TestStress(t *testing.T) {
 	time.Sleep(10 * time.Millisecond)
 }
 
-func testCancel(t *testing.T, ignore bool) {
-	// Send SIGWINCH. By default this signal should be ignored.
-	syscall.Kill(syscall.Getpid(), syscall.SIGWINCH)
-	time.Sleep(100 * time.Millisecond)
-
-	// Ask to be notified on c1 when a SIGWINCH is received.
-	c1 := make(chan os.Signal, 1)
-	Notify(c1, syscall.SIGWINCH)
-	defer Stop(c1)
-
-	// Ask to be notified on c2 when a SIGHUP is received.
-	c2 := make(chan os.Signal, 1)
-	Notify(c2, syscall.SIGHUP)
-	defer Stop(c2)
-
-	// Send this process a SIGWINCH and wait for notification on c1.
-	syscall.Kill(syscall.Getpid(), syscall.SIGWINCH)
-	waitSig(t, c1, syscall.SIGWINCH)
-
-	// Send this process a SIGHUP and wait for notification on c2.
-	syscall.Kill(syscall.Getpid(), syscall.SIGHUP)
-	waitSig(t, c2, syscall.SIGHUP)
-
-	// Ignore, or reset the signal handlers for, SIGWINCH and SIGHUP.
-	if ignore {
-		Ignore(syscall.SIGWINCH, syscall.SIGHUP)
-	} else {
-		Reset(syscall.SIGWINCH, syscall.SIGHUP)
-	}
-
-	// Send this process a SIGWINCH. It should be ignored.
-	syscall.Kill(syscall.Getpid(), syscall.SIGWINCH)
-
-	// If ignoring, Send this process a SIGHUP. It should be ignored.
-	if ignore {
-		syscall.Kill(syscall.Getpid(), syscall.SIGHUP)
-	}
-
-	select {
-	case s := <-c1:
-		t.Fatalf("unexpected signal %v", s)
-	case <-time.After(100 * time.Millisecond):
-		// nothing to read - good
-	}
-
-	select {
-	case s := <-c2:
-		t.Fatalf("unexpected signal %v", s)
-	case <-time.After(100 * time.Millisecond):
-		// nothing to read - good
-	}
-
-	// Reset the signal handlers for all signals.
-	Reset()
-}
-
-// Test that Reset cancels registration for listed signals on all channels.
-func TestReset(t *testing.T) {
-	testCancel(t, false)
-}
-
-// Test that Ignore cancels registration for listed signals on all channels.
-func TestIgnore(t *testing.T) {
-	testCancel(t, true)
-}
-
 var sendUncaughtSighup = flag.Int("send_uncaught_sighup", 0, "send uncaught SIGHUP during TestStop")
 
 // Test that Stop cancels the channel's registrations.
diff --git a/src/os/signal/signal_unix.go b/src/os/signal/signal_unix.go
index 1bdf1d7..94b8ab3 100644
--- a/src/os/signal/signal_unix.go
+++ b/src/os/signal/signal_unix.go
@@ -14,7 +14,6 @@ import (
 // In assembly.
 func signal_disable(uint32)
 func signal_enable(uint32)
-func signal_ignore(uint32)
 func signal_recv() uint32
 
 func loop() {
@@ -52,7 +51,3 @@ func enableSignal(sig int) {
 func disableSignal(sig int) {
 	signal_disable(uint32(sig))
 }
-
-func ignoreSignal(sig int) {
-	signal_ignore(uint32(sig))
-}
diff --git a/src/os/stat_plan9.go b/src/os/stat_plan9.go
index fa4bd83..25c9a8c 100644
--- a/src/os/stat_plan9.go
+++ b/src/os/stat_plan9.go
@@ -9,8 +9,6 @@ import (
 	"time"
 )
 
-const _BIT16SZ = 2
-
 func sameFile(fs1, fs2 *fileStat) bool {
 	a := fs1.sys.(*syscall.Dir)
 	b := fs2.sys.(*syscall.Dir)
@@ -43,14 +41,16 @@ func fileInfoFromStat(d *syscall.Dir) FileInfo {
 // arg is an open *File or a path string.
 func dirstat(arg interface{}) (*syscall.Dir, error) {
 	var name string
-	var err error
 
-	size := syscall.STATFIXLEN + 16*4
+	// This is big enough for most stat messages
+	// and rounded to a multiple of 128 bytes.
+	size := (syscall.STATFIXLEN + 16*4 + 128) &^ 128
 
 	for i := 0; i < 2; i++ {
-		buf := make([]byte, _BIT16SZ+size)
+		buf := make([]byte, size)
 
 		var n int
+		var err error
 		switch a := arg.(type) {
 		case *File:
 			name = a.name
@@ -61,36 +61,34 @@ func dirstat(arg interface{}) (*syscall.Dir, error) {
 		default:
 			panic("phase error in dirstat")
 		}
-
-		if n < _BIT16SZ {
+		if err != nil {
 			return nil, &PathError{"stat", name, err}
 		}
+		if n < syscall.STATFIXLEN {
+			return nil, &PathError{"stat", name, syscall.ErrShortStat}
+		}
 
 		// Pull the real size out of the stat message.
 		size = int(uint16(buf[0]) | uint16(buf[1])<<8)
 
 		// If the stat message is larger than our buffer we will
 		// go around the loop and allocate one that is big enough.
-		if size <= n {
-			d, err := syscall.UnmarshalDir(buf[:n])
-			if err != nil {
-				return nil, &PathError{"stat", name, err}
-			}
-			return d, nil
+		if size > n {
+			continue
 		}
 
+		d, err := syscall.UnmarshalDir(buf[:n])
+		if err != nil {
+			return nil, &PathError{"stat", name, err}
+		}
+		return d, nil
 	}
-
-	if err == nil {
-		err = syscall.ErrBadStat
-	}
-
-	return nil, &PathError{"stat", name, err}
+	return nil, &PathError{"stat", name, syscall.ErrBadStat}
 }
 
 // Stat returns a FileInfo describing the named file.
 // If there is an error, it will be of type *PathError.
-func Stat(name string) (FileInfo, error) {
+func Stat(name string) (fi FileInfo, err error) {
 	d, err := dirstat(name)
 	if err != nil {
 		return nil, err
@@ -102,7 +100,7 @@ func Stat(name string) (FileInfo, error) {
 // If the file is a symbolic link, the returned FileInfo
 // describes the symbolic link.  Lstat makes no attempt to follow the link.
 // If there is an error, it will be of type *PathError.
-func Lstat(name string) (FileInfo, error) {
+func Lstat(name string) (fi FileInfo, err error) {
 	return Stat(name)
 }
 
diff --git a/src/os/stat_windows.go b/src/os/stat_windows.go
index 966163b..f396c1d 100644
--- a/src/os/stat_windows.go
+++ b/src/os/stat_windows.go
@@ -11,7 +11,7 @@ import (
 
 // Stat returns the FileInfo structure describing file.
 // If there is an error, it will be of type *PathError.
-func (file *File) Stat() (FileInfo, error) {
+func (file *File) Stat() (fi FileInfo, err error) {
 	if file == nil {
 		return nil, ErrInvalid
 	}
@@ -48,29 +48,28 @@ func (file *File) Stat() (FileInfo, error) {
 
 // Stat returns a FileInfo structure describing the named file.
 // If there is an error, it will be of type *PathError.
-func Stat(name string) (FileInfo, error) {
-	var fi FileInfo
-	var err error
+func Stat(name string) (fi FileInfo, err error) {
 	for {
 		fi, err = Lstat(name)
 		if err != nil {
-			return fi, err
+			return
 		}
 		if fi.Mode()&ModeSymlink == 0 {
-			return fi, nil
+			return
 		}
 		name, err = Readlink(name)
 		if err != nil {
-			return fi, err
+			return
 		}
 	}
+	return fi, err
 }
 
 // Lstat returns the FileInfo structure describing the named file.
 // If the file is a symbolic link, the returned FileInfo
 // describes the symbolic link.  Lstat makes no attempt to follow the link.
 // If there is an error, it will be of type *PathError.
-func Lstat(name string) (FileInfo, error) {
+func Lstat(name string) (fi FileInfo, err error) {
 	if len(name) == 0 {
 		return nil, &PathError{"Lstat", name, syscall.Errno(syscall.ERROR_PATH_NOT_FOUND)}
 	}
diff --git a/src/os/str.go b/src/os/str.go
index d3e03e9..e3606b6 100644
--- a/src/os/str.go
+++ b/src/os/str.go
@@ -2,32 +2,21 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// Simple converions to avoid depending on strconv.
+// +build plan9
 
 package os
 
-// Convert integer to decimal string
-func itoa(val int) string {
+func itoa(val int) string { // do it here rather than with fmt to avoid dependency
 	if val < 0 {
-		return "-" + uitoa(uint(-val))
+		return "-" + itoa(-val)
 	}
-	return uitoa(uint(val))
-}
-
-// Convert unsigned integer to decimal string
-func uitoa(val uint) string {
-	if val == 0 { // avoid string allocation
-		return "0"
-	}
-	var buf [20]byte // big enough for 64bit value base 10
+	var buf [32]byte // big enough for int64
 	i := len(buf) - 1
 	for val >= 10 {
-		q := val / 10
-		buf[i] = byte('0' + val - q*10)
+		buf[i] = byte(val%10 + '0')
 		i--
-		val = q
+		val /= 10
 	}
-	// val < 10
-	buf[i] = byte('0' + val)
+	buf[i] = byte(val + '0')
 	return string(buf[i:])
 }
diff --git a/src/os/sys_windows.go b/src/os/sys_windows.go
index 9490ea6..92617de 100644
--- a/src/os/sys_windows.go
+++ b/src/os/sys_windows.go
@@ -4,30 +4,12 @@
 
 package os
 
-import (
-	"internal/syscall/windows"
-	"syscall"
-)
+import "syscall"
 
 func hostname() (name string, err error) {
-	// Use PhysicalDnsHostname to uniquely identify host in a cluster
-	const format = windows.ComputerNamePhysicalDnsHostname
-
-	n := uint32(64)
-	for {
-		b := make([]uint16, n)
-		err := windows.GetComputerNameEx(format, &b[0], &n)
-		if err == nil {
-			return syscall.UTF16ToString(b[:n]), nil
-		}
-		if err != syscall.ERROR_MORE_DATA {
-			return "", NewSyscallError("ComputerNameEx", err)
-		}
-
-		// If we received a ERROR_MORE_DATA, but n doesn't get larger,
-		// something has gone wrong and we may be in an infinite loop
-		if n <= uint32(len(b)) {
-			return "", NewSyscallError("ComputerNameEx", err)
-		}
+	s, e := syscall.ComputerName()
+	if e != nil {
+		return "", NewSyscallError("ComputerName", e)
 	}
+	return s, nil
 }
diff --git a/src/os/types.go b/src/os/types.go
index 9d6f8e1..473d431 100644
--- a/src/os/types.go
+++ b/src/os/types.go
@@ -53,7 +53,7 @@ const (
 	// Mask for the type bits. For regular files, none will be set.
 	ModeType = ModeDir | ModeSymlink | ModeNamedPipe | ModeSocket | ModeDevice
 
-	ModePerm FileMode = 0777 // Unix permission bits
+	ModePerm FileMode = 0777 // permission bits
 )
 
 func (m FileMode) String() string {
diff --git a/src/os/user/lookup_unix.go b/src/os/user/lookup_unix.go
index f4f603e..0871473 100644
--- a/src/os/user/lookup_unix.go
+++ b/src/os/user/lookup_unix.go
@@ -17,7 +17,6 @@ import (
 )
 
 /*
-#cgo solaris CFLAGS: -D_POSIX_PTHREAD_SEMANTICS
 #include <unistd.h>
 #include <sys/types.h>
 #include <pwd.h>
@@ -25,12 +24,7 @@ import (
 
 static int mygetpwuid_r(int uid, struct passwd *pwd,
 	char *buf, size_t buflen, struct passwd **result) {
-	return getpwuid_r(uid, pwd, buf, buflen, result);
-}
-
-static int mygetpwnam_r(const char *name, struct passwd *pwd,
-	char *buf, size_t buflen, struct passwd **result) {
-	return getpwnam_r(name, pwd, buf, buflen, result);
+ return getpwuid_r(uid, pwd, buf, buflen, result);
 }
 */
 import "C"
@@ -73,11 +67,7 @@ func lookupUnix(uid int, username string, lookupByName bool) (*User, error) {
 	if lookupByName {
 		nameC := C.CString(username)
 		defer C.free(unsafe.Pointer(nameC))
-		// mygetpwnam_r is a wrapper around getpwnam_r to avoid
-		// passing a size_t to getpwnam_r, because for unknown
-		// reasons passing a size_t to getpwnam_r doesn't work on
-		// Solaris.
-		rv = C.mygetpwnam_r(nameC,
+		rv = C.getpwnam_r(nameC,
 			&pwd,
 			(*C.char)(buf),
 			C.size_t(bufSize),
diff --git a/src/path/filepath/example_unix_test.go b/src/path/filepath/example_unix_test.go
index 27d85d1..f3fe076 100644
--- a/src/path/filepath/example_unix_test.go
+++ b/src/path/filepath/example_unix_test.go
@@ -37,31 +37,3 @@ func ExampleRel() {
 	// "/b/c": "../b/c" <nil>
 	// "./b/c": "" Rel: can't make b/c relative to /a
 }
-
-func ExampleSplit() {
-	paths := []string{
-		"/home/arnie/amelia.jpg",
-		"/mnt/photos/",
-		"rabbit.jpg",
-		"/usr/local//go",
-	}
-	fmt.Println("On Unix:")
-	for _, p := range paths {
-		dir, file := filepath.Split(p)
-		fmt.Printf("input: %q\n\tdir: %q\n\tfile: %q\n", p, dir, file)
-	}
-	// Output:
-	// On Unix:
-	// input: "/home/arnie/amelia.jpg"
-	// 	dir: "/home/arnie/"
-	// 	file: "amelia.jpg"
-	// input: "/mnt/photos/"
-	// 	dir: "/mnt/photos/"
-	// 	file: ""
-	// input: "rabbit.jpg"
-	// 	dir: ""
-	// 	file: "rabbit.jpg"
-	// input: "/usr/local//go"
-	// 	dir: "/usr/local//"
-	// 	file: "go"
-}
diff --git a/src/path/filepath/match.go b/src/path/filepath/match.go
index 89f16de..ecc07aa 100644
--- a/src/path/filepath/match.go
+++ b/src/path/filepath/match.go
@@ -16,7 +16,7 @@ import (
 // ErrBadPattern indicates a globbing pattern was malformed.
 var ErrBadPattern = errors.New("syntax error in pattern")
 
-// Match reports whether name matches the shell file name pattern.
+// Match returns true if name matches the shell file name pattern.
 // The pattern syntax is:
 //
 //	pattern:
@@ -301,7 +301,7 @@ func glob(dir, pattern string, matches []string) (m []string, e error) {
 	return
 }
 
-// hasMeta reports whether path contains any of the magic characters
+// hasMeta returns true if path contains any of the magic characters
 // recognized by Match.
 func hasMeta(path string) bool {
 	// TODO(niemeyer): Should other magic characters be added here?
diff --git a/src/path/filepath/path.go b/src/path/filepath/path.go
index 5dc5cfd..d37fc9d 100644
--- a/src/path/filepath/path.go
+++ b/src/path/filepath/path.go
@@ -4,9 +4,6 @@
 
 // Package filepath implements utility routines for manipulating filename paths
 // in a way compatible with the target operating system-defined file paths.
-//
-// Functions in this package replace any occurrences of the slash ('/') character
-// with os.PathSeparator when returning paths unless otherwise specified.
 package filepath
 
 import (
@@ -177,8 +174,7 @@ func FromSlash(path string) string {
 
 // SplitList splits a list of paths joined by the OS-specific ListSeparator,
 // usually found in PATH or GOPATH environment variables.
-// Unlike strings.Split, SplitList returns an empty slice when passed an empty
-// string. SplitList does not replace slash characters in the returned paths.
+// Unlike strings.Split, SplitList returns an empty slice when passed an empty string.
 func SplitList(path string) []string {
 	return splitList(path)
 }
@@ -200,10 +196,13 @@ func Split(path string) (dir, file string) {
 // Join joins any number of path elements into a single path, adding
 // a Separator if necessary. The result is Cleaned, in particular
 // all empty strings are ignored.
-// On Windows, the result is a UNC path if and only if the first path
-// element is a UNC path.
 func Join(elem ...string) string {
-	return join(elem)
+	for i, e := range elem {
+		if e != "" {
+			return Clean(strings.Join(elem[i:], string(Separator)))
+		}
+	}
+	return ""
 }
 
 // Ext returns the file name extension used by path.
@@ -335,11 +334,10 @@ var SkipDir = errors.New("skip this directory")
 // If there was a problem walking to the file or directory named by path, the
 // incoming error will describe the problem and the function can decide how
 // to handle that error (and Walk will not descend into that directory). If
-// an error is returned, processing stops. The sole exception is when the function
-// returns the special value SkipDir. If the function returns SkipDir when invoked
-// on a directory, Walk skips the directory's contents entirely.
-// If the function returns SkipDir when invoked on a non-directory file,
-// Walk skips the remaining files in the containing directory.
+// an error is returned, processing stops. The sole exception is that if path
+// is a directory and the function returns the special value SkipDir, the
+// contents of the directory are skipped and processing continues as usual on
+// the next file.
 type WalkFunc func(path string, info os.FileInfo, err error) error
 
 var lstat = os.Lstat // for testing
@@ -458,9 +456,9 @@ func Dir(path string) string {
 }
 
 // VolumeName returns leading volume name.
-// Given "C:\foo\bar" it returns "C:" on Windows.
+// Given "C:\foo\bar" it returns "C:" under windows.
 // Given "\\host\share\foo" it returns "\\host\share".
 // On other platforms it returns "".
-func VolumeName(path string) string {
+func VolumeName(path string) (v string) {
 	return path[:volumeNameLen(path)]
 }
diff --git a/src/path/filepath/path_plan9.go b/src/path/filepath/path_plan9.go
index 962774e..ee8912d 100644
--- a/src/path/filepath/path_plan9.go
+++ b/src/path/filepath/path_plan9.go
@@ -6,7 +6,7 @@ package filepath
 
 import "strings"
 
-// IsAbs reports whether the path is absolute.
+// IsAbs returns true if the path is absolute.
 func IsAbs(path string) bool {
 	return strings.HasPrefix(path, "/") || strings.HasPrefix(path, "#")
 }
@@ -32,13 +32,3 @@ func splitList(path string) []string {
 func abs(path string) (string, error) {
 	return unixAbs(path)
 }
-
-func join(elem []string) string {
-	// If there's a bug here, fix the logic in ./path_unix.go too.
-	for i, e := range elem {
-		if e != "" {
-			return Clean(strings.Join(elem[i:], string(Separator)))
-		}
-	}
-	return ""
-}
diff --git a/src/path/filepath/path_test.go b/src/path/filepath/path_test.go
index 1c32e27..399284b 100644
--- a/src/path/filepath/path_test.go
+++ b/src/path/filepath/path_test.go
@@ -242,7 +242,6 @@ var jointests = []JoinTest{
 
 	// one parameter
 	{[]string{""}, ""},
-	{[]string{"/"}, "/"},
 	{[]string{"a"}, "a"},
 
 	// two parameters
@@ -250,16 +249,10 @@ var jointests = []JoinTest{
 	{[]string{"a", ""}, "a"},
 	{[]string{"", "b"}, "b"},
 	{[]string{"/", "a"}, "/a"},
-	{[]string{"/", "a/b"}, "/a/b"},
 	{[]string{"/", ""}, "/"},
-	{[]string{"//", "a"}, "/a"},
-	{[]string{"/a", "b"}, "/a/b"},
 	{[]string{"a/", "b"}, "a/b"},
 	{[]string{"a/", ""}, "a"},
 	{[]string{"", ""}, ""},
-
-	// three parameters
-	{[]string{"/", "a", "b"}, "/a/b"},
 }
 
 var winjointests = []JoinTest{
@@ -269,17 +262,13 @@ var winjointests = []JoinTest{
 	{[]string{`C:\`, `Windows`}, `C:\Windows`},
 	{[]string{`C:`, `Windows`}, `C:\Windows`},
 	{[]string{`\\host\share`, `foo`}, `\\host\share\foo`},
-	{[]string{`\\host\share\foo`}, `\\host\share\foo`},
 	{[]string{`//host/share`, `foo/bar`}, `\\host\share\foo\bar`},
-	{[]string{`\`}, `\`},
-	{[]string{`\`, ``}, `\`},
-	{[]string{`\`, `a`}, `\a`},
-	{[]string{`\\`, `a`}, `\a`},
-	{[]string{`\`, `a`, `b`}, `\a\b`},
-	{[]string{`\\`, `a`, `b`}, `\a\b`},
-	{[]string{`\`, `\\a\b`, `c`}, `\a\b\c`},
-	{[]string{`\\a`, `b`, `c`}, `\a\b\c`},
-	{[]string{`\\a\`, `b`, `c`}, `\a\b\c`},
+}
+
+// join takes a []string and passes it to Join.
+func join(elem []string, args ...string) string {
+	args = elem
+	return filepath.Join(args...)
 }
 
 func TestJoin(t *testing.T) {
@@ -287,9 +276,8 @@ func TestJoin(t *testing.T) {
 		jointests = append(jointests, winjointests...)
 	}
 	for _, test := range jointests {
-		expected := filepath.FromSlash(test.path)
-		if p := filepath.Join(test.elem...); p != expected {
-			t.Errorf("join(%q) = %q, want %q", test.elem, p, expected)
+		if p := join(test.elem); p != filepath.FromSlash(test.path) {
+			t.Errorf("join(%q) = %q, want %q", test.elem, p, test.path)
 		}
 	}
 }
@@ -399,34 +387,7 @@ func mark(path string, info os.FileInfo, err error, errors *[]error, clear bool)
 	return nil
 }
 
-func chtmpdir(t *testing.T) (restore func()) {
-	oldwd, err := os.Getwd()
-	if err != nil {
-		t.Fatal("chtmpdir: %v", err)
-	}
-	d, err := ioutil.TempDir("", "test")
-	if err != nil {
-		t.Fatal("chtmpdir: %v", err)
-	}
-	if err := os.Chdir(d); err != nil {
-		t.Fatal("chtmpdir: %v", err)
-	}
-	return func() {
-		if err := os.Chdir(oldwd); err != nil {
-			t.Fatal("chtmpdir: %v", err)
-		}
-		os.RemoveAll(d)
-	}
-}
-
 func TestWalk(t *testing.T) {
-	if runtime.GOOS == "darwin" {
-		switch runtime.GOARCH {
-		case "arm", "arm64":
-			restore := chtmpdir(t)
-			defer restore()
-		}
-	}
 	makeTree(t)
 	errors := make([]error, 0, 10)
 	clear := true
@@ -510,35 +471,6 @@ func touch(t *testing.T, name string) {
 	}
 }
 
-func TestWalkSkipDirOnFile(t *testing.T) {
-	td, err := ioutil.TempDir("", "walktest")
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer os.RemoveAll(td)
-
-	if err := os.MkdirAll(filepath.Join(td, "dir"), 0755); err != nil {
-		t.Fatal(err)
-	}
-	touch(t, filepath.Join(td, "dir/foo1"))
-	touch(t, filepath.Join(td, "dir/foo2"))
-
-	sawFoo2 := false
-	filepath.Walk(td, func(path string, info os.FileInfo, err error) error {
-		if strings.HasSuffix(path, "foo2") {
-			sawFoo2 = true
-		}
-		if strings.HasSuffix(path, "foo1") {
-			return filepath.SkipDir
-		}
-		return nil
-	})
-
-	if sawFoo2 {
-		t.Errorf("SkipDir on file foo1 did not block processing of foo2")
-	}
-}
-
 func TestWalkFileError(t *testing.T) {
 	td, err := ioutil.TempDir("", "walktest")
 	if err != nil {
@@ -1064,13 +996,7 @@ func TestDriveLetterInEvalSymlinks(t *testing.T) {
 	}
 }
 
-func TestBug3486(t *testing.T) { // https://golang.org/issue/3486
-	if runtime.GOOS == "darwin" {
-		switch runtime.GOARCH {
-		case "arm", "arm64":
-			t.Skipf("skipping on %s/%s", runtime.GOOS, runtime.GOARCH)
-		}
-	}
+func TestBug3486(t *testing.T) { // http://code.google.com/p/go/issues/detail?id=3486
 	root, err := filepath.EvalSymlinks(runtime.GOROOT() + "/test")
 	if err != nil {
 		t.Fatal(err)
diff --git a/src/path/filepath/path_unix.go b/src/path/filepath/path_unix.go
index d241d78..4e7d0d1 100644
--- a/src/path/filepath/path_unix.go
+++ b/src/path/filepath/path_unix.go
@@ -8,7 +8,7 @@ package filepath
 
 import "strings"
 
-// IsAbs reports whether the path is absolute.
+// IsAbs returns true if the path is absolute.
 func IsAbs(path string) bool {
 	return strings.HasPrefix(path, "/")
 }
@@ -34,13 +34,3 @@ func splitList(path string) []string {
 func abs(path string) (string, error) {
 	return unixAbs(path)
 }
-
-func join(elem []string) string {
-	// If there's a bug here, fix the logic in ./path_plan9.go too.
-	for i, e := range elem {
-		if e != "" {
-			return Clean(strings.Join(elem[i:], string(Separator)))
-		}
-	}
-	return ""
-}
diff --git a/src/path/filepath/path_windows.go b/src/path/filepath/path_windows.go
index bcfe0a3..ec50f6b 100644
--- a/src/path/filepath/path_windows.go
+++ b/src/path/filepath/path_windows.go
@@ -13,7 +13,7 @@ func isSlash(c uint8) bool {
 	return c == '\\' || c == '/'
 }
 
-// IsAbs reports whether the path is absolute.
+// IsAbs returns true if the path is absolute.
 func IsAbs(path string) (b bool) {
 	l := volumeNameLen(path)
 	if l == 0 {
@@ -108,40 +108,3 @@ func splitList(path string) []string {
 func abs(path string) (string, error) {
 	return syscall.FullPath(path)
 }
-
-func join(elem []string) string {
-	for i, e := range elem {
-		if e != "" {
-			return joinNonEmpty(elem[i:])
-		}
-	}
-	return ""
-}
-
-// joinNonEmpty is like join, but it assumes that the first element is non-empty.
-func joinNonEmpty(elem []string) string {
-	// The following logic prevents Join from inadvertently creating a
-	// UNC path on Windows. Unless the first element is a UNC path, Join
-	// shouldn't create a UNC path. See golang.org/issue/9167.
-	p := Clean(strings.Join(elem, string(Separator)))
-	if !isUNC(p) {
-		return p
-	}
-	// p == UNC only allowed when the first element is a UNC path.
-	head := Clean(elem[0])
-	if isUNC(head) {
-		return p
-	}
-	// head + tail == UNC, but joining two non-UNC paths should not result
-	// in a UNC path. Undo creation of UNC path.
-	tail := Clean(strings.Join(elem[1:], string(Separator)))
-	if head[len(head)-1] == Separator {
-		return head + tail
-	}
-	return head + string(Separator) + tail
-}
-
-// isUNC reports whether path is a UNC path.
-func isUNC(path string) bool {
-	return volumeNameLen(path) > 2
-}
diff --git a/src/path/filepath/symlink_windows.go b/src/path/filepath/symlink_windows.go
index 4b38f6f..327c2c8 100644
--- a/src/path/filepath/symlink_windows.go
+++ b/src/path/filepath/symlink_windows.go
@@ -14,17 +14,18 @@ func toShort(path string) (string, error) {
 		return "", err
 	}
 	b := p // GetShortPathName says we can reuse buffer
-	n := uint32(len(b))
-	for {
+	n, err := syscall.GetShortPathName(&p[0], &b[0], uint32(len(b)))
+	if err != nil {
+		return "", err
+	}
+	if n > uint32(len(b)) {
+		b = make([]uint16, n)
 		n, err = syscall.GetShortPathName(&p[0], &b[0], uint32(len(b)))
 		if err != nil {
 			return "", err
 		}
-		if n <= uint32(len(b)) {
-			return syscall.UTF16ToString(b[:n]), nil
-		}
-		b = make([]uint16, n)
 	}
+	return syscall.UTF16ToString(b), nil
 }
 
 func toLong(path string) (string, error) {
@@ -33,17 +34,19 @@ func toLong(path string) (string, error) {
 		return "", err
 	}
 	b := p // GetLongPathName says we can reuse buffer
-	n := uint32(len(b))
-	for {
+	n, err := syscall.GetLongPathName(&p[0], &b[0], uint32(len(b)))
+	if err != nil {
+		return "", err
+	}
+	if n > uint32(len(b)) {
+		b = make([]uint16, n)
 		n, err = syscall.GetLongPathName(&p[0], &b[0], uint32(len(b)))
 		if err != nil {
 			return "", err
 		}
-		if n <= uint32(len(b)) {
-			return syscall.UTF16ToString(b[:n]), nil
-		}
-		b = make([]uint16, n)
 	}
+	b = b[:n]
+	return syscall.UTF16ToString(b), nil
 }
 
 func evalSymlinks(path string) (string, error) {
diff --git a/src/path/match.go b/src/path/match.go
index 75dd3b3..8154bf6 100644
--- a/src/path/match.go
+++ b/src/path/match.go
@@ -13,7 +13,7 @@ import (
 // ErrBadPattern indicates a globbing pattern was malformed.
 var ErrBadPattern = errors.New("syntax error in pattern")
 
-// Match reports whether name matches the shell file name pattern.
+// Match returns true if name matches the shell file name pattern.
 // The pattern syntax is:
 //
 //	pattern:
diff --git a/src/path/path.go b/src/path/path.go
index 77f2185..98a6d52 100644
--- a/src/path/path.go
+++ b/src/path/path.go
@@ -134,7 +134,7 @@ func Clean(path string) string {
 	return out.string()
 }
 
-// Split splits path immediately following the final slash,
+// Split splits path immediately following the final slash.
 // separating it into a directory and file name component.
 // If there is no slash path, Split returns an empty dir and
 // file set to path.
@@ -192,7 +192,7 @@ func Base(path string) string {
 	return path
 }
 
-// IsAbs reports whether the path is absolute.
+// IsAbs returns true if the path is absolute.
 func IsAbs(path string) bool {
 	return len(path) > 0 && path[0] == '/'
 }
diff --git a/src/race.bash b/src/race.bash
index e091736..6225840 100755
--- a/src/race.bash
+++ b/src/race.bash
@@ -4,7 +4,7 @@
 # license that can be found in the LICENSE file.
 
 # race.bash tests the standard library under the race detector.
-# https://golang.org/doc/articles/race_detector.html
+# http://golang.org/doc/articles/race_detector.html
 
 set -e
 
@@ -40,5 +40,14 @@ if [ ! -f make.bash ]; then
 	exit 1
 fi
 . ./make.bash --no-banner
+# 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
-go tool dist test -no-rebuild -race
+
+# 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 33db692..8858c57 100644
--- a/src/race.bat
+++ b/src/race.bat
@@ -3,7 +3,7 @@
 :: license that can be found in the LICENSE file.
 
 :: race.bash tests the standard library under the race detector.
-:: https://golang.org/doc/articles/race_detector.html
+:: http://golang.org/doc/articles/race_detector.html
 
 @echo off
 
@@ -18,7 +18,7 @@ goto end
 set GOROOT=%CD%\..
 call make.bat --dist-tool >NUL
 if errorlevel 1 goto fail
-.\cmd\dist\dist env -w -p >env.bat
+.\cmd\dist\dist env -wp >env.bat
 if errorlevel 1 goto fail
 call env.bat
 del env.bat
@@ -30,12 +30,23 @@ goto fail
 :continue
 call make.bat --no-banner --no-local
 if %GOBUILDFAIL%==1 goto end
+:: golang.org/issue/5537 - we must build a race enabled cmd/cgo before trying to use it.
+echo # go install -race cmd/cgo
+go install -race cmd/cgo
 echo # go install -race std
 go install -race std
 if errorlevel 1 goto fail
 
-go tool dist test -no-rebuild -race
+:: 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
+go test -race -run=nothingplease -bench=.* -benchtime=.1s -cpu=4 std
 if errorlevel 1 goto fail
 goto succ
 
diff --git a/src/reflect/all_test.go b/src/reflect/all_test.go
index 1748bf6..7a01c95 100644
--- a/src/reflect/all_test.go
+++ b/src/reflect/all_test.go
@@ -15,7 +15,6 @@ import (
 	. "reflect"
 	"runtime"
 	"sort"
-	"strconv"
 	"strings"
 	"sync"
 	"testing"
@@ -1053,11 +1052,6 @@ func TestChan(t *testing.T) {
 		ok = cv.TrySend(ValueOf(6))
 		if !ok {
 			t.Errorf("TrySend on empty chan failed")
-			select {
-			case x := <-c:
-				t.Errorf("TrySend failed but it did send %d", x)
-			default:
-			}
 		} else {
 			if i = <-c; i != 6 {
 				t.Errorf("TrySend 6, recv %d", i)
@@ -1382,7 +1376,7 @@ func selectWatcher() {
 	for {
 		time.Sleep(1 * time.Second)
 		selectWatch.Lock()
-		if selectWatch.info != nil && time.Since(selectWatch.now) > 10*time.Second {
+		if selectWatch.info != nil && time.Since(selectWatch.now) > 1*time.Second {
 			fmt.Fprintf(os.Stderr, "TestSelect:\n%s blocked indefinitely\n", fmtSelect(selectWatch.info))
 			panic("select stuck")
 		}
@@ -1507,17 +1501,6 @@ func TestCallWithStruct(t *testing.T) {
 	}
 }
 
-func BenchmarkCall(b *testing.B) {
-	fv := ValueOf(func(a, b string) {})
-	b.ReportAllocs()
-	b.RunParallel(func(pb *testing.PB) {
-		args := []Value{ValueOf("a"), ValueOf("b")}
-		for pb.Next() {
-			fv.Call(args)
-		}
-	})
-}
-
 func TestMakeFunc(t *testing.T) {
 	f := dummy
 	fv := MakeFunc(TypeOf(f), func(in []Value) []Value { return in })
@@ -2736,8 +2719,6 @@ var tagGetTests = []struct {
 	{`protobuf:"PB(1,2)"`, `rotobuf`, ``},
 	{`protobuf:"PB(1,2)" json:"name"`, `json`, `name`},
 	{`protobuf:"PB(1,2)" json:"name"`, `protobuf`, `PB(1,2)`},
-	{`k0:"values contain spaces" k1:"and\ttabs"`, "k0", "values contain spaces"},
-	{`k0:"values contain spaces" k1:"and\ttabs"`, "k1", "and\ttabs"},
 }
 
 func TestTagGet(t *testing.T) {
@@ -3389,240 +3370,24 @@ func checkSameType(t *testing.T, x, y interface{}) {
 }
 
 func TestArrayOf(t *testing.T) {
-	// check construction and use of type not in binary
-	for _, table := range []struct {
-		n          int
-		value      func(i int) interface{}
-		comparable bool
-		want       string
-	}{
-		{
-			n:          0,
-			value:      func(i int) interface{} { type Tint int; return Tint(i) },
-			comparable: true,
-			want:       "[]",
-		},
-		{
-			n:          10,
-			value:      func(i int) interface{} { type Tint int; return Tint(i) },
-			comparable: true,
-			want:       "[0 1 2 3 4 5 6 7 8 9]",
-		},
-		{
-			n:          10,
-			value:      func(i int) interface{} { type Tfloat float64; return Tfloat(i) },
-			comparable: true,
-			want:       "[0 1 2 3 4 5 6 7 8 9]",
-		},
-		{
-			n:          10,
-			value:      func(i int) interface{} { type Tstring string; return Tstring(strconv.Itoa(i)) },
-			comparable: true,
-			want:       "[0 1 2 3 4 5 6 7 8 9]",
-		},
-		{
-			n:          10,
-			value:      func(i int) interface{} { type Tstruct struct{ V int }; return Tstruct{i} },
-			comparable: true,
-			want:       "[{0} {1} {2} {3} {4} {5} {6} {7} {8} {9}]",
-		},
-		{
-			n:          10,
-			value:      func(i int) interface{} { type Tint int; return []Tint{Tint(i)} },
-			comparable: false,
-			want:       "[[0] [1] [2] [3] [4] [5] [6] [7] [8] [9]]",
-		},
-		{
-			n:          10,
-			value:      func(i int) interface{} { type Tint int; return [1]Tint{Tint(i)} },
-			comparable: true,
-			want:       "[[0] [1] [2] [3] [4] [5] [6] [7] [8] [9]]",
-		},
-		{
-			n:          10,
-			value:      func(i int) interface{} { type Tstruct struct{ V [1]int }; return Tstruct{[1]int{i}} },
-			comparable: true,
-			want:       "[{[0]} {[1]} {[2]} {[3]} {[4]} {[5]} {[6]} {[7]} {[8]} {[9]}]",
-		},
-		{
-			n:          10,
-			value:      func(i int) interface{} { type Tstruct struct{ V []int }; return Tstruct{[]int{i}} },
-			comparable: false,
-			want:       "[{[0]} {[1]} {[2]} {[3]} {[4]} {[5]} {[6]} {[7]} {[8]} {[9]}]",
-		},
-		{
-			n:          10,
-			value:      func(i int) interface{} { type TstructUV struct{ U, V int }; return TstructUV{i, i} },
-			comparable: true,
-			want:       "[{0 0} {1 1} {2 2} {3 3} {4 4} {5 5} {6 6} {7 7} {8 8} {9 9}]",
-		},
-		{
-			n: 10,
-			value: func(i int) interface{} {
-				type TstructUV struct {
-					U int
-					V float64
-				}
-				return TstructUV{i, float64(i)}
-			},
-			comparable: true,
-			want:       "[{0 0} {1 1} {2 2} {3 3} {4 4} {5 5} {6 6} {7 7} {8 8} {9 9}]",
-		},
-	} {
-		at := ArrayOf(table.n, TypeOf(table.value(0)))
-		v := New(at).Elem()
-		vok := New(at).Elem()
-		vnot := New(at).Elem()
-		for i := 0; i < v.Len(); i++ {
-			v.Index(i).Set(ValueOf(table.value(i)))
-			vok.Index(i).Set(ValueOf(table.value(i)))
-			j := i
-			if i+1 == v.Len() {
-				j = i + 1
-			}
-			vnot.Index(i).Set(ValueOf(table.value(j))) // make it differ only by last element
-		}
-		s := fmt.Sprint(v.Interface())
-		if s != table.want {
-			t.Errorf("constructed array = %s, want %s", s, table.want)
-		}
+	// TODO(rsc): Finish ArrayOf and enable-test.
+	t.Skip("ArrayOf is not finished (and not exported)")
 
-		if table.comparable != at.Comparable() {
-			t.Errorf("constructed array (%#v) is comparable=%v, want=%v", v.Interface(), at.Comparable(), table.comparable)
-		}
-		if table.comparable {
-			if table.n > 0 {
-				if DeepEqual(vnot.Interface(), v.Interface()) {
-					t.Errorf(
-						"arrays (%#v) compare ok (but should not)",
-						v.Interface(),
-					)
-				}
-			}
-			if !DeepEqual(vok.Interface(), v.Interface()) {
-				t.Errorf(
-					"arrays (%#v) compare NOT-ok (but should)",
-					v.Interface(),
-				)
-			}
-		}
-	}
-
-	// check that type already in binary is found
+	// check construction and use of type not in binary
 	type T int
-	checkSameType(t, Zero(ArrayOf(5, TypeOf(T(1)))).Interface(), [5]T{})
-}
-
-func TestArrayOfGC(t *testing.T) {
-	type T *uintptr
-	tt := TypeOf(T(nil))
-	const n = 100
-	var x []interface{}
-	for i := 0; i < n; i++ {
-		v := New(ArrayOf(n, tt)).Elem()
-		for j := 0; j < v.Len(); j++ {
-			p := new(uintptr)
-			*p = uintptr(i*n + j)
-			v.Index(j).Set(ValueOf(p).Convert(tt))
-		}
-		x = append(x, v.Interface())
-	}
-	runtime.GC()
-
-	for i, xi := range x {
-		v := ValueOf(xi)
-		for j := 0; j < v.Len(); j++ {
-			k := v.Index(j).Elem().Interface()
-			if k != uintptr(i*n+j) {
-				t.Errorf("lost x[%d][%d] = %d, want %d", i, j, k, i*n+j)
-			}
-		}
-	}
-}
-
-func TestArrayOfAlg(t *testing.T) {
-	at := ArrayOf(6, TypeOf(byte(0)))
-	v1 := New(at).Elem()
-	v2 := New(at).Elem()
-	if v1.Interface() != v1.Interface() {
-		t.Errorf("constructed array %v not equal to itself", v1.Interface())
-	}
-	v1.Index(5).Set(ValueOf(byte(1)))
-	if i1, i2 := v1.Interface(), v2.Interface(); i1 == i2 {
-		t.Errorf("constructed arrays %v and %v should not be equal", i1, i2)
-	}
-
-	at = ArrayOf(6, TypeOf([]int(nil)))
-	v1 = New(at).Elem()
-	shouldPanic(func() { _ = v1.Interface() == v1.Interface() })
-}
-
-func TestArrayOfGenericAlg(t *testing.T) {
-	at1 := ArrayOf(5, TypeOf(string("")))
-	at := ArrayOf(6, at1)
-	v1 := New(at).Elem()
-	v2 := New(at).Elem()
-	if v1.Interface() != v1.Interface() {
-		t.Errorf("constructed array %v not equal to itself", v1.Interface())
-	}
-
-	v1.Index(0).Index(0).Set(ValueOf("abc"))
-	v2.Index(0).Index(0).Set(ValueOf("efg"))
-	if i1, i2 := v1.Interface(), v2.Interface(); i1 == i2 {
-		t.Errorf("constructed arrays %v and %v should not be equal", i1, i2)
-	}
-
-	v1.Index(0).Index(0).Set(ValueOf("abc"))
-	v2.Index(0).Index(0).Set(ValueOf((v1.Index(0).Index(0).String() + " ")[:3]))
-	if i1, i2 := v1.Interface(), v2.Interface(); i1 != i2 {
-		t.Errorf("constructed arrays %v and %v should be equal", i1, i2)
-	}
-
-	// Test hash
-	m := MakeMap(MapOf(at, TypeOf(int(0))))
-	m.SetMapIndex(v1, ValueOf(1))
-	if i1, i2 := v1.Interface(), v2.Interface(); !m.MapIndex(v2).IsValid() {
-		t.Errorf("constructed arrays %v and %v have different hashes", i1, i2)
+	at := ArrayOf(10, TypeOf(T(1)))
+	v := New(at).Elem()
+	for i := 0; i < v.Len(); i++ {
+		v.Index(i).Set(ValueOf(T(i)))
 	}
-}
-
-func TestArrayOfDirectIface(t *testing.T) {
-	{
-		type T [1]*byte
-		i1 := Zero(TypeOf(T{})).Interface()
-		v1 := ValueOf(&i1).Elem()
-		p1 := v1.InterfaceData()[1]
-
-		i2 := Zero(ArrayOf(1, PtrTo(TypeOf(int8(0))))).Interface()
-		v2 := ValueOf(&i2).Elem()
-		p2 := v2.InterfaceData()[1]
-
-		if p1 != 0 {
-			t.Errorf("got p1=%v. want=%v", p1, nil)
-		}
-
-		if p2 != 0 {
-			t.Errorf("got p2=%v. want=%v", p2, nil)
-		}
+	s := fmt.Sprint(v.Interface())
+	want := "[0 1 2 3 4 5 6 7 8 9]"
+	if s != want {
+		t.Errorf("constructed array = %s, want %s", s, want)
 	}
-	{
-		type T [0]*byte
-		i1 := Zero(TypeOf(T{})).Interface()
-		v1 := ValueOf(&i1).Elem()
-		p1 := v1.InterfaceData()[1]
-
-		i2 := Zero(ArrayOf(0, PtrTo(TypeOf(int8(0))))).Interface()
-		v2 := ValueOf(&i2).Elem()
-		p2 := v2.InterfaceData()[1]
 
-		if p1 == 0 {
-			t.Errorf("got p1=%v. want=not-%v", p1, nil)
-		}
-
-		if p2 == 0 {
-			t.Errorf("got p2=%v. want=not-%v", p2, nil)
-		}
-	}
+	// check that type already in binary is found
+	checkSameType(t, Zero(ArrayOf(5, TypeOf(T(1)))).Interface(), [5]T{})
 }
 
 func TestSliceOf(t *testing.T) {
@@ -3717,26 +3482,6 @@ func TestChanOf(t *testing.T) {
 	checkSameType(t, Zero(ChanOf(BothDir, TypeOf(T1(1)))).Interface(), (chan T1)(nil))
 }
 
-func TestChanOfDir(t *testing.T) {
-	// check construction and use of type not in binary
-	type T string
-	crt := ChanOf(RecvDir, TypeOf(T("")))
-	cst := ChanOf(SendDir, TypeOf(T("")))
-
-	// check that type already in binary is found
-	type T1 int
-	checkSameType(t, Zero(ChanOf(RecvDir, TypeOf(T1(1)))).Interface(), (<-chan T1)(nil))
-	checkSameType(t, Zero(ChanOf(SendDir, TypeOf(T1(1)))).Interface(), (chan<- T1)(nil))
-
-	// check String form of ChanDir
-	if crt.ChanDir().String() != "<-chan" {
-		t.Errorf("chan dir: have %q, want %q", crt.ChanDir().String(), "<-chan")
-	}
-	if cst.ChanDir().String() != "chan<-" {
-		t.Errorf("chan dir: have %q, want %q", cst.ChanDir().String(), "chan<-")
-	}
-}
-
 func TestChanOfGC(t *testing.T) {
 	done := make(chan bool, 1)
 	go func() {
@@ -3880,67 +3625,6 @@ func TestMapOfGCValues(t *testing.T) {
 	}
 }
 
-func TestTypelinksSorted(t *testing.T) {
-	var last string
-	for i, n := range TypeLinks() {
-		if n < last {
-			t.Errorf("typelinks not sorted: %q [%d] > %q [%d]", last, i-1, n, i)
-		}
-		last = n
-	}
-}
-
-func TestFuncOf(t *testing.T) {
-	// check construction and use of type not in binary
-	type K string
-	type V float64
-
-	fn := func(args []Value) []Value {
-		if len(args) != 1 {
-			t.Errorf("args == %v, want exactly one arg", args)
-		} else if args[0].Type() != TypeOf(K("")) {
-			t.Errorf("args[0] is type %v, want %v", args[0].Type, TypeOf(K("")))
-		} else if args[0].String() != "gopher" {
-			t.Errorf("args[0] = %q, want %q", args[0].String(), "gopher")
-		}
-		return []Value{ValueOf(V(3.14))}
-	}
-	v := MakeFunc(FuncOf([]Type{TypeOf(K(""))}, []Type{TypeOf(V(0))}, false), fn)
-
-	outs := v.Call([]Value{ValueOf(K("gopher"))})
-	if len(outs) != 1 {
-		t.Fatalf("v.Call returned %v, want exactly one result", outs)
-	} else if outs[0].Type() != TypeOf(V(0)) {
-		t.Fatalf("c.Call[0] is type %v, want %v", outs[0].Type, TypeOf(V(0)))
-	}
-	f := outs[0].Float()
-	if f != 3.14 {
-		t.Errorf("constructed func returned %f, want %f", f, 3.14)
-	}
-
-	// check that types already in binary are found
-	type T1 int
-	testCases := []struct {
-		in, out  []Type
-		variadic bool
-		want     interface{}
-	}{
-		{in: []Type{TypeOf(T1(0))}, want: (func(T1))(nil)},
-		{in: []Type{TypeOf(int(0))}, want: (func(int))(nil)},
-		{in: []Type{SliceOf(TypeOf(int(0)))}, variadic: true, want: (func(...int))(nil)},
-		{in: []Type{TypeOf(int(0))}, out: []Type{TypeOf(false)}, want: (func(int) bool)(nil)},
-		{in: []Type{TypeOf(int(0))}, out: []Type{TypeOf(false), TypeOf("")}, want: (func(int) (bool, string))(nil)},
-	}
-	for _, tt := range testCases {
-		checkSameType(t, Zero(FuncOf(tt.in, tt.out, tt.variadic)).Interface(), tt.want)
-	}
-
-	// check that variadic requires last element be a slice.
-	FuncOf([]Type{TypeOf(1), TypeOf(""), SliceOf(TypeOf(false))}, nil, true)
-	shouldPanic(func() { FuncOf([]Type{TypeOf(0), TypeOf(""), TypeOf(false)}, nil, true) })
-	shouldPanic(func() { FuncOf(nil, nil, true) })
-}
-
 type B1 struct {
 	X int
 	Y int
@@ -4386,16 +4070,15 @@ func TestCallGC(t *testing.T) {
 }
 
 type funcLayoutTest struct {
-	rcvr, t                  Type
-	size, argsize, retOffset uintptr
-	stack                    []byte // pointer bitmap: 1 is pointer, 0 is scalar (or uninitialized)
-	gc                       []byte
+	rcvr, t            Type
+	argsize, retOffset uintptr
+	stack              []byte
 }
 
 var funcLayoutTests []funcLayoutTest
 
 func init() {
-	var argAlign uintptr = PtrSize
+	var argAlign = PtrSize
 	if runtime.GOARCH == "amd64p32" {
 		argAlign = 2 * PtrSize
 	}
@@ -4407,28 +4090,24 @@ func init() {
 		funcLayoutTest{
 			nil,
 			ValueOf(func(a, b string) string { return "" }).Type(),
-			6 * PtrSize,
 			4 * PtrSize,
 			4 * PtrSize,
-			[]byte{1, 0, 1},
-			[]byte{1, 0, 1, 0, 1},
+			[]byte{BitsPointer, BitsScalar, BitsPointer},
 		})
 
 	var r []byte
 	if PtrSize == 4 {
-		r = []byte{0, 0, 0, 1}
+		r = []byte{BitsScalar, BitsScalar, BitsScalar, BitsPointer}
 	} else {
-		r = []byte{0, 0, 1}
+		r = []byte{BitsScalar, BitsScalar, BitsPointer}
 	}
 	funcLayoutTests = append(funcLayoutTests,
 		funcLayoutTest{
 			nil,
 			ValueOf(func(a, b, c uint32, p *byte, d uint16) {}).Type(),
-			roundup(roundup(3*4, PtrSize)+PtrSize+2, argAlign),
 			roundup(3*4, PtrSize) + PtrSize + 2,
 			roundup(roundup(3*4, PtrSize)+PtrSize+2, argAlign),
 			r,
-			r,
 		})
 
 	funcLayoutTests = append(funcLayoutTests,
@@ -4437,9 +4116,7 @@ func init() {
 			ValueOf(func(a map[int]int, b uintptr, c interface{}) {}).Type(),
 			4 * PtrSize,
 			4 * PtrSize,
-			4 * PtrSize,
-			[]byte{1, 0, 1, 1},
-			[]byte{1, 0, 1, 1},
+			[]byte{BitsPointer, BitsScalar, BitsPointer, BitsPointer},
 		})
 
 	type S struct {
@@ -4452,65 +4129,22 @@ func init() {
 			ValueOf(func(a S) {}).Type(),
 			4 * PtrSize,
 			4 * PtrSize,
-			4 * PtrSize,
-			[]byte{0, 0, 1, 1},
-			[]byte{0, 0, 1, 1},
+			[]byte{BitsScalar, BitsScalar, BitsPointer, BitsPointer},
 		})
 
 	funcLayoutTests = append(funcLayoutTests,
 		funcLayoutTest{
 			ValueOf((*byte)(nil)).Type(),
 			ValueOf(func(a uintptr, b *int) {}).Type(),
-			roundup(3*PtrSize, argAlign),
 			3 * PtrSize,
 			roundup(3*PtrSize, argAlign),
-			[]byte{1, 0, 1},
-			[]byte{1, 0, 1},
-		})
-
-	funcLayoutTests = append(funcLayoutTests,
-		funcLayoutTest{
-			nil,
-			ValueOf(func(a uintptr) {}).Type(),
-			roundup(PtrSize, argAlign),
-			PtrSize,
-			roundup(PtrSize, argAlign),
-			[]byte{},
-			[]byte{},
-		})
-
-	funcLayoutTests = append(funcLayoutTests,
-		funcLayoutTest{
-			nil,
-			ValueOf(func() uintptr { return 0 }).Type(),
-			PtrSize,
-			0,
-			0,
-			[]byte{},
-			[]byte{},
-		})
-
-	funcLayoutTests = append(funcLayoutTests,
-		funcLayoutTest{
-			ValueOf(uintptr(0)).Type(),
-			ValueOf(func(a uintptr) {}).Type(),
-			2 * PtrSize,
-			2 * PtrSize,
-			2 * PtrSize,
-			[]byte{1},
-			[]byte{1},
-			// Note: this one is tricky, as the receiver is not a pointer.  But we
-			// pass the receiver by reference to the autogenerated pointer-receiver
-			// version of the function.
+			[]byte{BitsPointer, BitsScalar, BitsPointer},
 		})
 }
 
 func TestFuncLayout(t *testing.T) {
 	for _, lt := range funcLayoutTests {
-		typ, argsize, retOffset, stack, gc, ptrs := FuncLayout(lt.t, lt.rcvr)
-		if typ.Size() != lt.size {
-			t.Errorf("funcLayout(%v, %v).size=%d, want %d", lt.t, lt.rcvr, typ.Size(), lt.size)
-		}
+		_, argsize, retOffset, stack := FuncLayout(lt.t, lt.rcvr)
 		if argsize != lt.argsize {
 			t.Errorf("funcLayout(%v, %v).argsize=%d, want %d", lt.t, lt.rcvr, argsize, lt.argsize)
 		}
@@ -4520,258 +4154,5 @@ func TestFuncLayout(t *testing.T) {
 		if !bytes.Equal(stack, lt.stack) {
 			t.Errorf("funcLayout(%v, %v).stack=%v, want %v", lt.t, lt.rcvr, stack, lt.stack)
 		}
-		if !bytes.Equal(gc, lt.gc) {
-			t.Errorf("funcLayout(%v, %v).gc=%v, want %v", lt.t, lt.rcvr, gc, lt.gc)
-		}
-		if ptrs && len(stack) == 0 || !ptrs && len(stack) > 0 {
-			t.Errorf("funcLayout(%v, %v) pointers flag=%v, want %v", lt.t, lt.rcvr, ptrs, !ptrs)
-		}
-	}
-}
-
-func verifyGCBits(t *testing.T, typ Type, bits []byte) {
-	heapBits := GCBits(New(typ).Interface())
-	if !bytes.Equal(heapBits, bits) {
-		t.Errorf("heapBits incorrect for %v\nhave %v\nwant %v", typ, heapBits, bits)
-	}
-}
-
-func verifyGCBitsSlice(t *testing.T, typ Type, cap int, bits []byte) {
-	// Creating a slice causes the runtime to repeat a bitmap,
-	// which exercises a different path from making the compiler
-	// repeat a bitmap for a small array or executing a repeat in
-	// a GC program.
-	val := MakeSlice(typ, 0, cap)
-	data := NewAt(ArrayOf(cap, typ), unsafe.Pointer(val.Pointer()))
-	heapBits := GCBits(data.Interface())
-	// Repeat the bitmap for the slice size, trimming scalars in
-	// the last element.
-	bits = rep(cap, bits)
-	for len(bits) > 2 && bits[len(bits)-1] == 0 {
-		bits = bits[:len(bits)-1]
-	}
-	if !bytes.Equal(heapBits, bits) {
-		t.Errorf("heapBits incorrect for make(%v, 0, %v)\nhave %v\nwant %v", typ, cap, heapBits, bits)
-	}
-}
-
-func TestGCBits(t *testing.T) {
-	verifyGCBits(t, TypeOf((*byte)(nil)), []byte{1})
-
-	// Building blocks for types seen by the compiler (like [2]Xscalar).
-	// The compiler will create the type structures for the derived types,
-	// including their GC metadata.
-	type Xscalar struct{ x uintptr }
-	type Xptr struct{ x *byte }
-	type Xptrscalar struct {
-		*byte
-		uintptr
-	}
-	type Xscalarptr struct {
-		uintptr
-		*byte
-	}
-	type Xbigptrscalar struct {
-		_ [100]*byte
-		_ [100]uintptr
-	}
-
-	var Tscalar, Tint64, Tptr, Tscalarptr, Tptrscalar, Tbigptrscalar Type
-	{
-		// Building blocks for types constructed by reflect.
-		// This code is in a separate block so that code below
-		// cannot accidentally refer to these.
-		// The compiler must NOT see types derived from these
-		// (for example, [2]Scalar must NOT appear in the program),
-		// or else reflect will use it instead of having to construct one.
-		// The goal is to test the construction.
-		type Scalar struct{ x uintptr }
-		type Ptr struct{ x *byte }
-		type Ptrscalar struct {
-			*byte
-			uintptr
-		}
-		type Scalarptr struct {
-			uintptr
-			*byte
-		}
-		type Bigptrscalar struct {
-			_ [100]*byte
-			_ [100]uintptr
-		}
-		type Int64 int64
-		Tscalar = TypeOf(Scalar{})
-		Tint64 = TypeOf(Int64(0))
-		Tptr = TypeOf(Ptr{})
-		Tscalarptr = TypeOf(Scalarptr{})
-		Tptrscalar = TypeOf(Ptrscalar{})
-		Tbigptrscalar = TypeOf(Bigptrscalar{})
-	}
-
-	empty := []byte{}
-
-	verifyGCBits(t, TypeOf(Xscalar{}), empty)
-	verifyGCBits(t, Tscalar, empty)
-	verifyGCBits(t, TypeOf(Xptr{}), lit(1))
-	verifyGCBits(t, Tptr, lit(1))
-	verifyGCBits(t, TypeOf(Xscalarptr{}), lit(0, 1))
-	verifyGCBits(t, Tscalarptr, lit(0, 1))
-	verifyGCBits(t, TypeOf(Xptrscalar{}), lit(1))
-	verifyGCBits(t, Tptrscalar, lit(1))
-
-	verifyGCBits(t, TypeOf([0]Xptr{}), empty)
-	verifyGCBits(t, ArrayOf(0, Tptr), empty)
-	verifyGCBits(t, TypeOf([1]Xptrscalar{}), lit(1))
-	verifyGCBits(t, ArrayOf(1, Tptrscalar), lit(1))
-	verifyGCBits(t, TypeOf([2]Xscalar{}), empty)
-	verifyGCBits(t, ArrayOf(2, Tscalar), empty)
-	verifyGCBits(t, TypeOf([10000]Xscalar{}), empty)
-	verifyGCBits(t, ArrayOf(10000, Tscalar), empty)
-	verifyGCBits(t, TypeOf([2]Xptr{}), lit(1, 1))
-	verifyGCBits(t, ArrayOf(2, Tptr), lit(1, 1))
-	verifyGCBits(t, TypeOf([10000]Xptr{}), rep(10000, lit(1)))
-	verifyGCBits(t, ArrayOf(10000, Tptr), rep(10000, lit(1)))
-	verifyGCBits(t, TypeOf([2]Xscalarptr{}), lit(0, 1, 0, 1))
-	verifyGCBits(t, ArrayOf(2, Tscalarptr), lit(0, 1, 0, 1))
-	verifyGCBits(t, TypeOf([10000]Xscalarptr{}), rep(10000, lit(0, 1)))
-	verifyGCBits(t, ArrayOf(10000, Tscalarptr), rep(10000, lit(0, 1)))
-	verifyGCBits(t, TypeOf([2]Xptrscalar{}), lit(1, 0, 1))
-	verifyGCBits(t, ArrayOf(2, Tptrscalar), lit(1, 0, 1))
-	verifyGCBits(t, TypeOf([10000]Xptrscalar{}), rep(10000, lit(1, 0)))
-	verifyGCBits(t, ArrayOf(10000, Tptrscalar), rep(10000, lit(1, 0)))
-	verifyGCBits(t, TypeOf([1][10000]Xptrscalar{}), rep(10000, lit(1, 0)))
-	verifyGCBits(t, ArrayOf(1, ArrayOf(10000, Tptrscalar)), rep(10000, lit(1, 0)))
-	verifyGCBits(t, TypeOf([2][10000]Xptrscalar{}), rep(2*10000, lit(1, 0)))
-	verifyGCBits(t, ArrayOf(2, ArrayOf(10000, Tptrscalar)), rep(2*10000, lit(1, 0)))
-	verifyGCBits(t, TypeOf([4]Xbigptrscalar{}), join(rep(3, join(rep(100, lit(1)), rep(100, lit(0)))), rep(100, lit(1))))
-	verifyGCBits(t, ArrayOf(4, Tbigptrscalar), join(rep(3, join(rep(100, lit(1)), rep(100, lit(0)))), rep(100, lit(1))))
-
-	verifyGCBitsSlice(t, TypeOf([]Xptr{}), 0, empty)
-	verifyGCBitsSlice(t, SliceOf(Tptr), 0, empty)
-	verifyGCBitsSlice(t, TypeOf([]Xptrscalar{}), 1, lit(1))
-	verifyGCBitsSlice(t, SliceOf(Tptrscalar), 1, lit(1))
-	verifyGCBitsSlice(t, TypeOf([]Xscalar{}), 2, lit(0))
-	verifyGCBitsSlice(t, SliceOf(Tscalar), 2, lit(0))
-	verifyGCBitsSlice(t, TypeOf([]Xscalar{}), 10000, lit(0))
-	verifyGCBitsSlice(t, SliceOf(Tscalar), 10000, lit(0))
-	verifyGCBitsSlice(t, TypeOf([]Xptr{}), 2, lit(1))
-	verifyGCBitsSlice(t, SliceOf(Tptr), 2, lit(1))
-	verifyGCBitsSlice(t, TypeOf([]Xptr{}), 10000, lit(1))
-	verifyGCBitsSlice(t, SliceOf(Tptr), 10000, lit(1))
-	verifyGCBitsSlice(t, TypeOf([]Xscalarptr{}), 2, lit(0, 1))
-	verifyGCBitsSlice(t, SliceOf(Tscalarptr), 2, lit(0, 1))
-	verifyGCBitsSlice(t, TypeOf([]Xscalarptr{}), 10000, lit(0, 1))
-	verifyGCBitsSlice(t, SliceOf(Tscalarptr), 10000, lit(0, 1))
-	verifyGCBitsSlice(t, TypeOf([]Xptrscalar{}), 2, lit(1, 0))
-	verifyGCBitsSlice(t, SliceOf(Tptrscalar), 2, lit(1, 0))
-	verifyGCBitsSlice(t, TypeOf([]Xptrscalar{}), 10000, lit(1, 0))
-	verifyGCBitsSlice(t, SliceOf(Tptrscalar), 10000, lit(1, 0))
-	verifyGCBitsSlice(t, TypeOf([][10000]Xptrscalar{}), 1, rep(10000, lit(1, 0)))
-	verifyGCBitsSlice(t, SliceOf(ArrayOf(10000, Tptrscalar)), 1, rep(10000, lit(1, 0)))
-	verifyGCBitsSlice(t, TypeOf([][10000]Xptrscalar{}), 2, rep(10000, lit(1, 0)))
-	verifyGCBitsSlice(t, SliceOf(ArrayOf(10000, Tptrscalar)), 2, rep(10000, lit(1, 0)))
-	verifyGCBitsSlice(t, TypeOf([]Xbigptrscalar{}), 4, join(rep(100, lit(1)), rep(100, lit(0))))
-	verifyGCBitsSlice(t, SliceOf(Tbigptrscalar), 4, join(rep(100, lit(1)), rep(100, lit(0))))
-
-	verifyGCBits(t, TypeOf((chan [100]Xscalar)(nil)), lit(1))
-	verifyGCBits(t, ChanOf(BothDir, ArrayOf(100, Tscalar)), lit(1))
-
-	verifyGCBits(t, TypeOf((func([10000]Xscalarptr))(nil)), lit(1))
-	verifyGCBits(t, FuncOf([]Type{ArrayOf(10000, Tscalarptr)}, nil, false), lit(1))
-
-	verifyGCBits(t, TypeOf((map[[10000]Xscalarptr]Xscalar)(nil)), lit(1))
-	verifyGCBits(t, MapOf(ArrayOf(10000, Tscalarptr), Tscalar), lit(1))
-
-	verifyGCBits(t, TypeOf((*[10000]Xscalar)(nil)), lit(1))
-	verifyGCBits(t, PtrTo(ArrayOf(10000, Tscalar)), lit(1))
-
-	verifyGCBits(t, TypeOf(([][10000]Xscalar)(nil)), lit(1))
-	verifyGCBits(t, SliceOf(ArrayOf(10000, Tscalar)), lit(1))
-
-	hdr := make([]byte, 8/PtrSize)
-
-	verifyMapBucket := func(t *testing.T, k, e Type, m interface{}, want []byte) {
-		verifyGCBits(t, MapBucketOf(k, e), want)
-		verifyGCBits(t, CachedBucketOf(TypeOf(m)), want)
-	}
-	verifyMapBucket(t,
-		Tscalar, Tptr,
-		map[Xscalar]Xptr(nil),
-		join(hdr, rep(8, lit(0)), rep(8, lit(1)), lit(1)))
-	verifyMapBucket(t,
-		Tscalarptr, Tptr,
-		map[Xscalarptr]Xptr(nil),
-		join(hdr, rep(8, lit(0, 1)), rep(8, lit(1)), lit(1)))
-	verifyMapBucket(t, Tint64, Tptr,
-		map[int64]Xptr(nil),
-		join(hdr, rep(8, rep(8/PtrSize, lit(0))), rep(8, lit(1)), naclpad(), lit(1)))
-	verifyMapBucket(t,
-		Tscalar, Tscalar,
-		map[Xscalar]Xscalar(nil),
-		empty)
-	verifyMapBucket(t,
-		ArrayOf(2, Tscalarptr), ArrayOf(3, Tptrscalar),
-		map[[2]Xscalarptr][3]Xptrscalar(nil),
-		join(hdr, rep(8*2, lit(0, 1)), rep(8*3, lit(1, 0)), lit(1)))
-	verifyMapBucket(t,
-		ArrayOf(64/PtrSize, Tscalarptr), ArrayOf(64/PtrSize, Tptrscalar),
-		map[[64 / PtrSize]Xscalarptr][64 / PtrSize]Xptrscalar(nil),
-		join(hdr, rep(8*64/PtrSize, lit(0, 1)), rep(8*64/PtrSize, lit(1, 0)), lit(1)))
-	verifyMapBucket(t,
-		ArrayOf(64/PtrSize+1, Tscalarptr), ArrayOf(64/PtrSize, Tptrscalar),
-		map[[64/PtrSize + 1]Xscalarptr][64 / PtrSize]Xptrscalar(nil),
-		join(hdr, rep(8, lit(1)), rep(8*64/PtrSize, lit(1, 0)), lit(1)))
-	verifyMapBucket(t,
-		ArrayOf(64/PtrSize, Tscalarptr), ArrayOf(64/PtrSize+1, Tptrscalar),
-		map[[64 / PtrSize]Xscalarptr][64/PtrSize + 1]Xptrscalar(nil),
-		join(hdr, rep(8*64/PtrSize, lit(0, 1)), rep(8, lit(1)), lit(1)))
-	verifyMapBucket(t,
-		ArrayOf(64/PtrSize+1, Tscalarptr), ArrayOf(64/PtrSize+1, Tptrscalar),
-		map[[64/PtrSize + 1]Xscalarptr][64/PtrSize + 1]Xptrscalar(nil),
-		join(hdr, rep(8, lit(1)), rep(8, lit(1)), lit(1)))
-}
-
-func naclpad() []byte {
-	if runtime.GOARCH == "amd64p32" {
-		return lit(0)
-	}
-	return nil
-}
-
-func rep(n int, b []byte) []byte { return bytes.Repeat(b, n) }
-func join(b ...[]byte) []byte    { return bytes.Join(b, nil) }
-func lit(x ...byte) []byte       { return x }
-
-func TestTypeOfTypeOf(t *testing.T) {
-	// Check that all the type constructors return concrete *rtype implementations.
-	// It's difficult to test directly because the reflect package is only at arm's length.
-	// The easiest thing to do is just call a function that crashes if it doesn't get an *rtype.
-	check := func(name string, typ Type) {
-		if underlying := TypeOf(typ).String(); underlying != "*reflect.rtype" {
-			t.Errorf("%v returned %v, not *reflect.rtype", name, underlying)
-		}
-	}
-
-	type T struct{ int }
-	check("TypeOf", TypeOf(T{}))
-
-	check("ArrayOf", ArrayOf(10, TypeOf(T{})))
-	check("ChanOf", ChanOf(BothDir, TypeOf(T{})))
-	check("FuncOf", FuncOf([]Type{TypeOf(T{})}, nil, false))
-	check("MapOf", MapOf(TypeOf(T{}), TypeOf(T{})))
-	check("PtrTo", PtrTo(TypeOf(T{})))
-	check("SliceOf", SliceOf(TypeOf(T{})))
-}
-
-type XM struct{}
-
-func (*XM) String() string { return "" }
-
-func TestPtrToMethods(t *testing.T) {
-	var y struct{ XM }
-	yp := New(TypeOf(y)).Interface()
-	_, ok := yp.(fmt.Stringer)
-	if !ok {
-		t.Fatal("does not implement Stringer, but should")
 	}
 }
diff --git a/src/reflect/example_test.go b/src/reflect/example_test.go
index 8ebf976..cca28ee 100644
--- a/src/reflect/example_test.go
+++ b/src/reflect/example_test.go
@@ -6,8 +6,6 @@ package reflect_test
 
 import (
 	"fmt"
-	"io"
-	"os"
 	"reflect"
 )
 
@@ -66,16 +64,3 @@ func ExampleStructTag() {
 	// Output:
 	// blue gopher
 }
-
-func ExampleTypeOf() {
-	// As interface types are only used for static typing, a
-	// common idiom to find the reflection Type for an interface
-	// type Foo is to use a *Foo value.
-	writerType := reflect.TypeOf((*io.Writer)(nil)).Elem()
-
-	fileType := reflect.TypeOf((*os.File)(nil))
-	fmt.Println(fileType.Implements(writerType))
-
-	// Output:
-	// true
-}
diff --git a/src/reflect/export_test.go b/src/reflect/export_test.go
index 0b9d0fd..caaf51a 100644
--- a/src/reflect/export_test.go
+++ b/src/reflect/export_test.go
@@ -4,8 +4,6 @@
 
 package reflect
 
-import "unsafe"
-
 // MakeRO returns a copy of v with the read-only flag set.
 func MakeRO(v Value) Value {
 	v.flag |= flagRO
@@ -17,56 +15,24 @@ func IsRO(v Value) bool {
 	return v.flag&flagRO != 0
 }
 
+var ArrayOf = arrayOf
 var CallGC = &callGC
 
 const PtrSize = ptrSize
+const BitsPointer = bitsPointer
+const BitsScalar = bitsScalar
 
-func FuncLayout(t Type, rcvr Type) (frametype Type, argSize, retOffset uintptr, stack []byte, gc []byte, ptrs bool) {
+func FuncLayout(t Type, rcvr Type) (frametype Type, argSize, retOffset uintptr, stack []byte) {
 	var ft *rtype
 	var s *bitVector
 	if rcvr != nil {
-		ft, argSize, retOffset, s, _ = funcLayout(t.(*rtype), rcvr.(*rtype))
+		ft, argSize, retOffset, s = funcLayout(t.(*rtype), rcvr.(*rtype))
 	} else {
-		ft, argSize, retOffset, s, _ = funcLayout(t.(*rtype), nil)
+		ft, argSize, retOffset, s = funcLayout(t.(*rtype), nil)
 	}
 	frametype = ft
-	for i := uint32(0); i < s.n; i++ {
-		stack = append(stack, s.data[i/8]>>(i%8)&1)
-	}
-	if ft.kind&kindGCProg != 0 {
-		panic("can't handle gc programs")
+	for i := uint32(0); i < s.n; i += 2 {
+		stack = append(stack, s.data[i/8]>>(i%8)&3)
 	}
-	gcdata := (*[1000]byte)(unsafe.Pointer(ft.gcdata))
-	for i := uintptr(0); i < ft.ptrdata/ptrSize; i++ {
-		gc = append(gc, gcdata[i/8]>>(i%8)&1)
-	}
-	ptrs = ft.kind&kindNoPointers == 0
 	return
 }
-
-func TypeLinks() []string {
-	var r []string
-	for _, m := range typelinks() {
-		for _, t := range m {
-			r = append(r, *t.string)
-		}
-	}
-	return r
-}
-
-var GCBits = gcbits
-
-func gcbits(interface{}) []byte // provided by runtime
-
-func MapBucketOf(x, y Type) Type {
-	return bucketOf(x.(*rtype), y.(*rtype))
-}
-
-func CachedBucketOf(m Type) Type {
-	t := m.(*rtype)
-	if Kind(t.kind&kindMask) != Map {
-		panic("not map")
-	}
-	tt := (*mapType)(unsafe.Pointer(t))
-	return tt.bucket
-}
diff --git a/src/reflect/makefunc.go b/src/reflect/makefunc.go
index 032057d..d89f7f6 100644
--- a/src/reflect/makefunc.go
+++ b/src/reflect/makefunc.go
@@ -51,12 +51,12 @@ func MakeFunc(typ Type, fn func(args []Value) (results []Value)) Value {
 
 	// Indirect Go func value (dummy) to obtain
 	// actual code address. (A Go func value is a pointer
-	// to a C function pointer. https://golang.org/s/go11func.)
+	// to a C function pointer. http://golang.org/s/go11func.)
 	dummy := makeFuncStub
 	code := **(**uintptr)(unsafe.Pointer(&dummy))
 
 	// makeFuncImpl contains a stack map for use by the runtime
-	_, _, _, stack, _ := funcLayout(t, nil)
+	_, _, _, stack := funcLayout(t, nil)
 
 	impl := &makeFuncImpl{code: code, stack: stack, typ: ftyp, fn: fn}
 
@@ -99,12 +99,12 @@ func makeMethodValue(op string, v Value) Value {
 
 	// Indirect Go func value (dummy) to obtain
 	// actual code address. (A Go func value is a pointer
-	// to a C function pointer. https://golang.org/s/go11func.)
+	// to a C function pointer. http://golang.org/s/go11func.)
 	dummy := methodValueCall
 	code := **(**uintptr)(unsafe.Pointer(&dummy))
 
 	// methodValue contains a stack map for use by the runtime
-	_, _, _, stack, _ := funcLayout(funcType, nil)
+	_, _, _, stack := funcLayout(funcType, nil)
 
 	fv := &methodValue{
 		fn:     code,
diff --git a/src/reflect/type.go b/src/reflect/type.go
index e20e5cf..6fd6894 100644
--- a/src/reflect/type.go
+++ b/src/reflect/type.go
@@ -12,7 +12,7 @@
 // for that type.
 //
 // See "The Laws of Reflection" for an introduction to reflection in Go:
-// https://golang.org/doc/articles/laws_of_reflection.html
+// http://golang.org/doc/articles/laws_of_reflection.html
 package reflect
 
 import (
@@ -87,16 +87,16 @@ type Type interface {
 	// Kind returns the specific kind of this type.
 	Kind() Kind
 
-	// Implements reports whether the type implements the interface type u.
+	// Implements returns true if the type implements the interface type u.
 	Implements(u Type) bool
 
-	// AssignableTo reports whether a value of the type is assignable to type u.
+	// AssignableTo returns true if a value of the type is assignable to type u.
 	AssignableTo(u Type) bool
 
-	// ConvertibleTo reports whether a value of the type is convertible to type u.
+	// ConvertibleTo returns true if a value of the type is convertible to type u.
 	ConvertibleTo(u Type) bool
 
-	// Comparable reports whether values of this type are comparable.
+	// Comparable returns true if values of this type are comparable.
 	Comparable() bool
 
 	// Methods applicable only to some types, depending on Kind.
@@ -120,7 +120,7 @@ type Type interface {
 	// It panics if the type's Kind is not Chan.
 	ChanDir() ChanDir
 
-	// IsVariadic reports whether a function type's final input parameter
+	// IsVariadic returns true if a function type's final input parameter
 	// is a "..." parameter.  If so, t.In(t.NumIn() - 1) returns the parameter's
 	// implicit actual type []T.
 	//
@@ -201,9 +201,9 @@ type Type interface {
 // See golang.org/issue/4876 for more details.
 
 /*
- * These data structures are known to the compiler (../../cmd/internal/gc/reflect.go).
+ * These data structures are known to the compiler (../../cmd/gc/reflect.c).
  * A few are known to ../runtime/type.go to convey to debuggers.
- * They are also known to ../runtime/type.go.
+ * They are also known to ../runtime/type.h.
  */
 
 // A Kind represents the specific kind of type that a Type represents.
@@ -246,28 +246,26 @@ const (
 // so that code cannot convert from, say, *arrayType to *ptrType.
 type rtype struct {
 	size          uintptr
-	ptrdata       uintptr
-	hash          uint32         // hash of type; avoids computation in hash tables
-	_             uint8          // unused/padding
-	align         uint8          // alignment of variable with this type
-	fieldAlign    uint8          // alignment of struct field with this type
-	kind          uint8          // enumeration for C
-	alg           *typeAlg       // algorithm table
-	gcdata        *byte          // garbage collection data
-	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
-}
-
-// a copy of runtime.typeAlg
+	hash          uint32            // hash of type; avoids computation in hash tables
+	_             uint8             // unused/padding
+	align         uint8             // alignment of variable with this type
+	fieldAlign    uint8             // alignment of struct field with this type
+	kind          uint8             // enumeration for C
+	alg           *typeAlg          // algorithm table (../runtime/runtime.h:/Alg)
+	gc            [2]unsafe.Pointer // garbage collection data
+	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
+}
+
 type typeAlg struct {
 	// function for hashing objects of this type
-	// (ptr to object, seed) -> hash
-	hash func(unsafe.Pointer, uintptr) uintptr
+	// (ptr to object, size, seed) -> hash
+	hash func(unsafe.Pointer, uintptr, uintptr) uintptr
 	// function for comparing objects of this type
-	// (ptr to object A, ptr to object B) -> ==?
-	equal func(unsafe.Pointer, unsafe.Pointer) bool
+	// (ptr to object A, ptr to object B, size) -> ==?
+	equal func(unsafe.Pointer, unsafe.Pointer, uintptr) bool
 }
 
 // Method on non-interface type
@@ -347,7 +345,6 @@ type mapType struct {
 	valuesize     uint8  // size of value slot
 	indirectvalue uint8  // store ptr to value instead of value itself
 	bucketsize    uint16 // size of bucket
-	reflexivekey  bool   // true if k==k for all keys
 }
 
 // ptrType represents a pointer type.
@@ -389,7 +386,7 @@ type Method struct {
 	// method name.  It is empty for upper case (exported) method names.
 	// The combination of PkgPath and Name uniquely identifies a method
 	// in a method set.
-	// See https://golang.org/ref/spec#Uniqueness_of_identifiers
+	// See http://golang.org/ref/spec#Uniqueness_of_identifiers
 	Name    string
 	PkgPath string
 
@@ -527,7 +524,7 @@ func (t *uncommonType) MethodByName(name string) (m Method, ok bool) {
 	return
 }
 
-// TODO(rsc): gc supplies these, but they are not
+// TODO(rsc): 6g supplies these, but they are not
 // as efficient as they could be: they have commonType
 // as the receiver instead of *rtype.
 func (t *rtype) NumMethod() int {
@@ -737,7 +734,7 @@ type StructField struct {
 	// Name is the field name.
 	// PkgPath is the package path that qualifies a lower case (unexported)
 	// field name.  It is empty for upper case (exported) field names.
-	// See https://golang.org/ref/spec#Uniqueness_of_identifiers
+	// See http://golang.org/ref/spec#Uniqueness_of_identifiers
 	Name    string
 	PkgPath string
 
@@ -763,11 +760,8 @@ type StructTag string
 // If the tag does not have the conventional format, the value
 // returned by Get is unspecified.
 func (tag StructTag) Get(key string) string {
-	// When modifying this code, also update the validateStructTag code
-	// in golang.org/x/tools/cmd/vet/structtag.go.
-
 	for tag != "" {
-		// Skip leading space.
+		// skip leading space
 		i := 0
 		for i < len(tag) && tag[i] == ' ' {
 			i++
@@ -777,21 +771,19 @@ func (tag StructTag) Get(key string) string {
 			break
 		}
 
-		// Scan to colon. A space, a quote or a control character is a syntax error.
-		// Strictly speaking, control chars include the range [0x7f, 0x9f], not just
-		// [0x00, 0x1f], but in practice, we ignore the multi-byte control characters
-		// as it is simpler to inspect the tag's bytes than the tag's runes.
+		// scan to colon.
+		// a space or a quote is a syntax error
 		i = 0
-		for i < len(tag) && tag[i] > ' ' && tag[i] != ':' && tag[i] != '"' && tag[i] != 0x7f {
+		for i < len(tag) && tag[i] != ' ' && tag[i] != ':' && tag[i] != '"' {
 			i++
 		}
-		if i == 0 || i+1 >= len(tag) || tag[i] != ':' || tag[i+1] != '"' {
+		if i+1 >= len(tag) || tag[i] != ':' || tag[i+1] != '"' {
 			break
 		}
 		name := string(tag[:i])
 		tag = tag[i+1:]
 
-		// Scan quoted string to find value.
+		// scan quoted string to find value
 		i = 1
 		for i < len(tag) && tag[i] != '"' {
 			if tag[i] == '\\' {
@@ -806,10 +798,7 @@ func (tag StructTag) Get(key string) string {
 		tag = tag[i+1:]
 
 		if key == name {
-			value, err := strconv.Unquote(qvalue)
-			if err != nil {
-				break
-			}
+			value, _ := strconv.Unquote(qvalue)
 			return value
 		}
 	}
@@ -1010,8 +999,8 @@ func (t *structType) FieldByName(name string) (f StructField, present bool) {
 	return t.FieldByNameFunc(func(s string) bool { return s == name })
 }
 
-// TypeOf returns the reflection Type that represents the dynamic type of i.
-// If i is a nil interface value, TypeOf returns nil.
+// TypeOf returns the reflection Type of the value in the interface{}.
+// TypeOf(nil) returns nil.
 func TypeOf(i interface{}) Type {
 	eface := *(*emptyInterface)(unsafe.Pointer(&i))
 	return toType(eface.typ)
@@ -1058,17 +1047,6 @@ func (t *rtype) ptrTo() *rtype {
 		return &p.rtype
 	}
 
-	// Look in known types.
-	s := "*" + *t.string
-	for _, tt := range typesByString(s) {
-		p = (*ptrType)(unsafe.Pointer(tt))
-		if p.elem == t {
-			ptrMap.m[t] = p
-			ptrMap.Unlock()
-			return &p.rtype
-		}
-	}
-
 	// Create a new ptrType starting with the description
 	// of an *unsafe.Pointer.
 	p = new(ptrType)
@@ -1076,6 +1054,7 @@ func (t *rtype) ptrTo() *rtype {
 	prototype := *(**ptrType)(unsafe.Pointer(&iptr))
 	*p = *prototype
 
+	s := "*" + *t.string
 	p.string = &s
 
 	// For the type structures linked into the binary, the
@@ -1087,6 +1066,7 @@ func (t *rtype) ptrTo() *rtype {
 
 	p.uncommonType = nil
 	p.ptrToThis = nil
+	p.zero = unsafe.Pointer(&make([]byte, p.size)[0])
 	p.elem = t
 
 	ptrMap.m[t] = p
@@ -1132,7 +1112,7 @@ func (t *rtype) Comparable() bool {
 	return t.alg != nil && t.alg.equal != nil
 }
 
-// implements reports whether the type V implements the interface type T.
+// implements returns true if the type V implements the interface type T.
 func implements(T, V *rtype) bool {
 	if T.Kind() != Interface {
 		return false
@@ -1153,14 +1133,14 @@ func implements(T, V *rtype) bool {
 	// methods along the way, or else V does not implement T.
 	// This lets us run the scan in overall linear time instead of
 	// the quadratic time  a naive search would require.
-	// See also ../runtime/iface.go.
+	// See also ../runtime/iface.c.
 	if V.Kind() == Interface {
 		v := (*interfaceType)(unsafe.Pointer(V))
 		i := 0
 		for j := 0; j < len(v.methods); j++ {
 			tm := &t.methods[i]
 			vm := &v.methods[j]
-			if *vm.name == *tm.name && vm.pkgPath == tm.pkgPath && vm.typ == tm.typ {
+			if vm.name == tm.name && vm.pkgPath == tm.pkgPath && vm.typ == tm.typ {
 				if i++; i >= len(t.methods) {
 					return true
 				}
@@ -1177,7 +1157,7 @@ func implements(T, V *rtype) bool {
 	for j := 0; j < len(v.methods); j++ {
 		tm := &t.methods[i]
 		vm := &v.methods[j]
-		if *vm.name == *tm.name && vm.pkgPath == tm.pkgPath && vm.mtyp == tm.typ {
+		if vm.name == tm.name && vm.pkgPath == tm.pkgPath && vm.mtyp == tm.typ {
 			if i++; i >= len(t.methods) {
 				return true
 			}
@@ -1186,9 +1166,9 @@ func implements(T, V *rtype) bool {
 	return false
 }
 
-// directlyAssignable reports whether a value x of type V can be directly
+// directlyAssignable returns true if a value x of type V can be directly
 // assigned (using memmove) to a value of type T.
-// https://golang.org/doc/go_spec.html#Assignability
+// http://golang.org/doc/go_spec.html#Assignability
 // Ignoring the interface rules (implemented elsewhere)
 // and the ideal constant rules (no ideal constants at run time).
 func directlyAssignable(T, V *rtype) bool {
@@ -1311,48 +1291,39 @@ func haveIdenticalUnderlyingType(T, V *rtype) bool {
 // there can be more than one with a given string.
 // Only types we might want to look up are included:
 // channels, maps, slices, and arrays.
-func typelinks() [][]*rtype
+func typelinks() []*rtype
 
 // typesByString returns the subslice of typelinks() whose elements have
 // the given string representation.
 // It may be empty (no known types with that string) or may have
 // multiple elements (multiple types with that string).
 func typesByString(s string) []*rtype {
-	typs := typelinks()
-	var ret []*rtype
-
-	for _, typ := range typs {
-		// We are looking for the first index i where the string becomes >= s.
-		// This is a copy of sort.Search, with f(h) replaced by (*typ[h].string >= s).
-		i, j := 0, len(typ)
-		for i < j {
-			h := i + (j-i)/2 // avoid overflow when computing h
-			// i ≤ h < j
-			if !(*typ[h].string >= s) {
-				i = h + 1 // preserves f(i-1) == false
-			} else {
-				j = h // preserves f(j) == true
-			}
-		}
-		// i == j, f(i-1) == false, and f(j) (= f(i)) == true  =>  answer is i.
-
-		// Having found the first, linear scan forward to find the last.
-		// We could do a second binary search, but the caller is going
-		// to do a linear scan anyway.
-		j = i
-		for j < len(typ) && *typ[j].string == s {
-			j++
+	typ := typelinks()
+
+	// We are looking for the first index i where the string becomes >= s.
+	// This is a copy of sort.Search, with f(h) replaced by (*typ[h].string >= s).
+	i, j := 0, len(typ)
+	for i < j {
+		h := i + (j-i)/2 // avoid overflow when computing h
+		// i ≤ h < j
+		if !(*typ[h].string >= s) {
+			i = h + 1 // preserves f(i-1) == false
+		} else {
+			j = h // preserves f(j) == true
 		}
+	}
+	// i == j, f(i-1) == false, and f(j) (= f(i)) == true  =>  answer is i.
 
-		if j > i {
-			if ret == nil {
-				ret = typ[i:j:j]
-			} else {
-				ret = append(ret, typ[i:j]...)
-			}
-		}
+	// Having found the first, linear scan forward to find the last.
+	// We could do a second binary search, but the caller is going
+	// to do a linear scan anyway.
+	j = i
+	for j < len(typ) && *typ[j].string == s {
+		j++
 	}
-	return ret
+
+	// This slice will be empty if the string is not found.
+	return typ[i:j]
 }
 
 // The lookupCache caches ChanOf, MapOf, and SliceOf lookups.
@@ -1406,14 +1377,6 @@ func cachePut(k cacheKey, t *rtype) Type {
 	return t
 }
 
-// The funcLookupCache caches FuncOf lookups.
-// FuncOf does not share the common lookupCache since cacheKey is not
-// sufficient to represent functions unambiguously.
-var funcLookupCache struct {
-	sync.RWMutex
-	m map[uint32][]*rtype // keyed by hash calculated in FuncOf
-}
-
 // ChanOf returns the channel type with the given direction and element type.
 // For example, if t represents int, ChanOf(RecvDir, t) represents <-chan int.
 //
@@ -1460,12 +1423,12 @@ func ChanOf(dir ChanDir, t Type) Type {
 	prototype := *(**chanType)(unsafe.Pointer(&ichan))
 	ch := new(chanType)
 	*ch = *prototype
-	ch.dir = uintptr(dir)
 	ch.string = &s
 	ch.hash = fnv1(typ.hash, 'c', byte(dir))
 	ch.elem = typ
 	ch.uncommonType = nil
 	ch.ptrToThis = nil
+	ch.zero = unsafe.Pointer(&make([]byte, ch.size)[0])
 
 	return cachePut(ckey, &ch.rtype)
 }
@@ -1503,8 +1466,9 @@ func MapOf(key, elem Type) Type {
 
 	// Make a map type.
 	var imap interface{} = (map[unsafe.Pointer]unsafe.Pointer)(nil)
+	prototype := *(**mapType)(unsafe.Pointer(&imap))
 	mt := new(mapType)
-	*mt = **(**mapType)(unsafe.Pointer(&imap))
+	*mt = *prototype
 	mt.string = &s
 	mt.hash = fnv1(etyp.hash, 'm', byte(ktyp.hash>>24), byte(ktyp.hash>>16), byte(ktyp.hash>>8), byte(ktyp.hash))
 	mt.key = ktyp
@@ -1525,256 +1489,162 @@ func MapOf(key, elem Type) Type {
 		mt.indirectvalue = 0
 	}
 	mt.bucketsize = uint16(mt.bucket.size)
-	mt.reflexivekey = isReflexive(ktyp)
 	mt.uncommonType = nil
 	mt.ptrToThis = nil
+	mt.zero = unsafe.Pointer(&make([]byte, mt.size)[0])
 
 	return cachePut(ckey, &mt.rtype)
 }
 
-// FuncOf returns the function type with the given argument and result types.
-// For example if k represents int and e represents string,
-// FuncOf([]Type{k}, []Type{e}, false) represents func(int) string.
-//
-// The variadic argument controls whether the function is variadic. FuncOf
-// panics if the in[len(in)-1] does not represent a slice and variadic is
-// true.
-func FuncOf(in, out []Type, variadic bool) Type {
-	if variadic && (len(in) == 0 || in[len(in)-1].Kind() != Slice) {
-		panic("reflect.FuncOf: last arg of variadic func must be slice")
-	}
-
-	// Make a func type.
-	var ifunc interface{} = (func())(nil)
-	prototype := *(**funcType)(unsafe.Pointer(&ifunc))
-	ft := new(funcType)
-	*ft = *prototype
-
-	// Build a hash and minimally populate ft.
-	var hash uint32
-	var fin, fout []*rtype
-	for _, in := range in {
-		t := in.(*rtype)
-		fin = append(fin, t)
-		hash = fnv1(hash, byte(t.hash>>24), byte(t.hash>>16), byte(t.hash>>8), byte(t.hash))
-	}
-	if variadic {
-		hash = fnv1(hash, 'v')
-	}
-	hash = fnv1(hash, '.')
-	for _, out := range out {
-		t := out.(*rtype)
-		fout = append(fout, t)
-		hash = fnv1(hash, byte(t.hash>>24), byte(t.hash>>16), byte(t.hash>>8), byte(t.hash))
-	}
-	ft.hash = hash
-	ft.in = fin
-	ft.out = fout
-	ft.dotdotdot = variadic
+// gcProg is a helper type for generatation of GC pointer info.
+type gcProg struct {
+	gc     []byte
+	size   uintptr // size of type in bytes
+	hasPtr bool
+}
 
-	// Look in cache.
-	funcLookupCache.RLock()
-	for _, t := range funcLookupCache.m[hash] {
-		if haveIdenticalUnderlyingType(&ft.rtype, t) {
-			funcLookupCache.RUnlock()
-			return t
-		}
-	}
-	funcLookupCache.RUnlock()
+func (gc *gcProg) append(v byte) {
+	gc.align(unsafe.Sizeof(uintptr(0)))
+	gc.appendWord(v)
+}
 
-	// Not in cache, lock and retry.
-	funcLookupCache.Lock()
-	defer funcLookupCache.Unlock()
-	if funcLookupCache.m == nil {
-		funcLookupCache.m = make(map[uint32][]*rtype)
+// Appends t's type info to the current program.
+func (gc *gcProg) appendProg(t *rtype) {
+	gc.align(uintptr(t.align))
+	if !t.pointers() {
+		gc.size += t.size
+		return
 	}
-	for _, t := range funcLookupCache.m[hash] {
-		if haveIdenticalUnderlyingType(&ft.rtype, t) {
-			return t
+	switch t.Kind() {
+	default:
+		panic("reflect: non-pointer type marked as having pointers")
+	case Ptr, UnsafePointer, Chan, Func, Map:
+		gc.appendWord(bitsPointer)
+	case Slice:
+		gc.appendWord(bitsPointer)
+		gc.appendWord(bitsScalar)
+		gc.appendWord(bitsScalar)
+	case String:
+		gc.appendWord(bitsPointer)
+		gc.appendWord(bitsScalar)
+	case Array:
+		c := t.Len()
+		e := t.Elem().common()
+		for i := 0; i < c; i++ {
+			gc.appendProg(e)
 		}
-	}
-
-	// Look in known types for the same string representation.
-	str := funcStr(ft)
-	for _, tt := range typesByString(str) {
-		if haveIdenticalUnderlyingType(&ft.rtype, tt) {
-			funcLookupCache.m[hash] = append(funcLookupCache.m[hash], tt)
-			return tt
+	case Interface:
+		gc.appendWord(bitsMultiWord)
+		if t.NumMethod() == 0 {
+			gc.appendWord(bitsEface)
+		} else {
+			gc.appendWord(bitsIface)
 		}
+	case Struct:
+		c := t.NumField()
+		for i := 0; i < c; i++ {
+			gc.appendProg(t.Field(i).Type.common())
+		}
+		gc.align(uintptr(t.align))
 	}
-
-	// Populate the remaining fields of ft and store in cache.
-	ft.string = &str
-	ft.uncommonType = nil
-	ft.ptrToThis = nil
-	funcLookupCache.m[hash] = append(funcLookupCache.m[hash], &ft.rtype)
-
-	return &ft.rtype
 }
 
-// funcStr builds a string representation of a funcType.
-func funcStr(ft *funcType) string {
-	repr := make([]byte, 0, 64)
-	repr = append(repr, "func("...)
-	for i, t := range ft.in {
-		if i > 0 {
-			repr = append(repr, ", "...)
-		}
-		if ft.dotdotdot && i == len(ft.in)-1 {
-			repr = append(repr, "..."...)
-			repr = append(repr, *(*sliceType)(unsafe.Pointer(t)).elem.string...)
-		} else {
-			repr = append(repr, *t.string...)
-		}
-	}
-	repr = append(repr, ')')
-	if l := len(ft.out); l == 1 {
-		repr = append(repr, ' ')
-	} else if l > 1 {
-		repr = append(repr, " ("...)
+func (gc *gcProg) appendWord(v byte) {
+	ptrsize := unsafe.Sizeof(uintptr(0))
+	if gc.size%ptrsize != 0 {
+		panic("reflect: unaligned GC program")
 	}
-	for i, t := range ft.out {
-		if i > 0 {
-			repr = append(repr, ", "...)
-		}
-		repr = append(repr, *t.string...)
+	nptr := gc.size / ptrsize
+	for uintptr(len(gc.gc)) < nptr/2+1 {
+		gc.gc = append(gc.gc, 0x44) // BitsScalar
 	}
-	if len(ft.out) > 1 {
-		repr = append(repr, ')')
+	gc.gc[nptr/2] &= ^(3 << ((nptr%2)*4 + 2))
+	gc.gc[nptr/2] |= v << ((nptr%2)*4 + 2)
+	gc.size += ptrsize
+	if v == bitsPointer {
+		gc.hasPtr = true
 	}
-	return string(repr)
 }
 
-// isReflexive reports whether the == operation on the type is reflexive.
-// That is, x == x for all values x of type t.
-func isReflexive(t *rtype) bool {
-	switch t.Kind() {
-	case Bool, Int, Int8, Int16, Int32, Int64, Uint, Uint8, Uint16, Uint32, Uint64, Uintptr, Chan, Ptr, String, UnsafePointer:
-		return true
-	case Float32, Float64, Complex64, Complex128, Interface:
-		return false
-	case Array:
-		tt := (*arrayType)(unsafe.Pointer(t))
-		return isReflexive(tt.elem)
-	case Struct:
-		tt := (*structType)(unsafe.Pointer(t))
-		for _, f := range tt.fields {
-			if !isReflexive(f.typ) {
-				return false
-			}
+func (gc *gcProg) finalize() (unsafe.Pointer, bool) {
+	if gc.size == 0 {
+		return nil, false
+	}
+	ptrsize := unsafe.Sizeof(uintptr(0))
+	gc.align(ptrsize)
+	nptr := gc.size / ptrsize
+	for uintptr(len(gc.gc)) < nptr/2+1 {
+		gc.gc = append(gc.gc, 0x44) // BitsScalar
+	}
+	// If number of words is odd, repeat the mask twice.
+	// Compiler does the same.
+	if nptr%2 != 0 {
+		for i := uintptr(0); i < nptr; i++ {
+			gc.appendWord(extractGCWord(gc.gc, i))
 		}
-		return true
-	default:
-		// Func, Map, Slice, Invalid
-		panic("isReflexive called on non-key type " + t.String())
 	}
+	return unsafe.Pointer(&gc.gc[0]), gc.hasPtr
+}
+
+func extractGCWord(gc []byte, i uintptr) byte {
+	return (gc[i/2] >> ((i%2)*4 + 2)) & 3
+}
+
+func (gc *gcProg) align(a uintptr) {
+	gc.size = align(gc.size, a)
 }
 
+// These constants must stay in sync with ../runtime/mgc0.h.
+const (
+	bitsScalar    = 1
+	bitsPointer   = 2
+	bitsMultiWord = 3
+
+	bitsIface = 2
+	bitsEface = 3
+)
+
 // Make sure these routines stay in sync with ../../runtime/hashmap.go!
 // These types exist only for GC, so we only fill out GC relevant info.
 // Currently, that's just size and the GC program.  We also fill in string
 // for possible debugging use.
 const (
-	bucketSize uintptr = 8
-	maxKeySize uintptr = 128
-	maxValSize uintptr = 128
+	bucketSize = 8
+	maxKeySize = 128
+	maxValSize = 128
 )
 
 func bucketOf(ktyp, etyp *rtype) *rtype {
-	// See comment on hmap.overflow in ../runtime/hashmap.go.
-	var kind uint8
-	if ktyp.kind&kindNoPointers != 0 && etyp.kind&kindNoPointers != 0 &&
-		ktyp.size <= maxKeySize && etyp.size <= maxValSize {
-		kind = kindNoPointers
-	}
-
 	if ktyp.size > maxKeySize {
 		ktyp = PtrTo(ktyp).(*rtype)
 	}
 	if etyp.size > maxValSize {
 		etyp = PtrTo(etyp).(*rtype)
 	}
+	ptrsize := unsafe.Sizeof(uintptr(0))
 
-	// Prepare GC data if any.
-	// A bucket is at most bucketSize*(1+maxKeySize+maxValSize)+2*ptrSize bytes,
-	// or 2072 bytes, or 259 pointer-size words, or 33 bytes of pointer bitmap.
-	// Normally the enforced limit on pointer maps is 16 bytes,
-	// but larger ones are acceptable, 33 bytes isn't too too big,
-	// and it's easier to generate a pointer bitmap than a GC program.
-	// Note that since the key and value are known to be <= 128 bytes,
-	// they're guaranteed to have bitmaps instead of GC programs.
-	var gcdata *byte
-	var ptrdata uintptr
-	var overflowPad uintptr
-
-	// On NaCl, pad if needed to make overflow end at the proper struct alignment.
-	// On other systems, align > ptrSize is not possible.
-	if runtime.GOARCH == "amd64p32" && (ktyp.align > ptrSize || etyp.align > ptrSize) {
-		overflowPad = ptrSize
-	}
-	size := bucketSize*(1+ktyp.size+etyp.size) + overflowPad + ptrSize
-	if size&uintptr(ktyp.align-1) != 0 || size&uintptr(etyp.align-1) != 0 {
-		panic("reflect: bad size computation in MapOf")
-	}
-
-	if kind != kindNoPointers {
-		nptr := (bucketSize*(1+ktyp.size+etyp.size) + ptrSize) / ptrSize
-		mask := make([]byte, (nptr+7)/8)
-		base := bucketSize / ptrSize
-
-		if ktyp.kind&kindNoPointers == 0 {
-			if ktyp.kind&kindGCProg != 0 {
-				panic("reflect: unexpected GC program in MapOf")
-			}
-			kmask := (*[16]byte)(unsafe.Pointer(ktyp.gcdata))
-			for i := uintptr(0); i < ktyp.size/ptrSize; i++ {
-				if (kmask[i/8]>>(i%8))&1 != 0 {
-					for j := uintptr(0); j < bucketSize; j++ {
-						word := base + j*ktyp.size/ptrSize + i
-						mask[word/8] |= 1 << (word % 8)
-					}
-				}
-			}
-		}
-		base += bucketSize * ktyp.size / ptrSize
-
-		if etyp.kind&kindNoPointers == 0 {
-			if etyp.kind&kindGCProg != 0 {
-				panic("reflect: unexpected GC program in MapOf")
-			}
-			emask := (*[16]byte)(unsafe.Pointer(etyp.gcdata))
-			for i := uintptr(0); i < etyp.size/ptrSize; i++ {
-				if (emask[i/8]>>(i%8))&1 != 0 {
-					for j := uintptr(0); j < bucketSize; j++ {
-						word := base + j*etyp.size/ptrSize + i
-						mask[word/8] |= 1 << (word % 8)
-					}
-				}
-			}
-		}
-		base += bucketSize * etyp.size / ptrSize
-		base += overflowPad / ptrSize
-
-		word := base
-		mask[word/8] |= 1 << (word % 8)
-		gcdata = &mask[0]
-		ptrdata = (word + 1) * ptrSize
-
-		// overflow word must be last
-		if ptrdata != size {
-			panic("reflect: bad layout computation in MapOf")
-		}
+	var gc gcProg
+	// topbits
+	for i := 0; i < int(bucketSize*unsafe.Sizeof(uint8(0))/ptrsize); i++ {
+		gc.append(bitsScalar)
+	}
+	// keys
+	for i := 0; i < bucketSize; i++ {
+		gc.appendProg(ktyp)
+	}
+	// values
+	for i := 0; i < bucketSize; i++ {
+		gc.appendProg(etyp)
+	}
+	// overflow
+	gc.append(bitsPointer)
+	if runtime.GOARCH == "amd64p32" {
+		gc.append(bitsScalar)
 	}
 
 	b := new(rtype)
-	b.align = ptrSize
-	if overflowPad > 0 {
-		b.align = 8
-	}
-	b.size = size
-	b.ptrdata = ptrdata
-	b.kind = kind
-	b.gcdata = gcdata
+	b.size = gc.size
+	b.gc[0], _ = gc.finalize()
 	s := "bucket(" + *ktyp.string + "," + *etyp.string + ")"
 	b.string = &s
 	return b
@@ -1810,36 +1680,36 @@ func SliceOf(t Type) Type {
 	slice.elem = typ
 	slice.uncommonType = nil
 	slice.ptrToThis = nil
+	slice.zero = unsafe.Pointer(&make([]byte, slice.size)[0])
 
 	return cachePut(ckey, &slice.rtype)
 }
 
-// See cmd/compile/internal/gc/reflect.go for derivation of constant.
-const maxPtrmaskBytes = 2048
-
 // ArrayOf returns the array type with the given count and element type.
 // For example, if t represents int, ArrayOf(5, t) represents [5]int.
 //
 // If the resulting type would be larger than the available address space,
 // ArrayOf panics.
-func ArrayOf(count int, elem Type) Type {
+//
+// TODO(rsc): Unexported for now. Export once the alg field is set correctly
+// for the type. This may require significant work.
+//
+// TODO(rsc): TestArrayOf is also disabled. Re-enable.
+func arrayOf(count int, elem Type) Type {
 	typ := elem.(*rtype)
-	// call SliceOf here as it calls cacheGet/cachePut.
-	// ArrayOf also calls cacheGet/cachePut and thus may modify the state of
-	// the lookupCache mutex.
 	slice := SliceOf(elem)
 
 	// Look in cache.
 	ckey := cacheKey{Array, typ, nil, uintptr(count)}
-	if array := cacheGet(ckey); array != nil {
-		return array
+	if slice := cacheGet(ckey); slice != nil {
+		return slice
 	}
 
 	// Look in known types.
 	s := "[" + strconv.Itoa(count) + "]" + *typ.string
 	for _, tt := range typesByString(s) {
-		array := (*arrayType)(unsafe.Pointer(tt))
-		if array.elem == typ {
+		slice := (*sliceType)(unsafe.Pointer(tt))
+		if slice.elem == typ {
 			return cachePut(ckey, tt)
 		}
 	}
@@ -1849,6 +1719,7 @@ func ArrayOf(count int, elem Type) Type {
 	prototype := *(**arrayType)(unsafe.Pointer(&iarray))
 	array := new(arrayType)
 	*array = *prototype
+	// TODO: Set extra kind bits correctly.
 	array.string = &s
 	array.hash = fnv1(typ.hash, '[')
 	for n := uint32(count); n > 0; n >>= 8 {
@@ -1861,144 +1732,20 @@ func ArrayOf(count int, elem Type) Type {
 		panic("reflect.ArrayOf: array size would exceed virtual address space")
 	}
 	array.size = typ.size * uintptr(count)
-	if count > 0 && typ.ptrdata != 0 {
-		array.ptrdata = typ.size*uintptr(count-1) + typ.ptrdata
-	}
 	array.align = typ.align
 	array.fieldAlign = typ.fieldAlign
+	// TODO: array.alg
+	// TODO: array.gc
+	// TODO:
 	array.uncommonType = nil
 	array.ptrToThis = nil
+	array.zero = unsafe.Pointer(&make([]byte, array.size)[0])
 	array.len = uintptr(count)
 	array.slice = slice.(*rtype)
 
-	array.kind &^= kindNoPointers
-	switch {
-	case typ.kind&kindNoPointers != 0 || array.size == 0:
-		// No pointers.
-		array.kind |= kindNoPointers
-		array.gcdata = nil
-		array.ptrdata = 0
-
-	case count == 1:
-		// In memory, 1-element array looks just like the element.
-		array.kind |= typ.kind & kindGCProg
-		array.gcdata = typ.gcdata
-		array.ptrdata = typ.ptrdata
-
-	case typ.kind&kindGCProg == 0 && array.size <= maxPtrmaskBytes*8*ptrSize:
-		// Element is small with pointer mask; array is still small.
-		// Create direct pointer mask by turning each 1 bit in elem
-		// into count 1 bits in larger mask.
-		mask := make([]byte, (array.ptrdata/ptrSize+7)/8)
-		elemMask := (*[1 << 30]byte)(unsafe.Pointer(typ.gcdata))[:]
-		elemWords := typ.size / ptrSize
-		for j := uintptr(0); j < typ.ptrdata/ptrSize; j++ {
-			if (elemMask[j/8]>>(j%8))&1 != 0 {
-				for i := uintptr(0); i < array.len; i++ {
-					k := i*elemWords + j
-					mask[k/8] |= 1 << (k % 8)
-				}
-			}
-		}
-		array.gcdata = &mask[0]
-
-	default:
-		// Create program that emits one element
-		// and then repeats to make the array.
-		prog := []byte{0, 0, 0, 0} // will be length of prog
-		elemGC := (*[1 << 30]byte)(unsafe.Pointer(typ.gcdata))[:]
-		elemPtrs := typ.ptrdata / ptrSize
-		if typ.kind&kindGCProg == 0 {
-			// Element is small with pointer mask; use as literal bits.
-			mask := elemGC
-			// Emit 120-bit chunks of full bytes (max is 127 but we avoid using partial bytes).
-			var n uintptr
-			for n = elemPtrs; n > 120; n -= 120 {
-				prog = append(prog, 120)
-				prog = append(prog, mask[:15]...)
-				mask = mask[15:]
-			}
-			prog = append(prog, byte(n))
-			prog = append(prog, mask[:(n+7)/8]...)
-		} else {
-			// Element has GC program; emit one element.
-			elemProg := elemGC[4 : 4+*(*uint32)(unsafe.Pointer(&elemGC[0]))-1]
-			prog = append(prog, elemProg...)
-		}
-		// Pad from ptrdata to size.
-		elemWords := typ.size / ptrSize
-		if elemPtrs < elemWords {
-			// Emit literal 0 bit, then repeat as needed.
-			prog = append(prog, 0x01, 0x00)
-			if elemPtrs+1 < elemWords {
-				prog = append(prog, 0x81)
-				prog = appendVarint(prog, elemWords-elemPtrs-1)
-			}
-		}
-		// Repeat count-1 times.
-		if elemWords < 0x80 {
-			prog = append(prog, byte(elemWords|0x80))
-		} else {
-			prog = append(prog, 0x80)
-			prog = appendVarint(prog, elemWords)
-		}
-		prog = appendVarint(prog, uintptr(count)-1)
-		prog = append(prog, 0)
-		*(*uint32)(unsafe.Pointer(&prog[0])) = uint32(len(prog) - 4)
-		array.kind |= kindGCProg
-		array.gcdata = &prog[0]
-		array.ptrdata = array.size // overestimate but ok; must match program
-	}
-
-	etyp := typ.common()
-	esize := etyp.Size()
-	ealg := etyp.alg
-
-	array.alg = new(typeAlg)
-	if ealg.equal != nil {
-		eequal := ealg.equal
-		array.alg.equal = func(p, q unsafe.Pointer) bool {
-			for i := 0; i < count; i++ {
-				pi := arrayAt(p, i, esize)
-				qi := arrayAt(q, i, esize)
-				if !eequal(pi, qi) {
-					return false
-				}
-
-			}
-			return true
-		}
-	}
-	if ealg.hash != nil {
-		ehash := ealg.hash
-		array.alg.hash = func(ptr unsafe.Pointer, seed uintptr) uintptr {
-			o := seed
-			for i := 0; i < count; i++ {
-				o = ehash(arrayAt(ptr, i, esize), o)
-			}
-			return o
-		}
-	}
-
-	switch {
-	case count == 1 && !ifaceIndir(typ):
-		// array of 1 direct iface type can be direct
-		array.kind |= kindDirectIface
-	default:
-		array.kind &^= kindDirectIface
-	}
-
 	return cachePut(ckey, &array.rtype)
 }
 
-func appendVarint(x []byte, v uintptr) []byte {
-	for ; v >= 0x80; v >>= 7 {
-		x = append(x, byte(v|0x80))
-	}
-	x = append(x, byte(v))
-	return x
-}
-
 // toType converts from a *rtype to a Type that can be returned
 // to the client of package reflect. In gc, the only concern is that
 // a nil *rtype must be replaced by a nil Type, but in gccgo this
@@ -2021,7 +1768,6 @@ type layoutType struct {
 	argSize   uintptr // size of arguments
 	retOffset uintptr // offset of return values.
 	stack     *bitVector
-	framePool *sync.Pool
 }
 
 var layoutCache struct {
@@ -2035,7 +1781,7 @@ var layoutCache struct {
 // 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, stk *bitVector, framePool *sync.Pool) {
+func funcLayout(t *rtype, rcvr *rtype) (frametype *rtype, argSize, retOffset uintptr, stack *bitVector) {
 	if t.Kind() != Func {
 		panic("reflect: funcLayout of non-func type")
 	}
@@ -2046,63 +1792,64 @@ func funcLayout(t *rtype, rcvr *rtype) (frametype *rtype, argSize, retOffset uin
 	layoutCache.RLock()
 	if x := layoutCache.m[k]; x.t != nil {
 		layoutCache.RUnlock()
-		return x.t, x.argSize, x.retOffset, x.stack, x.framePool
+		return x.t, x.argSize, x.retOffset, x.stack
 	}
 	layoutCache.RUnlock()
 	layoutCache.Lock()
 	if x := layoutCache.m[k]; x.t != nil {
 		layoutCache.Unlock()
-		return x.t, x.argSize, x.retOffset, x.stack, x.framePool
+		return x.t, x.argSize, x.retOffset, x.stack
 	}
 
 	tt := (*funcType)(unsafe.Pointer(t))
 
 	// compute gc program & stack bitmap for arguments
-	ptrmap := new(bitVector)
+	stack = new(bitVector)
+	var gc gcProg
 	var offset uintptr
 	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 ifaceIndir(rcvr) || rcvr.pointers() {
-			ptrmap.append(1)
+		if ifaceIndir(rcvr) {
+			// we pass a pointer to the receiver.
+			gc.append(bitsPointer)
+			stack.append2(bitsPointer)
+		} else if rcvr.pointers() {
+			// rcvr is a one-word pointer object.  Its gc program
+			// is just what we need here.
+			gc.append(bitsPointer)
+			stack.append2(bitsPointer)
+		} else {
+			gc.append(bitsScalar)
+			stack.append2(bitsScalar)
 		}
 		offset += ptrSize
 	}
 	for _, arg := range tt.in {
-		offset += -offset & uintptr(arg.align-1)
-		addTypeBits(ptrmap, offset, arg)
-		offset += arg.size
+		gc.appendProg(arg)
+		addTypeBits(stack, &offset, arg)
 	}
-	argN := ptrmap.n
-	argSize = offset
+	argSize = gc.size
 	if runtime.GOARCH == "amd64p32" {
-		offset += -offset & (8 - 1)
+		gc.align(8)
 	}
-	offset += -offset & (ptrSize - 1)
-	retOffset = offset
+	gc.align(ptrSize)
+	retOffset = gc.size
 	for _, res := range tt.out {
-		offset += -offset & uintptr(res.align-1)
-		addTypeBits(ptrmap, offset, res)
-		offset += res.size
+		gc.appendProg(res)
+		// stack map does not need result bits
 	}
-	offset += -offset & (ptrSize - 1)
+	gc.align(ptrSize)
 
 	// build dummy rtype holding gc program
 	x := new(rtype)
-	x.align = ptrSize
-	if runtime.GOARCH == "amd64p32" {
-		x.align = 8
-	}
-	x.size = offset
-	x.ptrdata = uintptr(ptrmap.n) * ptrSize
-	if ptrmap.n > 0 {
-		x.gcdata = &ptrmap.data[0]
-	} else {
+	x.size = gc.size
+	var hasPtr bool
+	x.gc[0], hasPtr = gc.finalize()
+	if !hasPtr {
 		x.kind |= kindNoPointers
 	}
-	ptrmap.n = argN
-
 	var s string
 	if rcvr != nil {
 		s = "methodargs(" + *rcvr.string + ")(" + *t.string + ")"
@@ -2115,18 +1862,14 @@ func funcLayout(t *rtype, rcvr *rtype) (frametype *rtype, argSize, retOffset uin
 	if layoutCache.m == nil {
 		layoutCache.m = make(map[layoutKey]layoutType)
 	}
-	framePool = &sync.Pool{New: func() interface{} {
-		return unsafe_New(x)
-	}}
 	layoutCache.m[k] = layoutType{
 		t:         x,
 		argSize:   argSize,
 		retOffset: retOffset,
-		stack:     ptrmap,
-		framePool: framePool,
+		stack:     stack,
 	}
 	layoutCache.Unlock()
-	return x, argSize, retOffset, ptrmap, framePool
+	return x, argSize, retOffset, stack
 }
 
 // ifaceIndir reports whether t is stored indirectly in an interface value.
@@ -2140,49 +1883,56 @@ type bitVector struct {
 	data []byte
 }
 
-// append a bit to the bitmap.
-func (bv *bitVector) append(bit uint8) {
+// append a bit pair to the bitmap.
+func (bv *bitVector) append2(bits uint8) {
+	// assume bv.n is a multiple of 2, since append2 is the only operation.
 	if bv.n%8 == 0 {
 		bv.data = append(bv.data, 0)
 	}
-	bv.data[bv.n/8] |= bit << (bv.n % 8)
-	bv.n++
+	bv.data[bv.n/8] |= bits << (bv.n % 8)
+	bv.n += 2
 }
 
-func addTypeBits(bv *bitVector, offset uintptr, t *rtype) {
+func addTypeBits(bv *bitVector, offset *uintptr, t *rtype) {
+	*offset = align(*offset, uintptr(t.align))
 	if t.kind&kindNoPointers != 0 {
+		*offset += t.size
 		return
 	}
 
 	switch Kind(t.kind & kindMask) {
 	case Chan, Func, Map, Ptr, Slice, String, UnsafePointer:
 		// 1 pointer at start of representation
-		for bv.n < uint32(offset/uintptr(ptrSize)) {
-			bv.append(0)
+		for bv.n < 2*uint32(*offset/uintptr(ptrSize)) {
+			bv.append2(bitsScalar)
 		}
-		bv.append(1)
+		bv.append2(bitsPointer)
 
 	case Interface:
 		// 2 pointers
-		for bv.n < uint32(offset/uintptr(ptrSize)) {
-			bv.append(0)
+		for bv.n < 2*uint32(*offset/uintptr(ptrSize)) {
+			bv.append2(bitsScalar)
 		}
-		bv.append(1)
-		bv.append(1)
+		bv.append2(bitsPointer)
+		bv.append2(bitsPointer)
 
 	case Array:
 		// repeat inner type
 		tt := (*arrayType)(unsafe.Pointer(t))
 		for i := 0; i < int(tt.len); i++ {
-			addTypeBits(bv, offset+uintptr(i)*tt.elem.size, tt.elem)
+			addTypeBits(bv, offset, tt.elem)
 		}
 
 	case Struct:
 		// apply fields
 		tt := (*structType)(unsafe.Pointer(t))
+		start := *offset
 		for i := range tt.fields {
 			f := &tt.fields[i]
-			addTypeBits(bv, offset+f.offset, f.typ)
+			off := start + f.offset
+			addTypeBits(bv, &off, f.typ)
 		}
 	}
+
+	*offset += t.size
 }
diff --git a/src/reflect/value.go b/src/reflect/value.go
index 001d027..43843e9 100644
--- a/src/reflect/value.go
+++ b/src/reflect/value.go
@@ -10,7 +10,7 @@ import (
 	"unsafe"
 )
 
-const ptrSize = 4 << (^uintptr(0) >> 63) // unsafe.Sizeof(uintptr(0)) but an ideal const
+const ptrSize = unsafe.Sizeof((*byte)(nil))
 const cannotSet = "cannot set value obtained from unexported struct field"
 
 // Value is the reflection interface to a Go value.
@@ -30,10 +30,6 @@ const cannotSet = "cannot set value obtained from unexported struct field"
 // A Value can be used concurrently by multiple goroutines provided that
 // the underlying Go value can be used concurrently for the equivalent
 // direct operations.
-//
-// Using == on two Values does not compare the underlying values
-// they represent, but rather the contents of the Value structs.
-// To compare two Values, compare the results of the Interface method.
 type Value struct {
 	// typ holds the type of the value represented by a Value.
 	typ *rtype
@@ -107,7 +103,7 @@ func packEface(v Value) interface{} {
 			// TODO: pass safe boolean from valueInterface so
 			// we don't need to copy if safe==true?
 			c := unsafe_New(t)
-			typedmemmove(t, c, ptr)
+			memmove(c, ptr, t.size)
 			ptr = c
 		}
 		e.word = ptr
@@ -176,7 +172,7 @@ type emptyInterface struct {
 
 // nonEmptyInterface is the header for a interface value with methods.
 type nonEmptyInterface struct {
-	// see ../runtime/iface.go:/Itab
+	// see ../runtime/iface.c:/Itab
 	itab *struct {
 		ityp   *rtype // static interface type
 		typ    *rtype // dynamic concrete type
@@ -268,7 +264,7 @@ func (v Value) runes() []rune {
 	return *(*[]rune)(v.ptr)
 }
 
-// CanAddr reports whether the value's address can be obtained with Addr.
+// CanAddr returns true if the value's address can be obtained with Addr.
 // Such values are called addressable.  A value is addressable if it is
 // an element of a slice, an element of an addressable array,
 // a field of an addressable struct, or the result of dereferencing a pointer.
@@ -277,11 +273,11 @@ func (v Value) CanAddr() bool {
 	return v.flag&flagAddr != 0
 }
 
-// CanSet reports whether the value of v can be changed.
+// CanSet returns true if the value of v can be changed.
 // A Value can be changed only if it is addressable and was not
 // obtained by the use of unexported struct fields.
 // If CanSet returns false, calling Set or any type-specific
-// setter (e.g., SetBool, SetInt) will panic.
+// setter (e.g., SetBool, SetInt64) will panic.
 func (v Value) CanSet() bool {
 	return v.flag&(flagAddr|flagRO) == flagAddr
 }
@@ -302,8 +298,8 @@ func (v Value) Call(in []Value) []Value {
 
 // CallSlice calls the variadic function v with the input arguments in,
 // assigning the slice in[len(in)-1] to v's final variadic argument.
-// For example, if len(in) == 3, v.CallSlice(in) represents the Go call v(in[0], in[1], in[2]...).
-// CallSlice panics if v's Kind is not Func or if v is not variadic.
+// For example, if len(in) == 3, v.Call(in) represents the Go call v(in[0], in[1], in[2]...).
+// Call panics if v's Kind is not Func or if v is not variadic.
 // It returns the output results as Values.
 // As in Go, each input argument must be assignable to the
 // type of the function's corresponding input parameter.
@@ -393,18 +389,9 @@ func (v Value) call(op string, in []Value) []Value {
 	}
 	nout := t.NumOut()
 
-	// Compute frame type.
-	frametype, _, retOffset, _, framePool := funcLayout(t, rcvrtype)
-
-	// Allocate a chunk of memory for frame.
-	var args unsafe.Pointer
-	if nout == 0 {
-		args = framePool.Get().(unsafe.Pointer)
-	} else {
-		// Can't use pool if the function has return values.
-		// We will leak pointer to args in ret, so its lifetime is not scoped.
-		args = unsafe_New(frametype)
-	}
+	// Compute frame type, allocate a chunk of memory for frame
+	frametype, _, retOffset, _ := funcLayout(t, rcvrtype)
+	args := unsafe_New(frametype)
 	off := uintptr(0)
 
 	// Copy inputs into args.
@@ -421,7 +408,7 @@ func (v Value) call(op string, in []Value) []Value {
 		addr := unsafe.Pointer(uintptr(args) + off)
 		v = v.assignTo("reflect.Value.Call", targ, addr)
 		if v.flag&flagIndir != 0 {
-			typedmemmove(targ, addr, v.ptr)
+			memmove(addr, v.ptr, n)
 		} else {
 			*(*unsafe.Pointer)(addr) = v.ptr
 		}
@@ -429,33 +416,23 @@ func (v Value) call(op string, in []Value) []Value {
 	}
 
 	// Call.
-	call(frametype, fn, args, uint32(frametype.size), uint32(retOffset))
+	call(fn, args, uint32(frametype.size), uint32(retOffset))
 
 	// For testing; see TestCallMethodJump.
 	if callGC {
 		runtime.GC()
 	}
 
-	var ret []Value
-	if nout == 0 {
-		memclr(args, frametype.size)
-		framePool.Put(args)
-	} else {
-		// Zero the now unused input area of args,
-		// because the Values returned by this function contain pointers to the args object,
-		// and will thus keep the args object alive indefinitely.
-		memclr(args, retOffset)
-		// Copy return values out of args.
-		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())
-			ret[i] = Value{tv.common(), unsafe.Pointer(uintptr(args) + off), fl}
-			off += tv.Size()
-		}
+	// Copy return values out of args.
+	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())
+		ret[i] = Value{tv.common(), unsafe.Pointer(uintptr(args) + off), fl}
+		off += tv.Size()
 	}
 
 	return ret
@@ -492,7 +469,7 @@ func callReflect(ctxt *makeFuncImpl, frame unsafe.Pointer) {
 			// and we cannot let f keep a reference to the stack frame
 			// after this function returns, not even a read-only reference.
 			v.ptr = unsafe_New(typ)
-			typedmemmove(typ, v.ptr, addr)
+			memmove(v.ptr, addr, typ.size)
 			v.flag |= flagIndir
 		} else {
 			v.ptr = *(*unsafe.Pointer)(addr)
@@ -528,7 +505,7 @@ func callReflect(ctxt *makeFuncImpl, frame unsafe.Pointer) {
 			off += -off & uintptr(typ.align-1)
 			addr := unsafe.Pointer(uintptr(ptr) + off)
 			if v.flag&flagIndir != 0 {
-				typedmemmove(typ, addr, v.ptr)
+				memmove(addr, v.ptr, typ.size)
 			} else {
 				*(*unsafe.Pointer)(addr) = v.ptr
 			}
@@ -615,17 +592,17 @@ func align(x, n uintptr) uintptr {
 func callMethod(ctxt *methodValue, frame unsafe.Pointer) {
 	rcvr := ctxt.rcvr
 	rcvrtype, t, fn := methodReceiver("call", rcvr, ctxt.method)
-	frametype, argSize, retOffset, _, framePool := funcLayout(t, rcvrtype)
+	frametype, argSize, retOffset, _ := funcLayout(t, rcvrtype)
 
 	// Make a new frame that is one word bigger so we can store the receiver.
-	args := framePool.Get().(unsafe.Pointer)
+	args := unsafe_New(frametype)
 
 	// Copy in receiver and rest of args.
 	storeRcvr(rcvr, args)
-	typedmemmovepartial(frametype, unsafe.Pointer(uintptr(args)+ptrSize), frame, ptrSize, argSize-ptrSize)
+	memmove(unsafe.Pointer(uintptr(args)+ptrSize), frame, argSize-ptrSize)
 
 	// Call.
-	call(frametype, fn, args, uint32(frametype.size), uint32(retOffset))
+	call(fn, args, uint32(frametype.size), uint32(retOffset))
 
 	// Copy return values. On amd64p32, the beginning of return values
 	// is 64-bit aligned, so the caller's frame layout (which doesn't have
@@ -636,14 +613,8 @@ func callMethod(ctxt *methodValue, frame unsafe.Pointer) {
 	if runtime.GOARCH == "amd64p32" {
 		callerRetOffset = align(argSize-ptrSize, 8)
 	}
-	typedmemmovepartial(frametype,
-		unsafe.Pointer(uintptr(frame)+callerRetOffset),
-		unsafe.Pointer(uintptr(args)+retOffset),
-		retOffset,
-		frametype.size-retOffset)
-
-	memclr(args, frametype.size)
-	framePool.Put(args)
+	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.
@@ -754,7 +725,7 @@ func (v Value) Field(i int) Value {
 	// Either flagIndir is set and v.ptr points at struct,
 	// or flagIndir is not set and v.ptr is the actual struct data.
 	// In the former case, we want v.ptr + offset.
-	// In the latter case, we must have field.offset = 0,
+	// In the latter case, we must be have field.offset = 0,
 	// so v.ptr + field.offset is still okay.
 	ptr := unsafe.Pointer(uintptr(v.ptr) + field.offset)
 	return Value{typ, ptr, fl}
@@ -848,7 +819,7 @@ func (v Value) Index(i int) Value {
 		}
 		tt := (*sliceType)(unsafe.Pointer(v.typ))
 		typ := tt.elem
-		val := arrayAt(s.Data, i, typ.size)
+		val := unsafe.Pointer(uintptr(s.Data) + uintptr(i)*typ.size)
 		fl := flagAddr | flagIndir | v.flag&flagRO | flag(typ.Kind())
 		return Value{typ, val, fl}
 
@@ -857,7 +828,7 @@ func (v Value) Index(i int) Value {
 		if uint(i) >= uint(s.Len) {
 			panic("reflect: string index out of range")
 		}
-		p := arrayAt(s.Data, i, 1)
+		p := unsafe.Pointer(uintptr(s.Data) + uintptr(i))
 		fl := v.flag&flagRO | flag(Uint8) | flagIndir
 		return Value{uint8Type, p, fl}
 	}
@@ -884,7 +855,7 @@ func (v Value) Int() int64 {
 	panic(&ValueError{"reflect.Value.Int", v.kind()})
 }
 
-// CanInterface reports whether Interface can be used without panicking.
+// CanInterface returns true if Interface can be used without panicking.
 func (v Value) CanInterface() bool {
 	if v.flag == 0 {
 		panic(&ValueError{"reflect.Value.CanInterface", Invalid})
@@ -971,7 +942,7 @@ func (v Value) IsNil() bool {
 	panic(&ValueError{"reflect.Value.IsNil", v.kind()})
 }
 
-// IsValid reports whether v represents a value.
+// IsValid returns true if v represents a value.
 // It returns false if v is the zero Value.
 // If IsValid returns false, all other methods except String panic.
 // Most functions and methods never return an invalid value.
@@ -1042,7 +1013,7 @@ func (v Value) MapIndex(key Value) Value {
 		// Copy result so future changes to the map
 		// won't change the underlying value.
 		c := unsafe_New(typ)
-		typedmemmove(typ, c, e)
+		memmove(c, e, typ.size)
 		return Value{typ, c, fl | flagIndir}
 	} else {
 		return Value{typ, *(*unsafe.Pointer)(e), fl}
@@ -1080,7 +1051,7 @@ func (v Value) MapKeys() []Value {
 			// Copy result so future changes to the map
 			// won't change the underlying value.
 			c := unsafe_New(keyType)
-			typedmemmove(keyType, c, key)
+			memmove(c, key, keyType.size)
 			a[i] = Value{keyType, c, fl | flagIndir}
 		} else {
 			a[i] = Value{keyType, *(*unsafe.Pointer)(key), fl}
@@ -1148,7 +1119,7 @@ func (v Value) NumField() int {
 	return len(tt.fields)
 }
 
-// OverflowComplex reports whether the complex128 x cannot be represented by v's type.
+// OverflowComplex returns true if the complex128 x cannot be represented by v's type.
 // It panics if v's Kind is not Complex64 or Complex128.
 func (v Value) OverflowComplex(x complex128) bool {
 	k := v.kind()
@@ -1161,7 +1132,7 @@ func (v Value) OverflowComplex(x complex128) bool {
 	panic(&ValueError{"reflect.Value.OverflowComplex", v.kind()})
 }
 
-// OverflowFloat reports whether the float64 x cannot be represented by v's type.
+// OverflowFloat returns true if the float64 x cannot be represented by v's type.
 // It panics if v's Kind is not Float32 or Float64.
 func (v Value) OverflowFloat(x float64) bool {
 	k := v.kind()
@@ -1181,7 +1152,7 @@ func overflowFloat32(x float64) bool {
 	return math.MaxFloat32 < x && x <= math.MaxFloat64
 }
 
-// OverflowInt reports whether the int64 x cannot be represented by v's type.
+// OverflowInt returns true if the int64 x cannot be represented by v's type.
 // It panics if v's Kind is not Int, Int8, int16, Int32, or Int64.
 func (v Value) OverflowInt(x int64) bool {
 	k := v.kind()
@@ -1194,7 +1165,7 @@ func (v Value) OverflowInt(x int64) bool {
 	panic(&ValueError{"reflect.Value.OverflowInt", v.kind()})
 }
 
-// OverflowUint reports whether the uint64 x cannot be represented by v's type.
+// OverflowUint returns true if the uint64 x cannot be represented by v's type.
 // It panics if v's Kind is not Uint, Uintptr, Uint8, Uint16, Uint32, or Uint64.
 func (v Value) OverflowUint(x uint64) bool {
 	k := v.kind()
@@ -1326,7 +1297,7 @@ func (v Value) Set(x Value) {
 	}
 	x = x.assignTo("reflect.Set", v.typ, target)
 	if x.flag&flagIndir != 0 {
-		typedmemmove(v.typ, v.ptr, x.ptr)
+		memmove(v.ptr, x.ptr, v.typ.size)
 	} else {
 		*(*unsafe.Pointer)(v.ptr) = x.ptr
 	}
@@ -1540,7 +1511,7 @@ func (v Value) Slice(i, j int) Value {
 		if i < 0 || j < i || j > s.Len {
 			panic("reflect.Value.Slice: string slice index out of bounds")
 		}
-		t := stringHeader{arrayAt(s.Data, i, 1), j - i}
+		t := stringHeader{unsafe.Pointer(uintptr(s.Data) + uintptr(i)), j - i}
 		return Value{v.typ, unsafe.Pointer(&t), v.flag}
 	}
 
@@ -1556,7 +1527,7 @@ func (v Value) Slice(i, j int) Value {
 	s.Len = j - i
 	s.Cap = cap - i
 	if cap-i > 0 {
-		s.Data = arrayAt(base, i, typ.elem.Size())
+		s.Data = unsafe.Pointer(uintptr(base) + uintptr(i)*typ.elem.Size())
 	} else {
 		// do not advance pointer, to avoid pointing beyond end of slice
 		s.Data = base
@@ -1608,7 +1579,7 @@ func (v Value) Slice3(i, j, k int) Value {
 	s.Len = j - i
 	s.Cap = k - i
 	if k-i > 0 {
-		s.Data = arrayAt(base, i, typ.elem.Size())
+		s.Data = unsafe.Pointer(uintptr(base) + uintptr(i)*typ.elem.Size())
 	} else {
 		// do not advance pointer, to avoid pointing beyond end of slice
 		s.Data = base
@@ -1622,8 +1593,6 @@ func (v Value) Slice3(i, j, k int) Value {
 // String is a special case because of Go's String method convention.
 // Unlike the other getters, it does not panic if v's Kind is not String.
 // Instead, it returns a string of the form "<T value>" where T is v's type.
-// The fmt package treats Values specially. It does not call their String
-// method implicitly but instead prints the concrete values they hold.
 func (v Value) String() string {
 	switch k := v.kind(); k {
 	case Invalid:
@@ -1649,7 +1618,7 @@ func (v Value) TryRecv() (x Value, ok bool) {
 
 // TrySend attempts to send x on the channel v but will not block.
 // It panics if v's Kind is not Chan.
-// It reports whether the value was sent.
+// It returns true if the value was sent, false otherwise.
 // As in Go, x's value must be assignable to the channel's element type.
 func (v Value) TrySend(x Value) bool {
 	v.mustBe(Chan)
@@ -1767,12 +1736,6 @@ func typesMustMatch(what string, t1, t2 Type) {
 	}
 }
 
-// arrayAt returns the i-th element of p, a C-array whose elements are
-// eltSize wide (in bytes).
-func arrayAt(p unsafe.Pointer, i int, eltSize uintptr) unsafe.Pointer {
-	return unsafe.Pointer(uintptr(p) + uintptr(i)*eltSize)
-}
-
 // grow grows the slice s so that it can hold extra more values, allocating
 // more capacity if needed. It also returns the old and new slice lengths.
 func grow(s Value, extra int) (Value, int, int) {
@@ -1848,23 +1811,27 @@ func Copy(dst, src Value) int {
 	se := src.typ.Elem()
 	typesMustMatch("reflect.Copy", de, se)
 
-	var ds, ss sliceHeader
+	n := dst.Len()
+	if sn := src.Len(); n > sn {
+		n = sn
+	}
+
+	// Copy via memmove.
+	var da, sa unsafe.Pointer
 	if dk == Array {
-		ds.Data = dst.ptr
-		ds.Len = dst.Len()
-		ds.Cap = ds.Len
+		da = dst.ptr
 	} else {
-		ds = *(*sliceHeader)(dst.ptr)
+		da = (*sliceHeader)(dst.ptr).Data
 	}
-	if sk == Array {
-		ss.Data = src.ptr
-		ss.Len = src.Len()
-		ss.Cap = ss.Len
+	if src.flag&flagIndir == 0 {
+		sa = unsafe.Pointer(&src.ptr)
+	} else if sk == Array {
+		sa = src.ptr
 	} else {
-		ss = *(*sliceHeader)(src.ptr)
+		sa = (*sliceHeader)(src.ptr).Data
 	}
-
-	return typedslicecopy(de.common(), ds, ss)
+	memmove(da, sa, uintptr(n)*de.Size())
+	return n
 }
 
 // A runtimeSelect is a single case passed to rselect.
@@ -2405,7 +2372,7 @@ func cvtDirect(v Value, typ Type) Value {
 	if f&flagAddr != 0 {
 		// indirect, mutable word - make a copy
 		c := unsafe_New(t)
-		typedmemmove(t, c, ptr)
+		memmove(c, ptr, t.size)
 		ptr = c
 		f &^= flagAddr
 	}
@@ -2447,54 +2414,19 @@ 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)
-
-//go:noescape
 func mapaccess(t *rtype, m unsafe.Pointer, key unsafe.Pointer) (val unsafe.Pointer)
-
 func mapassign(t *rtype, m unsafe.Pointer, key, val unsafe.Pointer)
-
-//go:noescape
 func mapdelete(t *rtype, m unsafe.Pointer, key unsafe.Pointer)
-
-// m escapes into the return value, but the caller of mapiterinit
-// doesn't let the return value escape.
-//go:noescape
 func mapiterinit(t *rtype, m unsafe.Pointer) unsafe.Pointer
-
-//go:noescape
 func mapiterkey(it unsafe.Pointer) (key unsafe.Pointer)
-
-//go:noescape
 func mapiternext(it unsafe.Pointer)
-
-//go:noescape
 func maplen(m unsafe.Pointer) int
-
-// call calls fn with a copy of the n argument bytes pointed at by arg.
-// After fn returns, reflectcall copies n-retoffset result bytes
-// back into arg+retoffset before returning. If copying result bytes back,
-// the caller must pass the argument frame type as argtype, so that
-// call can execute appropriate write barriers during the copy.
-func call(argtype *rtype, fn, arg unsafe.Pointer, n uint32, retoffset uint32)
+func call(fn, arg unsafe.Pointer, n uint32, retoffset uint32)
 
 func ifaceE2I(t *rtype, src interface{}, dst unsafe.Pointer)
 
-// typedmemmove copies a value of type t to dst from src.
-//go:noescape
-func typedmemmove(t *rtype, dst, src unsafe.Pointer)
-
-// typedmemmovepartial is like typedmemmove but assumes that
-// dst and src point off bytes into the value and only copies size bytes.
-//go:noescape
-func typedmemmovepartial(t *rtype, dst, src unsafe.Pointer, off, size uintptr)
-
-// typedslicecopy copies a slice of elemType values from src to dst,
-// returning the number of elements copied.
-//go:noescape
-func typedslicecopy(elemType *rtype, dst, src sliceHeader) int
-
 //go:noescape
-func memclr(ptr unsafe.Pointer, n uintptr)
+func memmove(adst, asrc unsafe.Pointer, n uintptr)
 
 // Dummy annotation marking that the value x escapes,
 // for use in cases where the reflect code is so clever that
diff --git a/src/regexp/all_test.go b/src/regexp/all_test.go
index d78ae6a..01ea374 100644
--- a/src/regexp/all_test.go
+++ b/src/regexp/all_test.go
@@ -489,17 +489,6 @@ func TestOnePassCutoff(t *testing.T) {
 	}
 }
 
-// Check that the same machine can be used with the standard matcher
-// and then the backtracker when there are no captures.
-func TestSwitchBacktrack(t *testing.T) {
-	re := MustCompile(`a|b`)
-	long := make([]byte, maxBacktrackVector+1)
-
-	// The following sequence of Match calls used to panic. See issue #10319.
-	re.Match(long)     // triggers standard matcher
-	re.Match(long[:1]) // triggers backtracker
-}
-
 func BenchmarkLiteral(b *testing.B) {
 	x := strings.Repeat("x", 50) + "y"
 	b.StopTimer()
diff --git a/src/regexp/exec.go b/src/regexp/exec.go
index 5182720..c4cb201 100644
--- a/src/regexp/exec.go
+++ b/src/regexp/exec.go
@@ -35,15 +35,13 @@ type thread struct {
 
 // A machine holds all the state during an NFA simulation for p.
 type machine struct {
-	re             *Regexp      // corresponding Regexp
-	p              *syntax.Prog // compiled program
-	op             *onePassProg // compiled onepass program, or notOnePass
-	maxBitStateLen int          // max length of string to search with bitstate
-	b              *bitState    // state for backtracker, allocated lazily
-	q0, q1         queue        // two queues for runq, nextq
-	pool           []*thread    // pool of available threads
-	matched        bool         // whether a match was found
-	matchcap       []int        // capture information for the match
+	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
+	matchcap []int        // capture information for the match
 
 	// cached inputs, to avoid allocation
 	inputBytes  inputBytes
@@ -78,9 +76,6 @@ func progMachine(p *syntax.Prog, op *onePassProg) *machine {
 	if ncap < 2 {
 		ncap = 2
 	}
-	if op == notOnePass {
-		m.maxBitStateLen = maxBitStateLen(p)
-	}
 	m.matchcap = make([]int, ncap)
 	return m
 }
@@ -427,29 +422,18 @@ var empty = make([]int, 0)
 func (re *Regexp) doExecute(r io.RuneReader, b []byte, s string, pos int, ncap int) []int {
 	m := re.get()
 	var i input
-	var size int
 	if r != nil {
 		i = m.newInputReader(r)
 	} else if b != nil {
 		i = m.newInputBytes(b)
-		size = len(b)
 	} else {
 		i = m.newInputString(s)
-		size = len(s)
 	}
 	if m.op != notOnePass {
 		if !m.onepass(i, pos) {
 			re.put(m)
 			return nil
 		}
-	} else if size < m.maxBitStateLen && r == nil {
-		if m.b == nil {
-			m.b = newBitState(m.p)
-		}
-		if !m.backtrack(i, pos, size, ncap) {
-			re.put(m)
-			return nil
-		}
 	} else {
 		m.init(ncap)
 		if !m.match(i, pos) {
diff --git a/src/regexp/exec_test.go b/src/regexp/exec_test.go
index 4872cb3..70d069c 100644
--- a/src/regexp/exec_test.go
+++ b/src/regexp/exec_test.go
@@ -24,8 +24,8 @@ import (
 // complexity, over all possible strings over a given alphabet,
 // up to a given size.  Rather than try to link with RE2, we read a
 // log file containing the test cases and the expected matches.
-// The log file, re2-exhaustive.txt, is generated by running 'make log'
-// in the open source RE2 distribution https://github.com/google/re2/.
+// The log file, re2.txt, is generated by running 'make exhaustive-log'
+// in the open source RE2 distribution.  http://code.google.com/p/re2/
 //
 // The test file format is a sequence of stanzas like:
 //
@@ -59,8 +59,8 @@ import (
 // a capital letter are test names printed during RE2's test suite
 // and are echoed into t but otherwise ignored.
 //
-// At time of writing, re2-exhaustive.txt is 59 MB but compresses to 385 kB,
-// so we store re2-exhaustive.txt.bz2 in the repository and decompress it on the fly.
+// At time of writing, re2.txt is 32 MB but compresses to 760 kB,
+// so we store re2.txt.gz in the repository and decompress it on the fly.
 //
 func TestRE2Search(t *testing.T) {
 	testRE2(t, "testdata/re2-search.txt")
@@ -326,7 +326,7 @@ func same(x, y []int) bool {
 
 // TestFowler runs this package's regexp API against the
 // POSIX regular expression tests collected by Glenn Fowler
-// at http://www2.research.att.com/~astopen/testregex/testregex.html.
+// at http://www2.research.att.com/~gsf/testregex/.
 func TestFowler(t *testing.T) {
 	files, err := filepath.Glob("testdata/*.dat")
 	if err != nil {
@@ -361,7 +361,7 @@ Reading:
 			break Reading
 		}
 
-		// http://www2.research.att.com/~astopen/man/man1/testregex.html
+		// http://www2.research.att.com/~gsf/man/man1/testregex.html
 		//
 		// INPUT FORMAT
 		//   Input lines may be blank, a comment beginning with #, or a test
@@ -713,15 +713,3 @@ func TestLongest(t *testing.T) {
 		t.Errorf("longest match was %q, want %q", g, w)
 	}
 }
-
-// TestProgramTooLongForBacktrack tests that a regex which is too long
-// for the backtracker still executes properly.
-func TestProgramTooLongForBacktrack(t *testing.T) {
-	longRegex := MustCompile(`(one|two|three|four|five|six|seven|eight|nine|ten|eleven|twelve|thirteen|fourteen|fifteen|sixteen|seventeen|eighteen|nineteen|twenty|twentyone|twentytwo|twentythree|twentyfour|twentyfive|twentysix|twentyseven|twentyeight|twentynine|thirty|thirtyone|thirtytwo|thirtythree|thirtyfour|thirtyfive|thirtysix|thirtyseven|thirtyeight|thirtynine|forty|fortyone|fortytwo|fortythree|fortyfour|fortyfive|fortysix|fortyseven|fortyeight|fortynine|fifty|fiftyone|fiftytwo|fiftyth [...]
-	if !longRegex.MatchString("two") {
-		t.Errorf("longRegex.MatchString(\"two\") was false, want true")
-	}
-	if longRegex.MatchString("xxx") {
-		t.Errorf("longRegex.MatchString(\"xxx\") was true, want false")
-	}
-}
diff --git a/src/regexp/regexp.go b/src/regexp/regexp.go
index 4e4b412..b615acd 100644
--- a/src/regexp/regexp.go
+++ b/src/regexp/regexp.go
@@ -7,9 +7,9 @@
 // The syntax of the regular expressions accepted is the same
 // general syntax used by Perl, Python, and other languages.
 // More precisely, it is the syntax accepted by RE2 and described at
-// https://golang.org/s/re2syntax, except for \C.
+// http://code.google.com/p/re2/wiki/Syntax, except for \C.
 // For an overview of the syntax, run
-//   go doc regexp/syntax
+//   godoc regexp/syntax
 //
 // The regexp implementation provided by this package is
 // guaranteed to run in time linear in the size of the input.
@@ -83,7 +83,7 @@ type Regexp struct {
 	// read-only after Compile
 	expr           string         // as passed to Compile
 	prog           *syntax.Prog   // compiled program
-	onepass        *onePassProg   // onepass program or nil
+	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
diff --git a/src/regexp/syntax/prog.go b/src/regexp/syntax/prog.go
index ae6db31..29bd282 100644
--- a/src/regexp/syntax/prog.go
+++ b/src/regexp/syntax/prog.go
@@ -189,7 +189,7 @@ Loop:
 
 const noMatch = -1
 
-// MatchRune reports whether the instruction matches (and consumes) r.
+// 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
@@ -256,7 +256,7 @@ func wordRune(r rune) bool {
 		('0' <= r && r <= '9')
 }
 
-// MatchEmptyWidth reports whether the instruction matches
+// MatchEmptyWidth returns true if the instruction matches
 // an empty string between the runes before and after.
 // It should only be called when i.Op == InstEmptyWidth.
 func (i *Inst) MatchEmptyWidth(before rune, after rune) bool {
diff --git a/src/regexp/testdata/README b/src/regexp/testdata/README
index 58cec82..b1b301b 100644
--- a/src/regexp/testdata/README
+++ b/src/regexp/testdata/README
@@ -19,6 +19,5 @@ Such changes are marked with 'RE2/Go'.
 RE2 Test Files
 
 re2-exhaustive.txt.bz2 and re2-search.txt are built by running
-'make log' in the RE2 distribution https://github.com/google/re2/
-
+'make log' in the RE2 distribution.  http://code.google.com/p/re2/.
 The exhaustive file is compressed because it is huge.
diff --git a/src/run.bash b/src/run.bash
index f35ec78..5f20451 100755
--- a/src/run.bash
+++ b/src/run.bash
@@ -12,9 +12,6 @@ unset CDPATH	# in case user has it set
 unset GOPATH    # we disallow local import for non-local packages, if $GOROOT happens
                 # to be under $GOPATH, then some tests below will fail
 
-export GOHOSTOS
-export CC
-
 # no core files, please
 ulimit -c 0
 
@@ -35,4 +32,232 @@ if ulimit -T &> /dev/null; then
 	[ "$(ulimit -H -T)" == "unlimited" ] || ulimit -S -T $(ulimit -H -T)
 fi
 
-exec go tool dist test "$@"
+# allow all.bash to avoid double-build of everything
+rebuild=true
+if [ "$1" == "--no-rebuild" ]; then
+	shift
+else
+	echo '# Building packages and commands.'
+	time go install -a -v std
+	echo
+fi
+
+# 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
+
+# increase timeout for ARM up to 3 times the normal value
+timeout_scale=1
+[ "$GOARCH" == "arm" ] && timeout_scale=3
+
+echo '# Testing packages.'
+time go test std -short -timeout=$(expr 120 \* $timeout_scale)s -gcflags "$GO_GCFLAGS"
+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
+
+echo '# sync -cpu=10'
+go test sync -short -timeout=$(expr 120 \* $timeout_scale)s -cpu=10
+
+xcd() {
+	echo
+	echo '#' $1
+	builtin cd "$GOROOT"/src/$1 || exit 1
+}
+
+# NOTE: "set -e" cannot help us in subshells. It works until you test it with ||.
+#
+#	$ bash --version
+#	GNU bash, version 3.2.48(1)-release (x86_64-apple-darwin12)
+#	Copyright (C) 2007 Free Software Foundation, Inc.
+#
+#	$ set -e; (set -e; false; echo still here); echo subshell exit status $?
+#	subshell exit status 1
+#	# subshell stopped early, set exit status, but outer set -e didn't stop.
+#
+#	$ set -e; (set -e; false; echo still here) || echo stopped
+#	still here
+#	# somehow the '|| echo stopped' broke the inner set -e.
+#	
+# To avoid this bug, every command in a subshell should have '|| exit 1' on it.
+# Strictly speaking, the test may be unnecessary on the final command of
+# the subshell, but it aids later editing and may avoid future bash bugs.
+
+if [ "$GOOS" == "android" ]; then
+	# Disable cgo tests on android.
+	# They are not designed to run off the host.
+	# golang.org/issue/8345
+	CGO_ENABLED=0
+fi
+
+[ "$CGO_ENABLED" != 1 ] ||
+[ "$GOHOSTOS" == windows ] ||
+(xcd ../misc/cgo/stdio
+go run $GOROOT/test/run.go - . || exit 1
+) || exit $?
+
+[ "$CGO_ENABLED" != 1 ] ||
+(xcd ../misc/cgo/life
+go run $GOROOT/test/run.go - . || exit 1
+) || exit $?
+
+[ "$CGO_ENABLED" != 1 ] ||
+(xcd ../misc/cgo/test
+# cgo tests inspect the traceback for runtime functions
+extlink=0
+export GOTRACEBACK=2
+go test -ldflags '-linkmode=auto' || exit 1
+# linkmode=internal fails on dragonfly since errno is a TLS relocation.
+[ "$GOHOSTOS" == dragonfly ] || go test -ldflags '-linkmode=internal' || exit 1
+case "$GOHOSTOS-$GOARCH" in
+openbsd-386 | openbsd-amd64)
+	# test linkmode=external, but __thread not supported, so skip testtls.
+	go test -ldflags '-linkmode=external' || exit 1
+	extlink=1
+	;;
+darwin-386 | darwin-amd64)
+	# linkmode=external fails on OS X 10.6 and earlier == Darwin
+	# 10.8 and earlier.
+	case $(uname -r) in
+	[0-9].* | 10.*) ;;
+	*)
+		go test -ldflags '-linkmode=external'  || exit 1
+		extlink=1
+		;;
+	esac
+	;;
+android-arm | 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
+	extlink=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 $?
+
+# Race detector only supported on Linux, FreeBSD and OS X,
+# and only on amd64, and only when cgo is enabled.
+# Delayed until here so we know whether to try external linking.
+case "$GOHOSTOS-$GOOS-$GOARCH-$CGO_ENABLED" in
+linux-linux-amd64-1 | freebsd-freebsd-amd64-1 | darwin-darwin-amd64-1)
+	echo
+	echo '# Testing race detector.'
+	go test -race -i runtime/race flag os/exec
+	go test -race -run=Output runtime/race
+	go test -race -short flag os/exec
+	
+	# Test with external linking; see issue 9133.
+	if [ "$extlink" = 1 ]; then
+		go test -race -short -ldflags=-linkmode=external flag os/exec
+	fi
+esac
+
+# This tests cgo -cdefs. That mode is not supported,
+# so it's okay if it doesn't work on some systems.
+# In particular, it works badly with clang on OS X.
+# It doesn't work at all now that we disallow C code
+# outside runtime. Once runtime has no C code it won't
+# even be necessary.
+# [ "$CGO_ENABLED" != 1 ] || [ "$GOOS" == darwin ] ||
+# (xcd ../misc/cgo/testcdefs
+# ./test.bash || exit 1
+# ) || exit $?
+
+[ "$CGO_ENABLED" != 1 ] || [ "$GOOS" == darwin ] ||
+(xcd ../misc/cgo/testgodefs
+./test.bash || exit 1
+) || exit $?
+
+[ "$CGO_ENABLED" != 1 ] ||
+[ "$GOHOSTOS" == windows ] ||
+(xcd ../misc/cgo/testso
+./test.bash || exit 1
+) || exit $?
+
+[ "$CGO_ENABLED" != 1 ] ||
+[ "$GOHOSTOS-$GOARCH" != linux-amd64 ] ||
+(xcd ../misc/cgo/testasan
+go run main.go || exit 1
+) || exit $?
+
+[ "$CGO_ENABLED" != 1 ] ||
+[ "$GOHOSTOS" == windows ] ||
+(xcd ../misc/cgo/errors
+./test.bash || exit 1
+) || exit $?
+
+[ "$GOOS" == nacl ] ||
+[ "$GOOS" == android ] ||
+(xcd ../doc/progs
+time ./run || exit 1
+) || exit $?
+
+[ "$GOOS" == android ] ||
+[ "$GOOS" == nacl ] ||
+[ "$GOARCH" == arm ] ||  # uses network, fails under QEMU
+(xcd ../doc/articles/wiki
+./test.bash || exit 1
+) || exit $?
+
+[ "$GOOS" == android ] ||
+[ "$GOOS" == nacl ] ||
+(xcd ../doc/codewalk
+time ./run || exit 1
+) || exit $?
+
+[ "$GOOS" == nacl ] ||
+[ "$GOARCH" == arm ] ||
+(xcd ../test/bench/shootout
+time ./timing.sh -test || exit 1
+) || exit $?
+
+[ "$GOOS" == android ] || # TODO(crawshaw): get this working
+[ "$GOOS" == openbsd ] || # golang.org/issue/5057
+(
+echo
+echo '#' ../test/bench/go1
+go test ../test/bench/go1 || exit 1
+) || exit $?
+
+[ "$GOOS" == android ] ||
+(xcd ../test
+unset GOMAXPROCS
+GOOS=$GOHOSTOS GOARCH=$GOHOSTARCH go build -o runtest run.go || exit 1
+time ./runtest || exit 1
+rm -f runtest
+) || exit $?
+
+[ "$GOOS" == android ] ||
+[ "$GOOS" == nacl ] ||
+(
+echo
+echo '# Checking API compatibility.'
+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 4957111..14c1b45 100644
--- a/src/run.bat
+++ b/src/run.bat
@@ -19,8 +19,8 @@ set GOPATH=
 rem TODO avoid rebuild if possible
 
 if x%1==x--no-rebuild goto norebuild
-echo ##### Building packages and commands.
-go install -a -v std cmd
+echo # Building packages and commands.
+go install -a -v std
 if errorlevel 1 goto fail
 echo.
 :norebuild
@@ -37,10 +37,109 @@ call env.bat
 del env.bat
 echo.
 
-go tool dist test --no-rebuild
+echo # Testing packages.
+go test std -short -timeout=120s
 if errorlevel 1 goto fail
 echo.
 
+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
+if errorlevel 1 goto fail
+go test -race -run=Output runtime/race
+if errorlevel 1 goto fail
+go test -race -short flag
+if errorlevel 1 goto fail
+echo.
+:norace
+
+echo # ..\test\bench\go1
+go test ..\test\bench\go1
+if errorlevel 1 goto fail
+echo.
+
+:: cgo tests
+if x%CGO_ENABLED% == x0 goto nocgo
+echo # ..\misc\cgo\life
+go run "%GOROOT%\test\run.go" - ..\misc\cgo\life
+if errorlevel 1 goto fail
+echo.
+
+echo # ..\misc\cgo\stdio
+go run "%GOROOT%\test\run.go" - ..\misc\cgo\stdio
+if errorlevel 1 goto fail
+echo.
+
+:: cgo tests inspect the traceback for runtime functions
+set OLDGOTRACEBACK=%GOTRACEBACK%
+set GOTRACEBACK=2
+
+echo # ..\misc\cgo\test
+go test ..\misc\cgo\test
+if errorlevel 1 goto fail
+echo.
+
+set GOTRACEBACK=%OLDGOTRACEBACK%
+set OLDGOTRACEBACK=
+
+echo # ..\misc\cgo\testso
+cd ..\misc\cgo\testso
+set FAIL=0
+call test.bat
+cd ..\..\..\src
+if %FAIL%==1 goto fail
+echo.
+:nocgo
+
+echo # ..\doc\progs
+go run "%GOROOT%\test\run.go" - ..\doc\progs
+if errorlevel 1 goto fail
+echo.
+
+:: TODO: The other tests in run.bash.
+
+
+set OLDGOMAXPROCS=%GOMAXPROCS%
+
+echo # ..\test
+cd ..\test
+set FAIL=0
+set GOMAXPROCS=
+go run run.go
+if errorlevel 1 set FAIL=1
+cd ..\src
+echo.
+if %FAIL%==1 goto fail
+
+set GOMAXPROCS=%OLDGOMAXPROCS%
+set OLDGOMAXPROCS=
+
+echo # Checking API compatibility.
+go run "%GOROOT%\src\cmd\api\run.go"
+if errorlevel 1 goto fail
+echo.
+
+echo ALL TESTS PASSED
 goto end
 
 :fail
diff --git a/src/run.rc b/src/run.rc
index d0ba866..b0995d8 100755
--- a/src/run.rc
+++ b/src/run.rc
@@ -10,4 +10,52 @@ eval `{go env}
 GOPATH = () # we disallow local import for non-local packages, if $GOROOT happens
             # to be under $GOPATH, then some tests below will fail
 
-exec go tool dist test $*
+# allow all.rc to avoid double-build of everything
+rebuild = true
+if(~ $1 --no-rebuild)
+	shift
+if not {
+	# Run only one process at a time on 9vx.
+	if(~ $sysname vx32)
+		pflag = (-p 1)
+	echo '# Building packages and commands.'
+	time go install -a -v $pflag std
+	echo
+}
+
+# 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.
+GOROOT_FINAL = ()
+
+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
+
+echo '# sync -cpu=10'
+go test sync -short -timeout 120s -cpu 10
+echo
+
+fn xcd {
+	echo
+	echo '#' $1
+	cd $"GOROOT/src/$1
+}
+
+echo
+echo '#' ../test/bench/go1
+go test ../test/bench/go1
+
+@{
+	xcd ../test
+	GOMAXPROCS='' time go run run.go -v
+}
+
+echo
+echo ALL TESTS PASSED
diff --git a/src/runtime/alg.go b/src/runtime/alg.go
index c666836..e9ed595 100644
--- a/src/runtime/alg.go
+++ b/src/runtime/alg.go
@@ -38,49 +38,23 @@ const (
 	alg_max
 )
 
-// typeAlg is also copied/used in reflect/type.go.
-// keep them in sync.
 type typeAlg struct {
 	// function for hashing objects of this type
-	// (ptr to object, seed) -> hash
-	hash func(unsafe.Pointer, uintptr) uintptr
+	// (ptr to object, size, seed) -> hash
+	hash func(unsafe.Pointer, uintptr, uintptr) uintptr
 	// function for comparing objects of this type
-	// (ptr to object A, ptr to object B) -> ==?
-	equal func(unsafe.Pointer, unsafe.Pointer) bool
+	// (ptr to object A, ptr to object B, size) -> ==?
+	equal func(unsafe.Pointer, unsafe.Pointer, uintptr) bool
 }
 
-func memhash0(p unsafe.Pointer, h uintptr) uintptr {
-	return h
-}
-func memhash8(p unsafe.Pointer, h uintptr) uintptr {
-	return memhash(p, h, 1)
-}
-func memhash16(p unsafe.Pointer, h uintptr) uintptr {
-	return memhash(p, h, 2)
-}
-func memhash32(p unsafe.Pointer, h uintptr) uintptr {
-	return memhash(p, h, 4)
-}
-func memhash64(p unsafe.Pointer, h uintptr) uintptr {
-	return memhash(p, h, 8)
-}
-func memhash128(p unsafe.Pointer, h uintptr) uintptr {
-	return memhash(p, h, 16)
-}
-
-// memhash_varlen is defined in assembly because it needs access
-// to the closure.  It appears here to provide an argument
-// signature for the assembly routine.
-func memhash_varlen(p unsafe.Pointer, h uintptr) uintptr
-
 var algarray = [alg_max]typeAlg{
-	alg_MEM:      {nil, nil}, // not used
-	alg_MEM0:     {memhash0, memequal0},
-	alg_MEM8:     {memhash8, memequal8},
-	alg_MEM16:    {memhash16, memequal16},
-	alg_MEM32:    {memhash32, memequal32},
-	alg_MEM64:    {memhash64, memequal64},
-	alg_MEM128:   {memhash128, memequal128},
+	alg_MEM:      {memhash, memequal},
+	alg_MEM0:     {memhash, memequal0},
+	alg_MEM8:     {memhash, memequal8},
+	alg_MEM16:    {memhash, memequal16},
+	alg_MEM32:    {memhash, memequal32},
+	alg_MEM64:    {memhash, memequal64},
+	alg_MEM128:   {memhash, memequal128},
 	alg_NOEQ:     {nil, nil},
 	alg_NOEQ0:    {nil, nil},
 	alg_NOEQ8:    {nil, nil},
@@ -98,17 +72,32 @@ var algarray = [alg_max]typeAlg{
 	alg_CPLX128:  {c128hash, c128equal},
 }
 
+const nacl = GOOS == "nacl"
+
 var useAeshash bool
 
 // in asm_*.s
-func aeshash(p unsafe.Pointer, h, s uintptr) uintptr
-func aeshash32(p unsafe.Pointer, h uintptr) uintptr
-func aeshash64(p unsafe.Pointer, h uintptr) uintptr
-func aeshashstr(p unsafe.Pointer, h uintptr) uintptr
+func aeshash(p unsafe.Pointer, s, h uintptr) uintptr
+func aeshash32(p unsafe.Pointer, s, h uintptr) uintptr
+func aeshash64(p unsafe.Pointer, s, h uintptr) uintptr
+func aeshashstr(p unsafe.Pointer, s, h uintptr) uintptr
+
+func memhash(p unsafe.Pointer, s, h uintptr) uintptr {
+	if !nacl && useAeshash {
+		return aeshash(p, s, h)
+	}
 
-func strhash(a unsafe.Pointer, h uintptr) uintptr {
-	x := (*stringStruct)(a)
-	return memhash(x.str, h, uintptr(x.len))
+	h ^= c0
+	for s > 0 {
+		h = (h ^ uintptr(*(*byte)(p))) * c1
+		p = add(p, 1)
+		s--
+	}
+	return h
+}
+
+func strhash(a unsafe.Pointer, s, h uintptr) uintptr {
+	return memhash((*stringStruct)(a).str, uintptr(len(*(*string)(a))), h)
 }
 
 // NOTE: Because NaN != NaN, a map can contain any
@@ -116,7 +105,7 @@ func strhash(a unsafe.Pointer, h uintptr) uintptr {
 // To avoid long hash chains, we assign a random number
 // as the hash value for a NaN.
 
-func f32hash(p unsafe.Pointer, h uintptr) uintptr {
+func f32hash(p unsafe.Pointer, s, h uintptr) uintptr {
 	f := *(*float32)(p)
 	switch {
 	case f == 0:
@@ -124,11 +113,11 @@ func f32hash(p unsafe.Pointer, h uintptr) uintptr {
 	case f != f:
 		return c1 * (c0 ^ h ^ uintptr(fastrand1())) // any kind of NaN
 	default:
-		return memhash(p, h, 4)
+		return memhash(p, 4, h)
 	}
 }
 
-func f64hash(p unsafe.Pointer, h uintptr) uintptr {
+func f64hash(p unsafe.Pointer, s, h uintptr) uintptr {
 	f := *(*float64)(p)
 	switch {
 	case f == 0:
@@ -136,52 +125,52 @@ func f64hash(p unsafe.Pointer, h uintptr) uintptr {
 	case f != f:
 		return c1 * (c0 ^ h ^ uintptr(fastrand1())) // any kind of NaN
 	default:
-		return memhash(p, h, 8)
+		return memhash(p, 8, h)
 	}
 }
 
-func c64hash(p unsafe.Pointer, h uintptr) uintptr {
+func c64hash(p unsafe.Pointer, s, h uintptr) uintptr {
 	x := (*[2]float32)(p)
-	return f32hash(unsafe.Pointer(&x[1]), f32hash(unsafe.Pointer(&x[0]), h))
+	return f32hash(unsafe.Pointer(&x[1]), 4, f32hash(unsafe.Pointer(&x[0]), 4, h))
 }
 
-func c128hash(p unsafe.Pointer, h uintptr) uintptr {
+func c128hash(p unsafe.Pointer, s, h uintptr) uintptr {
 	x := (*[2]float64)(p)
-	return f64hash(unsafe.Pointer(&x[1]), f64hash(unsafe.Pointer(&x[0]), h))
+	return f64hash(unsafe.Pointer(&x[1]), 8, f64hash(unsafe.Pointer(&x[0]), 8, h))
 }
 
-func interhash(p unsafe.Pointer, h uintptr) uintptr {
+func interhash(p unsafe.Pointer, s, h uintptr) uintptr {
 	a := (*iface)(p)
 	tab := a.tab
 	if tab == nil {
 		return h
 	}
 	t := tab._type
-	fn := t.alg.hash
+	fn := goalg(t.alg).hash
 	if fn == nil {
 		panic(errorString("hash of unhashable type " + *t._string))
 	}
 	if isDirectIface(t) {
-		return c1 * fn(unsafe.Pointer(&a.data), h^c0)
+		return c1 * fn(unsafe.Pointer(&a.data), uintptr(t.size), h^c0)
 	} else {
-		return c1 * fn(a.data, h^c0)
+		return c1 * fn(a.data, uintptr(t.size), h^c0)
 	}
 }
 
-func nilinterhash(p unsafe.Pointer, h uintptr) uintptr {
+func nilinterhash(p unsafe.Pointer, s, h uintptr) uintptr {
 	a := (*eface)(p)
 	t := a._type
 	if t == nil {
 		return h
 	}
-	fn := t.alg.hash
+	fn := goalg(t.alg).hash
 	if fn == nil {
 		panic(errorString("hash of unhashable type " + *t._string))
 	}
 	if isDirectIface(t) {
-		return c1 * fn(unsafe.Pointer(&a.data), h^c0)
+		return c1 * fn(unsafe.Pointer(&a.data), uintptr(t.size), h^c0)
 	} else {
-		return c1 * fn(a.data, h^c0)
+		return c1 * fn(a.data, uintptr(t.size), h^c0)
 	}
 }
 
@@ -192,47 +181,47 @@ func memequal(p, q unsafe.Pointer, size uintptr) bool {
 	return memeq(p, q, size)
 }
 
-func memequal0(p, q unsafe.Pointer) bool {
+func memequal0(p, q unsafe.Pointer, size uintptr) bool {
 	return true
 }
-func memequal8(p, q unsafe.Pointer) bool {
+func memequal8(p, q unsafe.Pointer, size uintptr) bool {
 	return *(*int8)(p) == *(*int8)(q)
 }
-func memequal16(p, q unsafe.Pointer) bool {
+func memequal16(p, q unsafe.Pointer, size uintptr) bool {
 	return *(*int16)(p) == *(*int16)(q)
 }
-func memequal32(p, q unsafe.Pointer) bool {
+func memequal32(p, q unsafe.Pointer, size uintptr) bool {
 	return *(*int32)(p) == *(*int32)(q)
 }
-func memequal64(p, q unsafe.Pointer) bool {
+func memequal64(p, q unsafe.Pointer, size uintptr) bool {
 	return *(*int64)(p) == *(*int64)(q)
 }
-func memequal128(p, q unsafe.Pointer) bool {
+func memequal128(p, q unsafe.Pointer, size uintptr) bool {
 	return *(*[2]int64)(p) == *(*[2]int64)(q)
 }
-func f32equal(p, q unsafe.Pointer) bool {
+func f32equal(p, q unsafe.Pointer, size uintptr) bool {
 	return *(*float32)(p) == *(*float32)(q)
 }
-func f64equal(p, q unsafe.Pointer) bool {
+func f64equal(p, q unsafe.Pointer, size uintptr) bool {
 	return *(*float64)(p) == *(*float64)(q)
 }
-func c64equal(p, q unsafe.Pointer) bool {
+func c64equal(p, q unsafe.Pointer, size uintptr) bool {
 	return *(*complex64)(p) == *(*complex64)(q)
 }
-func c128equal(p, q unsafe.Pointer) bool {
+func c128equal(p, q unsafe.Pointer, size uintptr) bool {
 	return *(*complex128)(p) == *(*complex128)(q)
 }
-func strequal(p, q unsafe.Pointer) bool {
+func strequal(p, q unsafe.Pointer, size uintptr) bool {
 	return *(*string)(p) == *(*string)(q)
 }
-func interequal(p, q unsafe.Pointer) bool {
+func interequal(p, q unsafe.Pointer, size uintptr) bool {
 	return ifaceeq(*(*interface {
 		f()
 	})(p), *(*interface {
 		f()
 	})(q))
 }
-func nilinterequal(p, q unsafe.Pointer) bool {
+func nilinterequal(p, q unsafe.Pointer, size uintptr) bool {
 	return efaceeq(*(*interface{})(p), *(*interface{})(q))
 }
 func efaceeq(p, q interface{}) bool {
@@ -245,14 +234,14 @@ func efaceeq(p, q interface{}) bool {
 	if t == nil {
 		return true
 	}
-	eq := t.alg.equal
+	eq := goalg(t.alg).equal
 	if eq == nil {
 		panic(errorString("comparing uncomparable type " + *t._string))
 	}
 	if isDirectIface(t) {
-		return eq(noescape(unsafe.Pointer(&x.data)), noescape(unsafe.Pointer(&y.data)))
+		return eq(noescape(unsafe.Pointer(&x.data)), noescape(unsafe.Pointer(&y.data)), uintptr(t.size))
 	}
-	return eq(x.data, y.data)
+	return eq(x.data, y.data, uintptr(t.size))
 }
 func ifaceeq(p, q interface {
 	f()
@@ -267,73 +256,97 @@ func ifaceeq(p, q interface {
 		return true
 	}
 	t := xtab._type
-	eq := t.alg.equal
+	eq := goalg(t.alg).equal
 	if eq == nil {
 		panic(errorString("comparing uncomparable type " + *t._string))
 	}
 	if isDirectIface(t) {
-		return eq(noescape(unsafe.Pointer(&x.data)), noescape(unsafe.Pointer(&y.data)))
+		return eq(noescape(unsafe.Pointer(&x.data)), noescape(unsafe.Pointer(&y.data)), uintptr(t.size))
 	}
-	return eq(x.data, y.data)
+	return eq(x.data, y.data, uintptr(t.size))
 }
 
 // Testing adapters for hash quality tests (see hash_test.go)
+func haveGoodHash() bool {
+	return useAeshash
+}
+
 func stringHash(s string, seed uintptr) uintptr {
-	return algarray[alg_STRING].hash(noescape(unsafe.Pointer(&s)), seed)
+	return algarray[alg_STRING].hash(noescape(unsafe.Pointer(&s)), unsafe.Sizeof(s), seed)
 }
 
 func bytesHash(b []byte, seed uintptr) uintptr {
-	s := (*slice)(unsafe.Pointer(&b))
-	return memhash(s.array, seed, uintptr(s.len))
+	s := (*sliceStruct)(unsafe.Pointer(&b))
+	return algarray[alg_MEM].hash(s.array, uintptr(s.len), seed)
 }
 
 func int32Hash(i uint32, seed uintptr) uintptr {
-	return algarray[alg_MEM32].hash(noescape(unsafe.Pointer(&i)), seed)
+	return algarray[alg_MEM32].hash(noescape(unsafe.Pointer(&i)), 4, seed)
 }
 
 func int64Hash(i uint64, seed uintptr) uintptr {
-	return algarray[alg_MEM64].hash(noescape(unsafe.Pointer(&i)), seed)
+	return algarray[alg_MEM64].hash(noescape(unsafe.Pointer(&i)), 8, seed)
 }
 
 func efaceHash(i interface{}, seed uintptr) uintptr {
-	return algarray[alg_NILINTER].hash(noescape(unsafe.Pointer(&i)), seed)
+	return algarray[alg_NILINTER].hash(noescape(unsafe.Pointer(&i)), unsafe.Sizeof(i), seed)
 }
 
 func ifaceHash(i interface {
 	F()
 }, seed uintptr) uintptr {
-	return algarray[alg_INTER].hash(noescape(unsafe.Pointer(&i)), seed)
+	return algarray[alg_INTER].hash(noescape(unsafe.Pointer(&i)), unsafe.Sizeof(i), seed)
 }
 
 // Testing adapter for memclr
 func memclrBytes(b []byte) {
-	s := (*slice)(unsafe.Pointer(&b))
+	s := (*sliceStruct)(unsafe.Pointer(&b))
 	memclr(s.array, uintptr(s.len))
 }
 
-const hashRandomBytes = ptrSize / 4 * 64
+// TODO(dvyukov): remove when Type is converted to Go and contains *typeAlg.
+func goalg(a unsafe.Pointer) *typeAlg {
+	return (*typeAlg)(a)
+}
+
+// used in asm_{386,amd64}.s
+const hashRandomBytes = 32
 
-// used in asm_{386,amd64}.s to seed the hash function
 var aeskeysched [hashRandomBytes]byte
 
-// used in hash{32,64}.go to seed the hash function
-var hashkey [4]uintptr
+//go:noescape
+func get_random_data(rnd *unsafe.Pointer, n *int32)
 
 func init() {
+	if theGoos == "nacl" {
+		return
+	}
+
 	// Install aes hash algorithm if we have the instructions we need
-	if (GOARCH == "386" || GOARCH == "amd64") &&
-		GOOS != "nacl" &&
-		cpuid_ecx&(1<<25) != 0 && // aes (aesenc)
-		cpuid_ecx&(1<<9) != 0 && // sse3 (pshufb)
-		cpuid_ecx&(1<<19) != 0 { // sse4.1 (pinsr{d,q})
+	if (cpuid_ecx&(1<<25)) != 0 && // aes (aesenc)
+		(cpuid_ecx&(1<<9)) != 0 && // sse3 (pshufb)
+		(cpuid_ecx&(1<<19)) != 0 { // sse4.1 (pinsr{d,q})
 		useAeshash = true
+		algarray[alg_MEM].hash = aeshash
+		algarray[alg_MEM8].hash = aeshash
+		algarray[alg_MEM16].hash = aeshash
 		algarray[alg_MEM32].hash = aeshash32
 		algarray[alg_MEM64].hash = aeshash64
+		algarray[alg_MEM128].hash = aeshash
 		algarray[alg_STRING].hash = aeshashstr
 		// Initialize with random data so hash collisions will be hard to engineer.
-		getRandomData(aeskeysched[:])
-		return
+		var rnd unsafe.Pointer
+		var n int32
+		get_random_data(&rnd, &n)
+		if n > hashRandomBytes {
+			n = hashRandomBytes
+		}
+		memmove(unsafe.Pointer(&aeskeysched[0]), rnd, uintptr(n))
+		if n < hashRandomBytes {
+			// Not very random, but better than nothing.
+			for t := nanotime(); n < hashRandomBytes; n++ {
+				aeskeysched[n] = byte(t >> uint(8*(n%8)))
+			}
+		}
 	}
-	getRandomData((*[len(hashkey) * ptrSize]byte)(unsafe.Pointer(&hashkey))[:])
-	hashkey[0] |= 1 // make sure this number is odd
 }
diff --git a/src/runtime/arch_386.h b/src/runtime/arch_386.h
new file mode 100644
index 0000000..75a5ba7
--- /dev/null
+++ b/src/runtime/arch_386.h
@@ -0,0 +1,17 @@
+// 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 = '8',
+	BigEndian = 0,
+	CacheLineSize = 64,
+	RuntimeGogoBytes = 64,
+#ifdef GOOS_nacl
+	PhysPageSize = 65536,
+#else
+	PhysPageSize = 4096,
+#endif
+	PCQuantum = 1,
+	Int64Align = 4
+};
diff --git a/src/runtime/arch_amd64.h b/src/runtime/arch_amd64.h
new file mode 100644
index 0000000..d7b81ee
--- /dev/null
+++ b/src/runtime/arch_amd64.h
@@ -0,0 +1,25 @@
+// 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,
+#ifdef GOOS_solaris
+	RuntimeGogoBytes = 80,
+#else
+#ifdef GOOS_windows
+	RuntimeGogoBytes = 80,
+#else
+#ifdef GOOS_plan9
+	RuntimeGogoBytes = 80,
+#else
+	RuntimeGogoBytes = 64,
+#endif	// Plan 9
+#endif	// Windows
+#endif	// Solaris
+	PhysPageSize = 4096,
+	PCQuantum = 1,
+	Int64Align = 8
+};
diff --git a/src/runtime/arch_amd64p32.h b/src/runtime/arch_amd64p32.h
new file mode 100644
index 0000000..d3e8649
--- /dev/null
+++ b/src/runtime/arch_amd64p32.h
@@ -0,0 +1,17 @@
+// 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,
+	Int64Align = 8
+};
diff --git a/src/runtime/arch_arm.h b/src/runtime/arch_arm.h
new file mode 100644
index 0000000..637a334
--- /dev/null
+++ b/src/runtime/arch_arm.h
@@ -0,0 +1,17 @@
+// 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 = '5',
+	BigEndian = 0,
+	CacheLineSize = 32,
+	RuntimeGogoBytes = 60,
+#ifdef GOOS_nacl
+	PhysPageSize = 65536,
+#else
+	PhysPageSize = 4096,
+#endif
+	PCQuantum = 4,
+	Int64Align = 4
+};
diff --git a/src/runtime/asm.s b/src/runtime/asm.s
index f1c812b..e6d782f 100644
--- a/src/runtime/asm.s
+++ b/src/runtime/asm.s
@@ -12,8 +12,3 @@ DATA runtime·no_pointers_stackmap+0x00(SB)/4, $2
 DATA runtime·no_pointers_stackmap+0x04(SB)/4, $0
 GLOBL runtime·no_pointers_stackmap(SB),RODATA, $8
 
-TEXT runtime·nop(SB),NOSPLIT,$0-0
-	RET
-
-GLOBL runtime·mheap_(SB), NOPTR, $0
-GLOBL runtime·memstats(SB), NOPTR, $0
diff --git a/src/runtime/asm_386.s b/src/runtime/asm_386.s
index eb9ca63..b4b81d7 100644
--- a/src/runtime/asm_386.s
+++ b/src/runtime/asm_386.s
@@ -2,8 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-#include "go_asm.h"
-#include "go_tls.h"
+#include "zasm_GOOS_GOARCH.h"
 #include "funcdata.h"
 #include "textflag.h"
 
@@ -30,19 +29,6 @@ TEXT runtime·rt0_go(SB),NOSPLIT,$0
 	CPUID
 	CMPL	AX, $0
 	JE	nocpuinfo
-
-	// Figure out how to serialize RDTSC.
-	// On Intel processors LFENCE is enough. AMD requires MFENCE.
-	// Don't know about the rest, so let's do MFENCE.
-	CMPL	BX, $0x756E6547  // "Genu"
-	JNE	notintel
-	CMPL	DX, $0x49656E69  // "ineI"
-	JNE	notintel
-	CMPL	CX, $0x6C65746E  // "ntel"
-	JNE	notintel
-	MOVB	$1, runtime·lfenceBeforeRdtsc(SB)
-notintel:
-
 	MOVL	$1, AX
 	CPUID
 	MOVL	CX, runtime·cpuid_ecx(SB)
@@ -63,7 +49,7 @@ nocpuinfo:
 	// update stackguard after _cgo_init
 	MOVL	$runtime·g0(SB), CX
 	MOVL	(g_stack+stack_lo)(CX), AX
-	ADDL	$const__StackGuard, AX
+	ADDL	$const_StackGuard, AX
 	MOVL	AX, g_stackguard0(CX)
 	MOVL	AX, g_stackguard1(CX)
 
@@ -114,7 +100,7 @@ ok:
 	CALL	runtime·schedinit(SB)
 
 	// create a new goroutine to start program
-	PUSHL	$runtime·mainPC(SB)	// entry
+	PUSHL	$runtime·main·f(SB)	// entry
 	PUSHL	$0	// arg size
 	CALL	runtime·newproc(SB)
 	POPL	AX
@@ -126,8 +112,8 @@ ok:
 	INT $3
 	RET
 
-DATA	runtime·mainPC+0(SB)/4,$runtime·main(SB)
-GLOBL	runtime·mainPC(SB),RODATA,$4
+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
@@ -213,49 +199,62 @@ TEXT runtime·mcall(SB), NOSPLIT, $0-4
 	JMP	AX
 	RET
 
-// systemstack_switch is a dummy routine that systemstack leaves at the bottom
+// switchtoM is a dummy routine that onM leaves at the bottom
 // of the G stack.  We need to distinguish the routine that
 // lives at the bottom of the G stack from the one that lives
-// at the top of the system stack because the one at the top of
-// the system stack terminates the stack walk (see topofstack()).
-TEXT runtime·systemstack_switch(SB), NOSPLIT, $0-0
+// at the top of the M stack because the one at the top of
+// the M stack terminates the stack walk (see topofstack()).
+TEXT runtime·switchtoM(SB), NOSPLIT, $0-0
 	RET
 
-// func systemstack(fn func())
-TEXT runtime·systemstack(SB), NOSPLIT, $0-4
-	MOVL	fn+0(FP), DI	// DI = fn
+// func onM_signalok(fn func())
+TEXT runtime·onM_signalok(SB), NOSPLIT, $0-4
 	get_tls(CX)
 	MOVL	g(CX), AX	// AX = g
 	MOVL	g_m(AX), BX	// BX = m
-
 	MOVL	m_gsignal(BX), DX	// DX = gsignal
 	CMPL	AX, DX
-	JEQ	noswitch
+	JEQ	ongsignal
+	JMP	runtime·onM(SB)
+
+ongsignal:
+	MOVL	fn+0(FP), DI	// DI = fn
+	MOVL	DI, DX
+	MOVL	0(DI), DI
+	CALL	DI
+	RET
+
+// func onM(fn func())
+TEXT runtime·onM(SB), NOSPLIT, $0-4
+	MOVL	fn+0(FP), DI	// DI = fn
+	get_tls(CX)
+	MOVL	g(CX), AX	// AX = g
+	MOVL	g_m(AX), BX	// BX = m
 
 	MOVL	m_g0(BX), DX	// DX = g0
 	CMPL	AX, DX
-	JEQ	noswitch
+	JEQ	onm
 
 	MOVL	m_curg(BX), BP
 	CMPL	AX, BP
-	JEQ	switch
+	JEQ	oncurg
 	
-	// Bad: g is not gsignal, not g0, not curg. What is it?
+	// Not g0, not curg. Must be gsignal, but that's not allowed.
 	// Hide call from linker nosplit analysis.
-	MOVL	$runtime·badsystemstack(SB), AX
+	MOVL	$runtime·badonm(SB), AX
 	CALL	AX
 
-switch:
+oncurg:
 	// save our state in g->sched.  Pretend to
-	// be systemstack_switch if the G stack is scanned.
-	MOVL	$runtime·systemstack_switch(SB), (g_sched+gobuf_pc)(AX)
+	// be switchtoM if the G stack is scanned.
+	MOVL	$runtime·switchtoM(SB), (g_sched+gobuf_pc)(AX)
 	MOVL	SP, (g_sched+gobuf_sp)(AX)
 	MOVL	AX, (g_sched+gobuf_g)(AX)
 
 	// switch to g0
 	MOVL	DX, g(CX)
 	MOVL	(g_sched+gobuf_sp)(DX), BX
-	// make it look like mstart called systemstack on g0, to stop traceback
+	// make it look like mstart called onM on g0, to stop traceback
 	SUBL	$4, BX
 	MOVL	$runtime·mstart(SB), DX
 	MOVL	DX, 0(BX)
@@ -276,8 +275,8 @@ switch:
 	MOVL	$0, (g_sched+gobuf_sp)(AX)
 	RET
 
-noswitch:
-	// already on system stack, just call directly
+onm:
+	// already on m stack, just call directly
 	MOVL	DI, DX
 	MOVL	0(DI), DI
 	CALL	DI
@@ -341,24 +340,8 @@ TEXT runtime·morestack_noctxt(SB),NOSPLIT,$0-0
 	MOVL	$0, DX
 	JMP runtime·morestack(SB)
 
-TEXT runtime·stackBarrier(SB),NOSPLIT,$0
-	// We came here via a RET to an overwritten return PC.
-	// AX may be live. Other registers are available.
-
-	// Get the original return PC, g.stkbar[g.stkbarPos].savedLRVal.
-	get_tls(CX)
-	MOVL	g(CX), CX
-	MOVL	(g_stkbar+slice_array)(CX), DX
-	MOVL	g_stkbarPos(CX), BX
-	IMULL	$stkbar__size, BX	// Too big for SIB.
-	MOVL	stkbar_savedLRVal(DX)(BX*1), BX
-	// Record that this stack barrier was hit.
-	ADDL	$1, g_stkbarPos(CX)
-	// Jump to the original return PC.
-	JMP	BX
-
 // reflectcall: call a function with the given argument list
-// func call(argtype *_type, f *FuncVal, arg *byte, argsize, retoffset uint32).
+// func call(f *FuncVal, arg *byte, argsize, retoffset 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!
@@ -370,11 +353,8 @@ TEXT runtime·stackBarrier(SB),NOSPLIT,$0
 	JMP	AX
 // Note: can't just "JMP NAME(SB)" - bad inlining results.
 
-TEXT reflect·call(SB), NOSPLIT, $0-0
-	JMP	·reflectcall(SB)
-
-TEXT ·reflectcall(SB), NOSPLIT, $0-20
-	MOVL	argsize+12(FP), CX
+TEXT ·reflectcall(SB), NOSPLIT, $0-16
+	MOVL	argsize+8(FP), CX
 	DISPATCH(runtime·call16, 16)
 	DISPATCH(runtime·call32, 32)
 	DISPATCH(runtime·call64, 64)
@@ -406,37 +386,27 @@ TEXT ·reflectcall(SB), NOSPLIT, $0-20
 	JMP	AX
 
 #define CALLFN(NAME,MAXSIZE)			\
-TEXT NAME(SB), WRAPPER, $MAXSIZE-20;		\
+TEXT NAME(SB), WRAPPER, $MAXSIZE-16;		\
 	NO_LOCAL_POINTERS;			\
 	/* copy arguments to stack */		\
-	MOVL	argptr+8(FP), SI;		\
-	MOVL	argsize+12(FP), CX;		\
+	MOVL	argptr+4(FP), SI;		\
+	MOVL	argsize+8(FP), CX;		\
 	MOVL	SP, DI;				\
 	REP;MOVSB;				\
 	/* call function */			\
-	MOVL	f+4(FP), DX;			\
+	MOVL	f+0(FP), DX;			\
 	MOVL	(DX), AX; 			\
 	PCDATA  $PCDATA_StackMapIndex, $0;	\
 	CALL	AX;				\
 	/* copy return values back */		\
-	MOVL	argptr+8(FP), DI;		\
-	MOVL	argsize+12(FP), CX;		\
-	MOVL	retoffset+16(FP), BX;		\
+	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;				\
-	/* execute write barrier updates */	\
-	MOVL	argtype+0(FP), DX;		\
-	MOVL	argptr+8(FP), DI;		\
-	MOVL	argsize+12(FP), CX;		\
-	MOVL	retoffset+16(FP), BX;		\
-	MOVL	DX, 0(SP);			\
-	MOVL	DI, 4(SP);			\
-	MOVL	CX, 8(SP);			\
-	MOVL	BX, 12(SP);			\
-	CALL	runtime·callwritebarrier(SB);	\
 	RET
 
 CALLFN(·call16, 16)
@@ -480,7 +450,12 @@ TEXT runtime·cas(SB), NOSPLIT, $0-13
 	MOVL	new+8(FP), CX
 	LOCK
 	CMPXCHGL	CX, 0(BX)
-	SETEQ	ret+12(FP)
+	JZ 4(PC)
+	MOVL	$0, AX
+	MOVB	AX, ret+12(FP)
+	RET
+	MOVL	$1, AX
+	MOVB	AX, ret+12(FP)
 	RET
 
 TEXT runtime·casuintptr(SB), NOSPLIT, $0-13
@@ -511,7 +486,13 @@ TEXT runtime·cas64(SB), NOSPLIT, $0-21
 	MOVL	new_hi+16(FP), CX
 	LOCK
 	CMPXCHG8B	0(BP)
-	SETEQ	ret+20(FP)
+	JNZ	cas64_fail
+	MOVL	$1, AX
+	MOVB	AX, ret+20(FP)
+	RET
+cas64_fail:
+	MOVL	$0, AX
+	MOVB	AX, ret+20(FP)
 	RET
 
 // bool casp(void **p, void *old, void *new)
@@ -521,13 +502,18 @@ TEXT runtime·cas64(SB), NOSPLIT, $0-21
 //		return 1;
 //	}else
 //		return 0;
-TEXT runtime·casp1(SB), NOSPLIT, $0-13
+TEXT runtime·casp(SB), NOSPLIT, $0-13
 	MOVL	ptr+0(FP), BX
 	MOVL	old+4(FP), AX
 	MOVL	new+8(FP), CX
 	LOCK
 	CMPXCHGL	CX, 0(BX)
-	SETEQ	ret+12(FP)
+	JZ 4(PC)
+	MOVL	$0, AX
+	MOVB	AX, ret+12(FP)
+	RET
+	MOVL	$1, AX
+	MOVB	AX, ret+12(FP)
 	RET
 
 // uint32 xadd(uint32 volatile *val, int32 delta)
@@ -551,7 +537,7 @@ TEXT runtime·xchg(SB), NOSPLIT, $0-12
 	MOVL	AX, ret+8(FP)
 	RET
 
-TEXT runtime·xchgp1(SB), NOSPLIT, $0-12
+TEXT runtime·xchgp(SB), NOSPLIT, $0-12
 	MOVL	ptr+0(FP), BX
 	MOVL	new+4(FP), AX
 	XCHGL	AX, 0(BX)
@@ -569,7 +555,7 @@ again:
 	JNZ	again
 	RET
 
-TEXT runtime·atomicstorep1(SB), NOSPLIT, $0-8
+TEXT runtime·atomicstorep(SB), NOSPLIT, $0-8
 	MOVL	ptr+0(FP), BX
 	MOVL	val+4(FP), AX
 	XCHGL	AX, 0(BX)
@@ -584,9 +570,6 @@ TEXT runtime·atomicstore(SB), NOSPLIT, $0-8
 // uint64 atomicload64(uint64 volatile* addr);
 TEXT runtime·atomicload64(SB), NOSPLIT, $0-12
 	MOVL	ptr+0(FP), AX
-	TESTL	$7, AX
-	JZ	2(PC)
-	MOVL	0, AX // crash with nil ptr deref
 	LEAL	ret_lo+4(FP), BX
 	// MOVQ (%EAX), %MM0
 	BYTE $0x0f; BYTE $0x6f; BYTE $0x00
@@ -599,9 +582,6 @@ TEXT runtime·atomicload64(SB), NOSPLIT, $0-12
 // void runtime·atomicstore64(uint64 volatile* addr, uint64 v);
 TEXT runtime·atomicstore64(SB), NOSPLIT, $0-12
 	MOVL	ptr+0(FP), AX
-	TESTL	$7, AX
-	JZ	2(PC)
-	MOVL	0, AX // crash with nil ptr deref
 	// MOVQ and EMMS were introduced on the Pentium MMX.
 	// MOVQ 0x8(%ESP), %MM0
 	BYTE $0x0f; BYTE $0x6f; BYTE $0x44; BYTE $0x24; BYTE $0x08
@@ -624,19 +604,6 @@ TEXT runtime·atomicor8(SB), NOSPLIT, $0-5
 	ORB	BX, (AX)
 	RET
 
-// void	runtime·atomicand8(byte volatile*, byte);
-TEXT runtime·atomicand8(SB), NOSPLIT, $0-5
-	MOVL	ptr+0(FP), AX
-	MOVB	val+4(FP), BX
-	LOCK
-	ANDB	BX, (AX)
-	RET
-
-TEXT ·publicationBarrier(SB),NOSPLIT,$0-0
-	// Stores are already ordered on x86, so this is just a
-	// compile barrier.
-	RET
-
 // void jmpdefer(fn, sp);
 // called from deferreturn.
 // 1. pop the caller
@@ -666,14 +633,25 @@ TEXT gosave<>(SB),NOSPLIT,$0
 	POPL	AX
 	RET
 
-// func asmcgocall(fn, arg unsafe.Pointer) int32
+// asmcgocall(void(*fn)(void*), void *arg)
 // Call fn(arg) on the scheduler stack,
 // aligned appropriately for the gcc ABI.
-// See cgocall.go for more details.
-TEXT ·asmcgocall(SB),NOSPLIT,$0-12
+// See cgocall.c for more details.
+TEXT ·asmcgocall(SB),NOSPLIT,$0-8
 	MOVL	fn+0(FP), AX
 	MOVL	arg+4(FP), BX
+	CALL	asmcgocall<>(SB)
+	RET
 
+TEXT ·asmcgocall_errno(SB),NOSPLIT,$0-12
+	MOVL	fn+0(FP), AX
+	MOVL	arg+4(FP), BX
+	CALL	asmcgocall<>(SB)
+	MOVL	AX, ret+8(FP)
+	RET
+
+TEXT asmcgocall<>(SB),NOSPLIT,$0-0
+	// fn in AX, arg in BX
 	MOVL	SP, DX
 
 	// Figure out if we need to switch to m->g0 stack.
@@ -707,8 +685,6 @@ TEXT ·asmcgocall(SB),NOSPLIT,$0-12
 	SUBL	4(SP), SI
 	MOVL	DI, g(CX)
 	MOVL	SI, SP
-
-	MOVL	AX, ret+8(FP)
 	RET
 
 // cgocallback(void (*fn)(void*), void *frame, uintptr framesize)
@@ -726,7 +702,7 @@ TEXT runtime·cgocallback(SB),NOSPLIT,$12-12
 	RET
 
 // cgocallback_gofunc(FuncVal*, void *frame, uintptr framesize)
-// See cgocall.go for more details.
+// See cgocall.c for more details.
 TEXT ·cgocallback_gofunc(SB),NOSPLIT,$12-12
 	NO_LOCAL_POINTERS
 
@@ -764,7 +740,7 @@ needm:
 	// the same SP back to m->sched.sp. That seems redundant,
 	// but if an unrecovered panic happens, unwindm will
 	// restore the g->sched.sp from the stack location
-	// and then systemstack will try to use it. If we don't set it here,
+	// and then onM will try to use it. If we don't set it here,
 	// that restored SP will be uninitialized (typically 0) and
 	// will not be usable.
 	MOVL	m_g0(BP), SI
@@ -872,48 +848,38 @@ TEXT runtime·stackcheck(SB), NOSPLIT, $0-0
 	INT	$3
 	RET
 
-TEXT runtime·getcallerpc(SB),NOSPLIT,$4-8
+TEXT runtime·getcallerpc(SB),NOSPLIT,$0-8
 	MOVL	argp+0(FP),AX		// addr of first arg
 	MOVL	-4(AX),AX		// get calling pc
-	CMPL	AX, runtime·stackBarrierPC(SB)
-	JNE	nobar
-	// Get original return PC.
-	CALL	runtime·nextBarrierPC(SB)
-	MOVL	0(SP), AX
-nobar:
 	MOVL	AX, ret+4(FP)
 	RET
 
-TEXT runtime·setcallerpc(SB),NOSPLIT,$4-8
+TEXT runtime·gogetcallerpc(SB),NOSPLIT,$0-8
+	MOVL	p+0(FP),AX		// addr of first arg
+	MOVL	-4(AX),AX		// get calling pc
+	MOVL	AX, ret+4(FP)
+	RET
+
+TEXT runtime·setcallerpc(SB),NOSPLIT,$0-8
 	MOVL	argp+0(FP),AX		// addr of first arg
 	MOVL	pc+4(FP), BX
-	MOVL	-4(AX), CX
-	CMPL	CX, runtime·stackBarrierPC(SB)
-	JEQ	setbar
 	MOVL	BX, -4(AX)		// set calling pc
 	RET
-setbar:
-	// Set the stack barrier return PC.
-	MOVL	BX, 0(SP)
-	CALL	runtime·setNextBarrierPC(SB)
-	RET
 
 TEXT runtime·getcallersp(SB), NOSPLIT, $0-8
 	MOVL	argp+0(FP), AX
 	MOVL	AX, ret+4(FP)
 	RET
 
-// func cputicks() int64
+// func gogetcallersp(p unsafe.Pointer) uintptr
+TEXT runtime·gogetcallersp(SB),NOSPLIT,$0-8
+	MOVL	p+0(FP),AX		// addr of first arg
+	MOVL	AX, ret+4(FP)
+	RET
+
+// int64 runtime·cputicks(void), so really
+// void runtime·cputicks(int64 *ticks)
 TEXT runtime·cputicks(SB),NOSPLIT,$0-8
-	TESTL	$0x4000000, runtime·cpuid_edx(SB) // no sse2, no mfence
-	JEQ	done
-	CMPB	runtime·lfenceBeforeRdtsc(SB), $1
-	JNE	mfence
-	BYTE	$0x0f; BYTE $0xae; BYTE $0xe8 // LFENCE
-	JMP	done
-mfence:
-	BYTE	$0x0f; BYTE $0xae; BYTE $0xf0 // MFENCE
-done:
 	RDTSC
 	MOVL	AX, ret_lo+0(FP)
 	MOVL	DX, ret_hi+4(FP)
@@ -936,218 +902,96 @@ TEXT runtime·emptyfunc(SB),0,$0-0
 TEXT runtime·abort(SB),NOSPLIT,$0-0
 	INT $0x3
 
-// memhash_varlen(p unsafe.Pointer, h seed) uintptr
-// redirects to memhash(p, h, size) using the size
-// stored in the closure.
-TEXT runtime·memhash_varlen(SB),NOSPLIT,$16-12
-	GO_ARGS
-	NO_LOCAL_POINTERS
-	MOVL	p+0(FP), AX
-	MOVL	h+4(FP), BX
-	MOVL	4(DX), CX
-	MOVL	AX, 0(SP)
-	MOVL	BX, 4(SP)
-	MOVL	CX, 8(SP)
-	CALL	runtime·memhash(SB)
-	MOVL	12(SP), AX
-	MOVL	AX, ret+8(FP)
-	RET
-
 // hash function using AES hardware instructions
 TEXT runtime·aeshash(SB),NOSPLIT,$0-16
 	MOVL	p+0(FP), AX	// ptr to data
-	MOVL	s+8(FP), CX	// size
-	LEAL	ret+12(FP), DX
+	MOVL	s+4(FP), CX	// size
 	JMP	runtime·aeshashbody(SB)
 
-TEXT runtime·aeshashstr(SB),NOSPLIT,$0-12
+TEXT runtime·aeshashstr(SB),NOSPLIT,$0-16
 	MOVL	p+0(FP), AX	// ptr to string object
+	// s+4(FP) is ignored, it is always sizeof(String)
 	MOVL	4(AX), CX	// length of string
 	MOVL	(AX), AX	// string data
-	LEAL	ret+8(FP), DX
 	JMP	runtime·aeshashbody(SB)
 
 // AX: data
 // CX: length
-// DX: address to put return value
-TEXT runtime·aeshashbody(SB),NOSPLIT,$0-0
-	MOVL	h+4(FP), X6	// seed to low 64 bits of xmm6
-	PINSRD	$2, CX, X6	// size to high 64 bits of xmm6
-	PSHUFHW	$0, X6, X6	// replace size with its low 2 bytes repeated 4 times
-	MOVO	runtime·aeskeysched(SB), X7
+TEXT runtime·aeshashbody(SB),NOSPLIT,$0-16
+	MOVL	h+8(FP), X0	// seed to low 32 bits of xmm0
+	PINSRD	$1, CX, X0	// size to next 32 bits of xmm0
+	MOVO	runtime·aeskeysched+0(SB), X2
+	MOVO	runtime·aeskeysched+16(SB), X3
 	CMPL	CX, $16
-	JB	aes0to15
-	JE	aes16
-	CMPL	CX, $32
-	JBE	aes17to32
-	CMPL	CX, $64
-	JBE	aes33to64
-	JMP	aes65plus
-	
-aes0to15:
+	JB	aessmall
+aesloop:
+	CMPL	CX, $16
+	JBE	aesloopend
+	MOVOU	(AX), X1
+	AESENC	X2, X0
+	AESENC	X1, X0
+	SUBL	$16, CX
+	ADDL	$16, AX
+	JMP	aesloop
+// 1-16 bytes remaining
+aesloopend:
+	// This load may overlap with the previous load above.
+	// We'll hash some bytes twice, but that's ok.
+	MOVOU	-16(AX)(CX*1), X1
+	JMP	partial
+// 0-15 bytes
+aessmall:
 	TESTL	CX, CX
-	JE	aes0
+	JE	finalize	// 0 bytes
 
-	ADDL	$16, AX
-	TESTW	$0xff0, AX
-	JE	endofpage
+	CMPB	AX, $0xf0
+	JA	highpartial
 
 	// 16 bytes loaded at this address won't cross
 	// a page boundary, so we can load it directly.
-	MOVOU	-16(AX), X0
+	MOVOU	(AX), X1
 	ADDL	CX, CX
-	PAND	masks<>(SB)(CX*8), X0
-
-	// scramble 3 times
-	AESENC	X6, X0
-	AESENC	X7, X0
-	AESENC	X7, X0
-	MOVL	X0, (DX)
-	RET
-
-endofpage:
+	PAND	masks<>(SB)(CX*8), X1
+	JMP	partial
+highpartial:
 	// address ends in 1111xxxx.  Might be up against
 	// a page boundary, so load ending at last byte.
 	// Then shift bytes down using pshufb.
-	MOVOU	-32(AX)(CX*1), X0
-	ADDL	CX, CX
-	PSHUFB	shifts<>(SB)(CX*8), X0
-	AESENC	X6, X0
-	AESENC	X7, X0
-	AESENC	X7, X0
-	MOVL	X0, (DX)
-	RET
-
-aes0:
-	// return input seed
-	MOVL	h+4(FP), AX
-	MOVL	AX, (DX)
-	RET
-
-aes16:
-	MOVOU	(AX), X0
-	AESENC	X6, X0
-	AESENC	X7, X0
-	AESENC	X7, X0
-	MOVL	X0, (DX)
-	RET
-
-
-aes17to32:
-	// load data to be hashed
-	MOVOU	(AX), X0
 	MOVOU	-16(AX)(CX*1), X1
-
-	// scramble 3 times
-	AESENC	X6, X0
-	AESENC	runtime·aeskeysched+16(SB), X1
-	AESENC	X7, X0
-	AESENC	X7, X1
-	AESENC	X7, X0
-	AESENC	X7, X1
-
-	// combine results
-	PXOR	X1, X0
-	MOVL	X0, (DX)
-	RET
-
-aes33to64:
-	MOVOU	(AX), X0
-	MOVOU	16(AX), X1
-	MOVOU	-32(AX)(CX*1), X2
-	MOVOU	-16(AX)(CX*1), X3
-	
-	AESENC	X6, X0
-	AESENC	runtime·aeskeysched+16(SB), X1
-	AESENC	runtime·aeskeysched+32(SB), X2
-	AESENC	runtime·aeskeysched+48(SB), X3
-	AESENC	X7, X0
-	AESENC	X7, X1
-	AESENC	X7, X2
-	AESENC	X7, X3
-	AESENC	X7, X0
-	AESENC	X7, X1
-	AESENC	X7, X2
-	AESENC	X7, X3
-
-	PXOR	X2, X0
-	PXOR	X3, X1
-	PXOR	X1, X0
-	MOVL	X0, (DX)
-	RET
-
-aes65plus:
-	// start with last (possibly overlapping) block
-	MOVOU	-64(AX)(CX*1), X0
-	MOVOU	-48(AX)(CX*1), X1
-	MOVOU	-32(AX)(CX*1), X2
-	MOVOU	-16(AX)(CX*1), X3
-
-	// scramble state once
-	AESENC	X6, X0
-	AESENC	runtime·aeskeysched+16(SB), X1
-	AESENC	runtime·aeskeysched+32(SB), X2
-	AESENC	runtime·aeskeysched+48(SB), X3
-
-	// compute number of remaining 64-byte blocks
-	DECL	CX
-	SHRL	$6, CX
-	
-aesloop:
-	// scramble state, xor in a block
-	MOVOU	(AX), X4
-	MOVOU	16(AX), X5
-	AESENC	X4, X0
-	AESENC	X5, X1
-	MOVOU	32(AX), X4
-	MOVOU	48(AX), X5
-	AESENC	X4, X2
-	AESENC	X5, X3
-
-	// scramble state
-	AESENC	X7, X0
-	AESENC	X7, X1
-	AESENC	X7, X2
-	AESENC	X7, X3
-
-	ADDL	$64, AX
-	DECL	CX
-	JNE	aesloop
-
-	// 2 more scrambles to finish
-	AESENC	X7, X0
-	AESENC	X7, X1
-	AESENC	X7, X2
-	AESENC	X7, X3
-	AESENC	X7, X0
-	AESENC	X7, X1
-	AESENC	X7, X2
-	AESENC	X7, X3
-
-	PXOR	X2, X0
-	PXOR	X3, X1
-	PXOR	X1, X0
-	MOVL	X0, (DX)
-	RET
-
-TEXT runtime·aeshash32(SB),NOSPLIT,$0-12
+	ADDL	CX, CX
+	PSHUFB	shifts<>(SB)(CX*8), X1
+partial:
+	// incorporate partial block into hash
+	AESENC	X3, X0
+	AESENC	X1, X0
+finalize:	
+	// finalize hash
+	AESENC	X2, X0
+	AESENC	X3, X0
+	AESENC	X2, X0
+	MOVL	X0, ret+12(FP)
+	RET
+
+TEXT runtime·aeshash32(SB),NOSPLIT,$0-16
 	MOVL	p+0(FP), AX	// ptr to data
-	MOVL	h+4(FP), X0	// seed
+	// s+4(FP) is ignored, it is always sizeof(int32)
+	MOVL	h+8(FP), X0	// seed
 	PINSRD	$1, (AX), X0	// data
 	AESENC	runtime·aeskeysched+0(SB), X0
 	AESENC	runtime·aeskeysched+16(SB), X0
-	AESENC	runtime·aeskeysched+32(SB), X0
-	MOVL	X0, ret+8(FP)
+	AESENC	runtime·aeskeysched+0(SB), X0
+	MOVL	X0, ret+12(FP)
 	RET
 
-TEXT runtime·aeshash64(SB),NOSPLIT,$0-12
+TEXT runtime·aeshash64(SB),NOSPLIT,$0-16
 	MOVL	p+0(FP), AX	// ptr to data
+	// s+4(FP) is ignored, it is always sizeof(int64)
 	MOVQ	(AX), X0	// data
-	PINSRD	$2, h+4(FP), X0	// seed
+	PINSRD	$2, h+8(FP), X0	// seed
 	AESENC	runtime·aeskeysched+0(SB), X0
 	AESENC	runtime·aeskeysched+16(SB), X0
-	AESENC	runtime·aeskeysched+32(SB), X0
-	MOVL	X0, ret+8(FP)
+	AESENC	runtime·aeskeysched+0(SB), X0
+	MOVL	X0, ret+12(FP)
 	RET
 
 // simple mask to get rid of data in the high part of the register.
@@ -1322,57 +1166,51 @@ TEXT runtime·memeq(SB),NOSPLIT,$0-13
 	MOVL	a+0(FP), SI
 	MOVL	b+4(FP), DI
 	MOVL	size+8(FP), BX
-	LEAL	ret+12(FP), AX
-	JMP	runtime·memeqbody(SB)
-
-// memequal_varlen(a, b unsafe.Pointer) bool
-TEXT runtime·memequal_varlen(SB),NOSPLIT,$0-9
-	MOVL    a+0(FP), SI
-	MOVL    b+4(FP), DI
-	CMPL    SI, DI
-	JEQ     eq
-	MOVL    4(DX), BX    // compiler stores size at offset 4 in the closure
-	LEAL	ret+8(FP), AX
-	JMP	runtime·memeqbody(SB)
-eq:
-	MOVB    $1, ret+8(FP)
+	CALL	runtime·memeqbody(SB)
+	MOVB	AX, ret+12(FP)
 	RET
 
 // eqstring tests whether two strings are equal.
-// The compiler guarantees that strings passed
-// to eqstring have equal length.
 // See runtime_test.go:eqstring_generic for
 // equivalent Go code.
 TEXT runtime·eqstring(SB),NOSPLIT,$0-17
+	MOVL	s1len+4(FP), AX
+	MOVL	s2len+12(FP), BX
+	CMPL	AX, BX
+	JNE	different
 	MOVL	s1str+0(FP), SI
 	MOVL	s2str+8(FP), DI
 	CMPL	SI, DI
 	JEQ	same
-	MOVL	s1len+4(FP), BX
-	LEAL	v+16(FP), AX
-	JMP	runtime·memeqbody(SB)
+	CALL	runtime·memeqbody(SB)
+	MOVB	AX, v+16(FP)
+	RET
 same:
 	MOVB	$1, v+16(FP)
 	RET
+different:
+	MOVB	$0, v+16(FP)
+	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
-	LEAL	ret+24(FP), AX
-	JMP	runtime·memeqbody(SB)
+	CALL	runtime·memeqbody(SB)
 eqret:
-	MOVB	$0, ret+24(FP)
+	MOVB	AX, ret+24(FP)
 	RET
 
 // a in SI
 // b in DI
 // count in BX
-// address of result byte in AX
 TEXT runtime·memeqbody(SB),NOSPLIT,$0-0
+	XORL	AX, AX
+
 	CMPL	BX, $4
 	JB	small
 
@@ -1403,7 +1241,6 @@ hugeloop:
 	SUBL	$64, BX
 	CMPL	DX, $0xffff
 	JEQ	hugeloop
-	MOVB	$0, (AX)
 	RET
 
 	// 4 bytes at a time using 32-bit register
@@ -1417,7 +1254,6 @@ bigloop:
 	SUBL	$4, BX
 	CMPL	CX, DX
 	JEQ	bigloop
-	MOVB	$0, (AX)
 	RET
 
 	// remaining 0-4 bytes
@@ -1425,7 +1261,7 @@ leftover:
 	MOVL	-4(SI)(BX*1), CX
 	MOVL	-4(DI)(BX*1), DX
 	CMPL	CX, DX
-	SETEQ	(AX)
+	SETEQ	AX
 	RET
 
 small:
@@ -1462,7 +1298,7 @@ di_finish:
 	SUBL	SI, DI
 	SHLL	CX, DI
 equal:
-	SETEQ	(AX)
+	SETEQ	AX
 	RET
 
 TEXT runtime·cmpstring(SB),NOSPLIT,$0-20
@@ -1470,18 +1306,20 @@ TEXT runtime·cmpstring(SB),NOSPLIT,$0-20
 	MOVL	s1_len+4(FP), BX
 	MOVL	s2_base+8(FP), DI
 	MOVL	s2_len+12(FP), DX
-	LEAL	ret+16(FP), AX
-	JMP	runtime·cmpbody(SB)
+	CALL	runtime·cmpbody(SB)
+	MOVL	AX, ret+16(FP)
+	RET
 
-TEXT bytes·Compare(SB),NOSPLIT,$0-28
+TEXT runtime·cmpbytes(SB),NOSPLIT,$0-28
 	MOVL	s1+0(FP), SI
 	MOVL	s1+4(FP), BX
 	MOVL	s2+12(FP), DI
 	MOVL	s2+16(FP), DX
-	LEAL	ret+24(FP), AX
-	JMP	runtime·cmpbody(SB)
+	CALL	runtime·cmpbody(SB)
+	MOVL	AX, ret+24(FP)
+	RET
 
-TEXT bytes·IndexByte(SB),NOSPLIT,$0-20
+TEXT bytes·IndexByte(SB),NOSPLIT,$0
 	MOVL	s+0(FP), SI
 	MOVL	s_len+4(FP), CX
 	MOVB	c+12(FP), AL
@@ -1495,7 +1333,7 @@ TEXT bytes·IndexByte(SB),NOSPLIT,$0-20
 	MOVL	DI, ret+16(FP)
 	RET
 
-TEXT strings·IndexByte(SB),NOSPLIT,$0-16
+TEXT strings·IndexByte(SB),NOSPLIT,$0
 	MOVL	s+0(FP), SI
 	MOVL	s_len+4(FP), CX
 	MOVB	c+8(FP), AL
@@ -1514,119 +1352,910 @@ TEXT strings·IndexByte(SB),NOSPLIT,$0-16
 //   DI = b
 //   BX = alen
 //   DX = blen
-//   AX = address of return word (set to 1/0/-1)
+// output:
+//   AX = 1/0/-1
 TEXT runtime·cmpbody(SB),NOSPLIT,$0-0
-	MOVL	DX, BP
-	SUBL	BX, DX // DX = blen-alen
-	CMOVLGT	BX, BP // BP = min(alen, blen)
 	CMPL	SI, DI
-	JEQ	allsame
+	JEQ	cmp_allsame
+	CMPL	BX, DX
+	MOVL	DX, BP
+	CMOVLLT	BX, BP // BP = min(alen, blen)
 	CMPL	BP, $4
-	JB	small
+	JB	cmp_small
 	TESTL	$0x4000000, runtime·cpuid_edx(SB) // check for sse2
-	JE	mediumloop
-largeloop:
+	JE	cmp_mediumloop
+cmp_largeloop:
 	CMPL	BP, $16
-	JB	mediumloop
+	JB	cmp_mediumloop
 	MOVOU	(SI), X0
 	MOVOU	(DI), X1
 	PCMPEQB X0, X1
-	PMOVMSKB X1, BX
-	XORL	$0xffff, BX	// convert EQ to NE
-	JNE	diff16	// branch if at least one byte is not equal
+	PMOVMSKB X1, AX
+	XORL	$0xffff, AX	// convert EQ to NE
+	JNE	cmp_diff16	// branch if at least one byte is not equal
 	ADDL	$16, SI
 	ADDL	$16, DI
 	SUBL	$16, BP
-	JMP	largeloop
+	JMP	cmp_largeloop
 
-diff16:
-	BSFL	BX, BX	// index of first byte that differs
-	XORL	DX, DX
+cmp_diff16:
+	BSFL	AX, BX	// index of first byte that differs
+	XORL	AX, AX
 	MOVB	(SI)(BX*1), CX
 	CMPB	CX, (DI)(BX*1)
-	SETHI	DX
-	LEAL	-1(DX*2), DX	// convert 1/0 to +1/-1
-	MOVL	DX, (AX)
+	SETHI	AX
+	LEAL	-1(AX*2), AX	// convert 1/0 to +1/-1
 	RET
 
-mediumloop:
+cmp_mediumloop:
 	CMPL	BP, $4
-	JBE	_0through4
-	MOVL	(SI), BX
+	JBE	cmp_0through4
+	MOVL	(SI), AX
 	MOVL	(DI), CX
-	CMPL	BX, CX
-	JNE	diff4
+	CMPL	AX, CX
+	JNE	cmp_diff4
 	ADDL	$4, SI
 	ADDL	$4, DI
 	SUBL	$4, BP
-	JMP	mediumloop
+	JMP	cmp_mediumloop
 
-_0through4:
-	MOVL	-4(SI)(BP*1), BX
+cmp_0through4:
+	MOVL	-4(SI)(BP*1), AX
 	MOVL	-4(DI)(BP*1), CX
-	CMPL	BX, CX
-	JEQ	allsame
+	CMPL	AX, CX
+	JEQ	cmp_allsame
 
-diff4:
-	BSWAPL	BX	// reverse order of bytes
+cmp_diff4:
+	BSWAPL	AX	// reverse order of bytes
 	BSWAPL	CX
-	XORL	BX, CX	// find bit differences
+	XORL	AX, CX	// find bit differences
 	BSRL	CX, CX	// index of highest bit difference
-	SHRL	CX, BX	// move a's bit to bottom
-	ANDL	$1, BX	// mask bit
-	LEAL	-1(BX*2), BX // 1/0 => +1/-1
-	MOVL	BX, (AX)
+	SHRL	CX, AX	// move a's bit to bottom
+	ANDL	$1, AX	// mask bit
+	LEAL	-1(AX*2), AX // 1/0 => +1/-1
 	RET
 
 	// 0-3 bytes in common
-small:
+cmp_small:
 	LEAL	(BP*8), CX
 	NEGL	CX
-	JEQ	allsame
+	JEQ	cmp_allsame
 
 	// load si
 	CMPB	SI, $0xfc
-	JA	si_high
+	JA	cmp_si_high
 	MOVL	(SI), SI
-	JMP	si_finish
-si_high:
+	JMP	cmp_si_finish
+cmp_si_high:
 	MOVL	-4(SI)(BP*1), SI
 	SHRL	CX, SI
-si_finish:
+cmp_si_finish:
 	SHLL	CX, SI
 
 	// same for di
 	CMPB	DI, $0xfc
-	JA	di_high
+	JA	cmp_di_high
 	MOVL	(DI), DI
-	JMP	di_finish
-di_high:
+	JMP	cmp_di_finish
+cmp_di_high:
 	MOVL	-4(DI)(BP*1), DI
 	SHRL	CX, DI
-di_finish:
+cmp_di_finish:
 	SHLL	CX, DI
 
 	BSWAPL	SI	// reverse order of bytes
 	BSWAPL	DI
 	XORL	SI, DI	// find bit differences
-	JEQ	allsame
+	JEQ	cmp_allsame
 	BSRL	DI, CX	// index of highest bit difference
 	SHRL	CX, SI	// move a's bit to bottom
 	ANDL	$1, SI	// mask bit
-	LEAL	-1(SI*2), BX // 1/0 => +1/-1
-	MOVL	BX, (AX)
+	LEAL	-1(SI*2), AX // 1/0 => +1/-1
 	RET
 
 	// all the bytes in common are the same, so we just need
 	// to compare the lengths.
-allsame:
-	XORL	BX, BX
+cmp_allsame:
+	XORL	AX, AX
 	XORL	CX, CX
-	TESTL	DX, DX
-	SETLT	BX	// 1 if alen > blen
+	CMPL	BX, DX
+	SETGT	AX	// 1 if alen > blen
 	SETEQ	CX	// 1 if alen == blen
-	LEAL	-1(CX)(BX*2), BX	// 1,0,-1 result
-	MOVL	BX, (AX)
+	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·fastrand1(SB), NOSPLIT, $0-4
@@ -1661,26 +2290,3 @@ TEXT _cgo_topofstack(SB),NOSPLIT,$0
 TEXT runtime·goexit(SB),NOSPLIT,$0-0
 	BYTE	$0x90	// NOP
 	CALL	runtime·goexit1(SB)	// does not return
-	// traceback from goexit1 must hit code range of goexit
-	BYTE	$0x90	// NOP
-
-TEXT runtime·prefetcht0(SB),NOSPLIT,$0-4
-	MOVL	addr+0(FP), AX
-	PREFETCHT0	(AX)
-	RET
-
-TEXT runtime·prefetcht1(SB),NOSPLIT,$0-4
-	MOVL	addr+0(FP), AX
-	PREFETCHT1	(AX)
-	RET
-
-
-TEXT runtime·prefetcht2(SB),NOSPLIT,$0-4
-	MOVL	addr+0(FP), AX
-	PREFETCHT2	(AX)
-	RET
-
-TEXT runtime·prefetchnta(SB),NOSPLIT,$0-4
-	MOVL	addr+0(FP), AX
-	PREFETCHNTA	(AX)
-	RET
diff --git a/src/runtime/asm_amd64.s b/src/runtime/asm_amd64.s
index 3b4ca4d..39d7c78 100644
--- a/src/runtime/asm_amd64.s
+++ b/src/runtime/asm_amd64.s
@@ -2,8 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-#include "go_asm.h"
-#include "go_tls.h"
+#include "zasm_GOOS_GOARCH.h"
 #include "funcdata.h"
 #include "textflag.h"
 
@@ -30,19 +29,6 @@ TEXT runtime·rt0_go(SB),NOSPLIT,$0
 	CPUID
 	CMPQ	AX, $0
 	JE	nocpuinfo
-
-	// Figure out how to serialize RDTSC.
-	// On Intel processors LFENCE is enough. AMD requires MFENCE.
-	// Don't know about the rest, so let's do MFENCE.
-	CMPL	BX, $0x756E6547  // "Genu"
-	JNE	notintel
-	CMPL	DX, $0x49656E69  // "ineI"
-	JNE	notintel
-	CMPL	CX, $0x6C65746E  // "ntel"
-	JNE	notintel
-	MOVB	$1, runtime·lfenceBeforeRdtsc(SB)
-notintel:
-
 	MOVQ	$1, AX
 	CPUID
 	MOVL	CX, runtime·cpuid_ecx(SB)
@@ -61,7 +47,7 @@ nocpuinfo:
 	// update stackguard after _cgo_init
 	MOVQ	$runtime·g0(SB), CX
 	MOVQ	(g_stack+stack_lo)(CX), AX
-	ADDQ	$const__StackGuard, AX
+	ADDQ	$const_StackGuard, AX
 	MOVQ	AX, g_stackguard0(CX)
 	MOVQ	AX, g_stackguard1(CX)
 
@@ -109,8 +95,8 @@ ok:
 	CALL	runtime·schedinit(SB)
 
 	// create a new goroutine to start program
-	MOVQ	$runtime·mainPC(SB), AX		// entry
-	PUSHQ	AX
+	MOVQ	$runtime·main·f(SB), BP		// entry
+	PUSHQ	BP
 	PUSHQ	$0			// arg size
 	CALL	runtime·newproc(SB)
 	POPQ	AX
@@ -122,8 +108,8 @@ ok:
 	MOVL	$0xf1, 0xf1  // crash
 	RET
 
-DATA	runtime·mainPC+0(SB)/8,$runtime·main(SB)
-GLOBL	runtime·mainPC(SB),RODATA,$8
+DATA	runtime·main·f+0(SB)/8,$runtime·main(SB)
+GLOBL	runtime·main·f(SB),RODATA,$8
 
 TEXT runtime·breakpoint(SB),NOSPLIT,$0-0
 	BYTE	$0xcc
@@ -147,7 +133,6 @@ TEXT runtime·gosave(SB), NOSPLIT, $0-8
 	MOVQ	BX, gobuf_pc(AX)
 	MOVQ	$0, gobuf_ret(AX)
 	MOVQ	$0, gobuf_ctxt(AX)
-	MOVQ	BP, gobuf_bp(AX)
 	get_tls(CX)
 	MOVQ	g(CX), BX
 	MOVQ	BX, gobuf_g(AX)
@@ -164,11 +149,9 @@ TEXT runtime·gogo(SB), NOSPLIT, $0-8
 	MOVQ	gobuf_sp(BX), SP	// restore SP
 	MOVQ	gobuf_ret(BX), AX
 	MOVQ	gobuf_ctxt(BX), DX
-	MOVQ	gobuf_bp(BX), BP
 	MOVQ	$0, gobuf_sp(BX)	// clear to help garbage collector
 	MOVQ	$0, gobuf_ret(BX)
 	MOVQ	$0, gobuf_ctxt(BX)
-	MOVQ	$0, gobuf_bp(BX)
 	MOVQ	gobuf_pc(BX), BX
 	JMP	BX
 
@@ -186,7 +169,6 @@ TEXT runtime·mcall(SB), NOSPLIT, $0-8
 	LEAQ	fn+0(FP), BX	// caller's SP
 	MOVQ	BX, (g_sched+gobuf_sp)(AX)
 	MOVQ	AX, (g_sched+gobuf_g)(AX)
-	MOVQ	BP, (g_sched+gobuf_bp)(AX)
 
 	// switch to m->g0 & its stack, call fn
 	MOVQ	g(CX), BX
@@ -207,50 +189,63 @@ TEXT runtime·mcall(SB), NOSPLIT, $0-8
 	JMP	AX
 	RET
 
-// systemstack_switch is a dummy routine that systemstack leaves at the bottom
+// switchtoM is a dummy routine that onM leaves at the bottom
 // of the G stack.  We need to distinguish the routine that
 // lives at the bottom of the G stack from the one that lives
-// at the top of the system stack because the one at the top of
-// the system stack terminates the stack walk (see topofstack()).
-TEXT runtime·systemstack_switch(SB), NOSPLIT, $0-0
+// at the top of the M stack because the one at the top of
+// the M stack terminates the stack walk (see topofstack()).
+TEXT runtime·switchtoM(SB), NOSPLIT, $0-0
 	RET
 
-// func systemstack(fn func())
-TEXT runtime·systemstack(SB), NOSPLIT, $0-8
-	MOVQ	fn+0(FP), DI	// DI = fn
+// func onM_signalok(fn func())
+TEXT runtime·onM_signalok(SB), NOSPLIT, $0-8
 	get_tls(CX)
 	MOVQ	g(CX), AX	// AX = g
 	MOVQ	g_m(AX), BX	// BX = m
-
 	MOVQ	m_gsignal(BX), DX	// DX = gsignal
 	CMPQ	AX, DX
-	JEQ	noswitch
+	JEQ	ongsignal
+	JMP	runtime·onM(SB)
+
+ongsignal:
+	MOVQ	fn+0(FP), DI	// DI = fn
+	MOVQ	DI, DX
+	MOVQ	0(DI), DI
+	CALL	DI
+	RET
+
+// func onM(fn func())
+TEXT runtime·onM(SB), NOSPLIT, $0-8
+	MOVQ	fn+0(FP), DI	// DI = fn
+	get_tls(CX)
+	MOVQ	g(CX), AX	// AX = g
+	MOVQ	g_m(AX), BX	// BX = m
 
 	MOVQ	m_g0(BX), DX	// DX = g0
 	CMPQ	AX, DX
-	JEQ	noswitch
+	JEQ	onm
 
-	MOVQ	m_curg(BX), R8
-	CMPQ	AX, R8
-	JEQ	switch
+	MOVQ	m_curg(BX), BP
+	CMPQ	AX, BP
+	JEQ	oncurg
 	
-	// Bad: g is not gsignal, not g0, not curg. What is it?
-	MOVQ	$runtime·badsystemstack(SB), AX
+	// Not g0, not curg. Must be gsignal, but that's not allowed.
+	// Hide call from linker nosplit analysis.
+	MOVQ	$runtime·badonm(SB), AX
 	CALL	AX
 
-switch:
+oncurg:
 	// save our state in g->sched.  Pretend to
-	// be systemstack_switch if the G stack is scanned.
-	MOVQ	$runtime·systemstack_switch(SB), SI
-	MOVQ	SI, (g_sched+gobuf_pc)(AX)
+	// be switchtoM if the G stack is scanned.
+	MOVQ	$runtime·switchtoM(SB), BP
+	MOVQ	BP, (g_sched+gobuf_pc)(AX)
 	MOVQ	SP, (g_sched+gobuf_sp)(AX)
 	MOVQ	AX, (g_sched+gobuf_g)(AX)
-	MOVQ	BP, (g_sched+gobuf_bp)(AX)
 
 	// switch to g0
 	MOVQ	DX, g(CX)
 	MOVQ	(g_sched+gobuf_sp)(DX), BX
-	// make it look like mstart called systemstack on g0, to stop traceback
+	// make it look like mstart called onM on g0, to stop traceback
 	SUBQ	$8, BX
 	MOVQ	$runtime·mstart(SB), DX
 	MOVQ	DX, 0(BX)
@@ -271,7 +266,7 @@ switch:
 	MOVQ	$0, (g_sched+gobuf_sp)(AX)
 	RET
 
-noswitch:
+onm:
 	// already on m stack, just call directly
 	MOVQ	DI, DX
 	MOVQ	0(DI), DI
@@ -321,12 +316,11 @@ TEXT runtime·morestack(SB),NOSPLIT,$0-0
 	LEAQ	8(SP), AX // f's SP
 	MOVQ	AX, (g_sched+gobuf_sp)(SI)
 	MOVQ	DX, (g_sched+gobuf_ctxt)(SI)
-	MOVQ	BP, (g_sched+gobuf_bp)(SI)
 
 	// Call newstack on m->g0's stack.
-	MOVQ	m_g0(BX), BX
-	MOVQ	BX, g(CX)
-	MOVQ	(g_sched+gobuf_sp)(BX), SP
+	MOVQ	m_g0(BX), BP
+	MOVQ	BP, g(CX)
+	MOVQ	(g_sched+gobuf_sp)(BP), SP
 	CALL	runtime·newstack(SB)
 	MOVQ	$0, 0x1003	// crash if newstack returns
 	RET
@@ -336,24 +330,8 @@ TEXT runtime·morestack_noctxt(SB),NOSPLIT,$0
 	MOVL	$0, DX
 	JMP	runtime·morestack(SB)
 
-TEXT runtime·stackBarrier(SB),NOSPLIT,$0
-	// We came here via a RET to an overwritten return PC.
-	// AX may be live. Other registers are available.
-
-	// Get the original return PC, g.stkbar[g.stkbarPos].savedLRVal.
-	get_tls(CX)
-	MOVQ	g(CX), CX
-	MOVQ	(g_stkbar+slice_array)(CX), DX
-	MOVQ	g_stkbarPos(CX), BX
-	IMULQ	$stkbar__size, BX	// Too big for SIB.
-	MOVQ	stkbar_savedLRVal(DX)(BX*1), BX
-	// Record that this stack barrier was hit.
-	ADDQ	$1, g_stkbarPos(CX)
-	// Jump to the original return PC.
-	JMP	BX
-
 // reflectcall: call a function with the given argument list
-// func call(argtype *_type, f *FuncVal, arg *byte, argsize, retoffset uint32).
+// func call(f *FuncVal, arg *byte, argsize, retoffset 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!
@@ -365,13 +343,9 @@ TEXT runtime·stackBarrier(SB),NOSPLIT,$0
 	JMP	AX
 // Note: can't just "JMP NAME(SB)" - bad inlining results.
 
-TEXT reflect·call(SB), NOSPLIT, $0-0
-	JMP	·reflectcall(SB)
-
-TEXT ·reflectcall(SB), NOSPLIT, $0-32
-	MOVLQZX argsize+24(FP), CX
-	// NOTE(rsc): No call16, because CALLFN needs four words
-	// of argument space to invoke callwritebarrier.
+TEXT ·reflectcall(SB), NOSPLIT, $0-24
+	MOVLQZX argsize+16(FP), CX
+	DISPATCH(runtime·call16, 16)
 	DISPATCH(runtime·call32, 32)
 	DISPATCH(runtime·call64, 64)
 	DISPATCH(runtime·call128, 128)
@@ -402,38 +376,29 @@ TEXT ·reflectcall(SB), NOSPLIT, $0-32
 	JMP	AX
 
 #define CALLFN(NAME,MAXSIZE)			\
-TEXT NAME(SB), WRAPPER, $MAXSIZE-32;		\
+TEXT NAME(SB), WRAPPER, $MAXSIZE-24;		\
 	NO_LOCAL_POINTERS;			\
 	/* copy arguments to stack */		\
-	MOVQ	argptr+16(FP), SI;		\
-	MOVLQZX argsize+24(FP), CX;		\
+	MOVQ	argptr+8(FP), SI;		\
+	MOVLQZX argsize+16(FP), CX;		\
 	MOVQ	SP, DI;				\
 	REP;MOVSB;				\
 	/* call function */			\
-	MOVQ	f+8(FP), DX;			\
+	MOVQ	f+0(FP), DX;			\
 	PCDATA  $PCDATA_StackMapIndex, $0;	\
 	CALL	(DX);				\
 	/* copy return values back */		\
-	MOVQ	argptr+16(FP), DI;		\
-	MOVLQZX	argsize+24(FP), CX;		\
-	MOVLQZX retoffset+28(FP), BX;		\
+	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;				\
-	/* execute write barrier updates */	\
-	MOVQ	argtype+0(FP), DX;		\
-	MOVQ	argptr+16(FP), DI;		\
-	MOVLQZX	argsize+24(FP), CX;		\
-	MOVLQZX retoffset+28(FP), BX;		\
-	MOVQ	DX, 0(SP);			\
-	MOVQ	DI, 8(SP);			\
-	MOVQ	CX, 16(SP);			\
-	MOVQ	BX, 24(SP);			\
-	CALL	runtime·callwritebarrier(SB);	\
 	RET
 
+CALLFN(·call16, 16)
 CALLFN(·call32, 32)
 CALLFN(·call64, 64)
 CALLFN(·call128, 128)
@@ -474,7 +439,12 @@ TEXT runtime·cas(SB), NOSPLIT, $0-17
 	MOVL	new+12(FP), CX
 	LOCK
 	CMPXCHGL	CX, 0(BX)
-	SETEQ	ret+16(FP)
+	JZ 4(PC)
+	MOVL	$0, AX
+	MOVB	AX, ret+16(FP)
+	RET
+	MOVL	$1, AX
+	MOVB	AX, ret+16(FP)
 	RET
 
 // bool	runtime·cas64(uint64 *val, uint64 old, uint64 new)
@@ -491,7 +461,13 @@ TEXT runtime·cas64(SB), NOSPLIT, $0-25
 	MOVQ	new+16(FP), CX
 	LOCK
 	CMPXCHGQ	CX, 0(BX)
-	SETEQ	ret+24(FP)
+	JNZ	cas64_fail
+	MOVL	$1, AX
+	MOVB	AX, ret+24(FP)
+	RET
+cas64_fail:
+	MOVL	$0, AX
+	MOVB	AX, ret+24(FP)
 	RET
 	
 TEXT runtime·casuintptr(SB), NOSPLIT, $0-25
@@ -513,13 +489,18 @@ TEXT runtime·atomicstoreuintptr(SB), NOSPLIT, $0-16
 //		return 1;
 //	} else
 //		return 0;
-TEXT runtime·casp1(SB), NOSPLIT, $0-25
+TEXT runtime·casp(SB), NOSPLIT, $0-25
 	MOVQ	ptr+0(FP), BX
 	MOVQ	old+8(FP), AX
 	MOVQ	new+16(FP), CX
 	LOCK
 	CMPXCHGQ	CX, 0(BX)
-	SETEQ	ret+24(FP)
+	JZ 4(PC)
+	MOVL	$0, AX
+	MOVB	AX, ret+24(FP)
+	RET
+	MOVL	$1, AX
+	MOVB	AX, ret+24(FP)
 	RET
 
 // uint32 xadd(uint32 volatile *val, int32 delta)
@@ -546,9 +527,6 @@ TEXT runtime·xadd64(SB), NOSPLIT, $0-24
 	MOVQ	AX, ret+16(FP)
 	RET
 
-TEXT runtime·xadduintptr(SB), NOSPLIT, $0-24
-	JMP	runtime·xadd64(SB)
-
 TEXT runtime·xchg(SB), NOSPLIT, $0-20
 	MOVQ	ptr+0(FP), BX
 	MOVL	new+8(FP), AX
@@ -563,7 +541,7 @@ TEXT runtime·xchg64(SB), NOSPLIT, $0-24
 	MOVQ	AX, ret+16(FP)
 	RET
 
-TEXT runtime·xchgp1(SB), NOSPLIT, $0-24
+TEXT runtime·xchgp(SB), NOSPLIT, $0-24
 	MOVQ	ptr+0(FP), BX
 	MOVQ	new+8(FP), AX
 	XCHGQ	AX, 0(BX)
@@ -581,7 +559,7 @@ again:
 	JNZ	again
 	RET
 
-TEXT runtime·atomicstorep1(SB), NOSPLIT, $0-16
+TEXT runtime·atomicstorep(SB), NOSPLIT, $0-16
 	MOVQ	ptr+0(FP), BX
 	MOVQ	val+8(FP), AX
 	XCHGQ	AX, 0(BX)
@@ -607,19 +585,6 @@ TEXT runtime·atomicor8(SB), NOSPLIT, $0-9
 	ORB	BX, (AX)
 	RET
 
-// void	runtime·atomicand8(byte volatile*, byte);
-TEXT runtime·atomicand8(SB), NOSPLIT, $0-9
-	MOVQ	ptr+0(FP), AX
-	MOVB	val+8(FP), BX
-	LOCK
-	ANDB	BX, (AX)
-	RET
-
-TEXT ·publicationBarrier(SB),NOSPLIT,$0-0
-	// Stores are already ordered on x86, so this is just a
-	// compile barrier.
-	RET
-
 // void jmpdefer(fn, sp);
 // called from deferreturn.
 // 1. pop the caller
@@ -643,34 +608,44 @@ TEXT gosave<>(SB),NOSPLIT,$0
 	MOVQ	R9, (g_sched+gobuf_sp)(R8)
 	MOVQ	$0, (g_sched+gobuf_ret)(R8)
 	MOVQ	$0, (g_sched+gobuf_ctxt)(R8)
-	MOVQ	BP, (g_sched+gobuf_bp)(R8)
 	RET
 
-// func asmcgocall(fn, arg unsafe.Pointer) int32
+// asmcgocall(void(*fn)(void*), void *arg)
 // Call fn(arg) on the scheduler stack,
 // aligned appropriately for the gcc ABI.
-// See cgocall.go for more details.
-TEXT ·asmcgocall(SB),NOSPLIT,$0-20
+// See cgocall.c for more details.
+TEXT ·asmcgocall(SB),NOSPLIT,$0-16
 	MOVQ	fn+0(FP), AX
 	MOVQ	arg+8(FP), BX
+	CALL	asmcgocall<>(SB)
+	RET
 
+TEXT ·asmcgocall_errno(SB),NOSPLIT,$0-20
+	MOVQ	fn+0(FP), AX
+	MOVQ	arg+8(FP), BX
+	CALL	asmcgocall<>(SB)
+	MOVL	AX, ret+16(FP)
+	RET
+
+// asmcgocall common code. fn in AX, arg in BX. returns errno in AX.
+TEXT asmcgocall<>(SB),NOSPLIT,$0-0
 	MOVQ	SP, DX
 
 	// Figure out if we need to switch to m->g0 stack.
 	// We get called to create new OS threads too, and those
 	// come in on the m->g0 stack already.
 	get_tls(CX)
-	MOVQ	g(CX), R8
-	MOVQ	g_m(R8), R8
-	MOVQ	m_g0(R8), SI
+	MOVQ	g(CX), BP
+	MOVQ	g_m(BP), BP
+	MOVQ	m_g0(BP), SI
 	MOVQ	g(CX), DI
 	CMPQ	SI, DI
 	JEQ	nosave
-	MOVQ	m_gsignal(R8), SI
+	MOVQ	m_gsignal(BP), SI
 	CMPQ	SI, DI
 	JEQ	nosave
 	
-	MOVQ	m_g0(R8), SI
+	MOVQ	m_g0(BP), SI
 	CALL	gosave<>(SB)
 	MOVQ	SI, g(CX)
 	MOVQ	(g_sched+gobuf_sp)(SI), SP
@@ -696,8 +671,6 @@ nosave:
 	SUBQ	40(SP), SI
 	MOVQ	DI, g(CX)
 	MOVQ	SI, SP
-
-	MOVL	AX, ret+16(FP)
 	RET
 
 // cgocallback(void (*fn)(void*), void *frame, uintptr framesize)
@@ -715,7 +688,7 @@ TEXT runtime·cgocallback(SB),NOSPLIT,$24-24
 	RET
 
 // cgocallback_gofunc(FuncVal*, void *frame, uintptr framesize)
-// See cgocall.go for more details.
+// See cgocall.c for more details.
 TEXT ·cgocallback_gofunc(SB),NOSPLIT,$8-24
 	NO_LOCAL_POINTERS
 
@@ -726,15 +699,15 @@ TEXT ·cgocallback_gofunc(SB),NOSPLIT,$8-24
 	// the linker analysis by using an indirect call through AX.
 	get_tls(CX)
 #ifdef GOOS_windows
-	MOVL	$0, BX
+	MOVL	$0, BP
 	CMPQ	CX, $0
 	JEQ	2(PC)
 #endif
-	MOVQ	g(CX), BX
-	CMPQ	BX, $0
+	MOVQ	g(CX), BP
+	CMPQ	BP, $0
 	JEQ	needm
-	MOVQ	g_m(BX), BX
-	MOVQ	BX, R8 // holds oldm until end of function
+	MOVQ	g_m(BP), BP
+	MOVQ	BP, R8 // holds oldm until end of function
 	JMP	havem
 needm:
 	MOVQ	$0, 0(SP)
@@ -742,8 +715,8 @@ needm:
 	CALL	AX
 	MOVQ	0(SP), R8
 	get_tls(CX)
-	MOVQ	g(CX), BX
-	MOVQ	g_m(BX), BX
+	MOVQ	g(CX), BP
+	MOVQ	g_m(BP), BP
 	
 	// Set m->sched.sp = SP, so that if a panic happens
 	// during the function we are about to execute, it will
@@ -753,10 +726,10 @@ needm:
 	// the same SP back to m->sched.sp. That seems redundant,
 	// but if an unrecovered panic happens, unwindm will
 	// restore the g->sched.sp from the stack location
-	// and then systemstack will try to use it. If we don't set it here,
+	// and then onM will try to use it. If we don't set it here,
 	// that restored SP will be uninitialized (typically 0) and
 	// will not be usable.
-	MOVQ	m_g0(BX), SI
+	MOVQ	m_g0(BP), SI
 	MOVQ	SP, (g_sched+gobuf_sp)(SI)
 
 havem:
@@ -765,7 +738,7 @@ 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).
-	MOVQ	m_g0(BX), SI
+	MOVQ	m_g0(BP), SI
 	MOVQ	(g_sched+gobuf_sp)(SI), AX
 	MOVQ	AX, 0(SP)
 	MOVQ	SP, (g_sched+gobuf_sp)(SI)
@@ -785,43 +758,30 @@ havem:
 	// the earlier calls.
 	//
 	// In the new goroutine, 0(SP) holds the saved R8.
-	MOVQ	m_curg(BX), SI
+	MOVQ	m_curg(BP), SI
 	MOVQ	SI, g(CX)
 	MOVQ	(g_sched+gobuf_sp)(SI), DI  // prepare stack as DI
-	MOVQ	(g_sched+gobuf_pc)(SI), BX
-	MOVQ	BX, -8(DI)
-	// Compute the size of the frame, including return PC and, if
-	// GOEXPERIMENT=framepointer, the saved based pointer
-	LEAQ	fv+0(FP), AX
-	SUBQ	SP, AX
-	SUBQ	AX, DI
-	MOVQ	DI, SP
-
+	MOVQ	(g_sched+gobuf_pc)(SI), BP
+	MOVQ	BP, -8(DI)
+	LEAQ	-(8+8)(DI), SP
 	MOVQ	R8, 0(SP)
 	CALL	runtime·cgocallbackg(SB)
 	MOVQ	0(SP), R8
 
-	// Compute the size of the frame again.  FP and SP have
-	// completely different values here than they did above,
-	// but only their difference matters.
-	LEAQ	fv+0(FP), AX
-	SUBQ	SP, AX
-
 	// Restore g->sched (== m->curg->sched) from saved values.
 	get_tls(CX)
 	MOVQ	g(CX), SI
-	MOVQ	SP, DI
-	ADDQ	AX, DI
-	MOVQ	-8(DI), BX
-	MOVQ	BX, (g_sched+gobuf_pc)(SI)
+	MOVQ	8(SP), BP
+	MOVQ	BP, (g_sched+gobuf_pc)(SI)
+	LEAQ	(8+8)(SP), DI
 	MOVQ	DI, (g_sched+gobuf_sp)(SI)
 
 	// Switch back to m->g0's stack and restore m->g0->sched.sp.
 	// (Unlike m->curg, the g0 goroutine never uses sched.pc,
 	// so we do not have to restore it.)
-	MOVQ	g(CX), BX
-	MOVQ	g_m(BX), BX
-	MOVQ	m_g0(BX), SI
+	MOVQ	g(CX), BP
+	MOVQ	g_m(BP), BP
+	MOVQ	m_g0(BP), SI
 	MOVQ	SI, g(CX)
 	MOVQ	(g_sched+gobuf_sp)(SI), SP
 	MOVQ	0(SP), AX
@@ -872,344 +832,135 @@ TEXT runtime·stackcheck(SB), NOSPLIT, $0-0
 	INT	$3
 	RET
 
-TEXT runtime·getcallerpc(SB),NOSPLIT,$8-16
+TEXT runtime·getcallerpc(SB),NOSPLIT,$0-16
 	MOVQ	argp+0(FP),AX		// addr of first arg
 	MOVQ	-8(AX),AX		// get calling pc
-	CMPQ	AX, runtime·stackBarrierPC(SB)
-	JNE	nobar
-	// Get original return PC.
-	CALL	runtime·nextBarrierPC(SB)
-	MOVQ	0(SP), AX
-nobar:
 	MOVQ	AX, ret+8(FP)
 	RET
 
-TEXT runtime·setcallerpc(SB),NOSPLIT,$8-16
+TEXT runtime·gogetcallerpc(SB),NOSPLIT,$0-16
+	MOVQ	p+0(FP),AX		// addr of first arg
+	MOVQ	-8(AX),AX		// get calling pc
+	MOVQ	AX,ret+8(FP)
+	RET
+
+TEXT runtime·setcallerpc(SB),NOSPLIT,$0-16
 	MOVQ	argp+0(FP),AX		// addr of first arg
 	MOVQ	pc+8(FP), BX
-	MOVQ	-8(AX), CX
-	CMPQ	CX, runtime·stackBarrierPC(SB)
-	JEQ	setbar
 	MOVQ	BX, -8(AX)		// set calling pc
 	RET
-setbar:
-	// Set the stack barrier return PC.
-	MOVQ	BX, 0(SP)
-	CALL	runtime·setNextBarrierPC(SB)
-	RET
 
 TEXT runtime·getcallersp(SB),NOSPLIT,$0-16
 	MOVQ	argp+0(FP), AX
 	MOVQ	AX, ret+8(FP)
 	RET
 
-// func cputicks() int64
+// func gogetcallersp(p unsafe.Pointer) uintptr
+TEXT runtime·gogetcallersp(SB),NOSPLIT,$0-16
+	MOVQ	p+0(FP),AX		// addr of first arg
+	MOVQ	AX, ret+8(FP)
+	RET
+
+// int64 runtime·cputicks(void)
 TEXT runtime·cputicks(SB),NOSPLIT,$0-0
-	CMPB	runtime·lfenceBeforeRdtsc(SB), $1
-	JNE	mfence
-	BYTE	$0x0f; BYTE $0xae; BYTE $0xe8 // LFENCE
-	JMP	done
-mfence:
-	BYTE	$0x0f; BYTE $0xae; BYTE $0xf0 // MFENCE
-done:
 	RDTSC
 	SHLQ	$32, DX
 	ADDQ	DX, AX
 	MOVQ	AX, ret+0(FP)
 	RET
 
-// memhash_varlen(p unsafe.Pointer, h seed) uintptr
-// redirects to memhash(p, h, size) using the size
-// stored in the closure.
-TEXT runtime·memhash_varlen(SB),NOSPLIT,$32-24
-	GO_ARGS
-	NO_LOCAL_POINTERS
-	MOVQ	p+0(FP), AX
-	MOVQ	h+8(FP), BX
-	MOVQ	8(DX), CX
-	MOVQ	AX, 0(SP)
-	MOVQ	BX, 8(SP)
-	MOVQ	CX, 16(SP)
-	CALL	runtime·memhash(SB)
-	MOVQ	24(SP), AX
-	MOVQ	AX, ret+16(FP)
-	RET
-
 // hash function using AES hardware instructions
 TEXT runtime·aeshash(SB),NOSPLIT,$0-32
 	MOVQ	p+0(FP), AX	// ptr to data
-	MOVQ	s+16(FP), CX	// size
-	LEAQ	ret+24(FP), DX
+	MOVQ	s+8(FP), CX	// size
 	JMP	runtime·aeshashbody(SB)
 
-TEXT runtime·aeshashstr(SB),NOSPLIT,$0-24
+TEXT runtime·aeshashstr(SB),NOSPLIT,$0-32
 	MOVQ	p+0(FP), AX	// ptr to string struct
+	// s+8(FP) is ignored, it is always sizeof(String)
 	MOVQ	8(AX), CX	// length of string
 	MOVQ	(AX), AX	// string data
-	LEAQ	ret+16(FP), DX
 	JMP	runtime·aeshashbody(SB)
 
 // AX: data
 // CX: length
-// DX: address to put return value
-TEXT runtime·aeshashbody(SB),NOSPLIT,$0-0
-	MOVQ	h+8(FP), X6	// seed to low 64 bits of xmm6
-	PINSRQ	$1, CX, X6	// size to high 64 bits of xmm6
-	PSHUFHW	$0, X6, X6	// replace size with its low 2 bytes repeated 4 times
-	MOVO	runtime·aeskeysched(SB), X7
+TEXT runtime·aeshashbody(SB),NOSPLIT,$0-32
+	MOVQ	h+16(FP), X0	// seed to low 64 bits of xmm0
+	PINSRQ	$1, CX, X0	// size to high 64 bits of xmm0
+	MOVO	runtime·aeskeysched+0(SB), X2
+	MOVO	runtime·aeskeysched+16(SB), X3
 	CMPQ	CX, $16
-	JB	aes0to15
-	JE	aes16
-	CMPQ	CX, $32
-	JBE	aes17to32
-	CMPQ	CX, $64
-	JBE	aes33to64
-	CMPQ	CX, $128
-	JBE	aes65to128
-	JMP	aes129plus
-
-aes0to15:
+	JB	aessmall
+aesloop:
+	CMPQ	CX, $16
+	JBE	aesloopend
+	MOVOU	(AX), X1
+	AESENC	X2, X0
+	AESENC	X1, X0
+	SUBQ	$16, CX
+	ADDQ	$16, AX
+	JMP	aesloop
+// 1-16 bytes remaining
+aesloopend:
+	// This load may overlap with the previous load above.
+	// We'll hash some bytes twice, but that's ok.
+	MOVOU	-16(AX)(CX*1), X1
+	JMP	partial
+// 0-15 bytes
+aessmall:
 	TESTQ	CX, CX
-	JE	aes0
+	JE	finalize	// 0 bytes
 
-	ADDQ	$16, AX
-	TESTW	$0xff0, AX
-	JE	endofpage
+	CMPB	AX, $0xf0
+	JA	highpartial
 
 	// 16 bytes loaded at this address won't cross
 	// a page boundary, so we can load it directly.
-	MOVOU	-16(AX), X0
+	MOVOU	(AX), X1
 	ADDQ	CX, CX
-	MOVQ	$masks<>(SB), AX
-	PAND	(AX)(CX*8), X0
-
-	// scramble 3 times
-	AESENC	X6, X0
-	AESENC	X7, X0
-	AESENC	X7, X0
-	MOVQ	X0, (DX)
-	RET
-
-endofpage:
+	MOVQ	$masks<>(SB), BP
+	PAND	(BP)(CX*8), X1
+	JMP	partial
+highpartial:
 	// address ends in 1111xxxx.  Might be up against
 	// a page boundary, so load ending at last byte.
 	// Then shift bytes down using pshufb.
-	MOVOU	-32(AX)(CX*1), X0
-	ADDQ	CX, CX
-	MOVQ	$shifts<>(SB), AX
-	PSHUFB	(AX)(CX*8), X0
-	AESENC	X6, X0
-	AESENC	X7, X0
-	AESENC	X7, X0
-	MOVQ	X0, (DX)
-	RET
-
-aes0:
-	// return input seed
-	MOVQ	h+8(FP), AX
-	MOVQ	AX, (DX)
-	RET
-
-aes16:
-	MOVOU	(AX), X0
-	AESENC	X6, X0
-	AESENC	X7, X0
-	AESENC	X7, X0
-	MOVQ	X0, (DX)
-	RET
-
-aes17to32:
-	// load data to be hashed
-	MOVOU	(AX), X0
 	MOVOU	-16(AX)(CX*1), X1
-
-	// scramble 3 times
-	AESENC	X6, X0
-	AESENC	runtime·aeskeysched+16(SB), X1
-	AESENC	X7, X0
-	AESENC	X7, X1
-	AESENC	X7, X0
-	AESENC	X7, X1
-
-	// combine results
-	PXOR	X1, X0
-	MOVQ	X0, (DX)
-	RET
-
-aes33to64:
-	MOVOU	(AX), X0
-	MOVOU	16(AX), X1
-	MOVOU	-32(AX)(CX*1), X2
-	MOVOU	-16(AX)(CX*1), X3
-	
-	AESENC	X6, X0
-	AESENC	runtime·aeskeysched+16(SB), X1
-	AESENC	runtime·aeskeysched+32(SB), X2
-	AESENC	runtime·aeskeysched+48(SB), X3
-	AESENC	X7, X0
-	AESENC	X7, X1
-	AESENC	X7, X2
-	AESENC	X7, X3
-	AESENC	X7, X0
-	AESENC	X7, X1
-	AESENC	X7, X2
-	AESENC	X7, X3
-
-	PXOR	X2, X0
-	PXOR	X3, X1
-	PXOR	X1, X0
-	MOVQ	X0, (DX)
-	RET
-
-aes65to128:
-	MOVOU	(AX), X0
-	MOVOU	16(AX), X1
-	MOVOU	32(AX), X2
-	MOVOU	48(AX), X3
-	MOVOU	-64(AX)(CX*1), X4
-	MOVOU	-48(AX)(CX*1), X5
-	MOVOU	-32(AX)(CX*1), X8
-	MOVOU	-16(AX)(CX*1), X9
-	
-	AESENC	X6, X0
-	AESENC	runtime·aeskeysched+16(SB), X1
-	AESENC	runtime·aeskeysched+32(SB), X2
-	AESENC	runtime·aeskeysched+48(SB), X3
-	AESENC	runtime·aeskeysched+64(SB), X4
-	AESENC	runtime·aeskeysched+80(SB), X5
-	AESENC	runtime·aeskeysched+96(SB), X8
-	AESENC	runtime·aeskeysched+112(SB), X9
-	AESENC	X7, X0
-	AESENC	X7, X1
-	AESENC	X7, X2
-	AESENC	X7, X3
-	AESENC	X7, X4
-	AESENC	X7, X5
-	AESENC	X7, X8
-	AESENC	X7, X9
-	AESENC	X7, X0
-	AESENC	X7, X1
-	AESENC	X7, X2
-	AESENC	X7, X3
-	AESENC	X7, X4
-	AESENC	X7, X5
-	AESENC	X7, X8
-	AESENC	X7, X9
-
-	PXOR	X4, X0
-	PXOR	X5, X1
-	PXOR	X8, X2
-	PXOR	X9, X3
-	PXOR	X2, X0
-	PXOR	X3, X1
-	PXOR	X1, X0
-	MOVQ	X0, (DX)
-	RET
-
-aes129plus:
-	// start with last (possibly overlapping) block
-	MOVOU	-128(AX)(CX*1), X0
-	MOVOU	-112(AX)(CX*1), X1
-	MOVOU	-96(AX)(CX*1), X2
-	MOVOU	-80(AX)(CX*1), X3
-	MOVOU	-64(AX)(CX*1), X4
-	MOVOU	-48(AX)(CX*1), X5
-	MOVOU	-32(AX)(CX*1), X8
-	MOVOU	-16(AX)(CX*1), X9
-
-	// scramble state once
-	AESENC	X6, X0
-	AESENC	runtime·aeskeysched+16(SB), X1
-	AESENC	runtime·aeskeysched+32(SB), X2
-	AESENC	runtime·aeskeysched+48(SB), X3
-	AESENC	runtime·aeskeysched+64(SB), X4
-	AESENC	runtime·aeskeysched+80(SB), X5
-	AESENC	runtime·aeskeysched+96(SB), X8
-	AESENC	runtime·aeskeysched+112(SB), X9
-
-	// compute number of remaining 128-byte blocks
-	DECQ	CX
-	SHRQ	$7, CX
-	
-aesloop:
-	// scramble state, xor in a block
-	MOVOU	(AX), X10
-	MOVOU	16(AX), X11
-	MOVOU	32(AX), X12
-	MOVOU	48(AX), X13
-	AESENC	X10, X0
-	AESENC	X11, X1
-	AESENC	X12, X2
-	AESENC	X13, X3
-	MOVOU	64(AX), X10
-	MOVOU	80(AX), X11
-	MOVOU	96(AX), X12
-	MOVOU	112(AX), X13
-	AESENC	X10, X4
-	AESENC	X11, X5
-	AESENC	X12, X8
-	AESENC	X13, X9
-
-	// scramble state
-	AESENC	X7, X0
-	AESENC	X7, X1
-	AESENC	X7, X2
-	AESENC	X7, X3
-	AESENC	X7, X4
-	AESENC	X7, X5
-	AESENC	X7, X8
-	AESENC	X7, X9
-
-	ADDQ	$128, AX
-	DECQ	CX
-	JNE	aesloop
-
-	// 2 more scrambles to finish
-	AESENC	X7, X0
-	AESENC	X7, X1
-	AESENC	X7, X2
-	AESENC	X7, X3
-	AESENC	X7, X4
-	AESENC	X7, X5
-	AESENC	X7, X8
-	AESENC	X7, X9
-	AESENC	X7, X0
-	AESENC	X7, X1
-	AESENC	X7, X2
-	AESENC	X7, X3
-	AESENC	X7, X4
-	AESENC	X7, X5
-	AESENC	X7, X8
-	AESENC	X7, X9
-
-	PXOR	X4, X0
-	PXOR	X5, X1
-	PXOR	X8, X2
-	PXOR	X9, X3
-	PXOR	X2, X0
-	PXOR	X3, X1
-	PXOR	X1, X0
-	MOVQ	X0, (DX)
-	RET
-	
-TEXT runtime·aeshash32(SB),NOSPLIT,$0-24
+	ADDQ	CX, CX
+	MOVQ	$shifts<>(SB), BP
+	PSHUFB	(BP)(CX*8), X1
+partial:
+	// incorporate partial block into hash
+	AESENC	X3, X0
+	AESENC	X1, X0
+finalize:	
+	// finalize hash
+	AESENC	X2, X0
+	AESENC	X3, X0
+	AESENC	X2, X0
+	MOVQ	X0, res+24(FP)
+	RET
+
+TEXT runtime·aeshash32(SB),NOSPLIT,$0-32
 	MOVQ	p+0(FP), AX	// ptr to data
-	MOVQ	h+8(FP), X0	// seed
+	// s+8(FP) is ignored, it is always sizeof(int32)
+	MOVQ	h+16(FP), X0	// seed
 	PINSRD	$2, (AX), X0	// data
 	AESENC	runtime·aeskeysched+0(SB), X0
 	AESENC	runtime·aeskeysched+16(SB), X0
-	AESENC	runtime·aeskeysched+32(SB), X0
-	MOVQ	X0, ret+16(FP)
+	AESENC	runtime·aeskeysched+0(SB), X0
+	MOVQ	X0, ret+24(FP)
 	RET
 
-TEXT runtime·aeshash64(SB),NOSPLIT,$0-24
+TEXT runtime·aeshash64(SB),NOSPLIT,$0-32
 	MOVQ	p+0(FP), AX	// ptr to data
-	MOVQ	h+8(FP), X0	// seed
+	// s+8(FP) is ignored, it is always sizeof(int64)
+	MOVQ	h+16(FP), X0	// seed
 	PINSRQ	$1, (AX), X0	// data
 	AESENC	runtime·aeskeysched+0(SB), X0
 	AESENC	runtime·aeskeysched+16(SB), X0
-	AESENC	runtime·aeskeysched+32(SB), X0
-	MOVQ	X0, ret+16(FP)
+	AESENC	runtime·aeskeysched+0(SB), X0
+	MOVQ	X0, ret+24(FP)
 	RET
 
 // simple mask to get rid of data in the high part of the register.
@@ -1288,44 +1039,38 @@ TEXT runtime·memeq(SB),NOSPLIT,$0-25
 	MOVQ	a+0(FP), SI
 	MOVQ	b+8(FP), DI
 	MOVQ	size+16(FP), BX
-	LEAQ	ret+24(FP), AX
-	JMP	runtime·memeqbody(SB)
-
-// memequal_varlen(a, b unsafe.Pointer) bool
-TEXT runtime·memequal_varlen(SB),NOSPLIT,$0-17
-	MOVQ	a+0(FP), SI
-	MOVQ	b+8(FP), DI
-	CMPQ	SI, DI
-	JEQ	eq
-	MOVQ	8(DX), BX    // compiler stores size at offset 8 in the closure
-	LEAQ	ret+16(FP), AX
-	JMP	runtime·memeqbody(SB)
-eq:
-	MOVB	$1, ret+16(FP)
+	CALL	runtime·memeqbody(SB)
+	MOVB	AX, ret+24(FP)
 	RET
 
 // eqstring tests whether two strings are equal.
-// The compiler guarantees that strings passed
-// to eqstring have equal length.
 // See runtime_test.go:eqstring_generic for
 // equivalent Go code.
 TEXT runtime·eqstring(SB),NOSPLIT,$0-33
+	MOVQ	s1len+8(FP), AX
+	MOVQ	s2len+24(FP), BX
+	CMPQ	AX, BX
+	JNE	different
 	MOVQ	s1str+0(FP), SI
 	MOVQ	s2str+16(FP), DI
 	CMPQ	SI, DI
-	JEQ	eq
-	MOVQ	s1len+8(FP), BX
-	LEAQ	v+32(FP), AX
-	JMP	runtime·memeqbody(SB)
-eq:
+	JEQ	same
+	CALL	runtime·memeqbody(SB)
+	MOVB	AX, v+32(FP)
+	RET
+same:
 	MOVB	$1, v+32(FP)
 	RET
+different:
+	MOVB	$0, v+32(FP)
+	RET
 
 // a in SI
 // b in DI
 // count in BX
-// address of result byte in AX
 TEXT runtime·memeqbody(SB),NOSPLIT,$0-0
+	XORQ	AX, AX
+
 	CMPQ	BX, $8
 	JB	small
 	
@@ -1354,7 +1099,6 @@ hugeloop:
 	SUBQ	$64, BX
 	CMPL	DX, $0xffff
 	JEQ	hugeloop
-	MOVB	$0, (AX)
 	RET
 
 	// 8 bytes at a time using 64-bit register
@@ -1368,7 +1112,6 @@ bigloop:
 	SUBQ	$8, BX
 	CMPQ	CX, DX
 	JEQ	bigloop
-	MOVB	$0, (AX)
 	RET
 
 	// remaining 0-8 bytes
@@ -1376,7 +1119,7 @@ leftover:
 	MOVQ	-8(SI)(BX*1), CX
 	MOVQ	-8(DI)(BX*1), DX
 	CMPQ	CX, DX
-	SETEQ	(AX)
+	SETEQ	AX
 	RET
 
 small:
@@ -1411,7 +1154,7 @@ di_finish:
 	SUBQ	SI, DI
 	SHLQ	CX, DI
 equal:
-	SETEQ	(AX)
+	SETEQ	AX
 	RET
 
 TEXT runtime·cmpstring(SB),NOSPLIT,$0-40
@@ -1419,73 +1162,75 @@ TEXT runtime·cmpstring(SB),NOSPLIT,$0-40
 	MOVQ	s1_len+8(FP), BX
 	MOVQ	s2_base+16(FP), DI
 	MOVQ	s2_len+24(FP), DX
-	LEAQ	ret+32(FP), R9
-	JMP	runtime·cmpbody(SB)
+	CALL	runtime·cmpbody(SB)
+	MOVQ	AX, ret+32(FP)
+	RET
 
-TEXT bytes·Compare(SB),NOSPLIT,$0-56
+TEXT runtime·cmpbytes(SB),NOSPLIT,$0-56
 	MOVQ	s1+0(FP), SI
 	MOVQ	s1+8(FP), BX
 	MOVQ	s2+24(FP), DI
 	MOVQ	s2+32(FP), DX
-	LEAQ	res+48(FP), R9
-	JMP	runtime·cmpbody(SB)
+	CALL	runtime·cmpbody(SB)
+	MOVQ	AX, res+48(FP)
+	RET
 
 // input:
 //   SI = a
 //   DI = b
 //   BX = alen
 //   DX = blen
-//   R9 = address of output word (stores -1/0/1 here)
+// output:
+//   AX = 1/0/-1
 TEXT runtime·cmpbody(SB),NOSPLIT,$0-0
 	CMPQ	SI, DI
-	JEQ	allsame
+	JEQ	cmp_allsame
 	CMPQ	BX, DX
-	MOVQ	DX, R8
-	CMOVQLT	BX, R8 // R8 = min(alen, blen) = # of bytes to compare
-	CMPQ	R8, $8
-	JB	small
-
-loop:
-	CMPQ	R8, $16
-	JBE	_0through16
+	MOVQ	DX, BP
+	CMOVQLT	BX, BP // BP = min(alen, blen) = # of bytes to compare
+	CMPQ	BP, $8
+	JB	cmp_small
+
+cmp_loop:
+	CMPQ	BP, $16
+	JBE	cmp_0through16
 	MOVOU	(SI), X0
 	MOVOU	(DI), X1
 	PCMPEQB X0, X1
 	PMOVMSKB X1, AX
 	XORQ	$0xffff, AX	// convert EQ to NE
-	JNE	diff16	// branch if at least one byte is not equal
+	JNE	cmp_diff16	// branch if at least one byte is not equal
 	ADDQ	$16, SI
 	ADDQ	$16, DI
-	SUBQ	$16, R8
-	JMP	loop
+	SUBQ	$16, BP
+	JMP	cmp_loop
 	
 	// AX = bit mask of differences
-diff16:
+cmp_diff16:
 	BSFQ	AX, BX	// index of first byte that differs
 	XORQ	AX, AX
 	MOVB	(SI)(BX*1), CX
 	CMPB	CX, (DI)(BX*1)
 	SETHI	AX
 	LEAQ	-1(AX*2), AX	// convert 1/0 to +1/-1
-	MOVQ	AX, (R9)
 	RET
 
 	// 0 through 16 bytes left, alen>=8, blen>=8
-_0through16:
-	CMPQ	R8, $8
-	JBE	_0through8
+cmp_0through16:
+	CMPQ	BP, $8
+	JBE	cmp_0through8
 	MOVQ	(SI), AX
 	MOVQ	(DI), CX
 	CMPQ	AX, CX
-	JNE	diff8
-_0through8:
-	MOVQ	-8(SI)(R8*1), AX
-	MOVQ	-8(DI)(R8*1), CX
+	JNE	cmp_diff8
+cmp_0through8:
+	MOVQ	-8(SI)(BP*1), AX
+	MOVQ	-8(DI)(BP*1), CX
 	CMPQ	AX, CX
-	JEQ	allsame
+	JEQ	cmp_allsame
 
 	// AX and CX contain parts of a and b that differ.
-diff8:
+cmp_diff8:
 	BSWAPQ	AX	// reverse order of bytes
 	BSWAPQ	CX
 	XORQ	AX, CX
@@ -1493,82 +1238,82 @@ diff8:
 	SHRQ	CX, AX	// move a's bit to bottom
 	ANDQ	$1, AX	// mask bit
 	LEAQ	-1(AX*2), AX // 1/0 => +1/-1
-	MOVQ	AX, (R9)
 	RET
 
 	// 0-7 bytes in common
-small:
-	LEAQ	(R8*8), CX	// bytes left -> bits left
+cmp_small:
+	LEAQ	(BP*8), CX	// bytes left -> bits left
 	NEGQ	CX		//  - bits lift (== 64 - bits left mod 64)
-	JEQ	allsame
+	JEQ	cmp_allsame
 
 	// load bytes of a into high bytes of AX
 	CMPB	SI, $0xf8
-	JA	si_high
+	JA	cmp_si_high
 	MOVQ	(SI), SI
-	JMP	si_finish
-si_high:
-	MOVQ	-8(SI)(R8*1), SI
+	JMP	cmp_si_finish
+cmp_si_high:
+	MOVQ	-8(SI)(BP*1), SI
 	SHRQ	CX, SI
-si_finish:
+cmp_si_finish:
 	SHLQ	CX, SI
 
 	// load bytes of b in to high bytes of BX
 	CMPB	DI, $0xf8
-	JA	di_high
+	JA	cmp_di_high
 	MOVQ	(DI), DI
-	JMP	di_finish
-di_high:
-	MOVQ	-8(DI)(R8*1), DI
+	JMP	cmp_di_finish
+cmp_di_high:
+	MOVQ	-8(DI)(BP*1), DI
 	SHRQ	CX, DI
-di_finish:
+cmp_di_finish:
 	SHLQ	CX, DI
 
 	BSWAPQ	SI	// reverse order of bytes
 	BSWAPQ	DI
 	XORQ	SI, DI	// find bit differences
-	JEQ	allsame
+	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
-	MOVQ	AX, (R9)
 	RET
 
-allsame:
+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
-	MOVQ	AX, (R9)
 	RET
 
-TEXT bytes·IndexByte(SB),NOSPLIT,$0-40
+TEXT bytes·IndexByte(SB),NOSPLIT,$0
 	MOVQ s+0(FP), SI
 	MOVQ s_len+8(FP), BX
 	MOVB c+24(FP), AL
-	LEAQ ret+32(FP), R8
-	JMP  runtime·indexbytebody(SB)
+	CALL runtime·indexbytebody(SB)
+	MOVQ AX, ret+32(FP)
+	RET
 
-TEXT strings·IndexByte(SB),NOSPLIT,$0-32
+TEXT strings·IndexByte(SB),NOSPLIT,$0
 	MOVQ s+0(FP), SI
 	MOVQ s_len+8(FP), BX
 	MOVB c+16(FP), AL
-	LEAQ ret+24(FP), R8
-	JMP  runtime·indexbytebody(SB)
+	CALL runtime·indexbytebody(SB)
+	MOVQ AX, ret+24(FP)
+	RET
 
 // input:
 //   SI: data
 //   BX: data len
 //   AL: byte sought
-//   R8: address to put result
+// output:
+//   AX
 TEXT runtime·indexbytebody(SB),NOSPLIT,$0
 	MOVQ SI, DI
 
 	CMPQ BX, $16
-	JLT small
+	JLT indexbyte_small
 
 	// round up to first 16-byte boundary
 	TESTQ $15, SI
@@ -1622,15 +1367,15 @@ condition:
 	JZ success
 
 failure:
-	MOVQ $-1, (R8)
+	MOVQ $-1, AX
 	RET
 
 // handle for lengths < 16
-small:
+indexbyte_small:
 	MOVQ BX, CX
 	REPN; SCASB
 	JZ success
-	MOVQ $-1, (R8)
+	MOVQ $-1, AX
 	RET
 
 // we've found the chunk containing the byte
@@ -1640,26 +1385,821 @@ ssesuccess:
 	BSFW DX, DX
 	SUBQ SI, DI
 	ADDQ DI, DX
-	MOVQ DX, (R8)
+	MOVQ DX, AX
 	RET
 
 success:
 	SUBQ SI, DI
 	SUBL $1, DI
-	MOVQ DI, (R8)
+	MOVQ DI, AX
 	RET
 
 TEXT bytes·Equal(SB),NOSPLIT,$0-49
 	MOVQ	a_len+8(FP), BX
 	MOVQ	b_len+32(FP), CX
+	XORQ	AX, AX
 	CMPQ	BX, CX
 	JNE	eqret
 	MOVQ	a+0(FP), SI
 	MOVQ	b+24(FP), DI
-	LEAQ	ret+48(FP), AX
-	JMP	runtime·memeqbody(SB)
+	CALL	runtime·memeqbody(SB)
 eqret:
-	MOVB	$0, ret+48(FP)
+	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·fastrand1(SB), NOSPLIT, $0-4
@@ -1695,34 +2235,3 @@ TEXT _cgo_topofstack(SB),NOSPLIT,$0
 TEXT runtime·goexit(SB),NOSPLIT,$0-0
 	BYTE	$0x90	// NOP
 	CALL	runtime·goexit1(SB)	// does not return
-	// traceback from goexit1 must hit code range of goexit
-	BYTE	$0x90	// NOP
-
-TEXT runtime·prefetcht0(SB),NOSPLIT,$0-8
-	MOVQ	addr+0(FP), AX
-	PREFETCHT0	(AX)
-	RET
-
-TEXT runtime·prefetcht1(SB),NOSPLIT,$0-8
-	MOVQ	addr+0(FP), AX
-	PREFETCHT1	(AX)
-	RET
-
-TEXT runtime·prefetcht2(SB),NOSPLIT,$0-8
-	MOVQ	addr+0(FP), AX
-	PREFETCHT2	(AX)
-	RET
-
-TEXT runtime·prefetchnta(SB),NOSPLIT,$0-8
-	MOVQ	addr+0(FP), AX
-	PREFETCHNTA	(AX)
-	RET
-
-// This is called from .init_array and follows the platform, not Go, ABI.
-TEXT runtime·addmoduledata(SB),NOSPLIT,$0-0
-	PUSHQ	R15 // The access to global variables below implicitly uses R15, which is callee-save
-	MOVQ	runtime·lastmoduledatap(SB), AX
-	MOVQ	DI, moduledata_next(AX)
-	MOVQ	DI, runtime·lastmoduledatap(SB)
-	POPQ	R15
-	RET
diff --git a/src/runtime/asm_amd64p32.s b/src/runtime/asm_amd64p32.s
index a5d6e81..a1116b5 100644
--- a/src/runtime/asm_amd64p32.s
+++ b/src/runtime/asm_amd64p32.s
@@ -2,8 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-#include "go_asm.h"
-#include "go_tls.h"
+#include "zasm_GOOS_GOARCH.h"
 #include "funcdata.h"
 #include "textflag.h"
 
@@ -73,7 +72,7 @@ ok:
 	CALL	runtime·schedinit(SB)
 
 	// create a new goroutine to start program
-	MOVL	$runtime·mainPC(SB), AX	// entry
+	MOVL	$runtime·main·f(SB), AX	// entry
 	MOVL	$0, 0(SP)
 	MOVL	AX, 4(SP)
 	CALL	runtime·newproc(SB)
@@ -84,8 +83,8 @@ ok:
 	MOVL	$0xf1, 0xf1  // crash
 	RET
 
-DATA	runtime·mainPC+0(SB)/4,$runtime·main(SB)
-GLOBL	runtime·mainPC(SB),RODATA,$4
+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
@@ -165,42 +164,55 @@ TEXT runtime·mcall(SB), NOSPLIT, $0-4
 	JMP	AX
 	RET
 
-// systemstack_switch is a dummy routine that systemstack leaves at the bottom
+// switchtoM is a dummy routine that onM leaves at the bottom
 // of the G stack.  We need to distinguish the routine that
 // lives at the bottom of the G stack from the one that lives
-// at the top of the system stack because the one at the top of
-// the system stack terminates the stack walk (see topofstack()).
-TEXT runtime·systemstack_switch(SB), NOSPLIT, $0-0
+// at the top of the M stack because the one at the top of
+// the M stack terminates the stack walk (see topofstack()).
+TEXT runtime·switchtoM(SB), NOSPLIT, $0-0
 	RET
 
-// func systemstack(fn func())
-TEXT runtime·systemstack(SB), NOSPLIT, $0-4
-	MOVL	fn+0(FP), DI	// DI = fn
+// func onM_signalok(fn func())
+TEXT runtime·onM_signalok(SB), NOSPLIT, $0-4
 	get_tls(CX)
 	MOVL	g(CX), AX	// AX = g
 	MOVL	g_m(AX), BX	// BX = m
-
 	MOVL	m_gsignal(BX), DX	// DX = gsignal
 	CMPL	AX, DX
-	JEQ	noswitch
+	JEQ	ongsignal
+	JMP	runtime·onM(SB)
+
+ongsignal:
+	MOVL	fn+0(FP), DI	// DI = fn
+	MOVL	DI, DX
+	MOVL	0(DI), DI
+	CALL	DI
+	RET
+
+// func onM(fn func())
+TEXT runtime·onM(SB), NOSPLIT, $0-4
+	MOVL	fn+0(FP), DI	// DI = fn
+	get_tls(CX)
+	MOVL	g(CX), AX	// AX = g
+	MOVL	g_m(AX), BX	// BX = m
 
 	MOVL	m_g0(BX), DX	// DX = g0
 	CMPL	AX, DX
-	JEQ	noswitch
+	JEQ	onm
 
 	MOVL	m_curg(BX), R8
 	CMPL	AX, R8
-	JEQ	switch
+	JEQ	oncurg
 	
 	// Not g0, not curg. Must be gsignal, but that's not allowed.
 	// Hide call from linker nosplit analysis.
-	MOVL	$runtime·badsystemstack(SB), AX
+	MOVL	$runtime·badonm(SB), AX
 	CALL	AX
 
-switch:
+oncurg:
 	// save our state in g->sched.  Pretend to
-	// be systemstack_switch if the G stack is scanned.
-	MOVL	$runtime·systemstack_switch(SB), SI
+	// be switchtoM if the G stack is scanned.
+	MOVL	$runtime·switchtoM(SB), SI
 	MOVL	SI, (g_sched+gobuf_pc)(AX)
 	MOVL	SP, (g_sched+gobuf_sp)(AX)
 	MOVL	AX, (g_sched+gobuf_g)(AX)
@@ -224,7 +236,7 @@ switch:
 	MOVL	$0, (g_sched+gobuf_sp)(AX)
 	RET
 
-noswitch:
+onm:
 	// already on m stack, just call directly
 	MOVL	DI, DX
 	MOVL	0(DI), DI
@@ -289,25 +301,8 @@ TEXT runtime·morestack_noctxt(SB),NOSPLIT,$0
 	MOVL	$0, DX
 	JMP	runtime·morestack(SB)
 
-TEXT runtime·stackBarrier(SB),NOSPLIT,$0
-	// We came here via a RET to an overwritten return PC.
-	// AX may be live. Other registers are available.
-
-	// Get the original return PC, g.stkbar[g.stkbarPos].savedLRVal.
-	get_tls(CX)
-	MOVL	g(CX), CX
-	MOVL	(g_stkbar+slice_array)(CX), DX
-	MOVL	g_stkbarPos(CX), BX
-	IMULL	$stkbar__size, BX	// Too big for SIB.
-	ADDL	DX, BX
-	MOVL	stkbar_savedLRVal(BX), BX
-	// Record that this stack barrier was hit.
-	ADDL	$1, g_stkbarPos(CX)
-	// Jump to the original return PC.
-	JMP	BX
-
 // reflectcall: call a function with the given argument list
-// func call(argtype *_type, f *FuncVal, arg *byte, argsize, retoffset uint32).
+// func call(f *FuncVal, arg *byte, argsize, retoffset 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!
@@ -319,11 +314,8 @@ TEXT runtime·stackBarrier(SB),NOSPLIT,$0
 	JMP	AX
 // Note: can't just "JMP NAME(SB)" - bad inlining results.
 
-TEXT reflect·call(SB), NOSPLIT, $0-0
-	JMP	·reflectcall(SB)
-
-TEXT ·reflectcall(SB), NOSPLIT, $0-20
-	MOVLQZX argsize+12(FP), CX
+TEXT ·reflectcall(SB), NOSPLIT, $0-16
+	MOVLQZX argsize+8(FP), CX
 	DISPATCH(runtime·call16, 16)
 	DISPATCH(runtime·call32, 32)
 	DISPATCH(runtime·call64, 64)
@@ -355,36 +347,26 @@ TEXT ·reflectcall(SB), NOSPLIT, $0-20
 	JMP	AX
 
 #define CALLFN(NAME,MAXSIZE)			\
-TEXT NAME(SB), WRAPPER, $MAXSIZE-20;		\
+TEXT NAME(SB), WRAPPER, $MAXSIZE-16;		\
 	NO_LOCAL_POINTERS;			\
 	/* copy arguments to stack */		\
-	MOVL	argptr+8(FP), SI;		\
-	MOVL	argsize+12(FP), CX;		\
+	MOVL	argptr+4(FP), SI;		\
+	MOVL	argsize+8(FP), CX;		\
 	MOVL	SP, DI;				\
 	REP;MOVSB;				\
 	/* call function */			\
-	MOVL	f+4(FP), DX;			\
+	MOVL	f+0(FP), DX;			\
 	MOVL	(DX), AX;			\
 	CALL	AX;				\
 	/* copy return values back */		\
-	MOVL	argptr+8(FP), DI;		\
-	MOVL	argsize+12(FP), CX;		\
-	MOVL	retoffset+16(FP), BX;		\
+	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;				\
-	/* execute write barrier updates */	\
-	MOVL	argtype+0(FP), DX;		\
-	MOVL	argptr+8(FP), DI;		\
-	MOVL	argsize+12(FP), CX;		\
-	MOVL	retoffset+16(FP), BX;		\
-	MOVL	DX, 0(SP);			\
-	MOVL	DI, 4(SP);			\
-	MOVL	CX, 8(SP);			\
-	MOVL	BX, 12(SP);			\
-	CALL	runtime·callwritebarrier(SB);	\
 	RET
 
 CALLFN(·call16, 16)
@@ -428,7 +410,12 @@ TEXT runtime·cas(SB), NOSPLIT, $0-17
 	MOVL	new+8(FP), CX
 	LOCK
 	CMPXCHGL	CX, 0(BX)
-	SETEQ	ret+16(FP)
+	JZ 4(PC)
+	MOVL	$0, AX
+	MOVB	AX, ret+16(FP)
+	RET
+	MOVL	$1, AX
+	MOVB	AX, ret+16(FP)
 	RET
 
 TEXT runtime·casuintptr(SB), NOSPLIT, $0-17
@@ -457,7 +444,13 @@ TEXT runtime·cas64(SB), NOSPLIT, $0-25
 	MOVQ	new+16(FP), CX
 	LOCK
 	CMPXCHGQ	CX, 0(BX)
-	SETEQ	ret+24(FP)
+	JNZ	cas64_fail
+	MOVL	$1, AX
+	MOVB	AX, ret+24(FP)
+	RET
+cas64_fail:
+	MOVL	$0, AX
+	MOVB	AX, ret+24(FP)
 	RET
 
 // bool casp(void **val, void *old, void *new)
@@ -467,13 +460,18 @@ TEXT runtime·cas64(SB), NOSPLIT, $0-25
 //		return 1;
 //	} else
 //		return 0;
-TEXT runtime·casp1(SB), NOSPLIT, $0-17
+TEXT runtime·casp(SB), NOSPLIT, $0-17
 	MOVL	ptr+0(FP), BX
 	MOVL	old+4(FP), AX
 	MOVL	new+8(FP), CX
 	LOCK
 	CMPXCHGL	CX, 0(BX)
-	SETEQ	ret+16(FP)
+	JZ 4(PC)
+	MOVL	$0, AX
+	MOVB	AX, ret+16(FP)
+	RET
+	MOVL	$1, AX
+	MOVB	AX, ret+16(FP)
 	RET
 
 // uint32 xadd(uint32 volatile *val, int32 delta)
@@ -500,9 +498,6 @@ TEXT runtime·xadd64(SB), NOSPLIT, $0-24
 	MOVQ	AX, ret+16(FP)
 	RET
 
-TEXT runtime·xadduintptr(SB), NOSPLIT, $0-12
-	JMP	runtime·xadd(SB)
-
 TEXT runtime·xchg(SB), NOSPLIT, $0-12
 	MOVL	ptr+0(FP), BX
 	MOVL	new+4(FP), AX
@@ -517,7 +512,7 @@ TEXT runtime·xchg64(SB), NOSPLIT, $0-24
 	MOVQ	AX, ret+16(FP)
 	RET
 
-TEXT runtime·xchgp1(SB), NOSPLIT, $0-12
+TEXT runtime·xchgp(SB), NOSPLIT, $0-12
 	MOVL	ptr+0(FP), BX
 	MOVL	new+4(FP), AX
 	XCHGL	AX, 0(BX)
@@ -535,7 +530,7 @@ again:
 	JNZ	again
 	RET
 
-TEXT runtime·atomicstorep1(SB), NOSPLIT, $0-8
+TEXT runtime·atomicstorep(SB), NOSPLIT, $0-8
 	MOVL	ptr+0(FP), BX
 	MOVL	val+4(FP), AX
 	XCHGL	AX, 0(BX)
@@ -561,19 +556,6 @@ TEXT runtime·atomicor8(SB), NOSPLIT, $0-5
 	ORB	AX, 0(BX)
 	RET
 
-// void	runtime·atomicand8(byte volatile*, byte);
-TEXT runtime·atomicand8(SB), NOSPLIT, $0-5
-	MOVL	ptr+0(FP), BX
-	MOVB	val+4(FP), AX
-	LOCK
-	ANDB	AX, 0(BX)
-	RET
-
-TEXT ·publicationBarrier(SB),NOSPLIT,$0-0
-	// Stores are already ordered on x86, so this is just a
-	// compile barrier.
-	RET
-
 // void jmpdefer(fn, sp);
 // called from deferreturn.
 // 1. pop the caller
@@ -587,9 +569,15 @@ TEXT runtime·jmpdefer(SB), NOSPLIT, $0-8
 	MOVL	0(DX), BX
 	JMP	BX	// but first run the deferred function
 
-// func asmcgocall(fn, arg unsafe.Pointer) int32
+// asmcgocall(void(*fn)(void*), void *arg)
 // Not implemented.
-TEXT runtime·asmcgocall(SB),NOSPLIT,$0-12
+TEXT runtime·asmcgocall(SB),NOSPLIT,$0-8
+	MOVL	0, AX
+	RET
+
+// asmcgocall(void(*fn)(void*), void *arg)
+// Not implemented.
+TEXT runtime·asmcgocall_errno(SB),NOSPLIT,$0-12
 	MOVL	0, AX
 	RET
 
@@ -632,37 +620,35 @@ TEXT runtime·memclr(SB),NOSPLIT,$0-8
 	STOSB
 	RET
 
-TEXT runtime·getcallerpc(SB),NOSPLIT,$8-12
+TEXT runtime·getcallerpc(SB),NOSPLIT,$0-12
 	MOVL	argp+0(FP),AX		// addr of first arg
 	MOVL	-8(AX),AX		// get calling pc
-	CMPL	AX, runtime·stackBarrierPC(SB)
-	JNE	nobar
-	// Get original return PC.
-	CALL	runtime·nextBarrierPC(SB)
-	MOVL	0(SP), AX
-nobar:
 	MOVL	AX, ret+8(FP)
 	RET
 
-TEXT runtime·setcallerpc(SB),NOSPLIT,$8-8
+TEXT runtime·gogetcallerpc(SB),NOSPLIT,$0-12
+	MOVL	p+0(FP),AX		// addr of first arg
+	MOVL	-8(AX),AX		// get calling pc
+	MOVL	AX, ret+8(FP)
+	RET
+
+TEXT runtime·setcallerpc(SB),NOSPLIT,$0-8
 	MOVL	argp+0(FP),AX		// addr of first arg
 	MOVL	pc+4(FP), BX		// pc to set
-	MOVL	-8(AX), CX
-	CMPL	CX, runtime·stackBarrierPC(SB)
-	JEQ	setbar
 	MOVQ	BX, -8(AX)		// set calling pc
 	RET
-setbar:
-	// Set the stack barrier return PC.
-	MOVL	BX, 0(SP)
-	CALL	runtime·setNextBarrierPC(SB)
-	RET
 
 TEXT runtime·getcallersp(SB),NOSPLIT,$0-12
 	MOVL	argp+0(FP), AX
 	MOVL	AX, ret+8(FP)
 	RET
 
+// func gogetcallersp(p unsafe.Pointer) uintptr
+TEXT runtime·gogetcallersp(SB),NOSPLIT,$0-12
+	MOVL	p+0(FP),AX		// addr of first arg
+	MOVL	AX, ret+8(FP)
+	RET
+
 // int64 runtime·cputicks(void)
 TEXT runtime·cputicks(SB),NOSPLIT,$0-0
 	RDTSC
@@ -671,23 +657,6 @@ TEXT runtime·cputicks(SB),NOSPLIT,$0-0
 	MOVQ	AX, ret+0(FP)
 	RET
 
-// memhash_varlen(p unsafe.Pointer, h seed) uintptr
-// redirects to memhash(p, h, size) using the size
-// stored in the closure.
-TEXT runtime·memhash_varlen(SB),NOSPLIT,$24-12
-	GO_ARGS
-	NO_LOCAL_POINTERS
-	MOVL	p+0(FP), AX
-	MOVL	h+4(FP), BX
-	MOVL	4(DX), CX
-	MOVL	AX, 0(SP)
-	MOVL	BX, 4(SP)
-	MOVL	CX, 8(SP)
-	CALL	runtime·memhash(SB)
-	MOVL	16(SP), AX
-	MOVL	AX, ret+8(FP)
-	RET
-
 // hash function using AES hardware instructions
 // For now, our one amd64p32 system (NaCl) does not
 // support using AES instructions, so have not bothered to
@@ -718,37 +687,27 @@ TEXT runtime·memeq(SB),NOSPLIT,$0-17
 	MOVB	AX, ret+16(FP)
 	RET
 
-// memequal_varlen(a, b unsafe.Pointer) bool
-TEXT runtime·memequal_varlen(SB),NOSPLIT,$0-9
-	MOVL    a+0(FP), SI
-	MOVL    b+4(FP), DI
-	CMPL    SI, DI
-	JEQ     eq
-	MOVL    4(DX), BX    // compiler stores size at offset 4 in the closure
-	CALL    runtime·memeqbody(SB)
-	MOVB    AX, ret+8(FP)
-	RET
-eq:
-	MOVB    $1, ret+8(FP)
-	RET
-
 // eqstring tests whether two strings are equal.
-// The compiler guarantees that strings passed
-// to eqstring have equal length.
 // See runtime_test.go:eqstring_generic for
 // equivalent Go code.
 TEXT runtime·eqstring(SB),NOSPLIT,$0-17
+	MOVL	s1len+4(FP), AX
+	MOVL	s2len+12(FP), BX
+	CMPL	AX, BX
+	JNE	different
 	MOVL	s1str+0(FP), SI
 	MOVL	s2str+8(FP), DI
 	CMPL	SI, DI
 	JEQ	same
-	MOVL	s1len+4(FP), BX
 	CALL	runtime·memeqbody(SB)
 	MOVB	AX, v+16(FP)
 	RET
 same:
 	MOVB	$1, v+16(FP)
 	RET
+different:
+	MOVB	$0, v+16(FP)
+	RET
 
 // a in SI
 // b in DI
@@ -857,13 +816,13 @@ TEXT runtime·cmpstring(SB),NOSPLIT,$0-20
 	MOVL	AX, ret+16(FP)
 	RET
 
-TEXT bytes·Compare(SB),NOSPLIT,$0-28
+TEXT runtime·cmpbytes(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)
-	MOVL	AX, res+24(FP)
+	MOVQ	AX, res+24(FP)
 	RET
 
 // input:
@@ -875,29 +834,29 @@ TEXT bytes·Compare(SB),NOSPLIT,$0-28
 //   AX = 1/0/-1
 TEXT runtime·cmpbody(SB),NOSPLIT,$0-0
 	CMPQ	SI, DI
-	JEQ	allsame
+	JEQ	cmp_allsame
 	CMPQ	BX, DX
 	MOVQ	DX, R8
 	CMOVQLT	BX, R8 // R8 = min(alen, blen) = # of bytes to compare
 	CMPQ	R8, $8
-	JB	small
+	JB	cmp_small
 
-loop:
+cmp_loop:
 	CMPQ	R8, $16
-	JBE	_0through16
+	JBE	cmp_0through16
 	MOVOU	(SI), X0
 	MOVOU	(DI), X1
 	PCMPEQB X0, X1
 	PMOVMSKB X1, AX
 	XORQ	$0xffff, AX	// convert EQ to NE
-	JNE	diff16	// branch if at least one byte is not equal
+	JNE	cmp_diff16	// branch if at least one byte is not equal
 	ADDQ	$16, SI
 	ADDQ	$16, DI
 	SUBQ	$16, R8
-	JMP	loop
+	JMP	cmp_loop
 	
 	// AX = bit mask of differences
-diff16:
+cmp_diff16:
 	BSFQ	AX, BX	// index of first byte that differs
 	XORQ	AX, AX
 	ADDQ	BX, SI
@@ -909,23 +868,23 @@ diff16:
 	RET
 
 	// 0 through 16 bytes left, alen>=8, blen>=8
-_0through16:
+cmp_0through16:
 	CMPQ	R8, $8
-	JBE	_0through8
+	JBE	cmp_0through8
 	MOVQ	(SI), AX
 	MOVQ	(DI), CX
 	CMPQ	AX, CX
-	JNE	diff8
-_0through8:
+	JNE	cmp_diff8
+cmp_0through8:
 	ADDQ	R8, SI
 	ADDQ	R8, DI
 	MOVQ	-8(SI), AX
 	MOVQ	-8(DI), CX
 	CMPQ	AX, CX
-	JEQ	allsame
+	JEQ	cmp_allsame
 
 	// AX and CX contain parts of a and b that differ.
-diff8:
+cmp_diff8:
 	BSWAPQ	AX	// reverse order of bytes
 	BSWAPQ	CX
 	XORQ	AX, CX
@@ -936,46 +895,46 @@ diff8:
 	RET
 
 	// 0-7 bytes in common
-small:
+cmp_small:
 	LEAQ	(R8*8), CX	// bytes left -> bits left
 	NEGQ	CX		//  - bits lift (== 64 - bits left mod 64)
-	JEQ	allsame
+	JEQ	cmp_allsame
 
 	// load bytes of a into high bytes of AX
 	CMPB	SI, $0xf8
-	JA	si_high
+	JA	cmp_si_high
 	MOVQ	(SI), SI
-	JMP	si_finish
-si_high:
+	JMP	cmp_si_finish
+cmp_si_high:
 	ADDQ	R8, SI
 	MOVQ	-8(SI), SI
 	SHRQ	CX, SI
-si_finish:
+cmp_si_finish:
 	SHLQ	CX, SI
 
 	// load bytes of b in to high bytes of BX
 	CMPB	DI, $0xf8
-	JA	di_high
+	JA	cmp_di_high
 	MOVQ	(DI), DI
-	JMP	di_finish
-di_high:
+	JMP	cmp_di_finish
+cmp_di_high:
 	ADDQ	R8, DI
 	MOVQ	-8(DI), DI
 	SHRQ	CX, DI
-di_finish:
+cmp_di_finish:
 	SHLQ	CX, DI
 
 	BSWAPQ	SI	// reverse order of bytes
 	BSWAPQ	DI
 	XORQ	SI, DI	// find bit differences
-	JEQ	allsame
+	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
 
-allsame:
+cmp_allsame:
 	XORQ	AX, AX
 	XORQ	CX, CX
 	CMPQ	BX, DX
@@ -984,7 +943,7 @@ allsame:
 	LEAQ	-1(CX)(AX*2), AX	// 1,0,-1 result
 	RET
 
-TEXT bytes·IndexByte(SB),NOSPLIT,$0-20
+TEXT bytes·IndexByte(SB),NOSPLIT,$0
 	MOVL s+0(FP), SI
 	MOVL s_len+4(FP), BX
 	MOVB c+12(FP), AL
@@ -992,7 +951,7 @@ TEXT bytes·IndexByte(SB),NOSPLIT,$0-20
 	MOVL AX, ret+16(FP)
 	RET
 
-TEXT strings·IndexByte(SB),NOSPLIT,$0-20
+TEXT strings·IndexByte(SB),NOSPLIT,$0
 	MOVL s+0(FP), SI
 	MOVL s_len+4(FP), BX
 	MOVB c+8(FP), AL
@@ -1010,7 +969,7 @@ TEXT runtime·indexbytebody(SB),NOSPLIT,$0
 	MOVL SI, DI
 
 	CMPL BX, $16
-	JLT small
+	JLT indexbyte_small
 
 	// round up to first 16-byte boundary
 	TESTL $15, SI
@@ -1068,7 +1027,7 @@ failure:
 	RET
 
 // handle for lengths < 16
-small:
+indexbyte_small:
 	MOVL BX, CX
 	REPN; SCASB
 	JZ success
@@ -1126,26 +1085,3 @@ TEXT runtime·return0(SB), NOSPLIT, $0
 TEXT runtime·goexit(SB),NOSPLIT,$0-0
 	BYTE	$0x90	// NOP
 	CALL	runtime·goexit1(SB)	// does not return
-	// traceback from goexit1 must hit code range of goexit
-	BYTE	$0x90	// NOP
-
-TEXT runtime·prefetcht0(SB),NOSPLIT,$0-4
-	MOVL	addr+0(FP), AX
-	PREFETCHT0	(AX)
-	RET
-
-TEXT runtime·prefetcht1(SB),NOSPLIT,$0-4
-	MOVL	addr+0(FP), AX
-	PREFETCHT1	(AX)
-	RET
-
-
-TEXT runtime·prefetcht2(SB),NOSPLIT,$0-4
-	MOVL	addr+0(FP), AX
-	PREFETCHT2	(AX)
-	RET
-
-TEXT runtime·prefetchnta(SB),NOSPLIT,$0-4
-	MOVL	addr+0(FP), AX
-	PREFETCHNTA	(AX)
-	RET
diff --git a/src/runtime/asm_arm.s b/src/runtime/asm_arm.s
index 9c32e42..0f3b5ee 100644
--- a/src/runtime/asm_arm.s
+++ b/src/runtime/asm_arm.s
@@ -2,8 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-#include "go_asm.h"
-#include "go_tls.h"
+#include "zasm_GOOS_GOARCH.h"
 #include "funcdata.h"
 #include "textflag.h"
 
@@ -39,14 +38,27 @@ TEXT runtime·rt0_go(SB),NOSPLIT,$-4
 
 	BL	runtime·emptyfunc(SB)	// fault if stack check is wrong
 
-	BL	runtime·_initcgo(SB)	// will clobber R0-R3
+#ifndef GOOS_nacl
+	// if there is an _cgo_init, call it.
+	MOVW	_cgo_init(SB), R4
+	CMP	$0, R4
+	B.EQ	nocgo
+	MRC     15, 0, R0, C13, C0, 3 	// load TLS base pointer
+	MOVW 	R0, R3 			// arg 3: TLS base pointer
+	MOVW 	$runtime·tlsg(SB), R2 	// arg 2: tlsg
+	MOVW	$setg_gcc<>(SB), R1 	// arg 1: setg
+	MOVW	g, R0 			// arg 0: G
+	BL	(R4) // will clobber R0-R3
+#endif
 
+nocgo:
 	// update stackguard after _cgo_init
 	MOVW	(g_stack+stack_lo)(g), R0
-	ADD	$const__StackGuard, R0
+	ADD	$const_StackGuard, R0
 	MOVW	R0, g_stackguard0(g)
 	MOVW	R0, g_stackguard1(g)
 
+	BL	runtime·checkgoarm(SB)
 	BL	runtime·check(SB)
 
 	// saved argc, argv
@@ -55,12 +67,11 @@ TEXT runtime·rt0_go(SB),NOSPLIT,$-4
 	MOVW	64(R13), R1
 	MOVW	R1, 8(R13)
 	BL	runtime·args(SB)
-	BL	runtime·checkgoarm(SB)
 	BL	runtime·osinit(SB)
 	BL	runtime·schedinit(SB)
 
 	// create a new goroutine to start program
-	MOVW	$runtime·mainPC(SB), R0
+	MOVW	$runtime·main·f(SB), R0
 	MOVW.W	R0, -4(R13)
 	MOVW	$8, R0
 	MOVW.W	R0, -4(R13)
@@ -76,8 +87,8 @@ TEXT runtime·rt0_go(SB),NOSPLIT,$-4
 	MOVW	$1000, R1
 	MOVW	R0, (R1)	// fail hard
 
-DATA	runtime·mainPC+0(SB)/4,$runtime·main(SB)
-GLOBL	runtime·mainPC(SB),RODATA,$4
+DATA	runtime·main·f+0(SB)/4,$runtime·main(SB)
+GLOBL	runtime·main·f(SB),RODATA,$4
 
 TEXT runtime·breakpoint(SB),NOSPLIT,$0-0
 	// gdb won't skip this breakpoint instruction automatically,
@@ -106,8 +117,8 @@ TEXT runtime·asminit(SB),NOSPLIT,$0-0
 // void gosave(Gobuf*)
 // save state in Gobuf; setjmp
 TEXT runtime·gosave(SB),NOSPLIT,$-4-4
-	MOVW	buf+0(FP), R0
-	MOVW	R13, gobuf_sp(R0)
+	MOVW	0(FP), R0		// gobuf
+	MOVW	SP, gobuf_sp(R0)
 	MOVW	LR, gobuf_pc(R0)
 	MOVW	g, gobuf_g(R0)
 	MOVW	$0, R11
@@ -119,7 +130,7 @@ TEXT runtime·gosave(SB),NOSPLIT,$-4-4
 // void gogo(Gobuf*)
 // restore state from Gobuf; longjmp
 TEXT runtime·gogo(SB),NOSPLIT,$-4-4
-	MOVW	buf+0(FP), R1
+	MOVW	0(FP), R1		// gobuf
 	MOVW	gobuf_g(R1), R0
 	BL	setg<>(SB)
 
@@ -133,7 +144,7 @@ TEXT runtime·gogo(SB),NOSPLIT,$-4-4
 	// after this point: it must be straight-line code until the
 	// final B instruction.
 	// See large comment in sigprof for more details.
-	MOVW	gobuf_sp(R1), R13	// restore SP==R13
+	MOVW	gobuf_sp(R1), SP	// restore SP
 	MOVW	gobuf_lr(R1), LR
 	MOVW	gobuf_ret(R1), R0
 	MOVW	gobuf_ctxt(R1), R7
@@ -152,7 +163,7 @@ TEXT runtime·gogo(SB),NOSPLIT,$-4-4
 // to keep running g.
 TEXT runtime·mcall(SB),NOSPLIT,$-4-4
 	// Save caller state in g->sched.
-	MOVW	R13, (g_sched+gobuf_sp)(g)
+	MOVW	SP, (g_sched+gobuf_sp)(g)
 	MOVW	LR, (g_sched+gobuf_pc)(g)
 	MOVW	$0, R11
 	MOVW	R11, (g_sched+gobuf_lr)(g)
@@ -170,57 +181,65 @@ TEXT runtime·mcall(SB),NOSPLIT,$-4-4
 	CMP	$0, R11
 	BL.NE	runtime·save_g(SB)
 	MOVW	fn+0(FP), R0
-	MOVW	(g_sched+gobuf_sp)(g), R13
-	SUB	$8, R13
-	MOVW	R1, 4(R13)
+	MOVW	(g_sched+gobuf_sp)(g), SP
+	SUB	$8, SP
+	MOVW	R1, 4(SP)
 	MOVW	R0, R7
 	MOVW	0(R0), R0
 	BL	(R0)
 	B	runtime·badmcall2(SB)
 	RET
 
-// systemstack_switch is a dummy routine that systemstack leaves at the bottom
+// switchtoM is a dummy routine that onM leaves at the bottom
 // of the G stack.  We need to distinguish the routine that
 // lives at the bottom of the G stack from the one that lives
-// at the top of the system stack because the one at the top of
-// the system stack terminates the stack walk (see topofstack()).
-TEXT runtime·systemstack_switch(SB),NOSPLIT,$0-0
+// at the top of the M stack because the one at the top of
+// the M stack terminates the stack walk (see topofstack()).
+TEXT runtime·switchtoM(SB),NOSPLIT,$0-0
 	MOVW	$0, R0
 	BL	(R0) // clobber lr to ensure push {lr} is kept
 	RET
 
-// func systemstack(fn func())
-TEXT runtime·systemstack(SB),NOSPLIT,$0-4
+// func onM_signalok(fn func())
+TEXT runtime·onM_signalok(SB), NOSPLIT, $-4-4
+	MOVW	g_m(g), R1
+	MOVW	m_gsignal(R1), R2
+	CMP	g, R2
+	B.EQ	ongsignal
+	B	runtime·onM(SB)
+
+ongsignal:
+	MOVW	fn+0(FP), R0
+	MOVW	R0, R7
+	MOVW	0(R0), R0
+	BL	(R0)
+	RET
+
+// func onM(fn func())
+TEXT runtime·onM(SB),NOSPLIT,$0-4
 	MOVW	fn+0(FP), R0	// R0 = fn
 	MOVW	g_m(g), R1	// R1 = m
 
-	MOVW	m_gsignal(R1), R2	// R2 = gsignal
-	CMP	g, R2
-	B.EQ	noswitch
-
 	MOVW	m_g0(R1), R2	// R2 = g0
 	CMP	g, R2
-	B.EQ	noswitch
+	B.EQ	onm
 
 	MOVW	m_curg(R1), R3
 	CMP	g, R3
-	B.EQ	switch
+	B.EQ	oncurg
 
-	// Bad: g is not gsignal, not g0, not curg. What is it?
+	// Not g0, not curg. Must be gsignal, but that's not allowed.
 	// Hide call from linker nosplit analysis.
-	MOVW	$runtime·badsystemstack(SB), R0
+	MOVW	$runtime·badonm(SB), R0
 	BL	(R0)
 
-switch:
+oncurg:
 	// save our state in g->sched.  Pretend to
-	// be systemstack_switch if the G stack is scanned.
-	MOVW	$runtime·systemstack_switch(SB), R3
-#ifdef GOOS_nacl
-	ADD	$4, R3, R3 // get past nacl-insert bic instruction
-#endif
+	// be switchtoM if the G stack is scanned.
+	MOVW	$runtime·switchtoM(SB), R3
 	ADD	$4, R3, R3 // get past push {lr}
 	MOVW	R3, (g_sched+gobuf_pc)(g)
-	MOVW	R13, (g_sched+gobuf_sp)(g)
+	MOVW	SP, (g_sched+gobuf_sp)(g)
 	MOVW	LR, (g_sched+gobuf_lr)(g)
 	MOVW	g, (g_sched+gobuf_g)(g)
 
@@ -230,11 +249,11 @@ switch:
 	BL	setg<>(SB)
 	MOVW	R5, R0
 	MOVW	(g_sched+gobuf_sp)(R2), R3
-	// make it look like mstart called systemstack on g0, to stop traceback
+	// make it look like mstart called onM on g0, to stop traceback
 	SUB	$4, R3, R3
 	MOVW	$runtime·mstart(SB), R4
 	MOVW	R4, 0(R3)
-	MOVW	R3, R13
+	MOVW	R3, SP
 
 	// call target function
 	MOVW	R0, R7
@@ -245,12 +264,12 @@ switch:
 	MOVW	g_m(g), R1
 	MOVW	m_curg(R1), R0
 	BL	setg<>(SB)
-	MOVW	(g_sched+gobuf_sp)(g), R13
+	MOVW	(g_sched+gobuf_sp)(g), SP
 	MOVW	$0, R3
 	MOVW	R3, (g_sched+gobuf_sp)(g)
 	RET
 
-noswitch:
+onm:
 	MOVW	R0, R7
 	MOVW	0(R0), R0
 	BL	(R0)
@@ -262,6 +281,7 @@ noswitch:
 
 // Called during function prolog when more stack is needed.
 // R1 frame size
+// R2 arg size
 // R3 prolog's LR
 // NB. we do not save R0 because we've forced 5c to pass all arguments
 // on the stack.
@@ -286,21 +306,21 @@ TEXT runtime·morestack(SB),NOSPLIT,$-4-0
 	// Called from f.
 	// Set g->sched to context in f.
 	MOVW	R7, (g_sched+gobuf_ctxt)(g)
-	MOVW	R13, (g_sched+gobuf_sp)(g)
+	MOVW	SP, (g_sched+gobuf_sp)(g)
 	MOVW	LR, (g_sched+gobuf_pc)(g)
 	MOVW	R3, (g_sched+gobuf_lr)(g)
 
 	// Called from f.
 	// Set m->morebuf to f's caller.
 	MOVW	R3, (m_morebuf+gobuf_pc)(R8)	// f's caller's PC
-	MOVW	R13, (m_morebuf+gobuf_sp)(R8)	// f's caller's SP
-	MOVW	$4(R13), R3			// f's argument pointer
+	MOVW	SP, (m_morebuf+gobuf_sp)(R8)	// f's caller's SP
+	MOVW	$4(SP), R3			// f's argument pointer
 	MOVW	g, (m_morebuf+gobuf_g)(R8)
 
 	// Call newstack on m->g0's stack.
 	MOVW	m_g0(R8), R0
 	BL	setg<>(SB)
-	MOVW	(g_sched+gobuf_sp)(g), R13
+	MOVW	(g_sched+gobuf_sp)(g), SP
 	BL	runtime·newstack(SB)
 
 	// Not reached, but make sure the return PC from the call to newstack
@@ -311,25 +331,8 @@ TEXT runtime·morestack_noctxt(SB),NOSPLIT,$-4-0
 	MOVW	$0, R7
 	B runtime·morestack(SB)
 
-TEXT runtime·stackBarrier(SB),NOSPLIT,$0
-	// We came here via a RET to an overwritten LR.
-	// R0 may be live. Other registers are available.
-
-	// Get the original return PC, g.stkbar[g.stkbarPos].savedLRVal.
-	MOVW	(g_stkbar+slice_array)(g), R4
-	MOVW	g_stkbarPos(g), R5
-	MOVW	$stkbar__size, R6
-	MUL	R5, R6
-	ADD	R4, R6
-	MOVW	stkbar_savedLRVal(R6), R6
-	// Record that this stack barrier was hit.
-	ADD	$1, R5
-	MOVW	R5, g_stkbarPos(g)
-	// Jump to the original return PC.
-	B	(R6)
-
 // reflectcall: call a function with the given argument list
-// func call(argtype *_type, f *FuncVal, arg *byte, argsize, retoffset uint32).
+// func call(f *FuncVal, arg *byte, argsize, retoffset 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!
@@ -340,11 +343,8 @@ TEXT runtime·stackBarrier(SB),NOSPLIT,$0
 	MOVW	$NAME(SB), R1;		\
 	B	(R1)
 
-TEXT reflect·call(SB), NOSPLIT, $0-0
-	B	·reflectcall(SB)
-
-TEXT ·reflectcall(SB),NOSPLIT,$-4-20
-	MOVW	argsize+12(FP), R0
+TEXT ·reflectcall(SB),NOSPLIT,$-4-16
+	MOVW	argsize+8(FP), R0
 	DISPATCH(runtime·call16, 16)
 	DISPATCH(runtime·call32, 32)
 	DISPATCH(runtime·call64, 64)
@@ -376,12 +376,12 @@ TEXT ·reflectcall(SB),NOSPLIT,$-4-20
 	B	(R1)
 
 #define CALLFN(NAME,MAXSIZE)			\
-TEXT NAME(SB), WRAPPER, $MAXSIZE-20;		\
+TEXT NAME(SB), WRAPPER, $MAXSIZE-16;		\
 	NO_LOCAL_POINTERS;			\
 	/* copy arguments to stack */		\
-	MOVW	argptr+8(FP), R0;		\
-	MOVW	argsize+12(FP), R2;		\
-	ADD	$4, R13, R1;			\
+	MOVW	argptr+4(FP), R0;		\
+	MOVW	argsize+8(FP), R2;		\
+	ADD	$4, SP, R1;			\
 	CMP	$0, R2;				\
 	B.EQ	5(PC);				\
 	MOVBU.P	1(R0), R5;			\
@@ -389,37 +389,24 @@ TEXT NAME(SB), WRAPPER, $MAXSIZE-20;		\
 	SUB	$1, R2, R2;			\
 	B	-5(PC);				\
 	/* call function */			\
-	MOVW	f+4(FP), R7;			\
+	MOVW	f+0(FP), R7;			\
 	MOVW	(R7), R0;			\
 	PCDATA  $PCDATA_StackMapIndex, $0;	\
 	BL	(R0);				\
 	/* copy return values back */		\
-	MOVW	argptr+8(FP), R0;		\
-	MOVW	argsize+12(FP), R2;		\
-	MOVW	retoffset+16(FP), R3;		\
-	ADD	$4, R13, R1;			\
+	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;				\
-loop:						\
 	CMP	$0, R2;				\
-	B.EQ	end;				\
+	RET.EQ	;				\
 	MOVBU.P	1(R1), R5;			\
 	MOVBU.P R5, 1(R0);			\
 	SUB	$1, R2, R2;			\
-	B	loop;				\
-end:						\
-	/* execute write barrier updates */	\
-	MOVW	argtype+0(FP), R1;		\
-	MOVW	argptr+8(FP), R0;		\
-	MOVW	argsize+12(FP), R2;		\
-	MOVW	retoffset+16(FP), R3;		\
-	MOVW	R1, 4(R13);			\
-	MOVW	R0, 8(R13);			\
-	MOVW	R2, 12(R13);			\
-	MOVW	R3, 16(R13);			\
-	BL	runtime·callwritebarrier(SB);	\
-	RET	
+	B	-5(PC)				\
 
 CALLFN(·call16, 16)
 CALLFN(·call32, 32)
@@ -459,11 +446,11 @@ CALLFN(·call1073741824, 1073741824)
 // 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(R13), LR
+	MOVW	0(SP), LR
 	MOVW	$-4(LR), LR	// BL deferreturn
 	MOVW	fv+0(FP), R7
-	MOVW	argp+4(FP), R13
-	MOVW	$-4(R13), R13	// SP is 4 below argp, due to saved LR
+	MOVW	argp+4(FP), SP
+	MOVW	$-4(SP), SP	// SP is 4 below argp, due to saved LR
 	MOVW	0(R7), R1
 	B	(R1)
 
@@ -477,14 +464,25 @@ TEXT gosave<>(SB),NOSPLIT,$0
 	MOVW	R11, (g_sched+gobuf_ctxt)(g)
 	RET
 
-// func asmcgocall(fn, arg unsafe.Pointer) int32
+// asmcgocall(void(*fn)(void*), void *arg)
 // Call fn(arg) on the scheduler stack,
 // aligned appropriately for the gcc ABI.
-// See cgocall.go for more details.
-TEXT ·asmcgocall(SB),NOSPLIT,$0-12
+// See cgocall.c for more details.
+TEXT	·asmcgocall(SB),NOSPLIT,$0-8
+	MOVW	fn+0(FP), R1
+	MOVW	arg+4(FP), R0
+	BL	asmcgocall<>(SB)
+	RET
+
+TEXT ·asmcgocall_errno(SB),NOSPLIT,$0-12
 	MOVW	fn+0(FP), R1
 	MOVW	arg+4(FP), R0
+	BL	asmcgocall<>(SB)
+	MOVW	R0, ret+8(FP)
+	RET
 
+TEXT asmcgocall<>(SB),NOSPLIT,$0-0
+	// fn in R1, arg in R0.
 	MOVW	R13, R2
 	MOVW	g, R4
 
@@ -494,7 +492,7 @@ TEXT ·asmcgocall(SB),NOSPLIT,$0-12
 	MOVW	g_m(g), R8
 	MOVW	m_g0(R8), R3
 	CMP	R3, g
-	BEQ	g0
+	BEQ	asmcgocall_g0
 	BL	gosave<>(SB)
 	MOVW	R0, R5
 	MOVW	R3, R0
@@ -503,7 +501,7 @@ TEXT ·asmcgocall(SB),NOSPLIT,$0-12
 	MOVW	(g_sched+gobuf_sp)(g), R13
 
 	// Now on a scheduling stack (a pthread-created stack).
-g0:
+asmcgocall_g0:
 	SUB	$24, R13
 	BIC	$0x7, R13	// alignment for gcc ABI
 	MOVW	R4, 20(R13) // save old g
@@ -521,8 +519,6 @@ g0:
 	SUB	R2, R1
 	MOVW	R5, R0
 	MOVW	R1, R13
-
-	MOVW	R0, ret+8(FP)
 	RET
 
 // cgocallback(void (*fn)(void*), void *frame, uintptr framesize)
@@ -540,7 +536,7 @@ TEXT runtime·cgocallback(SB),NOSPLIT,$12-12
 	RET
 
 // cgocallback_gofunc(void (*fn)(void*), void *frame, uintptr framesize)
-// See cgocall.go for more details.
+// See cgocall.c for more details.
 TEXT	·cgocallback_gofunc(SB),NOSPLIT,$8-12
 	NO_LOCAL_POINTERS
 	
@@ -568,7 +564,7 @@ TEXT	·cgocallback_gofunc(SB),NOSPLIT,$8-12
 	// the same SP back to m->sched.sp. That seems redundant,
 	// but if an unrecovered panic happens, unwindm will
 	// restore the g->sched.sp from the stack location
-	// and then systemstack will try to use it. If we don't set it here,
+	// and then onM will try to use it. If we don't set it here,
 	// that restored SP will be uninitialized (typically 0) and
 	// will not be usable.
 	MOVW	g_m(g), R8
@@ -655,34 +651,29 @@ TEXT setg<>(SB),NOSPLIT,$-4-0
 	MOVW	g, R0
 	RET
 
-TEXT runtime·getcallerpc(SB),NOSPLIT,$4-8
-	MOVW	8(R13), R0		// LR saved by caller
-	MOVW	runtime·stackBarrierPC(SB), R1
-	CMP	R0, R1
-	BNE	nobar
-	// Get original return PC.
-	BL	runtime·nextBarrierPC(SB)
-	MOVW	4(R13), R0
-nobar:
+TEXT runtime·getcallerpc(SB),NOSPLIT,$-4-4
+	MOVW	0(SP), R0
 	MOVW	R0, ret+4(FP)
 	RET
 
-TEXT runtime·setcallerpc(SB),NOSPLIT,$4-8
+TEXT runtime·gogetcallerpc(SB),NOSPLIT,$-4-8
+	MOVW	R14, ret+4(FP)
+	RET
+
+TEXT runtime·setcallerpc(SB),NOSPLIT,$-4-8
 	MOVW	pc+4(FP), R0
-	MOVW	8(R13), R1
-	MOVW	runtime·stackBarrierPC(SB), R2
-	CMP	R1, R2
-	BEQ	setbar
-	MOVW	R0, 8(R13)		// set LR in caller
+	MOVW	R0, 0(SP)
 	RET
-setbar:
-	// Set the stack barrier return PC.
-	MOVW	R0, 4(R13)
-	BL	runtime·setNextBarrierPC(SB)
+
+TEXT runtime·getcallersp(SB),NOSPLIT,$-4-4
+	MOVW	0(FP), R0
+	MOVW	$-4(R0), R0
+	MOVW	R0, ret+4(FP)
 	RET
 
-TEXT runtime·getcallersp(SB),NOSPLIT,$-4-8
-	MOVW	argp+0(FP), R0
+// func gogetcallersp(p unsafe.Pointer) uintptr
+TEXT runtime·gogetcallersp(SB),NOSPLIT,$-4-8
+	MOVW	0(FP), R0
 	MOVW	$-4(R0), R0
 	MOVW	R0, ret+4(FP)
 	RET
@@ -716,22 +707,10 @@ casl:
 	LDREX	(R1), R0
 	CMP	R0, R2
 	BNE	casfail
-
-	MOVB	runtime·goarm(SB), R11
-	CMP	$7, R11
-	BLT	2(PC)
-	WORD	$0xf57ff05a	// dmb ishst
-
 	STREX	R3, (R1), R0
 	CMP	$0, R0
 	BNE	casl
 	MOVW	$1, R0
-
-	MOVB	runtime·goarm(SB), R11
-	CMP	$7, R11
-	BLT	2(PC)
-	WORD	$0xf57ff05b	// dmb ish
-
 	MOVB	R0, ret+12(FP)
 	RET
 casfail:
@@ -751,22 +730,6 @@ TEXT runtime·atomicloaduint(SB),NOSPLIT,$0-8
 TEXT runtime·atomicstoreuintptr(SB),NOSPLIT,$0-8
 	B	runtime·atomicstore(SB)
 
-// armPublicationBarrier is a native store/store barrier for ARMv7+.
-// On earlier ARM revisions, armPublicationBarrier is a no-op.
-// This will not work on SMP ARMv6 machines, if any are in use.
-// To implement publiationBarrier in sys_$GOOS_arm.s using the native
-// instructions, use:
-//
-//	TEXT ·publicationBarrier(SB),NOSPLIT,$-4-0
-//		B	runtime·armPublicationBarrier(SB)
-//
-TEXT runtime·armPublicationBarrier(SB),NOSPLIT,$-4-0
-	MOVB	runtime·goarm(SB), R11
-	CMP	$7, R11
-	BLT	2(PC)
-	WORD $0xf57ff05e	// DMB ST
-	RET
-
 // AES hashing not implemented for ARM
 TEXT runtime·aeshash(SB),NOSPLIT,$-4-0
 	MOVW	$0, R0
@@ -781,23 +744,6 @@ TEXT runtime·aeshashstr(SB),NOSPLIT,$-4-0
 	MOVW	$0, R0
 	MOVW	(R0), R1
 
-// memhash_varlen(p unsafe.Pointer, h seed) uintptr
-// redirects to memhash(p, h, size) using the size
-// stored in the closure.
-TEXT runtime·memhash_varlen(SB),NOSPLIT,$16-12
-	GO_ARGS
-	NO_LOCAL_POINTERS
-	MOVW	p+0(FP), R0
-	MOVW	h+4(FP), R1
-	MOVW	4(R7), R2
-	MOVW	R0, 4(R13)
-	MOVW	R1, 8(R13)
-	MOVW	R2, 12(R13)
-	BL	runtime·memhash(SB)
-	MOVW	16(R13), R0
-	MOVW	R0, ret+8(FP)
-	RET
-
 TEXT runtime·memeq(SB),NOSPLIT,$-4-13
 	MOVW	a+0(FP), R1
 	MOVW	b+4(FP), R2
@@ -805,149 +751,86 @@ TEXT runtime·memeq(SB),NOSPLIT,$-4-13
 	ADD	R1, R3, R6
 	MOVW	$1, R0
 	MOVB	R0, ret+12(FP)
-loop:
+_next2:
 	CMP	R1, R6
 	RET.EQ
 	MOVBU.P	1(R1), R4
 	MOVBU.P	1(R2), R5
 	CMP	R4, R5
-	BEQ	loop
+	BEQ	_next2
 
 	MOVW	$0, R0
 	MOVB	R0, ret+12(FP)
 	RET
 
-// memequal_varlen(a, b unsafe.Pointer) bool
-TEXT runtime·memequal_varlen(SB),NOSPLIT,$16-9
-	MOVW	a+0(FP), R0
-	MOVW	b+4(FP), R1
-	CMP	R0, R1
-	BEQ	eq
-	MOVW	4(R7), R2    // compiler stores size at offset 4 in the closure
-	MOVW	R0, 4(R13)
-	MOVW	R1, 8(R13)
-	MOVW	R2, 12(R13)
-	BL	runtime·memeq(SB)
-	MOVB	16(R13), R0
-	MOVB	R0, ret+8(FP)
-	RET
-eq:
-	MOVW	$1, R0
-	MOVB	R0, ret+8(FP)
-	RET
-
-TEXT runtime·cmpstring(SB),NOSPLIT,$-4-20
-	MOVW	s1_base+0(FP), R2
-	MOVW	s1_len+4(FP), R0
-	MOVW	s2_base+8(FP), R3
-	MOVW	s2_len+12(FP), R1
-	ADD	$20, R13, R7
-	B	runtime·cmpbody(SB)
-
-TEXT bytes·Compare(SB),NOSPLIT,$-4-28
-	MOVW	s1+0(FP), R2
-	MOVW	s1+4(FP), R0
-	MOVW	s2+12(FP), R3
-	MOVW	s2+16(FP), R1
-	ADD	$28, R13, R7
-	B	runtime·cmpbody(SB)
-
-// On entry:
-// R0 is the length of s1
-// R1 is the length of s2
-// R2 points to the start of s1
-// R3 points to the start of s2
-// R7 points to return value (-1/0/1 will be written here)
-//
-// On exit:
-// R4, R5, and R6 are clobbered
-TEXT runtime·cmpbody(SB),NOSPLIT,$-4-0
-	CMP 	R0, R1
-	MOVW 	R0, R6
-	MOVW.LT	R1, R6	// R6 is min(R0, R1)
-
-	ADD	R2, R6	// R2 is current byte in s1, R6 is last byte in s1 to compare
-loop:
-	CMP	R2, R6
-	BEQ	samebytes // all compared bytes were the same; compare lengths
-	MOVBU.P	1(R2), R4
-	MOVBU.P	1(R3), R5
-	CMP	R4, R5
-	BEQ	loop
-	// bytes differed
-	MOVW.LT	$1, R0
-	MOVW.GT	$-1, R0
-	MOVW	R0, (R7)
-	RET
-samebytes:
-	CMP	R0, R1
-	MOVW.LT	$1, R0
-	MOVW.GT	$-1, R0
-	MOVW.EQ	$0, R0
-	MOVW	R0, (R7)
-	RET
-
 // eqstring tests whether two strings are equal.
-// The compiler guarantees that strings passed
-// to eqstring have equal length.
 // See runtime_test.go:eqstring_generic for
 // equivalent Go code.
 TEXT runtime·eqstring(SB),NOSPLIT,$-4-17
+	MOVW	s1len+4(FP), R0
+	MOVW	s2len+12(FP), R1
+	MOVW	$0, R7
+	CMP	R0, R1
+	MOVB.NE R7, v+16(FP)
+	RET.NE
 	MOVW	s1str+0(FP), R2
 	MOVW	s2str+8(FP), R3
 	MOVW	$1, R8
 	MOVB	R8, v+16(FP)
 	CMP	R2, R3
 	RET.EQ
-	MOVW	s1len+4(FP), R0
 	ADD	R2, R0, R6
-loop:
+_eqnext:
 	CMP	R2, R6
 	RET.EQ
 	MOVBU.P	1(R2), R4
 	MOVBU.P	1(R3), R5
 	CMP	R4, R5
-	BEQ	loop
-	MOVW	$0, R8
-	MOVB	R8, v+16(FP)
+	BEQ	_eqnext
+	MOVB	R7, v+16(FP)
 	RET
 
+// void setg_gcc(G*); set g called from gcc.
+TEXT setg_gcc<>(SB),NOSPLIT,$0
+	MOVW	R0, g
+	B		runtime·save_g(SB)
+
 // TODO: share code with memeq?
-TEXT bytes·Equal(SB),NOSPLIT,$0-25
+TEXT bytes·Equal(SB),NOSPLIT,$0
 	MOVW	a_len+4(FP), R1
 	MOVW	b_len+16(FP), R3
 	
 	CMP	R1, R3		// unequal lengths are not equal
-	B.NE	notequal
+	B.NE	_notequal
 
 	MOVW	a+0(FP), R0
 	MOVW	b+12(FP), R2
 	ADD	R0, R1		// end
 
-loop:
+_byteseq_next:
 	CMP	R0, R1
-	B.EQ	equal		// reached the end
+	B.EQ	_equal		// reached the end
 	MOVBU.P	1(R0), R4
 	MOVBU.P	1(R2), R5
 	CMP	R4, R5
-	B.EQ	loop
+	B.EQ	_byteseq_next
 
-notequal:
+_notequal:
 	MOVW	$0, R0
 	MOVBU	R0, ret+24(FP)
 	RET
 
-equal:
+_equal:
 	MOVW	$1, R0
 	MOVBU	R0, ret+24(FP)
 	RET
 
-TEXT bytes·IndexByte(SB),NOSPLIT,$0-20
+TEXT bytes·IndexByte(SB),NOSPLIT,$0
 	MOVW	s+0(FP), R0
 	MOVW	s_len+4(FP), R1
 	MOVBU	c+12(FP), R2	// byte to find
 	MOVW	R0, R4		// store base for later
-	ADD	R0, R1		// end
+	ADD	R0, R1		// end 
 
 _loop:
 	CMP	R0, R1
@@ -958,7 +841,7 @@ _loop:
 
 	SUB	$1, R0		// R0 will be one beyond the position we want
 	SUB	R4, R0		// remove base
-	MOVW    R0, ret+16(FP)
+	MOVW    R0, ret+16(FP) 
 	RET
 
 _notfound:
@@ -966,12 +849,12 @@ _notfound:
 	MOVW	R0, ret+16(FP)
 	RET
 
-TEXT strings·IndexByte(SB),NOSPLIT,$0-16
+TEXT strings·IndexByte(SB),NOSPLIT,$0
 	MOVW	s+0(FP), R0
 	MOVW	s_len+4(FP), R1
 	MOVBU	c+8(FP), R2	// byte to find
 	MOVW	R0, R4		// store base for later
-	ADD	R0, R1		// end
+	ADD	R0, R1		// end 
 
 _sib_loop:
 	CMP	R0, R1
@@ -982,7 +865,7 @@ _sib_loop:
 
 	SUB	$1, R0		// R0 will be one beyond the position we want
 	SUB	R4, R0		// remove base
-	MOVW	R0, ret+12(FP)
+	MOVW	R0, ret+12(FP) 
 	RET
 
 _sib_notfound:
@@ -990,6 +873,414 @@ _sib_notfound:
 	MOVW	R0, ret+12(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/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
+
 TEXT runtime·fastrand1(SB),NOSPLIT,$-4-4
 	MOVW	g_m(g), R1
 	MOVW	m_fastrand(R1), R0
@@ -1035,38 +1326,3 @@ TEXT _cgo_topofstack(SB),NOSPLIT,$8
 TEXT runtime·goexit(SB),NOSPLIT,$-4-0
 	MOVW	R0, R0	// NOP
 	BL	runtime·goexit1(SB)	// does not return
-	// traceback from goexit1 must hit code range of goexit
-	MOVW	R0, R0	// NOP
-
-TEXT runtime·prefetcht0(SB),NOSPLIT,$0-4
-	RET
-
-TEXT runtime·prefetcht1(SB),NOSPLIT,$0-4
-	RET
-
-TEXT runtime·prefetcht2(SB),NOSPLIT,$0-4
-	RET
-
-TEXT runtime·prefetchnta(SB),NOSPLIT,$0-4
-	RET
-
-// x -> x/1000000, x%1000000, called from Go with args, results on stack.
-TEXT runtime·usplit(SB),NOSPLIT,$0-12
-	MOVW	x+0(FP), R0
-	CALL	runtime·usplitR0(SB)
-	MOVW	R0, q+4(FP)
-	MOVW	R1, r+8(FP)
-	RET
-
-// R0, R1 = R0/1000000, R0%1000000
-TEXT runtime·usplitR0(SB),NOSPLIT,$0
-	// magic multiply to avoid software divide without available m.
-	// see output of go tool compile -S for x/1000000.
-	MOVW	R0, R3
-	MOVW	$1125899907, R1
-	MULLU	R1, R0, (R0, R1)
-	MOVW	R0>>18, R0
-	MOVW	$1000000, R1
-	MULU	R0, R1
-	SUB	R1, R3, R1
-	RET
diff --git a/src/runtime/atomic.go b/src/runtime/atomic.go
new file mode 100644
index 0000000..7e9d9b3
--- /dev/null
+++ b/src/runtime/atomic.go
@@ -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.
+
+// +build !arm
+
+package runtime
+
+import "unsafe"
+
+//go:noescape
+func xadd(ptr *uint32, delta int32) uint32
+
+//go:noescape
+func xadd64(ptr *uint64, delta int64) uint64
+
+//go:noescape
+func xchg(ptr *uint32, new uint32) uint32
+
+//go:noescape
+func xchg64(ptr *uint64, new uint64) uint64
+
+//go:noescape
+func xchgp(ptr unsafe.Pointer, new unsafe.Pointer) unsafe.Pointer
+
+//go:noescape
+func xchguintptr(ptr *uintptr, new uintptr) uintptr
+
+//go:noescape
+func atomicload(ptr *uint32) uint32
+
+//go:noescape
+func atomicload64(ptr *uint64) uint64
+
+//go:noescape
+func atomicloadp(ptr unsafe.Pointer) unsafe.Pointer
+
+//go:noescape
+func atomicor8(ptr *uint8, val uint8)
+
+//go:noescape
+func cas64(ptr *uint64, old, new uint64) bool
+
+//go:noescape
+func atomicstore(ptr *uint32, val uint32)
+
+//go:noescape
+func atomicstore64(ptr *uint64, val uint64)
+
+//go:noescape
+func atomicstorep(ptr unsafe.Pointer, val unsafe.Pointer)
diff --git a/src/runtime/atomic_386.c b/src/runtime/atomic_386.c
new file mode 100644
index 0000000..82d36f2
--- /dev/null
+++ b/src/runtime/atomic_386.c
@@ -0,0 +1,46 @@
+// 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 "textflag.h"
+
+#pragma textflag NOSPLIT
+uint32
+runtime·atomicload(uint32 volatile* addr)
+{
+	return *addr;
+}
+
+#pragma textflag NOSPLIT
+void*
+runtime·atomicloadp(void* volatile* addr)
+{
+	return *addr;
+}
+
+#pragma textflag NOSPLIT
+uint64
+runtime·xadd64(uint64 volatile* addr, int64 v)
+{
+	uint64 old;
+
+	do
+		old = *addr;
+	while(!runtime·cas64(addr, old, old+v));
+
+	return old+v;
+}
+
+#pragma textflag NOSPLIT
+uint64
+runtime·xchg64(uint64 volatile* addr, uint64 v)
+{
+	uint64 old;
+
+	do
+		old = *addr;
+	while(!runtime·cas64(addr, old, v));
+
+	return old;
+}
diff --git a/src/runtime/atomic_amd64x.c b/src/runtime/atomic_amd64x.c
new file mode 100644
index 0000000..7be57ac
--- /dev/null
+++ b/src/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 "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/runtime/atomic_arm.go b/src/runtime/atomic_arm.go
index 02a1f35..b1632cd 100644
--- a/src/runtime/atomic_arm.go
+++ b/src/runtime/atomic_arm.go
@@ -27,10 +27,6 @@ func xadd(val *uint32, delta int32) uint32 {
 	}
 }
 
-//go:noescape
-//go:linkname xadduintptr runtime.xadd
-func xadduintptr(ptr *uintptr, delta uintptr) uintptr
-
 //go:nosplit
 func xchg(addr *uint32, v uint32) uint32 {
 	for {
@@ -42,10 +38,10 @@ func xchg(addr *uint32, v uint32) uint32 {
 }
 
 //go:nosplit
-func xchgp1(addr unsafe.Pointer, v unsafe.Pointer) unsafe.Pointer {
+func xchgp(addr *unsafe.Pointer, v unsafe.Pointer) unsafe.Pointer {
 	for {
-		old := *(*unsafe.Pointer)(addr)
-		if casp1((*unsafe.Pointer)(addr), old, v) {
+		old := *addr
+		if casp(addr, old, v) {
 			return old
 		}
 	}
@@ -67,10 +63,10 @@ func atomicloadp(addr unsafe.Pointer) unsafe.Pointer {
 }
 
 //go:nosplit
-func atomicstorep1(addr unsafe.Pointer, v unsafe.Pointer) {
+func atomicstorep(addr unsafe.Pointer, v unsafe.Pointer) {
 	for {
 		old := *(*unsafe.Pointer)(addr)
-		if casp1((*unsafe.Pointer)(addr), old, v) {
+		if casp((*unsafe.Pointer)(addr), old, v) {
 			return
 		}
 	}
@@ -89,7 +85,7 @@ func atomicstore(addr *uint32, v uint32) {
 //go:nosplit
 func cas64(addr *uint64, old, new uint64) bool {
 	var ok bool
-	systemstack(func() {
+	onM(func() {
 		lock(addrLock(addr))
 		if *addr == old {
 			*addr = new
@@ -103,7 +99,7 @@ func cas64(addr *uint64, old, new uint64) bool {
 //go:nosplit
 func xadd64(addr *uint64, delta int64) uint64 {
 	var r uint64
-	systemstack(func() {
+	onM(func() {
 		lock(addrLock(addr))
 		r = *addr + uint64(delta)
 		*addr = r
@@ -115,7 +111,7 @@ func xadd64(addr *uint64, delta int64) uint64 {
 //go:nosplit
 func xchg64(addr *uint64, v uint64) uint64 {
 	var r uint64
-	systemstack(func() {
+	onM(func() {
 		lock(addrLock(addr))
 		r = *addr
 		*addr = v
@@ -127,7 +123,7 @@ func xchg64(addr *uint64, v uint64) uint64 {
 //go:nosplit
 func atomicload64(addr *uint64) uint64 {
 	var r uint64
-	systemstack(func() {
+	onM(func() {
 		lock(addrLock(addr))
 		r = *addr
 		unlock(addrLock(addr))
@@ -137,7 +133,7 @@ func atomicload64(addr *uint64) uint64 {
 
 //go:nosplit
 func atomicstore64(addr *uint64, v uint64) {
-	systemstack(func() {
+	onM(func() {
 		lock(addrLock(addr))
 		*addr = v
 		unlock(addrLock(addr))
@@ -157,19 +153,3 @@ func atomicor8(addr *uint8, v uint8) {
 		}
 	}
 }
-
-//go:nosplit
-func atomicand8(addr *uint8, v uint8) {
-	// Align down to 4 bytes and use 32-bit CAS.
-	uaddr := uintptr(unsafe.Pointer(addr))
-	addr32 := (*uint32)(unsafe.Pointer(uaddr &^ 3))
-	word := uint32(v) << ((uaddr & 3) * 8)    // little endian
-	mask := uint32(0xFF) << ((uaddr & 3) * 8) // little endian
-	word |= ^mask
-	for {
-		old := *addr32
-		if cas(addr32, old, old&word) {
-			return
-		}
-	}
-}
diff --git a/src/runtime/cgo/asm_arm.s b/src/runtime/cgo/asm_arm.s
index 9aeaf9a..6e57432 100644
--- a/src/runtime/cgo/asm_arm.s
+++ b/src/runtime/cgo/asm_arm.s
@@ -12,13 +12,13 @@ TEXT crosscall2(SB),NOSPLIT,$-4
 	/* 
 	 * We still need to save all callee save register as before, and then
 	 *  push 2 args for fn (R1 and R2).
-	 * Also note that at procedure entry in gc world, 4(R13) will be the
+	 * Also note that at procedure entry in 5c/5g world, 4(R13) will be the
 	 *  first arg, so we must push another dummy reg (R0) for 0(R13).
 	 *  Additionally, runtime·load_g will clobber R0, so we need to save R0
 	 *  nevertheless.
 	 */
 	MOVM.WP	[R0, R1, R2, R4, R5, R6, R7, R8, R9, g, R11, R12, R14], (R13)
 	BL	runtime·load_g(SB)
-	MOVW	R15, R14 // R15 is PC.
-	MOVW	0(R13), R15
-	MOVM.IAW	(R13), [R0, R1, R2, R4, R5, R6, R7, R8, R9, g, R11, R12, R15]
+	MOVW	PC, R14
+	MOVW	0(R13), PC
+	MOVM.IAW	(R13), [R0, R1, R2, R4, R5, R6, R7, R8, R9, g, R11, R12, PC]
diff --git a/src/runtime/cgo/callbacks.c b/src/runtime/cgo/callbacks.c
new file mode 100644
index 0000000..282beee
--- /dev/null
+++ b/src/runtime/cgo/callbacks.c
@@ -0,0 +1,83 @@
+// 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 "../cgocall.h"
+#include "textflag.h"
+
+// These utility functions are available to be called from code
+// compiled with gcc via crosscall2.
+
+// The declaration of crosscall2 is:
+//   void crosscall2(void (*fn)(void *, int), void *, int);
+// 
+// We need to export the symbol crosscall2 in order to support
+// callbacks from shared libraries. This applies regardless of
+// linking mode.
+#pragma cgo_export_static crosscall2
+#pragma cgo_export_dynamic crosscall2
+
+// Allocate memory.  This allocates the requested number of bytes in
+// memory controlled by the Go runtime.  The allocated memory will be
+// zeroed.  You are responsible for ensuring that the Go garbage
+// collector can see a pointer to the allocated memory for as long as
+// it is valid, e.g., by storing a pointer in a local variable in your
+// C function, or in memory allocated by the Go runtime.  If the only
+// pointers are in a C global variable or in memory allocated via
+// malloc, then the Go garbage collector may collect the memory.
+
+// Call like this in code compiled with gcc:
+//   struct { size_t len; void *ret; } a;
+//   a.len = /* number of bytes to allocate */;
+//   crosscall2(_cgo_allocate, &a, sizeof a);
+//   /* Here a.ret is a pointer to the allocated memory.  */
+
+void runtime·_cgo_allocate_internal(void);
+
+#pragma cgo_export_static _cgo_allocate
+#pragma cgo_export_dynamic _cgo_allocate
+#pragma textflag NOSPLIT
+void
+_cgo_allocate(void *a, int32 n)
+{
+	runtime·cgocallback((void(*)(void))runtime·_cgo_allocate_internal, a, n);
+}
+
+// Panic.  The argument is converted into a Go string.
+
+// Call like this in code compiled with gcc:
+//   struct { const char *p; } a;
+//   a.p = /* string to pass to panic */;
+//   crosscall2(_cgo_panic, &a, sizeof a);
+//   /* The function call will not return.  */
+
+void runtime·_cgo_panic_internal(void);
+
+#pragma cgo_export_static _cgo_panic
+#pragma cgo_export_dynamic _cgo_panic
+#pragma textflag NOSPLIT
+void
+_cgo_panic(void *a, int32 n)
+{
+	runtime·cgocallback((void(*)(void))runtime·_cgo_panic_internal, a, n);
+}
+
+#pragma cgo_import_static x_cgo_init
+extern void x_cgo_init(G*);
+void (*_cgo_init)(G*) = x_cgo_init;
+
+#pragma cgo_import_static x_cgo_malloc
+extern void x_cgo_malloc(void*);
+void (*_cgo_malloc)(void*) = x_cgo_malloc;
+
+#pragma cgo_import_static x_cgo_free
+extern void x_cgo_free(void*);
+void (*_cgo_free)(void*) = x_cgo_free;
+
+#pragma cgo_import_static x_cgo_thread_start
+extern void x_cgo_thread_start(void*);
+void (*_cgo_thread_start)(void*) = x_cgo_thread_start;
+
+#pragma cgo_export_static _cgo_topofstack
+#pragma cgo_export_dynamic _cgo_topofstack
diff --git a/src/runtime/cgo/cgo.go b/src/runtime/cgo/cgo.go
index cb24678..8528692 100644
--- a/src/runtime/cgo/cgo.go
+++ b/src/runtime/cgo/cgo.go
@@ -11,9 +11,7 @@ package cgo
 
 /*
 
-#cgo darwin,!arm,!arm64 LDFLAGS: -lpthread
-#cgo darwin,arm LDFLAGS: -framework CoreFoundation
-#cgo darwin,arm64 LDFLAGS: -framework CoreFoundation
+#cgo darwin LDFLAGS: -lpthread
 #cgo dragonfly LDFLAGS: -lpthread
 #cgo freebsd LDFLAGS: -lpthread
 #cgo android LDFLAGS: -llog
@@ -24,7 +22,5 @@ package cgo
 
 #cgo CFLAGS: -Wall -Werror
 
-#cgo solaris CPPFLAGS: -D_POSIX_PTHREAD_SEMANTICS
-
 */
 import "C"
diff --git a/src/runtime/cgo/dragonfly.c b/src/runtime/cgo/dragonfly.c
new file mode 100644
index 0000000..c233c8b
--- /dev/null
+++ b/src/runtime/cgo/dragonfly.c
@@ -0,0 +1,19 @@
+// 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.
+
+// +build dragonfly
+
+#include "textflag.h"
+
+// Supply environ and __progname, because we don't
+// link against the standard DragonFly crt0.o and the
+// libc dynamic library needs them.
+
+#pragma dataflag NOPTR
+char *environ[1];
+#pragma dataflag NOPTR
+char *__progname;
+
+#pragma dynexport environ environ
+#pragma dynexport __progname __progname
diff --git a/src/runtime/cgo/freebsd.c b/src/runtime/cgo/freebsd.c
new file mode 100644
index 0000000..4876b2a
--- /dev/null
+++ b/src/runtime/cgo/freebsd.c
@@ -0,0 +1,19 @@
+// 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.
+
+// +build freebsd
+
+#include "textflag.h"
+
+// Supply environ and __progname, because we don't
+// link against the standard FreeBSD crt0.o and the
+// libc dynamic library needs them.
+
+#pragma dataflag NOPTR
+char *environ[1];
+#pragma dataflag NOPTR
+char *__progname;
+
+#pragma dynexport environ environ
+#pragma dynexport __progname __progname
diff --git a/src/runtime/cgo/gcc_android_arm.c b/src/runtime/cgo/gcc_android_arm.c
index 85cd244..07f7e72 100644
--- a/src/runtime/cgo/gcc_android_arm.c
+++ b/src/runtime/cgo/gcc_android_arm.c
@@ -12,10 +12,8 @@
 
 // PTHREAD_KEYS_MAX has been added to sys/limits.h at head in bionic:
 // https://android.googlesource.com/platform/bionic/+/master/libc/include/sys/limits.h
-// TODO(crawshaw): remove this definition when NDK r10d is required.
-#ifndef PTHREAD_KEYS_MAX
+// TODO(crawshaw): remove this definition when a new NDK is released.
 #define PTHREAD_KEYS_MAX 128
-#endif
 
 // inittls allocates a thread-local storage slot for g.
 //
diff --git a/src/runtime/cgo/gcc_arm.S b/src/runtime/cgo/gcc_arm.S
index 980ab57..d5833bf 100644
--- a/src/runtime/cgo/gcc_arm.S
+++ b/src/runtime/cgo/gcc_arm.S
@@ -11,10 +11,6 @@
 #define EXT(s) s
 #endif
 
-// Apple's ld64 wants 4-byte alignment for ARM code sections.
-// .align in both Apple as and GNU as treat n as aligning to 2**n bytes.
-.align	2
-
 /*
  * void crosscall_arm1(void (*fn)(void), void (*setg_gcc)(void *g), void *g)
  *
diff --git a/src/runtime/cgo/gcc_dragonfly_386.c b/src/runtime/cgo/gcc_dragonfly_386.c
new file mode 100644
index 0000000..074418f
--- /dev/null
+++ b/src/runtime/cgo/gcc_dragonfly_386.c
@@ -0,0 +1,70 @@
+// 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 <sys/types.h>
+#include <sys/signalvar.h>
+#include <pthread.h>
+#include <signal.h>
+#include <string.h>
+#include "libcgo.h"
+
+static void* threadentry(void*);
+static void (*setg_gcc)(void*);
+
+void
+x_cgo_init(G *g, void (*setg)(void*))
+{
+	pthread_attr_t attr;
+	size_t size;
+
+	setg_gcc = setg;
+	pthread_attr_init(&attr);
+	pthread_attr_getstacksize(&attr, &size);
+	g->stacklo = (uintptr)&attr - size + 4096;
+	pthread_attr_destroy(&attr);
+}
+
+
+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);
+
+	pthread_attr_init(&attr);
+	pthread_attr_getstacksize(&attr, &size);
+	// Leave stacklo=0 and set stackhi=size; mstack will do the rest.
+	ts->g->stackhi = 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();
+	}
+}
+
+static void*
+threadentry(void *v)
+{
+	ThreadStart ts;
+
+	ts = *(ThreadStart*)v;
+	free(v);
+
+	/*
+	 * Set specific keys.
+	 */
+	setg_gcc((void*)ts.g);
+
+	crosscall_386(ts.fn);
+	return nil;
+}
diff --git a/src/runtime/cgo/gcc_setenv.c b/src/runtime/cgo/gcc_setenv.c
index ca29dcb..af0fc5d 100644
--- a/src/runtime/cgo/gcc_setenv.c
+++ b/src/runtime/cgo/gcc_setenv.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 solaris
+// +build darwin dragonfly freebsd linux netbsd openbsd
 
 #include "libcgo.h"
 
diff --git a/src/runtime/cgo/iscgo.c b/src/runtime/cgo/iscgo.c
new file mode 100644
index 0000000..0907a19
--- /dev/null
+++ b/src/runtime/cgo/iscgo.c
@@ -0,0 +1,15 @@
+// Copyright 2010 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// The runtime package contains an uninitialized definition
+// for runtime·iscgo.  Override it to tell the runtime we're here.
+// There are various function pointers that should be set too,
+// but those depend on dynamic linker magic to get initialized
+// correctly, and sometimes they break.  This variable is a
+// backup: it depends only on old C style static linking rules.
+
+#include "../runtime.h"
+
+bool runtime·iscgo = 1;
+uint32 runtime·needextram = 1;  // create an extra M on first cgo call
diff --git a/src/runtime/cgo/libcgo.h b/src/runtime/cgo/libcgo.h
index bda2499..9d918fd 100644
--- a/src/runtime/cgo/libcgo.h
+++ b/src/runtime/cgo/libcgo.h
@@ -45,22 +45,11 @@ struct ThreadStart
 extern void (*_cgo_thread_start)(ThreadStart *ts);
 
 /*
- * Creates a new operating system thread without updating any Go state
- * (OS dependent).
- */
-extern void (*_cgo_sys_thread_create)(void* (*func)(void*), void* arg);
-
-/*
  * Creates the new operating system thread (OS, arch dependent).
  */
 void _cgo_sys_thread_start(ThreadStart *ts);
 
 /*
- * Waits for the Go runtime to be initialized (OS dependent).
- */
-void _cgo_wait_runtime_init_done();
-
-/*
  * Call fn in the 6c world.
  */
 void crosscall_amd64(void (*fn)(void));
@@ -74,13 +63,3 @@ void crosscall_386(void (*fn)(void));
  * Prints error then calls abort. For linux and android.
  */
 void fatalf(const char* format, ...);
-
-/*
- * Registers the current mach thread port for EXC_BAD_ACCESS processing.
- */
-void darwin_arm_init_thread_exception_port(void);
-
-/*
- * Starts a mach message server processing EXC_BAD_ACCESS.
- */
-void darwin_arm_init_mach_exception_handler(void);
diff --git a/src/runtime/cgo/netbsd.c b/src/runtime/cgo/netbsd.c
new file mode 100644
index 0000000..076cc87
--- /dev/null
+++ b/src/runtime/cgo/netbsd.c
@@ -0,0 +1,19 @@
+// 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.
+
+// +build netbsd
+
+#include "textflag.h"
+
+// Supply environ and __progname, because we don't
+// link against the standard NetBSD crt0.o and the
+// libc dynamic library needs them.
+
+#pragma dataflag NOPTR
+char *environ[1];
+#pragma dataflag NOPTR
+char *__progname;
+
+#pragma dynexport environ environ
+#pragma dynexport __progname __progname
diff --git a/src/runtime/cgo/openbsd.c b/src/runtime/cgo/openbsd.c
new file mode 100644
index 0000000..4766495
--- /dev/null
+++ b/src/runtime/cgo/openbsd.c
@@ -0,0 +1,27 @@
+// 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.
+
+// +build openbsd
+
+#include "textflag.h"
+
+// Supply environ, __progname and __guard_local, because
+// we don't link against the standard OpenBSD crt0.o and
+// the libc dynamic library needs them.
+
+#pragma dataflag NOPTR
+char *environ[1];
+#pragma dataflag NOPTR
+char *__progname;
+long __guard_local;
+
+#pragma dynexport environ environ
+#pragma dynexport __progname __progname
+
+// This is normally marked as hidden and placed in the
+// .openbsd.randomdata section.
+#pragma dynexport __guard_local __guard_local
+
+// We override pthread_create to support PT_TLS.
+#pragma dynexport pthread_create pthread_create
diff --git a/src/runtime/cgo/setenv.c b/src/runtime/cgo/setenv.c
new file mode 100644
index 0000000..76d88cb
--- /dev/null
+++ b/src/runtime/cgo/setenv.c
@@ -0,0 +1,13 @@
+// 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 dragonfly freebsd linux netbsd openbsd
+
+#pragma cgo_import_static x_cgo_setenv
+#pragma cgo_import_static x_cgo_unsetenv
+
+void x_cgo_setenv(char**);
+void (*runtime·_cgo_setenv)(char**) = x_cgo_setenv;
+void x_cgo_unsetenv(char**);
+void (*runtime·_cgo_unsetenv)(char**) = x_cgo_unsetenv;
diff --git a/src/runtime/cgocall.go b/src/runtime/cgocall.go
index f09a66a..7fd9146 100644
--- a/src/runtime/cgocall.go
+++ b/src/runtime/cgocall.go
@@ -83,19 +83,29 @@ import "unsafe"
 
 // Call from Go to C.
 //go:nosplit
-func cgocall(fn, arg unsafe.Pointer) int32 {
+func cgocall(fn, arg unsafe.Pointer) {
+	cgocall_errno(fn, arg)
+}
+
+//go:nosplit
+func cgocall_errno(fn, arg unsafe.Pointer) int32 {
 	if !iscgo && GOOS != "solaris" && GOOS != "windows" {
-		throw("cgocall unavailable")
+		gothrow("cgocall unavailable")
 	}
 
 	if fn == nil {
-		throw("cgocall nil")
+		gothrow("cgocall nil")
 	}
 
 	if raceenabled {
 		racereleasemerge(unsafe.Pointer(&racecgosync))
 	}
 
+	// Create an extra M for callbacks on threads not created by Go on first cgo call.
+	if needextram == 1 && cas(&needextram, 1, 0) {
+		onM(newextram)
+	}
+
 	/*
 	 * Lock g to m to ensure we stay on the same stack if we do a
 	 * cgo callback. Add entry to defer stack in case of panic.
@@ -117,9 +127,9 @@ func cgocall(fn, arg unsafe.Pointer) int32 {
 	 * so it is safe to call while "in a system call", outside
 	 * the $GOMAXPROCS accounting.
 	 */
-	entersyscall(0)
-	errno := asmcgocall(fn, arg)
-	exitsyscall(0)
+	entersyscall()
+	errno := asmcgocall_errno(fn, arg)
+	exitsyscall()
 
 	return errno
 }
@@ -127,6 +137,12 @@ func cgocall(fn, arg unsafe.Pointer) int32 {
 //go:nosplit
 func endcgo(mp *m) {
 	mp.ncgo--
+	if mp.ncgo == 0 {
+		// We are going back to Go and are not in a recursive
+		// call.  Let the GC collect any memory allocated via
+		// _cgo_allocate that is no longer referenced.
+		mp.cgomal = nil
+	}
 
 	if raceenabled {
 		raceacquire(unsafe.Pointer(&racecgosync))
@@ -137,21 +153,25 @@ func endcgo(mp *m) {
 
 // Helper functions for cgo code.
 
+// Filled by schedinit from corresponding C variables,
+// which are in turn filled in by dynamic linker when Cgo is available.
+var cgoMalloc, cgoFree unsafe.Pointer
+
 func cmalloc(n uintptr) unsafe.Pointer {
 	var args struct {
 		n   uint64
 		ret unsafe.Pointer
 	}
 	args.n = uint64(n)
-	cgocall(_cgo_malloc, unsafe.Pointer(&args))
+	cgocall(cgoMalloc, unsafe.Pointer(&args))
 	if args.ret == nil {
-		throw("C malloc failed")
+		gothrow("C malloc failed")
 	}
 	return args.ret
 }
 
 func cfree(p unsafe.Pointer) {
-	cgocall(_cgo_free, p)
+	cgocall(cgoFree, p)
 }
 
 // Call from C back to Go.
@@ -163,37 +183,23 @@ func cgocallbackg() {
 		exit(2)
 	}
 
-	// Save current syscall parameters, so m.syscall can be
-	// used again if callback decide to make syscall.
-	syscall := gp.m.syscall
-
 	// entersyscall saves the caller's SP to allow the GC to trace the Go
 	// stack. However, since we're returning to an earlier stack frame and
 	// need to pair with the entersyscall() call made by cgocall, we must
 	// save syscall* and let reentersyscall restore them.
 	savedsp := unsafe.Pointer(gp.syscallsp)
 	savedpc := gp.syscallpc
-	exitsyscall(0) // coming out of cgo call
+	exitsyscall() // coming out of cgo call
 	cgocallbackg1()
 	// going back to cgo call
-	reentersyscall(savedpc, uintptr(savedsp))
-
-	gp.m.syscall = syscall
+	reentersyscall(savedpc, savedsp)
 }
 
 func cgocallbackg1() {
 	gp := getg()
 	if gp.m.needextram {
 		gp.m.needextram = false
-		systemstack(newextram)
-	}
-
-	if gp.m.ncgo == 0 {
-		// The C call to Go came from a thread not currently running
-		// any Go. In the case of -buildmode=c-archive or c-shared,
-		// this call may be coming in before package initialization
-		// is complete. Wait until it is.
-		<-main_init_done
+		onM(newextram)
 	}
 
 	// Add entry to defer stack in case of panic.
@@ -216,40 +222,21 @@ func cgocallbackg1() {
 	sp := gp.m.g0.sched.sp
 	switch GOARCH {
 	default:
-		throw("cgocallbackg is unimplemented on arch")
+		gothrow("cgocallbackg is unimplemented on arch")
 	case "arm":
 		// On arm, stack frame is two words and there's a saved LR between
 		// SP and the stack frame and between the stack frame and the arguments.
 		cb = (*args)(unsafe.Pointer(sp + 4*ptrSize))
-	case "arm64":
-		// On arm64, stack frame is four words and there's a saved LR between
-		// SP and the stack frame and between the stack frame and the arguments.
-		cb = (*args)(unsafe.Pointer(sp + 5*ptrSize))
 	case "amd64":
 		// On amd64, stack frame is one word, plus caller PC.
-		if framepointer_enabled {
-			// In this case, there's also saved BP.
-			cb = (*args)(unsafe.Pointer(sp + 3*ptrSize))
-			break
-		}
 		cb = (*args)(unsafe.Pointer(sp + 2*ptrSize))
 	case "386":
 		// On 386, stack frame is three words, plus caller PC.
 		cb = (*args)(unsafe.Pointer(sp + 4*ptrSize))
-	case "ppc64", "ppc64le":
-		// On ppc64, stack frame is two words and there's a
-		// saved LR between SP and the stack frame and between
-		// the stack frame and the arguments.
-		cb = (*args)(unsafe.Pointer(sp + 4*ptrSize))
 	}
 
 	// Invoke callback.
-	// NOTE(rsc): passing nil for argtype means that the copying of the
-	// results back into cb.arg happens without any corresponding write barriers.
-	// For cgo, cb.arg points into a C stack frame and therefore doesn't
-	// hold any pointers that the GC can find anyway - the write barrier
-	// would be a no-op.
-	reflectcall(nil, unsafe.Pointer(cb.fn), unsafe.Pointer(cb.arg), uint32(cb.argsize), 0)
+	reflectcall(unsafe.Pointer(cb.fn), unsafe.Pointer(cb.arg), uint32(cb.argsize), 0)
 
 	if raceenabled {
 		racereleasemerge(unsafe.Pointer(&racecgosync))
@@ -270,27 +257,23 @@ func unwindm(restore *bool) {
 	sched := &mp.g0.sched
 	switch GOARCH {
 	default:
-		throw("unwindm not implemented")
+		gothrow("unwindm not implemented")
 	case "386", "amd64":
 		sched.sp = *(*uintptr)(unsafe.Pointer(sched.sp))
 	case "arm":
 		sched.sp = *(*uintptr)(unsafe.Pointer(sched.sp + 4))
-	case "arm64":
-		sched.sp = *(*uintptr)(unsafe.Pointer(sched.sp + 16))
-	case "ppc64", "ppc64le":
-		sched.sp = *(*uintptr)(unsafe.Pointer(sched.sp + 8))
 	}
 	releasem(mp)
 }
 
 // called from assembly
 func badcgocallback() {
-	throw("misaligned stack in cgocallback")
+	gothrow("misaligned stack in cgocallback")
 }
 
 // called from (incomplete) assembly
 func cgounimpl() {
-	throw("cgo not implemented")
+	gothrow("cgo not implemented")
 }
 
 var racecgosync uint64 // represents possible synchronization in C code
diff --git a/src/runtime/cgocall.h b/src/runtime/cgocall.h
new file mode 100644
index 0000000..c87a9cd
--- /dev/null
+++ b/src/runtime/cgocall.h
@@ -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.
+
+/*
+ * Cgo interface.
+ */
+
+void runtime·cgocall(void (*fn)(void*), void*);
+int32 runtime·cgocall_errno(void (*fn)(void*), void*);
+void runtime·cgocallback(void (*fn)(void), void*, uintptr);
+void *runtime·cmalloc(uintptr);
+void runtime·cfree(void*);
diff --git a/src/runtime/cgocallback.go b/src/runtime/cgocallback.go
index f93acab..2c89143 100644
--- a/src/runtime/cgocallback.go
+++ b/src/runtime/cgocallback.go
@@ -4,7 +4,34 @@
 
 package runtime
 
-// These functions are called from C code via cgo/callbacks.go.
+import "unsafe"
+
+// These functions are called from C code via cgo/callbacks.c.
+
+// Allocate memory.  This allocates the requested number of bytes in
+// memory controlled by the Go runtime.  The allocated memory will be
+// zeroed.  You are responsible for ensuring that the Go garbage
+// collector can see a pointer to the allocated memory for as long as
+// it is valid, e.g., by storing a pointer in a local variable in your
+// C function, or in memory allocated by the Go runtime.  If the only
+// pointers are in a C global variable or in memory allocated via
+// malloc, then the Go garbage collector may collect the memory.
+//
+// TODO(rsc,iant): This memory is untyped.
+// Either we need to add types or we need to stop using it.
+
+func _cgo_allocate_internal(len uintptr) unsafe.Pointer {
+	if len == 0 {
+		len = 1
+	}
+	ret := unsafe.Pointer(&make([]unsafe.Pointer, (len+ptrSize-1)/ptrSize)[0])
+	c := new(cgomal)
+	c.alloc = ret
+	gp := getg()
+	c.next = gp.m.cgomal
+	gp.m.cgomal = c
+	return ret
+}
 
 // Panic.
 
diff --git a/src/runtime/chan.go b/src/runtime/chan.go
index cfee12a..0eb87df 100644
--- a/src/runtime/chan.go
+++ b/src/runtime/chan.go
@@ -14,41 +14,19 @@ const (
 	debugChan = false
 )
 
-type hchan struct {
-	qcount   uint           // total data in the queue
-	dataqsiz uint           // size of the circular queue
-	buf      unsafe.Pointer // points to an array of dataqsiz elements
-	elemsize uint16
-	closed   uint32
-	elemtype *_type // element type
-	sendx    uint   // send index
-	recvx    uint   // receive index
-	recvq    waitq  // list of recv waiters
-	sendq    waitq  // list of send waiters
-	lock     mutex
-}
-
-type waitq struct {
-	first *sudog
-	last  *sudog
-}
-
-//go:linkname reflect_makechan reflect.makechan
-func reflect_makechan(t *chantype, size int64) *hchan {
-	return makechan(t, size)
-}
+// TODO(khr): make hchan.buf an unsafe.Pointer, not a *uint8
 
 func makechan(t *chantype, size int64) *hchan {
 	elem := t.elem
 
 	// compiler checks this but be safe.
 	if elem.size >= 1<<16 {
-		throw("makechan: invalid channel element type")
+		gothrow("makechan: invalid channel element type")
 	}
 	if hchanSize%maxAlign != 0 || elem.align > maxAlign {
-		throw("makechan: bad alignment")
+		gothrow("makechan: bad alignment")
 	}
-	if size < 0 || int64(uintptr(size)) != size || (elem.size > 0 && uintptr(size) > (_MaxMem-hchanSize)/uintptr(elem.size)) {
+	if size < 0 || int64(uintptr(size)) != size || (elem.size > 0 && uintptr(size) > (maxmem-hchanSize)/uintptr(elem.size)) {
 		panic("makechan: size out of range")
 	}
 
@@ -61,15 +39,13 @@ func makechan(t *chantype, size int64) *hchan {
 		// TODO(dvyukov,rlh): Rethink when collector can move allocated objects.
 		c = (*hchan)(mallocgc(hchanSize+uintptr(size)*uintptr(elem.size), nil, flagNoScan))
 		if size > 0 && elem.size != 0 {
-			c.buf = add(unsafe.Pointer(c), hchanSize)
+			c.buf = (*uint8)(add(unsafe.Pointer(c), hchanSize))
 		} else {
-			// race detector uses this location for synchronization
-			// Also prevents us from pointing beyond the allocation (see issue 9401).
-			c.buf = unsafe.Pointer(c)
+			c.buf = (*uint8)(unsafe.Pointer(c)) // race detector uses this location for synchronization
 		}
 	} else {
 		c = new(hchan)
-		c.buf = newarray(elem, uintptr(size))
+		c.buf = (*uint8)(newarray(elem, uintptr(size)))
 	}
 	c.elemsize = uint16(elem.size)
 	c.elemtype = elem
@@ -83,7 +59,7 @@ func makechan(t *chantype, size int64) *hchan {
 
 // chanbuf(c, i) is pointer to the i'th slot in the buffer.
 func chanbuf(c *hchan, i uint) unsafe.Pointer {
-	return add(c.buf, uintptr(i)*uintptr(c.elemsize))
+	return add(unsafe.Pointer(c.buf), uintptr(i)*uintptr(c.elemsize))
 }
 
 // entry point for c <- x from compiled code
@@ -113,8 +89,8 @@ func chansend(t *chantype, c *hchan, ep unsafe.Pointer, block bool, callerpc uin
 		if !block {
 			return false
 		}
-		gopark(nil, nil, "chan send (nil chan)", traceEvGoStop, 2)
-		throw("unreachable")
+		gopark(nil, nil, "chan send (nil chan)")
+		gothrow("unreachable")
 	}
 
 	if debugChan {
@@ -165,13 +141,14 @@ func chansend(t *chantype, c *hchan, ep unsafe.Pointer, block bool, callerpc uin
 
 			recvg := sg.g
 			if sg.elem != nil {
-				syncsend(c, sg, ep)
+				memmove(unsafe.Pointer(sg.elem), ep, uintptr(c.elemsize))
+				sg.elem = nil
 			}
 			recvg.param = unsafe.Pointer(sg)
 			if sg.releasetime != 0 {
 				sg.releasetime = cputicks()
 			}
-			goready(recvg, 3)
+			goready(recvg)
 			return true
 		}
 
@@ -194,16 +171,16 @@ func chansend(t *chantype, c *hchan, ep unsafe.Pointer, block bool, callerpc uin
 		mysg.selectdone = nil
 		gp.param = nil
 		c.sendq.enqueue(mysg)
-		goparkunlock(&c.lock, "chan send", traceEvGoBlockSend, 3)
+		goparkunlock(&c.lock, "chan send")
 
 		// someone woke us up.
 		if mysg != gp.waiting {
-			throw("G waiting list is corrupted!")
+			gothrow("G waiting list is corrupted!")
 		}
 		gp.waiting = nil
 		if gp.param == nil {
 			if c.closed == 0 {
-				throw("chansend: spurious wakeup")
+				gothrow("chansend: spurious wakeup")
 			}
 			panic("send on closed channel")
 		}
@@ -218,7 +195,7 @@ func chansend(t *chantype, c *hchan, ep unsafe.Pointer, block bool, callerpc uin
 	// asynchronous channel
 	// wait for some space to write our data
 	var t1 int64
-	for futile := byte(0); c.qcount >= c.dataqsiz; futile = traceFutileWakeup {
+	for c.qcount >= c.dataqsiz {
 		if !block {
 			unlock(&c.lock)
 			return false
@@ -233,7 +210,7 @@ func chansend(t *chantype, c *hchan, ep unsafe.Pointer, block bool, callerpc uin
 		mysg.elem = nil
 		mysg.selectdone = nil
 		c.sendq.enqueue(mysg)
-		goparkunlock(&c.lock, "chan send", traceEvGoBlockSend|futile, 3)
+		goparkunlock(&c.lock, "chan send")
 
 		// someone woke us up - try again
 		if mysg.releasetime > 0 {
@@ -252,7 +229,7 @@ func chansend(t *chantype, c *hchan, ep unsafe.Pointer, block bool, callerpc uin
 		raceacquire(chanbuf(c, c.sendx))
 		racerelease(chanbuf(c, c.sendx))
 	}
-	typedmemmove(c.elemtype, chanbuf(c, c.sendx), ep)
+	memmove(chanbuf(c, c.sendx), ep, uintptr(c.elemsize))
 	c.sendx++
 	if c.sendx == c.dataqsiz {
 		c.sendx = 0
@@ -267,7 +244,7 @@ func chansend(t *chantype, c *hchan, ep unsafe.Pointer, block bool, callerpc uin
 		if sg.releasetime != 0 {
 			sg.releasetime = cputicks()
 		}
-		goready(recvg, 3)
+		goready(recvg)
 	} else {
 		unlock(&c.lock)
 	}
@@ -277,21 +254,6 @@ func chansend(t *chantype, c *hchan, ep unsafe.Pointer, block bool, callerpc uin
 	return true
 }
 
-func syncsend(c *hchan, sg *sudog, elem unsafe.Pointer) {
-	// Send on unbuffered channel is the only operation
-	// in the entire runtime where one goroutine
-	// writes to the stack of another goroutine. The GC assumes that
-	// stack writes only happen when the goroutine is running and are
-	// only done by that goroutine. Using a write barrier is sufficient to
-	// make up for violating that assumption, but the write barrier has to work.
-	// typedmemmove will call heapBitsBulkBarrier, but the target bytes
-	// are not in the heap, so that will not help. We arrange to call
-	// memmove and typeBitsBulkBarrier instead.
-	memmove(sg.elem, elem, c.elemtype.size)
-	typeBitsBulkBarrier(c.elemtype, uintptr(sg.elem), c.elemtype.size)
-	sg.elem = nil
-}
-
 func closechan(c *hchan) {
 	if c == nil {
 		panic("close of nil channel")
@@ -323,7 +285,7 @@ func closechan(c *hchan) {
 		if sg.releasetime != 0 {
 			sg.releasetime = cputicks()
 		}
-		goready(gp, 3)
+		goready(gp)
 	}
 
 	// release all writers
@@ -338,7 +300,7 @@ func closechan(c *hchan) {
 		if sg.releasetime != 0 {
 			sg.releasetime = cputicks()
 		}
-		goready(gp, 3)
+		goready(gp)
 	}
 	unlock(&c.lock)
 }
@@ -371,8 +333,8 @@ func chanrecv(t *chantype, c *hchan, ep unsafe.Pointer, block bool) (selected, r
 		if !block {
 			return
 		}
-		gopark(nil, nil, "chan receive (nil chan)", traceEvGoStop, 2)
-		throw("unreachable")
+		gopark(nil, nil, "chan receive (nil chan)")
+		gothrow("unreachable")
 	}
 
 	// Fast path: check for failed non-blocking operation without acquiring the lock.
@@ -412,7 +374,7 @@ func chanrecv(t *chantype, c *hchan, ep unsafe.Pointer, block bool) (selected, r
 			unlock(&c.lock)
 
 			if ep != nil {
-				typedmemmove(c.elemtype, ep, sg.elem)
+				memmove(ep, sg.elem, uintptr(c.elemsize))
 			}
 			sg.elem = nil
 			gp := sg.g
@@ -420,7 +382,7 @@ func chanrecv(t *chantype, c *hchan, ep unsafe.Pointer, block bool) (selected, r
 			if sg.releasetime != 0 {
 				sg.releasetime = cputicks()
 			}
-			goready(gp, 3)
+			goready(gp)
 			selected = true
 			received = true
 			return
@@ -445,11 +407,11 @@ func chanrecv(t *chantype, c *hchan, ep unsafe.Pointer, block bool) (selected, r
 		mysg.selectdone = nil
 		gp.param = nil
 		c.recvq.enqueue(mysg)
-		goparkunlock(&c.lock, "chan receive", traceEvGoBlockRecv, 3)
+		goparkunlock(&c.lock, "chan receive")
 
 		// someone woke us up
 		if mysg != gp.waiting {
-			throw("G waiting list is corrupted!")
+			gothrow("G waiting list is corrupted!")
 		}
 		gp.waiting = nil
 		if mysg.releasetime > 0 {
@@ -468,7 +430,7 @@ func chanrecv(t *chantype, c *hchan, ep unsafe.Pointer, block bool) (selected, r
 
 		lock(&c.lock)
 		if c.closed == 0 {
-			throw("chanrecv: spurious wakeup")
+			gothrow("chanrecv: spurious wakeup")
 		}
 		return recvclosed(c, ep)
 	}
@@ -476,7 +438,7 @@ func chanrecv(t *chantype, c *hchan, ep unsafe.Pointer, block bool) (selected, r
 	// asynchronous channel
 	// wait for some data to appear
 	var t1 int64
-	for futile := byte(0); c.qcount <= 0; futile = traceFutileWakeup {
+	for c.qcount <= 0 {
 		if c.closed != 0 {
 			selected, received = recvclosed(c, ep)
 			if t1 > 0 {
@@ -502,7 +464,7 @@ func chanrecv(t *chantype, c *hchan, ep unsafe.Pointer, block bool) (selected, r
 		mysg.selectdone = nil
 
 		c.recvq.enqueue(mysg)
-		goparkunlock(&c.lock, "chan receive", traceEvGoBlockRecv|futile, 3)
+		goparkunlock(&c.lock, "chan receive")
 
 		// someone woke us up - try again
 		if mysg.releasetime > 0 {
@@ -517,7 +479,7 @@ func chanrecv(t *chantype, c *hchan, ep unsafe.Pointer, block bool) (selected, r
 		racerelease(chanbuf(c, c.recvx))
 	}
 	if ep != nil {
-		typedmemmove(c.elemtype, ep, chanbuf(c, c.recvx))
+		memmove(ep, chanbuf(c, c.recvx), uintptr(c.elemsize))
 	}
 	memclr(chanbuf(c, c.recvx), uintptr(c.elemsize))
 
@@ -535,7 +497,7 @@ func chanrecv(t *chantype, c *hchan, ep unsafe.Pointer, block bool) (selected, r
 		if sg.releasetime != 0 {
 			sg.releasetime = cputicks()
 		}
-		goready(gp, 3)
+		goready(gp)
 	} else {
 		unlock(&c.lock)
 	}
@@ -628,17 +590,14 @@ func selectnbrecv2(t *chantype, elem unsafe.Pointer, received *bool, c *hchan) (
 	return
 }
 
-//go:linkname reflect_chansend reflect.chansend
 func reflect_chansend(t *chantype, c *hchan, elem unsafe.Pointer, nb bool) (selected bool) {
 	return chansend(t, c, elem, !nb, getcallerpc(unsafe.Pointer(&t)))
 }
 
-//go:linkname reflect_chanrecv reflect.chanrecv
 func reflect_chanrecv(t *chantype, c *hchan, nb bool, elem unsafe.Pointer) (selected bool, received bool) {
 	return chanrecv(t, c, elem, !nb)
 }
 
-//go:linkname reflect_chanlen reflect.chanlen
 func reflect_chanlen(c *hchan) int {
 	if c == nil {
 		return 0
@@ -646,7 +605,6 @@ func reflect_chanlen(c *hchan) int {
 	return int(c.qcount)
 }
 
-//go:linkname reflect_chancap reflect.chancap
 func reflect_chancap(c *hchan) int {
 	if c == nil {
 		return 0
@@ -654,22 +612,14 @@ func reflect_chancap(c *hchan) int {
 	return int(c.dataqsiz)
 }
 
-//go:linkname reflect_chanclose reflect.chanclose
-func reflect_chanclose(c *hchan) {
-	closechan(c)
-}
-
 func (q *waitq) enqueue(sgp *sudog) {
 	sgp.next = nil
-	x := q.last
-	if x == nil {
-		sgp.prev = nil
+	if q.first == nil {
 		q.first = sgp
 		q.last = sgp
 		return
 	}
-	sgp.prev = x
-	x.next = sgp
+	q.last.next = sgp
 	q.last = sgp
 }
 
@@ -679,14 +629,10 @@ func (q *waitq) dequeue() *sudog {
 		if sgp == nil {
 			return nil
 		}
-		y := sgp.next
-		if y == nil {
-			q.first = nil
+		q.first = sgp.next
+		sgp.next = nil
+		if q.last == sgp {
 			q.last = nil
-		} else {
-			y.prev = nil
-			q.first = y
-			sgp.next = nil // mark as removed (see dequeueSudog)
 		}
 
 		// if sgp participates in a select and is already signaled, ignore it
diff --git a/src/runtime/chan.h b/src/runtime/chan.h
new file mode 100644
index 0000000..c34ff15
--- /dev/null
+++ b/src/runtime/chan.h
@@ -0,0 +1,68 @@
+// 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	Select	Select;
+typedef	struct	Scase	Scase;
+
+struct	WaitQ
+{
+	SudoG*	first;
+	SudoG*	last;
+};
+
+struct	Hchan
+{
+	uintgo	qcount;			// total data in the q
+	uintgo	dataqsiz;		// size of the circular q
+	byte*	buf;
+	uint16	elemsize;
+	uint32	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
+	Mutex	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)->buf)+(uintptr)(c)->elemsize*(i))
+
+enum
+{
+	debug = 0,
+
+	// Scase.kind
+	CaseRecv,
+	CaseSend,
+	CaseDefault,
+};
+
+// Known to compiler.
+// Changes here must also be made in src/cmd/gc/select.c's selecttype.
+struct	Scase
+{
+	void*	elem;			// data element
+	Hchan*	chan;			// chan
+	uintptr	pc;			// return pc
+	uint16	kind;
+	uint16	so;			// vararg of selected bool
+	bool*	receivedp;		// pointer to received bool (recv2)
+	int64	releasetime;
+};
+
+// Known to compiler.
+// Changes here must also be made in src/cmd/gc/select.c's selecttype.
+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/runtime/chan_test.go b/src/runtime/chan_test.go
index 497e87f..e689cea 100644
--- a/src/runtime/chan_test.go
+++ b/src/runtime/chan_test.go
@@ -218,81 +218,6 @@ func TestNonblockRecvRace(t *testing.T) {
 	}
 }
 
-// This test checks that select acts on the state of the channels at one
-// moment in the execution, not over a smeared time window.
-// In the test, one goroutine does:
-//	create c1, c2
-//	make c1 ready for receiving
-//	create second goroutine
-//	make c2 ready for receiving
-//	make c1 no longer ready for receiving (if possible)
-// The second goroutine does a non-blocking select receiving from c1 and c2.
-// From the time the second goroutine is created, at least one of c1 and c2
-// is always ready for receiving, so the select in the second goroutine must
-// always receive from one or the other. It must never execute the default case.
-func TestNonblockSelectRace(t *testing.T) {
-	n := 100000
-	if testing.Short() {
-		n = 1000
-	}
-	done := make(chan bool, 1)
-	for i := 0; i < n; i++ {
-		c1 := make(chan int, 1)
-		c2 := make(chan int, 1)
-		c1 <- 1
-		go func() {
-			select {
-			case <-c1:
-			case <-c2:
-			default:
-				done <- false
-				return
-			}
-			done <- true
-		}()
-		c2 <- 1
-		select {
-		case <-c1:
-		default:
-		}
-		if !<-done {
-			t.Fatal("no chan is ready")
-		}
-	}
-}
-
-// Same as TestNonblockSelectRace, but close(c2) replaces c2 <- 1.
-func TestNonblockSelectRace2(t *testing.T) {
-	n := 100000
-	if testing.Short() {
-		n = 1000
-	}
-	done := make(chan bool, 1)
-	for i := 0; i < n; i++ {
-		c1 := make(chan int, 1)
-		c2 := make(chan int)
-		c1 <- 1
-		go func() {
-			select {
-			case <-c1:
-			case <-c2:
-			default:
-				done <- false
-				return
-			}
-			done <- true
-		}()
-		close(c2)
-		select {
-		case <-c1:
-		default:
-		}
-		if !<-done {
-			t.Fatal("no chan is ready")
-		}
-	}
-}
-
 func TestSelfSelect(t *testing.T) {
 	// Ensure that send/recv on the same chan in select
 	// does not crash nor deadlock.
@@ -528,7 +453,7 @@ func TestMultiConsumer(t *testing.T) {
 func TestShrinkStackDuringBlockedSend(t *testing.T) {
 	// make sure that channel operations still work when we are
 	// blocked on a channel send and we shrink the stack.
-	// NOTE: this test probably won't fail unless stack1.go:stackDebug
+	// NOTE: this test probably won't fail unless stack.c:StackDebug
 	// is set to >= 1.
 	const n = 10
 	c := make(chan int)
@@ -893,30 +818,3 @@ func BenchmarkChanSem(b *testing.B) {
 		}
 	})
 }
-
-func BenchmarkChanPopular(b *testing.B) {
-	const n = 1000
-	c := make(chan bool)
-	var a []chan bool
-	var wg sync.WaitGroup
-	wg.Add(n)
-	for j := 0; j < n; j++ {
-		d := make(chan bool)
-		a = append(a, d)
-		go func() {
-			for i := 0; i < b.N; i++ {
-				select {
-				case <-c:
-				case <-d:
-				}
-			}
-			wg.Done()
-		}()
-	}
-	for i := 0; i < b.N; i++ {
-		for _, d := range a {
-			d <- true
-		}
-	}
-	wg.Wait()
-}
diff --git a/src/runtime/compiler.go b/src/runtime/compiler.go
index 5f1e8d8..562a460 100644
--- a/src/runtime/compiler.go
+++ b/src/runtime/compiler.go
@@ -7,7 +7,7 @@ package runtime
 // Compiler is the name of the compiler toolchain that built the
 // running binary.  Known toolchains are:
 //
-//	gc      Also known as cmd/compile.
+//	gc      The 5g/6g/8g compiler suite at code.google.com/p/go.
 //	gccgo   The gccgo front end, part of the GCC compiler suite.
 //
 const Compiler = "gc"
diff --git a/src/runtime/complex.go b/src/runtime/complex.go
index 73f1161..ec50f89 100644
--- a/src/runtime/complex.go
+++ b/src/runtime/complex.go
@@ -4,47 +4,28 @@
 
 package runtime
 
-func isposinf(f float64) bool { return f > maxFloat64 }
-func isneginf(f float64) bool { return f < -maxFloat64 }
-func isnan(f float64) bool    { return f != f }
-
-func nan() float64 {
-	var f float64 = 0
-	return f / f
-}
-
-func posinf() float64 {
-	var f float64 = maxFloat64
-	return f * f
-}
-
-func neginf() float64 {
-	var f float64 = maxFloat64
-	return -f * f
-}
-
 func complex128div(n complex128, d complex128) complex128 {
 	// Special cases as in C99.
-	ninf := isposinf(real(n)) || isneginf(real(n)) ||
-		isposinf(imag(n)) || isneginf(imag(n))
-	dinf := isposinf(real(d)) || isneginf(real(d)) ||
-		isposinf(imag(d)) || isneginf(imag(d))
+	ninf := real(n) == posinf || real(n) == neginf ||
+		imag(n) == posinf || imag(n) == neginf
+	dinf := real(d) == posinf || real(d) == neginf ||
+		imag(d) == posinf || imag(d) == neginf
 
-	nnan := !ninf && (isnan(real(n)) || isnan(imag(n)))
-	dnan := !dinf && (isnan(real(d)) || isnan(imag(d)))
+	nnan := !ninf && (real(n) != real(n) || imag(n) != imag(n))
+	dnan := !dinf && (real(d) != real(d) || imag(d) != imag(d))
 
 	switch {
 	case nnan || dnan:
-		return complex(nan(), nan())
+		return complex(nan, nan)
 	case ninf && !dinf:
-		return complex(posinf(), posinf())
+		return complex(posinf, posinf)
 	case !ninf && dinf:
 		return complex(0, 0)
 	case real(d) == 0 && imag(d) == 0:
 		if real(n) == 0 && imag(n) == 0 {
-			return complex(nan(), nan())
+			return complex(nan, nan)
 		} else {
-			return complex(posinf(), posinf())
+			return complex(posinf, posinf)
 		}
 	default:
 		// Standard complex arithmetic, factored to avoid unnecessary overflow.
diff --git a/src/runtime/cpuprof.go b/src/runtime/cpuprof.go
index 0790852..8b1c1c6 100644
--- a/src/runtime/cpuprof.go
+++ b/src/runtime/cpuprof.go
@@ -30,8 +30,8 @@
 // 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)
+// 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
@@ -61,7 +61,7 @@ const (
 
 type cpuprofEntry struct {
 	count uintptr
-	depth int
+	depth uintptr
 	stack [maxCPUProfStack]uintptr
 }
 
@@ -81,7 +81,7 @@ type cpuProfile struct {
 	// Signal handler has filled log[toggle][:nlog].
 	// Goroutine is writing log[1-toggle][:handoff].
 	log     [2][logSize / 2]uintptr
-	nlog    int
+	nlog    uintptr
 	toggle  int32
 	handoff uint32
 
@@ -101,10 +101,12 @@ var (
 	eod = [3]uintptr{0, 1, 0}
 )
 
+func setcpuprofilerate_m() // proc.c
+
 func setcpuprofilerate(hz int32) {
-	systemstack(func() {
-		setcpuprofilerate_m(hz)
-	})
+	g := getg()
+	g.m.scalararg[0] = uintptr(hz)
+	onM(setcpuprofilerate_m)
 }
 
 // lostProfileData is a no-op function used in profiles
@@ -167,7 +169,7 @@ func SetCPUProfileRate(hz int) {
 		cpuprof.on = false
 
 		// Now add is not running anymore, and getprofile owns the entire log.
-		// Set the high bit in cpuprof.handoff to tell getprofile.
+		// Set the high bit in prof->handoff to tell getprofile.
 		for {
 			n := cpuprof.handoff
 			if n&0x80000000 != 0 {
@@ -185,21 +187,25 @@ func SetCPUProfileRate(hz int) {
 	unlock(&cpuprofLock)
 }
 
+func cpuproftick(pc *uintptr, n int32) {
+	if n > maxCPUProfStack {
+		n = maxCPUProfStack
+	}
+	s := (*[maxCPUProfStack]uintptr)(unsafe.Pointer(pc))[:n]
+	cpuprof.add(s)
+}
+
 // 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.
 func (p *cpuProfile) add(pc []uintptr) {
-	if len(pc) > maxCPUProfStack {
-		pc = pc[:maxCPUProfStack]
-	}
-
 	// Compute hash.
 	h := uintptr(0)
 	for _, x := range pc {
 		h = h<<8 | (h >> (8 * (unsafe.Sizeof(h) - 1)))
-		h += x * 41
+		h += x*31 + x*7 + x*3
 	}
 	p.count++
 
@@ -208,7 +214,7 @@ func (p *cpuProfile) add(pc []uintptr) {
 Assoc:
 	for i := range b.entry {
 		e := &b.entry[i]
-		if e.depth != len(pc) {
+		if e.depth != uintptr(len(pc)) {
 			continue
 		}
 		for j := range pc {
@@ -237,7 +243,7 @@ Assoc:
 	}
 
 	// Reuse the newly evicted entry.
-	e.depth = len(pc)
+	e.depth = uintptr(len(pc))
 	e.count = 1
 	copy(e.stack[:], pc)
 }
@@ -252,7 +258,7 @@ func (p *cpuProfile) evict(e *cpuprofEntry) bool {
 	d := e.depth
 	nslot := d + 2
 	log := &p.log[p.toggle]
-	if p.nlog+nslot > len(log) {
+	if p.nlog+nslot > uintptr(len(p.log[0])) {
 		if !p.flushlog() {
 			return false
 		}
@@ -262,7 +268,7 @@ func (p *cpuProfile) evict(e *cpuprofEntry) bool {
 	q := p.nlog
 	log[q] = e.count
 	q++
-	log[q] = uintptr(d)
+	log[q] = d
 	q++
 	copy(log[q:], e.stack[:d])
 	q += d
@@ -283,7 +289,7 @@ func (p *cpuProfile) flushlog() bool {
 
 	p.toggle = 1 - p.toggle
 	log := &p.log[p.toggle]
-	q := 0
+	q := uintptr(0)
 	if p.lost > 0 {
 		lostPC := funcPC(lostProfileData)
 		log[0] = p.lost
@@ -356,7 +362,7 @@ func (p *cpuProfile) getprofile() []byte {
 
 	// In flush mode.
 	// Add is no longer being called.  We own the log.
-	// Also, p.handoff is non-zero, so flushlog will return false.
+	// Also, p->handoff is non-zero, so flushlog will return false.
 	// Evict the hash table into the log and return it.
 Flush:
 	for i := range p.hash {
@@ -396,8 +402,8 @@ Flush:
 }
 
 func uintptrBytes(p []uintptr) (ret []byte) {
-	pp := (*slice)(unsafe.Pointer(&p))
-	rp := (*slice)(unsafe.Pointer(&ret))
+	pp := (*sliceStruct)(unsafe.Pointer(&p))
+	rp := (*sliceStruct)(unsafe.Pointer(&ret))
 
 	rp.array = pp.array
 	rp.len = pp.len * int(unsafe.Sizeof(p[0]))
@@ -417,8 +423,3 @@ func uintptrBytes(p []uintptr) (ret []byte) {
 func CPUProfile() []byte {
 	return cpuprof.getprofile()
 }
-
-//go:linkname runtime_pprof_runtime_cyclesPerSecond runtime/pprof.runtime_cyclesPerSecond
-func runtime_pprof_runtime_cyclesPerSecond() int64 {
-	return tickspersecond()
-}
diff --git a/src/runtime/crash_cgo_test.go b/src/runtime/crash_cgo_test.go
index 2e65e4c..29f90fa 100644
--- a/src/runtime/crash_cgo_test.go
+++ b/src/runtime/crash_cgo_test.go
@@ -36,20 +36,6 @@ func TestCgoTraceback(t *testing.T) {
 	}
 }
 
-func TestCgoCallbackGC(t *testing.T) {
-	if runtime.GOOS == "plan9" || runtime.GOOS == "windows" {
-		t.Skipf("no pthreads on %s", runtime.GOOS)
-	}
-	if testing.Short() && runtime.GOOS == "dragonfly" {
-		t.Skip("see golang.org/issue/11990")
-	}
-	got := executeTest(t, cgoCallbackGCSource, nil)
-	want := "OK\n"
-	if got != want {
-		t.Fatalf("expected %q, but got %q", want, got)
-	}
-}
-
 func TestCgoExternalThreadPanic(t *testing.T) {
 	if runtime.GOOS == "plan9" {
 		t.Skipf("no pthreads on %s", runtime.GOOS)
@@ -71,23 +57,16 @@ func TestCgoExternalThreadSIGPROF(t *testing.T) {
 	case "plan9", "windows":
 		t.Skipf("no pthreads on %s", runtime.GOOS)
 	case "darwin":
-		if runtime.GOARCH != "arm" && runtime.GOARCH != "arm64" {
-			// static constructor needs external linking, but we don't support
-			// external linking on OS X 10.6.
-			out, err := exec.Command("uname", "-r").Output()
-			if err != nil {
-				t.Fatalf("uname -r failed: %v", err)
-			}
-			// OS X 10.6 == Darwin 10.x
-			if strings.HasPrefix(string(out), "10.") {
-				t.Skipf("no external linking on OS X 10.6")
-			}
+		// static constructor needs external linking, but we don't support
+		// external linking on OS X 10.6.
+		out, err := exec.Command("uname", "-r").Output()
+		if err != nil {
+			t.Fatalf("uname -r failed: %v", err)
+		}
+		// OS X 10.6 == Darwin 10.x
+		if strings.HasPrefix(string(out), "10.") {
+			t.Skipf("no external linking on OS X 10.6")
 		}
-	}
-	if runtime.GOARCH == "ppc64" || runtime.GOARCH == "ppc64le" {
-		// TODO(austin) External linking not implemented on
-		// ppc64 (issue #8912)
-		t.Skipf("no external linking on ppc64")
 	}
 	got := executeTest(t, cgoExternalThreadSIGPROFSource, nil)
 	want := "OK\n"
@@ -96,31 +75,6 @@ func TestCgoExternalThreadSIGPROF(t *testing.T) {
 	}
 }
 
-func TestCgoExternalThreadSignal(t *testing.T) {
-	// issue 10139
-	switch runtime.GOOS {
-	case "plan9", "windows":
-		t.Skipf("no pthreads on %s", runtime.GOOS)
-	}
-	got := executeTest(t, cgoExternalThreadSignalSource, nil)
-	want := "OK\n"
-	if got != want {
-		t.Fatalf("expected %q, but got %q", want, got)
-	}
-}
-
-func TestCgoDLLImports(t *testing.T) {
-	// test issue 9356
-	if runtime.GOOS != "windows" {
-		t.Skip("skipping windows specific test")
-	}
-	got := executeTest(t, cgoDLLImportsMainSource, nil, "a/a.go", cgoDLLImportsPkgSource)
-	want := "OK\n"
-	if got != want {
-		t.Fatalf("expected %q, but got %v", want, got)
-	}
-}
-
 const cgoSignalDeadlockSource = `
 package main
 
@@ -205,83 +159,6 @@ func main() {
 }
 `
 
-const cgoCallbackGCSource = `
-package main
-
-import "runtime"
-
-/*
-#include <pthread.h>
-
-void go_callback();
-
-static void *thr(void *arg) {
-    go_callback();
-    return 0;
-}
-
-static void foo() {
-    pthread_t th;
-    pthread_create(&th, 0, thr, 0);
-    pthread_join(th, 0);
-}
-*/
-import "C"
-import "fmt"
-
-//export go_callback
-func go_callback() {
-	runtime.GC()
-	grow()
-	runtime.GC()
-}
-
-var cnt int
-
-func grow() {
-	x := 10000
-	sum := 0
-	if grow1(&x, &sum) == 0 {
-		panic("bad")
-	}
-}
-
-func grow1(x, sum *int) int {
-	if *x == 0 {
-		return *sum + 1
-	}
-	*x--
-	sum1 := *sum + *x
-	return grow1(x, &sum1)
-}
-
-func main() {
-	const P = 100
-	done := make(chan bool)
-	// allocate a bunch of stack frames and spray them with pointers
-	for i := 0; i < P; i++ {
-		go func() {
-			grow()
-			done <- true
-		}()
-	}
-	for i := 0; i < P; i++ {
-		<-done
-	}
-	// now give these stack frames to cgo callbacks
-	for i := 0; i < P; i++ {
-		go func() {
-			C.foo()
-			done <- true
-		}()
-	}
-	for i := 0; i < P; i++ {
-		<-done
-	}
-	fmt.Printf("OK\n")
-}
-`
-
 const cgoExternalThreadPanicSource = `
 package main
 
@@ -377,7 +254,7 @@ import (
 func main() {
 	// This test intends to test that sending SIGPROF to foreign threads
 	// before we make any cgo call will not abort the whole process, so
-	// we cannot make any cgo call here. See https://golang.org/issue/9456.
+	// we cannot make any cgo call here. See http://golang.org/issue/9456.
 	atomic.StoreInt32((*int32)(unsafe.Pointer(&C.spinlock)), 1)
 	for atomic.LoadInt32((*int32)(unsafe.Pointer(&C.spinlock))) == 1 {
 		runtime.Gosched()
@@ -385,97 +262,3 @@ func main() {
 	println("OK")
 }
 `
-
-const cgoExternalThreadSignalSource = `
-package main
-
-/*
-#include <pthread.h>
-
-void **nullptr;
-
-void *crash(void *p) {
-	*nullptr = p;
-	return 0;
-}
-
-int start_crashing_thread(void) {
-	pthread_t tid;
-	return pthread_create(&tid, 0, crash, 0);
-}
-*/
-import "C"
-
-import (
-	"fmt"
-	"os"
-	"os/exec"
-	"time"
-)
-
-func main() {
-	if len(os.Args) > 1 && os.Args[1] == "crash" {
-		i := C.start_crashing_thread()
-		if i != 0 {
-			fmt.Println("pthread_create failed:", i)
-			// Exit with 0 because parent expects us to crash.
-			return
-		}
-
-		// We should crash immediately, but give it plenty of
-		// time before failing (by exiting 0) in case we are
-		// running on a slow system.
-		time.Sleep(5 * time.Second)
-		return
-	}
-
-	out, err := exec.Command(os.Args[0], "crash").CombinedOutput()
-	if err == nil {
-		fmt.Println("C signal did not crash as expected\n")
-		fmt.Printf("%s\n", out)
-		os.Exit(1)
-	}
-
-	fmt.Println("OK")
-}
-`
-
-const cgoDLLImportsMainSource = `
-package main
-
-/*
-#include <windows.h>
-
-DWORD getthread() {
-	return GetCurrentThreadId();
-}
-*/
-import "C"
-
-import "./a"
-
-func main() {
-	C.getthread()
-	a.GetThread()
-	println("OK")
-}
-`
-
-const cgoDLLImportsPkgSource = `
-package a
-
-/*
-#cgo CFLAGS: -mnop-fun-dllimport
-
-#include <windows.h>
-
-DWORD agetthread() {
-	return GetCurrentThreadId();
-}
-*/
-import "C"
-
-func GetThread() uint32 {
-	return uint32(C.agetthread())
-}
-`
diff --git a/src/runtime/crash_test.go b/src/runtime/crash_test.go
index 8efce4d..211a047 100644
--- a/src/runtime/crash_test.go
+++ b/src/runtime/crash_test.go
@@ -5,41 +5,37 @@
 package runtime_test
 
 import (
-	"fmt"
-	"internal/testenv"
 	"io/ioutil"
 	"os"
 	"os/exec"
 	"path/filepath"
-	"regexp"
 	"runtime"
 	"strings"
-	"sync"
 	"testing"
 	"text/template"
 )
 
+// testEnv excludes GODEBUG from the environment
+// to prevent its output from breaking tests that
+// are trying to parse other command output.
 func testEnv(cmd *exec.Cmd) *exec.Cmd {
 	if cmd.Env != nil {
 		panic("environment already set")
 	}
 	for _, env := range os.Environ() {
-		// Exclude GODEBUG from the environment to prevent its output
-		// from breaking tests that are trying to parse other command output.
 		if strings.HasPrefix(env, "GODEBUG=") {
 			continue
 		}
-		// Exclude GOTRACEBACK for the same reason.
-		if strings.HasPrefix(env, "GOTRACEBACK=") {
-			continue
-		}
 		cmd.Env = append(cmd.Env, env)
 	}
 	return cmd
 }
 
 func executeTest(t *testing.T, templ string, data interface{}, extra ...string) string {
-	testenv.MustHaveGoBuild(t)
+	switch runtime.GOOS {
+	case "android", "nacl":
+		t.Skipf("skipping on %s", runtime.GOOS)
+	}
 
 	checkStaleRuntime(t)
 
@@ -66,14 +62,7 @@ func executeTest(t *testing.T, templ string, data interface{}, extra ...string)
 	}
 
 	for i := 0; i < len(extra); i += 2 {
-		fname := extra[i]
-		contents := extra[i+1]
-		if d, _ := filepath.Split(fname); d != "" {
-			if err := os.Mkdir(filepath.Join(dir, d), 0755); err != nil {
-				t.Fatal(err)
-			}
-		}
-		if err := ioutil.WriteFile(filepath.Join(dir, fname), []byte(contents), 0666); err != nil {
+		if err := ioutil.WriteFile(filepath.Join(dir, extra[i]), []byte(extra[i+1]), 0666); err != nil {
 			t.Fatal(err)
 		}
 	}
@@ -89,25 +78,14 @@ func executeTest(t *testing.T, templ string, data interface{}, extra ...string)
 	return string(got)
 }
 
-var (
-	staleRuntimeOnce sync.Once // guards init of staleRuntimeErr
-	staleRuntimeErr  error
-)
-
 func checkStaleRuntime(t *testing.T) {
-	staleRuntimeOnce.Do(func() {
-		// 'go run' uses the installed copy of runtime.a, which may be out of date.
-		out, err := testEnv(exec.Command("go", "list", "-f", "{{.Stale}}", "runtime")).CombinedOutput()
-		if err != nil {
-			staleRuntimeErr = fmt.Errorf("failed to execute 'go list': %v\n%v", err, string(out))
-			return
-		}
-		if string(out) != "false\n" {
-			staleRuntimeErr = fmt.Errorf("Stale runtime.a. Run 'go install runtime'.")
-		}
-	})
-	if staleRuntimeErr != nil {
-		t.Fatal(staleRuntimeErr)
+	// 'go run' uses the installed copy of runtime.a, which may be out of date.
+	out, err := testEnv(exec.Command("go", "list", "-f", "{{.Stale}}", "runtime")).CombinedOutput()
+	if err != nil {
+		t.Fatalf("failed to execute 'go list': %v\n%v", err, string(out))
+	}
+	if string(out) != "false\n" {
+		t.Fatalf("Stale runtime.a. Run 'go install runtime'.")
 	}
 }
 
@@ -226,14 +204,6 @@ func TestMainGoroutineId(t *testing.T) {
 	}
 }
 
-func TestNoHelperGoroutines(t *testing.T) {
-	output := executeTest(t, noHelperGoroutinesSource, nil)
-	matches := regexp.MustCompile(`goroutine [0-9]+ \[`).FindAllStringSubmatch(output, -1)
-	if len(matches) != 1 || matches[0][0] != "goroutine 1 [" {
-		t.Fatalf("want to see only goroutine 1, see:\n%s", output)
-	}
-}
-
 func TestBreakpoint(t *testing.T) {
 	output := executeTest(t, breakpointSource, nil)
 	want := "runtime.Breakpoint()"
@@ -448,22 +418,6 @@ func main() {
 }
 `
 
-const noHelperGoroutinesSource = `
-package main
-import (
-	"runtime"
-	"time"
-)
-func init() {
-	i := 0
-	runtime.SetFinalizer(&i, func(p *int) {})
-	time.AfterFunc(time.Hour, func() {})
-	panic("oops")
-}
-func main() {
-}
-`
-
 const breakpointSource = `
 package main
 import "runtime"
@@ -559,31 +513,3 @@ func TestRecoverBeforePanicAfterGoexit(t *testing.T) {
 	}()
 	runtime.Goexit()
 }
-
-func TestNetpollDeadlock(t *testing.T) {
-	output := executeTest(t, netpollDeadlockSource, nil)
-	want := "done\n"
-	if !strings.HasSuffix(output, want) {
-		t.Fatalf("output does not start with %q:\n%s", want, output)
-	}
-}
-
-const netpollDeadlockSource = `
-package main
-import (
-	"fmt"
-	"net"
-)
-func init() {
-	fmt.Println("dialing")
-	c, err := net.Dial("tcp", "localhost:14356")
-	if err == nil {
-		c.Close()
-	} else {
-		fmt.Println("error: ", err)
-	}
-}
-func main() {
-	fmt.Println("done")
-}
-`
diff --git a/src/runtime/debug.go b/src/runtime/debug.go
index b7e7971..4414dd5 100644
--- a/src/runtime/debug.go
+++ b/src/runtime/debug.go
@@ -6,6 +6,18 @@ package runtime
 
 import "unsafe"
 
+// Breakpoint executes a breakpoint trap.
+func Breakpoint()
+
+// LockOSThread wires the calling goroutine to its current operating system thread.
+// Until the calling goroutine exits or calls UnlockOSThread, it will always
+// execute in that thread, and no other goroutine can.
+func LockOSThread()
+
+// UnlockOSThread unwires the calling goroutine from its fixed operating system thread.
+// If the calling goroutine has not called LockOSThread, UnlockOSThread is a no-op.
+func UnlockOSThread()
+
 // GOMAXPROCS sets the maximum number of CPUs that can be executing
 // simultaneously and returns the previous setting.  If n < 1, it does not
 // change the current setting.
@@ -22,16 +34,21 @@ func GOMAXPROCS(n int) int {
 		return ret
 	}
 
-	stopTheWorld("GOMAXPROCS")
+	semacquire(&worldsema, false)
+	gp := getg()
+	gp.m.gcing = 1
+	onM(stoptheworld)
 
-	// newprocs will be processed by startTheWorld
+	// newprocs will be processed by starttheworld
 	newprocs = int32(n)
 
-	startTheWorld()
+	gp.m.gcing = 0
+	semrelease(&worldsema)
+	onM(starttheworld)
 	return ret
 }
 
-// NumCPU returns the number of logical CPUs usable by the current process.
+// NumCPU returns the number of logical CPUs on the local machine.
 func NumCPU() int {
 	return int(ncpu)
 }
@@ -49,3 +66,5 @@ func NumCgoCall() int64 {
 func NumGoroutine() int {
 	return int(gcount())
 }
+
+func gcount() int32
diff --git a/src/runtime/debug/garbage.go b/src/runtime/debug/garbage.go
index 41202f9..4a77dcf 100644
--- a/src/runtime/debug/garbage.go
+++ b/src/runtime/debug/garbage.go
@@ -155,5 +155,5 @@ 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 https://golang.org/s/go13heapdump.
+// The heap dump format is defined at http://golang.org/s/go13heapdump.
 func WriteHeapDump(fd uintptr)
diff --git a/src/runtime/debug/garbage_test.go b/src/runtime/debug/garbage_test.go
index 3e3483d..54c33bd 100644
--- a/src/runtime/debug/garbage_test.go
+++ b/src/runtime/debug/garbage_test.go
@@ -88,10 +88,6 @@ func TestReadGCStats(t *testing.T) {
 var big = make([]byte, 1<<20)
 
 func TestFreeOSMemory(t *testing.T) {
-	if runtime.GOARCH == "arm64" || runtime.GOARCH == "ppc64" || runtime.GOARCH == "ppc64le" ||
-		runtime.GOOS == "nacl" {
-		t.Skip("issue 9993; scavenger temporarily disabled on systems with physical pages larger than logical pages")
-	}
 	var ms1, ms2 runtime.MemStats
 
 	if big == nil {
diff --git a/src/runtime/debug/heapdump_test.go b/src/runtime/debug/heapdump_test.go
index cb2f2f0..9201901 100644
--- a/src/runtime/debug/heapdump_test.go
+++ b/src/runtime/debug/heapdump_test.go
@@ -31,39 +31,3 @@ func TestWriteHeapDumpNonempty(t *testing.T) {
 		t.Fatalf("Heap dump size %d bytes, expected at least %d bytes", size, minSize)
 	}
 }
-
-type Obj struct {
-	x, y int
-}
-
-func objfin(x *Obj) {
-	println("finalized", x)
-}
-
-func TestWriteHeapDumpFinalizers(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()
-
-	// bug 9172: WriteHeapDump couldn't handle more than one finalizer
-	println("allocating objects")
-	x := &Obj{}
-	runtime.SetFinalizer(x, objfin)
-	y := &Obj{}
-	runtime.SetFinalizer(y, objfin)
-
-	// Trigger collection of x and y, queueing of their finalizers.
-	println("starting gc")
-	runtime.GC()
-
-	// Make sure WriteHeapDump doesn't fail with multiple queued finalizers.
-	println("starting dump")
-	WriteHeapDump(f.Fd())
-	println("done dump")
-}
diff --git a/src/runtime/debug/stack.go b/src/runtime/debug/stack.go
index ab12bff..c29b0a2 100644
--- a/src/runtime/debug/stack.go
+++ b/src/runtime/debug/stack.go
@@ -31,7 +31,7 @@ func PrintStack() {
 // then attempts to discover, for Go functions, the calling function or
 // method and the text of the line containing the invocation.
 //
-// Deprecated: Use package runtime's Stack instead.
+// This function is deprecated. Use package runtime's Stack instead.
 func Stack() []byte {
 	return stack()
 }
diff --git a/src/runtime/debug/stubs.go b/src/runtime/debug/stubs.go
index 95b33e4..8fba6cf 100644
--- a/src/runtime/debug/stubs.go
+++ b/src/runtime/debug/stubs.go
@@ -16,4 +16,5 @@ func setMaxThreads(int) int
 
 // Implemented in package runtime.
 func readGCStats(*[]time.Duration)
+func enableGC(bool) bool
 func freeOSMemory()
diff --git a/src/runtime/debug/stubs.s b/src/runtime/debug/stubs.s
index 9dc8e54..d56274f 100644
--- a/src/runtime/debug/stubs.s
+++ b/src/runtime/debug/stubs.s
@@ -7,15 +7,6 @@
 #ifdef GOARCH_arm
 #define JMP B
 #endif
-#ifdef GOARCH_arm64
-#define JMP B
-#endif
-#ifdef GOARCH_ppc64
-#define JMP BR
-#endif
-#ifdef GOARCH_ppc64le
-#define JMP BR
-#endif
 
 TEXT ·setMaxStack(SB),NOSPLIT,$0-0
   JMP runtime·setMaxStack(SB)
diff --git a/src/runtime/defs.c b/src/runtime/defs.c
new file mode 100644
index 0000000..b0a9b20
--- /dev/null
+++ b/src/runtime/defs.c
@@ -0,0 +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.
+
+// 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 "chan.h"
+#include "defs_GOOS_GOARCH.h"
+#include "os_GOOS.h"
diff --git a/src/runtime/defs1_linux.go b/src/runtime/defs1_linux.go
index 87c6e02..392cc4a 100644
--- a/src/runtime/defs1_linux.go
+++ b/src/runtime/defs1_linux.go
@@ -15,14 +15,12 @@ package runtime
 /*
 #include <ucontext.h>
 #include <fcntl.h>
-#include <asm/signal.h>
 */
 import "C"
 
 const (
-	O_RDONLY    = C.O_RDONLY
-	O_CLOEXEC   = C.O_CLOEXEC
-	SA_RESTORER = C.SA_RESTORER
+	O_RDONLY  = C.O_RDONLY
+	O_CLOEXEC = C.O_CLOEXEC
 )
 
 type Usigset C.__sigset_t
diff --git a/src/runtime/defs_android_arm.h b/src/runtime/defs_android_arm.h
new file mode 100644
index 0000000..3611b3a
--- /dev/null
+++ b/src/runtime/defs_android_arm.h
@@ -0,0 +1,3 @@
+// TODO: Generate using cgo like defs_linux_{386,amd64}.h
+
+#include "defs_linux_arm.h"
diff --git a/src/runtime/defs_darwin_386.h b/src/runtime/defs_darwin_386.h
new file mode 100644
index 0000000..0e0b4fb
--- /dev/null
+++ b/src/runtime/defs_darwin_386.h
@@ -0,0 +1,392 @@
+// Created by cgo -cdefs - DO NOT EDIT
+// cgo -cdefs defs_darwin.go
+
+
+enum {
+	EINTR	= 0x4,
+	EFAULT	= 0xe,
+
+	PROT_NONE	= 0x0,
+	PROT_READ	= 0x1,
+	PROT_WRITE	= 0x2,
+	PROT_EXEC	= 0x4,
+
+	MAP_ANON	= 0x1000,
+	MAP_PRIVATE	= 0x2,
+	MAP_FIXED	= 0x10,
+
+	MADV_DONTNEED	= 0x4,
+	MADV_FREE	= 0x5,
+
+	MACH_MSG_TYPE_MOVE_RECEIVE	= 0x10,
+	MACH_MSG_TYPE_MOVE_SEND		= 0x11,
+	MACH_MSG_TYPE_MOVE_SEND_ONCE	= 0x12,
+	MACH_MSG_TYPE_COPY_SEND		= 0x13,
+	MACH_MSG_TYPE_MAKE_SEND		= 0x14,
+	MACH_MSG_TYPE_MAKE_SEND_ONCE	= 0x15,
+	MACH_MSG_TYPE_COPY_RECEIVE	= 0x16,
+
+	MACH_MSG_PORT_DESCRIPTOR		= 0x0,
+	MACH_MSG_OOL_DESCRIPTOR			= 0x1,
+	MACH_MSG_OOL_PORTS_DESCRIPTOR		= 0x2,
+	MACH_MSG_OOL_VOLATILE_DESCRIPTOR	= 0x3,
+
+	MACH_MSGH_BITS_COMPLEX	= 0x80000000,
+
+	MACH_SEND_MSG	= 0x1,
+	MACH_RCV_MSG	= 0x2,
+	MACH_RCV_LARGE	= 0x4,
+
+	MACH_SEND_TIMEOUT	= 0x10,
+	MACH_SEND_INTERRUPT	= 0x40,
+	MACH_SEND_ALWAYS	= 0x10000,
+	MACH_SEND_TRAILER	= 0x20000,
+	MACH_RCV_TIMEOUT	= 0x100,
+	MACH_RCV_NOTIFY		= 0x200,
+	MACH_RCV_INTERRUPT	= 0x400,
+	MACH_RCV_OVERWRITE	= 0x1000,
+
+	NDR_PROTOCOL_2_0	= 0x0,
+	NDR_INT_BIG_ENDIAN	= 0x0,
+	NDR_INT_LITTLE_ENDIAN	= 0x1,
+	NDR_FLOAT_IEEE		= 0x0,
+	NDR_CHAR_ASCII		= 0x0,
+
+	SA_SIGINFO	= 0x40,
+	SA_RESTART	= 0x2,
+	SA_ONSTACK	= 0x1,
+	SA_USERTRAMP	= 0x100,
+	SA_64REGSET	= 0x200,
+
+	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		= 0x10,
+	SIGSTOP		= 0x11,
+	SIGTSTP		= 0x12,
+	SIGCONT		= 0x13,
+	SIGCHLD		= 0x14,
+	SIGTTIN		= 0x15,
+	SIGTTOU		= 0x16,
+	SIGIO		= 0x17,
+	SIGXCPU		= 0x18,
+	SIGXFSZ		= 0x19,
+	SIGVTALRM	= 0x1a,
+	SIGPROF		= 0x1b,
+	SIGWINCH	= 0x1c,
+	SIGINFO		= 0x1d,
+	SIGUSR1		= 0x1e,
+	SIGUSR2		= 0x1f,
+
+	FPE_INTDIV	= 0x7,
+	FPE_INTOVF	= 0x8,
+	FPE_FLTDIV	= 0x1,
+	FPE_FLTOVF	= 0x2,
+	FPE_FLTUND	= 0x3,
+	FPE_FLTRES	= 0x4,
+	FPE_FLTINV	= 0x5,
+	FPE_FLTSUB	= 0x6,
+
+	BUS_ADRALN	= 0x1,
+	BUS_ADRERR	= 0x2,
+	BUS_OBJERR	= 0x3,
+
+	SEGV_MAPERR	= 0x1,
+	SEGV_ACCERR	= 0x2,
+
+	ITIMER_REAL	= 0x0,
+	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,
+};
+
+typedef struct MachBody MachBody;
+typedef struct MachHeader MachHeader;
+typedef struct MachNDR MachNDR;
+typedef struct MachPort MachPort;
+typedef struct StackT StackT;
+typedef struct SigactionT SigactionT;
+typedef struct Siginfo Siginfo;
+typedef struct Timeval Timeval;
+typedef struct Itimerval Itimerval;
+typedef struct Timespec Timespec;
+typedef struct FPControl FPControl;
+typedef struct FPStatus FPStatus;
+typedef struct RegMMST RegMMST;
+typedef struct RegXMM RegXMM;
+typedef struct Regs64 Regs64;
+typedef struct FloatState64 FloatState64;
+typedef struct ExceptionState64 ExceptionState64;
+typedef struct Mcontext64 Mcontext64;
+typedef struct Regs32 Regs32;
+typedef struct FloatState32 FloatState32;
+typedef struct ExceptionState32 ExceptionState32;
+typedef struct Mcontext32 Mcontext32;
+typedef struct Ucontext Ucontext;
+typedef struct KeventT KeventT;
+
+#pragma pack on
+
+struct MachBody {
+	uint32	msgh_descriptor_count;
+};
+struct MachHeader {
+	uint32	msgh_bits;
+	uint32	msgh_size;
+	uint32	msgh_remote_port;
+	uint32	msgh_local_port;
+	uint32	msgh_reserved;
+	int32	msgh_id;
+};
+struct MachNDR {
+	uint8	mig_vers;
+	uint8	if_vers;
+	uint8	reserved1;
+	uint8	mig_encoding;
+	uint8	int_rep;
+	uint8	char_rep;
+	uint8	float_rep;
+	uint8	reserved2;
+};
+struct MachPort {
+	uint32	name;
+	uint32	pad1;
+	uint16	pad2;
+	uint8	disposition;
+	uint8	type;
+};
+
+struct StackT {
+	byte	*ss_sp;
+	uint32	ss_size;
+	int32	ss_flags;
+};
+typedef	byte	Sighandler[4];
+
+struct SigactionT {
+	byte	__sigaction_u[4];
+	void	*sa_tramp;
+	uint32	sa_mask;
+	int32	sa_flags;
+};
+
+typedef	byte	Sigval[4];
+struct Siginfo {
+	int32	si_signo;
+	int32	si_errno;
+	int32	si_code;
+	int32	si_pid;
+	uint32	si_uid;
+	int32	si_status;
+	byte	*si_addr;
+	byte	si_value[4];
+	int32	si_band;
+	uint32	__pad[7];
+};
+struct Timeval {
+	int32	tv_sec;
+	int32	tv_usec;
+};
+struct Itimerval {
+	Timeval	it_interval;
+	Timeval	it_value;
+};
+struct Timespec {
+	int32	tv_sec;
+	int32	tv_nsec;
+};
+
+struct FPControl {
+	byte	Pad_cgo_0[2];
+};
+struct FPStatus {
+	byte	Pad_cgo_0[2];
+};
+struct RegMMST {
+	int8	mmst_reg[10];
+	int8	mmst_rsrv[6];
+};
+struct RegXMM {
+	int8	xmm_reg[16];
+};
+
+struct Regs64 {
+	uint64	rax;
+	uint64	rbx;
+	uint64	rcx;
+	uint64	rdx;
+	uint64	rdi;
+	uint64	rsi;
+	uint64	rbp;
+	uint64	rsp;
+	uint64	r8;
+	uint64	r9;
+	uint64	r10;
+	uint64	r11;
+	uint64	r12;
+	uint64	r13;
+	uint64	r14;
+	uint64	r15;
+	uint64	rip;
+	uint64	rflags;
+	uint64	cs;
+	uint64	fs;
+	uint64	gs;
+};
+struct FloatState64 {
+	int32	fpu_reserved[2];
+	FPControl	fpu_fcw;
+	FPStatus	fpu_fsw;
+	uint8	fpu_ftw;
+	uint8	fpu_rsrv1;
+	uint16	fpu_fop;
+	uint32	fpu_ip;
+	uint16	fpu_cs;
+	uint16	fpu_rsrv2;
+	uint32	fpu_dp;
+	uint16	fpu_ds;
+	uint16	fpu_rsrv3;
+	uint32	fpu_mxcsr;
+	uint32	fpu_mxcsrmask;
+	RegMMST	fpu_stmm0;
+	RegMMST	fpu_stmm1;
+	RegMMST	fpu_stmm2;
+	RegMMST	fpu_stmm3;
+	RegMMST	fpu_stmm4;
+	RegMMST	fpu_stmm5;
+	RegMMST	fpu_stmm6;
+	RegMMST	fpu_stmm7;
+	RegXMM	fpu_xmm0;
+	RegXMM	fpu_xmm1;
+	RegXMM	fpu_xmm2;
+	RegXMM	fpu_xmm3;
+	RegXMM	fpu_xmm4;
+	RegXMM	fpu_xmm5;
+	RegXMM	fpu_xmm6;
+	RegXMM	fpu_xmm7;
+	RegXMM	fpu_xmm8;
+	RegXMM	fpu_xmm9;
+	RegXMM	fpu_xmm10;
+	RegXMM	fpu_xmm11;
+	RegXMM	fpu_xmm12;
+	RegXMM	fpu_xmm13;
+	RegXMM	fpu_xmm14;
+	RegXMM	fpu_xmm15;
+	int8	fpu_rsrv4[96];
+	int32	fpu_reserved1;
+};
+struct ExceptionState64 {
+	uint16	trapno;
+	uint16	cpu;
+	uint32	err;
+	uint64	faultvaddr;
+};
+struct Mcontext64 {
+	ExceptionState64	es;
+	Regs64	ss;
+	FloatState64	fs;
+};
+
+struct Regs32 {
+	uint32	eax;
+	uint32	ebx;
+	uint32	ecx;
+	uint32	edx;
+	uint32	edi;
+	uint32	esi;
+	uint32	ebp;
+	uint32	esp;
+	uint32	ss;
+	uint32	eflags;
+	uint32	eip;
+	uint32	cs;
+	uint32	ds;
+	uint32	es;
+	uint32	fs;
+	uint32	gs;
+};
+struct FloatState32 {
+	int32	fpu_reserved[2];
+	FPControl	fpu_fcw;
+	FPStatus	fpu_fsw;
+	uint8	fpu_ftw;
+	uint8	fpu_rsrv1;
+	uint16	fpu_fop;
+	uint32	fpu_ip;
+	uint16	fpu_cs;
+	uint16	fpu_rsrv2;
+	uint32	fpu_dp;
+	uint16	fpu_ds;
+	uint16	fpu_rsrv3;
+	uint32	fpu_mxcsr;
+	uint32	fpu_mxcsrmask;
+	RegMMST	fpu_stmm0;
+	RegMMST	fpu_stmm1;
+	RegMMST	fpu_stmm2;
+	RegMMST	fpu_stmm3;
+	RegMMST	fpu_stmm4;
+	RegMMST	fpu_stmm5;
+	RegMMST	fpu_stmm6;
+	RegMMST	fpu_stmm7;
+	RegXMM	fpu_xmm0;
+	RegXMM	fpu_xmm1;
+	RegXMM	fpu_xmm2;
+	RegXMM	fpu_xmm3;
+	RegXMM	fpu_xmm4;
+	RegXMM	fpu_xmm5;
+	RegXMM	fpu_xmm6;
+	RegXMM	fpu_xmm7;
+	int8	fpu_rsrv4[224];
+	int32	fpu_reserved1;
+};
+struct ExceptionState32 {
+	uint16	trapno;
+	uint16	cpu;
+	uint32	err;
+	uint32	faultvaddr;
+};
+struct Mcontext32 {
+	ExceptionState32	es;
+	Regs32	ss;
+	FloatState32	fs;
+};
+
+struct Ucontext {
+	int32	uc_onstack;
+	uint32	uc_sigmask;
+	StackT	uc_stack;
+	Ucontext	*uc_link;
+	uint32	uc_mcsize;
+	Mcontext32	*uc_mcontext;
+};
+
+struct KeventT {
+	uint32	ident;
+	int16	filter;
+	uint16	flags;
+	uint32	fflags;
+	int32	data;
+	byte	*udata;
+};
+
+
+#pragma pack off
diff --git a/src/runtime/defs_darwin_amd64.h b/src/runtime/defs_darwin_amd64.h
new file mode 100644
index 0000000..4bf83c1
--- /dev/null
+++ b/src/runtime/defs_darwin_amd64.h
@@ -0,0 +1,395 @@
+// Created by cgo -cdefs - DO NOT EDIT
+// cgo -cdefs defs_darwin.go
+
+
+enum {
+	EINTR	= 0x4,
+	EFAULT	= 0xe,
+
+	PROT_NONE	= 0x0,
+	PROT_READ	= 0x1,
+	PROT_WRITE	= 0x2,
+	PROT_EXEC	= 0x4,
+
+	MAP_ANON	= 0x1000,
+	MAP_PRIVATE	= 0x2,
+	MAP_FIXED	= 0x10,
+
+	MADV_DONTNEED	= 0x4,
+	MADV_FREE	= 0x5,
+
+	MACH_MSG_TYPE_MOVE_RECEIVE	= 0x10,
+	MACH_MSG_TYPE_MOVE_SEND		= 0x11,
+	MACH_MSG_TYPE_MOVE_SEND_ONCE	= 0x12,
+	MACH_MSG_TYPE_COPY_SEND		= 0x13,
+	MACH_MSG_TYPE_MAKE_SEND		= 0x14,
+	MACH_MSG_TYPE_MAKE_SEND_ONCE	= 0x15,
+	MACH_MSG_TYPE_COPY_RECEIVE	= 0x16,
+
+	MACH_MSG_PORT_DESCRIPTOR		= 0x0,
+	MACH_MSG_OOL_DESCRIPTOR			= 0x1,
+	MACH_MSG_OOL_PORTS_DESCRIPTOR		= 0x2,
+	MACH_MSG_OOL_VOLATILE_DESCRIPTOR	= 0x3,
+
+	MACH_MSGH_BITS_COMPLEX	= 0x80000000,
+
+	MACH_SEND_MSG	= 0x1,
+	MACH_RCV_MSG	= 0x2,
+	MACH_RCV_LARGE	= 0x4,
+
+	MACH_SEND_TIMEOUT	= 0x10,
+	MACH_SEND_INTERRUPT	= 0x40,
+	MACH_SEND_ALWAYS	= 0x10000,
+	MACH_SEND_TRAILER	= 0x20000,
+	MACH_RCV_TIMEOUT	= 0x100,
+	MACH_RCV_NOTIFY		= 0x200,
+	MACH_RCV_INTERRUPT	= 0x400,
+	MACH_RCV_OVERWRITE	= 0x1000,
+
+	NDR_PROTOCOL_2_0	= 0x0,
+	NDR_INT_BIG_ENDIAN	= 0x0,
+	NDR_INT_LITTLE_ENDIAN	= 0x1,
+	NDR_FLOAT_IEEE		= 0x0,
+	NDR_CHAR_ASCII		= 0x0,
+
+	SA_SIGINFO	= 0x40,
+	SA_RESTART	= 0x2,
+	SA_ONSTACK	= 0x1,
+	SA_USERTRAMP	= 0x100,
+	SA_64REGSET	= 0x200,
+
+	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		= 0x10,
+	SIGSTOP		= 0x11,
+	SIGTSTP		= 0x12,
+	SIGCONT		= 0x13,
+	SIGCHLD		= 0x14,
+	SIGTTIN		= 0x15,
+	SIGTTOU		= 0x16,
+	SIGIO		= 0x17,
+	SIGXCPU		= 0x18,
+	SIGXFSZ		= 0x19,
+	SIGVTALRM	= 0x1a,
+	SIGPROF		= 0x1b,
+	SIGWINCH	= 0x1c,
+	SIGINFO		= 0x1d,
+	SIGUSR1		= 0x1e,
+	SIGUSR2		= 0x1f,
+
+	FPE_INTDIV	= 0x7,
+	FPE_INTOVF	= 0x8,
+	FPE_FLTDIV	= 0x1,
+	FPE_FLTOVF	= 0x2,
+	FPE_FLTUND	= 0x3,
+	FPE_FLTRES	= 0x4,
+	FPE_FLTINV	= 0x5,
+	FPE_FLTSUB	= 0x6,
+
+	BUS_ADRALN	= 0x1,
+	BUS_ADRERR	= 0x2,
+	BUS_OBJERR	= 0x3,
+
+	SEGV_MAPERR	= 0x1,
+	SEGV_ACCERR	= 0x2,
+
+	ITIMER_REAL	= 0x0,
+	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,
+};
+
+typedef struct MachBody MachBody;
+typedef struct MachHeader MachHeader;
+typedef struct MachNDR MachNDR;
+typedef struct MachPort MachPort;
+typedef struct StackT StackT;
+typedef struct SigactionT SigactionT;
+typedef struct Siginfo Siginfo;
+typedef struct Timeval Timeval;
+typedef struct Itimerval Itimerval;
+typedef struct Timespec Timespec;
+typedef struct FPControl FPControl;
+typedef struct FPStatus FPStatus;
+typedef struct RegMMST RegMMST;
+typedef struct RegXMM RegXMM;
+typedef struct Regs64 Regs64;
+typedef struct FloatState64 FloatState64;
+typedef struct ExceptionState64 ExceptionState64;
+typedef struct Mcontext64 Mcontext64;
+typedef struct Regs32 Regs32;
+typedef struct FloatState32 FloatState32;
+typedef struct ExceptionState32 ExceptionState32;
+typedef struct Mcontext32 Mcontext32;
+typedef struct Ucontext Ucontext;
+typedef struct KeventT KeventT;
+
+#pragma pack on
+
+struct MachBody {
+	uint32	msgh_descriptor_count;
+};
+struct MachHeader {
+	uint32	msgh_bits;
+	uint32	msgh_size;
+	uint32	msgh_remote_port;
+	uint32	msgh_local_port;
+	uint32	msgh_reserved;
+	int32	msgh_id;
+};
+struct MachNDR {
+	uint8	mig_vers;
+	uint8	if_vers;
+	uint8	reserved1;
+	uint8	mig_encoding;
+	uint8	int_rep;
+	uint8	char_rep;
+	uint8	float_rep;
+	uint8	reserved2;
+};
+struct MachPort {
+	uint32	name;
+	uint32	pad1;
+	uint16	pad2;
+	uint8	disposition;
+	uint8	type;
+};
+
+struct StackT {
+	byte	*ss_sp;
+	uint64	ss_size;
+	int32	ss_flags;
+	byte	Pad_cgo_0[4];
+};
+typedef	byte	Sighandler[8];
+
+struct SigactionT {
+	byte	__sigaction_u[8];
+	void	*sa_tramp;
+	uint32	sa_mask;
+	int32	sa_flags;
+};
+
+typedef	byte	Sigval[8];
+struct Siginfo {
+	int32	si_signo;
+	int32	si_errno;
+	int32	si_code;
+	int32	si_pid;
+	uint32	si_uid;
+	int32	si_status;
+	byte	*si_addr;
+	byte	si_value[8];
+	int64	si_band;
+	uint64	__pad[7];
+};
+struct Timeval {
+	int64	tv_sec;
+	int32	tv_usec;
+	byte	Pad_cgo_0[4];
+};
+struct Itimerval {
+	Timeval	it_interval;
+	Timeval	it_value;
+};
+struct Timespec {
+	int64	tv_sec;
+	int64	tv_nsec;
+};
+
+struct FPControl {
+	byte	Pad_cgo_0[2];
+};
+struct FPStatus {
+	byte	Pad_cgo_0[2];
+};
+struct RegMMST {
+	int8	mmst_reg[10];
+	int8	mmst_rsrv[6];
+};
+struct RegXMM {
+	int8	xmm_reg[16];
+};
+
+struct Regs64 {
+	uint64	rax;
+	uint64	rbx;
+	uint64	rcx;
+	uint64	rdx;
+	uint64	rdi;
+	uint64	rsi;
+	uint64	rbp;
+	uint64	rsp;
+	uint64	r8;
+	uint64	r9;
+	uint64	r10;
+	uint64	r11;
+	uint64	r12;
+	uint64	r13;
+	uint64	r14;
+	uint64	r15;
+	uint64	rip;
+	uint64	rflags;
+	uint64	cs;
+	uint64	fs;
+	uint64	gs;
+};
+struct FloatState64 {
+	int32	fpu_reserved[2];
+	FPControl	fpu_fcw;
+	FPStatus	fpu_fsw;
+	uint8	fpu_ftw;
+	uint8	fpu_rsrv1;
+	uint16	fpu_fop;
+	uint32	fpu_ip;
+	uint16	fpu_cs;
+	uint16	fpu_rsrv2;
+	uint32	fpu_dp;
+	uint16	fpu_ds;
+	uint16	fpu_rsrv3;
+	uint32	fpu_mxcsr;
+	uint32	fpu_mxcsrmask;
+	RegMMST	fpu_stmm0;
+	RegMMST	fpu_stmm1;
+	RegMMST	fpu_stmm2;
+	RegMMST	fpu_stmm3;
+	RegMMST	fpu_stmm4;
+	RegMMST	fpu_stmm5;
+	RegMMST	fpu_stmm6;
+	RegMMST	fpu_stmm7;
+	RegXMM	fpu_xmm0;
+	RegXMM	fpu_xmm1;
+	RegXMM	fpu_xmm2;
+	RegXMM	fpu_xmm3;
+	RegXMM	fpu_xmm4;
+	RegXMM	fpu_xmm5;
+	RegXMM	fpu_xmm6;
+	RegXMM	fpu_xmm7;
+	RegXMM	fpu_xmm8;
+	RegXMM	fpu_xmm9;
+	RegXMM	fpu_xmm10;
+	RegXMM	fpu_xmm11;
+	RegXMM	fpu_xmm12;
+	RegXMM	fpu_xmm13;
+	RegXMM	fpu_xmm14;
+	RegXMM	fpu_xmm15;
+	int8	fpu_rsrv4[96];
+	int32	fpu_reserved1;
+};
+struct ExceptionState64 {
+	uint16	trapno;
+	uint16	cpu;
+	uint32	err;
+	uint64	faultvaddr;
+};
+struct Mcontext64 {
+	ExceptionState64	es;
+	Regs64	ss;
+	FloatState64	fs;
+	byte	Pad_cgo_0[4];
+};
+
+struct Regs32 {
+	uint32	eax;
+	uint32	ebx;
+	uint32	ecx;
+	uint32	edx;
+	uint32	edi;
+	uint32	esi;
+	uint32	ebp;
+	uint32	esp;
+	uint32	ss;
+	uint32	eflags;
+	uint32	eip;
+	uint32	cs;
+	uint32	ds;
+	uint32	es;
+	uint32	fs;
+	uint32	gs;
+};
+struct FloatState32 {
+	int32	fpu_reserved[2];
+	FPControl	fpu_fcw;
+	FPStatus	fpu_fsw;
+	uint8	fpu_ftw;
+	uint8	fpu_rsrv1;
+	uint16	fpu_fop;
+	uint32	fpu_ip;
+	uint16	fpu_cs;
+	uint16	fpu_rsrv2;
+	uint32	fpu_dp;
+	uint16	fpu_ds;
+	uint16	fpu_rsrv3;
+	uint32	fpu_mxcsr;
+	uint32	fpu_mxcsrmask;
+	RegMMST	fpu_stmm0;
+	RegMMST	fpu_stmm1;
+	RegMMST	fpu_stmm2;
+	RegMMST	fpu_stmm3;
+	RegMMST	fpu_stmm4;
+	RegMMST	fpu_stmm5;
+	RegMMST	fpu_stmm6;
+	RegMMST	fpu_stmm7;
+	RegXMM	fpu_xmm0;
+	RegXMM	fpu_xmm1;
+	RegXMM	fpu_xmm2;
+	RegXMM	fpu_xmm3;
+	RegXMM	fpu_xmm4;
+	RegXMM	fpu_xmm5;
+	RegXMM	fpu_xmm6;
+	RegXMM	fpu_xmm7;
+	int8	fpu_rsrv4[224];
+	int32	fpu_reserved1;
+};
+struct ExceptionState32 {
+	uint16	trapno;
+	uint16	cpu;
+	uint32	err;
+	uint32	faultvaddr;
+};
+struct Mcontext32 {
+	ExceptionState32	es;
+	Regs32	ss;
+	FloatState32	fs;
+};
+
+struct Ucontext {
+	int32	uc_onstack;
+	uint32	uc_sigmask;
+	StackT	uc_stack;
+	Ucontext	*uc_link;
+	uint64	uc_mcsize;
+	Mcontext64	*uc_mcontext;
+};
+
+struct KeventT {
+	uint64	ident;
+	int16	filter;
+	uint16	flags;
+	uint32	fflags;
+	int64	data;
+	byte	*udata;
+};
+
+
+#pragma pack off
diff --git a/src/runtime/defs_dragonfly.go b/src/runtime/defs_dragonfly.go
index c5ebe75..555b8f5 100644
--- a/src/runtime/defs_dragonfly.go
+++ b/src/runtime/defs_dragonfly.go
@@ -8,6 +8,7 @@
 Input to cgo.
 
 GOARCH=amd64 go tool cgo -cdefs defs_dragonfly.go >defs_dragonfly_amd64.h
+GOARCH=386 go tool cgo -cdefs defs_dragonfly.go >defs_dragonfly_386.h
 */
 
 package runtime
diff --git a/src/runtime/defs_dragonfly_386.h b/src/runtime/defs_dragonfly_386.h
new file mode 100644
index 0000000..f86b9c6
--- /dev/null
+++ b/src/runtime/defs_dragonfly_386.h
@@ -0,0 +1,198 @@
+// Created by cgo -cdefs - DO NOT EDIT
+// cgo -cdefs defs_dragonfly.go
+
+
+enum {
+	EINTR	= 0x4,
+	EFAULT	= 0xe,
+	EBUSY	= 0x10,
+	EAGAIN	= 0x23,
+
+	PROT_NONE	= 0x0,
+	PROT_READ	= 0x1,
+	PROT_WRITE	= 0x2,
+	PROT_EXEC	= 0x4,
+
+	MAP_ANON	= 0x1000,
+	MAP_PRIVATE	= 0x2,
+	MAP_FIXED	= 0x10,
+
+	MADV_FREE	= 0x5,
+
+	SA_SIGINFO	= 0x40,
+	SA_RESTART	= 0x2,
+	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		= 0x10,
+	SIGSTOP		= 0x11,
+	SIGTSTP		= 0x12,
+	SIGCONT		= 0x13,
+	SIGCHLD		= 0x14,
+	SIGTTIN		= 0x15,
+	SIGTTOU		= 0x16,
+	SIGIO		= 0x17,
+	SIGXCPU		= 0x18,
+	SIGXFSZ		= 0x19,
+	SIGVTALRM	= 0x1a,
+	SIGPROF		= 0x1b,
+	SIGWINCH	= 0x1c,
+	SIGINFO		= 0x1d,
+	SIGUSR1		= 0x1e,
+	SIGUSR2		= 0x1f,
+
+	FPE_INTDIV	= 0x2,
+	FPE_INTOVF	= 0x1,
+	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,
+
+	EV_ADD		= 0x1,
+	EV_DELETE	= 0x2,
+	EV_CLEAR	= 0x20,
+	EV_ERROR	= 0x4000,
+	EVFILT_READ	= -0x1,
+	EVFILT_WRITE	= -0x2,
+};
+
+typedef struct Rtprio Rtprio;
+typedef struct Lwpparams Lwpparams;
+typedef struct SigaltstackT SigaltstackT;
+typedef struct Sigset Sigset;
+typedef struct StackT StackT;
+typedef struct Siginfo Siginfo;
+typedef struct Mcontext Mcontext;
+typedef struct Ucontext Ucontext;
+typedef struct Timespec Timespec;
+typedef struct Timeval Timeval;
+typedef struct Itimerval Itimerval;
+typedef struct KeventT KeventT;
+
+#pragma pack on
+
+struct Rtprio {
+	uint16	type;
+	uint16	prio;
+};
+struct Lwpparams {
+	void	*func;
+	byte	*arg;
+	byte	*stack;
+	int32	*tid1;
+	int32	*tid2;
+};
+struct SigaltstackT {
+	int8	*ss_sp;
+	uint32	ss_size;
+	int32	ss_flags;
+};
+struct Sigset {
+	uint32	__bits[4];
+};
+struct StackT {
+	int8	*ss_sp;
+	uint32	ss_size;
+	int32	ss_flags;
+};
+
+struct Siginfo {
+	int32	si_signo;
+	int32	si_errno;
+	int32	si_code;
+	int32	si_pid;
+	uint32	si_uid;
+	int32	si_status;
+	byte	*si_addr;
+	byte	si_value[4];
+	int32	si_band;
+	int32	__spare__[7];
+};
+
+struct Mcontext {
+	int32	mc_onstack;
+	int32	mc_gs;
+	int32	mc_fs;
+	int32	mc_es;
+	int32	mc_ds;
+	int32	mc_edi;
+	int32	mc_esi;
+	int32	mc_ebp;
+	int32	mc_isp;
+	int32	mc_ebx;
+	int32	mc_edx;
+	int32	mc_ecx;
+	int32	mc_eax;
+	int32	mc_xflags;
+	int32	mc_trapno;
+	int32	mc_err;
+	int32	mc_eip;
+	int32	mc_cs;
+	int32	mc_eflags;
+	int32	mc_esp;
+	int32	mc_ss;
+	int32	mc_len;
+	int32	mc_fpformat;
+	int32	mc_ownedfp;
+	int32	mc_fpregs[128];
+	int32	__spare__[16];
+};
+struct Ucontext {
+	Sigset	uc_sigmask;
+	Mcontext	uc_mcontext;
+	Ucontext	*uc_link;
+	StackT	uc_stack;
+	int32	__spare__[8];
+};
+
+struct Timespec {
+	int32	tv_sec;
+	int32	tv_nsec;
+};
+struct Timeval {
+	int32	tv_sec;
+	int32	tv_usec;
+};
+struct Itimerval {
+	Timeval	it_interval;
+	Timeval	it_value;
+};
+
+struct KeventT {
+	uint32	ident;
+	int16	filter;
+	uint16	flags;
+	uint32	fflags;
+	int32	data;
+	byte	*udata;
+};
+
+
+#pragma pack off
diff --git a/src/runtime/defs_dragonfly_amd64.h b/src/runtime/defs_dragonfly_amd64.h
new file mode 100644
index 0000000..6715552
--- /dev/null
+++ b/src/runtime/defs_dragonfly_amd64.h
@@ -0,0 +1,208 @@
+// Created by cgo -cdefs - DO NOT EDIT
+// cgo -cdefs defs_dragonfly.go
+
+
+enum {
+	EINTR	= 0x4,
+	EFAULT	= 0xe,
+	EBUSY	= 0x10,
+	EAGAIN	= 0x23,
+
+	PROT_NONE	= 0x0,
+	PROT_READ	= 0x1,
+	PROT_WRITE	= 0x2,
+	PROT_EXEC	= 0x4,
+
+	MAP_ANON	= 0x1000,
+	MAP_PRIVATE	= 0x2,
+	MAP_FIXED	= 0x10,
+
+	MADV_FREE	= 0x5,
+
+	SA_SIGINFO	= 0x40,
+	SA_RESTART	= 0x2,
+	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		= 0x10,
+	SIGSTOP		= 0x11,
+	SIGTSTP		= 0x12,
+	SIGCONT		= 0x13,
+	SIGCHLD		= 0x14,
+	SIGTTIN		= 0x15,
+	SIGTTOU		= 0x16,
+	SIGIO		= 0x17,
+	SIGXCPU		= 0x18,
+	SIGXFSZ		= 0x19,
+	SIGVTALRM	= 0x1a,
+	SIGPROF		= 0x1b,
+	SIGWINCH	= 0x1c,
+	SIGINFO		= 0x1d,
+	SIGUSR1		= 0x1e,
+	SIGUSR2		= 0x1f,
+
+	FPE_INTDIV	= 0x2,
+	FPE_INTOVF	= 0x1,
+	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,
+
+	EV_ADD		= 0x1,
+	EV_DELETE	= 0x2,
+	EV_CLEAR	= 0x20,
+	EV_ERROR	= 0x4000,
+	EVFILT_READ	= -0x1,
+	EVFILT_WRITE	= -0x2,
+};
+
+typedef struct Rtprio Rtprio;
+typedef struct Lwpparams Lwpparams;
+typedef struct SigaltstackT SigaltstackT;
+typedef struct Sigset Sigset;
+typedef struct StackT StackT;
+typedef struct Siginfo Siginfo;
+typedef struct Mcontext Mcontext;
+typedef struct Ucontext Ucontext;
+typedef struct Timespec Timespec;
+typedef struct Timeval Timeval;
+typedef struct Itimerval Itimerval;
+typedef struct KeventT KeventT;
+
+#pragma pack on
+
+struct Rtprio {
+	uint16	type;
+	uint16	prio;
+};
+struct Lwpparams {
+	void	*func;
+	byte	*arg;
+	byte	*stack;
+	int32	*tid1;
+	int32	*tid2;
+};
+struct SigaltstackT {
+	int8	*ss_sp;
+	uint64	ss_size;
+	int32	ss_flags;
+	byte	Pad_cgo_0[4];
+};
+struct Sigset {
+	uint32	__bits[4];
+};
+struct StackT {
+	int8	*ss_sp;
+	uint64	ss_size;
+	int32	ss_flags;
+	byte	Pad_cgo_0[4];
+};
+
+struct Siginfo {
+	int32	si_signo;
+	int32	si_errno;
+	int32	si_code;
+	int32	si_pid;
+	uint32	si_uid;
+	int32	si_status;
+	byte	*si_addr;
+	byte	si_value[8];
+	int64	si_band;
+	int32	__spare__[7];
+	byte	Pad_cgo_0[4];
+};
+
+struct Mcontext {
+	int64	mc_onstack;
+	int64	mc_rdi;
+	int64	mc_rsi;
+	int64	mc_rdx;
+	int64	mc_rcx;
+	int64	mc_r8;
+	int64	mc_r9;
+	int64	mc_rax;
+	int64	mc_rbx;
+	int64	mc_rbp;
+	int64	mc_r10;
+	int64	mc_r11;
+	int64	mc_r12;
+	int64	mc_r13;
+	int64	mc_r14;
+	int64	mc_r15;
+	int64	mc_xflags;
+	int64	mc_trapno;
+	int64	mc_addr;
+	int64	mc_flags;
+	int64	mc_err;
+	int64	mc_rip;
+	int64	mc_cs;
+	int64	mc_rflags;
+	int64	mc_rsp;
+	int64	mc_ss;
+	uint32	mc_len;
+	uint32	mc_fpformat;
+	uint32	mc_ownedfp;
+	uint32	mc_reserved;
+	uint32	mc_unused[8];
+	int32	mc_fpregs[256];
+};
+struct Ucontext {
+	Sigset	uc_sigmask;
+	byte	Pad_cgo_0[48];
+	Mcontext	uc_mcontext;
+	Ucontext	*uc_link;
+	StackT	uc_stack;
+	int32	__spare__[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 KeventT {
+	uint64	ident;
+	int16	filter;
+	uint16	flags;
+	uint32	fflags;
+	int64	data;
+	byte	*udata;
+};
+
+
+#pragma pack off
diff --git a/src/runtime/defs_freebsd_386.h b/src/runtime/defs_freebsd_386.h
new file mode 100644
index 0000000..156dccb
--- /dev/null
+++ b/src/runtime/defs_freebsd_386.h
@@ -0,0 +1,213 @@
+// Created by cgo -cdefs - DO NOT EDIT
+// cgo -cdefs defs_freebsd.go
+
+
+enum {
+	EINTR	= 0x4,
+	EFAULT	= 0xe,
+
+	PROT_NONE	= 0x0,
+	PROT_READ	= 0x1,
+	PROT_WRITE	= 0x2,
+	PROT_EXEC	= 0x4,
+
+	MAP_ANON	= 0x1000,
+	MAP_PRIVATE	= 0x2,
+	MAP_FIXED	= 0x10,
+
+	MADV_FREE	= 0x5,
+
+	SA_SIGINFO	= 0x40,
+	SA_RESTART	= 0x2,
+	SA_ONSTACK	= 0x1,
+
+	UMTX_OP_WAIT_UINT		= 0xb,
+	UMTX_OP_WAIT_UINT_PRIVATE	= 0xf,
+	UMTX_OP_WAKE			= 0x3,
+	UMTX_OP_WAKE_PRIVATE		= 0x10,
+
+	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		= 0x10,
+	SIGSTOP		= 0x11,
+	SIGTSTP		= 0x12,
+	SIGCONT		= 0x13,
+	SIGCHLD		= 0x14,
+	SIGTTIN		= 0x15,
+	SIGTTOU		= 0x16,
+	SIGIO		= 0x17,
+	SIGXCPU		= 0x18,
+	SIGXFSZ		= 0x19,
+	SIGVTALRM	= 0x1a,
+	SIGPROF		= 0x1b,
+	SIGWINCH	= 0x1c,
+	SIGINFO		= 0x1d,
+	SIGUSR1		= 0x1e,
+	SIGUSR2		= 0x1f,
+
+	FPE_INTDIV	= 0x2,
+	FPE_INTOVF	= 0x1,
+	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,
+
+	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;
+typedef struct ThrParam ThrParam;
+typedef struct SigaltstackT SigaltstackT;
+typedef struct Sigset Sigset;
+typedef struct StackT StackT;
+typedef struct Siginfo Siginfo;
+typedef struct Mcontext Mcontext;
+typedef struct Ucontext Ucontext;
+typedef struct Timespec Timespec;
+typedef struct Timeval Timeval;
+typedef struct Itimerval Itimerval;
+typedef struct KeventT KeventT;
+
+#pragma pack on
+
+struct Rtprio {
+	uint16	type;
+	uint16	prio;
+};
+struct ThrParam {
+	void	*start_func;
+	byte	*arg;
+	int8	*stack_base;
+	uint32	stack_size;
+	int8	*tls_base;
+	uint32	tls_size;
+	int32	*child_tid;
+	int32	*parent_tid;
+	int32	flags;
+	Rtprio	*rtp;
+	void	*spare[3];
+};
+struct SigaltstackT {
+	int8	*ss_sp;
+	uint32	ss_size;
+	int32	ss_flags;
+};
+struct Sigset {
+	uint32	__bits[4];
+};
+struct StackT {
+	int8	*ss_sp;
+	uint32	ss_size;
+	int32	ss_flags;
+};
+
+struct Siginfo {
+	int32	si_signo;
+	int32	si_errno;
+	int32	si_code;
+	int32	si_pid;
+	uint32	si_uid;
+	int32	si_status;
+	byte	*si_addr;
+	byte	si_value[4];
+	byte	_reason[32];
+};
+
+struct Mcontext {
+	int32	mc_onstack;
+	int32	mc_gs;
+	int32	mc_fs;
+	int32	mc_es;
+	int32	mc_ds;
+	int32	mc_edi;
+	int32	mc_esi;
+	int32	mc_ebp;
+	int32	mc_isp;
+	int32	mc_ebx;
+	int32	mc_edx;
+	int32	mc_ecx;
+	int32	mc_eax;
+	int32	mc_trapno;
+	int32	mc_err;
+	int32	mc_eip;
+	int32	mc_cs;
+	int32	mc_eflags;
+	int32	mc_esp;
+	int32	mc_ss;
+	int32	mc_len;
+	int32	mc_fpformat;
+	int32	mc_ownedfp;
+	int32	mc_flags;
+	int32	mc_fpstate[128];
+	int32	mc_fsbase;
+	int32	mc_gsbase;
+	int32	mc_xfpustate;
+	int32	mc_xfpustate_len;
+	int32	mc_spare2[4];
+};
+struct Ucontext {
+	Sigset	uc_sigmask;
+	Mcontext	uc_mcontext;
+	Ucontext	*uc_link;
+	StackT	uc_stack;
+	int32	uc_flags;
+	int32	__spare__[4];
+	byte	Pad_cgo_0[12];
+};
+
+struct Timespec {
+	int32	tv_sec;
+	int32	tv_nsec;
+};
+struct Timeval {
+	int32	tv_sec;
+	int32	tv_usec;
+};
+struct Itimerval {
+	Timeval	it_interval;
+	Timeval	it_value;
+};
+
+struct KeventT {
+	uint32	ident;
+	int16	filter;
+	uint16	flags;
+	uint32	fflags;
+	int32	data;
+	byte	*udata;
+};
+
+
+#pragma pack off
diff --git a/src/runtime/defs_freebsd_amd64.h b/src/runtime/defs_freebsd_amd64.h
new file mode 100644
index 0000000..4ba8956
--- /dev/null
+++ b/src/runtime/defs_freebsd_amd64.h
@@ -0,0 +1,224 @@
+// Created by cgo -cdefs - DO NOT EDIT
+// cgo -cdefs defs_freebsd.go
+
+
+enum {
+	EINTR	= 0x4,
+	EFAULT	= 0xe,
+
+	PROT_NONE	= 0x0,
+	PROT_READ	= 0x1,
+	PROT_WRITE	= 0x2,
+	PROT_EXEC	= 0x4,
+
+	MAP_ANON	= 0x1000,
+	MAP_PRIVATE	= 0x2,
+	MAP_FIXED	= 0x10,
+
+	MADV_FREE	= 0x5,
+
+	SA_SIGINFO	= 0x40,
+	SA_RESTART	= 0x2,
+	SA_ONSTACK	= 0x1,
+
+	UMTX_OP_WAIT_UINT		= 0xb,
+	UMTX_OP_WAIT_UINT_PRIVATE	= 0xf,
+	UMTX_OP_WAKE			= 0x3,
+	UMTX_OP_WAKE_PRIVATE		= 0x10,
+
+	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		= 0x10,
+	SIGSTOP		= 0x11,
+	SIGTSTP		= 0x12,
+	SIGCONT		= 0x13,
+	SIGCHLD		= 0x14,
+	SIGTTIN		= 0x15,
+	SIGTTOU		= 0x16,
+	SIGIO		= 0x17,
+	SIGXCPU		= 0x18,
+	SIGXFSZ		= 0x19,
+	SIGVTALRM	= 0x1a,
+	SIGPROF		= 0x1b,
+	SIGWINCH	= 0x1c,
+	SIGINFO		= 0x1d,
+	SIGUSR1		= 0x1e,
+	SIGUSR2		= 0x1f,
+
+	FPE_INTDIV	= 0x2,
+	FPE_INTOVF	= 0x1,
+	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,
+
+	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;
+typedef struct ThrParam ThrParam;
+typedef struct SigaltstackT SigaltstackT;
+typedef struct Sigset Sigset;
+typedef struct StackT StackT;
+typedef struct Siginfo Siginfo;
+typedef struct Mcontext Mcontext;
+typedef struct Ucontext Ucontext;
+typedef struct Timespec Timespec;
+typedef struct Timeval Timeval;
+typedef struct Itimerval Itimerval;
+typedef struct KeventT KeventT;
+
+#pragma pack on
+
+struct Rtprio {
+	uint16	type;
+	uint16	prio;
+};
+struct ThrParam {
+	void	*start_func;
+	byte	*arg;
+	int8	*stack_base;
+	uint64	stack_size;
+	int8	*tls_base;
+	uint64	tls_size;
+	int64	*child_tid;
+	int64	*parent_tid;
+	int32	flags;
+	byte	Pad_cgo_0[4];
+	Rtprio	*rtp;
+	void	*spare[3];
+};
+struct SigaltstackT {
+	int8	*ss_sp;
+	uint64	ss_size;
+	int32	ss_flags;
+	byte	Pad_cgo_0[4];
+};
+struct Sigset {
+	uint32	__bits[4];
+};
+struct StackT {
+	int8	*ss_sp;
+	uint64	ss_size;
+	int32	ss_flags;
+	byte	Pad_cgo_0[4];
+};
+
+struct Siginfo {
+	int32	si_signo;
+	int32	si_errno;
+	int32	si_code;
+	int32	si_pid;
+	uint32	si_uid;
+	int32	si_status;
+	byte	*si_addr;
+	byte	si_value[8];
+	byte	_reason[40];
+};
+
+struct Mcontext {
+	int64	mc_onstack;
+	int64	mc_rdi;
+	int64	mc_rsi;
+	int64	mc_rdx;
+	int64	mc_rcx;
+	int64	mc_r8;
+	int64	mc_r9;
+	int64	mc_rax;
+	int64	mc_rbx;
+	int64	mc_rbp;
+	int64	mc_r10;
+	int64	mc_r11;
+	int64	mc_r12;
+	int64	mc_r13;
+	int64	mc_r14;
+	int64	mc_r15;
+	uint32	mc_trapno;
+	uint16	mc_fs;
+	uint16	mc_gs;
+	int64	mc_addr;
+	uint32	mc_flags;
+	uint16	mc_es;
+	uint16	mc_ds;
+	int64	mc_err;
+	int64	mc_rip;
+	int64	mc_cs;
+	int64	mc_rflags;
+	int64	mc_rsp;
+	int64	mc_ss;
+	int64	mc_len;
+	int64	mc_fpformat;
+	int64	mc_ownedfp;
+	int64	mc_fpstate[64];
+	int64	mc_fsbase;
+	int64	mc_gsbase;
+	int64	mc_xfpustate;
+	int64	mc_xfpustate_len;
+	int64	mc_spare[4];
+};
+struct Ucontext {
+	Sigset	uc_sigmask;
+	Mcontext	uc_mcontext;
+	Ucontext	*uc_link;
+	StackT	uc_stack;
+	int32	uc_flags;
+	int32	__spare__[4];
+	byte	Pad_cgo_0[12];
+};
+
+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 KeventT {
+	uint64	ident;
+	int16	filter;
+	uint16	flags;
+	uint32	fflags;
+	int64	data;
+	byte	*udata;
+};
+
+
+#pragma pack off
diff --git a/src/runtime/defs_freebsd_arm.h b/src/runtime/defs_freebsd_arm.h
new file mode 100644
index 0000000..17deba6
--- /dev/null
+++ b/src/runtime/defs_freebsd_arm.h
@@ -0,0 +1,186 @@
+// Created by cgo -cdefs - DO NOT EDIT
+// cgo -cdefs defs_freebsd.go
+
+
+enum {
+	EINTR	= 0x4,
+	EFAULT	= 0xe,
+
+	PROT_NONE	= 0x0,
+	PROT_READ	= 0x1,
+	PROT_WRITE	= 0x2,
+	PROT_EXEC	= 0x4,
+
+	MAP_ANON	= 0x1000,
+	MAP_PRIVATE	= 0x2,
+	MAP_FIXED	= 0x10,
+
+	MADV_FREE	= 0x5,
+
+	SA_SIGINFO	= 0x40,
+	SA_RESTART	= 0x2,
+	SA_ONSTACK	= 0x1,
+
+	UMTX_OP_WAIT_UINT		= 0xb,
+	UMTX_OP_WAIT_UINT_PRIVATE	= 0xf,
+	UMTX_OP_WAKE			= 0x3,
+	UMTX_OP_WAKE_PRIVATE		= 0x10,
+
+	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		= 0x10,
+	SIGSTOP		= 0x11,
+	SIGTSTP		= 0x12,
+	SIGCONT		= 0x13,
+	SIGCHLD		= 0x14,
+	SIGTTIN		= 0x15,
+	SIGTTOU		= 0x16,
+	SIGIO		= 0x17,
+	SIGXCPU		= 0x18,
+	SIGXFSZ		= 0x19,
+	SIGVTALRM	= 0x1a,
+	SIGPROF		= 0x1b,
+	SIGWINCH	= 0x1c,
+	SIGINFO		= 0x1d,
+	SIGUSR1		= 0x1e,
+	SIGUSR2		= 0x1f,
+
+	FPE_INTDIV	= 0x2,
+	FPE_INTOVF	= 0x1,
+	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,
+
+	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;
+typedef struct ThrParam ThrParam;
+typedef struct SigaltstackT SigaltstackT;
+typedef struct Sigset Sigset;
+typedef struct StackT StackT;
+typedef struct Siginfo Siginfo;
+typedef struct Mcontext Mcontext;
+typedef struct Ucontext Ucontext;
+typedef struct Timespec Timespec;
+typedef struct Timeval Timeval;
+typedef struct Itimerval Itimerval;
+typedef struct KeventT KeventT;
+
+#pragma pack on
+
+struct Rtprio {
+	uint16	type;
+	uint16	prio;
+};
+struct ThrParam {
+	void	*start_func;
+	byte	*arg;
+	uint8	*stack_base;
+	uint32	stack_size;
+	uint8	*tls_base;
+	uint32	tls_size;
+	int32	*child_tid;
+	int32	*parent_tid;
+	int32	flags;
+	Rtprio	*rtp;
+	void	*spare[3];
+};
+struct SigaltstackT {
+	uint8	*ss_sp;
+	uint32	ss_size;
+	int32	ss_flags;
+};
+struct Sigset {
+	uint32	__bits[4];
+};
+struct StackT {
+	uint8	*ss_sp;
+	uint32	ss_size;
+	int32	ss_flags;
+};
+
+struct Siginfo {
+	int32	si_signo;
+	int32	si_errno;
+	int32	si_code;
+	int32	si_pid;
+	uint32	si_uid;
+	int32	si_status;
+	byte	*si_addr;
+	byte	si_value[4];
+	byte	_reason[32];
+};
+
+struct Mcontext {
+	uint32	__gregs[17];
+	byte	__fpu[140];
+};
+struct Ucontext {
+	Sigset	uc_sigmask;
+	Mcontext	uc_mcontext;
+	Ucontext	*uc_link;
+	StackT	uc_stack;
+	int32	uc_flags;
+	int32	__spare__[4];
+};
+
+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;
+	Timeval	it_value;
+};
+
+struct KeventT {
+	uint32	ident;
+	int16	filter;
+	uint16	flags;
+	uint32	fflags;
+	int32	data;
+	byte	*udata;
+};
+
+
+#pragma pack off
diff --git a/src/runtime/defs_linux.go b/src/runtime/defs_linux.go
index 553366a..8657dbb 100644
--- a/src/runtime/defs_linux.go
+++ b/src/runtime/defs_linux.go
@@ -20,7 +20,6 @@ package runtime
 // headers for things like ucontext_t, so that happens in
 // a separate file, defs1.go.
 
-#define	_SYS_TYPES_H	// avoid inclusion of sys/types.h
 #include <asm/posix_types.h>
 #define size_t __kernel_size_t
 #include <asm/signal.h>
@@ -29,7 +28,7 @@ package runtime
 #include <asm-generic/errno.h>
 #include <asm-generic/poll.h>
 #include <linux/eventpoll.h>
-#include <linux/time.h>
+#undef size_t
 */
 import "C"
 
@@ -49,9 +48,10 @@ const (
 
 	MADV_DONTNEED = C.MADV_DONTNEED
 
-	SA_RESTART = C.SA_RESTART
-	SA_ONSTACK = C.SA_ONSTACK
-	SA_SIGINFO = C.SA_SIGINFO
+	SA_RESTART  = C.SA_RESTART
+	SA_ONSTACK  = C.SA_ONSTACK
+	SA_RESTORER = C.SA_RESTORER
+	SA_SIGINFO  = C.SA_SIGINFO
 
 	SIGHUP    = C.SIGHUP
 	SIGINT    = C.SIGINT
@@ -116,7 +116,6 @@ const (
 	EPOLL_CTL_MOD = C.EPOLL_CTL_MOD
 )
 
-type Sigset C.sigset_t
 type Timespec C.struct_timespec
 type Timeval C.struct_timeval
 type Sigaction C.struct_sigaction
diff --git a/src/runtime/defs_linux_386.h b/src/runtime/defs_linux_386.h
new file mode 100644
index 0000000..24a05d8
--- /dev/null
+++ b/src/runtime/defs_linux_386.h
@@ -0,0 +1,211 @@
+// Created by cgo -cdefs - DO NOT EDIT
+// cgo -cdefs defs2_linux.go
+
+
+enum {
+	EINTR	= 0x4,
+	EAGAIN	= 0xb,
+	ENOMEM	= 0xc,
+
+	PROT_NONE	= 0x0,
+	PROT_READ	= 0x1,
+	PROT_WRITE	= 0x2,
+	PROT_EXEC	= 0x4,
+
+	MAP_ANON	= 0x20,
+	MAP_PRIVATE	= 0x2,
+	MAP_FIXED	= 0x10,
+
+	MADV_DONTNEED	= 0x4,
+
+	SA_RESTART	= 0x10000000,
+	SA_ONSTACK	= 0x8000000,
+	SA_RESTORER	= 0x4000000,
+	SA_SIGINFO	= 0x4,
+
+	SIGHUP		= 0x1,
+	SIGINT		= 0x2,
+	SIGQUIT		= 0x3,
+	SIGILL		= 0x4,
+	SIGTRAP		= 0x5,
+	SIGABRT		= 0x6,
+	SIGBUS		= 0x7,
+	SIGFPE		= 0x8,
+	SIGKILL		= 0x9,
+	SIGUSR1		= 0xa,
+	SIGSEGV		= 0xb,
+	SIGUSR2		= 0xc,
+	SIGPIPE		= 0xd,
+	SIGALRM		= 0xe,
+	SIGSTKFLT	= 0x10,
+	SIGCHLD		= 0x11,
+	SIGCONT		= 0x12,
+	SIGSTOP		= 0x13,
+	SIGTSTP		= 0x14,
+	SIGTTIN		= 0x15,
+	SIGTTOU		= 0x16,
+	SIGURG		= 0x17,
+	SIGXCPU		= 0x18,
+	SIGXFSZ		= 0x19,
+	SIGVTALRM	= 0x1a,
+	SIGPROF		= 0x1b,
+	SIGWINCH	= 0x1c,
+	SIGIO		= 0x1d,
+	SIGPWR		= 0x1e,
+	SIGSYS		= 0x1f,
+
+	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,
+
+	O_RDONLY	= 0x0,
+	O_CLOEXEC	= 0x80000,
+
+	EPOLLIN		= 0x1,
+	EPOLLOUT	= 0x4,
+	EPOLLERR	= 0x8,
+	EPOLLHUP	= 0x10,
+	EPOLLRDHUP	= 0x2000,
+	EPOLLET		= -0x80000000,
+	EPOLL_CLOEXEC	= 0x80000,
+	EPOLL_CTL_ADD	= 0x1,
+	EPOLL_CTL_DEL	= 0x2,
+	EPOLL_CTL_MOD	= 0x3,
+};
+
+typedef struct Fpreg Fpreg;
+typedef struct Fpxreg Fpxreg;
+typedef struct Xmmreg Xmmreg;
+typedef struct Fpstate Fpstate;
+typedef struct Timespec Timespec;
+typedef struct Timeval Timeval;
+typedef struct SigactionT SigactionT;
+typedef struct Siginfo Siginfo;
+typedef struct SigaltstackT SigaltstackT;
+typedef struct Sigcontext Sigcontext;
+typedef struct Ucontext Ucontext;
+typedef struct Itimerval Itimerval;
+typedef struct EpollEvent EpollEvent;
+
+#pragma pack on
+
+struct Fpreg {
+	uint16	significand[4];
+	uint16	exponent;
+};
+struct Fpxreg {
+	uint16	significand[4];
+	uint16	exponent;
+	uint16	padding[3];
+};
+struct Xmmreg {
+	uint32	element[4];
+};
+struct Fpstate {
+	uint32	cw;
+	uint32	sw;
+	uint32	tag;
+	uint32	ipoff;
+	uint32	cssel;
+	uint32	dataoff;
+	uint32	datasel;
+	Fpreg	_st[8];
+	uint16	status;
+	uint16	magic;
+	uint32	_fxsr_env[6];
+	uint32	mxcsr;
+	uint32	reserved;
+	Fpxreg	_fxsr_st[8];
+	Xmmreg	_xmm[8];
+	uint32	padding1[44];
+	byte	anon0[48];
+};
+struct Timespec {
+	int32	tv_sec;
+	int32	tv_nsec;
+};
+struct Timeval {
+	int32	tv_sec;
+	int32	tv_usec;
+};
+struct SigactionT {
+	void	*k_sa_handler;
+	uint32	sa_flags;
+	void	*sa_restorer;
+	uint64	sa_mask;
+};
+struct Siginfo {
+	int32	si_signo;
+	int32	si_errno;
+	int32	si_code;
+	byte	_sifields[116];
+};
+struct SigaltstackT {
+	byte	*ss_sp;
+	int32	ss_flags;
+	uint32	ss_size;
+};
+struct Sigcontext {
+	uint16	gs;
+	uint16	__gsh;
+	uint16	fs;
+	uint16	__fsh;
+	uint16	es;
+	uint16	__esh;
+	uint16	ds;
+	uint16	__dsh;
+	uint32	edi;
+	uint32	esi;
+	uint32	ebp;
+	uint32	esp;
+	uint32	ebx;
+	uint32	edx;
+	uint32	ecx;
+	uint32	eax;
+	uint32	trapno;
+	uint32	err;
+	uint32	eip;
+	uint16	cs;
+	uint16	__csh;
+	uint32	eflags;
+	uint32	esp_at_signal;
+	uint16	ss;
+	uint16	__ssh;
+	Fpstate	*fpstate;
+	uint32	oldmask;
+	uint32	cr2;
+};
+struct Ucontext {
+	uint32	uc_flags;
+	Ucontext	*uc_link;
+	SigaltstackT	uc_stack;
+	Sigcontext	uc_mcontext;
+	uint32	uc_sigmask;
+};
+struct Itimerval {
+	Timeval	it_interval;
+	Timeval	it_value;
+};
+struct EpollEvent {
+	uint32	events;
+	byte	data[8]; // to match amd64
+};
+
+
+#pragma pack off
diff --git a/src/runtime/defs_linux_amd64.h b/src/runtime/defs_linux_amd64.h
new file mode 100644
index 0000000..14616df
--- /dev/null
+++ b/src/runtime/defs_linux_amd64.h
@@ -0,0 +1,254 @@
+// Created by cgo -cdefs - DO NOT EDIT
+// cgo -cdefs defs_linux.go defs1_linux.go
+
+
+enum {
+	EINTR	= 0x4,
+	EAGAIN	= 0xb,
+	ENOMEM	= 0xc,
+
+	PROT_NONE	= 0x0,
+	PROT_READ	= 0x1,
+	PROT_WRITE	= 0x2,
+	PROT_EXEC	= 0x4,
+
+	MAP_ANON	= 0x20,
+	MAP_PRIVATE	= 0x2,
+	MAP_FIXED	= 0x10,
+
+	MADV_DONTNEED	= 0x4,
+
+	SA_RESTART	= 0x10000000,
+	SA_ONSTACK	= 0x8000000,
+	SA_RESTORER	= 0x4000000,
+	SA_SIGINFO	= 0x4,
+
+	SIGHUP		= 0x1,
+	SIGINT		= 0x2,
+	SIGQUIT		= 0x3,
+	SIGILL		= 0x4,
+	SIGTRAP		= 0x5,
+	SIGABRT		= 0x6,
+	SIGBUS		= 0x7,
+	SIGFPE		= 0x8,
+	SIGKILL		= 0x9,
+	SIGUSR1		= 0xa,
+	SIGSEGV		= 0xb,
+	SIGUSR2		= 0xc,
+	SIGPIPE		= 0xd,
+	SIGALRM		= 0xe,
+	SIGSTKFLT	= 0x10,
+	SIGCHLD		= 0x11,
+	SIGCONT		= 0x12,
+	SIGSTOP		= 0x13,
+	SIGTSTP		= 0x14,
+	SIGTTIN		= 0x15,
+	SIGTTOU		= 0x16,
+	SIGURG		= 0x17,
+	SIGXCPU		= 0x18,
+	SIGXFSZ		= 0x19,
+	SIGVTALRM	= 0x1a,
+	SIGPROF		= 0x1b,
+	SIGWINCH	= 0x1c,
+	SIGIO		= 0x1d,
+	SIGPWR		= 0x1e,
+	SIGSYS		= 0x1f,
+
+	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,
+
+	EPOLLIN		= 0x1,
+	EPOLLOUT	= 0x4,
+	EPOLLERR	= 0x8,
+	EPOLLHUP	= 0x10,
+	EPOLLRDHUP	= 0x2000,
+	EPOLLET		= -0x80000000,
+	EPOLL_CLOEXEC	= 0x80000,
+	EPOLL_CTL_ADD	= 0x1,
+	EPOLL_CTL_DEL	= 0x2,
+	EPOLL_CTL_MOD	= 0x3,
+};
+
+typedef struct Timespec Timespec;
+typedef struct Timeval Timeval;
+typedef struct SigactionT SigactionT;
+typedef struct Siginfo Siginfo;
+typedef struct Itimerval Itimerval;
+typedef struct EpollEvent EpollEvent;
+
+#pragma pack on
+
+struct Timespec {
+	int64	tv_sec;
+	int64	tv_nsec;
+};
+struct Timeval {
+	int64	tv_sec;
+	int64	tv_usec;
+};
+struct SigactionT {
+	void	*sa_handler;
+	uint64	sa_flags;
+	void	*sa_restorer;
+	uint64	sa_mask;
+};
+struct Siginfo {
+	int32	si_signo;
+	int32	si_errno;
+	int32	si_code;
+	byte	Pad_cgo_0[4];
+	byte	_sifields[112];
+};
+struct Itimerval {
+	Timeval	it_interval;
+	Timeval	it_value;
+};
+struct EpollEvent {
+	uint32	events;
+	byte	data[8]; // unaligned uintptr
+};
+
+
+#pragma pack off
+// Created by cgo -cdefs - DO NOT EDIT
+// cgo -cdefs defs_linux.go defs1_linux.go
+
+
+enum {
+	O_RDONLY	= 0x0,
+	O_CLOEXEC	= 0x80000,
+};
+
+typedef struct Usigset Usigset;
+typedef struct Fpxreg Fpxreg;
+typedef struct Xmmreg Xmmreg;
+typedef struct Fpstate Fpstate;
+typedef struct Fpxreg1 Fpxreg1;
+typedef struct Xmmreg1 Xmmreg1;
+typedef struct Fpstate1 Fpstate1;
+typedef struct Fpreg1 Fpreg1;
+typedef struct SigaltstackT SigaltstackT;
+typedef struct Mcontext Mcontext;
+typedef struct Ucontext Ucontext;
+typedef struct Sigcontext Sigcontext;
+
+#pragma pack on
+
+struct Usigset {
+	uint64	__val[16];
+};
+struct Fpxreg {
+	uint16	significand[4];
+	uint16	exponent;
+	uint16	padding[3];
+};
+struct Xmmreg {
+	uint32	element[4];
+};
+struct Fpstate {
+	uint16	cwd;
+	uint16	swd;
+	uint16	ftw;
+	uint16	fop;
+	uint64	rip;
+	uint64	rdp;
+	uint32	mxcsr;
+	uint32	mxcr_mask;
+	Fpxreg	_st[8];
+	Xmmreg	_xmm[16];
+	uint32	padding[24];
+};
+struct Fpxreg1 {
+	uint16	significand[4];
+	uint16	exponent;
+	uint16	padding[3];
+};
+struct Xmmreg1 {
+	uint32	element[4];
+};
+struct Fpstate1 {
+	uint16	cwd;
+	uint16	swd;
+	uint16	ftw;
+	uint16	fop;
+	uint64	rip;
+	uint64	rdp;
+	uint32	mxcsr;
+	uint32	mxcr_mask;
+	Fpxreg1	_st[8];
+	Xmmreg1	_xmm[16];
+	uint32	padding[24];
+};
+struct Fpreg1 {
+	uint16	significand[4];
+	uint16	exponent;
+};
+struct SigaltstackT {
+	byte	*ss_sp;
+	int32	ss_flags;
+	byte	Pad_cgo_0[4];
+	uint64	ss_size;
+};
+struct Mcontext {
+	int64	gregs[23];
+	Fpstate	*fpregs;
+	uint64	__reserved1[8];
+};
+struct Ucontext {
+	uint64	uc_flags;
+	Ucontext	*uc_link;
+	SigaltstackT	uc_stack;
+	Mcontext	uc_mcontext;
+	Usigset	uc_sigmask;
+	Fpstate	__fpregs_mem;
+};
+struct Sigcontext {
+	uint64	r8;
+	uint64	r9;
+	uint64	r10;
+	uint64	r11;
+	uint64	r12;
+	uint64	r13;
+	uint64	r14;
+	uint64	r15;
+	uint64	rdi;
+	uint64	rsi;
+	uint64	rbp;
+	uint64	rbx;
+	uint64	rdx;
+	uint64	rax;
+	uint64	rcx;
+	uint64	rsp;
+	uint64	rip;
+	uint64	eflags;
+	uint16	cs;
+	uint16	gs;
+	uint16	fs;
+	uint16	__pad0;
+	uint64	err;
+	uint64	trapno;
+	uint64	oldmask;
+	uint64	cr2;
+	Fpstate1	*fpstate;
+	uint64	__reserved1[8];
+};
+
+
+#pragma pack off
diff --git a/src/runtime/defs_linux_arm.h b/src/runtime/defs_linux_arm.h
new file mode 100644
index 0000000..50b3c91
--- /dev/null
+++ b/src/runtime/defs_linux_arm.h
@@ -0,0 +1,168 @@
+// TODO: Generate using cgo like defs_linux_{386,amd64}.h
+
+// Constants
+enum {
+	EINTR  = 0x4,
+	ENOMEM = 0xc,
+	EAGAIN = 0xb,
+
+	PROT_NONE = 0,
+	PROT_READ = 0x1,
+	PROT_WRITE = 0x2,
+	PROT_EXEC = 0x4,
+	MAP_ANON = 0x20,
+	MAP_PRIVATE = 0x2,
+	MAP_FIXED = 0x10,
+	MADV_DONTNEED = 0x4,
+	SA_RESTART = 0x10000000,
+	SA_ONSTACK = 0x8000000,
+	SA_RESTORER = 0, // unused on ARM
+	SA_SIGINFO = 0x4,
+	SIGHUP = 0x1,
+	SIGINT = 0x2,
+	SIGQUIT = 0x3,
+	SIGILL = 0x4,
+	SIGTRAP = 0x5,
+	SIGABRT = 0x6,
+	SIGBUS = 0x7,
+	SIGFPE = 0x8,
+	SIGKILL = 0x9,
+	SIGUSR1 = 0xa,
+	SIGSEGV = 0xb,
+	SIGUSR2 = 0xc,
+	SIGPIPE = 0xd,
+	SIGALRM = 0xe,
+	SIGSTKFLT = 0x10,
+	SIGCHLD = 0x11,
+	SIGCONT = 0x12,
+	SIGSTOP = 0x13,
+	SIGTSTP = 0x14,
+	SIGTTIN = 0x15,
+	SIGTTOU = 0x16,
+	SIGURG = 0x17,
+	SIGXCPU = 0x18,
+	SIGXFSZ = 0x19,
+	SIGVTALRM = 0x1a,
+	SIGPROF = 0x1b,
+	SIGWINCH = 0x1c,
+	SIGIO = 0x1d,
+	SIGPWR = 0x1e,
+	SIGSYS = 0x1f,
+	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 = 0,
+	ITIMER_PROF = 0x2,
+	ITIMER_VIRTUAL = 0x1,
+	O_RDONLY = 0,
+	O_CLOEXEC = 02000000,
+
+	EPOLLIN		= 0x1,
+	EPOLLOUT	= 0x4,
+	EPOLLERR	= 0x8,
+	EPOLLHUP	= 0x10,
+	EPOLLRDHUP	= 0x2000,
+	EPOLLET		= -0x80000000,
+	EPOLL_CLOEXEC	= 0x80000,
+	EPOLL_CTL_ADD	= 0x1,
+	EPOLL_CTL_DEL	= 0x2,
+	EPOLL_CTL_MOD	= 0x3,
+};
+
+// Types
+#pragma pack on
+
+typedef struct Timespec Timespec;
+struct Timespec {
+	int32 tv_sec;
+	int32 tv_nsec;
+};
+
+typedef struct SigaltstackT SigaltstackT;
+struct SigaltstackT {
+	void *ss_sp;
+	int32 ss_flags;
+	uint32 ss_size;
+};
+
+typedef struct Sigcontext Sigcontext;
+struct Sigcontext {
+	uint32 trap_no;
+	uint32 error_code;
+	uint32 oldmask;
+	uint32 arm_r0;
+	uint32 arm_r1;
+	uint32 arm_r2;
+	uint32 arm_r3;
+	uint32 arm_r4;
+	uint32 arm_r5;
+	uint32 arm_r6;
+	uint32 arm_r7;
+	uint32 arm_r8;
+	uint32 arm_r9;
+	uint32 arm_r10;
+	uint32 arm_fp;
+	uint32 arm_ip;
+	uint32 arm_sp;
+	uint32 arm_lr;
+	uint32 arm_pc;
+	uint32 arm_cpsr;
+	uint32 fault_address;
+};
+
+typedef struct Ucontext Ucontext;
+struct Ucontext {
+	uint32 uc_flags;
+	Ucontext *uc_link;
+	SigaltstackT uc_stack;
+	Sigcontext uc_mcontext;
+	uint32 uc_sigmask;
+	int32 __unused[31];
+	uint32 uc_regspace[128];
+};
+
+typedef struct Timeval Timeval;
+struct Timeval {
+	int32 tv_sec;
+	int32 tv_usec;
+};
+
+typedef struct Itimerval Itimerval;
+struct Itimerval {
+	Timeval it_interval;
+	Timeval it_value;
+};
+
+typedef struct Siginfo Siginfo;
+struct Siginfo {
+	int32 si_signo;
+	int32 si_errno;
+	int32 si_code;
+	uint8 _sifields[4];
+};
+
+typedef struct SigactionT SigactionT;
+struct SigactionT {
+	void *sa_handler;
+	uint32 sa_flags;
+	void *sa_restorer;
+	uint64 sa_mask;
+};
+
+typedef struct EpollEvent EpollEvent;
+struct EpollEvent {
+	uint32	events;
+	uint32	_pad;
+	byte	data[8]; // to match amd64
+};
+#pragma pack off
diff --git a/src/runtime/defs_nacl_386.h b/src/runtime/defs_nacl_386.h
new file mode 100644
index 0000000..e8fbb38
--- /dev/null
+++ b/src/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/runtime/defs_nacl_amd64p32.h b/src/runtime/defs_nacl_amd64p32.h
new file mode 100644
index 0000000..45663d4
--- /dev/null
+++ b/src/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;
+	} regs;
+};
+
+struct ExcPortableContext
+{
+	uint32	pc;
+	uint32	sp;
+	uint32	fp;
+};
diff --git a/src/runtime/defs_nacl_arm.h b/src/runtime/defs_nacl_arm.h
new file mode 100644
index 0000000..9ce07cc
--- /dev/null
+++ b/src/runtime/defs_nacl_arm.h
@@ -0,0 +1,70 @@
+// 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.
+
+// 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 ExcRegsARM ExcRegsARM;
+
+struct ExcRegsARM
+{
+	uint32	r0;
+	uint32	r1;
+	uint32	r2;
+	uint32	r3;
+	uint32	r4;
+	uint32	r5;
+	uint32	r6;
+	uint32	r7;
+	uint32	r8;
+	uint32	r9;	// the value reported here is undefined.
+	uint32	r10;
+	uint32	r11;
+	uint32	r12;
+	uint32	sp;	/* r13 */
+	uint32	lr;	/* r14 */
+	uint32	pc;	/* r15 */
+	uint32	cpsr;
+};
+
+struct ExcContext
+{
+	uint32	size;
+	uint32	portable_context_offset;
+	uint32	portable_context_size;
+	uint32	arch;
+	uint32	regs_size;
+	uint32	reserved[11];
+	ExcRegsARM	regs;
+};
+
+struct ExcPortableContext
+{
+	uint32	pc;
+	uint32	sp;
+	uint32	fp;
+};
diff --git a/src/runtime/defs_netbsd_386.h b/src/runtime/defs_netbsd_386.h
new file mode 100644
index 0000000..fd87804
--- /dev/null
+++ b/src/runtime/defs_netbsd_386.h
@@ -0,0 +1,182 @@
+// Created by cgo -cdefs - DO NOT EDIT
+// cgo -cdefs defs_netbsd.go defs_netbsd_386.go
+
+
+enum {
+	EINTR	= 0x4,
+	EFAULT	= 0xe,
+
+	PROT_NONE	= 0x0,
+	PROT_READ	= 0x1,
+	PROT_WRITE	= 0x2,
+	PROT_EXEC	= 0x4,
+
+	MAP_ANON	= 0x1000,
+	MAP_PRIVATE	= 0x2,
+	MAP_FIXED	= 0x10,
+
+	MADV_FREE	= 0x6,
+
+	SA_SIGINFO	= 0x40,
+	SA_RESTART	= 0x2,
+	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		= 0x10,
+	SIGSTOP		= 0x11,
+	SIGTSTP		= 0x12,
+	SIGCONT		= 0x13,
+	SIGCHLD		= 0x14,
+	SIGTTIN		= 0x15,
+	SIGTTOU		= 0x16,
+	SIGIO		= 0x17,
+	SIGXCPU		= 0x18,
+	SIGXFSZ		= 0x19,
+	SIGVTALRM	= 0x1a,
+	SIGPROF		= 0x1b,
+	SIGWINCH	= 0x1c,
+	SIGINFO		= 0x1d,
+	SIGUSR1		= 0x1e,
+	SIGUSR2		= 0x1f,
+
+	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,
+
+	EV_ADD		= 0x1,
+	EV_DELETE	= 0x2,
+	EV_CLEAR	= 0x20,
+	EV_RECEIPT	= 0,
+	EV_ERROR	= 0x4000,
+	EVFILT_READ	= 0x0,
+	EVFILT_WRITE	= 0x1,
+};
+
+typedef struct SigaltstackT SigaltstackT;
+typedef struct Sigset Sigset;
+typedef struct Siginfo Siginfo;
+typedef struct StackT StackT;
+typedef struct Timespec Timespec;
+typedef struct Timeval Timeval;
+typedef struct Itimerval Itimerval;
+typedef struct McontextT McontextT;
+typedef struct UcontextT UcontextT;
+typedef struct KeventT KeventT;
+
+#pragma pack on
+
+struct SigaltstackT {
+	byte	*ss_sp;
+	uint32	ss_size;
+	int32	ss_flags;
+};
+struct Sigset {
+	uint32	__bits[4];
+};
+struct Siginfo {
+	int32	_signo;
+	int32	_code;
+	int32	_errno;
+	byte	_reason[20];
+};
+
+struct StackT {
+	byte	*ss_sp;
+	uint32	ss_size;
+	int32	ss_flags;
+};
+
+struct Timespec {
+	int64	tv_sec;
+	int32	tv_nsec;
+};
+struct Timeval {
+	int64	tv_sec;
+	int32	tv_usec;
+};
+struct Itimerval {
+	Timeval	it_interval;
+	Timeval	it_value;
+};
+
+struct McontextT {
+	int32	__gregs[19];
+	byte	__fpregs[644];
+	int32	_mc_tlsbase;
+};
+struct UcontextT {
+	uint32	uc_flags;
+	UcontextT	*uc_link;
+	Sigset	uc_sigmask;
+	StackT	uc_stack;
+	McontextT	uc_mcontext;
+	int32	__uc_pad[4];
+};
+
+struct KeventT {
+	uint32	ident;
+	uint32	filter;
+	uint32	flags;
+	uint32	fflags;
+	int64	data;
+	byte	*udata;
+};
+
+
+#pragma pack off
+// Created by cgo -cdefs - DO NOT EDIT
+// cgo -cdefs defs_netbsd.go defs_netbsd_386.go
+
+
+enum {
+	REG_GS		= 0x0,
+	REG_FS		= 0x1,
+	REG_ES		= 0x2,
+	REG_DS		= 0x3,
+	REG_EDI		= 0x4,
+	REG_ESI		= 0x5,
+	REG_EBP		= 0x6,
+	REG_ESP		= 0x7,
+	REG_EBX		= 0x8,
+	REG_EDX		= 0x9,
+	REG_ECX		= 0xa,
+	REG_EAX		= 0xb,
+	REG_TRAPNO	= 0xc,
+	REG_ERR		= 0xd,
+	REG_EIP		= 0xe,
+	REG_CS		= 0xf,
+	REG_EFL		= 0x10,
+	REG_UESP	= 0x11,
+	REG_SS		= 0x12,
+};
+
diff --git a/src/runtime/defs_netbsd_amd64.h b/src/runtime/defs_netbsd_amd64.h
new file mode 100644
index 0000000..dac94b1
--- /dev/null
+++ b/src/runtime/defs_netbsd_amd64.h
@@ -0,0 +1,194 @@
+// Created by cgo -cdefs - DO NOT EDIT
+// cgo -cdefs defs_netbsd.go defs_netbsd_amd64.go
+
+
+enum {
+	EINTR	= 0x4,
+	EFAULT	= 0xe,
+
+	PROT_NONE	= 0x0,
+	PROT_READ	= 0x1,
+	PROT_WRITE	= 0x2,
+	PROT_EXEC	= 0x4,
+
+	MAP_ANON	= 0x1000,
+	MAP_PRIVATE	= 0x2,
+	MAP_FIXED	= 0x10,
+
+	MADV_FREE	= 0x6,
+
+	SA_SIGINFO	= 0x40,
+	SA_RESTART	= 0x2,
+	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		= 0x10,
+	SIGSTOP		= 0x11,
+	SIGTSTP		= 0x12,
+	SIGCONT		= 0x13,
+	SIGCHLD		= 0x14,
+	SIGTTIN		= 0x15,
+	SIGTTOU		= 0x16,
+	SIGIO		= 0x17,
+	SIGXCPU		= 0x18,
+	SIGXFSZ		= 0x19,
+	SIGVTALRM	= 0x1a,
+	SIGPROF		= 0x1b,
+	SIGWINCH	= 0x1c,
+	SIGINFO		= 0x1d,
+	SIGUSR1		= 0x1e,
+	SIGUSR2		= 0x1f,
+
+	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,
+
+	EV_ADD		= 0x1,
+	EV_DELETE	= 0x2,
+	EV_CLEAR	= 0x20,
+	EV_RECEIPT	= 0,
+	EV_ERROR	= 0x4000,
+	EVFILT_READ	= 0x0,
+	EVFILT_WRITE	= 0x1,
+};
+
+typedef struct SigaltstackT SigaltstackT;
+typedef struct Sigset Sigset;
+typedef struct Siginfo Siginfo;
+typedef struct StackT StackT;
+typedef struct Timespec Timespec;
+typedef struct Timeval Timeval;
+typedef struct Itimerval Itimerval;
+typedef struct McontextT McontextT;
+typedef struct UcontextT UcontextT;
+typedef struct KeventT KeventT;
+
+#pragma pack on
+
+struct SigaltstackT {
+	byte	*ss_sp;
+	uint64	ss_size;
+	int32	ss_flags;
+	byte	Pad_cgo_0[4];
+};
+struct Sigset {
+	uint32	__bits[4];
+};
+struct Siginfo {
+	int32	_signo;
+	int32	_code;
+	int32	_errno;
+	int32	_pad;
+	byte	_reason[24];
+};
+
+struct StackT {
+	byte	*ss_sp;
+	uint64	ss_size;
+	int32	ss_flags;
+	byte	Pad_cgo_0[4];
+};
+
+struct Timespec {
+	int64	tv_sec;
+	int64	tv_nsec;
+};
+struct Timeval {
+	int64	tv_sec;
+	int32	tv_usec;
+	byte	Pad_cgo_0[4];
+};
+struct Itimerval {
+	Timeval	it_interval;
+	Timeval	it_value;
+};
+
+struct McontextT {
+	uint64	__gregs[26];
+	uint64	_mc_tlsbase;
+	int8	__fpregs[512];
+};
+struct UcontextT {
+	uint32	uc_flags;
+	byte	Pad_cgo_0[4];
+	UcontextT	*uc_link;
+	Sigset	uc_sigmask;
+	StackT	uc_stack;
+	McontextT	uc_mcontext;
+};
+
+struct KeventT {
+	uint64	ident;
+	uint32	filter;
+	uint32	flags;
+	uint32	fflags;
+	byte	Pad_cgo_0[4];
+	int64	data;
+	byte	*udata;
+};
+
+
+#pragma pack off
+// Created by cgo -cdefs - DO NOT EDIT
+// cgo -cdefs defs_netbsd.go defs_netbsd_amd64.go
+
+
+enum {
+	REG_RDI		= 0x0,
+	REG_RSI		= 0x1,
+	REG_RDX		= 0x2,
+	REG_RCX		= 0x3,
+	REG_R8		= 0x4,
+	REG_R9		= 0x5,
+	REG_R10		= 0x6,
+	REG_R11		= 0x7,
+	REG_R12		= 0x8,
+	REG_R13		= 0x9,
+	REG_R14		= 0xa,
+	REG_R15		= 0xb,
+	REG_RBP		= 0xc,
+	REG_RBX		= 0xd,
+	REG_RAX		= 0xe,
+	REG_GS		= 0xf,
+	REG_FS		= 0x10,
+	REG_ES		= 0x11,
+	REG_DS		= 0x12,
+	REG_TRAPNO	= 0x13,
+	REG_ERR		= 0x14,
+	REG_RIP		= 0x15,
+	REG_CS		= 0x16,
+	REG_RFLAGS	= 0x17,
+	REG_RSP		= 0x18,
+	REG_SS		= 0x19,
+};
+
diff --git a/src/runtime/defs_netbsd_arm.h b/src/runtime/defs_netbsd_arm.h
new file mode 100644
index 0000000..70f34af
--- /dev/null
+++ b/src/runtime/defs_netbsd_arm.h
@@ -0,0 +1,184 @@
+// Created by cgo -cdefs - DO NOT EDIT
+// cgo -cdefs defs_netbsd.go defs_netbsd_arm.go
+
+
+enum {
+	EINTR	= 0x4,
+	EFAULT	= 0xe,
+
+	PROT_NONE	= 0x0,
+	PROT_READ	= 0x1,
+	PROT_WRITE	= 0x2,
+	PROT_EXEC	= 0x4,
+
+	MAP_ANON	= 0x1000,
+	MAP_PRIVATE	= 0x2,
+	MAP_FIXED	= 0x10,
+
+	MADV_FREE	= 0x6,
+
+	SA_SIGINFO	= 0x40,
+	SA_RESTART	= 0x2,
+	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		= 0x10,
+	SIGSTOP		= 0x11,
+	SIGTSTP		= 0x12,
+	SIGCONT		= 0x13,
+	SIGCHLD		= 0x14,
+	SIGTTIN		= 0x15,
+	SIGTTOU		= 0x16,
+	SIGIO		= 0x17,
+	SIGXCPU		= 0x18,
+	SIGXFSZ		= 0x19,
+	SIGVTALRM	= 0x1a,
+	SIGPROF		= 0x1b,
+	SIGWINCH	= 0x1c,
+	SIGINFO		= 0x1d,
+	SIGUSR1		= 0x1e,
+	SIGUSR2		= 0x1f,
+
+	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,
+
+	EV_ADD		= 0x1,
+	EV_DELETE	= 0x2,
+	EV_CLEAR	= 0x20,
+	EV_RECEIPT	= 0,
+	EV_ERROR	= 0x4000,
+	EVFILT_READ	= 0x0,
+	EVFILT_WRITE	= 0x1,
+};
+
+typedef struct SigaltstackT SigaltstackT;
+typedef struct Sigset Sigset;
+typedef struct Siginfo Siginfo;
+typedef struct StackT StackT;
+typedef struct Timespec Timespec;
+typedef struct Timeval Timeval;
+typedef struct Itimerval Itimerval;
+typedef struct McontextT McontextT;
+typedef struct UcontextT UcontextT;
+typedef struct KeventT KeventT;
+
+#pragma pack on
+
+struct SigaltstackT {
+	byte	*ss_sp;
+	uint32	ss_size;
+	int32	ss_flags;
+};
+struct Sigset {
+	uint32	__bits[4];
+};
+struct Siginfo {
+	int32	_signo;
+	int32	_code;
+	int32	_errno;
+	byte	_reason[20];
+};
+
+struct StackT {
+	byte	*ss_sp;
+	uint32	ss_size;
+	int32	ss_flags;
+};
+
+struct Timespec {
+	int64	tv_sec;
+	int32	tv_nsec;
+};
+struct Timeval {
+	int64	tv_sec;
+	int32	tv_usec;
+};
+struct Itimerval {
+	Timeval	it_interval;
+	Timeval	it_value;
+};
+
+struct McontextT {
+	uint32	__gregs[17];
+#ifdef __ARM_EABI__
+	byte	__fpu[4+8*32+4];
+#else
+	byte	__fpu[4+4*33+4];
+#endif
+	uint32	_mc_tlsbase;
+};
+struct UcontextT {
+	uint32	uc_flags;
+	UcontextT	*uc_link;
+	Sigset	uc_sigmask;
+	StackT	uc_stack;
+	McontextT	uc_mcontext;
+	int32	__uc_pad[2];
+};
+
+struct KeventT {
+	uint32	ident;
+	uint32	filter;
+	uint32	flags;
+	uint32	fflags;
+	int64	data;
+	byte	*udata;
+};
+
+
+#pragma pack off
+// Created by cgo -cdefs - DO NOT EDIT
+// cgo -cdefs defs_netbsd.go defs_netbsd_arm.go
+
+
+enum {
+	REG_R0		= 0x0,
+	REG_R1		= 0x1,
+	REG_R2		= 0x2,
+	REG_R3		= 0x3,
+	REG_R4		= 0x4,
+	REG_R5		= 0x5,
+	REG_R6		= 0x6,
+	REG_R7		= 0x7,
+	REG_R8		= 0x8,
+	REG_R9		= 0x9,
+	REG_R10		= 0xa,
+	REG_R11		= 0xb,
+	REG_R12		= 0xc,
+	REG_R13		= 0xd,
+	REG_R14		= 0xe,
+	REG_R15		= 0xf,
+	REG_CPSR	= 0x10,
+};
+
diff --git a/src/runtime/defs_openbsd_386.h b/src/runtime/defs_openbsd_386.h
new file mode 100644
index 0000000..6b77e00
--- /dev/null
+++ b/src/runtime/defs_openbsd_386.h
@@ -0,0 +1,168 @@
+// Created by cgo -cdefs - DO NOT EDIT
+// cgo -cdefs defs_openbsd.go
+
+
+enum {
+	EINTR	= 0x4,
+	EFAULT	= 0xe,
+
+	PROT_NONE	= 0x0,
+	PROT_READ	= 0x1,
+	PROT_WRITE	= 0x2,
+	PROT_EXEC	= 0x4,
+
+	MAP_ANON	= 0x1000,
+	MAP_PRIVATE	= 0x2,
+	MAP_FIXED	= 0x10,
+
+	MADV_FREE	= 0x6,
+
+	SA_SIGINFO	= 0x40,
+	SA_RESTART	= 0x2,
+	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		= 0x10,
+	SIGSTOP		= 0x11,
+	SIGTSTP		= 0x12,
+	SIGCONT		= 0x13,
+	SIGCHLD		= 0x14,
+	SIGTTIN		= 0x15,
+	SIGTTOU		= 0x16,
+	SIGIO		= 0x17,
+	SIGXCPU		= 0x18,
+	SIGXFSZ		= 0x19,
+	SIGVTALRM	= 0x1a,
+	SIGPROF		= 0x1b,
+	SIGWINCH	= 0x1c,
+	SIGINFO		= 0x1d,
+	SIGUSR1		= 0x1e,
+	SIGUSR2		= 0x1f,
+
+	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,
+
+	EV_ADD		= 0x1,
+	EV_DELETE	= 0x2,
+	EV_CLEAR	= 0x20,
+	EV_ERROR	= 0x4000,
+	EVFILT_READ	= -0x1,
+	EVFILT_WRITE	= -0x2,
+};
+
+typedef struct TforkT TforkT;
+typedef struct SigaltstackT SigaltstackT;
+typedef struct Sigcontext Sigcontext;
+typedef struct Siginfo Siginfo;
+typedef struct StackT StackT;
+typedef struct Timespec Timespec;
+typedef struct Timeval Timeval;
+typedef struct Itimerval Itimerval;
+typedef struct KeventT KeventT;
+
+#pragma pack on
+
+struct TforkT {
+	byte	*tf_tcb;
+	int32	*tf_tid;
+	byte	*tf_stack;
+};
+
+struct SigaltstackT {
+	byte	*ss_sp;
+	uint32	ss_size;
+	int32	ss_flags;
+};
+struct Sigcontext {
+	int32	sc_gs;
+	int32	sc_fs;
+	int32	sc_es;
+	int32	sc_ds;
+	int32	sc_edi;
+	int32	sc_esi;
+	int32	sc_ebp;
+	int32	sc_ebx;
+	int32	sc_edx;
+	int32	sc_ecx;
+	int32	sc_eax;
+	int32	sc_eip;
+	int32	sc_cs;
+	int32	sc_eflags;
+	int32	sc_esp;
+	int32	sc_ss;
+	int32	__sc_unused;
+	int32	sc_mask;
+	int32	sc_trapno;
+	int32	sc_err;
+	void	*sc_fpstate;
+};
+struct Siginfo {
+	int32	si_signo;
+	int32	si_code;
+	int32	si_errno;
+	byte	_data[116];
+};
+typedef	uint32	Sigset;
+typedef	byte	Sigval[4];
+
+struct StackT {
+	byte	*ss_sp;
+	uint32	ss_size;
+	int32	ss_flags;
+};
+
+struct Timespec {
+	int64	tv_sec;
+	int32	tv_nsec;
+};
+struct Timeval {
+	int64	tv_sec;
+	int32	tv_usec;
+};
+struct Itimerval {
+	Timeval	it_interval;
+	Timeval	it_value;
+};
+
+struct KeventT {
+	uint32	ident;
+	int16	filter;
+	uint16	flags;
+	uint32	fflags;
+	int64	data;
+	byte	*udata;
+};
+
+
+#pragma pack off
diff --git a/src/runtime/defs_openbsd_amd64.h b/src/runtime/defs_openbsd_amd64.h
new file mode 100644
index 0000000..761e8e4
--- /dev/null
+++ b/src/runtime/defs_openbsd_amd64.h
@@ -0,0 +1,179 @@
+// Created by cgo -cdefs - DO NOT EDIT
+// cgo -cdefs defs_openbsd.go
+
+
+enum {
+	EINTR	= 0x4,
+	EFAULT	= 0xe,
+
+	PROT_NONE	= 0x0,
+	PROT_READ	= 0x1,
+	PROT_WRITE	= 0x2,
+	PROT_EXEC	= 0x4,
+
+	MAP_ANON	= 0x1000,
+	MAP_PRIVATE	= 0x2,
+	MAP_FIXED	= 0x10,
+
+	MADV_FREE	= 0x6,
+
+	SA_SIGINFO	= 0x40,
+	SA_RESTART	= 0x2,
+	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		= 0x10,
+	SIGSTOP		= 0x11,
+	SIGTSTP		= 0x12,
+	SIGCONT		= 0x13,
+	SIGCHLD		= 0x14,
+	SIGTTIN		= 0x15,
+	SIGTTOU		= 0x16,
+	SIGIO		= 0x17,
+	SIGXCPU		= 0x18,
+	SIGXFSZ		= 0x19,
+	SIGVTALRM	= 0x1a,
+	SIGPROF		= 0x1b,
+	SIGWINCH	= 0x1c,
+	SIGINFO		= 0x1d,
+	SIGUSR1		= 0x1e,
+	SIGUSR2		= 0x1f,
+
+	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,
+
+	EV_ADD		= 0x1,
+	EV_DELETE	= 0x2,
+	EV_CLEAR	= 0x20,
+	EV_ERROR	= 0x4000,
+	EVFILT_READ	= -0x1,
+	EVFILT_WRITE	= -0x2,
+};
+
+typedef struct TforkT TforkT;
+typedef struct SigaltstackT SigaltstackT;
+typedef struct Sigcontext Sigcontext;
+typedef struct Siginfo Siginfo;
+typedef struct StackT StackT;
+typedef struct Timespec Timespec;
+typedef struct Timeval Timeval;
+typedef struct Itimerval Itimerval;
+typedef struct KeventT KeventT;
+
+#pragma pack on
+
+struct TforkT {
+	byte	*tf_tcb;
+	int32	*tf_tid;
+	byte	*tf_stack;
+};
+
+struct SigaltstackT {
+	byte	*ss_sp;
+	uint64	ss_size;
+	int32	ss_flags;
+	byte	Pad_cgo_0[4];
+};
+struct Sigcontext {
+	int64	sc_rdi;
+	int64	sc_rsi;
+	int64	sc_rdx;
+	int64	sc_rcx;
+	int64	sc_r8;
+	int64	sc_r9;
+	int64	sc_r10;
+	int64	sc_r11;
+	int64	sc_r12;
+	int64	sc_r13;
+	int64	sc_r14;
+	int64	sc_r15;
+	int64	sc_rbp;
+	int64	sc_rbx;
+	int64	sc_rax;
+	int64	sc_gs;
+	int64	sc_fs;
+	int64	sc_es;
+	int64	sc_ds;
+	int64	sc_trapno;
+	int64	sc_err;
+	int64	sc_rip;
+	int64	sc_cs;
+	int64	sc_rflags;
+	int64	sc_rsp;
+	int64	sc_ss;
+	void	*sc_fpstate;
+	int32	__sc_unused;
+	int32	sc_mask;
+};
+struct Siginfo {
+	int32	si_signo;
+	int32	si_code;
+	int32	si_errno;
+	byte	Pad_cgo_0[4];
+	byte	_data[120];
+};
+typedef	uint32	Sigset;
+typedef	byte	Sigval[8];
+
+struct StackT {
+	byte	*ss_sp;
+	uint64	ss_size;
+	int32	ss_flags;
+	byte	Pad_cgo_0[4];
+};
+
+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 KeventT {
+	uint64	ident;
+	int16	filter;
+	uint16	flags;
+	uint32	fflags;
+	int64	data;
+	byte	*udata;
+};
+
+
+#pragma pack off
diff --git a/src/runtime/defs_plan9_386.h b/src/runtime/defs_plan9_386.h
new file mode 100644
index 0000000..a762b85
--- /dev/null
+++ b/src/runtime/defs_plan9_386.h
@@ -0,0 +1,26 @@
+#define PAGESIZE 0x1000
+
+typedef struct Ureg Ureg;
+
+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 */
+	uint32	sp;
+	uint32	ss;		/* old stack segment */
+};
diff --git a/src/runtime/defs_plan9_amd64.h b/src/runtime/defs_plan9_amd64.h
new file mode 100644
index 0000000..20bca47
--- /dev/null
+++ b/src/runtime/defs_plan9_amd64.h
@@ -0,0 +1,34 @@
+#define PAGESIZE 0x1000
+
+typedef struct Ureg Ureg;
+
+struct Ureg {
+	uint64	ax;
+	uint64	bx;
+	uint64	cx;
+	uint64	dx;
+	uint64	si;
+	uint64	di;
+	uint64	bp;
+	uint64	r8;
+	uint64	r9;
+	uint64	r10;
+	uint64	r11;
+	uint64	r12;
+	uint64	r13;
+	uint64	r14;
+	uint64	r15;
+
+	uint16	ds;
+	uint16	es;
+	uint16	fs;
+	uint16	gs;
+
+	uint64	type;
+	uint64	error;				/* error code (or zero) */
+	uint64	ip;				/* pc */
+	uint64	cs;				/* old context */
+	uint64	flags;				/* old flags */
+	uint64	sp;				/* sp */
+	uint64	ss;				/* old stack segment */
+};
diff --git a/src/runtime/defs_solaris_amd64.h b/src/runtime/defs_solaris_amd64.h
new file mode 100644
index 0000000..cb1cfea
--- /dev/null
+++ b/src/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 SigaltstackT SigaltstackT;
+typedef struct Sigset Sigset;
+typedef struct StackT StackT;
+typedef struct Siginfo Siginfo;
+typedef struct SigactionT SigactionT;
+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 SigaltstackT {
+	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 SigactionT {
+	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/runtime/defs_windows.go b/src/runtime/defs_windows.go
index 7ce6797..5dfb83a 100644
--- a/src/runtime/defs_windows.go
+++ b/src/runtime/defs_windows.go
@@ -41,6 +41,7 @@ const (
 	DUPLICATE_SAME_ACCESS   = C.DUPLICATE_SAME_ACCESS
 	THREAD_PRIORITY_HIGHEST = C.THREAD_PRIORITY_HIGHEST
 
+	SIGPROF          = 0 // dummy value for badsignal
 	SIGINT           = C.SIGINT
 	CTRL_C_EVENT     = C.CTRL_C_EVENT
 	CTRL_BREAK_EVENT = C.CTRL_BREAK_EVENT
diff --git a/src/runtime/defs_windows_386.h b/src/runtime/defs_windows_386.h
new file mode 100644
index 0000000..2317c04
--- /dev/null
+++ b/src/runtime/defs_windows_386.h
@@ -0,0 +1,116 @@
+// Created by cgo -cdefs - DO NOT EDIT
+// cgo -cdefs defs_windows.go
+
+
+enum {
+	PROT_NONE	= 0,
+	PROT_READ	= 1,
+	PROT_WRITE	= 2,
+	PROT_EXEC	= 4,
+
+	MAP_ANON	= 1,
+	MAP_PRIVATE	= 2,
+
+	DUPLICATE_SAME_ACCESS	= 0x2,
+	THREAD_PRIORITY_HIGHEST	= 0x2,
+
+	SIGINT			= 0x2,
+	CTRL_C_EVENT		= 0x0,
+	CTRL_BREAK_EVENT	= 0x1,
+
+	CONTEXT_CONTROL	= 0x10001,
+	CONTEXT_FULL	= 0x10007,
+
+	EXCEPTION_ACCESS_VIOLATION	= 0xc0000005,
+	EXCEPTION_BREAKPOINT		= 0x80000003,
+	EXCEPTION_FLT_DENORMAL_OPERAND	= 0xc000008d,
+	EXCEPTION_FLT_DIVIDE_BY_ZERO	= 0xc000008e,
+	EXCEPTION_FLT_INEXACT_RESULT	= 0xc000008f,
+	EXCEPTION_FLT_OVERFLOW		= 0xc0000091,
+	EXCEPTION_FLT_UNDERFLOW		= 0xc0000093,
+	EXCEPTION_INT_DIVIDE_BY_ZERO	= 0xc0000094,
+	EXCEPTION_INT_OVERFLOW		= 0xc0000095,
+
+	INFINITE	= 0xffffffff,
+	WAIT_TIMEOUT	= 0x102,
+
+	EXCEPTION_CONTINUE_EXECUTION	= -0x1,
+	EXCEPTION_CONTINUE_SEARCH	= 0x0,
+};
+
+typedef struct SystemInfo SystemInfo;
+typedef struct ExceptionRecord ExceptionRecord;
+typedef struct FloatingSaveArea FloatingSaveArea;
+typedef struct M128a M128a;
+typedef struct Context Context;
+typedef struct Overlapped Overlapped;
+
+#pragma pack on
+
+struct SystemInfo {
+	byte	anon0[4];
+	uint32	dwPageSize;
+	byte	*lpMinimumApplicationAddress;
+	byte	*lpMaximumApplicationAddress;
+	uint32	dwActiveProcessorMask;
+	uint32	dwNumberOfProcessors;
+	uint32	dwProcessorType;
+	uint32	dwAllocationGranularity;
+	uint16	wProcessorLevel;
+	uint16	wProcessorRevision;
+};
+struct ExceptionRecord {
+	uint32	ExceptionCode;
+	uint32	ExceptionFlags;
+	ExceptionRecord	*ExceptionRecord;
+	byte	*ExceptionAddress;
+	uint32	NumberParameters;
+	uint32	ExceptionInformation[15];
+};
+struct FloatingSaveArea {
+	uint32	ControlWord;
+	uint32	StatusWord;
+	uint32	TagWord;
+	uint32	ErrorOffset;
+	uint32	ErrorSelector;
+	uint32	DataOffset;
+	uint32	DataSelector;
+	uint8	RegisterArea[80];
+	uint32	Cr0NpxState;
+};
+struct Context {
+	uint32	ContextFlags;
+	uint32	Dr0;
+	uint32	Dr1;
+	uint32	Dr2;
+	uint32	Dr3;
+	uint32	Dr6;
+	uint32	Dr7;
+	FloatingSaveArea	FloatSave;
+	uint32	SegGs;
+	uint32	SegFs;
+	uint32	SegEs;
+	uint32	SegDs;
+	uint32	Edi;
+	uint32	Esi;
+	uint32	Ebx;
+	uint32	Edx;
+	uint32	Ecx;
+	uint32	Eax;
+	uint32	Ebp;
+	uint32	Eip;
+	uint32	SegCs;
+	uint32	EFlags;
+	uint32	Esp;
+	uint32	SegSs;
+	uint8	ExtendedRegisters[512];
+};
+struct Overlapped {
+	uint32	Internal;
+	uint32	InternalHigh;
+	byte	anon0[8];
+	byte	*hEvent;
+};
+
+
+#pragma pack off
diff --git a/src/runtime/defs_windows_amd64.h b/src/runtime/defs_windows_amd64.h
new file mode 100644
index 0000000..7f37a7a
--- /dev/null
+++ b/src/runtime/defs_windows_amd64.h
@@ -0,0 +1,131 @@
+// Created by cgo -cdefs - DO NOT EDIT
+// cgo -cdefs defs_windows.go
+
+
+enum {
+	PROT_NONE	= 0,
+	PROT_READ	= 1,
+	PROT_WRITE	= 2,
+	PROT_EXEC	= 4,
+
+	MAP_ANON	= 1,
+	MAP_PRIVATE	= 2,
+
+	DUPLICATE_SAME_ACCESS	= 0x2,
+	THREAD_PRIORITY_HIGHEST	= 0x2,
+
+	SIGINT			= 0x2,
+	CTRL_C_EVENT		= 0x0,
+	CTRL_BREAK_EVENT	= 0x1,
+
+	CONTEXT_CONTROL	= 0x100001,
+	CONTEXT_FULL	= 0x10000b,
+
+	EXCEPTION_ACCESS_VIOLATION	= 0xc0000005,
+	EXCEPTION_BREAKPOINT		= 0x80000003,
+	EXCEPTION_FLT_DENORMAL_OPERAND	= 0xc000008d,
+	EXCEPTION_FLT_DIVIDE_BY_ZERO	= 0xc000008e,
+	EXCEPTION_FLT_INEXACT_RESULT	= 0xc000008f,
+	EXCEPTION_FLT_OVERFLOW		= 0xc0000091,
+	EXCEPTION_FLT_UNDERFLOW		= 0xc0000093,
+	EXCEPTION_INT_DIVIDE_BY_ZERO	= 0xc0000094,
+	EXCEPTION_INT_OVERFLOW		= 0xc0000095,
+
+	INFINITE	= 0xffffffff,
+	WAIT_TIMEOUT	= 0x102,
+
+	EXCEPTION_CONTINUE_EXECUTION	= -0x1,
+	EXCEPTION_CONTINUE_SEARCH	= 0x0,
+};
+
+typedef struct SystemInfo SystemInfo;
+typedef struct ExceptionRecord ExceptionRecord;
+typedef struct FloatingSaveArea FloatingSaveArea;
+typedef struct M128a M128a;
+typedef struct Context Context;
+typedef struct Overlapped Overlapped;
+
+#pragma pack on
+
+struct SystemInfo {
+	byte	anon0[4];
+	uint32	dwPageSize;
+	byte	*lpMinimumApplicationAddress;
+	byte	*lpMaximumApplicationAddress;
+	uint64	dwActiveProcessorMask;
+	uint32	dwNumberOfProcessors;
+	uint32	dwProcessorType;
+	uint32	dwAllocationGranularity;
+	uint16	wProcessorLevel;
+	uint16	wProcessorRevision;
+};
+struct ExceptionRecord {
+	uint32	ExceptionCode;
+	uint32	ExceptionFlags;
+	ExceptionRecord	*ExceptionRecord;
+	byte	*ExceptionAddress;
+	uint32	NumberParameters;
+	byte	Pad_cgo_0[4];
+	uint64	ExceptionInformation[15];
+};
+struct M128a {
+	uint64	Low;
+	int64	High;
+};
+struct Context {
+	uint64	P1Home;
+	uint64	P2Home;
+	uint64	P3Home;
+	uint64	P4Home;
+	uint64	P5Home;
+	uint64	P6Home;
+	uint32	ContextFlags;
+	uint32	MxCsr;
+	uint16	SegCs;
+	uint16	SegDs;
+	uint16	SegEs;
+	uint16	SegFs;
+	uint16	SegGs;
+	uint16	SegSs;
+	uint32	EFlags;
+	uint64	Dr0;
+	uint64	Dr1;
+	uint64	Dr2;
+	uint64	Dr3;
+	uint64	Dr6;
+	uint64	Dr7;
+	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;
+	byte	anon0[512];
+	M128a	VectorRegister[26];
+	uint64	VectorControl;
+	uint64	DebugControl;
+	uint64	LastBranchToRip;
+	uint64	LastBranchFromRip;
+	uint64	LastExceptionToRip;
+	uint64	LastExceptionFromRip;
+};
+struct Overlapped {
+	uint64	Internal;
+	uint64	InternalHigh;
+	byte	anon0[8];
+	byte	*hEvent;
+};
+
+
+#pragma pack off
diff --git a/src/runtime/env_plan9.go b/src/runtime/env_plan9.go
index 0e2588b..e442c34 100644
--- a/src/runtime/env_plan9.go
+++ b/src/runtime/env_plan9.go
@@ -6,6 +6,15 @@ package runtime
 
 import "unsafe"
 
+func getenv(s *byte) *byte {
+	val := gogetenv(gostringnocopy(s))
+	if val == "" {
+		return nil
+	}
+	// Strings found in environment are NUL-terminated.
+	return &bytes(val)[0]
+}
+
 var tracebackbuf [128]byte
 
 func gogetenv(key string) string {
@@ -23,14 +32,14 @@ func gogetenv(key string) string {
 	}
 	n := seek(fd, 0, 2)
 	if n <= 0 {
-		closefd(fd)
+		close(fd)
 		return ""
 	}
 
 	p := make([]byte, n)
 
 	r := pread(fd, unsafe.Pointer(&p[0]), int32(n), 0)
-	closefd(fd)
+	close(fd)
 	if r < 0 {
 		return ""
 	}
@@ -45,6 +54,3 @@ func gogetenv(key string) string {
 	sp.len = int(r)
 	return s
 }
-
-var _cgo_setenv unsafe.Pointer   // pointer to C function
-var _cgo_unsetenv unsafe.Pointer // pointer to C function
diff --git a/src/runtime/env_posix.go b/src/runtime/env_posix.go
index 5e49287..dd57872 100644
--- a/src/runtime/env_posix.go
+++ b/src/runtime/env_posix.go
@@ -8,10 +8,21 @@ package runtime
 
 import "unsafe"
 
+func environ() []string
+
+func getenv(s *byte) *byte {
+	val := gogetenv(gostringnocopy(s))
+	if val == "" {
+		return nil
+	}
+	// Strings found in environment are NUL-terminated.
+	return &bytes(val)[0]
+}
+
 func gogetenv(key string) string {
 	env := environ()
 	if env == nil {
-		throw("getenv before env init")
+		gothrow("getenv before env init")
 	}
 	for _, s := range environ() {
 		if len(s) > len(key) && s[len(key)] == '=' && s[:len(key)] == key {
@@ -21,14 +32,13 @@ func gogetenv(key string) string {
 	return ""
 }
 
-var _cgo_setenv unsafe.Pointer   // pointer to C function
-var _cgo_unsetenv unsafe.Pointer // pointer to C function
+var _cgo_setenv uintptr   // pointer to C function
+var _cgo_unsetenv uintptr // pointer to C function
 
 // Update the C environment if cgo is loaded.
 // Called from syscall.Setenv.
-//go:linkname syscall_setenv_c syscall.setenv_c
 func syscall_setenv_c(k string, v string) {
-	if _cgo_setenv == nil {
+	if _cgo_setenv == 0 {
 		return
 	}
 	arg := [2]unsafe.Pointer{cstring(k), cstring(v)}
@@ -37,9 +47,8 @@ func syscall_setenv_c(k string, v string) {
 
 // Update the C environment if cgo is loaded.
 // Called from syscall.unsetenv.
-//go:linkname syscall_unsetenv_c syscall.unsetenv_c
 func syscall_unsetenv_c(k string) {
-	if _cgo_unsetenv == nil {
+	if _cgo_unsetenv == 0 {
 		return
 	}
 	arg := [1]unsafe.Pointer{cstring(k)}
diff --git a/src/runtime/error.go b/src/runtime/error.go
index 4280306..0b40c70 100644
--- a/src/runtime/error.go
+++ b/src/runtime/error.go
@@ -11,9 +11,9 @@ type Error interface {
 	error
 
 	// RuntimeError is a no-op function but
-	// serves to distinguish types that are run time
+	// serves to distinguish types that are runtime
 	// errors from ordinary errors: a type is a
-	// run time error if it has a RuntimeError method.
+	// runtime error if it has a RuntimeError method.
 	RuntimeError()
 }
 
@@ -43,6 +43,25 @@ func (e *TypeAssertionError) Error() string {
 		": missing method " + e.missingMethod
 }
 
+// For calling from C.
+func newTypeAssertionError(ps1, ps2, ps3 *string, pmeth *string, ret *interface{}) {
+	var s1, s2, s3, meth string
+
+	if ps1 != nil {
+		s1 = *ps1
+	}
+	if ps2 != nil {
+		s2 = *ps2
+	}
+	if ps3 != nil {
+		s3 = *ps3
+	}
+	if pmeth != nil {
+		meth = *pmeth
+	}
+	*ret = &TypeAssertionError{s1, s2, s3, meth}
+}
+
 // An errorString represents a runtime error described by a single string.
 type errorString string
 
diff --git a/src/runtime/export_test.go b/src/runtime/export_test.go
index 16d5476..be35255 100644
--- a/src/runtime/export_test.go
+++ b/src/runtime/export_test.go
@@ -17,78 +17,123 @@ var F32to64 = f32to64
 var Fcmp64 = fcmp64
 var Fintto64 = fintto64
 var F64toint = f64toint
-var Sqrt = sqrt
+
+// in asm_*.s
+func stackguard() (sp, limit uintptr)
 
 var Entersyscall = entersyscall
 var Exitsyscall = exitsyscall
 var LockedOSThread = lockedOSThread
-var Xadduintptr = xadduintptr
-
-var FuncPC = funcPC
 
 type LFNode struct {
-	Next    uint64
+	Next    *LFNode
 	Pushcnt uintptr
 }
 
+func lfstackpush_m()
+func lfstackpop_m()
+
 func LFStackPush(head *uint64, node *LFNode) {
-	lfstackpush(head, (*lfnode)(unsafe.Pointer(node)))
+	mp := acquirem()
+	mp.ptrarg[0] = unsafe.Pointer(head)
+	mp.ptrarg[1] = unsafe.Pointer(node)
+	onM(lfstackpush_m)
+	releasem(mp)
 }
 
 func LFStackPop(head *uint64) *LFNode {
-	return (*LFNode)(unsafe.Pointer(lfstackpop(head)))
+	mp := acquirem()
+	mp.ptrarg[0] = unsafe.Pointer(head)
+	onM(lfstackpop_m)
+	node := (*LFNode)(unsafe.Pointer(mp.ptrarg[0]))
+	mp.ptrarg[0] = nil
+	releasem(mp)
+	return node
 }
 
 type ParFor struct {
-	body   func(*ParFor, uint32)
-	done   uint32
-	Nthr   uint32
-	thrseq uint32
-	Cnt    uint32
-	wait   bool
+	body    *byte
+	done    uint32
+	Nthr    uint32
+	nthrmax uint32
+	thrseq  uint32
+	Cnt     uint32
+	Ctx     *byte
+	wait    bool
 }
 
+func newparfor_m()
+func parforsetup_m()
+func parfordo_m()
+func parforiters_m()
+
 func NewParFor(nthrmax uint32) *ParFor {
-	var desc *ParFor
-	systemstack(func() {
-		desc = (*ParFor)(unsafe.Pointer(parforalloc(nthrmax)))
-	})
+	mp := acquirem()
+	mp.scalararg[0] = uintptr(nthrmax)
+	onM(newparfor_m)
+	desc := (*ParFor)(mp.ptrarg[0])
+	mp.ptrarg[0] = nil
+	releasem(mp)
 	return desc
 }
 
-func ParForSetup(desc *ParFor, nthr, n uint32, wait bool, body func(*ParFor, uint32)) {
-	systemstack(func() {
-		parforsetup((*parfor)(unsafe.Pointer(desc)), nthr, n, wait,
-			*(*func(*parfor, uint32))(unsafe.Pointer(&body)))
-	})
+func ParForSetup(desc *ParFor, nthr, n uint32, ctx *byte, wait bool, body func(*ParFor, uint32)) {
+	mp := acquirem()
+	mp.ptrarg[0] = unsafe.Pointer(desc)
+	mp.ptrarg[1] = unsafe.Pointer(ctx)
+	mp.ptrarg[2] = unsafe.Pointer(funcPC(body)) // TODO(rsc): Should be a scalar.
+	mp.scalararg[0] = uintptr(nthr)
+	mp.scalararg[1] = uintptr(n)
+	mp.scalararg[2] = 0
+	if wait {
+		mp.scalararg[2] = 1
+	}
+	onM(parforsetup_m)
+	releasem(mp)
 }
 
 func ParForDo(desc *ParFor) {
-	systemstack(func() {
-		parfordo((*parfor)(unsafe.Pointer(desc)))
-	})
+	mp := acquirem()
+	mp.ptrarg[0] = unsafe.Pointer(desc)
+	onM(parfordo_m)
+	releasem(mp)
 }
 
 func ParForIters(desc *ParFor, tid uint32) (uint32, uint32) {
-	desc1 := (*parfor)(unsafe.Pointer(desc))
-	pos := desc1.thr[tid].pos
-	return uint32(pos), uint32(pos >> 32)
+	mp := acquirem()
+	mp.ptrarg[0] = unsafe.Pointer(desc)
+	mp.scalararg[0] = uintptr(tid)
+	onM(parforiters_m)
+	begin := uint32(mp.scalararg[0])
+	end := uint32(mp.scalararg[1])
+	releasem(mp)
+	return begin, end
 }
 
+// in mgc0.c
+//go:noescape
+func getgcmask(data unsafe.Pointer, typ *_type, array **byte, len *uint)
+
 func GCMask(x interface{}) (ret []byte) {
-	systemstack(func() {
-		ret = getgcmask(x)
+	e := (*eface)(unsafe.Pointer(&x))
+	s := (*slice)(unsafe.Pointer(&ret))
+	onM(func() {
+		getgcmask(e.data, e._type, &s.array, &s.len)
+		s.cap = s.len
 	})
 	return
 }
 
+func testSchedLocalQueue()
+func testSchedLocalQueueSteal()
 func RunSchedLocalQueueTest() {
-	testSchedLocalQueue()
+	onM(testSchedLocalQueue)
 }
 func RunSchedLocalQueueStealTest() {
-	testSchedLocalQueueSteal()
+	onM(testSchedLocalQueueSteal)
 }
 
+var HaveGoodHash = haveGoodHash
 var StringHash = stringHash
 var BytesHash = bytesHash
 var Int32Hash = int32Hash
@@ -99,9 +144,18 @@ var MemclrBytes = memclrBytes
 
 var HashLoad = &hashLoad
 
+// For testing.
+func GogoBytes() int32 {
+	return _RuntimeGogoBytes
+}
+
+// in string.c
+//go:noescape
+func gostringw(w *uint16) string
+
 // entry point for testing
 func GostringW(w []uint16) (s string) {
-	systemstack(func() {
+	onM(func() {
 		s = gostringw(&w[0])
 	})
 	return
@@ -109,48 +163,3 @@ func GostringW(w []uint16) (s string) {
 
 var Gostringnocopy = gostringnocopy
 var Maxstring = &maxstring
-
-type Uintreg uintreg
-
-var Open = open
-var Close = closefd
-var Read = read
-var Write = write
-
-func Envs() []string     { return envs }
-func SetEnvs(e []string) { envs = e }
-
-var BigEndian = _BigEndian
-
-// For benchmarking.
-
-func BenchSetType(n int, x interface{}) {
-	e := *(*eface)(unsafe.Pointer(&x))
-	t := e._type
-	var size uintptr
-	var p unsafe.Pointer
-	switch t.kind & kindMask {
-	case _KindPtr:
-		t = (*ptrtype)(unsafe.Pointer(t)).elem
-		size = t.size
-		p = e.data
-	case _KindSlice:
-		slice := *(*struct {
-			ptr      unsafe.Pointer
-			len, cap uintptr
-		})(e.data)
-		t = (*slicetype)(unsafe.Pointer(t)).elem
-		size = t.size * slice.len
-		p = slice.ptr
-	}
-	allocSize := roundupsize(size)
-	systemstack(func() {
-		for i := 0; i < n; i++ {
-			heapBitsSetType(uintptr(p), allocSize, size, t)
-		}
-	})
-}
-
-const PtrSize = ptrSize
-
-var TestingAssertE2I2GC = &testingAssertE2I2GC
diff --git a/src/runtime/extern.go b/src/runtime/extern.go
index d346362..6cc5df8 100644
--- a/src/runtime/extern.go
+++ b/src/runtime/extern.go
@@ -19,10 +19,10 @@ A collection is triggered when the ratio of freshly allocated data to live data
 remaining after the previous collection reaches this percentage. The default
 is GOGC=100. Setting GOGC=off disables the garbage collector entirely.
 The runtime/debug package's SetGCPercent function allows changing this
-percentage at run time. See https://golang.org/pkg/runtime/debug/#SetGCPercent.
+percentage at run time. See http://golang.org/pkg/runtime/debug/#SetGCPercent.
 
-The GODEBUG variable controls debugging variables within the runtime.
-It is a comma-separated list of name=val pairs setting these named variables:
+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.
@@ -31,50 +31,13 @@ It is a comma-separated list of name=val pairs setting these named variables:
 	where each object is allocated on a unique page and addresses are
 	never recycled.
 
-	gccheckmark: setting gccheckmark=1 enables verification of the
-	garbage collector's concurrent mark phase by performing a
-	second mark pass while the world is stopped.  If the second
-	pass finds a reachable object that was not found by concurrent
-	mark, the garbage collector will panic.
-
-	gcpacertrace: setting gcpacertrace=1 causes the garbage collector to
-	print information about the internal state of the concurrent pacer.
-
-	gcshrinkstackoff: setting gcshrinkstackoff=1 disables moving goroutines
-	onto smaller stacks. In this mode, a goroutine's stack can only grow.
-
-	gcstackbarrieroff: setting gcstackbarrieroff=1 disables the use of stack barriers
-	that allow the garbage collector to avoid repeating a stack scan during the
-	mark termination phase.
-
-	gcstoptheworld: setting gcstoptheworld=1 disables concurrent garbage collection,
-	making every garbage collection a stop-the-world event. Setting gcstoptheworld=2
-	also disables concurrent sweeping after the garbage collection finishes.
-
 	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. The format of this line is subject to change.
-	Currently, it is:
-		gc # @#s #%: #+...+# ms clock, #+...+# ms cpu, #->#-># MB, # MB goal, # P
-	where the fields are as follows:
-		gc #        the GC number, incremented at each GC
-		@#s         time in seconds since program start
-		#%          percentage of time spent in GC since program start
-		#+...+#     wall-clock/CPU times for the phases of the GC
-		#->#-># MB  heap size at GC start, at GC end, and live heap
-		# MB goal   goal heap size
-		# P         number of processors used
-	The phases are stop-the-world (STW) sweep termination, scan,
-	synchronize Ps, mark, and STW mark termination. The CPU times
-	for mark are broken down in to assist time (GC performed in
-	line with allocation), background GC time, and idle GC time.
-	If the line ends with "(forced)", this GC was forced by a
-	runtime.GC() call and all phases are STW.
-
-	memprofilerate: setting memprofilerate=X will update the value of runtime.MemProfileRate.
-	When set to 0 memory profiling is disabled.  Refer to the description of
-	MemProfileRate for the default value.
+	repeats each collection.
+
+	gcdead: setting gcdead=1 causes the garbage collector to clobber all stack slots
+	that it thinks are dead.
 
 	invalidptr: defaults to invalidptr=1, causing the garbage collector and stack
 	copier to crash the program if an invalid pointer value (for example, 1)
@@ -82,12 +45,6 @@ It is a comma-separated list of name=val pairs setting these named variables:
 	This should only be used as a temporary workaround to diagnose buggy code.
 	The real fix is to not store integers in pointer-typed locations.
 
-	sbrk: setting sbrk=1 replaces the memory allocator and garbage collector
-	with a trivial allocator that obtains memory from the operating system and
-	never reclaims any memory.
-
-	scavenge: scavenge=1 enables debugging mode of heap scavenger.
-
 	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.
@@ -95,6 +52,8 @@ It is a comma-separated list of name=val pairs setting these named variables:
 	schedtrace: setting schedtrace=X causes the scheduler to emit a single line to standard
 	error every X milliseconds, summarizing the scheduler state.
 
+	scavenge: scavenge=1 enables debugging mode of heap scavenger.
+
 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
@@ -115,7 +74,7 @@ core dump.
 
 The GOARCH, GOOS, GOPATH, and GOROOT environment variables complete
 the set of Go environment variables. They influence the building of Go programs
-(see https://golang.org/cmd/go and https://golang.org/pkg/go/build).
+(see http://golang.org/cmd/go and http://golang.org/pkg/go/build).
 GOARCH, GOOS, and GOROOT are recorded at compile time and made available by
 constants or functions in this package, but they do not influence the execution
 of the run-time system.
@@ -133,7 +92,7 @@ func Caller(skip int) (pc uintptr, file string, line int, ok bool) {
 	// and what it called, so that we can see if it
 	// "called" sigpanic.
 	var rpc [2]uintptr
-	if callers(1+skip-1, rpc[:]) < 2 {
+	if callers(1+skip-1, &rpc[0], 2) < 2 {
 		return
 	}
 	f := findfunc(rpc[1])
@@ -153,8 +112,7 @@ func Caller(skip int) (pc uintptr, file string, line int, ok bool) {
 	if xpc > f.entry && (g == nil || g.entry != funcPC(sigpanic)) {
 		xpc--
 	}
-	file, line32 := funcline(f, xpc)
-	line = int(line32)
+	line = int(funcline(f, xpc, &file))
 	ok = true
 	return
 }
@@ -180,7 +138,7 @@ func Callers(skip int, pc []uintptr) int {
 	if len(pc) == 0 {
 		return 0
 	}
-	return callers(skip, pc)
+	return callers(skip, &pc[0], len(pc))
 }
 
 // GOROOT returns the root of the Go tree.
diff --git a/src/runtime/float.c b/src/runtime/float.c
new file mode 100644
index 0000000..42082e4
--- /dev/null
+++ b/src/runtime/float.c
@@ -0,0 +1,10 @@
+// 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"
+
+// used as float64 via runtime· names
+uint64	·nan		= 0x7FF8000000000001ULL;
+uint64	·posinf	= 0x7FF0000000000000ULL;
+uint64	·neginf	= 0xFFF0000000000000ULL;
diff --git a/src/runtime/funcdata.h b/src/runtime/funcdata.h
index ce62dab..d6c14fc 100644
--- a/src/runtime/funcdata.h
+++ b/src/runtime/funcdata.h
@@ -3,10 +3,9 @@
 // license that can be found in the LICENSE file.
 
 // This file defines the IDs for PCDATA and FUNCDATA instructions
-// in Go binaries. It is included by assembly sources, so it must
-// be written using #defines.
-//
-// The Go compiler also #includes this file, for now.
+// in Go binaries. It is included by both C and assembly, so it must
+// be written using #defines. It is included by the runtime package
+// as well as the compilers.
 //
 // symtab.go also contains a copy of these constants.
 
@@ -51,7 +50,8 @@
 
 /*c2go
 enum {
-	PCDATA_StackMapIndex = 0,
+	PCDATA_ArgSize = 0,
+	PCDATA_StackMapIndex = 1,
 	FUNCDATA_ArgsPointerMaps = 0,
 	FUNCDATA_LocalsPointerMaps = 1,
 	FUNCDATA_DeadValueMaps = 2,
diff --git a/src/runtime/futex_test.go b/src/runtime/futex_test.go
index b85249a..f57fc52 100644
--- a/src/runtime/futex_test.go
+++ b/src/runtime/futex_test.go
@@ -44,9 +44,9 @@ func TestFutexsleep(t *testing.T) {
 	start := time.Now()
 	for _, tt := range futexsleepTests {
 		go func(tt futexsleepTest) {
-			runtime.Entersyscall(0)
+			runtime.Entersyscall()
 			runtime.Futexsleep(&tt.mtx, tt.mtx, tt.ns)
-			runtime.Exitsyscall(0)
+			runtime.Exitsyscall()
 			tt.ch <- tt
 		}(tt)
 	}
diff --git a/src/runtime/gc_test.go b/src/runtime/gc_test.go
index 636e524..6abec4c 100644
--- a/src/runtime/gc_test.go
+++ b/src/runtime/gc_test.go
@@ -5,9 +5,7 @@
 package runtime_test
 
 import (
-	"io"
 	"os"
-	"reflect"
 	"runtime"
 	"runtime/debug"
 	"testing"
@@ -199,166 +197,45 @@ func TestHugeGCInfo(t *testing.T) {
 	}
 }
 
-func BenchmarkSetTypePtr(b *testing.B) {
-	benchSetType(b, new(*byte))
-}
-
-func BenchmarkSetTypePtr8(b *testing.B) {
-	benchSetType(b, new([8]*byte))
-}
-
-func BenchmarkSetTypePtr16(b *testing.B) {
-	benchSetType(b, new([16]*byte))
-}
-
-func BenchmarkSetTypePtr32(b *testing.B) {
-	benchSetType(b, new([32]*byte))
-}
-
-func BenchmarkSetTypePtr64(b *testing.B) {
-	benchSetType(b, new([64]*byte))
-}
-
-func BenchmarkSetTypePtr126(b *testing.B) {
-	benchSetType(b, new([126]*byte))
-}
-
-func BenchmarkSetTypePtr128(b *testing.B) {
-	benchSetType(b, new([128]*byte))
-}
-
-func BenchmarkSetTypePtrSlice(b *testing.B) {
-	benchSetType(b, make([]*byte, 1<<10))
-}
-
-type Node1 struct {
-	Value       [1]uintptr
-	Left, Right *byte
-}
-
-func BenchmarkSetTypeNode1(b *testing.B) {
-	benchSetType(b, new(Node1))
-}
-
-func BenchmarkSetTypeNode1Slice(b *testing.B) {
-	benchSetType(b, make([]Node1, 32))
-}
-
-type Node8 struct {
-	Value       [8]uintptr
-	Left, Right *byte
-}
-
-func BenchmarkSetTypeNode8(b *testing.B) {
-	benchSetType(b, new(Node8))
-}
-
-func BenchmarkSetTypeNode8Slice(b *testing.B) {
-	benchSetType(b, make([]Node8, 32))
-}
-
-type Node64 struct {
-	Value       [64]uintptr
-	Left, Right *byte
-}
-
-func BenchmarkSetTypeNode64(b *testing.B) {
-	benchSetType(b, new(Node64))
-}
-
-func BenchmarkSetTypeNode64Slice(b *testing.B) {
-	benchSetType(b, make([]Node64, 32))
-}
-
-type Node64Dead struct {
-	Left, Right *byte
-	Value       [64]uintptr
-}
-
-func BenchmarkSetTypeNode64Dead(b *testing.B) {
-	benchSetType(b, new(Node64Dead))
-}
-
-func BenchmarkSetTypeNode64DeadSlice(b *testing.B) {
-	benchSetType(b, make([]Node64Dead, 32))
-}
-
-type Node124 struct {
-	Value       [124]uintptr
-	Left, Right *byte
-}
-
-func BenchmarkSetTypeNode124(b *testing.B) {
-	benchSetType(b, new(Node124))
-}
-
-func BenchmarkSetTypeNode124Slice(b *testing.B) {
-	benchSetType(b, make([]Node124, 32))
-}
-
-type Node126 struct {
-	Value       [126]uintptr
-	Left, Right *byte
-}
-
-func BenchmarkSetTypeNode126(b *testing.B) {
-	benchSetType(b, new(Node126))
-}
-
-func BenchmarkSetTypeNode126Slice(b *testing.B) {
-	benchSetType(b, make([]Node126, 32))
-}
-
-type Node128 struct {
-	Value       [128]uintptr
-	Left, Right *byte
-}
-
-func BenchmarkSetTypeNode128(b *testing.B) {
-	benchSetType(b, new(Node128))
-}
-
-func BenchmarkSetTypeNode128Slice(b *testing.B) {
-	benchSetType(b, make([]Node128, 32))
-}
-
-type Node130 struct {
-	Value       [130]uintptr
-	Left, Right *byte
-}
-
-func BenchmarkSetTypeNode130(b *testing.B) {
-	benchSetType(b, new(Node130))
-}
-
-func BenchmarkSetTypeNode130Slice(b *testing.B) {
-	benchSetType(b, make([]Node130, 32))
-}
-
-type Node1024 struct {
-	Value       [1024]uintptr
-	Left, Right *byte
+func BenchmarkSetTypeNoPtr1(b *testing.B) {
+	type NoPtr1 struct {
+		p uintptr
+	}
+	var p *NoPtr1
+	for i := 0; i < b.N; i++ {
+		p = &NoPtr1{}
+	}
+	_ = p
 }
-
-func BenchmarkSetTypeNode1024(b *testing.B) {
-	benchSetType(b, new(Node1024))
+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 BenchmarkSetTypeNode1024Slice(b *testing.B) {
-	benchSetType(b, make([]Node1024, 32))
+func BenchmarkSetTypePtr1(b *testing.B) {
+	type Ptr1 struct {
+		p *byte
+	}
+	var p *Ptr1
+	for i := 0; i < b.N; i++ {
+		p = &Ptr1{}
+	}
+	_ = p
 }
-
-func benchSetType(b *testing.B, x interface{}) {
-	v := reflect.ValueOf(x)
-	t := v.Type()
-	switch t.Kind() {
-	case reflect.Ptr:
-		b.SetBytes(int64(t.Elem().Size()))
-	case reflect.Slice:
-		b.SetBytes(int64(t.Elem().Size()) * int64(v.Len()))
-	}
-	b.ResetTimer()
-	runtime.BenchSetType(b.N, x)
+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) {
@@ -413,59 +290,3 @@ func TestPrintGC(t *testing.T) {
 	}
 	close(done)
 }
-
-// The implicit y, ok := x.(error) for the case error
-// in testTypeSwitch used to not initialize the result y
-// before passing &y to assertE2I2GC.
-// Catch this by making assertE2I2 call runtime.GC,
-// which will force a stack scan and failure if there are
-// bad pointers, and then fill the stack with bad pointers
-// and run the type switch.
-func TestAssertE2I2Liveness(t *testing.T) {
-	// Note that this flag is defined in export_test.go
-	// and is not available to ordinary imports of runtime.
-	*runtime.TestingAssertE2I2GC = true
-	defer func() {
-		*runtime.TestingAssertE2I2GC = false
-	}()
-
-	poisonStack()
-	testTypeSwitch(io.EOF)
-	poisonStack()
-	testAssert(io.EOF)
-	poisonStack()
-	testAssertVar(io.EOF)
-}
-
-func poisonStack() uintptr {
-	var x [1000]uintptr
-	for i := range x {
-		x[i] = 0xff
-	}
-	return x[123]
-}
-
-func testTypeSwitch(x interface{}) error {
-	switch y := x.(type) {
-	case nil:
-		// ok
-	case error:
-		return y
-	}
-	return nil
-}
-
-func testAssert(x interface{}) error {
-	if y, ok := x.(error); ok {
-		return y
-	}
-	return nil
-}
-
-func testAssertVar(x interface{}) error {
-	var y, ok = x.(error)
-	if ok {
-		return y
-	}
-	return nil
-}
diff --git a/src/runtime/gcinfo_test.go b/src/runtime/gcinfo_test.go
index f330bf2..88f6703 100644
--- a/src/runtime/gcinfo_test.go
+++ b/src/runtime/gcinfo_test.go
@@ -10,32 +10,24 @@ import (
 	"testing"
 )
 
-const (
-	typeScalar  = 0
-	typePointer = 1
-)
-
 // TestGCInfo tests that various objects in heap, data and bss receive correct GC pointer type info.
 func TestGCInfo(t *testing.T) {
-	verifyGCInfo(t, "bss Ptr", &bssPtr, infoPtr)
-	verifyGCInfo(t, "bss ScalarPtr", &bssScalarPtr, infoScalarPtr)
-	verifyGCInfo(t, "bss PtrScalar", &bssPtrScalar, infoPtrScalar)
-	verifyGCInfo(t, "bss BigStruct", &bssBigStruct, infoBigStruct())
-	verifyGCInfo(t, "bss string", &bssString, infoString)
-	verifyGCInfo(t, "bss slice", &bssSlice, infoSlice)
-	verifyGCInfo(t, "bss eface", &bssEface, infoEface)
-	verifyGCInfo(t, "bss iface", &bssIface, infoIface)
-
-	verifyGCInfo(t, "data Ptr", &dataPtr, infoPtr)
-	verifyGCInfo(t, "data ScalarPtr", &dataScalarPtr, infoScalarPtr)
-	verifyGCInfo(t, "data PtrScalar", &dataPtrScalar, infoPtrScalar)
-	verifyGCInfo(t, "data BigStruct", &dataBigStruct, infoBigStruct())
-	verifyGCInfo(t, "data string", &dataString, infoString)
-	verifyGCInfo(t, "data slice", &dataSlice, infoSlice)
-	verifyGCInfo(t, "data eface", &dataEface, infoEface)
-	verifyGCInfo(t, "data iface", &dataIface, infoIface)
-
-	verifyGCInfo(t, "stack Ptr", new(Ptr), infoPtr)
+	verifyGCInfo(t, "bss ScalarPtr", &bssScalarPtr, nonStackInfo(infoScalarPtr))
+	verifyGCInfo(t, "bss PtrScalar", &bssPtrScalar, nonStackInfo(infoPtrScalar))
+	verifyGCInfo(t, "bss BigStruct", &bssBigStruct, nonStackInfo(infoBigStruct()))
+	verifyGCInfo(t, "bss string", &bssString, nonStackInfo(infoString))
+	verifyGCInfo(t, "bss slice", &bssSlice, nonStackInfo(infoSlice))
+	verifyGCInfo(t, "bss eface", &bssEface, nonStackInfo(infoEface))
+	verifyGCInfo(t, "bss iface", &bssIface, nonStackInfo(infoIface))
+
+	verifyGCInfo(t, "data ScalarPtr", &dataScalarPtr, nonStackInfo(infoScalarPtr))
+	verifyGCInfo(t, "data PtrScalar", &dataPtrScalar, nonStackInfo(infoPtrScalar))
+	verifyGCInfo(t, "data BigStruct", &dataBigStruct, nonStackInfo(infoBigStruct()))
+	verifyGCInfo(t, "data string", &dataString, nonStackInfo(infoString))
+	verifyGCInfo(t, "data slice", &dataSlice, nonStackInfo(infoSlice))
+	verifyGCInfo(t, "data eface", &dataEface, nonStackInfo(infoEface))
+	verifyGCInfo(t, "data iface", &dataIface, nonStackInfo(infoIface))
+
 	verifyGCInfo(t, "stack ScalarPtr", new(ScalarPtr), infoScalarPtr)
 	verifyGCInfo(t, "stack PtrScalar", new(PtrScalar), infoPtrScalar)
 	verifyGCInfo(t, "stack BigStruct", new(BigStruct), infoBigStruct())
@@ -45,43 +37,40 @@ func TestGCInfo(t *testing.T) {
 	verifyGCInfo(t, "stack iface", new(Iface), infoIface)
 
 	for i := 0; i < 10; i++ {
-		verifyGCInfo(t, "heap Ptr", escape(new(Ptr)), trimDead(padDead(infoPtr)))
-		verifyGCInfo(t, "heap PtrSlice", escape(&make([]*byte, 10)[0]), trimDead(infoPtr10))
-		verifyGCInfo(t, "heap ScalarPtr", escape(new(ScalarPtr)), trimDead(infoScalarPtr))
-		verifyGCInfo(t, "heap ScalarPtrSlice", escape(&make([]ScalarPtr, 4)[0]), trimDead(infoScalarPtr4))
-		verifyGCInfo(t, "heap PtrScalar", escape(new(PtrScalar)), trimDead(infoPtrScalar))
-		verifyGCInfo(t, "heap BigStruct", escape(new(BigStruct)), trimDead(infoBigStruct()))
-		verifyGCInfo(t, "heap string", escape(new(string)), trimDead(infoString))
-		verifyGCInfo(t, "heap eface", escape(new(interface{})), trimDead(infoEface))
-		verifyGCInfo(t, "heap iface", escape(new(Iface)), trimDead(infoIface))
+		verifyGCInfo(t, "heap ScalarPtr", escape(new(ScalarPtr)), nonStackInfo(infoScalarPtr))
+		verifyGCInfo(t, "heap PtrScalar", escape(new(PtrScalar)), nonStackInfo(infoPtrScalar))
+		verifyGCInfo(t, "heap BigStruct", escape(new(BigStruct)), nonStackInfo(infoBigStruct()))
+		verifyGCInfo(t, "heap string", escape(new(string)), nonStackInfo(infoString))
+		verifyGCInfo(t, "heap eface", escape(new(interface{})), nonStackInfo(infoEface))
+		verifyGCInfo(t, "heap iface", escape(new(Iface)), nonStackInfo(infoIface))
 	}
+
 }
 
 func verifyGCInfo(t *testing.T, name string, p interface{}, mask0 []byte) {
 	mask := runtime.GCMask(p)
+	if len(mask) > len(mask0) {
+		mask0 = append(mask0, BitsDead)
+		mask = mask[:len(mask0)]
+	}
 	if bytes.Compare(mask, mask0) != 0 {
 		t.Errorf("bad GC program for %v:\nwant %+v\ngot  %+v", name, mask0, mask)
 		return
 	}
 }
 
-func padDead(mask []byte) []byte {
-	// Because the dead bit isn't encoded until the third word,
-	// and because on 32-bit systems a one-word allocation
-	// uses a two-word block, the pointer info for a one-word
-	// object needs to be expanded to include an extra scalar
-	// on 32-bit systems to match the heap bitmap.
-	if runtime.PtrSize == 4 && len(mask) == 1 {
-		return []byte{mask[0], 0}
-	}
-	return mask
-}
-
-func trimDead(mask []byte) []byte {
-	for len(mask) > 2 && mask[len(mask)-1] == typeScalar {
-		mask = mask[:len(mask)-1]
+func nonStackInfo(mask []byte) []byte {
+	// BitsDead is replaced with BitsScalar everywhere except stacks.
+	mask1 := make([]byte, len(mask))
+	mw := false
+	for i, v := range mask {
+		if !mw && v == BitsDead {
+			v = BitsScalar
+		}
+		mw = !mw && v == BitsMultiWord
+		mask1[i] = v
 	}
-	return mask
+	return mask1
 }
 
 var gcinfoSink interface{}
@@ -91,13 +80,19 @@ func escape(p interface{}) interface{} {
 	return p
 }
 
-var infoPtr = []byte{typePointer}
-
-type Ptr struct {
-	*byte
-}
+const (
+	BitsDead = iota
+	BitsScalar
+	BitsPointer
+	BitsMultiWord
+)
 
-var infoPtr10 = []byte{typePointer, typePointer, typePointer, typePointer, typePointer, typePointer, typePointer, typePointer, typePointer, typePointer}
+const (
+	BitsString = iota // unused
+	BitsSlice         // unused
+	BitsIface
+	BitsEface
+)
 
 type ScalarPtr struct {
 	q int
@@ -108,9 +103,7 @@ type ScalarPtr struct {
 	y *int
 }
 
-var infoScalarPtr = []byte{typeScalar, typePointer, typeScalar, typePointer, typeScalar, typePointer}
-
-var infoScalarPtr4 = append(append(append(append([]byte(nil), infoScalarPtr...), infoScalarPtr...), infoScalarPtr...), infoScalarPtr...)
+var infoScalarPtr = []byte{BitsScalar, BitsPointer, BitsScalar, BitsPointer, BitsScalar, BitsPointer}
 
 type PtrScalar struct {
 	q *int
@@ -121,7 +114,7 @@ type PtrScalar struct {
 	y int
 }
 
-var infoPtrScalar = []byte{typePointer, typeScalar, typePointer, typeScalar, typePointer, typeScalar}
+var infoPtrScalar = []byte{BitsPointer, BitsScalar, BitsPointer, BitsScalar, BitsPointer, BitsScalar}
 
 type BigStruct struct {
 	q *int
@@ -138,27 +131,27 @@ func infoBigStruct() []byte {
 	switch runtime.GOARCH {
 	case "386", "arm":
 		return []byte{
-			typePointer,                                                // q *int
-			typeScalar, typeScalar, typeScalar, typeScalar, typeScalar, // w byte; e [17]byte
-			typePointer, typeScalar, typeScalar, // r []byte
-			typeScalar, typeScalar, typeScalar, typeScalar, // t int; y uint16; u uint64
-			typePointer, typeScalar, // i string
+			BitsPointer,                                                // q *int
+			BitsScalar, BitsScalar, BitsScalar, BitsScalar, BitsScalar, // w byte; e [17]byte
+			BitsPointer, BitsDead, BitsDead, // r []byte
+			BitsScalar, BitsScalar, BitsScalar, BitsScalar, // t int; y uint16; u uint64
+			BitsPointer, BitsDead, // i string
 		}
-	case "arm64", "amd64", "ppc64", "ppc64le":
+	case "amd64":
 		return []byte{
-			typePointer,                        // q *int
-			typeScalar, typeScalar, typeScalar, // w byte; e [17]byte
-			typePointer, typeScalar, typeScalar, // r []byte
-			typeScalar, typeScalar, typeScalar, // t int; y uint16; u uint64
-			typePointer, typeScalar, // i string
+			BitsPointer,                        // q *int
+			BitsScalar, BitsScalar, BitsScalar, // w byte; e [17]byte
+			BitsPointer, BitsDead, BitsDead, // r []byte
+			BitsScalar, BitsScalar, BitsScalar, // t int; y uint16; u uint64
+			BitsPointer, BitsDead, // i string
 		}
 	case "amd64p32":
 		return []byte{
-			typePointer,                                                // q *int
-			typeScalar, typeScalar, typeScalar, typeScalar, typeScalar, // w byte; e [17]byte
-			typePointer, typeScalar, typeScalar, // r []byte
-			typeScalar, typeScalar, typeScalar, typeScalar, typeScalar, // t int; y uint16; u uint64
-			typePointer, typeScalar, // i string
+			BitsPointer,                                                // q *int
+			BitsScalar, BitsScalar, BitsScalar, BitsScalar, BitsScalar, // w byte; e [17]byte
+			BitsPointer, BitsDead, BitsDead, // r []byte
+			BitsScalar, BitsScalar, BitsDead, BitsScalar, BitsScalar, // t int; y uint16; u uint64
+			BitsPointer, BitsDead, // i string
 		}
 	default:
 		panic("unknown arch")
@@ -176,7 +169,6 @@ func (IfaceImpl) f() {
 
 var (
 	// BSS
-	bssPtr       Ptr
 	bssScalarPtr ScalarPtr
 	bssPtrScalar PtrScalar
 	bssBigStruct BigStruct
@@ -186,7 +178,6 @@ var (
 	bssIface     Iface
 
 	// DATA
-	dataPtr                   = Ptr{new(byte)}
 	dataScalarPtr             = ScalarPtr{q: 1}
 	dataPtrScalar             = PtrScalar{w: 1}
 	dataBigStruct             = BigStruct{w: 1}
@@ -195,8 +186,8 @@ var (
 	dataEface     interface{} = 42
 	dataIface     Iface       = IfaceImpl(42)
 
-	infoString = []byte{typePointer, typeScalar}
-	infoSlice  = []byte{typePointer, typeScalar, typeScalar}
-	infoEface  = []byte{typePointer, typePointer}
-	infoIface  = []byte{typePointer, typePointer}
+	infoString = []byte{BitsPointer, BitsDead}
+	infoSlice  = []byte{BitsPointer, BitsDead, BitsDead}
+	infoEface  = []byte{BitsMultiWord, BitsEface}
+	infoIface  = []byte{BitsMultiWord, BitsIface}
 )
diff --git a/src/runtime/hash_test.go b/src/runtime/hash_test.go
index 6b229bd..41fff98 100644
--- a/src/runtime/hash_test.go
+++ b/src/runtime/hash_test.go
@@ -171,6 +171,9 @@ func TestSmhasherCyclic(t *testing.T) {
 	if testing.Short() {
 		t.Skip("Skipping in short mode")
 	}
+	if !HaveGoodHash() {
+		t.Skip("fallback hash not good enough for this test")
+	}
 	r := rand.New(rand.NewSource(1234))
 	const REPEAT = 8
 	const N = 1000000
@@ -232,6 +235,9 @@ func TestSmhasherPermutation(t *testing.T) {
 	if testing.Short() {
 		t.Skip("Skipping in short mode")
 	}
+	if !HaveGoodHash() {
+		t.Skip("fallback hash not good enough for this test")
+	}
 	permutation(t, []uint32{0, 1, 2, 3, 4, 5, 6, 7}, 8)
 	permutation(t, []uint32{0, 1 << 29, 2 << 29, 3 << 29, 4 << 29, 5 << 29, 6 << 29, 7 << 29}, 8)
 	permutation(t, []uint32{0, 1}, 20)
@@ -398,6 +404,9 @@ func (k *IfaceKey) name() string {
 
 // Flipping a single bit of a key should flip each output bit with 50% probability.
 func TestSmhasherAvalanche(t *testing.T) {
+	if !HaveGoodHash() {
+		t.Skip("fallback hash not good enough for this test")
+	}
 	if testing.Short() {
 		t.Skip("Skipping in short mode")
 	}
diff --git a/src/runtime/hashmap.go b/src/runtime/hashmap.go
index 917ed21..791af8c 100644
--- a/src/runtime/hashmap.go
+++ b/src/runtime/hashmap.go
@@ -68,7 +68,7 @@ const (
 	// 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/internal/gc/walk.go must be at most this value.
+	// fast versions in ../../cmd/gc/walk.c must be at most this value.
 	maxKeySize   = 128
 	maxValueSize = 128
 
@@ -96,31 +96,23 @@ const (
 
 	// sentinel bucket ID for iterator checks
 	noCheck = 1<<(8*ptrSize) - 1
+
+	// trigger a garbage collection at every alloc called from this code
+	checkgc = false
 )
 
 // A header for a Go map.
 type hmap struct {
-	// Note: the format of the Hmap is encoded in ../../cmd/internal/gc/reflect.go and
+	// 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!
 	count int // # live cells == size of map.  Must be first (used by len() builtin)
-	flags uint8
-	B     uint8  // log_2 of # of buckets (can hold up to loadFactor * 2^B items)
+	flags uint32
 	hash0 uint32 // hash seed
+	B     uint8  // log_2 of # of buckets (can hold up to loadFactor * 2^B items)
 
 	buckets    unsafe.Pointer // array of 2^B Buckets. may be nil if count==0.
 	oldbuckets unsafe.Pointer // previous bucket array of half the size, non-nil only when growing
 	nevacuate  uintptr        // progress counter for evacuation (buckets less than this have been evacuated)
-
-	// If both key and value do not contain pointers and are inline, then we mark bucket
-	// type as containing no pointers. This avoids scanning such maps.
-	// However, bmap.overflow is a pointer. In order to keep overflow buckets
-	// alive, we store pointers to all overflow buckets in hmap.overflow.
-	// Overflow is used only if key and value do not contain pointers.
-	// overflow[0] contains overflow buckets for hmap.buckets.
-	// overflow[1] contains overflow buckets for hmap.oldbuckets.
-	// The first indirection allows us to reduce static size of hmap.
-	// The second indirection allows to store a pointer to the slice in hiter.
-	overflow *[2]*[]*bmap
 }
 
 // A bucket for a Go map.
@@ -134,16 +126,15 @@ type bmap struct {
 }
 
 // A hash iteration structure.
-// If you modify hiter, also change cmd/internal/gc/reflect.go to indicate
+// If you modify hiter, also change cmd/gc/reflect.c to indicate
 // the layout of this structure.
 type hiter struct {
-	key         unsafe.Pointer // Must be in first position.  Write nil to indicate iteration end (see cmd/internal/gc/range.go).
-	value       unsafe.Pointer // Must be in second position (see cmd/internal/gc/range.go).
+	key         unsafe.Pointer // Must be in first position.  Write nil to indicate iteration end (see cmd/gc/range.c).
+	value       unsafe.Pointer // Must be in second position (see cmd/gc/range.c).
 	t           *maptype
 	h           *hmap
 	buckets     unsafe.Pointer // bucket ptr at hash_iter initialization time
 	bptr        *bmap          // current bucket
-	overflow    [2]*[]*bmap    // keeps overflow buckets alive
 	startBucket uintptr        // bucket iteration started at
 	offset      uint8          // intra-bucket offset to start from during iteration (should be big enough to hold bucketCnt-1)
 	wrapped     bool           // already wrapped around from end of bucket array to beginning
@@ -159,35 +150,15 @@ func evacuated(b *bmap) bool {
 }
 
 func (b *bmap) overflow(t *maptype) *bmap {
-	return *(**bmap)(add(unsafe.Pointer(b), uintptr(t.bucketsize)-ptrSize))
-}
-
-func (h *hmap) setoverflow(t *maptype, b, ovf *bmap) {
-	if t.bucket.kind&kindNoPointers != 0 {
-		h.createOverflow()
-		*h.overflow[0] = append(*h.overflow[0], ovf)
-	}
-	*(**bmap)(add(unsafe.Pointer(b), uintptr(t.bucketsize)-ptrSize)) = ovf
+	return *(**bmap)(add(unsafe.Pointer(b), uintptr(t.bucketsize)-regSize))
 }
-
-func (h *hmap) createOverflow() {
-	if h.overflow == nil {
-		h.overflow = new([2]*[]*bmap)
-	}
-	if h.overflow[0] == nil {
-		h.overflow[0] = new([]*bmap)
-	}
+func (b *bmap) setoverflow(t *maptype, ovf *bmap) {
+	*(**bmap)(add(unsafe.Pointer(b), uintptr(t.bucketsize)-regSize)) = ovf
 }
 
-// makemap implements a Go map creation make(map[k]v, hint)
-// If the compiler has determined that the map or the first bucket
-// can be created on the stack, h and/or bucket may be non-nil.
-// If h != nil, the map can be created directly in h.
-// If bucket != nil, bucket can be used as the first bucket.
-func makemap(t *maptype, hint int64, h *hmap, bucket unsafe.Pointer) *hmap {
+func makemap(t *maptype, hint int64) *hmap {
 	if sz := unsafe.Sizeof(hmap{}); sz > 48 || sz != uintptr(t.hmap.size) {
-		println("runtime: sizeof(hmap) =", sz, ", t.hmap.size =", t.hmap.size)
-		throw("bad hmap size")
+		gothrow("bad hmap size")
 	}
 
 	if hint < 0 || int64(int32(hint)) != hint {
@@ -196,46 +167,43 @@ func makemap(t *maptype, hint int64, h *hmap, bucket unsafe.Pointer) *hmap {
 	}
 
 	if !ismapkey(t.key) {
-		throw("runtime.makemap: unsupported map key type")
+		gothrow("runtime.makemap: unsupported map key type")
 	}
 
 	// check compiler's and reflect's math
 	if t.key.size > maxKeySize && (!t.indirectkey || t.keysize != uint8(ptrSize)) ||
 		t.key.size <= maxKeySize && (t.indirectkey || t.keysize != uint8(t.key.size)) {
-		throw("key size wrong")
+		gothrow("key size wrong")
 	}
 	if t.elem.size > maxValueSize && (!t.indirectvalue || t.valuesize != uint8(ptrSize)) ||
 		t.elem.size <= maxValueSize && (t.indirectvalue || t.valuesize != uint8(t.elem.size)) {
-		throw("value size wrong")
+		gothrow("value size 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 > bucketCnt {
-		throw("key align too big")
+		gothrow("key align too big")
 	}
 	if t.elem.align > bucketCnt {
-		throw("value align too big")
+		gothrow("value align too big")
 	}
 	if uintptr(t.key.size)%uintptr(t.key.align) != 0 {
-		throw("key size not a multiple of key align")
+		gothrow("key size not a multiple of key align")
 	}
 	if uintptr(t.elem.size)%uintptr(t.elem.align) != 0 {
-		throw("value size not a multiple of value align")
+		gothrow("value size not a multiple of value align")
 	}
 	if bucketCnt < 8 {
-		throw("bucketsize too small for proper alignment")
+		gothrow("bucketsize too small for proper alignment")
 	}
 	if dataOffset%uintptr(t.key.align) != 0 {
-		throw("need padding in bucket (key)")
+		gothrow("need padding in bucket (key)")
 	}
 	if dataOffset%uintptr(t.elem.align) != 0 {
-		throw("need padding in bucket (value)")
+		gothrow("need padding in bucket (value)")
 	}
 
-	// make sure zero of element type is available.
-	mapzero(t.elem)
-
 	// find size parameter which will hold the requested # of elements
 	B := uint8(0)
 	for ; hint > bucketCnt && float32(hint) > loadFactor*float32(uintptr(1)<<B); B++ {
@@ -244,15 +212,19 @@ func makemap(t *maptype, hint int64, h *hmap, bucket unsafe.Pointer) *hmap {
 	// allocate initial hash table
 	// if B == 0, the buckets field is allocated lazily later (in mapassign)
 	// If hint is large zeroing this memory could take a while.
-	buckets := bucket
+	var buckets unsafe.Pointer
 	if B != 0 {
+		if checkgc {
+			memstats.next_gc = memstats.heap_alloc
+		}
 		buckets = newarray(t.bucket, uintptr(1)<<B)
 	}
 
 	// initialize Hmap
-	if h == nil {
-		h = (*hmap)(newobject(t.hmap))
+	if checkgc {
+		memstats.next_gc = memstats.heap_alloc
 	}
+	h := (*hmap)(newobject(t.hmap))
 	h.count = 0
 	h.B = B
 	h.flags = 0
@@ -279,8 +251,8 @@ func mapaccess1(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer {
 	if h == nil || h.count == 0 {
 		return unsafe.Pointer(t.elem.zero)
 	}
-	alg := t.key.alg
-	hash := alg.hash(key, uintptr(h.hash0))
+	alg := goalg(t.key.alg)
+	hash := alg.hash(key, uintptr(t.key.size), uintptr(h.hash0))
 	m := uintptr(1)<<h.B - 1
 	b := (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize)))
 	if c := h.oldbuckets; c != nil {
@@ -302,7 +274,7 @@ func mapaccess1(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer {
 			if t.indirectkey {
 				k = *((*unsafe.Pointer)(k))
 			}
-			if alg.equal(key, k) {
+			if alg.equal(key, k, uintptr(t.key.size)) {
 				v := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.keysize)+i*uintptr(t.valuesize))
 				if t.indirectvalue {
 					v = *((*unsafe.Pointer)(v))
@@ -327,8 +299,8 @@ func mapaccess2(t *maptype, h *hmap, key unsafe.Pointer) (unsafe.Pointer, bool)
 	if h == nil || h.count == 0 {
 		return unsafe.Pointer(t.elem.zero), false
 	}
-	alg := t.key.alg
-	hash := alg.hash(key, uintptr(h.hash0))
+	alg := goalg(t.key.alg)
+	hash := alg.hash(key, uintptr(t.key.size), uintptr(h.hash0))
 	m := uintptr(1)<<h.B - 1
 	b := (*bmap)(unsafe.Pointer(uintptr(h.buckets) + (hash&m)*uintptr(t.bucketsize)))
 	if c := h.oldbuckets; c != nil {
@@ -350,7 +322,7 @@ func mapaccess2(t *maptype, h *hmap, key unsafe.Pointer) (unsafe.Pointer, bool)
 			if t.indirectkey {
 				k = *((*unsafe.Pointer)(k))
 			}
-			if alg.equal(key, k) {
+			if alg.equal(key, k, uintptr(t.key.size)) {
 				v := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.keysize)+i*uintptr(t.valuesize))
 				if t.indirectvalue {
 					v = *((*unsafe.Pointer)(v))
@@ -370,8 +342,8 @@ func mapaccessK(t *maptype, h *hmap, key unsafe.Pointer) (unsafe.Pointer, unsafe
 	if h == nil || h.count == 0 {
 		return nil, nil
 	}
-	alg := t.key.alg
-	hash := alg.hash(key, uintptr(h.hash0))
+	alg := goalg(t.key.alg)
+	hash := alg.hash(key, uintptr(t.key.size), uintptr(h.hash0))
 	m := uintptr(1)<<h.B - 1
 	b := (*bmap)(unsafe.Pointer(uintptr(h.buckets) + (hash&m)*uintptr(t.bucketsize)))
 	if c := h.oldbuckets; c != nil {
@@ -393,7 +365,7 @@ func mapaccessK(t *maptype, h *hmap, key unsafe.Pointer) (unsafe.Pointer, unsafe
 			if t.indirectkey {
 				k = *((*unsafe.Pointer)(k))
 			}
-			if alg.equal(key, k) {
+			if alg.equal(key, k, uintptr(t.key.size)) {
 				v := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.keysize)+i*uintptr(t.valuesize))
 				if t.indirectvalue {
 					v = *((*unsafe.Pointer)(v))
@@ -420,10 +392,13 @@ func mapassign1(t *maptype, h *hmap, key unsafe.Pointer, val unsafe.Pointer) {
 		raceReadObjectPC(t.elem, val, callerpc, pc)
 	}
 
-	alg := t.key.alg
-	hash := alg.hash(key, uintptr(h.hash0))
+	alg := goalg(t.key.alg)
+	hash := alg.hash(key, uintptr(t.key.size), uintptr(h.hash0))
 
 	if h.buckets == nil {
+		if checkgc {
+			memstats.next_gc = memstats.heap_alloc
+		}
 		h.buckets = newarray(t.bucket, 1)
 	}
 
@@ -456,17 +431,17 @@ again:
 			if t.indirectkey {
 				k2 = *((*unsafe.Pointer)(k2))
 			}
-			if !alg.equal(key, k2) {
+			if !alg.equal(key, k2, uintptr(t.key.size)) {
 				continue
 			}
 			// already have a mapping for key.  Update it.
-			typedmemmove(t.key, k2, key)
+			memmove(k2, key, uintptr(t.key.size))
 			v := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.keysize)+i*uintptr(t.valuesize))
 			v2 := v
 			if t.indirectvalue {
 				v2 = *((*unsafe.Pointer)(v2))
 			}
-			typedmemmove(t.elem, v2, val)
+			memmove(v2, val, uintptr(t.elem.size))
 			return
 		}
 		ovf := b.overflow(t)
@@ -484,8 +459,11 @@ again:
 
 	if inserti == nil {
 		// all current buckets are full, allocate a new one.
+		if checkgc {
+			memstats.next_gc = memstats.heap_alloc
+		}
 		newb := (*bmap)(newobject(t.bucket))
-		h.setoverflow(t, b, newb)
+		b.setoverflow(t, newb)
 		inserti = &newb.tophash[0]
 		insertk = add(unsafe.Pointer(newb), dataOffset)
 		insertv = add(insertk, bucketCnt*uintptr(t.keysize))
@@ -493,17 +471,23 @@ again:
 
 	// store new key/value at insert position
 	if t.indirectkey {
+		if checkgc {
+			memstats.next_gc = memstats.heap_alloc
+		}
 		kmem := newobject(t.key)
 		*(*unsafe.Pointer)(insertk) = kmem
 		insertk = kmem
 	}
 	if t.indirectvalue {
+		if checkgc {
+			memstats.next_gc = memstats.heap_alloc
+		}
 		vmem := newobject(t.elem)
 		*(*unsafe.Pointer)(insertv) = vmem
 		insertv = vmem
 	}
-	typedmemmove(t.key, insertk, key)
-	typedmemmove(t.elem, insertv, val)
+	memmove(insertk, key, uintptr(t.key.size))
+	memmove(insertv, val, uintptr(t.elem.size))
 	*inserti = top
 	h.count++
 }
@@ -518,8 +502,8 @@ func mapdelete(t *maptype, h *hmap, key unsafe.Pointer) {
 	if h == nil || h.count == 0 {
 		return
 	}
-	alg := t.key.alg
-	hash := alg.hash(key, uintptr(h.hash0))
+	alg := goalg(t.key.alg)
+	hash := alg.hash(key, uintptr(t.key.size), uintptr(h.hash0))
 	bucket := hash & (uintptr(1)<<h.B - 1)
 	if h.oldbuckets != nil {
 		growWork(t, h, bucket)
@@ -539,7 +523,7 @@ func mapdelete(t *maptype, h *hmap, key unsafe.Pointer) {
 			if t.indirectkey {
 				k2 = *((*unsafe.Pointer)(k2))
 			}
-			if !alg.equal(key, k2) {
+			if !alg.equal(key, k2, uintptr(t.key.size)) {
 				continue
 			}
 			memclr(k, uintptr(t.keysize))
@@ -564,8 +548,6 @@ func mapiterinit(t *maptype, h *hmap, it *hiter) {
 	it.h = nil
 	it.buckets = nil
 	it.bptr = nil
-	it.overflow[0] = nil
-	it.overflow[1] = nil
 
 	if raceenabled && h != nil {
 		callerpc := getcallerpc(unsafe.Pointer(&t))
@@ -578,8 +560,8 @@ func mapiterinit(t *maptype, h *hmap, it *hiter) {
 		return
 	}
 
-	if unsafe.Sizeof(hiter{})/ptrSize != 12 {
-		throw("hash_iter size incorrect") // see ../../cmd/internal/gc/reflect.go
+	if unsafe.Sizeof(hiter{})/ptrSize != 10 {
+		gothrow("hash_iter size incorrect") // see ../../cmd/gc/reflect.c
 	}
 	it.t = t
 	it.h = h
@@ -587,14 +569,6 @@ func mapiterinit(t *maptype, h *hmap, it *hiter) {
 	// grab snapshot of bucket state
 	it.B = h.B
 	it.buckets = h.buckets
-	if t.bucket.kind&kindNoPointers != 0 {
-		// Allocate the current slice and remember pointers to both current and old.
-		// This preserves all relevant overflow buckets alive even if
-		// the table grows and/or overflow buckets are added to the table
-		// while we are iterating.
-		h.createOverflow()
-		it.overflow = *h.overflow
-	}
 
 	// decide where to start
 	r := uintptr(fastrand1())
@@ -611,8 +585,14 @@ func mapiterinit(t *maptype, h *hmap, it *hiter) {
 
 	// Remember we have an iterator.
 	// Can run concurrently with another hash_iter_init().
-	if old := h.flags; old&(iterator|oldIterator) != iterator|oldIterator {
-		atomicor8(&h.flags, iterator|oldIterator)
+	for {
+		old := h.flags
+		if old == old|iterator|oldIterator {
+			break
+		}
+		if cas(&h.flags, old, old|iterator|oldIterator) {
+			break
+		}
 	}
 
 	mapiternext(it)
@@ -629,7 +609,7 @@ func mapiternext(it *hiter) {
 	b := it.bptr
 	i := it.i
 	checkBucket := it.checkBucket
-	alg := t.key.alg
+	alg := goalg(t.key.alg)
 
 next:
 	if b == nil {
@@ -680,10 +660,10 @@ next:
 				if t.indirectkey {
 					k2 = *((*unsafe.Pointer)(k2))
 				}
-				if t.reflexivekey || alg.equal(k2, k2) {
+				if alg.equal(k2, k2, uintptr(t.key.size)) {
 					// If the item in the oldbucket is not destined for
 					// the current new bucket in the iteration, skip it.
-					hash := alg.hash(k2, uintptr(h.hash0))
+					hash := alg.hash(k2, uintptr(t.key.size), uintptr(h.hash0))
 					if hash&(uintptr(1)<<it.B-1) != checkBucket {
 						continue
 					}
@@ -717,7 +697,7 @@ next:
 				if t.indirectkey {
 					k2 = *((*unsafe.Pointer)(k2))
 				}
-				if t.reflexivekey || alg.equal(k2, k2) {
+				if alg.equal(k2, k2, uintptr(t.key.size)) {
 					// Check the current hash table for the data.
 					// This code handles the case where the key
 					// has been deleted, updated, or deleted and reinserted.
@@ -755,9 +735,12 @@ next:
 
 func hashGrow(t *maptype, h *hmap) {
 	if h.oldbuckets != nil {
-		throw("evacuation not done in time")
+		gothrow("evacuation not done in time")
 	}
 	oldbuckets := h.buckets
+	if checkgc {
+		memstats.next_gc = memstats.heap_alloc
+	}
 	newbuckets := newarray(t.bucket, uintptr(1)<<(h.B+1))
 	flags := h.flags &^ (iterator | oldIterator)
 	if h.flags&iterator != 0 {
@@ -770,15 +753,6 @@ func hashGrow(t *maptype, h *hmap) {
 	h.buckets = newbuckets
 	h.nevacuate = 0
 
-	if h.overflow != nil {
-		// Promote current overflow buckets to the old generation.
-		if h.overflow[1] != nil {
-			throw("overflow is not nil")
-		}
-		h.overflow[1] = h.overflow[0]
-		h.overflow[0] = nil
-	}
-
 	// the actual copying of the hash table data is done incrementally
 	// by growWork() and evacuate().
 }
@@ -799,7 +773,7 @@ func growWork(t *maptype, h *hmap, bucket uintptr) {
 func evacuate(t *maptype, h *hmap, oldbucket uintptr) {
 	b := (*bmap)(add(h.oldbuckets, oldbucket*uintptr(t.bucketsize)))
 	newbit := uintptr(1) << (h.B - 1)
-	alg := t.key.alg
+	alg := goalg(t.key.alg)
 	if !evacuated(b) {
 		// TODO: reuse overflow buckets instead of using new ones, if there
 		// is no iterator using the old buckets.  (If !oldIterator.)
@@ -822,7 +796,7 @@ func evacuate(t *maptype, h *hmap, oldbucket uintptr) {
 					continue
 				}
 				if top < minTopHash {
-					throw("bad map state")
+					gothrow("bad map state")
 				}
 				k2 := k
 				if t.indirectkey {
@@ -830,9 +804,9 @@ func evacuate(t *maptype, h *hmap, oldbucket uintptr) {
 				}
 				// Compute hash to make our evacuation decision (whether we need
 				// to send this key/value to bucket x or bucket y).
-				hash := alg.hash(k2, uintptr(h.hash0))
+				hash := alg.hash(k2, uintptr(t.key.size), uintptr(h.hash0))
 				if h.flags&iterator != 0 {
-					if !t.reflexivekey && !alg.equal(k2, k2) {
+					if !alg.equal(k2, k2, uintptr(t.key.size)) {
 						// 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
@@ -858,8 +832,11 @@ func evacuate(t *maptype, h *hmap, oldbucket uintptr) {
 				if (hash & newbit) == 0 {
 					b.tophash[i] = evacuatedX
 					if xi == bucketCnt {
+						if checkgc {
+							memstats.next_gc = memstats.heap_alloc
+						}
 						newx := (*bmap)(newobject(t.bucket))
-						h.setoverflow(t, x, newx)
+						x.setoverflow(t, newx)
 						x = newx
 						xi = 0
 						xk = add(unsafe.Pointer(x), dataOffset)
@@ -869,12 +846,12 @@ func evacuate(t *maptype, h *hmap, oldbucket uintptr) {
 					if t.indirectkey {
 						*(*unsafe.Pointer)(xk) = k2 // copy pointer
 					} else {
-						typedmemmove(t.key, xk, k) // copy value
+						memmove(xk, k, uintptr(t.key.size)) // copy value
 					}
 					if t.indirectvalue {
 						*(*unsafe.Pointer)(xv) = *(*unsafe.Pointer)(v)
 					} else {
-						typedmemmove(t.elem, xv, v)
+						memmove(xv, v, uintptr(t.elem.size))
 					}
 					xi++
 					xk = add(xk, uintptr(t.keysize))
@@ -882,8 +859,11 @@ func evacuate(t *maptype, h *hmap, oldbucket uintptr) {
 				} else {
 					b.tophash[i] = evacuatedY
 					if yi == bucketCnt {
+						if checkgc {
+							memstats.next_gc = memstats.heap_alloc
+						}
 						newy := (*bmap)(newobject(t.bucket))
-						h.setoverflow(t, y, newy)
+						y.setoverflow(t, newy)
 						y = newy
 						yi = 0
 						yk = add(unsafe.Pointer(y), dataOffset)
@@ -893,12 +873,12 @@ func evacuate(t *maptype, h *hmap, oldbucket uintptr) {
 					if t.indirectkey {
 						*(*unsafe.Pointer)(yk) = k2
 					} else {
-						typedmemmove(t.key, yk, k)
+						memmove(yk, k, uintptr(t.key.size))
 					}
 					if t.indirectvalue {
 						*(*unsafe.Pointer)(yv) = *(*unsafe.Pointer)(v)
 					} else {
-						typedmemmove(t.elem, yv, v)
+						memmove(yv, v, uintptr(t.elem.size))
 					}
 					yi++
 					yk = add(yk, uintptr(t.keysize))
@@ -919,28 +899,20 @@ func evacuate(t *maptype, h *hmap, oldbucket uintptr) {
 		if oldbucket+1 == newbit { // newbit == # of oldbuckets
 			// Growing is all done.  Free old main bucket array.
 			h.oldbuckets = nil
-			// Can discard old overflow buckets as well.
-			// If they are still referenced by an iterator,
-			// then the iterator holds a pointers to the slice.
-			if h.overflow != nil {
-				h.overflow[1] = nil
-			}
 		}
 	}
 }
 
 func ismapkey(t *_type) bool {
-	return t.alg.hash != nil
+	return goalg(t.alg).hash != nil
 }
 
 // Reflect stubs.  Called from ../reflect/asm_*.s
 
-//go:linkname reflect_makemap reflect.makemap
 func reflect_makemap(t *maptype) *hmap {
-	return makemap(t, 0, nil, nil)
+	return makemap(t, 0)
 }
 
-//go:linkname reflect_mapaccess reflect.mapaccess
 func reflect_mapaccess(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer {
 	val, ok := mapaccess2(t, h, key)
 	if !ok {
@@ -950,34 +922,28 @@ func reflect_mapaccess(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer {
 	return val
 }
 
-//go:linkname reflect_mapassign reflect.mapassign
 func reflect_mapassign(t *maptype, h *hmap, key unsafe.Pointer, val unsafe.Pointer) {
 	mapassign1(t, h, key, val)
 }
 
-//go:linkname reflect_mapdelete reflect.mapdelete
 func reflect_mapdelete(t *maptype, h *hmap, key unsafe.Pointer) {
 	mapdelete(t, h, key)
 }
 
-//go:linkname reflect_mapiterinit reflect.mapiterinit
 func reflect_mapiterinit(t *maptype, h *hmap) *hiter {
 	it := new(hiter)
 	mapiterinit(t, h, it)
 	return it
 }
 
-//go:linkname reflect_mapiternext reflect.mapiternext
 func reflect_mapiternext(it *hiter) {
 	mapiternext(it)
 }
 
-//go:linkname reflect_mapiterkey reflect.mapiterkey
 func reflect_mapiterkey(it *hiter) unsafe.Pointer {
 	return it.key
 }
 
-//go:linkname reflect_maplen reflect.maplen
 func reflect_maplen(h *hmap) int {
 	if h == nil {
 		return 0
@@ -989,64 +955,6 @@ func reflect_maplen(h *hmap) int {
 	return h.count
 }
 
-//go:linkname reflect_ismapkey reflect.ismapkey
 func reflect_ismapkey(t *_type) bool {
 	return ismapkey(t)
 }
-
-var zerobuf struct {
-	lock mutex
-	p    *byte
-	size uintptr
-}
-
-var zerotiny [1024]byte
-
-// mapzero ensures that t.zero points at a zero value for type t.
-// Types known to the compiler are in read-only memory and all point
-// to a single zero in the bss of a large enough size.
-// Types allocated by package reflect are in writable memory and
-// start out with zero set to nil; we initialize those on demand.
-func mapzero(t *_type) {
-	// On ARM, atomicloadp is implemented as xadd(p, 0),
-	// so we cannot use atomicloadp on read-only memory.
-	// Check whether the pointer is in the heap; if not, it's not writable
-	// so the zero value must already be set.
-	if GOARCH == "arm" && !inheap(uintptr(unsafe.Pointer(t))) {
-		if t.zero == nil {
-			print("runtime: map element ", *t._string, " missing zero value\n")
-			throw("mapzero")
-		}
-		return
-	}
-
-	// Already done?
-	// Check without lock, so must use atomicload to sync with atomicstore in allocation case below.
-	if atomicloadp(unsafe.Pointer(&t.zero)) != nil {
-		return
-	}
-
-	// Small enough for static buffer?
-	if t.size <= uintptr(len(zerotiny)) {
-		atomicstorep(unsafe.Pointer(&t.zero), unsafe.Pointer(&zerotiny[0]))
-		return
-	}
-
-	// Use allocated buffer.
-	lock(&zerobuf.lock)
-	if zerobuf.size < t.size {
-		if zerobuf.size == 0 {
-			zerobuf.size = 4 * 1024
-		}
-		for zerobuf.size < t.size {
-			zerobuf.size *= 2
-			if zerobuf.size == 0 {
-				// need >2GB zero on 32-bit machine
-				throw("map element too large")
-			}
-		}
-		zerobuf.p = (*byte)(persistentalloc(zerobuf.size, 64, &memstats.other_sys))
-	}
-	atomicstorep(unsafe.Pointer(&t.zero), unsafe.Pointer(zerobuf.p))
-	unlock(&zerobuf.lock)
-}
diff --git a/src/runtime/hashmap_fast.go b/src/runtime/hashmap_fast.go
index 02c51a2..afa6ecc 100644
--- a/src/runtime/hashmap_fast.go
+++ b/src/runtime/hashmap_fast.go
@@ -21,7 +21,7 @@ func mapaccess1_fast32(t *maptype, h *hmap, key uint32) unsafe.Pointer {
 		// One-bucket table.  No need to hash.
 		b = (*bmap)(h.buckets)
 	} else {
-		hash := t.key.alg.hash(noescape(unsafe.Pointer(&key)), uintptr(h.hash0))
+		hash := goalg(t.key.alg).hash(noescape(unsafe.Pointer(&key)), 4, uintptr(h.hash0))
 		m := uintptr(1)<<h.B - 1
 		b = (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize)))
 		if c := h.oldbuckets; c != nil {
@@ -63,7 +63,7 @@ func mapaccess2_fast32(t *maptype, h *hmap, key uint32) (unsafe.Pointer, bool) {
 		// One-bucket table.  No need to hash.
 		b = (*bmap)(h.buckets)
 	} else {
-		hash := t.key.alg.hash(noescape(unsafe.Pointer(&key)), uintptr(h.hash0))
+		hash := goalg(t.key.alg).hash(noescape(unsafe.Pointer(&key)), 4, uintptr(h.hash0))
 		m := uintptr(1)<<h.B - 1
 		b = (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize)))
 		if c := h.oldbuckets; c != nil {
@@ -105,7 +105,7 @@ func mapaccess1_fast64(t *maptype, h *hmap, key uint64) unsafe.Pointer {
 		// One-bucket table.  No need to hash.
 		b = (*bmap)(h.buckets)
 	} else {
-		hash := t.key.alg.hash(noescape(unsafe.Pointer(&key)), uintptr(h.hash0))
+		hash := goalg(t.key.alg).hash(noescape(unsafe.Pointer(&key)), 8, uintptr(h.hash0))
 		m := uintptr(1)<<h.B - 1
 		b = (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize)))
 		if c := h.oldbuckets; c != nil {
@@ -147,7 +147,7 @@ func mapaccess2_fast64(t *maptype, h *hmap, key uint64) (unsafe.Pointer, bool) {
 		// One-bucket table.  No need to hash.
 		b = (*bmap)(h.buckets)
 	} else {
-		hash := t.key.alg.hash(noescape(unsafe.Pointer(&key)), uintptr(h.hash0))
+		hash := goalg(t.key.alg).hash(noescape(unsafe.Pointer(&key)), 8, uintptr(h.hash0))
 		m := uintptr(1)<<h.B - 1
 		b = (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize)))
 		if c := h.oldbuckets; c != nil {
@@ -244,7 +244,7 @@ func mapaccess1_faststr(t *maptype, h *hmap, ky string) unsafe.Pointer {
 		return unsafe.Pointer(t.elem.zero)
 	}
 dohash:
-	hash := t.key.alg.hash(noescape(unsafe.Pointer(&ky)), uintptr(h.hash0))
+	hash := goalg(t.key.alg).hash(noescape(unsafe.Pointer(&ky)), 2*ptrSize, uintptr(h.hash0))
 	m := uintptr(1)<<h.B - 1
 	b := (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize)))
 	if c := h.oldbuckets; c != nil {
@@ -344,7 +344,7 @@ func mapaccess2_faststr(t *maptype, h *hmap, ky string) (unsafe.Pointer, bool) {
 		return unsafe.Pointer(t.elem.zero), false
 	}
 dohash:
-	hash := t.key.alg.hash(noescape(unsafe.Pointer(&ky)), uintptr(h.hash0))
+	hash := goalg(t.key.alg).hash(noescape(unsafe.Pointer(&ky)), 2*ptrSize, uintptr(h.hash0))
 	m := uintptr(1)<<h.B - 1
 	b := (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize)))
 	if c := h.oldbuckets; c != nil {
diff --git a/src/runtime/heapdump.c b/src/runtime/heapdump.c
new file mode 100644
index 0000000..7eba8c0
--- /dev/null
+++ b/src/runtime/heapdump.c
@@ -0,0 +1,864 @@
+// 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://golang.org/s/go14heapdump.
+
+#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 "textflag.h"
+
+extern byte runtime·data[];
+extern byte runtime·edata[];
+extern byte runtime·bss[];
+extern byte runtime·ebss[];
+
+enum {
+	FieldKindEol = 0,
+	FieldKindPtr = 1,
+	FieldKindIface = 2,
+	FieldKindEface = 3,
+
+	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,
+};
+
+static uintptr* playgcprog(uintptr offset, uintptr *prog, void (*callback)(void*,uintptr,uintptr), void *arg);
+static void dumpfields(BitVector bv);
+static void dumpbvtypes(BitVector *bv, byte *base);
+static BitVector makeheapobjbv(byte *p, uintptr size);
+
+// fd to write the dump to.
+static uintptr	dumpfd;
+
+#pragma dataflag NOPTR /* tmpbuf not a heap pointer at least */
+static byte	*tmpbuf;
+static uintptr	tmpbufsize;
+
+// 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];
+};
+#pragma dataflag NOPTR /* only initialized and used while world is stopped */
+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->kind & KindDirectIface) == 0 || (t->kind & KindNoPointers) == 0);
+}
+
+// dump an object
+static void
+dumpobj(byte *obj, uintptr size, BitVector bv)
+{
+	dumpbvtypes(&bv, obj);
+	dumpint(TagObject);
+	dumpint((uintptr)obj);
+	dumpmemrange(obj, size);
+	dumpfields(bv);
+}
+
+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->bytedata[i/8] >> i%8 & 3) {
+		case BitsDead:
+			// BitsDead has already been processed in makeheapobjbv.
+			// We should only see it in stack maps, in which case we should continue processing.
+			break;
+		case BitsScalar:
+			break;
+		case BitsPointer:
+			dumpint(FieldKindPtr);
+			dumpint(offset + i / BitsPerPointer * PtrSize);
+			break;
+		case BitsMultiWord:
+			switch(bv->bytedata[(i+BitsPerPointer)/8] >> (i+BitsPerPointer)%8 & 3) {
+			default:
+				runtime·throw("unexpected garbage collection bits");
+			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, (byte*)(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 - 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 - s->sp; off <  s->varp - 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 - s->sp);
+	}
+	dumpint(FieldKindEol);
+
+	// Record arg info for parent.
+	child->argoff = s->argp - 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;
+	bool (*fn)(Stkframe*, void*);
+
+	if(gp->syscallsp != (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(runtime·readgstatus(gp));
+	dumpbool(gp->issystem);
+	dumpbool(false);  // isbackground
+	dumpint(gp->waitsince);
+	dumpstr(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;
+	fn = dumpframe;
+	runtime·gentraceback(pc, sp, lr, gp, 0, nil, 0x7fffffff, &fn, &child, 0);
+
+	// 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(0); // was p->defer, no longer recorded
+		dumpint((uintptr)p->link);
+	}
+}
+
+static void
+dumpgs(void)
+{
+	G *gp;
+	uint32 i;
+	uint32 status;
+
+	// goroutines & stacks
+	for(i = 0; i < runtime·allglen; i++) {
+		gp = runtime·allg[i];
+		status = runtime·readgstatus(gp); // The world is stopped so gp will not be in a scan state.
+		switch(status){
+		default:
+			runtime·printf("runtime: unexpected G.status %d\n", status);
+			runtime·throw("dumpgs in STW - 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
+	dumpbvtypes(&runtime·gcdatamask, runtime·data);
+	dumpint(TagData);
+	dumpint((uintptr)runtime·data);
+	dumpmemrange(runtime·data, runtime·edata - runtime·data);
+	dumpfields(runtime·gcdatamask);
+
+	// bss segment
+	dumpbvtypes(&runtime·gcbssmask, runtime·bss);
+	dumpint(TagBss);
+	dumpint((uintptr)runtime·bss);
+	dumpmemrange(runtime·bss, runtime·ebss - runtime·bss);
+	dumpfields(runtime·gcbssmask);
+
+	// MSpan.types
+	allspans = runtime·mheap.allspans;
+	for(spanidx=0; spanidx<runtime·mheap.nspan; spanidx++) {
+		s = allspans[spanidx];
+		if(s->state == MSpanInUse) {
+			// Finalizers
+			for(sp = s->specials; sp != nil; sp = sp->next) {
+				if(sp->kind != KindSpecialFinalizer)
+					continue;
+				spf = (SpecialFinalizer*)sp;
+				p = (byte*)((s->start << PageShift) + spf->special.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.	
+#pragma dataflag NOPTR
+static byte free[PageSize/8];	
+
+static void
+dumpobjs(void)
+{
+	uintptr i, j, size, n;
+	MSpan *s;
+	MLink *l;
+	byte *p;
+
+	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 > nelem(free))	
+			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;	
+			}
+			dumpobj(p, size, makeheapobjbv(p, size));
+		}
+	}
+}
+
+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((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;
+
+	t = tab->type;
+	// Dump a map from itab* to the type of its data field.
+	// We want this map so we can deduce types of interface referents.
+	if((t->kind & KindDirectIface) == 0) {
+		// indirect - data slot is a pointer to t.
+		dumptype(t->ptrto);
+		dumpint(TagItab);
+		dumpint((uintptr)tab);
+		dumpint((uintptr)t->ptrto);
+	} else if((t->kind & KindNoPointers) == 0) {
+		// t is pointer-like - data slot is a t.
+		dumptype(t);
+		dumpint(TagItab);
+		dumpint((uintptr)tab);
+		dumpint((uintptr)t);
+	} else {
+		// Data slot is a scalar.  Dump type just for fun.
+		// With pointer-only interfaces, this shouldn't happen.
+		dumptype(t);
+		dumpint(TagItab);
+		dumpint((uintptr)tab);
+		dumpint((uintptr)t);
+	}
+}
+
+static void
+dumpitabs(void)
+{
+	void (*fn)(Itab*);
+	
+	fn = itab_callback;
+	runtime·iterate_itabs(&fn);
+}
+
+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;
+	void (*fn)(Bucket*, uintptr, uintptr*, uintptr, uintptr, uintptr);
+	
+	fn = dumpmemprof_callback;
+	runtime·iterate_memprof(&fn);
+
+	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->special.offset);
+			dumpint(TagAllocSample);
+			dumpint((uintptr)p);
+			dumpint((uintptr)spp->b);
+		}
+	}
+}
+
+static void
+mdump(void)
+{
+	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.4 heap dump\n";
+	write(hdr, runtime·findnull(hdr));
+	dumpparams();
+	dumpitabs();
+	dumpobjs();
+	dumpgs();
+	dumpms();
+	dumproots();
+	dumpmemstats();
+	dumpmemprof();
+	dumpint(TagEOF);
+	flush();
+}
+
+void
+runtime·writeheapdump_m(void)
+{
+	uintptr fd;
+	
+	fd = g->m->scalararg[0];
+	g->m->scalararg[0] = 0;
+
+	runtime·casgstatus(g->m->curg, Grunning, Gwaiting);
+	g->waitreason = runtime·gostringnocopy((byte*)"dumping heap");
+
+	// 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.
+	mdump();
+
+	// Reset dump file.
+	dumpfd = 0;
+	if(tmpbuf != nil) {
+		runtime·SysFree(tmpbuf, tmpbufsize, &mstats.other_sys);
+		tmpbuf = nil;
+		tmpbufsize = 0;
+	}
+
+	runtime·casgstatus(g->m->curg, Gwaiting, Grunning);
+}
+
+// dumpint() the kind & offset of each field in an object.
+static void
+dumpfields(BitVector bv)
+{
+	dumpbv(&bv, 0);
+	dumpint(FieldKindEol);
+}
+
+// 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 routine accomplishes that.
+
+// 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->bytedata[i/8] >> i%8 & 3) != BitsMultiWord)
+			continue;
+		switch(bv->bytedata[(i+BitsPerPointer)/8] >> (i+BitsPerPointer)%8 & 3) {
+		default:
+			runtime·throw("unexpected garbage collection bits");
+		case BitsIface:
+			i += BitsPerPointer;
+			break;
+		case BitsEface:
+			dumptype(*(Type**)(base + i / BitsPerPointer * PtrSize));
+			i += BitsPerPointer;
+			break;
+		}
+	}
+}
+
+static BitVector
+makeheapobjbv(byte *p, uintptr size)
+{
+	uintptr off, nptr, i;
+	byte shift, *bitp, bits;
+	bool mw;
+
+	// Extend the temp buffer if necessary.
+	nptr = size/PtrSize;
+	if(tmpbufsize < nptr*BitsPerPointer/8+1) {
+		if(tmpbuf != nil)
+			runtime·SysFree(tmpbuf, tmpbufsize, &mstats.other_sys);
+		tmpbufsize = nptr*BitsPerPointer/8+1;
+		tmpbuf = runtime·sysAlloc(tmpbufsize, &mstats.other_sys);
+		if(tmpbuf == nil)
+			runtime·throw("heapdump: out of memory");
+	}
+
+	// Copy and compact the bitmap.
+	mw = false;
+	for(i = 0; i < nptr; i++) {
+		off = (uintptr*)(p + i*PtrSize) - (uintptr*)runtime·mheap.arena_start;
+		bitp = runtime·mheap.arena_start - off/wordsPerBitmapByte - 1;
+		shift = (off % wordsPerBitmapByte) * gcBits;
+		bits = (*bitp >> (shift + 2)) & BitsMask;
+		if(!mw && bits == BitsDead)
+			break;  // end of heap object
+		mw = !mw && bits == BitsMultiWord;
+		tmpbuf[i*BitsPerPointer/8] &= ~(BitsMask<<((i*BitsPerPointer)%8));
+		tmpbuf[i*BitsPerPointer/8] |= bits<<((i*BitsPerPointer)%8);
+	}
+	return (BitVector){i*BitsPerPointer, tmpbuf};
+}
diff --git a/src/runtime/iface.go b/src/runtime/iface.go
index abd7068..f60b6a7 100644
--- a/src/runtime/iface.go
+++ b/src/runtime/iface.go
@@ -4,7 +4,9 @@
 
 package runtime
 
-import "unsafe"
+import (
+	"unsafe"
+)
 
 const (
 	hashSize = 1009
@@ -24,7 +26,7 @@ type fInterface interface {
 
 func getitab(inter *interfacetype, typ *_type, canfail bool) *itab {
 	if len(inter.mhdr) == 0 {
-		throw("internal error - misuse of itab")
+		gothrow("internal error - misuse of itab")
 	}
 
 	// easy case
@@ -33,7 +35,8 @@ func getitab(inter *interfacetype, typ *_type, canfail bool) *itab {
 		if canfail {
 			return nil
 		}
-		panic(&TypeAssertionError{"", *typ._string, *inter.typ._string, *inter.mhdr[0].name})
+		i := (*imethod)(add(unsafe.Pointer(inter), unsafe.Sizeof(interfacetype{})))
+		panic(&TypeAssertionError{"", *typ._string, *inter.typ._string, *i.name})
 	}
 
 	// compiler has provided some good hash codes for us.
@@ -73,7 +76,7 @@ func getitab(inter *interfacetype, typ *_type, canfail bool) *itab {
 		}
 	}
 
-	m = (*itab)(persistentalloc(unsafe.Sizeof(itab{})+uintptr(len(inter.mhdr)-1)*ptrSize, 0, &memstats.other_sys))
+	m = (*itab)(persistentalloc(unsafe.Sizeof(itab{})+uintptr(len(inter.mhdr))*ptrSize, 0, &memstats.other_sys))
 	m.inter = inter
 	m._type = typ
 
@@ -86,15 +89,15 @@ search:
 	nt := len(x.mhdr)
 	j := 0
 	for k := 0; k < ni; k++ {
-		i := &inter.mhdr[k]
+		i := (*imethod)(add(unsafe.Pointer(inter), unsafe.Sizeof(interfacetype{})+uintptr(k)*unsafe.Sizeof(imethod{})))
 		iname := i.name
 		ipkgpath := i.pkgpath
 		itype := i._type
 		for ; j < nt; j++ {
-			t := &x.mhdr[j]
-			if t.mtyp == itype && (t.name == iname || *t.name == *iname) && t.pkgpath == ipkgpath {
+			t := (*method)(add(unsafe.Pointer(x), unsafe.Sizeof(uncommontype{})+uintptr(j)*unsafe.Sizeof(method{})))
+			if t.mtyp == itype && t.name == iname && t.pkgpath == ipkgpath {
 				if m != nil {
-					*(*unsafe.Pointer)(add(unsafe.Pointer(&m.fun[0]), uintptr(k)*ptrSize)) = t.ifn
+					*(*unsafe.Pointer)(add(unsafe.Pointer(m), unsafe.Sizeof(itab{})+uintptr(k)*ptrSize)) = t.ifn
 				}
 				goto nextimethod
 			}
@@ -111,7 +114,7 @@ search:
 	nextimethod:
 	}
 	if locked == 0 {
-		throw("invalid itab locking")
+		gothrow("invalid itab locking")
 	}
 	m.link = hash[h]
 	atomicstorep(unsafe.Pointer(&hash[h]), unsafe.Pointer(m))
@@ -128,54 +131,47 @@ func typ2Itab(t *_type, inter *interfacetype, cache **itab) *itab {
 	return tab
 }
 
-func convT2E(t *_type, elem unsafe.Pointer, x unsafe.Pointer) (e interface{}) {
+func convT2E(t *_type, elem unsafe.Pointer) (e interface{}) {
+	size := uintptr(t.size)
 	ep := (*eface)(unsafe.Pointer(&e))
 	if isDirectIface(t) {
 		ep._type = t
-		typedmemmove(t, unsafe.Pointer(&ep.data), elem)
+		memmove(unsafe.Pointer(&ep.data), elem, size)
 	} else {
-		if x == nil {
-			x = newobject(t)
-		}
+		x := newobject(t)
 		// TODO: We allocate a zeroed object only to overwrite it with
 		// actual data.  Figure out how to avoid zeroing.  Also below in convT2I.
-		typedmemmove(t, x, elem)
+		memmove(x, elem, size)
 		ep._type = t
 		ep.data = x
 	}
 	return
 }
 
-func convT2I(t *_type, inter *interfacetype, cache **itab, elem unsafe.Pointer, x unsafe.Pointer) (i fInterface) {
+func convT2I(t *_type, inter *interfacetype, cache **itab, elem unsafe.Pointer) (i fInterface) {
 	tab := (*itab)(atomicloadp(unsafe.Pointer(cache)))
 	if tab == nil {
 		tab = getitab(inter, t, false)
 		atomicstorep(unsafe.Pointer(cache), unsafe.Pointer(tab))
 	}
+	size := uintptr(t.size)
 	pi := (*iface)(unsafe.Pointer(&i))
 	if isDirectIface(t) {
 		pi.tab = tab
-		typedmemmove(t, unsafe.Pointer(&pi.data), elem)
+		memmove(unsafe.Pointer(&pi.data), elem, size)
 	} else {
-		if x == nil {
-			x = newobject(t)
-		}
-		typedmemmove(t, x, elem)
+		x := newobject(t)
+		memmove(x, elem, size)
 		pi.tab = tab
 		pi.data = x
 	}
 	return
 }
 
-func panicdottype(have, want, iface *_type) {
-	haveString := ""
-	if have != nil {
-		haveString = *have._string
-	}
-	panic(&TypeAssertionError{*iface._string, haveString, *want._string, ""})
-}
-
-func assertI2T(t *_type, i fInterface, r unsafe.Pointer) {
+// TODO: give these routines a pointer to the result area instead of writing
+// extra data in the outargs section.  Then we can get rid of go:nosplit.
+//go:nosplit
+func assertI2T(t *_type, i fInterface) (r struct{}) {
 	ip := (*iface)(unsafe.Pointer(&i))
 	tab := ip.tab
 	if tab == nil {
@@ -184,35 +180,43 @@ func assertI2T(t *_type, i fInterface, r unsafe.Pointer) {
 	if tab._type != t {
 		panic(&TypeAssertionError{*tab.inter.typ._string, *tab._type._string, *t._string, ""})
 	}
-	if r != nil {
-		if isDirectIface(t) {
-			writebarrierptr((*uintptr)(r), uintptr(ip.data))
-		} else {
-			typedmemmove(t, r, ip.data)
-		}
+	size := uintptr(t.size)
+	if isDirectIface(t) {
+		memmove(unsafe.Pointer(&r), unsafe.Pointer(&ip.data), size)
+	} else {
+		memmove(unsafe.Pointer(&r), ip.data, size)
 	}
+	return
 }
 
-func assertI2T2(t *_type, i fInterface, r unsafe.Pointer) bool {
+//go:nosplit
+func assertI2T2(t *_type, i fInterface) (r byte) {
 	ip := (*iface)(unsafe.Pointer(&i))
+	size := uintptr(t.size)
+	ok := (*bool)(add(unsafe.Pointer(&r), size))
 	tab := ip.tab
 	if tab == nil || tab._type != t {
-		if r != nil {
-			memclr(r, uintptr(t.size))
-		}
-		return false
+		*ok = false
+		memclr(unsafe.Pointer(&r), size)
+		return
 	}
-	if r != nil {
-		if isDirectIface(t) {
-			writebarrierptr((*uintptr)(r), uintptr(ip.data))
-		} else {
-			typedmemmove(t, r, ip.data)
-		}
+	*ok = true
+	if isDirectIface(t) {
+		memmove(unsafe.Pointer(&r), unsafe.Pointer(&ip.data), size)
+	} else {
+		memmove(unsafe.Pointer(&r), ip.data, size)
 	}
-	return true
+	return
 }
 
-func assertE2T(t *_type, e interface{}, r unsafe.Pointer) {
+func assertI2TOK(t *_type, i fInterface) bool {
+	ip := (*iface)(unsafe.Pointer(&i))
+	tab := ip.tab
+	return tab != nil && tab._type == t
+}
+
+//go:nosplit
+func assertE2T(t *_type, e interface{}) (r struct{}) {
 	ep := (*eface)(unsafe.Pointer(&e))
 	if ep._type == nil {
 		panic(&TypeAssertionError{"", "", *t._string, ""})
@@ -220,28 +224,37 @@ func assertE2T(t *_type, e interface{}, r unsafe.Pointer) {
 	if ep._type != t {
 		panic(&TypeAssertionError{"", *ep._type._string, *t._string, ""})
 	}
-	if r != nil {
-		if isDirectIface(t) {
-			writebarrierptr((*uintptr)(r), uintptr(ep.data))
-		} else {
-			typedmemmove(t, r, ep.data)
-		}
+	size := uintptr(t.size)
+	if isDirectIface(t) {
+		memmove(unsafe.Pointer(&r), unsafe.Pointer(&ep.data), size)
+	} else {
+		memmove(unsafe.Pointer(&r), ep.data, size)
 	}
+	return
 }
 
-// The compiler ensures that r is non-nil.
-func assertE2T2(t *_type, e interface{}, r unsafe.Pointer) bool {
+//go:nosplit
+func assertE2T2(t *_type, e interface{}) (r byte) {
 	ep := (*eface)(unsafe.Pointer(&e))
+	size := uintptr(t.size)
+	ok := (*bool)(add(unsafe.Pointer(&r), size))
 	if ep._type != t {
-		memclr(r, uintptr(t.size))
-		return false
+		*ok = false
+		memclr(unsafe.Pointer(&r), size)
+		return
 	}
+	*ok = true
 	if isDirectIface(t) {
-		writebarrierptr((*uintptr)(r), uintptr(ep.data))
+		memmove(unsafe.Pointer(&r), unsafe.Pointer(&ep.data), size)
 	} else {
-		typedmemmove(t, r, ep.data)
+		memmove(unsafe.Pointer(&r), ep.data, size)
 	}
-	return true
+	return
+}
+
+func assertE2TOK(t *_type, e interface{}) bool {
+	ep := (*eface)(unsafe.Pointer(&e))
+	return t == ep._type
 }
 
 func convI2E(i fInterface) (r interface{}) {
@@ -256,30 +269,30 @@ func convI2E(i fInterface) (r interface{}) {
 	return
 }
 
-func assertI2E(inter *interfacetype, i fInterface, r *interface{}) {
+func assertI2E(inter *interfacetype, i fInterface) (r interface{}) {
 	ip := (*iface)(unsafe.Pointer(&i))
 	tab := ip.tab
 	if tab == nil {
 		// explicit conversions require non-nil interface value.
 		panic(&TypeAssertionError{"", "", *inter.typ._string, ""})
 	}
-	rp := (*eface)(unsafe.Pointer(r))
+	rp := (*eface)(unsafe.Pointer(&r))
 	rp._type = tab._type
 	rp.data = ip.data
 	return
 }
 
-// The compiler ensures that r is non-nil.
-func assertI2E2(inter *interfacetype, i fInterface, r *interface{}) bool {
+func assertI2E2(inter *interfacetype, i fInterface) (r interface{}, ok bool) {
 	ip := (*iface)(unsafe.Pointer(&i))
 	tab := ip.tab
 	if tab == nil {
-		return false
+		return
 	}
-	rp := (*eface)(unsafe.Pointer(r))
+	rp := (*eface)(unsafe.Pointer(&r))
 	rp._type = tab._type
 	rp.data = ip.data
-	return true
+	ok = true
+	return
 }
 
 func convI2I(inter *interfacetype, i fInterface) (r fInterface) {
@@ -299,14 +312,14 @@ func convI2I(inter *interfacetype, i fInterface) (r fInterface) {
 	return
 }
 
-func assertI2I(inter *interfacetype, i fInterface, r *fInterface) {
+func assertI2I(inter *interfacetype, i fInterface) (r fInterface) {
 	ip := (*iface)(unsafe.Pointer(&i))
 	tab := ip.tab
 	if tab == nil {
 		// explicit conversions require non-nil interface value.
 		panic(&TypeAssertionError{"", "", *inter.typ._string, ""})
 	}
-	rp := (*iface)(unsafe.Pointer(r))
+	rp := (*iface)(unsafe.Pointer(&r))
 	if tab.inter == inter {
 		rp.tab = tab
 		rp.data = ip.data
@@ -314,98 +327,84 @@ func assertI2I(inter *interfacetype, i fInterface, r *fInterface) {
 	}
 	rp.tab = getitab(inter, tab._type, false)
 	rp.data = ip.data
+	return
 }
 
-func assertI2I2(inter *interfacetype, i fInterface, r *fInterface) bool {
+func assertI2I2(inter *interfacetype, i fInterface) (r fInterface, ok bool) {
 	ip := (*iface)(unsafe.Pointer(&i))
 	tab := ip.tab
 	if tab == nil {
-		if r != nil {
-			*r = nil
-		}
-		return false
-	}
-	if tab.inter != inter {
-		tab = getitab(inter, tab._type, true)
-		if tab == nil {
-			if r != nil {
-				*r = nil
-			}
-			return false
-		}
+		return
 	}
-	if r != nil {
-		rp := (*iface)(unsafe.Pointer(r))
+	rp := (*iface)(unsafe.Pointer(&r))
+	if tab.inter == inter {
 		rp.tab = tab
 		rp.data = ip.data
+		ok = true
+		return
+	}
+	tab = getitab(inter, tab._type, true)
+	if tab == nil {
+		rp.data = nil
+		rp.tab = nil
+		ok = false
+		return
 	}
-	return true
+	rp.tab = tab
+	rp.data = ip.data
+	ok = true
+	return
 }
 
-func assertE2I(inter *interfacetype, e interface{}, r *fInterface) {
+func assertE2I(inter *interfacetype, e interface{}) (r fInterface) {
 	ep := (*eface)(unsafe.Pointer(&e))
 	t := ep._type
 	if t == nil {
 		// explicit conversions require non-nil interface value.
 		panic(&TypeAssertionError{"", "", *inter.typ._string, ""})
 	}
-	rp := (*iface)(unsafe.Pointer(r))
+	rp := (*iface)(unsafe.Pointer(&r))
 	rp.tab = getitab(inter, t, false)
 	rp.data = ep.data
+	return
 }
 
-var testingAssertE2I2GC bool
-
-func assertE2I2(inter *interfacetype, e interface{}, r *fInterface) bool {
-	if testingAssertE2I2GC {
-		GC()
-	}
+func assertE2I2(inter *interfacetype, e interface{}) (r fInterface, ok bool) {
 	ep := (*eface)(unsafe.Pointer(&e))
 	t := ep._type
 	if t == nil {
-		if r != nil {
-			*r = nil
-		}
-		return false
+		return
 	}
 	tab := getitab(inter, t, true)
 	if tab == nil {
-		if r != nil {
-			*r = nil
-		}
-		return false
-	}
-	if r != nil {
-		rp := (*iface)(unsafe.Pointer(r))
-		rp.tab = tab
-		rp.data = ep.data
+		return
 	}
-	return true
+	rp := (*iface)(unsafe.Pointer(&r))
+	rp.tab = tab
+	rp.data = ep.data
+	ok = true
+	return
 }
 
-//go:linkname reflect_ifaceE2I reflect.ifaceE2I
 func reflect_ifaceE2I(inter *interfacetype, e interface{}, dst *fInterface) {
-	assertE2I(inter, e, dst)
+	*dst = assertE2I(inter, e)
 }
 
-func assertE2E(inter *interfacetype, e interface{}, r *interface{}) {
+func assertE2E(inter *interfacetype, e interface{}) interface{} {
 	ep := (*eface)(unsafe.Pointer(&e))
 	if ep._type == nil {
 		// explicit conversions require non-nil interface value.
 		panic(&TypeAssertionError{"", "", *inter.typ._string, ""})
 	}
-	*r = e
+	return e
 }
 
-// The compiler ensures that r is non-nil.
-func assertE2E2(inter *interfacetype, e interface{}, r *interface{}) bool {
+func assertE2E2(inter *interfacetype, e interface{}) (interface{}, bool) {
 	ep := (*eface)(unsafe.Pointer(&e))
 	if ep._type == nil {
-		*r = nil
-		return false
+		return nil, false
 	}
-	*r = e
-	return true
+	return e, true
 }
 
 func ifacethash(i fInterface) uint32 {
@@ -433,3 +432,8 @@ func iterate_itabs(fn func(*itab)) {
 		}
 	}
 }
+
+func ifaceE2I2(inter *interfacetype, e interface{}, r *fInterface) (ok bool) {
+	*r, ok = assertE2I2(inter, e)
+	return
+}
diff --git a/src/runtime/iface_test.go b/src/runtime/iface_test.go
index 7f27baa..bca0ea0 100644
--- a/src/runtime/iface_test.go
+++ b/src/runtime/iface_test.go
@@ -5,7 +5,6 @@
 package runtime_test
 
 import (
-	"runtime"
 	"testing"
 )
 
@@ -37,50 +36,8 @@ var (
 	ts TS
 	tm TM
 	tl TL
-	ok bool
 )
 
-// Issue 9370
-func TestCmpIfaceConcreteAlloc(t *testing.T) {
-	if runtime.Compiler != "gc" {
-		t.Skip("skipping on non-gc compiler")
-	}
-
-	n := testing.AllocsPerRun(1, func() {
-		_ = e == ts
-		_ = i1 == ts
-		_ = e == 1
-	})
-
-	if n > 0 {
-		t.Fatalf("iface cmp allocs=%v; want 0", n)
-	}
-}
-
-func BenchmarkEqEfaceConcrete(b *testing.B) {
-	for i := 0; i < b.N; i++ {
-		_ = e == ts
-	}
-}
-
-func BenchmarkEqIfaceConcrete(b *testing.B) {
-	for i := 0; i < b.N; i++ {
-		_ = i1 == ts
-	}
-}
-
-func BenchmarkNeEfaceConcrete(b *testing.B) {
-	for i := 0; i < b.N; i++ {
-		_ = e != ts
-	}
-}
-
-func BenchmarkNeIfaceConcrete(b *testing.B) {
-	for i := 0; i < b.N; i++ {
-		_ = i1 != ts
-	}
-}
-
 func BenchmarkConvT2ESmall(b *testing.B) {
 	for i := 0; i < b.N; i++ {
 		e = ts
@@ -179,85 +136,3 @@ func BenchmarkAssertE2E(b *testing.B) {
 		e_ = e
 	}
 }
-
-func BenchmarkAssertE2T2(b *testing.B) {
-	e = tm
-	for i := 0; i < b.N; i++ {
-		tm, ok = e.(TM)
-	}
-}
-
-func BenchmarkAssertE2T2Blank(b *testing.B) {
-	e = tm
-	for i := 0; i < b.N; i++ {
-		_, ok = e.(TM)
-	}
-}
-
-func BenchmarkAssertI2E2(b *testing.B) {
-	i1 = tm
-	for i := 0; i < b.N; i++ {
-		e, ok = i1.(interface{})
-	}
-}
-
-func BenchmarkAssertI2E2Blank(b *testing.B) {
-	i1 = tm
-	for i := 0; i < b.N; i++ {
-		_, ok = i1.(interface{})
-	}
-}
-
-func BenchmarkAssertE2E2(b *testing.B) {
-	e = tm
-	for i := 0; i < b.N; i++ {
-		e_, ok = e.(interface{})
-	}
-}
-
-func BenchmarkAssertE2E2Blank(b *testing.B) {
-	e = tm
-	for i := 0; i < b.N; i++ {
-		_, ok = e.(interface{})
-	}
-}
-
-func TestNonEscapingConvT2E(t *testing.T) {
-	m := make(map[interface{}]bool)
-	m[42] = true
-	if !m[42] {
-		t.Fatalf("42 is not present in the map")
-	}
-	if m[0] {
-		t.Fatalf("0 is present in the map")
-	}
-
-	n := testing.AllocsPerRun(1000, func() {
-		if m[0] {
-			t.Fatalf("0 is present in the map")
-		}
-	})
-	if n != 0 {
-		t.Fatalf("want 0 allocs, got %v", n)
-	}
-}
-
-func TestNonEscapingConvT2I(t *testing.T) {
-	m := make(map[I1]bool)
-	m[TM(42)] = true
-	if !m[TM(42)] {
-		t.Fatalf("42 is not present in the map")
-	}
-	if m[TM(0)] {
-		t.Fatalf("0 is present in the map")
-	}
-
-	n := testing.AllocsPerRun(1000, func() {
-		if m[TM(0)] {
-			t.Fatalf("0 is present in the map")
-		}
-	})
-	if n != 0 {
-		t.Fatalf("want 0 allocs, got %v", n)
-	}
-}
diff --git a/src/runtime/lfstack.c b/src/runtime/lfstack.c
new file mode 100644
index 0000000..57e0af2
--- /dev/null
+++ b/src/runtime/lfstack.c
@@ -0,0 +1,87 @@
+// 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.
+// The following code runs only on g0 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)
+
+#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;
+	}
+}
+
+void
+runtime·lfstackpush_m(void)
+{
+	runtime·lfstackpush(g->m->ptrarg[0], g->m->ptrarg[1]);
+	g->m->ptrarg[0] = nil;
+	g->m->ptrarg[1] = nil;
+}
+
+void
+runtime·lfstackpop_m(void)
+{
+	g->m->ptrarg[0] = runtime·lfstackpop(g->m->ptrarg[0]);
+}
diff --git a/src/runtime/lfstack_test.go b/src/runtime/lfstack_test.go
index fb4b459..e518777 100644
--- a/src/runtime/lfstack_test.go
+++ b/src/runtime/lfstack_test.go
@@ -24,13 +24,9 @@ func toMyNode(node *LFNode) *MyNode {
 	return (*MyNode)(unsafe.Pointer(node))
 }
 
-var global interface{}
-
 func TestLFStack(t *testing.T) {
 	stack := new(uint64)
-	global = stack // force heap allocation
-
-	// Need to keep additional references to nodes, the stack is not all that type-safe.
+	// Need to keep additional referenfces to nodes, the stack is not all that type-safe.
 	var nodes []*MyNode
 
 	// Check the stack is initially empty.
@@ -125,7 +121,7 @@ func TestLFStackStress(t *testing.T) {
 			}
 			cnt++
 			sum2 += node.data
-			node.Next = 0
+			node.Next = nil
 		}
 	}
 	if cnt != K {
diff --git a/src/runtime/lock_futex.go b/src/runtime/lock_futex.go
index 768fd57..7259623 100644
--- a/src/runtime/lock_futex.go
+++ b/src/runtime/lock_futex.go
@@ -34,6 +34,9 @@ const (
 // Note that there can be spinning threads during all states - they do not
 // affect mutex's state.
 
+func futexsleep(addr *uint32, val uint32, ns int64)
+func futexwakeup(addr *uint32, cnt uint32)
+
 // We use the uintptr mutex.key and note.key as a uint32.
 func key32(p *uintptr) *uint32 {
 	return (*uint32)(unsafe.Pointer(p))
@@ -43,7 +46,7 @@ func lock(l *mutex) {
 	gp := getg()
 
 	if gp.m.locks < 0 {
-		throw("runtime·lock: lock count")
+		gothrow("runtime·lock: lock count")
 	}
 	gp.m.locks++
 
@@ -102,7 +105,7 @@ func lock(l *mutex) {
 func unlock(l *mutex) {
 	v := xchg(key32(&l.key), mutex_unlocked)
 	if v == mutex_unlocked {
-		throw("unlock of unlocked lock")
+		gothrow("unlock of unlocked lock")
 	}
 	if v == mutex_sleeping {
 		futexwakeup(key32(&l.key), 1)
@@ -111,7 +114,7 @@ func unlock(l *mutex) {
 	gp := getg()
 	gp.m.locks--
 	if gp.m.locks < 0 {
-		throw("runtime·unlock: lock count")
+		gothrow("runtime·unlock: lock count")
 	}
 	if gp.m.locks == 0 && gp.preempt { // restore the preemption request in case we've cleared it in newstack
 		gp.stackguard0 = stackPreempt
@@ -127,7 +130,7 @@ func notewakeup(n *note) {
 	old := xchg(key32(&n.key), 1)
 	if old != 0 {
 		print("notewakeup - double wakeup (", old, ")\n")
-		throw("notewakeup - double wakeup")
+		gothrow("notewakeup - double wakeup")
 	}
 	futexwakeup(key32(&n.key), 1)
 }
@@ -135,7 +138,7 @@ func notewakeup(n *note) {
 func notesleep(n *note) {
 	gp := getg()
 	if gp != gp.m.g0 {
-		throw("notesleep not on g0")
+		gothrow("notesleep not on g0")
 	}
 	for atomicload(key32(&n.key)) == 0 {
 		gp.m.blocked = true
@@ -144,11 +147,7 @@ func notesleep(n *note) {
 	}
 }
 
-// May run with m.p==nil if called from notetsleep, so write barriers
-// are not allowed.
-//
 //go:nosplit
-//go:nowritebarrier
 func notetsleep_internal(n *note, ns int64) bool {
 	gp := getg()
 
@@ -184,8 +183,8 @@ func notetsleep_internal(n *note, ns int64) bool {
 
 func notetsleep(n *note, ns int64) bool {
 	gp := getg()
-	if gp != gp.m.g0 && gp.m.preemptoff != "" {
-		throw("notetsleep not on g0")
+	if gp != gp.m.g0 && gp.m.gcing == 0 {
+		gothrow("notetsleep not on g0")
 	}
 
 	return notetsleep_internal(n, ns)
@@ -196,11 +195,11 @@ func notetsleep(n *note, ns int64) bool {
 func notetsleepg(n *note, ns int64) bool {
 	gp := getg()
 	if gp == gp.m.g0 {
-		throw("notetsleepg on g0")
+		gothrow("notetsleepg on g0")
 	}
 
-	entersyscallblock(0)
+	entersyscallblock()
 	ok := notetsleep_internal(n, ns)
-	exitsyscall(0)
+	exitsyscall()
 	return ok
 }
diff --git a/src/runtime/lock_sema.go b/src/runtime/lock_sema.go
index d9d91c9..d136b82 100644
--- a/src/runtime/lock_sema.go
+++ b/src/runtime/lock_sema.go
@@ -31,10 +31,14 @@ const (
 	passive_spin    = 1
 )
 
+func semacreate() uintptr
+func semasleep(int64) int32
+func semawakeup(mp *m)
+
 func lock(l *mutex) {
 	gp := getg()
 	if gp.m.locks < 0 {
-		throw("runtime·lock: lock count")
+		gothrow("runtime·lock: lock count")
 	}
 	gp.m.locks++
 
@@ -72,7 +76,7 @@ Loop:
 			// for this lock, chained through m->nextwaitm.
 			// Queue this M.
 			for {
-				gp.m.nextwaitm = v &^ locked
+				gp.m.nextwaitm = (*m)((unsafe.Pointer)(v &^ locked))
 				if casuintptr(&l.key, v, uintptr(unsafe.Pointer(gp.m))|locked) {
 					break
 				}
@@ -90,8 +94,6 @@ Loop:
 	}
 }
 
-//go:nowritebarrier
-// We might not be holding a p in this code.
 func unlock(l *mutex) {
 	gp := getg()
 	var mp *m
@@ -105,7 +107,7 @@ func unlock(l *mutex) {
 			// Other M's are waiting for the lock.
 			// Dequeue an M.
 			mp = (*m)((unsafe.Pointer)(v &^ locked))
-			if casuintptr(&l.key, v, mp.nextwaitm) {
+			if casuintptr(&l.key, v, uintptr(unsafe.Pointer(mp.nextwaitm))) {
 				// Dequeued an M.  Wake it.
 				semawakeup(mp)
 				break
@@ -114,7 +116,7 @@ func unlock(l *mutex) {
 	}
 	gp.m.locks--
 	if gp.m.locks < 0 {
-		throw("runtime·unlock: lock count")
+		gothrow("runtime·unlock: lock count")
 	}
 	if gp.m.locks == 0 && gp.preempt { // restore the preemption request in case we've cleared it in newstack
 		gp.stackguard0 = stackPreempt
@@ -142,7 +144,7 @@ func notewakeup(n *note) {
 		// Nothing was waiting. Done.
 	case v == locked:
 		// Two notewakeups!  Not allowed.
-		throw("notewakeup - double wakeup")
+		gothrow("notewakeup - double wakeup")
 	default:
 		// Must be the waiting m.  Wake it up.
 		semawakeup((*m)(unsafe.Pointer(v)))
@@ -152,7 +154,7 @@ func notewakeup(n *note) {
 func notesleep(n *note) {
 	gp := getg()
 	if gp != gp.m.g0 {
-		throw("notesleep not on g0")
+		gothrow("notesleep not on g0")
 	}
 	if gp.m.waitsema == 0 {
 		gp.m.waitsema = semacreate()
@@ -160,7 +162,7 @@ func notesleep(n *note) {
 	if !casuintptr(&n.key, 0, uintptr(unsafe.Pointer(gp.m))) {
 		// Must be locked (got wakeup).
 		if n.key != locked {
-			throw("notesleep - waitm out of sync")
+			gothrow("notesleep - waitm out of sync")
 		}
 		return
 	}
@@ -182,7 +184,7 @@ func notetsleep_internal(n *note, ns int64, gp *g, deadline int64) bool {
 	if !casuintptr(&n.key, 0, uintptr(unsafe.Pointer(gp.m))) {
 		// Must be locked (got wakeup).
 		if n.key != locked {
-			throw("notetsleep - waitm out of sync")
+			gothrow("notetsleep - waitm out of sync")
 		}
 		return true
 	}
@@ -230,20 +232,20 @@ func notetsleep_internal(n *note, ns int64, gp *g, deadline int64) bool {
 			// Grab it to avoid getting out of sync.
 			gp.m.blocked = true
 			if semasleep(-1) < 0 {
-				throw("runtime: unable to acquire - semaphore out of sync")
+				gothrow("runtime: unable to acquire - semaphore out of sync")
 			}
 			gp.m.blocked = false
 			return true
 		default:
-			throw("runtime: unexpected waitm - semaphore out of sync")
+			gothrow("runtime: unexpected waitm - semaphore out of sync")
 		}
 	}
 }
 
 func notetsleep(n *note, ns int64) bool {
 	gp := getg()
-	if gp != gp.m.g0 && gp.m.preemptoff != "" {
-		throw("notetsleep not on g0")
+	if gp != gp.m.g0 && gp.m.gcing == 0 {
+		gothrow("notetsleep not on g0")
 	}
 	if gp.m.waitsema == 0 {
 		gp.m.waitsema = semacreate()
@@ -256,13 +258,13 @@ func notetsleep(n *note, ns int64) bool {
 func notetsleepg(n *note, ns int64) bool {
 	gp := getg()
 	if gp == gp.m.g0 {
-		throw("notetsleepg on g0")
+		gothrow("notetsleepg on g0")
 	}
 	if gp.m.waitsema == 0 {
 		gp.m.waitsema = semacreate()
 	}
-	entersyscallblock(0)
+	entersyscallblock()
 	ok := notetsleep_internal(n, ns, nil, 0)
-	exitsyscall(0)
+	exitsyscall()
 	return ok
 }
diff --git a/src/runtime/malloc.c b/src/runtime/malloc.c
new file mode 100644
index 0000000..b79c30b
--- /dev/null
+++ b/src/runtime/malloc.c
@@ -0,0 +1,396 @@
+// 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.
+
+// See malloc.h for overview.
+//
+// TODO(rsc): double-check stats.
+
+#include "runtime.h"
+#include "arch_GOARCH.h"
+#include "malloc.h"
+#include "type.h"
+#include "typekind.h"
+#include "race.h"
+#include "stack.h"
+#include "textflag.h"
+
+// Mark mheap as 'no pointers', it does not contain interesting pointers but occupies ~45K.
+#pragma dataflag NOPTR
+MHeap runtime·mheap;
+#pragma dataflag NOPTR
+MStats runtime·memstats;
+
+int32
+runtime·mlookup(void *v, byte **base, uintptr *size, MSpan **sp)
+{
+	uintptr n, i;
+	byte *p;
+	MSpan *s;
+
+	g->m->mcache->local_nlookup++;
+	if (sizeof(void*) == 4 && g->m->mcache->local_nlookup >= (1<<30)) {
+		// purge cache stats to prevent overflow
+		runtime·lock(&runtime·mheap.lock);
+		runtime·purgecachedstats(g->m->mcache);
+		runtime·unlock(&runtime·mheap.lock);
+	}
+
+	s = runtime·MHeap_LookupMaybe(&runtime·mheap, v);
+	if(sp)
+		*sp = s;
+	if(s == nil) {
+		if(base)
+			*base = nil;
+		if(size)
+			*size = 0;
+		return 0;
+	}
+
+	p = (byte*)((uintptr)s->start<<PageShift);
+	if(s->sizeclass == 0) {
+		// Large object.
+		if(base)
+			*base = p;
+		if(size)
+			*size = s->npages<<PageShift;
+		return 1;
+	}
+
+	n = s->elemsize;
+	if(base) {
+		i = ((byte*)v - p)/n;
+		*base = p + i*n;
+	}
+	if(size)
+		*size = n;
+
+	return 1;
+}
+
+#pragma textflag NOSPLIT
+void
+runtime·purgecachedstats(MCache *c)
+{
+	MHeap *h;
+	int32 i;
+
+	// Protected by either heap or GC lock.
+	h = &runtime·mheap;
+	mstats.heap_alloc += c->local_cachealloc;
+	c->local_cachealloc = 0;
+	mstats.tinyallocs += c->local_tinyallocs;
+	c->local_tinyallocs = 0;
+	mstats.nlookup += c->local_nlookup;
+	c->local_nlookup = 0;
+	h->largefree += c->local_largefree;
+	c->local_largefree = 0;
+	h->nlargefree += c->local_nlargefree;
+	c->local_nlargefree = 0;
+	for(i=0; i<nelem(c->local_nsmallfree); i++) {
+		h->nsmallfree[i] += c->local_nsmallfree[i];
+		c->local_nsmallfree[i] = 0;
+	}
+}
+
+// Size of the trailing by_size array differs between Go and C,
+// and all data after by_size is local to C, not exported to Go.
+// 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 = offsetof(MStats, by_size[61]);
+
+#define MaxArena32 (2U<<30)
+
+// For use by Go. If it were a C enum it would be made available automatically,
+// but the value of MaxMem is too large for enum.
+uintptr runtime·maxmem = MaxMem;
+
+void
+runtime·mallocinit(void)
+{
+	byte *p, *p1;
+	uintptr arena_size, bitmap_size, spans_size, p_size;
+	extern byte runtime·end[];
+	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.
+	limit = 0;
+
+	// Set up the allocation arena, a contiguous area of memory where
+	// allocated data will be found.  The arena begins with a bitmap large
+	// enough to hold 4 bits per allocated word.
+	if(sizeof(void*) == 8 && (limit == 0 || limit > (1<<30))) {
+		// On a 64-bit machine, allocate from a single contiguous reservation.
+		// 128 GB (MaxMem) should be big enough for now.
+		//
+		// The code will work with the reservation at any address, but ask
+		// SysReserve to use 0x0000XXc000000000 if possible (XX=00...7f).
+		// Allocating a 128 GB region takes away 37 bits, and the amd64
+		// doesn't let us choose the top 17 bits, so that leaves the 11 bits
+		// in the middle of 0x00c0 for us to choose.  Choosing 0x00c0 means
+		// that the valid memory addresses will begin 0x00c0, 0x00c1, ..., 0x00df.
+		// In little-endian, that's c0 00, c1 00, ..., df 00. None of those are valid
+		// UTF-8 sequences, and they are otherwise as far away from 
+		// ff (likely a common byte) as possible.  If that fails, we try other 0xXXc0
+		// addresses.  An earlier attempt to use 0x11f8 caused out of memory errors
+		// on OS X during thread allocations.  0x00c0 causes conflicts with
+		// AddressSanitizer which reserves all memory up to 0x0100.
+		// These choices are both for debuggability and to reduce the
+		// odds of the conservative garbage collector not collecting memory
+		// because some non-pointer block of memory had a bit pattern
+		// that matched a memory address.
+		//
+		// Actually we reserve 136 GB (because the bitmap ends up being 8 GB)
+		// but it hardly matters: e0 00 is not valid UTF-8 either.
+		//
+		// If this fails we fall back to the 32 bit memory mechanism
+		arena_size = MaxMem;
+		bitmap_size = arena_size / (sizeof(void*)*8/4);
+		spans_size = arena_size / PageSize * sizeof(runtime·mheap.spans[0]);
+		spans_size = ROUND(spans_size, PageSize);
+		for(i = 0; i <= 0x7f; i++) {
+			p = (void*)(i<<40 | 0x00c0ULL<<32);
+			p_size = bitmap_size + spans_size + arena_size + PageSize;
+			p = runtime·SysReserve(p, p_size, &reserved);
+			if(p != nil)
+				break;
+		}
+	}
+	if (p == nil) {
+		// On a 32-bit machine, we can't typically get away
+		// with a giant virtual address space reservation.
+		// Instead we map the memory information bitmap
+		// immediately after the data segment, large enough
+		// to handle another 2GB of mappings (256 MB),
+		// along with a reservation for another 512 MB of memory.
+		// When that gets used up, we'll start asking the kernel
+		// for any memory anywhere and hope it's in the 2GB
+		// following the bitmap (presumably the executable begins
+		// near the bottom of memory, so we'll have to use up
+		// most of memory before the kernel resorts to giving out
+		// memory before the beginning of the text segment).
+		//
+		// Alternatively we could reserve 512 MB bitmap, enough
+		// for 4GB of mappings, and then accept any memory the
+		// kernel threw at us, but normally that's a waste of 512 MB
+		// of address space, which is probably too much in a 32-bit world.
+		bitmap_size = MaxArena32 / (sizeof(void*)*8/4);
+		arena_size = 512<<20;
+		spans_size = MaxArena32 / PageSize * sizeof(runtime·mheap.spans[0]);
+		if(limit > 0 && arena_size+bitmap_size+spans_size > limit) {
+			bitmap_size = (limit / 9) & ~((1<<PageShift) - 1);
+			arena_size = bitmap_size * 8;
+			spans_size = arena_size / PageSize * sizeof(runtime·mheap.spans[0]);
+		}
+		spans_size = ROUND(spans_size, PageSize);
+
+		// SysReserve treats the address we ask for, end, as a hint,
+		// not as an absolute requirement.  If we ask for the end
+		// of the data segment but the operating system requires
+		// a little more space before we can start allocating, it will
+		// give out a slightly higher pointer.  Except QEMU, which
+		// is buggy, as usual: it won't adjust the pointer upward.
+		// 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.
+		p = (byte*)ROUND((uintptr)runtime·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");
+	}
+
+	// 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 = 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);
+	g->m->mcache = runtime·allocmcache();
+}
+
+void*
+runtime·MHeap_SysAlloc(MHeap *h, uintptr n)
+{
+	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;
+
+		p_size = ROUND(n + PageSize, 256<<20);
+		new_end = h->arena_end + p_size;
+		if(new_end <= h->arena_start + MaxArena32) {
+			// 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, 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(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_size = ROUND(n, PageSize) + PageSize;
+	p = runtime·sysAlloc(p_size, &mstats.heap_sys);
+	if(p == nil)
+		return nil;
+
+	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, 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(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;
+}
+
+void
+runtime·setFinalizer_m(void)
+{
+	FuncVal *fn;
+	void *arg;
+	uintptr nret;
+	Type *fint;
+	PtrType *ot;
+
+	fn = g->m->ptrarg[0];
+	arg = g->m->ptrarg[1];
+	nret = g->m->scalararg[0];
+	fint = g->m->ptrarg[2];
+	ot = g->m->ptrarg[3];
+	g->m->ptrarg[0] = nil;
+	g->m->ptrarg[1] = nil;
+	g->m->ptrarg[2] = nil;
+	g->m->ptrarg[3] = nil;
+
+	g->m->scalararg[0] = runtime·addfinalizer(arg, fn, nret, fint, ot);
+}
+
+void
+runtime·removeFinalizer_m(void)
+{
+	void *p;
+
+	p = g->m->ptrarg[0];
+	g->m->ptrarg[0] = nil;
+	runtime·removefinalizer(p);
+}
+
+// mcallable cache refill
+void 
+runtime·mcacheRefill_m(void)
+{
+	runtime·MCache_Refill(g->m->mcache, (int32)g->m->scalararg[0]);
+}
+
+void
+runtime·largeAlloc_m(void)
+{
+	uintptr npages, size;
+	MSpan *s;
+	void *v;
+	int32 flag;
+
+	//runtime·printf("largeAlloc size=%D\n", g->m->scalararg[0]);
+	// Allocate directly from heap.
+	size = g->m->scalararg[0];
+	flag = (int32)g->m->scalararg[1];
+	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;
+	v = (void*)(s->start << PageShift);
+	// setup for mark sweep
+	runtime·markspan(v, 0, 0, true);
+	g->m->ptrarg[0] = s;
+}
diff --git a/src/runtime/malloc.go b/src/runtime/malloc.go
index 353f840..1170449 100644
--- a/src/runtime/malloc.go
+++ b/src/runtime/malloc.go
@@ -2,87 +2,11 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// Memory allocator, based on tcmalloc.
-// http://goog-perftools.sourceforge.net/doc/tcmalloc.html
-
-// The main allocator works in runs of pages.
-// Small allocation sizes (up to and including 32 kB) are
-// rounded to one of about 100 size classes, each of which
-// has its own free list of objects of exactly that size.
-// Any free page of memory can be split into a set of objects
-// of one size class, which are then managed using free list
-// allocators.
-//
-// The allocator's data structures are:
-//
-//	FixAlloc: a free-list allocator for fixed-size objects,
-//		used to manage storage used by the allocator.
-//	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-P) cache for small objects.
-//	MStats: allocation statistics.
-//
-// Allocating a small object proceeds up a hierarchy of caches:
-//
-//	1. Round the size up to one of the small size classes
-//	   and look in the corresponding MCache free list.
-//	   If the list is not empty, allocate an object from it.
-//	   This can all be done without acquiring a lock.
-//
-//	2. If the MCache free list is empty, replenish it by
-//	   taking a bunch of objects from the MCentral free list.
-//	   Moving a bunch amortizes the cost of acquiring the MCentral lock.
-//
-//	3. If the MCentral free list is empty, replenish it by
-//	   allocating a run of pages from the MHeap and then
-//	   chopping that memory into objects of the given size.
-//	   Allocating many objects amortizes the cost of locking
-//	   the heap.
-//
-//	4. If the MHeap is empty or has no page runs large enough,
-//	   allocate a new group of pages (at least 1MB) from the
-//	   operating system.  Allocating a large run of pages
-//	   amortizes the cost of talking to the operating system.
-//
-// Freeing a small object proceeds up the same hierarchy:
-//
-//	1. Look up the size class for the object and add it to
-//	   the MCache free list.
-//
-//	2. If the MCache free list is too long or the MCache has
-//	   too much memory, return some to the MCentral free lists.
-//
-//	3. If all the objects in a given span have returned to
-//	   the MCentral list, return that span to the page heap.
-//
-//	4. If the heap has too much memory, return some to the
-//	   operating system.
-//
-//	TODO(rsc): Step 4 is not implemented.
-//
-// Allocating and freeing a large object uses the page heap
-// directly, bypassing the MCache and MCentral free lists.
-//
-// 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.  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
-//	   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.
-//
-// This code was written with an eye toward translating to Go
-// in the future.  Methods have the form Type_Method(Type *t, ...).
-
 package runtime
 
-import "unsafe"
+import (
+	"unsafe"
+)
 
 const (
 	debugMalloc = false
@@ -98,427 +22,53 @@ const (
 	pageSize  = _PageSize
 	pageMask  = _PageMask
 
-	mSpanInUse = _MSpanInUse
-
-	concurrentSweep = _ConcurrentSweep
-)
+	bitsPerPointer  = _BitsPerPointer
+	bitsMask        = _BitsMask
+	pointersPerByte = _PointersPerByte
+	maxGCMask       = _MaxGCMask
+	bitsDead        = _BitsDead
+	bitsPointer     = _BitsPointer
 
-const (
-	_PageShift = 13
-	_PageSize  = 1 << _PageShift
-	_PageMask  = _PageSize - 1
-)
+	mSpanInUse = _MSpanInUse
 
-const (
-	// _64bit = 1 on 64-bit systems, 0 on 32-bit systems
-	_64bit = 1 << (^uintptr(0) >> 63) / 2
-
-	// Computed constant.  The definition of MaxSmallSize and the
-	// algorithm in msize.go produces some number of different allocation
-	// 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 = 67
-
-	// Tunable constants.
-	_MaxSmallSize = 32 << 10
-
-	// Tiny allocator parameters, see "Tiny allocator" comment in malloc.go.
-	_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
-
-	// Per-P, per order stack segment cache size.
-	_StackCacheSize = 32 * 1024
-
-	// Number of orders that get caching.  Order 0 is FixedStack
-	// and each successive order is twice as large.
-	// We want to cache 2KB, 4KB, 8KB, and 16KB stacks.  Larger stacks
-	// will be allocated directly.
-	// Since FixedStack is different on different systems, we
-	// must vary NumStackOrders to keep the same maximum cached size.
-	//   OS               | FixedStack | NumStackOrders
-	//   -----------------+------------+---------------
-	//   linux/darwin/bsd | 2KB        | 4
-	//   windows/32       | 4KB        | 3
-	//   windows/64       | 8KB        | 2
-	//   plan9            | 4KB        | 3
-	_NumStackOrders = 4 - ptrSize/4*goos_windows - 1*goos_plan9
-
-	// Number of bits in page to span calculations (4k pages).
-	// On Windows 64-bit we limit the arena to 32GB or 35 bits.
-	// Windows counts memory used by page table into committed memory
-	// of the process, so we can't reserve too much memory.
-	// See https://golang.org/issue/5402 and https://golang.org/issue/5236.
-	// On other 64-bit platforms, we limit the arena to 512GB, or 39 bits.
-	// On 32-bit, we don't bother limiting anything, so we use the full 32-bit address.
-	// On Darwin/arm64, we cannot reserve more than ~5GB of virtual memory,
-	// but as most devices have less than 4GB of physical memory anyway, we
-	// try to be conservative here, and only ask for a 2GB heap.
-	_MHeapMap_TotalBits = (_64bit*goos_windows)*35 + (_64bit*(1-goos_windows)*(1-goos_darwin*goarch_arm64))*39 + goos_darwin*goarch_arm64*31 + (1-_64bit)*32
-	_MHeapMap_Bits      = _MHeapMap_TotalBits - _PageShift
-
-	_MaxMem = uintptr(1<<_MHeapMap_TotalBits - 1)
-
-	// Max number of threads to run garbage collection.
-	// 2, 3, and 4 are all plausible maximums depending
-	// on the hardware details of the machine.  The garbage
-	// collector scales well to 32 cpus.
-	_MaxGcproc = 32
+	concurrentSweep = _ConcurrentSweep != 0
 )
 
 // Page number (address>>pageShift)
 type pageID uintptr
 
-const _MaxArena32 = 2 << 30
-
-// OS-defined helpers:
-//
-// 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
-// for other purposes.
-// SysUsed notifies the operating system that the contents
-// of the memory region are needed again.
-//
-// SysFree returns it unconditionally; this is only used if
-// an out-of-memory error has been detected midway through
-// an allocation.  It is okay if SysFree is a no-op.
-//
-// 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.  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.
-
-func mallocinit() {
-	initSizes()
-
-	if class_to_size[_TinySizeClass] != _TinySize {
-		throw("bad TinySizeClass")
-	}
-
-	var p, bitmapSize, spansSize, pSize, limit uintptr
-	var reserved bool
-
-	// limit = runtime.memlimit();
-	// See https://golang.org/issue/5049
-	// TODO(rsc): Fix after 1.1.
-	limit = 0
-
-	// Set up the allocation arena, a contiguous area of memory where
-	// allocated data will be found.  The arena begins with a bitmap large
-	// enough to hold 4 bits per allocated word.
-	if ptrSize == 8 && (limit == 0 || limit > 1<<30) {
-		// On a 64-bit machine, allocate from a single contiguous reservation.
-		// 512 GB (MaxMem) should be big enough for now.
-		//
-		// The code will work with the reservation at any address, but ask
-		// SysReserve to use 0x0000XXc000000000 if possible (XX=00...7f).
-		// Allocating a 512 GB region takes away 39 bits, and the amd64
-		// doesn't let us choose the top 17 bits, so that leaves the 9 bits
-		// in the middle of 0x00c0 for us to choose.  Choosing 0x00c0 means
-		// that the valid memory addresses will begin 0x00c0, 0x00c1, ..., 0x00df.
-		// In little-endian, that's c0 00, c1 00, ..., df 00. None of those are valid
-		// UTF-8 sequences, and they are otherwise as far away from
-		// ff (likely a common byte) as possible.  If that fails, we try other 0xXXc0
-		// addresses.  An earlier attempt to use 0x11f8 caused out of memory errors
-		// on OS X during thread allocations.  0x00c0 causes conflicts with
-		// AddressSanitizer which reserves all memory up to 0x0100.
-		// These choices are both for debuggability and to reduce the
-		// odds of a conservative garbage collector (as is still used in gccgo)
-		// not collecting memory because some non-pointer block of memory
-		// had a bit pattern that matched a memory address.
-		//
-		// Actually we reserve 544 GB (because the bitmap ends up being 32 GB)
-		// but it hardly matters: e0 00 is not valid UTF-8 either.
-		//
-		// If this fails we fall back to the 32 bit memory mechanism
-		//
-		// However, on arm64, we ignore all this advice above and slam the
-		// allocation at 0x40 << 32 because when using 4k pages with 3-level
-		// translation buffers, the user address space is limited to 39 bits
-		// On darwin/arm64, the address space is even smaller.
-		arenaSize := round(_MaxMem, _PageSize)
-		bitmapSize = arenaSize / (ptrSize * 8 / 4)
-		spansSize = arenaSize / _PageSize * ptrSize
-		spansSize = round(spansSize, _PageSize)
-		for i := 0; i <= 0x7f; i++ {
-			switch {
-			case GOARCH == "arm64" && GOOS == "darwin":
-				p = uintptr(i)<<40 | uintptrMask&(0x0013<<28)
-			case GOARCH == "arm64":
-				p = uintptr(i)<<40 | uintptrMask&(0x0040<<32)
-			default:
-				p = uintptr(i)<<40 | uintptrMask&(0x00c0<<32)
-			}
-			pSize = bitmapSize + spansSize + arenaSize + _PageSize
-			p = uintptr(sysReserve(unsafe.Pointer(p), pSize, &reserved))
-			if p != 0 {
-				break
-			}
-		}
-	}
-
-	if p == 0 {
-		// On a 32-bit machine, we can't typically get away
-		// with a giant virtual address space reservation.
-		// Instead we map the memory information bitmap
-		// immediately after the data segment, large enough
-		// to handle another 2GB of mappings (256 MB),
-		// along with a reservation for an initial arena.
-		// When that gets used up, we'll start asking the kernel
-		// for any memory anywhere and hope it's in the 2GB
-		// following the bitmap (presumably the executable begins
-		// near the bottom of memory, so we'll have to use up
-		// most of memory before the kernel resorts to giving out
-		// memory before the beginning of the text segment).
-		//
-		// Alternatively we could reserve 512 MB bitmap, enough
-		// for 4GB of mappings, and then accept any memory the
-		// kernel threw at us, but normally that's a waste of 512 MB
-		// of address space, which is probably too much in a 32-bit world.
-
-		// If we fail to allocate, try again with a smaller arena.
-		// This is necessary on Android L where we share a process
-		// with ART, which reserves virtual memory aggressively.
-		arenaSizes := []uintptr{
-			512 << 20,
-			256 << 20,
-			128 << 20,
-		}
-
-		for _, arenaSize := range arenaSizes {
-			bitmapSize = _MaxArena32 / (ptrSize * 8 / 4)
-			spansSize = _MaxArena32 / _PageSize * ptrSize
-			if limit > 0 && arenaSize+bitmapSize+spansSize > limit {
-				bitmapSize = (limit / 9) &^ ((1 << _PageShift) - 1)
-				arenaSize = bitmapSize * 8
-				spansSize = arenaSize / _PageSize * ptrSize
-			}
-			spansSize = round(spansSize, _PageSize)
-
-			// SysReserve treats the address we ask for, end, as a hint,
-			// not as an absolute requirement.  If we ask for the end
-			// of the data segment but the operating system requires
-			// a little more space before we can start allocating, it will
-			// give out a slightly higher pointer.  Except QEMU, which
-			// is buggy, as usual: it won't adjust the pointer upward.
-			// 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.
-			p = round(firstmoduledata.end+(1<<18), 1<<20)
-			pSize = bitmapSize + spansSize + arenaSize + _PageSize
-			p = uintptr(sysReserve(unsafe.Pointer(p), pSize, &reserved))
-			if p != 0 {
-				break
-			}
-		}
-		if p == 0 {
-			throw("runtime: cannot reserve arena virtual address space")
-		}
-	}
-
-	// 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 := round(p, _PageSize)
-
-	mheap_.spans = (**mspan)(unsafe.Pointer(p1))
-	mheap_.bitmap = p1 + spansSize
-	mheap_.arena_start = p1 + (spansSize + bitmapSize)
-	mheap_.arena_used = mheap_.arena_start
-	mheap_.arena_end = p + pSize
-	mheap_.arena_reserved = reserved
-
-	if mheap_.arena_start&(_PageSize-1) != 0 {
-		println("bad pagesize", hex(p), hex(p1), hex(spansSize), hex(bitmapSize), hex(_PageSize), "start", hex(mheap_.arena_start))
-		throw("misrounded allocation in mallocinit")
-	}
-
-	// Initialize the rest of the allocator.
-	mHeap_Init(&mheap_, spansSize)
-	_g_ := getg()
-	_g_.m.mcache = allocmcache()
-}
-
-// sysReserveHigh reserves space somewhere high in the address space.
-// sysReserve doesn't actually reserve the full amount requested on
-// 64-bit systems, because of problems with ulimit. Instead it checks
-// that it can get the first 64 kB and assumes it can grab the rest as
-// needed. This doesn't work well with the "let the kernel pick an address"
-// mode, so don't do that. Pick a high address instead.
-func sysReserveHigh(n uintptr, reserved *bool) unsafe.Pointer {
-	if ptrSize == 4 {
-		return sysReserve(nil, n, reserved)
-	}
-
-	for i := 0; i <= 0x7f; i++ {
-		p := uintptr(i)<<40 | uintptrMask&(0x00c0<<32)
-		*reserved = false
-		p = uintptr(sysReserve(unsafe.Pointer(p), n, reserved))
-		if p != 0 {
-			return unsafe.Pointer(p)
-		}
-	}
-
-	return sysReserve(nil, n, reserved)
-}
-
-func mHeap_SysAlloc(h *mheap, n uintptr) unsafe.Pointer {
-	if n > uintptr(h.arena_end)-uintptr(h.arena_used) {
-		// We are in 32-bit mode, maybe we didn't use all possible address space yet.
-		// Reserve some more space.
-		p_size := round(n+_PageSize, 256<<20)
-		new_end := h.arena_end + p_size
-		if new_end <= h.arena_start+_MaxArena32 {
-			// TODO: It would be bad if part of the arena
-			// is reserved and part is not.
-			var reserved bool
-			p := uintptr(sysReserve((unsafe.Pointer)(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
-				used := p + (-uintptr(p) & (_PageSize - 1))
-				mHeap_MapBits(h, used)
-				mHeap_MapSpans(h, used)
-				h.arena_used = used
-				h.arena_reserved = reserved
-			} else {
-				var stat uint64
-				sysFree((unsafe.Pointer)(p), p_size, &stat)
-			}
-		}
-	}
-
-	if n <= uintptr(h.arena_end)-uintptr(h.arena_used) {
-		// Keep taking from our reservation.
-		p := h.arena_used
-		sysMap((unsafe.Pointer)(p), n, h.arena_reserved, &memstats.heap_sys)
-		mHeap_MapBits(h, p+n)
-		mHeap_MapSpans(h, p+n)
-		h.arena_used = p + n
-		if raceenabled {
-			racemapshadow((unsafe.Pointer)(p), n)
-		}
-
-		if uintptr(p)&(_PageSize-1) != 0 {
-			throw("misrounded allocation in MHeap_SysAlloc")
-		}
-		return (unsafe.Pointer)(p)
-	}
-
-	// If using 64-bit, our reservation is all we have.
-	if uintptr(h.arena_end)-uintptr(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_size := round(n, _PageSize) + _PageSize
-	p := uintptr(sysAlloc(p_size, &memstats.heap_sys))
-	if p == 0 {
-		return nil
-	}
-
-	if p < h.arena_start || uintptr(p)+p_size-uintptr(h.arena_start) >= _MaxArena32 {
-		print("runtime: memory allocated by OS (", p, ") not in usable range [", hex(h.arena_start), ",", hex(h.arena_start+_MaxArena32), ")\n")
-		sysFree((unsafe.Pointer)(p), p_size, &memstats.heap_sys)
-		return nil
-	}
-
-	p_end := p + p_size
-	p += -p & (_PageSize - 1)
-	if uintptr(p)+n > uintptr(h.arena_used) {
-		mHeap_MapBits(h, p+n)
-		mHeap_MapSpans(h, p+n)
-		h.arena_used = p + n
-		if p_end > h.arena_end {
-			h.arena_end = p_end
-		}
-		if raceenabled {
-			racemapshadow((unsafe.Pointer)(p), n)
-		}
-	}
-
-	if uintptr(p)&(_PageSize-1) != 0 {
-		throw("misrounded allocation in MHeap_SysAlloc")
-	}
-	return (unsafe.Pointer)(p)
-}
-
 // base address for all 0-byte allocations
 var zerobase uintptr
 
-const (
-	// flags to malloc
-	_FlagNoScan = 1 << 0 // GC doesn't have to scan object
-	_FlagNoZero = 1 << 1 // don't zero memory
-)
-
 // Allocate an object of size bytes.
 // Small objects are allocated from the per-P cache's free lists.
 // Large objects (> 32 kB) are allocated straight from the heap.
 func mallocgc(size uintptr, typ *_type, flags uint32) unsafe.Pointer {
-	if gcphase == _GCmarktermination {
-		throw("mallocgc called with gcphase == _GCmarktermination")
-	}
-
 	if size == 0 {
 		return unsafe.Pointer(&zerobase)
 	}
+	size0 := size
 
 	if flags&flagNoScan == 0 && typ == nil {
-		throw("malloc missing type")
-	}
-
-	if debug.sbrk != 0 {
-		align := uintptr(16)
-		if typ != nil {
-			align = uintptr(typ.align)
+		gothrow("malloc missing type")
+	}
+
+	// This function must be atomic wrt GC, but for performance reasons
+	// we don't acquirem/releasem on fast path. The code below does not have
+	// split stack checks, so it can't be preempted by GC.
+	// Functions like roundup/add are inlined. And onM/racemalloc are nosplit.
+	// If debugMalloc = true, these assumptions are checked below.
+	if debugMalloc {
+		mp := acquirem()
+		if mp.mallocing != 0 {
+			gothrow("malloc deadlock")
+		}
+		mp.mallocing = 1
+		if mp.curg != nil {
+			mp.curg.stackguard0 = ^uintptr(0xfff) | 0xbad
 		}
-		return persistentalloc(size, align, &memstats.other_sys)
-	}
-
-	// Set mp.mallocing to keep from being preempted by GC.
-	mp := acquirem()
-	if mp.mallocing != 0 {
-		throw("malloc deadlock")
-	}
-	if mp.gsignal == getg() {
-		throw("malloc during signal")
 	}
-	mp.mallocing = 1
 
-	shouldhelpgc := false
-	dataSize := size
 	c := gomcache()
 	var s *mspan
 	var x unsafe.Pointer
@@ -553,47 +103,63 @@ func mallocgc(size uintptr, typ *_type, flags uint32) unsafe.Pointer {
 			// standalone escaping variables. On a json benchmark
 			// the allocator reduces number of allocations by ~12% and
 			// reduces heap size by ~20%.
-			off := c.tinyoffset
-			// Align tiny pointer for required (conservative) alignment.
-			if size&7 == 0 {
-				off = round(off, 8)
-			} else if size&3 == 0 {
-				off = round(off, 4)
-			} else if size&1 == 0 {
-				off = round(off, 2)
-			}
-			if off+size <= maxTinySize && c.tiny != nil {
-				// The object fits into existing tiny block.
-				x = add(c.tiny, off)
-				c.tinyoffset = off + size
-				c.local_tinyallocs++
-				mp.mallocing = 0
-				releasem(mp)
-				return x
+			tinysize := uintptr(c.tinysize)
+			if size <= tinysize {
+				tiny := unsafe.Pointer(c.tiny)
+				// Align tiny pointer for required (conservative) alignment.
+				if size&7 == 0 {
+					tiny = roundup(tiny, 8)
+				} else if size&3 == 0 {
+					tiny = roundup(tiny, 4)
+				} else if size&1 == 0 {
+					tiny = roundup(tiny, 2)
+				}
+				size1 := size + (uintptr(tiny) - uintptr(unsafe.Pointer(c.tiny)))
+				if size1 <= tinysize {
+					// The object fits into existing tiny block.
+					x = tiny
+					c.tiny = (*byte)(add(x, size))
+					c.tinysize -= uintptr(size1)
+					c.local_tinyallocs++
+					if debugMalloc {
+						mp := acquirem()
+						if mp.mallocing == 0 {
+							gothrow("bad malloc")
+						}
+						mp.mallocing = 0
+						if mp.curg != nil {
+							mp.curg.stackguard0 = mp.curg.stack.lo + _StackGuard
+						}
+						// Note: one releasem for the acquirem just above.
+						// The other for the acquirem at start of malloc.
+						releasem(mp)
+						releasem(mp)
+					}
+					return x
+				}
 			}
 			// Allocate a new maxTinySize block.
 			s = c.alloc[tinySizeClass]
 			v := s.freelist
-			if v.ptr() == nil {
-				systemstack(func() {
-					mCache_Refill(c, tinySizeClass)
-				})
-				shouldhelpgc = true
+			if v == nil {
+				mp := acquirem()
+				mp.scalararg[0] = tinySizeClass
+				onM(mcacheRefill_m)
+				releasem(mp)
 				s = c.alloc[tinySizeClass]
 				v = s.freelist
 			}
-			s.freelist = v.ptr().next
+			s.freelist = v.next
 			s.ref++
-			// prefetchnta offers best performance, see change list message.
-			prefetchnta(uintptr(v.ptr().next))
+			//TODO: prefetch v.next
 			x = unsafe.Pointer(v)
 			(*[2]uint64)(x)[0] = 0
 			(*[2]uint64)(x)[1] = 0
 			// See if we need to replace the existing tiny block with the new one
 			// based on amount of remaining free space.
-			if size < c.tinyoffset {
-				c.tiny = x
-				c.tinyoffset = size
+			if maxTinySize-size > tinysize {
+				c.tiny = (*byte)(add(x, size))
+				c.tinysize = uintptr(maxTinySize - size)
 			}
 			size = maxTinySize
 		} else {
@@ -606,86 +172,156 @@ func mallocgc(size uintptr, typ *_type, flags uint32) unsafe.Pointer {
 			size = uintptr(class_to_size[sizeclass])
 			s = c.alloc[sizeclass]
 			v := s.freelist
-			if v.ptr() == nil {
-				systemstack(func() {
-					mCache_Refill(c, int32(sizeclass))
-				})
-				shouldhelpgc = true
+			if v == nil {
+				mp := acquirem()
+				mp.scalararg[0] = uintptr(sizeclass)
+				onM(mcacheRefill_m)
+				releasem(mp)
 				s = c.alloc[sizeclass]
 				v = s.freelist
 			}
-			s.freelist = v.ptr().next
+			s.freelist = v.next
 			s.ref++
-			// prefetchnta offers best performance, see change list message.
-			prefetchnta(uintptr(v.ptr().next))
+			//TODO: prefetch
 			x = unsafe.Pointer(v)
 			if flags&flagNoZero == 0 {
-				v.ptr().next = 0
+				v.next = nil
 				if size > 2*ptrSize && ((*[2]uintptr)(x))[1] != 0 {
 					memclr(unsafe.Pointer(v), size)
 				}
 			}
 		}
-		c.local_cachealloc += size
+		c.local_cachealloc += intptr(size)
 	} else {
-		var s *mspan
-		shouldhelpgc = true
-		systemstack(func() {
-			s = largeAlloc(size, uint32(flags))
-		})
+		mp := acquirem()
+		mp.scalararg[0] = uintptr(size)
+		mp.scalararg[1] = uintptr(flags)
+		onM(largeAlloc_m)
+		s = (*mspan)(mp.ptrarg[0])
+		mp.ptrarg[0] = nil
+		releasem(mp)
 		x = unsafe.Pointer(uintptr(s.start << pageShift))
 		size = uintptr(s.elemsize)
 	}
 
 	if flags&flagNoScan != 0 {
-		// All objects are pre-marked as noscan. Nothing to do.
-	} else {
-		// If allocating a defer+arg block, now that we've picked a malloc size
-		// large enough to hold everything, cut the "asked for" size down to
-		// just the defer header, so that the GC bitmap will record the arg block
-		// as containing nothing at all (as if it were unused space at the end of
-		// a malloc block caused by size rounding).
-		// The defer arg areas are scanned as part of scanstack.
-		if typ == deferType {
-			dataSize = unsafe.Sizeof(_defer{})
+		// All objects are pre-marked as noscan.
+		goto marked
+	}
+
+	// If allocating a defer+arg block, now that we've picked a malloc size
+	// large enough to hold everything, cut the "asked for" size down to
+	// just the defer header, so that the GC bitmap will record the arg block
+	// as containing nothing at all (as if it were unused space at the end of
+	// a malloc block caused by size rounding).
+	// The defer arg areas are scanned as part of scanstack.
+	if typ == deferType {
+		size0 = unsafe.Sizeof(_defer{})
+	}
+
+	// From here till marked label marking the object as allocated
+	// and storing type info in the GC bitmap.
+	{
+		arena_start := uintptr(unsafe.Pointer(mheap_.arena_start))
+		off := (uintptr(x) - arena_start) / ptrSize
+		xbits := (*uint8)(unsafe.Pointer(arena_start - off/wordsPerBitmapByte - 1))
+		shift := (off % wordsPerBitmapByte) * gcBits
+		if debugMalloc && ((*xbits>>shift)&(bitMask|bitPtrMask)) != bitBoundary {
+			println("runtime: bits =", (*xbits>>shift)&(bitMask|bitPtrMask))
+			gothrow("bad bits in markallocated")
 		}
-		heapBitsSetType(uintptr(x), size, dataSize, typ)
-		if dataSize > typ.size {
-			// Array allocation. If there are any
-			// pointers, GC has to scan to the last
-			// element.
-			if typ.ptrdata != 0 {
-				c.local_scan += dataSize - typ.size + typ.ptrdata
+
+		var ti, te uintptr
+		var ptrmask *uint8
+		if size == ptrSize {
+			// It's one word and it has pointers, it must be a pointer.
+			*xbits |= (bitsPointer << 2) << shift
+			goto marked
+		}
+		if typ.kind&kindGCProg != 0 {
+			nptr := (uintptr(typ.size) + ptrSize - 1) / ptrSize
+			masksize := nptr
+			if masksize%2 != 0 {
+				masksize *= 2 // repeated
+			}
+			masksize = masksize * pointersPerByte / 8 // 4 bits per word
+			masksize++                                // unroll flag in the beginning
+			if masksize > maxGCMask && typ.gc[1] != 0 {
+				// If the mask is too large, unroll the program directly
+				// into the GC bitmap. It's 7 times slower than copying
+				// from the pre-unrolled mask, but saves 1/16 of type size
+				// memory for the mask.
+				mp := acquirem()
+				mp.ptrarg[0] = x
+				mp.ptrarg[1] = unsafe.Pointer(typ)
+				mp.scalararg[0] = uintptr(size)
+				mp.scalararg[1] = uintptr(size0)
+				onM(unrollgcproginplace_m)
+				releasem(mp)
+				goto marked
 			}
+			ptrmask = (*uint8)(unsafe.Pointer(uintptr(typ.gc[0])))
+			// Check whether the program is already unrolled.
+			if uintptr(atomicloadp(unsafe.Pointer(ptrmask)))&0xff == 0 {
+				mp := acquirem()
+				mp.ptrarg[0] = unsafe.Pointer(typ)
+				onM(unrollgcprog_m)
+				releasem(mp)
+			}
+			ptrmask = (*uint8)(add(unsafe.Pointer(ptrmask), 1)) // skip the unroll flag byte
 		} else {
-			c.local_scan += typ.ptrdata
+			ptrmask = (*uint8)(unsafe.Pointer(typ.gc[0])) // pointer to unrolled mask
 		}
+		if size == 2*ptrSize {
+			*xbits = *ptrmask | bitBoundary
+			goto marked
+		}
+		te = uintptr(typ.size) / ptrSize
+		// If the type occupies odd number of words, its mask is repeated.
+		if te%2 == 0 {
+			te /= 2
+		}
+		// Copy pointer bitmask into the bitmap.
+		for i := uintptr(0); i < size0; i += 2 * ptrSize {
+			v := *(*uint8)(add(unsafe.Pointer(ptrmask), ti))
+			ti++
+			if ti == te {
+				ti = 0
+			}
+			if i == 0 {
+				v |= bitBoundary
+			}
+			if i+ptrSize == size0 {
+				v &^= uint8(bitPtrMask << 4)
+			}
 
-		// Ensure that the stores above that initialize x to
-		// type-safe memory and set the heap bits occur before
-		// the caller can make x observable to the garbage
-		// collector. Otherwise, on weakly ordered machines,
-		// the garbage collector could follow a pointer to x,
-		// but see uninitialized memory or stale heap bits.
-		publicationBarrier()
-	}
-
-	// GCmarkterminate allocates black
-	// All slots hold nil so no scanning is needed.
-	// This may be racing with GC so do it atomically if there can be
-	// a race marking the bit.
-	if gcphase == _GCmarktermination || gcBlackenPromptly {
-		systemstack(func() {
-			gcmarknewobject_m(uintptr(x), size)
-		})
+			*xbits = v
+			xbits = (*byte)(add(unsafe.Pointer(xbits), ^uintptr(0)))
+		}
+		if size0%(2*ptrSize) == 0 && size0 < size {
+			// Mark the word after last object's word as bitsDead.
+			*xbits = bitsDead << 2
+		}
 	}
-
+marked:
 	if raceenabled {
 		racemalloc(x, size)
 	}
 
-	mp.mallocing = 0
-	releasem(mp)
+	if debugMalloc {
+		mp := acquirem()
+		if mp.mallocing == 0 {
+			gothrow("bad malloc")
+		}
+		mp.mallocing = 0
+		if mp.curg != nil {
+			mp.curg.stackguard0 = mp.curg.stack.lo + _StackGuard
+		}
+		// Note: one releasem for the acquirem just above.
+		// The other for the acquirem at start of malloc.
+		releasem(mp)
+		releasem(mp)
+	}
 
 	if debug.allocfreetrace != 0 {
 		tracealloc(x, size, typ)
@@ -701,56 +337,13 @@ func mallocgc(size uintptr, typ *_type, flags uint32) unsafe.Pointer {
 		}
 	}
 
-	if shouldhelpgc && shouldtriggergc() {
-		startGC(gcBackgroundMode, false)
-	} else if gcBlackenEnabled != 0 {
-		// Assist garbage collector. We delay this until the
-		// epilogue so that it doesn't interfere with the
-		// inner working of malloc such as mcache refills that
-		// might happen while doing the gcAssistAlloc.
-		gcAssistAlloc(size, shouldhelpgc)
-	} else if shouldhelpgc && bggc.working != 0 {
-		// The GC is starting up or shutting down, so we can't
-		// assist, but we also can't allocate unabated. Slow
-		// down this G's allocation and help the GC stay
-		// scheduled by yielding.
-		//
-		// TODO: This is a workaround. Either help the GC make
-		// the transition or block.
-		gp := getg()
-		if gp != gp.m.g0 && gp.m.locks == 0 && gp.m.preemptoff == "" {
-			Gosched()
-		}
+	if memstats.heap_alloc >= memstats.next_gc {
+		gogc(0)
 	}
 
 	return x
 }
 
-func largeAlloc(size uintptr, flag uint32) *mspan {
-	// print("largeAlloc size=", size, "\n")
-
-	if size+_PageSize < size {
-		throw("out of memory")
-	}
-	npages := size >> _PageShift
-	if size&_PageMask != 0 {
-		npages++
-	}
-
-	// Deduct credit for this span allocation and sweep if
-	// necessary. mHeap_Alloc will also sweep npages, so this only
-	// pays the debt down to npage pages.
-	deductSweepCredit(npages*_PageSize, npages)
-
-	s := mHeap_Alloc(&mheap_, npages, 0, true, flag&_FlagNoZero == 0)
-	if s == nil {
-		throw("out of memory")
-	}
-	s.limit = uintptr(s.start)<<_PageShift + size
-	heapBitsForSpan(s.base()).initSpan(s.layout())
-	return s
-}
-
 // implementation of new builtin
 func newobject(typ *_type) unsafe.Pointer {
 	flags := uint32(0)
@@ -760,34 +353,38 @@ func newobject(typ *_type) unsafe.Pointer {
 	return mallocgc(uintptr(typ.size), typ, flags)
 }
 
-//go:linkname reflect_unsafe_New reflect.unsafe_New
-func reflect_unsafe_New(typ *_type) unsafe.Pointer {
-	return newobject(typ)
-}
-
 // implementation of make builtin for slices
 func newarray(typ *_type, n uintptr) unsafe.Pointer {
 	flags := uint32(0)
 	if typ.kind&kindNoPointers != 0 {
 		flags |= flagNoScan
 	}
-	if int(n) < 0 || (typ.size > 0 && n > _MaxMem/uintptr(typ.size)) {
+	if int(n) < 0 || (typ.size > 0 && n > maxmem/uintptr(typ.size)) {
 		panic("runtime: allocation size out of range")
 	}
 	return mallocgc(uintptr(typ.size)*n, typ, flags)
 }
 
-//go:linkname reflect_unsafe_NewArray reflect.unsafe_NewArray
-func reflect_unsafe_NewArray(typ *_type, n uintptr) unsafe.Pointer {
-	return newarray(typ, n)
-}
-
 // rawmem returns a chunk of pointerless memory.  It is
 // not zeroed.
 func rawmem(size uintptr) unsafe.Pointer {
 	return mallocgc(size, nil, flagNoScan|flagNoZero)
 }
 
+// round size up to next size class
+func goroundupsize(size uintptr) uintptr {
+	if size < maxSmallSize {
+		if size <= 1024-8 {
+			return uintptr(class_to_size[size_to_class8[(size+7)>>3]])
+		}
+		return uintptr(class_to_size[size_to_class128[(size-1024+127)>>7]])
+	}
+	if size+pageSize < size {
+		return size
+	}
+	return (size + pageSize - 1) &^ pageMask
+}
+
 func profilealloc(mp *m, x unsafe.Pointer, size uintptr) {
 	c := mp.mcache
 	rate := MemProfileRate
@@ -811,84 +408,430 @@ func profilealloc(mp *m, x unsafe.Pointer, size uintptr) {
 	mProf_Malloc(x, size)
 }
 
-type persistentAlloc struct {
-	base unsafe.Pointer
-	off  uintptr
+// force = 1 - do GC regardless of current heap usage
+// force = 2 - go GC and eager sweep
+func gogc(force int32) {
+	// The gc is turned off (via enablegc) until the bootstrap has completed.
+	// Also, malloc gets called in the guts of a number of libraries that might be
+	// holding locks. To avoid deadlocks during stoptheworld, don't bother
+	// trying to run gc while holding a lock. The next mallocgc without a lock
+	// will do the gc instead.
+	mp := acquirem()
+	if gp := getg(); gp == mp.g0 || mp.locks > 1 || !memstats.enablegc || panicking != 0 || gcpercent < 0 {
+		releasem(mp)
+		return
+	}
+	releasem(mp)
+	mp = nil
+
+	semacquire(&worldsema, false)
+
+	if force == 0 && memstats.heap_alloc < memstats.next_gc {
+		// typically threads which lost the race to grab
+		// worldsema exit here when gc is done.
+		semrelease(&worldsema)
+		return
+	}
+
+	// Ok, we're doing it!  Stop everybody else
+	startTime := nanotime()
+	mp = acquirem()
+	mp.gcing = 1
+	releasem(mp)
+	onM(stoptheworld)
+	if mp != acquirem() {
+		gothrow("gogc: rescheduled")
+	}
+
+	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).  We also
+	// need to switch to g0 so we can shrink the stack.
+	n := 1
+	if debug.gctrace > 1 {
+		n = 2
+	}
+	for i := 0; i < n; i++ {
+		if i > 0 {
+			startTime = nanotime()
+		}
+		// switch to g0, call gc, then switch back
+		mp.scalararg[0] = uintptr(uint32(startTime)) // low 32 bits
+		mp.scalararg[1] = uintptr(startTime >> 32)   // high 32 bits
+		if force >= 2 {
+			mp.scalararg[2] = 1 // eagersweep
+		} else {
+			mp.scalararg[2] = 0
+		}
+		onM(gc_m)
+	}
+
+	// all done
+	mp.gcing = 0
+	semrelease(&worldsema)
+	onM(starttheworld)
+	releasem(mp)
+	mp = nil
+
+	// now that gc is done, kick off finalizer thread if needed
+	if !concurrentSweep {
+		// give the queued finalizers, if any, a chance to run
+		Gosched()
+	}
+}
+
+// GC runs a garbage collection.
+func GC() {
+	gogc(2)
+}
+
+// linker-provided
+var noptrdata struct{}
+var enoptrdata struct{}
+var noptrbss struct{}
+var enoptrbss struct{}
+
+// SetFinalizer sets the finalizer associated with x to f.
+// When the garbage collector finds an unreachable block
+// with an associated finalizer, it clears the association and runs
+// f(x) in a separate goroutine.  This makes x reachable again, but
+// now without an associated finalizer.  Assuming that SetFinalizer
+// is not called again, the next time the garbage collector sees
+// that x is unreachable, it will free x.
+//
+// SetFinalizer(x, nil) clears any finalizer associated with x.
+//
+// The argument x must be a pointer to an object allocated by
+// calling new or by taking the address of a composite literal.
+// The argument f must be a function that takes a single argument
+// to which x's type can be assigned, and can have arbitrary ignored return
+// values. If either of these is not true, SetFinalizer aborts the
+// program.
+//
+// Finalizers are run in dependency order: if A points at B, both have
+// finalizers, and they are otherwise unreachable, only the finalizer
+// for A runs; once A is freed, the finalizer for B can run.
+// If a cyclic structure includes a block with a finalizer, that
+// cycle is not guaranteed to be garbage collected and the finalizer
+// is not guaranteed to run, because there is no ordering that
+// respects the dependencies.
+//
+// The finalizer for x is scheduled to run at some arbitrary time after
+// x becomes unreachable.
+// There is no guarantee that finalizers will run before a program exits,
+// so typically they are useful only for releasing non-memory resources
+// associated with an object during a long-running program.
+// For example, an os.File object could use a finalizer to close the
+// associated operating system file descriptor when a program discards
+// an os.File without calling Close, but it would be a mistake
+// 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.
+//
+// It is not guaranteed that a finalizer will run for objects allocated
+// in initializers for package-level variables. Such objects may be
+// linker-allocated, not heap-allocated.
+//
+// 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.
+func SetFinalizer(obj interface{}, finalizer interface{}) {
+	e := (*eface)(unsafe.Pointer(&obj))
+	etyp := e._type
+	if etyp == nil {
+		gothrow("runtime.SetFinalizer: first argument is nil")
+	}
+	if etyp.kind&kindMask != kindPtr {
+		gothrow("runtime.SetFinalizer: first argument is " + *etyp._string + ", not pointer")
+	}
+	ot := (*ptrtype)(unsafe.Pointer(etyp))
+	if ot.elem == nil {
+		gothrow("nil elem type!")
+	}
+
+	// find the containing object
+	_, base, _ := findObject(e.data)
+
+	if base == nil {
+		// 0-length objects are okay.
+		if e.data == unsafe.Pointer(&zerobase) {
+			return
+		}
+
+		// Global initializers might be linker-allocated.
+		//	var Foo = &Object{}
+		//	func main() {
+		//		runtime.SetFinalizer(Foo, nil)
+		//	}
+		// The relevant segments are: noptrdata, data, bss, noptrbss.
+		// We cannot assume they are in any order or even contiguous,
+		// due to external linking.
+		if uintptr(unsafe.Pointer(&noptrdata)) <= uintptr(e.data) && uintptr(e.data) < uintptr(unsafe.Pointer(&enoptrdata)) ||
+			uintptr(unsafe.Pointer(&data)) <= uintptr(e.data) && uintptr(e.data) < uintptr(unsafe.Pointer(&edata)) ||
+			uintptr(unsafe.Pointer(&bss)) <= uintptr(e.data) && uintptr(e.data) < uintptr(unsafe.Pointer(&ebss)) ||
+			uintptr(unsafe.Pointer(&noptrbss)) <= uintptr(e.data) && uintptr(e.data) < uintptr(unsafe.Pointer(&enoptrbss)) {
+			return
+		}
+		gothrow("runtime.SetFinalizer: pointer not in allocated block")
+	}
+
+	if e.data != base {
+		// 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 >= maxTinySize {
+			gothrow("runtime.SetFinalizer: pointer not at beginning of allocated block")
+		}
+	}
+
+	f := (*eface)(unsafe.Pointer(&finalizer))
+	ftyp := f._type
+	if ftyp == nil {
+		// switch to M stack and remove finalizer
+		mp := acquirem()
+		mp.ptrarg[0] = e.data
+		onM(removeFinalizer_m)
+		releasem(mp)
+		return
+	}
+
+	if ftyp.kind&kindMask != kindFunc {
+		gothrow("runtime.SetFinalizer: second argument is " + *ftyp._string + ", not a function")
+	}
+	ft := (*functype)(unsafe.Pointer(ftyp))
+	ins := *(*[]*_type)(unsafe.Pointer(&ft.in))
+	if ft.dotdotdot || len(ins) != 1 {
+		gothrow("runtime.SetFinalizer: cannot pass " + *etyp._string + " to finalizer " + *ftyp._string)
+	}
+	fint := ins[0]
+	switch {
+	case fint == etyp:
+		// ok - same type
+		goto okarg
+	case fint.kind&kindMask == kindPtr:
+		if (fint.x == nil || fint.x.name == nil || etyp.x == nil || etyp.x.name == nil) && (*ptrtype)(unsafe.Pointer(fint)).elem == ot.elem {
+			// ok - not same type, but both pointers,
+			// one or the other is unnamed, and same element type, so assignable.
+			goto okarg
+		}
+	case fint.kind&kindMask == kindInterface:
+		ityp := (*interfacetype)(unsafe.Pointer(fint))
+		if len(ityp.mhdr) == 0 {
+			// ok - satisfies empty interface
+			goto okarg
+		}
+		if _, ok := assertE2I2(ityp, obj); ok {
+			goto okarg
+		}
+	}
+	gothrow("runtime.SetFinalizer: cannot pass " + *etyp._string + " to finalizer " + *ftyp._string)
+okarg:
+	// compute size needed for return parameters
+	nret := uintptr(0)
+	for _, t := range *(*[]*_type)(unsafe.Pointer(&ft.out)) {
+		nret = round(nret, uintptr(t.align)) + uintptr(t.size)
+	}
+	nret = round(nret, ptrSize)
+
+	// make sure we have a finalizer goroutine
+	createfing()
+
+	// switch to M stack to add finalizer record
+	mp := acquirem()
+	mp.ptrarg[0] = f.data
+	mp.ptrarg[1] = e.data
+	mp.scalararg[0] = nret
+	mp.ptrarg[2] = unsafe.Pointer(fint)
+	mp.ptrarg[3] = unsafe.Pointer(ot)
+	onM(setFinalizer_m)
+	if mp.scalararg[0] != 1 {
+		gothrow("runtime.SetFinalizer: finalizer already set")
+	}
+	releasem(mp)
+}
+
+// round n up to a multiple of a.  a must be a power of 2.
+func round(n, a uintptr) uintptr {
+	return (n + a - 1) &^ (a - 1)
 }
 
-var globalAlloc struct {
-	mutex
-	persistentAlloc
+// Look up pointer v in heap.  Return the span containing the object,
+// the start of the object, and the size of the object.  If the object
+// does not exist, return nil, nil, 0.
+func findObject(v unsafe.Pointer) (s *mspan, x unsafe.Pointer, n uintptr) {
+	c := gomcache()
+	c.local_nlookup++
+	if ptrSize == 4 && c.local_nlookup >= 1<<30 {
+		// purge cache stats to prevent overflow
+		lock(&mheap_.lock)
+		purgecachedstats(c)
+		unlock(&mheap_.lock)
+	}
+
+	// find span
+	arena_start := uintptr(unsafe.Pointer(mheap_.arena_start))
+	arena_used := uintptr(unsafe.Pointer(mheap_.arena_used))
+	if uintptr(v) < arena_start || uintptr(v) >= arena_used {
+		return
+	}
+	p := uintptr(v) >> pageShift
+	q := p - arena_start>>pageShift
+	s = *(**mspan)(add(unsafe.Pointer(mheap_.spans), q*ptrSize))
+	if s == nil {
+		return
+	}
+	x = unsafe.Pointer(uintptr(s.start) << pageShift)
+
+	if uintptr(v) < uintptr(x) || uintptr(v) >= uintptr(unsafe.Pointer(s.limit)) || s.state != mSpanInUse {
+		s = nil
+		x = nil
+		return
+	}
+
+	n = uintptr(s.elemsize)
+	if s.sizeclass != 0 {
+		x = add(x, (uintptr(v)-uintptr(x))/n*n)
+	}
+	return
+}
+
+var fingCreate uint32
+
+func createfing() {
+	// start the finalizer goroutine exactly once
+	if fingCreate == 0 && cas(&fingCreate, 0, 1) {
+		go runfinq()
+	}
+}
+
+// This is the goroutine that runs all of the finalizers
+func runfinq() {
+	var (
+		frame    unsafe.Pointer
+		framecap uintptr
+	)
+
+	for {
+		lock(&finlock)
+		fb := finq
+		finq = nil
+		if fb == nil {
+			gp := getg()
+			fing = gp
+			fingwait = true
+			gp.issystem = true
+			goparkunlock(&finlock, "finalizer wait")
+			gp.issystem = false
+			continue
+		}
+		unlock(&finlock)
+		if raceenabled {
+			racefingo()
+		}
+		for fb != nil {
+			for i := int32(0); i < fb.cnt; i++ {
+				f := (*finalizer)(add(unsafe.Pointer(&fb.fin), uintptr(i)*unsafe.Sizeof(finalizer{})))
+
+				framesz := unsafe.Sizeof((interface{})(nil)) + uintptr(f.nret)
+				if framecap < framesz {
+					// The frame does not contain pointers interesting for GC,
+					// 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 = mallocgc(framesz, nil, flagNoScan)
+					framecap = framesz
+				}
+
+				if f.fint == nil {
+					gothrow("missing type in runfinq")
+				}
+				switch f.fint.kind & kindMask {
+				case kindPtr:
+					// direct use of pointer
+					*(*unsafe.Pointer)(frame) = f.arg
+				case kindInterface:
+					ityp := (*interfacetype)(unsafe.Pointer(f.fint))
+					// set up with empty interface
+					(*eface)(frame)._type = &f.ot.typ
+					(*eface)(frame).data = f.arg
+					if len(ityp.mhdr) != 0 {
+						// convert to interface with methods
+						// this conversion is guaranteed to succeed - we checked in SetFinalizer
+						*(*fInterface)(frame) = assertE2I(ityp, *(*interface{})(frame))
+					}
+				default:
+					gothrow("bad kind in runfinq")
+				}
+				reflectcall(unsafe.Pointer(f.fn), frame, uint32(framesz), uint32(framesz))
+
+				// drop finalizer queue references to finalized object
+				f.fn = nil
+				f.arg = nil
+				f.ot = nil
+			}
+			fb.cnt = 0
+			next := fb.next
+			lock(&finlock)
+			fb.next = finc
+			finc = fb
+			unlock(&finlock)
+			fb = next
+		}
+	}
+}
+
+var persistent struct {
+	lock mutex
+	pos  unsafe.Pointer
+	end  unsafe.Pointer
 }
 
 // Wrapper around sysAlloc that can allocate small chunks.
 // There is no associated free operation.
 // Intended for things like function/type/debug-related persistent data.
 // If align is 0, uses default align (currently 8).
-func persistentalloc(size, align uintptr, sysStat *uint64) unsafe.Pointer {
-	var p unsafe.Pointer
-	systemstack(func() {
-		p = persistentalloc1(size, align, sysStat)
-	})
-	return p
-}
-
-// Must run on system stack because stack growth can (re)invoke it.
-// See issue 9174.
-//go:systemstack
-func persistentalloc1(size, align uintptr, sysStat *uint64) unsafe.Pointer {
+func persistentalloc(size, align uintptr, stat *uint64) unsafe.Pointer {
 	const (
 		chunk    = 256 << 10
 		maxBlock = 64 << 10 // VM reservation granularity is 64K on windows
 	)
 
-	if size == 0 {
-		throw("persistentalloc: size == 0")
-	}
 	if align != 0 {
 		if align&(align-1) != 0 {
-			throw("persistentalloc: align is not a power of 2")
+			gothrow("persistentalloc: align is not a power of 2")
 		}
 		if align > _PageSize {
-			throw("persistentalloc: align is too large")
+			gothrow("persistentalloc: align is too large")
 		}
 	} else {
 		align = 8
 	}
 
 	if size >= maxBlock {
-		return sysAlloc(size, sysStat)
+		return sysAlloc(size, stat)
 	}
 
-	mp := acquirem()
-	var persistent *persistentAlloc
-	if mp != nil && mp.p != 0 {
-		persistent = &mp.p.ptr().palloc
-	} else {
-		lock(&globalAlloc.mutex)
-		persistent = &globalAlloc.persistentAlloc
-	}
-	persistent.off = round(persistent.off, align)
-	if persistent.off+size > chunk || persistent.base == nil {
-		persistent.base = sysAlloc(chunk, &memstats.other_sys)
-		if persistent.base == nil {
-			if persistent == &globalAlloc.persistentAlloc {
-				unlock(&globalAlloc.mutex)
-			}
-			throw("runtime: cannot allocate memory")
+	lock(&persistent.lock)
+	persistent.pos = roundup(persistent.pos, align)
+	if uintptr(persistent.pos)+size > uintptr(persistent.end) {
+		persistent.pos = sysAlloc(chunk, &memstats.other_sys)
+		if persistent.pos == nil {
+			unlock(&persistent.lock)
+			gothrow("runtime: cannot allocate memory")
 		}
-		persistent.off = 0
-	}
-	p := add(persistent.base, persistent.off)
-	persistent.off += size
-	releasem(mp)
-	if persistent == &globalAlloc.persistentAlloc {
-		unlock(&globalAlloc.mutex)
+		persistent.end = add(persistent.pos, chunk)
 	}
+	p := persistent.pos
+	persistent.pos = add(persistent.pos, size)
+	unlock(&persistent.lock)
 
-	if sysStat != &memstats.other_sys {
-		mSysStatInc(sysStat, size)
-		mSysStatDec(&memstats.other_sys, size)
+	if stat != &memstats.other_sys {
+		xadd64(stat, int64(size))
+		xadd64(&memstats.other_sys, -int64(size))
 	}
 	return p
 }
diff --git a/src/runtime/malloc.h b/src/runtime/malloc.h
new file mode 100644
index 0000000..adb8d3d
--- /dev/null
+++ b/src/runtime/malloc.h
@@ -0,0 +1,621 @@
+// 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.
+
+// Memory allocator, based on tcmalloc.
+// http://goog-perftools.sourceforge.net/doc/tcmalloc.html
+
+// The main allocator works in runs of pages.
+// Small allocation sizes (up to and including 32 kB) are
+// rounded to one of about 100 size classes, each of which
+// has its own free list of objects of exactly that size.
+// Any free page of memory can be split into a set of objects
+// of one size class, which are then managed using free list
+// allocators.
+//
+// The allocator's data structures are:
+//
+//	FixAlloc: a free-list allocator for fixed-size objects,
+//		used to manage storage used by the allocator.
+//	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-P) cache for small objects.
+//	MStats: allocation statistics.
+//
+// Allocating a small object proceeds up a hierarchy of caches:
+//
+//	1. Round the size up to one of the small size classes
+//	   and look in the corresponding MCache free list.
+//	   If the list is not empty, allocate an object from it.
+//	   This can all be done without acquiring a lock.
+//
+//	2. If the MCache free list is empty, replenish it by
+//	   taking a bunch of objects from the MCentral free list.
+//	   Moving a bunch amortizes the cost of acquiring the MCentral lock.
+//
+//	3. If the MCentral free list is empty, replenish it by
+//	   allocating a run of pages from the MHeap and then
+//	   chopping that memory into a objects of the given size.
+//	   Allocating many objects amortizes the cost of locking
+//	   the heap.
+//
+//	4. If the MHeap is empty or has no page runs large enough,
+//	   allocate a new group of pages (at least 1MB) from the
+//	   operating system.  Allocating a large run of pages
+//	   amortizes the cost of talking to the operating system.
+//
+// Freeing a small object proceeds up the same hierarchy:
+//
+//	1. Look up the size class for the object and add it to
+//	   the MCache free list.
+//
+//	2. If the MCache free list is too long or the MCache has
+//	   too much memory, return some to the MCentral free lists.
+//
+//	3. If all the objects in a given span have returned to
+//	   the MCentral list, return that span to the page heap.
+//
+//	4. If the heap has too much memory, return some to the
+//	   operating system.
+//
+//	TODO(rsc): Step 4 is not implemented.
+//
+// Allocating and freeing a large object uses the page heap
+// directly, bypassing the MCache and MCentral free lists.
+//
+// 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.  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
+//	   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.
+//
+// This C code was written with an eye toward translating to Go
+// in the future.  Methods have the form Type_Method(Type *t, ...).
+
+typedef struct MCentral	MCentral;
+typedef struct MHeap	MHeap;
+typedef struct MSpan	MSpan;
+typedef struct MStats	MStats;
+typedef struct MLink	MLink;
+typedef struct GCStats	GCStats;
+
+enum
+{
+	PageShift	= 13,
+	PageSize	= 1<<PageShift,
+	PageMask	= PageSize - 1,
+};
+typedef	uintptr	pageID;		// address >> PageShift
+
+enum
+{
+	// Computed constant.  The definition of MaxSmallSize and the
+	// algorithm in msize.c produce some number of different allocation
+	// 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 = 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
+
+	// Per-P, per order stack segment cache size.
+	StackCacheSize = 32*1024,
+	// Number of orders that get caching.  Order 0 is FixedStack
+	// and each successive order is twice as large.
+	NumStackOrders = 3,
+
+	// Number of bits in page to span calculations (4k pages).
+	// On Windows 64-bit we limit the arena to 32GB or 35 bits (see below for reason).
+	// On other 64-bit platforms, we limit the arena to 128GB, or 37 bits.
+	// On 32-bit, we don't bother limiting anything, so we use the full 32-bit address.
+#ifdef _64BIT
+#ifdef GOOS_windows
+	// Windows counts memory used by page table into committed memory
+	// of the process, so we can't reserve too much memory.
+	// See http://golang.org/issue/5402 and http://golang.org/issue/5236.
+	MHeapMap_Bits = 35 - PageShift,
+#else
+	MHeapMap_Bits = 37 - PageShift,
+#endif
+#else
+	MHeapMap_Bits = 32 - PageShift,
+#endif
+
+	// Max number of threads to run garbage collection.
+	// 2, 3, and 4 are all plausible maximums depending
+	// on the hardware details of the machine.  The garbage
+	// collector scales well to 32 cpus.
+	MaxGcproc = 32,
+};
+
+// Maximum memory allocation size, a hint for callers.
+// This must be a #define instead of an enum because it
+// is so large.
+#ifdef _64BIT
+#define	MaxMem	(1ULL<<(MHeapMap_Bits+PageShift))	/* 128 GB or 32 GB */
+#else
+#define	MaxMem	((uintptr)-1)
+#endif
+
+// A generic linked list of blocks.  (Typically the block is bigger than sizeof(MLink).)
+struct MLink
+{
+	MLink *next;
+};
+
+// 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
+// for other purposes.
+// SysUsed notifies the operating system that the contents
+// of the memory region are needed again.
+//
+// SysFree returns it unconditionally; this is only used if
+// an out-of-memory error has been detected midway through
+// an allocation.  It is okay if SysFree is a no-op.
+//
+// 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.  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, 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
+// MCache and MSpan objects.
+//
+// Memory returned by FixAlloc_Alloc is not zeroed.
+// The caller is responsible for locking around FixAlloc calls.
+// Callers can keep state in the object but the first word is
+// smashed by freeing and reallocating.
+struct FixAlloc
+{
+	uintptr	size;
+	void	(*first)(void *arg, byte *p);	// called first time p is returned
+	void*	arg;
+	MLink*	list;
+	byte*	chunk;
+	uint32	nchunk;
+	uintptr	inuse;	// in-use bytes now
+	uint64*	stat;
+};
+
+void	runtime·FixAlloc_Init(FixAlloc *f, uintptr size, void (*first)(void*, byte*), void *arg, uint64 *stat);
+void*	runtime·FixAlloc_Alloc(FixAlloc *f);
+void	runtime·FixAlloc_Free(FixAlloc *f, void *p);
+
+
+// Statistics.
+// Shared with Go: if you edit this structure, also edit type MemStats in mem.go.
+struct MStats
+{
+	// General statistics.
+	uint64	alloc;		// bytes allocated and still in use
+	uint64	total_alloc;	// bytes allocated (even if freed)
+	uint64	sys;		// bytes obtained from system (should be sum of xxx_sys below, no locking, approximate)
+	uint64	nlookup;	// number of pointer lookups
+	uint64	nmalloc;	// number of mallocs
+	uint64	nfree;  // number of frees
+
+	// Statistics about malloc heap.
+	// protected by mheap.lock
+	uint64	heap_alloc;	// bytes allocated and still in use
+	uint64	heap_sys;	// bytes obtained from system
+	uint64	heap_idle;	// bytes in idle spans
+	uint64	heap_inuse;	// bytes in non-idle spans
+	uint64	heap_released;	// bytes released to the OS
+	uint64	heap_objects;	// total number of allocated objects
+
+	// Statistics about allocation of low-level fixed-size structures.
+	// Protected by FixAlloc locks.
+	uint64	stacks_inuse;	// this number is included in heap_inuse above
+	uint64	stacks_sys;	// always 0 in mstats
+	uint64	mspan_inuse;	// MSpan structures
+	uint64	mspan_sys;
+	uint64	mcache_inuse;	// MCache structures
+	uint64	mcache_sys;
+	uint64	buckhash_sys;	// profiling bucket hash table
+	uint64	gc_sys;
+	uint64	other_sys;
+
+	// Statistics about garbage collector.
+	// Protected by mheap or stopping the world during GC.
+	uint64	next_gc;	// next GC (in heap_alloc time)
+	uint64  last_gc;	// last GC (in absolute time)
+	uint64	pause_total_ns;
+	uint64	pause_ns[256];  // circular buffer of recent GC pause lengths
+	uint64	pause_end[256]; // circular buffer of recent GC end times (nanoseconds since 1970)
+	uint32	numgc;
+	bool	enablegc;
+	bool	debuggc;
+
+	// Statistics about allocation size classes.
+	
+	struct MStatsBySize {
+		uint32 size;
+		uint64 nmalloc;
+		uint64 nfree;
+	} by_size[NumSizeClasses];
+	
+	uint64	tinyallocs;	// number of tiny allocations that didn't cause actual allocation; not exported to Go directly
+};
+
+
+#define mstats runtime·memstats
+extern MStats mstats;
+void	runtime·updatememstats(GCStats *stats);
+void	runtime·ReadMemStats(MStats *stats);
+
+// Size classes.  Computed and initialized by InitSizes.
+//
+// SizeToClass(0 <= n <= MaxSmallSize) returns the size class,
+//	1 <= sizeclass < NumSizeClasses, for n.
+//	Size class 0 is reserved to mean "not small".
+//
+// class_to_size[i] = largest size in class i
+// class_to_allocnpages[i] = number of pages to allocate when
+//	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];
+extern	int8	runtime·size_to_class128[(MaxSmallSize-1024)/128 + 1];
+extern	void	runtime·InitSizes(void);
+
+typedef struct MCacheList MCacheList;
+struct MCacheList
+{
+	MLink *list;
+	uint32 nlist;
+};
+
+typedef struct StackFreeList StackFreeList;
+struct StackFreeList
+{
+	MLink *list;  // linked list of free stacks
+	uintptr size; // total size of stacks in list
+};
+
+typedef struct SudoG SudoG;
+
+// 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;
+	uintptr	local_tinyallocs;	// number of tiny allocs not counted in other stats
+	// The rest is not accessed on every malloc.
+	MSpan*	alloc[NumSizeClasses];	// spans to allocate from
+
+	StackFreeList stackcache[NumStackOrders];
+
+	SudoG*	sudogcache;
+
+	void*	gcworkbuf;
+
+	// Local allocator stats, flushed during GC.
+	uintptr local_nlookup;		// number of pointer lookups
+	uintptr local_largefree;	// bytes freed for large objects (>MaxSmallSize)
+	uintptr local_nlargefree;	// number of frees for large objects (>MaxSmallSize)
+	uintptr local_nsmallfree[NumSizeClasses];	// number of frees for small objects (<=MaxSmallSize)
+};
+
+MSpan*	runtime·MCache_Refill(MCache *c, int32 sizeclass);
+void	runtime·MCache_ReleaseAll(MCache *c);
+void	runtime·stackcache_clear(MCache *c);
+void	runtime·gcworkbuffree(void *b);
+
+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		special;
+	FuncVal*	fn;
+	uintptr		nret;
+	Type*		fint;
+	PtrType*	ot;
+};
+
+// The described object is being heap profiled.
+typedef struct Bucket Bucket; // from mprof.h
+typedef struct SpecialProfile SpecialProfile;
+struct SpecialProfile
+{
+	Special	special;
+	Bucket*	b;
+};
+
+// An MSpan is a run of pages.
+enum
+{
+	MSpanInUse = 0, // allocated for garbage collected heap
+	MSpanStack,     // allocated for use by stack allocator
+	MSpanFree,
+	MSpanListHead,
+	MSpanDead,
+};
+struct MSpan
+{
+	MSpan	*next;		// in a span linked list
+	MSpan	*prev;		// in a span linked list
+	pageID	start;		// starting page number
+	uintptr	npages;		// number of pages in span
+	MLink	*freelist;	// list of free objects
+	// 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
+	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
+	Mutex	specialLock;	// guards specials list
+	Special	*specials;	// linked list of special records sorted by offset.
+};
+
+void	runtime·MSpan_Init(MSpan *span, pageID start, uintptr npages);
+void	runtime·MSpan_EnsureSwept(MSpan *span);
+bool	runtime·MSpan_Sweep(MSpan *span, bool preserve);
+
+// Every MSpan is in one doubly-linked list,
+// either one of the MHeap's free lists or one of the
+// MCentral's span lists.  We use empty MSpan structures as list heads.
+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
+
+
+// Central list of free objects of a given size.
+struct MCentral
+{
+	Mutex  lock;
+	int32 sizeclass;
+	MSpan nonempty;	// list of spans with a free object
+	MSpan empty;	// list of spans with no free objects (or cached in an MCache)
+};
+
+void	runtime·MCentral_Init(MCentral *c, int32 sizeclass);
+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, bool preserve);
+
+// Main malloc heap.
+// The heap itself is the "free[]" and "large" arrays,
+// but all the other global data is here too.
+struct MHeap
+{
+	Mutex  lock;
+	MSpan free[MaxMHeapList];	// free lists of given length
+	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 **gcspans;		// copy of allspans referenced by GC marker or sweeper
+	uint32	nspan;
+	uint32	nspancap;
+	uint32	sweepgen;		// sweep generation, see comment in MSpan
+	uint32	sweepdone;		// all spans are swept
+
+	// span lookup
+	MSpan**	spans;
+	uintptr	spans_mapped;
+
+	// range of addresses we might see in the heap
+	byte *bitmap;
+	uintptr bitmap_mapped;
+	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
+	// spaced CacheLineSize bytes apart, so that each MCentral.lock
+	// gets its own cache line.
+	struct MHeapCentral {
+		MCentral mcentral;
+		byte pad[CacheLineSize];
+	} central[NumSizeClasses];
+
+	FixAlloc spanalloc;	// allocator for Span*
+	FixAlloc cachealloc;	// allocator for MCache*
+	FixAlloc specialfinalizeralloc;	// allocator for SpecialFinalizer*
+	FixAlloc specialprofilealloc;	// allocator for SpecialProfile*
+	Mutex speciallock; // lock for sepcial record allocators.
+
+	// Malloc stats.
+	uint64 largefree;	// bytes freed for large objects (>MaxSmallSize)
+	uint64 nlargefree;	// number of frees for large objects (>MaxSmallSize)
+	uint64 nsmallfree[NumSizeClasses];	// number of frees for small objects (<=MaxSmallSize)
+};
+#define runtime·mheap runtime·mheap_
+extern MHeap runtime·mheap;
+
+void	runtime·MHeap_Init(MHeap *h);
+MSpan*	runtime·MHeap_Alloc(MHeap *h, uintptr npage, int32 sizeclass, bool large, bool needzero);
+MSpan*	runtime·MHeap_AllocStack(MHeap *h, uintptr npage);
+void	runtime·MHeap_Free(MHeap *h, MSpan *s, int32 acct);
+void	runtime·MHeap_FreeStack(MHeap *h, MSpan *s);
+MSpan*	runtime·MHeap_Lookup(MHeap *h, void *v);
+MSpan*	runtime·MHeap_LookupMaybe(MHeap *h, void *v);
+void*	runtime·MHeap_SysAlloc(MHeap *h, uintptr n);
+void	runtime·MHeap_MapBits(MHeap *h);
+void	runtime·MHeap_MapSpans(MHeap *h);
+void	runtime·MHeap_Scavenge(int32 k, uint64 now, uint64 limit);
+
+void*	runtime·persistentalloc(uintptr size, uintptr align, uint64 *stat);
+int32	runtime·mlookup(void *v, byte **base, uintptr *size, MSpan **s);
+uintptr	runtime·sweepone(void);
+void	runtime·markspan(void *v, uintptr size, uintptr n, bool leftover);
+void	runtime·unmarkspan(void *v, uintptr size);
+void	runtime·purgecachedstats(MCache*);
+void	runtime·tracealloc(void*, uintptr, Type*);
+void	runtime·tracefree(void*, uintptr);
+void	runtime·tracegc(void);
+
+int32	runtime·gcpercent;
+int32	runtime·readgogc(void);
+void	runtime·clearpools(void);
+
+enum
+{
+	// flags to malloc
+	FlagNoScan	= 1<<0,	// GC doesn't have to scan object
+	FlagNoZero	= 1<<1, // don't zero memory
+};
+
+void	runtime·mProf_Malloc(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);
+void	runtime·getgcmask(byte*, Type*, byte**, uintptr*);
+
+// NOTE: Layout known to queuefinalizer.
+typedef struct Finalizer Finalizer;
+struct Finalizer
+{
+	FuncVal *fn;	// function to call
+	void *arg;	// ptr to object
+	uintptr nret;	// bytes of return values from fn
+	Type *fint;	// type of first argument of fn
+	PtrType *ot;	// type of ptr to object
+};
+
+typedef struct FinBlock FinBlock;
+struct FinBlock
+{
+	FinBlock *alllink;
+	FinBlock *next;
+	int32 cnt;
+	int32 cap;
+	Finalizer fin[1];
+};
+extern Mutex	runtime·finlock;	// protects the following variables
+extern G*	runtime·fing;
+extern bool	runtime·fingwait;
+extern bool	runtime·fingwake;
+extern FinBlock	*runtime·finq;		// list of finalizers that are to be executed
+extern FinBlock	*runtime·finc;		// cache of free blocks
+
+void	runtime·setprofilebucket_m(void);
+
+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);
+bool	runtime·freespecial(Special *s, void *p, uintptr size, bool freed);
+
+// Information from the compiler about the layout of stack frames.
+struct BitVector
+{
+	int32 n; // # of bits
+	uint8 *bytedata;
+};
+typedef struct StackMap StackMap;
+struct StackMap
+{
+	int32 n; // number of bitmaps
+	int32 nbit; // number of bits in each bitmap
+	uint8 bytedata[]; // bitmaps, each starting on a 32-bit boundary
+};
+// Returns pointer map data for the given stackmap index
+// (the index is encoded in PCDATA_StackMapIndex).
+BitVector	runtime·stackmapdata(StackMap *stackmap, int32 n);
+
+extern	BitVector	runtime·gcdatamask;
+extern	BitVector	runtime·gcbssmask;
+
+// defined in mgc0.go
+void	runtime·gc_m_ptr(Eface*);
+void	runtime·gc_g_ptr(Eface*);
+void	runtime·gc_itab_ptr(Eface*);
+
+void  runtime·setgcpercent_m(void);
+
+// Value we use to mark dead pointers when GODEBUG=gcdead=1.
+#define PoisonGC ((uintptr)0xf969696969696969ULL)
+#define PoisonStack ((uintptr)0x6868686868686868ULL)
diff --git a/src/runtime/malloc_test.go b/src/runtime/malloc_test.go
index f0e73ba..b7795aa 100644
--- a/src/runtime/malloc_test.go
+++ b/src/runtime/malloc_test.go
@@ -32,7 +32,7 @@ func TestMemStats(t *testing.T) {
 		st.HeapIdle > 1e10 || st.HeapInuse > 1e10 || st.HeapObjects > 1e10 || st.StackInuse > 1e10 ||
 		st.StackSys > 1e10 || st.MSpanInuse > 1e10 || st.MSpanSys > 1e10 || st.MCacheInuse > 1e10 ||
 		st.MCacheSys > 1e10 || st.BuckHashSys > 1e10 || st.GCSys > 1e10 || st.OtherSys > 1e10 ||
-		st.NextGC > 1e10 || st.NumGC > 1e9 || st.PauseTotalNs > 1e11 {
+		st.NextGC > 1e10 || st.NumGC > 1e9 {
 		t.Fatalf("Insanely high value (overflow?): %+v", *st)
 	}
 
@@ -44,42 +44,6 @@ func TestMemStats(t *testing.T) {
 	if st.HeapIdle+st.HeapInuse != st.HeapSys {
 		t.Fatalf("HeapIdle(%d) + HeapInuse(%d) should be equal to HeapSys(%d), but isn't.", st.HeapIdle, st.HeapInuse, st.HeapSys)
 	}
-
-	if lpe := st.PauseEnd[int(st.NumGC+255)%len(st.PauseEnd)]; st.LastGC != lpe {
-		t.Fatalf("LastGC(%d) != last PauseEnd(%d)", st.LastGC, lpe)
-	}
-
-	var pauseTotal uint64
-	for _, pause := range st.PauseNs {
-		pauseTotal += pause
-	}
-	if int(st.NumGC) < len(st.PauseNs) {
-		// We have all pauses, so this should be exact.
-		if st.PauseTotalNs != pauseTotal {
-			t.Fatalf("PauseTotalNs(%d) != sum PauseNs(%d)", st.PauseTotalNs, pauseTotal)
-		}
-	} else {
-		if st.PauseTotalNs < pauseTotal {
-			t.Fatalf("PauseTotalNs(%d) < sum PauseNs(%d)", st.PauseTotalNs, pauseTotal)
-		}
-	}
-}
-
-func TestStringConcatenationAllocs(t *testing.T) {
-	n := testing.AllocsPerRun(1e3, func() {
-		b := make([]byte, 10)
-		for i := 0; i < 10; i++ {
-			b[i] = byte(i) + '0'
-		}
-		s := "foo" + string(b)
-		if want := "foo0123456789"; s != want {
-			t.Fatalf("want %v, got %v", want, s)
-		}
-	})
-	// Only string concatenation allocates.
-	if n != 1 {
-		t.Fatalf("want 1 allocation, got %v", n)
-	}
 }
 
 var mallocSink uintptr
diff --git a/src/runtime/map_test.go b/src/runtime/map_test.go
index 9d2894c..92da2d8 100644
--- a/src/runtime/map_test.go
+++ b/src/runtime/map_test.go
@@ -515,61 +515,6 @@ func TestMapStringBytesLookup(t *testing.T) {
 	}
 }
 
-func TestMapLargeKeyNoPointer(t *testing.T) {
-	const (
-		I = 1000
-		N = 64
-	)
-	type T [N]int
-	m := make(map[T]int)
-	for i := 0; i < I; i++ {
-		var v T
-		for j := 0; j < N; j++ {
-			v[j] = i + j
-		}
-		m[v] = i
-	}
-	runtime.GC()
-	for i := 0; i < I; i++ {
-		var v T
-		for j := 0; j < N; j++ {
-			v[j] = i + j
-		}
-		if m[v] != i {
-			t.Fatalf("corrupted map: want %+v, got %+v", i, m[v])
-		}
-	}
-}
-
-func TestMapLargeValNoPointer(t *testing.T) {
-	const (
-		I = 1000
-		N = 64
-	)
-	type T [N]int
-	m := make(map[int]T)
-	for i := 0; i < I; i++ {
-		var v T
-		for j := 0; j < N; j++ {
-			v[j] = i + j
-		}
-		m[i] = v
-	}
-	runtime.GC()
-	for i := 0; i < I; i++ {
-		var v T
-		for j := 0; j < N; j++ {
-			v[j] = i + j
-		}
-		v1 := m[i]
-		for j := 0; j < N; j++ {
-			if v1[j] != v[j] {
-				t.Fatalf("corrupted map: want %+v, got %+v", v, v1)
-			}
-		}
-	}
-}
-
 func benchmarkMapPop(b *testing.B, n int) {
 	m := map[int]int{}
 	for i := 0; i < b.N; i++ {
@@ -590,13 +535,3 @@ func benchmarkMapPop(b *testing.B, n int) {
 func BenchmarkMapPop100(b *testing.B)   { benchmarkMapPop(b, 100) }
 func BenchmarkMapPop1000(b *testing.B)  { benchmarkMapPop(b, 1000) }
 func BenchmarkMapPop10000(b *testing.B) { benchmarkMapPop(b, 10000) }
-
-func TestNonEscapingMap(t *testing.T) {
-	n := testing.AllocsPerRun(1000, func() {
-		m := make(map[int]int)
-		m[0] = 0
-	})
-	if n != 0 {
-		t.Fatalf("want 0 allocs, got %v", n)
-	}
-}
diff --git a/src/runtime/mapspeed_test.go b/src/runtime/mapspeed_test.go
index ac93119..119eb3f 100644
--- a/src/runtime/mapspeed_test.go
+++ b/src/runtime/mapspeed_test.go
@@ -234,15 +234,6 @@ func BenchmarkNewEmptyMap(b *testing.B) {
 	}
 }
 
-func BenchmarkNewSmallMap(b *testing.B) {
-	b.ReportAllocs()
-	for i := 0; i < b.N; i++ {
-		m := make(map[int]int)
-		m[0] = 0
-		m[1] = 1
-	}
-}
-
 func BenchmarkMapIter(b *testing.B) {
 	m := make(map[int]bool)
 	for i := 0; i < 8; i++ {
@@ -307,22 +298,3 @@ func BenchmarkSmallKeyMap(b *testing.B) {
 		_ = m[5]
 	}
 }
-
-type ComplexAlgKey struct {
-	a, b, c int64
-	_       int
-	d       int32
-	_       int
-	e       string
-	_       int
-	f, g, h int64
-}
-
-func BenchmarkComplexAlgMap(b *testing.B) {
-	m := make(map[ComplexAlgKey]bool)
-	var k ComplexAlgKey
-	m[k] = true
-	for i := 0; i < b.N; i++ {
-		_ = m[k]
-	}
-}
diff --git a/src/runtime/mcache.c b/src/runtime/mcache.c
new file mode 100644
index 0000000..5fdbe32
--- /dev/null
+++ b/src/runtime/mcache.c
@@ -0,0 +1,115 @@
+// 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.
+
+// Per-P malloc cache for small objects.
+//
+// See malloc.h for an overview.
+
+#include "runtime.h"
+#include "arch_GOARCH.h"
+#include "malloc.h"
+
+extern volatile intgo runtime·MemProfileRate;
+
+// dummy MSpan that contains no free objects.
+MSpan runtime·emptymspan;
+
+MCache*
+runtime·allocmcache(void)
+{
+	intgo rate;
+	MCache *c;
+	int32 i;
+
+	runtime·lock(&runtime·mheap.lock);
+	c = runtime·FixAlloc_Alloc(&runtime·mheap.cachealloc);
+	runtime·unlock(&runtime·mheap.lock);
+	runtime·memclr((byte*)c, sizeof(*c));
+	for(i = 0; i < NumSizeClasses; i++)
+		c->alloc[i] = &runtime·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;
+}
+
+static void
+freemcache(MCache *c)
+{
+	runtime·MCache_ReleaseAll(c);
+	runtime·stackcache_clear(c);
+	runtime·gcworkbuffree(c->gcworkbuf);
+	runtime·lock(&runtime·mheap.lock);
+	runtime·purgecachedstats(c);
+	runtime·FixAlloc_Free(&runtime·mheap.cachealloc, c);
+	runtime·unlock(&runtime·mheap.lock);
+}
+
+static void
+freemcache_m(void)
+{
+	MCache *c;
+
+	c = g->m->ptrarg[0];
+	g->m->ptrarg[0] = nil;
+	freemcache(c);
+}
+
+void
+runtime·freemcache(MCache *c)
+{
+	void (*fn)(void);
+
+	g->m->ptrarg[0] = c;
+	fn = freemcache_m;
+	runtime·onM(&fn);
+}
+
+// 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)
+{
+	MSpan *s;
+
+	g->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 != &runtime·emptymspan)
+		s->incache = false;
+
+	// Get a new cached span from the central lists.
+	s = runtime·MCentral_CacheSpan(&runtime·mheap.central[sizeclass].mcentral);
+	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;
+	g->m->locks--;
+	return s;
+}
+
+void
+runtime·MCache_ReleaseAll(MCache *c)
+{
+	int32 i;
+	MSpan *s;
+
+	for(i=0; i<NumSizeClasses; i++) {
+		s = c->alloc[i];
+		if(s != &runtime·emptymspan) {
+			runtime·MCentral_UncacheSpan(&runtime·mheap.central[i].mcentral, s);
+			c->alloc[i] = &runtime·emptymspan;
+		}
+	}
+}
diff --git a/src/runtime/mcentral.c b/src/runtime/mcentral.c
new file mode 100644
index 0000000..fe6bcfe
--- /dev/null
+++ b/src/runtime/mcentral.c
@@ -0,0 +1,214 @@
+// 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.
+
+// Central free lists.
+//
+// See malloc.h for an overview.
+//
+// The MCentral doesn't actually contain the list of free objects; the MSpan does.
+// Each MCentral is two lists of MSpans: those with free objects (c->nonempty)
+// and those that are completely allocated (c->empty).
+
+#include "runtime.h"
+#include "arch_GOARCH.h"
+#include "malloc.h"
+
+static MSpan* MCentral_Grow(MCentral *c);
+
+// Initialize a single central free list.
+void
+runtime·MCentral_Init(MCentral *c, int32 sizeclass)
+{
+	c->sizeclass = sizeclass;
+	runtime·MSpanList_Init(&c->nonempty);
+	runtime·MSpanList_Init(&c->empty);
+}
+
+// Allocate a span to use in an MCache.
+MSpan*
+runtime·MCentral_CacheSpan(MCentral *c)
+{
+	MSpan *s;
+	int32 cap, n;
+	uint32 sg;
+
+	runtime·lock(&c->lock);
+	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·MSpanList_Remove(s);
+			runtime·MSpanList_InsertBack(&c->empty, s);
+			runtime·unlock(&c->lock);
+			runtime·MSpan_Sweep(s, true);
+			goto havespan;
+		}
+		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
+		runtime·MSpanList_Remove(s);
+		runtime·MSpanList_InsertBack(&c->empty, s);
+		runtime·unlock(&c->lock);
+		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->lock);
+			runtime·MSpan_Sweep(s, true);
+			if(s->freelist != nil)
+				goto havespan;
+			runtime·lock(&c->lock);
+			// the span is still empty after sweep
+			// it is already in the empty list, so just 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;
+	}
+	runtime·unlock(&c->lock);
+
+	// Replenish central list if empty.
+	s = MCentral_Grow(c);
+	if(s == nil)
+		return nil;
+	runtime·lock(&c->lock);
+	runtime·MSpanList_InsertBack(&c->empty, s);
+	runtime·unlock(&c->lock);
+
+havespan:
+	// At this point s is a non-empty span, queued at the end of the empty list,
+	// c is unlocked.
+	cap = (s->npages << PageShift) / s->elemsize;
+	n = cap - s->ref;
+	if(n == 0)
+		runtime·throw("empty span");
+	if(s->freelist == nil)
+		runtime·throw("freelist empty");
+	s->incache = true;
+	return s;
+}
+
+// Return span from an MCache.
+void
+runtime·MCentral_UncacheSpan(MCentral *c, MSpan *s)
+{
+	int32 cap, n;
+
+	runtime·lock(&c->lock);
+
+	s->incache = false;
+
+	if(s->ref == 0)
+		runtime·throw("uncaching full span");
+
+	cap = (s->npages << PageShift) / s->elemsize;
+	n = cap - s->ref;
+	if(n > 0) {
+		runtime·MSpanList_Remove(s);
+		runtime·MSpanList_Insert(&c->nonempty, s);
+	}
+	runtime·unlock(&c->lock);
+}
+
+// Free n objects from a span s back into the central free list c.
+// Called during sweep.
+// Returns true if the span was returned to heap.  Sets sweepgen to
+// the latest generation.
+// If preserve=true, don't return the span to heap nor relink in MCentral lists;
+// caller takes care of it.
+bool
+runtime·MCentral_FreeSpan(MCentral *c, MSpan *s, int32 n, MLink *start, MLink *end, bool preserve)
+{
+	bool wasempty;
+
+	if(s->incache)
+		runtime·throw("freespan into cached span");
+
+	// Add the objects back to s's free list.
+	wasempty = s->freelist == nil;
+	end->next = s->freelist;
+	s->freelist = start;
+	s->ref -= n;
+
+	if(preserve) {
+		// preserve is set only when called from MCentral_CacheSpan above,
+		// the span must be in the empty list.
+		if(s->next == nil)
+			runtime·throw("can't preserve unlinked span");
+		runtime·atomicstore(&s->sweepgen, runtime·mheap.sweepgen);
+		return false;
+	}
+
+	runtime·lock(&c->lock);
+
+	// Move to nonempty if necessary.
+	if(wasempty) {
+		runtime·MSpanList_Remove(s);
+		runtime·MSpanList_Insert(&c->nonempty, s);
+	}
+
+	// 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->ref != 0) {
+		runtime·unlock(&c->lock);
+		return false;
+	}
+
+	// s is completely freed, return it to the heap.
+	runtime·MSpanList_Remove(s);
+	s->needzero = 1;
+	s->freelist = nil;
+	runtime·unlock(&c->lock);
+	runtime·unmarkspan((byte*)(s->start<<PageShift), s->npages<<PageShift);
+	runtime·MHeap_Free(&runtime·mheap, s, 0);
+	return true;
+}
+
+// Fetch a new span from the heap and carve into objects for the free list.
+static MSpan*
+MCentral_Grow(MCentral *c)
+{
+	uintptr size, npages, i, n;
+	MLink **tailp, *v;
+	byte *p;
+	MSpan *s;
+
+	npages = runtime·class_to_allocnpages[c->sizeclass];
+	size = runtime·class_to_size[c->sizeclass];
+	n = (npages << PageShift) / size;
+	s = runtime·MHeap_Alloc(&runtime·mheap, npages, c->sizeclass, 0, 1);
+	if(s == nil)
+		return nil;
+
+	// Carve span into sequence of blocks.
+	tailp = &s->freelist;
+	p = (byte*)(s->start << PageShift);
+	s->limit = p + size*n;
+	for(i=0; i<n; i++) {
+		v = (MLink*)p;
+		*tailp = v;
+		tailp = &v->next;
+		p += size;
+	}
+	*tailp = nil;
+	runtime·markspan((byte*)(s->start<<PageShift), size, n, size*n < (s->npages<<PageShift));
+	return s;
+}
diff --git a/src/runtime/mem.go b/src/runtime/mem.go
new file mode 100644
index 0000000..e6f1eb0
--- /dev/null
+++ b/src/runtime/mem.go
@@ -0,0 +1,108 @@
+// 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
+
+import "unsafe"
+
+// Note: the MemStats struct should be kept in sync with
+// struct MStats in malloc.h
+
+// A MemStats records statistics about the memory allocator.
+type MemStats struct {
+	// General statistics.
+	Alloc      uint64 // bytes allocated and still in use
+	TotalAlloc uint64 // bytes allocated (even if freed)
+	Sys        uint64 // bytes obtained from system (sum of XxxSys below)
+	Lookups    uint64 // number of pointer lookups
+	Mallocs    uint64 // number of mallocs
+	Frees      uint64 // number of frees
+
+	// Main allocation heap statistics.
+	HeapAlloc    uint64 // bytes allocated and still in use
+	HeapSys      uint64 // bytes obtained from system
+	HeapIdle     uint64 // bytes in idle spans
+	HeapInuse    uint64 // bytes in non-idle span
+	HeapReleased uint64 // bytes released to the OS
+	HeapObjects  uint64 // total number of allocated objects
+
+	// Low-level fixed-size structure allocator statistics.
+	//	Inuse is bytes used now.
+	//	Sys is bytes obtained from system.
+	StackInuse  uint64 // bytes used by stack allocator
+	StackSys    uint64
+	MSpanInuse  uint64 // mspan structures
+	MSpanSys    uint64
+	MCacheInuse uint64 // mcache structures
+	MCacheSys   uint64
+	BuckHashSys uint64 // profiling bucket hash table
+	GCSys       uint64 // GC metadata
+	OtherSys    uint64 // other system allocations
+
+	// Garbage collector statistics.
+	NextGC       uint64 // next collection will happen when HeapAlloc ≥ this amount
+	LastGC       uint64 // end time of last collection (nanoseconds since 1970)
+	PauseTotalNs uint64
+	PauseNs      [256]uint64 // circular buffer of recent GC pause durations, most recent at [(NumGC+255)%256]
+	PauseEnd     [256]uint64 // circular buffer of recent GC pause end times
+	NumGC        uint32
+	EnableGC     bool
+	DebugGC      bool
+
+	// Per-size allocation statistics.
+	// 61 is NumSizeClasses in the C code.
+	BySize [61]struct {
+		Size    uint32
+		Mallocs uint64
+		Frees   uint64
+	}
+}
+
+var sizeof_C_MStats uintptr // filled in by malloc.goc
+
+func init() {
+	var memStats MemStats
+	if sizeof_C_MStats != unsafe.Sizeof(memStats) {
+		println(sizeof_C_MStats, unsafe.Sizeof(memStats))
+		gothrow("MStats vs MemStatsType size mismatch")
+	}
+}
+
+// ReadMemStats populates m with memory allocator statistics.
+func ReadMemStats(m *MemStats) {
+	// Have to acquire worldsema to stop the world,
+	// because stoptheworld can only be used by
+	// one goroutine at a time, and there might be
+	// a pending garbage collection already calling it.
+	semacquire(&worldsema, false)
+	gp := getg()
+	gp.m.gcing = 1
+	onM(stoptheworld)
+
+	gp.m.ptrarg[0] = noescape(unsafe.Pointer(m))
+	onM(readmemstats_m)
+
+	gp.m.gcing = 0
+	gp.m.locks++
+	semrelease(&worldsema)
+	onM(starttheworld)
+	gp.m.locks--
+}
+
+// Implementation of runtime/debug.WriteHeapDump
+func writeHeapDump(fd uintptr) {
+	semacquire(&worldsema, false)
+	gp := getg()
+	gp.m.gcing = 1
+	onM(stoptheworld)
+
+	gp.m.scalararg[0] = fd
+	onM(writeheapdump_m)
+
+	gp.m.gcing = 0
+	gp.m.locks++
+	semrelease(&worldsema)
+	onM(starttheworld)
+	gp.m.locks--
+}
diff --git a/src/runtime/mem_darwin.c b/src/runtime/mem_darwin.c
new file mode 100644
index 0000000..bf3ede5
--- /dev/null
+++ b/src/runtime/mem_darwin.c
@@ -0,0 +1,82 @@
+// 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"
+#include "textflag.h"
+
+#pragma textflag NOSPLIT
+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)
+{
+	// Linux's MADV_DONTNEED is like BSD's MADV_FREE.
+	runtime·madvise(v, n, MADV_FREE);
+}
+
+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;
+
+	*reserved = true;
+	p = runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
+	if(p < (void*)4096)
+		return nil;
+	return p;
+}
+
+enum
+{
+	ENOMEM = 12,
+};
+
+void
+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)
+		runtime·throw("runtime: out of memory");
+	if(p != v)
+		runtime·throw("runtime: cannot map pages in arena address space");
+}
diff --git a/src/runtime/mem_dragonfly.c b/src/runtime/mem_dragonfly.c
new file mode 100644
index 0000000..11457b2
--- /dev/null
+++ b/src/runtime/mem_dragonfly.c
@@ -0,0 +1,105 @@
+// 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"
+#include "textflag.h"
+
+enum
+{
+	ENOMEM = 12,
+};
+
+#pragma textflag NOSPLIT
+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)
+{
+	runtime·madvise(v, n, MADV_FREE);
+}
+
+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;
+	}
+
+	*reserved = true;
+	p = runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
+	if(p < (void*)4096)
+		return nil;
+	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) {
+		// 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
+		// avoided by using MAP_FIXED, but I'm not sure we should need
+		// to do this - we do not on other platforms.
+		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·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/runtime/mem_freebsd.c b/src/runtime/mem_freebsd.c
new file mode 100644
index 0000000..18a9a2f
--- /dev/null
+++ b/src/runtime/mem_freebsd.c
@@ -0,0 +1,100 @@
+// 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"
+#include "textflag.h"
+
+enum
+{
+	ENOMEM = 12,
+};
+
+#pragma textflag NOSPLIT
+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)
+{
+	runtime·madvise(v, n, MADV_FREE);
+}
+
+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;
+	}
+
+	*reserved = true;
+	p = runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
+	if(p < (void*)4096)
+		return nil;
+	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/runtime/mem_linux.c b/src/runtime/mem_linux.c
new file mode 100644
index 0000000..bfb4056
--- /dev/null
+++ b/src/runtime/mem_linux.c
@@ -0,0 +1,162 @@
+// 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"
+#include "textflag.h"
+
+enum
+{
+	_PAGE_SIZE = 4096,
+	EACCES = 13,
+};
+
+static int32
+addrspace_free(void *v, uintptr n)
+{
+	int32 errval;
+	uintptr chunk;
+	uintptr off;
+	
+	// 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);
+		// ENOMEM means unmapped, which is what we want.
+		// Anything else we assume means the pages are mapped.
+		if (errval != -ENOMEM)
+			return 0;
+	}
+	return 1;
+}
+
+static void *
+mmap_fixed(byte *v, uintptr n, int32 prot, int32 flags, int32 fd, uint32 offset)
+{
+	void *p;
+
+	p = runtime·mmap(v, n, prot, flags, fd, offset);
+	if(p != v && addrspace_free(v, n)) {
+		// On some systems, mmap ignores v without
+		// MAP_FIXED, so retry if the address space is free.
+		if(p > (void*)4096)
+			runtime·munmap(p, n);
+		p = runtime·mmap(v, n, prot, flags|MAP_FIXED, fd, offset);
+	}
+	return p;
+}
+
+#pragma textflag NOSPLIT
+void*
+runtime·sysAlloc(uintptr n, uint64 *stat)
+{
+	void *p;
+
+	p = runtime·mmap(nil, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
+	if(p < (void*)4096) {
+		if(p == (void*)EACCES) {
+			runtime·printf("runtime: mmap: access denied\n");
+			runtime·printf("if you're running SELinux, enable execmem for this process.\n");
+			runtime·exit(2);
+		}
+		if(p == (void*)EAGAIN) {
+			runtime·printf("runtime: mmap: too much locked memory (check 'ulimit -l').\n");
+			runtime·exit(2);
+		}
+		return nil;
+	}
+	runtime·xadd64(stat, n);
+	return p;
+}
+
+void
+runtime·SysUnused(void *v, uintptr n)
+{
+	runtime·madvise(v, n, MADV_DONTNEED);
+}
+
+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
+	// 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 && n > 1LL<<32) {
+		p = mmap_fixed(v, 64<<10, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
+		if (p != v) {
+			if(p >= (void*)4096)
+				runtime·munmap(p, 64<<10);
+			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, 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 = mmap_fixed(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/runtime/mem_nacl.c b/src/runtime/mem_nacl.c
new file mode 100644
index 0000000..6c836f1
--- /dev/null
+++ b/src/runtime/mem_nacl.c
@@ -0,0 +1,120 @@
+// 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"
+#include "textflag.h"
+
+enum
+{
+	Debug = 0,
+};
+
+#pragma textflag NOSPLIT
+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/runtime/mem_netbsd.c b/src/runtime/mem_netbsd.c
new file mode 100644
index 0000000..31820e5
--- /dev/null
+++ b/src/runtime/mem_netbsd.c
@@ -0,0 +1,100 @@
+// 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"
+#include "textflag.h"
+
+enum
+{
+	ENOMEM = 12,
+};
+
+#pragma textflag NOSPLIT
+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)
+{
+	runtime·madvise(v, n, MADV_FREE);
+}
+
+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/runtime/mem_openbsd.c b/src/runtime/mem_openbsd.c
new file mode 100644
index 0000000..31820e5
--- /dev/null
+++ b/src/runtime/mem_openbsd.c
@@ -0,0 +1,100 @@
+// 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"
+#include "textflag.h"
+
+enum
+{
+	ENOMEM = 12,
+};
+
+#pragma textflag NOSPLIT
+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)
+{
+	runtime·madvise(v, n, MADV_FREE);
+}
+
+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/runtime/mem_plan9.c b/src/runtime/mem_plan9.c
new file mode 100644
index 0000000..d673d6f
--- /dev/null
+++ b/src/runtime/mem_plan9.c
@@ -0,0 +1,121 @@
+// 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 "arch_GOARCH.h"
+#include "malloc.h"
+#include "os_GOOS.h"
+#include "textflag.h"
+
+extern byte runtime·end[];
+#pragma dataflag NOPTR
+static byte *bloc = { runtime·end };
+static Mutex memlock;
+
+enum
+{
+	Round = PAGESIZE-1
+};
+
+static void*
+brk(uintptr nbytes)
+{
+	uintptr bl;
+
+	runtime·lock(&memlock);
+	// Plan 9 sbrk from /sys/src/libc/9sys/sbrk.c
+	bl = ((uintptr)bloc + Round) & ~Round;
+	if(runtime·brk_((void*)(bl + nbytes)) < 0) {
+		runtime·unlock(&memlock);
+		return nil;
+	}
+	bloc = (byte*)bl + nbytes;
+	runtime·unlock(&memlock);
+	return (void*)bl;	
+}
+
+static void
+sysalloc(void)
+{
+	uintptr nbytes;
+	uint64 *stat;
+	void *p;
+
+	nbytes = g->m->scalararg[0];
+	stat = g->m->ptrarg[0];
+	g->m->scalararg[0] = 0;
+	g->m->ptrarg[0] = nil;
+
+	p = brk(nbytes);
+	if(p != nil)
+		runtime·xadd64(stat, nbytes);
+
+	g->m->ptrarg[0] = p;
+}
+
+#pragma textflag NOSPLIT
+void*
+runtime·sysAlloc(uintptr nbytes, uint64 *stat)
+{
+	void (*fn)(void);
+	void *p;
+
+	g->m->scalararg[0] = nbytes;
+	g->m->ptrarg[0] = stat;
+	fn = sysalloc;
+	runtime·onM(&fn);
+	p = g->m->ptrarg[0];
+	g->m->ptrarg[0] = nil;
+	return p;
+}
+
+void
+runtime·SysFree(void *v, uintptr nbytes, uint64 *stat)
+{
+	runtime·xadd64(stat, -(uint64)nbytes);
+	runtime·lock(&memlock);
+	// from tiny/mem.c
+	// Push pointer back if this is a free
+	// of the most recent sysAlloc.
+	nbytes += (nbytes + Round) & ~Round;
+	if(bloc == (byte*)v+nbytes)
+		bloc -= nbytes;
+	runtime·unlock(&memlock);
+}
+
+void
+runtime·SysUnused(void *v, uintptr nbytes)
+{
+	USED(v, nbytes);
+}
+
+void
+runtime·SysUsed(void *v, uintptr nbytes)
+{
+	USED(v, nbytes);
+}
+
+void
+runtime·SysMap(void *v, uintptr nbytes, bool reserved, uint64 *stat)
+{
+	// SysReserve has already allocated all heap memory,
+	// but has not adjusted stats.
+	USED(v, reserved);
+	runtime·xadd64(stat, nbytes);
+}
+
+void
+runtime·SysFault(void *v, uintptr nbytes)
+{
+	USED(v, nbytes);
+}
+
+void*
+runtime·SysReserve(void *v, uintptr nbytes, bool *reserved)
+{
+	USED(v);
+	*reserved = true;
+	return brk(nbytes);
+}
diff --git a/src/runtime/mem_solaris.c b/src/runtime/mem_solaris.c
new file mode 100644
index 0000000..8e90ba1
--- /dev/null
+++ b/src/runtime/mem_solaris.c
@@ -0,0 +1,101 @@
+// 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"
+#include "textflag.h"
+
+enum
+{
+	ENOMEM = 12,
+};
+
+#pragma textflag NOSPLIT
+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/runtime/mem_windows.c b/src/runtime/mem_windows.c
new file mode 100644
index 0000000..6ea9920
--- /dev/null
+++ b/src/runtime/mem_windows.c
@@ -0,0 +1,132 @@
+// 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 "os_GOOS.h"
+#include "defs_GOOS_GOARCH.h"
+#include "malloc.h"
+#include "textflag.h"
+
+enum {
+	MEM_COMMIT = 0x1000,
+	MEM_RESERVE = 0x2000,
+	MEM_DECOMMIT = 0x4000,
+	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;
+
+#pragma textflag NOSPLIT
+void*
+runtime·sysAlloc(uintptr n, uint64 *stat)
+{
+	runtime·xadd64(stat, n);
+	return runtime·stdcall4(runtime·VirtualAlloc, 0, n, MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE);
+}
+
+void
+runtime·SysUnused(void *v, uintptr n)
+{
+	void *r;
+	uintptr small;
+
+	r = runtime·stdcall3(runtime·VirtualFree, (uintptr)v, n, MEM_DECOMMIT);
+	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·stdcall3(runtime·VirtualFree, (uintptr)v, small, 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
+runtime·SysUsed(void *v, uintptr n)
+{
+	void *r;
+	uintptr small;
+
+	r = runtime·stdcall4(runtime·VirtualAlloc, (uintptr)v, n, MEM_COMMIT, PAGE_READWRITE);
+	if(r != v)
+		runtime·throw("runtime: failed to commit pages");
+
+	// Commit failed. See SysUnused.
+	while(n > 0) {
+		small = n;
+		while(small >= 4096 && runtime·stdcall4(runtime·VirtualAlloc, (uintptr)v, small, MEM_COMMIT, PAGE_READWRITE) == nil)
+			small = (small / 2) & ~(4096-1);
+		if(small < 4096)
+			runtime·throw("runtime: failed to decommit pages");
+		v = (byte*)v + small;
+		n -= small;
+	}
+}
+
+void
+runtime·SysFree(void *v, uintptr n, uint64 *stat)
+{
+	uintptr r;
+
+	runtime·xadd64(stat, -(uint64)n);
+	r = (uintptr)runtime·stdcall3(runtime·VirtualFree, (uintptr)v, 0, MEM_RELEASE);
+	if(r == 0)
+		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, bool *reserved)
+{
+	*reserved = true;
+	// v is just a hint.
+	// First try at v.
+	v = runtime·stdcall4(runtime·VirtualAlloc, (uintptr)v, n, MEM_RESERVE, PAGE_READWRITE);
+	if(v != nil)
+		return v;
+	
+	// Next let the kernel choose the address.
+	return runtime·stdcall4(runtime·VirtualAlloc, 0, n, MEM_RESERVE, PAGE_READWRITE);
+}
+
+void
+runtime·SysMap(void *v, uintptr n, bool reserved, uint64 *stat)
+{
+	void *p;
+
+	USED(reserved);
+
+	runtime·xadd64(stat, n);
+	p = runtime·stdcall4(runtime·VirtualAlloc, (uintptr)v, n, MEM_COMMIT, PAGE_READWRITE);
+	if(p != v)
+		runtime·throw("runtime: cannot map pages in arena address space");
+}
diff --git a/src/runtime/memclr_386.s b/src/runtime/memclr_386.s
index 3f20b69..1520aea 100644
--- a/src/runtime/memclr_386.s
+++ b/src/runtime/memclr_386.s
@@ -15,31 +15,31 @@ TEXT runtime·memclr(SB), NOSPLIT, $0-8
 	XORL	AX, AX
 
 	// MOVOU seems always faster than REP STOSL.
-tail:
+clr_tail:
 	TESTL	BX, BX
-	JEQ	_0
+	JEQ	clr_0
 	CMPL	BX, $2
-	JBE	_1or2
+	JBE	clr_1or2
 	CMPL	BX, $4
-	JBE	_3or4
+	JBE	clr_3or4
 	CMPL	BX, $8
-	JBE	_5through8
+	JBE	clr_5through8
 	CMPL	BX, $16
-	JBE	_9through16
+	JBE	clr_9through16
 	TESTL	$0x4000000, runtime·cpuid_edx(SB) // check for sse2
 	JEQ	nosse2
 	PXOR	X0, X0
 	CMPL	BX, $32
-	JBE	_17through32
+	JBE	clr_17through32
 	CMPL	BX, $64
-	JBE	_33through64
+	JBE	clr_33through64
 	CMPL	BX, $128
-	JBE	_65through128
+	JBE	clr_65through128
 	CMPL	BX, $256
-	JBE	_129through256
+	JBE	clr_129through256
 	// TODO: use branch table and BSR to make this just a single dispatch
 
-loop:
+clr_loop:
 	MOVOU	X0, 0(DI)
 	MOVOU	X0, 16(DI)
 	MOVOU	X0, 32(DI)
@@ -59,40 +59,40 @@ loop:
 	SUBL	$256, BX
 	ADDL	$256, DI
 	CMPL	BX, $256
-	JAE	loop
-	JMP	tail
+	JAE	clr_loop
+	JMP	clr_tail
 
-_1or2:
+clr_1or2:
 	MOVB	AX, (DI)
 	MOVB	AX, -1(DI)(BX*1)
 	RET
-_0:
+clr_0:
 	RET
-_3or4:
+clr_3or4:
 	MOVW	AX, (DI)
 	MOVW	AX, -2(DI)(BX*1)
 	RET
-_5through8:
+clr_5through8:
 	MOVL	AX, (DI)
 	MOVL	AX, -4(DI)(BX*1)
 	RET
-_9through16:
+clr_9through16:
 	MOVL	AX, (DI)
 	MOVL	AX, 4(DI)
 	MOVL	AX, -8(DI)(BX*1)
 	MOVL	AX, -4(DI)(BX*1)
 	RET
-_17through32:
+clr_17through32:
 	MOVOU	X0, (DI)
 	MOVOU	X0, -16(DI)(BX*1)
 	RET
-_33through64:
+clr_33through64:
 	MOVOU	X0, (DI)
 	MOVOU	X0, 16(DI)
 	MOVOU	X0, -32(DI)(BX*1)
 	MOVOU	X0, -16(DI)(BX*1)
 	RET
-_65through128:
+clr_65through128:
 	MOVOU	X0, (DI)
 	MOVOU	X0, 16(DI)
 	MOVOU	X0, 32(DI)
@@ -102,7 +102,7 @@ _65through128:
 	MOVOU	X0, -32(DI)(BX*1)
 	MOVOU	X0, -16(DI)(BX*1)
 	RET
-_129through256:
+clr_129through256:
 	MOVOU	X0, (DI)
 	MOVOU	X0, 16(DI)
 	MOVOU	X0, 32(DI)
@@ -126,5 +126,5 @@ nosse2:
 	REP
 	STOSL
 	ANDL	$3, BX
-	JNE	tail
+	JNE	clr_tail
 	RET
diff --git a/src/runtime/memclr_amd64.s b/src/runtime/memclr_amd64.s
index ec24f1d..94a2c7f 100644
--- a/src/runtime/memclr_amd64.s
+++ b/src/runtime/memclr_amd64.s
@@ -15,30 +15,30 @@ TEXT runtime·memclr(SB), NOSPLIT, $0-16
 	XORQ	AX, AX
 
 	// MOVOU seems always faster than REP STOSQ.
-tail:
+clr_tail:
 	TESTQ	BX, BX
-	JEQ	_0
+	JEQ	clr_0
 	CMPQ	BX, $2
-	JBE	_1or2
+	JBE	clr_1or2
 	CMPQ	BX, $4
-	JBE	_3or4
+	JBE	clr_3or4
 	CMPQ	BX, $8
-	JBE	_5through8
+	JBE	clr_5through8
 	CMPQ	BX, $16
-	JBE	_9through16
+	JBE	clr_9through16
 	PXOR	X0, X0
 	CMPQ	BX, $32
-	JBE	_17through32
+	JBE	clr_17through32
 	CMPQ	BX, $64
-	JBE	_33through64
+	JBE	clr_33through64
 	CMPQ	BX, $128
-	JBE	_65through128
+	JBE	clr_65through128
 	CMPQ	BX, $256
-	JBE	_129through256
+	JBE	clr_129through256
 	// TODO: use branch table and BSR to make this just a single dispatch
 	// TODO: for really big clears, use MOVNTDQ.
 
-loop:
+clr_loop:
 	MOVOU	X0, 0(DI)
 	MOVOU	X0, 16(DI)
 	MOVOU	X0, 32(DI)
@@ -58,38 +58,38 @@ loop:
 	SUBQ	$256, BX
 	ADDQ	$256, DI
 	CMPQ	BX, $256
-	JAE	loop
-	JMP	tail
+	JAE	clr_loop
+	JMP	clr_tail
 
-_1or2:
+clr_1or2:
 	MOVB	AX, (DI)
 	MOVB	AX, -1(DI)(BX*1)
 	RET
-_0:
+clr_0:
 	RET
-_3or4:
+clr_3or4:
 	MOVW	AX, (DI)
 	MOVW	AX, -2(DI)(BX*1)
 	RET
-_5through8:
+clr_5through8:
 	MOVL	AX, (DI)
 	MOVL	AX, -4(DI)(BX*1)
 	RET
-_9through16:
+clr_9through16:
 	MOVQ	AX, (DI)
 	MOVQ	AX, -8(DI)(BX*1)
 	RET
-_17through32:
+clr_17through32:
 	MOVOU	X0, (DI)
 	MOVOU	X0, -16(DI)(BX*1)
 	RET
-_33through64:
+clr_33through64:
 	MOVOU	X0, (DI)
 	MOVOU	X0, 16(DI)
 	MOVOU	X0, -32(DI)(BX*1)
 	MOVOU	X0, -16(DI)(BX*1)
 	RET
-_65through128:
+clr_65through128:
 	MOVOU	X0, (DI)
 	MOVOU	X0, 16(DI)
 	MOVOU	X0, 32(DI)
@@ -99,7 +99,7 @@ _65through128:
 	MOVOU	X0, -32(DI)(BX*1)
 	MOVOU	X0, -16(DI)(BX*1)
 	RET
-_129through256:
+clr_129through256:
 	MOVOU	X0, (DI)
 	MOVOU	X0, 16(DI)
 	MOVOU	X0, 32(DI)
diff --git a/src/runtime/memclr_arm.s b/src/runtime/memclr_arm.s
index 8b5fe31..1824d33 100644
--- a/src/runtime/memclr_arm.s
+++ b/src/runtime/memclr_arm.s
@@ -25,31 +25,31 @@
 
 #include "textflag.h"
 
-#define TO	R8
-#define TOE	R11
-#define N	R12
-#define TMP	R12				/* N and TMP don't overlap */
+TO = 8
+TOE = 11
+N = 12
+TMP = 12				/* N and TMP don't overlap */
 
 TEXT runtime·memclr(SB),NOSPLIT,$0-8
-	MOVW	ptr+0(FP), TO
-	MOVW	n+4(FP), N
-	MOVW	$0, R0
+	MOVW	ptr+0(FP), R(TO)
+	MOVW	n+4(FP), R(N)
+	MOVW	$0, R(0)
 
-	ADD	N, TO, TOE	/* to end pointer */
+	ADD	R(N), R(TO), R(TOE)	/* to end pointer */
 
-	CMP	$4, N		/* need at least 4 bytes to copy */
+	CMP	$4, R(N)		/* need at least 4 bytes to copy */
 	BLT	_1tail
 
 _4align:				/* align on 4 */
-	AND.S	$3, TO, TMP
+	AND.S	$3, R(TO), R(TMP)
 	BEQ	_4aligned
 
-	MOVBU.P	R0, 1(TO)		/* implicit write back */
+	MOVBU.P	R(0), 1(R(TO))		/* implicit write back */
 	B	_4align
 
 _4aligned:
-	SUB	$31, TOE, TMP	/* do 32-byte chunks if possible */
-	CMP	TMP, TO
+	SUB	$31, R(TOE), R(TMP)	/* do 32-byte chunks if possible */
+	CMP	R(TMP), R(TO)
 	BHS	_4tail
 
 	MOVW	R0, R1			/* replicate */
@@ -61,26 +61,26 @@ _4aligned:
 	MOVW	R0, R7
 
 _f32loop:
-	CMP	TMP, TO
+	CMP	R(TMP), R(TO)
 	BHS	_4tail
 
-	MOVM.IA.W [R0-R7], (TO)
+	MOVM.IA.W [R0-R7], (R(TO))
 	B	_f32loop
 
 _4tail:
-	SUB	$3, TOE, TMP	/* do remaining words if possible */
+	SUB	$3, R(TOE), R(TMP)	/* do remaining words if possible */
 _4loop:
-	CMP	TMP, TO
+	CMP	R(TMP), R(TO)
 	BHS	_1tail
 
-	MOVW.P	R0, 4(TO)		/* implicit write back */
+	MOVW.P	R(0), 4(R(TO))		/* implicit write back */
 	B	_4loop
 
 _1tail:
-	CMP	TO, TOE
+	CMP	R(TO), R(TOE)
 	BEQ	_return
 
-	MOVBU.P	R0, 1(TO)		/* implicit write back */
+	MOVBU.P	R(0), 1(R(TO))		/* implicit write back */
 	B	_1tail
 
 _return:
diff --git a/src/runtime/memclr_plan9_386.s b/src/runtime/memclr_plan9_386.s
index 50f327b..b4b671f 100644
--- a/src/runtime/memclr_plan9_386.s
+++ b/src/runtime/memclr_plan9_386.s
@@ -10,40 +10,40 @@ TEXT runtime·memclr(SB), NOSPLIT, $0-8
 	MOVL	n+4(FP), BX
 	XORL	AX, AX
 
-tail:
+clr_tail:
 	TESTL	BX, BX
-	JEQ	_0
+	JEQ	clr_0
 	CMPL	BX, $2
-	JBE	_1or2
+	JBE	clr_1or2
 	CMPL	BX, $4
-	JBE	_3or4
+	JBE	clr_3or4
 	CMPL	BX, $8
-	JBE	_5through8
+	JBE	clr_5through8
 	CMPL	BX, $16
-	JBE	_9through16
+	JBE	clr_9through16
 	MOVL	BX, CX
 	SHRL	$2, CX
 	REP
 	STOSL
 	ANDL	$3, BX
-	JNE	tail
+	JNE	clr_tail
 	RET
 
-_1or2:
+clr_1or2:
 	MOVB	AX, (DI)
 	MOVB	AX, -1(DI)(BX*1)
 	RET
-_0:
+clr_0:
 	RET
-_3or4:
+clr_3or4:
 	MOVW	AX, (DI)
 	MOVW	AX, -2(DI)(BX*1)
 	RET
-_5through8:
+clr_5through8:
 	MOVL	AX, (DI)
 	MOVL	AX, -4(DI)(BX*1)
 	RET
-_9through16:
+clr_9through16:
 	MOVL	AX, (DI)
 	MOVL	AX, 4(DI)
 	MOVL	AX, -8(DI)(BX*1)
diff --git a/src/runtime/memmove_arm.s b/src/runtime/memmove_arm.s
index 35f04a8..f187d42 100644
--- a/src/runtime/memmove_arm.s
+++ b/src/runtime/memmove_arm.s
@@ -26,138 +26,138 @@
 #include "textflag.h"
 
 // TE or TS are spilled to the stack during bulk register moves.
-#define TS	R0
-#define TE	R8
+TS = 0
+TE = 8
 
 // Warning: the linker will use R11 to synthesize certain instructions. Please
 // take care and double check with objdump.
-#define FROM	R11
-#define N	R12
-#define TMP	R12				/* N and TMP don't overlap */
-#define TMP1	R5
-
-#define RSHIFT	R5
-#define LSHIFT	R6
-#define OFFSET	R7
-
-#define BR0	R0					/* shared with TS */
-#define BW0	R1
-#define BR1	R1
-#define BW1	R2
-#define BR2	R2
-#define BW2	R3
-#define BR3	R3
-#define BW3	R4
-
-#define FW0	R1
-#define FR0	R2
-#define FW1	R2
-#define FR1	R3
-#define FW2	R3
-#define FR2	R4
-#define FW3	R4
-#define FR3	R8					/* shared with TE */
+FROM = 11
+N = 12
+TMP = 12				/* N and TMP don't overlap */
+TMP1 = 5
+
+RSHIFT = 5
+LSHIFT = 6
+OFFSET = 7
+
+BR0 = 0					/* shared with TS */
+BW0 = 1
+BR1 = 1
+BW1 = 2
+BR2 = 2
+BW2 = 3
+BR3 = 3
+BW3 = 4
+
+FW0 = 1
+FR0 = 2
+FW1 = 2
+FR1 = 3
+FW2 = 3
+FR2 = 4
+FW3 = 4
+FR3 = 8					/* shared with TE */
 
 TEXT runtime·memmove(SB), NOSPLIT, $4-12
 _memmove:
-	MOVW	to+0(FP), TS
-	MOVW	from+4(FP), FROM
-	MOVW	n+8(FP), N
+	MOVW	to+0(FP), R(TS)
+	MOVW	from+4(FP), R(FROM)
+	MOVW	n+8(FP), R(N)
 
-	ADD	N, TS, TE	/* to end pointer */
+	ADD	R(N), R(TS), R(TE)	/* to end pointer */
 
-	CMP	FROM, TS
+	CMP	R(FROM), R(TS)
 	BLS	_forward
 
 _back:
-	ADD	N, FROM		/* from end pointer */
-	CMP	$4, N		/* need at least 4 bytes to copy */
+	ADD	R(N), R(FROM)		/* from end pointer */
+	CMP	$4, R(N)		/* need at least 4 bytes to copy */
 	BLT	_b1tail
 
 _b4align:				/* align destination on 4 */
-	AND.S	$3, TE, TMP
+	AND.S	$3, R(TE), R(TMP)
 	BEQ	_b4aligned
 
-	MOVBU.W	-1(FROM), TMP	/* pre-indexed */
-	MOVBU.W	TMP, -1(TE)	/* pre-indexed */
+	MOVBU.W	-1(R(FROM)), R(TMP)	/* pre-indexed */
+	MOVBU.W	R(TMP), -1(R(TE))	/* pre-indexed */
 	B	_b4align
 
 _b4aligned:				/* is source now aligned? */
-	AND.S	$3, FROM, TMP
+	AND.S	$3, R(FROM), R(TMP)
 	BNE	_bunaligned
 
-	ADD	$31, TS, TMP	/* do 32-byte chunks if possible */
-	MOVW	TS, savedts-4(SP)
+	ADD	$31, R(TS), R(TMP)	/* do 32-byte chunks if possible */
+	MOVW	R(TS), savedts-4(SP)
 _b32loop:
-	CMP	TMP, TE
+	CMP	R(TMP), R(TE)
 	BLS	_b4tail
 
-	MOVM.DB.W (FROM), [R0-R7]
-	MOVM.DB.W [R0-R7], (TE)
+	MOVM.DB.W (R(FROM)), [R0-R7]
+	MOVM.DB.W [R0-R7], (R(TE))
 	B	_b32loop
 
 _b4tail:				/* do remaining words if possible */
-	MOVW	savedts-4(SP), TS
-	ADD	$3, TS, TMP
+	MOVW	savedts-4(SP), R(TS)
+	ADD	$3, R(TS), R(TMP)
 _b4loop:
-	CMP	TMP, TE
+	CMP	R(TMP), R(TE)
 	BLS	_b1tail
 
-	MOVW.W	-4(FROM), TMP1	/* pre-indexed */
-	MOVW.W	TMP1, -4(TE)	/* pre-indexed */
+	MOVW.W	-4(R(FROM)), R(TMP1)	/* pre-indexed */
+	MOVW.W	R(TMP1), -4(R(TE))	/* pre-indexed */
 	B	_b4loop
 
 _b1tail:				/* remaining bytes */
-	CMP	TE, TS
+	CMP	R(TE), R(TS)
 	BEQ	_return
 
-	MOVBU.W	-1(FROM), TMP	/* pre-indexed */
-	MOVBU.W	TMP, -1(TE)	/* pre-indexed */
+	MOVBU.W	-1(R(FROM)), R(TMP)	/* pre-indexed */
+	MOVBU.W	R(TMP), -1(R(TE))	/* pre-indexed */
 	B	_b1tail
 
 _forward:
-	CMP	$4, N		/* need at least 4 bytes to copy */
+	CMP	$4, R(N)		/* need at least 4 bytes to copy */
 	BLT	_f1tail
 
 _f4align:				/* align destination on 4 */
-	AND.S	$3, TS, TMP
+	AND.S	$3, R(TS), R(TMP)
 	BEQ	_f4aligned
 
-	MOVBU.P	1(FROM), TMP	/* implicit write back */
-	MOVBU.P	TMP, 1(TS)	/* implicit write back */
+	MOVBU.P	1(R(FROM)), R(TMP)	/* implicit write back */
+	MOVBU.P	R(TMP), 1(R(TS))	/* implicit write back */
 	B	_f4align
 
 _f4aligned:				/* is source now aligned? */
-	AND.S	$3, FROM, TMP
+	AND.S	$3, R(FROM), R(TMP)
 	BNE	_funaligned
 
-	SUB	$31, TE, TMP	/* do 32-byte chunks if possible */
-	MOVW	TE, savedte-4(SP)
+	SUB	$31, R(TE), R(TMP)	/* do 32-byte chunks if possible */
+	MOVW	R(TE), savedte-4(SP)
 _f32loop:
-	CMP	TMP, TS
+	CMP	R(TMP), R(TS)
 	BHS	_f4tail
 
-	MOVM.IA.W (FROM), [R1-R8] 
-	MOVM.IA.W [R1-R8], (TS)
+	MOVM.IA.W (R(FROM)), [R1-R8] 
+	MOVM.IA.W [R1-R8], (R(TS))
 	B	_f32loop
 
 _f4tail:
-	MOVW	savedte-4(SP), TE
-	SUB	$3, TE, TMP	/* do remaining words if possible */
+	MOVW	savedte-4(SP), R(TE)
+	SUB	$3, R(TE), R(TMP)	/* do remaining words if possible */
 _f4loop:
-	CMP	TMP, TS
+	CMP	R(TMP), R(TS)
 	BHS	_f1tail
 
-	MOVW.P	4(FROM), TMP1	/* implicit write back */
-	MOVW.P	TMP1, 4(TS)	/* implicit write back */
+	MOVW.P	4(R(FROM)), R(TMP1)	/* implicit write back */
+	MOVW.P	R(TMP1), 4(R(TS))	/* implicit write back */
 	B	_f4loop
 
 _f1tail:
-	CMP	TS, TE
+	CMP	R(TS), R(TE)
 	BEQ	_return
 
-	MOVBU.P	1(FROM), TMP	/* implicit write back */
-	MOVBU.P	TMP, 1(TS)	/* implicit write back */
+	MOVBU.P	1(R(FROM)), R(TMP)	/* implicit write back */
+	MOVBU.P	R(TMP), 1(R(TS))	/* implicit write back */
 	B	_f1tail
 
 _return:
@@ -165,97 +165,97 @@ _return:
 	RET
 
 _bunaligned:
-	CMP	$2, TMP		/* is TMP < 2 ? */
+	CMP	$2, R(TMP)		/* is R(TMP) < 2 ? */
 
-	MOVW.LT	$8, RSHIFT		/* (R(n)<<24)|(R(n-1)>>8) */
-	MOVW.LT	$24, LSHIFT
-	MOVW.LT	$1, OFFSET
+	MOVW.LT	$8, R(RSHIFT)		/* (R(n)<<24)|(R(n-1)>>8) */
+	MOVW.LT	$24, R(LSHIFT)
+	MOVW.LT	$1, R(OFFSET)
 
-	MOVW.EQ	$16, RSHIFT		/* (R(n)<<16)|(R(n-1)>>16) */
-	MOVW.EQ	$16, LSHIFT
-	MOVW.EQ	$2, OFFSET
+	MOVW.EQ	$16, R(RSHIFT)		/* (R(n)<<16)|(R(n-1)>>16) */
+	MOVW.EQ	$16, R(LSHIFT)
+	MOVW.EQ	$2, R(OFFSET)
 
-	MOVW.GT	$24, RSHIFT		/* (R(n)<<8)|(R(n-1)>>24) */
-	MOVW.GT	$8, LSHIFT
-	MOVW.GT	$3, OFFSET
+	MOVW.GT	$24, R(RSHIFT)		/* (R(n)<<8)|(R(n-1)>>24) */
+	MOVW.GT	$8, R(LSHIFT)
+	MOVW.GT	$3, R(OFFSET)
 
-	ADD	$16, TS, TMP	/* do 16-byte chunks if possible */
-	CMP	TMP, TE
+	ADD	$16, R(TS), R(TMP)	/* do 16-byte chunks if possible */
+	CMP	R(TMP), R(TE)
 	BLS	_b1tail
 
-	BIC	$3, FROM		/* align source */
-	MOVW	TS, savedts-4(SP)
-	MOVW	(FROM), BR0	/* prime first block register */
+	BIC	$3, R(FROM)		/* align source */
+	MOVW	R(TS), savedts-4(SP)
+	MOVW	(R(FROM)), R(BR0)	/* prime first block register */
 
 _bu16loop:
-	CMP	TMP, TE
+	CMP	R(TMP), R(TE)
 	BLS	_bu1tail
 
-	MOVW	BR0<<LSHIFT, BW3
-	MOVM.DB.W (FROM), [BR0-BR3]
-	ORR	BR3>>RSHIFT, BW3
+	MOVW	R(BR0)<<R(LSHIFT), R(BW3)
+	MOVM.DB.W (R(FROM)), [R(BR0)-R(BR3)]
+	ORR	R(BR3)>>R(RSHIFT), R(BW3)
 
-	MOVW	BR3<<LSHIFT, BW2
-	ORR	BR2>>RSHIFT, BW2
+	MOVW	R(BR3)<<R(LSHIFT), R(BW2)
+	ORR	R(BR2)>>R(RSHIFT), R(BW2)
 
-	MOVW	BR2<<LSHIFT, BW1
-	ORR	BR1>>RSHIFT, BW1
+	MOVW	R(BR2)<<R(LSHIFT), R(BW1)
+	ORR	R(BR1)>>R(RSHIFT), R(BW1)
 
-	MOVW	BR1<<LSHIFT, BW0
-	ORR	BR0>>RSHIFT, BW0
+	MOVW	R(BR1)<<R(LSHIFT), R(BW0)
+	ORR	R(BR0)>>R(RSHIFT), R(BW0)
 
-	MOVM.DB.W [BW0-BW3], (TE)
+	MOVM.DB.W [R(BW0)-R(BW3)], (R(TE))
 	B	_bu16loop
 
 _bu1tail:
-	MOVW	savedts-4(SP), TS
-	ADD	OFFSET, FROM
+	MOVW	savedts-4(SP), R(TS)
+	ADD	R(OFFSET), R(FROM)
 	B	_b1tail
 
 _funaligned:
-	CMP	$2, TMP
+	CMP	$2, R(TMP)
 
-	MOVW.LT	$8, RSHIFT		/* (R(n+1)<<24)|(R(n)>>8) */
-	MOVW.LT	$24, LSHIFT
-	MOVW.LT	$3, OFFSET
+	MOVW.LT	$8, R(RSHIFT)		/* (R(n+1)<<24)|(R(n)>>8) */
+	MOVW.LT	$24, R(LSHIFT)
+	MOVW.LT	$3, R(OFFSET)
 
-	MOVW.EQ	$16, RSHIFT		/* (R(n+1)<<16)|(R(n)>>16) */
-	MOVW.EQ	$16, LSHIFT
-	MOVW.EQ	$2, OFFSET
+	MOVW.EQ	$16, R(RSHIFT)		/* (R(n+1)<<16)|(R(n)>>16) */
+	MOVW.EQ	$16, R(LSHIFT)
+	MOVW.EQ	$2, R(OFFSET)
 
-	MOVW.GT	$24, RSHIFT		/* (R(n+1)<<8)|(R(n)>>24) */
-	MOVW.GT	$8, LSHIFT
-	MOVW.GT	$1, OFFSET
+	MOVW.GT	$24, R(RSHIFT)		/* (R(n+1)<<8)|(R(n)>>24) */
+	MOVW.GT	$8, R(LSHIFT)
+	MOVW.GT	$1, R(OFFSET)
 
-	SUB	$16, TE, TMP	/* do 16-byte chunks if possible */
-	CMP	TMP, TS
+	SUB	$16, R(TE), R(TMP)	/* do 16-byte chunks if possible */
+	CMP	R(TMP), R(TS)
 	BHS	_f1tail
 
-	BIC	$3, FROM		/* align source */
-	MOVW	TE, savedte-4(SP)
-	MOVW.P	4(FROM), FR3	/* prime last block register, implicit write back */
+	BIC	$3, R(FROM)		/* align source */
+	MOVW	R(TE), savedte-4(SP)
+	MOVW.P	4(R(FROM)), R(FR3)	/* prime last block register, implicit write back */
 
 _fu16loop:
-	CMP	TMP, TS
+	CMP	R(TMP), R(TS)
 	BHS	_fu1tail
 
-	MOVW	FR3>>RSHIFT, FW0
-	MOVM.IA.W (FROM), [FR0,FR1,FR2,FR3]
-	ORR	FR0<<LSHIFT, FW0
+	MOVW	R(FR3)>>R(RSHIFT), R(FW0)
+	MOVM.IA.W (R(FROM)), [R(FR0),R(FR1),R(FR2),R(FR3)]
+	ORR	R(FR0)<<R(LSHIFT), R(FW0)
 
-	MOVW	FR0>>RSHIFT, FW1
-	ORR	FR1<<LSHIFT, FW1
+	MOVW	R(FR0)>>R(RSHIFT), R(FW1)
+	ORR	R(FR1)<<R(LSHIFT), R(FW1)
 
-	MOVW	FR1>>RSHIFT, FW2
-	ORR	FR2<<LSHIFT, FW2
+	MOVW	R(FR1)>>R(RSHIFT), R(FW2)
+	ORR	R(FR2)<<R(LSHIFT), R(FW2)
 
-	MOVW	FR2>>RSHIFT, FW3
-	ORR	FR3<<LSHIFT, FW3
+	MOVW	R(FR2)>>R(RSHIFT), R(FW3)
+	ORR	R(FR3)<<R(LSHIFT), R(FW3)
 
-	MOVM.IA.W [FW0,FW1,FW2,FW3], (TS)
+	MOVM.IA.W [R(FW0),R(FW1),R(FW2),R(FW3)], (R(TS))
 	B	_fu16loop
 
 _fu1tail:
-	MOVW	savedte-4(SP), TE
-	SUB	OFFSET, FROM
+	MOVW	savedte-4(SP), R(TE)
+	SUB	R(OFFSET), R(FROM)
 	B	_f1tail
diff --git a/src/runtime/memmove_test.go b/src/runtime/memmove_test.go
index 857f99b..ffda4fe 100644
--- a/src/runtime/memmove_test.go
+++ b/src/runtime/memmove_test.go
@@ -162,20 +162,6 @@ 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 bmGoMemclr(b *testing.B, n int) {
-	x := make([]byte, n)
-	b.SetBytes(int64(n))
-	for i := 0; i < b.N; i++ {
-		for j := range x {
-			x[j] = 0
-		}
-	}
-}
-func BenchmarkGoMemclr5(b *testing.B)   { bmGoMemclr(b, 5) }
-func BenchmarkGoMemclr16(b *testing.B)  { bmGoMemclr(b, 16) }
-func BenchmarkGoMemclr64(b *testing.B)  { bmGoMemclr(b, 64) }
-func BenchmarkGoMemclr256(b *testing.B) { bmGoMemclr(b, 256) }
-
 func BenchmarkClearFat8(b *testing.B) {
 	for i := 0; i < b.N; i++ {
 		var x [8 / 4]uint32
@@ -206,24 +192,6 @@ func BenchmarkClearFat32(b *testing.B) {
 		_ = x
 	}
 }
-func BenchmarkClearFat40(b *testing.B) {
-	for i := 0; i < b.N; i++ {
-		var x [40 / 4]uint32
-		_ = x
-	}
-}
-func BenchmarkClearFat48(b *testing.B) {
-	for i := 0; i < b.N; i++ {
-		var x [48 / 4]uint32
-		_ = x
-	}
-}
-func BenchmarkClearFat56(b *testing.B) {
-	for i := 0; i < b.N; i++ {
-		var x [56 / 4]uint32
-		_ = x
-	}
-}
 func BenchmarkClearFat64(b *testing.B) {
 	for i := 0; i < b.N; i++ {
 		var x [64 / 4]uint32
diff --git a/src/runtime/mfinal_test.go b/src/runtime/mfinal_test.go
index e9e3601..d2cead2 100644
--- a/src/runtime/mfinal_test.go
+++ b/src/runtime/mfinal_test.go
@@ -171,6 +171,9 @@ func adjChunks() (*objtype, *objtype) {
 
 // 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.
diff --git a/src/runtime/mfixalloc.c b/src/runtime/mfixalloc.c
new file mode 100644
index 0000000..d670629
--- /dev/null
+++ b/src/runtime/mfixalloc.c
@@ -0,0 +1,64 @@
+// 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.
+
+// Fixed-size object allocator.  Returned memory is not zeroed.
+//
+// See malloc.h for overview.
+
+#include "runtime.h"
+#include "arch_GOARCH.h"
+#include "malloc.h"
+
+// Initialize f to allocate objects of the given size,
+// using the allocator to obtain chunks of memory.
+void
+runtime·FixAlloc_Init(FixAlloc *f, uintptr size, void (*first)(void*, byte*), void *arg, uint64 *stat)
+{
+	f->size = size;
+	f->first = first;
+	f->arg = arg;
+	f->list = nil;
+	f->chunk = nil;
+	f->nchunk = 0;
+	f->inuse = 0;
+	f->stat = stat;
+}
+
+void*
+runtime·FixAlloc_Alloc(FixAlloc *f)
+{
+	void *v;
+	
+	if(f->size == 0) {
+		runtime·printf("runtime: use of FixAlloc_Alloc before FixAlloc_Init\n");
+		runtime·throw("runtime: internal error");
+	}
+
+	if(f->list) {
+		v = f->list;
+		f->list = *(void**)f->list;
+		f->inuse += f->size;
+		return v;
+	}
+	if(f->nchunk < f->size) {
+		f->chunk = runtime·persistentalloc(FixAllocChunk, 0, f->stat);
+		f->nchunk = FixAllocChunk;
+	}
+	v = f->chunk;
+	if(f->first)
+		f->first(f->arg, v);
+	f->chunk += f->size;
+	f->nchunk -= f->size;
+	f->inuse += f->size;
+	return v;
+}
+
+void
+runtime·FixAlloc_Free(FixAlloc *f, void *p)
+{
+	f->inuse -= f->size;
+	*(void**)p = f->list;
+	f->list = p;
+}
+
diff --git a/src/runtime/mgc0.c b/src/runtime/mgc0.c
new file mode 100644
index 0000000..083beec
--- /dev/null
+++ b/src/runtime/mgc0.c
@@ -0,0 +1,2013 @@
+// 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.
+
+// 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"
+#include "funcdata.h"
+#include "textflag.h"
+
+enum {
+	Debug		= 0,
+	DebugPtrs	= 0, // if 1, print trace of every pointer load during GC
+	ConcurrentSweep	= 1,
+
+	WorkbufSize	= 4*1024,
+	FinBlockSize	= 4*1024,
+	RootData	= 0,
+	RootBss		= 1,
+	RootFinalizers	= 2,
+	RootSpans	= 3,
+	RootFlushCaches = 4,
+	RootCount	= 5,
+};
+
+// ptrmask for an allocation containing a single pointer.
+static byte oneptr[] = {BitsPointer};
+
+// Initialized from $GOGC.  GOGC=off means no gc.
+extern int32 runtime·gcpercent;
+
+// Holding worldsema grants an M the right to try to stop the world.
+// The procedure is:
+//
+//	runtime·semacquire(&runtime·worldsema);
+//	m->gcing = 1;
+//	runtime·stoptheworld();
+//
+//	... do stuff ...
+//
+//	m->gcing = 0;
+//	runtime·semrelease(&runtime·worldsema);
+//	runtime·starttheworld();
+//
+uint32 runtime·worldsema = 1;
+
+typedef struct Workbuf Workbuf;
+struct Workbuf
+{
+	LFNode	node; // must be first
+	uintptr	nobj;
+	byte*	obj[(WorkbufSize-sizeof(LFNode)-sizeof(uintptr))/PtrSize];
+};
+
+extern byte runtime·data[];
+extern byte runtime·edata[];
+extern byte runtime·bss[];
+extern byte runtime·ebss[];
+
+extern byte runtime·gcdata[];
+extern byte runtime·gcbss[];
+
+Mutex	runtime·finlock;	// protects the following variables
+G*	runtime·fing;		// goroutine that runs finalizers
+FinBlock*	runtime·finq;	// list of finalizers that are to be executed
+FinBlock*	runtime·finc;	// cache of free blocks
+static byte finptrmask[FinBlockSize/PtrSize/PointersPerByte];
+bool	runtime·fingwait;
+bool	runtime·fingwake;
+FinBlock	*runtime·allfin;	// list of all blocks
+
+BitVector	runtime·gcdatamask;
+BitVector	runtime·gcbssmask;
+
+Mutex	runtime·gclock;
+
+static	uintptr	badblock[1024];
+static	int32	nbadblock;
+
+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 *unused);
+static void	scanstack(G *gp);
+static BitVector	unrollglobgcprog(byte *prog, uintptr size);
+
+void runtime·bgsweep(void);
+static FuncVal bgsweepv = {runtime·bgsweep};
+
+typedef struct WorkData WorkData;
+struct WorkData {
+	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;
+	Note	alldone;
+	ParFor*	markfor;
+
+	// Copy of mheap.allspans for marker or sweeper.
+	MSpan**	spans;
+	uint32	nspan;
+};
+WorkData runtime·work;
+
+// Is _cgo_allocate linked into the binary?
+static bool
+have_cgo_allocate(void)
+{
+	extern	byte	go·weak·runtime·_cgo_allocate_internal[1];
+	return go·weak·runtime·_cgo_allocate_internal != nil;
+}
+
+// scanblock scans a block of n bytes starting at pointer b for references
+// to other objects, scanning any it finds recursively until there are no
+// unscanned objects left.  Instead of using an explicit recursion, it keeps
+// 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.
+static void
+scanblock(byte *b, uintptr n, byte *ptrmask)
+{
+	byte *obj, *obj0, *p, *arena_start, *arena_used, **wp, *scanbuf[8], *ptrbitp, *bitp;
+	uintptr i, j, nobj, size, idx, x, off, scanbufpos, bits, xbits, shift;
+	Workbuf *wbuf;
+	Iface *iface;
+	Eface *eface;
+	Type *typ;
+	MSpan *s;
+	pageID k;
+	bool keepworking;
+
+	// Cache memory arena parameters in local vars.
+	arena_start = runtime·mheap.arena_start;
+	arena_used = runtime·mheap.arena_used;
+
+	wbuf = getempty(nil);
+	nobj = wbuf->nobj;
+	wp = &wbuf->obj[nobj];
+	keepworking = b == nil;
+	scanbufpos = 0;
+	for(i = 0; i < nelem(scanbuf); i++)
+		scanbuf[i] = nil;
+
+	ptrbitp = nil;
+
+	// ptrmask can have 2 possible values:
+	// 1. nil - obtain pointer mask from GC bitmap.
+	// 2. pointer to a compact mask (for stacks and data).
+	if(b != nil)
+		goto scanobj;
+	for(;;) {
+		if(nobj == 0) {
+			// Out of work in workbuf.
+			// First, see is there is any work in scanbuf.
+			for(i = 0; i < nelem(scanbuf); i++) {
+				b = scanbuf[scanbufpos];
+				scanbuf[scanbufpos++] = nil;
+				scanbufpos %= nelem(scanbuf);
+				if(b != nil) {
+					n = arena_used - b; // scan until bitBoundary or BitsDead
+					ptrmask = nil; // use GC bitmap for pointer info
+					goto scanobj;
+				}
+			}
+			if(!keepworking) {
+				putempty(wbuf);
+				return;
+			}
+			// Refill workbuf from global queue.
+			wbuf = getfull(wbuf);
+			if(wbuf == nil)
+				return;
+			nobj = wbuf->nobj;
+			wp = &wbuf->obj[nobj];
+		}
+
+		// If another proc wants a pointer, give it some.
+		if(runtime·work.nwait > 0 && nobj > 4 && runtime·work.full == 0) {
+			wbuf->nobj = nobj;
+			wbuf = handoff(wbuf);
+			nobj = wbuf->nobj;
+			wp = &wbuf->obj[nobj];
+		}
+
+		wp--;
+		nobj--;
+		b = *wp;
+		n = arena_used - b; // scan until next bitBoundary or BitsDead
+		ptrmask = nil; // use GC bitmap for pointer info
+
+	scanobj:
+		if(DebugPtrs)
+			runtime·printf("scanblock %p +%p %p\n", b, n, ptrmask);
+		// Find bits of the beginning of the object.
+		if(ptrmask == nil) {
+			off = (uintptr*)b - (uintptr*)arena_start;
+			ptrbitp = arena_start - off/wordsPerBitmapByte - 1;
+		}
+		for(i = 0; i < n; i += PtrSize) {
+			obj = nil;
+			// Find bits for this word.
+			if(ptrmask == nil) {
+				// Check is we have reached end of span.
+				if((((uintptr)b+i)%PageSize) == 0 &&
+					runtime·mheap.spans[(b-arena_start)>>PageShift] != runtime·mheap.spans[(b+i-arena_start)>>PageShift])
+					break;
+				// Consult GC bitmap.
+				bits = *ptrbitp;
+
+				if(wordsPerBitmapByte != 2)
+					runtime·throw("alg doesn't work for wordsPerBitmapByte != 2");
+				j = ((uintptr)b+i)/PtrSize & 1;
+				ptrbitp -= j;
+				bits >>= gcBits*j;
+
+				if((bits&bitBoundary) != 0 && i != 0)
+					break; // reached beginning of the next object
+				bits = (bits>>2)&BitsMask;
+				if(bits == BitsDead)
+					break; // reached no-scan part of the object
+			} else // dense mask (stack or data)
+				bits = (ptrmask[(i/PtrSize)/4]>>(((i/PtrSize)%4)*BitsPerPointer))&BitsMask;
+
+			if(bits <= BitsScalar) // BitsScalar || BitsDead
+				continue;
+			if(bits == BitsPointer) {
+				obj = *(byte**)(b+i);
+				obj0 = obj;
+				goto markobj;
+			}
+
+			// With those three out of the way, must be multi-word.
+			if(Debug && bits != BitsMultiWord)
+				runtime·throw("unexpected garbage collection bits");
+			// Find the next pair of bits.
+			if(ptrmask == nil) {
+				bits = *ptrbitp;
+				j = ((uintptr)b+i+PtrSize)/PtrSize & 1;
+				ptrbitp -= j;
+				bits >>= gcBits*j;
+				bits = (bits>>2)&BitsMask;
+			} else
+				bits = (ptrmask[((i+PtrSize)/PtrSize)/4]>>((((i+PtrSize)/PtrSize)%4)*BitsPerPointer))&BitsMask;
+
+			if(Debug && bits != BitsIface && bits != BitsEface)
+				runtime·throw("unexpected garbage collection bits");
+
+			if(bits == BitsIface) {
+				iface = (Iface*)(b+i);
+				if(iface->tab != nil) {
+					typ = iface->tab->type;
+					if(!(typ->kind&KindDirectIface) || !(typ->kind&KindNoPointers))
+						obj = iface->data;
+				}
+			} else {
+				eface = (Eface*)(b+i);
+				typ = eface->type;
+				if(typ != nil) {
+					if(!(typ->kind&KindDirectIface) || !(typ->kind&KindNoPointers))
+						obj = eface->data;
+				}
+			}
+
+			i += PtrSize;
+
+			obj0 = obj;
+		markobj:
+			// At this point we have extracted the next potential pointer.
+			// Check if it points into heap.
+			if(obj == nil)
+				continue;
+			if(obj < arena_start || obj >= arena_used) {
+				if((uintptr)obj < PhysPageSize && runtime·invalidptr) {
+					s = nil;
+					goto badobj;
+				}
+				continue;
+			}
+			// Mark the object.
+			obj = (byte*)((uintptr)obj & ~(PtrSize-1));
+			off = (uintptr*)obj - (uintptr*)arena_start;
+			bitp = arena_start - off/wordsPerBitmapByte - 1;
+			shift = (off % wordsPerBitmapByte) * gcBits;
+			xbits = *bitp;
+			bits = (xbits >> shift) & bitMask;
+			if((bits&bitBoundary) == 0) {
+				// Not a beginning of a block, consult span table to find the block beginning.
+				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) {
+					// Sometimes 32-bit heaps have holes.  See issue 9872
+					if(PtrSize == 4 && s == nil)
+						continue;
+					// Stack pointers lie within the arena bounds but are not part of the GC heap.
+					// Ignore them.
+					if(s != nil && s->state == MSpanStack)
+						continue;
+				
+				badobj:
+					// If cgo_allocate is linked into the binary, it can allocate
+					// memory as []unsafe.Pointer that may not contain actual
+					// pointers and must be scanned conservatively.
+					// In this case alone, allow the bad pointer.
+					if(have_cgo_allocate() && ptrmask == nil)
+						continue;
+
+					// Anything else indicates a bug somewhere.
+					// If we're in the middle of chasing down a different bad pointer,
+					// don't confuse the trace by printing about this one.
+					if(nbadblock > 0)
+						continue;
+
+					runtime·printf("runtime: garbage collector found invalid heap pointer *(%p+%p)=%p", b, i, obj);
+					if(s == nil)
+						runtime·printf(" s=nil\n");
+					else
+						runtime·printf(" span=%p-%p-%p state=%d\n", (uintptr)s->start<<PageShift, s->limit, (uintptr)(s->start+s->npages)<<PageShift, s->state);
+					if(ptrmask != nil)
+						runtime·throw("invalid heap pointer");
+					// Add to badblock list, which will cause the garbage collection
+					// to keep repeating until it has traced the chain of pointers
+					// leading to obj all the way back to a root.
+					if(nbadblock == 0)
+						badblock[nbadblock++] = (uintptr)b;
+					continue;
+				}
+				p = (byte*)((uintptr)s->start<<PageShift);
+				if(s->sizeclass != 0) {
+					size = s->elemsize;
+					idx = ((byte*)obj - p)/size;
+					p = p+idx*size;
+				}
+				if(p == obj) {
+					runtime·printf("runtime: failed to find block beginning for %p s=%p s->limit=%p\n",
+						p, s->start*PageSize, s->limit);
+					runtime·throw("failed to find block beginning");
+				}
+				obj = p;
+				goto markobj;
+			}
+			if(DebugPtrs)
+				runtime·printf("scan *%p = %p => base %p\n", b+i, obj0, obj);
+
+			if(nbadblock > 0 && (uintptr)obj == badblock[nbadblock-1]) {
+				// Running garbage collection again because
+				// we want to find the path from a root to a bad pointer.
+				// Found possible next step; extend or finish path.
+				for(j=0; j<nbadblock; j++)
+					if(badblock[j] == (uintptr)b)
+						goto AlreadyBad;
+				runtime·printf("runtime: found *(%p+%p) = %p+%p\n", b, i, obj0, (uintptr)(obj-obj0));
+				if(ptrmask != nil)
+					runtime·throw("bad pointer");
+				if(nbadblock >= nelem(badblock))
+					runtime·throw("badblock trace too long");
+				badblock[nbadblock++] = (uintptr)b;
+			AlreadyBad:;
+			}
+
+			// Now we have bits, bitp, and shift correct for
+			// obj pointing at the base of the object.
+			// Only care about not marked objects.
+			if((bits&bitMarked) != 0)
+				continue;
+			// If obj size is greater than 8, then each byte of GC bitmap
+			// contains info for at most one object. In such case we use
+			// non-atomic byte store to mark the object. This can lead
+			// to double enqueue of the object for scanning, but scanning
+			// is an idempotent operation, so it is OK. This cannot lead
+			// to bitmap corruption because the single marked bit is the
+			// only thing that can change in the byte.
+			// For 8-byte objects we use non-atomic store, if the other
+			// quadruple is already marked. Otherwise we resort to CAS
+			// loop for marking.
+			if((xbits&(bitMask|(bitMask<<gcBits))) != (bitBoundary|(bitBoundary<<gcBits)) ||
+				runtime·work.nproc == 1)
+				*bitp = xbits | (bitMarked<<shift);
+			else
+				runtime·atomicor8(bitp, bitMarked<<shift);
+
+			if(((xbits>>(shift+2))&BitsMask) == BitsDead)
+				continue;  // noscan object
+
+			// Queue the obj for scanning.
+			PREFETCH(obj);
+			p = scanbuf[scanbufpos];
+			scanbuf[scanbufpos++] = obj;
+			scanbufpos %= nelem(scanbuf);
+			if(p == nil)
+				continue;
+
+			// If workbuf is full, obtain an empty one.
+			if(nobj >= nelem(wbuf->obj)) {
+				wbuf->nobj = nobj;
+				wbuf = getempty(wbuf);
+				nobj = wbuf->nobj;
+				wp = &wbuf->obj[nobj];
+			}
+			*wp = p;
+			wp++;
+			nobj++;
+		}
+		if(DebugPtrs)
+			runtime·printf("end scanblock %p +%p %p\n", b, n, ptrmask);
+
+		if(Debug && ptrmask == nil) {
+			// For heap objects ensure that we did not overscan.
+			n = 0;
+			p = nil;
+			if(!runtime·mlookup(b, &p, &n, nil) || b != p || i > n) {
+				runtime·printf("runtime: scanned (%p,%p), heap object (%p,%p)\n", b, i, p, n);
+				runtime·throw("scanblock: scanned invalid object");
+			}
+		}
+	}
+}
+
+static void
+markroot(ParFor *desc, uint32 i)
+{
+	FinBlock *fb;
+	MSpan *s;
+	uint32 spanidx, sg;
+	G *gp;
+	void *p;
+	uint32 status;
+	bool restart;
+
+	USED(&desc);
+	// Note: if you add a case here, please also update heapdump.c:dumproots.
+	switch(i) {
+	case RootData:
+		scanblock(runtime·data, runtime·edata - runtime·data, runtime·gcdatamask.bytedata);
+		break;
+
+	case RootBss:
+		scanblock(runtime·bss, runtime·ebss - runtime·bss, runtime·gcbssmask.bytedata);
+		break;
+
+	case RootFinalizers:
+		for(fb=runtime·allfin; fb; fb=fb->alllink)
+			scanblock((byte*)fb->fin, fb->cnt*sizeof(fb->fin[0]), finptrmask);
+		break;
+
+	case RootSpans:
+		// mark MSpan.specials
+		sg = runtime·mheap.sweepgen;
+		for(spanidx=0; spanidx<runtime·work.nspan; spanidx++) {
+			Special *sp;
+			SpecialFinalizer *spf;
+
+			s = runtime·work.spans[spanidx];
+			if(s->state != MSpanInUse)
+				continue;
+			if(s->sweepgen != sg) {
+				runtime·printf("sweep %d %d\n", s->sweepgen, sg);
+				runtime·throw("gc: unswept span");
+			}
+			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->special.offset/s->elemsize*s->elemsize);
+				scanblock(p, s->elemsize, nil);
+				scanblock((void*)&spf->fn, PtrSize, oneptr);
+			}
+		}
+		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
+		status = runtime·readgstatus(gp);
+		if((status == Gwaiting || status == Gsyscall) && gp->waitsince == 0)
+			gp->waitsince = runtime·work.tstart;
+		// Shrink a stack if not much of it is being used.
+		runtime·shrinkstack(gp);
+		if(runtime·readgstatus(gp) == Gdead) 
+			gp->gcworkdone = true;
+		else 
+			gp->gcworkdone = false; 
+		restart = runtime·stopg(gp);
+		scanstack(gp);
+		if(restart)
+			runtime·restartg(gp);
+		break;
+	}
+}
+
+// Get an empty work buffer off the work.empty list,
+// allocating new buffers as needed.
+static Workbuf*
+getempty(Workbuf *b)
+{
+	MCache *c;
+
+	if(b != nil)
+		runtime·lfstackpush(&runtime·work.full, &b->node);
+	b = nil;
+	c = g->m->mcache;
+	if(c->gcworkbuf != nil) {
+		b = c->gcworkbuf;
+		c->gcworkbuf = nil;
+	}
+	if(b == nil)
+		b = (Workbuf*)runtime·lfstackpop(&runtime·work.empty);
+	if(b == nil)
+		b = runtime·persistentalloc(sizeof(*b), CacheLineSize, &mstats.gc_sys);
+	b->nobj = 0;
+	return b;
+}
+
+static void
+putempty(Workbuf *b)
+{
+	MCache *c;
+
+	c = g->m->mcache;
+	if(c->gcworkbuf == nil) {
+		c->gcworkbuf = b;
+		return;
+	}
+	runtime·lfstackpush(&runtime·work.empty, &b->node);
+}
+
+void
+runtime·gcworkbuffree(void *b)
+{
+	if(b != nil)
+		putempty(b);
+}
+
+// Get a full work buffer off the work.full list, or return nil.
+static Workbuf*
+getfull(Workbuf *b)
+{
+	int32 i;
+
+	if(b != nil)
+		runtime·lfstackpush(&runtime·work.empty, &b->node);
+	b = (Workbuf*)runtime·lfstackpop(&runtime·work.full);
+	if(b != nil || runtime·work.nproc == 1)
+		return b;
+
+	runtime·xadd(&runtime·work.nwait, +1);
+	for(i=0;; i++) {
+		if(runtime·work.full != 0) {
+			runtime·xadd(&runtime·work.nwait, -1);
+			b = (Workbuf*)runtime·lfstackpop(&runtime·work.full);
+			if(b != nil)
+				return b;
+			runtime·xadd(&runtime·work.nwait, +1);
+		}
+		if(runtime·work.nwait == runtime·work.nproc)
+			return nil;
+		if(i < 10) {
+			g->m->gcstats.nprocyield++;
+			runtime·procyield(20);
+		} else if(i < 20) {
+			g->m->gcstats.nosyield++;
+			runtime·osyield();
+		} else {
+			g->m->gcstats.nsleep++;
+			runtime·usleep(100);
+		}
+	}
+}
+
+static Workbuf*
+handoff(Workbuf *b)
+{
+	int32 n;
+	Workbuf *b1;
+
+	// Make new buffer with half of b's pointers.
+	b1 = getempty(nil);
+	n = b->nobj/2;
+	b->nobj -= n;
+	b1->nobj = n;
+	runtime·memmove(b1->obj, b->obj+b->nobj, n*sizeof b1->obj[0]);
+	g->m->gcstats.nhandoff++;
+	g->m->gcstats.nhandoffcnt += n;
+
+	// Put b on full list - let first half of b get stolen.
+	runtime·lfstackpush(&runtime·work.full, &b->node);
+	return b1;
+}
+
+BitVector
+runtime·stackmapdata(StackMap *stackmap, int32 n)
+{
+	if(n < 0 || n >= stackmap->n)
+		runtime·throw("stackmapdata: index out of range");
+	return (BitVector){stackmap->nbit, stackmap->bytedata + n*((stackmap->nbit+31)/32*4)};
+}
+
+// Scan a stack frame: local variables and function arguments/results.
+static bool
+scanframe(Stkframe *frame, void *unused)
+{
+	Func *f;
+	StackMap *stackmap;
+	BitVector bv;
+	uintptr size, minsize;
+	uintptr targetpc;
+	int32 pcdata;
+
+	USED(unused);
+	f = frame->fn;
+	targetpc = frame->continpc;
+	if(targetpc == 0) {
+		// Frame is dead.
+		return true;
+	}
+	if(Debug > 1)
+		runtime·printf("scanframe %s\n", runtime·funcname(f));
+	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.
+	size = frame->varp - frame->sp;
+	if(thechar != '6' && thechar != '8')
+		minsize = sizeof(uintptr);
+	else
+		minsize = 0;
+	if(size > minsize) {
+		stackmap = runtime·funcdata(f, FUNCDATA_LocalsPointerMaps);
+		if(stackmap == nil || stackmap->n <= 0) {
+			runtime·printf("runtime: frame %s untyped locals %p+%p\n", runtime·funcname(f), (byte*)(frame->varp-size), size);
+			runtime·throw("missing stackmap");
+		}
+
+		// Locals bitmap information, scan just the pointers in locals.
+		if(pcdata < 0 || pcdata >= stackmap->n) {
+			// don't know where we are
+			runtime·printf("runtime: pcdata is %d and %d locals 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;
+		scanblock((byte*)(frame->varp - size), bv.n/BitsPerPointer*PtrSize, bv.bytedata);
+	}
+
+	// Scan arguments.
+	if(frame->arglen > 0) {
+		if(frame->argmap != nil)
+			bv = *frame->argmap;
+		else {
+			stackmap = runtime·funcdata(f, FUNCDATA_ArgsPointerMaps);
+			if(stackmap == nil || stackmap->n <= 0) {
+				runtime·printf("runtime: frame %s untyped args %p+%p\n", runtime·funcname(f), frame->argp, (uintptr)frame->arglen);
+				runtime·throw("missing stackmap");
+			}
+			if(pcdata < 0 || pcdata >= stackmap->n) {
+				// don't know where we are
+				runtime·printf("runtime: pcdata is %d and %d args 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);
+		}
+ 		scanblock((byte*)frame->argp, bv.n/BitsPerPointer*PtrSize, bv.bytedata);
+ 	}
+ 	return true;
+}
+
+static void
+scanstack(G *gp)
+{
+	M *mp;
+	bool (*fn)(Stkframe*, void*);
+
+	if(runtime·readgstatus(gp)&Gscan == 0) {
+		runtime·printf("runtime: gp=%p, goid=%D, gp->atomicstatus=%d\n", gp, gp->goid, runtime·readgstatus(gp));
+		runtime·throw("mark - bad status");
+	}
+
+	switch(runtime·readgstatus(gp)&~Gscan) {
+	default:
+		runtime·printf("runtime: gp=%p, goid=%D, gp->atomicstatus=%d\n", gp, gp->goid, runtime·readgstatus(gp));
+		runtime·throw("mark - bad status");
+	case Gdead:
+		return;
+	case Grunning:
+		runtime·printf("runtime: gp=%p, goid=%D, gp->atomicstatus=%d\n", gp, gp->goid, runtime·readgstatus(gp));
+		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");
+
+	fn = scanframe;
+	runtime·gentraceback(~(uintptr)0, ~(uintptr)0, 0, gp, 0, nil, 0x7fffffff, &fn, nil, 0);
+	runtime·tracebackdefers(gp, &fn, nil);
+}
+
+// The gp has been moved to a gc safepoint. If there is gcphase specific
+// work it is done here. 
+void
+runtime·gcphasework(G *gp)
+{
+	switch(runtime·gcphase) {
+	default:
+		runtime·throw("gcphasework in bad gcphase");
+	case GCoff:
+	case GCquiesce:
+	case GCstw:
+	case GCsweep:
+		// No work for now.
+		break;
+	case GCmark:
+		// Disabled until concurrent GC is implemented
+		// but indicate the scan has been done. 
+		// scanstack(gp);
+		break;
+	}
+	gp->gcworkdone = true;
+}
+
+#pragma dataflag NOPTR
+static byte finalizer1[] = {
+	// Each Finalizer is 5 words, ptr ptr uintptr ptr ptr.
+	// Each byte describes 4 words.
+	// Need 4 Finalizers described by 5 bytes before pattern repeats:
+	//	ptr ptr uintptr ptr ptr
+	//	ptr ptr uintptr ptr ptr
+	//	ptr ptr uintptr ptr ptr
+	//	ptr ptr uintptr ptr ptr
+	// aka
+	//	ptr ptr uintptr ptr
+	//	ptr ptr ptr uintptr
+	//	ptr ptr ptr ptr
+	//	uintptr ptr ptr ptr
+	//	ptr uintptr ptr ptr
+	// Assumptions about Finalizer layout checked below.
+	BitsPointer | BitsPointer<<2 | BitsScalar<<4 | BitsPointer<<6,
+	BitsPointer | BitsPointer<<2 | BitsPointer<<4 | BitsScalar<<6,
+	BitsPointer | BitsPointer<<2 | BitsPointer<<4 | BitsPointer<<6,
+	BitsScalar | BitsPointer<<2 | BitsPointer<<4 | BitsPointer<<6,
+	BitsPointer | BitsScalar<<2 | BitsPointer<<4 | BitsPointer<<6,
+};
+
+void
+runtime·queuefinalizer(byte *p, FuncVal *fn, uintptr nret, Type *fint, PtrType *ot)
+{
+	FinBlock *block;
+	Finalizer *f;
+	int32 i;
+
+	runtime·lock(&runtime·finlock);
+	if(runtime·finq == nil || runtime·finq->cnt == runtime·finq->cap) {
+		if(runtime·finc == nil) {
+			runtime·finc = runtime·persistentalloc(FinBlockSize, 0, &mstats.gc_sys);
+			runtime·finc->cap = (FinBlockSize - sizeof(FinBlock)) / sizeof(Finalizer) + 1;
+			runtime·finc->alllink = runtime·allfin;
+			runtime·allfin = runtime·finc;
+			if(finptrmask[0] == 0) {
+				// Build pointer mask for Finalizer array in block.
+				// Check assumptions made in finalizer1 array above.
+				if(sizeof(Finalizer) != 5*PtrSize ||
+					offsetof(Finalizer, fn) != 0 ||
+					offsetof(Finalizer, arg) != PtrSize ||
+					offsetof(Finalizer, nret) != 2*PtrSize ||
+					offsetof(Finalizer, fint) != 3*PtrSize ||
+					offsetof(Finalizer, ot) != 4*PtrSize ||
+					BitsPerPointer != 2) {
+					runtime·throw("finalizer out of sync");
+				}
+				for(i=0; i<nelem(finptrmask); i++)
+					finptrmask[i] = finalizer1[i%nelem(finalizer1)];
+			}
+		}
+		block = runtime·finc;
+		runtime·finc = block->next;
+		block->next = runtime·finq;
+		runtime·finq = block;
+	}
+	f = &runtime·finq->fin[runtime·finq->cnt];
+	runtime·finq->cnt++;
+	f->fn = fn;
+	f->nret = nret;
+	f->fint = fint;
+	f->ot = ot;
+	f->arg = p;
+	runtime·fingwake = true;
+	runtime·unlock(&runtime·finlock);
+}
+
+void
+runtime·iterate_finq(void (*callback)(FuncVal*, byte*, uintptr, Type*, PtrType*))
+{
+	FinBlock *fb;
+	Finalizer *f;
+	uintptr i;
+
+	for(fb = runtime·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(g->m->locks == 0 && g->m->mallocing == 0 && g != 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, false);
+		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.
+// Returns true if the span was returned to heap.
+// If preserve=true, don't return it to heap nor relink in MCentral lists;
+// caller takes care of it.
+bool
+runtime·MSpan_Sweep(MSpan *s, bool preserve)
+{
+	int32 cl, n, npages, nfree;
+	uintptr size, off, step;
+	uint32 sweepgen;
+	byte *p, *bitp, shift, xbits, bits;
+	MCache *c;
+	byte *arena_start;
+	MLink head, *end, *link;
+	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(g->m->locks == 0 && g->m->mallocing == 0 && g != 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;
+	cl = s->sizeclass;
+	size = s->elemsize;
+	if(cl == 0) {
+		n = 1;
+	} else {
+		// Chunk full of small blocks.
+		npages = runtime·class_to_allocnpages[cl];
+		n = (npages << PageShift) / size;
+	}
+	res = false;
+	nfree = 0;
+	end = &head;
+	c = g->m->mcache;
+	sweepgenset = false;
+
+	// Mark any free objects in this span so we don't collect them.
+	for(link = s->freelist; link != nil; link = link->next) {
+		off = (uintptr*)link - (uintptr*)arena_start;
+		bitp = arena_start - off/wordsPerBitmapByte - 1;
+		shift = (off % wordsPerBitmapByte) * gcBits;
+		*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 = arena_start - off/wordsPerBitmapByte - 1;
+		shift = (off % wordsPerBitmapByte) * gcBits;
+		bits = (*bitp>>shift) & bitMask;
+		if((bits&bitMarked) == 0) {
+			// 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;
+		}
+	}
+
+	// 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);
+	// Find bits for the beginning of the span.
+	off = (uintptr*)p - (uintptr*)arena_start;
+	bitp = arena_start - off/wordsPerBitmapByte - 1;
+	shift = 0;
+	step = size/(PtrSize*wordsPerBitmapByte);
+	// Rewind to the previous quadruple as we move to the next
+	// in the beginning of the loop.
+	bitp += step;
+	if(step == 0) {
+		// 8-byte objects.
+		bitp++;
+		shift = gcBits;
+	}
+	for(; n > 0; n--, p += size) {
+		bitp -= step;
+		if(step == 0) {
+			if(shift != 0)
+				bitp--;
+			shift = gcBits - shift;
+		}
+
+		xbits = *bitp;
+		bits = (xbits>>shift) & bitMask;
+
+		// Allocated and marked object, reset bits to allocated.
+		if((bits&bitMarked) != 0) {
+			*bitp &= ~(bitMarked<<shift);
+			continue;
+		}
+		// At this point we know that we are looking at garbage object
+		// that needs to be collected.
+		if(runtime·debug.allocfreetrace)
+			runtime·tracefree(p, size);
+		// Reset to allocated+noscan.
+		*bitp = (xbits & ~((bitMarked|(BitsMask<<2))<<shift)) | ((uintptr)BitsDead<<(shift+2));
+		if(cl == 0) {
+			// Free large span.
+			if(preserve)
+				runtime·throw("can't preserve large span");
+			runtime·unmarkspan(p, s->npages<<PageShift);
+			s->needzero = 1;
+			// important to set sweepgen before returning it to heap
+			runtime·atomicstore(&s->sweepgen, sweepgen);
+			sweepgenset = true;
+			// 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) {
+				s->limit = nil;	// prevent mlookup from finding this span
+				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 * (runtime·gcpercent + 100)/100));
+			res = true;
+		} else {
+			// Free small object.
+			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++;
+		}
+	}
+
+	// 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·xadd64(&mstats.next_gc, -(uint64)(nfree * size * (runtime·gcpercent + 100)/100));
+		res = runtime·MCentral_FreeSpan(&runtime·mheap.central[cl].mcentral, s, nfree, head.next, end, preserve);
+		// MCentral_FreeSpan updates sweepgen
+	}
+	return res;
+}
+
+// State of background runtime·sweep.
+// Protected by runtime·gclock.
+typedef struct SweepData SweepData;
+struct SweepData
+{
+	G*	g;
+	bool	parked;
+
+	uint32	spanidx;	// background sweeper position
+
+	uint32	nbgsweep;
+	uint32	npausesweep;
+};
+SweepData runtime·sweep;
+
+// 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
+	g->m->locks++;
+	sg = runtime·mheap.sweepgen;
+	for(;;) {
+		idx = runtime·xadd(&runtime·sweep.spanidx, 1) - 1;
+		if(idx >= runtime·work.nspan) {
+			runtime·mheap.sweepdone = true;
+			g->m->locks--;
+			return -1;
+		}
+		s = runtime·work.spans[idx];
+		if(s->state != MSpanInUse) {
+			s->sweepgen = sg;
+			continue;
+		}
+		if(s->sweepgen != sg-2 || !runtime·cas(&s->sweepgen, sg-2, sg-1))
+			continue;
+		npages = s->npages;
+		if(!runtime·MSpan_Sweep(s, false))
+			npages = 0;
+		g->m->locks--;
+		return npages;
+	}
+}
+
+static void
+sweepone_m(void)
+{
+	g->m->scalararg[0] = runtime·sweepone();
+}
+
+#pragma textflag NOSPLIT
+uintptr
+runtime·gosweepone(void)
+{
+	void (*fn)(void);
+	
+	fn = sweepone_m;
+	runtime·onM(&fn);
+	return g->m->scalararg[0];
+}
+
+#pragma textflag NOSPLIT
+bool
+runtime·gosweepdone(void)
+{
+	return runtime·mheap.sweepdone;
+}
+
+void
+runtime·gchelper(void)
+{
+	uint32 nproc;
+
+	g->m->traceback = 2;
+	gchelperstart();
+
+	// parallel mark for over gc roots
+	runtime·parfordo(runtime·work.markfor);
+
+	// help other threads scan secondary blocks
+	scanblock(nil, 0, nil);
+
+	nproc = runtime·work.nproc;  // runtime·work.nproc can change right after we increment runtime·work.ndone
+	if(runtime·xadd(&runtime·work.ndone, +1) == nproc-1)
+		runtime·notewakeup(&runtime·work.alldone);
+	g->m->traceback = 0;
+}
+
+static void
+cachestats(void)
+{
+	MCache *c;
+	P *p, **pp;
+
+	for(pp=runtime·allp; p=*pp; pp++) {
+		c = p->mcache;
+		if(c==nil)
+			continue;
+		runtime·purgecachedstats(c);
+	}
+}
+
+static void
+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);
+		runtime·stackcache_clear(c);
+	}
+}
+
+static void
+flushallmcaches_m(G *gp)
+{
+	flushallmcaches();
+	runtime·gogo(&gp->sched);
+}
+
+void
+runtime·updatememstats(GCStats *stats)
+{
+	M *mp;
+	MSpan *s;
+	int32 i;
+	uint64 smallfree;
+	uint64 *src, *dst;
+	void (*fn)(G*);
+
+	if(stats)
+		runtime·memclr((byte*)stats, sizeof(*stats));
+	for(mp=runtime·allm; mp; mp=mp->alllink) {
+		if(stats) {
+			src = (uint64*)&mp->gcstats;
+			dst = (uint64*)stats;
+			for(i=0; i<sizeof(*stats)/sizeof(uint64); i++)
+				dst[i] += src[i];
+			runtime·memclr((byte*)&mp->gcstats, sizeof(mp->gcstats));
+		}
+	}
+	mstats.mcache_inuse = runtime·mheap.cachealloc.inuse;
+	mstats.mspan_inuse = runtime·mheap.spanalloc.inuse;
+	mstats.sys = mstats.heap_sys + mstats.stacks_sys + mstats.mspan_sys +
+		mstats.mcache_sys + mstats.buckhash_sys + mstats.gc_sys + mstats.other_sys;
+	
+	// Calculate memory allocator stats.
+	// During program execution we only count number of frees and amount of freed memory.
+	// Current number of alive object in the heap and amount of alive heap memory
+	// are calculated by scanning all spans.
+	// Total number of mallocs is calculated as number of frees plus number of alive objects.
+	// Similarly, total amount of allocated memory is calculated as amount of freed memory
+	// plus amount of alive heap memory.
+	mstats.alloc = 0;
+	mstats.total_alloc = 0;
+	mstats.nmalloc = 0;
+	mstats.nfree = 0;
+	for(i = 0; i < nelem(mstats.by_size); i++) {
+		mstats.by_size[i].nmalloc = 0;
+		mstats.by_size[i].nfree = 0;
+	}
+
+	// Flush MCache's to MCentral.
+	if(g == g->m->g0)
+		flushallmcaches();
+	else {
+		fn = flushallmcaches_m;
+		runtime·mcall(&fn);
+	}
+
+	// Aggregate local stats.
+	cachestats();
+
+	// Scan all spans and count number of alive objects.
+	runtime·lock(&runtime·mheap.lock);
+	for(i = 0; i < runtime·mheap.nspan; i++) {
+		s = runtime·mheap.allspans[i];
+		if(s->state != MSpanInUse)
+			continue;
+		if(s->sizeclass == 0) {
+			mstats.nmalloc++;
+			mstats.alloc += s->elemsize;
+		} else {
+			mstats.nmalloc += s->ref;
+			mstats.by_size[s->sizeclass].nmalloc += s->ref;
+			mstats.alloc += s->ref*s->elemsize;
+		}
+	}
+	runtime·unlock(&runtime·mheap.lock);
+
+	// Aggregate by size class.
+	smallfree = 0;
+	mstats.nfree = runtime·mheap.nlargefree;
+	for(i = 0; i < nelem(mstats.by_size); i++) {
+		mstats.nfree += runtime·mheap.nsmallfree[i];
+		mstats.by_size[i].nfree = runtime·mheap.nsmallfree[i];
+		mstats.by_size[i].nmalloc += runtime·mheap.nsmallfree[i];
+		smallfree += runtime·mheap.nsmallfree[i] * runtime·class_to_size[i];
+	}
+	mstats.nfree += mstats.tinyallocs;
+	mstats.nmalloc += mstats.nfree;
+
+	// Calculate derived stats.
+	mstats.total_alloc = mstats.alloc + runtime·mheap.largefree + smallfree;
+	mstats.heap_alloc = mstats.alloc;
+	mstats.heap_objects = mstats.nmalloc - mstats.nfree;
+}
+
+// Structure of arguments passed to function gc().
+// This allows the arguments to be passed via runtime·mcall.
+struct gc_args
+{
+	int64 start_time; // start time of GC in ns (just before stoptheworld)
+	bool  eagersweep;
+};
+
+static void gc(struct gc_args *args);
+
+int32
+runtime·readgogc(void)
+{
+	byte *p;
+
+	p = runtime·getenv("GOGC");
+	if(p == nil || p[0] == '\0')
+		return 100;
+	if(runtime·strcmp(p, (byte*)"off") == 0)
+		return -1;
+	return runtime·atoi(p);
+}
+
+void
+runtime·gcinit(void)
+{
+	if(sizeof(Workbuf) != WorkbufSize)
+		runtime·throw("runtime: size of Workbuf is suboptimal");
+
+	runtime·work.markfor = runtime·parforalloc(MaxGcproc);
+	runtime·gcpercent = runtime·readgogc();
+	runtime·gcdatamask = unrollglobgcprog(runtime·gcdata, runtime·edata - runtime·data);
+	runtime·gcbssmask = unrollglobgcprog(runtime·gcbss, runtime·ebss - runtime·bss);
+}
+
+void
+runtime·gc_m(void)
+{
+	struct gc_args a;
+	G *gp;
+
+	gp = g->m->curg;
+	runtime·casgstatus(gp, Grunning, Gwaiting);
+	gp->waitreason = runtime·gostringnocopy((byte*)"garbage collection");
+
+	a.start_time = (uint64)(g->m->scalararg[0]) | ((uint64)(g->m->scalararg[1]) << 32);
+	a.eagersweep = g->m->scalararg[2];
+	gc(&a);
+
+	if(nbadblock > 0) {
+		// Work out path from root to bad block.
+		for(;;) {
+			gc(&a);
+			if(nbadblock >= nelem(badblock))
+				runtime·throw("cannot find path to bad pointer");
+		}
+	}
+
+	runtime·casgstatus(gp, Gwaiting, Grunning);
+}
+
+static void
+gc(struct gc_args *args)
+{
+	int64 t0, t1, t2, t3, t4;
+	uint64 heap0, heap1, obj;
+	GCStats stats;
+
+	if(DebugPtrs)
+		runtime·printf("GC start\n");
+
+	if(runtime·debug.allocfreetrace)
+		runtime·tracegc();
+
+	g->m->traceback = 2;
+	t0 = args->start_time;
+	runtime·work.tstart = args->start_time; 
+
+	t1 = 0;
+	if(runtime·debug.gctrace)
+		t1 = runtime·nanotime();
+
+	// Sweep what is not sweeped by bgsweep.
+	while(runtime·sweepone() != -1)
+		runtime·sweep.npausesweep++;
+
+	// Cache runtime.mheap.allspans in work.spans to avoid conflicts with
+	// resizing/freeing allspans.
+	// New spans can be created while GC progresses, but they are not garbage for
+	// this round:
+	//  - new stack spans can be created even while the world is stopped.
+	//  - new malloc spans can be created during the concurrent sweep
+
+	// Even if this is stop-the-world, a concurrent exitsyscall can allocate a stack from heap.
+	runtime·lock(&runtime·mheap.lock);
+	// Free the old cached sweep array if necessary.
+	if(runtime·work.spans != nil && runtime·work.spans != runtime·mheap.allspans)
+		runtime·SysFree(runtime·work.spans, runtime·work.nspan*sizeof(runtime·work.spans[0]), &mstats.other_sys);
+	// Cache the current array for marking.
+	runtime·mheap.gcspans = runtime·mheap.allspans;
+	runtime·work.spans = runtime·mheap.allspans;
+	runtime·work.nspan = runtime·mheap.nspan;
+	runtime·unlock(&runtime·mheap.lock);
+
+	runtime·work.nwait = 0;
+	runtime·work.ndone = 0;
+	runtime·work.nproc = runtime·gcprocs();
+	runtime·parforsetup(runtime·work.markfor, runtime·work.nproc, RootCount + runtime·allglen, nil, false, markroot);
+	if(runtime·work.nproc > 1) {
+		runtime·noteclear(&runtime·work.alldone);
+		runtime·helpgc(runtime·work.nproc);
+	}
+
+	t2 = 0;
+	if(runtime·debug.gctrace)
+		t2 = runtime·nanotime();
+
+	gchelperstart();
+	runtime·parfordo(runtime·work.markfor);
+	scanblock(nil, 0, nil);
+
+	t3 = 0;
+	if(runtime·debug.gctrace)
+		t3 = runtime·nanotime();
+
+	if(runtime·work.nproc > 1)
+		runtime·notesleep(&runtime·work.alldone);
+
+	runtime·shrinkfinish();
+
+	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/(runtime·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*runtime·gcpercent/100;
+
+	t4 = runtime·nanotime();
+	runtime·atomicstore64(&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_end[mstats.numgc%nelem(mstats.pause_end)] = t4;
+	mstats.pause_total_ns += t4 - t0;
+	mstats.numgc++;
+	if(mstats.debuggc)
+		runtime·printf("pause %D\n", t4-t0);
+
+	if(runtime·debug.gctrace) {
+		heap1 = mstats.heap_alloc;
+		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 += runtime·work.markfor->nprocyield;
+		stats.nosyield += runtime·work.markfor->nosyield;
+		stats.nsleep += runtime·work.markfor->nsleep;
+
+		runtime·printf("gc%d(%d): %D+%D+%D+%D us, %D -> %D MB, %D (%D-%D) objects,"
+				" %d goroutines,"
+				" %d/%d/%d sweeps,"
+				" %D(%D) handoff, %D(%D) steal, %D/%D/%D yields\n",
+			mstats.numgc, runtime·work.nproc, (t1-t0)/1000, (t2-t1)/1000, (t3-t2)/1000, (t4-t3)/1000,
+			heap0>>20, heap1>>20, obj,
+			mstats.nmalloc, mstats.nfree,
+			runtime·gcount(),
+			runtime·work.nspan, runtime·sweep.nbgsweep, runtime·sweep.npausesweep,
+			stats.nhandoff, stats.nhandoffcnt,
+			runtime·work.markfor->nsteal, runtime·work.markfor->nstealcnt,
+			stats.nprocyield, stats.nosyield, stats.nsleep);
+		runtime·sweep.nbgsweep = runtime·sweep.npausesweep = 0;
+	}
+
+	// See the comment in the beginning of this function as to why we need the following.
+	// Even if this is still stop-the-world, a concurrent exitsyscall can allocate a stack from heap.
+	runtime·lock(&runtime·mheap.lock);
+	// Free the old cached mark array if necessary.
+	if(runtime·work.spans != nil && runtime·work.spans != runtime·mheap.allspans)
+		runtime·SysFree(runtime·work.spans, runtime·work.nspan*sizeof(runtime·work.spans[0]), &mstats.other_sys);
+	// Cache the current array for sweeping.
+	runtime·mheap.gcspans = runtime·mheap.allspans;
+	runtime·mheap.sweepgen += 2;
+	runtime·mheap.sweepdone = false;
+	runtime·work.spans = runtime·mheap.allspans;
+	runtime·work.nspan = runtime·mheap.nspan;
+	runtime·sweep.spanidx = 0;
+	runtime·unlock(&runtime·mheap.lock);
+
+	if(ConcurrentSweep && !args->eagersweep) {
+		runtime·lock(&runtime·gclock);
+		if(runtime·sweep.g == nil)
+			runtime·sweep.g = runtime·newproc1(&bgsweepv, nil, 0, 0, gc);
+		else if(runtime·sweep.parked) {
+			runtime·sweep.parked = false;
+			runtime·ready(runtime·sweep.g);
+		}
+		runtime·unlock(&runtime·gclock);
+	} else {
+		// Sweep all spans eagerly.
+		while(runtime·sweepone() != -1)
+			runtime·sweep.npausesweep++;
+		// Do an additional mProf_GC, because all 'free' events are now real as well.
+		runtime·mProf_GC();
+	}
+
+	runtime·mProf_GC();
+	g->m->traceback = 0;
+
+	if(DebugPtrs)
+		runtime·printf("GC end\n");
+}
+
+extern uintptr runtime·sizeof_C_MStats;
+
+static void readmemstats_m(void);
+
+void
+runtime·readmemstats_m(void)
+{
+	MStats *stats;
+	
+	stats = g->m->ptrarg[0];
+	g->m->ptrarg[0] = nil;
+
+	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·memmove(stats, &mstats, runtime·sizeof_C_MStats);
+
+	// Stack numbers are part of the heap numbers, separate those out for user consumption
+	stats->stacks_sys = stats->stacks_inuse;
+	stats->heap_inuse -= stats->stacks_inuse;
+	stats->heap_sys -= stats->stacks_inuse;
+}
+
+static void readgcstats_m(void);
+
+#pragma textflag NOSPLIT
+void
+runtime∕debug·readGCStats(Slice *pauses)
+{
+	void (*fn)(void);
+	
+	g->m->ptrarg[0] = pauses;
+	fn = readgcstats_m;
+	runtime·onM(&fn);
+}
+
+static void
+readgcstats_m(void)
+{
+	Slice *pauses;	
+	uint64 *p;
+	uint32 i, j, n;
+	
+	pauses = g->m->ptrarg[0];
+	g->m->ptrarg[0] = nil;
+
+	// Calling code in runtime/debug should make the slice large enough.
+	if(pauses->cap < nelem(mstats.pause_ns)+3)
+		runtime·throw("runtime: short slice passed to readGCStats");
+
+	// Pass back: pauses, pause ends, last gc (absolute time), number of gc, total pause ns.
+	p = (uint64*)pauses->array;
+	runtime·lock(&runtime·mheap.lock);
+
+	n = mstats.numgc;
+	if(n > nelem(mstats.pause_ns))
+		n = nelem(mstats.pause_ns);
+
+	// The pause buffer is circular. The most recent pause is at
+	// pause_ns[(numgc-1)%nelem(pause_ns)], and then backward
+	// from there to go back farther in time. We deliver the times
+	// most recent first (in p[0]).
+	for(i=0; i<n; i++) {
+		j = (mstats.numgc-1-i)%nelem(mstats.pause_ns);
+		p[i] = mstats.pause_ns[j];
+		p[n+i] = mstats.pause_end[j];
+	}
+
+	p[n+n] = mstats.last_gc;
+	p[n+n+1] = mstats.numgc;
+	p[n+n+2] = mstats.pause_total_ns;	
+	runtime·unlock(&runtime·mheap.lock);
+	pauses->len = n+n+3;
+}
+
+void
+runtime·setgcpercent_m(void)
+{
+	int32 in;
+	int32 out;
+
+	in = (int32)(intptr)g->m->scalararg[0];
+
+	runtime·lock(&runtime·mheap.lock);
+	out = runtime·gcpercent;
+	if(in < 0)
+		in = -1;
+	runtime·gcpercent = in;
+	runtime·unlock(&runtime·mheap.lock);
+
+	g->m->scalararg[0] = (uintptr)(intptr)out;
+}
+
+static void
+gchelperstart(void)
+{
+	if(g->m->helpgc < 0 || g->m->helpgc >= MaxGcproc)
+		runtime·throw("gchelperstart: bad m->helpgc");
+	if(g != g->m->g0)
+		runtime·throw("gchelper not running on g0 stack");
+}
+
+G*
+runtime·wakefing(void)
+{
+	G *res;
+
+	res = nil;
+	runtime·lock(&runtime·finlock);
+	if(runtime·fingwait && runtime·fingwake) {
+		runtime·fingwait = false;
+		runtime·fingwake = false;
+		res = runtime·fing;
+	}
+	runtime·unlock(&runtime·finlock);
+	return res;
+}
+
+// Recursively unrolls GC program in prog.
+// mask is where to store the result.
+// ppos is a pointer to position in mask, in bits.
+// sparse says to generate 4-bits per word mask for heap (2-bits for data/bss otherwise).
+static byte*
+unrollgcprog1(byte *mask, byte *prog, uintptr *ppos, bool inplace, bool sparse)
+{
+	uintptr pos, siz, i, off;
+	byte *arena_start, *prog1, v, *bitp, shift;
+
+	arena_start = runtime·mheap.arena_start;
+	pos = *ppos;
+	for(;;) {
+		switch(prog[0]) {
+		case insData:
+			prog++;
+			siz = prog[0];
+			prog++;
+			for(i = 0; i < siz; i++) {
+				v = prog[i/PointersPerByte];
+				v >>= (i%PointersPerByte)*BitsPerPointer;
+				v &= BitsMask;
+				if(inplace) {
+					// Store directly into GC bitmap.
+					off = (uintptr*)(mask+pos) - (uintptr*)arena_start;
+					bitp = arena_start - off/wordsPerBitmapByte - 1;
+					shift = (off % wordsPerBitmapByte) * gcBits;
+					if(shift==0)
+						*bitp = 0;
+					*bitp |= v<<(shift+2);
+					pos += PtrSize;
+				} else if(sparse) {
+					// 4-bits per word
+					v <<= (pos%8)+2;
+					mask[pos/8] |= v;
+					pos += gcBits;
+				} else {
+					// 2-bits per word
+					v <<= pos%8;
+					mask[pos/8] |= v;
+					pos += BitsPerPointer;
+				}
+			}
+			prog += ROUND(siz*BitsPerPointer, 8)/8;
+			break;
+		case insArray:
+			prog++;
+			siz = 0;
+			for(i = 0; i < PtrSize; i++)
+				siz = (siz<<8) + prog[PtrSize-i-1];
+			prog += PtrSize;
+			prog1 = nil;
+			for(i = 0; i < siz; i++)
+				prog1 = unrollgcprog1(mask, prog, &pos, inplace, sparse);
+			if(prog1[0] != insArrayEnd)
+				runtime·throw("unrollgcprog: array does not end with insArrayEnd");
+			prog = prog1+1;
+			break;
+		case insArrayEnd:
+		case insEnd:
+			*ppos = pos;
+			return prog;
+		default:
+			runtime·throw("unrollgcprog: unknown instruction");
+		}
+	}
+}
+
+// Unrolls GC program prog for data/bss, returns dense GC mask.
+static BitVector
+unrollglobgcprog(byte *prog, uintptr size)
+{
+	byte *mask;
+	uintptr pos, masksize;
+
+	masksize = ROUND(ROUND(size, PtrSize)/PtrSize*BitsPerPointer, 8)/8;
+	mask = runtime·persistentalloc(masksize+1, 0, &mstats.gc_sys);
+	mask[masksize] = 0xa1;
+	pos = 0;
+	prog = unrollgcprog1(mask, prog, &pos, false, false);
+	if(pos != size/PtrSize*BitsPerPointer) {
+		runtime·printf("unrollglobgcprog: bad program size, got %D, expect %D\n",
+			(uint64)pos, (uint64)size/PtrSize*BitsPerPointer);
+		runtime·throw("unrollglobgcprog: bad program size");
+	}
+	if(prog[0] != insEnd)
+		runtime·throw("unrollglobgcprog: program does not end with insEnd");
+	if(mask[masksize] != 0xa1)
+		runtime·throw("unrollglobgcprog: overflow");
+	return (BitVector){masksize*8, mask};
+}
+
+void
+runtime·unrollgcproginplace_m(void)
+{
+	uintptr size, size0, pos, off;
+	byte *arena_start, *prog, *bitp, shift;
+	Type *typ;
+	void *v;
+
+	v = g->m->ptrarg[0];
+	typ = g->m->ptrarg[1];
+	size = g->m->scalararg[0];
+	size0 = g->m->scalararg[1];
+	g->m->ptrarg[0] = nil;
+	g->m->ptrarg[1] = nil;
+
+	pos = 0;
+	prog = (byte*)typ->gc[1];
+	while(pos != size0)
+		unrollgcprog1(v, prog, &pos, true, true);
+	// Mark first word as bitAllocated.
+	arena_start = runtime·mheap.arena_start;
+	off = (uintptr*)v - (uintptr*)arena_start;
+	bitp = arena_start - off/wordsPerBitmapByte - 1;
+	shift = (off % wordsPerBitmapByte) * gcBits;
+	*bitp |= bitBoundary<<shift;
+	// Mark word after last as BitsDead.
+	if(size0 < size) {
+		off = (uintptr*)((byte*)v + size0) - (uintptr*)arena_start;
+		bitp = arena_start - off/wordsPerBitmapByte - 1;
+		shift = (off % wordsPerBitmapByte) * gcBits;
+		*bitp &= ~(bitPtrMask<<shift) | ((uintptr)BitsDead<<(shift+2));
+	}
+}
+
+// Unrolls GC program in typ->gc[1] into typ->gc[0]
+void
+runtime·unrollgcprog_m(void)
+{
+	static Mutex lock;
+	Type *typ;
+	byte *mask, *prog;
+	uintptr pos;
+	uint32 x;
+
+	typ = g->m->ptrarg[0];
+	g->m->ptrarg[0] = nil;
+
+	runtime·lock(&lock);
+	mask = (byte*)typ->gc[0];
+	if(mask[0] == 0) {
+		pos = 8;  // skip the unroll flag
+		prog = (byte*)typ->gc[1];
+		prog = unrollgcprog1(mask, prog, &pos, false, true);
+		if(prog[0] != insEnd)
+			runtime·throw("unrollgcprog: program does not end with insEnd");
+		if(((typ->size/PtrSize)%2) != 0) {
+			// repeat the program twice
+			prog = (byte*)typ->gc[1];
+			unrollgcprog1(mask, prog, &pos, false, true);
+		}
+		// atomic way to say mask[0] = 1
+		x = ((uint32*)mask)[0];
+		runtime·atomicstore((uint32*)mask, x|1);
+	}
+	runtime·unlock(&lock);
+}
+
+// mark the span of memory at v as having n blocks of the given size.
+// if leftover is true, there is left over space at the end of the span.
+void
+runtime·markspan(void *v, uintptr size, uintptr n, bool leftover)
+{
+	uintptr i, off, step;
+	byte *b;
+
+	if((byte*)v+size*n > (byte*)runtime·mheap.arena_used || (byte*)v < runtime·mheap.arena_start)
+		runtime·throw("markspan: bad pointer");
+
+	// Find bits of the beginning of the span.
+	off = (uintptr*)v - (uintptr*)runtime·mheap.arena_start;  // word offset
+	b = runtime·mheap.arena_start - off/wordsPerBitmapByte - 1;
+	if((off%wordsPerBitmapByte) != 0)
+		runtime·throw("markspan: unaligned length");
+
+	// Okay to use non-atomic ops here, because we control
+	// the entire span, and each bitmap byte has bits for only
+	// one span, so no other goroutines are changing these bitmap words.
+
+	if(size == PtrSize) {
+		// Possible only on 64-bits (minimal size class is 8 bytes).
+		// Poor man's memset(0x11).
+		if(0x11 != ((bitBoundary+BitsDead)<<gcBits) + (bitBoundary+BitsDead))
+			runtime·throw("markspan: bad bits");
+		if((n%(wordsPerBitmapByte*PtrSize)) != 0)
+			runtime·throw("markspan: unaligned length");
+		b = b - n/wordsPerBitmapByte + 1;	// find first byte
+		if(((uintptr)b%PtrSize) != 0)
+			runtime·throw("markspan: unaligned pointer");
+		for(i = 0; i != n; i += wordsPerBitmapByte*PtrSize, b += PtrSize)
+			*(uintptr*)b = (uintptr)0x1111111111111111ULL;  // bitBoundary+BitsDead
+		return;
+	}
+
+	if(leftover)
+		n++;	// mark a boundary just past end of last block too
+	step = size/(PtrSize*wordsPerBitmapByte);
+	for(i = 0; i != n; i++, b -= step)
+		*b = bitBoundary|(BitsDead<<2);
+}
+
+// unmark the span of memory at v of length n bytes.
+void
+runtime·unmarkspan(void *v, uintptr n)
+{
+	uintptr off;
+	byte *b;
+
+	if((byte*)v+n > (byte*)runtime·mheap.arena_used || (byte*)v < runtime·mheap.arena_start)
+		runtime·throw("markspan: bad pointer");
+
+	off = (uintptr*)v - (uintptr*)runtime·mheap.arena_start;  // word offset
+	if((off % (PtrSize*wordsPerBitmapByte)) != 0)
+		runtime·throw("markspan: unaligned pointer");
+	b = runtime·mheap.arena_start - off/wordsPerBitmapByte - 1;
+	n /= PtrSize;
+	if(n%(PtrSize*wordsPerBitmapByte) != 0)
+		runtime·throw("unmarkspan: unaligned length");
+	// Okay to use non-atomic ops here, because we control
+	// the entire span, and each bitmap word has bits for only
+	// one span, so no other goroutines are changing these
+	// bitmap words.
+	n /= wordsPerBitmapByte;
+	runtime·memclr(b - n + 1, n);
+}
+
+void
+runtime·MHeap_MapBits(MHeap *h)
+{
+	// Caller has added extra mappings to the arena.
+	// Add extra mappings of bitmap words as needed.
+	// We allocate extra bitmap pieces in chunks of bitmapChunk.
+	enum {
+		bitmapChunk = 8192
+	};
+	uintptr n;
+
+	n = (h->arena_used - h->arena_start) / (PtrSize*wordsPerBitmapByte);
+	n = ROUND(n, bitmapChunk);
+	n = ROUND(n, PhysPageSize);
+	if(h->bitmap_mapped >= n)
+		return;
+
+	runtime·SysMap(h->arena_start - n, n - h->bitmap_mapped, h->arena_reserved, &mstats.gc_sys);
+	h->bitmap_mapped = n;
+}
+
+static bool
+getgcmaskcb(Stkframe *frame, void *ctxt)
+{
+	Stkframe *frame0;
+
+	frame0 = ctxt;
+	if(frame->sp <= frame0->sp && frame0->sp < frame->varp) {
+		*frame0 = *frame;
+		return false;
+	}
+	return true;
+}
+
+// Returns GC type info for object p for testing.
+void
+runtime·getgcmask(byte *p, Type *t, byte **mask, uintptr *len)
+{
+	Stkframe frame;
+	uintptr i, n, off;
+	byte *base, bits, shift, *b;
+	bool (*cb)(Stkframe*, void*);
+
+	*mask = nil;
+	*len = 0;
+
+	// data
+	if(p >= runtime·data && p < runtime·edata) {
+		n = ((PtrType*)t)->elem->size;
+		*len = n/PtrSize;
+		*mask = runtime·mallocgc(*len, nil, FlagNoScan);
+		for(i = 0; i < n; i += PtrSize) {
+			off = (p+i-runtime·data)/PtrSize;
+			bits = (runtime·gcdatamask.bytedata[off/PointersPerByte] >> ((off%PointersPerByte)*BitsPerPointer))&BitsMask;
+			(*mask)[i/PtrSize] = bits;
+		}
+		return;
+	}
+	// bss
+	if(p >= runtime·bss && p < runtime·ebss) {
+		n = ((PtrType*)t)->elem->size;
+		*len = n/PtrSize;
+		*mask = runtime·mallocgc(*len, nil, FlagNoScan);
+		for(i = 0; i < n; i += PtrSize) {
+			off = (p+i-runtime·bss)/PtrSize;
+			bits = (runtime·gcbssmask.bytedata[off/PointersPerByte] >> ((off%PointersPerByte)*BitsPerPointer))&BitsMask;
+			(*mask)[i/PtrSize] = bits;
+		}
+		return;
+	}
+	// heap
+	if(runtime·mlookup(p, &base, &n, nil)) {
+		*len = n/PtrSize;
+		*mask = runtime·mallocgc(*len, nil, FlagNoScan);
+		for(i = 0; i < n; i += PtrSize) {
+			off = (uintptr*)(base+i) - (uintptr*)runtime·mheap.arena_start;
+			b = runtime·mheap.arena_start - off/wordsPerBitmapByte - 1;
+			shift = (off % wordsPerBitmapByte) * gcBits;
+			bits = (*b >> (shift+2))&BitsMask;
+			(*mask)[i/PtrSize] = bits;
+		}
+		return;
+	}
+	// stack
+	frame.fn = nil;
+	frame.sp = (uintptr)p;
+	cb = getgcmaskcb;
+	runtime·gentraceback(g->m->curg->sched.pc, g->m->curg->sched.sp, 0, g->m->curg, 0, nil, 1000, &cb, &frame, 0);
+	if(frame.fn != nil) {
+		Func *f;
+		StackMap *stackmap;
+		BitVector bv;
+		uintptr size;
+		uintptr targetpc;
+		int32 pcdata;
+
+		f = frame.fn;
+		targetpc = frame.continpc;
+		if(targetpc == 0)
+			return;
+		if(targetpc != f->entry)
+			targetpc--;
+		pcdata = runtime·pcdatavalue(f, PCDATA_StackMapIndex, targetpc);
+		if(pcdata == -1)
+			return;
+		stackmap = runtime·funcdata(f, FUNCDATA_LocalsPointerMaps);
+		if(stackmap == nil || stackmap->n <= 0)
+			return;
+		bv = runtime·stackmapdata(stackmap, pcdata);
+		size = bv.n/BitsPerPointer*PtrSize;
+		n = ((PtrType*)t)->elem->size;
+		*len = n/PtrSize;
+		*mask = runtime·mallocgc(*len, nil, FlagNoScan);
+		for(i = 0; i < n; i += PtrSize) {
+			off = (p+i-(byte*)frame.varp+size)/PtrSize;
+			bits = (bv.bytedata[off*BitsPerPointer/8] >> ((off*BitsPerPointer)%8))&BitsMask;
+			(*mask)[i/PtrSize] = bits;
+		}
+	}
+}
+
+void runtime·gc_unixnanotime(int64 *now);
+
+int64
+runtime·unixnanotime(void)
+{
+	int64 now;
+
+	runtime·gc_unixnanotime(&now);
+	return now;
+}
diff --git a/src/runtime/mgc0.go b/src/runtime/mgc0.go
new file mode 100644
index 0000000..cbf5e9c
--- /dev/null
+++ b/src/runtime/mgc0.go
@@ -0,0 +1,152 @@
+// 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 runtime
+
+import "unsafe"
+
+// Called from C. Returns the Go type *m.
+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 gc_unixnanotime(now *int64) {
+	sec, nsec := timenow()
+	*now = sec*1e9 + int64(nsec)
+}
+
+func freeOSMemory() {
+	gogc(2) // force GC and do eager sweep
+	onM(scavenge_m)
+}
+
+var poolcleanup func()
+
+func registerPoolCleanup(f func()) {
+	poolcleanup = f
+}
+
+func clearpools() {
+	// clear sync.Pools
+	if poolcleanup != nil {
+		poolcleanup()
+	}
+
+	for _, p := range &allp {
+		if p == nil {
+			break
+		}
+		// clear tinyalloc pool
+		if c := p.mcache; c != nil {
+			c.tiny = nil
+			c.tinysize = 0
+
+			// disconnect cached list before dropping it on the floor,
+			// so that a dangling ref to one entry does not pin all of them.
+			var sg, sgnext *sudog
+			for sg = c.sudogcache; sg != nil; sg = sgnext {
+				sgnext = sg.next
+				sg.next = nil
+			}
+			c.sudogcache = nil
+		}
+
+		// clear defer pools
+		for i := range p.deferpool {
+			// disconnect cached list before dropping it on the floor,
+			// so that a dangling ref to one entry does not pin all of them.
+			var d, dlink *_defer
+			for d = p.deferpool[i]; d != nil; d = dlink {
+				dlink = d.link
+				d.link = nil
+			}
+			p.deferpool[i] = nil
+		}
+	}
+}
+
+func gosweepone() uintptr
+func gosweepdone() bool
+
+func bgsweep() {
+	getg().issystem = true
+	for {
+		for gosweepone() != ^uintptr(0) {
+			sweep.nbgsweep++
+			Gosched()
+		}
+		lock(&gclock)
+		if !gosweepdone() {
+			// This can happen if a GC runs between
+			// gosweepone returning ^0 above
+			// and the lock being acquired.
+			unlock(&gclock)
+			continue
+		}
+		sweep.parked = true
+		goparkunlock(&gclock, "GC sweep wait")
+	}
+}
+
+// NOTE: Really dst *unsafe.Pointer, src unsafe.Pointer,
+// but if we do that, Go inserts a write barrier on *dst = src.
+//go:nosplit
+func writebarrierptr(dst *uintptr, src uintptr) {
+	*dst = src
+}
+
+//go:nosplit
+func writebarrierstring(dst *[2]uintptr, src [2]uintptr) {
+	dst[0] = src[0]
+	dst[1] = src[1]
+}
+
+//go:nosplit
+func writebarrierslice(dst *[3]uintptr, src [3]uintptr) {
+	dst[0] = src[0]
+	dst[1] = src[1]
+	dst[2] = src[2]
+}
+
+//go:nosplit
+func writebarrieriface(dst *[2]uintptr, src [2]uintptr) {
+	dst[0] = src[0]
+	dst[1] = src[1]
+}
+
+//go:nosplit
+func writebarrierfat2(dst *[2]uintptr, _ *byte, src [2]uintptr) {
+	dst[0] = src[0]
+	dst[1] = src[1]
+}
+
+//go:nosplit
+func writebarrierfat3(dst *[3]uintptr, _ *byte, src [3]uintptr) {
+	dst[0] = src[0]
+	dst[1] = src[1]
+	dst[2] = src[2]
+}
+
+//go:nosplit
+func writebarrierfat4(dst *[4]uintptr, _ *byte, src [4]uintptr) {
+	dst[0] = src[0]
+	dst[1] = src[1]
+	dst[2] = src[2]
+	dst[3] = src[3]
+}
+
+//go:nosplit
+func writebarrierfat(typ *_type, dst, src unsafe.Pointer) {
+	memmove(dst, src, typ.size)
+}
diff --git a/src/runtime/mgc0.h b/src/runtime/mgc0.h
new file mode 100644
index 0000000..64f8189
--- /dev/null
+++ b/src/runtime/mgc0.h
@@ -0,0 +1,78 @@
+// 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.
+
+// Garbage collector (GC)
+
+enum {
+	// Four bits per word (see #defines below).
+	gcBits = 4,
+	wordsPerBitmapByte = 8/gcBits,
+
+	// GC type info programs.
+	// The programs allow to store type info required for GC in a compact form.
+	// Most importantly arrays take O(1) space instead of O(n).
+	// The program grammar is:
+	//
+	// Program = {Block} "insEnd"
+	// Block = Data | Array
+	// Data = "insData" DataSize DataBlock
+	// DataSize = int // size of the DataBlock in bit pairs, 1 byte
+	// DataBlock = binary // dense GC mask (2 bits per word) of size ]DataSize/4[ bytes
+	// Array = "insArray" ArrayLen Block "insArrayEnd"
+	// ArrayLen = int // length of the array, 8 bytes (4 bytes for 32-bit arch)
+	//
+	// Each instruction (insData, insArray, etc) is 1 byte.
+	// For example, for type struct { x []byte; y [20]struct{ z int; w *byte }; }
+	// the program looks as:
+	//
+	// insData 3 (BitsMultiWord BitsSlice BitsScalar)
+	//	insArray 20 insData 2 (BitsScalar BitsPointer) insArrayEnd insEnd
+	//
+	// Total size of the program is 17 bytes (13 bytes on 32-bits).
+	// The corresponding GC mask would take 43 bytes (it would be repeated
+	// because the type has odd number of words).
+	insData = 1,
+	insArray,
+	insArrayEnd,
+	insEnd,
+
+	// Pointer map
+	BitsPerPointer	= 2,
+	BitsMask	= (1<<BitsPerPointer)-1,
+	PointersPerByte	= 8/BitsPerPointer,
+
+	// If you change these, also change scanblock.
+	// scanblock does "if(bits == BitsScalar || bits == BitsDead)" as "if(bits <= BitsScalar)".
+	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.
+	// NOT USED ANYMORE: BitsString	= 0,
+	// NOT USED ANYMORE: BitsSlice	= 1,
+	BitsIface	= 2,
+	BitsEface	= 3,
+
+	// 64 bytes cover objects of size 1024/512 on 64/32 bits, respectively.
+	MaxGCMask	= 64,
+};
+
+// Bits in per-word bitmap.
+// #defines because we shift the values beyond 32 bits.
+//
+// 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 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.)
+enum {
+	bitBoundary = 1, // boundary of an object
+	bitMarked = 2, // marked object
+	bitMask = bitBoundary | bitMarked,
+	bitPtrMask = BitsMask<<2,
+};
diff --git a/src/runtime/mheap.c b/src/runtime/mheap.c
new file mode 100644
index 0000000..bb203d5
--- /dev/null
+++ b/src/runtime/mheap.c
@@ -0,0 +1,889 @@
+// 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.
+
+// Page heap.
+//
+// See malloc.h for overview.
+//
+// When a MSpan is in the heap free list, state == MSpanFree
+// and heapmap(s->start) == span, heapmap(s->start+s->npages-1) == span.
+//
+// When a MSpan is allocated, state == MSpanInUse or MSpanStack
+// and heapmap(i) == span for all s->start <= i < s->start+s->npages.
+
+#include "runtime.h"
+#include "arch_GOARCH.h"
+#include "malloc.h"
+
+static MSpan *MHeap_AllocSpanLocked(MHeap*, uintptr);
+static void MHeap_FreeSpanLocked(MHeap*, MSpan*, bool, bool);
+static bool MHeap_Grow(MHeap*, uintptr);
+static MSpan *MHeap_AllocLarge(MHeap*, uintptr);
+static MSpan *BestFit(MSpan*, uintptr, MSpan*);
+
+static void
+RecordSpan(void *vh, byte *p)
+{
+	MHeap *h;
+	MSpan *s;
+	MSpan **all;
+	uint32 cap;
+
+	h = vh;
+	s = (MSpan*)p;
+	if(h->nspan >= h->nspancap) {
+		cap = 64*1024/sizeof(all[0]);
+		if(cap < h->nspancap*3/2)
+			cap = h->nspancap*3/2;
+		all = (MSpan**)runtime·sysAlloc(cap*sizeof(all[0]), &mstats.other_sys);
+		if(all == nil)
+			runtime·throw("runtime: cannot allocate memory");
+		if(h->allspans) {
+			runtime·memmove(all, h->allspans, h->nspancap*sizeof(all[0]));
+			// Don't free the old array if it's referenced by sweep.
+			// See the comment in mgc0.c.
+			if(h->allspans != runtime·mheap.gcspans)
+				runtime·SysFree(h->allspans, h->nspancap*sizeof(all[0]), &mstats.other_sys);
+		}
+		h->allspans = all;
+		h->nspancap = cap;
+	}
+	h->allspans[h->nspan++] = s;
+}
+
+// Initialize the heap; fetch memory using alloc.
+void
+runtime·MHeap_Init(MHeap *h)
+{
+	uint32 i;
+
+	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++) {
+		runtime·MSpanList_Init(&h->free[i]);
+		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].mcentral, i);
+}
+
+void
+runtime·MHeap_MapSpans(MHeap *h)
+{
+	uintptr n;
+
+	// Map spans array, PageSize at a time.
+	n = (uintptr)h->arena_used;
+	n -= (uintptr)h->arena_start;
+	n = n / PageSize * sizeof(h->spans[0]);
+	n = ROUND(n, PhysPageSize);
+	if(h->spans_mapped >= n)
+		return;
+	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->lock);
+			n += runtime·MSpan_Sweep(s, false);
+			runtime·lock(&h->lock);
+			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->lock);
+	for(;;) {
+		n = runtime·sweepone();
+		if(n == -1)  // all spans are swept
+			break;
+		reclaimed += n;
+		if(reclaimed >= npage)
+			break;
+	}
+	runtime·lock(&h->lock);
+}
+
+// Allocate a new span of npage pages from the heap for GC'd memory
+// and record its size class in the HeapMap and HeapMapCache.
+static MSpan*
+mheap_alloc(MHeap *h, uintptr npage, int32 sizeclass, bool large)
+{
+	MSpan *s;
+
+	if(g != g->m->g0)
+		runtime·throw("mheap_alloc not on M stack");
+	runtime·lock(&h->lock);
+
+	// 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);
+
+	// transfer stats from cache to global
+	mstats.heap_alloc += g->m->mcache->local_cachealloc;
+	g->m->mcache->local_cachealloc = 0;
+	mstats.tinyallocs += g->m->mcache->local_tinyallocs;
+	g->m->mcache->local_tinyallocs = 0;
+
+	s = MHeap_AllocSpanLocked(h, npage);
+	if(s != nil) {
+		// Record span info, because gc needs to be
+		// able to map interior pointer to containing span.
+		runtime·atomicstore(&s->sweepgen, h->sweepgen);
+		s->state = MSpanInUse;
+		s->freelist = nil;
+		s->ref = 0;
+		s->sizeclass = sizeclass;
+		s->elemsize = (sizeclass==0 ? s->npages<<PageShift : runtime·class_to_size[sizeclass]);
+
+		// update stats, sweep lists
+		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->lock);
+	return s;
+}
+
+static void
+mheap_alloc_m(G *gp)
+{
+	MHeap *h;
+	MSpan *s;
+
+	h = g->m->ptrarg[0];
+	g->m->ptrarg[0] = nil;
+	s = mheap_alloc(h, g->m->scalararg[0], g->m->scalararg[1], g->m->scalararg[2]);
+	g->m->ptrarg[0] = s;
+
+	runtime·gogo(&gp->sched);
+}
+
+MSpan*
+runtime·MHeap_Alloc(MHeap *h, uintptr npage, int32 sizeclass, bool large, bool needzero)
+{
+	MSpan *s;
+	void (*fn)(G*);
+
+	// Don't do any operations that lock the heap on the G stack.
+	// It might trigger stack growth, and the stack growth code needs
+	// to be able to allocate heap.
+	if(g == g->m->g0) {
+		s = mheap_alloc(h, npage, sizeclass, large);
+	} else {
+		g->m->ptrarg[0] = h;
+		g->m->scalararg[0] = npage;
+		g->m->scalararg[1] = sizeclass;
+		g->m->scalararg[2] = large;
+		fn = mheap_alloc_m;
+		runtime·mcall(&fn);
+		s = g->m->ptrarg[0];
+		g->m->ptrarg[0] = nil;
+	}
+	if(s != nil) {
+		if(needzero && s->needzero)
+			runtime·memclr((byte*)(s->start<<PageShift), s->npages<<PageShift);
+		s->needzero = 0;
+	}
+	return s;
+}
+
+MSpan*
+runtime·MHeap_AllocStack(MHeap *h, uintptr npage)
+{
+	MSpan *s;
+
+	if(g != g->m->g0)
+		runtime·throw("mheap_allocstack not on M stack");
+	runtime·lock(&h->lock);
+	s = MHeap_AllocSpanLocked(h, npage);
+	if(s != nil) {
+		s->state = MSpanStack;
+		s->freelist = nil;
+		s->ref = 0;
+		mstats.stacks_inuse += s->npages<<PageShift;
+	}
+	runtime·unlock(&h->lock);
+	return s;
+}
+
+// Allocates a span of the given size.  h must be locked.
+// The returned span has been removed from the
+// free list, but its state is still MSpanFree.
+static MSpan*
+MHeap_AllocSpanLocked(MHeap *h, uintptr npage)
+{
+	uintptr n;
+	MSpan *s, *t;
+	pageID p;
+
+	// Try in fixed-size lists up to max.
+	for(n=npage; n < nelem(h->free); n++) {
+		if(!runtime·MSpanList_IsEmpty(&h->free[n])) {
+			s = h->free[n].next;
+			goto HaveSpan;
+		}
+	}
+
+	// Best fit in list of large spans.
+	if((s = MHeap_AllocLarge(h, npage)) == nil) {
+		if(!MHeap_Grow(h, npage))
+			return nil;
+		if((s = MHeap_AllocLarge(h, npage)) == nil)
+			return nil;
+	}
+
+HaveSpan:
+	// Mark span in use.
+	if(s->state != MSpanFree)
+		runtime·throw("MHeap_AllocLocked - MSpan not free");
+	if(s->npages < npage)
+		runtime·throw("MHeap_AllocLocked - bad npages");
+	runtime·MSpanList_Remove(s);
+	if(s->next != nil || s->prev != nil)
+		runtime·throw("still in list");
+	if(s->npreleased > 0) {
+		runtime·SysUsed((void*)(s->start<<PageShift), s->npages<<PageShift);
+		mstats.heap_released -= s->npreleased<<PageShift;
+		s->npreleased = 0;
+	}
+
+	if(s->npages > npage) {
+		// Trim extra and put it back in the heap.
+		t = runtime·FixAlloc_Alloc(&h->spanalloc);
+		runtime·MSpan_Init(t, s->start + npage, s->npages - npage);
+		s->npages = npage;
+		p = t->start;
+		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;
+		t->needzero = s->needzero;
+		s->state = MSpanStack; // prevent coalescing with s
+		t->state = MSpanStack;
+		MHeap_FreeSpanLocked(h, t, false, false);
+		t->unusedsince = s->unusedsince; // preserve age (TODO: wrong: t is possibly merged and/or deallocated at this point)
+		s->state = MSpanFree;
+	}
+	s->unusedsince = 0;
+
+	p = s->start;
+	p -= ((uintptr)h->arena_start>>PageShift);
+	for(n=0; n<npage; n++)
+		h->spans[p+n] = s;
+
+	mstats.heap_inuse += npage<<PageShift;
+	mstats.heap_idle -= npage<<PageShift;
+
+	//runtime·printf("spanalloc %p\n", s->start << PageShift);
+	if(s->next != nil || s->prev != nil)
+		runtime·throw("still in list");
+	return s;
+}
+
+// Allocate a span of exactly npage pages from the list of large spans.
+static MSpan*
+MHeap_AllocLarge(MHeap *h, uintptr npage)
+{
+	return BestFit(&h->freelarge, npage, nil);
+}
+
+// Search list for smallest span with >= npage pages.
+// If there are multiple smallest spans, take the one
+// with the earliest starting address.
+static MSpan*
+BestFit(MSpan *list, uintptr npage, MSpan *best)
+{
+	MSpan *s;
+
+	for(s=list->next; s != list; s=s->next) {
+		if(s->npages < npage)
+			continue;
+		if(best == nil
+		|| s->npages < best->npages
+		|| (s->npages == best->npages && s->start < best->start))
+			best = s;
+	}
+	return best;
+}
+
+// Try to add at least npage pages of memory to the heap,
+// returning whether it worked.
+static bool
+MHeap_Grow(MHeap *h, uintptr npage)
+{
+	uintptr ask;
+	void *v;
+	MSpan *s;
+	pageID p;
+
+	// Ask for a big chunk, to reduce the number of mappings
+	// the operating system needs to track; also amortizes
+	// the overhead of an operating system mapping.
+	// Allocate a multiple of 64kB.
+	npage = ROUND(npage, (64<<10)/PageSize);
+	ask = npage<<PageShift;
+	if(ask < HeapAllocChunk)
+		ask = HeapAllocChunk;
+
+	v = runtime·MHeap_SysAlloc(h, ask);
+	if(v == nil) {
+		if(ask > (npage<<PageShift)) {
+			ask = npage<<PageShift;
+			v = runtime·MHeap_SysAlloc(h, ask);
+		}
+		if(v == nil) {
+			runtime·printf("runtime: out of memory: cannot allocate %D-byte block (%D in use)\n", (uint64)ask, mstats.heap_sys);
+			return false;
+		}
+	}
+
+	// Create a fake "in use" span and free it, so that the
+	// right coalescing happens.
+	s = runtime·FixAlloc_Alloc(&h->spanalloc);
+	runtime·MSpan_Init(s, (uintptr)v>>PageShift, ask>>PageShift);
+	p = s->start;
+	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_FreeSpanLocked(h, s, false, true);
+	return true;
+}
+
+// Look up the span at the given address.
+// Address is guaranteed to be in map
+// and is guaranteed to be start or end of span.
+MSpan*
+runtime·MHeap_Lookup(MHeap *h, void *v)
+{
+	uintptr p;
+	
+	p = (uintptr)v;
+	p -= (uintptr)h->arena_start;
+	return h->spans[p >> PageShift];
+}
+
+// Look up the span at the given address.
+// Address is *not* guaranteed to be in map
+// and may be anywhere in the span.
+// Map entries for the middle of a span are only
+// valid for allocated spans.  Free spans may have
+// other garbage in their middles, so we have to
+// check for that.
+MSpan*
+runtime·MHeap_LookupMaybe(MHeap *h, void *v)
+{
+	MSpan *s;
+	pageID p, q;
+
+	if((byte*)v < h->arena_start || (byte*)v >= h->arena_used)
+		return nil;
+	p = (uintptr)v>>PageShift;
+	q = p;
+	q -= (uintptr)h->arena_start >> PageShift;
+	s = h->spans[q];
+	if(s == nil || p < s->start || v >= s->limit || s->state != MSpanInUse)
+		return nil;
+	return s;
+}
+
+// Free the span back into the heap.
+static void
+mheap_free(MHeap *h, MSpan *s, int32 acct)
+{
+	if(g != g->m->g0)
+		runtime·throw("mheap_free not on M stack");
+	runtime·lock(&h->lock);
+	mstats.heap_alloc += g->m->mcache->local_cachealloc;
+	g->m->mcache->local_cachealloc = 0;
+	mstats.tinyallocs += g->m->mcache->local_tinyallocs;
+	g->m->mcache->local_tinyallocs = 0;
+	if(acct) {
+		mstats.heap_alloc -= s->npages<<PageShift;
+		mstats.heap_objects--;
+	}
+	MHeap_FreeSpanLocked(h, s, true, true);
+	runtime·unlock(&h->lock);
+}
+
+static void
+mheap_free_m(G *gp)
+{
+	MHeap *h;
+	MSpan *s;
+	
+	h = g->m->ptrarg[0];
+	s = g->m->ptrarg[1];
+	g->m->ptrarg[0] = nil;
+	g->m->ptrarg[1] = nil;
+	mheap_free(h, s, g->m->scalararg[0]);
+	runtime·gogo(&gp->sched);
+}
+
+void
+runtime·MHeap_Free(MHeap *h, MSpan *s, int32 acct)
+{
+	void (*fn)(G*);
+
+	if(g == g->m->g0) {
+		mheap_free(h, s, acct);
+	} else {
+		g->m->ptrarg[0] = h;
+		g->m->ptrarg[1] = s;
+		g->m->scalararg[0] = acct;
+		fn = mheap_free_m;
+		runtime·mcall(&fn);
+	}
+}
+
+void
+runtime·MHeap_FreeStack(MHeap *h, MSpan *s)
+{
+	if(g != g->m->g0)
+		runtime·throw("mheap_freestack not on M stack");
+	s->needzero = 1;
+	runtime·lock(&h->lock);
+	mstats.stacks_inuse -= s->npages<<PageShift;
+	MHeap_FreeSpanLocked(h, s, true, true);
+	runtime·unlock(&h->lock);
+}
+
+static void
+MHeap_FreeSpanLocked(MHeap *h, MSpan *s, bool acctinuse, bool acctidle)
+{
+	MSpan *t;
+	pageID p;
+
+	switch(s->state) {
+	case MSpanStack:
+		if(s->ref != 0)
+			runtime·throw("MHeap_FreeSpanLocked - invalid stack free");
+		break;
+	case MSpanInUse:
+		if(s->ref != 0 || s->sweepgen != h->sweepgen) {
+			runtime·printf("MHeap_FreeSpanLocked - span %p ptr %p ref %d sweepgen %d/%d\n",
+				       s, s->start<<PageShift, s->ref, s->sweepgen, h->sweepgen);
+			runtime·throw("MHeap_FreeSpanLocked - invalid free");
+		}
+		break;
+	default:
+		runtime·throw("MHeap_FreeSpanLocked - invalid span state");
+		break;
+	}
+	if(acctinuse)
+		mstats.heap_inuse -= s->npages<<PageShift;
+	if(acctidle)
+		mstats.heap_idle += s->npages<<PageShift;
+	s->state = MSpanFree;
+	runtime·MSpanList_Remove(s);
+	// Stamp newly unused spans. The scavenger will use that
+	// info to potentially give back some pages to the OS.
+	s->unusedsince = runtime·nanotime();
+	s->npreleased = 0;
+
+	// Coalesce with earlier, later spans.
+	p = s->start;
+	p -= (uintptr)h->arena_start >> PageShift;
+	if(p > 0 && (t = h->spans[p-1]) != nil && t->state != MSpanInUse && t->state != MSpanStack) {
+		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);
+		t->state = MSpanDead;
+		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 && t->state != MSpanStack) {
+		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;
+		runtime·FixAlloc_Free(&h->spanalloc, t);
+	}
+
+	// Insert s into appropriate list.
+	if(s->npages < nelem(h->free))
+		runtime·MSpanList_Insert(&h->free[s->npages], s);
+	else
+		runtime·MSpanList_Insert(&h->freelarge, s);
+}
+
+static uintptr
+scavengelist(MSpan *list, uint64 now, uint64 limit)
+{
+	uintptr released, sumreleased;
+	MSpan *s;
+
+	if(runtime·MSpanList_IsEmpty(list))
+		return 0;
+
+	sumreleased = 0;
+	for(s=list->next; s != list; s=s->next) {
+		if((now - s->unusedsince) > limit && s->npreleased != s->npages) {
+			released = (s->npages - s->npreleased) << PageShift;
+			mstats.heap_released += released;
+			sumreleased += released;
+			s->npreleased = s->npages;
+			runtime·SysUnused((void*)(s->start << PageShift), s->npages << PageShift);
+		}
+	}
+	return sumreleased;
+}
+
+void
+runtime·MHeap_Scavenge(int32 k, uint64 now, uint64 limit)
+{
+	uint32 i;
+	uintptr sumreleased;
+	MHeap *h;
+	
+	h = &runtime·mheap;
+	runtime·lock(&h->lock);
+	sumreleased = 0;
+	for(i=0; i < nelem(h->free); i++)
+		sumreleased += scavengelist(&h->free[i], now, limit);
+	sumreleased += scavengelist(&h->freelarge, now, limit);
+	runtime·unlock(&h->lock);
+
+	if(runtime·debug.gctrace > 0) {
+		if(sumreleased > 0)
+			runtime·printf("scvg%d: %D MB released\n", k, (uint64)sumreleased>>20);
+		// TODO(dvyukov): these stats are incorrect as we don't subtract stack usage from heap.
+		// But we can't call ReadMemStats on g0 holding locks.
+		runtime·printf("scvg%d: inuse: %D, idle: %D, sys: %D, released: %D, consumed: %D (MB)\n",
+			k, mstats.heap_inuse>>20, mstats.heap_idle>>20, mstats.heap_sys>>20,
+			mstats.heap_released>>20, (mstats.heap_sys - mstats.heap_released)>>20);
+	}
+}
+
+void
+runtime·scavenge_m(void)
+{
+	runtime·MHeap_Scavenge(-1, ~(uintptr)0, 0);
+}
+
+// Initialize a new span with the given start and npages.
+void
+runtime·MSpan_Init(MSpan *span, pageID start, uintptr npages)
+{
+	span->next = nil;
+	span->prev = nil;
+	span->start = start;
+	span->npages = npages;
+	span->freelist = nil;
+	span->ref = 0;
+	span->sizeclass = 0;
+	span->incache = false;
+	span->elemsize = 0;
+	span->state = MSpanDead;
+	span->unusedsince = 0;
+	span->npreleased = 0;
+	span->specialLock.key = 0;
+	span->specials = nil;
+	span->needzero = 0;
+}
+
+// Initialize an empty doubly-linked list.
+void
+runtime·MSpanList_Init(MSpan *list)
+{
+	list->state = MSpanListHead;
+	list->next = list;
+	list->prev = list;
+}
+
+void
+runtime·MSpanList_Remove(MSpan *span)
+{
+	if(span->prev == nil && span->next == nil)
+		return;
+	span->prev->next = span->next;
+	span->next->prev = span->prev;
+	span->prev = nil;
+	span->next = nil;
+}
+
+bool
+runtime·MSpanList_IsEmpty(MSpan *list)
+{
+	return list->next == list;
+}
+
+void
+runtime·MSpanList_Insert(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->next;
+	span->prev = list;
+	span->next->prev = 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.
+	g->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);
+			g->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);
+	g->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.
+	g->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);
+			g->m->locks--;
+			return s;
+		}
+		t = &s->next;
+	}
+	runtime·unlock(&span->specialLock);
+	g->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->special.kind = KindSpecialFinalizer;
+	s->fn = f;
+	s->nret = nret;
+	s->fint = fint;
+	s->ot = ot;
+	if(addspecial(p, &s->special))
+		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_m(void)
+{	
+	void *p;
+	Bucket *b;
+	SpecialProfile *s;
+	
+	p = g->m->ptrarg[0];
+	b = g->m->ptrarg[1];
+	g->m->ptrarg[0] = nil;
+	g->m->ptrarg[1] = nil;
+
+	runtime·lock(&runtime·mheap.speciallock);
+	s = runtime·FixAlloc_Alloc(&runtime·mheap.specialprofilealloc);
+	runtime·unlock(&runtime·mheap.speciallock);
+	s->special.kind = KindSpecialProfile;
+	s->b = b;
+	if(!addspecial(p, &s->special))
+		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;
+	}
+}
diff --git a/src/runtime/mprof.go b/src/runtime/mprof.go
index a618bd5..f4da45f 100644
--- a/src/runtime/mprof.go
+++ b/src/runtime/mprof.go
@@ -100,7 +100,7 @@ func newBucket(typ bucketType, nstk int) *bucket {
 	size := unsafe.Sizeof(bucket{}) + uintptr(nstk)*unsafe.Sizeof(uintptr(0))
 	switch typ {
 	default:
-		throw("invalid profile bucket type")
+		gothrow("invalid profile bucket type")
 	case memProfile:
 		size += unsafe.Sizeof(memRecord{})
 	case blockProfile:
@@ -123,7 +123,7 @@ func (b *bucket) stk() []uintptr {
 // mp returns the memRecord associated with the memProfile bucket b.
 func (b *bucket) mp() *memRecord {
 	if b.typ != memProfile {
-		throw("bad use of bucket.mp")
+		gothrow("bad use of bucket.mp")
 	}
 	data := add(unsafe.Pointer(b), unsafe.Sizeof(*b)+b.nstk*unsafe.Sizeof(uintptr(0)))
 	return (*memRecord)(data)
@@ -132,7 +132,7 @@ func (b *bucket) mp() *memRecord {
 // bp returns the blockRecord associated with the blockProfile bucket b.
 func (b *bucket) bp() *blockRecord {
 	if b.typ != blockProfile {
-		throw("bad use of bucket.bp")
+		gothrow("bad use of bucket.bp")
 	}
 	data := add(unsafe.Pointer(b), unsafe.Sizeof(*b)+b.nstk*unsafe.Sizeof(uintptr(0)))
 	return (*blockRecord)(data)
@@ -143,7 +143,7 @@ func stkbucket(typ bucketType, size uintptr, stk []uintptr, alloc bool) *bucket
 	if buckhash == nil {
 		buckhash = (*[buckHashSize]*bucket)(sysAlloc(unsafe.Sizeof(*buckhash), &memstats.buckhash_sys))
 		if buckhash == nil {
-			throw("runtime: cannot allocate memory")
+			gothrow("runtime: cannot allocate memory")
 		}
 	}
 
@@ -190,6 +190,8 @@ func stkbucket(typ bucketType, size uintptr, stk []uintptr, alloc bool) *bucket
 	return b
 }
 
+func sysAlloc(n uintptr, stat *uint64) unsafe.Pointer
+
 func eqslice(x, y []uintptr) bool {
 	if len(x) != len(y) {
 		return false
@@ -232,7 +234,7 @@ func mProf_GC() {
 // Called by malloc to record a profiled block.
 func mProf_Malloc(p unsafe.Pointer, size uintptr) {
 	var stk [maxStack]uintptr
-	nstk := callers(4, stk[:])
+	nstk := callers(4, &stk[0], len(stk))
 	lock(&proflock)
 	b := stkbucket(memProfile, size, stk[:nstk], true)
 	mp := b.mp()
@@ -244,9 +246,16 @@ func mProf_Malloc(p unsafe.Pointer, size uintptr) {
 	// 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.
-	systemstack(func() {
-		setprofilebucket(p, b)
-	})
+	setprofilebucket(p, b)
+}
+
+func setprofilebucket_m() // mheap.c
+
+func setprofilebucket(p unsafe.Pointer, b *bucket) {
+	g := getg()
+	g.m.ptrarg[0] = p
+	g.m.ptrarg[1] = unsafe.Pointer(b)
+	onM(setprofilebucket_m)
 }
 
 // Called when freeing a profiled block.
@@ -300,9 +309,9 @@ func blockevent(cycles int64, skip int) {
 	var nstk int
 	var stk [maxStack]uintptr
 	if gp.m.curg == nil || gp.m.curg == gp {
-		nstk = callers(skip, stk[:])
+		nstk = callers(skip, &stk[0], len(stk))
 	} else {
-		nstk = gcallers(gp.m.curg, skip, stk[:])
+		nstk = gcallers(gp.m.curg, skip, &stk[0], len(stk))
 	}
 	lock(&proflock)
 	b := stkbucket(blockProfile, 0, stk[:nstk], true)
@@ -510,6 +519,8 @@ func ThreadCreateProfile(p []StackRecord) (n int, ok bool) {
 	return
 }
 
+var allgs []*g // proc.c
+
 // GoroutineProfile returns n, the number of records in the active goroutine stack profile.
 // If len(p) >= n, GoroutineProfile copies the profile into p and returns n, true.
 // If len(p) < n, GoroutineProfile does not change p and returns n, false.
@@ -521,7 +532,9 @@ func GoroutineProfile(p []StackRecord) (n int, ok bool) {
 	n = NumGoroutine()
 	if n <= len(p) {
 		gp := getg()
-		stopTheWorld("profile")
+		semacquire(&worldsema, false)
+		gp.m.gcing = 1
+		onM(stoptheworld)
 
 		n = NumGoroutine()
 		if n <= len(p) {
@@ -529,7 +542,7 @@ func GoroutineProfile(p []StackRecord) (n int, ok bool) {
 			r := p
 			sp := getcallersp(unsafe.Pointer(&p))
 			pc := getcallerpc(unsafe.Pointer(&p))
-			systemstack(func() {
+			onM(func() {
 				saveg(pc, sp, gp, &r[0])
 			})
 			r = r[1:]
@@ -542,7 +555,9 @@ func GoroutineProfile(p []StackRecord) (n int, ok bool) {
 			}
 		}
 
-		startTheWorld()
+		gp.m.gcing = 0
+		semrelease(&worldsema)
+		onM(starttheworld)
 	}
 
 	return n, ok
@@ -561,7 +576,10 @@ func saveg(pc, sp uintptr, gp *g, r *StackRecord) {
 // into buf after the trace for the current goroutine.
 func Stack(buf []byte, all bool) int {
 	if all {
-		stopTheWorld("stack trace")
+		semacquire(&worldsema, false)
+		gp := getg()
+		gp.m.gcing = 1
+		onM(stoptheworld)
 	}
 
 	n := 0
@@ -569,7 +587,7 @@ func Stack(buf []byte, all bool) int {
 		gp := getg()
 		sp := getcallersp(unsafe.Pointer(&buf))
 		pc := getcallerpc(unsafe.Pointer(&buf))
-		systemstack(func() {
+		onM(func() {
 			g0 := getg()
 			g0.writebuf = buf[0:0:len(buf)]
 			goroutineheader(gp)
@@ -583,7 +601,10 @@ func Stack(buf []byte, all bool) int {
 	}
 
 	if all {
-		startTheWorld()
+		gp := getg()
+		gp.m.gcing = 0
+		semrelease(&worldsema)
+		onM(starttheworld)
 	}
 	return n
 }
@@ -605,7 +626,7 @@ func tracealloc(p unsafe.Pointer, size uintptr, typ *_type) {
 		goroutineheader(gp)
 		pc := getcallerpc(unsafe.Pointer(&p))
 		sp := getcallersp(unsafe.Pointer(&p))
-		systemstack(func() {
+		onM(func() {
 			traceback(pc, sp, 0, gp)
 		})
 	} else {
@@ -625,7 +646,7 @@ func tracefree(p unsafe.Pointer, size uintptr) {
 	goroutineheader(gp)
 	pc := getcallerpc(unsafe.Pointer(&p))
 	sp := getcallersp(unsafe.Pointer(&p))
-	systemstack(func() {
+	onM(func() {
 		traceback(pc, sp, 0, gp)
 	})
 	print("\n")
diff --git a/src/runtime/msize.c b/src/runtime/msize.c
new file mode 100644
index 0000000..7cb65da
--- /dev/null
+++ b/src/runtime/msize.c
@@ -0,0 +1,184 @@
+// 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.
+
+// Malloc small size classes.
+//
+// See malloc.h for overview.
+//
+// The size classes are chosen so that rounding an allocation
+// request up to the next size class wastes at most 12.5% (1.125x).
+//
+// Each size class has its own page count that gets allocated
+// and chopped up when new objects of the size class are needed.
+// That page count is chosen so that chopping up the run of
+// pages into objects of the given size wastes at most 12.5% (1.125x)
+// of the memory.  It is not necessary that the cutoff here be
+// the same as above.
+//
+// The two sources of waste multiply, so the worst possible case
+// for the above constraints would be that allocations of some
+// size might have a 26.6% (1.266x) overhead.
+// In practice, only one of the wastes comes into play for a
+// given size (sizes < 512 waste mainly on the round-up,
+// sizes > 512 waste mainly on the page chopping).
+//
+// TODO(rsc): Compute max waste for any given size.
+
+#include "runtime.h"
+#include "arch_GOARCH.h"
+#include "malloc.h"
+#include "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,
+// one mapping sizes <= 1024 to their class and one mapping
+// sizes >= 1024 and <= MaxSmallSize to their class.
+// All objects are 8-aligned, so the first array is indexed by
+// the size divided by 8 (rounded up).  Objects >= 1024 bytes
+// are 128-aligned, so the second array is indexed by the
+// 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];
+
+void runtime·testdefersizes(void);
+
+int32
+runtime·SizeToClass(int32 size)
+{
+	if(size > MaxSmallSize)
+		runtime·throw("SizeToClass - invalid size");
+	if(size > 1024-8)
+		return runtime·size_to_class128[(size-1024+127) >> 7];
+	return runtime·size_to_class8[(size+7)>>3];
+}
+
+void
+runtime·InitSizes(void)
+{
+	int32 align, sizeclass, size, nextsize, n;
+	uint32 i;
+	uintptr allocsize, npages;
+
+	// Initialize the runtime·class_to_size table (and choose class sizes in the process).
+	runtime·class_to_size[0] = 0;
+	sizeclass = 1;	// 0 means no class
+	align = 8;
+	for(size = align; size <= MaxSmallSize; size += align) {
+		if((size&(size-1)) == 0) {	// bump alignment once in a while
+			if(size >= 2048)
+				align = 256;
+			else if(size >= 128)
+				align = size / 8;
+			else if(size >= 16)
+				align = 16;	// required for x86 SSE instructions, if we want to use them
+		}
+		if((align&(align-1)) != 0)
+			runtime·throw("InitSizes - bug");
+
+		// Make the allocnpages big enough that
+		// the leftover is less than 1/8 of the total,
+		// so wasted space is at most 12.5%.
+		allocsize = PageSize;
+		while(allocsize%size > allocsize/8)
+			allocsize += PageSize;
+		npages = allocsize >> PageShift;
+
+		// If the previous sizeclass chose the same
+		// allocation size and fit the same number of
+		// 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]) {
+			runtime·class_to_size[sizeclass-1] = size;
+			continue;
+		}
+
+		runtime·class_to_allocnpages[sizeclass] = npages;
+		runtime·class_to_size[sizeclass] = size;
+		sizeclass++;
+	}
+	if(sizeclass != NumSizeClasses) {
+		runtime·printf("sizeclass=%d NumSizeClasses=%d\n", sizeclass, NumSizeClasses);
+		runtime·throw("InitSizes - bad NumSizeClasses");
+	}
+
+	// Initialize the size_to_class tables.
+	nextsize = 0;
+	for (sizeclass = 1; sizeclass < NumSizeClasses; sizeclass++) {
+		for(; nextsize < 1024 && nextsize <= runtime·class_to_size[sizeclass]; nextsize+=8)
+			runtime·size_to_class8[nextsize/8] = sizeclass;
+		if(nextsize >= 1024)
+			for(; nextsize <= runtime·class_to_size[sizeclass]; nextsize += 128)
+				runtime·size_to_class128[(nextsize-1024)/128] = sizeclass;
+	}
+
+	// Double-check SizeToClass.
+	if(0) {
+		for(n=0; n < MaxSmallSize; 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");
+				goto dump;
+			}
+			if(sizeclass > 1 && runtime·class_to_size[sizeclass-1] >= n) {
+				runtime·printf("size=%d sizeclass=%d runtime·class_to_size=%d\n", n, sizeclass, runtime·class_to_size[sizeclass]);
+				runtime·printf("SizeToClass too big");
+				goto dump;
+			}
+		}
+	}
+
+	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];
+	return;
+
+dump:
+	if(1){
+		runtime·printf("NumSizeClasses=%d\n", NumSizeClasses);
+		runtime·printf("runtime·class_to_size:");
+		for(sizeclass=0; sizeclass<NumSizeClasses; sizeclass++)
+			runtime·printf(" %d", runtime·class_to_size[sizeclass]);
+		runtime·printf("\n\n");
+		runtime·printf("size_to_class8:");
+		for(i=0; i<nelem(runtime·size_to_class8); i++)
+			runtime·printf(" %d=>%d(%d)\n", i*8, runtime·size_to_class8[i],
+				runtime·class_to_size[runtime·size_to_class8[i]]);
+		runtime·printf("\n");
+		runtime·printf("size_to_class128:");
+		for(i=0; i<nelem(runtime·size_to_class128); i++)
+			runtime·printf(" %d=>%d(%d)\n", i*128, runtime·size_to_class128[i],
+				runtime·class_to_size[runtime·size_to_class128[i]]);
+		runtime·printf("\n");
+	}
+	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/runtime/netpoll.go b/src/runtime/netpoll.go
index 7c6e3fa..3456e02 100644
--- a/src/runtime/netpoll.go
+++ b/src/runtime/netpoll.go
@@ -46,17 +46,17 @@ type pollDesc struct {
 	// in a lock-free way by all operations.
 	// NOTE(dvyukov): the following code uses uintptr to store *g (rg/wg),
 	// that will blow up when GC starts moving objects.
-	lock    mutex // protects the following fields
+	lock    mutex // protectes the following fields
 	fd      uintptr
 	closing bool
-	seq     uintptr // protects from stale timers and ready notifications
-	rg      uintptr // pdReady, pdWait, G waiting for read or nil
-	rt      timer   // read deadline timer (set if rt.f != nil)
-	rd      int64   // read deadline
-	wg      uintptr // pdReady, pdWait, G waiting for write or nil
-	wt      timer   // write deadline timer
-	wd      int64   // write deadline
-	user    uint32  // user settable cookie
+	seq     uintptr        // protects from stale timers and ready notifications
+	rg      uintptr        // pdReady, pdWait, G waiting for read or nil
+	rt      timer          // read deadline timer (set if rt.f != nil)
+	rd      int64          // read deadline
+	wg      uintptr        // pdReady, pdWait, G waiting for write or nil
+	wt      timer          // write deadline timer
+	wd      int64          // write deadline
+	user    unsafe.Pointer // user settable cookie
 }
 
 type pollCache struct {
@@ -69,30 +69,20 @@ type pollCache struct {
 	// seq is incremented when deadlines are changed or descriptor is reused.
 }
 
-var (
-	netpollInited uint32
-	pollcache     pollCache
-)
-
-//go:linkname net_runtime_pollServerInit net.runtime_pollServerInit
-func net_runtime_pollServerInit() {
-	netpollinit()
-	atomicstore(&netpollInited, 1)
-}
+var pollcache pollCache
 
-func netpollinited() bool {
-	return atomicload(&netpollInited) != 0
+func netpollServerInit() {
+	onM(netpollinit)
 }
 
-//go:linkname net_runtime_pollOpen net.runtime_pollOpen
-func net_runtime_pollOpen(fd uintptr) (*pollDesc, int) {
+func netpollOpen(fd uintptr) (*pollDesc, int) {
 	pd := pollcache.alloc()
 	lock(&pd.lock)
 	if pd.wg != 0 && pd.wg != pdReady {
-		throw("netpollOpen: blocked write on free descriptor")
+		gothrow("netpollOpen: blocked write on free descriptor")
 	}
 	if pd.rg != 0 && pd.rg != pdReady {
-		throw("netpollOpen: blocked read on free descriptor")
+		gothrow("netpollOpen: blocked read on free descriptor")
 	}
 	pd.fd = fd
 	pd.closing = false
@@ -104,22 +94,25 @@ func net_runtime_pollOpen(fd uintptr) (*pollDesc, int) {
 	unlock(&pd.lock)
 
 	var errno int32
-	errno = netpollopen(fd, pd)
+	onM(func() {
+		errno = netpollopen(fd, pd)
+	})
 	return pd, int(errno)
 }
 
-//go:linkname net_runtime_pollClose net.runtime_pollClose
-func net_runtime_pollClose(pd *pollDesc) {
+func netpollClose(pd *pollDesc) {
 	if !pd.closing {
-		throw("netpollClose: close w/o unblock")
+		gothrow("netpollClose: close w/o unblock")
 	}
 	if pd.wg != 0 && pd.wg != pdReady {
-		throw("netpollClose: blocked write on closing descriptor")
+		gothrow("netpollClose: blocked write on closing descriptor")
 	}
 	if pd.rg != 0 && pd.rg != pdReady {
-		throw("netpollClose: blocked read on closing descriptor")
+		gothrow("netpollClose: blocked read on closing descriptor")
 	}
-	netpollclose(uintptr(pd.fd))
+	onM(func() {
+		netpollclose(uintptr(pd.fd))
+	})
 	pollcache.free(pd)
 }
 
@@ -130,8 +123,7 @@ func (c *pollCache) free(pd *pollDesc) {
 	unlock(&c.lock)
 }
 
-//go:linkname net_runtime_pollReset net.runtime_pollReset
-func net_runtime_pollReset(pd *pollDesc, mode int) int {
+func netpollReset(pd *pollDesc, mode int) int {
 	err := netpollcheckerr(pd, int32(mode))
 	if err != 0 {
 		return err
@@ -144,15 +136,16 @@ func net_runtime_pollReset(pd *pollDesc, mode int) int {
 	return 0
 }
 
-//go:linkname net_runtime_pollWait net.runtime_pollWait
-func net_runtime_pollWait(pd *pollDesc, mode int) int {
+func netpollWait(pd *pollDesc, mode int) int {
 	err := netpollcheckerr(pd, int32(mode))
 	if err != 0 {
 		return err
 	}
 	// As for now only Solaris uses level-triggered IO.
 	if GOOS == "solaris" {
-		netpollarm(pd, mode)
+		onM(func() {
+			netpollarm(pd, mode)
+		})
 	}
 	for !netpollblock(pd, int32(mode), false) {
 		err = netpollcheckerr(pd, int32(mode))
@@ -166,16 +159,14 @@ func net_runtime_pollWait(pd *pollDesc, mode int) int {
 	return 0
 }
 
-//go:linkname net_runtime_pollWaitCanceled net.runtime_pollWaitCanceled
-func net_runtime_pollWaitCanceled(pd *pollDesc, mode int) {
+func netpollWaitCanceled(pd *pollDesc, mode int) {
 	// 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.
 	for !netpollblock(pd, int32(mode), true) {
 	}
 }
 
-//go:linkname net_runtime_pollSetDeadline net.runtime_pollSetDeadline
-func net_runtime_pollSetDeadline(pd *pollDesc, d int64, mode int) {
+func netpollSetDeadline(pd *pollDesc, d int64, mode int) {
 	lock(&pd.lock)
 	if pd.closing {
 		unlock(&pd.lock)
@@ -237,18 +228,17 @@ func net_runtime_pollSetDeadline(pd *pollDesc, d int64, mode int) {
 	}
 	unlock(&pd.lock)
 	if rg != nil {
-		goready(rg, 3)
+		goready(rg)
 	}
 	if wg != nil {
-		goready(wg, 3)
+		goready(wg)
 	}
 }
 
-//go:linkname net_runtime_pollUnblock net.runtime_pollUnblock
-func net_runtime_pollUnblock(pd *pollDesc) {
+func netpollUnblock(pd *pollDesc) {
 	lock(&pd.lock)
 	if pd.closing {
-		throw("netpollUnblock: already closing")
+		gothrow("netpollUnblock: already closing")
 	}
 	pd.closing = true
 	pd.seq++
@@ -266,30 +256,48 @@ func net_runtime_pollUnblock(pd *pollDesc) {
 	}
 	unlock(&pd.lock)
 	if rg != nil {
-		goready(rg, 3)
+		goready(rg)
 	}
 	if wg != nil {
-		goready(wg, 3)
+		goready(wg)
 	}
 }
 
+func netpollfd(pd *pollDesc) uintptr {
+	return pd.fd
+}
+
+func netpolluser(pd *pollDesc) *unsafe.Pointer {
+	return &pd.user
+}
+
+func netpollclosing(pd *pollDesc) bool {
+	return pd.closing
+}
+
+func netpolllock(pd *pollDesc) {
+	lock(&pd.lock)
+}
+
+func netpollunlock(pd *pollDesc) {
+	unlock(&pd.lock)
+}
+
 // make pd ready, newly runnable goroutines (if any) are returned in rg/wg
-// May run during STW, so write barriers are not allowed.
-//go:nowritebarrier
-func netpollready(gpp *guintptr, pd *pollDesc, mode int32) {
-	var rg, wg guintptr
+func netpollready(gpp **g, pd *pollDesc, mode int32) {
+	var rg, wg *g
 	if mode == 'r' || mode == 'r'+'w' {
-		rg.set(netpollunblock(pd, 'r', true))
+		rg = netpollunblock(pd, 'r', true)
 	}
 	if mode == 'w' || mode == 'r'+'w' {
-		wg.set(netpollunblock(pd, 'w', true))
+		wg = netpollunblock(pd, 'w', true)
 	}
-	if rg != 0 {
-		rg.ptr().schedlink = *gpp
+	if rg != nil {
+		rg.schedlink = *gpp
 		*gpp = rg
 	}
-	if wg != 0 {
-		wg.ptr().schedlink = *gpp
+	if wg != nil {
+		wg.schedlink = *gpp
 		*gpp = wg
 	}
 }
@@ -324,7 +332,7 @@ func netpollblock(pd *pollDesc, mode int32, waitio bool) bool {
 			return true
 		}
 		if old != 0 {
-			throw("netpollblock: double wait")
+			gothrow("netpollblock: double wait")
 		}
 		if casuintptr(gpp, 0, pdWait) {
 			break
@@ -335,12 +343,13 @@ func netpollblock(pd *pollDesc, mode int32, waitio bool) bool {
 	// this is necessary because runtime_pollUnblock/runtime_pollSetDeadline/deadlineimpl
 	// do the opposite: store to closing/rd/wd, membarrier, load of rg/wg
 	if waitio || netpollcheckerr(pd, mode) == 0 {
-		gopark(netpollblockcommit, unsafe.Pointer(gpp), "IO wait", traceEvGoBlockNet, 5)
+		f := netpollblockcommit
+		gopark(**(**unsafe.Pointer)(unsafe.Pointer(&f)), unsafe.Pointer(gpp), "IO wait")
 	}
 	// be careful to not lose concurrent READY notification
 	old := xchguintptr(gpp, 0)
 	if old > pdWait {
-		throw("netpollblock: corrupted state")
+		gothrow("netpollblock: corrupted state")
 	}
 	return old == pdReady
 }
@@ -386,7 +395,7 @@ func netpolldeadlineimpl(pd *pollDesc, seq uintptr, read, write bool) {
 	var rg *g
 	if read {
 		if pd.rd <= 0 || pd.rt.f == nil {
-			throw("netpolldeadlineimpl: inconsistent read deadline")
+			gothrow("netpolldeadlineimpl: inconsistent read deadline")
 		}
 		pd.rd = -1
 		atomicstorep(unsafe.Pointer(&pd.rt.f), nil) // full memory barrier between store to rd and load of rg in netpollunblock
@@ -395,7 +404,7 @@ func netpolldeadlineimpl(pd *pollDesc, seq uintptr, read, write bool) {
 	var wg *g
 	if write {
 		if pd.wd <= 0 || pd.wt.f == nil && !read {
-			throw("netpolldeadlineimpl: inconsistent write deadline")
+			gothrow("netpolldeadlineimpl: inconsistent write deadline")
 		}
 		pd.wd = -1
 		atomicstorep(unsafe.Pointer(&pd.wt.f), nil) // full memory barrier between store to wd and load of wg in netpollunblock
@@ -403,10 +412,10 @@ func netpolldeadlineimpl(pd *pollDesc, seq uintptr, read, write bool) {
 	}
 	unlock(&pd.lock)
 	if rg != nil {
-		goready(rg, 0)
+		goready(rg)
 	}
 	if wg != nil {
-		goready(wg, 0)
+		goready(wg)
 	}
 }
 
diff --git a/src/runtime/netpoll_epoll.go b/src/runtime/netpoll_epoll.go
index 7b4052a..ecfc9cd 100644
--- a/src/runtime/netpoll_epoll.go
+++ b/src/runtime/netpoll_epoll.go
@@ -34,7 +34,7 @@ func netpollinit() {
 		return
 	}
 	println("netpollinit: failed to create epoll descriptor", -epfd)
-	throw("netpollinit: failed to create descriptor")
+	gothrow("netpollinit: failed to create descriptor")
 }
 
 func netpollopen(fd uintptr, pd *pollDesc) int32 {
@@ -50,14 +50,14 @@ func netpollclose(fd uintptr) int32 {
 }
 
 func netpollarm(pd *pollDesc, mode int) {
-	throw("unused")
+	gothrow("unused")
 }
 
 // polls for ready network connections
 // returns list of goroutines that become runnable
-func netpoll(block bool) *g {
+func netpoll(block bool) (gp *g) {
 	if epfd == -1 {
-		return nil
+		return
 	}
 	waitms := int32(-1)
 	if !block {
@@ -73,7 +73,6 @@ retry:
 		}
 		goto retry
 	}
-	var gp guintptr
 	for i := int32(0); i < n; i++ {
 		ev := &events[i]
 		if ev.events == 0 {
@@ -88,12 +87,11 @@ retry:
 		}
 		if mode != 0 {
 			pd := *(**pollDesc)(unsafe.Pointer(&ev.data))
-
-			netpollready(&gp, pd, mode)
+			netpollready((**g)(noescape(unsafe.Pointer(&gp))), pd, mode)
 		}
 	}
-	if block && gp == 0 {
+	if block && gp == nil {
 		goto retry
 	}
-	return gp.ptr()
+	return gp
 }
diff --git a/src/runtime/netpoll_kqueue.go b/src/runtime/netpoll_kqueue.go
index 01445dc..d6d55b9 100644
--- a/src/runtime/netpoll_kqueue.go
+++ b/src/runtime/netpoll_kqueue.go
@@ -25,7 +25,7 @@ func netpollinit() {
 	kq = kqueue()
 	if kq < 0 {
 		println("netpollinit: kqueue failed with", -kq)
-		throw("netpollinit: kqueue failed")
+		gothrow("netpollinit: kqueue failed")
 	}
 	closeonexec(kq)
 }
@@ -57,14 +57,14 @@ func netpollclose(fd uintptr) int32 {
 }
 
 func netpollarm(pd *pollDesc, mode int) {
-	throw("unused")
+	gothrow("unused")
 }
 
 // Polls for ready network connections.
 // Returns list of goroutines that become runnable.
-func netpoll(block bool) *g {
+func netpoll(block bool) (gp *g) {
 	if kq == -1 {
-		return nil
+		return
 	}
 	var tp *timespec
 	var ts timespec
@@ -81,7 +81,6 @@ retry:
 		}
 		goto retry
 	}
-	var gp guintptr
 	for i := 0; i < int(n); i++ {
 		ev := &events[i]
 		var mode int32
@@ -92,11 +91,11 @@ retry:
 			mode += 'w'
 		}
 		if mode != 0 {
-			netpollready(&gp, (*pollDesc)(unsafe.Pointer(ev.udata)), mode)
+			netpollready((**g)(noescape(unsafe.Pointer(&gp))), (*pollDesc)(unsafe.Pointer(ev.udata)), mode)
 		}
 	}
-	if block && gp == 0 {
+	if block && gp == nil {
 		goto retry
 	}
-	return gp.ptr()
+	return gp
 }
diff --git a/src/runtime/netpoll_solaris.c b/src/runtime/netpoll_solaris.c
new file mode 100644
index 0000000..d422719
--- /dev/null
+++ b/src/runtime/netpoll_solaris.c
@@ -0,0 +1,264 @@
+// 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 (*g->m->perrno)
+
+int32
+runtime·fcntl(int32 fd, int32 cmd, uintptr arg)
+{
+	return runtime·sysvicall3(libc·fcntl, (uintptr)fd, (uintptr)cmd, (uintptr)arg);
+}
+
+int32
+runtime·port_create(void)
+{
+	return runtime·sysvicall0(libc·port_create);
+}
+
+int32
+runtime·port_associate(int32 port, int32 source, uintptr object, int32 events, uintptr user)
+{
+	return runtime·sysvicall5(libc·port_associate, (uintptr)port, (uintptr)source, object, (uintptr)events, user);
+}
+
+int32
+runtime·port_dissociate(int32 port, int32 source, uintptr object)
+{
+	return runtime·sysvicall3(libc·port_dissociate, (uintptr)port, (uintptr)source, object);
+}
+
+int32
+runtime·port_getn(int32 port, PortEvent *evs, uint32 max, uint32 *nget, Timespec *timeout)
+{
+	return runtime·sysvicall5(libc·port_getn, (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/runtime/netpoll_stub.c b/src/runtime/netpoll_stub.c
new file mode 100644
index 0000000..b7a8f29
--- /dev/null
+++ b/src/runtime/netpoll_stub.c
@@ -0,0 +1,18 @@
+// 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 plan9
+
+#include "runtime.h"
+
+// Polls for ready network connections.
+// Returns list of goroutines that become runnable.
+G*
+runtime·netpoll(bool block)
+{
+	// Implementation for platforms that do not support
+	// integrated network poller.
+	USED(block);
+	return nil;
+}
diff --git a/src/runtime/netpoll_windows.c b/src/runtime/netpoll_windows.c
new file mode 100644
index 0000000..64da41a
--- /dev/null
+++ b/src/runtime/netpoll_windows.c
@@ -0,0 +1,163 @@
+// 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"
+
+#define DWORD_MAX 0xffffffff
+
+#pragma dynimport runtime·CreateIoCompletionPort CreateIoCompletionPort "kernel32.dll"
+#pragma dynimport runtime·GetQueuedCompletionStatus GetQueuedCompletionStatus "kernel32.dll"
+#pragma dynimport runtime·WSAGetOverlappedResult WSAGetOverlappedResult "ws2_32.dll"
+
+extern void *runtime·CreateIoCompletionPort;
+extern void *runtime·GetQueuedCompletionStatus;
+extern void *runtime·WSAGetOverlappedResult;
+
+#define INVALID_HANDLE_VALUE ((uintptr)-1)
+
+// net_op must be the same as beginning of net.operation. Keep these in sync.
+typedef struct net_op net_op;
+struct net_op
+{
+	// used by windows
+	Overlapped	o;
+	// used by netpoll
+	PollDesc*	pd;
+	int32	mode;
+	int32	errno;
+	uint32	qty;
+};
+
+typedef struct OverlappedEntry OverlappedEntry;
+struct OverlappedEntry
+{
+	uintptr	key;
+	net_op*	op;  // In reality it's Overlapped*, but we cast it to net_op* anyway.
+	uintptr	internal;
+	uint32	qty;
+};
+
+static void handlecompletion(G **gpp, net_op *o, int32 errno, uint32 qty);
+
+static uintptr iocphandle = INVALID_HANDLE_VALUE;  // completion port io handle
+
+void
+runtime·netpollinit(void)
+{
+	iocphandle = (uintptr)runtime·stdcall4(runtime·CreateIoCompletionPort, INVALID_HANDLE_VALUE, 0, 0, DWORD_MAX);
+	if(iocphandle == 0) {
+		runtime·printf("netpoll: failed to create iocp handle (errno=%d)\n", runtime·getlasterror());
+		runtime·throw("netpoll: failed to create iocp handle");
+	}
+	return;
+}
+
+int32
+runtime·netpollopen(uintptr fd, PollDesc *pd)
+{
+	USED(pd);
+	if(runtime·stdcall4(runtime·CreateIoCompletionPort, fd, iocphandle, 0, 0) == 0)
+		return -runtime·getlasterror();
+	return 0;
+}
+
+int32
+runtime·netpollclose(uintptr fd)
+{
+	// nothing to do
+	USED(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*
+runtime·netpoll(bool block)
+{
+	OverlappedEntry entries[64];
+	uint32 wait, qty, key, flags, n, i;
+	int32 errno;
+	net_op *op;
+	G *gp;
+
+	if(iocphandle == INVALID_HANDLE_VALUE)
+		return nil;
+	gp = nil;
+	wait = 0;
+	if(block)
+		wait = INFINITE;
+retry:
+	if(runtime·GetQueuedCompletionStatusEx != nil) {
+		n = nelem(entries) / runtime·gomaxprocs;
+		if(n < 8)
+			n = 8;
+		if(block)
+			g->m->blocked = true;
+		if(runtime·stdcall6(runtime·GetQueuedCompletionStatusEx, iocphandle, (uintptr)entries, n, (uintptr)&n, wait, 0) == 0) {
+			g->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");
+		}
+		g->m->blocked = false;
+		for(i = 0; i < n; i++) {
+			op = entries[i].op;
+			errno = 0;
+			qty = 0;
+			if(runtime·stdcall5(runtime·WSAGetOverlappedResult, runtime·netpollfd(op->pd), (uintptr)op, (uintptr)&qty, 0, (uintptr)&flags) == 0)
+				errno = runtime·getlasterror();
+			handlecompletion(&gp, op, errno, qty);
+		}
+	} else {
+		op = nil;
+		errno = 0;
+		qty = 0;
+		if(block)
+			g->m->blocked = true;
+		if(runtime·stdcall5(runtime·GetQueuedCompletionStatus, iocphandle, (uintptr)&qty, (uintptr)&key, (uintptr)&op, wait) == 0) {
+			g->m->blocked = false;
+			errno = runtime·getlasterror();
+			if(!block && errno == WAIT_TIMEOUT)
+				return nil;
+			if(op == nil) {
+				runtime·printf("netpoll: GetQueuedCompletionStatus failed (errno=%d)\n", errno);
+				runtime·throw("netpoll: GetQueuedCompletionStatus failed");
+			}
+			// dequeued failed IO packet, so report that
+		}
+		g->m->blocked = false;
+		handlecompletion(&gp, op, errno, qty);
+	}
+	if(block && gp == nil)
+		goto retry;
+	return gp;
+}
+
+static void
+handlecompletion(G **gpp, net_op *op, int32 errno, uint32 qty)
+{
+	int32 mode;
+
+	if(op == nil)
+		runtime·throw("netpoll: GetQueuedCompletionStatus returned op == nil");
+	mode = op->mode;
+	if(mode != 'r' && mode != 'w') {
+		runtime·printf("netpoll: GetQueuedCompletionStatus returned invalid mode=%d\n", mode);
+		runtime·throw("netpoll: GetQueuedCompletionStatus returned invalid mode");
+	}
+	op->errno = errno;
+	op->qty = qty;
+	runtime·netpollready(gpp, op->pd, mode);
+}
diff --git a/src/runtime/noasm_arm.go b/src/runtime/noasm_arm.go
new file mode 100644
index 0000000..dd3ef82
--- /dev/null
+++ b/src/runtime/noasm_arm.go
@@ -0,0 +1,54 @@
+// 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.
+
+// Routines that are implemented in assembly in asm_{amd64,386}.s
+// but are implemented in Go for arm.
+
+package runtime
+
+func cmpstring(s1, s2 string) int {
+	l := len(s1)
+	if len(s2) < l {
+		l = len(s2)
+	}
+	for i := 0; i < l; i++ {
+		c1, c2 := s1[i], s2[i]
+		if c1 < c2 {
+			return -1
+		}
+		if c1 > c2 {
+			return +1
+		}
+	}
+	if len(s1) < len(s2) {
+		return -1
+	}
+	if len(s1) > len(s2) {
+		return +1
+	}
+	return 0
+}
+
+func cmpbytes(s1, s2 []byte) int {
+	l := len(s1)
+	if len(s2) < l {
+		l = len(s2)
+	}
+	for i := 0; i < l; i++ {
+		c1, c2 := s1[i], s2[i]
+		if c1 < c2 {
+			return -1
+		}
+		if c1 > c2 {
+			return +1
+		}
+	}
+	if len(s1) < len(s2) {
+		return -1
+	}
+	if len(s1) > len(s2) {
+		return +1
+	}
+	return 0
+}
diff --git a/src/runtime/norace_test.go b/src/runtime/norace_test.go
index 3681bf1..3b17187 100644
--- a/src/runtime/norace_test.go
+++ b/src/runtime/norace_test.go
@@ -34,12 +34,12 @@ func benchmarkSyscall(b *testing.B, work, excess int) {
 	b.RunParallel(func(pb *testing.PB) {
 		foo := 42
 		for pb.Next() {
-			runtime.Entersyscall(0)
+			runtime.Entersyscall()
 			for i := 0; i < work; i++ {
 				foo *= 2
 				foo /= 2
 			}
-			runtime.Exitsyscall(0)
+			runtime.Exitsyscall()
 		}
 		_ = foo
 	})
diff --git a/src/runtime/os_android.c b/src/runtime/os_android.c
new file mode 100644
index 0000000..5805f68
--- /dev/null
+++ b/src/runtime/os_android.c
@@ -0,0 +1,16 @@
+// 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 "defs_GOOS_GOARCH.h"
+#include "os_GOOS.h"
+
+// Export the runtime entry point symbol.
+//
+// Used by the app package to start the Go runtime after loading
+// a shared library via JNI. See golang.org/x/mobile/app.
+
+void _rt0_arm_linux1();
+#pragma cgo_export_static _rt0_arm_linux1
+#pragma cgo_export_dynamic _rt0_arm_linux1
diff --git a/src/runtime/os_android.h b/src/runtime/os_android.h
new file mode 100644
index 0000000..c7c1098
--- /dev/null
+++ b/src/runtime/os_android.h
@@ -0,0 +1 @@
+#include "os_linux.h"
diff --git a/src/runtime/os_darwin.c b/src/runtime/os_darwin.c
new file mode 100644
index 0000000..bbd2928
--- /dev/null
+++ b/src/runtime/os_darwin.c
@@ -0,0 +1,567 @@
+// 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 "defs_GOOS_GOARCH.h"
+#include "os_GOOS.h"
+#include "signal_unix.h"
+#include "stack.h"
+#include "textflag.h"
+
+extern SigTab runtime·sigtab[];
+
+static Sigset sigset_none;
+static Sigset sigset_all = ~(Sigset)0;
+
+static void
+unimplemented(int8 *name)
+{
+	runtime·prints(name);
+	runtime·prints(" not implemented\n");
+	*(int32*)1231 = 1231;
+}
+
+#pragma textflag NOSPLIT
+void
+runtime·semawakeup(M *mp)
+{
+	runtime·mach_semrelease(mp->waitsema);
+}
+
+static void
+semacreate(void)
+{
+	g->m->scalararg[0] = runtime·mach_semcreate();
+}
+
+#pragma textflag NOSPLIT
+uintptr
+runtime·semacreate(void)
+{
+	uintptr x;
+	void (*fn)(void);
+	
+	fn = semacreate;
+	runtime·onM(&fn);
+	x = g->m->scalararg[0];
+	g->m->scalararg[0] = 0;
+	return x;
+}
+
+// BSD interface for threading.
+void
+runtime·osinit(void)
+{
+	// bsdthread_register delayed until end of goenvs so that we
+	// can look at the environment first.
+
+	// Use sysctl to fetch hw.ncpu.
+	uint32 mib[2];
+	uint32 out;
+	int32 ret;
+	uintptr nout;
+
+	mib[0] = 6;
+	mib[1] = 3;
+	nout = sizeof out;
+	out = 0;
+	ret = runtime·sysctl(mib, 2, (byte*)&out, &nout, nil, 0);
+	if(ret >= 0)
+		runtime·ncpu = out;
+}
+
+#pragma textflag NOSPLIT
+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();
+
+	// Register our thread-creation callback (see sys_darwin_{amd64,386}.s)
+	// but only if we're not using cgo.  If we are using cgo we need
+	// to let the C pthread library install its own thread-creation callback.
+	if(!runtime·iscgo) {
+		if(runtime·bsdthread_register() != 0) {
+			if(runtime·getenv("DYLD_INSERT_LIBRARIES"))
+				runtime·throw("runtime: bsdthread_register error (unset DYLD_INSERT_LIBRARIES)");
+			runtime·throw("runtime: bsdthread_register error");
+		}
+	}
+
+}
+
+void
+runtime·newosproc(M *mp, void *stk)
+{
+	int32 errno;
+	Sigset oset;
+
+	mp->tls[0] = mp->id;	// so 386 asm can find it
+	if(0){
+		runtime·printf("newosproc stk=%p m=%p g=%p id=%d/%d ostk=%p\n",
+			stk, mp, mp->g0, mp->id, (int32)mp->tls[0], &mp);
+	}
+
+	runtime·sigprocmask(SIG_SETMASK, &sigset_all, &oset);
+	errno = runtime·bsdthread_create(stk, mp, mp->g0, runtime·mstart);
+	runtime·sigprocmask(SIG_SETMASK, &oset, nil);
+
+	if(errno < 0) {
+		runtime·printf("runtime: failed to create new OS thread (have %d already; errno=%d)\n", runtime·mcount(), -errno);
+		runtime·throw("runtime.newosproc");
+	}
+}
+
+// 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
+	mp->gsignal->m = mp;
+}
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the new thread, can not allocate memory.
+void
+runtime·minit(void)
+{
+	// Initialize signal handling.
+	runtime·signalstack((byte*)g->m->gsignal->stack.lo, 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);
+}
+
+// Mach IPC, to get at semaphores
+// Definitions are in /usr/include/mach on a Mac.
+
+static void
+macherror(int32 r, int8 *fn)
+{
+	runtime·prints("mach error ");
+	runtime·prints(fn);
+	runtime·prints(": ");
+	runtime·printint(r);
+	runtime·prints("\n");
+	runtime·throw("mach error");
+}
+
+enum
+{
+	DebugMach = 0
+};
+
+static MachNDR zerondr;
+
+#define MACH_MSGH_BITS(a, b) ((a) | ((b)<<8))
+
+static int32
+mach_msg(MachHeader *h,
+	int32 op,
+	uint32 send_size,
+	uint32 rcv_size,
+	uint32 rcv_name,
+	uint32 timeout,
+	uint32 notify)
+{
+	// TODO: Loop on interrupt.
+	return runtime·mach_msg_trap(h, op, send_size, rcv_size, rcv_name, timeout, notify);
+}
+
+// Mach RPC (MIG)
+
+enum
+{
+	MinMachMsg = 48,
+	Reply = 100,
+};
+
+#pragma pack on
+typedef struct CodeMsg CodeMsg;
+struct CodeMsg
+{
+	MachHeader h;
+	MachNDR NDR;
+	int32 code;
+};
+#pragma pack off
+
+static int32
+machcall(MachHeader *h, int32 maxsize, int32 rxsize)
+{
+	uint32 *p;
+	int32 i, ret, id;
+	uint32 port;
+	CodeMsg *c;
+
+	if((port = g->m->machport) == 0){
+		port = runtime·mach_reply_port();
+		g->m->machport = port;
+	}
+
+	h->msgh_bits |= MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND_ONCE);
+	h->msgh_local_port = port;
+	h->msgh_reserved = 0;
+	id = h->msgh_id;
+
+	if(DebugMach){
+		p = (uint32*)h;
+		runtime·prints("send:\t");
+		for(i=0; i<h->msgh_size/sizeof(p[0]); i++){
+			runtime·prints(" ");
+			runtime·printpointer((void*)p[i]);
+			if(i%8 == 7)
+				runtime·prints("\n\t");
+		}
+		if(i%8)
+			runtime·prints("\n");
+	}
+
+	ret = mach_msg(h, MACH_SEND_MSG|MACH_RCV_MSG,
+		h->msgh_size, maxsize, port, 0, 0);
+	if(ret != 0){
+		if(DebugMach){
+			runtime·prints("mach_msg error ");
+			runtime·printint(ret);
+			runtime·prints("\n");
+		}
+		return ret;
+	}
+
+	if(DebugMach){
+		p = (uint32*)h;
+		runtime·prints("recv:\t");
+		for(i=0; i<h->msgh_size/sizeof(p[0]); i++){
+			runtime·prints(" ");
+			runtime·printpointer((void*)p[i]);
+			if(i%8 == 7)
+				runtime·prints("\n\t");
+		}
+		if(i%8)
+			runtime·prints("\n");
+	}
+
+	if(h->msgh_id != id+Reply){
+		if(DebugMach){
+			runtime·prints("mach_msg reply id mismatch ");
+			runtime·printint(h->msgh_id);
+			runtime·prints(" != ");
+			runtime·printint(id+Reply);
+			runtime·prints("\n");
+		}
+		return -303;	// MIG_REPLY_MISMATCH
+	}
+
+	// Look for a response giving the return value.
+	// Any call can send this back with an error,
+	// and some calls only have return values so they
+	// send it back on success too.  I don't quite see how
+	// you know it's one of these and not the full response
+	// format, so just look if the message is right.
+	c = (CodeMsg*)h;
+	if(h->msgh_size == sizeof(CodeMsg)
+	&& !(h->msgh_bits & MACH_MSGH_BITS_COMPLEX)){
+		if(DebugMach){
+			runtime·prints("mig result ");
+			runtime·printint(c->code);
+			runtime·prints("\n");
+		}
+		return c->code;
+	}
+
+	if(h->msgh_size != rxsize){
+		if(DebugMach){
+			runtime·prints("mach_msg reply size mismatch ");
+			runtime·printint(h->msgh_size);
+			runtime·prints(" != ");
+			runtime·printint(rxsize);
+			runtime·prints("\n");
+		}
+		return -307;	// MIG_ARRAY_TOO_LARGE
+	}
+
+	return 0;
+}
+
+
+// Semaphores!
+
+enum
+{
+	Tmach_semcreate = 3418,
+	Rmach_semcreate = Tmach_semcreate + Reply,
+
+	Tmach_semdestroy = 3419,
+	Rmach_semdestroy = Tmach_semdestroy + Reply,
+
+	// Mach calls that get interrupted by Unix signals
+	// return this error code.  We retry them.
+	KERN_ABORTED = 14,
+	KERN_OPERATION_TIMED_OUT = 49,
+};
+
+typedef struct Tmach_semcreateMsg Tmach_semcreateMsg;
+typedef struct Rmach_semcreateMsg Rmach_semcreateMsg;
+typedef struct Tmach_semdestroyMsg Tmach_semdestroyMsg;
+// Rmach_semdestroyMsg = CodeMsg
+
+#pragma pack on
+struct Tmach_semcreateMsg
+{
+	MachHeader h;
+	MachNDR ndr;
+	int32 policy;
+	int32 value;
+};
+
+struct Rmach_semcreateMsg
+{
+	MachHeader h;
+	MachBody body;
+	MachPort semaphore;
+};
+
+struct Tmach_semdestroyMsg
+{
+	MachHeader h;
+	MachBody body;
+	MachPort semaphore;
+};
+#pragma pack off
+
+uint32
+runtime·mach_semcreate(void)
+{
+	union {
+		Tmach_semcreateMsg tx;
+		Rmach_semcreateMsg rx;
+		uint8 pad[MinMachMsg];
+	} m;
+	int32 r;
+
+	m.tx.h.msgh_bits = 0;
+	m.tx.h.msgh_size = sizeof(m.tx);
+	m.tx.h.msgh_remote_port = runtime·mach_task_self();
+	m.tx.h.msgh_id = Tmach_semcreate;
+	m.tx.ndr = zerondr;
+
+	m.tx.policy = 0;	// 0 = SYNC_POLICY_FIFO
+	m.tx.value = 0;
+
+	while((r = machcall(&m.tx.h, sizeof m, sizeof(m.rx))) != 0){
+		if(r == KERN_ABORTED)	// interrupted
+			continue;
+		macherror(r, "semaphore_create");
+	}
+	if(m.rx.body.msgh_descriptor_count != 1)
+		unimplemented("mach_semcreate desc count");
+	return m.rx.semaphore.name;
+}
+
+void
+runtime·mach_semdestroy(uint32 sem)
+{
+	union {
+		Tmach_semdestroyMsg tx;
+		uint8 pad[MinMachMsg];
+	} m;
+	int32 r;
+
+	m.tx.h.msgh_bits = MACH_MSGH_BITS_COMPLEX;
+	m.tx.h.msgh_size = sizeof(m.tx);
+	m.tx.h.msgh_remote_port = runtime·mach_task_self();
+	m.tx.h.msgh_id = Tmach_semdestroy;
+	m.tx.body.msgh_descriptor_count = 1;
+	m.tx.semaphore.name = sem;
+	m.tx.semaphore.disposition = MACH_MSG_TYPE_MOVE_SEND;
+	m.tx.semaphore.type = 0;
+
+	while((r = machcall(&m.tx.h, sizeof m, 0)) != 0){
+		if(r == KERN_ABORTED)	// interrupted
+			continue;
+		macherror(r, "semaphore_destroy");
+	}
+}
+
+// The other calls have simple system call traps in sys_darwin_{amd64,386}.s
+int32 runtime·mach_semaphore_wait(uint32 sema);
+int32 runtime·mach_semaphore_timedwait(uint32 sema, uint32 sec, uint32 nsec);
+int32 runtime·mach_semaphore_signal(uint32 sema);
+int32 runtime·mach_semaphore_signal_all(uint32 sema);
+
+static void
+semasleep(void)
+{
+	int32 r, secs, nsecs;
+	int64 ns;
+	
+	ns = (int64)(uint32)g->m->scalararg[0] | (int64)(uint32)g->m->scalararg[1]<<32;
+	g->m->scalararg[0] = 0;
+	g->m->scalararg[1] = 0;
+
+	if(ns >= 0) {
+		secs = runtime·timediv(ns, 1000000000, &nsecs);
+		r = runtime·mach_semaphore_timedwait(g->m->waitsema, secs, nsecs);
+		if(r == KERN_ABORTED || r == KERN_OPERATION_TIMED_OUT) {
+			g->m->scalararg[0] = -1;
+			return;
+		}
+		if(r != 0)
+			macherror(r, "semaphore_wait");
+		g->m->scalararg[0] = 0;
+		return;
+	}
+	while((r = runtime·mach_semaphore_wait(g->m->waitsema)) != 0) {
+		if(r == KERN_ABORTED)	// interrupted
+			continue;
+		macherror(r, "semaphore_wait");
+	}
+	g->m->scalararg[0] = 0;
+	return;
+}
+
+#pragma textflag NOSPLIT
+int32
+runtime·semasleep(int64 ns)
+{
+	int32 r;
+	void (*fn)(void);
+
+	g->m->scalararg[0] = (uint32)ns;
+	g->m->scalararg[1] = (uint32)(ns>>32);
+	fn = semasleep;
+	runtime·onM(&fn);
+	r = g->m->scalararg[0];
+	g->m->scalararg[0] = 0;
+	return r;
+}
+
+static int32 mach_semrelease_errno;
+
+static void
+mach_semrelease_fail(void)
+{
+	macherror(mach_semrelease_errno, "semaphore_signal");
+}
+
+#pragma textflag NOSPLIT
+void
+runtime·mach_semrelease(uint32 sem)
+{
+	int32 r;
+	void (*fn)(void);
+
+	while((r = runtime·mach_semaphore_signal(sem)) != 0) {
+		if(r == KERN_ABORTED)	// interrupted
+			continue;
+		
+		// mach_semrelease must be completely nosplit,
+		// because it is called from Go code.
+		// If we're going to die, start that process on the m stack
+		// to avoid a Go stack split.
+		// Only do that if we're actually running on the g stack.
+		// We might be on the gsignal stack, and if so, onM will abort.
+		// We use the global variable instead of scalararg because
+		// we might be on the gsignal stack, having interrupted a
+		// normal call to onM. It doesn't quite matter, since the
+		// program is about to die, but better to be clean.
+		mach_semrelease_errno = r;
+		fn = mach_semrelease_fail;
+		if(g == g->m->curg)
+			runtime·onM(&fn);
+		else
+			fn();
+	}
+}
+
+#pragma textflag NOSPLIT
+void
+runtime·osyield(void)
+{
+	runtime·usleep(1);
+}
+
+uintptr
+runtime·memlimit(void)
+{
+	// NOTE(rsc): Could use getrlimit here,
+	// like on FreeBSD or Linux, but Darwin doesn't enforce
+	// ulimit -v, so it's unclear why we'd try to stay within
+	// the limit.
+	return 0;
+}
+
+void
+runtime·setsig(int32 i, GoSighandler *fn, bool restart)
+{
+	SigactionT sa;
+		
+	runtime·memclr((byte*)&sa, sizeof sa);
+	sa.sa_flags = SA_SIGINFO|SA_ONSTACK;
+	if(restart)
+		sa.sa_flags |= SA_RESTART;
+	sa.sa_mask = ~(uintptr)0;
+	sa.sa_tramp = (void*)runtime·sigtramp;	// runtime·sigtramp's job is to call into real handler
+	*(uintptr*)sa.__sigaction_u = (uintptr)fn;
+	runtime·sigaction(i, &sa, nil);
+}
+
+GoSighandler*
+runtime·getsig(int32 i)
+{
+	SigactionT sa;
+
+	runtime·memclr((byte*)&sa, sizeof sa);
+	runtime·sigaction(i, nil, &sa);
+	return *(void**)sa.__sigaction_u;
+}
+
+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
+int8*
+runtime·signame(int32 sig)
+{
+	return runtime·sigtab[sig].name;
+}
diff --git a/src/runtime/os_darwin.go b/src/runtime/os_darwin.go
index 3deafd5..4327ced 100644
--- a/src/runtime/os_darwin.go
+++ b/src/runtime/os_darwin.go
@@ -6,32 +6,19 @@ package runtime
 
 import "unsafe"
 
-func bsdthread_create(stk, arg unsafe.Pointer, fn uintptr) int32
+func bsdthread_create(stk, mm, gg, fn unsafe.Pointer) int32
 func bsdthread_register() int32
-
-//go:noescape
 func mach_msg_trap(h unsafe.Pointer, op int32, send_size, rcv_size, rcv_name, timeout, notify uint32) int32
-
 func mach_reply_port() uint32
 func mach_task_self() uint32
 func mach_thread_self() uint32
-
-//go:noescape
 func sysctl(mib *uint32, miblen uint32, out *byte, size *uintptr, dst *byte, ndst uintptr) int32
-
-//go:noescape
-func sigprocmask(how uint32, new, old *uint32)
-
-//go:noescape
-func sigaction(mode uint32, new, old *sigactiont)
-
-//go:noescape
-func sigaltstack(new, old *stackt)
-
+func sigprocmask(sig int32, new, old unsafe.Pointer)
+func sigaction(mode uint32, new, old unsafe.Pointer)
+func sigaltstack(new, old unsafe.Pointer)
 func sigtramp()
-
-//go:noescape
-func setitimer(mode int32, new, old *itimerval)
-
-func raise(sig int32)
-func raiseproc(int32)
+func setitimer(mode int32, new, old unsafe.Pointer)
+func mach_semaphore_wait(sema uint32) int32
+func mach_semaphore_timedwait(sema, sec, nsec uint32) int32
+func mach_semaphore_signal(sema uint32) int32
+func mach_semaphore_signal_all(sema uint32) int32
diff --git a/src/runtime/os_darwin.h b/src/runtime/os_darwin.h
new file mode 100644
index 0000000..e8bb45d
--- /dev/null
+++ b/src/runtime/os_darwin.h
@@ -0,0 +1,43 @@
+// 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.
+
+typedef byte* kevent_udata;
+
+int32	runtime·bsdthread_create(void*, M*, G*, void(*)(void));
+int32	runtime·bsdthread_register(void);
+int32	runtime·mach_msg_trap(MachHeader*, int32, uint32, uint32, uint32, uint32, uint32);
+uint32	runtime·mach_reply_port(void);
+int32	runtime·mach_semacquire(uint32, int64);
+uint32	runtime·mach_semcreate(void);
+void	runtime·mach_semdestroy(uint32);
+void	runtime·mach_semrelease(uint32);
+void	runtime·mach_semreset(uint32);
+uint32	runtime·mach_task_self(void);
+uint32	runtime·mach_task_self(void);
+uint32	runtime·mach_thread_self(void);
+uint32	runtime·mach_thread_self(void);
+int32	runtime·sysctl(uint32*, uint32, byte*, uintptr*, byte*, uintptr);
+
+typedef uint32 Sigset;
+void	runtime·sigprocmask(int32, Sigset*, Sigset*);
+void	runtime·unblocksignals(void);
+
+struct SigactionT;
+void	runtime·sigaction(uintptr, struct SigactionT*, struct SigactionT*);
+
+struct StackT;
+void	runtime·sigaltstack(struct StackT*, struct StackT*);
+void	runtime·sigtramp(void);
+void	runtime·sigpanic(void);
+void	runtime·setitimer(int32, Itimerval*, Itimerval*);
+
+
+enum {
+	NSIG = 32,
+	SI_USER = 0, /* empirically true, but not what headers say */
+	SIG_BLOCK = 1,
+	SIG_UNBLOCK = 2,
+	SIG_SETMASK = 3,
+	SS_DISABLE = 4,
+};
diff --git a/src/runtime/os_dragonfly.c b/src/runtime/os_dragonfly.c
new file mode 100644
index 0000000..e372205
--- /dev/null
+++ b/src/runtime/os_dragonfly.c
@@ -0,0 +1,312 @@
+// 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 "textflag.h"
+
+extern SigTab runtime·sigtab[];
+extern int32 runtime·sys_umtx_sleep(uint32*, int32, int32);
+extern int32 runtime·sys_umtx_wakeup(uint32*, int32);
+
+// From DragonFly's <sys/sysctl.h>
+#define	CTL_HW	6
+#define	HW_NCPU	3
+
+static Sigset sigset_none;
+static Sigset sigset_all = { ~(uint32)0, ~(uint32)0, ~(uint32)0, ~(uint32)0, };
+
+static int32
+getncpu(void)
+{
+	uint32 mib[2];
+	uint32 out;
+	int32 ret;
+	uintptr nout;
+
+	// Fetch hw.ncpu via sysctl.
+	mib[0] = CTL_HW;
+	mib[1] = HW_NCPU;
+	nout = sizeof out;
+	out = 0;
+	ret = runtime·sysctl(mib, 2, (byte*)&out, &nout, nil, 0);
+	if(ret >= 0)
+		return out;
+	else
+		return 1;
+}
+
+static void futexsleep(void);
+
+#pragma textflag NOSPLIT
+void
+runtime·futexsleep(uint32 *addr, uint32 val, int64 ns)
+{
+	void (*fn)(void);
+
+	g->m->ptrarg[0] = addr;
+	g->m->scalararg[0] = val;
+	g->m->ptrarg[1] = &ns;
+
+	fn = futexsleep;
+	runtime·onM(&fn);
+}
+
+static void
+futexsleep(void)
+{
+	uint32 *addr;
+	uint32 val;
+	int64 ns;
+	int32 timeout = 0;
+	int32 ret;
+
+	addr = g->m->ptrarg[0];
+	val = g->m->scalararg[0];
+	ns = *(int64*)g->m->ptrarg[1];
+	g->m->ptrarg[0] = nil;
+	g->m->scalararg[0] = 0;
+	g->m->ptrarg[1] = nil;
+
+	if(ns >= 0) {
+		// The timeout is specified in microseconds - ensure that we
+		// do not end up dividing to zero, which would put us to sleep
+		// indefinitely...
+		timeout = runtime·timediv(ns, 1000, nil);
+		if(timeout == 0)
+			timeout = 1;
+	}
+
+	// sys_umtx_sleep will return EWOULDBLOCK (EAGAIN) when the timeout
+	// expires or EBUSY if the mutex value does not match. 
+	ret = runtime·sys_umtx_sleep(addr, val, timeout);
+	if(ret >= 0 || ret == -EINTR || ret == -EAGAIN || ret == -EBUSY)
+		return;
+
+	runtime·prints("umtx_wait addr=");
+	runtime·printpointer(addr);
+	runtime·prints(" val=");
+	runtime·printint(val);
+	runtime·prints(" ret=");
+	runtime·printint(ret);
+	runtime·prints("\n");
+	*(int32*)0x1005 = 0x1005;
+}
+
+static void badfutexwakeup(void);
+
+#pragma textflag NOSPLIT
+void
+runtime·futexwakeup(uint32 *addr, uint32 cnt)
+{
+	int32 ret;
+	void (*fn)(void);
+
+	ret = runtime·sys_umtx_wakeup(addr, cnt);
+	if(ret >= 0)
+		return;
+
+	g->m->ptrarg[0] = addr;
+	g->m->scalararg[0] = ret;
+	fn = badfutexwakeup;
+	if(g == g->m->gsignal)
+		fn();
+	else
+		runtime·onM(&fn);
+	*(int32*)0x1006 = 0x1006;
+}
+
+static void
+badfutexwakeup(void)
+{
+	void *addr;
+	int32 ret;
+	
+	addr = g->m->ptrarg[0];
+	ret = g->m->scalararg[0];
+	runtime·printf("umtx_wake addr=%p ret=%d\n", addr, ret);
+}
+
+void runtime·lwp_start(void*);
+
+void
+runtime·newosproc(M *mp, void *stk)
+{
+	Lwpparams params;
+	Sigset oset;
+
+	if(0){
+		runtime·printf("newosproc stk=%p m=%p g=%p id=%d/%d ostk=%p\n",
+			stk, mp, mp->g0, mp->id, (int32)mp->tls[0], &mp);
+	}
+
+	runtime·sigprocmask(&sigset_all, &oset);
+	runtime·memclr((byte*)&params, sizeof params);
+
+	params.func = runtime·lwp_start;
+	params.arg = (byte*)mp;
+	params.stack = (byte*)stk;
+	params.tid1 = (int32*)&mp->procid;
+	params.tid2 = nil;
+
+	mp->tls[0] = mp->id;	// so 386 asm can find it
+
+	runtime·lwp_create(&params);
+	runtime·sigprocmask(&oset, nil);
+}
+
+void
+runtime·osinit(void)
+{
+	runtime·ncpu = getncpu();
+}
+
+#pragma textflag NOSPLIT
+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);
+	mp->gsignal->m = mp;
+}
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the new thread, can not allocate memory.
+void
+runtime·minit(void)
+{
+	// Initialize signal handling
+	runtime·signalstack((byte*)g->m->gsignal->stack.lo, 32*1024);
+	runtime·sigprocmask(&sigset_none, nil);
+}
+
+// Called from dropm to undo the effect of an minit.
+void
+runtime·unminit(void)
+{
+	runtime·signalstack(nil, 0);
+}
+
+uintptr
+runtime·memlimit(void)
+{
+	Rlimit rl;
+	extern byte runtime·text[], runtime·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 = runtime·end - runtime·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;
+}
+
+extern void runtime·sigtramp(void);
+
+typedef struct sigaction {
+	union {
+		void    (*__sa_handler)(int32);
+		void    (*__sa_sigaction)(int32, Siginfo*, void *);
+	} __sigaction_u;		/* signal handler */
+	int32	sa_flags;		/* see signal options below */
+	Sigset	sa_mask;		/* signal mask to apply */
+} SigactionT;
+
+void
+runtime·setsig(int32 i, GoSighandler *fn, bool restart)
+{
+	SigactionT sa;
+
+	runtime·memclr((byte*)&sa, sizeof sa);
+	sa.sa_flags = SA_SIGINFO|SA_ONSTACK;
+	if(restart)
+		sa.sa_flags |= SA_RESTART;
+	sa.sa_mask.__bits[0] = ~(uint32)0;
+	sa.sa_mask.__bits[1] = ~(uint32)0;
+	sa.sa_mask.__bits[2] = ~(uint32)0;
+	sa.sa_mask.__bits[3] = ~(uint32)0;
+	if(fn == runtime·sighandler)
+		fn = (void*)runtime·sigtramp;
+	sa.__sigaction_u.__sa_sigaction = (void*)fn;
+	runtime·sigaction(i, &sa, nil);
+}
+
+GoSighandler*
+runtime·getsig(int32 i)
+{
+	SigactionT sa;
+
+	runtime·memclr((byte*)&sa, sizeof sa);
+	runtime·sigaction(i, nil, &sa);
+	if((void*)sa.__sigaction_u.__sa_sigaction == runtime·sigtramp)
+		return runtime·sighandler;
+	return (void*)sa.__sigaction_u.__sa_sigaction;
+}
+
+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(&sigset_none, nil);
+}
+
+#pragma textflag NOSPLIT
+int8*
+runtime·signame(int32 sig)
+{
+	return runtime·sigtab[sig].name;
+}
diff --git a/src/runtime/os_dragonfly.go b/src/runtime/os_dragonfly.go
index b19270a..cdaa069 100644
--- a/src/runtime/os_dragonfly.go
+++ b/src/runtime/os_dragonfly.go
@@ -6,39 +6,15 @@ package runtime
 
 import "unsafe"
 
-//go:noescape
-func lwp_create(param *lwpparams) int32
-
-//go:noescape
-func sigaltstack(new, old *sigaltstackt)
-
-//go:noescape
-func sigfwd(fn uintptr, sig uint32, info *siginfo, ctx unsafe.Pointer)
-
-//go:noescape
-func sigaction(sig int32, new, old *sigactiont)
-
-//go:noescape
-func sigprocmask(how int32, new, old *sigset)
-
-//go:noescape
-func setitimer(mode int32, new, old *itimerval)
-
-//go:noescape
+func lwp_create(param unsafe.Pointer) int32
+func sigaltstack(new, old unsafe.Pointer)
+func sigaction(sig int32, new, old unsafe.Pointer)
+func sigprocmask(new, old unsafe.Pointer)
+func setitimer(mode int32, new, old unsafe.Pointer)
 func sysctl(mib *uint32, miblen uint32, out *byte, size *uintptr, dst *byte, ndst uintptr) int32
-
-//go:noescape
 func getrlimit(kind int32, limit unsafe.Pointer) int32
-
 func raise(sig int32)
-func raiseproc(sig int32)
-
-//go:noescape
-func sys_umtx_sleep(addr *uint32, val, timeout int32) int32
-
-//go:noescape
-func sys_umtx_wakeup(addr *uint32, val int32) int32
-
-func osyield()
+func sys_umtx_sleep(addr unsafe.Pointer, val, timeout int32) int32
+func sys_umtx_wakeup(addr unsafe.Pointer, val int32) int32
 
 const stackSystem = 0
diff --git a/src/runtime/os_dragonfly.h b/src/runtime/os_dragonfly.h
new file mode 100644
index 0000000..389736a
--- /dev/null
+++ b/src/runtime/os_dragonfly.h
@@ -0,0 +1,30 @@
+// 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.
+
+
+typedef byte* kevent_udata;
+
+int32	runtime·lwp_create(Lwpparams*);
+void	runtime·sigpanic(void);
+void	runtime·sigaltstack(SigaltstackT*, SigaltstackT*);
+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);
+
+enum {
+	NSIG = 33,
+	SI_USER = 0x10001,
+	SS_DISABLE = 4,
+	RLIMIT_AS = 10,
+};
+
+typedef struct Rlimit Rlimit;
+struct Rlimit {
+	int64	rlim_cur;
+	int64	rlim_max;
+};
+int32	runtime·getrlimit(int32, Rlimit*);
diff --git a/src/runtime/os_freebsd.c b/src/runtime/os_freebsd.c
new file mode 100644
index 0000000..a513cb6
--- /dev/null
+++ b/src/runtime/os_freebsd.c
@@ -0,0 +1,320 @@
+// 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 "textflag.h"
+
+extern SigTab runtime·sigtab[];
+extern int32 runtime·sys_umtx_op(uint32*, int32, uint32, void*, void*);
+
+// From FreeBSD's <sys/sysctl.h>
+#define	CTL_HW	6
+#define	HW_NCPU	3
+
+static Sigset sigset_none;
+static Sigset sigset_all = { ~(uint32)0, ~(uint32)0, ~(uint32)0, ~(uint32)0, };
+
+static int32
+getncpu(void)
+{
+	uint32 mib[2];
+	uint32 out;
+	int32 ret;
+	uintptr nout;
+
+	// Fetch hw.ncpu via sysctl.
+	mib[0] = CTL_HW;
+	mib[1] = HW_NCPU;
+	nout = sizeof out;
+	out = 0;
+	ret = runtime·sysctl(mib, 2, (byte*)&out, &nout, nil, 0);
+	if(ret >= 0)
+		return out;
+	else
+		return 1;
+}
+
+// FreeBSD's umtx_op syscall is effectively the same as Linux's futex, and
+// thus the code is largely similar. See linux/thread.c and lock_futex.c for comments.
+
+static void futexsleep(void);
+
+#pragma textflag NOSPLIT
+void
+runtime·futexsleep(uint32 *addr, uint32 val, int64 ns)
+{
+	void (*fn)(void);
+
+	g->m->ptrarg[0] = addr;
+	g->m->scalararg[0] = val;
+	g->m->ptrarg[1] = &ns;
+
+	fn = futexsleep;
+	runtime·onM(&fn);
+}
+
+static void
+futexsleep(void)
+{
+	uint32 *addr;
+	uint32 val;
+	int64 ns;
+	int32 ret;
+	Timespec ts;
+	
+	addr = g->m->ptrarg[0];
+	val = g->m->scalararg[0];
+	ns = *(int64*)g->m->ptrarg[1];
+	g->m->ptrarg[0] = nil;
+	g->m->scalararg[0] = 0;
+	g->m->ptrarg[1] = nil;
+
+	if(ns < 0) {
+		ret = runtime·sys_umtx_op(addr, UMTX_OP_WAIT_UINT_PRIVATE, val, nil, nil);
+		if(ret >= 0 || ret == -EINTR)
+			return;
+		goto fail;
+	}
+	// 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_PRIVATE, val, nil, &ts);
+	if(ret >= 0 || ret == -EINTR)
+		return;
+
+fail:
+	runtime·prints("umtx_wait addr=");
+	runtime·printpointer(addr);
+	runtime·prints(" val=");
+	runtime·printint(val);
+	runtime·prints(" ret=");
+	runtime·printint(ret);
+	runtime·prints("\n");
+	*(int32*)0x1005 = 0x1005;
+}
+
+static void badfutexwakeup(void);
+
+#pragma textflag NOSPLIT
+void
+runtime·futexwakeup(uint32 *addr, uint32 cnt)
+{
+	int32 ret;
+	void (*fn)(void);
+
+	ret = runtime·sys_umtx_op(addr, UMTX_OP_WAKE_PRIVATE, cnt, nil, nil);
+	if(ret >= 0)
+		return;
+
+	g->m->ptrarg[0] = addr;
+	g->m->scalararg[0] = ret;
+	fn = badfutexwakeup;
+	if(g == g->m->gsignal)
+		fn();
+	else
+		runtime·onM(&fn);
+	*(int32*)0x1006 = 0x1006;
+}
+
+static void
+badfutexwakeup(void)
+{
+	void *addr;
+	int32 ret;
+	
+	addr = g->m->ptrarg[0];
+	ret = g->m->scalararg[0];
+	runtime·printf("umtx_wake addr=%p ret=%d\n", addr, ret);
+}
+
+void runtime·thr_start(void*);
+
+void
+runtime·newosproc(M *mp, void *stk)
+{
+	ThrParam param;
+	Sigset oset;
+
+	if(0){
+		runtime·printf("newosproc stk=%p m=%p g=%p id=%d/%d ostk=%p\n",
+			stk, mp, mp->g0, mp->id, (int32)mp->tls[0], &mp);
+	}
+
+	runtime·sigprocmask(&sigset_all, &oset);
+	runtime·memclr((byte*)&param, sizeof param);
+
+	param.start_func = runtime·thr_start;
+	param.arg = (byte*)mp;
+	
+	// NOTE(rsc): This code is confused. stackbase is the top of the stack
+	// and is equal to stk. However, it's working, so I'm not changing it.
+	param.stack_base = (void*)mp->g0->stack.hi;
+	param.stack_size = (byte*)stk - (byte*)mp->g0->stack.hi;
+
+	param.child_tid = (void*)&mp->procid;
+	param.parent_tid = nil;
+	param.tls_base = (void*)&mp->tls[0];
+	param.tls_size = sizeof mp->tls;
+
+	mp->tls[0] = mp->id;	// so 386 asm can find it
+
+	runtime·thr_new(&param, sizeof param);
+	runtime·sigprocmask(&oset, nil);
+}
+
+void
+runtime·osinit(void)
+{
+	runtime·ncpu = getncpu();
+}
+
+#pragma textflag NOSPLIT
+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);
+	mp->gsignal->m = mp;
+}
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the new thread, can not allocate memory.
+void
+runtime·minit(void)
+{
+	// Initialize signal handling
+	runtime·signalstack((byte*)g->m->gsignal->stack.lo, 32*1024);
+	runtime·sigprocmask(&sigset_none, nil);
+}
+
+// Called from dropm to undo the effect of an minit.
+void
+runtime·unminit(void)
+{
+	runtime·signalstack(nil, 0);
+}
+
+uintptr
+runtime·memlimit(void)
+{
+	Rlimit rl;
+	extern byte runtime·text[], runtime·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 = runtime·end - runtime·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;
+}
+
+extern void runtime·sigtramp(void);
+
+typedef struct sigaction {
+	union {
+		void    (*__sa_handler)(int32);
+		void    (*__sa_sigaction)(int32, Siginfo*, void *);
+	} __sigaction_u;		/* signal handler */
+	int32	sa_flags;		/* see signal options below */
+	Sigset	sa_mask;		/* signal mask to apply */
+} SigactionT;
+
+void
+runtime·setsig(int32 i, GoSighandler *fn, bool restart)
+{
+	SigactionT sa;
+
+	runtime·memclr((byte*)&sa, sizeof sa);
+	sa.sa_flags = SA_SIGINFO|SA_ONSTACK;
+	if(restart)
+		sa.sa_flags |= SA_RESTART;
+	sa.sa_mask.__bits[0] = ~(uint32)0;
+	sa.sa_mask.__bits[1] = ~(uint32)0;
+	sa.sa_mask.__bits[2] = ~(uint32)0;
+	sa.sa_mask.__bits[3] = ~(uint32)0;
+	if(fn == runtime·sighandler)
+		fn = (void*)runtime·sigtramp;
+	sa.__sigaction_u.__sa_sigaction = (void*)fn;
+	runtime·sigaction(i, &sa, nil);
+}
+
+GoSighandler*
+runtime·getsig(int32 i)
+{
+	SigactionT sa;
+
+	runtime·memclr((byte*)&sa, sizeof sa);
+	runtime·sigaction(i, nil, &sa);
+	if((void*)sa.__sigaction_u.__sa_sigaction == runtime·sigtramp)
+		return runtime·sighandler;
+	return (void*)sa.__sigaction_u.__sa_sigaction;
+}
+
+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(&sigset_none, nil);
+}
+
+#pragma textflag NOSPLIT
+int8*
+runtime·signame(int32 sig)
+{
+	return runtime·sigtab[sig].name;
+}
diff --git a/src/runtime/os_freebsd.go b/src/runtime/os_freebsd.go
index 8c8a106..5970804 100644
--- a/src/runtime/os_freebsd.go
+++ b/src/runtime/os_freebsd.go
@@ -6,33 +6,12 @@ package runtime
 
 import "unsafe"
 
-//go:noescape
-func thr_new(param *thrparam, size int32)
-
-//go:noescape
-func sigaltstack(new, old *stackt)
-
-//go:noescape
-func sigfwd(fn uintptr, sig uint32, info *siginfo, ctx unsafe.Pointer)
-
-//go:noescape
-func sigaction(sig int32, new, old *sigactiont)
-
-//go:noescape
-func sigprocmask(how int32, new, old *sigset)
-
-//go:noescape
-func setitimer(mode int32, new, old *itimerval)
-
-//go:noescape
+func thr_new(param unsafe.Pointer, size int32)
+func sigaltstack(new, old unsafe.Pointer)
+func sigaction(sig int32, new, old unsafe.Pointer)
+func sigprocmask(new, old unsafe.Pointer)
+func setitimer(mode int32, new, old unsafe.Pointer)
 func sysctl(mib *uint32, miblen uint32, out *byte, size *uintptr, dst *byte, ndst uintptr) int32
-
-//go:noescape
 func getrlimit(kind int32, limit unsafe.Pointer) int32
 func raise(sig int32)
-func raiseproc(sig int32)
-
-//go:noescape
-func sys_umtx_op(addr *uint32, mode int32, val uint32, ptr2, ts *timespec) int32
-
-func osyield()
+func sys_umtx_op(addr unsafe.Pointer, mode int32, val uint32, ptr2, ts unsafe.Pointer) int32
diff --git a/src/runtime/os_freebsd.h b/src/runtime/os_freebsd.h
new file mode 100644
index 0000000..b86bb39
--- /dev/null
+++ b/src/runtime/os_freebsd.h
@@ -0,0 +1,29 @@
+// 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.
+
+typedef byte* kevent_udata;
+
+int32	runtime·thr_new(ThrParam*, int32);
+void	runtime·sigpanic(void);
+void	runtime·sigaltstack(SigaltstackT*, SigaltstackT*);
+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);
+
+enum {
+	SS_DISABLE = 4,
+	NSIG = 33,
+	SI_USER = 0x10001,
+	RLIMIT_AS = 10,
+};
+
+typedef struct Rlimit Rlimit;
+struct Rlimit {
+	int64	rlim_cur;
+	int64	rlim_max;
+};
+int32	runtime·getrlimit(int32, Rlimit*);
diff --git a/src/runtime/os_freebsd_arm.c b/src/runtime/os_freebsd_arm.c
new file mode 100644
index 0000000..2f2d776
--- /dev/null
+++ b/src/runtime/os_freebsd_arm.c
@@ -0,0 +1,24 @@
+// 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 "runtime.h"
+#include "defs_GOOS_GOARCH.h"
+#include "os_GOOS.h"
+#include "textflag.h"
+
+void
+runtime·checkgoarm(void)
+{
+	// TODO(minux)
+}
+
+#pragma textflag NOSPLIT
+int64
+runtime·cputicks(void)
+{
+	// Currently cputicks() is used in blocking profiler and to seed runtime·fastrand1().
+	// runtime·nanotime() is a poor approximation of CPU ticks that is enough for the profiler.
+	// TODO: need more entropy to better seed fastrand1.
+	return runtime·nanotime();
+}
diff --git a/src/runtime/os_linux.c b/src/runtime/os_linux.c
new file mode 100644
index 0000000..0d8ffc9
--- /dev/null
+++ b/src/runtime/os_linux.c
@@ -0,0 +1,342 @@
+// 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 "defs_GOOS_GOARCH.h"
+#include "os_GOOS.h"
+#include "signal_unix.h"
+#include "stack.h"
+#include "textflag.h"
+
+extern SigTab runtime·sigtab[];
+
+static Sigset sigset_none;
+static Sigset sigset_all = { ~(uint32)0, ~(uint32)0 };
+
+// Linux futex.
+//
+//	futexsleep(uint32 *addr, uint32 val)
+//	futexwakeup(uint32 *addr)
+//
+// Futexsleep atomically checks if *addr == val and if so, sleeps on addr.
+// Futexwakeup wakes up threads sleeping on addr.
+// Futexsleep is allowed to wake up spuriously.
+
+enum
+{
+	FUTEX_WAIT = 0,
+	FUTEX_WAKE = 1,
+};
+
+// Atomically,
+//	if(*addr == val) sleep
+// Might be woken up spuriously; that's allowed.
+// Don't sleep longer than ns; ns < 0 means forever.
+#pragma textflag NOSPLIT
+void
+runtime·futexsleep(uint32 *addr, uint32 val, int64 ns)
+{
+	Timespec ts;
+
+	// Some Linux kernels have a bug where futex of
+	// FUTEX_WAIT returns an internal error code
+	// as an errno.  Libpthread ignores the return value
+	// here, and so can we: as it says a few lines up,
+	// spurious wakeups are allowed.
+
+	if(ns < 0) {
+		runtime·futex(addr, FUTEX_WAIT, val, nil, nil, 0);
+		return;
+	}
+	// NOTE: tv_nsec is int64 on amd64, so this assumes a little-endian system.
+	ts.tv_nsec = 0;
+	ts.tv_sec = runtime·timediv(ns, 1000000000LL, (int32*)&ts.tv_nsec);
+	runtime·futex(addr, FUTEX_WAIT, val, &ts, nil, 0);
+}
+
+static void badfutexwakeup(void);
+
+// If any procs are sleeping on addr, wake up at most cnt.
+#pragma textflag NOSPLIT
+void
+runtime·futexwakeup(uint32 *addr, uint32 cnt)
+{
+	int64 ret;
+	void (*fn)(void);
+
+	ret = runtime·futex(addr, FUTEX_WAKE, cnt, nil, nil, 0);
+	if(ret >= 0)
+		return;
+
+	// I don't know that futex wakeup can return
+	// EAGAIN or EINTR, but if it does, it would be
+	// safe to loop and call futex again.
+	g->m->ptrarg[0] = addr;
+	g->m->scalararg[0] = (int32)ret; // truncated but fine
+	fn = badfutexwakeup;
+	if(g == g->m->gsignal)
+		fn();
+	else
+		runtime·onM(&fn);
+	*(int32*)0x1006 = 0x1006;
+}
+
+static void
+badfutexwakeup(void)
+{
+	void *addr;
+	int64 ret;
+	
+	addr = g->m->ptrarg[0];
+	ret = (int32)g->m->scalararg[0];
+	runtime·printf("futexwakeup addr=%p returned %D\n", addr, ret);
+}
+
+extern runtime·sched_getaffinity(uintptr pid, uintptr len, uintptr *buf);
+static int32
+getproccount(void)
+{
+	uintptr buf[16], t;
+	int32 r, cnt, i;
+
+	cnt = 0;
+	r = runtime·sched_getaffinity(0, sizeof(buf), buf);
+	if(r > 0)
+	for(i = 0; i < r/sizeof(buf[0]); i++) {
+		t = buf[i];
+		t = t - ((t >> 1) & 0x5555555555555555ULL);
+		t = (t & 0x3333333333333333ULL) + ((t >> 2) & 0x3333333333333333ULL);
+		cnt += (int32)((((t + (t >> 4)) & 0xF0F0F0F0F0F0F0FULL) * 0x101010101010101ULL) >> 56);
+	}
+
+	return cnt ? cnt : 1;
+}
+
+// Clone, the Linux rfork.
+enum
+{
+	CLONE_VM = 0x100,
+	CLONE_FS = 0x200,
+	CLONE_FILES = 0x400,
+	CLONE_SIGHAND = 0x800,
+	CLONE_PTRACE = 0x2000,
+	CLONE_VFORK = 0x4000,
+	CLONE_PARENT = 0x8000,
+	CLONE_THREAD = 0x10000,
+	CLONE_NEWNS = 0x20000,
+	CLONE_SYSVSEM = 0x40000,
+	CLONE_SETTLS = 0x80000,
+	CLONE_PARENT_SETTID = 0x100000,
+	CLONE_CHILD_CLEARTID = 0x200000,
+	CLONE_UNTRACED = 0x800000,
+	CLONE_CHILD_SETTID = 0x1000000,
+	CLONE_STOPPED = 0x2000000,
+	CLONE_NEWUTS = 0x4000000,
+	CLONE_NEWIPC = 0x8000000,
+};
+
+void
+runtime·newosproc(M *mp, void *stk)
+{
+	int32 ret;
+	int32 flags;
+	Sigset oset;
+
+	/*
+	 * note: strace gets confused if we use CLONE_PTRACE here.
+	 */
+	flags = CLONE_VM	/* share memory */
+		| CLONE_FS	/* share cwd, etc */
+		| CLONE_FILES	/* share fd table */
+		| CLONE_SIGHAND	/* share sig handler table */
+		| CLONE_THREAD	/* revisit - okay for now */
+		;
+
+	mp->tls[0] = mp->id;	// so 386 asm can find it
+	if(0){
+		runtime·printf("newosproc stk=%p m=%p g=%p clone=%p id=%d/%d ostk=%p\n",
+			stk, mp, mp->g0, runtime·clone, mp->id, (int32)mp->tls[0], &mp);
+	}
+
+	// Disable signals during clone, so that the new thread starts
+	// with signals disabled.  It will enable them in minit.
+	runtime·rtsigprocmask(SIG_SETMASK, &sigset_all, &oset, sizeof oset);
+	ret = runtime·clone(flags, stk, mp, mp->g0, runtime·mstart);
+	runtime·rtsigprocmask(SIG_SETMASK, &oset, nil, sizeof oset);
+
+	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·osinit(void)
+{
+	runtime·ncpu = getproccount();
+}
+
+// Random bytes initialized at startup.  These come
+// from the ELF AT_RANDOM auxiliary vector (vdso_linux_amd64.c).
+byte*	runtime·startup_random_data;
+uint32	runtime·startup_random_data_len;
+
+#pragma textflag NOSPLIT
+void
+runtime·get_random_data(byte **rnd, int32 *rnd_len)
+{
+	if(runtime·startup_random_data != nil) {
+		*rnd = runtime·startup_random_data;
+		*rnd_len = runtime·startup_random_data_len;
+	} else {
+		#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);	// OS X wants >=8K, Linux >=2K
+	mp->gsignal->m = mp;
+}
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the new thread, can not allocate memory.
+void
+runtime·minit(void)
+{
+	// Initialize signal handling.
+	runtime·signalstack((byte*)g->m->gsignal->stack.lo, 32*1024);
+	runtime·rtsigprocmask(SIG_SETMASK, &sigset_none, nil, sizeof(Sigset));
+}
+
+// Called from dropm to undo the effect of an minit.
+void
+runtime·unminit(void)
+{
+	runtime·signalstack(nil, 0);
+}
+
+uintptr
+runtime·memlimit(void)
+{
+	Rlimit rl;
+	extern byte runtime·text[], runtime·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 = runtime·end - runtime·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;
+}
+
+#ifdef GOARCH_386
+#define sa_handler k_sa_handler
+#endif
+
+/*
+ * This assembler routine takes the args from registers, puts them on the stack,
+ * and calls sighandler().
+ */
+extern void runtime·sigtramp(void);
+extern void runtime·sigreturn(void);	// calls rt_sigreturn, only used with SA_RESTORER
+
+void
+runtime·setsig(int32 i, GoSighandler *fn, bool restart)
+{
+	SigactionT sa;
+
+	runtime·memclr((byte*)&sa, sizeof sa);
+	sa.sa_flags = SA_ONSTACK | SA_SIGINFO | SA_RESTORER;
+	if(restart)
+		sa.sa_flags |= SA_RESTART;
+	sa.sa_mask = ~0ULL;
+	// Although Linux manpage says "sa_restorer element is obsolete and
+	// should not be used". x86_64 kernel requires it. Only use it on
+	// x86.
+#ifdef GOARCH_386
+	sa.sa_restorer = (void*)runtime·sigreturn;
+#endif
+#ifdef GOARCH_amd64
+	sa.sa_restorer = (void*)runtime·sigreturn;
+#endif
+	if(fn == runtime·sighandler)
+		fn = (void*)runtime·sigtramp;
+	sa.sa_handler = fn;
+	if(runtime·rt_sigaction(i, &sa, nil, sizeof(sa.sa_mask)) != 0)
+		runtime·throw("rt_sigaction failure");
+}
+
+GoSighandler*
+runtime·getsig(int32 i)
+{
+	SigactionT sa;
+
+	runtime·memclr((byte*)&sa, sizeof sa);
+	if(runtime·rt_sigaction(i, nil, &sa, sizeof(sa.sa_mask)) != 0)
+		runtime·throw("rt_sigaction read failure");
+	if((void*)sa.sa_handler == runtime·sigtramp)
+		return runtime·sighandler;
+	return (void*)sa.sa_handler;
+}
+
+void
+runtime·signalstack(byte *p, int32 n)
+{
+	SigaltstackT st;
+
+	st.ss_sp = 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·rtsigprocmask(SIG_SETMASK, &sigset_none, nil, sizeof sigset_none);
+}
+
+#pragma textflag NOSPLIT
+int8*
+runtime·signame(int32 sig)
+{
+	return runtime·sigtab[sig].name;
+}
diff --git a/src/runtime/os_linux.go b/src/runtime/os_linux.go
index bd492f5..41123ad 100644
--- a/src/runtime/os_linux.go
+++ b/src/runtime/os_linux.go
@@ -6,32 +6,12 @@ package runtime
 
 import "unsafe"
 
-//go:noescape
 func futex(addr unsafe.Pointer, op int32, val uint32, ts, addr2 unsafe.Pointer, val3 uint32) int32
-
-//go:noescape
 func clone(flags int32, stk, mm, gg, fn unsafe.Pointer) int32
-
-//go:noescape
-func rt_sigaction(sig uintptr, new, old *sigactiont, size uintptr) int32
-
-//go:noescape
-func sigaltstack(new, old *sigaltstackt)
-
-//go:noescape
-func sigfwd(fn uintptr, sig uint32, info *siginfo, ctx unsafe.Pointer)
-
-//go:noescape
-func setitimer(mode int32, new, old *itimerval)
-
-//go:noescape
-func rtsigprocmask(sig uint32, new, old *sigset, size int32)
-
-//go:noescape
+func rt_sigaction(sig uintptr, new, old unsafe.Pointer, size uintptr) int32
+func sigaltstack(new, old unsafe.Pointer)
+func setitimer(mode int32, new, old unsafe.Pointer)
+func rtsigprocmask(sig int32, new, old unsafe.Pointer, size int32)
 func getrlimit(kind int32, limit unsafe.Pointer) int32
 func raise(sig int32)
-func raiseproc(sig int32)
-
-//go:noescape
 func sched_getaffinity(pid, len uintptr, buf *uintptr) int32
-func osyield()
diff --git a/src/runtime/os_linux.h b/src/runtime/os_linux.h
new file mode 100644
index 0000000..75606d6
--- /dev/null
+++ b/src/runtime/os_linux.h
@@ -0,0 +1,41 @@
+// 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.
+
+
+// Linux-specific system calls
+int32	runtime·futex(uint32*, int32, uint32, Timespec*, uint32*, uint32);
+int32	runtime·clone(int32, void*, M*, G*, void(*)(void));
+
+struct SigactionT;
+int32	runtime·rt_sigaction(uintptr, struct SigactionT*, void*, uintptr);
+
+void	runtime·sigaltstack(SigaltstackT*, SigaltstackT*);
+void	runtime·sigpanic(void);
+void runtime·setitimer(int32, Itimerval*, Itimerval*);
+
+enum {
+	SS_DISABLE = 2,
+	NSIG = 65,
+	SI_USER = 0,
+	SIG_SETMASK = 2,
+	RLIMIT_AS = 9,
+};
+
+// It's hard to tease out exactly how big a Sigset is, but
+// rt_sigprocmask crashes if we get it wrong, so if binaries
+// are running, this is right.
+typedef struct Sigset Sigset;
+struct Sigset
+{
+	uint32 mask[2];
+};
+void	runtime·rtsigprocmask(int32, Sigset*, Sigset*, int32);
+void	runtime·unblocksignals(void);
+
+typedef struct Rlimit Rlimit;
+struct Rlimit {
+	uintptr	rlim_cur;
+	uintptr	rlim_max;
+};
+int32	runtime·getrlimit(int32, Rlimit*);
diff --git a/src/runtime/os_linux_386.c b/src/runtime/os_linux_386.c
new file mode 100644
index 0000000..dc89d04
--- /dev/null
+++ b/src/runtime/os_linux_386.c
@@ -0,0 +1,38 @@
+// 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 "defs_GOOS_GOARCH.h"
+#include "os_GOOS.h"
+#include "textflag.h"
+
+#define AT_NULL		0
+#define AT_RANDOM	25
+#define AT_SYSINFO	32
+extern uint32 runtime·_vdso;
+
+#pragma textflag NOSPLIT
+void
+runtime·linux_setup_vdso(int32 argc, byte **argv)
+{
+	byte **envp;
+	uint32 *auxv;
+
+	// skip envp to get to ELF auxiliary vector.
+	for(envp = &argv[argc+1]; *envp != nil; envp++)
+		;
+	envp++;
+	
+	for(auxv=(uint32*)envp; auxv[0] != AT_NULL; auxv += 2) {
+		if(auxv[0] == AT_SYSINFO) {
+			runtime·_vdso = auxv[1];
+			continue;
+		}
+		if(auxv[0] == AT_RANDOM) {
+			runtime·startup_random_data = (byte*)auxv[1];
+			runtime·startup_random_data_len = 16;
+			continue;
+		}
+	}
+}
diff --git a/src/runtime/os_linux_arm.c b/src/runtime/os_linux_arm.c
new file mode 100644
index 0000000..e3eda7c
--- /dev/null
+++ b/src/runtime/os_linux_arm.c
@@ -0,0 +1,80 @@
+// 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 "defs_GOOS_GOARCH.h"
+#include "os_GOOS.h"
+#include "textflag.h"
+
+#define AT_NULL		0
+#define AT_PLATFORM	15 // introduced in at least 2.6.11
+#define AT_HWCAP	16 // introduced in at least 2.6.11
+#define AT_RANDOM	25 // introduced in 2.6.29
+#define HWCAP_VFP	(1 << 6) // introduced in at least 2.6.11
+#define HWCAP_VFPv3	(1 << 13) // introduced in 2.6.30
+static uint32 runtime·randomNumber;
+uint8  runtime·armArch = 6;	// we default to ARMv6
+uint32 runtime·hwcap;	// set by setup_auxv
+extern uint8  runtime·goarm;	// set by 5l
+
+void
+runtime·checkgoarm(void)
+{
+	if(runtime·goarm > 5 && !(runtime·hwcap & HWCAP_VFP)) {
+		runtime·printf("runtime: this CPU has no floating point hardware, so it cannot run\n");
+		runtime·printf("this GOARM=%d binary. Recompile using GOARM=5.\n", runtime·goarm);
+		runtime·exit(1);
+	}
+	if(runtime·goarm > 6 && !(runtime·hwcap & HWCAP_VFPv3)) {
+		runtime·printf("runtime: this CPU has no VFPv3 floating point hardware, so it cannot run\n");
+		runtime·printf("this GOARM=%d binary. Recompile using GOARM=6.\n", runtime·goarm);
+		runtime·exit(1);
+	}
+}
+
+#pragma textflag NOSPLIT
+void
+runtime·setup_auxv(int32 argc, byte **argv)
+{
+	byte **envp;
+	byte *rnd;
+	uint32 *auxv;
+	uint32 t;
+
+	// skip envp to get to ELF auxiliary vector.
+	for(envp = &argv[argc+1]; *envp != nil; envp++)
+		;
+	envp++;
+	
+	for(auxv=(uint32*)envp; auxv[0] != AT_NULL; auxv += 2) {
+		switch(auxv[0]) {
+		case AT_RANDOM: // kernel provided 16-byte worth of random data
+			if(auxv[1]) {
+				rnd = (byte*)auxv[1];
+				runtime·randomNumber = rnd[4] | rnd[5]<<8 | rnd[6]<<16 | rnd[7]<<24;
+			}
+			break;
+		case AT_PLATFORM: // v5l, v6l, v7l
+			if(auxv[1]) {
+				t = *(uint8*)(auxv[1]+1);
+				if(t >= '5' && t <= '7')
+					runtime·armArch = t - '0';
+			}
+			break;
+		case AT_HWCAP: // CPU capability bit flags
+			runtime·hwcap = auxv[1];
+			break;
+		}
+	}
+}
+
+#pragma textflag NOSPLIT
+int64
+runtime·cputicks(void)
+{
+	// Currently cputicks() is used in blocking profiler and to seed runtime·fastrand1().
+	// runtime·nanotime() is a poor approximation of CPU ticks that is enough for the profiler.
+	// runtime·randomNumber provides better seeding of fastrand1.
+	return runtime·nanotime() + runtime·randomNumber;
+}
diff --git a/src/runtime/os_nacl.c b/src/runtime/os_nacl.c
new file mode 100644
index 0000000..14b5583
--- /dev/null
+++ b/src/runtime/os_nacl.c
@@ -0,0 +1,312 @@
+// 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 "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
+	mp->gsignal->m = mp;
+}
+
+// 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*)g->m->gsignal->stack.lo, 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;
+	g->m->procid = 2;
+//runtime·nacl_exception_handler(runtime·sigtramp, nil);
+}
+
+void
+runtime·crash(void)
+{
+	*(int32*)0 = 0;
+}
+
+#pragma textflag NOSPLIT
+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");
+	}
+}
+
+static void
+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");
+	}
+	g->m->waitsemalock = mu;
+	g->m->scalararg[0] = cond; // assigned to m->waitsema
+}
+
+#pragma textflag NOSPLIT
+uint32
+runtime·semacreate(void)
+{
+	void (*fn)(void);
+	uint32 x;
+	
+	fn = semacreate;
+	runtime·onM(&fn);
+	x = g->m->scalararg[0];
+	g->m->scalararg[0] = 0;
+	return x;
+}
+
+static void
+semasleep(void)
+{
+	int32 ret;
+	int64 ns;
+	
+	ns = (int64)(uint32)g->m->scalararg[0] | (int64)(uint32)g->m->scalararg[1]<<32;
+	g->m->scalararg[0] = 0;
+	g->m->scalararg[1] = 0;
+	
+	ret = runtime·nacl_mutex_lock(g->m->waitsemalock);
+	if(ret < 0) {
+		//runtime·printf("nacl_mutex_lock: error %d\n", -ret);
+		runtime·throw("semasleep");
+	}
+	if(g->m->waitsemacount > 0) {
+		g->m->waitsemacount = 0;
+		runtime·nacl_mutex_unlock(g->m->waitsemalock);
+		g->m->scalararg[0] = 0;
+		return;
+	}
+
+	while(g->m->waitsemacount == 0) {
+		if(ns < 0) {
+			ret = runtime·nacl_cond_wait(g->m->waitsema, g->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(g->m->waitsema, g->m->waitsemalock, &ts);
+			if(ret == -ETIMEDOUT) {
+				runtime·nacl_mutex_unlock(g->m->waitsemalock);
+				g->m->scalararg[0] = -1;
+				return;
+			}
+			if(ret < 0) {
+				//runtime·printf("nacl_cond_timed_wait_abs: error %d\n", -ret);
+				runtime·throw("semasleep");
+			}
+		}
+	}
+			
+	g->m->waitsemacount = 0;
+	runtime·nacl_mutex_unlock(g->m->waitsemalock);
+	g->m->scalararg[0] = 0;
+}
+
+#pragma textflag NOSPLIT
+int32
+runtime·semasleep(int64 ns)
+{
+	int32 r;
+	void (*fn)(void);
+
+	g->m->scalararg[0] = (uint32)ns;
+	g->m->scalararg[1] = (uint32)(ns>>32);
+	fn = semasleep;
+	runtime·onM(&fn);
+	r = g->m->scalararg[0];
+	g->m->scalararg[0] = 0;
+	return r;
+}
+
+static void
+semawakeup(void)
+{
+	int32 ret;
+	M *mp;
+	
+	mp = g->m->ptrarg[0];
+	g->m->ptrarg[0] = nil;
+
+	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);
+}
+
+#pragma textflag NOSPLIT
+void
+runtime·semawakeup(M *mp)
+{
+	void (*fn)(void);
+
+	g->m->ptrarg[0] = mp;
+	fn = semawakeup;
+	runtime·onM(&fn);
+}
+
+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)
+{
+}
+
+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);
+*/
diff --git a/src/runtime/os_nacl.go b/src/runtime/os_nacl.go
index 3b4c136..8dd43ff 100644
--- a/src/runtime/os_nacl.go
+++ b/src/runtime/os_nacl.go
@@ -6,8 +6,8 @@ package runtime
 
 import "unsafe"
 
-func nacl_exception_stack(p uintptr, size int32) int32
-func nacl_exception_handler(fn uintptr, arg unsafe.Pointer) int32
+func nacl_exception_stack(p unsafe.Pointer, size int32) int32
+func nacl_exception_handler(fn, arg unsafe.Pointer) int32
 func nacl_sem_create(flag int32) int32
 func nacl_sem_wait(sem int32) int32
 func nacl_sem_post(sem int32) int32
@@ -19,45 +19,21 @@ func nacl_cond_create(flag int32) int32
 func nacl_cond_wait(cond, n int32) int32
 func nacl_cond_signal(cond int32) int32
 func nacl_cond_broadcast(cond int32) int32
+func nacl_cond_timed_wait_abs(cond, lock int32, ts unsafe.Pointer) int32
+func nacl_thread_create(fn, stk, tls, xx unsafe.Pointer) int32
+func nacl_nanosleep(ts, extra unsafe.Pointer) int32
 
-//go:noescape
-func nacl_cond_timed_wait_abs(cond, lock int32, ts *timespec) int32
-func nacl_thread_create(fn uintptr, stk, tls, xx unsafe.Pointer) int32
-
-//go:noescape
-func nacl_nanosleep(ts, extra *timespec) int32
-func nanotime() int64
-func mmap(addr unsafe.Pointer, n uintptr, prot, flags, fd int32, off uint32) unsafe.Pointer
-func exit(code int32)
-func osyield()
-
-//go:noescape
-func write(fd uintptr, p unsafe.Pointer, n int32) int32
-
-//go:linkname os_sigpipe os.sigpipe
 func os_sigpipe() {
-	throw("too many writes on closed pipe")
+	gothrow("too many writes on closed pipe")
 }
 
 func sigpanic() {
 	g := getg()
 	if !canpanic(g) {
-		throw("unexpected signal during runtime execution")
+		gothrow("unexpected signal during runtime execution")
 	}
 
 	// Native Client only invokes the exception handler for memory faults.
 	g.sig = _SIGSEGV
 	panicmem()
 }
-
-func sigfwd(fn uintptr, sig uint32, info *siginfo, ctx unsafe.Pointer) {
-	throw("sigfwd not implemented")
-}
-
-func raiseproc(sig int32) {
-}
-
-// Stubs so tests can link correctly.  These should never be called.
-func open(name *byte, mode, perm int32) int32
-func closefd(fd int32) int32
-func read(fd int32, p unsafe.Pointer, n int32) int32
diff --git a/src/runtime/os_nacl.h b/src/runtime/os_nacl.h
new file mode 100644
index 0000000..7c9d9c2
--- /dev/null
+++ b/src/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/runtime/os_nacl_arm.c b/src/runtime/os_nacl_arm.c
new file mode 100644
index 0000000..1248ea6
--- /dev/null
+++ b/src/runtime/os_nacl_arm.c
@@ -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.
+
+#include "runtime.h"
+#include "defs_GOOS_GOARCH.h"
+#include "os_GOOS.h"
+#include "textflag.h"
+
+void
+runtime·checkgoarm(void)
+{
+	return; // NaCl/ARM only supports ARMv7
+}
+
+#pragma textflag NOSPLIT
+int64
+runtime·cputicks(void)
+{
+	// Currently cputicks() is used in blocking profiler and to seed runtime·fastrand1().
+	// runtime·nanotime() is a poor approximation of CPU ticks that is enough for the profiler.
+	// TODO: need more entropy to better seed fastrand1.
+	return runtime·nanotime();
+}
diff --git a/src/runtime/os_netbsd.c b/src/runtime/os_netbsd.c
new file mode 100644
index 0000000..58e5bed
--- /dev/null
+++ b/src/runtime/os_netbsd.c
@@ -0,0 +1,368 @@
+// 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 "textflag.h"
+
+enum
+{
+	ESRCH = 3,
+	ENOTSUP = 91,
+
+	// From NetBSD's <sys/time.h>
+	CLOCK_REALTIME = 0,
+	CLOCK_VIRTUAL = 1,
+	CLOCK_PROF = 2,
+	CLOCK_MONOTONIC = 3
+};
+
+extern SigTab runtime·sigtab[];
+
+static Sigset sigset_none;
+static Sigset sigset_all = { ~(uint32)0, ~(uint32)0, ~(uint32)0, ~(uint32)0, };
+
+extern void runtime·getcontext(UcontextT *context);
+extern int32 runtime·lwp_create(UcontextT *context, uintptr flags, void *lwpid);
+extern void runtime·lwp_mcontext_init(void *mc, void *stack, M *mp, G *gp, void (*fn)(void));
+extern int32 runtime·lwp_park(Timespec *abstime, int32 unpark, void *hint, void *unparkhint);
+extern int32 runtime·lwp_unpark(int32 lwp, void *hint);
+extern int32 runtime·lwp_self(void);
+
+// From NetBSD's <sys/sysctl.h>
+#define	CTL_HW	6
+#define	HW_NCPU	3
+
+static int32
+getncpu(void)
+{
+	uint32 mib[2];
+	uint32 out;
+	int32 ret;
+	uintptr nout;
+
+	// Fetch hw.ncpu via sysctl.
+	mib[0] = CTL_HW;
+	mib[1] = HW_NCPU;
+	nout = sizeof out;
+	out = 0;
+	ret = runtime·sysctl(mib, 2, (byte*)&out, &nout, nil, 0);
+	if(ret >= 0)
+		return out;
+	else
+		return 1;
+}
+
+#pragma textflag NOSPLIT
+uintptr
+runtime·semacreate(void)
+{
+	return 1;
+}
+
+static void
+semasleep(void)
+{
+	int64 ns;
+	Timespec ts;
+
+	ns = (int64)(uint32)g->m->scalararg[0] | (int64)(uint32)g->m->scalararg[1]<<32;
+	g->m->scalararg[0] = 0;
+	g->m->scalararg[1] = 0;
+
+	// spin-mutex lock
+	while(runtime·xchg(&g->m->waitsemalock, 1))
+		runtime·osyield();
+
+	for(;;) {
+		// lock held
+		if(g->m->waitsemacount == 0) {
+			// sleep until semaphore != 0 or timeout.
+			// thrsleep unlocks m->waitsemalock.
+			if(ns < 0) {
+				// TODO(jsing) - potential deadlock!
+				//
+				// There is a potential deadlock here since we
+				// have to release the waitsemalock mutex
+				// before we call lwp_park() to suspend the
+				// thread. This allows another thread to
+				// release the lock and call lwp_unpark()
+				// before the thread is actually suspended.
+				// If this occurs the current thread will end
+				// up sleeping indefinitely. Unfortunately
+				// the NetBSD kernel does not appear to provide
+				// a mechanism for unlocking the userspace
+				// mutex once the thread is actually parked.
+				runtime·atomicstore(&g->m->waitsemalock, 0);
+				runtime·lwp_park(nil, 0, &g->m->waitsemacount, nil);
+			} else {
+				ns = ns + runtime·nanotime();
+				// 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);
+				// TODO(jsing) - potential deadlock!
+				// See above for details.
+				runtime·atomicstore(&g->m->waitsemalock, 0);
+				runtime·lwp_park(&ts, 0, &g->m->waitsemacount, nil);
+			}
+			// reacquire lock
+			while(runtime·xchg(&g->m->waitsemalock, 1))
+				runtime·osyield();
+		}
+
+		// lock held (again)
+		if(g->m->waitsemacount != 0) {
+			// semaphore is available.
+			g->m->waitsemacount--;
+			// spin-mutex unlock
+			runtime·atomicstore(&g->m->waitsemalock, 0);
+			g->m->scalararg[0] = 0; // semaphore acquired
+			return;
+		}
+
+		// semaphore not available.
+		// if there is a timeout, stop now.
+		// otherwise keep trying.
+		if(ns >= 0)
+			break;
+	}
+
+	// lock held but giving up
+	// spin-mutex unlock
+	runtime·atomicstore(&g->m->waitsemalock, 0);
+	g->m->scalararg[0] = -1;
+	return;
+}
+
+#pragma textflag NOSPLIT
+int32
+runtime·semasleep(int64 ns)
+{
+	int32 r;
+	void (*fn)(void);
+
+	g->m->scalararg[0] = (uint32)ns;
+	g->m->scalararg[1] = (uint32)(ns>>32);
+	fn = semasleep;
+	runtime·onM(&fn);
+	r = g->m->scalararg[0];
+	g->m->scalararg[0] = 0;
+	return r;
+}
+
+static void badsemawakeup(void);
+
+#pragma textflag NOSPLIT
+void
+runtime·semawakeup(M *mp)
+{
+	uint32 ret;
+	void (*fn)(void);
+	void *oldptr;
+	uintptr oldscalar;
+
+	// spin-mutex lock
+	while(runtime·xchg(&mp->waitsemalock, 1))
+		runtime·osyield();
+	mp->waitsemacount++;
+	// TODO(jsing) - potential deadlock, see semasleep() for details.
+	// Confirm that LWP is parked before unparking...
+	ret = runtime·lwp_unpark(mp->procid, &mp->waitsemacount);
+	if(ret != 0 && ret != ESRCH) {
+		// semawakeup can be called on signal stack.
+		// Save old ptrarg/scalararg so we can restore them.
+		oldptr = g->m->ptrarg[0];
+		oldscalar = g->m->scalararg[0];
+		g->m->ptrarg[0] = mp;
+		g->m->scalararg[0] = ret;
+		fn = badsemawakeup;
+		if(g == g->m->gsignal)
+			fn();
+		else
+			runtime·onM(&fn);
+		g->m->ptrarg[0] = oldptr;
+		g->m->scalararg[0] = oldscalar;
+	}
+	// spin-mutex unlock
+	runtime·atomicstore(&mp->waitsemalock, 0);
+}
+
+static void
+badsemawakeup(void)
+{
+	M *mp;
+	int32 ret;
+
+	mp = g->m->ptrarg[0];
+	g->m->ptrarg[0] = nil;
+	ret = g->m->scalararg[0];
+	g->m->scalararg[0] = 0;
+
+	runtime·printf("thrwakeup addr=%p sem=%d ret=%d\n", &mp->waitsemacount, mp->waitsemacount, ret);
+}
+
+void
+runtime·newosproc(M *mp, void *stk)
+{
+	UcontextT uc;
+	int32 ret;
+
+	if(0) {
+		runtime·printf(
+			"newosproc stk=%p m=%p g=%p id=%d/%d ostk=%p\n",
+			stk, mp, mp->g0, mp->id, (int32)mp->tls[0], &mp);
+	}
+
+	mp->tls[0] = mp->id;	// so 386 asm can find it
+
+	runtime·getcontext(&uc);
+	
+	uc.uc_flags = _UC_SIGMASK | _UC_CPU;
+	uc.uc_link = nil;
+	uc.uc_sigmask = sigset_all;
+
+	runtime·lwp_mcontext_init(&uc.uc_mcontext, stk, mp, mp->g0, runtime·mstart);
+
+	ret = runtime·lwp_create(&uc, 0, &mp->procid);
+
+	if(ret < 0) {
+		runtime·printf("runtime: failed to create new OS thread (have %d already; errno=%d)\n", runtime·mcount() - 1, -ret);
+		runtime·throw("runtime.newosproc");
+	}
+}
+
+void
+runtime·osinit(void)
+{
+	runtime·ncpu = getncpu();
+}
+
+#pragma textflag NOSPLIT
+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);
+	mp->gsignal->m = mp;
+}
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the new thread, can not allocate memory.
+void
+runtime·minit(void)
+{
+	g->m->procid = runtime·lwp_self();
+
+	// Initialize signal handling
+	runtime·signalstack((byte*)g->m->gsignal->stack.lo, 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);
+}
+
+uintptr
+runtime·memlimit(void)
+{
+	return 0;
+}
+
+extern void runtime·sigtramp(void);
+
+typedef struct sigaction {
+	union {
+		void    (*_sa_handler)(int32);
+		void    (*_sa_sigaction)(int32, Siginfo*, void *);
+	} _sa_u;			/* signal handler */
+	uint32	sa_mask[4];		/* signal mask to apply */
+	int32	sa_flags;		/* see signal options below */
+} SigactionT;
+
+void
+runtime·setsig(int32 i, GoSighandler *fn, bool restart)
+{
+	SigactionT sa;
+
+	runtime·memclr((byte*)&sa, sizeof sa);
+	sa.sa_flags = SA_SIGINFO|SA_ONSTACK;
+	if(restart)
+		sa.sa_flags |= SA_RESTART;
+	sa.sa_mask[0] = ~0U;
+	sa.sa_mask[1] = ~0U;
+	sa.sa_mask[2] = ~0U;
+	sa.sa_mask[3] = ~0U;
+	if (fn == runtime·sighandler)
+		fn = (void*)runtime·sigtramp;
+	sa._sa_u._sa_sigaction = (void*)fn;
+	runtime·sigaction(i, &sa, nil);
+}
+
+GoSighandler*
+runtime·getsig(int32 i)
+{
+	SigactionT sa;
+
+	runtime·memclr((byte*)&sa, sizeof sa);
+	runtime·sigaction(i, nil, &sa);
+	if((void*)sa._sa_u._sa_sigaction == runtime·sigtramp)
+		return runtime·sighandler;
+	return (void*)sa._sa_u._sa_sigaction;
+}
+
+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
+int8*
+runtime·signame(int32 sig)
+{
+	return runtime·sigtab[sig].name;
+}
diff --git a/src/runtime/os_netbsd.go b/src/runtime/os_netbsd.go
index af52099..f000c5e 100644
--- a/src/runtime/os_netbsd.go
+++ b/src/runtime/os_netbsd.go
@@ -6,42 +6,15 @@ package runtime
 
 import "unsafe"
 
-//go:noescape
-func setitimer(mode int32, new, old *itimerval)
-
-//go:noescape
-func sigaction(sig int32, new, old *sigactiont)
-
-//go:noescape
-func sigaltstack(new, old *sigaltstackt)
-
-func sigfwd(fn uintptr, sig uint32, info *siginfo, ctx unsafe.Pointer) {
-	throw("sigfwd not implemented")
-}
-
-//go:noescape
-func sigprocmask(mode int32, new, old *sigset)
-
-//go:noescape
+func setitimer(mode int32, new, old unsafe.Pointer)
+func sigaction(sig int32, new, old unsafe.Pointer)
+func sigaltstack(new, old unsafe.Pointer)
+func sigprocmask(mode int32, new, old unsafe.Pointer)
 func sysctl(mib *uint32, miblen uint32, out *byte, size *uintptr, dst *byte, ndst uintptr) int32
-
 func lwp_tramp()
-
 func raise(sig int32)
-func raiseproc(sig int32)
-
-//go:noescape
 func getcontext(ctxt unsafe.Pointer)
-
-//go:noescape
 func lwp_create(ctxt unsafe.Pointer, flags uintptr, lwpid unsafe.Pointer) int32
-
-//go:noescape
-func lwp_park(abstime *timespec, unpark int32, hint, unparkhint unsafe.Pointer) int32
-
-//go:noescape
+func lwp_park(abstime unsafe.Pointer, unpark int32, hint, unparkhint unsafe.Pointer) int32
 func lwp_unpark(lwp int32, hint unsafe.Pointer) int32
-
 func lwp_self() int32
-
-func osyield()
diff --git a/src/runtime/os_netbsd.h b/src/runtime/os_netbsd.h
new file mode 100644
index 0000000..f95db32
--- /dev/null
+++ b/src/runtime/os_netbsd.h
@@ -0,0 +1,31 @@
+// 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.
+
+
+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(SigaltstackT*, SigaltstackT*);
+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);
+
+enum {
+	SS_DISABLE = 4,
+	SIG_BLOCK = 1,
+	SIG_UNBLOCK = 2,
+	SIG_SETMASK = 3,
+	NSIG = 33,
+	SI_USER = 0,
+
+	// From NetBSD's <sys/ucontext.h>
+	_UC_SIGMASK = 0x01,
+	_UC_CPU = 0x04,
+};
diff --git a/src/runtime/os_netbsd_386.c b/src/runtime/os_netbsd_386.c
new file mode 100644
index 0000000..23e9db3
--- /dev/null
+++ b/src/runtime/os_netbsd_386.c
@@ -0,0 +1,17 @@
+// 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 "defs_GOOS_GOARCH.h"
+#include "os_GOOS.h"
+
+void
+runtime·lwp_mcontext_init(McontextT *mc, void *stack, M *mp, G *gp, void (*fn)(void))
+{
+	mc->__gregs[REG_EIP] = (uint32)runtime·lwp_tramp;
+	mc->__gregs[REG_UESP] = (uint32)stack;
+	mc->__gregs[REG_EBX] = (uint32)mp;
+	mc->__gregs[REG_EDX] = (uint32)gp;
+	mc->__gregs[REG_ESI] = (uint32)fn;
+}
diff --git a/src/runtime/os_netbsd_amd64.c b/src/runtime/os_netbsd_amd64.c
new file mode 100644
index 0000000..226846c
--- /dev/null
+++ b/src/runtime/os_netbsd_amd64.c
@@ -0,0 +1,18 @@
+// 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 "defs_GOOS_GOARCH.h"
+#include "os_GOOS.h"
+
+void
+runtime·lwp_mcontext_init(McontextT *mc, void *stack, M *mp, G *gp, void (*fn)(void))
+{
+	// Machine dependent mcontext initialisation for LWP.
+	mc->__gregs[REG_RIP] = (uint64)runtime·lwp_tramp;
+	mc->__gregs[REG_RSP] = (uint64)stack;
+	mc->__gregs[REG_R8] = (uint64)mp;
+	mc->__gregs[REG_R9] = (uint64)gp;
+	mc->__gregs[REG_R12] = (uint64)fn;
+}
diff --git a/src/runtime/os_netbsd_arm.c b/src/runtime/os_netbsd_arm.c
new file mode 100644
index 0000000..9dd4bcd
--- /dev/null
+++ b/src/runtime/os_netbsd_arm.c
@@ -0,0 +1,34 @@
+// 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"
+#include "signal_GOOS_GOARCH.h"
+#include "textflag.h"
+
+void
+runtime·lwp_mcontext_init(McontextT *mc, void *stack, M *mp, G *gp, void (*fn)(void))
+{
+	mc->__gregs[REG_R15] = (uint32)runtime·lwp_tramp;
+	mc->__gregs[REG_R13] = (uint32)stack;
+	mc->__gregs[REG_R0] = (uint32)mp;
+	mc->__gregs[REG_R1] = (uint32)gp;
+	mc->__gregs[REG_R2] = (uint32)fn;
+}
+
+void
+runtime·checkgoarm(void)
+{
+	// TODO(minux)
+}
+
+#pragma textflag NOSPLIT
+int64
+runtime·cputicks() {
+	// Currently cputicks() is used in blocking profiler and to seed runtime·fastrand1().
+	// runtime·nanotime() is a poor approximation of CPU ticks that is enough for the profiler.
+	// TODO: need more entropy to better seed fastrand1.
+	return runtime·nanotime();
+}
diff --git a/src/runtime/os_openbsd.c b/src/runtime/os_openbsd.c
new file mode 100644
index 0000000..eebaa13
--- /dev/null
+++ b/src/runtime/os_openbsd.c
@@ -0,0 +1,309 @@
+// 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 "textflag.h"
+
+enum
+{
+	ESRCH = 3,
+	EAGAIN = 35,
+	EWOULDBLOCK = EAGAIN,
+	ENOTSUP = 91,
+
+	// From OpenBSD's sys/time.h
+	CLOCK_REALTIME = 0,
+	CLOCK_VIRTUAL = 1,
+	CLOCK_PROF = 2,
+	CLOCK_MONOTONIC = 3
+};
+
+extern SigTab runtime·sigtab[];
+
+static Sigset sigset_none;
+static Sigset sigset_all = ~(Sigset)0;
+
+extern int32 runtime·tfork(TforkT *param, uintptr psize, M *mp, G *gp, void (*fn)(void));
+extern int32 runtime·thrsleep(void *ident, int32 clock_id, void *tsp, void *lock, const int32 *abort);
+extern int32 runtime·thrwakeup(void *ident, int32 n);
+
+// From OpenBSD's <sys/sysctl.h>
+#define	CTL_HW	6
+#define	HW_NCPU	3
+
+static int32
+getncpu(void)
+{
+	uint32 mib[2];
+	uint32 out;
+	int32 ret;
+	uintptr nout;
+
+	// Fetch hw.ncpu via sysctl.
+	mib[0] = CTL_HW;
+	mib[1] = HW_NCPU;
+	nout = sizeof out;
+	out = 0;
+	ret = runtime·sysctl(mib, 2, (byte*)&out, &nout, nil, 0);
+	if(ret >= 0)
+		return out;
+	else
+		return 1;
+}
+
+#pragma textflag NOSPLIT
+uintptr
+runtime·semacreate(void)
+{
+	return 1;
+}
+
+#pragma textflag NOSPLIT
+int32
+runtime·semasleep(int64 ns)
+{
+	Timespec ts, *tsp = nil;
+
+	// Compute sleep deadline.
+	if(ns >= 0) {
+		int32 nsec;
+		ns += runtime·nanotime();
+		ts.tv_sec = runtime·timediv(ns, 1000000000, &nsec);
+		ts.tv_nsec = nsec; // tv_nsec is int64 on amd64
+		tsp = &ts;
+	}
+
+	for(;;) {
+		int32 ret;
+
+		// spin-mutex lock
+		while(runtime·xchg(&g->m->waitsemalock, 1))
+			runtime·osyield();
+
+		if(g->m->waitsemacount != 0) {
+			// semaphore is available.
+			g->m->waitsemacount--;
+			// spin-mutex unlock
+			runtime·atomicstore(&g->m->waitsemalock, 0);
+			return 0;  // semaphore acquired
+		}
+
+		// sleep until semaphore != 0 or timeout.
+		// thrsleep unlocks m->waitsemalock.
+		ret = runtime·thrsleep(&g->m->waitsemacount, CLOCK_MONOTONIC, tsp, &g->m->waitsemalock, (int32 *)&g->m->waitsemacount);
+		if(ret == EWOULDBLOCK)
+			return -1;
+	}
+}
+
+static void badsemawakeup(void);
+
+#pragma textflag NOSPLIT
+void
+runtime·semawakeup(M *mp)
+{
+	uint32 ret;
+	void *oldptr;
+	uint32 oldscalar;
+	void (*fn)(void);
+
+	// spin-mutex lock
+	while(runtime·xchg(&mp->waitsemalock, 1))
+		runtime·osyield();
+	mp->waitsemacount++;
+	ret = runtime·thrwakeup(&mp->waitsemacount, 1);
+	if(ret != 0 && ret != ESRCH) {
+		// semawakeup can be called on signal stack.
+		// Save old ptrarg/scalararg so we can restore them.
+		oldptr = g->m->ptrarg[0];
+		oldscalar = g->m->scalararg[0];
+		g->m->ptrarg[0] = mp;
+		g->m->scalararg[0] = ret;
+		fn = badsemawakeup;
+		if(g == g->m->gsignal)
+			fn();
+		else
+			runtime·onM(&fn);
+		g->m->ptrarg[0] = oldptr;
+		g->m->scalararg[0] = oldscalar;
+	}
+	// spin-mutex unlock
+	runtime·atomicstore(&mp->waitsemalock, 0);
+}
+
+static void
+badsemawakeup(void)
+{
+	M *mp;
+	int32 ret;
+
+	mp = g->m->ptrarg[0];
+	g->m->ptrarg[0] = nil;
+	ret = g->m->scalararg[0];
+	g->m->scalararg[0] = 0;
+
+	runtime·printf("thrwakeup addr=%p sem=%d ret=%d\n", &mp->waitsemacount, mp->waitsemacount, ret);
+}
+
+void
+runtime·newosproc(M *mp, void *stk)
+{
+	TforkT param;
+	Sigset oset;
+	int32 ret;
+
+	if(0) {
+		runtime·printf(
+			"newosproc stk=%p m=%p g=%p id=%d/%d ostk=%p\n",
+			stk, mp, mp->g0, mp->id, (int32)mp->tls[0], &mp);
+	}
+
+	mp->tls[0] = mp->id;	// so 386 asm can find it
+
+	param.tf_tcb = (byte*)&mp->tls[0];
+	param.tf_tid = (int32*)&mp->procid;
+	param.tf_stack = stk;
+
+	oset = runtime·sigprocmask(SIG_SETMASK, sigset_all);
+	ret = runtime·tfork(&param, sizeof(param), mp, mp->g0, runtime·mstart);
+	runtime·sigprocmask(SIG_SETMASK, oset);
+
+	if(ret < 0) {
+		runtime·printf("runtime: failed to create new OS thread (have %d already; errno=%d)\n", runtime·mcount() - 1, -ret);
+		if (ret == -ENOTSUP)
+			runtime·printf("runtime: is kern.rthreads disabled?\n");
+		runtime·throw("runtime.newosproc");
+	}
+}
+
+void
+runtime·osinit(void)
+{
+	runtime·ncpu = getncpu();
+}
+
+#pragma textflag NOSPLIT
+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);
+	mp->gsignal->m = mp;
+}
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the new thread, can not allocate memory.
+void
+runtime·minit(void)
+{
+	// Initialize signal handling
+	runtime·signalstack((byte*)g->m->gsignal->stack.lo, 32*1024);
+	runtime·sigprocmask(SIG_SETMASK, sigset_none);
+}
+
+// Called from dropm to undo the effect of an minit.
+void
+runtime·unminit(void)
+{
+	runtime·signalstack(nil, 0);
+}
+
+uintptr
+runtime·memlimit(void)
+{
+	return 0;
+}
+
+extern void runtime·sigtramp(void);
+
+typedef struct sigaction {
+	union {
+		void    (*__sa_handler)(int32);
+		void    (*__sa_sigaction)(int32, Siginfo*, void *);
+	} __sigaction_u;		/* signal handler */
+	uint32	sa_mask;		/* signal mask to apply */
+	int32	sa_flags;		/* see signal options below */
+} SigactionT;
+
+void
+runtime·setsig(int32 i, GoSighandler *fn, bool restart)
+{
+	SigactionT sa;
+
+	runtime·memclr((byte*)&sa, sizeof sa);
+	sa.sa_flags = SA_SIGINFO|SA_ONSTACK;
+	if(restart)
+		sa.sa_flags |= SA_RESTART;
+	sa.sa_mask = ~0U;
+	if(fn == runtime·sighandler)
+		fn = (void*)runtime·sigtramp;
+	sa.__sigaction_u.__sa_sigaction = (void*)fn;
+	runtime·sigaction(i, &sa, nil);
+}
+
+GoSighandler*
+runtime·getsig(int32 i)
+{
+	SigactionT sa;
+
+	runtime·memclr((byte*)&sa, sizeof sa);
+	runtime·sigaction(i, nil, &sa);
+	if((void*)sa.__sigaction_u.__sa_sigaction == runtime·sigtramp)
+		return runtime·sighandler;
+	return (void*)sa.__sigaction_u.__sa_sigaction;
+}
+
+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);
+}
+
+#pragma textflag NOSPLIT
+int8*
+runtime·signame(int32 sig)
+{
+	return runtime·sigtab[sig].name;
+}
diff --git a/src/runtime/os_openbsd.go b/src/runtime/os_openbsd.go
index f94b490..a000f96 100644
--- a/src/runtime/os_openbsd.go
+++ b/src/runtime/os_openbsd.go
@@ -6,34 +6,12 @@ package runtime
 
 import "unsafe"
 
-//go:noescape
-func setitimer(mode int32, new, old *itimerval)
-
-//go:noescape
-func sigaction(sig int32, new, old *sigactiont)
-
-//go:noescape
-func sigaltstack(new, old *stackt)
-
-//go:noescape
-func sigfwd(fn uintptr, sig uint32, info *siginfo, ctx unsafe.Pointer)
-
-//go:noescape
+func setitimer(mode int32, new, old unsafe.Pointer)
+func sigaction(sig int32, new, old unsafe.Pointer)
+func sigaltstack(new, old unsafe.Pointer)
 func sigprocmask(mode int32, new uint32) uint32
-
-//go:noescape
 func sysctl(mib *uint32, miblen uint32, out *byte, size *uintptr, dst *byte, ndst uintptr) int32
-
 func raise(sig int32)
-func raiseproc(sig int32)
-
-//go:noescape
-func tfork(param *tforkt, psize uintptr, mm *m, gg *g, fn uintptr) int32
-
-//go:noescape
-func thrsleep(ident uintptr, clock_id int32, tsp *timespec, lock uintptr, abort *uint32) int32
-
-//go:noescape
-func thrwakeup(ident uintptr, n int32) int32
-
-func osyield()
+func tfork(param unsafe.Pointer, psize uintptr, mm, gg, fn unsafe.Pointer) int32
+func thrsleep(ident unsafe.Pointer, clock_id int32, tsp, lock, abort unsafe.Pointer) int32
+func thrwakeup(ident unsafe.Pointer, n int32) int32
diff --git a/src/runtime/os_openbsd.h b/src/runtime/os_openbsd.h
new file mode 100644
index 0000000..6ad9810
--- /dev/null
+++ b/src/runtime/os_openbsd.h
@@ -0,0 +1,26 @@
+// 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.
+
+
+typedef byte* 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(SigaltstackT*, SigaltstackT*);
+Sigset	runtime·sigprocmask(int32, Sigset);
+void	runtime·unblocksignals(void);
+int32	runtime·sysctl(uint32*, uint32, byte*, uintptr*, byte*, uintptr);
+
+enum {
+	SS_DISABLE = 4,
+	SIG_BLOCK = 1,
+	SIG_UNBLOCK = 2,
+	SIG_SETMASK = 3,
+	NSIG = 33,
+	SI_USER = 0,
+};
diff --git a/src/runtime/os_plan9.c b/src/runtime/os_plan9.c
new file mode 100644
index 0000000..f8c543f
--- /dev/null
+++ b/src/runtime/os_plan9.c
@@ -0,0 +1,362 @@
+// 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 "os_GOOS.h"
+#include "arch_GOARCH.h"
+#include "textflag.h"
+#include "malloc.h"
+
+int8 *goos = "plan9";
+extern SigTab runtime·sigtab[];
+
+int32 runtime·postnote(int32, int8*);
+
+// 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)
+{
+	// Initialize stack and goroutine for note handling.
+	mp->gsignal = runtime·malg(32*1024);
+	mp->gsignal->m = mp;
+	mp->notesig = (int8*)runtime·mallocgc(ERRMAX*sizeof(int8), nil, FlagNoScan);
+
+	// Initialize stack for handling strings from the
+	// errstr system call, as used in package syscall.
+	mp->errstr = (byte*)runtime·mallocgc(ERRMAX*sizeof(byte), nil, FlagNoScan);
+}
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the new thread, can not allocate memory.
+void
+runtime·minit(void)
+{
+	// Mask all SSE floating-point exceptions
+	// when running on the 64-bit kernel.
+	runtime·setfpmasks();
+}
+
+// Called from dropm to undo the effect of an minit.
+void
+runtime·unminit(void)
+{
+}
+
+
+static int32
+getproccount(void)
+{
+	int32 fd, i, n, ncpu;
+	byte buf[2048];
+
+	fd = runtime·open("/dev/sysstat", OREAD, 0);
+	if(fd < 0)
+		return 1;
+	ncpu = 0;
+	for(;;) {
+		n = runtime·read(fd, buf, sizeof buf);
+		if(n <= 0)
+			break;
+		for(i = 0; i < n; i++) {
+			if(buf[i] == '\n')
+				ncpu++;
+		}
+	}
+	runtime·close(fd);
+	return ncpu > 0 ? ncpu : 1;
+}
+
+static int32
+getpid(void)
+{
+	byte b[20], *c;
+	int32 fd;
+
+	runtime·memclr(b, sizeof(b));
+	fd = runtime·open("#c/pid", 0, 0);
+	if(fd >= 0) {
+		runtime·read(fd, b, sizeof(b));
+		runtime·close(fd);
+	}
+	c = b;
+	while(*c == ' ' || *c == '\t')
+		c++;
+	return runtime·atoi(c);
+}
+
+void
+runtime·osinit(void)
+{
+	runtime·ncpu = getproccount();
+	g->m->procid = getpid();
+	runtime·notify(runtime·sigtramp);
+}
+
+void
+runtime·crash(void)
+{
+	runtime·notify(nil);
+	*(int32*)0 = 0;
+}
+
+#pragma textflag NOSPLIT
+void
+runtime·get_random_data(byte **rnd, int32 *rnd_len)
+{
+	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
+runtime·goenvs(void)
+{
+}
+
+void
+runtime·initsig(void)
+{
+}
+
+#pragma textflag NOSPLIT
+void
+runtime·osyield(void)
+{
+	runtime·sleep(0);
+}
+
+#pragma textflag NOSPLIT
+void
+runtime·usleep(uint32 µs)
+{
+	uint32 ms;
+
+	ms = µs/1000;
+	if(ms == 0)
+		ms = 1;
+	runtime·sleep(ms);
+}
+
+#pragma textflag NOSPLIT
+int64
+runtime·nanotime(void)
+{
+	int64 ns, scratch;
+
+	ns = runtime·nsec(&scratch);
+	// TODO(aram): remove hack after I fix _nsec in the pc64 kernel.
+	if(ns == 0)
+		return scratch;
+	return ns;
+}
+
+#pragma textflag NOSPLIT
+void
+runtime·itoa(int32 n, byte *p, uint32 len)
+{
+	byte *q, c;
+	uint32 i;
+
+	if(len <= 1)
+		return;
+
+	runtime·memclr(p, len);
+	q = p;
+
+	if(n==0) {
+		*q++ = '0';
+		USED(q);
+		return;
+	}
+	if(n < 0) {
+		*q++ = '-';
+		p++;
+		n = -n;
+	}
+	for(i=0; n > 0 && i < len; i++) {
+		*q++ = '0' + (n%10);
+		n = n/10;
+	}
+	for(q--; q >= p; ) {
+		c = *p;
+		*p++ = *q;
+		*q-- = c;
+	}
+}
+
+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, buf);
+}
+
+int32
+runtime·postnote(int32 pid, int8* msg)
+{
+	int32 fd;
+	intgo len;
+	uint8 buf[128];
+	uint8 tmp[16];
+	uint8 *p, *q;
+
+	runtime·memclr(buf, sizeof buf);
+
+	/* build path string /proc/pid/note */
+	q = tmp;
+	p = buf;
+	runtime·itoa(pid, tmp, sizeof tmp);
+	runtime·memmove((void*)p, (void*)"/proc/", 6);
+	for(p += 6; *p++ = *q++; );
+	p--;
+	runtime·memmove((void*)p, (void*)"/note", 5);
+
+	fd = runtime·open((int8*)buf, OWRITE, 0);
+	if(fd < 0)
+		return -1;
+
+	len = runtime·findnull((byte*)msg);
+	if(runtime·write(fd, msg, len) != len) {
+		runtime·close(fd);
+		return -1;
+	}
+	runtime·close(fd);
+	return 0;
+}
+
+static void exit(void);
+
+#pragma textflag NOSPLIT
+void
+runtime·exit(int32 e)
+{
+	void (*fn)(void);
+
+	g->m->scalararg[0] = e;
+	fn = exit;
+	runtime·onM(&fn);
+}
+
+static void
+exit(void)
+{
+	int32 e;
+	byte tmp[16];
+	int8 *status;
+ 
+ 	e = g->m->scalararg[0];
+ 	g->m->scalararg[0] = 0;
+
+	if(e == 0)
+		status = "";
+	else {
+		/* build error string */
+		runtime·itoa(e, tmp, sizeof tmp);
+		status = (int8*)tmp;
+	}
+
+	runtime·goexitsall(status);
+	runtime·exits(status);
+}
+
+void
+runtime·newosproc(M *mp, void *stk)
+{
+	int32 pid;
+
+	if(0)
+		runtime·printf("newosproc mp=%p ostk=%p\n", mp, &mp);
+
+	USED(stk);
+	if((pid = runtime·rfork(RFPROC|RFMEM|RFNOWAIT)) < 0)
+		runtime·throw("newosproc: rfork failed\n");
+	if(pid == 0)
+		runtime·tstart_plan9(mp);
+}
+
+#pragma textflag NOSPLIT
+uintptr
+runtime·semacreate(void)
+{
+	return 1;
+}
+
+#pragma textflag NOSPLIT
+int32
+runtime·semasleep(int64 ns)
+{
+	int32 ret;
+	int32 ms;
+
+	if(ns >= 0) {
+		ms = runtime·timediv(ns, 1000000, nil);
+		if(ms == 0)
+			ms = 1;
+		ret = runtime·plan9_tsemacquire(&g->m->waitsemacount, ms);
+		if(ret == 1)
+			return 0;  // success
+		return -1;  // timeout or interrupted
+	}
+
+	while(runtime·plan9_semacquire(&g->m->waitsemacount, 1) < 0) {
+		/* interrupted; try again (c.f. lock_sema.c) */
+	}
+	return 0;  // success
+}
+
+#pragma textflag NOSPLIT
+void
+runtime·semawakeup(M *mp)
+{
+	runtime·plan9_semrelease(&mp->waitsemacount, 1);
+}
+
+#pragma textflag NOSPLIT
+int32
+runtime·read(int32 fd, void *buf, int32 nbytes)
+{
+	return runtime·pread(fd, buf, nbytes, -1LL);
+}
+
+#pragma textflag NOSPLIT
+int32
+runtime·write(uintptr fd, void *buf, int32 nbytes)
+{
+	return runtime·pwrite((int32)fd, buf, nbytes, -1LL);
+}
+
+uintptr
+runtime·memlimit(void)
+{
+	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·pwrite(2, badsignal, sizeof badsignal - 1, -1LL);
+	runtime·exits(badsignal);
+}
diff --git a/src/runtime/os_plan9.go b/src/runtime/os_plan9.go
index 6def35c..10e5531 100644
--- a/src/runtime/os_plan9.go
+++ b/src/runtime/os_plan9.go
@@ -6,67 +6,36 @@ package runtime
 
 import "unsafe"
 
-func closefd(fd int32) int32
+const _SIGPROF = 0 // dummy value for badsignal
 
-//go:noescape
-func open(name *byte, mode, perm int32) int32
-
-//go:noescape
 func pread(fd int32, buf unsafe.Pointer, nbytes int32, offset int64) int32
-
-//go:noescape
 func pwrite(fd int32, buf unsafe.Pointer, nbytes int32, offset int64) int32
-
 func seek(fd int32, offset int64, whence int32) int64
-
-//go:noescape
 func exits(msg *byte)
-
-//go:noescape
-func brk_(addr unsafe.Pointer) int32
-
+func brk_(addr unsafe.Pointer) uintptr
 func sleep(ms int32) int32
-
 func rfork(flags int32) int32
-
-//go:noescape
 func plan9_semacquire(addr *uint32, block int32) int32
-
-//go:noescape
 func plan9_tsemacquire(addr *uint32, ms int32) int32
-
-//go:noescape
 func plan9_semrelease(addr *uint32, count int32) int32
-
-//go:noescape
 func notify(fn unsafe.Pointer) int32
-
 func noted(mode int32) int32
-
-//go:noescape
 func nsec(*int64) int64
-
-//go:noescape
 func sigtramp(ureg, msg unsafe.Pointer)
-
 func setfpmasks()
-
-//go:noescape
 func tstart_plan9(newm *m)
-
 func errstr() string
 
 type _Plink uintptr
 
-//go:linkname os_sigpipe os.sigpipe
 func os_sigpipe() {
-	throw("too many writes on closed pipe")
+	gothrow("too many writes on closed pipe")
 }
 
 func sigpanic() {
 	g := getg()
 	if !canpanic(g) {
-		throw("unexpected signal during runtime execution")
+		gothrow("unexpected signal during runtime execution")
 	}
 
 	note := gostringnocopy((*byte)(unsafe.Pointer(g.m.notesig)))
@@ -78,12 +47,12 @@ func sigpanic() {
 			panicmem()
 		}
 		print("unexpected fault address ", hex(g.sigcode1), "\n")
-		throw("fault")
+		gothrow("fault")
 	case _SIGTRAP:
 		if g.paniconfault {
 			panicmem()
 		}
-		throw(note)
+		gothrow(note)
 	case _SIGINTDIV:
 		panicdivide()
 	case _SIGFLOAT:
diff --git a/src/runtime/os_plan9.h b/src/runtime/os_plan9.h
new file mode 100644
index 0000000..6d18024
--- /dev/null
+++ b/src/runtime/os_plan9.h
@@ -0,0 +1,93 @@
+// 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.
+
+// Plan 9-specific system calls
+int32	runtime·pread(int32 fd, void *buf, int32 nbytes, int64 offset);
+int32	runtime·pwrite(int32 fd, void *buf, int32 nbytes, int64 offset);
+int64	runtime·seek(int32 fd, int64 offset, int32 whence);
+void	runtime·exits(int8* msg);
+intptr	runtime·brk_(void*);
+int32	runtime·sleep(int32 ms);
+int32	runtime·rfork(int32 flags);
+int32	runtime·plan9_semacquire(uint32 *addr, int32 block);
+int32	runtime·plan9_tsemacquire(uint32 *addr, int32 ms);
+int32 	runtime·plan9_semrelease(uint32 *addr, int32 count);
+int32	runtime·notify(void (*fn)(void*, int8*));
+int32	runtime·noted(int32);
+int64	runtime·nsec(int64*);
+void	runtime·sigtramp(void*, int8*);
+void	runtime·sigpanic(void);
+void	runtime·goexitsall(int8*);
+void	runtime·setfpmasks(void);
+void	runtime·tstart_plan9(M *newm);
+
+/* open */
+enum
+{
+	OREAD	= 0,
+	OWRITE	= 1,
+	ORDWR	= 2,
+	OEXEC	= 3,
+	OTRUNC	= 16,
+	OCEXEC	= 32,
+	ORCLOSE	= 64,
+	OEXCL	= 0x1000
+};
+
+/* rfork */
+enum
+{
+	RFNAMEG         = (1<<0),
+	RFENVG          = (1<<1),
+	RFFDG           = (1<<2),
+	RFNOTEG         = (1<<3),
+	RFPROC          = (1<<4),
+	RFMEM           = (1<<5),
+	RFNOWAIT        = (1<<6),
+	RFCNAMEG        = (1<<10),
+	RFCENVG         = (1<<11),
+	RFCFDG          = (1<<12),
+	RFREND          = (1<<13),
+	RFNOMNT         = (1<<14)
+};
+
+/* notify */
+enum
+{
+	NCONT	= 0,
+	NDFLT	= 1
+};
+
+typedef struct Tos Tos;
+typedef intptr _Plink;
+
+struct Tos {
+	struct TosProf			/* Per process profiling */
+	{
+		_Plink	*pp;	/* known to be 0(ptr) */
+		_Plink	*next;	/* known to be 4(ptr) */
+		_Plink	*last;
+		_Plink	*first;
+		uint32	pid;
+		uint32	what;
+	} prof;
+	uint64	cyclefreq;	/* cycle clock frequency if there is one, 0 otherwise */
+	int64	kcycles;	/* cycles spent in kernel */
+	int64	pcycles;	/* cycles spent in process (kernel + user) */
+	uint32	pid;		/* might as well put the pid here */
+	uint32	clock;
+	/* top of stack is here */
+};
+
+enum {
+	NSIG = 14, /* number of signals in runtime·SigTab array */
+	ERRMAX = 128, /* max length of note string */
+
+	/* Notes in runtime·sigtab that are handled by runtime·sigpanic. */
+	SIGRFAULT = 2,
+	SIGWFAULT = 3,
+	SIGINTDIV = 4,
+	SIGFLOAT = 5,
+	SIGTRAP = 6,
+};
diff --git a/src/runtime/os_plan9_386.c b/src/runtime/os_plan9_386.c
new file mode 100644
index 0000000..42c6d16
--- /dev/null
+++ b/src/runtime/os_plan9_386.c
@@ -0,0 +1,150 @@
+// 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 "signals_GOOS.h"
+
+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);
+}
+
+int32
+runtime·sighandler(void *v, int8 *note, G *gp)
+{
+	uintptr *sp;
+	SigTab *t;
+	bool crash;
+	Ureg *ureg;
+	intgo len, n;
+	int32 sig, flags;
+
+	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;
+		}
+	}
+
+	if(flags & SigGoExit)
+		runtime·exits(note+9); // Strip "go: exit " prefix.
+
+	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(g->m->notesig, note, len+1);
+
+		gp->sig = sig;
+		gp->sigpc = ureg->pc;
+
+		// 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;
+			ureg->sp = (uint32)sp;
+		}
+		ureg->pc = (uintptr)runtime·sigpanic;
+		return NCONT;
+	}
+
+	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:
+	g->m->throwing = 1;
+	g->m->caughtsig = gp;
+	runtime·startpanic();
+
+	runtime·printf("%s\n", note);
+	runtime·printf("PC=%x\n", ureg->pc);
+	runtime·printf("\n");
+
+	if(runtime·gotraceback(&crash)) {
+		runtime·goroutineheader(gp);
+		runtime·tracebacktrap(ureg->pc, ureg->sp, 0, gp);
+		runtime·tracebackothers(gp);
+		runtime·printf("\n");
+		runtime·dumpregs(ureg);
+	}
+	
+	if(crash)
+		runtime·crash();
+
+Exit:
+	runtime·goexitsall(note);
+	runtime·exits(note);
+	return NDFLT; // not reached
+}
+
+void
+runtime·sigenable(uint32 sig)
+{
+	USED(sig);
+}
+
+void
+runtime·sigdisable(uint32 sig)
+{
+	USED(sig);
+}
+
+void
+runtime·resetcpuprofiler(int32 hz)
+{
+	// TODO: Enable profiling interrupts.
+	
+	g->m->profilehz = hz;
+}
diff --git a/src/runtime/os_plan9_amd64.c b/src/runtime/os_plan9_amd64.c
new file mode 100644
index 0000000..a9dc0eb
--- /dev/null
+++ b/src/runtime/os_plan9_amd64.c
@@ -0,0 +1,158 @@
+// 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 "signals_GOOS.h"
+
+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("r8	%X\n", u->r8);
+	runtime·printf("r9	%X\n", u->r9);
+	runtime·printf("r10	%X\n", u->r10);
+	runtime·printf("r11	%X\n", u->r11);
+	runtime·printf("r12	%X\n", u->r12);
+	runtime·printf("r13	%X\n", u->r13);
+	runtime·printf("r14	%X\n", u->r14);
+	runtime·printf("r15	%X\n", u->r15);
+	runtime·printf("ip	%X\n", u->ip);
+	runtime·printf("flags	%X\n", u->flags);
+	runtime·printf("cs	%X\n", (uint64)u->cs);
+	runtime·printf("fs	%X\n", (uint64)u->fs);
+	runtime·printf("gs	%X\n", (uint64)u->gs);
+}
+
+int32
+runtime·sighandler(void *v, int8 *note, G *gp)
+{
+	uintptr *sp;
+	SigTab *t;
+	bool crash;
+	Ureg *ureg;
+	intgo len, n;
+	int32 sig, flags;
+
+	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;
+		}
+	}
+
+	if(flags & SigGoExit)
+		runtime·exits(note+9); // Strip "go: exit " prefix.
+
+	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(g->m->notesig, note, len+1);
+
+		gp->sig = sig;
+		gp->sigpc = ureg->ip;
+
+		// 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;
+			ureg->sp = (uint64)sp;
+		}
+		ureg->ip = (uintptr)runtime·sigpanic;
+		return NCONT;
+	}
+
+	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:
+	g->m->throwing = 1;
+	g->m->caughtsig = gp;
+	runtime·startpanic();
+
+	runtime·printf("%s\n", note);
+	runtime·printf("PC=%X\n", ureg->ip);
+	runtime·printf("\n");
+
+	if(runtime·gotraceback(&crash)) {
+		runtime·goroutineheader(gp);
+		runtime·tracebacktrap(ureg->ip, ureg->sp, 0, gp);
+		runtime·tracebackothers(gp);
+		runtime·printf("\n");
+		runtime·dumpregs(ureg);
+	}
+	
+	if(crash)
+		runtime·crash();
+
+Exit:
+	runtime·goexitsall(note);
+	runtime·exits(note);
+	return NDFLT; // not reached
+}
+
+void
+runtime·sigenable(uint32 sig)
+{
+	USED(sig);
+}
+
+void
+runtime·sigdisable(uint32 sig)
+{
+	USED(sig);
+}
+
+void
+runtime·resetcpuprofiler(int32 hz)
+{
+	// TODO: Enable profiling interrupts.
+	
+	g->m->profilehz = hz;
+}
diff --git a/src/runtime/os_solaris.c b/src/runtime/os_solaris.c
new file mode 100644
index 0000000..e16b8e6
--- /dev/null
+++ b/src/runtime/os_solaris.c
@@ -0,0 +1,557 @@
+// 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 "textflag.h"
+
+#pragma dynexport runtime·end _end
+#pragma dynexport runtime·etext _etext
+#pragma dynexport runtime·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, };
+
+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;
+	uint64 size;
+
+	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");
+	size = 0;
+	if(runtime·pthread_attr_getstack(&attr, (void**)&mp->g0->stack.hi, &size) != 0)
+		runtime·throw("pthread_attr_getstack");	
+	mp->g0->stack.lo = mp->g0->stack.hi - size;
+	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");
+	}
+}
+
+#pragma textflag NOSPLIT
+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);
+	mp->gsignal->m = mp;
+}
+
+// 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*)g->m->gsignal->stack.lo, 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);
+}
+
+uintptr
+runtime·memlimit(void)
+{
+	Rlimit rl;
+	extern byte runtime·text[], runtime·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 = runtime·end - runtime·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)
+{
+	SigactionT 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)
+{
+	SigactionT 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.
+	g->m->libcall.fn = (uintptr)(void*)libc·malloc;
+	g->m->libcall.n = 1;
+	runtime·memclr((byte*)&g->m->scratch, sizeof(g->m->scratch));
+	g->m->scratch.v[0] = (uintptr)sizeof(*sem);
+	g->m->libcall.args = (uintptr)(uintptr*)&g->m->scratch;
+	runtime·asmcgocall(runtime·asmsysvicall6, &g->m->libcall);
+	sem = (void*)g->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)
+{
+	M *m;
+
+	m = g->m;
+	if(ns >= 0) {
+		m->ts.tv_sec = ns / 1000000000LL;
+		m->ts.tv_nsec = ns % 1000000000LL;
+
+		m->libcall.fn = (uintptr)(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)(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 = (uintptr)(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)(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");
+}
+
+#pragma textflag NOSPLIT
+int32
+runtime·close(int32 fd)
+{
+	return runtime·sysvicall1(libc·close, (uintptr)fd);
+}
+
+#pragma textflag NOSPLIT
+void
+runtime·exit(int32 r)
+{
+	runtime·sysvicall1(libc·exit, (uintptr)r);
+}
+
+#pragma textflag NOSPLIT
+/* int32 */ void
+runtime·getcontext(Ucontext* context)
+{
+	runtime·sysvicall1(libc·getcontext, (uintptr)context);
+}
+
+#pragma textflag NOSPLIT
+int32
+runtime·getrlimit(int32 res, Rlimit* rlp)
+{
+	return runtime·sysvicall2(libc·getrlimit, (uintptr)res, (uintptr)rlp);
+}
+
+#pragma textflag NOSPLIT
+uint8*
+runtime·mmap(byte* addr, uintptr len, int32 prot, int32 flags, int32 fildes, uint32 off)
+{
+	return (uint8*)runtime·sysvicall6(libc·mmap, (uintptr)addr, (uintptr)len, (uintptr)prot, (uintptr)flags, (uintptr)fildes, (uintptr)off);
+}
+
+#pragma textflag NOSPLIT
+void
+runtime·munmap(byte* addr, uintptr len)
+{
+	runtime·sysvicall2(libc·munmap, (uintptr)addr, (uintptr)len);
+}
+
+extern int64 runtime·nanotime1(void);
+#pragma textflag NOSPLIT
+int64
+runtime·nanotime(void)
+{
+	return runtime·sysvicall0((uintptr)runtime·nanotime1);
+}
+
+#pragma textflag NOSPLIT
+int32
+runtime·open(int8* path, int32 oflag, int32 mode)
+{
+	return runtime·sysvicall3(libc·open, (uintptr)path, (uintptr)oflag, (uintptr)mode);
+}
+
+int32
+runtime·pthread_attr_destroy(PthreadAttr* attr)
+{
+	return runtime·sysvicall1(libc·pthread_attr_destroy, (uintptr)attr);
+}
+
+int32
+runtime·pthread_attr_getstack(PthreadAttr* attr, void** addr, uint64* size)
+{
+	return runtime·sysvicall3(libc·pthread_attr_getstack, (uintptr)attr, (uintptr)addr, (uintptr)size);
+}
+
+int32
+runtime·pthread_attr_init(PthreadAttr* attr)
+{
+	return runtime·sysvicall1(libc·pthread_attr_init, (uintptr)attr);
+}
+
+int32
+runtime·pthread_attr_setdetachstate(PthreadAttr* attr, int32 state)
+{
+	return runtime·sysvicall2(libc·pthread_attr_setdetachstate, (uintptr)attr, (uintptr)state);
+}
+
+int32
+runtime·pthread_attr_setstack(PthreadAttr* attr, void* addr, uint64 size)
+{
+	return runtime·sysvicall3(libc·pthread_attr_setstack, (uintptr)attr, (uintptr)addr, (uintptr)size);
+}
+
+int32
+runtime·pthread_create(Pthread* thread, PthreadAttr* attr, void(*fn)(void), void *arg)
+{
+	return runtime·sysvicall4(libc·pthread_create, (uintptr)thread, (uintptr)attr, (uintptr)fn, (uintptr)arg);
+}
+
+/* int32 */ void
+runtime·raise(int32 sig)
+{
+	runtime·sysvicall1(libc·raise, (uintptr)sig);
+}
+
+#pragma textflag NOSPLIT
+int32
+runtime·read(int32 fd, void* buf, int32 nbyte)
+{
+	return runtime·sysvicall3(libc·read, (uintptr)fd, (uintptr)buf, (uintptr)nbyte);
+}
+
+#pragma textflag NOSPLIT
+int32
+runtime·sem_init(SemT* sem, int32 pshared, uint32 value)
+{
+	return runtime·sysvicall3(libc·sem_init, (uintptr)sem, (uintptr)pshared, (uintptr)value);
+}
+
+#pragma textflag NOSPLIT
+int32
+runtime·sem_post(SemT* sem)
+{
+	return runtime·sysvicall1(libc·sem_post, (uintptr)sem);
+}
+
+#pragma textflag NOSPLIT
+int32
+runtime·sem_reltimedwait_np(SemT* sem, Timespec* timeout)
+{
+	return runtime·sysvicall2(libc·sem_reltimedwait_np, (uintptr)sem, (uintptr)timeout);
+}
+
+#pragma textflag NOSPLIT
+int32
+runtime·sem_wait(SemT* sem)
+{
+	return runtime·sysvicall1(libc·sem_wait, (uintptr)sem);
+}
+
+/* int32 */ void
+runtime·setitimer(int32 which, Itimerval* value, Itimerval* ovalue)
+{
+	runtime·sysvicall3(libc·setitimer, (uintptr)which, (uintptr)value, (uintptr)ovalue);
+}
+
+/* int32 */ void
+runtime·sigaction(int32 sig, struct SigactionT* act, struct SigactionT* oact)
+{
+	runtime·sysvicall3(libc·sigaction, (uintptr)sig, (uintptr)act, (uintptr)oact);
+}
+
+/* int32 */ void
+runtime·sigaltstack(SigaltstackT* ss, SigaltstackT* oss)
+{
+	runtime·sysvicall2(libc·sigaltstack, (uintptr)ss, (uintptr)oss);
+}
+
+/* int32 */ void
+runtime·sigprocmask(int32 how, Sigset* set, Sigset* oset)
+{
+	runtime·sysvicall3(libc·sigprocmask, (uintptr)how, (uintptr)set, (uintptr)oset);
+}
+
+int64
+runtime·sysconf(int32 name)
+{
+	return runtime·sysvicall1(libc·sysconf, (uintptr)name);
+}
+
+extern void runtime·usleep1(uint32);
+
+#pragma textflag NOSPLIT
+void
+runtime·usleep(uint32 µs)
+{
+	runtime·usleep1(µs);
+}
+
+#pragma textflag NOSPLIT
+int32
+runtime·write(uintptr fd, void* buf, int32 nbyte)
+{
+	return runtime·sysvicall3(libc·write, (uintptr)fd, (uintptr)buf, (uintptr)nbyte);
+}
+
+extern void runtime·osyield1(void);
+
+#pragma textflag NOSPLIT
+void
+runtime·osyield(void)
+{
+	// Check the validity of m because we might be called in cgo callback
+	// path early enough where there isn't a m available yet.
+	if(g && g->m != nil) {
+		runtime·sysvicall0(libc·sched_yield);
+		return;
+	}
+	runtime·osyield1();
+}
+
+#pragma textflag NOSPLIT
+int8*
+runtime·signame(int32 sig)
+{
+	return runtime·sigtab[sig].name;
+}
diff --git a/src/runtime/os_solaris.go b/src/runtime/os_solaris.go
index fd20a5c..ca13151 100644
--- a/src/runtime/os_solaris.go
+++ b/src/runtime/os_solaris.go
@@ -6,19 +6,35 @@ package runtime
 
 import "unsafe"
 
-type libcFunc uintptr
+func setitimer(mode int32, new, old unsafe.Pointer)
+func sigaction(sig int32, new, old unsafe.Pointer)
+func sigaltstack(new, old unsafe.Pointer)
+func sigprocmask(mode int32, new, old unsafe.Pointer)
+func sysctl(mib *uint32, miblen uint32, out *byte, size *uintptr, dst *byte, ndst uintptr) int32
+func getrlimit(kind int32, limit unsafe.Pointer)
+func miniterrno(fn unsafe.Pointer)
+func raise(sig int32)
+func getcontext(ctxt unsafe.Pointer)
+func tstart_sysvicall(mm unsafe.Pointer) uint32
+func nanotime1() int64
+func usleep1(usec uint32)
+func osyield1()
+func netpollinit()
+func netpollopen(fd uintptr, pd *pollDesc) int32
+func netpollclose(fd uintptr) int32
+func netpollarm(pd *pollDesc, mode int)
 
-var asmsysvicall6 libcFunc
+type libcFunc byte
 
-//go:noescape
-func sigfwd(fn uintptr, sig uint32, info *siginfo, ctx unsafe.Pointer)
+var asmsysvicall6 libcFunc
 
 //go:nosplit
 func sysvicall0(fn *libcFunc) uintptr {
 	libcall := &getg().m.libcall
 	libcall.fn = uintptr(unsafe.Pointer(fn))
 	libcall.n = 0
-	libcall.args = uintptr(unsafe.Pointer(fn)) // it's unused but must be non-nil, otherwise crashes
+	// TODO(rsc): Why is noescape necessary here and below?
+	libcall.args = uintptr(noescape(unsafe.Pointer(&fn))) // it's unused but must be non-nil, otherwise crashes
 	asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(libcall))
 	return libcall.r1
 }
@@ -28,7 +44,6 @@ func sysvicall1(fn *libcFunc, a1 uintptr) uintptr {
 	libcall := &getg().m.libcall
 	libcall.fn = uintptr(unsafe.Pointer(fn))
 	libcall.n = 1
-	// TODO(rsc): Why is noescape necessary here and below?
 	libcall.args = uintptr(noescape(unsafe.Pointer(&a1)))
 	asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(libcall))
 	return libcall.r1
diff --git a/src/runtime/os_solaris.h b/src/runtime/os_solaris.h
new file mode 100644
index 0000000..3d9e1a2
--- /dev/null
+++ b/src/runtime/os_solaris.h
@@ -0,0 +1,55 @@
+// 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 uintptr kevent_udata;
+
+struct sigaction;
+
+void	runtime·sigpanic(void);
+
+void	runtime·setitimer(int32, Itimerval*, Itimerval*);
+void	runtime·sigaction(int32, struct SigactionT*, struct SigactionT*);
+void	runtime·sigaltstack(SigaltstackT*, SigaltstackT*);
+void	runtime·sigprocmask(int32, Sigset*, Sigset*);
+void	runtime·unblocksignals(void);
+int32	runtime·sysctl(uint32*, uint32, byte*, uintptr*, byte*, uintptr);
+
+
+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);
+
+enum {
+	SS_DISABLE = 2,
+	SIG_BLOCK = 1,
+	SIG_UNBLOCK = 2,
+	SIG_SETMASK = 3,
+	NSIG = 73, /* number of signals in runtime·SigTab array */
+	SI_USER = 0,
+	_UC_SIGMASK = 0x01,
+	_UC_CPU = 0x04,
+	RLIMIT_AS = 10,
+};
+
+typedef struct Rlimit Rlimit;
+struct Rlimit {
+	int64   rlim_cur;
+	int64   rlim_max;
+};
+int32   runtime·getrlimit(int32, Rlimit*);
+
+// Call an external library function described by {fn, a0, ..., an}, with
+// SysV conventions, switching to os stack during the call, if necessary.
+uintptr	runtime·sysvicall0(uintptr fn);
+uintptr	runtime·sysvicall1(uintptr fn, uintptr a1);
+uintptr	runtime·sysvicall2(uintptr fn, uintptr a1, uintptr a2);
+uintptr	runtime·sysvicall3(uintptr fn, uintptr a1, uintptr a2, uintptr a3);
+uintptr	runtime·sysvicall4(uintptr fn, uintptr a1, uintptr a2, uintptr a3, uintptr a4);
+uintptr	runtime·sysvicall5(uintptr fn, uintptr a1, uintptr a2, uintptr a3, uintptr a4, uintptr a5);
+uintptr	runtime·sysvicall6(uintptr fn, uintptr a1, uintptr a2, uintptr a3, uintptr a4, uintptr a5, uintptr a6);
+void	runtime·asmsysvicall6(void *c);
+
+void	runtime·miniterrno(void *fn);
diff --git a/src/runtime/os_windows.c b/src/runtime/os_windows.c
new file mode 100644
index 0000000..b8b8eda
--- /dev/null
+++ b/src/runtime/os_windows.c
@@ -0,0 +1,636 @@
+// 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 "defs_GOOS_GOARCH.h"
+#include "os_GOOS.h"
+#include "textflag.h"
+#include "arch_GOARCH.h"
+#include "malloc.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"
+#pragma dynimport runtime·CreateWaitableTimer CreateWaitableTimerA "kernel32.dll"
+#pragma dynimport runtime·CryptAcquireContextW CryptAcquireContextW "advapi32.dll"
+#pragma dynimport runtime·CryptGenRandom CryptGenRandom "advapi32.dll"
+#pragma dynimport runtime·CryptReleaseContext CryptReleaseContext "advapi32.dll"
+#pragma dynimport runtime·DuplicateHandle DuplicateHandle "kernel32.dll"
+#pragma dynimport runtime·ExitProcess ExitProcess "kernel32.dll"
+#pragma dynimport runtime·FreeEnvironmentStringsW FreeEnvironmentStringsW "kernel32.dll"
+#pragma dynimport runtime·GetEnvironmentStringsW GetEnvironmentStringsW "kernel32.dll"
+#pragma dynimport runtime·GetProcAddress GetProcAddress "kernel32.dll"
+#pragma dynimport runtime·GetStdHandle GetStdHandle "kernel32.dll"
+#pragma dynimport runtime·GetSystemInfo GetSystemInfo "kernel32.dll"
+#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·SetUnhandledExceptionFilter SetUnhandledExceptionFilter "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·WaitForSingleObject WaitForSingleObject "kernel32.dll"
+#pragma dynimport runtime·WriteFile WriteFile "kernel32.dll"
+#pragma dynimport runtime·timeBeginPeriod timeBeginPeriod "winmm.dll"
+
+extern void *runtime·AddVectoredExceptionHandler;
+extern void *runtime·CloseHandle;
+extern void *runtime·CreateEvent;
+extern void *runtime·CreateThread;
+extern void *runtime·CreateWaitableTimer;
+extern void *runtime·CryptAcquireContextW;
+extern void *runtime·CryptGenRandom;
+extern void *runtime·CryptReleaseContext;
+extern void *runtime·DuplicateHandle;
+extern void *runtime·ExitProcess;
+extern void *runtime·FreeEnvironmentStringsW;
+extern void *runtime·GetEnvironmentStringsW;
+extern void *runtime·GetProcAddress;
+extern void *runtime·GetStdHandle;
+extern void *runtime·GetSystemInfo;
+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·SetUnhandledExceptionFilter;
+extern void *runtime·SetWaitableTimer;
+extern void *runtime·Sleep;
+extern void *runtime·SuspendThread;
+extern void *runtime·WaitForSingleObject;
+extern void *runtime·WriteFile;
+extern void *runtime·timeBeginPeriod;
+
+#pragma dataflag NOPTR
+void *runtime·GetQueuedCompletionStatusEx;
+
+extern uintptr runtime·externalthreadhandlerp;
+void runtime·externalthreadhandler(void);
+void runtime·exceptiontramp(void);
+void runtime·firstcontinuetramp(void);
+void runtime·lastcontinuetramp(void);
+
+#pragma textflag NOSPLIT
+uintptr
+runtime·getLoadLibrary(void)
+{
+	return (uintptr)runtime·LoadLibrary;
+}
+
+#pragma textflag NOSPLIT
+uintptr
+runtime·getGetProcAddress(void)
+{
+	return (uintptr)runtime·GetProcAddress;
+}
+
+static int32
+getproccount(void)
+{
+	SystemInfo info;
+
+	runtime·stdcall1(runtime·GetSystemInfo, (uintptr)&info);
+	return info.dwNumberOfProcessors;
+}
+
+void
+runtime·osinit(void)
+{
+	void *kernel32;
+	void *addVectoredContinueHandler;
+
+	kernel32 = runtime·stdcall1(runtime·LoadLibraryA, (uintptr)"kernel32.dll");
+
+	runtime·externalthreadhandlerp = (uintptr)runtime·externalthreadhandler;
+
+	runtime·stdcall2(runtime·AddVectoredExceptionHandler, 1, (uintptr)runtime·exceptiontramp);
+	addVectoredContinueHandler = nil;
+	if(kernel32 != nil)
+		addVectoredContinueHandler = runtime·stdcall2(runtime·GetProcAddress, (uintptr)kernel32, (uintptr)"AddVectoredContinueHandler");
+	if(addVectoredContinueHandler == nil || sizeof(void*) == 4) {
+		// use SetUnhandledExceptionFilter for windows-386 or
+		// if VectoredContinueHandler is unavailable.
+		// note: SetUnhandledExceptionFilter handler won't be called, if debugging.
+		runtime·stdcall1(runtime·SetUnhandledExceptionFilter, (uintptr)runtime·lastcontinuetramp);
+	} else {
+		runtime·stdcall2(addVectoredContinueHandler, 1, (uintptr)runtime·firstcontinuetramp);
+		runtime·stdcall2(addVectoredContinueHandler, 0, (uintptr)runtime·lastcontinuetramp);
+	}
+
+	runtime·stdcall2(runtime·SetConsoleCtrlHandler, (uintptr)runtime·ctrlhandler, 1);
+
+	runtime·stdcall1(runtime·timeBeginPeriod, 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·stdcall2(runtime·SetProcessPriorityBoost, -1, 1);
+
+	if(kernel32 != nil) {
+		runtime·GetQueuedCompletionStatusEx = runtime·stdcall2(runtime·GetProcAddress, (uintptr)kernel32, (uintptr)"GetQueuedCompletionStatusEx");
+	}
+}
+
+#pragma textflag NOSPLIT
+void
+runtime·get_random_data(byte **rnd, int32 *rnd_len)
+{
+	uintptr handle;
+	*rnd = nil;
+	*rnd_len = 0;
+	if(runtime·stdcall5(runtime·CryptAcquireContextW, (uintptr)&handle, (uintptr)nil, (uintptr)nil,
+			   1 /* PROV_RSA_FULL */,
+			   0xf0000000U /* CRYPT_VERIFYCONTEXT */) != 0) {
+		static byte random_data[HashRandomBytes];
+		if(runtime·stdcall3(runtime·CryptGenRandom, handle, HashRandomBytes, (uintptr)&random_data[0])) {
+			*rnd = random_data;
+			*rnd_len = HashRandomBytes;
+		}
+		runtime·stdcall2(runtime·CryptReleaseContext, handle, 0);
+	}
+}
+
+void
+runtime·goenvs(void)
+{
+	extern Slice runtime·envs;
+
+	uint16 *env;
+	String *s;
+	int32 i, n;
+	uint16 *p;
+
+	env = runtime·stdcall0(runtime·GetEnvironmentStringsW);
+
+	n = 0;
+	for(p=env; *p; n++)
+		p += runtime·findnullw(p)+1;
+
+	runtime·envs = runtime·makeStringSlice(n);
+	s = (String*)runtime·envs.array;
+
+	p = env;
+	for(i=0; i<n; i++) {
+		s[i] = runtime·gostringw(p);
+		p += runtime·findnullw(p)+1;
+	}
+
+	runtime·stdcall1(runtime·FreeEnvironmentStringsW, (uintptr)env);
+}
+
+#pragma textflag NOSPLIT
+void
+runtime·exit(int32 code)
+{
+	runtime·stdcall1(runtime·ExitProcess, code);
+}
+
+#pragma textflag NOSPLIT
+int32
+runtime·write(uintptr fd, void *buf, int32 n)
+{
+	void *handle;
+	uint32 written;
+
+	written = 0;
+	switch(fd) {
+	case 1:
+		handle = runtime·stdcall1(runtime·GetStdHandle, -11);
+		break;
+	case 2:
+		handle = runtime·stdcall1(runtime·GetStdHandle, -12);
+		break;
+	default:
+		// assume fd is real windows handle.
+		handle = (void*)fd;
+		break;
+	}
+	runtime·stdcall5(runtime·WriteFile, (uintptr)handle, (uintptr)buf, n, (uintptr)&written, 0);
+	return written;
+}
+
+#define INFINITE ((uintptr)0xFFFFFFFF)
+
+#pragma textflag NOSPLIT
+int32
+runtime·semasleep(int64 ns)
+{
+	// store ms in ns to save stack space
+	if(ns < 0)
+		ns = INFINITE;
+	else {
+		ns = runtime·timediv(ns, 1000000, nil);
+		if(ns == 0)
+			ns = 1;
+	}
+	if(runtime·stdcall2(runtime·WaitForSingleObject, (uintptr)g->m->waitsema, ns) != 0)
+		return -1;  // timeout
+	return 0;
+}
+
+#pragma textflag NOSPLIT
+void
+runtime·semawakeup(M *mp)
+{
+	runtime·stdcall1(runtime·SetEvent, mp->waitsema);
+}
+
+#pragma textflag NOSPLIT
+uintptr
+runtime·semacreate(void)
+{
+	return (uintptr)runtime·stdcall4(runtime·CreateEvent, 0, 0, 0, 0);
+}
+
+#define STACK_SIZE_PARAM_IS_A_RESERVATION ((uintptr)0x00010000)
+
+void
+runtime·newosproc(M *mp, void *stk)
+{
+	void *thandle;
+
+	USED(stk);
+
+	thandle = runtime·stdcall6(runtime·CreateThread,
+		(uintptr)nil, 0x20000, (uintptr)runtime·tstart_stdcall, (uintptr)mp,
+		STACK_SIZE_PARAM_IS_A_RESERVATION, (uintptr)nil);
+	if(thandle == nil) {
+		runtime·printf("runtime: failed to create new OS thread (have %d already; errno=%d)\n", runtime·mcount(), runtime·getlasterror());
+		runtime·throw("runtime.newosproc");
+	}
+}
+
+// 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)
+{
+	USED(mp);
+}
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the new thread, can not allocate memory.
+void
+runtime·minit(void)
+{
+	uintptr thandle;
+
+	// -1 = current process, -2 = current thread
+	runtime·stdcall7(runtime·DuplicateHandle, -1, -2, -1, (uintptr)&thandle, 0, 0, DUPLICATE_SAME_ACCESS);
+	runtime·atomicstoreuintptr(&g->m->thread, thandle);
+}
+
+// Called from dropm to undo the effect of an minit.
+void
+runtime·unminit(void)
+{
+	runtime·stdcall1(runtime·CloseHandle, g->m->thread);
+	g->m->thread = 0;
+}
+
+// Described in http://www.dcl.hpi.uni-potsdam.de/research/WRK/2007/08/getting-os-information-the-kuser_shared_data-structure/
+typedef struct KSYSTEM_TIME {
+	uint32	LowPart;
+	int32	High1Time;
+	int32	High2Time;
+} KSYSTEM_TIME;
+
+#pragma dataflag NOPTR
+const KSYSTEM_TIME* INTERRUPT_TIME	= (KSYSTEM_TIME*)0x7ffe0008;
+#pragma dataflag NOPTR
+const KSYSTEM_TIME* SYSTEM_TIME		= (KSYSTEM_TIME*)0x7ffe0014;
+
+static void badsystime(void);
+
+#pragma textflag NOSPLIT
+int64
+runtime·systime(KSYSTEM_TIME *timeaddr)
+{
+	KSYSTEM_TIME t;
+	int32 i;
+	void (*fn)(void);
+
+	for(i = 1; i < 10000; i++) {
+		// these fields must be read in that order (see URL above)
+		t.High1Time = timeaddr->High1Time;
+		t.LowPart = timeaddr->LowPart;
+		t.High2Time = timeaddr->High2Time;
+		if(t.High1Time == t.High2Time)
+			return (int64)t.High1Time<<32 | t.LowPart;
+		if((i%100) == 0)
+			runtime·osyield();
+	}
+	fn = badsystime;
+	runtime·onM(&fn);
+	return 0;
+}
+
+#pragma textflag NOSPLIT
+int64
+runtime·unixnano(void)
+{
+	return (runtime·systime(SYSTEM_TIME) - 116444736000000000LL) * 100LL;
+}
+
+static void
+badsystime(void)
+{
+	runtime·throw("interrupt/system time is changing too fast");
+}
+
+#pragma textflag NOSPLIT
+int64
+runtime·nanotime(void)
+{
+	return runtime·systime(INTERRUPT_TIME) * 100LL;
+}
+
+// Calling stdcall on os stack.
+#pragma textflag NOSPLIT
+static void*
+stdcall(void *fn)
+{
+	g->m->libcall.fn = (uintptr)fn;
+	if(g->m->profilehz != 0) {
+		// leave pc/sp for cpu profiler
+		g->m->libcallg = g;
+		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
+		g->m->libcallsp = (uintptr)runtime·getcallersp(&fn);
+	}
+	runtime·asmcgocall(runtime·asmstdcall, &g->m->libcall);
+	g->m->libcallsp = 0;
+	return (void*)g->m->libcall.r1;
+}
+
+#pragma textflag NOSPLIT
+void*
+runtime·stdcall0(void *fn)
+{
+	g->m->libcall.n = 0;
+	g->m->libcall.args = (uintptr)&fn;  // it's unused but must be non-nil, otherwise crashes
+	return stdcall(fn);
+}
+
+#pragma textflag NOSPLIT
+void*
+runtime·stdcall1(void *fn, uintptr a0)
+{
+	USED(a0);
+	g->m->libcall.n = 1;
+	g->m->libcall.args = (uintptr)&a0;
+	return stdcall(fn);
+}
+
+#pragma textflag NOSPLIT
+void*
+runtime·stdcall2(void *fn, uintptr a0, uintptr a1)
+{
+	USED(a0, a1);
+	g->m->libcall.n = 2;
+	g->m->libcall.args = (uintptr)&a0;
+	return stdcall(fn);
+}
+
+#pragma textflag NOSPLIT
+void*
+runtime·stdcall3(void *fn, uintptr a0, uintptr a1, uintptr a2)
+{
+	USED(a0, a1, a2);
+	g->m->libcall.n = 3;
+	g->m->libcall.args = (uintptr)&a0;
+	return stdcall(fn);
+}
+
+#pragma textflag NOSPLIT
+void*
+runtime·stdcall4(void *fn, uintptr a0, uintptr a1, uintptr a2, uintptr a3)
+{
+	USED(a0, a1, a2, a3);
+	g->m->libcall.n = 4;
+	g->m->libcall.args = (uintptr)&a0;
+	return stdcall(fn);
+}
+
+#pragma textflag NOSPLIT
+void*
+runtime·stdcall5(void *fn, uintptr a0, uintptr a1, uintptr a2, uintptr a3, uintptr a4)
+{
+	USED(a0, a1, a2, a3, a4);
+	g->m->libcall.n = 5;
+	g->m->libcall.args = (uintptr)&a0;
+	return stdcall(fn);
+}
+
+#pragma textflag NOSPLIT
+void*
+runtime·stdcall6(void *fn, uintptr a0, uintptr a1, uintptr a2, uintptr a3, uintptr a4, uintptr a5)
+{
+	USED(a0, a1, a2, a3, a4, a5);
+	g->m->libcall.n = 6;
+	g->m->libcall.args = (uintptr)&a0;
+	return stdcall(fn);
+}
+
+#pragma textflag NOSPLIT
+void*
+runtime·stdcall7(void *fn, uintptr a0, uintptr a1, uintptr a2, uintptr a3, uintptr a4, uintptr a5, uintptr a6)
+{
+	USED(a0, a1, a2, a3, a4, a5, a6);
+	g->m->libcall.n = 7;
+	g->m->libcall.args = (uintptr)&a0;
+	return stdcall(fn);
+}
+
+extern void runtime·usleep1(uint32);
+
+#pragma textflag NOSPLIT
+void
+runtime·osyield(void)
+{
+	runtime·usleep1(1);
+}
+
+#pragma textflag NOSPLIT
+void
+runtime·usleep(uint32 us)
+{
+	// Have 1us units; want 100ns units.
+	runtime·usleep1(10*us);
+}
+
+uint32
+runtime·issigpanic(uint32 code)
+{
+	switch(code) {
+	case EXCEPTION_ACCESS_VIOLATION:
+	case EXCEPTION_INT_DIVIDE_BY_ZERO:
+	case EXCEPTION_INT_OVERFLOW:
+	case EXCEPTION_FLT_DENORMAL_OPERAND:
+	case EXCEPTION_FLT_DIVIDE_BY_ZERO:
+	case EXCEPTION_FLT_INEXACT_RESULT:
+	case EXCEPTION_FLT_OVERFLOW:
+	case EXCEPTION_FLT_UNDERFLOW:
+	case EXCEPTION_BREAKPOINT:
+		return 1;
+	}
+	return 0;
+}
+
+void
+runtime·initsig(void)
+{
+	// following line keeps these functions alive at link stage
+	// if there's a better way please write it here
+	void *e = runtime·exceptiontramp;
+	void *f = runtime·firstcontinuetramp;
+	void *l = runtime·lastcontinuetramp;
+	USED(e);
+	USED(f);
+	USED(l);
+}
+
+uint32
+runtime·ctrlhandler1(uint32 type)
+{
+	int32 s;
+
+	switch(type) {
+	case CTRL_C_EVENT:
+	case CTRL_BREAK_EVENT:
+		s = SIGINT;
+		break;
+	default:
+		return 0;
+	}
+
+	if(runtime·sigsend(s))
+		return 1;
+	runtime·exit(2);	// SIGINT, SIGTERM, etc
+	return 0;
+}
+
+extern void runtime·dosigprof(Context *r, G *gp, M *mp);
+extern void runtime·profileloop(void);
+#pragma dataflag NOPTR
+static void *profiletimer;
+
+static void
+profilem(M *mp)
+{
+	extern M runtime·m0;
+	extern uint32 runtime·tls0[];
+	byte rbuf[sizeof(Context)+15];
+	Context *r;
+	void *tls;
+	G *gp;
+
+	tls = mp->tls;
+	if(mp == &runtime·m0)
+		tls = runtime·tls0;
+	gp = *(G**)tls;
+
+	// align Context to 16 bytes
+	r = (Context*)((uintptr)(&rbuf[15]) & ~15);
+	r->ContextFlags = CONTEXT_CONTROL;
+	runtime·stdcall2(runtime·GetThreadContext, (uintptr)mp->thread, (uintptr)r);
+	runtime·dosigprof(r, gp, mp);
+}
+
+void
+runtime·profileloop1(void)
+{
+	M *mp, *allm;
+	uintptr thread;
+
+	runtime·stdcall2(runtime·SetThreadPriority, -2, THREAD_PRIORITY_HIGHEST);
+
+	for(;;) {
+		runtime·stdcall2(runtime·WaitForSingleObject, (uintptr)profiletimer, -1);
+		allm = runtime·atomicloadp(&runtime·allm);
+		for(mp = allm; mp != nil; mp = mp->alllink) {
+			thread = runtime·atomicloaduintptr(&mp->thread);
+			// Do not profile threads blocked on Notes,
+			// this includes idle worker threads,
+			// idle timer thread, idle heap scavenger, etc.
+			if(thread == 0 || mp->profilehz == 0 || mp->blocked)
+				continue;
+			runtime·stdcall1(runtime·SuspendThread, (uintptr)thread);
+			if(mp->profilehz != 0 && !mp->blocked)
+				profilem(mp);
+			runtime·stdcall1(runtime·ResumeThread, (uintptr)thread);
+		}
+	}
+}
+
+void
+runtime·resetcpuprofiler(int32 hz)
+{
+	static Mutex lock;
+	void *timer, *thread;
+	int32 ms;
+	int64 due;
+
+	runtime·lock(&lock);
+	if(profiletimer == nil) {
+		timer = runtime·stdcall3(runtime·CreateWaitableTimer, (uintptr)nil, (uintptr)nil, (uintptr)nil);
+		runtime·atomicstorep(&profiletimer, timer);
+		thread = runtime·stdcall6(runtime·CreateThread,
+			(uintptr)nil, (uintptr)nil, (uintptr)runtime·profileloop, (uintptr)nil, (uintptr)nil, (uintptr)nil);
+		runtime·stdcall2(runtime·SetThreadPriority, (uintptr)thread, THREAD_PRIORITY_HIGHEST);
+		runtime·stdcall1(runtime·CloseHandle, (uintptr)thread);
+	}
+	runtime·unlock(&lock);
+
+	ms = 0;
+	due = 1LL<<63;
+	if(hz > 0) {
+		ms = 1000 / hz;
+		if(ms == 0)
+			ms = 1;
+		due = ms * -10000;
+	}
+	runtime·stdcall6(runtime·SetWaitableTimer,
+		(uintptr)profiletimer, (uintptr)&due, ms, (uintptr)nil, (uintptr)nil, (uintptr)nil);
+	runtime·atomicstore((uint32*)&g->m->profilehz, hz);
+}
+
+uintptr
+runtime·memlimit(void)
+{
+	return 0;
+}
+
+#pragma dataflag NOPTR
+int8 runtime·badsignalmsg[] = "runtime: signal received on thread not created by Go.\n";
+int32 runtime·badsignallen = sizeof runtime·badsignalmsg - 1;
+
+void
+runtime·crash(void)
+{
+	// TODO: This routine should do whatever is needed
+	// to make the Windows program abort/crash as it
+	// would if Go was not intercepting signals.
+	// On Unix the routine would remove the custom signal
+	// handler and then raise a signal (like SIGABRT).
+	// Something like that should happen here.
+	// It's okay to leave this empty for now: if crash returns
+	// the ordinary exit-after-panic happens.
+}
diff --git a/src/runtime/os_windows.go b/src/runtime/os_windows.go
index 545b416..1528d2f 100644
--- a/src/runtime/os_windows.go
+++ b/src/runtime/os_windows.go
@@ -8,21 +8,51 @@ import "unsafe"
 
 type stdFunction *byte
 
-//go:linkname os_sigpipe os.sigpipe
+func stdcall0(fn stdFunction) uintptr
+func stdcall1(fn stdFunction, a0 uintptr) uintptr
+func stdcall2(fn stdFunction, a0, a1 uintptr) uintptr
+func stdcall3(fn stdFunction, a0, a1, a2 uintptr) uintptr
+func stdcall4(fn stdFunction, a0, a1, a2, a3 uintptr) uintptr
+func stdcall5(fn stdFunction, a0, a1, a2, a3, a4 uintptr) uintptr
+func stdcall6(fn stdFunction, a0, a1, a2, a3, a4, a5 uintptr) uintptr
+func stdcall7(fn stdFunction, a0, a1, a2, a3, a4, a5, a6 uintptr) uintptr
+
+func asmstdcall(fn unsafe.Pointer)
+func getlasterror() uint32
+func setlasterror(err uint32)
+func usleep1(usec uint32)
+func netpollinit()
+func netpollopen(fd uintptr, pd *pollDesc) int32
+func netpollclose(fd uintptr) int32
+func netpollarm(pd *pollDesc, mode int)
+
 func os_sigpipe() {
-	throw("too many writes on closed pipe")
+	gothrow("too many writes on closed pipe")
 }
 
-// Stubs so tests can link correctly.  These should never be called.
-func open(name *byte, mode, perm int32) int32 {
-	throw("unimplemented")
-	return -1
-}
-func closefd(fd int32) int32 {
-	throw("unimplemented")
-	return -1
-}
-func read(fd int32, p unsafe.Pointer, n int32) int32 {
-	throw("unimplemented")
-	return -1
+func sigpanic() {
+	g := getg()
+	if !canpanic(g) {
+		gothrow("unexpected signal during runtime execution")
+	}
+
+	switch uint32(g.sig) {
+	case _EXCEPTION_ACCESS_VIOLATION:
+		if g.sigcode1 < 0x1000 || g.paniconfault {
+			panicmem()
+		}
+		print("unexpected fault address ", hex(g.sigcode1), "\n")
+		gothrow("fault")
+	case _EXCEPTION_INT_DIVIDE_BY_ZERO:
+		panicdivide()
+	case _EXCEPTION_INT_OVERFLOW:
+		panicoverflow()
+	case _EXCEPTION_FLT_DENORMAL_OPERAND,
+		_EXCEPTION_FLT_DIVIDE_BY_ZERO,
+		_EXCEPTION_FLT_INEXACT_RESULT,
+		_EXCEPTION_FLT_OVERFLOW,
+		_EXCEPTION_FLT_UNDERFLOW:
+		panicfloat()
+	}
+	gothrow("fault")
 }
diff --git a/src/runtime/os_windows.h b/src/runtime/os_windows.h
new file mode 100644
index 0000000..d5d168d
--- /dev/null
+++ b/src/runtime/os_windows.h
@@ -0,0 +1,42 @@
+// 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.
+
+extern void *runtime·LoadLibrary;
+extern void *runtime·GetProcAddress;
+extern void *runtime·GetQueuedCompletionStatusEx;
+
+// Call a Windows function with stdcall conventions,
+// and switch to os stack during the call.
+void runtime·asmstdcall(void *c);
+void *runtime·stdcall0(void *fn);
+void *runtime·stdcall1(void *fn, uintptr a0);
+void *runtime·stdcall2(void *fn, uintptr a0, uintptr a1);
+void *runtime·stdcall3(void *fn, uintptr a0, uintptr a1, uintptr a2);
+void *runtime·stdcall4(void *fn, uintptr a0, uintptr a1, uintptr a2, uintptr a3);
+void *runtime·stdcall5(void *fn, uintptr a0, uintptr a1, uintptr a2, uintptr a3, uintptr a4);
+void *runtime·stdcall6(void *fn, uintptr a0, uintptr a1, uintptr a2, uintptr a3, uintptr a4, uintptr a5);
+void *runtime·stdcall7(void *fn, uintptr a0, uintptr a1, uintptr a2, uintptr a3, uintptr a4, uintptr a5, uintptr a6);
+
+uint32 runtime·getlasterror(void);
+void runtime·setlasterror(uint32 err);
+
+// Function to be called by windows CreateThread
+// to start new os thread.
+uint32 runtime·tstart_stdcall(M *newm);
+
+uint32 runtime·issigpanic(uint32);
+void runtime·sigpanic(void);
+uint32 runtime·ctrlhandler(uint32 type);
+
+// Windows dll function to go callback entry.
+byte *runtime·compilecallback(Eface fn, bool cleanstack);
+void *runtime·callbackasm(void);
+
+void runtime·install_exception_handler(void);
+void runtime·remove_exception_handler(void);
+
+// TODO(brainman): should not need those
+enum {
+	NSIG = 65,
+};
diff --git a/src/runtime/os_windows_386.c b/src/runtime/os_windows_386.c
new file mode 100644
index 0000000..9962f0d
--- /dev/null
+++ b/src/runtime/os_windows_386.c
@@ -0,0 +1,128 @@
+// 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 "defs_GOOS_GOARCH.h"
+#include "os_GOOS.h"
+
+void
+runtime·dumpregs(Context *r)
+{
+	runtime·printf("eax     %x\n", r->Eax);
+	runtime·printf("ebx     %x\n", r->Ebx);
+	runtime·printf("ecx     %x\n", r->Ecx);
+	runtime·printf("edx     %x\n", r->Edx);
+	runtime·printf("edi     %x\n", r->Edi);
+	runtime·printf("esi     %x\n", r->Esi);
+	runtime·printf("ebp     %x\n", r->Ebp);
+	runtime·printf("esp     %x\n", r->Esp);
+	runtime·printf("eip     %x\n", r->Eip);
+	runtime·printf("eflags  %x\n", r->EFlags);
+	runtime·printf("cs      %x\n", r->SegCs);
+	runtime·printf("fs      %x\n", r->SegFs);
+	runtime·printf("gs      %x\n", r->SegGs);
+}
+
+bool
+runtime·isgoexception(ExceptionRecord *info, Context *r)
+{
+	extern byte runtime·text[], runtime·etext[];
+
+	// Only handle exception if executing instructions in Go binary
+	// (not Windows library code). 
+	if(r->Eip < (uint32)runtime·text || (uint32)runtime·etext < r->Eip)
+		return false;
+
+	if(!runtime·issigpanic(info->ExceptionCode))
+		return false;
+
+	return true;
+}
+
+// Called by sigtramp from Windows VEH handler.
+// Return value signals whether the exception has been handled (EXCEPTION_CONTINUE_EXECUTION)
+// or should be made available to other handlers in the chain (EXCEPTION_CONTINUE_SEARCH).
+uint32
+runtime·exceptionhandler(ExceptionRecord *info, Context *r, G *gp)
+{
+	uintptr *sp;
+
+	if(!runtime·isgoexception(info, r))
+		return EXCEPTION_CONTINUE_SEARCH;
+
+	// 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 = info->ExceptionCode;
+	gp->sigcode0 = info->ExceptionInformation[0];
+	gp->sigcode1 = info->ExceptionInformation[1];
+	gp->sigpc = r->Eip;
+
+	// Only push runtime·sigpanic if r->eip != 0.
+	// If r->eip == 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(r->Eip != 0) {
+		sp = (uintptr*)r->Esp;
+		*--sp = r->Eip;
+		r->Esp = (uintptr)sp;
+	}
+	r->Eip = (uintptr)runtime·sigpanic;
+	return EXCEPTION_CONTINUE_EXECUTION;
+}
+
+// lastcontinuehandler is reached, because runtime cannot handle
+// current exception. lastcontinuehandler will print crash info and exit.
+uint32
+runtime·lastcontinuehandler(ExceptionRecord *info, Context *r, G *gp)
+{
+	bool crash;
+
+	if(runtime·panicking)	// traceback already printed
+		runtime·exit(2);
+	runtime·panicking = 1;
+
+	runtime·printf("Exception %x %p %p %p\n", info->ExceptionCode,
+		(uintptr)info->ExceptionInformation[0], (uintptr)info->ExceptionInformation[1], (uintptr)r->Eip);
+
+	runtime·printf("PC=%x\n", r->Eip);
+	if(g->m->lockedg != nil && g->m->ncgo > 0 && gp == g->m->g0) {
+		runtime·printf("signal arrived during cgo execution\n");
+		gp = g->m->lockedg;
+	}
+	runtime·printf("\n");
+
+	if(runtime·gotraceback(&crash)){
+		runtime·tracebacktrap(r->Eip, r->Esp, 0, gp);
+		runtime·tracebackothers(gp);
+		runtime·dumpregs(r);
+	}
+	
+	if(crash)
+		runtime·crash();
+
+	runtime·exit(2);
+	return 0; // not reached
+}
+
+void
+runtime·sigenable(uint32 sig)
+{
+	USED(sig);
+}
+
+void
+runtime·sigdisable(uint32 sig)
+{
+	USED(sig);
+}
+
+void
+runtime·dosigprof(Context *r, G *gp, M *mp)
+{
+	runtime·sigprof((uint8*)r->Eip, (uint8*)r->Esp, nil, gp, mp);
+}
diff --git a/src/runtime/os_windows_386.go b/src/runtime/os_windows_386.go
new file mode 100644
index 0000000..86a1906
--- /dev/null
+++ b/src/runtime/os_windows_386.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 runtime
+
+// contextPC returns the EIP (program counter) register from the context.
+func contextPC(r *context) uintptr { return uintptr(r.eip) }
+
+// contextSP returns the ESP (stack pointer) register from the context.
+func contextSP(r *context) uintptr { return uintptr(r.esp) }
diff --git a/src/runtime/os_windows_amd64.c b/src/runtime/os_windows_amd64.c
new file mode 100644
index 0000000..e4617e4
--- /dev/null
+++ b/src/runtime/os_windows_amd64.c
@@ -0,0 +1,150 @@
+// 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"
+
+void
+runtime·dumpregs(Context *r)
+{
+	runtime·printf("rax     %X\n", r->Rax);
+	runtime·printf("rbx     %X\n", r->Rbx);
+	runtime·printf("rcx     %X\n", r->Rcx);
+	runtime·printf("rdx     %X\n", r->Rdx);
+	runtime·printf("rdi     %X\n", r->Rdi);
+	runtime·printf("rsi     %X\n", r->Rsi);
+	runtime·printf("rbp     %X\n", r->Rbp);
+	runtime·printf("rsp     %X\n", r->Rsp);
+	runtime·printf("r8      %X\n", r->R8 );
+	runtime·printf("r9      %X\n", r->R9 );
+	runtime·printf("r10     %X\n", r->R10);
+	runtime·printf("r11     %X\n", r->R11);
+	runtime·printf("r12     %X\n", r->R12);
+	runtime·printf("r13     %X\n", r->R13);
+	runtime·printf("r14     %X\n", r->R14);
+	runtime·printf("r15     %X\n", r->R15);
+	runtime·printf("rip     %X\n", r->Rip);
+	runtime·printf("rflags  %X\n", r->EFlags);
+	runtime·printf("cs      %X\n", (uint64)r->SegCs);
+	runtime·printf("fs      %X\n", (uint64)r->SegFs);
+	runtime·printf("gs      %X\n", (uint64)r->SegGs);
+}
+
+bool
+runtime·isgoexception(ExceptionRecord *info, Context *r)
+{
+	extern byte runtime·text[], runtime·etext[];
+
+	// Only handle exception if executing instructions in Go binary
+	// (not Windows library code). 
+	if(r->Rip < (uint64)runtime·text || (uint64)runtime·etext < r->Rip)
+		return false;
+
+	if(!runtime·issigpanic(info->ExceptionCode))
+		return false;
+
+	return true;
+}
+
+// Called by sigtramp from Windows VEH handler.
+// Return value signals whether the exception has been handled (EXCEPTION_CONTINUE_EXECUTION)
+// or should be made available to other handlers in the chain (EXCEPTION_CONTINUE_SEARCH).
+uint32
+runtime·exceptionhandler(ExceptionRecord *info, Context *r, G *gp)
+{
+	uintptr *sp;
+
+	if(!runtime·isgoexception(info, r))
+		return EXCEPTION_CONTINUE_SEARCH;
+
+	// 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 = info->ExceptionCode;
+	gp->sigcode0 = info->ExceptionInformation[0];
+	gp->sigcode1 = info->ExceptionInformation[1];
+	gp->sigpc = r->Rip;
+
+	// Only push runtime·sigpanic if r->rip != 0.
+	// If r->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(r->Rip != 0) {
+		sp = (uintptr*)r->Rsp;
+		*--sp = r->Rip;
+		r->Rsp = (uintptr)sp;
+	}
+	r->Rip = (uintptr)runtime·sigpanic;
+	return EXCEPTION_CONTINUE_EXECUTION;
+}
+
+// It seems Windows searches ContinueHandler's list even
+// if ExceptionHandler returns EXCEPTION_CONTINUE_EXECUTION.
+// firstcontinuehandler will stop that search,
+// if exceptionhandler did the same earlier.
+uint32
+runtime·firstcontinuehandler(ExceptionRecord *info, Context *r, G *gp)
+{
+	USED(gp);
+	if(!runtime·isgoexception(info, r))
+		return EXCEPTION_CONTINUE_SEARCH;
+	return EXCEPTION_CONTINUE_EXECUTION;
+}
+
+// lastcontinuehandler is reached, because runtime cannot handle
+// current exception. lastcontinuehandler will print crash info and exit.
+uint32
+runtime·lastcontinuehandler(ExceptionRecord *info, Context *r, G *gp)
+{
+	bool crash;
+
+	if(runtime·panicking)	// traceback already printed
+		runtime·exit(2);
+	runtime·panicking = 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(g->m->lockedg != nil && g->m->ncgo > 0 && gp == g->m->g0) {
+		runtime·printf("signal arrived during cgo execution\n");
+		gp = g->m->lockedg;
+	}
+	runtime·printf("\n");
+
+	if(runtime·gotraceback(&crash)){
+		runtime·tracebacktrap(r->Rip, r->Rsp, 0, gp);
+		runtime·tracebackothers(gp);
+		runtime·dumpregs(r);
+	}
+	
+	if(crash)
+		runtime·crash();
+
+	runtime·exit(2);
+	return 0; // not reached
+}
+
+void
+runtime·sigenable(uint32 sig)
+{
+	USED(sig);
+}
+
+void
+runtime·sigdisable(uint32 sig)
+{
+	USED(sig);
+}
+
+void
+runtime·dosigprof(Context *r, G *gp, M *mp)
+{
+	runtime·sigprof((uint8*)r->Rip, (uint8*)r->Rsp, nil, gp, mp);
+}
diff --git a/src/runtime/os_windows_amd64.go b/src/runtime/os_windows_amd64.go
new file mode 100644
index 0000000..3f4d4d0
--- /dev/null
+++ b/src/runtime/os_windows_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 runtime
+
+// contextPC returns the RIP (program counter) register from the context.
+func contextPC(r *context) uintptr { return uintptr(r.rip) }
+
+// contextSP returns the RSP (stack pointer) register from the context.
+func contextSP(r *context) uintptr { return uintptr(r.rsp) }
diff --git a/src/runtime/panic.c b/src/runtime/panic.c
new file mode 100644
index 0000000..24eb6db
--- /dev/null
+++ b/src/runtime/panic.c
@@ -0,0 +1,200 @@
+// 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 "runtime.h"
+#include "arch_GOARCH.h"
+#include "stack.h"
+#include "malloc.h"
+#include "textflag.h"
+
+// Code related to defer, panic and recover.
+
+// TODO: remove once code is moved to Go
+extern Defer* runtime·newdefer(int32 siz);
+extern runtime·freedefer(Defer *d);
+
+uint32 runtime·panicking;
+static Mutex paniclk;
+
+void
+runtime·deferproc_m(void)
+{
+	int32 siz;
+	FuncVal *fn;
+	uintptr argp;
+	uintptr callerpc;
+	Defer *d;
+
+	siz = g->m->scalararg[0];
+	fn = g->m->ptrarg[0];
+	argp = g->m->scalararg[1];
+	callerpc = g->m->scalararg[2];
+	g->m->ptrarg[0] = nil;
+	g->m->scalararg[1] = 0;
+
+	d = runtime·newdefer(siz);
+	if(d->panic != nil)
+		runtime·throw("deferproc: d->panic != nil after newdefer");
+	d->fn = fn;
+	d->pc = callerpc;
+	d->argp = argp;
+	runtime·memmove(d+1, (void*)argp, siz);
+}
+
+// Unwind the stack after a deferred function calls recover
+// after a panic.  Then arrange to continue running as though
+// the caller of the deferred function returned normally.
+void
+runtime·recovery_m(G *gp)
+{
+	void *argp;
+	uintptr pc;
+	
+	// Info about defer passed in G struct.
+	argp = (void*)gp->sigcode0;
+	pc = (uintptr)gp->sigcode1;
+
+	// d's arguments need to be in the stack.
+	if(argp != nil && ((uintptr)argp < gp->stack.lo || gp->stack.hi < (uintptr)argp)) {
+		runtime·printf("recover: %p not in [%p, %p]\n", argp, gp->stack.lo, gp->stack.hi);
+		runtime·throw("bad recovery");
+	}
+
+	// Make the deferproc for this d return again,
+	// this time returning 1.  The calling function will
+	// jump to the standard return epilogue.
+	// The -2*sizeof(uintptr) makes up for the
+	// two extra words that are on the stack at
+	// each call to deferproc.
+	// (The pc we're returning to does pop pop
+	// before it tests the return value.)
+	// On the arm there are 2 saved LRs mixed in too.
+	if(thechar == '5')
+		gp->sched.sp = (uintptr)argp - 4*sizeof(uintptr);
+	else
+		gp->sched.sp = (uintptr)argp - 2*sizeof(uintptr);
+	gp->sched.pc = pc;
+	gp->sched.lr = 0;
+	gp->sched.ret = 1;
+	runtime·gogo(&gp->sched);
+}
+
+void
+runtime·startpanic_m(void)
+{
+	if(runtime·mheap.cachealloc.size == 0) { // very early
+		runtime·printf("runtime: panic before malloc heap initialized\n");
+		g->m->mallocing = 1; // tell rest of panic not to try to malloc
+	} else if(g->m->mcache == nil) // can happen if called from signal handler or throw
+		g->m->mcache = runtime·allocmcache();
+	switch(g->m->dying) {
+	case 0:
+		g->m->dying = 1;
+		if(g != nil) {
+			g->writebuf.array = nil;
+			g->writebuf.len = 0;
+			g->writebuf.cap = 0;
+		}
+		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.
+		g->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.
+		g->m->dying = 3;
+		runtime·printf("stack trace unavailable\n");
+		runtime·exit(4);
+	default:
+		// Can't even print!  Just exit.
+		runtime·exit(5);
+	}
+}
+
+void
+runtime·dopanic_m(void)
+{
+	G *gp;
+	uintptr sp, pc;
+	static bool didothers;
+	bool crash;
+	int32 t;
+
+	gp = g->m->ptrarg[0];
+	g->m->ptrarg[0] = nil;
+	pc = g->m->scalararg[0];
+	sp = g->m->scalararg[1];
+	g->m->scalararg[1] = 0;
+	if(gp->sig != 0)
+		runtime·printf("[signal %x code=%p addr=%p pc=%p]\n",
+			gp->sig, gp->sigcode0, gp->sigcode1, gp->sigpc);
+
+	if((t = runtime·gotraceback(&crash)) > 0){
+		if(gp != gp->m->g0) {
+			runtime·printf("\n");
+			runtime·goroutineheader(gp);
+			runtime·traceback(pc, sp, 0, gp);
+		} else if(t >= 2 || g->m->throwing > 0) {
+			runtime·printf("\nruntime stack:\n");
+			runtime·traceback(pc, sp, 0, gp);
+		}
+		if(!didothers) {
+			didothers = true;
+			runtime·tracebackothers(gp);
+		}
+	}
+	runtime·unlock(&paniclk);
+	if(runtime·xadd(&runtime·panicking, -1) != 0) {
+		// Some other m is panicking too.
+		// Let it print what it needs to print.
+		// Wait forever without chewing up cpu.
+		// It will exit when it's done.
+		static Mutex deadlock;
+		runtime·lock(&deadlock);
+		runtime·lock(&deadlock);
+	}
+	
+	if(crash)
+		runtime·crash();
+
+	runtime·exit(2);
+}
+
+#pragma textflag NOSPLIT
+bool
+runtime·canpanic(G *gp)
+{
+	M *m;
+	uint32 status;
+
+	// Note that g is m->gsignal, different from gp.
+	// Note also that g->m can change at preemption, so m can go stale
+	// if this function ever makes a function call.
+	m = g->m;
+
+	// 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;
+	status = runtime·readgstatus(gp);
+	if((status&~Gscan) != Grunning || gp->syscallsp != 0)
+		return false;
+#ifdef GOOS_windows
+	if(m->libcallsp != 0)
+		return false;
+#endif
+	return true;
+}
diff --git a/src/runtime/panic.go b/src/runtime/panic.go
index a166281..685ff5c 100644
--- a/src/runtime/panic.go
+++ b/src/runtime/panic.go
@@ -43,41 +43,41 @@ func panicmem() {
 }
 
 func throwreturn() {
-	throw("no return at end of a typed function - compiler is broken")
+	gothrow("no return at end of a typed function - compiler is broken")
 }
 
 func throwinit() {
-	throw("recursive call during initialization - linker skew")
+	gothrow("recursive call during initialization - linker skew")
 }
 
 // Create a new deferred function fn with siz bytes of arguments.
 // The compiler turns a defer statement into a call to this.
 //go:nosplit
 func deferproc(siz int32, fn *funcval) { // arguments of fn follow fn
-	if getg().m.curg != getg() {
-		// go code on the system stack can't defer
-		throw("defer on system stack")
-	}
-
 	// the arguments of fn are in a perilous state.  The stack map
 	// for deferproc does not describe them.  So we can't let garbage
 	// collection or stack copying trigger until we've copied them out
-	// to somewhere safe.  The memmove below does that.
-	// Until the copy completes, we can only call nosplit routines.
-	sp := getcallersp(unsafe.Pointer(&siz))
-	argp := uintptr(unsafe.Pointer(&fn)) + unsafe.Sizeof(fn)
-	callerpc := getcallerpc(unsafe.Pointer(&siz))
-
-	systemstack(func() {
-		d := newdefer(siz)
-		if d._panic != nil {
-			throw("deferproc: d.panic != nil after newdefer")
-		}
-		d.fn = fn
-		d.pc = callerpc
-		d.sp = sp
-		memmove(add(unsafe.Pointer(d), unsafe.Sizeof(*d)), unsafe.Pointer(argp), uintptr(siz))
-	})
+	// to somewhere safe.  deferproc_m does that.  Until deferproc_m,
+	// we can only call nosplit routines.
+	argp := uintptr(unsafe.Pointer(&fn))
+	argp += unsafe.Sizeof(fn)
+	if GOARCH == "arm" {
+		argp += ptrSize // skip caller's saved link register
+	}
+	mp := acquirem()
+	mp.scalararg[0] = uintptr(siz)
+	mp.ptrarg[0] = unsafe.Pointer(fn)
+	mp.scalararg[1] = argp
+	mp.scalararg[2] = getcallerpc(unsafe.Pointer(&siz))
+
+	if mp.curg != getg() {
+		// go code on the m stack can't defer
+		gothrow("defer on m")
+	}
+
+	onM(deferproc_m)
+
+	releasem(mp)
 
 	// deferproc returns 0 normally.
 	// a deferred func that stops a panic
@@ -130,14 +130,14 @@ func testdefersizes() {
 		if defersc >= uintptr(len(m)) {
 			break
 		}
-		siz := roundupsize(totaldefersize(i))
+		siz := goroundupsize(totaldefersize(i))
 		if m[defersc] < 0 {
 			m[defersc] = int32(siz)
 			continue
 		}
 		if m[defersc] != int32(siz) {
 			print("bad defer size class: i=", i, " siz=", siz, " defersc=", defersc, "\n")
-			throw("bad defer size class")
+			gothrow("bad defer size class")
 		}
 	}
 }
@@ -159,32 +159,21 @@ func init() {
 
 // Allocate a Defer, usually using per-P pool.
 // Each defer must be released with freedefer.
-// Note: runs on g0 stack
+// Note: runs on M stack
 func newdefer(siz int32) *_defer {
 	var d *_defer
 	sc := deferclass(uintptr(siz))
 	mp := acquirem()
 	if sc < uintptr(len(p{}.deferpool)) {
-		pp := mp.p.ptr()
-		if len(pp.deferpool[sc]) == 0 && sched.deferpool[sc] != nil {
-			lock(&sched.deferlock)
-			for len(pp.deferpool[sc]) < cap(pp.deferpool[sc])/2 && sched.deferpool[sc] != nil {
-				d := sched.deferpool[sc]
-				sched.deferpool[sc] = d.link
-				d.link = nil
-				pp.deferpool[sc] = append(pp.deferpool[sc], d)
-			}
-			unlock(&sched.deferlock)
-		}
-		if n := len(pp.deferpool[sc]); n > 0 {
-			d = pp.deferpool[sc][n-1]
-			pp.deferpool[sc][n-1] = nil
-			pp.deferpool[sc] = pp.deferpool[sc][:n-1]
+		pp := mp.p
+		d = pp.deferpool[sc]
+		if d != nil {
+			pp.deferpool[sc] = d.link
 		}
 	}
 	if d == nil {
 		// Allocate new defer+args.
-		total := roundupsize(totaldefersize(uintptr(siz)))
+		total := goroundupsize(totaldefersize(uintptr(siz)))
 		d = (*_defer)(mallocgc(total, deferType, 0))
 	}
 	d.siz = siz
@@ -197,6 +186,7 @@ func newdefer(siz int32) *_defer {
 
 // Free the given defer.
 // The defer cannot be used after this call.
+//go:nosplit
 func freedefer(d *_defer) {
 	if d._panic != nil {
 		freedeferpanic()
@@ -207,29 +197,10 @@ func freedefer(d *_defer) {
 	sc := deferclass(uintptr(d.siz))
 	if sc < uintptr(len(p{}.deferpool)) {
 		mp := acquirem()
-		pp := mp.p.ptr()
-		if len(pp.deferpool[sc]) == cap(pp.deferpool[sc]) {
-			// Transfer half of local cache to the central cache.
-			var first, last *_defer
-			for len(pp.deferpool[sc]) > cap(pp.deferpool[sc])/2 {
-				n := len(pp.deferpool[sc])
-				d := pp.deferpool[sc][n-1]
-				pp.deferpool[sc][n-1] = nil
-				pp.deferpool[sc] = pp.deferpool[sc][:n-1]
-				if first == nil {
-					first = d
-				} else {
-					last.link = d
-				}
-				last = d
-			}
-			lock(&sched.deferlock)
-			last.link = sched.deferpool[sc]
-			sched.deferpool[sc] = first
-			unlock(&sched.deferlock)
-		}
+		pp := mp.p
 		*d = _defer{}
-		pp.deferpool[sc] = append(pp.deferpool[sc], d)
+		d.link = pp.deferpool[sc]
+		pp.deferpool[sc] = d
 		releasem(mp)
 	}
 }
@@ -238,12 +209,12 @@ func freedefer(d *_defer) {
 // Windows otherwise runs out of stack space.
 func freedeferpanic() {
 	// _panic must be cleared before d is unlinked from gp.
-	throw("freedefer with d._panic != nil")
+	gothrow("freedefer with d._panic != nil")
 }
 
 func freedeferfn() {
 	// fn must be cleared before d is unlinked from gp.
-	throw("freedefer with d.fn != nil")
+	gothrow("freedefer with d.fn != nil")
 }
 
 // Run a deferred function if there is one.
@@ -266,8 +237,8 @@ func deferreturn(arg0 uintptr) {
 	if d == nil {
 		return
 	}
-	sp := getcallersp(unsafe.Pointer(&arg0))
-	if d.sp != sp {
+	argp := uintptr(unsafe.Pointer(&arg0))
+	if d.argp != argp {
 		return
 	}
 
@@ -276,16 +247,13 @@ func deferreturn(arg0 uintptr) {
 	// won't know the form of the arguments until the jmpdefer can
 	// flip the PC over to fn.
 	mp := acquirem()
-	memmove(unsafe.Pointer(&arg0), deferArgs(d), uintptr(d.siz))
+	memmove(unsafe.Pointer(argp), deferArgs(d), uintptr(d.siz))
 	fn := d.fn
 	d.fn = nil
 	gp._defer = d.link
-	// Switch to systemstack merely to save nosplit stack space.
-	systemstack(func() {
-		freedefer(d)
-	})
+	freedefer(d)
 	releasem(mp)
-	jmpdefer(fn, uintptr(unsafe.Pointer(&arg0)))
+	jmpdefer(fn, argp)
 }
 
 // Goexit terminates the goroutine that calls it.  No other goroutine is affected.
@@ -317,9 +285,9 @@ func Goexit() {
 			continue
 		}
 		d.started = true
-		reflectcall(nil, unsafe.Pointer(d.fn), deferArgs(d), uint32(d.siz), uint32(d.siz))
+		reflectcall(unsafe.Pointer(d.fn), deferArgs(d), uint32(d.siz), uint32(d.siz))
 		if gp._defer != d {
-			throw("bad defer entry in Goexit")
+			gothrow("bad defer entry in Goexit")
 		}
 		d._panic = nil
 		d.fn = nil
@@ -327,9 +295,11 @@ func Goexit() {
 		freedefer(d)
 		// Note: we ignore recovers here because Goexit isn't a panic
 	}
-	goexit1()
+	goexit()
 }
 
+func canpanic(*g) bool
+
 // Print all currently active panics.  Used when crashing.
 func printpanics(p *_panic) {
 	if p.link != nil {
@@ -348,10 +318,7 @@ func printpanics(p *_panic) {
 func gopanic(e interface{}) {
 	gp := getg()
 	if gp.m.curg != gp {
-		print("panic: ")
-		printany(e)
-		print("\n")
-		throw("panic on system stack")
+		gothrow("panic on m stack")
 	}
 
 	// m.softfloat is set during software floating point.
@@ -361,28 +328,25 @@ func gopanic(e interface{}) {
 	if gp.m.softfloat != 0 {
 		gp.m.locks--
 		gp.m.softfloat = 0
-		throw("panic during softfloat")
+		gothrow("panic during softfloat")
 	}
 	if gp.m.mallocing != 0 {
 		print("panic: ")
 		printany(e)
 		print("\n")
-		throw("panic during malloc")
+		gothrow("panic during malloc")
 	}
-	if gp.m.preemptoff != "" {
+	if gp.m.gcing != 0 {
 		print("panic: ")
 		printany(e)
 		print("\n")
-		print("preempt off reason: ")
-		print(gp.m.preemptoff)
-		print("\n")
-		throw("panic during preemptoff")
+		gothrow("panic during gc")
 	}
 	if gp.m.locks != 0 {
 		print("panic: ")
 		printany(e)
 		print("\n")
-		throw("panic holding locks")
+		gothrow("panic holding locks")
 	}
 
 	var p _panic
@@ -411,7 +375,7 @@ func gopanic(e interface{}) {
 
 		// Mark defer as started, but keep on list, so that traceback
 		// can find and update the defer's argument frame if stack growth
-		// or a garbage collection happens before reflectcall starts executing d.fn.
+		// or a garbage collection hapens before reflectcall starts executing d.fn.
 		d.started = true
 
 		// Record the panic that is running the defer.
@@ -420,12 +384,12 @@ func gopanic(e interface{}) {
 		d._panic = (*_panic)(noescape((unsafe.Pointer)(&p)))
 
 		p.argp = unsafe.Pointer(getargp(0))
-		reflectcall(nil, unsafe.Pointer(d.fn), deferArgs(d), uint32(d.siz), uint32(d.siz))
+		reflectcall(unsafe.Pointer(d.fn), deferArgs(d), uint32(d.siz), uint32(d.siz))
 		p.argp = nil
 
 		// reflectcall did not panic. Remove d.
 		if gp._defer != d {
-			throw("bad defer entry in panic")
+			gothrow("bad defer entry in panic")
 		}
 		d._panic = nil
 		d.fn = nil
@@ -435,7 +399,7 @@ func gopanic(e interface{}) {
 		//GC()
 
 		pc := d.pc
-		sp := unsafe.Pointer(d.sp) // must be pointer so it gets adjusted during stack copy
+		argp := unsafe.Pointer(d.argp) // must be pointer so it gets adjusted during stack copy
 		freedefer(d)
 		if p.recovered {
 			gp._panic = p.link
@@ -448,10 +412,10 @@ func gopanic(e interface{}) {
 				gp.sig = 0
 			}
 			// Pass information about recovering frame to recovery.
-			gp.sigcode0 = uintptr(sp)
+			gp.sigcode0 = uintptr(argp)
 			gp.sigcode1 = pc
-			mcall(recovery)
-			throw("recovery failed") // mcall should not return
+			mcall(recovery_m)
+			gothrow("recovery failed") // mcall should not return
 		}
 	}
 
@@ -502,28 +466,40 @@ func gorecover(argp uintptr) interface{} {
 
 //go:nosplit
 func startpanic() {
-	systemstack(startpanic_m)
+	onM_signalok(startpanic_m)
 }
 
 //go:nosplit
 func dopanic(unused int) {
-	pc := getcallerpc(unsafe.Pointer(&unused))
-	sp := getcallersp(unsafe.Pointer(&unused))
 	gp := getg()
-	systemstack(func() {
-		dopanic_m(gp, pc, sp) // should never return
-	})
+	mp := acquirem()
+	mp.ptrarg[0] = unsafe.Pointer(gp)
+	mp.scalararg[0] = getcallerpc((unsafe.Pointer)(&unused))
+	mp.scalararg[1] = getcallersp((unsafe.Pointer)(&unused))
+	onM_signalok(dopanic_m) // should never return
 	*(*int)(nil) = 0
 }
 
 //go:nosplit
-func throw(s string) {
-	print("fatal error: ", s, "\n")
+func throw(s *byte) {
+	gp := getg()
+	if gp.m.throwing == 0 {
+		gp.m.throwing = 1
+	}
+	startpanic()
+	print("fatal error: ", gostringnocopy(s), "\n")
+	dopanic(0)
+	*(*int)(nil) = 0 // not reached
+}
+
+//go:nosplit
+func gothrow(s string) {
 	gp := getg()
 	if gp.m.throwing == 0 {
 		gp.m.throwing = 1
 	}
 	startpanic()
+	print("fatal error: ", s, "\n")
 	dopanic(0)
 	*(*int)(nil) = 0 // not reached
 }
diff --git a/src/runtime/parfor.c b/src/runtime/parfor.c
new file mode 100644
index 0000000..e449568
--- /dev/null
+++ b/src/runtime/parfor.c
@@ -0,0 +1,226 @@
+// 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.
+
+// Parallel for algorithm.
+
+#include "runtime.h"
+#include "arch_GOARCH.h"
+#include "malloc.h"
+
+struct ParForThread
+{
+	// the thread's iteration space [32lsb, 32msb)
+	uint64 pos;
+	// stats
+	uint64 nsteal;
+	uint64 nstealcnt;
+	uint64 nprocyield;
+	uint64 nosyield;
+	uint64 nsleep;
+	byte pad[CacheLineSize];
+};
+
+void
+runtime·parforsetup(ParFor *desc, uint32 nthr, uint32 n, void *ctx, bool wait, void (*body)(ParFor*, uint32))
+{
+	uint32 i, begin, end;
+	uint64 *pos;
+
+	if(desc == nil || nthr == 0 || nthr > desc->nthrmax || body == nil) {
+		runtime·printf("desc=%p nthr=%d count=%d body=%p\n", desc, nthr, n, body);
+		runtime·throw("parfor: invalid args");
+	}
+
+	desc->body = body;
+	desc->done = 0;
+	desc->nthr = nthr;
+	desc->thrseq = 0;
+	desc->cnt = n;
+	desc->ctx = ctx;
+	desc->wait = wait;
+	desc->nsteal = 0;
+	desc->nstealcnt = 0;
+	desc->nprocyield = 0;
+	desc->nosyield = 0;
+	desc->nsleep = 0;
+	for(i=0; i<nthr; i++) {
+		begin = (uint64)n*i / nthr;
+		end = (uint64)n*(i+1) / nthr;
+		pos = &desc->thr[i].pos;
+		if(((uintptr)pos & 7) != 0)
+			runtime·throw("parforsetup: pos is not aligned");
+		*pos = (uint64)begin | (((uint64)end)<<32);
+	}
+}
+
+void
+runtime·parfordo(ParFor *desc)
+{
+	ParForThread *me;
+	uint32 tid, begin, end, begin2, try, victim, i;
+	uint64 *mypos, *victimpos, pos, newpos;
+	void (*body)(ParFor*, uint32);
+	bool idle;
+
+	// Obtain 0-based thread index.
+	tid = runtime·xadd(&desc->thrseq, 1) - 1;
+	if(tid >= desc->nthr) {
+		runtime·printf("tid=%d nthr=%d\n", tid, desc->nthr);
+		runtime·throw("parfor: invalid tid");
+	}
+
+	// If single-threaded, just execute the for serially.
+	if(desc->nthr==1) {
+		for(i=0; i<desc->cnt; i++)
+			desc->body(desc, i);
+		return;
+	}
+
+	body = desc->body;
+	me = &desc->thr[tid];
+	mypos = &me->pos;
+	for(;;) {
+		for(;;) {
+			// While there is local work,
+			// bump low index and execute the iteration.
+			pos = runtime·xadd64(mypos, 1);
+			begin = (uint32)pos-1;
+			end = (uint32)(pos>>32);
+			if(begin < end) {
+				body(desc, begin);
+				continue;
+			}
+			break;
+		}
+
+		// Out of work, need to steal something.
+		idle = false;
+		for(try=0;; try++) {
+			// If we don't see any work for long enough,
+			// increment the done counter...
+			if(try > desc->nthr*4 && !idle) {
+				idle = true;
+				runtime·xadd(&desc->done, 1);
+			}
+			// ...if all threads have incremented the counter,
+			// we are done.
+			if(desc->done + !idle == desc->nthr) {
+				if(!idle)
+					runtime·xadd(&desc->done, 1);
+				goto exit;
+			}
+			// Choose a random victim for stealing.
+			victim = runtime·fastrand1() % (desc->nthr-1);
+			if(victim >= tid)
+				victim++;
+			victimpos = &desc->thr[victim].pos;
+			for(;;) {
+				// See if it has any work.
+				pos = runtime·atomicload64(victimpos);
+				begin = (uint32)pos;
+				end = (uint32)(pos>>32);
+				if(begin+1 >= end) {
+					begin = end = 0;
+					break;
+				}
+				if(idle) {
+					runtime·xadd(&desc->done, -1);
+					idle = false;
+				}
+				begin2 = begin + (end-begin)/2;
+				newpos = (uint64)begin | (uint64)begin2<<32;
+				if(runtime·cas64(victimpos, pos, newpos)) {
+					begin = begin2;
+					break;
+				}
+			}
+			if(begin < end) {
+				// Has successfully stolen some work.
+				if(idle)
+					runtime·throw("parfor: should not be idle");
+				runtime·atomicstore64(mypos, (uint64)begin | (uint64)end<<32);
+				me->nsteal++;
+				me->nstealcnt += end-begin;
+				break;
+			}
+			// Backoff.
+			if(try < desc->nthr) {
+				// nothing
+			} else if (try < 4*desc->nthr) {
+				me->nprocyield++;
+				runtime·procyield(20);
+			// If a caller asked not to wait for the others, exit now
+			// (assume that most work is already done at this point).
+			} else if (!desc->wait) {
+				if(!idle)
+					runtime·xadd(&desc->done, 1);
+				goto exit;
+			} else if (try < 6*desc->nthr) {
+				me->nosyield++;
+				runtime·osyield();
+			} else {
+				me->nsleep++;
+				runtime·usleep(1);
+			}
+		}
+	}
+exit:
+	runtime·xadd64(&desc->nsteal, me->nsteal);
+	runtime·xadd64(&desc->nstealcnt, me->nstealcnt);
+	runtime·xadd64(&desc->nprocyield, me->nprocyield);
+	runtime·xadd64(&desc->nosyield, me->nosyield);
+	runtime·xadd64(&desc->nsleep, me->nsleep);
+	me->nsteal = 0;
+	me->nstealcnt = 0;
+	me->nprocyield = 0;
+	me->nosyield = 0;
+	me->nsleep = 0;
+}
+
+// For testing from Go.
+void
+runtime·newparfor_m(void)
+{
+	g->m->ptrarg[0] = runtime·parforalloc(g->m->scalararg[0]);
+}
+
+void
+runtime·parforsetup_m(void)
+{
+	ParFor *desc;
+	void *ctx;
+	void (*body)(ParFor*, uint32);
+
+	desc = g->m->ptrarg[0];
+	g->m->ptrarg[0] = nil;
+	ctx = g->m->ptrarg[1];
+	g->m->ptrarg[1] = nil;
+	body = g->m->ptrarg[2];
+	g->m->ptrarg[2] = nil;
+
+	runtime·parforsetup(desc, g->m->scalararg[0], g->m->scalararg[1], ctx, g->m->scalararg[2], body);
+}
+
+void
+runtime·parfordo_m(void)
+{
+	ParFor *desc;
+
+	desc = g->m->ptrarg[0];
+	g->m->ptrarg[0] = nil;
+	runtime·parfordo(desc);
+}
+
+void
+runtime·parforiters_m(void)
+{
+	ParFor *desc;
+	uintptr tid;
+
+	desc = g->m->ptrarg[0];
+	g->m->ptrarg[0] = nil;
+	tid = g->m->scalararg[0];
+	g->m->scalararg[0] = desc->thr[tid].pos;
+	g->m->scalararg[1] = desc->thr[tid].pos>>32;
+}
diff --git a/src/runtime/parfor_test.go b/src/runtime/parfor_test.go
index 5d22aec..de64285 100644
--- a/src/runtime/parfor_test.go
+++ b/src/runtime/parfor_test.go
@@ -10,8 +10,11 @@ package runtime_test
 import (
 	. "runtime"
 	"testing"
+	"unsafe"
 )
 
+var gdata []uint64
+
 // Simple serial sanity test for parallelfor.
 func TestParFor(t *testing.T) {
 	const P = 1
@@ -21,7 +24,12 @@ func TestParFor(t *testing.T) {
 		data[i] = i
 	}
 	desc := NewParFor(P)
-	ParForSetup(desc, P, N, true, func(desc *ParFor, i uint32) {
+	// Avoid making func a closure: parfor cannot invoke them.
+	// Since it doesn't happen in the C code, it's not worth doing
+	// just for the test.
+	gdata = data
+	ParForSetup(desc, P, N, nil, true, func(desc *ParFor, i uint32) {
+		data := gdata
 		data[i] = data[i]*data[i] + 1
 	})
 	ParForDo(desc)
@@ -41,8 +49,9 @@ func TestParFor2(t *testing.T) {
 		data[i] = i
 	}
 	desc := NewParFor(P)
-	ParForSetup(desc, P, N, false, func(desc *ParFor, i uint32) {
-		data[i] = data[i]*data[i] + 1
+	ParForSetup(desc, P, N, (*byte)(unsafe.Pointer(&data)), false, func(desc *ParFor, i uint32) {
+		d := *(*[]uint64)(unsafe.Pointer(desc.Ctx))
+		d[i] = d[i]*d[i] + 1
 	})
 	for p := 0; p < P; p++ {
 		ParForDo(desc)
@@ -61,7 +70,7 @@ func TestParForSetup(t *testing.T) {
 	desc := NewParFor(P)
 	for n := uint32(0); n < N; n++ {
 		for p := uint32(1); p <= P; p++ {
-			ParForSetup(desc, p, n, true, func(desc *ParFor, i uint32) {})
+			ParForSetup(desc, p, n, nil, true, func(desc *ParFor, i uint32) {})
 			sum := uint32(0)
 			size0 := uint32(0)
 			end0 := uint32(0)
@@ -104,7 +113,9 @@ func TestParForParallel(t *testing.T) {
 	P := GOMAXPROCS(-1)
 	c := make(chan bool, P)
 	desc := NewParFor(uint32(P))
-	ParForSetup(desc, uint32(P), uint32(N), false, func(desc *ParFor, i uint32) {
+	gdata = data
+	ParForSetup(desc, uint32(P), uint32(N), nil, false, func(desc *ParFor, i uint32) {
+		data := gdata
 		data[i] = data[i]*data[i] + 1
 	})
 	for p := 1; p < P; p++ {
diff --git a/src/runtime/pprof/pprof.go b/src/runtime/pprof/pprof.go
index 23fc850..236de54 100644
--- a/src/runtime/pprof/pprof.go
+++ b/src/runtime/pprof/pprof.go
@@ -21,7 +21,7 @@ import (
 )
 
 // BUG(rsc): Profiles are incomplete and inaccurate on NetBSD and OS X.
-// See https://golang.org/issue/6047 for details.
+// See http://golang.org/issue/6047 for details.
 
 // A Profile is a collection of stack traces showing the call sequences
 // that led to instances of a particular event, such as allocation.
@@ -41,13 +41,6 @@ import (
 // These predefined profiles maintain themselves and panic on an explicit
 // Add or Remove method call.
 //
-// The heap profile reports statistics as of the most recently completed
-// garbage collection; it elides more recent allocation to avoid skewing
-// the profile away from live data and toward garbage.
-// If there has been no garbage collection at all, the heap profile reports
-// all known allocations. This exception helps mainly in programs running
-// without garbage collection enabled, usually for debugging purposes.
-//
 // The CPU profile is not available as a Profile.  It has a special API,
 // the StartCPUProfile and StopCPUProfile functions, because it streams
 // output to a writer during profiling.
@@ -449,33 +442,35 @@ func writeHeap(w io.Writer, debug int) error {
 
 	// Print memstats information too.
 	// Pprof will ignore, but useful for people
-	s := new(runtime.MemStats)
-	runtime.ReadMemStats(s)
-	fmt.Fprintf(w, "\n# runtime.MemStats\n")
-	fmt.Fprintf(w, "# Alloc = %d\n", s.Alloc)
-	fmt.Fprintf(w, "# TotalAlloc = %d\n", s.TotalAlloc)
-	fmt.Fprintf(w, "# Sys = %d\n", s.Sys)
-	fmt.Fprintf(w, "# Lookups = %d\n", s.Lookups)
-	fmt.Fprintf(w, "# Mallocs = %d\n", s.Mallocs)
-	fmt.Fprintf(w, "# Frees = %d\n", s.Frees)
-
-	fmt.Fprintf(w, "# HeapAlloc = %d\n", s.HeapAlloc)
-	fmt.Fprintf(w, "# HeapSys = %d\n", s.HeapSys)
-	fmt.Fprintf(w, "# HeapIdle = %d\n", s.HeapIdle)
-	fmt.Fprintf(w, "# HeapInuse = %d\n", s.HeapInuse)
-	fmt.Fprintf(w, "# HeapReleased = %d\n", s.HeapReleased)
-	fmt.Fprintf(w, "# HeapObjects = %d\n", s.HeapObjects)
-
-	fmt.Fprintf(w, "# Stack = %d / %d\n", s.StackInuse, s.StackSys)
-	fmt.Fprintf(w, "# MSpan = %d / %d\n", s.MSpanInuse, s.MSpanSys)
-	fmt.Fprintf(w, "# MCache = %d / %d\n", s.MCacheInuse, s.MCacheSys)
-	fmt.Fprintf(w, "# BuckHashSys = %d\n", s.BuckHashSys)
-
-	fmt.Fprintf(w, "# NextGC = %d\n", s.NextGC)
-	fmt.Fprintf(w, "# PauseNs = %d\n", s.PauseNs)
-	fmt.Fprintf(w, "# NumGC = %d\n", s.NumGC)
-	fmt.Fprintf(w, "# EnableGC = %v\n", s.EnableGC)
-	fmt.Fprintf(w, "# DebugGC = %v\n", s.DebugGC)
+	if debug > 0 {
+		s := new(runtime.MemStats)
+		runtime.ReadMemStats(s)
+		fmt.Fprintf(w, "\n# runtime.MemStats\n")
+		fmt.Fprintf(w, "# Alloc = %d\n", s.Alloc)
+		fmt.Fprintf(w, "# TotalAlloc = %d\n", s.TotalAlloc)
+		fmt.Fprintf(w, "# Sys = %d\n", s.Sys)
+		fmt.Fprintf(w, "# Lookups = %d\n", s.Lookups)
+		fmt.Fprintf(w, "# Mallocs = %d\n", s.Mallocs)
+		fmt.Fprintf(w, "# Frees = %d\n", s.Frees)
+
+		fmt.Fprintf(w, "# HeapAlloc = %d\n", s.HeapAlloc)
+		fmt.Fprintf(w, "# HeapSys = %d\n", s.HeapSys)
+		fmt.Fprintf(w, "# HeapIdle = %d\n", s.HeapIdle)
+		fmt.Fprintf(w, "# HeapInuse = %d\n", s.HeapInuse)
+		fmt.Fprintf(w, "# HeapReleased = %d\n", s.HeapReleased)
+		fmt.Fprintf(w, "# HeapObjects = %d\n", s.HeapObjects)
+
+		fmt.Fprintf(w, "# Stack = %d / %d\n", s.StackInuse, s.StackSys)
+		fmt.Fprintf(w, "# MSpan = %d / %d\n", s.MSpanInuse, s.MSpanSys)
+		fmt.Fprintf(w, "# MCache = %d / %d\n", s.MCacheInuse, s.MCacheSys)
+		fmt.Fprintf(w, "# BuckHashSys = %d\n", s.BuckHashSys)
+
+		fmt.Fprintf(w, "# NextGC = %d\n", s.NextGC)
+		fmt.Fprintf(w, "# PauseNs = %d\n", s.PauseNs)
+		fmt.Fprintf(w, "# NumGC = %d\n", s.NumGC)
+		fmt.Fprintf(w, "# EnableGC = %v\n", s.EnableGC)
+		fmt.Fprintf(w, "# DebugGC = %v\n", s.DebugGC)
+	}
 
 	if tw != nil {
 		tw.Flush()
diff --git a/src/runtime/pprof/pprof_test.go b/src/runtime/pprof/pprof_test.go
index 785d75a..8677cb3 100644
--- a/src/runtime/pprof/pprof_test.go
+++ b/src/runtime/pprof/pprof_test.go
@@ -9,9 +9,7 @@ package pprof_test
 import (
 	"bytes"
 	"fmt"
-	"internal/testenv"
 	"math/big"
-	"os"
 	"os/exec"
 	"regexp"
 	"runtime"
@@ -123,19 +121,15 @@ func parseProfile(t *testing.T, bytes []byte, f func(uintptr, []uintptr)) {
 func testCPUProfile(t *testing.T, need []string, f func()) {
 	switch runtime.GOOS {
 	case "darwin":
-		switch runtime.GOARCH {
-		case "arm", "arm64":
-			// nothing
-		default:
-			out, err := exec.Command("uname", "-a").CombinedOutput()
-			if err != nil {
-				t.Fatal(err)
-			}
-			vers := string(out)
-			t.Logf("uname -a: %v", vers)
+		out, err := exec.Command("uname", "-a").CombinedOutput()
+		if err != nil {
+			t.Fatal(err)
 		}
+		vers := string(out)
+		t.Logf("uname -a: %v", vers)
 	case "plan9":
-		t.Skip("skipping on plan9")
+		// unimplemented
+		return
 	}
 
 	var prof bytes.Buffer
@@ -147,9 +141,7 @@ func testCPUProfile(t *testing.T, need []string, f func()) {
 
 	// Check that profile is well formed and contains need.
 	have := make([]uintptr, len(need))
-	var samples uintptr
 	parseProfile(t, prof.Bytes(), func(count uintptr, stk []uintptr) {
-		samples += count
 		for _, pc := range stk {
 			f := runtime.FuncForPC(pc)
 			if f == nil {
@@ -162,14 +154,6 @@ func testCPUProfile(t *testing.T, need []string, f func()) {
 			}
 		}
 	})
-	t.Logf("total %d CPU profile samples collected", samples)
-
-	if samples < 10 && runtime.GOOS == "windows" {
-		// On some windows machines we end up with
-		// not enough samples due to coarse timer
-		// resolution. Let it go.
-		t.Skip("too few samples on Windows (golang.org/issue/10842)")
-	}
 
 	if len(need) == 0 {
 		return
@@ -202,28 +186,14 @@ func testCPUProfile(t *testing.T, need []string, f func()) {
 			t.Skipf("ignoring failure on %s; see golang.org/issue/6047", runtime.GOOS)
 			return
 		}
-		// Ignore the failure if the tests are running in a QEMU-based emulator,
-		// QEMU is not perfect at emulating everything.
-		// IN_QEMU environmental variable is set by some of the Go builders.
-		// IN_QEMU=1 indicates that the tests are running in QEMU. See issue 9605.
-		if os.Getenv("IN_QEMU") == "1" {
-			t.Skip("ignore the failure in QEMU; see golang.org/issue/9605")
-			return
-		}
 		t.FailNow()
 	}
 }
 
-// Fork can hang if preempted with signals frequently enough (see issue 5517).
-// Ensure that we do not do this.
 func TestCPUProfileWithFork(t *testing.T) {
-	testenv.MustHaveExec(t)
-
+	// Fork can hang if preempted with signals frequently enough (see issue 5517).
+	// Ensure that we do not do this.
 	heap := 1 << 30
-	if runtime.GOOS == "android" {
-		// Use smaller size for Android to avoid crash.
-		heap = 100 << 20
-	}
 	if testing.Short() {
 		heap = 100 << 20
 	}
@@ -246,7 +216,7 @@ func TestCPUProfileWithFork(t *testing.T) {
 	defer StopCPUProfile()
 
 	for i := 0; i < 10; i++ {
-		exec.Command(os.Args[0], "-h").CombinedOutput()
+		exec.Command("go").CombinedOutput()
 	}
 }
 
@@ -279,7 +249,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() == "runtime._System" || f.Name() == "runtime._ExternalCode" || f.Name() == "runtime._GC") {
+				if f != nil && (f.Name() == "System" || f.Name() == "ExternalCode" || f.Name() == "GC") {
 					return
 				}
 			}
@@ -396,7 +366,7 @@ func TestBlockProfile(t *testing.T) {
 	}
 
 	for _, test := range tests {
-		if !regexp.MustCompile(strings.Replace(test.re, "\t", "\t+", -1)).MatchString(prof) {
+		if !regexp.MustCompile(test.re).MatchString(prof) {
 			t.Fatalf("Bad %v entry, expect:\n%v\ngot:\n%v", test.name, test.re, prof)
 		}
 	}
diff --git a/src/runtime/print1.go b/src/runtime/print1.go
index 6eff381..8f82688 100644
--- a/src/runtime/print1.go
+++ b/src/runtime/print1.go
@@ -13,39 +13,35 @@ type hex uint64
 func bytes(s string) (ret []byte) {
 	rp := (*slice)(unsafe.Pointer(&ret))
 	sp := (*_string)(noescape(unsafe.Pointer(&s)))
-	rp.array = unsafe.Pointer(sp.str)
-	rp.len = sp.len
-	rp.cap = sp.len
+	rp.array = sp.str
+	rp.len = uint(sp.len)
+	rp.cap = uint(sp.len)
 	return
 }
 
-var debuglock mutex
+// printf is only called from C code. It has no type information for the args,
+// but C stacks are ignored by the garbage collector anyway, so having
+// type information would not add anything.
+//go:nosplit
+func printf(s *byte) {
+	vprintf(gostringnocopy(s), add(unsafe.Pointer(&s), unsafe.Sizeof(s)))
+}
 
-// The compiler emits calls to printlock and printunlock around
-// the multiple calls that implement a single Go print or println
-// statement. Some of the print helpers (printsp, for example)
-// call print recursively. There is also the problem of a crash
-// happening during the print routines and needing to acquire
-// the print lock to print information about the crash.
-// For both these reasons, let a thread acquire the printlock 'recursively'.
+// sprintf is only called from C code. It has no type information for the args,
+// but C stacks are ignored by the garbage collector anyway, so having
+// type information would not add anything.
+//go:nosplit
+func snprintf(dst *byte, n int32, s *byte) {
+	buf := (*[1 << 30]byte)(unsafe.Pointer(dst))[0:n:n]
 
-func printlock() {
-	mp := getg().m
-	mp.locks++ // do not reschedule between printlock++ and lock(&debuglock).
-	mp.printlock++
-	if mp.printlock == 1 {
-		lock(&debuglock)
-	}
-	mp.locks-- // now we know debuglock is held and holding up mp.locks for us.
+	gp := getg()
+	gp.writebuf = buf[0:0 : n-1] // leave room for NUL, this is called from C
+	vprintf(gostringnocopy(s), add(unsafe.Pointer(&s), unsafe.Sizeof(s)))
+	buf[len(gp.writebuf)] = '\x00'
+	gp.writebuf = nil
 }
 
-func printunlock() {
-	mp := getg().m
-	mp.printlock--
-	if mp.printlock == 0 {
-		unlock(&debuglock)
-	}
-}
+//var debuglock mutex
 
 // write to goroutine-local buffer if diverting output,
 // or else standard error.
@@ -55,7 +51,7 @@ func gwrite(b []byte) {
 	}
 	gp := getg()
 	if gp == nil || gp.writebuf == nil {
-		writeErr(b)
+		write(2, unsafe.Pointer(&b[0]), int32(len(b)))
 		return
 	}
 
@@ -63,6 +59,16 @@ func gwrite(b []byte) {
 	gp.writebuf = gp.writebuf[:len(gp.writebuf)+n]
 }
 
+func prints(s *byte) {
+	b := (*[1 << 30]byte)(unsafe.Pointer(s))
+	for i := 0; ; i++ {
+		if b[i] == 0 {
+			gwrite(b[:i])
+			return
+		}
+	}
+}
+
 func printsp() {
 	print(" ")
 }
@@ -71,6 +77,92 @@ func printnl() {
 	print("\n")
 }
 
+// Very simple printf.  Only for debugging prints.
+// Do not add to this without checking with Rob.
+func vprintf(str string, arg unsafe.Pointer) {
+	//lock(&debuglock);
+
+	s := bytes(str)
+	start := 0
+	i := 0
+	for ; i < len(s); i++ {
+		if s[i] != '%' {
+			continue
+		}
+		if i > start {
+			gwrite(s[start:i])
+		}
+		if i++; i >= len(s) {
+			break
+		}
+		var siz uintptr
+		switch s[i] {
+		case 't', 'c':
+			siz = 1
+		case 'd', 'x': // 32-bit
+			arg = roundup(arg, 4)
+			siz = 4
+		case 'D', 'U', 'X', 'f': // 64-bit
+			arg = roundup(arg, unsafe.Sizeof(uintreg(0)))
+			siz = 8
+		case 'C':
+			arg = roundup(arg, unsafe.Sizeof(uintreg(0)))
+			siz = 16
+		case 'p', 's': // pointer-sized
+			arg = roundup(arg, unsafe.Sizeof(uintptr(0)))
+			siz = unsafe.Sizeof(uintptr(0))
+		case 'S': // pointer-aligned but bigger
+			arg = roundup(arg, unsafe.Sizeof(uintptr(0)))
+			siz = unsafe.Sizeof(string(""))
+		case 'a': // pointer-aligned but bigger
+			arg = roundup(arg, unsafe.Sizeof(uintptr(0)))
+			siz = unsafe.Sizeof([]byte{})
+		case 'i', 'e': // pointer-aligned but bigger
+			arg = roundup(arg, unsafe.Sizeof(uintptr(0)))
+			siz = unsafe.Sizeof(interface{}(nil))
+		}
+		switch s[i] {
+		case 'a':
+			printslice(*(*[]byte)(arg))
+		case 'c':
+			printbyte(*(*byte)(arg))
+		case 'd':
+			printint(int64(*(*int32)(arg)))
+		case 'D':
+			printint(int64(*(*int64)(arg)))
+		case 'e':
+			printeface(*(*interface{})(arg))
+		case 'f':
+			printfloat(*(*float64)(arg))
+		case 'C':
+			printcomplex(*(*complex128)(arg))
+		case 'i':
+			printiface(*(*fInterface)(arg))
+		case 'p':
+			printpointer(*(*unsafe.Pointer)(arg))
+		case 's':
+			prints(*(**byte)(arg))
+		case 'S':
+			printstring(*(*string)(arg))
+		case 't':
+			printbool(*(*bool)(arg))
+		case 'U':
+			printuint(*(*uint64)(arg))
+		case 'x':
+			printhex(uint64(*(*uint32)(arg)))
+		case 'X':
+			printhex(*(*uint64)(arg))
+		}
+		arg = add(arg, siz)
+		start = i + 1
+	}
+	if start < i {
+		gwrite(s[start:i])
+	}
+
+	//unlock(&debuglock);
+}
+
 func printpc(p unsafe.Pointer) {
 	print("PC=", hex(uintptr(p)))
 }
diff --git a/src/runtime/proc.c b/src/runtime/proc.c
new file mode 100644
index 0000000..8462c4b
--- /dev/null
+++ b/src/runtime/proc.c
@@ -0,0 +1,3521 @@
+// 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 "zaexperiment.h"
+#include "malloc.h"
+#include "stack.h"
+#include "race.h"
+#include "type.h"
+#include "mgc0.h"
+#include "textflag.h"
+
+// Goroutine scheduler
+// The scheduler's job is to distribute ready-to-run goroutines over worker threads.
+//
+// The main concepts are:
+// G - goroutine.
+// M - worker thread, or machine.
+// P - processor, a resource that is required to execute Go code.
+//     M must have an associated P to execute Go code, however it can be
+//     blocked or in a syscall w/o an associated P.
+//
+// Design doc at http://golang.org/s/go11sched.
+
+enum
+{
+	// 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,
+};
+
+SchedT	runtime·sched;
+int32	runtime·gomaxprocs;
+uint32	runtime·needextram;
+bool	runtime·iscgo;
+M	runtime·m0;
+G	runtime·g0;	// idle goroutine for m0
+G*	runtime·lastg;
+M*	runtime·allm;
+M*	runtime·extram;
+P*	runtime·allp[MaxGomaxprocs+1];
+int8*	runtime·goos;
+int32	runtime·ncpu;
+int32	runtime·newprocs;
+
+Mutex runtime·allglock;	// the following vars are protected by this lock or by stoptheworld
+G**	runtime·allg;
+Slice	runtime·allgs;
+uintptr runtime·allglen;
+ForceGCState	runtime·forcegc;
+
+void runtime·mstart(void);
+static void runqput(P*, G*);
+static G* runqget(P*);
+static bool runqputslow(P*, G*, uint32, uint32);
+static G* runqsteal(P*, P*);
+static void mput(M*);
+static M* mget(void);
+static void mcommoninit(M*);
+static void schedule(void);
+static void procresize(int32);
+static void acquirep(P*);
+static P* releasep(void);
+static void newm(void(*)(void), P*);
+static void stopm(void);
+static void startm(P*, bool);
+static void handoffp(P*);
+static void wakep(void);
+static void stoplockedm(void);
+static void startlockedm(G*);
+static void sysmon(void);
+static uint32 retake(int64);
+static void incidlelocked(int32);
+static void checkdead(void);
+static void exitsyscall0(G*);
+void runtime·park_m(G*);
+static void goexit0(G*);
+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*);
+static void injectglist(G*);
+static bool preemptall(void);
+static bool preemptone(P*);
+static bool exitsyscallfast(void);
+static bool haveexperiment(int8*);
+void runtime·allgadd(G*);
+static void dropg(void);
+
+extern String runtime·buildVersion;
+
+// For cgo-using programs with external linking,
+// export "main" (defined in assembly) so that libc can handle basic
+// C runtime startup and call the Go program as if it were
+// the C main function.
+#pragma cgo_export_static main
+
+// Filled in by dynamic linker when Cgo is available.
+void (*_cgo_init)(void);
+void (*_cgo_malloc)(void);
+void (*_cgo_free)(void);
+
+// Copy for Go code.
+void* runtime·cgoMalloc;
+void* runtime·cgoFree;
+
+// The bootstrap sequence is:
+//
+//	call osinit
+//	call schedinit
+//	make & queue new G
+//	call runtime·mstart
+//
+// The new G calls runtime·main.
+void
+runtime·schedinit(void)
+{
+	int32 n, procs;
+	byte *p;
+
+	// raceinit must be the first call to race detector.
+	// In particular, it must be done before mallocinit below calls racemapshadow.
+	if(raceenabled)
+		g->racectx = runtime·raceinit();
+
+	runtime·sched.maxmcount = 10000;
+
+	runtime·tracebackinit();
+	runtime·symtabinit();
+	runtime·stackinit();
+	runtime·mallocinit();
+	mcommoninit(g->m);
+	
+	runtime·goargs();
+	runtime·goenvs();
+	runtime·parsedebugvars();
+	runtime·gcinit();
+
+	runtime·sched.lastpoll = runtime·nanotime();
+	procs = 1;
+	p = runtime·getenv("GOMAXPROCS");
+	if(p != nil && (n = runtime·atoi(p)) > 0) {
+		if(n > MaxGomaxprocs)
+			n = MaxGomaxprocs;
+		procs = n;
+	}
+	procresize(procs);
+
+	if(runtime·buildVersion.str == nil) {
+		// Condition should never trigger.  This code just serves
+		// to ensure runtime·buildVersion is kept in the resulting binary.
+		runtime·buildVersion.str = (uint8*)"unknown";
+		runtime·buildVersion.len = 7;
+	}
+
+	runtime·cgoMalloc = _cgo_malloc;
+	runtime·cgoFree = _cgo_free;
+}
+
+void
+runtime·newsysmon(void)
+{
+	newm(sysmon, nil);
+}
+
+static void
+dumpgstatus(G* gp)
+{
+	runtime·printf("runtime: gp: gp=%p, goid=%D, gp->atomicstatus=%x\n", gp, gp->goid, runtime·readgstatus(gp));
+	runtime·printf("runtime:  g:  g=%p, goid=%D,  g->atomicstatus=%x\n", g, g->goid, runtime·readgstatus(g));
+}
+
+static void
+checkmcount(void)
+{
+	// sched lock is held
+	if(runtime·sched.mcount > runtime·sched.maxmcount){
+		runtime·printf("runtime: program exceeds %d-thread limit\n", runtime·sched.maxmcount);
+		runtime·throw("thread exhaustion");
+	}
+}
+
+static void
+mcommoninit(M *mp)
+{
+	// g0 stack won't make sense for user (and is not necessary unwindable).
+	if(g != g->m->g0)
+		runtime·callers(1, mp->createstack, nelem(mp->createstack));
+
+	mp->fastrand = 0x49f6428aUL + mp->id + runtime·cputicks();
+
+	runtime·lock(&runtime·sched.lock);
+	mp->id = runtime·sched.mcount++;
+	checkmcount();
+	runtime·mpreinit(mp);
+	if(mp->gsignal)
+		mp->gsignal->stackguard1 = mp->gsignal->stack.lo + StackGuard;
+
+	// Add to runtime·allm so garbage collector doesn't free g->m
+	// when it is just in a register or thread-local storage.
+	mp->alllink = runtime·allm;
+	// runtime·NumCgoCall() iterates over allm w/o schedlock,
+	// so we need to publish it safely.
+	runtime·atomicstorep(&runtime·allm, mp);
+	runtime·unlock(&runtime·sched.lock);
+}
+
+// Mark gp ready to run.
+void
+runtime·ready(G *gp)
+{
+	uint32 status;
+
+	status = runtime·readgstatus(gp);
+	// Mark runnable.
+	g->m->locks++;  // disable preemption because it can be holding p in a local var
+	if((status&~Gscan) != Gwaiting){
+		dumpgstatus(gp);
+		runtime·throw("bad g->status in ready");
+	}
+	// status is Gwaiting or Gscanwaiting, make Grunnable and put on runq
+	runtime·casgstatus(gp, Gwaiting, Grunnable);
+	runqput(g->m->p, gp);
+	if(runtime·atomicload(&runtime·sched.npidle) != 0 && runtime·atomicload(&runtime·sched.nmspinning) == 0)  // TODO: fast atomic
+		wakep();
+	g->m->locks--;
+	if(g->m->locks == 0 && g->preempt)  // restore the preemption request in case we've cleared it in newstack
+		g->stackguard0 = StackPreempt;
+}
+
+void
+runtime·ready_m(void)
+{
+	G *gp;
+
+	gp = g->m->ptrarg[0];
+	g->m->ptrarg[0] = nil;
+	runtime·ready(gp);
+}
+
+int32
+runtime·gcprocs(void)
+{
+	int32 n;
+
+	// Figure out how many CPUs to use during GC.
+	// Limited by gomaxprocs, number of actual CPUs, and MaxGcproc.
+	runtime·lock(&runtime·sched.lock);
+	n = runtime·gomaxprocs;
+	if(n > runtime·ncpu)
+		n = runtime·ncpu;
+	if(n > MaxGcproc)
+		n = MaxGcproc;
+	if(n > runtime·sched.nmidle+1) // one M is currently running
+		n = runtime·sched.nmidle+1;
+	runtime·unlock(&runtime·sched.lock);
+	return n;
+}
+
+static bool
+needaddgcproc(void)
+{
+	int32 n;
+
+	runtime·lock(&runtime·sched.lock);
+	n = runtime·gomaxprocs;
+	if(n > runtime·ncpu)
+		n = runtime·ncpu;
+	if(n > MaxGcproc)
+		n = MaxGcproc;
+	n -= runtime·sched.nmidle+1; // one M is currently running
+	runtime·unlock(&runtime·sched.lock);
+	return n > 0;
+}
+
+void
+runtime·helpgc(int32 nproc)
+{
+	M *mp;
+	int32 n, pos;
+
+	runtime·lock(&runtime·sched.lock);
+	pos = 0;
+	for(n = 1; n < nproc; n++) {  // one M is currently running
+		if(runtime·allp[pos]->mcache == g->m->mcache)
+			pos++;
+		mp = mget();
+		if(mp == nil)
+			runtime·throw("runtime·gcprocs inconsistency");
+		mp->helpgc = n;
+		mp->mcache = runtime·allp[pos]->mcache;
+		pos++;
+		runtime·notewakeup(&mp->park);
+	}
+	runtime·unlock(&runtime·sched.lock);
+}
+
+// Similar to stoptheworld but best-effort and can be called several times.
+// There is no reverse operation, used during crashing.
+// This function must not lock any mutexes.
+void
+runtime·freezetheworld(void)
+{
+	int32 i;
+
+	if(runtime·gomaxprocs == 1)
+		return;
+	// stopwait and preemption requests can be lost
+	// due to races with concurrently executing threads,
+	// so try several times
+	for(i = 0; i < 5; i++) {
+		// this should tell the scheduler to not start any new goroutines
+		runtime·sched.stopwait = 0x7fffffff;
+		runtime·atomicstore((uint32*)&runtime·sched.gcwaiting, 1);
+		// this should stop running goroutines
+		if(!preemptall())
+			break;  // no running goroutines
+		runtime·usleep(1000);
+	}
+	// to be sure
+	runtime·usleep(1000);
+	preemptall();
+	runtime·usleep(1000);
+}
+
+static bool
+isscanstatus(uint32 status)
+{
+	if(status == Gscan)
+		runtime·throw("isscanstatus: Bad status Gscan");
+	return (status&Gscan) == Gscan;
+}
+
+// All reads and writes of g's status go through readgstatus, casgstatus
+// castogscanstatus, casfromgscanstatus.
+#pragma textflag NOSPLIT
+uint32
+runtime·readgstatus(G *gp)
+{
+	return runtime·atomicload(&gp->atomicstatus);
+}
+
+// The Gscanstatuses are acting like locks and this releases them.
+// If it proves to be a performance hit we should be able to make these
+// simple atomic stores but for now we are going to throw if
+// we see an inconsistent state.
+void
+runtime·casfromgscanstatus(G *gp, uint32 oldval, uint32 newval)
+{
+	bool success = false;
+
+	// Check that transition is valid.
+	switch(oldval) {
+	case Gscanrunnable:
+	case Gscanwaiting:
+	case Gscanrunning:
+	case Gscansyscall:
+		if(newval == (oldval&~Gscan))
+			success = runtime·cas(&gp->atomicstatus, oldval, newval);
+		break;
+	case Gscanenqueue:
+		if(newval == Gwaiting)
+			success = runtime·cas(&gp->atomicstatus, oldval, newval);
+		break;
+	}	
+	if(!success){
+		runtime·printf("runtime: casfromgscanstatus failed gp=%p, oldval=%d, newval=%d\n",  
+			gp, oldval, newval);
+		dumpgstatus(gp);
+		runtime·throw("casfromgscanstatus: gp->status is not in scan state");
+	}
+}
+
+// This will return false if the gp is not in the expected status and the cas fails. 
+// This acts like a lock acquire while the casfromgstatus acts like a lock release.
+bool
+runtime·castogscanstatus(G *gp, uint32 oldval, uint32 newval)
+{
+	switch(oldval) {
+	case Grunnable:
+	case Gwaiting:
+	case Gsyscall:
+		if(newval == (oldval|Gscan))
+			return runtime·cas(&gp->atomicstatus, oldval, newval);
+		break;
+	case Grunning:
+		if(newval == Gscanrunning || newval == Gscanenqueue)
+			return runtime·cas(&gp->atomicstatus, oldval, newval);
+		break;   
+	}
+
+	runtime·printf("runtime: castogscanstatus oldval=%d newval=%d\n", oldval, newval);
+	runtime·throw("castogscanstatus");
+	return false; // not reached
+}
+
+static void badcasgstatus(void);
+static void helpcasgstatus(void);
+static void badgstatusrunnable(void);
+
+// If asked to move to or from a Gscanstatus this will throw. Use the castogscanstatus
+// and casfromgscanstatus instead.
+// casgstatus will loop if the g->atomicstatus is in a Gscan status until the routine that 
+// put it in the Gscan state is finished.
+#pragma textflag NOSPLIT
+void
+runtime·casgstatus(G *gp, uint32 oldval, uint32 newval)
+{
+	void (*fn)(void);
+
+	if((oldval&Gscan) || (newval&Gscan) || oldval == newval) {
+		g->m->scalararg[0] = oldval;
+		g->m->scalararg[1] = newval;
+		fn = badcasgstatus;
+		runtime·onM(&fn);
+	}
+
+	// loop if gp->atomicstatus is in a scan state giving
+	// GC time to finish and change the state to oldval.
+	while(!runtime·cas(&gp->atomicstatus, oldval, newval)) {
+		if(oldval == Gwaiting && gp->atomicstatus == Grunnable) {
+			fn = badgstatusrunnable;
+			runtime·onM(&fn);
+		}
+		// Help GC if needed. 
+		if(gp->preemptscan && !gp->gcworkdone && (oldval == Grunning || oldval == Gsyscall)) {
+			gp->preemptscan = false;
+			g->m->ptrarg[0] = gp;
+			fn = helpcasgstatus;
+			runtime·onM(&fn);
+		}
+	}	
+}
+
+static void
+badgstatusrunnable(void)
+{
+	runtime·throw("casgstatus: waiting for Gwaiting but is Grunnable");
+}
+
+// casgstatus(gp, oldstatus, Gcopystack), assuming oldstatus is Gwaiting or Grunnable.
+// Returns old status. Cannot call casgstatus directly, because we are racing with an
+// async wakeup that might come in from netpoll. If we see Gwaiting from the readgstatus,
+// it might have become Grunnable by the time we get to the cas. If we called casgstatus,
+// it would loop waiting for the status to go back to Gwaiting, which it never will.
+#pragma textflag NOSPLIT
+uint32
+runtime·casgcopystack(G *gp)
+{
+	uint32 oldstatus;
+
+	for(;;) {
+		oldstatus = runtime·readgstatus(gp) & ~Gscan;
+		if(oldstatus != Gwaiting && oldstatus != Grunnable)
+			runtime·throw("copystack: bad status, not Gwaiting or Grunnable");
+		if(runtime·cas(&gp->atomicstatus, oldstatus, Gcopystack))
+			break;
+	}
+	return oldstatus;
+}
+
+static void
+badcasgstatus(void)
+{
+	uint32 oldval, newval;
+	
+	oldval = g->m->scalararg[0];
+	newval = g->m->scalararg[1];
+	g->m->scalararg[0] = 0;
+	g->m->scalararg[1] = 0;
+
+	runtime·printf("casgstatus: oldval=%d, newval=%d\n", oldval, newval);
+	runtime·throw("casgstatus: bad incoming values");
+}
+
+static void
+helpcasgstatus(void)
+{
+	G *gp;
+	
+	gp = g->m->ptrarg[0];
+	g->m->ptrarg[0] = 0;
+	runtime·gcphasework(gp);
+}
+
+// stopg ensures that gp is stopped at a GC safe point where its stack can be scanned
+// or in the context of a moving collector the pointers can be flipped from pointing 
+// to old object to pointing to new objects. 
+// If stopg returns true, the caller knows gp is at a GC safe point and will remain there until
+// the caller calls restartg.
+// If stopg returns false, the caller is not responsible for calling restartg. This can happen
+// if another thread, either the gp itself or another GC thread is taking the responsibility 
+// to do the GC work related to this thread.
+bool
+runtime·stopg(G *gp)
+{
+	uint32 s;
+
+	for(;;) {
+		if(gp->gcworkdone)
+			return false;
+
+		s = runtime·readgstatus(gp);
+		switch(s) {
+		default:
+			dumpgstatus(gp);
+			runtime·throw("stopg: gp->atomicstatus is not valid");
+
+		case Gdead:
+			return false;
+
+		case Gcopystack:
+			// Loop until a new stack is in place.
+			break;
+
+		case Grunnable:
+		case Gsyscall:
+		case Gwaiting:
+			// Claim goroutine by setting scan bit.
+			if(!runtime·castogscanstatus(gp, s, s|Gscan))
+				break;
+			// In scan state, do work.
+			runtime·gcphasework(gp);
+			return true;
+
+		case Gscanrunnable:
+		case Gscanwaiting:
+		case Gscansyscall:
+			// Goroutine already claimed by another GC helper.
+			return false;
+
+		case Grunning:
+			// Claim goroutine, so we aren't racing with a status
+			// transition away from Grunning.
+			if(!runtime·castogscanstatus(gp, Grunning, Gscanrunning))
+				break;
+
+			// Mark gp for preemption.
+			if(!gp->gcworkdone) {
+				gp->preemptscan = true;
+				gp->preempt = true;
+				gp->stackguard0 = StackPreempt;
+			}
+
+			// Unclaim.
+			runtime·casfromgscanstatus(gp, Gscanrunning, Grunning);
+			return false;
+		}
+	}
+	// Should not be here....
+}
+
+// The GC requests that this routine be moved from a scanmumble state to a mumble state.
+void 
+runtime·restartg (G *gp)
+{
+	uint32 s;
+
+	s = runtime·readgstatus(gp);
+	switch(s) {
+	default:
+		dumpgstatus(gp); 
+		runtime·throw("restartg: unexpected status");
+
+	case Gdead:
+		break;
+
+	case Gscanrunnable:
+	case Gscanwaiting:
+	case Gscansyscall:
+		runtime·casfromgscanstatus(gp, s, s&~Gscan);
+		break;
+
+	case Gscanenqueue:
+		// Scan is now completed.
+		// Goroutine now needs to be made runnable.
+		// We put it on the global run queue; ready blocks on the global scheduler lock.
+		runtime·casfromgscanstatus(gp, Gscanenqueue, Gwaiting);
+		if(gp != g->m->curg)
+			runtime·throw("processing Gscanenqueue on wrong m");
+		dropg();
+		runtime·ready(gp);
+		break;
+	}
+}
+
+static void
+stopscanstart(G* gp)
+{
+	if(g == gp)
+		runtime·throw("GC not moved to G0");
+	if(runtime·stopg(gp)) {
+		if(!isscanstatus(runtime·readgstatus(gp))) {
+			dumpgstatus(gp);
+			runtime·throw("GC not in scan state");
+		}
+		runtime·restartg(gp);
+	}
+}
+
+// Runs on g0 and does the actual work after putting the g back on the run queue.
+static void
+mquiesce(G *gpmaster)
+{
+	G* gp;
+	uint32 i;
+	uint32 status;
+	uint32 activeglen;
+
+	activeglen = runtime·allglen;
+	// enqueue the calling goroutine.
+	runtime·restartg(gpmaster);
+	for(i = 0; i < activeglen; i++) {
+		gp = runtime·allg[i];
+		if(runtime·readgstatus(gp) == Gdead) 
+			gp->gcworkdone = true; // noop scan.
+		else 
+			gp->gcworkdone = false; 
+		stopscanstart(gp); 
+	}
+
+	// Check that the G's gcwork (such as scanning) has been done. If not do it now. 
+	// You can end up doing work here if the page trap on a Grunning Goroutine has
+	// not been sprung or in some race situations. For example a runnable goes dead
+	// and is started up again with a gp->gcworkdone set to false.
+	for(i = 0; i < activeglen; i++) {
+		gp = runtime·allg[i];
+		while (!gp->gcworkdone) {
+			status = runtime·readgstatus(gp);
+			if(status == Gdead) {
+				gp->gcworkdone = true; // scan is a noop
+				break;
+				//do nothing, scan not needed. 
+			}
+			if(status == Grunning && gp->stackguard0 == (uintptr)StackPreempt && runtime·notetsleep(&runtime·sched.stopnote, 100*1000)) // nanosecond arg 
+				runtime·noteclear(&runtime·sched.stopnote);
+			else 
+				stopscanstart(gp);
+		}
+	}
+
+	for(i = 0; i < activeglen; i++) {
+		gp = runtime·allg[i];
+		status = runtime·readgstatus(gp);
+		if(isscanstatus(status)) {
+			runtime·printf("mstopandscang:bottom: post scan bad status gp=%p has status %x\n", gp, status);
+			dumpgstatus(gp);
+		}
+		if(!gp->gcworkdone && status != Gdead) {
+			runtime·printf("mstopandscang:bottom: post scan gp=%p->gcworkdone still false\n", gp);
+			dumpgstatus(gp);
+		}
+	}
+
+	schedule(); // Never returns.
+}
+
+// quiesce moves all the goroutines to a GC safepoint which for now is a at preemption point.
+// If the global runtime·gcphase is GCmark quiesce will ensure that all of the goroutine's stacks
+// have been scanned before it returns.
+void
+runtime·quiesce(G* mastergp)
+{
+	void (*fn)(G*);
+
+	runtime·castogscanstatus(mastergp, Grunning, Gscanenqueue);
+	// Now move this to the g0 (aka m) stack.
+	// g0 will potentially scan this thread and put mastergp on the runqueue 
+	fn = mquiesce;
+	runtime·mcall(&fn);
+}
+
+// This is used by the GC as well as the routines that do stack dumps. In the case
+// of GC all the routines can be reliably stopped. This is not always the case
+// when the system is in panic or being exited.
+void
+runtime·stoptheworld(void)
+{
+	int32 i;
+	uint32 s;
+	P *p;
+	bool wait;
+
+	// If we hold a lock, then we won't be able to stop another M
+	// that is blocked trying to acquire the lock.
+	if(g->m->locks > 0)
+		runtime·throw("stoptheworld: holding locks");
+
+	runtime·lock(&runtime·sched.lock);
+	runtime·sched.stopwait = runtime·gomaxprocs;
+	runtime·atomicstore((uint32*)&runtime·sched.gcwaiting, 1);
+	preemptall();
+	// stop current P
+	g->m->p->status = Pgcstop; // Pgcstop is only diagnostic.
+	runtime·sched.stopwait--;
+	// try to retake all P's in Psyscall status
+	for(i = 0; i < runtime·gomaxprocs; i++) {
+		p = runtime·allp[i];
+		s = p->status;
+		if(s == Psyscall && runtime·cas(&p->status, s, Pgcstop))
+			runtime·sched.stopwait--;
+	}
+	// stop idle P's
+	while(p = pidleget()) {
+		p->status = Pgcstop;
+		runtime·sched.stopwait--;
+	}
+	wait = runtime·sched.stopwait > 0;
+	runtime·unlock(&runtime·sched.lock);
+
+	// wait for remaining P's to stop voluntarily
+	if(wait) {
+		for(;;) {
+			// wait for 100us, then try to re-preempt in case of any races
+			if(runtime·notetsleep(&runtime·sched.stopnote, 100*1000)) {
+				runtime·noteclear(&runtime·sched.stopnote);
+				break;
+			}
+			preemptall();
+		}
+	}
+	if(runtime·sched.stopwait)
+		runtime·throw("stoptheworld: not stopped");
+	for(i = 0; i < runtime·gomaxprocs; i++) {
+		p = runtime·allp[i];
+		if(p->status != Pgcstop)
+			runtime·throw("stoptheworld: not stopped");
+	}
+}
+
+static void
+mhelpgc(void)
+{
+	g->m->helpgc = -1;
+}
+
+void
+runtime·starttheworld(void)
+{
+	P *p, *p1;
+	M *mp;
+	G *gp;
+	bool add;
+
+	g->m->locks++;  // disable preemption because it can be holding p in a local var
+	gp = runtime·netpoll(false);  // non-blocking
+	injectglist(gp);
+	add = needaddgcproc();
+	runtime·lock(&runtime·sched.lock);
+	if(runtime·newprocs) {
+		procresize(runtime·newprocs);
+		runtime·newprocs = 0;
+	} else
+		procresize(runtime·gomaxprocs);
+	runtime·sched.gcwaiting = 0;
+
+	p1 = nil;
+	while(p = pidleget()) {
+		// procresize() puts p's with work at the beginning of the list.
+		// Once we reach a p without a run queue, the rest don't have one either.
+		if(p->runqhead == p->runqtail) {
+			pidleput(p);
+			break;
+		}
+		p->m = mget();
+		p->link = p1;
+		p1 = p;
+	}
+	if(runtime·sched.sysmonwait) {
+		runtime·sched.sysmonwait = false;
+		runtime·notewakeup(&runtime·sched.sysmonnote);
+	}
+	runtime·unlock(&runtime·sched.lock);
+
+	while(p1) {
+		p = p1;
+		p1 = p1->link;
+		if(p->m) {
+			mp = p->m;
+			p->m = nil;
+			if(mp->nextp)
+				runtime·throw("starttheworld: inconsistent mp->nextp");
+			mp->nextp = p;
+			runtime·notewakeup(&mp->park);
+		} else {
+			// Start M to run P.  Do not start another M below.
+			newm(nil, p);
+			add = false;
+		}
+	}
+
+	if(add) {
+		// If GC could have used another helper proc, start one now,
+		// in the hope that it will be available next time.
+		// It would have been even better to start it before the collection,
+		// but doing so requires allocating memory, so it's tricky to
+		// coordinate.  This lazy approach works out in practice:
+		// we don't mind if the first couple gc rounds don't have quite
+		// the maximum number of procs.
+		newm(mhelpgc, nil);
+	}
+	g->m->locks--;
+	if(g->m->locks == 0 && g->preempt)  // restore the preemption request in case we've cleared it in newstack
+		g->stackguard0 = StackPreempt;
+}
+
+static void mstart(void);
+
+// Called to start an M.
+#pragma textflag NOSPLIT
+void
+runtime·mstart(void)
+{
+	uintptr x, size;
+	
+	if(g->stack.lo == 0) {
+		// Initialize stack bounds from system stack.
+		// Cgo may have left stack size in stack.hi.
+		size = g->stack.hi;
+		if(size == 0)
+			size = 8192;
+		g->stack.hi = (uintptr)&x;
+		g->stack.lo = g->stack.hi - size + 1024;
+	}
+	
+	// Initialize stack guards so that we can start calling
+	// both Go and C functions with stack growth prologues.
+	g->stackguard0 = g->stack.lo + StackGuard;
+	g->stackguard1 = g->stackguard0;
+	mstart();
+}
+
+static void
+mstart(void)
+{
+	if(g != g->m->g0)
+		runtime·throw("bad runtime·mstart");
+
+	// Record top of stack for use by mcall.
+	// Once we call schedule we're never coming back,
+	// so other calls can reuse this stack space.
+	runtime·gosave(&g->m->g0->sched);
+	g->m->g0->sched.pc = (uintptr)-1;  // make sure it is never used
+	runtime·asminit();
+	runtime·minit();
+
+	// Install signal handlers; after minit so that minit can
+	// prepare the thread to be able to handle the signals.
+	if(g->m == &runtime·m0)
+		runtime·initsig();
+	
+	if(g->m->mstartfn)
+		g->m->mstartfn();
+
+	if(g->m->helpgc) {
+		g->m->helpgc = 0;
+		stopm();
+	} else if(g->m != &runtime·m0) {
+		acquirep(g->m->nextp);
+		g->m->nextp = nil;
+	}
+	schedule();
+
+	// TODO(brainman): This point is never reached, because scheduler
+	// does not release os threads at the moment. But once this path
+	// is enabled, we must remove our seh here.
+}
+
+// When running with cgo, we call _cgo_thread_start
+// to start threads for us so that we can play nicely with
+// foreign code.
+void (*_cgo_thread_start)(void*);
+
+typedef struct CgoThreadStart CgoThreadStart;
+struct CgoThreadStart
+{
+	G *g;
+	uintptr *tls;
+	void (*fn)(void);
+};
+
+M *runtime·newM(void); // in proc.go
+
+// Allocate a new m unassociated with any thread.
+// Can use p for allocation context if needed.
+M*
+runtime·allocm(P *p)
+{
+	M *mp;
+
+	g->m->locks++;  // disable GC because it can be called from sysmon
+	if(g->m->p == nil)
+		acquirep(p);  // temporarily borrow p for mallocs in this function
+	mp = runtime·newM();
+	mcommoninit(mp);
+
+	// In case of cgo or Solaris, pthread_create will make us a stack.
+	// Windows and Plan 9 will layout sched stack on OS stack.
+	if(runtime·iscgo || Solaris || Windows || Plan9)
+		mp->g0 = runtime·malg(-1);
+	else
+		mp->g0 = runtime·malg(8192);
+	mp->g0->m = mp;
+
+	if(p == g->m->p)
+		releasep();
+	g->m->locks--;
+	if(g->m->locks == 0 && g->preempt)  // restore the preemption request in case we've cleared it in newstack
+		g->stackguard0 = StackPreempt;
+
+	return mp;
+}
+
+G *runtime·newG(void); // in proc.go
+
+static G*
+allocg(void)
+{
+	return runtime·newG();
+}
+
+static M* lockextra(bool nilokay);
+static void unlockextra(M*);
+
+// needm is called when a cgo callback happens on a
+// thread without an m (a thread not created by Go).
+// In this case, needm is expected to find an m to use
+// and return with m, g initialized correctly.
+// Since m and g are not set now (likely nil, but see below)
+// needm is limited in what routines it can call. In particular
+// it can only call nosplit functions (textflag 7) and cannot
+// do any scheduling that requires an m.
+//
+// In order to avoid needing heavy lifting here, we adopt
+// the following strategy: there is a stack of available m's
+// that can be stolen. Using compare-and-swap
+// to pop from the stack has ABA races, so we simulate
+// a lock by doing an exchange (via casp) to steal the stack
+// head and replace the top pointer with MLOCKED (1).
+// This serves as a simple spin lock that we can use even
+// without an m. The thread that locks the stack in this way
+// unlocks the stack by storing a valid stack head pointer.
+//
+// In order to make sure that there is always an m structure
+// available to be stolen, we maintain the invariant that there
+// is always one more than needed. At the beginning of the
+// program (if cgo is in use) the list is seeded with a single m.
+// If needm finds that it has taken the last m off the list, its job
+// is - once it has installed its own m so that it can do things like
+// allocate memory - to create a spare m and put it on the list.
+//
+// Each of these extra m's also has a g0 and a curg that are
+// pressed into service as the scheduling stack and current
+// goroutine for the duration of the cgo callback.
+//
+// When the callback is done with the m, it calls dropm to
+// put the m back on the list.
+#pragma textflag NOSPLIT
+void
+runtime·needm(byte x)
+{
+	M *mp;
+
+	if(runtime·needextram) {
+		// Can happen if C/C++ code calls Go from a global ctor.
+		// Can not throw, because scheduler is not initialized yet.
+		runtime·write(2, "fatal error: cgo callback before cgo call\n",
+			sizeof("fatal error: cgo callback before cgo call\n")-1);
+		runtime·exit(1);
+	}
+
+	// Lock extra list, take head, unlock popped list.
+	// nilokay=false is safe here because of the invariant above,
+	// that the extra list always contains or will soon contain
+	// at least one m.
+	mp = lockextra(false);
+
+	// Set needextram when we've just emptied the list,
+	// so that the eventual call into cgocallbackg will
+	// allocate a new m for the extra list. We delay the
+	// allocation until then so that it can be done
+	// after exitsyscall makes sure it is okay to be
+	// running at all (that is, there's no garbage collection
+	// running right now).
+	mp->needextram = mp->schedlink == nil;
+	unlockextra(mp->schedlink);
+
+	// Install g (= m->g0) and set the stack bounds
+	// to match the current stack. We don't actually know
+	// how big the stack is, like we don't know how big any
+	// scheduling stack is, but we assume there's at least 32 kB,
+	// which is more than enough for us.
+	runtime·setg(mp->g0);
+	g->stack.hi = (uintptr)(&x + 1024);
+	g->stack.lo = (uintptr)(&x - 32*1024);
+	g->stackguard0 = g->stack.lo + StackGuard;
+
+	// Initialize this thread to use the m.
+	runtime·asminit();
+	runtime·minit();
+}
+
+// newextram allocates an m and puts it on the extra list.
+// It is called with a working local m, so that it can do things
+// like call schedlock and allocate.
+void
+runtime·newextram(void)
+{
+	M *mp, *mnext;
+	G *gp;
+
+	// Create extra goroutine locked to extra m.
+	// The goroutine is the context in which the cgo callback will run.
+	// The sched.pc will never be returned to, but setting it to
+	// runtime.goexit makes clear to the traceback routines where
+	// the goroutine stack ends.
+	mp = runtime·allocm(nil);
+	gp = runtime·malg(4096);
+	gp->sched.pc = (uintptr)runtime·goexit + PCQuantum;
+	gp->sched.sp = gp->stack.hi;
+	gp->sched.sp -= 4*sizeof(uintreg); // extra space in case of reads slightly beyond frame
+	gp->sched.lr = 0;
+	gp->sched.g = gp;
+	gp->syscallpc = gp->sched.pc;
+	gp->syscallsp = gp->sched.sp;
+	// malg returns status as Gidle, change to Gsyscall before adding to allg
+	// where GC will see it.
+	runtime·casgstatus(gp, Gidle, Gsyscall);
+	gp->m = mp;
+	mp->curg = gp;
+	mp->locked = LockInternal;
+	mp->lockedg = gp;
+	gp->lockedm = mp;
+	gp->goid = runtime·xadd64(&runtime·sched.goidgen, 1);
+	if(raceenabled)
+		gp->racectx = runtime·racegostart(runtime·newextram);
+	// put on allg for garbage collector
+	runtime·allgadd(gp);
+
+	// Add m to the extra list.
+	mnext = lockextra(true);
+	mp->schedlink = mnext;
+	unlockextra(mp);
+}
+
+// dropm is called when a cgo callback has called needm but is now
+// done with the callback and returning back into the non-Go thread.
+// It puts the current m back onto the extra list.
+//
+// The main expense here is the call to signalstack to release the
+// m's signal stack, and then the call to needm on the next callback
+// from this thread. It is tempting to try to save the m for next time,
+// which would eliminate both these costs, but there might not be
+// a next time: the current thread (which Go does not control) might exit.
+// If we saved the m for that thread, there would be an m leak each time
+// such a thread exited. Instead, we acquire and release an m on each
+// call. These should typically not be scheduling operations, just a few
+// atomics, so the cost should be small.
+//
+// TODO(rsc): An alternative would be to allocate a dummy pthread per-thread
+// variable using pthread_key_create. Unlike the pthread keys we already use
+// on OS X, this dummy key would never be read by Go code. It would exist
+// only so that we could register at thread-exit-time destructor.
+// That destructor would put the m back onto the extra list.
+// This is purely a performance optimization. The current version,
+// in which dropm happens on each cgo call, is still correct too.
+// We may have to keep the current version on systems with cgo
+// but without pthreads, like Windows.
+void
+runtime·dropm(void)
+{
+	M *mp, *mnext;
+
+	// Undo whatever initialization minit did during needm.
+	runtime·unminit();
+
+	// Clear m and g, and return m to the extra list.
+	// After the call to setmg we can only call nosplit functions.
+	mp = g->m;
+	runtime·setg(nil);
+
+	mnext = lockextra(true);
+	mp->schedlink = mnext;
+	unlockextra(mp);
+}
+
+#define MLOCKED ((M*)1)
+
+// lockextra locks the extra list and returns the list head.
+// The caller must unlock the list by storing a new list head
+// to runtime.extram. If nilokay is true, then lockextra will
+// return a nil list head if that's what it finds. If nilokay is false,
+// lockextra will keep waiting until the list head is no longer nil.
+#pragma textflag NOSPLIT
+static M*
+lockextra(bool nilokay)
+{
+	M *mp;
+	void (*yield)(void);
+
+	for(;;) {
+		mp = runtime·atomicloadp(&runtime·extram);
+		if(mp == MLOCKED) {
+			yield = runtime·osyield;
+			yield();
+			continue;
+		}
+		if(mp == nil && !nilokay) {
+			runtime·usleep(1);
+			continue;
+		}
+		if(!runtime·casp(&runtime·extram, mp, MLOCKED)) {
+			yield = runtime·osyield;
+			yield();
+			continue;
+		}
+		break;
+	}
+	return mp;
+}
+
+#pragma textflag NOSPLIT
+static void
+unlockextra(M *mp)
+{
+	runtime·atomicstorep(&runtime·extram, mp);
+}
+
+
+// Create a new m.  It will start off with a call to fn, or else the scheduler.
+static void
+newm(void(*fn)(void), P *p)
+{
+	M *mp;
+
+	mp = runtime·allocm(p);
+	mp->nextp = p;
+	mp->mstartfn = fn;
+
+	if(runtime·iscgo) {
+		CgoThreadStart ts;
+
+		if(_cgo_thread_start == nil)
+			runtime·throw("_cgo_thread_start missing");
+		ts.g = mp->g0;
+		ts.tls = mp->tls;
+		ts.fn = runtime·mstart;
+		runtime·asmcgocall(_cgo_thread_start, &ts);
+		return;
+	}
+	runtime·newosproc(mp, (byte*)mp->g0->stack.hi);
+}
+
+// Stops execution of the current m until new work is available.
+// Returns with acquired P.
+static void
+stopm(void)
+{
+	if(g->m->locks)
+		runtime·throw("stopm holding locks");
+	if(g->m->p)
+		runtime·throw("stopm holding p");
+	if(g->m->spinning) {
+		g->m->spinning = false;
+		runtime·xadd(&runtime·sched.nmspinning, -1);
+	}
+
+retry:
+	runtime·lock(&runtime·sched.lock);
+	mput(g->m);
+	runtime·unlock(&runtime·sched.lock);
+	runtime·notesleep(&g->m->park);
+	runtime·noteclear(&g->m->park);
+	if(g->m->helpgc) {
+		runtime·gchelper();
+		g->m->helpgc = 0;
+		g->m->mcache = nil;
+		goto retry;
+	}
+	acquirep(g->m->nextp);
+	g->m->nextp = nil;
+}
+
+static void
+mspinning(void)
+{
+	g->m->spinning = true;
+}
+
+// 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 does nothing.
+static void
+startm(P *p, bool spinning)
+{
+	M *mp;
+	void (*fn)(void);
+
+	runtime·lock(&runtime·sched.lock);
+	if(p == nil) {
+		p = pidleget();
+		if(p == nil) {
+			runtime·unlock(&runtime·sched.lock);
+			if(spinning)
+				runtime·xadd(&runtime·sched.nmspinning, -1);
+			return;
+		}
+	}
+	mp = mget();
+	runtime·unlock(&runtime·sched.lock);
+	if(mp == nil) {
+		fn = nil;
+		if(spinning)
+			fn = mspinning;
+		newm(fn, p);
+		return;
+	}
+	if(mp->spinning)
+		runtime·throw("startm: m is spinning");
+	if(mp->nextp)
+		runtime·throw("startm: m has p");
+	mp->spinning = spinning;
+	mp->nextp = p;
+	runtime·notewakeup(&mp->park);
+}
+
+// Hands off P from syscall or locked M.
+static void
+handoffp(P *p)
+{
+	// if it has local work, start it straight away
+	if(p->runqhead != p->runqtail || runtime·sched.runqsize) {
+		startm(p, false);
+		return;
+	}
+	// no local work, check that there are no spinning/idle M's,
+	// otherwise our help is not required
+	if(runtime·atomicload(&runtime·sched.nmspinning) + runtime·atomicload(&runtime·sched.npidle) == 0 &&  // TODO: fast atomic
+		runtime·cas(&runtime·sched.nmspinning, 0, 1)){
+		startm(p, true);
+		return;
+	}
+	runtime·lock(&runtime·sched.lock);
+	if(runtime·sched.gcwaiting) {
+		p->status = Pgcstop;
+		if(--runtime·sched.stopwait == 0)
+			runtime·notewakeup(&runtime·sched.stopnote);
+		runtime·unlock(&runtime·sched.lock);
+		return;
+	}
+	if(runtime·sched.runqsize) {
+		runtime·unlock(&runtime·sched.lock);
+		startm(p, false);
+		return;
+	}
+	// If this is the last running P and nobody is polling network,
+	// need to wakeup another M to poll network.
+	if(runtime·sched.npidle == runtime·gomaxprocs-1 && runtime·atomicload64(&runtime·sched.lastpoll) != 0) {
+		runtime·unlock(&runtime·sched.lock);
+		startm(p, false);
+		return;
+	}
+	pidleput(p);
+	runtime·unlock(&runtime·sched.lock);
+}
+
+// Tries to add one more P to execute G's.
+// Called when a G is made runnable (newproc, ready).
+static void
+wakep(void)
+{
+	// be conservative about spinning threads
+	if(!runtime·cas(&runtime·sched.nmspinning, 0, 1))
+		return;
+	startm(nil, true);
+}
+
+// Stops execution of the current m that is locked to a g until the g is runnable again.
+// Returns with acquired P.
+static void
+stoplockedm(void)
+{
+	P *p;
+	uint32 status;
+
+	if(g->m->lockedg == nil || g->m->lockedg->lockedm != g->m)
+		runtime·throw("stoplockedm: inconsistent locking");
+	if(g->m->p) {
+		// Schedule another M to run this p.
+		p = releasep();
+		handoffp(p);
+	}
+	incidlelocked(1);
+	// Wait until another thread schedules lockedg again.
+	runtime·notesleep(&g->m->park);
+	runtime·noteclear(&g->m->park);
+	status = runtime·readgstatus(g->m->lockedg);
+	if((status&~Gscan) != Grunnable){
+		runtime·printf("runtime:stoplockedm: g is not Grunnable or Gscanrunnable");
+		dumpgstatus(g);
+		runtime·throw("stoplockedm: not runnable");
+	}
+	acquirep(g->m->nextp);
+	g->m->nextp = nil;
+}
+
+// Schedules the locked m to run the locked gp.
+static void
+startlockedm(G *gp)
+{
+	M *mp;
+	P *p;
+
+	mp = gp->lockedm;
+	if(mp == g->m)
+		runtime·throw("startlockedm: locked to me");
+	if(mp->nextp)
+		runtime·throw("startlockedm: m has p");
+	// directly handoff current P to the locked m
+	incidlelocked(-1);
+	p = releasep();
+	mp->nextp = p;
+	runtime·notewakeup(&mp->park);
+	stopm();
+}
+
+// Stops the current m for stoptheworld.
+// Returns when the world is restarted.
+static void
+gcstopm(void)
+{
+	P *p;
+
+	if(!runtime·sched.gcwaiting)
+		runtime·throw("gcstopm: not waiting for gc");
+	if(g->m->spinning) {
+		g->m->spinning = false;
+		runtime·xadd(&runtime·sched.nmspinning, -1);
+	}
+	p = releasep();
+	runtime·lock(&runtime·sched.lock);
+	p->status = Pgcstop;
+	if(--runtime·sched.stopwait == 0)
+		runtime·notewakeup(&runtime·sched.stopnote);
+	runtime·unlock(&runtime·sched.lock);
+	stopm();
+}
+
+// Schedules gp to run on the current M.
+// Never returns.
+static void
+execute(G *gp)
+{
+	int32 hz;
+	
+	runtime·casgstatus(gp, Grunnable, Grunning);
+	gp->waitsince = 0;
+	gp->preempt = false;
+	gp->stackguard0 = gp->stack.lo + StackGuard;
+	g->m->p->schedtick++;
+	g->m->curg = gp;
+	gp->m = g->m;
+
+	// Check whether the profiler needs to be turned on or off.
+	hz = runtime·sched.profilehz;
+	if(g->m->profilehz != hz)
+		runtime·resetcpuprofiler(hz);
+
+	runtime·gogo(&gp->sched);
+}
+
+// Finds a runnable goroutine to execute.
+// Tries to steal from other P's, get g from global queue, poll network.
+static G*
+findrunnable(void)
+{
+	G *gp;
+	P *p;
+	int32 i;
+
+top:
+	if(runtime·sched.gcwaiting) {
+		gcstopm();
+		goto top;
+	}
+	if(runtime·fingwait && runtime·fingwake && (gp = runtime·wakefing()) != nil)
+		runtime·ready(gp);
+	// local runq
+	gp = runqget(g->m->p);
+	if(gp)
+		return gp;
+	// global runq
+	if(runtime·sched.runqsize) {
+		runtime·lock(&runtime·sched.lock);
+		gp = globrunqget(g->m->p, 0);
+		runtime·unlock(&runtime·sched.lock);
+		if(gp)
+			return gp;
+	}
+	// poll network
+	gp = runtime·netpoll(false);  // non-blocking
+	if(gp) {
+		injectglist(gp->schedlink);
+		runtime·casgstatus(gp, Gwaiting, Grunnable);
+		return gp;
+	}
+	// If number of spinning M's >= number of busy P's, block.
+	// This is necessary to prevent excessive CPU consumption
+	// when GOMAXPROCS>>1 but the program parallelism is low.
+	if(!g->m->spinning && 2 * runtime·atomicload(&runtime·sched.nmspinning) >= runtime·gomaxprocs - runtime·atomicload(&runtime·sched.npidle))  // TODO: fast atomic
+		goto stop;
+	if(!g->m->spinning) {
+		g->m->spinning = true;
+		runtime·xadd(&runtime·sched.nmspinning, 1);
+	}
+	// random steal from other P's
+	for(i = 0; i < 2*runtime·gomaxprocs; i++) {
+		if(runtime·sched.gcwaiting)
+			goto top;
+		p = runtime·allp[runtime·fastrand1()%runtime·gomaxprocs];
+		if(p == g->m->p)
+			gp = runqget(p);
+		else
+			gp = runqsteal(g->m->p, p);
+		if(gp)
+			return gp;
+	}
+stop:
+	// return P and block
+	runtime·lock(&runtime·sched.lock);
+	if(runtime·sched.gcwaiting) {
+		runtime·unlock(&runtime·sched.lock);
+		goto top;
+	}
+	if(runtime·sched.runqsize) {
+		gp = globrunqget(g->m->p, 0);
+		runtime·unlock(&runtime·sched.lock);
+		return gp;
+	}
+	p = releasep();
+	pidleput(p);
+	runtime·unlock(&runtime·sched.lock);
+	if(g->m->spinning) {
+		g->m->spinning = false;
+		runtime·xadd(&runtime·sched.nmspinning, -1);
+	}
+	// check all runqueues once again
+	for(i = 0; i < runtime·gomaxprocs; i++) {
+		p = runtime·allp[i];
+		if(p && p->runqhead != p->runqtail) {
+			runtime·lock(&runtime·sched.lock);
+			p = pidleget();
+			runtime·unlock(&runtime·sched.lock);
+			if(p) {
+				acquirep(p);
+				goto top;
+			}
+			break;
+		}
+	}
+	// poll network
+	if(runtime·xchg64(&runtime·sched.lastpoll, 0) != 0) {
+		if(g->m->p)
+			runtime·throw("findrunnable: netpoll with p");
+		if(g->m->spinning)
+			runtime·throw("findrunnable: netpoll with spinning");
+		gp = runtime·netpoll(true);  // block until new work is available
+		runtime·atomicstore64(&runtime·sched.lastpoll, runtime·nanotime());
+		if(gp) {
+			runtime·lock(&runtime·sched.lock);
+			p = pidleget();
+			runtime·unlock(&runtime·sched.lock);
+			if(p) {
+				acquirep(p);
+				injectglist(gp->schedlink);
+				runtime·casgstatus(gp, Gwaiting, Grunnable);
+				return gp;
+			}
+			injectglist(gp);
+		}
+	}
+	stopm();
+	goto top;
+}
+
+static void
+resetspinning(void)
+{
+	int32 nmspinning;
+
+	if(g->m->spinning) {
+		g->m->spinning = false;
+		nmspinning = runtime·xadd(&runtime·sched.nmspinning, -1);
+		if(nmspinning < 0)
+			runtime·throw("findrunnable: negative nmspinning");
+	} else
+		nmspinning = runtime·atomicload(&runtime·sched.nmspinning);
+
+	// M wakeup policy is deliberately somewhat conservative (see nmspinning handling),
+	// so see if we need to wakeup another P here.
+	if (nmspinning == 0 && runtime·atomicload(&runtime·sched.npidle) > 0)
+		wakep();
+}
+
+// Injects the list of runnable G's into the scheduler.
+// Can run concurrently with GC.
+static void
+injectglist(G *glist)
+{
+	int32 n;
+	G *gp;
+
+	if(glist == nil)
+		return;
+	runtime·lock(&runtime·sched.lock);
+	for(n = 0; glist; n++) {
+		gp = glist;
+		glist = gp->schedlink;
+		runtime·casgstatus(gp, Gwaiting, Grunnable); 
+		globrunqput(gp);
+	}
+	runtime·unlock(&runtime·sched.lock);
+
+	for(; n && runtime·sched.npidle; n--)
+		startm(nil, false);
+}
+
+// One round of scheduler: find a runnable goroutine and execute it.
+// Never returns.
+static void
+schedule(void)
+{
+	G *gp;
+	uint32 tick;
+
+	if(g->m->locks)
+		runtime·throw("schedule: holding locks");
+
+	if(g->m->lockedg) {
+		stoplockedm();
+		execute(g->m->lockedg);  // Never returns.
+	}
+
+top:
+	if(runtime·sched.gcwaiting) {
+		gcstopm();
+		goto top;
+	}
+
+	gp = nil;
+	// Check the global runnable queue once in a while to ensure fairness.
+	// Otherwise two goroutines can completely occupy the local runqueue
+	// by constantly respawning each other.
+	tick = g->m->p->schedtick;
+	// This is a fancy way to say tick%61==0,
+	// it uses 2 MUL instructions instead of a single DIV and so is faster on modern processors.
+	if(tick - (((uint64)tick*0x4325c53fu)>>36)*61 == 0 && runtime·sched.runqsize > 0) {
+		runtime·lock(&runtime·sched.lock);
+		gp = globrunqget(g->m->p, 1);
+		runtime·unlock(&runtime·sched.lock);
+		if(gp)
+			resetspinning();
+	}
+	if(gp == nil) {
+		gp = runqget(g->m->p);
+		if(gp && g->m->spinning)
+			runtime·throw("schedule: spinning with local work");
+	}
+	if(gp == nil) {
+		gp = findrunnable();  // blocks until work is available
+		resetspinning();
+	}
+
+	if(gp->lockedm) {
+		// Hands off own p to the locked m,
+		// then blocks waiting for a new p.
+		startlockedm(gp);
+		goto top;
+	}
+
+	execute(gp);
+}
+
+// dropg removes the association between m and the current goroutine m->curg (gp for short).
+// Typically a caller sets gp's status away from Grunning and then
+// immediately calls dropg to finish the job. The caller is also responsible
+// for arranging that gp will be restarted using runtime·ready at an
+// appropriate time. After calling dropg and arranging for gp to be
+// readied later, the caller can do other work but eventually should
+// call schedule to restart the scheduling of goroutines on this m.
+static void
+dropg(void)
+{
+	if(g->m->lockedg == nil) {
+		g->m->curg->m = nil;
+		g->m->curg = nil;
+	}
+}
+
+// Puts the current goroutine into a waiting state and calls unlockf.
+// If unlockf returns false, the goroutine is resumed.
+void
+runtime·park(bool(*unlockf)(G*, void*), void *lock, String reason)
+{
+	void (*fn)(G*);
+
+	g->m->waitlock = lock;
+	g->m->waitunlockf = unlockf;
+	g->waitreason = reason;
+	fn = runtime·park_m;
+	runtime·mcall(&fn);
+}
+
+bool
+runtime·parkunlock_c(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(Mutex *lock, String reason)
+{
+	runtime·park(runtime·parkunlock_c, lock, reason);
+}
+
+// runtime·park continuation on g0.
+void
+runtime·park_m(G *gp)
+{
+	bool ok;
+
+	runtime·casgstatus(gp, Grunning, Gwaiting);
+	dropg();
+
+	if(g->m->waitunlockf) {
+		ok = g->m->waitunlockf(gp, g->m->waitlock);
+		g->m->waitunlockf = nil;
+		g->m->waitlock = nil;
+		if(!ok) {
+			runtime·casgstatus(gp, Gwaiting, Grunnable); 
+			execute(gp);  // Schedule it back, never returns.
+		}
+	}
+
+	schedule();
+}
+
+// Gosched continuation on g0.
+void
+runtime·gosched_m(G *gp)
+{
+	uint32 status;
+
+	status = runtime·readgstatus(gp);
+	if((status&~Gscan) != Grunning){
+		dumpgstatus(gp);
+		runtime·throw("bad g status");
+	}
+	runtime·casgstatus(gp, Grunning, Grunnable);
+	dropg();
+	runtime·lock(&runtime·sched.lock);
+	globrunqput(gp);
+	runtime·unlock(&runtime·sched.lock);
+
+	schedule();
+}
+
+// Finishes execution of the current goroutine.
+// Must be NOSPLIT because it is called from Go.
+#pragma textflag NOSPLIT
+void
+runtime·goexit1(void)
+{
+	void (*fn)(G*);
+
+	if(raceenabled)
+		runtime·racegoend();
+	fn = goexit0;
+	runtime·mcall(&fn);
+}
+
+// runtime·goexit continuation on g0.
+static void
+goexit0(G *gp)
+{
+	runtime·casgstatus(gp, Grunning, Gdead);
+	gp->m = nil;
+	gp->lockedm = nil;
+	g->m->lockedg = 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->writebuf.array = nil;
+	gp->writebuf.len = 0;
+	gp->writebuf.cap = 0;
+	gp->waitreason.str = nil;
+	gp->waitreason.len = 0;
+	gp->param = nil;
+
+	dropg();
+
+	if(g->m->locked & ~LockExternal) {
+		runtime·printf("invalid m->locked = %d\n", g->m->locked);
+		runtime·throw("internal lockOSThread error");
+	}	
+	g->m->locked = 0;
+	gfput(g->m->p, gp);
+	schedule();
+}
+
+#pragma textflag NOSPLIT
+static void
+save(uintptr pc, uintptr sp)
+{
+	g->sched.pc = pc;
+	g->sched.sp = sp;
+	g->sched.lr = 0;
+	g->sched.ret = 0;
+	g->sched.ctxt = 0;
+	g->sched.g = g;
+}
+
+static void entersyscall_bad(void);
+static void entersyscall_sysmon(void);
+static void entersyscall_gcwait(void);
+
+// The goroutine g is about to enter a system call.
+// Record that it's not using the cpu anymore.
+// This is called only from the go syscall library and cgocall,
+// not from the low-level system calls used by the runtime.
+//
+// Entersyscall cannot split the stack: the runtime·gosave must
+// make g->sched refer to the caller's stack segment, because
+// entersyscall is going to return immediately after.
+//
+// Nothing entersyscall calls can split the stack either.
+// We cannot safely move the stack during an active call to syscall,
+// because we do not know which of the uintptr arguments are
+// really pointers (back into the stack).
+// In practice, this means that we make the fast path run through
+// entersyscall doing no-split things, and the slow path has to use onM
+// to run bigger things on the m stack.
+//
+// reentersyscall is the entry point used by cgo callbacks, where explicitly
+// saved SP and PC are restored. This is needed when exitsyscall will be called
+// from a function further up in the call stack than the parent, as g->syscallsp
+// must always point to a valid stack frame. entersyscall below is the normal
+// entry point for syscalls, which obtains the SP and PC from the caller.
+#pragma textflag NOSPLIT
+void
+runtime·reentersyscall(uintptr pc, uintptr sp)
+{
+	void (*fn)(void);
+
+	// Disable preemption because during this function g is in Gsyscall status,
+	// but can have inconsistent g->sched, do not let GC observe it.
+	g->m->locks++;
+	
+	// Entersyscall must not call any function that might split/grow the stack.
+	// (See details in comment above.)
+	// Catch calls that might, by replacing the stack guard with something that
+	// will trip any stack check and leaving a flag to tell newstack to die.
+	g->stackguard0 = StackPreempt;
+	g->throwsplit = 1;
+
+	// Leave SP around for GC and traceback.
+	save(pc, sp);
+	g->syscallsp = sp;
+	g->syscallpc = pc;
+	runtime·casgstatus(g, Grunning, Gsyscall);
+	if(g->syscallsp < g->stack.lo || g->stack.hi < g->syscallsp) {
+		fn = entersyscall_bad;
+		runtime·onM(&fn);
+	}
+
+	if(runtime·atomicload(&runtime·sched.sysmonwait)) {  // TODO: fast atomic
+		fn = entersyscall_sysmon;
+		runtime·onM(&fn);
+		save(pc, sp);
+	}
+
+	g->m->mcache = nil;
+	g->m->p->m = nil;
+	runtime·atomicstore(&g->m->p->status, Psyscall);
+	if(runtime·sched.gcwaiting) {
+		fn = entersyscall_gcwait;
+		runtime·onM(&fn);
+		save(pc, sp);
+	}
+
+	// Goroutines must not split stacks in Gsyscall status (it would corrupt g->sched).
+	// We set stackguard to StackPreempt so that first split stack check calls morestack.
+	// Morestack detects this case and throws.
+	g->stackguard0 = StackPreempt;
+	g->m->locks--;
+}
+
+// Standard syscall entry used by the go syscall library and normal cgo calls.
+#pragma textflag NOSPLIT
+void
+·entersyscall(int32 dummy)
+{
+	runtime·reentersyscall((uintptr)runtime·getcallerpc(&dummy), runtime·getcallersp(&dummy));
+}
+
+static void
+entersyscall_bad(void)
+{
+	G *gp;
+	
+	gp = g->m->curg;
+	runtime·printf("entersyscall inconsistent %p [%p,%p]\n",
+		gp->syscallsp, gp->stack.lo, gp->stack.hi);
+	runtime·throw("entersyscall");
+}
+
+static void
+entersyscall_sysmon(void)
+{
+	runtime·lock(&runtime·sched.lock);
+	if(runtime·atomicload(&runtime·sched.sysmonwait)) {
+		runtime·atomicstore(&runtime·sched.sysmonwait, 0);
+		runtime·notewakeup(&runtime·sched.sysmonnote);
+	}
+	runtime·unlock(&runtime·sched.lock);
+}
+
+static void
+entersyscall_gcwait(void)
+{
+	runtime·lock(&runtime·sched.lock);
+	if (runtime·sched.stopwait > 0 && runtime·cas(&g->m->p->status, Psyscall, Pgcstop)) {
+		if(--runtime·sched.stopwait == 0)
+			runtime·notewakeup(&runtime·sched.stopnote);
+	}
+	runtime·unlock(&runtime·sched.lock);
+}
+
+static void entersyscallblock_handoff(void);
+
+// The same as runtime·entersyscall(), but with a hint that the syscall is blocking.
+#pragma textflag NOSPLIT
+void
+·entersyscallblock(int32 dummy)
+{
+	void (*fn)(void);
+
+	g->m->locks++;  // see comment in entersyscall
+	g->throwsplit = 1;
+	g->stackguard0 = StackPreempt;  // see comment in entersyscall
+
+	// Leave SP around for GC and traceback.
+	save((uintptr)runtime·getcallerpc(&dummy), runtime·getcallersp(&dummy));
+	g->syscallsp = g->sched.sp;
+	g->syscallpc = g->sched.pc;
+	runtime·casgstatus(g, Grunning, Gsyscall);
+	if(g->syscallsp < g->stack.lo || g->stack.hi < g->syscallsp) {
+		fn = entersyscall_bad;
+		runtime·onM(&fn);
+	}
+	
+	fn = entersyscallblock_handoff;
+	runtime·onM(&fn);
+
+	// Resave for traceback during blocked call.
+	save((uintptr)runtime·getcallerpc(&dummy), runtime·getcallersp(&dummy));
+
+	g->m->locks--;
+}
+
+static void
+entersyscallblock_handoff(void)
+{
+	handoffp(releasep());
+}
+
+// The goroutine g exited its system call.
+// Arrange for it to run on a cpu again.
+// This is called only from the go syscall library, not
+// from the low-level system calls used by the runtime.
+#pragma textflag NOSPLIT
+void
+·exitsyscall(int32 dummy)
+{
+	void (*fn)(G*);
+
+	g->m->locks++;  // see comment in entersyscall
+
+	if(runtime·getcallersp(&dummy) > g->syscallsp)
+		runtime·throw("exitsyscall: syscall frame is no longer valid");
+
+	g->waitsince = 0;
+	if(exitsyscallfast()) {
+		// There's a cpu for us, so we can run.
+		g->m->p->syscalltick++;
+		// We need to cas the status and scan before resuming...
+		runtime·casgstatus(g, Gsyscall, Grunning);
+
+		// Garbage collector isn't running (since we are),
+		// so okay to clear syscallsp.
+		g->syscallsp = (uintptr)nil;
+		g->m->locks--;
+		if(g->preempt) {
+			// restore the preemption request in case we've cleared it in newstack
+			g->stackguard0 = StackPreempt;
+		} else {
+			// otherwise restore the real stackguard, we've spoiled it in entersyscall/entersyscallblock
+			g->stackguard0 = g->stack.lo + StackGuard;
+		}
+		g->throwsplit = 0;
+		return;
+	}
+
+	g->m->locks--;
+
+	// Call the scheduler.
+	fn = exitsyscall0;
+	runtime·mcall(&fn);
+
+	// Scheduler returned, so we're allowed to run now.
+	// Delete the syscallsp information that we left for
+	// the garbage collector during the system call.
+	// Must wait until now because until gosched returns
+	// we don't know for sure that the garbage collector
+	// is not running.
+	g->syscallsp = (uintptr)nil;
+	g->m->p->syscalltick++;
+	g->throwsplit = 0;
+}
+
+static void exitsyscallfast_pidle(void);
+
+#pragma textflag NOSPLIT
+static bool
+exitsyscallfast(void)
+{
+	void (*fn)(void);
+
+	// Freezetheworld sets stopwait but does not retake P's.
+	if(runtime·sched.stopwait) {
+		g->m->p = nil;
+		return false;
+	}
+
+	// Try to re-acquire the last P.
+	if(g->m->p && g->m->p->status == Psyscall && runtime·cas(&g->m->p->status, Psyscall, Prunning)) {
+		// There's a cpu for us, so we can run.
+		g->m->mcache = g->m->p->mcache;
+		g->m->p->m = g->m;
+		return true;
+	}
+	// Try to get any other idle P.
+	g->m->p = nil;
+	if(runtime·sched.pidle) {
+		fn = exitsyscallfast_pidle;
+		runtime·onM(&fn);
+		if(g->m->scalararg[0]) {
+			g->m->scalararg[0] = 0;
+			return true;
+		}
+	}
+	return false;
+}
+
+static void
+exitsyscallfast_pidle(void)
+{
+	P *p;
+
+	runtime·lock(&runtime·sched.lock);
+	p = pidleget();
+	if(p && runtime·atomicload(&runtime·sched.sysmonwait)) {
+		runtime·atomicstore(&runtime·sched.sysmonwait, 0);
+		runtime·notewakeup(&runtime·sched.sysmonnote);
+	}
+	runtime·unlock(&runtime·sched.lock);
+	if(p) {
+		acquirep(p);
+		g->m->scalararg[0] = 1;
+	} else
+		g->m->scalararg[0] = 0;
+}
+
+// runtime·exitsyscall slow path on g0.
+// Failed to acquire P, enqueue gp as runnable.
+static void
+exitsyscall0(G *gp)
+{
+	P *p;
+
+	runtime·casgstatus(gp, Gsyscall, Grunnable);
+	dropg();
+	runtime·lock(&runtime·sched.lock);
+	p = pidleget();
+	if(p == nil)
+		globrunqput(gp);
+	else if(runtime·atomicload(&runtime·sched.sysmonwait)) {
+		runtime·atomicstore(&runtime·sched.sysmonwait, 0);
+		runtime·notewakeup(&runtime·sched.sysmonnote);
+	}
+	runtime·unlock(&runtime·sched.lock);
+	if(p) {
+		acquirep(p);
+		execute(gp);  // Never returns.
+	}
+	if(g->m->lockedg) {
+		// Wait until another thread schedules gp and so m again.
+		stoplockedm();
+		execute(gp);  // Never returns.
+	}
+	stopm();
+	schedule();  // Never returns.
+}
+
+static void
+beforefork(void)
+{
+	G *gp;
+	
+	gp = g->m->curg;
+	// Fork can hang if preempted with signals frequently enough (see issue 5517).
+	// Ensure that we stay on the same M where we disable profiling.
+	gp->m->locks++;
+	if(gp->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.
+	gp->stackguard0 = StackFork;
+}
+
+// Called from syscall package before fork.
+#pragma textflag NOSPLIT
+void
+syscall·runtime_BeforeFork(void)
+{
+	void (*fn)(void);
+	
+	fn = beforefork;
+	runtime·onM(&fn);
+}
+
+static void
+afterfork(void)
+{
+	int32 hz;
+	G *gp;
+	
+	gp = g->m->curg;
+	// See the comment in runtime_BeforeFork.
+	gp->stackguard0 = gp->stack.lo + StackGuard;
+
+	hz = runtime·sched.profilehz;
+	if(hz != 0)
+		runtime·resetcpuprofiler(hz);
+	gp->m->locks--;
+}
+
+// Called from syscall package after fork in parent.
+#pragma textflag NOSPLIT
+void
+syscall·runtime_AfterFork(void)
+{
+	void (*fn)(void);
+	
+	fn = afterfork;
+	runtime·onM(&fn);
+}
+
+// Hook used by runtime·malg to call runtime·stackalloc on the
+// scheduler stack.  This exists because runtime·stackalloc insists
+// on being called on the scheduler stack, to avoid trying to grow
+// the stack while allocating a new stack segment.
+static void
+mstackalloc(G *gp)
+{
+	G *newg;
+	uintptr size;
+
+	newg = g->m->ptrarg[0];
+	size = g->m->scalararg[0];
+
+	newg->stack = runtime·stackalloc(size);
+
+	runtime·gogo(&gp->sched);
+}
+
+// Allocate a new g, with a stack big enough for stacksize bytes.
+G*
+runtime·malg(int32 stacksize)
+{
+	G *newg;
+	void (*fn)(G*);
+
+	newg = allocg();
+	if(stacksize >= 0) {
+		stacksize = runtime·round2(StackSystem + stacksize);
+		if(g == g->m->g0) {
+			// running on scheduler stack already.
+			newg->stack = runtime·stackalloc(stacksize);
+		} else {
+			// have to call stackalloc on scheduler stack.
+			g->m->scalararg[0] = stacksize;
+			g->m->ptrarg[0] = newg;
+			fn = mstackalloc;
+			runtime·mcall(&fn);
+			g->m->ptrarg[0] = nil;
+		}
+		newg->stackguard0 = newg->stack.lo + StackGuard;
+		newg->stackguard1 = ~(uintptr)0;
+	}
+	return newg;
+}
+
+static void
+newproc_m(void)
+{
+	byte *argp;
+	void *callerpc;
+	FuncVal *fn;
+	int32 siz;
+
+	siz = g->m->scalararg[0];
+	callerpc = (void*)g->m->scalararg[1];	
+	argp = g->m->ptrarg[0];
+	fn = (FuncVal*)g->m->ptrarg[1];
+
+	runtime·newproc1(fn, argp, siz, 0, callerpc);
+	g->m->ptrarg[0] = nil;
+	g->m->ptrarg[1] = nil;
+}
+
+// Create a new g running fn with siz bytes of arguments.
+// Put it on the queue of g's waiting to run.
+// The compiler turns a go statement into a call to this.
+// Cannot split the stack because it assumes that the arguments
+// are available sequentially after &fn; they would not be
+// copied if a stack split occurred.
+#pragma textflag NOSPLIT
+void
+runtime·newproc(int32 siz, FuncVal* fn, ...)
+{
+	byte *argp;
+	void (*mfn)(void);
+
+	if(thechar == '5')
+		argp = (byte*)(&fn+2);  // skip caller's saved LR
+	else
+		argp = (byte*)(&fn+1);
+
+	g->m->locks++;
+	g->m->scalararg[0] = siz;
+	g->m->scalararg[1] = (uintptr)runtime·getcallerpc(&siz);
+	g->m->ptrarg[0] = argp;
+	g->m->ptrarg[1] = fn;
+	mfn = newproc_m;
+	runtime·onM(&mfn);
+	g->m->locks--;
+}
+
+void runtime·main(void);
+
+// Create a new g running fn with narg bytes of arguments starting
+// at argp and returning nret bytes of results.  callerpc is the
+// address of the go statement that created this.  The new g is put
+// on the queue of g's waiting to run.
+G*
+runtime·newproc1(FuncVal *fn, byte *argp, int32 narg, int32 nret, void *callerpc)
+{
+	byte *sp;
+	G *newg;
+	P *p;
+	int32 siz;
+
+	if(fn == nil) {
+		g->m->throwing = -1;  // do not dump full stacks
+		runtime·throw("go of nil func value");
+	}
+	g->m->locks++;  // disable preemption because it can be holding p in a local var
+	siz = narg + nret;
+	siz = (siz+7) & ~7;
+
+	// We could allocate a larger initial stack if necessary.
+	// Not worth it: this is almost always an error.
+	// 4*sizeof(uintreg): extra space added below
+	// sizeof(uintreg): caller's LR (arm) or return address (x86, in gostartcall).
+	if(siz >= StackMin - 4*sizeof(uintreg) - sizeof(uintreg))
+		runtime·throw("runtime.newproc: function arguments too large for new goroutine");
+
+	p = g->m->p;
+	if((newg = gfget(p)) == nil) {
+		newg = runtime·malg(StackMin);
+		runtime·casgstatus(newg, Gidle, Gdead);
+		runtime·allgadd(newg); // publishes with a g->status of Gdead so GC scanner doesn't look at uninitialized stack.
+	}
+	if(newg->stack.hi == 0)
+		runtime·throw("newproc1: newg missing stack");
+
+	if(runtime·readgstatus(newg) != Gdead) 
+		runtime·throw("newproc1: new g is not Gdead");
+
+	sp = (byte*)newg->stack.hi;
+	sp -= 4*sizeof(uintreg); // extra space in case of reads slightly beyond frame
+	sp -= siz;
+	runtime·memmove(sp, argp, narg);
+	if(thechar == '5') {
+		// caller's LR
+		sp -= sizeof(void*);
+		*(void**)sp = nil;
+	}
+
+	runtime·memclr((byte*)&newg->sched, sizeof newg->sched);
+	newg->sched.sp = (uintptr)sp;
+	newg->sched.pc = (uintptr)runtime·goexit + PCQuantum; // +PCQuantum so that previous instruction is in same function
+	newg->sched.g = newg;
+	runtime·gostartcallfn(&newg->sched, fn);
+	newg->gopc = (uintptr)callerpc;
+	runtime·casgstatus(newg, Gdead, Grunnable);
+
+	if(p->goidcache == p->goidcacheend) {
+		// Sched.goidgen is the last allocated id,
+		// this batch must be [sched.goidgen+1, sched.goidgen+GoidCacheBatch].
+		// At startup sched.goidgen=0, so main goroutine receives goid=1.
+		p->goidcache = runtime·xadd64(&runtime·sched.goidgen, GoidCacheBatch);
+		p->goidcache -= GoidCacheBatch - 1;
+		p->goidcacheend = p->goidcache + GoidCacheBatch;
+	}
+	newg->goid = p->goidcache++;
+	if(raceenabled)
+		newg->racectx = runtime·racegostart((void*)callerpc);
+	runqput(p, newg);
+
+	if(runtime·atomicload(&runtime·sched.npidle) != 0 && runtime·atomicload(&runtime·sched.nmspinning) == 0 && fn->fn != runtime·main)  // TODO: fast atomic
+		wakep();
+	g->m->locks--;
+	if(g->m->locks == 0 && g->preempt)  // restore the preemption request in case we've cleared it in newstack
+		g->stackguard0 = StackPreempt;
+	return newg;
+}
+
+// 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;
+
+	if(runtime·readgstatus(gp) != Gdead) 
+		runtime·throw("gfput: bad status (not Gdead)");
+
+	stksize = gp->stack.hi - gp->stack.lo;
+	
+	if(stksize != FixedStack) {
+		// non-standard stack size - free it.
+		runtime·stackfree(gp->stack);
+		gp->stack.lo = 0;
+		gp->stack.hi = 0;
+		gp->stackguard0 = 0;
+	}
+	gp->schedlink = p->gfree;
+	p->gfree = gp;
+	p->gfreecnt++;
+	if(p->gfreecnt >= 64) {
+		runtime·lock(&runtime·sched.gflock);
+		while(p->gfreecnt >= 32) {
+			p->gfreecnt--;
+			gp = p->gfree;
+			p->gfree = gp->schedlink;
+			gp->schedlink = runtime·sched.gfree;
+			runtime·sched.gfree = gp;
+			runtime·sched.ngfree++;
+		}
+		runtime·unlock(&runtime·sched.gflock);
+	}
+}
+
+// Get from gfree list.
+// If local list is empty, grab a batch from global list.
+static G*
+gfget(P *p)
+{
+	G *gp;
+	void (*fn)(G*);
+
+retry:
+	gp = p->gfree;
+	if(gp == nil && runtime·sched.gfree) {
+		runtime·lock(&runtime·sched.gflock);
+		while(p->gfreecnt < 32 && runtime·sched.gfree != nil) {
+			p->gfreecnt++;
+			gp = runtime·sched.gfree;
+			runtime·sched.gfree = gp->schedlink;
+			runtime·sched.ngfree--;
+			gp->schedlink = p->gfree;
+			p->gfree = gp;
+		}
+		runtime·unlock(&runtime·sched.gflock);
+		goto retry;
+	}
+	if(gp) {
+		p->gfree = gp->schedlink;
+		p->gfreecnt--;
+
+		if(gp->stack.lo == 0) {
+			// Stack was deallocated in gfput.  Allocate a new one.
+			if(g == g->m->g0) {
+				gp->stack = runtime·stackalloc(FixedStack);
+			} else {
+				g->m->scalararg[0] = FixedStack;
+				g->m->ptrarg[0] = gp;
+				fn = mstackalloc;
+				runtime·mcall(&fn);
+				g->m->ptrarg[0] = nil;
+			}
+			gp->stackguard0 = gp->stack.lo + StackGuard;
+		} else {
+			if(raceenabled)
+				runtime·racemalloc((void*)gp->stack.lo, gp->stack.hi - gp->stack.lo);
+		}
+	}
+	return gp;
+}
+
+// Purge all cached G's from gfree list to the global list.
+static void
+gfpurge(P *p)
+{
+	G *gp;
+
+	runtime·lock(&runtime·sched.gflock);
+	while(p->gfreecnt != 0) {
+		p->gfreecnt--;
+		gp = p->gfree;
+		p->gfree = gp->schedlink;
+		gp->schedlink = runtime·sched.gfree;
+		runtime·sched.gfree = gp;
+		runtime·sched.ngfree++;
+	}
+	runtime·unlock(&runtime·sched.gflock);
+}
+
+#pragma textflag NOSPLIT
+void
+runtime·Breakpoint(void)
+{
+	runtime·breakpoint();
+}
+
+// lockOSThread is called by runtime.LockOSThread and runtime.lockOSThread below
+// after they modify m->locked. Do not allow preemption during this call,
+// or else the m might be different in this function than in the caller.
+#pragma textflag NOSPLIT
+static void
+lockOSThread(void)
+{
+	g->m->lockedg = g;
+	g->lockedm = g->m;
+}
+
+#pragma textflag NOSPLIT
+void
+runtime·LockOSThread(void)
+{
+	g->m->locked |= LockExternal;
+	lockOSThread();
+}
+
+#pragma textflag NOSPLIT
+void
+runtime·lockOSThread(void)
+{
+	g->m->locked += LockInternal;
+	lockOSThread();
+}
+
+
+// unlockOSThread is called by runtime.UnlockOSThread and runtime.unlockOSThread below
+// after they update m->locked. Do not allow preemption during this call,
+// or else the m might be in different in this function than in the caller.
+#pragma textflag NOSPLIT
+static void
+unlockOSThread(void)
+{
+	if(g->m->locked != 0)
+		return;
+	g->m->lockedg = nil;
+	g->lockedm = nil;
+}
+
+#pragma textflag NOSPLIT
+void
+runtime·UnlockOSThread(void)
+{
+	g->m->locked &= ~LockExternal;
+	unlockOSThread();
+}
+
+static void badunlockOSThread(void);
+
+#pragma textflag NOSPLIT
+void
+runtime·unlockOSThread(void)
+{
+	void (*fn)(void);
+
+	if(g->m->locked < LockInternal) {
+		fn = badunlockOSThread;
+		runtime·onM(&fn);
+	}
+	g->m->locked -= LockInternal;
+	unlockOSThread();
+}
+
+static void
+badunlockOSThread(void)
+{
+	runtime·throw("runtime: internal error: misuse of lockOSThread/unlockOSThread");
+}
+
+#pragma textflag NOSPLIT
+int32
+runtime·gcount(void)
+{
+	P *p, **pp;
+	int32 n;
+
+	n = runtime·allglen - runtime·sched.ngfree;
+	for(pp=runtime·allp; p=*pp; pp++)
+		n -= p->gfreecnt;
+	// All these variables can be changed concurrently, so the result can be inconsistent.
+	// But at least the current goroutine is running.
+	if(n < 1)
+		n = 1;
+	return n;
+}
+
+int32
+runtime·mcount(void)
+{
+	return runtime·sched.mcount;
+}
+
+static struct ProfState {
+	uint32 lock;
+	int32 hz;
+} prof;
+
+static void System(void) { System(); }
+static void ExternalCode(void) { ExternalCode(); }
+static void GC(void) { GC(); }
+
+extern void runtime·cpuproftick(uintptr*, int32);
+extern byte runtime·etext[];
+
+// Called if we receive a SIGPROF signal.
+void
+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;
+	uintptr stk[100];
+
+	m = 0;
+	USED(m);
+
+	if(prof.hz == 0)
+		return;
+
+	// 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.
+	//
+	// It is not quite as easy as testing gp == m->curg (the current user g)
+	// because we might be interrupted for profiling halfway through a
+	// goroutine switch. The switch involves updating three (or four) values:
+	// g, PC, SP, and (on arm) LR. The PC must be the last to be updated,
+	// because once it gets updated the new g is running.
+	//
+	// When switching from a user g to a system g, LR is not considered live,
+	// so the update only affects g, SP, and PC. Since PC must be last, there
+	// the possible partial transitions in ordinary execution are (1) g alone is updated,
+	// (2) both g and SP are updated, and (3) SP alone is updated.
+	// If g is updated, we'll see a system g and not look closer.
+	// If SP alone is updated, we can detect the partial transition by checking
+	// whether the SP is within g's stack bounds. (We could also require that SP
+	// be changed only after g, but the stack bounds check is needed by other
+	// cases, so there is no need to impose an additional requirement.)
+	//
+	// There is one exceptional transition to a system g, not in ordinary execution.
+	// When a signal arrives, the operating system starts the signal handler running
+	// with an updated PC and SP. The g is updated last, at the beginning of the
+	// handler. There are two reasons this is okay. First, until g is updated the
+	// g and SP do not match, so the stack bounds check detects the partial transition.
+	// Second, signal handlers currently run with signals disabled, so a profiling
+	// signal cannot arrive during the handler.
+	//
+	// When switching from a system g to a user g, there are three possibilities.
+	//
+	// First, it may be that the g switch has no PC update, because the SP
+	// either corresponds to a user g throughout (as in runtime.asmcgocall)
+	// or because it has been arranged to look like a user g frame
+	// (as in runtime.cgocallback_gofunc). In this case, since the entire
+	// transition is a g+SP update, a partial transition updating just one of 
+	// those will be detected by the stack bounds check.
+	//
+	// Second, when returning from a signal handler, the PC and SP updates
+	// are performed by the operating system in an atomic update, so the g
+	// update must be done before them. The stack bounds check detects
+	// the partial transition here, and (again) signal handlers run with signals
+	// disabled, so a profiling signal cannot arrive then anyway.
+	//
+	// Third, the common case: it may be that the switch updates g, SP, and PC
+	// separately, as in runtime.gogo.
+	//
+	// Because runtime.gogo is the only instance, we check whether the PC lies
+	// within that function, and if so, not ask for a traceback. This approach
+	// requires knowing the size of the runtime.gogo function, which we
+	// record in arch_*.h and check in runtime_test.go.
+	//
+	// There is another apparently viable approach, recorded here in case
+	// the "PC within runtime.gogo" check turns out not to be usable.
+	// It would be possible to delay the update of either g or SP until immediately
+	// before the PC update instruction. Then, because of the stack bounds check,
+	// the only problematic interrupt point is just before that PC update instruction,
+	// and the sigprof handler can detect that instruction and simulate stepping past
+	// it in order to reach a consistent state. On ARM, the update of g must be made
+	// in two places (in R10 and also in a TLS slot), so the delayed update would
+	// need to be the SP update. The sigprof handler must read the instruction at
+	// the current PC and if it was the known instruction (for example, JMP BX or 
+	// MOV R2, PC), use that other register in place of the PC value.
+	// The biggest drawback to this solution is that it requires that we can tell
+	// whether it's safe to read from the memory pointed at by PC.
+	// In a correct program, we can test PC == nil and otherwise read,
+	// but if a profiling signal happens at the instant that a program executes
+	// a bad jump (before the program manages to handle the resulting fault)
+	// the profiling handler could fault trying to read nonexistent memory.
+	//
+	// 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.
+	traceback = true;
+	if(gp == nil || gp != mp->curg ||
+	   (uintptr)sp < gp->stack.lo || gp->stack.hi < (uintptr)sp ||
+	   ((uint8*)runtime·gogo <= pc && pc < (uint8*)runtime·gogo + RuntimeGogoBytes))
+		traceback = false;
+
+	n = 0;
+	if(traceback)
+		n = runtime·gentraceback((uintptr)pc, (uintptr)sp, (uintptr)lr, gp, 0, stk, nelem(stk), nil, nil, TraceTrap);
+	if(!traceback || n <= 0) {
+		// 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, stk, nelem(stk), nil, nil, 0);
+		}
+#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, stk, nelem(stk), nil, nil, 0);
+		}
+#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)runtime·etext)
+				pc = (byte*)ExternalCode + PCQuantum;
+			stk[0] = (uintptr)pc;
+			if(mp->gcing || mp->helpgc)
+				stk[1] = (uintptr)GC + PCQuantum;
+			else
+				stk[1] = (uintptr)System + PCQuantum;
+		}
+	}
+
+	if(prof.hz != 0) {
+		// Simple cas-lock to coordinate with setcpuprofilerate.
+		while(!runtime·cas(&prof.lock, 0, 1))
+			runtime·osyield();
+		if(prof.hz != 0)
+			runtime·cpuproftick(stk, n);
+		runtime·atomicstore(&prof.lock, 0);
+	}
+	mp->mallocing--;
+}
+
+// Arrange to call fn with a traceback hz times a second.
+void
+runtime·setcpuprofilerate_m(void)
+{
+	int32 hz;
+	
+	hz = g->m->scalararg[0];
+	g->m->scalararg[0] = 0;
+
+	// Force sane arguments.
+	if(hz < 0)
+		hz = 0;
+
+	// Disable preemption, otherwise we can be rescheduled to another thread
+	// that has profiling enabled.
+	g->m->locks++;
+
+	// Stop profiler on this thread so that it is safe to lock prof.
+	// if a profiling signal came in while we had prof locked,
+	// it would deadlock.
+	runtime·resetcpuprofiler(0);
+
+	while(!runtime·cas(&prof.lock, 0, 1))
+		runtime·osyield();
+	prof.hz = hz;
+	runtime·atomicstore(&prof.lock, 0);
+
+	runtime·lock(&runtime·sched.lock);
+	runtime·sched.profilehz = hz;
+	runtime·unlock(&runtime·sched.lock);
+
+	if(hz != 0)
+		runtime·resetcpuprofiler(hz);
+
+	g->m->locks--;
+}
+
+P *runtime·newP(void);
+
+// Change number of processors.  The world is stopped, sched is locked.
+static void
+procresize(int32 new)
+{
+	int32 i, old;
+	bool empty;
+	G *gp;
+	P *p;
+
+	old = runtime·gomaxprocs;
+	if(old < 0 || old > MaxGomaxprocs || new <= 0 || new >MaxGomaxprocs)
+		runtime·throw("procresize: invalid arg");
+	// initialize new P's
+	for(i = 0; i < new; i++) {
+		p = runtime·allp[i];
+		if(p == nil) {
+			p = runtime·newP();
+			p->id = i;
+			p->status = Pgcstop;
+			runtime·atomicstorep(&runtime·allp[i], p);
+		}
+		if(p->mcache == nil) {
+			if(old==0 && i==0)
+				p->mcache = g->m->mcache;  // bootstrap
+			else
+				p->mcache = runtime·allocmcache();
+		}
+	}
+
+	// redistribute runnable G's evenly
+	// 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; 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);
+	}
+
+	// free unused P's
+	for(i = new; i < old; i++) {
+		p = runtime·allp[i];
+		runtime·freemcache(p->mcache);
+		p->mcache = nil;
+		gfpurge(p);
+		p->status = Pdead;
+		// can't free P itself because it can be referenced by an M in syscall
+	}
+
+	if(g->m->p)
+		g->m->p->m = nil;
+	g->m->p = nil;
+	g->m->mcache = nil;
+	p = runtime·allp[0];
+	p->m = nil;
+	p->status = Pidle;
+	acquirep(p);
+	for(i = new-1; i > 0; i--) {
+		p = runtime·allp[i];
+		p->status = Pidle;
+		pidleput(p);
+	}
+	runtime·atomicstore((uint32*)&runtime·gomaxprocs, new);
+}
+
+// Associate p and the current m.
+static void
+acquirep(P *p)
+{
+	if(g->m->p || g->m->mcache)
+		runtime·throw("acquirep: already in go");
+	if(p->m || p->status != Pidle) {
+		runtime·printf("acquirep: p->m=%p(%d) p->status=%d\n", p->m, p->m ? p->m->id : 0, p->status);
+		runtime·throw("acquirep: invalid p state");
+	}
+	g->m->mcache = p->mcache;
+	g->m->p = p;
+	p->m = g->m;
+	p->status = Prunning;
+}
+
+// Disassociate p and the current m.
+static P*
+releasep(void)
+{
+	P *p;
+
+	if(g->m->p == nil || g->m->mcache == nil)
+		runtime·throw("releasep: invalid arg");
+	p = g->m->p;
+	if(p->m != g->m || p->mcache != g->m->mcache || p->status != Prunning) {
+		runtime·printf("releasep: m=%p m->p=%p p->m=%p m->mcache=%p p->mcache=%p p->status=%d\n",
+			g->m, g->m->p, p->m, g->m->mcache, p->mcache, p->status);
+		runtime·throw("releasep: invalid p state");
+	}
+	g->m->p = nil;
+	g->m->mcache = nil;
+	p->m = nil;
+	p->status = Pidle;
+	return p;
+}
+
+static void
+incidlelocked(int32 v)
+{
+	runtime·lock(&runtime·sched.lock);
+	runtime·sched.nmidlelocked += v;
+	if(v > 0)
+		checkdead();
+	runtime·unlock(&runtime·sched.lock);
+}
+
+// Check for deadlock situation.
+// The check is based on number of running M's, if 0 -> deadlock.
+static void
+checkdead(void)
+{
+	G *gp;
+	P *p;
+	M *mp;
+	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("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;
+	runtime·lock(&runtime·allglock);
+	for(i = 0; i < runtime·allglen; i++) {
+		gp = runtime·allg[i];
+		if(gp->issystem)
+			continue;
+		s = runtime·readgstatus(gp);
+		switch(s&~Gscan) {
+		case Gwaiting:
+			grunning++;
+			break;
+		case Grunnable:
+		case Grunning:
+		case Gsyscall:
+			runtime·unlock(&runtime·allglock);
+			runtime·printf("runtime: checkdead: find g %D in status %d\n", gp->goid, s);
+			runtime·throw("checkdead: runnable g");
+			break;
+		}
+	}
+	runtime·unlock(&runtime·allglock);
+	if(grunning == 0)  // possible if main goroutine calls runtime·Goexit()
+		runtime·throw("no goroutines (main called runtime.Goexit) - deadlock!");
+
+	// Maybe jump time forward for playground.
+	if((gp = runtime·timejump()) != nil) {
+		runtime·casgstatus(gp, Gwaiting, Grunnable);
+		globrunqput(gp);
+ 		p = pidleget();
+ 		if(p == nil)
+ 			runtime·throw("checkdead: no p for timer");
+ 		mp = mget();
+ 		if(mp == nil)
+ 			newm(nil, p);
+ 		else {
+ 			mp->nextp = p;
+ 			runtime·notewakeup(&mp->park);
+ 		}
+ 		return;
+ 	}
+
+	g->m->throwing = -1;  // do not dump full stacks
+	runtime·throw("all goroutines are asleep - deadlock!");
+}
+
+static void
+sysmon(void)
+{
+	uint32 idle, delay, nscavenge;
+	int64 now, unixnow, lastpoll, lasttrace, lastgc;
+	int64 forcegcperiod, scavengelimit, lastscavenge, maxsleep;
+	G *gp;
+
+	// If we go two minutes without a garbage collection, force one to run.
+	forcegcperiod = 2*60*1e9;
+	// If a heap span goes unused for 5 minutes after a garbage collection,
+	// we hand it back to the operating system.
+	scavengelimit = 5*60*1e9;
+	if(runtime·debug.scavenge > 0) {
+		// Scavenge-a-lot for testing.
+		forcegcperiod = 10*1e6;
+		scavengelimit = 20*1e6;
+	}
+	lastscavenge = runtime·nanotime();
+	nscavenge = 0;
+	// Make wake-up period small enough for the sampling to be correct.
+	maxsleep = forcegcperiod/2;
+	if(scavengelimit < forcegcperiod)
+		maxsleep = scavengelimit/2;
+
+	lasttrace = 0;
+	idle = 0;  // how many cycles in succession we had not wokeup somebody
+	delay = 0;
+	for(;;) {
+		if(idle == 0)  // start with 20us sleep...
+			delay = 20;
+		else if(idle > 50)  // start doubling the sleep after 1ms...
+			delay *= 2;
+		if(delay > 10*1000)  // up to 10ms
+			delay = 10*1000;
+		runtime·usleep(delay);
+		if(runtime·debug.schedtrace <= 0 &&
+			(runtime·sched.gcwaiting || runtime·atomicload(&runtime·sched.npidle) == runtime·gomaxprocs)) {  // TODO: fast atomic
+			runtime·lock(&runtime·sched.lock);
+			if(runtime·atomicload(&runtime·sched.gcwaiting) || runtime·atomicload(&runtime·sched.npidle) == runtime·gomaxprocs) {
+				runtime·atomicstore(&runtime·sched.sysmonwait, 1);
+				runtime·unlock(&runtime·sched.lock);
+				runtime·notetsleep(&runtime·sched.sysmonnote, maxsleep);
+				runtime·lock(&runtime·sched.lock);
+				runtime·atomicstore(&runtime·sched.sysmonwait, 0);
+				runtime·noteclear(&runtime·sched.sysmonnote);
+				idle = 0;
+				delay = 20;
+			}
+			runtime·unlock(&runtime·sched.lock);
+		}
+		// poll network if not polled for more than 10ms
+		lastpoll = runtime·atomicload64(&runtime·sched.lastpoll);
+		now = runtime·nanotime();
+		unixnow = runtime·unixnanotime();
+		if(lastpoll != 0 && lastpoll + 10*1000*1000 < now) {
+			runtime·cas64(&runtime·sched.lastpoll, lastpoll, now);
+			gp = runtime·netpoll(false);  // non-blocking
+			if(gp) {
+				// Need to decrement number of idle locked M's
+				// (pretending that one more is running) before injectglist.
+				// Otherwise it can lead to the following situation:
+				// injectglist grabs all P's but before it starts M's to run the P's,
+				// another M returns from syscall, finishes running its G,
+				// observes that there is no work to do and no other running M's
+				// and reports deadlock.
+				incidlelocked(-1);
+				injectglist(gp);
+				incidlelocked(1);
+			}
+		}
+		// retake P's blocked in syscalls
+		// and preempt long running G's
+		if(retake(now))
+			idle = 0;
+		else
+			idle++;
+
+		// check if we need to force a GC
+		lastgc = runtime·atomicload64(&mstats.last_gc);
+		if(lastgc != 0 && unixnow - lastgc > forcegcperiod && runtime·atomicload(&runtime·forcegc.idle)) {
+			runtime·lock(&runtime·forcegc.lock);
+			runtime·forcegc.idle = 0;
+			runtime·forcegc.g->schedlink = nil;
+			injectglist(runtime·forcegc.g);
+			runtime·unlock(&runtime·forcegc.lock);
+		}
+
+		// scavenge heap once in a while
+		if(lastscavenge + scavengelimit/2 < now) {
+			runtime·MHeap_Scavenge(nscavenge, now, scavengelimit);
+			lastscavenge = now;
+			nscavenge++;
+		}
+
+		if(runtime·debug.schedtrace > 0 && lasttrace + runtime·debug.schedtrace*1000000ll <= now) {
+			lasttrace = now;
+			runtime·schedtrace(runtime·debug.scheddetail);
+		}
+	}
+}
+
+typedef struct Pdesc Pdesc;
+struct Pdesc
+{
+	uint32	schedtick;
+	int64	schedwhen;
+	uint32	syscalltick;
+	int64	syscallwhen;
+};
+#pragma dataflag NOPTR
+static Pdesc pdesc[MaxGomaxprocs];
+
+static uint32
+retake(int64 now)
+{
+	uint32 i, s, n;
+	int64 t;
+	P *p;
+	Pdesc *pd;
+
+	n = 0;
+	for(i = 0; i < runtime·gomaxprocs; i++) {
+		p = runtime·allp[i];
+		if(p==nil)
+			continue;
+		pd = &pdesc[i];
+		s = p->status;
+		if(s == Psyscall) {
+			// 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 &&
+				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.
+			// Otherwise the M from which we retake can exit the syscall,
+			// increment nmidle and report deadlock.
+			incidlelocked(-1);
+			if(runtime·cas(&p->status, s, Pidle)) {
+				n++;
+				handoffp(p);
+			}
+			incidlelocked(1);
+		} else if(s == Prunning) {
+			// Preempt G if it's running for more than 10ms.
+			t = p->schedtick;
+			if(pd->schedtick != t) {
+				pd->schedtick = t;
+				pd->schedwhen = now;
+				continue;
+			}
+			if(pd->schedwhen + 10*1000*1000 > now)
+				continue;
+			preemptone(p);
+		}
+	}
+	return n;
+}
+
+// Tell all goroutines that they have been preempted and they should stop.
+// This function is purely best-effort.  It can fail to inform a goroutine if a
+// processor just started running it.
+// No locks need to be held.
+// Returns true if preemption request was issued to at least one goroutine.
+static bool
+preemptall(void)
+{
+	P *p;
+	int32 i;
+	bool res;
+
+	res = false;
+	for(i = 0; i < runtime·gomaxprocs; i++) {
+		p = runtime·allp[i];
+		if(p == nil || p->status != Prunning)
+			continue;
+		res |= preemptone(p);
+	}
+	return res;
+}
+
+// Tell the goroutine running on processor P to stop.
+// This function is purely best-effort.  It can incorrectly fail to inform the
+// goroutine.  It can send inform the wrong goroutine.  Even if it informs the
+// correct goroutine, that goroutine might ignore the request if it is
+// simultaneously executing runtime·newstack.
+// No lock needs to be held.
+// Returns true if preemption request was issued.
+// The actual preemption will happen at some point in the future
+// and will be indicated by the gp->status no longer being
+// Grunning
+static bool
+preemptone(P *p)
+{
+	M *mp;
+	G *gp;
+
+	mp = p->m;
+	if(mp == nil || mp == g->m)
+		return false;
+	gp = mp->curg;
+	if(gp == nil || gp == mp->g0)
+		return false;
+	gp->preempt = true;
+	// Every call in a go routine checks for stack overflow by
+	// comparing the current stack pointer to gp->stackguard0.
+	// Setting gp->stackguard0 to StackPreempt folds
+	// preemption into the normal stack overflow check.
+	gp->stackguard0 = StackPreempt;
+	return true;
+}
+
+void
+runtime·schedtrace(bool detailed)
+{
+	static int64 starttime;
+	int64 now;
+	int64 id1, id2, id3;
+	int32 i, t, h;
+	uintptr gi;
+	int8 *fmt;
+	M *mp, *lockedm;
+	G *gp, *lockedg;
+	P *p;
+
+	now = runtime·nanotime();
+	if(starttime == 0)
+		starttime = now;
+
+	runtime·lock(&runtime·sched.lock);
+	runtime·printf("SCHED %Dms: gomaxprocs=%d idleprocs=%d threads=%d spinningthreads=%d idlethreads=%d runqueue=%d",
+		(now-starttime)/1000000, runtime·gomaxprocs, runtime·sched.npidle, runtime·sched.mcount,
+		runtime·sched.nmspinning, runtime·sched.nmidle, runtime·sched.runqsize);
+	if(detailed) {
+		runtime·printf(" gcwaiting=%d nmidlelocked=%d stopwait=%d sysmonwait=%d\n",
+			runtime·sched.gcwaiting, runtime·sched.nmidlelocked,
+			runtime·sched.stopwait, runtime·sched.sysmonwait);
+	}
+	// We must be careful while reading data from P's, M's and G's.
+	// Even if we hold schedlock, most data can be changed concurrently.
+	// E.g. (p->m ? p->m->id : -1) can crash if p->m changes from non-nil to nil.
+	for(i = 0; i < runtime·gomaxprocs; i++) {
+		p = runtime·allp[i];
+		if(p == nil)
+			continue;
+		mp = p->m;
+		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 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]
+			fmt = " %d";
+			if(runtime·gomaxprocs == 1)
+				fmt = " [%d]\n";
+			else if(i == 0)
+				fmt = " [%d";
+			else if(i == runtime·gomaxprocs-1)
+				fmt = " %d]\n";
+			runtime·printf(fmt, t-h);
+		}
+	}
+	if(!detailed) {
+		runtime·unlock(&runtime·sched.lock);
+		return;
+	}
+	for(mp = runtime·allm; mp; mp = mp->alllink) {
+		p = mp->p;
+		gp = mp->curg;
+		lockedg = mp->lockedg;
+		id1 = -1;
+		if(p)
+			id1 = p->id;
+		id2 = -1;
+		if(gp)
+			id2 = gp->goid;
+		id3 = -1;
+		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 blocked=%d lockedg=%D\n",
+			mp->id, id1, id2,
+			mp->mallocing, mp->throwing, mp->gcing, mp->locks, mp->dying, mp->helpgc,
+			mp->spinning, g->m->blocked, id3);
+	}
+	runtime·lock(&runtime·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, runtime·readgstatus(gp), gp->waitreason, mp ? mp->id : -1,
+			lockedm ? lockedm->id : -1);
+	}
+	runtime·unlock(&runtime·allglock);
+	runtime·unlock(&runtime·sched.lock);
+}
+
+// Put mp on midle list.
+// Sched must be locked.
+static void
+mput(M *mp)
+{
+	mp->schedlink = runtime·sched.midle;
+	runtime·sched.midle = mp;
+	runtime·sched.nmidle++;
+	checkdead();
+}
+
+// Try to get an m from midle list.
+// Sched must be locked.
+static M*
+mget(void)
+{
+	M *mp;
+
+	if((mp = runtime·sched.midle) != nil){
+		runtime·sched.midle = mp->schedlink;
+		runtime·sched.nmidle--;
+	}
+	return mp;
+}
+
+// Put gp on the global runnable queue.
+// Sched must be locked.
+static void
+globrunqput(G *gp)
+{
+	gp->schedlink = nil;
+	if(runtime·sched.runqtail)
+		runtime·sched.runqtail->schedlink = gp;
+	else
+		runtime·sched.runqhead = gp;
+	runtime·sched.runqtail = 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*
+globrunqget(P *p, int32 max)
+{
+	G *gp, *gp1;
+	int32 n;
+
+	if(runtime·sched.runqsize == 0)
+		return nil;
+	n = runtime·sched.runqsize/runtime·gomaxprocs+1;
+	if(n > runtime·sched.runqsize)
+		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;
+	gp = runtime·sched.runqhead;
+	runtime·sched.runqhead = gp->schedlink;
+	n--;
+	while(n--) {
+		gp1 = runtime·sched.runqhead;
+		runtime·sched.runqhead = gp1->schedlink;
+		runqput(p, gp1);
+	}
+	return gp;
+}
+
+// Put p to on pidle list.
+// Sched must be locked.
+static void
+pidleput(P *p)
+{
+	p->link = runtime·sched.pidle;
+	runtime·sched.pidle = p;
+	runtime·xadd(&runtime·sched.npidle, 1);  // TODO: fast atomic
+}
+
+// Try get a p from pidle list.
+// Sched must be locked.
+static P*
+pidleget(void)
+{
+	P *p;
+
+	p = runtime·sched.pidle;
+	if(p) {
+		runtime·sched.pidle = p->link;
+		runtime·xadd(&runtime·sched.npidle, -1);  // TODO: fast atomic
+	}
+	return p;
+}
+
+// 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)
+{
+	uint32 h, t;
+
+retry:
+	h = runtime·atomicload(&p->runqhead);  // load-acquire, synchronize with consumers
+	t = p->runqtail;
+	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;
+	}
+	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.lock);
+	globrunqputbatch(batch[0], batch[n], n+1);
+	runtime·unlock(&runtime·sched.lock);
+	return true;
+}
+
+// Get g from local runnable queue.
+// Executed only by the owner P.
+static G*
+runqget(P *p)
+{
+	G *gp;
+	uint32 t, h;
+
+	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;
+	}
+}
+
+// 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)
+{
+	uint32 t, h, n, i;
+
+	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;
+	}
+	return n;
+}
+
+// Steal half of elements from local runnable queue of p2
+// and put onto local runnable queue of p.
+// Returns one of the stolen elements (or nil if failed).
+static G*
+runqsteal(P *p, P *p2)
+{
+	G *gp;
+	G *batch[nelem(p->runq)/2];
+	uint32 t, h, n, i;
+
+	n = runqgrab(p2, batch);
+	if(n == 0)
+		return nil;
+	n--;
+	gp = batch[n];
+	if(n == 0)
+		return gp;
+	h = runtime·atomicload(&p->runqhead);  // load-acquire, synchronize with consumers
+	t = p->runqtail;
+	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;
+}
+
+void
+runtime·testSchedLocalQueue(void)
+{
+	P *p;
+	G *gs;
+	int32 i, j;
+
+	p = (P*)runtime·mallocgc(sizeof(*p), nil, FlagNoScan);
+	gs = (G*)runtime·mallocgc(nelem(p->runq)*sizeof(*gs), nil, FlagNoScan);
+
+	for(i = 0; i < nelem(p->runq); i++) {
+		if(runqget(p) != nil)
+			runtime·throw("runq is not empty initially");
+		for(j = 0; j < i; j++)
+			runqput(p, &gs[i]);
+		for(j = 0; j < i; j++) {
+			if(runqget(p) != &gs[i]) {
+				runtime·printf("bad element at iter %d/%d\n", i, j);
+				runtime·throw("bad element");
+			}
+		}
+		if(runqget(p) != nil)
+			runtime·throw("runq is not empty afterwards");
+	}
+}
+
+void
+runtime·testSchedLocalQueueSteal(void)
+{
+	P *p1, *p2;
+	G *gs, *gp;
+	int32 i, j, s;
+
+	p1 = (P*)runtime·mallocgc(sizeof(*p1), nil, FlagNoScan);
+	p2 = (P*)runtime·mallocgc(sizeof(*p2), nil, FlagNoScan);
+	gs = (G*)runtime·mallocgc(nelem(p1->runq)*sizeof(*gs), nil, FlagNoScan);
+
+	for(i = 0; i < nelem(p1->runq); i++) {
+		for(j = 0; j < i; j++) {
+			gs[j].sig = 0;
+			runqput(p1, &gs[j]);
+		}
+		gp = runqsteal(p2, p1);
+		s = 0;
+		if(gp) {
+			s++;
+			gp->sig++;
+		}
+		while(gp = runqget(p2)) {
+			s++;
+			gp->sig++;
+		}
+		while(gp = runqget(p1))
+			gp->sig++;
+		for(j = 0; j < i; j++) {
+			if(gs[j].sig != 1) {
+				runtime·printf("bad element %d(%d) at iter %d\n", j, gs[j].sig, i);
+				runtime·throw("bad element");
+			}
+		}
+		if(s != i/2 && s != i/2+1) {
+			runtime·printf("bad steal %d, want %d or %d, iter %d\n",
+				s, i/2, i/2+1, i);
+			runtime·throw("bad steal");
+		}
+	}
+}
+
+void
+runtime·setmaxthreads_m(void)
+{
+	int32 in;
+	int32 out;
+
+	in = g->m->scalararg[0];
+
+	runtime·lock(&runtime·sched.lock);
+	out = runtime·sched.maxmcount;
+	runtime·sched.maxmcount = in;
+	checkmcount();
+	runtime·unlock(&runtime·sched.lock);
+
+	g->m->scalararg[0] = out;
+}
+
+static int8 experiment[] = GOEXPERIMENT; // defined in zaexperiment.h
+
+static bool
+haveexperiment(int8 *name)
+{
+	int32 i, j;
+	
+	for(i=0; i<sizeof(experiment); i++) {
+		if((i == 0 || experiment[i-1] == ',') && experiment[i] == name[0]) {
+			for(j=0; name[j]; j++)
+				if(experiment[i+j] != name[j])
+					goto nomatch;
+			if(experiment[i+j] != '\0' && experiment[i+j] != ',')
+				goto nomatch;
+			return 1;
+		}
+	nomatch:;
+	}
+	return 0;
+}
+
+#pragma textflag NOSPLIT
+void
+sync·runtime_procPin(intptr p)
+{
+	M *mp;
+
+	mp = g->m;
+	// Disable preemption.
+	mp->locks++;
+	p = mp->p->id;
+	FLUSH(&p);
+}
+
+#pragma textflag NOSPLIT
+void
+sync·runtime_procUnpin()
+{
+	g->m->locks--;
+}
diff --git a/src/runtime/proc.go b/src/runtime/proc.go
index c5b4a8c..517ca03 100644
--- a/src/runtime/proc.go
+++ b/src/runtime/proc.go
@@ -6,24 +6,12 @@ package runtime
 
 import "unsafe"
 
-//go:linkname runtime_init runtime.init
-func runtime_init()
+func newsysmon()
 
-//go:linkname main_init main.init
+func runtime_init()
 func main_init()
-
-// main_init_done is a signal used by cgocallbackg that initialization
-// has been completed. It is made before _cgo_notify_runtime_init_done,
-// so all cgo calls can rely on it existing. When main_init is complete,
-// it is closed, meaning cgocallbackg can reliably receive from it.
-var main_init_done chan bool
-
-//go:linkname main_main main.main
 func main_main()
 
-// runtimeInitTime is the nanotime() at which the runtime started.
-var runtimeInitTime int64
-
 // The main goroutine.
 func main() {
 	g := getg()
@@ -41,12 +29,7 @@ func main() {
 		maxstacksize = 250000000
 	}
 
-	// Record when the world started.
-	runtimeInitTime = nanotime()
-
-	systemstack(func() {
-		newm(sysmon, nil)
-	})
+	onM(newsysmon)
 
 	// Lock the main goroutine onto this, the main OS thread,
 	// during initialization.  Most programs won't care, but a few
@@ -57,7 +40,7 @@ func main() {
 	lockOSThread()
 
 	if g.m != &m0 {
-		throw("runtime.main not on m0")
+		gothrow("runtime.main not on m0")
 	}
 
 	runtime_init() // must be before defer
@@ -70,44 +53,13 @@ func main() {
 		}
 	}()
 
-	gcenable()
-
-	main_init_done = make(chan bool)
-	if iscgo {
-		if _cgo_thread_start == nil {
-			throw("_cgo_thread_start missing")
-		}
-		if _cgo_malloc == nil {
-			throw("_cgo_malloc missing")
-		}
-		if _cgo_free == nil {
-			throw("_cgo_free missing")
-		}
-		if GOOS != "windows" {
-			if _cgo_setenv == nil {
-				throw("_cgo_setenv missing")
-			}
-			if _cgo_unsetenv == nil {
-				throw("_cgo_unsetenv missing")
-			}
-		}
-		if _cgo_notify_runtime_init_done == nil {
-			throw("_cgo_notify_runtime_init_done missing")
-		}
-		cgocall(_cgo_notify_runtime_init_done, nil)
-	}
+	memstats.enablegc = true // now that runtime is initialized, GC is okay
 
 	main_init()
-	close(main_init_done)
 
 	needUnlock = false
 	unlockOSThread()
 
-	if isarchive || islibrary {
-		// A program compiled with -buildmode=c-archive or c-shared
-		// has a main, but it is not executed.
-		return
-	}
 	main_main()
 	if raceenabled {
 		racefini()
@@ -118,7 +70,7 @@ func main() {
 	// let the other goroutine finish printing the panic trace.
 	// Once it does, it will exit. See issue 3934.
 	if panicking != 0 {
-		gopark(nil, nil, "panicwait", traceEvGoStop, 1)
+		gopark(nil, nil, "panicwait")
 	}
 
 	exit(0)
@@ -128,13 +80,7 @@ func main() {
 	}
 }
 
-// os_beforeExit is called from os.Exit(0).
-//go:linkname os_beforeExit os.runtime_beforeExit
-func os_beforeExit() {
-	if raceenabled {
-		racefini()
-	}
-}
+var parkunlock_c byte
 
 // start forcegc helper goroutine
 func init() {
@@ -143,18 +89,19 @@ func init() {
 
 func forcegchelper() {
 	forcegc.g = getg()
+	forcegc.g.issystem = true
 	for {
 		lock(&forcegc.lock)
 		if forcegc.idle != 0 {
-			throw("forcegc: phase error")
+			gothrow("forcegc: phase error")
 		}
 		atomicstore(&forcegc.idle, 1)
-		goparkunlock(&forcegc.lock, "force gc (idle)", traceEvGoBlock, 1)
+		goparkunlock(&forcegc.lock, "force gc (idle)")
 		// this goroutine is explicitly resumed by sysmon
 		if debug.gctrace > 0 {
 			println("GC forced")
 		}
-		startGC(gcBackgroundMode, true)
+		gogc(1)
 	}
 }
 
@@ -168,18 +115,16 @@ func Gosched() {
 
 // Puts the current goroutine into a waiting state and calls unlockf.
 // If unlockf returns false, the goroutine is resumed.
-func gopark(unlockf func(*g, unsafe.Pointer) bool, lock unsafe.Pointer, reason string, traceEv byte, traceskip int) {
+func gopark(unlockf unsafe.Pointer, lock unsafe.Pointer, reason string) {
 	mp := acquirem()
 	gp := mp.curg
 	status := readgstatus(gp)
 	if status != _Grunning && status != _Gscanrunning {
-		throw("gopark: bad g status")
+		gothrow("gopark: bad g status")
 	}
 	mp.waitlock = lock
-	mp.waitunlockf = *(*unsafe.Pointer)(unsafe.Pointer(&unlockf))
+	mp.waitunlockf = unlockf
 	gp.waitreason = reason
-	mp.waittraceev = traceEv
-	mp.waittraceskip = traceskip
 	releasem(mp)
 	// can't do anything that might move the G between Ms here.
 	mcall(park_m)
@@ -187,99 +132,68 @@ func gopark(unlockf func(*g, unsafe.Pointer) bool, lock unsafe.Pointer, reason s
 
 // Puts the current goroutine into a waiting state and unlocks the lock.
 // The goroutine can be made runnable again by calling goready(gp).
-func goparkunlock(lock *mutex, reason string, traceEv byte, traceskip int) {
-	gopark(parkunlock_c, unsafe.Pointer(lock), reason, traceEv, traceskip)
+func goparkunlock(lock *mutex, reason string) {
+	gopark(unsafe.Pointer(&parkunlock_c), unsafe.Pointer(lock), reason)
 }
 
-func goready(gp *g, traceskip int) {
-	systemstack(func() {
-		ready(gp, traceskip)
-	})
+func goready(gp *g) {
+	mp := acquirem()
+	mp.ptrarg[0] = unsafe.Pointer(gp)
+	onM(ready_m)
+	releasem(mp)
 }
 
 //go:nosplit
 func acquireSudog() *sudog {
+	c := gomcache()
+	s := c.sudogcache
+	if s != nil {
+		if s.elem != nil {
+			gothrow("acquireSudog: found s.elem != nil in cache")
+		}
+		c.sudogcache = s.next
+		s.next = nil
+		return s
+	}
+
 	// Delicate dance: the semaphore implementation calls
 	// acquireSudog, acquireSudog calls new(sudog),
 	// new calls malloc, malloc can call the garbage collector,
 	// and the garbage collector calls the semaphore implementation
-	// in stopTheWorld.
+	// in stoptheworld.
 	// Break the cycle by doing acquirem/releasem around new(sudog).
 	// The acquirem/releasem increments m.locks during new(sudog),
 	// which keeps the garbage collector from being invoked.
 	mp := acquirem()
-	pp := mp.p.ptr()
-	if len(pp.sudogcache) == 0 {
-		lock(&sched.sudoglock)
-		// First, try to grab a batch from central cache.
-		for len(pp.sudogcache) < cap(pp.sudogcache)/2 && sched.sudogcache != nil {
-			s := sched.sudogcache
-			sched.sudogcache = s.next
-			s.next = nil
-			pp.sudogcache = append(pp.sudogcache, s)
-		}
-		unlock(&sched.sudoglock)
-		// If the central cache is empty, allocate a new one.
-		if len(pp.sudogcache) == 0 {
-			pp.sudogcache = append(pp.sudogcache, new(sudog))
-		}
-	}
-	n := len(pp.sudogcache)
-	s := pp.sudogcache[n-1]
-	pp.sudogcache[n-1] = nil
-	pp.sudogcache = pp.sudogcache[:n-1]
-	if s.elem != nil {
-		throw("acquireSudog: found s.elem != nil in cache")
-	}
+	p := new(sudog)
 	releasem(mp)
-	return s
+	return p
 }
 
 //go:nosplit
 func releaseSudog(s *sudog) {
 	if s.elem != nil {
-		throw("runtime: sudog with non-nil elem")
+		gothrow("runtime: sudog with non-nil elem")
 	}
 	if s.selectdone != nil {
-		throw("runtime: sudog with non-nil selectdone")
+		gothrow("runtime: sudog with non-nil selectdone")
 	}
 	if s.next != nil {
-		throw("runtime: sudog with non-nil next")
+		gothrow("runtime: sudog with non-nil next")
 	}
 	if s.prev != nil {
-		throw("runtime: sudog with non-nil prev")
+		gothrow("runtime: sudog with non-nil prev")
 	}
 	if s.waitlink != nil {
-		throw("runtime: sudog with non-nil waitlink")
+		gothrow("runtime: sudog with non-nil waitlink")
 	}
 	gp := getg()
 	if gp.param != nil {
-		throw("runtime: releaseSudog with non-nil gp.param")
-	}
-	mp := acquirem() // avoid rescheduling to another P
-	pp := mp.p.ptr()
-	if len(pp.sudogcache) == cap(pp.sudogcache) {
-		// Transfer half of local cache to the central cache.
-		var first, last *sudog
-		for len(pp.sudogcache) > cap(pp.sudogcache)/2 {
-			n := len(pp.sudogcache)
-			p := pp.sudogcache[n-1]
-			pp.sudogcache[n-1] = nil
-			pp.sudogcache = pp.sudogcache[:n-1]
-			if first == nil {
-				first = p
-			} else {
-				last.next = p
-			}
-			last = p
-		}
-		lock(&sched.sudoglock)
-		last.next = sched.sudogcache
-		sched.sudogcache = first
-		unlock(&sched.sudoglock)
+		gothrow("runtime: releaseSudog with non-nil gp.param")
 	}
-	pp.sudogcache = append(pp.sudogcache, s)
-	releasem(mp)
+	c := gomcache()
+	s.next = c.sudogcache
+	c.sudogcache = s
 }
 
 // funcPC returns the entry PC of the function f.
@@ -291,11 +205,11 @@ func funcPC(f interface{}) uintptr {
 
 // called from assembly
 func badmcall(fn func(*g)) {
-	throw("runtime: mcall called on m->g0 stack")
+	gothrow("runtime: mcall called on m->g0 stack")
 }
 
 func badmcall2(fn func(*g)) {
-	throw("runtime: mcall function returned")
+	gothrow("runtime: mcall function returned")
 }
 
 func badreflectcall() {
@@ -307,14 +221,21 @@ func lockedOSThread() bool {
 	return gp.lockedm != nil && gp.m.lockedg != nil
 }
 
-var (
-	allgs    []*g
-	allglock mutex
-)
+func newP() *p {
+	return new(p)
+}
+
+func newM() *m {
+	return new(m)
+}
+
+func newG() *g {
+	return new(g)
+}
 
 func allgadd(gp *g) {
 	if readgstatus(gp) == _Gidle {
-		throw("allgadd: bad status Gidle")
+		gothrow("allgadd: bad status Gidle")
 	}
 
 	lock(&allglock)
diff --git a/src/runtime/proc_test.go b/src/runtime/proc_test.go
index 2be103e..aa9bc81 100644
--- a/src/runtime/proc_test.go
+++ b/src/runtime/proc_test.go
@@ -7,8 +7,6 @@ package runtime_test
 import (
 	"math"
 	"runtime"
-	"runtime/debug"
-	"sync"
 	"sync/atomic"
 	"syscall"
 	"testing"
@@ -96,10 +94,6 @@ func TestYieldLocked(t *testing.T) {
 }
 
 func TestGoroutineParallelism(t *testing.T) {
-	if runtime.NumCPU() == 1 {
-		// Takes too long, too easy to deadlock, etc.
-		t.Skip("skipping on uniprocessor")
-	}
 	P := 4
 	N := 10
 	if testing.Short() {
@@ -109,8 +103,8 @@ func TestGoroutineParallelism(t *testing.T) {
 	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(P))
 	// If runtime triggers a forced GC during this test then it will deadlock,
 	// since the goroutines can't be stopped/preempted.
-	// Disable GC for this test (see issue #10958).
-	defer debug.SetGCPercent(debug.SetGCPercent(-1))
+	// So give this test as much time as possible.
+	runtime.GC()
 	for try := 0; try < N; try++ {
 		done := make(chan bool)
 		x := uint32(0)
@@ -297,98 +291,6 @@ func main() {
 }
 `
 
-func TestPingPongHog(t *testing.T) {
-	if testing.Short() {
-		t.Skip("skipping in -short mode")
-	}
-
-	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(1))
-	done := make(chan bool)
-	hogChan, lightChan := make(chan bool), make(chan bool)
-	hogCount, lightCount := 0, 0
-
-	run := func(limit int, counter *int, wake chan bool) {
-		for {
-			select {
-			case <-done:
-				return
-
-			case <-wake:
-				for i := 0; i < limit; i++ {
-					*counter++
-				}
-				wake <- true
-			}
-		}
-	}
-
-	// Start two co-scheduled hog goroutines.
-	for i := 0; i < 2; i++ {
-		go run(1e6, &hogCount, hogChan)
-	}
-
-	// Start two co-scheduled light goroutines.
-	for i := 0; i < 2; i++ {
-		go run(1e3, &lightCount, lightChan)
-	}
-
-	// Start goroutine pairs and wait for a few preemption rounds.
-	hogChan <- true
-	lightChan <- true
-	time.Sleep(100 * time.Millisecond)
-	close(done)
-	<-hogChan
-	<-lightChan
-
-	// Check that hogCount and lightCount are within a factor of
-	// 2, which indicates that both pairs of goroutines handed off
-	// the P within a time-slice to their buddy.
-	if hogCount > lightCount*2 || lightCount > hogCount*2 {
-		t.Fatalf("want hogCount/lightCount in [0.5, 2]; got %d/%d = %g", hogCount, lightCount, float64(hogCount)/float64(lightCount))
-	}
-}
-
-func BenchmarkPingPongHog(b *testing.B) {
-	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(1))
-
-	// Create a CPU hog
-	stop, done := make(chan bool), make(chan bool)
-	go func() {
-		for {
-			select {
-			case <-stop:
-				done <- true
-				return
-			default:
-			}
-		}
-	}()
-
-	// Ping-pong b.N times
-	ping, pong := make(chan bool), make(chan bool)
-	go func() {
-		for j := 0; j < b.N; j++ {
-			pong <- <-ping
-		}
-		close(stop)
-		done <- true
-	}()
-	go func() {
-		for i := 0; i < b.N; i++ {
-			ping <- <-pong
-		}
-		done <- true
-	}()
-	b.ResetTimer()
-	ping <- true // Start ping-pong
-	<-stop
-	b.StopTimer()
-	<-ping // Let last ponger exit
-	<-done // Make sure goroutines exit
-	<-done
-	<-done
-}
-
 func stackGrowthRecursive(i int) {
 	var pad [128]uint64
 	if i != 0 && pad[0] == 0 {
@@ -513,37 +415,6 @@ func benchmarkCreateGoroutines(b *testing.B, procs int) {
 	}
 }
 
-func BenchmarkCreateGoroutinesCapture(b *testing.B) {
-	b.ReportAllocs()
-	for i := 0; i < b.N; i++ {
-		const N = 4
-		var wg sync.WaitGroup
-		wg.Add(N)
-		for i := 0; i < N; i++ {
-			i := i
-			go func() {
-				if i >= N {
-					b.Logf("bad") // just to capture b
-				}
-				wg.Done()
-			}()
-		}
-		wg.Wait()
-	}
-}
-
-func BenchmarkClosureCall(b *testing.B) {
-	sum := 0
-	off1 := 1
-	for i := 0; i < b.N; i++ {
-		off2 := 2
-		func() {
-			sum += i + off1 + off2
-		}()
-	}
-	_ = sum
-}
-
 type Matrix [][]float64
 
 func BenchmarkMatmult(b *testing.B) {
diff --git a/src/runtime/race.c b/src/runtime/race.c
new file mode 100644
index 0000000..5b0d116
--- /dev/null
+++ b/src/runtime/race.c
@@ -0,0 +1,347 @@
+// 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.
+
+// Implementation of the race detector API.
+// +build race
+
+#include "runtime.h"
+#include "arch_GOARCH.h"
+#include "malloc.h"
+#include "race.h"
+#include "type.h"
+#include "typekind.h"
+#include "textflag.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);
+void __tsan_go_ignore_sync_begin(void);
+void __tsan_go_ignore_sync_end(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
+#pragma cgo_import_static __tsan_go_ignore_sync_begin
+#pragma cgo_import_static __tsan_go_ignore_sync_end
+
+// 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
+
+#pragma cgo_import_static __tsan_go_atomic32_load
+#pragma cgo_import_static __tsan_go_atomic64_load
+#pragma cgo_import_static __tsan_go_atomic32_store
+#pragma cgo_import_static __tsan_go_atomic64_store
+#pragma cgo_import_static __tsan_go_atomic32_exchange
+#pragma cgo_import_static __tsan_go_atomic64_exchange
+#pragma cgo_import_static __tsan_go_atomic32_fetch_add
+#pragma cgo_import_static __tsan_go_atomic64_fetch_add
+#pragma cgo_import_static __tsan_go_atomic32_compare_exchange
+#pragma cgo_import_static __tsan_go_atomic64_compare_exchange
+
+extern byte runtime·noptrdata[];
+extern byte runtime·enoptrdata[];
+extern byte runtime·data[];
+extern byte runtime·edata[];
+extern byte runtime·bss[];
+extern byte runtime·ebss[];
+extern byte runtime·noptrbss[];
+extern byte runtime·enoptrbss[];
+
+// start/end of global data (data+bss).
+uintptr runtime·racedatastart;
+uintptr runtime·racedataend;
+// start/end of heap for race_amd64.s
+uintptr runtime·racearenastart;
+uintptr runtime·racearenaend;
+
+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*);
+
+// racecall allows calling an arbitrary function f from C race runtime
+// with up to 4 uintptr arguments.
+void runtime·racecall(void(*f)(void), ...);
+
+// checks if the address has shadow (i.e. heap or data/bss)
+#pragma textflag NOSPLIT
+static bool
+isvalidaddr(uintptr addr)
+{
+	if(addr >= runtime·racearenastart && addr < runtime·racearenaend)
+		return true;
+	if(addr >= runtime·racedatastart && addr < runtime·racedataend)
+		return true;
+	return false;
+}
+
+#pragma textflag NOSPLIT
+uintptr
+runtime·raceinit(void)
+{
+	uintptr racectx, start, end, size;
+
+	// 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().
+	// The relevant sections are noptrdata, data, bss, noptrbss.
+	// In external linking mode, there may be other non-Go data mixed in,
+	// and the sections may even occur out of order.
+	// Work out a conservative range of addresses.
+	start = ~(uintptr)0;
+	end = 0;
+	if(start > (uintptr)runtime·noptrdata)
+		start = (uintptr)runtime·noptrdata;
+	if(start > (uintptr)runtime·data)
+		start = (uintptr)runtime·data;
+	if(start > (uintptr)runtime·noptrbss)
+		start = (uintptr)runtime·noptrbss;
+	if(start > (uintptr)runtime·bss)
+		start = (uintptr)runtime·bss;
+	if(end < (uintptr)runtime·enoptrdata)
+		end = (uintptr)runtime·enoptrdata;
+	if(end < (uintptr)runtime·edata)
+		end = (uintptr)runtime·edata;
+	if(end < (uintptr)runtime·enoptrbss)
+		end = (uintptr)runtime·enoptrbss;
+	if(end < (uintptr)runtime·ebss)
+		end = (uintptr)runtime·ebss;
+	start = start & ~(PageSize-1);
+	size = ROUND(end - start, PageSize);
+	runtime·racecall(__tsan_map_shadow, start, size);
+	runtime·racedatastart = start;
+	runtime·racedataend = start + size;
+	return racectx;
+}
+
+#pragma textflag NOSPLIT
+void
+runtime·racefini(void)
+{
+	runtime·racecall(__tsan_fini);
+}
+
+#pragma textflag NOSPLIT
+void
+runtime·racemapshadow(void *addr, uintptr size)
+{
+	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);
+}
+
+#pragma textflag NOSPLIT
+void
+runtime·racemalloc(void *p, uintptr sz)
+{
+	runtime·racecall(__tsan_malloc, p, sz);
+}
+
+#pragma textflag NOSPLIT
+uintptr
+runtime·racegostart(void *pc)
+{
+	uintptr racectx;
+	G *spawng;
+
+	if(g->m->curg != nil)
+		spawng = g->m->curg;
+	else
+		spawng = g;
+
+	runtime·racecall(__tsan_go_start, spawng->racectx, &racectx, pc);
+	return racectx;
+}
+
+#pragma textflag NOSPLIT
+void
+runtime·racegoend(void)
+{
+	runtime·racecall(__tsan_go_end, g->racectx);
+}
+
+#pragma textflag NOSPLIT
+void
+runtime·racewriterangepc(void *addr, uintptr sz, void *callpc, void *pc)
+{
+	if(g != g->m->curg) {
+		// The call is coming from manual instrumentation of Go code running on g0/gsignal.
+		// Not interesting.
+		return;
+	}
+	if(callpc != nil)
+		runtime·racefuncenter(callpc);
+	runtime·racewriterangepc1(addr, sz, pc);
+	if(callpc != nil)
+		runtime·racefuncexit();
+}
+
+#pragma textflag NOSPLIT
+void
+runtime·racereadrangepc(void *addr, uintptr sz, void *callpc, void *pc)
+{
+	if(g != g->m->curg) {
+		// The call is coming from manual instrumentation of Go code running on g0/gsignal.
+		// Not interesting.
+		return;
+	}
+	if(callpc != nil)
+		runtime·racefuncenter(callpc);
+	runtime·racereadrangepc1(addr, sz, pc);
+	if(callpc != nil)
+		runtime·racefuncexit();
+}
+
+#pragma textflag NOSPLIT
+void
+runtime·racewriteobjectpc(void *addr, Type *t, void *callpc, void *pc)
+{
+	uint8 kind;
+
+	kind = t->kind & KindMask;
+	if(kind == KindArray || kind == KindStruct)
+		runtime·racewriterangepc(addr, t->size, callpc, pc);
+	else
+		runtime·racewritepc(addr, callpc, pc);
+}
+
+#pragma textflag NOSPLIT
+void
+runtime·racereadobjectpc(void *addr, Type *t, void *callpc, void *pc)
+{
+	uint8 kind;
+
+	kind = t->kind & KindMask;
+	if(kind == KindArray || kind == KindStruct)
+		runtime·racereadrangepc(addr, t->size, callpc, pc);
+	else
+		runtime·racereadpc(addr, callpc, pc);
+}
+
+#pragma textflag NOSPLIT
+void
+runtime·raceacquire(void *addr)
+{
+	runtime·raceacquireg(g, addr);
+}
+
+#pragma textflag NOSPLIT
+void
+runtime·raceacquireg(G *gp, void *addr)
+{
+	if(g->raceignore || !isvalidaddr((uintptr)addr))
+		return;
+	runtime·racecall(__tsan_acquire, gp->racectx, addr);
+}
+
+#pragma textflag NOSPLIT
+void
+runtime·racerelease(void *addr)
+{
+	if(g->raceignore || !isvalidaddr((uintptr)addr))
+		return;
+	runtime·racereleaseg(g, addr);
+}
+
+#pragma textflag NOSPLIT
+void
+runtime·racereleaseg(G *gp, void *addr)
+{
+	if(g->raceignore || !isvalidaddr((uintptr)addr))
+		return;
+	runtime·racecall(__tsan_release, gp->racectx, addr);
+}
+
+#pragma textflag NOSPLIT
+void
+runtime·racereleasemerge(void *addr)
+{
+	runtime·racereleasemergeg(g, addr);
+}
+
+#pragma textflag NOSPLIT
+void
+runtime·racereleasemergeg(G *gp, void *addr)
+{
+	if(g->raceignore || !isvalidaddr((uintptr)addr))
+		return;
+	runtime·racecall(__tsan_release_merge, gp->racectx, addr);
+}
+
+#pragma textflag NOSPLIT
+void
+runtime·racefingo(void)
+{
+	runtime·racecall(__tsan_finalizer_goroutine, g->racectx);
+}
+
+// func RaceAcquire(addr unsafe.Pointer)
+#pragma textflag NOSPLIT
+void
+runtime·RaceAcquire(void *addr)
+{
+	runtime·raceacquire(addr);
+}
+
+// func RaceRelease(addr unsafe.Pointer)
+#pragma textflag NOSPLIT
+void
+runtime·RaceRelease(void *addr)
+{
+	runtime·racerelease(addr);
+}
+
+// func RaceReleaseMerge(addr unsafe.Pointer)
+#pragma textflag NOSPLIT
+void
+runtime·RaceReleaseMerge(void *addr)
+{
+	runtime·racereleasemerge(addr);
+}
+
+// func RaceDisable()
+#pragma textflag NOSPLIT
+void
+runtime·RaceDisable(void)
+{
+	if(g->raceignore++ == 0)
+		runtime·racecall(__tsan_go_ignore_sync_begin, g->racectx);
+}
+
+// func RaceEnable()
+#pragma textflag NOSPLIT
+void
+runtime·RaceEnable(void)
+{
+	if(--g->raceignore == 0)
+		runtime·racecall(__tsan_go_ignore_sync_end, g->racectx);
+}
diff --git a/src/runtime/race.go b/src/runtime/race.go
index 923d611..bb0ee6d 100644
--- a/src/runtime/race.go
+++ b/src/runtime/race.go
@@ -12,6 +12,18 @@ import (
 	"unsafe"
 )
 
+func racefini()
+
+// RaceDisable disables handling of race events in the current goroutine.
+func RaceDisable()
+
+// RaceEnable re-enables handling of race events in the current goroutine.
+func RaceEnable()
+
+func RaceAcquire(addr unsafe.Pointer)
+func RaceRelease(addr unsafe.Pointer)
+func RaceReleaseMerge(addr unsafe.Pointer)
+
 func RaceRead(addr unsafe.Pointer)
 func RaceWrite(addr unsafe.Pointer)
 func RaceReadRange(addr unsafe.Pointer, len int)
@@ -23,9 +35,6 @@ func RaceSemrelease(s *uint32)
 // private interface for the runtime
 const raceenabled = true
 
-// For all functions accepting callerpc and pc,
-// callerpc is a return PC of the function that calls this function,
-// pc is start PC of the function that calls this function.
 func raceReadObjectPC(t *_type, addr unsafe.Pointer, callerpc, pc uintptr) {
 	kind := t.kind & kindMask
 	if kind == kindArray || kind == kindStruct {
@@ -58,6 +67,32 @@ func racereadpc(addr unsafe.Pointer, callpc, pc uintptr)
 //go:noescape
 func racewritepc(addr unsafe.Pointer, callpc, pc uintptr)
 
+//go:noescape
+func racereadrangepc(addr unsafe.Pointer, len uintptr, callpc, pc uintptr)
+
+//go:noescape
+func racewriterangepc(addr unsafe.Pointer, len uintptr, callpc, pc uintptr)
+
+//go:noescape
+func raceacquire(addr unsafe.Pointer)
+
+//go:noescape
+func racerelease(addr unsafe.Pointer)
+
+//go:noescape
+func raceacquireg(gp *g, addr unsafe.Pointer)
+
+//go:noescape
+func racereleaseg(gp *g, addr unsafe.Pointer)
+
+func racefingo()
+
+//go:noescape
+func racemalloc(p unsafe.Pointer, size uintptr)
+
+//go:noescape
+func racereleasemerge(addr unsafe.Pointer)
+
 type symbolizeContext struct {
 	pc   uintptr
 	fn   *byte
@@ -82,9 +117,9 @@ func racesymbolize(ctx *symbolizeContext) {
 		return
 	}
 
-	ctx.fn = cfuncname(f)
-	file, line := funcline(f, ctx.pc)
-	ctx.line = uintptr(line)
+	ctx.fn = funcname(f)
+	var file string
+	ctx.line = uintptr(funcline(f, ctx.pc, &file))
 	ctx.file = &bytes(file)[0] // assume NUL-terminated
 	ctx.off = ctx.pc - f.entry
 	ctx.res = 1
diff --git a/src/runtime/race.h b/src/runtime/race.h
new file mode 100644
index 0000000..fee31e0
--- /dev/null
+++ b/src/runtime/race.h
@@ -0,0 +1,34 @@
+// 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.
+
+// Definitions related to data race detection.
+
+#ifdef RACE
+enum { raceenabled = 1 };
+#else
+enum { raceenabled = 0 };
+#endif
+
+// Initialize race detection subsystem.
+uintptr	runtime·raceinit(void);
+// Finalize race detection subsystem, does not return.
+void	runtime·racefini(void);
+
+void	runtime·racemapshadow(void *addr, uintptr size);
+void	runtime·racemalloc(void *p, uintptr sz);
+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);
+void	runtime·racerelease(void *addr);
+void	runtime·racereleaseg(G *gp, void *addr);
+void	runtime·racereleasemerge(void *addr);
+void	runtime·racereleasemergeg(G *gp, void *addr);
diff --git a/src/runtime/race/README b/src/runtime/race/README
index 52dd38e..7f18535 100644
--- a/src/runtime/race/README
+++ b/src/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 229396.
+Current runtime is built on rev 215000.
diff --git a/src/runtime/race/doc.go b/src/runtime/race/doc.go
index 9e93f66..aef805d 100644
--- a/src/runtime/race/doc.go
+++ b/src/runtime/race/doc.go
@@ -5,5 +5,5 @@
 // Package race implements data race detection logic.
 // No public interface is provided.
 // For details about the race detector see
-// https://golang.org/doc/articles/race_detector.html
+// http://golang.org/doc/articles/race_detector.html
 package race
diff --git a/src/runtime/race/output_test.go b/src/runtime/race/output_test.go
index a9f9f0f..d2303f7 100644
--- a/src/runtime/race/output_test.go
+++ b/src/runtime/race/output_test.go
@@ -23,11 +23,7 @@ func TestOutput(t *testing.T) {
 			t.Fatalf("failed to create temp directory: %v", err)
 		}
 		defer os.RemoveAll(dir)
-		source := "main.go"
-		if test.run == "test" {
-			source = "main_test.go"
-		}
-		src := filepath.Join(dir, source)
+		src := filepath.Join(dir, "main.go")
 		f, err := os.Create(src)
 		if err != nil {
 			t.Fatalf("failed to create file: %v", err)
@@ -41,7 +37,7 @@ func TestOutput(t *testing.T) {
 			t.Fatalf("failed to close file: %v", err)
 		}
 		// Pass -l to the compiler to test stack traces.
-		cmd := exec.Command("go", test.run, "-race", "-gcflags=-l", src)
+		cmd := exec.Command("go", "run", "-race", "-gcflags=-l", src)
 		// GODEBUG spoils program output, GOMAXPROCS makes it flaky.
 		for _, env := range os.Environ() {
 			if strings.HasPrefix(env, "GODEBUG=") ||
@@ -62,12 +58,11 @@ func TestOutput(t *testing.T) {
 
 var tests = []struct {
 	name   string
-	run    string
 	gorace string
 	source string
 	re     string
 }{
-	{"simple", "run", "atexit_sleep_ms=0", `
+	{"simple", "atexit_sleep_ms=0", `
 package main
 import "time"
 func main() {
@@ -112,7 +107,7 @@ Found 1 data race\(s\)
 exit status 66
 `},
 
-	{"exitcode", "run", "atexit_sleep_ms=0 exitcode=13", `
+	{"exitcode", "atexit_sleep_ms=0 exitcode=13", `
 package main
 func main() {
 	done := make(chan bool)
@@ -126,7 +121,7 @@ func main() {
 }
 `, `exit status 13`},
 
-	{"strip_path_prefix", "run", "atexit_sleep_ms=0 strip_path_prefix=/main.", `
+	{"strip_path_prefix", "atexit_sleep_ms=0 strip_path_prefix=/main.", `
 package main
 func main() {
 	done := make(chan bool)
@@ -142,7 +137,7 @@ func main() {
       go:7 \+0x[0-9,a-f]+
 `},
 
-	{"halt_on_error", "run", "atexit_sleep_ms=0 halt_on_error=1", `
+	{"halt_on_error", "atexit_sleep_ms=0 halt_on_error=1", `
 package main
 func main() {
 	done := make(chan bool)
@@ -158,23 +153,4 @@ func main() {
 ==================
 exit status 66
 `},
-
-	{"test_fails_on_race", "test", "atexit_sleep_ms=0", `
-package main_test
-import "testing"
-func TestFail(t *testing.T) {
-	done := make(chan bool)
-	x := 0
-	go func() {
-		x = 42
-		done <- true
-	}()
-	x = 43
-	<-done
-}
-`, `
-==================
-PASS
-Found 1 data race\(s\)
-FAIL`},
 }
diff --git a/src/runtime/race/race_darwin_amd64.syso b/src/runtime/race/race_darwin_amd64.syso
index 9cf1ecc..81b48c6 100644
Binary files a/src/runtime/race/race_darwin_amd64.syso and b/src/runtime/race/race_darwin_amd64.syso differ
diff --git a/src/runtime/race/race_freebsd_amd64.syso b/src/runtime/race/race_freebsd_amd64.syso
index 50ae2d3..5bbe322 100644
Binary files a/src/runtime/race/race_freebsd_amd64.syso and b/src/runtime/race/race_freebsd_amd64.syso differ
diff --git a/src/runtime/race/race_linux_amd64.syso b/src/runtime/race/race_linux_amd64.syso
index a141051..49bf08e 100644
Binary files a/src/runtime/race/race_linux_amd64.syso and b/src/runtime/race/race_linux_amd64.syso differ
diff --git a/src/runtime/race/race_test.go b/src/runtime/race/race_test.go
index 6898e74..7e0ee86 100644
--- a/src/runtime/race/race_test.go
+++ b/src/runtime/race/race_test.go
@@ -36,7 +36,7 @@ var (
 
 const (
 	visibleLen = 40
-	testPrefix = "=== RUN   Test"
+	testPrefix = "=== RUN Test"
 )
 
 func TestRace(t *testing.T) {
@@ -63,9 +63,6 @@ func TestRace(t *testing.T) {
 		}
 	}
 
-	if totalTests == 0 {
-		t.Fatalf("failed to parse test output")
-	}
 	fmt.Printf("\nPassed %d of %d tests (%.02f%%, %d+, %d-)\n",
 		passedTests, totalTests, 100*float64(passedTests)/float64(totalTests), falsePos, falseNeg)
 	fmt.Printf("%d expected failures (%d has not fail)\n", failingPos+failingNeg, failingNeg)
@@ -155,7 +152,7 @@ func runTests() ([]byte, error) {
 		}
 		cmd.Env = append(cmd.Env, env)
 	}
-	cmd.Env = append(cmd.Env, `GORACE=suppress_equal_stacks=0 suppress_equal_addresses=0 exitcode=0`)
+	cmd.Env = append(cmd.Env, `GORACE="suppress_equal_stacks=0 suppress_equal_addresses=0 exitcode=0"`)
 	return cmd.CombinedOutput()
 }
 
@@ -173,12 +170,3 @@ func TestIssue8102(t *testing.T) {
 		}
 	}
 }
-
-func TestIssue9137(t *testing.T) {
-	a := []string{"a"}
-	i := 0
-	a[i], a[len(a)-1], a = a[len(a)-1], "", a[:len(a)-1]
-	if len(a) != 0 || a[:1][0] != "" {
-		t.Errorf("mangled a: %q %q", a, a[:1])
-	}
-}
diff --git a/src/runtime/race/race_windows_amd64.syso b/src/runtime/race/race_windows_amd64.syso
index 125115e..a4eae9b 100644
Binary files a/src/runtime/race/race_windows_amd64.syso and b/src/runtime/race/race_windows_amd64.syso differ
diff --git a/src/runtime/race/testdata/io_test.go b/src/runtime/race/testdata/io_test.go
index 1b3ee38..9eb3552 100644
--- a/src/runtime/race/testdata/io_test.go
+++ b/src/runtime/race/testdata/io_test.go
@@ -49,7 +49,7 @@ func TestNoRaceIOHttp(t *testing.T) {
 			fmt.Fprintf(w, "test")
 			x = 42
 		})
-		err := http.ListenAndServe("127.0.0.1:23651", nil)
+		err := http.ListenAndServe(":23651", nil)
 		if err != nil {
 			t.Fatalf("http.ListenAndServe: %v", err)
 		}
diff --git a/src/runtime/race/testdata/mop_test.go b/src/runtime/race/testdata/mop_test.go
index d7cbc98..cb17a27 100644
--- a/src/runtime/race/testdata/mop_test.go
+++ b/src/runtime/race/testdata/mop_test.go
@@ -335,8 +335,6 @@ func TestRaceRange(t *testing.T) {
 			}
 			done <- true
 		}(i)
-		// Ensure the goroutine runs before we continue the loop.
-		runtime.Gosched()
 	}
 	for i := 0; i < N; i++ {
 		<-done
@@ -1065,7 +1063,6 @@ func TestRaceCrawl(t *testing.T) {
 		}()
 		seen[u] = true
 		if d <= 0 {
-			wg.Done()
 			return
 		}
 		urls := [...]string{"a", "b", "c"}
@@ -1587,110 +1584,6 @@ func TestRaceBlockAs(t *testing.T) {
 	<-c
 }
 
-func TestRaceBlockCall1(t *testing.T) {
-	done := make(chan bool)
-	x, y := 0, 0
-	go func() {
-		f := func() (int, int) {
-			return 42, 43
-		}
-		x, y = f()
-		done <- true
-	}()
-	_ = x
-	<-done
-	if x != 42 || y != 43 {
-		panic("corrupted data")
-	}
-}
-func TestRaceBlockCall2(t *testing.T) {
-	done := make(chan bool)
-	x, y := 0, 0
-	go func() {
-		f := func() (int, int) {
-			return 42, 43
-		}
-		x, y = f()
-		done <- true
-	}()
-	_ = y
-	<-done
-	if x != 42 || y != 43 {
-		panic("corrupted data")
-	}
-}
-func TestRaceBlockCall3(t *testing.T) {
-	done := make(chan bool)
-	var x *int
-	y := 0
-	go func() {
-		f := func() (*int, int) {
-			i := 42
-			return &i, 43
-		}
-		x, y = f()
-		done <- true
-	}()
-	_ = x
-	<-done
-	if *x != 42 || y != 43 {
-		panic("corrupted data")
-	}
-}
-func TestRaceBlockCall4(t *testing.T) {
-	done := make(chan bool)
-	x := 0
-	var y *int
-	go func() {
-		f := func() (int, *int) {
-			i := 43
-			return 42, &i
-		}
-		x, y = f()
-		done <- true
-	}()
-	_ = y
-	<-done
-	if x != 42 || *y != 43 {
-		panic("corrupted data")
-	}
-}
-func TestRaceBlockCall5(t *testing.T) {
-	done := make(chan bool)
-	var x *int
-	y := 0
-	go func() {
-		f := func() (*int, int) {
-			i := 42
-			return &i, 43
-		}
-		x, y = f()
-		done <- true
-	}()
-	_ = y
-	<-done
-	if *x != 42 || y != 43 {
-		panic("corrupted data")
-	}
-}
-func TestRaceBlockCall6(t *testing.T) {
-	done := make(chan bool)
-	x := 0
-	var y *int
-	go func() {
-		f := func() (int, *int) {
-			i := 43
-			return 42, &i
-		}
-		x, y = f()
-		done <- true
-	}()
-	_ = x
-	<-done
-	if x != 42 || *y != 43 {
-		panic("corrupted data")
-	}
-}
 func TestRaceSliceSlice(t *testing.T) {
 	c := make(chan bool, 1)
 	x := make([]int, 10)
@@ -1833,16 +1726,13 @@ func TestNoRaceAsFunc4(t *testing.T) {
 }
 
 func TestRaceHeapParam(t *testing.T) {
-	done := make(chan bool)
 	x := func() (x int) {
 		go func() {
 			x = 42
-			done <- true
 		}()
 		return
 	}()
 	_ = x
-	<-done
 }
 
 func TestNoRaceEmptyStruct(t *testing.T) {
diff --git a/src/runtime/race/testdata/rwmutex_test.go b/src/runtime/race/testdata/rwmutex_test.go
index 7ac829d..85cb5df 100644
--- a/src/runtime/race/testdata/rwmutex_test.go
+++ b/src/runtime/race/testdata/rwmutex_test.go
@@ -54,16 +54,13 @@ func TestNoRaceRWMutex(t *testing.T) {
 func TestRaceRWMutexMultipleReaders(t *testing.T) {
 	var mu sync.RWMutex
 	var x, y int64 = 0, 1
-	ch := make(chan bool, 4)
+	ch := make(chan bool, 3)
 	go func() {
 		mu.Lock()
 		defer mu.Unlock()
 		x = 2
 		ch <- true
 	}()
-	// Use three readers so that no matter what order they're
-	// scheduled in, two will be on the same side of the write
-	// lock above.
 	go func() {
 		mu.RLock()
 		y = x + 1
@@ -76,13 +73,6 @@ func TestRaceRWMutexMultipleReaders(t *testing.T) {
 		mu.RUnlock()
 		ch <- true
 	}()
-	go func() {
-		mu.RLock()
-		y = x + 3
-		mu.RUnlock()
-		ch <- true
-	}()
-	<-ch
 	<-ch
 	<-ch
 	<-ch
@@ -92,7 +82,7 @@ func TestRaceRWMutexMultipleReaders(t *testing.T) {
 func TestNoRaceRWMutexMultipleReaders(t *testing.T) {
 	var mu sync.RWMutex
 	x := int64(0)
-	ch := make(chan bool, 4)
+	ch := make(chan bool, 3)
 	go func() {
 		mu.Lock()
 		defer mu.Unlock()
@@ -113,14 +103,6 @@ func TestNoRaceRWMutexMultipleReaders(t *testing.T) {
 		mu.RUnlock()
 		ch <- true
 	}()
-	go func() {
-		mu.RLock()
-		y := x + 3
-		_ = y
-		mu.RUnlock()
-		ch <- true
-	}()
-	<-ch
 	<-ch
 	<-ch
 	<-ch
diff --git a/src/runtime/race/testdata/select_test.go b/src/runtime/race/testdata/select_test.go
index b4b1991..4a3a236 100644
--- a/src/runtime/race/testdata/select_test.go
+++ b/src/runtime/race/testdata/select_test.go
@@ -236,7 +236,7 @@ func TestRaceSelect4(t *testing.T) {
 // there are two variables, access to one
 // of them is synchronized, access to the other
 // is not.
-// Select must (unconditionally) choose the non-synchronized variable
+// Select must (unconditionaly) choose the non-synchronized variable
 // thus causing exactly one race.
 // Currently this test doesn't look like it accomplishes
 // this goal.
diff --git a/src/runtime/race/testdata/slice_test.go b/src/runtime/race/testdata/slice_test.go
index 1ec5243..5702d1a 100644
--- a/src/runtime/race/testdata/slice_test.go
+++ b/src/runtime/race/testdata/slice_test.go
@@ -144,54 +144,6 @@ func TestNoRaceSliceCopyRead(t *testing.T) {
 	<-ch
 }
 
-func TestRacePointerSliceCopyRead(t *testing.T) {
-	ch := make(chan bool, 1)
-	a := make([]*int, 10)
-	b := make([]*int, 10)
-	go func() {
-		_ = a[5]
-		ch <- true
-	}()
-	copy(a, b)
-	<-ch
-}
-
-func TestNoRacePointerSliceWriteCopy(t *testing.T) {
-	ch := make(chan bool, 1)
-	a := make([]*int, 10)
-	b := make([]*int, 10)
-	go func() {
-		a[5] = new(int)
-		ch <- true
-	}()
-	copy(a[:5], b[:5])
-	<-ch
-}
-
-func TestRacePointerSliceCopyWrite2(t *testing.T) {
-	ch := make(chan bool, 1)
-	a := make([]*int, 10)
-	b := make([]*int, 10)
-	go func() {
-		b[5] = new(int)
-		ch <- true
-	}()
-	copy(a, b)
-	<-ch
-}
-
-func TestNoRacePointerSliceCopyRead(t *testing.T) {
-	ch := make(chan bool, 1)
-	a := make([]*int, 10)
-	b := make([]*int, 10)
-	go func() {
-		_ = b[5]
-		ch <- true
-	}()
-	copy(a, b)
-	<-ch
-}
-
 func TestNoRaceSliceWriteSlice2(t *testing.T) {
 	ch := make(chan bool, 1)
 	a := make([]float64, 10)
@@ -443,53 +395,6 @@ func TestRaceSliceAppendString(t *testing.T) {
 	<-c
 }
 
-func TestRacePointerSliceAppend(t *testing.T) {
-	c := make(chan bool, 1)
-	s := make([]*int, 10, 20)
-	go func() {
-		_ = append(s, new(int))
-		c <- true
-	}()
-	_ = append(s, new(int))
-	<-c
-}
-
-func TestRacePointerSliceAppendWrite(t *testing.T) {
-	c := make(chan bool, 1)
-	s := make([]*int, 10)
-	go func() {
-		_ = append(s, new(int))
-		c <- true
-	}()
-	s[0] = new(int)
-	<-c
-}
-
-func TestRacePointerSliceAppendSlice(t *testing.T) {
-	c := make(chan bool, 1)
-	s := make([]*int, 10)
-	go func() {
-		s2 := make([]*int, 10)
-		_ = append(s, s2...)
-		c <- true
-	}()
-	s[0] = new(int)
-	<-c
-}
-
-func TestRacePointerSliceAppendSlice2(t *testing.T) {
-	c := make(chan bool, 1)
-	s := make([]*int, 10)
-	s2foobar := make([]*int, 10)
-	go func() {
-		_ = append(s, s2foobar...)
-		c <- true
-	}()
-	println("WRITE:", &s2foobar[5])
-	s2foobar[5] = nil
-	<-c
-}
-
 func TestNoRaceSliceIndexAccess(t *testing.T) {
 	c := make(chan bool, 1)
 	s := make([]int, 10)
@@ -578,15 +483,3 @@ func TestRaceCompareString(t *testing.T) {
 	s1 = s2
 	<-c
 }
-
-func TestRaceSlice3(t *testing.T) {
-	done := make(chan bool)
-	x := make([]int, 10)
-	i := 2
-	go func() {
-		i = 3
-		done <- true
-	}()
-	_ = x[:1:i]
-	<-done
-}
diff --git a/src/runtime/race/testdata/sync_test.go b/src/runtime/race/testdata/sync_test.go
index d48680d..93af0b1 100644
--- a/src/runtime/race/testdata/sync_test.go
+++ b/src/runtime/race/testdata/sync_test.go
@@ -10,52 +10,72 @@ import (
 	"time"
 )
 
-func TestNoRaceCond(t *testing.T) {
-	x := 0
-	condition := 0
+func TestNoRaceCond(t *testing.T) { // tsan's test02
+	ch := make(chan bool, 1)
+	var x int = 0
 	var mu sync.Mutex
-	cond := sync.NewCond(&mu)
-	go func() {
+	var cond *sync.Cond = sync.NewCond(&mu)
+	var condition int = 0
+	var waker func()
+	waker = func() {
 		x = 1
 		mu.Lock()
 		condition = 1
 		cond.Signal()
 		mu.Unlock()
-	}()
-	mu.Lock()
-	for condition != 1 {
-		cond.Wait()
 	}
-	mu.Unlock()
-	x = 2
+
+	var waiter func()
+	waiter = func() {
+		go waker()
+		cond.L.Lock()
+		for condition != 1 {
+			cond.Wait()
+		}
+		cond.L.Unlock()
+		x = 2
+		ch <- true
+	}
+	go waiter()
+	<-ch
 }
 
-func TestRaceCond(t *testing.T) {
-	done := make(chan bool)
+func TestRaceCond(t *testing.T) { // tsan's test50
+	ch := make(chan bool, 2)
+
+	var x int = 0
 	var mu sync.Mutex
-	cond := sync.NewCond(&mu)
-	x := 0
-	condition := 0
-	go func() {
-		time.Sleep(10 * time.Millisecond) // Enter cond.Wait loop
+	var condition int = 0
+	var cond *sync.Cond = sync.NewCond(&mu)
+
+	var waker func() = func() {
+		<-time.After(1e5)
 		x = 1
 		mu.Lock()
 		condition = 1
 		cond.Signal()
 		mu.Unlock()
-		time.Sleep(10 * time.Millisecond) // Exit cond.Wait loop
+		<-time.After(1e5)
 		mu.Lock()
 		x = 3
 		mu.Unlock()
-		done <- true
-	}()
-	mu.Lock()
-	for condition != 1 {
-		cond.Wait()
+		ch <- true
 	}
-	mu.Unlock()
-	x = 2
-	<-done
+
+	var waiter func() = func() {
+		mu.Lock()
+		for condition != 1 {
+			cond.Wait()
+		}
+		mu.Unlock()
+		x = 2
+		ch <- true
+	}
+	x = 0
+	go waker()
+	go waiter()
+	<-ch
+	<-ch
 }
 
 // We do not currently automatically
diff --git a/src/runtime/race0.go b/src/runtime/race0.go
index 591d5d9..5d90cc8 100644
--- a/src/runtime/race0.go
+++ b/src/runtime/race0.go
@@ -16,22 +16,22 @@ const raceenabled = false
 
 // Because raceenabled is false, none of these functions should be called.
 
-func raceReadObjectPC(t *_type, addr unsafe.Pointer, callerpc, pc uintptr)  { throw("race") }
-func raceWriteObjectPC(t *_type, addr unsafe.Pointer, callerpc, pc uintptr) { throw("race") }
-func raceinit() uintptr                                                     { throw("race"); return 0 }
-func racefini()                                                             { throw("race") }
-func racemapshadow(addr unsafe.Pointer, size uintptr)                       { throw("race") }
-func racewritepc(addr unsafe.Pointer, callerpc, pc uintptr)                 { throw("race") }
-func racereadpc(addr unsafe.Pointer, callerpc, pc uintptr)                  { throw("race") }
-func racereadrangepc(addr unsafe.Pointer, sz, callerpc, pc uintptr)         { throw("race") }
-func racewriterangepc(addr unsafe.Pointer, sz, callerpc, pc uintptr)        { throw("race") }
-func raceacquire(addr unsafe.Pointer)                                       { throw("race") }
-func raceacquireg(gp *g, addr unsafe.Pointer)                               { throw("race") }
-func racerelease(addr unsafe.Pointer)                                       { throw("race") }
-func racereleaseg(gp *g, addr unsafe.Pointer)                               { throw("race") }
-func racereleasemerge(addr unsafe.Pointer)                                  { throw("race") }
-func racereleasemergeg(gp *g, addr unsafe.Pointer)                          { throw("race") }
-func racefingo()                                                            { throw("race") }
-func racemalloc(p unsafe.Pointer, sz uintptr)                               { throw("race") }
-func racegostart(pc uintptr) uintptr                                        { throw("race"); return 0 }
-func racegoend()                                                            { throw("race") }
+func raceReadObjectPC(t *_type, addr unsafe.Pointer, callerpc, pc uintptr)  { gothrow("race") }
+func raceWriteObjectPC(t *_type, addr unsafe.Pointer, callerpc, pc uintptr) { gothrow("race") }
+func raceinit()                                                             { gothrow("race") }
+func racefini()                                                             { gothrow("race") }
+func racemapshadow(addr unsafe.Pointer, size uintptr)                       { gothrow("race") }
+func racewritepc(addr unsafe.Pointer, callerpc, pc uintptr)                 { gothrow("race") }
+func racereadpc(addr unsafe.Pointer, callerpc, pc uintptr)                  { gothrow("race") }
+func racereadrangepc(addr unsafe.Pointer, sz, callerpc, pc uintptr)         { gothrow("race") }
+func racewriterangepc(addr unsafe.Pointer, sz, callerpc, pc uintptr)        { gothrow("race") }
+func raceacquire(addr unsafe.Pointer)                                       { gothrow("race") }
+func raceacquireg(gp *g, addr unsafe.Pointer)                               { gothrow("race") }
+func racerelease(addr unsafe.Pointer)                                       { gothrow("race") }
+func racereleaseg(gp *g, addr unsafe.Pointer)                               { gothrow("race") }
+func racereleasemerge(addr unsafe.Pointer)                                  { gothrow("race") }
+func racereleasemergeg(gp *g, addr unsafe.Pointer)                          { gothrow("race") }
+func racefingo()                                                            { gothrow("race") }
+func racemalloc(p unsafe.Pointer, sz uintptr)                               { gothrow("race") }
+func racegostart(pc uintptr) uintptr                                        { gothrow("race"); return 0 }
+func racegoend()                                                            { gothrow("race") }
diff --git a/src/runtime/race_amd64.s b/src/runtime/race_amd64.s
index d9e674b..a96d9de 100644
--- a/src/runtime/race_amd64.s
+++ b/src/runtime/race_amd64.s
@@ -4,8 +4,7 @@
 
 // +build race
 
-#include "go_asm.h"
-#include "go_tls.h"
+#include "zasm_GOOS_GOARCH.h"
 #include "funcdata.h"
 #include "textflag.h"
 
@@ -58,7 +57,6 @@ TEXT	runtime·racereadpc(SB), NOSPLIT, $0-24
 	MOVQ	addr+0(FP), RARG1
 	MOVQ	callpc+8(FP), RARG2
 	MOVQ	pc+16(FP), RARG3
-	ADDQ	$1, RARG3 // pc is function start, tsan wants return address
 	// void __tsan_read_pc(ThreadState *thr, void *addr, void *callpc, void *pc);
 	MOVQ	$__tsan_read_pc(SB), AX
 	JMP	racecalladdr<>(SB)
@@ -82,7 +80,6 @@ TEXT	runtime·racewritepc(SB), NOSPLIT, $0-24
 	MOVQ	addr+0(FP), RARG1
 	MOVQ	callpc+8(FP), RARG2
 	MOVQ	pc+16(FP), RARG3
-	ADDQ	$1, RARG3 // pc is function start, tsan wants return address
 	// void __tsan_write_pc(ThreadState *thr, void *addr, void *callpc, void *pc);
 	MOVQ	$__tsan_write_pc(SB), AX
 	JMP	racecalladdr<>(SB)
@@ -107,7 +104,6 @@ TEXT	runtime·racereadrangepc1(SB), NOSPLIT, $0-24
 	MOVQ	addr+0(FP), RARG1
 	MOVQ	size+8(FP), RARG2
 	MOVQ	pc+16(FP), RARG3
-	ADDQ	$1, RARG3 // pc is function start, tsan wants return address
 	// void __tsan_read_range(ThreadState *thr, void *addr, uintptr size, void *pc);
 	MOVQ	$__tsan_read_range(SB), AX
 	JMP	racecalladdr<>(SB)
@@ -132,7 +128,6 @@ TEXT	runtime·racewriterangepc1(SB), NOSPLIT, $0-24
 	MOVQ	addr+0(FP), RARG1
 	MOVQ	size+8(FP), RARG2
 	MOVQ	pc+16(FP), RARG3
-	ADDQ	$1, RARG3 // pc is function start, tsan wants return address
 	// void __tsan_write_range(ThreadState *thr, void *addr, uintptr size, void *pc);
 	MOVQ	$__tsan_write_range(SB), AX
 	JMP	racecalladdr<>(SB)
@@ -145,18 +140,18 @@ TEXT	racecalladdr<>(SB), NOSPLIT, $0-0
 	MOVQ	g_racectx(R14), RARG0	// goroutine context
 	// Check that addr is within [arenastart, arenaend) or within [racedatastart, racedataend).
 	CMPQ	RARG1, runtime·racearenastart(SB)
-	JB	data
+	JB	racecalladdr_data
 	CMPQ	RARG1, runtime·racearenaend(SB)
-	JB	call
-data:
+	JB	racecalladdr_call
+racecalladdr_data:
 	CMPQ	RARG1, runtime·racedatastart(SB)
-	JB	ret
+	JB	racecalladdr_ret
 	CMPQ	RARG1, runtime·racedataend(SB)
-	JAE	ret
-call:
+	JAE	racecalladdr_ret
+racecalladdr_call:
 	MOVQ	AX, AX		// w/o this 6a miscompiles this function
 	JMP	racecall<>(SB)
-ret:
+racecalladdr_ret:
 	RET
 
 // func runtime·racefuncenter(pc uintptr)
@@ -229,6 +224,9 @@ TEXT	sync∕atomic·StoreUint64(SB), NOSPLIT, $0-0
 TEXT	sync∕atomic·StoreUintptr(SB), NOSPLIT, $0-0
 	JMP	sync∕atomic·StoreInt64(SB)
 
+TEXT	sync∕atomic·StorePointer(SB), NOSPLIT, $0-0
+	JMP	sync∕atomic·StoreInt64(SB)
+
 // Swap
 TEXT	sync∕atomic·SwapInt32(SB), NOSPLIT, $0-0
 	MOVQ	$__tsan_go_atomic32_exchange(SB), AX
@@ -249,6 +247,9 @@ TEXT	sync∕atomic·SwapUint64(SB), NOSPLIT, $0-0
 TEXT	sync∕atomic·SwapUintptr(SB), NOSPLIT, $0-0
 	JMP	sync∕atomic·SwapInt64(SB)
 
+TEXT	sync∕atomic·SwapPointer(SB), NOSPLIT, $0-0
+	JMP	sync∕atomic·SwapInt64(SB)
+
 // Add
 TEXT	sync∕atomic·AddInt32(SB), NOSPLIT, $0-0
 	MOVQ	$__tsan_go_atomic32_fetch_add(SB), AX
@@ -273,6 +274,9 @@ TEXT	sync∕atomic·AddUint64(SB), NOSPLIT, $0-0
 TEXT	sync∕atomic·AddUintptr(SB), NOSPLIT, $0-0
 	JMP	sync∕atomic·AddInt64(SB)
 
+TEXT	sync∕atomic·AddPointer(SB), NOSPLIT, $0-0
+	JMP	sync∕atomic·AddInt64(SB)
+
 // CompareAndSwap
 TEXT	sync∕atomic·CompareAndSwapInt32(SB), NOSPLIT, $0-0
 	MOVQ	$__tsan_go_atomic32_compare_exchange(SB), AX
@@ -293,6 +297,9 @@ TEXT	sync∕atomic·CompareAndSwapUint64(SB), NOSPLIT, $0-0
 TEXT	sync∕atomic·CompareAndSwapUintptr(SB), NOSPLIT, $0-0
 	JMP	sync∕atomic·CompareAndSwapInt64(SB)
 
+TEXT	sync∕atomic·CompareAndSwapPointer(SB), NOSPLIT, $0-0
+	JMP	sync∕atomic·CompareAndSwapInt64(SB)
+
 // Generic atomic operation implementation.
 // AX already contains target function.
 TEXT	racecallatomic<>(SB), NOSPLIT, $0-0
@@ -359,9 +366,9 @@ TEXT	racecall<>(SB), NOSPLIT, $0-0
 	MOVQ	SP, R12		// callee-saved, preserved across the CALL
 	MOVQ	m_g0(R13), R10
 	CMPQ	R10, R14
-	JE	call	// already on g0
+	JE	racecall_cont	// already on g0
 	MOVQ	(g_sched+gobuf_sp)(R10), SP
-call:
+racecall_cont:
 	ANDQ	$~15, SP	// alignment for gcc ABI
 	CALL	AX
 	MOVQ	R12, SP
@@ -387,9 +394,8 @@ TEXT	runtime·racesymbolizethunk(SB), NOSPLIT, $56-8
 	MOVQ	g_m(R13), R13
 	MOVQ	m_g0(R13), R14
 	MOVQ	R14, g(R12)	// g = m->g0
-	PUSHQ	RARG0	// func arg
+	MOVQ	RARG0, 0(SP)	// func arg
 	CALL	runtime·racesymbolize(SB)
-	POPQ	R12
 	// All registers are smashed after Go code, reload.
 	get_tls(R12)
 	MOVQ	g(R12), R13
diff --git a/src/runtime/rdebug.go b/src/runtime/rdebug.go
index f2766d7..e5e6911 100644
--- a/src/runtime/rdebug.go
+++ b/src/runtime/rdebug.go
@@ -10,6 +10,15 @@ func setMaxStack(in int) (out int) {
 	return out
 }
 
+func setGCPercent(in int32) (out int32) {
+	mp := acquirem()
+	mp.scalararg[0] = uintptr(int(in))
+	onM(setgcpercent_m)
+	out = int32(int(mp.scalararg[0]))
+	releasem(mp)
+	return out
+}
+
 func setPanicOnFault(new bool) (old bool) {
 	mp := acquirem()
 	old = mp.curg.paniconfault
@@ -17,3 +26,12 @@ func setPanicOnFault(new bool) (old bool) {
 	releasem(mp)
 	return old
 }
+
+func setMaxThreads(in int) (out int) {
+	mp := acquirem()
+	mp.scalararg[0] = uintptr(in)
+	onM(setmaxthreads_m)
+	out = int(mp.scalararg[0])
+	releasem(mp)
+	return out
+}
diff --git a/src/runtime/rt0_android_arm.s b/src/runtime/rt0_android_arm.s
index 8571253..6b65fb4 100644
--- a/src/runtime/rt0_android_arm.s
+++ b/src/runtime/rt0_android_arm.s
@@ -9,27 +9,3 @@ TEXT _rt0_arm_android(SB),NOSPLIT,$-4
 	MOVW		$4(R13), R1    // argv
 	MOVW		$_rt0_arm_linux1(SB), R4
 	B		(R4)
-
-// When building with -buildmode=c-shared, this symbol is called when the shared
-// library is loaded.
-TEXT _rt0_arm_android_lib(SB),NOSPLIT,$0
-	MOVW	$1, R0                          // argc
-	MOVW	$_rt0_arm_android_argv(SB), R1  // **argv
-	BL _rt0_arm_linux_lib(SB)
-	RET
-
-DATA _rt0_arm_android_argv+0x00(SB)/4,$_rt0_arm_android_argv0(SB)
-DATA _rt0_arm_android_argv+0x04(SB)/4,$0
-DATA _rt0_arm_android_argv+0x08(SB)/4,$0
-DATA _rt0_arm_android_argv+0x0C(SB)/4,$15      // AT_PLATFORM
-DATA _rt0_arm_android_argv+0x10(SB)/4,$_rt0_arm_android_auxv0(SB)
-DATA _rt0_arm_android_argv+0x14(SB)/4,$16      // AT_HWCAP
-DATA _rt0_arm_android_argv+0x18(SB)/4,$0x2040  // HWCAP_VFP | HWCAP_VFPv3
-DATA _rt0_arm_android_argv+0x1C(SB)/4,$0
-GLOBL _rt0_arm_android_argv(SB),NOPTR,$0x20
-
-DATA _rt0_arm_android_argv0(SB)/8, $"gojni"
-GLOBL _rt0_arm_android_argv0(SB),RODATA,$8
-
-DATA _rt0_arm_android_auxv0(SB)/4, $"v7l"
-GLOBL _rt0_arm_android_auxv0(SB),RODATA,$4
diff --git a/src/runtime/rt0_darwin_amd64.s b/src/runtime/rt0_darwin_amd64.s
index 8d50e96..452d854 100644
--- a/src/runtime/rt0_darwin_amd64.s
+++ b/src/runtime/rt0_darwin_amd64.s
@@ -10,40 +10,6 @@ TEXT _rt0_amd64_darwin(SB),NOSPLIT,$-8
 	MOVQ	$main(SB), AX
 	JMP	AX
 
-// When linking with -shared, this symbol is called when the shared library
-// is loaded.
-TEXT _rt0_amd64_darwin_lib(SB),NOSPLIT,$40
-	MOVQ	DI, _rt0_amd64_darwin_lib_argc<>(SB)
-	MOVQ	SI, _rt0_amd64_darwin_lib_argv<>(SB)
-
-	// Create a new thread to do the runtime initialization and return.
-	MOVQ	_cgo_sys_thread_create(SB), AX
-	TESTQ	AX, AX
-	JZ	nocgo
-	MOVQ	$_rt0_amd64_darwin_lib_go(SB), DI
-	MOVQ	$0, SI
-	CALL	AX
-	RET
-nocgo:
-	MOVQ	$8388608, 0(SP)                    // stacksize
-	MOVQ	$_rt0_amd64_darwin_lib_go(SB), AX
-	MOVQ	AX, 8(SP)                          // fn
-	MOVQ	$0, 16(SP)                         // fnarg
-	MOVQ	$runtime·newosproc0(SB), AX
-	CALL	AX
-	RET
-
-TEXT _rt0_amd64_darwin_lib_go(SB),NOSPLIT,$0
-	MOVQ	_rt0_amd64_darwin_lib_argc<>(SB), DI
-	MOVQ	_rt0_amd64_darwin_lib_argv<>(SB), SI
-	MOVQ	$runtime·rt0_go(SB), AX
-	JMP	AX
-
-DATA _rt0_amd64_darwin_lib_argc<>(SB)/8, $0
-GLOBL _rt0_amd64_darwin_lib_argc<>(SB),NOPTR, $8
-DATA _rt0_amd64_darwin_lib_argv<>(SB)/8, $0
-GLOBL _rt0_amd64_darwin_lib_argv<>(SB),NOPTR, $8
-
 TEXT main(SB),NOSPLIT,$-8
 	MOVQ	$runtime·rt0_go(SB), AX
 	JMP	AX
diff --git a/src/runtime/rt0_dragonfly_386.s b/src/runtime/rt0_dragonfly_386.s
new file mode 100644
index 0000000..548ba79
--- /dev/null
+++ b/src/runtime/rt0_dragonfly_386.s
@@ -0,0 +1,16 @@
+// 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 "textflag.h"
+
+TEXT _rt0_386_dragonfly(SB),NOSPLIT,$8
+	MOVL	8(SP), AX
+	LEAL	12(SP), BX
+	MOVL	AX, 0(SP)
+	MOVL	BX, 4(SP)
+	CALL	main(SB)
+	INT	$3
+
+TEXT main(SB),NOSPLIT,$0
+	JMP	runtime·rt0_go(SB)
diff --git a/src/runtime/rt0_freebsd_arm.s b/src/runtime/rt0_freebsd_arm.s
index e1bb13d..f312526 100644
--- a/src/runtime/rt0_freebsd_arm.s
+++ b/src/runtime/rt0_freebsd_arm.s
@@ -4,8 +4,10 @@
 
 #include "textflag.h"
 
+// FreeBSD and Linux use the same linkage to main
+
 TEXT _rt0_arm_freebsd(SB),NOSPLIT,$-4
-	MOVW	(R13), R0		// argc
+	MOVW	(R13), R0	// argc
 	MOVW	$4(R13), R1		// argv
 	MOVM.DB.W [R0-R1], (R13)
 	B	runtime·rt0_go(SB)
@@ -13,4 +15,4 @@ TEXT _rt0_arm_freebsd(SB),NOSPLIT,$-4
 TEXT main(SB),NOSPLIT,$-4
 	MOVM.DB.W [R0-R1], (R13)
 	MOVW	$runtime·rt0_go(SB), R4
-	B	(R4)
+	B		(R4)
diff --git a/src/runtime/rt0_linux_386.s b/src/runtime/rt0_linux_386.s
index 633e806..352e594 100644
--- a/src/runtime/rt0_linux_386.s
+++ b/src/runtime/rt0_linux_386.s
@@ -9,64 +9,10 @@ TEXT _rt0_386_linux(SB),NOSPLIT,$8
 	LEAL	12(SP), BX
 	MOVL	AX, 0(SP)
 	MOVL	BX, 4(SP)
+	CALL	runtime·linux_setup_vdso(SB)
 	CALL	main(SB)
 	INT	$3
 
-// When building with -buildmode=c-shared, this symbol is called when the shared
-// library is loaded.
-TEXT _rt0_386_linux_lib(SB),NOSPLIT,$0
-	PUSHL	BP
-	MOVL	SP, BP
-	PUSHL	BX
-	PUSHL	SI
-	PUSHL	DI
-
-	MOVL	8(BP), AX
-	MOVL	AX, _rt0_386_linux_lib_argc<>(SB)
-	MOVL	12(BP), AX
-	MOVL	AX, _rt0_386_linux_lib_argv<>(SB)
-
-	SUBL	$8, SP
-
-	// Create a new thread to do the runtime initialization.
-	MOVL	_cgo_sys_thread_create(SB), AX
-	TESTL	AX, AX
-	JZ	nocgo
-	MOVL	$_rt0_386_linux_lib_go(SB), BX
-	MOVL	BX, 0(SP)
-	MOVL	$0, 4(SP)
-	CALL	AX
-	JMP	restore
-
-nocgo:
-	MOVL	$0x800000, 0(SP)                    // stacksize = 8192KB
-	MOVL	$_rt0_386_linux_lib_go(SB), AX
-	MOVL	AX, 4(SP)                           // fn
-	MOVL	$runtime·newosproc0(SB), AX
-	CALL	AX
-
-restore:
-	ADDL	$8, SP
-	POPL	DI
-	POPL	SI
-	POPL	BX
-	POPL	BP
-	RET
-
-TEXT _rt0_386_linux_lib_go(SB),NOSPLIT,$12
-	MOVL	_rt0_386_linux_lib_argc<>(SB), AX
-	MOVL	AX, 0(SP)
-	MOVL	_rt0_386_linux_lib_argv<>(SB), AX
-	MOVL	AX, 4(SP)
-	MOVL	$runtime·rt0_go(SB), AX
-	CALL	AX
-	RET
-
-DATA _rt0_386_linux_lib_argc<>(SB)/4, $0
-GLOBL _rt0_386_linux_lib_argc<>(SB),NOPTR, $4
-DATA _rt0_386_linux_lib_argv<>(SB)/4, $0
-GLOBL _rt0_386_linux_lib_argv<>(SB),NOPTR, $4
-
 TEXT main(SB),NOSPLIT,$0
 	JMP	runtime·rt0_go(SB)
 
diff --git a/src/runtime/rt0_linux_amd64.s b/src/runtime/rt0_linux_amd64.s
index 726b550..985426a 100644
--- a/src/runtime/rt0_linux_amd64.s
+++ b/src/runtime/rt0_linux_amd64.s
@@ -10,55 +10,6 @@ TEXT _rt0_amd64_linux(SB),NOSPLIT,$-8
 	MOVQ	$main(SB), AX
 	JMP	AX
 
-// When building with -buildmode=c-shared, this symbol is called when the shared
-// library is loaded.
-TEXT _rt0_amd64_linux_lib(SB),NOSPLIT,$0x48
-	MOVQ	BX, 0x10(SP)
-	MOVQ	BP, 0x18(SP)
-	MOVQ	R12, 0x20(SP)
-	MOVQ	R13, 0x28(SP)
-	MOVQ	R14, 0x30(SP)
-	MOVQ	R15, 0x38(SP)
-
-	MOVQ	DI, _rt0_amd64_linux_lib_argc<>(SB)
-	MOVQ	SI, _rt0_amd64_linux_lib_argv<>(SB)
-
-	// Create a new thread to do the runtime initialization and return.
-	MOVQ	_cgo_sys_thread_create(SB), AX
-	TESTQ	AX, AX
-	JZ	nocgo
-	MOVQ	$_rt0_amd64_linux_lib_go(SB), DI
-	MOVQ	$0, SI
-	CALL	AX
-	JMP	restore
-
-nocgo:
-	MOVQ	$8388608, 0(SP)                    // stacksize
-	MOVQ	$_rt0_amd64_linux_lib_go(SB), AX
-	MOVQ	AX, 8(SP)                          // fn
-	MOVQ	$runtime·newosproc0(SB), AX
-	CALL	AX
-
-restore:
-	MOVQ	0x10(SP), BX
-	MOVQ	0x18(SP), BP
-	MOVQ	0x20(SP), R12
-	MOVQ	0x28(SP), R13
-	MOVQ	0x30(SP), R14
-	MOVQ	0x38(SP), R15
-	RET
-
-TEXT _rt0_amd64_linux_lib_go(SB),NOSPLIT,$0
-	MOVQ	_rt0_amd64_linux_lib_argc<>(SB), DI
-	MOVQ	_rt0_amd64_linux_lib_argv<>(SB), SI
-	MOVQ	$runtime·rt0_go(SB), AX
-	JMP	AX
-
-DATA _rt0_amd64_linux_lib_argc<>(SB)/8, $0
-GLOBL _rt0_amd64_linux_lib_argc<>(SB),NOPTR, $8
-DATA _rt0_amd64_linux_lib_argv<>(SB)/8, $0
-GLOBL _rt0_amd64_linux_lib_argv<>(SB),NOPTR, $8
-
 TEXT main(SB),NOSPLIT,$-8
 	MOVQ	$runtime·rt0_go(SB), AX
 	JMP	AX
diff --git a/src/runtime/rt0_linux_arm.s b/src/runtime/rt0_linux_arm.s
index b71a3f9..5f521d2 100644
--- a/src/runtime/rt0_linux_arm.s
+++ b/src/runtime/rt0_linux_arm.s
@@ -10,58 +10,6 @@ TEXT _rt0_arm_linux(SB),NOSPLIT,$-4
 	MOVW	$_rt0_arm_linux1(SB), R4
 	B		(R4)
 
-// When building with -buildmode=c-shared, this symbol is called when the shared
-// library is loaded.
-TEXT _rt0_arm_linux_lib(SB),NOSPLIT,$32
-	// Preserve callee-save registers.  Raspberry Pi's dlopen(), for example,
-	// actually cares that R11 is preserved.
-	MOVW	R4, 12(R13)
-	MOVW	R5, 16(R13)
-	MOVW	R6, 20(R13)
-	MOVW	R7, 24(R13)
-	MOVW	R8, 28(R13)
-	MOVW	R11, 32(R13)
-
-	// Save argc/argv.
-	MOVW	R0, _rt0_arm_linux_lib_argc<>(SB)
-	MOVW	R1, _rt0_arm_linux_lib_argv<>(SB)
-
-	// Create a new thread to do the runtime initialization.
-	MOVW	_cgo_sys_thread_create(SB), R2
-	CMP	$0, R2
-	BEQ	nocgo
-	MOVW	$_rt0_arm_linux_lib_go<>(SB), R0
-	MOVW	$0, R1
-	BL	(R2)
-	B	rr
-nocgo:
-	MOVW	$0x800000, R0                     // stacksize = 8192KB
-	MOVW	$_rt0_arm_linux_lib_go<>(SB), R1  // fn
-	MOVW	R0, 4(R13)
-	MOVW	R1, 8(R13)
-	BL	runtime·newosproc0(SB)
-rr:
-	// Restore callee-save registers and return.
-	MOVW	12(R13), R4
-	MOVW	16(R13), R5
-	MOVW	20(R13), R6
-	MOVW	24(R13), R7
-	MOVW	28(R13), R8
-	MOVW	32(R13), R11
-	RET
-
-TEXT _rt0_arm_linux_lib_go<>(SB),NOSPLIT,$8
-	MOVW	_rt0_arm_linux_lib_argc<>(SB), R0
-	MOVW	_rt0_arm_linux_lib_argv<>(SB), R1
-	MOVW	R0, 0(R13)
-	MOVW	R1, 4(R13)
-	B	runtime·rt0_go(SB)
-
-DATA _rt0_arm_linux_lib_argc<>(SB)/4,$0
-GLOBL _rt0_arm_linux_lib_argc<>(SB),NOPTR,$4
-DATA _rt0_arm_linux_lib_argv<>(SB)/4,$0
-GLOBL _rt0_arm_linux_lib_argv<>(SB),NOPTR,$4
-
 TEXT _rt0_arm_linux1(SB),NOSPLIT,$-4
 	// We first need to detect the kernel ABI, and warn the user
 	// if the system only supports OABI
@@ -105,6 +53,9 @@ TEXT _rt0_arm_linux1(SB),NOSPLIT,$-4
 	// SWI	$0 // restore signal handler
 	// ADD	$32, R13
 
+	SUB	$4, R13 // fake a stack frame for runtime·setup_auxv
+	BL	runtime·setup_auxv(SB)
+	ADD	$4, R13
 	B	runtime·rt0_go(SB)
 
 TEXT bad_abi<>(SB),NOSPLIT,$-4
@@ -129,7 +80,7 @@ DATA bad_abi_msg+0x2c(SB)/1, $0xa
 GLOBL bad_abi_msg(SB), RODATA, $45
 
 TEXT oabi_syscall<>(SB),NOSPLIT,$-4
-	ADD $1, R15, R4 // R15 is hardware PC
+	ADD $1, PC, R4
 	WORD $0xe12fff14 //BX	(R4) // enter thumb mode
 	// TODO(minux): only supports little-endian CPUs
 	WORD $0x4770df01 // swi $1; bx lr
diff --git a/src/runtime/rt0_netbsd_arm.s b/src/runtime/rt0_netbsd_arm.s
index 2cb1182..bad66e0 100644
--- a/src/runtime/rt0_netbsd_arm.s
+++ b/src/runtime/rt0_netbsd_arm.s
@@ -4,8 +4,10 @@
 
 #include "textflag.h"
 
+// FreeBSD/NetBSD and Linux use the same linkage to main
+
 TEXT _rt0_arm_netbsd(SB),NOSPLIT,$-4
-	MOVW	(R13), R0		// argc
+	MOVW	(R13), R0	// argc
 	MOVW	$4(R13), R1		// argv
 	MOVM.DB.W [R0-R1], (R13)
 	B runtime·rt0_go(SB)
diff --git a/src/runtime/rt0_windows_386.s b/src/runtime/rt0_windows_386.s
index 03f95d1..3c2deda 100644
--- a/src/runtime/rt0_windows_386.s
+++ b/src/runtime/rt0_windows_386.s
@@ -10,9 +10,9 @@ TEXT _rt0_386_windows(SB),NOSPLIT,$12
 	MOVL	AX, 4(SP)
 	MOVL	BX, 8(SP)
 	MOVL	$-1, 0(SP) // return PC for main
-	JMP	_main(SB)
+	JMP	main(SB)
 
-TEXT _main(SB),NOSPLIT,$0
+TEXT main(SB),NOSPLIT,$0
 	JMP	runtime·rt0_go(SB)
 
 
diff --git a/src/runtime/rt0_windows_amd64.s b/src/runtime/rt0_windows_amd64.s
index df956ba..197f52e 100644
--- a/src/runtime/rt0_windows_amd64.s
+++ b/src/runtime/rt0_windows_amd64.s
@@ -2,8 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-#include "go_asm.h"
-#include "go_tls.h"
+#include "zasm_GOOS_GOARCH.h"
 #include "textflag.h"
 
 TEXT _rt0_amd64_windows(SB),NOSPLIT,$-8
diff --git a/src/runtime/rune.go b/src/runtime/rune.go
index 99c38e0..a9f6835 100644
--- a/src/runtime/rune.go
+++ b/src/runtime/rune.go
@@ -15,7 +15,7 @@
 
 /*
  * This code is copied, with slight editing due to type differences,
- * from a subset of ../lib9/utf/rune.c [which no longer exists]
+ * from a subset of ../lib9/utf/rune.c
  */
 
 package runtime
diff --git a/src/runtime/runtime-gdb.py b/src/runtime/runtime-gdb.py
index e57fa00..eedac7c 100644
--- a/src/runtime/runtime-gdb.py
+++ b/src/runtime/runtime-gdb.py
@@ -28,31 +28,6 @@ goobjfile = gdb.current_objfile() or gdb.objfiles()[0]
 goobjfile.pretty_printers = []
 
 #
-#  Value wrappers
-#
-
-class SliceValue:
-	"Wrapper for slice values."
-
-	def __init__(self, val):
-		self.val = val
-
-	@property
-	def len(self):
-		return int(self.val['len'])
-
-	@property
-	def cap(self):
-		return int(self.val['cap'])
-
-	def __getitem__(self, i):
-		if i < 0 or i >= self.len:
-			raise IndexError(i)
-		ptr = self.val["array"]
-		return (ptr + i).dereference()
-
-
-#
 #  Pretty Printers
 #
 
@@ -60,7 +35,7 @@ class SliceValue:
 class StringTypePrinter:
 	"Pretty print Go strings."
 
-	pattern = re.compile(r'^struct string( \*)?$')
+	pattern = re.compile(r'^struct string$')
 
 	def __init__(self, val):
 		self.val = val
@@ -88,11 +63,11 @@ class SliceTypePrinter:
 		return str(self.val.type)[6:]  # skip 'struct '
 
 	def children(self):
-		sval = SliceValue(self.val)
-		if sval.len > sval.cap:
+		if self.val["len"] > self.val["cap"]:
 			return
-		for idx, item in enumerate(sval):
-			yield ('[{0}]'.format(idx), item)
+		ptr = self.val["array"]
+		for idx in range(int(self.val["len"])):
+			yield ('[{0}]'.format(idx), (ptr + idx).dereference())
 
 
 class MapTypePrinter:
@@ -114,7 +89,7 @@ class MapTypePrinter:
 		return str(self.val.type)
 
 	def children(self):
-		B = self.val['B']
+		B = self.val['b']
 		buckets = self.val['buckets']
 		oldbuckets = self.val['oldbuckets']
 		flags = self.val['flags']
@@ -227,6 +202,8 @@ def lookup_type(name):
 	except gdb.error:
 		pass
 
+_rctp_type = gdb.lookup_type("struct runtime.rtype").pointer()
+
 
 def iface_commontype(obj):
 	if is_iface(obj):
@@ -236,7 +213,7 @@ def iface_commontype(obj):
 	else:
 		return
 
-	return go_type_ptr.cast(gdb.lookup_type("struct reflect.rtype").pointer()).dereference()
+	return go_type_ptr.cast(_rctp_type).dereference()
 
 
 def iface_dtype(obj):
@@ -378,8 +355,8 @@ class GoroutinesCmd(gdb.Command):
 	def invoke(self, _arg, _from_tty):
 		# args = gdb.string_to_argv(arg)
 		vp = gdb.lookup_type('void').pointer()
-		for ptr in SliceValue(gdb.parse_and_eval("'runtime.allgs'")):
-			if ptr['atomicstatus'] == 6:  # 'gdead'
+		for ptr in linked_list(gdb.parse_and_eval("'runtime.allg'"), 'alllink'):
+			if ptr['status'] == 6:  # 'gdead'
 				continue
 			s = ' '
 			if ptr['m']:
@@ -393,12 +370,9 @@ class GoroutinesCmd(gdb.Command):
 				#python3 / newer versions of gdb
 				pc = int(pc)
 			except gdb.error:
-				# str(pc) can return things like
-				# "0x429d6c <runtime.gopark+284>", so
-				# chop at first space.
-				pc = int(str(pc).split(None, 1)[0], 16)
+				pc = int(str(pc), 16)
 			blk = gdb.block_for_pc(pc)
-			print(s, ptr['goid'], "{0:8s}".format(sts[int(ptr['atomicstatus'])]), blk.function)
+			print(s, ptr['goid'], "{0:8s}".format(sts[int(ptr['status'])]), blk.function)
 
 
 def find_goroutine(goid):
@@ -412,8 +386,8 @@ def find_goroutine(goid):
 	@return tuple (gdb.Value, gdb.Value)
 	"""
 	vp = gdb.lookup_type('void').pointer()
-	for ptr in SliceValue(gdb.parse_and_eval("'runtime.allgs'")):
-		if ptr['atomicstatus'] == 6:  # 'gdead'
+	for ptr in linked_list(gdb.parse_and_eval("'runtime.allg'"), 'alllink'):
+		if ptr['status'] == 6:  # 'gdead'
 			continue
 		if ptr['goid'] == goid:
 			return (ptr['sched'][x].cast(vp) for x in ('pc', 'sp'))
@@ -446,7 +420,7 @@ class GoroutineCmd(gdb.Command):
 			#python3 / newer versions of gdb
 			pc = int(pc)
 		except gdb.error:
-			pc = int(str(pc).split(None, 1)[0], 16)
+			pc = int(str(pc), 16)
 		save_frame = gdb.selected_frame()
 		gdb.parse_and_eval('$save_pc = $pc')
 		gdb.parse_and_eval('$save_sp = $sp')
diff --git a/src/runtime/runtime.c b/src/runtime/runtime.c
new file mode 100644
index 0000000..c823691
--- /dev/null
+++ b/src/runtime/runtime.c
@@ -0,0 +1,399 @@
+// 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 "stack.h"
+#include "arch_GOARCH.h"
+#include "textflag.h"
+#include "malloc.h"
+
+// 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 = 2<<1;
+
+// The GOTRACEBACK environment variable controls the
+// behavior of a Go program that is crashing and exiting.
+//	GOTRACEBACK=0   suppress all tracebacks
+//	GOTRACEBACK=1   default behavior - show tracebacks but exclude runtime frames
+//	GOTRACEBACK=2   show tracebacks including runtime frames
+//	GOTRACEBACK=crash   show tracebacks including runtime frames, then crash (core dump etc)
+#pragma textflag NOSPLIT
+int32
+runtime·gotraceback(bool *crash)
+{
+	if(crash != nil)
+		*crash = false;
+	if(g->m->traceback != 0)
+		return g->m->traceback;
+	if(crash != nil)
+		*crash = traceback_cache&1;
+	return traceback_cache>>1;
+}
+
+int32
+runtime·mcmp(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;
+	}
+	return 0;
+}
+
+
+byte*
+runtime·mchr(byte *p, byte c, byte *ep)
+{
+	for(; p < ep; p++)
+		if(*p == c)
+			return p;
+	return nil;
+}
+
+static int32	argc;
+
+#pragma dataflag NOPTR /* argv not a heap pointer */
+static uint8**	argv;
+
+extern Slice runtime·argslice;
+extern Slice runtime·envs;
+
+void (*runtime·sysargs)(int32, uint8**);
+
+void
+runtime·args(int32 c, uint8 **v)
+{
+	argc = c;
+	argv = v;
+	if(runtime·sysargs != nil)
+		runtime·sysargs(c, v);
+}
+
+int32 runtime·isplan9;
+int32 runtime·issolaris;
+int32 runtime·iswindows;
+
+// Information about what cpu features are available.
+// Set on startup in asm_{x86/amd64}.s.
+uint32 runtime·cpuid_ecx;
+uint32 runtime·cpuid_edx;
+
+void
+runtime·goargs(void)
+{
+	String *s;
+	int32 i;
+
+	// for windows implementation see "os" package
+	if(Windows)
+		return;
+
+	runtime·argslice = runtime·makeStringSlice(argc);
+	s = (String*)runtime·argslice.array;
+	for(i=0; i<argc; i++)
+		s[i] = runtime·gostringnocopy(argv[i]);
+}
+
+void
+runtime·goenvs_unix(void)
+{
+	String *s;
+	int32 i, n;
+
+	for(n=0; argv[argc+1+n] != 0; n++)
+		;
+
+	runtime·envs = runtime·makeStringSlice(n);
+	s = (String*)runtime·envs.array;
+	for(i=0; i<n; i++)
+		s[i] = runtime·gostringnocopy(argv[argc+1+i]);
+}
+
+#pragma textflag NOSPLIT
+Slice
+runtime·environ()
+{
+	return runtime·envs;
+}
+
+int32
+runtime·atoi(byte *p)
+{
+	int32 n;
+
+	n = 0;
+	while('0' <= *p && *p <= '9')
+		n = n*10 + *p++ - '0';
+	return n;
+}
+
+static void
+TestAtomic64(void)
+{
+	uint64 z64, x64;
+
+	z64 = 42;
+	x64 = 0;
+	PREFETCH(&z64);
+	if(runtime·cas64(&z64, x64, 1))
+		runtime·throw("cas64 failed");
+	if(x64 != 0)
+		runtime·throw("cas64 failed");
+	x64 = 42;
+	if(!runtime·cas64(&z64, x64, 1))
+		runtime·throw("cas64 failed");
+	if(x64 != 42 || z64 != 1)
+		runtime·throw("cas64 failed");
+	if(runtime·atomicload64(&z64) != 1)
+		runtime·throw("load64 failed");
+	runtime·atomicstore64(&z64, (1ull<<40)+1);
+	if(runtime·atomicload64(&z64) != (1ull<<40)+1)
+		runtime·throw("store64 failed");
+	if(runtime·xadd64(&z64, (1ull<<40)+1) != (2ull<<40)+2)
+		runtime·throw("xadd64 failed");
+	if(runtime·atomicload64(&z64) != (2ull<<40)+2)
+		runtime·throw("xadd64 failed");
+	if(runtime·xchg64(&z64, (3ull<<40)+3) != (2ull<<40)+2)
+		runtime·throw("xchg64 failed");
+	if(runtime·atomicload64(&z64) != (3ull<<40)+3)
+		runtime·throw("xchg64 failed");
+}
+
+void
+runtime·check(void)
+{
+	int8 a;
+	uint8 b;
+	int16 c;
+	uint16 d;
+	int32 e;
+	uint32 f;
+	int64 g;
+	uint64 h;
+	float32 i, i1;
+	float64 j, j1;
+	byte *k, *k1;
+	uint16* l;
+	struct x1 {
+		byte x;
+	};
+	struct y1 {
+		struct x1 x1;
+		byte y;
+	};
+
+	if(sizeof(a) != 1) runtime·throw("bad a");
+	if(sizeof(b) != 1) runtime·throw("bad b");
+	if(sizeof(c) != 2) runtime·throw("bad c");
+	if(sizeof(d) != 2) runtime·throw("bad d");
+	if(sizeof(e) != 4) runtime·throw("bad e");
+	if(sizeof(f) != 4) runtime·throw("bad f");
+	if(sizeof(g) != 8) runtime·throw("bad g");
+	if(sizeof(h) != 8) runtime·throw("bad h");
+	if(sizeof(i) != 4) runtime·throw("bad i");
+	if(sizeof(j) != 8) runtime·throw("bad j");
+	if(sizeof(k) != sizeof(uintptr)) runtime·throw("bad k");
+	if(sizeof(l) != sizeof(uintptr)) runtime·throw("bad l");
+	if(sizeof(struct x1) != 1) runtime·throw("bad sizeof x1");
+	if(offsetof(struct y1, y) != 1) runtime·throw("bad offsetof y1.y");
+	if(sizeof(struct y1) != 2) runtime·throw("bad sizeof y1");
+
+	if(runtime·timediv(12345LL*1000000000+54321, 1000000000, &e) != 12345 || e != 54321)
+		runtime·throw("bad timediv");
+
+	uint32 z;
+	z = 1;
+	if(!runtime·cas(&z, 1, 2))
+		runtime·throw("cas1");
+	if(z != 2)
+		runtime·throw("cas2");
+
+	z = 4;
+	if(runtime·cas(&z, 5, 6))
+		runtime·throw("cas3");
+	if(z != 4)
+		runtime·throw("cas4");
+
+	k = (byte*)0xfedcb123;
+	if(sizeof(void*) == 8)
+		k = (byte*)((uintptr)k<<10);
+	if(runtime·casp((void**)&k, nil, nil))
+		runtime·throw("casp1");
+	k1 = k+1;
+	if(!runtime·casp((void**)&k, k, k1))
+		runtime·throw("casp2");
+	if(k != k1)
+		runtime·throw("casp3");
+
+	*(uint64*)&j = ~0ULL;
+	if(j == j)
+		runtime·throw("float64nan");
+	if(!(j != j))
+		runtime·throw("float64nan1");
+
+	*(uint64*)&j1 = ~1ULL;
+	if(j == j1)
+		runtime·throw("float64nan2");
+	if(!(j != j1))
+		runtime·throw("float64nan3");
+
+	*(uint32*)&i = ~0UL;
+	if(i == i)
+		runtime·throw("float32nan");
+	if(!(i != i))
+		runtime·throw("float32nan1");
+
+	*(uint32*)&i1 = ~1UL;
+	if(i == i1)
+		runtime·throw("float32nan2");
+	if(!(i != i1))
+		runtime·throw("float32nan3");
+
+	TestAtomic64();
+
+	if(FixedStack != runtime·round2(FixedStack))
+		runtime·throw("FixedStack is not power-of-2");
+}
+
+#pragma dataflag NOPTR
+DebugVars	runtime·debug;
+
+typedef struct DbgVar DbgVar;
+struct DbgVar
+{
+	int8*	name;
+	int32*	value;
+};
+
+// Do we report invalid pointers found during stack or heap scans?
+int32 runtime·invalidptr = 1;
+
+#pragma dataflag NOPTR /* dbgvar has no heap pointers */
+static DbgVar dbgvar[] = {
+	{"allocfreetrace", &runtime·debug.allocfreetrace},
+	{"invalidptr", &runtime·invalidptr},
+	{"efence", &runtime·debug.efence},
+	{"gctrace", &runtime·debug.gctrace},
+	{"gcdead", &runtime·debug.gcdead},
+	{"scheddetail", &runtime·debug.scheddetail},
+	{"schedtrace", &runtime·debug.schedtrace},
+	{"scavenge", &runtime·debug.scavenge},
+};
+
+void
+runtime·parsedebugvars(void)
+{
+	byte *p;
+	intgo i, n;
+
+	p = runtime·getenv("GODEBUG");
+	if(p != nil){
+		for(;;) {
+			for(i=0; i<nelem(dbgvar); i++) {
+				n = runtime·findnull((byte*)dbgvar[i].name);
+				if(runtime·mcmp(p, (byte*)dbgvar[i].name, n) == 0 && p[n] == '=')
+					*dbgvar[i].value = runtime·atoi(p+n+1);
+			}
+			p = runtime·strstr(p, (byte*)",");
+			if(p == nil)
+				break;
+			p++;
+		}
+	}
+
+	p = runtime·getenv("GOTRACEBACK");
+	if(p == nil)
+		p = (byte*)"";
+	if(p[0] == '\0')
+		traceback_cache = 1<<1;
+	else if(runtime·strcmp(p, (byte*)"crash") == 0)
+		traceback_cache = (2<<1) | 1;
+	else
+		traceback_cache = runtime·atoi(p)<<1;	
+}
+
+// Poor mans 64-bit division.
+// This is a very special function, do not use it if you are not sure what you are doing.
+// int64 division is lowered into _divv() call on 386, which does not fit into nosplit functions.
+// Handles overflow in a time-specific manner.
+#pragma textflag NOSPLIT
+int32
+runtime·timediv(int64 v, int32 div, int32 *rem)
+{
+	int32 res, bit;
+
+	res = 0;
+	for(bit = 30; bit >= 0; bit--) {
+		if(v >= ((int64)div<<bit)) {
+			v = v - ((int64)div<<bit);
+			res += 1<<bit;
+		}
+	}
+	if(v >= (int64)div) {
+		if(rem != nil)
+			*rem = 0;
+		return 0x7fffffff;
+	}
+	if(rem != nil)
+		*rem = v;
+	return res;
+}
+
+// Helpers for Go. Must be NOSPLIT, must only call NOSPLIT functions, and must not block.
+
+#pragma textflag NOSPLIT
+G*
+runtime·getg(void)
+{
+	return g;
+}
+
+#pragma textflag NOSPLIT
+M*
+runtime·acquirem(void)
+{
+	g->m->locks++;
+	return g->m;
+}
+
+#pragma textflag NOSPLIT
+void
+runtime·releasem(M *mp)
+{
+	mp->locks--;
+	if(mp->locks == 0 && g->preempt) {
+		// restore the preemption request in case we've cleared it in newstack
+		g->stackguard0 = StackPreempt;
+	}
+}
+
+#pragma textflag NOSPLIT
+MCache*
+runtime·gomcache(void)
+{
+	return g->m->mcache;
+}
+
+#pragma textflag NOSPLIT
+Slice
+reflect·typelinks(void)
+{
+	extern Type *runtime·typelink[], *runtime·etypelink[];
+	Slice ret;
+
+	ret.array = (byte*)runtime·typelink;
+	ret.len = runtime·etypelink - runtime·typelink;
+	ret.cap = ret.len;
+	return ret;
+}
diff --git a/src/runtime/runtime.go b/src/runtime/runtime.go
index 2387d9a..4e4e1d1 100644
--- a/src/runtime/runtime.go
+++ b/src/runtime/runtime.go
@@ -4,14 +4,8 @@
 
 package runtime
 
-import _ "unsafe" // for go:linkname
-
-//go:generate go run wincallback.go
-//go:generate go run mkduff.go
-
 var ticks struct {
 	lock mutex
-	pad  uint32 // ensure 8-byte alignment of val on 386
 	val  uint64
 }
 
@@ -44,11 +38,23 @@ func tickspersecond() int64 {
 	return r
 }
 
+func makeStringSlice(n int) []string {
+	return make([]string, n)
+}
+
+// TODO: Move to parfor.go when parfor.c becomes parfor.go.
+func parforalloc(nthrmax uint32) *parfor {
+	return &parfor{
+		thr:     &make([]parforthread, nthrmax)[0],
+		nthrmax: nthrmax,
+	}
+}
+
 var envs []string
 var argslice []string
 
-//go:linkname syscall_runtime_envs syscall.runtime_envs
-func syscall_runtime_envs() []string { return append([]string{}, envs...) }
+// called from syscall
+func runtime_envs() []string { return envs }
 
-//go:linkname os_runtime_args os.runtime_args
-func os_runtime_args() []string { return append([]string{}, argslice...) }
+// called from os
+func runtime_args() []string { return argslice }
diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h
new file mode 100644
index 0000000..177a128
--- /dev/null
+++ b/src/runtime/runtime.h
@@ -0,0 +1,1132 @@
+// 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.
+
+/*
+ * basic types
+ */
+typedef	signed char		int8;
+typedef	unsigned char		uint8;
+typedef	signed short		int16;
+typedef	unsigned short		uint16;
+typedef	signed int		int32;
+typedef	unsigned int		uint32;
+typedef	signed long long int	int64;
+typedef	unsigned long long int	uint64;
+typedef	float			float32;
+typedef	double			float64;
+
+#ifdef _64BIT
+typedef	uint64		uintptr;
+typedef	int64		intptr;
+typedef	int64		intgo; // Go's int
+typedef	uint64		uintgo; // Go's uint
+#else
+typedef	uint32		uintptr;
+typedef	int32		intptr;
+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,
+ * which will show "last name: XXunsigned".
+ */
+#define	unsigned		XXunsigned / / /
+#define	signed			XXsigned / / /
+#define	char			XXchar / / /
+#define	short			XXshort / / /
+#define	int			XXint / / /
+#define	long			XXlong / / /
+#define	float			XXfloat / / /
+#define	double			XXdouble / / /
+
+/*
+ * defined types
+ */
+typedef	uint8			bool;
+typedef	uint8			byte;
+typedef	struct	Func		Func;
+typedef	struct	G		G;
+typedef	struct	Gobuf		Gobuf;
+typedef	struct	SudoG		SudoG;
+typedef	struct	Mutex		Mutex;
+typedef	struct	M		M;
+typedef	struct	P		P;
+typedef	struct	SchedT	SchedT;
+typedef	struct	Note		Note;
+typedef	struct	Slice		Slice;
+typedef	struct	String		String;
+typedef	struct	FuncVal		FuncVal;
+typedef	struct	SigTab		SigTab;
+typedef	struct	MCache		MCache;
+typedef	struct	FixAlloc	FixAlloc;
+typedef	struct	Iface		Iface;
+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	Panic		Panic;
+typedef	struct	Hmap		Hmap;
+typedef	struct	Hiter		Hiter;
+typedef	struct	Hchan		Hchan;
+typedef	struct	Complex64	Complex64;
+typedef	struct	Complex128	Complex128;
+typedef	struct	LibCall		LibCall;
+typedef	struct	WinCallbackContext	WinCallbackContext;
+typedef	struct	GCStats		GCStats;
+typedef	struct	LFNode		LFNode;
+typedef	struct	ParFor		ParFor;
+typedef	struct	ParForThread	ParForThread;
+typedef	struct	CgoMal		CgoMal;
+typedef	struct	PollDesc	PollDesc;
+typedef	struct	DebugVars	DebugVars;
+typedef	struct	ForceGCState	ForceGCState;
+typedef	struct	Stack		Stack;
+
+/*
+ * Per-CPU declaration.
+ *
+ * "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 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(TLS) as -8(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
+ * registers. The Go compiler (6g, 8g, etc.) knows to avoid them.
+ */
+extern	register	G*	g;
+
+/*
+ * defined constants
+ */
+enum
+{
+	// G status
+	//
+	// If you add to this list, add to the list
+	// of "okay during garbage collection" status
+	// in mgc0.c too.
+	Gidle,                                 // 0
+	Grunnable,                             // 1 runnable and on a run queue
+	Grunning,                              // 2
+	Gsyscall,                              // 3
+	Gwaiting,                              // 4
+	Gmoribund_unused,                      // 5 currently unused, but hardcoded in gdb scripts
+	Gdead,                                 // 6
+	Genqueue,                              // 7 Only the Gscanenqueue is used.
+	Gcopystack,                            // 8 in this state when newstack is moving the stack
+	// the following encode that the GC is scanning the stack and what to do when it is done 
+	Gscan = 0x1000,                        // atomicstatus&~Gscan = the non-scan state,
+	// Gscanidle =     Gscan + Gidle,      // Not used. Gidle only used with newly malloced gs
+	Gscanrunnable = Gscan + Grunnable,     //  0x1001 When scanning complets make Grunnable (it is already on run queue)
+	Gscanrunning =  Gscan + Grunning,      //  0x1002 Used to tell preemption newstack routine to scan preempted stack.
+	Gscansyscall =  Gscan + Gsyscall,      //  0x1003 When scanning completes make is Gsyscall
+	Gscanwaiting =  Gscan + Gwaiting,      //  0x1004 When scanning completes make it Gwaiting
+	// Gscanmoribund_unused,               //  not possible
+	// Gscandead,                          //  not possible
+	Gscanenqueue = Gscan + Genqueue,       //  When scanning completes make it Grunnable and put on runqueue
+};
+enum
+{
+	// P status
+	Pidle,
+	Prunning,
+	Psyscall,
+	Pgcstop,
+	Pdead,
+};
+enum
+{
+	true	= 1,
+	false	= 0,
+};
+enum
+{
+	PtrSize = sizeof(void*),
+};
+/*
+ * structures
+ */
+struct	Mutex
+{
+	// Futex-based impl treats it as uint32 key,
+	// while sema-based impl as M* waitm.
+	// Used to be a union, but unions break precise GC.
+	uintptr	key;
+};
+struct	Note
+{
+	// Futex-based impl treats it as uint32 key,
+	// while sema-based impl as M* waitm.
+	// Used to be a union, but unions break precise GC.
+	uintptr	key;
+};
+struct String
+{
+	byte*	str;
+	intgo	len;
+};
+struct FuncVal
+{
+	void	(*fn)(void);
+	// variable-size, fn-specific data here
+};
+struct Iface
+{
+	Itab*	tab;
+	void*	data;
+};
+struct Eface
+{
+	Type*	type;
+	void*	data;
+};
+struct Complex64
+{
+	float32	real;
+	float32	imag;
+};
+struct Complex128
+{
+	float64	real;
+	float64	imag;
+};
+
+struct	Slice
+{				// must not move anything
+	byte*	array;		// actual data
+	uintgo	len;		// number of elements
+	uintgo	cap;		// allocated number of elements
+};
+struct	Gobuf
+{
+	// The offsets of sp, pc, and g are known to (hard-coded in) libmach.
+	uintptr	sp;
+	uintptr	pc;
+	G*	g;
+	void*	ctxt; // this has to be a pointer so that GC scans it
+	uintreg	ret;
+	uintptr	lr;
+};
+// Known to compiler.
+// Changes here must also be made in src/cmd/gc/select.c's selecttype.
+struct	SudoG
+{
+	G*	g;
+	uint32*	selectdone;
+	SudoG*	next;
+	SudoG*	prev;
+	void*	elem;		// data element
+	int64	releasetime;
+	int32	nrelease;	// -1 for acquire
+	SudoG*	waitlink;	// G.waiting list
+};
+struct	GCStats
+{
+	// the struct must consist of only uint64's,
+	// because it is casted to uint64[].
+	uint64	nhandoff;
+	uint64	nhandoffcnt;
+	uint64	nprocyield;
+	uint64	nosyield;
+	uint64	nsleep;
+};
+
+struct	LibCall
+{
+	uintptr	fn;
+	uintptr	n;	// number of parameters
+	uintptr	args;	// parameters
+	uintptr	r1;	// return values
+	uintptr	r2;
+	uintptr	err;	// error number
+};
+
+// 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;
+};
+
+// Stack describes a Go execution stack.
+// The bounds of the stack are exactly [lo, hi),
+// with no implicit data structures on either side.
+struct	Stack
+{
+	uintptr	lo;
+	uintptr	hi;
+};
+
+struct	G
+{
+	// Stack parameters.
+	// stack describes the actual stack memory: [stack.lo, stack.hi).
+	// stackguard0 is the stack pointer compared in the Go stack growth prologue.
+	// It is stack.lo+StackGuard normally, but can be StackPreempt to trigger a preemption.
+	// stackguard1 is the stack pointer compared in the C stack growth prologue.
+	// It is stack.lo+StackGuard on g0 and gsignal stacks.
+	// It is ~0 on other goroutine stacks, to trigger a call to morestackc (and crash).
+	Stack	stack;	// offset known to runtime/cgo
+	uintptr	stackguard0;	// offset known to liblink
+	uintptr	stackguard1;	// offset known to liblink
+
+	Panic*	panic;	// innermost panic - offset known to liblink
+	Defer*	defer;	// innermost defer
+	Gobuf	sched;
+	uintptr	syscallsp;	// if status==Gsyscall, syscallsp = sched.sp to use during gc
+	uintptr	syscallpc;	// if status==Gsyscall, syscallpc = sched.pc to use during gc
+	void*	param;		// passed parameter on wakeup
+	uint32	atomicstatus;
+	int64	goid;
+	int64	waitsince;	// approx time when the G become blocked
+	String	waitreason;	// if status==Gwaiting
+	G*	schedlink;
+	bool	issystem;	// do not output in stack dump, ignore in deadlock detector
+	bool	preempt;	// preemption signal, duplicates stackguard0 = StackPreempt
+	bool	paniconfault;	// panic (instead of crash) on unexpected fault address
+	bool	preemptscan;    // preempted g does scan for GC
+	bool	gcworkdone;     // debug: cleared at begining of gc work phase cycle, set by gcphasework, tested at end of cycle
+	bool	throwsplit; // must not split stack
+	int8	raceignore;	// ignore race detection events
+	M*	m;		// for debuggers, but offset not hard-coded
+	M*	lockedm;
+	int32	sig;
+	Slice	writebuf;
+	uintptr	sigcode0;
+	uintptr	sigcode1;
+	uintptr	sigpc;
+	uintptr	gopc;		// pc of go statement that created this goroutine
+	uintptr	racectx;
+	SudoG*	waiting;	// sudog structures this G is waiting on (that have a valid elem ptr)
+	uintptr	end[];
+};
+
+struct	M
+{
+	G*	g0;		// goroutine with scheduling stack
+	Gobuf	morebuf;	// gobuf arg to morestack
+
+	// Fields not known to debuggers.
+	uint64	procid;		// for debuggers, but offset not hard-coded
+	G*	gsignal;	// signal-handling G
+	uintptr	tls[4];		// thread-local storage (for x86 extern register)
+	void	(*mstartfn)(void);
+	G*	curg;		// current running goroutine
+	G*	caughtsig;	// goroutine running during fatal signal
+	P*	p;		// attached P for executing Go code (nil if not executing Go code)
+	P*	nextp;
+	int32	id;
+	int32	mallocing;
+	int32	throwing;
+	int32	gcing;
+	int32	locks;
+	int32	softfloat;
+	int32	dying;
+	int32	profilehz;
+	int32	helpgc;
+	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
+	CgoMal*	cgomal;
+	Note	park;
+	M*	alllink;	// on allm
+	M*	schedlink;
+	uint32	machport;	// Return address for Mach IPC (OS X)
+	MCache*	mcache;
+	G*	lockedg;
+	uintptr	createstack[32];// Stack that created this thread.
+	uint32	freglo[16];	// D[i] lsb and F[i]
+	uint32	freghi[16];	// D[i] msb and F[i+16]
+	uint32	fflag;		// floating point compare flags
+	uint32	locked;		// tracking for LockOSThread
+	M*	nextwaitm;	// next M waiting for lock
+	uintptr	waitsema;	// semaphore for parking on locks
+	uint32	waitsemacount;
+	uint32	waitsemalock;
+	GCStats	gcstats;
+	bool	needextram;
+	uint8	traceback;
+	bool	(*waitunlockf)(G*, void*);
+	void*	waitlock;
+	uintptr scalararg[4];	// scalar argument/return for mcall
+	void*   ptrarg[4];	// pointer argument/return for mcall
+#ifdef GOOS_windows
+	uintptr	thread;		// thread handle
+	// 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 MTs {
+		int64	tv_sec;
+		int64	tv_nsec;
+	} ts;
+	struct MScratch {
+		uintptr v[6];
+	} scratch;
+#endif
+#ifdef GOOS_plan9
+	int8*	notesig;
+	byte*	errstr;
+#endif
+	uintptr	end[];
+};
+
+struct P
+{
+	Mutex	lock;
+
+	int32	id;
+	uint32	status;		// one of Pidle/Prunning/...
+	P*	link;
+	uint32	schedtick;	// incremented on every scheduler call
+	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.
+	uint32	runqhead;
+	uint32	runqtail;
+	G*	runq[256];
+
+	// Available G's (status == Gdead)
+	G*	gfree;
+	int32	gfreecnt;
+
+	byte	pad[64];
+};
+
+enum {
+	// The max value of GOMAXPROCS.
+	// There are no fundamental restrictions on the value.
+	MaxGomaxprocs = 1<<8,
+};
+
+struct	SchedT
+{
+	Mutex	lock;
+
+	uint64	goidgen;
+
+	M*	midle;	 // idle m's waiting for work
+	int32	nmidle;	 // number of idle m's waiting for work
+	int32	nmidlelocked; // number of locked m's waiting for work
+	int32	mcount;	 // number of m's that have been created
+	int32	maxmcount;	// maximum number of m's allowed (or die)
+
+	P*	pidle;  // idle P's
+	uint32	npidle;
+	uint32	nmspinning;
+
+	// Global runnable queue.
+	G*	runqhead;
+	G*	runqtail;
+	int32	runqsize;
+
+	// Global cache of dead G's.
+	Mutex	gflock;
+	G*	gfree;
+	int32	ngfree;
+
+	uint32	gcwaiting;	// gc is waiting to run
+	int32	stopwait;
+	Note	stopnote;
+	uint32	sysmonwait;
+	Note	sysmonnote;
+	uint64	lastpoll;
+
+	int32	profilehz;	// cpu profiling rate
+};
+
+// The m->locked word holds two pieces of state counting active calls to LockOSThread/lockOSThread.
+// The low bit (LockExternal) is a boolean reporting whether any LockOSThread call is active.
+// External locks are not recursive; a second lock is silently ignored.
+// The upper bits of m->lockedcount record the nesting depth of calls to lockOSThread
+// (counting up by LockInternal), popped by unlockOSThread (counting down by LockInternal).
+// Internal locks can be recursive. For instance, a lock for cgo can occur while the main
+// goroutine is holding the lock during the initialization phase.
+enum
+{
+	LockExternal = 1,
+	LockInternal = 2,
+};
+
+struct	SigTab
+{
+	int32	flags;
+	int8	*name;
+};
+enum
+{
+	SigNotify = 1<<0,	// let signal.Notify have signal, even if from kernel
+	SigKill = 1<<1,		// if signal.Notify doesn't take it, exit quietly
+	SigThrow = 1<<2,	// if signal.Notify doesn't take it, exit loudly
+	SigPanic = 1<<3,	// if the signal is from the kernel, panic
+	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
+// See http://golang.org/s/go12symtab.
+// Keep in sync with linker and with ../../libmach/sym.c
+// and with package debug/gosym and with symtab.go in package runtime.
+struct	Func
+{
+	uintptr	entry;	// start pc
+	int32	nameoff;// function name
+	
+	int32	args;	// in/out args size
+	int32	frame;	// legacy frame size; use pcsp if possible
+
+	int32	pcsp;
+	int32	pcfile;
+	int32	pcln;
+	int32	npcdata;
+	int32	nfuncdata;
+};
+
+// layout of Itab known to compilers
+// allocated in non-garbage-collected memory
+struct	Itab
+{
+	InterfaceType*	inter;
+	Type*	type;
+	Itab*	link;
+	int32	bad;
+	int32	unused;
+	void	(*fun[])(void);
+};
+
+#ifdef GOOS_nacl
+enum {
+   NaCl = 1,
+};
+#else
+enum {
+   NaCl = 0,
+};
+#endif
+
+#ifdef GOOS_windows
+enum {
+   Windows = 1
+};
+#else
+enum {
+   Windows = 0
+};
+#endif
+#ifdef GOOS_solaris
+enum {
+   Solaris = 1
+};
+#else
+enum {
+   Solaris = 0
+};
+#endif
+#ifdef GOOS_plan9
+enum {
+   Plan9 = 1
+};
+#else
+enum {
+   Plan9 = 0
+};
+#endif
+
+// Lock-free stack node.
+struct LFNode
+{
+	LFNode	*next;
+	uintptr	pushcnt;
+};
+
+// Parallel for descriptor.
+struct ParFor
+{
+	void (*body)(ParFor*, uint32);	// executed for each element
+	uint32 done;			// number of idle threads
+	uint32 nthr;			// total number of threads
+	uint32 nthrmax;			// maximum number of threads
+	uint32 thrseq;			// thread id sequencer
+	uint32 cnt;			// iteration space [0, cnt)
+	void *ctx;			// arbitrary user context
+	bool wait;			// if true, wait while all threads finish processing,
+					// otherwise parfor may return while other threads are still working
+	ParForThread *thr;		// array of thread descriptors
+	uint32 pad;			// to align ParForThread.pos for 64-bit atomic operations
+	// stats
+	uint64 nsteal;
+	uint64 nstealcnt;
+	uint64 nprocyield;
+	uint64 nosyield;
+	uint64 nsleep;
+};
+
+// Track memory allocated by code not written in Go during a cgo call,
+// so that the garbage collector can see them.
+struct CgoMal
+{
+	CgoMal	*next;
+	void	*alloc;
+};
+
+// Holds variables parsed from GODEBUG env var.
+struct DebugVars
+{
+	int32	allocfreetrace;
+	int32	efence;
+	int32	gctrace;
+	int32	gcdead;
+	int32	scheddetail;
+	int32	schedtrace;
+	int32	scavenge;
+};
+
+// Indicates to write barrier and sychronization task to preform.
+enum
+{                   // Synchronization            Write barrier
+	GCoff,      // stop and start             nop
+	GCquiesce,  // stop and start             nop
+	GCstw,      // stop the ps                nop
+	GCmark,     // scan the stacks and start  no white to black
+	GCsweep,    // stop and start             nop
+};
+
+struct ForceGCState
+{
+	Mutex	lock;
+	G*	g;
+	uint32	idle;
+};
+
+extern uint32 runtime·gcphase;
+
+/*
+ * defined macros
+ *    you need super-gopher-guru privilege
+ *    to add this list.
+ */
+#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)&~(uintptr)((n)-1)) /* all-caps to mark as macro: it evaluates n twice */
+
+/*
+ * known to compiler
+ */
+enum {
+	Structrnd = sizeof(uintreg),
+};
+
+byte*	runtime·startup_random_data;
+uint32	runtime·startup_random_data_len;
+
+int32	runtime·invalidptr;
+
+enum {
+	// hashinit wants this many random bytes
+	HashRandomBytes = 32
+};
+
+uint32  runtime·readgstatus(G*);
+void    runtime·casgstatus(G*, uint32, uint32);
+void    runtime·casgstatus(G*, uint32, uint32);
+uint32	runtime·casgcopystack(G*);
+void    runtime·quiesce(G*);
+bool    runtime·stopg(G*);
+void    runtime·restartg(G*);
+void    runtime·gcphasework(G*);
+
+/*
+ * deferred subroutine calls
+ */
+struct Defer
+{
+	int32	siz;
+	bool	started;
+	uintptr	argp;		// where args were copied from
+	uintptr	pc;
+	FuncVal*	fn;
+	Panic*	panic;	// panic that is running defer
+	Defer*	link;
+};
+
+// argp used in Defer structs when there is no argp.
+#define NoArgs ((uintptr)-1)
+
+/*
+ * panics
+ */
+struct Panic
+{
+	void*	argp;	// pointer to arguments of deferred call run during panic; cannot move - known to liblink
+	Eface	arg;		// argument to panic
+	Panic*	link;		// link to earlier panic
+	bool	recovered;	// whether this panic is over
+	bool	aborted;	// the panic was aborted
+};
+
+/*
+ * stack traces
+ */
+typedef struct Stkframe Stkframe;
+typedef struct BitVector BitVector;
+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
+	uintptr	varp;	// top of local variables
+	uintptr	argp;	// pointer to function arguments
+	uintptr	arglen;	// number of bytes at argp
+	BitVector*	argmap;	// force use of this argmap
+};
+
+enum
+{
+	TraceRuntimeFrames = 1<<0, // include frames for internal runtime functions.
+	TraceTrap = 1<<1, // the initial PC, SP are from a trap, not a return PC from a call
+};
+intgo	runtime·gentraceback(uintptr, uintptr, uintptr, G*, intgo, uintptr*, intgo, bool(**)(Stkframe*, void*), void*, uintgo);
+void	runtime·tracebackdefers(G*, bool(**)(Stkframe*, void*), void*);
+void	runtime·traceback(uintptr pc, uintptr sp, uintptr lr, G* gp);
+void	runtime·tracebacktrap(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	G**	runtime·allg;
+extern	Slice	runtime·allgs; // []*G
+extern	uintptr runtime·allglen;
+extern	G*	runtime·lastg;
+extern	M*	runtime·allm;
+extern	P*	runtime·allp[MaxGomaxprocs+1];
+extern	int32	runtime·gomaxprocs;
+extern	uint32	runtime·needextram;
+extern	uint32	runtime·panicking;
+extern	int8*	runtime·goos;
+extern	int32	runtime·ncpu;
+extern	bool	runtime·iscgo;
+extern 	void	(*runtime·sysargs)(int32, uint8**);
+extern	uintptr	runtime·maxstring;
+extern	uint32	runtime·cpuid_ecx;
+extern	uint32	runtime·cpuid_edx;
+extern	DebugVars	runtime·debug;
+extern	uintptr	runtime·maxstacksize;
+extern	Note	runtime·signote;
+extern	ForceGCState	runtime·forcegc;
+extern	SchedT	runtime·sched;
+extern	int32		runtime·newprocs;
+
+/*
+ * 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*);
+void	runtime·dump(byte*, int32);
+int32	runtime·runetochar(byte*, int32);
+int32	runtime·charntorune(int32*, uint8*, int32);
+
+
+/*
+ * 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*);
+void	runtime·gosave(Gobuf*);
+void	runtime·goargs(void);
+void	runtime·goenvs(void);
+void	runtime·goenvs_unix(void);
+void*	runtime·getu(void);
+void	runtime·throw(int8*);
+bool	runtime·canpanic(G*);
+void	runtime·prints(int8*);
+void	runtime·printf(int8*, ...);
+void	runtime·snprintf(byte*, int32, int8*, ...);
+byte*	runtime·mchr(byte*, byte, byte*);
+int32	runtime·mcmp(byte*, byte*, uintptr);
+void	runtime·memmove(void*, void*, uintptr);
+String	runtime·catstring(String, String);
+String	runtime·gostring(byte*);
+Slice	runtime·makeStringSlice(intgo);
+String  runtime·gostringn(byte*, intgo);
+Slice	runtime·gobytes(byte*, intgo);
+String	runtime·gostringnocopy(byte*);
+String	runtime·gostringw(uint16*);
+void	runtime·initsig(void);
+void	runtime·sigenable(uint32 sig);
+void	runtime·sigdisable(uint32 sig);
+int32	runtime·gotraceback(bool *crash);
+void	runtime·goroutineheader(G*);
+int32	runtime·open(int8*, int32, int32);
+int32	runtime·read(int32, void*, int32);
+int32	runtime·write(uintptr, void*, int32); // use uintptr to accommodate windows.
+int32	runtime·close(int32);
+int32	runtime·mincore(void*, uintptr, byte*);
+void	runtime·jmpdefer(FuncVal*, uintptr);
+void	runtime·exit1(int32);
+void	runtime·ready(G*);
+byte*	runtime·getenv(int8*);
+int32	runtime·atoi(byte*);
+void	runtime·newosproc(M *mp, void *stk);
+void	runtime·mstart(void);
+G*	runtime·malg(int32);
+void	runtime·asminit(void);
+void	runtime·mpreinit(M*);
+void	runtime·minit(void);
+void	runtime·unminit(void);
+void	runtime·signalstack(byte*, int32);
+void	runtime·tracebackinit(void);
+void	runtime·symtabinit(void);
+Func*	runtime·findfunc(uintptr);
+int32	runtime·funcline(Func*, uintptr, String*);
+int32	runtime·funcspdelta(Func*, uintptr);
+int8*	runtime·funcname(Func*);
+int32	runtime·pcdatavalue(Func*, int32, uintptr);
+void	runtime·stackinit(void);
+Stack	runtime·stackalloc(uint32);
+void	runtime·stackfree(Stack);
+void	runtime·shrinkstack(G*);
+void	runtime·shrinkfinish(void);
+MCache*	runtime·allocmcache(void);
+void	runtime·freemcache(MCache*);
+void	runtime·mallocinit(void);
+void	runtime·gcinit(void);
+void*	runtime·mallocgc(uintptr size, Type* typ, uint32 flag);
+void	runtime·runpanic(Panic*);
+uintptr	runtime·getcallersp(void*);
+int32	runtime·mcount(void);
+int32	runtime·gcount(void);
+void	runtime·mcall(void(**)(G*));
+void	runtime·onM(void(**)(void));
+void	runtime·onMsignal(void(**)(void));
+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*);
+uintptr	runtime·atomicloaduintptr(uintptr volatile*);
+void	runtime·atomicstorep(void* volatile*, void*);
+void	runtime·atomicstoreuintptr(uintptr volatile*, uintptr);
+void	runtime·atomicor8(byte volatile*, byte);
+
+void	runtime·setg(G*);
+void	runtime·newextram(void);
+void	runtime·exit(int32);
+void	runtime·breakpoint(void);
+void	runtime·gosched_m(G*);
+void	runtime·schedtrace(bool);
+void	runtime·park(bool(*)(G*, void*), void*, String);
+void	runtime·parkunlock(Mutex*, String);
+void	runtime·tsleep(int64, String);
+M*	runtime·newm(void);
+void	runtime·goexit(void);
+void	runtime·asmcgocall(void (*fn)(void*), void*);
+int32	runtime·asmcgocall_errno(void (*fn)(void*), void*);
+void	runtime·entersyscall(void);
+void	runtime·reentersyscall(uintptr, uintptr);
+void	runtime·entersyscallblock(void);
+void	runtime·exitsyscall(void);
+G*	runtime·newproc1(FuncVal*, byte*, int32, int32, void*);
+bool	runtime·sigsend(int32 sig);
+intgo	runtime·callers(intgo, uintptr*, intgo);
+intgo	runtime·gcallers(G*, intgo, uintptr*, intgo);
+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·sigprof(uint8 *pc, uint8 *sp, uint8 *lr, G *gp, M *mp);
+void	runtime·resetcpuprofiler(int32);
+void	runtime·setcpuprofilerate(int32);
+void	runtime·usleep(uint32);
+int64	runtime·cputicks(void);
+int64	runtime·tickspersecond(void);
+void	runtime·blockevent(int64, intgo);
+G*	runtime·netpoll(bool);
+void	runtime·netpollready(G**, PollDesc*, int32);
+uintptr	runtime·netpollfd(PollDesc*);
+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*	runtime·funcdata(Func*, int32);
+void	runtime·setmaxthreads_m(void);
+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
+#pragma	varargck	type	"d"	int32
+#pragma	varargck	type	"d"	uint32
+#pragma	varargck	type	"D"	int64
+#pragma	varargck	type	"D"	uint64
+#pragma	varargck	type	"x"	int32
+#pragma	varargck	type	"x"	uint32
+#pragma	varargck	type	"X"	int64
+#pragma	varargck	type	"X"	uint64
+#pragma	varargck	type	"p"	void*
+#pragma	varargck	type	"p"	uintptr
+#pragma	varargck	type	"s"	int8*
+#pragma	varargck	type	"s"	uint8*
+#pragma	varargck	type	"S"	String
+
+void	runtime·stoptheworld(void);
+void	runtime·starttheworld(void);
+extern uint32 runtime·worldsema;
+
+/*
+ * mutual exclusion locks.  in the uncontended case,
+ * as fast as spin locks (just a few user-level instructions),
+ * but on the contention path they sleep in the kernel.
+ * a zeroed Mutex is unlocked (no need to initialize each lock).
+ */
+void	runtime·lock(Mutex*);
+void	runtime·unlock(Mutex*);
+
+/*
+ * sleep and wakeup on one-time events.
+ * before any calls to notesleep or notewakeup,
+ * must call noteclear to initialize the Note.
+ * then, exactly one thread can call notesleep
+ * and exactly one thread can call notewakeup (once).
+ * once notewakeup has been called, the notesleep
+ * will return.  future notesleep will return immediately.
+ * subsequent noteclear must be called only after
+ * previous notesleep has returned, e.g. it's disallowed
+ * to call noteclear straight after notewakeup.
+ *
+ * notetsleep is like notesleep but wakes up after
+ * a given number of nanoseconds even if the event
+ * has not yet happened.  if a goroutine uses notetsleep to
+ * wake up early, it must wait to call noteclear until it
+ * can be sure that no other goroutine is calling
+ * notewakeup.
+ *
+ * notesleep/notetsleep are generally called on g0,
+ * notetsleepg is similar to notetsleep but is called on user g.
+ */
+void	runtime·noteclear(Note*);
+void	runtime·notesleep(Note*);
+void	runtime·notewakeup(Note*);
+bool	runtime·notetsleep(Note*, int64);  // false - timeout
+bool	runtime·notetsleepg(Note*, int64);  // false - timeout
+
+/*
+ * low-level synchronization for implementing the above
+ */
+uintptr	runtime·semacreate(void);
+int32	runtime·semasleep(int64);
+void	runtime·semawakeup(M*);
+// or
+void	runtime·futexsleep(uint32*, uint32, int64);
+void	runtime·futexwakeup(uint32*, uint32);
+
+/*
+ * Mutex-free stack.
+ * Initialize uint64 head to 0, compare with 0 to test for emptiness.
+ * The stack does not keep pointers to nodes,
+ * so they can be garbage collected if there are no other pointers to nodes.
+ */
+void	runtime·lfstackpush(uint64 *head, LFNode *node);
+LFNode*	runtime·lfstackpop(uint64 *head);
+
+/*
+ * Parallel for over [0, n).
+ * body() is executed for each iteration.
+ * nthr - total number of worker threads.
+ * ctx - arbitrary user context.
+ * if wait=true, threads return from parfor() when all work is done;
+ * otherwise, threads can return while other threads are still finishing processing.
+ */
+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);
+void	runtime·parforiters(ParFor*, uintptr, uintptr*, uintptr*);
+
+/*
+ * low level C-called
+ */
+// for mmap, we only pass the lower 32 bits of file offset to the 
+// assembly routine; the higher bits (if required), should be provided
+// by the assembly routine as 0.
+uint8*	runtime·mmap(byte*, uintptr, int32, int32, int32, uint32);
+void	runtime·munmap(byte*, uintptr);
+void	runtime·madvise(byte*, uintptr, int32);
+void	runtime·memclr(byte*, uintptr);
+void	runtime·setcallerpc(void*, void*);
+void*	runtime·getcallerpc(void*);
+void	runtime·printbool(bool);
+void	runtime·printbyte(int8);
+void	runtime·printfloat(float64);
+void	runtime·printint(int64);
+void	runtime·printiface(Iface);
+void	runtime·printeface(Eface);
+void	runtime·printstring(String);
+void	runtime·printpc(void*);
+void	runtime·printpointer(void*);
+void	runtime·printuint(uint64);
+void	runtime·printhex(uint64);
+void	runtime·printslice(Slice);
+void	runtime·printcomplex(Complex128);
+
+/*
+ * runtime go-called
+ */
+void	runtime·gopanic(Eface);
+void	runtime·panicindex(void);
+void	runtime·panicslice(void);
+void	runtime·panicdivide(void);
+
+/*
+ * runtime c-called (but written in Go)
+ */
+void	runtime·printany(Eface);
+void	runtime·newTypeAssertionError(String*, String*, String*, String*, Eface*);
+void	runtime·fadd64c(uint64, uint64, uint64*);
+void	runtime·fsub64c(uint64, uint64, uint64*);
+void	runtime·fmul64c(uint64, uint64, uint64*);
+void	runtime·fdiv64c(uint64, uint64, uint64*);
+void	runtime·fneg64c(uint64, uint64*);
+void	runtime·f32to64c(uint32, uint64*);
+void	runtime·f64to32c(uint64, uint32*);
+void	runtime·fcmp64c(uint64, uint64, int32*, bool*);
+void	runtime·fintto64c(int64, uint64*);
+void	runtime·f64tointc(uint64, int64*, bool*);
+
+/*
+ * wrapped for go users
+ */
+float64	runtime·Inf(int32 sign);
+float64	runtime·NaN(void);
+float32	runtime·float32frombits(uint32 i);
+uint32	runtime·float32tobits(float32 f);
+float64	runtime·float64frombits(uint64 i);
+uint64	runtime·float64tobits(float64 f);
+float64	runtime·frexp(float64 d, int32 *ep);
+bool	runtime·isInf(float64 f, int32 sign);
+bool	runtime·isNaN(float64 f);
+float64	runtime·ldexp(float64 d, int32 e);
+float64	runtime·modf(float64 d, float64 *ip);
+void	runtime·semacquire(uint32*, bool);
+void	runtime·semrelease(uint32*);
+int32	runtime·gomaxprocsfunc(int32 n);
+void	runtime·procyield(uint32);
+void	runtime·osyield(void);
+void	runtime·lockOSThread(void);
+void	runtime·unlockOSThread(void);
+
+bool	runtime·showframe(Func*, G*);
+void	runtime·printcreatedby(G*);
+
+void	runtime·ifaceE2I(InterfaceType*, Eface, Iface*);
+bool	runtime·ifaceE2I2(InterfaceType*, Eface, Iface*);
+uintptr	runtime·memlimit(void);
+
+// float.c
+extern float64 runtime·nan;
+extern float64 runtime·posinf;
+extern float64 runtime·neginf;
+extern uint64 ·nan;
+extern uint64 ·posinf;
+extern uint64 ·neginf;
+#define ISNAN(f) ((f) != (f))
+
+enum
+{
+	UseSpanType = 1,
+};
diff --git a/src/runtime/runtime_test.go b/src/runtime/runtime_test.go
index 75fc9bc..1688364 100644
--- a/src/runtime/runtime_test.go
+++ b/src/runtime/runtime_test.go
@@ -6,8 +6,13 @@ package runtime_test
 
 import (
 	"io"
+	"io/ioutil"
+	"os"
+	"os/exec"
 	. "runtime"
 	"runtime/debug"
+	"strconv"
+	"strings"
 	"testing"
 	"unsafe"
 )
@@ -83,6 +88,48 @@ func BenchmarkDeferMany(b *testing.B) {
 	}
 }
 
+// The profiling signal handler needs to know whether it is executing runtime.gogo.
+// The constant RuntimeGogoBytes in arch_*.h gives the size of the function;
+// we don't have a way to obtain it from the linker (perhaps someday).
+// Test that the constant matches the size determined by 'go tool nm -S'.
+// The value reported will include the padding between runtime.gogo and the
+// next function in memory. That's fine.
+func TestRuntimeGogoBytes(t *testing.T) {
+	switch GOOS {
+	case "android", "nacl":
+		t.Skipf("skipping on %s", GOOS)
+	}
+
+	dir, err := ioutil.TempDir("", "go-build")
+	if err != nil {
+		t.Fatalf("failed to create temp directory: %v", err)
+	}
+	defer os.RemoveAll(dir)
+
+	out, err := exec.Command("go", "build", "-o", dir+"/hello", "../../test/helloworld.go").CombinedOutput()
+	if err != nil {
+		t.Fatalf("building hello world: %v\n%s", err, out)
+	}
+
+	out, err = exec.Command("go", "tool", "nm", "-size", dir+"/hello").CombinedOutput()
+	if err != nil {
+		t.Fatalf("go tool nm: %v\n%s", err, out)
+	}
+
+	for _, line := range strings.Split(string(out), "\n") {
+		f := strings.Fields(line)
+		if len(f) == 4 && f[3] == "runtime.gogo" {
+			size, _ := strconv.Atoi(f[1])
+			if GogoBytes() != int32(size) {
+				t.Fatalf("RuntimeGogoBytes = %d, should be %d", GogoBytes(), size)
+			}
+			return
+		}
+	}
+
+	t.Fatalf("go tool nm did not report size for runtime.gogo")
+}
+
 // golang.org/issue/7063
 func TestStopCPUProfilingWithProfilerOff(t *testing.T) {
 	SetCPUProfileRate(0)
@@ -126,6 +173,12 @@ var faultAddrs = []uint64{
 }
 
 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)
 
@@ -194,110 +247,3 @@ func TestEqString(t *testing.T) {
 		}
 	}
 }
-
-func TestTrailingZero(t *testing.T) {
-	// make sure we add padding for structs with trailing zero-sized fields
-	type T1 struct {
-		n int32
-		z [0]byte
-	}
-	if unsafe.Sizeof(T1{}) != 8 {
-		t.Errorf("sizeof(%#v)==%d, want 8", T1{}, unsafe.Sizeof(T1{}))
-	}
-	type T2 struct {
-		n int64
-		z struct{}
-	}
-	if unsafe.Sizeof(T2{}) != 8+unsafe.Sizeof(Uintreg(0)) {
-		t.Errorf("sizeof(%#v)==%d, want %d", T2{}, unsafe.Sizeof(T2{}), 8+unsafe.Sizeof(Uintreg(0)))
-	}
-	type T3 struct {
-		n byte
-		z [4]struct{}
-	}
-	if unsafe.Sizeof(T3{}) != 2 {
-		t.Errorf("sizeof(%#v)==%d, want 2", T3{}, unsafe.Sizeof(T3{}))
-	}
-	// make sure padding can double for both zerosize and alignment
-	type T4 struct {
-		a int32
-		b int16
-		c int8
-		z struct{}
-	}
-	if unsafe.Sizeof(T4{}) != 8 {
-		t.Errorf("sizeof(%#v)==%d, want 8", T4{}, unsafe.Sizeof(T4{}))
-	}
-	// make sure we don't pad a zero-sized thing
-	type T5 struct {
-	}
-	if unsafe.Sizeof(T5{}) != 0 {
-		t.Errorf("sizeof(%#v)==%d, want 0", T5{}, unsafe.Sizeof(T5{}))
-	}
-}
-
-func TestBadOpen(t *testing.T) {
-	if GOOS == "windows" || GOOS == "nacl" {
-		t.Skip("skipping OS that doesn't have open/read/write/close")
-	}
-	// make sure we get the correct error code if open fails.  Same for
-	// read/write/close on the resulting -1 fd.  See issue 10052.
-	nonfile := []byte("/notreallyafile")
-	fd := Open(&nonfile[0], 0, 0)
-	if fd != -1 {
-		t.Errorf("open(\"%s\")=%d, want -1", string(nonfile), fd)
-	}
-	var buf [32]byte
-	r := Read(-1, unsafe.Pointer(&buf[0]), int32(len(buf)))
-	if r != -1 {
-		t.Errorf("read()=%d, want -1", r)
-	}
-	w := Write(^uintptr(0), unsafe.Pointer(&buf[0]), int32(len(buf)))
-	if w != -1 {
-		t.Errorf("write()=%d, want -1", w)
-	}
-	c := Close(-1)
-	if c != -1 {
-		t.Errorf("close()=%d, want -1", c)
-	}
-}
-
-func TestAppendGrowth(t *testing.T) {
-	var x []int64
-	check := func(want int) {
-		if cap(x) != want {
-			t.Errorf("len=%d, cap=%d, want cap=%d", len(x), cap(x), want)
-		}
-	}
-
-	check(0)
-	want := 1
-	for i := 1; i <= 100; i++ {
-		x = append(x, 1)
-		check(want)
-		if i&(i-1) == 0 {
-			want = 2 * i
-		}
-	}
-}
-
-var One = []int64{1}
-
-func TestAppendSliceGrowth(t *testing.T) {
-	var x []int64
-	check := func(want int) {
-		if cap(x) != want {
-			t.Errorf("len=%d, cap=%d, want cap=%d", len(x), cap(x), want)
-		}
-	}
-
-	check(0)
-	want := 1
-	for i := 1; i <= 100; i++ {
-		x = append(x, One...)
-		check(want)
-		if i&(i-1) == 0 {
-			want = 2 * i
-		}
-	}
-}
diff --git a/src/runtime/runtime_unix_test.go b/src/runtime/runtime_unix_test.go
index cfec332..963de8c 100644
--- a/src/runtime/runtime_unix_test.go
+++ b/src/runtime/runtime_unix_test.go
@@ -42,7 +42,7 @@ func TestGoroutineProfile(t *testing.T) {
 	if testing.Short() {
 		max = 100
 	}
-	stk := make([]runtime.StackRecord, 128)
+	stk := make([]runtime.StackRecord, 100)
 	for n := 0; n < max; n++ {
 		_, ok := runtime.GoroutineProfile(stk)
 		if !ok {
diff --git a/src/runtime/select.go b/src/runtime/select.go
index b18b44c..f735a71 100644
--- a/src/runtime/select.go
+++ b/src/runtime/select.go
@@ -10,59 +10,30 @@ import "unsafe"
 
 const (
 	debugSelect = false
-
-	// scase.kind
-	caseRecv = iota
-	caseSend
-	caseDefault
 )
 
-// Select statement header.
-// Known to compiler.
-// Changes here must also be made in src/cmd/internal/gc/select.go's selecttype.
-type hselect struct {
-	tcase     uint16   // total count of scase[]
-	ncase     uint16   // currently filled scase[]
-	pollorder *uint16  // case poll order
-	lockorder **hchan  // channel lock order
-	scase     [1]scase // one per case (in order of appearance)
-}
-
-// Select case descriptor.
-// Known to compiler.
-// Changes here must also be made in src/cmd/internal/gc/select.go's selecttype.
-type scase struct {
-	elem        unsafe.Pointer // data element
-	c           *hchan         // chan
-	pc          uintptr        // return pc
-	kind        uint16
-	so          uint16 // vararg of selected bool
-	receivedp   *bool  // pointer to received bool (recv2)
-	releasetime int64
-}
-
 var (
 	chansendpc = funcPC(chansend)
 	chanrecvpc = funcPC(chanrecv)
 )
 
 func selectsize(size uintptr) uintptr {
-	selsize := unsafe.Sizeof(hselect{}) +
-		(size-1)*unsafe.Sizeof(hselect{}.scase[0]) +
-		size*unsafe.Sizeof(*hselect{}.lockorder) +
-		size*unsafe.Sizeof(*hselect{}.pollorder)
+	selsize := unsafe.Sizeof(_select{}) +
+		(size-1)*unsafe.Sizeof(_select{}.scase[0]) +
+		size*unsafe.Sizeof(*_select{}.lockorder) +
+		size*unsafe.Sizeof(*_select{}.pollorder)
 	return round(selsize, _Int64Align)
 }
 
-func newselect(sel *hselect, selsize int64, size int32) {
+func newselect(sel *_select, selsize int64, size int32) {
 	if selsize != int64(selectsize(uintptr(size))) {
 		print("runtime: bad select size ", selsize, ", want ", selectsize(uintptr(size)), "\n")
-		throw("bad select size")
+		gothrow("bad select size")
 	}
 	sel.tcase = uint16(size)
 	sel.ncase = 0
-	sel.lockorder = (**hchan)(add(unsafe.Pointer(&sel.scase), uintptr(size)*unsafe.Sizeof(hselect{}.scase[0])))
-	sel.pollorder = (*uint16)(add(unsafe.Pointer(sel.lockorder), uintptr(size)*unsafe.Sizeof(*hselect{}.lockorder)))
+	sel.lockorder = (**hchan)(add(unsafe.Pointer(&sel.scase), uintptr(size)*unsafe.Sizeof(_select{}.scase[0])))
+	sel.pollorder = (*uint16)(add(unsafe.Pointer(sel.lockorder), uintptr(size)*unsafe.Sizeof(*_select{}.lockorder)))
 
 	if debugSelect {
 		print("newselect s=", sel, " size=", size, "\n")
@@ -70,7 +41,7 @@ func newselect(sel *hselect, selsize int64, size int32) {
 }
 
 //go:nosplit
-func selectsend(sel *hselect, c *hchan, elem unsafe.Pointer) (selected bool) {
+func selectsend(sel *_select, c *hchan, elem unsafe.Pointer) (selected bool) {
 	// nil cases do not compete
 	if c != nil {
 		selectsendImpl(sel, c, getcallerpc(unsafe.Pointer(&sel)), elem, uintptr(unsafe.Pointer(&selected))-uintptr(unsafe.Pointer(&sel)))
@@ -79,27 +50,27 @@ func selectsend(sel *hselect, c *hchan, elem unsafe.Pointer) (selected bool) {
 }
 
 // cut in half to give stack a chance to split
-func selectsendImpl(sel *hselect, c *hchan, pc uintptr, elem unsafe.Pointer, so uintptr) {
+func selectsendImpl(sel *_select, c *hchan, pc uintptr, elem unsafe.Pointer, so uintptr) {
 	i := sel.ncase
 	if i >= sel.tcase {
-		throw("selectsend: too many cases")
+		gothrow("selectsend: too many cases")
 	}
 	sel.ncase = i + 1
 	cas := (*scase)(add(unsafe.Pointer(&sel.scase), uintptr(i)*unsafe.Sizeof(sel.scase[0])))
 
 	cas.pc = pc
-	cas.c = c
+	cas._chan = c
 	cas.so = uint16(so)
-	cas.kind = caseSend
+	cas.kind = _CaseSend
 	cas.elem = elem
 
 	if debugSelect {
-		print("selectsend s=", sel, " pc=", hex(cas.pc), " chan=", cas.c, " so=", cas.so, "\n")
+		print("selectsend s=", sel, " pc=", hex(cas.pc), " chan=", cas._chan, " so=", cas.so, "\n")
 	}
 }
 
 //go:nosplit
-func selectrecv(sel *hselect, c *hchan, elem unsafe.Pointer) (selected bool) {
+func selectrecv(sel *_select, c *hchan, elem unsafe.Pointer) (selected bool) {
 	// nil cases do not compete
 	if c != nil {
 		selectrecvImpl(sel, c, getcallerpc(unsafe.Pointer(&sel)), elem, nil, uintptr(unsafe.Pointer(&selected))-uintptr(unsafe.Pointer(&sel)))
@@ -108,7 +79,7 @@ func selectrecv(sel *hselect, c *hchan, elem unsafe.Pointer) (selected bool) {
 }
 
 //go:nosplit
-func selectrecv2(sel *hselect, c *hchan, elem unsafe.Pointer, received *bool) (selected bool) {
+func selectrecv2(sel *_select, c *hchan, elem unsafe.Pointer, received *bool) (selected bool) {
 	// nil cases do not compete
 	if c != nil {
 		selectrecvImpl(sel, c, getcallerpc(unsafe.Pointer(&sel)), elem, received, uintptr(unsafe.Pointer(&selected))-uintptr(unsafe.Pointer(&sel)))
@@ -116,50 +87,50 @@ func selectrecv2(sel *hselect, c *hchan, elem unsafe.Pointer, received *bool) (s
 	return
 }
 
-func selectrecvImpl(sel *hselect, c *hchan, pc uintptr, elem unsafe.Pointer, received *bool, so uintptr) {
+func selectrecvImpl(sel *_select, c *hchan, pc uintptr, elem unsafe.Pointer, received *bool, so uintptr) {
 	i := sel.ncase
 	if i >= sel.tcase {
-		throw("selectrecv: too many cases")
+		gothrow("selectrecv: too many cases")
 	}
 	sel.ncase = i + 1
 	cas := (*scase)(add(unsafe.Pointer(&sel.scase), uintptr(i)*unsafe.Sizeof(sel.scase[0])))
 	cas.pc = pc
-	cas.c = c
+	cas._chan = c
 	cas.so = uint16(so)
-	cas.kind = caseRecv
+	cas.kind = _CaseRecv
 	cas.elem = elem
 	cas.receivedp = received
 
 	if debugSelect {
-		print("selectrecv s=", sel, " pc=", hex(cas.pc), " chan=", cas.c, " so=", cas.so, "\n")
+		print("selectrecv s=", sel, " pc=", hex(cas.pc), " chan=", cas._chan, " so=", cas.so, "\n")
 	}
 }
 
 //go:nosplit
-func selectdefault(sel *hselect) (selected bool) {
+func selectdefault(sel *_select) (selected bool) {
 	selectdefaultImpl(sel, getcallerpc(unsafe.Pointer(&sel)), uintptr(unsafe.Pointer(&selected))-uintptr(unsafe.Pointer(&sel)))
 	return
 }
 
-func selectdefaultImpl(sel *hselect, callerpc uintptr, so uintptr) {
+func selectdefaultImpl(sel *_select, callerpc uintptr, so uintptr) {
 	i := sel.ncase
 	if i >= sel.tcase {
-		throw("selectdefault: too many cases")
+		gothrow("selectdefault: too many cases")
 	}
 	sel.ncase = i + 1
 	cas := (*scase)(add(unsafe.Pointer(&sel.scase), uintptr(i)*unsafe.Sizeof(sel.scase[0])))
 	cas.pc = callerpc
-	cas.c = nil
+	cas._chan = nil
 	cas.so = uint16(so)
-	cas.kind = caseDefault
+	cas.kind = _CaseDefault
 
 	if debugSelect {
 		print("selectdefault s=", sel, " pc=", hex(cas.pc), " so=", cas.so, "\n")
 	}
 }
 
-func sellock(sel *hselect) {
-	lockslice := slice{unsafe.Pointer(sel.lockorder), int(sel.ncase), int(sel.ncase)}
+func sellock(sel *_select) {
+	lockslice := sliceStruct{unsafe.Pointer(sel.lockorder), int(sel.ncase), int(sel.ncase)}
 	lockorder := *(*[]*hchan)(unsafe.Pointer(&lockslice))
 	var c *hchan
 	for _, c0 := range lockorder {
@@ -170,7 +141,7 @@ func sellock(sel *hselect) {
 	}
 }
 
-func selunlock(sel *hselect) {
+func selunlock(sel *_select) {
 	// 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.
@@ -181,7 +152,7 @@ func selunlock(sel *hselect) {
 	// Now if the first M touches sel, it will access freed memory.
 	n := int(sel.ncase)
 	r := 0
-	lockslice := slice{unsafe.Pointer(sel.lockorder), n, n}
+	lockslice := sliceStruct{unsafe.Pointer(sel.lockorder), n, n}
 	lockorder := *(*[]*hchan)(unsafe.Pointer(&lockslice))
 	// skip the default case
 	if n > 0 && lockorder[0] == nil {
@@ -196,19 +167,19 @@ func selunlock(sel *hselect) {
 	}
 }
 
-func selparkcommit(gp *g, sel unsafe.Pointer) bool {
-	selunlock((*hselect)(sel))
+func selparkcommit(gp *g, sel *_select) bool {
+	selunlock(sel)
 	return true
 }
 
 func block() {
-	gopark(nil, nil, "select (no cases)", traceEvGoStop, 1) // forever
+	gopark(nil, nil, "select (no cases)") // forever
 }
 
 // overwrites return pc on stack to signal which case of the select
 // to run, so cannot appear at the top of a split stack.
 //go:nosplit
-func selectgo(sel *hselect) {
+func selectgo(sel *_select) {
 	pc, offset := selectgoImpl(sel)
 	*(*bool)(add(unsafe.Pointer(&sel), uintptr(offset))) = true
 	setcallerpc(unsafe.Pointer(&sel), pc)
@@ -216,12 +187,12 @@ func selectgo(sel *hselect) {
 
 // selectgoImpl returns scase.pc and scase.so for the select
 // case which fired.
-func selectgoImpl(sel *hselect) (uintptr, uint16) {
+func selectgoImpl(sel *_select) (uintptr, uint16) {
 	if debugSelect {
 		print("select: sel=", sel, "\n")
 	}
 
-	scaseslice := slice{unsafe.Pointer(&sel.scase), int(sel.ncase), int(sel.ncase)}
+	scaseslice := sliceStruct{unsafe.Pointer(&sel.scase), int(sel.ncase), int(sel.ncase)}
 	scases := *(*[]scase)(unsafe.Pointer(&scaseslice))
 
 	var t0 int64
@@ -241,21 +212,25 @@ func selectgoImpl(sel *hselect) (uintptr, uint16) {
 	// optimizing (and needing to test).
 
 	// generate permuted order
-	pollslice := slice{unsafe.Pointer(sel.pollorder), int(sel.ncase), int(sel.ncase)}
+	pollslice := sliceStruct{unsafe.Pointer(sel.pollorder), int(sel.ncase), int(sel.ncase)}
 	pollorder := *(*[]uint16)(unsafe.Pointer(&pollslice))
+	for i := 0; i < int(sel.ncase); i++ {
+		pollorder[i] = uint16(i)
+	}
 	for i := 1; i < int(sel.ncase); i++ {
+		o := pollorder[i]
 		j := int(fastrand1()) % (i + 1)
 		pollorder[i] = pollorder[j]
-		pollorder[j] = uint16(i)
+		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.
-	lockslice := slice{unsafe.Pointer(sel.lockorder), int(sel.ncase), int(sel.ncase)}
+	lockslice := sliceStruct{unsafe.Pointer(sel.lockorder), int(sel.ncase), int(sel.ncase)}
 	lockorder := *(*[]*hchan)(unsafe.Pointer(&lockslice))
 	for i := 0; i < int(sel.ncase); i++ {
 		j := i
-		c := scases[j].c
+		c := scases[j]._chan
 		for j > 0 && lockorder[(j-1)/2].sortkey() < c.sortkey() {
 			k := (j - 1) / 2
 			lockorder[j] = lockorder[k]
@@ -288,7 +263,7 @@ func selectgoImpl(sel *hselect) (uintptr, uint16) {
 		for i := 0; i+1 < int(sel.ncase); i++ {
 			if lockorder[i].sortkey() > lockorder[i+1].sortkey() {
 				print("i=", i, " x=", lockorder[i], " y=", lockorder[i+1], "\n")
-				throw("select: broken sort")
+				gothrow("select: broken sort")
 			}
 		}
 	*/
@@ -304,7 +279,6 @@ func selectgoImpl(sel *hselect) (uintptr, uint16) {
 		k      *scase
 		sglist *sudog
 		sgnext *sudog
-		futile byte
 	)
 
 loop:
@@ -313,10 +287,10 @@ loop:
 	var cas *scase
 	for i := 0; i < int(sel.ncase); i++ {
 		cas = &scases[pollorder[i]]
-		c = cas.c
+		c = cas._chan
 
 		switch cas.kind {
-		case caseRecv:
+		case _CaseRecv:
 			if c.dataqsiz > 0 {
 				if c.qcount > 0 {
 					goto asyncrecv
@@ -331,7 +305,7 @@ loop:
 				goto rclose
 			}
 
-		case caseSend:
+		case _CaseSend:
 			if raceenabled {
 				racereadpc(unsafe.Pointer(c), cas.pc, chansendpc)
 			}
@@ -349,7 +323,7 @@ loop:
 				}
 			}
 
-		case caseDefault:
+		case _CaseDefault:
 			dfl = cas
 		}
 	}
@@ -365,10 +339,10 @@ loop:
 	done = 0
 	for i := 0; i < int(sel.ncase); i++ {
 		cas = &scases[pollorder[i]]
-		c = cas.c
+		c = cas._chan
 		sg := acquireSudog()
 		sg.g = gp
-		// Note: selectdone is adjusted for stack copies in stack1.go:adjustsudogs
+		// Note: selectdone is adjusted for stack copies in stack.c:adjustsudogs
 		sg.selectdone = (*uint32)(noescape(unsafe.Pointer(&done)))
 		sg.elem = cas.elem
 		sg.releasetime = 0
@@ -379,17 +353,17 @@ loop:
 		gp.waiting = sg
 
 		switch cas.kind {
-		case caseRecv:
+		case _CaseRecv:
 			c.recvq.enqueue(sg)
 
-		case caseSend:
+		case _CaseSend:
 			c.sendq.enqueue(sg)
 		}
 	}
 
 	// wait for someone to wake us up
 	gp.param = nil
-	gopark(selparkcommit, unsafe.Pointer(sel), "select", traceEvGoBlockSelect|futile, 2)
+	gopark(unsafe.Pointer(funcPC(selparkcommit)), unsafe.Pointer(sel), "select")
 
 	// someone woke us up
 	sellock(sel)
@@ -403,7 +377,12 @@ loop:
 	// iterating through the linked list they are in reverse order.
 	cas = nil
 	sglist = gp.waiting
-	// Clear all elem before unlinking from gp.waiting.
+	// Clear all selectdone and elem before unlinking from gp.waiting.
+	// They must be cleared before being put back into the sudog cache.
+	// Clear before unlinking, because if a stack copy happens after the unlink,
+	// they will not be updated, they will be left pointing to the old stack,
+	// which creates dangling pointers, which may be detected by the
+	// garbage collector.
 	for sg1 := gp.waiting; sg1 != nil; sg1 = sg1.waitlink {
 		sg1.selectdone = nil
 		sg1.elem = nil
@@ -415,11 +394,10 @@ loop:
 			k.releasetime = sglist.releasetime
 		}
 		if sg == sglist {
-			// sg has already been dequeued by the G that woke us up.
 			cas = k
 		} else {
-			c = k.c
-			if k.kind == caseSend {
+			c = k._chan
+			if k.kind == _CaseSend {
 				c.sendq.dequeueSudoG(sglist)
 			} else {
 				c.recvq.dequeueSudoG(sglist)
@@ -432,30 +410,29 @@ loop:
 	}
 
 	if cas == nil {
-		futile = traceFutileWakeup
 		goto loop
 	}
 
-	c = cas.c
+	c = cas._chan
 
 	if c.dataqsiz > 0 {
-		throw("selectgo: shouldn't happen")
+		gothrow("selectgo: shouldn't happen")
 	}
 
 	if debugSelect {
 		print("wait-return: sel=", sel, " c=", c, " cas=", cas, " kind=", cas.kind, "\n")
 	}
 
-	if cas.kind == caseRecv {
+	if cas.kind == _CaseRecv {
 		if cas.receivedp != nil {
 			*cas.receivedp = true
 		}
 	}
 
 	if raceenabled {
-		if cas.kind == caseRecv && cas.elem != nil {
+		if cas.kind == _CaseRecv && cas.elem != nil {
 			raceWriteObjectPC(c.elemtype, cas.elem, cas.pc, chanrecvpc)
-		} else if cas.kind == caseSend {
+		} else if cas.kind == _CaseSend {
 			raceReadObjectPC(c.elemtype, cas.elem, cas.pc, chansendpc)
 		}
 	}
@@ -476,7 +453,7 @@ asyncrecv:
 		*cas.receivedp = true
 	}
 	if cas.elem != nil {
-		typedmemmove(c.elemtype, cas.elem, chanbuf(c, c.recvx))
+		memmove(cas.elem, chanbuf(c, c.recvx), uintptr(c.elemsize))
 	}
 	memclr(chanbuf(c, c.recvx), uintptr(c.elemsize))
 	c.recvx++
@@ -491,7 +468,7 @@ asyncrecv:
 		if sg.releasetime != 0 {
 			sg.releasetime = cputicks()
 		}
-		goready(gp, 3)
+		goready(gp)
 	} else {
 		selunlock(sel)
 	}
@@ -504,7 +481,7 @@ asyncsend:
 		racerelease(chanbuf(c, c.sendx))
 		raceReadObjectPC(c.elemtype, cas.elem, cas.pc, chansendpc)
 	}
-	typedmemmove(c.elemtype, chanbuf(c, c.sendx), cas.elem)
+	memmove(chanbuf(c, c.sendx), cas.elem, uintptr(c.elemsize))
 	c.sendx++
 	if c.sendx == c.dataqsiz {
 		c.sendx = 0
@@ -517,7 +494,7 @@ asyncsend:
 		if sg.releasetime != 0 {
 			sg.releasetime = cputicks()
 		}
-		goready(gp, 3)
+		goready(gp)
 	} else {
 		selunlock(sel)
 	}
@@ -539,7 +516,7 @@ syncrecv:
 		*cas.receivedp = true
 	}
 	if cas.elem != nil {
-		typedmemmove(c.elemtype, cas.elem, sg.elem)
+		memmove(cas.elem, sg.elem, uintptr(c.elemsize))
 	}
 	sg.elem = nil
 	gp = sg.g
@@ -547,7 +524,7 @@ syncrecv:
 	if sg.releasetime != 0 {
 		sg.releasetime = cputicks()
 	}
-	goready(gp, 3)
+	goready(gp)
 	goto retc
 
 rclose:
@@ -575,7 +552,7 @@ syncsend:
 		print("syncsend: sel=", sel, " c=", c, "\n")
 	}
 	if sg.elem != nil {
-		syncsend(c, sg, cas.elem)
+		memmove(sg.elem, cas.elem, uintptr(c.elemsize))
 	}
 	sg.elem = nil
 	gp = sg.g
@@ -583,7 +560,7 @@ syncsend:
 	if sg.releasetime != 0 {
 		sg.releasetime = cputicks()
 	}
-	goready(gp, 3)
+	goready(gp)
 
 retc:
 	if cas.releasetime > 0 {
@@ -622,11 +599,10 @@ const (
 	selectDefault           // default
 )
 
-//go:linkname reflect_rselect reflect.rselect
 func reflect_rselect(cases []runtimeSelect) (chosen int, recvOK bool) {
 	// flagNoScan is safe here, because all objects are also referenced from cases.
 	size := selectsize(uintptr(len(cases)))
-	sel := (*hselect)(mallocgc(size, nil, flagNoScan))
+	sel := (*_select)(mallocgc(size, nil, flagNoScan))
 	newselect(sel, int64(size), int32(len(cases)))
 	r := new(bool)
 	for i := range cases {
@@ -653,36 +629,23 @@ func reflect_rselect(cases []runtimeSelect) (chosen int, recvOK bool) {
 	return
 }
 
-func (q *waitq) dequeueSudoG(sgp *sudog) {
-	x := sgp.prev
-	y := sgp.next
-	if x != nil {
-		if y != nil {
-			// middle of queue
-			x.next = y
-			y.prev = x
-			sgp.next = nil
-			sgp.prev = nil
+func (q *waitq) dequeueSudoG(s *sudog) {
+	var prevsgp *sudog
+	l := &q.first
+	for {
+		sgp := *l
+		if sgp == nil {
+			return
+		}
+		if sgp == s {
+			*l = sgp.next
+			if q.last == sgp {
+				q.last = prevsgp
+			}
+			s.next = nil
 			return
 		}
-		// end of queue
-		x.next = nil
-		q.last = x
-		sgp.prev = nil
-		return
-	}
-	if y != nil {
-		// start of queue
-		y.prev = nil
-		q.first = y
-		sgp.next = nil
-		return
-	}
-
-	// x==y==nil.  Either sgp is the only element in the queue,
-	// or it has already been removed.  Use q.first to disambiguate.
-	if q.first == sgp {
-		q.first = nil
-		q.last = nil
+		l = &sgp.next
+		prevsgp = sgp
 	}
 }
diff --git a/src/runtime/sema.go b/src/runtime/sema.go
index 8ae51b4..26dbd30 100644
--- a/src/runtime/sema.go
+++ b/src/runtime/sema.go
@@ -38,23 +38,12 @@ var semtable [semTabSize]struct {
 	pad  [_CacheLineSize - unsafe.Sizeof(semaRoot{})]byte
 }
 
-//go:linkname sync_runtime_Semacquire sync.runtime_Semacquire
-func sync_runtime_Semacquire(addr *uint32) {
+// Called from sync/net packages.
+func asyncsemacquire(addr *uint32) {
 	semacquire(addr, true)
 }
 
-//go:linkname net_runtime_Semacquire net.runtime_Semacquire
-func net_runtime_Semacquire(addr *uint32) {
-	semacquire(addr, true)
-}
-
-//go:linkname sync_runtime_Semrelease sync.runtime_Semrelease
-func sync_runtime_Semrelease(addr *uint32) {
-	semrelease(addr)
-}
-
-//go:linkname net_runtime_Semrelease net.runtime_Semrelease
-func net_runtime_Semrelease(addr *uint32) {
+func asyncsemrelease(addr *uint32) {
 	semrelease(addr)
 }
 
@@ -62,7 +51,7 @@ func net_runtime_Semrelease(addr *uint32) {
 func semacquire(addr *uint32, profile bool) {
 	gp := getg()
 	if gp != gp.m.curg {
-		throw("semacquire not on the G stack")
+		gothrow("semacquire not on the G stack")
 	}
 
 	// Easy case.
@@ -97,7 +86,7 @@ func semacquire(addr *uint32, profile bool) {
 		// Any semrelease after the cansemacquire knows we're waiting
 		// (we set nwait above), so go to sleep.
 		root.queue(addr, s)
-		goparkunlock(&root.lock, "semacquire", traceEvGoBlockSync, 4)
+		goparkunlock(&root.lock, "semacquire")
 		if cansemacquire(addr) {
 			break
 		}
@@ -140,7 +129,7 @@ func semrelease(addr *uint32) {
 		if s.releasetime != 0 {
 			s.releasetime = cputicks()
 		}
-		goready(s.g, 4)
+		goready(s.g)
 	}
 }
 
@@ -196,8 +185,7 @@ type syncSema struct {
 	tail *sudog
 }
 
-// syncsemacquire waits for a pairing syncsemrelease on the same semaphore s.
-//go:linkname syncsemacquire sync.runtime_Syncsemacquire
+// Syncsemacquire waits for a pairing syncsemrelease on the same semaphore s.
 func syncsemacquire(s *syncSema) {
 	lock(&s.lock)
 	if s.head != nil && s.head.nrelease > 0 {
@@ -214,7 +202,7 @@ func syncsemacquire(s *syncSema) {
 		unlock(&s.lock)
 		if wake != nil {
 			wake.next = nil
-			goready(wake.g, 4)
+			goready(wake.g)
 		}
 	} else {
 		// Enqueue itself.
@@ -234,7 +222,7 @@ func syncsemacquire(s *syncSema) {
 			s.tail.next = w
 		}
 		s.tail = w
-		goparkunlock(&s.lock, "semacquire", traceEvGoBlockCond, 3)
+		goparkunlock(&s.lock, "semacquire")
 		if t0 != 0 {
 			blockevent(int64(w.releasetime)-t0, 2)
 		}
@@ -242,8 +230,7 @@ func syncsemacquire(s *syncSema) {
 	}
 }
 
-// syncsemrelease waits for n pairing syncsemacquire on the same semaphore s.
-//go:linkname syncsemrelease sync.runtime_Syncsemrelease
+// Syncsemrelease waits for n pairing syncsemacquire on the same semaphore s.
 func syncsemrelease(s *syncSema, n uint32) {
 	lock(&s.lock)
 	for n > 0 && s.head != nil && s.head.nrelease < 0 {
@@ -257,7 +244,7 @@ func syncsemrelease(s *syncSema, n uint32) {
 			wake.releasetime = cputicks()
 		}
 		wake.next = nil
-		goready(wake.g, 4)
+		goready(wake.g)
 		n--
 	}
 	if n > 0 {
@@ -273,17 +260,16 @@ func syncsemrelease(s *syncSema, n uint32) {
 			s.tail.next = w
 		}
 		s.tail = w
-		goparkunlock(&s.lock, "semarelease", traceEvGoBlockCond, 3)
+		goparkunlock(&s.lock, "semarelease")
 		releaseSudog(w)
 	} else {
 		unlock(&s.lock)
 	}
 }
 
-//go:linkname syncsemcheck sync.runtime_Syncsemcheck
 func syncsemcheck(sz uintptr) {
 	if sz != unsafe.Sizeof(syncSema{}) {
 		print("runtime: bad syncSema size - sync=", sz, " runtime=", unsafe.Sizeof(syncSema{}), "\n")
-		throw("bad syncSema size")
+		gothrow("bad syncSema size")
 	}
 }
diff --git a/src/runtime/signal.c b/src/runtime/signal.c
new file mode 100644
index 0000000..0674bfb
--- /dev/null
+++ b/src/runtime/signal.c
@@ -0,0 +1,25 @@
+// 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"
+
+void
+runtime·sigenable_m(void)
+{
+	uint32 s;
+	
+	s = g->m->scalararg[0];
+	g->m->scalararg[0] = 0;
+	runtime·sigenable(s);
+}
+
+void
+runtime·sigdisable_m(void)
+{
+	uint32 s;
+	
+	s = g->m->scalararg[0];
+	g->m->scalararg[0] = 0;
+	runtime·sigdisable(s);
+}
diff --git a/src/runtime/signal_386.c b/src/runtime/signal_386.c
new file mode 100644
index 0000000..30a7488
--- /dev/null
+++ b/src/runtime/signal_386.c
@@ -0,0 +1,122 @@
+// 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 nacl 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("eax     %x\n", SIG_EAX(info, ctxt));
+	runtime·printf("ebx     %x\n", SIG_EBX(info, ctxt));
+	runtime·printf("ecx     %x\n", SIG_ECX(info, ctxt));
+	runtime·printf("edx     %x\n", SIG_EDX(info, ctxt));
+	runtime·printf("edi     %x\n", SIG_EDI(info, ctxt));
+	runtime·printf("esi     %x\n", SIG_ESI(info, ctxt));
+	runtime·printf("ebp     %x\n", SIG_EBP(info, ctxt));
+	runtime·printf("esp     %x\n", SIG_ESP(info, ctxt));
+	runtime·printf("eip     %x\n", SIG_EIP(info, ctxt));
+	runtime·printf("eflags  %x\n", SIG_EFLAGS(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_EIP(info, ctxt), (byte*)SIG_ESP(info, ctxt), nil, gp, g->m);
+		return;
+	}
+
+	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_EIP(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] == 0x66)	// 16-bit instruction prefix
+				pc++;
+			if(pc[0] == 0xF6 || pc[0] == 0xF7)
+				gp->sigcode0 = FPE_INTDIV;
+		}
+#endif
+
+		// Only push runtime·sigpanic if eip != 0.
+		// If eip == 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_EIP(info, ctxt) != 0) {
+			sp = (uintptr*)SIG_ESP(info, ctxt);
+			*--sp = SIG_EIP(info, ctxt);
+			SIG_ESP(info, ctxt) = (uintptr)sp;
+		}
+		SIG_EIP(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;
+
+	g->m->throwing = 1;
+	g->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_EIP(info, ctxt));
+	if(g->m->lockedg != nil && g->m->ncgo > 0 && gp == g->m->g0) {
+		runtime·printf("signal arrived during cgo execution\n");
+		gp = g->m->lockedg;
+	}
+	runtime·printf("\n");
+
+	if(runtime·gotraceback(&crash)){
+		runtime·goroutineheader(gp);
+		runtime·tracebacktrap(SIG_EIP(info, ctxt), SIG_ESP(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/runtime/signal_amd64x.c b/src/runtime/signal_amd64x.c
new file mode 100644
index 0000000..feb4afc
--- /dev/null
+++ b/src/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, g->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;
+
+	g->m->throwing = 1;
+	g->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(g->m->lockedg != nil && g->m->ncgo > 0 && gp == g->m->g0) {
+		runtime·printf("signal arrived during cgo execution\n");
+		gp = g->m->lockedg;
+	}
+	runtime·printf("\n");
+
+	if(runtime·gotraceback(&crash)){
+		runtime·goroutineheader(gp);
+		runtime·tracebacktrap(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/runtime/signal_android_386.h b/src/runtime/signal_android_386.h
new file mode 100644
index 0000000..2a1bb4b
--- /dev/null
+++ b/src/runtime/signal_android_386.h
@@ -0,0 +1 @@
+#include "signal_linux_386.h"
diff --git a/src/runtime/signal_android_arm.h b/src/runtime/signal_android_arm.h
new file mode 100644
index 0000000..8a05e21
--- /dev/null
+++ b/src/runtime/signal_android_arm.h
@@ -0,0 +1 @@
+#include "signal_linux_arm.h"
diff --git a/src/runtime/signal_arm.c b/src/runtime/signal_arm.c
new file mode 100644
index 0000000..afad5e7
--- /dev/null
+++ b/src/runtime/signal_arm.c
@@ -0,0 +1,121 @@
+// 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 darwin dragonfly freebsd linux nacl 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("trap    %x\n", SIG_TRAP(info, ctxt));
+	runtime·printf("error   %x\n", SIG_ERROR(info, ctxt));
+	runtime·printf("oldmask %x\n", SIG_OLDMASK(info, ctxt));
+	runtime·printf("r0      %x\n", SIG_R0(info, ctxt));
+	runtime·printf("r1      %x\n", SIG_R1(info, ctxt));
+	runtime·printf("r2      %x\n", SIG_R2(info, ctxt));
+	runtime·printf("r3      %x\n", SIG_R3(info, ctxt));
+	runtime·printf("r4      %x\n", SIG_R4(info, ctxt));
+	runtime·printf("r5      %x\n", SIG_R5(info, ctxt));
+	runtime·printf("r6      %x\n", SIG_R6(info, ctxt));
+	runtime·printf("r7      %x\n", SIG_R7(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("fp      %x\n", SIG_FP(info, ctxt));
+	runtime·printf("ip      %x\n", SIG_IP(info, ctxt));
+	runtime·printf("sp      %x\n", SIG_SP(info, ctxt));
+	runtime·printf("lr      %x\n", SIG_LR(info, ctxt));
+	runtime·printf("pc      %x\n", SIG_PC(info, ctxt));
+	runtime·printf("cpsr    %x\n", SIG_CPSR(info, ctxt));
+	runtime·printf("fault   %x\n", SIG_FAULT(info, ctxt));
+}
+
+void
+runtime·sighandler(int32 sig, Siginfo *info, void *ctxt, G *gp)
+{
+	SigTab *t;
+	bool crash;
+
+	if(sig == SIGPROF) {
+		runtime·sigprof((uint8*)SIG_PC(info, ctxt), (uint8*)SIG_SP(info, ctxt), (uint8*)SIG_LR(info, ctxt), gp, g->m);
+		return;
+	}
+
+	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_FAULT(info, ctxt);
+		gp->sigpc = SIG_PC(info, ctxt);
+
+		// We arrange lr, and pc to pretend the panicking
+		// function calls sigpanic directly.
+		// Always save LR to stack so that panics in leaf
+		// functions are correctly handled. This smashes
+		// the stack frame but we're not going back there
+		// anyway.
+		SIG_SP(info, ctxt) -= 4;
+		*(uint32*)SIG_SP(info, ctxt) = SIG_LR(info, ctxt);
+		// Don't bother saving PC if it's zero, which is
+		// probably a call to a nil func: the old link register
+		// is more useful in the stack trace.
+		if(gp->sigpc != 0)
+			SIG_LR(info, ctxt) = gp->sigpc;
+		// In case we are panicking from external C code
+		SIG_R10(info, ctxt) = (uintptr)gp;
+		SIG_PC(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;
+
+	g->m->throwing = 1;
+	g->m->caughtsig = gp;
+	if(runtime·panicking)	// traceback already printed
+		runtime·exit(2);
+	runtime·panicking = 1;
+
+	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_PC(info, ctxt));
+	if(g->m->lockedg != nil && g->m->ncgo > 0 && gp == g->m->g0) {
+		runtime·printf("signal arrived during cgo execution\n");
+		gp = g->m->lockedg;
+	}
+	runtime·printf("\n");
+
+	if(runtime·gotraceback(&crash)){
+		runtime·goroutineheader(gp);
+		runtime·tracebacktrap(SIG_PC(info, ctxt), SIG_SP(info, ctxt), SIG_LR(info, ctxt), gp);
+		runtime·tracebackothers(gp);
+		runtime·printf("\n");
+		runtime·dumpregs(info, ctxt);
+	}
+	
+	if(crash)
+		runtime·crash();
+
+	runtime·exit(2);
+}
diff --git a/src/runtime/signal_darwin_386.h b/src/runtime/signal_darwin_386.h
new file mode 100644
index 0000000..5459e10
--- /dev/null
+++ b/src/runtime/signal_darwin_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) (((Ucontext*)(ctxt))->uc_mcontext->ss)
+
+#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) (SIG_REGS(ctxt).cs)
+#define SIG_FS(info, ctxt) (SIG_REGS(ctxt).fs)
+#define SIG_GS(info, ctxt) (SIG_REGS(ctxt).gs)
+
+#define SIG_CODE0(info, ctxt) ((info)->si_code)
+#define SIG_CODE1(info, ctxt) ((uintptr)(info)->si_addr)
diff --git a/src/runtime/signal_darwin_amd64.h b/src/runtime/signal_darwin_amd64.h
new file mode 100644
index 0000000..e3da6de
--- /dev/null
+++ b/src/runtime/signal_darwin_amd64.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) (((Ucontext*)(ctxt))->uc_mcontext->ss)
+
+#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) (SIG_REGS(ctxt).cs)
+#define SIG_FS(info, ctxt) (SIG_REGS(ctxt).fs)
+#define SIG_GS(info, ctxt) (SIG_REGS(ctxt).gs)
+
+#define SIG_CODE0(info, ctxt) ((info)->si_code)
+#define SIG_CODE1(info, ctxt) ((uintptr)(info)->si_addr)
diff --git a/src/runtime/signal_dragonfly_386.h b/src/runtime/signal_dragonfly_386.h
new file mode 100644
index 0000000..a24f1ee
--- /dev/null
+++ b/src/runtime/signal_dragonfly_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) (((Ucontext*)(ctxt))->uc_mcontext)
+
+#define SIG_EAX(info, ctxt) (SIG_REGS(ctxt).mc_eax)
+#define SIG_EBX(info, ctxt) (SIG_REGS(ctxt).mc_ebx)
+#define SIG_ECX(info, ctxt) (SIG_REGS(ctxt).mc_ecx)
+#define SIG_EDX(info, ctxt) (SIG_REGS(ctxt).mc_edx)
+#define SIG_EDI(info, ctxt) (SIG_REGS(ctxt).mc_edi)
+#define SIG_ESI(info, ctxt) (SIG_REGS(ctxt).mc_esi)
+#define SIG_EBP(info, ctxt) (SIG_REGS(ctxt).mc_ebp)
+#define SIG_ESP(info, ctxt) (SIG_REGS(ctxt).mc_esp)
+#define SIG_EIP(info, ctxt) (SIG_REGS(ctxt).mc_eip)
+#define SIG_EFLAGS(info, ctxt) (SIG_REGS(ctxt).mc_eflags)
+
+#define SIG_CS(info, ctxt) (SIG_REGS(ctxt).mc_cs)
+#define SIG_FS(info, ctxt) (SIG_REGS(ctxt).mc_fs)
+#define SIG_GS(info, ctxt) (SIG_REGS(ctxt).mc_gs)
+
+#define SIG_CODE0(info, ctxt) ((info)->si_code)
+#define SIG_CODE1(info, ctxt) ((uintptr)(info)->si_addr)
diff --git a/src/runtime/signal_dragonfly_amd64.h b/src/runtime/signal_dragonfly_amd64.h
new file mode 100644
index 0000000..5b4f977
--- /dev/null
+++ b/src/runtime/signal_dragonfly_amd64.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) (((Ucontext*)(ctxt))->uc_mcontext)
+
+#define SIG_RAX(info, ctxt) (SIG_REGS(ctxt).mc_rax)
+#define SIG_RBX(info, ctxt) (SIG_REGS(ctxt).mc_rbx)
+#define SIG_RCX(info, ctxt) (SIG_REGS(ctxt).mc_rcx)
+#define SIG_RDX(info, ctxt) (SIG_REGS(ctxt).mc_rdx)
+#define SIG_RDI(info, ctxt) (SIG_REGS(ctxt).mc_rdi)
+#define SIG_RSI(info, ctxt) (SIG_REGS(ctxt).mc_rsi)
+#define SIG_RBP(info, ctxt) (SIG_REGS(ctxt).mc_rbp)
+#define SIG_RSP(info, ctxt) (SIG_REGS(ctxt).mc_rsp)
+#define SIG_R8(info, ctxt) (SIG_REGS(ctxt).mc_r8)
+#define SIG_R9(info, ctxt) (SIG_REGS(ctxt).mc_r9)
+#define SIG_R10(info, ctxt) (SIG_REGS(ctxt).mc_r10)
+#define SIG_R11(info, ctxt) (SIG_REGS(ctxt).mc_r11)
+#define SIG_R12(info, ctxt) (SIG_REGS(ctxt).mc_r12)
+#define SIG_R13(info, ctxt) (SIG_REGS(ctxt).mc_r13)
+#define SIG_R14(info, ctxt) (SIG_REGS(ctxt).mc_r14)
+#define SIG_R15(info, ctxt) (SIG_REGS(ctxt).mc_r15)
+#define SIG_RIP(info, ctxt) (SIG_REGS(ctxt).mc_rip)
+#define SIG_RFLAGS(info, ctxt) (SIG_REGS(ctxt).mc_rflags)
+
+#define SIG_CS(info, ctxt) (SIG_REGS(ctxt).mc_cs)
+#define SIG_FS(info, ctxt) (SIG_REGS(ctxt).mc_ss)
+#define SIG_GS(info, ctxt) (SIG_REGS(ctxt).mc_ss)
+
+#define SIG_CODE0(info, ctxt) ((info)->si_code)
+#define SIG_CODE1(info, ctxt) ((uintptr)(info)->si_addr)
diff --git a/src/runtime/signal_freebsd_386.h b/src/runtime/signal_freebsd_386.h
new file mode 100644
index 0000000..a24f1ee
--- /dev/null
+++ b/src/runtime/signal_freebsd_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) (((Ucontext*)(ctxt))->uc_mcontext)
+
+#define SIG_EAX(info, ctxt) (SIG_REGS(ctxt).mc_eax)
+#define SIG_EBX(info, ctxt) (SIG_REGS(ctxt).mc_ebx)
+#define SIG_ECX(info, ctxt) (SIG_REGS(ctxt).mc_ecx)
+#define SIG_EDX(info, ctxt) (SIG_REGS(ctxt).mc_edx)
+#define SIG_EDI(info, ctxt) (SIG_REGS(ctxt).mc_edi)
+#define SIG_ESI(info, ctxt) (SIG_REGS(ctxt).mc_esi)
+#define SIG_EBP(info, ctxt) (SIG_REGS(ctxt).mc_ebp)
+#define SIG_ESP(info, ctxt) (SIG_REGS(ctxt).mc_esp)
+#define SIG_EIP(info, ctxt) (SIG_REGS(ctxt).mc_eip)
+#define SIG_EFLAGS(info, ctxt) (SIG_REGS(ctxt).mc_eflags)
+
+#define SIG_CS(info, ctxt) (SIG_REGS(ctxt).mc_cs)
+#define SIG_FS(info, ctxt) (SIG_REGS(ctxt).mc_fs)
+#define SIG_GS(info, ctxt) (SIG_REGS(ctxt).mc_gs)
+
+#define SIG_CODE0(info, ctxt) ((info)->si_code)
+#define SIG_CODE1(info, ctxt) ((uintptr)(info)->si_addr)
diff --git a/src/runtime/signal_freebsd_amd64.h b/src/runtime/signal_freebsd_amd64.h
new file mode 100644
index 0000000..7d35b7f
--- /dev/null
+++ b/src/runtime/signal_freebsd_amd64.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) (((Ucontext*)(ctxt))->uc_mcontext)
+
+#define SIG_RAX(info, ctxt) (SIG_REGS(ctxt).mc_rax)
+#define SIG_RBX(info, ctxt) (SIG_REGS(ctxt).mc_rbx)
+#define SIG_RCX(info, ctxt) (SIG_REGS(ctxt).mc_rcx)
+#define SIG_RDX(info, ctxt) (SIG_REGS(ctxt).mc_rdx)
+#define SIG_RDI(info, ctxt) (SIG_REGS(ctxt).mc_rdi)
+#define SIG_RSI(info, ctxt) (SIG_REGS(ctxt).mc_rsi)
+#define SIG_RBP(info, ctxt) (SIG_REGS(ctxt).mc_rbp)
+#define SIG_RSP(info, ctxt) (SIG_REGS(ctxt).mc_rsp)
+#define SIG_R8(info, ctxt) (SIG_REGS(ctxt).mc_r8)
+#define SIG_R9(info, ctxt) (SIG_REGS(ctxt).mc_r9)
+#define SIG_R10(info, ctxt) (SIG_REGS(ctxt).mc_r10)
+#define SIG_R11(info, ctxt) (SIG_REGS(ctxt).mc_r11)
+#define SIG_R12(info, ctxt) (SIG_REGS(ctxt).mc_r12)
+#define SIG_R13(info, ctxt) (SIG_REGS(ctxt).mc_r13)
+#define SIG_R14(info, ctxt) (SIG_REGS(ctxt).mc_r14)
+#define SIG_R15(info, ctxt) (SIG_REGS(ctxt).mc_r15)
+#define SIG_RIP(info, ctxt) (SIG_REGS(ctxt).mc_rip)
+#define SIG_RFLAGS(info, ctxt) (SIG_REGS(ctxt).mc_rflags)
+
+#define SIG_CS(info, ctxt) (SIG_REGS(ctxt).mc_cs)
+#define SIG_FS(info, ctxt) (SIG_REGS(ctxt).mc_fs)
+#define SIG_GS(info, ctxt) (SIG_REGS(ctxt).mc_gs)
+
+#define SIG_CODE0(info, ctxt) ((info)->si_code)
+#define SIG_CODE1(info, ctxt) ((uintptr)(info)->si_addr)
diff --git a/src/runtime/signal_freebsd_arm.h b/src/runtime/signal_freebsd_arm.h
new file mode 100644
index 0000000..87a45aa
--- /dev/null
+++ b/src/runtime/signal_freebsd_arm.h
@@ -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.
+
+#define SIG_REGS(ctxt) (((Ucontext*)(ctxt))->uc_mcontext)
+
+#define SIG_R0(info, ctxt) (SIG_REGS(ctxt).__gregs[0])
+#define SIG_R1(info, ctxt) (SIG_REGS(ctxt).__gregs[1])
+#define SIG_R2(info, ctxt) (SIG_REGS(ctxt).__gregs[2])
+#define SIG_R3(info, ctxt) (SIG_REGS(ctxt).__gregs[3])
+#define SIG_R4(info, ctxt) (SIG_REGS(ctxt).__gregs[4])
+#define SIG_R5(info, ctxt) (SIG_REGS(ctxt).__gregs[5])
+#define SIG_R6(info, ctxt) (SIG_REGS(ctxt).__gregs[6])
+#define SIG_R7(info, ctxt) (SIG_REGS(ctxt).__gregs[7])
+#define SIG_R8(info, ctxt) (SIG_REGS(ctxt).__gregs[8])
+#define SIG_R9(info, ctxt) (SIG_REGS(ctxt).__gregs[9])
+#define SIG_R10(info, ctxt) (SIG_REGS(ctxt).__gregs[10])
+#define SIG_FP(info, ctxt) (SIG_REGS(ctxt).__gregs[11])
+#define SIG_IP(info, ctxt) (SIG_REGS(ctxt).__gregs[12])
+#define SIG_SP(info, ctxt) (SIG_REGS(ctxt).__gregs[13])
+#define SIG_LR(info, ctxt) (SIG_REGS(ctxt).__gregs[14])
+#define SIG_PC(info, ctxt) (SIG_REGS(ctxt).__gregs[15])
+#define SIG_CPSR(info, ctxt) (SIG_REGS(ctxt).__gregs[16])
+#define SIG_FAULT(info, ctxt) ((uintptr)(info)->si_addr)
+#define SIG_TRAP(info, ctxt) (0)
+#define SIG_ERROR(info, ctxt) (0)
+#define SIG_OLDMASK(info, ctxt) (0)
+#define SIG_CODE0(info, ctxt) ((uintptr)(info)->si_code)
diff --git a/src/runtime/signal_linux_386.h b/src/runtime/signal_linux_386.h
new file mode 100644
index 0000000..f77f1c9
--- /dev/null
+++ b/src/runtime/signal_linux_386.h
@@ -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.
+
+#define SIG_REGS(ctxt) (*((Sigcontext*)&((Ucontext*)(ctxt))->uc_mcontext))
+
+#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) (SIG_REGS(ctxt).cs)
+#define SIG_FS(info, ctxt) (SIG_REGS(ctxt).fs)
+#define SIG_GS(info, ctxt) (SIG_REGS(ctxt).gs)
+
+#define SIG_CODE0(info, ctxt) ((info)->si_code)
+#define SIG_CODE1(info, ctxt) (((uintptr*)(info))[2])
+
diff --git a/src/runtime/signal_linux_amd64.h b/src/runtime/signal_linux_amd64.h
new file mode 100644
index 0000000..5a9a3e5
--- /dev/null
+++ b/src/runtime/signal_linux_amd64.h
@@ -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.
+
+#define SIG_REGS(ctxt) (*((Sigcontext*)&((Ucontext*)(ctxt))->uc_mcontext))
+
+#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) ((uint64)SIG_REGS(ctxt).eflags)
+
+#define SIG_CS(info, ctxt) ((uint64)SIG_REGS(ctxt).cs)
+#define SIG_FS(info, ctxt) ((uint64)SIG_REGS(ctxt).fs)
+#define SIG_GS(info, ctxt) ((uint64)SIG_REGS(ctxt).gs)
+
+#define SIG_CODE0(info, ctxt) ((info)->si_code)
+#define SIG_CODE1(info, ctxt) (((uintptr*)(info))[2])
+
diff --git a/src/runtime/signal_linux_arm.h b/src/runtime/signal_linux_arm.h
new file mode 100644
index 0000000..a674c0d
--- /dev/null
+++ b/src/runtime/signal_linux_arm.h
@@ -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.
+
+#define SIG_REGS(ctxt) (*((Sigcontext*)&((Ucontext*)(ctxt))->uc_mcontext))
+
+#define SIG_R0(info, ctxt) (SIG_REGS(ctxt).arm_r0)
+#define SIG_R1(info, ctxt) (SIG_REGS(ctxt).arm_r1)
+#define SIG_R2(info, ctxt) (SIG_REGS(ctxt).arm_r2)
+#define SIG_R3(info, ctxt) (SIG_REGS(ctxt).arm_r3)
+#define SIG_R4(info, ctxt) (SIG_REGS(ctxt).arm_r4)
+#define SIG_R5(info, ctxt) (SIG_REGS(ctxt).arm_r5)
+#define SIG_R6(info, ctxt) (SIG_REGS(ctxt).arm_r6)
+#define SIG_R7(info, ctxt) (SIG_REGS(ctxt).arm_r7)
+#define SIG_R8(info, ctxt) (SIG_REGS(ctxt).arm_r8)
+#define SIG_R9(info, ctxt) (SIG_REGS(ctxt).arm_r9)
+#define SIG_R10(info, ctxt) (SIG_REGS(ctxt).arm_r10)
+#define SIG_FP(info, ctxt) (SIG_REGS(ctxt).arm_fp)
+#define SIG_IP(info, ctxt) (SIG_REGS(ctxt).arm_ip)
+#define SIG_SP(info, ctxt) (SIG_REGS(ctxt).arm_sp)
+#define SIG_LR(info, ctxt) (SIG_REGS(ctxt).arm_lr)
+#define SIG_PC(info, ctxt) (SIG_REGS(ctxt).arm_pc)
+#define SIG_CPSR(info, ctxt) (SIG_REGS(ctxt).arm_cpsr)
+#define SIG_FAULT(info, ctxt) (SIG_REGS(ctxt).fault_address)
+#define SIG_TRAP(info, ctxt) (SIG_REGS(ctxt).trap_no)
+#define SIG_ERROR(info, ctxt) (SIG_REGS(ctxt).error_code)
+#define SIG_OLDMASK(info, ctxt) (SIG_REGS(ctxt).oldmask)
+#define SIG_CODE0(info, ctxt) ((uintptr)(info)->si_code)
diff --git a/src/runtime/signal_nacl_386.h b/src/runtime/signal_nacl_386.h
new file mode 100644
index 0000000..c9481b5
--- /dev/null
+++ b/src/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/runtime/signal_nacl_amd64p32.h b/src/runtime/signal_nacl_amd64p32.h
new file mode 100644
index 0000000..f62305c
--- /dev/null
+++ b/src/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))->regs.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/runtime/signal_nacl_arm.h b/src/runtime/signal_nacl_arm.h
new file mode 100644
index 0000000..e5bbb21
--- /dev/null
+++ b/src/runtime/signal_nacl_arm.h
@@ -0,0 +1,28 @@
+// 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) (((ExcContext*)(ctxt))->regs)
+
+#define SIG_R0(info, ctxt) (SIG_REGS(ctxt).r0)
+#define SIG_R1(info, ctxt) (SIG_REGS(ctxt).r1)
+#define SIG_R2(info, ctxt) (SIG_REGS(ctxt).r2)
+#define SIG_R3(info, ctxt) (SIG_REGS(ctxt).r3)
+#define SIG_R4(info, ctxt) (SIG_REGS(ctxt).r4)
+#define SIG_R5(info, ctxt) (SIG_REGS(ctxt).r5)
+#define SIG_R6(info, ctxt) (SIG_REGS(ctxt).r6)
+#define SIG_R7(info, ctxt) (SIG_REGS(ctxt).r7)
+#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_FP(info, ctxt) (SIG_REGS(ctxt).r11)
+#define SIG_IP(info, ctxt) (SIG_REGS(ctxt).r12)
+#define SIG_SP(info, ctxt) (SIG_REGS(ctxt).sp)
+#define SIG_LR(info, ctxt) (SIG_REGS(ctxt).lr)
+#define SIG_PC(info, ctxt) (SIG_REGS(ctxt).pc)
+#define SIG_CPSR(info, ctxt) (SIG_REGS(ctxt).cpsr)
+#define SIG_FAULT(info, ctxt) (~0)
+#define SIG_TRAP(info, ctxt) (~0)
+#define SIG_ERROR(info, ctxt) (~0)
+#define SIG_OLDMASK(info, ctxt) (~0)
+#define SIG_CODE0(info, ctxt) (~0)
diff --git a/src/runtime/signal_netbsd_386.h b/src/runtime/signal_netbsd_386.h
new file mode 100644
index 0000000..d5a8a0c
--- /dev/null
+++ b/src/runtime/signal_netbsd_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) (((UcontextT*)(ctxt))->uc_mcontext)
+
+#define SIG_EAX(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_EAX])
+#define SIG_EBX(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_EBX])
+#define SIG_ECX(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_ECX])
+#define SIG_EDX(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_EDX])
+#define SIG_EDI(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_EDI])
+#define SIG_ESI(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_ESI])
+#define SIG_EBP(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_EBP])
+#define SIG_ESP(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_UESP])
+#define SIG_EIP(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_EIP])
+#define SIG_EFLAGS(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_EFL])
+
+#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)->_code)
+#define SIG_CODE1(info, ctxt) (*(uintptr*)&(info)->_reason[0])
diff --git a/src/runtime/signal_netbsd_amd64.h b/src/runtime/signal_netbsd_amd64.h
new file mode 100644
index 0000000..7ec4cd9
--- /dev/null
+++ b/src/runtime/signal_netbsd_amd64.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) (((UcontextT*)(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)->_code)
+#define SIG_CODE1(info, ctxt) (*(uintptr*)&(info)->_reason[0])
diff --git a/src/runtime/signal_netbsd_arm.h b/src/runtime/signal_netbsd_arm.h
new file mode 100644
index 0000000..12f5827
--- /dev/null
+++ b/src/runtime/signal_netbsd_arm.h
@@ -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.
+
+#define SIG_REGS(ctxt) (((UcontextT*)(ctxt))->uc_mcontext)
+
+#define SIG_R0(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R0])
+#define SIG_R1(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R1])
+#define SIG_R2(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R2])
+#define SIG_R3(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R3])
+#define SIG_R4(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R4])
+#define SIG_R5(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R5])
+#define SIG_R6(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R6])
+#define SIG_R7(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R7])
+#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_FP(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R11])
+#define SIG_IP(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R12])
+#define SIG_SP(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R13])
+#define SIG_LR(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R14])
+#define SIG_PC(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R15])
+#define SIG_CPSR(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_CPSR])
+#define SIG_FAULT(info, ctxt) (*(uintptr*)&(info)->_reason[0])
+#define SIG_TRAP(info, ctxt) (0)
+#define SIG_ERROR(info, ctxt) (0)
+#define SIG_OLDMASK(info, ctxt) (0)
+
+#define SIG_CODE0(info, ctxt) ((info)->_code)
+#define SIG_CODE1(info, ctxt) (*(uintptr*)&(info)->_reason[0])
diff --git a/src/runtime/signal_openbsd_386.h b/src/runtime/signal_openbsd_386.h
new file mode 100644
index 0000000..6742db8
--- /dev/null
+++ b/src/runtime/signal_openbsd_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) (*(Sigcontext*)(ctxt))
+
+#define SIG_EAX(info, ctxt) (SIG_REGS(ctxt).sc_eax)
+#define SIG_EBX(info, ctxt) (SIG_REGS(ctxt).sc_ebx)
+#define SIG_ECX(info, ctxt) (SIG_REGS(ctxt).sc_ecx)
+#define SIG_EDX(info, ctxt) (SIG_REGS(ctxt).sc_edx)
+#define SIG_EDI(info, ctxt) (SIG_REGS(ctxt).sc_edi)
+#define SIG_ESI(info, ctxt) (SIG_REGS(ctxt).sc_esi)
+#define SIG_EBP(info, ctxt) (SIG_REGS(ctxt).sc_ebp)
+#define SIG_ESP(info, ctxt) (SIG_REGS(ctxt).sc_esp)
+#define SIG_EIP(info, ctxt) (SIG_REGS(ctxt).sc_eip)
+#define SIG_EFLAGS(info, ctxt) (SIG_REGS(ctxt).sc_eflags)
+
+#define SIG_CS(info, ctxt) (SIG_REGS(ctxt).sc_cs)
+#define SIG_FS(info, ctxt) (SIG_REGS(ctxt).sc_fs)
+#define SIG_GS(info, ctxt) (SIG_REGS(ctxt).sc_gs)
+
+#define SIG_CODE0(info, ctxt) ((info)->si_code)
+#define SIG_CODE1(info, ctxt) (*(uintptr*)((byte*)info + 12))
diff --git a/src/runtime/signal_openbsd_amd64.h b/src/runtime/signal_openbsd_amd64.h
new file mode 100644
index 0000000..b46a5df
--- /dev/null
+++ b/src/runtime/signal_openbsd_amd64.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) (*(Sigcontext*)(ctxt))
+
+#define SIG_RAX(info, ctxt) (SIG_REGS(ctxt).sc_rax)
+#define SIG_RBX(info, ctxt) (SIG_REGS(ctxt).sc_rbx)
+#define SIG_RCX(info, ctxt) (SIG_REGS(ctxt).sc_rcx)
+#define SIG_RDX(info, ctxt) (SIG_REGS(ctxt).sc_rdx)
+#define SIG_RDI(info, ctxt) (SIG_REGS(ctxt).sc_rdi)
+#define SIG_RSI(info, ctxt) (SIG_REGS(ctxt).sc_rsi)
+#define SIG_RBP(info, ctxt) (SIG_REGS(ctxt).sc_rbp)
+#define SIG_RSP(info, ctxt) (SIG_REGS(ctxt).sc_rsp)
+#define SIG_R8(info, ctxt) (SIG_REGS(ctxt).sc_r8)
+#define SIG_R9(info, ctxt) (SIG_REGS(ctxt).sc_r9)
+#define SIG_R10(info, ctxt) (SIG_REGS(ctxt).sc_r10)
+#define SIG_R11(info, ctxt) (SIG_REGS(ctxt).sc_r11)
+#define SIG_R12(info, ctxt) (SIG_REGS(ctxt).sc_r12)
+#define SIG_R13(info, ctxt) (SIG_REGS(ctxt).sc_r13)
+#define SIG_R14(info, ctxt) (SIG_REGS(ctxt).sc_r14)
+#define SIG_R15(info, ctxt) (SIG_REGS(ctxt).sc_r15)
+#define SIG_RIP(info, ctxt) (SIG_REGS(ctxt).sc_rip)
+#define SIG_RFLAGS(info, ctxt) (SIG_REGS(ctxt).sc_rflags)
+
+#define SIG_CS(info, ctxt) (SIG_REGS(ctxt).sc_cs)
+#define SIG_FS(info, ctxt) (SIG_REGS(ctxt).sc_fs)
+#define SIG_GS(info, ctxt) (SIG_REGS(ctxt).sc_gs)
+
+#define SIG_CODE0(info, ctxt) ((info)->si_code)
+#define SIG_CODE1(info, ctxt) (*(uintptr*)((byte*)(info) + 16))
diff --git a/src/runtime/signal_solaris_amd64.h b/src/runtime/signal_solaris_amd64.h
new file mode 100644
index 0000000..c2e0a15
--- /dev/null
+++ b/src/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/runtime/signal_unix.c b/src/runtime/signal_unix.c
new file mode 100644
index 0000000..0e33ece
--- /dev/null
+++ b/src/runtime/signal_unix.c
@@ -0,0 +1,119 @@
+// 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 darwin dragonfly freebsd linux netbsd openbsd solaris
+
+#include "runtime.h"
+#include "defs_GOOS_GOARCH.h"
+#include "os_GOOS.h"
+#include "signal_unix.h"
+
+extern SigTab runtime·sigtab[];
+
+void
+runtime·initsig(void)
+{
+	int32 i;
+	SigTab *t;
+
+	// First call: basic setup.
+	for(i = 0; i<NSIG; i++) {
+		t = &runtime·sigtab[i];
+		if((t->flags == 0) || (t->flags & SigDefault))
+			continue;
+
+		// For some signals, we respect an inherited SIG_IGN handler
+		// rather than insist on installing our own default handler.
+		// Even these signals can be fetched using the os/signal package.
+		switch(i) {
+		case SIGHUP:
+		case SIGINT:
+			if(runtime·getsig(i) == SIG_IGN) {
+				t->flags = SigNotify | SigIgnored;
+				continue;
+			}
+		}
+
+		t->flags |= SigHandling;
+		runtime·setsig(i, runtime·sighandler, true);
+	}
+}
+
+void
+runtime·sigenable(uint32 sig)
+{
+	SigTab *t;
+
+	if(sig >= NSIG)
+		return;
+
+	t = &runtime·sigtab[sig];
+	if((t->flags & SigNotify) && !(t->flags & SigHandling)) {
+		t->flags |= SigHandling;
+		if(runtime·getsig(sig) == SIG_IGN)
+			t->flags |= SigIgnored;
+		runtime·setsig(sig, runtime·sighandler, true);
+	}
+}
+
+void
+runtime·sigdisable(uint32 sig)
+{
+	SigTab *t;
+
+	if(sig >= NSIG)
+		return;
+
+	t = &runtime·sigtab[sig];
+	if((t->flags & SigNotify) && (t->flags & SigHandling)) {
+		t->flags &= ~SigHandling;
+		if(t->flags & SigIgnored)
+			runtime·setsig(sig, SIG_IGN, true);
+		else
+			runtime·setsig(sig, SIG_DFL, true);
+	}
+}
+
+void
+runtime·resetcpuprofiler(int32 hz)
+{
+	Itimerval it;
+
+	runtime·memclr((byte*)&it, sizeof it);
+	if(hz == 0) {
+		runtime·setitimer(ITIMER_PROF, &it, nil);
+	} else {
+		it.it_interval.tv_sec = 0;
+		it.it_interval.tv_usec = 1000000 / hz;
+		it.it_value = it.it_interval;
+		runtime·setitimer(ITIMER_PROF, &it, nil);
+	}
+	g->m->profilehz = hz;
+}
+
+void
+runtime·sigpipe(void)
+{
+	runtime·setsig(SIGPIPE, SIG_DFL, false);
+	runtime·raise(SIGPIPE);
+}
+
+void
+runtime·crash(void)
+{
+#ifdef GOOS_darwin
+	// OS X core dumps are linear dumps of the mapped memory,
+	// from the first virtual byte to the last, with zeros in the gaps.
+	// Because of the way we arrange the address space on 64-bit systems,
+	// this means the OS X core file will be >128 GB and even on a zippy
+	// workstation can take OS X well over an hour to write (uninterruptible).
+	// Save users from making that mistake.
+	if(sizeof(void*) == 8)
+		return;
+#endif
+
+	runtime·unblocksignals();
+	runtime·setsig(SIGABRT, SIG_DFL, false);
+	runtime·raise(SIGABRT);
+}
diff --git a/src/runtime/signal_unix.go b/src/runtime/signal_unix.go
index ad3ab31..ba77b6e 100644
--- a/src/runtime/signal_unix.go
+++ b/src/runtime/signal_unix.go
@@ -6,43 +6,8 @@
 
 package runtime
 
-import "unsafe"
+func sigpipe()
 
-//go:linkname os_sigpipe os.sigpipe
 func os_sigpipe() {
-	systemstack(sigpipe)
-}
-
-// Determines if the signal should be handled by Go and if not, forwards the
-// signal to the handler that was installed before Go's.  Returns whether the
-// signal was forwarded.
-//go:nosplit
-func sigfwdgo(sig uint32, info *siginfo, ctx unsafe.Pointer) bool {
-	g := getg()
-	c := &sigctxt{info, ctx}
-	if sig >= uint32(len(sigtable)) {
-		return false
-	}
-	fwdFn := fwdSig[sig]
-	flags := sigtable[sig].flags
-
-	// If there is no handler to forward to, no need to forward.
-	if fwdFn == _SIG_DFL {
-		return false
-	}
-	// Only forward synchronous signals.
-	if c.sigcode() == _SI_USER || flags&_SigPanic == 0 {
-		return false
-	}
-	// Determine if the signal occurred inside Go code.  We test that:
-	//   (1) we were in a goroutine (i.e., m.curg != nil), and
-	//   (2) we weren't in CGO (i.e., m.curg.syscallsp == 0).
-	if g != nil && g.m != nil && g.m.curg != nil && g.m.curg.syscallsp == 0 {
-		return false
-	}
-	// Signal not handled by Go, forward it.
-	if fwdFn != _SIG_IGN {
-		sigfwd(fwdFn, sig, info, ctx)
-	}
-	return true
+	onM(sigpipe)
 }
diff --git a/src/runtime/signal_unix.h b/src/runtime/signal_unix.h
new file mode 100644
index 0000000..2d84a01
--- /dev/null
+++ b/src/runtime/signal_unix.h
@@ -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.
+
+#define SIG_DFL ((void*)0)
+#define SIG_IGN ((void*)1)
+
+typedef void GoSighandler(int32, Siginfo*, void*, G*);
+void	runtime·setsig(int32, GoSighandler*, bool);
+GoSighandler* runtime·getsig(int32);
+
+void	runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp);
+void	runtime·raise(int32);
+
diff --git a/src/runtime/signals_android.h b/src/runtime/signals_android.h
new file mode 100644
index 0000000..5140d8a
--- /dev/null
+++ b/src/runtime/signals_android.h
@@ -0,0 +1 @@
+#include "signals_linux.h"
diff --git a/src/runtime/signals_darwin.h b/src/runtime/signals_darwin.h
new file mode 100644
index 0000000..8761e1b
--- /dev/null
+++ b/src/runtime/signals_darwin.h
@@ -0,0 +1,53 @@
+// 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 "textflag.h"
+
+#define N SigNotify
+#define K SigKill
+#define T SigThrow
+#define P SigPanic
+#define D SigDefault
+
+#pragma dataflag NOPTR
+SigTab runtime·sigtab[] = {
+	/* 0 */	0, "SIGNONE: no trap",
+	/* 1 */	N+K, "SIGHUP: terminal line hangup",
+	/* 2 */	N+K, "SIGINT: interrupt",
+	/* 3 */	N+T, "SIGQUIT: quit",
+	/* 4 */	T, "SIGILL: illegal instruction",
+	/* 5 */	T, "SIGTRAP: trace trap",
+	/* 6 */	N+T, "SIGABRT: abort",
+	/* 7 */	T, "SIGEMT: emulate instruction executed",
+	/* 8 */	P, "SIGFPE: floating-point exception",
+	/* 9 */	0, "SIGKILL: kill",
+	/* 10 */	P, "SIGBUS: bus error",
+	/* 11 */	P, "SIGSEGV: segmentation violation",
+	/* 12 */	T, "SIGSYS: bad system call",
+	/* 13 */	N, "SIGPIPE: write to broken pipe",
+	/* 14 */	N, "SIGALRM: alarm clock",
+	/* 15 */	N+K, "SIGTERM: termination",
+	/* 16 */	N, "SIGURG: urgent condition on socket",
+	/* 17 */	0, "SIGSTOP: stop",
+	/* 18 */	N+D, "SIGTSTP: keyboard stop",
+	/* 19 */	0, "SIGCONT: continue after stop",
+	/* 20 */	N, "SIGCHLD: child status has changed",
+	/* 21 */	N+D, "SIGTTIN: background read from tty",
+	/* 22 */	N+D, "SIGTTOU: background write to tty",
+	/* 23 */	N, "SIGIO: i/o now possible",
+	/* 24 */	N, "SIGXCPU: cpu limit exceeded",
+	/* 25 */	N, "SIGXFSZ: file size limit exceeded",
+	/* 26 */	N, "SIGVTALRM: virtual alarm clock",
+	/* 27 */	N, "SIGPROF: profiling alarm clock",
+	/* 28 */	N, "SIGWINCH: window size change",
+	/* 29 */	N, "SIGINFO: status request from keyboard",
+	/* 30 */	N, "SIGUSR1: user-defined signal 1",
+	/* 31 */	N, "SIGUSR2: user-defined signal 2",
+};
+
+#undef N
+#undef K
+#undef T
+#undef P
+#undef D
diff --git a/src/runtime/signals_dragonfly.h b/src/runtime/signals_dragonfly.h
new file mode 100644
index 0000000..07343a7
--- /dev/null
+++ b/src/runtime/signals_dragonfly.h
@@ -0,0 +1,54 @@
+// 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 "textflag.h"
+
+#define N SigNotify
+#define K SigKill
+#define T SigThrow
+#define P SigPanic
+#define D SigDefault
+
+#pragma dataflag NOPTR
+SigTab runtime·sigtab[] = {
+	/* 0 */	0, "SIGNONE: no trap",
+	/* 1 */	N+K, "SIGHUP: terminal line hangup",
+	/* 2 */	N+K, "SIGINT: interrupt",
+	/* 3 */	N+T, "SIGQUIT: quit",
+	/* 4 */	T, "SIGILL: illegal instruction",
+	/* 5 */	T, "SIGTRAP: trace trap",
+	/* 6 */	N+T, "SIGABRT: abort",
+	/* 7 */	T, "SIGEMT: emulate instruction executed",
+	/* 8 */	P, "SIGFPE: floating-point exception",
+	/* 9 */	0, "SIGKILL: kill",
+	/* 10 */	P, "SIGBUS: bus error",
+	/* 11 */	P, "SIGSEGV: segmentation violation",
+	/* 12 */	T, "SIGSYS: bad system call",
+	/* 13 */	N, "SIGPIPE: write to broken pipe",
+	/* 14 */	N, "SIGALRM: alarm clock",
+	/* 15 */	N+K, "SIGTERM: termination",
+	/* 16 */	N, "SIGURG: urgent condition on socket",
+	/* 17 */	0, "SIGSTOP: stop",
+	/* 18 */	N+D, "SIGTSTP: keyboard stop",
+	/* 19 */	0, "SIGCONT: continue after stop",
+	/* 20 */	N, "SIGCHLD: child status has changed",
+	/* 21 */	N+D, "SIGTTIN: background read from tty",
+	/* 22 */	N+D, "SIGTTOU: background write to tty",
+	/* 23 */	N, "SIGIO: i/o now possible",
+	/* 24 */	N, "SIGXCPU: cpu limit exceeded",
+	/* 25 */	N, "SIGXFSZ: file size limit exceeded",
+	/* 26 */	N, "SIGVTALRM: virtual alarm clock",
+	/* 27 */	N, "SIGPROF: profiling alarm clock",
+	/* 28 */	N, "SIGWINCH: window size change",
+	/* 29 */	N, "SIGINFO: status request from keyboard",
+	/* 30 */	N, "SIGUSR1: user-defined signal 1",
+	/* 31 */	N, "SIGUSR2: user-defined signal 2",
+	/* 32 */	N, "SIGTHR: reserved",
+};
+
+#undef N
+#undef K
+#undef T
+#undef P
+#undef D
diff --git a/src/runtime/signals_freebsd.h b/src/runtime/signals_freebsd.h
new file mode 100644
index 0000000..39e0a94
--- /dev/null
+++ b/src/runtime/signals_freebsd.h
@@ -0,0 +1,54 @@
+// 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 "textflag.h"
+
+#define N SigNotify
+#define K SigKill
+#define T SigThrow
+#define P SigPanic
+#define D SigDefault
+
+#pragma dataflag NOPTR
+SigTab runtime·sigtab[] = {
+	/* 0 */	0, "SIGNONE: no trap",
+	/* 1 */	N+K, "SIGHUP: terminal line hangup",
+	/* 2 */	N+K, "SIGINT: interrupt",
+	/* 3 */	N+T, "SIGQUIT: quit",
+	/* 4 */	T, "SIGILL: illegal instruction",
+	/* 5 */	T, "SIGTRAP: trace trap",
+	/* 6 */	N+T, "SIGABRT: abort",
+	/* 7 */	T, "SIGEMT: emulate instruction executed",
+	/* 8 */	P, "SIGFPE: floating-point exception",
+	/* 9 */	0, "SIGKILL: kill",
+	/* 10 */	P, "SIGBUS: bus error",
+	/* 11 */	P, "SIGSEGV: segmentation violation",
+	/* 12 */	N, "SIGSYS: bad system call",
+	/* 13 */	N, "SIGPIPE: write to broken pipe",
+	/* 14 */	N, "SIGALRM: alarm clock",
+	/* 15 */	N+K, "SIGTERM: termination",
+	/* 16 */	N, "SIGURG: urgent condition on socket",
+	/* 17 */	0, "SIGSTOP: stop",
+	/* 18 */	N+D, "SIGTSTP: keyboard stop",
+	/* 19 */	0, "SIGCONT: continue after stop",
+	/* 20 */	N, "SIGCHLD: child status has changed",
+	/* 21 */	N+D, "SIGTTIN: background read from tty",
+	/* 22 */	N+D, "SIGTTOU: background write to tty",
+	/* 23 */	N, "SIGIO: i/o now possible",
+	/* 24 */	N, "SIGXCPU: cpu limit exceeded",
+	/* 25 */	N, "SIGXFSZ: file size limit exceeded",
+	/* 26 */	N, "SIGVTALRM: virtual alarm clock",
+	/* 27 */	N, "SIGPROF: profiling alarm clock",
+	/* 28 */	N, "SIGWINCH: window size change",
+	/* 29 */	N, "SIGINFO: status request from keyboard",
+	/* 30 */	N, "SIGUSR1: user-defined signal 1",
+	/* 31 */	N, "SIGUSR2: user-defined signal 2",
+	/* 32 */	N, "SIGTHR: reserved",
+};
+
+#undef N
+#undef K
+#undef T
+#undef P
+#undef D
diff --git a/src/runtime/signals_linux.h b/src/runtime/signals_linux.h
new file mode 100644
index 0000000..3741076
--- /dev/null
+++ b/src/runtime/signals_linux.h
@@ -0,0 +1,86 @@
+// 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 "textflag.h"
+
+#define N SigNotify
+#define K SigKill
+#define T SigThrow
+#define P SigPanic
+#define D SigDefault
+
+#pragma dataflag NOPTR
+SigTab runtime·sigtab[] = {
+	/* 0 */	0, "SIGNONE: no trap",
+	/* 1 */	N+K, "SIGHUP: terminal line hangup",
+	/* 2 */	N+K, "SIGINT: interrupt",
+	/* 3 */	N+T, "SIGQUIT: quit",
+	/* 4 */	T, "SIGILL: illegal instruction",
+	/* 5 */	T, "SIGTRAP: trace trap",
+	/* 6 */	N+T, "SIGABRT: abort",
+	/* 7 */	P, "SIGBUS: bus error",
+	/* 8 */	P, "SIGFPE: floating-point exception",
+	/* 9 */	0, "SIGKILL: kill",
+	/* 10 */	N, "SIGUSR1: user-defined signal 1",
+	/* 11 */	P, "SIGSEGV: segmentation violation",
+	/* 12 */	N, "SIGUSR2: user-defined signal 2",
+	/* 13 */	N, "SIGPIPE: write to broken pipe",
+	/* 14 */	N, "SIGALRM: alarm clock",
+	/* 15 */	N+K, "SIGTERM: termination",
+	/* 16 */	T, "SIGSTKFLT: stack fault",
+	/* 17 */	N, "SIGCHLD: child status has changed",
+	/* 18 */	0, "SIGCONT: continue",
+	/* 19 */	0, "SIGSTOP: stop, unblockable",
+	/* 20 */	N+D, "SIGTSTP: keyboard stop",
+	/* 21 */	N+D, "SIGTTIN: background read from tty",
+	/* 22 */	N+D, "SIGTTOU: background write to tty",
+	/* 23 */	N, "SIGURG: urgent condition on socket",
+	/* 24 */	N, "SIGXCPU: cpu limit exceeded",
+	/* 25 */	N, "SIGXFSZ: file size limit exceeded",
+	/* 26 */	N, "SIGVTALRM: virtual alarm clock",
+	/* 27 */	N, "SIGPROF: profiling alarm clock",
+	/* 28 */	N, "SIGWINCH: window size change",
+	/* 29 */	N, "SIGIO: i/o now possible",
+	/* 30 */	N, "SIGPWR: power failure restart",
+	/* 31 */	N, "SIGSYS: bad system call",
+	/* 32 */	0, "signal 32", /* SIGCANCEL; see issue 6997 */
+	/* 33 */	0, "signal 33", /* SIGSETXID; see issue 3871 */
+	/* 34 */	N, "signal 34",
+	/* 35 */	N, "signal 35",
+	/* 36 */	N, "signal 36",
+	/* 37 */	N, "signal 37",
+	/* 38 */	N, "signal 38",
+	/* 39 */	N, "signal 39",
+	/* 40 */	N, "signal 40",
+	/* 41 */	N, "signal 41",
+	/* 42 */	N, "signal 42",
+	/* 43 */	N, "signal 43",
+	/* 44 */	N, "signal 44",
+	/* 45 */	N, "signal 45",
+	/* 46 */	N, "signal 46",
+	/* 47 */	N, "signal 47",
+	/* 48 */	N, "signal 48",
+	/* 49 */	N, "signal 49",
+	/* 50 */	N, "signal 50",
+	/* 51 */	N, "signal 51",
+	/* 52 */	N, "signal 52",
+	/* 53 */	N, "signal 53",
+	/* 54 */	N, "signal 54",
+	/* 55 */	N, "signal 55",
+	/* 56 */	N, "signal 56",
+	/* 57 */	N, "signal 57",
+	/* 58 */	N, "signal 58",
+	/* 59 */	N, "signal 59",
+	/* 60 */	N, "signal 60",
+	/* 61 */	N, "signal 61",
+	/* 62 */	N, "signal 62",
+	/* 63 */	N, "signal 63",
+	/* 64 */	N, "signal 64",
+};
+
+#undef N
+#undef K
+#undef T
+#undef P
+#undef D
diff --git a/src/runtime/signals_nacl.h b/src/runtime/signals_nacl.h
new file mode 100644
index 0000000..8761e1b
--- /dev/null
+++ b/src/runtime/signals_nacl.h
@@ -0,0 +1,53 @@
+// 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 "textflag.h"
+
+#define N SigNotify
+#define K SigKill
+#define T SigThrow
+#define P SigPanic
+#define D SigDefault
+
+#pragma dataflag NOPTR
+SigTab runtime·sigtab[] = {
+	/* 0 */	0, "SIGNONE: no trap",
+	/* 1 */	N+K, "SIGHUP: terminal line hangup",
+	/* 2 */	N+K, "SIGINT: interrupt",
+	/* 3 */	N+T, "SIGQUIT: quit",
+	/* 4 */	T, "SIGILL: illegal instruction",
+	/* 5 */	T, "SIGTRAP: trace trap",
+	/* 6 */	N+T, "SIGABRT: abort",
+	/* 7 */	T, "SIGEMT: emulate instruction executed",
+	/* 8 */	P, "SIGFPE: floating-point exception",
+	/* 9 */	0, "SIGKILL: kill",
+	/* 10 */	P, "SIGBUS: bus error",
+	/* 11 */	P, "SIGSEGV: segmentation violation",
+	/* 12 */	T, "SIGSYS: bad system call",
+	/* 13 */	N, "SIGPIPE: write to broken pipe",
+	/* 14 */	N, "SIGALRM: alarm clock",
+	/* 15 */	N+K, "SIGTERM: termination",
+	/* 16 */	N, "SIGURG: urgent condition on socket",
+	/* 17 */	0, "SIGSTOP: stop",
+	/* 18 */	N+D, "SIGTSTP: keyboard stop",
+	/* 19 */	0, "SIGCONT: continue after stop",
+	/* 20 */	N, "SIGCHLD: child status has changed",
+	/* 21 */	N+D, "SIGTTIN: background read from tty",
+	/* 22 */	N+D, "SIGTTOU: background write to tty",
+	/* 23 */	N, "SIGIO: i/o now possible",
+	/* 24 */	N, "SIGXCPU: cpu limit exceeded",
+	/* 25 */	N, "SIGXFSZ: file size limit exceeded",
+	/* 26 */	N, "SIGVTALRM: virtual alarm clock",
+	/* 27 */	N, "SIGPROF: profiling alarm clock",
+	/* 28 */	N, "SIGWINCH: window size change",
+	/* 29 */	N, "SIGINFO: status request from keyboard",
+	/* 30 */	N, "SIGUSR1: user-defined signal 1",
+	/* 31 */	N, "SIGUSR2: user-defined signal 2",
+};
+
+#undef N
+#undef K
+#undef T
+#undef P
+#undef D
diff --git a/src/runtime/signals_netbsd.h b/src/runtime/signals_netbsd.h
new file mode 100644
index 0000000..950a2fe
--- /dev/null
+++ b/src/runtime/signals_netbsd.h
@@ -0,0 +1,54 @@
+// 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 "textflag.h"
+
+#define N SigNotify
+#define K SigKill
+#define T SigThrow
+#define P SigPanic
+#define D SigDefault
+
+#pragma dataflag NOPTR
+SigTab runtime·sigtab[] = {
+	/*  0 */	0, "SIGNONE: no trap",
+	/*  1 */	N+K, "SIGHUP: terminal line hangup",
+	/*  2 */	N+K, "SIGINT: interrupt",
+	/*  3 */	N+T, "SIGQUIT: quit",
+	/*  4 */	T, "SIGILL: illegal instruction",
+	/*  5 */	T, "SIGTRAP: trace trap",
+	/*  6 */	N+T, "SIGABRT: abort",
+	/*  7 */	T, "SIGEMT: emulate instruction executed",
+	/*  8 */	P, "SIGFPE: floating-point exception",
+	/*  9 */	0, "SIGKILL: kill",
+	/* 10 */	P, "SIGBUS: bus error",
+	/* 11 */	P, "SIGSEGV: segmentation violation",
+	/* 12 */	T, "SIGSYS: bad system call",
+	/* 13 */	N, "SIGPIPE: write to broken pipe",
+	/* 14 */	N, "SIGALRM: alarm clock",
+	/* 15 */	N+K, "SIGTERM: termination",
+	/* 16 */	N, "SIGURG: urgent condition on socket",
+	/* 17 */	0, "SIGSTOP: stop",
+	/* 18 */	N+D, "SIGTSTP: keyboard stop",
+	/* 19 */	0, "SIGCONT: continue after stop",
+	/* 20 */	N, "SIGCHLD: child status has changed",
+	/* 21 */	N+D, "SIGTTIN: background read from tty",
+	/* 22 */	N+D, "SIGTTOU: background write to tty",
+	/* 23 */	N, "SIGIO: i/o now possible",
+	/* 24 */	N, "SIGXCPU: cpu limit exceeded",
+	/* 25 */	N, "SIGXFSZ: file size limit exceeded",
+	/* 26 */	N, "SIGVTALRM: virtual alarm clock",
+	/* 27 */	N, "SIGPROF: profiling alarm clock",
+	/* 28 */	N, "SIGWINCH: window size change",
+	/* 29 */	N, "SIGINFO: status request from keyboard",
+	/* 30 */	N, "SIGUSR1: user-defined signal 1",
+	/* 31 */	N, "SIGUSR2: user-defined signal 2",
+	/* 32 */	N, "SIGTHR: reserved",
+};
+
+#undef N
+#undef K
+#undef T
+#undef P
+#undef D
diff --git a/src/runtime/signals_openbsd.h b/src/runtime/signals_openbsd.h
new file mode 100644
index 0000000..950a2fe
--- /dev/null
+++ b/src/runtime/signals_openbsd.h
@@ -0,0 +1,54 @@
+// 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 "textflag.h"
+
+#define N SigNotify
+#define K SigKill
+#define T SigThrow
+#define P SigPanic
+#define D SigDefault
+
+#pragma dataflag NOPTR
+SigTab runtime·sigtab[] = {
+	/*  0 */	0, "SIGNONE: no trap",
+	/*  1 */	N+K, "SIGHUP: terminal line hangup",
+	/*  2 */	N+K, "SIGINT: interrupt",
+	/*  3 */	N+T, "SIGQUIT: quit",
+	/*  4 */	T, "SIGILL: illegal instruction",
+	/*  5 */	T, "SIGTRAP: trace trap",
+	/*  6 */	N+T, "SIGABRT: abort",
+	/*  7 */	T, "SIGEMT: emulate instruction executed",
+	/*  8 */	P, "SIGFPE: floating-point exception",
+	/*  9 */	0, "SIGKILL: kill",
+	/* 10 */	P, "SIGBUS: bus error",
+	/* 11 */	P, "SIGSEGV: segmentation violation",
+	/* 12 */	T, "SIGSYS: bad system call",
+	/* 13 */	N, "SIGPIPE: write to broken pipe",
+	/* 14 */	N, "SIGALRM: alarm clock",
+	/* 15 */	N+K, "SIGTERM: termination",
+	/* 16 */	N, "SIGURG: urgent condition on socket",
+	/* 17 */	0, "SIGSTOP: stop",
+	/* 18 */	N+D, "SIGTSTP: keyboard stop",
+	/* 19 */	0, "SIGCONT: continue after stop",
+	/* 20 */	N, "SIGCHLD: child status has changed",
+	/* 21 */	N+D, "SIGTTIN: background read from tty",
+	/* 22 */	N+D, "SIGTTOU: background write to tty",
+	/* 23 */	N, "SIGIO: i/o now possible",
+	/* 24 */	N, "SIGXCPU: cpu limit exceeded",
+	/* 25 */	N, "SIGXFSZ: file size limit exceeded",
+	/* 26 */	N, "SIGVTALRM: virtual alarm clock",
+	/* 27 */	N, "SIGPROF: profiling alarm clock",
+	/* 28 */	N, "SIGWINCH: window size change",
+	/* 29 */	N, "SIGINFO: status request from keyboard",
+	/* 30 */	N, "SIGUSR1: user-defined signal 1",
+	/* 31 */	N, "SIGUSR2: user-defined signal 2",
+	/* 32 */	N, "SIGTHR: reserved",
+};
+
+#undef N
+#undef K
+#undef T
+#undef P
+#undef D
diff --git a/src/runtime/signals_plan9.h b/src/runtime/signals_plan9.h
new file mode 100644
index 0000000..4ee8e54
--- /dev/null
+++ b/src/runtime/signals_plan9.h
@@ -0,0 +1,63 @@
+// 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 "textflag.h"
+
+#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.
+
+#pragma dataflag NOPTR
+SigTab runtime·sigtab[] = {
+	// 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/runtime/signals_solaris.h b/src/runtime/signals_solaris.h
new file mode 100644
index 0000000..1f0a65e
--- /dev/null
+++ b/src/runtime/signals_solaris.h
@@ -0,0 +1,97 @@
+// 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 "textflag.h"
+
+#define N SigNotify
+#define K SigKill
+#define T SigThrow
+#define P SigPanic
+#define D SigDefault
+
+#pragma dataflag NOPTR
+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/runtime/signals_windows.h b/src/runtime/signals_windows.h
new file mode 100644
index 0000000..6943714
--- /dev/null
+++ b/src/runtime/signals_windows.h
@@ -0,0 +1,3 @@
+// 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.
diff --git a/src/runtime/sigpanic_unix.go b/src/runtime/sigpanic_unix.go
index 1ce6223..6807985 100644
--- a/src/runtime/sigpanic_unix.go
+++ b/src/runtime/sigpanic_unix.go
@@ -6,10 +6,12 @@
 
 package runtime
 
+func signame(int32) *byte
+
 func sigpanic() {
 	g := getg()
 	if !canpanic(g) {
-		throw("unexpected signal during runtime execution")
+		gothrow("unexpected signal during runtime execution")
 	}
 
 	switch g.sig {
@@ -18,13 +20,13 @@ func sigpanic() {
 			panicmem()
 		}
 		print("unexpected fault address ", hex(g.sigcode1), "\n")
-		throw("fault")
+		gothrow("fault")
 	case _SIGSEGV:
 		if (g.sigcode0 == 0 || g.sigcode0 == _SEGV_MAPERR || g.sigcode0 == _SEGV_ACCERR) && g.sigcode1 < 0x1000 || g.paniconfault {
 			panicmem()
 		}
 		print("unexpected fault address ", hex(g.sigcode1), "\n")
-		throw("fault")
+		gothrow("fault")
 	case _SIGFPE:
 		switch g.sigcode0 {
 		case _FPE_INTDIV:
@@ -34,20 +36,5 @@ func sigpanic() {
 		}
 		panicfloat()
 	}
-
-	if g.sig >= uint32(len(sigtable)) {
-		// can't happen: we looked up g.sig in sigtable to decide to call sigpanic
-		throw("unexpected signal value")
-	}
-	panic(errorString(sigtable[g.sig].name))
-}
-
-// setsigsegv is used on darwin/arm{,64} to fake a segmentation fault.
-//go:nosplit
-func setsigsegv(pc uintptr) {
-	g := getg()
-	g.sig = _SIGSEGV
-	g.sigpc = pc
-	g.sigcode0 = _SEGV_MAPERR
-	g.sigcode1 = 0 // TODO: emulate si_addr
+	panic(errorString(gostringnocopy(signame(g.sig))))
 }
diff --git a/src/runtime/sigqueue.go b/src/runtime/sigqueue.go
index 3f50a59..fed4560 100644
--- a/src/runtime/sigqueue.go
+++ b/src/runtime/sigqueue.go
@@ -24,8 +24,6 @@
 // unnecessary rechecks of sig.mask, but it cannot lead to missed signals
 // nor deadlocks.
 
-// +build !plan9
-
 package runtime
 
 import "unsafe"
@@ -47,7 +45,7 @@ const (
 
 // Called from sighandler to send a signal back out of the signal handling thread.
 // Reports whether the signal was sent. If not, the caller typically crashes the program.
-func sigsend(s uint32) bool {
+func sigsend(s int32) bool {
 	bit := uint32(1) << uint(s&31)
 	if !sig.inuse || s < 0 || int(s) >= 32*len(sig.wanted) || sig.wanted[s/32]&bit == 0 {
 		return false
@@ -69,7 +67,7 @@ Send:
 	for {
 		switch atomicload(&sig.state) {
 		default:
-			throw("sigsend: inconsistent state")
+			gothrow("sigsend: inconsistent state")
 		case sigIdle:
 			if cas(&sig.state, sigIdle, sigSending) {
 				break Send
@@ -105,7 +103,7 @@ func signal_recv() uint32 {
 		for {
 			switch atomicload(&sig.state) {
 			default:
-				throw("signal_recv: inconsistent state")
+				gothrow("signal_recv: inconsistent state")
 			case sigIdle:
 				if cas(&sig.state, sigIdle, sigReceiving) {
 					notetsleepg(&sig.note, -1)
@@ -141,7 +139,7 @@ func signal_enable(s uint32) {
 		return
 	}
 	sig.wanted[s/32] |= 1 << (s & 31)
-	sigenable(s)
+	sigenable_go(s)
 }
 
 // Must only be called from a single goroutine at a time.
@@ -150,29 +148,35 @@ func signal_disable(s uint32) {
 		return
 	}
 	sig.wanted[s/32] &^= 1 << (s & 31)
-	sigdisable(s)
+	sigdisable_go(s)
 }
 
-// Must only be called from a single goroutine at a time.
-func signal_ignore(s uint32) {
-	if int(s) >= len(sig.wanted)*32 {
+// This runs on a foreign stack, without an m or a g.  No stack split.
+//go:nosplit
+func badsignal(sig uintptr) {
+	// Some external libraries, for example, OpenBLAS, create worker threads in
+	// a global constructor. If we're doing cpu profiling, and the SIGPROF signal
+	// comes to one of the foreign threads before we make our first cgo call, the
+	// call to cgocallback below will bring down the whole process.
+	// It's better to miss a few SIGPROF signals than to abort in this case.
+	// See http://golang.org/issue/9456.
+	if _SIGPROF != 0 && sig == _SIGPROF && needextram != 0 {
 		return
 	}
-	sig.wanted[s/32] &^= 1 << (s & 31)
-	sigignore(s)
+	cgocallback(unsafe.Pointer(funcPC(sigsend)), noescape(unsafe.Pointer(&sig)), unsafe.Sizeof(sig))
 }
 
-// This runs on a foreign stack, without an m or a g.  No stack split.
-//go:nosplit
-//go:norace
-func badsignal(sig uintptr) {
-	cgocallback(unsafe.Pointer(funcPC(badsignalgo)), noescape(unsafe.Pointer(&sig)), unsafe.Sizeof(sig))
+func sigenable_m()
+func sigdisable_m()
+
+func sigenable_go(s uint32) {
+	g := getg()
+	g.m.scalararg[0] = uintptr(s)
+	onM(sigenable_m)
 }
 
-func badsignalgo(sig uintptr) {
-	if !sigsend(uint32(sig)) {
-		// A foreign thread received the signal sig, and the
-		// Go code does not want to handle it.
-		raisebadsignal(int32(sig))
-	}
+func sigdisable_go(s uint32) {
+	g := getg()
+	g.m.scalararg[0] = uintptr(s)
+	onM(sigdisable_m)
 }
diff --git a/src/runtime/slice.go b/src/runtime/slice.go
index 5cda11d..171087d 100644
--- a/src/runtime/slice.go
+++ b/src/runtime/slice.go
@@ -8,48 +8,41 @@ import (
 	"unsafe"
 )
 
-type slice struct {
+type sliceStruct struct {
 	array unsafe.Pointer
 	len   int
 	cap   int
 }
 
 // TODO: take uintptrs instead of int64s?
-func makeslice(t *slicetype, len64, cap64 int64) slice {
+func makeslice(t *slicetype, len64 int64, cap64 int64) sliceStruct {
 	// 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.
 	len := int(len64)
-	if len64 < 0 || int64(len) != len64 || t.elem.size > 0 && uintptr(len) > _MaxMem/uintptr(t.elem.size) {
+	if len64 < 0 || int64(len) != len64 || t.elem.size > 0 && uintptr(len) > maxmem/uintptr(t.elem.size) {
 		panic(errorString("makeslice: len out of range"))
 	}
 	cap := int(cap64)
-	if cap < len || int64(cap) != cap64 || t.elem.size > 0 && uintptr(cap) > _MaxMem/uintptr(t.elem.size) {
+	if cap < len || int64(cap) != cap64 || t.elem.size > 0 && uintptr(cap) > maxmem/uintptr(t.elem.size) {
 		panic(errorString("makeslice: cap out of range"))
 	}
 	p := newarray(t.elem, uintptr(cap))
-	return slice{p, len, cap}
+	return sliceStruct{p, len, cap}
 }
 
-// growslice_n is a variant of growslice that takes the number of new elements
-// instead of the new minimum capacity.
-// TODO(rsc): This is used by append(slice, slice...).
-// The compiler should change that code to use growslice directly (issue #11419).
-func growslice_n(t *slicetype, old slice, n int) slice {
+// TODO: take uintptr instead of int64?
+func growslice(t *slicetype, old sliceStruct, n int64) sliceStruct {
 	if n < 1 {
 		panic(errorString("growslice: invalid n"))
 	}
-	return growslice(t, old, old.cap+n)
-}
 
-// growslice handles slice growth during append.
-// It is passed the slice type, the old slice, and the desired new minimum capacity,
-// and it returns a new slice with at least that capacity, with the old data
-// copied into it.
-func growslice(t *slicetype, old slice, cap int) slice {
-	if cap < old.cap || t.elem.size > 0 && uintptr(cap) > _MaxMem/uintptr(t.elem.size) {
+	cap64 := int64(old.cap) + n
+	cap := int(cap64)
+
+	if int64(cap) != cap64 || cap < old.cap || t.elem.size > 0 && uintptr(cap) > maxmem/uintptr(t.elem.size) {
 		panic(errorString("growslice: cap out of range"))
 	}
 
@@ -60,9 +53,7 @@ func growslice(t *slicetype, old slice, cap int) slice {
 
 	et := t.elem
 	if et.size == 0 {
-		// append should not create a slice with nil pointer but non-zero len.
-		// We assume that append doesn't need to preserve old.array in this case.
-		return slice{unsafe.Pointer(&zerobase), old.len, cap}
+		return sliceStruct{old.array, old.len, cap}
 	}
 
 	newcap := old.cap
@@ -81,34 +72,27 @@ func growslice(t *slicetype, old slice, cap int) slice {
 		}
 	}
 
-	if uintptr(newcap) >= _MaxMem/uintptr(et.size) {
+	if uintptr(newcap) >= maxmem/uintptr(et.size) {
 		panic(errorString("growslice: cap out of range"))
 	}
 	lenmem := uintptr(old.len) * uintptr(et.size)
-	capmem := roundupsize(uintptr(newcap) * uintptr(et.size))
+	capmem := goroundupsize(uintptr(newcap) * uintptr(et.size))
 	newcap = int(capmem / uintptr(et.size))
 	var p unsafe.Pointer
 	if et.kind&kindNoPointers != 0 {
 		p = rawmem(capmem)
-		memmove(p, old.array, lenmem)
 		memclr(add(p, lenmem), capmem-lenmem)
 	} else {
-		// Note: can't use rawmem (which avoids zeroing of memory), because then GC can scan uninitialized memory.
+		// Note: can't use rawmem (which avoids zeroing of memory), because then GC can scan unitialized memory
 		p = newarray(et, uintptr(newcap))
-		if !writeBarrierEnabled {
-			memmove(p, old.array, lenmem)
-		} else {
-			for i := uintptr(0); i < lenmem; i += et.size {
-				typedmemmove(et, add(p, i), add(old.array, i))
-			}
-		}
 	}
+	memmove(p, old.array, lenmem)
 
-	return slice{p, old.len, newcap}
+	return sliceStruct{p, old.len, newcap}
 }
 
-func slicecopy(to, fm slice, width uintptr) int {
-	if fm.len == 0 || to.len == 0 {
+func slicecopy(to sliceStruct, fm sliceStruct, width uintptr) int {
+	if fm.len == 0 || to.len == 0 || width == 0 {
 		return 0
 	}
 
@@ -117,10 +101,6 @@ func slicecopy(to, fm slice, width uintptr) int {
 		n = to.len
 	}
 
-	if width == 0 {
-		return n
-	}
-
 	if raceenabled {
 		callerpc := getcallerpc(unsafe.Pointer(&to))
 		pc := funcPC(slicecopy)
diff --git a/src/runtime/softfloat64.go b/src/runtime/softfloat64.go
index 790dbda..4fcf8f2 100644
--- a/src/runtime/softfloat64.go
+++ b/src/runtime/softfloat64.go
@@ -340,7 +340,7 @@ func f32to64(f uint32) uint64 {
 	return fpack64(fs64, uint64(fm)<<d, fe, 0)
 }
 
-func fcmp64(f, g uint64) (cmp int32, isnan bool) {
+func fcmp64(f, g uint64) (cmp int, isnan bool) {
 	fs, fm, _, fi, fn := funpack64(f)
 	gs, gm, _, gi, gn := funpack64(g)
 
@@ -483,3 +483,16 @@ again2:
 
 	return q1*b + q0, (un21*b + un0 - q0*v) >> s
 }
+
+// callable from C
+
+func fadd64c(f, g uint64, ret *uint64)            { *ret = fadd64(f, g) }
+func fsub64c(f, g uint64, ret *uint64)            { *ret = fsub64(f, g) }
+func fmul64c(f, g uint64, ret *uint64)            { *ret = fmul64(f, g) }
+func fdiv64c(f, g uint64, ret *uint64)            { *ret = fdiv64(f, g) }
+func fneg64c(f uint64, ret *uint64)               { *ret = fneg64(f) }
+func f32to64c(f uint32, ret *uint64)              { *ret = f32to64(f) }
+func f64to32c(f uint64, ret *uint32)              { *ret = f64to32(f) }
+func fcmp64c(f, g uint64, ret *int, retnan *bool) { *ret, *retnan = fcmp64(f, g) }
+func fintto64c(val int64, ret *uint64)            { *ret = fintto64(val) }
+func f64tointc(f uint64, ret *int64, retok *bool) { *ret, *retok = f64toint(f) }
diff --git a/src/runtime/softfloat64_test.go b/src/runtime/softfloat64_test.go
index e108872..df63010 100644
--- a/src/runtime/softfloat64_test.go
+++ b/src/runtime/softfloat64_test.go
@@ -182,7 +182,7 @@ func hwcmp(f, g float64) (cmp int, isnan bool) {
 func testcmp(t *testing.T, f, g float64) {
 	hcmp, hisnan := hwcmp(f, g)
 	scmp, sisnan := Fcmp64(math.Float64bits(f), math.Float64bits(g))
-	if int32(hcmp) != scmp || hisnan != sisnan {
+	if hcmp != scmp || hisnan != sisnan {
 		err(t, "cmp(%g, %g) = sw %v, %v, hw %v, %v\n", f, g, scmp, sisnan, hcmp, hisnan)
 	}
 }
diff --git a/src/runtime/softfloat_arm.c b/src/runtime/softfloat_arm.c
new file mode 100644
index 0000000..3f3f33a
--- /dev/null
+++ b/src/runtime/softfloat_arm.c
@@ -0,0 +1,687 @@
+// 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.
+
+// Software floating point interpretaton of ARM 7500 FP instructions.
+// The interpretation is not bit compatible with the 7500.
+// It uses true little-endian doubles, while the 7500 used mixed-endian.
+
+#include "runtime.h"
+#include "textflag.h"
+
+#define CPSR 14
+#define FLAGS_N (1U << 31)
+#define FLAGS_Z (1U << 30)
+#define FLAGS_C (1U << 29)
+#define FLAGS_V (1U << 28)
+
+void	runtime·abort(void);
+void	runtime·sqrtC(uint64, uint64*);
+
+static	uint32	trace = 0;
+
+static void
+fabort(void)
+{
+	if (1) {
+		runtime·printf("Unsupported floating point instruction\n");
+		runtime·abort();
+	}
+}
+
+static void
+putf(uint32 reg, uint32 val)
+{
+	g->m->freglo[reg] = val;
+}
+
+static void
+putd(uint32 reg, uint64 val)
+{
+	g->m->freglo[reg] = (uint32)val;
+	g->m->freghi[reg] = (uint32)(val>>32);
+}
+
+static uint64
+getd(uint32 reg)
+{
+	return (uint64)g->m->freglo[reg] | ((uint64)g->m->freghi[reg]<<32);
+}
+
+static void
+fprint(void)
+{
+	uint32 i;
+	for (i = 0; i < 16; i++) {
+		runtime·printf("\tf%d:\t%X %X\n", i, g->m->freghi[i], g->m->freglo[i]);
+	}
+}
+
+static uint32
+d2f(uint64 d)
+{
+	uint32 x;
+
+	runtime·f64to32c(d, &x);
+	return x;
+}
+
+static uint64
+f2d(uint32 f)
+{
+	uint64 x;
+
+	runtime·f32to64c(f, &x);
+	return x;
+}
+
+static uint32
+fstatus(bool nan, int32 cmp)
+{
+	if(nan)
+		return FLAGS_C | FLAGS_V;
+	if(cmp == 0)
+		return FLAGS_Z | FLAGS_C;
+	if(cmp < 0)
+		return FLAGS_N;
+	return FLAGS_C;
+}
+
+// conditions array record the required CPSR cond field for the
+// first 5 pairs of conditional execution opcodes
+// higher 4 bits are must set, lower 4 bits are must clear
+#pragma dataflag NOPTR
+static const uint8 conditions[10/2] = {
+	[0/2] = (FLAGS_Z >> 24) | 0, // 0: EQ (Z set), 1: NE (Z clear)
+	[2/2] = (FLAGS_C >> 24) | 0, // 2: CS/HS (C set), 3: CC/LO (C clear)
+	[4/2] = (FLAGS_N >> 24) | 0, // 4: MI (N set), 5: PL (N clear)
+	[6/2] = (FLAGS_V >> 24) | 0, // 6: VS (V set), 7: VC (V clear)
+	[8/2] = (FLAGS_C >> 24) | 
+	        (FLAGS_Z >> 28),     // 8: HI (C set and Z clear), 9: LS (C clear and Z set)
+};
+
+#define FAULT (0x80000000U) // impossible PC offset
+
+// returns number of words that the fp instruction
+// is occupying, 0 if next instruction isn't float.
+static uint32
+stepflt(uint32 *pc, uint32 *regs)
+{
+	uint32 i, opc, regd, regm, regn, cpsr;
+	int32 delta;
+	uint32 *addr;
+	uint64 uval;
+	int64 sval;
+	bool nan, ok;
+	int32 cmp;
+	M *m;
+
+	// m is locked in vlop_arm.s, so g->m cannot change during this function call,
+	// so caching it in a local variable is safe.
+	m = g->m;
+	i = *pc;
+
+	if(trace)
+		runtime·printf("stepflt %p %x (cpsr %x)\n", pc, i, regs[CPSR] >> 28);
+
+	opc = i >> 28;
+	if(opc == 14) // common case first
+		goto execute;
+	cpsr = regs[CPSR] >> 28;
+	switch(opc) {
+	case 0: case 1: case 2: case 3: case 4: 
+	case 5: case 6: case 7: case 8: case 9:
+		if(((cpsr & (conditions[opc/2] >> 4)) == (conditions[opc/2] >> 4)) &&
+		   ((cpsr & (conditions[opc/2] & 0xf)) == 0)) {
+			if(opc & 1) return 1;
+		} else {
+			if(!(opc & 1)) return 1;
+		}
+		break;
+	case 10: // GE (N == V)
+	case 11: // LT (N != V)
+		if((cpsr & (FLAGS_N >> 28)) == (cpsr & (FLAGS_V >> 28))) {
+			if(opc & 1) return 1;
+		} else {
+			if(!(opc & 1)) return 1;
+		}
+		break;
+	case 12: // GT (N == V and Z == 0)
+	case 13: // LE (N != V or Z == 1)
+		if((cpsr & (FLAGS_N >> 28)) == (cpsr & (FLAGS_V >> 28)) &&
+		   (cpsr & (FLAGS_Z >> 28)) == 0) {
+			if(opc & 1) return 1;
+		} else {
+			if(!(opc & 1)) return 1;
+		}
+		break;
+	case 14: // AL
+		break;
+	case 15: // shouldn't happen
+		return 0;
+	}
+	if(trace)
+		runtime·printf("conditional %x (cpsr %x) pass\n", opc, cpsr);
+	i = (0xeU << 28) | (i & 0xfffffff);
+
+execute:
+	// special cases
+	if((i&0xfffff000) == 0xe59fb000) {
+		// load r11 from pc-relative address.
+		// might be part of a floating point move
+		// (or might not, but no harm in simulating
+		// one instruction too many).
+		addr = (uint32*)((uint8*)pc + (i&0xfff) + 8);
+		regs[11] = addr[0];
+
+		if(trace)
+			runtime·printf("*** cpu R[%d] = *(%p) %x\n",
+				11, addr, regs[11]);
+		return 1;
+	}
+	if(i == 0xe08bb00d) {
+		// add sp to r11.
+		// might be part of a large stack offset address
+		// (or might not, but again no harm done).
+		regs[11] += regs[13];
+
+		if(trace)
+			runtime·printf("*** cpu R[%d] += R[%d] %x\n",
+				11, 13, regs[11]);
+		return 1;
+	}
+	if(i == 0xeef1fa10) {
+		regs[CPSR] = (regs[CPSR]&0x0fffffff) | m->fflag;
+
+		if(trace)
+			runtime·printf("*** fpsr R[CPSR] = F[CPSR] %x\n", regs[CPSR]);
+		return 1;
+	}
+	if((i&0xff000000) == 0xea000000) {
+		// unconditional branch
+		// can happen in the middle of floating point
+		// if the linker decides it is time to lay down
+		// a sequence of instruction stream constants.
+		delta = i&0xffffff;
+		delta = (delta<<8) >> 8;	// sign extend
+
+		if(trace)
+			runtime·printf("*** cpu PC += %x\n", (delta+2)*4);
+		return delta+2;
+	}
+
+	goto stage1;
+
+stage1:	// load/store regn is cpureg, regm is 8bit offset
+	regd = i>>12 & 0xf;
+	regn = i>>16 & 0xf;
+	regm = (i & 0xff) << 2;	// PLUS or MINUS ??
+
+	switch(i & 0xfff00f00) {
+	default:
+		goto stage2;
+
+	case 0xed900a00:	// single load
+		addr = (uint32*)(regs[regn] + regm);
+		if((uintptr)addr < 4096) {
+			if(trace)
+				runtime·printf("*** load @%p => fault\n", addr);
+			return FAULT;
+		}
+		m->freglo[regd] = addr[0];
+
+		if(trace)
+			runtime·printf("*** load F[%d] = %x\n",
+				regd, m->freglo[regd]);
+		break;
+
+	case 0xed900b00:	// double load
+		addr = (uint32*)(regs[regn] + regm);
+		if((uintptr)addr < 4096) {
+			if(trace)
+				runtime·printf("*** double load @%p => fault\n", addr);
+			return FAULT;
+		}
+		m->freglo[regd] = addr[0];
+		m->freghi[regd] = addr[1];
+
+		if(trace)
+			runtime·printf("*** load D[%d] = %x-%x\n",
+				regd, m->freghi[regd], m->freglo[regd]);
+		break;
+
+	case 0xed800a00:	// single store
+		addr = (uint32*)(regs[regn] + regm);
+		if((uintptr)addr < 4096) {
+			if(trace)
+				runtime·printf("*** store @%p => fault\n", addr);
+			return FAULT;
+		}
+		addr[0] = m->freglo[regd];
+
+		if(trace)
+			runtime·printf("*** *(%p) = %x\n",
+				addr, addr[0]);
+		break;
+
+	case 0xed800b00:	// double store
+		addr = (uint32*)(regs[regn] + regm);
+		if((uintptr)addr < 4096) {
+			if(trace)
+				runtime·printf("*** double store @%p => fault\n", addr);
+			return FAULT;
+		}
+		addr[0] = m->freglo[regd];
+		addr[1] = m->freghi[regd];
+
+		if(trace)
+			runtime·printf("*** *(%p) = %x-%x\n",
+				addr, addr[1], addr[0]);
+		break;
+	}
+	return 1;
+
+stage2:	// regd, regm, regn are 4bit variables
+	regm = i>>0 & 0xf;
+	switch(i & 0xfff00ff0) {
+	default:
+		goto stage3;
+
+	case 0xf3000110:	// veor
+		m->freglo[regd] = m->freglo[regm]^m->freglo[regn];
+		m->freghi[regd] = m->freghi[regm]^m->freghi[regn];
+
+		if(trace)
+			runtime·printf("*** veor D[%d] = %x-%x\n",
+				regd, m->freghi[regd], m->freglo[regd]);
+		break;
+
+	case 0xeeb00b00:	// D[regd] = const(regn,regm)
+		regn = (regn<<4) | regm;
+		regm = 0x40000000UL;
+		if(regn & 0x80)
+			regm |= 0x80000000UL;
+		if(regn & 0x40)
+			regm ^= 0x7fc00000UL;
+		regm |= (regn & 0x3f) << 16;
+		m->freglo[regd] = 0;
+		m->freghi[regd] = regm;
+
+		if(trace)
+			runtime·printf("*** immed D[%d] = %x-%x\n",
+				regd, m->freghi[regd], m->freglo[regd]);
+		break;
+
+	case 0xeeb00a00:	// F[regd] = const(regn,regm)
+		regn = (regn<<4) | regm;
+		regm = 0x40000000UL;
+		if(regn & 0x80)
+			regm |= 0x80000000UL;
+		if(regn & 0x40)
+			regm ^= 0x7e000000UL;
+		regm |= (regn & 0x3f) << 19;
+		m->freglo[regd] = regm;
+
+		if(trace)
+			runtime·printf("*** immed D[%d] = %x\n",
+				regd, m->freglo[regd]);
+		break;
+
+	case 0xee300b00:	// D[regd] = D[regn]+D[regm]
+		runtime·fadd64c(getd(regn), getd(regm), &uval);
+		putd(regd, uval);
+
+		if(trace)
+			runtime·printf("*** add D[%d] = D[%d]+D[%d] %x-%x\n",
+				regd, regn, regm, m->freghi[regd], m->freglo[regd]);
+		break;
+
+	case 0xee300a00:	// F[regd] = F[regn]+F[regm]
+		runtime·fadd64c(f2d(m->freglo[regn]), f2d(m->freglo[regm]), &uval);
+		m->freglo[regd] = d2f(uval);
+
+		if(trace)
+			runtime·printf("*** add F[%d] = F[%d]+F[%d] %x\n",
+				regd, regn, regm, m->freglo[regd]);
+		break;
+
+	case 0xee300b40:	// D[regd] = D[regn]-D[regm]
+		runtime·fsub64c(getd(regn), getd(regm), &uval);
+		putd(regd, uval);
+
+		if(trace)
+			runtime·printf("*** sub D[%d] = D[%d]-D[%d] %x-%x\n",
+				regd, regn, regm, m->freghi[regd], m->freglo[regd]);
+		break;
+
+	case 0xee300a40:	// F[regd] = F[regn]-F[regm]
+		runtime·fsub64c(f2d(m->freglo[regn]), f2d(m->freglo[regm]), &uval);
+		m->freglo[regd] = d2f(uval);
+
+		if(trace)
+			runtime·printf("*** sub F[%d] = F[%d]-F[%d] %x\n",
+				regd, regn, regm, m->freglo[regd]);
+		break;
+
+	case 0xee200b00:	// D[regd] = D[regn]*D[regm]
+		runtime·fmul64c(getd(regn), getd(regm), &uval);
+		putd(regd, uval);
+
+		if(trace)
+			runtime·printf("*** mul D[%d] = D[%d]*D[%d] %x-%x\n",
+				regd, regn, regm, m->freghi[regd], m->freglo[regd]);
+		break;
+
+	case 0xee200a00:	// F[regd] = F[regn]*F[regm]
+		runtime·fmul64c(f2d(m->freglo[regn]), f2d(m->freglo[regm]), &uval);
+		m->freglo[regd] = d2f(uval);
+
+		if(trace)
+			runtime·printf("*** mul F[%d] = F[%d]*F[%d] %x\n",
+				regd, regn, regm, m->freglo[regd]);
+		break;
+
+	case 0xee800b00:	// D[regd] = D[regn]/D[regm]
+		runtime·fdiv64c(getd(regn), getd(regm), &uval);
+		putd(regd, uval);
+
+		if(trace)
+			runtime·printf("*** div D[%d] = D[%d]/D[%d] %x-%x\n",
+				regd, regn, regm, m->freghi[regd], m->freglo[regd]);
+		break;
+
+	case 0xee800a00:	// F[regd] = F[regn]/F[regm]
+		runtime·fdiv64c(f2d(m->freglo[regn]), f2d(m->freglo[regm]), &uval);
+		m->freglo[regd] = d2f(uval);
+
+		if(trace)
+			runtime·printf("*** div F[%d] = F[%d]/F[%d] %x\n",
+				regd, regn, regm, m->freglo[regd]);
+		break;
+
+	case 0xee000b10:	// S[regn] = R[regd] (MOVW) (regm ignored)
+		m->freglo[regn] = regs[regd];
+
+		if(trace)
+			runtime·printf("*** cpy S[%d] = R[%d] %x\n",
+				regn, regd, m->freglo[regn]);
+		break;
+
+	case 0xee100b10:	// R[regd] = S[regn] (MOVW) (regm ignored)
+		regs[regd] = m->freglo[regn];
+
+		if(trace)
+			runtime·printf("*** cpy R[%d] = S[%d] %x\n",
+				regd, regn, regs[regd]);
+		break;
+	}
+	return 1;
+
+stage3:	// regd, regm are 4bit variables
+	switch(i & 0xffff0ff0) {
+	default:
+		goto done;
+
+	case 0xeeb00a40:	// F[regd] = F[regm] (MOVF)
+		m->freglo[regd] = m->freglo[regm];
+
+		if(trace)
+			runtime·printf("*** F[%d] = F[%d] %x\n",
+				regd, regm, m->freglo[regd]);
+		break;
+
+	case 0xeeb00b40:	// D[regd] = D[regm] (MOVD)
+		m->freglo[regd] = m->freglo[regm];
+		m->freghi[regd] = m->freghi[regm];
+
+		if(trace)
+			runtime·printf("*** D[%d] = D[%d] %x-%x\n",
+				regd, regm, m->freghi[regd], m->freglo[regd]);
+		break;
+
+	case 0xeeb10bc0:	// D[regd] = sqrt D[regm]
+		runtime·sqrtC(getd(regm), &uval);
+		putd(regd, uval);
+
+		if(trace)
+			runtime·printf("*** D[%d] = sqrt D[%d] %x-%x\n",
+				regd, regm, m->freghi[regd], m->freglo[regd]);
+		break;
+
+	case 0xeeb00bc0:	// D[regd] = abs D[regm]
+		m->freglo[regd] = m->freglo[regm];
+		m->freghi[regd] = m->freghi[regm] & ((1<<31)-1);
+
+		if(trace)
+			runtime·printf("*** D[%d] = abs D[%d] %x-%x\n",
+					regd, regm, m->freghi[regd], m->freglo[regd]);
+		break;
+
+	case 0xeeb00ac0:	// F[regd] = abs F[regm]
+		m->freglo[regd] = m->freglo[regm] & ((1<<31)-1);
+
+		if(trace)
+			runtime·printf("*** F[%d] = abs F[%d] %x\n",
+					regd, regm, m->freglo[regd]);
+		break;
+
+	case 0xeeb40bc0:	// D[regd] :: D[regm] (CMPD)
+		runtime·fcmp64c(getd(regd), getd(regm), &cmp, &nan);
+		m->fflag = fstatus(nan, cmp);
+
+		if(trace)
+			runtime·printf("*** cmp D[%d]::D[%d] %x\n",
+				regd, regm, m->fflag);
+		break;
+
+	case 0xeeb40ac0:	// F[regd] :: F[regm] (CMPF)
+		runtime·fcmp64c(f2d(m->freglo[regd]), f2d(m->freglo[regm]), &cmp, &nan);
+		m->fflag = fstatus(nan, cmp);
+
+		if(trace)
+			runtime·printf("*** cmp F[%d]::F[%d] %x\n",
+				regd, regm, m->fflag);
+		break;
+
+	case 0xeeb70ac0:	// D[regd] = F[regm] (MOVFD)
+		putd(regd, f2d(m->freglo[regm]));
+
+		if(trace)
+			runtime·printf("*** f2d D[%d]=F[%d] %x-%x\n",
+				regd, regm, m->freghi[regd], m->freglo[regd]);
+		break;
+
+	case 0xeeb70bc0:	// F[regd] = D[regm] (MOVDF)
+		m->freglo[regd] = d2f(getd(regm));
+
+		if(trace)
+			runtime·printf("*** d2f F[%d]=D[%d] %x-%x\n",
+				regd, regm, m->freghi[regd], m->freglo[regd]);
+		break;
+
+	case 0xeebd0ac0:	// S[regd] = F[regm] (MOVFW)
+		runtime·f64tointc(f2d(m->freglo[regm]), &sval, &ok);
+		if(!ok || (int32)sval != sval)
+			sval = 0;
+		m->freglo[regd] = sval;
+
+		if(trace)
+			runtime·printf("*** fix S[%d]=F[%d] %x\n",
+				regd, regm, m->freglo[regd]);
+		break;
+
+	case 0xeebc0ac0:	// S[regd] = F[regm] (MOVFW.U)
+		runtime·f64tointc(f2d(m->freglo[regm]), &sval, &ok);
+		if(!ok || (uint32)sval != sval)
+			sval = 0;
+		m->freglo[regd] = sval;
+
+		if(trace)
+			runtime·printf("*** fix unsigned S[%d]=F[%d] %x\n",
+				regd, regm, m->freglo[regd]);
+		break;
+
+	case 0xeebd0bc0:	// S[regd] = D[regm] (MOVDW)
+		runtime·f64tointc(getd(regm), &sval, &ok);
+		if(!ok || (int32)sval != sval)
+			sval = 0;
+		m->freglo[regd] = sval;
+
+		if(trace)
+			runtime·printf("*** fix S[%d]=D[%d] %x\n",
+				regd, regm, m->freglo[regd]);
+		break;
+
+	case 0xeebc0bc0:	// S[regd] = D[regm] (MOVDW.U)
+		runtime·f64tointc(getd(regm), &sval, &ok);
+		if(!ok || (uint32)sval != sval)
+			sval = 0;
+		m->freglo[regd] = sval;
+
+		if(trace)
+			runtime·printf("*** fix unsigned S[%d]=D[%d] %x\n",
+				regd, regm, m->freglo[regd]);
+		break;
+
+	case 0xeeb80ac0:	// D[regd] = S[regm] (MOVWF)
+		cmp = m->freglo[regm];
+		if(cmp < 0) {
+			runtime·fintto64c(-cmp, &uval);
+			putf(regd, d2f(uval));
+			m->freglo[regd] ^= 0x80000000;
+		} else {
+			runtime·fintto64c(cmp, &uval);
+			putf(regd, d2f(uval));
+		}
+
+		if(trace)
+			runtime·printf("*** float D[%d]=S[%d] %x-%x\n",
+				regd, regm, m->freghi[regd], m->freglo[regd]);
+		break;
+
+	case 0xeeb80a40:	// D[regd] = S[regm] (MOVWF.U)
+		runtime·fintto64c(m->freglo[regm], &uval);
+		putf(regd, d2f(uval));
+
+		if(trace)
+			runtime·printf("*** float unsigned D[%d]=S[%d] %x-%x\n",
+				regd, regm, m->freghi[regd], m->freglo[regd]);
+		break;
+
+	case 0xeeb80bc0:	// D[regd] = S[regm] (MOVWD)
+		cmp = m->freglo[regm];
+		if(cmp < 0) {
+			runtime·fintto64c(-cmp, &uval);
+			putd(regd, uval);
+			m->freghi[regd] ^= 0x80000000;
+		} else {
+			runtime·fintto64c(cmp, &uval);
+			putd(regd, uval);
+		}
+
+		if(trace)
+			runtime·printf("*** float D[%d]=S[%d] %x-%x\n",
+				regd, regm, m->freghi[regd], m->freglo[regd]);
+		break;
+
+	case 0xeeb80b40:	// D[regd] = S[regm] (MOVWD.U)
+		runtime·fintto64c(m->freglo[regm], &uval);
+		putd(regd, uval);
+
+		if(trace)
+			runtime·printf("*** float unsigned D[%d]=S[%d] %x-%x\n",
+				regd, regm, m->freghi[regd], m->freglo[regd]);
+		break;
+	}
+	return 1;
+
+done:
+	if((i&0xff000000) == 0xee000000 ||
+	   (i&0xff000000) == 0xed000000) {
+		runtime·printf("stepflt %p %x\n", pc, i);
+		fabort();
+	}
+	return 0;
+}
+
+typedef struct Sfregs Sfregs;
+
+// NOTE: These are all recorded as pointers because they are possibly live registers,
+// and we don't know what they contain. Recording them as pointers should be
+// safer than not.
+struct Sfregs
+{
+	uint32 *r0;
+	uint32 *r1;
+	uint32 *r2;
+	uint32 *r3;
+	uint32 *r4;
+	uint32 *r5;
+	uint32 *r6;
+	uint32 *r7;
+	uint32 *r8;
+	uint32 *r9;
+	uint32 *r10;
+	uint32 *r11;
+	uint32 *r12;
+	uint32 *r13;
+	uint32 cspr;
+};
+
+static void sfloat2(void);
+void _sfloatpanic(void);
+
+#pragma textflag NOSPLIT
+uint32*
+runtime·_sfloat2(uint32 *pc, Sfregs regs)
+{
+	void (*fn)(void);
+	
+	g->m->ptrarg[0] = pc;
+	g->m->ptrarg[1] = ®s;
+	fn = sfloat2;
+	runtime·onM(&fn);
+	pc = g->m->ptrarg[0];
+	g->m->ptrarg[0] = nil;
+	return pc;
+}
+
+static void
+sfloat2(void)
+{
+	uint32 *pc;
+	G *curg;
+	Sfregs *regs;
+	int32 skip;
+	bool first;
+	
+	pc = g->m->ptrarg[0];
+	regs = g->m->ptrarg[1];
+	g->m->ptrarg[0] = nil;
+	g->m->ptrarg[1] = nil;
+
+	first = true;
+	while(skip = stepflt(pc, (uint32*)&regs->r0)) {
+		first = false;
+		if(skip == FAULT) {
+			// Encountered bad address in store/load.
+			// Record signal information and return to assembly
+			// trampoline that fakes the call.
+			enum { SIGSEGV = 11 };
+			curg = g->m->curg;
+			curg->sig = SIGSEGV;
+			curg->sigcode0 = 0;
+			curg->sigcode1 = 0;
+			curg->sigpc = (uint32)pc;
+			pc = (uint32*)_sfloatpanic;
+			break;
+		}
+		pc += skip;
+	}
+	if(first) {
+		runtime·printf("sfloat2 %p %x\n", pc, *pc);
+		fabort(); // not ok to fail first instruction
+	}
+		
+	g->m->ptrarg[0] = pc;
+}
diff --git a/src/runtime/sqrt.go b/src/runtime/sqrt.go
index 7452a61..34a8c38 100644
--- a/src/runtime/sqrt.go
+++ b/src/runtime/sqrt.go
@@ -3,12 +3,11 @@
 // license that can be found in the LICENSE file.
 
 // Copy of math/sqrt.go, here for use by ARM softfloat.
-// Modified to not use any floating point arithmetic so
-// that we don't clobber any floating-point registers
-// while emulating the sqrt instruction.
 
 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
@@ -87,53 +86,47 @@ package runtime
 // Notes:  Rounding mode detection omitted.
 
 const (
-	float64Mask  = 0x7FF
-	float64Shift = 64 - 11 - 1
-	float64Bias  = 1023
-	float64NaN   = 0x7FF8000000000001
-	float64Inf   = 0x7FF0000000000000
-	maxFloat64   = 1.797693134862315708145274237317043567981e+308 // 2**1023 * (2**53 - 1) / 2**52
+	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
 )
 
-// isnanu returns whether ix represents a NaN floating point number.
-func isnanu(ix uint64) bool {
-	exp := (ix >> float64Shift) & float64Mask
-	sig := ix << (64 - float64Shift) >> (64 - float64Shift)
-	return exp == float64Mask && sig != 0
-}
+func float64bits(f float64) uint64     { return *(*uint64)(unsafe.Pointer(&f)) }
+func float64frombits(b uint64) float64 { return *(*float64)(unsafe.Pointer(&b)) }
 
-func sqrt(ix uint64) uint64 {
+func sqrt(x float64) float64 {
 	// special cases
 	switch {
-	case ix == 0 || ix == 1<<63: // x == 0
-		return ix
-	case isnanu(ix): // x != x
-		return ix
-	case ix&(1<<63) != 0: // x < 0
-		return float64NaN
-	case ix == float64Inf: // x > MaxFloat
-		return ix
+	case x == 0 || x != x || x > maxFloat64:
+		return x
+	case x < 0:
+		return nan
 	}
+	ix := float64bits(x)
 	// normalize x
-	exp := int((ix >> float64Shift) & float64Mask)
+	exp := int((ix >> shift) & mask)
 	if exp == 0 { // subnormal x
-		for ix&1<<float64Shift == 0 {
+		for ix&1<<shift == 0 {
 			ix <<= 1
 			exp--
 		}
 		exp++
 	}
-	exp -= float64Bias // unbias exponent
-	ix &^= float64Mask << float64Shift
-	ix |= 1 << float64Shift
+	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 << (float64Shift + 1)) // r = moving bit from MSB to LSB
+	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 {
@@ -148,6 +141,10 @@ func sqrt(ix uint64) uint64 {
 	if ix != 0 { // remainder, result not exact
 		q += q & 1 // round according to extra bit
 	}
-	ix = q>>1 + uint64(exp-1+float64Bias)<<float64Shift // significand + biased exponent
-	return ix
+	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/runtime/stack.c b/src/runtime/stack.c
new file mode 100644
index 0000000..cb95572
--- /dev/null
+++ b/src/runtime/stack.c
@@ -0,0 +1,892 @@
+// 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"
+#include "malloc.h"
+#include "stack.h"
+#include "funcdata.h"
+#include "typekind.h"
+#include "type.h"
+#include "race.h"
+#include "mgc0.h"
+#include "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
+	StackPoisonCopy = 0,	// fill stack that should not be accessed with garbage, to detect bad dereferences during copy
+
+	StackCache = 1,
+};
+
+// Global pool of spans that have free stacks.
+// Stacks are assigned an order according to size.
+//     order = log_2(size/FixedStack)
+// There is a free list for each order.
+MSpan runtime·stackpool[NumStackOrders];
+Mutex runtime·stackpoolmu;
+// TODO: one lock per order?
+
+static Stack stackfreequeue;
+
+void
+runtime·stackinit(void)
+{
+	int32 i;
+
+	if((StackCacheSize & PageMask) != 0)
+		runtime·throw("cache size must be a multiple of page size");
+
+	for(i = 0; i < NumStackOrders; i++)
+		runtime·MSpanList_Init(&runtime·stackpool[i]);
+}
+
+// Allocates a stack from the free pool.  Must be called with
+// stackpoolmu held.
+static MLink*
+poolalloc(uint8 order)
+{
+	MSpan *list;
+	MSpan *s;
+	MLink *x;
+	uintptr i;
+
+	list = &runtime·stackpool[order];
+	s = list->next;
+	if(s == list) {
+		// no free stacks.  Allocate another span worth.
+		s = runtime·MHeap_AllocStack(&runtime·mheap, StackCacheSize >> PageShift);
+		if(s == nil)
+			runtime·throw("out of memory");
+		if(s->ref != 0)
+			runtime·throw("bad ref");
+		if(s->freelist != nil)
+			runtime·throw("bad freelist");
+		for(i = 0; i < StackCacheSize; i += FixedStack << order) {
+			x = (MLink*)((s->start << PageShift) + i);
+			x->next = s->freelist;
+			s->freelist = x;
+		}
+		runtime·MSpanList_Insert(list, s);
+	}
+	x = s->freelist;
+	if(x == nil)
+		runtime·throw("span has no free stacks");
+	s->freelist = x->next;
+	s->ref++;
+	if(s->freelist == nil) {
+		// all stacks in s are allocated.
+		runtime·MSpanList_Remove(s);
+	}
+	return x;
+}
+
+// Adds stack x to the free pool.  Must be called with stackpoolmu held.
+static void
+poolfree(MLink *x, uint8 order)
+{
+	MSpan *s;
+
+	s = runtime·MHeap_Lookup(&runtime·mheap, x);
+	if(s->state != MSpanStack)
+		runtime·throw("freeing stack not in a stack span");
+	if(s->freelist == nil) {
+		// s will now have a free stack
+		runtime·MSpanList_Insert(&runtime·stackpool[order], s);
+	}
+	x->next = s->freelist;
+	s->freelist = x;
+	s->ref--;
+	if(s->ref == 0) {
+		// span is completely free - return to heap
+		runtime·MSpanList_Remove(s);
+		s->freelist = nil;
+		runtime·MHeap_FreeStack(&runtime·mheap, s);
+	}
+}
+
+// stackcacherefill/stackcacherelease implement a global pool of stack segments.
+// The pool is required to prevent unlimited growth of per-thread caches.
+static void
+stackcacherefill(MCache *c, uint8 order)
+{
+	MLink *x, *list;
+	uintptr size;
+
+	if(StackDebug >= 1)
+		runtime·printf("stackcacherefill order=%d\n", order);
+
+	// Grab some stacks from the global cache.
+	// Grab half of the allowed capacity (to prevent thrashing).
+	list = nil;
+	size = 0;
+	runtime·lock(&runtime·stackpoolmu);
+	while(size < StackCacheSize/2) {
+		x = poolalloc(order);
+		x->next = list;
+		list = x;
+		size += FixedStack << order;
+	}
+	runtime·unlock(&runtime·stackpoolmu);
+
+	c->stackcache[order].list = list;
+	c->stackcache[order].size = size;
+}
+
+static void
+stackcacherelease(MCache *c, uint8 order)
+{
+	MLink *x, *y;
+	uintptr size;
+
+	if(StackDebug >= 1)
+		runtime·printf("stackcacherelease order=%d\n", order);
+	x = c->stackcache[order].list;
+	size = c->stackcache[order].size;
+	runtime·lock(&runtime·stackpoolmu);
+	while(size > StackCacheSize/2) {
+		y = x->next;
+		poolfree(x, order);
+		x = y;
+		size -= FixedStack << order;
+	}
+	runtime·unlock(&runtime·stackpoolmu);
+	c->stackcache[order].list = x;
+	c->stackcache[order].size = size;
+}
+
+void
+runtime·stackcache_clear(MCache *c)
+{
+	uint8 order;
+	MLink *x, *y;
+
+	if(StackDebug >= 1)
+		runtime·printf("stackcache clear\n");
+	runtime·lock(&runtime·stackpoolmu);
+	for(order = 0; order < NumStackOrders; order++) {
+		x = c->stackcache[order].list;
+		while(x != nil) {
+			y = x->next;
+			poolfree(x, order);
+			x = y;
+		}
+		c->stackcache[order].list = nil;
+		c->stackcache[order].size = 0;
+	}
+	runtime·unlock(&runtime·stackpoolmu);
+}
+
+Stack
+runtime·stackalloc(uint32 n)
+{
+	uint8 order;
+	uint32 n2;
+	void *v;
+	MLink *x;
+	MSpan *s;
+	MCache *c;
+
+	// 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 != 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);
+
+	if(runtime·debug.efence || StackFromSystem) {
+		v = runtime·sysAlloc(ROUND(n, PageSize), &mstats.stacks_sys);
+		if(v == nil)
+			runtime·throw("out of memory (stackalloc)");
+		return (Stack){(uintptr)v, (uintptr)v+n};
+	}
+
+	// Small stacks are allocated with a fixed-size free-list allocator.
+	// If we need a stack of a bigger size, we fall back on allocating
+	// a dedicated span.
+	if(StackCache && n < FixedStack << NumStackOrders && n < StackCacheSize) {
+		order = 0;
+		n2 = n;
+		while(n2 > FixedStack) {
+			order++;
+			n2 >>= 1;
+		}
+		c = g->m->mcache;
+		if(c == nil || g->m->gcing || g->m->helpgc) {
+			// c == nil can happen in the guts of exitsyscall or
+			// procresize. Just get a stack from the global pool.
+			// Also don't touch stackcache during gc
+			// as it's flushed concurrently.
+			runtime·lock(&runtime·stackpoolmu);
+			x = poolalloc(order);
+			runtime·unlock(&runtime·stackpoolmu);
+		} else {
+			x = c->stackcache[order].list;
+			if(x == nil) {
+				stackcacherefill(c, order);
+				x = c->stackcache[order].list;
+			}
+			c->stackcache[order].list = x->next;
+			c->stackcache[order].size -= n;
+		}
+		v = (byte*)x;
+	} else {
+		s = runtime·MHeap_AllocStack(&runtime·mheap, ROUND(n, PageSize) >> PageShift);
+		if(s == nil)
+			runtime·throw("out of memory");
+		v = (byte*)(s->start<<PageShift);
+	}
+	
+	if(raceenabled)
+		runtime·racemalloc(v, n);
+	if(StackDebug >= 1)
+		runtime·printf("  allocated %p\n", v);
+	return (Stack){(uintptr)v, (uintptr)v+n};
+}
+
+void
+runtime·stackfree(Stack stk)
+{
+	uint8 order;
+	uintptr n, n2;
+	MSpan *s;
+	MLink *x;
+	MCache *c;
+	void *v;
+	
+	n = stk.hi - stk.lo;
+	v = (void*)stk.lo;
+	if(n & (n-1))
+		runtime·throw("stack not a power of 2");
+	if(StackDebug >= 1) {
+		runtime·printf("stackfree %p %d\n", v, (int32)n);
+		runtime·memclr(v, n); // for testing, clobber stack data
+	}
+	if(runtime·debug.efence || StackFromSystem) {
+		if(runtime·debug.efence || StackFaultOnFree)
+			runtime·SysFault(v, n);
+		else
+			runtime·SysFree(v, n, &mstats.stacks_sys);
+		return;
+	}
+	if(StackCache && n < FixedStack << NumStackOrders && n < StackCacheSize) {
+		order = 0;
+		n2 = n;
+		while(n2 > FixedStack) {
+			order++;
+			n2 >>= 1;
+		}
+		x = (MLink*)v;
+		c = g->m->mcache;
+		if(c == nil || g->m->gcing || g->m->helpgc) {
+			runtime·lock(&runtime·stackpoolmu);
+			poolfree(x, order);
+			runtime·unlock(&runtime·stackpoolmu);
+		} else {
+			if(c->stackcache[order].size >= StackCacheSize)
+				stackcacherelease(c, order);
+			x->next = c->stackcache[order].list;
+			c->stackcache[order].list = x;
+			c->stackcache[order].size += n;
+		}
+	} else {
+		s = runtime·MHeap_Lookup(&runtime·mheap, v);
+		if(s->state != MSpanStack) {
+			runtime·printf("%p %p\n", s->start<<PageShift, v);
+			runtime·throw("bad span state");
+		}
+		runtime·MHeap_FreeStack(&runtime·mheap, s);
+	}
+}
+
+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)
+// +------------------+
+// | args from caller |
+// +------------------+ <- frame->argp
+// | caller's retaddr |
+// +------------------+ <- frame->varp
+// |     locals       |
+// +------------------+
+// |  args to callee  |
+// +------------------+
+// |  return address  |
+// +------------------+ <- frame->sp
+
+void runtime·main(void);
+void runtime·switchtoM(void(*)(void));
+
+typedef struct AdjustInfo AdjustInfo;
+struct AdjustInfo {
+	Stack old;
+	uintptr delta;  // ptr distance from old to new stack (newbase - oldbase)
+};
+
+// Adjustpointer checks whether *vpp is in the old stack described by adjinfo.
+// If so, it rewrites *vpp to point into the new stack.
+static void
+adjustpointer(AdjustInfo *adjinfo, void *vpp)
+{
+	byte **pp, *p;
+	
+	pp = vpp;
+	p = *pp;
+	if(StackDebug >= 4)
+		runtime·printf("        %p:%p\n", pp, p);
+	if(adjinfo->old.lo <= (uintptr)p && (uintptr)p < adjinfo->old.hi) {
+		*pp = p + adjinfo->delta;
+		if(StackDebug >= 3)
+			runtime·printf("        adjust ptr %p: %p -> %p\n", pp, p, *pp);
+	}
+}
+
+// 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 = (byte*)adjinfo->old.lo;
+	maxp = (byte*)adjinfo->old.hi;
+	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->bytedata[i / (8 / BitsPerPointer)] >> (i * BitsPerPointer & 7) & 3], scanp[i]);
+		switch(bv->bytedata[i / (8 / BitsPerPointer)] >> (i * BitsPerPointer & 7) & 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 && runtime·invalidptr || (uintptr)p == PoisonGC || (uintptr)p == PoisonStack)) {
+				// Looks like a junk value in a pointer slot.
+				// Live analysis wrong?
+				g->m->traceback = 2;
+				runtime·printf("runtime: bad pointer in frame %s at %p: %p\n", runtime·funcname(f), &scanp[i], p);
+				runtime·throw("invalid stack 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->bytedata[(i+1) / (8 / BitsPerPointer)] >> ((i+1) * BitsPerPointer & 7) & 3) {
+			default:
+				runtime·throw("unexpected garbage collection bits");
+			case BitsEface:
+				t = (Type*)scanp[i];
+				if(t != nil && ((t->kind & KindDirectIface) == 0 || (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->kind & KindDirectIface) == 0 || (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, size, minsize;
+
+	adjinfo = arg;
+	targetpc = frame->continpc;
+	if(targetpc == 0) {
+		// Frame is dead.
+		return true;
+	}
+	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·switchtoM) {
+		// A special routine at the bottom of stack of a goroutine that does an onM call.
+		// We will allow it to be copied even though we don't
+		// have full GC info for it (because it is written in asm).
+		return true;
+	}
+	if(targetpc != f->entry)
+		targetpc--;
+	pcdata = runtime·pcdatavalue(f, PCDATA_StackMapIndex, targetpc);
+	if(pcdata == -1)
+		pcdata = 0; // in prologue
+
+	// Adjust local variables if stack frame has been allocated.
+	size = frame->varp - frame->sp;
+	if(thechar != '6' && thechar != '8')
+		minsize = sizeof(uintptr);
+	else
+		minsize = 0;
+	if(size > minsize) {
+		stackmap = runtime·funcdata(f, FUNCDATA_LocalsPointerMaps);
+		if(stackmap == nil || stackmap->n <= 0) {
+			runtime·printf("runtime: frame %s untyped locals %p+%p\n", runtime·funcname(f), (byte*)(frame->varp-size), size);
+			runtime·throw("missing stackmap");
+		}
+		// Locals bitmap information, scan just the pointers in locals.
+		if(pcdata < 0 || pcdata >= stackmap->n) {
+			// don't know where we are
+			runtime·printf("runtime: pcdata is %d and %d locals stack map entries for %s (targetpc=%p)\n",
+				pcdata, stackmap->n, runtime·funcname(f), targetpc);
+			runtime·throw("bad symbol table");
+		}
+		bv = runtime·stackmapdata(stackmap, pcdata);
+		size = (bv.n * PtrSize) / BitsPerPointer;
+		if(StackDebug >= 3)
+			runtime·printf("      locals\n");
+		adjustpointers((byte**)(frame->varp - size), &bv, adjinfo, f);
+	}
+	
+	// Adjust arguments.
+	if(frame->arglen > 0) {
+		if(frame->argmap != nil) {
+			bv = *frame->argmap;
+		} else {
+			stackmap = runtime·funcdata(f, FUNCDATA_ArgsPointerMaps);
+			if(stackmap == nil || stackmap->n <= 0) {
+				runtime·printf("runtime: frame %s untyped args %p+%p\n", runtime·funcname(f), frame->argp, (uintptr)frame->arglen);
+				runtime·throw("missing stackmap");
+			}
+			if(pcdata < 0 || pcdata >= stackmap->n) {
+				// don't know where we are
+				runtime·printf("runtime: pcdata is %d and %d args stack map entries for %s (targetpc=%p)\n",
+					pcdata, stackmap->n, runtime·funcname(f), targetpc);
+				runtime·throw("bad symbol table");
+			}
+			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)
+{
+	adjustpointer(adjinfo, &gp->sched.ctxt);
+}
+
+static void
+adjustdefers(G *gp, AdjustInfo *adjinfo)
+{
+	Defer *d;
+	bool (*cb)(Stkframe*, void*);
+
+	// Adjust defer argument blocks the same way we adjust active stack frames.
+	cb = adjustframe;
+	runtime·tracebackdefers(gp, &cb, adjinfo);
+
+	// Adjust pointers in the Defer structs.
+	// Defer structs themselves are never on the stack.
+	for(d = gp->defer; d != nil; d = d->link) {
+		adjustpointer(adjinfo, &d->fn);
+		adjustpointer(adjinfo, &d->argp);
+		adjustpointer(adjinfo, &d->panic);
+	}
+}
+
+static void
+adjustpanics(G *gp, AdjustInfo *adjinfo)
+{
+	// Panics are on stack and already adjusted.
+	// Update pointer to head of list in G.
+	adjustpointer(adjinfo, &gp->panic);
+}
+
+static void
+adjustsudogs(G *gp, AdjustInfo *adjinfo)
+{
+	SudoG *s;
+
+	// the data elements pointed to by a SudoG structure
+	// might be in the stack.
+	for(s = gp->waiting; s != nil; s = s->waitlink) {
+		adjustpointer(adjinfo, &s->elem);
+		adjustpointer(adjinfo, &s->selectdone);
+	}
+}
+
+// Copies gp's stack to a new stack of a different size.
+static void
+copystack(G *gp, uintptr newsize)
+{
+	Stack old, new;
+	uintptr used;
+	AdjustInfo adjinfo;
+	uint32 oldstatus;
+	bool (*cb)(Stkframe*, void*);
+	byte *p, *ep;
+
+	if(gp->syscallsp != 0)
+		runtime·throw("stack growth not allowed in system call");
+	old = gp->stack;
+	if(old.lo == 0)
+		runtime·throw("nil stackbase");
+	used = old.hi - gp->sched.sp;
+
+	// allocate new stack
+	new = runtime·stackalloc(newsize);
+	if(StackPoisonCopy) {
+		p = (byte*)new.lo;
+		ep = (byte*)new.hi;
+		while(p < ep)
+			*p++ = 0xfd;
+	}
+
+	if(StackDebug >= 1)
+		runtime·printf("copystack gp=%p [%p %p %p]/%d -> [%p %p %p]/%d\n", gp, old.lo, old.hi-used, old.hi, (int32)(old.hi-old.lo), new.lo, new.hi-used, new.hi, (int32)newsize);
+	
+	// adjust pointers in the to-be-copied frames
+	adjinfo.old = old;
+	adjinfo.delta = new.hi - old.hi;
+	cb = adjustframe;
+	runtime·gentraceback(~(uintptr)0, ~(uintptr)0, 0, gp, 0, nil, 0x7fffffff, &cb, &adjinfo, 0);
+	
+	// adjust other miscellaneous things that have pointers into stacks.
+	adjustctxt(gp, &adjinfo);
+	adjustdefers(gp, &adjinfo);
+	adjustpanics(gp, &adjinfo);
+	adjustsudogs(gp, &adjinfo);
+	
+	// copy the stack to the new location
+	if(StackPoisonCopy) {
+		p = (byte*)new.lo;
+		ep = (byte*)new.hi;
+		while(p < ep)
+			*p++ = 0xfb;
+	}
+	runtime·memmove((byte*)new.hi - used, (byte*)old.hi - used, used);
+
+	oldstatus = runtime·casgcopystack(gp); // cas from Gwaiting or Grunnable to Gcopystack, return old status
+
+	// Swap out old stack for new one
+	gp->stack = new;
+	gp->stackguard0 = new.lo + StackGuard; // NOTE: might clobber a preempt request
+	gp->sched.sp = new.hi - used;
+
+	runtime·casgstatus(gp, Gcopystack, oldstatus); // oldstatus is Gwaiting or Grunnable
+
+	// free old stack
+	if(StackPoisonCopy) {
+		p = (byte*)old.lo;
+		ep = (byte*)old.hi;
+		while(p < ep)
+			*p++ = 0xfc;
+	}
+	if(newsize > old.hi-old.lo) {
+		// growing, free stack immediately
+		runtime·stackfree(old);
+	} else {
+		// shrinking, queue up free operation.  We can't actually free the stack
+		// just yet because we might run into the following situation:
+		// 1) GC starts, scans a SudoG but does not yet mark the SudoG.elem pointer
+		// 2) The stack that pointer points to is shrunk
+		// 3) The old stack is freed
+		// 4) The containing span is marked free
+		// 5) GC attempts to mark the SudoG.elem pointer.  The marking fails because
+		//    the pointer looks like a pointer into a free span.
+		// By not freeing, we prevent step #4 until GC is done.
+		runtime·lock(&runtime·stackpoolmu);
+		*(Stack*)old.lo = stackfreequeue;
+		stackfreequeue = old;
+		runtime·unlock(&runtime·stackpoolmu);
+	}
+}
+
+// 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·morestack when more stack is needed.
+// Allocate larger stack and relocate to new stack.
+// Stack growth is multiplicative, for constant amortized cost.
+//
+// g->atomicstatus will be Grunning or Gscanrunning upon entry. 
+// If the GC is trying to stop this g then it will set preemptscan to true.
+void
+runtime·newstack(void)
+{
+	int32 oldsize, newsize;
+	uintptr sp;
+	G *gp;
+	Gobuf morebuf;
+
+	if(g->m->morebuf.g->stackguard0 == (uintptr)StackFork)
+		runtime·throw("stack growth after fork");
+	if(g->m->morebuf.g != g->m->curg) {
+		runtime·printf("runtime: newstack called from g=%p\n"
+			"\tm=%p m->curg=%p m->g0=%p m->gsignal=%p\n",
+			g->m->morebuf.g, g->m, g->m->curg, g->m->g0, g->m->gsignal);
+		morebuf = g->m->morebuf;
+		runtime·traceback(morebuf.pc, morebuf.sp, morebuf.lr, morebuf.g);
+		runtime·throw("runtime: wrong goroutine in newstack");
+	}
+	if(g->m->curg->throwsplit)
+		runtime·throw("runtime: stack split at bad time");
+
+	// The goroutine must be executing in order to call newstack,
+	// so it must be Grunning or Gscanrunning.
+
+	gp = g->m->curg;
+	morebuf = g->m->morebuf;
+	g->m->morebuf.pc = (uintptr)nil;
+	g->m->morebuf.lr = (uintptr)nil;
+	g->m->morebuf.sp = (uintptr)nil;
+	g->m->morebuf.g = (G*)nil;
+
+	runtime·casgstatus(gp, Grunning, Gwaiting);
+	gp->waitreason = runtime·gostringnocopy((byte*)"stack growth");
+
+	runtime·rewindmorestack(&gp->sched);
+
+	if(gp->stack.lo == 0)
+		runtime·throw("missing stack in newstack");
+	sp = gp->sched.sp;
+	if(thechar == '6' || thechar == '8') {
+		// The call to morestack cost a word.
+		sp -= sizeof(uintreg);
+	}
+	if(StackDebug >= 1 || sp < gp->stack.lo) {
+		runtime·printf("runtime: newstack sp=%p stack=[%p, %p]\n"
+			"\tmorebuf={pc:%p sp:%p lr:%p}\n"
+			"\tsched={pc:%p sp:%p lr:%p ctxt:%p}\n",
+			sp, gp->stack.lo, gp->stack.hi,
+			g->m->morebuf.pc, g->m->morebuf.sp, g->m->morebuf.lr,
+			gp->sched.pc, gp->sched.sp, gp->sched.lr, gp->sched.ctxt);
+	}
+	if(sp < gp->stack.lo) {
+		runtime·printf("runtime: gp=%p, gp->status=%d\n ", (void*)gp, runtime·readgstatus(gp));
+		runtime·printf("runtime: split stack overflow: %p < %p\n", sp, gp->stack.lo);
+		runtime·throw("runtime: split stack overflow");
+	}
+
+	if(gp->stackguard0 == (uintptr)StackPreempt) {
+		if(gp == g->m->g0)
+			runtime·throw("runtime: preempt g0");
+		if(g->m->p == nil && g->m->locks == 0)
+			runtime·throw("runtime: g is running but p is not");
+		if(gp->preemptscan) {
+			runtime·gcphasework(gp);
+			runtime·casgstatus(gp, Gwaiting, Grunning);
+			gp->stackguard0 = gp->stack.lo + StackGuard;
+			gp->preempt = false; 
+			gp->preemptscan = false;        // Tells the GC premption was successful.
+			runtime·gogo(&gp->sched);	// never return 
+		}
+
+		// Be conservative about where we preempt.
+		// We are interested in preempting user Go code, not runtime code.
+		if(g->m->locks || g->m->mallocing || g->m->gcing || g->m->p->status != Prunning) {
+			// Let the goroutine keep running for now.
+			// gp->preempt is set, so it will be preempted next time.
+			gp->stackguard0 = gp->stack.lo + StackGuard;
+			runtime·casgstatus(gp, Gwaiting, Grunning);
+			runtime·gogo(&gp->sched);	// never return
+		}
+		// Act like goroutine called runtime.Gosched.
+		runtime·casgstatus(gp, Gwaiting, Grunning);
+		runtime·gosched_m(gp);	// never return
+	}
+
+	// Allocate a bigger segment and move the stack.
+	oldsize = gp->stack.hi - gp->stack.lo;
+	newsize = oldsize * 2;
+	if(newsize > runtime·maxstacksize) {
+		runtime·printf("runtime: goroutine stack exceeds %D-byte limit\n", (uint64)runtime·maxstacksize);
+		runtime·throw("stack overflow");
+	}
+
+	// Note that the concurrent GC might be scanning the stack as we try to replace it.
+	// copystack takes care of the appropriate coordination with the stack scanner.
+	copystack(gp, newsize);
+	if(StackDebug >= 1)
+		runtime·printf("stack grow done\n");
+	runtime·casgstatus(gp, Gwaiting, Grunning);
+	runtime·gogo(&gp->sched);
+}
+
+#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)
+{
+	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·shrinkstack(G *gp)
+{
+	uintptr used, oldsize, newsize;
+
+	if(runtime·readgstatus(gp) == Gdead) {
+		if(gp->stack.lo != 0) {
+			// Free whole stack - it will get reallocated
+			// if G is used again.
+			runtime·stackfree(gp->stack);
+			gp->stack.lo = 0;
+			gp->stack.hi = 0;
+		}
+		return;
+	}
+	if(gp->stack.lo == 0)
+		runtime·throw("missing stack in shrinkstack");
+
+	oldsize = gp->stack.hi - gp->stack.lo;
+	newsize = oldsize / 2;
+	if(newsize < FixedStack)
+		return; // don't shrink below the minimum-sized stack
+	used = gp->stack.hi - gp->sched.sp;
+	if(used >= oldsize / 4)
+		return; // still using at least 1/4 of the segment.
+
+	// We can't copy the stack if we're in a syscall.
+	// The syscall might have pointers into the stack.
+	if(gp->syscallsp != 0)
+		return;
+
+#ifdef GOOS_windows
+	if(gp->m != nil && gp->m->libcallsp != 0)
+		return;
+#endif
+	if(StackDebug > 0)
+		runtime·printf("shrinking stack %D->%D\n", (uint64)oldsize, (uint64)newsize);
+	copystack(gp, newsize);
+}
+
+// Do any delayed stack freeing that was queued up during GC.
+void
+runtime·shrinkfinish(void)
+{
+	Stack s, t;
+
+	runtime·lock(&runtime·stackpoolmu);
+	s = stackfreequeue;
+	stackfreequeue = (Stack){0,0};
+	runtime·unlock(&runtime·stackpoolmu);
+	while(s.lo != 0) {
+		t = *(Stack*)s.lo;
+		runtime·stackfree(s);
+		s = t;
+	}
+}
+
+static void badc(void);
+
+#pragma textflag NOSPLIT
+void
+runtime·morestackc(void)
+{
+	void (*fn)(void);
+	
+	fn = badc;
+	runtime·onM(&fn);
+}
+
+static void
+badc(void)
+{
+	runtime·throw("attempt to execute C code on Go stack");
+}
diff --git a/src/runtime/stack.go b/src/runtime/stack.go
new file mode 100644
index 0000000..f1b7d32
--- /dev/null
+++ b/src/runtime/stack.go
@@ -0,0 +1,13 @@
+// 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 runtime
+
+const (
+	// Goroutine preemption request.
+	// Stored into g->stackguard0 to cause split stack check failure.
+	// Must be greater than any real sp.
+	// 0xfffffade in hex.
+	stackPreempt = ^uintptr(1313)
+)
diff --git a/src/runtime/stack.h b/src/runtime/stack.h
new file mode 100644
index 0000000..f97dc4e
--- /dev/null
+++ b/src/runtime/stack.h
@@ -0,0 +1,118 @@
+// 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.
+
+/*
+Stack layout parameters.
+Included both by runtime (compiled via 6c) and linkers (compiled via gcc).
+
+The per-goroutine g->stackguard is set to point StackGuard bytes
+above the bottom of the stack.  Each function compares its stack
+pointer against g->stackguard to check for overflow.  To cut one
+instruction from the check sequence for functions with tiny frames,
+the stack is allowed to protrude StackSmall bytes below the stack
+guard.  Functions with large frames don't bother with the check and
+always call morestack.  The sequences are (for amd64, others are
+similar):
+ 
+	guard = g->stackguard
+	frame = function's stack frame size
+	argsize = size of function arguments (call + return)
+
+	stack frame size <= StackSmall:
+		CMPQ guard, SP
+		JHI 3(PC)
+		MOVQ m->morearg, $(argsize << 32)
+		CALL morestack(SB)
+
+	stack frame size > StackSmall but < StackBig
+		LEAQ (frame-StackSmall)(SP), R0
+		CMPQ guard, R0
+		JHI 3(PC)
+		MOVQ m->morearg, $(argsize << 32)
+		CALL morestack(SB)
+
+	stack frame size >= StackBig:
+		MOVQ m->morearg, $((argsize << 32) | frame)
+		CALL morestack(SB)
+
+The bottom StackGuard - StackSmall bytes are important: there has
+to be enough room to execute functions that refuse to check for
+stack overflow, either because they need to be adjacent to the
+actual caller's frame (deferproc) or because they handle the imminent
+stack overflow (morestack).
+
+For example, deferproc might call malloc, which does one of the
+above checks (without allocating a full frame), which might trigger
+a call to morestack.  This sequence needs to fit in the bottom
+section of the stack.  On amd64, morestack's frame is 40 bytes, and
+deferproc's frame is 56 bytes.  That fits well within the
+StackGuard - StackSmall bytes at the bottom.  
+The linkers explore all possible call traces involving non-splitting
+functions to make sure that this limit cannot be violated.
+ */
+
+enum {
+	// StackSystem is a number of additional bytes to add
+	// to each stack below the usual guard area for OS-specific
+	// purposes like signal handling. Used on Windows and on
+	// Plan 9 because they do not use a separate stack.
+#ifdef GOOS_windows
+	StackSystem = 512 * sizeof(uintptr),
+#else
+#ifdef GOOS_plan9
+	// The size of the note handler frame varies among architectures,
+	// but 512 bytes should be enough for every implementation.
+	StackSystem = 512,
+#else
+	StackSystem = 0,
+#endif	// Plan 9
+#endif	// Windows
+
+	// The minimum size of stack used by Go code
+	StackMin = 2048,
+
+	// The minimum stack size to allocate.
+	// The hackery here rounds FixedStack0 up to a power of 2.
+	FixedStack0 = StackMin + StackSystem,
+	FixedStack1 = FixedStack0 - 1,
+	FixedStack2 = FixedStack1 | (FixedStack1 >> 1),
+	FixedStack3 = FixedStack2 | (FixedStack2 >> 2),
+	FixedStack4 = FixedStack3 | (FixedStack3 >> 4),
+	FixedStack5 = FixedStack4 | (FixedStack4 >> 8),
+	FixedStack6 = FixedStack5 | (FixedStack5 >> 16),
+	FixedStack = FixedStack6 + 1,
+
+	// Functions that need frames bigger than this use an extra
+	// instruction to do the stack split check, to avoid overflow
+	// in case SP - framesize wraps below zero.
+	// This value can be no bigger than the size of the unmapped
+	// space at zero.
+	StackBig = 4096,
+
+	// The stack guard is a pointer this many bytes above the
+	// bottom of the stack.
+	StackGuard = 512 + StackSystem,
+
+	// After a stack split check the SP is allowed to be this
+	// many bytes below the stack guard.  This saves an instruction
+	// in the checking sequence for tiny frames.
+	StackSmall = 128,
+
+	// The maximum number of bytes that a chain of NOSPLIT
+	// functions can use.
+	StackLimit = StackGuard - StackSystem - StackSmall,
+};
+
+// Goroutine preemption request.
+// Stored into g->stackguard0 to cause split stack check failure.
+// Must be greater than any real sp.
+// 0xfffffade in hex.
+#define StackPreempt ((uint64)-1314)
+/*c2go
+enum
+{
+	StackPreempt = -1314,
+};
+*/
+#define StackFork ((uint64)-1234)
diff --git a/src/runtime/stack_test.go b/src/runtime/stack_test.go
index fa073f1..652c72e 100644
--- a/src/runtime/stack_test.go
+++ b/src/runtime/stack_test.go
@@ -60,7 +60,7 @@ func TestStackMem(t *testing.T) {
 	if consumed > estimate {
 		t.Fatalf("Stack mem: want %v, got %v", estimate, consumed)
 	}
-	// Due to broken stack memory accounting (https://golang.org/issue/7468),
+	// 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)
@@ -309,40 +309,6 @@ func TestPanicUseStack(t *testing.T) {
 	panic(1)
 }
 
-func TestPanicFar(t *testing.T) {
-	var xtree *xtreeNode
-	pc := make([]uintptr, 10000)
-	defer func() {
-		// At this point we created a large stack and unwound
-		// it via recovery. Force a stack walk, which will
-		// check the consistency of stack barriers.
-		Callers(0, pc)
-	}()
-	defer func() {
-		recover()
-	}()
-	useStackAndCall(100, func() {
-		// Kick off the GC and make it do something nontrivial
-		// to keep stack barriers installed for a while.
-		xtree = makeTree(18)
-		// Give the GC time to install stack barriers.
-		time.Sleep(time.Millisecond)
-		panic(1)
-	})
-	_ = xtree
-}
-
-type xtreeNode struct {
-	l, r *xtreeNode
-}
-
-func makeTree(d int) *xtreeNode {
-	if d == 0 {
-		return new(xtreeNode)
-	}
-	return &xtreeNode{makeTree(d - 1), makeTree(d - 1)}
-}
-
 // use about n KB of stack and call f
 func useStackAndCall(n int, f func()) {
 	if n == 0 {
@@ -429,21 +395,3 @@ func TestStackPanic(t *testing.T) {
 	useStack(32)
 	panic("test panic")
 }
-
-func BenchmarkStackCopy(b *testing.B) {
-	c := make(chan bool)
-	for i := 0; i < b.N; i++ {
-		go func() {
-			count(1000000)
-			c <- true
-		}()
-		<-c
-	}
-}
-
-func count(n int) int {
-	if n == 0 {
-		return 0
-	}
-	return 1 + count(n-1)
-}
diff --git a/src/runtime/string.c b/src/runtime/string.c
new file mode 100644
index 0000000..ed5debc
--- /dev/null
+++ b/src/runtime/string.c
@@ -0,0 +1,226 @@
+// 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 "race.h"
+#include "textflag.h"
+
+String	runtime·emptystring;
+
+#pragma textflag NOSPLIT
+intgo
+runtime·findnull(byte *s)
+{
+	intgo l;
+
+	if(s == nil)
+		return 0;
+	for(l=0; s[l]!=0; l++)
+		;
+	return l;
+}
+
+intgo
+runtime·findnullw(uint16 *s)
+{
+	intgo l;
+
+	if(s == nil)
+		return 0;
+	for(l=0; s[l]!=0; l++)
+		;
+	return l;
+}
+
+uintptr runtime·maxstring = 256; // a hint for print
+
+#pragma textflag NOSPLIT
+String
+runtime·gostringnocopy(byte *str)
+{
+	String s;
+	uintptr ms;
+	
+	s.str = str;
+	s.len = runtime·findnull(str);
+	while(true) {
+		ms = runtime·maxstring;
+		if(s.len <= ms || runtime·casp((void**)&runtime·maxstring, (void*)ms, (void*)s.len))
+			return s;
+	}
+}
+
+// TODO: move this elsewhere
+enum
+{
+	Bit1	= 7,
+	Bitx	= 6,
+	Bit2	= 5,
+	Bit3	= 4,
+	Bit4	= 3,
+	Bit5	= 2,
+
+	Tx	= ((1<<(Bitx+1))-1) ^ 0xFF,	/* 1000 0000 */
+	T2	= ((1<<(Bit2+1))-1) ^ 0xFF,	/* 1100 0000 */
+	T3	= ((1<<(Bit3+1))-1) ^ 0xFF,	/* 1110 0000 */
+	T4	= ((1<<(Bit4+1))-1) ^ 0xFF,	/* 1111 0000 */
+
+	Rune1	= (1<<(Bit1+0*Bitx))-1,		/* 0000 0000 0111 1111 */
+	Rune2	= (1<<(Bit2+1*Bitx))-1,		/* 0000 0111 1111 1111 */
+	Rune3	= (1<<(Bit3+2*Bitx))-1,		/* 1111 1111 1111 1111 */
+
+	Maskx	= (1<<Bitx)-1,			/* 0011 1111 */
+
+	Runeerror	= 0xFFFD,
+
+	SurrogateMin = 0xD800,
+	SurrogateMax = 0xDFFF,
+
+	Runemax	= 0x10FFFF,	/* maximum rune value */
+};
+
+static int32
+runetochar(byte *str, int32 rune)  /* note: in original, arg2 was pointer */
+{
+	/* Runes are signed, so convert to unsigned for range check. */
+	uint32 c;
+
+	/*
+	 * one character sequence
+	 *	00000-0007F => 00-7F
+	 */
+	c = rune;
+	if(c <= Rune1) {
+		str[0] = c;
+		return 1;
+	}
+
+	/*
+	 * two character sequence
+	 *	0080-07FF => T2 Tx
+	 */
+	if(c <= Rune2) {
+		str[0] = T2 | (c >> 1*Bitx);
+		str[1] = Tx | (c & Maskx);
+		return 2;
+	}
+
+	/*
+	 * If the Rune is out of range or a surrogate half, convert it to the error rune.
+	 * Do this test here because the error rune encodes to three bytes.
+	 * Doing it earlier would duplicate work, since an out of range
+	 * Rune wouldn't have fit in one or two bytes.
+	 */
+	if (c > Runemax)
+		c = Runeerror;
+	if (SurrogateMin <= c && c <= SurrogateMax)
+		c = Runeerror;
+
+	/*
+	 * three character sequence
+	 *	0800-FFFF => T3 Tx Tx
+	 */
+	if (c <= Rune3) {
+		str[0] = T3 |  (c >> 2*Bitx);
+		str[1] = Tx | ((c >> 1*Bitx) & Maskx);
+		str[2] = Tx |  (c & Maskx);
+		return 3;
+	}
+
+	/*
+	 * four character sequence (21-bit value)
+	 *     10000-1FFFFF => T4 Tx Tx Tx
+	 */
+	str[0] = T4 | (c >> 3*Bitx);
+	str[1] = Tx | ((c >> 2*Bitx) & Maskx);
+	str[2] = Tx | ((c >> 1*Bitx) & Maskx);
+	str[3] = Tx | (c & Maskx);
+	return 4;
+}
+
+String runtime·gostringsize(intgo);
+
+String
+runtime·gostringw(uint16 *str)
+{
+	intgo n1, n2, i;
+	byte buf[8];
+	String s;
+
+	n1 = 0;
+	for(i=0; str[i]; i++)
+		n1 += runetochar(buf, str[i]);
+	s = runtime·gostringsize(n1+4);
+	n2 = 0;
+	for(i=0; str[i]; i++) {
+		// check for race
+		if(n2 >= n1)
+			break;
+		n2 += runetochar(s.str+n2, str[i]);
+	}
+	s.len = n2;
+	s.str[s.len] = 0;
+	return s;
+}
+
+int32
+runtime·strcmp(byte *s1, byte *s2)
+{
+	uintptr i;
+	byte c1, c2;
+
+	for(i=0;; i++) {
+		c1 = s1[i];
+		c2 = s2[i];
+		if(c1 < c2)
+			return -1;
+		if(c1 > c2)
+			return +1;
+		if(c1 == 0)
+			return 0;
+	}
+}
+
+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)
+{
+	byte *sp1, *sp2;
+
+	if(*s2 == 0)
+		return s1;
+	for(; *s1; s1++) {
+		if(*s1 != *s2)
+			continue;
+		sp1 = s1;
+		sp2 = s2;
+		for(;;) {
+			if(*sp2 == 0)
+				return s1;
+			if(*sp1++ != *sp2++)
+				break;
+		}
+	}
+	return nil;
+}
diff --git a/src/runtime/string.go b/src/runtime/string.go
index a5851b7..0809f89 100644
--- a/src/runtime/string.go
+++ b/src/runtime/string.go
@@ -8,18 +8,7 @@ import (
 	"unsafe"
 )
 
-// The constant is known to the compiler.
-// There is no fundamental theory behind this number.
-const tmpStringBufSize = 32
-
-type tmpBuf [tmpStringBufSize]byte
-
-// concatstrings implements a Go string concatenation x+y+z+...
-// The operands are passed in the slice a.
-// If buf != nil, the compiler has determined that the result does not
-// escape the calling function, so the string data can be stored in buf
-// if small enough.
-func concatstrings(buf *tmpBuf, a []string) string {
+func concatstrings(a []string) string {
 	idx := 0
 	l := 0
 	count := 0
@@ -29,7 +18,7 @@ func concatstrings(buf *tmpBuf, a []string) string {
 			continue
 		}
 		if l+n < l {
-			throw("string concatenation too long")
+			gothrow("string concatenation too long")
 		}
 		l += n
 		count++
@@ -38,14 +27,10 @@ func concatstrings(buf *tmpBuf, a []string) string {
 	if count == 0 {
 		return ""
 	}
-
-	// If there is just one string and either it is not on the stack
-	// or our result does not escape the calling frame (buf != nil),
-	// then we can return that string directly.
-	if count == 1 && (buf != nil || !stringDataOnStack(a[idx])) {
+	if count == 1 {
 		return a[idx]
 	}
-	s, b := rawstringtmp(buf, l)
+	s, b := rawstring(l)
 	l = 0
 	for _, x := range a {
 		copy(b[l:], x)
@@ -54,71 +39,46 @@ func concatstrings(buf *tmpBuf, a []string) string {
 	return s
 }
 
-func concatstring2(buf *tmpBuf, a [2]string) string {
-	return concatstrings(buf, a[:])
+//go:nosplit
+func concatstring2(a [2]string) string {
+	return concatstrings(a[:])
 }
 
-func concatstring3(buf *tmpBuf, a [3]string) string {
-	return concatstrings(buf, a[:])
+//go:nosplit
+func concatstring3(a [3]string) string {
+	return concatstrings(a[:])
 }
 
-func concatstring4(buf *tmpBuf, a [4]string) string {
-	return concatstrings(buf, a[:])
+//go:nosplit
+func concatstring4(a [4]string) string {
+	return concatstrings(a[:])
 }
 
-func concatstring5(buf *tmpBuf, a [5]string) string {
-	return concatstrings(buf, a[:])
+//go:nosplit
+func concatstring5(a [5]string) string {
+	return concatstrings(a[:])
 }
 
-// Buf is a fixed-size buffer for the result,
-// it is not nil if the result does not escape.
-func slicebytetostring(buf *tmpBuf, b []byte) string {
-	l := len(b)
-	if l == 0 {
-		// Turns out to be a relatively common case.
-		// Consider that you want to parse out data between parens in "foo()bar",
-		// you find the indices and convert the subslice to string.
-		return ""
-	}
-	if raceenabled && l > 0 {
+func slicebytetostring(b []byte) string {
+	if raceenabled && len(b) > 0 {
 		racereadrangepc(unsafe.Pointer(&b[0]),
-			uintptr(l),
+			uintptr(len(b)),
 			getcallerpc(unsafe.Pointer(&b)),
 			funcPC(slicebytetostring))
 	}
-	s, c := rawstringtmp(buf, l)
+	s, c := rawstring(len(b))
 	copy(c, b)
 	return s
 }
 
-// stringDataOnStack reports whether the string's data is
-// stored on the current goroutine's stack.
-func stringDataOnStack(s string) bool {
-	ptr := uintptr((*stringStruct)(unsafe.Pointer(&s)).str)
-	stk := getg().stack
-	return stk.lo <= ptr && ptr < stk.hi
-}
-
-func rawstringtmp(buf *tmpBuf, l int) (s string, b []byte) {
-	if buf != nil && l <= len(buf) {
-		b = buf[:l]
-		s = slicebytetostringtmp(b)
-	} else {
-		s, b = rawstring(l)
-	}
-	return
-}
-
 func slicebytetostringtmp(b []byte) string {
 	// 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.
-	// First such case is a m[string(k)] lookup where
+	// Today, the only such case is a m[string(k)] lookup where
 	// m is a string-keyed map and k is a []byte.
-	// Second such case is "<"+string(b)+">" concatenation where b is []byte.
-	// Third such case is string(b)=="foo" comparison where b is []byte.
 
 	if raceenabled && len(b) > 0 {
 		racereadrangepc(unsafe.Pointer(&b[0]),
@@ -129,30 +89,13 @@ func slicebytetostringtmp(b []byte) string {
 	return *(*string)(unsafe.Pointer(&b))
 }
 
-func stringtoslicebyte(buf *tmpBuf, s string) []byte {
-	var b []byte
-	if buf != nil && len(s) <= len(buf) {
-		b = buf[:len(s)]
-	} else {
-		b = rawbyteslice(len(s))
-	}
+func stringtoslicebyte(s string) []byte {
+	b := rawbyteslice(len(s))
 	copy(b, s)
 	return b
 }
 
-func stringtoslicebytetmp(s string) []byte {
-	// Return a slice referring to the actual string bytes.
-	// This is only for use by internal compiler optimizations
-	// that know that the slice won't be mutated.
-	// The only such case today is:
-	// for i, c := range []byte(str)
-
-	str := (*stringStruct)(unsafe.Pointer(&s))
-	ret := slice{array: unsafe.Pointer(str.str), len: str.len, cap: str.len}
-	return *(*[]byte)(unsafe.Pointer(&ret))
-}
-
-func stringtoslicerune(buf *[tmpStringBufSize]rune, s string) []rune {
+func stringtoslicerune(s string) []rune {
 	// two passes.
 	// unlike slicerunetostring, no race because strings are immutable.
 	n := 0
@@ -162,12 +105,7 @@ func stringtoslicerune(buf *[tmpStringBufSize]rune, s string) []rune {
 		s = s[k:]
 		n++
 	}
-	var a []rune
-	if buf != nil && n <= len(buf) {
-		a = buf[:n]
-	} else {
-		a = rawruneslice(n)
-	}
+	a := rawruneslice(n)
 	n = 0
 	for len(t) > 0 {
 		r, k := charntorune(t)
@@ -178,7 +116,7 @@ func stringtoslicerune(buf *[tmpStringBufSize]rune, s string) []rune {
 	return a
 }
 
-func slicerunetostring(buf *tmpBuf, a []rune) string {
+func slicerunetostring(a []rune) string {
 	if raceenabled && len(a) > 0 {
 		racereadrangepc(unsafe.Pointer(&a[0]),
 			uintptr(len(a))*unsafe.Sizeof(a[0]),
@@ -190,7 +128,7 @@ func slicerunetostring(buf *tmpBuf, a []rune) string {
 	for _, r := range a {
 		size1 += runetochar(dum[:], r)
 	}
-	s, b := rawstringtmp(buf, size1+3)
+	s, b := rawstring(size1 + 3)
 	size2 := 0
 	for _, r := range a {
 		// check for race
@@ -207,15 +145,8 @@ type stringStruct struct {
 	len int
 }
 
-func intstring(buf *[4]byte, v int64) string {
-	var s string
-	var b []byte
-	if buf != nil {
-		b = buf[:]
-		s = slicebytetostringtmp(b)
-	} else {
-		s, b = rawstring(4)
-	}
+func intstring(v int64) string {
+	s, b := rawstring(4)
 	n := runetochar(b, rune(v))
 	return s[:n]
 }
@@ -266,7 +197,9 @@ func rawstring(size int) (s string, b []byte) {
 	(*stringStruct)(unsafe.Pointer(&s)).str = p
 	(*stringStruct)(unsafe.Pointer(&s)).len = size
 
-	*(*slice)(unsafe.Pointer(&b)) = slice{p, size, size}
+	(*slice)(unsafe.Pointer(&b)).array = (*uint8)(p)
+	(*slice)(unsafe.Pointer(&b)).len = uint(size)
+	(*slice)(unsafe.Pointer(&b)).cap = uint(size)
 
 	for {
 		ms := maxstring
@@ -278,28 +211,32 @@ func rawstring(size int) (s string, b []byte) {
 
 // rawbyteslice allocates a new byte slice. The byte slice is not zeroed.
 func rawbyteslice(size int) (b []byte) {
-	cap := roundupsize(uintptr(size))
+	cap := goroundupsize(uintptr(size))
 	p := mallocgc(cap, nil, flagNoScan|flagNoZero)
 	if cap != uintptr(size) {
 		memclr(add(p, uintptr(size)), cap-uintptr(size))
 	}
 
-	*(*slice)(unsafe.Pointer(&b)) = slice{p, size, int(cap)}
+	(*slice)(unsafe.Pointer(&b)).array = (*uint8)(p)
+	(*slice)(unsafe.Pointer(&b)).len = uint(size)
+	(*slice)(unsafe.Pointer(&b)).cap = uint(cap)
 	return
 }
 
 // rawruneslice allocates a new rune slice. The rune slice is not zeroed.
 func rawruneslice(size int) (b []rune) {
-	if uintptr(size) > _MaxMem/4 {
-		throw("out of memory")
+	if uintptr(size) > maxmem/4 {
+		gothrow("out of memory")
 	}
-	mem := roundupsize(uintptr(size) * 4)
+	mem := goroundupsize(uintptr(size) * 4)
 	p := mallocgc(mem, nil, flagNoScan|flagNoZero)
 	if mem != uintptr(size)*4 {
 		memclr(add(p, uintptr(size)*4), mem-uintptr(size)*4)
 	}
 
-	*(*slice)(unsafe.Pointer(&b)) = slice{p, size, int(mem / 4)}
+	(*slice)(unsafe.Pointer(&b)).array = (*uint8)(p)
+	(*slice)(unsafe.Pointer(&b)).len = uint(size)
+	(*slice)(unsafe.Pointer(&b)).cap = uint(mem / 4)
 	return
 }
 
@@ -313,6 +250,14 @@ func gobytes(p *byte, n int) []byte {
 	return x
 }
 
+func gostringsize(n int) string {
+	s, _ := rawstring(n)
+	return s
+}
+
+//go:noescape
+func findnull(*byte) int
+
 func gostring(p *byte) string {
 	l := findnull(p)
 	if l == 0 {
@@ -351,12 +296,3 @@ func contains(s, t string) bool {
 func hasprefix(s, t string) bool {
 	return len(s) >= len(t) && s[:len(t)] == t
 }
-
-func atoi(s string) int {
-	n := 0
-	for len(s) > 0 && '0' <= s[0] && s[0] <= '9' {
-		n = n*10 + int(s[0]) - '0'
-		s = s[1:]
-	}
-	return n
-}
diff --git a/src/runtime/string_test.go b/src/runtime/string_test.go
index dfda950..1551ecc 100644
--- a/src/runtime/string_test.go
+++ b/src/runtime/string_test.go
@@ -158,80 +158,3 @@ func TestGostringnocopy(t *testing.T) {
 		t.Errorf("want %d, got %d", max+9, newmax)
 	}
 }
-
-func TestCompareTempString(t *testing.T) {
-	s := "foo"
-	b := []byte(s)
-	n := testing.AllocsPerRun(1000, func() {
-		if string(b) != s {
-			t.Fatalf("strings are not equal: '%v' and '%v'", string(b), s)
-		}
-		if string(b) == s {
-		} else {
-			t.Fatalf("strings are not equal: '%v' and '%v'", string(b), s)
-		}
-	})
-	if n != 0 {
-		t.Fatalf("want 0 allocs, got %v", n)
-	}
-}
-
-func TestStringOnStack(t *testing.T) {
-	s := ""
-	for i := 0; i < 3; i++ {
-		s = "a" + s + "b" + s + "c"
-	}
-
-	if want := "aaabcbabccbaabcbabccc"; s != want {
-		t.Fatalf("want: '%v', got '%v'", want, s)
-	}
-}
-
-func TestIntString(t *testing.T) {
-	// Non-escaping result of intstring.
-	s := ""
-	for i := 0; i < 4; i++ {
-		s += string(i+'0') + string(i+'0'+1)
-	}
-	if want := "01122334"; s != want {
-		t.Fatalf("want '%v', got '%v'", want, s)
-	}
-
-	// Escaping result of intstring.
-	var a [4]string
-	for i := 0; i < 4; i++ {
-		a[i] = string(i + '0')
-	}
-	s = a[0] + a[1] + a[2] + a[3]
-	if want := "0123"; s != want {
-		t.Fatalf("want '%v', got '%v'", want, s)
-	}
-}
-
-func TestIntStringAllocs(t *testing.T) {
-	unknown := '0'
-	n := testing.AllocsPerRun(1000, func() {
-		s1 := string(unknown)
-		s2 := string(unknown + 1)
-		if s1 == s2 {
-			t.Fatalf("bad")
-		}
-	})
-	if n != 0 {
-		t.Fatalf("want 0 allocs, got %v", n)
-	}
-}
-
-func TestRangeStringCast(t *testing.T) {
-	s := "abc"
-	n := testing.AllocsPerRun(1000, func() {
-		for i, c := range []byte(s) {
-			if c != s[i] {
-				t.Fatalf("want '%c' at pos %v, got '%c'", s[i], i, c)
-			}
-		}
-	})
-	if n != 0 {
-		t.Fatalf("want 0 allocs, got %v", n)
-	}
-}
diff --git a/src/runtime/stubs.go b/src/runtime/stubs.go
index d725bb1..fe8f9c9 100644
--- a/src/runtime/stubs.go
+++ b/src/runtime/stubs.go
@@ -8,9 +8,8 @@ import "unsafe"
 
 // Declarations for runtime services implemented in C or assembly.
 
-const ptrSize = 4 << (^uintptr(0) >> 63)             // unsafe.Sizeof(uintptr(0)) but an ideal const
-const regSize = 4 << (^uintreg(0) >> 63)             // unsafe.Sizeof(uintreg(0)) but an ideal const
-const spAlign = 1*(1-goarch_arm64) + 16*goarch_arm64 // SP alignment: 1 normally, 16 for ARM64
+const ptrSize = 4 << (^uintptr(0) >> 63) // unsafe.Sizeof(uintptr(0)) but an ideal const
+const regSize = 4 << (^uintreg(0) >> 63) // unsafe.Sizeof(uintreg(0)) but an ideal const
 
 // Should be a built-in for unsafe.Pointer?
 //go:nosplit
@@ -18,10 +17,18 @@ func add(p unsafe.Pointer, x uintptr) unsafe.Pointer {
 	return unsafe.Pointer(uintptr(p) + x)
 }
 
-// getg returns the pointer to the current g.
-// The compiler rewrites calls to this function into instructions
-// that fetch the g directly (from TLS or from the dedicated register).
+// n must be a power of 2
+func roundup(p unsafe.Pointer, n uintptr) unsafe.Pointer {
+	delta := -uintptr(p) & (n - 1)
+	return unsafe.Pointer(uintptr(p) + delta)
+}
+
+// in runtime.c
 func getg() *g
+func acquirem() *m
+func releasem(mp *m)
+func gomcache() *mcache
+func readgstatus(*g) uint32 // proc.c
 
 // mcall switches from the g to the g0 stack and invokes fn(g),
 // where g is the goroutine that made the call.
@@ -33,55 +40,103 @@ func getg() *g
 // run other goroutines.
 //
 // mcall can only be called from g stacks (not g0, not gsignal).
-//
-// This must NOT be go:noescape: if fn is a stack-allocated closure,
-// fn puts g on a run queue, and g executes before fn returns, the
-// closure will be invalidated while it is still executing.
+//go:noescape
 func mcall(fn func(*g))
 
-// systemstack runs fn on a system stack.
-// If systemstack is called from the per-OS-thread (g0) stack, or
-// if systemstack is called from the signal handling (gsignal) stack,
-// systemstack calls fn directly and returns.
-// Otherwise, systemstack is being called from the limited stack
-// of an ordinary goroutine. In this case, systemstack switches
-// to the per-OS-thread stack, calls fn, and switches back.
-// It is common to use a func literal as the argument, in order
-// to share inputs and outputs with the code around the call
-// to system stack:
+// onM switches from the g to the g0 stack and invokes fn().
+// When fn returns, onM switches back to the g and returns,
+// continuing execution on the g stack.
+// If arguments must be passed to fn, they can be written to
+// g->m->ptrarg (pointers) and g->m->scalararg (non-pointers)
+// before the call and then consulted during fn.
+// Similarly, fn can pass return values back in those locations.
+// If fn is written in Go, it can be a closure, which avoids the need for
+// ptrarg and scalararg entirely.
+// After reading values out of ptrarg and scalararg it is conventional
+// to zero them to avoid (memory or information) leaks.
+//
+// If onM is called from a g0 stack, it invokes fn and returns,
+// without any stack switches.
+//
+// If onM is called from a gsignal stack, it crashes the program.
+// The implication is that functions used in signal handlers must
+// not use onM.
 //
-//	... set up y ...
-//	systemstack(func() {
-//		x = bigcall(y)
-//	})
-//	... use x ...
+// NOTE(rsc): We could introduce a separate onMsignal that is
+// like onM but if called from a gsignal stack would just run fn on
+// that stack. The caller of onMsignal would be required to save the
+// old values of ptrarg/scalararg and restore them when the call
+// was finished, in case the signal interrupted an onM sequence
+// in progress on the g or g0 stacks. Until there is a clear need for this,
+// we just reject onM in signal handling contexts entirely.
 //
 //go:noescape
-func systemstack(fn func())
+func onM(fn func())
+
+// onMsignal is like onM but is allowed to be used in code that
+// might run on the gsignal stack. Code running on a signal stack
+// may be interrupting an onM sequence on the main stack, so
+// if the onMsignal calling sequence writes to ptrarg/scalararg,
+// it must first save the old values and then restore them when
+// finished. As an exception to the rule, it is fine not to save and
+// restore the values if the program is trying to crash rather than
+// return from the signal handler.
+// Once all the runtime is written in Go, there will be no ptrarg/scalararg
+// and the distinction between onM and onMsignal (and perhaps mcall)
+// can go away.
+//
+// If onMsignal is called from a gsignal stack, it invokes fn directly,
+// without a stack switch. Otherwise onMsignal behaves like onM.
+//
+//go:noescape
+func onM_signalok(fn func())
 
-func badsystemstack() {
-	throw("systemstack called from unexpected goroutine")
+func badonm() {
+	gothrow("onM called from signal goroutine")
 }
 
+// C functions that run on the M stack.
+// Call using mcall.
+func gosched_m(*g)
+func park_m(*g)
+func recovery_m(*g)
+
+// More C functions that run on the M stack.
+// Call using onM.
+func mcacheRefill_m()
+func largeAlloc_m()
+func gc_m()
+func scavenge_m()
+func setFinalizer_m()
+func removeFinalizer_m()
+func markallocated_m()
+func unrollgcprog_m()
+func unrollgcproginplace_m()
+func setgcpercent_m()
+func setmaxthreads_m()
+func ready_m()
+func deferproc_m()
+func goexit_m()
+func startpanic_m()
+func dopanic_m()
+func readmemstats_m()
+func writeheapdump_m()
+
 // memclr clears n bytes starting at ptr.
 // in memclr_*.s
 //go:noescape
 func memclr(ptr unsafe.Pointer, n uintptr)
 
-//go:linkname reflect_memclr reflect.memclr
-func reflect_memclr(ptr unsafe.Pointer, n uintptr) {
-	memclr(ptr, n)
-}
-
 // memmove copies n bytes from "from" to "to".
 // in memmove_*.s
 //go:noescape
-func memmove(to, from unsafe.Pointer, n uintptr)
+func memmove(to unsafe.Pointer, from unsafe.Pointer, n uintptr)
 
-//go:linkname reflect_memmove reflect.memmove
-func reflect_memmove(to, from unsafe.Pointer, n uintptr) {
-	memmove(to, from, n)
-}
+func starttheworld()
+func stoptheworld()
+func newextram()
+func lockOSThread()
+func unlockOSThread()
 
 // exported value for testing
 var hashLoad = loadFactor
@@ -104,9 +159,16 @@ func noescape(p unsafe.Pointer) unsafe.Pointer {
 	return unsafe.Pointer(x ^ 0)
 }
 
+func entersyscall()
+func reentersyscall(pc uintptr, sp unsafe.Pointer)
+func entersyscallblock()
+func exitsyscall()
+
 func cgocallback(fn, frame unsafe.Pointer, framesize uintptr)
 func gogo(buf *gobuf)
 func gosave(buf *gobuf)
+func read(fd int32, p unsafe.Pointer, n int32) int32
+func close(fd int32) int32
 func mincore(addr unsafe.Pointer, n uintptr, dst *byte) int32
 
 //go:noescape
@@ -114,50 +176,35 @@ func jmpdefer(fv *funcval, argp uintptr)
 func exit1(code int32)
 func asminit()
 func setg(gg *g)
+func exit(code int32)
 func breakpoint()
-
-// reflectcall calls fn with a copy of the n argument bytes pointed at by arg.
-// After fn returns, reflectcall copies n-retoffset result bytes
-// back into arg+retoffset before returning. If copying result bytes back,
-// the caller should pass the argument frame type as argtype, so that
-// call can execute appropriate write barriers during the copy.
-// Package reflect passes a frame type. In package runtime, there is only
-// one call that copies results back, in cgocallbackg1, and it does NOT pass a
-// frame type, meaning there are no write barriers invoked. See that call
-// site for justification.
-func reflectcall(argtype *_type, fn, arg unsafe.Pointer, argsize uint32, retoffset uint32)
-
+func nanotime() int64
+func usleep(usec uint32)
+
+// careful: cputicks is not guaranteed to be monotonic!  In particular, we have
+// noticed drift between cpus on certain os/arch combinations.  See issue 8976.
+func cputicks() int64
+
+func mmap(addr unsafe.Pointer, n uintptr, prot, flags, fd int32, off uint32) unsafe.Pointer
+func munmap(addr unsafe.Pointer, n uintptr)
+func madvise(addr unsafe.Pointer, n uintptr, flags int32)
+func reflectcall(fn, arg unsafe.Pointer, n uint32, retoffset uint32)
+func osyield()
 func procyield(cycles uint32)
+func cgocallback_gofunc(fv *funcval, frame unsafe.Pointer, framesize uintptr)
+func readgogc() int32
+func purgecachedstats(c *mcache)
+func gostringnocopy(b *byte) string
+func goexit()
 
-type neverCallThisFunction struct{}
-
-// goexit is the return stub at the top of every goroutine call stack.
-// Each goroutine stack is constructed as if goexit called the
-// goroutine's entry point function, so that when the entry point
-// function returns, it will return to goexit, which will call goexit1
-// to perform the actual exit.
-//
-// This function must never be called directly. Call goexit1 instead.
-// gentraceback assumes that goexit terminates the stack. A direct
-// call on the stack will cause gentraceback to stop walking the stack
-// prematurely and if there are leftover stack barriers it may panic.
-func goexit(neverCallThisFunction)
-
-// Not all cgocallback_gofunc frames are actually cgocallback_gofunc,
-// so not all have these arguments. Mark them uintptr so that the GC
-// does not misinterpret memory when the arguments are not present.
-// cgocallback_gofunc is not called from go, only from cgocallback,
-// so the arguments will be found via cgocallback's pointer-declared arguments.
-// See the assembly implementations for more details.
-func cgocallback_gofunc(fv uintptr, frame uintptr, framesize uintptr)
+//go:noescape
+func write(fd uintptr, p unsafe.Pointer, n int32) int32
 
 //go:noescape
 func cas(ptr *uint32, old, new uint32) bool
 
-// NO go:noescape annotation; see atomic_pointer.go.
-func casp1(ptr *unsafe.Pointer, old, new unsafe.Pointer) bool
-
-func nop() // call to prevent inlining of function body
+//go:noescape
+func casp(ptr *unsafe.Pointer, old, new unsafe.Pointer) bool
 
 //go:noescape
 func casuintptr(ptr *uintptr, old, new uintptr) bool
@@ -171,39 +218,6 @@ func atomicloaduintptr(ptr *uintptr) uintptr
 //go:noescape
 func atomicloaduint(ptr *uint) uint
 
-// TODO: Write native implementations of int64 atomic ops (or improve
-// inliner). These portable ones can't be inlined right now, so we're
-// taking an extra function call hit.
-
-func atomicstoreint64(ptr *int64, new int64) {
-	atomicstore64((*uint64)(unsafe.Pointer(ptr)), uint64(new))
-}
-
-func atomicloadint64(ptr *int64) int64 {
-	return int64(atomicload64((*uint64)(unsafe.Pointer(ptr))))
-}
-
-func xaddint64(ptr *int64, delta int64) int64 {
-	return int64(xadd64((*uint64)(unsafe.Pointer(ptr)), delta))
-}
-
-// publicationBarrier performs a store/store barrier (a "publication"
-// or "export" barrier). Some form of synchronization is required
-// between initializing an object and making that object accessible to
-// another processor. Without synchronization, the initialization
-// writes and the "publication" write may be reordered, allowing the
-// other processor to follow the pointer and observe an uninitialized
-// object. In general, higher-level synchronization should be used,
-// such as locking or an atomic pointer write. publicationBarrier is
-// for when those aren't an option, such as in the implementation of
-// the memory manager.
-//
-// There's no corresponding barrier for the read side because the read
-// side naturally has a data dependency order. All architectures that
-// Go supports or seems likely to ever support automatically enforce
-// data dependency ordering.
-func publicationBarrier()
-
 //go:noescape
 func setcallerpc(argp unsafe.Pointer, pc uintptr)
 
@@ -217,7 +231,7 @@ func setcallerpc(argp unsafe.Pointer, pc uintptr)
 //
 //	func f(arg1, arg2, arg3 int) {
 //		pc := getcallerpc(unsafe.Pointer(&arg1))
-//		sp := getcallersp(unsafe.Pointer(&arg1))
+//		sp := getcallerpc(unsafe.Pointer(&arg2))
 //	}
 //
 // These two lines find the PC and SP immediately following
@@ -242,21 +256,25 @@ func getcallerpc(argp unsafe.Pointer) uintptr
 func getcallersp(argp unsafe.Pointer) uintptr
 
 //go:noescape
-func asmcgocall(fn, arg unsafe.Pointer) int32
+func asmcgocall(fn, arg unsafe.Pointer)
+
+//go:noescape
+func asmcgocall_errno(fn, arg unsafe.Pointer) int32
+
+//go:noescape
+func open(name *byte, mode, perm int32) int32
+
+//go:noescape
+func gotraceback(*bool) int32
 
-// argp used in Defer structs when there is no argp.
 const _NoArgs = ^uintptr(0)
 
+func newstack()
+func newproc()
 func morestack()
+func mstart()
 func rt0_go()
 
-// stackBarrier records that the stack has been unwound past a certain
-// point. It is installed over a return PC on the stack. It must
-// retrieve the original return PC from g.stkbuf, increment
-// g.stkbufPos to record that the barrier was hit, and jump to the
-// original return PC.
-func stackBarrier()
-
 // return0 is a stub used to return 0 from deferproc.
 // It is called at the very end of deferproc to signal
 // the calling Go function that it should not jump
@@ -264,11 +282,12 @@ func stackBarrier()
 // in asm_*.s
 func return0()
 
-//go:linkname time_now time.now
-func time_now() (sec int64, nsec int32)
+// thunk to call time.now.
+func timenow() (sec int64, nsec int32)
 
 // in asm_*.s
 // not called directly; definitions here supply type information for traceback.
+func call16(fn, arg unsafe.Pointer, n, retoffset uint32)
 func call32(fn, arg unsafe.Pointer, n, retoffset uint32)
 func call64(fn, arg unsafe.Pointer, n, retoffset uint32)
 func call128(fn, arg unsafe.Pointer, n, retoffset uint32)
@@ -295,20 +314,3 @@ func call134217728(fn, arg unsafe.Pointer, n, retoffset uint32)
 func call268435456(fn, arg unsafe.Pointer, n, retoffset uint32)
 func call536870912(fn, arg unsafe.Pointer, n, retoffset uint32)
 func call1073741824(fn, arg unsafe.Pointer, n, retoffset uint32)
-
-func systemstack_switch()
-
-func prefetcht0(addr uintptr)
-func prefetcht1(addr uintptr)
-func prefetcht2(addr uintptr)
-func prefetchnta(addr uintptr)
-
-func unixnanotime() int64 {
-	sec, nsec := time_now()
-	return sec*1e9 + int64(nsec)
-}
-
-// round n up to a multiple of a.  a must be a power of 2.
-func round(n, a uintptr) uintptr {
-	return (n + a - 1) &^ (a - 1)
-}
diff --git a/src/runtime/symtab.go b/src/runtime/symtab.go
index 400ab6d..45d107b 100644
--- a/src/runtime/symtab.go
+++ b/src/runtime/symtab.go
@@ -22,149 +22,81 @@ func (f *Func) raw() *_func {
 
 // funcdata.h
 const (
-	_PCDATA_StackMapIndex       = 0
+	_PCDATA_ArgSize             = 0
+	_PCDATA_StackMapIndex       = 1
 	_FUNCDATA_ArgsPointerMaps   = 0
 	_FUNCDATA_LocalsPointerMaps = 1
 	_FUNCDATA_DeadValueMaps     = 2
 	_ArgsSizeUnknown            = -0x80000000
 )
 
-// moduledata records information about the layout of the executable
-// image. It is written by the linker. Any changes here must be
-// matched changes to the code in cmd/internal/ld/symtab.go:symtab.
-// moduledata is stored in read-only memory; none of the pointers here
-// are visible to the garbage collector.
-type moduledata struct {
-	pclntable    []byte
-	ftab         []functab
-	filetab      []uint32
-	findfunctab  uintptr
-	minpc, maxpc uintptr
-
-	text, etext           uintptr
-	noptrdata, enoptrdata uintptr
-	data, edata           uintptr
-	bss, ebss             uintptr
-	noptrbss, enoptrbss   uintptr
-	end, gcdata, gcbss    uintptr
-
-	typelinks []*_type
-
-	modulename   string
-	modulehashes []modulehash
-
-	gcdatamask, gcbssmask bitvector
-
-	next *moduledata
-}
-
-// For each shared library a module links against, the linker creates an entry in the
-// moduledata.modulehashes slice containing the name of the module, the abi hash seen
-// at link time and a pointer to the runtime abi hash. These are checked in
-// moduledataverify1 below.
-type modulehash struct {
-	modulename   string
-	linktimehash string
-	runtimehash  *string
-}
+var (
+	pclntable []byte
+	ftab      []functab
+	filetab   []uint32
 
-var firstmoduledata moduledata  // linker symbol
-var lastmoduledatap *moduledata // linker symbol
+	pclntab, epclntab struct{} // linker symbols
+)
 
 type functab struct {
 	entry   uintptr
 	funcoff uintptr
 }
 
-const minfunc = 16                 // minimum function size
-const pcbucketsize = 256 * minfunc // size of bucket in the pc->func lookup table
-
-// findfunctab is an array of these structures.
-// Each bucket represents 4096 bytes of the text segment.
-// Each subbucket represents 256 bytes of the text segment.
-// To find a function given a pc, locate the bucket and subbucket for
-// that pc.  Add together the idx and subbucket value to obtain a
-// function index.  Then scan the functab array starting at that
-// index to find the target function.
-// This table uses 20 bytes for every 4096 bytes of code, or ~0.5% overhead.
-type findfuncbucket struct {
-	idx        uint32
-	subbuckets [16]byte
-}
-
-func moduledataverify() {
-	for datap := &firstmoduledata; datap != nil; datap = datap.next {
-		moduledataverify1(datap)
-	}
-}
-
-const debugPcln = false
-
-func moduledataverify1(datap *moduledata) {
+func symtabinit() {
 	// 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.
-	pcln := *(**[8]byte)(unsafe.Pointer(&datap.pclntable))
-	pcln32 := *(**[2]uint32)(unsafe.Pointer(&datap.pclntable))
+	pcln := (*[8]byte)(unsafe.Pointer(&pclntab))
+	pcln32 := (*[2]uint32)(unsafe.Pointer(&pclntab))
 	if pcln32[0] != 0xfffffffb || pcln[4] != 0 || pcln[5] != 0 || pcln[6] != _PCQuantum || pcln[7] != ptrSize {
 		println("runtime: function symbol table header:", hex(pcln32[0]), hex(pcln[4]), hex(pcln[5]), hex(pcln[6]), hex(pcln[7]))
-		throw("invalid function symbol table\n")
+		gothrow("invalid function symbol table\n")
 	}
 
+	// pclntable is all bytes of pclntab symbol.
+	sp := (*sliceStruct)(unsafe.Pointer(&pclntable))
+	sp.array = unsafe.Pointer(&pclntab)
+	sp.len = int(uintptr(unsafe.Pointer(&epclntab)) - uintptr(unsafe.Pointer(&pclntab)))
+	sp.cap = sp.len
+
 	// ftab is lookup table for function by program counter.
-	nftab := len(datap.ftab) - 1
+	nftab := int(*(*uintptr)(add(unsafe.Pointer(pcln), 8)))
+	p := add(unsafe.Pointer(pcln), 8+ptrSize)
+	sp = (*sliceStruct)(unsafe.Pointer(&ftab))
+	sp.array = p
+	sp.len = nftab + 1
+	sp.cap = sp.len
 	for i := 0; i < nftab; i++ {
 		// NOTE: ftab[nftab].entry is legal; it is the address beyond the final function.
-		if datap.ftab[i].entry > datap.ftab[i+1].entry {
-			f1 := (*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i].funcoff]))
-			f2 := (*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i+1].funcoff]))
+		if ftab[i].entry > ftab[i+1].entry {
+			f1 := (*_func)(unsafe.Pointer(&pclntable[ftab[i].funcoff]))
+			f2 := (*_func)(unsafe.Pointer(&pclntable[ftab[i+1].funcoff]))
 			f2name := "end"
 			if i+1 < nftab {
-				f2name = funcname(f2)
+				f2name = gofuncname(f2)
 			}
-			println("function symbol table not sorted by program counter:", hex(datap.ftab[i].entry), funcname(f1), ">", hex(datap.ftab[i+1].entry), f2name)
+			println("function symbol table not sorted by program counter:", hex(ftab[i].entry), gofuncname(f1), ">", hex(ftab[i+1].entry), f2name)
 			for j := 0; j <= i; j++ {
-				print("\t", hex(datap.ftab[j].entry), " ", funcname((*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[j].funcoff]))), "\n")
-			}
-			throw("invalid runtime symbol table")
-		}
-
-		if debugPcln || nftab-i < 5 {
-			// Check a PC near but not at the very end.
-			// The very end might be just padding that is not covered by the tables.
-			// No architecture rounds function entries to more than 16 bytes,
-			// but if one came along we'd need to subtract more here.
-			// But don't use the next PC if it corresponds to a foreign object chunk
-			// (no pcln table, f2.pcln == 0). That chunk might have an alignment
-			// more than 16 bytes.
-			f := (*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i].funcoff]))
-			end := f.entry
-			if i+1 < nftab {
-				f2 := (*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i+1].funcoff]))
-				if f2.pcln != 0 {
-					end = f2.entry - 16
-					if end < f.entry {
-						end = f.entry
-					}
-				}
+				print("\t", hex(ftab[j].entry), " ", gofuncname((*_func)(unsafe.Pointer(&pclntable[ftab[j].funcoff]))))
 			}
-			pcvalue(f, f.pcfile, end, true)
-			pcvalue(f, f.pcln, end, true)
-			pcvalue(f, f.pcsp, end, true)
+			gothrow("invalid runtime symbol table")
 		}
 	}
 
-	if datap.minpc != datap.ftab[0].entry ||
-		datap.maxpc != datap.ftab[nftab].entry {
-		throw("minpc or maxpc invalid")
-	}
-
-	for _, modulehash := range datap.modulehashes {
-		if modulehash.linktimehash != *modulehash.runtimehash {
-			println("abi mismatch detected between", datap.modulename, "and", modulehash.modulename)
-			throw("abi mismatch")
-		}
-	}
+	// The ftab ends with a half functab consisting only of
+	// 'entry', followed by a uint32 giving the pcln-relative
+	// offset of the file table.
+	sp = (*sliceStruct)(unsafe.Pointer(&filetab))
+	end := unsafe.Pointer(&ftab[nftab].funcoff) // just beyond ftab
+	fileoffset := *(*uint32)(end)
+	sp.array = unsafe.Pointer(&pclntable[fileoffset])
+	// length is in first element of array.
+	// set len to 1 so we can get first element.
+	sp.len = 1
+	sp.cap = 1
+	sp.len = int(filetab[0])
+	sp.cap = sp.len
 }
 
 // FuncForPC returns a *Func describing the function that contains the
@@ -175,7 +107,7 @@ func FuncForPC(pc uintptr) *Func {
 
 // Name returns the name of the function.
 func (f *Func) Name() string {
-	return funcname(f.raw())
+	return gofuncname(f.raw())
 }
 
 // Entry returns the entry address of the function.
@@ -190,56 +122,44 @@ func (f *Func) Entry() uintptr {
 func (f *Func) FileLine(pc uintptr) (file string, line int) {
 	// Pass strict=false here, because anyone can call this function,
 	// and they might just be wrong about targetpc belonging to f.
-	file, line32 := funcline1(f.raw(), pc, false)
-	return file, int(line32)
-}
-
-func findmoduledatap(pc uintptr) *moduledata {
-	for datap := &firstmoduledata; datap != nil; datap = datap.next {
-		if datap.minpc <= pc && pc <= datap.maxpc {
-			return datap
-		}
-	}
-	return nil
+	line = int(funcline1(f.raw(), pc, &file, false))
+	return file, line
 }
 
 func findfunc(pc uintptr) *_func {
-	datap := findmoduledatap(pc)
-	if datap == nil {
+	if len(ftab) == 0 {
 		return nil
 	}
-	const nsub = uintptr(len(findfuncbucket{}.subbuckets))
-
-	x := pc - datap.minpc
-	b := x / pcbucketsize
-	i := x % pcbucketsize / (pcbucketsize / nsub)
 
-	ffb := (*findfuncbucket)(add(unsafe.Pointer(datap.findfunctab), b*unsafe.Sizeof(findfuncbucket{})))
-	idx := ffb.idx + uint32(ffb.subbuckets[i])
-	if pc < datap.ftab[idx].entry {
-		throw("findfunc: bad findfunctab entry")
+	if pc < ftab[0].entry || pc >= ftab[len(ftab)-1].entry {
+		return nil
 	}
 
-	// linear search to find func with pc >= entry.
-	for datap.ftab[idx+1].entry <= pc {
-		idx++
+	// binary search to find func with entry <= pc.
+	lo := 0
+	nf := len(ftab) - 1 // last entry is sentinel
+	for nf > 0 {
+		n := nf / 2
+		f := &ftab[lo+n]
+		if f.entry <= pc && pc < ftab[lo+n+1].entry {
+			return (*_func)(unsafe.Pointer(&pclntable[f.funcoff]))
+		} else if pc < f.entry {
+			nf = n
+		} else {
+			lo += n + 1
+			nf -= n + 1
+		}
 	}
-	return (*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[idx].funcoff]))
+
+	gothrow("findfunc: binary search failed")
+	return nil
 }
 
 func pcvalue(f *_func, off int32, targetpc uintptr, strict bool) int32 {
 	if off == 0 {
 		return -1
 	}
-	datap := findmoduledatap(f.entry) // inefficient
-	if datap == nil {
-		if strict && panicking == 0 {
-			print("runtime: no module data for ", hex(f.entry), "\n")
-			throw("no module data")
-		}
-		return -1
-	}
-	p := datap.pclntable[off:]
+	p := pclntable[off:]
 	pc := f.entry
 	val := int32(-1)
 	for {
@@ -259,9 +179,9 @@ func pcvalue(f *_func, off int32, targetpc uintptr, strict bool) int32 {
 		return -1
 	}
 
-	print("runtime: invalid pc-encoded table f=", funcname(f), " pc=", hex(pc), " targetpc=", hex(targetpc), " tab=", p, "\n")
+	print("runtime: invalid pc-encoded table f=", gofuncname(f), " pc=", hex(pc), " targetpc=", hex(targetpc), " tab=", p, "\n")
 
-	p = datap.pclntable[off:]
+	p = pclntable[off:]
 	pc = f.entry
 	val = -1
 	for {
@@ -273,48 +193,41 @@ func pcvalue(f *_func, off int32, targetpc uintptr, strict bool) int32 {
 		print("\tvalue=", val, " until pc=", hex(pc), "\n")
 	}
 
-	throw("invalid runtime symbol table")
+	gothrow("invalid runtime symbol table")
 	return -1
 }
 
-func cfuncname(f *_func) *byte {
+func funcname(f *_func) *byte {
 	if f == nil || f.nameoff == 0 {
 		return nil
 	}
-	datap := findmoduledatap(f.entry) // inefficient
-	if datap == nil {
-		return nil
-	}
-	return (*byte)(unsafe.Pointer(&datap.pclntable[f.nameoff]))
+	return (*byte)(unsafe.Pointer(&pclntable[f.nameoff]))
 }
 
-func funcname(f *_func) string {
-	return gostringnocopy(cfuncname(f))
+func gofuncname(f *_func) string {
+	return gostringnocopy(funcname(f))
 }
 
-func funcline1(f *_func, targetpc uintptr, strict bool) (file string, line int32) {
-	datap := findmoduledatap(f.entry) // inefficient
-	if datap == nil {
-		return "?", 0
-	}
+func funcline1(f *_func, targetpc uintptr, file *string, strict bool) int32 {
+	*file = "?"
 	fileno := int(pcvalue(f, f.pcfile, targetpc, strict))
-	line = pcvalue(f, f.pcln, targetpc, strict)
-	if fileno == -1 || line == -1 || fileno >= len(datap.filetab) {
-		// print("looking for ", hex(targetpc), " in ", funcname(f), " got file=", fileno, " line=", lineno, "\n")
-		return "?", 0
+	line := pcvalue(f, f.pcln, targetpc, strict)
+	if fileno == -1 || line == -1 || fileno >= len(filetab) {
+		// print("looking for ", hex(targetpc), " in ", gofuncname(f), " got file=", fileno, " line=", lineno, "\n")
+		return 0
 	}
-	file = gostringnocopy(&datap.pclntable[datap.filetab[fileno]])
-	return
+	*file = gostringnocopy(&pclntable[filetab[fileno]])
+	return line
 }
 
-func funcline(f *_func, targetpc uintptr) (file string, line int32) {
-	return funcline1(f, targetpc, true)
+func funcline(f *_func, targetpc uintptr, file *string) int32 {
+	return funcline1(f, targetpc, file, true)
 }
 
 func funcspdelta(f *_func, targetpc uintptr) int32 {
 	x := pcvalue(f, f.pcsp, targetpc, true)
 	if x&(ptrSize-1) != 0 {
-		print("invalid spdelta ", funcname(f), " ", hex(f.entry), " ", hex(targetpc), " ", hex(f.pcsp), " ", x, "\n")
+		print("invalid spdelta ", hex(f.entry), " ", hex(targetpc), " ", hex(f.pcsp), " ", x, "\n")
 	}
 	return x
 }
@@ -373,17 +286,3 @@ func readvarint(p []byte) (newp []byte, val uint32) {
 	}
 	return p, v
 }
-
-type stackmap struct {
-	n        int32   // number of bitmaps
-	nbit     int32   // number of bits in each bitmap
-	bytedata [1]byte // bitmaps, each starting on a 32-bit boundary
-}
-
-//go:nowritebarrier
-func stackmapdata(stkmap *stackmap, n int32) bitvector {
-	if n < 0 || n >= stkmap.n {
-		throw("stackmapdata: index out of range")
-	}
-	return bitvector{stkmap.nbit, (*byte)(add(unsafe.Pointer(&stkmap.bytedata), uintptr(n*((stkmap.nbit+31)/32*4))))}
-}
diff --git a/src/runtime/symtab_test.go b/src/runtime/symtab_test.go
index b15a2e9..bd9fe18 100644
--- a/src/runtime/symtab_test.go
+++ b/src/runtime/symtab_test.go
@@ -45,108 +45,3 @@ func testCallerBar(t *testing.T) {
 		}
 	}
 }
-
-func lineNumber() int {
-	_, _, line, _ := runtime.Caller(1)
-	return line // return 0 for error
-}
-
-// Do not add/remove lines in this block without updating the line numbers.
-var firstLine = lineNumber() // 0
-var (                        // 1
-	lineVar1             = lineNumber()               // 2
-	lineVar2a, lineVar2b = lineNumber(), lineNumber() // 3
-)                        // 4
-var compLit = []struct { // 5
-	lineA, lineB int // 6
-}{ // 7
-	{ // 8
-		lineNumber(), lineNumber(), // 9
-	}, // 10
-	{ // 11
-		lineNumber(), // 12
-		lineNumber(), // 13
-	}, // 14
-	{ // 15
-		lineB: lineNumber(), // 16
-		lineA: lineNumber(), // 17
-	}, // 18
-}                                     // 19
-var arrayLit = [...]int{lineNumber(), // 20
-	lineNumber(), lineNumber(), // 21
-	lineNumber(), // 22
-}                                  // 23
-var sliceLit = []int{lineNumber(), // 24
-	lineNumber(), lineNumber(), // 25
-	lineNumber(), // 26
-}                         // 27
-var mapLit = map[int]int{ // 28
-	29:           lineNumber(), // 29
-	30:           lineNumber(), // 30
-	lineNumber(): 31,           // 31
-	lineNumber(): 32,           // 32
-}                           // 33
-var intLit = lineNumber() + // 34
-	lineNumber() + // 35
-			lineNumber() // 36
-func trythis() { // 37
-	recordLines(lineNumber(), // 38
-		lineNumber(), // 39
-		lineNumber()) // 40
-}
-
-// Modifications below this line are okay.
-
-var l38, l39, l40 int
-
-func recordLines(a, b, c int) {
-	l38 = a
-	l39 = b
-	l40 = c
-}
-
-func TestLineNumber(t *testing.T) {
-	trythis()
-	for _, test := range []struct {
-		name string
-		val  int
-		want int
-	}{
-		{"firstLine", firstLine, 0},
-		{"lineVar1", lineVar1, 2},
-		{"lineVar2a", lineVar2a, 3},
-		{"lineVar2b", lineVar2b, 3},
-		{"compLit[0].lineA", compLit[0].lineA, 9},
-		{"compLit[0].lineB", compLit[0].lineB, 9},
-		{"compLit[1].lineA", compLit[1].lineA, 12},
-		{"compLit[1].lineB", compLit[1].lineB, 13},
-		{"compLit[2].lineA", compLit[2].lineA, 17},
-		{"compLit[2].lineB", compLit[2].lineB, 16},
-
-		{"arrayLit[0]", arrayLit[0], 20},
-		{"arrayLit[1]", arrayLit[1], 21},
-		{"arrayLit[2]", arrayLit[2], 21},
-		{"arrayLit[3]", arrayLit[3], 22},
-
-		{"sliceLit[0]", sliceLit[0], 24},
-		{"sliceLit[1]", sliceLit[1], 25},
-		{"sliceLit[2]", sliceLit[2], 25},
-		{"sliceLit[3]", sliceLit[3], 26},
-
-		{"mapLit[29]", mapLit[29], 29},
-		{"mapLit[30]", mapLit[30], 30},
-		{"mapLit[31]", mapLit[31+firstLine] + firstLine, 31}, // nb it's the key not the value
-		{"mapLit[32]", mapLit[32+firstLine] + firstLine, 32}, // nb it's the key not the value
-
-		{"intLit", intLit - 2*firstLine, 34 + 35 + 36},
-
-		{"l38", l38, 38},
-		{"l39", l39, 39},
-		{"l40", l40, 40},
-	} {
-		if got := test.val - firstLine; got != test.want {
-			t.Errorf("%s on firstLine+%d want firstLine+%d (firstLine=%d, val=%d)",
-				test.name, got, test.want, firstLine, test.val)
-		}
-	}
-}
diff --git a/src/runtime/sys_arm.c b/src/runtime/sys_arm.c
new file mode 100644
index 0000000..a65560e
--- /dev/null
+++ b/src/runtime/sys_arm.c
@@ -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.
+
+#include "runtime.h"
+
+// adjust Gobuf as if it executed a call to fn with context ctxt
+// and then did an immediate Gosave.
+void
+runtime·gostartcall(Gobuf *gobuf, void (*fn)(void), void *ctxt)
+{
+	if(gobuf->lr != 0)
+		runtime·throw("invalid use of gostartcall");
+	gobuf->lr = gobuf->pc;
+	gobuf->pc = (uintptr)fn;
+	gobuf->ctxt = ctxt;
+}
+
+// Called to rewind context saved during morestack back to beginning of function.
+// To help us, the linker emits a jmp back to the beginning right after the
+// call to morestack. We just have to decode and apply that jump.
+void
+runtime·rewindmorestack(Gobuf *gobuf)
+{
+	uint32 inst;
+
+	inst = *(uint32*)gobuf->pc;
+	if((gobuf->pc&3) == 0 && (inst>>24) == 0x9a) {
+		//runtime·printf("runtime: rewind pc=%p to pc=%p\n", gobuf->pc, gobuf->pc + ((int32)(inst<<8)>>6) + 8);
+		gobuf->pc += ((int32)(inst<<8)>>6) + 8;
+		return;
+	}
+	runtime·printf("runtime: pc=%p %x\n", gobuf->pc, inst);
+	runtime·throw("runtime: misuse of rewindmorestack");
+}
diff --git a/src/runtime/sys_darwin_386.s b/src/runtime/sys_darwin_386.s
index abc5d32..a961c71 100644
--- a/src/runtime/sys_darwin_386.s
+++ b/src/runtime/sys_darwin_386.s
@@ -6,8 +6,7 @@
 // See http://fxr.watson.org/fxr/source/bsd/kern/syscalls.c?v=xnu-1228
 // or /usr/include/sys/syscall.h (on a Mac) for system call numbers.
 
-#include "go_asm.h"
-#include "go_tls.h"
+#include "zasm_GOOS_GOARCH.h"
 #include "textflag.h"
 
 // Exit the entire program (like C exit)
@@ -29,41 +28,28 @@ TEXT runtime·exit1(SB),NOSPLIT,$0
 TEXT runtime·open(SB),NOSPLIT,$0
 	MOVL	$5, AX
 	INT	$0x80
-	JAE	2(PC)
-	MOVL	$-1, AX
 	MOVL	AX, ret+12(FP)
 	RET
 
-TEXT runtime·closefd(SB),NOSPLIT,$0
+TEXT runtime·close(SB),NOSPLIT,$0
 	MOVL	$6, AX
 	INT	$0x80
-	JAE	2(PC)
-	MOVL	$-1, AX
 	MOVL	AX, ret+4(FP)
 	RET
 
 TEXT runtime·read(SB),NOSPLIT,$0
 	MOVL	$3, AX
 	INT	$0x80
-	JAE	2(PC)
-	MOVL	$-1, AX
 	MOVL	AX, ret+12(FP)
 	RET
 
 TEXT runtime·write(SB),NOSPLIT,$0
 	MOVL	$4, AX
 	INT	$0x80
-	JAE	2(PC)
-	MOVL	$-1, AX
 	MOVL	AX, ret+12(FP)
 	RET
 
-TEXT runtime·raise(SB),NOSPLIT,$0
-	// Ideally we'd send the signal to the current thread,
-	// not the whole process, but that's too hard on OS X.
-	JMP	runtime·raiseproc(SB)
-
-TEXT runtime·raiseproc(SB),NOSPLIT,$16
+TEXT runtime·raise(SB),NOSPLIT,$16
 	MOVL	$20, AX // getpid
 	INT	$0x80
 	MOVL	AX, 4(SP)	// pid
@@ -221,7 +207,8 @@ TEXT time·now(SB),NOSPLIT,$0
 	MOVL	DX, nsec+8(FP)
 	RET
 
-// func nanotime() int64
+// int64 nanotime(void) so really
+// void nanotime(int64 *nsec)
 TEXT runtime·nanotime(SB),NOSPLIT,$0
 	CALL	runtime·now(SB)
 	MOVL	AX, ret_lo+0(FP)
@@ -261,7 +248,7 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$40
 	MOVL	BX, 0(SP)
 	MOVL	$runtime·badsignal(SB), AX
 	CALL	AX
-	JMP 	ret
+	JMP 	sigtramp_ret
 
 	// save g
 	MOVL	DI, 20(SP)
@@ -288,7 +275,7 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$40
 	MOVL	20(SP), DI
 	MOVL	DI, g(CX)
 
-ret:
+sigtramp_ret:
 	// call sigreturn
 	MOVL	context+16(FP), CX
 	MOVL	style+4(FP), BX
@@ -327,32 +314,33 @@ TEXT runtime·usleep(SB),NOSPLIT,$32
 	INT	$0x80
 	RET
 
-// func bsdthread_create(stk, arg unsafe.Pointer, fn uintptr) int32
+// void bsdthread_create(void *stk, M *mp, G *gp, void (*fn)(void))
 // System call args are: func arg stack pthread flags.
 TEXT runtime·bsdthread_create(SB),NOSPLIT,$32
 	MOVL	$360, AX
 	// 0(SP) is where the caller PC would be; kernel skips it
-	MOVL	fn+8(FP), BX
+	MOVL	fn+12(FP), BX
 	MOVL	BX, 4(SP)	// func
-	MOVL	arg+4(FP), BX
+	MOVL	mm+4(FP), BX
 	MOVL	BX, 8(SP)	// arg
 	MOVL	stk+0(FP), BX
 	MOVL	BX, 12(SP)	// stack
-	MOVL    $0, 16(SP)      // pthread
+	MOVL	gg+8(FP), BX
+	MOVL	BX, 16(SP)	// pthread
 	MOVL	$0x1000000, 20(SP)	// flags = PTHREAD_START_CUSTOM
 	INT	$0x80
 	JAE	4(PC)
 	NEGL	AX
-	MOVL	AX, ret+12(FP)
+	MOVL	AX, ret+16(FP)
 	RET
 	MOVL	$0, AX
-	MOVL	AX, ret+12(FP)
+	MOVL	AX, ret+16(FP)
 	RET
 
 // The thread that bsdthread_create creates starts executing here,
 // because we registered this function using bsdthread_register
 // at startup.
-//	AX = "pthread" (= 0x0)
+//	AX = "pthread" (= g)
 //	BX = mach thread port
 //	CX = "func" (= fn)
 //	DX = "arg" (= m)
@@ -379,7 +367,6 @@ TEXT runtime·bsdthread_start(SB),NOSPLIT,$0
 
 	// Now segment is established.  Initialize m, g.
 	get_tls(BP)
-	MOVL    m_g0(DX), AX
 	MOVL	AX, g(BP)
 	MOVL	DX, g_m(AX)
 	MOVL	BX, m_procid(DX)	// m->procid = thread port (for debuggers)
@@ -388,7 +375,7 @@ TEXT runtime·bsdthread_start(SB),NOSPLIT,$0
 	CALL	runtime·exit1(SB)
 	RET
 
-// func bsdthread_register() int32
+// void bsdthread_register(void)
 // registers callbacks for threadstart (see bsdthread_create above
 // and wqthread and pthsize (not used).  returns 0 on success.
 TEXT runtime·bsdthread_register(SB),NOSPLIT,$40
@@ -447,35 +434,35 @@ TEXT runtime·mach_task_self(SB),NOSPLIT,$0
 // Mach provides trap versions of the semaphore ops,
 // instead of requiring the use of RPC.
 
-// func mach_semaphore_wait(sema uint32) int32
+// uint32 mach_semaphore_wait(uint32)
 TEXT runtime·mach_semaphore_wait(SB),NOSPLIT,$0
 	MOVL	$-36, AX
 	CALL	runtime·sysenter(SB)
 	MOVL	AX, ret+4(FP)
 	RET
 
-// func mach_semaphore_timedwait(sema, sec, nsec uint32) int32
+// uint32 mach_semaphore_timedwait(uint32, uint32, uint32)
 TEXT runtime·mach_semaphore_timedwait(SB),NOSPLIT,$0
 	MOVL	$-38, AX
 	CALL	runtime·sysenter(SB)
 	MOVL	AX, ret+12(FP)
 	RET
 
-// func mach_semaphore_signal(sema uint32) int32
+// uint32 mach_semaphore_signal(uint32)
 TEXT runtime·mach_semaphore_signal(SB),NOSPLIT,$0
 	MOVL	$-33, AX
 	CALL	runtime·sysenter(SB)
 	MOVL	AX, ret+4(FP)
 	RET
 
-// func mach_semaphore_signal_all(sema uint32) int32
+// uint32 mach_semaphore_signal_all(uint32)
 TEXT runtime·mach_semaphore_signal_all(SB),NOSPLIT,$0
 	MOVL	$-34, AX
 	CALL	runtime·sysenter(SB)
 	MOVL	AX, ret+4(FP)
 	RET
 
-// func setldt(entry int, address int, limit int)
+// setldt(int entry, int address, int limit)
 // entry and limit are ignored.
 TEXT runtime·setldt(SB),NOSPLIT,$32
 	MOVL	address+4(FP), BX	// aka base
@@ -522,7 +509,7 @@ TEXT runtime·sysctl(SB),NOSPLIT,$0
 	MOVL	AX, ret+24(FP)
 	RET
 
-// func kqueue() int32
+// int32 runtime·kqueue(void);
 TEXT runtime·kqueue(SB),NOSPLIT,$0
 	MOVL	$362, AX
 	INT	$0x80
@@ -531,7 +518,7 @@ TEXT runtime·kqueue(SB),NOSPLIT,$0
 	MOVL	AX, ret+0(FP)
 	RET
 
-// func kevent(kq int32, ch *keventt, nch int32, ev *keventt, nev int32, ts *timespec) int32
+// int32 runtime·kevent(int kq, Kevent *changelist, int nchanges, Kevent *eventlist, int nevents, Timespec *timeout);
 TEXT runtime·kevent(SB),NOSPLIT,$0
 	MOVL	$363, AX
 	INT	$0x80
@@ -540,7 +527,7 @@ TEXT runtime·kevent(SB),NOSPLIT,$0
 	MOVL	AX, ret+24(FP)
 	RET
 
-// func closeonexec(fd int32)
+// int32 runtime·closeonexec(int32 fd);
 TEXT runtime·closeonexec(SB),NOSPLIT,$32
 	MOVL	$92, AX  // fcntl
 	// 0(SP) is where the caller PC would be; kernel skips it
diff --git a/src/runtime/sys_darwin_amd64.s b/src/runtime/sys_darwin_amd64.s
index 692dbca..bd397d7 100644
--- a/src/runtime/sys_darwin_amd64.s
+++ b/src/runtime/sys_darwin_amd64.s
@@ -11,8 +11,7 @@
 // The high 8 bits specify the kind of system call: 1=Mach, 2=BSD, 3=Machine-Dependent.
 //
 
-#include "go_asm.h"
-#include "go_tls.h"
+#include "zasm_GOOS_GOARCH.h"
 #include "textflag.h"
 
 // Exit the entire program (like C exit)
@@ -38,17 +37,13 @@ TEXT runtime·open(SB),NOSPLIT,$0
 	MOVL	perm+12(FP), DX		// arg 3 mode
 	MOVL	$(0x2000000+5), AX	// syscall entry
 	SYSCALL
-	JCC	2(PC)
-	MOVL	$-1, AX
 	MOVL	AX, ret+16(FP)
 	RET
 
-TEXT runtime·closefd(SB),NOSPLIT,$0
+TEXT runtime·close(SB),NOSPLIT,$0
 	MOVL	fd+0(FP), DI		// arg 1 fd
 	MOVL	$(0x2000000+6), AX	// syscall entry
 	SYSCALL
-	JCC	2(PC)
-	MOVL	$-1, AX
 	MOVL	AX, ret+8(FP)
 	RET
 
@@ -58,8 +53,6 @@ TEXT runtime·read(SB),NOSPLIT,$0
 	MOVL	n+16(FP), DX		// arg 3 count
 	MOVL	$(0x2000000+3), AX	// syscall entry
 	SYSCALL
-	JCC	2(PC)
-	MOVL	$-1, AX
 	MOVL	AX, ret+24(FP)
 	RET
 
@@ -69,17 +62,10 @@ TEXT runtime·write(SB),NOSPLIT,$0
 	MOVL	n+16(FP), DX		// arg 3 count
 	MOVL	$(0x2000000+4), AX	// syscall entry
 	SYSCALL
-	JCC	2(PC)
-	MOVL	$-1, AX
 	MOVL	AX, ret+24(FP)
 	RET
 
-TEXT runtime·raise(SB),NOSPLIT,$0
-	// Ideally we'd send the signal to the current thread,
-	// not the whole process, but that's too hard on OS X.
-	JMP	runtime·raiseproc(SB)
-
-TEXT runtime·raiseproc(SB),NOSPLIT,$24
+TEXT runtime·raise(SB),NOSPLIT,$24
 	MOVL	$(0x2000000+20), AX // getpid
 	SYSCALL
 	MOVQ	AX, DI	// arg 1 - pid
@@ -200,7 +186,7 @@ TEXT runtime·sigprocmask(SB),NOSPLIT,$0
 	MOVL	$0xf1, 0xf1  // crash
 	RET
 
-TEXT runtime·sigaction(SB),NOSPLIT,$0-24
+TEXT runtime·sigaction(SB),NOSPLIT,$0
 	MOVL	mode+0(FP), DI		// arg 1 sig
 	MOVQ	new+8(FP), SI		// arg 2 act
 	MOVQ	old+16(FP), DX		// arg 3 oact
@@ -212,29 +198,48 @@ TEXT runtime·sigaction(SB),NOSPLIT,$0-24
 	MOVL	$0xf1, 0xf1  // crash
 	RET
 
-TEXT runtime·sigfwd(SB),NOSPLIT,$0-32
-	MOVQ fn+0(FP),    AX
-	MOVQ sig+8(FP),   DI
-	MOVQ info+16(FP), SI
-	MOVQ ctx+24(FP),  DX
-	CALL AX
-	RET
+TEXT runtime·sigtramp(SB),NOSPLIT,$64
+	get_tls(BX)
 
-TEXT runtime·sigreturn(SB),NOSPLIT,$0-12
-	MOVQ ctx+0(FP),        DI
-	MOVL infostyle+8(FP),  SI
-	MOVL $(0x2000000+184), AX
-	SYSCALL
-	INT $3 // not reached
+	MOVQ	R8, 32(SP)	// save ucontext
+	MOVQ	SI, 40(SP)	// save infostyle
+
+	// check that g exists
+	MOVQ	g(BX), R10
+	CMPQ	R10, $0
+	JNE	5(PC)
+	MOVL	DX, 0(SP)
+	MOVQ	$runtime·badsignal(SB), AX
+	CALL	AX
+	JMP 	sigtramp_ret
+
+	// save g
+	MOVQ	R10, 48(SP)
 
-TEXT runtime·sigtramp(SB),NOSPLIT,$32
-	MOVQ DI,  0(SP) // fn
-	MOVL SI,  8(SP) // infostyle
-	MOVL DX, 12(SP) // sig
-	MOVQ CX, 16(SP) // info
-	MOVQ R8, 24(SP) // ctx
-	MOVQ $runtime·sigtrampgo(SB), AX
-	CALL AX
+	// g = m->gsignal
+	MOVQ	g_m(R10), BP
+	MOVQ	m_gsignal(BP), BP
+	MOVQ	BP, g(BX)
+
+	MOVL	DX, 0(SP)
+	MOVQ	CX, 8(SP)
+	MOVQ	R8, 16(SP)
+	MOVQ	R10, 24(SP)
+
+	CALL	DI
+
+	// restore g
+	get_tls(BX)
+	MOVQ	48(SP), R10
+	MOVQ	R10, g(BX)
+
+sigtramp_ret:
+	// call sigreturn
+	MOVL	$(0x2000000+184), AX	// sigreturn(ucontext, infostyle)
+	MOVQ	32(SP), DI	// saved ucontext
+	MOVQ	40(SP), SI	// saved infostyle
+	SYSCALL
+	INT $3	// not reached
 
 TEXT runtime·mmap(SB),NOSPLIT,$0
 	MOVQ	addr+0(FP), DI		// arg 1 addr
@@ -258,8 +263,8 @@ TEXT runtime·munmap(SB),NOSPLIT,$0
 	RET
 
 TEXT runtime·sigaltstack(SB),NOSPLIT,$0
-	MOVQ	new+0(FP), DI
-	MOVQ	old+8(FP), SI
+	MOVQ	new+8(SP), DI
+	MOVQ	old+16(SP), SI
 	MOVQ	$(0x2000000+53), AX
 	SYSCALL
 	JCC	2(PC)
@@ -284,25 +289,25 @@ TEXT runtime·usleep(SB),NOSPLIT,$16
 	SYSCALL
 	RET
 
-// func bsdthread_create(stk, arg unsafe.Pointer, fn uintptr) int32
+// void bsdthread_create(void *stk, M *mp, G *gp, void (*fn)(void))
 TEXT runtime·bsdthread_create(SB),NOSPLIT,$0
 	// Set up arguments to bsdthread_create system call.
 	// The ones in quotes pass through to the thread callback
 	// uninterpreted, so we can put whatever we want there.
-	MOVQ	fn+16(FP),   DI
-	MOVQ	arg+8(FP),  SI
-	MOVQ	stk+0(FP),   DX
-	MOVQ	$0x01000000, R8  // flags = PTHREAD_START_CUSTOM
-	MOVQ	$0,          R9  // paranoia
-	MOVQ	$0,          R10 // paranoia, "pthread"
+	MOVQ	fn+32(SP), DI	// "func"
+	MOVQ	mm+16(SP), SI	// "arg"
+	MOVQ	stk+8(SP), DX	// stack
+	MOVQ	gg+24(SP), R10	// "pthread"
+	MOVQ	$0x01000000, R8	// flags = PTHREAD_START_CUSTOM
+	MOVQ	$0, R9	// paranoia
 	MOVQ	$(0x2000000+360), AX	// bsdthread_create
 	SYSCALL
 	JCC 4(PC)
 	NEGQ	AX
-	MOVL	AX, ret+24(FP)
+	MOVL	AX, ret+32(FP)
 	RET
 	MOVL	$0, AX
-	MOVL	AX, ret+24(FP)
+	MOVL	AX, ret+32(FP)
 	RET
 
 // The thread that bsdthread_create creates starts executing here,
@@ -340,7 +345,7 @@ TEXT runtime·bsdthread_start(SB),NOSPLIT,$0
 	CALL	runtime·exit1(SB)
 	RET
 
-// func bsdthread_register() int32
+// void bsdthread_register(void)
 // registers callbacks for threadstart (see bsdthread_create above
 // and wqthread and pthsize (not used).  returns 0 on success.
 TEXT runtime·bsdthread_register(SB),NOSPLIT,$0
@@ -362,7 +367,7 @@ TEXT runtime·bsdthread_register(SB),NOSPLIT,$0
 
 // Mach system calls use 0x1000000 instead of the BSD's 0x2000000.
 
-// func mach_msg_trap(h unsafe.Pointer, op int32, send_size, rcv_size, rcv_name, timeout, notify uint32) int32
+// uint32 mach_msg_trap(void*, uint32, uint32, uint32, uint32, uint32, uint32)
 TEXT runtime·mach_msg_trap(SB),NOSPLIT,$0
 	MOVQ	h+0(FP), DI
 	MOVL	op+8(FP), SI
@@ -399,7 +404,7 @@ TEXT runtime·mach_reply_port(SB),NOSPLIT,$0
 // Mach provides trap versions of the semaphore ops,
 // instead of requiring the use of RPC.
 
-// func mach_semaphore_wait(sema uint32) int32
+// uint32 mach_semaphore_wait(uint32)
 TEXT runtime·mach_semaphore_wait(SB),NOSPLIT,$0
 	MOVL	sema+0(FP), DI
 	MOVL	$(0x1000000+36), AX	// semaphore_wait_trap
@@ -407,7 +412,7 @@ TEXT runtime·mach_semaphore_wait(SB),NOSPLIT,$0
 	MOVL	AX, ret+8(FP)
 	RET
 
-// func mach_semaphore_timedwait(sema, sec, nsec uint32) int32
+// uint32 mach_semaphore_timedwait(uint32, uint32, uint32)
 TEXT runtime·mach_semaphore_timedwait(SB),NOSPLIT,$0
 	MOVL	sema+0(FP), DI
 	MOVL	sec+4(FP), SI
@@ -417,7 +422,7 @@ TEXT runtime·mach_semaphore_timedwait(SB),NOSPLIT,$0
 	MOVL	AX, ret+16(FP)
 	RET
 
-// func mach_semaphore_signal(sema uint32) int32
+// uint32 mach_semaphore_signal(uint32)
 TEXT runtime·mach_semaphore_signal(SB),NOSPLIT,$0
 	MOVL	sema+0(FP), DI
 	MOVL	$(0x1000000+33), AX	// semaphore_signal_trap
@@ -425,7 +430,7 @@ TEXT runtime·mach_semaphore_signal(SB),NOSPLIT,$0
 	MOVL	AX, ret+8(FP)
 	RET
 
-// func mach_semaphore_signal_all(sema uint32) int32
+// uint32 mach_semaphore_signal_all(uint32)
 TEXT runtime·mach_semaphore_signal_all(SB),NOSPLIT,$0
 	MOVL	sema+0(FP), DI
 	MOVL	$(0x1000000+34), AX	// semaphore_signal_all_trap
@@ -463,7 +468,7 @@ TEXT runtime·sysctl(SB),NOSPLIT,$0
 	MOVL	AX, ret+48(FP)
 	RET
 
-// func kqueue() int32
+// int32 runtime·kqueue(void);
 TEXT runtime·kqueue(SB),NOSPLIT,$0
 	MOVQ    $0, DI
 	MOVQ    $0, SI
@@ -475,13 +480,13 @@ TEXT runtime·kqueue(SB),NOSPLIT,$0
 	MOVL	AX, ret+0(FP)
 	RET
 
-// func kevent(kq int32, ch *keventt, nch int32, ev *keventt, nev int32, ts *timespec) int32
+// int32 runtime·kevent(int kq, Kevent *changelist, int nchanges, Kevent *eventlist, int nevents, Timespec *timeout);
 TEXT runtime·kevent(SB),NOSPLIT,$0
-	MOVL    kq+0(FP), DI
-	MOVQ    ch+8(FP), SI
-	MOVL    nch+16(FP), DX
-	MOVQ    ev+24(FP), R10
-	MOVL    nev+32(FP), R8
+	MOVL    fd+0(FP), DI
+	MOVQ    ev1+8(FP), SI
+	MOVL    nev1+16(FP), DX
+	MOVQ    ev2+24(FP), R10
+	MOVL    nev2+32(FP), R8
 	MOVQ    ts+40(FP), R9
 	MOVL	$(0x2000000+363), AX
 	SYSCALL
@@ -490,7 +495,7 @@ TEXT runtime·kevent(SB),NOSPLIT,$0
 	MOVL	AX, ret+48(FP)
 	RET
 
-// func closeonexec(fd int32)
+// void runtime·closeonexec(int32 fd);
 TEXT runtime·closeonexec(SB),NOSPLIT,$0
 	MOVL    fd+0(FP), DI  // fd
 	MOVQ    $2, SI  // F_SETFD
diff --git a/src/runtime/sys_dragonfly_386.s b/src/runtime/sys_dragonfly_386.s
new file mode 100644
index 0000000..161eaec
--- /dev/null
+++ b/src/runtime/sys_dragonfly_386.s
@@ -0,0 +1,381 @@
+// 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.
+//
+// System calls and other sys.stuff for 386, FreeBSD
+// /usr/src/sys/kern/syscalls.master for syscall numbers.
+//
+
+#include "zasm_GOOS_GOARCH.h"
+#include "textflag.h"
+	
+TEXT runtime·sys_umtx_sleep(SB),NOSPLIT,$-4
+	MOVL	$469, AX		// umtx_sleep
+	INT	$0x80
+	JAE	2(PC)
+	NEGL	AX
+	MOVL	AX, ret+12(FP)
+	RET
+
+TEXT runtime·sys_umtx_wakeup(SB),NOSPLIT,$-4
+	MOVL	$470, AX		// umtx_wakeup
+	INT	$0x80
+	JAE	2(PC)
+	NEGL	AX
+	MOVL	AX, ret+8(FP)
+	RET
+
+TEXT runtime·lwp_create(SB),NOSPLIT,$-4
+	MOVL	$495, AX		// lwp_create
+	INT	$0x80
+	MOVL	AX, ret+4(FP)
+	RET
+
+TEXT runtime·lwp_start(SB),NOSPLIT,$0
+
+	// Set GS to point at m->tls.
+	MOVL	mm+0(FP), BX
+	MOVL	m_g0(BX), DX
+	LEAL	m_tls(BX), BP
+	PUSHAL
+	PUSHL	BP
+	CALL	runtime·settls(SB)
+	POPL	AX
+	POPAL
+	
+	// Now segment is established.  Initialize m, g.
+	get_tls(CX)
+	MOVL	BX, g_m(DX)
+	MOVL	DX, g(CX)
+
+	CALL	runtime·stackcheck(SB)	// smashes AX, CX
+	MOVL	0(DX), DX		// paranoia; check they are not nil
+	MOVL	0(BX), BX
+
+	// More paranoia; check that stack splitting code works.
+	PUSHAL
+	CALL	runtime·emptyfunc(SB)
+	POPAL
+
+	CALL	runtime·mstart(SB)
+
+	CALL	runtime·exit1(SB)
+	MOVL	$0x1234, 0x1005
+	RET
+
+// Exit the entire program (like C exit)
+TEXT runtime·exit(SB),NOSPLIT,$-4
+	MOVL	$1, AX
+	INT	$0x80
+	MOVL	$0xf1, 0xf1  // crash
+	RET
+
+TEXT runtime·exit1(SB),NOSPLIT,$16
+	MOVL	$0, 0(SP)		// syscall gap
+	MOVL	$0x10000, 4(SP)		// arg 1 - how (EXTEXIT_LWP)
+	MOVL	$0, 8(SP)		// arg 2 - status
+	MOVL	$0, 12(SP)		// arg 3 - addr
+	MOVL	$494, AX
+	INT	$0x80
+	JAE	2(PC)
+	MOVL	$0xf1, 0xf1  // crash
+	RET
+
+TEXT runtime·open(SB),NOSPLIT,$-4
+	MOVL	$5, AX
+	INT	$0x80
+	MOVL	AX, ret+12(FP)
+	RET
+
+TEXT runtime·close(SB),NOSPLIT,$-4
+	MOVL	$6, AX
+	INT	$0x80
+	MOVL	AX, ret+4(FP)
+	RET
+
+TEXT runtime·read(SB),NOSPLIT,$-4
+	MOVL	$3, AX
+	INT	$0x80
+	MOVL	AX, ret+12(FP)
+	RET
+
+TEXT runtime·write(SB),NOSPLIT,$-4
+	MOVL	$4, AX
+	INT	$0x80
+	MOVL	AX, ret+12(FP)
+	RET
+
+TEXT runtime·getrlimit(SB),NOSPLIT,$-4
+	MOVL	$194, AX
+	INT	$0x80
+	MOVL	AX, ret+8(FP)
+	RET
+
+TEXT runtime·raise(SB),NOSPLIT,$16
+	MOVL	$496, AX		// lwp_gettid
+	INT	$0x80
+	MOVL	$0, 0(SP)
+	MOVL	$-1, 4(SP)		// arg 1 - pid
+	MOVL	AX, 8(SP)		// arg 2 - tid
+	MOVL	sig+0(FP), AX
+	MOVL	AX, 8(SP)		// arg 3 - signum
+	MOVL	$497, AX		// lwp_kill
+	INT	$0x80
+	RET
+
+TEXT runtime·mmap(SB),NOSPLIT,$36
+	LEAL	addr+0(FP), SI
+	LEAL	4(SP), DI
+	CLD
+	MOVSL				// arg 1 - addr
+	MOVSL				// arg 2 - len
+	MOVSL				// arg 3 - prot
+	MOVSL				// arg 4 - flags
+	MOVSL				// arg 5 - fd
+	MOVL	$0, AX
+	STOSL				// arg 6 - pad
+	MOVSL				// arg 7 - offset
+	MOVL	$0, AX			// top 32 bits of file offset
+	STOSL
+	MOVL	$197, AX		// sys_mmap
+	INT	$0x80
+	MOVL	AX, ret+24(FP)
+	RET
+
+TEXT runtime·munmap(SB),NOSPLIT,$-4
+	MOVL	$73, AX
+	INT	$0x80
+	JAE	2(PC)
+	MOVL	$0xf1, 0xf1  // crash
+	RET
+
+TEXT runtime·madvise(SB),NOSPLIT,$-4
+	MOVL	$75, AX	// madvise
+	INT	$0x80
+	// ignore failure - maybe pages are locked
+	RET
+
+TEXT runtime·setitimer(SB), NOSPLIT, $-4
+	MOVL	$83, 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)	// CLOCK_REALTIME
+	MOVL	BX, 8(SP)
+	INT	$0x80
+	MOVL	12(SP), AX	// sec
+	MOVL	16(SP), BX	// nsec
+
+	// sec is in AX, nsec in BX
+	MOVL	AX, sec+0(FP)
+	MOVL	$0, sec+4(FP)
+	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	$4, 4(SP)	// CLOCK_MONOTONIC
+	MOVL	BX, 8(SP)
+	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
+	ADDL	BX, AX
+	ADCL	$0, DX
+
+	MOVL	AX, ret_lo+0(FP)
+	MOVL	DX, ret_hi+4(FP)
+	RET
+
+
+TEXT runtime·sigaction(SB),NOSPLIT,$-4
+	MOVL	$342, AX
+	INT	$0x80
+	JAE	2(PC)
+	MOVL	$0xf1, 0xf1  // crash
+	RET
+
+TEXT runtime·sigtramp(SB),NOSPLIT,$44
+	get_tls(CX)
+
+	// check that g exists
+	MOVL	g(CX), DI
+	CMPL	DI, $0
+	JNE	6(PC)
+	MOVL	signo+0(FP), BX
+	MOVL	BX, 0(SP)
+	MOVL	$runtime·badsignal(SB), AX
+	CALL	AX
+	JMP 	sigtramp_ret
+
+	// save g
+	MOVL	DI, 20(SP)
+	
+	// g = m->gsignal
+	MOVL	g_m(DI), BX
+	MOVL	m_gsignal(BX), BX
+	MOVL	BX, g(CX)
+
+	// copy arguments for call to sighandler
+	MOVL	signo+0(FP), BX
+	MOVL	BX, 0(SP)
+	MOVL	info+4(FP), BX
+	MOVL	BX, 4(SP)
+	MOVL	context+8(FP), BX
+	MOVL	BX, 8(SP)
+	MOVL	DI, 12(SP)
+
+	CALL	runtime·sighandler(SB)
+
+	// restore g
+	get_tls(CX)
+	MOVL	20(SP), BX
+	MOVL	BX, g(CX)
+
+sigtramp_ret:
+	// call sigreturn
+	MOVL	context+8(FP), AX
+	MOVL	$0, 0(SP)	// syscall gap
+	MOVL	AX, 4(SP)
+	MOVL	$344, AX	// sigreturn(ucontext)
+	INT	$0x80
+	MOVL	$0xf1, 0xf1  // crash
+	RET
+
+TEXT runtime·sigaltstack(SB),NOSPLIT,$0
+	MOVL	$53, AX
+	INT	$0x80
+	JAE	2(PC)
+	MOVL	$0xf1, 0xf1  // crash
+	RET
+
+TEXT runtime·usleep(SB),NOSPLIT,$20
+	MOVL	$0, DX
+	MOVL	usec+0(FP), AX
+	MOVL	$1000000, CX
+	DIVL	CX
+	MOVL	AX, 12(SP)		// tv_sec
+	MOVL	$1000, AX
+	MULL	DX
+	MOVL	AX, 16(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
+	INT	$0x80
+	RET
+
+TEXT runtime·setldt(SB),NOSPLIT,$4
+	// Under DragonFly we set the GS base instead of messing with the LDT.
+	MOVL	tls0+4(FP), AX
+	MOVL	AX, 0(SP)
+	CALL	runtime·settls(SB)
+	RET
+
+TEXT runtime·settls(SB),NOSPLIT,$24
+	// adjust for ELF: wants to use -8(GS) and -4(GS) for g and m
+	MOVL	tlsbase+0(FP), CX
+	ADDL	$8, CX
+
+	// Set up a struct tls_info - a size of -1 maps the whole address
+	// space and is required for direct-tls access of variable data
+	// via negative offsets.
+	LEAL	16(SP), BX
+	MOVL	CX, 16(SP)		// base
+	MOVL	$-1, 20(SP)		// size
+
+	// set_tls_area returns the descriptor that needs to be loaded into GS.
+	MOVL	$0, 0(SP)		// syscall gap
+	MOVL	$0, 4(SP)		// arg 1 - which
+	MOVL	BX, 8(SP)		// arg 2 - tls_info
+	MOVL	$8, 12(SP)		// arg 3 - infosize
+	MOVL    $472, AX                // set_tls_area
+	INT     $0x80
+	JCC     2(PC)
+	MOVL    $0xf1, 0xf1             // crash
+	MOVW	AX, GS
+	RET
+
+TEXT runtime·sysctl(SB),NOSPLIT,$28
+	LEAL	mib+0(FP), SI
+	LEAL	4(SP), DI
+	CLD
+	MOVSL				// arg 1 - name
+	MOVSL				// arg 2 - namelen
+	MOVSL				// arg 3 - oldp
+	MOVSL				// arg 4 - oldlenp
+	MOVSL				// arg 5 - newp
+	MOVSL				// arg 6 - newlen
+	MOVL	$202, AX		// sys___sysctl
+	INT	$0x80
+	JCC	4(PC)
+	NEGL	AX
+	MOVL	AX, ret+24(FP)
+	RET
+	MOVL	$0, AX
+	MOVL	AX, ret+24(FP)
+	RET
+
+TEXT runtime·osyield(SB),NOSPLIT,$-4
+	MOVL	$331, AX		// sys_sched_yield
+	INT	$0x80
+	RET
+
+TEXT runtime·sigprocmask(SB),NOSPLIT,$16
+	MOVL	$0, 0(SP)		// syscall gap
+	MOVL	$3, 4(SP)		// arg 1 - how (SIG_SETMASK)
+	MOVL	new+0(FP), AX
+	MOVL	AX, 8(SP)		// arg 2 - set
+	MOVL	old+4(FP), AX
+	MOVL	AX, 12(SP)		// arg 3 - oset
+	MOVL	$340, AX		// sys_sigprocmask
+	INT	$0x80
+	JAE	2(PC)
+	MOVL	$0xf1, 0xf1  // crash
+	RET
+
+// int32 runtime·kqueue(void);
+TEXT runtime·kqueue(SB),NOSPLIT,$0
+	MOVL	$362, AX
+	INT	$0x80
+	JAE	2(PC)
+	NEGL	AX
+	MOVL	AX, ret+0(FP)
+	RET
+
+// int32 runtime·kevent(int kq, Kevent *changelist, int nchanges, Kevent *eventlist, int nevents, Timespec *timeout);
+TEXT runtime·kevent(SB),NOSPLIT,$0
+	MOVL	$363, AX
+	INT	$0x80
+	JAE	2(PC)
+	NEGL	AX
+	MOVL	AX, ret+24(FP)
+	RET
+
+// int32 runtime·closeonexec(int32 fd);
+TEXT runtime·closeonexec(SB),NOSPLIT,$32
+	MOVL	$92, AX		// fcntl
+	// 0(SP) is where the caller PC would be; kernel skips it
+	MOVL	fd+0(FP), BX
+	MOVL	BX, 4(SP)	// fd
+	MOVL	$2, 8(SP)	// F_SETFD
+	MOVL	$1, 12(SP)	// FD_CLOEXEC
+	INT	$0x80
+	JAE	2(PC)
+	NEGL	AX
+	RET
+
+GLOBL runtime·tlsoffset(SB),NOPTR,$4
diff --git a/src/runtime/sys_dragonfly_amd64.s b/src/runtime/sys_dragonfly_amd64.s
index 26c9784..2c75601 100644
--- a/src/runtime/sys_dragonfly_amd64.s
+++ b/src/runtime/sys_dragonfly_amd64.s
@@ -6,8 +6,7 @@
 // /usr/src/sys/kern/syscalls.master for syscall numbers.
 //
 
-#include "go_asm.h"
-#include "go_tls.h"
+#include "zasm_GOOS_GOARCH.h"
 #include "textflag.h"
 	
 TEXT runtime·sys_umtx_sleep(SB),NOSPLIT,$0
@@ -77,17 +76,13 @@ TEXT runtime·open(SB),NOSPLIT,$-8
 	MOVL	perm+12(FP), DX		// arg 3 mode
 	MOVL	$5, AX
 	SYSCALL
-	JCC	2(PC)
-	MOVL	$-1, AX
 	MOVL	AX, ret+16(FP)
 	RET
 
-TEXT runtime·closefd(SB),NOSPLIT,$-8
+TEXT runtime·close(SB),NOSPLIT,$-8
 	MOVL	fd+0(FP), DI		// arg 1 fd
 	MOVL	$6, AX
 	SYSCALL
-	JCC	2(PC)
-	MOVL	$-1, AX
 	MOVL	AX, ret+8(FP)
 	RET
 
@@ -97,8 +92,6 @@ TEXT runtime·read(SB),NOSPLIT,$-8
 	MOVL	n+16(FP), DX		// arg 3 count
 	MOVL	$3, AX
 	SYSCALL
-	JCC	2(PC)
-	MOVL	$-1, AX
 	MOVL	AX, ret+24(FP)
 	RET
 
@@ -108,8 +101,6 @@ TEXT runtime·write(SB),NOSPLIT,$-8
 	MOVL	n+16(FP), DX		// arg 3 count
 	MOVL	$4, AX
 	SYSCALL
-	JCC	2(PC)
-	MOVL	$-1, AX
 	MOVL	AX, ret+24(FP)
 	RET
 
@@ -125,21 +116,12 @@ TEXT runtime·raise(SB),NOSPLIT,$16
 	MOVL	$496, AX	// lwp_gettid
 	SYSCALL
 	MOVQ	$-1, DI		// arg 1 - pid
-	MOVQ	AX, SI		// arg 2 - tid
-	MOVL	sig+0(FP), DX	// arg 3 - signum
+	MOVQ	8(SP), DI	// arg 2 - tid
+	MOVL	sig+0(FP), SI	// arg 3 - signum
 	MOVL	$497, AX	// lwp_kill
 	SYSCALL
 	RET
 
-TEXT runtime·raiseproc(SB),NOSPLIT,$0
-	MOVL	$20, AX		// getpid
-	SYSCALL
-	MOVQ	AX, DI		// arg 1 - pid
-	MOVL	sig+0(FP), SI	// arg 2 - signum
-	MOVL	$37, AX		// kill
-	SYSCALL
-	RET
-
 TEXT runtime·setitimer(SB), NOSPLIT, $-8
 	MOVL	mode+0(FP), DI
 	MOVQ	new+8(FP), SI
@@ -203,9 +185,9 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$64
 	MOVQ	R10, 40(SP)
 	
 	// g = m->signal
-	MOVQ	g_m(R10), AX
-	MOVQ	m_gsignal(AX), AX
-	MOVQ	AX, g(BX)
+	MOVQ	g_m(R10), BP
+	MOVQ	m_gsignal(BP), BP
+	MOVQ	BP, g(BX)
 	
 	MOVQ	DI, 0(SP)
 	MOVQ	SI, 8(SP)
@@ -281,7 +263,7 @@ TEXT runtime·usleep(SB),NOSPLIT,$16
 
 // set tls base to DI
 TEXT runtime·settls(SB),NOSPLIT,$16
-	ADDQ	$8, DI	// adjust for ELF: wants to use -8(FS) for g
+	ADDQ	$16, DI	// adjust for ELF: wants to use -16(FS) and -8(FS) for g and m
 	MOVQ	DI, 0(SP)
 	MOVQ	$16, 8(SP)
 	MOVQ	$0, DI			// arg 1 - which
@@ -316,9 +298,9 @@ TEXT runtime·osyield(SB),NOSPLIT,$-4
 	RET
 
 TEXT runtime·sigprocmask(SB),NOSPLIT,$0
-	MOVL	how+0(FP), DI		// arg 1 - how
-	MOVQ	new+8(FP), SI		// arg 2 - set
-	MOVQ	old+16(FP), DX		// arg 3 - oset
+	MOVL	$3, DI			// arg 1 - how (SIG_SETMASK)
+	MOVQ	new+0(FP), SI		// arg 2 - set
+	MOVQ	old+8(FP), DX		// arg 3 - oset
 	MOVL	$340, AX		// sys_sigprocmask
 	SYSCALL
 	JAE	2(PC)
diff --git a/src/runtime/sys_freebsd_386.s b/src/runtime/sys_freebsd_386.s
index b2dd780..2c40fc4 100644
--- a/src/runtime/sys_freebsd_386.s
+++ b/src/runtime/sys_freebsd_386.s
@@ -6,8 +6,7 @@
 // /usr/src/sys/kern/syscalls.master for syscall numbers.
 //
 
-#include "go_asm.h"
-#include "go_tls.h"
+#include "zasm_GOOS_GOARCH.h"
 #include "textflag.h"
 	
 TEXT runtime·sys_umtx_op(SB),NOSPLIT,$-4
@@ -62,32 +61,24 @@ TEXT runtime·exit1(SB),NOSPLIT,$-4
 TEXT runtime·open(SB),NOSPLIT,$-4
 	MOVL	$5, AX
 	INT	$0x80
-	JAE	2(PC)
-	MOVL	$-1, AX
 	MOVL	AX, ret+12(FP)
 	RET
 
-TEXT runtime·closefd(SB),NOSPLIT,$-4
+TEXT runtime·close(SB),NOSPLIT,$-4
 	MOVL	$6, AX
 	INT	$0x80
-	JAE	2(PC)
-	MOVL	$-1, AX
 	MOVL	AX, ret+4(FP)
 	RET
 
 TEXT runtime·read(SB),NOSPLIT,$-4
 	MOVL	$3, AX
 	INT	$0x80
-	JAE	2(PC)
-	MOVL	$-1, AX
 	MOVL	AX, ret+12(FP)
 	RET
 
 TEXT runtime·write(SB),NOSPLIT,$-4
 	MOVL	$4, AX
 	INT	$0x80
-	JAE	2(PC)
-	MOVL	$-1, AX
 	MOVL	AX, ret+12(FP)
 	RET
 
@@ -112,18 +103,6 @@ TEXT runtime·raise(SB),NOSPLIT,$16
 	INT	$0x80
 	RET
 
-TEXT runtime·raiseproc(SB),NOSPLIT,$16
-	// getpid
-	MOVL	$20, AX
-	INT	$0x80
-	// kill(self, sig)
-	MOVL	AX, 4(SP)
-	MOVL	sig+0(FP), AX
-	MOVL	AX, 8(SP)
-	MOVL	$37, AX
-	INT	$0x80
-	RET
-
 TEXT runtime·mmap(SB),NOSPLIT,$32
 	LEAL addr+0(FP), SI
 	LEAL	4(SP), DI
@@ -218,7 +197,7 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$44
 	MOVL	BX, 0(SP)
 	MOVL	$runtime·badsignal(SB), AX
 	CALL	AX
-	JMP 	ret
+	JMP 	sigtramp_ret
 
 	// save g
 	MOVL	DI, 20(SP)
@@ -244,7 +223,7 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$44
 	MOVL	20(SP), BX
 	MOVL	BX, g(CX)
 
-ret:
+sigtramp_ret:
 	// call sigreturn
 	MOVL	context+8(FP), AX
 	MOVL	$0, 0(SP)	// syscall gap
@@ -299,7 +278,7 @@ int i386_set_ldt(int, const union ldt_entry *, int);
 TEXT runtime·setldt(SB),NOSPLIT,$32
 	MOVL	address+4(FP), BX	// aka base
 	// see comment in sys_linux_386.s; freebsd is similar
-	ADDL	$0x4, BX
+	ADDL	$0x8, BX
 
 	// set up data_desc
 	LEAL	16(SP), AX	// struct data_desc
@@ -367,11 +346,10 @@ TEXT runtime·osyield(SB),NOSPLIT,$-4
 
 TEXT runtime·sigprocmask(SB),NOSPLIT,$16
 	MOVL	$0, 0(SP)		// syscall gap
-	MOVL	how+0(FP), AX		// arg 1 - how
-	MOVL	AX, 4(SP)
-	MOVL	new+4(FP), AX
+	MOVL	$3, 4(SP)		// arg 1 - how (SIG_SETMASK)
+	MOVL	new+0(FP), AX
 	MOVL	AX, 8(SP)		// arg 2 - set
-	MOVL	old+8(FP), AX
+	MOVL	old+4(FP), AX
 	MOVL	AX, 12(SP)		// arg 3 - oset
 	MOVL	$340, AX		// sys_sigprocmask
 	INT	$0x80
diff --git a/src/runtime/sys_freebsd_amd64.s b/src/runtime/sys_freebsd_amd64.s
index b1c67c7..65f8c1a 100644
--- a/src/runtime/sys_freebsd_amd64.s
+++ b/src/runtime/sys_freebsd_amd64.s
@@ -6,10 +6,34 @@
 // /usr/src/sys/kern/syscalls.master for syscall numbers.
 //
 
-#include "go_asm.h"
-#include "go_tls.h"
+#include "zasm_GOOS_GOARCH.h"
 #include "textflag.h"
 
+// FreeBSD 8, FreeBSD 9, and older versions that I have checked
+// do not restore R10 on exit from a "restarted" system call
+// if you use the SYSCALL instruction. This means that, for example,
+// if a signal arrives while the wait4 system call is executing,
+// the wait4 internally returns ERESTART, which makes the kernel
+// back up the PC to execute the SYSCALL instruction a second time.
+// However, since the kernel does not restore R10, the fourth
+// argument to the system call has been lost. (FreeBSD 9 also fails
+// to restore the fifth and sixth arguments, R8 and R9, although
+// some earlier versions did restore those correctly.)
+// The broken code is in fast_syscall in FreeBSD's amd64/amd64/exception.S.
+// It restores only DI, SI, DX, AX, and RFLAGS on system call return.
+// http://fxr.watson.org/fxr/source/amd64/amd64/exception.S?v=FREEBSD91#L399
+//
+// The INT $0x80 system call path (int0x80_syscall in FreeBSD's 
+// amd64/ia32/ia32_exception.S) does not have this problem,
+// but it expects the third argument in R10. Instead of rewriting
+// all the assembly in this file, #define SYSCALL to a safe simulation
+// using INT $0x80.
+//
+// INT $0x80 is a little slower than SYSCALL, but correctness wins.
+//
+// See golang.org/issue/6372.
+#define SYSCALL MOVQ R10, CX; INT $0x80
+	
 TEXT runtime·sys_umtx_op(SB),NOSPLIT,$0
 	MOVQ addr+0(FP), DI
 	MOVL mode+8(FP), SI
@@ -67,17 +91,13 @@ TEXT runtime·open(SB),NOSPLIT,$-8
 	MOVL	perm+12(FP), DX		// arg 3 mode
 	MOVL	$5, AX
 	SYSCALL
-	JCC	2(PC)
-	MOVL	$-1, AX
 	MOVL	AX, ret+16(FP)
 	RET
 
-TEXT runtime·closefd(SB),NOSPLIT,$-8
+TEXT runtime·close(SB),NOSPLIT,$-8
 	MOVL	fd+0(FP), DI		// arg 1 fd
 	MOVL	$6, AX
 	SYSCALL
-	JCC	2(PC)
-	MOVL	$-1, AX
 	MOVL	AX, ret+8(FP)
 	RET
 
@@ -87,8 +107,6 @@ TEXT runtime·read(SB),NOSPLIT,$-8
 	MOVL	n+16(FP), DX		// arg 3 count
 	MOVL	$3, AX
 	SYSCALL
-	JCC	2(PC)
-	MOVL	$-1, AX
 	MOVL	AX, ret+24(FP)
 	RET
 
@@ -98,8 +116,6 @@ TEXT runtime·write(SB),NOSPLIT,$-8
 	MOVL	n+16(FP), DX		// arg 3 count
 	MOVL	$4, AX
 	SYSCALL
-	JCC	2(PC)
-	MOVL	$-1, AX
 	MOVL	AX, ret+24(FP)
 	RET
 
@@ -123,17 +139,6 @@ TEXT runtime·raise(SB),NOSPLIT,$16
 	SYSCALL
 	RET
 
-TEXT runtime·raiseproc(SB),NOSPLIT,$0
-	// getpid
-	MOVL	$20, AX
-	SYSCALL
-	// kill(self, sig)
-	MOVQ	AX, DI		// arg 1 pid
-	MOVL	sig+0(FP), SI	// arg 2 sig
-	MOVL	$37, AX
-	SYSCALL
-	RET
-
 TEXT runtime·setitimer(SB), NOSPLIT, $-8
 	MOVL	mode+0(FP), DI
 	MOVQ	new+8(FP), SI
@@ -199,9 +204,9 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$64
 	MOVQ	R10, 40(SP)
 	
 	// g = m->signal
-	MOVQ	g_m(R10), AX
-	MOVQ	m_gsignal(AX), AX
-	MOVQ	AX, g(BX)
+	MOVQ	g_m(R10), BP
+	MOVQ	m_gsignal(BP), BP
+	MOVQ	BP, g(BX)
 	
 	MOVQ	DI, 0(SP)
 	MOVQ	SI, 8(SP)
@@ -273,7 +278,7 @@ TEXT runtime·usleep(SB),NOSPLIT,$16
 
 // set tls base to DI
 TEXT runtime·settls(SB),NOSPLIT,$8
-	ADDQ	$8, DI	// adjust for ELF: wants to use -8(FS) for g and m
+	ADDQ	$16, DI	// adjust for ELF: wants to use -16(FS) and -8(FS) for g and m
 	MOVQ	DI, 0(SP)
 	MOVQ	SP, SI
 	MOVQ	$129, DI	// AMD64_SET_FSBASE
@@ -306,9 +311,9 @@ TEXT runtime·osyield(SB),NOSPLIT,$-4
 	RET
 
 TEXT runtime·sigprocmask(SB),NOSPLIT,$0
-	MOVL	how+0(FP), DI		// arg 1 - how
-	MOVQ	new+8(FP), SI		// arg 2 - set
-	MOVQ	old+16(FP), DX		// arg 3 - oset
+	MOVL	$3, DI			// arg 1 - how (SIG_SETMASK)
+	MOVQ	new+0(FP), SI		// arg 2 - set
+	MOVQ	old+8(FP), DX		// arg 3 - oset
 	MOVL	$340, AX		// sys_sigprocmask
 	SYSCALL
 	JAE	2(PC)
diff --git a/src/runtime/sys_freebsd_arm.s b/src/runtime/sys_freebsd_arm.s
index bd6ff96..d875138 100644
--- a/src/runtime/sys_freebsd_arm.s
+++ b/src/runtime/sys_freebsd_arm.s
@@ -6,8 +6,7 @@
 // /usr/src/sys/kern/syscalls.master for syscall numbers.
 //
 
-#include "go_asm.h"
-#include "go_tls.h"
+#include "zasm_GOOS_GOARCH.h"
 #include "textflag.h"
 
 // for EABI, as we don't support OABI
@@ -18,8 +17,6 @@
 #define SYS_write (SYS_BASE + 4)
 #define SYS_open (SYS_BASE + 5)
 #define SYS_close (SYS_BASE + 6)
-#define SYS_getpid (SYS_BASE + 20)
-#define SYS_kill (SYS_BASE + 37)
 #define SYS_sigaltstack (SYS_BASE + 53)
 #define SYS_munmap (SYS_BASE + 73)
 #define SYS_madvise (SYS_BASE + 75)
@@ -42,10 +39,10 @@
 #define SYS_mmap (SYS_BASE + 477) 
 	
 TEXT runtime·sys_umtx_op(SB),NOSPLIT,$0
-	MOVW addr+0(FP), R0
-	MOVW mode+4(FP), R1
-	MOVW val+8(FP), R2
-	MOVW ptr2+12(FP), R3
+	MOVW 0(FP), R0
+	MOVW 4(FP), R1
+	MOVW 8(FP), R2
+	MOVW 12(FP), R3
 	ADD $20, R13 // arg 5 is passed on stack
 	MOVW $SYS__umtx_op, R7
 	SWI $0
@@ -55,8 +52,8 @@ TEXT runtime·sys_umtx_op(SB),NOSPLIT,$0
 	RET
 
 TEXT runtime·thr_new(SB),NOSPLIT,$0
-	MOVW param+0(FP), R0
-	MOVW size+4(FP), R1
+	MOVW 0(FP), R0
+	MOVW 4(FP), R1
 	MOVW $SYS_thr_new, R7
 	SWI $0
 	RET
@@ -74,7 +71,7 @@ TEXT runtime·thr_start(SB),NOSPLIT,$0
 
 // Exit the entire program (like C exit)
 TEXT runtime·exit(SB),NOSPLIT,$-8
-	MOVW code+0(FP), R0	// arg 1 exit status
+	MOVW 0(FP), R0	// arg 1 exit status
 	MOVW $SYS_exit, R7
 	SWI $0
 	MOVW.CS $0, R8 // crash on syscall failure
@@ -82,7 +79,7 @@ TEXT runtime·exit(SB),NOSPLIT,$-8
 	RET
 
 TEXT runtime·exit1(SB),NOSPLIT,$-8
-	MOVW code+0(FP), R0	// arg 1 exit status
+	MOVW 0(FP), R0	// arg 1 exit status
 	MOVW $SYS_thr_exit, R7	
 	SWI $0
 	MOVW.CS $0, R8 // crash on syscall failure
@@ -90,46 +87,42 @@ TEXT runtime·exit1(SB),NOSPLIT,$-8
 	RET
 
 TEXT runtime·open(SB),NOSPLIT,$-8
-	MOVW name+0(FP), R0	// arg 1 name
-	MOVW mode+4(FP), R1	// arg 2 mode
-	MOVW perm+8(FP), R2	// arg 3 perm
+	MOVW 0(FP), R0	// arg 1 name
+	MOVW 4(FP), R1	// arg 2 mode
+	MOVW 8(FP), R2	// arg 3 perm
 	MOVW $SYS_open, R7
 	SWI $0
-	MOVW.CS	$-1, R0
 	MOVW	R0, ret+12(FP)
 	RET
 
 TEXT runtime·read(SB),NOSPLIT,$-8
-	MOVW fd+0(FP), R0	// arg 1 fd
-	MOVW p+4(FP), R1	// arg 2 buf
-	MOVW n+8(FP), R2	// arg 3 count
+	MOVW 0(FP), R0	// arg 1 fd
+	MOVW 4(FP), R1	// arg 2 buf
+	MOVW 8(FP), R2	// arg 3 count
 	MOVW $SYS_read, R7
 	SWI $0
-	MOVW.CS	$-1, R0
 	MOVW	R0, ret+12(FP)
 	RET
 
 TEXT runtime·write(SB),NOSPLIT,$-8
-	MOVW fd+0(FP), R0	// arg 1 fd
-	MOVW p+4(FP), R1	// arg 2 buf
-	MOVW n+8(FP), R2	// arg 3 count
+	MOVW 0(FP), R0	// arg 1 fd
+	MOVW 4(FP), R1	// arg 2 buf
+	MOVW 8(FP), R2	// arg 3 count
 	MOVW $SYS_write, R7
 	SWI $0
-	MOVW.CS	$-1, R0
 	MOVW	R0, ret+12(FP)
 	RET
 
-TEXT runtime·closefd(SB),NOSPLIT,$-8
-	MOVW fd+0(FP), R0	// arg 1 fd
+TEXT runtime·close(SB),NOSPLIT,$-8
+	MOVW 0(FP), R0	// arg 1 fd
 	MOVW $SYS_close, R7
 	SWI $0
-	MOVW.CS	$-1, R0
 	MOVW	R0, ret+4(FP)
 	RET
 
 TEXT runtime·getrlimit(SB),NOSPLIT,$-8
-	MOVW kind+0(FP), R0
-	MOVW limit+4(FP), R1
+	MOVW 0(FP), R0
+	MOVW 4(FP), R1
 	MOVW $SYS_getrlimit, R7
 	SWI $0
 	MOVW	R0, ret+8(FP)
@@ -147,21 +140,10 @@ TEXT runtime·raise(SB),NOSPLIT,$8
 	SWI $0
 	RET
 
-TEXT runtime·raiseproc(SB),NOSPLIT,$0
-	// getpid
-	MOVW $SYS_getpid, R7
-	SWI $0
-	// kill(self, sig)
-				// arg 1 - pid, now in R0
-	MOVW sig+0(FP), R1	// arg 2 - signal
-	MOVW $SYS_kill, R7
-	SWI $0
-	RET
-
 TEXT runtime·setitimer(SB), NOSPLIT, $-8
-	MOVW mode+0(FP), R0
-	MOVW new+4(FP), R1
-	MOVW old+8(FP), R2
+	MOVW 0(FP), R0
+	MOVW 4(FP), R1
+	MOVW 8(FP), R2
 	MOVW $SYS_setitimer, R7
 	SWI $0
 	RET
@@ -177,9 +159,9 @@ TEXT time·now(SB), NOSPLIT, $32
 	MOVW 12(R13), R1 // sec.high
 	MOVW 16(R13), R2 // nsec
 
-	MOVW R0, sec_lo+0(FP)
-	MOVW R1, sec_hi+4(FP)
-	MOVW R2, nsec+8(FP)
+	MOVW R0, 0(FP)
+	MOVW R1, 4(FP)
+	MOVW R2, 8(FP)
 	RET
 
 // int64 nanotime(void) so really
@@ -207,9 +189,9 @@ TEXT runtime·nanotime(SB), NOSPLIT, $32
 	RET
 
 TEXT runtime·sigaction(SB),NOSPLIT,$-8
-	MOVW sig+0(FP), R0		// arg 1 sig
-	MOVW new+4(FP), R1		// arg 2 act
-	MOVW old+8(FP), R2		// arg 3 oact
+	MOVW 0(FP), R0		// arg 1 sig
+	MOVW 4(FP), R1		// arg 2 act
+	MOVW 8(FP), R2		// arg 3 oact
 	MOVW $SYS_sigaction, R7
 	SWI $0
 	MOVW.CS $0, R8 // crash on syscall failure
@@ -252,15 +234,15 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$24
 	RET
 
 TEXT runtime·mmap(SB),NOSPLIT,$16
-	MOVW addr+0(FP), R0		// arg 1 addr
-	MOVW n+4(FP), R1		// arg 2 len
-	MOVW prot+8(FP), R2		// arg 3 prot
-	MOVW flags+12(FP), R3		// arg 4 flags
+	MOVW 0(FP), R0		// arg 1 addr
+	MOVW 4(FP), R1		// arg 2 len
+	MOVW 8(FP), R2		// arg 3 prot
+	MOVW 12(FP), R3		// arg 4 flags
 	// arg 5 (fid) and arg6 (offset_lo, offset_hi) are passed on stack
 	// note the C runtime only passes the 32-bit offset_lo to us
-	MOVW fd+16(FP), R4		// arg 5
+	MOVW 16(FP), R4		// arg 5
 	MOVW R4, 4(R13)
-	MOVW off+20(FP), R5		// arg 6 lower 32-bit
+	MOVW 20(FP), R5		// arg 6 lower 32-bit
 	// the word at 8(R13) is skipped due to 64-bit argument alignment.
 	MOVW R5, 12(R13)
 	MOVW $0, R6 		// higher 32-bit for arg 6
@@ -274,8 +256,8 @@ TEXT runtime·mmap(SB),NOSPLIT,$16
 	RET
 
 TEXT runtime·munmap(SB),NOSPLIT,$0
-	MOVW addr+0(FP), R0		// arg 1 addr
-	MOVW n+4(FP), R1		// arg 2 len
+	MOVW 0(FP), R0		// arg 1 addr
+	MOVW 4(FP), R1		// arg 2 len
 	MOVW $SYS_munmap, R7
 	SWI $0
 	MOVW.CS $0, R8 // crash on syscall failure
@@ -283,9 +265,9 @@ TEXT runtime·munmap(SB),NOSPLIT,$0
 	RET
 
 TEXT runtime·madvise(SB),NOSPLIT,$0
-	MOVW addr+0(FP), R0		// arg 1 addr
-	MOVW n+4(FP), R1		// arg 2 len
-	MOVW flags+8(FP), R2		// arg 3 flags
+	MOVW 0(FP), R0		// arg 1 addr
+	MOVW 4(FP), R1		// arg 2 len
+	MOVW 8(FP), R2		// arg 3 flags
 	MOVW $SYS_madvise, R7
 	SWI $0
 	// ignore failure - maybe pages are locked
@@ -302,12 +284,15 @@ TEXT runtime·sigaltstack(SB),NOSPLIT,$-8
 
 TEXT runtime·usleep(SB),NOSPLIT,$16
 	MOVW usec+0(FP), R0
-	CALL runtime·usplitR0(SB)
+	MOVW R0, R2
+	MOVW $1000000, R1
+	DIV R1, R0
 	// 0(R13) is the saved LR, don't use it
 	MOVW R0, 4(R13) // tv_sec.low
 	MOVW $0, R0
 	MOVW R0, 8(R13) // tv_sec.high
-	MOVW $1000, R2
+	MOD R1, R2
+	MOVW $1000, R1
 	MUL R1, R2
 	MOVW R2, 12(R13) // tv_nsec
 
@@ -318,10 +303,10 @@ TEXT runtime·usleep(SB),NOSPLIT,$16
 	RET
 
 TEXT runtime·sysctl(SB),NOSPLIT,$0
-	MOVW mib+0(FP), R0	// arg 1 - name
-	MOVW miblen+4(FP), R1	// arg 2 - namelen
-	MOVW out+8(FP), R2	// arg 3 - old
-	MOVW size+12(FP), R3	// arg 4 - oldlenp
+	MOVW 0(FP), R0	// arg 1 - name
+	MOVW 4(FP), R1	// arg 2 - namelen
+	MOVW 8(FP), R2	// arg 3 - old
+	MOVW 12(FP), R3	// arg 4 - oldlenp
 	// arg 5 (newp) and arg 6 (newlen) are passed on stack
 	ADD $20, R13
 	MOVW $SYS___sysctl, R7
@@ -337,9 +322,9 @@ TEXT runtime·osyield(SB),NOSPLIT,$-4
 	RET
 
 TEXT runtime·sigprocmask(SB),NOSPLIT,$0
-	MOVW how+0(FP), R0	// arg 1 - how
-	MOVW new+4(FP), R1	// arg 2 - set
-	MOVW old+8(FP), R2	// arg 3 - oset
+	MOVW $3, R0	// arg 1 - how (SIG_SETMASK)
+	MOVW 0(FP), R1	// arg 2 - set
+	MOVW 4(FP), R2	// arg 3 - oset
 	MOVW $SYS_sigprocmask, R7
 	SWI $0
 	MOVW.CS $0, R8 // crash on syscall failure
@@ -356,10 +341,10 @@ 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
-	MOVW kq+0(FP), R0	// kq
-	MOVW ch+4(FP), R1	// changelist
-	MOVW nch+8(FP), R2	// nchanges
-	MOVW ev+12(FP), R3	// eventlist
+	MOVW 0(FP), R0	// kq
+	MOVW 4(FP), R1	// changelist
+	MOVW 8(FP), R2	// nchanges
+	MOVW 12(FP), R3	// eventlist
 	ADD $20, R13	// pass arg 5 and 6 on stack
 	MOVW $SYS_kevent, R7
 	SWI $0
@@ -370,14 +355,14 @@ TEXT runtime·kevent(SB),NOSPLIT,$0
 
 // void runtime·closeonexec(int32 fd)
 TEXT runtime·closeonexec(SB),NOSPLIT,$0
-	MOVW fd+0(FP), R0	// fd
+	MOVW 0(FP), R0	// fd
 	MOVW $2, R1	// F_SETFD
 	MOVW $1, R2	// FD_CLOEXEC
 	MOVW $SYS_fcntl, R7
 	SWI $0
 	RET
 
-TEXT runtime·casp1(SB),NOSPLIT,$0
+TEXT runtime·casp(SB),NOSPLIT,$0
 	B	runtime·cas(SB)
 
 // TODO(minux): this is only valid for ARMv6+
@@ -391,10 +376,6 @@ TEXT runtime·casp1(SB),NOSPLIT,$0
 TEXT runtime·cas(SB),NOSPLIT,$0
 	B runtime·armcas(SB)
 
-// TODO: this is only valid for ARMv7+
-TEXT ·publicationBarrier(SB),NOSPLIT,$-4-0
-	B	runtime·armPublicationBarrier(SB)
-
 // TODO(minux): this only supports ARMv6K+.
 TEXT runtime·read_tls_fallback(SB),NOSPLIT,$-4
 	WORD $0xee1d0f70 // mrc p15, 0, r0, c13, c0, 3
diff --git a/src/runtime/sys_linux_386.s b/src/runtime/sys_linux_386.s
index 98a1a0e..0f6d4bb 100644
--- a/src/runtime/sys_linux_386.s
+++ b/src/runtime/sys_linux_386.s
@@ -6,8 +6,7 @@
 // System calls and other sys.stuff for 386, Linux
 //
 
-#include "go_asm.h"
-#include "go_tls.h"
+#include "zasm_GOOS_GOARCH.h"
 #include "textflag.h"
 
 TEXT runtime·exit(SB),NOSPLIT,$0
@@ -30,19 +29,13 @@ TEXT runtime·open(SB),NOSPLIT,$0
 	MOVL	mode+4(FP), CX
 	MOVL	perm+8(FP), DX
 	CALL	*runtime·_vdso(SB)
-	CMPL	AX, $0xfffff001
-	JLS	2(PC)
-	MOVL	$-1, AX
 	MOVL	AX, ret+12(FP)
 	RET
 
-TEXT runtime·closefd(SB),NOSPLIT,$0
+TEXT runtime·close(SB),NOSPLIT,$0
 	MOVL	$6, AX		// syscall - close
 	MOVL	fd+0(FP), BX
 	CALL	*runtime·_vdso(SB)
-	CMPL	AX, $0xfffff001
-	JLS	2(PC)
-	MOVL	$-1, AX
 	MOVL	AX, ret+4(FP)
 	RET
 
@@ -52,9 +45,6 @@ TEXT runtime·write(SB),NOSPLIT,$0
 	MOVL	p+4(FP), CX
 	MOVL	n+8(FP), DX
 	CALL	*runtime·_vdso(SB)
-	CMPL	AX, $0xfffff001
-	JLS	2(PC)
-	MOVL	$-1, AX
 	MOVL	AX, ret+12(FP)
 	RET
 
@@ -64,9 +54,6 @@ TEXT runtime·read(SB),NOSPLIT,$0
 	MOVL	p+4(FP), CX
 	MOVL	n+8(FP), DX
 	CALL	*runtime·_vdso(SB)
-	CMPL	AX, $0xfffff001
-	JLS	2(PC)
-	MOVL	$-1, AX
 	MOVL	AX, ret+12(FP)
 	RET
 
@@ -96,12 +83,6 @@ TEXT runtime·usleep(SB),NOSPLIT,$8
 	CALL	*runtime·_vdso(SB)
 	RET
 
-TEXT runtime·gettid(SB),NOSPLIT,$0-4
-	MOVL	$224, AX	// syscall - gettid
-	CALL	*runtime·_vdso(SB)
-	MOVL	AX, ret+0(FP)
-	RET
-
 TEXT runtime·raise(SB),NOSPLIT,$12
 	MOVL	$224, AX	// syscall - gettid
 	CALL	*runtime·_vdso(SB)
@@ -111,15 +92,6 @@ TEXT runtime·raise(SB),NOSPLIT,$12
 	CALL	*runtime·_vdso(SB)
 	RET
 
-TEXT runtime·raiseproc(SB),NOSPLIT,$12
-	MOVL	$20, AX	// syscall - getpid
-	CALL	*runtime·_vdso(SB)
-	MOVL	AX, BX	// arg 1 pid
-	MOVL	sig+0(FP), CX	// arg 2 signal
-	MOVL	$37, AX	// syscall - kill
-	CALL	*runtime·_vdso(SB)
-	RET
-
 TEXT runtime·setitimer(SB),NOSPLIT,$0-12
 	MOVL	$104, AX			// syscall - setitimer
 	MOVL	mode+0(FP), BX
@@ -197,25 +169,43 @@ TEXT runtime·rt_sigaction(SB),NOSPLIT,$0
 	MOVL	AX, ret+16(FP)
 	RET
 
-TEXT runtime·sigfwd(SB),NOSPLIT,$12-16
-	MOVL	sig+4(FP), AX
-	MOVL	AX, 0(SP)
-	MOVL	info+8(FP), AX
-	MOVL	AX, 4(SP)
-	MOVL	ctx+12(FP), AX
-	MOVL	AX, 8(SP)
-	MOVL	fn+0(FP), AX
+TEXT runtime·sigtramp(SB),NOSPLIT,$44
+	get_tls(CX)
+
+	// check that g exists
+	MOVL	g(CX), DI
+	CMPL	DI, $0
+	JNE	6(PC)
+	MOVL	sig+0(FP), BX
+	MOVL	BX, 0(SP)
+	MOVL	$runtime·badsignal(SB), AX
 	CALL	AX
 	RET
 
-TEXT runtime·sigtramp(SB),NOSPLIT,$12
+	// save g
+	MOVL	DI, 20(SP)
+
+	// g = m->gsignal
+	MOVL	g_m(DI), BX
+	MOVL	m_gsignal(BX), BX
+	MOVL	BX, g(CX)
+
+	// copy arguments for call to sighandler
 	MOVL	sig+0(FP), BX
 	MOVL	BX, 0(SP)
 	MOVL	info+4(FP), BX
 	MOVL	BX, 4(SP)
 	MOVL	context+8(FP), BX
 	MOVL	BX, 8(SP)
-	CALL	runtime·sigtrampgo(SB)
+	MOVL	DI, 12(SP)
+
+	CALL	runtime·sighandler(SB)
+
+	// restore g
+	get_tls(CX)
+	MOVL	20(SP), BX
+	MOVL	BX, g(CX)
+
 	RET
 
 TEXT runtime·sigreturn(SB),NOSPLIT,$0
@@ -279,18 +269,18 @@ TEXT runtime·futex(SB),NOSPLIT,$0
 // int32 clone(int32 flags, void *stack, M *mp, G *gp, void (*fn)(void));
 TEXT runtime·clone(SB),NOSPLIT,$0
 	MOVL	$120, AX	// clone
-	MOVL	flags+0(FP), BX
-	MOVL	stack+4(FP), CX
+	MOVL	flags+4(SP), BX
+	MOVL	stack+8(SP), CX
 	MOVL	$0, DX	// parent tid ptr
 	MOVL	$0, DI	// child tid ptr
 
 	// Copy mp, gp, fn off parent stack for use by child.
 	SUBL	$16, CX
-	MOVL	mm+8(FP), SI
+	MOVL	mm+12(SP), SI
 	MOVL	SI, 0(CX)
-	MOVL	gg+12(FP), SI
+	MOVL	gg+16(SP), SI
 	MOVL	SI, 4(CX)
-	MOVL	fn+16(FP), SI
+	MOVL	fn+20(SP), SI
 	MOVL	SI, 8(CX)
 	MOVL	$1234, 12(CX)
 
@@ -307,7 +297,7 @@ TEXT runtime·clone(SB),NOSPLIT,$0
 	RET
 
 	// Paranoia: check that SP is as we expect.
-	MOVL	12(SP), BP
+	MOVL	mm+8(FP), BP
 	CMPL	BP, $1234
 	JEQ	2(PC)
 	INT	$3
@@ -316,14 +306,10 @@ TEXT runtime·clone(SB),NOSPLIT,$0
 	MOVL	$224, AX
 	CALL	*runtime·_vdso(SB)
 
-	MOVL	0(SP), BX	    // m
-	MOVL	4(SP), DX	    // g
-	MOVL	8(SP), SI	    // fn
-
-	CMPL	BX, $0
-	JEQ	nog
-	CMPL	DX, $0
-	JEQ	nog
+	// In child on new stack.  Reload registers (paranoia).
+	MOVL	0(SP), BX	// m
+	MOVL	flags+0(FP), DX	// g
+	MOVL	stk+4(FP), SI	// fn
 
 	MOVL	AX, m_procid(BX)	// save tid as m->procid
 
@@ -357,7 +343,6 @@ TEXT runtime·clone(SB),NOSPLIT,$0
 	CALL	runtime·emptyfunc(SB)
 	POPAL
 
-nog:
 	CALL	SI	// fn()
 	CALL	runtime·exit1(SB)
 	MOVL	$0x1234, 0x1005
@@ -403,16 +388,16 @@ TEXT runtime·setldt(SB),NOSPLIT,$32
 	 * When linking against the system libraries,
 	 * 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 -4(GS).
+	 * 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(TLS) into -4(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 -4(GS) maps to 0(address).
-	 * Also, the final 0(GS) (current 4(CX)) has to point
+	 * so that -8(GS) maps to 0(address).
+	 * Also, the final 0(GS) (current 8(CX)) has to point
 	 * to itself, to mimic ELF.
 	 */
-	ADDL	$0x4, CX	// address
+	ADDL	$0x8, CX	// address
 	MOVL	CX, 0(CX)
 
 	// set up user_desc
diff --git a/src/runtime/sys_linux_amd64.s b/src/runtime/sys_linux_amd64.s
index 59c21c5..33b91e8 100644
--- a/src/runtime/sys_linux_amd64.s
+++ b/src/runtime/sys_linux_amd64.s
@@ -6,8 +6,7 @@
 // System calls and other sys.stuff for AMD64, Linux
 //
 
-#include "go_asm.h"
-#include "go_tls.h"
+#include "zasm_GOOS_GOARCH.h"
 #include "textflag.h"
 
 TEXT runtime·exit(SB),NOSPLIT,$0-4
@@ -28,19 +27,13 @@ TEXT runtime·open(SB),NOSPLIT,$0-20
 	MOVL	perm+12(FP), DX
 	MOVL	$2, AX			// syscall entry
 	SYSCALL
-	CMPQ	AX, $0xfffffffffffff001
-	JLS	2(PC)
-	MOVL	$-1, AX
 	MOVL	AX, ret+16(FP)
 	RET
 
-TEXT runtime·closefd(SB),NOSPLIT,$0-12
+TEXT runtime·close(SB),NOSPLIT,$0-12
 	MOVL	fd+0(FP), DI
 	MOVL	$3, AX			// syscall entry
 	SYSCALL
-	CMPQ	AX, $0xfffffffffffff001
-	JLS	2(PC)
-	MOVL	$-1, AX
 	MOVL	AX, ret+8(FP)
 	RET
 
@@ -50,9 +43,6 @@ TEXT runtime·write(SB),NOSPLIT,$0-28
 	MOVL	n+16(FP), DX
 	MOVL	$1, AX			// syscall entry
 	SYSCALL
-	CMPQ	AX, $0xfffffffffffff001
-	JLS	2(PC)
-	MOVL	$-1, AX
 	MOVL	AX, ret+24(FP)
 	RET
 
@@ -62,9 +52,6 @@ TEXT runtime·read(SB),NOSPLIT,$0-28
 	MOVL	n+16(FP), DX
 	MOVL	$0, AX			// syscall entry
 	SYSCALL
-	CMPQ	AX, $0xfffffffffffff001
-	JLS	2(PC)
-	MOVL	$-1, AX
 	MOVL	AX, ret+24(FP)
 	RET
 
@@ -94,12 +81,6 @@ TEXT runtime·usleep(SB),NOSPLIT,$16
 	SYSCALL
 	RET
 
-TEXT runtime·gettid(SB),NOSPLIT,$0-4
-	MOVL	$186, AX	// syscall - gettid
-	SYSCALL
-	MOVL	AX, ret+0(FP)
-	RET
-
 TEXT runtime·raise(SB),NOSPLIT,$0
 	MOVL	$186, AX	// syscall - gettid
 	SYSCALL
@@ -109,15 +90,6 @@ TEXT runtime·raise(SB),NOSPLIT,$0
 	SYSCALL
 	RET
 
-TEXT runtime·raiseproc(SB),NOSPLIT,$0
-	MOVL	$39, AX	// syscall - getpid
-	SYSCALL
-	MOVL	AX, DI	// arg 1 pid
-	MOVL	sig+0(FP), SI	// arg 2
-	MOVL	$62, AX	// syscall - kill
-	SYSCALL
-	RET
-
 TEXT runtime·setitimer(SB),NOSPLIT,$0-24
 	MOVL	mode+0(FP), DI
 	MOVQ	new+8(FP), SI
@@ -143,7 +115,7 @@ TEXT time·now(SB),NOSPLIT,$16
 	// That leaves 104 for the gettime code to use. Hope that's enough!
 	MOVQ	runtime·__vdso_clock_gettime_sym(SB), AX
 	CMPQ	AX, $0
-	JEQ	fallback
+	JEQ	fallback_gtod
 	MOVL	$0, DI // CLOCK_REALTIME
 	LEAQ	0(SP), SI
 	CALL	AX
@@ -152,7 +124,7 @@ TEXT time·now(SB),NOSPLIT,$16
 	MOVQ	AX, sec+0(FP)
 	MOVL	DX, nsec+8(FP)
 	RET
-fallback:
+fallback_gtod:
 	LEAQ	0(SP), DI
 	MOVQ	$0, SI
 	MOVQ	runtime·__vdso_gettimeofday_sym(SB), AX
@@ -169,7 +141,7 @@ TEXT runtime·nanotime(SB),NOSPLIT,$16
 	// See comment above in time.now.
 	MOVQ	runtime·__vdso_clock_gettime_sym(SB), AX
 	CMPQ	AX, $0
-	JEQ	fallback
+	JEQ	fallback_gtod_nt
 	MOVL	$1, DI // CLOCK_MONOTONIC
 	LEAQ	0(SP), SI
 	CALL	AX
@@ -181,7 +153,7 @@ TEXT runtime·nanotime(SB),NOSPLIT,$16
 	ADDQ	DX, AX
 	MOVQ	AX, ret+0(FP)
 	RET
-fallback:
+fallback_gtod_nt:
 	LEAQ	0(SP), DI
 	MOVQ	$0, SI
 	MOVQ	runtime·__vdso_gettimeofday_sym(SB), AX
@@ -218,20 +190,37 @@ TEXT runtime·rt_sigaction(SB),NOSPLIT,$0-36
 	MOVL	AX, ret+32(FP)
 	RET
 
-TEXT runtime·sigfwd(SB),NOSPLIT,$0-32
-	MOVL	sig+8(FP), DI
-	MOVQ	info+16(FP), SI
-	MOVQ	ctx+24(FP), DX
-	MOVQ	fn+0(FP), AX
+TEXT runtime·sigtramp(SB),NOSPLIT,$64
+	get_tls(BX)
+
+	// check that g exists
+	MOVQ	g(BX), R10
+	CMPQ	R10, $0
+	JNE	5(PC)
+	MOVQ	DI, 0(SP)
+	MOVQ	$runtime·badsignal(SB), AX
 	CALL	AX
 	RET
 
-TEXT runtime·sigtramp(SB),NOSPLIT,$24
-	MOVQ	DI, 0(SP)   // signum
-	MOVQ	SI, 8(SP)   // info
-	MOVQ	DX, 16(SP)  // ctx
-	MOVQ	$runtime·sigtrampgo(SB), AX
-	CALL AX
+	// save g
+	MOVQ	R10, 40(SP)
+
+	// g = m->gsignal
+	MOVQ	g_m(R10), BP
+	MOVQ	m_gsignal(BP), BP
+	MOVQ	BP, g(BX)
+
+	MOVQ	DI, 0(SP)
+	MOVQ	SI, 8(SP)
+	MOVQ	DX, 16(SP)
+	MOVQ	R10, 24(SP)
+
+	CALL	runtime·sighandler(SB)
+
+	// restore g
+	get_tls(BX)
+	MOVQ	40(SP), R10
+	MOVQ	R10, g(BX)
 	RET
 
 TEXT runtime·sigreturn(SB),NOSPLIT,$0
@@ -291,16 +280,14 @@ TEXT runtime·futex(SB),NOSPLIT,$0
 
 // int32 clone(int32 flags, void *stack, M *mp, G *gp, void (*fn)(void));
 TEXT runtime·clone(SB),NOSPLIT,$0
-	MOVL	flags+0(FP), DI
-	MOVQ	stack+8(FP), SI
-	MOVQ	$0, DX
-	MOVQ	$0, R10
+	MOVL	flags+8(SP), DI
+	MOVQ	stack+16(SP), SI
 
 	// Copy mp, gp, fn off parent stack for use by child.
 	// Careful: Linux system call clobbers CX and R11.
-	MOVQ	mp+16(FP), R8
-	MOVQ	gp+24(FP), R9
-	MOVQ	fn+32(FP), R12
+	MOVQ	mm+24(SP), R8
+	MOVQ	gg+32(SP), R9
+	MOVQ	fn+40(SP), R12
 
 	MOVL	$56, AX
 	SYSCALL
@@ -314,12 +301,6 @@ TEXT runtime·clone(SB),NOSPLIT,$0
 	// In child, on new stack.
 	MOVQ	SI, SP
 
-	// If g or m are nil, skip Go-related setup.
-	CMPQ	R8, $0    // m
-	JEQ	nog
-	CMPQ	R9, $0    // g
-	JEQ	nog
-
 	// Initialize m->procid to Linux tid
 	MOVL	$186, AX	// gettid
 	SYSCALL
@@ -335,11 +316,10 @@ TEXT runtime·clone(SB),NOSPLIT,$0
 	MOVQ	R9, g(CX)
 	CALL	runtime·stackcheck(SB)
 
-nog:
 	// Call fn
 	CALL	R12
 
-	// It shouldn't return.  If it does, exit that thread.
+	// It shouldn't return.  If it does, exit
 	MOVL	$111, DI
 	MOVL	$60, AX
 	SYSCALL
@@ -357,7 +337,7 @@ TEXT runtime·sigaltstack(SB),NOSPLIT,$-8
 
 // set tls base to DI
 TEXT runtime·settls(SB),NOSPLIT,$32
-	ADDQ	$8, DI	// ELF wants to use -8(FS)
+	ADDQ	$16, DI	// ELF wants to use -16(FS), -8(FS)
 
 	MOVQ	DI, SI
 	MOVQ	$0x1002, DI	// ARCH_SET_FS
diff --git a/src/runtime/sys_linux_arm.s b/src/runtime/sys_linux_arm.s
index 29eb8eb..bd285f3 100644
--- a/src/runtime/sys_linux_arm.s
+++ b/src/runtime/sys_linux_arm.s
@@ -6,8 +6,7 @@
 // System calls and other sys.stuff for arm, Linux
 //
 
-#include "go_asm.h"
-#include "go_tls.h"
+#include "zasm_GOOS_GOARCH.h"
 #include "textflag.h"
 
 // for EABI, as we don't support OABI
@@ -18,8 +17,6 @@
 #define SYS_write (SYS_BASE + 4)
 #define SYS_open (SYS_BASE + 5)
 #define SYS_close (SYS_BASE + 6)
-#define SYS_getpid (SYS_BASE + 20)
-#define SYS_kill (SYS_BASE + 37)
 #define SYS_gettimeofday (SYS_BASE + 78)
 #define SYS_clone (SYS_BASE + 120)
 #define SYS_rt_sigreturn (SYS_BASE + 173)
@@ -45,68 +42,53 @@
 #define SYS_epoll_wait (SYS_BASE + 252)
 #define SYS_epoll_create1 (SYS_BASE + 357)
 #define SYS_fcntl (SYS_BASE + 55)
-#define SYS_access (SYS_BASE + 33)
-#define SYS_connect (SYS_BASE + 283)
-#define SYS_socket (SYS_BASE + 281)
 
 #define ARM_BASE (SYS_BASE + 0x0f0000)
 
 TEXT runtime·open(SB),NOSPLIT,$0
-	MOVW	name+0(FP), R0
-	MOVW	mode+4(FP), R1
-	MOVW	perm+8(FP), R2
+	MOVW	0(FP), R0
+	MOVW	4(FP), R1
+	MOVW	8(FP), R2
 	MOVW	$SYS_open, R7
 	SWI	$0
-	MOVW	$0xfffff001, R1
-	CMP	R1, R0
-	MOVW.HI	$-1, R0
 	MOVW	R0, ret+12(FP)
 	RET
 
-TEXT runtime·closefd(SB),NOSPLIT,$0
-	MOVW	fd+0(FP), R0
+TEXT runtime·close(SB),NOSPLIT,$0
+	MOVW	0(FP), R0
 	MOVW	$SYS_close, R7
 	SWI	$0
-	MOVW	$0xfffff001, R1
-	CMP	R1, R0
-	MOVW.HI	$-1, R0
 	MOVW	R0, ret+4(FP)
 	RET
 
 TEXT runtime·write(SB),NOSPLIT,$0
-	MOVW	fd+0(FP), R0
-	MOVW	p+4(FP), R1
-	MOVW	n+8(FP), R2
+	MOVW	0(FP), R0
+	MOVW	4(FP), R1
+	MOVW	8(FP), R2
 	MOVW	$SYS_write, R7
 	SWI	$0
-	MOVW	$0xfffff001, R1
-	CMP	R1, R0
-	MOVW.HI	$-1, R0
 	MOVW	R0, ret+12(FP)
 	RET
 
 TEXT runtime·read(SB),NOSPLIT,$0
-	MOVW	fd+0(FP), R0
-	MOVW	p+4(FP), R1
-	MOVW	n+8(FP), R2
+	MOVW	0(FP), R0
+	MOVW	4(FP), R1
+	MOVW	8(FP), R2
 	MOVW	$SYS_read, R7
 	SWI	$0
-	MOVW	$0xfffff001, R1
-	CMP	R1, R0
-	MOVW.HI	$-1, R0
 	MOVW	R0, ret+12(FP)
 	RET
 
 TEXT runtime·getrlimit(SB),NOSPLIT,$0
-	MOVW	kind+0(FP), R0
-	MOVW	limit+4(FP), R1
+	MOVW	0(FP), R0
+	MOVW	4(FP), R1
 	MOVW	$SYS_ugetrlimit, R7
 	SWI	$0
 	MOVW	R0, ret+8(FP)
 	RET
 
 TEXT runtime·exit(SB),NOSPLIT,$-4
-	MOVW	code+0(FP), R0
+	MOVW	0(FP), R0
 	MOVW	$SYS_exit_group, R7
 	SWI	$0
 	MOVW	$1234, R0
@@ -114,19 +96,13 @@ TEXT runtime·exit(SB),NOSPLIT,$-4
 	MOVW	R0, (R1)	// fail hard
 
 TEXT runtime·exit1(SB),NOSPLIT,$-4
-	MOVW	code+0(FP), R0
+	MOVW	0(FP), R0
 	MOVW	$SYS_exit, R7
 	SWI	$0
 	MOVW	$1234, R0
 	MOVW	$1003, R1
 	MOVW	R0, (R1)	// fail hard
 
-TEXT runtime·gettid(SB),NOSPLIT,$0-4
-	MOVW	$SYS_gettid, R7
-	SWI	$0
-	MOVW	R0, ret+0(FP)
-	RET
-
 TEXT	runtime·raise(SB),NOSPLIT,$-4
 	MOVW	$SYS_gettid, R7
 	SWI	$0
@@ -136,22 +112,13 @@ TEXT	runtime·raise(SB),NOSPLIT,$-4
 	SWI	$0
 	RET
 
-TEXT	runtime·raiseproc(SB),NOSPLIT,$-4
-	MOVW	$SYS_getpid, R7
-	SWI	$0
-	// arg 1 tid already in R0 from getpid
-	MOVW	sig+0(FP), R1	// arg 2 - signal
-	MOVW	$SYS_kill, R7
-	SWI	$0
-	RET
-
 TEXT runtime·mmap(SB),NOSPLIT,$0
-	MOVW	addr+0(FP), R0
-	MOVW	n+4(FP), R1
-	MOVW	prot+8(FP), R2
-	MOVW	flags+12(FP), R3
-	MOVW	fd+16(FP), R4
-	MOVW	off+20(FP), R5
+	MOVW	0(FP), R0
+	MOVW	4(FP), R1
+	MOVW	8(FP), R2
+	MOVW	12(FP), R3
+	MOVW	16(FP), R4
+	MOVW	20(FP), R5
 	MOVW	$SYS_mmap2, R7
 	SWI	$0
 	MOVW	$0xfffff001, R6
@@ -161,8 +128,8 @@ TEXT runtime·mmap(SB),NOSPLIT,$0
 	RET
 
 TEXT runtime·munmap(SB),NOSPLIT,$0
-	MOVW	addr+0(FP), R0
-	MOVW	n+4(FP), R1
+	MOVW	0(FP), R0
+	MOVW	4(FP), R1
 	MOVW	$SYS_munmap, R7
 	SWI	$0
 	MOVW	$0xfffff001, R6
@@ -172,26 +139,26 @@ TEXT runtime·munmap(SB),NOSPLIT,$0
 	RET
 
 TEXT runtime·madvise(SB),NOSPLIT,$0
-	MOVW	addr+0(FP), R0
-	MOVW	n+4(FP), R1
-	MOVW	flags+8(FP), R2
+	MOVW	0(FP), R0
+	MOVW	4(FP), R1
+	MOVW	8(FP), R2
 	MOVW	$SYS_madvise, R7
 	SWI	$0
 	// ignore failure - maybe pages are locked
 	RET
 
 TEXT runtime·setitimer(SB),NOSPLIT,$0
-	MOVW	mode+0(FP), R0
-	MOVW	new+4(FP), R1
-	MOVW	old+8(FP), R2
+	MOVW	0(FP), R0
+	MOVW	4(FP), R1
+	MOVW	8(FP), R2
 	MOVW	$SYS_setitimer, R7
 	SWI	$0
 	RET
 
 TEXT runtime·mincore(SB),NOSPLIT,$0
-	MOVW	addr+0(FP), R0
-	MOVW	n+4(FP), R1
-	MOVW	dst+8(FP), R2
+	MOVW	0(FP), R0
+	MOVW	4(FP), R1
+	MOVW	8(FP), R2
 	MOVW	$SYS_mincore, R7
 	SWI	$0
 	MOVW	R0, ret+12(FP)
@@ -206,10 +173,10 @@ TEXT time·now(SB), NOSPLIT, $32
 	MOVW	8(R13), R0  // sec
 	MOVW	12(R13), R2  // nsec
 	
-	MOVW	R0, sec+0(FP)
+	MOVW	R0, 0(FP)
 	MOVW	$0, R1
-	MOVW	R1, loc+4(FP)
-	MOVW	R2, nsec+8(FP)
+	MOVW	R1, 4(FP)
+	MOVW	R2, 8(FP)
 	RET	
 
 // int64 nanotime(void)
@@ -235,18 +202,18 @@ TEXT runtime·nanotime(SB),NOSPLIT,$32
 // int32 futex(int32 *uaddr, int32 op, int32 val,
 //	struct timespec *timeout, int32 *uaddr2, int32 val2);
 TEXT runtime·futex(SB),NOSPLIT,$0
-	// TODO: Rewrite to use FP references. Vet complains.
-	MOVW	4(R13), R0
-	MOVW	8(R13), R1
-	MOVW	12(R13), R2
-	MOVW	16(R13), R3
-	MOVW	20(R13), R4
-	MOVW	24(R13), R5
+	MOVW	4(SP), R0
+	MOVW	8(SP), R1
+	MOVW	12(SP), R2
+	MOVW	16(SP), R3
+	MOVW	20(SP), R4
+	MOVW	24(SP), R5
 	MOVW	$SYS_futex, R7
 	SWI	$0
 	MOVW	R0, ret+24(FP)
 	RET
 
+
 // int32 clone(int32 flags, void *stack, M *mp, G *gp, void (*fn)(void));
 TEXT runtime·clone(SB),NOSPLIT,$0
 	MOVW	flags+0(FP), R0
@@ -284,15 +251,8 @@ TEXT runtime·clone(SB),NOSPLIT,$0
 	BEQ	2(PC)
 	BL	runtime·abort(SB)
 
-	MOVW	0(R13), R8    // m
-	MOVW	4(R13), R0    // g
-
-	CMP	$0, R8
-	BEQ	nog
-	CMP	$0, R0
-	BEQ	nog
-
-	MOVW	R0, g
+	MOVW	4(R13), g
+	MOVW	0(R13), R8
 	MOVW	R8, g_m(g)
 
 	// paranoia; check they are not nil
@@ -307,25 +267,23 @@ TEXT runtime·clone(SB),NOSPLIT,$0
 	MOVW	g_m(g), R8
 	MOVW	R0, m_procid(R8)
 
-nog:
 	// Call fn
 	MOVW	8(R13), R0
 	MOVW	$16(R13), R13
 	BL	(R0)
 
-	// It shouldn't return.  If it does, exit that thread.
-	SUB	$16, R13 // restore the stack pointer to avoid memory corruption
 	MOVW	$0, R0
 	MOVW	R0, 4(R13)
 	BL	runtime·exit1(SB)
 
+	// It shouldn't return
 	MOVW	$1234, R0
 	MOVW	$1005, R1
 	MOVW	R0, (R1)
 
 TEXT runtime·sigaltstack(SB),NOSPLIT,$0
-	MOVW	new+0(FP), R0
-	MOVW	old+4(FP), R1
+	MOVW	0(FP), R0
+	MOVW	4(FP), R1
 	MOVW	$SYS_sigaltstack, R7
 	SWI	$0
 	MOVW	$0xfffff001, R6
@@ -334,15 +292,7 @@ TEXT runtime·sigaltstack(SB),NOSPLIT,$0
 	MOVW.HI	R8, (R8)
 	RET
 
-TEXT runtime·sigfwd(SB),NOSPLIT,$0-16
-	MOVW	sig+4(FP), R0
-	MOVW	info+8(FP), R1
-	MOVW	ctx+12(FP), R2
-	MOVW	fn+0(FP), R11
-	BL	(R11)
-	RET
-
-TEXT runtime·sigtramp(SB),NOSPLIT,$12
+TEXT runtime·sigtramp(SB),NOSPLIT,$24
 	// this might be called in external code context,
 	// where g is not set.
 	// first save R0, because runtime·load_g will clobber it
@@ -351,26 +301,48 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$12
 	CMP 	$0, R0
 	BL.NE	runtime·load_g(SB)
 
+	CMP 	$0, g
+	BNE 	4(PC)
+	// signal number is already prepared in 4(R13)
+	MOVW  	$runtime·badsignal(SB), R11
+	BL	(R11)
+	RET
+
+	// save g
+	MOVW	g, R3
+	MOVW	g, 20(R13)
+
+	// g = m->gsignal
+	MOVW	g_m(g), R8
+	MOVW	m_gsignal(R8), g
+
+	// copy arguments for call to sighandler
+	// R0 is already saved above
 	MOVW	R1, 8(R13)
 	MOVW	R2, 12(R13)
-	MOVW  	$runtime·sigtrampgo(SB), R11
-	BL	(R11)
+	MOVW	R3, 16(R13)
+
+	BL	runtime·sighandler(SB)
+
+	// restore g
+	MOVW	20(R13), g
+
 	RET
 
 TEXT runtime·rtsigprocmask(SB),NOSPLIT,$0
-	MOVW	sig+0(FP), R0
-	MOVW	new+4(FP), R1
-	MOVW	old+8(FP), R2
-	MOVW	size+12(FP), R3
+	MOVW	0(FP), R0
+	MOVW	4(FP), R1
+	MOVW	8(FP), R2
+	MOVW	12(FP), R3
 	MOVW	$SYS_rt_sigprocmask, R7
 	SWI	$0
 	RET
 
 TEXT runtime·rt_sigaction(SB),NOSPLIT,$0
-	MOVW	sig+0(FP), R0
-	MOVW	new+4(FP), R1
-	MOVW	old+8(FP), R2
-	MOVW	size+12(FP), R3
+	MOVW	0(FP), R0
+	MOVW	4(FP), R1
+	MOVW	8(FP), R2
+	MOVW	12(FP), R3
 	MOVW	$SYS_rt_sigaction, R7
 	SWI	$0
 	MOVW	R0, ret+16(FP)
@@ -378,14 +350,17 @@ TEXT runtime·rt_sigaction(SB),NOSPLIT,$0
 
 TEXT runtime·usleep(SB),NOSPLIT,$12
 	MOVW	usec+0(FP), R0
-	CALL	runtime·usplitR0(SB)
-	MOVW	R0, 4(R13)
-	MOVW	R1, 8(R13)
+	MOVW	R0, R1
+	MOVW	$1000000, R2
+	DIV	R2, R0
+	MOD	R2, R1
+	MOVW	R0, 4(SP)
+	MOVW	R1, 8(SP)
 	MOVW	$0, R0
 	MOVW	$0, R1
 	MOVW	$0, R2
 	MOVW	$0, R3
-	MOVW	$4(R13), R4
+	MOVW	$4(SP), R4
 	MOVW	$SYS_select, R7
 	SWI	$0
 	RET
@@ -393,57 +368,41 @@ TEXT runtime·usleep(SB),NOSPLIT,$12
 // Use kernel version instead of native armcas in asm_arm.s.
 // See ../sync/atomic/asm_linux_arm.s for details.
 TEXT cas<>(SB),NOSPLIT,$0
-	MOVW	$0xffff0fc0, R15 // R15 is hardware PC.
+	MOVW	$0xffff0fc0, PC
 
 TEXT runtime·cas(SB),NOSPLIT,$0
 	MOVW	ptr+0(FP), R2
 	MOVW	old+4(FP), R0
-loop:
+casagain:
 	MOVW	new+8(FP), R1
 	BL	cas<>(SB)
-	BCC	check
+	BCC	cascheck
 	MOVW	$1, R0
 	MOVB	R0, ret+12(FP)
 	RET
-check:
+cascheck:
 	// Kernel lies; double-check.
 	MOVW	ptr+0(FP), R2
 	MOVW	old+4(FP), R0
 	MOVW	0(R2), R3
 	CMP	R0, R3
-	BEQ	loop
+	BEQ	casagain
 	MOVW	$0, R0
 	MOVB	R0, ret+12(FP)
 	RET
 
-TEXT runtime·casp1(SB),NOSPLIT,$0
+TEXT runtime·casp(SB),NOSPLIT,$0
 	B	runtime·cas(SB)
 
-// As for cas, memory barriers are complicated on ARM, but the kernel
-// provides a user helper. ARMv5 does not support SMP and has no
-// memory barrier instruction at all. ARMv6 added SMP support and has
-// a memory barrier, but it requires writing to a coprocessor
-// register. ARMv7 introduced the DMB instruction, but it's expensive
-// even on single-core devices. The kernel helper takes care of all of
-// this for us.
-
-TEXT publicationBarrier<>(SB),NOSPLIT,$0
-	// void __kuser_memory_barrier(void);
-	MOVW	$0xffff0fa0, R15 // R15 is hardware PC.
-
-TEXT ·publicationBarrier(SB),NOSPLIT,$0
-	BL	publicationBarrier<>(SB)
-	RET
-
 TEXT runtime·osyield(SB),NOSPLIT,$0
 	MOVW	$SYS_sched_yield, R7
 	SWI	$0
 	RET
 
 TEXT runtime·sched_getaffinity(SB),NOSPLIT,$0
-	MOVW	pid+0(FP), R0
-	MOVW	len+4(FP), R1
-	MOVW	buf+8(FP), R2
+	MOVW	0(FP), R0
+	MOVW	4(FP), R1
+	MOVW	8(FP), R2
 	MOVW	$SYS_sched_getaffinity, R7
 	SWI	$0
 	MOVW	R0, ret+12(FP)
@@ -451,7 +410,7 @@ TEXT runtime·sched_getaffinity(SB),NOSPLIT,$0
 
 // int32 runtime·epollcreate(int32 size)
 TEXT runtime·epollcreate(SB),NOSPLIT,$0
-	MOVW	size+0(FP), R0
+	MOVW	0(FP), R0
 	MOVW	$SYS_epoll_create, R7
 	SWI	$0
 	MOVW	R0, ret+4(FP)
@@ -459,7 +418,7 @@ TEXT runtime·epollcreate(SB),NOSPLIT,$0
 
 // int32 runtime·epollcreate1(int32 flags)
 TEXT runtime·epollcreate1(SB),NOSPLIT,$0
-	MOVW	flags+0(FP), R0
+	MOVW	0(FP), R0
 	MOVW	$SYS_epoll_create1, R7
 	SWI	$0
 	MOVW	R0, ret+4(FP)
@@ -478,10 +437,10 @@ TEXT runtime·epollctl(SB),NOSPLIT,$0
 
 // int32 runtime·epollwait(int32 epfd, EpollEvent *ev, int32 nev, int32 timeout)
 TEXT runtime·epollwait(SB),NOSPLIT,$0
-	MOVW	epfd+0(FP), R0
-	MOVW	ev+4(FP), R1
-	MOVW	nev+8(FP), R2
-	MOVW	timeout+12(FP), R3
+	MOVW	0(FP), R0
+	MOVW	4(FP), R1
+	MOVW	8(FP), R2
+	MOVW	12(FP), R3
 	MOVW	$SYS_epoll_wait, R7
 	SWI	$0
 	MOVW	R0, ret+16(FP)
@@ -489,7 +448,7 @@ TEXT runtime·epollwait(SB),NOSPLIT,$0
 
 // void runtime·closeonexec(int32 fd)
 TEXT runtime·closeonexec(SB),NOSPLIT,$0
-	MOVW	fd+0(FP), R0	// fd
+	MOVW	0(FP), R0	// fd
 	MOVW	$2, R1	// F_SETFD
 	MOVW	$1, R2	// FD_CLOEXEC
 	MOVW	$SYS_fcntl, R7
@@ -500,29 +459,3 @@ TEXT runtime·closeonexec(SB),NOSPLIT,$0
 TEXT runtime·read_tls_fallback(SB),NOSPLIT,$-4
 	MOVW	$0xffff0fe0, R0
 	B	(R0)
-
-TEXT runtime·access(SB),NOSPLIT,$0
-	MOVW	name+0(FP), R0
-	MOVW	mode+4(FP), R1
-	MOVW	$SYS_access, R7
-	SWI	$0
-	MOVW	R0, ret+8(FP)
-	RET
-
-TEXT runtime·connect(SB),NOSPLIT,$0
-	MOVW	fd+0(FP), R0
-	MOVW	addr+4(FP), R1
-	MOVW	addrlen+8(FP), R2
-	MOVW	$SYS_connect, R7
-	SWI	$0
-	MOVW	R0, ret+12(FP)
-	RET
-
-TEXT runtime·socket(SB),NOSPLIT,$0
-	MOVW	domain+0(FP), R0
-	MOVW	type+4(FP), R1
-	MOVW	protocol+8(FP), R2
-	MOVW	$SYS_socket, R7
-	SWI	$0
-	MOVW	R0, ret+12(FP)
-	RET
diff --git a/src/runtime/sys_nacl_386.s b/src/runtime/sys_nacl_386.s
index bf2d36e..47985f3 100644
--- a/src/runtime/sys_nacl_386.s
+++ b/src/runtime/sys_nacl_386.s
@@ -2,8 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-#include "go_asm.h"
-#include "go_tls.h"
+#include "zasm_GOOS_GOARCH.h"
 #include "textflag.h"
 #include "syscall_nacl.h"
 
@@ -33,7 +32,7 @@ TEXT runtime·open(SB),NOSPLIT,$12
 	MOVL AX, ret+12(FP)
 	RET
 
-TEXT runtime·closefd(SB),NOSPLIT,$4
+TEXT runtime·close(SB),NOSPLIT,$4
 	MOVL fd+0(FP), AX
 	MOVL AX, 0(SP)
 	NACL_SYSCALL(SYS_close)
@@ -294,7 +293,7 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$0
 	MOVL	$0, 0(SP)
 	MOVL	$runtime·badsignal(SB), AX
 	CALL	AX
-	JMP 	ret
+	JMP 	sigtramp_ret
 
 	// save g
 	MOVL	DI, 20(SP)
@@ -318,11 +317,11 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$0
 	MOVL	20(SP), BX
 	MOVL	BX, g(CX)
 
-ret:
+sigtramp_ret:
 	// Enable exceptions again.
 	NACL_SYSCALL(SYS_exception_clear_flag)
 
-	// NaCl has abdicated its traditional operating system responsibility
+	// 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
@@ -362,12 +361,3 @@ ret:
 	// 36(BP) is saved EFLAGS, never to be seen again
 	MOVL	32(BP), BP // saved PC
 	JMP	BP
-
-// func getRandomData([]byte)
-TEXT runtime·getRandomData(SB),NOSPLIT,$8-12
-	MOVL buf+0(FP), AX
-	MOVL AX, 0(SP)
-	MOVL len+4(FP), AX
-	MOVL AX, 4(SP)
-	NACL_SYSCALL(SYS_get_random_bytes)
-	RET
diff --git a/src/runtime/sys_nacl_amd64p32.s b/src/runtime/sys_nacl_amd64p32.s
index 0b29c9f..4eb4aac 100644
--- a/src/runtime/sys_nacl_amd64p32.s
+++ b/src/runtime/sys_nacl_amd64p32.s
@@ -2,8 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-#include "go_asm.h"
-#include "go_tls.h"
+#include "zasm_GOOS_GOARCH.h"
 #include "textflag.h"
 #include "syscall_nacl.h"
 
@@ -32,7 +31,7 @@ TEXT runtime·open(SB),NOSPLIT,$0
 	MOVL AX, ret+16(FP)
 	RET
 
-TEXT runtime·closefd(SB),NOSPLIT,$0
+TEXT runtime·close(SB),NOSPLIT,$0
 	MOVL fd+0(FP), DI
 	NACL_SYSCALL(SYS_close)
 	MOVL AX, ret+8(FP)
@@ -94,13 +93,13 @@ playback:
 	MOVL n+8(FP), DX
 	BSWAPL DX
 	MOVL DX, 12(SP)
-	MOVL fd+0(FP), DI
+	MOVL $1, DI // standard output
 	MOVL SP, SI
 	MOVL $16, DX
 	NACL_SYSCALL(SYS_write)
 
 	// Write actual data.
-	MOVL fd+0(FP), DI
+	MOVL $1, DI // standard output
 	MOVL p+4(FP), SI
 	MOVL n+8(FP), DX
 	NACL_SYSCALL(SYS_write)
@@ -339,6 +338,7 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$80
 	MOVL	20(SP), BX
 	MOVL	BX, g(CX)
 
+sigtramp_ret:
 	// Enable exceptions again.
 	NACL_SYSCALL(SYS_exception_clear_flag)
 
@@ -412,13 +412,6 @@ nog:
 // cannot do real signal handling yet, because gsignal has not been allocated.
 MOVL $1, DI; NACL_SYSCALL(SYS_exit)
 
-// func getRandomData([]byte)
-TEXT runtime·getRandomData(SB),NOSPLIT,$0-12
-	MOVL buf+0(FP), DI
-	MOVL len+4(FP), SI
-	NACL_SYSCALL(SYS_get_random_bytes)
-	RET
-
 TEXT runtime·nacl_sysinfo(SB),NOSPLIT,$16
 /*
 	MOVL	di+0(FP), DI
diff --git a/src/runtime/sys_nacl_arm.s b/src/runtime/sys_nacl_arm.s
index cf4804f..d354ab4 100644
--- a/src/runtime/sys_nacl_arm.s
+++ b/src/runtime/sys_nacl_arm.s
@@ -2,8 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-#include "go_asm.h"
-#include "go_tls.h"
+#include "zasm_GOOS_GOARCH.h"
 #include "textflag.h"
 #include "syscall_nacl.h"
 
@@ -28,7 +27,7 @@ TEXT runtime·open(SB),NOSPLIT,$0
 	MOVW	R0, ret+12(FP)
 	RET
 
-TEXT runtime·closefd(SB),NOSPLIT,$0
+TEXT runtime·close(SB),NOSPLIT,$0
 	MOVW	fd+0(FP), R0
 	NACL_SYSCALL(SYS_close)
 	MOVW	R0, ret+4(FP)
@@ -270,6 +269,7 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$80
 	// restore g
 	MOVW	20(R13), g
 
+sigtramp_ret:
 	// Enable exceptions again.
 	NACL_SYSCALL(SYS_exception_clear_flag)
 
@@ -301,14 +301,7 @@ nog:
 TEXT runtime·nacl_sysinfo(SB),NOSPLIT,$16
 	RET
 
-// func getRandomData([]byte)
-TEXT runtime·getRandomData(SB),NOSPLIT,$0-12
-	MOVW buf+0(FP), R0
-	MOVW len+4(FP), R1
-	NACL_SYSCALL(SYS_get_random_bytes)
-	RET
-
-TEXT runtime·casp1(SB),NOSPLIT,$0
+TEXT runtime·casp(SB),NOSPLIT,$0
 	B	runtime·cas(SB)
 
 // This is only valid for ARMv6+, however, NaCl/ARM is only defined
@@ -323,9 +316,5 @@ TEXT runtime·casp1(SB),NOSPLIT,$0
 TEXT runtime·cas(SB),NOSPLIT,$0
 	B runtime·armcas(SB)
 
-// Likewise, this is only valid for ARMv7+, but that's okay.
-TEXT ·publicationBarrier(SB),NOSPLIT,$-4-0
-	B	runtime·armPublicationBarrier(SB)
-
 TEXT runtime·read_tls_fallback(SB),NOSPLIT,$-4
 	WORD $0xe7fedef0 // NACL_INSTR_ARM_ABORT_NOW (UDF #0xEDE0)
diff --git a/src/runtime/sys_netbsd_386.s b/src/runtime/sys_netbsd_386.s
index 13b8428..23f2f6b 100644
--- a/src/runtime/sys_netbsd_386.s
+++ b/src/runtime/sys_netbsd_386.s
@@ -6,8 +6,7 @@
 // /usr/src/sys/kern/syscalls.master for syscall numbers.
 //
 
-#include "go_asm.h"
-#include "go_tls.h"
+#include "zasm_GOOS_GOARCH.h"
 #include "textflag.h"
 
 // Exit the entire program (like C exit)
@@ -27,32 +26,24 @@ TEXT runtime·exit1(SB),NOSPLIT,$-4
 TEXT runtime·open(SB),NOSPLIT,$-4
 	MOVL	$5, AX
 	INT	$0x80
-	JAE	2(PC)
-	MOVL	$-1, AX
 	MOVL	AX, ret+12(FP)
 	RET
 
-TEXT runtime·closefd(SB),NOSPLIT,$-4
+TEXT runtime·close(SB),NOSPLIT,$-4
 	MOVL	$6, AX
 	INT	$0x80
-	JAE	2(PC)
-	MOVL	$-1, AX
 	MOVL	AX, ret+4(FP)
 	RET
 
 TEXT runtime·read(SB),NOSPLIT,$-4
 	MOVL	$3, AX
 	INT	$0x80
-	JAE	2(PC)
-	MOVL	$-1, AX
 	MOVL	AX, ret+12(FP)
 	RET
 
 TEXT runtime·write(SB),NOSPLIT,$-4
 	MOVL	$4, AX			// sys_write
 	INT	$0x80
-	JAE	2(PC)
-	MOVL	$-1, AX
 	MOVL	AX, ret+12(FP)
 	RET
 
@@ -86,17 +77,6 @@ TEXT runtime·raise(SB),NOSPLIT,$12
 	INT	$0x80
 	RET
 
-TEXT runtime·raiseproc(SB),NOSPLIT,$12
-	MOVL	$20, AX			// sys_getpid
-	INT	$0x80
-	MOVL	$0, 0(SP)
-	MOVL	AX, 4(SP)		// arg 1 - pid
-	MOVL	sig+0(FP), AX
-	MOVL	AX, 8(SP)		// arg 2 - signo
-	MOVL	$37, AX			// sys_kill
-	INT	$0x80
-	RET
-
 TEXT runtime·mmap(SB),NOSPLIT,$36
 	LEAL	addr+0(FP), SI
 	LEAL	4(SP), DI
@@ -318,9 +298,9 @@ TEXT runtime·setldt(SB),NOSPLIT,$8
 	RET
 
 TEXT runtime·settls(SB),NOSPLIT,$16
-	// adjust for ELF: wants to use -4(GS) for g
+	// adjust for ELF: wants to use -8(GS) and -4(GS) for g and m
 	MOVL	base+0(FP), CX
-	ADDL	$4, CX
+	ADDL	$8, CX
 	MOVL	$0, 0(SP)		// syscall gap
 	MOVL	CX, 4(SP)		// arg 1 - ptr
 	MOVL	$317, AX		// sys__lwp_setprivate
diff --git a/src/runtime/sys_netbsd_amd64.s b/src/runtime/sys_netbsd_amd64.s
index d0640db..eb9766d 100644
--- a/src/runtime/sys_netbsd_amd64.s
+++ b/src/runtime/sys_netbsd_amd64.s
@@ -6,8 +6,7 @@
 // /usr/src/sys/kern/syscalls.master for syscall numbers.
 //
 
-#include "go_asm.h"
-#include "go_tls.h"
+#include "zasm_GOOS_GOARCH.h"
 #include "textflag.h"
 
 // int32 lwp_create(void *context, uintptr flags, void *lwpid)
@@ -91,17 +90,13 @@ TEXT runtime·open(SB),NOSPLIT,$-8
 	MOVL	perm+12(FP), DX		// arg 3 mode
 	MOVL	$5, AX
 	SYSCALL
-	JCC	2(PC)
-	MOVL	$-1, AX
 	MOVL	AX, ret+16(FP)
 	RET
 
-TEXT runtime·closefd(SB),NOSPLIT,$-8
+TEXT runtime·close(SB),NOSPLIT,$-8
 	MOVL	fd+0(FP), DI		// arg 1 fd
 	MOVL	$6, AX
 	SYSCALL
-	JCC	2(PC)
-	MOVL	$-1, AX
 	MOVL	AX, ret+8(FP)
 	RET
 
@@ -111,8 +106,6 @@ TEXT runtime·read(SB),NOSPLIT,$-8
 	MOVL	n+16(FP), DX		// arg 3 count
 	MOVL	$3, AX
 	SYSCALL
-	JCC	2(PC)
-	MOVL	$-1, AX
 	MOVL	AX, ret+24(FP)
 	RET
 
@@ -122,8 +115,6 @@ TEXT runtime·write(SB),NOSPLIT,$-8
 	MOVL	n+16(FP), DX		// arg 3 - nbyte
 	MOVL	$4, AX			// sys_write
 	SYSCALL
-	JCC	2(PC)
-	MOVL	$-1, AX
 	MOVL	AX, ret+24(FP)
 	RET
 
@@ -152,15 +143,6 @@ TEXT runtime·raise(SB),NOSPLIT,$16
 	SYSCALL
 	RET
 
-TEXT runtime·raiseproc(SB),NOSPLIT,$16
-	MOVL	$20, AX			// sys_getpid
-	SYSCALL
-	MOVQ	AX, DI			// arg 1 - pid
-	MOVL	sig+0(FP), SI		// arg 2 - signo
-	MOVL	$37, AX			// sys_kill
-	SYSCALL
-	RET
-
 TEXT runtime·setitimer(SB),NOSPLIT,$-8
 	MOVL	mode+0(FP), DI		// arg 1 - which
 	MOVQ	new+8(FP), SI		// arg 2 - itv
@@ -253,9 +235,9 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$64
 	MOVQ	R10, 40(SP)
 
 	// g = m->signal
-	MOVQ	g_m(R10), AX
-	MOVQ	m_gsignal(AX), AX
-	MOVQ	AX, g(BX)
+	MOVQ	g_m(R10), BP
+	MOVQ	m_gsignal(BP), BP
+	MOVQ	BP, g(BX)
 
 	MOVQ	DI, 0(SP)
 	MOVQ	SI, 8(SP)
@@ -316,8 +298,8 @@ TEXT runtime·sigaltstack(SB),NOSPLIT,$-8
 
 // set tls base to DI
 TEXT runtime·settls(SB),NOSPLIT,$8
-	// adjust for ELF: wants to use -8(FS) for g
-	ADDQ	$8, DI			// arg 1 - ptr
+	// adjust for ELF: wants to use -16(FS) and -8(FS) for g and m
+	ADDQ	$16, DI			// arg 1 - ptr
 	MOVQ	$317, AX		// sys__lwp_setprivate
 	SYSCALL
 	JCC	2(PC)
diff --git a/src/runtime/sys_netbsd_arm.s b/src/runtime/sys_netbsd_arm.s
index ae669ce..039a083 100644
--- a/src/runtime/sys_netbsd_arm.s
+++ b/src/runtime/sys_netbsd_arm.s
@@ -6,13 +6,12 @@
 // /usr/src/sys/kern/syscalls.master for syscall numbers.
 //
 
-#include "go_asm.h"
-#include "go_tls.h"
+#include "zasm_GOOS_GOARCH.h"
 #include "textflag.h"
 
 // Exit the entire program (like C exit)
 TEXT runtime·exit(SB),NOSPLIT,$-4
-	MOVW code+0(FP), R0	// arg 1 exit status
+	MOVW 0(FP), R0	// arg 1 exit status
 	SWI $0xa00001
 	MOVW.CS $0, R8	// crash on syscall failure
 	MOVW.CS R8, (R8)
@@ -25,36 +24,32 @@ TEXT runtime·exit1(SB),NOSPLIT,$-4
 	RET
 	
 TEXT runtime·open(SB),NOSPLIT,$-8
-	MOVW name+0(FP), R0
-	MOVW mode+4(FP), R1
-	MOVW perm+8(FP), R2
+	MOVW 0(FP), R0
+	MOVW 4(FP), R1
+	MOVW 8(FP), R2
 	SWI $0xa00005
-	MOVW.CS	$-1, R0
 	MOVW	R0, ret+12(FP)
 	RET
 
-TEXT runtime·closefd(SB),NOSPLIT,$-8
-	MOVW fd+0(FP), R0
+TEXT runtime·close(SB),NOSPLIT,$-8
+	MOVW 0(FP), R0
 	SWI $0xa00006
-	MOVW.CS	$-1, R0
 	MOVW	R0, ret+4(FP)
 	RET
 
 TEXT runtime·read(SB),NOSPLIT,$-8
-	MOVW fd+0(FP), R0
-	MOVW p+4(FP), R1
-	MOVW n+8(FP), R2
+	MOVW 0(FP), R0
+	MOVW 4(FP), R1
+	MOVW 8(FP), R2
 	SWI $0xa00003
-	MOVW.CS	$-1, R0
 	MOVW	R0, ret+12(FP)
 	RET
 
 TEXT runtime·write(SB),NOSPLIT,$-4
-	MOVW	fd+0(FP), R0	// arg 1 - fd
-	MOVW	p+4(FP), R1	// arg 2 - buf
-	MOVW	n+8(FP), R2	// arg 3 - nbyte
+	MOVW	0(FP), R0	// arg 1 - fd
+	MOVW	4(FP), R1	// arg 2 - buf
+	MOVW	8(FP), R2	// arg 3 - nbyte
 	SWI $0xa00004	// sys_write
-	MOVW.CS	$-1, R0
 	MOVW	R0, ret+12(FP)
 	RET
 
@@ -72,17 +67,17 @@ TEXT runtime·osyield(SB),NOSPLIT,$0
 	RET
 
 TEXT runtime·lwp_park(SB),NOSPLIT,$0
-	MOVW abstime+0(FP), R0	// arg 1 - abstime
-	MOVW unpark+4(FP), R1	// arg 2 - unpark
-	MOVW hint+8(FP), R2	// arg 3 - hint
-	MOVW unparkhint+12(FP), R3	// arg 4 - unparkhint
+	MOVW 0(FP), R0	// arg 1 - abstime
+	MOVW 4(FP), R1	// arg 2 - unpark
+	MOVW 8(FP), R2	// arg 3 - hint
+	MOVW 12(FP), R3	// arg 4 - unparkhint
 	SWI $0xa001b2	// sys__lwp_park
 	MOVW	R0, ret+16(FP)
 	RET
 
 TEXT runtime·lwp_unpark(SB),NOSPLIT,$0
-	MOVW	lwp+0(FP), R0	// arg 1 - lwp
-	MOVW	hint+4(FP), R1	// arg 2 - hint
+	MOVW	0(FP), R0	// arg 1 - lwp
+	MOVW	4(FP), R1	// arg 2 - hint
 	SWI $0xa00141 // sys__lwp_unpark
 	MOVW	R0, ret+8(FP)
 	RET
@@ -104,12 +99,15 @@ TEXT runtime·lwp_tramp(SB),NOSPLIT,$0
 
 TEXT runtime·usleep(SB),NOSPLIT,$16
 	MOVW usec+0(FP), R0
-	CALL runtime·usplitR0(SB)
+	MOVW R0, R2
+	MOVW $1000000, R1
+	DIV R1, R0
 	// 0(R13) is the saved LR, don't use it
 	MOVW R0, 4(R13) // tv_sec.low
 	MOVW $0, R0
 	MOVW R0, 8(R13) // tv_sec.high
-	MOVW $1000, R2
+	MOD R1, R2
+	MOVW $1000, R1
 	MUL R1, R2
 	MOVW R2, 12(R13) // tv_nsec
 
@@ -124,16 +122,10 @@ TEXT runtime·raise(SB),NOSPLIT,$16
 	SWI $0xa0013e	// sys__lwp_kill
 	RET
 
-TEXT runtime·raiseproc(SB),NOSPLIT,$16
-	SWI $0xa00014	// sys_getpid, the returned R0 is arg 1
-	MOVW	sig+0(FP), R1	// arg 2 - signal
-	SWI $0xa00025	// sys_kill
-	RET
-
 TEXT runtime·setitimer(SB),NOSPLIT,$-4
-	MOVW mode+0(FP), R0	// arg 1 - which
-	MOVW new+4(FP), R1	// arg 2 - itv
-	MOVW old+8(FP), R2	// arg 3 - oitv
+	MOVW 0(FP), R0	// arg 1 - which
+	MOVW 4(FP), R1	// arg 2 - itv
+	MOVW 8(FP), R2	// arg 3 - oitv
 	SWI $0xa001a9	// sys_setitimer
 	RET
 
@@ -147,9 +139,9 @@ TEXT time·now(SB), NOSPLIT, $32
 	MOVW 12(R13), R1 // sec.high
 	MOVW 16(R13), R2 // nsec
 
-	MOVW R0, sec_lo+0(FP)
-	MOVW R1, sec_hi+4(FP)
-	MOVW R2, nsec+8(FP)
+	MOVW R0, 0(FP)
+	MOVW R1, 4(FP)
+	MOVW R2, 8(FP)
 	RET
 
 // int64 nanotime(void) so really
@@ -174,16 +166,16 @@ TEXT runtime·nanotime(SB), NOSPLIT, $32
 	RET
 
 TEXT runtime·getcontext(SB),NOSPLIT,$-4
-	MOVW ctxt+0(FP), R0	// arg 1 - context
+	MOVW 0(FP), R0	// arg 1 - context
 	SWI $0xa00133	// sys_getcontext
 	MOVW.CS $0, R8	// crash on syscall failure
 	MOVW.CS R8, (R8)
 	RET
 
 TEXT runtime·sigprocmask(SB),NOSPLIT,$0
-	MOVW mode+0(FP), R0	// arg 1 - how
-	MOVW new+4(FP), R1	// arg 2 - set
-	MOVW old+8(FP), R2	// arg 3 - oset
+	MOVW 0(FP), R0	// arg 1 - how
+	MOVW 4(FP), R1	// arg 2 - set
+	MOVW 8(FP), R2	// arg 3 - oset
 	SWI $0xa00125	// sys_sigprocmask
 	MOVW.CS $0, R8	// crash on syscall failure
 	MOVW.CS R8, (R8)
@@ -200,9 +192,9 @@ TEXT runtime·sigreturn_tramp(SB),NOSPLIT,$-4
 	B -2(PC)	// continue exit
 
 TEXT runtime·sigaction(SB),NOSPLIT,$4
-	MOVW sig+0(FP), R0	// arg 1 - signum
-	MOVW new+4(FP), R1	// arg 2 - nsa
-	MOVW old+8(FP), R2	// arg 3 - osa
+	MOVW 0(FP), R0	// arg 1 - signum
+	MOVW 4(FP), R1	// arg 2 - nsa
+	MOVW 8(FP), R2	// arg 3 - osa
 	MOVW $runtime·sigreturn_tramp(SB), R3	// arg 4 - tramp
 	MOVW $2, R4	// arg 5 - vers
 	MOVW R4, 4(R13)
@@ -249,15 +241,15 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$24
 	RET
 
 TEXT runtime·mmap(SB),NOSPLIT,$12
-	MOVW addr+0(FP), R0	// arg 1 - addr
-	MOVW n+4(FP), R1	// arg 2 - len
-	MOVW prot+8(FP), R2	// arg 3 - prot
-	MOVW flags+12(FP), R3	// arg 4 - flags
+	MOVW 0(FP), R0	// arg 1 - addr
+	MOVW 4(FP), R1	// arg 2 - len
+	MOVW 8(FP), R2	// arg 3 - prot
+	MOVW 12(FP), R3	// arg 4 - flags
 	// arg 5 (fid) and arg6 (offset_lo, offset_hi) are passed on stack
 	// note the C runtime only passes the 32-bit offset_lo to us
-	MOVW fd+16(FP), R4		// arg 5
+	MOVW 16(FP), R4		// arg 5
 	MOVW R4, 4(R13)
-	MOVW off+20(FP), R5		// arg 6 lower 32-bit
+	MOVW 20(FP), R5		// arg 6 lower 32-bit
 	MOVW R5, 8(R13)
 	MOVW $0, R6 // higher 32-bit for arg 6
 	MOVW R6, 12(R13)
@@ -268,37 +260,37 @@ TEXT runtime·mmap(SB),NOSPLIT,$12
 	RET
 
 TEXT runtime·munmap(SB),NOSPLIT,$0
-	MOVW addr+0(FP), R0	// arg 1 - addr
-	MOVW n+4(FP), R1	// arg 2 - len
+	MOVW 0(FP), R0	// arg 1 - addr
+	MOVW 4(FP), R1	// arg 2 - len
 	SWI $0xa00049	// sys_munmap
 	MOVW.CS $0, R8	// crash on syscall failure
 	MOVW.CS R8, (R8)
 	RET
 
 TEXT runtime·madvise(SB),NOSPLIT,$0
-	MOVW addr+0(FP), R0	// arg 1 - addr
-	MOVW n+4(FP), R1	// arg 2 - len
-	MOVW flags+8(FP), R2	// arg 3 - behav
+	MOVW 0(FP), R0	// arg 1 - addr
+	MOVW 4(FP), R1	// arg 2 - len
+	MOVW 8(FP), R2	// arg 3 - behav
 	SWI $0xa0004b	// sys_madvise
 	// ignore failure - maybe pages are locked
 	RET
 
 TEXT runtime·sigaltstack(SB),NOSPLIT,$-4
-	MOVW new+0(FP), R0	// arg 1 - nss
-	MOVW old+4(FP), R1	// arg 2 - oss
+	MOVW 0(FP), R0	// arg 1 - nss
+	MOVW 4(FP), R1	// arg 2 - oss
 	SWI $0xa00119	// sys___sigaltstack14
 	MOVW.CS $0, R8	// crash on syscall failure
 	MOVW.CS R8, (R8)
 	RET
 
 TEXT runtime·sysctl(SB),NOSPLIT,$8
-	MOVW mib+0(FP), R0	// arg 1 - name
-	MOVW miblen+4(FP), R1	// arg 2 - namelen
-	MOVW out+8(FP), R2	// arg 3 - oldp
-	MOVW size+12(FP), R3	// arg 4 - oldlenp
-	MOVW dst+16(FP), R4	// arg 5 - newp
+	MOVW 0(FP), R0	// arg 1 - name
+	MOVW 4(FP), R1	// arg 2 - namelen
+	MOVW 8(FP), R2	// arg 3 - oldp
+	MOVW 12(FP), R3	// arg 4 - oldlenp
+	MOVW 16(FP), R4	// arg 5 - newp
 	MOVW R4, 4(R13)
-	MOVW ndst+20(FP), R4	// arg 6 - newlen
+	MOVW 20(FP), R4	// arg 6 - newlen
 	MOVW R4, 8(R13)
 	ADD $4, R13	// pass arg 5 and 6 on stack
 	SWI $0xa000ca	// sys___sysctl
@@ -315,13 +307,13 @@ 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,$8
-	MOVW kq+0(FP), R0	// kq
-	MOVW ch+4(FP), R1	// changelist
-	MOVW nch+8(FP), R2	// nchanges
-	MOVW ev+12(FP), R3	// eventlist
-	MOVW nev+16(FP), R4	// nevents
+	MOVW 0(FP), R0	// kq
+	MOVW 4(FP), R1	// changelist
+	MOVW 8(FP), R2	// nchanges
+	MOVW 12(FP), R3	// eventlist
+	MOVW 16(FP), R4	// nevents
 	MOVW R4, 4(R13)
-	MOVW ts+20(FP), R4	// timeout
+	MOVW 20(FP), R4	// timeout
 	MOVW R4, 8(R13)
 	ADD $4, R13	// pass arg 5 and 6 on stack
 	SWI $0xa001b3	// sys___kevent50
@@ -332,13 +324,13 @@ TEXT runtime·kevent(SB),NOSPLIT,$8
 
 // void runtime·closeonexec(int32 fd)
 TEXT runtime·closeonexec(SB),NOSPLIT,$0
-	MOVW fd+0(FP), R0	// fd
+	MOVW 0(FP), R0	// fd
 	MOVW $2, R1	// F_SETFD
 	MOVW $1, R2	// FD_CLOEXEC
 	SWI $0xa0005c	// sys_fcntl
 	RET
 
-TEXT runtime·casp1(SB),NOSPLIT,$0
+TEXT runtime·casp(SB),NOSPLIT,$0
 	B	runtime·cas(SB)
 
 // TODO(minux): this is only valid for ARMv6+
@@ -352,10 +344,6 @@ TEXT runtime·casp1(SB),NOSPLIT,$0
 TEXT runtime·cas(SB),NOSPLIT,$0
 	B runtime·armcas(SB)
 
-// TODO: this is only valid for ARMv7+
-TEXT ·publicationBarrier(SB),NOSPLIT,$-4-0
-	B	runtime·armPublicationBarrier(SB)
-
 TEXT runtime·read_tls_fallback(SB),NOSPLIT,$-4
 	MOVM.WP [R1, R2, R3, R12], (R13)
 	SWI $0x00a0013c // _lwp_getprivate
diff --git a/src/runtime/sys_openbsd_386.s b/src/runtime/sys_openbsd_386.s
index bdf18d8..5cda776 100644
--- a/src/runtime/sys_openbsd_386.s
+++ b/src/runtime/sys_openbsd_386.s
@@ -6,8 +6,7 @@
 // /usr/src/sys/kern/syscalls.master for syscall numbers.
 //
 
-#include "go_asm.h"
-#include "go_tls.h"
+#include "zasm_GOOS_GOARCH.h"
 #include "textflag.h"
 
 #define	CLOCK_MONOTONIC	$3
@@ -31,32 +30,24 @@ TEXT runtime·exit1(SB),NOSPLIT,$8
 TEXT runtime·open(SB),NOSPLIT,$-4
 	MOVL	$5, AX
 	INT	$0x80
-	JAE	2(PC)
-	MOVL	$-1, AX
 	MOVL	AX, ret+12(FP)
 	RET
 
-TEXT runtime·closefd(SB),NOSPLIT,$-4
+TEXT runtime·close(SB),NOSPLIT,$-4
 	MOVL	$6, AX
 	INT	$0x80
-	JAE	2(PC)
-	MOVL	$-1, AX
 	MOVL	AX, ret+4(FP)
 	RET
 
 TEXT runtime·read(SB),NOSPLIT,$-4
 	MOVL	$3, AX
 	INT	$0x80
-	JAE	2(PC)
-	MOVL	$-1, AX
 	MOVL	AX, ret+12(FP)
 	RET
 
 TEXT runtime·write(SB),NOSPLIT,$-4
 	MOVL	$4, AX			// sys_write
 	INT	$0x80
-	JAE	2(PC)
-	MOVL	$-1, AX
 	MOVL	AX, ret+12(FP)
 	RET
 
@@ -90,17 +81,6 @@ TEXT runtime·raise(SB),NOSPLIT,$12
 	INT	$0x80
 	RET
 
-TEXT runtime·raiseproc(SB),NOSPLIT,$12
-	MOVL	$20, AX			// sys_getpid
-	INT	$0x80
-	MOVL	$0, 0(SP)
-	MOVL	AX, 4(SP)		// arg 1 - pid
-	MOVL	sig+0(FP), AX
-	MOVL	AX, 8(SP)		// arg 2 - signum
-	MOVL	$37, AX			// sys_kill
-	INT	$0x80
-	RET
-
 TEXT runtime·mmap(SB),NOSPLIT,$36
 	LEAL	addr+0(FP), SI
 	LEAL	4(SP), DI
@@ -206,7 +186,7 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$44
 	MOVL	BX, 0(SP)
 	MOVL	$runtime·badsignal(SB), AX
 	CALL	AX
-	JMP 	ret
+	JMP 	sigtramp_ret
 
 	// save g
 	MOVL	DI, 20(SP)
@@ -232,7 +212,7 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$44
 	MOVL	20(SP), BX
 	MOVL	BX, g(CX)
 
-ret:
+sigtramp_ret:
 	// call sigreturn
 	MOVL	context+8(FP), AX
 	MOVL	$0, 0(SP)		// syscall gap
@@ -336,9 +316,9 @@ TEXT runtime·setldt(SB),NOSPLIT,$4
 	RET
 
 TEXT runtime·settls(SB),NOSPLIT,$8
-	// adjust for ELF: wants to use -4(GS) for g
+	// adjust for ELF: wants to use -8(GS) and -4(GS) for g and m
 	MOVL	tlsbase+0(FP), CX
-	ADDL	$4, CX
+	ADDL	$8, CX
 	MOVL	$0, 0(SP)		// syscall gap
 	MOVL	CX, 4(SP)		// arg 1 - tcb
 	MOVL	$329, AX		// sys___set_tcb
diff --git a/src/runtime/sys_openbsd_amd64.s b/src/runtime/sys_openbsd_amd64.s
index 213ffc1..4e9db23 100644
--- a/src/runtime/sys_openbsd_amd64.s
+++ b/src/runtime/sys_openbsd_amd64.s
@@ -6,8 +6,7 @@
 // /usr/src/sys/kern/syscalls.master for syscall numbers.
 //
 
-#include "go_asm.h"
-#include "go_tls.h"
+#include "zasm_GOOS_GOARCH.h"
 #include "textflag.h"
 
 #define CLOCK_MONOTONIC	$3
@@ -101,17 +100,13 @@ TEXT runtime·open(SB),NOSPLIT,$-8
 	MOVL	perm+12(FP), DX		// arg 3 mode
 	MOVL	$5, AX
 	SYSCALL
-	JCC	2(PC)
-	MOVL	$-1, AX
 	MOVL	AX, ret+16(FP)
 	RET
 
-TEXT runtime·closefd(SB),NOSPLIT,$-8
+TEXT runtime·close(SB),NOSPLIT,$-8
 	MOVL	fd+0(FP), DI		// arg 1 fd
 	MOVL	$6, AX
 	SYSCALL
-	JCC	2(PC)
-	MOVL	$-1, AX
 	MOVL	AX, ret+8(FP)
 	RET
 
@@ -121,8 +116,6 @@ TEXT runtime·read(SB),NOSPLIT,$-8
 	MOVL	n+16(FP), DX		// arg 3 count
 	MOVL	$3, AX
 	SYSCALL
-	JCC	2(PC)
-	MOVL	$-1, AX
 	MOVL	AX, ret+24(FP)
 	RET
 
@@ -132,8 +125,6 @@ TEXT runtime·write(SB),NOSPLIT,$-8
 	MOVL	n+16(FP), DX		// arg 3 - nbyte
 	MOVL	$4, AX			// sys_write
 	SYSCALL
-	JCC	2(PC)
-	MOVL	$-1, AX
 	MOVL	AX, ret+24(FP)
 	RET
 
@@ -162,15 +153,6 @@ TEXT runtime·raise(SB),NOSPLIT,$16
 	SYSCALL
 	RET
 
-TEXT runtime·raiseproc(SB),NOSPLIT,$16
-	MOVL	$20, AX			// sys_getpid
-	SYSCALL
-	MOVQ	AX, DI			// arg 1 - pid
-	MOVL	sig+0(FP), SI		// arg 2 - signum
-	MOVL	$37, AX			// sys_kill
-	SYSCALL
-	RET
-
 TEXT runtime·setitimer(SB),NOSPLIT,$-8
 	MOVL	mode+0(FP), DI		// arg 1 - which
 	MOVQ	new+8(FP), SI		// arg 2 - itv
@@ -244,9 +226,9 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$64
 	MOVQ	R10, 40(SP)
 	
 	// g = m->signal
-	MOVQ	g_m(R10), AX
-	MOVQ	m_gsignal(AX), AX
-	MOVQ	AX, g(BX)
+	MOVQ	g_m(R10), BP
+	MOVQ	m_gsignal(BP), BP
+	MOVQ	BP, g(BX)
 	
 	MOVQ	DI, 0(SP)
 	MOVQ	SI, 8(SP)
@@ -307,7 +289,7 @@ TEXT runtime·sigaltstack(SB),NOSPLIT,$-8
 // set tls base to DI
 TEXT runtime·settls(SB),NOSPLIT,$0
 	// adjust for ELF: wants to use -16(FS) and -8(FS) for g and m
-	ADDQ	$8, DI
+	ADDQ	$16, DI
 	MOVQ	$329, AX		// sys___settcb
 	SYSCALL
 	JCC	2(PC)
diff --git a/src/runtime/sys_plan9_386.s b/src/runtime/sys_plan9_386.s
index cae326a..a41b562 100644
--- a/src/runtime/sys_plan9_386.s
+++ b/src/runtime/sys_plan9_386.s
@@ -2,8 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-#include "go_asm.h"
-#include "go_tls.h"
+#include "zasm_GOOS_GOARCH.h"
 #include "textflag.h"
 
 // setldt(int entry, int address, int limit)
@@ -52,7 +51,7 @@ TEXT runtime·seek(SB),NOSPLIT,$24
 	MOVL	$-1, ret_hi+20(FP)
 	RET
 
-TEXT runtime·closefd(SB),NOSPLIT,$0
+TEXT runtime·close(SB),NOSPLIT,$0
 	MOVL	$4, AX
 	INT	$64
 	MOVL	AX, ret+4(FP)
diff --git a/src/runtime/sys_plan9_amd64.s b/src/runtime/sys_plan9_amd64.s
index 6aefe5f..3a96c2b 100644
--- a/src/runtime/sys_plan9_amd64.s
+++ b/src/runtime/sys_plan9_amd64.s
@@ -2,8 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-#include "go_asm.h"
-#include "go_tls.h"
+#include "zasm_GOOS_GOARCH.h"
 #include "textflag.h"
 
 // setldt(int entry, int address, int limit)
@@ -51,7 +50,7 @@ TEXT runtime·seek(SB),NOSPLIT,$32
 	MOVQ	$-1, ret+24(FP)
 	RET
 
-TEXT runtime·closefd(SB),NOSPLIT,$0
+TEXT runtime·close(SB),NOSPLIT,$0
 	MOVQ	$4, BP
 	SYSCALL
 	MOVL	AX, ret+8(FP)
diff --git a/src/runtime/sys_solaris_amd64.s b/src/runtime/sys_solaris_amd64.s
index e431564..0ebdab6 100644
--- a/src/runtime/sys_solaris_amd64.s
+++ b/src/runtime/sys_solaris_amd64.s
@@ -6,15 +6,14 @@
 // /usr/include/sys/syscall.h for syscall numbers.
 //
 
-#include "go_asm.h"
-#include "go_tls.h"
+#include "zasm_GOOS_GOARCH.h"
 #include "textflag.h"
 
 // This is needed by asm_amd64.s
 TEXT runtime·settls(SB),NOSPLIT,$8
 	RET
 
-// void libc_miniterrno(void *(*___errno)(void));
+// void libc·miniterrno(void *(*___errno)(void));
 //
 // Set the TLS errno pointer in M.
 //
@@ -41,7 +40,7 @@ TEXT runtime·nanotime1(SB),NOSPLIT,$0
 	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
-	LEAQ	libc_clock_gettime(SB), AX
+	MOVQ	libc·clock_gettime(SB), AX
 	CALL	AX
 	MOVQ	(SP), AX	// tv_sec from struct timespec
 	IMULQ	$1000000000, AX	// multiply into nanoseconds
@@ -54,7 +53,7 @@ TEXT runtime·nanotime1(SB),NOSPLIT,$0
 TEXT runtime·pipe1(SB),NOSPLIT,$0
 	SUBQ	$16, SP // 8 bytes will do, but stack has to be 16-byte alligned
 	MOVQ	SP, DI
-	LEAQ	libc_pipe(SB), AX
+	MOVQ	libc·pipe(SB), AX
 	CALL	AX
 	MOVL	0(SP), AX
 	MOVL	4(SP), DX
@@ -133,7 +132,7 @@ TEXT runtime·tstart_sysvicall(SB),NOSPLIT,$0
 	MOVQ	AX, (g_stack+stack_hi)(DX)
 	SUBQ	$(0x100000), AX		// stack size
 	MOVQ	AX, (g_stack+stack_lo)(DX)
-	ADDQ	$const__StackGuard, AX
+	ADDQ	$const_StackGuard, AX
 	MOVQ	AX, g_stackguard0(DX)
 	MOVQ	AX, g_stackguard1(DX)
 
@@ -288,24 +287,24 @@ TEXT runtime·usleep1(SB),NOSPLIT,$0
 	// Execute call on m->g0.
 	get_tls(R15)
 	CMPQ	R15, $0
-	JE	noswitch
+	JE	usleep1_noswitch
 
 	MOVQ	g(R15), R13
 	CMPQ	R13, $0
-	JE	noswitch
+	JE	usleep1_noswitch
 	MOVQ	g_m(R13), R13
 	CMPQ	R13, $0
-	JE	noswitch
+	JE	usleep1_noswitch
 	// TODO(aram): do something about the cpu profiler here.
 
 	MOVQ	m_g0(R13), R14
 	CMPQ	g(R15), R14
-	JNE	switch
+	JNE	usleep1_switch
 	// executing on m->g0 already
 	CALL	AX
 	RET
 
-switch:
+usleep1_switch:
 	// Switch to m->g0 stack and back.
 	MOVQ	(g_sched+gobuf_sp)(R14), R14
 	MOVQ	SP, -8(R14)
@@ -314,20 +313,20 @@ switch:
 	MOVQ	0(SP), SP
 	RET
 
-noswitch:
+usleep1_noswitch:
 	// Not a Go-managed thread. Do not switch stack.
 	CALL	AX
 	RET
 
 // Runs on OS stack. duration (in µs units) is in DI.
 TEXT runtime·usleep2(SB),NOSPLIT,$0
-	LEAQ	libc_usleep(SB), AX
+	MOVQ	libc·usleep(SB), AX
 	CALL	AX
 	RET
 
 // Runs on OS stack, called from runtime·osyield.
 TEXT runtime·osyield1(SB),NOSPLIT,$0
-	LEAQ	libc_sched_yield(SB), AX
+	MOVQ	libc·sched_yield(SB), AX
 	CALL	AX
 	RET
 
diff --git a/src/runtime/sys_windows_386.s b/src/runtime/sys_windows_386.s
index e5fe88a..932fe9d 100644
--- a/src/runtime/sys_windows_386.s
+++ b/src/runtime/sys_windows_386.s
@@ -2,8 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-#include "go_asm.h"
-#include "go_tls.h"
+#include "zasm_GOOS_GOARCH.h"
 #include "textflag.h"
 
 // void runtime·asmstdcall(void *c);
@@ -44,7 +43,7 @@ TEXT	runtime·badsignal2(SB),NOSPLIT,$24
 	// stderr
 	MOVL	$-12, 0(SP)
 	MOVL	SP, BP
-	CALL	*runtime·_GetStdHandle(SB)
+	CALL	*runtime·GetStdHandle(SB)
 	MOVL	BP, SP
 
 	MOVL	AX, 0(SP)	// handle
@@ -56,7 +55,7 @@ TEXT	runtime·badsignal2(SB),NOSPLIT,$24
 	MOVL	$0, 0(DX)
 	MOVL	DX, 12(SP)
 	MOVL	$0, 16(SP) // overlapped
-	CALL	*runtime·_WriteFile(SB)
+	CALL	*runtime·WriteFile(SB)
 	MOVL	BP, SI
 	RET
 
@@ -107,7 +106,7 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$0-0
 	MOVL	g_m(DX), BX
 	MOVL	m_g0(BX), BX
 	CMPL	DX, BX
-	JEQ	g0
+	JEQ	sigtramp_g0
 
 	// switch to the g0 stack
 	get_tls(BP)
@@ -124,7 +123,7 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$0-0
 	MOVL	SP, 36(DI)
 	MOVL	DI, SP
 
-g0:
+sigtramp_g0:
 	MOVL	0(CX), BX // ExceptionRecord*
 	MOVL	4(CX), CX // Context*
 	MOVL	BX, 0(SP)
@@ -189,35 +188,33 @@ TEXT runtime·externalthreadhandler(SB),NOSPLIT,$0
 	MOVL	SP, DX
 
 	// setup dummy m, g
-	SUBL	$m__size, SP		// space for M
+	SUBL	$m_end, SP		// space for M
 	MOVL	SP, 0(SP)
-	MOVL	$m__size, 4(SP)
+	MOVL	$m_end, 4(SP)
 	CALL	runtime·memclr(SB)	// smashes AX,BX,CX
 
 	LEAL	m_tls(SP), CX
 	MOVL	CX, 0x14(FS)
 	MOVL	SP, BX
-	SUBL	$g__size, SP		// space for G
+	SUBL	$g_end, SP		// space for G
 	MOVL	SP, g(CX)
 	MOVL	SP, m_g0(BX)
 
 	MOVL	SP, 0(SP)
-	MOVL	$g__size, 4(SP)
+	MOVL	$g_end, 4(SP)
 	CALL	runtime·memclr(SB)	// smashes AX,BX,CX
-	LEAL	g__size(SP), BX
+	LEAL	g_end(SP), BX
 	MOVL	BX, g_m(SP)
 	LEAL	-8192(SP), CX
 	MOVL	CX, (g_stack+stack_lo)(SP)
-	ADDL	$const__StackGuard, CX
+	ADDL	$const_StackGuard, CX
 	MOVL	CX, g_stackguard0(SP)
 	MOVL	CX, g_stackguard1(SP)
 	MOVL	DX, (g_stack+stack_hi)(SP)
 
-	PUSHL	AX			// room for return value
 	PUSHL	16(BP)			// arg for handler
 	CALL	8(BP)
 	POPL	CX
-	POPL	AX			// pass return value to Windows in AX
 
 	get_tls(CX)
 	MOVL	g(CX), CX
@@ -250,15 +247,15 @@ TEXT runtime·callbackasm1+0(SB),NOSPLIT,$0
 	SUBL	$runtime·callbackasm(SB), AX
 	MOVL	$0, DX
 	MOVL	$5, BX	// divide by 5 because each call instruction in runtime·callbacks is 5 bytes long
-	DIVL	BX
+	DIVL	BX,
 
 	// find correspondent runtime·cbctxts table entry
 	MOVL	runtime·cbctxts(SB), BX
 	MOVL	-4(BX)(AX*4), BX
 
 	// extract callback context
-	MOVL	wincallbackcontext_gobody(BX), AX
-	MOVL	wincallbackcontext_argsize(BX), DX
+	MOVL	cbctxt_gobody(BX), AX
+	MOVL	cbctxt_argsize(BX), DX
 
 	// preserve whatever's at the memory location that
 	// the callback will use to store the return value
@@ -268,7 +265,7 @@ TEXT runtime·callbackasm1+0(SB),NOSPLIT,$0
 	ADDL	$4, DX
 
 	// remember how to restore stack on return
-	MOVL	wincallbackcontext_restorestack(BX), BX
+	MOVL	cbctxt_restorestack(BX), BX
 	PUSHL	BX
 
 	// call target Go function
@@ -316,7 +313,7 @@ TEXT runtime·tstart(SB),NOSPLIT,$0
 	MOVL	AX, (g_stack+stack_hi)(DX)
 	SUBL	$(64*1024), AX		// stack size
 	MOVL	AX, (g_stack+stack_lo)(DX)
-	ADDL	$const__StackGuard, AX
+	ADDL	$const_StackGuard, AX
 	MOVL	AX, g_stackguard0(DX)
 	MOVL	AX, g_stackguard1(DX)
 
@@ -386,12 +383,12 @@ TEXT runtime·usleep1(SB),NOSPLIT,$0
 
 	MOVL	m_g0(BP), SI
 	CMPL	g(CX), SI
-	JNE	switch
+	JNE	usleep1_switch
 	// executing on m->g0 already
 	CALL	AX
-	JMP	ret
+	JMP	usleep1_ret
 
-switch:
+usleep1_switch:
 	// Switch to m->g0 stack and back.
 	MOVL	(g_sched+gobuf_sp)(SI), SI
 	MOVL	SP, -4(SI)
@@ -399,7 +396,7 @@ switch:
 	CALL	AX
 	MOVL	0(SP), SP
 
-ret:
+usleep1_ret:
 	get_tls(CX)
 	MOVL	g(CX), BP
 	MOVL	g_m(BP), BP
@@ -417,7 +414,7 @@ TEXT runtime·usleep2(SB),NOSPLIT,$20
 	MOVL	$0, alertable-16(SP)
 	MOVL	$-1, handle-20(SP)
 	MOVL	SP, BP
-	MOVL	runtime·_NtWaitForSingleObject(SB), AX
+	MOVL	runtime·NtWaitForSingleObject(SB), AX
 	CALL	AX
 	MOVL	BP, SP
 	RET
diff --git a/src/runtime/sys_windows_amd64.s b/src/runtime/sys_windows_amd64.s
index ea4f3e0..e6190ce 100644
--- a/src/runtime/sys_windows_amd64.s
+++ b/src/runtime/sys_windows_amd64.s
@@ -2,8 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-#include "go_asm.h"
-#include "go_tls.h"
+#include "zasm_GOOS_GOARCH.h"
 #include "textflag.h"
 
 // maxargs should be divisible by 2, as Windows stack
@@ -66,7 +65,7 @@ TEXT runtime·badsignal2(SB),NOSPLIT,$48
 	// stderr
 	MOVQ	$-12, CX // stderr
 	MOVQ	CX, 0(SP)
-	MOVQ	runtime·_GetStdHandle(SB), AX
+	MOVQ	runtime·GetStdHandle(SB), AX
 	CALL	AX
 
 	MOVQ	AX, CX	// handle
@@ -79,7 +78,7 @@ TEXT runtime·badsignal2(SB),NOSPLIT,$48
 	MOVQ	$0, 0(R9)
 	MOVQ	R9, 24(SP)
 	MOVQ	$0, 32(SP)	// overlapped
-	MOVQ	runtime·_WriteFile(SB), AX
+	MOVQ	runtime·WriteFile(SB), AX
 	CALL	AX
 	
 	RET
@@ -139,7 +138,7 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$0-0
 	MOVQ	g_m(DX), BX
 	MOVQ	m_g0(BX), BX
 	CMPQ	DX, BX
-	JEQ	g0
+	JEQ	sigtramp_g0
 
 	// switch to g0 stack
 	get_tls(BP)
@@ -158,7 +157,7 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$0-0
 	MOVQ	SP, 104(DI)
 	MOVQ	DI, SP
 
-g0:
+sigtramp_g0:
 	MOVQ	0(CX), BX // ExceptionRecord*
 	MOVQ	8(CX), CX // Context*
 	MOVQ	BX, 0(SP)
@@ -225,36 +224,34 @@ TEXT runtime·externalthreadhandler(SB),NOSPLIT,$0
 	MOVQ	SP, DX
 
 	// setup dummy m, g
-	SUBQ	$m__size, SP		// space for M
+	SUBQ	$m_end, SP		// space for M
 	MOVQ	SP, 0(SP)
-	MOVQ	$m__size, 8(SP)
+	MOVQ	$m_end, 8(SP)
 	CALL	runtime·memclr(SB)	// smashes AX,BX,CX
 
 	LEAQ	m_tls(SP), CX
 	MOVQ	CX, 0x28(GS)
 	MOVQ	SP, BX
-	SUBQ	$g__size, SP		// space for G
+	SUBQ	$g_end, SP		// space for G
 	MOVQ	SP, g(CX)
 	MOVQ	SP, m_g0(BX)
 
 	MOVQ	SP, 0(SP)
-	MOVQ	$g__size, 8(SP)
+	MOVQ	$g_end, 8(SP)
 	CALL	runtime·memclr(SB)	// smashes AX,BX,CX
-	LEAQ	g__size(SP), BX
+	LEAQ	g_end(SP), BX
 	MOVQ	BX, g_m(SP)
 
 	LEAQ	-8192(SP), CX
 	MOVQ	CX, (g_stack+stack_lo)(SP)
-	ADDQ	$const__StackGuard, CX
+	ADDQ	$const_StackGuard, CX
 	MOVQ	CX, g_stackguard0(SP)
 	MOVQ	CX, g_stackguard1(SP)
 	MOVQ	DX, (g_stack+stack_hi)(SP)
 
-	PUSHQ	AX			// room for return value
 	PUSHQ	32(BP)			// arg for handler
 	CALL	16(BP)
 	POPQ	CX
-	POPQ	AX			// pass return value to Windows in AX
 
 	get_tls(CX)
 	MOVQ	g(CX), CX
@@ -289,15 +286,15 @@ TEXT runtime·callbackasm1(SB),NOSPLIT,$0
 	SUBQ	DX, AX
 	MOVQ	$0, DX
 	MOVQ	$5, CX	// divide by 5 because each call instruction in runtime·callbacks is 5 bytes long
-	DIVL	CX
+	DIVL	CX,
 
 	// find correspondent runtime·cbctxts table entry
 	MOVQ	runtime·cbctxts(SB), CX
 	MOVQ	-8(CX)(AX*8), AX
 
 	// extract callback context
-	MOVQ	wincallbackcontext_argsize(AX), DX
-	MOVQ	wincallbackcontext_gobody(AX), AX
+	MOVQ	cbctxt_argsize(AX), DX
+	MOVQ	cbctxt_gobody(AX), AX
 
 	// preserve whatever's at the memory location that
 	// the callback will use to store the return value
@@ -357,7 +354,7 @@ TEXT runtime·tstart_stdcall(SB),NOSPLIT,$0
 	MOVQ	AX, (g_stack+stack_hi)(DX)
 	SUBQ	$(64*1024), AX		// stack size
 	MOVQ	AX, (g_stack+stack_lo)(DX)
-	ADDQ	$const__StackGuard, AX
+	ADDQ	$const_StackGuard, AX
 	MOVQ	AX, g_stackguard0(DX)
 	MOVQ	AX, g_stackguard1(DX)
 
@@ -410,12 +407,12 @@ TEXT runtime·usleep1(SB),NOSPLIT,$0
 
 	MOVQ	m_g0(R13), R14
 	CMPQ	g(R15), R14
-	JNE	switch
+	JNE	usleep1_switch
 	// executing on m->g0 already
 	CALL	AX
-	JMP	ret
+	JMP	usleep1_ret
 
-switch:
+usleep1_switch:
 	// Switch to m->g0 stack and back.
 	MOVQ	(g_sched+gobuf_sp)(R14), R14
 	MOVQ	SP, -8(R14)
@@ -423,7 +420,7 @@ switch:
 	CALL	AX
 	MOVQ	0(SP), SP
 
-ret:
+usleep1_ret:
 	MOVQ	$0, m_libcallsp(R13)
 	RET
 
@@ -438,7 +435,7 @@ TEXT runtime·usleep2(SB),NOSPLIT,$16
 	MOVQ	BX, (R8)
 	MOVQ	$-1, CX // handle
 	MOVQ	$0, DX // alertable
-	MOVQ	runtime·_NtWaitForSingleObject(SB), AX
+	MOVQ	runtime·NtWaitForSingleObject(SB), AX
 	CALL	AX
 	MOVQ	8(SP), SP
 	RET
diff --git a/src/runtime/sys_x86.c b/src/runtime/sys_x86.c
new file mode 100644
index 0000000..a450b3e
--- /dev/null
+++ b/src/runtime/sys_x86.c
@@ -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.
+
+// +build amd64 amd64p32 386
+
+#include "runtime.h"
+
+// adjust Gobuf as it if executed a call to fn with context ctxt
+// and then did an immediate gosave.
+void
+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;
+	gobuf->ctxt = ctxt;
+}
+
+// Called to rewind context saved during morestack back to beginning of function.
+// To help us, the linker emits a jmp back to the beginning right after the
+// call to morestack. We just have to decode and apply that jump.
+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);
+		return;
+	}
+	if(pc[0] == 0xeb) { // jmp 1-byte offset
+		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;
+	}
+	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/runtime/syscall_nacl.h b/src/runtime/syscall_nacl.h
index 834ecfc..b33852e 100644
--- a/src/runtime/syscall_nacl.h
+++ b/src/runtime/syscall_nacl.h
@@ -8,10 +8,10 @@
 #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_isatty 19
 #define SYS_brk 20
 #define SYS_mmap 21
 #define SYS_munmap 22
@@ -69,16 +69,3 @@
 #define SYS_test_crash 110
 #define SYS_test_syscall_1 111
 #define SYS_test_syscall_2 112
-#define SYS_futex_wait_abs 120
-#define SYS_futex_wake 121
-#define SYS_pread 130
-#define SYS_pwrite 131
-#define SYS_truncate 140
-#define SYS_lstat 141
-#define SYS_link 142
-#define SYS_rename 143
-#define SYS_symlink 144
-#define SYS_access 145
-#define SYS_readlink 146
-#define SYS_utimes 147
-#define SYS_get_random_bytes 150
diff --git a/src/runtime/syscall_solaris.c b/src/runtime/syscall_solaris.c
new file mode 100644
index 0000000..13ac31b
--- /dev/null
+++ b/src/runtime/syscall_solaris.c
@@ -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.
+
+#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"
diff --git a/src/runtime/syscall_solaris.go b/src/runtime/syscall_solaris.go
index ae1f334..50d3a1d 100644
--- a/src/runtime/syscall_solaris.go
+++ b/src/runtime/syscall_solaris.go
@@ -9,11 +9,15 @@ import "unsafe"
 var (
 	libc_chdir,
 	libc_chroot,
+	libc_close,
+	libc_dlopen,
+	libc_dlclose,
+	libc_dlsym,
 	libc_execve,
+	libc_exit,
 	libc_fcntl,
 	libc_forkx,
 	libc_gethostname,
-	libc_getpid,
 	libc_ioctl,
 	libc_pipe,
 	libc_setgid,
@@ -23,6 +27,7 @@ var (
 	libc_setpgid,
 	libc_syscall,
 	libc_wait4,
+	libc_write,
 	pipe1 libcFunc
 )
 
@@ -33,9 +38,9 @@ func syscall_sysvicall6(fn, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err
 		n:    nargs,
 		args: uintptr(unsafe.Pointer(&a1)),
 	}
-	entersyscallblock(0)
+	entersyscallblock()
 	asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(&call))
-	exitsyscall(0)
+	exitsyscall()
 	return call.r1, call.r2, call.err
 }
 
@@ -82,6 +87,48 @@ func syscall_close(fd int32) int32 {
 	return int32(sysvicall1(&libc_close, uintptr(fd)))
 }
 
+func syscall_dlopen(name *byte, mode uintptr) (handle uintptr, err uintptr) {
+	call := libcall{
+		fn:   uintptr(unsafe.Pointer(&libc_dlopen)),
+		n:    2,
+		args: uintptr(unsafe.Pointer(&name)),
+	}
+	entersyscallblock()
+	asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(&call))
+	exitsyscall()
+	if call.r1 == 0 {
+		return call.r1, call.err
+	}
+	return call.r1, 0
+}
+
+func syscall_dlclose(handle uintptr) (err uintptr) {
+	call := libcall{
+		fn:   uintptr(unsafe.Pointer(&libc_dlclose)),
+		n:    1,
+		args: uintptr(unsafe.Pointer(&handle)),
+	}
+	entersyscallblock()
+	asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(&call))
+	exitsyscall()
+	return call.r1
+}
+
+func syscall_dlsym(handle uintptr, name *byte) (proc uintptr, err uintptr) {
+	call := libcall{
+		fn:   uintptr(unsafe.Pointer(&libc_dlsym)),
+		n:    2,
+		args: uintptr(unsafe.Pointer(&handle)),
+	}
+	entersyscallblock()
+	asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(&call))
+	exitsyscall()
+	if call.r1 == 0 {
+		return call.r1, call.err
+	}
+	return call.r1, 0
+}
+
 //go:nosplit
 func syscall_execve(path, argv, envp uintptr) (err uintptr) {
 	call := libcall{
@@ -129,9 +176,9 @@ func syscall_gethostname() (name string, err uintptr) {
 		n:    2,
 		args: uintptr(unsafe.Pointer(&args[0])),
 	}
-	entersyscallblock(0)
+	entersyscallblock()
 	asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(&call))
-	exitsyscall(0)
+	exitsyscall()
 	if call.r1 != 0 {
 		return "", call.err
 	}
@@ -140,17 +187,6 @@ func syscall_gethostname() (name string, err uintptr) {
 }
 
 //go:nosplit
-func syscall_getpid() (pid, err uintptr) {
-	call := libcall{
-		fn:   uintptr(unsafe.Pointer(&libc_getpid)),
-		n:    0,
-		args: uintptr(unsafe.Pointer(&libc_getpid)), // it's unused but must be non-nil, otherwise crashes
-	}
-	asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(&call))
-	return call.r1, call.err
-}
-
-//go:nosplit
 func syscall_ioctl(fd, req, arg uintptr) (err uintptr) {
 	call := libcall{
 		fn:   uintptr(unsafe.Pointer(&libc_ioctl)),
@@ -167,9 +203,9 @@ func syscall_pipe() (r, w, err uintptr) {
 		n:    0,
 		args: uintptr(unsafe.Pointer(&pipe1)), // it's unused but must be non-nil, otherwise crashes
 	}
-	entersyscallblock(0)
+	entersyscallblock()
 	asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(&call))
-	exitsyscall(0)
+	exitsyscall()
 	return call.r1, call.r2, call.err
 }
 
@@ -256,9 +292,9 @@ func syscall_syscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr) {
 		n:    4,
 		args: uintptr(unsafe.Pointer(&trap)),
 	}
-	entersyscallblock(0)
+	entersyscallblock()
 	asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(&call))
-	exitsyscall(0)
+	exitsyscall()
 	return call.r1, call.r2, call.err
 }
 
@@ -268,9 +304,9 @@ func syscall_wait4(pid uintptr, wstatus *uint32, options uintptr, rusage unsafe.
 		n:    4,
 		args: uintptr(unsafe.Pointer(&pid)),
 	}
-	entersyscallblock(0)
+	entersyscallblock()
 	asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(&call))
-	exitsyscall(0)
+	exitsyscall()
 	return int(call.r1), call.err
 }
 
diff --git a/src/runtime/syscall_windows.go b/src/runtime/syscall_windows.go
index 8e069cd..51004b7 100644
--- a/src/runtime/syscall_windows.go
+++ b/src/runtime/syscall_windows.go
@@ -8,6 +8,8 @@ import (
 	"unsafe"
 )
 
+const _SIGPROF = 0 // dummy value for badsignal
+
 type callbacks struct {
 	lock mutex
 	ctxt [cb_max]*wincallbackcontext
@@ -39,25 +41,26 @@ func callbackasmAddr(i int) uintptr {
 	return uintptr(add(unsafe.Pointer(&callbackasm), uintptr(i*5)))
 }
 
-//go:linkname compileCallback syscall.compileCallback
 func compileCallback(fn eface, cleanstack bool) (code uintptr) {
 	if fn._type == nil || (fn._type.kind&kindMask) != kindFunc {
-		panic("compileCallback: not a function")
+		panic("compilecallback: not a function")
 	}
 	ft := (*functype)(unsafe.Pointer(fn._type))
-	if ft.out.len != 1 {
-		panic("compileCallback: function must have one output parameter")
+	if len(ft.out) != 1 {
+		panic("compilecallback: function must have one output parameter")
 	}
 	uintptrSize := unsafe.Sizeof(uintptr(0))
-	if t := (**_type)(unsafe.Pointer(ft.out.array)); (*t).size != uintptrSize {
-		panic("compileCallback: output parameter size is wrong")
+	if t := (**_type)(unsafe.Pointer(&ft.out[0])); (*t).size != uintptrSize {
+		panic("compilecallback: output parameter size is wrong")
 	}
 	argsize := uintptr(0)
-	for _, t := range (*[1024](*_type))(unsafe.Pointer(ft.in.array))[:ft.in.len] {
-		if (*t).size > uintptrSize {
-			panic("compileCallback: input parameter size is wrong")
+	if len(ft.in) > 0 {
+		for _, t := range (*[1024](*_type))(unsafe.Pointer(&ft.in[0]))[:len(ft.in)] {
+			if (*t).size > uintptrSize {
+				panic("compilecallback: input parameter size is wrong")
+			}
+			argsize += uintptrSize
 		}
-		argsize += uintptrSize
 	}
 
 	lock(&cbs.lock)
@@ -70,7 +73,7 @@ func compileCallback(fn eface, cleanstack bool) (code uintptr) {
 		}
 	}
 	if n >= cb_max {
-		throw("too many callback functions")
+		gothrow("too many callback functions")
 	}
 
 	c := new(wincallbackcontext)
@@ -88,14 +91,15 @@ func compileCallback(fn eface, cleanstack bool) (code uintptr) {
 	return callbackasmAddr(n)
 }
 
-//go:linkname syscall_loadlibrary syscall.loadlibrary
+func getLoadLibrary() uintptr
+
 //go:nosplit
 func syscall_loadlibrary(filename *uint16) (handle, err uintptr) {
-	c := &getg().m.syscall
+	var c libcall
 	c.fn = getLoadLibrary()
 	c.n = 1
-	c.args = uintptr(noescape(unsafe.Pointer(&filename)))
-	cgocall(asmstdcallAddr, unsafe.Pointer(c))
+	c.args = uintptr(unsafe.Pointer(&filename))
+	cgocall_errno(unsafe.Pointer(funcPC(asmstdcall)), unsafe.Pointer(&c))
 	handle = c.r1
 	if handle == 0 {
 		err = c.err
@@ -103,14 +107,15 @@ func syscall_loadlibrary(filename *uint16) (handle, err uintptr) {
 	return
 }
 
-//go:linkname syscall_getprocaddress syscall.getprocaddress
+func getGetProcAddress() uintptr
+
 //go:nosplit
 func syscall_getprocaddress(handle uintptr, procname *byte) (outhandle, err uintptr) {
-	c := &getg().m.syscall
+	var c libcall
 	c.fn = getGetProcAddress()
 	c.n = 2
-	c.args = uintptr(noescape(unsafe.Pointer(&handle)))
-	cgocall(asmstdcallAddr, unsafe.Pointer(c))
+	c.args = uintptr(unsafe.Pointer(&handle))
+	cgocall_errno(unsafe.Pointer(funcPC(asmstdcall)), unsafe.Pointer(&c))
 	outhandle = c.r1
 	if outhandle == 0 {
 		err = c.err
@@ -118,57 +123,52 @@ func syscall_getprocaddress(handle uintptr, procname *byte) (outhandle, err uint
 	return
 }
 
-//go:linkname syscall_Syscall syscall.Syscall
 //go:nosplit
 func syscall_Syscall(fn, nargs, a1, a2, a3 uintptr) (r1, r2, err uintptr) {
-	c := &getg().m.syscall
+	var c libcall
 	c.fn = fn
 	c.n = nargs
-	c.args = uintptr(noescape(unsafe.Pointer(&a1)))
-	cgocall(asmstdcallAddr, unsafe.Pointer(c))
+	c.args = uintptr(unsafe.Pointer(&a1))
+	cgocall_errno(unsafe.Pointer(funcPC(asmstdcall)), unsafe.Pointer(&c))
 	return c.r1, c.r2, c.err
 }
 
-//go:linkname syscall_Syscall6 syscall.Syscall6
 //go:nosplit
 func syscall_Syscall6(fn, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) {
-	c := &getg().m.syscall
+	var c libcall
 	c.fn = fn
 	c.n = nargs
-	c.args = uintptr(noescape(unsafe.Pointer(&a1)))
-	cgocall(asmstdcallAddr, unsafe.Pointer(c))
+	c.args = uintptr(unsafe.Pointer(&a1))
+	cgocall_errno(unsafe.Pointer(funcPC(asmstdcall)), unsafe.Pointer(&c))
 	return c.r1, c.r2, c.err
 }
 
-//go:linkname syscall_Syscall9 syscall.Syscall9
 //go:nosplit
 func syscall_Syscall9(fn, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2, err uintptr) {
-	c := &getg().m.syscall
+	var c libcall
 	c.fn = fn
 	c.n = nargs
-	c.args = uintptr(noescape(unsafe.Pointer(&a1)))
-	cgocall(asmstdcallAddr, unsafe.Pointer(c))
+	c.args = uintptr(unsafe.Pointer(&a1))
+	cgocall_errno(unsafe.Pointer(funcPC(asmstdcall)), unsafe.Pointer(&c))
 	return c.r1, c.r2, c.err
 }
 
-//go:linkname syscall_Syscall12 syscall.Syscall12
 //go:nosplit
 func syscall_Syscall12(fn, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12 uintptr) (r1, r2, err uintptr) {
-	c := &getg().m.syscall
+	var c libcall
 	c.fn = fn
 	c.n = nargs
-	c.args = uintptr(noescape(unsafe.Pointer(&a1)))
-	cgocall(asmstdcallAddr, unsafe.Pointer(c))
+	c.args = uintptr(unsafe.Pointer(&a1))
+	cgocall_errno(unsafe.Pointer(funcPC(asmstdcall)), unsafe.Pointer(&c))
 	return c.r1, c.r2, c.err
 }
 
-//go:linkname syscall_Syscall15 syscall.Syscall15
 //go:nosplit
 func syscall_Syscall15(fn, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15 uintptr) (r1, r2, err uintptr) {
-	c := &getg().m.syscall
+	var c libcall
 	c.fn = fn
 	c.n = nargs
-	c.args = uintptr(noescape(unsafe.Pointer(&a1)))
-	cgocall(asmstdcallAddr, unsafe.Pointer(c))
+	c.args = uintptr(unsafe.Pointer(&a1))
+	cgocall_errno(unsafe.Pointer(funcPC(asmstdcall)), unsafe.Pointer(&c))
 	return c.r1, c.r2, c.err
 }
diff --git a/src/runtime/syscall_windows_test.go b/src/runtime/syscall_windows_test.go
index 677eb5f..126bef6 100644
--- a/src/runtime/syscall_windows_test.go
+++ b/src/runtime/syscall_windows_test.go
@@ -271,7 +271,7 @@ func (f cbDLLFunc) buildOne(stdcall bool) string {
 	typename := "t" + funcname
 	p := make([]string, f)
 	for i := range p {
-		p[i] = "uintptr_t"
+		p[i] = "void*"
 	}
 	params := strings.Join(p, ",")
 	for i := range p {
@@ -280,9 +280,9 @@ func (f cbDLLFunc) buildOne(stdcall bool) string {
 	args := strings.Join(p, ",")
 	return fmt.Sprintf(`
 typedef void %s (*%s)(%s);
-void %s(%s f, uintptr_t n) {
-	uintptr_t i;
-	for(i=0;i<n;i++){
+void %s(%s f, void *n) {
+	int i;
+	for(i=0;i<(int)n;i++){
 		f(%s);
 	}
 }
@@ -290,7 +290,7 @@ void %s(%s f, uintptr_t n) {
 }
 
 func (f cbDLLFunc) build() string {
-	return "#include <stdint.h>\n\n" + f.buildOne(false) + f.buildOne(true)
+	return f.buildOne(false) + f.buildOne(true)
 }
 
 var cbFuncs = [...]interface{}{
@@ -379,13 +379,13 @@ var cbDLLs = []cbDLL{
 	{
 		"test",
 		func(out, src string) []string {
-			return []string{"gcc", "-shared", "-s", "-Werror", "-o", out, src}
+			return []string{"gcc", "-shared", "-s", "-o", out, src}
 		},
 	},
 	{
 		"testO2",
 		func(out, src string) []string {
-			return []string{"gcc", "-shared", "-s", "-Werror", "-o", out, "-O2", src}
+			return []string{"gcc", "-shared", "-s", "-o", out, "-O2", src}
 		},
 	},
 }
@@ -436,9 +436,6 @@ var cbTests = []cbTest{
 }
 
 func TestStdcallAndCDeclCallbacks(t *testing.T) {
-	if _, err := exec.LookPath("gcc"); err != nil {
-		t.Skip("skipping test: gcc is missing")
-	}
 	tmp, err := ioutil.TempDir("", "TestCDeclCallback")
 	if err != nil {
 		t.Fatal("TempDir failed: ", err)
@@ -537,106 +534,10 @@ func main() {
 }
 `
 
-func TestWERDialogue(t *testing.T) {
-	if os.Getenv("TESTING_WER_DIALOGUE") == "1" {
-		defer os.Exit(0)
-
-		*runtime.TestingWER = true
-		const EXCEPTION_NONCONTINUABLE = 1
-		mod := syscall.MustLoadDLL("kernel32.dll")
-		proc := mod.MustFindProc("RaiseException")
-		proc.Call(0xbad, EXCEPTION_NONCONTINUABLE, 0, 0)
-		println("RaiseException should not return")
-		return
-	}
-	cmd := exec.Command(os.Args[0], "-test.run=TestWERDialogue")
-	cmd.Env = []string{"TESTING_WER_DIALOGUE=1"}
-	// Child process should not open WER dialogue, but return immediately instead.
-	cmd.CombinedOutput()
-}
-
-var used byte
-
-func use(buf []byte) {
-	for _, c := range buf {
-		used += c
-	}
-}
-
-func forceStackCopy() (r int) {
-	var f func(int) int
-	f = func(i int) int {
-		var buf [256]byte
-		use(buf[:])
-		if i == 0 {
-			return 0
-		}
-		return i + f(i-1)
-	}
-	r = f(128)
-	return
-}
-
-func TestReturnAfterStackGrowInCallback(t *testing.T) {
-	if _, err := exec.LookPath("gcc"); err != nil {
-		t.Skip("skipping test: gcc is missing")
-	}
-
-	const src = `
-#include <stdint.h>
-#include <windows.h>
-
-typedef uintptr_t __stdcall (*callback)(uintptr_t);
-
-uintptr_t cfunc(callback f, uintptr_t n) {
-   uintptr_t r;
-   r = f(n);
-   SetLastError(333);
-   return r;
-}
-`
-	tmpdir, err := ioutil.TempDir("", "TestReturnAfterStackGrowInCallback")
-	if err != nil {
-		t.Fatal("TempDir failed: ", err)
-	}
-	defer os.RemoveAll(tmpdir)
-
-	srcname := "mydll.c"
-	err = ioutil.WriteFile(filepath.Join(tmpdir, srcname), []byte(src), 0)
-	if err != nil {
-		t.Fatal(err)
-	}
-	outname := "mydll.dll"
-	cmd := exec.Command("gcc", "-shared", "-s", "-Werror", "-o", outname, srcname)
-	cmd.Dir = tmpdir
-	out, err := cmd.CombinedOutput()
-	if err != nil {
-		t.Fatalf("failed to build dll: %v - %v", err, string(out))
-	}
-	dllpath := filepath.Join(tmpdir, outname)
-
-	dll := syscall.MustLoadDLL(dllpath)
-	defer dll.Release()
-
-	proc := dll.MustFindProc("cfunc")
-
-	cb := syscall.NewCallback(func(n uintptr) uintptr {
-		forceStackCopy()
-		return n
-	})
-
-	// Use a new goroutine so that we get a small stack.
-	type result struct {
-		r   uintptr
-		err syscall.Errno
-	}
-	c := make(chan result)
-	go func() {
-		r, _, err := proc.Call(cb, 100)
-		c <- result{r, err.(syscall.Errno)}
-	}()
-	want := result{r: 100, err: 333}
-	if got := <-c; got != want {
-		t.Errorf("got %d want %d", got, want)
-	}
+func TestCallbackWithNoInputParameters(t *testing.T) {
+	// Test that NewCallback and NewCallbackCDecl can accept functions without
+	// input parameters, see issue 9871.
+	cb := func() uintptr { return 0 }
+	_ = syscall.NewCallback(cb)
+	_ = syscall.NewCallbackCDecl(cb)
 }
diff --git a/src/runtime/thunk.s b/src/runtime/thunk.s
new file mode 100644
index 0000000..0a0f147
--- /dev/null
+++ b/src/runtime/thunk.s
@@ -0,0 +1,183 @@
+// 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 file exposes various internal runtime functions to other packages in std lib.
+
+#include "zasm_GOOS_GOARCH.h"
+#include "textflag.h"
+
+#ifdef GOARCH_arm
+#define JMP B
+#endif
+
+TEXT net·runtimeNano(SB),NOSPLIT,$0-0
+	JMP	runtime·nanotime(SB)
+
+TEXT time·runtimeNano(SB),NOSPLIT,$0-0
+	JMP     runtime·nanotime(SB)
+
+TEXT time·Sleep(SB),NOSPLIT,$0-0
+	JMP     runtime·timeSleep(SB)
+
+TEXT time·startTimer(SB),NOSPLIT,$0-0
+	JMP     runtime·startTimer(SB)
+
+TEXT time·stopTimer(SB),NOSPLIT,$0-0
+	JMP     runtime·stopTimer(SB)
+
+TEXT sync·runtime_Syncsemacquire(SB),NOSPLIT,$0-0
+	JMP	runtime·syncsemacquire(SB)
+
+TEXT sync·runtime_Syncsemrelease(SB),NOSPLIT,$0-0
+	JMP	runtime·syncsemrelease(SB)
+
+TEXT sync·runtime_Syncsemcheck(SB),NOSPLIT,$0-0
+	JMP	runtime·syncsemcheck(SB)
+
+TEXT sync·runtime_Semacquire(SB),NOSPLIT,$0-0
+	JMP	runtime·asyncsemacquire(SB)
+
+TEXT sync·runtime_Semrelease(SB),NOSPLIT,$0-0
+	JMP	runtime·asyncsemrelease(SB)
+
+TEXT sync·runtime_registerPoolCleanup(SB),NOSPLIT,$0-0
+	JMP	runtime·registerPoolCleanup(SB)
+
+TEXT net·runtime_Semacquire(SB),NOSPLIT,$0-0
+	JMP	runtime·asyncsemacquire(SB)
+
+TEXT net·runtime_Semrelease(SB),NOSPLIT,$0-0
+	JMP	runtime·asyncsemrelease(SB)
+
+TEXT runtime∕pprof·runtime_cyclesPerSecond(SB),NOSPLIT,$0-0
+	JMP	runtime·tickspersecond(SB)
+
+TEXT bytes·Compare(SB),NOSPLIT,$0-0
+	JMP	runtime·cmpbytes(SB)
+
+TEXT reflect·call(SB), NOSPLIT, $0-0
+	JMP	runtime·reflectcall(SB)
+
+TEXT reflect·chanclose(SB), NOSPLIT, $0-0
+	JMP	runtime·closechan(SB)
+
+TEXT reflect·chanlen(SB), NOSPLIT, $0-0
+	JMP	runtime·reflect_chanlen(SB)
+
+TEXT reflect·chancap(SB), NOSPLIT, $0-0
+	JMP	runtime·reflect_chancap(SB)
+
+TEXT reflect·chansend(SB), NOSPLIT, $0-0
+	JMP	runtime·reflect_chansend(SB)
+
+TEXT reflect·chanrecv(SB), NOSPLIT, $0-0
+	JMP	runtime·reflect_chanrecv(SB)
+
+TEXT reflect·memmove(SB), NOSPLIT, $0-0
+	JMP	runtime·memmove(SB)
+
+TEXT runtime∕debug·freeOSMemory(SB), NOSPLIT, $0-0
+	JMP	runtime·freeOSMemory(SB)
+
+TEXT runtime∕debug·WriteHeapDump(SB), NOSPLIT, $0-0
+	JMP	runtime·writeHeapDump(SB)
+
+TEXT net·runtime_pollServerInit(SB),NOSPLIT,$0-0
+	JMP	runtime·netpollServerInit(SB)
+
+TEXT net·runtime_pollOpen(SB),NOSPLIT,$0-0
+	JMP	runtime·netpollOpen(SB)
+
+TEXT net·runtime_pollClose(SB),NOSPLIT,$0-0
+	JMP	runtime·netpollClose(SB)
+
+TEXT net·runtime_pollReset(SB),NOSPLIT,$0-0
+	JMP	runtime·netpollReset(SB)
+
+TEXT net·runtime_pollWait(SB),NOSPLIT,$0-0
+	JMP	runtime·netpollWait(SB)
+
+TEXT net·runtime_pollWaitCanceled(SB),NOSPLIT,$0-0
+	JMP	runtime·netpollWaitCanceled(SB)
+
+TEXT net·runtime_pollSetDeadline(SB),NOSPLIT,$0-0
+	JMP	runtime·netpollSetDeadline(SB)
+
+TEXT net·runtime_pollUnblock(SB),NOSPLIT,$0-0
+	JMP	runtime·netpollUnblock(SB)
+
+TEXT syscall·setenv_c(SB), NOSPLIT, $0-0
+	JMP	runtime·syscall_setenv_c(SB)
+
+TEXT syscall·unsetenv_c(SB), NOSPLIT, $0-0
+	JMP	runtime·syscall_unsetenv_c(SB)
+
+TEXT reflect·makemap(SB),NOSPLIT,$0-0
+	JMP	runtime·reflect_makemap(SB)
+
+TEXT reflect·mapaccess(SB),NOSPLIT,$0-0
+	JMP	runtime·reflect_mapaccess(SB)
+
+TEXT reflect·mapassign(SB),NOSPLIT,$0-0
+	JMP	runtime·reflect_mapassign(SB)
+
+TEXT reflect·mapdelete(SB),NOSPLIT,$0-0
+	JMP	runtime·reflect_mapdelete(SB)
+
+TEXT reflect·mapiterinit(SB),NOSPLIT,$0-0
+	JMP	runtime·reflect_mapiterinit(SB)
+
+TEXT reflect·mapiterkey(SB),NOSPLIT,$0-0
+	JMP	runtime·reflect_mapiterkey(SB)
+
+TEXT reflect·mapiternext(SB),NOSPLIT,$0-0
+	JMP	runtime·reflect_mapiternext(SB)
+
+TEXT reflect·maplen(SB),NOSPLIT,$0-0
+	JMP	runtime·reflect_maplen(SB)
+
+TEXT reflect·ismapkey(SB),NOSPLIT,$0-0
+	JMP	runtime·reflect_ismapkey(SB)
+
+TEXT reflect·ifaceE2I(SB),NOSPLIT,$0-0
+	JMP	runtime·reflect_ifaceE2I(SB)
+
+TEXT reflect·unsafe_New(SB),NOSPLIT,$0-0
+	JMP	runtime·newobject(SB)
+
+TEXT reflect·unsafe_NewArray(SB),NOSPLIT,$0-0
+	JMP	runtime·newarray(SB)
+
+TEXT reflect·makechan(SB),NOSPLIT,$0-0
+	JMP	runtime·makechan(SB)
+
+TEXT reflect·rselect(SB),NOSPLIT,$0-0
+	JMP	runtime·reflect_rselect(SB)
+
+TEXT os·sigpipe(SB),NOSPLIT,$0-0
+	JMP	runtime·os_sigpipe(SB)
+
+TEXT runtime·runtime_init(SB),NOSPLIT,$0-0
+	JMP	runtime·init(SB)
+
+TEXT runtime·main_init(SB),NOSPLIT,$0-0
+	JMP	main·init(SB)
+
+TEXT runtime·main_main(SB),NOSPLIT,$0-0
+	JMP	main·main(SB)
+
+TEXT runtime·timenow(SB),NOSPLIT,$0-0
+	JMP	time·now(SB)
+
+TEXT sync∕atomic·runtime_procPin(SB),NOSPLIT,$0-0
+	JMP     sync·runtime_procPin(SB)
+
+TEXT sync∕atomic·runtime_procUnpin(SB),NOSPLIT,$0-0
+	JMP     sync·runtime_procUnpin(SB)
+
+TEXT syscall·runtime_envs(SB),NOSPLIT,$0-0
+	JMP	runtime·runtime_envs(SB)
+
+TEXT os·runtime_args(SB),NOSPLIT,$0-0
+	JMP	runtime·runtime_args(SB)
diff --git a/src/runtime/thunk_solaris_amd64.s b/src/runtime/thunk_solaris_amd64.s
new file mode 100644
index 0000000..f61188c
--- /dev/null
+++ b/src/runtime/thunk_solaris_amd64.s
@@ -0,0 +1,88 @@
+// 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 file exposes various external library functions to Go code in the runtime.
+
+#include "zasm_GOOS_GOARCH.h"
+#include "textflag.h"
+
+TEXT runtime·libc_chdir(SB),NOSPLIT,$0
+	MOVQ	libc·chdir(SB), AX
+	JMP	AX
+
+TEXT runtime·libc_chroot(SB),NOSPLIT,$0
+	MOVQ	libc·chroot(SB), AX
+	JMP	AX
+
+TEXT runtime·libc_close(SB),NOSPLIT,$0
+	MOVQ	libc·close(SB), AX
+	JMP	AX
+
+TEXT runtime·libc_dlopen(SB),NOSPLIT,$0
+	MOVQ	libc·dlopen(SB), AX
+	JMP	AX
+
+TEXT runtime·libc_dlclose(SB),NOSPLIT,$0
+	MOVQ	libc·dlclose(SB), AX
+	JMP	AX
+
+TEXT runtime·libc_dlsym(SB),NOSPLIT,$0
+	MOVQ	libc·dlsym(SB), AX
+	JMP	AX
+
+TEXT runtime·libc_execve(SB),NOSPLIT,$0
+	MOVQ	libc·execve(SB), AX
+	JMP	AX
+
+TEXT runtime·libc_exit(SB),NOSPLIT,$0
+	MOVQ	libc·exit(SB), AX
+	JMP	AX
+
+TEXT runtime·libc_fcntl(SB),NOSPLIT,$0
+	MOVQ	libc·fcntl(SB), AX
+	JMP	AX
+
+TEXT runtime·libc_forkx(SB),NOSPLIT,$0
+	MOVQ	libc·forkx(SB), AX
+	JMP	AX
+
+TEXT runtime·libc_gethostname(SB),NOSPLIT,$0
+	MOVQ	libc·gethostname(SB), AX
+	JMP	AX
+
+TEXT runtime·libc_ioctl(SB),NOSPLIT,$0
+	MOVQ	libc·ioctl(SB), AX
+	JMP	AX
+
+TEXT runtime·libc_setgid(SB),NOSPLIT,$0
+	MOVQ	libc·setgid(SB), AX
+	JMP	AX
+
+TEXT runtime·libc_setgroups(SB),NOSPLIT,$0
+	MOVQ	libc·setgroups(SB), AX
+	JMP	AX
+
+TEXT runtime·libc_setsid(SB),NOSPLIT,$0
+	MOVQ	libc·setsid(SB), AX
+	JMP	AX
+
+TEXT runtime·libc_setuid(SB),NOSPLIT,$0
+	MOVQ	libc·setuid(SB), AX
+	JMP	AX
+
+TEXT runtime·libc_setpgid(SB),NOSPLIT,$0
+	MOVQ	libc·setpgid(SB), AX
+	JMP	AX
+
+TEXT runtime·libc_syscall(SB),NOSPLIT,$0
+	MOVQ	libc·syscall(SB), AX
+	JMP	AX
+
+TEXT runtime·libc_wait4(SB),NOSPLIT,$0
+	MOVQ	libc·wait4(SB), AX
+	JMP	AX
+
+TEXT runtime·libc_write(SB),NOSPLIT,$0
+	MOVQ	libc·write(SB), AX
+	JMP	AX
diff --git a/src/runtime/thunk_windows.s b/src/runtime/thunk_windows.s
new file mode 100644
index 0000000..7ccb98f
--- /dev/null
+++ b/src/runtime/thunk_windows.s
@@ -0,0 +1,30 @@
+// 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 "zasm_GOOS_GOARCH.h"
+#include "textflag.h"
+
+TEXT syscall·Syscall(SB),NOSPLIT,$0-0
+	JMP	runtime·syscall_Syscall(SB)
+
+TEXT syscall·Syscall6(SB),NOSPLIT,$0-0
+	JMP	runtime·syscall_Syscall6(SB)
+
+TEXT syscall·Syscall9(SB),NOSPLIT,$0-0
+	JMP	runtime·syscall_Syscall9(SB)
+
+TEXT syscall·Syscall12(SB),NOSPLIT,$0-0
+	JMP	runtime·syscall_Syscall12(SB)
+
+TEXT syscall·Syscall15(SB),NOSPLIT,$0-0
+	JMP	runtime·syscall_Syscall15(SB)
+
+TEXT syscall·loadlibrary(SB),NOSPLIT,$0-0
+	JMP	runtime·syscall_loadlibrary(SB)
+
+TEXT syscall·getprocaddress(SB),NOSPLIT,$0-0
+	JMP	runtime·syscall_getprocaddress(SB)
+
+TEXT syscall·compileCallback(SB),NOSPLIT,$0
+	JMP	runtime·compileCallback(SB)
diff --git a/src/runtime/time.go b/src/runtime/time.go
index ffe7590..11862c7 100644
--- a/src/runtime/time.go
+++ b/src/runtime/time.go
@@ -43,8 +43,7 @@ var faketime int64
 
 // time.now is implemented in assembly.
 
-// timeSleep puts the current goroutine to sleep for at least ns nanoseconds.
-//go:linkname timeSleep time.Sleep
+// Sleep puts the current goroutine to sleep for at least ns nanoseconds.
 func timeSleep(ns int64) {
 	if ns <= 0 {
 		return
@@ -56,11 +55,10 @@ func timeSleep(ns int64) {
 	t.arg = getg()
 	lock(&timers.lock)
 	addtimerLocked(t)
-	goparkunlock(&timers.lock, "sleep", traceEvGoSleep, 2)
+	goparkunlock(&timers.lock, "sleep")
 }
 
 // startTimer adds t to the timer heap.
-//go:linkname startTimer time.startTimer
 func startTimer(t *timer) {
 	if raceenabled {
 		racerelease(unsafe.Pointer(t))
@@ -70,7 +68,6 @@ func startTimer(t *timer) {
 
 // stopTimer removes t from the timer heap if it is there.
 // It returns true if t was removed, false if t wasn't even there.
-//go:linkname stopTimer time.stopTimer
 func stopTimer(t *timer) bool {
 	return deltimer(t)
 }
@@ -79,7 +76,7 @@ func stopTimer(t *timer) bool {
 
 // Ready the goroutine arg.
 func goroutineReady(arg interface{}, seq uintptr) {
-	goready(arg.(*g), 0)
+	goready(arg.(*g))
 }
 
 func addtimer(t *timer) {
@@ -108,7 +105,7 @@ func addtimerLocked(t *timer) {
 		}
 		if timers.rescheduling {
 			timers.rescheduling = false
-			goready(timers.gp, 0)
+			goready(timers.gp)
 		}
 	}
 	if !timers.created {
@@ -153,6 +150,7 @@ func deltimer(t *timer) bool {
 // If addtimer inserts a new earlier event, addtimer1 wakes timerproc early.
 func timerproc() {
 	timers.gp = getg()
+	timers.gp.issystem = true
 	for {
 		lock(&timers.lock)
 		timers.sleeping = false
@@ -199,7 +197,7 @@ func timerproc() {
 		if delta < 0 || faketime > 0 {
 			// No timers left - put goroutine to sleep.
 			timers.rescheduling = true
-			goparkunlock(&timers.lock, "timer goroutine (idle)", traceEvGoBlock, 1)
+			goparkunlock(&timers.lock, "timer goroutine (idle)")
 			continue
 		}
 		// At least one timer pending.  Sleep until then.
@@ -289,15 +287,3 @@ func siftdownTimer(i int) {
 		i = c
 	}
 }
-
-// Entry points for net, time to call nanotime.
-
-//go:linkname net_runtimeNano net.runtimeNano
-func net_runtimeNano() int64 {
-	return nanotime()
-}
-
-//go:linkname time_runtimeNano time.runtimeNano
-func time_runtimeNano() int64 {
-	return nanotime()
-}
diff --git a/src/runtime/tls_arm.s b/src/runtime/tls_arm.s
index d37970e..85c3940 100644
--- a/src/runtime/tls_arm.s
+++ b/src/runtime/tls_arm.s
@@ -2,8 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-#include "go_asm.h"
-#include "go_tls.h"
+#include "zasm_GOOS_GOARCH.h"
 #include "funcdata.h"
 #include "textflag.h"
 
@@ -15,14 +14,8 @@
 // Note: both functions will clobber R0 and R11 and
 // can be called from 5c ABI code.
 
-// On android and darwin, runtime.tlsg is a normal variable.
+// On android, runtime.tlsg is a normal variable.
 // TLS offset is computed in x_cgo_inittls.
-#ifdef GOOS_android
-#define TLSG_IS_VARIABLE
-#endif
-#ifdef GOOS_darwin
-#define TLSG_IS_VARIABLE
-#endif
 
 // save_g saves the g register into pthread-provided
 // thread-local memory, so that we can call externally compiled
@@ -40,11 +33,10 @@ TEXT runtime·save_g(SB),NOSPLIT,$-4
 	// a call to runtime.read_tls_fallback which jumps to __kuser_get_tls.
 	// The replacement function saves LR in R11 over the call to read_tls_fallback.
 	MRC	15, 0, R0, C13, C0, 3 // fetch TLS base pointer
-	BIC $3, R0 // Darwin/ARM might return unaligned pointer
 	// $runtime.tlsg(SB) is a special linker symbol.
 	// It is the offset from the TLS base pointer to our
 	// thread-local storage for g.
-#ifdef TLSG_IS_VARIABLE
+#ifdef GOOS_android
 	MOVW	runtime·tlsg(SB), R11
 #else
 	MOVW	$runtime·tlsg(SB), R11
@@ -64,11 +56,10 @@ TEXT runtime·load_g(SB),NOSPLIT,$0
 #endif
 	// See save_g
 	MRC	15, 0, R0, C13, C0, 3 // fetch TLS base pointer
-	BIC $3, R0 // Darwin/ARM might return unaligned pointer
 	// $runtime.tlsg(SB) is a special linker symbol.
 	// It is the offset from the TLS base pointer to our
 	// thread-local storage for g.
-#ifdef TLSG_IS_VARIABLE
+#ifdef GOOS_android
 	MOVW	runtime·tlsg(SB), R11
 #else
 	MOVW	$runtime·tlsg(SB), R11
@@ -76,38 +67,3 @@ TEXT runtime·load_g(SB),NOSPLIT,$0
 	ADD	R11, R0
 	MOVW	0(R0), g
 	RET
-
-// This is called from rt0_go, which runs on the system stack
-// using the initial stack allocated by the OS.
-// It calls back into standard C using the BL (R4) below.
-// To do that, the stack pointer must be 8-byte-aligned
-// on some systems, notably FreeBSD.
-// The ARM ABI says the stack pointer must be 8-byte-aligned
-// on entry to any function, but only FreeBSD's C library seems to care.
-// The caller was 8-byte aligned, but we push an LR.
-// Declare a dummy word ($4, not $0) to make sure the
-// frame is 8 bytes and stays 8-byte-aligned.
-TEXT runtime·_initcgo(SB),NOSPLIT,$4
-#ifndef GOOS_nacl
-	// if there is an _cgo_init, call it.
-	MOVW	_cgo_init(SB), R4
-	CMP	$0, R4
-	B.EQ	nocgo
-	MRC     15, 0, R0, C13, C0, 3 	// load TLS base pointer
-	MOVW 	R0, R3 			// arg 3: TLS base pointer
-	MOVW 	$runtime·tlsg(SB), R2 	// arg 2: tlsg
-	MOVW	$setg_gcc<>(SB), R1 	// arg 1: setg
-	MOVW	g, R0 			// arg 0: G
-	BL	(R4) // will clobber R0-R3
-#endif
-nocgo:
-	RET
-
-// void setg_gcc(G*); set g called from gcc.
-TEXT setg_gcc<>(SB),NOSPLIT,$0
-	MOVW	R0, g
-	B		runtime·save_g(SB)
-
-#ifdef TLSG_IS_VARIABLE
-GLOBL runtime·tlsg+0(SB), NOPTR, $4
-#endif
diff --git a/src/runtime/traceback.go b/src/runtime/traceback.go
index 48ef6e5..1c6ce6e 100644
--- a/src/runtime/traceback.go
+++ b/src/runtime/traceback.go
@@ -32,24 +32,15 @@ const usesLR = GOARCH != "amd64" && GOARCH != "amd64p32" && GOARCH != "386"
 
 var (
 	// initialized in tracebackinit
-	goexitPC             uintptr
-	jmpdeferPC           uintptr
-	mcallPC              uintptr
-	morestackPC          uintptr
-	mstartPC             uintptr
-	rt0_goPC             uintptr
-	sigpanicPC           uintptr
-	runfinqPC            uintptr
-	backgroundgcPC       uintptr
-	bgsweepPC            uintptr
-	forcegchelperPC      uintptr
-	timerprocPC          uintptr
-	gcBgMarkWorkerPC     uintptr
-	systemstack_switchPC uintptr
-	systemstackPC        uintptr
-	stackBarrierPC       uintptr
-
-	gogoPC uintptr
+	deferprocPC uintptr
+	goexitPC    uintptr
+	jmpdeferPC  uintptr
+	mcallPC     uintptr
+	morestackPC uintptr
+	mstartPC    uintptr
+	newprocPC   uintptr
+	rt0_goPC    uintptr
+	sigpanicPC  uintptr
 
 	externalthreadhandlerp uintptr // initialized elsewhere
 )
@@ -59,25 +50,15 @@ func tracebackinit() {
 	// Instead of initializing the variables above in the declarations,
 	// schedinit calls this function so that the variables are
 	// initialized and available earlier in the startup sequence.
+	deferprocPC = funcPC(deferproc)
 	goexitPC = funcPC(goexit)
 	jmpdeferPC = funcPC(jmpdefer)
 	mcallPC = funcPC(mcall)
 	morestackPC = funcPC(morestack)
 	mstartPC = funcPC(mstart)
+	newprocPC = funcPC(newproc)
 	rt0_goPC = funcPC(rt0_go)
 	sigpanicPC = funcPC(sigpanic)
-	runfinqPC = funcPC(runfinq)
-	backgroundgcPC = funcPC(backgroundgc)
-	bgsweepPC = funcPC(bgsweep)
-	forcegchelperPC = funcPC(forcegchelper)
-	timerprocPC = funcPC(timerproc)
-	gcBgMarkWorkerPC = funcPC(gcBgMarkWorker)
-	systemstack_switchPC = funcPC(systemstack_switch)
-	systemstackPC = funcPC(systemstack)
-	stackBarrierPC = funcPC(stackBarrier)
-
-	// used by sigprof handler
-	gogoPC = funcPC(gogo)
 }
 
 // Traceback over the deferred function calls.
@@ -98,7 +79,7 @@ func tracebackdefers(gp *g, callback func(*stkframe, unsafe.Pointer) bool, v uns
 			f := findfunc(frame.pc)
 			if f == nil {
 				print("runtime: unknown pc in defer ", hex(frame.pc), "\n")
-				throw("unknown pc")
+				gothrow("unknown pc")
 			}
 			frame.fn = f
 			frame.argp = uintptr(deferArgs(d))
@@ -115,9 +96,9 @@ func tracebackdefers(gp *g, callback func(*stkframe, unsafe.Pointer) bool, v uns
 // the runtime.Callers function (pcbuf != nil), as well as the garbage
 // collector (callback != nil).  A little clunky to merge these, but avoids
 // duplicating the code and all its subtlety.
-func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max int, callback func(*stkframe, unsafe.Pointer) bool, v unsafe.Pointer, flags uint) int {
+func gentraceback(pc0 uintptr, sp0 uintptr, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max int, callback func(*stkframe, unsafe.Pointer) bool, v unsafe.Pointer, flags uint) int {
 	if goexitPC == 0 {
-		throw("gentraceback before goexitPC initialization")
+		gothrow("gentraceback before goexitPC initialization")
 	}
 	g := getg()
 	if g == gp && g == g.m.curg {
@@ -134,14 +115,9 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
 		// accepts an sp for the current goroutine (typically obtained by
 		// calling getcallersp) must not run on that goroutine's stack but
 		// instead on the g0 stack.
-		throw("gentraceback cannot trace user goroutine on its own stack")
+		gothrow("gentraceback cannot trace user goroutine on its own stack")
 	}
 	gotraceback := gotraceback(nil)
-
-	// Fix up returns to the stack barrier by fetching the
-	// original return PC from gp.stkbar.
-	stkbar := gp.stkbar[gp.stkbarPos:]
-
 	if pc0 == ^uintptr(0) && sp0 == ^uintptr(0) { // Signal to fetch saved values from gp.
 		if gp.syscallsp != 0 {
 			pc0 = gp.syscallpc
@@ -166,10 +142,11 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
 		frame.lr = lr0
 	}
 	waspanic := false
+	wasnewproc := false
 	printing := pcbuf == nil && callback == nil
 	_defer := gp._defer
 
-	for _defer != nil && uintptr(_defer.sp) == _NoArgs {
+	for _defer != nil && uintptr(_defer.argp) == _NoArgs {
 		_defer = _defer.link
 	}
 
@@ -189,7 +166,7 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
 	if f == nil {
 		if callback != nil {
 			print("runtime: unknown pc ", hex(frame.pc), "\n")
-			throw("unknown pc")
+			gothrow("unknown pc")
 		}
 		return 0
 	}
@@ -208,15 +185,7 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
 		// Found an actual function.
 		// Derive frame pointer and link register.
 		if frame.fp == 0 {
-			// We want to jump over the systemstack switch. If we're running on the
-			// g0, this systemstack is at the top of the stack.
-			// if we're not on g0 or there's a no curg, then this is a regular call.
-			sp := frame.sp
-			if flags&_TraceJumpStack != 0 && f.entry == systemstackPC && gp == g.m.g0 && gp.m.curg != nil {
-				sp = gp.m.curg.sched.sp
-				stkbar = gp.m.curg.stkbar[gp.m.curg.stkbarPos:]
-			}
-			frame.fp = sp + uintptr(funcspdelta(f, frame.pc))
+			frame.fp = frame.sp + uintptr(funcspdelta(f, frame.pc))
 			if !usesLR {
 				// On x86, call instruction pushes return PC before entering new function.
 				frame.fp += regSize
@@ -234,33 +203,19 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
 			// to avoid that confusion.
 			// See golang.org/issue/8153.
 			if callback != nil {
-				throw("traceback_arm: found jmpdefer when tracing with callback")
+				gothrow("traceback_arm: found jmpdefer when tracing with callback")
 			}
 			frame.lr = 0
 		} else {
-			var lrPtr uintptr
 			if usesLR {
 				if n == 0 && frame.sp < frame.fp || frame.lr == 0 {
-					lrPtr = frame.sp
-					frame.lr = *(*uintptr)(unsafe.Pointer(lrPtr))
+					frame.lr = *(*uintptr)(unsafe.Pointer(frame.sp))
 				}
 			} else {
 				if frame.lr == 0 {
-					lrPtr = frame.fp - regSize
-					frame.lr = uintptr(*(*uintreg)(unsafe.Pointer(lrPtr)))
+					frame.lr = uintptr(*(*uintreg)(unsafe.Pointer(frame.fp - regSize)))
 				}
 			}
-			if frame.lr == stackBarrierPC {
-				// Recover original PC.
-				if stkbar[0].savedLRPtr != lrPtr {
-					print("found next stack barrier at ", hex(lrPtr), "; expected ")
-					gcPrintStkbars(stkbar)
-					print("\n")
-					throw("missed stack barrier")
-				}
-				frame.lr = stkbar[0].savedLRVal
-				stkbar = stkbar[1:]
-			}
 			flr = findfunc(frame.lr)
 			if flr == nil {
 				// This happens if you get a profiling interrupt at just the wrong time.
@@ -268,8 +223,8 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
 				// But if callback is set, we're doing a garbage collection and must
 				// get everything, so crash loudly.
 				if callback != nil {
-					print("runtime: unexpected return pc for ", funcname(f), " called from ", hex(frame.lr), "\n")
-					throw("unknown caller pc")
+					print("runtime: unexpected return pc for ", gofuncname(f), " called from ", hex(frame.lr), "\n")
+					gothrow("unknown caller pc")
 				}
 			}
 		}
@@ -280,12 +235,6 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
 			frame.varp -= regSize
 		}
 
-		// If framepointer_enabled and there's a frame, then
-		// there's a saved bp here.
-		if framepointer_enabled && GOARCH == "amd64" && frame.varp > frame.sp {
-			frame.varp -= regSize
-		}
-
 		// Derive size of arguments.
 		// Most functions have a fixed-size argument block,
 		// so we can use metadata about the function f.
@@ -300,6 +249,32 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
 			setArgInfo(&frame, f, callback != nil)
 		}
 
+		// Determine function SP where deferproc would find its arguments.
+		var sparg uintptr
+		if usesLR {
+			// On link register architectures, that's 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
+			// leave sparg=0 in that case.
+			if frame.fp != frame.sp {
+				sparg = frame.sp + regSize
+				if wasnewproc {
+					sparg += 3 * regSize
+				}
+			}
+		} else {
+			// On x86 that's 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 * ptrSize
+			}
+		}
+
 		// 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
@@ -312,7 +287,7 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
 		// returns; everything live at earlier deferprocs is still live at that one.
 		frame.continpc = frame.pc
 		if waspanic {
-			if _defer != nil && _defer.sp == frame.sp {
+			if _defer != nil && _defer.argp == sparg {
 				frame.continpc = _defer.pc
 			} else {
 				frame.continpc = 0
@@ -320,7 +295,7 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
 		}
 
 		// Unwind our local defer stack past this frame.
-		for _defer != nil && (_defer.sp == frame.sp || _defer.sp == _NoArgs) {
+		for _defer != nil && (_defer.argp == sparg || _defer.argp == _NoArgs) {
 			_defer = _defer.link
 		}
 
@@ -347,7 +322,7 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
 				if (n > 0 || flags&_TraceTrap == 0) && frame.pc > f.entry && !waspanic {
 					tracepc--
 				}
-				print(funcname(f), "(")
+				print(gofuncname(f), "(")
 				argp := (*[100]uintptr)(unsafe.Pointer(frame.argp))
 				for i := uintptr(0); i < frame.arglen/ptrSize; i++ {
 					if i >= 10 {
@@ -360,7 +335,8 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
 					print(hex(argp[i]))
 				}
 				print(")\n")
-				file, line := funcline(f, tracepc)
+				var file string
+				line := funcline(f, tracepc, &file)
 				print("\t", file, ":", line)
 				if frame.pc > f.entry {
 					print(" +", hex(frame.pc-f.entry))
@@ -376,6 +352,7 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
 
 	skipped:
 		waspanic = f.entry == sigpanicPC
+		wasnewproc = f.entry == newprocPC || f.entry == deferprocPC
 
 		// Do not unwind past the bottom of the stack.
 		if flr == nil {
@@ -395,21 +372,17 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
 		if usesLR && waspanic {
 			x := *(*uintptr)(unsafe.Pointer(frame.sp))
 			frame.sp += ptrSize
-			if GOARCH == "arm64" {
-				// arm64 needs 16-byte aligned SP, always
-				frame.sp += ptrSize
-			}
 			f = findfunc(frame.pc)
 			frame.fn = f
 			if f == nil {
 				frame.pc = x
-			} else if funcspdelta(f, frame.pc) == 0 {
+			} else if f.frame == 0 {
 				frame.lr = x
 			}
 		}
 	}
 
-	if printing {
+	if pcbuf == nil && callback == nil {
 		n = nprint
 	}
 
@@ -464,19 +437,12 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
 	// incomplete information then is still better than nothing.
 	if callback != nil && n < max && _defer != nil {
 		if _defer != nil {
-			print("runtime: g", gp.goid, ": leftover defer sp=", hex(_defer.sp), " pc=", hex(_defer.pc), "\n")
+			print("runtime: g", gp.goid, ": leftover defer argp=", hex(_defer.argp), " pc=", hex(_defer.pc), "\n")
 		}
 		for _defer = gp._defer; _defer != nil; _defer = _defer.link {
-			print("\tdefer ", _defer, " sp=", hex(_defer.sp), " pc=", hex(_defer.pc), "\n")
+			print("\tdefer ", _defer, " argp=", hex(_defer.argp), " pc=", hex(_defer.pc), "\n")
 		}
-		throw("traceback has leftover defers")
-	}
-
-	if callback != nil && n < max && len(stkbar) > 0 {
-		print("runtime: g", gp.goid, ": leftover stack barriers ")
-		gcPrintStkbars(stkbar)
-		print("\n")
-		throw("traceback has leftover stack barriers")
+		gothrow("traceback has leftover defers")
 	}
 
 	return n
@@ -486,7 +452,7 @@ func setArgInfo(frame *stkframe, f *_func, needArgMap bool) {
 	frame.arglen = uintptr(f.args)
 	if needArgMap && f.args == _ArgsSizeUnknown {
 		// Extract argument bitmaps for reflect stubs from the calls they made to reflect.
-		switch funcname(f) {
+		switch gofuncname(f) {
 		case "reflect.makeFuncStub", "reflect.methodValueCall":
 			arg0 := frame.sp
 			if usesLR {
@@ -494,11 +460,11 @@ func setArgInfo(frame *stkframe, f *_func, needArgMap bool) {
 			}
 			fn := *(**[2]uintptr)(unsafe.Pointer(arg0))
 			if fn[0] != f.entry {
-				print("runtime: confused by ", funcname(f), "\n")
-				throw("reflect mismatch")
+				print("runtime: confused by ", gofuncname(f), "\n")
+				gothrow("reflect mismatch")
 			}
 			bv := (*bitvector)(unsafe.Pointer(fn[1]))
-			frame.arglen = uintptr(bv.n * ptrSize)
+			frame.arglen = uintptr(bv.n / 2 * ptrSize)
 			frame.argmap = bv
 		}
 	}
@@ -509,12 +475,13 @@ func printcreatedby(gp *g) {
 	pc := gp.gopc
 	f := findfunc(pc)
 	if f != nil && showframe(f, gp) && gp.goid != 1 {
-		print("created by ", funcname(f), "\n")
+		print("created by ", gofuncname(f), "\n")
 		tracepc := pc // back up to CALL instruction for funcline.
 		if pc > f.entry {
 			tracepc -= _PCQuantum
 		}
-		file, line := funcline(f, tracepc)
+		var file string
+		line := funcline(f, tracepc, &file)
 		print("\t", file, ":", line)
 		if pc > f.entry {
 			print(" +", hex(pc-f.entry))
@@ -523,7 +490,7 @@ func printcreatedby(gp *g) {
 	}
 }
 
-func traceback(pc, sp, lr uintptr, gp *g) {
+func traceback(pc uintptr, sp uintptr, lr uintptr, gp *g) {
 	traceback1(pc, sp, lr, gp, 0)
 }
 
@@ -533,11 +500,11 @@ func traceback(pc, sp, lr uintptr, gp *g) {
 // the initial PC must not be rewound to the previous instruction.
 // (All the saved pairs record a PC that is a return address, so we
 // rewind it into the CALL instruction.)
-func tracebacktrap(pc, sp, lr uintptr, gp *g) {
+func tracebacktrap(pc uintptr, sp uintptr, lr uintptr, gp *g) {
 	traceback1(pc, sp, lr, gp, _TraceTrap)
 }
 
-func traceback1(pc, sp, lr uintptr, gp *g, flags uint) {
+func traceback1(pc uintptr, sp uintptr, lr uintptr, gp *g, flags uint) {
 	var n int
 	if readgstatus(gp)&^_Gscan == _Gsyscall {
 		// Override registers if blocked in system call.
@@ -557,28 +524,27 @@ func traceback1(pc, sp, lr uintptr, gp *g, flags uint) {
 	printcreatedby(gp)
 }
 
-func callers(skip int, pcbuf []uintptr) int {
+func callers(skip int, pcbuf *uintptr, m int) int {
 	sp := getcallersp(unsafe.Pointer(&skip))
 	pc := uintptr(getcallerpc(unsafe.Pointer(&skip)))
-	gp := getg()
 	var n int
-	systemstack(func() {
-		n = gentraceback(pc, sp, 0, gp, skip, &pcbuf[0], len(pcbuf), nil, nil, 0)
+	onM(func() {
+		n = gentraceback(pc, sp, 0, getg(), skip, pcbuf, m, nil, nil, 0)
 	})
 	return n
 }
 
-func gcallers(gp *g, skip int, pcbuf []uintptr) int {
-	return gentraceback(^uintptr(0), ^uintptr(0), 0, gp, skip, &pcbuf[0], len(pcbuf), nil, nil, 0)
+func gcallers(gp *g, skip int, pcbuf *uintptr, m int) int {
+	return gentraceback(^uintptr(0), ^uintptr(0), 0, gp, skip, pcbuf, m, nil, nil, 0)
 }
 
 func showframe(f *_func, gp *g) bool {
 	g := getg()
-	if g.m.throwing > 0 && gp != nil && (gp == g.m.curg || gp == g.m.caughtsig.ptr()) {
+	if g.m.throwing > 0 && gp != nil && (gp == g.m.curg || gp == g.m.caughtsig) {
 		return true
 	}
 	traceback := gotraceback(nil)
-	name := funcname(f)
+	name := gostringnocopy(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.
@@ -666,16 +632,12 @@ func tracebackothers(me *g) {
 
 	lock(&allglock)
 	for _, gp := range allgs {
-		if gp == me || gp == g.m.curg || readgstatus(gp) == _Gdead || isSystemGoroutine(gp) && level < 2 {
+		if gp == me || gp == g.m.curg || readgstatus(gp) == _Gdead || gp.issystem && level < 2 {
 			continue
 		}
 		print("\n")
 		goroutineheader(gp)
-		// Note: gp.m == g.m occurs when tracebackothers is
-		// called from a signal handler initiated during a
-		// systemstack call.  The original G is still in the
-		// running state, and we want to print its stack.
-		if gp.m != g.m && readgstatus(gp)&^_Gscan == _Grunning {
+		if readgstatus(gp)&^_Gscan == _Grunning {
 			print("\tgoroutine running on other thread; stack unavailable\n")
 			printcreatedby(gp)
 		} else {
@@ -695,15 +657,3 @@ func topofstack(f *_func) bool {
 		pc == rt0_goPC ||
 		externalthreadhandlerp != 0 && pc == externalthreadhandlerp
 }
-
-// isSystemGoroutine reports whether the goroutine g must be omitted in
-// stack dumps and deadlock detector.
-func isSystemGoroutine(gp *g) bool {
-	pc := gp.startpc
-	return pc == runfinqPC && !fingRunning ||
-		pc == backgroundgcPC ||
-		pc == bgsweepPC ||
-		pc == forcegchelperPC ||
-		pc == timerprocPC ||
-		pc == gcBgMarkWorkerPC
-}
diff --git a/src/runtime/type.h b/src/runtime/type.h
new file mode 100644
index 0000000..f5b4f9d
--- /dev/null
+++ b/src/runtime/type.h
@@ -0,0 +1,113 @@
+// 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 type representation.
+
+typedef struct Type Type;
+typedef struct UncommonType UncommonType;
+typedef struct InterfaceType InterfaceType;
+typedef struct Method Method;
+typedef struct IMethod IMethod;
+typedef struct SliceType SliceType;
+typedef struct FuncType FuncType;
+
+// Needs to be in sync with ../../cmd/ld/decodesym.c:/^commonsize and pkg/reflect/type.go:/type.
+struct Type
+{
+	uintptr size;
+	uint32 hash;
+	uint8 _unused;
+	uint8 align;
+	uint8 fieldAlign;
+	uint8 kind;
+	void* alg;
+	// gc stores type info required for garbage collector.
+	// If (kind&KindGCProg)==0, then gc[0] points at sparse GC bitmap
+	// (no indirection), 4 bits per word.
+	// If (kind&KindGCProg)!=0, then gc[1] points to a compiler-generated
+	// read-only GC program; and gc[0] points to BSS space for sparse GC bitmap.
+	// For huge types (>MaxGCMask), runtime unrolls the program directly into
+	// GC bitmap and gc[0] is not used. For moderately-sized types, runtime
+	// unrolls the program into gc[0] space on first use. The first byte of gc[0]
+	// (gc[0][0]) contains 'unroll' flag saying whether the program is already
+	// unrolled into gc[0] or not.
+	uintptr gc[2];
+	String *string;
+	UncommonType *x;
+	Type *ptrto;
+	byte *zero;  // ptr to the zero value for this type
+};
+
+struct Method
+{
+	String *name;
+	String *pkgPath;
+	Type	*mtyp;
+	Type *typ;
+	void (*ifn)(void);
+	void (*tfn)(void);
+};
+
+struct UncommonType
+{
+	String *name;
+	String *pkgPath;
+	Slice mhdr;
+	Method m[];
+};
+
+struct IMethod
+{
+	String *name;
+	String *pkgPath;
+	Type *type;
+};
+
+struct InterfaceType
+{
+	Type  typ;
+	Slice mhdr;
+	IMethod m[];
+};
+
+struct MapType
+{
+	Type typ;
+	Type *key;
+	Type *elem;
+	Type *bucket;		// internal type representing a hash bucket
+	Type *hmap;		// internal type representing a Hmap
+	uint8 keysize;		// size of key slot
+	bool indirectkey;	// store ptr to key instead of key itself
+	uint8 valuesize;	// size of value slot
+	bool indirectvalue;	// store ptr to value instead of value itself
+	uint16 bucketsize;	// size of bucket
+};
+
+struct ChanType
+{
+	Type typ;
+	Type *elem;
+	uintptr dir;
+};
+
+struct SliceType
+{
+	Type typ;
+	Type *elem;
+};
+
+struct FuncType
+{
+	Type typ;
+	bool dotdotdot;
+	Slice in;
+	Slice out;
+};
+
+struct PtrType
+{
+	Type typ;
+	Type *elem;
+};
diff --git a/src/runtime/typekind.h b/src/runtime/typekind.h
new file mode 100644
index 0000000..e0fe177
--- /dev/null
+++ b/src/runtime/typekind.h
@@ -0,0 +1,38 @@
+// 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.
+
+enum {
+	KindBool = 1,
+	KindInt,
+	KindInt8,
+	KindInt16,
+	KindInt32,
+	KindInt64,
+	KindUint,
+	KindUint8,
+	KindUint16,
+	KindUint32,
+	KindUint64,
+	KindUintptr,
+	KindFloat32,
+	KindFloat64,
+	KindComplex64,
+	KindComplex128,
+	KindArray,
+	KindChan,
+	KindFunc,
+	KindInterface,
+	KindMap,
+	KindPtr,
+	KindSlice,
+	KindString,
+	KindStruct,
+	KindUnsafePointer,
+
+	KindDirectIface = 1<<5,
+	KindGCProg = 1<<6,	// Type.gc points to GC program
+	KindNoPointers = 1<<7,
+	KindMask = (1<<5)-1,
+};
+
diff --git a/src/runtime/vdso_linux_amd64.c b/src/runtime/vdso_linux_amd64.c
new file mode 100644
index 0000000..681340c
--- /dev/null
+++ b/src/runtime/vdso_linux_amd64.c
@@ -0,0 +1,371 @@
+// 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 "runtime.h"
+#include "textflag.h"
+
+// Look up symbols in the Linux vDSO.
+
+// This code was originally based on the sample Linux vDSO parser at
+// https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/Documentation/vDSO/parse_vdso.c
+
+// This implements the ELF dynamic linking spec at
+// http://sco.com/developers/gabi/latest/ch5.dynamic.html
+
+// The version section is documented at
+// http://refspecs.linuxfoundation.org/LSB_3.2.0/LSB-Core-generic/LSB-Core-generic/symversion.html
+
+#define AT_RANDOM 25
+#define AT_SYSINFO_EHDR 33
+#define AT_NULL	0    /* End of vector */
+#define PT_LOAD	1    /* Loadable program segment */
+#define PT_DYNAMIC 2 /* Dynamic linking information */
+#define DT_NULL 0    /* Marks end of dynamic section */
+#define DT_HASH 4    /* Dynamic symbol hash table */
+#define DT_STRTAB 5  /* Address of string table */
+#define DT_SYMTAB 6  /* Address of symbol table */
+#define DT_VERSYM 0x6ffffff0
+#define	DT_VERDEF 0x6ffffffc
+
+#define VER_FLG_BASE 0x1 /* Version definition of file itself */
+#define SHN_UNDEF 0      /* Undefined section */
+#define SHT_DYNSYM 11    /* Dynamic linker symbol table */
+#define STT_FUNC 2       /* Symbol is a code object */
+#define STB_GLOBAL 1     /* Global symbol */
+#define STB_WEAK 2       /* Weak symbol */
+
+/* How to extract and insert information held in the st_info field.  */
+#define ELF64_ST_BIND(val) (((byte) (val)) >> 4)
+#define ELF64_ST_TYPE(val) ((val) & 0xf)
+
+#define EI_NIDENT (16)
+
+typedef uint16 Elf64_Half;
+typedef uint32 Elf64_Word;
+typedef	int32  Elf64_Sword;
+typedef uint64 Elf64_Xword;
+typedef	int64  Elf64_Sxword;
+typedef uint64 Elf64_Addr;
+typedef uint64 Elf64_Off;
+typedef uint16 Elf64_Section;
+typedef Elf64_Half Elf64_Versym;
+
+
+typedef struct Elf64_Sym
+{
+	Elf64_Word st_name;
+	byte st_info;
+	byte st_other;
+	Elf64_Section st_shndx;
+	Elf64_Addr st_value;
+	Elf64_Xword st_size;
+} Elf64_Sym;
+
+typedef struct Elf64_Verdef
+{
+	Elf64_Half vd_version; /* Version revision */
+	Elf64_Half vd_flags;   /* Version information */
+	Elf64_Half vd_ndx;     /* Version Index */
+	Elf64_Half vd_cnt;     /* Number of associated aux entries */
+	Elf64_Word vd_hash;    /* Version name hash value */
+	Elf64_Word vd_aux;     /* Offset in bytes to verdaux array */
+	Elf64_Word vd_next;    /* Offset in bytes to next verdef entry */
+} Elf64_Verdef;
+
+typedef struct Elf64_Ehdr
+{
+	byte e_ident[EI_NIDENT]; /* Magic number and other info */
+	Elf64_Half e_type;       /* Object file type */
+	Elf64_Half e_machine;    /* Architecture */
+	Elf64_Word e_version;    /* Object file version */
+	Elf64_Addr e_entry;      /* Entry point virtual address */
+	Elf64_Off e_phoff;       /* Program header table file offset */
+	Elf64_Off e_shoff;       /* Section header table file offset */
+	Elf64_Word e_flags;      /* Processor-specific flags */
+	Elf64_Half e_ehsize;     /* ELF header size in bytes */
+	Elf64_Half e_phentsize;  /* Program header table entry size */
+	Elf64_Half e_phnum;      /* Program header table entry count */
+	Elf64_Half e_shentsize;  /* Section header table entry size */
+	Elf64_Half e_shnum;      /* Section header table entry count */
+	Elf64_Half e_shstrndx;   /* Section header string table index */
+} Elf64_Ehdr;
+
+typedef struct Elf64_Phdr
+{
+	Elf64_Word p_type;    /* Segment type */
+	Elf64_Word p_flags;   /* Segment flags */
+	Elf64_Off p_offset;   /* Segment file offset */
+	Elf64_Addr p_vaddr;   /* Segment virtual address */
+	Elf64_Addr p_paddr;   /* Segment physical address */
+	Elf64_Xword p_filesz; /* Segment size in file */
+	Elf64_Xword p_memsz;  /* Segment size in memory */
+	Elf64_Xword p_align;  /* Segment alignment */
+} Elf64_Phdr;
+
+typedef struct Elf64_Shdr
+{
+	Elf64_Word sh_name;       /* Section name (string tbl index) */
+	Elf64_Word sh_type;       /* Section type */
+	Elf64_Xword sh_flags;     /* Section flags */
+	Elf64_Addr sh_addr;       /* Section virtual addr at execution */
+	Elf64_Off sh_offset;      /* Section file offset */
+	Elf64_Xword sh_size;      /* Section size in bytes */
+	Elf64_Word sh_link;       /* Link to another section */
+	Elf64_Word sh_info;       /* Additional section information */
+	Elf64_Xword sh_addralign; /* Section alignment */
+	Elf64_Xword sh_entsize;   /* Entry size if section holds table */
+} Elf64_Shdr;
+
+typedef struct Elf64_Dyn
+{
+	Elf64_Sxword d_tag; /* Dynamic entry type */
+	union
+	{
+		Elf64_Xword d_val;  /* Integer value */
+		Elf64_Addr d_ptr;   /* Address value */
+	} d_un;
+} Elf64_Dyn;
+
+typedef struct Elf64_Verdaux
+{
+	Elf64_Word vda_name; /* Version or dependency names */
+	Elf64_Word vda_next; /* Offset in bytes to next verdaux entry */
+} Elf64_Verdaux;
+
+typedef struct Elf64_auxv_t
+{
+	uint64 a_type;        /* Entry type */
+	union
+	{
+		uint64 a_val; /* Integer value */
+	} a_un;
+} Elf64_auxv_t;
+
+
+typedef struct symbol_key {
+	byte* name;
+	int32 sym_hash;
+	void** var_ptr;
+} symbol_key;
+
+typedef struct version_key {
+	byte* version;
+	int32 ver_hash;
+} version_key;
+
+struct vdso_info {
+	bool valid;
+
+	/* Load information */
+	uintptr load_addr;
+	uintptr load_offset;  /* load_addr - recorded vaddr */
+
+	/* Symbol table */
+	Elf64_Sym *symtab;
+	const byte *symstrings;
+	Elf64_Word *bucket, *chain;
+	Elf64_Word nbucket, nchain;
+
+	/* Version table */
+	Elf64_Versym *versym;
+	Elf64_Verdef *verdef;
+};
+
+#pragma dataflag NOPTR
+static version_key linux26 = { (byte*)"LINUX_2.6", 0x3ae75f6 };
+
+// initialize with vsyscall fallbacks
+#pragma dataflag NOPTR
+void* runtime·__vdso_time_sym = (void*)0xffffffffff600400ULL;
+#pragma dataflag NOPTR
+void* runtime·__vdso_gettimeofday_sym = (void*)0xffffffffff600000ULL;
+#pragma dataflag NOPTR
+void* runtime·__vdso_clock_gettime_sym = (void*)0;
+
+#pragma dataflag NOPTR
+static symbol_key sym_keys[] = {
+	{ (byte*)"__vdso_time", 0xa33c485, &runtime·__vdso_time_sym },
+	{ (byte*)"__vdso_gettimeofday", 0x315ca59, &runtime·__vdso_gettimeofday_sym },
+	{ (byte*)"__vdso_clock_gettime", 0xd35ec75, &runtime·__vdso_clock_gettime_sym },
+};
+
+static void
+vdso_init_from_sysinfo_ehdr(struct vdso_info *vdso_info, Elf64_Ehdr* hdr)
+{
+	uint64 i;
+	bool found_vaddr = false;
+	Elf64_Phdr *pt;
+	Elf64_Dyn *dyn;
+	Elf64_Word *hash;
+
+	vdso_info->valid = false;
+	vdso_info->load_addr = (uintptr) hdr;
+
+	pt = (Elf64_Phdr*)(vdso_info->load_addr + hdr->e_phoff);
+	dyn = nil;
+
+	// We need two things from the segment table: the load offset
+	// and the dynamic table.
+	for(i=0; i<hdr->e_phnum; i++) {
+		if(pt[i].p_type == PT_LOAD && found_vaddr == false) {
+			found_vaddr = true;
+			vdso_info->load_offset =	(uintptr)hdr
+				+ (uintptr)pt[i].p_offset
+				- (uintptr)pt[i].p_vaddr;
+		} else if(pt[i].p_type == PT_DYNAMIC) {
+			dyn = (Elf64_Dyn*)((uintptr)hdr + pt[i].p_offset);
+		}
+	}
+
+	if(found_vaddr == false || dyn == nil)
+		return;  // Failed
+
+	// Fish out the useful bits of the dynamic table.
+	hash = nil;
+	vdso_info->symstrings = nil;
+	vdso_info->symtab = nil;
+	vdso_info->versym = nil;
+	vdso_info->verdef = nil;
+	for(i=0; dyn[i].d_tag!=DT_NULL; i++) {
+		switch(dyn[i].d_tag) {
+		case DT_STRTAB:
+			vdso_info->symstrings = (const byte *)
+				((uintptr)dyn[i].d_un.d_ptr
+				 + vdso_info->load_offset);
+			break;
+		case DT_SYMTAB:
+			vdso_info->symtab = (Elf64_Sym *)
+				((uintptr)dyn[i].d_un.d_ptr
+				 + vdso_info->load_offset);
+			break;
+		case DT_HASH:
+			hash = (Elf64_Word *)
+			  ((uintptr)dyn[i].d_un.d_ptr
+			   + vdso_info->load_offset);
+			break;
+		case DT_VERSYM:
+			vdso_info->versym = (Elf64_Versym *)
+				((uintptr)dyn[i].d_un.d_ptr
+				 + vdso_info->load_offset);
+			break;
+		case DT_VERDEF:
+			vdso_info->verdef = (Elf64_Verdef *)
+				((uintptr)dyn[i].d_un.d_ptr
+				 + vdso_info->load_offset);
+			break;
+		}
+	}
+	if(vdso_info->symstrings == nil || vdso_info->symtab == nil || hash == nil)
+		return;  // Failed
+
+	if(vdso_info->verdef == nil)
+		vdso_info->versym = 0;
+
+	// Parse the hash table header.
+	vdso_info->nbucket = hash[0];
+	vdso_info->nchain = hash[1];
+	vdso_info->bucket = &hash[2];
+	vdso_info->chain = &hash[vdso_info->nbucket + 2];
+
+	// That's all we need.
+	vdso_info->valid = true;
+}
+
+static int32
+vdso_find_version(struct vdso_info *vdso_info, version_key* ver)
+{
+	if(vdso_info->valid == false) {
+		return 0;
+	}
+	Elf64_Verdef *def = vdso_info->verdef;
+	while(true) {
+		if((def->vd_flags & VER_FLG_BASE) == 0) {
+			Elf64_Verdaux *aux = (Elf64_Verdaux*)((byte *)def + def->vd_aux);
+			if(def->vd_hash == ver->ver_hash &&
+				runtime·strcmp(ver->version, vdso_info->symstrings + aux->vda_name) == 0) {
+				return def->vd_ndx & 0x7fff;
+			}
+		}
+
+		if(def->vd_next == 0) {
+			break;
+		}
+		def = (Elf64_Verdef *)((byte *)def + def->vd_next);
+	}
+	return -1; // can not match any version
+}
+
+static void
+vdso_parse_symbols(struct vdso_info *vdso_info, int32 version)
+{
+	int32 i;
+	Elf64_Word chain;
+	Elf64_Sym *sym;
+
+	if(vdso_info->valid == false)
+		return;
+
+	for(i=0; i<nelem(sym_keys); i++) {
+		for(chain = vdso_info->bucket[sym_keys[i].sym_hash % vdso_info->nbucket];
+			chain != 0; chain = vdso_info->chain[chain]) {
+
+			sym = &vdso_info->symtab[chain];
+			if(ELF64_ST_TYPE(sym->st_info) != STT_FUNC)
+				continue;
+			if(ELF64_ST_BIND(sym->st_info) != STB_GLOBAL &&
+				 ELF64_ST_BIND(sym->st_info) != STB_WEAK)
+				continue;
+			if(sym->st_shndx == SHN_UNDEF)
+				continue;
+			if(runtime·strcmp(sym_keys[i].name, vdso_info->symstrings + sym->st_name) != 0)
+				continue;
+
+			// Check symbol version.
+			if(vdso_info->versym != nil && version != 0
+				&& vdso_info->versym[chain] & 0x7fff != version)
+				continue;
+
+			*sym_keys[i].var_ptr = (void *)(vdso_info->load_offset + sym->st_value);
+			break;
+		}
+	}
+}
+
+static void
+runtime·linux_setup_vdso(int32 argc, uint8** argv)
+{
+	struct vdso_info vdso_info;
+
+	// skip argvc
+	byte **p = argv;
+	p = &p[argc+1];
+
+	// skip envp to get to ELF auxiliary vector.
+	for(; *p!=0; p++) {}
+
+	// skip NULL separator
+	p++;
+
+	// now, p points to auxv
+	Elf64_auxv_t *elf_auxv = (Elf64_auxv_t*) p;
+
+	for(int32 i=0; elf_auxv[i].a_type!=AT_NULL; i++) {
+		if(elf_auxv[i].a_type == AT_SYSINFO_EHDR) {
+			if(elf_auxv[i].a_un.a_val == 0) {
+				// Something went wrong
+				continue;
+			}
+			vdso_init_from_sysinfo_ehdr(&vdso_info, (Elf64_Ehdr*)elf_auxv[i].a_un.a_val);
+			vdso_parse_symbols(&vdso_info, vdso_find_version(&vdso_info, &linux26));
+			continue;
+		}
+		if(elf_auxv[i].a_type == AT_RANDOM) {
+		        runtime·startup_random_data = (byte*)elf_auxv[i].a_un.a_val;
+		        runtime·startup_random_data_len = 16;
+			continue;
+		}
+	}
+}
+
+void (*runtime·sysargs)(int32, uint8**) = runtime·linux_setup_vdso;
diff --git a/src/runtime/vlop_arm.s b/src/runtime/vlop_arm.s
index ae1f582..b4b905b 100644
--- a/src/runtime/vlop_arm.s
+++ b/src/runtime/vlop_arm.s
@@ -23,11 +23,11 @@
 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 // THE SOFTWARE.
 
-#include "go_asm.h"
-#include "go_tls.h"
-#include "funcdata.h"
+#include "zasm_GOOS_GOARCH.h"
 #include "textflag.h"
 
+arg=0
+
 /* replaced use of R10 by R11 because the former can be the data segment base register */
 
 TEXT _mulv(SB), NOSPLIT, $0
@@ -100,7 +100,7 @@ TEXT _sfloat(SB), NOSPLIT, $68-0 // 4 arg + 14*4 saved regs + cpsr + return valu
 // load the signal fault address into LR, and jump
 // to the real sigpanic.
 // This simulates what sighandler does for a memory fault.
-TEXT runtime·_sfloatpanic(SB),NOSPLIT,$-4
+TEXT _sfloatpanic(SB),NOSPLIT,$-4
 	MOVW	$0, R0
 	MOVW.W	R0, -4(R13)
 	MOVW	g_sigpc(g), LR
@@ -110,76 +110,89 @@ TEXT runtime·_sfloatpanic(SB),NOSPLIT,$-4
 // Reference: 
 // Sloss, Andrew et. al; ARM System Developer's Guide: Designing and Optimizing System Software
 // Morgan Kaufmann; 1 edition (April 8, 2004), ISBN 978-1558608740
-#define Rq	R0 // input d, output q
-#define Rr	R1 // input n, output r
-#define Rs	R2 // three temporary variables
-#define RM	R3
-#define Ra	R11
-
-// Be careful: Ra == R11 will be used by the linker for synthesized instructions.
+q = 0 // input d, output q
+r = 1 // input n, output r
+s = 2 // three temporary variables
+M = 3
+a = 11
+// Be careful: R(a) == R11 will be used by the linker for synthesized instructions.
 TEXT udiv<>(SB),NOSPLIT,$-4
-	CLZ 	Rq, Rs // find normalizing shift
-	MOVW.S	Rq<<Rs, Ra
-	MOVW	$fast_udiv_tab<>-64(SB), RM
-	ADD.NE	Ra>>25, RM, Ra // index by most significant 7 bits of divisor
-	MOVBU.NE	(Ra), Ra
+	CLZ 	R(q), R(s) // find normalizing shift
+	MOVW.S	R(q)<<R(s), R(a)
+	MOVW	$fast_udiv_tab<>-64(SB), R(M)
+	ADD.NE	R(a)>>25, R(M), R(a) // index by most significant 7 bits of divisor
+	MOVBU.NE	(R(a)), R(a)
 
-	SUB.S	$7, Rs
-	RSB 	$0, Rq, RM // M = -q
-	MOVW.PL	Ra<<Rs, Rq
+	SUB.S	$7, R(s)
+	RSB 	$0, R(q), R(M) // M = -q
+	MOVW.PL	R(a)<<R(s), R(q)
 
 	// 1st Newton iteration
-	MUL.PL	RM, Rq, Ra // a = -q*d
+	MUL.PL	R(M), R(q), R(a) // a = -q*d
 	BMI 	udiv_by_large_d
-	MULAWT	Ra, Rq, Rq, Rq // q approx q-(q*q*d>>32)
-	TEQ 	RM->1, RM // check for d=0 or d=1
+	MULAWT	R(a), R(q), R(q), R(q) // q approx q-(q*q*d>>32)
+	TEQ 	R(M)->1, R(M) // check for d=0 or d=1
 
 	// 2nd Newton iteration
-	MUL.NE	RM, Rq, Ra
-	MOVW.NE	$0, Rs
-	MULAL.NE Rq, Ra, (Rq,Rs)
+	MUL.NE	R(M), R(q), R(a)
+	MOVW.NE	$0, R(s)
+	MULAL.NE R(q), R(a), (R(q),R(s))
 	BEQ 	udiv_by_0_or_1
 
 	// q now accurate enough for a remainder r, 0<=r<3*d
-	MULLU	Rq, Rr, (Rq,Rs) // q = (r * q) >> 32
-	ADD 	RM, Rr, Rr // r = n - d
-	MULA	RM, Rq, Rr, Rr // r = n - (q+1)*d
+	MULLU	R(q), R(r), (R(q),R(s)) // q = (r * q) >> 32	
+	ADD 	R(M), R(r), R(r) // r = n - d
+	MULA	R(M), R(q), R(r), R(r) // r = n - (q+1)*d
 
 	// since 0 <= n-q*d < 3*d; thus -d <= r < 2*d
-	CMN 	RM, Rr // t = r-d
-	SUB.CS	RM, Rr, Rr // if (t<-d || t>=0) r=r+d
-	ADD.CC	$1, Rq
-	ADD.PL	RM<<1, Rr
-	ADD.PL	$2, Rq
+	CMN 	R(M), R(r) // t = r-d
+	SUB.CS	R(M), R(r), R(r) // if (t<-d || t>=0) r=r+d
+	ADD.CC	$1, R(q)
+	ADD.PL	R(M)<<1, R(r)
+	ADD.PL	$2, R(q)
 	RET
 
 udiv_by_large_d:
 	// at this point we know d>=2^(31-6)=2^25
-	SUB 	$4, Ra, Ra
-	RSB 	$0, Rs, Rs
-	MOVW	Ra>>Rs, Rq
-	MULLU	Rq, Rr, (Rq,Rs)
-	MULA	RM, Rq, Rr, Rr
+	SUB 	$4, R(a), R(a)
+	RSB 	$0, R(s), R(s)
+	MOVW	R(a)>>R(s), R(q)
+	MULLU	R(q), R(r), (R(q),R(s))
+	MULA	R(M), R(q), R(r), R(r)
 
 	// q now accurate enough for a remainder r, 0<=r<4*d
-	CMN 	Rr>>1, RM // if(r/2 >= d)
-	ADD.CS	RM<<1, Rr
-	ADD.CS	$2, Rq
-	CMN 	Rr, RM
-	ADD.CS	RM, Rr
-	ADD.CS	$1, Rq
+	CMN 	R(r)>>1, R(M) // if(r/2 >= d)
+	ADD.CS	R(M)<<1, R(r)
+	ADD.CS	$2, R(q)
+	CMN 	R(r), R(M)
+	ADD.CS	R(M), R(r)
+	ADD.CS	$1, R(q)
 	RET
 
 udiv_by_0_or_1:
 	// carry set if d==1, carry clear if d==0
 	BCC udiv_by_0
-	MOVW	Rr, Rq
-	MOVW	$0, Rr
+	MOVW	R(r), R(q)
+	MOVW	$0, R(r)
 	RET
 
 udiv_by_0:
-	MOVW	$runtime·panicdivide(SB), R11
-	B	(R11)
+	// The ARM toolchain expects it can emit references to DIV and MOD
+	// instructions. The linker rewrites each pseudo-instruction into
+	// a sequence that pushes two values onto the stack and then calls
+	// _divu, _modu, _div, or _mod (below), all of which have a 16-byte
+	// frame plus the saved LR. The traceback routine knows the expanded
+	// stack frame size at the pseudo-instruction call site, but it
+	// doesn't know that the frame has a non-standard layout. In particular,
+	// it expects to find a saved LR in the bottom word of the frame.
+	// Unwind the stack back to the pseudo-instruction call site, copy the
+	// saved LR where the traceback routine will look for it, and make it
+	// appear that panicdivide was called from that PC.
+	MOVW	0(R13), LR
+	ADD	$20, R13
+	MOVW	8(R13), R1 // actual saved LR
+	MOVW	R1, 0(R13) // expected here for traceback
+	B 	runtime·panicdivide(SB)
 
 // var tab [64]byte
 // tab[0] = 255; for i := 1; i <= 63; i++ { tab[i] = (1<<14)/(64+i) }
@@ -202,115 +215,96 @@ DATA fast_udiv_tab<>+0x38(SB)/4, $0x85868788
 DATA fast_udiv_tab<>+0x3c(SB)/4, $0x81828384
 GLOBL fast_udiv_tab<>(SB), RODATA, $64
 
-// The linker will pass numerator in RTMP, and it also
-// expects the result in RTMP
-#define RTMP R11
+// The linker will pass numerator in R(TMP), and it also
+// expects the result in R(TMP)
+TMP = 11
 
-TEXT _divu(SB), NOSPLIT, $16-0
-	// It's not strictly true that there are no local pointers.
-	// It could be that the saved registers Rq, Rr, Rs, and Rm
-	// contain pointers. However, the only way this can matter
-	// is if the stack grows (which it can't, udiv is nosplit)
-	// or if a fault happens and more frames are added to
-	// the stack due to deferred functions.
-	// In the latter case, the stack can grow arbitrarily,
-	// and garbage collection can happen, and those
-	// operations care about pointers, but in that case
-	// the calling frame is dead, and so are the saved
-	// registers. So we can claim there are no pointers here.
-	NO_LOCAL_POINTERS
-	MOVW	Rq, 4(R13)
-	MOVW	Rr, 8(R13)
-	MOVW	Rs, 12(R13)
-	MOVW	RM, 16(R13)
+TEXT _divu(SB), NOSPLIT, $16
+	MOVW	R(q), 4(R13)
+	MOVW	R(r), 8(R13)
+	MOVW	R(s), 12(R13)
+	MOVW	R(M), 16(R13)
 
-	MOVW	RTMP, Rr		/* numerator */
-	MOVW	g_m(g), Rq
-	MOVW	m_divmod(Rq), Rq	/* denominator */
+	MOVW	R(TMP), R(r)		/* numerator */
+	MOVW	0(FP), R(q) 		/* denominator */
 	BL  	udiv<>(SB)
-	MOVW	Rq, RTMP
-	MOVW	4(R13), Rq
-	MOVW	8(R13), Rr
-	MOVW	12(R13), Rs
-	MOVW	16(R13), RM
+	MOVW	R(q), R(TMP)
+	MOVW	4(R13), R(q)
+	MOVW	8(R13), R(r)
+	MOVW	12(R13), R(s)
+	MOVW	16(R13), R(M)
 	RET
 
-TEXT _modu(SB), NOSPLIT, $16-0
-	NO_LOCAL_POINTERS
-	MOVW	Rq, 4(R13)
-	MOVW	Rr, 8(R13)
-	MOVW	Rs, 12(R13)
-	MOVW	RM, 16(R13)
+TEXT _modu(SB), NOSPLIT, $16
+	MOVW	R(q), 4(R13)
+	MOVW	R(r), 8(R13)
+	MOVW	R(s), 12(R13)
+	MOVW	R(M), 16(R13)
 
-	MOVW	RTMP, Rr		/* numerator */
-	MOVW	g_m(g), Rq
-	MOVW	m_divmod(Rq), Rq	/* denominator */
+	MOVW	R(TMP), R(r)		/* numerator */
+	MOVW	0(FP), R(q) 		/* denominator */
 	BL  	udiv<>(SB)
-	MOVW	Rr, RTMP
-	MOVW	4(R13), Rq
-	MOVW	8(R13), Rr
-	MOVW	12(R13), Rs
-	MOVW	16(R13), RM
+	MOVW	R(r), R(TMP)
+	MOVW	4(R13), R(q)
+	MOVW	8(R13), R(r)
+	MOVW	12(R13), R(s)
+	MOVW	16(R13), R(M)
 	RET
 
-TEXT _div(SB),NOSPLIT,$16-0
-	NO_LOCAL_POINTERS
-	MOVW	Rq, 4(R13)
-	MOVW	Rr, 8(R13)
-	MOVW	Rs, 12(R13)
-	MOVW	RM, 16(R13)
-	MOVW	RTMP, Rr		/* numerator */
-	MOVW	g_m(g), Rq
-	MOVW	m_divmod(Rq), Rq	/* denominator */
-	CMP 	$0, Rr
+TEXT _div(SB),NOSPLIT,$16
+	MOVW	R(q), 4(R13)
+	MOVW	R(r), 8(R13)
+	MOVW	R(s), 12(R13)
+	MOVW	R(M), 16(R13)
+	MOVW	R(TMP), R(r)		/* numerator */
+	MOVW	0(FP), R(q) 		/* denominator */
+	CMP 	$0, R(r)
 	BGE 	d1
-	RSB 	$0, Rr, Rr
-	CMP 	$0, Rq
+	RSB 	$0, R(r), R(r)
+	CMP 	$0, R(q)
 	BGE 	d2
-	RSB 	$0, Rq, Rq
+	RSB 	$0, R(q), R(q)
 d0:
 	BL  	udiv<>(SB)  		/* none/both neg */
-	MOVW	Rq, RTMP
+	MOVW	R(q), R(TMP)
 	B		out1
 d1:
-	CMP 	$0, Rq
+	CMP 	$0, R(q)
 	BGE 	d0
-	RSB 	$0, Rq, Rq
+	RSB 	$0, R(q), R(q)
 d2:
 	BL  	udiv<>(SB)  		/* one neg */
-	RSB		$0, Rq, RTMP
+	RSB		$0, R(q), R(TMP)
 out1:
-	MOVW	4(R13), Rq
-	MOVW	8(R13), Rr
-	MOVW	12(R13), Rs
-	MOVW	16(R13), RM
+	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-0
-	NO_LOCAL_POINTERS
-	MOVW	Rq, 4(R13)
-	MOVW	Rr, 8(R13)
-	MOVW	Rs, 12(R13)
-	MOVW	RM, 16(R13)
-	MOVW	RTMP, Rr		/* numerator */
-	MOVW	g_m(g), Rq
-	MOVW	m_divmod(Rq), Rq	/* denominator */
-	CMP 	$0, Rq
-	RSB.LT	$0, Rq, Rq
-	CMP 	$0, Rr
+TEXT _mod(SB),NOSPLIT,$16
+	MOVW	R(q), 4(R13)
+	MOVW	R(r), 8(R13)
+	MOVW	R(s), 12(R13)
+	MOVW	R(M), 16(R13)
+	MOVW	R(TMP), R(r)		/* numerator */
+	MOVW	0(FP), R(q) 		/* denominator */
+	CMP 	$0, R(q)
+	RSB.LT	$0, R(q), R(q)
+	CMP 	$0, R(r)
 	BGE 	m1
-	RSB 	$0, Rr, Rr
+	RSB 	$0, R(r), R(r)
 	BL  	udiv<>(SB)  		/* neg numerator */
-	RSB 	$0, Rr, RTMP
+	RSB 	$0, R(r), R(TMP)
 	B   	out
 m1:
 	BL  	udiv<>(SB)  		/* pos numerator */
-	MOVW	Rr, RTMP
+	MOVW	R(r), R(TMP)
 out:
-	MOVW	4(R13), Rq
-	MOVW	8(R13), Rr
-	MOVW	12(R13), Rs
-	MOVW	16(R13), RM
+	MOVW	4(R13), R(q)
+	MOVW	8(R13), R(r)
+	MOVW	12(R13), R(s)
+	MOVW	16(R13), R(M)
 	RET
 
 // _mul64by32 and _div64by32 not implemented on arm
diff --git a/src/runtime/vlop_arm_test.go b/src/runtime/vlop_arm_test.go
index 1a21119..cd28419 100644
--- a/src/runtime/vlop_arm_test.go
+++ b/src/runtime/vlop_arm_test.go
@@ -4,10 +4,7 @@
 
 package runtime_test
 
-import (
-	"runtime"
-	"testing"
-)
+import "testing"
 
 // arm soft division benchmarks adapted from
 // http://ridiculousfish.com/files/division_benchmarks.tar.gz
@@ -71,14 +68,3 @@ func BenchmarkUint32Mod13307(b *testing.B)     { bmUint32Mod(13307, b) }
 func BenchmarkUint32Mod52513(b *testing.B)     { bmUint32Mod(52513, b) }
 func BenchmarkUint32Mod60978747(b *testing.B)  { bmUint32Mod(60978747, b) }
 func BenchmarkUint32Mod106956295(b *testing.B) { bmUint32Mod(106956295, b) }
-
-func TestUsplit(t *testing.T) {
-	var den uint32 = 1000000
-	for _, x := range []uint32{0, 1, 999999, 1000000, 1010101, 0xFFFFFFFF} {
-		q1, r1 := runtime.Usplit(x)
-		q2, r2 := x/den, x%den
-		if q1 != q2 || r1 != r2 {
-			t.Errorf("%d/1e6, %d%%1e6 = %d, %d, want %d, %d", x, x, q1, r1, q2, r2)
-		}
-	}
-}
diff --git a/src/runtime/vlrt.c b/src/runtime/vlrt.c
new file mode 100644
index 0000000..cb0d147
--- /dev/null
+++ b/src/runtime/vlrt.c
@@ -0,0 +1,914 @@
+// Inferno's libkern/vlrt-386.c
+// http://code.google.com/p/inferno-os/source/browse/libkern/vlrt-386.c
+//
+//         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.
+
+// +build arm 386
+
+#include "textflag.h"
+
+/*
+ * C runtime for 64-bit divide, others.
+ *
+ * TODO(rsc): The simple functions are dregs--8c knows how
+ * to generate the code directly now.  Find and remove.
+ */
+
+void	runtime·panicdivide(void);
+
+typedef	unsigned long	ulong;
+typedef	unsigned int	uint;
+typedef	unsigned short	ushort;
+typedef	unsigned char	uchar;
+typedef	signed char	schar;
+
+#define	SIGN(n)	(1UL<<(n-1))
+
+typedef	struct	Vlong	Vlong;
+struct	Vlong
+{
+	ulong	lo;
+	ulong	hi;
+};
+
+typedef	union	Vlong64	Vlong64;
+union	Vlong64
+{
+	long long	v;
+	Vlong	v2;
+};
+
+void	runtime·abort(void);
+
+#pragma textflag NOSPLIT
+Vlong
+_addv(Vlong a, Vlong b)
+{
+	Vlong r;
+
+	r.lo = a.lo + b.lo;
+	r.hi = a.hi + b.hi;
+	if(r.lo < a.lo)
+		r.hi++;
+	return r;
+}
+
+#pragma textflag NOSPLIT
+Vlong
+_subv(Vlong a, Vlong b)
+{
+	Vlong r;
+
+	r.lo = a.lo - b.lo;
+	r.hi = a.hi - b.hi;
+	if(r.lo > a.lo)
+		r.hi--;
+	return r;
+}
+
+Vlong
+_d2v(double d)
+{
+	union { double d; Vlong vl; } x;
+	ulong xhi, xlo, ylo, yhi;
+	int sh;
+	Vlong y;
+
+	x.d = d;
+
+	xhi = (x.vl.hi & 0xfffff) | 0x100000;
+	xlo = x.vl.lo;
+	sh = 1075 - ((x.vl.hi >> 20) & 0x7ff);
+
+	ylo = 0;
+	yhi = 0;
+	if(sh >= 0) {
+		/* v = (hi||lo) >> sh */
+		if(sh < 32) {
+			if(sh == 0) {
+				ylo = xlo;
+				yhi = xhi;
+			} else {
+				ylo = (xlo >> sh) | (xhi << (32-sh));
+				yhi = xhi >> sh;
+			}
+		} else {
+			if(sh == 32) {
+				ylo = xhi;
+			} else
+			if(sh < 64) {
+				ylo = xhi >> (sh-32);
+			}
+		}
+	} else {
+		/* v = (hi||lo) << -sh */
+		sh = -sh;
+		if(sh <= 10) { /* NOTE: sh <= 11 on ARM??? */
+			ylo = xlo << sh;
+			yhi = (xhi << sh) | (xlo >> (32-sh));
+		} else {
+			/* overflow */
+			yhi = d;	/* causes something awful */
+		}
+	}
+	if(x.vl.hi & SIGN(32)) {
+		if(ylo != 0) {
+			ylo = -ylo;
+			yhi = ~yhi;
+		} else
+			yhi = -yhi;
+	}
+
+	y.hi = yhi;
+	y.lo = ylo;
+	return y;
+}
+
+Vlong
+_f2v(float f)
+{
+	return _d2v(f);
+}
+
+double
+_ul2d(ulong u)
+{
+	// compensate for bug in c
+	if(u & SIGN(32)) {
+		u ^= SIGN(32);
+		return 2147483648. + u;
+	}
+	return u;
+}
+
+double
+_v2d(Vlong x)
+{
+	if(x.hi & SIGN(32)) {
+		if(x.lo) {
+			x.lo = -x.lo;
+			x.hi = ~x.hi;
+		} else
+			x.hi = -x.hi;
+		return -(_ul2d(x.hi)*4294967296. + _ul2d(x.lo));
+	}
+	return (long)x.hi*4294967296. + x.lo;
+}
+
+float
+_v2f(Vlong x)
+{
+	return _v2d(x);
+}
+
+ulong	runtime·_div64by32(Vlong, ulong, ulong*);
+int	runtime·_mul64by32(Vlong*, Vlong, ulong);
+
+static void
+slowdodiv(Vlong num, Vlong den, Vlong *q, Vlong *r)
+{
+	ulong numlo, numhi, denhi, denlo, quohi, quolo, t;
+	int i;
+
+	numhi = num.hi;
+	numlo = num.lo;
+	denhi = den.hi;
+	denlo = den.lo;
+
+	/*
+	 * get a divide by zero
+	 */
+	if(denlo==0 && denhi==0) {
+		runtime·panicdivide();
+	}
+
+	/*
+	 * set up the divisor and find the number of iterations needed
+	 */
+	if(numhi >= SIGN(32)) {
+		quohi = SIGN(32);
+		quolo = 0;
+	} else {
+		quohi = numhi;
+		quolo = numlo;
+	}
+	i = 0;
+	while(denhi < quohi || (denhi == quohi && denlo < quolo)) {
+		denhi = (denhi<<1) | (denlo>>31);
+		denlo <<= 1;
+		i++;
+	}
+
+	quohi = 0;
+	quolo = 0;
+	for(; i >= 0; i--) {
+		quohi = (quohi<<1) | (quolo>>31);
+		quolo <<= 1;
+		if(numhi > denhi || (numhi == denhi && numlo >= denlo)) {
+			t = numlo;
+			numlo -= denlo;
+			if(numlo > t)
+				numhi--;
+			numhi -= denhi;
+			quolo |= 1;
+		}
+		denlo = (denlo>>1) | (denhi<<31);
+		denhi >>= 1;
+	}
+
+	if(q) {
+		q->lo = quolo;
+		q->hi = quohi;
+	}
+	if(r) {
+		r->lo = numlo;
+		r->hi = numhi;
+	}
+}
+
+#ifdef GOARCH_arm
+static void
+dodiv(Vlong num, Vlong den, Vlong *qp, Vlong *rp)
+{
+	slowdodiv(num, den, qp, rp);
+}
+#endif
+
+#ifdef GOARCH_386
+static void
+dodiv(Vlong num, Vlong den, Vlong *qp, Vlong *rp)
+{
+	ulong n;
+	Vlong x, q, r;
+	
+	if(den.hi > num.hi || (den.hi == num.hi && den.lo > num.lo)){
+		if(qp) {
+			qp->hi = 0;
+			qp->lo = 0;
+		}
+		if(rp) {
+			rp->hi = num.hi;
+			rp->lo = num.lo;
+		}
+		return;
+	}
+
+	if(den.hi != 0){
+		q.hi = 0;
+		n = num.hi/den.hi;
+		if(runtime·_mul64by32(&x, den, n) || x.hi > num.hi || (x.hi == num.hi && x.lo > num.lo))
+			slowdodiv(num, den, &q, &r);
+		else {
+			q.lo = n;
+			*(long long*)&r = *(long long*)&num - *(long long*)&x;
+		}
+	} 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 {
+			q.hi = 0;
+		}
+		q.lo = runtime·_div64by32(num, den.lo, &r.lo);
+		r.hi = 0;
+	}
+	if(qp) {
+		qp->lo = q.lo;
+		qp->hi = q.hi;
+	}
+	if(rp) {
+		rp->lo = r.lo;
+		rp->hi = r.hi;
+	}
+}
+#endif
+
+Vlong
+_divvu(Vlong n, Vlong d)
+{
+	Vlong q;
+
+	if(n.hi == 0 && d.hi == 0) {
+		if(d.lo == 0)
+			runtime·panicdivide();
+		q.hi = 0;
+		q.lo = n.lo / d.lo;
+		return q;
+	}
+	dodiv(n, d, &q, 0);
+	return q;
+}
+
+Vlong
+_modvu(Vlong n, Vlong d)
+{
+	Vlong r;
+
+	if(n.hi == 0 && d.hi == 0) {
+		if(d.lo == 0)
+			runtime·panicdivide();
+		r.hi = 0;
+		r.lo = n.lo % d.lo;
+		return r;
+	}
+	dodiv(n, d, 0, &r);
+	return r;
+}
+
+static void
+vneg(Vlong *v)
+{
+
+	if(v->lo == 0) {
+		v->hi = -v->hi;
+		return;
+	}
+	v->lo = -v->lo;
+	v->hi = ~v->hi;
+}
+
+Vlong
+_divv(Vlong n, Vlong d)
+{
+	long nneg, dneg;
+	Vlong q;
+
+	if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
+		if((long)n.lo == -0x80000000 && (long)d.lo == -1) {
+			// special case: 32-bit -0x80000000 / -1 causes divide error,
+			// but it's okay in this 64-bit context.
+			q.lo = 0x80000000;
+			q.hi = 0;
+			return q;
+		}
+		if(d.lo == 0)
+			runtime·panicdivide();
+		q.lo = (long)n.lo / (long)d.lo;
+		q.hi = ((long)q.lo) >> 31;
+		return q;
+	}
+	nneg = n.hi >> 31;
+	if(nneg)
+		vneg(&n);
+	dneg = d.hi >> 31;
+	if(dneg)
+		vneg(&d);
+	dodiv(n, d, &q, 0);
+	if(nneg != dneg)
+		vneg(&q);
+	return q;
+}
+
+Vlong
+_modv(Vlong n, Vlong d)
+{
+	long nneg, dneg;
+	Vlong r;
+
+	if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
+		if((long)n.lo == -0x80000000 && (long)d.lo == -1) {
+			// special case: 32-bit -0x80000000 % -1 causes divide error,
+			// but it's okay in this 64-bit context.
+			r.lo = 0;
+			r.hi = 0;
+			return r;
+		}
+		if(d.lo == 0)
+			runtime·panicdivide();
+		r.lo = (long)n.lo % (long)d.lo;
+		r.hi = ((long)r.lo) >> 31;
+		return r;
+	}
+	nneg = n.hi >> 31;
+	if(nneg)
+		vneg(&n);
+	dneg = d.hi >> 31;
+	if(dneg)
+		vneg(&d);
+	dodiv(n, d, 0, &r);
+	if(nneg)
+		vneg(&r);
+	return r;
+}
+
+#pragma textflag NOSPLIT
+Vlong
+_rshav(Vlong a, int b)
+{
+	long t;
+	Vlong r;
+
+	t = a.hi;
+	if(b >= 32) {
+		r.hi = t>>31;
+		if(b >= 64) {
+			/* this is illegal re C standard */
+			r.lo = t>>31;
+			return r;
+		}
+		r.lo = t >> (b-32);
+		return r;
+	}
+	if(b <= 0) {
+		r.hi = t;
+		r.lo = a.lo;
+		return r;
+	}
+	r.hi = t >> b;
+	r.lo = (t << (32-b)) | (a.lo >> b);
+	return r;
+}
+
+#pragma textflag NOSPLIT
+Vlong
+_rshlv(Vlong a, int b)
+{
+	ulong t;
+	Vlong r;
+
+	t = a.hi;
+	if(b >= 32) {
+		r.hi = 0;
+		if(b >= 64) {
+			/* this is illegal re C standard */
+			r.lo = 0;
+			return r;
+		}
+		r.lo = t >> (b-32);
+		return r;
+	}
+	if(b <= 0) {
+		r.hi = t;
+		r.lo = a.lo;
+		return r;
+	}
+	r.hi = t >> b;
+	r.lo = (t << (32-b)) | (a.lo >> b);
+	return r;
+}
+
+#pragma textflag NOSPLIT
+Vlong
+_lshv(Vlong a, int b)
+{
+	ulong t;
+
+	t = a.lo;
+	if(b >= 32) {
+		if(b >= 64) {
+			/* this is illegal re C standard */
+			return (Vlong){0, 0};
+		}
+		return (Vlong){0, t<<(b-32)};
+	}
+	if(b <= 0) {
+		return (Vlong){t, a.hi};
+	}
+	return (Vlong){t<<b, (t >> (32-b)) | (a.hi << b)};
+}
+
+#pragma textflag NOSPLIT
+Vlong
+_andv(Vlong a, Vlong b)
+{
+	Vlong r;
+
+	r.hi = a.hi & b.hi;
+	r.lo = a.lo & b.lo;
+	return r;
+}
+
+#pragma textflag NOSPLIT
+Vlong
+_orv(Vlong a, Vlong b)
+{
+	Vlong r;
+
+	r.hi = a.hi | b.hi;
+	r.lo = a.lo | b.lo;
+	return r;
+}
+
+#pragma textflag NOSPLIT
+Vlong
+_xorv(Vlong a, Vlong b)
+{
+	Vlong r;
+
+	r.hi = a.hi ^ b.hi;
+	r.lo = a.lo ^ b.lo;
+	return r;
+}
+
+Vlong
+_vpp(Vlong *r)
+{
+	Vlong l;
+
+	l = *r;
+	r->lo++;
+	if(r->lo == 0)
+		r->hi++;
+	return l;
+}
+
+#pragma textflag NOSPLIT
+Vlong
+_vmm(Vlong *r)
+{
+	Vlong l;
+
+	l = *r;
+	if(r->lo == 0)
+		r->hi--;
+	r->lo--;
+	return l;
+}
+
+#pragma textflag NOSPLIT
+Vlong
+_ppv(Vlong *r)
+{
+
+	r->lo++;
+	if(r->lo == 0)
+		r->hi++;
+	return *r;
+}
+
+#pragma textflag NOSPLIT
+Vlong
+_mmv(Vlong *r)
+{
+
+	if(r->lo == 0)
+		r->hi--;
+	r->lo--;
+	return *r;
+}
+
+#pragma textflag NOSPLIT
+Vlong
+_vasop(void *lv, Vlong fn(Vlong, Vlong), int type, Vlong rv)
+{
+	Vlong t, u;
+
+	u.lo = 0;
+	u.hi = 0;
+	switch(type) {
+	default:
+		runtime·abort();
+		break;
+
+	case 1:	/* schar */
+		t.lo = *(schar*)lv;
+		t.hi = t.lo >> 31;
+		u = fn(t, rv);
+		*(schar*)lv = u.lo;
+		break;
+
+	case 2:	/* uchar */
+		t.lo = *(uchar*)lv;
+		t.hi = 0;
+		u = fn(t, rv);
+		*(uchar*)lv = u.lo;
+		break;
+
+	case 3:	/* short */
+		t.lo = *(short*)lv;
+		t.hi = t.lo >> 31;
+		u = fn(t, rv);
+		*(short*)lv = u.lo;
+		break;
+
+	case 4:	/* ushort */
+		t.lo = *(ushort*)lv;
+		t.hi = 0;
+		u = fn(t, rv);
+		*(ushort*)lv = u.lo;
+		break;
+
+	case 9:	/* int */
+		t.lo = *(int*)lv;
+		t.hi = t.lo >> 31;
+		u = fn(t, rv);
+		*(int*)lv = u.lo;
+		break;
+
+	case 10:	/* uint */
+		t.lo = *(uint*)lv;
+		t.hi = 0;
+		u = fn(t, rv);
+		*(uint*)lv = u.lo;
+		break;
+
+	case 5:	/* long */
+		t.lo = *(long*)lv;
+		t.hi = t.lo >> 31;
+		u = fn(t, rv);
+		*(long*)lv = u.lo;
+		break;
+
+	case 6:	/* ulong */
+		t.lo = *(ulong*)lv;
+		t.hi = 0;
+		u = fn(t, rv);
+		*(ulong*)lv = u.lo;
+		break;
+
+	case 7:	/* vlong */
+	case 8:	/* uvlong */
+		if((void*)fn == _lshv || (void*)fn == _rshav || (void*)fn == _rshlv)
+			u = ((Vlong(*)(Vlong,int))fn)(*(Vlong*)lv, *(int*)&rv);
+		else
+			u = fn(*(Vlong*)lv, rv);
+		*(Vlong*)lv = u;
+		break;
+	}
+	return u;
+}
+
+#pragma textflag NOSPLIT
+Vlong
+_p2v(void *p)
+{
+	long t;
+	Vlong ret;
+
+	t = (ulong)p;
+	ret.lo = t;
+	ret.hi = 0;
+	return ret;
+}
+
+#pragma textflag NOSPLIT
+Vlong
+_sl2v(long sl)
+{
+	long t;
+	Vlong ret;
+
+	t = sl;
+	ret.lo = t;
+	ret.hi = t >> 31;
+	return ret;
+}
+
+#pragma textflag NOSPLIT
+Vlong
+_ul2v(ulong ul)
+{
+	long t;
+	Vlong ret;
+
+	t = ul;
+	ret.lo = t;
+	ret.hi = 0;
+	return ret;
+}
+
+#pragma textflag NOSPLIT
+Vlong
+_si2v(int si)
+{
+	return (Vlong){si, si>>31};
+}
+
+#pragma textflag NOSPLIT
+Vlong
+_ui2v(uint ui)
+{
+	long t;
+	Vlong ret;
+
+	t = ui;
+	ret.lo = t;
+	ret.hi = 0;
+	return ret;
+}
+
+#pragma textflag NOSPLIT
+Vlong
+_sh2v(long sh)
+{
+	long t;
+	Vlong ret;
+
+	t = (sh << 16) >> 16;
+	ret.lo = t;
+	ret.hi = t >> 31;
+	return ret;
+}
+
+#pragma textflag NOSPLIT
+Vlong
+_uh2v(ulong ul)
+{
+	long t;
+	Vlong ret;
+
+	t = ul & 0xffff;
+	ret.lo = t;
+	ret.hi = 0;
+	return ret;
+}
+
+#pragma textflag NOSPLIT
+Vlong
+_sc2v(long uc)
+{
+	long t;
+	Vlong ret;
+
+	t = (uc << 24) >> 24;
+	ret.lo = t;
+	ret.hi = t >> 31;
+	return ret;
+}
+
+#pragma textflag NOSPLIT
+Vlong
+_uc2v(ulong ul)
+{
+	long t;
+	Vlong ret;
+
+	t = ul & 0xff;
+	ret.lo = t;
+	ret.hi = 0;
+	return ret;
+}
+
+#pragma textflag NOSPLIT
+long
+_v2sc(Vlong rv)
+{
+	long t;
+
+	t = rv.lo & 0xff;
+	return (t << 24) >> 24;
+}
+
+#pragma textflag NOSPLIT
+long
+_v2uc(Vlong rv)
+{
+
+	return rv.lo & 0xff;
+}
+
+#pragma textflag NOSPLIT
+long
+_v2sh(Vlong rv)
+{
+	long t;
+
+	t = rv.lo & 0xffff;
+	return (t << 16) >> 16;
+}
+
+#pragma textflag NOSPLIT
+long
+_v2uh(Vlong rv)
+{
+
+	return rv.lo & 0xffff;
+}
+
+#pragma textflag NOSPLIT
+long
+_v2sl(Vlong rv)
+{
+
+	return rv.lo;
+}
+
+#pragma textflag NOSPLIT
+long
+_v2ul(Vlong rv)
+{
+
+	return rv.lo;
+}
+
+#pragma textflag NOSPLIT
+long
+_v2si(Vlong rv)
+{
+	return rv.lo;
+}
+
+#pragma textflag NOSPLIT
+long
+_v2ui(Vlong rv)
+{
+
+	return rv.lo;
+}
+
+#pragma textflag NOSPLIT
+int
+_testv(Vlong rv)
+{
+	return rv.lo || rv.hi;
+}
+
+#pragma textflag NOSPLIT
+int
+_eqv(Vlong lv, Vlong rv)
+{
+	return lv.lo == rv.lo && lv.hi == rv.hi;
+}
+
+#pragma textflag NOSPLIT
+int
+_nev(Vlong lv, Vlong rv)
+{
+	return lv.lo != rv.lo || lv.hi != rv.hi;
+}
+
+#pragma textflag NOSPLIT
+int
+_ltv(Vlong lv, Vlong rv)
+{
+	return (long)lv.hi < (long)rv.hi ||
+		(lv.hi == rv.hi && lv.lo < rv.lo);
+}
+
+#pragma textflag NOSPLIT
+int
+_lev(Vlong lv, Vlong rv)
+{
+	return (long)lv.hi < (long)rv.hi ||
+		(lv.hi == rv.hi && lv.lo <= rv.lo);
+}
+
+#pragma textflag NOSPLIT
+int
+_gtv(Vlong lv, Vlong rv)
+{
+	return (long)lv.hi > (long)rv.hi ||
+		(lv.hi == rv.hi && lv.lo > rv.lo);
+}
+
+#pragma textflag NOSPLIT
+int
+_gev(Vlong lv, Vlong rv)
+{
+	return (long)lv.hi > (long)rv.hi ||
+		(lv.hi == rv.hi && lv.lo >= rv.lo);
+}
+
+#pragma textflag NOSPLIT
+int
+_lov(Vlong lv, Vlong rv)
+{
+	return lv.hi < rv.hi ||
+		(lv.hi == rv.hi && lv.lo < rv.lo);
+}
+
+#pragma textflag NOSPLIT
+int
+_lsv(Vlong lv, Vlong rv)
+{
+	return lv.hi < rv.hi ||
+		(lv.hi == rv.hi && lv.lo <= rv.lo);
+}
+
+#pragma textflag NOSPLIT
+int
+_hiv(Vlong lv, Vlong rv)
+{
+	return lv.hi > rv.hi ||
+		(lv.hi == rv.hi && lv.lo > rv.lo);
+}
+
+#pragma textflag NOSPLIT
+int
+_hsv(Vlong lv, Vlong rv)
+{
+	return lv.hi > rv.hi ||
+		(lv.hi == rv.hi && lv.lo >= rv.lo);
+}
diff --git a/src/sort/sort.go b/src/sort/sort.go
index c7c3042..e980c29 100644
--- a/src/sort/sort.go
+++ b/src/sort/sort.go
@@ -75,19 +75,20 @@ func heapSort(data Interface, a, b int) {
 // Quicksort, following Bentley and McIlroy,
 // ``Engineering a Sort Function,'' SP&E November 1993.
 
-// medianOfThree moves the median of the three values data[m0], data[m1], data[m2] into data[m1].
-func medianOfThree(data Interface, m1, m0, m2 int) {
-	// sort 3 elements
+// medianOfThree moves the median of the three values data[a], data[b], data[c] into data[a].
+func medianOfThree(data Interface, a, b, c int) {
+	m0 := b
+	m1 := a
+	m2 := c
+	// bubble sort on 3 elements
 	if data.Less(m1, m0) {
 		data.Swap(m1, m0)
 	}
-	// data[m0] <= data[m1]
 	if data.Less(m2, m1) {
 		data.Swap(m2, m1)
-		// data[m0] <= data[m2] && data[m1] < data[m2]
-		if data.Less(m1, m0) {
-			data.Swap(m1, m0)
-		}
+	}
+	if data.Less(m1, m0) {
+		data.Swap(m1, m0)
 	}
 	// now data[m0] <= data[m1] <= data[m2]
 }
@@ -296,11 +297,11 @@ func StringsAreSorted(a []string) bool { return IsSorted(StringSlice(a)) }
 //    and Jukka Teuhola; Nordic Journal of Computing 3,1 (1996), 27-40:
 //    The given algorithms are in-place, number of Swap and Assignments
 //    grow as n log n but the algorithm is not stable.
-//  - "Fast Stable In-Place Sorting with O(n) Data Moves" J.I. Munro and
+//  - "Fast Stable In-Plcae Sorting with O(n) Data Moves" J.I. Munro and
 //    V. Raman in Algorithmica (1996) 16, 115-160:
 //    This algorithm either needs additional 2n bits or works only if there
 //    are enough different elements available to encode some permutations
-//    which have to be undone later (so not stable on any input).
+//    which have to be undone later (so not stable an any input).
 //  - All the optimal in-place sorting/merging algorithms I found are either
 //    unstable or rely on enough different elements in each step to encode the
 //    performed block rearrangements. See also "In-Place Merging Algorithms",
@@ -315,7 +316,7 @@ func StringsAreSorted(a []string) bool { return IsSorted(StringSlice(a)) }
 // data.Less and O(n*log(n)*log(n)) calls to data.Swap.
 func Stable(data Interface) {
 	n := data.Len()
-	blockSize := 20 // must be > 0
+	blockSize := 20
 	a, b := 0, blockSize
 	for b <= n {
 		insertionSort(data, a, b)
@@ -331,9 +332,7 @@ func Stable(data Interface) {
 			a = b
 			b += 2 * blockSize
 		}
-		if m := a + blockSize; m < n {
-			symMerge(data, a, m, n)
-		}
+		symMerge(data, a, a+blockSize, n)
 		blockSize *= 2
 	}
 }
@@ -353,111 +352,72 @@ func Stable(data Interface) {
 // 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.
-//
-// symMerge assumes non-degenerate arguments: a < m && m < b.
-// Having the caller check this condition eliminates many leaf recursion calls,
-// which improves performance.
 func symMerge(data Interface, a, m, b int) {
-	// Avoid unnecessary recursions of symMerge
-	// by direct insertion of data[a] into data[m:b]
-	// if data[a:m] only contains one element.
-	if m-a == 1 {
-		// Use binary search to find the lowest index i
-		// such that data[i] >= data[a] for m <= i < b.
-		// Exit the search loop with i == b in case no such index exists.
-		i := m
-		j := b
-		for i < j {
-			h := i + (j-i)/2
-			if data.Less(h, a) {
-				i = h + 1
-			} else {
-				j = h
-			}
-		}
-		// Swap values until data[a] reaches the position before i.
-		for k := a; k < i-1; k++ {
-			data.Swap(k, k+1)
-		}
-		return
-	}
-
-	// Avoid unnecessary recursions of symMerge
-	// by direct insertion of data[m] into data[a:m]
-	// if data[m:b] only contains one element.
-	if b-m == 1 {
-		// Use binary search to find the lowest index i
-		// such that data[i] > data[m] for a <= i < m.
-		// Exit the search loop with i == m in case no such index exists.
-		i := a
-		j := m
-		for i < j {
-			h := i + (j-i)/2
-			if !data.Less(m, h) {
-				i = h + 1
-			} else {
-				j = h
-			}
-		}
-		// Swap values until data[m] reaches the position i.
-		for k := m; k > i; k-- {
-			data.Swap(k, k-1)
-		}
+	if a >= m || m >= b {
 		return
 	}
 
 	mid := a + (b-a)/2
 	n := mid + m
-	var start, r int
+	start := 0
 	if m > mid {
 		start = n - b
-		r = mid
+		r, p := mid, n-1
+		for start < r {
+			c := start + (r-start)/2
+			if !data.Less(p-c, c) {
+				start = c + 1
+			} else {
+				r = c
+			}
+		}
 	} else {
 		start = a
-		r = m
-	}
-	p := n - 1
-
-	for start < r {
-		c := start + (r-start)/2
-		if !data.Less(p-c, c) {
-			start = c + 1
-		} else {
-			r = c
+		r, p := m, n-1
+		for start < r {
+			c := start + (r-start)/2
+			if !data.Less(p-c, c) {
+				start = c + 1
+			} else {
+				r = c
+			}
 		}
 	}
-
 	end := n - start
-	if start < m && m < end {
-		rotate(data, start, m, end)
-	}
-	if a < start && start < mid {
-		symMerge(data, a, start, mid)
-	}
-	if mid < end && end < b {
-		symMerge(data, mid, end, b)
-	}
+	rotate(data, start, m, end)
+	symMerge(data, a, start, mid)
+	symMerge(data, mid, end, b)
 }
 
 // Rotate two consecutives blocks u = data[a:m] and v = data[m:b] in data:
 // Data of the form 'x u v y' is changed to 'x v u y'.
 // Rotate performs at most b-a many calls to data.Swap.
-// Rotate assumes non-degenerate arguments: a < m && m < b.
 func rotate(data Interface, a, m, b int) {
 	i := m - a
+	if i == 0 {
+		return
+	}
 	j := b - m
+	if j == 0 {
+		return
+	}
+
+	if i == j {
+		swapRange(data, a, m, i)
+		return
+	}
 
+	p := a + i
 	for i != j {
 		if i > j {
-			swapRange(data, m-i, m, j)
+			swapRange(data, p-i, p, j)
 			i -= j
 		} else {
-			swapRange(data, m-i, m+j-i, i)
+			swapRange(data, p-i, p+j-i, i)
 			j -= i
 		}
 	}
-	// i == j
-	swapRange(data, m-i, m, i)
+	swapRange(data, p-i, p, i)
 }
 
 /*
diff --git a/src/strconv/atof.go b/src/strconv/atof.go
index 85b959f..2862064 100644
--- a/src/strconv/atof.go
+++ b/src/strconv/atof.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.
 
+// Package strconv implements conversions to and from string representations
+// of basic data types.
 package strconv
 
 // decimal to binary floating point conversion.
diff --git a/src/strconv/atoi.go b/src/strconv/atoi.go
index 965e3a2..9ecec5a 100644
--- a/src/strconv/atoi.go
+++ b/src/strconv/atoi.go
@@ -36,7 +36,13 @@ const intSize = 32 << (^uint(0) >> 63)
 // IntSize is the size in bits of an int or uint value.
 const IntSize = intSize
 
-const maxUint64 = (1<<64 - 1)
+// Return the first number n such that n*base >= 1<<64.
+func cutoff64(base int) uint64 {
+	if base < 2 {
+		return 0
+	}
+	return (1<<64-1)/uint64(base) + 1
+}
 
 // ParseUint is like ParseInt but for unsigned numbers.
 func ParseUint(s string, base int, bitSize int) (n uint64, err error) {
@@ -46,7 +52,7 @@ func ParseUint(s string, base int, bitSize int) (n uint64, err error) {
 		bitSize = int(IntSize)
 	}
 
-	i := 0
+	s0 := s
 	switch {
 	case len(s) < 1:
 		err = ErrSyntax
@@ -59,15 +65,14 @@ func ParseUint(s string, base int, bitSize int) (n uint64, err error) {
 		// Look for octal, hex prefix.
 		switch {
 		case s[0] == '0' && len(s) > 1 && (s[1] == 'x' || s[1] == 'X'):
-			if len(s) < 3 {
+			base = 16
+			s = s[2:]
+			if len(s) < 1 {
 				err = ErrSyntax
 				goto Error
 			}
-			base = 16
-			i = 2
 		case s[0] == '0':
 			base = 8
-			i = 1
 		default:
 			base = 10
 		}
@@ -77,20 +82,11 @@ func ParseUint(s string, base int, bitSize int) (n uint64, err error) {
 		goto Error
 	}
 
-	// Cutoff is the smallest number such that cutoff*base > maxUint64.
-	// Use compile-time constants for common cases.
-	switch base {
-	case 10:
-		cutoff = maxUint64/10 + 1
-	case 16:
-		cutoff = maxUint64/16 + 1
-	default:
-		cutoff = maxUint64/uint64(base) + 1
-	}
-
+	n = 0
+	cutoff = cutoff64(base)
 	maxVal = 1<<uint(bitSize) - 1
 
-	for ; i < len(s); i++ {
+	for i := 0; i < len(s); i++ {
 		var v byte
 		d := s[i]
 		switch {
@@ -105,7 +101,7 @@ func ParseUint(s string, base int, bitSize int) (n uint64, err error) {
 			err = ErrSyntax
 			goto Error
 		}
-		if v >= byte(base) {
+		if int(v) >= base {
 			n = 0
 			err = ErrSyntax
 			goto Error
@@ -113,7 +109,7 @@ func ParseUint(s string, base int, bitSize int) (n uint64, err error) {
 
 		if n >= cutoff {
 			// n*base overflows
-			n = maxUint64
+			n = 1<<64 - 1
 			err = ErrRange
 			goto Error
 		}
@@ -122,7 +118,7 @@ func ParseUint(s string, base int, bitSize int) (n uint64, err error) {
 		n1 := n + uint64(v)
 		if n1 < n || n1 > maxVal {
 			// n+v overflows
-			n = maxUint64
+			n = 1<<64 - 1
 			err = ErrRange
 			goto Error
 		}
@@ -132,7 +128,7 @@ func ParseUint(s string, base int, bitSize int) (n uint64, err error) {
 	return n, nil
 
 Error:
-	return n, &NumError{"ParseUint", s, err}
+	return n, &NumError{"ParseUint", s0, err}
 }
 
 // ParseInt interprets a string s in the given base (2 to 36) and
diff --git a/src/strconv/atoi_test.go b/src/strconv/atoi_test.go
index bd6a6a0..9407573 100644
--- a/src/strconv/atoi_test.go
+++ b/src/strconv/atoi_test.go
@@ -33,16 +33,12 @@ var atoui64tests = []atoui64Test{
 var btoui64tests = []atoui64Test{
 	{"", 0, ErrSyntax},
 	{"0", 0, nil},
-	{"0x", 0, ErrSyntax},
-	{"0X", 0, ErrSyntax},
 	{"1", 1, nil},
 	{"12345", 12345, nil},
 	{"012345", 012345, nil},
 	{"0x12345", 0x12345, nil},
 	{"0X12345", 0x12345, nil},
 	{"12345x", 0, ErrSyntax},
-	{"0xabcdefg123", 0, ErrSyntax},
-	{"123456789abc", 0, ErrSyntax},
 	{"98765432100", 98765432100, nil},
 	{"18446744073709551615", 1<<64 - 1, nil},
 	{"18446744073709551616", 1<<64 - 1, ErrRange},
@@ -81,61 +77,28 @@ var atoi64tests = []atoi64Test{
 	{"-9223372036854775809", -1 << 63, ErrRange},
 }
 
-type btoi64Test struct {
-	in   string
-	base int
-	out  int64
-	err  error
-}
-
-var btoi64tests = []btoi64Test{
-	{"", 0, 0, ErrSyntax},
-	{"0", 0, 0, nil},
-	{"-0", 0, 0, nil},
-	{"1", 0, 1, nil},
-	{"-1", 0, -1, nil},
-	{"12345", 0, 12345, nil},
-	{"-12345", 0, -12345, nil},
-	{"012345", 0, 012345, nil},
-	{"-012345", 0, -012345, nil},
-	{"0x12345", 0, 0x12345, nil},
-	{"-0X12345", 0, -0x12345, nil},
-	{"12345x", 0, 0, ErrSyntax},
-	{"-12345x", 0, 0, ErrSyntax},
-	{"98765432100", 0, 98765432100, nil},
-	{"-98765432100", 0, -98765432100, nil},
-	{"9223372036854775807", 0, 1<<63 - 1, nil},
-	{"-9223372036854775807", 0, -(1<<63 - 1), nil},
-	{"9223372036854775808", 0, 1<<63 - 1, ErrRange},
-	{"-9223372036854775808", 0, -1 << 63, nil},
-	{"9223372036854775809", 0, 1<<63 - 1, ErrRange},
-	{"-9223372036854775809", 0, -1 << 63, ErrRange},
-
-	// other bases
-	{"g", 17, 16, nil},
-	{"10", 25, 25, nil},
-	{"holycow", 35, (((((17*35+24)*35+21)*35+34)*35+12)*35+24)*35 + 32, nil},
-	{"holycow", 36, (((((17*36+24)*36+21)*36+34)*36+12)*36+24)*36 + 32, nil},
-
-	// base 2
-	{"0", 2, 0, nil},
-	{"-1", 2, -1, nil},
-	{"1010", 2, 10, nil},
-	{"1000000000000000", 2, 1 << 15, nil},
-	{"111111111111111111111111111111111111111111111111111111111111111", 2, 1<<63 - 1, nil},
-	{"1000000000000000000000000000000000000000000000000000000000000000", 2, 1<<63 - 1, ErrRange},
-	{"-1000000000000000000000000000000000000000000000000000000000000000", 2, -1 << 63, nil},
-	{"-1000000000000000000000000000000000000000000000000000000000000001", 2, -1 << 63, ErrRange},
-
-	// base 8
-	{"-10", 8, -8, nil},
-	{"57635436545", 8, 057635436545, nil},
-	{"100000000", 8, 1 << 24, nil},
-
-	// base 16
-	{"10", 16, 16, nil},
-	{"-123456789abcdef", 16, -0x123456789abcdef, nil},
-	{"7fffffffffffffff", 16, 1<<63 - 1, nil},
+var btoi64tests = []atoi64Test{
+	{"", 0, ErrSyntax},
+	{"0", 0, nil},
+	{"-0", 0, nil},
+	{"1", 1, nil},
+	{"-1", -1, nil},
+	{"12345", 12345, nil},
+	{"-12345", -12345, nil},
+	{"012345", 012345, nil},
+	{"-012345", -012345, nil},
+	{"0x12345", 0x12345, nil},
+	{"-0X12345", -0x12345, nil},
+	{"12345x", 0, ErrSyntax},
+	{"-12345x", 0, ErrSyntax},
+	{"98765432100", 98765432100, nil},
+	{"-98765432100", -98765432100, nil},
+	{"9223372036854775807", 1<<63 - 1, nil},
+	{"-9223372036854775807", -(1<<63 - 1), nil},
+	{"9223372036854775808", 1<<63 - 1, ErrRange},
+	{"-9223372036854775808", -1 << 63, nil},
+	{"9223372036854775809", 1<<63 - 1, ErrRange},
+	{"-9223372036854775809", -1 << 63, ErrRange},
 }
 
 type atoui32Test struct {
@@ -271,7 +234,7 @@ func TestParseInt64(t *testing.T) {
 func TestParseInt64Base(t *testing.T) {
 	for i := range btoi64tests {
 		test := &btoi64tests[i]
-		out, err := ParseInt(test.in, test.base, 64)
+		out, err := ParseInt(test.in, 0, 64)
 		if test.out != out || !reflect.DeepEqual(test.err, err) {
 			t.Errorf("ParseInt(%q) = %v, %v want %v, %v",
 				test.in, out, err, test.out, test.err)
diff --git a/src/strconv/decimal.go b/src/strconv/decimal.go
index 5252d6e..4260128 100644
--- a/src/strconv/decimal.go
+++ b/src/strconv/decimal.go
@@ -12,7 +12,7 @@
 package strconv
 
 type decimal struct {
-	d     [800]byte // digits, big-endian representation
+	d     [800]byte // digits
 	nd    int       // number of digits used
 	dp    int       // decimal point
 	neg   bool
@@ -102,17 +102,16 @@ func (a *decimal) Assign(v uint64) {
 }
 
 // Maximum shift that we can do in one pass without overflow.
-// A uint has 32 or 64 bits, and we have to be able to accommodate 9<<k.
-const uintSize = 32 << (^uint(0) >> 63)
-const maxShift = uintSize - 4
+// Signed int has 31 bits, and we have to be able to accommodate 9<<k.
+const maxShift = 27
 
-// Binary shift right (/ 2) by k bits.  k <= maxShift to avoid overflow.
+// Binary shift right (* 2) by k bits.  k <= maxShift to avoid overflow.
 func rightShift(a *decimal, k uint) {
 	r := 0 // read pointer
 	w := 0 // write pointer
 
 	// Pick up enough leading digits to cover first shift.
-	var n uint
+	n := 0
 	for ; n>>k == 0; r++ {
 		if r >= a.nd {
 			if n == 0 {
@@ -126,14 +125,14 @@ func rightShift(a *decimal, k uint) {
 			}
 			break
 		}
-		c := uint(a.d[r])
+		c := int(a.d[r])
 		n = n*10 + c - '0'
 	}
 	a.dp -= r - 1
 
 	// Pick up a digit, put down a digit.
 	for ; r < a.nd; r++ {
-		c := uint(a.d[r])
+		c := int(a.d[r])
 		dig := n >> k
 		n -= dig << k
 		a.d[w] = byte(dig + '0')
@@ -170,84 +169,50 @@ func rightShift(a *decimal, k uint) {
 
 type leftCheat struct {
 	delta  int    // number of new digits
-	cutoff string // minus one digit if original < a.
+	cutoff string //   minus one digit if original < a.
 }
 
 var leftcheats = []leftCheat{
 	// Leading digits of 1/2^i = 5^i.
 	// 5^23 is not an exact 64-bit floating point number,
 	// so have to use bc for the math.
-	// Go up to 60 to be large enough for 32bit and 64bit platforms.
 	/*
-		seq 60 | sed 's/^/5^/' | bc |
-		awk 'BEGIN{ print "\t{ 0, \"\" }," }
+		seq 27 | sed 's/^/5^/' | bc |
+		awk 'BEGIN{ print "\tleftCheat{ 0, \"\" }," }
 		{
 			log2 = log(2)/log(10)
-			printf("\t{ %d, \"%s\" },\t// * %d\n",
+			printf("\tleftCheat{ %d, \"%s\" },\t// * %d\n",
 				int(log2*NR+1), $0, 2**NR)
 		}'
 	*/
 	{0, ""},
-	{1, "5"},                                           // * 2
-	{1, "25"},                                          // * 4
-	{1, "125"},                                         // * 8
-	{2, "625"},                                         // * 16
-	{2, "3125"},                                        // * 32
-	{2, "15625"},                                       // * 64
-	{3, "78125"},                                       // * 128
-	{3, "390625"},                                      // * 256
-	{3, "1953125"},                                     // * 512
-	{4, "9765625"},                                     // * 1024
-	{4, "48828125"},                                    // * 2048
-	{4, "244140625"},                                   // * 4096
-	{4, "1220703125"},                                  // * 8192
-	{5, "6103515625"},                                  // * 16384
-	{5, "30517578125"},                                 // * 32768
-	{5, "152587890625"},                                // * 65536
-	{6, "762939453125"},                                // * 131072
-	{6, "3814697265625"},                               // * 262144
-	{6, "19073486328125"},                              // * 524288
-	{7, "95367431640625"},                              // * 1048576
-	{7, "476837158203125"},                             // * 2097152
-	{7, "2384185791015625"},                            // * 4194304
-	{7, "11920928955078125"},                           // * 8388608
-	{8, "59604644775390625"},                           // * 16777216
-	{8, "298023223876953125"},                          // * 33554432
-	{8, "1490116119384765625"},                         // * 67108864
-	{9, "7450580596923828125"},                         // * 134217728
-	{9, "37252902984619140625"},                        // * 268435456
-	{9, "186264514923095703125"},                       // * 536870912
-	{10, "931322574615478515625"},                      // * 1073741824
-	{10, "4656612873077392578125"},                     // * 2147483648
-	{10, "23283064365386962890625"},                    // * 4294967296
-	{10, "116415321826934814453125"},                   // * 8589934592
-	{11, "582076609134674072265625"},                   // * 17179869184
-	{11, "2910383045673370361328125"},                  // * 34359738368
-	{11, "14551915228366851806640625"},                 // * 68719476736
-	{12, "72759576141834259033203125"},                 // * 137438953472
-	{12, "363797880709171295166015625"},                // * 274877906944
-	{12, "1818989403545856475830078125"},               // * 549755813888
-	{13, "9094947017729282379150390625"},               // * 1099511627776
-	{13, "45474735088646411895751953125"},              // * 2199023255552
-	{13, "227373675443232059478759765625"},             // * 4398046511104
-	{13, "1136868377216160297393798828125"},            // * 8796093022208
-	{14, "5684341886080801486968994140625"},            // * 17592186044416
-	{14, "28421709430404007434844970703125"},           // * 35184372088832
-	{14, "142108547152020037174224853515625"},          // * 70368744177664
-	{15, "710542735760100185871124267578125"},          // * 140737488355328
-	{15, "3552713678800500929355621337890625"},         // * 281474976710656
-	{15, "17763568394002504646778106689453125"},        // * 562949953421312
-	{16, "88817841970012523233890533447265625"},        // * 1125899906842624
-	{16, "444089209850062616169452667236328125"},       // * 2251799813685248
-	{16, "2220446049250313080847263336181640625"},      // * 4503599627370496
-	{16, "11102230246251565404236316680908203125"},     // * 9007199254740992
-	{17, "55511151231257827021181583404541015625"},     // * 18014398509481984
-	{17, "277555756156289135105907917022705078125"},    // * 36028797018963968
-	{17, "1387778780781445675529539585113525390625"},   // * 72057594037927936
-	{18, "6938893903907228377647697925567626953125"},   // * 144115188075855872
-	{18, "34694469519536141888238489627838134765625"},  // * 288230376151711744
-	{18, "173472347597680709441192448139190673828125"}, // * 576460752303423488
-	{19, "867361737988403547205962240695953369140625"}, // * 1152921504606846976
+	{1, "5"},                   // * 2
+	{1, "25"},                  // * 4
+	{1, "125"},                 // * 8
+	{2, "625"},                 // * 16
+	{2, "3125"},                // * 32
+	{2, "15625"},               // * 64
+	{3, "78125"},               // * 128
+	{3, "390625"},              // * 256
+	{3, "1953125"},             // * 512
+	{4, "9765625"},             // * 1024
+	{4, "48828125"},            // * 2048
+	{4, "244140625"},           // * 4096
+	{4, "1220703125"},          // * 8192
+	{5, "6103515625"},          // * 16384
+	{5, "30517578125"},         // * 32768
+	{5, "152587890625"},        // * 65536
+	{6, "762939453125"},        // * 131072
+	{6, "3814697265625"},       // * 262144
+	{6, "19073486328125"},      // * 524288
+	{7, "95367431640625"},      // * 1048576
+	{7, "476837158203125"},     // * 2097152
+	{7, "2384185791015625"},    // * 4194304
+	{7, "11920928955078125"},   // * 8388608
+	{8, "59604644775390625"},   // * 16777216
+	{8, "298023223876953125"},  // * 33554432
+	{8, "1490116119384765625"}, // * 67108864
+	{9, "7450580596923828125"}, // * 134217728
 }
 
 // Is the leading prefix of b lexicographically less than s?
@@ -263,7 +228,7 @@ func prefixIsLessThan(b []byte, s string) bool {
 	return false
 }
 
-// Binary shift left (* 2) by k bits.  k <= maxShift to avoid overflow.
+// Binary shift left (/ 2) by k bits.  k <= maxShift to avoid overflow.
 func leftShift(a *decimal, k uint) {
 	delta := leftcheats[k].delta
 	if prefixIsLessThan(a.d[0:a.nd], leftcheats[k].cutoff) {
@@ -272,11 +237,11 @@ func leftShift(a *decimal, k uint) {
 
 	r := a.nd         // read index
 	w := a.nd + delta // write index
+	n := 0
 
 	// Pick up a digit, put down a digit.
-	var n uint
 	for r--; r >= 0; r-- {
-		n += (uint(a.d[r]) - '0') << k
+		n += (int(a.d[r]) - '0') << k
 		quo := n / 10
 		rem := n - 10*quo
 		w--
diff --git a/src/strconv/extfloat.go b/src/strconv/extfloat.go
index 019b4ee..bed8b16 100644
--- a/src/strconv/extfloat.go
+++ b/src/strconv/extfloat.go
@@ -256,7 +256,7 @@ var uint64pow10 = [...]uint64{
 }
 
 // AssignDecimal sets f to an approximate value mantissa*10^exp. It
-// reports whether the value represented by f is guaranteed to be the
+// returns true if the value represented by f is guaranteed to be the
 // best approximation of d after being rounded to a float64 or
 // float32 depending on flt.
 func (f *extFloat) AssignDecimal(mantissa uint64, exp10 int, neg bool, trunc bool, flt *floatInfo) (ok bool) {
diff --git a/src/strconv/ftoa.go b/src/strconv/ftoa.go
index 468c37f..1a9c41b 100644
--- a/src/strconv/ftoa.go
+++ b/src/strconv/ftoa.go
@@ -47,7 +47,7 @@ func FormatFloat(f float64, fmt byte, prec, bitSize int) string {
 
 // AppendFloat appends the string form of the floating-point number f,
 // as generated by FormatFloat, to dst and returns the extended buffer.
-func AppendFloat(dst []byte, f float64, fmt byte, prec, bitSize int) []byte {
+func AppendFloat(dst []byte, f float64, fmt byte, prec int, bitSize int) []byte {
 	return genericFtoa(dst, f, fmt, prec, bitSize)
 }
 
@@ -119,7 +119,7 @@ func genericFtoa(dst []byte, val float64, fmt byte, prec, bitSize int) []byte {
 		// Precision for shortest representation mode.
 		switch fmt {
 		case 'e', 'E':
-			prec = max(digs.nd-1, 0)
+			prec = digs.nd - 1
 		case 'f':
 			prec = max(digs.nd-digs.dp, 0)
 		case 'g', 'G':
@@ -223,8 +223,9 @@ func formatDigits(dst []byte, shortest bool, neg bool, digs decimalSlice, prec i
 	return append(dst, '%', fmt)
 }
 
-// roundShortest rounds d (= mant * 2^exp) to the shortest number of digits
-// that will let the original floating point value be precisely reconstructed.
+// Round d (= mant * 2^exp) to the shortest number of digits
+// that will let the original floating point value be precisely
+// reconstructed.  Size is original floating point size (64 or 32).
 func roundShortest(d *decimal, mant uint64, exp int, flt *floatInfo) {
 	// If mantissa is zero, the number is zero; stop now.
 	if mant == 0 {
@@ -347,13 +348,14 @@ func fmtE(dst []byte, neg bool, d decimalSlice, prec int, fmt byte) []byte {
 	if prec > 0 {
 		dst = append(dst, '.')
 		i := 1
-		m := min(d.nd, prec+1)
-		if i < m {
-			dst = append(dst, d.d[i:m]...)
-			i = m
+		m := d.nd + prec + 1 - max(d.nd, prec+1)
+		for i < m {
+			dst = append(dst, d.d[i])
+			i++
 		}
-		for ; i <= prec; i++ {
+		for i <= prec {
 			dst = append(dst, '0')
+			i++
 		}
 	}
 
@@ -371,16 +373,27 @@ func fmtE(dst []byte, neg bool, d decimalSlice, prec int, fmt byte) []byte {
 	}
 	dst = append(dst, ch)
 
-	// dd or ddd
-	switch {
-	case exp < 10:
-		dst = append(dst, '0', byte(exp)+'0')
-	case exp < 100:
-		dst = append(dst, byte(exp/10)+'0', byte(exp%10)+'0')
-	default:
-		dst = append(dst, byte(exp/100)+'0', byte(exp/10)%10+'0', byte(exp%10)+'0')
+	// dddd
+	var buf [3]byte
+	i := len(buf)
+	for exp >= 10 {
+		i--
+		buf[i] = byte(exp%10 + '0')
+		exp /= 10
 	}
+	// exp < 10
+	i--
+	buf[i] = byte(exp + '0')
 
+	switch i {
+	case 0:
+		dst = append(dst, buf[0], buf[1], buf[2])
+	case 1:
+		dst = append(dst, buf[1], buf[2])
+	case 2:
+		// leading zeroes
+		dst = append(dst, '0', buf[2])
+	}
 	return dst
 }
 
@@ -393,9 +406,11 @@ func fmtF(dst []byte, neg bool, d decimalSlice, prec int) []byte {
 
 	// integer, padded with zeros as needed.
 	if d.dp > 0 {
-		m := min(d.nd, d.dp)
-		dst = append(dst, d.d[:m]...)
-		for ; m < d.dp; m++ {
+		var i int
+		for i = 0; i < d.dp && i < d.nd; i++ {
+			dst = append(dst, d.d[i])
+		}
+		for ; i < d.dp; i++ {
 			dst = append(dst, '0')
 		}
 	} else {
@@ -417,34 +432,39 @@ func fmtF(dst []byte, neg bool, d decimalSlice, prec int) []byte {
 	return dst
 }
 
-// %b: -ddddddddp±ddd
+// %b: -ddddddddp+ddd
 func fmtB(dst []byte, neg bool, mant uint64, exp int, flt *floatInfo) []byte {
-	// sign
-	if neg {
-		dst = append(dst, '-')
-	}
-
-	// mantissa
-	dst, _ = formatBits(dst, mant, 10, false, true)
-
-	// p
-	dst = append(dst, 'p')
-
-	// ±exponent
+	var buf [50]byte
+	w := len(buf)
 	exp -= int(flt.mantbits)
-	if exp >= 0 {
-		dst = append(dst, '+')
+	esign := byte('+')
+	if exp < 0 {
+		esign = '-'
+		exp = -exp
 	}
-	dst, _ = formatBits(dst, uint64(exp), 10, exp < 0, true)
-
-	return dst
-}
-
-func min(a, b int) int {
-	if a < b {
-		return a
+	n := 0
+	for exp > 0 || n < 1 {
+		n++
+		w--
+		buf[w] = byte(exp%10 + '0')
+		exp /= 10
 	}
-	return b
+	w--
+	buf[w] = esign
+	w--
+	buf[w] = 'p'
+	n = 0
+	for mant > 0 || n < 1 {
+		n++
+		w--
+		buf[w] = byte(mant%10 + '0')
+		mant /= 10
+	}
+	if neg {
+		w--
+		buf[w] = '-'
+	}
+	return append(dst, buf[w:]...)
 }
 
 func max(a, b int) int {
diff --git a/src/strconv/ftoa_test.go b/src/strconv/ftoa_test.go
index 1b4dcd9..39b8615 100644
--- a/src/strconv/ftoa_test.go
+++ b/src/strconv/ftoa_test.go
@@ -227,7 +227,6 @@ func BenchmarkAppendFloatNegExp(b *testing.B)  { benchmarkAppendFloat(b, -5.11e-
 func BenchmarkAppendFloatBig(b *testing.B) {
 	benchmarkAppendFloat(b, 123456789123456789123456789, 'g', -1, 64)
 }
-func BenchmarkAppendFloatBinaryExp(b *testing.B) { benchmarkAppendFloat(b, -1, 'b', -1, 64) }
 
 func BenchmarkAppendFloat32Integer(b *testing.B)       { benchmarkAppendFloat(b, 33909, 'g', -1, 32) }
 func BenchmarkAppendFloat32ExactFraction(b *testing.B) { benchmarkAppendFloat(b, 3.375, 'g', -1, 32) }
diff --git a/src/strconv/isprint.go b/src/strconv/isprint.go
index 0cf363c..80738ed 100644
--- a/src/strconv/isprint.go
+++ b/src/strconv/isprint.go
@@ -7,7 +7,7 @@
 
 package strconv
 
-// (470+136+73)*2 + (342)*4 = 2726 bytes
+// (468+138+67)*2 + (326)*4 = 2650 bytes
 
 var isPrint16 = []uint16{
 	0x0020, 0x007e,
@@ -26,8 +26,8 @@ var isPrint16 = []uint16{
 	0x0800, 0x082d,
 	0x0830, 0x085b,
 	0x085e, 0x085e,
-	0x08a0, 0x08b4,
-	0x08e3, 0x098c,
+	0x08a0, 0x08b2,
+	0x08e4, 0x098c,
 	0x098f, 0x0990,
 	0x0993, 0x09b2,
 	0x09b6, 0x09b9,
@@ -51,7 +51,6 @@ var isPrint16 = []uint16{
 	0x0ad0, 0x0ad0,
 	0x0ae0, 0x0ae3,
 	0x0ae6, 0x0af1,
-	0x0af9, 0x0af9,
 	0x0b01, 0x0b0c,
 	0x0b0f, 0x0b10,
 	0x0b13, 0x0b39,
@@ -74,7 +73,7 @@ var isPrint16 = []uint16{
 	0x0be6, 0x0bfa,
 	0x0c00, 0x0c39,
 	0x0c3d, 0x0c4d,
-	0x0c55, 0x0c5a,
+	0x0c55, 0x0c59,
 	0x0c60, 0x0c63,
 	0x0c66, 0x0c6f,
 	0x0c78, 0x0cb9,
@@ -85,7 +84,7 @@ var isPrint16 = []uint16{
 	0x0d01, 0x0d3a,
 	0x0d3d, 0x0d4e,
 	0x0d57, 0x0d57,
-	0x0d5f, 0x0d63,
+	0x0d60, 0x0d63,
 	0x0d66, 0x0d75,
 	0x0d79, 0x0d7f,
 	0x0d82, 0x0d96,
@@ -118,8 +117,7 @@ var isPrint16 = []uint16{
 	0x1318, 0x135a,
 	0x135d, 0x137c,
 	0x1380, 0x1399,
-	0x13a0, 0x13f5,
-	0x13f8, 0x13fd,
+	0x13a0, 0x13f4,
 	0x1400, 0x169c,
 	0x16a0, 0x16f8,
 	0x1700, 0x1714,
@@ -169,9 +167,9 @@ var isPrint16 = []uint16{
 	0x2030, 0x205e,
 	0x2070, 0x2071,
 	0x2074, 0x209c,
-	0x20a0, 0x20be,
+	0x20a0, 0x20bd,
 	0x20d0, 0x20f0,
-	0x2100, 0x218b,
+	0x2100, 0x2189,
 	0x2190, 0x23fa,
 	0x2400, 0x2426,
 	0x2440, 0x244a,
@@ -179,7 +177,6 @@ var isPrint16 = []uint16{
 	0x2b76, 0x2b95,
 	0x2b98, 0x2bb9,
 	0x2bbd, 0x2bd1,
-	0x2bec, 0x2bef,
 	0x2c00, 0x2cf3,
 	0x2cf9, 0x2d27,
 	0x2d2d, 0x2d2d,
@@ -196,19 +193,19 @@ var isPrint16 = []uint16{
 	0x3131, 0x31ba,
 	0x31c0, 0x31e3,
 	0x31f0, 0x4db5,
-	0x4dc0, 0x9fd5,
+	0x4dc0, 0x9fcc,
 	0xa000, 0xa48c,
 	0xa490, 0xa4c6,
 	0xa4d0, 0xa62b,
 	0xa640, 0xa6f7,
 	0xa700, 0xa7ad,
-	0xa7b0, 0xa7b7,
+	0xa7b0, 0xa7b1,
 	0xa7f7, 0xa82b,
 	0xa830, 0xa839,
 	0xa840, 0xa877,
 	0xa880, 0xa8c4,
 	0xa8ce, 0xa8d9,
-	0xa8e0, 0xa8fd,
+	0xa8e0, 0xa8fb,
 	0xa900, 0xa953,
 	0xa95f, 0xa97c,
 	0xa980, 0xa9d9,
@@ -220,8 +217,9 @@ var isPrint16 = []uint16{
 	0xab01, 0xab06,
 	0xab09, 0xab0e,
 	0xab11, 0xab16,
-	0xab20, 0xab65,
-	0xab70, 0xabed,
+	0xab20, 0xab5f,
+	0xab64, 0xab65,
+	0xabc0, 0xabed,
 	0xabf0, 0xabf9,
 	0xac00, 0xd7a3,
 	0xd7b0, 0xd7c6,
@@ -236,7 +234,8 @@ var isPrint16 = []uint16{
 	0xfd92, 0xfdc7,
 	0xfdf0, 0xfdfd,
 	0xfe00, 0xfe19,
-	0xfe20, 0xfe6b,
+	0xfe20, 0xfe2d,
+	0xfe30, 0xfe6b,
 	0xfe70, 0xfefc,
 	0xff01, 0xffbe,
 	0xffc2, 0xffc7,
@@ -371,6 +370,8 @@ var isNotPrint16 = []uint16{
 	0x318f,
 	0x321f,
 	0x32ff,
+	0xa69e,
+	0xa78f,
 	0xa9ce,
 	0xa9ff,
 	0xab27,
@@ -417,13 +418,12 @@ var isPrint32 = []uint32{
 	0x01083c, 0x01083c,
 	0x01083f, 0x01089e,
 	0x0108a7, 0x0108af,
-	0x0108e0, 0x0108f5,
-	0x0108fb, 0x01091b,
+	0x010900, 0x01091b,
 	0x01091f, 0x010939,
 	0x01093f, 0x01093f,
 	0x010980, 0x0109b7,
-	0x0109bc, 0x0109cf,
-	0x0109d2, 0x010a06,
+	0x0109be, 0x0109bf,
+	0x010a00, 0x010a06,
 	0x010a0c, 0x010a33,
 	0x010a38, 0x010a3a,
 	0x010a3f, 0x010a47,
@@ -438,9 +438,6 @@ var isPrint32 = []uint32{
 	0x010b99, 0x010b9c,
 	0x010ba9, 0x010baf,
 	0x010c00, 0x010c48,
-	0x010c80, 0x010cb2,
-	0x010cc0, 0x010cf2,
-	0x010cfa, 0x010cff,
 	0x010e60, 0x010e7e,
 	0x011000, 0x01104d,
 	0x011052, 0x01106f,
@@ -449,19 +446,19 @@ var isPrint32 = []uint32{
 	0x0110f0, 0x0110f9,
 	0x011100, 0x011143,
 	0x011150, 0x011176,
-	0x011180, 0x0111cd,
-	0x0111d0, 0x0111f4,
+	0x011180, 0x0111c8,
+	0x0111cd, 0x0111cd,
+	0x0111d0, 0x0111da,
+	0x0111e1, 0x0111f4,
 	0x011200, 0x01123d,
-	0x011280, 0x0112a9,
 	0x0112b0, 0x0112ea,
 	0x0112f0, 0x0112f9,
-	0x011300, 0x01130c,
+	0x011301, 0x01130c,
 	0x01130f, 0x011310,
 	0x011313, 0x011339,
 	0x01133c, 0x011344,
 	0x011347, 0x011348,
 	0x01134b, 0x01134d,
-	0x011350, 0x011350,
 	0x011357, 0x011357,
 	0x01135d, 0x011363,
 	0x011366, 0x01136c,
@@ -469,22 +466,17 @@ var isPrint32 = []uint32{
 	0x011480, 0x0114c7,
 	0x0114d0, 0x0114d9,
 	0x011580, 0x0115b5,
-	0x0115b8, 0x0115dd,
+	0x0115b8, 0x0115c9,
 	0x011600, 0x011644,
 	0x011650, 0x011659,
 	0x011680, 0x0116b7,
 	0x0116c0, 0x0116c9,
-	0x011700, 0x011719,
-	0x01171d, 0x01172b,
-	0x011730, 0x01173f,
 	0x0118a0, 0x0118f2,
 	0x0118ff, 0x0118ff,
 	0x011ac0, 0x011af8,
-	0x012000, 0x012399,
+	0x012000, 0x012398,
 	0x012400, 0x012474,
-	0x012480, 0x012543,
 	0x013000, 0x01342e,
-	0x014400, 0x014646,
 	0x016800, 0x016a38,
 	0x016a40, 0x016a69,
 	0x016a6e, 0x016a6f,
@@ -505,7 +497,7 @@ var isPrint32 = []uint32{
 	0x01d000, 0x01d0f5,
 	0x01d100, 0x01d126,
 	0x01d129, 0x01d172,
-	0x01d17b, 0x01d1e8,
+	0x01d17b, 0x01d1dd,
 	0x01d200, 0x01d245,
 	0x01d300, 0x01d356,
 	0x01d360, 0x01d371,
@@ -516,8 +508,7 @@ var isPrint32 = []uint32{
 	0x01d50d, 0x01d546,
 	0x01d54a, 0x01d6a5,
 	0x01d6a8, 0x01d7cb,
-	0x01d7ce, 0x01da8b,
-	0x01da9b, 0x01daaf,
+	0x01d7ce, 0x01d7ff,
 	0x01e800, 0x01e8c4,
 	0x01e8c7, 0x01e8d6,
 	0x01ee00, 0x01ee24,
@@ -539,7 +530,13 @@ var isPrint32 = []uint32{
 	0x01f210, 0x01f23a,
 	0x01f240, 0x01f248,
 	0x01f250, 0x01f251,
-	0x01f300, 0x01f6d0,
+	0x01f300, 0x01f32c,
+	0x01f330, 0x01f37d,
+	0x01f380, 0x01f3ce,
+	0x01f3d4, 0x01f3f7,
+	0x01f400, 0x01f54a,
+	0x01f550, 0x01f642,
+	0x01f645, 0x01f6cf,
 	0x01f6e0, 0x01f6ec,
 	0x01f6f0, 0x01f6f3,
 	0x01f700, 0x01f773,
@@ -549,13 +546,9 @@ var isPrint32 = []uint32{
 	0x01f850, 0x01f859,
 	0x01f860, 0x01f887,
 	0x01f890, 0x01f8ad,
-	0x01f910, 0x01f918,
-	0x01f980, 0x01f984,
-	0x01f9c0, 0x01f9c0,
 	0x020000, 0x02a6d6,
 	0x02a700, 0x02b734,
 	0x02b740, 0x02b81d,
-	0x02b820, 0x02cea1,
 	0x02f800, 0x02fa1d,
 	0x0e0100, 0x0e01ef,
 }
@@ -569,18 +562,12 @@ var isNotPrint32 = []uint16{ // add 0x10000 to each entry
 	0x0809,
 	0x0836,
 	0x0856,
-	0x08f3,
 	0x0a04,
 	0x0a14,
 	0x0a18,
 	0x10bd,
 	0x1135,
-	0x11e0,
 	0x1212,
-	0x1287,
-	0x1289,
-	0x128e,
-	0x129e,
 	0x1304,
 	0x1329,
 	0x1331,
@@ -602,7 +589,6 @@ var isNotPrint32 = []uint16{ // add 0x10000 to each entry
 	0xd53f,
 	0xd545,
 	0xd551,
-	0xdaa0,
 	0xee04,
 	0xee20,
 	0xee23,
@@ -632,6 +618,7 @@ var isNotPrint32 = []uint16{ // add 0x10000 to each entry
 	0xf0c0,
 	0xf0d0,
 	0xf12f,
+	0xf4ff,
 	0xf57a,
 	0xf5a4,
 }
diff --git a/src/strconv/itoa.go b/src/strconv/itoa.go
index e6f6303..67f17d8 100644
--- a/src/strconv/itoa.go
+++ b/src/strconv/itoa.go
@@ -40,7 +40,9 @@ func AppendUint(dst []byte, i uint64, base int) []byte {
 }
 
 const (
-	digits = "0123456789abcdefghijklmnopqrstuvwxyz"
+	digits   = "0123456789abcdefghijklmnopqrstuvwxyz"
+	digits01 = "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"
+	digits10 = "0000000000111111111122222222223333333333444444444455555555556666666666777777777788888888889999999999"
 )
 
 var shifts = [len(digits) + 1]uint{
@@ -72,34 +74,23 @@ func formatBits(dst []byte, u uint64, base int, neg, append_ bool) (d []byte, s
 
 	// convert bits
 	if base == 10 {
-		// common case: use constants for / because
-		// the compiler can optimize it into a multiply+shift
-
-		if ^uintptr(0)>>32 == 0 {
-			for u > uint64(^uintptr(0)) {
-				q := u / 1e9
-				us := uintptr(u - q*1e9) // us % 1e9 fits into a uintptr
-				for j := 9; j > 0; j-- {
-					i--
-					qs := us / 10
-					a[i] = byte(us - qs*10 + '0')
-					us = qs
-				}
-				u = q
-			}
+		// common case: use constants for / and % because
+		// the compiler can optimize it into a multiply+shift,
+		// and unroll loop
+		for u >= 100 {
+			i -= 2
+			q := u / 100
+			j := uintptr(u - q*100)
+			a[i+1] = digits01[j]
+			a[i+0] = digits10[j]
+			u = q
 		}
-
-		// u guaranteed to fit into a uintptr
-		us := uintptr(u)
-		for us >= 10 {
+		if u >= 10 {
 			i--
-			q := us / 10
-			a[i] = byte(us - q*10 + '0')
-			us = q
+			q := u / 10
+			a[i] = digits[uintptr(u-q*10)]
+			u = q
 		}
-		// u < 10
-		i--
-		a[i] = byte(us + '0')
 
 	} else if s := shifts[base]; s > 0 {
 		// base is power of 2: use shifts and masks instead of / and %
@@ -110,24 +101,21 @@ func formatBits(dst []byte, u uint64, base int, neg, append_ bool) (d []byte, s
 			a[i] = digits[uintptr(u)&m]
 			u >>= s
 		}
-		// u < base
-		i--
-		a[i] = digits[uintptr(u)]
 
 	} else {
 		// general case
 		b := uint64(base)
 		for u >= b {
 			i--
-			q := u / b
-			a[i] = digits[uintptr(u-q*b)]
-			u = q
+			a[i] = digits[uintptr(u%b)]
+			u /= b
 		}
-		// u < base
-		i--
-		a[i] = digits[uintptr(u)]
 	}
 
+	// u < base
+	i--
+	a[i] = digits[uintptr(u)]
+
 	// add sign, if any
 	if neg {
 		i--
diff --git a/src/strconv/itoa_test.go b/src/strconv/itoa_test.go
index 48dc03e..e0213ae 100644
--- a/src/strconv/itoa_test.go
+++ b/src/strconv/itoa_test.go
@@ -51,7 +51,6 @@ var itob64tests = []itob64Test{
 	{-0x123456789abcdef, 16, "-123456789abcdef"},
 	{1<<63 - 1, 16, "7fffffffffffffff"},
 	{1<<63 - 1, 2, "111111111111111111111111111111111111111111111111111111111111111"},
-	{-1 << 63, 2, "-1000000000000000000000000000000000000000000000000000000000000000"},
 
 	{16, 17, "g"},
 	{25, 25, "10"},
diff --git a/src/strconv/quote_example_test.go b/src/strconv/quote_example_test.go
new file mode 100644
index 0000000..405a57e
--- /dev/null
+++ b/src/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/strings/reader.go b/src/strings/reader.go
index 7a872fb..82df974 100644
--- a/src/strings/reader.go
+++ b/src/strings/reader.go
@@ -28,12 +28,6 @@ func (r *Reader) Len() int {
 	return int(int64(len(r.s)) - r.i)
 }
 
-// Size returns the original length of the underlying string.
-// Size is the number of bytes available for reading via ReadAt.
-// The returned value is always the same and is not affected by calls
-// to any other method.
-func (r *Reader) Size() int64 { return int64(len(r.s)) }
-
 func (r *Reader) Read(b []byte) (n int, err error) {
 	if len(b) == 0 {
 		return 0, nil
diff --git a/src/strings/reader_test.go b/src/strings/reader_test.go
index 5003a37..bee90eb 100644
--- a/src/strings/reader_test.go
+++ b/src/strings/reader_test.go
@@ -8,7 +8,6 @@ import (
 	"bytes"
 	"fmt"
 	"io"
-	"io/ioutil"
 	"os"
 	"strings"
 	"sync"
@@ -158,15 +157,3 @@ func TestWriteTo(t *testing.T) {
 		}
 	}
 }
-
-// tests that Len is affected by reads, but Size is not.
-func TestReaderLenSize(t *testing.T) {
-	r := strings.NewReader("abc")
-	io.CopyN(ioutil.Discard, r, 1)
-	if r.Len() != 2 {
-		t.Errorf("Len = %d; want 2", r.Len())
-	}
-	if r.Size() != 3 {
-		t.Errorf("Size = %d; want 3", r.Size())
-	}
-}
diff --git a/src/strings/strings.go b/src/strings/strings.go
index dd51dab..27d3849 100644
--- a/src/strings/strings.go
+++ b/src/strings/strings.go
@@ -2,9 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// Package strings implements simple functions to manipulate UTF-8 encoded strings.
-//
-// For information about UTF-8 strings in Go, see https://blog.golang.org/strings.
+// Package strings implements simple functions to manipulate strings.
 package strings
 
 import (
@@ -80,7 +78,6 @@ func hashStrRev(sep string) (uint32, uint32) {
 }
 
 // Count counts the number of non-overlapping instances of sep in s.
-// If sep is an empty string, Count returns 1 + the number of Unicode code points in s.
 func Count(s, sep string) int {
 	n := 0
 	// special cases
@@ -128,17 +125,17 @@ func Count(s, sep string) int {
 	return n
 }
 
-// Contains reports whether substr is within s.
+// Contains returns true if substr is within s.
 func Contains(s, substr string) bool {
 	return Index(s, substr) >= 0
 }
 
-// ContainsAny reports whether any Unicode code points in chars are within s.
+// ContainsAny returns true if any Unicode code points in chars are within s.
 func ContainsAny(s, chars string) bool {
 	return IndexAny(s, chars) >= 0
 }
 
-// ContainsRune reports whether the Unicode code point r is within s.
+// ContainsRune returns true if the Unicode code point r is within s.
 func ContainsRune(s string, r rune) bool {
 	return IndexRune(s, r) >= 0
 }
@@ -187,7 +184,14 @@ func LastIndex(s, sep string) int {
 	case n == 0:
 		return len(s)
 	case n == 1:
-		return LastIndexByte(s, sep[0])
+		// special case worth making fast
+		c := sep[0]
+		for i := len(s) - 1; i >= 0; i-- {
+			if s[i] == c {
+				return i
+			}
+		}
+		return -1
 	case n == len(s):
 		if sep == s {
 			return 0
@@ -266,16 +270,6 @@ func LastIndexAny(s, chars string) int {
 	return -1
 }
 
-// LastIndexByte returns the index of the last instance of c in s, or -1 if c is not present in s.
-func LastIndexByte(s string, c byte) int {
-	for i := len(s) - 1; i >= 0; i-- {
-		if s[i] == c {
-			return i
-		}
-	}
-	return -1
-}
-
 // Generic split: splits after each instance of sep,
 // including sepSave bytes of sep in the subarrays.
 func genSplit(s, sep string, sepSave, n int) []string {
@@ -525,7 +519,7 @@ func isSeparator(r rune) bool {
 // Title returns a copy of the string s with all Unicode letters that begin words
 // mapped to their title case.
 //
-// BUG(rsc): The rule Title uses for word boundaries does not handle Unicode punctuation properly.
+// BUG: The rule Title uses for word boundaries does not handle Unicode punctuation properly.
 func Title(s string) string {
 	// Use a closure here to remember state.
 	// Hackish but effective. Depends on Map scanning in order and calling
diff --git a/src/strings/strings_test.go b/src/strings/strings_test.go
index 4e21dea..7bb81ef 100644
--- a/src/strings/strings_test.go
+++ b/src/strings/strings_test.go
@@ -120,23 +120,6 @@ func TestLastIndex(t *testing.T)    { runIndexTests(t, LastIndex, "LastIndex", l
 func TestIndexAny(t *testing.T)     { runIndexTests(t, IndexAny, "IndexAny", indexAnyTests) }
 func TestLastIndexAny(t *testing.T) { runIndexTests(t, LastIndexAny, "LastIndexAny", lastIndexAnyTests) }
 
-func TestLastIndexByte(t *testing.T) {
-	testCases := []IndexTest{
-		{"", "q", -1},
-		{"abcdef", "q", -1},
-		{"abcdefabcdef", "a", len("abcdef")},      // something in the middle
-		{"abcdefabcdef", "f", len("abcdefabcde")}, // last byte
-		{"zabcdefabcdef", "z", 0},                 // first byte
-		{"a☺b☻c☹d", "b", len("a☺")},               // non-ascii
-	}
-	for _, test := range testCases {
-		actual := LastIndexByte(test.s, test.sep[0])
-		if actual != test.out {
-			t.Errorf("LastIndexByte(%q,%c) = %v; want %v", test.s, test.sep[0], actual, test.out)
-		}
-	}
-}
-
 var indexRuneTests = []struct {
 	s    string
 	rune rune
@@ -586,35 +569,6 @@ func TestTrim(t *testing.T) {
 	}
 }
 
-func BenchmarkTrim(b *testing.B) {
-	b.ReportAllocs()
-
-	for i := 0; i < b.N; i++ {
-		for _, tc := range trimTests {
-			name := tc.f
-			var f func(string, string) string
-			switch name {
-			case "Trim":
-				f = Trim
-			case "TrimLeft":
-				f = TrimLeft
-			case "TrimRight":
-				f = TrimRight
-			case "TrimPrefix":
-				f = TrimPrefix
-			case "TrimSuffix":
-				f = TrimSuffix
-			default:
-				b.Errorf("Undefined trim function %s", name)
-			}
-			actual := f(tc.in, tc.arg)
-			if actual != tc.out {
-				b.Errorf("%s(%q, %q) = %q; want %q", name, tc.in, tc.arg, actual, tc.out)
-			}
-		}
-	}
-}
-
 type predicate struct {
 	f    func(rune) bool
 	name string
diff --git a/src/sudo.bash b/src/sudo.bash
new file mode 100755
index 0000000..33254c2
--- /dev/null
+++ b/src/sudo.bash
@@ -0,0 +1,41 @@
+#!/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.
+
+set -e
+
+case "`uname`" in
+Darwin)
+	;;
+*)
+	exit 0
+esac
+
+# Check that the go command exists
+if ! go help >/dev/null 2>&1; then
+	echo "The go command is not in your PATH." >&2
+	exit 2
+fi
+
+eval $(go env)
+if ! [ -x $GOTOOLDIR/prof ]; then
+	echo "You don't need to run sudo.bash." >&2
+	exit 2
+fi
+
+if [[ ! -d /usr/local/bin ]]; then
+	echo 1>&2 'sudo.bash: problem with /usr/local/bin; cannot install tools.'
+	exit 2
+fi
+
+cd $(dirname $0)
+for i in prof
+do
+	# Remove old binaries if present
+	sudo rm -f /usr/local/bin/6$i
+	# Install new binaries
+	sudo cp $GOTOOLDIR/$i /usr/local/bin/go$i
+	sudo chgrp procmod /usr/local/bin/go$i
+	sudo chmod g+s /usr/local/bin/go$i
+done
diff --git a/src/sync/atomic/asm_386.s b/src/sync/atomic/asm_386.s
index 383d759..740dfe7 100644
--- a/src/sync/atomic/asm_386.s
+++ b/src/sync/atomic/asm_386.s
@@ -50,6 +50,9 @@ swaploop:
 TEXT ·SwapUintptr(SB),NOSPLIT,$0-12
 	JMP	·SwapUint32(SB)
 
+TEXT ·SwapPointer(SB),NOSPLIT,$0-12
+	JMP	·SwapUint32(SB)
+
 TEXT ·CompareAndSwapInt32(SB),NOSPLIT,$0-13
 	JMP	·CompareAndSwapUint32(SB)
 
@@ -66,6 +69,9 @@ TEXT ·CompareAndSwapUint32(SB),NOSPLIT,$0-13
 TEXT ·CompareAndSwapUintptr(SB),NOSPLIT,$0-13
 	JMP	·CompareAndSwapUint32(SB)
 
+TEXT ·CompareAndSwapPointer(SB),NOSPLIT,$0-13
+	JMP	·CompareAndSwapUint32(SB)
+
 TEXT ·CompareAndSwapInt64(SB),NOSPLIT,$0-21
 	JMP	·CompareAndSwapUint64(SB)
 
@@ -203,3 +209,6 @@ TEXT ·StoreUint64(SB),NOSPLIT,$0-12
 
 TEXT ·StoreUintptr(SB),NOSPLIT,$0-8
 	JMP	·StoreUint32(SB)
+
+TEXT ·StorePointer(SB),NOSPLIT,$0-8
+	JMP	·StoreUint32(SB)
diff --git a/src/sync/atomic/asm_amd64.s b/src/sync/atomic/asm_amd64.s
index 551c002..6e53ebe 100644
--- a/src/sync/atomic/asm_amd64.s
+++ b/src/sync/atomic/asm_amd64.s
@@ -29,6 +29,9 @@ TEXT ·SwapUint64(SB),NOSPLIT,$0-24
 TEXT ·SwapUintptr(SB),NOSPLIT,$0-24
 	JMP	·SwapUint64(SB)
 
+TEXT ·SwapPointer(SB),NOSPLIT,$0-24
+	JMP	·SwapUint64(SB)
+
 TEXT ·CompareAndSwapInt32(SB),NOSPLIT,$0-17
 	JMP	·CompareAndSwapUint32(SB)
 
@@ -44,6 +47,9 @@ TEXT ·CompareAndSwapUint32(SB),NOSPLIT,$0-17
 TEXT ·CompareAndSwapUintptr(SB),NOSPLIT,$0-25
 	JMP	·CompareAndSwapUint64(SB)
 
+TEXT ·CompareAndSwapPointer(SB),NOSPLIT,$0-25
+	JMP	·CompareAndSwapUint64(SB)
+
 TEXT ·CompareAndSwapInt64(SB),NOSPLIT,$0-25
 	JMP	·CompareAndSwapUint64(SB)
 
@@ -131,4 +137,10 @@ TEXT ·StoreUint64(SB),NOSPLIT,$0-16
 	RET
 
 TEXT ·StoreUintptr(SB),NOSPLIT,$0-16
-	JMP	·StoreUint64(SB)
+	JMP	·StorePointer(SB)
+
+TEXT ·StorePointer(SB),NOSPLIT,$0-16
+	MOVQ	addr+0(FP), BP
+	MOVQ	val+8(FP), AX
+	XCHGQ	AX, 0(BP)
+	RET
diff --git a/src/sync/atomic/asm_amd64p32.s b/src/sync/atomic/asm_amd64p32.s
index b4e19ee..d77cc2c 100644
--- a/src/sync/atomic/asm_amd64p32.s
+++ b/src/sync/atomic/asm_amd64p32.s
@@ -30,6 +30,9 @@ TEXT ·SwapUint64(SB),NOSPLIT,$0-24
 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)
 
@@ -45,6 +48,9 @@ TEXT ·CompareAndSwapUint32(SB),NOSPLIT,$0-17
 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)
 
@@ -144,4 +150,10 @@ TEXT ·StoreUint64(SB),NOSPLIT,$0-16
 	RET
 
 TEXT ·StoreUintptr(SB),NOSPLIT,$0-8
-	JMP	·StoreUint32(SB)
+	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/sync/atomic/asm_arm.s b/src/sync/atomic/asm_arm.s
index 3b50657..8a85273 100644
--- a/src/sync/atomic/asm_arm.s
+++ b/src/sync/atomic/asm_arm.s
@@ -8,18 +8,6 @@
 
 // ARM atomic operations, for use by asm_$(GOOS)_arm.s.
 
-#define DMB_ISHST_7 \
-	MOVB	runtime·goarm(SB), R11; \
-	CMP	$7, R11; \
-	BLT	2(PC); \
-	WORD	$0xf57ff05a	// dmb ishst
-
-#define DMB_ISH_7 \
-	MOVB	runtime·goarm(SB), R11; \
-	CMP	$7, R11; \
-	BLT	2(PC); \
-	WORD	$0xf57ff05b	// dmb ish
-
 TEXT ·armCompareAndSwapUint32(SB),NOSPLIT,$0-13
 	MOVW	addr+0(FP), R1
 	MOVW	old+4(FP), R2
@@ -29,12 +17,10 @@ casloop:
 	LDREX	(R1), R0
 	CMP	R0, R2
 	BNE	casfail
-	DMB_ISHST_7
 	STREX	R3, (R1), R0
 	CMP	$0, R0
 	BNE	casloop
 	MOVW	$1, R0
-	DMB_ISH_7
 	MOVBU	R0, ret+12(FP)
 	RET
 casfail:
@@ -60,12 +46,10 @@ cas64loop:
 	BNE	cas64fail
 	CMP	R3, R7
 	BNE	cas64fail
-	DMB_ISHST_7
 	STREXD	R4, (R1), R0	// stores R4 and R5
 	CMP	$0, R0
 	BNE	cas64loop
 	MOVW	$1, R0
-	DMB_ISH_7
 	MOVBU	R0, ret+20(FP)
 	RET
 cas64fail:
@@ -80,11 +64,9 @@ addloop:
 	// LDREX and STREX were introduced in ARMv6.
 	LDREX	(R1), R3
 	ADD	R2, R3
-	DMB_ISHST_7
 	STREX	R3, (R1), R0
 	CMP	$0, R0
 	BNE	addloop
-	DMB_ISH_7
 	MOVW	R3, ret+8(FP)
 	RET
 
@@ -102,11 +84,9 @@ add64loop:
 	LDREXD	(R1), R4	// loads R4 and R5
 	ADD.S	R2, R4
 	ADC	R3, R5
-	DMB_ISHST_7
 	STREXD	R4, (R1), R0	// stores R4 and R5
 	CMP	$0, R0
 	BNE	add64loop
-	DMB_ISH_7
 	MOVW	R4, retlo+12(FP)
 	MOVW	R5, rethi+16(FP)
 	RET
@@ -117,11 +97,9 @@ TEXT ·armSwapUint32(SB),NOSPLIT,$0-12
 swaploop:
 	// LDREX and STREX were introduced in ARMv6.
 	LDREX	(R1), R3
-	DMB_ISHST_7
 	STREX	R2, (R1), R0
 	CMP	$0, R0
 	BNE	swaploop
-	DMB_ISH_7
 	MOVW	R3, old+8(FP)
 	RET
 
@@ -137,11 +115,9 @@ TEXT ·armSwapUint64(SB),NOSPLIT,$0-20
 swap64loop:
 	// LDREXD and STREXD were introduced in ARMv6k.
 	LDREXD	(R1), R4	// loads R4 and R5
-	DMB_ISHST_7
 	STREXD	R2, (R1), R0	// stores R2 and R3
 	CMP	$0, R0
 	BNE	swap64loop
-	DMB_ISH_7
 	MOVW	R4, oldlo+12(FP)
 	MOVW	R5, oldhi+16(FP)
 	RET
@@ -155,11 +131,9 @@ TEXT ·armLoadUint64(SB),NOSPLIT,$0-12
 	MOVW	R2, (R2)
 load64loop:
 	LDREXD	(R1), R2	// loads R2 and R3
-	DMB_ISHST_7
 	STREXD	R2, (R1), R0	// stores R2 and R3
 	CMP	$0, R0
 	BNE	load64loop
-	DMB_ISH_7
 	MOVW	R2, vallo+4(FP)
 	MOVW	R3, valhi+8(FP)
 	RET
@@ -175,11 +149,9 @@ TEXT ·armStoreUint64(SB),NOSPLIT,$0-12
 	MOVW	valhi+8(FP), R3
 store64loop:
 	LDREXD	(R1), R4	// loads R4 and R5
-	DMB_ISHST_7
 	STREXD	R2, (R1), R0	// stores R2 and R3
 	CMP	$0, R0
 	BNE	store64loop
-	DMB_ISH_7
 	RET
 
 // Check for broken 64-bit LDREXD as found in QEMU.
diff --git a/src/sync/atomic/asm_freebsd_arm.s b/src/sync/atomic/asm_freebsd_arm.s
index 46710ea..06b975e 100644
--- a/src/sync/atomic/asm_freebsd_arm.s
+++ b/src/sync/atomic/asm_freebsd_arm.s
@@ -16,6 +16,9 @@ TEXT ·CompareAndSwapUint32(SB),NOSPLIT,$0
 TEXT ·CompareAndSwapUintptr(SB),NOSPLIT,$0
 	B ·CompareAndSwapUint32(SB)
 
+TEXT ·CompareAndSwapPointer(SB),NOSPLIT,$0
+	B ·CompareAndSwapUint32(SB)
+
 TEXT ·AddInt32(SB),NOSPLIT,$0
 	B ·AddUint32(SB)
 
@@ -34,6 +37,9 @@ TEXT ·SwapUint32(SB),NOSPLIT,$0
 TEXT ·SwapUintptr(SB),NOSPLIT,$0
 	B ·SwapUint32(SB)
 
+TEXT ·SwapPointer(SB),NOSPLIT,$0
+	B ·SwapUint32(SB)
+
 TEXT ·CompareAndSwapInt64(SB),NOSPLIT,$0
 	B ·CompareAndSwapUint64(SB)
 
@@ -98,3 +104,6 @@ TEXT ·StoreUint64(SB),NOSPLIT,$0
 
 TEXT ·StoreUintptr(SB),NOSPLIT,$0
 	B ·StoreUint32(SB)
+
+TEXT ·StorePointer(SB),NOSPLIT,$0
+	B ·StoreUint32(SB)
diff --git a/src/sync/atomic/asm_linux_arm.s b/src/sync/atomic/asm_linux_arm.s
index 631c105..9447584 100644
--- a/src/sync/atomic/asm_linux_arm.s
+++ b/src/sync/atomic/asm_linux_arm.s
@@ -24,7 +24,7 @@
 // http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=b49c0f24cf6744a3f4fd09289fe7cade349dead5
 //
 TEXT cas<>(SB),NOSPLIT,$0
-	MOVW	$0xffff0fc0, R15
+	MOVW	$0xffff0fc0, PC
 
 TEXT ·CompareAndSwapInt32(SB),NOSPLIT,$0
 	B	·CompareAndSwapUint32(SB)
@@ -57,6 +57,9 @@ cascheck:
 TEXT ·CompareAndSwapUintptr(SB),NOSPLIT,$0
 	B	·CompareAndSwapUint32(SB)
 
+TEXT ·CompareAndSwapPointer(SB),NOSPLIT,$0
+	B	·CompareAndSwapUint32(SB)
+
 TEXT ·AddInt32(SB),NOSPLIT,$0
 	B	·AddUint32(SB)
 
@@ -94,8 +97,11 @@ swaploop1:
 TEXT ·SwapUintptr(SB),NOSPLIT,$0
 	B	·SwapUint32(SB)
 
+TEXT ·SwapPointer(SB),NOSPLIT,$0
+	B	·SwapUint32(SB)
+
 TEXT cas64<>(SB),NOSPLIT,$0
-	MOVW	$0xffff0f60, R15 // R15 = hardware PC. __kuser_cmpxchg64: Linux-3.1 and above
+	MOVW	$0xffff0f60, PC // __kuser_cmpxchg64: Linux-3.1 and above
 
 TEXT kernelCAS64<>(SB),NOSPLIT,$0-21
 	// int (*__kuser_cmpxchg64_t)(const int64_t *oldval, const int64_t *newval, volatile int64_t *ptr);
@@ -107,12 +113,12 @@ TEXT kernelCAS64<>(SB),NOSPLIT,$0-21
 	AND.S	$7, R2, R1
 	BEQ 	2(PC)
 	MOVW	R1, (R1)
-	MOVW	$oldval+4(FP), R0
-	MOVW	$newval+12(FP), R1
+	MOVW	$4(FP), R0 // oldval
+	MOVW	$12(FP), R1 // newval
 	BL	cas64<>(SB)
 	MOVW.CS	$1, R0 // C is set if the kernel has changed *ptr
 	MOVW.CC	$0, R0
-	MOVW	R0, ret+20(FP)
+	MOVW	R0, 20(FP)
 	RET
 
 TEXT ·generalCAS64(SB),NOSPLIT,$0-21
@@ -127,17 +133,17 @@ TEXT setupAndCallCAS64<>(SB),NOSPLIT,$-4-21
 	CMP 	$5, R0
 	MOVW.CS	$kernelCAS64<>(SB), R1
 	MOVW.CS	R1, armCAS64(SB)
-	MOVW.CS	R1, R15 // R15 = hardware PC
+	MOVW.CS	R1, PC
 	MOVB	runtime·armArch(SB), R0
 	// LDREXD, STREXD only present on ARMv6K or higher
 	CMP	$6, R0 // TODO(minux): how to differentiate ARMv6 with ARMv6K?
 	MOVW.CS	$·armCompareAndSwapUint64(SB), R1
 	MOVW.CS	R1, armCAS64(SB)
-	MOVW.CS	R1, R15
+	MOVW.CS	R1, PC
 	// we are out of luck, can only use runtime's emulated 64-bit cas
 	MOVW	$·generalCAS64(SB), R1
 	MOVW	R1, armCAS64(SB)
-	MOVW	R1, R15
+	MOVW	R1, PC
 
 TEXT ·CompareAndSwapInt64(SB),NOSPLIT,$0
 	B   	·CompareAndSwapUint64(SB)
@@ -145,7 +151,7 @@ TEXT ·CompareAndSwapInt64(SB),NOSPLIT,$0
 TEXT ·CompareAndSwapUint64(SB),NOSPLIT,$-4-21
 	MOVW	armCAS64(SB), R0
 	CMP 	$0, R0
-	MOVW.NE	R0, R15 // R15 = hardware PC
+	MOVW.NE	R0, PC
 	B	setupAndCallCAS64<>(SB)
 
 TEXT ·AddInt64(SB),NOSPLIT,$0
@@ -205,3 +211,6 @@ TEXT ·StoreUint64(SB),NOSPLIT,$0
 
 TEXT ·StoreUintptr(SB),NOSPLIT,$0
 	B	·StoreUint32(SB)
+
+TEXT ·StorePointer(SB),NOSPLIT,$0
+	B	·StoreUint32(SB)
diff --git a/src/sync/atomic/asm_nacl_arm.s b/src/sync/atomic/asm_nacl_arm.s
index 8b4b687..76f6233 100644
--- a/src/sync/atomic/asm_nacl_arm.s
+++ b/src/sync/atomic/asm_nacl_arm.s
@@ -16,6 +16,9 @@ TEXT ·CompareAndSwapUint32(SB),NOSPLIT,$0
 TEXT ·CompareAndSwapUintptr(SB),NOSPLIT,$0
 	B ·CompareAndSwapUint32(SB)
 
+TEXT ·CompareAndSwapPointer(SB),NOSPLIT,$0
+	B ·CompareAndSwapUint32(SB)
+
 TEXT ·AddInt32(SB),NOSPLIT,$0
 	B ·AddUint32(SB)
 
@@ -34,6 +37,9 @@ TEXT ·SwapUint32(SB),NOSPLIT,$0
 TEXT ·SwapUintptr(SB),NOSPLIT,$0
 	B ·SwapUint32(SB)
 
+TEXT ·SwapPointer(SB),NOSPLIT,$0
+	B ·SwapUint32(SB)
+
 TEXT ·CompareAndSwapInt64(SB),NOSPLIT,$0
 	B ·CompareAndSwapUint64(SB)
 
@@ -98,3 +104,6 @@ TEXT ·StoreUint64(SB),NOSPLIT,$0
 
 TEXT ·StoreUintptr(SB),NOSPLIT,$0
 	B ·StoreUint32(SB)
+
+TEXT ·StorePointer(SB),NOSPLIT,$0
+	B ·StoreUint32(SB)
diff --git a/src/sync/atomic/asm_netbsd_arm.s b/src/sync/atomic/asm_netbsd_arm.s
index 5c98de3..dbe8089 100644
--- a/src/sync/atomic/asm_netbsd_arm.s
+++ b/src/sync/atomic/asm_netbsd_arm.s
@@ -16,6 +16,9 @@ TEXT ·CompareAndSwapUint32(SB),NOSPLIT,$0
 TEXT ·CompareAndSwapUintptr(SB),NOSPLIT,$0
 	B ·CompareAndSwapUint32(SB)
 
+TEXT ·CompareAndSwapPointer(SB),NOSPLIT,$0
+	B ·CompareAndSwapUint32(SB)
+
 TEXT ·AddInt32(SB),NOSPLIT,$0
 	B ·AddUint32(SB)
 
@@ -34,6 +37,9 @@ TEXT ·SwapUint32(SB),NOSPLIT,$0
 TEXT ·SwapUintptr(SB),NOSPLIT,$0
 	B ·SwapUint32(SB)
 
+TEXT ·SwapPointer(SB),NOSPLIT,$0
+	B ·SwapUint32(SB)
+
 TEXT ·CompareAndSwapInt64(SB),NOSPLIT,$0
 	B ·CompareAndSwapUint64(SB)
 
@@ -98,3 +104,6 @@ TEXT ·StoreUint64(SB),NOSPLIT,$0
 
 TEXT ·StoreUintptr(SB),NOSPLIT,$0
 	B ·StoreUint32(SB)
+
+TEXT ·StorePointer(SB),NOSPLIT,$0
+	B ·StoreUint32(SB)
diff --git a/src/sync/atomic/atomic_test.go b/src/sync/atomic/atomic_test.go
index e2c63b9..9f13af4 100644
--- a/src/sync/atomic/atomic_test.go
+++ b/src/sync/atomic/atomic_test.go
@@ -164,7 +164,7 @@ func TestSwapPointer(t *testing.T) {
 	x.before = magicptr
 	x.after = magicptr
 	var j uintptr
-	for delta := uintptr(1 << 16); delta+delta > delta; delta += delta {
+	for delta := uintptr(1); delta+delta > delta; delta += delta {
 		k := SwapPointer(&x.i, unsafe.Pointer(delta))
 		if uintptr(x.i) != delta || uintptr(k) != j {
 			t.Fatalf("delta=%d i=%d j=%d k=%d", delta, x.i, j, k)
@@ -456,7 +456,7 @@ func TestCompareAndSwapPointer(t *testing.T) {
 	magicptr := uintptr(m)
 	x.before = magicptr
 	x.after = magicptr
-	for val := uintptr(1 << 16); val+val > val; val += val {
+	for val := uintptr(1); val+val > val; val += val {
 		x.i = unsafe.Pointer(val)
 		if !CompareAndSwapPointer(&x.i, unsafe.Pointer(val), unsafe.Pointer(val+1)) {
 			t.Fatalf("should have swapped %#x %#x", val, val+1)
@@ -595,7 +595,7 @@ func TestLoadPointer(t *testing.T) {
 	magicptr := uintptr(m)
 	x.before = magicptr
 	x.after = magicptr
-	for delta := uintptr(1 << 16); delta+delta > delta; delta += delta {
+	for delta := uintptr(1); delta+delta > delta; delta += delta {
 		k := LoadPointer(&x.i)
 		if k != x.i {
 			t.Fatalf("delta=%d i=%d k=%d", delta, x.i, k)
@@ -731,7 +731,7 @@ func TestStorePointer(t *testing.T) {
 	x.before = magicptr
 	x.after = magicptr
 	v := unsafe.Pointer(uintptr(0))
-	for delta := uintptr(1 << 16); delta+delta > delta; delta += delta {
+	for delta := uintptr(1); delta+delta > delta; delta += delta {
 		StorePointer(&x.i, unsafe.Pointer(v))
 		if x.i != v {
 			t.Fatalf("delta=%d i=%d v=%d", delta, x.i, v)
@@ -759,12 +759,14 @@ var hammer32 = map[string]func(*uint32, int){
 	"SwapInt32":             hammerSwapInt32,
 	"SwapUint32":            hammerSwapUint32,
 	"SwapUintptr":           hammerSwapUintptr32,
+	"SwapPointer":           hammerSwapPointer32,
 	"AddInt32":              hammerAddInt32,
 	"AddUint32":             hammerAddUint32,
 	"AddUintptr":            hammerAddUintptr32,
 	"CompareAndSwapInt32":   hammerCompareAndSwapInt32,
 	"CompareAndSwapUint32":  hammerCompareAndSwapUint32,
 	"CompareAndSwapUintptr": hammerCompareAndSwapUintptr32,
+	"CompareAndSwapPointer": hammerCompareAndSwapPointer32,
 }
 
 func init() {
@@ -816,6 +818,20 @@ func hammerSwapUintptr32(uaddr *uint32, count int) {
 	}
 }
 
+func hammerSwapPointer32(uaddr *uint32, count int) {
+	// only safe when uintptr is 32-bit.
+	// not called on 64-bit systems.
+	addr := (*unsafe.Pointer)(unsafe.Pointer(uaddr))
+	seed := int(uintptr(unsafe.Pointer(&count)))
+	for i := 0; i < count; i++ {
+		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: %#08x", old))
+		}
+	}
+}
+
 func hammerAddInt32(uaddr *uint32, count int) {
 	addr := (*int32)(unsafe.Pointer(uaddr))
 	for i := 0; i < count; i++ {
@@ -875,6 +891,20 @@ func hammerCompareAndSwapUintptr32(uaddr *uint32, count int) {
 	}
 }
 
+func hammerCompareAndSwapPointer32(uaddr *uint32, count int) {
+	// only safe when uintptr is 32-bit.
+	// not called on 64-bit systems.
+	addr := (*unsafe.Pointer)(unsafe.Pointer(uaddr))
+	for i := 0; i < count; i++ {
+		for {
+			v := LoadPointer(addr)
+			if CompareAndSwapPointer(addr, v, unsafe.Pointer(uintptr(v)+1)) {
+				break
+			}
+		}
+	}
+}
+
 func TestHammer32(t *testing.T) {
 	const p = 4
 	n := 100000
@@ -910,12 +940,14 @@ var hammer64 = map[string]func(*uint64, int){
 	"SwapInt64":             hammerSwapInt64,
 	"SwapUint64":            hammerSwapUint64,
 	"SwapUintptr":           hammerSwapUintptr64,
+	"SwapPointer":           hammerSwapPointer64,
 	"AddInt64":              hammerAddInt64,
 	"AddUint64":             hammerAddUint64,
 	"AddUintptr":            hammerAddUintptr64,
 	"CompareAndSwapInt64":   hammerCompareAndSwapInt64,
 	"CompareAndSwapUint64":  hammerCompareAndSwapUint64,
 	"CompareAndSwapUintptr": hammerCompareAndSwapUintptr64,
+	"CompareAndSwapPointer": hammerCompareAndSwapPointer64,
 }
 
 func init() {
@@ -967,6 +999,20 @@ func hammerSwapUintptr64(uaddr *uint64, count int) {
 	}
 }
 
+func hammerSwapPointer64(uaddr *uint64, count int) {
+	// only safe when uintptr is 64-bit.
+	// not called on 32-bit systems.
+	addr := (*unsafe.Pointer)(unsafe.Pointer(uaddr))
+	seed := int(uintptr(unsafe.Pointer(&count)))
+	for i := 0; i < count; i++ {
+		new := uintptr(seed+i)<<32 | uintptr(seed+i)<<32>>32
+		old := uintptr(SwapPointer(addr, unsafe.Pointer(new)))
+		if old>>32 != old<<32>>32 {
+			panic(fmt.Sprintf("SwapPointer is not atomic: %v", old))
+		}
+	}
+}
+
 func hammerAddInt64(uaddr *uint64, count int) {
 	addr := (*int64)(unsafe.Pointer(uaddr))
 	for i := 0; i < count; i++ {
@@ -1026,6 +1072,20 @@ func hammerCompareAndSwapUintptr64(uaddr *uint64, count int) {
 	}
 }
 
+func hammerCompareAndSwapPointer64(uaddr *uint64, count int) {
+	// only safe when uintptr is 64-bit.
+	// not called on 32-bit systems.
+	addr := (*unsafe.Pointer)(unsafe.Pointer(uaddr))
+	for i := 0; i < count; i++ {
+		for {
+			v := LoadPointer(addr)
+			if CompareAndSwapPointer(addr, v, unsafe.Pointer(uintptr(v)+1)) {
+				break
+			}
+		}
+	}
+}
+
 func TestHammer64(t *testing.T) {
 	if test64err != nil {
 		t.Skipf("Skipping 64-bit tests: %v", test64err)
@@ -1403,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/sync/export_test.go b/src/sync/export_test.go
index 6f49b3b..fa5983a 100644
--- a/src/sync/export_test.go
+++ b/src/sync/export_test.go
@@ -7,5 +7,3 @@ package sync
 // Export for testing.
 var Runtime_Semacquire = runtime_Semacquire
 var Runtime_Semrelease = runtime_Semrelease
-
-const RaceEnabled = raceenabled
diff --git a/src/sync/mutex.go b/src/sync/mutex.go
index 3f280ad..73b3377 100644
--- a/src/sync/mutex.go
+++ b/src/sync/mutex.go
@@ -48,31 +48,15 @@ func (m *Mutex) Lock() {
 	}
 
 	awoke := false
-	iter := 0
 	for {
 		old := m.state
 		new := old | mutexLocked
 		if old&mutexLocked != 0 {
-			if runtime_canSpin(iter) {
-				// Active spinning makes sense.
-				// Try to set mutexWoken flag to inform Unlock
-				// to not wake other blocked goroutines.
-				if !awoke && old&mutexWoken == 0 && old>>mutexWaiterShift != 0 &&
-					atomic.CompareAndSwapInt32(&m.state, old, old|mutexWoken) {
-					awoke = true
-				}
-				runtime_doSpin()
-				iter++
-				continue
-			}
 			new = old + 1<<mutexWaiterShift
 		}
 		if awoke {
 			// The goroutine has been woken from sleep,
 			// so we need to reset the flag in either case.
-			if new&mutexWoken == 0 {
-				panic("sync: inconsistent mutex state")
-			}
 			new &^= mutexWoken
 		}
 		if atomic.CompareAndSwapInt32(&m.state, old, new) {
@@ -81,7 +65,6 @@ func (m *Mutex) Lock() {
 			}
 			runtime_Semacquire(&m.sema)
 			awoke = true
-			iter = 0
 		}
 	}
 
diff --git a/src/sync/mutex_test.go b/src/sync/mutex_test.go
index 91a4855..151b25c 100644
--- a/src/sync/mutex_test.go
+++ b/src/sync/mutex_test.go
@@ -134,58 +134,3 @@ func BenchmarkMutexWork(b *testing.B) {
 func BenchmarkMutexWorkSlack(b *testing.B) {
 	benchmarkMutex(b, true, true)
 }
-
-func BenchmarkMutexNoSpin(b *testing.B) {
-	// This benchmark models a situation where spinning in the mutex should be
-	// non-profitable and allows to confirm that spinning does not do harm.
-	// To achieve this we create excess of goroutines most of which do local work.
-	// These goroutines yield during local work, so that switching from
-	// a blocked goroutine to other goroutines is profitable.
-	// As a matter of fact, this benchmark still triggers some spinning in the mutex.
-	var m Mutex
-	var acc0, acc1 uint64
-	b.SetParallelism(4)
-	b.RunParallel(func(pb *testing.PB) {
-		c := make(chan bool)
-		var data [4 << 10]uint64
-		for i := 0; pb.Next(); i++ {
-			if i%4 == 0 {
-				m.Lock()
-				acc0 -= 100
-				acc1 += 100
-				m.Unlock()
-			} else {
-				for i := 0; i < len(data); i += 4 {
-					data[i]++
-				}
-				// Elaborate way to say runtime.Gosched
-				// that does not put the goroutine onto global runq.
-				go func() {
-					c <- true
-				}()
-				<-c
-			}
-		}
-	})
-}
-
-func BenchmarkMutexSpin(b *testing.B) {
-	// This benchmark models a situation where spinning in the mutex should be
-	// profitable. To achieve this we create a goroutine per-proc.
-	// These goroutines access considerable amount of local data so that
-	// unnecessary rescheduling is penalized by cache misses.
-	var m Mutex
-	var acc0, acc1 uint64
-	b.RunParallel(func(pb *testing.PB) {
-		var data [16 << 10]uint64
-		for i := 0; pb.Next(); i++ {
-			m.Lock()
-			acc0 -= 100
-			acc1 += 100
-			m.Unlock()
-			for i := 0; i < len(data); i += 4 {
-				data[i]++
-			}
-		}
-	})
-}
diff --git a/src/sync/runtime.go b/src/sync/runtime.go
index c66d2de..3b86630 100644
--- a/src/sync/runtime.go
+++ b/src/sync/runtime.go
@@ -38,10 +38,3 @@ func init() {
 	var s syncSema
 	runtime_Syncsemcheck(unsafe.Sizeof(s))
 }
-
-// Active spinning runtime support.
-// runtime_canSpin returns true is spinning makes sense at the moment.
-func runtime_canSpin(i int) bool
-
-// runtime_doSpin does active spinning.
-func runtime_doSpin()
diff --git a/src/sync/waitgroup.go b/src/sync/waitgroup.go
index de399e6..92cc57d 100644
--- a/src/sync/waitgroup.go
+++ b/src/sync/waitgroup.go
@@ -15,21 +15,23 @@ import (
 // runs and calls Done when finished.  At the same time,
 // Wait can be used to block until all goroutines have finished.
 type WaitGroup struct {
-	// 64-bit value: high 32 bits are counter, low 32 bits are waiter count.
-	// 64-bit atomic operations require 64-bit alignment, but 32-bit
-	// compilers do not ensure it. So we allocate 12 bytes and then use
-	// the aligned 8 bytes in them as state.
-	state1 [12]byte
-	sema   uint32
+	m       Mutex
+	counter int32
+	waiters int32
+	sema    *uint32
 }
 
-func (wg *WaitGroup) state() *uint64 {
-	if uintptr(unsafe.Pointer(&wg.state1))%8 == 0 {
-		return (*uint64)(unsafe.Pointer(&wg.state1))
-	} else {
-		return (*uint64)(unsafe.Pointer(&wg.state1[4]))
-	}
-}
+// WaitGroup creates a new semaphore each time the old semaphore
+// is released. This is to avoid the following race:
+//
+// G1: Add(1)
+// G1: go G2()
+// G1: Wait() // Context switch after Unlock() and before Semacquire().
+// G2: Done() // Release semaphore: sema == 1, waiters == 0. G1 doesn't run yet.
+// G3: Wait() // Finds counter == 0, waiters == 0, doesn't block.
+// G3: Add(1) // Makes counter == 1, waiters == 0.
+// G3: go G4()
+// G3: Wait() // G1 still hasn't run, G3 finds sema == 1, unblocked! Bug.
 
 // Add adds delta, which may be negative, to the WaitGroup counter.
 // If the counter becomes zero, all goroutines blocked on Wait are released.
@@ -41,13 +43,10 @@ func (wg *WaitGroup) state() *uint64 {
 // at any time.
 // Typically this means the calls to Add should execute before the statement
 // creating the goroutine or other event to be waited for.
-// If a WaitGroup is reused to wait for several independent sets of events,
-// new Add calls must happen after all previous Wait calls have returned.
 // See the WaitGroup example.
 func (wg *WaitGroup) Add(delta int) {
-	statep := wg.state()
 	if raceenabled {
-		_ = *statep // trigger nil deref early
+		_ = wg.m.state // trigger nil deref early
 		if delta < 0 {
 			// Synchronize decrements with Wait.
 			raceReleaseMerge(unsafe.Pointer(wg))
@@ -55,9 +54,7 @@ func (wg *WaitGroup) Add(delta int) {
 		raceDisable()
 		defer raceEnable()
 	}
-	state := atomic.AddUint64(statep, uint64(delta)<<32)
-	v := int32(state >> 32)
-	w := uint32(state)
+	v := atomic.AddInt32(&wg.counter, int32(delta))
 	if raceenabled {
 		if delta > 0 && v == int32(delta) {
 			// The first increment must be synchronized with Wait.
@@ -69,25 +66,18 @@ func (wg *WaitGroup) Add(delta int) {
 	if v < 0 {
 		panic("sync: negative WaitGroup counter")
 	}
-	if w != 0 && delta > 0 && v == int32(delta) {
-		panic("sync: WaitGroup misuse: Add called concurrently with Wait")
-	}
-	if v > 0 || w == 0 {
+	if v > 0 || atomic.LoadInt32(&wg.waiters) == 0 {
 		return
 	}
-	// This goroutine has set counter to 0 when waiters > 0.
-	// Now there can't be concurrent mutations of state:
-	// - Adds must not happen concurrently with Wait,
-	// - Wait does not increment waiters if it sees counter == 0.
-	// Still do a cheap sanity check to detect WaitGroup misuse.
-	if *statep != state {
-		panic("sync: WaitGroup misuse: Add called concurrently with Wait")
-	}
-	// Reset waiters count to 0.
-	*statep = 0
-	for ; w != 0; w-- {
-		runtime_Semrelease(&wg.sema)
+	wg.m.Lock()
+	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.m.Unlock()
 }
 
 // Done decrements the WaitGroup counter.
@@ -97,41 +87,51 @@ func (wg *WaitGroup) Done() {
 
 // Wait blocks until the WaitGroup counter is zero.
 func (wg *WaitGroup) Wait() {
-	statep := wg.state()
 	if raceenabled {
-		_ = *statep // trigger nil deref early
+		_ = wg.m.state // trigger nil deref early
 		raceDisable()
 	}
-	for {
-		state := atomic.LoadUint64(statep)
-		v := int32(state >> 32)
-		w := uint32(state)
-		if v == 0 {
-			// Counter is 0, no need to wait.
-			if raceenabled {
-				raceEnable()
-				raceAcquire(unsafe.Pointer(wg))
-			}
-			return
+	if atomic.LoadInt32(&wg.counter) == 0 {
+		if raceenabled {
+			raceEnable()
+			raceAcquire(unsafe.Pointer(wg))
+		}
+		return
+	}
+	wg.m.Lock()
+	w := atomic.AddInt32(&wg.waiters, 1)
+	// This code is racing with the unlocked path in Add above.
+	// The code above modifies counter and then reads waiters.
+	// We must modify waiters and then read counter (the opposite order)
+	// to avoid missing an Add.
+	if atomic.LoadInt32(&wg.counter) == 0 {
+		atomic.AddInt32(&wg.waiters, -1)
+		if raceenabled {
+			raceEnable()
+			raceAcquire(unsafe.Pointer(wg))
+			raceDisable()
 		}
-		// Increment waiters count.
-		if atomic.CompareAndSwapUint64(statep, state, state+1) {
-			if raceenabled && w == 0 {
-				// Wait must be synchronized with the first Add.
-				// Need to model this is as a write to race with the read in Add.
-				// As a consequence, can do the write only for the first waiter,
-				// otherwise concurrent Waits will race with each other.
-				raceWrite(unsafe.Pointer(&wg.sema))
-			}
-			runtime_Semacquire(&wg.sema)
-			if *statep != 0 {
-				panic("sync: WaitGroup is reused before previous Wait has returned")
-			}
-			if raceenabled {
-				raceEnable()
-				raceAcquire(unsafe.Pointer(wg))
-			}
-			return
+		wg.m.Unlock()
+		if raceenabled {
+			raceEnable()
 		}
+		return
+	}
+	if raceenabled && w == 1 {
+		// Wait must be synchronized with the first Add.
+		// Need to model this is as a write to race with the read in Add.
+		// As a consequence, can do the write only for the first waiter,
+		// otherwise concurrent Waits will race with each other.
+		raceWrite(unsafe.Pointer(&wg.sema))
+	}
+	if wg.sema == nil {
+		wg.sema = new(uint32)
+	}
+	s := wg.sema
+	wg.m.Unlock()
+	runtime_Semacquire(s)
+	if raceenabled {
+		raceEnable()
+		raceAcquire(unsafe.Pointer(wg))
 	}
 }
diff --git a/src/sync/waitgroup_test.go b/src/sync/waitgroup_test.go
index 3e3e3bf..4c0a043 100644
--- a/src/sync/waitgroup_test.go
+++ b/src/sync/waitgroup_test.go
@@ -5,7 +5,6 @@
 package sync_test
 
 import (
-	"runtime"
 	. "sync"
 	"sync/atomic"
 	"testing"
@@ -47,12 +46,6 @@ func TestWaitGroup(t *testing.T) {
 	}
 }
 
-func knownRacy(t *testing.T) {
-	if RaceEnabled {
-		t.Skip("skipping known-racy test under the race detector")
-	}
-}
-
 func TestWaitGroupMisuse(t *testing.T) {
 	defer func() {
 		err := recover()
@@ -67,95 +60,6 @@ func TestWaitGroupMisuse(t *testing.T) {
 	t.Fatal("Should panic")
 }
 
-func TestWaitGroupMisuse2(t *testing.T) {
-	knownRacy(t)
-	if testing.Short() {
-		t.Skip("skipping flaky test in short mode; see issue 11443")
-	}
-	if runtime.NumCPU() <= 2 {
-		t.Skip("NumCPU<=2, skipping: this test requires parallelism")
-	}
-	defer func() {
-		err := recover()
-		if err != "sync: negative WaitGroup counter" &&
-			err != "sync: WaitGroup misuse: Add called concurrently with Wait" &&
-			err != "sync: WaitGroup is reused before previous Wait has returned" {
-			t.Fatalf("Unexpected panic: %#v", err)
-		}
-	}()
-	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4))
-	done := make(chan interface{}, 2)
-	// The detection is opportunistically, so we want it to panic
-	// at least in one run out of a million.
-	for i := 0; i < 1e6; i++ {
-		var wg WaitGroup
-		wg.Add(1)
-		go func() {
-			defer func() {
-				done <- recover()
-			}()
-			wg.Wait()
-		}()
-		go func() {
-			defer func() {
-				done <- recover()
-			}()
-			wg.Add(1) // This is the bad guy.
-			wg.Done()
-		}()
-		wg.Done()
-		for j := 0; j < 2; j++ {
-			if err := <-done; err != nil {
-				panic(err)
-			}
-		}
-	}
-	t.Fatal("Should panic")
-}
-
-func TestWaitGroupMisuse3(t *testing.T) {
-	knownRacy(t)
-	if runtime.NumCPU() <= 1 {
-		t.Skip("NumCPU==1, skipping: this test requires parallelism")
-	}
-	defer func() {
-		err := recover()
-		if err != "sync: negative WaitGroup counter" &&
-			err != "sync: WaitGroup misuse: Add called concurrently with Wait" &&
-			err != "sync: WaitGroup is reused before previous Wait has returned" {
-			t.Fatalf("Unexpected panic: %#v", err)
-		}
-	}()
-	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4))
-	done := make(chan interface{}, 1)
-	// The detection is opportunistically, so we want it to panic
-	// at least in one run out of a million.
-	for i := 0; i < 1e6; i++ {
-		var wg WaitGroup
-		wg.Add(1)
-		go func() {
-			wg.Done()
-		}()
-		go func() {
-			defer func() {
-				done <- recover()
-			}()
-			wg.Wait()
-			// Start reusing the wg before waiting for the Wait below to return.
-			wg.Add(1)
-			go func() {
-				wg.Done()
-			}()
-			wg.Wait()
-		}()
-		wg.Wait()
-		if err := <-done; err != nil {
-			panic(err)
-		}
-	}
-	t.Fatal("Should panic")
-}
-
 func TestWaitGroupRace(t *testing.T) {
 	// Run this test for about 1ms.
 	for i := 0; i < 1000; i++ {
@@ -181,19 +85,6 @@ func TestWaitGroupRace(t *testing.T) {
 	}
 }
 
-func TestWaitGroupAlign(t *testing.T) {
-	type X struct {
-		x  byte
-		wg WaitGroup
-	}
-	var x X
-	x.wg.Add(1)
-	go func(x *X) {
-		x.wg.Done()
-	}(&x)
-	x.wg.Wait()
-}
-
 func BenchmarkWaitGroupUncontended(b *testing.B) {
 	type PaddedWaitGroup struct {
 		WaitGroup
@@ -255,17 +146,3 @@ func BenchmarkWaitGroupWait(b *testing.B) {
 func BenchmarkWaitGroupWaitWork(b *testing.B) {
 	benchmarkWaitGroupWait(b, 100)
 }
-
-func BenchmarkWaitGroupActuallyWait(b *testing.B) {
-	b.ReportAllocs()
-	b.RunParallel(func(pb *testing.PB) {
-		for pb.Next() {
-			var wg WaitGroup
-			wg.Add(1)
-			go func() {
-				wg.Done()
-			}()
-			wg.Wait()
-		}
-	})
-}
diff --git a/src/syscall/asm_darwin_386.s b/src/syscall/asm_darwin_386.s
index dee7116..7205deb 100644
--- a/src/syscall/asm_darwin_386.s
+++ b/src/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 "textflag.h"
 #include "funcdata.h"
 
@@ -15,34 +18,34 @@
 
 TEXT	·Syscall(SB),NOSPLIT,$0-28
 	CALL	runtime·entersyscall(SB)
-	MOVL	trap+0(FP), AX	// syscall entry
+	MOVL	4(SP), AX	// syscall entry
 	// slide args down on top of system call number
-	LEAL		a1+4(FP), SI
-	LEAL		trap+0(FP), DI
+	LEAL		8(SP), SI
+	LEAL		4(SP), DI
 	CLD
 	MOVSL
 	MOVSL
 	MOVSL
 	INT	$0x80
 	JAE	ok
-	MOVL	$-1, r1+16(FP)
-	MOVL	$-1, r2+20(FP)
-	MOVL	AX, err+24(FP)
+	MOVL	$-1, 20(SP)	// r1
+	MOVL	$-1, 24(SP)	// r2
+	MOVL	AX, 28(SP)		// errno
 	CALL	runtime·exitsyscall(SB)
 	RET
 ok:
-	MOVL	AX, r1+16(FP)
-	MOVL	DX, r2+20(FP)
-	MOVL	$0, err+24(FP)
+	MOVL	AX, 20(SP)	// r1
+	MOVL	DX, 24(SP)	// r2
+	MOVL	$0, 28(SP)	// errno
 	CALL	runtime·exitsyscall(SB)
 	RET
 
 TEXT	·Syscall6(SB),NOSPLIT,$0-40
 	CALL	runtime·entersyscall(SB)
-	MOVL	trap+0(FP), AX	// syscall entry
+	MOVL	4(SP), AX	// syscall entry
 	// slide args down on top of system call number
-	LEAL		a1+4(FP), SI
-	LEAL		trap+0(FP), DI
+	LEAL		8(SP), SI
+	LEAL		4(SP), DI
 	CLD
 	MOVSL
 	MOVSL
@@ -52,24 +55,24 @@ TEXT	·Syscall6(SB),NOSPLIT,$0-40
 	MOVSL
 	INT	$0x80
 	JAE	ok6
-	MOVL	$-1, r1+28(FP)
-	MOVL	$-1, r2+32(FP)
-	MOVL	AX, err+36(FP)
+	MOVL	$-1, 32(SP)	// r1
+	MOVL	$-1, 36(SP)	// r2
+	MOVL	AX, 40(SP)		// errno
 	CALL	runtime·exitsyscall(SB)
 	RET
 ok6:
-	MOVL	AX, r1+28(FP)
-	MOVL	DX, r2+32(FP)
-	MOVL	$0, err+36(FP)
+	MOVL	AX, 32(SP)	// r1
+	MOVL	DX, 36(SP)	// r2
+	MOVL	$0, 40(SP)	// errno
 	CALL	runtime·exitsyscall(SB)
 	RET
 
 TEXT	·Syscall9(SB),NOSPLIT,$0-52
 	CALL	runtime·entersyscall(SB)
-	MOVL	num+0(FP), AX	// syscall entry
+	MOVL	4(SP), AX	// syscall entry
 	// slide args down on top of system call number
-	LEAL		a1+4(FP), SI
-	LEAL		num+0(FP), DI
+	LEAL		8(SP), SI
+	LEAL		4(SP), DI
 	CLD
 	MOVSL
 	MOVSL
@@ -82,44 +85,44 @@ TEXT	·Syscall9(SB),NOSPLIT,$0-52
 	MOVSL
 	INT	$0x80
 	JAE	ok9
-	MOVL	$-1, r1+40(FP)
-	MOVL	$-1, r2+44(FP)
-	MOVL	AX, err+48(FP)
+	MOVL	$-1, 44(SP)	// r1
+	MOVL	$-1, 48(SP)	// r2
+	MOVL	AX, 52(SP)		// errno
 	CALL	runtime·exitsyscall(SB)
 	RET
 ok9:
-	MOVL	AX, r1+40(FP)
-	MOVL	DX, r2+44(FP)
-	MOVL	$0, err+48(FP)
+	MOVL	AX, 44(SP)	// r1
+	MOVL	DX, 48(SP)	// r2
+	MOVL	$0, 52(SP)	// errno
 	CALL	runtime·exitsyscall(SB)
 	RET
 
 TEXT ·RawSyscall(SB),NOSPLIT,$0-28
-	MOVL	trap+0(FP), AX	// syscall entry
+	MOVL	4(SP), AX	// syscall entry
 	// slide args down on top of system call number
-	LEAL		a1+4(FP), SI
-	LEAL		trap+0(FP), DI
+	LEAL		8(SP), SI
+	LEAL		4(SP), DI
 	CLD
 	MOVSL
 	MOVSL
 	MOVSL
 	INT	$0x80
 	JAE	ok1
-	MOVL	$-1, r1+16(FP)
-	MOVL	$-1, r2+20(FP)
-	MOVL	AX, err+24(FP)
+	MOVL	$-1, 20(SP)	// r1
+	MOVL	$-1, 24(SP)	// r2
+	MOVL	AX, 28(SP)		// errno
 	RET
 ok1:
-	MOVL	AX, r1+16(FP)
-	MOVL	DX, r2+20(FP)
-	MOVL	$0, err+24(FP)
+	MOVL	AX, 20(SP)	// r1
+	MOVL	DX, 24(SP)	// r2
+	MOVL	$0, 28(SP)	// errno
 	RET
 
 TEXT	·RawSyscall6(SB),NOSPLIT,$0-40
-	MOVL	trap+0(FP), AX	// syscall entry
+	MOVL	4(SP), AX	// syscall entry
 	// slide args down on top of system call number
-	LEAL		a1+4(FP), SI
-	LEAL		trap+0(FP), DI
+	LEAL		8(SP), SI
+	LEAL		4(SP), DI
 	CLD
 	MOVSL
 	MOVSL
@@ -129,12 +132,12 @@ TEXT	·RawSyscall6(SB),NOSPLIT,$0-40
 	MOVSL
 	INT	$0x80
 	JAE	ok2
-	MOVL	$-1, r1+28(FP)
-	MOVL	$-1, r2+32(FP)
-	MOVL	AX, err+36(FP)
+	MOVL	$-1, 32(SP)	// r1
+	MOVL	$-1, 36(SP)	// r2
+	MOVL	AX, 40(SP)		// errno
 	RET
 ok2:
-	MOVL	AX, r1+28(FP)
-	MOVL	DX, r2+32(FP)
-	MOVL	$0, err+36(FP)
+	MOVL	AX, 32(SP)	// r1
+	MOVL	DX, 36(SP)	// r2
+	MOVL	$0, 40(SP)	// errno
 	RET
diff --git a/src/syscall/asm_darwin_amd64.s b/src/syscall/asm_darwin_amd64.s
index 01f461b..e57199d 100644
--- a/src/syscall/asm_darwin_amd64.s
+++ b/src/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 "textflag.h"
 #include "funcdata.h"
 
@@ -9,132 +12,96 @@
 // System call support for AMD64, Darwin
 //
 
+// func Syscall(trap int64, a1, a2, a3 int64) (r1, r2, err int64);
+// 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
 
-// func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno);
 TEXT	·Syscall(SB),NOSPLIT,$0-56
 	CALL	runtime·entersyscall(SB)
-	MOVQ	a1+8(FP), DI
-	MOVQ	a2+16(FP), SI
-	MOVQ	a3+24(FP), DX
+	MOVQ	16(SP), DI
+	MOVQ	24(SP), SI
+	MOVQ	32(SP), DX
 	MOVQ	$0, R10
 	MOVQ	$0, R8
 	MOVQ	$0, R9
-	MOVQ	trap+0(FP), AX	// syscall entry
+	MOVQ	8(SP), AX	// syscall entry
 	ADDQ	$0x2000000, AX
 	SYSCALL
 	JCC	ok
-	MOVQ	$-1, r1+32(FP)
-	MOVQ	$0, r2+40(FP)
-	MOVQ	AX, err+48(FP)
+	MOVQ	$-1, 40(SP)	// r1
+	MOVQ	$0, 48(SP)	// r2
+	MOVQ	AX, 56(SP)  // errno
 	CALL	runtime·exitsyscall(SB)
 	RET
 ok:
-	MOVQ	AX, r1+32(FP)
-	MOVQ	DX, r2+40(FP)
-	MOVQ	$0, err+48(FP)
+	MOVQ	AX, 40(SP)	// r1
+	MOVQ	DX, 48(SP)	// r2
+	MOVQ	$0, 56(SP)	// errno
 	CALL	runtime·exitsyscall(SB)
 	RET
 
-// func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno);
 TEXT	·Syscall6(SB),NOSPLIT,$0-80
 	CALL	runtime·entersyscall(SB)
-	MOVQ	a1+8(FP), DI
-	MOVQ	a2+16(FP), SI
-	MOVQ	a3+24(FP), DX
-	MOVQ	a4+32(FP), R10
-	MOVQ	a5+40(FP), R8
-	MOVQ	a6+48(FP), R9
-	MOVQ	trap+0(FP), AX	// syscall entry
+	MOVQ	16(SP), DI
+	MOVQ	24(SP), SI
+	MOVQ	32(SP), DX
+	MOVQ	40(SP), R10
+	MOVQ	48(SP), R8
+	MOVQ	56(SP), R9
+	MOVQ	8(SP), AX	// syscall entry
 	ADDQ	$0x2000000, AX
 	SYSCALL
 	JCC	ok6
-	MOVQ	$-1, r1+56(FP)
-	MOVQ	$0, r2+64(FP)
-	MOVQ	AX, err+72(FP)
+	MOVQ	$-1, 64(SP)	// r1
+	MOVQ	$0, 72(SP)	// r2
+	MOVQ	AX, 80(SP)  // errno
 	CALL	runtime·exitsyscall(SB)
 	RET
 ok6:
-	MOVQ	AX, r1+56(FP)
-	MOVQ	DX, r2+64(FP)
-	MOVQ	$0, err+72(FP)
-	CALL	runtime·exitsyscall(SB)
-	RET
-
-// func Syscall9(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno)
-TEXT	·Syscall9(SB),NOSPLIT,$0-104
-	CALL	runtime·entersyscall(SB)
-	MOVQ	trap+0(FP), AX	// syscall entry
-	MOVQ	a1+8(FP), DI
-	MOVQ	a2+16(FP), SI
-	MOVQ	a3+24(FP), DX
-	MOVQ	a4+32(FP), R10
-	MOVQ	a5+40(FP), R8
-	MOVQ	a6+48(FP), R9
-	MOVQ	a7+56(FP), R11
-	MOVQ	a8+64(FP), R12
-	MOVQ	a9+72(FP), R13
-	SUBQ	$32, SP
-	MOVQ	R11, 8(SP)
-	MOVQ	R12, 16(SP)
-	MOVQ	R13, 24(SP)
-	ADDQ	$0x2000000, AX
-	SYSCALL
-	JCC	ok9
-	ADDQ	$32, SP
-	MOVQ	$-1, r1+80(FP)
-	MOVQ	$0, r2+88(FP)
-	MOVQ	AX, err+96(FP)
-	CALL	runtime·exitsyscall(SB)
-	RET
-ok9:
-	ADDQ	$32, SP
-	MOVQ	AX, r1+80(FP)
-	MOVQ	DX, r2+88(FP)
-	MOVQ	$0, err+96(FP)
+	MOVQ	AX, 64(SP)	// r1
+	MOVQ	DX, 72(SP)	// r2
+	MOVQ	$0, 80(SP)	// errno
 	CALL	runtime·exitsyscall(SB)
 	RET
 
-// func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)
 TEXT ·RawSyscall(SB),NOSPLIT,$0-56
-	MOVQ	a1+8(FP), DI
-	MOVQ	a2+16(FP), SI
-	MOVQ	a3+24(FP), DX
+	MOVQ	16(SP), DI
+	MOVQ	24(SP), SI
+	MOVQ	32(SP), DX
 	MOVQ	$0, R10
 	MOVQ	$0, R8
 	MOVQ	$0, R9
-	MOVQ	trap+0(FP), AX	// syscall entry
+	MOVQ	8(SP), AX	// syscall entry
 	ADDQ	$0x2000000, AX
 	SYSCALL
 	JCC	ok1
-	MOVQ	$-1, r1+32(FP)
-	MOVQ	$0, r2+40(FP)
-	MOVQ	AX, err+48(FP)
+	MOVQ	$-1, 40(SP)	// r1
+	MOVQ	$0, 48(SP)	// r2
+	MOVQ	AX, 56(SP)  // errno
 	RET
 ok1:
-	MOVQ	AX, r1+32(FP)
-	MOVQ	DX, r2+40(FP)
-	MOVQ	$0, err+48(FP)
+	MOVQ	AX, 40(SP)	// r1
+	MOVQ	DX, 48(SP)	// r2
+	MOVQ	$0, 56(SP)	// errno
 	RET
 
-// func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)
 TEXT	·RawSyscall6(SB),NOSPLIT,$0-80
-	MOVQ	a1+8(FP), DI
-	MOVQ	a2+16(FP), SI
-	MOVQ	a3+24(FP), DX
-	MOVQ	a4+32(FP), R10
-	MOVQ	a5+40(FP), R8
-	MOVQ	a6+48(FP), R9
-	MOVQ	trap+0(FP), AX	// syscall entry
+	MOVQ	16(SP), DI
+	MOVQ	24(SP), SI
+	MOVQ	32(SP), DX
+	MOVQ	40(SP), R10
+	MOVQ	48(SP), R8
+	MOVQ	56(SP), R9
+	MOVQ	8(SP), AX	// syscall entry
 	ADDQ	$0x2000000, AX
 	SYSCALL
 	JCC	ok2
-	MOVQ	$-1, r1+56(FP)
-	MOVQ	$0, r2+64(FP)
-	MOVQ	AX, err+72(FP)
+	MOVQ	$-1, 64(SP)	// r1
+	MOVQ	$0, 72(SP)	// r2
+	MOVQ	AX, 80(SP)  // errno
 	RET
 ok2:
-	MOVQ	AX, r1+56(FP)
-	MOVQ	DX, r2+64(FP)
-	MOVQ	$0, err+72(FP)
+	MOVQ	AX, 64(SP)	// r1
+	MOVQ	DX, 72(SP)	// r2
+	MOVQ	$0, 80(SP)	// errno
 	RET
diff --git a/src/syscall/asm_dragonfly_386.s b/src/syscall/asm_dragonfly_386.s
new file mode 100644
index 0000000..7012d23
--- /dev/null
+++ b/src/syscall/asm_dragonfly_386.s
@@ -0,0 +1,140 @@
+// 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 "textflag.h"
+#include "funcdata.h"
+
+//
+// System call support for 386, 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);
+// Trap # in AX, args on stack above caller pc.
+
+TEXT	·Syscall(SB),NOSPLIT,$0-32
+	CALL	runtime·entersyscall(SB)
+	MOVL	4(SP), AX	// syscall entry
+	// slide args down on top of system call number
+	LEAL		8(SP), SI
+	LEAL		4(SP), DI
+	CLD
+	MOVSL
+	MOVSL
+	MOVSL
+	INT	$0x80
+	JAE	ok
+	MOVL	$-1, 20(SP)	// r1
+	MOVL	$-1, 24(SP)	// r2
+	MOVL	AX, 28(SP)		// errno
+	CALL	runtime·exitsyscall(SB)
+	RET
+ok:
+	MOVL	AX, 20(SP)	// r1
+	MOVL	DX, 24(SP)	// r2
+	MOVL	$0, 28(SP)	// errno
+	CALL	runtime·exitsyscall(SB)
+	RET
+
+TEXT	·Syscall6(SB),NOSPLIT,$0-44
+	CALL	runtime·entersyscall(SB)
+	MOVL	4(SP), AX	// syscall entry
+	// slide args down on top of system call number
+	LEAL		8(SP), SI
+	LEAL		4(SP), DI
+	CLD
+	MOVSL
+	MOVSL
+	MOVSL
+	MOVSL
+	MOVSL
+	MOVSL
+	INT	$0x80
+	JAE	ok6
+	MOVL	$-1, 32(SP)	// r1
+	MOVL	$-1, 36(SP)	// r2
+	MOVL	AX, 40(SP)		// errno
+	CALL	runtime·exitsyscall(SB)
+	RET
+ok6:
+	MOVL	AX, 32(SP)	// r1
+	MOVL	DX, 36(SP)	// r2
+	MOVL	$0, 40(SP)	// errno
+	CALL	runtime·exitsyscall(SB)
+	RET
+
+TEXT	·Syscall9(SB),NOSPLIT,$0-56
+	CALL	runtime·entersyscall(SB)
+	MOVL	4(SP), AX	// syscall entry
+	// slide args down on top of system call number
+	LEAL		8(SP), SI
+	LEAL		4(SP), DI
+	CLD
+	MOVSL
+	MOVSL
+	MOVSL
+	MOVSL
+	MOVSL
+	MOVSL
+	MOVSL
+	MOVSL
+	MOVSL
+	INT	$0x80
+	JAE	ok9
+	MOVL	$-1, 44(SP)	// r1
+	MOVL	$-1, 48(SP)	// r2
+	MOVL	AX, 52(SP)		// errno
+	CALL	runtime·exitsyscall(SB)
+	RET
+ok9:
+	MOVL	AX, 44(SP)	// r1
+	MOVL	DX, 48(SP)	// r2
+	MOVL	$0, 52(SP)	// errno
+	CALL	runtime·exitsyscall(SB)
+	RET
+
+TEXT ·RawSyscall(SB),NOSPLIT,$0-32
+	MOVL	4(SP), AX	// syscall entry
+	// slide args down on top of system call number
+	LEAL		8(SP), SI
+	LEAL		4(SP), DI
+	CLD
+	MOVSL
+	MOVSL
+	MOVSL
+	INT	$0x80
+	JAE	ok1
+	MOVL	$-1, 20(SP)	// r1
+	MOVL	$-1, 24(SP)	// r2
+	MOVL	AX, 28(SP)		// errno
+	RET
+ok1:
+	MOVL	AX, 20(SP)	// r1
+	MOVL	DX, 24(SP)	// r2
+	MOVL	$0, 28(SP)	// errno
+	RET
+
+TEXT	·RawSyscall6(SB),NOSPLIT,$0-44
+	MOVL	4(SP), AX	// syscall entry
+	// slide args down on top of system call number
+	LEAL		8(SP), SI
+	LEAL		4(SP), DI
+	CLD
+	MOVSL
+	MOVSL
+	MOVSL
+	MOVSL
+	MOVSL
+	MOVSL
+	INT	$0x80
+	JAE	ok2
+	MOVL	$-1, 32(SP)	// r1
+	MOVL	$-1, 36(SP)	// r2
+	MOVL	AX, 40(SP)		// errno
+	RET
+ok2:
+	MOVL	AX, 32(SP)	// r1
+	MOVL	DX, 36(SP)	// r2
+	MOVL	$0, 40(SP)	// errno
+	RET
diff --git a/src/syscall/asm_freebsd_amd64.s b/src/syscall/asm_freebsd_amd64.s
index c6988c9..c525190 100644
--- a/src/syscall/asm_freebsd_amd64.s
+++ b/src/syscall/asm_freebsd_amd64.s
@@ -12,6 +12,11 @@
 // System call support for AMD64, FreeBSD
 //
 
+// The SYSCALL variant for invoking system calls is broken in FreeBSD.
+// See comment at top of ../runtime/sys_freebsd_amd64.c and
+// golang.org/issue/6372.
+#define SYSCALL MOVQ R10, CX; INT $0x80
+
 // func Syscall(trap int64, a1, a2, a3 int64) (r1, r2, err int64);
 // func Syscall6(trap int64, a1, a2, a3, a4, a5, a6 int64) (r1, r2, err int64);
 // func Syscall9(trap int64, a1, a2, a3, a4, a5, a6, a7, a8, a9 int64) (r1, r2, err int64)
diff --git a/src/syscall/asm_freebsd_arm.s b/src/syscall/asm_freebsd_arm.s
index 64d9dee..6b0c182 100644
--- a/src/syscall/asm_freebsd_arm.s
+++ b/src/syscall/asm_freebsd_arm.s
@@ -15,116 +15,116 @@
 
 TEXT	·Syscall(SB),NOSPLIT,$0-28
 	BL runtime·entersyscall(SB)
-	MOVW trap+0(FP), R7 // syscall number
-	MOVW a1+4(FP), R0 // a1
-	MOVW a2+8(FP), R1 // a2
-	MOVW a3+12(FP), R2 // a3
+	MOVW 0(FP), R7 // syscall number
+	MOVW 4(FP), R0 // a1
+	MOVW 8(FP), R1 // a2
+	MOVW 12(FP), R2 // a3
 	SWI $0 // syscall
 	MOVW $0, R2
 	BCS error
-	MOVW R0, r1+16(FP) // r1
-	MOVW R1, r2+20(FP) // r2
-	MOVW R2, err+24(FP) // errno
+	MOVW R0, 16(FP) // r1
+	MOVW R1, 20(FP) // r2
+	MOVW R2, 24(FP) // errno
 	BL runtime·exitsyscall(SB)
 	RET
 error:
 	MOVW $-1, R3
-	MOVW R3, r1+16(FP) // r1
-	MOVW R2, r2+20(FP) // r2
-	MOVW R0, err+24(FP) // errno
+	MOVW R3, 16(FP) // r1
+	MOVW R2, 20(FP) // r2
+	MOVW R0, 24(FP) // errno
 	BL runtime·exitsyscall(SB)
 	RET
 
 TEXT	·Syscall6(SB),NOSPLIT,$0-40
 	BL runtime·entersyscall(SB)
-	MOVW trap+0(FP), R7 // syscall number
-	MOVW a1+4(FP), R0 // a1
-	MOVW a2+8(FP), R1 // a2
-	MOVW a3+12(FP), R2 // a3
-	MOVW a4+16(FP), R3 // a4
+	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
 	MOVW R13, R4
-	MOVW $a5+20(FP), R13 // a5 to a6 are passed on stack
+	MOVW $20(FP), R13 // a5 to a6 are passed on stack
 	SWI $0 // syscall
 	MOVW R4, R13
 	MOVW $0, R2
 	BCS error6
-	MOVW R0, r1+28(FP) // r1
-	MOVW R1, r2+32(FP) // r2
-	MOVW R2, err+36(FP) // errno
+	MOVW R0, 28(FP) // r1
+	MOVW R1, 32(FP) // r2
+	MOVW R2, 36(FP) // errno
 	BL runtime·exitsyscall(SB)
 	RET
 error6:
 	MOVW $-1, R3
-	MOVW R3, r1+28(FP) // r1
-	MOVW R2, r2+32(FP) // r2
-	MOVW R0, err+36(FP) // errno
+	MOVW R3, 28(FP) // r1
+	MOVW R2, 32(FP) // r2
+	MOVW R0, 36(FP) // errno
 	BL runtime·exitsyscall(SB)
 	RET
 
 TEXT	·Syscall9(SB),NOSPLIT,$0-52
 	BL runtime·entersyscall(SB)
-	MOVW num+0(FP), R7 // syscall number
-	MOVW a1+4(FP), R0 // a1
-	MOVW a2+8(FP), R1 // a2
-	MOVW a3+12(FP), R2 // a3
-	MOVW a4+16(FP), R3 // a4
+	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
 	MOVW R13, R4
-	MOVW $a5+20(FP), R13 // a5 to a9 are passed on stack
+	MOVW $20(FP), R13 // a5 to a9 are passed on stack
 	SWI $0 // syscall
 	MOVW R4, R13
 	MOVW $0, R2
 	BCS error9
-	MOVW R0, r1+40(FP) // r1
-	MOVW R1, r2+44(FP) // r2
-	MOVW R2, err+48(FP) // errno
+	MOVW R0, 40(FP) // r1
+	MOVW R1, 44(FP) // r2
+	MOVW R2, 48(FP) // errno
 	BL runtime·exitsyscall(SB)
 	RET
 error9:
 	MOVW $-1, R3
-	MOVW R3, r1+40(FP) // r1
-	MOVW R2, r2+44(FP) // r2
-	MOVW R0, err+48(FP) // errno
+	MOVW R3, 40(FP) // r1
+	MOVW R2, 44(FP) // r2
+	MOVW R0, 48(FP) // errno
 	BL runtime·exitsyscall(SB)
 	RET
 
 TEXT	·RawSyscall(SB),NOSPLIT,$0-28
-	MOVW trap+0(FP), R7 // syscall number
-	MOVW a1+4(FP), R0 // a1
-	MOVW a2+8(FP), R1 // a2
-	MOVW a3+12(FP), R2 // a3
+	MOVW 0(FP), R7 // syscall number
+	MOVW 4(FP), R0 // a1
+	MOVW 8(FP), R1 // a2
+	MOVW 12(FP), R2 // a3
 	SWI $0 // syscall
 	MOVW $0, R2
 	BCS errorr
-	MOVW R0, r1+16(FP) // r1
-	MOVW R1, r2+20(FP) // r2
-	MOVW R2, err+24(FP) // errno
+	MOVW R0, 16(FP) // r1
+	MOVW R1, 20(FP) // r2
+	MOVW R2, 24(FP) // errno
 	RET
 errorr:
 	MOVW $-1, R3
-	MOVW R3, r1+16(FP) // r1
-	MOVW R2, r2+20(FP) // r2
-	MOVW R0, err+24(FP) // errno
+	MOVW R3, 16(FP) // r1
+	MOVW R2, 20(FP) // r2
+	MOVW R0, 24(FP) // errno
 	RET
 
 TEXT	·RawSyscall6(SB),NOSPLIT,$0-40
-	MOVW trap+0(FP), R7 // syscall number
-	MOVW a1+4(FP), R0 // a1
-	MOVW a2+8(FP), R1 // a2
-	MOVW a3+12(FP), R2 // a3
-	MOVW a4+16(FP), R3 // a4
+	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
 	MOVW R13, R4
-	MOVW $a5+20(FP), R13 // a5 to a6 are passed on stack
+	MOVW $20(FP), R13 // a5 to a6 are passed on stack
 	SWI $0 // syscall
 	MOVW R4, R13
 	MOVW $0, R2
 	BCS errorr6
-	MOVW R0, r1+28(FP) // r1
-	MOVW R1, r2+32(FP) // r2
-	MOVW R2, err+36(FP) // errno
+	MOVW R0, 28(FP) // r1
+	MOVW R1, 32(FP) // r2
+	MOVW R2, 36(FP) // errno
 	RET
 errorr6:
 	MOVW $-1, R3
-	MOVW R3, r1+28(FP) // r1
-	MOVW R2, r2+32(FP) // r2
-	MOVW R0, err+36(FP) // errno
+	MOVW R3, 28(FP) // r1
+	MOVW R2, 32(FP) // r2
+	MOVW R0, 36(FP) // errno
 	RET
diff --git a/src/syscall/asm_linux_386.s b/src/syscall/asm_linux_386.s
index ec7487b..fa1b371 100644
--- a/src/syscall/asm_linux_386.s
+++ b/src/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 "textflag.h"
 #include "funcdata.h"
 
@@ -14,148 +17,148 @@
 
 TEXT	·Syscall(SB),NOSPLIT,$0-28
 	CALL	runtime·entersyscall(SB)
-	MOVL	trap+0(FP), AX	// syscall entry
-	MOVL	a1+4(FP), BX
-	MOVL	a2+8(FP), CX
-	MOVL	a3+12(FP), DX
+	MOVL	4(SP), AX	// syscall entry
+	MOVL	8(SP), BX
+	MOVL	12(SP), CX
+	MOVL	16(SP), DX
 	MOVL	$0, SI
 	MOVL	$0,  DI
 	CALL	*runtime·_vdso(SB)
 	CMPL	AX, $0xfffff001
 	JLS	ok
-	MOVL	$-1, r1+16(FP)
-	MOVL	$0, r2+20(FP)
+	MOVL	$-1, 20(SP)	// r1
+	MOVL	$0, 24(SP)	// r2
 	NEGL	AX
-	MOVL	AX, err+24(FP)
+	MOVL	AX, 28(SP)  // errno
 	CALL	runtime·exitsyscall(SB)
 	RET
 ok:
-	MOVL	AX, r1+16(FP)
-	MOVL	DX, r2+20(FP)
-	MOVL	$0, err+24(FP)
+	MOVL	AX, 20(SP)	// r1
+	MOVL	DX, 24(SP)	// r2
+	MOVL	$0, 28(SP)	// errno
 	CALL	runtime·exitsyscall(SB)
 	RET
 
 // func Syscall6(trap uintptr, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr);
 TEXT	·Syscall6(SB),NOSPLIT,$0-40
 	CALL	runtime·entersyscall(SB)
-	MOVL	trap+0(FP), AX	// syscall entry
-	MOVL	a1+4(FP), BX
-	MOVL	a2+8(FP), CX
-	MOVL	a3+12(FP), DX
-	MOVL	a4+16(FP), SI
-	MOVL	a5+20(FP), DI
-	MOVL	a6+24(FP), BP
+	MOVL	4(SP), AX	// syscall entry
+	MOVL	8(SP), BX
+	MOVL	12(SP), CX
+	MOVL	16(SP), DX
+	MOVL	20(SP), SI
+	MOVL	24(SP), DI
+	MOVL	28(SP), BP
 	CALL	*runtime·_vdso(SB)
 	CMPL	AX, $0xfffff001
 	JLS	ok6
-	MOVL	$-1, r1+28(FP)
-	MOVL	$0, r2+32(FP)
+	MOVL	$-1, 32(SP)	// r1
+	MOVL	$0, 36(SP)	// r2
 	NEGL	AX
-	MOVL	AX, err+36(FP)
+	MOVL	AX, 40(SP)  // errno
 	CALL	runtime·exitsyscall(SB)
 	RET
 ok6:
-	MOVL	AX, r1+28(FP)
-	MOVL	DX, r2+32(FP)
-	MOVL	$0, err+36(FP)
+	MOVL	AX, 32(SP)	// r1
+	MOVL	DX, 36(SP)	// r2
+	MOVL	$0, 40(SP)	// errno
 	CALL	runtime·exitsyscall(SB)
 	RET
 
 // func RawSyscall(trap uintptr, a1, a2, a3 uintptr) (r1, r2, err uintptr);
 TEXT ·RawSyscall(SB),NOSPLIT,$0-28
-	MOVL	trap+0(FP), AX	// syscall entry
-	MOVL	a1+4(FP), BX
-	MOVL	a2+8(FP), CX
-	MOVL	a3+12(FP), DX
+	MOVL	4(SP), AX	// syscall entry
+	MOVL	8(SP), BX
+	MOVL	12(SP), CX
+	MOVL	16(SP), DX
 	MOVL	$0, SI
 	MOVL	$0,  DI
 	CALL	*runtime·_vdso(SB)
 	CMPL	AX, $0xfffff001
 	JLS	ok1
-	MOVL	$-1, r1+16(FP)
-	MOVL	$0, r2+20(FP)
+	MOVL	$-1, 20(SP)	// r1
+	MOVL	$0, 24(SP)	// r2
 	NEGL	AX
-	MOVL	AX, err+24(FP)
+	MOVL	AX, 28(SP)  // errno
 	RET
 ok1:
-	MOVL	AX, r1+16(FP)
-	MOVL	DX, r2+20(FP)
-	MOVL	$0, err+24(FP)
+	MOVL	AX, 20(SP)	// r1
+	MOVL	DX, 24(SP)	// r2
+	MOVL	$0, 28(SP)	// errno
 	RET
 
 // func RawSyscall6(trap uintptr, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr);
 TEXT	·RawSyscall6(SB),NOSPLIT,$0-40
-	MOVL	trap+0(FP), AX	// syscall entry
-	MOVL	a1+4(FP), BX
-	MOVL	a2+8(FP), CX
-	MOVL	a3+12(FP), DX
-	MOVL	a4+16(FP), SI
-	MOVL	a5+20(FP), DI
-	MOVL	a6+24(FP), BP
+	MOVL	4(SP), AX	// syscall entry
+	MOVL	8(SP), BX
+	MOVL	12(SP), CX
+	MOVL	16(SP), DX
+	MOVL	20(SP), SI
+	MOVL	24(SP), DI
+	MOVL	28(SP), BP
 	CALL	*runtime·_vdso(SB)
 	CMPL	AX, $0xfffff001
 	JLS	ok2
-	MOVL	$-1, r1+28(FP)
-	MOVL	$0, r2+32(FP)
+	MOVL	$-1, 32(SP)	// r1
+	MOVL	$0, 36(SP)	// r2
 	NEGL	AX
-	MOVL	AX, err+36(FP)
+	MOVL	AX, 40(SP)  // errno
 	RET
 ok2:
-	MOVL	AX, r1+28(FP)
-	MOVL	DX, r2+32(FP)
-	MOVL	$0, err+36(FP)
+	MOVL	AX, 32(SP)	// r1
+	MOVL	DX, 36(SP)	// r2
+	MOVL	$0, 40(SP)	// errno
 	RET
 
 #define SYS_SOCKETCALL 102	/* from zsysnum_linux_386.go */
 
-// func socketcall(call int, a0, a1, a2, a3, a4, a5 uintptr) (n int, err int)
+// 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-36
 	CALL	runtime·entersyscall(SB)
 	MOVL	$SYS_SOCKETCALL, AX	// syscall entry
-	MOVL	call+0(FP), BX	// socket call number
-	LEAL		a0+4(FP), CX	// pointer to call arguments
+	MOVL	4(SP), BX	// socket call number
+	LEAL		8(SP), CX	// pointer to call arguments
 	MOVL	$0, DX
 	MOVL	$0, SI
 	MOVL	$0,  DI
 	CALL	*runtime·_vdso(SB)
 	CMPL	AX, $0xfffff001
 	JLS	oksock
-	MOVL	$-1, n+28(FP)
+	MOVL	$-1, 32(SP)	// n
 	NEGL	AX
-	MOVL	AX, err+32(FP)
+	MOVL	AX, 36(SP)  // errno
 	CALL	runtime·exitsyscall(SB)
 	RET
 oksock:
-	MOVL	AX, n+28(FP)
-	MOVL	$0, err+32(FP)
+	MOVL	AX, 32(SP)	// n
+	MOVL	$0, 36(SP)	// errno
 	CALL	runtime·exitsyscall(SB)
 	RET
 
-// func rawsocketcall(call int, a0, a1, a2, a3, a4, a5 uintptr) (n int, err int)
+// 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-36
 	MOVL	$SYS_SOCKETCALL, AX	// syscall entry
-	MOVL	call+0(FP), BX	// socket call number
-	LEAL		a0+4(FP), CX	// pointer to call arguments
+	MOVL	4(SP), BX	// socket call number
+	LEAL		8(SP), CX	// pointer to call arguments
 	MOVL	$0, DX
 	MOVL	$0, SI
 	MOVL	$0,  DI
 	CALL	*runtime·_vdso(SB)
 	CMPL	AX, $0xfffff001
 	JLS	oksock1
-	MOVL	$-1, n+28(FP)
+	MOVL	$-1, 32(SP)	// n
 	NEGL	AX
-	MOVL	AX, err+32(FP)
+	MOVL	AX, 36(SP)  // errno
 	RET
 oksock1:
-	MOVL	AX, n+28(FP)
-	MOVL	$0, err+32(FP)
+	MOVL	AX, 32(SP)	// n
+	MOVL	$0, 36(SP)	// errno
 	RET
 
 #define SYS__LLSEEK 140	/* from zsysnum_linux_386.go */
-// func Seek(fd int, offset int64, whence int) (newoffset int64, err 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
@@ -163,22 +166,22 @@ oksock1:
 TEXT ·seek(SB),NOSPLIT,$0-28
 	CALL	runtime·entersyscall(SB)
 	MOVL	$SYS__LLSEEK, AX	// syscall entry
-	MOVL	fd+0(FP), BX
-	MOVL	offset_hi+8(FP), CX
-	MOVL	offset_lo+4(FP), DX
-	LEAL	newoffset_lo+16(FP), SI	// result pointer
-	MOVL	whence+12(FP),  DI
+	MOVL	4(SP), BX	// fd
+	MOVL	12(SP), CX	// offset-high
+	MOVL	8(SP), DX	// offset-low
+	LEAL	20(SP), SI	// result pointer
+	MOVL	16(SP),  DI	// whence
 	CALL	*runtime·_vdso(SB)
 	CMPL	AX, $0xfffff001
 	JLS	okseek
-	MOVL	$-1, newoffset_lo+16(FP)
-	MOVL	$-1, newoffset_hi+20(FP)
+	MOVL	$-1, 20(SP)	// newoffset low
+	MOVL	$-1, 24(SP)	// newoffset high
 	NEGL	AX
-	MOVL	AX, err+24(FP)
+	MOVL	AX, 28(SP)  // errno
 	CALL	runtime·exitsyscall(SB)
 	RET
 okseek:
 	// system call filled in newoffset already
-	MOVL	$0, err+24(FP)
+	MOVL	$0, 28(SP)	// errno
 	CALL	runtime·exitsyscall(SB)
 	RET
diff --git a/src/syscall/asm_linux_amd64.s b/src/syscall/asm_linux_amd64.s
index 6634875..b3ce216 100644
--- a/src/syscall/asm_linux_amd64.s
+++ b/src/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 "textflag.h"
 #include "funcdata.h"
 
@@ -16,104 +19,100 @@
 
 TEXT	·Syscall(SB),NOSPLIT,$0-56
 	CALL	runtime·entersyscall(SB)
-	MOVQ	a1+8(FP), DI
-	MOVQ	a2+16(FP), SI
-	MOVQ	a3+24(FP), DX
+	MOVQ	16(SP), DI
+	MOVQ	24(SP), SI
+	MOVQ	32(SP), DX
 	MOVQ	$0, R10
 	MOVQ	$0, R8
 	MOVQ	$0, R9
-	MOVQ	trap+0(FP), AX	// syscall entry
+	MOVQ	8(SP), AX	// syscall entry
 	SYSCALL
 	CMPQ	AX, $0xfffffffffffff001
 	JLS	ok
-	MOVQ	$-1, r1+32(FP)
-	MOVQ	$0, r2+40(FP)
+	MOVQ	$-1, 40(SP)	// r1
+	MOVQ	$0, 48(SP)	// r2
 	NEGQ	AX
-	MOVQ	AX, err+48(FP)
+	MOVQ	AX, 56(SP)  // errno
 	CALL	runtime·exitsyscall(SB)
 	RET
 ok:
-	MOVQ	AX, r1+32(FP)
-	MOVQ	DX, r2+40(FP)
-	MOVQ	$0, err+48(FP)
+	MOVQ	AX, 40(SP)	// r1
+	MOVQ	DX, 48(SP)	// r2
+	MOVQ	$0, 56(SP)	// errno
 	CALL	runtime·exitsyscall(SB)
 	RET
 
-// func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr)
 TEXT ·Syscall6(SB),NOSPLIT,$0-80
 	CALL	runtime·entersyscall(SB)
-	MOVQ	a1+8(FP), DI
-	MOVQ	a2+16(FP), SI
-	MOVQ	a3+24(FP), DX
-	MOVQ	a4+32(FP), R10
-	MOVQ	a5+40(FP), R8
-	MOVQ	a6+48(FP), R9
-	MOVQ	trap+0(FP), AX	// syscall entry
+	MOVQ	16(SP), DI
+	MOVQ	24(SP), SI
+	MOVQ	32(SP), DX
+	MOVQ	40(SP), R10
+	MOVQ	48(SP), R8
+	MOVQ	56(SP), R9
+	MOVQ	8(SP), AX	// syscall entry
 	SYSCALL
 	CMPQ	AX, $0xfffffffffffff001
 	JLS	ok6
-	MOVQ	$-1, r1+56(FP)
-	MOVQ	$0, r2+64(FP)
+	MOVQ	$-1, 64(SP)	// r1
+	MOVQ	$0, 72(SP)	// r2
 	NEGQ	AX
-	MOVQ	AX, err+72(FP)
+	MOVQ	AX, 80(SP)  // errno
 	CALL	runtime·exitsyscall(SB)
 	RET
 ok6:
-	MOVQ	AX, r1+56(FP)
-	MOVQ	DX, r2+64(FP)
-	MOVQ	$0, err+72(FP)
+	MOVQ	AX, 64(SP)	// r1
+	MOVQ	DX, 72(SP)	// r2
+	MOVQ	$0, 80(SP)	// errno
 	CALL	runtime·exitsyscall(SB)
 	RET
 
-// func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr)
 TEXT ·RawSyscall(SB),NOSPLIT,$0-56
-	MOVQ	a1+8(FP), DI
-	MOVQ	a2+16(FP), SI
-	MOVQ	a3+24(FP), DX
+	MOVQ	16(SP), DI
+	MOVQ	24(SP), SI
+	MOVQ	32(SP), DX
 	MOVQ	$0, R10
 	MOVQ	$0, R8
 	MOVQ	$0, R9
-	MOVQ	trap+0(FP), AX	// syscall entry
+	MOVQ	8(SP), AX	// syscall entry
 	SYSCALL
 	CMPQ	AX, $0xfffffffffffff001
 	JLS	ok1
-	MOVQ	$-1, r1+32(FP)
-	MOVQ	$0, r2+40(FP)
+	MOVQ	$-1, 40(SP)	// r1
+	MOVQ	$0, 48(SP)	// r2
 	NEGQ	AX
-	MOVQ	AX, err+48(FP)
+	MOVQ	AX, 56(SP)  // errno
 	RET
 ok1:
-	MOVQ	AX, r1+32(FP)
-	MOVQ	DX, r2+40(FP)
-	MOVQ	$0, err+48(FP)
+	MOVQ	AX, 40(SP)	// r1
+	MOVQ	DX, 48(SP)	// r2
+	MOVQ	$0, 56(SP)	// errno
 	RET
 
-// func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr)
 TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
-	MOVQ	a1+8(FP), DI
-	MOVQ	a2+16(FP), SI
-	MOVQ	a3+24(FP), DX
-	MOVQ	a4+32(FP), R10
-	MOVQ	a5+40(FP), R8
-	MOVQ	a6+48(FP), R9
-	MOVQ	trap+0(FP), AX	// syscall entry
+	MOVQ	16(SP), DI
+	MOVQ	24(SP), SI
+	MOVQ	32(SP), DX
+	MOVQ	40(SP), R10
+	MOVQ	48(SP), R8
+	MOVQ	56(SP), R9
+	MOVQ	8(SP), AX	// syscall entry
 	SYSCALL
 	CMPQ	AX, $0xfffffffffffff001
 	JLS	ok2
-	MOVQ	$-1, r1+56(FP)
-	MOVQ	$0, r2+64(FP)
+	MOVQ	$-1, 64(SP)	// r1
+	MOVQ	$0, 72(SP)	// r2
 	NEGQ	AX
-	MOVQ	AX, err+72(FP)
+	MOVQ	AX, 80(SP)  // errno
 	RET
 ok2:
-	MOVQ	AX, r1+56(FP)
-	MOVQ	DX, r2+64(FP)
-	MOVQ	$0, err+72(FP)
+	MOVQ	AX, 64(SP)	// r1
+	MOVQ	DX, 72(SP)	// r2
+	MOVQ	$0, 80(SP)	// errno
 	RET
 
-// func gettimeofday(tv *Timeval) (err uintptr)
 TEXT ·gettimeofday(SB),NOSPLIT,$0-16
-	MOVQ	tv+0(FP), DI
+	MOVQ	8(SP), DI
 	MOVQ	$0, SI
 	MOVQ	runtime·__vdso_gettimeofday_sym(SB), AX
 	CALL	AX
@@ -121,8 +120,8 @@ TEXT ·gettimeofday(SB),NOSPLIT,$0-16
 	CMPQ	AX, $0xfffffffffffff001
 	JLS	ok7
 	NEGQ	AX
-	MOVQ	AX, err+8(FP)
+	MOVQ	AX, 16(SP)  // errno
 	RET
 ok7:
-	MOVQ	$0, err+8(FP)
+	MOVQ	$0, 16(SP)  // errno
 	RET
diff --git a/src/syscall/asm_linux_arm.s b/src/syscall/asm_linux_arm.s
index 997ba6f..3526533 100644
--- a/src/syscall/asm_linux_arm.s
+++ b/src/syscall/asm_linux_arm.s
@@ -15,10 +15,10 @@
 
 TEXT	·Syscall(SB),NOSPLIT,$0-28
 	BL		runtime·entersyscall(SB)
-	MOVW	trap+0(FP), R7
-	MOVW	a1+4(FP), R0
-	MOVW	a2+8(FP), R1
-	MOVW	a3+12(FP), R2
+	MOVW	4(SP), R7
+	MOVW	8(SP), R0
+	MOVW	12(SP), R1
+	MOVW	16(SP), R2
 	MOVW	$0, R3
 	MOVW	$0, R4
 	MOVW	$0, R5
@@ -27,18 +27,18 @@ TEXT	·Syscall(SB),NOSPLIT,$0-28
 	CMP		R1, R0
 	BLS		ok
 	MOVW	$-1, R1
-	MOVW	R1, r1+16(FP)
+	MOVW	R1, 20(SP)	// r1
 	MOVW	$0, R2
-	MOVW	R2, r2+20(FP)
+	MOVW	R2, 24(SP)	// r2
 	RSB		$0, R0, R0
-	MOVW	R0, err+24(FP)
+	MOVW	R0, 28(SP)	// errno
 	BL		runtime·exitsyscall(SB)
 	RET
 ok:
-	MOVW	R0, r1+16(FP)
+	MOVW	R0, 20(SP) // r1
 	MOVW	$0, R0
-	MOVW	R0, r2+20(FP)
-	MOVW	R0, err+24(FP)
+	MOVW	R0, 24(SP)	// r2
+	MOVW	R0, 28(SP)	// errno
 	BL		runtime·exitsyscall(SB)
 	RET
 
@@ -46,59 +46,59 @@ ok:
 // Actually Syscall5 but the rest of the code expects it to be named Syscall6.
 TEXT	·Syscall6(SB),NOSPLIT,$0-40
 	BL		runtime·entersyscall(SB)
-	MOVW	trap+0(FP), R7	// syscall entry
-	MOVW	a1+4(FP), R0
-	MOVW	a2+8(FP), R1
-	MOVW	a3+12(FP), R2
-	MOVW	a4+16(FP), R3
-	MOVW	a5+20(FP), R4
-	MOVW	a6+24(FP), R5
+	MOVW	4(SP), R7	// syscall entry
+	MOVW	8(SP), R0
+	MOVW	12(SP), R1
+	MOVW	16(SP), R2
+	MOVW	20(SP), R3
+	MOVW	24(SP), R4
+	MOVW	28(SP), R5
 	SWI		$0
 	MOVW	$0xfffff001, R6
 	CMP		R6, R0
 	BLS		ok6
 	MOVW	$-1, R1
-	MOVW	R1, r1+28(FP)
+	MOVW	R1, 32(SP)	// r1
 	MOVW	$0, R2
-	MOVW	R2, r2+32(FP)
+	MOVW	R2, 36(SP)	// r2
 	RSB		$0, R0, R0
-	MOVW	R0, err+36(FP)
+	MOVW	R0, 40(SP)	// errno
 	BL		runtime·exitsyscall(SB)
 	RET
 ok6:
-	MOVW	R0, r1+28(FP)
-	MOVW	R1, r2+32(FP)
+	MOVW	R0, 32(SP) // r1
+	MOVW	R1, 36(SP)	// r2
 	MOVW	$0, R0
-	MOVW	R0, err+36(FP)
+	MOVW	R0, 40(SP)	// errno
 	BL		runtime·exitsyscall(SB)
 	RET
 
 // func RawSyscall6(trap uintptr, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr);
 // Actually RawSyscall5 but the rest of the code expects it to be named RawSyscall6.
 TEXT	·RawSyscall6(SB),NOSPLIT,$0-40
-	MOVW	trap+0(FP), R7	// syscall entry
-	MOVW	a1+4(FP), R0
-	MOVW	a2+8(FP), R1
-	MOVW	a3+12(FP), R2
-	MOVW	a4+16(FP), R3
-	MOVW	a5+20(FP), R4
-	MOVW	a6+24(FP), R5
+	MOVW	4(SP), R7	// syscall entry
+	MOVW	8(SP), R0
+	MOVW	12(SP), R1
+	MOVW	16(SP), R2
+	MOVW	20(SP), R3
+	MOVW	24(SP), R4
+	MOVW	28(SP), R5
 	SWI		$0
 	MOVW	$0xfffff001, R6
 	CMP		R6, R0
 	BLS		ok2
 	MOVW	$-1, R1
-	MOVW	R1, r1+28(FP)
+	MOVW	R1, 32(SP)	// r1
 	MOVW	$0, R2
-	MOVW	R2, r2+32(FP)
+	MOVW	R2, 36(SP)	// r2
 	RSB		$0, R0, R0
-	MOVW	R0, err+36(FP)
+	MOVW	R0, 40(SP)	// errno
 	RET
 ok2:
-	MOVW	R0, r1+28(FP)
-	MOVW	R1, r2+32(FP)
+	MOVW	R0, 32(SP) // r1
+	MOVW	R1, 36(SP)	// r2
 	MOVW	$0, R0
-	MOVW	R0, err+36(FP)
+	MOVW	R0, 40(SP)	// errno
 	RET
 
 #define SYS__LLSEEK 140  /* from zsysnum_linux_arm.go */
@@ -107,53 +107,53 @@ ok2:
 // 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-28
+TEXT ·seek(SB),NOSPLIT,$0-32
 	BL	runtime·entersyscall(SB)
 	MOVW	$SYS__LLSEEK, R7	// syscall entry
-	MOVW	fd+0(FP), R0
-	MOVW	offset_hi+8(FP), R1
-	MOVW	offset_lo+4(FP), R2
-	MOVW	$newoffset_lo+16(FP), R3
-	MOVW	whence+12(FP), R4
+	MOVW	4(SP), R0	// fd
+	MOVW	12(SP), R1	// offset-high
+	MOVW	8(SP), R2	// offset-low
+	MOVW	$20(SP), R3
+	MOVW	16(SP), R4	// whence
 	SWI	$0
 	MOVW	$0xfffff001, R6
 	CMP	R6, R0
 	BLS	okseek
 	MOVW	$0, R1
-	MOVW	R1, newoffset_lo+16(FP)
-	MOVW	R1, newoffset_hi+20(FP)
+	MOVW	R1, 20(SP)
+	MOVW	R1, 24(SP)
 	RSB	$0, R0, R0
-	MOVW	R0, err+24(FP)
+	MOVW	R0, 28(SP)	// errno
 	BL	runtime·exitsyscall(SB)
 	RET
 okseek:
 	// system call filled in newoffset already
 	MOVW	$0, R0
-	MOVW	R0, err+24(FP)
+	MOVW	R0, 28(SP)	// errno
 	BL	runtime·exitsyscall(SB)
 	RET	
 
 // func RawSyscall(trap uintptr, a1, a2, a3 uintptr) (r1, r2, err uintptr);
 TEXT ·RawSyscall(SB),NOSPLIT,$0-28
-	MOVW	trap+0(FP), R7	// syscall entry
-	MOVW	a1+4(FP), R0
-	MOVW	a2+8(FP), R1
-	MOVW	a3+12(FP), R2
+	MOVW	4(SP), R7	// syscall entry
+	MOVW	8(SP), R0
+	MOVW	12(SP), R1
+	MOVW	16(SP), R2
 	SWI		$0
 	MOVW	$0xfffff001, R1
 	CMP		R1, R0
 	BLS		ok1
 	MOVW	$-1, R1
-	MOVW	R1, r1+16(FP)
+	MOVW	R1, 20(SP)	// r1
 	MOVW	$0, R2
-	MOVW	R2, r2+20(FP)
+	MOVW	R2, 24(SP)	// r2
 	RSB		$0, R0, R0
-	MOVW	R0, err+24(FP)
+	MOVW	R0, 28(SP)	// errno
 	RET
 ok1:
-	MOVW	R0, r1+16(FP)
+	MOVW	R0, 20(SP) // r1
 	MOVW	$0, R0
-	MOVW	R0, r2+20(FP)
-	MOVW	R0, err+24(FP)
+	MOVW	R0, 24(SP)	// r2
+	MOVW	R0, 28(SP)	// errno
 	RET
 
diff --git a/src/syscall/asm_nacl_386.s b/src/syscall/asm_nacl_386.s
index 9d1e541..cb6fb44 100644
--- a/src/syscall/asm_nacl_386.s
+++ b/src/syscall/asm_nacl_386.s
@@ -16,8 +16,7 @@
 #define NACL_SYSJMP(code) \
 	MOVL $(0x10000 + ((code)<<5)), AX; JMP AX
 
-TEXT ·Syscall(SB),NOSPLIT,$12-28
-	NO_LOCAL_POINTERS
+TEXT syscall·Syscall(SB),NOSPLIT,$12-28
 	CALL	runtime·entersyscall(SB)
 	MOVL	trap+0(FP), AX
 	MOVL	a1+4(FP), BX
diff --git a/src/syscall/asm_nacl_amd64p32.s b/src/syscall/asm_nacl_amd64p32.s
index b8c097b..72391c4 100644
--- a/src/syscall/asm_nacl_amd64p32.s
+++ b/src/syscall/asm_nacl_amd64p32.s
@@ -16,7 +16,7 @@
 #define NACL_SYSJMP(code) \
 	MOVL $(0x10000 + ((code)<<5)), AX; JMP AX
 
-TEXT ·Syscall(SB),NOSPLIT,$0-28
+TEXT syscall·Syscall(SB),NOSPLIT,$0-28
 	CALL	runtime·entersyscall(SB)
 	MOVL	trap+0(FP), AX
 	MOVL	a1+4(FP), DI
diff --git a/src/syscall/asm_nacl_arm.s b/src/syscall/asm_nacl_arm.s
index 3e7df1a..78e10bf 100644
--- a/src/syscall/asm_nacl_arm.s
+++ b/src/syscall/asm_nacl_arm.s
@@ -16,7 +16,7 @@
 #define NACL_SYSJMP(code) \
 	MOVW $(0x10000 + ((code)<<5)), R8; B (R8)
 
-TEXT ·Syscall(SB),NOSPLIT,$0-28
+TEXT syscall·Syscall(SB),NOSPLIT,$0-28
 	BL	runtime·entersyscall(SB)
 	MOVW	trap+0(FP), R8
 	MOVW	a1+4(FP), R0
diff --git a/src/syscall/asm_netbsd_arm.s b/src/syscall/asm_netbsd_arm.s
index 18bca56..290bb58 100644
--- a/src/syscall/asm_netbsd_arm.s
+++ b/src/syscall/asm_netbsd_arm.s
@@ -15,113 +15,113 @@
 
 TEXT	·Syscall(SB),NOSPLIT,$0-28
 	BL runtime·entersyscall(SB)
-	MOVW trap+0(FP), R0 // sigcall num
-	MOVW a1+4(FP), R1 // a1
-	MOVW a2+8(FP), R2 // a2
-	MOVW a3+12(FP), R3 // a3
+	MOVW 0(FP), R0 // sigcall num
+	MOVW 4(FP), R1 // a1
+	MOVW 8(FP), R2 // a2
+	MOVW 12(FP), R3 // a3
 	SWI $0 // syscall
 	MOVW $0, R2
 	BCS error
-	MOVW R0, r1+16(FP) // r1
-	MOVW R1, r2+20(FP) // r2
-	MOVW R2, err+24(FP) // err
+	MOVW R0, 16(FP) // r1
+	MOVW R1, 20(FP) // r2
+	MOVW R2, 24(FP) // err
 	BL runtime·exitsyscall(SB)
 	RET
 error:
 	MOVW $-1, R3
-	MOVW R3, r1+16(FP) // r1
-	MOVW R2, r2+20(FP) // r2
-	MOVW R0, err+24(FP) // err
+	MOVW R3, 16(FP) // r1
+	MOVW R2, 20(FP) // r2
+	MOVW R0, 24(FP) // err
 	BL runtime·exitsyscall(SB)
 	RET
 
 TEXT	·Syscall6(SB),NOSPLIT,$0-40
 	BL runtime·entersyscall(SB)
-	MOVW trap+0(FP), R0 // sigcall num
-	MOVW a1+4(FP), R1 // a1
-	MOVW a2+8(FP), R2 // a2
-	MOVW a3+12(FP), R3 // a3
+	MOVW 0(FP), R0 // sigcall num
+	MOVW 4(FP), R1 // a1
+	MOVW 8(FP), R2 // a2
+	MOVW 12(FP), R3 // a3
 	MOVW R13, R4
-	MOVW $a4+16(FP), R13 // a4 to a6 are passed on stack
+	MOVW $16(FP), R13 // a4 to a6 are passed on stack
 	SWI $0 // syscall
 	MOVW R4, R13
 	MOVW $0, R2
 	BCS error6
-	MOVW R0, r1+28(FP) // r1
-	MOVW R1, r2+32(FP) // r2
-	MOVW R2, err+36(FP) // err
+	MOVW R0, 28(FP) // r1
+	MOVW R1, 32(FP) // r2
+	MOVW R2, 36(FP) // err
 	BL runtime·exitsyscall(SB)
 	RET
 error6:
 	MOVW $-1, R3
-	MOVW R3, r1+28(FP) // r1
-	MOVW R2, r2+32(FP) // r2
-	MOVW R0, err+36(FP) // err
+	MOVW R3, 28(FP) // r1
+	MOVW R2, 32(FP) // r2
+	MOVW R0, 36(FP) // err
 	BL runtime·exitsyscall(SB)
 	RET
 
 TEXT	·Syscall9(SB),NOSPLIT,$0-52
 	BL runtime·entersyscall(SB)
-	MOVW trap+0(FP), R0 // sigcall num
-	MOVW a1+4(FP), R1 // a1
-	MOVW a2+8(FP), R2 // a2
-	MOVW a3+12(FP), R3 // a3
+	MOVW 0(FP), R0 // sigcall num
+	MOVW 4(FP), R1 // a1
+	MOVW 8(FP), R2 // a2
+	MOVW 12(FP), R3 // a3
 	MOVW R13, R4
-	MOVW $a4+16(FP), R13 // a4 to a9 are passed on stack
+	MOVW $16(FP), R13 // a4 to a9 are passed on stack
 	SWI $0 // syscall
 	MOVW R4, R13
 	MOVW $0, R2
 	BCS error9
-	MOVW R0, r1+40(FP) // r1
-	MOVW R1, r2+44(FP) // r2
-	MOVW R2, err+48(FP) // err
+	MOVW R0, 40(FP) // r1
+	MOVW R1, 44(FP) // r2
+	MOVW R2, 48(FP) // err
 	BL runtime·exitsyscall(SB)
 	RET
 error9:
 	MOVW $-1, R3
-	MOVW R3, r1+40(FP) // r1
-	MOVW R2, r2+44(FP) // r2
-	MOVW R0, err+48(FP) // err
+	MOVW R3, 40(FP) // r1
+	MOVW R2, 44(FP) // r2
+	MOVW R0, 48(FP) // err
 	BL runtime·exitsyscall(SB)
 	RET
 
 TEXT	·RawSyscall(SB),NOSPLIT,$0-28
-	MOVW trap+0(FP), R0 // sigcall num
-	MOVW a1+4(FP), R1 // a1
-	MOVW a2+8(FP), R2 // a2
-	MOVW a3+12(FP), R3 // a3
+	MOVW 0(FP), R0 // sigcall num
+	MOVW 4(FP), R1 // a1
+	MOVW 8(FP), R2 // a2
+	MOVW 12(FP), R3 // a3
 	SWI $0 // syscall
 	MOVW $0, R2
 	BCS errorr
-	MOVW R0, r1+16(FP) // r1
-	MOVW R1, r2+20(FP) // r2
-	MOVW R2, err+24(FP) // err
+	MOVW R0, 16(FP) // r1
+	MOVW R1, 20(FP) // r2
+	MOVW R2, 24(FP) // err
 	RET
 errorr:
 	MOVW $-1, R3
-	MOVW R3, r1+16(FP) // r1
-	MOVW R2, r2+20(FP) // r2
-	MOVW R0, err+24(FP) // err
+	MOVW R3, 16(FP) // r1
+	MOVW R2, 20(FP) // r2
+	MOVW R0, 24(FP) // err
 	RET
 
 TEXT	·RawSyscall6(SB),NOSPLIT,$0-40
-	MOVW trap+0(FP), R0 // sigcall num
-	MOVW a1+4(FP), R1 // a1
-	MOVW a2+8(FP), R2 // a2
-	MOVW a3+12(FP), R3 // a3
+	MOVW 0(FP), R0 // sigcall num
+	MOVW 4(FP), R1 // a1
+	MOVW 8(FP), R2 // a2
+	MOVW 12(FP), R3 // a3
 	MOVW R13, R4
-	MOVW $a4+16(FP), R13 // a4 to a9 are passed on stack
+	MOVW $16(FP), R13 // a4 to a9 are passed on stack
 	SWI $0 // syscall
 	MOVW R4, R13
 	MOVW $0, R2
 	BCS errorr6
-	MOVW R0, r1+28(FP) // r1
-	MOVW R1, r2+32(FP) // r2
-	MOVW R2, err+36(FP) // err
+	MOVW R0, 28(FP) // r1
+	MOVW R1, 32(FP) // r2
+	MOVW R2, 36(FP) // err
 	RET
 errorr6:
 	MOVW $-1, R3
-	MOVW R3, r1+28(FP) // r1
-	MOVW R2, r2+32(FP) // r2
-	MOVW R0, err+36(FP) // err
+	MOVW R3, 28(FP) // r1
+	MOVW R2, 32(FP) // r2
+	MOVW R0, 36(FP) // err
 	RET
diff --git a/src/syscall/asm_solaris_amd64.s b/src/syscall/asm_solaris_amd64.s
index cc69caa..d0d271c 100644
--- a/src/syscall/asm_solaris_amd64.s
+++ b/src/syscall/asm_solaris_amd64.s
@@ -47,9 +47,6 @@ TEXT ·forkx(SB),NOSPLIT,$0
 TEXT ·gethostname(SB),NOSPLIT,$0
 	JMP	runtime·syscall_gethostname(SB)
 
-TEXT ·getpid(SB),NOSPLIT,$0
-	JMP	runtime·syscall_getpid(SB)
-
 TEXT ·ioctl(SB),NOSPLIT,$0
 	JMP	runtime·syscall_ioctl(SB)
 
diff --git a/src/syscall/creds_test.go b/src/syscall/creds_test.go
index b4a14ff..b1894c6 100644
--- a/src/syscall/creds_test.go
+++ b/src/syscall/creds_test.go
@@ -56,13 +56,7 @@ func TestSCMCredentials(t *testing.T) {
 		ucred.Gid = 0
 		oob := syscall.UnixCredentials(&ucred)
 		_, _, err := cli.(*net.UnixConn).WriteMsgUnix(nil, oob, nil)
-		if op, ok := err.(*net.OpError); ok {
-			err = op.Err
-		}
-		if sys, ok := err.(*os.SyscallError); ok {
-			err = sys.Err
-		}
-		if err != syscall.EPERM {
+		if err.(*net.OpError).Err != syscall.EPERM {
 			t.Fatalf("WriteMsgUnix failed with %v, want EPERM", err)
 		}
 	}
diff --git a/src/syscall/dll_windows.go b/src/syscall/dll_windows.go
index c157e6d..18663b4 100644
--- a/src/syscall/dll_windows.go
+++ b/src/syscall/dll_windows.go
@@ -55,7 +55,7 @@ func LoadDLL(name string) (dll *DLL, err error) {
 	return d, nil
 }
 
-// MustLoadDLL is like LoadDLL but panics if load operation fails.
+// MustLoadDLL is like LoadDLL but panics if load operation failes.
 func MustLoadDLL(name string) *DLL {
 	d, e := LoadDLL(name)
 	if e != nil {
diff --git a/src/syscall/env_plan9.go b/src/syscall/env_plan9.go
index cbf7f41..9ea36c8 100644
--- a/src/syscall/env_plan9.go
+++ b/src/syscall/env_plan9.go
@@ -16,7 +16,7 @@ var (
 )
 
 func readenv(key string) (string, error) {
-	fd, err := open("/env/"+key, O_RDONLY)
+	fd, err := Open("/env/"+key, O_RDONLY)
 	if err != nil {
 		return "", err
 	}
@@ -35,7 +35,7 @@ func readenv(key string) (string, error) {
 }
 
 func writeenv(key, value string) error {
-	fd, err := create("/env/"+key, O_RDWR, 0666)
+	fd, err := Create("/env/"+key, O_RDWR, 0666)
 	if err != nil {
 		return err
 	}
@@ -86,7 +86,7 @@ func Unsetenv(key string) error {
 }
 
 func Environ() []string {
-	fd, err := open("/env", O_RDONLY)
+	fd, err := Open("/env", O_RDONLY)
 	if err != nil {
 		return nil
 	}
diff --git a/src/syscall/env_windows.go b/src/syscall/env_windows.go
index 1cb4754..bc21690 100644
--- a/src/syscall/env_windows.go
+++ b/src/syscall/env_windows.go
@@ -16,17 +16,19 @@ func Getenv(key string) (value string, found bool) {
 	if err != nil {
 		return "", false
 	}
-	n := uint32(100)
-	for {
-		b := make([]uint16, n)
-		n, err = GetEnvironmentVariable(keyp, &b[0], uint32(len(b)))
-		if n == 0 && err == ERROR_ENVVAR_NOT_FOUND {
-			return "", false
-		}
-		if n <= uint32(len(b)) {
-			return string(utf16.Decode(b[:n])), true
+	b := make([]uint16, 100)
+	n, e := GetEnvironmentVariable(keyp, &b[0], uint32(len(b)))
+	if n == 0 && e == ERROR_ENVVAR_NOT_FOUND {
+		return "", false
+	}
+	if n > uint32(len(b)) {
+		b = make([]uint16, n)
+		n, e = GetEnvironmentVariable(keyp, &b[0], uint32(len(b)))
+		if n > uint32(len(b)) {
+			n = 0
 		}
 	}
+	return string(utf16.Decode(b[0:n])), true
 }
 
 func Setenv(key, value string) error {
diff --git a/src/syscall/exec_bsd.go b/src/syscall/exec_bsd.go
index 4b5774b..ff78f19 100644
--- a/src/syscall/exec_bsd.go
+++ b/src/syscall/exec_bsd.go
@@ -16,12 +16,9 @@ type SysProcAttr struct {
 	Credential *Credential // Credential.
 	Ptrace     bool        // Enable tracing.
 	Setsid     bool        // Create session.
-	Setpgid    bool        // Set process group ID to Pgid, or, if Pgid == 0, to new pid.
-	Setctty    bool        // Set controlling terminal to fd Ctty
+	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
-	Ctty       int         // Controlling TTY fd
-	Foreground bool        // Place child's process group in foreground. (Implies Setpgid. Uses Ctty as fd of controlling TTY)
-	Pgid       int         // Child's process group ID if Setpgid.
 }
 
 // Implemented in runtime package.
@@ -104,27 +101,8 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
 	}
 
 	// Set process group
-	if sys.Setpgid || sys.Foreground {
-		// Place child in process group.
-		_, _, err1 = RawSyscall(SYS_SETPGID, 0, uintptr(sys.Pgid), 0)
-		if err1 != 0 {
-			goto childerror
-		}
-	}
-
-	if sys.Foreground {
-		pgrp := sys.Pgid
-		if pgrp == 0 {
-			r1, _, err1 = RawSyscall(SYS_GETPID, 0, 0, 0)
-			if err1 != 0 {
-				goto childerror
-			}
-
-			pgrp = int(r1)
-		}
-
-		// Place process group in foreground.
-		_, _, err1 = RawSyscall(SYS_IOCTL, uintptr(sys.Ctty), uintptr(TIOCSPGRP), uintptr(unsafe.Pointer(&pgrp)))
+	if sys.Setpgid {
+		_, _, err1 = RawSyscall(SYS_SETPGID, 0, 0, 0)
 		if err1 != 0 {
 			goto childerror
 		}
@@ -232,9 +210,9 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
 		}
 	}
 
-	// Set the controlling TTY to Ctty
+	// Make fd 0 the tty
 	if sys.Setctty {
-		_, _, err1 = RawSyscall(SYS_IOCTL, uintptr(sys.Ctty), uintptr(TIOCSCTTY), 0)
+		_, _, err1 = RawSyscall(SYS_IOCTL, 0, uintptr(TIOCSCTTY), 0)
 		if err1 != 0 {
 			goto childerror
 		}
diff --git a/src/syscall/exec_linux.go b/src/syscall/exec_linux.go
index 9bac042..042c20a 100644
--- a/src/syscall/exec_linux.go
+++ b/src/syscall/exec_linux.go
@@ -23,21 +23,14 @@ type SysProcAttr struct {
 	Credential  *Credential    // Credential.
 	Ptrace      bool           // Enable tracing.
 	Setsid      bool           // Create session.
-	Setpgid     bool           // Set process group ID to Pgid, or, if Pgid == 0, to new pid.
+	Setpgid     bool           // Set process group ID to new pid (SYSV setpgrp)
 	Setctty     bool           // Set controlling terminal to fd Ctty (only meaningful if Setsid is set)
 	Noctty      bool           // Detach fd 0 from controlling terminal
-	Ctty        int            // Controlling TTY fd
-	Foreground  bool           // Place child's process group in foreground. (Implies Setpgid. Uses Ctty as fd of controlling TTY)
-	Pgid        int            // Child's process group ID if Setpgid.
+	Ctty        int            // Controlling TTY fd (Linux only)
 	Pdeathsig   Signal         // Signal that the process will get when its parent dies (Linux only)
 	Cloneflags  uintptr        // Flags for clone calls (Linux only)
 	UidMappings []SysProcIDMap // User ID mappings for user namespaces.
 	GidMappings []SysProcIDMap // Group ID mappings for user namespaces.
-	// GidMappingsEnableSetgroups enabling setgroups syscall.
-	// If false, then setgroups syscall will be disabled for the child process.
-	// This parameter is no-op if GidMappings == nil. Otherwise for unprivileged
-	// users this should be set to false for mappings work.
-	GidMappingsEnableSetgroups bool
 }
 
 // Implemented in runtime package.
@@ -65,9 +58,6 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
 		p      [2]int
 	)
 
-	// Record parent PID so child can test if it has died.
-	ppid, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0)
-
 	// 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.
@@ -137,6 +127,26 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
 		}
 	}
 
+	// Parent death signal
+	if sys.Pdeathsig != 0 {
+		_, _, err1 = RawSyscall6(SYS_PRCTL, PR_SET_PDEATHSIG, uintptr(sys.Pdeathsig), 0, 0, 0, 0)
+		if err1 != 0 {
+			goto childerror
+		}
+
+		// Signal self if parent is already dead. This might cause a
+		// duplicate signal in rare cases, but it won't matter when
+		// using SIGKILL.
+		r1, _, _ = RawSyscall(SYS_GETPPID, 0, 0, 0)
+		if r1 == 1 {
+			pid, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0)
+			_, _, err1 := RawSyscall(SYS_KILL, pid, uintptr(sys.Pdeathsig), 0)
+			if err1 != 0 {
+				goto childerror
+			}
+		}
+	}
+
 	// Enable tracing if requested.
 	if sys.Ptrace {
 		_, _, err1 = RawSyscall(SYS_PTRACE, uintptr(PTRACE_TRACEME), 0, 0)
@@ -154,27 +164,8 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
 	}
 
 	// Set process group
-	if sys.Setpgid || sys.Foreground {
-		// Place child in process group.
-		_, _, err1 = RawSyscall(SYS_SETPGID, 0, uintptr(sys.Pgid), 0)
-		if err1 != 0 {
-			goto childerror
-		}
-	}
-
-	if sys.Foreground {
-		pgrp := int32(sys.Pgid)
-		if pgrp == 0 {
-			r1, _, err1 = RawSyscall(SYS_GETPID, 0, 0, 0)
-			if err1 != 0 {
-				goto childerror
-			}
-
-			pgrp = int32(r1)
-		}
-
-		// Place process group in foreground.
-		_, _, err1 = RawSyscall(SYS_IOCTL, uintptr(sys.Ctty), uintptr(TIOCSPGRP), uintptr(unsafe.Pointer(&pgrp)))
+	if sys.Setpgid {
+		_, _, err1 = RawSyscall(SYS_SETPGID, 0, 0, 0)
 		if err1 != 0 {
 			goto childerror
 		}
@@ -217,30 +208,10 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
 		}
 	}
 
-	// Parent death signal
-	if sys.Pdeathsig != 0 {
-		_, _, err1 = RawSyscall6(SYS_PRCTL, PR_SET_PDEATHSIG, uintptr(sys.Pdeathsig), 0, 0, 0, 0)
-		if err1 != 0 {
-			goto childerror
-		}
-
-		// Signal self if parent is already dead. This might cause a
-		// duplicate signal in rare cases, but it won't matter when
-		// using SIGKILL.
-		r1, _, _ = RawSyscall(SYS_GETPPID, 0, 0, 0)
-		if r1 != ppid {
-			pid, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0)
-			_, _, err1 := RawSyscall(SYS_KILL, pid, uintptr(sys.Pdeathsig), 0)
-			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 = RawSyscall(_SYS_dup, uintptr(pipe), uintptr(nextfd), 0)
+		_, _, err1 = RawSyscall(SYS_DUP2, uintptr(pipe), uintptr(nextfd), 0)
 		if err1 != 0 {
 			goto childerror
 		}
@@ -250,7 +221,7 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
 	}
 	for i = 0; i < len(fd); i++ {
 		if fd[i] >= 0 && fd[i] < int(i) {
-			_, _, err1 = RawSyscall(_SYS_dup, uintptr(fd[i]), uintptr(nextfd), 0)
+			_, _, err1 = RawSyscall(SYS_DUP2, uintptr(fd[i]), uintptr(nextfd), 0)
 			if err1 != 0 {
 				goto childerror
 			}
@@ -280,7 +251,7 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
 		}
 		// The new fd is created NOT close-on-exec,
 		// which is exactly what we want.
-		_, _, err1 = RawSyscall(_SYS_dup, uintptr(fd[i]), uintptr(i), 0)
+		_, _, err1 = RawSyscall(SYS_DUP2, uintptr(fd[i]), uintptr(i), 0)
 		if err1 != 0 {
 			goto childerror
 		}
@@ -303,7 +274,7 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
 	}
 
 	// Set the controlling TTY to Ctty
-	if sys.Setctty {
+	if sys.Setctty && sys.Ctty >= 0 {
 		_, _, err1 = RawSyscall(SYS_IOCTL, uintptr(sys.Ctty), uintptr(TIOCSCTTY), 0)
 		if err1 != 0 {
 			goto childerror
@@ -371,32 +342,6 @@ func writeIDMappings(path string, idMap []SysProcIDMap) error {
 	return nil
 }
 
-// writeSetgroups writes to /proc/PID/setgroups "deny" if enable is false
-// and "allow" if enable is true.
-// This is needed since kernel 3.19, because you can't write gid_map without
-// disabling setgroups() system call.
-func writeSetgroups(pid int, enable bool) error {
-	sgf := "/proc/" + itoa(pid) + "/setgroups"
-	fd, err := Open(sgf, O_RDWR, 0)
-	if err != nil {
-		return err
-	}
-
-	var data []byte
-	if enable {
-		data = []byte("allow")
-	} else {
-		data = []byte("deny")
-	}
-
-	if _, err := Write(fd, data); err != nil {
-		Close(fd)
-		return err
-	}
-
-	return Close(fd)
-}
-
 // writeUidGidMappings writes User ID and Group ID mappings for user namespaces
 // for a process and it is called from the parent process.
 func writeUidGidMappings(pid int, sys *SysProcAttr) error {
@@ -408,10 +353,6 @@ func writeUidGidMappings(pid int, sys *SysProcAttr) error {
 	}
 
 	if sys.GidMappings != nil {
-		// If the kernel is too old to support /proc/PID/setgroups, writeSetGroups will return ENOENT; this is OK.
-		if err := writeSetgroups(pid, sys.GidMappingsEnableSetgroups); err != nil && err != ENOENT {
-			return err
-		}
 		gidf := "/proc/" + itoa(pid) + "/gid_map"
 		if err := writeIDMappings(gidf, sys.GidMappings); err != nil {
 			return err
diff --git a/src/syscall/exec_plan9.go b/src/syscall/exec_plan9.go
index 7a415fd..45ee542 100644
--- a/src/syscall/exec_plan9.go
+++ b/src/syscall/exec_plan9.go
@@ -61,11 +61,9 @@ import (
 
 var ForkLock sync.RWMutex
 
-// StringSlicePtr converts a slice of strings to a slice of pointers
-// to NUL-terminated byte arrays. If any string contains a NUL byte
-// this function panics instead of returning an error.
-//
-// Deprecated: Use SlicePtrFromStrings instead.
+// StringSlicePtr is deprecated. Use SlicePtrFromStrings instead.
+// If any string contains a NUL byte this function panics instead
+// of returning an error.
 func StringSlicePtr(ss []string) []*byte {
 	bb := make([]*byte, len(ss)+1)
 	for i := 0; i < len(ss); i++ {
@@ -76,7 +74,7 @@ func StringSlicePtr(ss []string) []*byte {
 }
 
 // SlicePtrFromStrings converts a slice of strings to a slice of
-// pointers to NUL-terminated byte arrays. If any string contains
+// pointers to NUL-terminated byte slices. If any string contains
 // a NUL byte, it returns (nil, EINVAL).
 func SlicePtrFromStrings(ss []string) ([]*byte, error) {
 	var err error
@@ -398,15 +396,9 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error)
 		return 0, err
 	}
 
-	destDir := attr.Dir
-	if destDir == "" {
-		wdmu.Lock()
-		destDir = wdStr
-		wdmu.Unlock()
-	}
 	var dir *byte
-	if destDir != "" {
-		dir, err = BytePtrFromString(destDir)
+	if attr.Dir != "" {
+		dir, err = BytePtrFromString(attr.Dir)
 		if err != nil {
 			return 0, err
 		}
diff --git a/src/syscall/exec_solaris.go b/src/syscall/exec_solaris.go
index 3e949f1..97de6ca 100644
--- a/src/syscall/exec_solaris.go
+++ b/src/syscall/exec_solaris.go
@@ -12,12 +12,9 @@ type SysProcAttr struct {
 	Chroot     string      // Chroot.
 	Credential *Credential // Credential.
 	Setsid     bool        // Create session.
-	Setpgid    bool        // Set process group ID to Pgid, or, if Pgid == 0, to new pid.
-	Setctty    bool        // Set controlling terminal to fd Ctty
+	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
-	Ctty       int         // Controlling TTY fd
-	Foreground bool        // Place child's process group in foreground. (Implies Setpgid. Uses Ctty as fd of controlling TTY)
-	Pgid       int         // Child's process group ID if Setpgid.
 }
 
 // Implemented in runtime package.
@@ -31,7 +28,6 @@ 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 getpid() (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)
@@ -48,7 +44,7 @@ func write1(fd uintptr, buf uintptr, nbyte uintptr) (n uintptr, err Errno)
 // no rescheduling, no malloc calls, and no new stack segments.
 //
 // We call hand-crafted syscalls, implemented in
-// ../runtime/syscall_solaris.go, rather than generated libc wrappers
+// ../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.
@@ -101,27 +97,8 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
 	}
 
 	// Set process group
-	if sys.Setpgid || sys.Foreground {
-		// Place child in process group.
-		err1 = setpgid(0, uintptr(sys.Pgid))
-		if err1 != 0 {
-			goto childerror
-		}
-	}
-
-	if sys.Foreground {
-		pgrp := sys.Pgid
-		if pgrp == 0 {
-			r1, err1 = getpid()
-			if err1 != 0 {
-				goto childerror
-			}
-
-			pgrp = int(r1)
-		}
-
-		// Place process group in foreground.
-		err1 = ioctl(uintptr(sys.Ctty), uintptr(TIOCSPGRP), uintptr(unsafe.Pointer(&pgrp)))
+	if sys.Setpgid {
+		err1 = setpgid(0, 0)
 		if err1 != 0 {
 			goto childerror
 		}
@@ -229,9 +206,9 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
 		}
 	}
 
-	// Set the controlling TTY to Ctty
+	// Make fd 0 the tty
 	if sys.Setctty {
-		err1 = ioctl(uintptr(sys.Ctty), uintptr(TIOCSCTTY), 0)
+		err1 = ioctl(0, uintptr(TIOCSCTTY), 0)
 		if err1 != 0 {
 			goto childerror
 		}
diff --git a/src/syscall/exec_unix.go b/src/syscall/exec_unix.go
index 565252c..890bfdc 100644
--- a/src/syscall/exec_unix.go
+++ b/src/syscall/exec_unix.go
@@ -63,11 +63,9 @@ import (
 
 var ForkLock sync.RWMutex
 
-// StringSlicePtr converts a slice of strings to a slice of pointers
-// to NUL-terminated byte arrays. If any string contains a NUL byte
-// this function panics instead of returning an error.
-//
-// Deprecated: Use SlicePtrFromStrings instead.
+// StringSlicePtr is deprecated. Use SlicePtrFromStrings instead.
+// If any string contains a NUL byte this function panics instead
+// of returning an error.
 func StringSlicePtr(ss []string) []*byte {
 	bb := make([]*byte, len(ss)+1)
 	for i := 0; i < len(ss); i++ {
@@ -78,7 +76,7 @@ func StringSlicePtr(ss []string) []*byte {
 }
 
 // SlicePtrFromStrings converts a slice of strings to a slice of
-// pointers to NUL-terminated byte arrays. If any string contains
+// pointers to NUL-terminated byte slices. If any string contains
 // a NUL byte, it returns (nil, EINVAL).
 func SlicePtrFromStrings(ss []string) ([]*byte, error) {
 	var err error
diff --git a/src/syscall/exec_windows.go b/src/syscall/exec_windows.go
index 5a01843..936aeb5 100644
--- a/src/syscall/exec_windows.go
+++ b/src/syscall/exec_windows.go
@@ -135,17 +135,23 @@ func FullPath(name string) (path string, err error) {
 	if err != nil {
 		return "", err
 	}
-	n := uint32(100)
-	for {
-		buf := make([]uint16, n)
+	buf := make([]uint16, 100)
+	n, err := GetFullPathName(p, uint32(len(buf)), &buf[0], nil)
+	if err != nil {
+		return "", err
+	}
+	if n > uint32(len(buf)) {
+		// Windows is asking for bigger buffer.
+		buf = make([]uint16, n)
 		n, err = GetFullPathName(p, uint32(len(buf)), &buf[0], nil)
 		if err != nil {
 			return "", err
 		}
-		if n <= uint32(len(buf)) {
-			return UTF16ToString(buf[:n]), nil
+		if n > uint32(len(buf)) {
+			return "", EINVAL
 		}
 	}
+	return UTF16ToString(buf[:n]), nil
 }
 
 func isSlash(c uint8) bool {
@@ -244,9 +250,6 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle
 	if len(attr.Files) > 3 {
 		return 0, 0, EWINDOWS
 	}
-	if len(attr.Files) < 3 {
-		return 0, 0, EINVAL
-	}
 
 	if len(attr.Dir) != 0 {
 		// StartProcess assumes that argv0 is relative to attr.Dir,
diff --git a/src/syscall/fs_nacl.go b/src/syscall/fs_nacl.go
index 711809f..6e6ce2a 100644
--- a/src/syscall/fs_nacl.go
+++ b/src/syscall/fs_nacl.go
@@ -772,24 +772,29 @@ func (f *zeroFile) pread(b []byte, offset int64) (int, error) {
 	return len(b), nil
 }
 
-type randomFile struct{}
+type randomFile struct {
+	naclFD int
+}
 
 func openRandom() (devFile, error) {
-	return randomFile{}, nil
+	fd, err := openNamedService("SecureRandom", O_RDONLY)
+	if err != nil {
+		return nil, err
+	}
+	return &randomFile{naclFD: fd}, nil
 }
 
-func (f randomFile) close() error {
+func (f *randomFile) close() error {
+	naclClose(f.naclFD)
+	f.naclFD = -1
 	return nil
 }
 
-func (f randomFile) pread(b []byte, offset int64) (int, error) {
-	if err := naclGetRandomBytes(b); err != nil {
-		return 0, err
-	}
-	return len(b), 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) {
+func (f *randomFile) pwrite(b []byte, offset int64) (int, error) {
 	return 0, EPERM
 }
 
@@ -810,7 +815,7 @@ func fdToFsysFile(fd int) (*fsysFile, error) {
 // 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()
-	defer fs.mu.Unlock()
+	fs.mu.Unlock()
 	f, err := fs.open(name, O_CREATE|O_EXCL, mode)
 	if err != nil {
 		if mode&S_IFMT == S_IFDIR {
diff --git a/src/syscall/mkall.sh b/src/syscall/mkall.sh
index 85fab4f..9cb82a6 100755
--- a/src/syscall/mkall.sh
+++ b/src/syscall/mkall.sh
@@ -107,7 +107,6 @@ case "$#" in
 	exit 2
 esac
 
-GOOSARCH_in=syscall_$GOOSARCH.go
 case "$GOOSARCH" in
 _* | *_ | _)
 	echo 'undefined $GOOS_$GOARCH:' "$GOOSARCH" 1>&2
@@ -124,11 +123,6 @@ darwin_amd64)
 	mksysnum="./mksysnum_darwin.pl /usr/include/sys/syscall.h"
 	mktypes="GOARCH=$GOARCH go tool cgo -godefs"
 	;;
-darwin_arm64)
-	mkerrors="$mkerrors -m64"
-	mksysnum="./mksysnum_darwin.pl /usr/include/sys/syscall.h"
-	mktypes="GOARCH=$GOARCH go tool cgo -godefs"
-	;;
 dragonfly_386)
 	mkerrors="$mkerrors -m32"
 	mksyscall="./mksyscall.pl -l32 -dragonfly"
@@ -179,32 +173,7 @@ linux_amd64)
 linux_arm)
 	mkerrors="$mkerrors"
 	mksyscall="./mksyscall.pl -l32 -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"
-	;;
-linux_arm64)
-	unistd_h=$(ls -1 /usr/include/asm/unistd.h /usr/include/asm-generic/unistd.h 2>/dev/null | head -1)
-	if [ "$unistd_h" = "" ]; then
-		echo >&2 cannot find unistd_64.h
-		exit 1
-	fi
-	mksysnum="./mksysnum_linux.pl $unistd_h"
-	# 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_ppc64)
-	GOOSARCH_in=syscall_linux_ppc64x.go
-	unistd_h=/usr/include/asm/unistd.h
-	mkerrors="$mkerrors -m64"
-	mksysnum="./mksysnum_linux.pl $unistd_h"
-	mktypes="GOARCH=$GOARCH go tool cgo -godefs"
-	;;
-linux_ppc64le)
-	GOOSARCH_in=syscall_linux_ppc64x.go
-	unistd_h=/usr/include/powerpc64le-linux-gnu/asm/unistd.h
-	mkerrors="$mkerrors -m64"
-	mksysnum="./mksysnum_linux.pl $unistd_h"
+	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)
@@ -236,7 +205,7 @@ openbsd_386)
 	mksyscall="./mksyscall.pl -l32 -openbsd"
 	mksysctl="./mksysctl_openbsd.pl"
 	zsysctl="zsysctl_openbsd.go"
-	mksysnum="curl -s 'http://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/kern/syscalls.master' | ./mksysnum_openbsd.pl"
+	mksysnum="curl -s 'http://www.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/kern/syscalls.master' | ./mksysnum_openbsd.pl"
 	mktypes="GOARCH=$GOARCH go tool cgo -godefs"
 	;;
 openbsd_amd64)
@@ -244,15 +213,7 @@ openbsd_amd64)
 	mksyscall="./mksyscall.pl -openbsd"
 	mksysctl="./mksysctl_openbsd.pl"
 	zsysctl="zsysctl_openbsd.go"
-	mksysnum="curl -s 'http://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/kern/syscalls.master' | ./mksysnum_openbsd.pl"
-	mktypes="GOARCH=$GOARCH go tool cgo -godefs"
-	;;
-openbsd_arm)
-	mkerrors="$mkerrors"
-	mksyscall="./mksyscall.pl -l32 -openbsd -arm"
-	mksysctl="./mksysctl_openbsd.pl"
-	zsysctl="zsysctl_openbsd.go"
-	mksysnum="curl -s 'http://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/kern/syscalls.master' | ./mksysnum_openbsd.pl"
+	mksysnum="curl -s 'http://www.openbsd.org/cgi-bin/cvsweb/~checkout~/src/sys/kern/syscalls.master' | ./mksysnum_openbsd.pl"
 	mktypes="GOARCH=$GOARCH go tool cgo -godefs"
 	;;
 plan9_386)
@@ -268,8 +229,9 @@ solaris_amd64)
 	mktypes="GOARCH=$GOARCH go tool cgo -godefs"
 	;;
 windows_*)
-	echo 'run "go generate syscall_windows.go" instead' 1>&2
-	exit 1
+	mksyscall=
+	mkerrors=
+	zerrors=
 	;;
 *)
 	echo 'unrecognized $GOOS_$GOARCH: ' "$GOOSARCH" 1>&2
@@ -279,13 +241,22 @@ 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"
- 		;;
- 	esac
-	if [ -n "$mksyscall" ]; then echo "$mksyscall $syscall_goos $GOOSARCH_in |gofmt >zsyscall_$GOOSARCH.go"; fi
+	case "$GOOS" in
+	windows)
+		echo "GOOS= GOARCH= go build mksyscall_windows.go"
+		echo "./mksyscall_windows syscall_windows.go security_windows.go |gofmt >zsyscall_windows.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 "$mksysnum" ]; then echo "$mksysnum |gofmt >zsysnum_$GOOSARCH.go"; fi
 	if [ -n "$mktypes" ]; then echo "$mktypes types_$GOOS.go |gofmt >ztypes_$GOOSARCH.go"; fi
diff --git a/src/syscall/mkall_windows.bat b/src/syscall/mkall_windows.bat
new file mode 100644
index 0000000..0f3a98b
--- /dev/null
+++ b/src/syscall/mkall_windows.bat
@@ -0,0 +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.
+ at echo off
+
+if exist mkall.sh goto dirok
+echo mkall_windows.bat must be run from src\syscall directory
+goto :end
+:dirok
+
+go build mksyscall_windows.go
+.\mksyscall_windows syscall_windows.go security_windows.go |gofmt >zsyscall_windows.go
+del mksyscall_windows.exe
+
+:end
diff --git a/src/syscall/mkerrors.sh b/src/syscall/mkerrors.sh
index 438de6e..cf0afe0 100755
--- a/src/syscall/mkerrors.sh
+++ b/src/syscall/mkerrors.sh
@@ -87,9 +87,7 @@ includes_FreeBSD='
 includes_Linux='
 #define _LARGEFILE_SOURCE
 #define _LARGEFILE64_SOURCE
-#ifndef __LP64__
 #define _FILE_OFFSET_BITS 64
-#endif
 #define _GNU_SOURCE
 
 #include <bits/sockaddr.h>
@@ -123,14 +121,6 @@ includes_Linux='
 #ifndef MSG_FASTOPEN
 #define MSG_FASTOPEN    0x20000000
 #endif
-
-#ifndef PTRACE_GETREGS
-#define PTRACE_GETREGS	0xc
-#endif
-
-#ifndef PTRACE_SETREGS
-#define PTRACE_SETREGS	0xd
-#endif
 '
 
 includes_NetBSD='
@@ -252,7 +242,6 @@ ccflags="$@"
 		$2 ~ /^(SIGEV_|SIGSTKSZ|SIGRT(MIN|MAX))/ {next}
 		$2 ~ /^(SCM_SRCRT)$/ {next}
 		$2 ~ /^(MAP_FAILED)$/ {next}
-		$2 ~ /^ELF_.*$/ {next}	# <asm/elf.h> contains ELF_ARCH, etc.
 
 		$2 !~ /^ETH_/ &&
 		$2 !~ /^EPROC_/ &&
diff --git a/src/syscall/mksyscall.pl b/src/syscall/mksyscall.pl
index 96437fe..dff9138 100755
--- a/src/syscall/mksyscall.pl
+++ b/src/syscall/mksyscall.pl
@@ -292,7 +292,7 @@ while(<>) {
 		$text .= "\t}\n";
 	} elsif ($do_errno) {
 		$text .= "\tif e1 != 0 {\n";
-		$text .= "\t\terr = errnoErr(e1)\n";
+		$text .= "\t\terr = e1\n";
 		$text .= "\t}\n";
 	}
 	$text .= "\treturn\n";
diff --git a/src/syscall/mksyscall_solaris.pl b/src/syscall/mksyscall_solaris.pl
index f5eb4b3..e72a4d1 100755
--- a/src/syscall/mksyscall_solaris.pl
+++ b/src/syscall/mksyscall_solaris.pl
@@ -61,8 +61,8 @@ sub parseparam($) {
 my $package = "";
 my $text = "";
 my $vars = "";
-my $dynimports = "";
-my $linknames = "";
+my $mods = "";
+my $modnames = "";
 while(<>) {
 	chomp;
 	s/\s+/ /g;
@@ -93,6 +93,11 @@ while(<>) {
 	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 "") {
@@ -100,20 +105,14 @@ while(<>) {
 	}
 
 	# System call pointer variable name.
-	my $sysvarname = "libc_$sysname";
+	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.
-	if($vars eq "") {
-		$vars .= "\t$sysvarname";
-	} else {
-		$vars .= ",\n\t$sysvarname";
-	}
-	$dynimports .= "//go:cgo_import_dynamic $sysvarname $sysname \"$modname.so\"\n";
-	$linknames .= "//go:linkname $sysvarname $sysvarname\n";
+	$vars .= "\t$sysvarname = $modvname.NewProc(\"$sysname\")\n";
 
 	# Go function header.
 	$out = join(', ', @out);
@@ -197,7 +196,7 @@ while(<>) {
 
 	# Actual call.
 	my $args = join(', ', @args);
-	my $call = "$asm(uintptr(unsafe.Pointer(&$sysvarname)), $nargs, $args)";
+	my $call = "$asm($sysvarname.Addr(), $nargs, $args)";
 
 	# Assign return values.
 	my $body = "";
@@ -249,7 +248,7 @@ while(<>) {
 
 	if ($do_errno) {
 		$text .= "\tif e1 != 0 {\n";
-		$text .= "\t\terr = errnoErr(e1)\n";
+		$text .= "\t\terr = e1\n";
 		$text .= "\t}\n";
 	}
 	$text .= "\treturn\n";
@@ -273,12 +272,9 @@ print "import \"syscall\"\n" if $package ne "syscall";
 
 print <<EOF;
 
-$dynimports
-$linknames
-type libcFunc uintptr
-
 var (
-$vars libcFunc
+$mods
+$vars
 )
 
 $text
diff --git a/src/syscall/mksyscall_windows.go b/src/syscall/mksyscall_windows.go
index 622272a..316e88d 100644
--- a/src/syscall/mksyscall_windows.go
+++ b/src/syscall/mksyscall_windows.go
@@ -37,8 +37,6 @@ Usage:
 	mksyscall_windows [flags] [path ...]
 
 The flags are:
-	-output
-		Specify output file name (outputs to console if blank).
 	-trace
 		Generate print statement after every syscall.
 */
@@ -46,15 +44,12 @@ package main
 
 import (
 	"bufio"
-	"bytes"
 	"errors"
 	"flag"
 	"fmt"
-	"go/format"
 	"go/parser"
 	"go/token"
 	"io"
-	"io/ioutil"
 	"log"
 	"os"
 	"strconv"
@@ -62,10 +57,7 @@ import (
 	"text/template"
 )
 
-var (
-	filename       = flag.String("output", "", "output file name (standard output if omitted)")
-	printTraceFlag = flag.Bool("trace", false, "generate print statement after every syscall")
-)
+var PrintTraceFlag = flag.Bool("trace", false, "generate print statement after every syscall")
 
 func trim(s string) string {
 	return strings.Trim(s, " \t")
@@ -387,7 +379,7 @@ func newFn(s string) (*Fn, error) {
 	f := &Fn{
 		Rets:       &Rets{},
 		src:        s,
-		PrintTrace: *printTraceFlag,
+		PrintTrace: *PrintTraceFlag,
 	}
 	// function name and args
 	prefix, body, s, found := extractSection(s, '(', ')')
@@ -627,7 +619,7 @@ func (src *Source) DLLs() []string {
 	return r
 }
 
-// ParseFile adds additional file path to a source set src.
+// 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 {
@@ -677,8 +669,8 @@ func (src *Source) ParseFile(path string) error {
 // Generate output source file from a source set src.
 func (src *Source) Generate(w io.Writer) error {
 	funcMap := template.FuncMap{
-		"packagename": packagename,
 		"syscalldot":  syscalldot,
+		"packagename": packagename,
 	}
 	t := template.Must(template.New("main").Funcs(funcMap).Parse(srcTemplate))
 	err := t.Execute(w, src)
@@ -697,31 +689,15 @@ func usage() {
 func main() {
 	flag.Usage = usage
 	flag.Parse()
-	if len(flag.Args()) <= 0 {
+	if len(os.Args) <= 1 {
 		fmt.Fprintf(os.Stderr, "no files to parse provided\n")
 		usage()
 	}
-
-	src, err := ParseFiles(flag.Args())
-	if err != nil {
-		log.Fatal(err)
-	}
-
-	var buf bytes.Buffer
-	if err := src.Generate(&buf); err != nil {
-		log.Fatal(err)
-	}
-
-	data, err := format.Source(buf.Bytes())
+	src, err := ParseFiles(os.Args[1:])
 	if err != nil {
 		log.Fatal(err)
 	}
-	if *filename == "" {
-		_, err = os.Stdout.Write(data)
-	} else {
-		err = ioutil.WriteFile(*filename, data, 0644)
-	}
-	if err != nil {
+	if err := src.Generate(os.Stdout); err != nil {
 		log.Fatal(err)
 	}
 }
@@ -729,15 +705,14 @@ func main() {
 // TODO: use println instead to print in the following template
 const srcTemplate = `
 
-{{define "main"}}// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT
+{{define "main"}}// go build mksyscall_windows.go && ./mksyscall_windows{{range .Files}} {{.}}{{end}}
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
 package {{packagename}}
 
 import "unsafe"{{if syscalldot}}
 import "syscall"{{end}}
 
-var _ unsafe.Pointer
-
 var (
 {{template "dlls" .}}
 {{template "funcnames" .}})
diff --git a/src/syscall/mksysnum_linux.pl b/src/syscall/mksysnum_linux.pl
index b6fbcb5..c7e5cf7 100755
--- a/src/syscall/mksysnum_linux.pl
+++ b/src/syscall/mksysnum_linux.pl
@@ -18,26 +18,13 @@ EOF
 
 sub fmt {
 	my ($name, $num) = @_;
-	if($num > 999){
-		# ignore depricated syscalls that are no longer implemented
-		# https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/include/uapi/asm-generic/unistd.h?id=refs/heads/master#n716
-		return;
-	}
 	$name =~ y/a-z/A-Z/;
 	print "	SYS_$name = $num;\n";
 }
 
 my $prev;
-open(GCC, "gcc -E -dD $ARGV[0] |") || die "can't run gcc";
-while(<GCC>){
-	if(/^#define __NR_syscalls\s+/) {
-		# ignore redefinitions of __NR_syscalls
-	}
-	elsif(/^#define __NR_(\w+)\s+([0-9]+)/){
-		$prev = $2;
-		fmt($1, $2);
-	}
-	elsif(/^#define __NR3264_(\w+)\s+([0-9]+)/){
+while(<>){
+	if(/^#define __NR_(\w+)\s+([0-9]+)/){
 		$prev = $2;
 		fmt($1, $2);
 	}
diff --git a/src/syscall/route_bsd.go b/src/syscall/route_bsd.go
index c62fdc3..1dabe42 100644
--- a/src/syscall/route_bsd.go
+++ b/src/syscall/route_bsd.go
@@ -4,37 +4,23 @@
 
 // +build darwin dragonfly freebsd netbsd openbsd
 
-package syscall
+// Routing sockets and messages
 
-import (
-	"runtime"
-	"unsafe"
-)
+package syscall
 
-var (
-	freebsdConfArch       string // "machine $arch" line in kern.conftxt on freebsd
-	minRoutingSockaddrLen = rsaAlignOf(0)
-)
+import "unsafe"
 
 // Round the length of a raw sockaddr up to align it properly.
 func rsaAlignOf(salen int) int {
 	salign := sizeofPtr
+	// NOTE: It seems like 64-bit Darwin kernel still requires
+	// 32-bit aligned access to BSD subsystem. Also NetBSD 6
+	// kernel and beyond require 64-bit aligned access to routing
+	// facilities.
 	if darwin64Bit {
-		// Darwin kernels require 32-bit aligned access to
-		// routing facilities.
 		salign = 4
 	} else if netbsd32Bit {
-		// NetBSD 6 and beyond kernels require 64-bit aligned
-		// access to routing facilities.
 		salign = 8
-	} else if runtime.GOOS == "freebsd" {
-		// In the case of kern.supported_archs="amd64 i386",
-		// we need to know the underlying kernel's
-		// architecture because the alignment for routing
-		// facilities are set at the build time of the kernel.
-		if freebsdConfArch == "amd64" {
-			salign = 8
-		}
 	}
 	if salen == 0 {
 		return salign
@@ -42,134 +28,6 @@ func rsaAlignOf(salen int) int {
 	return (salen + salign - 1) & ^(salign - 1)
 }
 
-// parseSockaddrLink parses b as a datalink socket address.
-func parseSockaddrLink(b []byte) (*SockaddrDatalink, error) {
-	sa, _, err := parseLinkLayerAddr(b[4:])
-	if err != nil {
-		return nil, err
-	}
-	rsa := (*RawSockaddrDatalink)(unsafe.Pointer(&b[0]))
-	sa.Len = rsa.Len
-	sa.Family = rsa.Family
-	sa.Index = rsa.Index
-	return sa, nil
-}
-
-// parseLinkLayerAddr parses b as a datalink socket address in
-// conventional BSD kernel form.
-func parseLinkLayerAddr(b []byte) (*SockaddrDatalink, int, error) {
-	// The encoding looks like the following:
-	// +----------------------------+
-	// | Type             (1 octet) |
-	// +----------------------------+
-	// | Name length      (1 octet) |
-	// +----------------------------+
-	// | Address length   (1 octet) |
-	// +----------------------------+
-	// | Selector length  (1 octet) |
-	// +----------------------------+
-	// | Data            (variable) |
-	// +----------------------------+
-	type linkLayerAddr struct {
-		Type byte
-		Nlen byte
-		Alen byte
-		Slen byte
-	}
-	lla := (*linkLayerAddr)(unsafe.Pointer(&b[0]))
-	l := rsaAlignOf(int(4 + lla.Nlen + lla.Alen + lla.Slen))
-	if len(b) < l {
-		return nil, 0, EINVAL
-	}
-	b = b[4:]
-	sa := &SockaddrDatalink{Type: lla.Type, Nlen: lla.Nlen, Alen: lla.Alen, Slen: lla.Slen}
-	for i := 0; len(sa.Data) > i && i < int(lla.Nlen+lla.Alen+lla.Slen); i++ {
-		sa.Data[i] = int8(b[i])
-	}
-	return sa, l, nil
-}
-
-// parseSockaddrInet parses b as an internet socket address.
-func parseSockaddrInet(b []byte, family byte) (Sockaddr, error) {
-	switch family {
-	case AF_INET:
-		if len(b) < SizeofSockaddrInet4 {
-			return nil, EINVAL
-		}
-		rsa := (*RawSockaddrAny)(unsafe.Pointer(&b[0]))
-		return anyToSockaddr(rsa)
-	case AF_INET6:
-		if len(b) < SizeofSockaddrInet6 {
-			return nil, EINVAL
-		}
-		rsa := (*RawSockaddrAny)(unsafe.Pointer(&b[0]))
-		return anyToSockaddr(rsa)
-	default:
-		return nil, EINVAL
-	}
-}
-
-const (
-	offsetofInet4 = int(unsafe.Offsetof(RawSockaddrInet4{}.Addr))
-	offsetofInet6 = int(unsafe.Offsetof(RawSockaddrInet6{}.Addr))
-)
-
-// parseNetworkLayerAddr parses b as an internet socket address in
-// conventional BSD kernel form.
-func parseNetworkLayerAddr(b []byte, family byte) (Sockaddr, error) {
-	// The encoding looks similar to the NLRI encoding.
-	// +----------------------------+
-	// | Length           (1 octet) |
-	// +----------------------------+
-	// | Address prefix  (variable) |
-	// +----------------------------+
-	//
-	// The differences between the kernel form and the NLRI
-	// encoding are:
-	//
-	// - The length field of the kernel form indicates the prefix
-	//   length in bytes, not in bits
-	//
-	// - In the kernel form, zero value of the length field
-	//   doesn't mean 0.0.0.0/0 or ::/0
-	//
-	// - The kernel form appends leading bytes to the prefix field
-	//   to make the <length, prefix> tuple to be conformed with
-	//   the routing messeage boundary
-	l := int(rsaAlignOf(int(b[0])))
-	if len(b) < l {
-		return nil, EINVAL
-	}
-	// Don't reorder case expressions.
-	// The case expressions for IPv6 must come first.
-	switch {
-	case b[0] == SizeofSockaddrInet6:
-		sa := &SockaddrInet6{}
-		copy(sa.Addr[:], b[offsetofInet6:])
-		return sa, nil
-	case family == AF_INET6:
-		sa := &SockaddrInet6{}
-		if l-1 < offsetofInet6 {
-			copy(sa.Addr[:], b[1:l])
-		} else {
-			copy(sa.Addr[:], b[l-offsetofInet6:l])
-		}
-		return sa, nil
-	case b[0] == SizeofSockaddrInet4:
-		sa := &SockaddrInet4{}
-		copy(sa.Addr[:], b[offsetofInet4:])
-		return sa, nil
-	default: // an old fashion, AF_UNSPEC or unknown means AF_INET
-		sa := &SockaddrInet4{}
-		if l-1 < offsetofInet4 {
-			copy(sa.Addr[:], b[1:l])
-		} else {
-			copy(sa.Addr[:], b[l-offsetofInet4:l])
-		}
-		return sa, nil
-	}
-}
-
 // RouteRIB returns routing information base, as known as RIB,
 // which consists of network facility information, states and
 // parameters.
@@ -192,7 +50,7 @@ func RouteRIB(facility, param int) ([]byte, error) {
 
 // RoutingMessage represents a routing message.
 type RoutingMessage interface {
-	sockaddr() ([]Sockaddr, error)
+	sockaddr() []Sockaddr
 }
 
 const anyMessageLen = int(unsafe.Sizeof(anyMessage{}))
@@ -210,41 +68,50 @@ type RouteMessage struct {
 	Data   []byte
 }
 
-func (m *RouteMessage) sockaddr() ([]Sockaddr, error) {
-	var sas [RTAX_MAX]Sockaddr
+const rtaRtMask = RTA_DST | RTA_GATEWAY | RTA_NETMASK | RTA_GENMASK
+
+func (m *RouteMessage) sockaddr() []Sockaddr {
+	var (
+		af  int
+		sas [4]Sockaddr
+	)
 	b := m.Data[:]
-	family := uint8(AF_UNSPEC)
-	for i := uint(0); i < RTAX_MAX && len(b) >= minRoutingSockaddrLen; i++ {
-		if m.Header.Addrs&(1<<i) == 0 {
+	for i := uint(0); i < RTAX_MAX; i++ {
+		if m.Header.Addrs&rtaRtMask&(1<<i) == 0 {
 			continue
 		}
 		rsa := (*RawSockaddr)(unsafe.Pointer(&b[0]))
-		switch rsa.Family {
-		case AF_LINK:
-			sa, err := parseSockaddrLink(b)
+		switch i {
+		case RTAX_DST, RTAX_GATEWAY:
+			sa, err := anyToSockaddr((*RawSockaddrAny)(unsafe.Pointer(rsa)))
 			if err != nil {
-				return nil, err
+				return nil
 			}
-			sas[i] = sa
-			b = b[rsaAlignOf(int(rsa.Len)):]
-		case AF_INET, AF_INET6:
-			sa, err := parseSockaddrInet(b, rsa.Family)
-			if err != nil {
-				return nil, err
+			if i == RTAX_DST {
+				af = int(rsa.Family)
 			}
 			sas[i] = sa
-			b = b[rsaAlignOf(int(rsa.Len)):]
-			family = rsa.Family
-		default:
-			sa, err := parseNetworkLayerAddr(b, family)
-			if err != nil {
-				return nil, err
+		case RTAX_NETMASK, RTAX_GENMASK:
+			switch af {
+			case AF_INET:
+				rsa4 := (*RawSockaddrInet4)(unsafe.Pointer(&b[0]))
+				sa := new(SockaddrInet4)
+				for j := 0; rsa4.Len > 0 && j < int(rsa4.Len)-int(unsafe.Offsetof(rsa4.Addr)); j++ {
+					sa.Addr[j] = rsa4.Addr[j]
+				}
+				sas[i] = sa
+			case AF_INET6:
+				rsa6 := (*RawSockaddrInet6)(unsafe.Pointer(&b[0]))
+				sa := new(SockaddrInet6)
+				for j := 0; rsa6.Len > 0 && j < int(rsa6.Len)-int(unsafe.Offsetof(rsa6.Addr)); j++ {
+					sa.Addr[j] = rsa6.Addr[j]
+				}
+				sas[i] = sa
 			}
-			sas[i] = sa
-			b = b[rsaAlignOf(int(b[0])):]
 		}
+		b = b[rsaAlignOf(int(rsa.Len)):]
 	}
-	return sas[:], nil
+	return sas[:]
 }
 
 // InterfaceMessage represents a routing message containing
@@ -254,17 +121,15 @@ type InterfaceMessage struct {
 	Data   []byte
 }
 
-func (m *InterfaceMessage) sockaddr() ([]Sockaddr, error) {
-	var sas [RTAX_MAX]Sockaddr
+func (m *InterfaceMessage) sockaddr() (sas []Sockaddr) {
 	if m.Header.Addrs&RTA_IFP == 0 {
-		return nil, nil
+		return nil
 	}
-	sa, err := parseSockaddrLink(m.Data[:])
+	sa, err := anyToSockaddr((*RawSockaddrAny)(unsafe.Pointer(&m.Data[0])))
 	if err != nil {
-		return nil, err
+		return nil
 	}
-	sas[RTAX_IFP] = sa
-	return sas[:], nil
+	return append(sas, sa)
 }
 
 // InterfaceAddrMessage represents a routing message containing
@@ -274,63 +139,79 @@ type InterfaceAddrMessage struct {
 	Data   []byte
 }
 
-func (m *InterfaceAddrMessage) sockaddr() ([]Sockaddr, error) {
-	var sas [RTAX_MAX]Sockaddr
+const rtaIfaMask = RTA_IFA | RTA_NETMASK | RTA_BRD
+
+func (m *InterfaceAddrMessage) sockaddr() (sas []Sockaddr) {
+	if m.Header.Addrs&rtaIfaMask == 0 {
+		return nil
+	}
 	b := m.Data[:]
-	family := uint8(AF_UNSPEC)
-	for i := uint(0); i < RTAX_MAX && len(b) >= minRoutingSockaddrLen; i++ {
+	// We still see AF_UNSPEC in socket addresses on some
+	// platforms. To identify each address family correctly, we
+	// will use the address family of RTAX_NETMASK as a preferred
+	// one on the 32-bit NetBSD kernel, also use the length of
+	// RTAX_NETMASK socket address on the FreeBSD kernel.
+	preferredFamily := uint8(AF_UNSPEC)
+	for i := uint(0); i < RTAX_MAX; i++ {
 		if m.Header.Addrs&(1<<i) == 0 {
 			continue
 		}
 		rsa := (*RawSockaddr)(unsafe.Pointer(&b[0]))
-		switch rsa.Family {
-		case AF_LINK:
-			sa, err := parseSockaddrLink(b)
-			if err != nil {
-				return nil, err
+		switch i {
+		case RTAX_IFA:
+			if rsa.Family == AF_UNSPEC {
+				rsa.Family = preferredFamily
 			}
-			sas[i] = sa
-			b = b[rsaAlignOf(int(rsa.Len)):]
-		case AF_INET, AF_INET6:
-			sa, err := parseSockaddrInet(b, rsa.Family)
+			sa, err := anyToSockaddr((*RawSockaddrAny)(unsafe.Pointer(rsa)))
 			if err != nil {
-				return nil, err
+				return nil
 			}
-			sas[i] = sa
-			b = b[rsaAlignOf(int(rsa.Len)):]
-			family = rsa.Family
-		default:
-			sa, err := parseNetworkLayerAddr(b, family)
+			sas = append(sas, sa)
+		case RTAX_NETMASK:
+			switch rsa.Family {
+			case AF_UNSPEC:
+				switch rsa.Len {
+				case SizeofSockaddrInet4:
+					rsa.Family = AF_INET
+				case SizeofSockaddrInet6:
+					rsa.Family = AF_INET6
+				default:
+					rsa.Family = AF_INET // an old fashion, AF_UNSPEC means AF_INET
+				}
+			case AF_INET, AF_INET6:
+				preferredFamily = rsa.Family
+			default:
+				return nil
+			}
+			sa, err := anyToSockaddr((*RawSockaddrAny)(unsafe.Pointer(rsa)))
 			if err != nil {
-				return nil, err
+				return nil
 			}
-			sas[i] = sa
-			b = b[rsaAlignOf(int(b[0])):]
+			sas = append(sas, sa)
+		case RTAX_BRD:
+			// nothing to do
 		}
+		b = b[rsaAlignOf(int(rsa.Len)):]
 	}
-	return sas[:], nil
+	return sas
 }
 
 // ParseRoutingMessage parses b as routing messages and returns the
 // slice containing the RoutingMessage interfaces.
 func ParseRoutingMessage(b []byte) (msgs []RoutingMessage, err error) {
-	nmsgs, nskips := 0, 0
+	msgCount := 0
 	for len(b) >= anyMessageLen {
-		nmsgs++
+		msgCount++
 		any := (*anyMessage)(unsafe.Pointer(&b[0]))
 		if any.Version != RTM_VERSION {
 			b = b[any.Msglen:]
 			continue
 		}
-		if m := any.toRoutingMessage(b); m == nil {
-			nskips++
-		} else {
-			msgs = append(msgs, m)
-		}
+		msgs = append(msgs, any.toRoutingMessage(b))
 		b = b[any.Msglen:]
 	}
 	// We failed to parse any of the messages - version mismatch?
-	if nmsgs != len(msgs)+nskips {
+	if msgCount > 0 && len(msgs) == 0 {
 		return nil, EINVAL
 	}
 	return msgs, nil
@@ -338,10 +219,6 @@ func ParseRoutingMessage(b []byte) (msgs []RoutingMessage, err error) {
 
 // ParseRoutingMessage parses msg's payload as raw sockaddrs and
 // returns the slice containing the Sockaddr interfaces.
-func ParseRoutingSockaddr(msg RoutingMessage) ([]Sockaddr, error) {
-	sas, err := msg.sockaddr()
-	if err != nil {
-		return nil, err
-	}
-	return sas, nil
+func ParseRoutingSockaddr(msg RoutingMessage) (sas []Sockaddr, err error) {
+	return append(sas, msg.sockaddr()...), nil
 }
diff --git a/src/syscall/route_darwin.go b/src/syscall/route_darwin.go
index 89bca12..ad27907 100644
--- a/src/syscall/route_darwin.go
+++ b/src/syscall/route_darwin.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.
 
+// Routing sockets and messages for Darwin
+
 package syscall
 
 import "unsafe"
@@ -31,37 +33,29 @@ type InterfaceMulticastAddrMessage struct {
 	Data   []byte
 }
 
-func (m *InterfaceMulticastAddrMessage) sockaddr() ([]Sockaddr, error) {
-	var sas [RTAX_MAX]Sockaddr
+const rtaIfmaMask = RTA_GATEWAY | RTA_IFP | RTA_IFA
+
+func (m *InterfaceMulticastAddrMessage) sockaddr() (sas []Sockaddr) {
+	if m.Header.Addrs&rtaIfmaMask == 0 {
+		return nil
+	}
 	b := m.Data[:]
-	for i := uint(0); i < RTAX_MAX && len(b) >= minRoutingSockaddrLen; i++ {
-		if m.Header.Addrs&(1<<i) == 0 {
+	for i := uint(0); i < RTAX_MAX; i++ {
+		if m.Header.Addrs&rtaIfmaMask&(1<<i) == 0 {
 			continue
 		}
 		rsa := (*RawSockaddr)(unsafe.Pointer(&b[0]))
-		switch rsa.Family {
-		case AF_LINK:
-			sa, err := parseSockaddrLink(b)
-			if err != nil {
-				return nil, err
-			}
-			sas[i] = sa
-			b = b[rsaAlignOf(int(rsa.Len)):]
-		case AF_INET, AF_INET6:
-			sa, err := parseSockaddrInet(b, rsa.Family)
-			if err != nil {
-				return nil, err
-			}
-			sas[i] = sa
-			b = b[rsaAlignOf(int(rsa.Len)):]
-		default:
-			sa, l, err := parseLinkLayerAddr(b)
-			if err != nil {
-				return nil, err
+		switch i {
+		case RTAX_IFA:
+			sa, e := anyToSockaddr((*RawSockaddrAny)(unsafe.Pointer(rsa)))
+			if e != nil {
+				return nil
 			}
-			sas[i] = sa
-			b = b[l:]
+			sas = append(sas, sa)
+		case RTAX_GATEWAY, RTAX_IFP:
+			// nothing to do
 		}
+		b = b[rsaAlignOf(int(rsa.Len)):]
 	}
-	return sas[:], nil
+	return sas
 }
diff --git a/src/syscall/route_dragonfly.go b/src/syscall/route_dragonfly.go
index 5226f7f..79190d2 100644
--- a/src/syscall/route_dragonfly.go
+++ b/src/syscall/route_dragonfly.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.
 
+// Routing sockets and messages for Dragonfly
+
 package syscall
 
 import "unsafe"
@@ -10,8 +12,6 @@ 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))
-		// We don't support sockaddr_mpls for now.
-		p.Header.Addrs &= RTA_DST | RTA_GATEWAY | RTA_NETMASK | RTA_GENMASK | RTA_IFA | RTA_IFP | RTA_BRD | RTA_AUTHOR
 		return &RouteMessage{Header: p.Header, Data: b[SizeofRtMsghdr:any.Msglen]}
 	case RTM_IFINFO:
 		p := (*InterfaceMessage)(unsafe.Pointer(any))
@@ -35,7 +35,7 @@ type InterfaceAnnounceMessage struct {
 	Header IfAnnounceMsghdr
 }
 
-func (m *InterfaceAnnounceMessage) sockaddr() ([]Sockaddr, error) { return nil, nil }
+func (m *InterfaceAnnounceMessage) sockaddr() (sas []Sockaddr) { return nil }
 
 // InterfaceMulticastAddrMessage represents a routing message
 // containing network interface address entries.
@@ -44,37 +44,29 @@ type InterfaceMulticastAddrMessage struct {
 	Data   []byte
 }
 
-func (m *InterfaceMulticastAddrMessage) sockaddr() ([]Sockaddr, error) {
-	var sas [RTAX_MAX]Sockaddr
+const rtaIfmaMask = RTA_GATEWAY | RTA_IFP | RTA_IFA
+
+func (m *InterfaceMulticastAddrMessage) sockaddr() (sas []Sockaddr) {
+	if m.Header.Addrs&rtaIfmaMask == 0 {
+		return nil
+	}
 	b := m.Data[:]
-	for i := uint(0); i < RTAX_MAX && len(b) >= minRoutingSockaddrLen; i++ {
-		if m.Header.Addrs&(1<<i) == 0 {
+	for i := uint(0); i < RTAX_MAX; i++ {
+		if m.Header.Addrs&rtaIfmaMask&(1<<i) == 0 {
 			continue
 		}
 		rsa := (*RawSockaddr)(unsafe.Pointer(&b[0]))
-		switch rsa.Family {
-		case AF_LINK:
-			sa, err := parseSockaddrLink(b)
-			if err != nil {
-				return nil, err
-			}
-			sas[i] = sa
-			b = b[rsaAlignOf(int(rsa.Len)):]
-		case AF_INET, AF_INET6:
-			sa, err := parseSockaddrInet(b, rsa.Family)
-			if err != nil {
-				return nil, err
-			}
-			sas[i] = sa
-			b = b[rsaAlignOf(int(rsa.Len)):]
-		default:
-			sa, l, err := parseLinkLayerAddr(b)
-			if err != nil {
-				return nil, err
+		switch i {
+		case RTAX_IFA:
+			sa, e := anyToSockaddr((*RawSockaddrAny)(unsafe.Pointer(rsa)))
+			if e != nil {
+				return nil
 			}
-			sas[i] = sa
-			b = b[l:]
+			sas = append(sas, sa)
+		case RTAX_GATEWAY, RTAX_IFP:
+			// nothing to do
 		}
+		b = b[rsaAlignOf(int(rsa.Len)):]
 	}
-	return sas[:], nil
+	return sas
 }
diff --git a/src/syscall/route_freebsd.go b/src/syscall/route_freebsd.go
index 0e18103..15897b1 100644
--- a/src/syscall/route_freebsd.go
+++ b/src/syscall/route_freebsd.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.
 
+// Routing sockets and messages for FreeBSD
+
 package syscall
 
 import "unsafe"
@@ -11,31 +13,13 @@ var freebsdVersion uint32
 
 func init() {
 	freebsdVersion, _ = SysctlUint32("kern.osreldate")
-	conf, _ := Sysctl("kern.conftxt")
-	for i, j := 0, 0; j < len(conf); j++ {
-		if conf[j] != '\n' {
-			continue
-		}
-		s := conf[i:j]
-		i = j + 1
-		if len(s) > len("machine") && s[:len("machine")] == "machine" {
-			s = s[len("machine"):]
-			for k := 0; k < len(s); k++ {
-				if s[k] == ' ' || s[k] == '\t' {
-					s = s[1:]
-				}
-				break
-			}
-			freebsdConfArch = s
-			break
-		}
-	}
 }
 
 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:
-		return any.parseRouteMessage(b)
+		p := (*RouteMessage)(unsafe.Pointer(any))
+		return &RouteMessage{Header: p.Header, Data: b[SizeofRtMsghdr:any.Msglen]}
 	case RTM_IFINFO:
 		return any.parseInterfaceMessage(b)
 	case RTM_IFANNOUNCE:
@@ -57,7 +41,7 @@ type InterfaceAnnounceMessage struct {
 	Header IfAnnounceMsghdr
 }
 
-func (m *InterfaceAnnounceMessage) sockaddr() ([]Sockaddr, error) { return nil, nil }
+func (m *InterfaceAnnounceMessage) sockaddr() (sas []Sockaddr) { return nil }
 
 // InterfaceMulticastAddrMessage represents a routing message
 // containing network interface address entries.
@@ -66,37 +50,29 @@ type InterfaceMulticastAddrMessage struct {
 	Data   []byte
 }
 
-func (m *InterfaceMulticastAddrMessage) sockaddr() ([]Sockaddr, error) {
-	var sas [RTAX_MAX]Sockaddr
+const rtaIfmaMask = RTA_GATEWAY | RTA_IFP | RTA_IFA
+
+func (m *InterfaceMulticastAddrMessage) sockaddr() (sas []Sockaddr) {
+	if m.Header.Addrs&rtaIfmaMask == 0 {
+		return nil
+	}
 	b := m.Data[:]
-	for i := uint(0); i < RTAX_MAX && len(b) >= minRoutingSockaddrLen; i++ {
-		if m.Header.Addrs&(1<<i) == 0 {
+	for i := uint(0); i < RTAX_MAX; i++ {
+		if m.Header.Addrs&rtaIfmaMask&(1<<i) == 0 {
 			continue
 		}
 		rsa := (*RawSockaddr)(unsafe.Pointer(&b[0]))
-		switch rsa.Family {
-		case AF_LINK:
-			sa, err := parseSockaddrLink(b)
-			if err != nil {
-				return nil, err
-			}
-			sas[i] = sa
-			b = b[rsaAlignOf(int(rsa.Len)):]
-		case AF_INET, AF_INET6:
-			sa, err := parseSockaddrInet(b, rsa.Family)
-			if err != nil {
-				return nil, err
-			}
-			sas[i] = sa
-			b = b[rsaAlignOf(int(rsa.Len)):]
-		default:
-			sa, l, err := parseLinkLayerAddr(b)
-			if err != nil {
-				return nil, err
+		switch i {
+		case RTAX_IFA:
+			sa, e := anyToSockaddr((*RawSockaddrAny)(unsafe.Pointer(rsa)))
+			if e != nil {
+				return nil
 			}
-			sas[i] = sa
-			b = b[l:]
+			sas = append(sas, sa)
+		case RTAX_GATEWAY, RTAX_IFP:
+			// nothing to do
 		}
+		b = b[rsaAlignOf(int(rsa.Len)):]
 	}
-	return sas[:], nil
+	return sas
 }
diff --git a/src/syscall/route_freebsd_32bit.go b/src/syscall/route_freebsd_32bit.go
index 5c10b05..93efddd 100644
--- a/src/syscall/route_freebsd_32bit.go
+++ b/src/syscall/route_freebsd_32bit.go
@@ -8,15 +8,6 @@ package syscall
 
 import "unsafe"
 
-func (any *anyMessage) parseRouteMessage(b []byte) *RouteMessage {
-	p := (*RouteMessage)(unsafe.Pointer(any))
-	off := int(unsafe.Offsetof(p.Header.Rmx)) + SizeofRtMetrics
-	if freebsdConfArch == "amd64" {
-		off += SizeofRtMetrics // rt_metrics on amd64 is simply doubled
-	}
-	return &RouteMessage{Header: p.Header, Data: b[rsaAlignOf(off):any.Msglen]}
-}
-
 func (any *anyMessage) parseInterfaceMessage(b []byte) *InterfaceMessage {
 	p := (*InterfaceMessage)(unsafe.Pointer(any))
 	// FreeBSD 10 and beyond have a restructured mbuf
@@ -27,7 +18,7 @@ func (any *anyMessage) parseInterfaceMessage(b []byte) *InterfaceMessage {
 		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[int(unsafe.Offsetof(p.Header.Data))+int(p.Header.Data.Datalen) : any.Msglen]}
+		return &InterfaceMessage{Header: p.Header, Data: b[sizeofIfMsghdr:any.Msglen]}
 	}
-	return &InterfaceMessage{Header: p.Header, Data: b[int(unsafe.Offsetof(p.Header.Data))+int(p.Header.Data.Datalen) : any.Msglen]}
+	return &InterfaceMessage{Header: p.Header, Data: b[SizeofIfMsghdr:any.Msglen]}
 }
diff --git a/src/syscall/route_freebsd_64bit.go b/src/syscall/route_freebsd_64bit.go
index 728837e..9377f2f 100644
--- a/src/syscall/route_freebsd_64bit.go
+++ b/src/syscall/route_freebsd_64bit.go
@@ -8,12 +8,7 @@ package syscall
 
 import "unsafe"
 
-func (any *anyMessage) parseRouteMessage(b []byte) *RouteMessage {
-	p := (*RouteMessage)(unsafe.Pointer(any))
-	return &RouteMessage{Header: p.Header, Data: b[rsaAlignOf(int(unsafe.Offsetof(p.Header.Rmx))+SizeofRtMetrics):any.Msglen]}
-}
-
 func (any *anyMessage) parseInterfaceMessage(b []byte) *InterfaceMessage {
 	p := (*InterfaceMessage)(unsafe.Pointer(any))
-	return &InterfaceMessage{Header: p.Header, Data: b[int(unsafe.Offsetof(p.Header.Data))+int(p.Header.Data.Datalen) : any.Msglen]}
+	return &InterfaceMessage{Header: p.Header, Data: b[SizeofIfMsghdr:any.Msglen]}
 }
diff --git a/src/syscall/route_netbsd.go b/src/syscall/route_netbsd.go
index d605ffa..9883aeb 100644
--- a/src/syscall/route_netbsd.go
+++ b/src/syscall/route_netbsd.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.
 
+// Routing sockets and messages for NetBSD
+
 package syscall
 
 import "unsafe"
@@ -10,8 +12,6 @@ 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))
-		// We don't support sockaddr_mpls for now.
-		p.Header.Addrs &= RTA_DST | RTA_GATEWAY | RTA_NETMASK | RTA_GENMASK | RTA_IFA | RTA_IFP | RTA_BRD | RTA_AUTHOR
 		return &RouteMessage{Header: p.Header, Data: b[SizeofRtMsghdr:any.Msglen]}
 	case RTM_IFINFO:
 		p := (*InterfaceMessage)(unsafe.Pointer(any))
@@ -32,4 +32,4 @@ type InterfaceAnnounceMessage struct {
 	Header IfAnnounceMsghdr
 }
 
-func (m *InterfaceAnnounceMessage) sockaddr() ([]Sockaddr, error) { return nil, nil }
+func (m *InterfaceAnnounceMessage) sockaddr() (sas []Sockaddr) { return nil }
diff --git a/src/syscall/route_openbsd.go b/src/syscall/route_openbsd.go
index 7804a08..e508640 100644
--- a/src/syscall/route_openbsd.go
+++ b/src/syscall/route_openbsd.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.
 
+// Routing sockets and messages for OpenBSD
+
 package syscall
 
 import "unsafe"
@@ -10,8 +12,6 @@ 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))
-		// We don't support sockaddr_rtlabel for now.
-		p.Header.Addrs &= RTA_DST | RTA_GATEWAY | RTA_NETMASK | RTA_GENMASK | RTA_IFA | RTA_IFP | RTA_BRD | RTA_AUTHOR | RTA_SRC | RTA_SRCMASK
 		return &RouteMessage{Header: p.Header, Data: b[p.Header.Hdrlen:any.Msglen]}
 	case RTM_IFINFO:
 		p := (*InterfaceMessage)(unsafe.Pointer(any))
@@ -32,4 +32,4 @@ type InterfaceAnnounceMessage struct {
 	Header IfAnnounceMsghdr
 }
 
-func (m *InterfaceAnnounceMessage) sockaddr() ([]Sockaddr, error) { return nil, nil }
+func (m *InterfaceAnnounceMessage) sockaddr() (sas []Sockaddr) { return nil }
diff --git a/src/syscall/security_windows.go b/src/syscall/security_windows.go
index 1625b07..b22ecf5 100644
--- a/src/syscall/security_windows.go
+++ b/src/syscall/security_windows.go
@@ -41,20 +41,21 @@ func TranslateAccountName(username string, from, to uint32, initSize int) (strin
 	if e != nil {
 		return "", e
 	}
-	n := uint32(50)
-	for {
-		b := make([]uint16, n)
-		e = TranslateName(u, from, to, &b[0], &n)
-		if e == nil {
-			return UTF16ToString(b[:n]), nil
-		}
+	b := make([]uint16, 50)
+	n := uint32(len(b))
+	e = TranslateName(u, from, to, &b[0], &n)
+	if e != nil {
 		if e != ERROR_INSUFFICIENT_BUFFER {
 			return "", e
 		}
-		if n <= uint32(len(b)) {
+		// make receive buffers of requested size and try again
+		b = make([]uint16, n)
+		e = TranslateName(u, from, to, &b[0], &n)
+		if e != nil {
 			return "", e
 		}
 	}
+	return UTF16ToString(b), nil
 }
 
 const (
@@ -135,23 +136,26 @@ func LookupSID(system, account string) (sid *SID, domain string, accType uint32,
 			return nil, "", 0, e
 		}
 	}
-	n := uint32(50)
-	dn := uint32(50)
-	for {
-		b := make([]byte, n)
-		db := make([]uint16, dn)
-		sid = (*SID)(unsafe.Pointer(&b[0]))
-		e = LookupAccountName(sys, acc, sid, &n, &db[0], &dn, &accType)
-		if e == nil {
-			return sid, UTF16ToString(db), accType, nil
-		}
+	db := make([]uint16, 50)
+	dn := uint32(len(db))
+	b := make([]byte, 50)
+	n := uint32(len(b))
+	sid = (*SID)(unsafe.Pointer(&b[0]))
+	e = LookupAccountName(sys, acc, sid, &n, &db[0], &dn, &accType)
+	if e != nil {
 		if e != ERROR_INSUFFICIENT_BUFFER {
 			return nil, "", 0, e
 		}
-		if n <= uint32(len(b)) {
+		// make receive buffers of requested size and try again
+		b = make([]byte, n)
+		sid = (*SID)(unsafe.Pointer(&b[0]))
+		db = make([]uint16, dn)
+		e = LookupAccountName(sys, acc, sid, &n, &db[0], &dn, &accType)
+		if e != nil {
 			return nil, "", 0, e
 		}
 	}
+	return sid, UTF16ToString(db), accType, nil
 }
 
 // String converts sid to a string format
@@ -193,22 +197,24 @@ func (sid *SID) LookupAccount(system string) (account, domain string, accType ui
 			return "", "", 0, err
 		}
 	}
-	n := uint32(50)
-	dn := uint32(50)
-	for {
-		b := make([]uint16, n)
-		db := make([]uint16, dn)
-		e := LookupAccountSid(sys, sid, &b[0], &n, &db[0], &dn, &accType)
-		if e == nil {
-			return UTF16ToString(b), UTF16ToString(db), accType, nil
-		}
+	b := make([]uint16, 50)
+	n := uint32(len(b))
+	db := make([]uint16, 50)
+	dn := uint32(len(db))
+	e := LookupAccountSid(sys, sid, &b[0], &n, &db[0], &dn, &accType)
+	if e != nil {
 		if e != ERROR_INSUFFICIENT_BUFFER {
 			return "", "", 0, e
 		}
-		if n <= uint32(len(b)) {
+		// make receive buffers of requested size and try again
+		b = make([]uint16, n)
+		db = make([]uint16, dn)
+		e = LookupAccountSid(nil, sid, &b[0], &n, &db[0], &dn, &accType)
+		if e != nil {
 			return "", "", 0, e
 		}
 	}
+	return UTF16ToString(b), UTF16ToString(db), accType, nil
 }
 
 const (
@@ -320,20 +326,21 @@ func (t Token) Close() error {
 
 // getInfo retrieves a specified type of information about an access token.
 func (t Token) getInfo(class uint32, initSize int) (unsafe.Pointer, error) {
-	n := uint32(initSize)
-	for {
-		b := make([]byte, n)
-		e := GetTokenInformation(t, class, &b[0], uint32(len(b)), &n)
-		if e == nil {
-			return unsafe.Pointer(&b[0]), nil
-		}
+	b := make([]byte, initSize)
+	var n uint32
+	e := GetTokenInformation(t, class, &b[0], uint32(len(b)), &n)
+	if e != nil {
 		if e != ERROR_INSUFFICIENT_BUFFER {
 			return nil, e
 		}
-		if n <= uint32(len(b)) {
+		// make receive buffers of requested size and try again
+		b = make([]byte, n)
+		e = GetTokenInformation(t, class, &b[0], uint32(len(b)), &n)
+		if e != nil {
 			return nil, e
 		}
 	}
+	return unsafe.Pointer(&b[0]), nil
 }
 
 // GetTokenUser retrieves access token t user account information.
@@ -359,18 +366,19 @@ func (t Token) GetTokenPrimaryGroup() (*Tokenprimarygroup, error) {
 // GetUserProfileDirectory retrieves path to the
 // root directory of the access token t user's profile.
 func (t Token) GetUserProfileDirectory() (string, error) {
-	n := uint32(100)
-	for {
-		b := make([]uint16, n)
-		e := GetUserProfileDirectory(t, &b[0], &n)
-		if e == nil {
-			return UTF16ToString(b), nil
-		}
+	b := make([]uint16, 100)
+	n := uint32(len(b))
+	e := GetUserProfileDirectory(t, &b[0], &n)
+	if e != nil {
 		if e != ERROR_INSUFFICIENT_BUFFER {
 			return "", e
 		}
-		if n <= uint32(len(b)) {
+		// make receive buffers of requested size and try again
+		b = make([]uint16, n)
+		e = GetUserProfileDirectory(t, &b[0], &n)
+		if e != nil {
 			return "", e
 		}
 	}
+	return UTF16ToString(b), nil
 }
diff --git a/src/syscall/so_solaris.go b/src/syscall/so_solaris.go
new file mode 100644
index 0000000..8b1980f
--- /dev/null
+++ b/src/syscall/so_solaris.go
@@ -0,0 +1,262 @@
+// 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 asm_solaris_amd64.s.
+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
+	use(unsafe.Pointer(namep))
+	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)
+	use(unsafe.Pointer(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/syscall/syscall.go b/src/syscall/syscall.go
index 791bcbb..1f209ec 100644
--- a/src/syscall/syscall.go
+++ b/src/syscall/syscall.go
@@ -20,7 +20,7 @@
 //
 // NOTE: This package is locked down. Code outside the standard
 // Go repository should be migrated to use the corresponding
-// package in the golang.org/x/sys repository. That is also where updates
+// package in the go.sys subrepository. That is also where updates
 // required by new systems or versions should be applied.
 // See https://golang.org/s/go1.4-syscall for more information.
 //
@@ -28,11 +28,9 @@ package syscall
 
 import "unsafe"
 
-// StringByteSlice converts a string to a NUL-terminated []byte,
+// StringByteSlice is deprecated. Use ByteSliceFromString instead.
 // If s contains a NUL byte this function panics instead of
 // returning an error.
-//
-// Deprecated: Use ByteSliceFromString instead.
 func StringByteSlice(s string) []byte {
 	a, err := ByteSliceFromString(s)
 	if err != nil {
@@ -55,11 +53,9 @@ func ByteSliceFromString(s string) ([]byte, error) {
 	return a, nil
 }
 
-// StringBytePtr returns a pointer to a NUL-terminated array of bytes.
-// If s contains a NUL byte this function panics instead of returning
-// an error.
-//
-// Deprecated: Use BytePtrFromString instead.
+// StringBytePtr is deprecated. Use BytePtrFromString instead.
+// If s contains a NUL byte this function panics instead of
+// returning an error.
 func StringBytePtr(s string) *byte { return &StringByteSlice(s)[0] }
 
 // BytePtrFromString returns a pointer to a NUL-terminated array of
diff --git a/src/syscall/syscall_bsd.go b/src/syscall/syscall_bsd.go
index af56391..2556fa8 100644
--- a/src/syscall/syscall_bsd.go
+++ b/src/syscall/syscall_bsd.go
@@ -68,7 +68,40 @@ func ReadDirent(fd int, buf []byte) (n int, err error) {
 	// actual system call is getdirentries64, 64 is a good guess.
 	// TODO(rsc): Can we use a single global basep for all calls?
 	var base = (*uintptr)(unsafe.Pointer(new(uint64)))
-	return Getdirentries(fd, buf, base)
+	n, err = Getdirentries(fd, buf, base)
+
+	// On OS X 10.10 Yosemite, if you have a directory that can be returned
+	// in a single getdirentries64 call (for example, a directory with one file),
+	// and you read from the directory at EOF twice, you get EOF both times:
+	//	fd = open("dir")
+	//	getdirentries64(fd) // returns data
+	//	getdirentries64(fd) // returns 0 (EOF)
+	//	getdirentries64(fd) // returns 0 (EOF)
+	//
+	// But if you remove the file in the middle between the two calls, the
+	// second call returns an error instead.
+	//	fd = open("dir")
+	//	getdirentries64(fd) // returns data
+	//	getdirentries64(fd) // returns 0 (EOF)
+	//	remove("dir/file")
+	//	getdirentries64(fd) // returns ENOENT/EINVAL
+	//
+	// Whether you get ENOENT or EINVAL depends on exactly what was
+	// in the directory. It is deterministic, just data-dependent.
+	//
+	// This only happens in small directories. A directory containing more data
+	// than fits in a 4k getdirentries64 call will return EOF correctly.
+	// (It's not clear if the criteria is that the directory be split across multiple
+	// getdirentries64 calls or that it be split across multiple file system blocks.)
+	//
+	// We could change package os to avoid the second read at EOF,
+	// and maybe we should, but that's a bit involved.
+	// For now, treat the EINVAL/ENOENT as EOF.
+	if runtime.GOOS == "darwin" && (err == EINVAL || err == ENOENT) {
+		err = nil
+	}
+
+	return
 }
 
 // Wait status is 7 bits at bottom, either 0 (exited),
diff --git a/src/syscall/syscall_darwin.go b/src/syscall/syscall_darwin.go
index 52fd4e7..f026a56 100644
--- a/src/syscall/syscall_darwin.go
+++ b/src/syscall/syscall_darwin.go
@@ -222,8 +222,8 @@ func Kill(pid int, signum Signal) (err error) { return kill(pid, int(signum), 1)
 //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	Dup2(from int, to int) (err error)
+//sysnb	Dup(fd int) (nfd int, err error)
+//sysnb	Dup2(from int, to int) (err error)
 //sys	Exchangedata(path1 string, path2 string, options int) (err error)
 //sys	Exit(code int)
 //sys	Fchdir(fd int) (err error)
diff --git a/src/syscall/syscall_darwin_amd64.go b/src/syscall/syscall_darwin_amd64.go
index 70b53b8..81b1fd3 100644
--- a/src/syscall/syscall_darwin_amd64.go
+++ b/src/syscall/syscall_darwin_amd64.go
@@ -67,4 +67,4 @@ func sendfile(outfd int, infd int, offset *int64, count int) (written int, err e
 	return
 }
 
-func Syscall9(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno)
+func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno) // sic
diff --git a/src/syscall/syscall_dragonfly.go b/src/syscall/syscall_dragonfly.go
index c25963c..39c51df 100644
--- a/src/syscall/syscall_dragonfly.go
+++ b/src/syscall/syscall_dragonfly.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.
 
-// DragonflyBSD system calls.
+// FreeBSD 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.
@@ -127,8 +127,8 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, 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	Dup2(from int, to int) (err error)
+//sysnb	Dup(fd int) (nfd int, err error)
+//sysnb	Dup2(from int, to int) (err error)
 //sys	Exit(code int)
 //sys	Fchdir(fd int) (err error)
 //sys	Fchflags(fd int, flags int) (err error)
diff --git a/src/syscall/syscall_dragonfly_386.go b/src/syscall/syscall_dragonfly_386.go
new file mode 100644
index 0000000..ebd3d4c
--- /dev/null
+++ b/src/syscall/syscall_dragonfly_386.go
@@ -0,0 +1,58 @@
+// 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
+
+import "unsafe"
+
+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.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 = int32(nsec / 1e9)
+	return
+}
+
+func SetKevent(k *Kevent_t, fd, mode, flags int) {
+	k.Ident = uint32(fd)
+	k.Filter = int16(mode)
+	k.Flags = uint16(flags)
+}
+
+func (iov *Iovec) SetLen(length int) {
+	iov.Len = uint32(length)
+}
+
+func (msghdr *Msghdr) SetControllen(length int) {
+	msghdr.Controllen = uint32(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) {
+	var writtenOut uint64 = 0
+	_, _, e1 := Syscall9(SYS_SENDFILE, uintptr(infd), uintptr(outfd), uintptr(*offset), uintptr((*offset)>>32), uintptr(count), 0, uintptr(unsafe.Pointer(&writtenOut)), 0, 0)
+
+	written = int(writtenOut)
+
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+func Syscall9(num, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno) // sic
diff --git a/src/syscall/syscall_freebsd.go b/src/syscall/syscall_freebsd.go
index 257d419..3d834f5 100644
--- a/src/syscall/syscall_freebsd.go
+++ b/src/syscall/syscall_freebsd.go
@@ -147,8 +147,8 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, 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	Dup2(from int, to int) (err error)
+//sysnb	Dup(fd int) (nfd int, err error)
+//sysnb	Dup2(from int, to int) (err error)
 //sys	Exit(code int)
 //sys	Fchdir(fd int) (err error)
 //sys	Fchflags(fd int, flags int) (err error)
diff --git a/src/syscall/syscall_linux.go b/src/syscall/syscall_linux.go
index 4f88d51..c40c718 100644
--- a/src/syscall/syscall_linux.go
+++ b/src/syscall/syscall_linux.go
@@ -17,38 +17,10 @@ import "unsafe"
  * Wrapped
  */
 
-func Access(path string, mode uint32) (err error) {
-	return Faccessat(_AT_FDCWD, path, mode, 0)
-}
-
-func Chmod(path string, mode uint32) (err error) {
-	return Fchmodat(_AT_FDCWD, path, mode, 0)
-}
-
-func Chown(path string, uid int, gid int) (err error) {
-	return Fchownat(_AT_FDCWD, path, uid, gid, 0)
-}
-
-func Creat(path string, mode uint32) (fd int, err error) {
-	return Open(path, O_CREAT|O_WRONLY|O_TRUNC, mode)
-}
-
-//sys	linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags int) (err error)
-
-func Link(oldpath string, newpath string) (err error) {
-	return linkat(_AT_FDCWD, oldpath, _AT_FDCWD, newpath, 0)
-}
-
-func Mkdir(path string, mode uint32) (err error) {
-	return Mkdirat(_AT_FDCWD, path, mode)
-}
-
-func Mknod(path string, mode uint32, dev int) (err error) {
-	return Mknodat(_AT_FDCWD, path, mode, dev)
-}
+//sys	open(path string, mode int, perm uint32) (fd int, err error)
 
 func Open(path string, mode int, perm uint32) (fd int, err error) {
-	return openat(_AT_FDCWD, path, mode|O_LARGEFILE, perm)
+	return open(path, mode|O_LARGEFILE, perm)
 }
 
 //sys	openat(dirfd int, path string, flags int, mode uint32) (fd int, err error)
@@ -57,34 +29,30 @@ func Openat(dirfd int, path string, flags int, mode uint32) (fd int, err error)
 	return openat(dirfd, path, flags|O_LARGEFILE, mode)
 }
 
-//sys	readlinkat(dirfd int, path string, buf []byte) (n int, err error)
-
-func Readlink(path string, buf []byte) (n int, err error) {
-	return readlinkat(_AT_FDCWD, path, buf)
-}
+//sysnb	pipe(p *[2]_C_int) (err error)
 
-func Rename(oldpath string, newpath string) (err error) {
-	return Renameat(_AT_FDCWD, oldpath, _AT_FDCWD, newpath)
-}
-
-func Rmdir(path string) error {
-	return unlinkat(_AT_FDCWD, path, _AT_REMOVEDIR)
-}
-
-//sys	symlinkat(oldpath string, newdirfd int, newpath string) (err error)
-
-func Symlink(oldpath string, newpath string) (err error) {
-	return symlinkat(oldpath, _AT_FDCWD, newpath)
-}
-
-func Unlink(path string) error {
-	return unlinkat(_AT_FDCWD, path, 0)
+func Pipe(p []int) (err error) {
+	if len(p) != 2 {
+		return EINVAL
+	}
+	var pp [2]_C_int
+	err = pipe(&pp)
+	p[0] = int(pp[0])
+	p[1] = int(pp[1])
+	return
 }
 
-//sys	unlinkat(dirfd int, path string, flags int) (err error)
+//sysnb pipe2(p *[2]_C_int, flags int) (err error)
 
-func Unlinkat(dirfd int, path string) error {
-	return unlinkat(dirfd, path, 0)
+func Pipe2(p []int, flags int) (err error) {
+	if len(p) != 2 {
+		return EINVAL
+	}
+	var pp [2]_C_int
+	err = pipe2(&pp, flags)
+	p[0] = int(pp[0])
+	p[1] = int(pp[1])
+	return
 }
 
 //sys	utimes(path string, times *[2]Timeval) (err error)
@@ -815,13 +783,17 @@ func Mount(source string, target string, fstype string, flags uintptr, data stri
 /*
  * Direct access
  */
+//sys	Access(path string, mode uint32) (err error)
 //sys	Acct(path string) (err error)
 //sys	Adjtimex(buf *Timex) (state int, err error)
 //sys	Chdir(path string) (err error)
+//sys	Chmod(path string, mode uint32) (err error)
 //sys	Chroot(path string) (err error)
 //sys	Close(fd int) (err error)
-//sys	Dup(oldfd int) (fd int, err error)
-//sys	Dup3(oldfd int, newfd int, flags int) (err error)
+//sys	Creat(path string, mode uint32) (fd int, err error)
+//sysnb	Dup(oldfd int) (fd int, err error)
+//sysnb	Dup2(oldfd int, newfd int) (err error)
+//sysnb	Dup3(oldfd int, newfd int, flags int) (err error)
 //sysnb	EpollCreate(size int) (fd int, err error)
 //sysnb	EpollCreate1(flag int) (fd int, err error)
 //sysnb	EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error)
@@ -839,12 +811,7 @@ func Mount(source string, target string, fstype string, flags uintptr, data stri
 //sys	Fsync(fd int) (err error)
 //sys	Getdents(fd int, buf []byte) (n int, err error) = SYS_GETDENTS64
 //sysnb	Getpgid(pid int) (pgid int, err error)
-
-func Getpgrp() (pid int) {
-	pid, _ = Getpgid(0)
-	return
-}
-
+//sysnb	Getpgrp() (pid int)
 //sysnb	Getpid() (pid int)
 //sysnb	Getppid() (ppid int)
 //sys	Getpriority(which int, who int) (prio int, err error)
@@ -852,20 +819,27 @@ func Getpgrp() (pid int) {
 //sysnb	Gettid() (tid int)
 //sys	Getxattr(path string, attr string, dest []byte) (sz int, err error)
 //sys	InotifyAddWatch(fd int, pathname string, mask uint32) (watchdesc int, err error)
+//sysnb	InotifyInit() (fd int, err error)
 //sysnb	InotifyInit1(flags int) (fd int, err error)
 //sysnb	InotifyRmWatch(fd int, watchdesc uint32) (success int, err error)
 //sysnb	Kill(pid int, sig Signal) (err error)
 //sys	Klogctl(typ int, buf []byte) (n int, err error) = SYS_SYSLOG
+//sys	Link(oldpath string, newpath string) (err error)
 //sys	Listxattr(path string, dest []byte) (sz int, err error)
+//sys	Mkdir(path string, mode uint32) (err error)
 //sys	Mkdirat(dirfd int, path string, mode uint32) (err error)
+//sys	Mknod(path string, mode uint32, dev int) (err error)
 //sys	Mknodat(dirfd int, path string, mode uint32, dev int) (err error)
 //sys	Nanosleep(time *Timespec, leftover *Timespec) (err error)
 //sys	Pause() (err error)
 //sys	PivotRoot(newroot string, putold string) (err error) = SYS_PIVOT_ROOT
 //sysnb prlimit(pid int, resource int, old *Rlimit, newlimit *Rlimit) (err error) = SYS_PRLIMIT64
 //sys	read(fd int, p []byte) (n int, err error)
+//sys	Readlink(path string, buf []byte) (n int, err error)
 //sys	Removexattr(path string, attr string) (err error)
+//sys	Rename(oldpath string, newpath string) (err error)
 //sys	Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error)
+//sys	Rmdir(path string) (err error)
 //sys	Setdomainname(p []byte) (err error)
 //sys	Sethostname(p []byte) (err error)
 //sysnb	Setpgid(pid int, pgid int) (err error)
@@ -887,6 +861,7 @@ func Setgid(uid int) (err error) {
 
 //sys	Setpriority(which int, who int, prio int) (err error)
 //sys	Setxattr(path string, attr string, data []byte, flags int) (err error)
+//sys	Symlink(oldpath string, newpath string) (err error)
 //sys	Sync()
 //sysnb	Sysinfo(info *Sysinfo_t) (err error)
 //sys	Tee(rfd int, wfd int, len int, flags int) (n int64, err error)
@@ -894,6 +869,8 @@ func Setgid(uid int) (err error) {
 //sysnb	Times(tms *Tms) (ticks uintptr, err error)
 //sysnb	Umask(mask int) (oldmask int)
 //sysnb	Uname(buf *Utsname) (err error)
+//sys	Unlink(path string) (err error)
+//sys	Unlinkat(dirfd int, path string) (err error)
 //sys	Unmount(target string, flags int) (err error) = SYS_UMOUNT2
 //sys	Unshare(flags int) (err error)
 //sys	Ustat(dev int, ubuf *Ustat_t) (err error)
diff --git a/src/syscall/syscall_linux_386.go b/src/syscall/syscall_linux_386.go
index 9ee1c1c..8278750 100644
--- a/src/syscall/syscall_linux_386.go
+++ b/src/syscall/syscall_linux_386.go
@@ -9,8 +9,6 @@ package syscall
 
 import "unsafe"
 
-const _SYS_dup = SYS_DUP2
-
 func Getpagesize() int { return 4096 }
 
 func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
@@ -30,35 +28,9 @@ func NsecToTimeval(nsec int64) (tv Timeval) {
 	return
 }
 
-//sysnb	pipe(p *[2]_C_int) (err error)
-
-func Pipe(p []int) (err error) {
-	if len(p) != 2 {
-		return EINVAL
-	}
-	var pp [2]_C_int
-	err = pipe(&pp)
-	p[0] = int(pp[0])
-	p[1] = int(pp[1])
-	return
-}
-
-//sysnb pipe2(p *[2]_C_int, flags int) (err error)
-
-func Pipe2(p []int, flags int) (err error) {
-	if len(p) != 2 {
-		return EINVAL
-	}
-	var pp [2]_C_int
-	err = pipe2(&pp, flags)
-	p[0] = int(pp[0])
-	p[1] = int(pp[1])
-	return
-}
-
 // 64-bit file system and 32-bit uid calls
 // (386 default is 32-bit file system and 16-bit uid).
-//sys	Dup2(oldfd int, newfd int) (err error)
+//sys	Chown(path string, uid int, gid int) (err error) = SYS_CHOWN32
 //sys	Fchown(fd int, uid int, gid int) (err error) = SYS_FCHOWN32
 //sys	Fstat(fd int, stat *Stat_t) (err error) = SYS_FSTAT64
 //sys	Ftruncate(fd int, length int64) (err error) = SYS_FTRUNCATE64
@@ -66,7 +38,6 @@ func Pipe2(p []int, flags int) (err error) {
 //sysnb	Geteuid() (euid int) = SYS_GETEUID32
 //sysnb	Getgid() (gid int) = SYS_GETGID32
 //sysnb	Getuid() (uid int) = SYS_GETUID32
-//sysnb	InotifyInit() (fd int, err error)
 //sys	Ioperm(from int, num int, on int) (err error)
 //sys	Iopl(level int) (err error)
 //sys	Lchown(path string, uid int, gid int) (err error) = SYS_LCHOWN32
diff --git a/src/syscall/syscall_linux_amd64.go b/src/syscall/syscall_linux_amd64.go
index 6fbef21..74a89fb 100644
--- a/src/syscall/syscall_linux_amd64.go
+++ b/src/syscall/syscall_linux_amd64.go
@@ -4,9 +4,7 @@
 
 package syscall
 
-const _SYS_dup = SYS_DUP2
-
-//sys	Dup2(oldfd int, newfd int) (err error)
+//sys	Chown(path string, uid int, gid int) (err error)
 //sys	Fchown(fd int, uid int, gid int) (err error)
 //sys	Fstat(fd int, stat *Stat_t) (err error)
 //sys	Fstatfs(fd int, buf *Statfs_t) (err error)
@@ -16,7 +14,6 @@ const _SYS_dup = SYS_DUP2
 //sysnb	Getgid() (gid int)
 //sysnb	Getrlimit(resource int, rlim *Rlimit) (err error)
 //sysnb	Getuid() (uid int)
-//sysnb	InotifyInit() (fd int, err error)
 //sys	Ioperm(from int, num int, on int) (err error)
 //sys	Iopl(level int) (err error)
 //sys	Lchown(path string, uid int, gid int) (err error)
@@ -58,6 +55,8 @@ const _SYS_dup = SYS_DUP2
 //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 }
+
 //go:noescape
 func gettimeofday(tv *Timeval) (err Errno)
 
@@ -69,8 +68,6 @@ func Gettimeofday(tv *Timeval) (err error) {
 	return nil
 }
 
-func Getpagesize() int { return 4096 }
-
 func Time(t *Time_t) (tt Time_t, err error) {
 	var tv Timeval
 	errno := gettimeofday(&tv)
@@ -100,32 +97,6 @@ func NsecToTimeval(nsec int64) (tv Timeval) {
 	return
 }
 
-//sysnb	pipe(p *[2]_C_int) (err error)
-
-func Pipe(p []int) (err error) {
-	if len(p) != 2 {
-		return EINVAL
-	}
-	var pp [2]_C_int
-	err = pipe(&pp)
-	p[0] = int(pp[0])
-	p[1] = int(pp[1])
-	return
-}
-
-//sysnb pipe2(p *[2]_C_int, flags int) (err error)
-
-func Pipe2(p []int, flags int) (err error) {
-	if len(p) != 2 {
-		return EINVAL
-	}
-	var pp [2]_C_int
-	err = pipe2(&pp, flags)
-	p[0] = int(pp[0])
-	p[1] = int(pp[1])
-	return
-}
-
 func (r *PtraceRegs) PC() uint64 { return r.Rip }
 
 func (r *PtraceRegs) SetPC(pc uint64) { r.Rip = pc }
diff --git a/src/syscall/syscall_linux_arm.go b/src/syscall/syscall_linux_arm.go
index 218d6b8..b127345 100644
--- a/src/syscall/syscall_linux_arm.go
+++ b/src/syscall/syscall_linux_arm.go
@@ -6,8 +6,6 @@ package syscall
 
 import "unsafe"
 
-const _SYS_dup = SYS_DUP2
-
 func Getpagesize() int { return 4096 }
 
 func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
@@ -25,30 +23,6 @@ func NsecToTimeval(nsec int64) (tv Timeval) {
 	return
 }
 
-func Pipe(p []int) (err error) {
-	if len(p) != 2 {
-		return EINVAL
-	}
-	var pp [2]_C_int
-	err = pipe2(&pp, 0)
-	p[0] = int(pp[0])
-	p[1] = int(pp[1])
-	return
-}
-
-//sysnb pipe2(p *[2]_C_int, flags int) (err error)
-
-func Pipe2(p []int, flags int) (err error) {
-	if len(p) != 2 {
-		return EINVAL
-	}
-	var pp [2]_C_int
-	err = pipe2(&pp, flags)
-	p[0] = int(pp[0])
-	p[1] = int(pp[1])
-	return
-}
-
 // 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)
@@ -80,14 +54,13 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
 
 // 64-bit file system and 32-bit uid calls
 // (16-bit uid calls are not always supported in newer kernels)
-//sys	Dup2(oldfd int, newfd int) (err error)
+//sys	Chown(path string, uid int, gid int) (err error) = SYS_CHOWN32
 //sys	Fchown(fd int, uid int, gid int) (err error) = SYS_FCHOWN32
 //sys	Fstat(fd int, stat *Stat_t) (err error) = SYS_FSTAT64
 //sysnb	Getegid() (egid int) = SYS_GETEGID32
 //sysnb	Geteuid() (euid int) = SYS_GETEUID32
 //sysnb	Getgid() (gid int) = SYS_GETGID32
 //sysnb	Getuid() (uid int) = SYS_GETUID32
-//sysnb	InotifyInit() (fd int, err error)
 //sys	Lchown(path string, uid int, gid int) (err error) = SYS_LCHOWN32
 //sys	Listen(s int, n int) (err error)
 //sys	Lstat(path string, stat *Stat_t) (err error) = SYS_LSTAT64
diff --git a/src/syscall/syscall_nacl.go b/src/syscall/syscall_nacl.go
index f8f63ef..c2788b2 100644
--- a/src/syscall/syscall_nacl.go
+++ b/src/syscall/syscall_nacl.go
@@ -14,7 +14,6 @@ import (
 //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
-//sys	naclGetRandomBytes(b []byte) (err error) = sys_get_random_bytes
 
 const direntSize = 8 + 8 + 2 + 256
 
diff --git a/src/syscall/syscall_netbsd.go b/src/syscall/syscall_netbsd.go
index 7fd6e2b..9781271 100644
--- a/src/syscall/syscall_netbsd.go
+++ b/src/syscall/syscall_netbsd.go
@@ -148,8 +148,8 @@ func sendfile(outfd int, infd int, offset *int64, count int) (written int, err e
 //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	Dup2(from int, to int) (err error)
+//sysnb	Dup(fd int) (nfd int, err error)
+//sysnb	Dup2(from int, to int) (err error)
 //sys	Exit(code int)
 //sys	Fchdir(fd int) (err error)
 //sys	Fchflags(fd int, flags int) (err error)
diff --git a/src/syscall/syscall_openbsd.go b/src/syscall/syscall_openbsd.go
index e196e59..8d3f825 100644
--- a/src/syscall/syscall_openbsd.go
+++ b/src/syscall/syscall_openbsd.go
@@ -126,8 +126,8 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, 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	Dup2(from int, to int) (err error)
+//sysnb	Dup(fd int) (nfd int, err error)
+//sysnb	Dup2(from int, to int) (err error)
 //sys	Exit(code int)
 //sys	Fchdir(fd int) (err error)
 //sys	Fchflags(fd int, flags int) (err error)
diff --git a/src/syscall/syscall_plan9.go b/src/syscall/syscall_plan9.go
index 7968708..618e02c 100644
--- a/src/syscall/syscall_plan9.go
+++ b/src/syscall/syscall_plan9.go
@@ -129,6 +129,17 @@ func Write(fd int, p []byte) (n int, err error) {
 
 var ioSync int64
 
+func Getwd() (wd string, err error) {
+	fd, e := Open(".", O_RDONLY)
+
+	if e != nil {
+		return "", e
+	}
+	defer Close(fd)
+
+	return Fd2path(fd)
+}
+
 //sys	fd2path(fd int, buf []byte) (err error)
 func Fd2path(fd int) (path string, err error) {
 	var buf [512]byte
@@ -140,12 +151,12 @@ func Fd2path(fd int) (path string, err error) {
 	return cstring(buf[:]), nil
 }
 
-//sys	pipe(p *[2]int32) (err error)
+//sys	pipe(p *[2]_C_int) (err error)
 func Pipe(p []int) (err error) {
 	if len(p) != 2 {
 		return NewError("bad arg in system call")
 	}
-	var pp [2]int32
+	var pp [2]_C_int
 	err = pipe(&pp)
 	p[0] = int(pp[0])
 	p[1] = int(pp[1])
@@ -231,7 +242,6 @@ func Await(w *Waitmsg) (err error) {
 }
 
 func Unmount(name, old string) (err error) {
-	Fixwd()
 	oldp, err := BytePtrFromString(old)
 	if err != nil {
 		return err
@@ -315,52 +325,17 @@ func Getgroups() (gids []int, err error) {
 	return make([]int, 0), nil
 }
 
-//sys	open(path string, mode int) (fd int, err error)
-func Open(path string, mode int) (fd int, err error) {
-	Fixwd()
-	return open(path, mode)
-}
-
-//sys	create(path string, mode int, perm uint32) (fd int, err error)
-func Create(path string, mode int, perm uint32) (fd int, err error) {
-	Fixwd()
-	return create(path, mode, perm)
-}
-
-//sys	remove(path string) (err error)
-func Remove(path string) error {
-	Fixwd()
-	return remove(path)
-}
-
-//sys	stat(path string, edir []byte) (n int, err error)
-func Stat(path string, edir []byte) (n int, err error) {
-	Fixwd()
-	return stat(path, edir)
-}
-
-//sys	bind(name string, old string, flag int) (err error)
-func Bind(name string, old string, flag int) (err error) {
-	Fixwd()
-	return bind(name, old, flag)
-}
-
-//sys	mount(fd int, afd int, old string, flag int, aname string) (err error)
-func Mount(fd int, afd int, old string, flag int, aname string) (err error) {
-	Fixwd()
-	return mount(fd, afd, old, flag, aname)
-}
-
-//sys	wstat(path string, edir []byte) (err error)
-func Wstat(path string, edir []byte) (err error) {
-	Fixwd()
-	return wstat(path, edir)
-}
-
-//sys	chdir(path string) (err error)
 //sys	Dup(oldfd int, newfd int) (fd int, err error)
+//sys	Open(path string, mode int) (fd int, err error)
+//sys	Create(path string, mode int, perm uint32) (fd int, err error)
+//sys	Remove(path string) (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	Close(fd int) (err error)
+//sys	Chdir(path string) (err error)
+//sys	Bind(name string, old string, flag int) (err error)
+//sys	Mount(fd int, afd int, old string, flag int, aname string) (err error)
+//sys	Stat(path string, edir []byte) (n int, err error)
 //sys	Fstat(fd int, edir []byte) (n int, err error)
+//sys	Wstat(path string, edir []byte) (err error)
 //sys	Fwstat(fd int, edir []byte) (err error)
diff --git a/src/syscall/syscall_solaris.go b/src/syscall/syscall_solaris.go
index 0f60e21..adc52b1 100644
--- a/src/syscall/syscall_solaris.go
+++ b/src/syscall/syscall_solaris.go
@@ -14,10 +14,6 @@ package syscall
 
 import "unsafe"
 
-// Implemented in asm_solaris_amd64.s.
-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)
-
 type SockaddrDatalink struct {
 	Family uint16
 	Index  uint16
@@ -287,7 +283,7 @@ func UtimesNano(path string, ts []Timespec) (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(uintptr(unsafe.Pointer(&libc_fcntl)), 3, uintptr(fd), uintptr(cmd), uintptr(unsafe.Pointer(lk)), 0, 0, 0)
+	_, _, e1 := sysvicall6(procfcntl.Addr(), 3, uintptr(fd), uintptr(cmd), uintptr(unsafe.Pointer(lk)), 0, 0, 0)
 	if e1 != 0 {
 		return e1
 	}
@@ -473,7 +469,6 @@ func SendmsgN(fd int, p, oob []byte, to Sockaddr, flags int) (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
-//sys	sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) = libsendfile.sendfile
 //sysnb	Setegid(egid int) (err error)
 //sysnb	Seteuid(euid int) (err error)
 //sysnb	Setgid(gid int) (err error)
@@ -510,7 +505,7 @@ func SendmsgN(fd int, p, oob []byte, to Sockaddr, flags int) (n int, err error)
 //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(uintptr(unsafe.Pointer(&libc_read)), 3, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf), 0, 0, 0)
+	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
@@ -519,7 +514,7 @@ func readlen(fd int, buf *byte, nbuf int) (n int, err error) {
 }
 
 func writelen(fd int, buf *byte, nbuf int) (n int, err error) {
-	r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_write)), 3, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf), 0, 0, 0)
+	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
diff --git a/src/syscall/syscall_solaris_amd64.go b/src/syscall/syscall_solaris_amd64.go
index 67b8af1..37cf06d 100644
--- a/src/syscall/syscall_solaris_amd64.go
+++ b/src/syscall/syscall_solaris_amd64.go
@@ -30,3 +30,8 @@ func (iov *Iovec) SetLen(length int) {
 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/syscall/syscall_unix.go b/src/syscall/syscall_unix.go
index b133ea7..a06bd7d 100644
--- a/src/syscall/syscall_unix.go
+++ b/src/syscall/syscall_unix.go
@@ -116,30 +116,6 @@ func (e Errno) Timeout() bool {
 	return e == EAGAIN || e == EWOULDBLOCK || e == ETIMEDOUT
 }
 
-// Do the interface allocations only once for common
-// Errno values.
-var (
-	errEAGAIN error = EAGAIN
-	errEINVAL error = EINVAL
-	errENOENT error = ENOENT
-)
-
-// errnoErr returns common boxed Errno values, to prevent
-// allocations at runtime.
-func errnoErr(e Errno) error {
-	switch e {
-	case 0:
-		return nil
-	case EAGAIN:
-		return errEAGAIN
-	case EINVAL:
-		return errEINVAL
-	case ENOENT:
-		return errENOENT
-	}
-	return e
-}
-
 // A Signal is a number describing a process signal.
 // It implements the os.Signal interface.
 type Signal int
diff --git a/src/syscall/syscall_unix_test.go b/src/syscall/syscall_unix_test.go
index c7b4560..a0afb91 100644
--- a/src/syscall/syscall_unix_test.go
+++ b/src/syscall/syscall_unix_test.go
@@ -9,7 +9,6 @@ package syscall_test
 import (
 	"flag"
 	"fmt"
-	"internal/testenv"
 	"io/ioutil"
 	"net"
 	"os"
@@ -61,58 +60,20 @@ func _() {
 
 // TestFcntlFlock tests whether the file locking structure matches
 // the calling convention of each kernel.
-// On some Linux systems, glibc uses another set of values for the
-// commands and translates them to the correct value that the kernel
-// expects just before the actual fcntl syscall. As Go uses raw
-// syscalls directly, it must use the real value, not the glibc value.
-// Thus this test also verifies that the Flock_t structure can be
-// roundtripped with F_SETLK and F_GETLK.
 func TestFcntlFlock(t *testing.T) {
-	if runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64") {
-		t.Skip("skipping; no child processes allowed on iOS")
+	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_WRLCK,
-		Start: 31415, Len: 271828, Whence: 1,
+		Type:  syscall.F_RDLCK,
+		Start: 0, Len: 0, Whence: 1,
 	}
-	if os.Getenv("GO_WANT_HELPER_PROCESS") == "" {
-		// parent
-		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)
-		if err := syscall.Ftruncate(fd, 1<<20); err != nil {
-			t.Fatalf("Ftruncate(1<<20) failed: %v", err)
-		}
-		if err := syscall.FcntlFlock(uintptr(fd), syscall.F_SETLK, &flock); err != nil {
-			t.Fatalf("FcntlFlock(F_SETLK) failed: %v", err)
-		}
-		cmd := exec.Command(os.Args[0], "-test.run=^TestFcntlFlock$")
-		cmd.Env = append(os.Environ(), "GO_WANT_HELPER_PROCESS=1")
-		cmd.ExtraFiles = []*os.File{os.NewFile(uintptr(fd), name)}
-		out, err := cmd.CombinedOutput()
-		if len(out) > 0 || err != nil {
-			t.Fatalf("child process: %q, %v", out, err)
-		}
-	} else {
-		// child
-		got := flock
-		// make sure the child lock is conflicting with the parent lock
-		got.Start--
-		got.Len++
-		if err := syscall.FcntlFlock(3, syscall.F_GETLK, &got); err != nil {
-			t.Fatalf("FcntlFlock(F_GETLK) failed: %v", err)
-		}
-		flock.Pid = int32(syscall.Getppid())
-		// Linux kernel always set Whence to 0
-		flock.Whence = 0
-		if got.Type == flock.Type && got.Start == flock.Start && got.Len == flock.Len && got.Pid == flock.Pid && got.Whence == flock.Whence {
-			os.Exit(0)
-		}
-		t.Fatalf("FcntlFlock got %v, want %v", got, flock)
+	if err := syscall.FcntlFlock(uintptr(fd), syscall.F_GETLK, &flock); err != nil {
+		t.Fatalf("FcntlFlock failed: %v", err)
 	}
 }
 
@@ -132,9 +93,6 @@ func TestPassFD(t *testing.T) {
 		// TODO(aram): Figure out why ReadMsgUnix is returning empty message.
 		t.Skip("skipping test on solaris, see issue 7402")
 	}
-
-	testenv.MustHaveExec(t)
-
 	if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" {
 		passFDChild()
 		return
@@ -158,7 +116,7 @@ func TestPassFD(t *testing.T) {
 	defer readFile.Close()
 
 	cmd := exec.Command(os.Args[0], "-test.run=^TestPassFD$", "--", tempDir)
-	cmd.Env = append(os.Environ(), "GO_WANT_HELPER_PROCESS=1")
+	cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"}
 	cmd.ExtraFiles = []*os.File{writeFile}
 
 	out, err := cmd.CombinedOutput()
@@ -217,7 +175,7 @@ func passFDChild() {
 	defer os.Exit(0)
 
 	// Look for our fd. It should be fd 3, but we work around an fd leak
-	// bug here (https://golang.org/issue/2603) to let it be elsewhere.
+	// 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")
diff --git a/src/syscall/syscall_windows.go b/src/syscall/syscall_windows.go
index 1006a9b..e89fd09 100644
--- a/src/syscall/syscall_windows.go
+++ b/src/syscall/syscall_windows.go
@@ -13,17 +13,13 @@ import (
 	"unsafe"
 )
 
-//go:generate go run mksyscall_windows.go -output zsyscall_windows.go syscall_windows.go security_windows.go
-
 type Handle uintptr
 
 const InvalidHandle = ^Handle(0)
 
-// StringToUTF16 returns the UTF-16 encoding of the UTF-8 string s,
-// with a terminating NUL added. If s contains a NUL byte this
-// function panics instead of returning an error.
-//
-// Deprecated: Use UTF16FromString instead.
+// StringToUTF16 is deprecated. Use UTF16FromString instead.
+// If s contains a NUL byte this function panics instead of
+// returning an error.
 func StringToUTF16(s string) []uint16 {
 	a, err := UTF16FromString(s)
 	if err != nil {
@@ -56,12 +52,9 @@ func UTF16ToString(s []uint16) string {
 	return string(utf16.Decode(s))
 }
 
-// StringToUTF16Ptr returns pointer to the UTF-16 encoding of
-// the UTF-8 string s, with a terminating NUL added. If s
+// StringToUTF16Ptr is deprecated. Use UTF16PtrFromString instead.
 // If s contains a NUL byte this function panics instead of
 // returning an error.
-//
-// Deprecated: Use UTF16PtrFromString instead.
 func StringToUTF16Ptr(s string) *uint16 { return &StringToUTF16(s)[0] }
 
 // UTF16PtrFromString returns pointer to the UTF-16 encoding of
@@ -82,14 +75,6 @@ type Errno uintptr
 
 func langid(pri, sub uint16) uint32 { return uint32(sub)<<10 | uint32(pri) }
 
-// FormatMessage is deprecated (msgsrc should be uintptr, not uint32, but can
-// not be changed due to the Go 1 compatibility guarantee).
-//
-// Deprecated: Use FormatMessage from golang.org/x/sys/windows instead.
-func FormatMessage(flags uint32, msgsrc uint32, msgid uint32, langid uint32, buf []uint16, args *byte) (n uint32, err error) {
-	return formatMessage(flags, uintptr(msgsrc), msgid, langid, buf, args)
-}
-
 func (e Errno) Error() string {
 	// deal with special go errors
 	idx := int(e - APPLICATION_ERROR)
@@ -99,9 +84,9 @@ func (e Errno) Error() string {
 	// ask windows for the remaining errors
 	var flags uint32 = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY | FORMAT_MESSAGE_IGNORE_INSERTS
 	b := make([]uint16, 300)
-	n, err := formatMessage(flags, 0, uint32(e), langid(LANG_ENGLISH, SUBLANG_ENGLISH_US), b, nil)
+	n, err := FormatMessage(flags, 0, uint32(e), langid(LANG_ENGLISH, SUBLANG_ENGLISH_US), b, nil)
 	if err != nil {
-		n, err = formatMessage(flags, 0, uint32(e), 0, b, nil)
+		n, err = FormatMessage(flags, 0, uint32(e), 0, b, nil)
 		if err != nil {
 			return "winapi error #" + itoa(int(e))
 		}
@@ -120,7 +105,7 @@ func (e Errno) Timeout() bool {
 	return e == EAGAIN || e == EWOULDBLOCK || e == ETIMEDOUT
 }
 
-// Implemented in runtime/syscall_windows.go.
+// Implemented in asm_windows.s
 func compileCallback(fn interface{}, cleanstack bool) uintptr
 
 // Converts a Go function to a function pointer conforming
@@ -144,7 +129,7 @@ func NewCallbackCDecl(fn interface{}) uintptr {
 //sys	FreeLibrary(handle Handle) (err error)
 //sys	GetProcAddress(module Handle, procname string) (proc uintptr, err error)
 //sys	GetVersion() (ver uint32, err error)
-//sys	formatMessage(flags uint32, msgsrc uintptr, msgid uint32, langid uint32, buf []uint16, args *byte) (n uint32, err error) = FormatMessageW
+//sys	FormatMessage(flags uint32, msgsrc uint32, msgid uint32, langid uint32, buf []uint16, args *byte) (n uint32, err error) = FormatMessageW
 //sys	ExitProcess(exitcode uint32)
 //sys	CreateFile(name *uint16, access uint32, mode uint32, sa *SecurityAttributes, createmode uint32, attrs uint32, templatefile int32) (handle Handle, err error) [failretval==InvalidHandle] = CreateFileW
 //sys	ReadFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped) (err error)
@@ -1016,22 +1001,13 @@ func Readlink(path string, buf []byte) (n int, err error) {
 	}
 
 	rdb := (*reparseDataBuffer)(unsafe.Pointer(&rdbbuf[0]))
-	var s string
-	switch rdb.ReparseTag {
-	case IO_REPARSE_TAG_SYMLINK:
-		data := (*symbolicLinkReparseBuffer)(unsafe.Pointer(&rdb.reparseBuffer))
-		p := (*[0xffff]uint16)(unsafe.Pointer(&data.PathBuffer[0]))
-		s = UTF16ToString(p[data.PrintNameOffset/2 : (data.PrintNameLength-data.PrintNameOffset)/2])
-	case _IO_REPARSE_TAG_MOUNT_POINT:
-		data := (*mountPointReparseBuffer)(unsafe.Pointer(&rdb.reparseBuffer))
-		p := (*[0xffff]uint16)(unsafe.Pointer(&data.PathBuffer[0]))
-		s = UTF16ToString(p[data.PrintNameOffset/2 : (data.PrintNameLength-data.PrintNameOffset)/2])
-	default:
-		// the path is not a symlink or junction but another type of reparse
-		// point
+	if uintptr(bytesReturned) < unsafe.Sizeof(*rdb) ||
+		rdb.ReparseTag != IO_REPARSE_TAG_SYMLINK {
+		// the path is not a symlink but another type of reparse point
 		return -1, ENOENT
 	}
-	n = copy(buf, []byte(s))
 
+	s := UTF16ToString((*[0xffff]uint16)(unsafe.Pointer(&rdb.PathBuffer[0]))[:rdb.PrintNameLength/2])
+	n = copy(buf, []byte(s))
 	return n, nil
 }
diff --git a/src/syscall/tables_nacl.go b/src/syscall/tables_nacl.go
index adc6be2..08f4ced 100644
--- a/src/syscall/tables_nacl.go
+++ b/src/syscall/tables_nacl.go
@@ -15,10 +15,10 @@ const (
 	sys_read                 = 12
 	sys_write                = 13
 	sys_lseek                = 14
+	sys_ioctl                = 15
 	sys_stat                 = 16
 	sys_fstat                = 17
 	sys_chmod                = 18
-	sys_isatty               = 19
 	sys_brk                  = 20
 	sys_mmap                 = 21
 	sys_munmap               = 22
@@ -76,19 +76,6 @@ const (
 	sys_test_crash           = 110
 	sys_test_syscall_1       = 111
 	sys_test_syscall_2       = 112
-	sys_futex_wait_abs       = 120
-	sys_futex_wake           = 121
-	sys_pread                = 130
-	sys_pwrite               = 131
-	sys_truncate             = 140
-	sys_lstat                = 141
-	sys_link                 = 142
-	sys_rename               = 143
-	sys_symlink              = 144
-	sys_access               = 145
-	sys_readlink             = 146
-	sys_utimes               = 147
-	sys_get_random_bytes     = 150
 )
 
 // TODO: Auto-generate some day. (Hard-coded in binaries so not likely to change.)
@@ -335,27 +322,3 @@ var errorstr = [...]string{
 	ENOSHARE:        "No such host or network path",
 	ECASECLASH:      "Filename exists with different case",
 }
-
-// Do the interface allocations only once for common
-// Errno values.
-var (
-	errEAGAIN error = EAGAIN
-	errEINVAL error = EINVAL
-	errENOENT error = ENOENT
-)
-
-// errnoErr returns common boxed Errno values, to prevent
-// allocations at runtime.
-func errnoErr(e Errno) error {
-	switch e {
-	case 0:
-		return nil
-	case EAGAIN:
-		return errEAGAIN
-	case EINVAL:
-		return errEINVAL
-	case ENOENT:
-		return errENOENT
-	}
-	return e
-}
diff --git a/src/syscall/types_linux.go b/src/syscall/types_linux.go
index 0ebdc7c..e8396a4 100644
--- a/src/syscall/types_linux.go
+++ b/src/syscall/types_linux.go
@@ -77,8 +77,8 @@ struct sockaddr_any {
 // copied from /usr/include/linux/un.h
 struct my_sockaddr_un {
 	sa_family_t sun_family;
-#if defined(__ARM_EABI__) || defined(__powerpc64__)
-	// on ARM and PPC char is by default unsigned
+#ifdef __ARM_EABI__
+	// on ARM char is by default unsigned
 	signed char sun_path[108];
 #else
 	char sun_path[108];
@@ -87,10 +87,6 @@ struct my_sockaddr_un {
 
 #ifdef __ARM_EABI__
 typedef struct user_regs PtraceRegs;
-#elif defined(__aarch64__)
-typedef struct user_pt_regs PtraceRegs;
-#elif defined(__powerpc64__)
-typedef struct pt_regs PtraceRegs;
 #else
 typedef struct user_regs_struct PtraceRegs;
 #endif
@@ -378,9 +374,7 @@ type Ustat_t C.struct_ustat
 type EpollEvent C.struct_my_epoll_event
 
 const (
-	_AT_FDCWD            = C.AT_FDCWD
-	_AT_REMOVEDIR        = C.AT_REMOVEDIR
-	_AT_SYMLINK_NOFOLLOW = C.AT_SYMLINK_NOFOLLOW
+	_AT_FDCWD = C.AT_FDCWD
 )
 
 // Terminal handling
@@ -388,9 +382,103 @@ const (
 type Termios C.struct_termios
 
 const (
-	IUCLC  = C.IUCLC
-	OLCUC  = C.OLCUC
-	TCGETS = C.TCGETS
-	TCSETS = C.TCSETS
-	XCASE  = C.XCASE
+	VINTR    = C.VINTR
+	VQUIT    = C.VQUIT
+	VERASE   = C.VERASE
+	VKILL    = C.VKILL
+	VEOF     = C.VEOF
+	VTIME    = C.VTIME
+	VMIN     = C.VMIN
+	VSWTC    = C.VSWTC
+	VSTART   = C.VSTART
+	VSTOP    = C.VSTOP
+	VSUSP    = C.VSUSP
+	VEOL     = C.VEOL
+	VREPRINT = C.VREPRINT
+	VDISCARD = C.VDISCARD
+	VWERASE  = C.VWERASE
+	VLNEXT   = C.VLNEXT
+	VEOL2    = C.VEOL2
+	IGNBRK   = C.IGNBRK
+	BRKINT   = C.BRKINT
+	IGNPAR   = C.IGNPAR
+	PARMRK   = C.PARMRK
+	INPCK    = C.INPCK
+	ISTRIP   = C.ISTRIP
+	INLCR    = C.INLCR
+	IGNCR    = C.IGNCR
+	ICRNL    = C.ICRNL
+	IUCLC    = C.IUCLC
+	IXON     = C.IXON
+	IXANY    = C.IXANY
+	IXOFF    = C.IXOFF
+	IMAXBEL  = C.IMAXBEL
+	IUTF8    = C.IUTF8
+	OPOST    = C.OPOST
+	OLCUC    = C.OLCUC
+	ONLCR    = C.ONLCR
+	OCRNL    = C.OCRNL
+	ONOCR    = C.ONOCR
+	ONLRET   = C.ONLRET
+	OFILL    = C.OFILL
+	OFDEL    = C.OFDEL
+	B0       = C.B0
+	B50      = C.B50
+	B75      = C.B75
+	B110     = C.B110
+	B134     = C.B134
+	B150     = C.B150
+	B200     = C.B200
+	B300     = C.B300
+	B600     = C.B600
+	B1200    = C.B1200
+	B1800    = C.B1800
+	B2400    = C.B2400
+	B4800    = C.B4800
+	B9600    = C.B9600
+	B19200   = C.B19200
+	B38400   = C.B38400
+	CSIZE    = C.CSIZE
+	CS5      = C.CS5
+	CS6      = C.CS6
+	CS7      = C.CS7
+	CS8      = C.CS8
+	CSTOPB   = C.CSTOPB
+	CREAD    = C.CREAD
+	PARENB   = C.PARENB
+	PARODD   = C.PARODD
+	HUPCL    = C.HUPCL
+	CLOCAL   = C.CLOCAL
+	B57600   = C.B57600
+	B115200  = C.B115200
+	B230400  = C.B230400
+	B460800  = C.B460800
+	B500000  = C.B500000
+	B576000  = C.B576000
+	B921600  = C.B921600
+	B1000000 = C.B1000000
+	B1152000 = C.B1152000
+	B1500000 = C.B1500000
+	B2000000 = C.B2000000
+	B2500000 = C.B2500000
+	B3000000 = C.B3000000
+	B3500000 = C.B3500000
+	B4000000 = C.B4000000
+	ISIG     = C.ISIG
+	ICANON   = C.ICANON
+	XCASE    = C.XCASE
+	ECHO     = C.ECHO
+	ECHOE    = C.ECHOE
+	ECHOK    = C.ECHOK
+	ECHONL   = C.ECHONL
+	NOFLSH   = C.NOFLSH
+	TOSTOP   = C.TOSTOP
+	ECHOCTL  = C.ECHOCTL
+	ECHOPRT  = C.ECHOPRT
+	ECHOKE   = C.ECHOKE
+	FLUSHO   = C.FLUSHO
+	PENDIN   = C.PENDIN
+	IEXTEN   = C.IEXTEN
+	TCGETS   = C.TCGETS
+	TCSETS   = C.TCSETS
 )
diff --git a/src/syscall/types_plan9.c b/src/syscall/types_plan9.c
new file mode 100644
index 0000000..cd9e15f
--- /dev/null
+++ b/src/syscall/types_plan9.c
@@ -0,0 +1,115 @@
+// 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 godefs.  See also mkerrors.sh and mkall.sh
+*/
+
+typedef unsigned short ushort;
+typedef unsigned char uchar;
+typedef unsigned long ulong;
+typedef unsigned int uint;
+typedef long long vlong;
+typedef unsigned long long uvlong;
+
+typedef int $_C_int;
+
+enum {
+	OREAD	= 0,	// open for read
+	OWRITE	= 1,	// write
+	ORDWR	= 2,	// read and write
+	OEXEC	= 3,	// execute, == read but check execute permission
+	OTRUNC	= 16,	// or'ed in (except for exec), truncate file first
+	OCEXEC	= 32,	// or'ed in, close on exec
+	ORCLOSE	= 64,		// or'ed in, remove on close
+	OEXCL	= 0x1000,	// or'ed in, exclusive use (create only)
+
+	$O_RDONLY	= OREAD,
+	$O_WRONLY	= OWRITE,
+	$O_RDWR		= ORDWR,
+	$O_TRUNC	= OTRUNC,
+	$O_CLOEXEC	= OCEXEC,
+	$O_EXCL		= OEXCL,
+
+	$STATMAX	= 65535U,
+	$ERRMAX		= 128,
+
+	$MORDER		= 0x0003,	// mask for bits defining order of mounting
+	$MREPL		= 0x0000,	// mount replaces object
+	$MBEFORE	= 0x0001,	// mount goes before others in union directory
+	$MAFTER		= 0x0002,	// mount goes after others in union directory
+	$MCREATE	= 0x0004,	// permit creation in mounted directory
+	$MCACHE		= 0x0010,	// cache some data
+	$MMASK		= 0x0017,	// all bits on
+
+	$RFNAMEG	= (1<<0),
+	$RFENVG		= (1<<1),
+	$RFFDG		= (1<<2),
+	$RFNOTEG	= (1<<3),
+	$RFPROC		= (1<<4),
+	$RFMEM		= (1<<5),
+	$RFNOWAIT	= (1<<6),
+	$RFCNAMEG	= (1<<10),
+	$RFCENVG	= (1<<11),
+	$RFCFDG		= (1<<12),
+	$RFREND		= (1<<13),
+	$RFNOMNT	= (1<<14),
+
+	// bits in Qid.type
+	$QTDIR		= 0x80,		// type bit for directories
+	$QTAPPEND	= 0x40,		// type bit for append only files
+	$QTEXCL		= 0x20,		// type bit for exclusive use files
+	$QTMOUNT	= 0x10,		// type bit for mounted channel
+	$QTAUTH		= 0x08,		// type bit for authentication file
+	$QTTMP		= 0x04,		// type bit for not-backed-up file
+	$QTFILE		= 0x00,		// plain file
+
+
+	// bits in Dir.mode
+	$DMDIR		= 0x80000000,	// mode bit for directories
+	$DMAPPEND	= 0x40000000,	// mode bit for append only files
+	$DMEXCL		= 0x20000000,	// mode bit for exclusive use files
+	$DMMOUNT	= 0x10000000,	// mode bit for mounted channel
+	$DMAUTH		= 0x08000000,	// mode bit for authentication file
+	$DMTMP		= 0x04000000,	// mode bit for non-backed-up files
+	$DMREAD		= 0x4,		// mode bit for read permission
+	$DMWRITE	= 0x2,		// mode bit for write permission
+	$DMEXEC		= 0x1,		// mode bit for execute permission
+
+	BIT8SZ	= 1,
+	BIT16SZ	= 2,
+	BIT32SZ	= 4,
+	BIT64SZ	= 8,
+	QIDSZ = BIT8SZ+BIT32SZ+BIT64SZ,
+
+	// STATFIXLEN includes leading 16-bit count
+	// The count, however, excludes itself; total size is BIT16SZ+count
+	$STATFIXLEN = BIT16SZ+QIDSZ+5*BIT16SZ+4*BIT32SZ+1*BIT64SZ,	// amount of fixed length data in a stat buffer
+};
+
+
+struct Prof			// Per process profiling
+{
+	struct Plink	*pp;	// known to be 0(ptr)
+	struct Plink	*next;	// known to be 4(ptr)
+	struct Plink	*last;
+	struct Plink	*first;
+	ulong		pid;
+	ulong		what;
+};
+
+struct Tos {
+	struct Prof	prof;
+	uvlong		cyclefreq;	// cycle clock frequency if there is one, 0 otherwise
+	vlong		kcycles;	// cycles spent in kernel
+	vlong		pcycles;	// cycles spent in process (kernel + user)
+	ulong		pid;		// might as well put the pid here
+	ulong		clock;
+	// top of stack is here
+};
+
+typedef struct Prof $Prof;
+typedef struct Tos $Tos;
diff --git a/src/syscall/zerrors_darwin_386.go b/src/syscall/zerrors_darwin_386.go
index debadaa..bb3a161 100644
--- a/src/syscall/zerrors_darwin_386.go
+++ b/src/syscall/zerrors_darwin_386.go
@@ -4,8 +4,6 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs -- -m32 _const.go
 
-// +build 386,darwin
-
 package syscall
 
 const (
diff --git a/src/syscall/zerrors_darwin_amd64.go b/src/syscall/zerrors_darwin_amd64.go
index d4262ba..05ab48e 100644
--- a/src/syscall/zerrors_darwin_amd64.go
+++ b/src/syscall/zerrors_darwin_amd64.go
@@ -4,8 +4,6 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs -- -m64 _const.go
 
-// +build amd64,darwin
-
 package syscall
 
 const (
diff --git a/src/syscall/zerrors_dragonfly_386.go b/src/syscall/zerrors_dragonfly_386.go
new file mode 100644
index 0000000..701a1c3
--- /dev/null
+++ b/src/syscall/zerrors_dragonfly_386.go
@@ -0,0 +1,1526 @@
+// mkerrors.sh -m32
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs -- -m32 _const.go
+
+package syscall
+
+const (
+	AF_APPLETALK                      = 0x10
+	AF_ATM                            = 0x1e
+	AF_BLUETOOTH                      = 0x21
+	AF_CCITT                          = 0xa
+	AF_CHAOS                          = 0x5
+	AF_CNT                            = 0x15
+	AF_COIP                           = 0x14
+	AF_DATAKIT                        = 0x9
+	AF_DECnet                         = 0xc
+	AF_DLI                            = 0xd
+	AF_E164                           = 0x1a
+	AF_ECMA                           = 0x8
+	AF_HYLINK                         = 0xf
+	AF_IEEE80211                      = 0x23
+	AF_IMPLINK                        = 0x3
+	AF_INET                           = 0x2
+	AF_INET6                          = 0x1c
+	AF_IPX                            = 0x17
+	AF_ISDN                           = 0x1a
+	AF_ISO                            = 0x7
+	AF_LAT                            = 0xe
+	AF_LINK                           = 0x12
+	AF_LOCAL                          = 0x1
+	AF_MAX                            = 0x24
+	AF_MPLS                           = 0x22
+	AF_NATM                           = 0x1d
+	AF_NETGRAPH                       = 0x20
+	AF_NS                             = 0x6
+	AF_OSI                            = 0x7
+	AF_PUP                            = 0x4
+	AF_ROUTE                          = 0x11
+	AF_SIP                            = 0x18
+	AF_SNA                            = 0xb
+	AF_UNIX                           = 0x1
+	AF_UNSPEC                         = 0x0
+	B0                                = 0x0
+	B110                              = 0x6e
+	B115200                           = 0x1c200
+	B1200                             = 0x4b0
+	B134                              = 0x86
+	B14400                            = 0x3840
+	B150                              = 0x96
+	B1800                             = 0x708
+	B19200                            = 0x4b00
+	B200                              = 0xc8
+	B230400                           = 0x38400
+	B2400                             = 0x960
+	B28800                            = 0x7080
+	B300                              = 0x12c
+	B38400                            = 0x9600
+	B4800                             = 0x12c0
+	B50                               = 0x32
+	B57600                            = 0xe100
+	B600                              = 0x258
+	B7200                             = 0x1c20
+	B75                               = 0x4b
+	B76800                            = 0x12c00
+	B9600                             = 0x2580
+	BIOCFLUSH                         = 0x20004268
+	BIOCGBLEN                         = 0x40044266
+	BIOCGDLT                          = 0x4004426a
+	BIOCGDLTLIST                      = 0xc0084279
+	BIOCGETIF                         = 0x4020426b
+	BIOCGHDRCMPLT                     = 0x40044274
+	BIOCGRSIG                         = 0x40044272
+	BIOCGRTIMEOUT                     = 0x4008426e
+	BIOCGSEESENT                      = 0x40044276
+	BIOCGSTATS                        = 0x4008426f
+	BIOCIMMEDIATE                     = 0x80044270
+	BIOCLOCK                          = 0x2000427a
+	BIOCPROMISC                       = 0x20004269
+	BIOCSBLEN                         = 0xc0044266
+	BIOCSDLT                          = 0x80044278
+	BIOCSETF                          = 0x80084267
+	BIOCSETIF                         = 0x8020426c
+	BIOCSETWF                         = 0x8008427b
+	BIOCSHDRCMPLT                     = 0x80044275
+	BIOCSRSIG                         = 0x80044273
+	BIOCSRTIMEOUT                     = 0x8008426d
+	BIOCSSEESENT                      = 0x80044277
+	BIOCVERSION                       = 0x40044271
+	BPF_A                             = 0x10
+	BPF_ABS                           = 0x20
+	BPF_ADD                           = 0x0
+	BPF_ALIGNMENT                     = 0x4
+	BPF_ALU                           = 0x4
+	BPF_AND                           = 0x50
+	BPF_B                             = 0x10
+	BPF_DEFAULTBUFSIZE                = 0x1000
+	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                    = 0x80000
+	BPF_MAXINSNS                      = 0x200
+	BPF_MAX_CLONES                    = 0x80
+	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                            = 0x8000
+	CREAD                             = 0x800
+	CS5                               = 0x0
+	CS6                               = 0x100
+	CS7                               = 0x200
+	CS8                               = 0x300
+	CSIZE                             = 0x300
+	CSTART                            = 0x11
+	CSTATUS                           = 0x14
+	CSTOP                             = 0x13
+	CSTOPB                            = 0x400
+	CSUSP                             = 0x1a
+	CTL_MAXNAME                       = 0xc
+	CTL_NET                           = 0x4
+	DLT_A429                          = 0xb8
+	DLT_A653_ICM                      = 0xb9
+	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_AX25_KISS                     = 0xca
+	DLT_BACNET_MS_TP                  = 0xa5
+	DLT_BLUETOOTH_HCI_H4              = 0xbb
+	DLT_BLUETOOTH_HCI_H4_WITH_PHDR    = 0xc9
+	DLT_CAN20B                        = 0xbe
+	DLT_CHAOS                         = 0x5
+	DLT_CHDLC                         = 0x68
+	DLT_CISCO_IOS                     = 0x76
+	DLT_C_HDLC                        = 0x68
+	DLT_C_HDLC_WITH_DIR               = 0xcd
+	DLT_DOCSIS                        = 0x8f
+	DLT_ECONET                        = 0x73
+	DLT_EN10MB                        = 0x1
+	DLT_EN3MB                         = 0x2
+	DLT_ENC                           = 0x6d
+	DLT_ERF                           = 0xc5
+	DLT_ERF_ETH                       = 0xaf
+	DLT_ERF_POS                       = 0xb0
+	DLT_FDDI                          = 0xa
+	DLT_FLEXRAY                       = 0xd2
+	DLT_FRELAY                        = 0x6b
+	DLT_FRELAY_WITH_DIR               = 0xce
+	DLT_GCOM_SERIAL                   = 0xad
+	DLT_GCOM_T1E1                     = 0xac
+	DLT_GPF_F                         = 0xab
+	DLT_GPF_T                         = 0xaa
+	DLT_GPRS_LLC                      = 0xa9
+	DLT_HHDLC                         = 0x79
+	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_IEEE802_15_4                  = 0xc3
+	DLT_IEEE802_15_4_LINUX            = 0xbf
+	DLT_IEEE802_15_4_NONASK_PHY       = 0xd7
+	DLT_IEEE802_16_MAC_CPS            = 0xbc
+	DLT_IEEE802_16_MAC_CPS_RADIO      = 0xc1
+	DLT_IPFILTER                      = 0x74
+	DLT_IPMB                          = 0xc7
+	DLT_IPMB_LINUX                    = 0xd1
+	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_ISM                   = 0xc2
+	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_JUNIPER_ST                    = 0xc8
+	DLT_JUNIPER_VP                    = 0xb7
+	DLT_LAPB_WITH_DIR                 = 0xcf
+	DLT_LAPD                          = 0xcb
+	DLT_LIN                           = 0xd4
+	DLT_LINUX_IRDA                    = 0x90
+	DLT_LINUX_LAPD                    = 0xb1
+	DLT_LINUX_SLL                     = 0x71
+	DLT_LOOP                          = 0x6c
+	DLT_LTALK                         = 0x72
+	DLT_MFR                           = 0xb6
+	DLT_MOST                          = 0xd3
+	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_PPI                           = 0xc0
+	DLT_PPP                           = 0x9
+	DLT_PPP_BSDOS                     = 0x10
+	DLT_PPP_ETHER                     = 0x33
+	DLT_PPP_PPPD                      = 0xa6
+	DLT_PPP_SERIAL                    = 0x32
+	DLT_PPP_WITH_DIR                  = 0xcc
+	DLT_PRISM_HEADER                  = 0x77
+	DLT_PRONET                        = 0x4
+	DLT_RAIF1                         = 0xc6
+	DLT_RAW                           = 0xc
+	DLT_REDBACK_SMARTEDGE             = 0x20
+	DLT_RIO                           = 0x7c
+	DLT_SCCP                          = 0x8e
+	DLT_SITA                          = 0xc4
+	DLT_SLIP                          = 0x8
+	DLT_SLIP_BSDOS                    = 0xf
+	DLT_SUNATM                        = 0x7b
+	DLT_SYMANTEC_FIREWALL             = 0x63
+	DLT_TZSP                          = 0x80
+	DLT_USB                           = 0xba
+	DLT_USB_LINUX                     = 0xbd
+	DLT_X2E_SERIAL                    = 0xd5
+	DLT_X2E_XORAYA                    = 0xd6
+	DT_BLK                            = 0x6
+	DT_CHR                            = 0x2
+	DT_DBF                            = 0xf
+	DT_DIR                            = 0x4
+	DT_FIFO                           = 0x1
+	DT_LNK                            = 0xa
+	DT_REG                            = 0x8
+	DT_SOCK                           = 0xc
+	DT_UNKNOWN                        = 0x0
+	DT_WHT                            = 0xe
+	ECHO                              = 0x8
+	ECHOCTL                           = 0x40
+	ECHOE                             = 0x2
+	ECHOK                             = 0x4
+	ECHOKE                            = 0x1
+	ECHONL                            = 0x10
+	ECHOPRT                           = 0x20
+	EVFILT_AIO                        = -0x3
+	EVFILT_EXCEPT                     = -0x8
+	EVFILT_MARKER                     = 0xf
+	EVFILT_PROC                       = -0x5
+	EVFILT_READ                       = -0x1
+	EVFILT_SIGNAL                     = -0x6
+	EVFILT_SYSCOUNT                   = 0x8
+	EVFILT_TIMER                      = -0x7
+	EVFILT_VNODE                      = -0x4
+	EVFILT_WRITE                      = -0x2
+	EV_ADD                            = 0x1
+	EV_CLEAR                          = 0x20
+	EV_DELETE                         = 0x2
+	EV_DISABLE                        = 0x8
+	EV_ENABLE                         = 0x4
+	EV_EOF                            = 0x8000
+	EV_ERROR                          = 0x4000
+	EV_FLAG1                          = 0x2000
+	EV_NODATA                         = 0x1000
+	EV_ONESHOT                        = 0x10
+	EV_SYSFLAGS                       = 0xf000
+	EXTA                              = 0x4b00
+	EXTB                              = 0x9600
+	EXTEXIT_LWP                       = 0x10000
+	EXTEXIT_PROC                      = 0x0
+	EXTEXIT_SETINT                    = 0x1
+	EXTEXIT_SIMPLE                    = 0x0
+	EXTPROC                           = 0x800
+	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
+	F_GETOWN                          = 0x5
+	F_OK                              = 0x0
+	F_RDLCK                           = 0x1
+	F_SETFD                           = 0x2
+	F_SETFL                           = 0x4
+	F_SETLK                           = 0x8
+	F_SETLKW                          = 0x9
+	F_SETOWN                          = 0x6
+	F_UNLCK                           = 0x2
+	F_WRLCK                           = 0x3
+	HUPCL                             = 0x4000
+	ICANON                            = 0x100
+	ICMP6_FILTER                      = 0x12
+	ICRNL                             = 0x100
+	IEXTEN                            = 0x400
+	IFAN_ARRIVAL                      = 0x0
+	IFAN_DEPARTURE                    = 0x1
+	IFF_ALLMULTI                      = 0x200
+	IFF_ALTPHYS                       = 0x4000
+	IFF_BROADCAST                     = 0x2
+	IFF_CANTCHANGE                    = 0x118e72
+	IFF_DEBUG                         = 0x4
+	IFF_LINK0                         = 0x1000
+	IFF_LINK1                         = 0x2000
+	IFF_LINK2                         = 0x4000
+	IFF_LOOPBACK                      = 0x8
+	IFF_MONITOR                       = 0x40000
+	IFF_MULTICAST                     = 0x8000
+	IFF_NOARP                         = 0x80
+	IFF_NPOLLING                      = 0x100000
+	IFF_OACTIVE                       = 0x400
+	IFF_OACTIVE_COMPAT                = 0x400
+	IFF_POINTOPOINT                   = 0x10
+	IFF_POLLING                       = 0x10000
+	IFF_POLLING_COMPAT                = 0x10000
+	IFF_PPROMISC                      = 0x20000
+	IFF_PROMISC                       = 0x100
+	IFF_RUNNING                       = 0x40
+	IFF_SIMPLEX                       = 0x800
+	IFF_SMART                         = 0x20
+	IFF_STATICARP                     = 0x80000
+	IFF_UP                            = 0x1
+	IFNAMSIZ                          = 0x10
+	IFT_1822                          = 0x2
+	IFT_A12MPPSWITCH                  = 0x82
+	IFT_AAL2                          = 0xbb
+	IFT_AAL5                          = 0x31
+	IFT_ADSL                          = 0x5e
+	IFT_AFLANE8023                    = 0x3b
+	IFT_AFLANE8025                    = 0x3c
+	IFT_ARAP                          = 0x58
+	IFT_ARCNET                        = 0x23
+	IFT_ARCNETPLUS                    = 0x24
+	IFT_ASYNC                         = 0x54
+	IFT_ATM                           = 0x25
+	IFT_ATMDXI                        = 0x69
+	IFT_ATMFUNI                       = 0x6a
+	IFT_ATMIMA                        = 0x6b
+	IFT_ATMLOGICAL                    = 0x50
+	IFT_ATMRADIO                      = 0xbd
+	IFT_ATMSUBINTERFACE               = 0x86
+	IFT_ATMVCIENDPT                   = 0xc2
+	IFT_ATMVIRTUAL                    = 0x95
+	IFT_BGPPOLICYACCOUNTING           = 0xa2
+	IFT_BRIDGE                        = 0xd1
+	IFT_BSC                           = 0x53
+	IFT_CARP                          = 0xf8
+	IFT_CCTEMUL                       = 0x3d
+	IFT_CEPT                          = 0x13
+	IFT_CES                           = 0x85
+	IFT_CHANNEL                       = 0x46
+	IFT_CNR                           = 0x55
+	IFT_COFFEE                        = 0x84
+	IFT_COMPOSITELINK                 = 0x9b
+	IFT_DCN                           = 0x8d
+	IFT_DIGITALPOWERLINE              = 0x8a
+	IFT_DIGITALWRAPPEROVERHEADCHANNEL = 0xba
+	IFT_DLSW                          = 0x4a
+	IFT_DOCSCABLEDOWNSTREAM           = 0x80
+	IFT_DOCSCABLEMACLAYER             = 0x7f
+	IFT_DOCSCABLEUPSTREAM             = 0x81
+	IFT_DS0                           = 0x51
+	IFT_DS0BUNDLE                     = 0x52
+	IFT_DS1FDL                        = 0xaa
+	IFT_DS3                           = 0x1e
+	IFT_DTM                           = 0x8c
+	IFT_DVBASILN                      = 0xac
+	IFT_DVBASIOUT                     = 0xad
+	IFT_DVBRCCDOWNSTREAM              = 0x93
+	IFT_DVBRCCMACLAYER                = 0x92
+	IFT_DVBRCCUPSTREAM                = 0x94
+	IFT_ENC                           = 0xf4
+	IFT_EON                           = 0x19
+	IFT_EPLRS                         = 0x57
+	IFT_ESCON                         = 0x49
+	IFT_ETHER                         = 0x6
+	IFT_FAITH                         = 0xf2
+	IFT_FAST                          = 0x7d
+	IFT_FASTETHER                     = 0x3e
+	IFT_FASTETHERFX                   = 0x45
+	IFT_FDDI                          = 0xf
+	IFT_FIBRECHANNEL                  = 0x38
+	IFT_FRAMERELAYINTERCONNECT        = 0x3a
+	IFT_FRAMERELAYMPI                 = 0x5c
+	IFT_FRDLCIENDPT                   = 0xc1
+	IFT_FRELAY                        = 0x20
+	IFT_FRELAYDCE                     = 0x2c
+	IFT_FRF16MFRBUNDLE                = 0xa3
+	IFT_FRFORWARD                     = 0x9e
+	IFT_G703AT2MB                     = 0x43
+	IFT_G703AT64K                     = 0x42
+	IFT_GIF                           = 0xf0
+	IFT_GIGABITETHERNET               = 0x75
+	IFT_GR303IDT                      = 0xb2
+	IFT_GR303RDT                      = 0xb1
+	IFT_H323GATEKEEPER                = 0xa4
+	IFT_H323PROXY                     = 0xa5
+	IFT_HDH1822                       = 0x3
+	IFT_HDLC                          = 0x76
+	IFT_HDSL2                         = 0xa8
+	IFT_HIPERLAN2                     = 0xb7
+	IFT_HIPPI                         = 0x2f
+	IFT_HIPPIINTERFACE                = 0x39
+	IFT_HOSTPAD                       = 0x5a
+	IFT_HSSI                          = 0x2e
+	IFT_HY                            = 0xe
+	IFT_IBM370PARCHAN                 = 0x48
+	IFT_IDSL                          = 0x9a
+	IFT_IEEE1394                      = 0x90
+	IFT_IEEE80211                     = 0x47
+	IFT_IEEE80212                     = 0x37
+	IFT_IEEE8023ADLAG                 = 0xa1
+	IFT_IFGSN                         = 0x91
+	IFT_IMT                           = 0xbe
+	IFT_INTERLEAVE                    = 0x7c
+	IFT_IP                            = 0x7e
+	IFT_IPFORWARD                     = 0x8e
+	IFT_IPOVERATM                     = 0x72
+	IFT_IPOVERCDLC                    = 0x6d
+	IFT_IPOVERCLAW                    = 0x6e
+	IFT_IPSWITCH                      = 0x4e
+	IFT_ISDN                          = 0x3f
+	IFT_ISDNBASIC                     = 0x14
+	IFT_ISDNPRIMARY                   = 0x15
+	IFT_ISDNS                         = 0x4b
+	IFT_ISDNU                         = 0x4c
+	IFT_ISO88022LLC                   = 0x29
+	IFT_ISO88023                      = 0x7
+	IFT_ISO88024                      = 0x8
+	IFT_ISO88025                      = 0x9
+	IFT_ISO88025CRFPINT               = 0x62
+	IFT_ISO88025DTR                   = 0x56
+	IFT_ISO88025FIBER                 = 0x73
+	IFT_ISO88026                      = 0xa
+	IFT_ISUP                          = 0xb3
+	IFT_L2VLAN                        = 0x87
+	IFT_L3IPVLAN                      = 0x88
+	IFT_L3IPXVLAN                     = 0x89
+	IFT_LAPB                          = 0x10
+	IFT_LAPD                          = 0x4d
+	IFT_LAPF                          = 0x77
+	IFT_LOCALTALK                     = 0x2a
+	IFT_LOOP                          = 0x18
+	IFT_MEDIAMAILOVERIP               = 0x8b
+	IFT_MFSIGLINK                     = 0xa7
+	IFT_MIOX25                        = 0x26
+	IFT_MODEM                         = 0x30
+	IFT_MPC                           = 0x71
+	IFT_MPLS                          = 0xa6
+	IFT_MPLSTUNNEL                    = 0x96
+	IFT_MSDSL                         = 0x8f
+	IFT_MVL                           = 0xbf
+	IFT_MYRINET                       = 0x63
+	IFT_NFAS                          = 0xaf
+	IFT_NSIP                          = 0x1b
+	IFT_OPTICALCHANNEL                = 0xc3
+	IFT_OPTICALTRANSPORT              = 0xc4
+	IFT_OTHER                         = 0x1
+	IFT_P10                           = 0xc
+	IFT_P80                           = 0xd
+	IFT_PARA                          = 0x22
+	IFT_PFLOG                         = 0xf5
+	IFT_PFSYNC                        = 0xf6
+	IFT_PLC                           = 0xae
+	IFT_POS                           = 0xab
+	IFT_PPP                           = 0x17
+	IFT_PPPMULTILINKBUNDLE            = 0x6c
+	IFT_PROPBWAP2MP                   = 0xb8
+	IFT_PROPCNLS                      = 0x59
+	IFT_PROPDOCSWIRELESSDOWNSTREAM    = 0xb5
+	IFT_PROPDOCSWIRELESSMACLAYER      = 0xb4
+	IFT_PROPDOCSWIRELESSUPSTREAM      = 0xb6
+	IFT_PROPMUX                       = 0x36
+	IFT_PROPVIRTUAL                   = 0x35
+	IFT_PROPWIRELESSP2P               = 0x9d
+	IFT_PTPSERIAL                     = 0x16
+	IFT_PVC                           = 0xf1
+	IFT_QLLC                          = 0x44
+	IFT_RADIOMAC                      = 0xbc
+	IFT_RADSL                         = 0x5f
+	IFT_REACHDSL                      = 0xc0
+	IFT_RFC1483                       = 0x9f
+	IFT_RS232                         = 0x21
+	IFT_RSRB                          = 0x4f
+	IFT_SDLC                          = 0x11
+	IFT_SDSL                          = 0x60
+	IFT_SHDSL                         = 0xa9
+	IFT_SIP                           = 0x1f
+	IFT_SLIP                          = 0x1c
+	IFT_SMDSDXI                       = 0x2b
+	IFT_SMDSICIP                      = 0x34
+	IFT_SONET                         = 0x27
+	IFT_SONETOVERHEADCHANNEL          = 0xb9
+	IFT_SONETPATH                     = 0x32
+	IFT_SONETVT                       = 0x33
+	IFT_SRP                           = 0x97
+	IFT_SS7SIGLINK                    = 0x9c
+	IFT_STACKTOSTACK                  = 0x6f
+	IFT_STARLAN                       = 0xb
+	IFT_STF                           = 0xf3
+	IFT_T1                            = 0x12
+	IFT_TDLC                          = 0x74
+	IFT_TERMPAD                       = 0x5b
+	IFT_TR008                         = 0xb0
+	IFT_TRANSPHDLC                    = 0x7b
+	IFT_TUNNEL                        = 0x83
+	IFT_ULTRA                         = 0x1d
+	IFT_USB                           = 0xa0
+	IFT_V11                           = 0x40
+	IFT_V35                           = 0x2d
+	IFT_V36                           = 0x41
+	IFT_V37                           = 0x78
+	IFT_VDSL                          = 0x61
+	IFT_VIRTUALIPADDRESS              = 0x70
+	IFT_VOICEEM                       = 0x64
+	IFT_VOICEENCAP                    = 0x67
+	IFT_VOICEFXO                      = 0x65
+	IFT_VOICEFXS                      = 0x66
+	IFT_VOICEOVERATM                  = 0x98
+	IFT_VOICEOVERFRAMERELAY           = 0x99
+	IFT_VOICEOVERIP                   = 0x68
+	IFT_X213                          = 0x5d
+	IFT_X25                           = 0x5
+	IFT_X25DDN                        = 0x4
+	IFT_X25HUNTGROUP                  = 0x7a
+	IFT_X25MLP                        = 0x79
+	IFT_X25PLE                        = 0x28
+	IFT_XETHER                        = 0x1a
+	IGNBRK                            = 0x1
+	IGNCR                             = 0x80
+	IGNPAR                            = 0x4
+	IMAXBEL                           = 0x2000
+	INLCR                             = 0x40
+	INPCK                             = 0x10
+	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_LOOPBACKNET                    = 0x7f
+	IPPROTO_3PC                       = 0x22
+	IPPROTO_ADFS                      = 0x44
+	IPPROTO_AH                        = 0x33
+	IPPROTO_AHIP                      = 0x3d
+	IPPROTO_APES                      = 0x63
+	IPPROTO_ARGUS                     = 0xd
+	IPPROTO_AX25                      = 0x5d
+	IPPROTO_BHA                       = 0x31
+	IPPROTO_BLT                       = 0x1e
+	IPPROTO_BRSATMON                  = 0x4c
+	IPPROTO_CARP                      = 0x70
+	IPPROTO_CFTP                      = 0x3e
+	IPPROTO_CHAOS                     = 0x10
+	IPPROTO_CMTP                      = 0x26
+	IPPROTO_CPHB                      = 0x49
+	IPPROTO_CPNX                      = 0x48
+	IPPROTO_DDP                       = 0x25
+	IPPROTO_DGP                       = 0x56
+	IPPROTO_DIVERT                    = 0xfe
+	IPPROTO_DONE                      = 0x101
+	IPPROTO_DSTOPTS                   = 0x3c
+	IPPROTO_EGP                       = 0x8
+	IPPROTO_EMCON                     = 0xe
+	IPPROTO_ENCAP                     = 0x62
+	IPPROTO_EON                       = 0x50
+	IPPROTO_ESP                       = 0x32
+	IPPROTO_ETHERIP                   = 0x61
+	IPPROTO_FRAGMENT                  = 0x2c
+	IPPROTO_GGP                       = 0x3
+	IPPROTO_GMTP                      = 0x64
+	IPPROTO_GRE                       = 0x2f
+	IPPROTO_HELLO                     = 0x3f
+	IPPROTO_HMP                       = 0x14
+	IPPROTO_HOPOPTS                   = 0x0
+	IPPROTO_ICMP                      = 0x1
+	IPPROTO_ICMPV6                    = 0x3a
+	IPPROTO_IDP                       = 0x16
+	IPPROTO_IDPR                      = 0x23
+	IPPROTO_IDRP                      = 0x2d
+	IPPROTO_IGMP                      = 0x2
+	IPPROTO_IGP                       = 0x55
+	IPPROTO_IGRP                      = 0x58
+	IPPROTO_IL                        = 0x28
+	IPPROTO_INLSP                     = 0x34
+	IPPROTO_INP                       = 0x20
+	IPPROTO_IP                        = 0x0
+	IPPROTO_IPCOMP                    = 0x6c
+	IPPROTO_IPCV                      = 0x47
+	IPPROTO_IPEIP                     = 0x5e
+	IPPROTO_IPIP                      = 0x4
+	IPPROTO_IPPC                      = 0x43
+	IPPROTO_IPV4                      = 0x4
+	IPPROTO_IPV6                      = 0x29
+	IPPROTO_IRTP                      = 0x1c
+	IPPROTO_KRYPTOLAN                 = 0x41
+	IPPROTO_LARP                      = 0x5b
+	IPPROTO_LEAF1                     = 0x19
+	IPPROTO_LEAF2                     = 0x1a
+	IPPROTO_MAX                       = 0x100
+	IPPROTO_MAXID                     = 0x34
+	IPPROTO_MEAS                      = 0x13
+	IPPROTO_MHRP                      = 0x30
+	IPPROTO_MICP                      = 0x5f
+	IPPROTO_MOBILE                    = 0x37
+	IPPROTO_MTP                       = 0x5c
+	IPPROTO_MUX                       = 0x12
+	IPPROTO_ND                        = 0x4d
+	IPPROTO_NHRP                      = 0x36
+	IPPROTO_NONE                      = 0x3b
+	IPPROTO_NSP                       = 0x1f
+	IPPROTO_NVPII                     = 0xb
+	IPPROTO_OSPFIGP                   = 0x59
+	IPPROTO_PFSYNC                    = 0xf0
+	IPPROTO_PGM                       = 0x71
+	IPPROTO_PIGP                      = 0x9
+	IPPROTO_PIM                       = 0x67
+	IPPROTO_PRM                       = 0x15
+	IPPROTO_PUP                       = 0xc
+	IPPROTO_PVP                       = 0x4b
+	IPPROTO_RAW                       = 0xff
+	IPPROTO_RCCMON                    = 0xa
+	IPPROTO_RDP                       = 0x1b
+	IPPROTO_ROUTING                   = 0x2b
+	IPPROTO_RSVP                      = 0x2e
+	IPPROTO_RVD                       = 0x42
+	IPPROTO_SATEXPAK                  = 0x40
+	IPPROTO_SATMON                    = 0x45
+	IPPROTO_SCCSP                     = 0x60
+	IPPROTO_SCTP                      = 0x84
+	IPPROTO_SDRP                      = 0x2a
+	IPPROTO_SEP                       = 0x21
+	IPPROTO_SKIP                      = 0x39
+	IPPROTO_SRPC                      = 0x5a
+	IPPROTO_ST                        = 0x7
+	IPPROTO_SVMTP                     = 0x52
+	IPPROTO_SWIPE                     = 0x35
+	IPPROTO_TCF                       = 0x57
+	IPPROTO_TCP                       = 0x6
+	IPPROTO_TLSP                      = 0x38
+	IPPROTO_TP                        = 0x1d
+	IPPROTO_TPXX                      = 0x27
+	IPPROTO_TRUNK1                    = 0x17
+	IPPROTO_TRUNK2                    = 0x18
+	IPPROTO_TTP                       = 0x54
+	IPPROTO_UDP                       = 0x11
+	IPPROTO_UNKNOWN                   = 0x102
+	IPPROTO_VINES                     = 0x53
+	IPPROTO_VISA                      = 0x46
+	IPPROTO_VMTP                      = 0x51
+	IPPROTO_WBEXPAK                   = 0x4f
+	IPPROTO_WBMON                     = 0x4e
+	IPPROTO_WSN                       = 0x4a
+	IPPROTO_XNET                      = 0xf
+	IPPROTO_XTP                       = 0x24
+	IPV6_AUTOFLOWLABEL                = 0x3b
+	IPV6_BINDV6ONLY                   = 0x1b
+	IPV6_CHECKSUM                     = 0x1a
+	IPV6_DEFAULT_MULTICAST_HOPS       = 0x1
+	IPV6_DEFAULT_MULTICAST_LOOP       = 0x1
+	IPV6_DEFHLIM                      = 0x40
+	IPV6_DONTFRAG                     = 0x3e
+	IPV6_DSTOPTS                      = 0x32
+	IPV6_FAITH                        = 0x1d
+	IPV6_FLOWINFO_MASK                = 0xffffff0f
+	IPV6_FLOWLABEL_MASK               = 0xffff0f00
+	IPV6_FRAGTTL                      = 0x78
+	IPV6_FW_ADD                       = 0x1e
+	IPV6_FW_DEL                       = 0x1f
+	IPV6_FW_FLUSH                     = 0x20
+	IPV6_FW_GET                       = 0x22
+	IPV6_FW_ZERO                      = 0x21
+	IPV6_HLIMDEC                      = 0x1
+	IPV6_HOPLIMIT                     = 0x2f
+	IPV6_HOPOPTS                      = 0x31
+	IPV6_IPSEC_POLICY                 = 0x1c
+	IPV6_JOIN_GROUP                   = 0xc
+	IPV6_LEAVE_GROUP                  = 0xd
+	IPV6_MAXHLIM                      = 0xff
+	IPV6_MAXPACKET                    = 0xffff
+	IPV6_MMTU                         = 0x500
+	IPV6_MSFILTER                     = 0x4a
+	IPV6_MULTICAST_HOPS               = 0xa
+	IPV6_MULTICAST_IF                 = 0x9
+	IPV6_MULTICAST_LOOP               = 0xb
+	IPV6_NEXTHOP                      = 0x30
+	IPV6_PATHMTU                      = 0x2c
+	IPV6_PKTINFO                      = 0x2e
+	IPV6_PKTOPTIONS                   = 0x34
+	IPV6_PORTRANGE                    = 0xe
+	IPV6_PORTRANGE_DEFAULT            = 0x0
+	IPV6_PORTRANGE_HIGH               = 0x1
+	IPV6_PORTRANGE_LOW                = 0x2
+	IPV6_PREFER_TEMPADDR              = 0x3f
+	IPV6_RECVDSTOPTS                  = 0x28
+	IPV6_RECVHOPLIMIT                 = 0x25
+	IPV6_RECVHOPOPTS                  = 0x27
+	IPV6_RECVPATHMTU                  = 0x2b
+	IPV6_RECVPKTINFO                  = 0x24
+	IPV6_RECVRTHDR                    = 0x26
+	IPV6_RECVTCLASS                   = 0x39
+	IPV6_RTHDR                        = 0x33
+	IPV6_RTHDRDSTOPTS                 = 0x23
+	IPV6_RTHDR_LOOSE                  = 0x0
+	IPV6_RTHDR_STRICT                 = 0x1
+	IPV6_RTHDR_TYPE_0                 = 0x0
+	IPV6_SOCKOPT_RESERVED1            = 0x3
+	IPV6_TCLASS                       = 0x3d
+	IPV6_UNICAST_HOPS                 = 0x4
+	IPV6_USE_MIN_MTU                  = 0x2a
+	IPV6_V6ONLY                       = 0x1b
+	IPV6_VERSION                      = 0x60
+	IPV6_VERSION_MASK                 = 0xf0
+	IP_ADD_MEMBERSHIP                 = 0xc
+	IP_DEFAULT_MULTICAST_LOOP         = 0x1
+	IP_DEFAULT_MULTICAST_TTL          = 0x1
+	IP_DF                             = 0x4000
+	IP_DROP_MEMBERSHIP                = 0xd
+	IP_DUMMYNET_CONFIGURE             = 0x3c
+	IP_DUMMYNET_DEL                   = 0x3d
+	IP_DUMMYNET_FLUSH                 = 0x3e
+	IP_DUMMYNET_GET                   = 0x40
+	IP_FAITH                          = 0x16
+	IP_FW_ADD                         = 0x32
+	IP_FW_DEL                         = 0x33
+	IP_FW_FLUSH                       = 0x34
+	IP_FW_GET                         = 0x36
+	IP_FW_RESETLOG                    = 0x37
+	IP_FW_ZERO                        = 0x35
+	IP_HDRINCL                        = 0x2
+	IP_IPSEC_POLICY                   = 0x15
+	IP_MAXPACKET                      = 0xffff
+	IP_MAX_MEMBERSHIPS                = 0x14
+	IP_MF                             = 0x2000
+	IP_MINTTL                         = 0x42
+	IP_MSS                            = 0x240
+	IP_MULTICAST_IF                   = 0x9
+	IP_MULTICAST_LOOP                 = 0xb
+	IP_MULTICAST_TTL                  = 0xa
+	IP_MULTICAST_VIF                  = 0xe
+	IP_OFFMASK                        = 0x1fff
+	IP_OPTIONS                        = 0x1
+	IP_PORTRANGE                      = 0x13
+	IP_PORTRANGE_DEFAULT              = 0x0
+	IP_PORTRANGE_HIGH                 = 0x1
+	IP_PORTRANGE_LOW                  = 0x2
+	IP_RECVDSTADDR                    = 0x7
+	IP_RECVIF                         = 0x14
+	IP_RECVOPTS                       = 0x5
+	IP_RECVRETOPTS                    = 0x6
+	IP_RECVTTL                        = 0x41
+	IP_RETOPTS                        = 0x8
+	IP_RF                             = 0x8000
+	IP_RSVP_OFF                       = 0x10
+	IP_RSVP_ON                        = 0xf
+	IP_RSVP_VIF_OFF                   = 0x12
+	IP_RSVP_VIF_ON                    = 0x11
+	IP_TOS                            = 0x3
+	IP_TTL                            = 0x4
+	ISIG                              = 0x80
+	ISTRIP                            = 0x20
+	IXANY                             = 0x800
+	IXOFF                             = 0x400
+	IXON                              = 0x200
+	LOCK_EX                           = 0x2
+	LOCK_NB                           = 0x4
+	LOCK_SH                           = 0x1
+	LOCK_UN                           = 0x8
+	MADV_AUTOSYNC                     = 0x7
+	MADV_CONTROL_END                  = 0xb
+	MADV_CONTROL_START                = 0xa
+	MADV_CORE                         = 0x9
+	MADV_DONTNEED                     = 0x4
+	MADV_FREE                         = 0x5
+	MADV_INVAL                        = 0xa
+	MADV_NOCORE                       = 0x8
+	MADV_NORMAL                       = 0x0
+	MADV_NOSYNC                       = 0x6
+	MADV_RANDOM                       = 0x1
+	MADV_SEQUENTIAL                   = 0x2
+	MADV_SETMAP                       = 0xb
+	MADV_WILLNEED                     = 0x3
+	MAP_ANON                          = 0x1000
+	MAP_COPY                          = 0x2
+	MAP_FILE                          = 0x0
+	MAP_FIXED                         = 0x10
+	MAP_HASSEMAPHORE                  = 0x200
+	MAP_INHERIT                       = 0x80
+	MAP_NOCORE                        = 0x20000
+	MAP_NOEXTEND                      = 0x100
+	MAP_NORESERVE                     = 0x40
+	MAP_NOSYNC                        = 0x800
+	MAP_PRIVATE                       = 0x2
+	MAP_RENAME                        = 0x20
+	MAP_SHARED                        = 0x1
+	MAP_SIZEALIGN                     = 0x40000
+	MAP_STACK                         = 0x400
+	MAP_TRYFIXED                      = 0x10000
+	MAP_VPAGETABLE                    = 0x2000
+	MCL_CURRENT                       = 0x1
+	MCL_FUTURE                        = 0x2
+	MSG_CTRUNC                        = 0x20
+	MSG_DONTROUTE                     = 0x4
+	MSG_DONTWAIT                      = 0x80
+	MSG_EOF                           = 0x100
+	MSG_EOR                           = 0x8
+	MSG_FBLOCKING                     = 0x10000
+	MSG_FMASK                         = 0xffff0000
+	MSG_FNONBLOCKING                  = 0x20000
+	MSG_NOSIGNAL                      = 0x400
+	MSG_NOTIFICATION                  = 0x200
+	MSG_OOB                           = 0x1
+	MSG_PEEK                          = 0x2
+	MSG_SYNC                          = 0x800
+	MSG_TRUNC                         = 0x10
+	MSG_WAITALL                       = 0x40
+	MS_ASYNC                          = 0x1
+	MS_INVALIDATE                     = 0x2
+	MS_SYNC                           = 0x0
+	NAME_MAX                          = 0xff
+	NET_RT_DUMP                       = 0x1
+	NET_RT_FLAGS                      = 0x2
+	NET_RT_IFLIST                     = 0x3
+	NET_RT_MAXID                      = 0x4
+	NOFLSH                            = 0x80000000
+	NOTE_ATTRIB                       = 0x8
+	NOTE_CHILD                        = 0x4
+	NOTE_DELETE                       = 0x1
+	NOTE_EXEC                         = 0x20000000
+	NOTE_EXIT                         = 0x80000000
+	NOTE_EXTEND                       = 0x4
+	NOTE_FORK                         = 0x40000000
+	NOTE_LINK                         = 0x10
+	NOTE_LOWAT                        = 0x1
+	NOTE_OOB                          = 0x2
+	NOTE_PCTRLMASK                    = 0xf0000000
+	NOTE_PDATAMASK                    = 0xfffff
+	NOTE_RENAME                       = 0x20
+	NOTE_REVOKE                       = 0x40
+	NOTE_TRACK                        = 0x1
+	NOTE_TRACKERR                     = 0x2
+	NOTE_WRITE                        = 0x2
+	OCRNL                             = 0x10
+	ONLCR                             = 0x2
+	ONLRET                            = 0x40
+	ONOCR                             = 0x20
+	ONOEOT                            = 0x8
+	OPOST                             = 0x1
+	O_ACCMODE                         = 0x3
+	O_APPEND                          = 0x8
+	O_ASYNC                           = 0x40
+	O_CLOEXEC                         = 0x20000
+	O_CREAT                           = 0x200
+	O_DIRECT                          = 0x10000
+	O_DIRECTORY                       = 0x8000000
+	O_EXCL                            = 0x800
+	O_EXLOCK                          = 0x20
+	O_FAPPEND                         = 0x100000
+	O_FASYNCWRITE                     = 0x800000
+	O_FBLOCKING                       = 0x40000
+	O_FBUFFERED                       = 0x2000000
+	O_FMASK                           = 0x7fc0000
+	O_FNONBLOCKING                    = 0x80000
+	O_FOFFSET                         = 0x200000
+	O_FSYNC                           = 0x80
+	O_FSYNCWRITE                      = 0x400000
+	O_FUNBUFFERED                     = 0x1000000
+	O_MAPONREAD                       = 0x4000000
+	O_NDELAY                          = 0x4
+	O_NOCTTY                          = 0x8000
+	O_NOFOLLOW                        = 0x100
+	O_NONBLOCK                        = 0x4
+	O_RDONLY                          = 0x0
+	O_RDWR                            = 0x2
+	O_SHLOCK                          = 0x10
+	O_SYNC                            = 0x80
+	O_TRUNC                           = 0x400
+	O_WRONLY                          = 0x1
+	PARENB                            = 0x1000
+	PARMRK                            = 0x8
+	PARODD                            = 0x2000
+	PENDIN                            = 0x20000000
+	PRIO_PGRP                         = 0x1
+	PRIO_PROCESS                      = 0x0
+	PRIO_USER                         = 0x2
+	PROT_EXEC                         = 0x4
+	PROT_NONE                         = 0x0
+	PROT_READ                         = 0x1
+	PROT_WRITE                        = 0x2
+	RLIMIT_AS                         = 0xa
+	RLIMIT_CORE                       = 0x4
+	RLIMIT_CPU                        = 0x0
+	RLIMIT_DATA                       = 0x2
+	RLIMIT_FSIZE                      = 0x1
+	RLIMIT_NOFILE                     = 0x8
+	RLIMIT_STACK                      = 0x3
+	RLIM_INFINITY                     = 0x7fffffffffffffff
+	RTAX_AUTHOR                       = 0x6
+	RTAX_BRD                          = 0x7
+	RTAX_DST                          = 0x0
+	RTAX_GATEWAY                      = 0x1
+	RTAX_GENMASK                      = 0x3
+	RTAX_IFA                          = 0x5
+	RTAX_IFP                          = 0x4
+	RTAX_MAX                          = 0xb
+	RTAX_MPLS1                        = 0x8
+	RTAX_MPLS2                        = 0x9
+	RTAX_MPLS3                        = 0xa
+	RTAX_NETMASK                      = 0x2
+	RTA_AUTHOR                        = 0x40
+	RTA_BRD                           = 0x80
+	RTA_DST                           = 0x1
+	RTA_GATEWAY                       = 0x2
+	RTA_GENMASK                       = 0x8
+	RTA_IFA                           = 0x20
+	RTA_IFP                           = 0x10
+	RTA_MPLS1                         = 0x100
+	RTA_MPLS2                         = 0x200
+	RTA_MPLS3                         = 0x400
+	RTA_NETMASK                       = 0x4
+	RTF_BLACKHOLE                     = 0x1000
+	RTF_BROADCAST                     = 0x400000
+	RTF_CLONING                       = 0x100
+	RTF_DONE                          = 0x40
+	RTF_DYNAMIC                       = 0x10
+	RTF_GATEWAY                       = 0x2
+	RTF_HOST                          = 0x4
+	RTF_LLINFO                        = 0x400
+	RTF_LOCAL                         = 0x200000
+	RTF_MODIFIED                      = 0x20
+	RTF_MPLSOPS                       = 0x1000000
+	RTF_MULTICAST                     = 0x800000
+	RTF_PINNED                        = 0x100000
+	RTF_PRCLONING                     = 0x10000
+	RTF_PROTO1                        = 0x8000
+	RTF_PROTO2                        = 0x4000
+	RTF_PROTO3                        = 0x40000
+	RTF_REJECT                        = 0x8
+	RTF_STATIC                        = 0x800
+	RTF_UP                            = 0x1
+	RTF_WASCLONED                     = 0x20000
+	RTF_XRESOLVE                      = 0x200
+	RTM_ADD                           = 0x1
+	RTM_CHANGE                        = 0x3
+	RTM_DELADDR                       = 0xd
+	RTM_DELETE                        = 0x2
+	RTM_DELMADDR                      = 0x10
+	RTM_GET                           = 0x4
+	RTM_IEEE80211                     = 0x12
+	RTM_IFANNOUNCE                    = 0x11
+	RTM_IFINFO                        = 0xe
+	RTM_LOCK                          = 0x8
+	RTM_LOSING                        = 0x5
+	RTM_MISS                          = 0x7
+	RTM_NEWADDR                       = 0xc
+	RTM_NEWMADDR                      = 0xf
+	RTM_OLDADD                        = 0x9
+	RTM_OLDDEL                        = 0xa
+	RTM_REDIRECT                      = 0x6
+	RTM_RESOLVE                       = 0xb
+	RTM_RTTUNIT                       = 0xf4240
+	RTM_VERSION                       = 0x6
+	RTV_EXPIRE                        = 0x4
+	RTV_HOPCOUNT                      = 0x2
+	RTV_IWCAPSEGS                     = 0x400
+	RTV_IWMAXSEGS                     = 0x200
+	RTV_MSL                           = 0x100
+	RTV_MTU                           = 0x1
+	RTV_RPIPE                         = 0x8
+	RTV_RTT                           = 0x40
+	RTV_RTTVAR                        = 0x80
+	RTV_SPIPE                         = 0x10
+	RTV_SSTHRESH                      = 0x20
+	RUSAGE_CHILDREN                   = -0x1
+	RUSAGE_SELF                       = 0x0
+	SCM_CREDS                         = 0x3
+	SCM_RIGHTS                        = 0x1
+	SCM_TIMESTAMP                     = 0x2
+	SHUT_RD                           = 0x0
+	SHUT_RDWR                         = 0x2
+	SHUT_WR                           = 0x1
+	SIOCADDMULTI                      = 0x80206931
+	SIOCADDRT                         = 0x8030720a
+	SIOCAIFADDR                       = 0x8040691a
+	SIOCALIFADDR                      = 0x8118691b
+	SIOCATMARK                        = 0x40047307
+	SIOCDELMULTI                      = 0x80206932
+	SIOCDELRT                         = 0x8030720b
+	SIOCDIFADDR                       = 0x80206919
+	SIOCDIFPHYADDR                    = 0x80206949
+	SIOCDLIFADDR                      = 0x8118691d
+	SIOCGDRVSPEC                      = 0xc01c697b
+	SIOCGETSGCNT                      = 0xc0147210
+	SIOCGETVIFCNT                     = 0xc014720f
+	SIOCGHIWAT                        = 0x40047301
+	SIOCGIFADDR                       = 0xc0206921
+	SIOCGIFBRDADDR                    = 0xc0206923
+	SIOCGIFCAP                        = 0xc020691f
+	SIOCGIFCONF                       = 0xc0086924
+	SIOCGIFDATA                       = 0xc0206926
+	SIOCGIFDSTADDR                    = 0xc0206922
+	SIOCGIFFLAGS                      = 0xc0206911
+	SIOCGIFGENERIC                    = 0xc020693a
+	SIOCGIFGMEMB                      = 0xc024698a
+	SIOCGIFINDEX                      = 0xc0206920
+	SIOCGIFMEDIA                      = 0xc0286938
+	SIOCGIFMETRIC                     = 0xc0206917
+	SIOCGIFMTU                        = 0xc0206933
+	SIOCGIFNETMASK                    = 0xc0206925
+	SIOCGIFPDSTADDR                   = 0xc0206948
+	SIOCGIFPHYS                       = 0xc0206935
+	SIOCGIFPOLLCPU                    = 0xc020697e
+	SIOCGIFPSRCADDR                   = 0xc0206947
+	SIOCGIFSTATUS                     = 0xc331693b
+	SIOCGIFTSOLEN                     = 0xc0206980
+	SIOCGLIFADDR                      = 0xc118691c
+	SIOCGLIFPHYADDR                   = 0xc118694b
+	SIOCGLOWAT                        = 0x40047303
+	SIOCGPGRP                         = 0x40047309
+	SIOCGPRIVATE_0                    = 0xc0206950
+	SIOCGPRIVATE_1                    = 0xc0206951
+	SIOCIFCREATE                      = 0xc020697a
+	SIOCIFCREATE2                     = 0xc020697c
+	SIOCIFDESTROY                     = 0x80206979
+	SIOCIFGCLONERS                    = 0xc00c6978
+	SIOCSDRVSPEC                      = 0x801c697b
+	SIOCSHIWAT                        = 0x80047300
+	SIOCSIFADDR                       = 0x8020690c
+	SIOCSIFBRDADDR                    = 0x80206913
+	SIOCSIFCAP                        = 0x8020691e
+	SIOCSIFDSTADDR                    = 0x8020690e
+	SIOCSIFFLAGS                      = 0x80206910
+	SIOCSIFGENERIC                    = 0x80206939
+	SIOCSIFLLADDR                     = 0x8020693c
+	SIOCSIFMEDIA                      = 0xc0206937
+	SIOCSIFMETRIC                     = 0x80206918
+	SIOCSIFMTU                        = 0x80206934
+	SIOCSIFNAME                       = 0x80206928
+	SIOCSIFNETMASK                    = 0x80206916
+	SIOCSIFPHYADDR                    = 0x80406946
+	SIOCSIFPHYS                       = 0x80206936
+	SIOCSIFPOLLCPU                    = 0x8020697d
+	SIOCSIFTSOLEN                     = 0x8020697f
+	SIOCSLIFPHYADDR                   = 0x8118694a
+	SIOCSLOWAT                        = 0x80047302
+	SIOCSPGRP                         = 0x80047308
+	SOCK_DGRAM                        = 0x2
+	SOCK_MAXADDRLEN                   = 0xff
+	SOCK_RAW                          = 0x3
+	SOCK_RDM                          = 0x4
+	SOCK_SEQPACKET                    = 0x5
+	SOCK_STREAM                       = 0x1
+	SOL_SOCKET                        = 0xffff
+	SOMAXCONN                         = 0x80
+	SO_ACCEPTCONN                     = 0x2
+	SO_ACCEPTFILTER                   = 0x1000
+	SO_BROADCAST                      = 0x20
+	SO_DEBUG                          = 0x1
+	SO_DONTROUTE                      = 0x10
+	SO_ERROR                          = 0x1007
+	SO_KEEPALIVE                      = 0x8
+	SO_LINGER                         = 0x80
+	SO_NOSIGPIPE                      = 0x800
+	SO_OOBINLINE                      = 0x100
+	SO_RCVBUF                         = 0x1002
+	SO_RCVLOWAT                       = 0x1004
+	SO_RCVTIMEO                       = 0x1006
+	SO_REUSEADDR                      = 0x4
+	SO_REUSEPORT                      = 0x200
+	SO_SNDBUF                         = 0x1001
+	SO_SNDLOWAT                       = 0x1003
+	SO_SNDSPACE                       = 0x100a
+	SO_SNDTIMEO                       = 0x1005
+	SO_TIMESTAMP                      = 0x400
+	SO_TYPE                           = 0x1008
+	SO_USELOOPBACK                    = 0x40
+	TCIFLUSH                          = 0x1
+	TCIOFLUSH                         = 0x3
+	TCOFLUSH                          = 0x2
+	TCP_FASTKEEP                      = 0x80
+	TCP_KEEPCNT                       = 0x400
+	TCP_KEEPIDLE                      = 0x100
+	TCP_KEEPINIT                      = 0x20
+	TCP_KEEPINTVL                     = 0x200
+	TCP_MAXBURST                      = 0x4
+	TCP_MAXHLEN                       = 0x3c
+	TCP_MAXOLEN                       = 0x28
+	TCP_MAXSEG                        = 0x2
+	TCP_MAXWIN                        = 0xffff
+	TCP_MAX_WINSHIFT                  = 0xe
+	TCP_MINMSS                        = 0x100
+	TCP_MIN_WINSHIFT                  = 0x5
+	TCP_MSS                           = 0x200
+	TCP_NODELAY                       = 0x1
+	TCP_NOOPT                         = 0x8
+	TCP_NOPUSH                        = 0x4
+	TCP_SIGNATURE_ENABLE              = 0x10
+	TCSAFLUSH                         = 0x2
+	TIOCCBRK                          = 0x2000747a
+	TIOCCDTR                          = 0x20007478
+	TIOCCONS                          = 0x80047462
+	TIOCDCDTIMESTAMP                  = 0x40087458
+	TIOCDRAIN                         = 0x2000745e
+	TIOCEXCL                          = 0x2000740d
+	TIOCEXT                           = 0x80047460
+	TIOCFLUSH                         = 0x80047410
+	TIOCGDRAINWAIT                    = 0x40047456
+	TIOCGETA                          = 0x402c7413
+	TIOCGETD                          = 0x4004741a
+	TIOCGPGRP                         = 0x40047477
+	TIOCGSID                          = 0x40047463
+	TIOCGSIZE                         = 0x40087468
+	TIOCGWINSZ                        = 0x40087468
+	TIOCISPTMASTER                    = 0x20007455
+	TIOCMBIC                          = 0x8004746b
+	TIOCMBIS                          = 0x8004746c
+	TIOCMGDTRWAIT                     = 0x4004745a
+	TIOCMGET                          = 0x4004746a
+	TIOCMODG                          = 0x40047403
+	TIOCMODS                          = 0x80047404
+	TIOCMSDTRWAIT                     = 0x8004745b
+	TIOCMSET                          = 0x8004746d
+	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                         = 0x20007471
+	TIOCNXCL                          = 0x2000740e
+	TIOCOUTQ                          = 0x40047473
+	TIOCPKT                           = 0x80047470
+	TIOCPKT_DATA                      = 0x0
+	TIOCPKT_DOSTOP                    = 0x20
+	TIOCPKT_FLUSHREAD                 = 0x1
+	TIOCPKT_FLUSHWRITE                = 0x2
+	TIOCPKT_IOCTL                     = 0x40
+	TIOCPKT_NOSTOP                    = 0x10
+	TIOCPKT_START                     = 0x8
+	TIOCPKT_STOP                      = 0x4
+	TIOCREMOTE                        = 0x80047469
+	TIOCSBRK                          = 0x2000747b
+	TIOCSCTTY                         = 0x20007461
+	TIOCSDRAINWAIT                    = 0x80047457
+	TIOCSDTR                          = 0x20007479
+	TIOCSETA                          = 0x802c7414
+	TIOCSETAF                         = 0x802c7416
+	TIOCSETAW                         = 0x802c7415
+	TIOCSETD                          = 0x8004741b
+	TIOCSIG                           = 0x2000745f
+	TIOCSPGRP                         = 0x80047476
+	TIOCSSIZE                         = 0x80087467
+	TIOCSTART                         = 0x2000746e
+	TIOCSTAT                          = 0x20007465
+	TIOCSTI                           = 0x80017472
+	TIOCSTOP                          = 0x2000746f
+	TIOCSWINSZ                        = 0x80087467
+	TIOCTIMESTAMP                     = 0x40087459
+	TIOCUCNTL                         = 0x80047466
+	TOSTOP                            = 0x400000
+	VCHECKPT                          = 0x13
+	VDISCARD                          = 0xf
+	VDSUSP                            = 0xb
+	VEOF                              = 0x0
+	VEOL                              = 0x1
+	VEOL2                             = 0x2
+	VERASE                            = 0x3
+	VERASE2                           = 0x7
+	VINTR                             = 0x8
+	VKILL                             = 0x5
+	VLNEXT                            = 0xe
+	VMIN                              = 0x10
+	VQUIT                             = 0x9
+	VREPRINT                          = 0x6
+	VSTART                            = 0xc
+	VSTATUS                           = 0x12
+	VSTOP                             = 0xd
+	VSUSP                             = 0xa
+	VTIME                             = 0x11
+	VWERASE                           = 0x4
+	WCONTINUED                        = 0x4
+	WCOREFLAG                         = 0x80
+	WLINUXCLONE                       = 0x80000000
+	WNOHANG                           = 0x1
+	WSTOPPED                          = 0x7f
+	WUNTRACED                         = 0x2
+)
+
+// Errors
+const (
+	E2BIG           = Errno(0x7)
+	EACCES          = Errno(0xd)
+	EADDRINUSE      = Errno(0x30)
+	EADDRNOTAVAIL   = Errno(0x31)
+	EAFNOSUPPORT    = Errno(0x2f)
+	EAGAIN          = Errno(0x23)
+	EALREADY        = Errno(0x25)
+	EASYNC          = Errno(0x63)
+	EAUTH           = Errno(0x50)
+	EBADF           = Errno(0x9)
+	EBADMSG         = Errno(0x59)
+	EBADRPC         = Errno(0x48)
+	EBUSY           = Errno(0x10)
+	ECANCELED       = Errno(0x55)
+	ECHILD          = Errno(0xa)
+	ECONNABORTED    = Errno(0x35)
+	ECONNREFUSED    = Errno(0x3d)
+	ECONNRESET      = Errno(0x36)
+	EDEADLK         = Errno(0xb)
+	EDESTADDRREQ    = Errno(0x27)
+	EDOM            = Errno(0x21)
+	EDOOFUS         = Errno(0x58)
+	EDQUOT          = Errno(0x45)
+	EEXIST          = Errno(0x11)
+	EFAULT          = Errno(0xe)
+	EFBIG           = Errno(0x1b)
+	EFTYPE          = Errno(0x4f)
+	EHOSTDOWN       = Errno(0x40)
+	EHOSTUNREACH    = Errno(0x41)
+	EIDRM           = Errno(0x52)
+	EILSEQ          = Errno(0x56)
+	EINPROGRESS     = Errno(0x24)
+	EINTR           = Errno(0x4)
+	EINVAL          = Errno(0x16)
+	EIO             = Errno(0x5)
+	EISCONN         = Errno(0x38)
+	EISDIR          = Errno(0x15)
+	ELAST           = Errno(0x63)
+	ELOOP           = Errno(0x3e)
+	EMFILE          = Errno(0x18)
+	EMLINK          = Errno(0x1f)
+	EMSGSIZE        = Errno(0x28)
+	EMULTIHOP       = Errno(0x5a)
+	ENAMETOOLONG    = Errno(0x3f)
+	ENEEDAUTH       = Errno(0x51)
+	ENETDOWN        = Errno(0x32)
+	ENETRESET       = Errno(0x34)
+	ENETUNREACH     = Errno(0x33)
+	ENFILE          = Errno(0x17)
+	ENOATTR         = Errno(0x57)
+	ENOBUFS         = Errno(0x37)
+	ENODEV          = Errno(0x13)
+	ENOENT          = Errno(0x2)
+	ENOEXEC         = Errno(0x8)
+	ENOLCK          = Errno(0x4d)
+	ENOLINK         = Errno(0x5b)
+	ENOMEDIUM       = Errno(0x5d)
+	ENOMEM          = Errno(0xc)
+	ENOMSG          = Errno(0x53)
+	ENOPROTOOPT     = Errno(0x2a)
+	ENOSPC          = Errno(0x1c)
+	ENOSYS          = Errno(0x4e)
+	ENOTBLK         = Errno(0xf)
+	ENOTCONN        = Errno(0x39)
+	ENOTDIR         = Errno(0x14)
+	ENOTEMPTY       = Errno(0x42)
+	ENOTSOCK        = Errno(0x26)
+	ENOTSUP         = Errno(0x2d)
+	ENOTTY          = Errno(0x19)
+	ENXIO           = Errno(0x6)
+	EOPNOTSUPP      = Errno(0x2d)
+	EOVERFLOW       = Errno(0x54)
+	EPERM           = Errno(0x1)
+	EPFNOSUPPORT    = Errno(0x2e)
+	EPIPE           = Errno(0x20)
+	EPROCLIM        = Errno(0x43)
+	EPROCUNAVAIL    = Errno(0x4c)
+	EPROGMISMATCH   = Errno(0x4b)
+	EPROGUNAVAIL    = Errno(0x4a)
+	EPROTO          = Errno(0x5c)
+	EPROTONOSUPPORT = Errno(0x2b)
+	EPROTOTYPE      = Errno(0x29)
+	ERANGE          = Errno(0x22)
+	EREMOTE         = Errno(0x47)
+	EROFS           = Errno(0x1e)
+	ERPCMISMATCH    = Errno(0x49)
+	ESHUTDOWN       = Errno(0x3a)
+	ESOCKTNOSUPPORT = Errno(0x2c)
+	ESPIPE          = Errno(0x1d)
+	ESRCH           = Errno(0x3)
+	ESTALE          = Errno(0x46)
+	ETIMEDOUT       = Errno(0x3c)
+	ETOOMANYREFS    = Errno(0x3b)
+	ETXTBSY         = Errno(0x1a)
+	EUNUSED94       = Errno(0x5e)
+	EUNUSED95       = Errno(0x5f)
+	EUNUSED96       = Errno(0x60)
+	EUNUSED97       = Errno(0x61)
+	EUNUSED98       = Errno(0x62)
+	EUSERS          = Errno(0x44)
+	EWOULDBLOCK     = Errno(0x23)
+	EXDEV           = Errno(0x12)
+)
+
+// Signals
+const (
+	SIGABRT     = Signal(0x6)
+	SIGALRM     = Signal(0xe)
+	SIGBUS      = Signal(0xa)
+	SIGCHLD     = Signal(0x14)
+	SIGCKPT     = Signal(0x21)
+	SIGCKPTEXIT = Signal(0x22)
+	SIGCONT     = Signal(0x13)
+	SIGEMT      = Signal(0x7)
+	SIGFPE      = Signal(0x8)
+	SIGHUP      = Signal(0x1)
+	SIGILL      = Signal(0x4)
+	SIGINFO     = Signal(0x1d)
+	SIGINT      = Signal(0x2)
+	SIGIO       = Signal(0x17)
+	SIGIOT      = Signal(0x6)
+	SIGKILL     = Signal(0x9)
+	SIGPIPE     = Signal(0xd)
+	SIGPROF     = Signal(0x1b)
+	SIGQUIT     = Signal(0x3)
+	SIGSEGV     = Signal(0xb)
+	SIGSTOP     = Signal(0x11)
+	SIGSYS      = Signal(0xc)
+	SIGTERM     = Signal(0xf)
+	SIGTHR      = Signal(0x20)
+	SIGTRAP     = Signal(0x5)
+	SIGTSTP     = Signal(0x12)
+	SIGTTIN     = Signal(0x15)
+	SIGTTOU     = Signal(0x16)
+	SIGURG      = Signal(0x10)
+	SIGUSR1     = Signal(0x1e)
+	SIGUSR2     = Signal(0x1f)
+	SIGVTALRM   = Signal(0x1a)
+	SIGWINCH    = Signal(0x1c)
+	SIGXCPU     = Signal(0x18)
+	SIGXFSZ     = Signal(0x19)
+)
+
+// Error table
+var errors = [...]string{
+	1:  "operation not permitted",
+	2:  "no such file or directory",
+	3:  "no such process",
+	4:  "interrupted system call",
+	5:  "input/output error",
+	6:  "device not configured",
+	7:  "argument list too long",
+	8:  "exec format error",
+	9:  "bad file descriptor",
+	10: "no child processes",
+	11: "resource deadlock avoided",
+	12: "cannot allocate memory",
+	13: "permission denied",
+	14: "bad address",
+	15: "block device required",
+	16: "device busy",
+	17: "file exists",
+	18: "cross-device link",
+	19: "operation not supported by device",
+	20: "not a directory",
+	21: "is a directory",
+	22: "invalid argument",
+	23: "too many open files in system",
+	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: "numerical argument out of domain",
+	34: "result too large",
+	35: "resource temporarily unavailable",
+	36: "operation now in progress",
+	37: "operation already in progress",
+	38: "socket operation on non-socket",
+	39: "destination address required",
+	40: "message too long",
+	41: "protocol wrong type for socket",
+	42: "protocol not available",
+	43: "protocol not supported",
+	44: "socket type not supported",
+	45: "operation not supported",
+	46: "protocol family not supported",
+	47: "address family not supported by protocol family",
+	48: "address already in use",
+	49: "can't assign requested address",
+	50: "network is down",
+	51: "network is unreachable",
+	52: "network dropped connection on reset",
+	53: "software caused connection abort",
+	54: "connection reset by peer",
+	55: "no buffer space available",
+	56: "socket is already connected",
+	57: "socket is not connected",
+	58: "can't send after socket shutdown",
+	59: "too many references: can't splice",
+	60: "operation timed out",
+	61: "connection refused",
+	62: "too many levels of symbolic links",
+	63: "file name too long",
+	64: "host is down",
+	65: "no route to host",
+	66: "directory not empty",
+	67: "too many processes",
+	68: "too many users",
+	69: "disc quota exceeded",
+	70: "stale NFS file handle",
+	71: "too many levels of remote in path",
+	72: "RPC struct is bad",
+	73: "RPC version wrong",
+	74: "RPC prog. not avail",
+	75: "program version wrong",
+	76: "bad procedure for program",
+	77: "no locks available",
+	78: "function not implemented",
+	79: "inappropriate file type or format",
+	80: "authentication error",
+	81: "need authenticator",
+	82: "identifier removed",
+	83: "no message of desired type",
+	84: "value too large to be stored in data type",
+	85: "operation canceled",
+	86: "illegal byte sequence",
+	87: "attribute not found",
+	88: "programming error",
+	89: "bad message",
+	90: "multihop attempted",
+	91: "link has been severed",
+	92: "protocol error",
+	93: "no medium found",
+	94: "unknown error: 94",
+	95: "unknown error: 95",
+	96: "unknown error: 96",
+	97: "unknown error: 97",
+	98: "unknown error: 98",
+	99: "unknown error: 99",
+}
+
+// Signal table
+var signals = [...]string{
+	1:  "hangup",
+	2:  "interrupt",
+	3:  "quit",
+	4:  "illegal instruction",
+	5:  "trace/BPT trap",
+	6:  "abort trap",
+	7:  "EMT trap",
+	8:  "floating point exception",
+	9:  "killed",
+	10: "bus error",
+	11: "segmentation fault",
+	12: "bad system call",
+	13: "broken pipe",
+	14: "alarm clock",
+	15: "terminated",
+	16: "urgent I/O condition",
+	17: "suspended (signal)",
+	18: "suspended",
+	19: "continued",
+	20: "child exited",
+	21: "stopped (tty input)",
+	22: "stopped (tty output)",
+	23: "I/O possible",
+	24: "cputime limit exceeded",
+	25: "filesize limit exceeded",
+	26: "virtual timer expired",
+	27: "profiling timer expired",
+	28: "window size changes",
+	29: "information request",
+	30: "user defined signal 1",
+	31: "user defined signal 2",
+	32: "thread Scheduler",
+	33: "checkPoint",
+	34: "checkPointExit",
+}
diff --git a/src/syscall/zerrors_dragonfly_amd64.go b/src/syscall/zerrors_dragonfly_amd64.go
index 15d300f..59bff75 100644
--- a/src/syscall/zerrors_dragonfly_amd64.go
+++ b/src/syscall/zerrors_dragonfly_amd64.go
@@ -4,8 +4,6 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs -- -m64 _const.go
 
-// +build amd64,dragonfly
-
 package syscall
 
 const (
diff --git a/src/syscall/zerrors_freebsd_386.go b/src/syscall/zerrors_freebsd_386.go
index bbad05f..cd3aa80 100644
--- a/src/syscall/zerrors_freebsd_386.go
+++ b/src/syscall/zerrors_freebsd_386.go
@@ -4,8 +4,6 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs -- -m32 _const.go
 
-// +build 386,freebsd
-
 package syscall
 
 const (
diff --git a/src/syscall/zerrors_freebsd_amd64.go b/src/syscall/zerrors_freebsd_amd64.go
index b36125b..9edce6e 100644
--- a/src/syscall/zerrors_freebsd_amd64.go
+++ b/src/syscall/zerrors_freebsd_amd64.go
@@ -4,8 +4,6 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs -- -m64 _const.go
 
-// +build amd64,freebsd
-
 package syscall
 
 const (
diff --git a/src/syscall/zerrors_freebsd_arm.go b/src/syscall/zerrors_freebsd_arm.go
index 0c844f1..f29dd05 100644
--- a/src/syscall/zerrors_freebsd_arm.go
+++ b/src/syscall/zerrors_freebsd_arm.go
@@ -4,8 +4,6 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs -- _const.go
 
-// +build arm,freebsd
-
 package syscall
 
 const (
diff --git a/src/syscall/zerrors_linux_386.go b/src/syscall/zerrors_linux_386.go
index d433a4f..7aa8ff0 100644
--- a/src/syscall/zerrors_linux_386.go
+++ b/src/syscall/zerrors_linux_386.go
@@ -4,8 +4,6 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs -- -m32 _const.go
 
-// +build 386,linux
-
 package syscall
 
 const (
diff --git a/src/syscall/zerrors_linux_amd64.go b/src/syscall/zerrors_linux_amd64.go
index dd86a3b..94d051d 100644
--- a/src/syscall/zerrors_linux_amd64.go
+++ b/src/syscall/zerrors_linux_amd64.go
@@ -4,8 +4,6 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs -- -m64 _const.go
 
-// +build amd64,linux
-
 package syscall
 
 const (
diff --git a/src/syscall/zerrors_linux_arm.go b/src/syscall/zerrors_linux_arm.go
index 2a9c0f9..dcaaef7 100644
--- a/src/syscall/zerrors_linux_arm.go
+++ b/src/syscall/zerrors_linux_arm.go
@@ -4,8 +4,6 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs -- _const.go
 
-// +build arm,linux
-
 package syscall
 
 const (
diff --git a/src/syscall/zerrors_netbsd_386.go b/src/syscall/zerrors_netbsd_386.go
index 6f32def..1e3dff7 100644
--- a/src/syscall/zerrors_netbsd_386.go
+++ b/src/syscall/zerrors_netbsd_386.go
@@ -4,8 +4,6 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs -- -m32 _const.go
 
-// +build 386,netbsd
-
 package syscall
 
 const (
diff --git a/src/syscall/zerrors_netbsd_amd64.go b/src/syscall/zerrors_netbsd_amd64.go
index a6d1701..1469d00 100644
--- a/src/syscall/zerrors_netbsd_amd64.go
+++ b/src/syscall/zerrors_netbsd_amd64.go
@@ -4,8 +4,6 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs -- -m64 _const.go
 
-// +build amd64,netbsd
-
 package syscall
 
 const (
diff --git a/src/syscall/zerrors_netbsd_arm.go b/src/syscall/zerrors_netbsd_arm.go
index 7f99279..1a88c0d 100644
--- a/src/syscall/zerrors_netbsd_arm.go
+++ b/src/syscall/zerrors_netbsd_arm.go
@@ -4,8 +4,6 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs -- -marm _const.go
 
-// +build arm,netbsd
-
 package syscall
 
 const (
diff --git a/src/syscall/zerrors_openbsd_386.go b/src/syscall/zerrors_openbsd_386.go
index 540d310..0829834 100644
--- a/src/syscall/zerrors_openbsd_386.go
+++ b/src/syscall/zerrors_openbsd_386.go
@@ -4,8 +4,6 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs -- -m32 _const.go
 
-// +build 386,openbsd
-
 package syscall
 
 const (
diff --git a/src/syscall/zerrors_openbsd_amd64.go b/src/syscall/zerrors_openbsd_amd64.go
index ae5b8c9..e9fa37c 100644
--- a/src/syscall/zerrors_openbsd_amd64.go
+++ b/src/syscall/zerrors_openbsd_amd64.go
@@ -4,8 +4,6 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs -- -m64 _const.go
 
-// +build amd64,openbsd
-
 package syscall
 
 const (
diff --git a/src/syscall/zerrors_plan9_386.go b/src/syscall/zerrors_plan9_386.go
new file mode 100644
index 0000000..ede3d6a
--- /dev/null
+++ b/src/syscall/zerrors_plan9_386.go
@@ -0,0 +1,48 @@
+// 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
+
+// Constants
+const (
+	// Invented values to support what package os expects.
+	O_CREAT    = 0x02000
+	O_APPEND   = 0x00400
+	O_NOCTTY   = 0x00000
+	O_NONBLOCK = 0x00000
+	O_SYNC     = 0x00000
+	O_ASYNC    = 0x00000
+
+	S_IFMT   = 0x1f000
+	S_IFIFO  = 0x1000
+	S_IFCHR  = 0x2000
+	S_IFDIR  = 0x4000
+	S_IFBLK  = 0x6000
+	S_IFREG  = 0x8000
+	S_IFLNK  = 0xa000
+	S_IFSOCK = 0xc000
+)
+
+// Errors
+var (
+	EINVAL       = NewError("bad arg in system call")
+	ENOTDIR      = NewError("not a directory")
+	EISDIR       = NewError("file is a directory")
+	ENOENT       = NewError("file does not exist")
+	EEXIST       = NewError("file already exists")
+	EMFILE       = NewError("no free file descriptors")
+	EIO          = NewError("i/o error")
+	ENAMETOOLONG = NewError("file name too long")
+	EINTR        = NewError("interrupted")
+	EPERM        = NewError("permission denied")
+	EBUSY        = NewError("no free devices")
+	ETIMEDOUT    = NewError("connection timed out")
+	EPLAN9       = NewError("not supported by plan 9")
+
+	// The following errors do not correspond to any
+	// Plan 9 system messages. Invented to support
+	// what package os and others expect.
+	EACCES       = NewError("access permission denied")
+	EAFNOSUPPORT = NewError("address family not supported by protocol")
+)
diff --git a/src/syscall/zerrors_plan9_amd64.go b/src/syscall/zerrors_plan9_amd64.go
new file mode 100644
index 0000000..ede3d6a
--- /dev/null
+++ b/src/syscall/zerrors_plan9_amd64.go
@@ -0,0 +1,48 @@
+// 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
+
+// Constants
+const (
+	// Invented values to support what package os expects.
+	O_CREAT    = 0x02000
+	O_APPEND   = 0x00400
+	O_NOCTTY   = 0x00000
+	O_NONBLOCK = 0x00000
+	O_SYNC     = 0x00000
+	O_ASYNC    = 0x00000
+
+	S_IFMT   = 0x1f000
+	S_IFIFO  = 0x1000
+	S_IFCHR  = 0x2000
+	S_IFDIR  = 0x4000
+	S_IFBLK  = 0x6000
+	S_IFREG  = 0x8000
+	S_IFLNK  = 0xa000
+	S_IFSOCK = 0xc000
+)
+
+// Errors
+var (
+	EINVAL       = NewError("bad arg in system call")
+	ENOTDIR      = NewError("not a directory")
+	EISDIR       = NewError("file is a directory")
+	ENOENT       = NewError("file does not exist")
+	EEXIST       = NewError("file already exists")
+	EMFILE       = NewError("no free file descriptors")
+	EIO          = NewError("i/o error")
+	ENAMETOOLONG = NewError("file name too long")
+	EINTR        = NewError("interrupted")
+	EPERM        = NewError("permission denied")
+	EBUSY        = NewError("no free devices")
+	ETIMEDOUT    = NewError("connection timed out")
+	EPLAN9       = NewError("not supported by plan 9")
+
+	// The following errors do not correspond to any
+	// Plan 9 system messages. Invented to support
+	// what package os and others expect.
+	EACCES       = NewError("access permission denied")
+	EAFNOSUPPORT = NewError("address family not supported by protocol")
+)
diff --git a/src/syscall/zerrors_solaris_amd64.go b/src/syscall/zerrors_solaris_amd64.go
index 62ec81b..3f4cbfd 100644
--- a/src/syscall/zerrors_solaris_amd64.go
+++ b/src/syscall/zerrors_solaris_amd64.go
@@ -4,8 +4,6 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs -- -m64 _const.go
 
-// +build amd64,solaris
-
 package syscall
 
 const (
diff --git a/src/syscall/zsyscall_darwin_386.go b/src/syscall/zsyscall_darwin_386.go
index 23e7b5e..934565f 100644
--- a/src/syscall/zsyscall_darwin_386.go
+++ b/src/syscall/zsyscall_darwin_386.go
@@ -1,8 +1,6 @@
 // mksyscall.pl -l32 syscall_bsd.go syscall_darwin.go syscall_darwin_386.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
-// +build 386,darwin
-
 package syscall
 
 import "unsafe"
@@ -13,7 +11,7 @@ func getgroups(ngid int, gid *_Gid_t) (n int, err error) {
 	r0, _, e1 := RawSyscall(SYS_GETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -23,7 +21,7 @@ func getgroups(ngid int, gid *_Gid_t) (n int, err error) {
 func setgroups(ngid int, gid *_Gid_t) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -34,7 +32,7 @@ func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err
 	r0, _, e1 := Syscall6(SYS_WAIT4, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0)
 	wpid = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -45,7 +43,7 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
 	r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	fd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -55,7 +53,7 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -65,7 +63,7 @@ func bind(s int, addr unsafe.Pointer, 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -76,7 +74,7 @@ func socket(domain int, typ int, proto int) (fd int, err error) {
 	r0, _, e1 := RawSyscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto))
 	fd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -86,7 +84,7 @@ func socket(domain int, typ int, proto int) (fd int, 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -96,7 +94,7 @@ func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen
 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -106,7 +104,7 @@ func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr)
 func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETPEERNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -116,7 +114,7 @@ func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETSOCKNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -126,7 +124,7 @@ func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 func Shutdown(s int, how int) (err error) {
 	_, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(s), uintptr(how), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -136,7 +134,7 @@ func Shutdown(s int, how int) (err error) {
 func socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) {
 	_, _, e1 := RawSyscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -153,7 +151,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
 	r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -169,7 +167,7 @@ func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (
 	}
 	_, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -180,7 +178,7 @@ func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -191,7 +189,7 @@ 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -202,7 +200,7 @@ func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, ne
 	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 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -218,7 +216,7 @@ func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr)
 	}
 	_, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -234,7 +232,7 @@ func utimes(path string, timeval *[2]Timeval) (err error) {
 	_, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -244,7 +242,7 @@ func utimes(path string, timeval *[2]Timeval) (err error) {
 func futimes(fd int, timeval *[2]Timeval) (err error) {
 	_, _, e1 := Syscall(SYS_FUTIMES, uintptr(fd), uintptr(unsafe.Pointer(timeval)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -255,7 +253,7 @@ func fcntl(fd int, cmd int, arg int) (val int, err error) {
 	r0, _, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg))
 	val = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -265,7 +263,7 @@ func fcntl(fd int, cmd int, arg int) (val int, err error) {
 func ptrace(request int, pid int, addr uintptr, data uintptr) (err error) {
 	_, _, e1 := Syscall6(SYS_PTRACE, uintptr(request), uintptr(pid), uintptr(addr), uintptr(data), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -277,7 +275,7 @@ func pipe() (r int, w int, err error) {
 	r = int(r0)
 	w = int(r1)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -287,7 +285,7 @@ func pipe() (r int, w int, err error) {
 func kill(pid int, signum int, posix int) (err error) {
 	_, _, e1 := Syscall(SYS_KILL, uintptr(pid), uintptr(signum), uintptr(posix))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -303,7 +301,7 @@ func Access(path string, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -313,7 +311,7 @@ func Access(path string, mode uint32) (err error) {
 func Adjtime(delta *Timeval, olddelta *Timeval) (err error) {
 	_, _, e1 := Syscall(SYS_ADJTIME, uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -329,7 +327,7 @@ func Chdir(path string) (err error) {
 	_, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -345,7 +343,7 @@ func Chflags(path string, flags int) (err error) {
 	_, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -361,7 +359,7 @@ func Chmod(path string, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -377,7 +375,7 @@ func Chown(path string, uid int, gid int) (err error) {
 	_, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -393,7 +391,7 @@ func Chroot(path string) (err error) {
 	_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -403,7 +401,7 @@ func Chroot(path string) (err error) {
 func Close(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -411,10 +409,10 @@ func Close(fd int) (err error) {
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
 func Dup(fd int) (nfd int, err error) {
-	r0, _, e1 := Syscall(SYS_DUP, uintptr(fd), 0, 0)
+	r0, _, e1 := RawSyscall(SYS_DUP, uintptr(fd), 0, 0)
 	nfd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -422,9 +420,9 @@ func Dup(fd int) (nfd int, err error) {
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
 func Dup2(from int, to int) (err error) {
-	_, _, e1 := Syscall(SYS_DUP2, uintptr(from), uintptr(to), 0)
+	_, _, e1 := RawSyscall(SYS_DUP2, uintptr(from), uintptr(to), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -446,7 +444,7 @@ func Exchangedata(path1 string, path2 string, options int) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -463,7 +461,7 @@ func Exit(code int) {
 func Fchdir(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -473,7 +471,7 @@ func Fchdir(fd int) (err error) {
 func Fchflags(fd int, flags int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(fd), uintptr(flags), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -483,7 +481,7 @@ func Fchflags(fd int, flags int) (err error) {
 func Fchmod(fd int, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -493,7 +491,7 @@ func Fchmod(fd int, mode uint32) (err error) {
 func Fchown(fd int, uid int, gid int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -503,7 +501,7 @@ func Fchown(fd int, uid int, gid int) (err error) {
 func Flock(fd int, how int) (err error) {
 	_, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -514,7 +512,7 @@ func Fpathconf(fd int, name int) (val int, err error) {
 	r0, _, e1 := Syscall(SYS_FPATHCONF, uintptr(fd), uintptr(name), 0)
 	val = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -524,7 +522,7 @@ func Fpathconf(fd int, name int) (val int, err error) {
 func Fstat(fd int, stat *Stat_t) (err error) {
 	_, _, e1 := Syscall(SYS_FSTAT64, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -534,7 +532,7 @@ func Fstat(fd int, stat *Stat_t) (err error) {
 func Fstatfs(fd int, stat *Statfs_t) (err error) {
 	_, _, e1 := Syscall(SYS_FSTATFS64, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -544,7 +542,7 @@ func Fstatfs(fd int, stat *Statfs_t) (err error) {
 func Fsync(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -554,7 +552,7 @@ func Fsync(fd int) (err error) {
 func Ftruncate(fd int, length int64) (err error) {
 	_, _, e1 := Syscall(SYS_FTRUNCATE, uintptr(fd), uintptr(length), uintptr(length>>32))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -571,7 +569,7 @@ func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
 	r0, _, e1 := Syscall6(SYS_GETDIRENTRIES64, uintptr(fd), uintptr(_p0), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -614,7 +612,7 @@ func Getpgid(pid int) (pgid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0)
 	pgid = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -649,7 +647,7 @@ func Getpriority(which int, who int) (prio int, err error) {
 	r0, _, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0)
 	prio = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -659,7 +657,7 @@ func Getpriority(which int, who int) (prio int, err error) {
 func Getrlimit(which int, lim *Rlimit) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -669,7 +667,7 @@ func Getrlimit(which int, lim *Rlimit) (err error) {
 func Getrusage(who int, rusage *Rusage) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -680,7 +678,7 @@ func Getsid(pid int) (sid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0)
 	sid = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -707,7 +705,7 @@ func Kqueue() (fd int, err error) {
 	r0, _, e1 := Syscall(SYS_KQUEUE, 0, 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -723,7 +721,7 @@ func Lchown(path string, uid int, gid int) (err error) {
 	_, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -745,7 +743,7 @@ func Link(path string, link string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -755,7 +753,7 @@ func Link(path string, link string) (err error) {
 func Listen(s int, backlog int) (err error) {
 	_, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(backlog), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -771,7 +769,7 @@ func Lstat(path string, stat *Stat_t) (err error) {
 	_, _, e1 := Syscall(SYS_LSTAT64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -787,7 +785,7 @@ func Mkdir(path string, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -803,7 +801,7 @@ func Mkfifo(path string, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -819,7 +817,7 @@ func Mknod(path string, mode uint32, dev int) (err error) {
 	_, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -835,7 +833,7 @@ func Mlock(b []byte) (err error) {
 	}
 	_, _, e1 := Syscall(SYS_MLOCK, uintptr(_p0), uintptr(len(b)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -845,7 +843,7 @@ func Mlock(b []byte) (err error) {
 func Mlockall(flags int) (err error) {
 	_, _, e1 := Syscall(SYS_MLOCKALL, uintptr(flags), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -861,7 +859,7 @@ func Mprotect(b []byte, prot int) (err error) {
 	}
 	_, _, e1 := Syscall(SYS_MPROTECT, uintptr(_p0), uintptr(len(b)), uintptr(prot))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -877,7 +875,7 @@ func Munlock(b []byte) (err error) {
 	}
 	_, _, e1 := Syscall(SYS_MUNLOCK, uintptr(_p0), uintptr(len(b)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -887,7 +885,7 @@ func Munlock(b []byte) (err error) {
 func Munlockall() (err error) {
 	_, _, e1 := Syscall(SYS_MUNLOCKALL, 0, 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -904,7 +902,7 @@ func Open(path string, mode int, perm uint32) (fd int, err error) {
 	use(unsafe.Pointer(_p0))
 	fd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -921,7 +919,7 @@ func Pathconf(path string, name int) (val int, err error) {
 	use(unsafe.Pointer(_p0))
 	val = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -938,7 +936,7 @@ func Pread(fd int, p []byte, offset int64) (n int, err error) {
 	r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -955,7 +953,7 @@ func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
 	r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -972,7 +970,7 @@ func read(fd int, p []byte) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -995,7 +993,7 @@ func Readlink(path string, buf []byte) (n int, err error) {
 	use(unsafe.Pointer(_p0))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1017,7 +1015,7 @@ func Rename(from string, to string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1033,7 +1031,7 @@ func Revoke(path string) (err error) {
 	_, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1049,7 +1047,7 @@ func Rmdir(path string) (err error) {
 	_, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1060,7 +1058,7 @@ 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)
 	newoffset = int64(int64(r1)<<32 | int64(r0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1070,7 +1068,7 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
 func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error) {
 	_, _, e1 := Syscall6(SYS_SELECT, uintptr(n), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1080,7 +1078,7 @@ func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error) {
 func Setegid(egid int) (err error) {
 	_, _, e1 := Syscall(SYS_SETEGID, uintptr(egid), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1090,7 +1088,7 @@ func Setegid(egid int) (err error) {
 func Seteuid(euid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETEUID, uintptr(euid), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1100,7 +1098,7 @@ func Seteuid(euid int) (err error) {
 func Setgid(gid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETGID, uintptr(gid), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1116,7 +1114,7 @@ func Setlogin(name string) (err error) {
 	_, _, e1 := Syscall(SYS_SETLOGIN, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1126,7 +1124,7 @@ func Setlogin(name string) (err error) {
 func Setpgid(pid int, pgid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1136,7 +1134,7 @@ func Setpgid(pid int, pgid int) (err error) {
 func Setpriority(which int, who int, prio int) (err error) {
 	_, _, e1 := Syscall(SYS_SETPRIORITY, uintptr(which), uintptr(who), uintptr(prio))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1146,7 +1144,7 @@ func Setpriority(which int, who int, prio int) (err error) {
 func Setprivexec(flag int) (err error) {
 	_, _, e1 := Syscall(SYS_SETPRIVEXEC, uintptr(flag), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1156,7 +1154,7 @@ func Setprivexec(flag int) (err error) {
 func Setregid(rgid int, egid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1166,7 +1164,7 @@ func Setregid(rgid int, egid int) (err error) {
 func Setreuid(ruid int, euid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1176,7 +1174,7 @@ func Setreuid(ruid int, euid int) (err error) {
 func Setrlimit(which int, lim *Rlimit) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1187,7 +1185,7 @@ func Setsid() (pid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0)
 	pid = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1197,7 +1195,7 @@ func Setsid() (pid int, err error) {
 func Settimeofday(tp *Timeval) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1207,7 +1205,7 @@ func Settimeofday(tp *Timeval) (err error) {
 func Setuid(uid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETUID, uintptr(uid), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1223,7 +1221,7 @@ func Stat(path string, stat *Stat_t) (err error) {
 	_, _, e1 := Syscall(SYS_STAT64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1239,7 +1237,7 @@ func Statfs(path string, stat *Statfs_t) (err error) {
 	_, _, e1 := Syscall(SYS_STATFS64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1261,7 +1259,7 @@ func Symlink(path string, link string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1271,7 +1269,7 @@ func Symlink(path string, link string) (err error) {
 func Sync() (err error) {
 	_, _, e1 := Syscall(SYS_SYNC, 0, 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1287,7 +1285,7 @@ func Truncate(path string, length int64) (err error) {
 	_, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), uintptr(length), uintptr(length>>32))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1311,7 +1309,7 @@ func Undelete(path string) (err error) {
 	_, _, e1 := Syscall(SYS_UNDELETE, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1327,7 +1325,7 @@ func Unlink(path string) (err error) {
 	_, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1343,7 +1341,7 @@ func Unmount(path string, flags int) (err error) {
 	_, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1360,7 +1358,7 @@ func write(fd int, p []byte) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1371,7 +1369,7 @@ func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (
 	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)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1381,7 +1379,7 @@ func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (
 func munmap(addr uintptr, length uintptr) (err error) {
 	_, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1392,7 +1390,7 @@ 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1403,7 +1401,7 @@ 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1415,7 +1413,7 @@ func gettimeofday(tp *Timeval) (sec int32, usec int32, err error) {
 	sec = int32(r0)
 	usec = int32(r1)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
diff --git a/src/syscall/zsyscall_darwin_amd64.go b/src/syscall/zsyscall_darwin_amd64.go
index 6e63d9a..75cf251 100644
--- a/src/syscall/zsyscall_darwin_amd64.go
+++ b/src/syscall/zsyscall_darwin_amd64.go
@@ -1,8 +1,6 @@
 // mksyscall.pl syscall_bsd.go syscall_darwin.go syscall_darwin_amd64.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
-// +build amd64,darwin
-
 package syscall
 
 import "unsafe"
@@ -13,7 +11,7 @@ func getgroups(ngid int, gid *_Gid_t) (n int, err error) {
 	r0, _, e1 := RawSyscall(SYS_GETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -23,7 +21,7 @@ func getgroups(ngid int, gid *_Gid_t) (n int, err error) {
 func setgroups(ngid int, gid *_Gid_t) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -34,7 +32,7 @@ func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err
 	r0, _, e1 := Syscall6(SYS_WAIT4, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0)
 	wpid = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -45,7 +43,7 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
 	r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	fd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -55,7 +53,7 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -65,7 +63,7 @@ func bind(s int, addr unsafe.Pointer, 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -76,7 +74,7 @@ func socket(domain int, typ int, proto int) (fd int, err error) {
 	r0, _, e1 := RawSyscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto))
 	fd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -86,7 +84,7 @@ func socket(domain int, typ int, proto int) (fd int, 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -96,7 +94,7 @@ func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen
 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -106,7 +104,7 @@ func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr)
 func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETPEERNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -116,7 +114,7 @@ func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETSOCKNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -126,7 +124,7 @@ func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 func Shutdown(s int, how int) (err error) {
 	_, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(s), uintptr(how), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -136,7 +134,7 @@ func Shutdown(s int, how int) (err error) {
 func socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) {
 	_, _, e1 := RawSyscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -153,7 +151,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
 	r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -169,7 +167,7 @@ func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (
 	}
 	_, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -180,7 +178,7 @@ func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -191,7 +189,7 @@ 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -202,7 +200,7 @@ func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, ne
 	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 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -218,7 +216,7 @@ func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr)
 	}
 	_, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -234,7 +232,7 @@ func utimes(path string, timeval *[2]Timeval) (err error) {
 	_, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -244,7 +242,7 @@ func utimes(path string, timeval *[2]Timeval) (err error) {
 func futimes(fd int, timeval *[2]Timeval) (err error) {
 	_, _, e1 := Syscall(SYS_FUTIMES, uintptr(fd), uintptr(unsafe.Pointer(timeval)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -255,7 +253,7 @@ func fcntl(fd int, cmd int, arg int) (val int, err error) {
 	r0, _, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg))
 	val = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -265,7 +263,7 @@ func fcntl(fd int, cmd int, arg int) (val int, err error) {
 func ptrace(request int, pid int, addr uintptr, data uintptr) (err error) {
 	_, _, e1 := Syscall6(SYS_PTRACE, uintptr(request), uintptr(pid), uintptr(addr), uintptr(data), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -277,7 +275,7 @@ func pipe() (r int, w int, err error) {
 	r = int(r0)
 	w = int(r1)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -287,7 +285,7 @@ func pipe() (r int, w int, err error) {
 func kill(pid int, signum int, posix int) (err error) {
 	_, _, e1 := Syscall(SYS_KILL, uintptr(pid), uintptr(signum), uintptr(posix))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -303,7 +301,7 @@ func Access(path string, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -313,7 +311,7 @@ func Access(path string, mode uint32) (err error) {
 func Adjtime(delta *Timeval, olddelta *Timeval) (err error) {
 	_, _, e1 := Syscall(SYS_ADJTIME, uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -329,7 +327,7 @@ func Chdir(path string) (err error) {
 	_, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -345,7 +343,7 @@ func Chflags(path string, flags int) (err error) {
 	_, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -361,7 +359,7 @@ func Chmod(path string, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -377,7 +375,7 @@ func Chown(path string, uid int, gid int) (err error) {
 	_, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -393,7 +391,7 @@ func Chroot(path string) (err error) {
 	_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -403,7 +401,7 @@ func Chroot(path string) (err error) {
 func Close(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -411,10 +409,10 @@ func Close(fd int) (err error) {
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
 func Dup(fd int) (nfd int, err error) {
-	r0, _, e1 := Syscall(SYS_DUP, uintptr(fd), 0, 0)
+	r0, _, e1 := RawSyscall(SYS_DUP, uintptr(fd), 0, 0)
 	nfd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -422,9 +420,9 @@ func Dup(fd int) (nfd int, err error) {
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
 func Dup2(from int, to int) (err error) {
-	_, _, e1 := Syscall(SYS_DUP2, uintptr(from), uintptr(to), 0)
+	_, _, e1 := RawSyscall(SYS_DUP2, uintptr(from), uintptr(to), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -446,7 +444,7 @@ func Exchangedata(path1 string, path2 string, options int) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -463,7 +461,7 @@ func Exit(code int) {
 func Fchdir(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -473,7 +471,7 @@ func Fchdir(fd int) (err error) {
 func Fchflags(fd int, flags int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(fd), uintptr(flags), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -483,7 +481,7 @@ func Fchflags(fd int, flags int) (err error) {
 func Fchmod(fd int, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -493,7 +491,7 @@ func Fchmod(fd int, mode uint32) (err error) {
 func Fchown(fd int, uid int, gid int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -503,7 +501,7 @@ func Fchown(fd int, uid int, gid int) (err error) {
 func Flock(fd int, how int) (err error) {
 	_, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -514,7 +512,7 @@ func Fpathconf(fd int, name int) (val int, err error) {
 	r0, _, e1 := Syscall(SYS_FPATHCONF, uintptr(fd), uintptr(name), 0)
 	val = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -524,7 +522,7 @@ func Fpathconf(fd int, name int) (val int, err error) {
 func Fstat(fd int, stat *Stat_t) (err error) {
 	_, _, e1 := Syscall(SYS_FSTAT64, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -534,7 +532,7 @@ func Fstat(fd int, stat *Stat_t) (err error) {
 func Fstatfs(fd int, stat *Statfs_t) (err error) {
 	_, _, e1 := Syscall(SYS_FSTATFS64, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -544,7 +542,7 @@ func Fstatfs(fd int, stat *Statfs_t) (err error) {
 func Fsync(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -554,7 +552,7 @@ func Fsync(fd int) (err error) {
 func Ftruncate(fd int, length int64) (err error) {
 	_, _, e1 := Syscall(SYS_FTRUNCATE, uintptr(fd), uintptr(length), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -571,7 +569,7 @@ func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
 	r0, _, e1 := Syscall6(SYS_GETDIRENTRIES64, uintptr(fd), uintptr(_p0), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -614,7 +612,7 @@ func Getpgid(pid int) (pgid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0)
 	pgid = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -649,7 +647,7 @@ func Getpriority(which int, who int) (prio int, err error) {
 	r0, _, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0)
 	prio = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -659,7 +657,7 @@ func Getpriority(which int, who int) (prio int, err error) {
 func Getrlimit(which int, lim *Rlimit) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -669,7 +667,7 @@ func Getrlimit(which int, lim *Rlimit) (err error) {
 func Getrusage(who int, rusage *Rusage) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -680,7 +678,7 @@ func Getsid(pid int) (sid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0)
 	sid = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -707,7 +705,7 @@ func Kqueue() (fd int, err error) {
 	r0, _, e1 := Syscall(SYS_KQUEUE, 0, 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -723,7 +721,7 @@ func Lchown(path string, uid int, gid int) (err error) {
 	_, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -745,7 +743,7 @@ func Link(path string, link string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -755,7 +753,7 @@ func Link(path string, link string) (err error) {
 func Listen(s int, backlog int) (err error) {
 	_, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(backlog), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -771,7 +769,7 @@ func Lstat(path string, stat *Stat_t) (err error) {
 	_, _, e1 := Syscall(SYS_LSTAT64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -787,7 +785,7 @@ func Mkdir(path string, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -803,7 +801,7 @@ func Mkfifo(path string, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -819,7 +817,7 @@ func Mknod(path string, mode uint32, dev int) (err error) {
 	_, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -835,7 +833,7 @@ func Mlock(b []byte) (err error) {
 	}
 	_, _, e1 := Syscall(SYS_MLOCK, uintptr(_p0), uintptr(len(b)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -845,7 +843,7 @@ func Mlock(b []byte) (err error) {
 func Mlockall(flags int) (err error) {
 	_, _, e1 := Syscall(SYS_MLOCKALL, uintptr(flags), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -861,7 +859,7 @@ func Mprotect(b []byte, prot int) (err error) {
 	}
 	_, _, e1 := Syscall(SYS_MPROTECT, uintptr(_p0), uintptr(len(b)), uintptr(prot))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -877,7 +875,7 @@ func Munlock(b []byte) (err error) {
 	}
 	_, _, e1 := Syscall(SYS_MUNLOCK, uintptr(_p0), uintptr(len(b)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -887,7 +885,7 @@ func Munlock(b []byte) (err error) {
 func Munlockall() (err error) {
 	_, _, e1 := Syscall(SYS_MUNLOCKALL, 0, 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -904,7 +902,7 @@ func Open(path string, mode int, perm uint32) (fd int, err error) {
 	use(unsafe.Pointer(_p0))
 	fd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -921,7 +919,7 @@ func Pathconf(path string, name int) (val int, err error) {
 	use(unsafe.Pointer(_p0))
 	val = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -938,7 +936,7 @@ func Pread(fd int, p []byte, offset int64) (n int, err error) {
 	r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), 0, 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -955,7 +953,7 @@ func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
 	r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), 0, 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -972,7 +970,7 @@ func read(fd int, p []byte) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -995,7 +993,7 @@ func Readlink(path string, buf []byte) (n int, err error) {
 	use(unsafe.Pointer(_p0))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1017,7 +1015,7 @@ func Rename(from string, to string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1033,7 +1031,7 @@ func Revoke(path string) (err error) {
 	_, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1049,7 +1047,7 @@ func Rmdir(path string) (err error) {
 	_, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1060,7 +1058,7 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
 	r0, _, e1 := Syscall(SYS_LSEEK, uintptr(fd), uintptr(offset), uintptr(whence))
 	newoffset = int64(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1070,7 +1068,7 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
 func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error) {
 	_, _, e1 := Syscall6(SYS_SELECT, uintptr(n), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1080,7 +1078,7 @@ func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error) {
 func Setegid(egid int) (err error) {
 	_, _, e1 := Syscall(SYS_SETEGID, uintptr(egid), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1090,7 +1088,7 @@ func Setegid(egid int) (err error) {
 func Seteuid(euid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETEUID, uintptr(euid), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1100,7 +1098,7 @@ func Seteuid(euid int) (err error) {
 func Setgid(gid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETGID, uintptr(gid), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1116,7 +1114,7 @@ func Setlogin(name string) (err error) {
 	_, _, e1 := Syscall(SYS_SETLOGIN, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1126,7 +1124,7 @@ func Setlogin(name string) (err error) {
 func Setpgid(pid int, pgid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1136,7 +1134,7 @@ func Setpgid(pid int, pgid int) (err error) {
 func Setpriority(which int, who int, prio int) (err error) {
 	_, _, e1 := Syscall(SYS_SETPRIORITY, uintptr(which), uintptr(who), uintptr(prio))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1146,7 +1144,7 @@ func Setpriority(which int, who int, prio int) (err error) {
 func Setprivexec(flag int) (err error) {
 	_, _, e1 := Syscall(SYS_SETPRIVEXEC, uintptr(flag), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1156,7 +1154,7 @@ func Setprivexec(flag int) (err error) {
 func Setregid(rgid int, egid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1166,7 +1164,7 @@ func Setregid(rgid int, egid int) (err error) {
 func Setreuid(ruid int, euid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1176,7 +1174,7 @@ func Setreuid(ruid int, euid int) (err error) {
 func Setrlimit(which int, lim *Rlimit) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1187,7 +1185,7 @@ func Setsid() (pid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0)
 	pid = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1197,7 +1195,7 @@ func Setsid() (pid int, err error) {
 func Settimeofday(tp *Timeval) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1207,7 +1205,7 @@ func Settimeofday(tp *Timeval) (err error) {
 func Setuid(uid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETUID, uintptr(uid), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1223,7 +1221,7 @@ func Stat(path string, stat *Stat_t) (err error) {
 	_, _, e1 := Syscall(SYS_STAT64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1239,7 +1237,7 @@ func Statfs(path string, stat *Statfs_t) (err error) {
 	_, _, e1 := Syscall(SYS_STATFS64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1261,7 +1259,7 @@ func Symlink(path string, link string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1271,7 +1269,7 @@ func Symlink(path string, link string) (err error) {
 func Sync() (err error) {
 	_, _, e1 := Syscall(SYS_SYNC, 0, 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1287,7 +1285,7 @@ func Truncate(path string, length int64) (err error) {
 	_, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), uintptr(length), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1311,7 +1309,7 @@ func Undelete(path string) (err error) {
 	_, _, e1 := Syscall(SYS_UNDELETE, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1327,7 +1325,7 @@ func Unlink(path string) (err error) {
 	_, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1343,7 +1341,7 @@ func Unmount(path string, flags int) (err error) {
 	_, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1360,7 +1358,7 @@ func write(fd int, p []byte) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1371,7 +1369,7 @@ func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (
 	r0, _, e1 := Syscall6(SYS_MMAP, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flag), uintptr(fd), uintptr(pos))
 	ret = uintptr(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1381,7 +1379,7 @@ func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (
 func munmap(addr uintptr, length uintptr) (err error) {
 	_, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1392,7 +1390,7 @@ 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1403,7 +1401,7 @@ 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1415,7 +1413,7 @@ func gettimeofday(tp *Timeval) (sec int64, usec int32, err error) {
 	sec = int64(r0)
 	usec = int32(r1)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
diff --git a/src/syscall/zsyscall_dragonfly_386.go b/src/syscall/zsyscall_dragonfly_386.go
new file mode 100644
index 0000000..01b0819
--- /dev/null
+++ b/src/syscall/zsyscall_dragonfly_386.go
@@ -0,0 +1,1317 @@
+// mksyscall.pl -l32 -dragonfly syscall_bsd.go syscall_dragonfly.go syscall_dragonfly_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 getgroups(ngid int, gid *_Gid_t) (n int, err error) {
+	r0, _, e1 := RawSyscall(SYS_GETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
+	n = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func setgroups(ngid int, gid *_Gid_t) (err error) {
+	_, _, e1 := RawSyscall(SYS_SETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err error) {
+	r0, _, e1 := Syscall6(SYS_WAIT4, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0)
+	wpid = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
+	r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
+	fd = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+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
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+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
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func socket(domain int, typ int, proto int) (fd int, err error) {
+	r0, _, e1 := RawSyscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto))
+	fd = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+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
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+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
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
+	_, _, e1 := RawSyscall(SYS_GETPEERNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
+	_, _, e1 := RawSyscall(SYS_GETSOCKNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Shutdown(s int, how int) (err error) {
+	_, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(s), uintptr(how), 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) {
+	_, _, e1 := RawSyscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error) {
+	var _p0 unsafe.Pointer
+	if len(p) > 0 {
+		_p0 = unsafe.Pointer(&p[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
+	n = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+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])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	_, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
+	r0, _, e1 := Syscall(SYS_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), 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 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
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+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 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) {
+	var _p0 unsafe.Pointer
+	if len(mib) > 0 {
+		_p0 = unsafe.Pointer(&mib[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	_, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen))
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func utimes(path string, timeval *[2]Timeval) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0)
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func futimes(fd int, timeval *[2]Timeval) (err error) {
+	_, _, e1 := Syscall(SYS_FUTIMES, uintptr(fd), uintptr(unsafe.Pointer(timeval)), 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func fcntl(fd int, cmd int, arg int) (val int, err error) {
+	r0, _, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg))
+	val = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func pipe() (r int, w int, err error) {
+	r0, r1, e1 := RawSyscall(SYS_PIPE, 0, 0, 0)
+	r = int(r0)
+	w = int(r1)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func extpread(fd int, p []byte, flags int, offset int64) (n int, err error) {
+	var _p0 unsafe.Pointer
+	if len(p) > 0 {
+		_p0 = unsafe.Pointer(&p[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	r0, _, e1 := Syscall6(SYS_EXTPREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), 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 extpwrite(fd int, p []byte, flags int, offset int64) (n int, err error) {
+	var _p0 unsafe.Pointer
+	if len(p) > 0 {
+		_p0 = unsafe.Pointer(&p[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	r0, _, e1 := Syscall6(SYS_EXTPWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), 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 Access(path string, mode uint32) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Adjtime(delta *Timeval, olddelta *Timeval) (err error) {
+	_, _, e1 := Syscall(SYS_ADJTIME, uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Chdir(path string) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Chflags(path string, flags int) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Chmod(path string, mode uint32) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Chown(path string, uid int, gid int) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Chroot(path string) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0)
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Close(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 Dup(fd int) (nfd int, err error) {
+	r0, _, e1 := RawSyscall(SYS_DUP, uintptr(fd), 0, 0)
+	nfd = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Dup2(from int, to int) (err error) {
+	_, _, e1 := RawSyscall(SYS_DUP2, uintptr(from), uintptr(to), 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Exit(code int) {
+	Syscall(SYS_EXIT, uintptr(code), 0, 0)
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fchdir(fd int) (err error) {
+	_, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fchflags(fd int, flags int) (err error) {
+	_, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(fd), uintptr(flags), 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fchmod(fd int, mode uint32) (err error) {
+	_, _, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fchown(fd int, uid int, gid int) (err error) {
+	_, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid))
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Flock(fd int, how int) (err error) {
+	_, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fpathconf(fd int, name int) (val int, err error) {
+	r0, _, e1 := Syscall(SYS_FPATHCONF, uintptr(fd), uintptr(name), 0)
+	val = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fstat(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 Fstatfs(fd int, stat *Statfs_t) (err error) {
+	_, _, e1 := Syscall(SYS_FSTATFS, 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 Fsync(fd int) (err error) {
+	_, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Ftruncate(fd int, length int64) (err error) {
+	_, _, e1 := Syscall6(SYS_FTRUNCATE, uintptr(fd), 0, uintptr(length), uintptr(length>>32), 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// 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 Getdtablesize() (size int) {
+	r0, _, _ := Syscall(SYS_GETDTABLESIZE, 0, 0, 0)
+	size = int(r0)
+	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)
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Geteuid() (uid int) {
+	r0, _, _ := RawSyscall(SYS_GETEUID, 0, 0, 0)
+	uid = int(r0)
+	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)
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getpgid(pid int) (pgid int, err error) {
+	r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0)
+	pgid = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getpgrp() (pgrp int) {
+	r0, _, _ := RawSyscall(SYS_GETPGRP, 0, 0, 0)
+	pgrp = int(r0)
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getpid() (pid int) {
+	r0, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0)
+	pid = int(r0)
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getppid() (ppid int) {
+	r0, _, _ := RawSyscall(SYS_GETPPID, 0, 0, 0)
+	ppid = int(r0)
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getpriority(which int, who int) (prio int, err error) {
+	r0, _, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0)
+	prio = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getrlimit(which int, lim *Rlimit) (err error) {
+	_, _, e1 := RawSyscall(SYS_GETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getrusage(who int, rusage *Rusage) (err error) {
+	_, _, e1 := RawSyscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getsid(pid int) (sid int, err error) {
+	r0, _, e1 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0)
+	sid = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Gettimeofday(tv *Timeval) (err error) {
+	_, _, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getuid() (uid int) {
+	r0, _, _ := RawSyscall(SYS_GETUID, 0, 0, 0)
+	uid = int(r0)
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Issetugid() (tainted bool) {
+	r0, _, _ := Syscall(SYS_ISSETUGID, 0, 0, 0)
+	tainted = bool(r0 != 0)
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Kill(pid int, signum Signal) (err error) {
+	_, _, e1 := Syscall(SYS_KILL, uintptr(pid), uintptr(signum), 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Kqueue() (fd int, err error) {
+	r0, _, e1 := Syscall(SYS_KQUEUE, 0, 0, 0)
+	fd = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Lchown(path string, uid int, gid int) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+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 := Syscall(SYS_LINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
+	use(unsafe.Pointer(_p0))
+	use(unsafe.Pointer(_p1))
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Listen(s int, backlog int) (err error) {
+	_, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(backlog), 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Lstat(path string, stat *Stat_t) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mkdir(path string, mode uint32) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mkfifo(path string, mode uint32) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mknod(path string, mode uint32, dev int) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev))
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Nanosleep(time *Timespec, leftover *Timespec) (err error) {
+	_, _, e1 := Syscall(SYS_NANOSLEEP, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 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)
+	if err != nil {
+		return
+	}
+	r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm))
+	use(unsafe.Pointer(_p0))
+	fd = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Pathconf(path string, name int) (val int, err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	r0, _, e1 := Syscall(SYS_PATHCONF, uintptr(unsafe.Pointer(_p0)), uintptr(name), 0)
+	use(unsafe.Pointer(_p0))
+	val = 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
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Readlink(path string, buf []byte) (n int, err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	var _p1 unsafe.Pointer
+	if len(buf) > 0 {
+		_p1 = unsafe.Pointer(&buf[0])
+	} else {
+		_p1 = unsafe.Pointer(&_zero)
+	}
+	r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf)))
+	use(unsafe.Pointer(_p0))
+	n = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+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 := Syscall(SYS_RENAME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
+	use(unsafe.Pointer(_p0))
+	use(unsafe.Pointer(_p1))
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Revoke(path string) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(_p0)), 0, 0)
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Rmdir(path string) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// 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), 0, uintptr(offset), uintptr(offset>>32), uintptr(whence), 0)
+	newoffset = int64(int64(r1)<<32 | int64(r0))
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error) {
+	_, _, e1 := Syscall6(SYS_SELECT, uintptr(n), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setegid(egid int) (err error) {
+	_, _, e1 := RawSyscall(SYS_SETEGID, uintptr(egid), 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Seteuid(euid int) (err error) {
+	_, _, e1 := RawSyscall(SYS_SETEUID, uintptr(euid), 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setgid(gid int) (err error) {
+	_, _, e1 := RawSyscall(SYS_SETGID, uintptr(gid), 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setlogin(name string) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(name)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_SETLOGIN, uintptr(unsafe.Pointer(_p0)), 0, 0)
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setpgid(pid int, pgid int) (err error) {
+	_, _, e1 := RawSyscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setpriority(which int, who int, prio int) (err error) {
+	_, _, e1 := Syscall(SYS_SETPRIORITY, uintptr(which), uintptr(who), uintptr(prio))
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setregid(rgid int, egid int) (err error) {
+	_, _, e1 := RawSyscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setreuid(ruid int, euid int) (err error) {
+	_, _, e1 := RawSyscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setrlimit(which int, lim *Rlimit) (err error) {
+	_, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setsid() (pid int, err error) {
+	r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0)
+	pid = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Settimeofday(tp *Timeval) (err error) {
+	_, _, e1 := RawSyscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setuid(uid int) (err error) {
+	_, _, e1 := RawSyscall(SYS_SETUID, uintptr(uid), 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Stat(path string, stat *Stat_t) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Statfs(path string, stat *Statfs_t) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_STATFS, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+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 := Syscall(SYS_SYMLINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
+	use(unsafe.Pointer(_p0))
+	use(unsafe.Pointer(_p1))
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Sync() (err error) {
+	_, _, e1 := Syscall(SYS_SYNC, 0, 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Truncate(path string, length int64) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall6(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), 0, uintptr(length), uintptr(length>>32), 0, 0)
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Umask(newmask int) (oldmask int) {
+	r0, _, _ := Syscall(SYS_UMASK, uintptr(newmask), 0, 0)
+	oldmask = int(r0)
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Undelete(path string) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_UNDELETE, uintptr(unsafe.Pointer(_p0)), 0, 0)
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Unlink(path string) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(_p0)), 0, 0)
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Unmount(path string, flags int) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// 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)))
+	n = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// 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), 0, uintptr(pos), uintptr(pos>>32), 0)
+	ret = uintptr(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// 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)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// 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))
+	n = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// 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)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
diff --git a/src/syscall/zsyscall_dragonfly_amd64.go b/src/syscall/zsyscall_dragonfly_amd64.go
index 88e09d3..0121374 100644
--- a/src/syscall/zsyscall_dragonfly_amd64.go
+++ b/src/syscall/zsyscall_dragonfly_amd64.go
@@ -1,8 +1,6 @@
 // mksyscall.pl -dragonfly syscall_bsd.go syscall_dragonfly.go syscall_dragonfly_amd64.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
-// +build amd64,dragonfly
-
 package syscall
 
 import "unsafe"
@@ -13,7 +11,7 @@ func getgroups(ngid int, gid *_Gid_t) (n int, err error) {
 	r0, _, e1 := RawSyscall(SYS_GETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -23,7 +21,7 @@ func getgroups(ngid int, gid *_Gid_t) (n int, err error) {
 func setgroups(ngid int, gid *_Gid_t) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -34,7 +32,7 @@ func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err
 	r0, _, e1 := Syscall6(SYS_WAIT4, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0)
 	wpid = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -45,7 +43,7 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
 	r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	fd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -55,7 +53,7 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -65,7 +63,7 @@ func bind(s int, addr unsafe.Pointer, 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -76,7 +74,7 @@ func socket(domain int, typ int, proto int) (fd int, err error) {
 	r0, _, e1 := RawSyscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto))
 	fd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -86,7 +84,7 @@ func socket(domain int, typ int, proto int) (fd int, 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -96,7 +94,7 @@ func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen
 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -106,7 +104,7 @@ func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr)
 func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETPEERNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -116,7 +114,7 @@ func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETSOCKNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -126,7 +124,7 @@ func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 func Shutdown(s int, how int) (err error) {
 	_, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(s), uintptr(how), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -136,7 +134,7 @@ func Shutdown(s int, how int) (err error) {
 func socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) {
 	_, _, e1 := RawSyscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -153,7 +151,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
 	r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -169,7 +167,7 @@ func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (
 	}
 	_, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -180,7 +178,7 @@ func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -191,7 +189,7 @@ 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -202,7 +200,7 @@ func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, ne
 	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 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -218,7 +216,7 @@ func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr)
 	}
 	_, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -234,7 +232,7 @@ func utimes(path string, timeval *[2]Timeval) (err error) {
 	_, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -244,7 +242,7 @@ func utimes(path string, timeval *[2]Timeval) (err error) {
 func futimes(fd int, timeval *[2]Timeval) (err error) {
 	_, _, e1 := Syscall(SYS_FUTIMES, uintptr(fd), uintptr(unsafe.Pointer(timeval)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -255,7 +253,7 @@ func fcntl(fd int, cmd int, arg int) (val int, err error) {
 	r0, _, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg))
 	val = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -267,7 +265,7 @@ func pipe() (r int, w int, err error) {
 	r = int(r0)
 	w = int(r1)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -284,7 +282,7 @@ func extpread(fd int, p []byte, flags int, offset int64) (n int, err error) {
 	r0, _, e1 := Syscall6(SYS_EXTPREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(offset), 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -301,7 +299,7 @@ func extpwrite(fd int, p []byte, flags int, offset int64) (n int, err error) {
 	r0, _, e1 := Syscall6(SYS_EXTPWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(offset), 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -317,7 +315,7 @@ func Access(path string, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -327,7 +325,7 @@ func Access(path string, mode uint32) (err error) {
 func Adjtime(delta *Timeval, olddelta *Timeval) (err error) {
 	_, _, e1 := Syscall(SYS_ADJTIME, uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -343,7 +341,7 @@ func Chdir(path string) (err error) {
 	_, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -359,7 +357,7 @@ func Chflags(path string, flags int) (err error) {
 	_, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -375,7 +373,7 @@ func Chmod(path string, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -391,7 +389,7 @@ func Chown(path string, uid int, gid int) (err error) {
 	_, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -407,7 +405,7 @@ func Chroot(path string) (err error) {
 	_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -417,7 +415,7 @@ func Chroot(path string) (err error) {
 func Close(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -425,10 +423,10 @@ func Close(fd int) (err error) {
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
 func Dup(fd int) (nfd int, err error) {
-	r0, _, e1 := Syscall(SYS_DUP, uintptr(fd), 0, 0)
+	r0, _, e1 := RawSyscall(SYS_DUP, uintptr(fd), 0, 0)
 	nfd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -436,9 +434,9 @@ func Dup(fd int) (nfd int, err error) {
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
 func Dup2(from int, to int) (err error) {
-	_, _, e1 := Syscall(SYS_DUP2, uintptr(from), uintptr(to), 0)
+	_, _, e1 := RawSyscall(SYS_DUP2, uintptr(from), uintptr(to), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -455,7 +453,7 @@ func Exit(code int) {
 func Fchdir(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -465,7 +463,7 @@ func Fchdir(fd int) (err error) {
 func Fchflags(fd int, flags int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(fd), uintptr(flags), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -475,7 +473,7 @@ func Fchflags(fd int, flags int) (err error) {
 func Fchmod(fd int, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -485,7 +483,7 @@ func Fchmod(fd int, mode uint32) (err error) {
 func Fchown(fd int, uid int, gid int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -495,7 +493,7 @@ func Fchown(fd int, uid int, gid int) (err error) {
 func Flock(fd int, how int) (err error) {
 	_, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -506,7 +504,7 @@ func Fpathconf(fd int, name int) (val int, err error) {
 	r0, _, e1 := Syscall(SYS_FPATHCONF, uintptr(fd), uintptr(name), 0)
 	val = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -516,7 +514,7 @@ func Fpathconf(fd int, name int) (val int, err error) {
 func Fstat(fd int, stat *Stat_t) (err error) {
 	_, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -526,7 +524,7 @@ func Fstat(fd int, stat *Stat_t) (err error) {
 func Fstatfs(fd int, stat *Statfs_t) (err error) {
 	_, _, e1 := Syscall(SYS_FSTATFS, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -536,7 +534,7 @@ func Fstatfs(fd int, stat *Statfs_t) (err error) {
 func Fsync(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -546,7 +544,7 @@ func Fsync(fd int) (err error) {
 func Ftruncate(fd int, length int64) (err error) {
 	_, _, e1 := Syscall(SYS_FTRUNCATE, uintptr(fd), 0, uintptr(length))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -563,7 +561,7 @@ func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
 	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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -606,7 +604,7 @@ func Getpgid(pid int) (pgid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0)
 	pgid = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -641,7 +639,7 @@ func Getpriority(which int, who int) (prio int, err error) {
 	r0, _, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0)
 	prio = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -651,7 +649,7 @@ func Getpriority(which int, who int) (prio int, err error) {
 func Getrlimit(which int, lim *Rlimit) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -661,7 +659,7 @@ func Getrlimit(which int, lim *Rlimit) (err error) {
 func Getrusage(who int, rusage *Rusage) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -672,7 +670,7 @@ func Getsid(pid int) (sid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0)
 	sid = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -682,7 +680,7 @@ func Getsid(pid int) (sid int, err error) {
 func Gettimeofday(tv *Timeval) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -708,7 +706,7 @@ func Issetugid() (tainted bool) {
 func Kill(pid int, signum Signal) (err error) {
 	_, _, e1 := Syscall(SYS_KILL, uintptr(pid), uintptr(signum), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -719,7 +717,7 @@ func Kqueue() (fd int, err error) {
 	r0, _, e1 := Syscall(SYS_KQUEUE, 0, 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -735,7 +733,7 @@ func Lchown(path string, uid int, gid int) (err error) {
 	_, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -757,7 +755,7 @@ func Link(path string, link string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -767,7 +765,7 @@ func Link(path string, link string) (err error) {
 func Listen(s int, backlog int) (err error) {
 	_, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(backlog), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -783,7 +781,7 @@ func Lstat(path string, stat *Stat_t) (err error) {
 	_, _, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -799,7 +797,7 @@ func Mkdir(path string, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -815,7 +813,7 @@ func Mkfifo(path string, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -831,7 +829,7 @@ func Mknod(path string, mode uint32, dev int) (err error) {
 	_, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -841,7 +839,7 @@ func Mknod(path string, mode uint32, dev int) (err error) {
 func Nanosleep(time *Timespec, leftover *Timespec) (err error) {
 	_, _, e1 := Syscall(SYS_NANOSLEEP, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -858,7 +856,7 @@ func Open(path string, mode int, perm uint32) (fd int, err error) {
 	use(unsafe.Pointer(_p0))
 	fd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -875,7 +873,7 @@ func Pathconf(path string, name int) (val int, err error) {
 	use(unsafe.Pointer(_p0))
 	val = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -892,7 +890,7 @@ func read(fd int, p []byte) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -915,7 +913,7 @@ func Readlink(path string, buf []byte) (n int, err error) {
 	use(unsafe.Pointer(_p0))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -937,7 +935,7 @@ func Rename(from string, to string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -953,7 +951,7 @@ func Revoke(path string) (err error) {
 	_, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -969,7 +967,7 @@ func Rmdir(path string) (err error) {
 	_, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -980,7 +978,7 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
 	r0, _, e1 := Syscall6(SYS_LSEEK, uintptr(fd), 0, uintptr(offset), uintptr(whence), 0, 0)
 	newoffset = int64(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -990,7 +988,7 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
 func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error) {
 	_, _, e1 := Syscall6(SYS_SELECT, uintptr(n), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1000,7 +998,7 @@ func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error) {
 func Setegid(egid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETEGID, uintptr(egid), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1010,7 +1008,7 @@ func Setegid(egid int) (err error) {
 func Seteuid(euid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETEUID, uintptr(euid), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1020,7 +1018,7 @@ func Seteuid(euid int) (err error) {
 func Setgid(gid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETGID, uintptr(gid), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1036,7 +1034,7 @@ func Setlogin(name string) (err error) {
 	_, _, e1 := Syscall(SYS_SETLOGIN, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1046,7 +1044,7 @@ func Setlogin(name string) (err error) {
 func Setpgid(pid int, pgid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1056,7 +1054,7 @@ func Setpgid(pid int, pgid int) (err error) {
 func Setpriority(which int, who int, prio int) (err error) {
 	_, _, e1 := Syscall(SYS_SETPRIORITY, uintptr(which), uintptr(who), uintptr(prio))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1066,7 +1064,7 @@ func Setpriority(which int, who int, prio int) (err error) {
 func Setregid(rgid int, egid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1076,7 +1074,7 @@ func Setregid(rgid int, egid int) (err error) {
 func Setreuid(ruid int, euid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1086,7 +1084,7 @@ func Setreuid(ruid int, euid int) (err error) {
 func Setrlimit(which int, lim *Rlimit) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1097,7 +1095,7 @@ func Setsid() (pid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0)
 	pid = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1107,7 +1105,7 @@ func Setsid() (pid int, err error) {
 func Settimeofday(tp *Timeval) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1117,7 +1115,7 @@ func Settimeofday(tp *Timeval) (err error) {
 func Setuid(uid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETUID, uintptr(uid), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1133,7 +1131,7 @@ func Stat(path string, stat *Stat_t) (err error) {
 	_, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1149,7 +1147,7 @@ func Statfs(path string, stat *Statfs_t) (err error) {
 	_, _, e1 := Syscall(SYS_STATFS, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1171,7 +1169,7 @@ func Symlink(path string, link string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1181,7 +1179,7 @@ func Symlink(path string, link string) (err error) {
 func Sync() (err error) {
 	_, _, e1 := Syscall(SYS_SYNC, 0, 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1197,7 +1195,7 @@ func Truncate(path string, length int64) (err error) {
 	_, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), 0, uintptr(length))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1221,7 +1219,7 @@ func Undelete(path string) (err error) {
 	_, _, e1 := Syscall(SYS_UNDELETE, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1237,7 +1235,7 @@ func Unlink(path string) (err error) {
 	_, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1253,7 +1251,7 @@ func Unmount(path string, flags int) (err error) {
 	_, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1270,7 +1268,7 @@ func write(fd int, p []byte) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1281,7 +1279,7 @@ func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (
 	r0, _, e1 := Syscall9(SYS_MMAP, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flag), uintptr(fd), 0, uintptr(pos), 0, 0)
 	ret = uintptr(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1291,7 +1289,7 @@ func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (
 func munmap(addr uintptr, length uintptr) (err error) {
 	_, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1302,7 +1300,7 @@ 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1313,7 +1311,7 @@ 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
diff --git a/src/syscall/zsyscall_freebsd_386.go b/src/syscall/zsyscall_freebsd_386.go
index 30f29e5..c8c636f 100644
--- a/src/syscall/zsyscall_freebsd_386.go
+++ b/src/syscall/zsyscall_freebsd_386.go
@@ -1,8 +1,6 @@
 // mksyscall.pl -l32 syscall_bsd.go syscall_freebsd.go syscall_freebsd_386.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
-// +build 386,freebsd
-
 package syscall
 
 import "unsafe"
@@ -13,7 +11,7 @@ func getgroups(ngid int, gid *_Gid_t) (n int, err error) {
 	r0, _, e1 := RawSyscall(SYS_GETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -23,7 +21,7 @@ func getgroups(ngid int, gid *_Gid_t) (n int, err error) {
 func setgroups(ngid int, gid *_Gid_t) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -34,7 +32,7 @@ func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err
 	r0, _, e1 := Syscall6(SYS_WAIT4, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0)
 	wpid = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -45,7 +43,7 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
 	r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	fd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -55,7 +53,7 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -65,7 +63,7 @@ func bind(s int, addr unsafe.Pointer, 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -76,7 +74,7 @@ func socket(domain int, typ int, proto int) (fd int, err error) {
 	r0, _, e1 := RawSyscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto))
 	fd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -86,7 +84,7 @@ func socket(domain int, typ int, proto int) (fd int, 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -96,7 +94,7 @@ func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen
 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -106,7 +104,7 @@ func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr)
 func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETPEERNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -116,7 +114,7 @@ func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETSOCKNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -126,7 +124,7 @@ func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 func Shutdown(s int, how int) (err error) {
 	_, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(s), uintptr(how), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -136,7 +134,7 @@ func Shutdown(s int, how int) (err error) {
 func socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) {
 	_, _, e1 := RawSyscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -153,7 +151,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
 	r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -169,7 +167,7 @@ func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (
 	}
 	_, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -180,7 +178,7 @@ func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -191,7 +189,7 @@ 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -202,7 +200,7 @@ func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, ne
 	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 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -218,7 +216,7 @@ func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr)
 	}
 	_, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -234,7 +232,7 @@ func utimes(path string, timeval *[2]Timeval) (err error) {
 	_, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -244,7 +242,7 @@ func utimes(path string, timeval *[2]Timeval) (err error) {
 func futimes(fd int, timeval *[2]Timeval) (err error) {
 	_, _, e1 := Syscall(SYS_FUTIMES, uintptr(fd), uintptr(unsafe.Pointer(timeval)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -255,7 +253,7 @@ func fcntl(fd int, cmd int, arg int) (val int, err error) {
 	r0, _, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg))
 	val = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -267,7 +265,7 @@ func pipe() (r int, w int, err error) {
 	r = int(r0)
 	w = int(r1)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -283,7 +281,7 @@ func Access(path string, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -293,7 +291,7 @@ func Access(path string, mode uint32) (err error) {
 func Adjtime(delta *Timeval, olddelta *Timeval) (err error) {
 	_, _, e1 := Syscall(SYS_ADJTIME, uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -309,7 +307,7 @@ func Chdir(path string) (err error) {
 	_, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -325,7 +323,7 @@ func Chflags(path string, flags int) (err error) {
 	_, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -341,7 +339,7 @@ func Chmod(path string, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -357,7 +355,7 @@ func Chown(path string, uid int, gid int) (err error) {
 	_, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -373,7 +371,7 @@ func Chroot(path string) (err error) {
 	_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -383,7 +381,7 @@ func Chroot(path string) (err error) {
 func Close(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -391,10 +389,10 @@ func Close(fd int) (err error) {
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
 func Dup(fd int) (nfd int, err error) {
-	r0, _, e1 := Syscall(SYS_DUP, uintptr(fd), 0, 0)
+	r0, _, e1 := RawSyscall(SYS_DUP, uintptr(fd), 0, 0)
 	nfd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -402,9 +400,9 @@ func Dup(fd int) (nfd int, err error) {
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
 func Dup2(from int, to int) (err error) {
-	_, _, e1 := Syscall(SYS_DUP2, uintptr(from), uintptr(to), 0)
+	_, _, e1 := RawSyscall(SYS_DUP2, uintptr(from), uintptr(to), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -421,7 +419,7 @@ func Exit(code int) {
 func Fchdir(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -431,7 +429,7 @@ func Fchdir(fd int) (err error) {
 func Fchflags(fd int, flags int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(fd), uintptr(flags), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -441,7 +439,7 @@ func Fchflags(fd int, flags int) (err error) {
 func Fchmod(fd int, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -451,7 +449,7 @@ func Fchmod(fd int, mode uint32) (err error) {
 func Fchown(fd int, uid int, gid int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -461,7 +459,7 @@ func Fchown(fd int, uid int, gid int) (err error) {
 func Flock(fd int, how int) (err error) {
 	_, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -472,7 +470,7 @@ func Fpathconf(fd int, name int) (val int, err error) {
 	r0, _, e1 := Syscall(SYS_FPATHCONF, uintptr(fd), uintptr(name), 0)
 	val = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -482,7 +480,7 @@ func Fpathconf(fd int, name int) (val int, err error) {
 func Fstat(fd int, stat *Stat_t) (err error) {
 	_, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -492,7 +490,7 @@ func Fstat(fd int, stat *Stat_t) (err error) {
 func Fstatfs(fd int, stat *Statfs_t) (err error) {
 	_, _, e1 := Syscall(SYS_FSTATFS, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -502,7 +500,7 @@ func Fstatfs(fd int, stat *Statfs_t) (err error) {
 func Fsync(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -512,7 +510,7 @@ func Fsync(fd int) (err error) {
 func Ftruncate(fd int, length int64) (err error) {
 	_, _, e1 := Syscall(SYS_FTRUNCATE, uintptr(fd), uintptr(length), uintptr(length>>32))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -529,7 +527,7 @@ func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
 	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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -572,7 +570,7 @@ func Getpgid(pid int) (pgid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0)
 	pgid = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -607,7 +605,7 @@ func Getpriority(which int, who int) (prio int, err error) {
 	r0, _, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0)
 	prio = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -617,7 +615,7 @@ func Getpriority(which int, who int) (prio int, err error) {
 func Getrlimit(which int, lim *Rlimit) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -627,7 +625,7 @@ func Getrlimit(which int, lim *Rlimit) (err error) {
 func Getrusage(who int, rusage *Rusage) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -638,7 +636,7 @@ func Getsid(pid int) (sid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0)
 	sid = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -648,7 +646,7 @@ func Getsid(pid int) (sid int, err error) {
 func Gettimeofday(tv *Timeval) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -674,7 +672,7 @@ func Issetugid() (tainted bool) {
 func Kill(pid int, signum Signal) (err error) {
 	_, _, e1 := Syscall(SYS_KILL, uintptr(pid), uintptr(signum), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -685,7 +683,7 @@ func Kqueue() (fd int, err error) {
 	r0, _, e1 := Syscall(SYS_KQUEUE, 0, 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -701,7 +699,7 @@ func Lchown(path string, uid int, gid int) (err error) {
 	_, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -723,7 +721,7 @@ func Link(path string, link string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -733,7 +731,7 @@ func Link(path string, link string) (err error) {
 func Listen(s int, backlog int) (err error) {
 	_, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(backlog), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -749,7 +747,7 @@ func Lstat(path string, stat *Stat_t) (err error) {
 	_, _, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -765,7 +763,7 @@ func Mkdir(path string, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -781,7 +779,7 @@ func Mkfifo(path string, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -797,7 +795,7 @@ func Mknod(path string, mode uint32, dev int) (err error) {
 	_, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -807,7 +805,7 @@ func Mknod(path string, mode uint32, dev int) (err error) {
 func Nanosleep(time *Timespec, leftover *Timespec) (err error) {
 	_, _, e1 := Syscall(SYS_NANOSLEEP, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -824,7 +822,7 @@ func Open(path string, mode int, perm uint32) (fd int, err error) {
 	use(unsafe.Pointer(_p0))
 	fd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -841,7 +839,7 @@ func Pathconf(path string, name int) (val int, err error) {
 	use(unsafe.Pointer(_p0))
 	val = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -858,7 +856,7 @@ func Pread(fd int, p []byte, offset int64) (n int, err error) {
 	r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -875,7 +873,7 @@ func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
 	r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -892,7 +890,7 @@ func read(fd int, p []byte) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -915,7 +913,7 @@ func Readlink(path string, buf []byte) (n int, err error) {
 	use(unsafe.Pointer(_p0))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -937,7 +935,7 @@ func Rename(from string, to string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -953,7 +951,7 @@ func Revoke(path string) (err error) {
 	_, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -969,7 +967,7 @@ func Rmdir(path string) (err error) {
 	_, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -980,7 +978,7 @@ 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)
 	newoffset = int64(int64(r1)<<32 | int64(r0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -990,7 +988,7 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
 func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error) {
 	_, _, e1 := Syscall6(SYS_SELECT, uintptr(n), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1000,7 +998,7 @@ func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error) {
 func Setegid(egid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETEGID, uintptr(egid), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1010,7 +1008,7 @@ func Setegid(egid int) (err error) {
 func Seteuid(euid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETEUID, uintptr(euid), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1020,7 +1018,7 @@ func Seteuid(euid int) (err error) {
 func Setgid(gid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETGID, uintptr(gid), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1036,7 +1034,7 @@ func Setlogin(name string) (err error) {
 	_, _, e1 := Syscall(SYS_SETLOGIN, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1046,7 +1044,7 @@ func Setlogin(name string) (err error) {
 func Setpgid(pid int, pgid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1056,7 +1054,7 @@ func Setpgid(pid int, pgid int) (err error) {
 func Setpriority(which int, who int, prio int) (err error) {
 	_, _, e1 := Syscall(SYS_SETPRIORITY, uintptr(which), uintptr(who), uintptr(prio))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1066,7 +1064,7 @@ func Setpriority(which int, who int, prio int) (err error) {
 func Setregid(rgid int, egid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1076,7 +1074,7 @@ func Setregid(rgid int, egid int) (err error) {
 func Setreuid(ruid int, euid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1086,7 +1084,7 @@ func Setreuid(ruid int, euid int) (err error) {
 func Setrlimit(which int, lim *Rlimit) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1097,7 +1095,7 @@ func Setsid() (pid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0)
 	pid = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1107,7 +1105,7 @@ func Setsid() (pid int, err error) {
 func Settimeofday(tp *Timeval) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1117,7 +1115,7 @@ func Settimeofday(tp *Timeval) (err error) {
 func Setuid(uid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETUID, uintptr(uid), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1133,7 +1131,7 @@ func Stat(path string, stat *Stat_t) (err error) {
 	_, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1149,7 +1147,7 @@ func Statfs(path string, stat *Statfs_t) (err error) {
 	_, _, e1 := Syscall(SYS_STATFS, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1171,7 +1169,7 @@ func Symlink(path string, link string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1181,7 +1179,7 @@ func Symlink(path string, link string) (err error) {
 func Sync() (err error) {
 	_, _, e1 := Syscall(SYS_SYNC, 0, 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1197,7 +1195,7 @@ func Truncate(path string, length int64) (err error) {
 	_, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), uintptr(length), uintptr(length>>32))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1221,7 +1219,7 @@ func Undelete(path string) (err error) {
 	_, _, e1 := Syscall(SYS_UNDELETE, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1237,7 +1235,7 @@ func Unlink(path string) (err error) {
 	_, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1253,7 +1251,7 @@ func Unmount(path string, flags int) (err error) {
 	_, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1270,7 +1268,7 @@ func write(fd int, p []byte) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1281,7 +1279,7 @@ func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (
 	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)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1291,7 +1289,7 @@ func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (
 func munmap(addr uintptr, length uintptr) (err error) {
 	_, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1302,7 +1300,7 @@ 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1313,7 +1311,7 @@ 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1324,7 +1322,7 @@ func accept4(fd int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (nfd int
 	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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
diff --git a/src/syscall/zsyscall_freebsd_amd64.go b/src/syscall/zsyscall_freebsd_amd64.go
index 93059d1..026b560 100644
--- a/src/syscall/zsyscall_freebsd_amd64.go
+++ b/src/syscall/zsyscall_freebsd_amd64.go
@@ -1,8 +1,6 @@
 // mksyscall.pl syscall_bsd.go syscall_freebsd.go syscall_freebsd_amd64.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
-// +build amd64,freebsd
-
 package syscall
 
 import "unsafe"
@@ -13,7 +11,7 @@ func getgroups(ngid int, gid *_Gid_t) (n int, err error) {
 	r0, _, e1 := RawSyscall(SYS_GETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -23,7 +21,7 @@ func getgroups(ngid int, gid *_Gid_t) (n int, err error) {
 func setgroups(ngid int, gid *_Gid_t) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -34,7 +32,7 @@ func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err
 	r0, _, e1 := Syscall6(SYS_WAIT4, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0)
 	wpid = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -45,7 +43,7 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
 	r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	fd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -55,7 +53,7 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -65,7 +63,7 @@ func bind(s int, addr unsafe.Pointer, 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -76,7 +74,7 @@ func socket(domain int, typ int, proto int) (fd int, err error) {
 	r0, _, e1 := RawSyscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto))
 	fd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -86,7 +84,7 @@ func socket(domain int, typ int, proto int) (fd int, 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -96,7 +94,7 @@ func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen
 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -106,7 +104,7 @@ func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr)
 func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETPEERNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -116,7 +114,7 @@ func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETSOCKNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -126,7 +124,7 @@ func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 func Shutdown(s int, how int) (err error) {
 	_, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(s), uintptr(how), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -136,7 +134,7 @@ func Shutdown(s int, how int) (err error) {
 func socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) {
 	_, _, e1 := RawSyscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -153,7 +151,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
 	r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -169,7 +167,7 @@ func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (
 	}
 	_, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -180,7 +178,7 @@ func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -191,7 +189,7 @@ 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -202,7 +200,7 @@ func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, ne
 	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 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -218,7 +216,7 @@ func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr)
 	}
 	_, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -234,7 +232,7 @@ func utimes(path string, timeval *[2]Timeval) (err error) {
 	_, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -244,7 +242,7 @@ func utimes(path string, timeval *[2]Timeval) (err error) {
 func futimes(fd int, timeval *[2]Timeval) (err error) {
 	_, _, e1 := Syscall(SYS_FUTIMES, uintptr(fd), uintptr(unsafe.Pointer(timeval)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -255,7 +253,7 @@ func fcntl(fd int, cmd int, arg int) (val int, err error) {
 	r0, _, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg))
 	val = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -267,7 +265,7 @@ func pipe() (r int, w int, err error) {
 	r = int(r0)
 	w = int(r1)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -283,7 +281,7 @@ func Access(path string, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -293,7 +291,7 @@ func Access(path string, mode uint32) (err error) {
 func Adjtime(delta *Timeval, olddelta *Timeval) (err error) {
 	_, _, e1 := Syscall(SYS_ADJTIME, uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -309,7 +307,7 @@ func Chdir(path string) (err error) {
 	_, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -325,7 +323,7 @@ func Chflags(path string, flags int) (err error) {
 	_, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -341,7 +339,7 @@ func Chmod(path string, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -357,7 +355,7 @@ func Chown(path string, uid int, gid int) (err error) {
 	_, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -373,7 +371,7 @@ func Chroot(path string) (err error) {
 	_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -383,7 +381,7 @@ func Chroot(path string) (err error) {
 func Close(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -391,10 +389,10 @@ func Close(fd int) (err error) {
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
 func Dup(fd int) (nfd int, err error) {
-	r0, _, e1 := Syscall(SYS_DUP, uintptr(fd), 0, 0)
+	r0, _, e1 := RawSyscall(SYS_DUP, uintptr(fd), 0, 0)
 	nfd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -402,9 +400,9 @@ func Dup(fd int) (nfd int, err error) {
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
 func Dup2(from int, to int) (err error) {
-	_, _, e1 := Syscall(SYS_DUP2, uintptr(from), uintptr(to), 0)
+	_, _, e1 := RawSyscall(SYS_DUP2, uintptr(from), uintptr(to), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -421,7 +419,7 @@ func Exit(code int) {
 func Fchdir(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -431,7 +429,7 @@ func Fchdir(fd int) (err error) {
 func Fchflags(fd int, flags int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(fd), uintptr(flags), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -441,7 +439,7 @@ func Fchflags(fd int, flags int) (err error) {
 func Fchmod(fd int, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -451,7 +449,7 @@ func Fchmod(fd int, mode uint32) (err error) {
 func Fchown(fd int, uid int, gid int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -461,7 +459,7 @@ func Fchown(fd int, uid int, gid int) (err error) {
 func Flock(fd int, how int) (err error) {
 	_, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -472,7 +470,7 @@ func Fpathconf(fd int, name int) (val int, err error) {
 	r0, _, e1 := Syscall(SYS_FPATHCONF, uintptr(fd), uintptr(name), 0)
 	val = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -482,7 +480,7 @@ func Fpathconf(fd int, name int) (val int, err error) {
 func Fstat(fd int, stat *Stat_t) (err error) {
 	_, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -492,7 +490,7 @@ func Fstat(fd int, stat *Stat_t) (err error) {
 func Fstatfs(fd int, stat *Statfs_t) (err error) {
 	_, _, e1 := Syscall(SYS_FSTATFS, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -502,7 +500,7 @@ func Fstatfs(fd int, stat *Statfs_t) (err error) {
 func Fsync(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -512,7 +510,7 @@ func Fsync(fd int) (err error) {
 func Ftruncate(fd int, length int64) (err error) {
 	_, _, e1 := Syscall(SYS_FTRUNCATE, uintptr(fd), uintptr(length), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -529,7 +527,7 @@ func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
 	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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -572,7 +570,7 @@ func Getpgid(pid int) (pgid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0)
 	pgid = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -607,7 +605,7 @@ func Getpriority(which int, who int) (prio int, err error) {
 	r0, _, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0)
 	prio = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -617,7 +615,7 @@ func Getpriority(which int, who int) (prio int, err error) {
 func Getrlimit(which int, lim *Rlimit) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -627,7 +625,7 @@ func Getrlimit(which int, lim *Rlimit) (err error) {
 func Getrusage(who int, rusage *Rusage) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -638,7 +636,7 @@ func Getsid(pid int) (sid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0)
 	sid = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -648,7 +646,7 @@ func Getsid(pid int) (sid int, err error) {
 func Gettimeofday(tv *Timeval) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -674,7 +672,7 @@ func Issetugid() (tainted bool) {
 func Kill(pid int, signum Signal) (err error) {
 	_, _, e1 := Syscall(SYS_KILL, uintptr(pid), uintptr(signum), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -685,7 +683,7 @@ func Kqueue() (fd int, err error) {
 	r0, _, e1 := Syscall(SYS_KQUEUE, 0, 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -701,7 +699,7 @@ func Lchown(path string, uid int, gid int) (err error) {
 	_, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -723,7 +721,7 @@ func Link(path string, link string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -733,7 +731,7 @@ func Link(path string, link string) (err error) {
 func Listen(s int, backlog int) (err error) {
 	_, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(backlog), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -749,7 +747,7 @@ func Lstat(path string, stat *Stat_t) (err error) {
 	_, _, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -765,7 +763,7 @@ func Mkdir(path string, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -781,7 +779,7 @@ func Mkfifo(path string, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -797,7 +795,7 @@ func Mknod(path string, mode uint32, dev int) (err error) {
 	_, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -807,7 +805,7 @@ func Mknod(path string, mode uint32, dev int) (err error) {
 func Nanosleep(time *Timespec, leftover *Timespec) (err error) {
 	_, _, e1 := Syscall(SYS_NANOSLEEP, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -824,7 +822,7 @@ func Open(path string, mode int, perm uint32) (fd int, err error) {
 	use(unsafe.Pointer(_p0))
 	fd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -841,7 +839,7 @@ func Pathconf(path string, name int) (val int, err error) {
 	use(unsafe.Pointer(_p0))
 	val = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -858,7 +856,7 @@ func Pread(fd int, p []byte, offset int64) (n int, err error) {
 	r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), 0, 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -875,7 +873,7 @@ func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
 	r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), 0, 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -892,7 +890,7 @@ func read(fd int, p []byte) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -915,7 +913,7 @@ func Readlink(path string, buf []byte) (n int, err error) {
 	use(unsafe.Pointer(_p0))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -937,7 +935,7 @@ func Rename(from string, to string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -953,7 +951,7 @@ func Revoke(path string) (err error) {
 	_, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -969,7 +967,7 @@ func Rmdir(path string) (err error) {
 	_, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -980,7 +978,7 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
 	r0, _, e1 := Syscall(SYS_LSEEK, uintptr(fd), uintptr(offset), uintptr(whence))
 	newoffset = int64(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -990,7 +988,7 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
 func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error) {
 	_, _, e1 := Syscall6(SYS_SELECT, uintptr(n), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1000,7 +998,7 @@ func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error) {
 func Setegid(egid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETEGID, uintptr(egid), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1010,7 +1008,7 @@ func Setegid(egid int) (err error) {
 func Seteuid(euid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETEUID, uintptr(euid), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1020,7 +1018,7 @@ func Seteuid(euid int) (err error) {
 func Setgid(gid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETGID, uintptr(gid), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1036,7 +1034,7 @@ func Setlogin(name string) (err error) {
 	_, _, e1 := Syscall(SYS_SETLOGIN, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1046,7 +1044,7 @@ func Setlogin(name string) (err error) {
 func Setpgid(pid int, pgid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1056,7 +1054,7 @@ func Setpgid(pid int, pgid int) (err error) {
 func Setpriority(which int, who int, prio int) (err error) {
 	_, _, e1 := Syscall(SYS_SETPRIORITY, uintptr(which), uintptr(who), uintptr(prio))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1066,7 +1064,7 @@ func Setpriority(which int, who int, prio int) (err error) {
 func Setregid(rgid int, egid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1076,7 +1074,7 @@ func Setregid(rgid int, egid int) (err error) {
 func Setreuid(ruid int, euid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1086,7 +1084,7 @@ func Setreuid(ruid int, euid int) (err error) {
 func Setrlimit(which int, lim *Rlimit) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1097,7 +1095,7 @@ func Setsid() (pid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0)
 	pid = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1107,7 +1105,7 @@ func Setsid() (pid int, err error) {
 func Settimeofday(tp *Timeval) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1117,7 +1115,7 @@ func Settimeofday(tp *Timeval) (err error) {
 func Setuid(uid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETUID, uintptr(uid), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1133,7 +1131,7 @@ func Stat(path string, stat *Stat_t) (err error) {
 	_, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1149,7 +1147,7 @@ func Statfs(path string, stat *Statfs_t) (err error) {
 	_, _, e1 := Syscall(SYS_STATFS, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1171,7 +1169,7 @@ func Symlink(path string, link string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1181,7 +1179,7 @@ func Symlink(path string, link string) (err error) {
 func Sync() (err error) {
 	_, _, e1 := Syscall(SYS_SYNC, 0, 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1197,7 +1195,7 @@ func Truncate(path string, length int64) (err error) {
 	_, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), uintptr(length), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1221,7 +1219,7 @@ func Undelete(path string) (err error) {
 	_, _, e1 := Syscall(SYS_UNDELETE, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1237,7 +1235,7 @@ func Unlink(path string) (err error) {
 	_, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1253,7 +1251,7 @@ func Unmount(path string, flags int) (err error) {
 	_, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1270,7 +1268,7 @@ func write(fd int, p []byte) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1281,7 +1279,7 @@ func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (
 	r0, _, e1 := Syscall6(SYS_MMAP, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flag), uintptr(fd), uintptr(pos))
 	ret = uintptr(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1291,7 +1289,7 @@ func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (
 func munmap(addr uintptr, length uintptr) (err error) {
 	_, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1302,7 +1300,7 @@ 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1313,7 +1311,7 @@ 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1324,7 +1322,7 @@ func accept4(fd int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (nfd int
 	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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
diff --git a/src/syscall/zsyscall_freebsd_arm.go b/src/syscall/zsyscall_freebsd_arm.go
index 84096b0..0c349cb 100644
--- a/src/syscall/zsyscall_freebsd_arm.go
+++ b/src/syscall/zsyscall_freebsd_arm.go
@@ -1,8 +1,6 @@
 // mksyscall.pl -l32 -arm syscall_bsd.go syscall_freebsd.go syscall_freebsd_arm.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
-// +build arm,freebsd
-
 package syscall
 
 import "unsafe"
@@ -13,7 +11,7 @@ func getgroups(ngid int, gid *_Gid_t) (n int, err error) {
 	r0, _, e1 := RawSyscall(SYS_GETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -23,7 +21,7 @@ func getgroups(ngid int, gid *_Gid_t) (n int, err error) {
 func setgroups(ngid int, gid *_Gid_t) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -34,7 +32,7 @@ func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err
 	r0, _, e1 := Syscall6(SYS_WAIT4, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0)
 	wpid = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -45,7 +43,7 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
 	r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	fd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -55,7 +53,7 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -65,7 +63,7 @@ func bind(s int, addr unsafe.Pointer, 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -76,7 +74,7 @@ func socket(domain int, typ int, proto int) (fd int, err error) {
 	r0, _, e1 := RawSyscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto))
 	fd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -86,7 +84,7 @@ func socket(domain int, typ int, proto int) (fd int, 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -96,7 +94,7 @@ func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen
 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -106,7 +104,7 @@ func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr)
 func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETPEERNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -116,7 +114,7 @@ func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETSOCKNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -126,7 +124,7 @@ func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 func Shutdown(s int, how int) (err error) {
 	_, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(s), uintptr(how), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -136,7 +134,7 @@ func Shutdown(s int, how int) (err error) {
 func socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) {
 	_, _, e1 := RawSyscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -153,7 +151,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
 	r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -169,7 +167,7 @@ func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (
 	}
 	_, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -180,7 +178,7 @@ func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -191,7 +189,7 @@ 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -202,7 +200,7 @@ func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, ne
 	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 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -218,7 +216,7 @@ func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr)
 	}
 	_, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -234,7 +232,7 @@ func utimes(path string, timeval *[2]Timeval) (err error) {
 	_, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -244,7 +242,7 @@ func utimes(path string, timeval *[2]Timeval) (err error) {
 func futimes(fd int, timeval *[2]Timeval) (err error) {
 	_, _, e1 := Syscall(SYS_FUTIMES, uintptr(fd), uintptr(unsafe.Pointer(timeval)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -255,7 +253,7 @@ func fcntl(fd int, cmd int, arg int) (val int, err error) {
 	r0, _, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg))
 	val = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -267,7 +265,7 @@ func pipe() (r int, w int, err error) {
 	r = int(r0)
 	w = int(r1)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -283,7 +281,7 @@ func Access(path string, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -293,7 +291,7 @@ func Access(path string, mode uint32) (err error) {
 func Adjtime(delta *Timeval, olddelta *Timeval) (err error) {
 	_, _, e1 := Syscall(SYS_ADJTIME, uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -309,7 +307,7 @@ func Chdir(path string) (err error) {
 	_, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -325,7 +323,7 @@ func Chflags(path string, flags int) (err error) {
 	_, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -341,7 +339,7 @@ func Chmod(path string, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -357,7 +355,7 @@ func Chown(path string, uid int, gid int) (err error) {
 	_, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -373,7 +371,7 @@ func Chroot(path string) (err error) {
 	_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -383,7 +381,7 @@ func Chroot(path string) (err error) {
 func Close(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -391,10 +389,10 @@ func Close(fd int) (err error) {
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
 func Dup(fd int) (nfd int, err error) {
-	r0, _, e1 := Syscall(SYS_DUP, uintptr(fd), 0, 0)
+	r0, _, e1 := RawSyscall(SYS_DUP, uintptr(fd), 0, 0)
 	nfd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -402,9 +400,9 @@ func Dup(fd int) (nfd int, err error) {
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
 func Dup2(from int, to int) (err error) {
-	_, _, e1 := Syscall(SYS_DUP2, uintptr(from), uintptr(to), 0)
+	_, _, e1 := RawSyscall(SYS_DUP2, uintptr(from), uintptr(to), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -421,7 +419,7 @@ func Exit(code int) {
 func Fchdir(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -431,7 +429,7 @@ func Fchdir(fd int) (err error) {
 func Fchflags(fd int, flags int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(fd), uintptr(flags), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -441,7 +439,7 @@ func Fchflags(fd int, flags int) (err error) {
 func Fchmod(fd int, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -451,7 +449,7 @@ func Fchmod(fd int, mode uint32) (err error) {
 func Fchown(fd int, uid int, gid int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -461,7 +459,7 @@ func Fchown(fd int, uid int, gid int) (err error) {
 func Flock(fd int, how int) (err error) {
 	_, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -472,7 +470,7 @@ func Fpathconf(fd int, name int) (val int, err error) {
 	r0, _, e1 := Syscall(SYS_FPATHCONF, uintptr(fd), uintptr(name), 0)
 	val = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -482,7 +480,7 @@ func Fpathconf(fd int, name int) (val int, err error) {
 func Fstat(fd int, stat *Stat_t) (err error) {
 	_, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -492,7 +490,7 @@ func Fstat(fd int, stat *Stat_t) (err error) {
 func Fstatfs(fd int, stat *Statfs_t) (err error) {
 	_, _, e1 := Syscall(SYS_FSTATFS, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -502,7 +500,7 @@ func Fstatfs(fd int, stat *Statfs_t) (err error) {
 func Fsync(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -512,7 +510,7 @@ func Fsync(fd int) (err error) {
 func Ftruncate(fd int, length int64) (err error) {
 	_, _, e1 := Syscall6(SYS_FTRUNCATE, uintptr(fd), 0, uintptr(length), uintptr(length>>32), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -529,7 +527,7 @@ func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
 	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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -572,7 +570,7 @@ func Getpgid(pid int) (pgid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0)
 	pgid = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -607,7 +605,7 @@ func Getpriority(which int, who int) (prio int, err error) {
 	r0, _, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0)
 	prio = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -617,7 +615,7 @@ func Getpriority(which int, who int) (prio int, err error) {
 func Getrlimit(which int, lim *Rlimit) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -627,7 +625,7 @@ func Getrlimit(which int, lim *Rlimit) (err error) {
 func Getrusage(who int, rusage *Rusage) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -638,7 +636,7 @@ func Getsid(pid int) (sid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0)
 	sid = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -648,7 +646,7 @@ func Getsid(pid int) (sid int, err error) {
 func Gettimeofday(tv *Timeval) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -674,7 +672,7 @@ func Issetugid() (tainted bool) {
 func Kill(pid int, signum Signal) (err error) {
 	_, _, e1 := Syscall(SYS_KILL, uintptr(pid), uintptr(signum), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -685,7 +683,7 @@ func Kqueue() (fd int, err error) {
 	r0, _, e1 := Syscall(SYS_KQUEUE, 0, 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -701,7 +699,7 @@ func Lchown(path string, uid int, gid int) (err error) {
 	_, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -723,7 +721,7 @@ func Link(path string, link string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -733,7 +731,7 @@ func Link(path string, link string) (err error) {
 func Listen(s int, backlog int) (err error) {
 	_, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(backlog), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -749,7 +747,7 @@ func Lstat(path string, stat *Stat_t) (err error) {
 	_, _, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -765,7 +763,7 @@ func Mkdir(path string, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -781,7 +779,7 @@ func Mkfifo(path string, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -797,7 +795,7 @@ func Mknod(path string, mode uint32, dev int) (err error) {
 	_, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -807,7 +805,7 @@ func Mknod(path string, mode uint32, dev int) (err error) {
 func Nanosleep(time *Timespec, leftover *Timespec) (err error) {
 	_, _, e1 := Syscall(SYS_NANOSLEEP, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -824,7 +822,7 @@ func Open(path string, mode int, perm uint32) (fd int, err error) {
 	use(unsafe.Pointer(_p0))
 	fd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -841,7 +839,7 @@ func Pathconf(path string, name int) (val int, err error) {
 	use(unsafe.Pointer(_p0))
 	val = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -858,7 +856,7 @@ func Pread(fd int, p []byte, offset int64) (n int, err error) {
 	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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -875,7 +873,7 @@ func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
 	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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -892,7 +890,7 @@ func read(fd int, p []byte) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -915,7 +913,7 @@ func Readlink(path string, buf []byte) (n int, err error) {
 	use(unsafe.Pointer(_p0))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -937,7 +935,7 @@ func Rename(from string, to string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -953,7 +951,7 @@ func Revoke(path string) (err error) {
 	_, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -969,7 +967,7 @@ func Rmdir(path string) (err error) {
 	_, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -980,7 +978,7 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
 	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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -990,7 +988,7 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
 func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error) {
 	_, _, e1 := Syscall6(SYS_SELECT, uintptr(n), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1000,7 +998,7 @@ func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error) {
 func Setegid(egid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETEGID, uintptr(egid), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1010,7 +1008,7 @@ func Setegid(egid int) (err error) {
 func Seteuid(euid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETEUID, uintptr(euid), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1020,7 +1018,7 @@ func Seteuid(euid int) (err error) {
 func Setgid(gid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETGID, uintptr(gid), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1036,7 +1034,7 @@ func Setlogin(name string) (err error) {
 	_, _, e1 := Syscall(SYS_SETLOGIN, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1046,7 +1044,7 @@ func Setlogin(name string) (err error) {
 func Setpgid(pid int, pgid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1056,7 +1054,7 @@ func Setpgid(pid int, pgid int) (err error) {
 func Setpriority(which int, who int, prio int) (err error) {
 	_, _, e1 := Syscall(SYS_SETPRIORITY, uintptr(which), uintptr(who), uintptr(prio))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1066,7 +1064,7 @@ func Setpriority(which int, who int, prio int) (err error) {
 func Setregid(rgid int, egid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1076,7 +1074,7 @@ func Setregid(rgid int, egid int) (err error) {
 func Setreuid(ruid int, euid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1086,7 +1084,7 @@ func Setreuid(ruid int, euid int) (err error) {
 func Setrlimit(which int, lim *Rlimit) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1097,7 +1095,7 @@ func Setsid() (pid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0)
 	pid = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1107,7 +1105,7 @@ func Setsid() (pid int, err error) {
 func Settimeofday(tp *Timeval) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1117,7 +1115,7 @@ func Settimeofday(tp *Timeval) (err error) {
 func Setuid(uid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETUID, uintptr(uid), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1133,7 +1131,7 @@ func Stat(path string, stat *Stat_t) (err error) {
 	_, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1149,7 +1147,7 @@ func Statfs(path string, stat *Statfs_t) (err error) {
 	_, _, e1 := Syscall(SYS_STATFS, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1171,7 +1169,7 @@ func Symlink(path string, link string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1181,7 +1179,7 @@ func Symlink(path string, link string) (err error) {
 func Sync() (err error) {
 	_, _, e1 := Syscall(SYS_SYNC, 0, 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1197,7 +1195,7 @@ func Truncate(path string, length int64) (err error) {
 	_, _, e1 := Syscall6(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), 0, uintptr(length), uintptr(length>>32), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1221,7 +1219,7 @@ func Undelete(path string) (err error) {
 	_, _, e1 := Syscall(SYS_UNDELETE, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1237,7 +1235,7 @@ func Unlink(path string) (err error) {
 	_, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1253,7 +1251,7 @@ func Unmount(path string, flags int) (err error) {
 	_, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1270,7 +1268,7 @@ func write(fd int, p []byte) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1281,7 +1279,7 @@ func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (
 	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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1291,7 +1289,7 @@ func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (
 func munmap(addr uintptr, length uintptr) (err error) {
 	_, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1302,7 +1300,7 @@ 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1313,7 +1311,7 @@ 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1324,7 +1322,7 @@ func accept4(fd int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (nfd int
 	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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
diff --git a/src/syscall/zsyscall_linux_386.go b/src/syscall/zsyscall_linux_386.go
index 620fba2..dee8343 100644
--- a/src/syscall/zsyscall_linux_386.go
+++ b/src/syscall/zsyscall_linux_386.go
@@ -1,30 +1,23 @@
 // mksyscall.pl -l32 syscall_linux.go syscall_linux_386.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
-// +build 386,linux
-
 package syscall
 
 import "unsafe"
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags int) (err error) {
+func open(path string, mode int, perm uint32) (fd int, err error) {
 	var _p0 *byte
-	_p0, err = BytePtrFromString(oldpath)
-	if err != nil {
-		return
-	}
-	var _p1 *byte
-	_p1, err = BytePtrFromString(newpath)
+	_p0, err = BytePtrFromString(path)
 	if err != nil {
 		return
 	}
-	_, _, e1 := Syscall6(SYS_LINKAT, uintptr(olddirfd), uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1)), uintptr(flags), 0)
+	r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm))
 	use(unsafe.Pointer(_p0))
-	use(unsafe.Pointer(_p1))
+	fd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -41,68 +34,27 @@ func openat(dirfd int, path string, flags int, mode uint32) (fd int, err error)
 	use(unsafe.Pointer(_p0))
 	fd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func readlinkat(dirfd int, path string, buf []byte) (n int, err error) {
-	var _p0 *byte
-	_p0, err = BytePtrFromString(path)
-	if err != nil {
-		return
-	}
-	var _p1 unsafe.Pointer
-	if len(buf) > 0 {
-		_p1 = unsafe.Pointer(&buf[0])
-	} else {
-		_p1 = unsafe.Pointer(&_zero)
-	}
-	r0, _, e1 := Syscall6(SYS_READLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf)), 0, 0)
-	use(unsafe.Pointer(_p0))
-	n = int(r0)
-	if e1 != 0 {
-		err = errnoErr(e1)
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func symlinkat(oldpath string, newdirfd int, newpath string) (err error) {
-	var _p0 *byte
-	_p0, err = BytePtrFromString(oldpath)
-	if err != nil {
-		return
-	}
-	var _p1 *byte
-	_p1, err = BytePtrFromString(newpath)
-	if err != nil {
-		return
-	}
-	_, _, e1 := Syscall(SYS_SYMLINKAT, uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1)))
-	use(unsafe.Pointer(_p0))
-	use(unsafe.Pointer(_p1))
+func pipe(p *[2]_C_int) (err error) {
+	_, _, e1 := RawSyscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func unlinkat(dirfd int, path string, flags int) (err error) {
-	var _p0 *byte
-	_p0, err = BytePtrFromString(path)
-	if err != nil {
-		return
-	}
-	_, _, e1 := Syscall(SYS_UNLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags))
-	use(unsafe.Pointer(_p0))
+func pipe2(p *[2]_C_int, flags int) (err error) {
+	_, _, e1 := RawSyscall(SYS_PIPE2, uintptr(unsafe.Pointer(p)), uintptr(flags), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -118,7 +70,7 @@ func utimes(path string, times *[2]Timeval) (err error) {
 	_, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -134,7 +86,7 @@ func utimensat(dirfd int, path string, times *[2]Timespec) (err error) {
 	_, _, e1 := Syscall(SYS_UTIMENSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -144,7 +96,7 @@ func utimensat(dirfd int, path string, times *[2]Timespec) (err error) {
 func futimesat(dirfd int, path *byte, times *[2]Timeval) (err error) {
 	_, _, e1 := Syscall(SYS_FUTIMESAT, uintptr(dirfd), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(times)))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -161,7 +113,7 @@ func Getcwd(buf []byte) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_GETCWD, uintptr(_p0), uintptr(len(buf)), 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -172,7 +124,7 @@ func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err
 	r0, _, e1 := Syscall6(SYS_WAIT4, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0)
 	wpid = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -182,7 +134,7 @@ func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err
 func ptrace(request int, pid int, addr uintptr, data uintptr) (err error) {
 	_, _, e1 := Syscall6(SYS_PTRACE, uintptr(request), uintptr(pid), uintptr(addr), uintptr(data), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -198,7 +150,7 @@ func reboot(magic1 uint, magic2 uint, cmd int, arg string) (err error) {
 	_, _, e1 := Syscall6(SYS_REBOOT, uintptr(magic1), uintptr(magic2), uintptr(cmd), uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -226,7 +178,23 @@ func mount(source string, target string, fstype string, flags uintptr, data *byt
 	use(unsafe.Pointer(_p1))
 	use(unsafe.Pointer(_p2))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		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)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = e1
 	}
 	return
 }
@@ -242,7 +210,7 @@ func Acct(path string) (err error) {
 	_, _, e1 := Syscall(SYS_ACCT, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -253,7 +221,7 @@ func Adjtimex(buf *Timex) (state int, err error) {
 	r0, _, e1 := Syscall(SYS_ADJTIMEX, uintptr(unsafe.Pointer(buf)), 0, 0)
 	state = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -269,7 +237,23 @@ func Chdir(path string) (err error) {
 	_, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Chmod(path string, mode uint32) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = e1
 	}
 	return
 }
@@ -285,7 +269,7 @@ func Chroot(path string) (err error) {
 	_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -295,7 +279,24 @@ func Chroot(path string) (err error) {
 func Close(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Creat(path string, mode uint32) (fd int, err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	r0, _, e1 := Syscall(SYS_CREAT, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
+	use(unsafe.Pointer(_p0))
+	fd = int(r0)
+	if e1 != 0 {
+		err = e1
 	}
 	return
 }
@@ -303,10 +304,20 @@ func Close(fd int) (err error) {
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
 func Dup(oldfd int) (fd int, err error) {
-	r0, _, e1 := Syscall(SYS_DUP, uintptr(oldfd), 0, 0)
+	r0, _, e1 := RawSyscall(SYS_DUP, uintptr(oldfd), 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Dup2(oldfd int, newfd int) (err error) {
+	_, _, e1 := RawSyscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0)
+	if e1 != 0 {
+		err = e1
 	}
 	return
 }
@@ -314,9 +325,9 @@ func Dup(oldfd int) (fd int, err error) {
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
 func Dup3(oldfd int, newfd int, flags int) (err error) {
-	_, _, e1 := Syscall(SYS_DUP3, uintptr(oldfd), uintptr(newfd), uintptr(flags))
+	_, _, e1 := RawSyscall(SYS_DUP3, uintptr(oldfd), uintptr(newfd), uintptr(flags))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -327,7 +338,7 @@ func EpollCreate(size int) (fd int, err error) {
 	r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -338,7 +349,7 @@ func EpollCreate1(flag int) (fd int, err error) {
 	r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE1, uintptr(flag), 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -348,7 +359,7 @@ func EpollCreate1(flag int) (fd int, err error) {
 func EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error) {
 	_, _, e1 := RawSyscall6(SYS_EPOLL_CTL, uintptr(epfd), uintptr(op), uintptr(fd), uintptr(unsafe.Pointer(event)), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -365,7 +376,7 @@ func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
 	r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -388,7 +399,7 @@ func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) {
 	_, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -398,7 +409,7 @@ func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) {
 func Fallocate(fd int, mode uint32, off int64, len int64) (err error) {
 	_, _, e1 := Syscall6(SYS_FALLOCATE, uintptr(fd), uintptr(mode), uintptr(off), uintptr(off>>32), uintptr(len), uintptr(len>>32))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -408,7 +419,7 @@ func Fallocate(fd int, mode uint32, off int64, len int64) (err error) {
 func Fchdir(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -418,7 +429,7 @@ func Fchdir(fd int) (err error) {
 func Fchmod(fd int, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -434,7 +445,7 @@ func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) {
 	_, _, e1 := Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -450,7 +461,7 @@ func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) {
 	_, _, e1 := Syscall6(SYS_FCHOWNAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid), uintptr(flags), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -461,7 +472,7 @@ func fcntl(fd int, cmd int, arg int) (val int, err error) {
 	r0, _, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg))
 	val = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -471,7 +482,7 @@ func fcntl(fd int, cmd int, arg int) (val int, err error) {
 func Fdatasync(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FDATASYNC, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -481,7 +492,7 @@ func Fdatasync(fd int) (err error) {
 func Flock(fd int, how int) (err error) {
 	_, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -491,7 +502,7 @@ func Flock(fd int, how int) (err error) {
 func Fsync(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -508,7 +519,7 @@ func Getdents(fd int, buf []byte) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_GETDENTS64, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -519,13 +530,21 @@ func Getpgid(pid int) (pgid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0)
 	pgid = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
+func Getpgrp() (pid int) {
+	r0, _, _ := RawSyscall(SYS_GETPGRP, 0, 0, 0)
+	pid = int(r0)
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
 func Getpid() (pid int) {
 	r0, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0)
 	pid = int(r0)
@@ -546,7 +565,7 @@ func Getpriority(which int, who int) (prio int, err error) {
 	r0, _, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0)
 	prio = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -556,7 +575,7 @@ func Getpriority(which int, who int) (prio int, err error) {
 func Getrusage(who int, rusage *Rusage) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -593,7 +612,7 @@ func Getxattr(path string, attr string, dest []byte) (sz int, err error) {
 	use(unsafe.Pointer(_p1))
 	sz = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -610,7 +629,18 @@ func InotifyAddWatch(fd int, pathname string, mask uint32) (watchdesc int, err e
 	use(unsafe.Pointer(_p0))
 	watchdesc = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func InotifyInit() (fd int, err error) {
+	r0, _, e1 := RawSyscall(SYS_INOTIFY_INIT, 0, 0, 0)
+	fd = int(r0)
+	if e1 != 0 {
+		err = e1
 	}
 	return
 }
@@ -621,7 +651,7 @@ func InotifyInit1(flags int) (fd int, err error) {
 	r0, _, e1 := RawSyscall(SYS_INOTIFY_INIT1, uintptr(flags), 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -632,7 +662,7 @@ func InotifyRmWatch(fd int, watchdesc uint32) (success int, err error) {
 	r0, _, e1 := RawSyscall(SYS_INOTIFY_RM_WATCH, uintptr(fd), uintptr(watchdesc), 0)
 	success = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -642,7 +672,7 @@ func InotifyRmWatch(fd int, watchdesc uint32) (success int, err error) {
 func Kill(pid int, sig Signal) (err error) {
 	_, _, e1 := RawSyscall(SYS_KILL, uintptr(pid), uintptr(sig), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -659,7 +689,29 @@ func Klogctl(typ int, buf []byte) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_SYSLOG, uintptr(typ), uintptr(_p0), uintptr(len(buf)))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Link(oldpath string, newpath string) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(oldpath)
+	if err != nil {
+		return
+	}
+	var _p1 *byte
+	_p1, err = BytePtrFromString(newpath)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_LINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
+	use(unsafe.Pointer(_p0))
+	use(unsafe.Pointer(_p1))
+	if e1 != 0 {
+		err = e1
 	}
 	return
 }
@@ -682,7 +734,23 @@ func Listxattr(path string, dest []byte) (sz int, err error) {
 	use(unsafe.Pointer(_p0))
 	sz = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mkdir(path string, mode uint32) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = e1
 	}
 	return
 }
@@ -698,7 +766,23 @@ func Mkdirat(dirfd int, path string, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_MKDIRAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mknod(path string, mode uint32, dev int) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev))
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = e1
 	}
 	return
 }
@@ -714,7 +798,7 @@ func Mknodat(dirfd int, path string, mode uint32, dev int) (err error) {
 	_, _, e1 := Syscall6(SYS_MKNODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -724,7 +808,7 @@ func Mknodat(dirfd int, path string, mode uint32, dev int) (err error) {
 func Nanosleep(time *Timespec, leftover *Timespec) (err error) {
 	_, _, e1 := Syscall(SYS_NANOSLEEP, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -734,7 +818,7 @@ func Nanosleep(time *Timespec, leftover *Timespec) (err error) {
 func Pause() (err error) {
 	_, _, e1 := Syscall(SYS_PAUSE, 0, 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -756,7 +840,7 @@ func PivotRoot(newroot string, putold string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -766,7 +850,7 @@ func PivotRoot(newroot string, putold string) (err error) {
 func prlimit(pid int, resource int, old *Rlimit, newlimit *Rlimit) (err error) {
 	_, _, e1 := RawSyscall6(SYS_PRLIMIT64, uintptr(pid), uintptr(resource), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(newlimit)), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -783,7 +867,30 @@ func read(fd int, p []byte) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Readlink(path string, buf []byte) (n int, err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	var _p1 unsafe.Pointer
+	if len(buf) > 0 {
+		_p1 = unsafe.Pointer(&buf[0])
+	} else {
+		_p1 = unsafe.Pointer(&_zero)
+	}
+	r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf)))
+	use(unsafe.Pointer(_p0))
+	n = int(r0)
+	if e1 != 0 {
+		err = e1
 	}
 	return
 }
@@ -805,7 +912,29 @@ func Removexattr(path string, attr string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Rename(oldpath string, newpath string) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(oldpath)
+	if err != nil {
+		return
+	}
+	var _p1 *byte
+	_p1, err = BytePtrFromString(newpath)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_RENAME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
+	use(unsafe.Pointer(_p0))
+	use(unsafe.Pointer(_p1))
+	if e1 != 0 {
+		err = e1
 	}
 	return
 }
@@ -827,7 +956,23 @@ func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err e
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Rmdir(path string) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = e1
 	}
 	return
 }
@@ -843,7 +988,7 @@ func Setdomainname(p []byte) (err error) {
 	}
 	_, _, e1 := Syscall(SYS_SETDOMAINNAME, uintptr(_p0), uintptr(len(p)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -859,7 +1004,7 @@ func Sethostname(p []byte) (err error) {
 	}
 	_, _, e1 := Syscall(SYS_SETHOSTNAME, uintptr(_p0), uintptr(len(p)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -869,7 +1014,7 @@ func Sethostname(p []byte) (err error) {
 func Setpgid(pid int, pgid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -880,7 +1025,7 @@ func Setsid() (pid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0)
 	pid = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -890,7 +1035,7 @@ func Setsid() (pid int, err error) {
 func Settimeofday(tv *Timeval) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -900,7 +1045,7 @@ func Settimeofday(tv *Timeval) (err error) {
 func Setpriority(which int, who int, prio int) (err error) {
 	_, _, e1 := Syscall(SYS_SETPRIORITY, uintptr(which), uintptr(who), uintptr(prio))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -928,7 +1073,29 @@ func Setxattr(path string, attr string, data []byte, flags int) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Symlink(oldpath string, newpath string) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(oldpath)
+	if err != nil {
+		return
+	}
+	var _p1 *byte
+	_p1, err = BytePtrFromString(newpath)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_SYMLINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
+	use(unsafe.Pointer(_p0))
+	use(unsafe.Pointer(_p1))
+	if e1 != 0 {
+		err = e1
 	}
 	return
 }
@@ -945,7 +1112,7 @@ func Sync() {
 func Sysinfo(info *Sysinfo_t) (err error) {
 	_, _, e1 := RawSyscall(SYS_SYSINFO, uintptr(unsafe.Pointer(info)), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -956,7 +1123,7 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) {
 	r0, r1, e1 := Syscall6(SYS_TEE, uintptr(rfd), uintptr(wfd), uintptr(len), uintptr(flags), 0, 0)
 	n = int64(int64(r1)<<32 | int64(r0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -966,7 +1133,7 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) {
 func Tgkill(tgid int, tid int, sig Signal) (err error) {
 	_, _, e1 := RawSyscall(SYS_TGKILL, uintptr(tgid), uintptr(tid), uintptr(sig))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -977,7 +1144,7 @@ func Times(tms *Tms) (ticks uintptr, err error) {
 	r0, _, e1 := RawSyscall(SYS_TIMES, uintptr(unsafe.Pointer(tms)), 0, 0)
 	ticks = uintptr(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -995,7 +1162,39 @@ func Umask(mask int) (oldmask int) {
 func Uname(buf *Utsname) (err error) {
 	_, _, e1 := RawSyscall(SYS_UNAME, uintptr(unsafe.Pointer(buf)), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Unlink(path string) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(_p0)), 0, 0)
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Unlinkat(dirfd int, path string) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_UNLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), 0)
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = e1
 	}
 	return
 }
@@ -1011,7 +1210,7 @@ func Unmount(target string, flags int) (err error) {
 	_, _, e1 := Syscall(SYS_UMOUNT2, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1021,7 +1220,7 @@ func Unmount(target string, flags int) (err error) {
 func Unshare(flags int) (err error) {
 	_, _, e1 := Syscall(SYS_UNSHARE, uintptr(flags), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1031,7 +1230,7 @@ func Unshare(flags int) (err error) {
 func Ustat(dev int, ubuf *Ustat_t) (err error) {
 	_, _, e1 := Syscall(SYS_USTAT, uintptr(dev), uintptr(unsafe.Pointer(ubuf)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1047,7 +1246,7 @@ func Utime(path string, buf *Utimbuf) (err error) {
 	_, _, e1 := Syscall(SYS_UTIME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(buf)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1064,7 +1263,7 @@ func write(fd int, p []byte) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1074,7 +1273,7 @@ func write(fd int, p []byte) (n int, err error) {
 func exitThread(code int) (err error) {
 	_, _, e1 := Syscall(SYS_EXIT, uintptr(code), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1085,7 +1284,7 @@ func readlen(fd int, p *byte, np int) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(p)), uintptr(np))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1096,7 +1295,7 @@ func writelen(fd int, p *byte, np int) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(p)), uintptr(np))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1106,7 +1305,7 @@ func writelen(fd int, p *byte, np int) (n int, err error) {
 func munmap(addr uintptr, length uintptr) (err error) {
 	_, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1122,7 +1321,7 @@ func Madvise(b []byte, advice int) (err error) {
 	}
 	_, _, e1 := Syscall(SYS_MADVISE, uintptr(_p0), uintptr(len(b)), uintptr(advice))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1138,7 +1337,7 @@ func Mprotect(b []byte, prot int) (err error) {
 	}
 	_, _, e1 := Syscall(SYS_MPROTECT, uintptr(_p0), uintptr(len(b)), uintptr(prot))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1154,7 +1353,7 @@ func Mlock(b []byte) (err error) {
 	}
 	_, _, e1 := Syscall(SYS_MLOCK, uintptr(_p0), uintptr(len(b)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1170,7 +1369,7 @@ func Munlock(b []byte) (err error) {
 	}
 	_, _, e1 := Syscall(SYS_MUNLOCK, uintptr(_p0), uintptr(len(b)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1180,7 +1379,7 @@ func Munlock(b []byte) (err error) {
 func Mlockall(flags int) (err error) {
 	_, _, e1 := Syscall(SYS_MLOCKALL, uintptr(flags), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1190,37 +1389,23 @@ func Mlockall(flags int) (err error) {
 func Munlockall() (err error) {
 	_, _, e1 := Syscall(SYS_MUNLOCKALL, 0, 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func pipe(p *[2]_C_int) (err error) {
-	_, _, e1 := RawSyscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0)
-	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func pipe2(p *[2]_C_int, flags int) (err error) {
-	_, _, e1 := RawSyscall(SYS_PIPE2, uintptr(unsafe.Pointer(p)), uintptr(flags), 0)
-	if e1 != 0 {
-		err = errnoErr(e1)
+func Chown(path string, uid int, gid int) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
 	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Dup2(oldfd int, newfd int) (err error) {
-	_, _, e1 := Syscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0)
+	_, _, e1 := Syscall(SYS_CHOWN32, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
+	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1230,7 +1415,7 @@ func Dup2(oldfd int, newfd int) (err error) {
 func Fchown(fd int, uid int, gid int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHOWN32, uintptr(fd), uintptr(uid), uintptr(gid))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1240,7 +1425,7 @@ func Fchown(fd int, uid int, gid int) (err error) {
 func Fstat(fd int, stat *Stat_t) (err error) {
 	_, _, e1 := Syscall(SYS_FSTAT64, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1250,7 +1435,7 @@ func Fstat(fd int, stat *Stat_t) (err error) {
 func Ftruncate(fd int, length int64) (err error) {
 	_, _, e1 := Syscall(SYS_FTRUNCATE64, uintptr(fd), uintptr(length), uintptr(length>>32))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1289,21 +1474,10 @@ func Getuid() (uid int) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func InotifyInit() (fd int, err error) {
-	r0, _, e1 := RawSyscall(SYS_INOTIFY_INIT, 0, 0, 0)
-	fd = int(r0)
-	if e1 != 0 {
-		err = errnoErr(e1)
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
 func Ioperm(from int, num int, on int) (err error) {
 	_, _, e1 := Syscall(SYS_IOPERM, uintptr(from), uintptr(num), uintptr(on))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1313,7 +1487,7 @@ func Ioperm(from int, num int, on int) (err error) {
 func Iopl(level int) (err error) {
 	_, _, e1 := Syscall(SYS_IOPL, uintptr(level), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1329,7 +1503,7 @@ func Lchown(path string, uid int, gid int) (err error) {
 	_, _, e1 := Syscall(SYS_LCHOWN32, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1345,7 +1519,7 @@ func Lstat(path string, stat *Stat_t) (err error) {
 	_, _, e1 := Syscall(SYS_LSTAT64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1362,7 +1536,7 @@ func Pread(fd int, p []byte, offset int64) (n int, err error) {
 	r0, _, e1 := Syscall6(SYS_PREAD64, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1379,7 +1553,7 @@ func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
 	r0, _, e1 := Syscall6(SYS_PWRITE64, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1390,7 +1564,7 @@ func sendfile(outfd int, infd int, offset *int64, count int) (written int, err e
 	r0, _, e1 := Syscall6(SYS_SENDFILE64, uintptr(outfd), uintptr(infd), uintptr(unsafe.Pointer(offset)), uintptr(count), 0, 0)
 	written = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1400,7 +1574,7 @@ func sendfile(outfd int, infd int, offset *int64, count int) (written int, err e
 func Setfsgid(gid int) (err error) {
 	_, _, e1 := Syscall(SYS_SETFSGID32, uintptr(gid), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1410,7 +1584,7 @@ func Setfsgid(gid int) (err error) {
 func Setfsuid(uid int) (err error) {
 	_, _, e1 := Syscall(SYS_SETFSUID32, uintptr(uid), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1420,7 +1594,7 @@ func Setfsuid(uid int) (err error) {
 func Setregid(rgid int, egid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETREGID32, uintptr(rgid), uintptr(egid), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1430,7 +1604,7 @@ func Setregid(rgid int, egid int) (err error) {
 func Setresgid(rgid int, egid int, sgid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETRESGID32, uintptr(rgid), uintptr(egid), uintptr(sgid))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1440,7 +1614,7 @@ func Setresgid(rgid int, egid int, sgid int) (err error) {
 func Setresuid(ruid int, euid int, suid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETRESUID32, uintptr(ruid), uintptr(euid), uintptr(suid))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1450,7 +1624,7 @@ func Setresuid(ruid int, euid int, suid int) (err error) {
 func Setreuid(ruid int, euid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETREUID32, uintptr(ruid), uintptr(euid), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1461,7 +1635,7 @@ func Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n i
 	r0, _, e1 := Syscall6(SYS_SPLICE, uintptr(rfd), uintptr(unsafe.Pointer(roff)), uintptr(wfd), uintptr(unsafe.Pointer(woff)), uintptr(len), uintptr(flags))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1477,7 +1651,7 @@ func Stat(path string, stat *Stat_t) (err error) {
 	_, _, e1 := Syscall(SYS_STAT64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1487,7 +1661,7 @@ func Stat(path string, stat *Stat_t) (err error) {
 func SyncFileRange(fd int, off int64, n int64, flags int) (err error) {
 	_, _, e1 := Syscall6(SYS_SYNC_FILE_RANGE, uintptr(fd), uintptr(off), uintptr(off>>32), uintptr(n), uintptr(n>>32), uintptr(flags))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1503,7 +1677,7 @@ func Truncate(path string, length int64) (err error) {
 	_, _, e1 := Syscall(SYS_TRUNCATE64, uintptr(unsafe.Pointer(_p0)), uintptr(length), uintptr(length>>32))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1514,7 +1688,7 @@ func getgroups(n int, list *_Gid_t) (nn int, err error) {
 	r0, _, e1 := RawSyscall(SYS_GETGROUPS32, uintptr(n), uintptr(unsafe.Pointer(list)), 0)
 	nn = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1524,7 +1698,7 @@ func getgroups(n int, list *_Gid_t) (nn int, err error) {
 func setgroups(n int, list *_Gid_t) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETGROUPS32, uintptr(n), uintptr(unsafe.Pointer(list)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1535,7 +1709,7 @@ func Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err
 	r0, _, e1 := Syscall6(SYS__NEWSELECT, uintptr(nfd), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1546,7 +1720,7 @@ func mmap2(addr uintptr, length uintptr, prot int, flags int, fd int, pageOffset
 	r0, _, e1 := Syscall6(SYS_MMAP2, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flags), uintptr(fd), uintptr(pageOffset))
 	xaddr = uintptr(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1556,7 +1730,7 @@ func mmap2(addr uintptr, length uintptr, prot int, flags int, fd int, pageOffset
 func getrlimit(resource int, rlim *rlimit32) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1566,7 +1740,7 @@ func getrlimit(resource int, rlim *rlimit32) (err error) {
 func setrlimit(resource int, rlim *rlimit32) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1576,7 +1750,7 @@ func setrlimit(resource int, rlim *rlimit32) (err error) {
 func Gettimeofday(tv *Timeval) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1587,7 +1761,7 @@ func Time(t *Time_t) (tt Time_t, err error) {
 	r0, _, e1 := RawSyscall(SYS_TIME, uintptr(unsafe.Pointer(t)), 0, 0)
 	tt = Time_t(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
diff --git a/src/syscall/zsyscall_linux_amd64.go b/src/syscall/zsyscall_linux_amd64.go
index 16cafbf..ed3afd4 100644
--- a/src/syscall/zsyscall_linux_amd64.go
+++ b/src/syscall/zsyscall_linux_amd64.go
@@ -1,30 +1,23 @@
 // mksyscall.pl syscall_linux.go syscall_linux_amd64.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
-// +build amd64,linux
-
 package syscall
 
 import "unsafe"
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags int) (err error) {
+func open(path string, mode int, perm uint32) (fd int, err error) {
 	var _p0 *byte
-	_p0, err = BytePtrFromString(oldpath)
-	if err != nil {
-		return
-	}
-	var _p1 *byte
-	_p1, err = BytePtrFromString(newpath)
+	_p0, err = BytePtrFromString(path)
 	if err != nil {
 		return
 	}
-	_, _, e1 := Syscall6(SYS_LINKAT, uintptr(olddirfd), uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1)), uintptr(flags), 0)
+	r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm))
 	use(unsafe.Pointer(_p0))
-	use(unsafe.Pointer(_p1))
+	fd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -41,68 +34,27 @@ func openat(dirfd int, path string, flags int, mode uint32) (fd int, err error)
 	use(unsafe.Pointer(_p0))
 	fd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func readlinkat(dirfd int, path string, buf []byte) (n int, err error) {
-	var _p0 *byte
-	_p0, err = BytePtrFromString(path)
-	if err != nil {
-		return
-	}
-	var _p1 unsafe.Pointer
-	if len(buf) > 0 {
-		_p1 = unsafe.Pointer(&buf[0])
-	} else {
-		_p1 = unsafe.Pointer(&_zero)
-	}
-	r0, _, e1 := Syscall6(SYS_READLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf)), 0, 0)
-	use(unsafe.Pointer(_p0))
-	n = int(r0)
-	if e1 != 0 {
-		err = errnoErr(e1)
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func symlinkat(oldpath string, newdirfd int, newpath string) (err error) {
-	var _p0 *byte
-	_p0, err = BytePtrFromString(oldpath)
-	if err != nil {
-		return
-	}
-	var _p1 *byte
-	_p1, err = BytePtrFromString(newpath)
-	if err != nil {
-		return
-	}
-	_, _, e1 := Syscall(SYS_SYMLINKAT, uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1)))
-	use(unsafe.Pointer(_p0))
-	use(unsafe.Pointer(_p1))
+func pipe(p *[2]_C_int) (err error) {
+	_, _, e1 := RawSyscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func unlinkat(dirfd int, path string, flags int) (err error) {
-	var _p0 *byte
-	_p0, err = BytePtrFromString(path)
-	if err != nil {
-		return
-	}
-	_, _, e1 := Syscall(SYS_UNLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags))
-	use(unsafe.Pointer(_p0))
+func pipe2(p *[2]_C_int, flags int) (err error) {
+	_, _, e1 := RawSyscall(SYS_PIPE2, uintptr(unsafe.Pointer(p)), uintptr(flags), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -118,7 +70,7 @@ func utimes(path string, times *[2]Timeval) (err error) {
 	_, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -134,7 +86,7 @@ func utimensat(dirfd int, path string, times *[2]Timespec) (err error) {
 	_, _, e1 := Syscall(SYS_UTIMENSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -144,7 +96,7 @@ func utimensat(dirfd int, path string, times *[2]Timespec) (err error) {
 func futimesat(dirfd int, path *byte, times *[2]Timeval) (err error) {
 	_, _, e1 := Syscall(SYS_FUTIMESAT, uintptr(dirfd), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(times)))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -161,7 +113,7 @@ func Getcwd(buf []byte) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_GETCWD, uintptr(_p0), uintptr(len(buf)), 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -172,7 +124,7 @@ func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err
 	r0, _, e1 := Syscall6(SYS_WAIT4, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0)
 	wpid = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -182,7 +134,7 @@ func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err
 func ptrace(request int, pid int, addr uintptr, data uintptr) (err error) {
 	_, _, e1 := Syscall6(SYS_PTRACE, uintptr(request), uintptr(pid), uintptr(addr), uintptr(data), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -198,7 +150,7 @@ func reboot(magic1 uint, magic2 uint, cmd int, arg string) (err error) {
 	_, _, e1 := Syscall6(SYS_REBOOT, uintptr(magic1), uintptr(magic2), uintptr(cmd), uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -226,7 +178,23 @@ func mount(source string, target string, fstype string, flags uintptr, data *byt
 	use(unsafe.Pointer(_p1))
 	use(unsafe.Pointer(_p2))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		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)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = e1
 	}
 	return
 }
@@ -242,7 +210,7 @@ func Acct(path string) (err error) {
 	_, _, e1 := Syscall(SYS_ACCT, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -253,7 +221,7 @@ func Adjtimex(buf *Timex) (state int, err error) {
 	r0, _, e1 := Syscall(SYS_ADJTIMEX, uintptr(unsafe.Pointer(buf)), 0, 0)
 	state = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -269,7 +237,23 @@ func Chdir(path string) (err error) {
 	_, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Chmod(path string, mode uint32) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = e1
 	}
 	return
 }
@@ -285,7 +269,7 @@ func Chroot(path string) (err error) {
 	_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -295,7 +279,24 @@ func Chroot(path string) (err error) {
 func Close(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Creat(path string, mode uint32) (fd int, err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	r0, _, e1 := Syscall(SYS_CREAT, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
+	use(unsafe.Pointer(_p0))
+	fd = int(r0)
+	if e1 != 0 {
+		err = e1
 	}
 	return
 }
@@ -303,10 +304,20 @@ func Close(fd int) (err error) {
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
 func Dup(oldfd int) (fd int, err error) {
-	r0, _, e1 := Syscall(SYS_DUP, uintptr(oldfd), 0, 0)
+	r0, _, e1 := RawSyscall(SYS_DUP, uintptr(oldfd), 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Dup2(oldfd int, newfd int) (err error) {
+	_, _, e1 := RawSyscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0)
+	if e1 != 0 {
+		err = e1
 	}
 	return
 }
@@ -314,9 +325,9 @@ func Dup(oldfd int) (fd int, err error) {
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
 func Dup3(oldfd int, newfd int, flags int) (err error) {
-	_, _, e1 := Syscall(SYS_DUP3, uintptr(oldfd), uintptr(newfd), uintptr(flags))
+	_, _, e1 := RawSyscall(SYS_DUP3, uintptr(oldfd), uintptr(newfd), uintptr(flags))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -327,7 +338,7 @@ func EpollCreate(size int) (fd int, err error) {
 	r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -338,7 +349,7 @@ func EpollCreate1(flag int) (fd int, err error) {
 	r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE1, uintptr(flag), 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -348,7 +359,7 @@ func EpollCreate1(flag int) (fd int, err error) {
 func EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error) {
 	_, _, e1 := RawSyscall6(SYS_EPOLL_CTL, uintptr(epfd), uintptr(op), uintptr(fd), uintptr(unsafe.Pointer(event)), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -365,7 +376,7 @@ func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
 	r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -388,7 +399,7 @@ func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) {
 	_, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -398,7 +409,7 @@ func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) {
 func Fallocate(fd int, mode uint32, off int64, len int64) (err error) {
 	_, _, e1 := Syscall6(SYS_FALLOCATE, uintptr(fd), uintptr(mode), uintptr(off), uintptr(len), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -408,7 +419,7 @@ func Fallocate(fd int, mode uint32, off int64, len int64) (err error) {
 func Fchdir(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -418,7 +429,7 @@ func Fchdir(fd int) (err error) {
 func Fchmod(fd int, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -434,7 +445,7 @@ func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) {
 	_, _, e1 := Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -450,7 +461,7 @@ func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) {
 	_, _, e1 := Syscall6(SYS_FCHOWNAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid), uintptr(flags), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -461,7 +472,7 @@ func fcntl(fd int, cmd int, arg int) (val int, err error) {
 	r0, _, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg))
 	val = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -471,7 +482,7 @@ func fcntl(fd int, cmd int, arg int) (val int, err error) {
 func Fdatasync(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FDATASYNC, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -481,7 +492,7 @@ func Fdatasync(fd int) (err error) {
 func Flock(fd int, how int) (err error) {
 	_, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -491,7 +502,7 @@ func Flock(fd int, how int) (err error) {
 func Fsync(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -508,7 +519,7 @@ func Getdents(fd int, buf []byte) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_GETDENTS64, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -519,13 +530,21 @@ func Getpgid(pid int) (pgid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0)
 	pgid = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
+func Getpgrp() (pid int) {
+	r0, _, _ := RawSyscall(SYS_GETPGRP, 0, 0, 0)
+	pid = int(r0)
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
 func Getpid() (pid int) {
 	r0, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0)
 	pid = int(r0)
@@ -546,7 +565,7 @@ func Getpriority(which int, who int) (prio int, err error) {
 	r0, _, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0)
 	prio = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -556,7 +575,7 @@ func Getpriority(which int, who int) (prio int, err error) {
 func Getrusage(who int, rusage *Rusage) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -593,7 +612,7 @@ func Getxattr(path string, attr string, dest []byte) (sz int, err error) {
 	use(unsafe.Pointer(_p1))
 	sz = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -610,7 +629,18 @@ func InotifyAddWatch(fd int, pathname string, mask uint32) (watchdesc int, err e
 	use(unsafe.Pointer(_p0))
 	watchdesc = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func InotifyInit() (fd int, err error) {
+	r0, _, e1 := RawSyscall(SYS_INOTIFY_INIT, 0, 0, 0)
+	fd = int(r0)
+	if e1 != 0 {
+		err = e1
 	}
 	return
 }
@@ -621,7 +651,7 @@ func InotifyInit1(flags int) (fd int, err error) {
 	r0, _, e1 := RawSyscall(SYS_INOTIFY_INIT1, uintptr(flags), 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -632,7 +662,7 @@ func InotifyRmWatch(fd int, watchdesc uint32) (success int, err error) {
 	r0, _, e1 := RawSyscall(SYS_INOTIFY_RM_WATCH, uintptr(fd), uintptr(watchdesc), 0)
 	success = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -642,7 +672,7 @@ func InotifyRmWatch(fd int, watchdesc uint32) (success int, err error) {
 func Kill(pid int, sig Signal) (err error) {
 	_, _, e1 := RawSyscall(SYS_KILL, uintptr(pid), uintptr(sig), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -659,7 +689,29 @@ func Klogctl(typ int, buf []byte) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_SYSLOG, uintptr(typ), uintptr(_p0), uintptr(len(buf)))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Link(oldpath string, newpath string) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(oldpath)
+	if err != nil {
+		return
+	}
+	var _p1 *byte
+	_p1, err = BytePtrFromString(newpath)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_LINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
+	use(unsafe.Pointer(_p0))
+	use(unsafe.Pointer(_p1))
+	if e1 != 0 {
+		err = e1
 	}
 	return
 }
@@ -682,7 +734,23 @@ func Listxattr(path string, dest []byte) (sz int, err error) {
 	use(unsafe.Pointer(_p0))
 	sz = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mkdir(path string, mode uint32) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = e1
 	}
 	return
 }
@@ -698,7 +766,23 @@ func Mkdirat(dirfd int, path string, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_MKDIRAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mknod(path string, mode uint32, dev int) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev))
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = e1
 	}
 	return
 }
@@ -714,7 +798,7 @@ func Mknodat(dirfd int, path string, mode uint32, dev int) (err error) {
 	_, _, e1 := Syscall6(SYS_MKNODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -724,7 +808,7 @@ func Mknodat(dirfd int, path string, mode uint32, dev int) (err error) {
 func Nanosleep(time *Timespec, leftover *Timespec) (err error) {
 	_, _, e1 := Syscall(SYS_NANOSLEEP, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -734,7 +818,7 @@ func Nanosleep(time *Timespec, leftover *Timespec) (err error) {
 func Pause() (err error) {
 	_, _, e1 := Syscall(SYS_PAUSE, 0, 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -756,7 +840,7 @@ func PivotRoot(newroot string, putold string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -766,7 +850,7 @@ func PivotRoot(newroot string, putold string) (err error) {
 func prlimit(pid int, resource int, old *Rlimit, newlimit *Rlimit) (err error) {
 	_, _, e1 := RawSyscall6(SYS_PRLIMIT64, uintptr(pid), uintptr(resource), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(newlimit)), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -783,7 +867,30 @@ func read(fd int, p []byte) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Readlink(path string, buf []byte) (n int, err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	var _p1 unsafe.Pointer
+	if len(buf) > 0 {
+		_p1 = unsafe.Pointer(&buf[0])
+	} else {
+		_p1 = unsafe.Pointer(&_zero)
+	}
+	r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf)))
+	use(unsafe.Pointer(_p0))
+	n = int(r0)
+	if e1 != 0 {
+		err = e1
 	}
 	return
 }
@@ -805,7 +912,29 @@ func Removexattr(path string, attr string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Rename(oldpath string, newpath string) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(oldpath)
+	if err != nil {
+		return
+	}
+	var _p1 *byte
+	_p1, err = BytePtrFromString(newpath)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_RENAME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
+	use(unsafe.Pointer(_p0))
+	use(unsafe.Pointer(_p1))
+	if e1 != 0 {
+		err = e1
 	}
 	return
 }
@@ -827,7 +956,23 @@ func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err e
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Rmdir(path string) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = e1
 	}
 	return
 }
@@ -843,7 +988,7 @@ func Setdomainname(p []byte) (err error) {
 	}
 	_, _, e1 := Syscall(SYS_SETDOMAINNAME, uintptr(_p0), uintptr(len(p)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -859,7 +1004,7 @@ func Sethostname(p []byte) (err error) {
 	}
 	_, _, e1 := Syscall(SYS_SETHOSTNAME, uintptr(_p0), uintptr(len(p)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -869,7 +1014,7 @@ func Sethostname(p []byte) (err error) {
 func Setpgid(pid int, pgid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -880,7 +1025,7 @@ func Setsid() (pid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0)
 	pid = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -890,7 +1035,7 @@ func Setsid() (pid int, err error) {
 func Settimeofday(tv *Timeval) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -900,7 +1045,7 @@ func Settimeofday(tv *Timeval) (err error) {
 func Setpriority(which int, who int, prio int) (err error) {
 	_, _, e1 := Syscall(SYS_SETPRIORITY, uintptr(which), uintptr(who), uintptr(prio))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -928,7 +1073,29 @@ func Setxattr(path string, attr string, data []byte, flags int) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Symlink(oldpath string, newpath string) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(oldpath)
+	if err != nil {
+		return
+	}
+	var _p1 *byte
+	_p1, err = BytePtrFromString(newpath)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_SYMLINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
+	use(unsafe.Pointer(_p0))
+	use(unsafe.Pointer(_p1))
+	if e1 != 0 {
+		err = e1
 	}
 	return
 }
@@ -945,7 +1112,7 @@ func Sync() {
 func Sysinfo(info *Sysinfo_t) (err error) {
 	_, _, e1 := RawSyscall(SYS_SYSINFO, uintptr(unsafe.Pointer(info)), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -956,7 +1123,7 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) {
 	r0, _, e1 := Syscall6(SYS_TEE, uintptr(rfd), uintptr(wfd), uintptr(len), uintptr(flags), 0, 0)
 	n = int64(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -966,7 +1133,7 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) {
 func Tgkill(tgid int, tid int, sig Signal) (err error) {
 	_, _, e1 := RawSyscall(SYS_TGKILL, uintptr(tgid), uintptr(tid), uintptr(sig))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -977,7 +1144,7 @@ func Times(tms *Tms) (ticks uintptr, err error) {
 	r0, _, e1 := RawSyscall(SYS_TIMES, uintptr(unsafe.Pointer(tms)), 0, 0)
 	ticks = uintptr(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -995,7 +1162,39 @@ func Umask(mask int) (oldmask int) {
 func Uname(buf *Utsname) (err error) {
 	_, _, e1 := RawSyscall(SYS_UNAME, uintptr(unsafe.Pointer(buf)), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Unlink(path string) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(_p0)), 0, 0)
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Unlinkat(dirfd int, path string) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_UNLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), 0)
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = e1
 	}
 	return
 }
@@ -1011,7 +1210,7 @@ func Unmount(target string, flags int) (err error) {
 	_, _, e1 := Syscall(SYS_UMOUNT2, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1021,7 +1220,7 @@ func Unmount(target string, flags int) (err error) {
 func Unshare(flags int) (err error) {
 	_, _, e1 := Syscall(SYS_UNSHARE, uintptr(flags), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1031,7 +1230,7 @@ func Unshare(flags int) (err error) {
 func Ustat(dev int, ubuf *Ustat_t) (err error) {
 	_, _, e1 := Syscall(SYS_USTAT, uintptr(dev), uintptr(unsafe.Pointer(ubuf)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1047,7 +1246,7 @@ func Utime(path string, buf *Utimbuf) (err error) {
 	_, _, e1 := Syscall(SYS_UTIME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(buf)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1064,7 +1263,7 @@ func write(fd int, p []byte) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1074,7 +1273,7 @@ func write(fd int, p []byte) (n int, err error) {
 func exitThread(code int) (err error) {
 	_, _, e1 := Syscall(SYS_EXIT, uintptr(code), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1085,7 +1284,7 @@ func readlen(fd int, p *byte, np int) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(p)), uintptr(np))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1096,7 +1295,7 @@ func writelen(fd int, p *byte, np int) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(p)), uintptr(np))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1106,7 +1305,7 @@ func writelen(fd int, p *byte, np int) (n int, err error) {
 func munmap(addr uintptr, length uintptr) (err error) {
 	_, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1122,7 +1321,7 @@ func Madvise(b []byte, advice int) (err error) {
 	}
 	_, _, e1 := Syscall(SYS_MADVISE, uintptr(_p0), uintptr(len(b)), uintptr(advice))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1138,7 +1337,7 @@ func Mprotect(b []byte, prot int) (err error) {
 	}
 	_, _, e1 := Syscall(SYS_MPROTECT, uintptr(_p0), uintptr(len(b)), uintptr(prot))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1154,7 +1353,7 @@ func Mlock(b []byte) (err error) {
 	}
 	_, _, e1 := Syscall(SYS_MLOCK, uintptr(_p0), uintptr(len(b)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1170,7 +1369,7 @@ func Munlock(b []byte) (err error) {
 	}
 	_, _, e1 := Syscall(SYS_MUNLOCK, uintptr(_p0), uintptr(len(b)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1180,7 +1379,7 @@ func Munlock(b []byte) (err error) {
 func Mlockall(flags int) (err error) {
 	_, _, e1 := Syscall(SYS_MLOCKALL, uintptr(flags), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1190,17 +1389,23 @@ func Mlockall(flags int) (err error) {
 func Munlockall() (err error) {
 	_, _, e1 := Syscall(SYS_MUNLOCKALL, 0, 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func Dup2(oldfd int, newfd int) (err error) {
-	_, _, e1 := Syscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0)
+func Chown(path string, uid int, gid int) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
+	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1210,7 +1415,7 @@ func Dup2(oldfd int, newfd int) (err error) {
 func Fchown(fd int, uid int, gid int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1220,7 +1425,7 @@ func Fchown(fd int, uid int, gid int) (err error) {
 func Fstat(fd int, stat *Stat_t) (err error) {
 	_, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1230,7 +1435,7 @@ func Fstat(fd int, stat *Stat_t) (err error) {
 func Fstatfs(fd int, buf *Statfs_t) (err error) {
 	_, _, e1 := Syscall(SYS_FSTATFS, uintptr(fd), uintptr(unsafe.Pointer(buf)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1240,7 +1445,7 @@ func Fstatfs(fd int, buf *Statfs_t) (err error) {
 func Ftruncate(fd int, length int64) (err error) {
 	_, _, e1 := Syscall(SYS_FTRUNCATE, uintptr(fd), uintptr(length), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1274,7 +1479,7 @@ func Getgid() (gid int) {
 func Getrlimit(resource int, rlim *Rlimit) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1289,21 +1494,10 @@ func Getuid() (uid int) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func InotifyInit() (fd int, err error) {
-	r0, _, e1 := RawSyscall(SYS_INOTIFY_INIT, 0, 0, 0)
-	fd = int(r0)
-	if e1 != 0 {
-		err = errnoErr(e1)
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
 func Ioperm(from int, num int, on int) (err error) {
 	_, _, e1 := Syscall(SYS_IOPERM, uintptr(from), uintptr(num), uintptr(on))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1313,7 +1507,7 @@ func Ioperm(from int, num int, on int) (err error) {
 func Iopl(level int) (err error) {
 	_, _, e1 := Syscall(SYS_IOPL, uintptr(level), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1329,7 +1523,7 @@ func Lchown(path string, uid int, gid int) (err error) {
 	_, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1339,7 +1533,7 @@ func Lchown(path string, uid int, gid int) (err error) {
 func Listen(s int, n int) (err error) {
 	_, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(n), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1355,7 +1549,7 @@ func Lstat(path string, stat *Stat_t) (err error) {
 	_, _, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1372,7 +1566,7 @@ func Pread(fd int, p []byte, offset int64) (n int, err error) {
 	r0, _, e1 := Syscall6(SYS_PREAD64, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), 0, 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1389,7 +1583,7 @@ func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
 	r0, _, e1 := Syscall6(SYS_PWRITE64, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), 0, 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1400,7 +1594,7 @@ func Seek(fd int, offset int64, whence int) (off int64, err error) {
 	r0, _, e1 := Syscall(SYS_LSEEK, uintptr(fd), uintptr(offset), uintptr(whence))
 	off = int64(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1411,7 +1605,7 @@ func Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err
 	r0, _, e1 := Syscall6(SYS_SELECT, uintptr(nfd), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1422,7 +1616,7 @@ func sendfile(outfd int, infd int, offset *int64, count int) (written int, err e
 	r0, _, e1 := Syscall6(SYS_SENDFILE, uintptr(outfd), uintptr(infd), uintptr(unsafe.Pointer(offset)), uintptr(count), 0, 0)
 	written = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1432,7 +1626,7 @@ func sendfile(outfd int, infd int, offset *int64, count int) (written int, err e
 func Setfsgid(gid int) (err error) {
 	_, _, e1 := Syscall(SYS_SETFSGID, uintptr(gid), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1442,7 +1636,7 @@ func Setfsgid(gid int) (err error) {
 func Setfsuid(uid int) (err error) {
 	_, _, e1 := Syscall(SYS_SETFSUID, uintptr(uid), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1452,7 +1646,7 @@ func Setfsuid(uid int) (err error) {
 func Setregid(rgid int, egid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1462,7 +1656,7 @@ func Setregid(rgid int, egid int) (err error) {
 func Setresgid(rgid int, egid int, sgid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETRESGID, uintptr(rgid), uintptr(egid), uintptr(sgid))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1472,7 +1666,7 @@ func Setresgid(rgid int, egid int, sgid int) (err error) {
 func Setresuid(ruid int, euid int, suid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETRESUID, uintptr(ruid), uintptr(euid), uintptr(suid))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1482,7 +1676,7 @@ func Setresuid(ruid int, euid int, suid int) (err error) {
 func Setrlimit(resource int, rlim *Rlimit) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1492,7 +1686,7 @@ func Setrlimit(resource int, rlim *Rlimit) (err error) {
 func Setreuid(ruid int, euid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1502,7 +1696,7 @@ func Setreuid(ruid int, euid int) (err error) {
 func Shutdown(fd int, how int) (err error) {
 	_, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(fd), uintptr(how), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1513,7 +1707,7 @@ func Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n i
 	r0, _, e1 := Syscall6(SYS_SPLICE, uintptr(rfd), uintptr(unsafe.Pointer(roff)), uintptr(wfd), uintptr(unsafe.Pointer(woff)), uintptr(len), uintptr(flags))
 	n = int64(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1529,7 +1723,7 @@ func Stat(path string, stat *Stat_t) (err error) {
 	_, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1545,7 +1739,7 @@ func Statfs(path string, buf *Statfs_t) (err error) {
 	_, _, e1 := Syscall(SYS_STATFS, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(buf)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1555,7 +1749,7 @@ func Statfs(path string, buf *Statfs_t) (err error) {
 func SyncFileRange(fd int, off int64, n int64, flags int) (err error) {
 	_, _, e1 := Syscall6(SYS_SYNC_FILE_RANGE, uintptr(fd), uintptr(off), uintptr(n), uintptr(flags), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1571,7 +1765,7 @@ func Truncate(path string, length int64) (err error) {
 	_, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), uintptr(length), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1582,7 +1776,7 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
 	r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	fd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1593,7 +1787,7 @@ func accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int,
 	r0, _, e1 := Syscall6(SYS_ACCEPT4, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), uintptr(flags), 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1603,7 +1797,7 @@ func accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int,
 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1613,7 +1807,7 @@ func bind(s int, addr unsafe.Pointer, 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1624,7 +1818,7 @@ func getgroups(n int, list *_Gid_t) (nn int, err error) {
 	r0, _, e1 := RawSyscall(SYS_GETGROUPS, uintptr(n), uintptr(unsafe.Pointer(list)), 0)
 	nn = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1634,7 +1828,7 @@ func getgroups(n int, list *_Gid_t) (nn int, err error) {
 func setgroups(n int, list *_Gid_t) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETGROUPS, uintptr(n), uintptr(unsafe.Pointer(list)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1644,7 +1838,7 @@ func setgroups(n int, list *_Gid_t) (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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1654,7 +1848,7 @@ func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen
 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1665,7 +1859,7 @@ func socket(domain int, typ int, proto int) (fd int, err error) {
 	r0, _, e1 := RawSyscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto))
 	fd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1675,7 +1869,7 @@ func socket(domain int, typ int, proto int) (fd int, err error) {
 func socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) {
 	_, _, e1 := RawSyscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1685,7 +1879,7 @@ func socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) {
 func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETPEERNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1695,7 +1889,7 @@ func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETSOCKNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1712,7 +1906,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
 	r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1728,7 +1922,7 @@ func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (
 	}
 	_, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1739,7 +1933,7 @@ func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1750,7 +1944,7 @@ 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1761,27 +1955,7 @@ func mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int6
 	r0, _, e1 := Syscall6(SYS_MMAP, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flags), uintptr(fd), uintptr(offset))
 	xaddr = uintptr(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func pipe(p *[2]_C_int) (err error) {
-	_, _, e1 := RawSyscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0)
-	if e1 != 0 {
-		err = errnoErr(e1)
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func pipe2(p *[2]_C_int, flags int) (err error) {
-	_, _, e1 := RawSyscall(SYS_PIPE2, uintptr(unsafe.Pointer(p)), uintptr(flags), 0)
-	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
diff --git a/src/syscall/zsyscall_linux_arm.go b/src/syscall/zsyscall_linux_arm.go
index 9bc3a54..fbf6935 100644
--- a/src/syscall/zsyscall_linux_arm.go
+++ b/src/syscall/zsyscall_linux_arm.go
@@ -1,30 +1,23 @@
 // mksyscall.pl -l32 -arm syscall_linux.go syscall_linux_arm.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
-// +build arm,linux
-
 package syscall
 
 import "unsafe"
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags int) (err error) {
+func open(path string, mode int, perm uint32) (fd int, err error) {
 	var _p0 *byte
-	_p0, err = BytePtrFromString(oldpath)
-	if err != nil {
-		return
-	}
-	var _p1 *byte
-	_p1, err = BytePtrFromString(newpath)
+	_p0, err = BytePtrFromString(path)
 	if err != nil {
 		return
 	}
-	_, _, e1 := Syscall6(SYS_LINKAT, uintptr(olddirfd), uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1)), uintptr(flags), 0)
+	r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm))
 	use(unsafe.Pointer(_p0))
-	use(unsafe.Pointer(_p1))
+	fd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -41,68 +34,27 @@ func openat(dirfd int, path string, flags int, mode uint32) (fd int, err error)
 	use(unsafe.Pointer(_p0))
 	fd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func readlinkat(dirfd int, path string, buf []byte) (n int, err error) {
-	var _p0 *byte
-	_p0, err = BytePtrFromString(path)
-	if err != nil {
-		return
-	}
-	var _p1 unsafe.Pointer
-	if len(buf) > 0 {
-		_p1 = unsafe.Pointer(&buf[0])
-	} else {
-		_p1 = unsafe.Pointer(&_zero)
-	}
-	r0, _, e1 := Syscall6(SYS_READLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf)), 0, 0)
-	use(unsafe.Pointer(_p0))
-	n = int(r0)
+func pipe(p *[2]_C_int) (err error) {
+	_, _, e1 := RawSyscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func symlinkat(oldpath string, newdirfd int, newpath string) (err error) {
-	var _p0 *byte
-	_p0, err = BytePtrFromString(oldpath)
-	if err != nil {
-		return
-	}
-	var _p1 *byte
-	_p1, err = BytePtrFromString(newpath)
-	if err != nil {
-		return
-	}
-	_, _, e1 := Syscall(SYS_SYMLINKAT, uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1)))
-	use(unsafe.Pointer(_p0))
-	use(unsafe.Pointer(_p1))
-	if e1 != 0 {
-		err = errnoErr(e1)
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func unlinkat(dirfd int, path string, flags int) (err error) {
-	var _p0 *byte
-	_p0, err = BytePtrFromString(path)
-	if err != nil {
-		return
-	}
-	_, _, e1 := Syscall(SYS_UNLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(flags))
-	use(unsafe.Pointer(_p0))
+func pipe2(p *[2]_C_int, flags int) (err error) {
+	_, _, e1 := RawSyscall(SYS_PIPE2, uintptr(unsafe.Pointer(p)), uintptr(flags), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -118,7 +70,7 @@ func utimes(path string, times *[2]Timeval) (err error) {
 	_, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -134,7 +86,7 @@ func utimensat(dirfd int, path string, times *[2]Timespec) (err error) {
 	_, _, e1 := Syscall(SYS_UTIMENSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -144,7 +96,7 @@ func utimensat(dirfd int, path string, times *[2]Timespec) (err error) {
 func futimesat(dirfd int, path *byte, times *[2]Timeval) (err error) {
 	_, _, e1 := Syscall(SYS_FUTIMESAT, uintptr(dirfd), uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(times)))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -161,7 +113,7 @@ func Getcwd(buf []byte) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_GETCWD, uintptr(_p0), uintptr(len(buf)), 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -172,7 +124,7 @@ func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err
 	r0, _, e1 := Syscall6(SYS_WAIT4, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0)
 	wpid = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -182,7 +134,7 @@ func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err
 func ptrace(request int, pid int, addr uintptr, data uintptr) (err error) {
 	_, _, e1 := Syscall6(SYS_PTRACE, uintptr(request), uintptr(pid), uintptr(addr), uintptr(data), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -198,7 +150,7 @@ func reboot(magic1 uint, magic2 uint, cmd int, arg string) (err error) {
 	_, _, e1 := Syscall6(SYS_REBOOT, uintptr(magic1), uintptr(magic2), uintptr(cmd), uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -226,7 +178,23 @@ func mount(source string, target string, fstype string, flags uintptr, data *byt
 	use(unsafe.Pointer(_p1))
 	use(unsafe.Pointer(_p2))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		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)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = e1
 	}
 	return
 }
@@ -242,7 +210,7 @@ func Acct(path string) (err error) {
 	_, _, e1 := Syscall(SYS_ACCT, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -253,7 +221,7 @@ func Adjtimex(buf *Timex) (state int, err error) {
 	r0, _, e1 := Syscall(SYS_ADJTIMEX, uintptr(unsafe.Pointer(buf)), 0, 0)
 	state = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -269,7 +237,23 @@ func Chdir(path string) (err error) {
 	_, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Chmod(path string, mode uint32) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = e1
 	}
 	return
 }
@@ -285,7 +269,7 @@ func Chroot(path string) (err error) {
 	_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -295,7 +279,24 @@ func Chroot(path string) (err error) {
 func Close(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Creat(path string, mode uint32) (fd int, err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	r0, _, e1 := Syscall(SYS_CREAT, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
+	use(unsafe.Pointer(_p0))
+	fd = int(r0)
+	if e1 != 0 {
+		err = e1
 	}
 	return
 }
@@ -303,10 +304,20 @@ func Close(fd int) (err error) {
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
 func Dup(oldfd int) (fd int, err error) {
-	r0, _, e1 := Syscall(SYS_DUP, uintptr(oldfd), 0, 0)
+	r0, _, e1 := RawSyscall(SYS_DUP, uintptr(oldfd), 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Dup2(oldfd int, newfd int) (err error) {
+	_, _, e1 := RawSyscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0)
+	if e1 != 0 {
+		err = e1
 	}
 	return
 }
@@ -314,9 +325,9 @@ func Dup(oldfd int) (fd int, err error) {
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
 func Dup3(oldfd int, newfd int, flags int) (err error) {
-	_, _, e1 := Syscall(SYS_DUP3, uintptr(oldfd), uintptr(newfd), uintptr(flags))
+	_, _, e1 := RawSyscall(SYS_DUP3, uintptr(oldfd), uintptr(newfd), uintptr(flags))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -327,7 +338,7 @@ func EpollCreate(size int) (fd int, err error) {
 	r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE, uintptr(size), 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -338,7 +349,7 @@ func EpollCreate1(flag int) (fd int, err error) {
 	r0, _, e1 := RawSyscall(SYS_EPOLL_CREATE1, uintptr(flag), 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -348,7 +359,7 @@ func EpollCreate1(flag int) (fd int, err error) {
 func EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error) {
 	_, _, e1 := RawSyscall6(SYS_EPOLL_CTL, uintptr(epfd), uintptr(op), uintptr(fd), uintptr(unsafe.Pointer(event)), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -365,7 +376,7 @@ func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
 	r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -388,7 +399,7 @@ func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) {
 	_, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -398,7 +409,7 @@ func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) {
 func Fallocate(fd int, mode uint32, off int64, len int64) (err error) {
 	_, _, e1 := Syscall6(SYS_FALLOCATE, uintptr(fd), uintptr(mode), uintptr(off), uintptr(off>>32), uintptr(len), uintptr(len>>32))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -408,7 +419,7 @@ func Fallocate(fd int, mode uint32, off int64, len int64) (err error) {
 func Fchdir(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -418,7 +429,7 @@ func Fchdir(fd int) (err error) {
 func Fchmod(fd int, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -434,7 +445,7 @@ func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) {
 	_, _, e1 := Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -450,7 +461,7 @@ func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) {
 	_, _, e1 := Syscall6(SYS_FCHOWNAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid), uintptr(flags), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -461,7 +472,7 @@ func fcntl(fd int, cmd int, arg int) (val int, err error) {
 	r0, _, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg))
 	val = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -471,7 +482,7 @@ func fcntl(fd int, cmd int, arg int) (val int, err error) {
 func Fdatasync(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FDATASYNC, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -481,7 +492,7 @@ func Fdatasync(fd int) (err error) {
 func Flock(fd int, how int) (err error) {
 	_, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -491,7 +502,7 @@ func Flock(fd int, how int) (err error) {
 func Fsync(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -508,7 +519,7 @@ func Getdents(fd int, buf []byte) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_GETDENTS64, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -519,13 +530,21 @@ func Getpgid(pid int) (pgid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0)
 	pgid = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
+func Getpgrp() (pid int) {
+	r0, _, _ := RawSyscall(SYS_GETPGRP, 0, 0, 0)
+	pid = int(r0)
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
 func Getpid() (pid int) {
 	r0, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0)
 	pid = int(r0)
@@ -546,7 +565,7 @@ func Getpriority(which int, who int) (prio int, err error) {
 	r0, _, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0)
 	prio = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -556,7 +575,7 @@ func Getpriority(which int, who int) (prio int, err error) {
 func Getrusage(who int, rusage *Rusage) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -593,7 +612,7 @@ func Getxattr(path string, attr string, dest []byte) (sz int, err error) {
 	use(unsafe.Pointer(_p1))
 	sz = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -610,7 +629,18 @@ func InotifyAddWatch(fd int, pathname string, mask uint32) (watchdesc int, err e
 	use(unsafe.Pointer(_p0))
 	watchdesc = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func InotifyInit() (fd int, err error) {
+	r0, _, e1 := RawSyscall(SYS_INOTIFY_INIT, 0, 0, 0)
+	fd = int(r0)
+	if e1 != 0 {
+		err = e1
 	}
 	return
 }
@@ -621,7 +651,7 @@ func InotifyInit1(flags int) (fd int, err error) {
 	r0, _, e1 := RawSyscall(SYS_INOTIFY_INIT1, uintptr(flags), 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -632,7 +662,7 @@ func InotifyRmWatch(fd int, watchdesc uint32) (success int, err error) {
 	r0, _, e1 := RawSyscall(SYS_INOTIFY_RM_WATCH, uintptr(fd), uintptr(watchdesc), 0)
 	success = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -642,7 +672,7 @@ func InotifyRmWatch(fd int, watchdesc uint32) (success int, err error) {
 func Kill(pid int, sig Signal) (err error) {
 	_, _, e1 := RawSyscall(SYS_KILL, uintptr(pid), uintptr(sig), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -659,7 +689,29 @@ func Klogctl(typ int, buf []byte) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_SYSLOG, uintptr(typ), uintptr(_p0), uintptr(len(buf)))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Link(oldpath string, newpath string) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(oldpath)
+	if err != nil {
+		return
+	}
+	var _p1 *byte
+	_p1, err = BytePtrFromString(newpath)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_LINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
+	use(unsafe.Pointer(_p0))
+	use(unsafe.Pointer(_p1))
+	if e1 != 0 {
+		err = e1
 	}
 	return
 }
@@ -682,7 +734,23 @@ func Listxattr(path string, dest []byte) (sz int, err error) {
 	use(unsafe.Pointer(_p0))
 	sz = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mkdir(path string, mode uint32) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = e1
 	}
 	return
 }
@@ -698,7 +766,23 @@ func Mkdirat(dirfd int, path string, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_MKDIRAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Mknod(path string, mode uint32, dev int) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev))
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = e1
 	}
 	return
 }
@@ -714,7 +798,7 @@ func Mknodat(dirfd int, path string, mode uint32, dev int) (err error) {
 	_, _, e1 := Syscall6(SYS_MKNODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -724,7 +808,7 @@ func Mknodat(dirfd int, path string, mode uint32, dev int) (err error) {
 func Nanosleep(time *Timespec, leftover *Timespec) (err error) {
 	_, _, e1 := Syscall(SYS_NANOSLEEP, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -734,7 +818,7 @@ func Nanosleep(time *Timespec, leftover *Timespec) (err error) {
 func Pause() (err error) {
 	_, _, e1 := Syscall(SYS_PAUSE, 0, 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -756,7 +840,7 @@ func PivotRoot(newroot string, putold string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -766,7 +850,7 @@ func PivotRoot(newroot string, putold string) (err error) {
 func prlimit(pid int, resource int, old *Rlimit, newlimit *Rlimit) (err error) {
 	_, _, e1 := RawSyscall6(SYS_PRLIMIT64, uintptr(pid), uintptr(resource), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(newlimit)), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -783,7 +867,30 @@ func read(fd int, p []byte) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Readlink(path string, buf []byte) (n int, err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	var _p1 unsafe.Pointer
+	if len(buf) > 0 {
+		_p1 = unsafe.Pointer(&buf[0])
+	} else {
+		_p1 = unsafe.Pointer(&_zero)
+	}
+	r0, _, e1 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf)))
+	use(unsafe.Pointer(_p0))
+	n = int(r0)
+	if e1 != 0 {
+		err = e1
 	}
 	return
 }
@@ -805,7 +912,29 @@ func Removexattr(path string, attr string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Rename(oldpath string, newpath string) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(oldpath)
+	if err != nil {
+		return
+	}
+	var _p1 *byte
+	_p1, err = BytePtrFromString(newpath)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_RENAME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
+	use(unsafe.Pointer(_p0))
+	use(unsafe.Pointer(_p1))
+	if e1 != 0 {
+		err = e1
 	}
 	return
 }
@@ -827,7 +956,23 @@ func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err e
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Rmdir(path string) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = e1
 	}
 	return
 }
@@ -843,7 +988,7 @@ func Setdomainname(p []byte) (err error) {
 	}
 	_, _, e1 := Syscall(SYS_SETDOMAINNAME, uintptr(_p0), uintptr(len(p)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -859,7 +1004,7 @@ func Sethostname(p []byte) (err error) {
 	}
 	_, _, e1 := Syscall(SYS_SETHOSTNAME, uintptr(_p0), uintptr(len(p)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -869,7 +1014,7 @@ func Sethostname(p []byte) (err error) {
 func Setpgid(pid int, pgid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -880,7 +1025,7 @@ func Setsid() (pid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0)
 	pid = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -890,7 +1035,7 @@ func Setsid() (pid int, err error) {
 func Settimeofday(tv *Timeval) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -900,7 +1045,7 @@ func Settimeofday(tv *Timeval) (err error) {
 func Setpriority(which int, who int, prio int) (err error) {
 	_, _, e1 := Syscall(SYS_SETPRIORITY, uintptr(which), uintptr(who), uintptr(prio))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -928,7 +1073,29 @@ func Setxattr(path string, attr string, data []byte, flags int) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Symlink(oldpath string, newpath string) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(oldpath)
+	if err != nil {
+		return
+	}
+	var _p1 *byte
+	_p1, err = BytePtrFromString(newpath)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_SYMLINK, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0)
+	use(unsafe.Pointer(_p0))
+	use(unsafe.Pointer(_p1))
+	if e1 != 0 {
+		err = e1
 	}
 	return
 }
@@ -945,7 +1112,7 @@ func Sync() {
 func Sysinfo(info *Sysinfo_t) (err error) {
 	_, _, e1 := RawSyscall(SYS_SYSINFO, uintptr(unsafe.Pointer(info)), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -956,7 +1123,7 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) {
 	r0, r1, e1 := Syscall6(SYS_TEE, uintptr(rfd), uintptr(wfd), uintptr(len), uintptr(flags), 0, 0)
 	n = int64(int64(r1)<<32 | int64(r0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -966,7 +1133,7 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) {
 func Tgkill(tgid int, tid int, sig Signal) (err error) {
 	_, _, e1 := RawSyscall(SYS_TGKILL, uintptr(tgid), uintptr(tid), uintptr(sig))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -977,7 +1144,7 @@ func Times(tms *Tms) (ticks uintptr, err error) {
 	r0, _, e1 := RawSyscall(SYS_TIMES, uintptr(unsafe.Pointer(tms)), 0, 0)
 	ticks = uintptr(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -995,7 +1162,39 @@ func Umask(mask int) (oldmask int) {
 func Uname(buf *Utsname) (err error) {
 	_, _, e1 := RawSyscall(SYS_UNAME, uintptr(unsafe.Pointer(buf)), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Unlink(path string) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(_p0)), 0, 0)
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Unlinkat(dirfd int, path string) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_UNLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), 0)
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = e1
 	}
 	return
 }
@@ -1011,7 +1210,7 @@ func Unmount(target string, flags int) (err error) {
 	_, _, e1 := Syscall(SYS_UMOUNT2, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1021,7 +1220,7 @@ func Unmount(target string, flags int) (err error) {
 func Unshare(flags int) (err error) {
 	_, _, e1 := Syscall(SYS_UNSHARE, uintptr(flags), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1031,7 +1230,7 @@ func Unshare(flags int) (err error) {
 func Ustat(dev int, ubuf *Ustat_t) (err error) {
 	_, _, e1 := Syscall(SYS_USTAT, uintptr(dev), uintptr(unsafe.Pointer(ubuf)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1047,7 +1246,7 @@ func Utime(path string, buf *Utimbuf) (err error) {
 	_, _, e1 := Syscall(SYS_UTIME, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(buf)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1064,7 +1263,7 @@ func write(fd int, p []byte) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1074,7 +1273,7 @@ func write(fd int, p []byte) (n int, err error) {
 func exitThread(code int) (err error) {
 	_, _, e1 := Syscall(SYS_EXIT, uintptr(code), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1085,7 +1284,7 @@ func readlen(fd int, p *byte, np int) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(p)), uintptr(np))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1096,7 +1295,7 @@ func writelen(fd int, p *byte, np int) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(p)), uintptr(np))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1106,7 +1305,7 @@ func writelen(fd int, p *byte, np int) (n int, err error) {
 func munmap(addr uintptr, length uintptr) (err error) {
 	_, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1122,7 +1321,7 @@ func Madvise(b []byte, advice int) (err error) {
 	}
 	_, _, e1 := Syscall(SYS_MADVISE, uintptr(_p0), uintptr(len(b)), uintptr(advice))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1138,7 +1337,7 @@ func Mprotect(b []byte, prot int) (err error) {
 	}
 	_, _, e1 := Syscall(SYS_MPROTECT, uintptr(_p0), uintptr(len(b)), uintptr(prot))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1154,7 +1353,7 @@ func Mlock(b []byte) (err error) {
 	}
 	_, _, e1 := Syscall(SYS_MLOCK, uintptr(_p0), uintptr(len(b)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1170,7 +1369,7 @@ func Munlock(b []byte) (err error) {
 	}
 	_, _, e1 := Syscall(SYS_MUNLOCK, uintptr(_p0), uintptr(len(b)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1180,7 +1379,7 @@ func Munlock(b []byte) (err error) {
 func Mlockall(flags int) (err error) {
 	_, _, e1 := Syscall(SYS_MLOCKALL, uintptr(flags), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1190,17 +1389,7 @@ func Mlockall(flags int) (err error) {
 func Munlockall() (err error) {
 	_, _, e1 := Syscall(SYS_MUNLOCKALL, 0, 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func pipe2(p *[2]_C_int, flags int) (err error) {
-	_, _, e1 := RawSyscall(SYS_PIPE2, uintptr(unsafe.Pointer(p)), uintptr(flags), 0)
-	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1211,7 +1400,7 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
 	r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	fd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1222,7 +1411,7 @@ func accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int,
 	r0, _, e1 := Syscall6(SYS_ACCEPT4, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), uintptr(flags), 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1232,7 +1421,7 @@ func accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int,
 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1242,7 +1431,7 @@ func bind(s int, addr unsafe.Pointer, 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1253,7 +1442,7 @@ func getgroups(n int, list *_Gid_t) (nn int, err error) {
 	r0, _, e1 := RawSyscall(SYS_GETGROUPS32, uintptr(n), uintptr(unsafe.Pointer(list)), 0)
 	nn = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1263,7 +1452,7 @@ func getgroups(n int, list *_Gid_t) (nn int, err error) {
 func setgroups(n int, list *_Gid_t) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETGROUPS32, uintptr(n), uintptr(unsafe.Pointer(list)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1273,7 +1462,7 @@ func setgroups(n int, list *_Gid_t) (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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1283,7 +1472,7 @@ func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen
 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1294,7 +1483,7 @@ func socket(domain int, typ int, proto int) (fd int, err error) {
 	r0, _, e1 := RawSyscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto))
 	fd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1304,7 +1493,7 @@ func socket(domain int, typ int, proto int) (fd int, err error) {
 func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETPEERNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1314,7 +1503,7 @@ func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETSOCKNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1331,7 +1520,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
 	r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1347,7 +1536,7 @@ func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (
 	}
 	_, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1357,7 +1546,7 @@ func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (
 func socketpair(domain int, typ int, flags int, fd *[2]int32) (err error) {
 	_, _, e1 := RawSyscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(flags), uintptr(unsafe.Pointer(fd)), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1368,7 +1557,7 @@ func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1379,17 +1568,23 @@ 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func Dup2(oldfd int, newfd int) (err error) {
-	_, _, e1 := Syscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0)
+func Chown(path string, uid int, gid int) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_CHOWN32, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
+	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1399,7 +1594,7 @@ func Dup2(oldfd int, newfd int) (err error) {
 func Fchown(fd int, uid int, gid int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHOWN32, uintptr(fd), uintptr(uid), uintptr(gid))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1409,7 +1604,7 @@ func Fchown(fd int, uid int, gid int) (err error) {
 func Fstat(fd int, stat *Stat_t) (err error) {
 	_, _, e1 := Syscall(SYS_FSTAT64, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1448,17 +1643,6 @@ func Getuid() (uid int) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func InotifyInit() (fd int, err error) {
-	r0, _, e1 := RawSyscall(SYS_INOTIFY_INIT, 0, 0, 0)
-	fd = int(r0)
-	if e1 != 0 {
-		err = errnoErr(e1)
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
 func Lchown(path string, uid int, gid int) (err error) {
 	var _p0 *byte
 	_p0, err = BytePtrFromString(path)
@@ -1468,7 +1652,7 @@ func Lchown(path string, uid int, gid int) (err error) {
 	_, _, e1 := Syscall(SYS_LCHOWN32, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1478,7 +1662,7 @@ func Lchown(path string, uid int, gid int) (err error) {
 func Listen(s int, n int) (err error) {
 	_, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(n), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1494,7 +1678,7 @@ func Lstat(path string, stat *Stat_t) (err error) {
 	_, _, e1 := Syscall(SYS_LSTAT64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1505,7 +1689,7 @@ func sendfile(outfd int, infd int, offset *int64, count int) (written int, err e
 	r0, _, e1 := Syscall6(SYS_SENDFILE64, uintptr(outfd), uintptr(infd), uintptr(unsafe.Pointer(offset)), uintptr(count), 0, 0)
 	written = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1516,7 +1700,7 @@ func Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err
 	r0, _, e1 := Syscall6(SYS__NEWSELECT, uintptr(nfd), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1526,7 +1710,7 @@ func Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err
 func Setfsgid(gid int) (err error) {
 	_, _, e1 := Syscall(SYS_SETFSGID32, uintptr(gid), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1536,7 +1720,7 @@ func Setfsgid(gid int) (err error) {
 func Setfsuid(uid int) (err error) {
 	_, _, e1 := Syscall(SYS_SETFSUID32, uintptr(uid), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1546,7 +1730,7 @@ func Setfsuid(uid int) (err error) {
 func Setregid(rgid int, egid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETREGID32, uintptr(rgid), uintptr(egid), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1556,7 +1740,7 @@ func Setregid(rgid int, egid int) (err error) {
 func Setresgid(rgid int, egid int, sgid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETRESGID32, uintptr(rgid), uintptr(egid), uintptr(sgid))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1566,7 +1750,7 @@ func Setresgid(rgid int, egid int, sgid int) (err error) {
 func Setresuid(ruid int, euid int, suid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETRESUID32, uintptr(ruid), uintptr(euid), uintptr(suid))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1576,7 +1760,7 @@ func Setresuid(ruid int, euid int, suid int) (err error) {
 func Setreuid(ruid int, euid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETREUID32, uintptr(ruid), uintptr(euid), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1586,7 +1770,7 @@ func Setreuid(ruid int, euid int) (err error) {
 func Shutdown(fd int, how int) (err error) {
 	_, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(fd), uintptr(how), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1597,7 +1781,7 @@ func Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n i
 	r0, _, e1 := Syscall6(SYS_SPLICE, uintptr(rfd), uintptr(unsafe.Pointer(roff)), uintptr(wfd), uintptr(unsafe.Pointer(woff)), uintptr(len), uintptr(flags))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1613,7 +1797,7 @@ func Stat(path string, stat *Stat_t) (err error) {
 	_, _, e1 := Syscall(SYS_STAT64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1623,7 +1807,7 @@ func Stat(path string, stat *Stat_t) (err error) {
 func Gettimeofday(tv *Timeval) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1634,7 +1818,7 @@ func Time(t *Time_t) (tt Time_t, err error) {
 	r0, _, e1 := RawSyscall(SYS_TIME, uintptr(unsafe.Pointer(t)), 0, 0)
 	tt = Time_t(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1651,7 +1835,7 @@ func Pread(fd int, p []byte, offset int64) (n int, err error) {
 	r0, _, e1 := Syscall6(SYS_PREAD64, uintptr(fd), uintptr(_p0), uintptr(len(p)), 0, uintptr(offset), uintptr(offset>>32))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1668,7 +1852,7 @@ func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
 	r0, _, e1 := Syscall6(SYS_PWRITE64, uintptr(fd), uintptr(_p0), uintptr(len(p)), 0, uintptr(offset), uintptr(offset>>32))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1684,7 +1868,7 @@ func Truncate(path string, length int64) (err error) {
 	_, _, e1 := Syscall6(SYS_TRUNCATE64, uintptr(unsafe.Pointer(_p0)), 0, uintptr(length), uintptr(length>>32), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1694,7 +1878,7 @@ func Truncate(path string, length int64) (err error) {
 func Ftruncate(fd int, length int64) (err error) {
 	_, _, e1 := Syscall6(SYS_FTRUNCATE64, uintptr(fd), 0, uintptr(length), uintptr(length>>32), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1705,7 +1889,7 @@ func mmap2(addr uintptr, length uintptr, prot int, flags int, fd int, pageOffset
 	r0, _, e1 := Syscall6(SYS_MMAP2, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flags), uintptr(fd), uintptr(pageOffset))
 	xaddr = uintptr(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1715,7 +1899,7 @@ func mmap2(addr uintptr, length uintptr, prot int, flags int, fd int, pageOffset
 func getrlimit(resource int, rlim *rlimit32) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1725,7 +1909,7 @@ func getrlimit(resource int, rlim *rlimit32) (err error) {
 func setrlimit(resource int, rlim *rlimit32) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(resource), uintptr(unsafe.Pointer(rlim)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
diff --git a/src/syscall/zsyscall_nacl_386.go b/src/syscall/zsyscall_nacl_386.go
index bf3f9e3..32eed33 100644
--- a/src/syscall/zsyscall_nacl_386.go
+++ b/src/syscall/zsyscall_nacl_386.go
@@ -1,8 +1,6 @@
 // mksyscall.pl -l32 -nacl syscall_nacl.go syscall_nacl_386.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
-// +build 386,nacl
-
 package syscall
 
 import "unsafe"
@@ -12,7 +10,7 @@ import "unsafe"
 func naclClose(fd int) (err error) {
 	_, _, e1 := Syscall(sys_close, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -22,7 +20,7 @@ func naclClose(fd int) (err error) {
 func Exit(code int) (err error) {
 	_, _, e1 := Syscall(sys_exit, uintptr(code), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -32,7 +30,7 @@ func Exit(code int) (err error) {
 func naclFstat(fd int, stat *Stat_t) (err error) {
 	_, _, e1 := Syscall(sys_fstat, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -49,7 +47,7 @@ func naclRead(fd int, b []byte) (n int, err error) {
 	r0, _, e1 := Syscall(sys_read, uintptr(fd), uintptr(_p0), uintptr(len(b)))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -59,23 +57,7 @@ func naclRead(fd int, b []byte) (n int, err error) {
 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 = errnoErr(e1)
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func naclGetRandomBytes(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_get_random_bytes, uintptr(_p0), uintptr(len(b)), 0)
-	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
diff --git a/src/syscall/zsyscall_nacl_amd64p32.go b/src/syscall/zsyscall_nacl_amd64p32.go
index 3f08da6..8bc81fa 100644
--- a/src/syscall/zsyscall_nacl_amd64p32.go
+++ b/src/syscall/zsyscall_nacl_amd64p32.go
@@ -1,8 +1,6 @@
 // mksyscall.pl -nacl syscall_nacl.go syscall_nacl_amd64p32.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
-// +build amd64p32,nacl
-
 package syscall
 
 import "unsafe"
@@ -12,7 +10,7 @@ import "unsafe"
 func naclClose(fd int) (err error) {
 	_, _, e1 := Syscall(sys_close, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -22,7 +20,7 @@ func naclClose(fd int) (err error) {
 func Exit(code int) (err error) {
 	_, _, e1 := Syscall(sys_exit, uintptr(code), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -32,7 +30,7 @@ func Exit(code int) (err error) {
 func naclFstat(fd int, stat *Stat_t) (err error) {
 	_, _, e1 := Syscall(sys_fstat, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -49,7 +47,7 @@ func naclRead(fd int, b []byte) (n int, err error) {
 	r0, _, e1 := Syscall(sys_read, uintptr(fd), uintptr(_p0), uintptr(len(b)))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -59,23 +57,7 @@ func naclRead(fd int, b []byte) (n int, err error) {
 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 = errnoErr(e1)
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func naclGetRandomBytes(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_get_random_bytes, uintptr(_p0), uintptr(len(b)), 0)
-	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
diff --git a/src/syscall/zsyscall_nacl_arm.go b/src/syscall/zsyscall_nacl_arm.go
index 77d46c3..adbaed0 100644
--- a/src/syscall/zsyscall_nacl_arm.go
+++ b/src/syscall/zsyscall_nacl_arm.go
@@ -1,8 +1,6 @@
 // mksyscall.pl -l32 -nacl -arm syscall_nacl.go syscall_nacl_arm.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
-// +build arm,nacl
-
 package syscall
 
 import "unsafe"
@@ -12,7 +10,7 @@ import "unsafe"
 func naclClose(fd int) (err error) {
 	_, _, e1 := Syscall(sys_close, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -22,7 +20,7 @@ func naclClose(fd int) (err error) {
 func Exit(code int) (err error) {
 	_, _, e1 := Syscall(sys_exit, uintptr(code), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -32,7 +30,7 @@ func Exit(code int) (err error) {
 func naclFstat(fd int, stat *Stat_t) (err error) {
 	_, _, e1 := Syscall(sys_fstat, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -49,7 +47,7 @@ func naclRead(fd int, b []byte) (n int, err error) {
 	r0, _, e1 := Syscall(sys_read, uintptr(fd), uintptr(_p0), uintptr(len(b)))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -59,23 +57,7 @@ func naclRead(fd int, b []byte) (n int, err error) {
 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 = errnoErr(e1)
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func naclGetRandomBytes(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_get_random_bytes, uintptr(_p0), uintptr(len(b)), 0)
-	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
diff --git a/src/syscall/zsyscall_netbsd_386.go b/src/syscall/zsyscall_netbsd_386.go
index e24c3b7..e9bd3d0 100644
--- a/src/syscall/zsyscall_netbsd_386.go
+++ b/src/syscall/zsyscall_netbsd_386.go
@@ -1,8 +1,6 @@
 // mksyscall.pl -l32 -netbsd syscall_bsd.go syscall_netbsd.go syscall_netbsd_386.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
-// +build 386,netbsd
-
 package syscall
 
 import "unsafe"
@@ -13,7 +11,7 @@ func getgroups(ngid int, gid *_Gid_t) (n int, err error) {
 	r0, _, e1 := RawSyscall(SYS_GETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -23,7 +21,7 @@ func getgroups(ngid int, gid *_Gid_t) (n int, err error) {
 func setgroups(ngid int, gid *_Gid_t) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -34,7 +32,7 @@ func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err
 	r0, _, e1 := Syscall6(SYS_WAIT4, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0)
 	wpid = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -45,7 +43,7 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
 	r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	fd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -55,7 +53,7 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -65,7 +63,7 @@ func bind(s int, addr unsafe.Pointer, 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -76,7 +74,7 @@ func socket(domain int, typ int, proto int) (fd int, err error) {
 	r0, _, e1 := RawSyscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto))
 	fd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -86,7 +84,7 @@ func socket(domain int, typ int, proto int) (fd int, 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -96,7 +94,7 @@ func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen
 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -106,7 +104,7 @@ func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr)
 func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETPEERNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -116,7 +114,7 @@ func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETSOCKNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -126,7 +124,7 @@ func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 func Shutdown(s int, how int) (err error) {
 	_, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(s), uintptr(how), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -136,7 +134,7 @@ func Shutdown(s int, how int) (err error) {
 func socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) {
 	_, _, e1 := RawSyscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -153,7 +151,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
 	r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -169,7 +167,7 @@ func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (
 	}
 	_, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -180,7 +178,7 @@ func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -191,7 +189,7 @@ 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -202,7 +200,7 @@ func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, ne
 	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 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -218,7 +216,7 @@ func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr)
 	}
 	_, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -234,7 +232,7 @@ func utimes(path string, timeval *[2]Timeval) (err error) {
 	_, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -244,7 +242,7 @@ func utimes(path string, timeval *[2]Timeval) (err error) {
 func futimes(fd int, timeval *[2]Timeval) (err error) {
 	_, _, e1 := Syscall(SYS_FUTIMES, uintptr(fd), uintptr(unsafe.Pointer(timeval)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -255,7 +253,7 @@ func fcntl(fd int, cmd int, arg int) (val int, err error) {
 	r0, _, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg))
 	val = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -267,7 +265,7 @@ func pipe() (fd1 int, fd2 int, err error) {
 	fd1 = int(r0)
 	fd2 = int(r1)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -284,7 +282,7 @@ func getdents(fd int, buf []byte) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_GETDENTS, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -300,7 +298,7 @@ func Access(path string, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -310,7 +308,7 @@ func Access(path string, mode uint32) (err error) {
 func Adjtime(delta *Timeval, olddelta *Timeval) (err error) {
 	_, _, e1 := Syscall(SYS_ADJTIME, uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -326,7 +324,7 @@ func Chdir(path string) (err error) {
 	_, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -342,7 +340,7 @@ func Chflags(path string, flags int) (err error) {
 	_, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -358,7 +356,7 @@ func Chmod(path string, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -374,7 +372,7 @@ func Chown(path string, uid int, gid int) (err error) {
 	_, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -390,7 +388,7 @@ func Chroot(path string) (err error) {
 	_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -400,7 +398,7 @@ func Chroot(path string) (err error) {
 func Close(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -408,10 +406,10 @@ func Close(fd int) (err error) {
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
 func Dup(fd int) (nfd int, err error) {
-	r0, _, e1 := Syscall(SYS_DUP, uintptr(fd), 0, 0)
+	r0, _, e1 := RawSyscall(SYS_DUP, uintptr(fd), 0, 0)
 	nfd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -419,9 +417,9 @@ func Dup(fd int) (nfd int, err error) {
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
 func Dup2(from int, to int) (err error) {
-	_, _, e1 := Syscall(SYS_DUP2, uintptr(from), uintptr(to), 0)
+	_, _, e1 := RawSyscall(SYS_DUP2, uintptr(from), uintptr(to), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -438,7 +436,7 @@ func Exit(code int) {
 func Fchdir(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -448,7 +446,7 @@ func Fchdir(fd int) (err error) {
 func Fchflags(fd int, flags int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(fd), uintptr(flags), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -458,7 +456,7 @@ func Fchflags(fd int, flags int) (err error) {
 func Fchmod(fd int, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -468,7 +466,7 @@ func Fchmod(fd int, mode uint32) (err error) {
 func Fchown(fd int, uid int, gid int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -478,7 +476,7 @@ func Fchown(fd int, uid int, gid int) (err error) {
 func Flock(fd int, how int) (err error) {
 	_, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -489,7 +487,7 @@ func Fpathconf(fd int, name int) (val int, err error) {
 	r0, _, e1 := Syscall(SYS_FPATHCONF, uintptr(fd), uintptr(name), 0)
 	val = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -499,7 +497,7 @@ func Fpathconf(fd int, name int) (val int, err error) {
 func Fstat(fd int, stat *Stat_t) (err error) {
 	_, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -509,7 +507,7 @@ func Fstat(fd int, stat *Stat_t) (err error) {
 func Fsync(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -519,7 +517,7 @@ func Fsync(fd int) (err error) {
 func Ftruncate(fd int, length int64) (err error) {
 	_, _, e1 := Syscall6(SYS_FTRUNCATE, uintptr(fd), 0, uintptr(length), uintptr(length>>32), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -554,7 +552,7 @@ func Getpgid(pid int) (pgid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0)
 	pgid = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -589,7 +587,7 @@ func Getpriority(which int, who int) (prio int, err error) {
 	r0, _, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0)
 	prio = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -599,7 +597,7 @@ func Getpriority(which int, who int) (prio int, err error) {
 func Getrlimit(which int, lim *Rlimit) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -609,7 +607,7 @@ func Getrlimit(which int, lim *Rlimit) (err error) {
 func Getrusage(who int, rusage *Rusage) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -620,7 +618,7 @@ func Getsid(pid int) (sid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0)
 	sid = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -630,7 +628,7 @@ func Getsid(pid int) (sid int, err error) {
 func Gettimeofday(tv *Timeval) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -656,7 +654,7 @@ func Issetugid() (tainted bool) {
 func Kill(pid int, signum Signal) (err error) {
 	_, _, e1 := Syscall(SYS_KILL, uintptr(pid), uintptr(signum), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -667,7 +665,7 @@ func Kqueue() (fd int, err error) {
 	r0, _, e1 := Syscall(SYS_KQUEUE, 0, 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -683,7 +681,7 @@ func Lchown(path string, uid int, gid int) (err error) {
 	_, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -705,7 +703,7 @@ func Link(path string, link string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -715,7 +713,7 @@ func Link(path string, link string) (err error) {
 func Listen(s int, backlog int) (err error) {
 	_, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(backlog), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -731,7 +729,7 @@ func Lstat(path string, stat *Stat_t) (err error) {
 	_, _, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -747,7 +745,7 @@ func Mkdir(path string, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -763,7 +761,7 @@ func Mkfifo(path string, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -779,7 +777,7 @@ func Mknod(path string, mode uint32, dev int) (err error) {
 	_, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -789,7 +787,7 @@ func Mknod(path string, mode uint32, dev int) (err error) {
 func Nanosleep(time *Timespec, leftover *Timespec) (err error) {
 	_, _, e1 := Syscall(SYS_NANOSLEEP, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -806,7 +804,7 @@ func Open(path string, mode int, perm uint32) (fd int, err error) {
 	use(unsafe.Pointer(_p0))
 	fd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -823,7 +821,7 @@ func Pathconf(path string, name int) (val int, err error) {
 	use(unsafe.Pointer(_p0))
 	val = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -840,7 +838,7 @@ func Pread(fd int, p []byte, offset int64) (n int, err error) {
 	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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -857,7 +855,7 @@ func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
 	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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -874,7 +872,7 @@ func read(fd int, p []byte) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -897,7 +895,7 @@ func Readlink(path string, buf []byte) (n int, err error) {
 	use(unsafe.Pointer(_p0))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -919,7 +917,7 @@ func Rename(from string, to string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -935,7 +933,7 @@ func Revoke(path string) (err error) {
 	_, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -951,7 +949,7 @@ func Rmdir(path string) (err error) {
 	_, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -962,7 +960,7 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
 	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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -972,7 +970,7 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
 func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error) {
 	_, _, e1 := Syscall6(SYS_SELECT, uintptr(n), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -982,7 +980,7 @@ func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error) {
 func Setegid(egid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETEGID, uintptr(egid), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -992,7 +990,7 @@ func Setegid(egid int) (err error) {
 func Seteuid(euid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETEUID, uintptr(euid), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1002,7 +1000,7 @@ func Seteuid(euid int) (err error) {
 func Setgid(gid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETGID, uintptr(gid), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1012,7 +1010,7 @@ func Setgid(gid int) (err error) {
 func Setpgid(pid int, pgid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1022,7 +1020,7 @@ func Setpgid(pid int, pgid int) (err error) {
 func Setpriority(which int, who int, prio int) (err error) {
 	_, _, e1 := Syscall(SYS_SETPRIORITY, uintptr(which), uintptr(who), uintptr(prio))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1032,7 +1030,7 @@ func Setpriority(which int, who int, prio int) (err error) {
 func Setregid(rgid int, egid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1042,7 +1040,7 @@ func Setregid(rgid int, egid int) (err error) {
 func Setreuid(ruid int, euid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1052,7 +1050,7 @@ func Setreuid(ruid int, euid int) (err error) {
 func Setrlimit(which int, lim *Rlimit) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1063,7 +1061,7 @@ func Setsid() (pid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0)
 	pid = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1073,7 +1071,7 @@ func Setsid() (pid int, err error) {
 func Settimeofday(tp *Timeval) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1083,7 +1081,7 @@ func Settimeofday(tp *Timeval) (err error) {
 func Setuid(uid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETUID, uintptr(uid), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1099,7 +1097,7 @@ func Stat(path string, stat *Stat_t) (err error) {
 	_, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1121,7 +1119,7 @@ func Symlink(path string, link string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1131,7 +1129,7 @@ func Symlink(path string, link string) (err error) {
 func Sync() (err error) {
 	_, _, e1 := Syscall(SYS_SYNC, 0, 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1147,7 +1145,7 @@ func Truncate(path string, length int64) (err error) {
 	_, _, e1 := Syscall6(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), 0, uintptr(length), uintptr(length>>32), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1171,7 +1169,7 @@ func Unlink(path string) (err error) {
 	_, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1187,7 +1185,7 @@ func Unmount(path string, flags int) (err error) {
 	_, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1204,7 +1202,7 @@ func write(fd int, p []byte) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1215,7 +1213,7 @@ func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (
 	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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1225,7 +1223,7 @@ func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (
 func munmap(addr uintptr, length uintptr) (err error) {
 	_, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1236,7 +1234,7 @@ 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1247,7 +1245,7 @@ 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
diff --git a/src/syscall/zsyscall_netbsd_amd64.go b/src/syscall/zsyscall_netbsd_amd64.go
index 7aa75ab..1acd7c2 100644
--- a/src/syscall/zsyscall_netbsd_amd64.go
+++ b/src/syscall/zsyscall_netbsd_amd64.go
@@ -1,8 +1,6 @@
 // mksyscall.pl -netbsd syscall_bsd.go syscall_netbsd.go syscall_netbsd_amd64.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
-// +build amd64,netbsd
-
 package syscall
 
 import "unsafe"
@@ -13,7 +11,7 @@ func getgroups(ngid int, gid *_Gid_t) (n int, err error) {
 	r0, _, e1 := RawSyscall(SYS_GETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -23,7 +21,7 @@ func getgroups(ngid int, gid *_Gid_t) (n int, err error) {
 func setgroups(ngid int, gid *_Gid_t) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -34,7 +32,7 @@ func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err
 	r0, _, e1 := Syscall6(SYS_WAIT4, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0)
 	wpid = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -45,7 +43,7 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
 	r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	fd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -55,7 +53,7 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -65,7 +63,7 @@ func bind(s int, addr unsafe.Pointer, 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -76,7 +74,7 @@ func socket(domain int, typ int, proto int) (fd int, err error) {
 	r0, _, e1 := RawSyscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto))
 	fd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -86,7 +84,7 @@ func socket(domain int, typ int, proto int) (fd int, 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -96,7 +94,7 @@ func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen
 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -106,7 +104,7 @@ func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr)
 func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETPEERNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -116,7 +114,7 @@ func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETSOCKNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -126,7 +124,7 @@ func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 func Shutdown(s int, how int) (err error) {
 	_, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(s), uintptr(how), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -136,7 +134,7 @@ func Shutdown(s int, how int) (err error) {
 func socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) {
 	_, _, e1 := RawSyscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -153,7 +151,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
 	r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -169,7 +167,7 @@ func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (
 	}
 	_, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -180,7 +178,7 @@ func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -191,7 +189,7 @@ 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -202,7 +200,7 @@ func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, ne
 	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 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -218,7 +216,7 @@ func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr)
 	}
 	_, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -234,7 +232,7 @@ func utimes(path string, timeval *[2]Timeval) (err error) {
 	_, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -244,7 +242,7 @@ func utimes(path string, timeval *[2]Timeval) (err error) {
 func futimes(fd int, timeval *[2]Timeval) (err error) {
 	_, _, e1 := Syscall(SYS_FUTIMES, uintptr(fd), uintptr(unsafe.Pointer(timeval)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -255,7 +253,7 @@ func fcntl(fd int, cmd int, arg int) (val int, err error) {
 	r0, _, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg))
 	val = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -267,7 +265,7 @@ func pipe() (fd1 int, fd2 int, err error) {
 	fd1 = int(r0)
 	fd2 = int(r1)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -284,7 +282,7 @@ func getdents(fd int, buf []byte) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_GETDENTS, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -300,7 +298,7 @@ func Access(path string, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -310,7 +308,7 @@ func Access(path string, mode uint32) (err error) {
 func Adjtime(delta *Timeval, olddelta *Timeval) (err error) {
 	_, _, e1 := Syscall(SYS_ADJTIME, uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -326,7 +324,7 @@ func Chdir(path string) (err error) {
 	_, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -342,7 +340,7 @@ func Chflags(path string, flags int) (err error) {
 	_, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -358,7 +356,7 @@ func Chmod(path string, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -374,7 +372,7 @@ func Chown(path string, uid int, gid int) (err error) {
 	_, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -390,7 +388,7 @@ func Chroot(path string) (err error) {
 	_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -400,7 +398,7 @@ func Chroot(path string) (err error) {
 func Close(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -408,10 +406,10 @@ func Close(fd int) (err error) {
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
 func Dup(fd int) (nfd int, err error) {
-	r0, _, e1 := Syscall(SYS_DUP, uintptr(fd), 0, 0)
+	r0, _, e1 := RawSyscall(SYS_DUP, uintptr(fd), 0, 0)
 	nfd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -419,9 +417,9 @@ func Dup(fd int) (nfd int, err error) {
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
 func Dup2(from int, to int) (err error) {
-	_, _, e1 := Syscall(SYS_DUP2, uintptr(from), uintptr(to), 0)
+	_, _, e1 := RawSyscall(SYS_DUP2, uintptr(from), uintptr(to), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -438,7 +436,7 @@ func Exit(code int) {
 func Fchdir(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -448,7 +446,7 @@ func Fchdir(fd int) (err error) {
 func Fchflags(fd int, flags int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(fd), uintptr(flags), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -458,7 +456,7 @@ func Fchflags(fd int, flags int) (err error) {
 func Fchmod(fd int, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -468,7 +466,7 @@ func Fchmod(fd int, mode uint32) (err error) {
 func Fchown(fd int, uid int, gid int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -478,7 +476,7 @@ func Fchown(fd int, uid int, gid int) (err error) {
 func Flock(fd int, how int) (err error) {
 	_, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -489,7 +487,7 @@ func Fpathconf(fd int, name int) (val int, err error) {
 	r0, _, e1 := Syscall(SYS_FPATHCONF, uintptr(fd), uintptr(name), 0)
 	val = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -499,7 +497,7 @@ func Fpathconf(fd int, name int) (val int, err error) {
 func Fstat(fd int, stat *Stat_t) (err error) {
 	_, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -509,7 +507,7 @@ func Fstat(fd int, stat *Stat_t) (err error) {
 func Fsync(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -519,7 +517,7 @@ func Fsync(fd int) (err error) {
 func Ftruncate(fd int, length int64) (err error) {
 	_, _, e1 := Syscall(SYS_FTRUNCATE, uintptr(fd), 0, uintptr(length))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -554,7 +552,7 @@ func Getpgid(pid int) (pgid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0)
 	pgid = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -589,7 +587,7 @@ func Getpriority(which int, who int) (prio int, err error) {
 	r0, _, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0)
 	prio = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -599,7 +597,7 @@ func Getpriority(which int, who int) (prio int, err error) {
 func Getrlimit(which int, lim *Rlimit) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -609,7 +607,7 @@ func Getrlimit(which int, lim *Rlimit) (err error) {
 func Getrusage(who int, rusage *Rusage) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -620,7 +618,7 @@ func Getsid(pid int) (sid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0)
 	sid = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -630,7 +628,7 @@ func Getsid(pid int) (sid int, err error) {
 func Gettimeofday(tv *Timeval) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -656,7 +654,7 @@ func Issetugid() (tainted bool) {
 func Kill(pid int, signum Signal) (err error) {
 	_, _, e1 := Syscall(SYS_KILL, uintptr(pid), uintptr(signum), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -667,7 +665,7 @@ func Kqueue() (fd int, err error) {
 	r0, _, e1 := Syscall(SYS_KQUEUE, 0, 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -683,7 +681,7 @@ func Lchown(path string, uid int, gid int) (err error) {
 	_, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -705,7 +703,7 @@ func Link(path string, link string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -715,7 +713,7 @@ func Link(path string, link string) (err error) {
 func Listen(s int, backlog int) (err error) {
 	_, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(backlog), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -731,7 +729,7 @@ func Lstat(path string, stat *Stat_t) (err error) {
 	_, _, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -747,7 +745,7 @@ func Mkdir(path string, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -763,7 +761,7 @@ func Mkfifo(path string, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -779,7 +777,7 @@ func Mknod(path string, mode uint32, dev int) (err error) {
 	_, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -789,7 +787,7 @@ func Mknod(path string, mode uint32, dev int) (err error) {
 func Nanosleep(time *Timespec, leftover *Timespec) (err error) {
 	_, _, e1 := Syscall(SYS_NANOSLEEP, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -806,7 +804,7 @@ func Open(path string, mode int, perm uint32) (fd int, err error) {
 	use(unsafe.Pointer(_p0))
 	fd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -823,7 +821,7 @@ func Pathconf(path string, name int) (val int, err error) {
 	use(unsafe.Pointer(_p0))
 	val = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -840,7 +838,7 @@ func Pread(fd int, p []byte, offset int64) (n int, err error) {
 	r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), 0, uintptr(offset), 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -857,7 +855,7 @@ func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
 	r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), 0, uintptr(offset), 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -874,7 +872,7 @@ func read(fd int, p []byte) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -897,7 +895,7 @@ func Readlink(path string, buf []byte) (n int, err error) {
 	use(unsafe.Pointer(_p0))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -919,7 +917,7 @@ func Rename(from string, to string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -935,7 +933,7 @@ func Revoke(path string) (err error) {
 	_, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -951,7 +949,7 @@ func Rmdir(path string) (err error) {
 	_, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -962,7 +960,7 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
 	r0, _, e1 := Syscall6(SYS_LSEEK, uintptr(fd), 0, uintptr(offset), uintptr(whence), 0, 0)
 	newoffset = int64(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -972,7 +970,7 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
 func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error) {
 	_, _, e1 := Syscall6(SYS_SELECT, uintptr(n), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -982,7 +980,7 @@ func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error) {
 func Setegid(egid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETEGID, uintptr(egid), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -992,7 +990,7 @@ func Setegid(egid int) (err error) {
 func Seteuid(euid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETEUID, uintptr(euid), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1002,7 +1000,7 @@ func Seteuid(euid int) (err error) {
 func Setgid(gid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETGID, uintptr(gid), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1012,7 +1010,7 @@ func Setgid(gid int) (err error) {
 func Setpgid(pid int, pgid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1022,7 +1020,7 @@ func Setpgid(pid int, pgid int) (err error) {
 func Setpriority(which int, who int, prio int) (err error) {
 	_, _, e1 := Syscall(SYS_SETPRIORITY, uintptr(which), uintptr(who), uintptr(prio))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1032,7 +1030,7 @@ func Setpriority(which int, who int, prio int) (err error) {
 func Setregid(rgid int, egid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1042,7 +1040,7 @@ func Setregid(rgid int, egid int) (err error) {
 func Setreuid(ruid int, euid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1052,7 +1050,7 @@ func Setreuid(ruid int, euid int) (err error) {
 func Setrlimit(which int, lim *Rlimit) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1063,7 +1061,7 @@ func Setsid() (pid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0)
 	pid = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1073,7 +1071,7 @@ func Setsid() (pid int, err error) {
 func Settimeofday(tp *Timeval) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1083,7 +1081,7 @@ func Settimeofday(tp *Timeval) (err error) {
 func Setuid(uid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETUID, uintptr(uid), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1099,7 +1097,7 @@ func Stat(path string, stat *Stat_t) (err error) {
 	_, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1121,7 +1119,7 @@ func Symlink(path string, link string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1131,7 +1129,7 @@ func Symlink(path string, link string) (err error) {
 func Sync() (err error) {
 	_, _, e1 := Syscall(SYS_SYNC, 0, 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1147,7 +1145,7 @@ func Truncate(path string, length int64) (err error) {
 	_, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), 0, uintptr(length))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1171,7 +1169,7 @@ func Unlink(path string) (err error) {
 	_, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1187,7 +1185,7 @@ func Unmount(path string, flags int) (err error) {
 	_, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1204,7 +1202,7 @@ func write(fd int, p []byte) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1215,7 +1213,7 @@ func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (
 	r0, _, e1 := Syscall9(SYS_MMAP, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flag), uintptr(fd), 0, uintptr(pos), 0, 0)
 	ret = uintptr(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1225,7 +1223,7 @@ func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (
 func munmap(addr uintptr, length uintptr) (err error) {
 	_, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1236,7 +1234,7 @@ 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1247,7 +1245,7 @@ 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
diff --git a/src/syscall/zsyscall_netbsd_arm.go b/src/syscall/zsyscall_netbsd_arm.go
index 21f482b..898e0ce 100644
--- a/src/syscall/zsyscall_netbsd_arm.go
+++ b/src/syscall/zsyscall_netbsd_arm.go
@@ -1,8 +1,6 @@
 // mksyscall.pl -l32 -arm syscall_bsd.go syscall_netbsd.go syscall_netbsd_arm.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
-// +build arm,netbsd
-
 package syscall
 
 import "unsafe"
@@ -13,7 +11,7 @@ func getgroups(ngid int, gid *_Gid_t) (n int, err error) {
 	r0, _, e1 := RawSyscall(SYS_GETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -23,7 +21,7 @@ func getgroups(ngid int, gid *_Gid_t) (n int, err error) {
 func setgroups(ngid int, gid *_Gid_t) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -34,7 +32,7 @@ func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err
 	r0, _, e1 := Syscall6(SYS_WAIT4, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0)
 	wpid = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -45,7 +43,7 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
 	r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	fd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -55,7 +53,7 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -65,7 +63,7 @@ func bind(s int, addr unsafe.Pointer, 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -76,7 +74,7 @@ func socket(domain int, typ int, proto int) (fd int, err error) {
 	r0, _, e1 := RawSyscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto))
 	fd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -86,7 +84,7 @@ func socket(domain int, typ int, proto int) (fd int, 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -96,7 +94,7 @@ func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen
 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -106,7 +104,7 @@ func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr)
 func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETPEERNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -116,7 +114,7 @@ func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETSOCKNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -126,7 +124,7 @@ func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 func Shutdown(s int, how int) (err error) {
 	_, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(s), uintptr(how), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -136,7 +134,7 @@ func Shutdown(s int, how int) (err error) {
 func socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) {
 	_, _, e1 := RawSyscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -153,7 +151,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
 	r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -169,7 +167,7 @@ func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (
 	}
 	_, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -180,7 +178,7 @@ func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -191,7 +189,7 @@ 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -202,7 +200,7 @@ func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, ne
 	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 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -218,7 +216,7 @@ func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr)
 	}
 	_, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -234,7 +232,7 @@ func utimes(path string, timeval *[2]Timeval) (err error) {
 	_, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -244,7 +242,7 @@ func utimes(path string, timeval *[2]Timeval) (err error) {
 func futimes(fd int, timeval *[2]Timeval) (err error) {
 	_, _, e1 := Syscall(SYS_FUTIMES, uintptr(fd), uintptr(unsafe.Pointer(timeval)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -255,7 +253,7 @@ func fcntl(fd int, cmd int, arg int) (val int, err error) {
 	r0, _, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg))
 	val = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -267,7 +265,7 @@ func pipe() (fd1 int, fd2 int, err error) {
 	fd1 = int(r0)
 	fd2 = int(r1)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -284,7 +282,7 @@ func getdents(fd int, buf []byte) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_GETDENTS, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -300,7 +298,7 @@ func Access(path string, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -310,7 +308,7 @@ func Access(path string, mode uint32) (err error) {
 func Adjtime(delta *Timeval, olddelta *Timeval) (err error) {
 	_, _, e1 := Syscall(SYS_ADJTIME, uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -326,7 +324,7 @@ func Chdir(path string) (err error) {
 	_, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -342,7 +340,7 @@ func Chflags(path string, flags int) (err error) {
 	_, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -358,7 +356,7 @@ func Chmod(path string, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -374,7 +372,7 @@ func Chown(path string, uid int, gid int) (err error) {
 	_, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -390,7 +388,7 @@ func Chroot(path string) (err error) {
 	_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -400,7 +398,7 @@ func Chroot(path string) (err error) {
 func Close(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -408,10 +406,10 @@ func Close(fd int) (err error) {
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
 func Dup(fd int) (nfd int, err error) {
-	r0, _, e1 := Syscall(SYS_DUP, uintptr(fd), 0, 0)
+	r0, _, e1 := RawSyscall(SYS_DUP, uintptr(fd), 0, 0)
 	nfd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -419,9 +417,9 @@ func Dup(fd int) (nfd int, err error) {
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
 func Dup2(from int, to int) (err error) {
-	_, _, e1 := Syscall(SYS_DUP2, uintptr(from), uintptr(to), 0)
+	_, _, e1 := RawSyscall(SYS_DUP2, uintptr(from), uintptr(to), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -438,7 +436,7 @@ func Exit(code int) {
 func Fchdir(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -448,7 +446,7 @@ func Fchdir(fd int) (err error) {
 func Fchflags(fd int, flags int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(fd), uintptr(flags), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -458,7 +456,7 @@ func Fchflags(fd int, flags int) (err error) {
 func Fchmod(fd int, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -468,7 +466,7 @@ func Fchmod(fd int, mode uint32) (err error) {
 func Fchown(fd int, uid int, gid int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -478,7 +476,7 @@ func Fchown(fd int, uid int, gid int) (err error) {
 func Flock(fd int, how int) (err error) {
 	_, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -489,7 +487,7 @@ func Fpathconf(fd int, name int) (val int, err error) {
 	r0, _, e1 := Syscall(SYS_FPATHCONF, uintptr(fd), uintptr(name), 0)
 	val = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -499,7 +497,7 @@ func Fpathconf(fd int, name int) (val int, err error) {
 func Fstat(fd int, stat *Stat_t) (err error) {
 	_, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -509,7 +507,7 @@ func Fstat(fd int, stat *Stat_t) (err error) {
 func Fsync(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -519,7 +517,7 @@ func Fsync(fd int) (err error) {
 func Ftruncate(fd int, length int64) (err error) {
 	_, _, e1 := Syscall6(SYS_FTRUNCATE, uintptr(fd), 0, uintptr(length), uintptr(length>>32), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -554,7 +552,7 @@ func Getpgid(pid int) (pgid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0)
 	pgid = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -589,7 +587,7 @@ func Getpriority(which int, who int) (prio int, err error) {
 	r0, _, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0)
 	prio = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -599,7 +597,7 @@ func Getpriority(which int, who int) (prio int, err error) {
 func Getrlimit(which int, lim *Rlimit) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -609,7 +607,7 @@ func Getrlimit(which int, lim *Rlimit) (err error) {
 func Getrusage(who int, rusage *Rusage) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -620,7 +618,7 @@ func Getsid(pid int) (sid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0)
 	sid = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -630,7 +628,7 @@ func Getsid(pid int) (sid int, err error) {
 func Gettimeofday(tv *Timeval) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -656,7 +654,7 @@ func Issetugid() (tainted bool) {
 func Kill(pid int, signum Signal) (err error) {
 	_, _, e1 := Syscall(SYS_KILL, uintptr(pid), uintptr(signum), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -667,7 +665,7 @@ func Kqueue() (fd int, err error) {
 	r0, _, e1 := Syscall(SYS_KQUEUE, 0, 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -683,7 +681,7 @@ func Lchown(path string, uid int, gid int) (err error) {
 	_, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -705,7 +703,7 @@ func Link(path string, link string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -715,7 +713,7 @@ func Link(path string, link string) (err error) {
 func Listen(s int, backlog int) (err error) {
 	_, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(backlog), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -731,7 +729,7 @@ func Lstat(path string, stat *Stat_t) (err error) {
 	_, _, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -747,7 +745,7 @@ func Mkdir(path string, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -763,7 +761,7 @@ func Mkfifo(path string, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -779,7 +777,7 @@ func Mknod(path string, mode uint32, dev int) (err error) {
 	_, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -789,7 +787,7 @@ func Mknod(path string, mode uint32, dev int) (err error) {
 func Nanosleep(time *Timespec, leftover *Timespec) (err error) {
 	_, _, e1 := Syscall(SYS_NANOSLEEP, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -806,7 +804,7 @@ func Open(path string, mode int, perm uint32) (fd int, err error) {
 	use(unsafe.Pointer(_p0))
 	fd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -823,7 +821,7 @@ func Pathconf(path string, name int) (val int, err error) {
 	use(unsafe.Pointer(_p0))
 	val = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -840,7 +838,7 @@ func Pread(fd int, p []byte, offset int64) (n int, err error) {
 	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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -857,7 +855,7 @@ func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
 	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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -874,7 +872,7 @@ func read(fd int, p []byte) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -897,7 +895,7 @@ func Readlink(path string, buf []byte) (n int, err error) {
 	use(unsafe.Pointer(_p0))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -919,7 +917,7 @@ func Rename(from string, to string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -935,7 +933,7 @@ func Revoke(path string) (err error) {
 	_, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -951,7 +949,7 @@ func Rmdir(path string) (err error) {
 	_, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -962,7 +960,7 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
 	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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -972,7 +970,7 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
 func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error) {
 	_, _, e1 := Syscall6(SYS_SELECT, uintptr(n), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -982,7 +980,7 @@ func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error) {
 func Setegid(egid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETEGID, uintptr(egid), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -992,7 +990,7 @@ func Setegid(egid int) (err error) {
 func Seteuid(euid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETEUID, uintptr(euid), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1002,7 +1000,7 @@ func Seteuid(euid int) (err error) {
 func Setgid(gid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETGID, uintptr(gid), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1012,7 +1010,7 @@ func Setgid(gid int) (err error) {
 func Setpgid(pid int, pgid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1022,7 +1020,7 @@ func Setpgid(pid int, pgid int) (err error) {
 func Setpriority(which int, who int, prio int) (err error) {
 	_, _, e1 := Syscall(SYS_SETPRIORITY, uintptr(which), uintptr(who), uintptr(prio))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1032,7 +1030,7 @@ func Setpriority(which int, who int, prio int) (err error) {
 func Setregid(rgid int, egid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1042,7 +1040,7 @@ func Setregid(rgid int, egid int) (err error) {
 func Setreuid(ruid int, euid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1052,7 +1050,7 @@ func Setreuid(ruid int, euid int) (err error) {
 func Setrlimit(which int, lim *Rlimit) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1063,7 +1061,7 @@ func Setsid() (pid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0)
 	pid = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1073,7 +1071,7 @@ func Setsid() (pid int, err error) {
 func Settimeofday(tp *Timeval) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1083,7 +1081,7 @@ func Settimeofday(tp *Timeval) (err error) {
 func Setuid(uid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETUID, uintptr(uid), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1099,7 +1097,7 @@ func Stat(path string, stat *Stat_t) (err error) {
 	_, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1121,7 +1119,7 @@ func Symlink(path string, link string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1131,7 +1129,7 @@ func Symlink(path string, link string) (err error) {
 func Sync() (err error) {
 	_, _, e1 := Syscall(SYS_SYNC, 0, 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1147,7 +1145,7 @@ func Truncate(path string, length int64) (err error) {
 	_, _, e1 := Syscall6(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), 0, uintptr(length), uintptr(length>>32), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1171,7 +1169,7 @@ func Unlink(path string) (err error) {
 	_, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1187,7 +1185,7 @@ func Unmount(path string, flags int) (err error) {
 	_, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1204,7 +1202,7 @@ func write(fd int, p []byte) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1215,7 +1213,7 @@ func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (
 	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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1225,7 +1223,7 @@ func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (
 func munmap(addr uintptr, length uintptr) (err error) {
 	_, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1236,7 +1234,7 @@ 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1247,7 +1245,7 @@ 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
diff --git a/src/syscall/zsyscall_openbsd_386.go b/src/syscall/zsyscall_openbsd_386.go
index df7df1e..5b005d2 100644
--- a/src/syscall/zsyscall_openbsd_386.go
+++ b/src/syscall/zsyscall_openbsd_386.go
@@ -1,8 +1,6 @@
 // mksyscall.pl -l32 -openbsd syscall_bsd.go syscall_openbsd.go syscall_openbsd_386.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
-// +build 386,openbsd
-
 package syscall
 
 import "unsafe"
@@ -13,7 +11,7 @@ func getgroups(ngid int, gid *_Gid_t) (n int, err error) {
 	r0, _, e1 := RawSyscall(SYS_GETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -23,7 +21,7 @@ func getgroups(ngid int, gid *_Gid_t) (n int, err error) {
 func setgroups(ngid int, gid *_Gid_t) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -34,7 +32,7 @@ func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err
 	r0, _, e1 := Syscall6(SYS_WAIT4, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0)
 	wpid = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -45,7 +43,7 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
 	r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	fd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -55,7 +53,7 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -65,7 +63,7 @@ func bind(s int, addr unsafe.Pointer, 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -76,7 +74,7 @@ func socket(domain int, typ int, proto int) (fd int, err error) {
 	r0, _, e1 := RawSyscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto))
 	fd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -86,7 +84,7 @@ func socket(domain int, typ int, proto int) (fd int, 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -96,7 +94,7 @@ func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen
 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -106,7 +104,7 @@ func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr)
 func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETPEERNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -116,7 +114,7 @@ func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETSOCKNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -126,7 +124,7 @@ func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 func Shutdown(s int, how int) (err error) {
 	_, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(s), uintptr(how), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -136,7 +134,7 @@ func Shutdown(s int, how int) (err error) {
 func socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) {
 	_, _, e1 := RawSyscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -153,7 +151,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
 	r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -169,7 +167,7 @@ func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (
 	}
 	_, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -180,7 +178,7 @@ func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -191,7 +189,7 @@ 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -202,7 +200,7 @@ func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, ne
 	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 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -218,7 +216,7 @@ func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr)
 	}
 	_, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -234,7 +232,7 @@ func utimes(path string, timeval *[2]Timeval) (err error) {
 	_, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -244,7 +242,7 @@ func utimes(path string, timeval *[2]Timeval) (err error) {
 func futimes(fd int, timeval *[2]Timeval) (err error) {
 	_, _, e1 := Syscall(SYS_FUTIMES, uintptr(fd), uintptr(unsafe.Pointer(timeval)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -255,7 +253,7 @@ func fcntl(fd int, cmd int, arg int) (val int, err error) {
 	r0, _, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg))
 	val = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -265,7 +263,7 @@ func fcntl(fd int, cmd int, arg int) (val int, err error) {
 func pipe(p *[2]_C_int) (err error) {
 	_, _, e1 := RawSyscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -282,7 +280,7 @@ func getdents(fd int, buf []byte) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_GETDENTS, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -298,7 +296,7 @@ func Access(path string, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -308,7 +306,7 @@ func Access(path string, mode uint32) (err error) {
 func Adjtime(delta *Timeval, olddelta *Timeval) (err error) {
 	_, _, e1 := Syscall(SYS_ADJTIME, uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -324,7 +322,7 @@ func Chdir(path string) (err error) {
 	_, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -340,7 +338,7 @@ func Chflags(path string, flags int) (err error) {
 	_, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -356,7 +354,7 @@ func Chmod(path string, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -372,7 +370,7 @@ func Chown(path string, uid int, gid int) (err error) {
 	_, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -388,7 +386,7 @@ func Chroot(path string) (err error) {
 	_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -398,7 +396,7 @@ func Chroot(path string) (err error) {
 func Close(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -406,10 +404,10 @@ func Close(fd int) (err error) {
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
 func Dup(fd int) (nfd int, err error) {
-	r0, _, e1 := Syscall(SYS_DUP, uintptr(fd), 0, 0)
+	r0, _, e1 := RawSyscall(SYS_DUP, uintptr(fd), 0, 0)
 	nfd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -417,9 +415,9 @@ func Dup(fd int) (nfd int, err error) {
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
 func Dup2(from int, to int) (err error) {
-	_, _, e1 := Syscall(SYS_DUP2, uintptr(from), uintptr(to), 0)
+	_, _, e1 := RawSyscall(SYS_DUP2, uintptr(from), uintptr(to), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -436,7 +434,7 @@ func Exit(code int) {
 func Fchdir(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -446,7 +444,7 @@ func Fchdir(fd int) (err error) {
 func Fchflags(fd int, flags int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(fd), uintptr(flags), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -456,7 +454,7 @@ func Fchflags(fd int, flags int) (err error) {
 func Fchmod(fd int, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -466,7 +464,7 @@ func Fchmod(fd int, mode uint32) (err error) {
 func Fchown(fd int, uid int, gid int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -476,7 +474,7 @@ func Fchown(fd int, uid int, gid int) (err error) {
 func Flock(fd int, how int) (err error) {
 	_, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -487,7 +485,7 @@ func Fpathconf(fd int, name int) (val int, err error) {
 	r0, _, e1 := Syscall(SYS_FPATHCONF, uintptr(fd), uintptr(name), 0)
 	val = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -497,7 +495,7 @@ func Fpathconf(fd int, name int) (val int, err error) {
 func Fstat(fd int, stat *Stat_t) (err error) {
 	_, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -507,7 +505,7 @@ func Fstat(fd int, stat *Stat_t) (err error) {
 func Fstatfs(fd int, stat *Statfs_t) (err error) {
 	_, _, e1 := Syscall(SYS_FSTATFS, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -517,7 +515,7 @@ func Fstatfs(fd int, stat *Statfs_t) (err error) {
 func Fsync(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -527,7 +525,7 @@ func Fsync(fd int) (err error) {
 func Ftruncate(fd int, length int64) (err error) {
 	_, _, e1 := Syscall6(SYS_FTRUNCATE, uintptr(fd), 0, uintptr(length), uintptr(length>>32), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -562,7 +560,7 @@ func Getpgid(pid int) (pgid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0)
 	pgid = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -597,7 +595,7 @@ func Getpriority(which int, who int) (prio int, err error) {
 	r0, _, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0)
 	prio = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -607,7 +605,7 @@ func Getpriority(which int, who int) (prio int, err error) {
 func Getrlimit(which int, lim *Rlimit) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -617,7 +615,7 @@ func Getrlimit(which int, lim *Rlimit) (err error) {
 func Getrusage(who int, rusage *Rusage) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -628,7 +626,7 @@ func Getsid(pid int) (sid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0)
 	sid = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -638,7 +636,7 @@ func Getsid(pid int) (sid int, err error) {
 func Gettimeofday(tv *Timeval) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -664,7 +662,7 @@ func Issetugid() (tainted bool) {
 func Kill(pid int, signum Signal) (err error) {
 	_, _, e1 := Syscall(SYS_KILL, uintptr(pid), uintptr(signum), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -675,7 +673,7 @@ func Kqueue() (fd int, err error) {
 	r0, _, e1 := Syscall(SYS_KQUEUE, 0, 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -691,7 +689,7 @@ func Lchown(path string, uid int, gid int) (err error) {
 	_, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -713,7 +711,7 @@ func Link(path string, link string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -723,7 +721,7 @@ func Link(path string, link string) (err error) {
 func Listen(s int, backlog int) (err error) {
 	_, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(backlog), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -739,7 +737,7 @@ func Lstat(path string, stat *Stat_t) (err error) {
 	_, _, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -755,7 +753,7 @@ func Mkdir(path string, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -771,7 +769,7 @@ func Mkfifo(path string, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -787,7 +785,7 @@ func Mknod(path string, mode uint32, dev int) (err error) {
 	_, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -797,7 +795,7 @@ func Mknod(path string, mode uint32, dev int) (err error) {
 func Nanosleep(time *Timespec, leftover *Timespec) (err error) {
 	_, _, e1 := Syscall(SYS_NANOSLEEP, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -814,7 +812,7 @@ func Open(path string, mode int, perm uint32) (fd int, err error) {
 	use(unsafe.Pointer(_p0))
 	fd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -831,7 +829,7 @@ func Pathconf(path string, name int) (val int, err error) {
 	use(unsafe.Pointer(_p0))
 	val = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -848,7 +846,7 @@ func Pread(fd int, p []byte, offset int64) (n int, err error) {
 	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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -865,7 +863,7 @@ func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
 	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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -882,7 +880,7 @@ func read(fd int, p []byte) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -905,7 +903,7 @@ func Readlink(path string, buf []byte) (n int, err error) {
 	use(unsafe.Pointer(_p0))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -927,7 +925,7 @@ func Rename(from string, to string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -943,7 +941,7 @@ func Revoke(path string) (err error) {
 	_, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -959,7 +957,7 @@ func Rmdir(path string) (err error) {
 	_, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -970,7 +968,7 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
 	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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -980,7 +978,7 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
 func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error) {
 	_, _, e1 := Syscall6(SYS_SELECT, uintptr(n), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -990,7 +988,7 @@ func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error) {
 func Setegid(egid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETEGID, uintptr(egid), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1000,7 +998,7 @@ func Setegid(egid int) (err error) {
 func Seteuid(euid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETEUID, uintptr(euid), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1010,7 +1008,7 @@ func Seteuid(euid int) (err error) {
 func Setgid(gid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETGID, uintptr(gid), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1026,7 +1024,7 @@ func Setlogin(name string) (err error) {
 	_, _, e1 := Syscall(SYS_SETLOGIN, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1036,7 +1034,7 @@ func Setlogin(name string) (err error) {
 func Setpgid(pid int, pgid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1046,7 +1044,7 @@ func Setpgid(pid int, pgid int) (err error) {
 func Setpriority(which int, who int, prio int) (err error) {
 	_, _, e1 := Syscall(SYS_SETPRIORITY, uintptr(which), uintptr(who), uintptr(prio))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1056,7 +1054,7 @@ func Setpriority(which int, who int, prio int) (err error) {
 func Setregid(rgid int, egid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1066,7 +1064,7 @@ func Setregid(rgid int, egid int) (err error) {
 func Setreuid(ruid int, euid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1076,7 +1074,7 @@ func Setreuid(ruid int, euid int) (err error) {
 func Setrlimit(which int, lim *Rlimit) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1087,7 +1085,7 @@ func Setsid() (pid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0)
 	pid = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1097,7 +1095,7 @@ func Setsid() (pid int, err error) {
 func Settimeofday(tp *Timeval) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1107,7 +1105,7 @@ func Settimeofday(tp *Timeval) (err error) {
 func Setuid(uid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETUID, uintptr(uid), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1123,7 +1121,7 @@ func Stat(path string, stat *Stat_t) (err error) {
 	_, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1139,7 +1137,7 @@ func Statfs(path string, stat *Statfs_t) (err error) {
 	_, _, e1 := Syscall(SYS_STATFS, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1161,7 +1159,7 @@ func Symlink(path string, link string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1171,7 +1169,7 @@ func Symlink(path string, link string) (err error) {
 func Sync() (err error) {
 	_, _, e1 := Syscall(SYS_SYNC, 0, 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1187,7 +1185,7 @@ func Truncate(path string, length int64) (err error) {
 	_, _, e1 := Syscall6(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), 0, uintptr(length), uintptr(length>>32), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1211,7 +1209,7 @@ func Unlink(path string) (err error) {
 	_, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1227,7 +1225,7 @@ func Unmount(path string, flags int) (err error) {
 	_, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1244,7 +1242,7 @@ func write(fd int, p []byte) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1255,7 +1253,7 @@ func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (
 	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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1265,7 +1263,7 @@ func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (
 func munmap(addr uintptr, length uintptr) (err error) {
 	_, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1276,7 +1274,7 @@ 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1287,7 +1285,7 @@ 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
diff --git a/src/syscall/zsyscall_openbsd_amd64.go b/src/syscall/zsyscall_openbsd_amd64.go
index 1d64070..ce9397b 100644
--- a/src/syscall/zsyscall_openbsd_amd64.go
+++ b/src/syscall/zsyscall_openbsd_amd64.go
@@ -1,8 +1,6 @@
 // mksyscall.pl -openbsd syscall_bsd.go syscall_openbsd.go syscall_openbsd_amd64.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
-// +build amd64,openbsd
-
 package syscall
 
 import "unsafe"
@@ -13,7 +11,7 @@ func getgroups(ngid int, gid *_Gid_t) (n int, err error) {
 	r0, _, e1 := RawSyscall(SYS_GETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -23,7 +21,7 @@ func getgroups(ngid int, gid *_Gid_t) (n int, err error) {
 func setgroups(ngid int, gid *_Gid_t) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -34,7 +32,7 @@ func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err
 	r0, _, e1 := Syscall6(SYS_WAIT4, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)), 0, 0)
 	wpid = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -45,7 +43,7 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
 	r0, _, e1 := Syscall(SYS_ACCEPT, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	fd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -55,7 +53,7 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -65,7 +63,7 @@ func bind(s int, addr unsafe.Pointer, 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -76,7 +74,7 @@ func socket(domain int, typ int, proto int) (fd int, err error) {
 	r0, _, e1 := RawSyscall(SYS_SOCKET, uintptr(domain), uintptr(typ), uintptr(proto))
 	fd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -86,7 +84,7 @@ func socket(domain int, typ int, proto int) (fd int, 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -96,7 +94,7 @@ func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen
 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -106,7 +104,7 @@ func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr)
 func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETPEERNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -116,7 +114,7 @@ func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETSOCKNAME, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -126,7 +124,7 @@ func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 func Shutdown(s int, how int) (err error) {
 	_, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(s), uintptr(how), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -136,7 +134,7 @@ func Shutdown(s int, how int) (err error) {
 func socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) {
 	_, _, e1 := RawSyscall6(SYS_SOCKETPAIR, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -153,7 +151,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
 	r0, _, e1 := Syscall6(SYS_RECVFROM, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -169,7 +167,7 @@ func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (
 	}
 	_, _, e1 := Syscall6(SYS_SENDTO, uintptr(s), uintptr(_p0), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -180,7 +178,7 @@ func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_RECVMSG, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -191,7 +189,7 @@ 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -202,7 +200,7 @@ func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, ne
 	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 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -218,7 +216,7 @@ func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr)
 	}
 	_, _, e1 := Syscall6(SYS___SYSCTL, uintptr(_p0), uintptr(len(mib)), uintptr(unsafe.Pointer(old)), uintptr(unsafe.Pointer(oldlen)), uintptr(unsafe.Pointer(new)), uintptr(newlen))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -234,7 +232,7 @@ func utimes(path string, timeval *[2]Timeval) (err error) {
 	_, _, e1 := Syscall(SYS_UTIMES, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(timeval)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -244,7 +242,7 @@ func utimes(path string, timeval *[2]Timeval) (err error) {
 func futimes(fd int, timeval *[2]Timeval) (err error) {
 	_, _, e1 := Syscall(SYS_FUTIMES, uintptr(fd), uintptr(unsafe.Pointer(timeval)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -255,7 +253,7 @@ func fcntl(fd int, cmd int, arg int) (val int, err error) {
 	r0, _, e1 := Syscall(SYS_FCNTL, uintptr(fd), uintptr(cmd), uintptr(arg))
 	val = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -265,7 +263,7 @@ func fcntl(fd int, cmd int, arg int) (val int, err error) {
 func pipe(p *[2]_C_int) (err error) {
 	_, _, e1 := RawSyscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -282,7 +280,7 @@ func getdents(fd int, buf []byte) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_GETDENTS, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -298,7 +296,7 @@ func Access(path string, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -308,7 +306,7 @@ func Access(path string, mode uint32) (err error) {
 func Adjtime(delta *Timeval, olddelta *Timeval) (err error) {
 	_, _, e1 := Syscall(SYS_ADJTIME, uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -324,7 +322,7 @@ func Chdir(path string) (err error) {
 	_, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -340,7 +338,7 @@ func Chflags(path string, flags int) (err error) {
 	_, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -356,7 +354,7 @@ func Chmod(path string, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -372,7 +370,7 @@ func Chown(path string, uid int, gid int) (err error) {
 	_, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -388,7 +386,7 @@ func Chroot(path string) (err error) {
 	_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -398,7 +396,7 @@ func Chroot(path string) (err error) {
 func Close(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -406,10 +404,10 @@ func Close(fd int) (err error) {
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
 func Dup(fd int) (nfd int, err error) {
-	r0, _, e1 := Syscall(SYS_DUP, uintptr(fd), 0, 0)
+	r0, _, e1 := RawSyscall(SYS_DUP, uintptr(fd), 0, 0)
 	nfd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -417,9 +415,9 @@ func Dup(fd int) (nfd int, err error) {
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
 func Dup2(from int, to int) (err error) {
-	_, _, e1 := Syscall(SYS_DUP2, uintptr(from), uintptr(to), 0)
+	_, _, e1 := RawSyscall(SYS_DUP2, uintptr(from), uintptr(to), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -436,7 +434,7 @@ func Exit(code int) {
 func Fchdir(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHDIR, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -446,7 +444,7 @@ func Fchdir(fd int) (err error) {
 func Fchflags(fd int, flags int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(fd), uintptr(flags), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -456,7 +454,7 @@ func Fchflags(fd int, flags int) (err error) {
 func Fchmod(fd int, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_FCHMOD, uintptr(fd), uintptr(mode), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -466,7 +464,7 @@ func Fchmod(fd int, mode uint32) (err error) {
 func Fchown(fd int, uid int, gid int) (err error) {
 	_, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -476,7 +474,7 @@ func Fchown(fd int, uid int, gid int) (err error) {
 func Flock(fd int, how int) (err error) {
 	_, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -487,7 +485,7 @@ func Fpathconf(fd int, name int) (val int, err error) {
 	r0, _, e1 := Syscall(SYS_FPATHCONF, uintptr(fd), uintptr(name), 0)
 	val = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -497,7 +495,7 @@ func Fpathconf(fd int, name int) (val int, err error) {
 func Fstat(fd int, stat *Stat_t) (err error) {
 	_, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -507,7 +505,7 @@ func Fstat(fd int, stat *Stat_t) (err error) {
 func Fstatfs(fd int, stat *Statfs_t) (err error) {
 	_, _, e1 := Syscall(SYS_FSTATFS, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -517,7 +515,7 @@ func Fstatfs(fd int, stat *Statfs_t) (err error) {
 func Fsync(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -527,7 +525,7 @@ func Fsync(fd int) (err error) {
 func Ftruncate(fd int, length int64) (err error) {
 	_, _, e1 := Syscall(SYS_FTRUNCATE, uintptr(fd), 0, uintptr(length))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -562,7 +560,7 @@ func Getpgid(pid int) (pgid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0)
 	pgid = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -597,7 +595,7 @@ func Getpriority(which int, who int) (prio int, err error) {
 	r0, _, e1 := Syscall(SYS_GETPRIORITY, uintptr(which), uintptr(who), 0)
 	prio = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -607,7 +605,7 @@ func Getpriority(which int, who int) (prio int, err error) {
 func Getrlimit(which int, lim *Rlimit) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -617,7 +615,7 @@ func Getrlimit(which int, lim *Rlimit) (err error) {
 func Getrusage(who int, rusage *Rusage) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETRUSAGE, uintptr(who), uintptr(unsafe.Pointer(rusage)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -628,7 +626,7 @@ func Getsid(pid int) (sid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0)
 	sid = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -638,7 +636,7 @@ func Getsid(pid int) (sid int, err error) {
 func Gettimeofday(tv *Timeval) (err error) {
 	_, _, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tv)), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -664,7 +662,7 @@ func Issetugid() (tainted bool) {
 func Kill(pid int, signum Signal) (err error) {
 	_, _, e1 := Syscall(SYS_KILL, uintptr(pid), uintptr(signum), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -675,7 +673,7 @@ func Kqueue() (fd int, err error) {
 	r0, _, e1 := Syscall(SYS_KQUEUE, 0, 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -691,7 +689,7 @@ func Lchown(path string, uid int, gid int) (err error) {
 	_, _, e1 := Syscall(SYS_LCHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -713,7 +711,7 @@ func Link(path string, link string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -723,7 +721,7 @@ func Link(path string, link string) (err error) {
 func Listen(s int, backlog int) (err error) {
 	_, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(backlog), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -739,7 +737,7 @@ func Lstat(path string, stat *Stat_t) (err error) {
 	_, _, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -755,7 +753,7 @@ func Mkdir(path string, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -771,7 +769,7 @@ func Mkfifo(path string, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -787,7 +785,7 @@ func Mknod(path string, mode uint32, dev int) (err error) {
 	_, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -797,7 +795,7 @@ func Mknod(path string, mode uint32, dev int) (err error) {
 func Nanosleep(time *Timespec, leftover *Timespec) (err error) {
 	_, _, e1 := Syscall(SYS_NANOSLEEP, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -814,7 +812,7 @@ func Open(path string, mode int, perm uint32) (fd int, err error) {
 	use(unsafe.Pointer(_p0))
 	fd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -831,7 +829,7 @@ func Pathconf(path string, name int) (val int, err error) {
 	use(unsafe.Pointer(_p0))
 	val = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -848,7 +846,7 @@ func Pread(fd int, p []byte, offset int64) (n int, err error) {
 	r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), 0, uintptr(offset), 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -865,7 +863,7 @@ func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
 	r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), 0, uintptr(offset), 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -882,7 +880,7 @@ func read(fd int, p []byte) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -905,7 +903,7 @@ func Readlink(path string, buf []byte) (n int, err error) {
 	use(unsafe.Pointer(_p0))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -927,7 +925,7 @@ func Rename(from string, to string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -943,7 +941,7 @@ func Revoke(path string) (err error) {
 	_, _, e1 := Syscall(SYS_REVOKE, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -959,7 +957,7 @@ func Rmdir(path string) (err error) {
 	_, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -970,7 +968,7 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
 	r0, _, e1 := Syscall6(SYS_LSEEK, uintptr(fd), 0, uintptr(offset), uintptr(whence), 0, 0)
 	newoffset = int64(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -980,7 +978,7 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
 func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error) {
 	_, _, e1 := Syscall6(SYS_SELECT, uintptr(n), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -990,7 +988,7 @@ func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error) {
 func Setegid(egid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETEGID, uintptr(egid), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1000,7 +998,7 @@ func Setegid(egid int) (err error) {
 func Seteuid(euid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETEUID, uintptr(euid), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1010,7 +1008,7 @@ func Seteuid(euid int) (err error) {
 func Setgid(gid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETGID, uintptr(gid), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1026,7 +1024,7 @@ func Setlogin(name string) (err error) {
 	_, _, e1 := Syscall(SYS_SETLOGIN, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1036,7 +1034,7 @@ func Setlogin(name string) (err error) {
 func Setpgid(pid int, pgid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1046,7 +1044,7 @@ func Setpgid(pid int, pgid int) (err error) {
 func Setpriority(which int, who int, prio int) (err error) {
 	_, _, e1 := Syscall(SYS_SETPRIORITY, uintptr(which), uintptr(who), uintptr(prio))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1056,7 +1054,7 @@ func Setpriority(which int, who int, prio int) (err error) {
 func Setregid(rgid int, egid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETREGID, uintptr(rgid), uintptr(egid), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1066,7 +1064,7 @@ func Setregid(rgid int, egid int) (err error) {
 func Setreuid(ruid int, euid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETREUID, uintptr(ruid), uintptr(euid), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1076,7 +1074,7 @@ func Setreuid(ruid int, euid int) (err error) {
 func Setrlimit(which int, lim *Rlimit) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1087,7 +1085,7 @@ func Setsid() (pid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0)
 	pid = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1097,7 +1095,7 @@ func Setsid() (pid int, err error) {
 func Settimeofday(tp *Timeval) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1107,7 +1105,7 @@ func Settimeofday(tp *Timeval) (err error) {
 func Setuid(uid int) (err error) {
 	_, _, e1 := RawSyscall(SYS_SETUID, uintptr(uid), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1123,7 +1121,7 @@ func Stat(path string, stat *Stat_t) (err error) {
 	_, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1139,7 +1137,7 @@ func Statfs(path string, stat *Statfs_t) (err error) {
 	_, _, e1 := Syscall(SYS_STATFS, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1161,7 +1159,7 @@ func Symlink(path string, link string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1171,7 +1169,7 @@ func Symlink(path string, link string) (err error) {
 func Sync() (err error) {
 	_, _, e1 := Syscall(SYS_SYNC, 0, 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1187,7 +1185,7 @@ func Truncate(path string, length int64) (err error) {
 	_, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), 0, uintptr(length))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1211,7 +1209,7 @@ func Unlink(path string) (err error) {
 	_, _, e1 := Syscall(SYS_UNLINK, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1227,7 +1225,7 @@ func Unmount(path string, flags int) (err error) {
 	_, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1244,7 +1242,7 @@ func write(fd int, p []byte) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1255,7 +1253,7 @@ func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (
 	r0, _, e1 := Syscall9(SYS_MMAP, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flag), uintptr(fd), 0, uintptr(pos), 0, 0)
 	ret = uintptr(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1265,7 +1263,7 @@ func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (
 func munmap(addr uintptr, length uintptr) (err error) {
 	_, _, e1 := Syscall(SYS_MUNMAP, uintptr(addr), uintptr(length), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1276,7 +1274,7 @@ 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1287,7 +1285,7 @@ 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
diff --git a/src/syscall/zsyscall_plan9_386.go b/src/syscall/zsyscall_plan9_386.go
index a424e78..44b74d7 100644
--- a/src/syscall/zsyscall_plan9_386.go
+++ b/src/syscall/zsyscall_plan9_386.go
@@ -1,8 +1,6 @@
 // mksyscall.pl -l32 -plan9 syscall_plan9.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
-// +build 386,plan9
-
 package syscall
 
 import "unsafe"
@@ -25,7 +23,7 @@ func fd2path(fd int, buf []byte) (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func pipe(p *[2]int32) (err error) {
+func pipe(p *[2]_C_int) (err error) {
 	r0, _, e1 := Syscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0)
 	if int32(r0) == -1 {
 		err = e1
@@ -52,7 +50,18 @@ func await(s []byte) (n int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func open(path string, mode int) (fd int, err error) {
+func Dup(oldfd int, newfd int) (fd int, err error) {
+	r0, _, e1 := Syscall(SYS_DUP, uintptr(oldfd), uintptr(newfd), 0)
+	fd = int(r0)
+	if int32(r0) == -1 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Open(path string, mode int) (fd int, err error) {
 	var _p0 *byte
 	_p0, err = BytePtrFromString(path)
 	if err != nil {
@@ -69,7 +78,7 @@ func open(path string, mode int) (fd int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func create(path string, mode int, perm uint32) (fd int, err error) {
+func Create(path string, mode int, perm uint32) (fd int, err error) {
 	var _p0 *byte
 	_p0, err = BytePtrFromString(path)
 	if err != nil {
@@ -86,7 +95,7 @@ func create(path string, mode int, perm uint32) (fd int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func remove(path string) (err error) {
+func Remove(path string) (err error) {
 	var _p0 *byte
 	_p0, err = BytePtrFromString(path)
 	if err != nil {
@@ -102,21 +111,58 @@ func remove(path string) (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func stat(path string, edir []byte) (n int, err error) {
+func Pread(fd int, p []byte, offset int64) (n int, err error) {
+	var _p0 unsafe.Pointer
+	if len(p) > 0 {
+		_p0 = unsafe.Pointer(&p[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
+	n = int(r0)
+	if int32(r0) == -1 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
+	var _p0 unsafe.Pointer
+	if len(p) > 0 {
+		_p0 = unsafe.Pointer(&p[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
+	n = int(r0)
+	if int32(r0) == -1 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Close(fd int) (err error) {
+	r0, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
+	if int32(r0) == -1 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Chdir(path string) (err error) {
 	var _p0 *byte
 	_p0, err = BytePtrFromString(path)
 	if err != nil {
 		return
 	}
-	var _p1 unsafe.Pointer
-	if len(edir) > 0 {
-		_p1 = unsafe.Pointer(&edir[0])
-	} else {
-		_p1 = unsafe.Pointer(&_zero)
-	}
-	r0, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(edir)))
+	r0, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
-	n = int(r0)
 	if int32(r0) == -1 {
 		err = e1
 	}
@@ -125,7 +171,7 @@ func stat(path string, edir []byte) (n int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func bind(name string, old string, flag int) (err error) {
+func Bind(name string, old string, flag int) (err error) {
 	var _p0 *byte
 	_p0, err = BytePtrFromString(name)
 	if err != nil {
@@ -147,7 +193,7 @@ func bind(name string, old string, flag int) (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func mount(fd int, afd int, old string, flag int, aname string) (err error) {
+func Mount(fd int, afd int, old string, flag int, aname string) (err error) {
 	var _p0 *byte
 	_p0, err = BytePtrFromString(old)
 	if err != nil {
@@ -169,7 +215,7 @@ func mount(fd int, afd int, old string, flag int, aname string) (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func wstat(path string, edir []byte) (err error) {
+func Stat(path string, edir []byte) (n int, err error) {
 	var _p0 *byte
 	_p0, err = BytePtrFromString(path)
 	if err != nil {
@@ -181,51 +227,8 @@ func wstat(path string, edir []byte) (err error) {
 	} else {
 		_p1 = unsafe.Pointer(&_zero)
 	}
-	r0, _, e1 := Syscall(SYS_WSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(edir)))
-	use(unsafe.Pointer(_p0))
-	if int32(r0) == -1 {
-		err = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func chdir(path string) (err error) {
-	var _p0 *byte
-	_p0, err = BytePtrFromString(path)
-	if err != nil {
-		return
-	}
-	r0, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
+	r0, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(edir)))
 	use(unsafe.Pointer(_p0))
-	if int32(r0) == -1 {
-		err = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Dup(oldfd int, newfd int) (fd int, err error) {
-	r0, _, e1 := Syscall(SYS_DUP, uintptr(oldfd), uintptr(newfd), 0)
-	fd = int(r0)
-	if int32(r0) == -1 {
-		err = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Pread(fd int, p []byte, offset int64) (n int, err error) {
-	var _p0 unsafe.Pointer
-	if len(p) > 0 {
-		_p0 = unsafe.Pointer(&p[0])
-	} else {
-		_p0 = unsafe.Pointer(&_zero)
-	}
-	r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
 	n = int(r0)
 	if int32(r0) == -1 {
 		err = e1
@@ -235,14 +238,14 @@ func Pread(fd int, p []byte, offset int64) (n int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
+func Fstat(fd int, edir []byte) (n int, err error) {
 	var _p0 unsafe.Pointer
-	if len(p) > 0 {
-		_p0 = unsafe.Pointer(&p[0])
+	if len(edir) > 0 {
+		_p0 = unsafe.Pointer(&edir[0])
 	} 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 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(_p0), uintptr(len(edir)))
 	n = int(r0)
 	if int32(r0) == -1 {
 		err = e1
@@ -252,25 +255,20 @@ func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func Close(fd int) (err error) {
-	r0, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
-	if int32(r0) == -1 {
-		err = e1
+func Wstat(path string, edir []byte) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
 	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Fstat(fd int, edir []byte) (n int, err error) {
-	var _p0 unsafe.Pointer
+	var _p1 unsafe.Pointer
 	if len(edir) > 0 {
-		_p0 = unsafe.Pointer(&edir[0])
+		_p1 = unsafe.Pointer(&edir[0])
 	} else {
-		_p0 = unsafe.Pointer(&_zero)
+		_p1 = unsafe.Pointer(&_zero)
 	}
-	r0, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(_p0), uintptr(len(edir)))
-	n = int(r0)
+	r0, _, e1 := Syscall(SYS_WSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(edir)))
+	use(unsafe.Pointer(_p0))
 	if int32(r0) == -1 {
 		err = e1
 	}
diff --git a/src/syscall/zsyscall_plan9_amd64.go b/src/syscall/zsyscall_plan9_amd64.go
index d58556b..44b74d7 100644
--- a/src/syscall/zsyscall_plan9_amd64.go
+++ b/src/syscall/zsyscall_plan9_amd64.go
@@ -1,8 +1,6 @@
 // mksyscall.pl -l32 -plan9 syscall_plan9.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
-// +build amd64,plan9
-
 package syscall
 
 import "unsafe"
@@ -25,7 +23,7 @@ func fd2path(fd int, buf []byte) (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func pipe(p *[2]int32) (err error) {
+func pipe(p *[2]_C_int) (err error) {
 	r0, _, e1 := Syscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0)
 	if int32(r0) == -1 {
 		err = e1
@@ -52,7 +50,18 @@ func await(s []byte) (n int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func open(path string, mode int) (fd int, err error) {
+func Dup(oldfd int, newfd int) (fd int, err error) {
+	r0, _, e1 := Syscall(SYS_DUP, uintptr(oldfd), uintptr(newfd), 0)
+	fd = int(r0)
+	if int32(r0) == -1 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Open(path string, mode int) (fd int, err error) {
 	var _p0 *byte
 	_p0, err = BytePtrFromString(path)
 	if err != nil {
@@ -69,7 +78,7 @@ func open(path string, mode int) (fd int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func create(path string, mode int, perm uint32) (fd int, err error) {
+func Create(path string, mode int, perm uint32) (fd int, err error) {
 	var _p0 *byte
 	_p0, err = BytePtrFromString(path)
 	if err != nil {
@@ -86,7 +95,7 @@ func create(path string, mode int, perm uint32) (fd int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func remove(path string) (err error) {
+func Remove(path string) (err error) {
 	var _p0 *byte
 	_p0, err = BytePtrFromString(path)
 	if err != nil {
@@ -102,21 +111,58 @@ func remove(path string) (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func stat(path string, edir []byte) (n int, err error) {
+func Pread(fd int, p []byte, offset int64) (n int, err error) {
+	var _p0 unsafe.Pointer
+	if len(p) > 0 {
+		_p0 = unsafe.Pointer(&p[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
+	n = int(r0)
+	if int32(r0) == -1 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
+	var _p0 unsafe.Pointer
+	if len(p) > 0 {
+		_p0 = unsafe.Pointer(&p[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
+	n = int(r0)
+	if int32(r0) == -1 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Close(fd int) (err error) {
+	r0, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
+	if int32(r0) == -1 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Chdir(path string) (err error) {
 	var _p0 *byte
 	_p0, err = BytePtrFromString(path)
 	if err != nil {
 		return
 	}
-	var _p1 unsafe.Pointer
-	if len(edir) > 0 {
-		_p1 = unsafe.Pointer(&edir[0])
-	} else {
-		_p1 = unsafe.Pointer(&_zero)
-	}
-	r0, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(edir)))
+	r0, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
-	n = int(r0)
 	if int32(r0) == -1 {
 		err = e1
 	}
@@ -125,7 +171,7 @@ func stat(path string, edir []byte) (n int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func bind(name string, old string, flag int) (err error) {
+func Bind(name string, old string, flag int) (err error) {
 	var _p0 *byte
 	_p0, err = BytePtrFromString(name)
 	if err != nil {
@@ -147,7 +193,7 @@ func bind(name string, old string, flag int) (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func mount(fd int, afd int, old string, flag int, aname string) (err error) {
+func Mount(fd int, afd int, old string, flag int, aname string) (err error) {
 	var _p0 *byte
 	_p0, err = BytePtrFromString(old)
 	if err != nil {
@@ -169,7 +215,7 @@ func mount(fd int, afd int, old string, flag int, aname string) (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func wstat(path string, edir []byte) (err error) {
+func Stat(path string, edir []byte) (n int, err error) {
 	var _p0 *byte
 	_p0, err = BytePtrFromString(path)
 	if err != nil {
@@ -181,51 +227,8 @@ func wstat(path string, edir []byte) (err error) {
 	} else {
 		_p1 = unsafe.Pointer(&_zero)
 	}
-	r0, _, e1 := Syscall(SYS_WSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(edir)))
-	use(unsafe.Pointer(_p0))
-	if int32(r0) == -1 {
-		err = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func chdir(path string) (err error) {
-	var _p0 *byte
-	_p0, err = BytePtrFromString(path)
-	if err != nil {
-		return
-	}
-	r0, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
+	r0, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(edir)))
 	use(unsafe.Pointer(_p0))
-	if int32(r0) == -1 {
-		err = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Dup(oldfd int, newfd int) (fd int, err error) {
-	r0, _, e1 := Syscall(SYS_DUP, uintptr(oldfd), uintptr(newfd), 0)
-	fd = int(r0)
-	if int32(r0) == -1 {
-		err = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Pread(fd int, p []byte, offset int64) (n int, err error) {
-	var _p0 unsafe.Pointer
-	if len(p) > 0 {
-		_p0 = unsafe.Pointer(&p[0])
-	} else {
-		_p0 = unsafe.Pointer(&_zero)
-	}
-	r0, _, e1 := Syscall6(SYS_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
 	n = int(r0)
 	if int32(r0) == -1 {
 		err = e1
@@ -235,14 +238,14 @@ func Pread(fd int, p []byte, offset int64) (n int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
+func Fstat(fd int, edir []byte) (n int, err error) {
 	var _p0 unsafe.Pointer
-	if len(p) > 0 {
-		_p0 = unsafe.Pointer(&p[0])
+	if len(edir) > 0 {
+		_p0 = unsafe.Pointer(&edir[0])
 	} 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 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(_p0), uintptr(len(edir)))
 	n = int(r0)
 	if int32(r0) == -1 {
 		err = e1
@@ -252,25 +255,20 @@ func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func Close(fd int) (err error) {
-	r0, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
-	if int32(r0) == -1 {
-		err = e1
+func Wstat(path string, edir []byte) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
 	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Fstat(fd int, edir []byte) (n int, err error) {
-	var _p0 unsafe.Pointer
+	var _p1 unsafe.Pointer
 	if len(edir) > 0 {
-		_p0 = unsafe.Pointer(&edir[0])
+		_p1 = unsafe.Pointer(&edir[0])
 	} else {
-		_p0 = unsafe.Pointer(&_zero)
+		_p1 = unsafe.Pointer(&_zero)
 	}
-	r0, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(_p0), uintptr(len(edir)))
-	n = int(r0)
+	r0, _, e1 := Syscall(SYS_WSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(edir)))
+	use(unsafe.Pointer(_p0))
 	if int32(r0) == -1 {
 		err = e1
 	}
diff --git a/src/syscall/zsyscall_solaris_amd64.go b/src/syscall/zsyscall_solaris_amd64.go
index cabab7e..43b224a 100644
--- a/src/syscall/zsyscall_solaris_amd64.go
+++ b/src/syscall/zsyscall_solaris_amd64.go
@@ -1,302 +1,136 @@
 // mksyscall_solaris.pl syscall_solaris.go syscall_solaris_amd64.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
-// +build amd64,solaris
-
 package syscall
 
 import "unsafe"
 
-//go:cgo_import_dynamic libc_getgroups getgroups "libc.so"
-//go:cgo_import_dynamic libc_setgroups setgroups "libc.so"
-//go:cgo_import_dynamic libc_fcntl fcntl "libc.so"
-//go:cgo_import_dynamic libc_accept accept "libsocket.so"
-//go:cgo_import_dynamic libc_sendmsg sendmsg "libsocket.so"
-//go:cgo_import_dynamic libc_Access access "libc.so"
-//go:cgo_import_dynamic libc_Adjtime adjtime "libc.so"
-//go:cgo_import_dynamic libc_Chdir chdir "libc.so"
-//go:cgo_import_dynamic libc_Chmod chmod "libc.so"
-//go:cgo_import_dynamic libc_Chown chown "libc.so"
-//go:cgo_import_dynamic libc_Chroot chroot "libc.so"
-//go:cgo_import_dynamic libc_Close close "libc.so"
-//go:cgo_import_dynamic libc_Dup dup "libc.so"
-//go:cgo_import_dynamic libc_Exit exit "libc.so"
-//go:cgo_import_dynamic libc_Fchdir fchdir "libc.so"
-//go:cgo_import_dynamic libc_Fchmod fchmod "libc.so"
-//go:cgo_import_dynamic libc_Fchown fchown "libc.so"
-//go:cgo_import_dynamic libc_Fpathconf fpathconf "libc.so"
-//go:cgo_import_dynamic libc_Fstat fstat "libc.so"
-//go:cgo_import_dynamic libc_Getdents getdents "libc.so"
-//go:cgo_import_dynamic libc_Getgid getgid "libc.so"
-//go:cgo_import_dynamic libc_Getpid getpid "libc.so"
-//go:cgo_import_dynamic libc_Geteuid geteuid "libc.so"
-//go:cgo_import_dynamic libc_Getegid getegid "libc.so"
-//go:cgo_import_dynamic libc_Getppid getppid "libc.so"
-//go:cgo_import_dynamic libc_Getpriority getpriority "libc.so"
-//go:cgo_import_dynamic libc_Getrlimit getrlimit "libc.so"
-//go:cgo_import_dynamic libc_Gettimeofday gettimeofday "libc.so"
-//go:cgo_import_dynamic libc_Getuid getuid "libc.so"
-//go:cgo_import_dynamic libc_Kill kill "libc.so"
-//go:cgo_import_dynamic libc_Lchown lchown "libc.so"
-//go:cgo_import_dynamic libc_Link link "libc.so"
-//go:cgo_import_dynamic libc_listen listen "libsocket.so"
-//go:cgo_import_dynamic libc_Lstat lstat "libc.so"
-//go:cgo_import_dynamic libc_Mkdir mkdir "libc.so"
-//go:cgo_import_dynamic libc_Mknod mknod "libc.so"
-//go:cgo_import_dynamic libc_Nanosleep nanosleep "libc.so"
-//go:cgo_import_dynamic libc_Open open "libc.so"
-//go:cgo_import_dynamic libc_Pathconf pathconf "libc.so"
-//go:cgo_import_dynamic libc_Pread pread "libc.so"
-//go:cgo_import_dynamic libc_Pwrite pwrite "libc.so"
-//go:cgo_import_dynamic libc_read read "libc.so"
-//go:cgo_import_dynamic libc_Readlink readlink "libc.so"
-//go:cgo_import_dynamic libc_Rename rename "libc.so"
-//go:cgo_import_dynamic libc_Rmdir rmdir "libc.so"
-//go:cgo_import_dynamic libc_lseek lseek "libc.so"
-//go:cgo_import_dynamic libc_sendfile sendfile "libsendfile.so"
-//go:cgo_import_dynamic libc_Setegid setegid "libc.so"
-//go:cgo_import_dynamic libc_Seteuid seteuid "libc.so"
-//go:cgo_import_dynamic libc_Setgid setgid "libc.so"
-//go:cgo_import_dynamic libc_Setpgid setpgid "libc.so"
-//go:cgo_import_dynamic libc_Setpriority setpriority "libc.so"
-//go:cgo_import_dynamic libc_Setregid setregid "libc.so"
-//go:cgo_import_dynamic libc_Setreuid setreuid "libc.so"
-//go:cgo_import_dynamic libc_Setrlimit setrlimit "libc.so"
-//go:cgo_import_dynamic libc_Setsid setsid "libc.so"
-//go:cgo_import_dynamic libc_Setuid setuid "libc.so"
-//go:cgo_import_dynamic libc_shutdown shutdown "libsocket.so"
-//go:cgo_import_dynamic libc_Stat stat "libc.so"
-//go:cgo_import_dynamic libc_Symlink symlink "libc.so"
-//go:cgo_import_dynamic libc_Sync sync "libc.so"
-//go:cgo_import_dynamic libc_Truncate truncate "libc.so"
-//go:cgo_import_dynamic libc_Fsync fsync "libc.so"
-//go:cgo_import_dynamic libc_Ftruncate ftruncate "libc.so"
-//go:cgo_import_dynamic libc_Umask umask "libc.so"
-//go:cgo_import_dynamic libc_Unlink unlink "libc.so"
-//go:cgo_import_dynamic libc_Utimes utimes "libc.so"
-//go:cgo_import_dynamic libc_bind bind "libsocket.so"
-//go:cgo_import_dynamic libc_connect connect "libsocket.so"
-//go:cgo_import_dynamic libc_mmap mmap "libc.so"
-//go:cgo_import_dynamic libc_munmap munmap "libc.so"
-//go:cgo_import_dynamic libc_sendto sendto "libsocket.so"
-//go:cgo_import_dynamic libc_socket socket "libsocket.so"
-//go:cgo_import_dynamic libc_socketpair socketpair "libsocket.so"
-//go:cgo_import_dynamic libc_write write "libc.so"
-//go:cgo_import_dynamic libc_getsockopt getsockopt "libsocket.so"
-//go:cgo_import_dynamic libc_getpeername getpeername "libsocket.so"
-//go:cgo_import_dynamic libc_getsockname getsockname "libsocket.so"
-//go:cgo_import_dynamic libc_setsockopt setsockopt "libsocket.so"
-//go:cgo_import_dynamic libc_recvfrom recvfrom "libsocket.so"
-//go:cgo_import_dynamic libc_recvmsg recvmsg "libsocket.so"
-
-//go:linkname libc_getgroups libc_getgroups
-//go:linkname libc_setgroups libc_setgroups
-//go:linkname libc_fcntl libc_fcntl
-//go:linkname libc_accept libc_accept
-//go:linkname libc_sendmsg libc_sendmsg
-//go:linkname libc_Access libc_Access
-//go:linkname libc_Adjtime libc_Adjtime
-//go:linkname libc_Chdir libc_Chdir
-//go:linkname libc_Chmod libc_Chmod
-//go:linkname libc_Chown libc_Chown
-//go:linkname libc_Chroot libc_Chroot
-//go:linkname libc_Close libc_Close
-//go:linkname libc_Dup libc_Dup
-//go:linkname libc_Exit libc_Exit
-//go:linkname libc_Fchdir libc_Fchdir
-//go:linkname libc_Fchmod libc_Fchmod
-//go:linkname libc_Fchown libc_Fchown
-//go:linkname libc_Fpathconf libc_Fpathconf
-//go:linkname libc_Fstat libc_Fstat
-//go:linkname libc_Getdents libc_Getdents
-//go:linkname libc_Getgid libc_Getgid
-//go:linkname libc_Getpid libc_Getpid
-//go:linkname libc_Geteuid libc_Geteuid
-//go:linkname libc_Getegid libc_Getegid
-//go:linkname libc_Getppid libc_Getppid
-//go:linkname libc_Getpriority libc_Getpriority
-//go:linkname libc_Getrlimit libc_Getrlimit
-//go:linkname libc_Gettimeofday libc_Gettimeofday
-//go:linkname libc_Getuid libc_Getuid
-//go:linkname libc_Kill libc_Kill
-//go:linkname libc_Lchown libc_Lchown
-//go:linkname libc_Link libc_Link
-//go:linkname libc_listen libc_listen
-//go:linkname libc_Lstat libc_Lstat
-//go:linkname libc_Mkdir libc_Mkdir
-//go:linkname libc_Mknod libc_Mknod
-//go:linkname libc_Nanosleep libc_Nanosleep
-//go:linkname libc_Open libc_Open
-//go:linkname libc_Pathconf libc_Pathconf
-//go:linkname libc_Pread libc_Pread
-//go:linkname libc_Pwrite libc_Pwrite
-//go:linkname libc_read libc_read
-//go:linkname libc_Readlink libc_Readlink
-//go:linkname libc_Rename libc_Rename
-//go:linkname libc_Rmdir libc_Rmdir
-//go:linkname libc_lseek libc_lseek
-//go:linkname libc_sendfile libc_sendfile
-//go:linkname libc_Setegid libc_Setegid
-//go:linkname libc_Seteuid libc_Seteuid
-//go:linkname libc_Setgid libc_Setgid
-//go:linkname libc_Setpgid libc_Setpgid
-//go:linkname libc_Setpriority libc_Setpriority
-//go:linkname libc_Setregid libc_Setregid
-//go:linkname libc_Setreuid libc_Setreuid
-//go:linkname libc_Setrlimit libc_Setrlimit
-//go:linkname libc_Setsid libc_Setsid
-//go:linkname libc_Setuid libc_Setuid
-//go:linkname libc_shutdown libc_shutdown
-//go:linkname libc_Stat libc_Stat
-//go:linkname libc_Symlink libc_Symlink
-//go:linkname libc_Sync libc_Sync
-//go:linkname libc_Truncate libc_Truncate
-//go:linkname libc_Fsync libc_Fsync
-//go:linkname libc_Ftruncate libc_Ftruncate
-//go:linkname libc_Umask libc_Umask
-//go:linkname libc_Unlink libc_Unlink
-//go:linkname libc_Utimes libc_Utimes
-//go:linkname libc_bind libc_bind
-//go:linkname libc_connect libc_connect
-//go:linkname libc_mmap libc_mmap
-//go:linkname libc_munmap libc_munmap
-//go:linkname libc_sendto libc_sendto
-//go:linkname libc_socket libc_socket
-//go:linkname libc_socketpair libc_socketpair
-//go:linkname libc_write libc_write
-//go:linkname libc_getsockopt libc_getsockopt
-//go:linkname libc_getpeername libc_getpeername
-//go:linkname libc_getsockname libc_getsockname
-//go:linkname libc_setsockopt libc_setsockopt
-//go:linkname libc_recvfrom libc_recvfrom
-//go:linkname libc_recvmsg libc_recvmsg
-
-type libcFunc uintptr
-
 var (
-	libc_getgroups,
-	libc_setgroups,
-	libc_fcntl,
-	libc_accept,
-	libc_sendmsg,
-	libc_Access,
-	libc_Adjtime,
-	libc_Chdir,
-	libc_Chmod,
-	libc_Chown,
-	libc_Chroot,
-	libc_Close,
-	libc_Dup,
-	libc_Exit,
-	libc_Fchdir,
-	libc_Fchmod,
-	libc_Fchown,
-	libc_Fpathconf,
-	libc_Fstat,
-	libc_Getdents,
-	libc_Getgid,
-	libc_Getpid,
-	libc_Geteuid,
-	libc_Getegid,
-	libc_Getppid,
-	libc_Getpriority,
-	libc_Getrlimit,
-	libc_Gettimeofday,
-	libc_Getuid,
-	libc_Kill,
-	libc_Lchown,
-	libc_Link,
-	libc_listen,
-	libc_Lstat,
-	libc_Mkdir,
-	libc_Mknod,
-	libc_Nanosleep,
-	libc_Open,
-	libc_Pathconf,
-	libc_Pread,
-	libc_Pwrite,
-	libc_read,
-	libc_Readlink,
-	libc_Rename,
-	libc_Rmdir,
-	libc_lseek,
-	libc_sendfile,
-	libc_Setegid,
-	libc_Seteuid,
-	libc_Setgid,
-	libc_Setpgid,
-	libc_Setpriority,
-	libc_Setregid,
-	libc_Setreuid,
-	libc_Setrlimit,
-	libc_Setsid,
-	libc_Setuid,
-	libc_shutdown,
-	libc_Stat,
-	libc_Symlink,
-	libc_Sync,
-	libc_Truncate,
-	libc_Fsync,
-	libc_Ftruncate,
-	libc_Umask,
-	libc_Unlink,
-	libc_Utimes,
-	libc_bind,
-	libc_connect,
-	libc_mmap,
-	libc_munmap,
-	libc_sendto,
-	libc_socket,
-	libc_socketpair,
-	libc_write,
-	libc_getsockopt,
-	libc_getpeername,
-	libc_getsockname,
-	libc_setsockopt,
-	libc_recvfrom,
-	libc_recvmsg libcFunc
+	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(uintptr(unsafe.Pointer(&libc_getgroups)), 2, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0, 0, 0, 0)
+	r0, _, e1 := rawSysvicall6(procgetgroups.Addr(), 2, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0, 0, 0, 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
 
 func setgroups(ngid int, gid *_Gid_t) (err error) {
-	_, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&libc_setgroups)), 2, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0, 0, 0, 0)
+	_, _, e1 := rawSysvicall6(procsetgroups.Addr(), 2, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0, 0, 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
 
 func fcntl(fd int, cmd int, arg int) (val int, err error) {
-	r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_fcntl)), 3, uintptr(fd), uintptr(cmd), uintptr(arg), 0, 0, 0)
+	r0, _, e1 := sysvicall6(procfcntl.Addr(), 3, uintptr(fd), uintptr(cmd), uintptr(arg), 0, 0, 0)
 	val = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
 
 func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
-	r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_accept)), 3, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), 0, 0, 0)
+	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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
 
 func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) {
-	r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_sendmsg)), 3, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags), 0, 0, 0)
+	r0, _, e1 := sysvicall6(procsendmsg.Addr(), 3, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags), 0, 0, 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -307,18 +141,18 @@ func Access(path string, mode uint32) (err error) {
 	if err != nil {
 		return
 	}
-	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Access)), 2, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(procAccess.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0, 0, 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
 
 func Adjtime(delta *Timeval, olddelta *Timeval) (err error) {
-	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Adjtime)), 2, uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(procAdjtime.Addr(), 2, uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0, 0, 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -329,10 +163,10 @@ func Chdir(path string) (err error) {
 	if err != nil {
 		return
 	}
-	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Chdir)), 1, uintptr(unsafe.Pointer(_p0)), 0, 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(procChdir.Addr(), 1, uintptr(unsafe.Pointer(_p0)), 0, 0, 0, 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -343,10 +177,10 @@ func Chmod(path string, mode uint32) (err error) {
 	if err != nil {
 		return
 	}
-	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Chmod)), 2, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(procChmod.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0, 0, 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -357,10 +191,10 @@ func Chown(path string, uid int, gid int) (err error) {
 	if err != nil {
 		return
 	}
-	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Chown)), 3, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid), 0, 0, 0)
+	_, _, e1 := sysvicall6(procChown.Addr(), 3, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid), 0, 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -371,73 +205,73 @@ func Chroot(path string) (err error) {
 	if err != nil {
 		return
 	}
-	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Chroot)), 1, uintptr(unsafe.Pointer(_p0)), 0, 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(procChroot.Addr(), 1, uintptr(unsafe.Pointer(_p0)), 0, 0, 0, 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
 
 func Close(fd int) (err error) {
-	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Close)), 1, uintptr(fd), 0, 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(procClose.Addr(), 1, uintptr(fd), 0, 0, 0, 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
 
 func Dup(fd int) (nfd int, err error) {
-	r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Dup)), 1, uintptr(fd), 0, 0, 0, 0, 0)
+	r0, _, e1 := sysvicall6(procDup.Addr(), 1, uintptr(fd), 0, 0, 0, 0, 0)
 	nfd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
 
 func Exit(code int) {
-	sysvicall6(uintptr(unsafe.Pointer(&libc_Exit)), 1, uintptr(code), 0, 0, 0, 0, 0)
+	sysvicall6(procExit.Addr(), 1, uintptr(code), 0, 0, 0, 0, 0)
 	return
 }
 
 func Fchdir(fd int) (err error) {
-	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Fchdir)), 1, uintptr(fd), 0, 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(procFchdir.Addr(), 1, uintptr(fd), 0, 0, 0, 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
 
 func Fchmod(fd int, mode uint32) (err error) {
-	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Fchmod)), 2, uintptr(fd), uintptr(mode), 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(procFchmod.Addr(), 2, uintptr(fd), uintptr(mode), 0, 0, 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
 
 func Fchown(fd int, uid int, gid int) (err error) {
-	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Fchown)), 3, uintptr(fd), uintptr(uid), uintptr(gid), 0, 0, 0)
+	_, _, e1 := sysvicall6(procFchown.Addr(), 3, uintptr(fd), uintptr(uid), uintptr(gid), 0, 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
 
 func Fpathconf(fd int, name int) (val int, err error) {
-	r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Fpathconf)), 2, uintptr(fd), uintptr(name), 0, 0, 0, 0)
+	r0, _, e1 := sysvicall6(procFpathconf.Addr(), 2, uintptr(fd), uintptr(name), 0, 0, 0, 0)
 	val = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
 
 func Fstat(fd int, stat *Stat_t) (err error) {
-	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Fstat)), 2, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(procFstat.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0, 0, 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -447,79 +281,79 @@ func Getdents(fd int, buf []byte, basep *uintptr) (n int, err error) {
 	if len(buf) > 0 {
 		_p0 = &buf[0]
 	}
-	r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Getdents)), 4, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
 
 func Getgid() (gid int) {
-	r0, _, _ := rawSysvicall6(uintptr(unsafe.Pointer(&libc_Getgid)), 0, 0, 0, 0, 0, 0, 0)
+	r0, _, _ := rawSysvicall6(procGetgid.Addr(), 0, 0, 0, 0, 0, 0, 0)
 	gid = int(r0)
 	return
 }
 
 func Getpid() (pid int) {
-	r0, _, _ := rawSysvicall6(uintptr(unsafe.Pointer(&libc_Getpid)), 0, 0, 0, 0, 0, 0, 0)
+	r0, _, _ := rawSysvicall6(procGetpid.Addr(), 0, 0, 0, 0, 0, 0, 0)
 	pid = int(r0)
 	return
 }
 
 func Geteuid() (euid int) {
-	r0, _, _ := sysvicall6(uintptr(unsafe.Pointer(&libc_Geteuid)), 0, 0, 0, 0, 0, 0, 0)
+	r0, _, _ := sysvicall6(procGeteuid.Addr(), 0, 0, 0, 0, 0, 0, 0)
 	euid = int(r0)
 	return
 }
 
 func Getegid() (egid int) {
-	r0, _, _ := sysvicall6(uintptr(unsafe.Pointer(&libc_Getegid)), 0, 0, 0, 0, 0, 0, 0)
+	r0, _, _ := sysvicall6(procGetegid.Addr(), 0, 0, 0, 0, 0, 0, 0)
 	egid = int(r0)
 	return
 }
 
 func Getppid() (ppid int) {
-	r0, _, _ := sysvicall6(uintptr(unsafe.Pointer(&libc_Getppid)), 0, 0, 0, 0, 0, 0, 0)
+	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(uintptr(unsafe.Pointer(&libc_Getpriority)), 2, uintptr(which), uintptr(who), 0, 0, 0, 0)
+	r0, _, e1 := sysvicall6(procGetpriority.Addr(), 2, uintptr(which), uintptr(who), 0, 0, 0, 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
 
 func Getrlimit(which int, lim *Rlimit) (err error) {
-	_, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&libc_Getrlimit)), 2, uintptr(which), uintptr(unsafe.Pointer(lim)), 0, 0, 0, 0)
+	_, _, e1 := rawSysvicall6(procGetrlimit.Addr(), 2, uintptr(which), uintptr(unsafe.Pointer(lim)), 0, 0, 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
 
 func Gettimeofday(tv *Timeval) (err error) {
-	_, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&libc_Gettimeofday)), 1, uintptr(unsafe.Pointer(tv)), 0, 0, 0, 0, 0)
+	_, _, e1 := rawSysvicall6(procGettimeofday.Addr(), 1, uintptr(unsafe.Pointer(tv)), 0, 0, 0, 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
 
 func Getuid() (uid int) {
-	r0, _, _ := rawSysvicall6(uintptr(unsafe.Pointer(&libc_Getuid)), 0, 0, 0, 0, 0, 0, 0)
+	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(uintptr(unsafe.Pointer(&libc_Kill)), 2, uintptr(pid), uintptr(signum), 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(procKill.Addr(), 2, uintptr(pid), uintptr(signum), 0, 0, 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -530,10 +364,10 @@ func Lchown(path string, uid int, gid int) (err error) {
 	if err != nil {
 		return
 	}
-	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Lchown)), 3, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid), 0, 0, 0)
+	_, _, e1 := sysvicall6(procLchown.Addr(), 3, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid), 0, 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -549,19 +383,19 @@ func Link(path string, link string) (err error) {
 	if err != nil {
 		return
 	}
-	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Link)), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(procLink.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0, 0, 0, 0)
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
 
 func Listen(s int, backlog int) (err error) {
-	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_listen)), 2, uintptr(s), uintptr(backlog), 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(proclisten.Addr(), 2, uintptr(s), uintptr(backlog), 0, 0, 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -572,10 +406,10 @@ func Lstat(path string, stat *Stat_t) (err error) {
 	if err != nil {
 		return
 	}
-	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Lstat)), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(procLstat.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0, 0, 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -586,10 +420,10 @@ func Mkdir(path string, mode uint32) (err error) {
 	if err != nil {
 		return
 	}
-	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Mkdir)), 2, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(procMkdir.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0, 0, 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -600,18 +434,18 @@ func Mknod(path string, mode uint32, dev int) (err error) {
 	if err != nil {
 		return
 	}
-	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Mknod)), 3, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev), 0, 0, 0)
+	_, _, e1 := sysvicall6(procMknod.Addr(), 3, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev), 0, 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
 
 func Nanosleep(time *Timespec, leftover *Timespec) (err error) {
-	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Nanosleep)), 2, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(procNanosleep.Addr(), 2, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0, 0, 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -622,11 +456,11 @@ func Open(path string, mode int, perm uint32) (fd int, err error) {
 	if err != nil {
 		return
 	}
-	r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Open)), 3, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm), 0, 0, 0)
+	r0, _, e1 := sysvicall6(procOpen.Addr(), 3, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm), 0, 0, 0)
 	use(unsafe.Pointer(_p0))
 	fd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -637,11 +471,11 @@ func Pathconf(path string, name int) (val int, err error) {
 	if err != nil {
 		return
 	}
-	r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Pathconf)), 2, uintptr(unsafe.Pointer(_p0)), uintptr(name), 0, 0, 0, 0)
+	r0, _, e1 := sysvicall6(procPathconf.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(name), 0, 0, 0, 0)
 	use(unsafe.Pointer(_p0))
 	val = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -651,10 +485,10 @@ func Pread(fd int, p []byte, offset int64) (n int, err error) {
 	if len(p) > 0 {
 		_p0 = &p[0]
 	}
-	r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Pread)), 4, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), uintptr(offset), 0, 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -664,10 +498,10 @@ func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
 	if len(p) > 0 {
 		_p0 = &p[0]
 	}
-	r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Pwrite)), 4, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), uintptr(offset), 0, 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -677,10 +511,10 @@ func read(fd int, p []byte) (n int, err error) {
 	if len(p) > 0 {
 		_p0 = &p[0]
 	}
-	r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_read)), 3, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), 0, 0, 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -695,11 +529,11 @@ func Readlink(path string, buf []byte) (n int, err error) {
 	if len(buf) > 0 {
 		_p1 = &buf[0]
 	}
-	r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Readlink)), 3, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(len(buf)), 0, 0, 0)
+	r0, _, e1 := sysvicall6(procReadlink.Addr(), 3, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(len(buf)), 0, 0, 0)
 	use(unsafe.Pointer(_p0))
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -715,11 +549,11 @@ func Rename(from string, to string) (err error) {
 	if err != nil {
 		return
 	}
-	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Rename)), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(procRename.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0, 0, 0, 0)
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -730,117 +564,108 @@ func Rmdir(path string) (err error) {
 	if err != nil {
 		return
 	}
-	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Rmdir)), 1, uintptr(unsafe.Pointer(_p0)), 0, 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(procRmdir.Addr(), 1, uintptr(unsafe.Pointer(_p0)), 0, 0, 0, 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
 
 func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
-	r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_lseek)), 3, uintptr(fd), uintptr(offset), uintptr(whence), 0, 0, 0)
+	r0, _, e1 := sysvicall6(proclseek.Addr(), 3, uintptr(fd), uintptr(offset), uintptr(whence), 0, 0, 0)
 	newoffset = int64(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
-	}
-	return
-}
-
-func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
-	r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_sendfile)), 4, uintptr(outfd), uintptr(infd), uintptr(unsafe.Pointer(offset)), uintptr(count), 0, 0)
-	written = int(r0)
-	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
 
 func Setegid(egid int) (err error) {
-	_, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&libc_Setegid)), 1, uintptr(egid), 0, 0, 0, 0, 0)
+	_, _, e1 := rawSysvicall6(procSetegid.Addr(), 1, uintptr(egid), 0, 0, 0, 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
 
 func Seteuid(euid int) (err error) {
-	_, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&libc_Seteuid)), 1, uintptr(euid), 0, 0, 0, 0, 0)
+	_, _, e1 := rawSysvicall6(procSeteuid.Addr(), 1, uintptr(euid), 0, 0, 0, 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
 
 func Setgid(gid int) (err error) {
-	_, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&libc_Setgid)), 1, uintptr(gid), 0, 0, 0, 0, 0)
+	_, _, e1 := rawSysvicall6(procSetgid.Addr(), 1, uintptr(gid), 0, 0, 0, 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
 
 func Setpgid(pid int, pgid int) (err error) {
-	_, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&libc_Setpgid)), 2, uintptr(pid), uintptr(pgid), 0, 0, 0, 0)
+	_, _, e1 := rawSysvicall6(procSetpgid.Addr(), 2, uintptr(pid), uintptr(pgid), 0, 0, 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
 
 func Setpriority(which int, who int, prio int) (err error) {
-	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Setpriority)), 3, uintptr(which), uintptr(who), uintptr(prio), 0, 0, 0)
+	_, _, e1 := sysvicall6(procSetpriority.Addr(), 3, uintptr(which), uintptr(who), uintptr(prio), 0, 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
 
 func Setregid(rgid int, egid int) (err error) {
-	_, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&libc_Setregid)), 2, uintptr(rgid), uintptr(egid), 0, 0, 0, 0)
+	_, _, e1 := rawSysvicall6(procSetregid.Addr(), 2, uintptr(rgid), uintptr(egid), 0, 0, 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
 
 func Setreuid(ruid int, euid int) (err error) {
-	_, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&libc_Setreuid)), 2, uintptr(ruid), uintptr(euid), 0, 0, 0, 0)
+	_, _, e1 := rawSysvicall6(procSetreuid.Addr(), 2, uintptr(ruid), uintptr(euid), 0, 0, 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
 
 func Setrlimit(which int, lim *Rlimit) (err error) {
-	_, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&libc_Setrlimit)), 2, uintptr(which), uintptr(unsafe.Pointer(lim)), 0, 0, 0, 0)
+	_, _, e1 := rawSysvicall6(procSetrlimit.Addr(), 2, uintptr(which), uintptr(unsafe.Pointer(lim)), 0, 0, 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
 
 func Setsid() (pid int, err error) {
-	r0, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&libc_Setsid)), 0, 0, 0, 0, 0, 0, 0)
+	r0, _, e1 := rawSysvicall6(procSetsid.Addr(), 0, 0, 0, 0, 0, 0, 0)
 	pid = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
 
 func Setuid(uid int) (err error) {
-	_, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&libc_Setuid)), 1, uintptr(uid), 0, 0, 0, 0, 0)
+	_, _, e1 := rawSysvicall6(procSetuid.Addr(), 1, uintptr(uid), 0, 0, 0, 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
 
 func Shutdown(s int, how int) (err error) {
-	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_shutdown)), 2, uintptr(s), uintptr(how), 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(procshutdown.Addr(), 2, uintptr(s), uintptr(how), 0, 0, 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -851,10 +676,10 @@ func Stat(path string, stat *Stat_t) (err error) {
 	if err != nil {
 		return
 	}
-	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Stat)), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(procStat.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0, 0, 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -870,19 +695,19 @@ func Symlink(path string, link string) (err error) {
 	if err != nil {
 		return
 	}
-	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Symlink)), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(procSymlink.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0, 0, 0, 0)
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
 
 func Sync() (err error) {
-	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Sync)), 0, 0, 0, 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(procSync.Addr(), 0, 0, 0, 0, 0, 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -893,32 +718,32 @@ func Truncate(path string, length int64) (err error) {
 	if err != nil {
 		return
 	}
-	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Truncate)), 2, uintptr(unsafe.Pointer(_p0)), uintptr(length), 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(procTruncate.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(length), 0, 0, 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
 
 func Fsync(fd int) (err error) {
-	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Fsync)), 1, uintptr(fd), 0, 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(procFsync.Addr(), 1, uintptr(fd), 0, 0, 0, 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
 
 func Ftruncate(fd int, length int64) (err error) {
-	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Ftruncate)), 2, uintptr(fd), uintptr(length), 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(procFtruncate.Addr(), 2, uintptr(fd), uintptr(length), 0, 0, 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
 
 func Umask(newmask int) (oldmask int) {
-	r0, _, _ := sysvicall6(uintptr(unsafe.Pointer(&libc_Umask)), 1, uintptr(newmask), 0, 0, 0, 0, 0)
+	r0, _, _ := sysvicall6(procUmask.Addr(), 1, uintptr(newmask), 0, 0, 0, 0, 0)
 	oldmask = int(r0)
 	return
 }
@@ -929,10 +754,10 @@ func Unlink(path string) (err error) {
 	if err != nil {
 		return
 	}
-	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Unlink)), 1, uintptr(unsafe.Pointer(_p0)), 0, 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(procUnlink.Addr(), 1, uintptr(unsafe.Pointer(_p0)), 0, 0, 0, 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -943,43 +768,43 @@ func Utimes(path string, times *[2]Timeval) (err error) {
 	if err != nil {
 		return
 	}
-	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Utimes)), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(procUtimes.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0, 0, 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
 
 func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
-	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_bind)), 3, uintptr(s), uintptr(addr), uintptr(addrlen), 0, 0, 0)
+	_, _, e1 := sysvicall6(procbind.Addr(), 3, uintptr(s), uintptr(addr), uintptr(addrlen), 0, 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
 
 func connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
-	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_connect)), 3, uintptr(s), uintptr(addr), uintptr(addrlen), 0, 0, 0)
+	_, _, e1 := sysvicall6(procconnect.Addr(), 3, uintptr(s), uintptr(addr), uintptr(addrlen), 0, 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
 
 func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error) {
-	r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_mmap)), 6, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flag), uintptr(fd), uintptr(pos))
+	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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
 
 func munmap(addr uintptr, length uintptr) (err error) {
-	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_munmap)), 2, uintptr(addr), uintptr(length), 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(procmunmap.Addr(), 2, uintptr(addr), uintptr(length), 0, 0, 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -989,26 +814,26 @@ func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (
 	if len(buf) > 0 {
 		_p0 = &buf[0]
 	}
-	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_sendto)), 6, uintptr(s), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
+	_, _, e1 := sysvicall6(procsendto.Addr(), 6, uintptr(s), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
 
 func socket(domain int, typ int, proto int) (fd int, err error) {
-	r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_socket)), 3, uintptr(domain), uintptr(typ), uintptr(proto), 0, 0, 0)
+	r0, _, e1 := sysvicall6(procsocket.Addr(), 3, uintptr(domain), uintptr(typ), uintptr(proto), 0, 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
 
 func socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) {
-	_, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&libc_socketpair)), 4, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0)
+	_, _, e1 := rawSysvicall6(procsocketpair.Addr(), 4, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1018,42 +843,42 @@ func write(fd int, p []byte) (n int, err error) {
 	if len(p) > 0 {
 		_p0 = &p[0]
 	}
-	r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_write)), 3, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), 0, 0, 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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
 
 func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) {
-	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_getsockopt)), 5, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
+	_, _, e1 := sysvicall6(procgetsockopt.Addr(), 5, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
 
 func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
-	_, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&libc_getpeername)), 3, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), 0, 0, 0)
+	_, _, e1 := rawSysvicall6(procgetpeername.Addr(), 3, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), 0, 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
 
 func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
-	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_getsockname)), 3, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), 0, 0, 0)
+	_, _, e1 := sysvicall6(procgetsockname.Addr(), 3, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), 0, 0, 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
 
 func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
-	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_setsockopt)), 5, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
+	_, _, e1 := sysvicall6(procsetsockopt.Addr(), 5, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
@@ -1063,19 +888,19 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
 	if len(p) > 0 {
 		_p0 = &p[0]
 	}
-	r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_recvfrom)), 6, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), uintptr(flags), uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(fromlen)))
+	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 = errnoErr(e1)
+		err = e1
 	}
 	return
 }
 
 func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
-	r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_recvmsg)), 3, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags), 0, 0, 0)
+	r0, _, e1 := sysvicall6(procrecvmsg.Addr(), 3, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags), 0, 0, 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = errnoErr(e1)
+		err = e1
 	}
 	return
 }
diff --git a/src/syscall/zsyscall_windows.go b/src/syscall/zsyscall_windows.go
index 7879ba1..afc28f9 100644
--- a/src/syscall/zsyscall_windows.go
+++ b/src/syscall/zsyscall_windows.go
@@ -1,11 +1,10 @@
-// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT
+// go build mksyscall_windows.go && ./mksyscall_windows syscall_windows.go security_windows.go
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
 package syscall
 
 import "unsafe"
 
-var _ unsafe.Pointer
-
 var (
 	modkernel32 = NewLazyDLL("kernel32.dll")
 	modadvapi32 = NewLazyDLL("advapi32.dll")
@@ -240,7 +239,7 @@ func GetVersion() (ver uint32, err error) {
 	return
 }
 
-func formatMessage(flags uint32, msgsrc uintptr, msgid uint32, langid uint32, buf []uint16, args *byte) (n uint32, err error) {
+func FormatMessage(flags uint32, msgsrc uint32, msgid uint32, langid uint32, buf []uint16, args *byte) (n uint32, err error) {
 	var _p0 *uint16
 	if len(buf) > 0 {
 		_p0 = &buf[0]
diff --git a/src/syscall/zsysnum_darwin_386.go b/src/syscall/zsysnum_darwin_386.go
index c6f8342..abdef77 100644
--- a/src/syscall/zsysnum_darwin_386.go
+++ b/src/syscall/zsysnum_darwin_386.go
@@ -1,8 +1,6 @@
 // mksysnum_darwin.pl /usr/include/sys/syscall.h
 // MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
 
-// +build 386,darwin
-
 package syscall
 
 const (
diff --git a/src/syscall/zsysnum_darwin_amd64.go b/src/syscall/zsysnum_darwin_amd64.go
index 7189abe..abdef77 100644
--- a/src/syscall/zsysnum_darwin_amd64.go
+++ b/src/syscall/zsysnum_darwin_amd64.go
@@ -1,8 +1,6 @@
 // mksysnum_darwin.pl /usr/include/sys/syscall.h
 // MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
 
-// +build amd64,darwin
-
 package syscall
 
 const (
diff --git a/src/syscall/zsysnum_dragonfly_386.go b/src/syscall/zsysnum_dragonfly_386.go
new file mode 100644
index 0000000..4b086b9
--- /dev/null
+++ b/src/syscall/zsysnum_dragonfly_386.go
@@ -0,0 +1,302 @@
+// mksysnum_dragonfly.pl
+// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
+
+package syscall
+
+const (
+	// SYS_NOSYS = 0;  // { int nosys(void); } syscall nosys_args int
+	SYS_EXIT          = 1   // { void exit(int rval); }
+	SYS_FORK          = 2   // { int fork(void); }
+	SYS_READ          = 3   // { ssize_t read(int fd, void *buf, size_t nbyte); }
+	SYS_WRITE         = 4   // { ssize_t write(int fd, const void *buf, size_t nbyte); }
+	SYS_OPEN          = 5   // { int open(char *path, int flags, int mode); }
+	SYS_CLOSE         = 6   // { int close(int fd); }
+	SYS_WAIT4         = 7   // { int wait4(int pid, int *status, int options, \
+	SYS_LINK          = 9   // { int link(char *path, char *link); }
+	SYS_UNLINK        = 10  // { int unlink(char *path); }
+	SYS_CHDIR         = 12  // { int chdir(char *path); }
+	SYS_FCHDIR        = 13  // { int fchdir(int fd); }
+	SYS_MKNOD         = 14  // { int mknod(char *path, int mode, int dev); }
+	SYS_CHMOD         = 15  // { int chmod(char *path, int mode); }
+	SYS_CHOWN         = 16  // { int chown(char *path, int uid, int gid); }
+	SYS_OBREAK        = 17  // { int obreak(char *nsize); } break obreak_args int
+	SYS_GETFSSTAT     = 18  // { int getfsstat(struct statfs *buf, long bufsize, \
+	SYS_GETPID        = 20  // { pid_t getpid(void); }
+	SYS_MOUNT         = 21  // { int mount(char *type, char *path, int flags, \
+	SYS_UNMOUNT       = 22  // { int unmount(char *path, int flags); }
+	SYS_SETUID        = 23  // { int setuid(uid_t uid); }
+	SYS_GETUID        = 24  // { uid_t getuid(void); }
+	SYS_GETEUID       = 25  // { uid_t geteuid(void); }
+	SYS_PTRACE        = 26  // { int ptrace(int req, pid_t pid, caddr_t addr, \
+	SYS_RECVMSG       = 27  // { int recvmsg(int s, struct msghdr *msg, int flags); }
+	SYS_SENDMSG       = 28  // { int sendmsg(int s, caddr_t msg, int flags); }
+	SYS_RECVFROM      = 29  // { int recvfrom(int s, caddr_t buf, size_t len, \
+	SYS_ACCEPT        = 30  // { int accept(int s, caddr_t name, int *anamelen); }
+	SYS_GETPEERNAME   = 31  // { int getpeername(int fdes, caddr_t asa, int *alen); }
+	SYS_GETSOCKNAME   = 32  // { int getsockname(int fdes, caddr_t asa, int *alen); }
+	SYS_ACCESS        = 33  // { int access(char *path, int flags); }
+	SYS_CHFLAGS       = 34  // { int chflags(char *path, int flags); }
+	SYS_FCHFLAGS      = 35  // { int fchflags(int fd, int flags); }
+	SYS_SYNC          = 36  // { int sync(void); }
+	SYS_KILL          = 37  // { int kill(int pid, int signum); }
+	SYS_GETPPID       = 39  // { pid_t getppid(void); }
+	SYS_DUP           = 41  // { int dup(u_int fd); }
+	SYS_PIPE          = 42  // { int pipe(void); }
+	SYS_GETEGID       = 43  // { gid_t getegid(void); }
+	SYS_PROFIL        = 44  // { int profil(caddr_t samples, size_t size, \
+	SYS_KTRACE        = 45  // { int ktrace(const char *fname, int ops, int facs, \
+	SYS_GETGID        = 47  // { gid_t getgid(void); }
+	SYS_GETLOGIN      = 49  // { int getlogin(char *namebuf, u_int namelen); }
+	SYS_SETLOGIN      = 50  // { int setlogin(char *namebuf); }
+	SYS_ACCT          = 51  // { int acct(char *path); }
+	SYS_SIGALTSTACK   = 53  // { int sigaltstack(stack_t *ss, stack_t *oss); }
+	SYS_IOCTL         = 54  // { int ioctl(int fd, u_long com, caddr_t data); }
+	SYS_REBOOT        = 55  // { int reboot(int opt); }
+	SYS_REVOKE        = 56  // { int revoke(char *path); }
+	SYS_SYMLINK       = 57  // { int symlink(char *path, char *link); }
+	SYS_READLINK      = 58  // { int readlink(char *path, char *buf, int count); }
+	SYS_EXECVE        = 59  // { int execve(char *fname, char **argv, char **envv); }
+	SYS_UMASK         = 60  // { int umask(int newmask); } umask umask_args int
+	SYS_CHROOT        = 61  // { int chroot(char *path); }
+	SYS_MSYNC         = 65  // { int msync(void *addr, size_t len, int flags); }
+	SYS_VFORK         = 66  // { pid_t vfork(void); }
+	SYS_SBRK          = 69  // { int sbrk(int incr); }
+	SYS_SSTK          = 70  // { int sstk(int incr); }
+	SYS_MUNMAP        = 73  // { int munmap(void *addr, size_t len); }
+	SYS_MPROTECT      = 74  // { int mprotect(void *addr, size_t len, int prot); }
+	SYS_MADVISE       = 75  // { int madvise(void *addr, size_t len, int behav); }
+	SYS_MINCORE       = 78  // { int mincore(const void *addr, size_t len, \
+	SYS_GETGROUPS     = 79  // { int getgroups(u_int gidsetsize, gid_t *gidset); }
+	SYS_SETGROUPS     = 80  // { int setgroups(u_int gidsetsize, gid_t *gidset); }
+	SYS_GETPGRP       = 81  // { int getpgrp(void); }
+	SYS_SETPGID       = 82  // { int setpgid(int pid, int pgid); }
+	SYS_SETITIMER     = 83  // { int setitimer(u_int which, struct itimerval *itv, \
+	SYS_SWAPON        = 85  // { int swapon(char *name); }
+	SYS_GETITIMER     = 86  // { int getitimer(u_int which, struct itimerval *itv); }
+	SYS_GETDTABLESIZE = 89  // { int getdtablesize(void); }
+	SYS_DUP2          = 90  // { int dup2(u_int from, u_int to); }
+	SYS_FCNTL         = 92  // { int fcntl(int fd, int cmd, long arg); }
+	SYS_SELECT        = 93  // { int select(int nd, fd_set *in, fd_set *ou, \
+	SYS_FSYNC         = 95  // { int fsync(int fd); }
+	SYS_SETPRIORITY   = 96  // { int setpriority(int which, int who, int prio); }
+	SYS_SOCKET        = 97  // { int socket(int domain, int type, int protocol); }
+	SYS_CONNECT       = 98  // { int connect(int s, caddr_t name, int namelen); }
+	SYS_GETPRIORITY   = 100 // { int getpriority(int which, int who); }
+	SYS_BIND          = 104 // { int bind(int s, caddr_t name, int namelen); }
+	SYS_SETSOCKOPT    = 105 // { int setsockopt(int s, int level, int name, \
+	SYS_LISTEN        = 106 // { int listen(int s, int backlog); }
+	SYS_GETTIMEOFDAY  = 116 // { int gettimeofday(struct timeval *tp, \
+	SYS_GETRUSAGE     = 117 // { int getrusage(int who, struct rusage *rusage); }
+	SYS_GETSOCKOPT    = 118 // { int getsockopt(int s, int level, int name, \
+	SYS_READV         = 120 // { int readv(int fd, struct iovec *iovp, u_int iovcnt); }
+	SYS_WRITEV        = 121 // { int writev(int fd, struct iovec *iovp, \
+	SYS_SETTIMEOFDAY  = 122 // { int settimeofday(struct timeval *tv, \
+	SYS_FCHOWN        = 123 // { int fchown(int fd, int uid, int gid); }
+	SYS_FCHMOD        = 124 // { int fchmod(int fd, int mode); }
+	SYS_SETREUID      = 126 // { int setreuid(int ruid, int euid); }
+	SYS_SETREGID      = 127 // { int setregid(int rgid, int egid); }
+	SYS_RENAME        = 128 // { int rename(char *from, char *to); }
+	SYS_FLOCK         = 131 // { int flock(int fd, int how); }
+	SYS_MKFIFO        = 132 // { int mkfifo(char *path, int mode); }
+	SYS_SENDTO        = 133 // { int sendto(int s, caddr_t buf, size_t len, \
+	SYS_SHUTDOWN      = 134 // { int shutdown(int s, int how); }
+	SYS_SOCKETPAIR    = 135 // { int socketpair(int domain, int type, int protocol, \
+	SYS_MKDIR         = 136 // { int mkdir(char *path, int mode); }
+	SYS_RMDIR         = 137 // { int rmdir(char *path); }
+	SYS_UTIMES        = 138 // { int utimes(char *path, struct timeval *tptr); }
+	SYS_ADJTIME       = 140 // { int adjtime(struct timeval *delta, \
+	SYS_SETSID        = 147 // { int setsid(void); }
+	SYS_QUOTACTL      = 148 // { int quotactl(char *path, int cmd, int uid, \
+	SYS_STATFS        = 157 // { int statfs(char *path, struct statfs *buf); }
+	SYS_FSTATFS       = 158 // { int fstatfs(int fd, struct statfs *buf); }
+	SYS_GETFH         = 161 // { int getfh(char *fname, struct fhandle *fhp); }
+	SYS_GETDOMAINNAME = 162 // { int getdomainname(char *domainname, int len); }
+	SYS_SETDOMAINNAME = 163 // { int setdomainname(char *domainname, int len); }
+	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_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); }
+	SYS_SETGID        = 181 // { int setgid(gid_t gid); }
+	SYS_SETEGID       = 182 // { int setegid(gid_t egid); }
+	SYS_SETEUID       = 183 // { int seteuid(uid_t euid); }
+	SYS_PATHCONF      = 191 // { int pathconf(char *path, int name); }
+	SYS_FPATHCONF     = 192 // { int fpathconf(int fd, int name); }
+	SYS_GETRLIMIT     = 194 // { int getrlimit(u_int which, \
+	SYS_SETRLIMIT     = 195 // { int setrlimit(u_int which, \
+	SYS_MMAP          = 197 // { caddr_t mmap(caddr_t addr, size_t len, int prot, \
+	// SYS_NOSYS = 198;  // { int nosys(void); } __syscall __syscall_args int
+	SYS_LSEEK                  = 199 // { off_t lseek(int fd, int pad, off_t offset, \
+	SYS_TRUNCATE               = 200 // { int truncate(char *path, int pad, off_t length); }
+	SYS_FTRUNCATE              = 201 // { int ftruncate(int fd, int pad, off_t length); }
+	SYS___SYSCTL               = 202 // { int __sysctl(int *name, u_int namelen, void *old, \
+	SYS_MLOCK                  = 203 // { int mlock(const void *addr, size_t len); }
+	SYS_MUNLOCK                = 204 // { int munlock(const void *addr, size_t len); }
+	SYS_UNDELETE               = 205 // { int undelete(char *path); }
+	SYS_FUTIMES                = 206 // { int futimes(int fd, struct timeval *tptr); }
+	SYS_GETPGID                = 207 // { int getpgid(pid_t pid); }
+	SYS_POLL                   = 209 // { int poll(struct pollfd *fds, u_int nfds, \
+	SYS___SEMCTL               = 220 // { int __semctl(int semid, int semnum, int cmd, \
+	SYS_SEMGET                 = 221 // { int semget(key_t key, int nsems, int semflg); }
+	SYS_SEMOP                  = 222 // { int semop(int semid, struct sembuf *sops, \
+	SYS_MSGCTL                 = 224 // { int msgctl(int msqid, int cmd, \
+	SYS_MSGGET                 = 225 // { int msgget(key_t key, int msgflg); }
+	SYS_MSGSND                 = 226 // { int msgsnd(int msqid, void *msgp, size_t msgsz, \
+	SYS_MSGRCV                 = 227 // { int msgrcv(int msqid, void *msgp, size_t msgsz, \
+	SYS_SHMAT                  = 228 // { caddr_t shmat(int shmid, const void *shmaddr, \
+	SYS_SHMCTL                 = 229 // { int shmctl(int shmid, int cmd, \
+	SYS_SHMDT                  = 230 // { int shmdt(const void *shmaddr); }
+	SYS_SHMGET                 = 231 // { int shmget(key_t key, size_t size, int shmflg); }
+	SYS_CLOCK_GETTIME          = 232 // { int clock_gettime(clockid_t clock_id, \
+	SYS_CLOCK_SETTIME          = 233 // { int clock_settime(clockid_t clock_id, \
+	SYS_CLOCK_GETRES           = 234 // { int clock_getres(clockid_t clock_id, \
+	SYS_NANOSLEEP              = 240 // { int nanosleep(const struct timespec *rqtp, \
+	SYS_MINHERIT               = 250 // { int minherit(void *addr, size_t len, int inherit); }
+	SYS_RFORK                  = 251 // { int rfork(int flags); }
+	SYS_OPENBSD_POLL           = 252 // { int openbsd_poll(struct pollfd *fds, u_int nfds, \
+	SYS_ISSETUGID              = 253 // { int issetugid(void); }
+	SYS_LCHOWN                 = 254 // { int lchown(char *path, int uid, int gid); }
+	SYS_LCHMOD                 = 274 // { int lchmod(char *path, mode_t mode); }
+	SYS_LUTIMES                = 276 // { int lutimes(char *path, struct timeval *tptr); }
+	SYS_EXTPREADV              = 289 // { ssize_t extpreadv(int fd, struct iovec *iovp, \
+	SYS_EXTPWRITEV             = 290 // { ssize_t extpwritev(int fd, struct iovec *iovp,\
+	SYS_FHSTATFS               = 297 // { int fhstatfs(const struct fhandle *u_fhp, struct statfs *buf); }
+	SYS_FHOPEN                 = 298 // { int fhopen(const struct fhandle *u_fhp, int flags); }
+	SYS_MODNEXT                = 300 // { int modnext(int modid); }
+	SYS_MODSTAT                = 301 // { int modstat(int modid, struct module_stat* stat); }
+	SYS_MODFNEXT               = 302 // { int modfnext(int modid); }
+	SYS_MODFIND                = 303 // { int modfind(const char *name); }
+	SYS_KLDLOAD                = 304 // { int kldload(const char *file); }
+	SYS_KLDUNLOAD              = 305 // { int kldunload(int fileid); }
+	SYS_KLDFIND                = 306 // { int kldfind(const char *file); }
+	SYS_KLDNEXT                = 307 // { int kldnext(int fileid); }
+	SYS_KLDSTAT                = 308 // { int kldstat(int fileid, struct kld_file_stat* stat); }
+	SYS_KLDFIRSTMOD            = 309 // { int kldfirstmod(int fileid); }
+	SYS_GETSID                 = 310 // { int getsid(pid_t pid); }
+	SYS_SETRESUID              = 311 // { int setresuid(uid_t ruid, uid_t euid, uid_t suid); }
+	SYS_SETRESGID              = 312 // { int setresgid(gid_t rgid, gid_t egid, gid_t sgid); }
+	SYS_AIO_RETURN             = 314 // { int aio_return(struct aiocb *aiocbp); }
+	SYS_AIO_SUSPEND            = 315 // { int aio_suspend(struct aiocb * const * aiocbp, int nent, const struct timespec *timeout); }
+	SYS_AIO_CANCEL             = 316 // { int aio_cancel(int fd, struct aiocb *aiocbp); }
+	SYS_AIO_ERROR              = 317 // { int aio_error(struct aiocb *aiocbp); }
+	SYS_AIO_READ               = 318 // { int aio_read(struct aiocb *aiocbp); }
+	SYS_AIO_WRITE              = 319 // { int aio_write(struct aiocb *aiocbp); }
+	SYS_LIO_LISTIO             = 320 // { int lio_listio(int mode, struct aiocb * const *acb_list, int nent, struct sigevent *sig); }
+	SYS_YIELD                  = 321 // { int yield(void); }
+	SYS_MLOCKALL               = 324 // { int mlockall(int how); }
+	SYS_MUNLOCKALL             = 325 // { int munlockall(void); }
+	SYS___GETCWD               = 326 // { int __getcwd(u_char *buf, u_int buflen); }
+	SYS_SCHED_SETPARAM         = 327 // { int sched_setparam (pid_t pid, const struct sched_param *param); }
+	SYS_SCHED_GETPARAM         = 328 // { int sched_getparam (pid_t pid, struct sched_param *param); }
+	SYS_SCHED_SETSCHEDULER     = 329 // { int sched_setscheduler (pid_t pid, int policy, const struct sched_param *param); }
+	SYS_SCHED_GETSCHEDULER     = 330 // { int sched_getscheduler (pid_t pid); }
+	SYS_SCHED_YIELD            = 331 // { int sched_yield (void); }
+	SYS_SCHED_GET_PRIORITY_MAX = 332 // { int sched_get_priority_max (int policy); }
+	SYS_SCHED_GET_PRIORITY_MIN = 333 // { int sched_get_priority_min (int policy); }
+	SYS_SCHED_RR_GET_INTERVAL  = 334 // { int sched_rr_get_interval (pid_t pid, struct timespec *interval); }
+	SYS_UTRACE                 = 335 // { int utrace(const void *addr, size_t len); }
+	SYS_KLDSYM                 = 337 // { int kldsym(int fileid, int cmd, void *data); }
+	SYS_JAIL                   = 338 // { int jail(struct jail *jail); }
+	SYS_SIGPROCMASK            = 340 // { int sigprocmask(int how, const sigset_t *set, \
+	SYS_SIGSUSPEND             = 341 // { int sigsuspend(const sigset_t *sigmask); }
+	SYS_SIGACTION              = 342 // { int sigaction(int sig, const struct sigaction *act, \
+	SYS_SIGPENDING             = 343 // { int sigpending(sigset_t *set); }
+	SYS_SIGRETURN              = 344 // { int sigreturn(ucontext_t *sigcntxp); }
+	SYS_SIGTIMEDWAIT           = 345 // { int sigtimedwait(const sigset_t *set,\
+	SYS_SIGWAITINFO            = 346 // { int sigwaitinfo(const sigset_t *set,\
+	SYS___ACL_GET_FILE         = 347 // { int __acl_get_file(const char *path, \
+	SYS___ACL_SET_FILE         = 348 // { int __acl_set_file(const char *path, \
+	SYS___ACL_GET_FD           = 349 // { int __acl_get_fd(int filedes, acl_type_t type, \
+	SYS___ACL_SET_FD           = 350 // { int __acl_set_fd(int filedes, acl_type_t type, \
+	SYS___ACL_DELETE_FILE      = 351 // { int __acl_delete_file(const char *path, \
+	SYS___ACL_DELETE_FD        = 352 // { int __acl_delete_fd(int filedes, acl_type_t type); }
+	SYS___ACL_ACLCHECK_FILE    = 353 // { int __acl_aclcheck_file(const char *path, \
+	SYS___ACL_ACLCHECK_FD      = 354 // { int __acl_aclcheck_fd(int filedes, acl_type_t type, \
+	SYS_EXTATTRCTL             = 355 // { int extattrctl(const char *path, int cmd, \
+	SYS_EXTATTR_SET_FILE       = 356 // { int extattr_set_file(const char *path, \
+	SYS_EXTATTR_GET_FILE       = 357 // { int extattr_get_file(const char *path, \
+	SYS_EXTATTR_DELETE_FILE    = 358 // { int extattr_delete_file(const char *path, \
+	SYS_AIO_WAITCOMPLETE       = 359 // { int aio_waitcomplete(struct aiocb **aiocbp, struct timespec *timeout); }
+	SYS_GETRESUID              = 360 // { int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid); }
+	SYS_GETRESGID              = 361 // { int getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid); }
+	SYS_KQUEUE                 = 362 // { int kqueue(void); }
+	SYS_KEVENT                 = 363 // { int kevent(int fd, \
+	SYS_SCTP_PEELOFF           = 364 // { int sctp_peeloff(int sd, caddr_t name ); }
+	SYS_LCHFLAGS               = 391 // { int lchflags(char *path, int flags); }
+	SYS_UUIDGEN                = 392 // { int uuidgen(struct uuid *store, int count); }
+	SYS_SENDFILE               = 393 // { int sendfile(int fd, int s, off_t offset, size_t nbytes, \
+	SYS_VARSYM_SET             = 450 // { int varsym_set(int level, const char *name, const char *data); }
+	SYS_VARSYM_GET             = 451 // { int varsym_get(int mask, const char *wild, char *buf, int bufsize); }
+	SYS_VARSYM_LIST            = 452 // { int varsym_list(int level, char *buf, int maxsize, int *marker); }
+	SYS_EXEC_SYS_REGISTER      = 465 // { int exec_sys_register(void *entry); }
+	SYS_EXEC_SYS_UNREGISTER    = 466 // { int exec_sys_unregister(int id); }
+	SYS_SYS_CHECKPOINT         = 467 // { int sys_checkpoint(int type, int fd, pid_t pid, int retval); }
+	SYS_MOUNTCTL               = 468 // { int mountctl(const char *path, int op, int fd, const void *ctl, int ctllen, void *buf, int buflen); }
+	SYS_UMTX_SLEEP             = 469 // { int umtx_sleep(volatile const int *ptr, int value, int timeout); }
+	SYS_UMTX_WAKEUP            = 470 // { int umtx_wakeup(volatile const int *ptr, int count); }
+	SYS_JAIL_ATTACH            = 471 // { int jail_attach(int jid); }
+	SYS_SET_TLS_AREA           = 472 // { int set_tls_area(int which, struct tls_info *info, size_t infosize); }
+	SYS_GET_TLS_AREA           = 473 // { int get_tls_area(int which, struct tls_info *info, size_t infosize); }
+	SYS_CLOSEFROM              = 474 // { int closefrom(int fd); }
+	SYS_STAT                   = 475 // { int stat(const char *path, struct stat *ub); }
+	SYS_FSTAT                  = 476 // { int fstat(int fd, struct stat *sb); }
+	SYS_LSTAT                  = 477 // { int lstat(const char *path, struct stat *ub); }
+	SYS_FHSTAT                 = 478 // { int fhstat(const struct fhandle *u_fhp, struct stat *sb); }
+	SYS_GETDIRENTRIES          = 479 // { int getdirentries(int fd, char *buf, u_int count, \
+	SYS_GETDENTS               = 480 // { int getdents(int fd, char *buf, size_t count); }
+	SYS_USCHED_SET             = 481 // { int usched_set(pid_t pid, int cmd, void *data, \
+	SYS_EXTACCEPT              = 482 // { int extaccept(int s, int flags, caddr_t name, int *anamelen); }
+	SYS_EXTCONNECT             = 483 // { int extconnect(int s, int flags, caddr_t name, int namelen); }
+	SYS_MCONTROL               = 485 // { int mcontrol(void *addr, size_t len, int behav, off_t value); }
+	SYS_VMSPACE_CREATE         = 486 // { int vmspace_create(void *id, int type, void *data); }
+	SYS_VMSPACE_DESTROY        = 487 // { int vmspace_destroy(void *id); }
+	SYS_VMSPACE_CTL            = 488 // { int vmspace_ctl(void *id, int cmd, 		\
+	SYS_VMSPACE_MMAP           = 489 // { int vmspace_mmap(void *id, void *addr, size_t len, \
+	SYS_VMSPACE_MUNMAP         = 490 // { int vmspace_munmap(void *id, void *addr,	\
+	SYS_VMSPACE_MCONTROL       = 491 // { int vmspace_mcontrol(void *id, void *addr, 	\
+	SYS_VMSPACE_PREAD          = 492 // { ssize_t vmspace_pread(void *id, void *buf, \
+	SYS_VMSPACE_PWRITE         = 493 // { ssize_t vmspace_pwrite(void *id, const void *buf, \
+	SYS_EXTEXIT                = 494 // { void extexit(int how, int status, void *addr); }
+	SYS_LWP_CREATE             = 495 // { int lwp_create(struct lwp_params *params); }
+	SYS_LWP_GETTID             = 496 // { lwpid_t lwp_gettid(void); }
+	SYS_LWP_KILL               = 497 // { int lwp_kill(pid_t pid, lwpid_t tid, int signum); }
+	SYS_LWP_RTPRIO             = 498 // { int lwp_rtprio(int function, pid_t pid, lwpid_t tid, struct rtprio *rtp); }
+	SYS_PSELECT                = 499 // { int pselect(int nd, fd_set *in, fd_set *ou, \
+	SYS_STATVFS                = 500 // { int statvfs(const char *path, struct statvfs *buf); }
+	SYS_FSTATVFS               = 501 // { int fstatvfs(int fd, struct statvfs *buf); }
+	SYS_FHSTATVFS              = 502 // { int fhstatvfs(const struct fhandle *u_fhp, struct statvfs *buf); }
+	SYS_GETVFSSTAT             = 503 // { int getvfsstat(struct statfs *buf,          \
+	SYS_OPENAT                 = 504 // { int openat(int fd, char *path, int flags, int mode); }
+	SYS_FSTATAT                = 505 // { int fstatat(int fd, char *path, 	\
+	SYS_FCHMODAT               = 506 // { int fchmodat(int fd, char *path, int mode, \
+	SYS_FCHOWNAT               = 507 // { int fchownat(int fd, char *path, int uid, int gid, \
+	SYS_UNLINKAT               = 508 // { int unlinkat(int fd, char *path, int flags); }
+	SYS_FACCESSAT              = 509 // { int faccessat(int fd, char *path, int amode, \
+	SYS_MQ_OPEN                = 510 // { mqd_t mq_open(const char * name, int oflag, \
+	SYS_MQ_CLOSE               = 511 // { int mq_close(mqd_t mqdes); }
+	SYS_MQ_UNLINK              = 512 // { int mq_unlink(const char *name); }
+	SYS_MQ_GETATTR             = 513 // { int mq_getattr(mqd_t mqdes, \
+	SYS_MQ_SETATTR             = 514 // { int mq_setattr(mqd_t mqdes, \
+	SYS_MQ_NOTIFY              = 515 // { int mq_notify(mqd_t mqdes, \
+	SYS_MQ_SEND                = 516 // { int mq_send(mqd_t mqdes, const char *msg_ptr, \
+	SYS_MQ_RECEIVE             = 517 // { ssize_t mq_receive(mqd_t mqdes, char *msg_ptr, \
+	SYS_MQ_TIMEDSEND           = 518 // { int mq_timedsend(mqd_t mqdes, \
+	SYS_MQ_TIMEDRECEIVE        = 519 // { ssize_t mq_timedreceive(mqd_t mqdes, \
+	SYS_IOPRIO_SET             = 520 // { int ioprio_set(int which, int who, int prio); }
+	SYS_IOPRIO_GET             = 521 // { int ioprio_get(int which, int who); }
+	SYS_CHROOT_KERNEL          = 522 // { int chroot_kernel(char *path); }
+	SYS_RENAMEAT               = 523 // { int renameat(int oldfd, char *old, int newfd, \
+	SYS_MKDIRAT                = 524 // { int mkdirat(int fd, char *path, mode_t mode); }
+	SYS_MKFIFOAT               = 525 // { int mkfifoat(int fd, char *path, mode_t mode); }
+	SYS_MKNODAT                = 526 // { int mknodat(int fd, char *path, mode_t mode, \
+	SYS_READLINKAT             = 527 // { int readlinkat(int fd, char *path, char *buf, \
+	SYS_SYMLINKAT              = 528 // { int symlinkat(char *path1, int fd, char *path2); }
+	SYS_SWAPOFF                = 529 // { int swapoff(char *name); }
+	SYS_VQUOTACTL              = 530 // { int vquotactl(const char *path, \
+	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/syscall/zsysnum_dragonfly_amd64.go b/src/syscall/zsysnum_dragonfly_amd64.go
index 277478d..4b086b9 100644
--- a/src/syscall/zsysnum_dragonfly_amd64.go
+++ b/src/syscall/zsysnum_dragonfly_amd64.go
@@ -1,8 +1,6 @@
 // mksysnum_dragonfly.pl
 // MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
 
-// +build amd64,dragonfly
-
 package syscall
 
 const (
diff --git a/src/syscall/zsysnum_freebsd_386.go b/src/syscall/zsysnum_freebsd_386.go
index 5e47217..dfca558 100644
--- a/src/syscall/zsysnum_freebsd_386.go
+++ b/src/syscall/zsysnum_freebsd_386.go
@@ -1,8 +1,6 @@
 // mksysnum_freebsd.pl
 // MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
 
-// +build 386,freebsd
-
 package syscall
 
 const (
diff --git a/src/syscall/zsysnum_freebsd_amd64.go b/src/syscall/zsysnum_freebsd_amd64.go
index df8928c..dfca558 100644
--- a/src/syscall/zsysnum_freebsd_amd64.go
+++ b/src/syscall/zsysnum_freebsd_amd64.go
@@ -1,8 +1,6 @@
 // mksysnum_freebsd.pl
 // MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
 
-// +build amd64,freebsd
-
 package syscall
 
 const (
diff --git a/src/syscall/zsysnum_freebsd_arm.go b/src/syscall/zsysnum_freebsd_arm.go
index f670a59..dfca558 100644
--- a/src/syscall/zsysnum_freebsd_arm.go
+++ b/src/syscall/zsysnum_freebsd_arm.go
@@ -1,8 +1,6 @@
 // mksysnum_freebsd.pl
 // MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
 
-// +build arm,freebsd
-
 package syscall
 
 const (
diff --git a/src/syscall/zsysnum_linux_386.go b/src/syscall/zsysnum_linux_386.go
index c277ed9..c40b5f1 100644
--- a/src/syscall/zsysnum_linux_386.go
+++ b/src/syscall/zsysnum_linux_386.go
@@ -1,8 +1,6 @@
 // mksysnum_linux.pl /usr/include/asm/unistd_32.h
 // MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
 
-// +build 386,linux
-
 package syscall
 
 const (
diff --git a/src/syscall/zsysnum_linux_amd64.go b/src/syscall/zsysnum_linux_amd64.go
index 978a4d3..7cf70a4 100644
--- a/src/syscall/zsysnum_linux_amd64.go
+++ b/src/syscall/zsysnum_linux_amd64.go
@@ -1,8 +1,6 @@
 // mksysnum_linux.pl /usr/include/asm/unistd_64.h
 // MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
 
-// +build amd64,linux
-
 package syscall
 
 const (
diff --git a/src/syscall/zsysnum_linux_arm.go b/src/syscall/zsysnum_linux_arm.go
index 5061cba..7068e4e 100644
--- a/src/syscall/zsysnum_linux_arm.go
+++ b/src/syscall/zsysnum_linux_arm.go
@@ -1,8 +1,6 @@
 // mksysnum_linux.pl
 // MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
 
-// +build arm,linux
-
 package syscall
 
 const (
diff --git a/src/syscall/zsysnum_netbsd_386.go b/src/syscall/zsysnum_netbsd_386.go
index c8af210..c570965 100644
--- a/src/syscall/zsysnum_netbsd_386.go
+++ b/src/syscall/zsysnum_netbsd_386.go
@@ -1,8 +1,6 @@
 // mksysnum_netbsd.pl
 // MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
 
-// +build 386,netbsd
-
 package syscall
 
 const (
diff --git a/src/syscall/zsysnum_netbsd_amd64.go b/src/syscall/zsysnum_netbsd_amd64.go
index e342a3c..c570965 100644
--- a/src/syscall/zsysnum_netbsd_amd64.go
+++ b/src/syscall/zsysnum_netbsd_amd64.go
@@ -1,8 +1,6 @@
 // mksysnum_netbsd.pl
 // MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
 
-// +build amd64,netbsd
-
 package syscall
 
 const (
diff --git a/src/syscall/zsysnum_netbsd_arm.go b/src/syscall/zsysnum_netbsd_arm.go
index 1f5b569..c570965 100644
--- a/src/syscall/zsysnum_netbsd_arm.go
+++ b/src/syscall/zsysnum_netbsd_arm.go
@@ -1,8 +1,6 @@
 // mksysnum_netbsd.pl
 // MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
 
-// +build arm,netbsd
-
 package syscall
 
 const (
diff --git a/src/syscall/zsysnum_openbsd_386.go b/src/syscall/zsysnum_openbsd_386.go
index c19f6de..3b9ac4c 100644
--- a/src/syscall/zsysnum_openbsd_386.go
+++ b/src/syscall/zsysnum_openbsd_386.go
@@ -1,8 +1,6 @@
 // mksysnum_openbsd.pl
 // MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
 
-// +build 386,openbsd
-
 package syscall
 
 const (
diff --git a/src/syscall/zsysnum_openbsd_amd64.go b/src/syscall/zsysnum_openbsd_amd64.go
index 86e04cd..3b9ac4c 100644
--- a/src/syscall/zsysnum_openbsd_amd64.go
+++ b/src/syscall/zsysnum_openbsd_amd64.go
@@ -1,8 +1,6 @@
 // mksysnum_openbsd.pl
 // MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
 
-// +build amd64,openbsd
-
 package syscall
 
 const (
diff --git a/src/syscall/zsysnum_plan9_386.go b/src/syscall/zsysnum_plan9_386.go
new file mode 100644
index 0000000..07498c4
--- /dev/null
+++ b/src/syscall/zsysnum_plan9_386.go
@@ -0,0 +1,49 @@
+// mksysnum_plan9.sh /media/sys/src/libc/9syscall/sys.h
+// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
+
+package syscall
+
+const (
+	SYS_SYSR1       = 0
+	SYS_BIND        = 2
+	SYS_CHDIR       = 3
+	SYS_CLOSE       = 4
+	SYS_DUP         = 5
+	SYS_ALARM       = 6
+	SYS_EXEC        = 7
+	SYS_EXITS       = 8
+	SYS_FAUTH       = 10
+	SYS_SEGBRK      = 12
+	SYS_OPEN        = 14
+	SYS_OSEEK       = 16
+	SYS_SLEEP       = 17
+	SYS_RFORK       = 19
+	SYS_PIPE        = 21
+	SYS_CREATE      = 22
+	SYS_FD2PATH     = 23
+	SYS_BRK_        = 24
+	SYS_REMOVE      = 25
+	SYS_NOTIFY      = 28
+	SYS_NOTED       = 29
+	SYS_SEGATTACH   = 30
+	SYS_SEGDETACH   = 31
+	SYS_SEGFREE     = 32
+	SYS_SEGFLUSH    = 33
+	SYS_RENDEZVOUS  = 34
+	SYS_UNMOUNT     = 35
+	SYS_SEMACQUIRE  = 37
+	SYS_SEMRELEASE  = 38
+	SYS_SEEK        = 39
+	SYS_FVERSION    = 40
+	SYS_ERRSTR      = 41
+	SYS_STAT        = 42
+	SYS_FSTAT       = 43
+	SYS_WSTAT       = 44
+	SYS_FWSTAT      = 45
+	SYS_MOUNT       = 46
+	SYS_AWAIT       = 47
+	SYS_PREAD       = 50
+	SYS_PWRITE      = 51
+	SYS_TSEMACQUIRE = 52
+	SYS_NSEC        = 53
+)
diff --git a/src/syscall/zsysnum_plan9_amd64.go b/src/syscall/zsysnum_plan9_amd64.go
new file mode 100644
index 0000000..07498c4
--- /dev/null
+++ b/src/syscall/zsysnum_plan9_amd64.go
@@ -0,0 +1,49 @@
+// mksysnum_plan9.sh /media/sys/src/libc/9syscall/sys.h
+// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
+
+package syscall
+
+const (
+	SYS_SYSR1       = 0
+	SYS_BIND        = 2
+	SYS_CHDIR       = 3
+	SYS_CLOSE       = 4
+	SYS_DUP         = 5
+	SYS_ALARM       = 6
+	SYS_EXEC        = 7
+	SYS_EXITS       = 8
+	SYS_FAUTH       = 10
+	SYS_SEGBRK      = 12
+	SYS_OPEN        = 14
+	SYS_OSEEK       = 16
+	SYS_SLEEP       = 17
+	SYS_RFORK       = 19
+	SYS_PIPE        = 21
+	SYS_CREATE      = 22
+	SYS_FD2PATH     = 23
+	SYS_BRK_        = 24
+	SYS_REMOVE      = 25
+	SYS_NOTIFY      = 28
+	SYS_NOTED       = 29
+	SYS_SEGATTACH   = 30
+	SYS_SEGDETACH   = 31
+	SYS_SEGFREE     = 32
+	SYS_SEGFLUSH    = 33
+	SYS_RENDEZVOUS  = 34
+	SYS_UNMOUNT     = 35
+	SYS_SEMACQUIRE  = 37
+	SYS_SEMRELEASE  = 38
+	SYS_SEEK        = 39
+	SYS_FVERSION    = 40
+	SYS_ERRSTR      = 41
+	SYS_STAT        = 42
+	SYS_FSTAT       = 43
+	SYS_WSTAT       = 44
+	SYS_FWSTAT      = 45
+	SYS_MOUNT       = 46
+	SYS_AWAIT       = 47
+	SYS_PREAD       = 50
+	SYS_PWRITE      = 51
+	SYS_TSEMACQUIRE = 52
+	SYS_NSEC        = 53
+)
diff --git a/src/syscall/zsysnum_solaris_amd64.go b/src/syscall/zsysnum_solaris_amd64.go
index be198f8..43b3d8b 100644
--- a/src/syscall/zsysnum_solaris_amd64.go
+++ b/src/syscall/zsysnum_solaris_amd64.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.
 
-// +build amd64,solaris
-
 package syscall
 
 // TODO(aram): remove these before Go 1.3.
diff --git a/src/syscall/ztypes_darwin_386.go b/src/syscall/ztypes_darwin_386.go
index 7298d02..13724c3 100644
--- a/src/syscall/ztypes_darwin_386.go
+++ b/src/syscall/ztypes_darwin_386.go
@@ -1,8 +1,6 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs types_darwin.go
 
-// +build 386,darwin
-
 package syscall
 
 const (
diff --git a/src/syscall/ztypes_darwin_amd64.go b/src/syscall/ztypes_darwin_amd64.go
index ec95d51..65b02ae 100644
--- a/src/syscall/ztypes_darwin_amd64.go
+++ b/src/syscall/ztypes_darwin_amd64.go
@@ -1,8 +1,6 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs types_darwin.go
 
-// +build amd64,darwin
-
 package syscall
 
 const (
diff --git a/src/syscall/ztypes_dragonfly_386.go b/src/syscall/ztypes_dragonfly_386.go
new file mode 100644
index 0000000..6b6ec15
--- /dev/null
+++ b/src/syscall/ztypes_dragonfly_386.go
@@ -0,0 +1,435 @@
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs types_dragonfly.go
+
+package syscall
+
+const (
+	sizeofPtr      = 0x4
+	sizeofShort    = 0x2
+	sizeofInt      = 0x4
+	sizeofLong     = 0x4
+	sizeofLongLong = 0x8
+)
+
+type (
+	_C_short     int16
+	_C_int       int32
+	_C_long      int32
+	_C_long_long int64
+)
+
+type Timespec struct {
+	Sec  int32
+	Nsec int32
+}
+
+type Timeval struct {
+	Sec  int32
+	Usec int32
+}
+
+type Rusage struct {
+	Utime    Timeval
+	Stime    Timeval
+	Maxrss   int32
+	Ixrss    int32
+	Idrss    int32
+	Isrss    int32
+	Minflt   int32
+	Majflt   int32
+	Nswap    int32
+	Inblock  int32
+	Oublock  int32
+	Msgsnd   int32
+	Msgrcv   int32
+	Nsignals int32
+	Nvcsw    int32
+	Nivcsw   int32
+}
+
+type Rlimit struct {
+	Cur int64
+	Max int64
+}
+
+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 {
+	Ino      uint64
+	Nlink    uint32
+	Dev      uint32
+	Mode     uint16
+	Padding1 uint16
+	Uid      uint32
+	Gid      uint32
+	Rdev     uint32
+	Atim     Timespec
+	Mtim     Timespec
+	Ctim     Timespec
+	Size     int64
+	Blocks   int64
+	Blksize  uint32
+	Flags    uint32
+	Gen      uint32
+	Lspare   int32
+	Qspare1  int64
+	Qspare2  int64
+}
+
+type Statfs_t struct {
+	Spare2      int32
+	Bsize       int32
+	Iosize      int32
+	Blocks      int32
+	Bfree       int32
+	Bavail      int32
+	Files       int32
+	Ffree       int32
+	Fsid        Fsid
+	Owner       uint32
+	Type        int32
+	Flags       int32
+	Syncwrites  int32
+	Asyncwrites int32
+	Fstypename  [16]int8
+	Mntonname   [80]int8
+	Syncreads   int32
+	Asyncreads  int32
+	Spares1     int16
+	Mntfromname [80]int8
+	Spares2     int16
+	Spare       [2]int32
+}
+
+type Flock_t struct {
+	Start  int64
+	Len    int64
+	Pid    int32
+	Type   int16
+	Whence int16
+}
+
+type Dirent struct {
+	Fileno  uint64
+	Namlen  uint16
+	Type    uint8
+	Unused1 uint8
+	Unused2 uint32
+	Name    [256]int8
+}
+
+type Fsid struct {
+	Val [2]int32
+}
+
+type RawSockaddrInet4 struct {
+	Len    uint8
+	Family uint8
+	Port   uint16
+	Addr   [4]byte /* in_addr */
+	Zero   [8]int8
+}
+
+type RawSockaddrInet6 struct {
+	Len      uint8
+	Family   uint8
+	Port     uint16
+	Flowinfo uint32
+	Addr     [16]byte /* in6_addr */
+	Scope_id uint32
+}
+
+type RawSockaddrUnix struct {
+	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   [12]int8
+	Rcf    uint16
+	Route  [16]uint16
+}
+
+type RawSockaddr struct {
+	Len    uint8
+	Family uint8
+	Data   [14]int8
+}
+
+type RawSockaddrAny struct {
+	Addr RawSockaddr
+	Pad  [92]int8
+}
+
+type _Socklen uint32
+
+type Linger struct {
+	Onoff  int32
+	Linger int32
+}
+
+type Iovec struct {
+	Base *byte
+	Len  uint32
+}
+
+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
+	Iov        *Iovec
+	Iovlen     int32
+	Control    *byte
+	Controllen uint32
+	Flags      int32
+}
+
+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 {
+	Filt [8]uint32
+}
+
+const (
+	SizeofSockaddrInet4    = 0x10
+	SizeofSockaddrInet6    = 0x1c
+	SizeofSockaddrAny      = 0x6c
+	SizeofSockaddrUnix     = 0x6a
+	SizeofSockaddrDatalink = 0x36
+	SizeofLinger           = 0x8
+	SizeofIPMreq           = 0x8
+	SizeofIPv6Mreq         = 0x14
+	SizeofMsghdr           = 0x1c
+	SizeofCmsghdr          = 0xc
+	SizeofInet6Pktinfo     = 0x14
+	SizeofIPv6MTUInfo      = 0x20
+	SizeofICMPv6Filter     = 0x20
+)
+
+const (
+	PTRACE_TRACEME = 0x0
+	PTRACE_CONT    = 0x7
+	PTRACE_KILL    = 0x8
+)
+
+type Kevent_t struct {
+	Ident  uint32
+	Filter int16
+	Flags  uint16
+	Fflags uint32
+	Data   int32
+	Udata  *byte
+}
+
+type FdSet struct {
+	Bits [32]uint32
+}
+
+const (
+	SizeofIfMsghdr         = 0x68
+	SizeofIfData           = 0x58
+	SizeofIfaMsghdr        = 0x14
+	SizeofIfmaMsghdr       = 0x10
+	SizeofIfAnnounceMsghdr = 0x18
+	SizeofRtMsghdr         = 0x5c
+	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 IfData struct {
+	Type       uint8
+	Physical   uint8
+	Addrlen    uint8
+	Hdrlen     uint8
+	Recvquota  uint8
+	Xmitquota  uint8
+	Pad_cgo_0  [2]byte
+	Mtu        uint32
+	Metric     uint32
+	Link_state uint32
+	Baudrate   uint64
+	Ipackets   uint32
+	Ierrors    uint32
+	Opackets   uint32
+	Oerrors    uint32
+	Collisions uint32
+	Ibytes     uint32
+	Obytes     uint32
+	Imcasts    uint32
+	Omcasts    uint32
+	Iqdrops    uint32
+	Noproto    uint32
+	Hwassist   uint32
+	Unused     uint32
+	Lastchange Timeval
+}
+
+type IfaMsghdr struct {
+	Msglen    uint16
+	Version   uint8
+	Type      uint8
+	Addrs     int32
+	Flags     int32
+	Index     uint16
+	Pad_cgo_0 [2]byte
+	Metric    int32
+}
+
+type IfmaMsghdr struct {
+	Msglen    uint16
+	Version   uint8
+	Type      uint8
+	Addrs     int32
+	Flags     int32
+	Index     uint16
+	Pad_cgo_0 [2]byte
+}
+
+type IfAnnounceMsghdr struct {
+	Msglen  uint16
+	Version uint8
+	Type    uint8
+	Index   uint16
+	Name    [16]int8
+	What    uint16
+}
+
+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
+	Pksent    uint32
+	Expire    uint32
+	Sendpipe  uint32
+	Ssthresh  uint32
+	Rtt       uint32
+	Rttvar    uint32
+	Recvpipe  uint32
+	Hopcount  uint32
+	Mssopt    uint16
+	Pad       uint16
+	Msl       uint32
+	Iwmaxsegs uint32
+	Iwcapsegs uint32
+}
+
+const (
+	SizeofBpfVersion = 0x4
+	SizeofBpfStat    = 0x8
+	SizeofBpfProgram = 0x8
+	SizeofBpfInsn    = 0x8
+	SizeofBpfHdr     = 0x14
+)
+
+type BpfVersion struct {
+	Major uint16
+	Minor uint16
+}
+
+type BpfStat struct {
+	Recv uint32
+	Drop uint32
+}
+
+type BpfProgram struct {
+	Len   uint32
+	Insns *BpfInsn
+}
+
+type BpfInsn struct {
+	Code uint16
+	Jt   uint8
+	Jf   uint8
+	K    uint32
+}
+
+type BpfHdr struct {
+	Tstamp    Timeval
+	Caplen    uint32
+	Datalen   uint32
+	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/syscall/ztypes_dragonfly_amd64.go b/src/syscall/ztypes_dragonfly_amd64.go
index 00120d0..954ffd7 100644
--- a/src/syscall/ztypes_dragonfly_amd64.go
+++ b/src/syscall/ztypes_dragonfly_amd64.go
@@ -1,8 +1,6 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs types_dragonfly.go
 
-// +build amd64,dragonfly
-
 package syscall
 
 const (
diff --git a/src/syscall/ztypes_freebsd_386.go b/src/syscall/ztypes_freebsd_386.go
index d972fb6..b809eea 100644
--- a/src/syscall/ztypes_freebsd_386.go
+++ b/src/syscall/ztypes_freebsd_386.go
@@ -1,8 +1,6 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs types_freebsd.go
 
-// +build 386,freebsd
-
 package syscall
 
 const (
diff --git a/src/syscall/ztypes_freebsd_amd64.go b/src/syscall/ztypes_freebsd_amd64.go
index 0a5a10b..a05908a 100644
--- a/src/syscall/ztypes_freebsd_amd64.go
+++ b/src/syscall/ztypes_freebsd_amd64.go
@@ -1,8 +1,6 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs types_freebsd.go
 
-// +build amd64,freebsd
-
 package syscall
 
 const (
diff --git a/src/syscall/ztypes_freebsd_arm.go b/src/syscall/ztypes_freebsd_arm.go
index 5d7acd5..9303816 100644
--- a/src/syscall/ztypes_freebsd_arm.go
+++ b/src/syscall/ztypes_freebsd_arm.go
@@ -1,8 +1,6 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs -- -fsigned-char types_freebsd.go
 
-// +build arm,freebsd
-
 package syscall
 
 const (
diff --git a/src/syscall/ztypes_linux_386.go b/src/syscall/ztypes_linux_386.go
index dd198cb..daecb1d 100644
--- a/src/syscall/ztypes_linux_386.go
+++ b/src/syscall/ztypes_linux_386.go
@@ -1,8 +1,6 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs types_linux.go
 
-// +build 386,linux
-
 package syscall
 
 const (
@@ -574,9 +572,7 @@ type EpollEvent struct {
 }
 
 const (
-	_AT_FDCWD            = -0x64
-	_AT_REMOVEDIR        = 0x200
-	_AT_SYMLINK_NOFOLLOW = 0x100
+	_AT_FDCWD = -0x64
 )
 
 type Termios struct {
diff --git a/src/syscall/ztypes_linux_amd64.go b/src/syscall/ztypes_linux_amd64.go
index a39489e..694fe1e 100644
--- a/src/syscall/ztypes_linux_amd64.go
+++ b/src/syscall/ztypes_linux_amd64.go
@@ -1,8 +1,6 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs types_linux.go
 
-// +build amd64,linux
-
 package syscall
 
 const (
@@ -592,9 +590,7 @@ type EpollEvent struct {
 }
 
 const (
-	_AT_FDCWD            = -0x64
-	_AT_REMOVEDIR        = 0x200
-	_AT_SYMLINK_NOFOLLOW = 0x100
+	_AT_FDCWD = -0x64
 )
 
 type Termios struct {
diff --git a/src/syscall/ztypes_linux_arm.go b/src/syscall/ztypes_linux_arm.go
index f446e41..5f21a94 100644
--- a/src/syscall/ztypes_linux_arm.go
+++ b/src/syscall/ztypes_linux_arm.go
@@ -1,8 +1,6 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs types_linux.go
 
-// +build arm,linux
-
 package syscall
 
 const (
@@ -563,9 +561,7 @@ type EpollEvent struct {
 }
 
 const (
-	_AT_FDCWD            = -0x64
-	_AT_REMOVEDIR        = 0x200
-	_AT_SYMLINK_NOFOLLOW = 0x100
+	_AT_FDCWD = -0x64
 )
 
 type Termios struct {
diff --git a/src/syscall/ztypes_netbsd_386.go b/src/syscall/ztypes_netbsd_386.go
index 1752c6c..6add325 100644
--- a/src/syscall/ztypes_netbsd_386.go
+++ b/src/syscall/ztypes_netbsd_386.go
@@ -1,8 +1,6 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs types_netbsd.go
 
-// +build 386,netbsd
-
 package syscall
 
 const (
diff --git a/src/syscall/ztypes_netbsd_amd64.go b/src/syscall/ztypes_netbsd_amd64.go
index b8d4b0b..4451fc1 100644
--- a/src/syscall/ztypes_netbsd_amd64.go
+++ b/src/syscall/ztypes_netbsd_amd64.go
@@ -1,8 +1,6 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs types_netbsd.go
 
-// +build amd64,netbsd
-
 package syscall
 
 const (
diff --git a/src/syscall/ztypes_netbsd_arm.go b/src/syscall/ztypes_netbsd_arm.go
index c21d875..4e853ea 100644
--- a/src/syscall/ztypes_netbsd_arm.go
+++ b/src/syscall/ztypes_netbsd_arm.go
@@ -1,8 +1,6 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs types_netbsd.go
 
-// +build arm,netbsd
-
 package syscall
 
 const (
diff --git a/src/syscall/ztypes_openbsd_386.go b/src/syscall/ztypes_openbsd_386.go
index 0376d3a..2e4d9dd 100644
--- a/src/syscall/ztypes_openbsd_386.go
+++ b/src/syscall/ztypes_openbsd_386.go
@@ -1,8 +1,6 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs types_openbsd.go
 
-// +build 386,openbsd
-
 package syscall
 
 const (
diff --git a/src/syscall/ztypes_openbsd_amd64.go b/src/syscall/ztypes_openbsd_amd64.go
index bf23626..f07bc71 100644
--- a/src/syscall/ztypes_openbsd_amd64.go
+++ b/src/syscall/ztypes_openbsd_amd64.go
@@ -1,8 +1,6 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs types_openbsd.go
 
-// +build amd64,openbsd
-
 package syscall
 
 const (
diff --git a/src/syscall/ztypes_plan9_386.go b/src/syscall/ztypes_plan9_386.go
new file mode 100644
index 0000000..3e3a8d1
--- /dev/null
+++ b/src/syscall/ztypes_plan9_386.go
@@ -0,0 +1,75 @@
+// godefs -gsyscall -f -m32 types_plan9.c
+
+// MACHINE GENERATED - DO NOT EDIT.
+
+package syscall
+
+// Constants
+const (
+	O_RDONLY   = 0
+	O_WRONLY   = 0x1
+	O_RDWR     = 0x2
+	O_TRUNC    = 0x10
+	O_CLOEXEC  = 0x20
+	O_EXCL     = 0x1000
+	STATMAX    = 0xffff
+	ERRMAX     = 0x80
+	MORDER     = 0x3
+	MREPL      = 0
+	MBEFORE    = 0x1
+	MAFTER     = 0x2
+	MCREATE    = 0x4
+	MCACHE     = 0x10
+	MMASK      = 0x17
+	RFNAMEG    = 0x1
+	RFENVG     = 0x2
+	RFFDG      = 0x4
+	RFNOTEG    = 0x8
+	RFPROC     = 0x10
+	RFMEM      = 0x20
+	RFNOWAIT   = 0x40
+	RFCNAMEG   = 0x400
+	RFCENVG    = 0x800
+	RFCFDG     = 0x1000
+	RFREND     = 0x2000
+	RFNOMNT    = 0x4000
+	QTDIR      = 0x80
+	QTAPPEND   = 0x40
+	QTEXCL     = 0x20
+	QTMOUNT    = 0x10
+	QTAUTH     = 0x8
+	QTTMP      = 0x4
+	QTFILE     = 0
+	DMDIR      = 0x80000000
+	DMAPPEND   = 0x40000000
+	DMEXCL     = 0x20000000
+	DMMOUNT    = 0x10000000
+	DMAUTH     = 0x8000000
+	DMTMP      = 0x4000000
+	DMREAD     = 0x4
+	DMWRITE    = 0x2
+	DMEXEC     = 0x1
+	STATFIXLEN = 0x31
+)
+
+// Types
+
+type _C_int int32
+
+type Prof struct {
+	Pp    *[0]byte /* sPlink */
+	Next  *[0]byte /* sPlink */
+	Last  *[0]byte /* sPlink */
+	First *[0]byte /* sPlink */
+	Pid   uint32
+	What  uint32
+}
+
+type Tos struct {
+	Prof      Prof
+	Cyclefreq uint64
+	Kcycles   int64
+	Pcycles   int64
+	Pid       uint32
+	Clock     uint32
+}
diff --git a/src/syscall/ztypes_plan9_amd64.go b/src/syscall/ztypes_plan9_amd64.go
new file mode 100644
index 0000000..3e3a8d1
--- /dev/null
+++ b/src/syscall/ztypes_plan9_amd64.go
@@ -0,0 +1,75 @@
+// godefs -gsyscall -f -m32 types_plan9.c
+
+// MACHINE GENERATED - DO NOT EDIT.
+
+package syscall
+
+// Constants
+const (
+	O_RDONLY   = 0
+	O_WRONLY   = 0x1
+	O_RDWR     = 0x2
+	O_TRUNC    = 0x10
+	O_CLOEXEC  = 0x20
+	O_EXCL     = 0x1000
+	STATMAX    = 0xffff
+	ERRMAX     = 0x80
+	MORDER     = 0x3
+	MREPL      = 0
+	MBEFORE    = 0x1
+	MAFTER     = 0x2
+	MCREATE    = 0x4
+	MCACHE     = 0x10
+	MMASK      = 0x17
+	RFNAMEG    = 0x1
+	RFENVG     = 0x2
+	RFFDG      = 0x4
+	RFNOTEG    = 0x8
+	RFPROC     = 0x10
+	RFMEM      = 0x20
+	RFNOWAIT   = 0x40
+	RFCNAMEG   = 0x400
+	RFCENVG    = 0x800
+	RFCFDG     = 0x1000
+	RFREND     = 0x2000
+	RFNOMNT    = 0x4000
+	QTDIR      = 0x80
+	QTAPPEND   = 0x40
+	QTEXCL     = 0x20
+	QTMOUNT    = 0x10
+	QTAUTH     = 0x8
+	QTTMP      = 0x4
+	QTFILE     = 0
+	DMDIR      = 0x80000000
+	DMAPPEND   = 0x40000000
+	DMEXCL     = 0x20000000
+	DMMOUNT    = 0x10000000
+	DMAUTH     = 0x8000000
+	DMTMP      = 0x4000000
+	DMREAD     = 0x4
+	DMWRITE    = 0x2
+	DMEXEC     = 0x1
+	STATFIXLEN = 0x31
+)
+
+// Types
+
+type _C_int int32
+
+type Prof struct {
+	Pp    *[0]byte /* sPlink */
+	Next  *[0]byte /* sPlink */
+	Last  *[0]byte /* sPlink */
+	First *[0]byte /* sPlink */
+	Pid   uint32
+	What  uint32
+}
+
+type Tos struct {
+	Prof      Prof
+	Cyclefreq uint64
+	Kcycles   int64
+	Pcycles   int64
+	Pid       uint32
+	Clock     uint32
+}
diff --git a/src/syscall/ztypes_solaris_amd64.go b/src/syscall/ztypes_solaris_amd64.go
index 2471519..77275a5 100644
--- a/src/syscall/ztypes_solaris_amd64.go
+++ b/src/syscall/ztypes_solaris_amd64.go
@@ -1,8 +1,6 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs types_solaris.go
 
-// +build amd64,solaris
-
 package syscall
 
 const (
diff --git a/src/syscall/ztypes_windows.go b/src/syscall/ztypes_windows.go
index e5c7325..4c8a99a 100644
--- a/src/syscall/ztypes_windows.go
+++ b/src/syscall/ztypes_windows.go
@@ -1083,36 +1083,23 @@ type TCPKeepalive struct {
 	Interval uint32
 }
 
-type symbolicLinkReparseBuffer struct {
-	SubstituteNameOffset uint16
-	SubstituteNameLength uint16
-	PrintNameOffset      uint16
-	PrintNameLength      uint16
-	Flags                uint32
-	PathBuffer           [1]uint16
-}
+type reparseDataBuffer struct {
+	ReparseTag        uint32
+	ReparseDataLength uint16
+	Reserved          uint16
 
-type mountPointReparseBuffer struct {
+	// SymbolicLinkReparseBuffer
 	SubstituteNameOffset uint16
 	SubstituteNameLength uint16
 	PrintNameOffset      uint16
 	PrintNameLength      uint16
+	Flags                uint32
 	PathBuffer           [1]uint16
 }
 
-type reparseDataBuffer struct {
-	ReparseTag        uint32
-	ReparseDataLength uint16
-	Reserved          uint16
-
-	// GenericReparseBuffer
-	reparseBuffer byte
-}
-
 const (
 	FSCTL_GET_REPARSE_POINT          = 0x900A8
 	MAXIMUM_REPARSE_DATA_BUFFER_SIZE = 16 * 1024
-	_IO_REPARSE_TAG_MOUNT_POINT      = 0xA0000003
 	IO_REPARSE_TAG_SYMLINK           = 0xA000000C
 	SYMBOLIC_LINK_FLAG_DIRECTORY     = 0x1
 )
diff --git a/src/testing/benchmark.go b/src/testing/benchmark.go
index 62e696d..ffd5376 100644
--- a/src/testing/benchmark.go
+++ b/src/testing/benchmark.go
@@ -280,14 +280,6 @@ func (r BenchmarkResult) MemString() string {
 		r.AllocedBytesPerOp(), r.AllocsPerOp())
 }
 
-// benchmarkName returns full name of benchmark including procs suffix.
-func benchmarkName(name string, n int) string {
-	if n != 1 {
-		return fmt.Sprintf("%s-%d", name, n)
-	}
-	return name
-}
-
 // An internal function but exported because it is cross-package; part of the implementation
 // of the "go test" command.
 func RunBenchmarks(matchString func(pat, str string) (bool, error), benchmarks []InternalBenchmark) {
@@ -295,30 +287,15 @@ func RunBenchmarks(matchString func(pat, str string) (bool, error), benchmarks [
 	if len(*matchBenchmarks) == 0 {
 		return
 	}
-	// Collect matching benchmarks and determine longest name.
-	maxprocs := 1
-	for _, procs := range cpuList {
-		if procs > maxprocs {
-			maxprocs = procs
-		}
-	}
-	maxlen := 0
-	var bs []InternalBenchmark
 	for _, Benchmark := range benchmarks {
 		matched, err := matchString(*matchBenchmarks, Benchmark.Name)
 		if err != nil {
 			fmt.Fprintf(os.Stderr, "testing: invalid regexp for -test.bench: %s\n", err)
 			os.Exit(1)
 		}
-		if matched {
-			bs = append(bs, Benchmark)
-			benchName := benchmarkName(Benchmark.Name, maxprocs)
-			if l := len(benchName); l > maxlen {
-				maxlen = l
-			}
+		if !matched {
+			continue
 		}
-	}
-	for _, Benchmark := range bs {
 		for _, procs := range cpuList {
 			runtime.GOMAXPROCS(procs)
 			b := &B{
@@ -327,8 +304,11 @@ func RunBenchmarks(matchString func(pat, str string) (bool, error), benchmarks [
 				},
 				benchmark: Benchmark,
 			}
-			benchName := benchmarkName(Benchmark.Name, procs)
-			fmt.Printf("%-*s\t", maxlen, benchName)
+			benchName := Benchmark.Name
+			if procs != 1 {
+				benchName = fmt.Sprintf("%s-%d", Benchmark.Name, procs)
+			}
+			fmt.Printf("%s\t", benchName)
 			r := b.run()
 			if b.failed {
 				// The output could be very long here, but probably isn't.
diff --git a/src/testing/example.go b/src/testing/example.go
index 30baf27..f5762e4 100644
--- a/src/testing/example.go
+++ b/src/testing/example.go
@@ -43,7 +43,7 @@ func RunExamples(matchString func(pat, str string) (bool, error), examples []Int
 
 func runExample(eg InternalExample) (ok bool) {
 	if *chatty {
-		fmt.Printf("=== RUN   %s\n", eg.Name)
+		fmt.Printf("=== RUN: %s\n", eg.Name)
 	}
 
 	// Capture stdout.
@@ -56,8 +56,8 @@ func runExample(eg InternalExample) (ok bool) {
 	os.Stdout = w
 	outC := make(chan string)
 	go func() {
-		var buf bytes.Buffer
-		_, err := io.Copy(&buf, r)
+		buf := new(bytes.Buffer)
+		_, err := io.Copy(buf, r)
 		r.Close()
 		if err != nil {
 			fmt.Fprintf(os.Stderr, "testing: copying pipe: %v\n", err)
diff --git a/src/testing/iotest/logger.go b/src/testing/iotest/logger.go
index 0aec15c..1475d9b 100644
--- a/src/testing/iotest/logger.go
+++ b/src/testing/iotest/logger.go
@@ -48,7 +48,7 @@ func (l *readLogger) Read(p []byte) (n int, err error) {
 
 // NewReadLogger returns a reader that behaves like r except
 // that it logs (using log.Print) each read to standard error,
-// printing the prefix and the hexadecimal data read.
+// printing the prefix and the hexadecimal data written.
 func NewReadLogger(prefix string, r io.Reader) io.Reader {
 	return &readLogger{prefix, r}
 }
diff --git a/src/testing/quick/quick.go b/src/testing/quick/quick.go
index 13c56cd..909c65f 100644
--- a/src/testing/quick/quick.go
+++ b/src/testing/quick/quick.go
@@ -102,16 +102,12 @@ func Value(t reflect.Type, rand *rand.Rand) (value reflect.Value, ok bool) {
 			v.SetMapIndex(key, value)
 		}
 	case reflect.Ptr:
-		if rand.Intn(complexSize) == 0 {
-			v.Set(reflect.Zero(concrete)) // Generate nil pointer.
-		} else {
-			elem, ok := Value(concrete.Elem(), rand)
-			if !ok {
-				return reflect.Value{}, false
-			}
-			v.Set(reflect.New(concrete.Elem()))
-			v.Elem().Set(elem)
+		elem, ok := Value(concrete.Elem(), rand)
+		if !ok {
+			return reflect.Value{}, false
 		}
+		v.Set(reflect.New(concrete.Elem()))
+		v.Elem().Set(elem)
 	case reflect.Slice:
 		numElems := rand.Intn(complexSize)
 		v.Set(reflect.MakeSlice(concrete, numElems, numElems))
@@ -122,14 +118,6 @@ func Value(t reflect.Type, rand *rand.Rand) (value reflect.Value, ok bool) {
 			}
 			v.Index(i).Set(elem)
 		}
-	case reflect.Array:
-		for i := 0; i < v.Len(); i++ {
-			elem, ok := Value(concrete.Elem(), rand)
-			if !ok {
-				return reflect.Value{}, false
-			}
-			v.Index(i).Set(elem)
-		}
 	case reflect.String:
 		numChars := rand.Intn(complexSize)
 		codePoints := make([]rune, numChars)
@@ -165,7 +153,7 @@ type Config struct {
 	Rand *rand.Rand
 	// If non-nil, the Values function generates a slice of arbitrary
 	// reflect.Values that are congruent with the arguments to the function
-	// being tested. Otherwise, the top-level Value function is used
+	// being tested. Otherwise, the top-level Values function is used
 	// to generate them.
 	Values func([]reflect.Value, *rand.Rand)
 }
@@ -249,7 +237,7 @@ func Check(f interface{}, config *Config) (err error) {
 	}
 
 	if fType.NumOut() != 1 {
-		err = SetupError("function does not return one value")
+		err = SetupError("function returns more than one value.")
 		return
 	}
 	if fType.Out(0).Kind() != reflect.Bool {
diff --git a/src/testing/quick/quick_test.go b/src/testing/quick/quick_test.go
index c79f30e..e925ba6 100644
--- a/src/testing/quick/quick_test.go
+++ b/src/testing/quick/quick_test.go
@@ -10,12 +10,6 @@ import (
 	"testing"
 )
 
-func fArray(a [4]byte) [4]byte { return a }
-
-type TestArrayAlias [4]byte
-
-func fArrayAlias(a TestArrayAlias) TestArrayAlias { return a }
-
 func fBool(a bool) bool { return a }
 
 type TestBoolAlias bool
@@ -82,18 +76,6 @@ type TestMapAlias map[int]int
 
 func fMapAlias(a TestMapAlias) TestMapAlias { return a }
 
-func fPtr(a *int) *int {
-	if a == nil {
-		return nil
-	}
-	b := *a
-	return &b
-}
-
-type TestPtrAlias *int
-
-func fPtrAlias(a TestPtrAlias) TestPtrAlias { return a }
-
 func fSlice(a []byte) []byte { return a }
 
 type TestSliceAlias []byte
@@ -153,6 +135,15 @@ type TestUintptrAlias uintptr
 
 func fUintptrAlias(a TestUintptrAlias) TestUintptrAlias { return a }
 
+func fIntptr(a *int) *int {
+	b := *a
+	return &b
+}
+
+type TestIntptrAlias *int
+
+func fIntptrAlias(a TestIntptrAlias) TestIntptrAlias { return a }
+
 func reportError(property string, err error, t *testing.T) {
 	if err != nil {
 		t.Errorf("%s: %s", property, err)
@@ -160,8 +151,6 @@ func reportError(property string, err error, t *testing.T) {
 }
 
 func TestCheckEqual(t *testing.T) {
-	reportError("fArray", CheckEqual(fArray, fArray, nil), t)
-	reportError("fArrayAlias", CheckEqual(fArrayAlias, fArrayAlias, nil), t)
 	reportError("fBool", CheckEqual(fBool, fBool, nil), t)
 	reportError("fBoolAlias", CheckEqual(fBoolAlias, fBoolAlias, nil), t)
 	reportError("fFloat32", CheckEqual(fFloat32, fFloat32, nil), t)
@@ -186,8 +175,6 @@ func TestCheckEqual(t *testing.T) {
 	reportError("fInt32Alias", CheckEqual(fInt32Alias, fInt32Alias, nil), t)
 	reportError("fMap", CheckEqual(fMap, fMap, nil), t)
 	reportError("fMapAlias", CheckEqual(fMapAlias, fMapAlias, nil), t)
-	reportError("fPtr", CheckEqual(fPtr, fPtr, nil), t)
-	reportError("fPtrAlias", CheckEqual(fPtrAlias, fPtrAlias, nil), t)
 	reportError("fSlice", CheckEqual(fSlice, fSlice, nil), t)
 	reportError("fSliceAlias", CheckEqual(fSliceAlias, fSliceAlias, nil), t)
 	reportError("fString", CheckEqual(fString, fString, nil), t)
@@ -206,6 +193,8 @@ func TestCheckEqual(t *testing.T) {
 	reportError("fUintAlias", CheckEqual(fUintAlias, fUintAlias, nil), t)
 	reportError("fUintptr", CheckEqual(fUintptr, fUintptr, nil), t)
 	reportError("fUintptrAlias", CheckEqual(fUintptrAlias, fUintptrAlias, nil), t)
+	reportError("fIntptr", CheckEqual(fIntptr, fIntptr, nil), t)
+	reportError("fIntptrAlias", CheckEqual(fIntptrAlias, fIntptrAlias, nil), t)
 }
 
 // This tests that ArbitraryValue is working by checking that all the arbitrary
@@ -258,17 +247,3 @@ func TestFailure(t *testing.T) {
 		t.Errorf("#3 Error was not a SetupError: %s", err)
 	}
 }
-
-// The following test didn't terminate because nil pointers were not
-// generated.
-// Issue 8818.
-func TestNilPointers(t *testing.T) {
-	type Recursive struct {
-		Next *Recursive
-	}
-
-	f := func(rec Recursive) bool {
-		return true
-	}
-	Check(f, nil)
-}
diff --git a/src/testing/testing.go b/src/testing/testing.go
index 1dcc35e..e54a3b8 100644
--- a/src/testing/testing.go
+++ b/src/testing/testing.go
@@ -34,7 +34,7 @@
 // its -bench flag is provided. Benchmarks are run sequentially.
 //
 // For a description of the testing flags, see
-// https://golang.org/cmd/go/#hdr-Description_of_testing_flags.
+// http://golang.org/cmd/go/#hdr-Description_of_testing_flags.
 //
 // A sample benchmark function looks like this:
 //     func BenchmarkHello(b *testing.B) {
@@ -44,7 +44,7 @@
 //     }
 //
 // The benchmark function must run the target code b.N times.
-// During benchmark execution, b.N is adjusted until the benchmark function lasts
+// During benchark execution, b.N is adjusted until the benchmark function lasts
 // long enough to be timed reliably.  The output
 //     BenchmarkHello    10000000    282 ns/op
 // means that the loop ran 10000000 times at a speed of 282 ns per loop.
@@ -130,17 +130,13 @@
 // then the generated test will call TestMain(m) instead of running the tests
 // directly. TestMain runs in the main goroutine and can do whatever setup
 // and teardown is necessary around a call to m.Run. It should then call
-// os.Exit with the result of m.Run. When TestMain is called, flag.Parse has
-// not been run. If TestMain depends on command-line flags, including those
-// of the testing package, it should call flag.Parse explicitly.
+// os.Exit with the result of m.Run.
 //
-// A simple implementation of TestMain is:
+// The minimal implementation of TestMain is:
 //
-//	func TestMain(m *testing.M) {
-//		flag.Parse()
-//		os.Exit(m.Run())
-//	}
+//	func TestMain(m *testing.M) { os.Exit(m.Run()) }
 //
+// In effect, that is the implementation used when no TestMain is explicitly defined.
 package testing
 
 import (
@@ -150,7 +146,6 @@ import (
 	"os"
 	"runtime"
 	"runtime/pprof"
-	"runtime/trace"
 	"strconv"
 	"strings"
 	"sync"
@@ -173,7 +168,6 @@ var (
 
 	// Report as tests are run; default is silent for success.
 	chatty           = flag.Bool("test.v", false, "verbose: print additional output")
-	count            = flag.Uint("test.count", 1, "run tests and benchmarks `n` times")
 	coverProfile     = flag.String("test.coverprofile", "", "write a coverage profile to the named file after execution")
 	match            = flag.String("test.run", "", "regular expression to select tests and examples to run")
 	memProfile       = flag.String("test.memprofile", "", "write a memory profile to the named file after execution")
@@ -181,7 +175,6 @@ var (
 	cpuProfile       = flag.String("test.cpuprofile", "", "write a cpu profile to the named file during execution")
 	blockProfile     = flag.String("test.blockprofile", "", "write a goroutine blocking profile to the named file after execution")
 	blockProfileRate = flag.Int("test.blockprofilerate", 1, "if >= 0, calls runtime.SetBlockProfileRate()")
-	traceFile        = flag.String("test.trace", "", "write an execution trace to the named file after execution")
 	timeout          = flag.Duration("test.timeout", 0, "if positive, sets an aggregate time limit for all tests")
 	cpuListStr       = flag.String("test.cpu", "", "comma-separated list of number of CPUs to use for each test")
 	parallel         = flag.Int("test.parallel", runtime.GOMAXPROCS(0), "maximum test parallelism")
@@ -344,15 +337,13 @@ func (c *common) log(s string) {
 }
 
 // Log formats its arguments using default formatting, analogous to Println,
-// and records the text in the error log. For tests, the text will be printed only if
-// the test fails or the -test.v flag is set. For benchmarks, the text is always
-// printed to avoid having performance depend on the value of the -test.v flag.
+// and records the text in the error log. The text will be printed only if
+// the test fails or the -test.v flag is set.
 func (c *common) Log(args ...interface{}) { c.log(fmt.Sprintln(args...)) }
 
 // Logf formats its arguments according to the format, analogous to Printf,
-// and records the text in the error log. For tests, the text will be printed only if
-// the test fails or the -test.v flag is set. For benchmarks, the text is always
-// printed to avoid having performance depend on the value of the -test.v flag.
+// and records the text in the error log. The text will be printed only if
+// the test fails or the -test.v flag is set.
 func (c *common) Logf(format string, args ...interface{}) { c.log(fmt.Sprintf(format, args...)) }
 
 // Error is equivalent to Log followed by Fail.
@@ -547,6 +538,9 @@ func RunTests(matchString func(pat, str string) (bool, error), tests []InternalT
 				continue
 			}
 			testName := tests[i].Name
+			if procs != 1 {
+				testName = fmt.Sprintf("%s-%d", tests[i].Name, procs)
+			}
 			t := &T{
 				common: common{
 					signal: make(chan interface{}),
@@ -556,7 +550,7 @@ func RunTests(matchString func(pat, str string) (bool, error), tests []InternalT
 			}
 			t.self = t
 			if *chatty {
-				fmt.Printf("=== RUN   %s\n", t.name)
+				fmt.Printf("=== RUN %s\n", t.name)
 			}
 			go tRunner(t, &tests[i])
 			out := (<-t.signal).(*T)
@@ -606,19 +600,6 @@ func before() {
 		}
 		// Could save f so after can call f.Close; not worth the effort.
 	}
-	if *traceFile != "" {
-		f, err := os.Create(toOutputDir(*traceFile))
-		if err != nil {
-			fmt.Fprintf(os.Stderr, "testing: %s", err)
-			return
-		}
-		if err := trace.Start(f); err != nil {
-			fmt.Fprintf(os.Stderr, "testing: can't start tracing: %s", err)
-			f.Close()
-			return
-		}
-		// Could save f so after can call f.Close; not worth the effort.
-	}
 	if *blockProfile != "" && *blockProfileRate >= 0 {
 		runtime.SetBlockProfileRate(*blockProfileRate)
 	}
@@ -633,9 +614,6 @@ func after() {
 	if *cpuProfile != "" {
 		pprof.StopCPUProfile() // flushes profile to disk
 	}
-	if *traceFile != "" {
-		trace.Stop() // flushes trace to disk
-	}
 	if *memProfile != "" {
 		f, err := os.Create(toOutputDir(*memProfile))
 		if err != nil {
@@ -723,13 +701,9 @@ func parseCpuList() {
 			fmt.Fprintf(os.Stderr, "testing: invalid value %q for -test.cpu\n", val)
 			os.Exit(1)
 		}
-		for i := uint(0); i < *count; i++ {
-			cpuList = append(cpuList, cpu)
-		}
+		cpuList = append(cpuList, cpu)
 	}
 	if cpuList == nil {
-		for i := uint(0); i < *count; i++ {
-			cpuList = append(cpuList, runtime.GOMAXPROCS(-1))
-		}
+		cpuList = append(cpuList, runtime.GOMAXPROCS(-1))
 	}
 }
diff --git a/src/text/scanner/scanner.go b/src/text/scanner/scanner.go
index 3ab01ed..5199ee4 100644
--- a/src/text/scanner/scanner.go
+++ b/src/text/scanner/scanner.go
@@ -12,6 +12,17 @@
 // literals as defined by the Go language specification.  It may be
 // customized to recognize only a subset of those literals and to recognize
 // different identifier and white space characters.
+//
+// Basic usage pattern:
+//
+//	var s scanner.Scanner
+//	s.Init(src)
+//	tok := s.Scan()
+//	for tok != scanner.EOF {
+//		// do something with tok
+//		tok = s.Scan()
+//	}
+//
 package scanner
 
 import (
@@ -32,7 +43,7 @@ type Position struct {
 	Column   int    // column number, starting at 1 (character count per line)
 }
 
-// IsValid reports whether the position is valid.
+// IsValid returns true if the position is valid.
 func (pos *Position) IsValid() bool { return pos.Line > 0 }
 
 func (pos Position) String() string {
@@ -197,7 +208,7 @@ func (s *Scanner) Init(src io.Reader) *Scanner {
 	s.tokPos = -1
 
 	// initialize one character look-ahead
-	s.ch = -2 // no char read yet, not EOF
+	s.ch = -1 // no char read yet
 
 	// initialize public fields
 	s.Error = nil
@@ -303,9 +314,7 @@ func (s *Scanner) Next() rune {
 	s.tokPos = -1 // don't collect token text
 	s.Line = 0    // invalidate token position
 	ch := s.Peek()
-	if ch != EOF {
-		s.ch = s.next()
-	}
+	s.ch = s.next()
 	return ch
 }
 
@@ -313,7 +322,7 @@ func (s *Scanner) Next() rune {
 // the scanner. It returns EOF if the scanner's position is at the last
 // character of the source.
 func (s *Scanner) Peek() rune {
-	if s.ch == -2 {
+	if s.ch < 0 {
 		// this code is only run for the very first character
 		s.ch = s.next()
 		if s.ch == '\uFEFF' {
@@ -588,8 +597,6 @@ redo:
 		}
 	default:
 		switch ch {
-		case EOF:
-			break
 		case '"':
 			if s.Mode&ScanStrings != 0 {
 				s.scanString('"')
diff --git a/src/text/scanner/scanner_test.go b/src/text/scanner/scanner_test.go
index 798bed7..702fac2 100644
--- a/src/text/scanner/scanner_test.go
+++ b/src/text/scanner/scanner_test.go
@@ -616,52 +616,3 @@ func TestPos(t *testing.T) {
 		t.Errorf("%d errors", s.ErrorCount)
 	}
 }
-
-type countReader int
-
-func (r *countReader) Read([]byte) (int, error) {
-	*r++
-	return 0, io.EOF
-}
-
-func TestNextEOFHandling(t *testing.T) {
-	var r countReader
-
-	// corner case: empty source
-	s := new(Scanner).Init(&r)
-
-	tok := s.Next()
-	if tok != EOF {
-		t.Error("1) EOF not reported")
-	}
-
-	tok = s.Peek()
-	if tok != EOF {
-		t.Error("2) EOF not reported")
-	}
-
-	if r != 1 {
-		t.Errorf("scanner called Read %d times, not once", r)
-	}
-}
-
-func TestScanEOFHandling(t *testing.T) {
-	var r countReader
-
-	// corner case: empty source
-	s := new(Scanner).Init(&r)
-
-	tok := s.Scan()
-	if tok != EOF {
-		t.Error("1) EOF not reported")
-	}
-
-	tok = s.Peek()
-	if tok != EOF {
-		t.Error("2) EOF not reported")
-	}
-
-	if r != 1 {
-		t.Errorf("scanner called Read %d times, not once", r)
-	}
-}
diff --git a/src/text/template/doc.go b/src/text/template/doc.go
index 0ce63f6..223c595 100644
--- a/src/text/template/doc.go
+++ b/src/text/template/doc.go
@@ -18,7 +18,7 @@ structure as execution proceeds.
 The input text for a template is UTF-8-encoded text in any format.
 "Actions"--data evaluations or control structures--are delimited by
 "{{" and "}}"; all text outside actions is copied to the output unchanged.
-Except for raw strings, actions may not span newlines, although comments can.
+Actions may not span newlines, although comments can.
 
 Once parsed, a template may be executed safely in parallel.
 
@@ -106,7 +106,7 @@ An argument is a simple value, denoted by one of the following.
 
 	- A boolean, string, character, integer, floating-point, imaginary
 	  or complex constant in Go syntax. These behave like Go's untyped
-	  constants.
+	  constants, although raw strings may not span newlines.
 	- The keyword nil, representing an untyped Go nil.
 	- The character '.' (period):
 		.
diff --git a/src/text/template/exec.go b/src/text/template/exec.go
index daba788..b00e10c 100644
--- a/src/text/template/exec.go
+++ b/src/text/template/exec.go
@@ -113,10 +113,7 @@ func errRecover(errp *error) {
 // the output writer.
 // A template may be executed safely in parallel.
 func (t *Template) ExecuteTemplate(wr io.Writer, name string, data interface{}) error {
-	var tmpl *Template
-	if t.common != nil {
-		tmpl = t.tmpl[name]
-	}
+	tmpl := t.tmpl[name]
 	if tmpl == nil {
 		return fmt.Errorf("template: no template %q associated with template %q", name, t.name)
 	}
@@ -137,36 +134,26 @@ func (t *Template) Execute(wr io.Writer, data interface{}) (err error) {
 		wr:   wr,
 		vars: []variable{{"$", value}},
 	}
+	t.init()
 	if t.Tree == nil || t.Root == nil {
-		state.errorf("%q is an incomplete or empty template%s", t.Name(), t.DefinedTemplates())
-	}
-	state.walk(value, t.Root)
-	return
-}
-
-// DefinedTemplates returns a string listing the defined templates,
-// prefixed by the string "defined templates are: ". If there are none,
-// it returns the empty string. For generating an error message here
-// and in html/template.
-func (t *Template) DefinedTemplates() string {
-	if t.common == nil {
-		return ""
-	}
-	var b bytes.Buffer
-	for name, tmpl := range t.tmpl {
-		if tmpl.Tree == nil || tmpl.Root == nil {
-			continue
+		var b bytes.Buffer
+		for name, tmpl := range t.tmpl {
+			if tmpl.Tree == nil || tmpl.Root == nil {
+				continue
+			}
+			if b.Len() > 0 {
+				b.WriteString(", ")
+			}
+			fmt.Fprintf(&b, "%q", name)
 		}
+		var s string
 		if b.Len() > 0 {
-			b.WriteString(", ")
+			s = "; defined templates are: " + b.String()
 		}
-		fmt.Fprintf(&b, "%q", name)
-	}
-	var s string
-	if b.Len() > 0 {
-		s = "; defined templates are: " + b.String()
+		state.errorf("%q is an incomplete or empty template%s", t.Name(), s)
 	}
-	return s
+	state.walk(value, t.Root)
+	return
 }
 
 // Walk functions step through the major pieces of the template structure,
@@ -431,14 +418,11 @@ func (s *state) evalFieldNode(dot reflect.Value, field *parse.FieldNode, args []
 
 func (s *state) evalChainNode(dot reflect.Value, chain *parse.ChainNode, args []parse.Node, final reflect.Value) reflect.Value {
 	s.at(chain)
+	// (pipe).Field1.Field2 has pipe as .Node, fields as .Field. Eval the pipeline, then the fields.
+	pipe := s.evalArg(dot, nil, chain.Node)
 	if len(chain.Field) == 0 {
 		s.errorf("internal error: no fields in evalChainNode")
 	}
-	if chain.Node.Type() == parse.NodeNil {
-		s.errorf("indirection through explicit nil in %s", chain)
-	}
-	// (pipe).Field1.Field2 has pipe as .Node, fields as .Field. Eval the pipeline, then the fields.
-	pipe := s.evalArg(dot, nil, chain.Node)
 	return s.evalFieldChain(dot, pipe, chain, chain.Field, args, final)
 }
 
@@ -521,18 +505,7 @@ func (s *state) evalField(dot reflect.Value, fieldName string, node parse.Node,
 			if hasArgs {
 				s.errorf("%s is not a method but has arguments", fieldName)
 			}
-			result := receiver.MapIndex(nameVal)
-			if !result.IsValid() {
-				switch s.tmpl.option.missingKey {
-				case mapInvalid:
-					// Just use the invalid value.
-				case mapZeroValue:
-					result = reflect.Zero(receiver.Type().Elem())
-				case mapError:
-					s.errorf("map has no entry for key %q", fieldName)
-				}
-			}
-			return result
+			return receiver.MapIndex(nameVal)
 		}
 	}
 	s.errorf("can't evaluate field %s in type %s", fieldName, typ)
@@ -587,15 +560,7 @@ func (s *state) evalCall(dot, fun reflect.Value, node parse.Node, name string, a
 	if final.IsValid() {
 		t := typ.In(typ.NumIn() - 1)
 		if typ.IsVariadic() {
-			if numIn-1 < numFixed {
-				// The added final argument corresponds to a fixed parameter of the function.
-				// Validate against the type of the actual parameter.
-				t = typ.In(numIn - 1)
-			} else {
-				// The added final argument corresponds to the variadic part.
-				// Validate against the type of the elements of the variadic slice.
-				t = t.Elem()
-			}
+			t = t.Elem()
 		}
 		argv[i] = s.validateType(final, t)
 	}
@@ -670,7 +635,7 @@ func (s *state) evalArg(dot reflect.Value, typ reflect.Type, n parse.Node) refle
 	case *parse.PipeNode:
 		return s.validateType(s.evalPipeline(dot, arg), typ)
 	case *parse.IdentifierNode:
-		return s.validateType(s.evalFunction(dot, arg, arg, nil, zero), typ)
+		return s.evalFunction(dot, arg, arg, nil, zero)
 	case *parse.ChainNode:
 		return s.validateType(s.evalChainNode(dot, arg, nil, zero), typ)
 	}
diff --git a/src/text/template/exec_test.go b/src/text/template/exec_test.go
index ba0e434..69c213e 100644
--- a/src/text/template/exec_test.go
+++ b/src/text/template/exec_test.go
@@ -527,24 +527,6 @@ var execTests = []execTest{
 	{"bug12XE", "{{printf `%T` 0XEE}}", "int", T{}, true},
 	// Chained nodes did not work as arguments. Issue 8473.
 	{"bug13", "{{print (.Copy).I}}", "17", tVal, true},
-	// Didn't protect against nil or literal values in field chains.
-	{"bug14a", "{{(nil).True}}", "", tVal, false},
-	{"bug14b", "{{$x := nil}}{{$x.anything}}", "", tVal, false},
-	{"bug14c", `{{$x := (1.0)}}{{$y := ("hello")}}{{$x.anything}}{{$y.true}}`, "", tVal, false},
-	// Didn't call validateType on function results. Issue 10800.
-	{"bug15", "{{valueString returnInt}}", "", tVal, false},
-	// Variadic function corner cases. Issue 10946.
-	{"bug16a", "{{true|printf}}", "", tVal, false},
-	{"bug16b", "{{1|printf}}", "", tVal, false},
-	{"bug16c", "{{1.1|printf}}", "", tVal, false},
-	{"bug16d", "{{'x'|printf}}", "", tVal, false},
-	{"bug16e", "{{0i|printf}}", "", tVal, false},
-	{"bug16f", "{{true|twoArgs \"xxx\"}}", "", tVal, false},
-	{"bug16g", "{{\"aaa\" |twoArgs \"bbb\"}}", "twoArgs=bbbaaa", tVal, true},
-	{"bug16h", "{{1|oneArg}}", "", tVal, false},
-	{"bug16i", "{{\"aaa\"|oneArg}}", "oneArg=aaa", tVal, true},
-	{"bug16j", "{{1+2i|printf \"%v\"}}", "(1+2i)", tVal, true},
-	{"bug16k", "{{\"aaa\"|printf }}", "aaa", tVal, true},
 }
 
 func zeroArgs() string {
@@ -555,10 +537,6 @@ func oneArg(a string) string {
 	return "oneArg=" + a
 }
 
-func twoArgs(a, b string) string {
-	return "twoArgs=" + a + b
-}
-
 func dddArg(a int, b ...string) string {
 	return fmt.Sprintln(a, b)
 }
@@ -588,11 +566,6 @@ func valueString(v string) string {
 	return "value is ignored"
 }
 
-// returnInt returns an int
-func returnInt() int {
-	return 7
-}
-
 func add(args ...int) int {
 	sum := 0
 	for _, x := range args {
@@ -634,9 +607,7 @@ func testExecute(execTests []execTest, template *Template, t *testing.T) {
 		"makemap":     makemap,
 		"mapOfThree":  mapOfThree,
 		"oneArg":      oneArg,
-		"returnInt":   returnInt,
 		"stringer":    stringer,
-		"twoArgs":     twoArgs,
 		"typeOf":      typeOf,
 		"valueString": valueString,
 		"vfunc":       vfunc,
@@ -882,13 +853,7 @@ func TestTree(t *testing.T) {
 
 func TestExecuteOnNewTemplate(t *testing.T) {
 	// This is issue 3872.
-	New("Name").Templates()
-	// This is issue 11379.
-	new(Template).Templates()
-	new(Template).Parse("")
-	new(Template).New("abc").Parse("")
-	new(Template).Execute(nil, nil)                // returns an error (but does not crash)
-	new(Template).ExecuteTemplate(nil, "XXX", nil) // returns an error (but does not crash)
+	_ = New("Name").Templates()
 }
 
 const testTemplates = `{{define "one"}}one{{end}}{{define "two"}}two{{end}}`
@@ -1077,67 +1042,3 @@ func TestComparison(t *testing.T) {
 		}
 	}
 }
-
-func TestMissingMapKey(t *testing.T) {
-	data := map[string]int{
-		"x": 99,
-	}
-	tmpl, err := New("t1").Parse("{{.x}} {{.y}}")
-	if err != nil {
-		t.Fatal(err)
-	}
-	var b bytes.Buffer
-	// By default, just get "<no value>"
-	err = tmpl.Execute(&b, data)
-	if err != nil {
-		t.Fatal(err)
-	}
-	want := "99 <no value>"
-	got := b.String()
-	if got != want {
-		t.Errorf("got %q; expected %q", got, want)
-	}
-	// Same if we set the option explicitly to the default.
-	tmpl.Option("missingkey=default")
-	b.Reset()
-	err = tmpl.Execute(&b, data)
-	if err != nil {
-		t.Fatal("default:", err)
-	}
-	want = "99 <no value>"
-	got = b.String()
-	if got != want {
-		t.Errorf("got %q; expected %q", got, want)
-	}
-	// Next we ask for a zero value
-	tmpl.Option("missingkey=zero")
-	b.Reset()
-	err = tmpl.Execute(&b, data)
-	if err != nil {
-		t.Fatal("zero:", err)
-	}
-	want = "99 0"
-	got = b.String()
-	if got != want {
-		t.Errorf("got %q; expected %q", got, want)
-	}
-	// Now we ask for an error.
-	tmpl.Option("missingkey=error")
-	err = tmpl.Execute(&b, data)
-	if err == nil {
-		t.Errorf("expected error; got none")
-	}
-}
-
-// Test that the error message for multiline unterminated string
-// refers to the line number of the opening quote.
-func TestUnterminatedStringError(t *testing.T) {
-	_, err := New("X").Parse("hello\n\n{{`unterminated\n\n\n\n}}\n some more\n\n")
-	if err == nil {
-		t.Fatal("expected error")
-	}
-	str := err.Error()
-	if !strings.Contains(str, "X:3: unexpected unterminated raw quoted strin") {
-		t.Fatalf("unexpected error: %s", str)
-	}
-}
diff --git a/src/text/template/funcs.go b/src/text/template/funcs.go
index ccd0dfc..39ee5ed 100644
--- a/src/text/template/funcs.go
+++ b/src/text/template/funcs.go
@@ -92,8 +92,6 @@ func goodFunc(typ reflect.Type) bool {
 // findFunction looks for a function in the template, and global map.
 func findFunction(name string, tmpl *Template) (reflect.Value, bool) {
 	if tmpl != nil && tmpl.common != nil {
-		tmpl.muFuncs.RLock()
-		defer tmpl.muFuncs.RUnlock()
 		if fn := tmpl.execFuncs[name]; fn.IsValid() {
 			return fn, true
 		}
@@ -592,7 +590,7 @@ func evalArgs(args []interface{}) string {
 			a, ok := printableValue(reflect.ValueOf(arg))
 			if ok {
 				args[i] = a
-			} // else let fmt do its thing
+			} // else left fmt do its thing
 		}
 		s = fmt.Sprint(args...)
 	}
diff --git a/src/text/template/helper.go b/src/text/template/helper.go
index 787ca62..3636fb5 100644
--- a/src/text/template/helper.go
+++ b/src/text/template/helper.go
@@ -26,8 +26,8 @@ func Must(t *Template, err error) *Template {
 }
 
 // ParseFiles creates a new Template and parses the template definitions from
-// the named files. The returned template's name will have the base name and
-// parsed contents of the first file. There must be at least one file.
+// the named files. The returned template's name will have the (base) name and
+// (parsed) contents of the first file. There must be at least one file.
 // If an error occurs, parsing stops and the returned *Template is nil.
 func ParseFiles(filenames ...string) (*Template, error) {
 	return parseFiles(nil, filenames...)
@@ -36,13 +36,7 @@ func ParseFiles(filenames ...string) (*Template, error) {
 // ParseFiles parses the named files and associates the resulting templates with
 // t. If an error occurs, parsing stops and the returned template is nil;
 // otherwise it is t. There must be at least one file.
-// Since the templates created by ParseFiles are named by the base
-// names of the argument files, t should usually have the name of one
-// of the (base) names of the files. If it does not, depending on t's
-// contents before calling ParseFiles, t.Execute may fail. In that
-// case use t.ExecuteTemplate to execute a valid template.
 func (t *Template) ParseFiles(filenames ...string) (*Template, error) {
-	t.init()
 	return parseFiles(t, filenames...)
 }
 
@@ -98,7 +92,6 @@ func ParseGlob(pattern string) (*Template, error) {
 // equivalent to calling t.ParseFiles with the list of files matched by the
 // pattern.
 func (t *Template) ParseGlob(pattern string) (*Template, error) {
-	t.init()
 	return parseGlob(t, pattern)
 }
 
diff --git a/src/text/template/multi_test.go b/src/text/template/multi_test.go
index ea01875..e4e8048 100644
--- a/src/text/template/multi_test.go
+++ b/src/text/template/multi_test.go
@@ -290,76 +290,3 @@ func TestRedefinition(t *testing.T) {
 		t.Fatalf("expected redefinition error; got %v", err)
 	}
 }
-
-// Issue 10879
-func TestEmptyTemplateCloneCrash(t *testing.T) {
-	t1 := New("base")
-	t1.Clone() // used to panic
-}
-
-// Issue 10910, 10926
-func TestTemplateLookUp(t *testing.T) {
-	t1 := New("foo")
-	if t1.Lookup("foo") != nil {
-		t.Error("Lookup returned non-nil value for undefined template foo")
-	}
-	t1.New("bar")
-	if t1.Lookup("bar") != nil {
-		t.Error("Lookup returned non-nil value for undefined template bar")
-	}
-	t1.Parse(`{{define "foo"}}test{{end}}`)
-	if t1.Lookup("foo") == nil {
-		t.Error("Lookup returned nil value for defined template")
-	}
-}
-
-func TestNew(t *testing.T) {
-	// template with same name already exists
-	t1, _ := New("test").Parse(`{{define "test"}}foo{{end}}`)
-	t2 := t1.New("test")
-
-	if t1.common != t2.common {
-		t.Errorf("t1 & t2 didn't share common struct; got %v != %v", t1.common, t2.common)
-	}
-	if t1.Tree == nil {
-		t.Error("defined template got nil Tree")
-	}
-	if t2.Tree != nil {
-		t.Error("undefined template got non-nil Tree")
-	}
-
-	containsT1 := false
-	for _, tmpl := range t1.Templates() {
-		if tmpl == t2 {
-			t.Error("Templates included undefined template")
-		}
-		if tmpl == t1 {
-			containsT1 = true
-		}
-	}
-	if !containsT1 {
-		t.Error("Templates didn't include defined template")
-	}
-}
-
-func TestParse(t *testing.T) {
-	// In multiple calls to Parse with the same receiver template, only one call
-	// can contain text other than space, comments, and template definitions
-	var err error
-	t1 := New("test")
-	if _, err := t1.Parse(`{{define "test"}}{{end}}`); err != nil {
-		t.Fatalf("parsing test: %s", err)
-	}
-	if _, err := t1.Parse(`{{define "test"}}{{/* this is a comment */}}{{end}}`); err != nil {
-		t.Fatalf("parsing test: %s", err)
-	}
-	if _, err := t1.Parse(`{{define "test"}}foo{{end}}`); err != nil {
-		t.Fatalf("parsing test: %s", err)
-	}
-	if _, err = t1.Parse(`{{define "test"}}foo{{end}}`); err == nil {
-		t.Fatal("no error from redefining a template")
-	}
-	if !strings.Contains(err.Error(), "redefinition") {
-		t.Fatalf("expected redefinition error; got %v", err)
-	}
-}
diff --git a/src/text/template/parse/lex.go b/src/text/template/parse/lex.go
index 8f9fe1d..1674aaf 100644
--- a/src/text/template/parse/lex.go
+++ b/src/text/template/parse/lex.go
@@ -167,20 +167,12 @@ func (l *lexer) errorf(format string, args ...interface{}) stateFn {
 }
 
 // nextItem returns the next item from the input.
-// Called by the parser, not in the lexing goroutine.
 func (l *lexer) nextItem() item {
 	item := <-l.items
 	l.lastPos = item.pos
 	return item
 }
 
-// drain drains the output so the lexing goroutine will exit.
-// Called by the parser, not in the lexing goroutine.
-func (l *lexer) drain() {
-	for range l.items {
-	}
-}
-
 // lex creates a new scanner for the input string.
 func lex(name, input, left, right string) *lexer {
 	if left == "" {
@@ -205,7 +197,6 @@ func (l *lexer) run() {
 	for l.state = lexText; l.state != nil; {
 		l.state = l.state(l)
 	}
-	close(l.items)
 }
 
 // state functions
@@ -322,12 +313,14 @@ func lexInsideAction(l *lexer) stateFn {
 	case r == '(':
 		l.emit(itemLeftParen)
 		l.parenDepth++
+		return lexInsideAction
 	case r == ')':
 		l.emit(itemRightParen)
 		l.parenDepth--
 		if l.parenDepth < 0 {
 			return l.errorf("unexpected right paren %#U", r)
 		}
+		return lexInsideAction
 	case r <= unicode.MaxASCII && unicode.IsPrint(r):
 		l.emit(itemChar)
 		return lexInsideAction
@@ -532,7 +525,7 @@ func lexRawQuote(l *lexer) stateFn {
 Loop:
 	for {
 		switch l.next() {
-		case eof:
+		case eof, '\n':
 			return l.errorf("unterminated raw quoted string")
 		case '`':
 			break Loop
diff --git a/src/text/template/parse/lex_test.go b/src/text/template/parse/lex_test.go
index be551d8..d251ccf 100644
--- a/src/text/template/parse/lex_test.go
+++ b/src/text/template/parse/lex_test.go
@@ -58,20 +58,18 @@ type lexTest struct {
 }
 
 var (
-	tEOF        = item{itemEOF, 0, ""}
-	tFor        = item{itemIdentifier, 0, "for"}
-	tLeft       = item{itemLeftDelim, 0, "{{"}
-	tLpar       = item{itemLeftParen, 0, "("}
-	tPipe       = item{itemPipe, 0, "|"}
-	tQuote      = item{itemString, 0, `"abc \n\t\" "`}
-	tRange      = item{itemRange, 0, "range"}
-	tRight      = item{itemRightDelim, 0, "}}"}
-	tRpar       = item{itemRightParen, 0, ")"}
-	tSpace      = item{itemSpace, 0, " "}
-	raw         = "`" + `abc\n\t\" ` + "`"
-	rawNL       = "`now is{{\n}}the time`" // Contains newline inside raw quote.
-	tRawQuote   = item{itemRawString, 0, raw}
-	tRawQuoteNL = item{itemRawString, 0, rawNL}
+	tEOF      = item{itemEOF, 0, ""}
+	tFor      = item{itemIdentifier, 0, "for"}
+	tLeft     = item{itemLeftDelim, 0, "{{"}
+	tLpar     = item{itemLeftParen, 0, "("}
+	tPipe     = item{itemPipe, 0, "|"}
+	tQuote    = item{itemString, 0, `"abc \n\t\" "`}
+	tRange    = item{itemRange, 0, "range"}
+	tRight    = item{itemRightDelim, 0, "}}"}
+	tRpar     = item{itemRightParen, 0, ")"}
+	tSpace    = item{itemSpace, 0, " "}
+	raw       = "`" + `abc\n\t\" ` + "`"
+	tRawQuote = item{itemRawString, 0, raw}
 )
 
 var lexTests = []lexTest{
@@ -106,7 +104,6 @@ var lexTests = []lexTest{
 	{"for", `{{for}}`, []item{tLeft, tFor, tRight, tEOF}},
 	{"quote", `{{"abc \n\t\" "}}`, []item{tLeft, tQuote, tRight, tEOF}},
 	{"raw quote", "{{" + raw + "}}", []item{tLeft, tRawQuote, tRight, tEOF}},
-	{"raw quote with newline", "{{" + rawNL + "}}", []item{tLeft, tRawQuoteNL, tRight, tEOF}},
 	{"numbers", "{{1 02 0x14 -7.2i 1e3 +1.2e-4 4.2i 1+2i}}", []item{
 		tLeft,
 		{itemNumber, 0, "1"},
@@ -297,7 +294,7 @@ var lexTests = []lexTest{
 		tLeft,
 		{itemError, 0, "unterminated quoted string"},
 	}},
-	{"unclosed raw quote", "{{`xx}}", []item{
+	{"unclosed raw quote", "{{`xx\n`}}", []item{
 		tLeft,
 		{itemError, 0, "unterminated raw quoted string"},
 	}},
@@ -466,31 +463,3 @@ func TestPos(t *testing.T) {
 		}
 	}
 }
-
-// Test that an error shuts down the lexing goroutine.
-func TestShutdown(t *testing.T) {
-	// We need to duplicate template.Parse here to hold on to the lexer.
-	const text = "erroneous{{define}}{{else}}1234"
-	lexer := lex("foo", text, "{{", "}}")
-	_, err := New("root").parseLexer(lexer, text)
-	if err == nil {
-		t.Fatalf("expected error")
-	}
-	// The error should have drained the input. Therefore, the lexer should be shut down.
-	token, ok := <-lexer.items
-	if ok {
-		t.Fatalf("input was not drained; got %v", token)
-	}
-}
-
-// parseLexer is a local version of parse that lets us pass in the lexer instead of building it.
-// We expect an error, so the tree set and funcs list are explicitly nil.
-func (t *Tree) parseLexer(lex *lexer, text string) (tree *Tree, err error) {
-	defer t.recover(&err)
-	t.ParseName = t.Name
-	t.startParse(nil, lex)
-	t.parse(nil)
-	t.add(nil)
-	t.stopParse()
-	return t, nil
-}
diff --git a/src/text/template/parse/node.go b/src/text/template/parse/node.go
index 55ff46c..55c37f6 100644
--- a/src/text/template/parse/node.go
+++ b/src/text/template/parse/node.go
@@ -145,7 +145,7 @@ type PipeNode struct {
 	NodeType
 	Pos
 	tr   *Tree
-	Line int             // The line number in the input. Deprecated: Kept for compatibility.
+	Line int             // The line number in the input (deprecated; kept for compatibility)
 	Decl []*VariableNode // Variable declarations in lexical order.
 	Cmds []*CommandNode  // The commands in lexical order.
 }
@@ -208,7 +208,7 @@ type ActionNode struct {
 	NodeType
 	Pos
 	tr   *Tree
-	Line int       // The line number in the input. Deprecated: Kept for compatibility.
+	Line int       // The line number in the input (deprecated; kept for compatibility)
 	Pipe *PipeNode // The pipeline in the action.
 }
 
@@ -592,11 +592,6 @@ func (t *Tree) newNumber(pos Pos, text string, typ itemType) (*NumberNode, error
 	} else {
 		f, err := strconv.ParseFloat(text, 64)
 		if err == nil {
-			// If we parsed it as a float but it looks like an integer,
-			// it's a huge number too large to fit in an int. Reject it.
-			if !strings.ContainsAny(text, ".eE") {
-				return nil, fmt.Errorf("integer overflow: %q", text)
-			}
 			n.IsFloat = true
 			n.Float64 = f
 			// If a floating-point extraction succeeded, extract the int if needed.
@@ -701,7 +696,7 @@ type elseNode struct {
 	NodeType
 	Pos
 	tr   *Tree
-	Line int // The line number in the input. Deprecated: Kept for compatibility.
+	Line int // The line number in the input (deprecated; kept for compatibility)
 }
 
 func (t *Tree) newElse(pos Pos, line int) *elseNode {
@@ -729,7 +724,7 @@ type BranchNode struct {
 	NodeType
 	Pos
 	tr       *Tree
-	Line     int       // The line number in the input. Deprecated: Kept for compatibility.
+	Line     int       // The line number in the input (deprecated; kept for compatibility)
 	Pipe     *PipeNode // The pipeline to be evaluated.
 	List     *ListNode // What to execute if the value is non-empty.
 	ElseList *ListNode // What to execute if the value is empty (nil if absent).
@@ -814,7 +809,7 @@ type TemplateNode struct {
 	NodeType
 	Pos
 	tr   *Tree
-	Line int       // The line number in the input. Deprecated: Kept for compatibility.
+	Line int       // The line number in the input (deprecated; kept for compatibility)
 	Name string    // The name of the template (unquoted).
 	Pipe *PipeNode // The command to evaluate as dot for the template.
 }
diff --git a/src/text/template/parse/parse.go b/src/text/template/parse/parse.go
index 88aacd1..af33880 100644
--- a/src/text/template/parse/parse.go
+++ b/src/text/template/parse/parse.go
@@ -196,7 +196,6 @@ func (t *Tree) recover(errp *error) {
 			panic(e)
 		}
 		if t != nil {
-			t.lex.drain()
 			t.stopParse()
 		}
 		*errp = e.(error)
@@ -289,12 +288,11 @@ func (t *Tree) parse(treeSet map[string]*Tree) (next Node) {
 			}
 			t.backup2(delim)
 		}
-		switch n := t.textOrAction(); n.Type() {
-		case nodeEnd, nodeElse:
+		n := t.textOrAction()
+		if n.Type() == nodeEnd {
 			t.errorf("unexpected %s", n)
-		default:
-			t.Root.append(n)
 		}
+		t.Root.append(n)
 	}
 	return nil
 }
@@ -413,8 +411,9 @@ func (t *Tree) pipeline(context string) (pipe *PipeNode) {
 	for {
 		switch token := t.nextNonSpace(); token.typ {
 		case itemRightDelim, itemRightParen:
-			// At this point, the pipeline is complete
-			t.checkPipeline(pipe, context)
+			if len(pipe.Cmds) == 0 {
+				t.errorf("missing value for %s", context)
+			}
 			if token.typ == itemRightParen {
 				t.backup()
 			}
@@ -429,21 +428,6 @@ func (t *Tree) pipeline(context string) (pipe *PipeNode) {
 	}
 }
 
-func (t *Tree) checkPipeline(pipe *PipeNode, context string) {
-	// Reject empty pipelines
-	if len(pipe.Cmds) == 0 {
-		t.errorf("missing value for %s", context)
-	}
-	// Only the first command of a pipeline can start with a non executable operand
-	for i, c := range pipe.Cmds[1:] {
-		switch c.Args[0].Type() {
-		case NodeBool, NodeDot, NodeNil, NodeNumber, NodeString:
-			// With A|B|C, pipeline stage 2 is B
-			t.errorf("non executable command in pipeline stage %d", i+2)
-		}
-	}
-}
-
 func (t *Tree) parseControl(allowElseIf bool, context string) (pos Pos, line int, pipe *PipeNode, list, elseList *ListNode) {
 	defer t.popVars(len(t.vars))
 	line = t.lex.lineNumber()
@@ -569,7 +553,7 @@ func (t *Tree) command() *CommandNode {
 			t.backup()
 		case itemPipe:
 		default:
-			t.errorf("unexpected %s in operand", token)
+			t.errorf("unexpected %s in operand; missing space?", token)
 		}
 		break
 	}
@@ -597,15 +581,12 @@ func (t *Tree) operand() Node {
 		// Compatibility with original API: If the term is of type NodeField
 		// or NodeVariable, just put more fields on the original.
 		// Otherwise, keep the Chain node.
-		// Obvious parsing errors involving literal values are detected here.
-		// More complex error cases will have to be handled at execution time.
+		// TODO: Switch to Chains always when we can.
 		switch node.Type() {
 		case NodeField:
 			node = t.newField(chain.Position(), chain.String())
 		case NodeVariable:
 			node = t.newVariable(chain.Position(), chain.String())
-		case NodeBool, NodeString, NodeNumber, NodeNil, NodeDot:
-			t.errorf("unexpected . after term %q", node.String())
 		default:
 			node = chain
 		}
diff --git a/src/text/template/parse/parse_test.go b/src/text/template/parse/parse_test.go
index 200d50c..4a504fa 100644
--- a/src/text/template/parse/parse_test.go
+++ b/src/text/template/parse/parse_test.go
@@ -69,7 +69,6 @@ var numberTests = []numberTest{
 	{text: "1+2."},
 	{text: "'x"},
 	{text: "'xx'"},
-	{text: "'433937734937734969526500969526500'"}, // Integer too large - issue 10634.
 	// Issue 8622 - 0xe parsed as floating point. Very embarrassing.
 	{"0xef", true, true, true, false, 0xef, 0xef, 0xef, 0},
 }
@@ -231,9 +230,6 @@ var parseTests = []parseTest{
 	// Errors.
 	{"unclosed action", "hello{{range", hasError, ""},
 	{"unmatched end", "{{end}}", hasError, ""},
-	{"unmatched else", "{{else}}", hasError, ""},
-	{"unmatched else after if", "{{if .X}}hello{{end}}{{else}}", hasError, ""},
-	{"multiple else", "{{if .X}}1{{else}}2{{else}}3{{end}}", hasError, ""},
 	{"missing end", "hello{{range .x}}", hasError, ""},
 	{"missing end after else", "hello{{range .x}}{{else}}", hasError, ""},
 	{"undefined function", "hello{{undefined}}", hasError, ""},
@@ -261,22 +257,6 @@ var parseTests = []parseTest{
 	{"bug1a", "{{$x:=.}}{{$x!2}}", hasError, ""},                     // ! is just illegal here.
 	{"bug1b", "{{$x:=.}}{{$x+2}}", hasError, ""},                     // $x+2 should not parse as ($x) (+2).
 	{"bug1c", "{{$x:=.}}{{$x +2}}", noError, "{{$x := .}}{{$x +2}}"}, // It's OK with a space.
-	// dot following a literal value
-	{"dot after integer", "{{1.E}}", hasError, ""},
-	{"dot after float", "{{0.1.E}}", hasError, ""},
-	{"dot after boolean", "{{true.E}}", hasError, ""},
-	{"dot after char", "{{'a'.any}}", hasError, ""},
-	{"dot after string", `{{"hello".guys}}`, hasError, ""},
-	{"dot after dot", "{{..E}}", hasError, ""},
-	{"dot after nil", "{{nil.E}}", hasError, ""},
-	// Wrong pipeline
-	{"wrong pipeline dot", "{{12|.}}", hasError, ""},
-	{"wrong pipeline number", "{{.|12|printf}}", hasError, ""},
-	{"wrong pipeline string", "{{.|printf|\"error\"}}", hasError, ""},
-	{"wrong pipeline char", "{{12|printf|'e'}}", hasError, ""},
-	{"wrong pipeline boolean", "{{.|true}}", hasError, ""},
-	{"wrong pipeline nil", "{{'c'|nil}}", hasError, ""},
-	{"empty pipeline", `{{printf "%d" ( ) }}`, hasError, ""},
 }
 
 var builtins = map[string]interface{}{
@@ -395,7 +375,7 @@ var errorTests = []parseTest{
 		hasError, `unexpected ")"`},
 	{"space",
 		"{{`x`3}}",
-		hasError, `in operand`},
+		hasError, `missing space?`},
 	{"idchar",
 		"{{a#}}",
 		hasError, `'#'`},
@@ -427,15 +407,6 @@ var errorTests = []parseTest{
 	{"undefvar",
 		"{{$a}}",
 		hasError, `undefined variable`},
-	{"wrongdot",
-		"{{true.any}}",
-		hasError, `unexpected . after term`},
-	{"wrongpipeline",
-		"{{12|false}}",
-		hasError, `non executable command in pipeline`},
-	{"emptypipeline",
-		`{{ ( ) }}`,
-		hasError, `missing value for parenthesized pipeline`},
 }
 
 func TestErrors(t *testing.T) {
diff --git a/src/text/template/template.go b/src/text/template/template.go
index 3e80982..249d0cb 100644
--- a/src/text/template/template.go
+++ b/src/text/template/template.go
@@ -7,18 +7,15 @@ package template
 import (
 	"fmt"
 	"reflect"
-	"sync"
 	"text/template/parse"
 )
 
 // common holds the information shared by related templates.
 type common struct {
-	tmpl   map[string]*Template // Map from name to defined templates.
-	option option
+	tmpl map[string]*Template
 	// We use two maps, one for parsing and one for execution.
 	// This separation makes the API cleaner since it doesn't
 	// expose reflection to the client.
-	muFuncs    sync.RWMutex // protects parseFuncs and execFuncs
 	parseFuncs FuncMap
 	execFuncs  map[string]reflect.Value
 }
@@ -34,13 +31,11 @@ type Template struct {
 	rightDelim string
 }
 
-// New allocates a new, undefined template with the given name.
+// New allocates a new template with the given name.
 func New(name string) *Template {
-	t := &Template{
+	return &Template{
 		name: name,
 	}
-	t.init()
-	return t
 }
 
 // Name returns the name of the template.
@@ -48,28 +43,25 @@ func (t *Template) Name() string {
 	return t.name
 }
 
-// New allocates a new, undefined template associated with the given one and with the same
+// New allocates a new template associated with the given one and with the same
 // delimiters. The association, which is transitive, allows one template to
 // invoke another with a {{template}} action.
 func (t *Template) New(name string) *Template {
 	t.init()
-	nt := &Template{
+	return &Template{
 		name:       name,
 		common:     t.common,
 		leftDelim:  t.leftDelim,
 		rightDelim: t.rightDelim,
 	}
-	return nt
 }
 
-// init guarantees that t has a valid common structure.
 func (t *Template) init() {
 	if t.common == nil {
-		c := new(common)
-		c.tmpl = make(map[string]*Template)
-		c.parseFuncs = make(FuncMap)
-		c.execFuncs = make(map[string]reflect.Value)
-		t.common = c
+		t.common = new(common)
+		t.tmpl = make(map[string]*Template)
+		t.parseFuncs = make(FuncMap)
+		t.execFuncs = make(map[string]reflect.Value)
 	}
 }
 
@@ -82,20 +74,15 @@ func (t *Template) init() {
 func (t *Template) Clone() (*Template, error) {
 	nt := t.copy(nil)
 	nt.init()
-	if t.common == nil {
-		return nt, nil
-	}
+	nt.tmpl[t.name] = nt
 	for k, v := range t.tmpl {
-		if k == t.name {
-			nt.tmpl[t.name] = nt
+		if k == t.name { // Already installed.
 			continue
 		}
 		// The associated templates share nt's common structure.
 		tmpl := v.copy(nt.common)
 		nt.tmpl[k] = tmpl
 	}
-	t.muFuncs.RLock()
-	defer t.muFuncs.RUnlock()
 	for k, v := range t.parseFuncs {
 		nt.parseFuncs[k] = v
 	}
@@ -115,27 +102,20 @@ func (t *Template) copy(c *common) *Template {
 	return nt
 }
 
-// AddParseTree adds parse tree for template with given name and associates it with t.
-// If the template does not already exist, it will create a new one.
-// It is an error to reuse a name except to overwrite an empty 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) {
-	t.init()
-	// If the name is the name of this template, overwrite this template.
-	// The associate method checks it's not a redefinition.
-	nt := t
-	if name != t.name {
-		nt = t.New(name)
-	}
-	// Even if nt == t, we need to install it in the common.tmpl map.
-	if replace, err := t.associate(nt, tree); err != nil {
-		return nil, err
-	} else if replace {
-		nt.Tree = tree
+	if t.common != nil && t.tmpl[name] != nil {
+		return nil, fmt.Errorf("template: redefinition of template %q", name)
 	}
+	nt := t.New(name)
+	nt.Tree = tree
+	t.tmpl[name] = nt
 	return nt, nil
 }
 
-// Templates returns a slice of defined templates associated with t.
+// Templates returns a slice of the templates associated with t, including t
+// itself.
 func (t *Template) Templates() []*Template {
 	if t.common == nil {
 		return nil
@@ -154,7 +134,6 @@ func (t *Template) Templates() []*Template {
 // corresponding default: {{ or }}.
 // The return value is the template, so calls can be chained.
 func (t *Template) Delims(left, right string) *Template {
-	t.init()
 	t.leftDelim = left
 	t.rightDelim = right
 	return t
@@ -166,15 +145,13 @@ func (t *Template) Delims(left, right string) *Template {
 // value is the template, so calls can be chained.
 func (t *Template) Funcs(funcMap FuncMap) *Template {
 	t.init()
-	t.muFuncs.Lock()
-	defer t.muFuncs.Unlock()
 	addValueFuncs(t.execFuncs, funcMap)
 	addFuncs(t.parseFuncs, funcMap)
 	return t
 }
 
-// Lookup returns the template with the given name that is associated with t.
-// It returns nil if there is no such template or the template has no definition.
+// Lookup returns the template with the given name that is associated with t,
+// or nil if there is no such template.
 func (t *Template) Lookup(name string) *Template {
 	if t.common == nil {
 		return nil
@@ -182,7 +159,7 @@ func (t *Template) Lookup(name string) *Template {
 	return t.tmpl[name]
 }
 
-// Parse defines the template by parsing the text. Nested template definitions will be
+// Parse parses a string into a template. Nested template definitions will be
 // associated with the top-level template t. Parse may be called multiple times
 // to parse definitions of templates to associate with t. It is an error if a
 // resulting template is non-empty (contains content other than template
@@ -191,17 +168,26 @@ func (t *Template) Lookup(name string) *Template {
 // can contain text other than space, comments, and template definitions.)
 func (t *Template) Parse(text string) (*Template, error) {
 	t.init()
-	t.muFuncs.RLock()
 	trees, err := parse.Parse(t.name, text, t.leftDelim, t.rightDelim, t.parseFuncs, builtins)
-	t.muFuncs.RUnlock()
 	if err != nil {
 		return nil, err
 	}
 	// Add the newly parsed trees, including the one for t, into our common structure.
 	for name, tree := range trees {
-		if _, err := t.AddParseTree(name, tree); err != nil {
+		// If the name we parsed is the name of this template, overwrite this template.
+		// The associate method checks it's not a redefinition.
+		tmpl := t
+		if name != t.name {
+			tmpl = t.New(name)
+		}
+		// Even if t == tmpl, we need to install it in the common.tmpl map.
+		if replace, err := t.associate(tmpl, tree); err != nil {
 			return nil, err
+		} else if replace {
+			tmpl.Tree = tree
 		}
+		tmpl.leftDelim = t.leftDelim
+		tmpl.rightDelim = t.rightDelim
 	}
 	return t, nil
 }
diff --git a/src/time/example_test.go b/src/time/example_test.go
index f76fdcd..a37e8b8 100644
--- a/src/time/example_test.go
+++ b/src/time/example_test.go
@@ -58,127 +58,17 @@ func ExampleDate() {
 }
 
 func ExampleTime_Format() {
-	// Parse a time value from a string in the standard Unix format.
-	t, err := time.Parse(time.UnixDate, "Sat Mar  7 11:06:39 PST 2015")
-	if err != nil { // Always check errors even if they should not happen.
-		panic(err)
-	}
-
-	// time.Time's Stringer method is useful without any format.
-	fmt.Println("default format:", t)
-
-	// Predefined constants in the package implement common layouts.
-	fmt.Println("Unix format:", t.Format(time.UnixDate))
-
-	// The time zone attached to the time value affects its output.
-	fmt.Println("Same, in UTC:", t.UTC().Format(time.UnixDate))
-
-	// The rest of this function demonstrates the properties of the
-	// layout string used in the format.
-
-	// The layout string used by the Parse function and Format method
-	// shows by example how the reference time should be represented.
-	// We stress that one must show how the reference time is formatted,
-	// not a time of the user's choosing. Thus each layout string is a
-	// representation of the time stamp,
-	//	Jan 2 15:04:05 2006 MST
-	// An easy way to remember this value is that it holds, when presented
-	// in this order, the values (lined up with the elements above):
-	//	  1 2  3  4  5    6  -7
-	// There are some wrinkles illustrated below.
-
-	// Most uses of Format and Parse use constant layout strings such as
-	// the ones defined in this package, but the interface is flexible,
-	// as these examples show.
-
-	// Define a helper function to make the examples' output look nice.
-	do := func(name, layout, want string) {
-		got := t.Format(layout)
-		if want != got {
-			fmt.Printf("error: for %q got %q; expected %q\n", layout, got, want)
-			return
-		}
-		fmt.Printf("%-15s %q gives %q\n", name, layout, got)
-	}
-
-	// Print a header in our output.
-	fmt.Printf("\nFormats:\n\n")
-
-	// A simple starter example.
-	do("Basic", "Mon Jan 2 15:04:05 MST 2006", "Sat Mar 7 11:06:39 PST 2015")
-
-	// For fixed-width printing of values, such as the date, that may be one or
-	// two characters (7 vs. 07), use an _ instead of a space in the layout string.
-	// Here we print just the day, which is 2 in our layout string and 7 in our
-	// value.
-	do("No pad", "<2>", "<7>")
-
-	// An underscore represents a zero pad, if required.
-	do("Spaces", "<_2>", "< 7>")
-
-	// Similarly, a 0 indicates zero padding.
-	do("Zeros", "<02>", "<07>")
-
-	// If the value is already the right width, padding is not used.
-	// For instance, the second (05 in the reference time) in our value is 39,
-	// so it doesn't need padding, but the minutes (04, 06) does.
-	do("Suppressed pad", "04:05", "06:39")
-
-	// The predefined constant Unix uses an underscore to pad the day.
-	// Compare with our simple starter example.
-	do("Unix", time.UnixDate, "Sat Mar  7 11:06:39 PST 2015")
-
-	// The hour of the reference time is 15, or 3PM. The layout can express
-	// it either way, and since our value is the morning we should see it as
-	// an AM time. We show both in one format string. Lower case too.
-	do("AM/PM", "3PM==3pm==15h", "11AM==11am==11h")
-
-	// When parsing, if the seconds value is followed by a decimal point
-	// and some digits, that is taken as a fraction of a second even if
-	// the layout string does not represent the fractional second.
-	// Here we add a fractional second to our time value used above.
-	t, err = time.Parse(time.UnixDate, "Sat Mar  7 11:06:39.1234 PST 2015")
-	if err != nil {
-		panic(err)
-	}
-	// It does not appear in the output if the layout string does not contain
-	// a representation of the fractional second.
-	do("No fraction", time.UnixDate, "Sat Mar  7 11:06:39 PST 2015")
-
-	// Fractional seconds can be printed by adding a run of 0s or 9s after
-	// a decimal point in the seconds value in the layout string.
-	// If the layout digits are 0s, the fractional second is of the specified
-	// width. Note that the output has a trailing zero.
-	do("0s for fraction", "15:04:05.00000", "11:06:39.12340")
-
-	// If the fraction in the layout is 9s, trailing zeros are dropped.
-	do("9s for fraction", "15:04:05.99999999", "11:06:39.1234")
-
+	// layout shows by example how the reference time should be represented.
+	const layout = "Jan 2, 2006 at 3:04pm (MST)"
+	t := time.Date(2009, time.November, 10, 15, 0, 0, 0, time.Local)
+	fmt.Println(t.Format(layout))
+	fmt.Println(t.UTC().Format(layout))
 	// Output:
-	// default format: 2015-03-07 11:06:39 -0800 PST
-	// Unix format: Sat Mar  7 11:06:39 PST 2015
-	// Same, in UTC: Sat Mar  7 19:06:39 UTC 2015
-	//
-	// Formats:
-	//
-	// Basic           "Mon Jan 2 15:04:05 MST 2006" gives "Sat Mar 7 11:06:39 PST 2015"
-	// No pad          "<2>" gives "<7>"
-	// Spaces          "<_2>" gives "< 7>"
-	// Zeros           "<02>" gives "<07>"
-	// Suppressed pad  "04:05" gives "06:39"
-	// Unix            "Mon Jan _2 15:04:05 MST 2006" gives "Sat Mar  7 11:06:39 PST 2015"
-	// AM/PM           "3PM==3pm==15h" gives "11AM==11am==11h"
-	// No fraction     "Mon Jan _2 15:04:05 MST 2006" gives "Sat Mar  7 11:06:39 PST 2015"
-	// 0s for fraction "15:04:05.00000" gives "11:06:39.12340"
-	// 9s for fraction "15:04:05.99999999" gives "11:06:39.1234"
-
+	// Nov 10, 2009 at 3:00pm (PST)
+	// Nov 10, 2009 at 11:00pm (UTC)
 }
 
 func ExampleParse() {
-	// See the example for time.Format for a thorough description of how
-	// to define the layout string to parse a time.Time value; Parse and
-	// Format use the same model to describe their input and output.
-
 	// longForm shows by example how the reference time would be represented in
 	// the desired layout.
 	const longForm = "Jan 2, 2006 at 3:04pm (MST)"
diff --git a/src/time/export_windows_test.go b/src/time/export_windows_test.go
index 6fd4509..7e689b8 100644
--- a/src/time/export_windows_test.go
+++ b/src/time/export_windows_test.go
@@ -8,7 +8,3 @@ func ForceAusForTesting() {
 	ResetLocalOnceForTest()
 	localOnce.Do(initAusTestingZone)
 }
-
-func ToEnglishName(stdname, dstname string) (string, error) {
-	return toEnglishName(stdname, dstname)
-}
diff --git a/src/time/format.go b/src/time/format.go
index 873d3ff..04e79f3 100644
--- a/src/time/format.go
+++ b/src/time/format.go
@@ -39,9 +39,6 @@ import "errors"
 // offset for the UTC zone.  Thus:
 //	Z0700  Z or ±hhmm
 //	Z07:00 Z or ±hh:mm
-//
-// The executable example for time.Format demonstrates the working
-// of the layout string in detail and is a good reference.
 const (
 	ANSIC       = "Mon Jan _2 15:04:05 2006"
 	UnixDate    = "Mon Jan _2 15:04:05 MST 2006"
@@ -291,7 +288,7 @@ var longMonthNames = []string{
 	"December",
 }
 
-// match reports whether s1 and s2 match ignoring case.
+// match returns true if s1 and s2 match ignoring case.
 // It is assumed s1 and s2 are the same length.
 func match(s1, s2 string) bool {
 	for i := 0; i < len(s1); i++ {
@@ -318,34 +315,36 @@ func lookup(tab []string, val string) (int, string, error) {
 	return -1, val, errBad
 }
 
-// appendInt appends the decimal form of x to b and returns the result.
-// If the decimal form (excluding sign) is shorter than width, the result is padded with leading 0's.
+// appendUint appends the decimal form of x to b and returns the result.
+// If x is a single-digit number and pad != 0, appendUint inserts the pad byte
+// before the digit.
 // Duplicates functionality in strconv, but avoids dependency.
-func appendInt(b []byte, x int, width int) []byte {
-	u := uint(x)
-	if x < 0 {
-		b = append(b, '-')
-		u = uint(-x)
+func appendUint(b []byte, x uint, pad byte) []byte {
+	if x < 10 {
+		if pad != 0 {
+			b = append(b, pad)
+		}
+		return append(b, byte('0'+x))
 	}
-
-	// Assemble decimal in reverse order.
-	var buf [20]byte
-	i := len(buf)
-	for u >= 10 {
-		i--
-		q := u / 10
-		buf[i] = byte('0' + u - q*10)
-		u = q
+	if x < 100 {
+		b = append(b, byte('0'+x/10))
+		b = append(b, byte('0'+x%10))
+		return b
 	}
-	i--
-	buf[i] = byte('0' + u)
 
-	// Add 0-padding.
-	for w := len(buf) - i; w < width; w++ {
-		b = append(b, '0')
+	var buf [32]byte
+	n := len(buf)
+	if x == 0 {
+		return append(b, '0')
 	}
-
-	return append(b, buf[i:]...)
+	for x >= 10 {
+		n--
+		buf[n] = byte(x%10 + '0')
+		x /= 10
+	}
+	n--
+	buf[n] = byte(x + '0')
+	return append(b, buf[n:]...)
 }
 
 // Never printed, just needs to be non-nil for return by atoi.
@@ -408,32 +407,11 @@ func (t Time) String() string {
 // would be displayed if it were the value; it serves as an example of the
 // desired output. The same display rules will then be applied to the time
 // value.
-//
-// A fractional second is represented by adding a period and zeros
-// to the end of the seconds section of layout string, as in "15:04:05.000"
-// to format a time stamp with millisecond precision.
-//
 // Predefined layouts ANSIC, UnixDate, RFC3339 and others describe standard
 // and convenient representations of the reference time. For more information
 // about the formats and the definition of the reference time, see the
 // documentation for ANSIC and the other constants defined by this package.
 func (t Time) Format(layout string) string {
-	const bufSize = 64
-	var b []byte
-	max := len(layout) + 10
-	if max < bufSize {
-		var buf [bufSize]byte
-		b = buf[:0]
-	} else {
-		b = make([]byte, 0, max)
-	}
-	b = t.AppendFormat(b, layout)
-	return string(b)
-}
-
-// AppendFormat is like Format but appends the textual
-// representation to b and returns the extended buffer.
-func (t Time) AppendFormat(b []byte, layout string) []byte {
 	var (
 		name, offset, abs = t.locabs()
 
@@ -443,7 +421,16 @@ func (t Time) AppendFormat(b []byte, layout string) []byte {
 		hour  int = -1
 		min   int
 		sec   int
+
+		b   []byte
+		buf [64]byte
 	)
+	max := len(layout) + 10
+	if max <= len(buf) {
+		b = buf[:0]
+	} else {
+		b = make([]byte, 0, max)
+	}
 	// Each iteration generates one std value.
 	for layout != "" {
 		prefix, std, suffix := nextStdChunk(layout)
@@ -471,56 +458,75 @@ func (t Time) AppendFormat(b []byte, layout string) []byte {
 			if y < 0 {
 				y = -y
 			}
-			b = appendInt(b, y%100, 2)
+			b = appendUint(b, uint(y%100), '0')
 		case stdLongYear:
-			b = appendInt(b, year, 4)
+			// Pad year to at least 4 digits.
+			y := year
+			switch {
+			case year <= -1000:
+				b = append(b, '-')
+				y = -y
+			case year <= -100:
+				b = append(b, "-0"...)
+				y = -y
+			case year <= -10:
+				b = append(b, "-00"...)
+				y = -y
+			case year < 0:
+				b = append(b, "-000"...)
+				y = -y
+			case year < 10:
+				b = append(b, "000"...)
+			case year < 100:
+				b = append(b, "00"...)
+			case year < 1000:
+				b = append(b, '0')
+			}
+			b = appendUint(b, uint(y), 0)
 		case stdMonth:
 			b = append(b, month.String()[:3]...)
 		case stdLongMonth:
 			m := month.String()
 			b = append(b, m...)
 		case stdNumMonth:
-			b = appendInt(b, int(month), 0)
+			b = appendUint(b, uint(month), 0)
 		case stdZeroMonth:
-			b = appendInt(b, int(month), 2)
+			b = appendUint(b, uint(month), '0')
 		case stdWeekDay:
 			b = append(b, absWeekday(abs).String()[:3]...)
 		case stdLongWeekDay:
 			s := absWeekday(abs).String()
 			b = append(b, s...)
 		case stdDay:
-			b = appendInt(b, day, 0)
+			b = appendUint(b, uint(day), 0)
 		case stdUnderDay:
-			if day < 10 {
-				b = append(b, ' ')
-			}
-			b = appendInt(b, day, 0)
+			b = appendUint(b, uint(day), ' ')
 		case stdZeroDay:
-			b = appendInt(b, day, 2)
+			b = appendUint(b, uint(day), '0')
 		case stdHour:
-			b = appendInt(b, hour, 2)
+			b = appendUint(b, uint(hour), '0')
 		case stdHour12:
 			// Noon is 12PM, midnight is 12AM.
 			hr := hour % 12
 			if hr == 0 {
 				hr = 12
 			}
-			b = appendInt(b, hr, 0)
+			b = appendUint(b, uint(hr), 0)
 		case stdZeroHour12:
 			// Noon is 12PM, midnight is 12AM.
 			hr := hour % 12
 			if hr == 0 {
 				hr = 12
 			}
-			b = appendInt(b, hr, 2)
+			b = appendUint(b, uint(hr), '0')
 		case stdMinute:
-			b = appendInt(b, min, 0)
+			b = appendUint(b, uint(min), 0)
 		case stdZeroMinute:
-			b = appendInt(b, min, 2)
+			b = appendUint(b, uint(min), '0')
 		case stdSecond:
-			b = appendInt(b, sec, 2)
+			b = appendUint(b, uint(sec), 0)
 		case stdZeroSecond:
-			b = appendInt(b, sec, 2)
+			b = appendUint(b, uint(sec), '0')
 		case stdPM:
 			if hour >= 12 {
 				b = append(b, "PM"...)
@@ -549,18 +555,18 @@ func (t Time) AppendFormat(b []byte, layout string) []byte {
 			} else {
 				b = append(b, '+')
 			}
-			b = appendInt(b, zone/60, 2)
+			b = appendUint(b, uint(zone/60), '0')
 			if std == stdISO8601ColonTZ || std == stdNumColonTZ || std == stdISO8601ColonSecondsTZ || std == stdNumColonSecondsTZ {
 				b = append(b, ':')
 			}
-			b = appendInt(b, zone%60, 2)
+			b = appendUint(b, uint(zone%60), '0')
 
 			// append seconds if appropriate
 			if std == stdISO8601SecondsTZ || std == stdNumSecondsTz || std == stdNumColonSecondsTZ || std == stdISO8601ColonSecondsTZ {
 				if std == stdNumColonSecondsTZ || std == stdISO8601ColonSecondsTZ {
 					b = append(b, ':')
 				}
-				b = appendInt(b, absoffset%60, 2)
+				b = appendUint(b, uint(absoffset%60), '0')
 			}
 
 		case stdTZ:
@@ -577,13 +583,13 @@ func (t Time) AppendFormat(b []byte, layout string) []byte {
 			} else {
 				b = append(b, '+')
 			}
-			b = appendInt(b, zone/60, 2)
-			b = appendInt(b, zone%60, 2)
+			b = appendUint(b, uint(zone/60), '0')
+			b = appendUint(b, uint(zone%60), '0')
 		case stdFracSecond0, stdFracSecond9:
 			b = formatNano(b, uint(t.Nanosecond()), std>>stdArgShift, std&stdMask == stdFracSecond9)
 		}
 	}
-	return b
+	return string(b)
 }
 
 var errBad = errors.New("bad value for field") // placeholder not passed to user
@@ -614,7 +620,8 @@ func (e *ParseError) Error() string {
 		quote(e.Value) + e.Message
 }
 
-// isDigit reports whether s[i] is in range and is a decimal digit.
+// isDigit returns true if s[i] is a decimal digit, false if not or
+// if s[i] is out of range.
 func isDigit(s string, i int) bool {
 	if len(s) <= i {
 		return false
@@ -674,13 +681,10 @@ func skip(value, prefix string) (string, error) {
 // would be interpreted if it were the value; it serves as an example of
 // the input format. The same interpretation will then be made to the
 // input string.
-//
 // Predefined layouts ANSIC, UnixDate, RFC3339 and others describe standard
 // and convenient representations of the reference time. For more information
 // about the formats and the definition of the reference time, see the
 // documentation for ANSIC and the other constants defined by this package.
-// Also, the executable example for time.Format demonstrates the working
-// of the layout string in detail and is a good reference.
 //
 // Elements omitted from the value are assumed to be zero or, when
 // zero is impossible, one, so parsing "3:04pm" returns the time
@@ -1127,28 +1131,24 @@ func leadingInt(s string) (x int64, rem string, err error) {
 		if c < '0' || c > '9' {
 			break
 		}
-		if x > (1<<63-1)/10 {
+		if x >= (1<<63-10)/10 {
 			// overflow
 			return 0, "", errLeadingInt
 		}
 		x = x*10 + int64(c) - '0'
-		if x < 0 {
-			// overflow
-			return 0, "", errLeadingInt
-		}
 	}
 	return x, s[i:], nil
 }
 
-var unitMap = map[string]int64{
-	"ns": int64(Nanosecond),
-	"us": int64(Microsecond),
-	"µs": int64(Microsecond), // U+00B5 = micro symbol
-	"μs": int64(Microsecond), // U+03BC = Greek letter mu
-	"ms": int64(Millisecond),
-	"s":  int64(Second),
-	"m":  int64(Minute),
-	"h":  int64(Hour),
+var unitMap = map[string]float64{
+	"ns": float64(Nanosecond),
+	"us": float64(Microsecond),
+	"µs": float64(Microsecond), // U+00B5 = micro symbol
+	"μs": float64(Microsecond), // U+03BC = Greek letter mu
+	"ms": float64(Millisecond),
+	"s":  float64(Second),
+	"m":  float64(Minute),
+	"h":  float64(Hour),
 }
 
 // ParseDuration parses a duration string.
@@ -1159,7 +1159,7 @@ var unitMap = map[string]int64{
 func ParseDuration(s string) (Duration, error) {
 	// [-+]?([0-9]*(\.[0-9]*)?[a-z]+)+
 	orig := s
-	var d int64
+	f := float64(0)
 	neg := false
 
 	// Consume [-+]?
@@ -1178,23 +1178,22 @@ func ParseDuration(s string) (Duration, error) {
 		return 0, errors.New("time: invalid duration " + orig)
 	}
 	for s != "" {
-		var (
-			v, f  int64       // integers before, after decimal point
-			scale float64 = 1 // value = v + f/scale
-		)
+		g := float64(0) // this element of the sequence
 
+		var x int64
 		var err error
 
 		// The next character must be [0-9.]
-		if !(s[0] == '.' || '0' <= s[0] && s[0] <= '9') {
+		if !(s[0] == '.' || ('0' <= s[0] && s[0] <= '9')) {
 			return 0, errors.New("time: invalid duration " + orig)
 		}
 		// Consume [0-9]*
 		pl := len(s)
-		v, s, err = leadingInt(s)
+		x, s, err = leadingInt(s)
 		if err != nil {
 			return 0, errors.New("time: invalid duration " + orig)
 		}
+		g = float64(x)
 		pre := pl != len(s) // whether we consumed anything before a period
 
 		// Consume (\.[0-9]*)?
@@ -1202,13 +1201,15 @@ func ParseDuration(s string) (Duration, error) {
 		if s != "" && s[0] == '.' {
 			s = s[1:]
 			pl := len(s)
-			f, s, err = leadingInt(s)
+			x, s, err = leadingInt(s)
 			if err != nil {
 				return 0, errors.New("time: invalid duration " + orig)
 			}
+			scale := 1.0
 			for n := pl - len(s); n > 0; n-- {
 				scale *= 10
 			}
+			g += float64(x) / scale
 			post = pl != len(s)
 		}
 		if !pre && !post {
@@ -1220,7 +1221,7 @@ func ParseDuration(s string) (Duration, error) {
 		i := 0
 		for ; i < len(s); i++ {
 			c := s[i]
-			if c == '.' || '0' <= c && c <= '9' {
+			if c == '.' || ('0' <= c && c <= '9') {
 				break
 			}
 		}
@@ -1233,29 +1234,15 @@ func ParseDuration(s string) (Duration, error) {
 		if !ok {
 			return 0, errors.New("time: unknown unit " + u + " in duration " + orig)
 		}
-		if v > (1<<63-1)/unit {
-			// overflow
-			return 0, errors.New("time: invalid duration " + orig)
-		}
-		v *= unit
-		if f > 0 {
-			// float64 is needed to be nanosecond accurate for fractions of hours.
-			// v >= 0 && (f*unit/scale) <= 3.6e+12 (ns/h, h is the largest unit)
-			v += int64(float64(f) * (float64(unit) / scale))
-			if v < 0 {
-				// overflow
-				return 0, errors.New("time: invalid duration " + orig)
-			}
-		}
-		d += v
-		if d < 0 {
-			// overflow
-			return 0, errors.New("time: invalid duration " + orig)
-		}
+
+		f += g * unit
 	}
 
 	if neg {
-		d = -d
+		f = -f
+	}
+	if f < float64(-1<<63) || f > float64(1<<63-1) {
+		return 0, errors.New("time: overflow parsing duration")
 	}
-	return Duration(d), nil
+	return Duration(f), nil
 }
diff --git a/src/time/sleep_test.go b/src/time/sleep_test.go
index dd0a820..c9b2956 100644
--- a/src/time/sleep_test.go
+++ b/src/time/sleep_test.go
@@ -8,6 +8,7 @@ import (
 	"errors"
 	"fmt"
 	"runtime"
+	"sort"
 	"strings"
 	"sync"
 	"sync/atomic"
@@ -223,11 +224,10 @@ func TestAfterStop(t *testing.T) {
 func TestAfterQueuing(t *testing.T) {
 	// This test flakes out on some systems,
 	// so we'll try it a few times before declaring it a failure.
-	const attempts = 5
+	const attempts = 3
 	err := errors.New("!=nil")
 	for i := 0; i < attempts && err != nil; i++ {
-		delta := Duration(20+i*50) * Millisecond
-		if err = testAfterQueuing(t, delta); err != nil {
+		if err = testAfterQueuing(t); err != nil {
 			t.Logf("attempt %v failed: %v", i, err)
 		}
 	}
@@ -247,7 +247,11 @@ func await(slot int, result chan<- afterResult, ac <-chan Time) {
 	result <- afterResult{slot, <-ac}
 }
 
-func testAfterQueuing(t *testing.T, delta Duration) error {
+func testAfterQueuing(t *testing.T) error {
+	Delta := 100 * Millisecond
+	if testing.Short() {
+		Delta = 20 * Millisecond
+	}
 	// make the result channel buffered because we don't want
 	// to depend on channel queueing semantics that might
 	// possibly change in the future.
@@ -255,25 +259,18 @@ func testAfterQueuing(t *testing.T, delta Duration) error {
 
 	t0 := Now()
 	for _, slot := range slots {
-		go await(slot, result, After(Duration(slot)*delta))
+		go await(slot, result, After(Duration(slot)*Delta))
 	}
-	var order []int
-	var times []Time
-	for range slots {
+	sort.Ints(slots)
+	for _, slot := range slots {
 		r := <-result
-		order = append(order, r.slot)
-		times = append(times, r.t)
-	}
-	for i := range order {
-		if i > 0 && order[i] < order[i-1] {
-			return fmt.Errorf("After calls returned out of order: %v", order)
+		if r.slot != slot {
+			return fmt.Errorf("after slot %d, expected %d", r.slot, slot)
 		}
-	}
-	for i, t := range times {
-		dt := t.Sub(t0)
-		target := Duration(order[i]) * delta
-		if dt < target-delta/2 || dt > target+delta*10 {
-			return fmt.Errorf("After(%s) arrived at %s, expected [%s,%s]", target, dt, target-delta/2, target+delta*10)
+		dt := r.t.Sub(t0)
+		target := Duration(slot) * Delta
+		if dt < target-Delta/2 || dt > target+Delta*10 {
+			return fmt.Errorf("After(%s) arrived at %s, expected [%s,%s]", target, dt, target-Delta/2, target+Delta*10)
 		}
 	}
 	return nil
@@ -386,10 +383,6 @@ func TestOverflowSleep(t *testing.T) {
 // Test that a panic while deleting a timer does not leave
 // the timers mutex held, deadlocking a ticker.Stop in a defer.
 func TestIssue5745(t *testing.T) {
-	if runtime.GOOS == "darwin" && runtime.GOARCH == "arm" {
-		t.Skipf("skipping on %s/%s, see issue 10043", runtime.GOOS, runtime.GOARCH)
-	}
-
 	ticker := NewTicker(Hour)
 	defer func() {
 		// would deadlock here before the fix due to
diff --git a/src/time/sys_unix.go b/src/time/sys_unix.go
index e592415..379e13d 100644
--- a/src/time/sys_unix.go
+++ b/src/time/sys_unix.go
@@ -74,5 +74,3 @@ func preadn(fd uintptr, buf []byte, off int) error {
 	}
 	return nil
 }
-
-func isNotExist(err error) bool { return err == syscall.ENOENT }
diff --git a/src/time/tick.go b/src/time/tick.go
index 196e8ac..1900784 100644
--- a/src/time/tick.go
+++ b/src/time/tick.go
@@ -47,9 +47,7 @@ func (t *Ticker) Stop() {
 }
 
 // Tick is a convenience wrapper for NewTicker providing access to the ticking
-// channel only. While Tick is useful for clients that have no need to shut down
-// the Ticker, be aware that without a way to shut it down the underlying
-// Ticker cannot be recovered by the garbage collector; it "leaks".
+// channel only.  Useful for clients that have no need to shut down the ticker.
 func Tick(d Duration) <-chan Time {
 	if d <= 0 {
 		return nil
diff --git a/src/time/time.go b/src/time/time.go
index 294cc77..0300e84 100644
--- a/src/time/time.go
+++ b/src/time/time.go
@@ -966,8 +966,6 @@ func (t *Time) UnmarshalText(data []byte) (err error) {
 // Unix returns the local Time corresponding to the given Unix time,
 // sec seconds and nsec nanoseconds since January 1, 1970 UTC.
 // It is valid to pass nsec outside the range [0, 999999999].
-// Not all sec values have a corresponding time value. One such
-// value is 1<<63-1 (the largest int64 value).
 func Unix(sec int64, nsec int64) Time {
 	if nsec < 0 || nsec >= 1e9 {
 		n := nsec / 1e9
diff --git a/src/time/time_test.go b/src/time/time_test.go
index 2d16ea5..7e31dd7 100644
--- a/src/time/time_test.go
+++ b/src/time/time_test.go
@@ -830,16 +830,8 @@ var parseDurationTests = []struct {
 	{"39h9m14.425s", true, 39*Hour + 9*Minute + 14*Second + 425*Millisecond},
 	// large value
 	{"52763797000ns", true, 52763797000 * Nanosecond},
-	// more than 9 digits after decimal point, see https://golang.org/issue/6617
+	// more than 9 digits after decimal point, see http://golang.org/issue/6617
 	{"0.3333333333333333333h", true, 20 * Minute},
-	// 9007199254740993 = 1<<53+1 cannot be stored precisely in a float64
-	{"9007199254740993ns", true, (1<<53 + 1) * Nanosecond},
-	// largest duration that can be represented by int64 in nanoseconds
-	{"9223372036854775807ns", true, (1<<63 - 1) * Nanosecond},
-	{"9223372036854775.807us", true, (1<<63 - 1) * Nanosecond},
-	{"9223372036s854ms775us807ns", true, (1<<63 - 1) * Nanosecond},
-	// large negative value
-	{"-9223372036854775807ns", true, -1<<63 + 1*Nanosecond},
 
 	// errors
 	{"", false, 0},
@@ -850,13 +842,7 @@ var parseDurationTests = []struct {
 	{"-.", false, 0},
 	{".s", false, 0},
 	{"+.s", false, 0},
-	{"3000000h", false, 0},                  // overflow
-	{"9223372036854775808ns", false, 0},     // overflow
-	{"9223372036854775.808us", false, 0},    // overflow
-	{"9223372036854ms775us808ns", false, 0}, // overflow
-	// largest negative value of type int64 in nanoseconds should fail
-	// see https://go-review.googlesource.com/#/c/2461/
-	{"-9223372036854775808ns", false, 0},
+	{"3000000h", false, 0}, // overflow
 }
 
 func TestParseDuration(t *testing.T) {
@@ -1066,13 +1052,6 @@ func BenchmarkParse(b *testing.B) {
 	}
 }
 
-func BenchmarkParseDuration(b *testing.B) {
-	for i := 0; i < b.N; i++ {
-		ParseDuration("9007199254.740993ms")
-		ParseDuration("9007199254740993ns")
-	}
-}
-
 func BenchmarkHour(b *testing.B) {
 	t := Now()
 	for i := 0; i < b.N; i++ {
diff --git a/src/time/zoneinfo_plan9.go b/src/time/zoneinfo_plan9.go
index 0694f0a..4bb0cb3 100644
--- a/src/time/zoneinfo_plan9.go
+++ b/src/time/zoneinfo_plan9.go
@@ -7,6 +7,7 @@
 package time
 
 import (
+	"errors"
 	"runtime"
 	"syscall"
 )
@@ -147,12 +148,11 @@ func initLocal() {
 }
 
 func loadLocation(name string) (*Location, error) {
-	z, err := loadZoneFile(runtime.GOROOT()+"/lib/time/zoneinfo.zip", name)
-	if err != nil {
-		return nil, err
+	if z, err := loadZoneFile(runtime.GOROOT()+"/lib/time/zoneinfo.zip", name); err == nil {
+		z.name = name
+		return z, nil
 	}
-	z.name = name
-	return z, nil
+	return nil, errors.New("unknown time zone " + name)
 }
 
 func forceZipFileForTesting(zipOnly bool) {
diff --git a/src/time/zoneinfo_unix.go b/src/time/zoneinfo_unix.go
index ed9502d..ab7e461 100644
--- a/src/time/zoneinfo_unix.go
+++ b/src/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,386 darwin,amd64 dragonfly freebsd linux nacl netbsd openbsd solaris
+// +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.
@@ -74,17 +74,11 @@ func initLocal() {
 }
 
 func loadLocation(name string) (*Location, error) {
-	var firstErr error
 	for _, zoneDir := range zoneDirs {
 		if z, err := loadZoneFile(zoneDir, name); err == nil {
 			z.name = name
 			return z, nil
-		} else if firstErr == nil && !isNotExist(err) {
-			firstErr = err
 		}
 	}
-	if firstErr != nil {
-		return nil, firstErr
-	}
 	return nil, errors.New("unknown time zone " + name)
 }
diff --git a/src/time/zoneinfo_windows.go b/src/time/zoneinfo_windows.go
index d04ebec..02d8e0e 100644
--- a/src/time/zoneinfo_windows.go
+++ b/src/time/zoneinfo_windows.go
@@ -6,9 +6,9 @@ package time
 
 import (
 	"errors"
-	"internal/syscall/windows/registry"
 	"runtime"
 	"syscall"
+	"unsafe"
 )
 
 //go:generate go run genzabbrs.go -output zoneinfo_abbrs_windows.go
@@ -20,23 +20,39 @@ import (
 // The implementation assumes that this year's rules for daylight savings
 // time apply to all previous and future years as well.
 
+// getKeyValue retrieves the string value kname associated with the open registry key kh.
+func getKeyValue(kh syscall.Handle, kname string) (string, error) {
+	var buf [50]uint16 // buf needs to be large enough to fit zone descriptions
+	var typ uint32
+	n := uint32(len(buf) * 2) // RegQueryValueEx's signature expects array of bytes, not uint16
+	p, _ := syscall.UTF16PtrFromString(kname)
+	if err := syscall.RegQueryValueEx(kh, p, nil, &typ, (*byte)(unsafe.Pointer(&buf[0])), &n); err != nil {
+		return "", err
+	}
+	if typ != syscall.REG_SZ { // null terminated strings only
+		return "", errors.New("Key is not string")
+	}
+	return syscall.UTF16ToString(buf[:]), nil
+}
+
 // matchZoneKey checks if stdname and dstname match the corresponding "Std"
 // and "Dlt" key values in the kname key stored under the open registry key zones.
-func matchZoneKey(zones registry.Key, kname string, stdname, dstname string) (matched bool, err2 error) {
-	k, err := registry.OpenKey(zones, kname, registry.READ)
-	if err != nil {
+func matchZoneKey(zones syscall.Handle, kname string, stdname, dstname string) (matched bool, err2 error) {
+	var h syscall.Handle
+	p, _ := syscall.UTF16PtrFromString(kname)
+	if err := syscall.RegOpenKeyEx(zones, p, 0, syscall.KEY_READ, &h); err != nil {
 		return false, err
 	}
-	defer k.Close()
+	defer syscall.RegCloseKey(h)
 
-	s, _, err := k.GetStringValue("Std")
+	s, err := getKeyValue(h, "Std")
 	if err != nil {
 		return false, err
 	}
 	if s != stdname {
 		return false, nil
 	}
-	s, _, err = k.GetStringValue("Dlt")
+	s, err = getKeyValue(h, "Dlt")
 	if err != nil {
 		return false, err
 	}
@@ -49,20 +65,28 @@ func matchZoneKey(zones registry.Key, kname string, stdname, dstname string) (ma
 // toEnglishName searches the registry for an English name of a time zone
 // whose zone names are stdname and dstname and returns the English name.
 func toEnglishName(stdname, dstname string) (string, error) {
-	k, err := registry.OpenKey(registry.LOCAL_MACHINE, `SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones`, registry.ENUMERATE_SUB_KEYS|registry.QUERY_VALUE)
-	if err != nil {
+	var zones syscall.Handle
+	p, _ := syscall.UTF16PtrFromString(`SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones`)
+	if err := syscall.RegOpenKeyEx(syscall.HKEY_LOCAL_MACHINE, p, 0, syscall.KEY_READ, &zones); err != nil {
 		return "", err
 	}
-	defer k.Close()
+	defer syscall.RegCloseKey(zones)
 
-	names, err := k.ReadSubKeyNames(-1)
-	if err != nil {
+	var count uint32
+	if err := syscall.RegQueryInfoKey(zones, nil, nil, nil, &count, nil, nil, nil, nil, nil, nil, nil); err != nil {
 		return "", err
 	}
-	for _, name := range names {
-		matched, err := matchZoneKey(k, name, stdname, dstname)
+
+	var buf [50]uint16 // buf needs to be large enough to fit zone descriptions
+	for i := uint32(0); i < count; i++ {
+		n := uint32(len(buf))
+		if syscall.RegEnumKeyEx(zones, i, &buf[0], &n, nil, nil, nil, nil) != nil {
+			continue
+		}
+		kname := syscall.UTF16ToString(buf[:])
+		matched, err := matchZoneKey(zones, kname, stdname, dstname)
 		if err == nil && matched {
-			return name, nil
+			return kname, nil
 		}
 	}
 	return "", errors.New(`English name for time zone "` + stdname + `" not found in registry`)
@@ -236,12 +260,11 @@ func initLocal() {
 }
 
 func loadLocation(name string) (*Location, error) {
-	z, err := loadZoneFile(runtime.GOROOT()+`\lib\time\zoneinfo.zip`, name)
-	if err != nil {
-		return nil, err
+	if z, err := loadZoneFile(runtime.GOROOT()+`\lib\time\zoneinfo.zip`, name); err == nil {
+		z.name = name
+		return z, nil
 	}
-	z.name = name
-	return z, nil
+	return nil, errors.New("unknown time zone " + name)
 }
 
 func forceZipFileForTesting(zipOnly bool) {
diff --git a/src/time/zoneinfo_windows_test.go b/src/time/zoneinfo_windows_test.go
index 5f1141d..9db81b7 100644
--- a/src/time/zoneinfo_windows_test.go
+++ b/src/time/zoneinfo_windows_test.go
@@ -5,7 +5,6 @@
 package time_test
 
 import (
-	"internal/syscall/windows/registry"
 	"testing"
 	. "time"
 )
@@ -34,27 +33,3 @@ func TestAusZoneAbbr(t *testing.T) {
 	defer ForceUSPacificForTesting()
 	testZoneAbbr(t)
 }
-
-func TestToEnglishName(t *testing.T) {
-	const want = "Central Europe Standard Time"
-	k, err := registry.OpenKey(registry.LOCAL_MACHINE, `SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones\`+want, registry.READ)
-	if err != nil {
-		t.Fatalf("cannot open CEST time zone information from registry: %s", err)
-	}
-	defer k.Close()
-	std, _, err := k.GetStringValue("Std")
-	if err != nil {
-		t.Fatalf("cannot read CEST Std registry key: %s", err)
-	}
-	dlt, _, err := k.GetStringValue("Dlt")
-	if err != nil {
-		t.Fatalf("cannot read CEST Dlt registry key: %s", err)
-	}
-	name, err := ToEnglishName(std, dlt)
-	if err != nil {
-		t.Fatalf("toEnglishName failed: %s", err)
-	}
-	if name != want {
-		t.Fatalf("english name: %q, want: %q", name, want)
-	}
-}
diff --git a/src/unicode/graphic.go b/src/unicode/graphic.go
index 81eae3e..ba90b4e 100644
--- a/src/unicode/graphic.go
+++ b/src/unicode/graphic.go
@@ -82,7 +82,7 @@ func IsControl(r rune) bool {
 	if uint32(r) <= MaxLatin1 {
 		return properties[uint8(r)]&pC != 0
 	}
-	// All control characters are < MaxLatin1.
+	// All control characters are < Latin1Max.
 	return false
 }
 
diff --git a/src/unicode/letter_test.go b/src/unicode/letter_test.go
index a40b412..4ee11fb 100644
--- a/src/unicode/letter_test.go
+++ b/src/unicode/letter_test.go
@@ -24,7 +24,6 @@ var upperTest = []rune{
 	0x181,
 	0x376,
 	0x3cf,
-	0x13bd,
 	0x1f2a,
 	0x2102,
 	0x2c00,
@@ -47,7 +46,6 @@ var notupperTest = []rune{
 	0x377,
 	0x387,
 	0x2150,
-	0xab7d,
 	0xffff,
 	0x10000,
 }
@@ -196,15 +194,6 @@ var caseTest = []caseT{
 	{LowerCase, 0x0148, 0x0148},
 	{TitleCase, 0x0148, 0x0147},
 
-	// Lowercase lower than uppercase.
-	// AB78;CHEROKEE SMALL LETTER GE;Ll;0;L;;;;;N;;;13A8;;13A8
-	{UpperCase, 0xab78, 0x13a8},
-	{LowerCase, 0xab78, 0xab78},
-	{TitleCase, 0xab78, 0x13a8},
-	{UpperCase, 0x13a8, 0x13a8},
-	{LowerCase, 0x13a8, 0xab78},
-	{TitleCase, 0x13a8, 0x13a8},
-
 	// Last block in the 5.1.0 table
 	// 10400;DESERET CAPITAL LETTER LONG I;Lu;0;L;;;;;N;;;;10428;
 	{UpperCase, 0x10400, 0x10400},
@@ -416,9 +405,6 @@ var simpleFoldTests = []string{
 	// Extra special cases: has lower/upper but no case fold.
 	"İ",
 	"ı",
-
-	// Upper comes before lower (Cherokee).
-	"\u13b0\uab80",
 }
 
 func TestSimpleFold(t *testing.T) {
diff --git a/src/unicode/maketables.go b/src/unicode/maketables.go
index 9fccdec..d1c9aa0 100644
--- a/src/unicode/maketables.go
+++ b/src/unicode/maketables.go
@@ -44,7 +44,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/8.0.0/ucd/",
+	"http://www.unicode.org/Public/7.0.0/ucd/",
 	"URL of Unicode database directory")
 var tablelist = flag.String("tables",
 	"all",
@@ -1152,14 +1152,11 @@ func printCasefold() {
 		}
 	}
 
-	// Delete the groups for which assuming [lower, upper] or [upper, lower] is right.
+	// Delete the groups for which assuming [lower, upper] is right.
 	for i, orb := range caseOrbit {
 		if len(orb) == 2 && chars[orb[0]].upperCase == orb[1] && chars[orb[1]].lowerCase == orb[0] {
 			caseOrbit[i] = nil
 		}
-		if len(orb) == 2 && chars[orb[1]].upperCase == orb[0] && chars[orb[0]].lowerCase == orb[1] {
-			caseOrbit[i] = nil
-		}
 	}
 
 	// Record orbit information in chars.
diff --git a/src/unicode/script_test.go b/src/unicode/script_test.go
index 935c225..795cb4e 100644
--- a/src/unicode/script_test.go
+++ b/src/unicode/script_test.go
@@ -14,11 +14,9 @@ type T struct {
 	script string
 }
 
-// Hand-chosen tests from Unicode 5.1.0, 6.0.0, 6.2.0, 6.3.0, 7.0.0 and 8.0.0
-// mostly to discover when new scripts and categories arise.
+// Hand-chosen tests from Unicode 5.1.0, 6.0.0, 6.2.0, 6.3.0 and 7.0.0 mostly to
+// discover when new scripts and categories arise.
 var inTest = []T{
-	{0x11711, "Ahom"},
-	{0x14646, "Anatolian_Hieroglyphs"},
 	{0x06e2, "Arabic"},
 	{0x0567, "Armenian"},
 	{0x10b20, "Avestan"},
@@ -60,7 +58,6 @@ var inTest = []T{
 	{0x3028, "Han"},
 	{0x11b8, "Hangul"},
 	{0x1727, "Hanunoo"},
-	{0x108FF, "Hatran"},
 	{0x05a0, "Hebrew"},
 	{0x3058, "Hiragana"},
 	{0x10841, "Imperial_Aramaic"},
@@ -97,14 +94,12 @@ var inTest = []T{
 	{0x11611, "Modi"},
 	{0x1822, "Mongolian"},
 	{0x16a60, "Mro"},
-	{0x11293, "Multani"},
 	{0x104c, "Myanmar"},
 	{0x10880, "Nabataean"},
 	{0x19c3, "New_Tai_Lue"},
 	{0x07f8, "Nko"},
 	{0x169b, "Ogham"},
 	{0x1c6a, "Ol_Chiki"},
-	{0x10C80, "Old_Hungarian"},
 	{0x10310, "Old_Italic"},
 	{0x10a80, "Old_North_Arabian"},
 	{0x10350, "Old_Permic"},
@@ -126,7 +121,6 @@ var inTest = []T{
 	{0x111a0, "Sharada"},
 	{0x10463, "Shavian"},
 	{0x115c1, "Siddham"},
-	{0x1D920, "SignWriting"},
 	{0x0dbd, "Sinhala"},
 	{0x110d0, "Sora_Sompeng"},
 	{0x1ba3, "Sundanese"},
diff --git a/src/unicode/tables.go b/src/unicode/tables.go
index 370a9d1..8b77dd6 100644
--- a/src/unicode/tables.go
+++ b/src/unicode/tables.go
@@ -3,13 +3,13 @@
 // license that can be found in the LICENSE file.
 
 // Generated by running
-//	maketables --tables=all --data=http://www.unicode.org/Public/8.0.0/ucd/UnicodeData.txt --casefolding=http://www.unicode.org/Public/8.0.0/ucd/CaseFolding.txt
+//	maketables --tables=all --data=http://www.unicode.org/Public/7.0.0/ucd/UnicodeData.txt --casefolding=http://www.unicode.org/Public/7.0.0/ucd/CaseFolding.txt
 // DO NOT EDIT
 
 package unicode
 
 // Version is the Unicode edition from which the tables are derived.
-const Version = "8.0.0"
+const Version = "7.0.0"
 
 // Categories is the set of Unicode category tables.
 var Categories = map[string]*RangeTable{
@@ -170,7 +170,7 @@ var _L = &RangeTable{
 		{0x081a, 0x0824, 10},
 		{0x0828, 0x0840, 24},
 		{0x0841, 0x0858, 1},
-		{0x08a0, 0x08b4, 1},
+		{0x08a0, 0x08b2, 1},
 		{0x0904, 0x0939, 1},
 		{0x093d, 0x0950, 19},
 		{0x0958, 0x0961, 1},
@@ -203,8 +203,7 @@ var _L = &RangeTable{
 		{0x0ab5, 0x0ab9, 1},
 		{0x0abd, 0x0ad0, 19},
 		{0x0ae0, 0x0ae1, 1},
-		{0x0af9, 0x0b05, 12},
-		{0x0b06, 0x0b0c, 1},
+		{0x0b05, 0x0b0c, 1},
 		{0x0b0f, 0x0b10, 1},
 		{0x0b13, 0x0b28, 1},
 		{0x0b2a, 0x0b30, 1},
@@ -229,9 +228,9 @@ var _L = &RangeTable{
 		{0x0c12, 0x0c28, 1},
 		{0x0c2a, 0x0c39, 1},
 		{0x0c3d, 0x0c58, 27},
-		{0x0c59, 0x0c5a, 1},
-		{0x0c60, 0x0c61, 1},
-		{0x0c85, 0x0c8c, 1},
+		{0x0c59, 0x0c60, 7},
+		{0x0c61, 0x0c85, 36},
+		{0x0c86, 0x0c8c, 1},
 		{0x0c8e, 0x0c90, 1},
 		{0x0c92, 0x0ca8, 1},
 		{0x0caa, 0x0cb3, 1},
@@ -242,7 +241,7 @@ var _L = &RangeTable{
 		{0x0d05, 0x0d0c, 1},
 		{0x0d0e, 0x0d10, 1},
 		{0x0d12, 0x0d3a, 1},
-		{0x0d3d, 0x0d5f, 17},
+		{0x0d3d, 0x0d4e, 17},
 		{0x0d60, 0x0d61, 1},
 		{0x0d7a, 0x0d7f, 1},
 		{0x0d85, 0x0d96, 1},
@@ -301,8 +300,7 @@ var _L = &RangeTable{
 		{0x1312, 0x1315, 1},
 		{0x1318, 0x135a, 1},
 		{0x1380, 0x138f, 1},
-		{0x13a0, 0x13f5, 1},
-		{0x13f8, 0x13fd, 1},
+		{0x13a0, 0x13f4, 1},
 		{0x1401, 0x166c, 1},
 		{0x166f, 0x167f, 1},
 		{0x1681, 0x169a, 1},
@@ -324,7 +322,7 @@ var _L = &RangeTable{
 		{0x1950, 0x196d, 1},
 		{0x1970, 0x1974, 1},
 		{0x1980, 0x19ab, 1},
-		{0x19b0, 0x19c9, 1},
+		{0x19c1, 0x19c7, 1},
 		{0x1a00, 0x1a16, 1},
 		{0x1a20, 0x1a54, 1},
 		{0x1aa7, 0x1b05, 94},
@@ -401,7 +399,7 @@ var _L = &RangeTable{
 		{0x31a0, 0x31ba, 1},
 		{0x31f0, 0x31ff, 1},
 		{0x3400, 0x4db5, 1},
-		{0x4e00, 0x9fd5, 1},
+		{0x4e00, 0x9fcc, 1},
 		{0xa000, 0xa48c, 1},
 		{0xa4d0, 0xa4fd, 1},
 		{0xa500, 0xa60c, 1},
@@ -412,8 +410,9 @@ var _L = &RangeTable{
 		{0xa6a0, 0xa6e5, 1},
 		{0xa717, 0xa71f, 1},
 		{0xa722, 0xa788, 1},
-		{0xa78b, 0xa7ad, 1},
-		{0xa7b0, 0xa7b7, 1},
+		{0xa78b, 0xa78e, 1},
+		{0xa790, 0xa7ad, 1},
+		{0xa7b0, 0xa7b1, 1},
 		{0xa7f7, 0xa801, 1},
 		{0xa803, 0xa805, 1},
 		{0xa807, 0xa80a, 1},
@@ -421,8 +420,8 @@ var _L = &RangeTable{
 		{0xa840, 0xa873, 1},
 		{0xa882, 0xa8b3, 1},
 		{0xa8f2, 0xa8f7, 1},
-		{0xa8fb, 0xa8fd, 2},
-		{0xa90a, 0xa925, 1},
+		{0xa8fb, 0xa90a, 15},
+		{0xa90b, 0xa925, 1},
 		{0xa930, 0xa946, 1},
 		{0xa960, 0xa97c, 1},
 		{0xa984, 0xa9b2, 1},
@@ -449,8 +448,9 @@ var _L = &RangeTable{
 		{0xab20, 0xab26, 1},
 		{0xab28, 0xab2e, 1},
 		{0xab30, 0xab5a, 1},
-		{0xab5c, 0xab65, 1},
-		{0xab70, 0xabe2, 1},
+		{0xab5c, 0xab5f, 1},
+		{0xab64, 0xab65, 1},
+		{0xabc0, 0xabe2, 1},
 		{0xac00, 0xd7a3, 1},
 		{0xd7b0, 0xd7c6, 1},
 		{0xd7cb, 0xd7fb, 1},
@@ -511,8 +511,6 @@ var _L = &RangeTable{
 		{0x10840, 0x10855, 1},
 		{0x10860, 0x10876, 1},
 		{0x10880, 0x1089e, 1},
-		{0x108e0, 0x108f2, 1},
-		{0x108f4, 0x108f5, 1},
 		{0x10900, 0x10915, 1},
 		{0x10920, 0x10939, 1},
 		{0x10980, 0x109b7, 1},
@@ -530,8 +528,6 @@ var _L = &RangeTable{
 		{0x10b60, 0x10b72, 1},
 		{0x10b80, 0x10b91, 1},
 		{0x10c00, 0x10c48, 1},
-		{0x10c80, 0x10cb2, 1},
-		{0x10cc0, 0x10cf2, 1},
 		{0x11003, 0x11037, 1},
 		{0x11083, 0x110af, 1},
 		{0x110d0, 0x110e8, 1},
@@ -540,14 +536,9 @@ var _L = &RangeTable{
 		{0x11176, 0x11183, 13},
 		{0x11184, 0x111b2, 1},
 		{0x111c1, 0x111c4, 1},
-		{0x111da, 0x111dc, 2},
-		{0x11200, 0x11211, 1},
+		{0x111da, 0x11200, 38},
+		{0x11201, 0x11211, 1},
 		{0x11213, 0x1122b, 1},
-		{0x11280, 0x11286, 1},
-		{0x11288, 0x1128a, 2},
-		{0x1128b, 0x1128d, 1},
-		{0x1128f, 0x1129d, 1},
-		{0x1129f, 0x112a8, 1},
 		{0x112b0, 0x112de, 1},
 		{0x11305, 0x1130c, 1},
 		{0x1130f, 0x11310, 1},
@@ -555,24 +546,20 @@ var _L = &RangeTable{
 		{0x1132a, 0x11330, 1},
 		{0x11332, 0x11333, 1},
 		{0x11335, 0x11339, 1},
-		{0x1133d, 0x11350, 19},
-		{0x1135d, 0x11361, 1},
+		{0x1133d, 0x1135d, 32},
+		{0x1135e, 0x11361, 1},
 		{0x11480, 0x114af, 1},
 		{0x114c4, 0x114c5, 1},
 		{0x114c7, 0x11580, 185},
 		{0x11581, 0x115ae, 1},
-		{0x115d8, 0x115db, 1},
 		{0x11600, 0x1162f, 1},
 		{0x11644, 0x11680, 60},
 		{0x11681, 0x116aa, 1},
-		{0x11700, 0x11719, 1},
 		{0x118a0, 0x118df, 1},
 		{0x118ff, 0x11ac0, 449},
 		{0x11ac1, 0x11af8, 1},
-		{0x12000, 0x12399, 1},
-		{0x12480, 0x12543, 1},
+		{0x12000, 0x12398, 1},
 		{0x13000, 0x1342e, 1},
-		{0x14400, 0x14646, 1},
 		{0x16800, 0x16a38, 1},
 		{0x16a40, 0x16a5e, 1},
 		{0x16ad0, 0x16aed, 1},
@@ -646,7 +633,6 @@ var _L = &RangeTable{
 		{0x20000, 0x2a6d6, 1},
 		{0x2a700, 0x2b734, 1},
 		{0x2b740, 0x2b81d, 1},
-		{0x2b820, 0x2cea1, 1},
 		{0x2f800, 0x2fa1d, 1},
 	},
 	LatinOffset: 6,
@@ -705,7 +691,6 @@ var _Ll = &RangeTable{
 		{0x04c2, 0x04ce, 2},
 		{0x04cf, 0x052f, 2},
 		{0x0561, 0x0587, 1},
-		{0x13f8, 0x13fd, 1},
 		{0x1d00, 0x1d2b, 1},
 		{0x1d6b, 0x1d77, 1},
 		{0x1d79, 0x1d9a, 1},
@@ -762,18 +747,15 @@ var _Ll = &RangeTable{
 		{0xa791, 0xa793, 2},
 		{0xa794, 0xa795, 1},
 		{0xa797, 0xa7a9, 2},
-		{0xa7b5, 0xa7b7, 2},
 		{0xa7fa, 0xab30, 822},
 		{0xab31, 0xab5a, 1},
-		{0xab60, 0xab65, 1},
-		{0xab70, 0xabbf, 1},
+		{0xab64, 0xab65, 1},
 		{0xfb00, 0xfb06, 1},
 		{0xfb13, 0xfb17, 1},
 		{0xff41, 0xff5a, 1},
 	},
 	R32: []Range32{
 		{0x10428, 0x1044f, 1},
-		{0x10cc0, 0x10cf2, 1},
 		{0x118c0, 0x118df, 1},
 		{0x1d41a, 0x1d433, 1},
 		{0x1d44e, 0x1d454, 1},
@@ -879,7 +861,7 @@ var _Lo = &RangeTable{
 		{0x07cb, 0x07ea, 1},
 		{0x0800, 0x0815, 1},
 		{0x0840, 0x0858, 1},
-		{0x08a0, 0x08b4, 1},
+		{0x08a0, 0x08b2, 1},
 		{0x0904, 0x0939, 1},
 		{0x093d, 0x0950, 19},
 		{0x0958, 0x0961, 1},
@@ -912,8 +894,7 @@ var _Lo = &RangeTable{
 		{0x0ab5, 0x0ab9, 1},
 		{0x0abd, 0x0ad0, 19},
 		{0x0ae0, 0x0ae1, 1},
-		{0x0af9, 0x0b05, 12},
-		{0x0b06, 0x0b0c, 1},
+		{0x0b05, 0x0b0c, 1},
 		{0x0b0f, 0x0b10, 1},
 		{0x0b13, 0x0b28, 1},
 		{0x0b2a, 0x0b30, 1},
@@ -938,9 +919,9 @@ var _Lo = &RangeTable{
 		{0x0c12, 0x0c28, 1},
 		{0x0c2a, 0x0c39, 1},
 		{0x0c3d, 0x0c58, 27},
-		{0x0c59, 0x0c5a, 1},
-		{0x0c60, 0x0c61, 1},
-		{0x0c85, 0x0c8c, 1},
+		{0x0c59, 0x0c60, 7},
+		{0x0c61, 0x0c85, 36},
+		{0x0c86, 0x0c8c, 1},
 		{0x0c8e, 0x0c90, 1},
 		{0x0c92, 0x0ca8, 1},
 		{0x0caa, 0x0cb3, 1},
@@ -951,7 +932,7 @@ var _Lo = &RangeTable{
 		{0x0d05, 0x0d0c, 1},
 		{0x0d0e, 0x0d10, 1},
 		{0x0d12, 0x0d3a, 1},
-		{0x0d3d, 0x0d5f, 17},
+		{0x0d3d, 0x0d4e, 17},
 		{0x0d60, 0x0d61, 1},
 		{0x0d7a, 0x0d7f, 1},
 		{0x0d85, 0x0d96, 1},
@@ -1007,6 +988,7 @@ var _Lo = &RangeTable{
 		{0x1312, 0x1315, 1},
 		{0x1318, 0x135a, 1},
 		{0x1380, 0x138f, 1},
+		{0x13a0, 0x13f4, 1},
 		{0x1401, 0x166c, 1},
 		{0x166f, 0x167f, 1},
 		{0x1681, 0x169a, 1},
@@ -1029,7 +1011,7 @@ var _Lo = &RangeTable{
 		{0x1950, 0x196d, 1},
 		{0x1970, 0x1974, 1},
 		{0x1980, 0x19ab, 1},
-		{0x19b0, 0x19c9, 1},
+		{0x19c1, 0x19c7, 1},
 		{0x1a00, 0x1a16, 1},
 		{0x1a20, 0x1a54, 1},
 		{0x1b05, 0x1b33, 1},
@@ -1064,7 +1046,7 @@ var _Lo = &RangeTable{
 		{0x31a0, 0x31ba, 1},
 		{0x31f0, 0x31ff, 1},
 		{0x3400, 0x4db5, 1},
-		{0x4e00, 0x9fd5, 1},
+		{0x4e00, 0x9fcc, 1},
 		{0xa000, 0xa014, 1},
 		{0xa016, 0xa48c, 1},
 		{0xa4d0, 0xa4f7, 1},
@@ -1073,16 +1055,16 @@ var _Lo = &RangeTable{
 		{0xa62a, 0xa62b, 1},
 		{0xa66e, 0xa6a0, 50},
 		{0xa6a1, 0xa6e5, 1},
-		{0xa78f, 0xa7f7, 104},
-		{0xa7fb, 0xa801, 1},
+		{0xa7f7, 0xa7fb, 4},
+		{0xa7fc, 0xa801, 1},
 		{0xa803, 0xa805, 1},
 		{0xa807, 0xa80a, 1},
 		{0xa80c, 0xa822, 1},
 		{0xa840, 0xa873, 1},
 		{0xa882, 0xa8b3, 1},
 		{0xa8f2, 0xa8f7, 1},
-		{0xa8fb, 0xa8fd, 2},
-		{0xa90a, 0xa925, 1},
+		{0xa8fb, 0xa90a, 15},
+		{0xa90b, 0xa925, 1},
 		{0xa930, 0xa946, 1},
 		{0xa960, 0xa97c, 1},
 		{0xa984, 0xa9b2, 1},
@@ -1167,8 +1149,6 @@ var _Lo = &RangeTable{
 		{0x10840, 0x10855, 1},
 		{0x10860, 0x10876, 1},
 		{0x10880, 0x1089e, 1},
-		{0x108e0, 0x108f2, 1},
-		{0x108f4, 0x108f5, 1},
 		{0x10900, 0x10915, 1},
 		{0x10920, 0x10939, 1},
 		{0x10980, 0x109b7, 1},
@@ -1194,14 +1174,9 @@ var _Lo = &RangeTable{
 		{0x11176, 0x11183, 13},
 		{0x11184, 0x111b2, 1},
 		{0x111c1, 0x111c4, 1},
-		{0x111da, 0x111dc, 2},
-		{0x11200, 0x11211, 1},
+		{0x111da, 0x11200, 38},
+		{0x11201, 0x11211, 1},
 		{0x11213, 0x1122b, 1},
-		{0x11280, 0x11286, 1},
-		{0x11288, 0x1128a, 2},
-		{0x1128b, 0x1128d, 1},
-		{0x1128f, 0x1129d, 1},
-		{0x1129f, 0x112a8, 1},
 		{0x112b0, 0x112de, 1},
 		{0x11305, 0x1130c, 1},
 		{0x1130f, 0x11310, 1},
@@ -1209,23 +1184,19 @@ var _Lo = &RangeTable{
 		{0x1132a, 0x11330, 1},
 		{0x11332, 0x11333, 1},
 		{0x11335, 0x11339, 1},
-		{0x1133d, 0x11350, 19},
-		{0x1135d, 0x11361, 1},
+		{0x1133d, 0x1135d, 32},
+		{0x1135e, 0x11361, 1},
 		{0x11480, 0x114af, 1},
 		{0x114c4, 0x114c5, 1},
 		{0x114c7, 0x11580, 185},
 		{0x11581, 0x115ae, 1},
-		{0x115d8, 0x115db, 1},
 		{0x11600, 0x1162f, 1},
 		{0x11644, 0x11680, 60},
 		{0x11681, 0x116aa, 1},
-		{0x11700, 0x11719, 1},
 		{0x118ff, 0x11ac0, 449},
 		{0x11ac1, 0x11af8, 1},
-		{0x12000, 0x12399, 1},
-		{0x12480, 0x12543, 1},
+		{0x12000, 0x12398, 1},
 		{0x13000, 0x1342e, 1},
-		{0x14400, 0x14646, 1},
 		{0x16800, 0x16a38, 1},
 		{0x16a40, 0x16a5e, 1},
 		{0x16ad0, 0x16aed, 1},
@@ -1267,7 +1238,6 @@ var _Lo = &RangeTable{
 		{0x20000, 0x2a6d6, 1},
 		{0x2a700, 0x2b734, 1},
 		{0x2b740, 0x2b81d, 1},
-		{0x2b820, 0x2cea1, 1},
 		{0x2f800, 0x2fa1d, 1},
 	},
 	LatinOffset: 1,
@@ -1342,7 +1312,6 @@ var _Lu = &RangeTable{
 		{0x0531, 0x0556, 1},
 		{0x10a0, 0x10c5, 1},
 		{0x10c7, 0x10cd, 6},
-		{0x13a0, 0x13f5, 1},
 		{0x1e00, 0x1e94, 2},
 		{0x1e9e, 0x1efe, 2},
 		{0x1f08, 0x1f0f, 1},
@@ -1387,13 +1356,11 @@ var _Lu = &RangeTable{
 		{0xa790, 0xa792, 2},
 		{0xa796, 0xa7aa, 2},
 		{0xa7ab, 0xa7ad, 1},
-		{0xa7b0, 0xa7b4, 1},
-		{0xa7b6, 0xff21, 22379},
-		{0xff22, 0xff3a, 1},
+		{0xa7b0, 0xa7b1, 1},
+		{0xff21, 0xff3a, 1},
 	},
 	R32: []Range32{
 		{0x10400, 0x10427, 1},
-		{0x10c80, 0x10cb2, 1},
 		{0x118a0, 0x118bf, 1},
 		{0x1d400, 0x1d419, 1},
 		{0x1d434, 0x1d44d, 1},
@@ -1453,7 +1420,7 @@ var _M = &RangeTable{
 		{0x0825, 0x0827, 1},
 		{0x0829, 0x082d, 1},
 		{0x0859, 0x085b, 1},
-		{0x08e3, 0x0903, 1},
+		{0x08e4, 0x0903, 1},
 		{0x093a, 0x093c, 1},
 		{0x093e, 0x094f, 1},
 		{0x0951, 0x0957, 1},
@@ -1549,6 +1516,8 @@ var _M = &RangeTable{
 		{0x18a9, 0x1920, 119},
 		{0x1921, 0x192b, 1},
 		{0x1930, 0x193b, 1},
+		{0x19b0, 0x19c0, 1},
+		{0x19c8, 0x19c9, 1},
 		{0x1a17, 0x1a1b, 1},
 		{0x1a55, 0x1a5e, 1},
 		{0x1a60, 0x1a7c, 1},
@@ -1576,11 +1545,10 @@ var _M = &RangeTable{
 		{0x3099, 0x309a, 1},
 		{0xa66f, 0xa672, 1},
 		{0xa674, 0xa67d, 1},
-		{0xa69e, 0xa69f, 1},
-		{0xa6f0, 0xa6f1, 1},
-		{0xa802, 0xa806, 4},
-		{0xa80b, 0xa823, 24},
-		{0xa824, 0xa827, 1},
+		{0xa69f, 0xa6f0, 81},
+		{0xa6f1, 0xa802, 273},
+		{0xa806, 0xa80b, 5},
+		{0xa823, 0xa827, 1},
 		{0xa880, 0xa881, 1},
 		{0xa8b4, 0xa8c4, 1},
 		{0xa8e0, 0xa8f1, 1},
@@ -1604,7 +1572,7 @@ var _M = &RangeTable{
 		{0xabec, 0xabed, 1},
 		{0xfb1e, 0xfe00, 738},
 		{0xfe01, 0xfe0f, 1},
-		{0xfe20, 0xfe2f, 1},
+		{0xfe20, 0xfe2d, 1},
 	},
 	R32: []Range32{
 		{0x101fd, 0x102e0, 227},
@@ -1624,10 +1592,9 @@ var _M = &RangeTable{
 		{0x11173, 0x11180, 13},
 		{0x11181, 0x11182, 1},
 		{0x111b3, 0x111c0, 1},
-		{0x111ca, 0x111cc, 1},
 		{0x1122c, 0x11237, 1},
 		{0x112df, 0x112ea, 1},
-		{0x11300, 0x11303, 1},
+		{0x11301, 0x11303, 1},
 		{0x1133c, 0x1133e, 2},
 		{0x1133f, 0x11344, 1},
 		{0x11347, 0x11348, 1},
@@ -1639,10 +1606,8 @@ var _M = &RangeTable{
 		{0x114b0, 0x114c3, 1},
 		{0x115af, 0x115b5, 1},
 		{0x115b8, 0x115c0, 1},
-		{0x115dc, 0x115dd, 1},
 		{0x11630, 0x11640, 1},
 		{0x116ab, 0x116b7, 1},
-		{0x1171d, 0x1172b, 1},
 		{0x16af0, 0x16af4, 1},
 		{0x16b30, 0x16b36, 1},
 		{0x16f51, 0x16f7e, 1},
@@ -1654,11 +1619,6 @@ var _M = &RangeTable{
 		{0x1d185, 0x1d18b, 1},
 		{0x1d1aa, 0x1d1ad, 1},
 		{0x1d242, 0x1d244, 1},
-		{0x1da00, 0x1da36, 1},
-		{0x1da3b, 0x1da6c, 1},
-		{0x1da75, 0x1da84, 15},
-		{0x1da9b, 0x1da9f, 1},
-		{0x1daa1, 0x1daaf, 1},
 		{0x1e8d0, 0x1e8d6, 1},
 		{0xe0100, 0xe01ef, 1},
 	},
@@ -1725,6 +1685,8 @@ var _Mc = &RangeTable{
 		{0x1929, 0x192b, 1},
 		{0x1930, 0x1931, 1},
 		{0x1933, 0x1938, 1},
+		{0x19b0, 0x19c0, 1},
+		{0x19c8, 0x19c9, 1},
 		{0x1a19, 0x1a1a, 1},
 		{0x1a55, 0x1a57, 2},
 		{0x1a61, 0x1a63, 2},
@@ -1793,9 +1755,8 @@ var _Mc = &RangeTable{
 		{0x1163b, 0x1163c, 1},
 		{0x1163e, 0x116ac, 110},
 		{0x116ae, 0x116af, 1},
-		{0x116b6, 0x11720, 106},
-		{0x11721, 0x11726, 5},
-		{0x16f51, 0x16f7e, 1},
+		{0x116b6, 0x16f51, 22683},
+		{0x16f52, 0x16f7e, 1},
 		{0x1d165, 0x1d166, 1},
 		{0x1d16d, 0x1d172, 1},
 	},
@@ -1835,7 +1796,7 @@ var _Mn = &RangeTable{
 		{0x0825, 0x0827, 1},
 		{0x0829, 0x082d, 1},
 		{0x0859, 0x085b, 1},
-		{0x08e3, 0x0902, 1},
+		{0x08e4, 0x0902, 1},
 		{0x093a, 0x093c, 2},
 		{0x0941, 0x0948, 1},
 		{0x094d, 0x0951, 4},
@@ -1957,12 +1918,12 @@ var _Mn = &RangeTable{
 		{0x3099, 0x309a, 1},
 		{0xa66f, 0xa674, 5},
 		{0xa675, 0xa67d, 1},
-		{0xa69e, 0xa69f, 1},
-		{0xa6f0, 0xa6f1, 1},
-		{0xa802, 0xa806, 4},
-		{0xa80b, 0xa825, 26},
-		{0xa826, 0xa8c4, 158},
-		{0xa8e0, 0xa8f1, 1},
+		{0xa69f, 0xa6f0, 81},
+		{0xa6f1, 0xa802, 273},
+		{0xa806, 0xa80b, 5},
+		{0xa825, 0xa826, 1},
+		{0xa8c4, 0xa8e0, 28},
+		{0xa8e1, 0xa8f1, 1},
 		{0xa926, 0xa92d, 1},
 		{0xa947, 0xa951, 1},
 		{0xa980, 0xa982, 1},
@@ -1982,7 +1943,7 @@ var _Mn = &RangeTable{
 		{0xabe5, 0xabe8, 3},
 		{0xabed, 0xfb1e, 20273},
 		{0xfe00, 0xfe0f, 1},
-		{0xfe20, 0xfe2f, 1},
+		{0xfe20, 0xfe2d, 1},
 	},
 	R32: []Range32{
 		{0x101fd, 0x102e0, 227},
@@ -2003,14 +1964,13 @@ var _Mn = &RangeTable{
 		{0x11173, 0x11180, 13},
 		{0x11181, 0x111b6, 53},
 		{0x111b7, 0x111be, 1},
-		{0x111ca, 0x111cc, 1},
 		{0x1122f, 0x11231, 1},
 		{0x11234, 0x11236, 2},
 		{0x11237, 0x112df, 168},
 		{0x112e3, 0x112ea, 1},
-		{0x11300, 0x11301, 1},
-		{0x1133c, 0x11340, 4},
-		{0x11366, 0x1136c, 1},
+		{0x11301, 0x1133c, 59},
+		{0x11340, 0x11366, 38},
+		{0x11367, 0x1136c, 1},
 		{0x11370, 0x11374, 1},
 		{0x114b3, 0x114b8, 1},
 		{0x114ba, 0x114bf, 5},
@@ -2019,17 +1979,13 @@ var _Mn = &RangeTable{
 		{0x115b3, 0x115b5, 1},
 		{0x115bc, 0x115bd, 1},
 		{0x115bf, 0x115c0, 1},
-		{0x115dc, 0x115dd, 1},
 		{0x11633, 0x1163a, 1},
 		{0x1163d, 0x1163f, 2},
 		{0x11640, 0x116ab, 107},
 		{0x116ad, 0x116b0, 3},
 		{0x116b1, 0x116b5, 1},
-		{0x116b7, 0x1171d, 102},
-		{0x1171e, 0x1171f, 1},
-		{0x11722, 0x11725, 1},
-		{0x11727, 0x1172b, 1},
-		{0x16af0, 0x16af4, 1},
+		{0x116b7, 0x16af0, 21561},
+		{0x16af1, 0x16af4, 1},
 		{0x16b30, 0x16b36, 1},
 		{0x16f8f, 0x16f92, 1},
 		{0x1bc9d, 0x1bc9e, 1},
@@ -2038,11 +1994,6 @@ var _Mn = &RangeTable{
 		{0x1d185, 0x1d18b, 1},
 		{0x1d1aa, 0x1d1ad, 1},
 		{0x1d242, 0x1d244, 1},
-		{0x1da00, 0x1da36, 1},
-		{0x1da3b, 0x1da6c, 1},
-		{0x1da75, 0x1da84, 15},
-		{0x1da9b, 0x1da9f, 1},
-		{0x1daa1, 0x1daaf, 1},
 		{0x1e8d0, 0x1e8d6, 1},
 		{0xe0100, 0xe01ef, 1},
 	},
@@ -2128,11 +2079,7 @@ var _N = &RangeTable{
 		{0x10858, 0x1085f, 1},
 		{0x10879, 0x1087f, 1},
 		{0x108a7, 0x108af, 1},
-		{0x108fb, 0x108ff, 1},
 		{0x10916, 0x1091b, 1},
-		{0x109bc, 0x109bd, 1},
-		{0x109c0, 0x109cf, 1},
-		{0x109d2, 0x109ff, 1},
 		{0x10a40, 0x10a47, 1},
 		{0x10a7d, 0x10a7e, 1},
 		{0x10a9d, 0x10a9f, 1},
@@ -2140,7 +2087,6 @@ var _N = &RangeTable{
 		{0x10b58, 0x10b5f, 1},
 		{0x10b78, 0x10b7f, 1},
 		{0x10ba9, 0x10baf, 1},
-		{0x10cfa, 0x10cff, 1},
 		{0x10e60, 0x10e7e, 1},
 		{0x11052, 0x1106f, 1},
 		{0x110f0, 0x110f9, 1},
@@ -2151,7 +2097,6 @@ var _N = &RangeTable{
 		{0x114d0, 0x114d9, 1},
 		{0x11650, 0x11659, 1},
 		{0x116c0, 0x116c9, 1},
-		{0x11730, 0x1173b, 1},
 		{0x118e0, 0x118f2, 1},
 		{0x12400, 0x1246e, 1},
 		{0x16a60, 0x16a69, 1},
@@ -2215,7 +2160,6 @@ var _Nd = &RangeTable{
 		{0x114d0, 0x114d9, 1},
 		{0x11650, 0x11659, 1},
 		{0x116c0, 0x116c9, 1},
-		{0x11730, 0x11739, 1},
 		{0x118e0, 0x118e9, 1},
 		{0x16a60, 0x16a69, 1},
 		{0x16b50, 0x16b59, 1},
@@ -2281,11 +2225,7 @@ var _No = &RangeTable{
 		{0x10858, 0x1085f, 1},
 		{0x10879, 0x1087f, 1},
 		{0x108a7, 0x108af, 1},
-		{0x108fb, 0x108ff, 1},
 		{0x10916, 0x1091b, 1},
-		{0x109bc, 0x109bd, 1},
-		{0x109c0, 0x109cf, 1},
-		{0x109d2, 0x109ff, 1},
 		{0x10a40, 0x10a47, 1},
 		{0x10a7d, 0x10a7e, 1},
 		{0x10a9d, 0x10a9f, 1},
@@ -2293,11 +2233,9 @@ var _No = &RangeTable{
 		{0x10b58, 0x10b5f, 1},
 		{0x10b78, 0x10b7f, 1},
 		{0x10ba9, 0x10baf, 1},
-		{0x10cfa, 0x10cff, 1},
 		{0x10e60, 0x10e7e, 1},
 		{0x11052, 0x11065, 1},
 		{0x111e1, 0x111f4, 1},
-		{0x1173a, 0x1173b, 1},
 		{0x118ea, 0x118f2, 1},
 		{0x16b5b, 0x16b61, 1},
 		{0x1d360, 0x1d371, 1},
@@ -2398,9 +2336,9 @@ var _P = &RangeTable{
 		{0xa874, 0xa877, 1},
 		{0xa8ce, 0xa8cf, 1},
 		{0xa8f8, 0xa8fa, 1},
-		{0xa8fc, 0xa92e, 50},
-		{0xa92f, 0xa95f, 48},
-		{0xa9c1, 0xa9cd, 1},
+		{0xa92e, 0xa92f, 1},
+		{0xa95f, 0xa9c1, 98},
+		{0xa9c2, 0xa9cd, 1},
 		{0xa9de, 0xa9df, 1},
 		{0xaa5c, 0xaa5f, 1},
 		{0xaade, 0xaadf, 1},
@@ -2437,20 +2375,17 @@ var _P = &RangeTable{
 		{0x110be, 0x110c1, 1},
 		{0x11140, 0x11143, 1},
 		{0x11174, 0x11175, 1},
-		{0x111c5, 0x111c9, 1},
-		{0x111cd, 0x111db, 14},
-		{0x111dd, 0x111df, 1},
-		{0x11238, 0x1123d, 1},
-		{0x112a9, 0x114c6, 541},
-		{0x115c1, 0x115d7, 1},
+		{0x111c5, 0x111c8, 1},
+		{0x111cd, 0x11238, 107},
+		{0x11239, 0x1123d, 1},
+		{0x114c6, 0x115c1, 251},
+		{0x115c2, 0x115c9, 1},
 		{0x11641, 0x11643, 1},
-		{0x1173c, 0x1173e, 1},
 		{0x12470, 0x12474, 1},
 		{0x16a6e, 0x16a6f, 1},
 		{0x16af5, 0x16b37, 66},
 		{0x16b38, 0x16b3b, 1},
 		{0x16b44, 0x1bc9f, 20827},
-		{0x1da87, 0x1da8b, 1},
 	},
 	LatinOffset: 11,
 }
@@ -2615,9 +2550,9 @@ var _Po = &RangeTable{
 		{0xa874, 0xa877, 1},
 		{0xa8ce, 0xa8cf, 1},
 		{0xa8f8, 0xa8fa, 1},
-		{0xa8fc, 0xa92e, 50},
-		{0xa92f, 0xa95f, 48},
-		{0xa9c1, 0xa9cd, 1},
+		{0xa92e, 0xa92f, 1},
+		{0xa95f, 0xa9c1, 98},
+		{0xa9c2, 0xa9cd, 1},
 		{0xa9de, 0xa9df, 1},
 		{0xaa5c, 0xaa5f, 1},
 		{0xaade, 0xaadf, 1},
@@ -2657,20 +2592,17 @@ var _Po = &RangeTable{
 		{0x110be, 0x110c1, 1},
 		{0x11140, 0x11143, 1},
 		{0x11174, 0x11175, 1},
-		{0x111c5, 0x111c9, 1},
-		{0x111cd, 0x111db, 14},
-		{0x111dd, 0x111df, 1},
-		{0x11238, 0x1123d, 1},
-		{0x112a9, 0x114c6, 541},
-		{0x115c1, 0x115d7, 1},
+		{0x111c5, 0x111c8, 1},
+		{0x111cd, 0x11238, 107},
+		{0x11239, 0x1123d, 1},
+		{0x114c6, 0x115c1, 251},
+		{0x115c2, 0x115c9, 1},
 		{0x11641, 0x11643, 1},
-		{0x1173c, 0x1173e, 1},
 		{0x12470, 0x12474, 1},
 		{0x16a6e, 0x16a6f, 1},
 		{0x16af5, 0x16b37, 66},
 		{0x16b38, 0x16b3b, 1},
 		{0x16b44, 0x1bc9f, 20827},
-		{0x1da87, 0x1da8b, 1},
 	},
 	LatinOffset: 8,
 }
@@ -2762,7 +2694,7 @@ var _S = &RangeTable{
 		{0x2044, 0x2052, 14},
 		{0x207a, 0x207c, 1},
 		{0x208a, 0x208c, 1},
-		{0x20a0, 0x20be, 1},
+		{0x20a0, 0x20bd, 1},
 		{0x2100, 0x2101, 1},
 		{0x2103, 0x2106, 1},
 		{0x2108, 0x2109, 1},
@@ -2774,8 +2706,7 @@ var _S = &RangeTable{
 		{0x213b, 0x2140, 5},
 		{0x2141, 0x2144, 1},
 		{0x214a, 0x214d, 1},
-		{0x214f, 0x218a, 59},
-		{0x218b, 0x2190, 5},
+		{0x214f, 0x2190, 65},
 		{0x2191, 0x2307, 1},
 		{0x230c, 0x2328, 1},
 		{0x232b, 0x23fa, 1},
@@ -2793,7 +2724,6 @@ var _S = &RangeTable{
 		{0x2b98, 0x2bb9, 1},
 		{0x2bbd, 0x2bc8, 1},
 		{0x2bca, 0x2bd1, 1},
-		{0x2bec, 0x2bef, 1},
 		{0x2ce5, 0x2cea, 1},
 		{0x2e80, 0x2e99, 1},
 		{0x2e9b, 0x2ef3, 1},
@@ -2844,8 +2774,8 @@ var _S = &RangeTable{
 		{0x101a0, 0x101d0, 48},
 		{0x101d1, 0x101fc, 1},
 		{0x10877, 0x10878, 1},
-		{0x10ac8, 0x1173f, 3191},
-		{0x16b3c, 0x16b3f, 1},
+		{0x10ac8, 0x16b3c, 24692},
+		{0x16b3d, 0x16b3f, 1},
 		{0x16b45, 0x1bc9c, 20823},
 		{0x1d000, 0x1d0f5, 1},
 		{0x1d100, 0x1d126, 1},
@@ -2853,7 +2783,7 @@ var _S = &RangeTable{
 		{0x1d16a, 0x1d16c, 1},
 		{0x1d183, 0x1d184, 1},
 		{0x1d18c, 0x1d1a9, 1},
-		{0x1d1ae, 0x1d1e8, 1},
+		{0x1d1ae, 0x1d1dd, 1},
 		{0x1d200, 0x1d241, 1},
 		{0x1d245, 0x1d300, 187},
 		{0x1d301, 0x1d356, 1},
@@ -2862,11 +2792,6 @@ var _S = &RangeTable{
 		{0x1d735, 0x1d74f, 26},
 		{0x1d76f, 0x1d789, 26},
 		{0x1d7a9, 0x1d7c3, 26},
-		{0x1d800, 0x1d9ff, 1},
-		{0x1da37, 0x1da3a, 1},
-		{0x1da6d, 0x1da74, 1},
-		{0x1da76, 0x1da83, 1},
-		{0x1da85, 0x1da86, 1},
 		{0x1eef0, 0x1eef1, 1},
 		{0x1f000, 0x1f02b, 1},
 		{0x1f030, 0x1f093, 1},
@@ -2881,9 +2806,16 @@ var _S = &RangeTable{
 		{0x1f210, 0x1f23a, 1},
 		{0x1f240, 0x1f248, 1},
 		{0x1f250, 0x1f251, 1},
-		{0x1f300, 0x1f579, 1},
+		{0x1f300, 0x1f32c, 1},
+		{0x1f330, 0x1f37d, 1},
+		{0x1f380, 0x1f3ce, 1},
+		{0x1f3d4, 0x1f3f7, 1},
+		{0x1f400, 0x1f4fe, 1},
+		{0x1f500, 0x1f54a, 1},
+		{0x1f550, 0x1f579, 1},
 		{0x1f57b, 0x1f5a3, 1},
-		{0x1f5a5, 0x1f6d0, 1},
+		{0x1f5a5, 0x1f642, 1},
+		{0x1f645, 0x1f6cf, 1},
 		{0x1f6e0, 0x1f6ec, 1},
 		{0x1f6f0, 0x1f6f3, 1},
 		{0x1f700, 0x1f773, 1},
@@ -2893,9 +2825,6 @@ var _S = &RangeTable{
 		{0x1f850, 0x1f859, 1},
 		{0x1f860, 0x1f887, 1},
 		{0x1f890, 0x1f8ad, 1},
-		{0x1f910, 0x1f918, 1},
-		{0x1f980, 0x1f984, 1},
-		{0x1f9c0, 0x1f9c0, 1},
 	},
 	LatinOffset: 10,
 }
@@ -2909,7 +2838,7 @@ var _Sc = &RangeTable{
 		{0x09fb, 0x0af1, 246},
 		{0x0bf9, 0x0e3f, 582},
 		{0x17db, 0x20a0, 2245},
-		{0x20a1, 0x20be, 1},
+		{0x20a1, 0x20bd, 1},
 		{0xa838, 0xfdfc, 21956},
 		{0xfe69, 0xff04, 155},
 		{0xffe0, 0xffe1, 1},
@@ -2944,10 +2873,6 @@ var _Sk = &RangeTable{
 		{0xff3e, 0xff40, 2},
 		{0xffe3, 0xffe3, 1},
 	},
-	R32: []Range32{
-		{0x1f3fb, 0x1f3fb, 1},
-		{0x1f3fc, 0x1f3ff, 1},
-	},
 	LatinOffset: 3,
 }
 
@@ -3046,8 +2971,7 @@ var _So = &RangeTable{
 		{0x212e, 0x213a, 12},
 		{0x213b, 0x214a, 15},
 		{0x214c, 0x214d, 1},
-		{0x214f, 0x218a, 59},
-		{0x218b, 0x2195, 10},
+		{0x214f, 0x2195, 70},
 		{0x2196, 0x2199, 1},
 		{0x219c, 0x219f, 1},
 		{0x21a1, 0x21a2, 1},
@@ -3081,7 +3005,6 @@ var _So = &RangeTable{
 		{0x2b98, 0x2bb9, 1},
 		{0x2bbd, 0x2bc8, 1},
 		{0x2bca, 0x2bd1, 1},
-		{0x2bec, 0x2bef, 1},
 		{0x2ce5, 0x2cea, 1},
 		{0x2e80, 0x2e99, 1},
 		{0x2e9b, 0x2ef3, 1},
@@ -3121,8 +3044,8 @@ var _So = &RangeTable{
 		{0x101a0, 0x101d0, 48},
 		{0x101d1, 0x101fc, 1},
 		{0x10877, 0x10878, 1},
-		{0x10ac8, 0x1173f, 3191},
-		{0x16b3c, 0x16b3f, 1},
+		{0x10ac8, 0x16b3c, 24692},
+		{0x16b3d, 0x16b3f, 1},
 		{0x16b45, 0x1bc9c, 20823},
 		{0x1d000, 0x1d0f5, 1},
 		{0x1d100, 0x1d126, 1},
@@ -3130,15 +3053,10 @@ var _So = &RangeTable{
 		{0x1d16a, 0x1d16c, 1},
 		{0x1d183, 0x1d184, 1},
 		{0x1d18c, 0x1d1a9, 1},
-		{0x1d1ae, 0x1d1e8, 1},
+		{0x1d1ae, 0x1d1dd, 1},
 		{0x1d200, 0x1d241, 1},
 		{0x1d245, 0x1d300, 187},
 		{0x1d301, 0x1d356, 1},
-		{0x1d800, 0x1d9ff, 1},
-		{0x1da37, 0x1da3a, 1},
-		{0x1da6d, 0x1da74, 1},
-		{0x1da76, 0x1da83, 1},
-		{0x1da85, 0x1da86, 1},
 		{0x1f000, 0x1f02b, 1},
 		{0x1f030, 0x1f093, 1},
 		{0x1f0a0, 0x1f0ae, 1},
@@ -3152,10 +3070,16 @@ var _So = &RangeTable{
 		{0x1f210, 0x1f23a, 1},
 		{0x1f240, 0x1f248, 1},
 		{0x1f250, 0x1f251, 1},
-		{0x1f300, 0x1f3fa, 1},
-		{0x1f400, 0x1f579, 1},
+		{0x1f300, 0x1f32c, 1},
+		{0x1f330, 0x1f37d, 1},
+		{0x1f380, 0x1f3ce, 1},
+		{0x1f3d4, 0x1f3f7, 1},
+		{0x1f400, 0x1f4fe, 1},
+		{0x1f500, 0x1f54a, 1},
+		{0x1f550, 0x1f579, 1},
 		{0x1f57b, 0x1f5a3, 1},
-		{0x1f5a5, 0x1f6d0, 1},
+		{0x1f5a5, 0x1f642, 1},
+		{0x1f645, 0x1f6cf, 1},
 		{0x1f6e0, 0x1f6ec, 1},
 		{0x1f6f0, 0x1f6f3, 1},
 		{0x1f700, 0x1f773, 1},
@@ -3165,9 +3089,6 @@ var _So = &RangeTable{
 		{0x1f850, 0x1f859, 1},
 		{0x1f860, 0x1f887, 1},
 		{0x1f890, 0x1f8ad, 1},
-		{0x1f910, 0x1f918, 1},
-		{0x1f980, 0x1f984, 1},
-		{0x1f9c0, 0x1f9c0, 1},
 	},
 	LatinOffset: 2,
 }
@@ -3259,13 +3180,11 @@ var (
 )
 
 // Generated by running
-//	maketables --scripts=all --url=http://www.unicode.org/Public/8.0.0/ucd/
+//	maketables --scripts=all --url=http://www.unicode.org/Public/7.0.0/ucd/
 // DO NOT EDIT
 
 // Scripts is the set of Unicode script tables.
 var Scripts = map[string]*RangeTable{
-	"Ahom":                   Ahom,
-	"Anatolian_Hieroglyphs":  Anatolian_Hieroglyphs,
 	"Arabic":                 Arabic,
 	"Armenian":               Armenian,
 	"Avestan":                Avestan,
@@ -3306,7 +3225,6 @@ var Scripts = map[string]*RangeTable{
 	"Han":                    Han,
 	"Hangul":                 Hangul,
 	"Hanunoo":                Hanunoo,
-	"Hatran":                 Hatran,
 	"Hebrew":                 Hebrew,
 	"Hiragana":               Hiragana,
 	"Imperial_Aramaic":       Imperial_Aramaic,
@@ -3343,14 +3261,12 @@ var Scripts = map[string]*RangeTable{
 	"Modi":                   Modi,
 	"Mongolian":              Mongolian,
 	"Mro":                    Mro,
-	"Multani":                Multani,
 	"Myanmar":                Myanmar,
 	"Nabataean":              Nabataean,
 	"New_Tai_Lue":            New_Tai_Lue,
 	"Nko":                    Nko,
 	"Ogham":                  Ogham,
 	"Ol_Chiki":               Ol_Chiki,
-	"Old_Hungarian":          Old_Hungarian,
 	"Old_Italic":             Old_Italic,
 	"Old_North_Arabian":      Old_North_Arabian,
 	"Old_Permic":             Old_Permic,
@@ -3372,7 +3288,6 @@ var Scripts = map[string]*RangeTable{
 	"Sharada":                Sharada,
 	"Shavian":                Shavian,
 	"Siddham":                Siddham,
-	"SignWriting":            SignWriting,
 	"Sinhala":                Sinhala,
 	"Sora_Sompeng":           Sora_Sompeng,
 	"Sundanese":              Sundanese,
@@ -3397,22 +3312,6 @@ var Scripts = map[string]*RangeTable{
 	"Yi":                     Yi,
 }
 
-var _Ahom = &RangeTable{
-	R16: []Range16{},
-	R32: []Range32{
-		{0x11700, 0x11719, 1},
-		{0x1171d, 0x1172b, 1},
-		{0x11730, 0x1173f, 1},
-	},
-}
-
-var _Anatolian_Hieroglyphs = &RangeTable{
-	R16: []Range16{},
-	R32: []Range32{
-		{0x14400, 0x14646, 1},
-	},
-}
-
 var _Arabic = &RangeTable{
 	R16: []Range16{
 		{0x0600, 0x0604, 1},
@@ -3421,12 +3320,13 @@ var _Arabic = &RangeTable{
 		{0x061e, 0x061e, 1},
 		{0x0620, 0x063f, 1},
 		{0x0641, 0x064a, 1},
-		{0x0656, 0x066f, 1},
+		{0x0656, 0x065f, 1},
+		{0x066a, 0x066f, 1},
 		{0x0671, 0x06dc, 1},
 		{0x06de, 0x06ff, 1},
 		{0x0750, 0x077f, 1},
-		{0x08a0, 0x08b4, 1},
-		{0x08e3, 0x08ff, 1},
+		{0x08a0, 0x08b2, 1},
+		{0x08e4, 0x08ff, 1},
 		{0xfb50, 0xfbc1, 1},
 		{0xfbd3, 0xfd3d, 1},
 		{0xfd50, 0xfd8f, 1},
@@ -3620,9 +3520,7 @@ var _Cham = &RangeTable{
 
 var _Cherokee = &RangeTable{
 	R16: []Range16{
-		{0x13a0, 0x13f5, 1},
-		{0x13f8, 0x13fd, 1},
-		{0xab70, 0xabbf, 1},
+		{0x13a0, 0x13f4, 1},
 	},
 }
 
@@ -3648,6 +3546,7 @@ var _Common = &RangeTable{
 		{0x061b, 0x061c, 1},
 		{0x061f, 0x061f, 1},
 		{0x0640, 0x0640, 1},
+		{0x0660, 0x0669, 1},
 		{0x06dd, 0x06dd, 1},
 		{0x0964, 0x0965, 1},
 		{0x0e3f, 0x0e3f, 1},
@@ -3667,13 +3566,13 @@ var _Common = &RangeTable{
 		{0x2066, 0x2070, 1},
 		{0x2074, 0x207e, 1},
 		{0x2080, 0x208e, 1},
-		{0x20a0, 0x20be, 1},
+		{0x20a0, 0x20bd, 1},
 		{0x2100, 0x2125, 1},
 		{0x2127, 0x2129, 1},
 		{0x212c, 0x2131, 1},
 		{0x2133, 0x214d, 1},
 		{0x214f, 0x215f, 1},
-		{0x2189, 0x218b, 1},
+		{0x2189, 0x2189, 1},
 		{0x2190, 0x23fa, 1},
 		{0x2400, 0x2426, 1},
 		{0x2440, 0x244a, 1},
@@ -3683,7 +3582,6 @@ var _Common = &RangeTable{
 		{0x2b98, 0x2bb9, 1},
 		{0x2bbd, 0x2bc8, 1},
 		{0x2bca, 0x2bd1, 1},
-		{0x2bec, 0x2bef, 1},
 		{0x2e00, 0x2e42, 1},
 		{0x2ff0, 0x2ffb, 1},
 		{0x3000, 0x3004, 1},
@@ -3735,7 +3633,7 @@ var _Common = &RangeTable{
 		{0x1d16a, 0x1d17a, 1},
 		{0x1d183, 0x1d184, 1},
 		{0x1d18c, 0x1d1a9, 1},
-		{0x1d1ae, 0x1d1e8, 1},
+		{0x1d1ae, 0x1d1dd, 1},
 		{0x1d300, 0x1d356, 1},
 		{0x1d360, 0x1d371, 1},
 		{0x1d400, 0x1d454, 1},
@@ -3774,9 +3672,16 @@ var _Common = &RangeTable{
 		{0x1f210, 0x1f23a, 1},
 		{0x1f240, 0x1f248, 1},
 		{0x1f250, 0x1f251, 1},
-		{0x1f300, 0x1f579, 1},
+		{0x1f300, 0x1f32c, 1},
+		{0x1f330, 0x1f37d, 1},
+		{0x1f380, 0x1f3ce, 1},
+		{0x1f3d4, 0x1f3f7, 1},
+		{0x1f400, 0x1f4fe, 1},
+		{0x1f500, 0x1f54a, 1},
+		{0x1f550, 0x1f579, 1},
 		{0x1f57b, 0x1f5a3, 1},
-		{0x1f5a5, 0x1f6d0, 1},
+		{0x1f5a5, 0x1f642, 1},
+		{0x1f645, 0x1f6cf, 1},
 		{0x1f6e0, 0x1f6ec, 1},
 		{0x1f6f0, 0x1f6f3, 1},
 		{0x1f700, 0x1f773, 1},
@@ -3786,9 +3691,6 @@ var _Common = &RangeTable{
 		{0x1f850, 0x1f859, 1},
 		{0x1f860, 0x1f887, 1},
 		{0x1f890, 0x1f8ad, 1},
-		{0x1f910, 0x1f918, 1},
-		{0x1f980, 0x1f984, 1},
-		{0x1f9c0, 0x1f9c0, 1},
 		{0xe0001, 0xe0001, 1},
 		{0xe0020, 0xe007f, 1},
 	},
@@ -3806,10 +3708,9 @@ var _Coptic = &RangeTable{
 var _Cuneiform = &RangeTable{
 	R16: []Range16{},
 	R32: []Range32{
-		{0x12000, 0x12399, 1},
+		{0x12000, 0x12398, 1},
 		{0x12400, 0x1246e, 1},
 		{0x12470, 0x12474, 1},
-		{0x12480, 0x12543, 1},
 	},
 }
 
@@ -3832,8 +3733,8 @@ var _Cyrillic = &RangeTable{
 		{0x1d2b, 0x1d2b, 1},
 		{0x1d78, 0x1d78, 1},
 		{0x2de0, 0x2dff, 1},
-		{0xa640, 0xa69f, 1},
-		{0xfe2e, 0xfe2f, 1},
+		{0xa640, 0xa69d, 1},
+		{0xa69f, 0xa69f, 1},
 	},
 }
 
@@ -3849,7 +3750,7 @@ var _Devanagari = &RangeTable{
 		{0x0900, 0x0950, 1},
 		{0x0953, 0x0963, 1},
 		{0x0966, 0x097f, 1},
-		{0xa8e0, 0xa8fd, 1},
+		{0xa8e0, 0xa8fb, 1},
 	},
 }
 
@@ -3945,7 +3846,7 @@ var _Gothic = &RangeTable{
 var _Grantha = &RangeTable{
 	R16: []Range16{},
 	R32: []Range32{
-		{0x11300, 0x11303, 1},
+		{0x11301, 0x11303, 1},
 		{0x11305, 0x1130c, 1},
 		{0x1130f, 0x11310, 1},
 		{0x11313, 0x11328, 1},
@@ -3955,7 +3856,6 @@ var _Grantha = &RangeTable{
 		{0x1133c, 0x11344, 1},
 		{0x11347, 0x11348, 1},
 		{0x1134b, 0x1134d, 1},
-		{0x11350, 0x11350, 1},
 		{0x11357, 0x11357, 1},
 		{0x1135d, 0x11363, 1},
 		{0x11366, 0x1136c, 1},
@@ -4021,7 +3921,6 @@ var _Gujarati = &RangeTable{
 		{0x0ad0, 0x0ad0, 1},
 		{0x0ae0, 0x0ae3, 1},
 		{0x0ae6, 0x0af1, 1},
-		{0x0af9, 0x0af9, 1},
 	},
 }
 
@@ -4056,7 +3955,7 @@ var _Han = &RangeTable{
 		{0x3021, 0x3029, 1},
 		{0x3038, 0x303b, 1},
 		{0x3400, 0x4db5, 1},
-		{0x4e00, 0x9fd5, 1},
+		{0x4e00, 0x9fcc, 1},
 		{0xf900, 0xfa6d, 1},
 		{0xfa70, 0xfad9, 1},
 	},
@@ -4064,7 +3963,6 @@ var _Han = &RangeTable{
 		{0x20000, 0x2a6d6, 1},
 		{0x2a700, 0x2b734, 1},
 		{0x2b740, 0x2b81d, 1},
-		{0x2b820, 0x2cea1, 1},
 		{0x2f800, 0x2fa1d, 1},
 	},
 }
@@ -4094,15 +3992,6 @@ var _Hanunoo = &RangeTable{
 	},
 }
 
-var _Hatran = &RangeTable{
-	R16: []Range16{},
-	R32: []Range32{
-		{0x108e0, 0x108f2, 1},
-		{0x108f4, 0x108f5, 1},
-		{0x108fb, 0x108ff, 1},
-	},
-}
-
 var _Hebrew = &RangeTable{
 	R16: []Range16{
 		{0x0591, 0x05c7, 1},
@@ -4329,11 +4218,13 @@ var _Latin = &RangeTable{
 		{0x2160, 0x2188, 1},
 		{0x2c60, 0x2c7f, 1},
 		{0xa722, 0xa787, 1},
-		{0xa78b, 0xa7ad, 1},
-		{0xa7b0, 0xa7b7, 1},
+		{0xa78b, 0xa78e, 1},
+		{0xa790, 0xa7ad, 1},
+		{0xa7b0, 0xa7b1, 1},
 		{0xa7f7, 0xa7ff, 1},
 		{0xab30, 0xab5a, 1},
-		{0xab5c, 0xab64, 1},
+		{0xab5c, 0xab5f, 1},
+		{0xab64, 0xab64, 1},
 		{0xfb00, 0xfb06, 1},
 		{0xff21, 0xff3a, 1},
 		{0xff41, 0xff5a, 1},
@@ -4419,7 +4310,7 @@ var _Malayalam = &RangeTable{
 		{0x0d46, 0x0d48, 1},
 		{0x0d4a, 0x0d4e, 1},
 		{0x0d57, 0x0d57, 1},
-		{0x0d5f, 0x0d63, 1},
+		{0x0d60, 0x0d63, 1},
 		{0x0d66, 0x0d75, 1},
 		{0x0d79, 0x0d7f, 1},
 	},
@@ -4460,8 +4351,7 @@ var _Meroitic_Cursive = &RangeTable{
 	R16: []Range16{},
 	R32: []Range32{
 		{0x109a0, 0x109b7, 1},
-		{0x109bc, 0x109cf, 1},
-		{0x109d2, 0x109ff, 1},
+		{0x109be, 0x109bf, 1},
 	},
 }
 
@@ -4509,17 +4399,6 @@ var _Mro = &RangeTable{
 	},
 }
 
-var _Multani = &RangeTable{
-	R16: []Range16{},
-	R32: []Range32{
-		{0x11280, 0x11286, 1},
-		{0x11288, 0x11288, 1},
-		{0x1128a, 0x1128d, 1},
-		{0x1128f, 0x1129d, 1},
-		{0x1129f, 0x112a9, 1},
-	},
-}
-
 var _Myanmar = &RangeTable{
 	R16: []Range16{
 		{0x1000, 0x109f, 1},
@@ -4563,15 +4442,6 @@ var _Ol_Chiki = &RangeTable{
 	},
 }
 
-var _Old_Hungarian = &RangeTable{
-	R16: []Range16{},
-	R32: []Range32{
-		{0x10c80, 0x10cb2, 1},
-		{0x10cc0, 0x10cf2, 1},
-		{0x10cfa, 0x10cff, 1},
-	},
-}
-
 var _Old_Italic = &RangeTable{
 	R16: []Range16{},
 	R32: []Range32{
@@ -4721,8 +4591,9 @@ var _Saurashtra = &RangeTable{
 var _Sharada = &RangeTable{
 	R16: []Range16{},
 	R32: []Range32{
-		{0x11180, 0x111cd, 1},
-		{0x111d0, 0x111df, 1},
+		{0x11180, 0x111c8, 1},
+		{0x111cd, 0x111cd, 1},
+		{0x111d0, 0x111da, 1},
 	},
 }
 
@@ -4737,16 +4608,7 @@ var _Siddham = &RangeTable{
 	R16: []Range16{},
 	R32: []Range32{
 		{0x11580, 0x115b5, 1},
-		{0x115b8, 0x115dd, 1},
-	},
-}
-
-var _SignWriting = &RangeTable{
-	R16: []Range16{},
-	R32: []Range32{
-		{0x1d800, 0x1da8b, 1},
-		{0x1da9b, 0x1da9f, 1},
-		{0x1daa1, 0x1daaf, 1},
+		{0x115b8, 0x115c9, 1},
 	},
 }
 
@@ -4878,7 +4740,7 @@ var _Telugu = &RangeTable{
 		{0x0c46, 0x0c48, 1},
 		{0x0c4a, 0x0c4d, 1},
 		{0x0c55, 0x0c56, 1},
-		{0x0c58, 0x0c5a, 1},
+		{0x0c58, 0x0c59, 1},
 		{0x0c60, 0x0c63, 1},
 		{0x0c66, 0x0c6f, 1},
 		{0x0c78, 0x0c7f, 1},
@@ -4957,8 +4819,6 @@ var _Yi = &RangeTable{
 
 // These variables have type *RangeTable.
 var (
-	Ahom                   = _Ahom                   // Ahom is the set of Unicode characters in script Ahom.
-	Anatolian_Hieroglyphs  = _Anatolian_Hieroglyphs  // Anatolian_Hieroglyphs is the set of Unicode characters in script Anatolian_Hieroglyphs.
 	Arabic                 = _Arabic                 // Arabic is the set of Unicode characters in script Arabic.
 	Armenian               = _Armenian               // Armenian is the set of Unicode characters in script Armenian.
 	Avestan                = _Avestan                // Avestan is the set of Unicode characters in script Avestan.
@@ -4999,7 +4859,6 @@ var (
 	Han                    = _Han                    // Han is the set of Unicode characters in script Han.
 	Hangul                 = _Hangul                 // Hangul is the set of Unicode characters in script Hangul.
 	Hanunoo                = _Hanunoo                // Hanunoo is the set of Unicode characters in script Hanunoo.
-	Hatran                 = _Hatran                 // Hatran is the set of Unicode characters in script Hatran.
 	Hebrew                 = _Hebrew                 // Hebrew is the set of Unicode characters in script Hebrew.
 	Hiragana               = _Hiragana               // Hiragana is the set of Unicode characters in script Hiragana.
 	Imperial_Aramaic       = _Imperial_Aramaic       // Imperial_Aramaic is the set of Unicode characters in script Imperial_Aramaic.
@@ -5036,14 +4895,12 @@ var (
 	Modi                   = _Modi                   // Modi is the set of Unicode characters in script Modi.
 	Mongolian              = _Mongolian              // Mongolian is the set of Unicode characters in script Mongolian.
 	Mro                    = _Mro                    // Mro is the set of Unicode characters in script Mro.
-	Multani                = _Multani                // Multani is the set of Unicode characters in script Multani.
 	Myanmar                = _Myanmar                // Myanmar is the set of Unicode characters in script Myanmar.
 	Nabataean              = _Nabataean              // Nabataean is the set of Unicode characters in script Nabataean.
 	New_Tai_Lue            = _New_Tai_Lue            // New_Tai_Lue is the set of Unicode characters in script New_Tai_Lue.
 	Nko                    = _Nko                    // Nko is the set of Unicode characters in script Nko.
 	Ogham                  = _Ogham                  // Ogham is the set of Unicode characters in script Ogham.
 	Ol_Chiki               = _Ol_Chiki               // Ol_Chiki is the set of Unicode characters in script Ol_Chiki.
-	Old_Hungarian          = _Old_Hungarian          // Old_Hungarian is the set of Unicode characters in script Old_Hungarian.
 	Old_Italic             = _Old_Italic             // Old_Italic is the set of Unicode characters in script Old_Italic.
 	Old_North_Arabian      = _Old_North_Arabian      // Old_North_Arabian is the set of Unicode characters in script Old_North_Arabian.
 	Old_Permic             = _Old_Permic             // Old_Permic is the set of Unicode characters in script Old_Permic.
@@ -5065,7 +4922,6 @@ var (
 	Sharada                = _Sharada                // Sharada is the set of Unicode characters in script Sharada.
 	Shavian                = _Shavian                // Shavian is the set of Unicode characters in script Shavian.
 	Siddham                = _Siddham                // Siddham is the set of Unicode characters in script Siddham.
-	SignWriting            = _SignWriting            // SignWriting is the set of Unicode characters in script SignWriting.
 	Sinhala                = _Sinhala                // Sinhala is the set of Unicode characters in script Sinhala.
 	Sora_Sompeng           = _Sora_Sompeng           // Sora_Sompeng is the set of Unicode characters in script Sora_Sompeng.
 	Sundanese              = _Sundanese              // Sundanese is the set of Unicode characters in script Sundanese.
@@ -5091,7 +4947,7 @@ var (
 )
 
 // Generated by running
-//	maketables --props=all --url=http://www.unicode.org/Public/8.0.0/ucd/
+//	maketables --props=all --url=http://www.unicode.org/Public/7.0.0/ucd/
 // DO NOT EDIT
 
 // Properties is the set of Unicode property tables.
@@ -5187,7 +5043,7 @@ var _Deprecated = &RangeTable{
 	},
 	R32: []Range32{
 		{0xe0001, 0xe0001, 1},
-		{0xe007f, 0xe007f, 1},
+		{0xe0020, 0xe007f, 1},
 	},
 }
 
@@ -5221,7 +5077,7 @@ var _Diacritic = &RangeTable{
 		{0x07a6, 0x07b0, 1},
 		{0x07eb, 0x07f5, 1},
 		{0x0818, 0x0819, 1},
-		{0x08e3, 0x08fe, 1},
+		{0x08e4, 0x08fe, 1},
 		{0x093c, 0x093c, 1},
 		{0x094d, 0x094d, 1},
 		{0x0951, 0x0954, 1},
@@ -5308,7 +5164,7 @@ var _Diacritic = &RangeTable{
 		{0xab5b, 0xab5f, 1},
 		{0xabec, 0xabed, 1},
 		{0xfb1e, 0xfb1e, 1},
-		{0xfe20, 0xfe2f, 1},
+		{0xfe20, 0xfe2d, 1},
 		{0xff3e, 0xff3e, 1},
 		{0xff40, 0xff40, 1},
 		{0xff70, 0xff70, 1},
@@ -5322,7 +5178,6 @@ var _Diacritic = &RangeTable{
 		{0x11133, 0x11134, 1},
 		{0x11173, 0x11173, 1},
 		{0x111c0, 0x111c0, 1},
-		{0x111ca, 0x111cc, 1},
 		{0x11235, 0x11236, 1},
 		{0x112e9, 0x112ea, 1},
 		{0x1133c, 0x1133c, 1},
@@ -5333,7 +5188,6 @@ var _Diacritic = &RangeTable{
 		{0x115bf, 0x115c0, 1},
 		{0x1163f, 0x1163f, 1},
 		{0x116b6, 0x116b7, 1},
-		{0x1172b, 0x1172b, 1},
 		{0x16af0, 0x16af4, 1},
 		{0x16f8f, 0x16f9f, 1},
 		{0x1d167, 0x1d169, 1},
@@ -5427,7 +5281,7 @@ var _Ideographic = &RangeTable{
 		{0x3021, 0x3029, 1},
 		{0x3038, 0x303a, 1},
 		{0x3400, 0x4db5, 1},
-		{0x4e00, 0x9fd5, 1},
+		{0x4e00, 0x9fcc, 1},
 		{0xf900, 0xfa6d, 1},
 		{0xfa70, 0xfad9, 1},
 	},
@@ -5435,7 +5289,6 @@ var _Ideographic = &RangeTable{
 		{0x20000, 0x2a6d6, 1},
 		{0x2a700, 0x2b734, 1},
 		{0x2b740, 0x2b81d, 1},
-		{0x2b820, 0x2cea1, 1},
 		{0x2f800, 0x2fa1d, 1},
 	},
 }
@@ -5450,8 +5303,6 @@ var _Logical_Order_Exception = &RangeTable{
 	R16: []Range16{
 		{0x0e40, 0x0e44, 1},
 		{0x0ec0, 0x0ec4, 1},
-		{0x19b5, 0x19b7, 1},
-		{0x19ba, 0x19ba, 1},
 		{0xaab5, 0xaab6, 1},
 		{0xaab9, 0xaab9, 1},
 		{0xaabb, 0xaabc, 1},
@@ -5506,7 +5357,7 @@ var _Other_Alphabetic = &RangeTable{
 		{0x081b, 0x0823, 1},
 		{0x0825, 0x0827, 1},
 		{0x0829, 0x082c, 1},
-		{0x08e3, 0x08e9, 1},
+		{0x08e4, 0x08e9, 1},
 		{0x08f0, 0x0903, 1},
 		{0x093a, 0x093b, 1},
 		{0x093e, 0x094c, 1},
@@ -5594,6 +5445,8 @@ var _Other_Alphabetic = &RangeTable{
 		{0x18a9, 0x18a9, 1},
 		{0x1920, 0x192b, 1},
 		{0x1930, 0x1938, 1},
+		{0x19b0, 0x19c0, 1},
+		{0x19c8, 0x19c9, 1},
 		{0x1a17, 0x1a1b, 1},
 		{0x1a55, 0x1a5e, 1},
 		{0x1a61, 0x1a74, 1},
@@ -5609,7 +5462,7 @@ var _Other_Alphabetic = &RangeTable{
 		{0x24b6, 0x24e9, 1},
 		{0x2de0, 0x2dff, 1},
 		{0xa674, 0xa67b, 1},
-		{0xa69e, 0xa69f, 1},
+		{0xa69f, 0xa69f, 1},
 		{0xa823, 0xa827, 1},
 		{0xa880, 0xa881, 1},
 		{0xa8b4, 0xa8c3, 1},
@@ -5645,7 +5498,7 @@ var _Other_Alphabetic = &RangeTable{
 		{0x1122c, 0x11234, 1},
 		{0x11237, 0x11237, 1},
 		{0x112df, 0x112e8, 1},
-		{0x11300, 0x11303, 1},
+		{0x11301, 0x11303, 1},
 		{0x1133e, 0x11344, 1},
 		{0x11347, 0x11348, 1},
 		{0x1134b, 0x1134c, 1},
@@ -5654,11 +5507,9 @@ var _Other_Alphabetic = &RangeTable{
 		{0x114b0, 0x114c1, 1},
 		{0x115af, 0x115b5, 1},
 		{0x115b8, 0x115be, 1},
-		{0x115dc, 0x115dd, 1},
 		{0x11630, 0x1163e, 1},
 		{0x11640, 0x11640, 1},
 		{0x116ab, 0x116b5, 1},
-		{0x1171d, 0x1172a, 1},
 		{0x16b30, 0x16b36, 1},
 		{0x16f51, 0x16f7e, 1},
 		{0x1bc9e, 0x1bc9e, 1},
@@ -6039,20 +5890,16 @@ var _STerm = &RangeTable{
 		{0x11141, 0x11143, 1},
 		{0x111c5, 0x111c6, 1},
 		{0x111cd, 0x111cd, 1},
-		{0x111de, 0x111df, 1},
 		{0x11238, 0x11239, 1},
 		{0x1123b, 0x1123c, 1},
-		{0x112a9, 0x112a9, 1},
 		{0x115c2, 0x115c3, 1},
-		{0x115c9, 0x115d7, 1},
+		{0x115c9, 0x115c9, 1},
 		{0x11641, 0x11642, 1},
-		{0x1173c, 0x1173e, 1},
 		{0x16a6e, 0x16a6f, 1},
 		{0x16af5, 0x16af5, 1},
 		{0x16b37, 0x16b38, 1},
 		{0x16b44, 0x16b44, 1},
 		{0x1bc9f, 0x1bc9f, 1},
-		{0x1da88, 0x1da88, 1},
 	},
 	LatinOffset: 3,
 }
@@ -6176,20 +6023,16 @@ var _Terminal_Punctuation = &RangeTable{
 		{0x11141, 0x11143, 1},
 		{0x111c5, 0x111c6, 1},
 		{0x111cd, 0x111cd, 1},
-		{0x111de, 0x111df, 1},
 		{0x11238, 0x1123c, 1},
-		{0x112a9, 0x112a9, 1},
 		{0x115c2, 0x115c5, 1},
-		{0x115c9, 0x115d7, 1},
+		{0x115c9, 0x115c9, 1},
 		{0x11641, 0x11642, 1},
-		{0x1173c, 0x1173e, 1},
 		{0x12470, 0x12474, 1},
 		{0x16a6e, 0x16a6f, 1},
 		{0x16af5, 0x16af5, 1},
 		{0x16b37, 0x16b39, 1},
 		{0x16b44, 0x16b44, 1},
 		{0x1bc9f, 0x1bc9f, 1},
-		{0x1da87, 0x1da8a, 1},
 	},
 	LatinOffset: 5,
 }
@@ -6197,7 +6040,7 @@ var _Terminal_Punctuation = &RangeTable{
 var _Unified_Ideograph = &RangeTable{
 	R16: []Range16{
 		{0x3400, 0x4db5, 1},
-		{0x4e00, 0x9fd5, 1},
+		{0x4e00, 0x9fcc, 1},
 		{0xfa0e, 0xfa0f, 1},
 		{0xfa11, 0xfa11, 1},
 		{0xfa13, 0xfa14, 1},
@@ -6210,7 +6053,6 @@ var _Unified_Ideograph = &RangeTable{
 		{0x20000, 0x2a6d6, 1},
 		{0x2a700, 0x2b734, 1},
 		{0x2b740, 0x2b81d, 1},
-		{0x2b820, 0x2cea1, 1},
 	},
 }
 
@@ -6277,7 +6119,7 @@ var (
 )
 
 // Generated by running
-//	maketables --data=http://www.unicode.org/Public/8.0.0/ucd/UnicodeData.txt --casefolding=http://www.unicode.org/Public/8.0.0/ucd/CaseFolding.txt
+//	maketables --data=http://www.unicode.org/Public/7.0.0/ucd/UnicodeData.txt --casefolding=http://www.unicode.org/Public/7.0.0/ucd/CaseFolding.txt
 // DO NOT EDIT
 
 // CaseRanges is the table describing case mappings for all letters with
@@ -6398,7 +6240,6 @@ var _CaseRanges = []CaseRange{
 	{0x028A, 0x028B, d{-217, 0, -217}},
 	{0x028C, 0x028C, d{-71, 0, -71}},
 	{0x0292, 0x0292, d{-219, 0, -219}},
-	{0x029D, 0x029D, d{42261, 0, 42261}},
 	{0x029E, 0x029E, d{42258, 0, 42258}},
 	{0x0345, 0x0345, d{84, 0, 84}},
 	{0x0370, 0x0373, d{UpperLower, UpperLower, UpperLower}},
@@ -6450,9 +6291,6 @@ var _CaseRanges = []CaseRange{
 	{0x10A0, 0x10C5, d{0, 7264, 0}},
 	{0x10C7, 0x10C7, d{0, 7264, 0}},
 	{0x10CD, 0x10CD, d{0, 7264, 0}},
-	{0x13A0, 0x13EF, d{0, 38864, 0}},
-	{0x13F0, 0x13F5, d{0, 8, 0}},
-	{0x13F8, 0x13FD, d{-8, 0, -8}},
 	{0x1D79, 0x1D79, d{35332, 0, 35332}},
 	{0x1D7D, 0x1D7D, d{3814, 0, 3814}},
 	{0x1E00, 0x1E95, d{UpperLower, UpperLower, UpperLower}},
@@ -6561,17 +6399,10 @@ var _CaseRanges = []CaseRange{
 	{0xA7AD, 0xA7AD, d{0, -42305, 0}},
 	{0xA7B0, 0xA7B0, d{0, -42258, 0}},
 	{0xA7B1, 0xA7B1, d{0, -42282, 0}},
-	{0xA7B2, 0xA7B2, d{0, -42261, 0}},
-	{0xA7B3, 0xA7B3, d{0, 928, 0}},
-	{0xA7B4, 0xA7B7, d{UpperLower, UpperLower, UpperLower}},
-	{0xAB53, 0xAB53, d{-928, 0, -928}},
-	{0xAB70, 0xABBF, d{-38864, 0, -38864}},
 	{0xFF21, 0xFF3A, d{0, 32, 0}},
 	{0xFF41, 0xFF5A, d{-32, 0, -32}},
 	{0x10400, 0x10427, d{0, 40, 0}},
 	{0x10428, 0x1044F, d{-40, 0, -40}},
-	{0x10C80, 0x10CB2, d{0, 64, 0}},
-	{0x10CC0, 0x10CF2, d{-64, 0, -64}},
 	{0x118A0, 0x118BF, d{0, 32, 0}},
 	{0x118C0, 0x118DF, d{-32, 0, -32}},
 }
@@ -7001,7 +6832,6 @@ var foldLl = &RangeTable{
 		{0x0531, 0x0556, 1},
 		{0x10a0, 0x10c5, 1},
 		{0x10c7, 0x10cd, 6},
-		{0x13a0, 0x13f5, 1},
 		{0x1e00, 0x1e94, 2},
 		{0x1e9e, 0x1efe, 2},
 		{0x1f08, 0x1f0f, 1},
@@ -7042,13 +6872,11 @@ var foldLl = &RangeTable{
 		{0xa790, 0xa792, 2},
 		{0xa796, 0xa7aa, 2},
 		{0xa7ab, 0xa7ad, 1},
-		{0xa7b0, 0xa7b4, 1},
-		{0xa7b6, 0xff21, 22379},
-		{0xff22, 0xff3a, 1},
+		{0xa7b0, 0xa7b1, 1},
+		{0xff21, 0xff3a, 1},
 	},
 	R32: []Range32{
 		{0x10400, 0x10427, 1},
-		{0x10c80, 0x10cb2, 1},
 		{0x118a0, 0x118bf, 1},
 	},
 	LatinOffset: 3,
@@ -7114,10 +6942,9 @@ var foldLu = &RangeTable{
 		{0x0275, 0x027d, 8},
 		{0x0280, 0x0283, 3},
 		{0x0287, 0x028c, 1},
-		{0x0292, 0x029d, 11},
-		{0x029e, 0x0345, 167},
-		{0x0371, 0x0373, 2},
-		{0x0377, 0x037b, 4},
+		{0x0292, 0x029e, 12},
+		{0x0345, 0x0371, 44},
+		{0x0373, 0x037b, 4},
 		{0x037c, 0x037d, 1},
 		{0x03ac, 0x03af, 1},
 		{0x03b1, 0x03ce, 1},
@@ -7132,7 +6959,6 @@ var foldLu = &RangeTable{
 		{0x04c2, 0x04ce, 2},
 		{0x04cf, 0x052f, 2},
 		{0x0561, 0x0586, 1},
-		{0x13f8, 0x13fd, 1},
 		{0x1d79, 0x1d7d, 4},
 		{0x1e01, 0x1e95, 2},
 		{0x1e9b, 0x1ea1, 6},
@@ -7168,14 +6994,10 @@ var foldLu = &RangeTable{
 		{0xa78c, 0xa791, 5},
 		{0xa793, 0xa797, 4},
 		{0xa799, 0xa7a9, 2},
-		{0xa7b5, 0xa7b7, 2},
-		{0xab53, 0xab70, 29},
-		{0xab71, 0xabbf, 1},
 		{0xff41, 0xff5a, 1},
 	},
 	R32: []Range32{
 		{0x10428, 0x1044f, 1},
-		{0x10cc0, 0x10cf2, 1},
 		{0x118c0, 0x118df, 1},
 	},
 	LatinOffset: 4,
@@ -7201,7 +7023,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: 3546 16-bit, 1306 32-bit, 4852 total.
-// Range bytes: 21276 16-bit, 15672 32-bit, 36948 total.
+// Range entries: 3532 16-bit, 1204 32-bit, 4736 total.
+// Range bytes: 21192 16-bit, 14448 32-bit, 35640 total.
 
 // Fold orbit bytes: 63 pairs, 252 bytes
diff --git a/src/unicode/utf16/utf16.go b/src/unicode/utf16/utf16.go
index b497500..c0e47c5 100644
--- a/src/unicode/utf16/utf16.go
+++ b/src/unicode/utf16/utf16.go
@@ -25,7 +25,7 @@ const (
 	surrSelf = 0x10000
 )
 
-// IsSurrogate reports whether the specified Unicode code point
+// IsSurrogate returns true if the specified Unicode code point
 // can appear in a surrogate pair.
 func IsSurrogate(r rune) bool {
 	return surr1 <= r && r < surr3
diff --git a/src/unsafe/unsafe.go b/src/unsafe/unsafe.go
index 752792f..79499b2 100644
--- a/src/unsafe/unsafe.go
+++ b/src/unsafe/unsafe.go
@@ -24,19 +24,17 @@ type ArbitraryType int
 // arbitrary memory. It should be used with extreme care.
 type Pointer *ArbitraryType
 
-// Sizeof takes an expression x of any type and returns the size in bytes
-// of a hypothetical variable v as if v was declared via var v = x.
-// The size does not include any memory possibly referenced by x.
-// For instance, if x is a slice,  Sizeof returns the size of the slice
-// descriptor, not the size of the memory referenced by the slice.
-func Sizeof(x ArbitraryType) uintptr
+// Sizeof returns the size in bytes occupied by the value v.  The size is that of the
+// "top level" of the value only.  For instance, if v is a slice, it returns the size of
+// the slice descriptor, not the size of the memory referenced by the slice.
+func Sizeof(v ArbitraryType) uintptr
 
-// Offsetof returns the offset within the struct of the field represented by x,
+// Offsetof returns the offset within the struct of the field represented by v,
 // which must be of the form structValue.field.  In other words, it returns the
 // number of bytes between the start of the struct and the start of the field.
-func Offsetof(x ArbitraryType) uintptr
+func Offsetof(v ArbitraryType) uintptr
 
-// Alignof takes an expression x of any type and returns the alignment
-// of a hypothetical variable v as if v was declared via var v = x.
-// It is the largest value m such that the address of v is zero mod m.
-func Alignof(x ArbitraryType) uintptr
+// Alignof returns the alignment of the value v.  It is the maximum value m such
+// that the address of a variable with the type of v will always be zero mod m.
+// If v is of the form structValue.field, it returns the alignment of field f within struct object obj.
+func Alignof(v ArbitraryType) uintptr
diff --git a/test/bench/shootout/fasta-1000.out b/test/bench/shootout/fasta-1000.out
new file mode 100644
index 0000000..f1caba0
--- /dev/null
+++ b/test/bench/shootout/fasta-1000.out
@@ -0,0 +1,171 @@
+>ONE Homo sapiens alu
+GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGA
+TCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACT
+AAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAG
+GCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCG
+CCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGT
+GGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCA
+GGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAA
+TTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAG
+AATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCA
+GCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGT
+AATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACC
+AGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTG
+GTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACC
+CGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAG
+AGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTT
+TGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACA
+TGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCT
+GTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGG
+TTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGT
+CTCAAAAAGGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGG
+CGGGCGGATCACCTGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCG
+TCTCTACTAAAAATACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTA
+CTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCG
+AGATCGCGCCACTGCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCG
+GGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACC
+TGAGGTCAGGAGTTCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAA
+TACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGA
+GGCAGGAGAATCGCTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACT
+GCACTCCAGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAAGGCCGGGCGCGGTGGCTC
+ACGCCTGTAATCCCAGCACTTTGGGAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGT
+TCGAGACCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAATACAAAAATTAGC
+CGGGCGTGGTGGCGCGCGCCTGTAATCCCAGCTACTCGGGAGGCTGAGGCAGGAGAATCG
+CTTGAACCCGGGAGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCCAGCCTG
+GGCGACAGAGCGAGACTCCG
+>TWO IUB ambiguity codes
+cttBtatcatatgctaKggNcataaaSatgtaaaDcDRtBggDtctttataattcBgtcg
+tactDtDagcctatttSVHtHttKtgtHMaSattgWaHKHttttagacatWatgtRgaaa
+NtactMcSMtYtcMgRtacttctWBacgaaatatagScDtttgaagacacatagtVgYgt
+cattHWtMMWcStgttaggKtSgaYaaccWStcgBttgcgaMttBYatcWtgacaYcaga
+gtaBDtRacttttcWatMttDBcatWtatcttactaBgaYtcttgttttttttYaaScYa
+HgtgttNtSatcMtcVaaaStccRcctDaataataStcYtRDSaMtDttgttSagtRRca
+tttHatSttMtWgtcgtatSSagactYaaattcaMtWatttaSgYttaRgKaRtccactt
+tattRggaMcDaWaWagttttgacatgttctacaaaRaatataataaMttcgDacgaSSt
+acaStYRctVaNMtMgtaggcKatcttttattaaaaagVWaHKYagtttttatttaacct
+tacgtVtcVaattVMBcttaMtttaStgacttagattWWacVtgWYagWVRctDattBYt
+gtttaagaagattattgacVatMaacattVctgtBSgaVtgWWggaKHaatKWcBScSWa
+accRVacacaaactaccScattRatatKVtactatatttHttaagtttSKtRtacaaagt
+RDttcaaaaWgcacatWaDgtDKacgaacaattacaRNWaatHtttStgttattaaMtgt
+tgDcgtMgcatBtgcttcgcgaDWgagctgcgaggggVtaaScNatttacttaatgacag
+cccccacatYScaMgtaggtYaNgttctgaMaacNaMRaacaaacaKctacatagYWctg
+ttWaaataaaataRattagHacacaagcgKatacBttRttaagtatttccgatctHSaat
+actcNttMaagtattMtgRtgaMgcataatHcMtaBSaRattagttgatHtMttaaKagg
+YtaaBataSaVatactWtataVWgKgttaaaacagtgcgRatatacatVtHRtVYataSa
+KtWaStVcNKHKttactatccctcatgWHatWaRcttactaggatctataDtDHBttata
+aaaHgtacVtagaYttYaKcctattcttcttaataNDaaggaaaDYgcggctaaWSctBa
+aNtgctggMBaKctaMVKagBaactaWaDaMaccYVtNtaHtVWtKgRtcaaNtYaNacg
+gtttNattgVtttctgtBaWgtaattcaagtcaVWtactNggattctttaYtaaagccgc
+tcttagHVggaYtgtNcDaVagctctctKgacgtatagYcctRYHDtgBattDaaDgccK
+tcHaaStttMcctagtattgcRgWBaVatHaaaataYtgtttagMDMRtaataaggatMt
+ttctWgtNtgtgaaaaMaatatRtttMtDgHHtgtcattttcWattRSHcVagaagtacg
+ggtaKVattKYagactNaatgtttgKMMgYNtcccgSKttctaStatatNVataYHgtNa
+BKRgNacaactgatttcctttaNcgatttctctataScaHtataRagtcRVttacDSDtt
+aRtSatacHgtSKacYagttMHtWataggatgactNtatSaNctataVtttRNKtgRacc
+tttYtatgttactttttcctttaaacatacaHactMacacggtWataMtBVacRaSaatc
+cgtaBVttccagccBcttaRKtgtgcctttttRtgtcagcRttKtaaacKtaaatctcac
+aattgcaNtSBaaccgggttattaaBcKatDagttactcttcattVtttHaaggctKKga
+tacatcBggScagtVcacattttgaHaDSgHatRMaHWggtatatRgccDttcgtatcga
+aacaHtaagttaRatgaVacttagattVKtaaYttaaatcaNatccRttRRaMScNaaaD
+gttVHWgtcHaaHgacVaWtgttScactaagSgttatcttagggDtaccagWattWtRtg
+ttHWHacgattBtgVcaYatcggttgagKcWtKKcaVtgaYgWctgYggVctgtHgaNcV
+taBtWaaYatcDRaaRtSctgaHaYRttagatMatgcatttNattaDttaattgttctaa
+ccctcccctagaWBtttHtBccttagaVaatMcBHagaVcWcagBVttcBtaYMccagat
+gaaaaHctctaacgttagNWRtcggattNatcRaNHttcagtKttttgWatWttcSaNgg
+gaWtactKKMaacatKatacNattgctWtatctaVgagctatgtRaHtYcWcttagccaa
+tYttWttaWSSttaHcaaaaagVacVgtaVaRMgattaVcDactttcHHggHRtgNcctt
+tYatcatKgctcctctatVcaaaaKaaaagtatatctgMtWtaaaacaStttMtcgactt
+taSatcgDataaactaaacaagtaaVctaggaSccaatMVtaaSKNVattttgHccatca
+cBVctgcaVatVttRtactgtVcaattHgtaaattaaattttYtatattaaRSgYtgBag
+aHSBDgtagcacRHtYcBgtcacttacactaYcgctWtattgSHtSatcataaatataHt
+cgtYaaMNgBaatttaRgaMaatatttBtttaaaHHKaatctgatWatYaacttMctctt
+ttVctagctDaaagtaVaKaKRtaacBgtatccaaccactHHaagaagaaggaNaaatBW
+attccgStaMSaMatBttgcatgRSacgttVVtaaDMtcSgVatWcaSatcttttVatag
+ttactttacgatcaccNtaDVgSRcgVcgtgaacgaNtaNatatagtHtMgtHcMtagaa
+attBgtataRaaaacaYKgtRccYtatgaagtaataKgtaaMttgaaRVatgcagaKStc
+tHNaaatctBBtcttaYaBWHgtVtgacagcaRcataWctcaBcYacYgatDgtDHccta
+>THREE Homo sapiens frequency
+aacacttcaccaggtatcgtgaaggctcaagattacccagagaacctttgcaatataaga
+atatgtatgcagcattaccctaagtaattatattctttttctgactcaaagtgacaagcc
+ctagtgtatattaaatcggtatatttgggaaattcctcaaactatcctaatcaggtagcc
+atgaaagtgatcaaaaaagttcgtacttataccatacatgaattctggccaagtaaaaaa
+tagattgcgcaaaattcgtaccttaagtctctcgccaagatattaggatcctattactca
+tatcgtgtttttctttattgccgccatccccggagtatctcacccatccttctcttaaag
+gcctaatattacctatgcaaataaacatatattgttgaaaattgagaacctgatcgtgat
+tcttatgtgtaccatatgtatagtaatcacgcgactatatagtgctttagtatcgcccgt
+gggtgagtgaatattctgggctagcgtgagatagtttcttgtcctaatatttttcagatc
+gaatagcttctatttttgtgtttattgacatatgtcgaaactccttactcagtgaaagtc
+atgaccagatccacgaacaatcttcggaatcagtctcgttttacggcggaatcttgagtc
+taacttatatcccgtcgcttactttctaacaccccttatgtatttttaaaattacgttta
+ttcgaacgtacttggcggaagcgttattttttgaagtaagttacattgggcagactcttg
+acattttcgatacgactttctttcatccatcacaggactcgttcgtattgatatcagaag
+ctcgtgatgattagttgtcttctttaccaatactttgaggcctattctgcgaaatttttg
+ttgccctgcgaacttcacataccaaggaacacctcgcaacatgccttcatatccatcgtt
+cattgtaattcttacacaatgaatcctaagtaattacatccctgcgtaaaagatggtagg
+ggcactgaggatatattaccaagcatttagttatgagtaatcagcaatgtttcttgtatt
+aagttctctaaaatagttacatcgtaatgttatctcgggttccgcgaataaacgagatag
+attcattatatatggccctaagcaaaaacctcctcgtattctgttggtaattagaatcac
+acaatacgggttgagatattaattatttgtagtacgaagagatataaaaagatgaacaat
+tactcaagtcaagatgtatacgggatttataataaaaatcgggtagagatctgctttgca
+attcagacgtgccactaaatcgtaatatgtcgcgttacatcagaaagggtaactattatt
+aattaataaagggcttaatcactacatattagatcttatccgatagtcttatctattcgt
+tgtatttttaagcggttctaattcagtcattatatcagtgctccgagttctttattattg
+ttttaaggatgacaaaatgcctcttgttataacgctgggagaagcagactaagagtcgga
+gcagttggtagaatgaggctgcaaaagacggtctcgacgaatggacagactttactaaac
+caatgaaagacagaagtagagcaaagtctgaagtggtatcagcttaattatgacaaccct
+taatacttccctttcgccgaatactggcgtggaaaggttttaaaagtcgaagtagttaga
+ggcatctctcgctcataaataggtagactactcgcaatccaatgtgactatgtaatactg
+ggaacatcagtccgcgatgcagcgtgtttatcaaccgtccccactcgcctggggagacat
+gagaccacccccgtggggattattagtccgcagtaatcgactcttgacaatccttttcga
+ttatgtcatagcaatttacgacagttcagcgaagtgactactcggcgaaatggtattact
+aaagcattcgaacccacatgaatgtgattcttggcaatttctaatccactaaagcttttc
+cgttgaatctggttgtagatatttatataagttcactaattaagatcacggtagtatatt
+gatagtgatgtctttgcaagaggttggccgaggaatttacggattctctattgatacaat
+ttgtctggcttataactcttaaggctgaaccaggcgtttttagacgacttgatcagctgt
+tagaatggtttggactccctctttcatgtcagtaacatttcagccgttattgttacgata
+tgcttgaacaatattgatctaccacacacccatagtatattttataggtcatgctgttac
+ctacgagcatggtattccacttcccattcaatgagtattcaacatcactagcctcagaga
+tgatgacccacctctaataacgtcacgttgcggccatgtgaaacctgaacttgagtagac
+gatatcaagcgctttaaattgcatataacatttgagggtaaagctaagcggatgctttat
+ataatcaatactcaataataagatttgattgcattttagagttatgacacgacatagttc
+actaacgagttactattcccagatctagactgaagtactgatcgagacgatccttacgtc
+gatgatcgttagttatcgacttaggtcgggtctctagcggtattggtacttaaccggaca
+ctatactaataacccatgatcaaagcataacagaatacagacgataatttcgccaacata
+tatgtacagaccccaagcatgagaagctcattgaaagctatcattgaagtcccgctcaca
+atgtgtcttttccagacggtttaactggttcccgggagtcctggagtttcgacttacata
+aatggaaacaatgtattttgctaatttatctatagcgtcatttggaccaatacagaatat
+tatgttgcctagtaatccactataacccgcaagtgctgatagaaaatttttagacgattt
+ataaatgccccaagtatccctcccgtgaatcctccgttatactaattagtattcgttcat
+acgtataccgcgcatatatgaacatttggcgataaggcgcgtgaattgttacgtgacaga
+gatagcagtttcttgtgatatggttaacagacgtacatgaagggaaactttatatctata
+gtgatgcttccgtagaaataccgccactggtctgccaatgatgaagtatgtagctttagg
+tttgtactatgaggctttcgtttgtttgcagagtataacagttgcgagtgaaaaaccgac
+gaatttatactaatacgctttcactattggctacaaaatagggaagagtttcaatcatga
+gagggagtatatggatgctttgtagctaaaggtagaacgtatgtatatgctgccgttcat
+tcttgaaagatacataagcgataagttacgacaattataagcaacatccctaccttcgta
+acgatttcactgttactgcgcttgaaatacactatggggctattggcggagagaagcaga
+tcgcgccgagcatatacgagacctataatgttgatgatagagaaggcgtctgaattgata
+catcgaagtacactttctttcgtagtatctctcgtcctctttctatctccggacacaaga
+attaagttatatatatagagtcttaccaatcatgttgaatcctgattctcagagttcttt
+ggcgggccttgtgatgactgagaaacaatgcaatattgctccaaatttcctaagcaaatt
+ctcggttatgttatgttatcagcaaagcgttacgttatgttatttaaatctggaatgacg
+gagcgaagttcttatgtcggtgtgggaataattcttttgaagacagcactccttaaataa
+tatcgctccgtgtttgtatttatcgaatgggtctgtaaccttgcacaagcaaatcggtgg
+tgtatatatcggataacaattaatacgatgttcatagtgacagtatactgatcgagtcct
+ctaaagtcaattacctcacttaacaatctcattgatgttgtgtcattcccggtatcgccc
+gtagtatgtgctctgattgaccgagtgtgaaccaaggaacatctactaatgcctttgtta
+ggtaagatctctctgaattccttcgtgccaacttaaaacattatcaaaatttcttctact
+tggattaactacttttacgagcatggcaaattcccctgtggaagacggttcattattatc
+ggaaaccttatagaaattgcgtgttgactgaaattagatttttattgtaagagttgcatc
+tttgcgattcctctggtctagcttccaatgaacagtcctcccttctattcgacatcgggt
+ccttcgtacatgtctttgcgatgtaataattaggttcggagtgtggccttaatgggtgca
+actaggaatacaacgcaaatttgctgacatgatagcaaatcggtatgccggcaccaaaac
+gtgctccttgcttagcttgtgaatgagactcagtagttaaataaatccatatctgcaatc
+gattccacaggtattgtccactatctttgaactactctaagagatacaagcttagctgag
+accgaggtgtatatgactacgctgatatctgtaaggtaccaatgcaggcaaagtatgcga
+gaagctaataccggctgtttccagctttataagattaaaatttggctgtcctggcggcct
+cagaattgttctatcgtaatcagttggttcattaattagctaagtacgaggtacaactta
+tctgtcccagaacagctccacaagtttttttacagccgaaacccctgtgtgaatcttaat
+atccaagcgcgttatctgattagagtttacaactcagtattttatcagtacgttttgttt
+ccaacattacccggtatgacaaaatgacgccacgtgtcgaataatggtctgaccaatgta
+ggaagtgaaaagataaatat
diff --git a/test/bench/shootout/timing.sh b/test/bench/shootout/timing.sh
index 9abcf78..a06c326 100755
--- a/test/bench/shootout/timing.sh
+++ b/test/bench/shootout/timing.sh
@@ -6,8 +6,9 @@
 set -e
 
 eval $(go tool dist env)
-GC="go tool compile"
-LD="go tool link"
+O=$GOCHAR
+GC="go tool ${O}g"
+LD="go tool ${O}l"
 
 gccm=""
 case "$O" in
@@ -60,11 +61,11 @@ X-test)
 esac
 
 gc() {
-	$GC $1.go; $LD -o a.$EXE $1.o
+	$GC $1.go; $LD -o $O.$EXE $1.$O
 }
 
 gc_B() {
-	$GC -B $1.go; $LD -o a.$EXE $1.o
+	$GC -B $1.go; $LD -o $O.$EXE $1.$O
 }
 
 runonly() {
@@ -83,7 +84,7 @@ run() {
 			program=$(echo $1 | sed 's/gc //')
 			shift
 			echo $program
-			$1 <fasta-1000.txt > /tmp/$$
+			$1 <fasta-1000.out > /tmp/$$
 			case $program in
 			chameneosredux)
 				# exact numbers may vary but non-numbers should match
@@ -114,8 +115,8 @@ fasta() {
 	runonly echo 'fasta -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' a.$EXE -n 25000000
-	run 'gc_B fasta' a.$EXE -n 25000000
+	run 'gc fasta' $O.$EXE -n 25000000
+	run 'gc_B fasta' $O.$EXE -n 25000000
 }
 
 revcomp() {
@@ -124,8 +125,8 @@ revcomp() {
 	runonly echo 'reverse-complement < output-of-fasta-25000000'
 	run "gcc $gccm -O2 reverse-complement.c" a.$EXE < x
 	run 'gccgo -O2 reverse-complement.go' a.$EXE < x
-	run 'gc reverse-complement' a.$EXE < x
-	run 'gc_B reverse-complement' a.$EXE < x
+	run 'gc reverse-complement' $O.$EXE < x
+	run 'gc_B reverse-complement' $O.$EXE < x
 	rm x
 }
 
@@ -133,8 +134,8 @@ nbody() {
 	runonly echo 'nbody -n 50000000'
 	run "gcc $gccm -O2 nbody.c -lm" a.$EXE 50000000
 	run 'gccgo -O2 nbody.go' a.$EXE -n 50000000
-	run 'gc nbody' a.$EXE -n 50000000
-	run 'gc_B nbody' a.$EXE -n 50000000
+	run 'gc nbody' $O.$EXE -n 50000000
+	run 'gc_B nbody' $O.$EXE -n 50000000
 }
 
 binarytree() {
@@ -142,8 +143,8 @@ binarytree() {
 	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' a.$EXE -n 15
-	run 'gc binary-tree-freelist' a.$EXE -n 15
+	run 'gc binary-tree' $O.$EXE -n 15
+	run 'gc binary-tree-freelist' $O.$EXE -n 15
 }
 
 fannkuch() {
@@ -151,9 +152,9 @@ fannkuch() {
 	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' a.$EXE -n 12
-	run 'gc fannkuch-parallel' a.$EXE -n 12
-	run 'gc_B fannkuch' 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() {
@@ -165,9 +166,9 @@ regexdna() {
 	fi
 	run 'gccgo -O2 regex-dna.go' a.$EXE <x
 	run 'gccgo -O2 regex-dna-parallel.go' a.$EXE <x
-	run 'gc regex-dna' a.$EXE <x
-	run 'gc regex-dna-parallel' a.$EXE <x
-	run 'gc_B regex-dna' 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
 }
 
@@ -175,8 +176,8 @@ spectralnorm() {
 	runonly echo 'spectral-norm 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' a.$EXE -n 5500
-	run 'gc_B spectral-norm' a.$EXE -n 5500
+	run 'gc spectral-norm' $O.$EXE -n 5500
+	run 'gc_B spectral-norm' $O.$EXE -n 5500
 }
 
 knucleotide() {
@@ -188,9 +189,9 @@ knucleotide() {
 	fi
 	run 'gccgo -O2 k-nucleotide.go' a.$EXE <x
 	run 'gccgo -O2 k-nucleotide-parallel.go' a.$EXE <x
-	run 'gc k-nucleotide' a.$EXE <x
-	run 'gc k-nucleotide-parallel' a.$EXE <x
-	run 'gc_B k-nucleotide' 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
 }
 
@@ -198,16 +199,16 @@ mandelbrot() {
 	runonly echo 'mandelbrot 16000'
 	run "gcc $gccm -O2 mandelbrot.c" a.$EXE 16000
 	run 'gccgo -O2 mandelbrot.go' a.$EXE -n 16000
-	run 'gc mandelbrot' a.$EXE -n 16000
-	run 'gc_B mandelbrot' 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.$EXE 2098
 	run 'gccgo -O2 meteor-contest.go' a.$EXE -n 2098
-	run 'gc meteor-contest' a.$EXE -n 2098
-	run 'gc_B  meteor-contest' a.$EXE -n 2098
+	run 'gc meteor-contest' $O.$EXE -n 2098
+	run 'gc_B  meteor-contest' $O.$EXE -n 2098
 }
 
 pidigits() {
@@ -216,22 +217,22 @@ pidigits() {
 		run "gcc $gccm -O2 pidigits.c -lgmp" a.$EXE 10000
 	fi
 	run 'gccgo -O2 pidigits.go' a.$EXE -n 10000
-	run 'gc pidigits' a.$EXE -n 10000
-	run 'gc_B  pidigits' 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.$EXE 50000000
 	run 'gccgo -O2 threadring.go' a.$EXE -n 50000000
-	run 'gc threadring' a.$EXE -n 50000000
+	run 'gc threadring' $O.$EXE -n 50000000
 }
 
 chameneos() {
 	runonly echo 'chameneos 6000000'
 	run "gcc $gccm -O2 chameneosredux.c -lpthread" a.$EXE 6000000
 	run 'gccgo -O2 chameneosredux.go' a.$EXE 6000000
-	run 'gc chameneosredux' a.$EXE 6000000
+	run 'gc chameneosredux' $O.$EXE 6000000
 }
 
 case $# in
@@ -247,6 +248,3 @@ do
 	$i
 	runonly echo
 done
-
-rm *.o *.$EXE # Clean up
-
diff --git a/test/bugs/bug395.go b/test/bugs/bug395.go
index 5490a3d..4632dcd 100644
--- a/test/bugs/bug395.go
+++ b/test/bugs/bug395.go
@@ -1,6 +1,8 @@
-// skip
+// echo bug395 is broken  # takes 90+ seconds to break
+// # $G $D/$F.go || echo bug395
 
-// When issue 1909 is fixed, change from skip to compile.
+// NOTE: This test is not run by 'run.go' and so not run by all.bash.
+// To run this test you must use the ./run shell script.
 
 // Copyright 2011 The Go Authors.  All rights reserved.
 // Use of this source code is governed by a BSD-style
@@ -8,7 +10,6 @@
 
 // Issue 1909
 // Would OOM due to exponential recursion on Foo's expanded methodset in nodefmt
-
 package test
 
 type Foo interface {
diff --git a/test/chan/select5.go b/test/chan/select5.go
index cfdc085..1081cb2 100644
--- a/test/chan/select5.go
+++ b/test/chan/select5.go
@@ -28,7 +28,7 @@ func main() {
 	a := new(arg)
 
 	// Generate each test as a separate function to avoid
-	// hitting the gc optimizer with one enormous function.
+	// hitting the 6g optimizer with one enormous function.
 	// If we name all the functions init we don't have to
 	// maintain a list of which ones to run.
 	do := func(t *template.Template) {
diff --git a/test/cmp.go b/test/cmp.go
index 6db9ce5..80d1bf6 100644
--- a/test/cmp.go
+++ b/test/cmp.go
@@ -115,7 +115,7 @@ func main() {
 	isfalse(ic != d)
 	isfalse(ie != e)
 
-	// gc used to let this go through as true.
+	// 6g used to let this go through as true.
 	var g uint64 = 123
 	var h int64 = 123
 	var ig interface{} = g
diff --git a/test/cmplxdivide.c b/test/cmplxdivide.c
index d654362..12dc4f1 100644
--- a/test/cmplxdivide.c
+++ b/test/cmplxdivide.c
@@ -2,18 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// This C program generates the file cmplxdivide1.go. It uses the
-// output of the operations by C99 as the reference to check
-// the implementation of complex numbers in Go.
-// The generated file, cmplxdivide1.go, is compiled along
-// with the driver cmplxdivide.go (the names are confusing
-// and unimaginative) to run the actual test. This is done by
-// the usual test runner.
-//
-// The file cmplxdivide1.go is checked in to the repository, but
-// if it needs to be regenerated, compile and run this C program
-// like this:
-//	gcc '-std=c99' cmplxdivide.c && a.out >cmplxdivide1.go
+// gcc '-std=c99' cmplxdivide.c && a.out >cmplxdivide1.go
 
 #include <complex.h>
 #include <math.h>
diff --git a/test/cmplxdivide.go b/test/cmplxdivide.go
index 8e29672..40c8448 100644
--- a/test/cmplxdivide.go
+++ b/test/cmplxdivide.go
@@ -5,7 +5,6 @@
 // license that can be found in the LICENSE file.
 
 // Driver for complex division table defined in cmplxdivide1.go
-// For details, see the comment at the top of in cmplxdivide.c.
 
 package main
 
diff --git a/test/complit1.go b/test/complit1.go
index c7a2ac9..521401d 100644
--- a/test/complit1.go
+++ b/test/complit1.go
@@ -40,17 +40,3 @@ var (
 	_ = &T{i: 0, f: 0, s: "", next: {}} // ERROR "missing type in composite literal|omit types within composite literal"
 	_ = &T{0, 0, "", {}}                // ERROR "missing type in composite literal|omit types within composite literal"
 )
-
-type M map[T]T
-
-var (
-	_ = M{{i:1}: {i:2}}
-	_ = M{T{i:1}: {i:2}}
-	_ = M{{i:1}: T{i:2}}
-	_ = M{T{i:1}: T{i:2}}
-)
-
-type S struct { s [1]*M1 }
-type M1 map[S]int
-var _ = M1{{s:[1]*M1{&M1{{}:1}}}:2}
-
diff --git a/test/const4.go b/test/const4.go
index 785e1ec..2fb2d06 100644
--- a/test/const4.go
+++ b/test/const4.go
@@ -4,7 +4,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// Test len constants and non-constants, https://golang.org/issue/3244.
+// Test len constants and non-constants, http://golang.org/issue/3244.
 
 package main
 
diff --git a/test/const5.go b/test/const5.go
index 51e46cb..60b4d0d 100644
--- a/test/const5.go
+++ b/test/const5.go
@@ -4,7 +4,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// Test that len non-constants are not constants, https://golang.org/issue/3244.
+// Test that len non-constants are not constants, http://golang.org/issue/3244.
 
 package p
 
diff --git a/test/convlit.go b/test/convlit.go
index 904e1e6..8a6145d 100644
--- a/test/convlit.go
+++ b/test/convlit.go
@@ -9,8 +9,6 @@
 
 package main
 
-import "unsafe"
-
 // explicit conversion of constants
 var x1 = string(1)
 var x2 string = string(1)
@@ -20,11 +18,6 @@ var x5 = "a" + string(1)
 var x6 = int(1e100)      // ERROR "overflow"
 var x7 = float32(1e1000) // ERROR "overflow"
 
-// unsafe.Pointer can only convert to/from uintptr
-var _ = string(unsafe.Pointer(uintptr(65)))  // ERROR "convert"
-var _ = float64(unsafe.Pointer(uintptr(65))) // ERROR "convert"
-var _ = int(unsafe.Pointer(uintptr(65)))     // ERROR "convert"
-
 // implicit conversions merit scrutiny
 var s string
 var bad1 string = 1  // ERROR "conver|incompatible|invalid|cannot"
diff --git a/test/errchk b/test/errchk
index b07bbc7..de0c4fd 100755
--- a/test/errchk
+++ b/test/errchk
@@ -47,7 +47,7 @@ foreach $file (@file) {
 $cmd = join(' ', @ARGV);
 open(CMD, "exec $cmd </dev/null 2>&1 |") || die "BUG: errchk: run $cmd: $!";
 
-# gc error messages continue onto additional lines with leading tabs.
+# 6g error messages continue onto additional lines with leading tabs.
 # Split the output at the beginning of each line that doesn't begin with a tab.
 $out = join('', <CMD>);
 @out = split(/^(?!\t)/m, $out);
diff --git a/test/escape2.go b/test/escape2.go
index 46cfde4..6a46ce8 100644
--- a/test/escape2.go
+++ b/test/escape2.go
@@ -18,94 +18,94 @@ import (
 
 var gxx *int
 
-func foo1(x int) { // ERROR "moved to heap: x$"
-	gxx = &x // ERROR "&x escapes to heap$"
+func foo1(x int) { // ERROR "moved to heap: x"
+	gxx = &x // ERROR "&x escapes to heap"
 }
 
-func foo2(yy *int) { // ERROR "leaking param: yy$"
+func foo2(yy *int) { // ERROR "leaking param: yy"
 	gxx = yy
 }
 
-func foo3(x int) *int { // ERROR "moved to heap: x$"
-	return &x // ERROR "&x escapes to heap$"
+func foo3(x int) *int { // ERROR "moved to heap: x"
+	return &x // ERROR "&x escapes to heap"
 }
 
 type T *T
 
-func foo3b(t T) { // ERROR "leaking param: t$"
+func foo3b(t T) { // ERROR "leaking param: t"
 	*t = t
 }
 
 // xx isn't going anywhere, so use of yy is ok
-func foo4(xx, yy *int) { // ERROR "foo4 xx does not escape$" "foo4 yy does not escape$"
+func foo4(xx, yy *int) { // ERROR "xx does not escape" "yy does not escape"
 	xx = yy
 }
 
 // xx isn't going anywhere, so taking address of yy is ok
-func foo5(xx **int, yy *int) { // ERROR "foo5 xx does not escape$" "foo5 yy does not escape$"
-	xx = &yy // ERROR "foo5 &yy does not escape$"
+func foo5(xx **int, yy *int) { // ERROR "xx does not escape" "yy does not escape"
+	xx = &yy // ERROR "&yy does not escape"
 }
 
-func foo6(xx **int, yy *int) { // ERROR "foo6 xx does not escape$" "leaking param: yy$"
+func foo6(xx **int, yy *int) { // ERROR "xx does not escape" "leaking param: yy"
 	*xx = yy
 }
 
-func foo7(xx **int, yy *int) { // ERROR "foo7 xx does not escape$" "foo7 yy does not escape$"
+func foo7(xx **int, yy *int) { // ERROR "xx does not escape" "yy does not escape"
 	**xx = *yy
 }
 
-func foo8(xx, yy *int) int { // ERROR "foo8 xx does not escape$" "foo8 yy does not escape$"
+func foo8(xx, yy *int) int { // ERROR "xx does not escape" "yy does not escape"
 	xx = yy
 	return *xx
 }
 
-func foo9(xx, yy *int) *int { // ERROR "leaking param: xx to result ~r2 level=0$" "leaking param: yy to result ~r2 level=0$"
+func foo9(xx, yy *int) *int { // ERROR "leaking param: xx" "leaking param: yy"
 	xx = yy
 	return xx
 }
 
-func foo10(xx, yy *int) { // ERROR "foo10 xx does not escape$" "foo10 yy does not escape$"
+func foo10(xx, yy *int) { // ERROR "xx does not escape" "yy does not escape"
 	*xx = *yy
 }
 
 func foo11() int {
 	x, y := 0, 42
-	xx := &x // ERROR "foo11 &x does not escape$"
-	yy := &y // ERROR "foo11 &y does not escape$"
+	xx := &x // ERROR "&x does not escape"
+	yy := &y // ERROR "&y does not escape"
 	*xx = *yy
 	return x
 }
 
 var xxx **int
 
-func foo12(yyy **int) { // ERROR "leaking param: yyy$"
+func foo12(yyy **int) { // ERROR "leaking param: yyy"
 	xxx = yyy
 }
 
 // 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 content: yyy$"
+func foo13(yyy **int) { // ERROR "leaking param: yyy"
 	*xxx = *yyy
 }
 
-func foo14(yyy **int) { // ERROR "foo14 yyy does not escape$"
+func foo14(yyy **int) { // ERROR "yyy does not escape"
 	**xxx = **yyy
 }
 
-func foo15(yy *int) { // ERROR "moved to heap: yy$"
-	xxx = &yy // ERROR "&yy escapes to heap$"
+func foo15(yy *int) { // ERROR "moved to heap: yy"
+	xxx = &yy // ERROR "&yy escapes to heap"
 }
 
-func foo16(yy *int) { // ERROR "leaking param: yy$"
+func foo16(yy *int) { // ERROR "leaking param: yy"
 	*xxx = yy
 }
 
-func foo17(yy *int) { // ERROR "foo17 yy does not escape$"
+func foo17(yy *int) { // ERROR "yy does not escape"
 	**xxx = *yy
 }
 
-func foo18(y int) { // ERROR "moved to heap: y$"
-	*xxx = &y // ERROR "&y escapes to heap$"
+func foo18(y int) { // ERROR "moved to heap: "y"
+	*xxx = &y // ERROR "&y escapes to heap"
 }
 
 func foo19(y int) {
@@ -118,52 +118,52 @@ type Bar struct {
 }
 
 func NewBar() *Bar {
-	return &Bar{42, nil} // ERROR "&Bar literal escapes to heap$"
+	return &Bar{42, nil} // ERROR "&Bar literal escapes to heap"
 }
 
-func NewBarp(x *int) *Bar { // ERROR "leaking param: x to result ~r1 level=-1$"
-	return &Bar{42, x} // ERROR "&Bar literal escapes to heap$"
+func NewBarp(x *int) *Bar { // ERROR "leaking param: x"
+	return &Bar{42, x} // ERROR "&Bar literal escapes to heap"
 }
 
-func NewBarp2(x *int) *Bar { // ERROR "NewBarp2 x does not escape$"
-	return &Bar{*x, nil} // ERROR "&Bar literal escapes to heap$"
+func NewBarp2(x *int) *Bar { // ERROR "x does not escape"
+	return &Bar{*x, nil} // ERROR "&Bar literal escapes to heap"
 }
 
-func (b *Bar) NoLeak() int { // ERROR "\(\*Bar\).NoLeak b does not escape$"
+func (b *Bar) NoLeak() int { // ERROR "b does not escape"
 	return *(b.ii)
 }
 
-func (b *Bar) Leak() *int { // ERROR "leaking param: b to result ~r0 level=0$"
-	return &b.i // ERROR "&b.i escapes to heap$"
+func (b *Bar) Leak() *int { // ERROR "leaking param: b"
+	return &b.i // ERROR "&b.i escapes to heap"
 }
 
-func (b *Bar) AlsoNoLeak() *int { // ERROR "leaking param: b to result ~r0 level=1$"
+func (b *Bar) AlsoNoLeak() *int { // ERROR "leaking param b content to result ~r0"
 	return b.ii
 }
 
-func (b Bar) AlsoLeak() *int { // ERROR "leaking param: b to result ~r0 level=0$"
+func (b Bar) AlsoLeak() *int { // ERROR "leaking param: b"
 	return b.ii
 }
 
-func (b Bar) LeaksToo() *int { // ERROR "leaking param: b to result ~r0 level=0$"
-	v := 0    // ERROR "moved to heap: v$"
-	b.ii = &v // ERROR "&v escapes to heap$"
+func (b Bar) LeaksToo() *int { // ERROR "leaking param: b"
+	v := 0    // ERROR "moved to heap: v"
+	b.ii = &v // ERROR "&v escapes"
 	return b.ii
 }
 
-func (b *Bar) LeaksABit() *int { // ERROR "leaking param: b to result ~r0 level=1$"
-	v := 0    // ERROR "moved to heap: v$"
-	b.ii = &v // ERROR "&v escapes to heap$"
+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
 }
 
-func (b Bar) StillNoLeak() int { // ERROR "Bar.StillNoLeak b does not escape$"
+func (b Bar) StillNoLeak() int { // ERROR "b does not escape"
 	v := 0
-	b.ii = &v // ERROR "Bar.StillNoLeak &v does not escape$"
+	b.ii = &v // ERROR "&v does not escape"
 	return b.i
 }
 
-func goLeak(b *Bar) { // ERROR "leaking param: b$"
+func goLeak(b *Bar) { // ERROR "leaking param: b"
 	go b.NoLeak()
 }
 
@@ -173,105 +173,90 @@ type Bar2 struct {
 }
 
 func NewBar2() *Bar2 {
-	return &Bar2{[12]int{42}, nil} // ERROR "&Bar2 literal escapes to heap$"
+	return &Bar2{[12]int{42}, nil} // ERROR "&Bar2 literal escapes to heap"
 }
 
-func (b *Bar2) NoLeak() int { // ERROR "\(\*Bar2\).NoLeak b does not escape$"
+func (b *Bar2) NoLeak() int { // ERROR "b does not escape"
 	return b.i[0]
 }
 
-func (b *Bar2) Leak() []int { // ERROR "leaking param: b to result ~r0 level=0$"
-	return b.i[:] // ERROR "b.i escapes to heap$"
+func (b *Bar2) Leak() []int { // ERROR "leaking param: b"
+	return b.i[:] // ERROR "b.i escapes to heap"
 }
 
-func (b *Bar2) AlsoNoLeak() []int { // ERROR "leaking param: b to result ~r0 level=1$"
+func (b *Bar2) AlsoNoLeak() []int { // ERROR "leaking param b content to result ~r0"
 	return b.ii[0:1]
 }
 
-func (b Bar2) AgainNoLeak() [12]int { // ERROR "Bar2.AgainNoLeak b does not escape$"
+func (b Bar2) AgainNoLeak() [12]int { // ERROR "b does not escape"
 	return b.i
 }
 
-func (b *Bar2) LeakSelf() { // ERROR "leaking param: b$"
-	b.ii = b.i[0:4] // ERROR "b.i escapes to heap$"
+func (b *Bar2) LeakSelf() { // ERROR "leaking param: b"
+	b.ii = b.i[0:4] // ERROR "b.i escapes to heap"
 }
 
-func (b *Bar2) LeakSelf2() { // ERROR "leaking param: b$"
+func (b *Bar2) LeakSelf2() { // ERROR "leaking param: b"
 	var buf []int
-	buf = b.i[0:] // ERROR "b.i escapes to heap$"
+	buf = b.i[0:] // ERROR "b.i escapes to heap"
 	b.ii = buf
 }
 
 func foo21() func() int {
-	x := 42
-	return func() int { // ERROR "func literal escapes to heap$"
-		return x
-	}
-}
-
-func foo21a() func() int {
-	x := 42             // ERROR "moved to heap: x$"
-	return func() int { // ERROR "func literal escapes to heap$"
-		x++ // ERROR "&x escapes to heap$"
-		return x
+	x := 42             // ERROR "moved to heap: x"
+	return func() int { // ERROR "func literal escapes to heap"
+		return x // ERROR "&x escapes to heap"
 	}
 }
 
 func foo22() int {
 	x := 42
-	return func() int { // ERROR "foo22 func literal does not escape$"
+	return func() int { // ERROR "func literal does not escape"
 		return x
 	}()
 }
 
-func foo23(x int) func() int {
-	return func() int { // ERROR "func literal escapes to heap$"
-		return x
+func foo23(x int) func() int { // ERROR "moved to heap: x"
+	return func() int { // ERROR "func literal escapes to heap"
+		return x // ERROR "&x escapes to heap"
 	}
 }
 
-func foo23a(x int) func() int {
-	f := func() int { // ERROR "func literal escapes to heap$"
-		return x
+func foo23a(x int) func() int { // ERROR "moved to heap: x"
+	f := func() int { // ERROR "func literal escapes to heap"
+		return x // ERROR "&x escapes to heap"
 	}
 	return f
 }
 
-func foo23b(x int) *(func() int) {
-	f := func() int { return x } // ERROR "func literal escapes to heap$" "moved to heap: f$"
-	return &f                    // ERROR "&f escapes to heap$"
-}
-
-func foo23c(x int) func() int { // ERROR "moved to heap: x$"
-	return func() int { // ERROR "func literal escapes to heap$"
-		x++ // ERROR "&x escapes to heap$"
-		return x
-	}
+func foo23b(x int) *(func() int) { // ERROR "moved to heap: x"
+	f := func() int { return x } // ERROR "moved to heap: f" "func literal escapes to heap" "&x escapes to heap"
+	return &f                    // ERROR "&f escapes to heap"
 }
 
 func foo24(x int) int {
-	return func() int { // ERROR "foo24 func literal does not escape$"
+	return func() int { // ERROR "func literal does not escape"
 		return x
 	}()
 }
 
 var x *int
 
-func fooleak(xx *int) int { // ERROR "leaking param: xx$"
+func fooleak(xx *int) int { // ERROR "leaking param: xx"
 	x = xx
 	return *x
 }
 
-func foonoleak(xx *int) int { // ERROR "foonoleak xx does not escape$"
+func foonoleak(xx *int) int { // ERROR "xx does not escape"
 	return *x + *xx
 }
 
-func foo31(x int) int { // ERROR "moved to heap: x$"
-	return fooleak(&x) // ERROR "&x escapes to heap$"
+func foo31(x int) int { // ERROR "moved to heap: x"
+	return fooleak(&x) // ERROR "&x escapes to heap"
 }
 
 func foo32(x int) int {
-	return foonoleak(&x) // ERROR "foo32 &x does not escape$"
+	return foonoleak(&x) // ERROR "&x does not escape"
 }
 
 type Foo struct {
@@ -282,114 +267,114 @@ type Foo struct {
 var F Foo
 var pf *Foo
 
-func (f *Foo) fooleak() { // ERROR "leaking param: f$"
+func (f *Foo) fooleak() { // ERROR "leaking param: f"
 	pf = f
 }
 
-func (f *Foo) foonoleak() { // ERROR "\(\*Foo\).foonoleak f does not escape$"
+func (f *Foo) foonoleak() { // ERROR "f does not escape"
 	F.x = f.x
 }
 
-func (f *Foo) Leak() { // ERROR "leaking param: f$"
+func (f *Foo) Leak() { // ERROR "leaking param: f"
 	f.fooleak()
 }
 
-func (f *Foo) NoLeak() { // ERROR "\(\*Foo\).NoLeak f does not escape$"
+func (f *Foo) NoLeak() { // ERROR "f does not escape"
 	f.foonoleak()
 }
 
-func foo41(x int) { // ERROR "moved to heap: x$"
-	F.xx = &x // ERROR "&x escapes to heap$"
+func foo41(x int) { // ERROR "moved to heap: x"
+	F.xx = &x // ERROR "&x escapes to heap"
 }
 
-func (f *Foo) foo42(x int) { // ERROR "\(\*Foo\).foo42 f does not escape$" "moved to heap: x$"
-	f.xx = &x // ERROR "&x escapes to heap$"
+func (f *Foo) foo42(x int) { // ERROR "f does not escape" "moved to heap: x"
+	f.xx = &x // ERROR "&x escapes to heap"
 }
 
-func foo43(f *Foo, x int) { // ERROR "foo43 f does not escape$" "moved to heap: x$"
-	f.xx = &x // ERROR "&x escapes to heap$"
+func foo43(f *Foo, x int) { // ERROR "f does not escape" "moved to heap: x"
+	f.xx = &x // ERROR "&x escapes to heap"
 }
 
-func foo44(yy *int) { // ERROR "leaking param: yy$"
+func foo44(yy *int) { // ERROR "leaking param: yy"
 	F.xx = yy
 }
 
-func (f *Foo) foo45() { // ERROR "\(\*Foo\).foo45 f does not escape$"
+func (f *Foo) foo45() { // ERROR "f does not escape"
 	F.x = f.x
 }
 
 // See foo13 above for explanation of why f leaks.
-func (f *Foo) foo46() { // ERROR "leaking param content: f$"
+func (f *Foo) foo46() { // ERROR "leaking param: f"
 	F.xx = f.xx
 }
 
-func (f *Foo) foo47() { // ERROR "leaking param: f$"
-	f.xx = &f.x // ERROR "&f.x escapes to heap$"
+func (f *Foo) foo47() { // ERROR "leaking param: f"
+	f.xx = &f.x // ERROR "&f.x escapes to heap"
 }
 
 var ptrSlice []*int
 
-func foo50(i *int) { // ERROR "leaking param: i$"
+func foo50(i *int) { // ERROR "leaking param: i"
 	ptrSlice[0] = i
 }
 
 var ptrMap map[*int]*int
 
-func foo51(i *int) { // ERROR "leaking param: i$"
+func foo51(i *int) { // ERROR "leaking param: i"
 	ptrMap[i] = i
 }
 
-func indaddr1(x int) *int { // ERROR "moved to heap: x$"
-	return &x // ERROR "&x escapes to heap$"
+func indaddr1(x int) *int { // ERROR "moved to heap: x"
+	return &x // ERROR "&x escapes to heap"
 }
 
-func indaddr2(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$"
-	return *&x // ERROR "indaddr2 &x does not escape$"
+func indaddr2(x *int) *int { // ERROR "leaking param: x"
+	return *&x // ERROR "&x does not escape"
 }
 
-func indaddr3(x *int32) *int { // ERROR "leaking param: x to result ~r1 level=0$"
-	return *(**int)(unsafe.Pointer(&x)) // ERROR "indaddr3 &x does not escape$"
+func indaddr3(x *int32) *int { // ERROR "leaking param: x"
+	return *(**int)(unsafe.Pointer(&x)) // ERROR "&x does not escape"
 }
 
 // From package math:
 
 func Float32bits(f float32) uint32 {
-	return *(*uint32)(unsafe.Pointer(&f)) // ERROR "Float32bits &f does not escape$"
+	return *(*uint32)(unsafe.Pointer(&f)) // ERROR "&f does not escape"
 }
 
 func Float32frombits(b uint32) float32 {
-	return *(*float32)(unsafe.Pointer(&b)) // ERROR "Float32frombits &b does not escape$"
+	return *(*float32)(unsafe.Pointer(&b)) // ERROR "&b does not escape"
 }
 
 func Float64bits(f float64) uint64 {
-	return *(*uint64)(unsafe.Pointer(&f)) // ERROR "Float64bits &f does not escape$"
+	return *(*uint64)(unsafe.Pointer(&f)) // ERROR "&f does not escape"
 }
 
 func Float64frombits(b uint64) float64 {
-	return *(*float64)(unsafe.Pointer(&b)) // ERROR "Float64frombits &b does not escape$"
+	return *(*float64)(unsafe.Pointer(&b)) // ERROR "&b does not escape"
 }
 
 // contrast with
-func float64bitsptr(f float64) *uint64 { // ERROR "moved to heap: f$"
-	return (*uint64)(unsafe.Pointer(&f)) // ERROR "&f escapes to heap$"
+func float64bitsptr(f float64) *uint64 { // ERROR "moved to heap: f"
+	return (*uint64)(unsafe.Pointer(&f)) // ERROR "&f escapes to heap"
 }
 
-func float64ptrbitsptr(f *float64) *uint64 { // ERROR "leaking param: f to result ~r1 level=0$"
+func float64ptrbitsptr(f *float64) *uint64 { // ERROR "leaking param: f"
 	return (*uint64)(unsafe.Pointer(f))
 }
 
-func typesw(i interface{}) *int { // ERROR "leaking param: i to result ~r1 level=0$"
+func typesw(i interface{}) *int { // ERROR "leaking param: i"
 	switch val := i.(type) {
 	case *int:
 		return val
 	case *int8:
-		v := int(*val) // ERROR "moved to heap: v$"
-		return &v      // ERROR "&v escapes to heap$"
+		v := int(*val) // ERROR "moved to heap: v"
+		return &v      // ERROR "&v escapes to heap"
 	}
 	return nil
 }
 
-func exprsw(i *int) *int { // ERROR "leaking param: i to result ~r1 level=0$"
+func exprsw(i *int) *int { // ERROR "leaking param: i"
 	switch j := i; *j + 110 {
 	case 12:
 		return j
@@ -401,20 +386,20 @@ func exprsw(i *int) *int { // ERROR "leaking param: i to result ~r1 level=0$"
 }
 
 // assigning to an array element is like assigning to the array
-func foo60(i *int) *int { // ERROR "leaking param: i to result ~r1 level=0$"
+func foo60(i *int) *int { // ERROR "leaking param: i"
 	var a [12]*int
 	a[0] = i
 	return a[1]
 }
 
-func foo60a(i *int) *int { // ERROR "foo60a i does not escape$"
+func foo60a(i *int) *int { // ERROR "i does not escape"
 	var a [12]*int
 	a[0] = i
 	return nil
 }
 
 // assigning to a struct field  is like assigning to the struct
-func foo61(i *int) *int { // ERROR "leaking param: i to result ~r1 level=0$"
+func foo61(i *int) *int { // ERROR "leaking param: i"
 	type S struct {
 		a, b *int
 	}
@@ -423,7 +408,7 @@ func foo61(i *int) *int { // ERROR "leaking param: i to result ~r1 level=0$"
 	return s.b
 }
 
-func foo61a(i *int) *int { // ERROR "foo61a i does not escape$"
+func foo61a(i *int) *int { // ERROR "i does not escape"
 	type S struct {
 		a, b *int
 	}
@@ -435,11 +420,11 @@ func foo61a(i *int) *int { // ERROR "foo61a i does not escape$"
 // assigning to a struct field is like assigning to the struct but
 // here this subtlety is lost, since s.a counts as an assignment to a
 // track-losing dereference.
-func foo62(i *int) *int { // ERROR "leaking param: i$"
+func foo62(i *int) *int { // ERROR "leaking param: i"
 	type S struct {
 		a, b *int
 	}
-	s := new(S) // ERROR "foo62 new\(S\) does not escape$"
+	s := new(S) // ERROR "new[(]S[)] does not escape"
 	s.a = i
 	return nil // s.b
 }
@@ -448,14 +433,14 @@ type M interface {
 	M()
 }
 
-func foo63(m M) { // ERROR "foo63 m does not escape$"
+func foo63(m M) { // ERROR "m does not escape"
 }
 
-func foo64(m M) { // ERROR "leaking param: m$"
+func foo64(m M) { // ERROR "leaking param: m"
 	m.M()
 }
 
-func foo64b(m M) { // ERROR "leaking param: m$"
+func foo64b(m M) { // ERROR "leaking param: m"
 	defer m.M()
 }
 
@@ -465,56 +450,55 @@ func (MV) M() {}
 
 func foo65() {
 	var mv MV
-	foo63(&mv) // ERROR "foo65 &mv does not escape$"
+	foo63(&mv) // ERROR "&mv does not escape"
 }
 
 func foo66() {
-	var mv MV  // ERROR "moved to heap: mv$"
-	foo64(&mv) // ERROR "&mv escapes to heap$"
+	var mv MV  // ERROR "moved to heap: mv"
+	foo64(&mv) // ERROR "&mv escapes to heap"
 }
 
 func foo67() {
 	var mv MV
-	foo63(mv) // ERROR "foo67 mv does not escape$"
+	foo63(mv)
 }
 
 func foo68() {
 	var mv MV
-	// escapes but it's an int so irrelevant
-	foo64(mv) // ERROR "mv escapes to heap$"
+	foo64(mv) // escapes but it's an int so irrelevant
 }
 
-func foo69(m M) { // ERROR "leaking param: m$"
+func foo69(m M) { // ERROR "leaking param: m"
 	foo64(m)
 }
 
-func foo70(mv1 *MV, m M) { // ERROR "leaking param: m$" "leaking param: mv1$"
-	m = mv1 // ERROR "mv1 escapes to heap$"
+func foo70(mv1 *MV, m M) { // ERROR "leaking param: mv1" "leaking param: m"
+	m = mv1
 	foo64(m)
 }
 
-func foo71(x *int) []*int { // ERROR "leaking param: x$"
+func foo71(x *int) []*int { // ERROR "leaking param: x"
 	var y []*int
 	y = append(y, x)
 	return y
 }
 
-func foo71a(x int) []*int { // ERROR "moved to heap: x$"
+func foo71a(x int) []*int { // ERROR "moved to heap: x"
 	var y []*int
-	y = append(y, &x) // ERROR "&x escapes to heap$"
+	y = append(y, &x) // ERROR "&x escapes to heap"
 	return y
 }
 
 func foo72() {
 	var x int
 	var y [1]*int
-	y[0] = &x // ERROR "foo72 &x does not escape$"
+	y[0] = &x // ERROR "&x does not escape"
 }
 
 func foo72aa() [10]*int {
-	var x int // ERROR "moved to heap: x$"
+	var x int // ERROR "moved to heap: x"
 	var y [10]*int
-	y[0] = &x // ERROR "&x escapes to heap$"
+	y[0] = &x // ERROR "&x escapes to heap"
 	return y
 }
 
@@ -522,8 +506,8 @@ func foo72a() {
 	var y [10]*int
 	for i := 0; i < 10; i++ {
 		// escapes its scope
-		x := i    // ERROR "moved to heap: x$"
-		y[i] = &x // ERROR "&x escapes to heap$"
+		x := i    // ERROR "moved to heap: x"
+		y[i] = &x // ERROR "&x escapes to heap"
 	}
 	return
 }
@@ -531,56 +515,31 @@ func foo72a() {
 func foo72b() [10]*int {
 	var y [10]*int
 	for i := 0; i < 10; i++ {
-		x := i    // ERROR "moved to heap: x$"
-		y[i] = &x // ERROR "&x escapes to heap$"
+		x := i    // ERROR "moved to heap: x"
+		y[i] = &x // ERROR "&x escapes to heap"
 	}
 	return y
 }
 
 // issue 2145
 func foo73() {
-	s := []int{3, 2, 1} // ERROR "foo73 \[\]int literal does not escape$"
-	for _, v := range s {
-		vv := v
-		// actually just escapes its scope
-		defer func() { // ERROR "func literal escapes to heap$"
-			println(vv)
-		}()
-	}
-}
-
-func foo731() {
-	s := []int{3, 2, 1} // ERROR "foo731 \[\]int literal does not escape$"
+	s := []int{3, 2, 1} // ERROR "\[\]int literal does not escape"
 	for _, v := range s {
-		vv := v // ERROR "moved to heap: vv$"
+		vv := v // ERROR "moved to heap: vv"
 		// actually just escapes its scope
-		defer func() { // ERROR "func literal escapes to heap$"
-			vv = 42 // ERROR "&vv escapes to heap$"
-			println(vv)
+		defer func() { // ERROR "func literal escapes to heap"
+			println(vv) // ERROR "&vv escapes to heap"
 		}()
 	}
 }
 
 func foo74() {
-	s := []int{3, 2, 1} // ERROR "foo74 \[\]int literal does not escape$"
+	s := []int{3, 2, 1} // ERROR "\[\]int literal does not escape"
 	for _, v := range s {
-		vv := v
+		vv := v // ERROR "moved to heap: vv"
 		// actually just escapes its scope
-		fn := func() { // ERROR "func literal escapes to heap$"
-			println(vv)
-		}
-		defer fn()
-	}
-}
-
-func foo74a() {
-	s := []int{3, 2, 1} // ERROR "foo74a \[\]int literal does not escape$"
-	for _, v := range s {
-		vv := v // ERROR "moved to heap: vv$"
-		// actually just escapes its scope
-		fn := func() { // ERROR "func literal escapes to heap$"
-			vv += 1 // ERROR "&vv escapes to heap$"
-			println(vv)
+		fn := func() { // ERROR "func literal escapes to heap"
+			println(vv) // ERROR "&vv escapes to heap"
 		}
 		defer fn()
 	}
@@ -589,142 +548,110 @@ func foo74a() {
 // issue 3975
 func foo74b() {
 	var array [3]func()
-	s := []int{3, 2, 1} // ERROR "foo74b \[\]int literal does not escape$"
+	s := []int{3, 2, 1} // ERROR "\[\]int literal does not escape"
 	for i, v := range s {
-		vv := v
+		vv := v // ERROR "moved to heap: vv"
 		// actually just escapes its scope
-		array[i] = func() { // ERROR "func literal escapes to heap$"
-			println(vv)
+		array[i] = func() { // ERROR "func literal escapes to heap"
+			println(vv) // ERROR "&vv escapes to heap"
 		}
 	}
 }
 
-func foo74c() {
-	var array [3]func()
-	s := []int{3, 2, 1} // ERROR "foo74c \[\]int literal does not escape$"
-	for i, v := range s {
-		vv := v // ERROR "moved to heap: vv$"
-		// actually just escapes its scope
-		array[i] = func() { // ERROR "func literal escapes to heap$"
-			println(&vv) // ERROR "&vv escapes to heap$" "foo74c.func1 &vv does not escape$"
-		}
-	}
-}
-
-func myprint(y *int, x ...interface{}) *int { // ERROR "leaking param: y to result ~r2 level=0$" "myprint x does not escape$"
+func myprint(y *int, x ...interface{}) *int { // ERROR "x does not escape" "leaking param: y"
 	return y
 }
 
-func myprint1(y *int, x ...interface{}) *interface{} { // ERROR "leaking param: x to result ~r2 level=0$" "myprint1 y does not escape$"
-	return &x[0] // ERROR "&x\[0\] escapes to heap$"
+func myprint1(y *int, x ...interface{}) *interface{} { // ERROR "y does not escape" "leaking param: x"
+	return &x[0] // ERROR "&x.0. escapes to heap"
 }
 
-func foo75(z *int) { // ERROR "foo75 z does not escape$"
-	myprint(z, 1, 2, 3) // ERROR "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$" "foo75 ... argument does not escape$"
+func foo75(z *int) { // ERROR "z does not escape"
+	myprint(z, 1, 2, 3) // ERROR "[.][.][.] argument does not escape"
 }
 
-func foo75a(z *int) { // ERROR "foo75a z does not escape$"
-	myprint1(z, 1, 2, 3) // ERROR "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$" "foo75a ... argument does not escape$"
+func foo75a(z *int) { // ERROR "z does not escape"
+	myprint1(z, 1, 2, 3) // ERROR "[.][.][.] argument does not escape"
 }
 
-func foo75esc(z *int) { // ERROR "leaking param: z$"
-	gxx = myprint(z, 1, 2, 3) // ERROR "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$" "foo75esc ... argument does not escape$"
+func foo75esc(z *int) { // ERROR "leaking param: z"
+	gxx = myprint(z, 1, 2, 3) // ERROR "[.][.][.] argument does not escape"
 }
 
-func foo75aesc(z *int) { // ERROR "foo75aesc z does not escape$"
+func foo75aesc(z *int) { // ERROR "z does not escape"
 	var ppi **interface{}       // assignments to pointer dereferences lose track
-	*ppi = myprint1(z, 1, 2, 3) // ERROR "... argument escapes to heap$" "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$"
-}
-
-func foo75aesc1(z *int) { // ERROR "foo75aesc1 z does not escape$"
-	sink = myprint1(z, 1, 2, 3) // ERROR "... argument escapes to heap$" "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$" "myprint1\(z, 1, 2, 3\) escapes to heap$"
+	*ppi = myprint1(z, 1, 2, 3) // ERROR "[.][.][.] argument escapes to heap"
 }
 
-// BAD: z does not escape here
-func foo76(z *int) { // ERROR "leaking param: z$"
-	myprint(nil, z) // ERROR "foo76 ... argument does not escape$" "z escapes to heap$"
+func foo76(z *int) { // ERROR "leaking param: z"
+	myprint(nil, z) // ERROR "[.][.][.] argument does not escape"
 }
 
-// BAD: z does not escape here
-func foo76a(z *int) { // ERROR "leaking param: z$"
-	myprint1(nil, z) // ERROR "foo76a ... argument does not escape$" "z escapes to heap$"
+func foo76a(z *int) { // ERROR "leaking param: z"
+	myprint1(nil, z) // ERROR "[.][.][.] argument does not escape"
 }
 
 func foo76b() {
-	myprint(nil, 1, 2, 3) // ERROR "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$" "foo76b ... argument does not escape$"
+	myprint(nil, 1, 2, 3) // ERROR "[.][.][.] argument does not escape"
 }
 
 func foo76c() {
-	myprint1(nil, 1, 2, 3) // ERROR "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$" "foo76c ... argument does not escape$"
+	myprint1(nil, 1, 2, 3) // ERROR "[.][.][.] argument does not escape"
 }
 
 func foo76d() {
-	defer myprint(nil, 1, 2, 3) // ERROR "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$" "foo76d ... argument does not escape$"
+	defer myprint(nil, 1, 2, 3) // ERROR "[.][.][.] argument does not escape"
 }
 
 func foo76e() {
-	defer myprint1(nil, 1, 2, 3) // ERROR "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$" "foo76e ... argument does not escape$"
+	defer myprint1(nil, 1, 2, 3) // ERROR "[.][.][.] argument does not escape"
 }
 
 func foo76f() {
 	for {
 		// TODO: This one really only escapes its scope, but we don't distinguish yet.
-		defer myprint(nil, 1, 2, 3) // ERROR "... argument escapes to heap$" "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$"
+		defer myprint(nil, 1, 2, 3) // ERROR "[.][.][.] argument escapes to heap"
 	}
 }
 
 func foo76g() {
 	for {
-		defer myprint1(nil, 1, 2, 3) // ERROR "... argument escapes to heap$" "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$"
+		defer myprint1(nil, 1, 2, 3) // ERROR "[.][.][.] argument escapes to heap"
 	}
 }
 
-func foo77(z []interface{}) { // ERROR "foo77 z does not escape$"
+func foo77(z []interface{}) { // ERROR "z does not escape"
 	myprint(nil, z...) // z does not escape
 }
 
-func foo77a(z []interface{}) { // ERROR "foo77a z does not escape$"
+func foo77a(z []interface{}) { // ERROR "z does not escape"
 	myprint1(nil, z...)
 }
 
-func foo77b(z []interface{}) { // ERROR "leaking param: z$"
+func foo77b(z []interface{}) { // ERROR "leaking param: z"
 	var ppi **interface{}
 	*ppi = myprint1(nil, z...)
 }
 
-func foo77c(z []interface{}) { // ERROR "leaking param: z$"
-	sink = myprint1(nil, z...) // ERROR "myprint1\(nil, z...\) escapes to heap$"
+func foo78(z int) *int { // ERROR "moved to heap: z"
+	return &z // ERROR "&z escapes to heap"
 }
 
-func dotdotdot() {
-	// BAD: i should not escape here
-	i := 0           // ERROR "moved to heap: i$"
-	myprint(nil, &i) // ERROR "&i escapes to heap$" "dotdotdot ... argument does not escape$"
-
-	// BAD: j should not escape here
-	j := 0            // ERROR "moved to heap: j$"
-	myprint1(nil, &j) // ERROR "&j escapes to heap$" "dotdotdot ... argument does not escape$"
-}
-
-func foo78(z int) *int { // ERROR "moved to heap: z$"
-	return &z // ERROR "&z escapes to heap$"
-}
-
-func foo78a(z int) *int { // ERROR "moved to heap: z$"
-	y := &z   // ERROR "&z escapes to heap$"
-	x := &y   // ERROR "foo78a &y does not escape$"
+func foo78a(z int) *int { // ERROR "moved to heap: z"
+	y := &z   // ERROR "&z escapes to heap"
+	x := &y   // ERROR "&y does not escape"
 	return *x // really return y
 }
 
 func foo79() *int {
-	return new(int) // ERROR "new\(int\) escapes to heap$"
+	return new(int) // ERROR "new[(]int[)] escapes to heap"
 }
 
 func foo80() *int {
 	var z *int
 	for {
 		// Really just escapes its scope but we don't distinguish
-		z = new(int) // ERROR "new\(int\) escapes to heap$"
+		z = new(int) // ERROR "new[(]int[)] escapes to heap"
 	}
 	_ = z
 	return nil
@@ -732,24 +659,24 @@ func foo80() *int {
 
 func foo81() *int {
 	for {
-		z := new(int) // ERROR "foo81 new\(int\) does not escape$"
+		z := new(int) // ERROR "new[(]int[)] does not escape"
 		_ = z
 	}
 	return nil
 }
 
-func tee(p *int) (x, y *int) { return p, p } // ERROR "leaking param: p to result x level=0$" "leaking param: p to result y level=0$"
+func tee(p *int) (x, y *int) { return p, p } // ERROR "leaking param"
 
-func noop(x, y *int) {} // ERROR "noop x does not escape$" "noop y does not escape$"
+func noop(x, y *int) {} // ERROR "does not escape"
 
 func foo82() {
-	var x, y, z int  // ERROR "moved to heap: x$" "moved to heap: y$" "moved to heap: z$"
-	go noop(tee(&z)) // ERROR "&z escapes to heap$"
-	go noop(&x, &y)  // ERROR "&x escapes to heap$" "&y escapes to heap$"
+	var x, y, z int  // ERROR "moved to heap"
+	go noop(tee(&z)) // ERROR "&z escapes to heap"
+	go noop(&x, &y)  // ERROR "escapes to heap"
 	for {
-		var u, v, w int     // ERROR "moved to heap: u$" "moved to heap: v$" "moved to heap: w$"
-		defer noop(tee(&u)) // ERROR "&u escapes to heap$"
-		defer noop(&v, &w)  // ERROR "&v escapes to heap$" "&w escapes to heap$"
+		var u, v, w int     // ERROR "moved to heap"
+		defer noop(tee(&u)) // ERROR "&u escapes to heap"
+		defer noop(&v, &w)  // ERROR "escapes to heap"
 	}
 }
 
@@ -762,24 +689,24 @@ type LimitedFooer struct {
 	N int64
 }
 
-func LimitFooer(r Fooer, n int64) Fooer { // ERROR "leaking param: r to result ~r2 level=-1$"
-	return &LimitedFooer{r, n} // ERROR "&LimitedFooer literal escapes to heap$"
+func LimitFooer(r Fooer, n int64) Fooer { // ERROR "leaking param: r"
+	return &LimitedFooer{r, n} // ERROR "&LimitedFooer literal escapes to heap"
 }
 
-func foo90(x *int) map[*int]*int { // ERROR "leaking param: x$"
-	return map[*int]*int{nil: x} // ERROR "map\[\*int\]\*int literal escapes to heap$"
+func foo90(x *int) map[*int]*int { // ERROR "leaking param: x"
+	return map[*int]*int{nil: x} // ERROR "map\[\*int\]\*int literal escapes to heap"
 }
 
-func foo91(x *int) map[*int]*int { // ERROR "leaking param: x$"
-	return map[*int]*int{x: nil} // ERROR "map\[\*int\]\*int literal escapes to heap$"
+func foo91(x *int) map[*int]*int { // ERROR "leaking param: x"
+	return map[*int]*int{x: nil} // ERROR "map\[\*int\]\*int literal escapes to heap"
 }
 
-func foo92(x *int) [2]*int { // ERROR "leaking param: x to result ~r1 level=0$"
+func foo92(x *int) [2]*int { // ERROR "leaking param: x"
 	return [2]*int{x, nil}
 }
 
 // does not leak c
-func foo93(c chan *int) *int { // ERROR "foo93 c does not escape$"
+func foo93(c chan *int) *int { // ERROR "c does not escape"
 	for v := range c {
 		return v
 	}
@@ -787,7 +714,7 @@ func foo93(c chan *int) *int { // ERROR "foo93 c does not escape$"
 }
 
 // does not leak m
-func foo94(m map[*int]*int, b bool) *int { // ERROR "leaking param: m to result ~r2 level=1"
+func foo94(m map[*int]*int, b bool) *int { // ERROR "m does not escape"
 	for k, v := range m {
 		if b {
 			return k
@@ -798,32 +725,32 @@ func foo94(m map[*int]*int, b bool) *int { // ERROR "leaking param: m to result
 }
 
 // does leak x
-func foo95(m map[*int]*int, x *int) { // ERROR "foo95 m does not escape$" "leaking param: x$"
+func foo95(m map[*int]*int, x *int) { // ERROR "m does not escape" "leaking param: x"
 	m[x] = x
 }
 
-// does not leak m but does leak content
-func foo96(m []*int) *int { // ERROR "leaking param: m to result ~r1 level=1"
+// does not leak m
+func foo96(m []*int) *int { // ERROR "m does not escape"
 	return m[0]
 }
 
 // does leak m
-func foo97(m [1]*int) *int { // ERROR "leaking param: m to result ~r1 level=0$"
+func foo97(m [1]*int) *int { // ERROR "leaking param: m"
 	return m[0]
 }
 
 // does not leak m
-func foo98(m map[int]*int) *int { // ERROR "foo98 m does not escape$"
+func foo98(m map[int]*int) *int { // ERROR "m does not escape"
 	return m[0]
 }
 
 // does leak m
-func foo99(m *[1]*int) []*int { // ERROR "leaking param: m to result ~r1 level=0$"
+func foo99(m *[1]*int) []*int { // ERROR "leaking param: m"
 	return m[:]
 }
 
 // does not leak m
-func foo100(m []*int) *int { // ERROR "leaking param: m to result ~r1 level=1"
+func foo100(m []*int) *int { // ERROR "m does not escape"
 	for _, v := range m {
 		return v
 	}
@@ -831,7 +758,7 @@ func foo100(m []*int) *int { // ERROR "leaking param: m to result ~r1 level=1"
 }
 
 // does leak m
-func foo101(m [1]*int) *int { // ERROR "leaking param: m to result ~r1 level=0$"
+func foo101(m [1]*int) *int { // ERROR "leaking param: m"
 	for _, v := range m {
 		return v
 	}
@@ -839,109 +766,109 @@ func foo101(m [1]*int) *int { // ERROR "leaking param: m to result ~r1 level=0$"
 }
 
 // does not leak m
-func foo101a(m [1]*int) *int { // ERROR "foo101a m does not escape$"
-	for i := range m { // ERROR "moved to heap: i$"
-		return &i // ERROR "&i escapes to heap$"
+func foo101a(m [1]*int) *int { // ERROR "m does not escape"
+	for i := range m { // ERROR "moved to heap: i"
+		return &i // ERROR "&i escapes to heap"
 	}
 	return nil
 }
 
 // does leak x
-func foo102(m []*int, x *int) { // ERROR "foo102 m does not escape$" "leaking param: x$"
+func foo102(m []*int, x *int) { // ERROR "m does not escape" "leaking param: x"
 	m[0] = x
 }
 
 // does not leak x
-func foo103(m [1]*int, x *int) { // ERROR "foo103 m does not escape$" "foo103 x does not escape$"
+func foo103(m [1]*int, x *int) { // ERROR "m does not escape" "x does not escape"
 	m[0] = x
 }
 
 var y []*int
 
-// does not leak x but does leak content
-func foo104(x []*int) { // ERROR "leaking param content: x"
+// does not leak x
+func foo104(x []*int) { // ERROR "x does not escape"
 	copy(y, x)
 }
 
-// does not leak x but does leak content
-func foo105(x []*int) { // ERROR "leaking param content: x"
+// does not leak x
+func foo105(x []*int) { // ERROR "x does not escape"
 	_ = append(y, x...)
 }
 
 // does leak x
-func foo106(x *int) { // ERROR "leaking param: x$"
+func foo106(x *int) { // ERROR "leaking param: x"
 	_ = append(y, x)
 }
 
-func foo107(x *int) map[*int]*int { // ERROR "leaking param: x$"
-	return map[*int]*int{x: nil} // ERROR "map\[\*int\]\*int literal escapes to heap$"
+func foo107(x *int) map[*int]*int { // ERROR "leaking param: x"
+	return map[*int]*int{x: nil} // ERROR "map.* literal escapes to heap"
 }
 
-func foo108(x *int) map[*int]*int { // ERROR "leaking param: x$"
-	return map[*int]*int{nil: x} // ERROR "map\[\*int\]\*int literal escapes to heap$"
+func foo108(x *int) map[*int]*int { // ERROR "leaking param: x"
+	return map[*int]*int{nil: x} // ERROR "map.* literal escapes to heap"
 }
 
-func foo109(x *int) *int { // ERROR "leaking param: x$"
-	m := map[*int]*int{x: nil} // ERROR "foo109 map\[\*int\]\*int literal does not escape$"
+func foo109(x *int) *int { // ERROR "leaking param: x"
+	m := map[*int]*int{x: nil} // ERROR "map.* literal does not escape"
 	for k, _ := range m {
 		return k
 	}
 	return nil
 }
 
-func foo110(x *int) *int { // ERROR "leaking param: x$"
-	m := map[*int]*int{nil: x} // ERROR "foo110 map\[\*int\]\*int literal does not escape$"
+func foo110(x *int) *int { // ERROR "leaking param: x"
+	m := map[*int]*int{nil: x} // ERROR "map.* literal does not escape"
 	return m[nil]
 }
 
-func foo111(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0"
-	m := []*int{x} // ERROR "foo111 \[\]\*int literal does not escape$"
+func foo111(x *int) *int { // ERROR "leaking param: x"
+	m := []*int{x} // ERROR "\[\]\*int literal does not escape"
 	return m[0]
 }
 
-func foo112(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$"
+func foo112(x *int) *int { // ERROR "leaking param: x"
 	m := [1]*int{x}
 	return m[0]
 }
 
-func foo113(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$"
+func foo113(x *int) *int { // ERROR "leaking param: x"
 	m := Bar{ii: x}
 	return m.ii
 }
 
-func foo114(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$"
-	m := &Bar{ii: x} // ERROR "foo114 &Bar literal does not escape$"
+func foo114(x *int) *int { // ERROR "leaking param: x"
+	m := &Bar{ii: x} // ERROR "&Bar literal does not escape"
 	return m.ii
 }
 
-func foo115(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$"
+func foo115(x *int) *int { // ERROR "leaking param: x"
 	return (*int)(unsafe.Pointer(uintptr(unsafe.Pointer(x)) + 1))
 }
 
 func foo116(b bool) *int {
 	if b {
-		x := 1    // ERROR "moved to heap: x$"
-		return &x // ERROR "&x escapes to heap$"
+		x := 1    // ERROR "moved to heap: x"
+		return &x // ERROR "&x escapes to heap"
 	} else {
-		y := 1    // ERROR "moved to heap: y$"
-		return &y // ERROR "&y escapes to heap$"
+		y := 1    // ERROR "moved to heap: y"
+		return &y // ERROR "&y escapes to heap"
 	}
 	return nil
 }
 
-func foo117(unknown func(interface{})) { // ERROR "foo117 unknown does not escape$"
-	x := 1      // ERROR "moved to heap: x$"
-	unknown(&x) // ERROR "&x escapes to heap$"
+func foo117(unknown func(interface{})) { // ERROR "unknown does not escape"
+	x := 1      // ERROR "moved to heap: x"
+	unknown(&x) // ERROR "&x escapes to heap"
 }
 
-func foo118(unknown func(*int)) { // ERROR "foo118 unknown does not escape$"
-	x := 1      // ERROR "moved to heap: x$"
-	unknown(&x) // ERROR "&x escapes to heap$"
+func foo118(unknown func(*int)) { // ERROR "unknown does not escape"
+	x := 1      // ERROR "moved to heap: x"
+	unknown(&x) // ERROR "&x escapes to heap"
 }
 
 func external(*int)
 
-func foo119(x *int) { // ERROR "leaking param: x$"
+func foo119(x *int) { // ERROR "leaking param: x"
 	external(x)
 }
 
@@ -1152,16 +1079,16 @@ L100:
 
 func foo121() {
 	for i := 0; i < 10; i++ {
-		defer myprint(nil, i) // ERROR "... argument escapes to heap$" "i escapes to heap$"
-		go myprint(nil, i)    // ERROR "... argument escapes to heap$" "i escapes to heap$"
+		defer myprint(nil, i) // ERROR "[.][.][.] argument escapes to heap"
+		go myprint(nil, i)    // ERROR "[.][.][.] argument escapes to heap"
 	}
 }
 
 // same as foo121 but check across import
 func foo121b() {
 	for i := 0; i < 10; i++ {
-		defer fmt.Printf("%d", i) // ERROR "... argument escapes to heap$" "i escapes to heap$"
-		go fmt.Printf("%d", i)    // ERROR "... argument escapes to heap$" "i escapes to heap$"
+		defer fmt.Printf("%d", i) // ERROR "[.][.][.] argument escapes to heap"
+		go fmt.Printf("%d", i)    // ERROR "[.][.][.] argument escapes to heap"
 	}
 }
 
@@ -1171,7 +1098,7 @@ func foo122() {
 
 	goto L1
 L1:
-	i = new(int) // ERROR "foo122 new\(int\) does not escape$"
+	i = new(int) // ERROR "new.int. does not escape"
 	_ = i
 }
 
@@ -1180,25 +1107,25 @@ func foo123() {
 	var i *int
 
 L1:
-	i = new(int) // ERROR "new\(int\) escapes to heap$"
+	i = new(int) // ERROR "new.int. escapes to heap"
 
 	goto L1
 	_ = i
 }
 
-func foo124(x **int) { // ERROR "foo124 x does not escape$"
-	var i int // ERROR "moved to heap: i$"
-	p := &i   // ERROR "&i escapes to heap$"
-	func() {  // ERROR "foo124 func literal does not escape$"
-		*x = p // ERROR "leaking closure reference p$"
+func foo124(x **int) { // ERROR "x does not escape"
+	var i int // ERROR "moved to heap: i"
+	p := &i   // ERROR "&i escapes"
+	func() {  // ERROR "func literal does not escape"
+		*x = p // ERROR "leaking closure reference p"
 	}()
 }
 
-func foo125(ch chan *int) { // ERROR "foo125 ch does not escape$"
-	var i int // ERROR "moved to heap: i$"
-	p := &i   // ERROR "&i escapes to heap$"
-	func() {  // ERROR "foo125 func literal does not escape$"
-		ch <- p // ERROR "leaking closure reference p$"
+func foo125(ch chan *int) { // ERROR "does not escape"
+	var i int // ERROR "moved to heap"
+	p := &i   // ERROR "&i escapes to heap"
+	func() {  // ERROR "func literal does not escape"
+		ch <- p // ERROR "leaking closure reference p"
 	}()
 }
 
@@ -1206,9 +1133,9 @@ func foo126() {
 	var px *int // loopdepth 0
 	for {
 		// loopdepth 1
-		var i int // ERROR "moved to heap: i$"
-		func() {  // ERROR "foo126 func literal does not escape$"
-			px = &i // ERROR "&i escapes to heap$"
+		var i int // ERROR "moved to heap"
+		func() {  // ERROR "func literal does not escape"
+			px = &i // ERROR "&i escapes"
 		}()
 	}
 	_ = px
@@ -1217,26 +1144,26 @@ func foo126() {
 var px *int
 
 func foo127() {
-	var i int // ERROR "moved to heap: i$"
-	p := &i   // ERROR "&i escapes to heap$"
+	var i int // ERROR "moved to heap: i"
+	p := &i   // ERROR "&i escapes to heap"
 	q := p
 	px = q
 }
 
 func foo128() {
 	var i int
-	p := &i // ERROR "foo128 &i does not escape$"
+	p := &i // ERROR "&i does not escape"
 	q := p
 	_ = q
 }
 
 func foo129() {
-	var i int // ERROR "moved to heap: i$"
-	p := &i   // ERROR "&i escapes to heap$"
-	func() {  // ERROR "foo129 func literal does not escape$"
-		q := p   // ERROR "leaking closure reference p$"
-		func() { // ERROR "foo129.func1 func literal does not escape$"
-			r := q // ERROR "leaking closure reference q$"
+	var i int // ERROR "moved to heap: i"
+	p := &i   // ERROR "&i escapes to heap"
+	func() {  // ERROR "func literal does not escape"
+		q := p   // ERROR "leaking closure reference p"
+		func() { // ERROR "func literal does not escape"
+			r := q // ERROR "leaking closure reference q"
 			px = r
 		}()
 	}()
@@ -1244,40 +1171,40 @@ func foo129() {
 
 func foo130() {
 	for {
-		var i int // ERROR "moved to heap: i$"
-		func() {  // ERROR "foo130 func literal does not escape$"
-			px = &i // ERROR "&i escapes to heap$" "leaking closure reference i$"
+		var i int // ERROR "moved to heap"
+		func() {  // ERROR "func literal does not escape"
+			px = &i // ERROR "&i escapes" "leaking closure reference i"
 		}()
 	}
 }
 
 func foo131() {
-	var i int // ERROR "moved to heap: i$"
-	func() {  // ERROR "foo131 func literal does not escape$"
-		px = &i // ERROR "&i escapes to heap$" "leaking closure reference i$"
+	var i int // ERROR "moved to heap"
+	func() {  // ERROR "func literal does not escape"
+		px = &i // ERROR "&i escapes" "leaking closure reference i"
 	}()
 }
 
 func foo132() {
-	var i int   // ERROR "moved to heap: i$"
-	go func() { // ERROR "func literal escapes to heap$"
-		px = &i // ERROR "&i escapes to heap$" "leaking closure reference i$"
+	var i int   // ERROR "moved to heap"
+	go func() { // ERROR "func literal escapes to heap"
+		px = &i // ERROR "&i escapes" "leaking closure reference i"
 	}()
 }
 
 func foo133() {
-	var i int      // ERROR "moved to heap: i$"
-	defer func() { // ERROR "foo133 func literal does not escape$"
-		px = &i // ERROR "&i escapes to heap$" "leaking closure reference i$"
+	var i int      // ERROR "moved to heap"
+	defer func() { // ERROR "func literal does not escape"
+		px = &i // ERROR "&i escapes" "leaking closure reference i"
 	}()
 }
 
 func foo134() {
 	var i int
-	p := &i  // ERROR "foo134 &i does not escape$"
-	func() { // ERROR "foo134 func literal does not escape$"
+	p := &i  // ERROR "&i does not escape"
+	func() { // ERROR "func literal does not escape"
 		q := p
-		func() { // ERROR "foo134.func1 func literal does not escape$"
+		func() { // ERROR "func literal does not escape"
 			r := q
 			_ = r
 		}()
@@ -1285,11 +1212,11 @@ func foo134() {
 }
 
 func foo135() {
-	var i int   // ERROR "moved to heap: i$"
-	p := &i     // ERROR "&i escapes to heap$"
-	go func() { // ERROR "func literal escapes to heap$"
-		q := p
-		func() { // ERROR "foo135.func1 func literal does not escape$"
+	var i int   // ERROR "moved to heap: i"
+	p := &i     // ERROR "&i escapes to heap" "moved to heap: p"
+	go func() { // ERROR "func literal escapes to heap"
+		q := p   // ERROR "&p escapes to heap"
+		func() { // ERROR "func literal does not escape"
 			r := q
 			_ = r
 		}()
@@ -1297,24 +1224,24 @@ func foo135() {
 }
 
 func foo136() {
-	var i int   // ERROR "moved to heap: i$"
-	p := &i     // ERROR "&i escapes to heap$"
-	go func() { // ERROR "func literal escapes to heap$"
-		q := p   // ERROR "leaking closure reference p$"
-		func() { // ERROR "foo136.func1 func literal does not escape$"
-			r := q // ERROR "leaking closure reference q$"
+	var i int   // ERROR "moved to heap: i"
+	p := &i     // ERROR "&i escapes to heap" "moved to heap: p"
+	go func() { // ERROR "func literal escapes to heap"
+		q := p   // ERROR "&p escapes to heap" "leaking closure reference p"
+		func() { // ERROR "func literal does not escape"
+			r := q // ERROR "leaking closure reference q"
 			px = r
 		}()
 	}()
 }
 
 func foo137() {
-	var i int // ERROR "moved to heap: i$"
-	p := &i   // ERROR "&i escapes to heap$"
-	func() {  // ERROR "foo137 func literal does not escape$"
-		q := p      // ERROR "leaking closure reference p$"
-		go func() { // ERROR "func literal escapes to heap$"
-			r := q
+	var i int // ERROR "moved to heap: i"
+	p := &i   // ERROR "&i escapes to heap"
+	func() {  // ERROR "func literal does not escape"
+		q := p      // ERROR "leaking closure reference p" "moved to heap: q"
+		go func() { // ERROR "func literal escapes to heap"
+			r := q // ERROR "&q escapes to heap"
 			_ = r
 		}()
 	}()
@@ -1324,8 +1251,8 @@ func foo138() *byte {
 	type T struct {
 		x [1]byte
 	}
-	t := new(T)    // ERROR "new\(T\) escapes to heap$"
-	return &t.x[0] // ERROR "&t.x\[0\] escapes to heap$"
+	t := new(T)    // ERROR "new.T. escapes to heap"
+	return &t.x[0] // ERROR "&t.x.0. escapes to heap"
 }
 
 func foo139() *byte {
@@ -1334,8 +1261,8 @@ func foo139() *byte {
 			y byte
 		}
 	}
-	t := new(T)   // ERROR "new\(T\) escapes to heap$"
-	return &t.x.y // ERROR "&t.x.y escapes to heap$"
+	t := new(T)   // ERROR "new.T. escapes to heap"
+	return &t.x.y // ERROR "&t.x.y escapes to heap"
 }
 
 // issue 4751
@@ -1347,8 +1274,8 @@ func foo140() interface{} {
 		X string
 		T *T
 	}
-	t := &T{} // ERROR "&T literal escapes to heap$"
-	return U{ // ERROR "U literal escapes to heap$"
+	t := &T{} // ERROR "&T literal escapes to heap"
+	return U{
 		X: t.X,
 		T: t,
 	}
@@ -1362,53 +1289,53 @@ func F2([]byte)
 
 //go:noescape
 
-func F3(x []byte) // ERROR "F3 x does not escape$"
+func F3(x []byte) // ERROR "F3 x does not escape"
 
 func F4(x []byte)
 
 func G() {
 	var buf1 [10]byte
-	F1(buf1[:]) // ERROR "G buf1 does not escape$"
+	F1(buf1[:]) // ERROR "buf1 does not escape"
 
-	var buf2 [10]byte // ERROR "moved to heap: buf2$"
-	F2(buf2[:])       // ERROR "buf2 escapes to heap$"
+	var buf2 [10]byte // ERROR "moved to heap: buf2"
+	F2(buf2[:])       // ERROR "buf2 escapes to heap"
 
 	var buf3 [10]byte
-	F3(buf3[:]) // ERROR "G buf3 does not escape$"
+	F3(buf3[:]) // ERROR "buf3 does not escape"
 
-	var buf4 [10]byte // ERROR "moved to heap: buf4$"
-	F4(buf4[:])       // ERROR "buf4 escapes to heap$"
+	var buf4 [10]byte // ERROR "moved to heap: buf4"
+	F4(buf4[:])       // ERROR "buf4 escapes to heap"
 }
 
 type Tm struct {
 	x int
 }
 
-func (t *Tm) M() { // ERROR "\(\*Tm\).M t does not escape$"
+func (t *Tm) M() { // ERROR "t does not escape"
 }
 
 func foo141() {
 	var f func()
 
-	t := new(Tm) // ERROR "new\(Tm\) escapes to heap$"
-	f = t.M      // ERROR "foo141 t.M does not escape$"
+	t := new(Tm) // ERROR "escapes to heap"
+	f = t.M      // ERROR "t.M does not escape"
 	_ = f
 }
 
 var gf func()
 
 func foo142() {
-	t := new(Tm) // ERROR "new\(Tm\) escapes to heap$"
-	gf = t.M     // ERROR "t.M escapes to heap$"
+	t := new(Tm) // ERROR "escapes to heap"
+	gf = t.M     // ERROR "t.M escapes to heap"
 }
 
 // issue 3888.
 func foo143() {
 	for i := 0; i < 1000; i++ {
-		func() { // ERROR "foo143 func literal does not escape$"
+		func() { // ERROR "func literal does not escape"
 			for i := 0; i < 1; i++ {
 				var t Tm
-				t.M() // ERROR "foo143.func1 t does not escape$"
+				t.M() // ERROR "t does not escape"
 			}
 		}()
 	}
@@ -1424,9 +1351,9 @@ func foo144a(*int)
 
 func foo144() {
 	var x int
-	foo144a(&x) // ERROR "foo144 &x does not escape$"
+	foo144a(&x) // ERROR "&x does not escape"
 	var y int
-	foo144b(&y) // ERROR "foo144 &y does not escape$"
+	foo144b(&y) // ERROR "&y does not escape"
 }
 
 //go:noescape
@@ -1439,38 +1366,38 @@ type List struct {
 	Next *List
 }
 
-func foo145(l List) { // ERROR "foo145 l does not escape$"
+func foo145(l List) { // ERROR "l does not escape"
 	var p *List
-	for p = &l; p.Next != nil; p = p.Next { // ERROR "foo145 &l does not escape$"
+	for p = &l; p.Next != nil; p = p.Next { // ERROR "&l does not escape"
 	}
 }
 
-func foo146(l List) { // ERROR "foo146 l does not escape$"
+func foo146(l List) { // ERROR "l does not escape"
 	var p *List
-	p = &l // ERROR "foo146 &l does not escape$"
+	p = &l // ERROR "&l does not escape"
 	for ; p.Next != nil; p = p.Next {
 	}
 }
 
-func foo147(l List) { // ERROR "foo147 l does not escape$"
+func foo147(l List) { // ERROR "l does not escape"
 	var p *List
-	p = &l // ERROR "foo147 &l does not escape$"
+	p = &l // ERROR "&l does not escape"
 	for p.Next != nil {
 		p = p.Next
 	}
 }
 
-func foo148(l List) { // ERROR "foo148 l does not escape$"
-	for p := &l; p.Next != nil; p = p.Next { // ERROR "foo148 &l does not escape$"
+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 "foo149 l does not escape$"
+func foo149(l List) { // ERROR " l does not escape"
 	var p *List
 	for {
-		for p = &l; p.Next != nil; p = p.Next { // ERROR "foo149 &l does not escape$"
+		for p = &l; p.Next != nil; p = p.Next { // ERROR "&l does not escape"
 		}
 	}
 }
@@ -1479,44 +1406,44 @@ func foo149(l List) { // ERROR "foo149 l does not escape$"
 
 var save150 []byte
 
-func foo150(x ...byte) { // ERROR "leaking param: x$"
+func foo150(x ...byte) { // ERROR "leaking param: x"
 	save150 = x
 }
 
 func bar150() {
-	foo150(1, 2, 3) // ERROR "... argument escapes to heap$"
+	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$"
+func foo151(x *int) { // ERROR "leaking param: x"
 	save151 = x
 }
 
 func bar151() {
-	var a [64]int // ERROR "moved to heap: a$"
+	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$"
+	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$"
+	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$"
+	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$"
+	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$"
+	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
@@ -1525,7 +1452,7 @@ type U struct {
 	s *string
 }
 
-func (u *U) String() *string { // ERROR "leaking param: u to result ~r0 level=1$"
+func (u *U) String() *string { // ERROR "leaking param u content to result ~r0"
 	return u.s
 }
 
@@ -1533,298 +1460,35 @@ type V struct {
 	s *string
 }
 
-// BAD -- level of leak ought to be 0
-func NewV(u U) *V { // ERROR "leaking param: u to result ~r1 level=-1"
-	return &V{u.String()} // ERROR "&V literal escapes to heap$" "NewV u does not escape"
+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$"
+	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 to result ~r1 level=-1$"
+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$"
+	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$"
+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$"
+func g() (x interface{}) { // ERROR "moved to heap: x"
+	x = &x // ERROR "&x escapes to heap"
 	return
 }
-
-var sink interface{}
-
-type Lit struct {
-	p *int
-}
-
-func ptrlitNoescape() {
-	// Both literal and element do not escape.
-	i := 0
-	x := &Lit{&i} // ERROR "ptrlitNoescape &Lit literal does not escape$" "ptrlitNoescape &i does not escape$"
-	_ = x
-}
-
-func ptrlitNoEscape2() {
-	// Literal does not escape, but element does.
-	i := 0        // ERROR "moved to heap: i$"
-	x := &Lit{&i} // ERROR "&i escapes to heap$" "ptrlitNoEscape2 &Lit literal does not escape$"
-	sink = *x     // ERROR "\*x escapes to heap$"
-}
-
-func ptrlitEscape() {
-	// Both literal and element escape.
-	i := 0        // ERROR "moved to heap: i$"
-	x := &Lit{&i} // ERROR "&Lit literal escapes to heap$" "&i escapes to heap$"
-	sink = x      // ERROR "x escapes to heap$"
-}
-
-// self-assignments
-
-type Buffer struct {
-	arr  [64]byte
-	buf1 []byte
-	buf2 []byte
-	str1 string
-	str2 string
-}
-
-func (b *Buffer) foo() { // ERROR "\(\*Buffer\).foo b does not escape$"
-	b.buf1 = b.buf1[1:2]   // ERROR "\(\*Buffer\).foo ignoring self-assignment to b.buf1$"
-	b.buf1 = b.buf1[1:2:3] // ERROR "\(\*Buffer\).foo ignoring self-assignment to b.buf1$"
-	b.buf1 = b.buf2[1:2]   // ERROR "\(\*Buffer\).foo ignoring self-assignment to b.buf1$"
-	b.buf1 = b.buf2[1:2:3] // ERROR "\(\*Buffer\).foo ignoring self-assignment to b.buf1$"
-}
-
-func (b *Buffer) bar() { // ERROR "leaking param: b$"
-	b.buf1 = b.arr[1:2] // ERROR "b.arr escapes to heap$"
-}
-
-func (b *Buffer) baz() { // ERROR "\(\*Buffer\).baz b does not escape$"
-	b.str1 = b.str1[1:2] // ERROR "\(\*Buffer\).baz ignoring self-assignment to b.str1$"
-	b.str1 = b.str2[1:2] // ERROR "\(\*Buffer\).baz ignoring self-assignment to b.str1$"
-}
-
-func (b *Buffer) bat() { // ERROR "leaking param content: b$"
-	o := new(Buffer) // ERROR "new\(Buffer\) escapes to heap$"
-	o.buf1 = b.buf1[1:2]
-	sink = o // ERROR "o escapes to heap$"
-}
-
-func quux(sp *string, bp *[]byte) { // ERROR "quux bp does not escape$" "quux sp does not escape$"
-	*sp = (*sp)[1:2] // ERROR "quux ignoring self-assignment to \*sp$"
-	*bp = (*bp)[1:2] // ERROR "quux ignoring self-assignment to \*bp$"
-}
-
-type StructWithString struct {
-	p *int
-	s string
-}
-
-// This is escape analysis false negative.
-// We assign the pointer to x.p but leak x.s. Escape analysis coarsens flows
-// to just x, and thus &i looks escaping.
-func fieldFlowTracking() {
-	var x StructWithString
-	i := 0     // ERROR "moved to heap: i$"
-	x.p = &i   // ERROR "&i escapes to heap$"
-	sink = x.s // ERROR "x.s escapes to heap$"
-}
-
-// String operations.
-
-func slicebytetostring0() {
-	b := make([]byte, 20) // ERROR "slicebytetostring0 make\(\[\]byte, 20\) does not escape$"
-	s := string(b)        // ERROR "slicebytetostring0 string\(b\) does not escape$"
-	_ = s
-}
-
-func slicebytetostring1() {
-	b := make([]byte, 20) // ERROR "slicebytetostring1 make\(\[\]byte, 20\) does not escape$"
-	s := string(b)        // ERROR "slicebytetostring1 string\(b\) does not escape$"
-	s1 := s[0:1]
-	_ = s1
-}
-
-func slicebytetostring2() {
-	b := make([]byte, 20) // ERROR "slicebytetostring2 make\(\[\]byte, 20\) does not escape$"
-	s := string(b)        // ERROR "string\(b\) escapes to heap$"
-	s1 := s[0:1]          // ERROR "moved to heap: s1$"
-	sink = &s1            // ERROR "&s1 escapes to heap$"
-}
-
-func slicebytetostring3() {
-	b := make([]byte, 20) // ERROR "slicebytetostring3 make\(\[\]byte, 20\) does not escape$"
-	s := string(b)        // ERROR "string\(b\) escapes to heap$"
-	s1 := s[0:1]
-	sink = s1 // ERROR "s1 escapes to heap$"
-}
-
-func addstr0() {
-	s0 := "a"
-	s1 := "b"
-	s := s0 + s1 // ERROR "addstr0 s0 \+ s1 does not escape$"
-	_ = s
-}
-
-func addstr1() {
-	s0 := "a"
-	s1 := "b"
-	s := "c"
-	s += s0 + s1 // ERROR "addstr1 s0 \+ s1 does not escape$"
-	_ = s
-}
-
-func addstr2() {
-	b := make([]byte, 20) // ERROR "addstr2 make\(\[\]byte, 20\) does not escape$"
-	s0 := "a"
-	s := string(b) + s0 // ERROR "addstr2 string\(b\) \+ s0 does not escape$" "addstr2 string\(b\) does not escape$"
-	_ = s
-}
-
-func addstr3() {
-	s0 := "a"
-	s1 := "b"
-	s := s0 + s1 // ERROR "s0 \+ s1 escapes to heap$"
-	s2 := s[0:1]
-	sink = s2 // ERROR "s2 escapes to heap$"
-}
-
-func intstring0() bool {
-	// string does not escape
-	x := '0'
-	s := string(x) // ERROR "intstring0 string\(x\) does not escape$"
-	return s == "0"
-}
-
-func intstring1() string {
-	// string does not escape, but the buffer does
-	x := '0'
-	s := string(x) // ERROR "string\(x\) escapes to heap$"
-	return s
-}
-
-func intstring2() {
-	// string escapes to heap
-	x := '0'
-	s := string(x) // ERROR "moved to heap: s$" "string\(x\) escapes to heap$"
-	sink = &s      // ERROR "&s escapes to heap$"
-}
-
-func stringtoslicebyte0() {
-	s := "foo"
-	x := []byte(s) // ERROR "stringtoslicebyte0 \(\[\]byte\)\(s\) does not escape$"
-	_ = x
-}
-
-func stringtoslicebyte1() []byte {
-	s := "foo"
-	return []byte(s) // ERROR "\(\[\]byte\)\(s\) escapes to heap$"
-}
-
-func stringtoslicebyte2() {
-	s := "foo"
-	sink = []byte(s) // ERROR "\(\[\]byte\)\(s\) escapes to heap$"
-}
-
-func stringtoslicerune0() {
-	s := "foo"
-	x := []rune(s) // ERROR "stringtoslicerune0 \(\[\]rune\)\(s\) does not escape$"
-	_ = x
-}
-
-func stringtoslicerune1() []rune {
-	s := "foo"
-	return []rune(s) // ERROR "\(\[\]rune\)\(s\) escapes to heap$"
-}
-
-func stringtoslicerune2() {
-	s := "foo"
-	sink = []rune(s) // ERROR "\(\[\]rune\)\(s\) escapes to heap$"
-}
-
-func slicerunetostring0() {
-	r := []rune{1, 2, 3} // ERROR "slicerunetostring0 \[\]rune literal does not escape$"
-	s := string(r)       // ERROR "slicerunetostring0 string\(r\) does not escape$"
-	_ = s
-}
-
-func slicerunetostring1() string {
-	r := []rune{1, 2, 3} // ERROR "slicerunetostring1 \[\]rune literal does not escape$"
-	return string(r)     // ERROR "string\(r\) escapes to heap$"
-}
-
-func slicerunetostring2() {
-	r := []rune{1, 2, 3} // ERROR "slicerunetostring2 \[\]rune literal does not escape$"
-	sink = string(r)     // ERROR "string\(r\) escapes to heap$"
-}
-
-func makemap0() {
-	m := make(map[int]int) // ERROR "makemap0 make\(map\[int\]int\) does not escape$"
-	m[0] = 0
-	m[1]++
-	delete(m, 1)
-	sink = m[0] // ERROR "m\[0\] escapes to heap$"
-}
-
-func makemap1() map[int]int {
-	return make(map[int]int) // ERROR "make\(map\[int\]int\) escapes to heap$"
-}
-
-func makemap2() {
-	m := make(map[int]int) // ERROR "make\(map\[int\]int\) escapes to heap$"
-	sink = m               // ERROR "m escapes to heap$"
-}
-
-func nonescapingEface(m map[interface{}]bool) bool { // ERROR "nonescapingEface m does not escape$"
-	return m["foo"] // ERROR "nonescapingEface .foo. does not escape$"
-}
-
-func nonescapingIface(m map[M]bool) bool { // ERROR "nonescapingIface m does not escape$"
-	return m[MV(0)] // ERROR "nonescapingIface MV\(0\) does not escape$"
-}
-
-func issue10353() {
-	x := new(int) // ERROR "new\(int\) escapes to heap$"
-	issue10353a(x)()
-}
-
-func issue10353a(x *int) func() { // ERROR "leaking param: x to result ~r1 level=-1$"
-	return func() { // ERROR "func literal escapes to heap$"
-		println(*x)
-	}
-}
-
-func issue10353b() {
-	var f func()
-	for {
-		x := new(int) // ERROR "new\(int\) escapes to heap$"
-		f = func() {  // ERROR "func literal escapes to heap$"
-			println(*x)
-		}
-	}
-	_ = f
-}
-
-func issue11387(x int) func() int {
-	f := func() int { return x }    // ERROR "func literal escapes to heap"
-	slice1 := []func() int{f}       // ERROR "\[\].* does not escape"
-	slice2 := make([]func() int, 1) // ERROR "make\(.*\) does not escape"
-	copy(slice2, slice1)
-	return slice2[0]
-}
diff --git a/test/escape2n.go b/test/escape2n.go
index c328773..002a78e 100644
--- a/test/escape2n.go
+++ b/test/escape2n.go
@@ -18,94 +18,94 @@ import (
 
 var gxx *int
 
-func foo1(x int) { // ERROR "moved to heap: x$"
-	gxx = &x // ERROR "&x escapes to heap$"
+func foo1(x int) { // ERROR "moved to heap: x"
+	gxx = &x // ERROR "&x escapes to heap"
 }
 
-func foo2(yy *int) { // ERROR "leaking param: yy$"
+func foo2(yy *int) { // ERROR "leaking param: yy"
 	gxx = yy
 }
 
-func foo3(x int) *int { // ERROR "moved to heap: x$"
-	return &x // ERROR "&x escapes to heap$"
+func foo3(x int) *int { // ERROR "moved to heap: x"
+	return &x // ERROR "&x escapes to heap"
 }
 
 type T *T
 
-func foo3b(t T) { // ERROR "leaking param: t$"
+func foo3b(t T) { // ERROR "leaking param: t"
 	*t = t
 }
 
 // xx isn't going anywhere, so use of yy is ok
-func foo4(xx, yy *int) { // ERROR "foo4 xx does not escape$" "foo4 yy does not escape$"
+func foo4(xx, yy *int) { // ERROR "xx does not escape" "yy does not escape"
 	xx = yy
 }
 
 // xx isn't going anywhere, so taking address of yy is ok
-func foo5(xx **int, yy *int) { // ERROR "foo5 xx does not escape$" "foo5 yy does not escape$"
-	xx = &yy // ERROR "foo5 &yy does not escape$"
+func foo5(xx **int, yy *int) { // ERROR "xx does not escape" "yy does not escape"
+	xx = &yy // ERROR "&yy does not escape"
 }
 
-func foo6(xx **int, yy *int) { // ERROR "foo6 xx does not escape$" "leaking param: yy$"
+func foo6(xx **int, yy *int) { // ERROR "xx does not escape" "leaking param: yy"
 	*xx = yy
 }
 
-func foo7(xx **int, yy *int) { // ERROR "foo7 xx does not escape$" "foo7 yy does not escape$"
+func foo7(xx **int, yy *int) { // ERROR "xx does not escape" "yy does not escape"
 	**xx = *yy
 }
 
-func foo8(xx, yy *int) int { // ERROR "foo8 xx does not escape$" "foo8 yy does not escape$"
+func foo8(xx, yy *int) int { // ERROR "xx does not escape" "yy does not escape"
 	xx = yy
 	return *xx
 }
 
-func foo9(xx, yy *int) *int { // ERROR "leaking param: xx to result ~r2 level=0$" "leaking param: yy to result ~r2 level=0$"
+func foo9(xx, yy *int) *int { // ERROR "leaking param: xx" "leaking param: yy"
 	xx = yy
 	return xx
 }
 
-func foo10(xx, yy *int) { // ERROR "foo10 xx does not escape$" "foo10 yy does not escape$"
+func foo10(xx, yy *int) { // ERROR "xx does not escape" "yy does not escape"
 	*xx = *yy
 }
 
 func foo11() int {
 	x, y := 0, 42
-	xx := &x // ERROR "foo11 &x does not escape$"
-	yy := &y // ERROR "foo11 &y does not escape$"
+	xx := &x // ERROR "&x does not escape"
+	yy := &y // ERROR "&y does not escape"
 	*xx = *yy
 	return x
 }
 
 var xxx **int
 
-func foo12(yyy **int) { // ERROR "leaking param: yyy$"
+func foo12(yyy **int) { // ERROR "leaking param: yyy"
 	xxx = yyy
 }
 
 // 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 content: yyy$"
+func foo13(yyy **int) { // ERROR "leaking param: yyy"
 	*xxx = *yyy
 }
 
-func foo14(yyy **int) { // ERROR "foo14 yyy does not escape$"
+func foo14(yyy **int) { // ERROR "yyy does not escape"
 	**xxx = **yyy
 }
 
-func foo15(yy *int) { // ERROR "moved to heap: yy$"
-	xxx = &yy // ERROR "&yy escapes to heap$"
+func foo15(yy *int) { // ERROR "moved to heap: yy"
+	xxx = &yy // ERROR "&yy escapes to heap"
 }
 
-func foo16(yy *int) { // ERROR "leaking param: yy$"
+func foo16(yy *int) { // ERROR "leaking param: yy"
 	*xxx = yy
 }
 
-func foo17(yy *int) { // ERROR "foo17 yy does not escape$"
+func foo17(yy *int) { // ERROR "yy does not escape"
 	**xxx = *yy
 }
 
-func foo18(y int) { // ERROR "moved to heap: y$"
-	*xxx = &y // ERROR "&y escapes to heap$"
+func foo18(y int) { // ERROR "moved to heap: "y"
+	*xxx = &y // ERROR "&y escapes to heap"
 }
 
 func foo19(y int) {
@@ -118,52 +118,52 @@ type Bar struct {
 }
 
 func NewBar() *Bar {
-	return &Bar{42, nil} // ERROR "&Bar literal escapes to heap$"
+	return &Bar{42, nil} // ERROR "&Bar literal escapes to heap"
 }
 
-func NewBarp(x *int) *Bar { // ERROR "leaking param: x to result ~r1 level=-1$"
-	return &Bar{42, x} // ERROR "&Bar literal escapes to heap$"
+func NewBarp(x *int) *Bar { // ERROR "leaking param: x"
+	return &Bar{42, x} // ERROR "&Bar literal escapes to heap"
 }
 
-func NewBarp2(x *int) *Bar { // ERROR "NewBarp2 x does not escape$"
-	return &Bar{*x, nil} // ERROR "&Bar literal escapes to heap$"
+func NewBarp2(x *int) *Bar { // ERROR "x does not escape"
+	return &Bar{*x, nil} // ERROR "&Bar literal escapes to heap"
 }
 
-func (b *Bar) NoLeak() int { // ERROR "\(\*Bar\).NoLeak b does not escape$"
+func (b *Bar) NoLeak() int { // ERROR "b does not escape"
 	return *(b.ii)
 }
 
-func (b *Bar) Leak() *int { // ERROR "leaking param: b to result ~r0 level=0$"
-	return &b.i // ERROR "&b.i escapes to heap$"
+func (b *Bar) Leak() *int { // ERROR "leaking param: b"
+	return &b.i // ERROR "&b.i escapes to heap"
 }
 
-func (b *Bar) AlsoNoLeak() *int { // ERROR "leaking param: b to result ~r0 level=1$"
+func (b *Bar) AlsoNoLeak() *int { // ERROR "leaking param b content to result ~r0"
 	return b.ii
 }
 
-func (b Bar) AlsoLeak() *int { // ERROR "leaking param: b to result ~r0 level=0$"
+func (b Bar) AlsoLeak() *int { // ERROR "leaking param: b"
 	return b.ii
 }
 
-func (b Bar) LeaksToo() *int { // ERROR "leaking param: b to result ~r0 level=0$"
-	v := 0    // ERROR "moved to heap: v$"
-	b.ii = &v // ERROR "&v escapes to heap$"
+func (b Bar) LeaksToo() *int { // ERROR "leaking param: b"
+	v := 0    // ERROR "moved to heap: v"
+	b.ii = &v // ERROR "&v escapes"
 	return b.ii
 }
 
-func (b *Bar) LeaksABit() *int { // ERROR "leaking param: b to result ~r0 level=1$"
-	v := 0    // ERROR "moved to heap: v$"
-	b.ii = &v // ERROR "&v escapes to heap$"
+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
 }
 
-func (b Bar) StillNoLeak() int { // ERROR "Bar.StillNoLeak b does not escape$"
+func (b Bar) StillNoLeak() int { // ERROR "b does not escape"
 	v := 0
-	b.ii = &v // ERROR "Bar.StillNoLeak &v does not escape$"
+	b.ii = &v // ERROR "&v does not escape"
 	return b.i
 }
 
-func goLeak(b *Bar) { // ERROR "leaking param: b$"
+func goLeak(b *Bar) { // ERROR "leaking param: b"
 	go b.NoLeak()
 }
 
@@ -173,105 +173,90 @@ type Bar2 struct {
 }
 
 func NewBar2() *Bar2 {
-	return &Bar2{[12]int{42}, nil} // ERROR "&Bar2 literal escapes to heap$"
+	return &Bar2{[12]int{42}, nil} // ERROR "&Bar2 literal escapes to heap"
 }
 
-func (b *Bar2) NoLeak() int { // ERROR "\(\*Bar2\).NoLeak b does not escape$"
+func (b *Bar2) NoLeak() int { // ERROR "b does not escape"
 	return b.i[0]
 }
 
-func (b *Bar2) Leak() []int { // ERROR "leaking param: b to result ~r0 level=0$"
-	return b.i[:] // ERROR "b.i escapes to heap$"
+func (b *Bar2) Leak() []int { // ERROR "leaking param: b"
+	return b.i[:] // ERROR "b.i escapes to heap"
 }
 
-func (b *Bar2) AlsoNoLeak() []int { // ERROR "leaking param: b to result ~r0 level=1$"
+func (b *Bar2) AlsoNoLeak() []int { // ERROR "leaking param b content to result ~r0"
 	return b.ii[0:1]
 }
 
-func (b Bar2) AgainNoLeak() [12]int { // ERROR "Bar2.AgainNoLeak b does not escape$"
+func (b Bar2) AgainNoLeak() [12]int { // ERROR "b does not escape"
 	return b.i
 }
 
-func (b *Bar2) LeakSelf() { // ERROR "leaking param: b$"
-	b.ii = b.i[0:4] // ERROR "b.i escapes to heap$"
+func (b *Bar2) LeakSelf() { // ERROR "leaking param: b"
+	b.ii = b.i[0:4] // ERROR "b.i escapes to heap"
 }
 
-func (b *Bar2) LeakSelf2() { // ERROR "leaking param: b$"
+func (b *Bar2) LeakSelf2() { // ERROR "leaking param: b"
 	var buf []int
-	buf = b.i[0:] // ERROR "b.i escapes to heap$"
+	buf = b.i[0:] // ERROR "b.i escapes to heap"
 	b.ii = buf
 }
 
 func foo21() func() int {
-	x := 42
-	return func() int { // ERROR "func literal escapes to heap$"
-		return x
-	}
-}
-
-func foo21a() func() int {
-	x := 42             // ERROR "moved to heap: x$"
-	return func() int { // ERROR "func literal escapes to heap$"
-		x++ // ERROR "&x escapes to heap$"
-		return x
+	x := 42             // ERROR "moved to heap: x"
+	return func() int { // ERROR "func literal escapes to heap"
+		return x // ERROR "&x escapes to heap"
 	}
 }
 
 func foo22() int {
 	x := 42
-	return func() int { // ERROR "foo22 func literal does not escape$"
+	return func() int { // ERROR "func literal does not escape"
 		return x
 	}()
 }
 
-func foo23(x int) func() int {
-	return func() int { // ERROR "func literal escapes to heap$"
-		return x
+func foo23(x int) func() int { // ERROR "moved to heap: x"
+	return func() int { // ERROR "func literal escapes to heap"
+		return x // ERROR "&x escapes to heap"
 	}
 }
 
-func foo23a(x int) func() int {
-	f := func() int { // ERROR "func literal escapes to heap$"
-		return x
+func foo23a(x int) func() int { // ERROR "moved to heap: x"
+	f := func() int { // ERROR "func literal escapes to heap"
+		return x // ERROR "&x escapes to heap"
 	}
 	return f
 }
 
-func foo23b(x int) *(func() int) {
-	f := func() int { return x } // ERROR "func literal escapes to heap$" "moved to heap: f$"
-	return &f                    // ERROR "&f escapes to heap$"
-}
-
-func foo23c(x int) func() int { // ERROR "moved to heap: x$"
-	return func() int { // ERROR "func literal escapes to heap$"
-		x++ // ERROR "&x escapes to heap$"
-		return x
-	}
+func foo23b(x int) *(func() int) { // ERROR "moved to heap: x"
+	f := func() int { return x } // ERROR "moved to heap: f" "func literal escapes to heap" "&x escapes to heap"
+	return &f                    // ERROR "&f escapes to heap"
 }
 
 func foo24(x int) int {
-	return func() int { // ERROR "foo24 func literal does not escape$"
+	return func() int { // ERROR "func literal does not escape"
 		return x
 	}()
 }
 
 var x *int
 
-func fooleak(xx *int) int { // ERROR "leaking param: xx$"
+func fooleak(xx *int) int { // ERROR "leaking param: xx"
 	x = xx
 	return *x
 }
 
-func foonoleak(xx *int) int { // ERROR "foonoleak xx does not escape$"
+func foonoleak(xx *int) int { // ERROR "xx does not escape"
 	return *x + *xx
 }
 
-func foo31(x int) int { // ERROR "moved to heap: x$"
-	return fooleak(&x) // ERROR "&x escapes to heap$"
+func foo31(x int) int { // ERROR "moved to heap: x"
+	return fooleak(&x) // ERROR "&x escapes to heap"
 }
 
 func foo32(x int) int {
-	return foonoleak(&x) // ERROR "foo32 &x does not escape$"
+	return foonoleak(&x) // ERROR "&x does not escape"
 }
 
 type Foo struct {
@@ -282,114 +267,114 @@ type Foo struct {
 var F Foo
 var pf *Foo
 
-func (f *Foo) fooleak() { // ERROR "leaking param: f$"
+func (f *Foo) fooleak() { // ERROR "leaking param: f"
 	pf = f
 }
 
-func (f *Foo) foonoleak() { // ERROR "\(\*Foo\).foonoleak f does not escape$"
+func (f *Foo) foonoleak() { // ERROR "f does not escape"
 	F.x = f.x
 }
 
-func (f *Foo) Leak() { // ERROR "leaking param: f$"
+func (f *Foo) Leak() { // ERROR "leaking param: f"
 	f.fooleak()
 }
 
-func (f *Foo) NoLeak() { // ERROR "\(\*Foo\).NoLeak f does not escape$"
+func (f *Foo) NoLeak() { // ERROR "f does not escape"
 	f.foonoleak()
 }
 
-func foo41(x int) { // ERROR "moved to heap: x$"
-	F.xx = &x // ERROR "&x escapes to heap$"
+func foo41(x int) { // ERROR "moved to heap: x"
+	F.xx = &x // ERROR "&x escapes to heap"
 }
 
-func (f *Foo) foo42(x int) { // ERROR "\(\*Foo\).foo42 f does not escape$" "moved to heap: x$"
-	f.xx = &x // ERROR "&x escapes to heap$"
+func (f *Foo) foo42(x int) { // ERROR "f does not escape" "moved to heap: x"
+	f.xx = &x // ERROR "&x escapes to heap"
 }
 
-func foo43(f *Foo, x int) { // ERROR "foo43 f does not escape$" "moved to heap: x$"
-	f.xx = &x // ERROR "&x escapes to heap$"
+func foo43(f *Foo, x int) { // ERROR "f does not escape" "moved to heap: x"
+	f.xx = &x // ERROR "&x escapes to heap"
 }
 
-func foo44(yy *int) { // ERROR "leaking param: yy$"
+func foo44(yy *int) { // ERROR "leaking param: yy"
 	F.xx = yy
 }
 
-func (f *Foo) foo45() { // ERROR "\(\*Foo\).foo45 f does not escape$"
+func (f *Foo) foo45() { // ERROR "f does not escape"
 	F.x = f.x
 }
 
 // See foo13 above for explanation of why f leaks.
-func (f *Foo) foo46() { // ERROR "leaking param content: f$"
+func (f *Foo) foo46() { // ERROR "leaking param: f"
 	F.xx = f.xx
 }
 
-func (f *Foo) foo47() { // ERROR "leaking param: f$"
-	f.xx = &f.x // ERROR "&f.x escapes to heap$"
+func (f *Foo) foo47() { // ERROR "leaking param: f"
+	f.xx = &f.x // ERROR "&f.x escapes to heap"
 }
 
 var ptrSlice []*int
 
-func foo50(i *int) { // ERROR "leaking param: i$"
+func foo50(i *int) { // ERROR "leaking param: i"
 	ptrSlice[0] = i
 }
 
 var ptrMap map[*int]*int
 
-func foo51(i *int) { // ERROR "leaking param: i$"
+func foo51(i *int) { // ERROR "leaking param: i"
 	ptrMap[i] = i
 }
 
-func indaddr1(x int) *int { // ERROR "moved to heap: x$"
-	return &x // ERROR "&x escapes to heap$"
+func indaddr1(x int) *int { // ERROR "moved to heap: x"
+	return &x // ERROR "&x escapes to heap"
 }
 
-func indaddr2(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$"
-	return *&x // ERROR "indaddr2 &x does not escape$"
+func indaddr2(x *int) *int { // ERROR "leaking param: x"
+	return *&x // ERROR "&x does not escape"
 }
 
-func indaddr3(x *int32) *int { // ERROR "leaking param: x to result ~r1 level=0$"
-	return *(**int)(unsafe.Pointer(&x)) // ERROR "indaddr3 &x does not escape$"
+func indaddr3(x *int32) *int { // ERROR "leaking param: x"
+	return *(**int)(unsafe.Pointer(&x)) // ERROR "&x does not escape"
 }
 
 // From package math:
 
 func Float32bits(f float32) uint32 {
-	return *(*uint32)(unsafe.Pointer(&f)) // ERROR "Float32bits &f does not escape$"
+	return *(*uint32)(unsafe.Pointer(&f)) // ERROR "&f does not escape"
 }
 
 func Float32frombits(b uint32) float32 {
-	return *(*float32)(unsafe.Pointer(&b)) // ERROR "Float32frombits &b does not escape$"
+	return *(*float32)(unsafe.Pointer(&b)) // ERROR "&b does not escape"
 }
 
 func Float64bits(f float64) uint64 {
-	return *(*uint64)(unsafe.Pointer(&f)) // ERROR "Float64bits &f does not escape$"
+	return *(*uint64)(unsafe.Pointer(&f)) // ERROR "&f does not escape"
 }
 
 func Float64frombits(b uint64) float64 {
-	return *(*float64)(unsafe.Pointer(&b)) // ERROR "Float64frombits &b does not escape$"
+	return *(*float64)(unsafe.Pointer(&b)) // ERROR "&b does not escape"
 }
 
 // contrast with
-func float64bitsptr(f float64) *uint64 { // ERROR "moved to heap: f$"
-	return (*uint64)(unsafe.Pointer(&f)) // ERROR "&f escapes to heap$"
+func float64bitsptr(f float64) *uint64 { // ERROR "moved to heap: f"
+	return (*uint64)(unsafe.Pointer(&f)) // ERROR "&f escapes to heap"
 }
 
-func float64ptrbitsptr(f *float64) *uint64 { // ERROR "leaking param: f to result ~r1 level=0$"
+func float64ptrbitsptr(f *float64) *uint64 { // ERROR "leaking param: f"
 	return (*uint64)(unsafe.Pointer(f))
 }
 
-func typesw(i interface{}) *int { // ERROR "leaking param: i to result ~r1 level=0$"
+func typesw(i interface{}) *int { // ERROR "leaking param: i"
 	switch val := i.(type) {
 	case *int:
 		return val
 	case *int8:
-		v := int(*val) // ERROR "moved to heap: v$"
-		return &v      // ERROR "&v escapes to heap$"
+		v := int(*val) // ERROR "moved to heap: v"
+		return &v      // ERROR "&v escapes to heap"
 	}
 	return nil
 }
 
-func exprsw(i *int) *int { // ERROR "leaking param: i to result ~r1 level=0$"
+func exprsw(i *int) *int { // ERROR "leaking param: i"
 	switch j := i; *j + 110 {
 	case 12:
 		return j
@@ -401,20 +386,20 @@ func exprsw(i *int) *int { // ERROR "leaking param: i to result ~r1 level=0$"
 }
 
 // assigning to an array element is like assigning to the array
-func foo60(i *int) *int { // ERROR "leaking param: i to result ~r1 level=0$"
+func foo60(i *int) *int { // ERROR "leaking param: i"
 	var a [12]*int
 	a[0] = i
 	return a[1]
 }
 
-func foo60a(i *int) *int { // ERROR "foo60a i does not escape$"
+func foo60a(i *int) *int { // ERROR "i does not escape"
 	var a [12]*int
 	a[0] = i
 	return nil
 }
 
 // assigning to a struct field  is like assigning to the struct
-func foo61(i *int) *int { // ERROR "leaking param: i to result ~r1 level=0$"
+func foo61(i *int) *int { // ERROR "leaking param: i"
 	type S struct {
 		a, b *int
 	}
@@ -423,7 +408,7 @@ func foo61(i *int) *int { // ERROR "leaking param: i to result ~r1 level=0$"
 	return s.b
 }
 
-func foo61a(i *int) *int { // ERROR "foo61a i does not escape$"
+func foo61a(i *int) *int { // ERROR "i does not escape"
 	type S struct {
 		a, b *int
 	}
@@ -435,11 +420,11 @@ func foo61a(i *int) *int { // ERROR "foo61a i does not escape$"
 // assigning to a struct field is like assigning to the struct but
 // here this subtlety is lost, since s.a counts as an assignment to a
 // track-losing dereference.
-func foo62(i *int) *int { // ERROR "leaking param: i$"
+func foo62(i *int) *int { // ERROR "leaking param: i"
 	type S struct {
 		a, b *int
 	}
-	s := new(S) // ERROR "foo62 new\(S\) does not escape$"
+	s := new(S) // ERROR "new[(]S[)] does not escape"
 	s.a = i
 	return nil // s.b
 }
@@ -448,14 +433,14 @@ type M interface {
 	M()
 }
 
-func foo63(m M) { // ERROR "foo63 m does not escape$"
+func foo63(m M) { // ERROR "m does not escape"
 }
 
-func foo64(m M) { // ERROR "leaking param: m$"
+func foo64(m M) { // ERROR "leaking param: m"
 	m.M()
 }
 
-func foo64b(m M) { // ERROR "leaking param: m$"
+func foo64b(m M) { // ERROR "leaking param: m"
 	defer m.M()
 }
 
@@ -465,56 +450,55 @@ func (MV) M() {}
 
 func foo65() {
 	var mv MV
-	foo63(&mv) // ERROR "foo65 &mv does not escape$"
+	foo63(&mv) // ERROR "&mv does not escape"
 }
 
 func foo66() {
-	var mv MV  // ERROR "moved to heap: mv$"
-	foo64(&mv) // ERROR "&mv escapes to heap$"
+	var mv MV  // ERROR "moved to heap: mv"
+	foo64(&mv) // ERROR "&mv escapes to heap"
 }
 
 func foo67() {
 	var mv MV
-	foo63(mv) // ERROR "foo67 mv does not escape$"
+	foo63(mv)
 }
 
 func foo68() {
 	var mv MV
-	// escapes but it's an int so irrelevant
-	foo64(mv) // ERROR "mv escapes to heap$"
+	foo64(mv) // escapes but it's an int so irrelevant
 }
 
-func foo69(m M) { // ERROR "leaking param: m$"
+func foo69(m M) { // ERROR "leaking param: m"
 	foo64(m)
 }
 
-func foo70(mv1 *MV, m M) { // ERROR "leaking param: m$" "leaking param: mv1$"
-	m = mv1 // ERROR "mv1 escapes to heap$"
+func foo70(mv1 *MV, m M) { // ERROR "leaking param: mv1" "leaking param: m"
+	m = mv1
 	foo64(m)
 }
 
-func foo71(x *int) []*int { // ERROR "leaking param: x$"
+func foo71(x *int) []*int { // ERROR "leaking param: x"
 	var y []*int
 	y = append(y, x)
 	return y
 }
 
-func foo71a(x int) []*int { // ERROR "moved to heap: x$"
+func foo71a(x int) []*int { // ERROR "moved to heap: x"
 	var y []*int
-	y = append(y, &x) // ERROR "&x escapes to heap$"
+	y = append(y, &x) // ERROR "&x escapes to heap"
 	return y
 }
 
 func foo72() {
 	var x int
 	var y [1]*int
-	y[0] = &x // ERROR "foo72 &x does not escape$"
+	y[0] = &x // ERROR "&x does not escape"
 }
 
 func foo72aa() [10]*int {
-	var x int // ERROR "moved to heap: x$"
+	var x int // ERROR "moved to heap: x"
 	var y [10]*int
-	y[0] = &x // ERROR "&x escapes to heap$"
+	y[0] = &x // ERROR "&x escapes to heap"
 	return y
 }
 
@@ -522,8 +506,8 @@ func foo72a() {
 	var y [10]*int
 	for i := 0; i < 10; i++ {
 		// escapes its scope
-		x := i    // ERROR "moved to heap: x$"
-		y[i] = &x // ERROR "&x escapes to heap$"
+		x := i    // ERROR "moved to heap: x"
+		y[i] = &x // ERROR "&x escapes to heap"
 	}
 	return
 }
@@ -531,56 +515,31 @@ func foo72a() {
 func foo72b() [10]*int {
 	var y [10]*int
 	for i := 0; i < 10; i++ {
-		x := i    // ERROR "moved to heap: x$"
-		y[i] = &x // ERROR "&x escapes to heap$"
+		x := i    // ERROR "moved to heap: x"
+		y[i] = &x // ERROR "&x escapes to heap"
 	}
 	return y
 }
 
 // issue 2145
 func foo73() {
-	s := []int{3, 2, 1} // ERROR "foo73 \[\]int literal does not escape$"
-	for _, v := range s {
-		vv := v
-		// actually just escapes its scope
-		defer func() { // ERROR "func literal escapes to heap$"
-			println(vv)
-		}()
-	}
-}
-
-func foo731() {
-	s := []int{3, 2, 1} // ERROR "foo731 \[\]int literal does not escape$"
+	s := []int{3, 2, 1} // ERROR "\[\]int literal does not escape"
 	for _, v := range s {
-		vv := v // ERROR "moved to heap: vv$"
+		vv := v // ERROR "moved to heap: vv"
 		// actually just escapes its scope
-		defer func() { // ERROR "func literal escapes to heap$"
-			vv = 42 // ERROR "&vv escapes to heap$"
-			println(vv)
+		defer func() { // ERROR "func literal escapes to heap"
+			println(vv) // ERROR "&vv escapes to heap"
 		}()
 	}
 }
 
 func foo74() {
-	s := []int{3, 2, 1} // ERROR "foo74 \[\]int literal does not escape$"
+	s := []int{3, 2, 1} // ERROR "\[\]int literal does not escape"
 	for _, v := range s {
-		vv := v
+		vv := v // ERROR "moved to heap: vv"
 		// actually just escapes its scope
-		fn := func() { // ERROR "func literal escapes to heap$"
-			println(vv)
-		}
-		defer fn()
-	}
-}
-
-func foo74a() {
-	s := []int{3, 2, 1} // ERROR "foo74a \[\]int literal does not escape$"
-	for _, v := range s {
-		vv := v // ERROR "moved to heap: vv$"
-		// actually just escapes its scope
-		fn := func() { // ERROR "func literal escapes to heap$"
-			vv += 1 // ERROR "&vv escapes to heap$"
-			println(vv)
+		fn := func() { // ERROR "func literal escapes to heap"
+			println(vv) // ERROR "&vv escapes to heap"
 		}
 		defer fn()
 	}
@@ -589,142 +548,110 @@ func foo74a() {
 // issue 3975
 func foo74b() {
 	var array [3]func()
-	s := []int{3, 2, 1} // ERROR "foo74b \[\]int literal does not escape$"
+	s := []int{3, 2, 1} // ERROR "\[\]int literal does not escape"
 	for i, v := range s {
-		vv := v
+		vv := v // ERROR "moved to heap: vv"
 		// actually just escapes its scope
-		array[i] = func() { // ERROR "func literal escapes to heap$"
-			println(vv)
+		array[i] = func() { // ERROR "func literal escapes to heap"
+			println(vv) // ERROR "&vv escapes to heap"
 		}
 	}
 }
 
-func foo74c() {
-	var array [3]func()
-	s := []int{3, 2, 1} // ERROR "foo74c \[\]int literal does not escape$"
-	for i, v := range s {
-		vv := v // ERROR "moved to heap: vv$"
-		// actually just escapes its scope
-		array[i] = func() { // ERROR "func literal escapes to heap$"
-			println(&vv) // ERROR "&vv escapes to heap$" "foo74c.func1 &vv does not escape$"
-		}
-	}
-}
-
-func myprint(y *int, x ...interface{}) *int { // ERROR "leaking param: y to result ~r2 level=0$" "myprint x does not escape$"
+func myprint(y *int, x ...interface{}) *int { // ERROR "x does not escape" "leaking param: y"
 	return y
 }
 
-func myprint1(y *int, x ...interface{}) *interface{} { // ERROR "leaking param: x to result ~r2 level=0$" "myprint1 y does not escape$"
-	return &x[0] // ERROR "&x\[0\] escapes to heap$"
+func myprint1(y *int, x ...interface{}) *interface{} { // ERROR "y does not escape" "leaking param: x"
+	return &x[0] // ERROR "&x.0. escapes to heap"
 }
 
-func foo75(z *int) { // ERROR "foo75 z does not escape$"
-	myprint(z, 1, 2, 3) // ERROR "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$" "foo75 ... argument does not escape$"
+func foo75(z *int) { // ERROR "z does not escape"
+	myprint(z, 1, 2, 3) // ERROR "[.][.][.] argument does not escape"
 }
 
-func foo75a(z *int) { // ERROR "foo75a z does not escape$"
-	myprint1(z, 1, 2, 3) // ERROR "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$" "foo75a ... argument does not escape$"
+func foo75a(z *int) { // ERROR "z does not escape"
+	myprint1(z, 1, 2, 3) // ERROR "[.][.][.] argument does not escape"
 }
 
-func foo75esc(z *int) { // ERROR "leaking param: z$"
-	gxx = myprint(z, 1, 2, 3) // ERROR "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$" "foo75esc ... argument does not escape$"
+func foo75esc(z *int) { // ERROR "leaking param: z"
+	gxx = myprint(z, 1, 2, 3) // ERROR "[.][.][.] argument does not escape"
 }
 
-func foo75aesc(z *int) { // ERROR "foo75aesc z does not escape$"
+func foo75aesc(z *int) { // ERROR "z does not escape"
 	var ppi **interface{}       // assignments to pointer dereferences lose track
-	*ppi = myprint1(z, 1, 2, 3) // ERROR "... argument escapes to heap$" "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$"
-}
-
-func foo75aesc1(z *int) { // ERROR "foo75aesc1 z does not escape$"
-	sink = myprint1(z, 1, 2, 3) // ERROR "... argument escapes to heap$" "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$" "myprint1\(z, 1, 2, 3\) escapes to heap$"
+	*ppi = myprint1(z, 1, 2, 3) // ERROR "[.][.][.] argument escapes to heap"
 }
 
-// BAD: z does not escape here
-func foo76(z *int) { // ERROR "leaking param: z$"
-	myprint(nil, z) // ERROR "foo76 ... argument does not escape$" "z escapes to heap$"
+func foo76(z *int) { // ERROR "leaking param: z"
+	myprint(nil, z) // ERROR "[.][.][.] argument does not escape"
 }
 
-// BAD: z does not escape here
-func foo76a(z *int) { // ERROR "leaking param: z$"
-	myprint1(nil, z) // ERROR "foo76a ... argument does not escape$" "z escapes to heap$"
+func foo76a(z *int) { // ERROR "leaking param: z"
+	myprint1(nil, z) // ERROR "[.][.][.] argument does not escape"
 }
 
 func foo76b() {
-	myprint(nil, 1, 2, 3) // ERROR "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$" "foo76b ... argument does not escape$"
+	myprint(nil, 1, 2, 3) // ERROR "[.][.][.] argument does not escape"
 }
 
 func foo76c() {
-	myprint1(nil, 1, 2, 3) // ERROR "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$" "foo76c ... argument does not escape$"
+	myprint1(nil, 1, 2, 3) // ERROR "[.][.][.] argument does not escape"
 }
 
 func foo76d() {
-	defer myprint(nil, 1, 2, 3) // ERROR "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$" "foo76d ... argument does not escape$"
+	defer myprint(nil, 1, 2, 3) // ERROR "[.][.][.] argument does not escape"
 }
 
 func foo76e() {
-	defer myprint1(nil, 1, 2, 3) // ERROR "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$" "foo76e ... argument does not escape$"
+	defer myprint1(nil, 1, 2, 3) // ERROR "[.][.][.] argument does not escape"
 }
 
 func foo76f() {
 	for {
 		// TODO: This one really only escapes its scope, but we don't distinguish yet.
-		defer myprint(nil, 1, 2, 3) // ERROR "... argument escapes to heap$" "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$"
+		defer myprint(nil, 1, 2, 3) // ERROR "[.][.][.] argument escapes to heap"
 	}
 }
 
 func foo76g() {
 	for {
-		defer myprint1(nil, 1, 2, 3) // ERROR "... argument escapes to heap$" "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$"
+		defer myprint1(nil, 1, 2, 3) // ERROR "[.][.][.] argument escapes to heap"
 	}
 }
 
-func foo77(z []interface{}) { // ERROR "foo77 z does not escape$"
+func foo77(z []interface{}) { // ERROR "z does not escape"
 	myprint(nil, z...) // z does not escape
 }
 
-func foo77a(z []interface{}) { // ERROR "foo77a z does not escape$"
+func foo77a(z []interface{}) { // ERROR "z does not escape"
 	myprint1(nil, z...)
 }
 
-func foo77b(z []interface{}) { // ERROR "leaking param: z$"
+func foo77b(z []interface{}) { // ERROR "leaking param: z"
 	var ppi **interface{}
 	*ppi = myprint1(nil, z...)
 }
 
-func foo77c(z []interface{}) { // ERROR "leaking param: z$"
-	sink = myprint1(nil, z...) // ERROR "myprint1\(nil, z...\) escapes to heap$"
+func foo78(z int) *int { // ERROR "moved to heap: z"
+	return &z // ERROR "&z escapes to heap"
 }
 
-func dotdotdot() {
-	// BAD: i should not escape here
-	i := 0           // ERROR "moved to heap: i$"
-	myprint(nil, &i) // ERROR "&i escapes to heap$" "dotdotdot ... argument does not escape$"
-
-	// BAD: j should not escape here
-	j := 0            // ERROR "moved to heap: j$"
-	myprint1(nil, &j) // ERROR "&j escapes to heap$" "dotdotdot ... argument does not escape$"
-}
-
-func foo78(z int) *int { // ERROR "moved to heap: z$"
-	return &z // ERROR "&z escapes to heap$"
-}
-
-func foo78a(z int) *int { // ERROR "moved to heap: z$"
-	y := &z   // ERROR "&z escapes to heap$"
-	x := &y   // ERROR "foo78a &y does not escape$"
+func foo78a(z int) *int { // ERROR "moved to heap: z"
+	y := &z   // ERROR "&z escapes to heap"
+	x := &y   // ERROR "&y does not escape"
 	return *x // really return y
 }
 
 func foo79() *int {
-	return new(int) // ERROR "new\(int\) escapes to heap$"
+	return new(int) // ERROR "new[(]int[)] escapes to heap"
 }
 
 func foo80() *int {
 	var z *int
 	for {
 		// Really just escapes its scope but we don't distinguish
-		z = new(int) // ERROR "new\(int\) escapes to heap$"
+		z = new(int) // ERROR "new[(]int[)] escapes to heap"
 	}
 	_ = z
 	return nil
@@ -732,24 +659,24 @@ func foo80() *int {
 
 func foo81() *int {
 	for {
-		z := new(int) // ERROR "foo81 new\(int\) does not escape$"
+		z := new(int) // ERROR "new[(]int[)] does not escape"
 		_ = z
 	}
 	return nil
 }
 
-func tee(p *int) (x, y *int) { return p, p } // ERROR "leaking param: p to result x level=0$" "leaking param: p to result y level=0$"
+func tee(p *int) (x, y *int) { return p, p } // ERROR "leaking param"
 
-func noop(x, y *int) {} // ERROR "noop x does not escape$" "noop y does not escape$"
+func noop(x, y *int) {} // ERROR "does not escape"
 
 func foo82() {
-	var x, y, z int  // ERROR "moved to heap: x$" "moved to heap: y$" "moved to heap: z$"
-	go noop(tee(&z)) // ERROR "&z escapes to heap$"
-	go noop(&x, &y)  // ERROR "&x escapes to heap$" "&y escapes to heap$"
+	var x, y, z int  // ERROR "moved to heap"
+	go noop(tee(&z)) // ERROR "&z escapes to heap"
+	go noop(&x, &y)  // ERROR "escapes to heap"
 	for {
-		var u, v, w int     // ERROR "moved to heap: u$" "moved to heap: v$" "moved to heap: w$"
-		defer noop(tee(&u)) // ERROR "&u escapes to heap$"
-		defer noop(&v, &w)  // ERROR "&v escapes to heap$" "&w escapes to heap$"
+		var u, v, w int     // ERROR "moved to heap"
+		defer noop(tee(&u)) // ERROR "&u escapes to heap"
+		defer noop(&v, &w)  // ERROR "escapes to heap"
 	}
 }
 
@@ -762,24 +689,24 @@ type LimitedFooer struct {
 	N int64
 }
 
-func LimitFooer(r Fooer, n int64) Fooer { // ERROR "leaking param: r to result ~r2 level=-1$"
-	return &LimitedFooer{r, n} // ERROR "&LimitedFooer literal escapes to heap$"
+func LimitFooer(r Fooer, n int64) Fooer { // ERROR "leaking param: r"
+	return &LimitedFooer{r, n} // ERROR "&LimitedFooer literal escapes to heap"
 }
 
-func foo90(x *int) map[*int]*int { // ERROR "leaking param: x$"
-	return map[*int]*int{nil: x} // ERROR "map\[\*int\]\*int literal escapes to heap$"
+func foo90(x *int) map[*int]*int { // ERROR "leaking param: x"
+	return map[*int]*int{nil: x} // ERROR "map\[\*int\]\*int literal escapes to heap"
 }
 
-func foo91(x *int) map[*int]*int { // ERROR "leaking param: x$"
-	return map[*int]*int{x: nil} // ERROR "map\[\*int\]\*int literal escapes to heap$"
+func foo91(x *int) map[*int]*int { // ERROR "leaking param: x"
+	return map[*int]*int{x: nil} // ERROR "map\[\*int\]\*int literal escapes to heap"
 }
 
-func foo92(x *int) [2]*int { // ERROR "leaking param: x to result ~r1 level=0$"
+func foo92(x *int) [2]*int { // ERROR "leaking param: x"
 	return [2]*int{x, nil}
 }
 
 // does not leak c
-func foo93(c chan *int) *int { // ERROR "foo93 c does not escape$"
+func foo93(c chan *int) *int { // ERROR "c does not escape"
 	for v := range c {
 		return v
 	}
@@ -787,7 +714,7 @@ func foo93(c chan *int) *int { // ERROR "foo93 c does not escape$"
 }
 
 // does not leak m
-func foo94(m map[*int]*int, b bool) *int { // ERROR "leaking param: m to result ~r2 level=1"
+func foo94(m map[*int]*int, b bool) *int { // ERROR "m does not escape"
 	for k, v := range m {
 		if b {
 			return k
@@ -798,32 +725,32 @@ func foo94(m map[*int]*int, b bool) *int { // ERROR "leaking param: m to result
 }
 
 // does leak x
-func foo95(m map[*int]*int, x *int) { // ERROR "foo95 m does not escape$" "leaking param: x$"
+func foo95(m map[*int]*int, x *int) { // ERROR "m does not escape" "leaking param: x"
 	m[x] = x
 }
 
-// does not leak m but does leak content
-func foo96(m []*int) *int { // ERROR "leaking param: m to result ~r1 level=1"
+// does not leak m
+func foo96(m []*int) *int { // ERROR "m does not escape"
 	return m[0]
 }
 
 // does leak m
-func foo97(m [1]*int) *int { // ERROR "leaking param: m to result ~r1 level=0$"
+func foo97(m [1]*int) *int { // ERROR "leaking param: m"
 	return m[0]
 }
 
 // does not leak m
-func foo98(m map[int]*int) *int { // ERROR "foo98 m does not escape$"
+func foo98(m map[int]*int) *int { // ERROR "m does not escape"
 	return m[0]
 }
 
 // does leak m
-func foo99(m *[1]*int) []*int { // ERROR "leaking param: m to result ~r1 level=0$"
+func foo99(m *[1]*int) []*int { // ERROR "leaking param: m"
 	return m[:]
 }
 
 // does not leak m
-func foo100(m []*int) *int { // ERROR "leaking param: m to result ~r1 level=1"
+func foo100(m []*int) *int { // ERROR "m does not escape"
 	for _, v := range m {
 		return v
 	}
@@ -831,7 +758,7 @@ func foo100(m []*int) *int { // ERROR "leaking param: m to result ~r1 level=1"
 }
 
 // does leak m
-func foo101(m [1]*int) *int { // ERROR "leaking param: m to result ~r1 level=0$"
+func foo101(m [1]*int) *int { // ERROR "leaking param: m"
 	for _, v := range m {
 		return v
 	}
@@ -839,109 +766,109 @@ func foo101(m [1]*int) *int { // ERROR "leaking param: m to result ~r1 level=0$"
 }
 
 // does not leak m
-func foo101a(m [1]*int) *int { // ERROR "foo101a m does not escape$"
-	for i := range m { // ERROR "moved to heap: i$"
-		return &i // ERROR "&i escapes to heap$"
+func foo101a(m [1]*int) *int { // ERROR "m does not escape"
+	for i := range m { // ERROR "moved to heap: i"
+		return &i // ERROR "&i escapes to heap"
 	}
 	return nil
 }
 
 // does leak x
-func foo102(m []*int, x *int) { // ERROR "foo102 m does not escape$" "leaking param: x$"
+func foo102(m []*int, x *int) { // ERROR "m does not escape" "leaking param: x"
 	m[0] = x
 }
 
 // does not leak x
-func foo103(m [1]*int, x *int) { // ERROR "foo103 m does not escape$" "foo103 x does not escape$"
+func foo103(m [1]*int, x *int) { // ERROR "m does not escape" "x does not escape"
 	m[0] = x
 }
 
 var y []*int
 
-// does not leak x but does leak content
-func foo104(x []*int) { // ERROR "leaking param content: x"
+// does not leak x
+func foo104(x []*int) { // ERROR "x does not escape"
 	copy(y, x)
 }
 
-// does not leak x but does leak content
-func foo105(x []*int) { // ERROR "leaking param content: x"
+// does not leak x
+func foo105(x []*int) { // ERROR "x does not escape"
 	_ = append(y, x...)
 }
 
 // does leak x
-func foo106(x *int) { // ERROR "leaking param: x$"
+func foo106(x *int) { // ERROR "leaking param: x"
 	_ = append(y, x)
 }
 
-func foo107(x *int) map[*int]*int { // ERROR "leaking param: x$"
-	return map[*int]*int{x: nil} // ERROR "map\[\*int\]\*int literal escapes to heap$"
+func foo107(x *int) map[*int]*int { // ERROR "leaking param: x"
+	return map[*int]*int{x: nil} // ERROR "map.* literal escapes to heap"
 }
 
-func foo108(x *int) map[*int]*int { // ERROR "leaking param: x$"
-	return map[*int]*int{nil: x} // ERROR "map\[\*int\]\*int literal escapes to heap$"
+func foo108(x *int) map[*int]*int { // ERROR "leaking param: x"
+	return map[*int]*int{nil: x} // ERROR "map.* literal escapes to heap"
 }
 
-func foo109(x *int) *int { // ERROR "leaking param: x$"
-	m := map[*int]*int{x: nil} // ERROR "foo109 map\[\*int\]\*int literal does not escape$"
+func foo109(x *int) *int { // ERROR "leaking param: x"
+	m := map[*int]*int{x: nil} // ERROR "map.* literal does not escape"
 	for k, _ := range m {
 		return k
 	}
 	return nil
 }
 
-func foo110(x *int) *int { // ERROR "leaking param: x$"
-	m := map[*int]*int{nil: x} // ERROR "foo110 map\[\*int\]\*int literal does not escape$"
+func foo110(x *int) *int { // ERROR "leaking param: x"
+	m := map[*int]*int{nil: x} // ERROR "map.* literal does not escape"
 	return m[nil]
 }
 
-func foo111(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0"
-	m := []*int{x} // ERROR "foo111 \[\]\*int literal does not escape$"
+func foo111(x *int) *int { // ERROR "leaking param: x"
+	m := []*int{x} // ERROR "\[\]\*int literal does not escape"
 	return m[0]
 }
 
-func foo112(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$"
+func foo112(x *int) *int { // ERROR "leaking param: x"
 	m := [1]*int{x}
 	return m[0]
 }
 
-func foo113(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$"
+func foo113(x *int) *int { // ERROR "leaking param: x"
 	m := Bar{ii: x}
 	return m.ii
 }
 
-func foo114(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$"
-	m := &Bar{ii: x} // ERROR "foo114 &Bar literal does not escape$"
+func foo114(x *int) *int { // ERROR "leaking param: x"
+	m := &Bar{ii: x} // ERROR "&Bar literal does not escape"
 	return m.ii
 }
 
-func foo115(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$"
+func foo115(x *int) *int { // ERROR "leaking param: x"
 	return (*int)(unsafe.Pointer(uintptr(unsafe.Pointer(x)) + 1))
 }
 
 func foo116(b bool) *int {
 	if b {
-		x := 1    // ERROR "moved to heap: x$"
-		return &x // ERROR "&x escapes to heap$"
+		x := 1    // ERROR "moved to heap: x"
+		return &x // ERROR "&x escapes to heap"
 	} else {
-		y := 1    // ERROR "moved to heap: y$"
-		return &y // ERROR "&y escapes to heap$"
+		y := 1    // ERROR "moved to heap: y"
+		return &y // ERROR "&y escapes to heap"
 	}
 	return nil
 }
 
-func foo117(unknown func(interface{})) { // ERROR "foo117 unknown does not escape$"
-	x := 1      // ERROR "moved to heap: x$"
-	unknown(&x) // ERROR "&x escapes to heap$"
+func foo117(unknown func(interface{})) { // ERROR "unknown does not escape"
+	x := 1      // ERROR "moved to heap: x"
+	unknown(&x) // ERROR "&x escapes to heap"
 }
 
-func foo118(unknown func(*int)) { // ERROR "foo118 unknown does not escape$"
-	x := 1      // ERROR "moved to heap: x$"
-	unknown(&x) // ERROR "&x escapes to heap$"
+func foo118(unknown func(*int)) { // ERROR "unknown does not escape"
+	x := 1      // ERROR "moved to heap: x"
+	unknown(&x) // ERROR "&x escapes to heap"
 }
 
 func external(*int)
 
-func foo119(x *int) { // ERROR "leaking param: x$"
+func foo119(x *int) { // ERROR "leaking param: x"
 	external(x)
 }
 
@@ -1152,16 +1079,16 @@ L100:
 
 func foo121() {
 	for i := 0; i < 10; i++ {
-		defer myprint(nil, i) // ERROR "... argument escapes to heap$" "i escapes to heap$"
-		go myprint(nil, i)    // ERROR "... argument escapes to heap$" "i escapes to heap$"
+		defer myprint(nil, i) // ERROR "[.][.][.] argument escapes to heap"
+		go myprint(nil, i)    // ERROR "[.][.][.] argument escapes to heap"
 	}
 }
 
 // same as foo121 but check across import
 func foo121b() {
 	for i := 0; i < 10; i++ {
-		defer fmt.Printf("%d", i) // ERROR "... argument escapes to heap$" "i escapes to heap$"
-		go fmt.Printf("%d", i)    // ERROR "... argument escapes to heap$" "i escapes to heap$"
+		defer fmt.Printf("%d", i) // ERROR "[.][.][.] argument escapes to heap"
+		go fmt.Printf("%d", i)    // ERROR "[.][.][.] argument escapes to heap"
 	}
 }
 
@@ -1171,7 +1098,7 @@ func foo122() {
 
 	goto L1
 L1:
-	i = new(int) // ERROR "foo122 new\(int\) does not escape$"
+	i = new(int) // ERROR "new.int. does not escape"
 	_ = i
 }
 
@@ -1180,25 +1107,25 @@ func foo123() {
 	var i *int
 
 L1:
-	i = new(int) // ERROR "new\(int\) escapes to heap$"
+	i = new(int) // ERROR "new.int. escapes to heap"
 
 	goto L1
 	_ = i
 }
 
-func foo124(x **int) { // ERROR "foo124 x does not escape$"
-	var i int // ERROR "moved to heap: i$"
-	p := &i   // ERROR "&i escapes to heap$"
-	func() {  // ERROR "foo124 func literal does not escape$"
-		*x = p // ERROR "leaking closure reference p$"
+func foo124(x **int) { // ERROR "x does not escape"
+	var i int // ERROR "moved to heap: i"
+	p := &i   // ERROR "&i escapes"
+	func() {  // ERROR "func literal does not escape"
+		*x = p // ERROR "leaking closure reference p"
 	}()
 }
 
-func foo125(ch chan *int) { // ERROR "foo125 ch does not escape$"
-	var i int // ERROR "moved to heap: i$"
-	p := &i   // ERROR "&i escapes to heap$"
-	func() {  // ERROR "foo125 func literal does not escape$"
-		ch <- p // ERROR "leaking closure reference p$"
+func foo125(ch chan *int) { // ERROR "does not escape"
+	var i int // ERROR "moved to heap"
+	p := &i   // ERROR "&i escapes to heap"
+	func() {  // ERROR "func literal does not escape"
+		ch <- p // ERROR "leaking closure reference p"
 	}()
 }
 
@@ -1206,9 +1133,9 @@ func foo126() {
 	var px *int // loopdepth 0
 	for {
 		// loopdepth 1
-		var i int // ERROR "moved to heap: i$"
-		func() {  // ERROR "foo126 func literal does not escape$"
-			px = &i // ERROR "&i escapes to heap$"
+		var i int // ERROR "moved to heap"
+		func() {  // ERROR "func literal does not escape"
+			px = &i // ERROR "&i escapes"
 		}()
 	}
 	_ = px
@@ -1217,26 +1144,26 @@ func foo126() {
 var px *int
 
 func foo127() {
-	var i int // ERROR "moved to heap: i$"
-	p := &i   // ERROR "&i escapes to heap$"
+	var i int // ERROR "moved to heap: i"
+	p := &i   // ERROR "&i escapes to heap"
 	q := p
 	px = q
 }
 
 func foo128() {
 	var i int
-	p := &i // ERROR "foo128 &i does not escape$"
+	p := &i // ERROR "&i does not escape"
 	q := p
 	_ = q
 }
 
 func foo129() {
-	var i int // ERROR "moved to heap: i$"
-	p := &i   // ERROR "&i escapes to heap$"
-	func() {  // ERROR "foo129 func literal does not escape$"
-		q := p   // ERROR "leaking closure reference p$"
-		func() { // ERROR "foo129.func1 func literal does not escape$"
-			r := q // ERROR "leaking closure reference q$"
+	var i int // ERROR "moved to heap: i"
+	p := &i   // ERROR "&i escapes to heap"
+	func() {  // ERROR "func literal does not escape"
+		q := p   // ERROR "leaking closure reference p"
+		func() { // ERROR "func literal does not escape"
+			r := q // ERROR "leaking closure reference q"
 			px = r
 		}()
 	}()
@@ -1244,40 +1171,40 @@ func foo129() {
 
 func foo130() {
 	for {
-		var i int // ERROR "moved to heap: i$"
-		func() {  // ERROR "foo130 func literal does not escape$"
-			px = &i // ERROR "&i escapes to heap$" "leaking closure reference i$"
+		var i int // ERROR "moved to heap"
+		func() {  // ERROR "func literal does not escape"
+			px = &i // ERROR "&i escapes" "leaking closure reference i"
 		}()
 	}
 }
 
 func foo131() {
-	var i int // ERROR "moved to heap: i$"
-	func() {  // ERROR "foo131 func literal does not escape$"
-		px = &i // ERROR "&i escapes to heap$" "leaking closure reference i$"
+	var i int // ERROR "moved to heap"
+	func() {  // ERROR "func literal does not escape"
+		px = &i // ERROR "&i escapes" "leaking closure reference i"
 	}()
 }
 
 func foo132() {
-	var i int   // ERROR "moved to heap: i$"
-	go func() { // ERROR "func literal escapes to heap$"
-		px = &i // ERROR "&i escapes to heap$" "leaking closure reference i$"
+	var i int   // ERROR "moved to heap"
+	go func() { // ERROR "func literal escapes to heap"
+		px = &i // ERROR "&i escapes" "leaking closure reference i"
 	}()
 }
 
 func foo133() {
-	var i int      // ERROR "moved to heap: i$"
-	defer func() { // ERROR "foo133 func literal does not escape$"
-		px = &i // ERROR "&i escapes to heap$" "leaking closure reference i$"
+	var i int      // ERROR "moved to heap"
+	defer func() { // ERROR "func literal does not escape"
+		px = &i // ERROR "&i escapes" "leaking closure reference i"
 	}()
 }
 
 func foo134() {
 	var i int
-	p := &i  // ERROR "foo134 &i does not escape$"
-	func() { // ERROR "foo134 func literal does not escape$"
+	p := &i  // ERROR "&i does not escape"
+	func() { // ERROR "func literal does not escape"
 		q := p
-		func() { // ERROR "foo134.func1 func literal does not escape$"
+		func() { // ERROR "func literal does not escape"
 			r := q
 			_ = r
 		}()
@@ -1285,11 +1212,11 @@ func foo134() {
 }
 
 func foo135() {
-	var i int   // ERROR "moved to heap: i$"
-	p := &i     // ERROR "&i escapes to heap$"
-	go func() { // ERROR "func literal escapes to heap$"
-		q := p
-		func() { // ERROR "foo135.func1 func literal does not escape$"
+	var i int   // ERROR "moved to heap: i"
+	p := &i     // ERROR "&i escapes to heap" "moved to heap: p"
+	go func() { // ERROR "func literal escapes to heap"
+		q := p   // ERROR "&p escapes to heap"
+		func() { // ERROR "func literal does not escape"
 			r := q
 			_ = r
 		}()
@@ -1297,24 +1224,24 @@ func foo135() {
 }
 
 func foo136() {
-	var i int   // ERROR "moved to heap: i$"
-	p := &i     // ERROR "&i escapes to heap$"
-	go func() { // ERROR "func literal escapes to heap$"
-		q := p   // ERROR "leaking closure reference p$"
-		func() { // ERROR "foo136.func1 func literal does not escape$"
-			r := q // ERROR "leaking closure reference q$"
+	var i int   // ERROR "moved to heap: i"
+	p := &i     // ERROR "&i escapes to heap" "moved to heap: p"
+	go func() { // ERROR "func literal escapes to heap"
+		q := p   // ERROR "&p escapes to heap" "leaking closure reference p"
+		func() { // ERROR "func literal does not escape"
+			r := q // ERROR "leaking closure reference q"
 			px = r
 		}()
 	}()
 }
 
 func foo137() {
-	var i int // ERROR "moved to heap: i$"
-	p := &i   // ERROR "&i escapes to heap$"
-	func() {  // ERROR "foo137 func literal does not escape$"
-		q := p      // ERROR "leaking closure reference p$"
-		go func() { // ERROR "func literal escapes to heap$"
-			r := q
+	var i int // ERROR "moved to heap: i"
+	p := &i   // ERROR "&i escapes to heap"
+	func() {  // ERROR "func literal does not escape"
+		q := p      // ERROR "leaking closure reference p" "moved to heap: q"
+		go func() { // ERROR "func literal escapes to heap"
+			r := q // ERROR "&q escapes to heap"
 			_ = r
 		}()
 	}()
@@ -1324,8 +1251,8 @@ func foo138() *byte {
 	type T struct {
 		x [1]byte
 	}
-	t := new(T)    // ERROR "new\(T\) escapes to heap$"
-	return &t.x[0] // ERROR "&t.x\[0\] escapes to heap$"
+	t := new(T)    // ERROR "new.T. escapes to heap"
+	return &t.x[0] // ERROR "&t.x.0. escapes to heap"
 }
 
 func foo139() *byte {
@@ -1334,8 +1261,8 @@ func foo139() *byte {
 			y byte
 		}
 	}
-	t := new(T)   // ERROR "new\(T\) escapes to heap$"
-	return &t.x.y // ERROR "&t.x.y escapes to heap$"
+	t := new(T)   // ERROR "new.T. escapes to heap"
+	return &t.x.y // ERROR "&t.x.y escapes to heap"
 }
 
 // issue 4751
@@ -1347,8 +1274,8 @@ func foo140() interface{} {
 		X string
 		T *T
 	}
-	t := &T{} // ERROR "&T literal escapes to heap$"
-	return U{ // ERROR "U literal escapes to heap$"
+	t := &T{} // ERROR "&T literal escapes to heap"
+	return U{
 		X: t.X,
 		T: t,
 	}
@@ -1362,53 +1289,53 @@ func F2([]byte)
 
 //go:noescape
 
-func F3(x []byte) // ERROR "F3 x does not escape$"
+func F3(x []byte) // ERROR "F3 x does not escape"
 
 func F4(x []byte)
 
 func G() {
 	var buf1 [10]byte
-	F1(buf1[:]) // ERROR "G buf1 does not escape$"
+	F1(buf1[:]) // ERROR "buf1 does not escape"
 
-	var buf2 [10]byte // ERROR "moved to heap: buf2$"
-	F2(buf2[:])       // ERROR "buf2 escapes to heap$"
+	var buf2 [10]byte // ERROR "moved to heap: buf2"
+	F2(buf2[:])       // ERROR "buf2 escapes to heap"
 
 	var buf3 [10]byte
-	F3(buf3[:]) // ERROR "G buf3 does not escape$"
+	F3(buf3[:]) // ERROR "buf3 does not escape"
 
-	var buf4 [10]byte // ERROR "moved to heap: buf4$"
-	F4(buf4[:])       // ERROR "buf4 escapes to heap$"
+	var buf4 [10]byte // ERROR "moved to heap: buf4"
+	F4(buf4[:])       // ERROR "buf4 escapes to heap"
 }
 
 type Tm struct {
 	x int
 }
 
-func (t *Tm) M() { // ERROR "\(\*Tm\).M t does not escape$"
+func (t *Tm) M() { // ERROR "t does not escape"
 }
 
 func foo141() {
 	var f func()
 
-	t := new(Tm) // ERROR "new\(Tm\) escapes to heap$"
-	f = t.M      // ERROR "foo141 t.M does not escape$"
+	t := new(Tm) // ERROR "escapes to heap"
+	f = t.M      // ERROR "t.M does not escape"
 	_ = f
 }
 
 var gf func()
 
 func foo142() {
-	t := new(Tm) // ERROR "new\(Tm\) escapes to heap$"
-	gf = t.M     // ERROR "t.M escapes to heap$"
+	t := new(Tm) // ERROR "escapes to heap"
+	gf = t.M     // ERROR "t.M escapes to heap"
 }
 
 // issue 3888.
 func foo143() {
 	for i := 0; i < 1000; i++ {
-		func() { // ERROR "foo143 func literal does not escape$"
+		func() { // ERROR "func literal does not escape"
 			for i := 0; i < 1; i++ {
 				var t Tm
-				t.M() // ERROR "foo143.func1 t does not escape$"
+				t.M() // ERROR "t does not escape"
 			}
 		}()
 	}
@@ -1424,9 +1351,9 @@ func foo144a(*int)
 
 func foo144() {
 	var x int
-	foo144a(&x) // ERROR "foo144 &x does not escape$"
+	foo144a(&x) // ERROR "&x does not escape"
 	var y int
-	foo144b(&y) // ERROR "foo144 &y does not escape$"
+	foo144b(&y) // ERROR "&y does not escape"
 }
 
 //go:noescape
@@ -1439,38 +1366,38 @@ type List struct {
 	Next *List
 }
 
-func foo145(l List) { // ERROR "foo145 l does not escape$"
+func foo145(l List) { // ERROR "l does not escape"
 	var p *List
-	for p = &l; p.Next != nil; p = p.Next { // ERROR "foo145 &l does not escape$"
+	for p = &l; p.Next != nil; p = p.Next { // ERROR "&l does not escape"
 	}
 }
 
-func foo146(l List) { // ERROR "foo146 l does not escape$"
+func foo146(l List) { // ERROR "l does not escape"
 	var p *List
-	p = &l // ERROR "foo146 &l does not escape$"
+	p = &l // ERROR "&l does not escape"
 	for ; p.Next != nil; p = p.Next {
 	}
 }
 
-func foo147(l List) { // ERROR "foo147 l does not escape$"
+func foo147(l List) { // ERROR "l does not escape"
 	var p *List
-	p = &l // ERROR "foo147 &l does not escape$"
+	p = &l // ERROR "&l does not escape"
 	for p.Next != nil {
 		p = p.Next
 	}
 }
 
-func foo148(l List) { // ERROR "foo148 l does not escape$"
-	for p := &l; p.Next != nil; p = p.Next { // ERROR "foo148 &l does not escape$"
+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 "foo149 l does not escape$"
+func foo149(l List) { // ERROR " l does not escape"
 	var p *List
 	for {
-		for p = &l; p.Next != nil; p = p.Next { // ERROR "foo149 &l does not escape$"
+		for p = &l; p.Next != nil; p = p.Next { // ERROR "&l does not escape"
 		}
 	}
 }
@@ -1479,44 +1406,44 @@ func foo149(l List) { // ERROR "foo149 l does not escape$"
 
 var save150 []byte
 
-func foo150(x ...byte) { // ERROR "leaking param: x$"
+func foo150(x ...byte) { // ERROR "leaking param: x"
 	save150 = x
 }
 
 func bar150() {
-	foo150(1, 2, 3) // ERROR "... argument escapes to heap$"
+	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$"
+func foo151(x *int) { // ERROR "leaking param: x"
 	save151 = x
 }
 
 func bar151() {
-	var a [64]int // ERROR "moved to heap: a$"
+	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$"
+	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$"
+	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$"
+	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$"
+	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$"
+	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
@@ -1525,7 +1452,7 @@ type U struct {
 	s *string
 }
 
-func (u *U) String() *string { // ERROR "leaking param: u to result ~r0 level=1$"
+func (u *U) String() *string { // ERROR "leaking param u content to result ~r0"
 	return u.s
 }
 
@@ -1533,298 +1460,35 @@ type V struct {
 	s *string
 }
 
-// BAD -- level of leak ought to be 0
-func NewV(u U) *V { // ERROR "leaking param: u to result ~r1 level=-1"
-	return &V{u.String()} // ERROR "&V literal escapes to heap$" "NewV u does not escape"
+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$"
+	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 to result ~r1 level=-1$"
+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$"
+	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$"
+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$"
+func g() (x interface{}) { // ERROR "moved to heap: x"
+	x = &x // ERROR "&x escapes to heap"
 	return
 }
-
-var sink interface{}
-
-type Lit struct {
-	p *int
-}
-
-func ptrlitNoescape() {
-	// Both literal and element do not escape.
-	i := 0
-	x := &Lit{&i} // ERROR "ptrlitNoescape &Lit literal does not escape$" "ptrlitNoescape &i does not escape$"
-	_ = x
-}
-
-func ptrlitNoEscape2() {
-	// Literal does not escape, but element does.
-	i := 0        // ERROR "moved to heap: i$"
-	x := &Lit{&i} // ERROR "&i escapes to heap$" "ptrlitNoEscape2 &Lit literal does not escape$"
-	sink = *x     // ERROR "\*x escapes to heap$"
-}
-
-func ptrlitEscape() {
-	// Both literal and element escape.
-	i := 0        // ERROR "moved to heap: i$"
-	x := &Lit{&i} // ERROR "&Lit literal escapes to heap$" "&i escapes to heap$"
-	sink = x      // ERROR "x escapes to heap$"
-}
-
-// self-assignments
-
-type Buffer struct {
-	arr  [64]byte
-	buf1 []byte
-	buf2 []byte
-	str1 string
-	str2 string
-}
-
-func (b *Buffer) foo() { // ERROR "\(\*Buffer\).foo b does not escape$"
-	b.buf1 = b.buf1[1:2]   // ERROR "\(\*Buffer\).foo ignoring self-assignment to b.buf1$"
-	b.buf1 = b.buf1[1:2:3] // ERROR "\(\*Buffer\).foo ignoring self-assignment to b.buf1$"
-	b.buf1 = b.buf2[1:2]   // ERROR "\(\*Buffer\).foo ignoring self-assignment to b.buf1$"
-	b.buf1 = b.buf2[1:2:3] // ERROR "\(\*Buffer\).foo ignoring self-assignment to b.buf1$"
-}
-
-func (b *Buffer) bar() { // ERROR "leaking param: b$"
-	b.buf1 = b.arr[1:2] // ERROR "b.arr escapes to heap$"
-}
-
-func (b *Buffer) baz() { // ERROR "\(\*Buffer\).baz b does not escape$"
-	b.str1 = b.str1[1:2] // ERROR "\(\*Buffer\).baz ignoring self-assignment to b.str1$"
-	b.str1 = b.str2[1:2] // ERROR "\(\*Buffer\).baz ignoring self-assignment to b.str1$"
-}
-
-func (b *Buffer) bat() { // ERROR "leaking param content: b$"
-	o := new(Buffer) // ERROR "new\(Buffer\) escapes to heap$"
-	o.buf1 = b.buf1[1:2]
-	sink = o // ERROR "o escapes to heap$"
-}
-
-func quux(sp *string, bp *[]byte) { // ERROR "quux bp does not escape$" "quux sp does not escape$"
-	*sp = (*sp)[1:2] // ERROR "quux ignoring self-assignment to \*sp$"
-	*bp = (*bp)[1:2] // ERROR "quux ignoring self-assignment to \*bp$"
-}
-
-type StructWithString struct {
-	p *int
-	s string
-}
-
-// This is escape analysis false negative.
-// We assign the pointer to x.p but leak x.s. Escape analysis coarsens flows
-// to just x, and thus &i looks escaping.
-func fieldFlowTracking() {
-	var x StructWithString
-	i := 0     // ERROR "moved to heap: i$"
-	x.p = &i   // ERROR "&i escapes to heap$"
-	sink = x.s // ERROR "x.s escapes to heap$"
-}
-
-// String operations.
-
-func slicebytetostring0() {
-	b := make([]byte, 20) // ERROR "slicebytetostring0 make\(\[\]byte, 20\) does not escape$"
-	s := string(b)        // ERROR "slicebytetostring0 string\(b\) does not escape$"
-	_ = s
-}
-
-func slicebytetostring1() {
-	b := make([]byte, 20) // ERROR "slicebytetostring1 make\(\[\]byte, 20\) does not escape$"
-	s := string(b)        // ERROR "slicebytetostring1 string\(b\) does not escape$"
-	s1 := s[0:1]
-	_ = s1
-}
-
-func slicebytetostring2() {
-	b := make([]byte, 20) // ERROR "slicebytetostring2 make\(\[\]byte, 20\) does not escape$"
-	s := string(b)        // ERROR "string\(b\) escapes to heap$"
-	s1 := s[0:1]          // ERROR "moved to heap: s1$"
-	sink = &s1            // ERROR "&s1 escapes to heap$"
-}
-
-func slicebytetostring3() {
-	b := make([]byte, 20) // ERROR "slicebytetostring3 make\(\[\]byte, 20\) does not escape$"
-	s := string(b)        // ERROR "string\(b\) escapes to heap$"
-	s1 := s[0:1]
-	sink = s1 // ERROR "s1 escapes to heap$"
-}
-
-func addstr0() {
-	s0 := "a"
-	s1 := "b"
-	s := s0 + s1 // ERROR "addstr0 s0 \+ s1 does not escape$"
-	_ = s
-}
-
-func addstr1() {
-	s0 := "a"
-	s1 := "b"
-	s := "c"
-	s += s0 + s1 // ERROR "addstr1 s0 \+ s1 does not escape$"
-	_ = s
-}
-
-func addstr2() {
-	b := make([]byte, 20) // ERROR "addstr2 make\(\[\]byte, 20\) does not escape$"
-	s0 := "a"
-	s := string(b) + s0 // ERROR "addstr2 string\(b\) \+ s0 does not escape$" "addstr2 string\(b\) does not escape$"
-	_ = s
-}
-
-func addstr3() {
-	s0 := "a"
-	s1 := "b"
-	s := s0 + s1 // ERROR "s0 \+ s1 escapes to heap$"
-	s2 := s[0:1]
-	sink = s2 // ERROR "s2 escapes to heap$"
-}
-
-func intstring0() bool {
-	// string does not escape
-	x := '0'
-	s := string(x) // ERROR "intstring0 string\(x\) does not escape$"
-	return s == "0"
-}
-
-func intstring1() string {
-	// string does not escape, but the buffer does
-	x := '0'
-	s := string(x) // ERROR "string\(x\) escapes to heap$"
-	return s
-}
-
-func intstring2() {
-	// string escapes to heap
-	x := '0'
-	s := string(x) // ERROR "moved to heap: s$" "string\(x\) escapes to heap$"
-	sink = &s      // ERROR "&s escapes to heap$"
-}
-
-func stringtoslicebyte0() {
-	s := "foo"
-	x := []byte(s) // ERROR "stringtoslicebyte0 \(\[\]byte\)\(s\) does not escape$"
-	_ = x
-}
-
-func stringtoslicebyte1() []byte {
-	s := "foo"
-	return []byte(s) // ERROR "\(\[\]byte\)\(s\) escapes to heap$"
-}
-
-func stringtoslicebyte2() {
-	s := "foo"
-	sink = []byte(s) // ERROR "\(\[\]byte\)\(s\) escapes to heap$"
-}
-
-func stringtoslicerune0() {
-	s := "foo"
-	x := []rune(s) // ERROR "stringtoslicerune0 \(\[\]rune\)\(s\) does not escape$"
-	_ = x
-}
-
-func stringtoslicerune1() []rune {
-	s := "foo"
-	return []rune(s) // ERROR "\(\[\]rune\)\(s\) escapes to heap$"
-}
-
-func stringtoslicerune2() {
-	s := "foo"
-	sink = []rune(s) // ERROR "\(\[\]rune\)\(s\) escapes to heap$"
-}
-
-func slicerunetostring0() {
-	r := []rune{1, 2, 3} // ERROR "slicerunetostring0 \[\]rune literal does not escape$"
-	s := string(r)       // ERROR "slicerunetostring0 string\(r\) does not escape$"
-	_ = s
-}
-
-func slicerunetostring1() string {
-	r := []rune{1, 2, 3} // ERROR "slicerunetostring1 \[\]rune literal does not escape$"
-	return string(r)     // ERROR "string\(r\) escapes to heap$"
-}
-
-func slicerunetostring2() {
-	r := []rune{1, 2, 3} // ERROR "slicerunetostring2 \[\]rune literal does not escape$"
-	sink = string(r)     // ERROR "string\(r\) escapes to heap$"
-}
-
-func makemap0() {
-	m := make(map[int]int) // ERROR "makemap0 make\(map\[int\]int\) does not escape$"
-	m[0] = 0
-	m[1]++
-	delete(m, 1)
-	sink = m[0] // ERROR "m\[0\] escapes to heap$"
-}
-
-func makemap1() map[int]int {
-	return make(map[int]int) // ERROR "make\(map\[int\]int\) escapes to heap$"
-}
-
-func makemap2() {
-	m := make(map[int]int) // ERROR "make\(map\[int\]int\) escapes to heap$"
-	sink = m               // ERROR "m escapes to heap$"
-}
-
-func nonescapingEface(m map[interface{}]bool) bool { // ERROR "nonescapingEface m does not escape$"
-	return m["foo"] // ERROR "nonescapingEface .foo. does not escape$"
-}
-
-func nonescapingIface(m map[M]bool) bool { // ERROR "nonescapingIface m does not escape$"
-	return m[MV(0)] // ERROR "nonescapingIface MV\(0\) does not escape$"
-}
-
-func issue10353() {
-	x := new(int) // ERROR "new\(int\) escapes to heap$"
-	issue10353a(x)()
-}
-
-func issue10353a(x *int) func() { // ERROR "leaking param: x to result ~r1 level=-1$"
-	return func() { // ERROR "func literal escapes to heap$"
-		println(*x)
-	}
-}
-
-func issue10353b() {
-	var f func()
-	for {
-		x := new(int) // ERROR "new\(int\) escapes to heap$"
-		f = func() {  // ERROR "func literal escapes to heap$"
-			println(*x)
-		}
-	}
-	_ = f
-}
-
-func issue11387(x int) func() int {
-	f := func() int { return x }    // ERROR "func literal escapes to heap"
-	slice1 := []func() int{f}       // ERROR "\[\].* does not escape"
-	slice2 := make([]func() int, 1) // ERROR "make\(.*\) does not escape"
-	copy(slice2, slice1)
-	return slice2[0]
-}
diff --git a/test/escape4.go b/test/escape4.go
index 248f8a9..83bc8eb 100644
--- a/test/escape4.go
+++ b/test/escape4.go
@@ -22,11 +22,11 @@ func f1() {
 
 	// Escape analysis used to miss inlined code in closures.
 
-	func() { // ERROR "func literal does not escape" "can inline f1.func1"
+	func() { // ERROR "func literal does not escape"
 		p = alloc(3) // ERROR "inlining call to alloc" "&x escapes to heap" "moved to heap: x"
 	}()
 
-	f = func() { // ERROR "func literal escapes to heap" "can inline f1.func2"
+	f = func() { // ERROR "func literal escapes to heap"
 		p = alloc(3) // ERROR "inlining call to alloc" "&x escapes to heap" "moved to heap: x"
 	}
 	f()
@@ -42,7 +42,7 @@ func f5() *byte {
 	type T struct {
 		x [1]byte
 	}
-	t := new(T)    // ERROR "new.T. escapes to heap"
+	t := new(T) // ERROR "new.T. escapes to heap"
 	return &t.x[0] // ERROR "&t.x.0. escapes to heap"
 }
 
@@ -52,6 +52,6 @@ func f6() *byte {
 			y byte
 		}
 	}
-	t := new(T)   // ERROR "new.T. escapes to heap"
+	t := new(T) // ERROR "new.T. escapes to heap"
 	return &t.x.y // ERROR "&t.x.y escapes to heap"
 }
diff --git a/test/escape5.go b/test/escape5.go
index 6a138ea..a33daee 100644
--- a/test/escape5.go
+++ b/test/escape5.go
@@ -117,6 +117,7 @@ func leakrecursive2(p, q *int) (*int, *int) { // ERROR "leaking param: p" "leaki
 	return p, q
 }
 
+
 var global interface{}
 
 type T1 struct {
@@ -133,19 +134,18 @@ func f8(p *T1) (k T2) { // ERROR "leaking param: p to result k" "leaking param:
 		return
 	}
 
-	// should make p leak always
-	global = p // ERROR "p escapes to heap"
+	global = p // should make p leak always
 	return T2{p}
 }
 
 func f9() {
 	var j T1 // ERROR "moved to heap: j"
-	f8(&j)   // ERROR "&j escapes to heap"
+	f8(&j) // ERROR "&j escapes to heap"
 }
 
 func f10() {
 	// These don't escape but are too big for the stack
-	var x [1 << 30]byte         // ERROR "moved to heap: x"
-	var y = make([]byte, 1<<30) // ERROR "make\(\[\]byte, 1 << 30\) escapes to heap"
+	var x [1<<30]byte // ERROR "moved to heap: x"
+	var y = make([]byte, 1<<30) // ERROR "does not escape"
 	_ = x[0] + y[0]
 }
diff --git a/test/fixedbugs/bug121.go b/test/fixedbugs/bug121.go
index 22c7181..5adf982 100644
--- a/test/fixedbugs/bug121.go
+++ b/test/fixedbugs/bug121.go
@@ -15,3 +15,4 @@ type I interface {
 type J interface {
 	h T;  // ERROR "syntax|signature"
 }
+
diff --git a/test/fixedbugs/bug214.go b/test/fixedbugs/bug214.go
index f3c25e7..5420058 100644
--- a/test/fixedbugs/bug214.go
+++ b/test/fixedbugs/bug214.go
@@ -5,7 +5,7 @@
 // license that can be found in the LICENSE file.
 
 // Used to crash the compiler.
-// https://golang.org/issue/88
+// http://code.google.com/p/go/issues/detail?id=88
 
 package main
 
diff --git a/test/fixedbugs/bug215.go b/test/fixedbugs/bug215.go
index b27cc7d..08ed662 100644
--- a/test/fixedbugs/bug215.go
+++ b/test/fixedbugs/bug215.go
@@ -5,7 +5,7 @@
 // license that can be found in the LICENSE file.
 
 // Used to crash the compiler.
-// https://golang.org/issue/158
+// http://code.google.com/p/go/issues/detail?id=158
 
 package main
 
diff --git a/test/fixedbugs/bug216.go b/test/fixedbugs/bug216.go
index 470369a..c83a522 100644
--- a/test/fixedbugs/bug216.go
+++ b/test/fixedbugs/bug216.go
@@ -5,7 +5,7 @@
 // license that can be found in the LICENSE file.
 
 // Used to be rejected
-// https://golang.org/issue/188
+// http://code.google.com/p/go/issues/detail?id=188
 
 package main
 
diff --git a/test/fixedbugs/bug217.go b/test/fixedbugs/bug217.go
index aafc260..ec93c25 100644
--- a/test/fixedbugs/bug217.go
+++ b/test/fixedbugs/bug217.go
@@ -5,7 +5,7 @@
 // license that can be found in the LICENSE file.
 
 // Used to crash
-// https://golang.org/issue/204
+// http://code.google.com/p/go/issues/detail?id=204
 
 package main
 
diff --git a/test/fixedbugs/bug218.go b/test/fixedbugs/bug218.go
index f159f05..0e008db 100644
--- a/test/fixedbugs/bug218.go
+++ b/test/fixedbugs/bug218.go
@@ -5,7 +5,7 @@
 // license that can be found in the LICENSE file.
 
 // Crashes 6g, 8g
-// https://golang.org/issue/238
+// http://code.google.com/p/go/issues/detail?id=238
 
 package main
 
diff --git a/test/fixedbugs/bug221.go b/test/fixedbugs/bug221.go
index 4275474..86fda20 100644
--- a/test/fixedbugs/bug221.go
+++ b/test/fixedbugs/bug221.go
@@ -7,7 +7,7 @@
 // function call arg reordering was picking out 1 call that
 // didn't need to be in a temporary, but it was picking
 // out the first call instead of the last call.
-// https://golang.org/issue/370
+// http://code.google.com/p/go/issues/detail?id=370
 
 package main
 
diff --git a/test/fixedbugs/bug248.go b/test/fixedbugs/bug248.go
index 173b46f..98cda35 100644
--- a/test/fixedbugs/bug248.go
+++ b/test/fixedbugs/bug248.go
@@ -1,53 +1,15 @@
-// +build !nacl,!plan9,!windows
-// run
+// $G $D/$F.dir/bug0.go &&
+// $G $D/$F.dir/bug1.go &&
+// $G $D/$F.dir/bug2.go &&
+// errchk $G -e $D/$F.dir/bug3.go &&
+// $L bug2.$A &&
+// ./$A.out || echo BUG: failed to compile
+
+// NOTE: This test is not run by 'run.go' and so not run by all.bash.
+// To run this test you must use the ./run shell script.
 
 // 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 main
-
-import (
-	"fmt"
-	"os"
-	"os/exec"
-	"path/filepath"
-)
-
-func main() {
-	// TODO: If we get rid of errchk, re-enable this test on Windows.
-	errchk, err := filepath.Abs("errchk")
-	check(err)
-
-	err = os.Chdir(filepath.Join("fixedbugs", "bug248.dir"))
-	check(err)
-
-	run("go", "tool", "compile", "bug0.go")
-	run("go", "tool", "compile", "bug1.go")
-	run("go", "tool", "compile", "bug2.go")
-	run(errchk, "go", "tool", "compile", "-e", "bug3.go")
-	run("go", "tool", "link", "bug2.o")
-	run(fmt.Sprintf(".%ca.out", filepath.Separator))
-
-	os.Remove("bug0.o")
-	os.Remove("bug1.o")
-	os.Remove("bug2.o")
-	os.Remove("a.out")
-}
-
-func run(name string, args ...string) {
-	cmd := exec.Command(name, args...)
-	out, err := cmd.CombinedOutput()
-	if err != nil {
-		fmt.Println(string(out))
-		fmt.Println(err)
-		os.Exit(1)
-	}
-}
-
-func check(err error) {
-	if err != nil {
-		fmt.Println(err)
-		os.Exit(1)
-	}
-}
+ignored
diff --git a/test/fixedbugs/bug264.go b/test/fixedbugs/bug264.go
index 2f320de..fcf373c 100644
--- a/test/fixedbugs/bug264.go
+++ b/test/fixedbugs/bug264.go
@@ -4,7 +4,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// Test case for https://golang.org/issue/692
+// Test case for http://code.google.com/p/go/issues/detail?id=692
 
 package main
 
diff --git a/test/fixedbugs/bug265.go b/test/fixedbugs/bug265.go
index 5e05166..7f06fce 100644
--- a/test/fixedbugs/bug265.go
+++ b/test/fixedbugs/bug265.go
@@ -4,7 +4,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// Test case for https://golang.org/issue/700
+// Test case for http://code.google.com/p/go/issues/detail?id=700
 
 package main
 
diff --git a/test/fixedbugs/bug269.go b/test/fixedbugs/bug269.go
index 60ee7ee..c13eb26 100644
--- a/test/fixedbugs/bug269.go
+++ b/test/fixedbugs/bug269.go
@@ -4,7 +4,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// https://golang.org/issue/749
+// http://code.google.com/p/go/issues/detail?id=749
 
 package main
 
diff --git a/test/fixedbugs/bug271.go b/test/fixedbugs/bug271.go
index 30d9bb1..88add70 100644
--- a/test/fixedbugs/bug271.go
+++ b/test/fixedbugs/bug271.go
@@ -4,7 +4,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// https://golang.org/issue/662
+// http://code.google.com/p/go/issues/detail?id=662
 
 package main
 
diff --git a/test/fixedbugs/bug272.go b/test/fixedbugs/bug272.go
index f943d68..c27f7ee 100644
--- a/test/fixedbugs/bug272.go
+++ b/test/fixedbugs/bug272.go
@@ -4,7 +4,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// https://golang.org/issue/589
+// http://code.google.com/p/go/issues/detail?id=589
 
 package main
 
diff --git a/test/fixedbugs/bug273.go b/test/fixedbugs/bug273.go
index b4e3f65..aabb912 100644
--- a/test/fixedbugs/bug273.go
+++ b/test/fixedbugs/bug273.go
@@ -4,7 +4,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// https://golang.org/issue/589
+// http://code.google.com/p/go/issues/detail?id=589
 
 package main
 
diff --git a/test/fixedbugs/bug274.go b/test/fixedbugs/bug274.go
index e57d147..beb2d61 100644
--- a/test/fixedbugs/bug274.go
+++ b/test/fixedbugs/bug274.go
@@ -13,7 +13,7 @@
 // Both gccgo and gofmt correctly refuse this program as is and accept it
 // when the semicolons are present.
 
-// This is a test case for issue 777 ( https://golang.org/issue/777 ).
+// This is a test case for issue 777 ( http://code.google.com/p/go/issues/detail?id=777 ).
 
 package main
 
diff --git a/test/fixedbugs/bug279.go b/test/fixedbugs/bug279.go
index 726ba60..e5ec594 100644
--- a/test/fixedbugs/bug279.go
+++ b/test/fixedbugs/bug279.go
@@ -4,7 +4,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// https://golang.org/issue/799
+// http://code.google.com/p/go/issues/detail?id=799
 
 package main
 
diff --git a/test/fixedbugs/bug280.go b/test/fixedbugs/bug280.go
index 3925b9a..ba594a2 100644
--- a/test/fixedbugs/bug280.go
+++ b/test/fixedbugs/bug280.go
@@ -4,7 +4,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// https://golang.org/issue/808
+// http://code.google.com/p/go/issues/detail?id=808
 
 package main
 
diff --git a/test/fixedbugs/bug281.go b/test/fixedbugs/bug281.go
index 92c8d86..24d6fdc 100644
--- a/test/fixedbugs/bug281.go
+++ b/test/fixedbugs/bug281.go
@@ -4,7 +4,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// https://golang.org/issue/807
+// http://code.google.com/p/go/issues/detail?id=807
 
 package main
 
diff --git a/test/fixedbugs/bug283.go b/test/fixedbugs/bug283.go
index 1f7f6e0..eefed03 100644
--- a/test/fixedbugs/bug283.go
+++ b/test/fixedbugs/bug283.go
@@ -4,7 +4,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// https://golang.org/issue/806
+// http://code.google.com/p/go/issues/detail?id=806
 // triggered out of registers on 8g
 
 package bug283
diff --git a/test/fixedbugs/bug285.go b/test/fixedbugs/bug285.go
index e0b3766..0a8a0f0 100644
--- a/test/fixedbugs/bug285.go
+++ b/test/fixedbugs/bug285.go
@@ -6,7 +6,7 @@
 
 // Test for issue 778: Map key values that are assignment
 // compatible with the map key type must be accepted according
-// to the spec: https://golang.org/doc/go_spec.html#Indexes .
+// to the spec: http://golang.org/doc/go_spec.html#Indexes .
 
 package main
 
diff --git a/test/fixedbugs/bug290.go b/test/fixedbugs/bug290.go
index 46ebc1f..c8ff0bc 100644
--- a/test/fixedbugs/bug290.go
+++ b/test/fixedbugs/bug290.go
@@ -4,7 +4,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// https://golang.org/issue/920
+// http://code.google.com/p/go/issues/detail?id=920
 
 package main
 
diff --git a/test/fixedbugs/bug291.go b/test/fixedbugs/bug291.go
index d627a9d..17a5483 100644
--- a/test/fixedbugs/bug291.go
+++ b/test/fixedbugs/bug291.go
@@ -4,7 +4,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// https://golang.org/issue/915
+// http://code.google.com/p/go/issues/detail?id=915
 
 package main
 
diff --git a/test/fixedbugs/bug292.go b/test/fixedbugs/bug292.go
index 0c24912..07051dd 100644
--- a/test/fixedbugs/bug292.go
+++ b/test/fixedbugs/bug292.go
@@ -4,7 +4,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// https://golang.org/issue/843
+// http://code.google.com/p/go/issues/detail?id=843
 
 package main
 
diff --git a/test/fixedbugs/bug293.go b/test/fixedbugs/bug293.go
index c985305..bf926f5 100644
--- a/test/fixedbugs/bug293.go
+++ b/test/fixedbugs/bug293.go
@@ -4,7 +4,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// https://golang.org/issue/846
+// http://code.google.com/p/go/issues/detail?id=846
 
 package main
 
diff --git a/test/fixedbugs/bug294.go b/test/fixedbugs/bug294.go
index ec41fe8..0f3e380 100644
--- a/test/fixedbugs/bug294.go
+++ b/test/fixedbugs/bug294.go
@@ -4,7 +4,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// https://golang.org/issue/800
+// http://code.google.com/p/go/issues/detail?id=800
 
 package main
 
diff --git a/test/fixedbugs/bug301.go b/test/fixedbugs/bug301.go
index fc52503..572668f 100644
--- a/test/fixedbugs/bug301.go
+++ b/test/fixedbugs/bug301.go
@@ -4,7 +4,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// https://golang.org/issue/990
+// http://code.google.com/p/go/issues/detail?id=990
 
 package main
 
diff --git a/test/fixedbugs/bug302.dir/main.go b/test/fixedbugs/bug302.dir/main.go
index 281f908..9f874d0 100644
--- a/test/fixedbugs/bug302.dir/main.go
+++ b/test/fixedbugs/bug302.dir/main.go
@@ -5,8 +5,8 @@
 package main
 
 // Check that the export information is correct in p.6.
-import _ "p"
+import _ "./p"
 
 // Check that it's still correct in pp.a (which contains p.6).
-import _ "pp"
+import _ "./pp"
 
diff --git a/test/fixedbugs/bug302.go b/test/fixedbugs/bug302.go
index 42345a9..dc7637f 100644
--- a/test/fixedbugs/bug302.go
+++ b/test/fixedbugs/bug302.go
@@ -1,33 +1,9 @@
-// +build !nacl
-// run
+// $G $D/bug302.dir/p.go && pack grc pp.a p.$A && $G $D/bug302.dir/main.go
+
+// NOTE: This test is not run by 'run.go' and so not run by all.bash.
+// To run this test you must use the ./run shell script.
 
 // 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 (
-	"fmt"
-	"os"
-	"os/exec"
-	"path/filepath"
-)
-
-func main() {
-	run("go", "tool", "compile", filepath.Join("fixedbugs", "bug302.dir", "p.go"))
-	run("go", "tool", "pack", "grc", "pp.a", "p.o")
-	run("go", "tool", "compile", "-I", ".", filepath.Join("fixedbugs", "bug302.dir", "main.go"))
-	os.Remove("p.o")
-	os.Remove("pp.a")
-	os.Remove("main.o")
-}
-
-func run(cmd string, args ...string) {
-	out, err := exec.Command(cmd, args...).CombinedOutput()
-	if err != nil {
-		fmt.Println(string(out))
-		fmt.Println(err)
-		os.Exit(1)
-	}
-}
diff --git a/test/fixedbugs/bug345.go b/test/fixedbugs/bug345.go
index e291a55..e3705f6 100644
--- a/test/fixedbugs/bug345.go
+++ b/test/fixedbugs/bug345.go
@@ -1,45 +1,10 @@
-// +build !nacl,!plan9,!windows
-// run
+// $G $D/$F.dir/io.go && errchk $G -e $D/$F.dir/main.go
+
+// NOTE: This test is not run by 'run.go' and so not run by all.bash.
+// To run this test you must use the ./run shell script.
 
 // 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 main
-
-import (
-	"fmt"
-	"os"
-	"os/exec"
-	"path/filepath"
-)
-
-func main() {
-	// TODO: If we get rid of errchk, re-enable this test on Plan 9 and Windows.
-	errchk, err := filepath.Abs("errchk")
-	check(err)
-
-	err = os.Chdir(filepath.Join(".", "fixedbugs", "bug345.dir"))
-	check(err)
-
-	run("go", "tool", "compile", "io.go")
-	run(errchk, "go", "tool", "compile", "-e", "main.go")
-	os.Remove("io.o")
-}
-
-func run(name string, args ...string) {
-	cmd := exec.Command(name, args...)
-	out, err := cmd.CombinedOutput()
-	if err != nil {
-		fmt.Println(string(out))
-		fmt.Println(err)
-		os.Exit(1)
-	}
-}
-
-func check(err error) {
-	if err != nil {
-		fmt.Println(err)
-		os.Exit(1)
-	}
-}
+package ignored
diff --git a/test/fixedbugs/bug346.go b/test/fixedbugs/bug346.go
index f69b58d..d9203aa 100644
--- a/test/fixedbugs/bug346.go
+++ b/test/fixedbugs/bug346.go
@@ -9,28 +9,11 @@ package main
 import "os"
 
 func main() {
-	// Test unclosed closure.
-	{
-		x := 4
-		a, b, c, d := func(i int) (p int, q int, r int, s int) { return 1, i, 3, x }(2)
+	x := 4
+	a, b, c, d := func(i int) (p int, q int, r int, s int) { return 1, i, 3, x }(2)
 
-		if a != 1 || b != 2 || c != 3 || d != 4 {
-			println("1# abcd: expected 1 2 3 4 got", a, b, c, d)
-			os.Exit(1)
-		}
-	}
-	// Test real closure.
-	{
-		x := 4
-		gf = func(i int) (p int, q int, r int, s int) { return 1, i, 3, x }
-
-		a, b, c, d := gf(2)
-
-		if a != 1 || b != 2 || c != 3 || d != 4 {
-			println("2# abcd: expected 1 2 3 4 got", a, b, c, d)
-			os.Exit(1)
-		}
+	if a != 1 || b != 2 || c != 3 || d != 4 {
+		println("abcd: expected 1 2 3 4 got", a, b, c, d)
+		os.Exit(1)
 	}
 }
-
-var gf func(int) (int, int, int, int)
diff --git a/test/fixedbugs/bug369.go b/test/fixedbugs/bug369.go
index dd48da8..6d52622 100644
--- a/test/fixedbugs/bug369.go
+++ b/test/fixedbugs/bug369.go
@@ -1,6 +1,10 @@
-// +build !nacl,!windows
+// $G -N -o slow.$A $D/bug369.dir/pkg.go &&
+// $G -o fast.$A $D/bug369.dir/pkg.go &&
 // run
 
+// NOTE: This test is not run by 'run.go' and so not run by all.bash.
+// To run this test you must use the ./run shell script.
+
 // 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.
@@ -10,41 +14,49 @@
 package main
 
 import (
-	"fmt"
+	"flag"
 	"os"
-	"os/exec"
-	"path/filepath"
+	"runtime"
+	"testing"
+
+	fast "./fast"
+	slow "./slow"
 )
 
-func main() {
-	err := os.Chdir(filepath.Join(".", "fixedbugs", "bug369.dir"))
-	check(err)
-
-	run("go", "tool", "compile", "-N", "-o", "slow.o", "pkg.go")
-	run("go", "tool", "compile", "-o", "fast.o", "pkg.go")
-	run("go", "tool", "compile", "-o", "main.o", "main.go")
-	run("go", "tool", "link", "-o", "a.exe", "main.o")
-	run("." + string(filepath.Separator) + "a.exe")
-
-	os.Remove("slow.o")
-	os.Remove("fast.o")
-	os.Remove("main.o")
-	os.Remove("a.exe")
+var buf = make([]byte, 1048576)
+
+func BenchmarkFastNonASCII(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		fast.NonASCII(buf, 0)
+	}
 }
 
-func run(name string, args ...string) {
-	cmd := exec.Command(name, args...)
-	out, err := cmd.CombinedOutput()
-	if err != nil {
-		fmt.Println(string(out))
-		fmt.Println(err)
-		os.Exit(1)
+func BenchmarkSlowNonASCII(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		slow.NonASCII(buf, 0)
 	}
 }
 
-func check(err error) {
-	if err != nil {
-		fmt.Println(err)
-		os.Exit(1)
+func main() {
+	os.Args = []string{os.Args[0], "-test.benchtime=100ms"}
+	flag.Parse()
+
+	rslow := testing.Benchmark(BenchmarkSlowNonASCII)
+	rfast := testing.Benchmark(BenchmarkFastNonASCII)
+	tslow := rslow.NsPerOp()
+	tfast := rfast.NsPerOp()
+
+	// Optimization should be good for at least 2x, but be forgiving.
+	// On the ARM simulator we see closer to 1.5x.
+	speedup := float64(tslow)/float64(tfast)
+	want := 1.8
+	if runtime.GOARCH == "arm" {
+		want = 1.3
+	}
+	if speedup < want {
+		// TODO(rsc): doesn't work on linux-amd64 or darwin-amd64 builders, nor on
+		// a Lenovo x200 (linux-amd64) laptop.
+		//println("fast:", tfast, "slow:", tslow, "speedup:", speedup, "want:", want)
+		//println("not fast enough")
 	}
 }
diff --git a/test/fixedbugs/bug425.go b/test/fixedbugs/bug425.go
index c3035f6..5546bd9 100644
--- a/test/fixedbugs/bug425.go
+++ b/test/fixedbugs/bug425.go
@@ -4,7 +4,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// https://golang.org/issue/3119
+// http://code.google.com/p/go/issues/detail?id=3119
 
 package main
 
diff --git a/test/fixedbugs/bug427.go b/test/fixedbugs/bug427.go
index c13bb81..1239e7a 100644
--- a/test/fixedbugs/bug427.go
+++ b/test/fixedbugs/bug427.go
@@ -4,7 +4,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// https://golang.org/issue/3351
+// http://code.google.com/p/go/issues/detail?id=3351
 
 package main
 
diff --git a/test/fixedbugs/bug429.go b/test/fixedbugs/bug429.go
index 31d5a3a..794d293 100644
--- a/test/fixedbugs/bug429.go
+++ b/test/fixedbugs/bug429.go
@@ -1,11 +1,13 @@
-// skip
+// $G $D/$F.go && $L $F.$A && ! ./$A.out || echo BUG: bug429
+
+// NOTE: This test is not run by 'run.go' and so not run by all.bash.
+// To run this test you must use the ./run shell script.
 
 // 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.
 
 // Should print deadlock message, not hang.
-// This test is run by bug429_run.go.
 
 package main
 
diff --git a/test/fixedbugs/bug435.go b/test/fixedbugs/bug435.go
index 0c2ac7b..45323d8 100644
--- a/test/fixedbugs/bug435.go
+++ b/test/fixedbugs/bug435.go
@@ -7,7 +7,7 @@
 // Test that a syntax error caused by an unexpected EOF
 // gives an error message with the correct line number.
 //
-// https://golang.org/issue/3392
+// https://code.google.com/p/go/issues/detail?id=3392
 
 package main
 
diff --git a/test/fixedbugs/issue3924.go b/test/fixedbugs/issue3924.go
new file mode 100644
index 0000000..d4739b2
--- /dev/null
+++ b/test/fixedbugs/issue3924.go
@@ -0,0 +1,13 @@
+// errorcheck
+
+// 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 foo
+
+type mybool bool
+
+var x, y = 1, 2
+var _ mybool = x < y && x < y // ERROR "cannot use"
+var _ mybool = x < y || x < y // ERROR "cannot use"
diff --git a/test/fixedbugs/issue6889.go b/test/fixedbugs/issue6889.go
index 805a877..46bb5da 100644
--- a/test/fixedbugs/issue6889.go
+++ b/test/fixedbugs/issue6889.go
@@ -99,13 +99,5 @@ const (
 	f88 = f87 * 88
 	f89 = f88 * 89
 	f90 = f89 * 90
-	f91 = f90 * 91
-	f92 = f91 * 92
-	f93 = f92 * 93
-	f94 = f93 * 94
-	f95 = f94 * 95
-	f96 = f95 * 96
-	f97 = f96 * 97
-	f98 = f97 * 98
-	f99 = f98 * 99 // ERROR "overflow"
+	f91 = f90 * 91 // ERROR "overflow"
 )
diff --git a/test/fixedbugs/issue6964.go b/test/fixedbugs/issue6964.go
index 8f4b60d..821735c 100644
--- a/test/fixedbugs/issue6964.go
+++ b/test/fixedbugs/issue6964.go
@@ -7,5 +7,5 @@
 package main
 
 func main() {
-	_ = string(-4 + 2i + 2) // ERROR "-4 \+ 2i"
+	_ = string(-4 + 2i + 2) // ERROR "-4\+2i"
 }
diff --git a/test/fixedbugs/issue9110.go b/test/fixedbugs/issue9110.go
index b9e861f..7294633 100644
--- a/test/fixedbugs/issue9110.go
+++ b/test/fixedbugs/issue9110.go
@@ -17,7 +17,6 @@ import (
 )
 
 func main() {
-	runtime.GOMAXPROCS(1)
 	debug.SetGCPercent(1000000) // only GC when we ask for GC
 
 	var stats, stats1, stats2 runtime.MemStats
diff --git a/test/fixedbugs/issue9321.go b/test/fixedbugs/issue9321.go
index e850d8f..06cb5a6 100644
--- a/test/fixedbugs/issue9321.go
+++ b/test/fixedbugs/issue9321.go
@@ -17,7 +17,7 @@ func test() {
 	var wg sync.WaitGroup
 	wg.Add(2)
 	test := func() {
-		for i := 0; i < 10; i++ {
+		for i := 0; i < 100; i++ {
 			buf := &bytes.Buffer{}
 			pprof.Lookup("goroutine").WriteTo(buf, 2)
 		}
@@ -30,8 +30,8 @@ func test() {
 }
 
 func main() {
-	runtime.GOMAXPROCS(4)
-	for i := 0; i < 10; i++ {
+	runtime.GOMAXPROCS(2)
+	for i := 0; i < 100; i++ {
 		test()
 	}
 }
diff --git a/test/func6.go b/test/func6.go
index d1b7f46..456cb49 100644
--- a/test/func6.go
+++ b/test/func6.go
@@ -9,7 +9,7 @@
 package main
 
 func main() {
-	if func() bool { return true }() {}  // gc used to say this was a syntax error
+	if func() bool { return true }() {}  // 6g used to say this was a syntax error
 	if (func() bool { return true })() {}
 	if (func() bool { return true }()) {}
 }
diff --git a/test/func7.go b/test/func7.go
index feb7c20..2d646b6 100644
--- a/test/func7.go
+++ b/test/func7.go
@@ -23,7 +23,7 @@ func g() int {
 }
 
 func main() {
-	// gc used to evaluate g() before f().
+	// 6g, 8g, 5g all used to evaluate g() before f().
 	if f() < g() {
 		panic("wrong answer")
 	}
diff --git a/test/gc2.go b/test/gc2.go
index b33a027..561516b 100644
--- a/test/gc2.go
+++ b/test/gc2.go
@@ -1,6 +1,7 @@
-// +build !nacl
 // 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.
diff --git a/test/golden.out b/test/golden.out
new file mode 100644
index 0000000..742a5d3
--- /dev/null
+++ b/test/golden.out
@@ -0,0 +1,24 @@
+
+== ./
+
+== ken/
+
+== chan/
+
+== interface/
+
+== syntax/
+
+== dwarf/
+
+== safe/
+
+== fixedbugs/
+
+=========== fixedbugs/bug429.go
+fatal error: all goroutines are asleep - deadlock!
+
+== bugs/
+
+=========== bugs/bug395.go
+bug395 is broken
diff --git a/test/index.go b/test/index.go
index 9ff9e9f..a8c471b 100644
--- a/test/index.go
+++ b/test/index.go
@@ -216,7 +216,7 @@ func main() {
 		thisPass := 0
 		if c == "c" && (a == "a" || a == "pa" || n == "n" || i == "i64big" || i == "i64bigger" || i == "huge" || i == "fbad") {
 			if i == "huge" {
-				// Due to a detail of gc's internals,
+				// Due to a detail of 6g's internals,
 				// the huge constant errors happen in an
 				// earlier pass than the others and inhibits
 				// the next pass from running.
diff --git a/test/init1.go b/test/init1.go
index 62dfb72..f6eda6e 100644
--- a/test/init1.go
+++ b/test/init1.go
@@ -17,30 +17,22 @@ func init() {
 	go send(c)
 	<-c
 
-	const N = 1000
-	const MB = 1 << 20
-	b := make([]byte, MB)
+	const chunk = 1 << 20
+	memstats := new(runtime.MemStats)
+	runtime.ReadMemStats(memstats)
+	sys := memstats.Sys
+	b := make([]byte, chunk)
 	for i := range b {
 		b[i] = byte(i%10 + '0')
 	}
 	s := string(b)
-
-	memstats := new(runtime.MemStats)
-	runtime.ReadMemStats(memstats)
-	sys, numGC := memstats.Sys, memstats.NumGC
-
-	// Generate 1,000 MB of garbage, only retaining 1 MB total.
-	for i := 0; i < N; i++ {
+	for i := 0; i < 1000; i++ {
 		x = []byte(s)
 	}
-
-	// Verify that the garbage collector ran by seeing if we
-	// allocated fewer than N*MB bytes from the system.
 	runtime.ReadMemStats(memstats)
-	sys1, numGC1 := memstats.Sys, memstats.NumGC
-	if sys1-sys >= N*MB || numGC1 == numGC {
-		println("allocated 1000 chunks of", MB, "and used ", sys1-sys, "memory")
-		println("numGC went", numGC, "to", numGC)
+	sys1 := memstats.Sys
+	if sys1-sys > chunk*50 {
+		println("allocated 1000 chunks of", chunk, "and used ", sys1-sys, "memory")
 		panic("init1")
 	}
 }
diff --git a/test/interface/embed2.go b/test/interface/embed2.go
index df3e2e4..1636db7 100644
--- a/test/interface/embed2.go
+++ b/test/interface/embed2.go
@@ -12,25 +12,20 @@ import "os"
 
 const Value = 1e12
 
-type Inter interface {
-	M() int64
-}
+type Inter interface { M() int64 }
 
 type T int64
-
 func (t T) M() int64 { return int64(t) }
-
 var t = T(Value)
 var pt = &t
 var ti Inter = t
 var pti = &ti
 
-type S struct{ Inter }
-
-var s = S{ti}
+type S struct { Inter }
+var s = S{ ti }
 var ps = &s
 
-type SP struct{ *Inter } // ERROR "interface"
+type SP struct { *Inter }	// ERROR "interface"
 
 var i Inter
 var pi = &i
@@ -48,25 +43,25 @@ func main() {
 	check("t.M()", t.M())
 	check("pt.M()", pt.M())
 	check("ti.M()", ti.M())
-	check("pti.M()", pti.M()) // ERROR "pointer to interface, not interface"
+	check("pti.M()", pti.M())	// ERROR "method"
 	check("s.M()", s.M())
 	check("ps.M()", ps.M())
 
 	i = t
 	check("i = t; i.M()", i.M())
-	check("i = t; pi.M()", pi.M()) // ERROR "pointer to interface, not interface"
+	check("i = t; pi.M()", pi.M())	// ERROR "method"
 
 	i = pt
 	check("i = pt; i.M()", i.M())
-	check("i = pt; pi.M()", pi.M()) // ERROR "pointer to interface, not interface"
+	check("i = pt; pi.M()", pi.M())	// ERROR "method"
 
 	i = s
 	check("i = s; i.M()", i.M())
-	check("i = s; pi.M()", pi.M()) // ERROR "pointer to interface, not interface"
+	check("i = s; pi.M()", pi.M())	// ERROR "method"
 
 	i = ps
 	check("i = ps; i.M()", i.M())
-	check("i = ps; pi.M()", pi.M()) // ERROR "pointer to interface, not interface"
+	check("i = ps; pi.M()", pi.M())	// ERROR "method"
 
 	if !ok {
 		println("BUG: interface10")
diff --git a/test/linkx.go b/test/linkx.go
index ac20334..151b6db 100644
--- a/test/linkx.go
+++ b/test/linkx.go
@@ -9,15 +9,10 @@
 
 package main
 
-import "fmt"
-
 var tbd string
 var overwrite string = "dibs"
 
-var b bool
-var x int
-
 func main() {
-	fmt.Println(tbd)
-	fmt.Println(overwrite)
+	println(tbd)
+	println(overwrite)
 }
diff --git a/test/linkx_run.go b/test/linkx_run.go
index a6c7c67..5b67ce7 100644
--- a/test/linkx_run.go
+++ b/test/linkx_run.go
@@ -10,61 +10,24 @@
 package main
 
 import (
-	"bytes"
 	"fmt"
 	"os"
 	"os/exec"
-	"strings"
 )
 
 func main() {
-	test(" ") // old deprecated syntax
-	test("=") // new syntax
-}
-
-func test(sep string) {
-	// Successful run
-	cmd := exec.Command("go", "run", "-ldflags=-X main.tbd"+sep+"hello -X main.overwrite"+sep+"trumped -X main.nosuchsymbol"+sep+"neverseen", "linkx.go")
-	var out, errbuf bytes.Buffer
-	cmd.Stdout = &out
-	cmd.Stderr = &errbuf
-	err := cmd.Run()
+	cmd := exec.Command("go", "run", "-ldflags=-X main.tbd hello -X main.overwrite trumped", "linkx.go")
+	out, err := cmd.CombinedOutput()
 	if err != nil {
-		fmt.Println(errbuf.String())
-		fmt.Println(out.String())
+		fmt.Println(string(out))
 		fmt.Println(err)
 		os.Exit(1)
 	}
 
 	want := "hello\ntrumped\n"
-	got := out.String()
+	got := string(out)
 	if got != want {
 		fmt.Printf("got %q want %q\n", got, want)
 		os.Exit(1)
 	}
-
-	// Issue 8810
-	cmd = exec.Command("go", "run", "-ldflags=-X main.tbd", "linkx.go")
-	_, err = cmd.CombinedOutput()
-	if err == nil {
-		fmt.Println("-X linker flag should not accept keys without values")
-		os.Exit(1)
-	}
-
-	// Issue 9621
-	cmd = exec.Command("go", "run", "-ldflags=-X main.b=false -X main.x=42", "linkx.go")
-	outx, err := cmd.CombinedOutput()
-	if err == nil {
-		fmt.Println("-X linker flag should not overwrite non-strings")
-		os.Exit(1)
-	}
-	outstr := string(outx)
-	if !strings.Contains(outstr, "main.b") {
-		fmt.Printf("-X linker flag did not diagnose overwrite of main.b\n")
-		os.Exit(1)
-	}
-	if !strings.Contains(outstr, "main.x") {
-		fmt.Printf("-X linker flag did not diagnose overwrite of main.x\n")
-		os.Exit(1)
-	}
 }
diff --git a/test/live.go b/test/live.go
index ae982f4..f15bb74 100644
--- a/test/live.go
+++ b/test/live.go
@@ -9,39 +9,20 @@
 
 package main
 
-func printnl()
-
-//go:noescape
-func printpointer(**int)
-
-//go:noescape
-func printintpointer(*int)
-
-//go:noescape
-func printstringpointer(*string)
-
-//go:noescape
-func printstring(string)
-
-//go:noescape
-func printbytepointer(*byte)
-
-func printint(int)
-
 func f1() {
 	var x *int
-	printpointer(&x) // ERROR "live at call to printpointer: x$"
-	printpointer(&x) // ERROR "live at call to printpointer: x$"
+	print(&x) // ERROR "live at call to printpointer: x$"
+	print(&x) // ERROR "live at call to printpointer: x$"
 }
 
 func f2(b bool) {
 	if b {
-		printint(0) // nothing live here
+		print(0) // nothing live here
 		return
 	}
 	var x *int
-	printpointer(&x) // ERROR "live at call to printpointer: x$"
-	printpointer(&x) // ERROR "live at call to printpointer: x$"
+	print(&x) // ERROR "live at call to printpointer: x$"
+	print(&x) // ERROR "live at call to printpointer: x$"
 }
 
 func f3(b bool) {
@@ -49,22 +30,22 @@ func f3(b bool) {
 	// live throughout the function, to avoid being poisoned
 	// in GODEBUG=gcdead=1 mode.
 
-	printint(0) // ERROR "live at call to printint: x y$"
+	print(0) // ERROR "live at call to printint: x y$"
 	if b == false {
-		printint(0) // ERROR "live at call to printint: x y$"
+		print(0) // ERROR "live at call to printint: x y$"
 		return
 	}
 
 	if b {
 		var x *int
-		printpointer(&x) // ERROR "live at call to printpointer: x y$"
-		printpointer(&x) // ERROR "live at call to printpointer: x y$"
+		print(&x) // ERROR "live at call to printpointer: x y$"
+		print(&x) // ERROR "live at call to printpointer: x y$"
 	} else {
 		var y *int
-		printpointer(&y) // ERROR "live at call to printpointer: x y$"
-		printpointer(&y) // ERROR "live at call to printpointer: x y$"
+		print(&y) // ERROR "live at call to printpointer: x y$"
+		print(&y) // ERROR "live at call to printpointer: x y$"
 	}
-	printint(0) // ERROR "f3: x \(type \*int\) is ambiguously live$" "f3: y \(type \*int\) is ambiguously live$" "live at call to printint: 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
@@ -75,20 +56,20 @@ func f3(b bool) {
 
 func f4(b1, b2 bool) { // x not live here
 	if b2 {
-		printint(0) // x not live here
+		print(0) // x not live here
 		return
 	}
 	var z **int
 	x := new(int)
 	*x = 42
 	z = &x
-	printint(**z) // ERROR "live at call to printint: x z$"
+	print(**z) // ERROR "live at call to printint: x z$"
 	if b2 {
-		printint(1) // ERROR "live at call to printint: x$"
+		print(1) // ERROR "live at call to printint: x$"
 		return
 	}
 	for {
-		printint(**z) // ERROR "live at call to printint: x z$"
+		print(**z) // ERROR "live at call to printint: x z$"
 	}
 }
 
@@ -103,7 +84,7 @@ func f5(b1 bool) {
 		*y = 54
 		z = &y
 	}
-	printint(**z) // ERROR "f5: x \(type \*int\) is ambiguously live$" "f5: y \(type \*int\) is ambiguously live$" "live at call to printint: x 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: _".
@@ -137,7 +118,10 @@ var i9 interface{}
 func f9() bool {
 	g8()
 	x := i9
-	return x != interface{}(99.0i) // ERROR "live at call to convT2E: x$"
+	// using complex number in comparison so that
+	// there is always a convT2E, no matter what the
+	// interface rules are.
+	return x != 99.0i // ERROR "live at call to convT2E: x"
 }
 
 // liveness formerly confused by UNDEF followed by RET,
@@ -157,10 +141,10 @@ var b bool
 
 // this used to have a spurious "live at entry to f11a: ~r0"
 func f11a() *int {
-	select { // ERROR "live at call to newselect: autotmp_[0-9]+$" "live at call to selectgo: autotmp_[0-9]+$"
-	case <-c: // ERROR "live at call to selectrecv: autotmp_[0-9]+$"
+	select { // ERROR "live at call to newselect: autotmp" "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_[0-9]+$"
+	case <-c: // ERROR "live at call to selectrecv: autotmp"
 		return nil
 	}
 }
@@ -171,11 +155,11 @@ func f11b() *int {
 		// 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".
-		printint(1) // nothing live here!
-		select {    // ERROR "live at call to newselect: autotmp_[0-9]+$" "live at call to selectgo: autotmp_[0-9]+$"
-		case <-c: // ERROR "live at call to selectrecv: autotmp_[0-9]+$"
+		print(1) // nothing live here!
+		select { // ERROR "live at call to newselect: autotmp" "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_[0-9]+$"
+		case <-c: // ERROR "live at call to selectrecv: autotmp"
 			return nil
 		}
 	}
@@ -188,10 +172,10 @@ func f11c() *int {
 	if b {
 		// Unlike previous, the cases in this select fall through,
 		// so we can get to the println, so p is not dead.
-		printint(1) // ERROR "live at call to printint: p$"
-		select {    // ERROR "live at call to newselect: autotmp_[0-9]+ p$" "live at call to selectgo: autotmp_[0-9]+ p$"
-		case <-c: // ERROR "live at call to selectrecv: autotmp_[0-9]+ p$"
-		case <-c: // ERROR "live at call to selectrecv: autotmp_[0-9]+ p$"
+		print(1) // ERROR "live at call to printint: p"
+		select { // ERROR "live at call to newselect: autotmp.* 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)
@@ -215,7 +199,7 @@ func f12() *int {
 
 func f13() {
 	s := "hello"
-	s = h13(s, g13(s)) // ERROR "live at call to g13: s$"
+	s = h13(s, g13(s)) // ERROR "live at call to g13: s"
 }
 
 func g13(string) string
@@ -225,7 +209,7 @@ func h13(string, string) string
 
 func f14() {
 	x := g14()
-	printstringpointer(&x) // ERROR "live at call to printstringpointer: x$"
+	print(&x) // ERROR "live at call to printpointer: x"
 }
 
 func g14() string
@@ -233,8 +217,8 @@ func g14() string
 func f15() {
 	var x string
 	_ = &x
-	x = g15()      // ERROR "live at call to g15: x$"
-	printstring(x) // ERROR "live at call to printstring: x$"
+	x = g15() // ERROR "live at call to g15: x"
+	print(x)  // ERROR "live at call to printstring: x"
 }
 
 func g15() string
@@ -298,7 +282,7 @@ func f18() {
 	}
 	z = m2[g18()] // ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
 	z = m2[g18()] // ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
-	printbytepointer(z)
+	print(z)
 }
 
 var ch chan *byte
@@ -312,7 +296,7 @@ func f19() {
 	}
 	z = <-ch // ERROR "live at call to chanrecv1: autotmp_[0-9]+$"
 	z = <-ch // ERROR "live at call to chanrecv1: autotmp_[0-9]+$"
-	printbytepointer(z)
+	print(z)
 }
 
 func f20() {
@@ -332,7 +316,7 @@ func f21() {
 	}
 	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]+$"
-	printbytepointer(z)
+	print(z)
 }
 
 func f23() {
@@ -344,8 +328,7 @@ func f23() {
 	}
 	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]+$"
-	printbytepointer(z)
-	print(ok)
+	print(z, ok)
 }
 
 func f24() {
@@ -367,9 +350,9 @@ func f25(b bool) {
 	}
 	var x string
 	_ = &x
-	x = g15()      // ERROR "live at call to g15: x$"
-	printstring(x) // ERROR "live at call to printstring: x$"
-} // ERROR "live at call to deferreturn: 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()
 
@@ -383,7 +366,7 @@ func f26(b bool) {
 	}
 	print26((*int)(nil), (*int)(nil), (*int)(nil)) // ERROR "live at call to print26: autotmp_[0-9]+$"
 	print26((*int)(nil), (*int)(nil), (*int)(nil)) // ERROR "live at call to print26: autotmp_[0-9]+$"
-	printnl()
+	println()
 }
 
 //go:noescape
@@ -398,7 +381,7 @@ func f27(b bool) {
 	}
 	call27(func() { x++ }) // ERROR "live at call to call27: autotmp_[0-9]+$"
 	call27(func() { x++ }) // ERROR "live at call to call27: autotmp_[0-9]+$"
-	printnl()
+	println()
 }
 
 // but defer does escape to later execution in the function
@@ -408,8 +391,8 @@ func f27defer(b bool) {
 	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 "f27defer: autotmp_[0-9]+ \(type struct { F uintptr; x \*int }\) is ambiguously live$" "live at call to deferproc: autotmp_[0-9]+ autotmp_[0-9]+$" "live at call to deferreturn: autotmp_[0-9]+ autotmp_[0-9]+$"
-	printnl()                    // ERROR "live at call to printnl: autotmp_[0-9]+ 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
@@ -417,10 +400,10 @@ func f27defer(b bool) {
 func f27go(b bool) {
 	x := 0
 	if b {
-		go call27(func() { x++ }) // ERROR "live at call to newobject: &x$" "live at call to newproc: &x$"
+		go call27(func() { x++ }) // ERROR "live at call to newobject: &x" "live at call to newproc: &x$"
 	}
-	go call27(func() { x++ }) // ERROR "live at call to newobject: &x$"
-	printnl()
+	go call27(func() { x++ }) // ERROR "live at call to newobject: &x"
+	println()
 }
 
 //go:noescape
@@ -432,10 +415,10 @@ var s1, s2, s3, s4, s5, s6, s7, s8, s9, s10 string
 
 func f28(b bool) {
 	if b {
-		printstring(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]+$"
 	}
-	printstring(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]+$"
-	printstring(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
@@ -443,14 +426,14 @@ func f28(b bool) {
 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]+$"
-			printstring(k) // ERROR "live at call to printstring: 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]+$"
-		printstring(k) // ERROR "live at call to printstring: 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]+$"
-		printstring(k) // ERROR "live at call to printstring: autotmp_[0-9]+$"
+		print(k) // ERROR "live at call to printstring: autotmp_[0-9]+$"
 	}
 }
 
@@ -463,14 +446,14 @@ func f30(b bool) {
 	// the copy of ptrarr and the internal iterator pointer.
 	if b {
 		for _, p := range ptrarr {
-			printintpointer(p) // ERROR "live at call to printintpointer: autotmp_[0-9]+ autotmp_[0-9]+$"
+			print(p) // ERROR "live at call to printpointer: autotmp_[0-9]+ autotmp_[0-9]+$"
 		}
 	}
 	for _, p := range ptrarr {
-		printintpointer(p) // ERROR "live at call to printintpointer: autotmp_[0-9]+ autotmp_[0-9]+$"
+		print(p) // ERROR "live at call to printpointer: autotmp_[0-9]+ autotmp_[0-9]+$"
 	}
 	for _, p := range ptrarr {
-		printintpointer(p) // ERROR "live at call to printintpointer: autotmp_[0-9]+ autotmp_[0-9]+$"
+		print(p) // ERROR "live at call to printpointer: autotmp_[0-9]+ autotmp_[0-9]+$"
 	}
 }
 
@@ -481,7 +464,7 @@ func f31(b1, b2, b3 bool) {
 		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 convT2E: autotmp_[0-9]+ autotmp_[0-9]+$" "live at call to h31: autotmp_[0-9]+$" "live at call to newobject: autotmp_[0-9]+$"
+		h31("b") // ERROR "live at call to newobject: 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 gopanic: autotmp_[0-9]+$"
@@ -496,7 +479,7 @@ func h31(...interface{})
 
 type T32 int
 
-func (t *T32) Inc() { // ERROR "live at entry to \(\*T32\).Inc: t$"
+func (t *T32) Inc() { // ERROR "live at entry"
 	*t++
 }
 
@@ -520,44 +503,44 @@ var m33 map[interface{}]int
 
 func f33() {
 	if m33[nil] == 0 { // ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
-		printnl()
+		println()
 		return
 	} else {
-		printnl()
+		println()
 	}
-	printnl()
+	println()
 }
 
 func f34() {
 	if m33[nil] == 0 { // ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
-		printnl()
+		println()
 		return
 	}
-	printnl()
+	println()
 }
 
 func f35() {
 	if m33[nil] == 0 && m33[nil] == 0 { // ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
-		printnl()
+		println()
 		return
 	}
-	printnl()
+	println()
 }
 
 func f36() {
 	if m33[nil] == 0 || m33[nil] == 0 { // ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
-		printnl()
+		println()
 		return
 	}
-	printnl()
+	println()
 }
 
 func f37() {
 	if (m33[nil] == 0 || m33[nil] == 0) && m33[nil] == 0 { // ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
-		printnl()
+		println()
 		return
 	}
-	printnl()
+	println()
 }
 
 // select temps should disappear in the case bodies
@@ -573,46 +556,46 @@ func f38(b bool) {
 	// we care that the println lines have no live variables
 	// and therefore no output.
 	if b {
-		select { // ERROR "live at call to newselect: autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+$" "live at call to selectgo: autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+$"
-		case <-fc38(): // ERROR "live at call to selectrecv: autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+$"
-			printnl()
-		case fc38() <- *fi38(1): // ERROR "live at call to fc38: autotmp_[0-9]+$" "live at call to fi38: autotmp_[0-9]+ autotmp_[0-9]+$" "live at call to selectsend: autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+$"
-			printnl()
-		case *fi38(2) = <-fc38(): // ERROR "live at call to fc38: autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+$" "live at call to fi38: autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+$" "live at call to selectrecv: autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+$"
-			printnl()
-		case *fi38(3), *fb38() = <-fc38(): // ERROR "live at call to fb38: autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+$" "live at call to fc38: autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+$" "live at call to fi38: autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+$" "live at call to selectrecv2: autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+$"
-			printnl()
+		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()
 		}
-		printnl()
+		println()
 	}
-	printnl()
+	println()
 }
 
 // issue 8097: mishandling of x = x during return.
 
 func f39() (x []int) {
 	x = []int{1}
-	printnl() // ERROR "live at call to printnl: x$"
+	println() // ERROR "live at call to printnl: x"
 	return x
 }
 
 func f39a() (x []int) {
 	x = []int{1}
-	printnl() // ERROR "live at call to printnl: x$"
+	println() // ERROR "live at call to printnl: x"
 	return
 }
 
 func f39b() (x [10]*int) {
 	x = [10]*int{}
-	x[0] = new(int) // ERROR "live at call to newobject: x$"
-	printnl()       // ERROR "live at call to printnl: x$"
+	x[0] = new(int) // ERROR "live at call to newobject: x"
+	println()       // ERROR "live at call to printnl: x"
 	return x
 }
 
 func f39c() (x [10]*int) {
 	x = [10]*int{}
-	x[0] = new(int) // ERROR "live at call to newobject: x$"
-	printnl()       // ERROR "live at call to printnl: x$"
+	x[0] = new(int) // ERROR "live at call to newobject: x"
+	println()       // ERROR "live at call to printnl: x"
 	return
 }
 
@@ -625,20 +608,20 @@ type T40 struct {
 
 func newT40() *T40 {
 	ret := T40{}
-	ret.m = make(map[int]int) // ERROR "live at call to makemap: &ret$"
+	ret.m = make(map[int]int) // ERROR "live at call to makemap: &ret"
 	return &ret
 }
 
 func bad40() {
 	t := newT40()
+	println()
 	_ = t
-	printnl()
 }
 
 func good40() {
 	ret := T40{}
-	ret.m = make(map[int]int) // ERROR "live at call to makemap: autotmp_[0-9]+ ret$"
+	ret.m = make(map[int]int) // ERROR "live at call to makemap: ret"
 	t := &ret
-	printnl() // ERROR "live at call to printnl: autotmp_[0-9]+ ret$"
+	println() // ERROR "live at call to printnl: ret"
 	_ = t
 }
diff --git a/test/live2.go b/test/live2.go
index 7474756..ef6ad99 100644
--- a/test/live2.go
+++ b/test/live2.go
@@ -12,8 +12,6 @@ package main
 // issue 8142: lost 'addrtaken' bit on inlined variables.
 // no inlining in this test, so just checking that non-inlined works.
 
-func printnl()
-
 type T40 struct {
 	m map[int]int
 }
@@ -25,15 +23,15 @@ func newT40() *T40 {
 }
 
 func bad40() {
-	t := newT40() // ERROR "live at call to makemap: autotmp_.* ret"
-	printnl()     // ERROR "live at call to printnl: autotmp_.* ret"
+	t := newT40() // ERROR "live at call to makemap: ret"
+	println()     // ERROR "live at call to printnl: ret"
 	_ = t
 }
 
 func good40() {
 	ret := T40{}
-	ret.m = make(map[int]int) // ERROR "live at call to makemap: autotmp_.* ret"
+	ret.m = make(map[int]int) // ERROR "live at call to makemap: ret"
 	t := &ret
-	printnl() // ERROR "live at call to printnl: autotmp_.* ret"
+	println() // ERROR "live at call to printnl: ret"
 	_ = t
 }
diff --git a/test/nilcheck.go b/test/nilcheck.go
index 99c3c5f..fe05d05 100644
--- a/test/nilcheck.go
+++ b/test/nilcheck.go
@@ -182,8 +182,3 @@ func f4(x *[10]int) {
 	_ = &x[9] // ERROR "nil check"
 }
 
-func f5(m map[string]struct{}) bool {
-	// Existence-only map lookups should not generate a nil check
-	_, ok := m[""]
-	return ok
-}
diff --git a/test/nilptr3.go b/test/nilptr3.go
index 607c6fb..2757dae 100644
--- a/test/nilptr3.go
+++ b/test/nilptr3.go
@@ -1,7 +1,4 @@
 // errorcheck -0 -d=nil
-// Fails on ppc64x because of incomplete optimization.
-// See issues 9058.
-// +build !ppc64,!ppc64le
 
 // Copyright 2013 The Go Authors.  All rights reserved.
 // Use of this source code is governed by a BSD-style
diff --git a/test/nosplit.go b/test/nosplit.go
index e5c2a9f..953a5bf 100644
--- a/test/nosplit.go
+++ b/test/nosplit.go
@@ -1,6 +1,7 @@
-// +build !nacl
 // 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.
@@ -126,9 +127,8 @@ 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.
-# Because ppc64 doesn't save LR in the leaf, it gets an extra 8 bytes.
 main 112 nosplit call f; f 0 nosplit
-main 116 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
@@ -137,8 +137,8 @@ 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 and ppc64 work in less space.
+# 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
@@ -184,17 +184,6 @@ func main() {
 		goarch = runtime.GOARCH
 	}
 
-	version, err := exec.Command("go", "tool", "compile", "-V").Output()
-	if err != nil {
-		bug()
-		fmt.Printf("running go tool compile -V: %v\n", err)
-		return
-	}
-	if strings.Contains(string(version), "framepointer") {
-		// Skip this test if GOEXPERIMENT=framepointer
-		return
-	}
-
 	dir, err := ioutil.TempDir("", "go-test-nosplit")
 	if err != nil {
 		bug()
@@ -245,20 +234,9 @@ TestCases:
 		fmt.Fprintf(&gobuf, "package main\n")
 
 		var buf bytes.Buffer
-		ptrSize := 4
-		switch goarch {
-		case "ppc64", "ppc64le":
-			ptrSize = 8
-			fmt.Fprintf(&buf, "#define CALL BL\n#define REGISTER (CTR)\n")
-		case "arm":
-			fmt.Fprintf(&buf, "#define CALL BL\n#define REGISTER (R0)\n")
-		case "arm64":
-			ptrSize = 8
+		if goarch == "arm" {
 			fmt.Fprintf(&buf, "#define CALL BL\n#define REGISTER (R0)\n")
-		case "amd64":
-			ptrSize = 8
-			fmt.Fprintf(&buf, "#define REGISTER AX\n")
-		default:
+		} else {
 			fmt.Fprintf(&buf, "#define REGISTER AX\n")
 		}
 
@@ -281,21 +259,14 @@ TestCases:
 				name := m[1]
 				size, _ := strconv.Atoi(m[2])
 
-				// The limit was originally 128 but is now 512.
+				// The limit was originally 128 but is now 384.
 				// Instead of rewriting the test cases above, adjust
-				// the first stack frame to use up the extra bytes.
+				// the first stack frame to use up the extra 32 bytes.
 				if i == 0 {
-					size += 512 - 128
-					// Noopt builds have a larger stackguard.
-					// See ../cmd/dist/buildruntime.go:stackGuardMultiplier
-					for _, s := range strings.Split(os.Getenv("GO_GCFLAGS"), " ") {
-						if s == "-N" {
-							size += 640
-						}
-					}
+					size += 384 - 128
 				}
 
-				if size%ptrSize == 4 || goarch == "arm64" && size != 0 && (size+8)%16 != 0 {
+				if goarch == "amd64" && size%8 == 4 {
 					continue TestCases
 				}
 				nosplit := m[3]
diff --git a/test/run b/test/run
new file mode 100755
index 0000000..729fc1e
--- /dev/null
+++ b/test/run
@@ -0,0 +1,138 @@
+#!/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.
+
+eval $(go tool dist env)
+export GOARCH GOOS GOROOT
+export E=
+
+case X"$GOARCH" in
+Xamd64)
+	export A=6
+	;;
+X386)
+	export A=8
+	;;
+Xarm)
+	export A=5
+	export E="$GORUN"
+	;;
+*)
+	echo 1>&2 run: unsupported '$GOARCH'
+	exit 1
+esac
+
+export G="${A}g ${GCFLAGS}"
+export L=${A}l
+export GOTRACEBACK=0
+export LANG=C
+unset GREP_OPTIONS	# in case user has a non-standard set
+
+unset GOROOT_FINAL  # breaks ./ imports
+
+failed=0
+
+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"
+
+RUNFILE="${TMPDIR:-/tmp}/gorun-$$-$USER"
+TMP1FILE="${TMPDIR:-/tmp}/gotest1-$$-$USER"
+TMP2FILE="${TMPDIR:-/tmp}/gotest2-$$-$USER"
+
+# don't run the machine out of memory: limit individual processes to 4GB.
+# on thresher, 3GB suffices to run the tests; with 2GB, peano fails.
+ulimit -v 4000000
+
+# no core files please
+ulimit -c 0
+
+true >pass.out >times.out
+
+exclude=false	# exclude nothing
+golden=golden.out
+
+rm -f tmp.go  # generated by some tests, left behind if interrupted
+
+filterout() {
+	grep '^'"$2"'$' $1 >/dev/null
+}
+
+for dir in . ken chan interface syntax dwarf safe fixedbugs bugs
+do
+	echo
+	echo '==' $dir'/'
+	for i in $(ls $dir/*.go 2>/dev/null)
+	do (
+		if $exclude $i; then
+			exit 0  # continues for loop
+		fi
+		export F=$(basename $i .go)
+		export D=$dir
+		echo '. ./testlib' >"$RUNFILE"
+		sed '/^\/\//!q' $i | sed 's@//@@; $d' |sed 's|./\$A.out|$E &|g' >>"$RUNFILE"
+		if ! { time -p bash -c "bash '$RUNFILE' >'$TMP1FILE' 2>&1" ; } 2>"$TMP2FILE"
+		then
+			echo
+			echo "===========" $i
+			cat "$TMP1FILE"
+			echo >&2 fail: $i
+			echo "# $i	# fail" >>pass.out
+		elif test -s "$TMP1FILE"
+		then
+			echo
+			echo "===========" $i
+			cat "$TMP1FILE"
+			if grep -q '^BUG' "$TMP1FILE"
+			then
+				if [ $dir != bugs ]
+				then
+					echo >&2 bug: $i
+				fi
+				echo "# $i	# fail, BUG" >>pass.out
+			else
+				echo $i >>pass.out
+			fi
+		elif [ $dir = "bugs" ]
+		then
+			echo $i succeeded with no output.
+		else
+			echo $i >>pass.out
+		fi
+		echo $(awk 'NR==1{print $2}' "$TMP2FILE") $D/$F >>times.out
+		rm -f $F.$A $A.out tmp.go
+	) done
+done | # clean up some stack noise
+	egrep -v '^(r[0-9a-z]+|[cfg]s)  +0x'  |
+	sed '/tmp.*Bus error/s/.*Bus/Bus/; /tmp.*Trace.BPT/s/.*Trace/Trace/
+		s!'"$RUNFILE"'!$RUNFILE!g
+		s/^PC=0x[0-9a-f]*/pc: xxx/
+		s/^pc: 0x[0-9a-f]*/pc: xxx/
+		s/PC=0x[0-9a-f]*/PC=xxx/
+		/^Trace\/breakpoint trap/d
+		/^Trace\/BPT trap/d
+		/RUNFILE/ s/line 1: *[0-9]*/line 1: PID/
+		/^\$RUNFILE: line 1: PID Trace\/breakpoint trap/d
+		/Segmentation fault/d
+		/^qemu: uncaught target signal 11 (Segmentation fault) - exiting/d' > run.out
+
+rm -f "$RUNFILE" "$TMP1FILE" "$TMP2FILE" *.$A *.a $A.out
+diffmsg=""
+if ! diff $golden run.out
+then
+	diffmsg="; test output differs"
+	failed=1
+fi
+
+notinbugs=$(sed '/^== bugs/q' run.out | grep -c '^BUG')
+inbugs=$(sed '1,/^== bugs/d' run.out | grep -c '^BUG')
+
+echo 2>&1 $inbugs known bugs';' $notinbugs unexpected bugs$diffmsg
+
+if [ "$failed" != "0" ]; then
+	echo FAILED
+fi
+
+exit $failed
diff --git a/test/run.go b/test/run.go
index 6e1cde9..e8ec2df 100644
--- a/test/run.go
+++ b/test/run.go
@@ -15,8 +15,7 @@ import (
 	"errors"
 	"flag"
 	"fmt"
-	"hash/fnv"
-	"io"
+	"go/build"
 	"io/ioutil"
 	"log"
 	"os"
@@ -37,14 +36,16 @@ var (
 	numParallel    = flag.Int("n", runtime.NumCPU(), "number of parallel tests to run")
 	summary        = flag.Bool("summary", false, "show summary of results")
 	showSkips      = flag.Bool("show_skips", false, "show skipped tests")
-	updateErrors   = flag.Bool("update_errors", false, "update error messages in test file based on compiler output")
 	runoutputLimit = flag.Int("l", defaultRunOutputLimit(), "number of parallel runoutput tests to run")
-
-	shard  = flag.Int("shard", 0, "shard index to run. Only applicable if -shards is non-zero.")
-	shards = flag.Int("shards", 0, "number of shards. If 0, all tests are run. This is used by the continuous build.")
 )
 
 var (
+	// gc and ld are [568][gl].
+	gc, ld string
+
+	// letter is the build.ArchChar
+	letter string
+
 	goos, goarch string
 
 	// dirs are the directories to look for *.go files in.
@@ -82,6 +83,11 @@ func main() {
 
 	ratec = make(chan bool, *numParallel)
 	rungatec = make(chan bool, *runoutputLimit)
+	var err error
+	letter, err = build.ArchChar(build.Default.GOARCH)
+	check(err)
+	gc = letter + "g"
+	ld = letter + "l"
 
 	var tests []*test
 	if flag.NArg() > 0 {
@@ -120,9 +126,12 @@ func main() {
 		status := "ok  "
 		errStr := ""
 		if _, isSkip := test.err.(skipError); isSkip {
+			status = "skip"
 			test.err = nil
-			errStr = "unexpected skip for " + path.Join(test.dir, test.gofile) + ": " + errStr
-			status = "FAIL"
+			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"
@@ -167,15 +176,6 @@ func toolPath(name string) string {
 	return p
 }
 
-func shardMatch(name string) bool {
-	if *shards == 0 {
-		return true
-	}
-	h := fnv.New32()
-	io.WriteString(h, name)
-	return int(h.Sum32()%uint32(*shards)) == *shard
-}
-
 func goFiles(dir string) []string {
 	f, err := os.Open(dir)
 	check(err)
@@ -183,7 +183,7 @@ func goFiles(dir string) []string {
 	check(err)
 	names := []string{}
 	for _, name := range dirnames {
-		if !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".go") && shardMatch(name) {
+		if !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".go") {
 			names = append(names, name)
 		}
 	}
@@ -194,11 +194,11 @@ func goFiles(dir string) []string {
 type runCmd func(...string) ([]byte, error)
 
 func compileFile(runcmd runCmd, longname string) (out []byte, err error) {
-	return runcmd("go", "tool", "compile", "-e", longname)
+	return runcmd("go", "tool", gc, "-e", longname)
 }
 
 func compileInDir(runcmd runCmd, dir string, names ...string) (out []byte, err error) {
-	cmd := []string{"go", "tool", "compile", "-e", "-D", ".", "-I", "."}
+	cmd := []string{"go", "tool", gc, "-e", "-D", ".", "-I", "."}
 	for _, name := range names {
 		cmd = append(cmd, filepath.Join(dir, name))
 	}
@@ -206,8 +206,8 @@ 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", ".o", -1)
-	_, err = runcmd("go", "tool", "link", "-w", "-o", "a.exe", "-L", ".", pfile)
+	pfile := strings.Replace(goname, ".go", "."+letter, -1)
+	_, err = runcmd("go", "tool", ld, "-w", "-o", "a.exe", "-L", ".", pfile)
 	return
 }
 
@@ -328,6 +328,9 @@ type context struct {
 // shouldTest looks for build tags in a source file and returns
 // whether the file should be used according to the tags.
 func shouldTest(src string, goos, goarch string) (ok bool, whyNot string) {
+	if idx := strings.Index(src, "\npackage"); idx >= 0 {
+		src = src[:idx]
+	}
 	for _, line := range strings.Split(src, "\n") {
 		line = strings.TrimSpace(line)
 		if strings.HasPrefix(line, "//") {
@@ -412,13 +415,18 @@ func (t *test) run() {
 		t.err = skipError("starts with newline")
 		return
 	}
-
-	// Execution recipe stops at first blank line.
 	pos := strings.Index(t.src, "\n\n")
 	if pos == -1 {
 		t.err = errors.New("double newline not found")
 		return
 	}
+	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)
+		}
+		return
+	}
 	action := t.src[:pos]
 	if nl := strings.Index(action, "\n"); nl >= 0 && strings.Contains(action[:nl], "+build") {
 		// skip first line
@@ -428,19 +436,6 @@ func (t *test) run() {
 		action = action[2:]
 	}
 
-	// Check for build constraints only up to the actual code.
-	pkgPos := strings.Index(t.src, "\npackage")
-	if pkgPos == -1 {
-		pkgPos = pos // some files are intentionally malformed
-	}
-	if ok, why := shouldTest(t.src[:pkgPos], goos, goarch); !ok {
-		t.action = "skip"
-		if *showSkips {
-			fmt.Printf("%-20s %-20s: %s\n", t.action, t.goFileName(), why)
-		}
-		return
-	}
-
 	var args, flags []string
 	wantError := false
 	f := strings.Fields(action)
@@ -515,7 +510,7 @@ func (t *test) run() {
 		t.err = fmt.Errorf("unimplemented action %q", action)
 
 	case "errorcheck":
-		cmdline := []string{"go", "tool", "compile", "-e", "-o", "a.o"}
+		cmdline := []string{"go", "tool", gc, "-e", "-o", "a." + letter}
 		cmdline = append(cmdline, flags...)
 		cmdline = append(cmdline, long)
 		out, err := runcmd(cmdline...)
@@ -530,9 +525,6 @@ func (t *test) run() {
 				return
 			}
 		}
-		if *updateErrors {
-			t.updateErrors(string(out), long)
-		}
 		t.err = t.errorCheck(string(out), long, t.gofile)
 		return
 
@@ -678,7 +670,7 @@ func (t *test) run() {
 			t.err = fmt.Errorf("write tempfile:%s", err)
 			return
 		}
-		cmdline := []string{"go", "tool", "compile", "-e", "-o", "a.o"}
+		cmdline := []string{"go", "tool", gc, "-e", "-o", "a." + letter}
 		cmdline = append(cmdline, flags...)
 		cmdline = append(cmdline, tfile)
 		out, err = runcmd(cmdline...)
@@ -733,34 +725,29 @@ func (t *test) expectedOutput() string {
 	return string(b)
 }
 
-func splitOutput(out string) []string {
-	// gc error messages continue onto additional lines with leading tabs.
+func (t *test) errorCheck(outStr string, fullshort ...string) (err error) {
+	defer func() {
+		if *verbose && err != nil {
+			log.Printf("%s gc output:\n%s", t, outStr)
+		}
+	}()
+	var errs []error
+
+	var out []string
+	// 6g error messages continue onto additional lines with leading tabs.
 	// Split the output at the beginning of each line that doesn't begin with a tab.
-	// <autogenerated> lines are impossible to match so those are filtered out.
-	var res []string
-	for _, line := range strings.Split(out, "\n") {
+	for _, line := range strings.Split(outStr, "\n") {
 		if strings.HasSuffix(line, "\r") { // remove '\r', output by compiler on windows
 			line = line[:len(line)-1]
 		}
 		if strings.HasPrefix(line, "\t") {
-			res[len(res)-1] += "\n" + line
-		} else if strings.HasPrefix(line, "go tool") || strings.HasPrefix(line, "<autogenerated>") {
+			out[len(out)-1] += "\n" + line
+		} else if strings.HasPrefix(line, "go tool") {
 			continue
 		} else if strings.TrimSpace(line) != "" {
-			res = append(res, line)
+			out = append(out, line)
 		}
 	}
-	return res
-}
-
-func (t *test) errorCheck(outStr string, fullshort ...string) (err error) {
-	defer func() {
-		if *verbose && err != nil {
-			log.Printf("%s gc output:\n%s", t, outStr)
-		}
-	}()
-	var errs []error
-	out := splitOutput(outStr)
 
 	// Cut directory name.
 	for i := range out {
@@ -817,72 +804,7 @@ func (t *test) errorCheck(outStr string, fullshort ...string) (err error) {
 		fmt.Fprintf(&buf, "%s\n", err.Error())
 	}
 	return errors.New(buf.String())
-}
 
-func (t *test) updateErrors(out string, file string) {
-	// Read in source file.
-	src, err := ioutil.ReadFile(file)
-	if err != nil {
-		fmt.Fprintln(os.Stderr, err)
-		return
-	}
-	lines := strings.Split(string(src), "\n")
-	// Remove old errors.
-	for i, ln := range lines {
-		pos := strings.Index(ln, " // ERROR ")
-		if pos >= 0 {
-			lines[i] = ln[:pos]
-		}
-	}
-	// Parse new errors.
-	errors := make(map[int]map[string]bool)
-	tmpRe := regexp.MustCompile(`autotmp_[0-9]+`)
-	for _, errStr := range splitOutput(out) {
-		colon1 := strings.Index(errStr, ":")
-		if colon1 < 0 || errStr[:colon1] != file {
-			continue
-		}
-		colon2 := strings.Index(errStr[colon1+1:], ":")
-		if colon2 < 0 {
-			continue
-		}
-		colon2 += colon1 + 1
-		line, err := strconv.Atoi(errStr[colon1+1 : colon2])
-		line--
-		if err != nil || line < 0 || line >= len(lines) {
-			continue
-		}
-		msg := errStr[colon2+2:]
-		for _, r := range []string{`\`, `*`, `+`, `[`, `]`, `(`, `)`} {
-			msg = strings.Replace(msg, r, `\`+r, -1)
-		}
-		msg = strings.Replace(msg, `"`, `.`, -1)
-		msg = tmpRe.ReplaceAllLiteralString(msg, `autotmp_[0-9]+`)
-		if errors[line] == nil {
-			errors[line] = make(map[string]bool)
-		}
-		errors[line][msg] = true
-	}
-	// Add new errors.
-	for line, errs := range errors {
-		var sorted []string
-		for e := range errs {
-			sorted = append(sorted, e)
-		}
-		sort.Strings(sorted)
-		lines[line] += " // ERROR"
-		for _, e := range sorted {
-			lines[line] += fmt.Sprintf(` "%s$"`, e)
-		}
-	}
-	// Write new file.
-	err = ioutil.WriteFile(file, []byte(strings.Join(lines, "\n")), 0640)
-	if err != nil {
-		fmt.Fprintln(os.Stderr, err)
-		return
-	}
-	// Polish.
-	exec.Command("go", "fmt", file).CombinedOutput()
 }
 
 // matchPrefix reports whether s is of the form ^(.*/)?prefix(:|[),
@@ -966,7 +888,7 @@ func (t *test) wantedErrors(file, short string) (errs []wantedError) {
 				var err error
 				re, err = regexp.Compile(rx)
 				if err != nil {
-					log.Fatalf("%s:%d: invalid regexp \"%s\" in ERROR line: %v", t.goFileName(), lineNum, rx, err)
+					log.Fatalf("%s:%d: invalid regexp in ERROR line: %v", t.goFileName(), lineNum, err)
 				}
 				cache[rx] = re
 			}
@@ -984,6 +906,15 @@ func (t *test) wantedErrors(file, short string) (errs []wantedError) {
 	return
 }
 
+var skipOkay = map[string]bool{
+	"fixedbugs/bug248.go": true, // combines errorcheckdir and rundir in the same dir.
+	"fixedbugs/bug302.go": true, // tests both .$O and .a imports.
+	"fixedbugs/bug345.go": true, // needs the appropriate flags in gc invocation.
+	"fixedbugs/bug369.go": true, // needs compiler flags.
+	"fixedbugs/bug429.go": true, // like "run" but program should fail
+	"bugs/bug395.go":      true,
+}
+
 // defaultRunOutputLimit returns the number of runoutput tests that
 // can be executed in parallel.
 func defaultRunOutputLimit() int {
diff --git a/test/sinit.go b/test/sinit.go
index 188a530..df1a4cc 100644
--- a/test/sinit.go
+++ b/test/sinit.go
@@ -10,8 +10,6 @@
 
 package p
 
-import "unsafe"
-
 // Should be no init func in the assembly.
 // All these initializations should be done at link time.
 
@@ -286,6 +284,3 @@ type Mer interface {
 }
 
 var _ Mer = (*T1)(nil)
-
-var Byte byte
-var PtrByte unsafe.Pointer = unsafe.Pointer(&Byte)
diff --git a/test/sinit_run.go b/test/sinit_run.go
index c9afd3b..b0a91ce 100644
--- a/test/sinit_run.go
+++ b/test/sinit_run.go
@@ -12,19 +12,26 @@ package main
 import (
 	"bytes"
 	"fmt"
+	"go/build"
 	"os"
 	"os/exec"
 )
 
 func main() {
-	cmd := exec.Command("go", "tool", "compile", "-S", "sinit.go")
+	letter, err := build.ArchChar(build.Default.GOARCH)
+	if err != nil {
+		fmt.Println(err)
+		os.Exit(1)
+	}
+
+	cmd := exec.Command("go", "tool", letter+"g", "-S", "sinit.go")
 	out, err := cmd.CombinedOutput()
 	if err != nil {
 		fmt.Println(string(out))
 		fmt.Println(err)
 		os.Exit(1)
 	}
-	os.Remove("sinit.o")
+	os.Remove("sinit." + letter)
 
 	if bytes.Contains(out, []byte("initdone")) {
 		fmt.Println("sinit generated an init function")
diff --git a/test/testlib b/test/testlib
new file mode 100644
index 0000000..4a17f4f
--- /dev/null
+++ b/test/testlib
@@ -0,0 +1,170 @@
+# 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.
+
+# These function names are also known to
+# (and are the plan for transitioning to) run.go.
+
+# helper (not known to run.go)
+# group file list by packages and return list of packages
+# each package is a comma-separated list of go files.
+pkgs() {
+	pkglist=$(grep -h '^package ' $* | awk '{print $2}' | sort -u)
+	for p in $pkglist
+	do
+		echo $(grep -l "^package $p\$" $*) | tr ' ' ,
+	done | sort
+}
+
+_match() {
+	case $1 in
+	*,*)
+		#echo >&2 "match comma separated $1"
+		first=$(echo $1 | sed 's/,.*//')
+		rest=$(echo $1 | sed 's/[^,]*,//')
+		if _match $first && _match $rest; then
+			return 0
+		fi
+		return 1
+		;;
+	'!'*)
+		#echo >&2 "match negation $1"
+		neg=$(echo $1 | sed 's/^!//')
+		if _match $neg; then
+			return 1
+		fi
+		return 0
+		;;
+	$GOARCH|$GOOS)
+		#echo >&2 "match GOARCH or GOOS $1"
+		return 0
+		;;
+	esac
+	return 1
+}
+
+# +build aborts execution if the supplied tags don't match,
+# i.e. none of the tags (x or !x) matches GOARCH or GOOS.
++build() {
+	if (( $# == 0 )); then
+		return
+	fi
+	m=0
+	for tag; do
+		if _match $tag; then
+			m=1
+		fi
+	done
+	if [ $m = 0 ]; then
+		#echo >&2 no match
+		exit 0
+	fi
+	unset m
+}
+
+compile() {
+	$G $D/$F.go
+}
+
+compiledir() {
+	for pkg in $(pkgs $D/$F.dir/*.go)
+	do
+		$G -I . $(echo $pkg | tr , ' ') || return 1
+	done
+}
+
+errorcheckdir() {
+	lastzero=""
+	if [ "$1" = "-0" ]; then
+		lastzero="-0"
+	fi
+	pkgs=$(pkgs $D/$F.dir/*.go)
+	for pkg in $pkgs.last
+	do
+		zero="-0"
+		case $pkg in
+		*.last)
+			pkg=$(echo $pkg |sed 's/\.last$//')
+			zero=$lastzero
+		esac
+		errchk $zero $G -D . -I . -e $(echo $pkg | tr , ' ')
+	done
+}
+
+rundir() {
+	lastfile=""
+	for pkg in $(pkgs $D/$F.dir/*.go)
+	do
+		name=$(echo $pkg | sed 's/\.go.*//; s/.*\///')
+		$G -D . -I . -e $(echo $pkg | tr , ' ') || return 1
+		lastfile=$name
+	done
+	$L -o $A.out -L . $lastfile.$A
+	./$A.out
+}
+
+rundircmpout() {
+	lastfile=""
+	for pkg in $(pkgs $D/$F.dir/*.go)
+	do
+		name=$(echo $pkg | sed 's/\.go.*//; s/.*\///')
+		$G -D . -I . -e $(echo $pkg | tr , ' ') || return 1
+		lastfile=$name
+	done
+	$L -o $A.out -L . $lastfile.$A
+	./$A.out 2>&1 | cmp - $D/$F.out
+}
+
+build() {
+	$G $D/$F.go && $L $F.$A
+}
+
+runoutput() {
+	go run "$D/$F.go" "$@" > tmp.go
+	go run tmp.go
+}
+
+run() {
+	gofiles=""
+	ingo=true
+	while $ingo; do
+		case "$1" in
+		*.go)
+			gofiles="$gofiles $1"
+			shift
+			;;
+		*)
+			ingo=false
+			;;
+		esac
+	done
+
+	$G $D/$F.go $gofiles && $L $F.$A && ./$A.out "$@"
+}
+
+cmpout() {
+	$G $D/$F.go && $L $F.$A && ./$A.out 2>&1 | cmp - $D/$F.out
+}
+
+errorcheck() {
+	zero=""
+	if [ "$1" = "-0" ]; then
+		zero="-0"
+		shift
+	fi
+	errchk $zero $G -e $* $D/$F.go
+}
+
+errorcheckoutput() {
+	zero=""
+	if [ "$1" = "-0" ]; then
+		zero="-0"
+		shift
+	fi
+	go run "$D/$F.go" "$@" > tmp.go
+	errchk $zero $G -e tmp.go
+}
+
+skip() {
+	true
+}

-- 
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