Merge tag 'go1.11rc2'

Change-Id: I5e4800603950d6ae91dcde331c0f8161d254ecdc
diff --git a/BUILD.gn b/BUILD.gn
new file mode 100644
index 0000000..31d334d
--- /dev/null
+++ b/BUILD.gn
@@ -0,0 +1,122 @@
+# Copyright 2016 The Fuchsia Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/sysroot.gni")
+import("//build/go/go_test.gni")
+import("//build/host.gni")
+import("//build/package.gni")
+
+if (current_toolchain == target_toolchain) {
+  action("go_toolchain") {
+    go_root = "$host_tools_dir/goroot"
+
+    # These files are copied over to //out by makefuchsia.go.
+    copied_files = [
+      "misc/fuchsia/clangwrap.sh",
+      "misc/fuchsia/gccwrap.sh",
+      "misc/fuchsia/go_stdlib_tests.json",
+    ]
+
+    inputs = copied_files
+    inputs += [ "makefuchsia.go" ]
+
+    outputs = [
+      "$root_gen_dir/goroot.done",
+    ]
+    foreach(file, copied_files) {
+      outputs += [ "$go_root/$file" ]
+    }
+
+    depfile = "$root_gen_dir/goroot.d"
+
+    visibility = [ ":*" ]
+
+    script = rebase_path("//buildtools/go")
+    args = [
+      "run",
+      rebase_path("makefuchsia.go", root_build_dir),
+      "-buildtools-go",
+      rebase_path("//buildtools/go"),
+      "-fuchsia-goroot",
+      rebase_path("."),
+      "-depfile",
+      rebase_path(depfile),
+      "-root-gen-dir",
+      rebase_path("$root_gen_dir"),
+      "-root-out-dir",
+      rebase_path("$root_out_dir"),
+      "--out-goroot",
+      rebase_path(go_root),
+      "-target-cpu",
+      target_cpu,
+    ]
+  }
+
+  # A symlink from the old location to the new, while we're transitioning
+  # to the new.
+  action("old_go_toolchain_symlink") {
+    old_go_root = "$root_out_dir/goroot"
+    go_root = "$host_tools_dir/goroot"
+    script = "make-goroot-symlink.sh"
+    args = [
+      rebase_path(go_root),
+      rebase_path(old_go_root),
+    ]
+    outputs = [
+      old_go_root
+    ]
+    deps = [
+      ":go_toolchain"
+    ]
+  }
+}
+
+group("go_runtime") {
+  public_deps = [
+    ":go_toolchain(${target_toolchain})",
+    ":old_go_toolchain_symlink(${target_toolchain})",
+  ]
+}
+
+go_test("go_dispatch_test") {
+  gopackage = "syscall/zx/dispatch"
+}
+
+go_test("go_zxwait_test") {
+  gopackage = "syscall/zx/zxwait"
+}
+
+go_test("go_os_test") {
+  gopackage = "os"
+}
+
+go_test("go_net_test") {
+  gopackage = "net"
+}
+
+package("go_stdlib_tests") {
+  testonly = true
+
+  deps = [
+    ":go_dispatch_test",
+    ":go_os_test",
+    ":go_net_test",
+    ":go_zxwait_test",
+  ]
+
+  tests = [
+    {
+      name = "go_dispatch_test"
+    },
+    {
+      name = "go_net_test"
+    },
+    {
+      name = "go_os_test"
+    },
+    {
+      name = "go_zxwait_test"
+    },
+  ]
+}
diff --git a/make-goroot-symlink.sh b/make-goroot-symlink.sh
new file mode 100755
index 0000000..ecc5d76
--- /dev/null
+++ b/make-goroot-symlink.sh
@@ -0,0 +1,37 @@
+#!/bin/bash
+# Copyright 2018 The Fuchsia Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+#
+# Make a symlink, handling the case where the source is a directory
+# by removing the source first.
+# "ln -sf" doesn't work in this case: the symbolic link is placed in the
+# directory named LINK-NAME.
+# For paranoia purposes, this script only works if the basename of
+# TARGET and LINK-NAME are "goroot". This is to avoid accidents resulting
+# in rm -rf removing way more than intended.
+
+set -e
+
+if [[ $# != 2 ]]
+then
+  echo >&2 "Usage: $(basename $0) TARGET LINK-NAME"
+  exit 1
+fi
+
+declare -r TARGET=$1
+declare -r LINK_NAME=$2
+
+if [[ $(basename "$TARGET") != "goroot" ]]
+then
+  echo >&2 "TARGET basename is not goroot"
+  exit 1
+fi
+if [[ $(basename "$LINK_NAME") != "goroot" ]]
+then
+  echo >&2 "LINK-NAME basename is not goroot"
+  exit 1
+fi
+
+/bin/rm -rf "$LINK_NAME"
+/bin/ln -s "$TARGET" "$LINK_NAME"
diff --git a/makefuchsia.go b/makefuchsia.go
new file mode 100644
index 0000000..d2c995b
--- /dev/null
+++ b/makefuchsia.go
@@ -0,0 +1,187 @@
+// Copyright 2017 The Fuchsia 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 makefuchsia.go script builds a GOROOT in the out/ build directory
+// using sources from third_party/go.
+package main
+
+import (
+	"bytes"
+	"flag"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"log"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"strings"
+)
+
+var (
+	flagBuildtoolsGo   = flag.String("buildtools-go", "", "Path to go tool used for bootstrap")
+	flagFuchsiaGoroot = flag.String("fuchsia-goroot", "", "Path to Fuchsia's source GOROOT")
+	flagDepfile       = flag.String("depfile", "", "Stdlib depfile")
+	flagRootOutDir    = flag.String("root-out-dir", "", "GN variable")
+	flagRootGenDir    = flag.String("root-gen-dir", "", "GN variable")
+	flagTargetCPU     = flag.String("target-cpu", "", "GN variable")
+	flagOutGoroot     = flag.String("out-goroot", "", "Path to the output GOROOT")
+)
+
+func relGenDir() string {
+	return (*flagRootGenDir)[len(*flagRootOutDir)+1:]
+}
+
+func mkdir(path ...string) {
+	if err := os.MkdirAll(join(path...), 0755); err != nil {
+		log.Fatal(err)
+	}
+}
+
+func join(path ...string) string { return filepath.Join(path...) }
+
+// copyfile copies src to dst if the two files have different contents.
+func copyfile(src, dst string) {
+	srcfile, err := os.Open(src)
+	if err != nil {
+		log.Fatal(err)
+	}
+	defer srcfile.Close()
+
+	fi, err := srcfile.Stat()
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	mkdir(filepath.Dir(dst))
+	f, err := os.OpenFile(dst, os.O_CREATE|os.O_RDWR|os.O_TRUNC, fi.Mode())
+	if err != nil {
+		log.Fatal(err)
+	}
+	if _, err := io.Copy(f, srcfile); err != nil {
+		log.Fatalf("cp %s %s: %v", src, dst, err)
+	}
+	if err := f.Close(); err != nil {
+		log.Fatalf("cp %s %s: close: %v", src, dst, err)
+	}
+}
+
+func convCPU(cpu string) (arch string) {
+	switch cpu {
+	case "x64":
+		return "amd64"
+	case "arm64":
+		return "arm64"
+	}
+	return ""
+}
+
+// allFilesIn recursively walks a set of files, returning the entire tree in
+// paths relative to the given root. A map is returned for convenience. If
+// prefix is given, only files that match the prefix are considered.
+func allFilesIn(root string, paths map[string]struct{}, prefix ...string) error {
+	return filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
+		if err != nil || info.IsDir() {
+			return err
+		}
+		for _, pfx := range prefix {
+			if strings.HasPrefix(path, join(root, pfx)) {
+				relPath := strings.TrimPrefix(path, root)[1:]
+				paths[relPath] = struct{}{}
+				return err
+			}
+		}
+		return err
+	})
+}
+
+func main() {
+	log.SetFlags(0)
+	log.SetPrefix("makefuchsia.go: ")
+	flag.Parse()
+
+	if *flagRootGenDir == "" {
+		log.Fatal("must specify -root-gen-dir")
+	}
+
+	if *flagFuchsiaGoroot == "" {
+		log.Fatal("must specify -fuchsia-goroot when building toolchain")
+	}
+
+	goarchTarget := convCPU(*flagTargetCPU)
+	if goarchTarget == "" {
+		log.Fatalf("unsupported target CPU: %s", *flagTargetCPU)
+	}
+
+	srcGoroot := *flagFuchsiaGoroot
+	dstGoroot := *flagOutGoroot
+
+	srcFiles := map[string]struct{}{}
+	if err := allFilesIn(join(srcGoroot), srcFiles, "src/", "misc/fuchsia/"); err != nil {
+		log.Fatal(err)
+	}
+
+	dstFiles := map[string]struct{}{}
+	if _, err := os.Stat(join(dstGoroot)); err == nil {
+		if err := allFilesIn(join(dstGoroot), dstFiles, ""); err != nil {
+			log.Fatal(err)
+		}
+	}
+
+	for f := range dstFiles {
+		if _, ok := srcFiles[f]; !ok {
+			// try to preserve the bin/ and pkg/ trees, as they can be used to do faster
+			// rebuilds of the toolchain.
+			if strings.HasPrefix(f, "src/") || strings.HasPrefix(f, "misc/fuchsia/") {
+				os.Remove(filepath.Join(dstGoroot, f))
+			}
+		}
+	}
+
+	for f := range srcFiles {
+		src, dst := join(srcGoroot, f), join(dstGoroot, f)
+		copyfile(src, dst)
+	}
+
+	versionFile := join(dstGoroot, "VERSION")
+	if err := ioutil.WriteFile(versionFile, []byte("devel third_party/go fuchsia"), 0664); err != nil {
+		log.Fatal(err)
+	}
+
+	cmd := exec.Command(*flagBuildtoolsGo, "env", "GOROOT")
+	out, err := cmd.CombinedOutput()
+	if err != nil {
+		log.Fatalf("cannot find bootstrap GOROOT: %v", err)
+	}
+
+	env := os.Environ()
+	env = append(env, "GOROOT_BOOTSTRAP="+strings.TrimSpace(string(out)))
+	env = append(env, "CC_FOR_fuchsia_"+goarchTarget+"="+dstGoroot+"/misc/fuchsia/gccwrap.sh")
+
+	cmd = exec.Command(join(dstGoroot, "src", "make.bash"))
+	cmd.Args = []string{"--no-clean"}
+	cmd.Dir = join(dstGoroot, "src")
+	cmd.Env = env
+	buf := new(bytes.Buffer)
+	cmd.Stdout = buf
+	cmd.Stderr = buf
+	if err := cmd.Run(); err != nil {
+		log.Fatalf("make.bash failed: %v\n%s", err, buf.String())
+	}
+
+	depfile, err := os.Create(*flagDepfile)
+	if err != nil {
+		log.Fatal(err)
+	}
+	fmt.Fprintf(depfile, "%s/goroot.done:", relGenDir())
+	for f := range srcFiles {
+		fmt.Fprintf(depfile, " %s", join(srcGoroot, f))
+	}
+	fmt.Fprintf(depfile, " %s", join(srcGoroot, "makefuchsia.go"))
+
+	donePath := join(*flagRootGenDir, "goroot.done")
+	if err := ioutil.WriteFile(donePath, []byte("done"), 0664); err != nil {
+		log.Fatalf("writing goroot.done failed: %v", err)
+	}
+}
diff --git a/misc/fuchsia/README.md b/misc/fuchsia/README.md
new file mode 100644
index 0000000..e26e84b
--- /dev/null
+++ b/misc/fuchsia/README.md
@@ -0,0 +1,47 @@
+Go on Fuchsia
+=========
+
+To build a toolchain on Linux for Fuchsia, first follow the
+instructions on
+
+  https://fuchsia.googlesource.com/manifest/
+
+Then,
+* Set the SDK environment variable to the location of the Fuchsia SDK:
+  If you downloaded fuchsia to your ${HOME} directory:
+  ```
+  export SDK=${HOME}/fuchsia/buildtools
+  ```
+
+* Identify where a host version of go exists, with:
+  ```
+  export GOROOT_BOOTSTRAP=`path to directory containing go`
+  ```
+  On my machine, `which go` returned /usr/lib/golang/bin/go, so I set
+  GOROOT_BOOTSTRAP=/usr/lib/golang/
+
+* Build Go in `fuchsia/third_party/go/src` using
+  ```
+  GOOS=fuchsia CC_FOR_TARGET=../misc/fuchsia/clangwrap.sh ./make.bash
+  ```
+
+* To build a program, junk.go in go/src, use:
+  ```
+  GOOS=fuchsia ../bin/go build junk.go
+  ```
+  This program can be put in a bootfs and run on qemu with:
+  ```
+  echo bin/junk=junk > junk.manifest
+  fuchsia/buildtools/mkbootfs -o junk.bootfs junk.manifest
+  ./scripts/run-zircon-x64 -x path/to/fuchsia/third_party/go/src/junk.bootfs
+  ```
+  A cgo variant can be build by adding CGO_ENABLED=1 to both
+  the make.bash command and the go build command.
+
+* To build a program using just the zircon prebuild toolchain
+  (useful for debugging if the fuchsia sysroot is out of sync
+  with your zircon) set the environment variable ZIRCON to
+  the location of your zircon and build with the gccwrap.sh
+  script:
+  ```
+  ZIRCON=$HOME/zircon CGO_ENABLED=1 CC_FOR_TARGET=$(pwd)/../misc/fuchsia/gccwrap.sh GOOS=fuchsia ./make.bash
diff --git a/misc/fuchsia/clangwrap.sh b/misc/fuchsia/clangwrap.sh
new file mode 100755
index 0000000..40514e2
--- /dev/null
+++ b/misc/fuchsia/clangwrap.sh
@@ -0,0 +1,40 @@
+#!/bin/bash
+# This uses the Fuchsia clang and Zircon sysroot.
+set -eu
+
+if [ "$GOHOSTARCH" == "amd64" ]; then
+	HOST_ARCH="x64"
+elif [ "$GOHOSTARCH" == "arm64" ]; then
+	HOST_ARCH="arm64"
+else
+	echo "clangwrap.sh: missing/invalid GOHOSTARCH env variable" >&2
+	exit 1
+fi
+
+if [ "$GOHOSTOS" == "linux" ]; then
+	HOST_OS="linux"
+elif [ "$GOHOSTOS" == "darwin" ]; then
+	HOST_OS="mac"
+else
+	echo "clangwrap.sh: missing/invalid GOHOSTOS env variable" >&2
+	exit 1
+fi
+
+if [ "$GOARCH" == "amd64" ]; then
+	TARGET_ARCH="x86_64"
+elif [ "$GOHOSTARCH" == "arm64" ]; then
+	TARGET_ARCH="aarch64"
+else
+	echo "clangwrap.sh: missing/invalid GOARCH env variable" >&2
+	exit 1
+fi
+
+if [ "$FUCHSIA" == "" ]; then
+	echo "clangwrap.sh: missing FUCHSIA env variable" >&2
+	exit 1
+fi
+
+exec ${FUCHSIA}/buildtools/${HOST_OS}-${HOST_ARCH}/clang/bin/clang \
+	--target=${TARGET_ARCH}-fuchsia \
+	--sysroot=${FUCHSIA}/out/sysroot/${TARGET_ARCH}-fuchsia \
+	"$@"
diff --git a/misc/fuchsia/gccwrap.sh b/misc/fuchsia/gccwrap.sh
new file mode 100755
index 0000000..93c86cd
--- /dev/null
+++ b/misc/fuchsia/gccwrap.sh
@@ -0,0 +1,66 @@
+#!/bin/bash
+# This uses the zircon prebuild C++ toolchain
+
+if [ -z "${ZIRCON}" ]; then
+	echo "gccwrap.sh: missing ZIRCON env variable" >&2
+	exit 1
+fi
+
+zirconsysroot="${ZIRCON_SYSROOT}"
+if [ -z "${zirconsysroot}" ]; then
+	echo "gccwrap.sh: missing ZIRCON_SYSROOT env variable" >&2
+	exit 1
+fi
+
+if [ -z "${FUCHSIA_ROOT_OUT_DIR}" ]; then
+	echo "gccwrap.sh: missing FUCHSIA_ROOT_OUT_DIR env variable" >&2
+	exit 1
+fi
+
+if [ "$GOARCH" == "amd64" ]; then
+	libdir="x64-shared"
+	gccbin="$ZIRCON/prebuilt/downloads/gcc/bin/x86_64-elf-gcc"
+elif [ "$GOARCH" == "arm64" ]; then
+	libdir="arm64-shared"
+	gccbin="$ZIRCON/prebuilt/downloads/gcc/bin/aarch64-elf-gcc"
+else
+	echo "gccwrap.sh: unsupported GOARCH: $GOARCH" >&2
+	exit 1
+fi
+
+compiler=false
+extra_args=""
+
+for var in "$@"
+do
+	if [[ "$var" == "-r" || "$var" == "-c" ]]; then
+		compiler=true
+	fi
+done
+
+if ! $compiler; then
+	extra_args="-lc $zirconsysroot/lib/Scrt1.o $zirconsysroot/lib/libzircon.so -lfdio"
+fi
+
+exec $gccbin \
+	--sysroot=$zirconsysroot \
+	-I$zirconsysroot/include \
+	-I${ZIRCON}/system/ulib/fdio/include \
+	-L$zirconsysroot/lib \
+	-L${FUCHSIA_ROOT_OUT_DIR}/${libdir} \
+	-nostdlib \
+	-fuse-ld=gold \
+	-fno-use-linker-plugin \
+	-Wl,-nostdlib \
+	-Wl,--build-id \
+	-Wl,-z,max-page-size=4096 \
+	-Wl,-z,combreloc \
+	-Wl,-z,relro \
+	-Wl,-z,now \
+	-Wl,-z,text \
+	-Wl,-z,noexecstack \
+	-Wl,--hash-style=gnu \
+	-Wl,--eh-frame-hdr \
+	-Wl,-dynamic-linker=ld.so.1 \
+	$extra_args \
+	"$@"
diff --git a/misc/fuchsia/go_stdlib_tests.json b/misc/fuchsia/go_stdlib_tests.json
new file mode 100644
index 0000000..e52c708
--- /dev/null
+++ b/misc/fuchsia/go_stdlib_tests.json
@@ -0,0 +1,8 @@
+{
+  "tests":[
+    {
+      "name":"go_os_test",
+      "exec":"/system/bin/report_result /system/test/go_os_test"
+    }
+  ]
+}
diff --git a/src/cmd/dist/build.go b/src/cmd/dist/build.go
index eed9866..a4eeb3d 100644
--- a/src/cmd/dist/build.go
+++ b/src/cmd/dist/build.go
@@ -81,6 +81,7 @@
 	"android",
 	"solaris",
 	"freebsd",
+	"fuchsia",
 	"nacl",
 	"netbsd",
 	"openbsd",
@@ -1034,6 +1035,8 @@
 		xremoveall(pathf("%s/pkg/%s_%s", goroot, goos, goarch))
 		xremoveall(pathf("%s/pkg/%s_%s_race", goroot, gohostos, gohostarch))
 		xremoveall(pathf("%s/pkg/%s_%s_race", goroot, goos, goarch))
+		xremoveall(pathf("%s/pkg/%s_%s_shared", goroot, gohostos, gohostarch))
+		xremoveall(pathf("%s/pkg/%s_%s_shared", goroot, goos, goarch))
 		xremoveall(tooldir)
 
 		// Remove cached version info.
@@ -1390,6 +1393,8 @@
 	"freebsd/386":     true,
 	"freebsd/amd64":   true,
 	"freebsd/arm":     false,
+	"fuchsia/amd64":   true,
+	"fuchsia/arm64":   true,
 	"linux/386":       true,
 	"linux/amd64":     true,
 	"linux/arm":       true,
diff --git a/src/cmd/go/internal/base/signal_notunix.go b/src/cmd/go/internal/base/signal_notunix.go
index 9e869b0..a8e5a34 100644
--- a/src/cmd/go/internal/base/signal_notunix.go
+++ b/src/cmd/go/internal/base/signal_notunix.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build plan9 windows
+// +build plan9 fuchsia windows
 
 package base
 
diff --git a/src/cmd/go/internal/load/pkg.go b/src/cmd/go/internal/load/pkg.go
index ec2fa73..1f6e72c 100644
--- a/src/cmd/go/internal/load/pkg.go
+++ b/src/cmd/go/internal/load/pkg.go
@@ -1550,6 +1550,11 @@
 
 // LinkerDeps returns the list of linker-induced dependencies for main package p.
 func LinkerDeps(p *Package) []string {
+	// Don't add deps to Fuchsia internal syscall stuff.
+	if p.ImportPath == "syscall/zx" || p.ImportPath == "syscall/mx" {
+		return []string{}
+	}
+
 	// Everything links runtime.
 	deps := []string{"runtime"}
 
@@ -1578,7 +1583,7 @@
 func externalLinkingForced(p *Package) bool {
 	// Some targets must use external linking even inside GOROOT.
 	switch cfg.BuildContext.GOOS {
-	case "android":
+	case "android", "fuchsia":
 		return true
 	case "darwin":
 		switch cfg.BuildContext.GOARCH {
diff --git a/src/cmd/go/internal/work/exec.go b/src/cmd/go/internal/work/exec.go
index 42fa0e6..0ec6710 100644
--- a/src/cmd/go/internal/work/exec.go
+++ b/src/cmd/go/internal/work/exec.go
@@ -2157,6 +2157,7 @@
 		switch cfg.Goos {
 		case "windows":
 			a = append(a, "-mthreads")
+		case "fuchsia":
 		default:
 			a = append(a, "-pthread")
 		}
diff --git a/src/cmd/go/internal/work/gccgo.go b/src/cmd/go/internal/work/gccgo.go
index 91daf52..1e30cf2 100644
--- a/src/cmd/go/internal/work/gccgo.go
+++ b/src/cmd/go/internal/work/gccgo.go
@@ -395,7 +395,12 @@
 		// 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")
+		if cfg.Goos == "fuchsia" {
+			ldflags = append(ldflags, "-r")
+		} else {
+			ldflags = append(ldflags, "-Wl,-r")
+		}
+		ldflags = append(ldflags, "-nostdlib", "-Wl,--whole-archive", "-lgolibbegin", "-Wl,--no-whole-archive")
 
 		if nopie := b.gccNoPie([]string{tools.linker()}); nopie != "" {
 			ldflags = append(ldflags, nopie)
diff --git a/src/cmd/go/internal/work/init.go b/src/cmd/go/internal/work/init.go
index eb99815..bf2cefe 100644
--- a/src/cmd/go/internal/work/init.go
+++ b/src/cmd/go/internal/work/init.go
@@ -123,7 +123,8 @@
 		ldBuildmode = "c-shared"
 	case "default":
 		switch platform {
-		case "android/arm", "android/arm64", "android/amd64", "android/386":
+		case "android/arm", "android/arm64", "android/amd64", "android/386",
+			"fuchsia/amd64", "fuchsia/arm64":
 			codegenArg = "-shared"
 			ldBuildmode = "pie"
 		case "darwin/arm", "darwin/arm64":
@@ -151,7 +152,8 @@
 			switch platform {
 			case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64le", "linux/s390x",
 				"android/amd64", "android/arm", "android/arm64", "android/386",
-				"freebsd/amd64":
+				"freebsd/amd64",
+				"fuchsia/amd64", "fuchsia/arm64":
 				codegenArg = "-shared"
 			case "darwin/amd64":
 				codegenArg = "-shared"
diff --git a/src/cmd/internal/obj/x86/asm6.go b/src/cmd/internal/obj/x86/asm6.go
index d3389e4..ad21e38 100644
--- a/src/cmd/internal/obj/x86/asm6.go
+++ b/src/cmd/internal/obj/x86/asm6.go
@@ -2350,6 +2350,9 @@
 					return 0x64 // FS
 				}
 
+			case objabi.Hfuchsia:
+				log.Fatalf("unknown TLS base register, fuchsia requires PIC code")
+
 			case objabi.Hdragonfly,
 				objabi.Hfreebsd,
 				objabi.Hnetbsd,
@@ -4977,7 +4980,7 @@
 					default:
 						log.Fatalf("unknown TLS base location for %v", ctxt.Headtype)
 
-					case objabi.Hlinux, objabi.Hfreebsd:
+					case objabi.Hlinux, objabi.Hfreebsd, objabi.Hfuchsia:
 						if !ctxt.Flag_shared {
 							log.Fatalf("unknown TLS base location for linux/freebsd without -shared")
 						}
diff --git a/src/cmd/internal/obj/x86/obj6.go b/src/cmd/internal/obj/x86/obj6.go
index 139f293..7e42dcc 100644
--- a/src/cmd/internal/obj/x86/obj6.go
+++ b/src/cmd/internal/obj/x86/obj6.go
@@ -67,6 +67,8 @@
 		return false
 	case objabi.Hlinux, objabi.Hfreebsd:
 		return !ctxt.Flag_shared
+	case objabi.Hfuchsia:
+		return false
 	}
 
 	return true
diff --git a/src/cmd/internal/objabi/head.go b/src/cmd/internal/objabi/head.go
index 23c7b62..521876a 100644
--- a/src/cmd/internal/objabi/head.go
+++ b/src/cmd/internal/objabi/head.go
@@ -40,6 +40,7 @@
 	Hdarwin
 	Hdragonfly
 	Hfreebsd
+	Hfuchsia
 	Hjs
 	Hlinux
 	Hnacl
@@ -58,6 +59,8 @@
 		*h = Hdragonfly
 	case "freebsd":
 		*h = Hfreebsd
+	case "fuchsia":
+		*h = Hfuchsia
 	case "js":
 		*h = Hjs
 	case "linux", "android":
@@ -88,6 +91,8 @@
 		return "dragonfly"
 	case Hfreebsd:
 		return "freebsd"
+	case Hfuchsia:
+		return "fuchsia"
 	case Hjs:
 		return "js"
 	case Hlinux:
diff --git a/src/cmd/link/internal/amd64/asm.go b/src/cmd/link/internal/amd64/asm.go
index af27444..7817240 100644
--- a/src/cmd/link/internal/amd64/asm.go
+++ b/src/cmd/link/internal/amd64/asm.go
@@ -37,6 +37,7 @@
 	"cmd/link/internal/sym"
 	"debug/elf"
 	"log"
+	"strings"
 )
 
 func PADDR(x uint32) uint32 {
@@ -414,6 +415,8 @@
 		if r.Siz == 4 {
 			if r.Xsym.Type == sym.SDYNIMPORT && r.Xsym.ElfType == elf.STT_FUNC {
 				ctxt.Out.Write64(uint64(elf.R_X86_64_PLT32) | uint64(elfsym)<<32)
+			} else if r.Xsym.Type == sym.SDYNIMPORT && ctxt.HeadType == objabi.Hfuchsia && strings.HasPrefix(r.Xsym.Name, "vdso_") {
+				ctxt.Out.Write64(uint64(elf.R_X86_64_GOTPCREL) | uint64(elfsym)<<32)
 			} else {
 				ctxt.Out.Write64(uint64(elf.R_X86_64_PC32) | uint64(elfsym)<<32)
 			}
@@ -723,6 +726,7 @@
 
 	case objabi.Hlinux,
 		objabi.Hfreebsd,
+		objabi.Hfuchsia,
 		objabi.Hnetbsd,
 		objabi.Hopenbsd,
 		objabi.Hdragonfly,
@@ -753,6 +757,7 @@
 
 		case objabi.Hlinux,
 			objabi.Hfreebsd,
+			objabi.Hfuchsia,
 			objabi.Hnetbsd,
 			objabi.Hopenbsd,
 			objabi.Hdragonfly,
@@ -833,6 +838,7 @@
 
 	case objabi.Hlinux,
 		objabi.Hfreebsd,
+		objabi.Hfuchsia,
 		objabi.Hnetbsd,
 		objabi.Hopenbsd,
 		objabi.Hdragonfly,
diff --git a/src/cmd/link/internal/amd64/obj.go b/src/cmd/link/internal/amd64/obj.go
index 87e8091..96f5e66 100644
--- a/src/cmd/link/internal/amd64/obj.go
+++ b/src/cmd/link/internal/amd64/obj.go
@@ -105,6 +105,7 @@
 
 	case objabi.Hlinux, /* elf64 executable */
 		objabi.Hfreebsd,   /* freebsd */
+		objabi.Hfuchsia,   /* fuchsia */
 		objabi.Hnetbsd,    /* netbsd */
 		objabi.Hopenbsd,   /* openbsd */
 		objabi.Hdragonfly, /* dragonfly */
diff --git a/src/cmd/link/internal/arm64/asm.go b/src/cmd/link/internal/arm64/asm.go
index 5b3b9e5..d899d45 100644
--- a/src/cmd/link/internal/arm64/asm.go
+++ b/src/cmd/link/internal/arm64/asm.go
@@ -363,7 +363,7 @@
 		return true
 	case objabi.R_ARM64_TLS_LE:
 		r.Done = false
-		if ctxt.HeadType != objabi.Hlinux {
+		if ctxt.HeadType != objabi.Hlinux && ctxt.HeadType != objabi.Hfuchsia {
 			ld.Errorf(s, "TLS reloc on unsupported OS %v", ctxt.HeadType)
 		}
 		// The TCB is two pointers. This is not documented anywhere, but is
@@ -514,6 +514,7 @@
 
 	case objabi.Hlinux,
 		objabi.Hfreebsd,
+		objabi.Hfuchsia,
 		objabi.Hnetbsd,
 		objabi.Hopenbsd,
 		objabi.Hnacl:
diff --git a/src/cmd/link/internal/arm64/obj.go b/src/cmd/link/internal/arm64/obj.go
index 405d22d..3a14d43 100644
--- a/src/cmd/link/internal/arm64/obj.go
+++ b/src/cmd/link/internal/arm64/obj.go
@@ -87,7 +87,7 @@
 			*ld.FlagRound = 4096
 		}
 
-	case objabi.Hlinux: /* arm64 elf */
+	case objabi.Hlinux, objabi.Hfuchsia: /* arm64 elf */
 		ld.Elfinit(ctxt)
 		ld.HEADR = ld.ELFRESERVE
 		if *ld.FlagTextAddr == -1 {
diff --git a/src/cmd/link/internal/ld/config.go b/src/cmd/link/internal/ld/config.go
index 18fbea6..f9d438c 100644
--- a/src/cmd/link/internal/ld/config.go
+++ b/src/cmd/link/internal/ld/config.go
@@ -35,10 +35,13 @@
 	default:
 		return fmt.Errorf("invalid buildmode: %q", s)
 	case "exe":
+		if objabi.GOOS == "fuchsia" {
+			return badmode()
+		}
 		*mode = BuildModeExe
 	case "pie":
 		switch objabi.GOOS {
-		case "android", "linux":
+		case "android", "linux", "fuchsia":
 		case "darwin", "freebsd":
 			switch objabi.GOARCH {
 			case "amd64":
diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go
index 0ae93f1..a2b4443 100644
--- a/src/cmd/link/internal/ld/data.go
+++ b/src/cmd/link/internal/ld/data.go
@@ -162,8 +162,8 @@
 		}
 
 		// We need to be able to reference dynimport symbols when linking against
-		// shared libraries, and Solaris and Darwin need it always
-		if ctxt.HeadType != objabi.Hsolaris && ctxt.HeadType != objabi.Hdarwin && r.Sym != nil && r.Sym.Type == sym.SDYNIMPORT && !ctxt.DynlinkingGo() && !r.Sym.Attr.SubSymbol() {
+		// shared libraries; Solaris, Fuchsia, and Darwin need it always
+		if ctxt.HeadType != objabi.Hsolaris && ctxt.HeadType != objabi.Hdarwin && ctxt.HeadType != objabi.Hfuchsia && r.Sym != nil && r.Sym.Type == sym.SDYNIMPORT && !ctxt.DynlinkingGo() && !r.Sym.Attr.SubSymbol() {
 			if !(ctxt.Arch.Family == sys.PPC64 && ctxt.LinkMode == LinkExternal && r.Sym.Name == ".TOC.") {
 				Errorf(s, "unhandled relocation for %s (type %d (%s) rtype %d (%s))", r.Sym.Name, r.Sym.Type, r.Sym.Type, r.Type, sym.RelocName(ctxt.Arch, r.Type))
 			}
diff --git a/src/cmd/link/internal/ld/elf.go b/src/cmd/link/internal/ld/elf.go
index 4ecbff8..49089c0 100644
--- a/src/cmd/link/internal/ld/elf.go
+++ b/src/cmd/link/internal/ld/elf.go
@@ -1848,6 +1848,9 @@
 			case objabi.Hfreebsd:
 				interpreter = thearch.Freebsddynld
 
+			case objabi.Hfuchsia:
+				interpreter = "lib/ld.so.1"
+
 			case objabi.Hnetbsd:
 				interpreter = thearch.Netbsddynld
 
@@ -2085,7 +2088,7 @@
 		}
 	}
 
-	if ctxt.HeadType == objabi.Hlinux {
+	if ctxt.HeadType == objabi.Hlinux || ctxt.HeadType == objabi.Hfuchsia {
 		ph := newElfPhdr()
 		ph.type_ = PT_GNU_STACK
 		ph.flags = PF_W + PF_R
diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go
index 220aab3..d89bbea 100644
--- a/src/cmd/link/internal/ld/lib.go
+++ b/src/cmd/link/internal/ld/lib.go
@@ -1213,7 +1213,10 @@
 	}
 
 	// Force global symbols to be exported for dlopen, etc.
-	if ctxt.IsELF {
+	if ctxt.HeadType == objabi.Hfuchsia && !strings.Contains(argv[0], "clang") {
+		// Find libgcc
+		argv = append(argv, ctxt.findLibPathCmd("--print-libgcc-file-name", "libgcc"))
+	} else if ctxt.IsELF {
 		argv = append(argv, "-rdynamic")
 	}
 
@@ -1314,6 +1317,9 @@
 		argv = append(argv, "-Wl,--start-group", "-lmingwex", "-lmingw32", "-Wl,--end-group")
 		argv = append(argv, peimporteddlls()...)
 	}
+	if ctxt.HeadType == objabi.Hfuchsia && strings.Contains(argv[0], "clang") {
+		argv = append(argv, "-lzircon", "-lfdio")
+	}
 
 	if ctxt.Debugvlog != 0 {
 		ctxt.Logf("%5.2f host link:", Cputime())
diff --git a/src/cmd/link/internal/ld/sym.go b/src/cmd/link/internal/ld/sym.go
index 3aa90c1..d8ea7ed 100644
--- a/src/cmd/link/internal/ld/sym.go
+++ b/src/cmd/link/internal/ld/sym.go
@@ -96,6 +96,9 @@
 			ctxt.Tlsoffset = -1 * ctxt.Arch.PtrSize
 		}
 
+	case objabi.Hfuchsia:
+		ctxt.Tlsoffset = -1 * ctxt.Arch.PtrSize
+
 	case objabi.Hnacl:
 		switch ctxt.Arch.Family {
 		default:
diff --git a/src/crypto/rand/rand_fuchsia.go b/src/crypto/rand/rand_fuchsia.go
new file mode 100644
index 0000000..40be276
--- /dev/null
+++ b/src/crypto/rand/rand_fuchsia.go
@@ -0,0 +1,25 @@
+// Copyright 2016 The Go 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 fuchsia
+
+package rand
+
+import "syscall/zx"
+
+func init() {
+	Reader = new(cprngReader)
+}
+
+// cprngReader uses the PRNG exposed by zircon syscall.
+//
+// TODO(crawshaw): does it perform as well as /dev/urandom?
+// If not, borrow newReader from rand_unix.go and use this
+// as the entropy source.
+type cprngReader struct{}
+
+func (r *cprngReader) Read(b []byte) (n int, err error) {
+	zx.RandRead(b)
+	return len(b), nil
+}
diff --git a/src/crypto/x509/root_darwin_armx.go b/src/crypto/x509/root_darwin_armx.go
index fcbbd6b..87c9334 100644
--- a/src/crypto/x509/root_darwin_armx.go
+++ b/src/crypto/x509/root_darwin_armx.go
@@ -4,9 +4,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build cgo
-// +build darwin
-// +build arm arm64 ios
+// +build cgo,darwin,arm cgo,darwin,arm64 ios fuchsia
 
 package x509
 
diff --git a/src/crypto/x509/root_fuchsia.go b/src/crypto/x509/root_fuchsia.go
new file mode 100644
index 0000000..bf37319
--- /dev/null
+++ b/src/crypto/x509/root_fuchsia.go
@@ -0,0 +1,9 @@
+// Copyright 2016 The Go 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
+
+func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) {
+	return nil, nil
+}
diff --git a/src/go/build/syslist.go b/src/go/build/syslist.go
index d7938fa..2ccc386 100644
--- a/src/go/build/syslist.go
+++ b/src/go/build/syslist.go
@@ -4,5 +4,5 @@
 
 package build
 
-const goosList = "android darwin dragonfly freebsd js linux nacl netbsd openbsd plan9 solaris windows zos "
+const goosList = "android darwin dragonfly freebsd fuchsia js linux nacl netbsd openbsd plan9 solaris windows zos "
 const goarchList = "386 amd64 amd64p32 arm armbe arm64 arm64be ppc64 ppc64le mips mipsle mips64 mips64le mips64p32 mips64p32le ppc riscv riscv64 s390 s390x sparc sparc64 wasm "
diff --git a/src/internal/poll/fd_fuchsia.go b/src/internal/poll/fd_fuchsia.go
new file mode 100644
index 0000000..ccdd9e5
--- /dev/null
+++ b/src/internal/poll/fd_fuchsia.go
@@ -0,0 +1,305 @@
+// Copyright 2017 The Go 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 poll
+
+import (
+	"io"
+	"sync/atomic"
+	"syscall"
+	"syscall/zx/fdio"
+	"syscall/zx/zxsocket"
+)
+
+// FD is a file descriptor. The net and os packages embed this type in
+// a larger type representing a network connection or OS file.
+type FD struct {
+	// Lock sysfd and serialize access to Read and Write methods.
+	fdmu fdMutex
+
+	// System file descriptor. Immutable until Close.
+	Sysfd  int
+	Handle fdio.FDIO
+
+	// I/O poller.
+	pd pollDesc
+
+	// Semaphore signaled when file is closed.
+	csema uint32
+
+	// Whether this is a streaming descriptor, as opposed to a
+	// packet-based descriptor like a UDP socket.
+	IsStream bool
+
+	// Whether a zero byte read indicates EOF. This is false for a
+	// message based socket connection.
+	ZeroReadIsEOF bool
+
+	// Whether this is a normal file.
+	isFile bool
+
+	// Whether in blocking mode
+	isBlocking uint32
+}
+
+// Init initializes the FD. The Sysfd field should already be set.
+// This can be called multiple times on a single FD.
+// The net argument is a network name from the net package (e.g., "tcp"),
+// or "file".
+// Set pollable to true if fd should be managed by runtime netpoll.
+func (fd *FD) Init(net string, pollable bool) error {
+	// We don't actually care about the various network types.
+	if net == "file" {
+		fd.isFile = true
+	}
+	if fd.Handle == nil {
+		fd.Handle = syscall.FDIOForFD(fd.Sysfd)
+		if fd.Handle == nil {
+			panic("No Handle available")
+		}
+	}
+	if !pollable {
+		fd.isBlocking = 1
+		return nil
+	}
+	return fd.pd.init(fd)
+}
+
+// Destroy closes the file descriptor. This is called when there are
+// no remaining references.
+func (fd *FD) destroy() error {
+	// Poller may want to unregister fd in readiness notification mechanism,
+	// so this must be executed before closing the fd.
+	fd.pd.close()
+	err := fd.Handle.Close()
+	fd.Sysfd = -1
+	fd.Handle = nil
+	runtime_Semrelease(&fd.csema)
+	return err
+}
+
+// Close closes the FD. The underlying file descriptor is closed by the
+// destroy method when there are no remaining references.
+func (fd *FD) Close() error {
+	if !fd.fdmu.increfAndClose() {
+		return errClosing(fd.isFile)
+	}
+	fd.pd.evict()
+	err := fd.decref()
+	// Wait until the descriptor is closed. If this was the only
+	// reference, it is already closed.
+	runtime_Semacquire(&fd.csema)
+	return err
+}
+
+// Shutdown wraps the shutdown network call.
+func (fd *FD) Shutdown(how int) error {
+	if err := fd.incref(); err != nil {
+		return err
+	}
+	defer fd.decref()
+	panic("TODO shutdown")
+	//return syscall.Shutdown(fd.Sysfd, how) // TODO
+}
+
+func (fd *FD) Read(p []byte) (int, error) {
+	if err := fd.readLock(); err != nil {
+		return 0, err
+	}
+	defer fd.readUnlock()
+	if len(p) == 0 {
+		// If the caller wanted a zero byte read, return immediately
+		// without trying (but after acquiring the readLock).
+		return 0, nil
+	}
+	if err := fd.pd.prepareRead(fd.isFile); err != nil {
+		return 0, err
+	}
+	// TODO: pollable() read
+	n, err := syscall.Read(fd.Sysfd, p)
+	err = fd.eofError(n, err)
+	return n, err
+}
+
+// Pread wraps the pread system call.
+func (fd *FD) Pread(p []byte, off int64) (int, error) {
+	// Call incref, not readLock, because since pread specifies the
+	// offset it is independent from other reads.
+	// Similarly, using the poller doesn't make sense for pread.
+	if err := fd.incref(); err != nil {
+		return 0, err
+	}
+	n, err := syscall.Pread(fd.Sysfd, p, off)
+	if err != nil {
+		n = 0
+	}
+	fd.decref()
+	err = fd.eofError(n, err)
+	return n, err
+}
+
+// Write implements io.Writer.
+func (fd *FD) Write(p []byte) (int, error) {
+	if err := fd.writeLock(); err != nil {
+		return 0, err
+	}
+	defer fd.writeUnlock()
+	if err := fd.pd.prepareWrite(fd.isFile); err != nil {
+		return 0, err
+	}
+	var nn int
+	for {
+		n, err := fd.Handle.Write(p[nn:])
+		if n > 0 {
+			nn += n
+		}
+		if nn == len(p) {
+			return nn, err
+		}
+		if n == 0 {
+			return nn, io.ErrUnexpectedEOF
+		}
+	}
+}
+
+// Pwrite wraps the pwrite system call.
+func (fd *FD) Pwrite(p []byte, off int64) (int, error) {
+	// Call incref, not writeLock, because since pwrite specifies the
+	// offset it is independent from other writes.
+	// Similarly, using the poller doesn't make sense for pwrite.
+	if err := fd.incref(); err != nil {
+		return 0, err
+	}
+	defer fd.decref()
+	var nn int
+	for {
+		n, err := syscall.Pwrite(fd.Sysfd, p[nn:], off+int64(nn))
+		if n > 0 {
+			nn += n
+		}
+		if nn == len(p) {
+			return nn, err
+		}
+		if err != nil {
+			return nn, err
+		}
+		if n == 0 {
+			return nn, io.ErrUnexpectedEOF
+		}
+	}
+}
+
+// Accept wraps the accept network call.
+func (fd *FD) Accept() (newm *zxsocket.Socket, err error) {
+	if err := fd.readLock(); err != nil {
+		return nil, err
+	}
+	defer fd.readUnlock()
+
+	if err := fd.pd.prepareRead(fd.isFile); err != nil {
+		return nil, err
+	}
+
+	return fd.Handle.(*zxsocket.Socket).Accept()
+}
+
+// Seek wraps syscall.Seek.
+func (fd *FD) Seek(offset int64, whence int) (int64, error) {
+	if err := fd.incref(); err != nil {
+		return 0, err
+	}
+	defer fd.decref()
+	return syscall.Seek(fd.Sysfd, offset, whence)
+}
+
+// ReadDirent wraps syscall.ReadDirent.
+// We treat this like an ordinary system call rather than a call
+// that tries to fill the buffer.
+func (fd *FD) ReadDirent(buf []byte) (int, error) {
+	if err := fd.incref(); err != nil {
+		return 0, err
+	}
+	defer fd.decref()
+	return syscall.ReadDirent(fd.Sysfd, buf)
+}
+
+// Fstat wraps syscall.Fstat
+func (fd *FD) Fstat(s *syscall.Stat_t) error {
+	if err := fd.incref(); err != nil {
+		return err
+	}
+	defer fd.decref()
+	return syscall.Fstat(fd.Sysfd, s)
+}
+
+// eofError returns io.EOF when fd is available for reading end of
+// file.
+func (fd *FD) eofError(n int, err error) error {
+	if n == 0 && err == nil && fd.ZeroReadIsEOF {
+		return io.EOF
+	}
+	return err
+}
+
+// RawControl invokes the user-defined function f for a non-IO
+// operation.
+func (fd *FD) RawControl(f func(uintptr)) error {
+	if err := fd.incref(); err != nil {
+		return err
+	}
+	defer fd.decref()
+	f(uintptr(fd.Sysfd))
+	return nil
+}
+
+// RawRead invokes the user-defined function f for a read operation.
+func (fd *FD) RawRead(f func(uintptr) bool) error {
+	if err := fd.readLock(); err != nil {
+		return err
+	}
+	defer fd.readUnlock()
+	if err := fd.pd.prepareRead(fd.isFile); err != nil {
+		return err
+	}
+	for {
+		if f(uintptr(fd.Sysfd)) {
+			return nil
+		}
+		if err := fd.pd.waitRead(fd.isFile); err != nil {
+			return err
+		}
+	}
+}
+
+// RawWrite invokes the user-defined function f for a write operation.
+func (fd *FD) RawWrite(f func(uintptr) bool) error {
+	if err := fd.writeLock(); err != nil {
+		return err
+	}
+	defer fd.writeUnlock()
+	if err := fd.pd.prepareWrite(fd.isFile); err != nil {
+		return err
+	}
+	for {
+		if f(uintptr(fd.Sysfd)) {
+			return nil
+		}
+		if err := fd.pd.waitWrite(fd.isFile); err != nil {
+			return err
+		}
+	}
+}
+
+// SetBlocking puts the file into blocking mode.
+func (fd *FD) SetBlocking() error {
+	if err := fd.incref(); err != nil {
+		return err
+	}
+	defer fd.decref()
+	// Atomic store so that concurrent calls to SetBlocking
+	// do not cause a race condition. isBlocking only ever goes
+	// from 0 to 1 so there is no real race here.
+	atomic.StoreUint32(&fd.isBlocking, 1)
+	return syscall.SetNonblock(fd.Sysfd, false)
+}
diff --git a/src/internal/poll/fd_poll_fuchsia.go b/src/internal/poll/fd_poll_fuchsia.go
new file mode 100644
index 0000000..1ccc1c7
--- /dev/null
+++ b/src/internal/poll/fd_poll_fuchsia.go
@@ -0,0 +1,78 @@
+// 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.
+
+// TODO: use fd_poll_runtime.go for fuchsia
+
+package poll
+
+import (
+	"time"
+)
+
+type pollDesc struct {
+	fd      *FD
+	closing bool
+}
+
+func (pd *pollDesc) init(fd *FD) error { pd.fd = fd; return nil }
+
+func (pd *pollDesc) close() {}
+
+func (pd *pollDesc) evict() {
+	pd.closing = true
+	if pd.fd != nil {
+		// TODO syscall.StopIO(pd.fd.Sysfd)
+	}
+}
+
+func (pd *pollDesc) prepare(mode int, isFile bool) error {
+	if pd.closing {
+		return errClosing(isFile)
+	}
+	return nil
+}
+
+func (pd *pollDesc) prepareRead(isFile bool) error { return pd.prepare('r', isFile) }
+
+func (pd *pollDesc) prepareWrite(isFile bool) error { return pd.prepare('w', isFile) }
+
+func (pd *pollDesc) wait(mode int, isFile bool) error {
+	if pd.closing {
+		return errClosing(isFile)
+	}
+	return ErrTimeout
+}
+
+func (pd *pollDesc) waitRead(isFile bool) error { return pd.wait('r', isFile) }
+
+func (pd *pollDesc) waitWrite(isFile bool) error { return pd.wait('w', isFile) }
+
+func (pd *pollDesc) waitCanceled(mode int) {}
+
+func (pd *pollDesc) pollable() bool { return true }
+
+// SetDeadline sets the read and write deadlines associated with fd.
+func (fd *FD) SetDeadline(t time.Time) error {
+	return setDeadlineImpl(fd, t, 'r'+'w')
+}
+
+// SetReadDeadline sets the read deadline associated with fd.
+func (fd *FD) SetReadDeadline(t time.Time) error {
+	return setDeadlineImpl(fd, t, 'r')
+}
+
+// SetWriteDeadline sets the write deadline associated with fd.
+func (fd *FD) SetWriteDeadline(t time.Time) error {
+	return setDeadlineImpl(fd, t, 'w')
+}
+
+func setDeadlineImpl(fd *FD, t time.Time, mode int) error {
+	return ErrNoDeadline // TODO set deadline
+}
+
+// PollDescriptor returns the descriptor being used by the poller,
+// or ^uintptr(0) if there isn't one. This is only used for testing.
+func PollDescriptor() uintptr {
+	return ^uintptr(0)
+}
diff --git a/src/internal/syscall/unix/nonblocking_fuchsia.go b/src/internal/syscall/unix/nonblocking_fuchsia.go
new file mode 100644
index 0000000..ff67c75
--- /dev/null
+++ b/src/internal/syscall/unix/nonblocking_fuchsia.go
@@ -0,0 +1,9 @@
+// Copyright 2018 The Go 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 unix
+
+func IsNonblock(fd int) (nonblocking bool, err error) {
+	return false, nil
+}
diff --git a/src/internal/syscall/unix/stub_fuchsia.go b/src/internal/syscall/unix/stub_fuchsia.go
new file mode 100644
index 0000000..2d7b8de
--- /dev/null
+++ b/src/internal/syscall/unix/stub_fuchsia.go
@@ -0,0 +1,7 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file exists to make the go tool happy.
+
+package unix
diff --git a/src/internal/testenv/testenv.go b/src/internal/testenv/testenv.go
index 8f69fe0..fd09e35 100644
--- a/src/internal/testenv/testenv.go
+++ b/src/internal/testenv/testenv.go
@@ -149,7 +149,7 @@
 // HasExternalNetwork reports whether the current system can use
 // external (non-localhost) networks.
 func HasExternalNetwork() bool {
-	return !testing.Short() && runtime.GOOS != "nacl" && runtime.GOOS != "js"
+	return !testing.Short() && runtime.GOOS != "nacl" && runtime.GOOS != "js" && runtime.GOOS != "fuchsia"
 }
 
 // MustHaveExternalNetwork checks that the current system can use
@@ -162,6 +162,10 @@
 	if testing.Short() {
 		t.Skipf("skipping test: no external network in -short mode")
 	}
+
+	if runtime.GOOS == "fuchsia" {
+		t.Skipf("external network tests disabled on fuchsia; not all builders have one.")
+	}
 }
 
 var haveCGO bool
@@ -209,6 +213,11 @@
 	}
 }
 
+// HasChmod reports whether the current system can use os.Chmod.
+func HasChmod() bool {
+	return runtime.GOOS != "fuchsia"
+}
+
 var flaky = flag.Bool("flaky", false, "run known-flaky tests too")
 
 func SkipFlaky(t testing.TB, issue int) {
diff --git a/src/internal/testenv/testenv_notwin.go b/src/internal/testenv/testenv_notwin.go
index d8ce6cd..e587e6a 100644
--- a/src/internal/testenv/testenv_notwin.go
+++ b/src/internal/testenv/testenv_notwin.go
@@ -12,7 +12,7 @@
 
 func hasSymlink() (ok bool, reason string) {
 	switch runtime.GOOS {
-	case "android", "nacl", "plan9":
+	case "android", "nacl", "plan9", "fuchsia":
 		return false, ""
 	}
 
diff --git a/src/io/io_fuchsia.go b/src/io/io_fuchsia.go
new file mode 100644
index 0000000..ac81e67
--- /dev/null
+++ b/src/io/io_fuchsia.go
@@ -0,0 +1,15 @@
+// Copyright 2016 The Go 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 fuchsia
+
+package io
+
+import (
+	"syscall/zx"
+)
+
+func init() {
+	zx.EOF = EOF
+}
diff --git a/src/mime/type_fuchsia.go b/src/mime/type_fuchsia.go
new file mode 100644
index 0000000..986c0bb
--- /dev/null
+++ b/src/mime/type_fuchsia.go
@@ -0,0 +1,15 @@
+// Copyright 2017 The Go 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 fuchsia
+
+package mime
+
+func init() {
+	osInitMime = initMimeFuchsia
+}
+
+func initMimeFuchsia() {
+	// TODO: find an equivalent to /etc/mime.types.
+}
diff --git a/src/net/addrselect.go b/src/net/addrselect.go
index 1ab9fc5..16871fc 100644
--- a/src/net/addrselect.go
+++ b/src/net/addrselect.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build darwin dragonfly freebsd fuchsia linux netbsd openbsd solaris
 
 // Minimal RFC 6724 address selection.
 
diff --git a/src/net/cgo_stub.go b/src/net/cgo_stub.go
index 5125972..94c95b5 100644
--- a/src/net/cgo_stub.go
+++ b/src/net/cgo_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 !cgo netgo
+// +build !cgo netgo fuchsia
 
 package net
 
diff --git a/src/net/conf.go b/src/net/conf.go
index 71ed136..fa7dcf4 100644
--- a/src/net/conf.go
+++ b/src/net/conf.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build darwin dragonfly freebsd fuchsia linux netbsd openbsd solaris
 
 package net
 
diff --git a/src/net/dial_test.go b/src/net/dial_test.go
index 00a84d1..cfc4c37 100644
--- a/src/net/dial_test.go
+++ b/src/net/dial_test.go
@@ -77,7 +77,7 @@
 
 func TestDialerDualStackFDLeak(t *testing.T) {
 	switch runtime.GOOS {
-	case "plan9":
+	case "plan9", "fuchsia":
 		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)
@@ -431,6 +431,10 @@
 	if !supportsIPv4() || !supportsIPv6() {
 		t.Skip("both IPv4 and IPv6 are required")
 	}
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
 
 	var wg sync.WaitGroup
 	wg.Add(2)
@@ -541,6 +545,10 @@
 	if !supportsIPv4() || !supportsIPv6() {
 		t.Skip("both IPv4 and IPv6 are required")
 	}
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
 
 	type test struct {
 		network, raddr string
@@ -712,6 +720,11 @@
 }
 
 func TestDialerKeepAlive(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
+
 	handler := func(ls *localServer, ln Listener) {
 		for {
 			c, err := ln.Accept()
@@ -815,6 +828,10 @@
 }
 
 func TestCancelAfterDial(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
 	if testing.Short() {
 		t.Skip("avoiding time.Sleep")
 	}
@@ -916,7 +933,7 @@
 
 func TestDialerControl(t *testing.T) {
 	switch runtime.GOOS {
-	case "nacl", "plan9":
+	case "fuchsia", "nacl", "plan9":
 		t.Skipf("not supported on %s", runtime.GOOS)
 	}
 
diff --git a/src/net/dnsclient_unix.go b/src/net/dnsclient_unix.go
index 2fee334..bd3b7ae 100644
--- a/src/net/dnsclient_unix.go
+++ b/src/net/dnsclient_unix.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build darwin dragonfly freebsd fuchsia linux netbsd openbsd solaris
 
 // DNS client: see RFC 1035.
 // Has to be linked into package net for Dial.
diff --git a/src/net/dnsconfig_fuchsia.go b/src/net/dnsconfig_fuchsia.go
new file mode 100644
index 0000000..c13658b
--- /dev/null
+++ b/src/net/dnsconfig_fuchsia.go
@@ -0,0 +1,44 @@
+// Copyright 2017 The Go 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 fuchsia
+
+// TODO: use dnsconfig_unix when 127.0.0.1:53 is a valid DNS server.
+
+package net
+
+import (
+	"os"
+	"time"
+)
+
+var (
+	defaultNS   = []string{"8.8.8.8:53"}
+	getHostname = os.Hostname // variable for testing
+)
+
+type dnsConfig struct {
+	servers    []string
+	attempts   int
+	timeout    time.Duration
+	search     []string
+	ndots      int
+	rotate     bool
+	unknownOpt bool
+	lookup     []string
+	err        error
+	mtime      time.Time
+	soffset    uint32
+}
+
+func dnsReadConfig(filename string) *dnsConfig {
+	return &dnsConfig{
+		ndots:    1,
+		timeout:  5 * time.Second,
+		attempts: 2,
+		servers:  defaultNS,
+	}
+}
+
+func (c *dnsConfig) serverOffset() uint32 { return 0 }
diff --git a/src/net/dnsconfig_unix.go b/src/net/dnsconfig_unix.go
index 707fd6f..348d2a4 100644
--- a/src/net/dnsconfig_unix.go
+++ b/src/net/dnsconfig_unix.go
@@ -15,7 +15,7 @@
 )
 
 var (
-	defaultNS   = []string{"127.0.0.1:53", "[::1]:53"}
+	defaultNS   = []string{"8.8.8.8:53"}
 	getHostname = os.Hostname // variable for testing
 )
 
diff --git a/src/net/error_fuchsia.go b/src/net/error_fuchsia.go
new file mode 100644
index 0000000..caad133
--- /dev/null
+++ b/src/net/error_fuchsia.go
@@ -0,0 +1,9 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package net
+
+func isConnError(err error) bool {
+	return false
+}
diff --git a/src/net/error_fuchsia_test.go b/src/net/error_fuchsia_test.go
new file mode 100644
index 0000000..a72a2b8
--- /dev/null
+++ b/src/net/error_fuchsia_test.go
@@ -0,0 +1,35 @@
+// Copyright 2018 The Go 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 fuchsia !plan9,!windows,!unix
+
+package net
+
+import (
+	"os"
+	"syscall"
+	"syscall/zx"
+)
+
+var (
+	errTimedout       = syscall.ETIMEDOUT
+	errOpNotSupported = syscall.EOPNOTSUPP
+
+	abortedConnRequestErrors = []error{syscall.ECONNABORTED} // see accept in fd_unix.go
+)
+
+func isPlatformError(err error) bool {
+	_, ok := err.(zx.Error)
+	return ok
+}
+
+func samePlatformError(err, want error) bool {
+	if op, ok := err.(*OpError); ok {
+		err = op.Err
+	}
+	if sys, ok := err.(*os.SyscallError); ok {
+		err = sys.Err
+	}
+	return err == want
+}
diff --git a/src/net/error_posix_test.go b/src/net/error_posix_test.go
index b411a37..ab44e70 100644
--- a/src/net/error_posix_test.go
+++ b/src/net/error_posix_test.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build !plan9
+// +build !plan9,!fuchsia
 
 package net
 
diff --git a/src/net/error_test.go b/src/net/error_test.go
index e09670e..0a9ebd0 100644
--- a/src/net/error_test.go
+++ b/src/net/error_test.go
@@ -137,8 +137,9 @@
 }
 
 func TestDialError(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
 	switch runtime.GOOS {
-	case "plan9":
+	case "plan9", "fuchsia":
 		t.Skipf("%s does not have full support of socktest", runtime.GOOS)
 	}
 
@@ -184,6 +185,10 @@
 }
 
 func TestProtocolDialError(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
 	switch runtime.GOOS {
 	case "nacl", "solaris":
 		t.Skipf("not supported on %s", runtime.GOOS)
@@ -286,6 +291,10 @@
 }
 
 func TestListenError(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
 	switch runtime.GOOS {
 	case "plan9":
 		t.Skipf("%s does not have full support of socktest", runtime.GOOS)
@@ -346,6 +355,10 @@
 }
 
 func TestListenPacketError(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
 	switch runtime.GOOS {
 	case "plan9":
 		t.Skipf("%s does not have full support of socktest", runtime.GOOS)
@@ -375,6 +388,10 @@
 }
 
 func TestProtocolListenError(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
 	switch runtime.GOOS {
 	case "nacl", "plan9":
 		t.Skipf("not supported on %s", runtime.GOOS)
@@ -548,6 +565,10 @@
 }
 
 func TestCloseError(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
 	ln, err := newLocalListener("tcp")
 	if err != nil {
 		t.Fatal(err)
@@ -582,6 +603,11 @@
 		}
 	}
 
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
+
 	pc, err := ListenPacket("udp", "127.0.0.1:0")
 	if err != nil {
 		t.Fatal(err)
@@ -640,6 +666,11 @@
 }
 
 func TestAcceptError(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
+
 	handler := func(ls *localServer, ln Listener) {
 		for {
 			ln.(*TCPListener).SetDeadline(time.Now().Add(5 * time.Millisecond))
@@ -719,6 +750,10 @@
 }
 
 func TestFileError(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
 	switch runtime.GOOS {
 	case "windows":
 		t.Skipf("not supported on %s", runtime.GOOS)
diff --git a/src/net/error_unix_test.go b/src/net/error_unix_test.go
index 9ce9e12..441ca49 100644
--- a/src/net/error_unix_test.go
+++ b/src/net/error_unix_test.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build !plan9,!windows
+// +build !plan9,!windows,!fuchsia
 
 package net
 
diff --git a/src/net/fd_fuchsia.go b/src/net/fd_fuchsia.go
new file mode 100644
index 0000000..385bd0f
--- /dev/null
+++ b/src/net/fd_fuchsia.go
@@ -0,0 +1,146 @@
+// Copyright 2016 The Go 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: move to using fd_unix for fuchsia?
+
+package net
+
+import (
+	"errors"
+	"internal/poll"
+	"os"
+	"runtime"
+	"syscall"
+	"syscall/zx/mxnet"
+	"syscall/zx/zxsocket"
+	"time"
+)
+
+// Network file descriptor.
+type netFD struct {
+	pfd poll.FD
+
+	// immutable until Close
+	net         string
+	family      int
+	sotype      int
+	isStream    bool
+	isConnected bool
+	laddr       Addr
+	raddr       Addr
+}
+
+func newFD(handle *zxsocket.Socket, family, sotype int, net string) *netFD {
+	netfd := &netFD{
+		pfd: poll.FD{
+			Sysfd:  syscall.OpenFDIO(handle),
+			Handle: handle,
+		},
+		family: family,
+		sotype: sotype,
+		net:    net,
+	}
+	return netfd
+}
+
+func (fd *netFD) destroy() {
+	panic("TODO")
+}
+
+func sysInit() {
+}
+
+func (fd *netFD) isTCP() bool {
+	return len(fd.net) >= 3 && fd.net[:3] == "tcp"
+}
+
+func (fd *netFD) Read(b []byte) (n int, err error) {
+	n, err = fd.pfd.Read(b)
+	runtime.KeepAlive(fd)
+	return n, err
+}
+
+func (fd *netFD) Write(b []byte) (n int, err error) {
+	n, err = fd.pfd.Write(b)
+	runtime.KeepAlive(fd)
+	return n, err
+}
+
+func (fd *netFD) readMsg(b []byte) (n, flags int, addr string, port uint16, err error) {
+	// TODO: move call to pfd
+	data, flags, addr, port, err := fd.pfd.Handle.(*zxsocket.Socket).RecvMsg(len(b))
+	runtime.KeepAlive(fd)
+	n = copy(b, data)
+	return n, flags, addr, port, err
+}
+
+func (fd *netFD) sendMsg(b []byte, addr string, port uint16) (n int, err error) {
+	// TODO: move call to pfd
+	n, err = fd.pfd.Handle.(*zxsocket.Socket).SendMsg(b, addr, port)
+	runtime.KeepAlive(fd)
+	return n, err
+}
+
+func (fd *netFD) closeRead() error {
+	return errors.New("net: closeRead not implemented on fuchsia")
+}
+
+func (fd *netFD) closeWrite() error {
+	return errors.New("net: closeWrite not implemented on fuchsia")
+}
+
+func (fd *netFD) Close() error {
+	return fd.pfd.Close()
+}
+
+func (fd *netFD) dup() (*os.File, error) {
+	// TODO(mknyszek): fd.sock is an FDIO so one can make an FD from it to
+	// implement this.
+	return nil, errors.New("net: dup not implemented on fuchsia")
+}
+
+func (fd *netFD) accept() (netfd *netFD, err error) {
+	newm, err := fd.pfd.Accept()
+	if err != nil {
+		return nil, err
+	}
+	netfd = newFD(newm, fd.family, fd.sotype, fd.net)
+	netfd.setAddr()
+	return netfd, nil
+}
+
+func (fd *netFD) asAddr(ipAddr mxnet.Addr, port uint16, err error) sockaddr {
+	if err != nil {
+		return nil
+	}
+	ip := IP(ipAddr)
+	if isZeros(ip) && port == 0 {
+		return nil
+	}
+	switch fd.sotype {
+	case syscall.SOCK_STREAM:
+		return &TCPAddr{IP: ip, Port: int(port)}
+	case syscall.SOCK_DGRAM:
+		return &UDPAddr{IP: ip, Port: int(port)}
+	}
+	return nil
+}
+
+func (fd *netFD) setAddr() {
+	fd.laddr = fd.asAddr(fd.pfd.Handle.(*zxsocket.Socket).SockName())
+	fd.raddr = fd.asAddr(fd.pfd.Handle.(*zxsocket.Socket).PeerName())
+	runtime.SetFinalizer(fd, (*netFD).Close)
+}
+
+func (fd *netFD) SetDeadline(t time.Time) error {
+	return fd.pfd.SetDeadline(t)
+}
+
+func (fd *netFD) SetReadDeadline(t time.Time) error {
+	return fd.pfd.SetReadDeadline(t)
+}
+
+func (fd *netFD) SetWriteDeadline(t time.Time) error {
+	return fd.pfd.SetWriteDeadline(t)
+}
diff --git a/src/net/file_stub.go b/src/net/file_stub.go
index 2256608..dce5470 100644
--- a/src/net/file_stub.go
+++ b/src/net/file_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 nacl js,wasm
+// +build nacl js,wasm fuchsia
 
 package net
 
diff --git a/src/net/file_test.go b/src/net/file_test.go
index cd71774..87aeaf6 100644
--- a/src/net/file_test.go
+++ b/src/net/file_test.go
@@ -30,8 +30,9 @@
 }
 
 func TestFileConn(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
 	switch runtime.GOOS {
-	case "nacl", "plan9", "windows":
+	case "nacl", "plan9", "windows", "fuchsia":
 		t.Skipf("not supported on %s", runtime.GOOS)
 	}
 
@@ -137,8 +138,9 @@
 }
 
 func TestFileListener(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
 	switch runtime.GOOS {
-	case "nacl", "plan9", "windows":
+	case "nacl", "plan9", "windows", "fuchsia":
 		t.Skipf("not supported on %s", runtime.GOOS)
 	}
 
@@ -229,8 +231,9 @@
 }
 
 func TestFilePacketConn(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
 	switch runtime.GOOS {
-	case "nacl", "plan9", "windows":
+	case "nacl", "plan9", "windows", "fuchsia":
 		t.Skipf("not supported on %s", runtime.GOOS)
 	}
 
@@ -297,7 +300,7 @@
 // Issue 24483.
 func TestFileCloseRace(t *testing.T) {
 	switch runtime.GOOS {
-	case "nacl", "plan9", "windows":
+	case "fuchsia", "nacl", "plan9", "windows":
 		t.Skipf("not supported on %s", runtime.GOOS)
 	}
 	if !testableNetwork("tcp") {
diff --git a/src/net/hook_fuchsia.go b/src/net/hook_fuchsia.go
new file mode 100644
index 0000000..e445c1a
--- /dev/null
+++ b/src/net/hook_fuchsia.go
@@ -0,0 +1,17 @@
+// Copyright 2017 The Go 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 fuchsia
+
+package net
+
+import "syscall"
+
+var (
+	testHookDialChannel  = func() {} // for golang.org/issue/5349
+	testHookCanceledDial = func() {} // for golang.org/issue/16523
+
+	// Placeholders for socket system calls.
+	closeFunc func(int) error = syscall.Close
+)
diff --git a/src/net/hosts_test.go b/src/net/hosts_test.go
index f850e2f..3169866 100644
--- a/src/net/hosts_test.go
+++ b/src/net/hosts_test.go
@@ -6,6 +6,7 @@
 
 import (
 	"reflect"
+	"runtime"
 	"strings"
 	"testing"
 )
@@ -59,6 +60,11 @@
 }
 
 func TestLookupStaticHost(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
+
 	defer func(orig string) { testHookHostsPath = orig }(testHookHostsPath)
 
 	for _, tt := range lookupStaticHostTests {
@@ -128,6 +134,10 @@
 }
 
 func TestLookupStaticAddr(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
 	defer func(orig string) { testHookHostsPath = orig }(testHookHostsPath)
 
 	for _, tt := range lookupStaticAddrTests {
@@ -149,6 +159,10 @@
 }
 
 func TestHostCacheModification(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
 	// Ensure that programs can't modify the internals of the host cache.
 	// See https://golang.org/issues/14212.
 	defer func(orig string) { testHookHostsPath = orig }(testHookHostsPath)
diff --git a/src/net/interface_stub.go b/src/net/interface_stub.go
index 0afaa80..426ac46 100644
--- a/src/net/interface_stub.go
+++ b/src/net/interface_stub.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build nacl js,wasm
+// +build nacl js,wasm fuchsia
 
 package net
 
diff --git a/src/net/internal/socktest/switch_posix.go b/src/net/internal/socktest/switch_posix.go
index 863edef..0ead109 100644
--- a/src/net/internal/socktest/switch_posix.go
+++ b/src/net/internal/socktest/switch_posix.go
@@ -3,6 +3,7 @@
 // license that can be found in the LICENSE file.
 
 // +build !plan9
+// +build !fuchsia
 
 package socktest
 
diff --git a/src/net/internal/socktest/switch_stub.go b/src/net/internal/socktest/switch_stub.go
index 28ce72c..9ba7d73 100644
--- a/src/net/internal/socktest/switch_stub.go
+++ b/src/net/internal/socktest/switch_stub.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build plan9
+// +build plan9 fuchsia
 
 package socktest
 
diff --git a/src/net/ip_test.go b/src/net/ip_test.go
index a5fc5e6..cde5eca 100644
--- a/src/net/ip_test.go
+++ b/src/net/ip_test.go
@@ -61,6 +61,7 @@
 }
 
 func TestLookupWithIP(t *testing.T) {
+	mustHaveExternalNetwork(t)
 	_, err := LookupIP("")
 	if err == nil {
 		t.Errorf(`LookupIP("") succeeded, should fail`)
diff --git a/src/net/iprawsock_fuchsia.go b/src/net/iprawsock_fuchsia.go
new file mode 100644
index 0000000..0bfd133
--- /dev/null
+++ b/src/net/iprawsock_fuchsia.go
@@ -0,0 +1,34 @@
+// Copyright 2016 The Go 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 (
+	"context"
+	"syscall"
+)
+
+func (c *IPConn) readFrom(b []byte) (int, *IPAddr, error) {
+	return 0, nil, syscall.EFUCHSIA
+}
+
+func (c *IPConn) readMsg(b, oob []byte) (n, oobn, flags int, addr *IPAddr, err error) {
+	return 0, 0, 0, nil, syscall.EFUCHSIA
+}
+
+func (c *IPConn) writeTo(b []byte, addr *IPAddr) (int, error) {
+	return 0, syscall.EFUCHSIA
+}
+
+func (c *IPConn) writeMsg(b, oob []byte, addr *IPAddr) (n, oobn int, err error) {
+	return 0, 0, syscall.EFUCHSIA
+}
+
+func (sd *sysDialer) dialIP(ctx context.Context, laddr, raddr *IPAddr) (*IPConn, error) {
+	return nil, syscall.EFUCHSIA
+}
+
+func (sl *sysListener) listenIP(ctx context.Context, laddr *IPAddr) (*IPConn, error) {
+	return nil, syscall.EFUCHSIA
+}
diff --git a/src/net/iprawsock_test.go b/src/net/iprawsock_test.go
index 8e3543d..4985e88 100644
--- a/src/net/iprawsock_test.go
+++ b/src/net/iprawsock_test.go
@@ -8,6 +8,7 @@
 
 import (
 	"reflect"
+	"runtime"
 	"testing"
 )
 
@@ -88,6 +89,10 @@
 }
 
 func TestIPConnLocalName(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
 	for _, tt := range ipConnLocalNameTests {
 		if !testableNetwork(tt.net) {
 			t.Logf("skipping %s test", tt.net)
@@ -105,6 +110,10 @@
 }
 
 func TestIPConnRemoteName(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
 	if !testableNetwork("ip:tcp") {
 		t.Skip("ip:tcp test")
 	}
diff --git a/src/net/ipsock_fuchsia.go b/src/net/ipsock_fuchsia.go
new file mode 100644
index 0000000..4af25bb
--- /dev/null
+++ b/src/net/ipsock_fuchsia.go
@@ -0,0 +1,174 @@
+// Copyright 2016 The Go 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 (
+	"context"
+	"errors"
+	"sync"
+	"syscall"
+	"syscall/zx"
+	"syscall/zx/fdio"
+	"syscall/zx/fidl"
+	"syscall/zx/mxnet"
+	zxnet "syscall/zx/net"
+	"syscall/zx/zxsocket"
+	"time"
+)
+
+func (p *ipStackCapabilities) probe() {
+	p.ipv4Enabled = true
+	p.ipv6Enabled = true
+	p.ipv4MappedIPv6Enabled = true
+}
+
+// A sockaddr represents a TCP, UDP, IP or Unix network endpoint
+// address that can be converted into an fdio sockaddr message.
+type sockaddr interface {
+	Addr
+
+	family() int
+	isWildcard() bool
+	sockaddr(family int) (addr mxnet.Addr, port uint16, err error)
+}
+
+func favoriteAddrFamily(net string, laddr, raddr sockaddr, mode string) (family int, ipv6only bool) {
+	switch net[len(net)-1] {
+	case '4':
+		return syscall.AF_INET, false
+	case '6':
+		return syscall.AF_INET6, true
+	}
+
+	if mode == "listen" && (laddr == nil || laddr.isWildcard()) {
+		if supportsIPv4map() || !supportsIPv4() {
+			return syscall.AF_INET6, false
+		}
+		if laddr == nil {
+			return syscall.AF_INET, false
+		}
+		return laddr.family(), false
+	}
+
+	if (laddr == nil || laddr.family() == syscall.AF_INET) &&
+		(raddr == nil || raddr.family() == syscall.AF_INET) {
+		return syscall.AF_INET, false
+	}
+	return syscall.AF_INET6, false
+}
+
+type socketProviderInfo struct {
+	mu sync.Mutex
+	h  zx.Handle
+}
+
+var socketProvider socketProviderInfo
+
+func getSocketProvider() zx.Handle {
+	socketProvider.mu.Lock()
+	defer socketProvider.mu.Unlock()
+	if socketProvider.h == zx.HandleInvalid {
+		c0, c1, err := zx.NewChannel(0)
+		if err == nil {
+			err = fdio.ServiceConnect("/svc/fuchsia.net.LegacySocketProvider", zx.Handle(c0))
+			if err == nil {
+				socketProvider.h = zx.Handle(c1)
+			}
+		}
+	}
+	return socketProvider.h
+}
+
+func dialFuchsia(ctx context.Context, net string, laddr, raddr sockaddr) (fd *netFD, err error) {
+	family, _ := favoriteAddrFamily(net, laddr, raddr, "dial")
+
+	sotype := syscall.SOCK_STREAM
+	if len(net) >= 3 && net[:3] == "udp" {
+		sotype = syscall.SOCK_DGRAM
+	}
+	proto := syscall.IPPROTO_IP
+
+	var sock *zxsocket.Socket
+	// Wait for the network stack to publish the socket device.
+	// See similar logic in zircon/system/ulib/fdio/bsdsocket.c.
+	for i := 0; i < 40; i++ {
+		c := zx.Channel(getSocketProvider())
+		if c.Handle().IsValid() {
+			sp := zxnet.LegacySocketProviderInterface(fidl.Proxy{Channel: c})
+			s, _, err := sp.OpenSocket(zxnet.SocketDomain(family), zxnet.SocketType(sotype), zxnet.SocketProtocol(proto))
+			if err == nil {
+				sock = zxsocket.NewSocket(s)
+				break
+			}
+		}
+		time.Sleep(250 * time.Millisecond)
+	}
+	if err != nil {
+		return nil, err
+	}
+	if sotype == syscall.SOCK_DGRAM {
+		sock.SetDgram()
+	}
+
+	fd = newFD(sock, family, sotype, net)
+	if laddr != nil {
+		addr, port, err := laddr.sockaddr(family)
+		if err != nil {
+			return nil, err
+		}
+		if addr != "" || port != 0 {
+			if err := fd.pfd.Handle.(*zxsocket.Socket).Bind(addr, port); err != nil {
+				return nil, err
+			}
+		}
+		if raddr == nil {
+			switch sotype {
+			case syscall.SOCK_STREAM:
+				if err := fd.pfd.Handle.(*zxsocket.Socket).ListenStream(listenerBacklog); err != nil {
+					return nil, err
+				}
+			case syscall.SOCK_DGRAM:
+				return nil, errors.New("net: TODO listen datagram")
+			}
+		}
+	}
+	if raddr != nil {
+		addr, port, err := raddr.sockaddr(family)
+		if err != nil {
+			return nil, err
+		}
+		if err := fd.pfd.Handle.(*zxsocket.Socket).Connect(addr, port); err != nil {
+			return nil, err
+		}
+		fd.isConnected = true
+	}
+	fd.setAddr()
+
+	return fd, nil
+}
+
+func ipToSockaddr(family int, ip IP, port int, zone string) (addr mxnet.Addr, portres uint16, err error) {
+	switch family {
+	case syscall.AF_INET:
+		if len(ip) == 0 {
+			ip = IPv4zero
+		}
+		ip4 := ip.To4()
+		if ip4 == nil {
+			return "", 0, &AddrError{Err: "non-IPv4 address", Addr: ip.String()}
+		}
+		return mxnet.Addr(ip4)[:4], uint16(port), nil
+	case syscall.AF_INET6:
+		if len(ip) == 0 || ip.Equal(IPv4zero) {
+			ip = IPv6zero
+		}
+		ip6 := ip.To16()
+		if ip6 == nil {
+			return "", 0, &AddrError{Err: "non-IPv6 address", Addr: ip.String()}
+		}
+		return mxnet.Addr(ip6), uint16(port), nil
+	}
+	return "", 0, &AddrError{Err: "invalid address family", Addr: ip.String()}
+}
diff --git a/src/net/listen_test.go b/src/net/listen_test.go
index ffce8e2..971f233 100644
--- a/src/net/listen_test.go
+++ b/src/net/listen_test.go
@@ -63,6 +63,10 @@
 // listener with same address family, same listening address and
 // same port.
 func TestTCPListener(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
 	switch runtime.GOOS {
 	case "plan9":
 		t.Skipf("not supported on %s", runtime.GOOS)
@@ -124,8 +128,9 @@
 // listener with same address family, same listening address and
 // same port.
 func TestUDPListener(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
 	switch runtime.GOOS {
-	case "plan9":
+	case "plan9", "fuchsia":
 		t.Skipf("not supported on %s", runtime.GOOS)
 	}
 
@@ -223,6 +228,10 @@
 // On DragonFly BSD, we expect the kernel version of node under test
 // to be greater than or equal to 4.4.
 func TestDualStackTCPListener(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
 	switch runtime.GOOS {
 	case "nacl", "plan9":
 		t.Skipf("not supported on %s", runtime.GOOS)
@@ -313,8 +322,9 @@
 // On DragonFly BSD, we expect the kernel version of node under test
 // to be greater than or equal to 4.4.
 func TestDualStackUDPListener(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
 	switch runtime.GOOS {
-	case "nacl", "plan9":
+	case "nacl", "plan9", "fuchsia":
 		t.Skipf("not supported on %s", runtime.GOOS)
 	}
 	if !supportsIPv4() || !supportsIPv6() {
@@ -488,8 +498,9 @@
 func TestWildWildcardListener(t *testing.T) {
 	testenv.MustHaveExternalNetwork(t)
 
+	// TODO(TC-149): disabled without further triage. Needs work.
 	switch runtime.GOOS {
-	case "plan9":
+	case "plan9", "fuchsia":
 		t.Skipf("not supported on %s", runtime.GOOS)
 	}
 
@@ -531,8 +542,9 @@
 func TestIPv4MulticastListener(t *testing.T) {
 	testenv.MustHaveExternalNetwork(t)
 
+	// TODO(TC-149): disabled without further triage. Needs work.
 	switch runtime.GOOS {
-	case "android", "nacl", "plan9":
+	case "android", "nacl", "plan9", "fuchsia":
 		t.Skipf("not supported on %s", runtime.GOOS)
 	case "solaris":
 		t.Skipf("not supported on solaris, see golang.org/issue/7399")
@@ -606,8 +618,9 @@
 func TestIPv6MulticastListener(t *testing.T) {
 	testenv.MustHaveExternalNetwork(t)
 
+	// TODO(TC-149): disabled without further triage. Needs work.
 	switch runtime.GOOS {
-	case "plan9":
+	case "plan9", "fuchsia":
 		t.Skipf("not supported on %s", runtime.GOOS)
 	case "solaris":
 		t.Skipf("not supported on solaris, see issue 7399")
@@ -701,6 +714,11 @@
 
 // Issue 21856.
 func TestClosingListener(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
+
 	ln, err := newLocalListener("tcp")
 	if err != nil {
 		t.Fatal(err)
@@ -733,7 +751,7 @@
 
 func TestListenConfigControl(t *testing.T) {
 	switch runtime.GOOS {
-	case "nacl", "plan9":
+	case "fuchsia", "nacl", "plan9":
 		t.Skipf("not supported on %s", runtime.GOOS)
 	}
 
diff --git a/src/net/lookup_fuchsia.go b/src/net/lookup_fuchsia.go
new file mode 100644
index 0000000..b3d5f97
--- /dev/null
+++ b/src/net/lookup_fuchsia.go
@@ -0,0 +1,323 @@
+// 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 fuchsia linux netbsd openbsd solaris
+
+package net
+
+import (
+	"context"
+	"sync"
+
+	"golang_org/x/net/dns/dnsmessage"
+)
+
+var onceReadProtocols sync.Once
+
+// readProtocols loads contents of /etc/protocols into protocols map
+// for quick access.
+func readProtocols() {
+	file, err := open("/etc/protocols")
+	if err != nil {
+		return
+	}
+	defer file.close()
+
+	for line, ok := file.readLine(); ok; line, ok = file.readLine() {
+		// tcp    6   TCP    # transmission control protocol
+		if i := byteIndex(line, '#'); i >= 0 {
+			line = line[0:i]
+		}
+		f := getFields(line)
+		if len(f) < 2 {
+			continue
+		}
+		if proto, _, ok := dtoi(f[1]); ok {
+			if _, ok := protocols[f[0]]; !ok {
+				protocols[f[0]] = proto
+			}
+			for _, alias := range f[2:] {
+				if _, ok := protocols[alias]; !ok {
+					protocols[alias] = proto
+				}
+			}
+		}
+	}
+}
+
+// lookupProtocol looks up IP protocol name in /etc/protocols and
+// returns correspondent protocol number.
+func lookupProtocol(_ context.Context, name string) (int, error) {
+	onceReadProtocols.Do(readProtocols)
+	return lookupProtocolMap(name)
+}
+
+func (r *Resolver) dial(ctx context.Context, network, server string) (Conn, error) {
+	// Calling Dial here is scary -- we have to be sure not to
+	// dial a name that will require a DNS lookup, or Dial will
+	// call back here to translate it. The DNS config parser has
+	// already checked that all the cfg.servers are IP
+	// addresses, which Dial will use without a DNS lookup.
+	var c Conn
+	var err error
+	if r != nil && r.Dial != nil {
+		c, err = r.Dial(ctx, network, server)
+	} else {
+		var d Dialer
+		c, err = d.DialContext(ctx, network, server)
+	}
+	if err != nil {
+		return nil, mapErr(err)
+	}
+	return c, nil
+}
+
+func (r *Resolver) lookupHost(ctx context.Context, host string) (addrs []string, err error) {
+	order := systemConf().hostLookupOrder(r, host)
+	if !r.preferGo() && order == hostLookupCgo {
+		if addrs, err, ok := cgoLookupHost(ctx, host); ok {
+			return addrs, err
+		}
+		// cgo not available (or netgo); fall back to Go's DNS resolver
+		order = hostLookupFilesDNS
+	}
+	return r.goLookupHostOrder(ctx, host, order)
+}
+
+func (r *Resolver) lookupIP(ctx context.Context, host string) (addrs []IPAddr, err error) {
+	if r.preferGo() {
+		return r.goLookupIP(ctx, host)
+	}
+	order := systemConf().hostLookupOrder(r, host)
+	if order == hostLookupCgo {
+		if addrs, err, ok := cgoLookupIP(ctx, host); ok {
+			return addrs, err
+		}
+		// cgo not available (or netgo); fall back to Go's DNS resolver
+		order = hostLookupFilesDNS
+	}
+	ips, _, err := r.goLookupIPCNAMEOrder(ctx, host, order)
+	return ips, err
+}
+
+func (r *Resolver) lookupPort(ctx context.Context, network, service string) (int, error) {
+	if !r.preferGo() && systemConf().canUseCgo() {
+		if port, err, ok := cgoLookupPort(ctx, network, service); ok {
+			if err != nil {
+				// Issue 18213: if cgo fails, first check to see whether we
+				// have the answer baked-in to the net package.
+				if port, err := goLookupPort(network, service); err == nil {
+					return port, nil
+				}
+			}
+			return port, err
+		}
+	}
+	return goLookupPort(network, service)
+}
+
+func (r *Resolver) lookupCNAME(ctx context.Context, name string) (string, error) {
+	if !r.preferGo() && systemConf().canUseCgo() {
+		if cname, err, ok := cgoLookupCNAME(ctx, name); ok {
+			return cname, err
+		}
+	}
+	return r.goLookupCNAME(ctx, name)
+}
+
+func (r *Resolver) lookupSRV(ctx context.Context, service, proto, name string) (string, []*SRV, error) {
+	var target string
+	if service == "" && proto == "" {
+		target = name
+	} else {
+		target = "_" + service + "._" + proto + "." + name
+	}
+	p, server, err := r.lookup(ctx, target, dnsmessage.TypeSRV)
+	if err != nil {
+		return "", nil, err
+	}
+	var srvs []*SRV
+	var cname dnsmessage.Name
+	for {
+		h, err := p.AnswerHeader()
+		if err == dnsmessage.ErrSectionDone {
+			break
+		}
+		if err != nil {
+			return "", nil, &DNSError{
+				Err:    "cannot unmarshal DNS message",
+				Name:   name,
+				Server: server,
+			}
+		}
+		if h.Type != dnsmessage.TypeSRV {
+			if err := p.SkipAnswer(); err != nil {
+				return "", nil, &DNSError{
+					Err:    "cannot unmarshal DNS message",
+					Name:   name,
+					Server: server,
+				}
+			}
+			continue
+		}
+		if cname.Length == 0 && h.Name.Length != 0 {
+			cname = h.Name
+		}
+		srv, err := p.SRVResource()
+		if err != nil {
+			return "", nil, &DNSError{
+				Err:    "cannot unmarshal DNS message",
+				Name:   name,
+				Server: server,
+			}
+		}
+		srvs = append(srvs, &SRV{Target: srv.Target.String(), Port: srv.Port, Priority: srv.Priority, Weight: srv.Weight})
+	}
+	byPriorityWeight(srvs).sort()
+	return cname.String(), srvs, nil
+}
+
+func (r *Resolver) lookupMX(ctx context.Context, name string) ([]*MX, error) {
+	p, server, err := r.lookup(ctx, name, dnsmessage.TypeMX)
+	if err != nil {
+		return nil, err
+	}
+	var mxs []*MX
+	for {
+		h, err := p.AnswerHeader()
+		if err == dnsmessage.ErrSectionDone {
+			break
+		}
+		if err != nil {
+			return nil, &DNSError{
+				Err:    "cannot unmarshal DNS message",
+				Name:   name,
+				Server: server,
+			}
+		}
+		if h.Type != dnsmessage.TypeMX {
+			if err := p.SkipAnswer(); err != nil {
+				return nil, &DNSError{
+					Err:    "cannot unmarshal DNS message",
+					Name:   name,
+					Server: server,
+				}
+			}
+			continue
+		}
+		mx, err := p.MXResource()
+		if err != nil {
+			return nil, &DNSError{
+				Err:    "cannot unmarshal DNS message",
+				Name:   name,
+				Server: server,
+			}
+		}
+		mxs = append(mxs, &MX{Host: mx.MX.String(), Pref: mx.Pref})
+
+	}
+	byPref(mxs).sort()
+	return mxs, nil
+}
+
+func (r *Resolver) lookupNS(ctx context.Context, name string) ([]*NS, error) {
+	p, server, err := r.lookup(ctx, name, dnsmessage.TypeNS)
+	if err != nil {
+		return nil, err
+	}
+	var nss []*NS
+	for {
+		h, err := p.AnswerHeader()
+		if err == dnsmessage.ErrSectionDone {
+			break
+		}
+		if err != nil {
+			return nil, &DNSError{
+				Err:    "cannot unmarshal DNS message",
+				Name:   name,
+				Server: server,
+			}
+		}
+		if h.Type != dnsmessage.TypeNS {
+			if err := p.SkipAnswer(); err != nil {
+				return nil, &DNSError{
+					Err:    "cannot unmarshal DNS message",
+					Name:   name,
+					Server: server,
+				}
+			}
+			continue
+		}
+		ns, err := p.NSResource()
+		if err != nil {
+			return nil, &DNSError{
+				Err:    "cannot unmarshal DNS message",
+				Name:   name,
+				Server: server,
+			}
+		}
+		nss = append(nss, &NS{Host: ns.NS.String()})
+	}
+	return nss, nil
+}
+
+func (r *Resolver) lookupTXT(ctx context.Context, name string) ([]string, error) {
+	p, server, err := r.lookup(ctx, name, dnsmessage.TypeTXT)
+	if err != nil {
+		return nil, err
+	}
+	var txts []string
+	for {
+		h, err := p.AnswerHeader()
+		if err == dnsmessage.ErrSectionDone {
+			break
+		}
+		if err != nil {
+			return nil, &DNSError{
+				Err:    "cannot unmarshal DNS message",
+				Name:   name,
+				Server: server,
+			}
+		}
+		if h.Type != dnsmessage.TypeTXT {
+			if err := p.SkipAnswer(); err != nil {
+				return nil, &DNSError{
+					Err:    "cannot unmarshal DNS message",
+					Name:   name,
+					Server: server,
+				}
+			}
+			continue
+		}
+		txt, err := p.TXTResource()
+		if err != nil {
+			return nil, &DNSError{
+				Err:    "cannot unmarshal DNS message",
+				Name:   name,
+				Server: server,
+			}
+		}
+		if len(txts) == 0 {
+			txts = txt.TXT
+		} else {
+			txts = append(txts, txt.TXT...)
+		}
+	}
+	return txts, nil
+}
+
+func (r *Resolver) lookupAddr(ctx context.Context, addr string) ([]string, error) {
+	if !r.preferGo() && systemConf().canUseCgo() {
+		if ptrs, err, ok := cgoLookupPTR(ctx, addr); ok {
+			return ptrs, err
+		}
+	}
+	return r.goLookupPTR(ctx, addr)
+}
+
+// concurrentThreadsLimit returns the number of threads we permit to
+// run concurrently doing DNS lookups via cgo.
+func concurrentThreadsLimit() int {
+	return 500
+}
diff --git a/src/net/lookup_test.go b/src/net/lookup_test.go
index 5c66dfa..cb92c3c 100644
--- a/src/net/lookup_test.go
+++ b/src/net/lookup_test.go
@@ -742,6 +742,11 @@
 }
 
 func TestLookupPort(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
+
 	// See https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml
 	//
 	// Please be careful about adding new test cases.
@@ -800,6 +805,10 @@
 // Like TestLookupPort but with minimal tests that should always pass
 // because the answers are baked-in to the net package.
 func TestLookupPort_Minimal(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
 	type test struct {
 		network string
 		name    string
diff --git a/src/net/main_fuchsia_test.go b/src/net/main_fuchsia_test.go
new file mode 100644
index 0000000..b266361
--- /dev/null
+++ b/src/net/main_fuchsia_test.go
@@ -0,0 +1,20 @@
+// Copyright 2017 The Go 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 fuchsia
+
+package net
+
+func installTestHooks() {
+}
+
+func uninstallTestHooks() {
+}
+
+// forceCloseSockets must be called only from TestMain.
+func forceCloseSockets() {
+	for s := range sw.Sockets() {
+		closeFunc(s)
+	}
+}
diff --git a/src/net/net_test.go b/src/net/net_test.go
index 692f269..e880564 100644
--- a/src/net/net_test.go
+++ b/src/net/net_test.go
@@ -19,6 +19,10 @@
 )
 
 func TestCloseRead(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
 	switch runtime.GOOS {
 	case "plan9":
 		t.Skipf("not supported on %s", runtime.GOOS)
@@ -71,8 +75,9 @@
 }
 
 func TestCloseWrite(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
 	switch runtime.GOOS {
-	case "nacl", "plan9":
+	case "nacl", "plan9", "fuchsia":
 		t.Skipf("not supported on %s", runtime.GOOS)
 	}
 
@@ -255,6 +260,10 @@
 }
 
 func TestPacketConnClose(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
 	for _, network := range []string{"udp", "unixgram"} {
 		if !testableNetwork(network) {
 			t.Logf("skipping %s test", network)
@@ -287,6 +296,10 @@
 
 // nacl was previous failing to reuse an address.
 func TestListenCloseListen(t *testing.T) {
+	// TODO(NET-1266): disabled.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
 	const maxTries = 10
 	for tries := 0; tries < maxTries; tries++ {
 		ln, err := newLocalListener("tcp")
@@ -313,6 +326,10 @@
 
 // See golang.org/issue/6163, golang.org/issue/6987.
 func TestAcceptIgnoreAbortedConnRequest(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
 	switch runtime.GOOS {
 	case "plan9":
 		t.Skipf("%s does not have full support of socktest", runtime.GOOS)
@@ -460,6 +477,10 @@
 // See golang.org/cl/30164 which documented this. The net/http package
 // depends on this.
 func TestReadTimeoutUnblocksRead(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
 	serverDone := make(chan struct{})
 	server := func(cs *TCPConn) error {
 		defer close(serverDone)
@@ -503,6 +524,10 @@
 
 // Issue 17695: verify that a blocked Read is woken up by a Close.
 func TestCloseUnblocksRead(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
 	t.Parallel()
 	server := func(cs *TCPConn) error {
 		// Give the client time to get stuck in a Read:
@@ -522,6 +547,10 @@
 
 // Issue 24808: verify that ECONNRESET is not temporary for read.
 func TestNotTemporaryRead(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
 	if runtime.GOOS == "freebsd" {
 		testenv.SkipFlaky(t, 25289)
 	}
diff --git a/src/net/nss.go b/src/net/nss.go
index 08c3e6a..3533ab0 100644
--- a/src/net/nss.go
+++ b/src/net/nss.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build darwin dragonfly freebsd fuchsia linux netbsd openbsd solaris
 
 package net
 
diff --git a/src/net/packetconn_test.go b/src/net/packetconn_test.go
index a377d33..eafad0a 100644
--- a/src/net/packetconn_test.go
+++ b/src/net/packetconn_test.go
@@ -11,6 +11,7 @@
 
 import (
 	"os"
+	"runtime"
 	"testing"
 	"time"
 )
@@ -38,6 +39,10 @@
 }
 
 func TestPacketConn(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
 	closer := func(c PacketConn, net, addr1, addr2 string) {
 		c.Close()
 		switch net {
@@ -92,6 +97,10 @@
 }
 
 func TestConnAndPacketConn(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
 	closer := func(c PacketConn, net, addr1, addr2 string) {
 		c.Close()
 		switch net {
diff --git a/src/net/parse_test.go b/src/net/parse_test.go
index c5f8bfd..ffe4d12 100644
--- a/src/net/parse_test.go
+++ b/src/net/parse_test.go
@@ -14,7 +14,7 @@
 func TestReadLine(t *testing.T) {
 	// /etc/services file does not exist on android, plan9, windows.
 	switch runtime.GOOS {
-	case "android", "plan9", "windows":
+	case "android", "plan9", "windows", "fuchsia":
 		t.Skipf("not supported on %s", runtime.GOOS)
 	}
 	filename := "/etc/services" // a nice big file
diff --git a/src/net/platform_test.go b/src/net/platform_test.go
index 8e7d915..13b59df 100644
--- a/src/net/platform_test.go
+++ b/src/net/platform_test.go
@@ -33,7 +33,7 @@
 		}
 	case "unix", "unixgram":
 		switch runtime.GOOS {
-		case "android", "nacl", "plan9", "windows":
+		case "android", "fuchsia", "nacl", "plan9", "windows":
 			return false
 		}
 		// iOS does not support unix, unixgram.
@@ -42,7 +42,7 @@
 		}
 	case "unixpacket":
 		switch runtime.GOOS {
-		case "android", "darwin", "nacl", "plan9", "windows":
+		case "android", "darwin", "fuchsia", "nacl", "plan9", "windows":
 			return false
 		case "netbsd":
 			// It passes on amd64 at least. 386 fails (Issue 22927). arm is unknown.
diff --git a/src/net/port_fuchsia.go b/src/net/port_fuchsia.go
new file mode 100644
index 0000000..c8438b1
--- /dev/null
+++ b/src/net/port_fuchsia.go
@@ -0,0 +1,11 @@
+// Copyright 2017 The Go 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"
+
+func goLookupPort(network, service string) (port int, err error) {
+	return -1, errors.New("net: port lookup not supported yet on fuchsia")
+}
diff --git a/src/net/protoconn_test.go b/src/net/protoconn_test.go
index 9f6772c..266657f 100644
--- a/src/net/protoconn_test.go
+++ b/src/net/protoconn_test.go
@@ -23,6 +23,10 @@
 //	golang.org/x/net/icmp
 
 func TestTCPListenerSpecificMethods(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
 	switch runtime.GOOS {
 	case "plan9":
 		t.Skipf("not supported on %s", runtime.GOOS)
@@ -115,6 +119,10 @@
 }
 
 func TestUDPConnSpecificMethods(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
 	la, err := ResolveUDPAddr("udp4", "127.0.0.1:0")
 	if err != nil {
 		t.Fatal(err)
@@ -164,6 +172,10 @@
 }
 
 func TestIPConnSpecificMethods(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
 	if os.Getuid() != 0 {
 		t.Skip("must be root")
 	}
@@ -203,6 +215,10 @@
 }
 
 func TestUnixListenerSpecificMethods(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
 	if !testableNetwork("unix") {
 		t.Skip("unix test")
 	}
@@ -244,6 +260,10 @@
 }
 
 func TestUnixConnSpecificMethods(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
 	if !testableNetwork("unixgram") {
 		t.Skip("unixgram test")
 	}
diff --git a/src/net/rawconn_stub_test.go b/src/net/rawconn_stub_test.go
index 0a033c1..9c18a62 100644
--- a/src/net/rawconn_stub_test.go
+++ b/src/net/rawconn_stub_test.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build js,wasm nacl plan9
+// +build fuchsia js,wasm nacl plan9
 
 package net
 
diff --git a/src/net/rawconn_test.go b/src/net/rawconn_test.go
index 11900df..e01318d 100644
--- a/src/net/rawconn_test.go
+++ b/src/net/rawconn_test.go
@@ -15,7 +15,7 @@
 
 func TestRawConnReadWrite(t *testing.T) {
 	switch runtime.GOOS {
-	case "nacl", "plan9":
+	case "fuchsia", "nacl", "plan9":
 		t.Skipf("not supported on %s", runtime.GOOS)
 	}
 
@@ -175,7 +175,7 @@
 
 func TestRawConnControl(t *testing.T) {
 	switch runtime.GOOS {
-	case "nacl", "plan9":
+	case "fuchsia", "nacl", "plan9":
 		t.Skipf("not supported on %s", runtime.GOOS)
 	}
 
diff --git a/src/net/sendfile_test.go b/src/net/sendfile_test.go
index 3b98277..67d2a46 100644
--- a/src/net/sendfile_test.go
+++ b/src/net/sendfile_test.go
@@ -13,6 +13,7 @@
 	"fmt"
 	"io"
 	"os"
+	"runtime"
 	"testing"
 )
 
@@ -23,6 +24,10 @@
 )
 
 func TestSendfile(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
 	ln, err := newLocalListener("tcp")
 	if err != nil {
 		t.Fatal(err)
@@ -93,6 +98,11 @@
 }
 
 func TestSendfileParts(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
+
 	ln, err := newLocalListener("tcp")
 	if err != nil {
 		t.Fatal(err)
@@ -151,6 +161,11 @@
 }
 
 func TestSendfileSeeked(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
+
 	ln, err := newLocalListener("tcp")
 	if err != nil {
 		t.Fatal(err)
diff --git a/src/net/server_test.go b/src/net/server_test.go
index 1608beb..4bec5ae 100644
--- a/src/net/server_test.go
+++ b/src/net/server_test.go
@@ -8,6 +8,7 @@
 
 import (
 	"os"
+	"runtime"
 	"testing"
 )
 
@@ -53,6 +54,10 @@
 
 // TestTCPServer tests concurrent accept-read-write servers.
 func TestTCPServer(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
 	const N = 3
 
 	for i, tt := range tcpServerTests {
@@ -137,6 +142,10 @@
 // TestUnixAndUnixpacketServer tests concurrent accept-read-write
 // servers
 func TestUnixAndUnixpacketServer(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
 	const N = 3
 
 	for i, tt := range unixAndUnixpacketServerTests {
@@ -251,6 +260,10 @@
 }
 
 func TestUDPServer(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
 	for i, tt := range udpServerTests {
 		if !testableListenArgs(tt.snet, tt.saddr, tt.taddr) {
 			t.Logf("skipping %s test", tt.snet+" "+tt.saddr+"<-"+tt.taddr)
@@ -329,6 +342,10 @@
 }
 
 func TestUnixgramServer(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
 	for i, tt := range unixgramServerTests {
 		if !testableListenArgs("unixgram", tt.saddr, "") {
 			t.Logf("skipping %s test", "unixgram "+tt.saddr+"<-"+tt.caddr)
diff --git a/src/net/sock_stub.go b/src/net/sock_stub.go
index 38fc819..1a09ecf 100644
--- a/src/net/sock_stub.go
+++ b/src/net/sock_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 nacl js,wasm solaris
+// +build nacl js,wasm solaris fuchsia
 
 package net
 
diff --git a/src/net/sockopt_stub.go b/src/net/sockopt_stub.go
index bc06675..7240cac 100644
--- a/src/net/sockopt_stub.go
+++ b/src/net/sockopt_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 nacl js,wasm
+// +build nacl js,wasm fuchsia
 
 package net
 
diff --git a/src/net/tcpsock_fuchsia.go b/src/net/tcpsock_fuchsia.go
new file mode 100644
index 0000000..447e9a9
--- /dev/null
+++ b/src/net/tcpsock_fuchsia.go
@@ -0,0 +1,85 @@
+// Copyright 2016 The Go 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 (
+	"context"
+	"io"
+	"os"
+	"syscall"
+	"syscall/zx/mxnet"
+)
+
+func (a *TCPAddr) encode() ([]byte, error) { // TODO remove
+	b := make([]byte, mxnet.SockaddrLen)
+	_, err := mxnet.EncodeSockaddr(b, mxnet.Addr(a.IP), uint16(a.Port))
+	return b, err
+}
+
+func (a *TCPAddr) family() int {
+	if a == nil || len(a.IP) <= IPv4len {
+		return syscall.AF_INET
+	}
+	if a.IP.To4() != nil {
+		return syscall.AF_INET
+	}
+	return syscall.AF_INET6
+}
+
+func (a *TCPAddr) sockaddr(family int) (addr mxnet.Addr, port uint16, err error) {
+	if a == nil {
+		return "", 0, nil
+	}
+	return ipToSockaddr(family, a.IP, a.Port, a.Zone)
+}
+
+func (c *TCPConn) readFrom(r io.Reader) (int64, error) {
+	return genericReadFrom(c, r)
+}
+
+func (sd *sysDialer) dialTCP(ctx context.Context, laddr, raddr *TCPAddr) (*TCPConn, error) {
+	if testHookDialTCP != nil {
+		return testHookDialTCP(ctx, sd.network, laddr, raddr)
+	}
+	return sd.doDialTCP(ctx, laddr, raddr)
+}
+
+func (sd *sysDialer) doDialTCP(ctx context.Context, laddr, raddr *TCPAddr) (*TCPConn, error) {
+	switch sd.network {
+	case "tcp", "tcp4", "tcp6":
+	default:
+		return nil, UnknownNetworkError(sd.network)
+	}
+	if raddr == nil {
+		return nil, errMissingAddress
+	}
+	fd, err := dialFuchsia(ctx, sd.network, laddr, raddr)
+	if err != nil {
+		return nil, err
+	}
+	return newTCPConn(fd), nil
+}
+
+func (ln *TCPListener) ok() bool { return ln != nil && ln.fd != nil }
+
+func (ln *TCPListener) accept() (*TCPConn, error) {
+	fd, err := ln.fd.accept()
+	if err != nil {
+		return nil, err
+	}
+	return newTCPConn(fd), nil
+}
+
+func (ln *TCPListener) close() error { return ln.fd.Close() }
+
+func (ln *TCPListener) file() (*os.File, error) { return ln.fd.dup() }
+
+func (sl *sysListener) listenTCP(ctx context.Context, laddr *TCPAddr) (*TCPListener, error) {
+	fd, err := dialFuchsia(ctx, sl.network, laddr, nil)
+	if err != nil {
+		return nil, err
+	}
+	return &TCPListener{fd}, nil
+}
diff --git a/src/net/tcpsock_test.go b/src/net/tcpsock_test.go
index c2f26b1..e5bf8d8 100644
--- a/src/net/tcpsock_test.go
+++ b/src/net/tcpsock_test.go
@@ -328,6 +328,10 @@
 }
 
 func TestResolveTCPAddr(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
 	origTestHookLookupIP := testHookLookupIP
 	defer func() { testHookLookupIP = origTestHookLookupIP }()
 	testHookLookupIP = lookupLocalhost
@@ -428,6 +432,11 @@
 }
 
 func TestTCPConcurrentAccept(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
+
 	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4))
 	ln, err := Listen("tcp", "127.0.0.1:0")
 	if err != nil {
@@ -470,6 +479,10 @@
 }
 
 func TestTCPReadWriteAllocs(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
 	switch runtime.GOOS {
 	case "plan9":
 		// The implementation of asynchronous cancelable
@@ -543,6 +556,10 @@
 }
 
 func TestTCPStress(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
 	const conns = 2
 	const msgLen = 512
 	msgs := int(1e4)
@@ -625,6 +642,10 @@
 }
 
 func TestTCPSelfConnect(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
 	if runtime.GOOS == "windows" {
 		// TODO(brainman): do not know why it hangs.
 		t.Skip("known-broken test on windows")
@@ -674,6 +695,10 @@
 // Test that >32-bit reads work on 64-bit systems.
 // On 32-bit systems this tests that maxint reads work.
 func TestTCPBig(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
 	if !*testTCPBig {
 		t.Skip("test disabled; use -tcpbig to enable")
 	}
@@ -727,6 +752,11 @@
 }
 
 func TestCopyPipeIntoTCP(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
+
 	ln, err := newLocalListener("tcp")
 	if err != nil {
 		t.Fatal(err)
diff --git a/src/net/tcpsock_unix_test.go b/src/net/tcpsock_unix_test.go
index 2bd591b..65d0a96 100644
--- a/src/net/tcpsock_unix_test.go
+++ b/src/net/tcpsock_unix_test.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build !js,!plan9,!windows
+// +build !fuchsia,!js,!plan9,!windows
 
 package net
 
diff --git a/src/net/tcpsockopt_stub.go b/src/net/tcpsockopt_stub.go
index fd7f579..7e23c1f 100644
--- a/src/net/tcpsockopt_stub.go
+++ b/src/net/tcpsockopt_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 nacl js,wasm
+// +build nacl js,wasm fuchsia
 
 package net
 
diff --git a/src/net/timeout_test.go b/src/net/timeout_test.go
index 7c7d0c8..868890c 100644
--- a/src/net/timeout_test.go
+++ b/src/net/timeout_test.go
@@ -39,6 +39,10 @@
 }
 
 func TestDialTimeout(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
 	// Cannot use t.Parallel - modifies global hooks.
 	origTestHookDialChannel := testHookDialChannel
 	defer func() { testHookDialChannel = origTestHookDialChannel }()
@@ -46,7 +50,7 @@
 
 	for i, tt := range dialTimeoutTests {
 		switch runtime.GOOS {
-		case "plan9", "windows":
+		case "plan9", "windows", "fuchsia":
 			testHookDialChannel = func() { time.Sleep(tt.guard) }
 			if runtime.GOOS == "plan9" {
 				break
@@ -102,9 +106,17 @@
 }
 
 func TestDialTimeoutMaxDuration(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
 	if runtime.GOOS == "openbsd" {
 		testenv.SkipFlaky(t, 15157)
 	}
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
 
 	ln, err := newLocalListener("tcp")
 	if err != nil {
@@ -154,6 +166,10 @@
 }
 
 func TestAcceptTimeout(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
 	testenv.SkipFlaky(t, 17948)
 	t.Parallel()
 
@@ -211,6 +227,10 @@
 }
 
 func TestAcceptTimeoutMustReturn(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
 	t.Parallel()
 
 	switch runtime.GOOS {
@@ -257,6 +277,10 @@
 }
 
 func TestAcceptTimeoutMustNotReturn(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
 	t.Parallel()
 
 	switch runtime.GOOS {
@@ -308,6 +332,10 @@
 }
 
 func TestReadTimeout(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
 	handler := func(ls *localServer, ln Listener) {
 		c, err := ln.Accept()
 		if err != nil {
@@ -362,6 +390,10 @@
 }
 
 func TestReadTimeoutMustNotReturn(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
 	t.Parallel()
 
 	switch runtime.GOOS {
@@ -432,6 +464,10 @@
 }
 
 func TestReadFromTimeout(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
 	switch runtime.GOOS {
 	case "nacl":
 		t.Skipf("not supported on %s", runtime.GOOS) // see golang.org/issue/8916
@@ -505,6 +541,10 @@
 }
 
 func TestWriteTimeout(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
 	t.Parallel()
 
 	ln, err := newLocalListener("tcp")
@@ -548,6 +588,10 @@
 }
 
 func TestWriteTimeoutMustNotReturn(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
 	t.Parallel()
 
 	switch runtime.GOOS {
@@ -619,6 +663,10 @@
 }
 
 func TestWriteToTimeout(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
 	t.Parallel()
 
 	switch runtime.GOOS {
@@ -672,6 +720,10 @@
 }
 
 func TestReadTimeoutFluctuation(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
 	t.Parallel()
 
 	ln, err := newLocalListener("tcp")
@@ -705,6 +757,10 @@
 }
 
 func TestReadFromTimeoutFluctuation(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
 	t.Parallel()
 
 	c1, err := newLocalPacketListener("udp")
@@ -738,6 +794,10 @@
 }
 
 func TestWriteTimeoutFluctuation(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
 	t.Parallel()
 
 	switch runtime.GOOS {
@@ -780,11 +840,19 @@
 }
 
 func TestVariousDeadlines(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
 	t.Parallel()
 	testVariousDeadlines(t)
 }
 
 func TestVariousDeadlines1Proc(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
 	// Cannot use t.Parallel - modifies global GOMAXPROCS.
 	if testing.Short() {
 		t.Skip("skipping in short mode")
@@ -794,6 +862,10 @@
 }
 
 func TestVariousDeadlines4Proc(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
 	// Cannot use t.Parallel - modifies global GOMAXPROCS.
 	if testing.Short() {
 		t.Skip("skipping in short mode")
@@ -925,6 +997,10 @@
 // TestReadWriteProlongedTimeout tests concurrent deadline
 // modification. Known to cause data races in the past.
 func TestReadWriteProlongedTimeout(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
 	t.Parallel()
 
 	switch runtime.GOOS {
@@ -1005,6 +1081,10 @@
 }
 
 func TestReadWriteDeadlineRace(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
 	t.Parallel()
 
 	switch runtime.GOOS {
diff --git a/src/net/udpsock_fuchsia.go b/src/net/udpsock_fuchsia.go
new file mode 100644
index 0000000..b97e1ef
--- /dev/null
+++ b/src/net/udpsock_fuchsia.go
@@ -0,0 +1,92 @@
+// Copyright 2016 The Go 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 (
+	"context"
+	"syscall"
+	"syscall/zx/mxnet"
+)
+
+func (a *UDPAddr) encode() ([]byte, error) {
+	b := make([]byte, mxnet.SockaddrLen)
+	_, err := mxnet.EncodeSockaddr(b, mxnet.Addr(a.IP), uint16(a.Port))
+	return b, err
+}
+
+func (a *UDPAddr) family() int {
+	if a == nil || len(a.IP) <= IPv4len {
+		return syscall.AF_INET
+	}
+	if a.IP.To4() != nil {
+		return syscall.AF_INET
+	}
+	return syscall.AF_INET6
+}
+
+func (a *UDPAddr) sockaddr(family int) (addr mxnet.Addr, port uint16, err error) {
+	if a == nil {
+		return "", 0, nil
+	}
+	return ipToSockaddr(family, a.IP, a.Port, a.Zone)
+}
+
+func (c *UDPConn) readFrom(b []byte) (n int, addr *UDPAddr, err error) {
+	panic("TODO readFrom")
+}
+
+func (c *UDPConn) readMsg(b, oob []byte) (n, oobn, flags int, addr *UDPAddr, err error) {
+	n, flags, addrstr, port, err := c.fd.readMsg(b)
+	if err != nil {
+		return 0, 0, 0, nil, err
+	}
+	addr = &UDPAddr{
+		IP:   IP(addrstr),
+		Port: int(port),
+	}
+	return n, 0, flags, addr, nil
+}
+
+func (c *UDPConn) writeTo(b []byte, addr *UDPAddr) (int, error) {
+	panic("TODO writeTo")
+}
+
+func (c *UDPConn) writeMsg(b, oob []byte, addr *UDPAddr) (n, oobn int, err error) {
+	if len(oob) > 0 {
+		return 0, 0, syscall.EFUCHSIA
+	}
+	n, err = c.fd.sendMsg(b, string(addr.IP), uint16(addr.Port))
+	return n, 0, err
+}
+
+func (sd *sysDialer) dialUDP(ctx context.Context, laddr, raddr *UDPAddr) (*UDPConn, error) {
+	switch sd.network {
+	case "udp", "udp4", "udp6":
+	default:
+		return nil, UnknownNetworkError(sd.network)
+	}
+	if raddr == nil {
+		return nil, errMissingAddress
+	}
+	var laddrif sockaddr
+	if laddr != nil {
+		laddrif = laddr
+	}
+	fd, err := dialFuchsia(ctx, sd.network, laddrif, raddr)
+	if err != nil {
+		return nil, err
+	}
+	return newUDPConn(fd), nil
+}
+
+const udpHeaderSize = 16*3 + 2*2
+
+func (sl *sysListener) listenUDP(ctx context.Context, laddr *UDPAddr) (*UDPConn, error) {
+	panic("TODO listenUDP")
+}
+
+func (sl *sysListener) listenMulticastUDP(ctx context.Context, ifi *Interface, gaddr *UDPAddr) (*UDPConn, error) {
+	return nil, syscall.EFUCHSIA
+}
diff --git a/src/net/udpsock_test.go b/src/net/udpsock_test.go
index 4940644..977b2a8 100644
--- a/src/net/udpsock_test.go
+++ b/src/net/udpsock_test.go
@@ -15,6 +15,10 @@
 )
 
 func BenchmarkUDP6LinkLocalUnicast(b *testing.B) {
+	if runtime.GOOS == "fuchsia" {
+		b.Skip("Fuchsia doesn't implement UDP")
+	}
+
 	testHookUninstaller.Do(uninstallTestHooks)
 
 	if !supportsIPv6() {
@@ -88,6 +92,10 @@
 }
 
 func TestResolveUDPAddr(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
 	origTestHookLookupIP := testHookLookupIP
 	defer func() { testHookLookupIP = origTestHookLookupIP }()
 	testHookLookupIP = lookupLocalhost
@@ -108,6 +116,10 @@
 }
 
 func TestWriteToUDP(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
 	switch runtime.GOOS {
 	case "plan9":
 		t.Skipf("not supported on %s", runtime.GOOS)
@@ -124,6 +136,10 @@
 }
 
 func testWriteToConn(t *testing.T, raddr string) {
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("Fuchsia doesn't implement UDP")
+	}
+
 	c, err := Dial("udp", raddr)
 	if err != nil {
 		t.Fatal(err)
@@ -173,6 +189,10 @@
 }
 
 func testWriteToPacketConn(t *testing.T, raddr string) {
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("Fuchsia doesn't implement UDP")
+	}
+
 	c, err := ListenPacket("udp", "127.0.0.1:0")
 	if err != nil {
 		t.Fatal(err)
@@ -241,6 +261,10 @@
 }
 
 func TestUDPConnLocalAndRemoteNames(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
 	for _, laddr := range []string{"", "127.0.0.1:0"} {
 		c1, err := ListenPacket("udp", "127.0.0.1:0")
 		if err != nil {
@@ -334,6 +358,10 @@
 }
 
 func TestUDPZeroBytePayload(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
 	switch runtime.GOOS {
 	case "nacl", "plan9":
 		t.Skipf("not supported on %s", runtime.GOOS)
@@ -371,6 +399,10 @@
 }
 
 func TestUDPZeroByteBuffer(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
 	switch runtime.GOOS {
 	case "nacl", "plan9":
 		t.Skipf("not supported on %s", runtime.GOOS)
@@ -409,7 +441,7 @@
 
 func TestUDPReadSizeError(t *testing.T) {
 	switch runtime.GOOS {
-	case "nacl", "plan9":
+	case "fuchsia", "nacl", "plan9":
 		t.Skipf("not supported on %s", runtime.GOOS)
 	}
 
diff --git a/src/net/unixsock_fuchsia.go b/src/net/unixsock_fuchsia.go
new file mode 100644
index 0000000..1ed9304
--- /dev/null
+++ b/src/net/unixsock_fuchsia.go
@@ -0,0 +1,51 @@
+// Copyright 2016 The Go 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 (
+	"context"
+	"os"
+	"syscall"
+)
+
+func (c *UnixConn) readFrom(b []byte) (int, *UnixAddr, error) {
+	return 0, nil, syscall.EFUCHSIA
+}
+
+func (c *UnixConn) readMsg(b, oob []byte) (n, oobn, flags int, addr *UnixAddr, err error) {
+	return 0, 0, 0, nil, syscall.EFUCHSIA
+}
+
+func (c *UnixConn) writeTo(b []byte, addr *UnixAddr) (int, error) {
+	return 0, syscall.EFUCHSIA
+}
+
+func (c *UnixConn) writeMsg(b, oob []byte, addr *UnixAddr) (n, oobn int, err error) {
+	return 0, 0, syscall.EFUCHSIA
+}
+
+func (sd *sysDialer) dialUnix(ctx context.Context, laddr, raddr *UnixAddr) (*UnixConn, error) {
+	return nil, syscall.EFUCHSIA
+}
+
+func (ln *UnixListener) accept() (*UnixConn, error) {
+	return nil, syscall.EFUCHSIA
+}
+
+func (ln *UnixListener) close() error {
+	return syscall.EFUCHSIA
+}
+
+func (ln *UnixListener) file() (*os.File, error) {
+	return nil, syscall.EFUCHSIA
+}
+
+func (sl *sysListener) listenUnix(ctx context.Context, laddr *UnixAddr) (*UnixListener, error) {
+	return nil, syscall.EFUCHSIA
+}
+
+func (sl *sysListener) listenUnixgram(ctx context.Context, laddr *UnixAddr) (*UnixConn, error) {
+	return nil, syscall.EFUCHSIA
+}
diff --git a/src/net/unixsock_test.go b/src/net/unixsock_test.go
index 4828990..b725be5 100644
--- a/src/net/unixsock_test.go
+++ b/src/net/unixsock_test.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build !js,!nacl,!plan9,!windows
+// +build !js,!nacl,!plan9,!windows,!fuchsia
 
 package net
 
diff --git a/src/net/writev_test.go b/src/net/writev_test.go
index c43be84..933c826 100644
--- a/src/net/writev_test.go
+++ b/src/net/writev_test.go
@@ -19,6 +19,10 @@
 )
 
 func TestBuffers_read(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
 	const story = "once upon a time in Gopherland ... "
 	buffers := Buffers{
 		[]byte("once "),
@@ -41,6 +45,10 @@
 }
 
 func TestBuffers_consume(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
 	tests := []struct {
 		in      Buffers
 		consume int64
@@ -92,6 +100,10 @@
 }
 
 func TestBuffers_WriteTo(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
 	for _, name := range []string{"WriteTo", "Copy"} {
 		for _, size := range []int{0, 10, 1023, 1024, 1025} {
 			t.Run(fmt.Sprintf("%s/%d", name, size), func(t *testing.T) {
@@ -183,6 +195,10 @@
 }
 
 func TestWritevError(t *testing.T) {
+	// TODO(TC-149): disabled without further triage. Needs work.
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("network test disabled for GOOS=fuchsia")
+	}
 	if runtime.GOOS == "windows" {
 		t.Skipf("skipping the test: windows does not have problem sending large chunks of data")
 	}
diff --git a/src/os/dir_unix.go b/src/os/dir_unix.go
index 79d61c7..604f0c2 100644
--- a/src/os/dir_unix.go
+++ b/src/os/dir_unix.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris
+// +build darwin dragonfly freebsd fuchsia js,wasm linux nacl netbsd openbsd solaris
 
 package os
 
diff --git a/src/os/error_fuchsia.go b/src/os/error_fuchsia.go
new file mode 100644
index 0000000..2572f7e
--- /dev/null
+++ b/src/os/error_fuchsia.go
@@ -0,0 +1,50 @@
+// 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 fuchsia
+
+package os
+
+import (
+	"syscall"
+	"syscall/zx"
+)
+
+func isExist(err error) bool {
+	err = underlyingError(err)
+	switch err := err.(type) {
+	case zx.Error:
+		return err.Status == zx.ErrAlreadyExists
+	}
+	return err == syscall.EEXIST || err == syscall.ENOTEMPTY || err == ErrExist
+}
+
+func isNotExist(err error) bool {
+	err = underlyingError(err)
+	switch err := err.(type) {
+	case zx.Error:
+		return err.Status == zx.ErrNotFound
+	}
+	return err == syscall.ENOENT || err == ErrNotExist
+}
+
+func isPermission(err error) bool {
+	err = underlyingError(err)
+	switch err := err.(type) {
+	case zx.Error:
+		return err.Status == zx.ErrAccessDenied
+	}
+	return err == syscall.EACCES || err == syscall.EPERM || err == ErrPermission
+}
+
+func wrapSyscallError(name string, err error) error {
+	if zerr, ok := err.(zx.Error); ok {
+		text := name
+		if zerr.Text != "" {
+			text = text + ": " + zerr.Text
+		}
+		err = zx.Error{Status: zerr.Status, Text: zerr.Text}
+	}
+	return err
+}
diff --git a/src/os/exec/exec_test.go b/src/os/exec/exec_test.go
index 7bb2308..aad9500 100644
--- a/src/os/exec/exec_test.go
+++ b/src/os/exec/exec_test.go
@@ -537,7 +537,7 @@
 func TestExtraFiles(t *testing.T) {
 	testenv.MustHaveExec(t)
 
-	if runtime.GOOS == "windows" {
+	if runtime.GOOS == "windows" || runtime.GOOS == "fuchsia" {
 		t.Skipf("skipping test on %q", runtime.GOOS)
 	}
 
@@ -612,7 +612,7 @@
 }
 
 func TestExtraFilesRace(t *testing.T) {
-	if runtime.GOOS == "windows" {
+	if runtime.GOOS == "windows" || runtime.GOOS == "fuchsia" {
 		t.Skip("no operating system support; skipping")
 	}
 	listen := func() net.Listener {
diff --git a/src/os/exec/lp_unix.go b/src/os/exec/lp_unix.go
index e098ff8..97b5b72 100644
--- a/src/os/exec/lp_unix.go
+++ b/src/os/exec/lp_unix.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
+// +build darwin dragonfly freebsd fuchsia linux nacl netbsd openbsd solaris
 
 package exec
 
diff --git a/src/os/exec_fuchsia.go b/src/os/exec_fuchsia.go
new file mode 100644
index 0000000..87d6020
--- /dev/null
+++ b/src/os/exec_fuchsia.go
@@ -0,0 +1,83 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os
+
+import (
+	"errors"
+	"syscall/zx"
+	"time"
+)
+
+type ProcessState struct {
+	retCode int
+}
+
+func (p *ProcessState) exited() bool {
+	panic("TODO os.Exited")
+}
+
+func (p *ProcessState) Pid() int {
+	panic("TODO os.Pid")
+}
+
+func (p *ProcessState) String() string {
+	if p == nil {
+		return "<nil>"
+	}
+	return "exit status " + itoa(p.retCode)
+}
+
+func (p *ProcessState) success() bool {
+	return p.retCode == 0
+}
+
+func (p *ProcessState) sys() interface{} {
+	panic("TODO os.sys")
+}
+
+func (p *ProcessState) sysUsage() interface{} {
+	panic("TODO os.sysUsage")
+}
+
+func (p *ProcessState) systemTime() time.Duration {
+	panic("TODO os.systemTime")
+}
+
+func (p *ProcessState) userTime() time.Duration {
+	panic("TODO os.userTime")
+}
+
+func (p *Process) release() error {
+	procHandle := zx.Handle(p.handle)
+	return procHandle.Close()
+}
+
+func (p *Process) signal(sig Signal) error {
+	panic("TODO os.Process.signal")
+}
+
+func findProcess(pid int) (p *Process, err error) {
+	panic("TODO os.findProcess")
+}
+
+func startProcess(name string, argv []string, attr *ProcAttr) (p *Process, err error) {
+	h, err := fdioStartProcess(name, argv, attr)
+	if err != nil {
+		return nil, err
+	}
+	pid := 1 // TODO: what does this even mean for us?
+	return newProcess(pid, uintptr(h)), nil
+}
+
+func hostname() (name string, err error) {
+	return "", errors.New("os.hostname unimplemented")
+}
+
+type signal string
+
+func (s signal) String() string { return string(s) }
+func (s signal) Signal()        {}
+
+var Interrupt = signal("signal_interrupt")
diff --git a/src/os/exec_fuchsia_cgo.go b/src/os/exec_fuchsia_cgo.go
new file mode 100644
index 0000000..7297daa
--- /dev/null
+++ b/src/os/exec_fuchsia_cgo.go
@@ -0,0 +1,206 @@
+// Copyright 2017 The Go 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 fuchsia
+
+package os
+
+// #cgo fuchsia CFLAGS: -I${SRCDIR}/../../../../../zircon/system/ulib/fdio/include
+// #cgo fuchsia LDFLAGS: -lfdio
+//
+// #include <zircon/syscalls/object.h>
+// #include <zircon/types.h>
+// #include <lib/fdio/spawn.h>
+// #include <lib/fdio/util.h>
+// #include <stdlib.h>
+//
+// static int fsa_get_local_fd(fdio_spawn_action_t *fsa) { return fsa->fd.local_fd; }
+// static int fsa_get_target_fd(fdio_spawn_action_t *fsa) { return fsa->fd.target_fd; }
+//
+// static void fsa_set_local_fd(fdio_spawn_action_t *fsa, int fd) { fsa->fd.local_fd = fd; }
+// static void fsa_set_target_fd(fdio_spawn_action_t *fsa, int fd) { fsa->fd.target_fd = fd; }
+import "C"
+
+import (
+	"errors"
+	"strings"
+	"syscall"
+	"syscall/zx"
+	"syscall/zx/fdio"
+	"syscall/zx/zxwait"
+	"unsafe"
+)
+
+func makeCStringArray(s []string) []*C.char {
+	ret := make([]*C.char, len(s)+1)
+	for i, s := range s {
+		ret[i] = (*C.char)(C.CString(s))
+	}
+	ret[len(ret)-1] = nil
+	return ret
+}
+
+func freeCStringArray(a []*C.char) {
+	for i := range a {
+		if a[i] != nil {
+			C.free(unsafe.Pointer(a[i]))
+		}
+	}
+}
+
+// asLibfdioFD returns a File as a libfdio file descriptor.
+func asLibfdioFD(f *File) (int, error) {
+	m := syscall.FDIOForFD(int(f.Fd()))
+	if m == nil {
+		return -1, ErrInvalid
+	}
+
+	var fdioType C.uint32_t
+	switch m.(type) {
+	case *fdio.Object, *fdio.Node, *fdio.File, *fdio.Directory:
+		fdioType = fdio.HandleTypeRemote
+	case *fdio.Pipe:
+		fdioType = fdio.HandleTypePipe
+	case *fdio.Logger:
+		fdioType = fdio.HandleTypeLogger
+	default:
+		return -1, ErrInvalid
+	}
+
+	mCopy, err := m.Clone()
+	if err != nil {
+		return -1, err
+	}
+	handles := mCopy.Handles()
+
+	var handlesC [fdio.MaxUnderlyingHandles]C.zx_handle_t
+	var typesC [fdio.MaxUnderlyingHandles]C.uint32_t
+	for i, h := range handles {
+		handlesC[i] = C.zx_handle_t(h)
+		typesC[i] = C.uint32_t(fdioType)
+	}
+
+	var fd C.int
+	status := zx.Status(C.fdio_create_fd(&handlesC[0], &typesC[0], C.size_t(len(handles)), &fd))
+	if status != zx.ErrOk {
+		mCopy.Close()
+		return -1, errors.New("fdio_create_fd failed")
+	}
+	return int(fd), nil
+}
+
+func fdioSpawnActions(attr *ProcAttr) (actions []C.fdio_spawn_action_t, err error) {
+	defer func() {
+		if err != nil {
+			for _, action := range actions {
+				C.close(C.fsa_get_local_fd(&action))
+			}
+		}
+	}()
+
+	for i, f := range attr.Files {
+		if f == nil {
+			continue
+		}
+		fd, err := asLibfdioFD(f)
+		if err != nil {
+			return nil, err
+		}
+		action := C.fdio_spawn_action_t{action: C.FDIO_SPAWN_ACTION_TRANSFER_FD}
+		C.fsa_set_local_fd(&action, C.int(fd))
+		C.fsa_set_target_fd(&action, C.int(i))
+		actions = append(actions, action)
+	}
+
+	return actions, nil
+}
+
+func fdioStartProcess(name string, argv []string, attr *ProcAttr) (zx.Handle, error) {
+	env := attr.Env
+	if env == nil {
+		env = Environ()
+	}
+	if attr.Dir != "" {
+		found := false
+		for i, s := range env {
+			if strings.HasPrefix(s, "PWD=") {
+				found = true
+				env[i] = "PWD=" + attr.Dir
+				break
+			}
+		}
+		if !found {
+			env = append(env, "PWD="+attr.Dir)
+		}
+	}
+
+	nameC := C.CString(name)
+	defer C.free(unsafe.Pointer(nameC))
+	argvC := makeCStringArray(argv)
+	defer freeCStringArray(argvC)
+	envC := makeCStringArray(env)
+	defer freeCStringArray(envC)
+
+	actions, err := fdioSpawnActions(attr)
+	if err != nil {
+		return 0, err
+	}
+
+	var actions0 *C.fdio_spawn_action_t
+	if len(actions) > 0 {
+		actions0 = &actions[0]
+	}
+
+	var h C.zx_handle_t
+	var errmsg [C.FDIO_SPAWN_ERR_MSG_MAX_LENGTH]C.char
+	status := zx.Status(C.fdio_spawn_etc(
+		C.ZX_HANDLE_INVALID,
+		C.FDIO_SPAWN_CLONE_JOB | C.FDIO_SPAWN_CLONE_LDSVC | C.FDIO_SPAWN_CLONE_NAMESPACE, // TODO(mdempsky): Flags.
+		nameC,
+		&argvC[0],
+		&envC[0],
+		C.size_t(len(actions)),
+		actions0,
+		&h,
+		&errmsg[0],
+	))
+	if status != zx.ErrOk {
+		return 0, errors.New("fdio_spawn_etc: " + itoa(int(status)) + ": " + charsAsString(errmsg[:]))
+	}
+	return zx.Handle(h), nil
+}
+
+func charsAsString(s []C.char) string {
+	var x []byte
+	for _, c := range s {
+		if c == 0 {
+			break
+		}
+		x = append(x, byte(c))
+	}
+	return string(x)
+}
+
+func (p *Process) kill() error {
+	procHandle := zx.Handle(p.handle)
+	status := zx.Sys_task_kill(procHandle)
+	if status != zx.ErrOk {
+		return errors.New("kill error: " + itoa(int(status)))
+	}
+	return nil
+}
+
+func (p *Process) wait() (ps *ProcessState, err error) {
+	procHandle := zx.Handle(p.handle)
+	_, err = zxwait.Wait(procHandle, zx.SignalTaskTerminated, zx.TimensecInfinite)
+	if err != nil {
+		return nil, err
+	}
+	procInfo := C.zx_info_process_t{}
+	status := zx.Sys_object_get_info(procHandle, zx.ObjectInfoProcess, unsafe.Pointer(&procInfo), C.sizeof_zx_info_process_t, nil, nil)
+	if status != zx.ErrOk {
+		return nil, errors.New("error retreiving process info: " + itoa(int(status)))
+	}
+	return &ProcessState{int(procInfo.return_code)}, nil
+}
diff --git a/src/os/executable_procfs.go b/src/os/executable_procfs.go
index 5bb63b9..3c35f23 100644
--- a/src/os/executable_procfs.go
+++ b/src/os/executable_procfs.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build linux netbsd dragonfly nacl js,wasm
+// +build linux netbsd dragonfly nacl js,wasm fuchsia
 
 package os
 
diff --git a/src/os/executable_test.go b/src/os/executable_test.go
index 4a9a883..125d1a3 100644
--- a/src/os/executable_test.go
+++ b/src/os/executable_test.go
@@ -20,6 +20,9 @@
 	testenv.MustHaveExec(t) // will also exclude nacl, which doesn't support Executable anyway
 	ep, err := os.Executable()
 	if err != nil {
+		if runtime.GOOS == "fuchsia" {
+			t.Skipf("Executable failed on %s: %v, expected", runtime.GOOS, err) // TODO(dhobsd): rebase
+		}
 		t.Fatalf("Executable failed: %v", err)
 	}
 	// we want fn to be of the form "dir/prog"
diff --git a/src/os/file_fuchsia.go b/src/os/file_fuchsia.go
new file mode 100644
index 0000000..31ff6af
--- /dev/null
+++ b/src/os/file_fuchsia.go
@@ -0,0 +1,152 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os
+
+import (
+	"errors"
+	"internal/poll"
+	"syscall"
+	"syscall/zx/fdio"
+	"time"
+)
+
+func (f *File) Truncate(size int64) error {
+	if err := f.checkValid("truncate"); err != nil {
+		return err
+	}
+	return syscall.Ftruncate(f.pfd.Sysfd, size)
+}
+
+func (f *File) Sync() error {
+	if f == nil {
+		return ErrInvalid
+	}
+	return syscall.Fsync(f.pfd.Sysfd)
+}
+
+func syscallMode(i FileMode) (o uint32) {
+	o |= uint32(i.Perm())
+	// TODO i&ModeSetuid != 0
+	// TODO i&ModeSetgid != 0
+	// TODO i&ModeSticky != 0
+	return o
+}
+
+func (f *File) chmod(mode FileMode) error {
+	return errors.New("os: Chmod unimplemented on fuchsia")
+}
+
+func (f *File) Chown(uid, gid int) error {
+	return errors.New("os: Chown unimplemented on fuchsia")
+}
+
+func chmod(name string, mode FileMode) error {
+	return errors.New("os: chmod unimplemented on fuchsia")
+}
+
+func Chown(name string, uid, gid int) error {
+	return errors.New("os: Chown unimplemented on fuchsia")
+}
+
+func Chtimes(name string, atime time.Time, mtime time.Time) error {
+	var utimes [2]syscall.Timespec
+	utimes[0] = syscall.NsecToTimespec(atime.UnixNano())
+	utimes[1] = syscall.NsecToTimespec(mtime.UnixNano())
+	if e := syscall.UtimesNano(fixLongPath(name), utimes[0:]); e != nil {
+		return &PathError{"chtimes", name, e}
+	}
+	return nil
+}
+
+func Readlink(name string) (string, error) {
+	return "", errors.New("Readlink unimplemented")
+}
+
+func Pipe() (r *File, w *File, err error) {
+	p0, p1, err := fdio.NewPipes()
+	if err != nil {
+		return nil, nil, err
+	}
+	r = NewFile(uintptr(syscall.OpenFDIO(p0)), "|0")
+	w = NewFile(uintptr(syscall.OpenFDIO(p1)), "|1")
+	// TODO CloseOnExec equivalent
+	return r, w, nil
+}
+
+// Chdir changes the current working directory to the file,
+// which must be a directory.
+// If there is an error, it will be of type *PathError.
+func (f *File) Chdir() error {
+	if err := f.checkValid("chdir"); err != nil {
+		return err
+	}
+	if e := syscall.Fchdir(f.pfd.Sysfd); e != nil {
+		return &PathError{"chdir", f.name, e}
+	}
+	return nil
+}
+
+func sigpipe() // implemented in package runtime
+
+var supportsCloseOnExec = true
+
+func fillFileStatFromSys(fs *fileStat, name string) {
+	fs.name = basename(name)
+	fs.size = int64(fs.sys.Size)
+	// For now, pretend files have all bits. This should really be:
+	// fs.mode = FileMode(fs.sys.Dev & 0777)
+	// but we don't really set file modes properly and testing for executables
+	// in $PATH fails without the x bit set.
+	fs.mode = FileMode(0766)
+
+	switch fs.sys.Dev & 0xf000 {
+	case 0x4000:
+		fs.mode = fs.mode | ModeDir
+	case 0x2000:
+		fs.mode = fs.mode | ModeCharDevice
+	case 0xa000:
+		fs.mode = fs.mode | ModeSymlink
+	case 0xc000:
+		fs.mode = fs.mode | ModeSocket
+	}
+	fs.modTime = time.Unix(int64(fs.sys.ModifyTime), 0)
+}
+
+func atime(fi FileInfo) time.Time {
+	// TODO: fdio doesn't have atime yet
+	return time.Time{}
+}
+
+// setDeadline sets the read and write deadline.
+func (f *File) setDeadline(time.Time) error {
+	if err := f.checkValid("SetDeadline"); err != nil {
+		return err
+	}
+	return poll.ErrNoDeadline
+}
+
+// setReadDeadline sets the read deadline.
+func (f *File) setReadDeadline(time.Time) error {
+	if err := f.checkValid("SetReadDeadline"); err != nil {
+		return err
+	}
+	return poll.ErrNoDeadline
+}
+
+// setWriteDeadline sets the write deadline.
+func (f *File) setWriteDeadline(time.Time) error {
+	if err := f.checkValid("SetWriteDeadline"); err != nil {
+		return err
+	}
+	return poll.ErrNoDeadline
+}
+
+// checkValid checks whether f is valid for use.
+func (f *File) checkValid(op string) error {
+	if f == nil {
+		return ErrInvalid
+	}
+	return nil
+}
diff --git a/src/os/file_unix.go b/src/os/file_unix.go
index cb90b70..9451be1 100644
--- a/src/os/file_unix.go
+++ b/src/os/file_unix.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris
+// +build darwin dragonfly freebsd fuchsia js,wasm linux nacl netbsd openbsd solaris
 
 package os
 
diff --git a/src/os/getwd.go b/src/os/getwd.go
index 6d25466..39a4fd2 100644
--- a/src/os/getwd.go
+++ b/src/os/getwd.go
@@ -24,7 +24,7 @@
 // reached via multiple paths (due to symbolic links),
 // Getwd may return any one of them.
 func Getwd() (dir string, err error) {
-	if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
+	if runtime.GOOS == "windows" || runtime.GOOS == "plan9" || runtime.GOOS == "fuchsia" {
 		return syscall.Getwd()
 	}
 
diff --git a/src/os/os_test.go b/src/os/os_test.go
index 894105a..459b90e 100644
--- a/src/os/os_test.go
+++ b/src/os/os_test.go
@@ -26,15 +26,45 @@
 	"time"
 )
 
-var dot = []string{
-	"dir_unix.go",
-	"env.go",
-	"error.go",
-	"file.go",
-	"os_test.go",
-	"types.go",
-	"stat_darwin.go",
-	"stat_linux.go",
+var dot = func() []string {
+	switch runtime.GOOS {
+	case "fuchsia":
+		return []string{
+			"go_os_test_foo",
+			"go_os_test_bar",
+			"go_os_test_baz",
+		}
+	default:
+		return []string{
+			"dir_unix.go",
+			"env.go",
+			"error.go",
+			"file.go",
+			"os_test.go",
+			"types.go",
+			"stat_darwin.go",
+			"stat_linux.go",
+		}
+	}
+}()
+
+func init() { flag.CommandLine.Set("test.v", "true") }
+
+func tmpInit(t *testing.T) {
+	if runtime.GOOS == "fuchsia" {
+		dir, err := ioutil.TempDir("", "")
+		if err != nil {
+			t.Fatalf("tempdir: %v", err)
+		}
+		for _, fname := range dot {
+			if err := MkdirAll(filepath.Join(dir, fname), ModePerm); err != nil {
+				t.Fatalf("Initializing tmp: %v", err)
+			}
+		}
+		if err := Chdir(dir); err != nil {
+			t.Fatalf("chdir: %v", err)
+		}
+	}
 }
 
 type sysDir struct {
@@ -44,6 +74,14 @@
 
 var sysdir = func() *sysDir {
 	switch runtime.GOOS {
+	case "fuchsia":
+		return &sysDir{
+			"/boot/lib",
+			[]string{
+				"libfdio.so",
+				"ld.so.1",
+			},
+		}
 	case "android":
 		return &sysDir{
 			"/system/lib",
@@ -175,6 +213,9 @@
 }
 
 func TestStatError(t *testing.T) {
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("TODO(dhobsd): fix")
+	}
 	defer chtmpdir(t)()
 
 	path := "no-such-file"
@@ -347,11 +388,13 @@
 }
 
 func TestReaddirnames(t *testing.T) {
+	tmpInit(t)
 	testReaddirnames(".", dot, t)
 	testReaddirnames(sysdir.name, sysdir.files, t)
 }
 
 func TestReaddir(t *testing.T) {
+	tmpInit(t)
 	testReaddir(".", dot, t)
 	testReaddir(sysdir.name, sysdir.files, t)
 }
@@ -469,6 +512,8 @@
 	// big directory that doesn't change often.
 	dir := "/usr/bin"
 	switch runtime.GOOS {
+	case "fuchsia":
+		dir = "/boot/bin"
 	case "android":
 		dir = "/system/bin"
 	case "darwin":
@@ -1030,6 +1075,8 @@
 	switch runtime.GOOS {
 	case "android":
 		t.Skip("android doesn't have /bin/pwd")
+	case "fuchsia":
+		t.Skip("fuchsia doesn't have /bin/pwd")
 	case "windows":
 		cmd = Getenv("COMSPEC")
 		dir = Getenv("SystemRoot")
@@ -1063,8 +1110,8 @@
 }
 
 func TestChmod(t *testing.T) {
-	// Chmod is not supported under windows.
-	if runtime.GOOS == "windows" {
+	// Chmod is not supported under windows or Fuchsia
+	if runtime.GOOS == "windows" || runtime.GOOS == "fuchsia" {
 		return
 	}
 	f := newFile("TestChmod", t)
@@ -1137,6 +1184,11 @@
 // On NFS, timings can be off due to caching of meta-data on
 // NFS servers (Issue 848).
 func TestChtimes(t *testing.T) {
+	if runtime.GOOS == "fuchsia" {
+		// It passes sometimes, but seems to be flakey
+		t.Skipf("TODO(smklein): Implement")
+	}
+
 	f := newFile("TestChtimes", t)
 	defer Remove(f.Name())
 
@@ -1151,6 +1203,11 @@
 // On NFS, timings can be off due to caching of meta-data on
 // NFS servers (Issue 848).
 func TestChtimesDir(t *testing.T) {
+	if runtime.GOOS == "fuchsia" {
+		// It passes sometimes, but seems to be flakey
+		t.Skipf("TODO(smklein): Implement")
+	}
+
 	name := newDir("TestChtimes", t)
 	defer RemoveAll(name)
 
@@ -1182,7 +1239,7 @@
 	pmt := postStat.ModTime()
 	if !pat.Before(at) {
 		switch runtime.GOOS {
-		case "plan9", "nacl":
+		case "plan9", "nacl", "fuchsia":
 			// Ignore.
 			// Plan 9, NaCl:
 			// Mtime is the time of the last change of
@@ -1208,7 +1265,7 @@
 
 func TestChdirAndGetwd(t *testing.T) {
 	// TODO(brainman): file.Chdir() is not implemented on windows.
-	if runtime.GOOS == "windows" {
+	if runtime.GOOS == "windows" || runtime.GOOS == "fuchsia" {
 		return
 	}
 	fd, err := Open(".")
@@ -1439,6 +1496,10 @@
 }
 
 func TestOpenError(t *testing.T) {
+	if runtime.GOOS == "fuchsia" {
+		t.Skipf("TODO(smklein): Implement")
+	}
+
 	for _, tt := range openErrorTests {
 		f, err := OpenFile(tt.path, tt.mode, 0)
 		if err == nil {
@@ -1536,6 +1597,10 @@
 }
 
 func TestHostname(t *testing.T) {
+	if runtime.GOOS == "fuchsia" {
+		t.Skipf("TODO(dho): Implement")
+	}
+
 	hostname, err := Hostname()
 	if err != nil {
 		t.Fatal(err)
@@ -1760,6 +1825,10 @@
 }
 
 func TestSameFile(t *testing.T) {
+	if runtime.GOOS == "fuchsia" {
+		t.Skipf("TODO(smklein): Implement")
+	}
+
 	defer chtmpdir(t)()
 	fa, err := Create("a")
 	if err != nil {
@@ -1810,13 +1879,13 @@
 	if fi.Size() != 0 {
 		t.Errorf(pre+"wrong file size have %d want 0", fi.Size())
 	}
-	if fi.Mode()&ModeDevice == 0 {
+	if fi.Mode()&ModeDevice == 0 && runtime.GOOS != "fuchsia" {
 		t.Errorf(pre+"wrong file mode %q: ModeDevice is not set", fi.Mode())
 	}
 	if fi.Mode()&ModeCharDevice == 0 {
 		t.Errorf(pre+"wrong file mode %q: ModeCharDevice is not set", fi.Mode())
 	}
-	if fi.Mode().IsRegular() {
+	if fi.Mode().IsRegular() && runtime.GOOS != "fuchsia" {
 		t.Errorf(pre+"wrong file mode %q: IsRegular returns true", fi.Mode())
 	}
 }
@@ -1873,6 +1942,10 @@
 }
 
 func TestStatDirModeExec(t *testing.T) {
+	if runtime.GOOS == "fuchsia" {
+		t.Skipf("TODO(smklein): Implement")
+	}
+
 	const mode = 0111
 
 	path, err := ioutil.TempDir("", "go-build")
@@ -1896,7 +1969,8 @@
 
 func TestStatStdin(t *testing.T) {
 	switch runtime.GOOS {
-	case "android", "plan9":
+	case "android", "plan9", "fuchsia":
+		// TODO(smklein): Implement on Fuchsia
 		t.Skipf("%s doesn't have /bin/sh", runtime.GOOS)
 	}
 
@@ -2012,6 +2086,10 @@
 }
 
 func TestLongPath(t *testing.T) {
+	if runtime.GOOS == "fuchsia" {
+		t.Skipf("no chmod support on fuchsia")
+	}
+
 	tmpdir := newDir("TestLongPath", t)
 	defer func(d string) {
 		if err := RemoveAll(d); err != nil {
@@ -2068,9 +2146,11 @@
 					if dir.Size() != filesize || filesize != wantSize {
 						t.Errorf("Size(%q) is %d, len(ReadFile()) is %d, want %d", path, dir.Size(), filesize, wantSize)
 					}
-					err = Chmod(path, dir.Mode())
-					if err != nil {
-						t.Fatalf("Chmod(%q) failed: %v", path, err)
+					if testenv.HasChmod() {
+						err = Chmod(path, dir.Mode())
+						if err != nil {
+							t.Fatalf("Chmod(%q) failed: %v", path, err)
+						}
 					}
 				}
 				if err := Truncate(sizedTempDir+"/bar.txt", 0); err != nil {
@@ -2123,6 +2203,9 @@
 		// TODO: golang.org/issue/8206
 		t.Skipf("skipping test on plan9; see issue 8206")
 	}
+	if runtime.GOOS == "fuchsia" {
+		t.Skipf("TODO(smklein): Implement")
+	}
 
 	testenv.MustHaveExec(t)
 
@@ -2148,6 +2231,10 @@
 }
 
 func TestKillFindProcess(t *testing.T) {
+	if runtime.GOOS == "fuchsia" {
+		t.Skipf("TODO(smklein): Implement")
+	}
+
 	testKillProcess(t, func(p *Process) {
 		p2, err := FindProcess(p.Pid)
 		if err != nil {
@@ -2183,6 +2270,10 @@
 
 // Test that all File methods give ErrInvalid if the receiver is nil.
 func TestNilFileMethods(t *testing.T) {
+	if runtime.GOOS == "fuchsia" {
+		t.Skipf("TODO(smklein): Implement")
+	}
+
 	for _, tt := range nilFileMethodTests {
 		var file *File
 		got := tt.f(file)
@@ -2254,6 +2345,8 @@
 		t.Skip("skipping on Plan 9; does not support runtime poller")
 	case "js":
 		t.Skip("skipping on js; no support for os.Pipe")
+	case "fuchsia":
+		t.Skip("skipping on fuchsia; TODO")
 	}
 
 	threads := 100
diff --git a/src/os/path_test.go b/src/os/path_test.go
index f58c7e7..9ab3f14 100644
--- a/src/os/path_test.go
+++ b/src/os/path_test.go
@@ -230,7 +230,7 @@
 
 func TestMkdirAllAtSlash(t *testing.T) {
 	switch runtime.GOOS {
-	case "android", "plan9", "windows":
+	case "android", "fuchsia", "plan9", "windows":
 		t.Skipf("skipping on %s", runtime.GOOS)
 	case "darwin":
 		switch runtime.GOARCH {
diff --git a/src/os/path_unix.go b/src/os/path_unix.go
index b2e0bca..9d81f61 100644
--- a/src/os/path_unix.go
+++ b/src/os/path_unix.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris
+// +build darwin dragonfly freebsd fuchsia js,wasm linux nacl netbsd openbsd solaris
 
 package os
 
diff --git a/src/os/pipe_test.go b/src/os/pipe_test.go
index 59d31e5..ec81d8f 100644
--- a/src/os/pipe_test.go
+++ b/src/os/pipe_test.go
@@ -3,7 +3,7 @@
 // license that can be found in the LICENSE file.
 
 // Test broken pipes on Unix systems.
-// +build !windows,!plan9,!nacl,!js
+// +build !windows,!plan9,!nacl,!js,!fuchsia
 
 package os_test
 
@@ -397,6 +397,10 @@
 }
 
 func TestFdReadRace(t *testing.T) {
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("deadlines are TODO on fuchsia")
+	}
+
 	t.Parallel()
 
 	r, w, err := os.Pipe()
diff --git a/src/os/signal/signal_fuchsia.go b/src/os/signal/signal_fuchsia.go
new file mode 100644
index 0000000..c27eba3
--- /dev/null
+++ b/src/os/signal/signal_fuchsia.go
@@ -0,0 +1,25 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package signal
+
+import "os"
+
+const numSig = 65
+
+func signum(sig os.Signal) int {
+	panic("TODO")
+}
+
+func enableSignal(sig int) {
+	panic("TODO")
+}
+
+func disableSignal(sig int) {
+	panic("TODO")
+}
+
+func ignoreSignal(sig int) {
+	panic("TODO")
+}
diff --git a/src/os/stat_unix.go b/src/os/stat_unix.go
index 856b499..85af8d7 100644
--- a/src/os/stat_unix.go
+++ b/src/os/stat_unix.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris
+// +build darwin dragonfly freebsd fuchsia js,wasm linux nacl netbsd openbsd solaris
 
 package os
 
diff --git a/src/os/timeout_test.go b/src/os/timeout_test.go
index 1886acc..4ac191d 100644
--- a/src/os/timeout_test.go
+++ b/src/os/timeout_test.go
@@ -62,6 +62,10 @@
 }
 
 func TestReadTimeout(t *testing.T) {
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("deadlines are TODO on fuchsia")
+	}
+
 	t.Parallel()
 
 	r, w, err := os.Pipe()
@@ -102,6 +106,9 @@
 }
 
 func TestReadTimeoutMustNotReturn(t *testing.T) {
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("file read timeouts are TODO on fuchsia")
+	}
 	t.Parallel()
 
 	r, w, err := os.Pipe()
@@ -153,6 +160,10 @@
 }
 
 func TestWriteTimeout(t *testing.T) {
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("deadlines are TODO on fuchsia")
+	}
+
 	t.Parallel()
 
 	for i, tt := range writeTimeoutTests {
@@ -190,6 +201,10 @@
 }
 
 func TestWriteTimeoutMustNotReturn(t *testing.T) {
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("deadlines are TODO on fuchsia")
+	}
+
 	t.Parallel()
 
 	r, w, err := os.Pipe()
@@ -256,6 +271,10 @@
 }
 
 func TestReadTimeoutFluctuation(t *testing.T) {
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("deadlines are TODO on fuchsia")
+	}
+
 	t.Parallel()
 
 	r, w, err := os.Pipe()
@@ -307,6 +326,10 @@
 }
 
 func TestWriteTimeoutFluctuation(t *testing.T) {
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("deadlines are TODO on fuchsia")
+	}
+
 	t.Parallel()
 
 	r, w, err := os.Pipe()
@@ -365,6 +388,10 @@
 }
 
 func testVariousDeadlines(t *testing.T) {
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("deadlines are TODO on fuchsia")
+	}
+
 	type result struct {
 		n   int64
 		err error
@@ -458,6 +485,10 @@
 }
 
 func TestReadWriteDeadlineRace(t *testing.T) {
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("deadlines are TODO on fuchsia")
+	}
+
 	t.Parallel()
 
 	N := 1000
@@ -514,6 +545,10 @@
 // TestRacyRead tests that it is safe to mutate the input Read buffer
 // immediately after cancelation has occurred.
 func TestRacyRead(t *testing.T) {
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("deadlines are TODO on fuchsia")
+	}
+
 	t.Parallel()
 
 	r, w, err := os.Pipe()
@@ -553,6 +588,10 @@
 // TestRacyWrite tests that it is safe to mutate the input Write buffer
 // immediately after cancelation has occurred.
 func TestRacyWrite(t *testing.T) {
+	if runtime.GOOS == "fuchsia" {
+		t.Skip("deadlines are TODO on fuchsia")
+	}
+
 	t.Parallel()
 
 	r, w, err := os.Pipe()
diff --git a/src/os/user/lookup_fuchsia.go b/src/os/user/lookup_fuchsia.go
new file mode 100644
index 0000000..80fa82c
--- /dev/null
+++ b/src/os/user/lookup_fuchsia.go
@@ -0,0 +1,38 @@
+// Copyright 2016 The Go 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 fuchsia
+
+package user
+
+import "errors"
+
+func init() {
+	userImplemented = false
+	groupImplemented = false
+}
+
+func current() (*User, error) {
+	return nil, errors.New("user: Current not implemented on fuchsia")
+}
+
+func lookupUser(string) (*User, error) {
+	return nil, errors.New("user: Lookup not implemented on fuchsia")
+}
+
+func lookupUserId(string) (*User, error) {
+	return nil, errors.New("user: LookupId not implemented on fuchsia")
+}
+
+func lookupGroup(string) (*Group, error) {
+	return nil, errors.New("user: LookupGroup not implemented on fuchsia")
+}
+
+func lookupGroupId(string) (*Group, error) {
+	return nil, errors.New("user: LookupGroupId not implemented on fuchsia")
+}
+
+func listGroups(*User) ([]string, error) {
+	return nil, errors.New("user: GroupIds not implemented on fuchsia")
+}
diff --git a/src/os/user/lookup_stubs.go b/src/os/user/lookup_stubs.go
index f7d138f..71638de 100644
--- a/src/os/user/lookup_stubs.go
+++ b/src/os/user/lookup_stubs.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,!windows,!plan9 android osusergo,!windows,!plan9
+// +build !cgo,!windows,!plan9 android osusergo,!windows,!plan9,!fuchsia
 
 package user
 
diff --git a/src/path/filepath/path_unix.go b/src/path/filepath/path_unix.go
index 349dea7..66644d8 100644
--- a/src/path/filepath/path_unix.go
+++ b/src/path/filepath/path_unix.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris
+// +build darwin dragonfly freebsd fuchsia js,wasm linux nacl netbsd openbsd solaris
 
 package filepath
 
diff --git a/src/runtime/asm_amd64.s b/src/runtime/asm_amd64.s
index 6902ce2..97d2a4e 100644
--- a/src/runtime/asm_amd64.s
+++ b/src/runtime/asm_amd64.s
@@ -161,8 +161,8 @@
 	JMP ok
 #endif
 
-	LEAQ	runtime·m0+m_tls(SB), DI
-	CALL	runtime·settls(SB)
+	LEAQ    runtime·m0+m_tls(SB), DI
+	CALL    runtime·settls(SB)
 
 	// store through it, to make sure it works
 	get_tls(BX)
diff --git a/src/runtime/cgo/cgo.go b/src/runtime/cgo/cgo.go
index 241a821..bd1cd0e 100644
--- a/src/runtime/cgo/cgo.go
+++ b/src/runtime/cgo/cgo.go
@@ -16,6 +16,7 @@
 #cgo darwin,arm64 LDFLAGS: -framework CoreFoundation
 #cgo dragonfly LDFLAGS: -lpthread
 #cgo freebsd LDFLAGS: -lpthread
+#cgo fuchsia LDFLAGS: -lpthread -lfdio
 #cgo android LDFLAGS: -llog
 #cgo !android,linux LDFLAGS: -lpthread
 #cgo netbsd LDFLAGS: -lpthread
diff --git a/src/runtime/cgo/fdio.go b/src/runtime/cgo/fdio.go
new file mode 100644
index 0000000..d843125
--- /dev/null
+++ b/src/runtime/cgo/fdio.go
@@ -0,0 +1,15 @@
+// Copyright 2016 The Go 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 fuchsia
+
+package cgo
+
+import _ "unsafe" // for go:linkname
+
+//go:cgo_import_static x_cgo_get_initial_handles
+//go:linkname x_cgo_get_initial_handles x_cgo_get_initial_handles
+//go:linkname _cgo_get_initial_handles runtime._cgo_get_initial_handles
+var x_cgo_get_initial_handles byte
+var _cgo_get_initial_handles = &x_cgo_get_initial_handles
diff --git a/src/runtime/cgo/gcc_fatalf.c b/src/runtime/cgo/gcc_fatalf.c
index fdcf6f5..1f416b5 100644
--- a/src/runtime/cgo/gcc_fatalf.c
+++ b/src/runtime/cgo/gcc_fatalf.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 !android,linux freebsd
+// +build !android,linux freebsd fuchsia
 
 #include <stdarg.h>
 #include <stdio.h>
diff --git a/src/runtime/cgo/gcc_fdio.c b/src/runtime/cgo/gcc_fdio.c
new file mode 100644
index 0000000..db21dcb
--- /dev/null
+++ b/src/runtime/cgo/gcc_fdio.c
@@ -0,0 +1,81 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build cgo
+// +build fuchsia
+
+#include "libcgo.h"
+
+#include <stdlib.h>
+#include <zircon/process.h>
+#include <zircon/processargs.h>
+#include <lib/fdio/io.h>
+#include <lib/fdio/namespace.h>
+#include <lib/fdio/util.h>
+
+extern char **environ;
+
+// fdio_init matches a Go struct of the same name in os_fuchsia.go.
+struct fdio_init {
+	zx_handle_t stdioClones[3 * FDIO_MAX_HANDLES];
+	uint32_t stdioCloneNumHandles[3];
+	uint32_t stdioCloneTypes[3];
+	zx_handle_t processSelf;
+	zx_handle_t vmarRootSelf;
+	int32_t unused;
+	int32_t envlen;
+	char**  environ;
+	int32_t unused2;
+	int32_t rootNSNumHandles;
+	zx_handle_t *rootNSHandles;
+	char** rootNSPaths;
+};
+
+void
+x_cgo_get_initial_handles(struct fdio_init *handles)
+{
+	// When running with cgo support, there are two FDIO libraries in the
+	// same process. We let the C FDIO start first, then clone its root
+	// and use that for Go.
+	// TODO: there is some small amount of fdio library state we
+	//       have to share between Go and C, in particular, cwd.
+	//       Work out how.
+
+	// fdio may have initialized std{in,out,err} with a single fd if the FDIO_FLAG_USE_FOR_STDIO
+	// flag was set, or have separate in/out/err fds. We clone fds {0,1,2} to separate fds for use
+	// in the Go runtime. The cloned fds aren't installed into fdio's fd table so they are only
+	// usable from Go's table.
+	zx_status_t r;
+	for (int i = 0; i < 3; ++i) {
+		uint32_t handle_types[FDIO_MAX_HANDLES];
+		r = fdio_clone_fd(i, 0, &handles->stdioClones[i * FDIO_MAX_HANDLES], handle_types);
+		if (r <= 0) {
+			printf("runtime/cgo: fdio_clone_fd of stdio[%d] failed: %d\n", i, r);
+			handles->stdioCloneNumHandles[i] = 0;
+		} else {
+			handles->stdioCloneNumHandles[i] = r;
+			handles->stdioCloneTypes[i] = PA_HND_TYPE(handle_types[0]);
+		}
+	}
+
+	handles->processSelf = zx_process_self();
+	handles->vmarRootSelf = zx_vmar_root_self();
+
+	for (char** env = environ; *env; env++) {
+		handles->envlen++;
+	}
+	handles->environ = environ;
+
+	fdio_flat_namespace_t* rootNS;
+	r = fdio_ns_export_root(&rootNS);
+	if (r < 0) {
+		handles->rootNSNumHandles = 0;
+		handles->rootNSHandles = NULL;
+		handles->rootNSPaths = NULL;
+	} else {
+		handles->rootNSNumHandles = (int32_t)rootNS->count;
+		handles->rootNSHandles = rootNS->handle;
+		handles->rootNSPaths = (char**)rootNS->path;
+	}
+}
diff --git a/src/runtime/cgo/gcc_fuchsia_amd64.c b/src/runtime/cgo/gcc_fuchsia_amd64.c
new file mode 100644
index 0000000..ae65662
--- /dev/null
+++ b/src/runtime/cgo/gcc_fuchsia_amd64.c
@@ -0,0 +1,52 @@
+// 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 <pthread.h>
+#include <errno.h>
+#include <string.h> // strerror
+#include <signal.h>
+#include <stdlib.h>
+#include "libcgo.h"
+
+static void* threadentry(void*);
+static void (*setg_gcc)(void*);
+
+void
+x_cgo_init(G* g, void (*setg)(void*))
+{
+	setg_gcc = setg;
+}
+
+void
+_cgo_sys_thread_start(ThreadStart *ts)
+{
+	// TODO: switch to threads.h.
+	pthread_attr_t attr;
+	pthread_t p;
+	size_t size;
+	int err;
+
+	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);
+
+	if (err != 0) {
+		fatalf("pthread_create failed: %s", strerror(err));
+	}
+}
+
+static void*
+threadentry(void *v)
+{
+	ThreadStart ts;
+
+	ts = *(ThreadStart*)v;
+	free(v);
+	setg_gcc((void*)ts.g);
+
+	crosscall_amd64(ts.fn);
+	return 0;
+}
diff --git a/src/runtime/cgo/gcc_fuchsia_arm64.c b/src/runtime/cgo/gcc_fuchsia_arm64.c
new file mode 100644
index 0000000..e79d192
--- /dev/null
+++ b/src/runtime/cgo/gcc_fuchsia_arm64.c
@@ -0,0 +1,53 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include <pthread.h>
+#include <errno.h>
+#include <string.h> // strerror
+#include <signal.h>
+#include <stdlib.h>
+#include "libcgo.h"
+
+#include <stdio.h>
+
+static void* threadentry(void*);
+static void (*setg_gcc)(void*);
+
+void
+x_cgo_init(G* g, void (*setg)(void*))
+{
+	setg_gcc = setg;
+}
+
+void
+_cgo_sys_thread_start(ThreadStart *ts)
+{
+	pthread_attr_t attr;
+	pthread_t p;
+	size_t size;
+	int err;
+
+	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);
+
+	if (err != 0) {
+		fatalf("pthread_create failed: %s", strerror(err));
+	}
+}
+
+extern void crosscall1(void (*fn)(void), void (*setg_gcc)(void*), void *g);
+static void*
+threadentry(void *v)
+{
+	ThreadStart ts;
+
+	ts = *(ThreadStart*)v;
+	free(v);
+
+	crosscall1(ts.fn, setg_gcc, (void*)ts.g);
+	return 0;
+}
diff --git a/src/runtime/cgo/gcc_libinit.c b/src/runtime/cgo/gcc_libinit.c
index 3dc5bde..5a6d8fa 100644
--- a/src/runtime/cgo/gcc_libinit.c
+++ b/src/runtime/cgo/gcc_libinit.c
@@ -3,7 +3,7 @@
 // license that can be found in the LICENSE file.
 
 // +build cgo
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build darwin dragonfly freebsd fuchsia linux netbsd openbsd solaris
 
 #include <pthread.h>
 #include <errno.h>
diff --git a/src/runtime/cgo/gcc_setenv.c b/src/runtime/cgo/gcc_setenv.c
index ed5d203..2f2581d 100644
--- a/src/runtime/cgo/gcc_setenv.c
+++ b/src/runtime/cgo/gcc_setenv.c
@@ -3,7 +3,7 @@
 // license that can be found in the LICENSE file.
 
 // +build cgo
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build darwin dragonfly freebsd fuchsia linux netbsd openbsd solaris
 
 #include "libcgo.h"
 
diff --git a/src/runtime/cgo/setenv.go b/src/runtime/cgo/setenv.go
index fab4339..7fe251a 100644
--- a/src/runtime/cgo/setenv.go
+++ b/src/runtime/cgo/setenv.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build darwin dragonfly freebsd fuchsia linux netbsd openbsd solaris
 
 package cgo
 
diff --git a/src/runtime/env_posix.go b/src/runtime/env_posix.go
index 032e712..afd5fce 100644
--- a/src/runtime/env_posix.go
+++ b/src/runtime/env_posix.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris windows
+// +build darwin dragonfly freebsd fuchsia js,wasm linux nacl netbsd openbsd solaris windows
 
 package runtime
 
diff --git a/src/runtime/internal/sys/zgoos_android.go b/src/runtime/internal/sys/zgoos_android.go
index bfdc377..de8cdee 100644
--- a/src/runtime/internal/sys/zgoos_android.go
+++ b/src/runtime/internal/sys/zgoos_android.go
@@ -12,6 +12,7 @@
 const GoosFreebsd = 0
 const GoosJs = 0
 const GoosLinux = 0
+const GoosFuchsia = 0
 const GoosNacl = 0
 const GoosNetbsd = 0
 const GoosOpenbsd = 0
diff --git a/src/runtime/internal/sys/zgoos_darwin.go b/src/runtime/internal/sys/zgoos_darwin.go
index 1c4667f..f569e9d 100644
--- a/src/runtime/internal/sys/zgoos_darwin.go
+++ b/src/runtime/internal/sys/zgoos_darwin.go
@@ -12,6 +12,7 @@
 const GoosFreebsd = 0
 const GoosJs = 0
 const GoosLinux = 0
+const GoosFuchsia = 0
 const GoosNacl = 0
 const GoosNetbsd = 0
 const GoosOpenbsd = 0
diff --git a/src/runtime/internal/sys/zgoos_dragonfly.go b/src/runtime/internal/sys/zgoos_dragonfly.go
index 728bf6a..40988a4 100644
--- a/src/runtime/internal/sys/zgoos_dragonfly.go
+++ b/src/runtime/internal/sys/zgoos_dragonfly.go
@@ -12,6 +12,7 @@
 const GoosFreebsd = 0
 const GoosJs = 0
 const GoosLinux = 0
+const GoosFuchsia = 0
 const GoosNacl = 0
 const GoosNetbsd = 0
 const GoosOpenbsd = 0
diff --git a/src/runtime/internal/sys/zgoos_freebsd.go b/src/runtime/internal/sys/zgoos_freebsd.go
index a8d6591..4a2120d 100644
--- a/src/runtime/internal/sys/zgoos_freebsd.go
+++ b/src/runtime/internal/sys/zgoos_freebsd.go
@@ -12,6 +12,7 @@
 const GoosFreebsd = 1
 const GoosJs = 0
 const GoosLinux = 0
+const GoosFuchsia = 0
 const GoosNacl = 0
 const GoosNetbsd = 0
 const GoosOpenbsd = 0
diff --git a/src/runtime/internal/sys/zgoos_fuchsia.go b/src/runtime/internal/sys/zgoos_fuchsia.go
new file mode 100644
index 0000000..22de240
--- /dev/null
+++ b/src/runtime/internal/sys/zgoos_fuchsia.go
@@ -0,0 +1,18 @@
+// generated by gengoos.go using 'go generate'
+
+package sys
+
+const GOOS = `fuchsia`
+
+const GoosAndroid = 0
+const GoosDarwin = 0
+const GoosDragonfly = 0
+const GoosFreebsd = 0
+const GoosLinux = 0
+const GoosFuchsia = 1
+const GoosNacl = 0
+const GoosNetbsd = 0
+const GoosOpenbsd = 0
+const GoosPlan9 = 0
+const GoosSolaris = 0
+const GoosWindows = 0
diff --git a/src/runtime/internal/sys/zgoos_linux.go b/src/runtime/internal/sys/zgoos_linux.go
index 289400c..f9a4922 100644
--- a/src/runtime/internal/sys/zgoos_linux.go
+++ b/src/runtime/internal/sys/zgoos_linux.go
@@ -13,6 +13,7 @@
 const GoosFreebsd = 0
 const GoosJs = 0
 const GoosLinux = 1
+const GoosFuchsia = 0
 const GoosNacl = 0
 const GoosNetbsd = 0
 const GoosOpenbsd = 0
diff --git a/src/runtime/internal/sys/zgoos_nacl.go b/src/runtime/internal/sys/zgoos_nacl.go
index 3fedb0a..b3c2c01 100644
--- a/src/runtime/internal/sys/zgoos_nacl.go
+++ b/src/runtime/internal/sys/zgoos_nacl.go
@@ -12,6 +12,7 @@
 const GoosFreebsd = 0
 const GoosJs = 0
 const GoosLinux = 0
+const GoosFuchsia = 0
 const GoosNacl = 1
 const GoosNetbsd = 0
 const GoosOpenbsd = 0
diff --git a/src/runtime/internal/sys/zgoos_netbsd.go b/src/runtime/internal/sys/zgoos_netbsd.go
index 3346e37..83f33b3 100644
--- a/src/runtime/internal/sys/zgoos_netbsd.go
+++ b/src/runtime/internal/sys/zgoos_netbsd.go
@@ -12,6 +12,7 @@
 const GoosFreebsd = 0
 const GoosJs = 0
 const GoosLinux = 0
+const GoosFuchsia = 0
 const GoosNacl = 0
 const GoosNetbsd = 1
 const GoosOpenbsd = 0
diff --git a/src/runtime/internal/sys/zgoos_openbsd.go b/src/runtime/internal/sys/zgoos_openbsd.go
index 13c0323..114ea61 100644
--- a/src/runtime/internal/sys/zgoos_openbsd.go
+++ b/src/runtime/internal/sys/zgoos_openbsd.go
@@ -12,6 +12,7 @@
 const GoosFreebsd = 0
 const GoosJs = 0
 const GoosLinux = 0
+const GoosFuchsia = 0
 const GoosNacl = 0
 const GoosNetbsd = 0
 const GoosOpenbsd = 1
diff --git a/src/runtime/internal/sys/zgoos_plan9.go b/src/runtime/internal/sys/zgoos_plan9.go
index 6b2e977..53282e9 100644
--- a/src/runtime/internal/sys/zgoos_plan9.go
+++ b/src/runtime/internal/sys/zgoos_plan9.go
@@ -12,6 +12,7 @@
 const GoosFreebsd = 0
 const GoosJs = 0
 const GoosLinux = 0
+const GoosFuchsia = 0
 const GoosNacl = 0
 const GoosNetbsd = 0
 const GoosOpenbsd = 0
diff --git a/src/runtime/internal/sys/zgoos_solaris.go b/src/runtime/internal/sys/zgoos_solaris.go
index cbf70f0..dcadcc2 100644
--- a/src/runtime/internal/sys/zgoos_solaris.go
+++ b/src/runtime/internal/sys/zgoos_solaris.go
@@ -12,6 +12,7 @@
 const GoosFreebsd = 0
 const GoosJs = 0
 const GoosLinux = 0
+const GoosFuchsia = 0
 const GoosNacl = 0
 const GoosNetbsd = 0
 const GoosOpenbsd = 0
diff --git a/src/runtime/internal/sys/zgoos_windows.go b/src/runtime/internal/sys/zgoos_windows.go
index 70839ca..20fef09 100644
--- a/src/runtime/internal/sys/zgoos_windows.go
+++ b/src/runtime/internal/sys/zgoos_windows.go
@@ -12,6 +12,7 @@
 const GoosFreebsd = 0
 const GoosJs = 0
 const GoosLinux = 0
+const GoosFuchsia = 0
 const GoosNacl = 0
 const GoosNetbsd = 0
 const GoosOpenbsd = 0
diff --git a/src/runtime/lock_futex.go b/src/runtime/lock_futex.go
index b590c4b..129b1ef 100644
--- a/src/runtime/lock_futex.go
+++ b/src/runtime/lock_futex.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
+// +build dragonfly freebsd fuchsia linux
 
 package runtime
 
diff --git a/src/runtime/mem_fuchsia.go b/src/runtime/mem_fuchsia.go
new file mode 100644
index 0000000..e74883a
--- /dev/null
+++ b/src/runtime/mem_fuchsia.go
@@ -0,0 +1,81 @@
+// Copyright 2016 The Go 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 (
+	"syscall/zx"
+	"unsafe"
+)
+
+//go:nosplit
+func sysAlloc(n uintptr, sysStat *uint64) unsafe.Pointer {
+	var p unsafe.Pointer
+	sysMmap(unsafe.Pointer(&p), n, zx.VMFlagPermRead|zx.VMFlagPermWrite)
+	if uintptr(p) < 4096 {
+		println("runtime: sysMmap failed n=", n)
+		exit(2)
+	}
+	mSysStatInc(sysStat, n)
+	return p
+}
+
+func sysUnused(v unsafe.Pointer, n uintptr) {
+	// TODO(dho): Implement this based on ZX_VMO_OP_DECOMMIT
+}
+
+func sysUsed(v unsafe.Pointer, n uintptr) {
+	// TODO(dho): Maybe implement this based on ZX_VMO_OP_COMMIT
+}
+
+//go:nosplit
+func sysFree(v unsafe.Pointer, n uintptr, sysStat *uint64) {
+	mSysStatDec(sysStat, n)
+	if status := zx.Sys_vmar_unmap(zx.Handle(zx.VMARRoot), zx.Vaddr(v), uint64(n)); status != zx.ErrOk {
+		println("runtime: zx.Sys_vmar_unmap failed: ", status.String())
+	}
+}
+
+func sysMmap(ptr unsafe.Pointer, sz uintptr, flags zx.VMFlag) {
+	var h zx.Handle
+	if status := zx.Sys_vmo_create(uint64(sz), 0, &h); status != zx.ErrOk {
+		println("runtime: zx.Sys_vmo_create failed: ", status.String())
+		exit(2)
+	}
+
+	prop := []byte("go-sys-mmap")
+	if status := zx.Sys_object_set_property(h, zx.PropName, unsafe.Pointer(&prop[0]), uint(len(prop))); status != zx.ErrOk {
+		println("runtime: zx.Sys_object_set_property failed: ", status.String())
+		exit(2)
+	}
+
+	if status := zx.Sys_vmar_map(zx.Handle(zx.VMARRoot), 0, h, 0, uint64(sz), uint32(flags), (*zx.Vaddr)(ptr)); status != zx.ErrOk {
+		println("runtime: zx.Sys_vmar_map failed: ", status.String())
+		exit(2)
+	}
+
+	if status := zx.Sys_handle_close(h); status != zx.ErrOk {
+		println("runtime: zx.Sys_handle_close failed: ", status.String())
+		exit(2)
+	}
+}
+
+func sysReserve(v unsafe.Pointer, n uintptr) unsafe.Pointer {
+	p := v
+	sysMmap(unsafe.Pointer(&p), n, 0)
+	return p
+}
+
+func sysFault(v unsafe.Pointer, n uintptr) {
+	println("TODO sysFault")
+}
+
+func sysMap(v unsafe.Pointer, n uintptr, sysStat *uint64) {
+	mSysStatInc(sysStat, n)
+
+	if status := zx.Sys_vmar_protect(zx.Handle(zx.VMARRoot), zx.Vaddr(v), uint64(n), uint32(zx.VMFlagPermRead|zx.VMFlagPermWrite)); status != zx.ErrOk {
+		println("runtime: zx.Sys_vmar_protect failed: ", status.String())
+		exit(2)
+	}
+}
diff --git a/src/runtime/netpoll_stub.go b/src/runtime/netpoll_stub.go
index a4d6b46..03bd97d 100644
--- a/src/runtime/netpoll_stub.go
+++ b/src/runtime/netpoll_stub.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build plan9
+// +build fuchsia plan9
 
 package runtime
 
diff --git a/src/runtime/os_fuchsia.go b/src/runtime/os_fuchsia.go
new file mode 100644
index 0000000..7a33e81
--- /dev/null
+++ b/src/runtime/os_fuchsia.go
@@ -0,0 +1,317 @@
+// Copyright 2016 The Go 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 (
+	"syscall/zx"
+	"unsafe"
+)
+
+type mOS struct{}
+
+type sigset struct{}
+
+//go:nosplit
+func getRandomData(r []byte) {
+	zx.RandRead(r)
+}
+
+//go:nosplit
+func futexsleep(addr *uint32, val uint32, ns int64) {
+	deadline := zx.Sys_deadline_after(zx.Duration(ns))
+	if ns < 0 {
+		deadline = zx.Time(zx.TimensecInfinite)
+	}
+	zx.Sys_futex_wait((*int)(unsafe.Pointer(addr)), int32(val), deadline)
+}
+
+//go:nosplit
+func futexwakeup(addr *uint32, cnt uint32) {
+	zx.Sys_futex_wake((*int)(unsafe.Pointer(addr)), cnt)
+}
+
+//go:nosplit
+func osyield() {
+	zx.Sys_nanosleep(0)
+}
+
+// cgocallm0 calls a C function on the current stack.
+//
+// It is intended for use inside functions like osinit that run
+// before mstart directly on an OS thread stack.
+//
+// If in doubt, do not use.
+func cgocallm0(fn, arg unsafe.Pointer)
+
+func osinit() {
+	if _cgo_get_initial_handles != nil {
+		cgocallm0(_cgo_get_initial_handles, unsafe.Pointer(&fdioHandles))
+		for i := 0; i < 3; i = i + 1 {
+			for j := 0; j < int(fdioHandles.stdioCloneNumHandles[i]); j = j + 1 {
+				zx.StdioHandles[i][j] = fdioHandles.stdioClones[i*3+j]
+			}
+			zx.StdioHandleTypes[i] = int(fdioHandles.stdioCloneTypes[i])
+		}
+		zx.ProcHandle = zx.Handle(fdioHandles.processSelf)
+		zx.VMARRoot = zx.VMAR(fdioHandles.vmarRootSelf)
+	} else {
+		// TODO: implement cgo-less init
+		println("runtime: no fuchsia process handle without cgo yet")
+		exit(2)
+	}
+
+	ncpu = int32(zx.Sys_system_get_num_cpus())
+	physPageSize = 4096
+}
+
+func parseRootNS() {
+	if fdioHandles.rootNSNumHandles > 0 {
+		const maxHandleCount = 1 << 20 // arbitrary
+		paths := (*(*[maxHandleCount]*byte)(unsafe.Pointer(fdioHandles.rootNSPaths)))[:fdioHandles.rootNSNumHandles]
+		handles := (*(*[maxHandleCount]zx.Handle)(unsafe.Pointer(fdioHandles.rootNSHandles)))[:fdioHandles.rootNSNumHandles]
+		zx.RootNSMap = make(map[string]zx.Handle)
+		for i, p := range paths {
+			zx.RootNSMap[gostring(p)] = handles[i]
+		}
+	}
+}
+
+// Filled in by runtime/cgo when linked into binary.
+var _cgo_get_initial_handles unsafe.Pointer // pointer to C function
+
+func minit() {
+}
+
+//go:nosplit
+func unminit() {
+	// TODO
+}
+
+func sigpanic() {
+	// TODO
+}
+
+func mpreinit(mp *m) {
+	// TODO
+}
+
+//go:nosplit
+func msigsave(mp *m) {
+	// TODO
+}
+
+//go:nosplit
+func msigrestore(sigmask sigset) {
+	// TODO
+}
+
+func initsig(preinit bool) {
+	// TODO
+}
+
+//go:nosplit
+func sigblock() {
+	// TODO
+}
+
+func sigenable(sig uint32) {
+	// TODO
+}
+
+func sigdisable(sig uint32) {
+	// TODO
+}
+
+func sigignore(sig uint32) {
+	// TODO
+}
+
+func crash() {
+	*(*int32)(nil) = 0
+}
+
+func threadinit(mp *m)
+
+var gothreadname = []byte("gothread")
+
+//go:nowritebarrier
+func newosproc(mp *m) {
+	stk := unsafe.Pointer(mp.g0.stack.hi)
+	p := zx.Handle(0) // TODO: only works due to temporary hack in zircon
+	var h zx.Handle
+	status := zx.Sys_thread_create(p, &gothreadname[0], uint(len(gothreadname)), 0, &h)
+	if status < 0 {
+		println("runtime: newosproc zx.Sys_thread_create failed:", h)
+		exit(2)
+	}
+
+	status = zx.Sys_thread_start(h, zx.Vaddr(funcPC(threadinit)), zx.Vaddr(stk), uintptr(unsafe.Pointer(mp)), 0)
+	if status < 0 {
+		println("runtime: newosproc zx.Sys_thread_start failed:", h)
+		exit(2)
+	}
+}
+
+type zx_proc_args struct {
+	protocol        uint32
+	version         uint32
+	handle_info_off uint32
+	args_off        uint32
+	args_num        uint32
+}
+
+type zx_proc_info struct {
+	magic         uint32
+	version       uint32
+	next_tls_slot uint32
+	proc_args     *zx_proc_args
+	handle        *zx.Handle
+	handle_info   *uint32
+	handle_count  int32
+	argv          **byte
+	argc          int32
+}
+
+type zx_tls_root struct {
+	self     *zx_tls_root
+	proc     *zx_proc_info
+	magic    uint32
+	flags    uint16
+	maxslots uint16
+	slots    [8]uintptr // has length maxslots
+}
+
+func resetcpuprofiler(hz int32) {
+	// TODO
+}
+
+// fdio_init matches a Go struct of the same name in gcc_fdio.c.
+type fdio_init struct {
+	stdioClones          [9]zx.Handle // 3 * fdio.MaxHandles
+	stdioCloneNumHandles [3]uint32
+	stdioCloneTypes      [3]uint32
+	processSelf          zx.Handle
+	vmarRootSelf         zx.Handle
+	_                    int32
+	envlen               int32
+	environ              **byte
+	_                    int32
+	rootNSNumHandles     int32
+	rootNSHandles        *zx.Handle
+	rootNSPaths          **byte
+}
+
+var fdioHandles fdio_init
+
+func goenvs() {
+	if _cgo_get_initial_handles != nil {
+		const maxEnvSize = 1 << 20 // arbitrary
+		envp := (*(*[maxEnvSize]*byte)(unsafe.Pointer(fdioHandles.environ)))[:fdioHandles.envlen]
+		envs = make([]string, len(envp))
+		for i, e := range envp {
+			envs[i] = gostring(e)
+		}
+		// TODO: find a better place to call this
+		parseRootNS()
+	} else {
+		// TODO: implement cgo-less init
+		println("runtime: no fuchsia process handle without cgo yet")
+		exit(2)
+	}
+}
+
+const _NSIG = 65 // TODO
+
+//go:nosplit
+func nanotime() int64 {
+	const ZX_CLOCK_MONOTONIC = 0
+	return int64(zx.Sys_clock_get(ZX_CLOCK_MONOTONIC))
+}
+
+//go:linkname time_now time.now
+//go:nosplit
+func time_now() (sec int64, nsec int32, mono int64) {
+	const ZX_CLOCK_UTC = 1
+	x := int64(zx.Sys_clock_get(ZX_CLOCK_UTC))
+	return int64(x / 1e9), int32(x % 1e9), nanotime() - startNano
+}
+
+func unixnanotime() int64 {
+	return nanotime()
+}
+
+var logger zx.Handle
+var logBufferArray [1024]byte
+var logBufferN int
+
+//go:nosplit
+func write(fd uintptr, buf unsafe.Pointer, n int32) int32 {
+	if fd == 1 || fd == 2 {
+		// This initialization mechanism is not thread-safe, but if the only calls to 'write' with
+		// these file descriptors come from print, they will already be serialized by a lock in
+		// print's implementation.
+		if logger <= 0 {
+			zx.Sys_debuglog_create(0, 0, &logger)
+			logBufferN = 0
+		}
+		if logger > 0 {
+			// Sys_log_write adds a newline to output buffers. To prevent fragmented logs, we buffer
+			// output until a newline character is encountered.
+			logBufferN += copy(logBufferArray[logBufferN:], (*[1 << 30]byte)(buf)[:n])
+			if logBufferArray[logBufferN-1] == '\n' {
+				status := zx.Sys_log_write(logger, uint32(logBufferN), unsafe.Pointer(&logBufferArray[0]), 0)
+				// Flush buffer, regardless of status returned from write
+				logBufferN = 0
+				if status < 0 {
+					return int32(status)
+				}
+			}
+		}
+	}
+	// TODO
+	return n
+}
+
+//go:nosplit
+func exit(code int32) {
+	zx.Sys_process_exit(int64(code))
+}
+
+//go:nosplit
+func usleep(usec uint32) {
+	zx.Sys_nanosleep(zx.Sys_deadline_after(zx.Duration(usec * 1000)))
+}
+
+func signame(sig uint32) string {
+	return "unknown_sig" // TODO
+}
+
+// zircon_mktls
+//go:nosplit
+func zircon_mktls() {
+	// TODO
+}
+
+//go:nosplit
+func zircon_settls(val uintptr) {
+	// TODO: should call zx_set_object_property with property ZX_PROP_REGISTER_FS in amd64 or
+	// ZX_PROP_REGISTER_CP15 on arm.
+}
+
+//go:linkname os_sigpipe os.sigpipe
+func os_sigpipe() {
+	// TODO
+}
+
+// gsignalStack is unused on fuchsia
+type gsignalStack struct{}
+
+func exitThread(wait *uint32)        {}
+func setProcessCPUProfiler(hz int32) {}
+func setThreadCPUProfiler(hz int32)  {}
+
+//go:nosplit
+//go:nowritebarrierrec
+func clearSignalHandlers() {}
diff --git a/src/runtime/os_fuchsia_arm64.go b/src/runtime/os_fuchsia_arm64.go
new file mode 100644
index 0000000..143fe39
--- /dev/null
+++ b/src/runtime/os_fuchsia_arm64.go
@@ -0,0 +1,12 @@
+// Copyright 2016 The Go 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 "syscall/zx"
+
+//go:nosplit
+func cputicks() int64 {
+	return int64(zx.Sys_ticks_get())
+}
diff --git a/src/runtime/rt0_fuchsia_amd64.s b/src/runtime/rt0_fuchsia_amd64.s
new file mode 100644
index 0000000..40c92a3
--- /dev/null
+++ b/src/runtime/rt0_fuchsia_amd64.s
@@ -0,0 +1,8 @@
+// Copyright 2016 The Go 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_amd64_fuchsia(SB),NOSPLIT,$-8
+	JMP	_rt0_amd64(SB)
diff --git a/src/runtime/rt0_fuchsia_arm64.s b/src/runtime/rt0_fuchsia_arm64.s
new file mode 100644
index 0000000..f28e28d
--- /dev/null
+++ b/src/runtime/rt0_fuchsia_arm64.s
@@ -0,0 +1,14 @@
+// Copyright 2016 The Go 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_arm64_fuchsia(SB),NOSPLIT,$-8
+	MOVD 0(RSP),  R0 // argc
+	ADD  $8, RSP, R1 // argv
+	BL   main(SB)
+
+TEXT main(SB),NOSPLIT,$-8
+	MOVD $runtime·rt0_go(SB), R2
+	BL   R2
diff --git a/src/runtime/stubs2.go b/src/runtime/stubs2.go
index 02249d0..d91b8c4 100644
--- a/src/runtime/stubs2.go
+++ b/src/runtime/stubs2.go
@@ -8,6 +8,7 @@
 // +build !nacl
 // +build !js
 // +build !darwin
+// +build !fuchsia
 
 package runtime
 
diff --git a/src/runtime/stubs3.go b/src/runtime/stubs3.go
index 5c0786e..777fce2 100644
--- a/src/runtime/stubs3.go
+++ b/src/runtime/stubs3.go
@@ -8,6 +8,7 @@
 // +build !nacl
 // +build !freebsd
 // +build !darwin
+// +build !fuchsia
 
 package runtime
 
diff --git a/src/runtime/sys_manual_fuchsia_amd64.s b/src/runtime/sys_manual_fuchsia_amd64.s
new file mode 100644
index 0000000..81e9c90
--- /dev/null
+++ b/src/runtime/sys_manual_fuchsia_amd64.s
@@ -0,0 +1,71 @@
+// Copyright 2016 The Go 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 "go_asm.h"
+#include "go_tls.h"
+#include "textflag.h"
+
+TEXT runtime·threadinit(SB),NOSPLIT,$0
+	MOVQ	DI, R8
+
+	MOVQ	m_g0(R8), DX		// g
+	MOVQ	R8, g_m(DX)
+
+	// Layout new m scheduler stack on os stack.
+	// TODO: which os stack? do we need to make a new vmo?
+	LEAQ	(-8*1024+104)(SP), BX
+	MOVQ	BX, g_stackguard0(DX)
+	MOVQ	BX, g_stackguard1(DX)
+	MOVQ	BX, (g_stack+stack_lo)(DX)
+	MOVQ	SP, (g_stack+stack_hi)(DX)
+
+	PUSHQ	R8
+
+	// Set up tls.
+	LEAQ	m_tls(R8), DI
+	CALL 	runtime·settls(SB)
+
+	get_tls(CX)
+
+	POPQ	R8
+	MOVQ	m_g0(R8), DX
+	MOVQ	DX, g(CX)
+
+	CLD				// convention is D is always left cleared
+	CALL	runtime·stackcheck(SB)	// clobbers AX,CX
+	CALL	runtime·mstart(SB)
+	// TODO CALL	syscall/zx·Sys_zircon_thread_exit(SB)
+	RET
+
+// set tls base to DI
+// Note that this code is only used when CGO_ENABLED=0.
+// Not using syscall/zx so we can avoid setting up a G.
+//
+// TODO: make VSDO call directly here, avoid the syscall.
+TEXT runtime·settls(SB),NOSPLIT,$8
+	ADDQ   $8, DI	// ELF wants to use -8(FS)
+	PUSHQ  DI
+	LEAQ   0(SP), DX // prctl on zircon takes a pointer, not the value
+	MOVQ $0, DI
+	MOVQ $0, SI
+	MOVQ $0xff00ff00000035, AX // ZIRCON_SYSCALL_MAGIC | thread_arch_prctl (53)
+	SYSCALL
+	CMPQ	AX, $0xfffffffffffff001
+	JLS	2(PC)
+	MOVL	$0xf1, 0xf1  // crash
+	POPQ  DI
+	RET
+
+TEXT ·cgocallm0(SB),NOSPLIT,$0-20
+	MOVQ fn+0(FP), AX
+	MOVQ arg+8(FP), DI
+
+	MOVQ SP, BP // BP is callee-save in the x86-64 ABI
+
+	ANDQ $~15, SP
+	CALL AX
+
+	MOVQ BP, SP
+	get_tls(CX)
+	RET
diff --git a/src/runtime/sys_manual_fuchsia_arm64.s b/src/runtime/sys_manual_fuchsia_arm64.s
new file mode 100644
index 0000000..36b8107
--- /dev/null
+++ b/src/runtime/sys_manual_fuchsia_arm64.s
@@ -0,0 +1,42 @@
+// Copyright 2016 The Go 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 "go_asm.h"
+#include "funcdata.h"
+#include "textflag.h"
+
+TEXT runtime·threadinit(SB),NOSPLIT,$0
+	// Layout new m scheduler stack on os stack.
+	// TODO: which os stack? do we need to make a new vmo?
+
+	MOVD	m_g0(R0), g
+	MOVD	R0, g_m(g)
+
+	MOVD RSP, R7
+	MOVD $(-64*1024)(R7), R0
+	MOVD R0, g_stackguard0(g)
+	MOVD R0, g_stackguard1(g)
+	MOVD R0, (g_stack+stack_lo)(g)
+	MOVD R7, (g_stack+stack_hi)(g)
+
+	BL	runtime·mstart(SB)
+	MOVD	$0, R0
+	MOVD	R0, (R0)	// boom
+	UNDEF
+
+TEXT ·cgocallm0(SB),NOSPLIT,$0-20
+	MOVD fn+0(FP), R1
+	MOVD arg+8(FP), R0
+
+	MOVD RSP, R19 // R19 is callee-save by C
+	MOVD g, R21   // R21 is callee-save by C
+	MOVD RSP, R7
+	ADD  $-32, R7, R7
+	AND  $~15, R7
+	MOVD R7, RSP  // align stack for C
+	BL   R1
+
+	MOVD R19, RSP // restore SP
+	MOVD R21, g   // restore g
+	RET
diff --git a/src/runtime/timestub.go b/src/runtime/timestub.go
index f9230da..2c73258 100644
--- a/src/runtime/timestub.go
+++ b/src/runtime/timestub.go
@@ -6,6 +6,7 @@
 // indirectly, in terms of walltime and nanotime assembly.
 
 // +build !windows
+// +build !fuchsia
 
 package runtime
 
diff --git a/src/runtime/tls_arm64.h b/src/runtime/tls_arm64.h
index c29fa7f..c2480d7 100644
--- a/src/runtime/tls_arm64.h
+++ b/src/runtime/tls_arm64.h
@@ -9,6 +9,9 @@
 #ifdef GOOS_linux
 #define TLS_linux
 #endif
+#ifdef GOOS_fuchsia
+#define TLS_linux
+#endif
 #ifdef TLS_linux
 #define TPIDR TPIDR_EL0
 #define MRS_TPIDR_R0 WORD $0xd53bd040 // MRS TPIDR_EL0, R0
diff --git a/src/syscall/dirent.go b/src/syscall/dirent.go
index 26cbbbc..a85c818 100644
--- a/src/syscall/dirent.go
+++ b/src/syscall/dirent.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris
+// +build darwin dragonfly freebsd fuchsia js,wasm linux nacl netbsd openbsd solaris
 
 package syscall
 
diff --git a/src/syscall/env_unix.go b/src/syscall/env_unix.go
index 1ebc0b1..f4e1f65 100644
--- a/src/syscall/env_unix.go
+++ b/src/syscall/env_unix.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris
+// +build darwin dragonfly freebsd fuchsia js,wasm linux nacl netbsd openbsd solaris
 
 // Unix environment variables.
 
diff --git a/src/syscall/exec_fuchsia.go b/src/syscall/exec_fuchsia.go
new file mode 100644
index 0000000..3904808
--- /dev/null
+++ b/src/syscall/exec_fuchsia.go
@@ -0,0 +1,10 @@
+// Copyright 2016 The Go 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 ()
+
+type SysProcAttr struct {
+}
diff --git a/src/syscall/syscall_fuchsia.go b/src/syscall/syscall_fuchsia.go
new file mode 100644
index 0000000..68c138b
--- /dev/null
+++ b/src/syscall/syscall_fuchsia.go
@@ -0,0 +1,686 @@
+// Copyright 2016 The Go 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 (
+	"errors"
+	"io"
+	"path"
+	"strings"
+	"sync"
+	"unsafe"
+
+	"syscall/zx"
+	"syscall/zx/fdio"
+	"syscall/zx/fidl"
+	fidlIo "syscall/zx/io"
+)
+
+var (
+	Stdin  = 0
+	Stdout = 1
+	Stderr = 2
+)
+
+const (
+	FsRightReadable = 0x00000001
+	FsRightWritable = 0x00000002
+	FsRightAdmin    = 0x00000004
+	FsRightRight    = 0x0000FFFF
+	FsFlagCreate    = 0x00010000
+	FsFlagExclusive = 0x00020000
+	FsFlagTruncate  = 0x00040000
+	FsFlagDirectory = 0x00080000
+	FsFlagAppend    = 0x00100000
+	FsFlagNoRemote  = 0x00200000
+	FsFlagPath      = 0x00400000
+	FsFlagDescribe  = 0x00800000
+)
+
+const (
+	O_RDONLY   = 0x0
+	O_WRONLY   = 0x1
+	O_RDWR     = 0x2
+	O_PIPELINE = 0x80000000
+
+	// Flags which align with ZXIO_FS_*
+	O_ADMIN     = FsRightAdmin
+	O_CREAT     = FsFlagCreate
+	O_EXCL      = FsFlagExclusive
+	O_TRUNC     = FsFlagTruncate
+	O_DIRECTORY = FsFlagDirectory
+	O_APPEND    = FsFlagAppend
+	O_NOREMOTE  = FsFlagNoRemote
+	O_PATH      = FsFlagPath
+
+	FdioAlignedFlags = O_ADMIN | O_CREAT | O_EXCL | O_TRUNC | O_DIRECTORY | O_APPEND |
+		O_NOREMOTE | O_PATH
+
+	// Flags which do not align with ZXIO_FS_*
+	O_NONBLOCK  = 0x00000010
+	O_DSYNC     = 0x00000020
+	O_SYNC      = 0x00000040 | O_DSYNC
+	O_RSYNC     = O_SYNC
+	O_NOFOLLOW  = 0x00000080
+	O_CLOEXEC   = 0x00000100
+	O_NOCTTY    = 0x00000200
+	O_ASYNC     = 0x00000400
+	O_DIRECT    = 0x00000800
+	O_LARGEFILE = 0x00001000
+	O_NOATIME   = 0x00002000
+	O_TMPFILE   = 0x00004000
+)
+
+func FdioFlagsToZxio(flags uint32) (zflags uint32) {
+	perms := uint32(O_RDONLY | O_WRONLY | O_RDWR)
+	switch flags & perms {
+	case O_RDONLY:
+		zflags |= FsRightReadable
+	case O_WRONLY:
+		zflags |= FsRightWritable
+	case O_RDWR:
+		zflags |= FsRightReadable | FsRightWritable
+	}
+
+	if (flags & O_PIPELINE) == 0 {
+		zflags |= FsFlagDescribe
+	}
+
+	zflags |= (flags & FdioAlignedFlags)
+	return zflags
+}
+
+const (
+	S_IFMT  = 0000170000
+	S_IFDIR = 0000040000
+	S_IFREG = 0000100000
+	S_IFIFO = 0000010000
+)
+
+// TODO(crawshaw): generate a zerrors file once cgo is working
+const (
+	EPERM         = Errno(0x01)
+	ENOENT        = Errno(0x02)
+	EINTR         = Errno(0x04)
+	EIO           = Errno(0x05)
+	EBADF         = Errno(0x09)
+	EACCES        = Errno(0x0d)
+	EEXIST        = Errno(0x11)
+	ENOTDIR       = Errno(0x14)
+	EISDIR        = Errno(0x15)
+	EINVAL        = Errno(0x16)
+	EMFILE        = Errno(0x18)
+	ESPIPE        = Errno(0x1d)
+	ENAMETOOLONG  = Errno(0x24)
+	ENOTEMPTY     = Errno(0x27)
+	ENOPROTOOPT   = Errno(0x5c)
+	EOPNOTSUPP    = Errno(0x5f)
+	ENOTSUP       = EOPNOTSUPP
+	EADDRINUSE    = Errno(0x62)
+	EADDRNOTAVAIL = Errno(0x63)
+	ETIMEDOUT     = Errno(0x6e)
+	ECONNABORTED  = Errno(0x67)
+	EHOSTUNREACH  = Errno(0x71)
+	EFUCHSIA      = Errno(0xfa)
+)
+
+var EPIPE error = Errno(0x20)
+
+const (
+	SOMAXCONN = 0x80
+)
+
+const (
+	PathMax = 4096
+)
+
+type Stat_t struct {
+	Dev        uint64
+	Ino        uint64
+	Size       uint64
+	CreateTime uint64
+	ModifyTime uint64
+	Mode       uint64
+}
+
+func Getpid() (pid int) {
+	// TODO: is ProcHandle process-wide or OS-wide?
+	return int(zx.ProcHandle)
+}
+
+func Getppid() (ppid int) {
+	return 0
+}
+
+func Getuid() (uid int) {
+	return 0
+}
+
+func Geteuid() (uid int) {
+	return 0
+}
+
+func Getgid() (uid int) {
+	return 0
+}
+
+func Getegid() (uid int) {
+	return 0
+}
+
+func Getgroups() (gids []int, err error) {
+	return nil, errors.New("Getgroups unimplemented")
+}
+
+//func Exit(code int) {
+//zx.Sys_process_exit(int64(code))
+//}
+
+const ImplementsGetwd = true
+
+func Getwd() (wd string, err error) {
+	cwdMu.Lock()
+	wd = cwdStr
+	cwdMu.Unlock()
+	return wd, nil
+}
+
+func Chdir(dir string) (err error) {
+	// TODO: if cgo enabled, change the working directory there too.
+	f, err := OpenPath(dir, 0, 0)
+	if err != nil {
+		return err
+	}
+	cwdMu.Lock()
+	var old fdio.FDIO
+	old, cwd = cwd, f
+	// cwd starts as a reference to root, which should remain open.
+	if old != nil && old != root {
+		defer old.Close()
+	}
+	if path.IsAbs(dir) {
+		cwdStr = path.Clean(dir)
+	} else {
+		cwdStr = path.Join(cwdStr, dir)
+	}
+	cwdMu.Unlock()
+	return nil
+}
+
+func Mkdir(path string, mode uint32) (err error) {
+	f, err := OpenPath(path, O_CREAT|O_EXCL|O_RDWR, mode&0777|S_IFDIR)
+	if err != nil {
+		return err
+	}
+	f.Close()
+	return nil
+}
+
+func Rmdir(path string) error {
+	return Unlink(path)
+}
+
+func Unlink(p string) error {
+	dir, relp := fdioPath(path.Clean(p))
+	return dir.Unlink(relp)
+}
+
+func makeAbs(paths ...string) []string {
+	cwdMu.Lock()
+	dir := cwdStr
+	cwdMu.Unlock()
+	for i := range paths {
+		if !path.IsAbs(paths[i]) {
+			paths[i] = path.Join(dir, paths[i])
+		}
+	}
+	return paths
+}
+
+func Rename(oldpath, newpath string) error {
+	abs := makeAbs(oldpath, newpath)
+	rootMu.Lock()
+	r := root
+	rootMu.Unlock()
+	return r.Rename(abs[0][1:], abs[1][1:])
+}
+
+func Link(oldpath, newpath string) error {
+	abs := makeAbs(oldpath, newpath)
+	rootMu.Lock()
+	r := root
+	rootMu.Unlock()
+	return r.Link(abs[0][1:], abs[1][1:])
+}
+
+func Fsync(fd int) error {
+	fdsMu.Lock()
+	f := fds[fd-fdsOff]
+	fdsMu.Unlock()
+	return f.Sync()
+}
+
+func Fchdir(fd int) (err error) {
+	return errors.New("Fchdir unimplemented")
+}
+
+func CloseOnExec(r int) {
+	panic("syscall.CloseOnExec TODO")
+}
+
+func SetNonblock(fd int, nonblocking bool) (err error) {
+	if nonblocking {
+		return errors.New("syscall.SetNonblock: non-blocking not supported on fuchsia")
+	}
+	return nil
+}
+
+var (
+	rootMu sync.Mutex
+	root   fdio.FDIO
+)
+
+var (
+	cwdMu  sync.Mutex
+	cwd    fdio.FDIO
+	cwdStr string
+)
+
+var (
+	nsMu sync.Mutex
+	ns   *fdio.NS
+)
+
+var (
+	stdioMu sync.Mutex
+	stdin   fdio.FDIO
+	stdout  fdio.FDIO
+	stderr  fdio.FDIO
+)
+
+const fdsOff = 1e6 // move outside the fd range of unistd.c  FDIO
+
+var (
+	fdsMu sync.Mutex
+	fds   []fdio.FDIO
+)
+
+func Read(fd int, p []byte) (n int, err error) {
+	if fd == Stdin {
+		stdioMu.Lock()
+		n, err = stdin.Read(p)
+		stdioMu.Unlock()
+	} else {
+		if fd < fdsOff {
+			return 0, EINVAL
+		}
+		fdsMu.Lock()
+		f := fds[fd-fdsOff]
+		fdsMu.Unlock()
+
+		n, err = f.Read(p)
+	}
+	// An io.Reader can return n < len(p) and io.EOF.
+	// But this is the POSIX syscall read(3), which
+	// returns nil on eof.
+	if err == io.EOF {
+		err = nil
+	}
+	return n, err
+}
+
+func init() {
+	EPIPE = zx.EPIPE
+
+	var err error
+
+	nsMu.Lock()
+	ns, err = fdio.NewNSFromMap(zx.RootNSMap)
+	nsMu.Unlock()
+	if err != nil {
+		println("syscall: failed to create namespace: ", err.Error())
+	}
+
+	rootMu.Lock()
+	root, err = ns.OpenRoot()
+	rootMu.Unlock()
+	if err != nil {
+		println("syscall: failed to create root directory from namespace: ", err.Error())
+	}
+
+	cwdMu.Lock()
+	var found bool
+	cwdStr, found = Getenv("PWD")
+	if !found {
+		cwdStr = "/"
+	} else {
+		// Ensure the incoming cwd is absolute and cleaned
+		cwdStr = path.Join("/", cwdStr)
+	}
+	cwd = root
+	if cwdStr != "/" {
+		cwd, err = OpenPath(cwdStr, 0, 0)
+	}
+	cwdMu.Unlock()
+	if err != nil {
+		println("syscall: failed to create fdio cwd: ", err.Error())
+	}
+
+	initStdio := func(i int) (fdio.FDIO, error) {
+		switch zx.StdioHandleTypes[i] {
+		case 0:
+			return nil, EINVAL
+		case fdio.HandleTypeRemote:
+			obj := (*fidlIo.ObjectInterface)(&fidl.Proxy{Channel: zx.Channel(zx.StdioHandles[i][0])})
+			return &fdio.File{Node: fdio.Node{Object: fdio.Object{obj}}}, nil
+		case fdio.HandleTypePipe:
+			return fdio.NewPipe(zx.Socket(zx.StdioHandles[i][0])), nil
+		case fdio.HandleTypeLogger:
+			return fdio.NewLogger(zx.Log(zx.StdioHandles[i][0])), nil
+		default:
+			println("syscall: unknown handle type for stdio: " + itoa(zx.StdioHandleTypes[i]))
+			return nil, EINVAL
+		}
+	}
+	stdioMu.Lock()
+	stdin, err = initStdio(0)
+	if err != nil {
+		println("syscall: failed to create fdio stdin: ", err.Error())
+	}
+	stdout, err = initStdio(1)
+	if err != nil {
+		println("syscall: failed to create fdio stdiout: ", err.Error())
+	}
+	stderr, err = initStdio(2)
+	if err != nil {
+		println("syscall: failed to create fdio stderr: ", err.Error())
+	}
+	stdioMu.Unlock()
+}
+
+func Write(fd int, p []byte) (n int, err error) {
+	switch fd {
+	case Stdout:
+		stdioMu.Lock()
+		n, err := stdout.Write(p)
+		stdioMu.Unlock()
+		return n, err
+	case Stderr:
+		stdioMu.Lock()
+		n, err := stderr.Write(p)
+		stdioMu.Unlock()
+		return n, err
+	default:
+		fdsMu.Lock()
+		f := fds[fd-fdsOff]
+		fdsMu.Unlock()
+		return f.Write(p)
+	}
+	return 0, EINVAL
+}
+
+func Seek(fd int, offset int64, whence int) (off int64, err error) {
+	fdsMu.Lock()
+	f := fds[fd-fdsOff]
+	fdsMu.Unlock()
+	off, err = f.Seek(offset, whence)
+	if err != nil {
+		if status, isStatus := err.(zx.Error); isStatus {
+			if status.Status == zx.ErrNotSupported {
+				if _, isPipe := f.(*fdio.Pipe); isPipe {
+					return off, ESPIPE
+				}
+			}
+		}
+	}
+	return off, err
+}
+
+func Close(fd int) (err error) {
+	if fd < fdsOff {
+		return EINVAL
+	}
+	fdsMu.Lock()
+	if fd-fdsOff > len(fds) {
+		fdsMu.Unlock()
+		return EINVAL
+	}
+	f := fds[fd-fdsOff]
+	fds[fd-fdsOff] = nil
+	fdsMu.Unlock()
+	return f.Close()
+}
+
+func fdioPath(p string) (fdio.FDIO, string) {
+	if path.IsAbs(p) {
+		rootMu.Lock()
+		r := root
+		rootMu.Unlock()
+		return r, p[1:]
+	}
+	cwdMu.Lock()
+	c := cwd
+	cwdMu.Unlock()
+	return c, p
+}
+
+func OpenPath(p string, mode int, perm uint32) (f fdio.FDIO, err error) {
+	if strings.Contains(p, "\x00") {
+		return nil, EINVAL
+	}
+	dir, relp := fdioPath(path.Clean(p))
+	return dir.Open(relp, FdioFlagsToZxio(uint32(mode)), perm)
+}
+
+func Open(path string, mode int, perm uint32) (fd int, err error) {
+	if path == "" {
+		return -1, EINVAL
+	}
+	f, err := OpenPath(path, mode, perm)
+	if err != nil {
+		return -1, err
+	}
+	return OpenFDIO(f), nil
+}
+
+func OpenAt(fdParent int, path string, mode int, perm uint32) (fd int, err error) {
+	parent := FDIOForFD(fdParent)
+	if parent == nil {
+		return -1, EBADF
+	}
+	f, err := parent.Open(path, FdioFlagsToZxio(uint32(mode)), perm)
+	if err != nil {
+		return -1, err
+	}
+	return OpenFDIO(f), nil
+}
+
+func FDIOForFD(fd int) fdio.FDIO {
+	switch fd {
+	case Stdin:
+		return stdin
+	case Stdout:
+		return stdout
+	case Stderr:
+		return stderr
+	}
+	if fd < fdsOff {
+		return nil
+	}
+	fdsMu.Lock()
+	if fd-fdsOff > len(fds) {
+		fdsMu.Unlock()
+		return nil
+	}
+	f := fds[fd-fdsOff]
+	fdsMu.Unlock()
+	return f
+}
+
+func OpenFDIO(f fdio.FDIO) (fd int) {
+	fdsMu.Lock()
+	i := -1
+	for i = 0; i < len(fds); i++ {
+		if fds[i] == nil {
+			fds[i] = f
+			break
+		}
+	}
+	if i == len(fds) {
+		fds = append(fds, f)
+	}
+	fdsMu.Unlock()
+
+	return i + fdsOff
+}
+
+func Ioctl(fd int, op uint32, max uint64, in []byte, handles []zx.Handle) ([]byte, []zx.Handle, error) {
+	fdsMu.Lock()
+	f := fds[fd-fdsOff]
+	fdsMu.Unlock()
+	return f.Ioctl(op, max, in, handles)
+}
+
+func Fstat(fd int, stat *Stat_t) (err error) {
+	fdsMu.Lock()
+	f := fds[fd-fdsOff]
+	fdsMu.Unlock()
+
+	attr, err := f.GetAttr()
+	if err != nil {
+		return err
+	}
+	stat.Dev = uint64(attr.Mode)
+	stat.Ino = attr.Id
+	stat.Size = attr.ContentSize
+	stat.CreateTime = attr.CreationTime
+	stat.ModifyTime = attr.ModificationTime
+	return nil
+}
+
+func Stat(path string, stat *Stat_t) (err error) {
+	fd, err := Open(path, O_RDONLY, 0)
+	if err != nil {
+		return err
+	}
+	err = Fstat(fd, stat)
+	if err2 := Close(fd); err == nil {
+		err = err2
+	}
+	return err
+}
+
+func Lstat(path string, stat *Stat_t) (err error) {
+	// TODO: adjust when there are symlinks
+	return Stat(path, stat)
+}
+
+func Pread(fd int, p []byte, offset int64) (n int, err error) {
+	if fd == Stdout || fd == Stderr {
+		return 0, ESPIPE
+	}
+
+	fdsMu.Lock()
+	f := fds[fd-fdsOff]
+	fdsMu.Unlock()
+
+	// An io.Reader can return n < len(p) and io.EOF.
+	// But this is the POSIX syscall read(3), which
+	// returns nil on eof.
+	n, err = f.ReadAt(p, offset)
+	if err == io.EOF {
+		err = nil
+	}
+	return n, err
+}
+
+func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
+	if fd == Stdout || fd == Stderr {
+		return 0, ESPIPE
+	}
+
+	fdsMu.Lock()
+	f := fds[fd-fdsOff]
+	fdsMu.Unlock()
+	return f.WriteAt(p, offset)
+}
+
+func Ftruncate(fd int, length int64) (err error) {
+	fdsMu.Lock()
+	f := fds[fd-fdsOff]
+	fdsMu.Unlock()
+	return f.Truncate(uint64(length))
+}
+
+func Truncate(path string, length int64) (err error) {
+	fd, err := Open(path, O_WRONLY, 0)
+	if err != nil {
+		return err
+	}
+	err = Ftruncate(fd, length)
+	if err2 := Close(fd); err == nil {
+		err = err2
+	}
+	return err
+}
+
+func Symlink(oldpath string, newpath string) (err error) {
+	return EOPNOTSUPP // no fuchsia support yet
+}
+
+func UtimesNano(path string, ts []Timespec) (err error) {
+	f, err := OpenPath(path, 0, 0)
+	if err != nil {
+		return err
+	}
+	defer f.Close()
+	return f.SetAttr(fidlIo.KNodeAttributeFlagModificationTime, fidlIo.NodeAttributes{
+		ModificationTime: uint64(TimespecToNsec(ts[1])),
+	})
+}
+
+func clen(n []byte) int {
+	for i := 0; i < len(n); i++ {
+		if n[i] == 0 {
+			return i
+		}
+	}
+	return len(n)
+}
+
+func ReadDirent(fd int, buf []byte) (n int, err error) {
+	fdsMu.Lock()
+	f := fds[fd-fdsOff]
+	fdsMu.Unlock()
+	dirent, err := f.ReadDirents(uint64(len(buf)))
+	if err != nil {
+		return 0, err
+	}
+	return copy(buf, dirent), nil
+}
+
+func direntIno(buf []byte) (uint64, bool) {
+	// Inodes aren't exposed through Fuchsia; just lie.
+	// Use '1' instead of '0', since '0' means "entry not filled" on some operating systems.
+	return 1, true
+}
+
+func direntReclen(buf []byte) (uint64, bool) {
+	return readInt(buf, unsafe.Offsetof(Dirent{}.Size), unsafe.Sizeof(Dirent{}.Size))
+}
+
+func direntNamlen(buf []byte) (uint64, bool) {
+	reclen, ok := direntReclen(buf)
+	if !ok {
+		return 0, false
+	}
+	return reclen - uint64(unsafe.Offsetof(Dirent{}.Name)), true
+}
+
+type Dirent struct {
+	Size uint32
+	Type uint32
+	Name [1]byte
+}
diff --git a/src/syscall/timestruct.go b/src/syscall/timestruct.go
index 84a00a7..6bdc1a1 100644
--- a/src/syscall/timestruct.go
+++ b/src/syscall/timestruct.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris
+// +build darwin dragonfly freebsd fuchsia js,wasm linux nacl netbsd openbsd solaris
 
 package syscall
 
diff --git a/src/syscall/types_fuchsia.go b/src/syscall/types_fuchsia.go
new file mode 100644
index 0000000..9098a4a
--- /dev/null
+++ b/src/syscall/types_fuchsia.go
@@ -0,0 +1,29 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+
+type Errno uintptr
+
+func (e Errno) Error() string {
+	return "errno(" + itoa(int(e)) + ")"
+}
+
+type Timespec struct {
+	Sec  int64
+	Nsec int64
+}
+
+type Timeval struct {
+	Sec  int64
+	Usec int64
+}
+
+func setTimespec(sec, nsec int64) Timespec {
+	return Timespec{Sec: sec, Nsec: nsec}
+}
+
+func setTimeval(sec, usec int64) Timeval {
+	return Timeval{Sec: sec, Usec: usec}
+}
diff --git a/src/syscall/zerrors_fuchsia.go b/src/syscall/zerrors_fuchsia.go
new file mode 100644
index 0000000..cdd22ca
--- /dev/null
+++ b/src/syscall/zerrors_fuchsia.go
@@ -0,0 +1,72 @@
+// Copyright 2017 The Go 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
+
+const (
+	SOCK_STREAM = 1
+	SOCK_DGRAM  = 2
+	SOCK_RAW    = 3
+)
+
+const (
+	IPPROTO_IP     = 0
+	IPPROTO_ICMP   = 1
+	IPPROTO_TCP    = 6
+	IPPROTO_UDP    = 17
+	IPPROTO_ICMPV6 = 58
+)
+
+const (
+	AF_INET  = 0x2
+	AF_INET6 = 0xa
+)
+
+const (
+	SOL_SOCKET = 0x1
+	SOL_TCP    = 0x6
+)
+
+const (
+	SO_ACCEPTCONN  = 0x1e
+	SO_BROADCAST   = 0x6
+	SO_BSDCOMPAT   = 0xe
+	SO_DEBUG       = 0x1
+	SO_DOMAIN      = 0x27
+	SO_DONTROUTE   = 0x5
+	SO_ERROR       = 0x4
+	SO_KEEPALIVE   = 0x9
+	SO_LINGER      = 0xd
+	SO_NO_CHECK    = 0xb
+	SO_PASSCRED    = 0x10
+	SO_PEERCRED    = 0x11
+	SO_PRIORITY    = 0xc
+	SO_PROTOCOL    = 0x26
+	SO_RCVBUF      = 0x8
+	SO_RCVBUFFORCE = 0x21
+	SO_RCVLOWAT    = 0x12
+	SO_RCVTIMEO    = 0x14
+	SO_REUSEADDR   = 0x2
+	SO_REUSEPORT   = 0xf
+	SO_SNDBUF      = 0x7
+	SO_SNDBUFFORCE = 0x20
+	SO_SNDLOWAT    = 0x13
+	SO_SNDTIMEO    = 0x15
+	SO_TYPE        = 0x3
+)
+
+const (
+	TCP_NODELAY      = 1
+	TCP_MAXSEG       = 2
+	TCP_CORK         = 3
+	TCP_KEEPIDLE     = 4
+	TCP_KEEPINTVL    = 5
+	TCP_KEEPCNT      = 6
+	TCP_SYNCNT       = 7
+	TCP_LINGER2      = 8
+	TCP_DEFER_ACCEPT = 9
+	TCP_WINDOW_CLAMP = 10
+	TCP_INFO         = 11
+	TCP_QUICKACK     = 12
+)
diff --git a/src/syscall/ztypes_fuchsia_amd64.go b/src/syscall/ztypes_fuchsia_amd64.go
new file mode 100644
index 0000000..2f79cde
--- /dev/null
+++ b/src/syscall/ztypes_fuchsia_amd64.go
@@ -0,0 +1,28 @@
+// Copyright 2017 The Go 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
+
+// +build amd64,fuchsia
+
+type RawSockaddrInet4 struct {
+	Family uint16
+	Port   uint16
+	Addr   [4]byte /* in_addr */
+	Zero   [8]uint8
+}
+
+type RawSockaddrInet6 struct {
+	Family   uint16
+	Port     uint16
+	Flowinfo uint32
+	Addr     [16]byte /* in6_addr */
+	Scope_id uint32
+}
+
+const (
+	SizeofSockaddrInet4 = 0x10
+	SizeofSockaddrInet6 = 0x1c
+	SizeofSockaddrAny   = 0x70
+)
diff --git a/src/syscall/ztypes_fuchsia_arm64.go b/src/syscall/ztypes_fuchsia_arm64.go
new file mode 100644
index 0000000..0cca414
--- /dev/null
+++ b/src/syscall/ztypes_fuchsia_arm64.go
@@ -0,0 +1,28 @@
+// Copyright 2017 The Go 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
+
+// +build arm64,fuchsia
+
+type RawSockaddrInet4 struct {
+	Family uint16
+	Port   uint16
+	Addr   [4]byte /* in_addr */
+	Zero   [8]uint8
+}
+
+type RawSockaddrInet6 struct {
+	Family   uint16
+	Port     uint16
+	Flowinfo uint32
+	Addr     [16]byte /* in6_addr */
+	Scope_id uint32
+}
+
+const (
+	SizeofSockaddrInet4 = 0x10
+	SizeofSockaddrInet6 = 0x1c
+	SizeofSockaddrAny   = 0x70
+)
diff --git a/src/syscall/zx/dispatch/dispatcher.go b/src/syscall/zx/dispatch/dispatcher.go
new file mode 100644
index 0000000..df92757
--- /dev/null
+++ b/src/syscall/zx/dispatch/dispatcher.go
@@ -0,0 +1,225 @@
+// Copyright 2018 The Go 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 fuchsia
+
+package dispatch
+
+import (
+	"strconv"
+	"sync"
+	"syscall/zx"
+)
+
+// WaitResult represents a wait result that is returned by the callback.
+// WaitResult determines whether the wait should be re-queued.
+type WaitResult int
+
+const (
+	WaitFinished WaitResult = iota
+	WaitAgain
+)
+
+// WaitID is a monotonically increasing ID which corresponds to a particular
+// call to BeginWait. Note that it may become invalidated if a wait is dequeued.
+type WaitID uint64
+
+// WaitFlags represents the collection of certain options for waiting.
+type WaitFlags uint32
+
+const (
+	HandleShutdown WaitFlags = 1 << 0 // Calls the callback on shutdown.
+)
+
+// Handler is the callback that will be called when the wait is complete.
+type Handler func(*Dispatcher, zx.Status, *zx.PacketSignal) WaitResult
+
+// waitContext is a bookkeeping structure for in-progress waits.
+type waitContext struct {
+	object   zx.Handle
+	callback Handler
+	trigger  zx.Signals
+	flags    WaitFlags
+}
+
+// Dispatcher can read messages from a handle and assign them to a callback.
+type Dispatcher struct {
+	// port is the underlying port used to wait on signals and dispatch.
+	port zx.Port
+
+	// objects is a map that manages wait contexts.
+	mu         sync.RWMutex
+	objects    map[WaitID]*waitContext
+	nextWaitID WaitID
+
+	// handling is a map that manages which wait IDs that are current being
+	// handled. It is also protected by mu.
+	handling map[WaitID]struct{}
+
+	// shutdown is whether the dispatcher has shut down.
+	shutdown bool
+}
+
+// New creates a new dispatcher.
+func NewDispatcher() (*Dispatcher, error) {
+	port, err := zx.NewPort(0)
+	if err != nil {
+		return nil, err
+	}
+	return &Dispatcher{
+		port:     port,
+		objects:  make(map[WaitID]*waitContext),
+		handling: make(map[WaitID]struct{}),
+	}, nil
+}
+
+func assertWaitResult(result WaitResult, status zx.Status) {
+	if !(result == WaitFinished || (result == WaitAgain && status == zx.ErrOk)) {
+		panic("expected " + strconv.Itoa(int(result)) + " for status " + strconv.Itoa(int(status)))
+	}
+}
+
+// Closes a dispatcher, shutting down all handles added to the dispatcher.
+func (d *Dispatcher) Close() {
+	d.mu.Lock()
+	defer d.mu.Unlock()
+	d.port.Close()
+	for _, obj := range d.objects {
+		if obj != nil && (obj.flags&HandleShutdown) != 0 {
+			// Ignore the result; we won't be waiting again.
+			result := obj.callback(d, zx.ErrCanceled, nil)
+			assertWaitResult(result, zx.ErrCanceled)
+		}
+	}
+	d.objects = make(map[WaitID]*waitContext)
+	d.shutdown = true
+}
+
+func (d *Dispatcher) getWaitID() WaitID {
+	_, ok := d.objects[d.nextWaitID]
+	for ok {
+		d.nextWaitID++
+		_, ok = d.objects[d.nextWaitID]
+	}
+	return d.nextWaitID
+}
+
+// BeginWait creates a new wait on the handle h for signals t. The new wait
+// will respect the flags f, and call the handler c on wait completion.
+func (d *Dispatcher) BeginWait(h zx.Handle, t zx.Signals, f WaitFlags, c Handler) (WaitID, error) {
+	d.mu.Lock()
+	defer d.mu.Unlock()
+
+	// If we've shut down, just notify that we're in a bad state.
+	if d.shutdown {
+		return 0, zx.Error{Status: zx.ErrBadState}
+	}
+
+	// Register the wait.
+	id := d.getWaitID()
+	d.objects[id] = &waitContext{
+		object:   h,
+		callback: c,
+		trigger:  t,
+		flags:    f,
+	}
+
+	// Schedule the wait on the port.
+	err := d.port.WaitAsync(h, uint64(id), t, zx.PortWaitAsyncOnce)
+
+	// If we fail, make sure to de-register the wait.
+	if err != nil {
+		delete(d.objects, id)
+	}
+	return id, err
+}
+
+// CancelWait cancels the wait with the given WaitID.
+func (d *Dispatcher) CancelWait(id WaitID) error {
+	d.mu.Lock()
+	defer d.mu.Unlock()
+
+	// Look up the wait context.
+	wc := d.objects[id]
+	if wc == nil {
+		return zx.Error{Status: zx.ErrNotFound}
+	}
+
+	// If we're currently handling it, it's not being waited on, so there's nothing
+	// to cancel.
+	_, ok := d.handling[id]
+	if ok {
+		return zx.Error{Status: zx.ErrNotFound}
+	}
+
+	// Deregister no matter what here. Due to stack semantics of defer, this will always
+	// execute before the lock is released.
+	defer delete(d.objects, id)
+
+	// Cancel the actual wait.
+	return d.port.Cancel(wc.object, uint64(id))
+}
+
+func (d *Dispatcher) dispatch(id WaitID, wc *waitContext, signals *zx.PacketSignal) {
+	// Deregister the handler before invoking it.
+	d.mu.Lock()
+	d.handling[id] = struct{}{}
+	d.mu.Unlock()
+
+	// Call the handler.
+	result := wc.callback(d, zx.ErrOk, signals)
+	assertWaitResult(result, zx.ErrOk)
+	switch result {
+	case WaitAgain:
+		// Re-arm the handler, as the handler requested. Use a fresh ID since there's a
+		// chance the old ID has already been re-used.
+		d.mu.Lock()
+		delete(d.handling, id)
+		err := d.port.WaitAsync(wc.object, uint64(id), wc.trigger, zx.PortWaitAsyncOnce)
+		d.mu.Unlock()
+
+		// If we fail to re-arm, notify the handler of what happened.
+		if err != nil {
+			zxErr := err.(zx.Error)
+			result = wc.callback(d, zxErr.Status, nil)
+			assertWaitResult(result, zxErr.Status)
+		}
+	case WaitFinished:
+		d.mu.Lock()
+		delete(d.handling, id)
+		delete(d.objects, id)
+		d.mu.Unlock()
+	}
+}
+
+// Serve runs indefinitely, waiting for the port to return a packet and dispatches
+// the relevant handlers.
+func (d *Dispatcher) Serve() {
+	for {
+		// Wait for any handler to be ready
+		var packet zx.Packet
+		err := d.port.Wait(&packet, zx.TimensecInfinite)
+		if err != nil {
+			d.Close()
+			return
+		}
+		id := WaitID(packet.Hdr.Key)
+
+		// Get the object for dispatching.
+		d.mu.RLock()
+		wc := d.objects[id]
+		d.mu.RUnlock()
+
+		// If handler was removed while this packet was in the queue,
+		// just go back to waiting.
+		if wc == nil {
+			continue
+		}
+
+		// Dispatch to the appropriate handler.
+		if packet.Hdr.Type == zx.PortPacketTypeSignalOne {
+			d.dispatch(id, wc, packet.Signal())
+		}
+	}
+}
diff --git a/src/syscall/zx/dispatch/dispatcher_test.go b/src/syscall/zx/dispatch/dispatcher_test.go
new file mode 100644
index 0000000..9c1975b
--- /dev/null
+++ b/src/syscall/zx/dispatch/dispatcher_test.go
@@ -0,0 +1,231 @@
+// Copyright 2018 The Go 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 fuchsia
+
+package dispatch_test
+
+import (
+	"sync/atomic"
+	"syscall/zx"
+	. "syscall/zx/dispatch"
+	"testing"
+	"time"
+)
+
+func dispatcherTest(t *testing.T, name string, f func(d *Dispatcher) error) {
+	t.Run(name, func(t *testing.T) {
+		d, err := NewDispatcher()
+		if err != nil {
+			t.Fatal("creating dispatcher: ", err)
+		}
+		go d.Serve()
+		if err := f(d); err != nil {
+			t.Fatal("executing test: ", err)
+		}
+		d.Close()
+	})
+}
+
+func TestWait(t *testing.T) {
+	t.Parallel()
+	dispatcherTest(t, "WaitOnce", func(d *Dispatcher) error {
+		h0, h1, err := zx.NewChannel(0)
+		if err != nil {
+			return err
+		}
+		defer h0.Close()
+
+		done := make(chan struct{}, 1)
+		defer close(done)
+
+		handler := func(d *Dispatcher, s zx.Status, p *zx.PacketSignal) WaitResult {
+			done <- struct{}{}
+			return WaitFinished
+		}
+
+		_, err = d.BeginWait(zx.Handle(h0), zx.SignalChannelPeerClosed, 0, handler)
+		if err != nil {
+			return err
+		}
+
+		h1.Close()
+
+		select {
+		case <-done:
+			return nil
+		case <-time.After(5 * time.Second):
+			t.Fatal("timed out, handler never executed")
+		}
+		return nil
+	})
+	dispatcherTest(t, "WaitMultipleTimes", func(d *Dispatcher) error {
+		h0, h1, err := zx.NewChannel(0)
+		if err != nil {
+			return err
+		}
+		defer h0.Close()
+		defer h1.Close()
+
+		done := make(chan struct{}, 1)
+		defer close(done)
+
+		handler := func(d *Dispatcher, s zx.Status, p *zx.PacketSignal) WaitResult {
+			var b [zx.ChannelMaxMessageBytes]byte
+			var h [zx.ChannelMaxMessageHandles]zx.Handle
+			bn, hn, err := h0.Read(b[:], h[:], 0)
+			if err != nil {
+				t.Fatal("error reading: ", err)
+			}
+			if bn != 1 || hn != 0 {
+				t.Fatalf("unexpected read %d bytes %d handles", bn, hn)
+			}
+			if b[0] == 1 {
+				return WaitAgain
+			}
+			done <- struct{}{}
+			return WaitFinished
+		}
+
+		_, err = d.BeginWait(zx.Handle(h0), zx.SignalChannelReadable, 0, handler)
+		if err != nil {
+			return err
+		}
+
+		for i := 0; i < 5; i++ {
+			if err := h1.Write([]byte{1}, nil, 0); err != nil {
+				return err
+			}
+		}
+		if err := h1.Write([]byte{0}, nil, 0); err != nil {
+			return err
+		}
+
+		select {
+		case <-done:
+			return nil
+		case <-time.After(5 * time.Second):
+			t.Fatal("timed out, handler never executed")
+		}
+		return nil
+	})
+	dispatcherTest(t, "CancelWaitHandleShutdown", func(d *Dispatcher) error {
+		h0, h1, err := zx.NewChannel(0)
+		if err != nil {
+			return err
+		}
+		defer h0.Close()
+		defer h1.Close()
+
+		var i uint32
+		handler := func(d *Dispatcher, s zx.Status, p *zx.PacketSignal) WaitResult {
+			atomic.AddUint32(&i, 1)
+			return WaitFinished
+		}
+
+		id, err := d.BeginWait(zx.Handle(h0), zx.SignalChannelPeerClosed, HandleShutdown, handler)
+		if err != nil {
+			return err
+		}
+
+		if err := d.CancelWait(id); err != nil {
+			return err
+		}
+		d.Close()
+		if i != 0 {
+			t.Fatal("handler ran unexpectedly")
+		}
+		return nil
+	})
+	dispatcherTest(t, "Shutdown", func(d *Dispatcher) error {
+		h0, h1, err := zx.NewChannel(0)
+		if err != nil {
+			return err
+		}
+		defer h0.Close()
+		defer h1.Close()
+
+		handler := func(d *Dispatcher, s zx.Status, p *zx.PacketSignal) WaitResult {
+			return WaitFinished
+		}
+		d.Close()
+
+		_, err = d.BeginWait(zx.Handle(h0), zx.SignalChannelPeerClosed, 0, handler)
+		if err == nil {
+			t.Fatal("unexpected success for BeginWait on shut down dispatcher")
+		}
+		return nil
+	})
+	dispatcherTest(t, "HandleShutdown", func(d *Dispatcher) error {
+		h0, h1, err := zx.NewChannel(0)
+		if err != nil {
+			return err
+		}
+		defer h0.Close()
+		defer h1.Close()
+
+		done := make(chan struct{}, 1)
+		defer close(done)
+
+		handler := func(d *Dispatcher, s zx.Status, p *zx.PacketSignal) WaitResult {
+			done <- struct{}{}
+			return WaitFinished
+		}
+
+		_, err = d.BeginWait(zx.Handle(h0), zx.SignalChannelPeerClosed, HandleShutdown, handler)
+		if err != nil {
+			return err
+		}
+		d.Close()
+
+		select {
+		case <-done:
+			return nil
+		case <-time.After(5 * time.Second):
+			t.Fatal("timed out, handler never executed")
+		}
+		return nil
+	})
+	dispatcherTest(t, "MultipleGoroutines", func(d *Dispatcher) error {
+		// Spin up 5 goroutines all serving the dispatcher.
+		for i := 0; i < 5; i++ {
+			go d.Serve()
+		}
+
+		done := make(chan struct{}, 20)
+		defer close(done)
+
+		var ends []zx.Channel
+		for i := 0; i < 20; i++ {
+			h0, h1, err := zx.NewChannel(0)
+			if err != nil {
+				return err
+			}
+			defer h0.Close()
+
+			handler := func(d *Dispatcher, s zx.Status, p *zx.PacketSignal) WaitResult {
+				done <- struct{}{}
+				return WaitFinished
+			}
+
+			_, err = d.BeginWait(zx.Handle(h0), zx.SignalChannelPeerClosed, 0, handler)
+			if err != nil {
+				return err
+			}
+			ends = append(ends, h1)
+		}
+		for _, e := range ends {
+			e.Close()
+		}
+		for i := 0; i < 20; i++ {
+			select {
+			case <-done:
+				continue
+			case <-time.After(3 * time.Second):
+				t.Fatal("timed out, some handler never executed")
+			}
+		}
+		return nil
+	})
+}
diff --git a/src/syscall/zx/fdio/client.go b/src/syscall/zx/fdio/client.go
new file mode 100644
index 0000000..f7af0dc
--- /dev/null
+++ b/src/syscall/zx/fdio/client.go
@@ -0,0 +1,38 @@
+// Copyright 2016 The Go 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 fuchsia
+
+package fdio
+
+import (
+	"syscall/zx"
+	"syscall/zx/fidl"
+	"syscall/zx/io"
+)
+
+func ServiceConnect(svcpath string, h zx.Handle) error {
+	// Otherwise attempt to connect through the root namespace.
+	ns, err := NewNSFromMap(zx.RootNSMap)
+	if err == nil {
+		return ns.Connect(svcpath, h)
+	}
+	h.Close()
+	return zx.Error{Status: zx.ErrNotFound, Text: "fdio.ServiceConnect"}
+}
+
+func ServiceConnectAt(dir zx.Handle, path string, h zx.Handle) error {
+	if !dir.IsValid() || !h.IsValid() {
+		return zx.Error{Status: zx.ErrInvalidArgs, Text: "fdio.ServiceConnectAt"}
+	}
+	// Open the path on the remote.
+	iface := (*io.DirectoryInterface)(&fidl.Proxy{Channel: zx.Channel(dir)})
+	req := io.ObjectInterfaceRequest(fidl.InterfaceRequest{Channel: zx.Channel(h)})
+	err := iface.Open(io.KOpenRightReadable|io.KOpenRightWritable, 0755, path, req)
+	if err != nil {
+		h.Close()
+		return err
+	}
+	return nil
+}
diff --git a/src/syscall/zx/fdio/directory.go b/src/syscall/zx/fdio/directory.go
new file mode 100644
index 0000000..1b0dcd4
--- /dev/null
+++ b/src/syscall/zx/fdio/directory.go
@@ -0,0 +1,182 @@
+// Copyright 2018 The Go 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 fuchsia
+
+package fdio
+
+import (
+	"path"
+	"syscall/zx"
+	"syscall/zx/fidl"
+	"syscall/zx/io"
+)
+
+// Directory is a wrapper around a DirectoryInterface which implements FDIO.
+type Directory struct {
+	Node
+}
+
+func (d *Directory) getToken() (zx.Handle, error) {
+	status, token, err := d.DirectoryInterface().GetToken()
+	if err != nil {
+		return zx.HandleInvalid, err
+	} else if status != zx.ErrOk {
+		return zx.HandleInvalid, zx.Error{Status: status, Text: "io.directory"}
+	}
+	return token, nil
+}
+
+// DirectoryInterface returns the underlying Directory FIDL interface.
+func (d *Directory) DirectoryInterface() *io.DirectoryInterface {
+	return (*io.DirectoryInterface)(d.Node.Object.ObjectInterface)
+}
+
+// Close closes the Directory object.
+func (d *Directory) Close() error {
+	defer ((*fidl.Proxy)(d.Node.Object.ObjectInterface)).Close()
+	if status, err := d.Node.Object.ObjectInterface.Close(); err != nil {
+		return err
+	} else if status != zx.ErrOk {
+		return zx.Error{Status: status, Text: "io.directory"}
+	}
+	return nil
+}
+
+// Open opens an FDIO at path with the given flags and mode relative to this
+// Directory.
+func (d *Directory) Open(pathname string, flags uint32, mode uint32) (FDIO, error) {
+	req, obj, err := io.NewObjectInterfaceRequest()
+	if err != nil {
+		return nil, err
+	}
+	err = d.DirectoryInterface().Open(flags|io.KOpenFlagDescribe, mode, pathname, req)
+	if err != nil {
+		return nil, err
+	}
+	status, info, err := obj.ExpectOnOpen()
+	if err != nil {
+		return nil, err
+	} else if status != zx.ErrOk {
+		return nil, zx.Error{Status: status, Text: "io.directory"}
+	}
+	return objectFromInfo(info, obj)
+}
+
+func (d *Directory) openParent(pathname string) (FDIO, string, error) {
+	dirpath, name := path.Split(pathname)
+	parent, err := d.Open(path.Dir(dirpath), io.KOpenRightReadable, io.KOpenFlagDirectory)
+	if err != nil {
+		return nil, "", err
+	}
+	return parent, name, err
+}
+
+// Link creates a link between two paths under this Directory.
+func (d *Directory) Link(oldpath, newpath string) error {
+	oldparent, oldname, err := d.openParent(oldpath)
+	if err != nil {
+		return err
+	}
+	defer oldparent.Close()
+	newparent, newname, err := d.openParent(newpath)
+	if err != nil {
+		return err
+	}
+	defer newparent.Close()
+	olddir, ok := oldparent.(*Directory)
+	if !ok {
+		return zx.Error{Status: zx.ErrNotSupported, Text: "io.directory"}
+	}
+	newdir, ok := newparent.(*Directory)
+	if !ok {
+		return zx.Error{Status: zx.ErrNotSupported, Text: "io.directory"}
+	}
+	token, err := newdir.getToken()
+	if err != nil {
+		return err
+	}
+	status, err := olddir.DirectoryInterface().Link(oldname, token, newname)
+	if err != nil {
+		return err
+	} else if status != zx.ErrOk {
+		return zx.Error{Status: status, Text: "io.directory"}
+	}
+	return nil
+}
+
+// Rename renames an object at one path to another under this Directory.
+func (d *Directory) Rename(oldpath, newpath string) error {
+	oldf, oldname, err := d.openParent(oldpath)
+	if err != nil {
+		return err
+	}
+	defer oldf.Close()
+	newf, newname, err := d.openParent(newpath)
+	if err != nil {
+		return err
+	}
+	defer newf.Close()
+	olddir, ok := oldf.(*Directory)
+	if !ok {
+		return zx.Error{Status: zx.ErrNotSupported, Text: "io.directory"}
+	}
+	newdir, ok := newf.(*Directory)
+	if !ok {
+		return zx.Error{Status: zx.ErrNotSupported, Text: "io.directory"}
+	}
+	token, err := newdir.getToken()
+	if err != nil {
+		return err
+	}
+	status, err := olddir.DirectoryInterface().Rename(oldname, token, newname)
+	if err != nil {
+		return err
+	} else if status != zx.ErrOk {
+		return zx.Error{Status: status, Text: "io.directory"}
+	}
+	return nil
+}
+
+// Unlink unlinks an object at a pauth under this Directory.
+func (d *Directory) Unlink(pathname string) error {
+	parent, name, err := d.openParent(pathname)
+	if err != nil {
+		return err
+	}
+	defer parent.Close()
+	parentdir, ok := parent.(*Directory)
+	if !ok {
+		return zx.Error{Status: zx.ErrNotSupported, Text: "io.directory"}
+	}
+	if status, err := parentdir.DirectoryInterface().Unlink(name); err != nil {
+		return err
+	} else if status != zx.ErrOk {
+		return zx.Error{Status: status, Text: "io.directory"}
+	}
+	return nil
+}
+
+// ReadDirents returns up to max-worth bytes of byte-encoded dirents which represent
+// objects under this Directory. Repeated calls to ReadDirents continues giving back
+// objects.
+func (d *Directory) ReadDirents(max uint64) ([]byte, error) {
+	status, dirents, err := d.DirectoryInterface().ReadDirents(max)
+	if err != nil {
+		return nil, err
+	} else if status != zx.ErrOk {
+		return nil, zx.Error{Status: status, Text: "io.file"}
+	}
+	return dirents, nil
+}
+
+// Rewind resets the ReadDirents' counter.
+func (d *Directory) Rewind() error {
+	if status, err := d.DirectoryInterface().Rewind(); err != nil {
+		return err
+	} else if status != zx.ErrOk {
+		return zx.Error{Status: status, Text: "io.directory"}
+	}
+	return nil
+}
diff --git a/src/syscall/zx/fdio/fdio.go b/src/syscall/zx/fdio/fdio.go
new file mode 100644
index 0000000..eca6eb7
--- /dev/null
+++ b/src/syscall/zx/fdio/fdio.go
@@ -0,0 +1,225 @@
+// Copyright 2016 The Go 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 fuchsia
+
+// Package fdio provides unix-style IO, implementing Zircon's "system/ulib/fdio"
+package fdio
+
+import (
+	"syscall/zx"
+	"syscall/zx/io"
+)
+
+const (
+	// MaxUnderlyingHandles is the maximum number of handles which are
+	// necessary to implement any FDIO object.
+	MaxUnderlyingHandles = 2
+)
+
+// FDIO provides classic unix-style IO over various transports
+type FDIO interface {
+	Handles() []zx.Handle
+
+	Clone() (FDIO, error)
+	Close() error
+
+	Sync() error
+	GetAttr() (io.NodeAttributes, error)
+	SetAttr(flags uint32, attr io.NodeAttributes) error
+	Ioctl(op uint32, max uint64, in []byte, handles []zx.Handle) ([]byte, []zx.Handle, error)
+
+	Read(data []byte) (int, error)
+	ReadAt(data []byte, off int64) (int, error)
+	Write(data []byte) (int, error)
+	WriteAt(data []byte, off int64) (int, error)
+	Seek(offset int64, whence int) (int64, error)
+	Truncate(length uint64) error
+
+	Open(path string, flags uint32, mode uint32) (FDIO, error)
+	Link(oldpath, newpath string) error
+	Rename(oldpath, newpath string) error
+	Unlink(path string) error
+	ReadDirents(max uint64) ([]byte, error)
+	Rewind() error
+}
+
+// FDIO Ioctls
+func IoctlNum(kind, family, number uint32) uint32 {
+	return ((kind & 0xF) << 20) | ((family & 0xFF) << 8) | (number & 0xFF)
+}
+func IoctlKind(ioctl uint32) uint32 {
+	return (ioctl >> 20) & 0xF
+}
+func IoctlFamily(ioctl uint32) uint32 {
+	return (ioctl >> 8) & 0xFF
+}
+func IoctlNumber(ioctl uint32) uint32 {
+	return ioctl & 0xFF
+}
+
+const (
+	// IoctlMaxInput is the largest acceptable size for an Ioctl op input.
+	IoctlMaxInput = 1024
+)
+
+const (
+	IoctlKindDefault         = 0x0 // IOCTL_KIND_DEFAULT
+	IoctlKindGetHandle       = 0x1 // IOCTL_KIND_GET_HANDLE
+	IoctlKindGetTwoHandles   = 0x2 // IOCTL_KIND_GET_TWO_HANDLES
+	IoctlKindSetHandle       = 0x3 // IOCTL_KIND_SET_HANDLE
+	IoctlKindGetThreeHandles = 0x4 // IOCTL_KIND_GET_THREE_HANDLES
+)
+
+const (
+	IoctlFamilyReserved = 0x00 // IOCTL_FAMILY_RESERVED
+	IoctlFamilyDevice   = 0x01 // IOCTL_FAMILY_DEVICE
+	IoctlFamilyVFS      = 0x02 // IOCTL_FAMILY_VFS
+	IoctlFamilyDMCTL    = 0x03 // IOCTL_FAMILY_DMCTL
+	IoctlFamilyTest     = 0x04 // IOCTL_FAMILY_TEST
+)
+
+const (
+	IoctlFamilyBlock     = 0x13 // IOCTL_FAMILY_BLOCK
+	IoctlFamilyNetconfig = 0x26 // IOCTL_FAMILY_NETCONFIG
+)
+
+const (
+	IoctlFamilyPower = 0x30 // IOCTL_FAMILY_POWER
+)
+
+var IoctlDeviceBind = IoctlNum(IoctlKindDefault, IoctlFamilyDevice, 0)
+var IoctlDeviceGetEventHandle = IoctlNum(IoctlKindGetHandle, IoctlFamilyDevice, 1)
+var IoctlDeviceGetDriverName = IoctlNum(IoctlKindDefault, IoctlFamilyDevice, 2)
+var IoctlDeviceGetDeviceName = IoctlNum(IoctlKindDefault, IoctlFamilyDevice, 3)
+var IoctlDeviceGetTopoPath = IoctlNum(IoctlKindDefault, IoctlFamilyDevice, 4)
+var IoctlDeviceSync = IoctlNum(IoctlKindDefault, IoctlFamilyDevice, 6)
+var IoctlDeviceDebugSuspend = IoctlNum(IoctlKindDefault, IoctlFamilyDevice, 7)
+var IoctlDeviceDebugResume = IoctlNum(IoctlKindDefault, IoctlFamilyDevice, 8)
+
+var IoctlVFSMountFS = IoctlNum(IoctlKindSetHandle, IoctlFamilyVFS, 0)
+var IoctlVFSUnmountFS = IoctlNum(IoctlKindDefault, IoctlFamilyVFS, 1)
+var IoctlVFSUnmountNode = IoctlNum(IoctlKindGetHandle, IoctlFamilyVFS, 2)
+var IoctlVFSQueryFS = IoctlNum(IoctlKindDefault, IoctlFamilyVFS, 4)
+var IoctlVFSGetTokenFS = IoctlNum(IoctlKindGetHandle, IoctlFamilyVFS, 5)
+var IoctlVFSWatchDir = IoctlNum(IoctlKindSetHandle, IoctlFamilyVFS, 8)
+var IoctlVFSGetDevicePath = IoctlNum(IoctlKindDefault, IoctlFamilyVFS, 9)
+
+var IoctlPowerGetInfo = IoctlNum(IoctlKindDefault, IoctlFamilyPower, 1)
+var IoctlPowerGetBatteryInfo = IoctlNum(IoctlKindDefault, IoctlFamilyPower, 2)
+var IoctlPowerGetStateChangeEvent = IoctlNum(IoctlKindGetHandle, IoctlFamilyPower, 3)
+
+type PowerInfoResult struct {
+	PowerType uint32
+	State     uint32
+}
+
+type BatteryInfoResult struct {
+	Unit                           uint32
+	DesignCapacity                 uint32
+	LastFullCapacity               uint32
+	DesignVoltage                  uint32
+	CapacityWarning                uint32
+	CapacityLow                    uint32
+	CapacityGranularityLowWarning  uint32
+	CapacityGranularityWarningFull uint32
+	PresentRate                    int32
+	RemainingCapacity              uint32
+	PresentVoltage                 uint32
+}
+
+const (
+	PowerTypeAC      = 0
+	PowerTypeBattery = 1
+
+	PowerStateOnline      = 1 << 0
+	PowerStateDischarging = 1 << 1
+	PowerStateCharging    = 1 << 2
+	PowerStateCritical    = 1 << 3
+
+	BatteryUnitMW = 0
+	BatteryUnitMA = 1
+)
+
+type VFSWatchDirRequest struct {
+	H       zx.Handle
+	Mask    uint32
+	Options uint32
+}
+
+const (
+	VFSWatchEventDeleted = iota
+	VFSWatchEventAdded
+	VFSWatchEventRemoved
+	VFSWatchEventExisting
+	VFSWatchEventIdle
+)
+
+const (
+	VFSWatchMaskDeleted = 1 << iota
+	VFSWatchMaskAdded
+	VFSWatchMaskRemoved
+	VFSWatchMaskExisting
+	VFSWatchMaskIdle
+	VFSWatchMaskAll = 0x1F
+)
+
+type Vnattr struct {
+	Valid      uint32
+	Mode       Vtype
+	Inode      uint64
+	Size       uint64
+	Blksize    uint64
+	Blkcount   uint64
+	Nlink      uint64
+	CreateTime uint64
+	ModifyTime uint64
+}
+
+// VnattrBlksize is the size of block used in "Blockcount", which may be distinct from Blksize.
+const VnattrBlksize = 512
+
+const (
+	AttrCtime = 1 << iota
+	AttrMtime
+	AttrAtime
+)
+
+type Vtype uint32
+
+// bit-compatible with POSIX stat
+const (
+	VtypeMask Vtype = 0170000
+	VtypeSock Vtype = 0140000
+	VtypeLink Vtype = 0120000
+	VtypeFile Vtype = 0100000
+	VtypeBdev Vtype = 0060000
+	VtypeDir  Vtype = 0040000
+	VtypeCdev Vtype = 0020000
+	VtypePipe Vtype = 0010000
+
+	VtypeISUID Vtype = 0004000
+	VtypeISGID Vtype = 0002000
+	VtypeISVTX Vtype = 0001000
+	VtypeIRWXU Vtype = 0000700
+	VtypeIRUSR Vtype = 0000400
+	VtypeIWUSR Vtype = 0000200
+	VtypeIXUSR Vtype = 0000100
+	VtypeIRWXG Vtype = 0000070
+	VtypeIRGRP Vtype = 0000040
+	VtypeIWGRP Vtype = 0000020
+	VtypeIXGRP Vtype = 0000010
+	VtypeIRWXO Vtype = 0000007
+	VtypeIROTH Vtype = 0000004
+	VtypeIWOTH Vtype = 0000002
+	VtypeIXOTH Vtype = 0000001
+)
+
+const (
+	HandleTypeRemote = 0x32
+	HandleTypePipe   = 0x33
+	HandleTypeEvent  = 0x34
+	HandleTypeLogger = 0x35
+	HandleTypeSocket = 0x36
+)
diff --git a/src/syscall/zx/fdio/file.go b/src/syscall/zx/fdio/file.go
new file mode 100644
index 0000000..2d847d0
--- /dev/null
+++ b/src/syscall/zx/fdio/file.go
@@ -0,0 +1,152 @@
+// Copyright 2018 The Go 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 fuchsia
+
+package fdio
+
+import (
+	"syscall/zx"
+	"syscall/zx/io"
+)
+
+// File is a wrapper around a FileInterface which implements FDIO.
+type File struct {
+	Node
+	Event zx.Event
+}
+
+// FileInterface returns the underlying File FIDL interface.
+func (f *File) FileInterface() *io.FileInterface {
+	return (*io.FileInterface)(f.Node.Object.ObjectInterface)
+}
+
+// Handles returns all the underlying handles for this file,
+// which is the control channel and an event.
+func (f *File) Handles() []zx.Handle {
+	return append(f.Node.Handles(), zx.Handle(f.Event))
+}
+
+// Close closes all the control channel and event associated with the file
+// object.
+func (f *File) Close() error {
+	defer f.Event.Close()
+	return f.Node.Close()
+}
+
+// read reads data from a File. If off == -1 then it does a read
+// from whatever the seek offset is.
+func (f *File) read(data []byte, off int64) (int, error) {
+	ptr := 0
+	for ptr < len(data) {
+		bytesToRead := int(io.KMaxBuf)
+		if len(data)-ptr < int(io.KMaxBuf) {
+			bytesToRead = len(data) - ptr
+		}
+		var status zx.Status
+		var out []byte
+		var err error
+		if off == -1 {
+			status, out, err = f.FileInterface().Read(uint64(bytesToRead))
+		} else {
+			status, out, err = f.FileInterface().ReadAt(
+				uint64(bytesToRead),
+				uint64(int64(ptr)+off),
+			)
+		}
+		if err != nil {
+			return ptr, err
+		} else if status != zx.ErrOk {
+			return ptr, zx.Error{Status: status, Text: "io.file"}
+		}
+		if len(out) == 0 {
+			return ptr, nil
+		}
+		copy(data[ptr:ptr+len(out)], out)
+		ptr += len(out)
+		// Stop at short read.
+		if len(out) < bytesToRead {
+			return ptr, nil
+		}
+	}
+	return ptr, nil
+}
+
+// Read reads data from the internally held offset in the File.
+func (f *File) Read(data []byte) (int, error) {
+	return f.read(data, -1)
+}
+
+// ReadAt reads data at an offset in a File.
+func (f *File) ReadAt(data []byte, off int64) (int, error) {
+	return f.read(data, off)
+}
+
+// write writes data to a file. If off == -1 then the write occurs at
+// whatever the seek offset is.
+func (f *File) write(data []byte, off int64) (int, error) {
+	ptr := 0
+	for ptr < len(data) {
+		bytesToWrite := int(io.KMaxBuf)
+		if len(data)-ptr < int(io.KMaxBuf) {
+			bytesToWrite = len(data) - ptr
+		}
+		var status zx.Status
+		var written uint64
+		var err error
+		if off == -1 {
+			status, written, err = f.FileInterface().Write(
+				data[ptr : ptr+bytesToWrite],
+			)
+		} else {
+			status, written, err = f.FileInterface().WriteAt(
+				data[ptr:ptr+bytesToWrite],
+				uint64(int64(ptr)+off),
+			)
+		}
+		if err != nil {
+			return ptr, err
+		} else if status != zx.ErrOk {
+			return ptr, zx.Error{Status: status, Text: "io.file"}
+		}
+		ptr += int(written)
+		// Error on a short write.
+		if int(written) < bytesToWrite {
+			return ptr, zx.Error{Status: zx.ErrIO, Text: "io.file"}
+		}
+	}
+	return ptr, nil
+}
+
+// Write writes data at the internally held offset in the File.
+func (f *File) Write(data []byte) (int, error) {
+	return f.write(data, -1)
+}
+
+// WriteAt writes data at an offset in a File.
+func (f *File) WriteAt(data []byte, off int64) (int, error) {
+	return f.write(data, off)
+}
+
+// Seek moves the read/write head offset of the File.
+func (f *File) Seek(offset int64, whence int) (int64, error) {
+	status, off, err := f.FileInterface().Seek(offset, io.SeekOrigin(whence))
+	if err != nil {
+		return -1, err
+	} else if status != zx.ErrOk {
+		return -1, zx.Error{Status: status, Text: "io.file"}
+	}
+	return int64(off), nil
+}
+
+// Truncate truncates a File.
+func (f *File) Truncate(length uint64) error {
+	status, err := f.FileInterface().Truncate(length)
+	if err != nil {
+		return err
+	} else if status != zx.ErrOk {
+		return zx.Error{Status: status, Text: "io.file"}
+	}
+	return nil
+}
diff --git a/src/syscall/zx/fdio/logger.go b/src/syscall/zx/fdio/logger.go
new file mode 100644
index 0000000..d5723b6
--- /dev/null
+++ b/src/syscall/zx/fdio/logger.go
@@ -0,0 +1,134 @@
+// Copyright 2017 The Go 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 fuchsia
+
+package fdio
+
+import (
+	"syscall/zx"
+	"syscall/zx/io"
+)
+
+type Logger struct {
+	log            zx.Log
+	logBufferArray [1024]byte
+	logBufferN     int
+}
+
+func NewLogger(log zx.Log) *Logger {
+	return &Logger{log: log}
+}
+
+// Clone makes a clone of the object.
+func (f *Logger) Clone() (FDIO, error) {
+	logHandle := zx.Handle(f.log)
+	h, err := logHandle.Duplicate(zx.RightSameRights)
+	if err != nil {
+		return nil, err
+	}
+	return NewLogger(zx.Log(h)), nil
+}
+
+// Handle returns the underlying log handle as an untyped handle.
+func (f *Logger) Handles() []zx.Handle {
+	return []zx.Handle{zx.Handle(f.log)}
+}
+
+// Close closes the object.
+func (f *Logger) Close() error {
+	return f.log.Close()
+}
+
+// Sync implements FDIO for Logger.
+func (f *Logger) Sync() error {
+	return zx.Error{Status: zx.ErrNotSupported, Text: "fdio.logger"}
+}
+
+// GetAttr implements FDIO for Logger.
+func (f *Logger) GetAttr() (io.NodeAttributes, error) {
+	return io.NodeAttributes{}, zx.Error{Status: zx.ErrNotSupported, Text: "fdio.logger"}
+}
+
+// SetAttr implements FDIO for Logger.
+func (f *Logger) SetAttr(flags uint32, attr io.NodeAttributes) error {
+	return zx.Error{Status: zx.ErrNotSupported, Text: "fdio.logger"}
+}
+
+// Ioctl implements FDIO for Logger.
+func (f *Logger) Ioctl(op uint32, max uint64, in []byte, handles []zx.Handle) ([]byte, []zx.Handle, error) {
+	return nil, nil, zx.Error{Status: zx.ErrNotSupported, Text: "fdio.logger"}
+}
+
+// Read implements FDIO for Logger.
+func (f *Logger) Read(data []byte) (int, error) {
+	return 0, zx.Error{Status: zx.ErrNotSupported, Text: "fdio.logger"}
+}
+
+// ReadAt implements FDIO for Logger.
+func (f *Logger) ReadAt(data []byte, off int64) (int, error) {
+	return 0, zx.Error{Status: zx.ErrNotSupported, Text: "fdio.logger"}
+}
+
+// Write implements FDIO for Logger.
+func (f *Logger) Write(data []byte) (int, error) {
+	// Sys_log_write adds a newline to output buffers. To prevent fragmented logs, we buffer
+	// output until a newline character is encountered.
+	f.logBufferN += copy(f.logBufferArray[f.logBufferN:], data)
+	if f.logBufferArray[f.logBufferN-1] == '\n' {
+		n, err := f.log.Write(f.logBufferArray[:f.logBufferN])
+		// Flush buffer, regardless of status returned from write
+		f.logBufferN = 0
+		if err != nil {
+			return len(data), nil
+		}
+		return n, err
+	}
+	return len(data), nil
+}
+
+// WriteAt implements FDIO for Logger.
+func (f *Logger) WriteAt(data []byte, off int64) (int, error) {
+	return 0, zx.Error{Status: zx.ErrNotSupported, Text: "fdio.logger"}
+}
+
+// Seek implements FDIO for Logger.
+func (f *Logger) Seek(offset int64, whence int) (int64, error) {
+	return 0, zx.Error{Status: zx.ErrNotSupported, Text: "fdio.logger"}
+}
+
+// Truncate implements FDIO for Logger.
+func (f *Logger) Truncate(length uint64) error {
+	return zx.Error{Status: zx.ErrNotSupported, Text: "fdio.logger"}
+}
+
+// Open implements FDIO for Logger.
+func (f *Logger) Open(path string, flags uint32, mode uint32) (FDIO, error) {
+	return nil, zx.Error{Status: zx.ErrNotSupported, Text: "fdio.logger"}
+}
+
+// Link implements FDIO for Logger.
+func (f *Logger) Link(oldpath, newpath string) error {
+	return zx.Error{Status: zx.ErrNotSupported, Text: "fdio.logger"}
+}
+
+// Rename implements FDIO for Logger.
+func (f *Logger) Rename(oldpath, newpath string) error {
+	return zx.Error{Status: zx.ErrNotSupported, Text: "fdio.logger"}
+}
+
+// Unlink implements FDIO for Logger.
+func (f *Logger) Unlink(path string) error {
+	return zx.Error{Status: zx.ErrNotSupported, Text: "fdio.logger"}
+}
+
+// ReadDirents implements FDIO for Logger.
+func (f *Logger) ReadDirents(max uint64) ([]byte, error) {
+	return nil, zx.Error{Status: zx.ErrNotSupported, Text: "fdio.logger"}
+}
+
+// Rewind implements FDIO for Logger.
+func (f *Logger) Rewind() error {
+	return zx.Error{Status: zx.ErrNotSupported, Text: "fdio.logger"}
+}
diff --git a/src/syscall/zx/fdio/message.go b/src/syscall/zx/fdio/message.go
new file mode 100644
index 0000000..f5c55a3
--- /dev/null
+++ b/src/syscall/zx/fdio/message.go
@@ -0,0 +1,74 @@
+// Copyright 2016 The Go 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 fuchsia
+
+package fdio
+
+const (
+	OpFlagOneHandle = uint32(0x100 + iota)
+	OpFlagTwoHandles
+	OpFlagThreeHandles
+)
+
+// Values for op. Each one will signify a request for a different operation.
+const (
+	_ = uint32(iota)
+	OpClose
+	OpClone = uint32(iota) | OpFlagOneHandle
+	OpOpen  = uint32(iota) | OpFlagOneHandle
+	OpMisc  = uint32(iota)
+	OpRead
+	OpWrite
+	OpSeek
+	OpStat
+	OpReaddir
+	OpIoctl
+	OpUnlink
+	OpReadAt
+	OpWriteAt
+	OpTruncate
+	OpRename  = uint32(iota) | OpFlagOneHandle
+	OpConnect = uint32(iota)
+	OpBind
+	OpListen
+	OpGetSockname
+	OpGetPeerName
+	OpGetSockOpt
+	OpSetSockOpt
+	OpGetAddrInfo
+	OpSetAttr
+	OpSync
+	OpLink = uint32(iota) | OpFlagOneHandle
+	OpMmap = uint32(iota)
+	OpFcntl
+	OpAccept
+	OpNumOps = uint32(iota) // The total number of operations
+)
+
+// Control ordinal operations. Sent from server to client without
+// necessarily having an accompanying request message.
+const (
+	OpOnOpen = uint32(0x80000007)
+)
+
+const (
+	OpenFlagDescribe = 0x00800000
+)
+
+const (
+	OpOpenFlagReadable = 1
+	OpOpenFlagWritable = 2
+	OpOpenFlagRDWR     = OpOpenFlagReadable | OpOpenFlagWritable
+)
+
+// Ops which correspond to a previously listed operation, but have a different number of handles
+const (
+	OpIoctlOneHandle = OpIoctl | OpFlagOneHandle
+)
+
+const (
+	OpFcntlCmdGetFL = uint32(iota + 3)
+	OpFcntlCmdSetFL
+)
diff --git a/src/syscall/zx/fdio/mxc/mxc.go b/src/syscall/zx/fdio/mxc/mxc.go
new file mode 100644
index 0000000..5997cbfa
--- /dev/null
+++ b/src/syscall/zx/fdio/mxc/mxc.go
@@ -0,0 +1,19 @@
+// Copyright 2017 The Go 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 fuchsia
+
+package mxc
+
+import "syscall"
+
+func ExtractCFDIO(fd int) (uintptr, error) {
+	// Extract the 'C' fdio
+	f, err := transferFDIOFromCFD(fd)
+	if err != nil {
+		return 0, err
+	}
+	// Convert it to a 'Go' fdio
+	return uintptr(syscall.OpenFDIO(f)), nil
+}
diff --git a/src/syscall/zx/fdio/mxc/mxc_cgo.go b/src/syscall/zx/fdio/mxc/mxc_cgo.go
new file mode 100644
index 0000000..dd6795c
--- /dev/null
+++ b/src/syscall/zx/fdio/mxc/mxc_cgo.go
@@ -0,0 +1,59 @@
+// Copyright 2017 The Go 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 fuchsia
+// +build cgo
+
+package mxc
+
+// #cgo fuchsia LDFLAGS: -lfdio
+// #include <zircon/types.h>
+// #include <zircon/syscalls.h>
+// #include <stdlib.h>
+// #include <lib/fdio/util.h>
+import "C"
+import (
+	"errors"
+	"syscall/zx"
+	"syscall/zx/fdio"
+	"syscall/zx/fidl"
+	"syscall/zx/io"
+)
+
+func transferFDIOFromCFD(fd int) (fdio.FDIO, error) {
+	handlesC := make([]C.zx_handle_t, fdio.MaxUnderlyingHandles)
+	typesC := make([]C.uint32_t, fdio.MaxUnderlyingHandles)
+	status := C.fdio_transfer_fd(C.int(fd), 0, (*C.zx_handle_t)(&handlesC[0]), (*C.uint32_t)(&typesC[0]))
+	if status < 0 {
+		return nil, zx.Error{Status: zx.Status(status), Text: "mxc"}
+	} else if status == 0 || fdio.MaxUnderlyingHandles < status {
+		return nil, errors.New("Invalid handle from fdio_transfer_fd")
+	}
+	handles := make([]zx.Handle, int(status))
+	for i := 0; i < int(status); i++ {
+		handles[i] = zx.Handle(handlesC[i])
+	}
+	switch zx.HandleInfo(typesC[0]).Type() {
+	case fdio.HandleTypeRemote:
+		obj := (*io.ObjectInterface)(&fidl.Proxy{Channel: zx.Channel(handles[0])})
+		if len(handles) > 1 {
+			for _, h := range handles[1:] {
+				h.Close()
+			}
+		}
+		return &fdio.File{Node: fdio.Node{Object: fdio.Object{obj}}}, nil
+	case fdio.HandleTypePipe:
+		if len(handles) > 1 {
+			for _, h := range handles[1:] {
+				h.Close()
+			}
+		}
+		return fdio.NewPipe(zx.Socket(handles[0])), nil
+	default:
+		for _, h := range handles {
+			h.Close()
+		}
+		return nil, errors.New("Unexpected C handle type")
+	}
+}
diff --git a/src/syscall/zx/fdio/mxc/mxc_no_cgo.go b/src/syscall/zx/fdio/mxc/mxc_no_cgo.go
new file mode 100644
index 0000000..ef30d35
--- /dev/null
+++ b/src/syscall/zx/fdio/mxc/mxc_no_cgo.go
@@ -0,0 +1,17 @@
+// Copyright 2017 The Go 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 fuchsia
+// +build !cgo
+
+package mxc
+
+import (
+	"syscall/zx"
+	"syscall/zx/fdio"
+)
+
+func transferFDIOFromCFD(fd int) (fdio.FDIO, error) {
+	return nil, zx.ErrNotSupported
+}
diff --git a/src/syscall/zx/fdio/namespace.go b/src/syscall/zx/fdio/namespace.go
new file mode 100644
index 0000000..7dbf635
--- /dev/null
+++ b/src/syscall/zx/fdio/namespace.go
@@ -0,0 +1,391 @@
+// Copyright 2017 The Go 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 fuchsia
+
+package fdio
+
+import (
+	"path"
+	"strings"
+	"sync"
+	"syscall/zx"
+	"syscall/zx/fidl"
+	"syscall/zx/io"
+)
+
+func splitPath(path string) (name string, remaining string) {
+	slash := strings.IndexByte(path, '/')
+	if slash == 0 || slash == len(path)-1 {
+		return "", ""
+	} else if slash == -1 {
+		return path, ""
+	} else {
+		return path[:slash], path[slash+1:]
+	}
+}
+
+type NS struct {
+	mu sync.Mutex
+	m  map[string]zx.Handle
+}
+
+func NewNS() *NS {
+	return &NS{m: make(map[string]zx.Handle)}
+}
+
+func NewNSFromMap(m map[string]zx.Handle) (*NS, error) {
+	if m == nil {
+		return nil, zx.Error{Status: zx.ErrInvalidArgs, Text: "namespace.NewFromNSMAP"}
+	}
+	ns := &NS{m: make(map[string]zx.Handle)}
+	for k, v := range m {
+		ns.m[k] = v
+	}
+	return ns, nil
+}
+
+func (ns *NS) Bind(p string, h zx.Handle) {
+	ns.mu.Lock()
+	ns.m[p] = h
+	ns.mu.Unlock()
+}
+
+func (ns *NS) Connect(p string, h zx.Handle) error {
+	if p[0] != '/' {
+		h.Close()
+		return zx.Error{Status: zx.ErrNotFound, Text: "namespace.Connect"}
+	}
+	node := p
+	for {
+		ns.mu.Lock()
+		svcHandle := ns.m[node]
+		ns.mu.Unlock()
+		if svcHandle.IsValid() {
+			rest := strings.TrimPrefix(p, node)
+			rest = strings.TrimPrefix(rest, "/")
+			return ServiceConnectAt(svcHandle, rest, h)
+		}
+		if node == "/" {
+			break
+		}
+		node = path.Dir(node)
+	}
+	h.Close()
+	return zx.Error{Status: zx.ErrNotFound, Text: "namespace.Connect"}
+}
+
+func (ns *NS) OpenRoot() (FDIO, error) {
+	root := &vnode{}
+	ns.mu.Lock()
+	defer ns.mu.Unlock()
+	for path, h := range ns.m {
+		if path == "" || path[0] != '/' {
+			return nil, zx.Error{Status: zx.ErrBadPath, Text: "fdio.OpenRoot"}
+		}
+		vn := root
+		path = path[1:]
+		for path != "" {
+			name, remaining := splitPath(path)
+			vn = vn.getOrAddChild(name)
+			path = remaining
+		}
+		if vn.remote.IsValid() {
+			return nil, zx.Error{Status: zx.ErrAlreadyExists, Text: "fdio.OpenRoot"}
+		}
+		obj := (*io.ObjectInterface)(&fidl.Proxy{Channel: zx.Channel(h)})
+		vn.remote = Directory{Node: Node{Object: Object{obj}}}
+	}
+	return &dir{root}, nil
+}
+
+// vnode is a virtual node in the namespace "filesystem".
+type vnode struct {
+	child  *vnode
+	parent *vnode
+	next   *vnode
+	remote Directory
+	name   string
+}
+
+func (vn *vnode) getOrAddChild(name string) *vnode {
+	child := vn.getChild(name)
+	if child == nil {
+		child = &vnode{
+			parent: vn,
+			next:   vn.child,
+			name:   name,
+		}
+		vn.child = child
+	}
+	return child
+}
+
+func (vn *vnode) getChild(name string) *vnode {
+	for vn = vn.child; vn != nil; vn = vn.next {
+		if vn.name == name {
+			return vn
+		}
+	}
+	return nil
+}
+
+// dir represents a directory in the namespace.
+type dir struct {
+	vn *vnode
+}
+
+// Handle returns the underlying handle as an untyped handle.
+func (d *dir) Handles() []zx.Handle {
+	return d.vn.remote.Handles()
+}
+
+// Clone makes a clone of the dir, if possible.
+func (d *dir) Clone() (FDIO, error) {
+	if !d.vn.remote.IsValid() {
+		return nil, zx.Error{Status: zx.ErrNotSupported, Text: "fdio.ns.dir"}
+	}
+	return d.vn.remote.Clone()
+}
+
+// Close closes the dir.
+func (d *dir) Close() error {
+	return d.vn.remote.Close()
+}
+
+// Sync implements FDIO for dir.
+func (d *dir) Sync() error {
+	return zx.Error{Status: zx.ErrNotSupported, Text: "fdio.ns.dir"}
+}
+
+// GetAttr implements FDIO for dir.
+func (d *dir) GetAttr() (io.NodeAttributes, error) {
+	return io.NodeAttributes{
+		Mode:      uint32(io.KModeTypeDirectory) | uint32(VtypeIRUSR),
+		Id:        1,
+		LinkCount: 1,
+	}, nil
+}
+
+// SetAttr implements FDIO for dir.
+func (d *dir) SetAttr(flags uint32, attr io.NodeAttributes) error {
+	return zx.Error{Status: zx.ErrNotSupported, Text: "fdio.ns.dir"}
+}
+
+// Ioctl implements FDIO for dir.
+func (d *dir) Ioctl(op uint32, max uint64, in []byte, handles []zx.Handle) ([]byte, []zx.Handle, error) {
+	return nil, nil, zx.Error{Status: zx.ErrNotSupported, Text: "fdio.ns.dir"}
+}
+
+func (d *dir) Read(data []byte) (int, error) {
+	return 0, zx.Error{Status: zx.ErrNotSupported, Text: "fdio.dir"}
+}
+
+func (d *dir) ReadAt(data []byte, off int64) (int, error) {
+	return 0, zx.Error{Status: zx.ErrNotSupported, Text: "fdio.dir"}
+}
+
+func (d *dir) Write(data []byte) (n int, err error) {
+	return 0, zx.Error{Status: zx.ErrNotSupported, Text: "fdio.dir"}
+}
+
+func (d *dir) WriteAt(data []byte, off int64) (int, error) {
+	return 0, zx.Error{Status: zx.ErrNotSupported, Text: "fdio.dir"}
+}
+
+func (d *dir) Seek(offset int64, whence int) (int64, error) {
+	return 0, zx.Error{Status: zx.ErrNotSupported, Text: "fdio.dir"}
+}
+
+// Truncate implements FDIO for dir.
+func (d *dir) Truncate(length uint64) error {
+	return zx.Error{Status: zx.ErrNotSupported, Text: "fdio.ns.dir"}
+}
+
+func (d *dir) getVnode(path string) (vn *vnode, rpath string, isRemote bool, err error) {
+	vn = d.vn
+
+	if path == "." || path == "" {
+		if vn.remote.IsValid() {
+			return vn, ".", true, nil
+		}
+		return vn, "", false, nil
+	}
+
+	originalPath := path
+
+	var savedVn *vnode
+	var savedPath string
+
+	for {
+		name, remaining := splitPath(path)
+
+		if name == "" {
+			return nil, "", false, zx.Error{Status: zx.ErrBadPath, Text: path}
+		}
+
+		child := vn.getChild(name)
+
+		if child != nil {
+			if remaining == "" {
+				// We've resolved all the path segments and found the vnode we're
+				// looking for.
+				if child.remote.IsValid() {
+					return child, ".", true, nil
+				} else {
+					return child, "", false, nil
+				}
+			} else {
+				// We've got more path to resolve.
+				vn = child
+				path = remaining
+
+				// If this child has a remote file system, we might hand off to
+				// this remote if we don't find anything more specific below
+				// this vnode.
+				if child.remote.IsValid() {
+					savedVn = vn
+					savedPath = path
+				}
+
+				continue
+			}
+		}
+
+		// We've reached the end of our local vnode structure with more
+		// path to resolve.
+
+		if vn.remote.IsValid() {
+			// We've got a remote file system at this vnode. We can hand off
+			// directly to that file system.
+			return vn, path, true, nil
+		}
+
+		// We saw a remote file system earlier in our walk that might have this
+		// path. Let's hand off to it.
+		if savedVn != nil {
+			return savedVn, savedPath, true, nil
+		}
+
+		// There is no remote file system to resolve the path against,
+		// which means we failed to find what we were looking for.
+		return nil, "", false, zx.Error{Status: zx.ErrNotFound, Text: originalPath}
+	}
+}
+
+// Open implements FDIO for dir.
+func (d *dir) Open(pathname string, flags uint32, mode uint32) (FDIO, error) {
+	vn, relp, isRemote, err := d.getVnode(pathname)
+	if err != nil {
+		return nil, err
+	}
+	if isRemote {
+		return vn.remote.Open(relp, flags, mode)
+	}
+	return &dir{vn}, nil
+}
+
+func (d *dir) openParent(pathname string) (FDIO, string, error) {
+	dirpath, name := path.Split(pathname)
+	parent, err := d.Open(path.Dir(dirpath), io.KOpenRightReadable, io.KOpenFlagDirectory)
+	if err != nil {
+		return nil, "", err
+	}
+	return parent, name, err
+}
+
+// Link implements FDIO for dir.
+func (d *dir) Link(oldpath, newpath string) error {
+	oldparent, oldname, err := d.openParent(oldpath)
+	if err != nil {
+		return err
+	}
+	defer oldparent.Close()
+	newparent, newname, err := d.openParent(newpath)
+	if err != nil {
+		return err
+	}
+	defer newparent.Close()
+	olddir, ok := oldparent.(*Directory)
+	if !ok {
+		return zx.Error{Status: zx.ErrNotSupported, Text: "fdio.ns.dir"}
+	}
+	newdir, ok := newparent.(*Directory)
+	if !ok {
+		return zx.Error{Status: zx.ErrNotSupported, Text: "fdio.ns.dir"}
+	}
+	token, err := newdir.getToken()
+	if err != nil {
+		return err
+	}
+	status, err := olddir.DirectoryInterface().Link(oldname, token, newname)
+	if err != nil {
+		return err
+	} else if status != zx.ErrOk {
+		return zx.Error{Status: status, Text: "fdio.ns.dir"}
+	}
+	return nil
+}
+
+// Rename implements FDIO for dir.
+func (d *dir) Rename(oldpath, newpath string) error {
+	oldf, oldname, err := d.openParent(oldpath)
+	if err != nil {
+		return err
+	}
+	defer oldf.Close()
+	newf, newname, err := d.openParent(newpath)
+	if err != nil {
+		return err
+	}
+	defer newf.Close()
+	olddir, ok := oldf.(*Directory)
+	if !ok {
+		return zx.Error{Status: zx.ErrNotSupported, Text: "fdio.ns.dir"}
+	}
+	newdir, ok := newf.(*Directory)
+	if !ok {
+		return zx.Error{Status: zx.ErrNotSupported, Text: "fdio.ns.dir"}
+	}
+	token, err := newdir.getToken()
+	if err != nil {
+		return err
+	}
+	status, err := olddir.DirectoryInterface().Rename(oldname, token, newname)
+	if err != nil {
+		return err
+	} else if status != zx.ErrOk {
+		return zx.Error{Status: status, Text: "fdio.ns.dir"}
+	}
+	return nil
+}
+
+// Unlink implements FDIO for dir.
+func (d *dir) Unlink(pathname string) error {
+	parent, name, err := d.openParent(pathname)
+	if err != nil {
+		return err
+	}
+	defer parent.Close()
+	parentdir, ok := parent.(*Directory)
+	if !ok {
+		return zx.Error{Status: zx.ErrNotSupported, Text: "fdio.ns.dir"}
+	}
+	if status, err := parentdir.DirectoryInterface().Unlink(name); err != nil {
+		return err
+	} else if status != zx.ErrOk {
+		return zx.Error{Status: status, Text: "fdio.ns.dir"}
+	}
+	return nil
+}
+
+// ReadDirents implements FDIO for dir.
+func (d *dir) ReadDirents(max uint64) ([]byte, error) {
+	return nil, zx.Error{Status: zx.ErrNotSupported, Text: "fdio.ns.dir"}
+}
+
+// Rewind implements FDIO for dir.
+func (d *dir) Rewind() error {
+	return zx.Error{Status: zx.ErrNotSupported, Text: "fdio.ns.dir"}
+}
diff --git a/src/syscall/zx/fdio/node.go b/src/syscall/zx/fdio/node.go
new file mode 100644
index 0000000..5bdca5b
--- /dev/null
+++ b/src/syscall/zx/fdio/node.go
@@ -0,0 +1,64 @@
+// Copyright 2018 The Go 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 fuchsia
+
+package fdio
+
+import (
+	"syscall/zx"
+	"syscall/zx/io"
+)
+
+// Node is a wrapper around a NodeInterface which implements FDIO.
+type Node struct {
+	Object
+}
+
+// NodeInterface returns the underlying Node FIDL interface.
+func (n *Node) NodeInterface() (*io.NodeInterface) {
+	return (*io.NodeInterface)(n.Object.ObjectInterface)
+}
+
+// Sync performs a sync operation on a Node.
+func (n *Node) Sync() error {
+	if status, err := n.NodeInterface().Sync(); err != nil {
+		return err
+	} else if status != zx.ErrOk {
+		return zx.Error{Status: status, Text: "io.node"}
+	}
+	return nil
+}
+
+// GetAttr returns the attributes for the Node.
+func (n *Node) GetAttr() (io.NodeAttributes, error) {
+	status, attrs, err := n.NodeInterface().GetAttr()
+	if err != nil {
+		return io.NodeAttributes{}, err
+	} else if status != zx.ErrOk {
+		return io.NodeAttributes{}, zx.Error{Status: status, Text: "io.node"}
+	}
+	return attrs, nil
+}
+
+// SetAttr sets the attributes for Node as defined by flags.
+func (n *Node) SetAttr(flags uint32, attr io.NodeAttributes) error {
+	if status, err := n.NodeInterface().SetAttr(flags, attr); err != nil {
+		return err
+	} else if status != zx.ErrOk {
+		return zx.Error{Status: status, Text: "io.node"}
+	}
+	return nil
+}
+
+// Ioctl calls an ioctl on Node.
+func (n *Node) Ioctl(op uint32, max uint64, in []byte, handles []zx.Handle) ([]byte, []zx.Handle, error) {
+	status, h, b, err := n.NodeInterface().Ioctl(op, max, handles, in)
+	if err != nil {
+		return nil, nil, err
+	} else if status != zx.ErrOk {
+		return nil, nil, zx.Error{Status: status, Text: "io.node"}
+	}
+	return b, h, nil
+}
diff --git a/src/syscall/zx/fdio/object.go b/src/syscall/zx/fdio/object.go
new file mode 100644
index 0000000..6e41440
--- /dev/null
+++ b/src/syscall/zx/fdio/object.go
@@ -0,0 +1,179 @@
+// Copyright 2018 The Go 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 fuchsia
+
+package fdio
+
+import (
+	"syscall/zx"
+	"syscall/zx/fidl"
+	"syscall/zx/io"
+)
+
+func objectFromInfo(info *io.ObjectInfo, obj *io.ObjectInterface) (result FDIO, err error) {
+	if info == nil {
+		return nil, zx.Error{Status: zx.ErrNotSupported, Text: "io.object"}
+	}
+	switch info.ObjectInfoTag {
+	case io.ObjectInfoService:
+		// TODO(mknyszek): Figure out the correct type to return here.
+		result = &Object{ObjectInterface: obj}
+	case io.ObjectInfoFile:
+		result = &File{
+			Node:  Node{Object: Object{ObjectInterface: obj}},
+			Event: info.File.Event,
+		}
+	case io.ObjectInfoDevice:
+		result = &File{
+			Node:  Node{Object: Object{ObjectInterface: obj}},
+			Event: info.Device.Event,
+		}
+	case io.ObjectInfoDirectory:
+		result = &Directory{Node: Node{Object: Object{ObjectInterface: obj}}}
+	case io.ObjectInfoPipe:
+		result = NewPipe(info.Pipe.Socket)
+	case io.ObjectInfoVmofile:
+		result, err = NewVMOFile(
+			info.Vmofile.Vmo,
+			info.Vmofile.Offset,
+			info.Vmofile.Length,
+		)
+		if err != nil {
+			return nil, err
+		}
+	default:
+		return nil, zx.Error{Status: zx.ErrNotSupported, Text: "io.object"}
+	}
+	return result, nil
+}
+
+// Object is a wrapper around an ObjectInterface which implements FDIO.
+type Object struct {
+	*io.ObjectInterface
+}
+
+// IsValid returns true if the Object is valid.
+func (o *Object) IsValid() bool {
+	if o.ObjectInterface == nil {
+		return false
+	}
+	return ((*fidl.Proxy)(o.ObjectInterface)).IsValid()
+}
+
+// Handle returns the underlying channel as an untyped zx handle.
+func (o *Object) Handles() []zx.Handle {
+	return []zx.Handle{
+		zx.Handle(((*fidl.Proxy)(o.ObjectInterface)).Channel),
+	}
+}
+
+// Clone makes a clone of the object.
+func (o *Object) Clone() (FDIO, error) {
+	req, newObj, err := io.NewObjectInterfaceRequest()
+	if err != nil {
+		return nil, err
+	}
+	if err := o.ObjectInterface.Clone(io.KOpenFlagDescribe, req); err != nil {
+		return nil, err
+	}
+	status, info, err := newObj.ExpectOnOpen()
+	if err != nil {
+		return nil, err
+	} else if status != zx.ErrOk {
+		return nil, zx.Error{Status: status, Text: "io.object"}
+	}
+	return objectFromInfo(info, newObj)
+}
+
+// Close closes the object.
+func (o *Object) Close() error {
+	defer ((*fidl.Proxy)(o.ObjectInterface)).Close()
+	if status, err := o.ObjectInterface.Close(); err != nil {
+		return err
+	} else if status != zx.ErrOk {
+		return zx.Error{Status: status, Text: "io.object"}
+	}
+	return nil
+}
+
+// Sync implements FDIO for Object.
+func (o *Object) Sync() error {
+	return zx.Error{Status: zx.ErrNotSupported, Text: "io.object"}
+}
+
+// GetAttr implements FDIO for Object.
+func (o *Object) GetAttr() (io.NodeAttributes, error) {
+	return io.NodeAttributes{}, zx.Error{Status: zx.ErrNotSupported, Text: "io.object"}
+}
+
+// SetAttr implements FDIO for Object.
+func (o *Object) SetAttr(flags uint32, attr io.NodeAttributes) error {
+	return zx.Error{Status: zx.ErrNotSupported, Text: "io.object"}
+}
+
+// Ioctl implements FDIO for Object.
+func (o *Object) Ioctl(op uint32, max uint64, in []byte, handles []zx.Handle) ([]byte, []zx.Handle, error) {
+	return nil, nil, zx.Error{Status: zx.ErrNotSupported, Text: "io.object"}
+}
+
+// Read implements FDIO for Object.
+func (o *Object) Read(data []byte) (int, error) {
+	return 0, zx.Error{Status: zx.ErrNotSupported, Text: "io.object"}
+}
+
+// ReadAt implements FDIO for Object.
+func (o *Object) ReadAt(data []byte, off int64) (int, error) {
+	return 0, zx.Error{Status: zx.ErrNotSupported, Text: "io.object"}
+}
+
+// Write implements FDIO for Object.
+func (o *Object) Write(data []byte) (int, error) {
+	return 0, zx.Error{Status: zx.ErrNotSupported, Text: "io.object"}
+}
+
+// WriteAt implements FDIO for Object.
+func (o *Object) WriteAt(data []byte, off int64) (int, error) {
+	return 0, zx.Error{Status: zx.ErrNotSupported, Text: "io.object"}
+}
+
+// Seek implements FDIO for Object.
+func (o *Object) Seek(offset int64, whence int) (int64, error) {
+	return 0, zx.Error{Status: zx.ErrNotSupported, Text: "io.object"}
+}
+
+// Truncate implements FDIO for Object.
+func (o *Object) Truncate(length uint64) error {
+	return zx.Error{Status: zx.ErrNotSupported, Text: "io.object"}
+}
+
+// Open implements FDIO for Object.
+func (o *Object) Open(path string, flags uint32, mode uint32) (FDIO, error) {
+	return nil, zx.Error{Status: zx.ErrNotSupported, Text: "io.object"}
+}
+
+// Link implements FDIO for Object.
+func (o *Object) Link(oldpath, newpath string) error {
+	return zx.Error{Status: zx.ErrNotSupported, Text: "io.object"}
+}
+
+// Rename implements FDIO for Object.
+func (o *Object) Rename(oldpath, newpath string) error {
+	return zx.Error{Status: zx.ErrNotSupported, Text: "io.object"}
+}
+
+// Unlink implements FDIO for Object.
+func (o *Object) Unlink(path string) error {
+	return zx.Error{Status: zx.ErrNotSupported, Text: "io.object"}
+}
+
+// ReadDirents implements FDIO for Object.
+func (o *Object) ReadDirents(max uint64) ([]byte, error) {
+	return nil, zx.Error{Status: zx.ErrNotSupported, Text: "io.object"}
+}
+
+// Rewind implements FDIO for Object.
+func (o *Object) Rewind() error {
+	return zx.Error{Status: zx.ErrNotSupported, Text: "io.object"}
+}
diff --git a/src/syscall/zx/fdio/pipe.go b/src/syscall/zx/fdio/pipe.go
new file mode 100644
index 0000000..139a642
--- /dev/null
+++ b/src/syscall/zx/fdio/pipe.go
@@ -0,0 +1,172 @@
+// Copyright 2016 The Go 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 fuchsia
+
+package fdio
+
+import (
+	"syscall/zx"
+	"syscall/zx/io"
+	"syscall/zx/zxwait"
+)
+
+type Pipe struct {
+	s zx.Socket
+}
+
+func NewPipes() (*Pipe, *Pipe, error) {
+	s0, s1, err := zx.NewSocket(0)
+	if err != nil {
+		return nil, nil, err
+	}
+	return &Pipe{s0}, &Pipe{s1}, nil
+}
+
+func NewPipe(s zx.Socket) *Pipe {
+	return &Pipe{s}
+}
+
+func (f *Pipe) Wait(signals zx.Signals, timeout zx.Time) (observed zx.Signals, err error) {
+	return zxwait.Wait(zx.Handle(f.s), signals, timeout)
+}
+
+func (f *Pipe) Handles() []zx.Handle {
+	return []zx.Handle{zx.Handle(f.s)}
+}
+
+func (f *Pipe) Clone() (FDIO, error) {
+	h, err := f.s.Handle().Duplicate(zx.RightSameRights)
+	if err != nil {
+		return nil, err
+	}
+	return NewPipe(zx.Socket(h)), nil
+}
+
+func (f *Pipe) Close() error {
+	if err := f.s.Close(); err != nil {
+		return err
+	}
+	f.s = zx.Socket(zx.HandleInvalid)
+	return nil
+}
+
+func (f *Pipe) Sync() error {
+	return zx.Error{Status: zx.ErrNotSupported, Text: "fdio.Pipe"}
+}
+
+func (f *Pipe) GetAttr() (io.NodeAttributes, error) {
+	return io.NodeAttributes{}, zx.Error{Status: zx.ErrNotSupported, Text: "fdio.Pipe"}
+}
+
+func (f *Pipe) SetAttr(flags uint32, attr io.NodeAttributes) error {
+	return zx.Error{Status: zx.ErrNotSupported, Text: "fdio.Pipe"}
+}
+
+func (f *Pipe) Ioctl(op uint32, max uint64, in []byte, handles []zx.Handle) ([]byte, []zx.Handle, error) {
+	return nil, nil, zx.Error{Status: zx.ErrNotSupported, Text: "fdio.Pipe"}
+}
+
+func (f *Pipe) Read(data []byte) (n int, err error) {
+	for {
+		n, err = f.s.Read(data, 0)
+		if err == nil {
+			return n, nil
+		}
+		mxerr, ok := err.(zx.Error)
+		if !ok {
+			return n, err
+		}
+		switch mxerr.Status {
+		case zx.ErrPeerClosed:
+			return 0, zx.EOF
+		case zx.ErrShouldWait:
+			pending, err := f.Wait(zx.SignalSocketReadable|zx.SignalSocketPeerClosed, zx.TimensecInfinite)
+			if err != nil {
+				return 0, err
+			}
+			if pending&zx.SignalSocketReadable != 0 {
+				continue
+			}
+			if pending&zx.SignalSocketPeerClosed != 0 {
+				return 0, zx.EOF
+			}
+			// impossible
+			return 0, zx.Error{Status: zx.ErrInternal, Text: "fdio.Pipe"}
+		}
+		return 0, err
+	}
+}
+
+func (f *Pipe) ReadAt(data []byte, off int64) (int, error) {
+	return 0, zx.Error{Status: zx.ErrNotSupported, Text: "fdio.Pipe"}
+}
+
+func (f *Pipe) Write(data []byte) (n int, err error) {
+	for {
+		n, err = f.s.Write(data, 0)
+		if err == nil {
+			return n, nil
+		}
+		mxerr, ok := err.(zx.Error)
+		if !ok {
+			return n, err
+		}
+		switch mxerr.Status {
+		case zx.ErrPeerClosed:
+			return 0, zx.EOF
+			return 0, zx.EPIPE
+		case zx.ErrShouldWait:
+			pending, err := f.Wait(zx.SignalSocketWritable|zx.SignalSocketPeerClosed, zx.TimensecInfinite)
+			if err != nil {
+				return 0, err
+			}
+			if pending&zx.SignalSocketWritable != 0 {
+				continue
+			}
+			if pending&zx.SignalSocketPeerClosed != 0 {
+				return 0, zx.EPIPE
+			}
+			// impossible
+			return 0, zx.Error{Status: zx.ErrInternal, Text: "fdio.Pipe"}
+		}
+		return 0, err
+	}
+}
+
+func (f *Pipe) WriteAt(data []byte, off int64) (int, error) {
+	return 0, zx.Error{Status: zx.ErrNotSupported, Text: "fdio.Pipe"}
+}
+
+func (f *Pipe) Seek(offset int64, whence int) (int64, error) {
+	return 0, zx.Error{Status: zx.ErrNotSupported, Text: "fdio.Pipe"}
+}
+
+func (f *Pipe) Truncate(length uint64) error {
+	return zx.Error{Status: zx.ErrNotSupported, Text: "fdio.Pipe"}
+}
+
+func (f *Pipe) Open(path string, flags uint32, mode uint32) (FDIO, error) {
+	return nil, zx.Error{Status: zx.ErrNotSupported, Text: "fdio.Pipe"}
+}
+
+func (f *Pipe) Link(oldpath, newpath string) error {
+	return zx.Error{Status: zx.ErrNotSupported, Text: "fdio.Pipe"}
+}
+
+func (f *Pipe) Rename(oldpath, newpath string) error {
+	return zx.Error{Status: zx.ErrNotSupported, Text: "fdio.Pipe"}
+}
+
+func (f *Pipe) Unlink(path string) error {
+	return zx.Error{Status: zx.ErrNotSupported, Text: "fdio.Pipe"}
+}
+
+func (f *Pipe) ReadDirents(max uint64) ([]byte, error) {
+	return nil, zx.Error{Status: zx.ErrNotSupported, Text: "fdio.Pipe"}
+}
+
+func (f *Pipe) Rewind() error {
+	return zx.Error{Status: zx.ErrNotSupported, Text: "fdio.Pipe"}
+}
diff --git a/src/syscall/zx/fdio/vmo.go b/src/syscall/zx/fdio/vmo.go
new file mode 100644
index 0000000..d51094a
--- /dev/null
+++ b/src/syscall/zx/fdio/vmo.go
@@ -0,0 +1,161 @@
+// Copyright 2016 The Go 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 fuchsia
+
+package fdio
+
+import (
+	"syscall/zx"
+	"syscall/zx/io"
+)
+
+type VMOFile struct {
+	h   zx.VMO
+	off int64
+	len int64
+	end int64
+	at  int64
+}
+
+func NewVMOFile(handle zx.VMO, offset uint64, length uint64) (*VMOFile, error) {
+	// fdio_vmofile_create
+	f := &VMOFile{
+		h:   handle,
+		off: int64(offset),
+		len: int64(length),
+	}
+	f.end = f.off + f.len
+	f.at = f.off
+	return f, nil
+}
+
+func (f *VMOFile) Handles() []zx.Handle {
+	return []zx.Handle{zx.Handle(f.h)}
+}
+
+func (f *VMOFile) Clone() (FDIO, error) {
+	return nil, zx.Error{Status: zx.ErrNotSupported, Text: "fdio.VMOFile"}
+}
+
+func (f *VMOFile) Close() error {
+	if err := f.h.Close(); err != nil {
+		return err
+	}
+	f.h = 0
+	return nil
+}
+
+func (f *VMOFile) Sync() error {
+	return zx.Error{Status: zx.ErrNotSupported, Text: "fdio.VMOFile"}
+}
+
+func (f *VMOFile) GetAttr() (io.NodeAttributes, error) {
+	return io.NodeAttributes{
+		ContentSize: uint64(f.len),
+		StorageSize: uint64(f.len),
+		Mode: uint32(io.KModeTypeFile) | uint32(VtypeIRUSR),
+	}, nil
+}
+
+func (f *VMOFile) SetAttr(flags uint32, attr io.NodeAttributes) error {
+	return zx.Error{Status: zx.ErrNotSupported, Text: "fdio.VMOFile"}
+}
+
+func (f *VMOFile) Ioctl(op uint32, max uint64, in []byte, handles []zx.Handle) ([]byte, []zx.Handle, error) {
+	return nil, nil, zx.Error{Status: zx.ErrNotSupported, Text: "fdio.VMOFile"}
+}
+
+func (f *VMOFile) Read(data []byte) (n int, err error) {
+	if int64(len(data)) > f.end-f.at {
+		data = data[:f.end-f.at]
+		err = zx.EOF
+	}
+	if len(data) == 0 {
+		return 0, err
+	}
+	if err2 := f.h.Read(data, uint64(f.at)); err2 != nil {
+		return 0, err2
+	}
+	n = len(data)
+	f.at += int64(n)
+	return
+}
+
+func (f *VMOFile) ReadAt(data []byte, off int64) (n int, err error) {
+	if off < 0 {
+		return 0, zx.Error{Status: zx.ErrInvalidArgs, Text: "fdio.VMOFile.ReadAt"}
+	}
+	if off >= f.end {
+		return 0, zx.EOF
+	}
+	if len(data) == 0 {
+		return 0, zx.EOF
+	}
+	n = len(data)
+	max := int(f.end - off)
+	if max < n {
+		n = max
+		err = zx.EOF
+	}
+	data = data[:n]
+	if err2 := f.h.Read(data, uint64(off)); err2 != nil {
+		return 0, err2
+	}
+	return
+}
+
+func (f *VMOFile) Write(data []byte) (int, error) {
+	return 0, zx.Error{Status: zx.ErrNotSupported, Text: "fdio.VMOFile"}
+}
+
+func (f *VMOFile) WriteAt(data []byte, off int64) (int, error) {
+	return 0, zx.Error{Status: zx.ErrNotSupported, Text: "fdio.VMOFile"}
+}
+
+func (f *VMOFile) Seek(offset int64, whence int) (int64, error) {
+	var at int64
+	switch whence {
+	case 0: // SEEK_SET
+		at = offset
+	case 1: // SEEK_CUR
+		at = f.at - f.off + offset
+	case 2: // SEEK_END
+		at = f.end - f.off + offset
+	}
+
+	if at > f.end-f.off {
+		return 0, zx.Error{Status: zx.ErrOutOfRange, Text: "fdio.VMOFile"}
+	}
+	f.at = f.off + at
+	return at, nil
+}
+
+func (f *VMOFile) Truncate(length uint64) error {
+	return zx.Error{Status: zx.ErrNotSupported, Text: "fdio.VMOFile"}
+}
+
+func (f *VMOFile) Open(path string, flags uint32, mode uint32) (FDIO, error) {
+	return nil, zx.Error{Status: zx.ErrNotSupported, Text: "fdio.VMOFile"}
+}
+
+func (f *VMOFile) Link(oldpath, newpath string) error {
+	return zx.Error{Status: zx.ErrNotSupported, Text: "fdio.VMOFile"}
+}
+
+func (f *VMOFile) Rename(oldpath, newpath string) error {
+	return zx.Error{Status: zx.ErrNotSupported, Text: "fdio.VMOFile"}
+}
+
+func (f *VMOFile) Unlink(path string) error {
+	return zx.Error{Status: zx.ErrNotSupported, Text: "fdio.VMOFile"}
+}
+
+func (f *VMOFile) ReadDirents(max uint64) ([]byte, error) {
+	return nil, zx.Error{Status: zx.ErrNotSupported, Text: "fdio.VMOFile"}
+}
+
+func (f *VMOFile) Rewind() error {
+	return zx.Error{Status: zx.ErrNotSupported, Text: "fdio.VMOFile"}
+}
diff --git a/src/syscall/zx/fidl/bindings.go b/src/syscall/zx/fidl/bindings.go
new file mode 100644
index 0000000..f1e5c83
--- /dev/null
+++ b/src/syscall/zx/fidl/bindings.go
@@ -0,0 +1,306 @@
+// Copyright 2018 The Go 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 fuchsia
+
+package fidl
+
+import (
+	"sync"
+	"syscall/zx"
+	"syscall/zx/dispatch"
+)
+
+const prefix = "zx/fidl: "
+
+// d is a process-local dispatcher.
+var d *dispatch.Dispatcher
+
+func init() {
+	disp, err := dispatch.NewDispatcher()
+	if err != nil {
+		panic(prefix + "failed to create dispatcher: " + err.Error())
+	}
+	d = disp
+}
+
+// Serve is a blocking call to the process-local dispatcher's serve method.
+func Serve() {
+	d.Serve()
+}
+
+type bindingState int32
+
+const (
+	idle bindingState = iota
+	handling
+	cleanup
+)
+
+// Binding binds the implementation of a Stub to a Channel.
+//
+// A Binding listens for incoming messages on the Channel, decodes them, and
+// asks the Stub to dispatch to the appropriate implementation of the interface.
+// If the message expects a reply, the Binding will also encode the reply and
+// send it back over the Channel.
+type Binding struct {
+	// Stub is a wrapper around an implementation of a FIDL interface which
+	// knows how to dispatch to a method by ordinal.
+	Stub Stub
+
+	// Channel is the Channel primitive to which the Stub is bound.
+	Channel zx.Channel
+
+	// id is an identifier for this waiter in the process-local dispatcher.
+	id *dispatch.WaitID
+
+	// errHandler is called with connection errors, when encountered.
+	errHandler func(error)
+
+	// handling is an atomically-updated signal which represents the state of the
+	// binding.
+	stateMu sync.Mutex
+	state   bindingState
+}
+
+// Init initializes a Binding.
+func (b *Binding) Init(errHandler func(error)) error {
+	// Declare the wait handler as a closure.
+	h := func(d *dispatch.Dispatcher, s zx.Status, sigs *zx.PacketSignal) (result dispatch.WaitResult) {
+		b.stateMu.Lock()
+		if b.state == cleanup {
+			b.close()
+			b.stateMu.Unlock()
+			return dispatch.WaitFinished
+		}
+		b.state = handling
+		b.stateMu.Unlock()
+		defer func() {
+			b.stateMu.Lock()
+			defer b.stateMu.Unlock()
+			if b.state == cleanup {
+				b.close()
+				result = dispatch.WaitFinished
+			}
+			b.state = idle
+		}()
+		if s != zx.ErrOk {
+			b.errHandler(zx.Error{Status: s})
+			return dispatch.WaitFinished
+		}
+		if sigs.Observed&zx.SignalChannelReadable != 0 {
+			for i := uint64(0); i < sigs.Count; i++ {
+				shouldWait, err := b.dispatch()
+				if err != nil {
+					b.errHandler(err)
+					return dispatch.WaitFinished
+				}
+				if shouldWait {
+					return dispatch.WaitAgain
+				}
+			}
+			return dispatch.WaitAgain
+		}
+		b.errHandler(zx.Error{Status: zx.ErrPeerClosed})
+		return dispatch.WaitFinished
+	}
+
+	b.stateMu.Lock()
+	b.state = idle
+	b.stateMu.Unlock()
+
+	b.errHandler = errHandler
+
+	// Start the wait on the Channel.
+	id, err := d.BeginWait(
+		zx.Handle(b.Channel),
+		zx.SignalChannelReadable|zx.SignalChannelPeerClosed,
+		0,
+		h,
+	)
+	if err != nil {
+		return err
+	}
+	b.id = &id
+	return nil
+}
+
+// dispatch reads from the underlying Channel and dispatches into the Stub.
+//
+// Returns true if the channel should be waited, or false if there is more data to be read.
+func (b *Binding) dispatch() (shouldWait bool, err error) {
+	respb := messageBytesPool.Get().([]byte)
+	resph := messageHandlesPool.Get().([]zx.Handle)
+
+	defer messageBytesPool.Put(respb)
+	defer messageHandlesPool.Put(resph)
+
+	nb, nh, err := b.Channel.Read(respb[:], resph[:], 0)
+	if err != nil {
+		zxErr, ok := err.(zx.Error)
+		if ok && zxErr.Status == zx.ErrShouldWait {
+			return true, nil
+		}
+		return false, err
+	}
+	var header MessageHeader
+	if err := UnmarshalHeader(respb[:], &header); err != nil {
+		return false, err
+	}
+	start := MessageHeaderSize
+	p, err := b.Stub.Dispatch(header.Ordinal, respb[start:int(nb)], resph[:nh])
+	switch {
+	case err == ErrUnknownOrdinal:
+		// If we couldn't determine the ordinal, we still own the
+		// handles, so we should close them all.
+		for _, h := range resph[:nh] {
+			h.Close()
+		}
+		fallthrough
+	case err != nil:
+		return false, err
+	}
+	// Message has no response.
+	if p == nil {
+		return false, nil
+	}
+	cnb, cnh, err := MarshalMessage(&header, p, respb[:], resph[:])
+	if err != nil {
+		return false, err
+	}
+	if err := b.Channel.Write(respb[:cnb], resph[:cnh], 0); err != nil {
+		return false, err
+	}
+	return false, nil
+}
+
+// Close cancels any outstanding waits, resets the Binding's state, and closes
+// the bound Channel once any out-standing requests are finished being handled.
+func (b *Binding) Close() error {
+	b.stateMu.Lock()
+	defer b.stateMu.Unlock()
+	if zx.Handle(b.Channel) == zx.HandleInvalid || b.state == cleanup {
+		panic(prefix + "double binding close")
+	}
+	switch b.state {
+	case idle:
+		return b.close()
+	case handling:
+		b.state = cleanup
+	}
+	return nil
+}
+
+// close cancels any outstanding waits, resets the Binding's state, and
+// closes the bound Channel. This method is not thread-safe, and should be
+// called with the binding's mutex set.
+func (b *Binding) close() error {
+	if err := d.CancelWait(*b.id); err != nil {
+		zxErr, ok := err.(zx.Error)
+		// If it just says that the ID isn't found, there are cases where this is
+		// a reasonable error (particularly when we're in the middle of handling
+		// a signal from the dispatcher).
+		if !ok || zxErr.Status != zx.ErrNotFound {
+			// Attempt to close the channel if we hit a more serious error.
+			b.Channel.Close()
+			return err
+		}
+	}
+	b.id = nil
+	b.state = idle
+	return b.Channel.Close()
+}
+
+// BindingKey is a key which maps to a specific binding.
+//
+// It is only valid for the BindingSet that produced it.
+type BindingKey uint64
+
+// BindingSet is a managed set of Bindings which know how to unbind and
+// remove themselves in the event of a connection error.
+type BindingSet struct {
+	nextKey  BindingKey
+	mu       sync.Mutex
+	Bindings map[BindingKey]*Binding
+}
+
+// Add creates a new Binding, initializes it, and adds it to the set.
+//
+// onError is an optional handler than may be passed which will be called after
+// the binding between the Stub and the Channel is successfully closed.
+func (b *BindingSet) Add(s Stub, c zx.Channel, onError func(error)) (BindingKey, error) {
+	binding := &Binding{
+		Stub:    s,
+		Channel: c,
+	}
+	b.mu.Lock()
+	defer b.mu.Unlock()
+	if b.Bindings == nil {
+		b.Bindings = make(map[BindingKey]*Binding)
+	}
+	key := b.nextKey
+	err := binding.Init(func(err error) {
+		if b.Remove(key) && onError != nil {
+			onError(err)
+		}
+	})
+	if err != nil {
+		return 0, err
+	}
+	b.Bindings[key] = binding
+	b.nextKey += 1
+	return key, nil
+}
+
+// ProxyFor returns an event proxy created from the channel of the binding referred
+// to by key.
+func (b *BindingSet) ProxyFor(key BindingKey) (*Proxy, bool) {
+	b.mu.Lock()
+	defer b.mu.Unlock()
+	if binding, ok := b.Bindings[key]; ok {
+		return &Proxy{Channel: binding.Channel}, true
+	}
+	return nil, false
+}
+
+// Remove removes a Binding from the set when it is next idle.
+//
+// Note that this method invalidates the key, and it will never remove a Binding
+// while it is actively being handled.
+//
+// Returns true if a Binding was found and removed.
+func (b *BindingSet) Remove(key BindingKey) bool {
+	b.mu.Lock()
+	if binding, ok := b.Bindings[key]; ok {
+		delete(b.Bindings, key)
+		b.mu.Unlock()
+
+		// Close the binding before calling the callback.
+		if err := binding.Close(); err != nil {
+			// Just panic. The only reason this can fail is if the handle
+			// is bad, which it shouldn't be if we're tracking things. If
+			// it does fail, better to fail fast.
+			panic(prefix + err.Error())
+		}
+		return true
+	}
+	b.mu.Unlock()
+	return false
+}
+
+// Close removes all the bindings from the set.
+func (b *BindingSet) Close() {
+	// Lock, close all the bindings, and clear the map.
+	b.mu.Lock()
+	for _, binding := range b.Bindings {
+		if err := binding.Close(); err != nil {
+			// Just panic. The only reason this can fail is if the handle
+			// is bad, which it shouldn't be if we're tracking things. If
+			// it does fail, better to fail fast.
+			panic(prefix + err.Error())
+		}
+	}
+	b.Bindings = make(map[BindingKey]*Binding)
+	b.mu.Unlock()
+}
diff --git a/src/syscall/zx/fidl/bindings_test.go b/src/syscall/zx/fidl/bindings_test.go
new file mode 100644
index 0000000..faa44b6
--- /dev/null
+++ b/src/syscall/zx/fidl/bindings_test.go
@@ -0,0 +1,84 @@
+// Copyright 2018 The Go 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 fuchsia
+
+package fidl_test
+
+import (
+	"syscall/zx"
+	"testing"
+	"time"
+
+	. "fidl/bindings"
+	. "fuchsia/go/go_fidl_bindings_test"
+)
+
+type Test1Impl struct{}
+
+func (t *Test1Impl) Echo(s *string) (*string, error) {
+	return s, nil
+}
+
+func TestEcho(t *testing.T) {
+	t.Parallel()
+
+	ch, sh, err := zx.NewChannel(0)
+	if err != nil {
+		t.Fatal(err)
+	}
+	client := Test1Interface(Proxy{Channel: ch})
+	server := Test1Service{}
+	clientKey, err := server.Add(&Test1Impl{}, sh, nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+	go Serve()
+
+	t.Run("Basic", func(t *testing.T) {
+		str := "Hello World!"
+		r, err := client.Echo(&str)
+		if err != nil {
+			t.Fatal(err)
+		}
+		if r == nil {
+			t.Fatal("unexpected nil result")
+		}
+		if *r != str {
+			t.Fatalf("expected %s, got %s", str, *r)
+		}
+	})
+
+	t.Run("Event", func(t *testing.T) {
+		str := "Surprise!"
+		done := make(chan struct{})
+		// Spin up goroutine with waiting client.
+		go func() {
+			s, err := client.ExpectSurprise()
+			if err != nil {
+				t.Fatal(err)
+			}
+			if s != str {
+				t.Fatalf("expected %s, got %s", str, s)
+			}
+			done <- struct{}{}
+		}()
+		// Spin up server goroutine which makes the call.
+		go func() {
+			pxy, ok := server.EventProxyFor(clientKey)
+			if !ok {
+				t.Fatalf("could not create proxy for key %d", clientKey)
+			}
+			if err := pxy.Surprise(str); err != nil {
+				t.Fatal(err)
+			}
+		}()
+		select {
+		case <-done:
+			return
+		case <-time.After(5 * time.Second):
+			t.Fatalf("test timed out")
+		}
+	})
+}
diff --git a/src/syscall/zx/fidl/bindings_test/test.fidl b/src/syscall/zx/fidl/bindings_test/test.fidl
new file mode 100644
index 0000000..cf0aeed
--- /dev/null
+++ b/src/syscall/zx/fidl/bindings_test/test.fidl
@@ -0,0 +1,145 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+library go_fidl_bindings_test;
+
+struct TestSimple {
+    int64 x;
+};
+
+struct TestSimpleBool {
+    bool x;
+};
+
+struct TestAlignment1 {
+    int8 x;
+    int8 y;
+    uint32 z;
+};
+
+struct TestAlignment2 {
+    uint32 a;
+    uint32 b;
+    int8 c;
+    int8 d;
+    int8 e;
+    uint8 f;
+    uint32 g;
+    uint16 h;
+    uint16 i;
+};
+
+struct TestFloat1 {
+    float32 a;
+};
+
+struct TestFloat2 {
+    float64 a;
+};
+
+struct TestFloat3 {
+    float32 a;
+    float64 b;
+    uint64 c;
+    float32 d;
+};
+
+struct TestArray1 {
+    array<int8>:5 a;
+};
+
+struct TestArray2 {
+    float64 a;
+    array<float32>:1 b;
+};
+
+struct TestArray3 {
+    int32 a;
+    array<uint16>:3 b;
+    uint64 c;
+};
+
+struct TestArray4 {
+    array<bool>:9 a;
+};
+
+struct TestString1 {
+    string a;
+    string? b;
+};
+
+struct TestString2 {
+    array<string>:2 a;
+};
+
+struct TestString3 {
+    array<string:4>:2 a;
+    array<string:4?>:2 b;
+};
+
+struct TestVector1 {
+    vector<int8> a;
+    vector<int16>? b;
+    vector<int32>:2 c;
+    vector<int64>:2? d;
+};
+
+struct TestVector2 {
+    array<vector<int8>>:2 a;
+    vector<vector<int8>>:2 b;
+    vector<vector<string:5>:2?>:2 c;
+};
+
+struct TestStruct1 {
+    TestSimple a;
+    TestSimple? b;
+};
+
+struct TestStruct2 {
+    TestArray1 a;
+    TestFloat1 b;
+    TestVector1 c;
+    TestString1? d;
+};
+
+union Union1 {
+    array<int8>:3 a;
+    TestSimple b;
+    TestSimple? c;
+    float32 d;
+};
+
+struct TestUnion1 {
+    Union1 a;
+    Union1? b;
+};
+
+struct TestUnion2 {
+    vector<Union1> a;
+    vector<Union1?> b;
+};
+
+struct TestHandle1 {
+    handle a;
+    handle? b;
+    handle<vmo> c;
+    handle<vmo>? d;
+};
+
+struct TestHandle2 {
+    vector<handle>:1 a;
+    vector<handle<vmo>?>:1 b;
+};
+
+interface Test1 {
+    10: Echo(string? in) -> (string? out);
+    11: -> Surprise(string foo);
+};
+
+struct TestInterface1 {
+    Test1 a;
+    Test1? b;
+    request<Test1> c;
+    request<Test1>? d;
+};
diff --git a/src/syscall/zx/fidl/encoding.go b/src/syscall/zx/fidl/encoding.go
new file mode 100644
index 0000000..bba6e0d
--- /dev/null
+++ b/src/syscall/zx/fidl/encoding.go
@@ -0,0 +1,1017 @@
+// Copyright 2018 The Go 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 fuchsia
+
+package fidl
+
+import (
+	"errors"
+	"math"
+	"reflect"
+	"strconv"
+	"strings"
+	"syscall/zx"
+)
+
+const (
+	allocPresent uint64 = math.MaxUint64
+	noAlloc             = 0
+)
+
+const (
+	handlePresent uint32 = math.MaxUint32
+	noHandle             = 0
+)
+
+var (
+	// TODO(mknyszek): Add support here for process, thread, job, resource,
+	// interrupt, eventpair, fifo, guest, and time once these are actually
+	// supported in the Go runtime.
+	handleType           reflect.Type = reflect.TypeOf(zx.Handle(0))
+	channelType                       = reflect.TypeOf(zx.Channel(0))
+	logType                           = reflect.TypeOf(zx.Log(0))
+	portType                          = reflect.TypeOf(zx.Port(0))
+	vmoType                           = reflect.TypeOf(zx.VMO(0))
+	eventType                         = reflect.TypeOf(zx.Event(0))
+	socketType                        = reflect.TypeOf(zx.Socket(0))
+	vmarType                          = reflect.TypeOf(zx.VMAR(0))
+	interfaceRequestType              = reflect.TypeOf(InterfaceRequest{})
+	proxyType                         = reflect.TypeOf(Proxy{})
+)
+
+// isUnionType returns true if the reflected type is a FIDL union type.
+func isUnionType(t reflect.Type) bool {
+	// This is a safe way to check if it's a union type because the generated
+	// code inserts a "dummy" field (of type struct{}) at the beginning as a
+	// marker that the struct should be treated as a FIDL union. Because all FIDL
+	// fields are exported, there's no potential for name collision either, and a
+	// struct accidentally being treated as a union.
+	return t.Kind() == reflect.Struct && t.NumField() > 1 && t.Field(0).Tag.Get("fidl") == "tag"
+}
+
+// isHandleType returns true if the reflected type is a Fuchsia handle type.
+func isHandleType(t reflect.Type) bool {
+	switch t {
+	case handleType:
+		fallthrough
+	case channelType:
+		fallthrough
+	case logType:
+		fallthrough
+	case portType:
+		fallthrough
+	case vmoType:
+		fallthrough
+	case eventType:
+		fallthrough
+	case socketType:
+		fallthrough
+	case vmarType:
+		return true
+	}
+	return false
+}
+
+// isInterfaceType returns true if the reflected type is a FIDL interface type.
+func isInterfaceType(t reflect.Type) bool {
+	// FIDL interfaces are represented as aliases over Proxy.
+	return t.ConvertibleTo(proxyType)
+}
+
+// isInterfaceRequestType returns true if the reflected type is a FIDL interface
+// request type.
+func isInterfaceRequestType(t reflect.Type) bool {
+	// FIDL interfaces are represented as aliases over InterfaceRequest.
+	return t.ConvertibleTo(interfaceRequestType)
+}
+
+// getSize returns the size of the type. Occasionally this requires the value,
+// particularly for a struct.
+func getSize(t reflect.Type, v reflect.Value) (int, error) {
+	switch t.Kind() {
+	case reflect.Array:
+		if v.Len() == 0 {
+			return 0, nil
+		}
+		s, err := getSize(t.Elem(), v.Index(0))
+		if err != nil {
+			return 0, err
+		}
+		return v.Len() * s, nil
+	case reflect.Bool, reflect.Int8, reflect.Uint8:
+		return 1, nil
+	case reflect.Int16, reflect.Uint16:
+		return 2, nil
+	case reflect.Int32, reflect.Uint32, reflect.Float32:
+		return 4, nil
+	case reflect.Int64, reflect.Uint64, reflect.Float64:
+		return 8, nil
+	case reflect.Ptr:
+		i := t.Elem()
+		switch i.Kind() {
+		case reflect.Slice:
+			return 16, nil
+		case reflect.String:
+			return 16, nil
+		case reflect.Struct:
+			// Handles both structs and unions.
+			return 8, nil
+		}
+		return 0, newValueError(ErrInvalidPointerType, t.Name())
+	case reflect.String:
+		return 16, nil
+	case reflect.Slice:
+		return 16, nil
+	case reflect.Struct:
+		// Handles both structs and unions.
+		return getPayloadSize(t, v)
+	}
+	return 0, newValueError(ErrInvalidInlineType, t.Name())
+}
+
+func structAsPayload(t reflect.Type, v reflect.Value) (Payload, error) {
+	// Get the size and alignment for the struct.
+	//
+	// Note that Addr can fail if the originally derived value is not "addressable",
+	// meaning the root ValueOf() call was on a struct value, not a pointer. However,
+	// we guarantee the struct is addressable by forcing a Payload to be passed in
+	// (a struct value will never cast as an interface).
+	//
+	// We avoid using Implements(), MethodByName(), and Call() here because they're
+	// very slow.
+	payload, ok := v.Addr().Interface().(Payload)
+	if !ok {
+		return nil, ErrStructIsNotPayload
+	}
+	return payload, nil
+}
+
+func getPayloadSize(t reflect.Type, v reflect.Value) (int, error) {
+	p, err := structAsPayload(t, v)
+	if err != nil {
+		return 0, err
+	}
+	return p.InlineSize(), nil
+}
+
+func getPayloadAlignment(t reflect.Type, v reflect.Value) (int, error) {
+	p, err := structAsPayload(t, v)
+	if err != nil {
+		return 0, err
+	}
+	return p.InlineAlignment(), nil
+}
+
+// fieldData contains metadata for a single struct field for use during encoding and
+// decoding. It is derived from a struct field tag, and generally contains facilities
+// for managing state in a recursive context (since even the type in a single struct field
+// may be recursively defined).
+type nestedTypeData struct {
+	// maxElems represents the maximum number of elements allowed for a
+	// container type. "nil" means there is no maximum. It is represented
+	// as a slice because FIDL container types may be nested arbitrarily
+	// deeply. The lower the index, the more deeply nested the type is.
+	maxElems []*int
+
+	// nullable reflects whether the innermost type for a struct field is nullable.
+	// This is only used for types where nullability is non-obvious, which is only
+	// handles for now.
+	nullable bool
+}
+
+// Unnest attempts to unnest the nestedTypeData one level. If it succeeds, it returns the type
+// data for that nesting level, and modifies the data structure for the next nested container.
+func (n *nestedTypeData) Unnest() *int {
+	if len(n.maxElems) == 0 {
+		return nil
+	}
+	v := n.maxElems[len(n.maxElems)-1]
+	n.maxElems = n.maxElems[:len(n.maxElems)-1]
+	return v
+}
+
+// FromTag derives metadata from data serialized into a golang struct field
+// tag.
+func (n *nestedTypeData) FromTag(tag reflect.StructTag) error {
+	raw, ok := tag.Lookup("fidl")
+	if !ok {
+		return nil
+	}
+	split := strings.Split(raw, ",")
+	if split[0] == "*" {
+		n.nullable = true
+		split = split[1:]
+	}
+	var maxElems []*int
+	for _, e := range split {
+		if e == "" {
+			maxElems = append(maxElems, nil)
+			continue
+		}
+		i, err := strconv.ParseInt(e, 0, 64)
+		if err != nil {
+			return err
+		}
+		val := int(i)
+		maxElems = append(maxElems, &val)
+	}
+	n.maxElems = maxElems
+	return nil
+}
+
+// align increases size such that size is aligned to bytes, and returns the new size.
+//
+// bytes must be a power of 2.
+func align(size, bytes int) int {
+	offset := size & (bytes - 1)
+	// If we're not currently aligned to |bytes| bytes, add padding.
+	if offset != 0 {
+		size += (bytes - offset)
+	}
+	return size
+}
+
+// encoder represents the encoding context that is necessary to maintain across
+// recursive calls within the same FIDL object.
+type encoder struct {
+	// head is the index into buffer at which new data will be written to for the current
+	// object. It must be updated before writing to a new out-of-line object, and then
+	// fixed when that object is finished.
+	head int
+
+	// buffer represents the output buffer that the encoder writes into.
+	buffer []byte
+
+	// handles are the handles discovered when traversing the FIDL data
+	// structure. They are referenced from within the serialized data
+	// structure in buffer.
+	handles []zx.Handle
+}
+
+func (e *encoder) newObject(size int) int {
+	size = align(size, 8)
+	start := len(e.buffer)
+	e.buffer = append(e.buffer, make([]byte, size)...)
+	return start
+}
+
+// writeInt writes an integer of byte-width size to the buffer.
+//
+// Before writing, it pads the buffer such that the integer is aligned to
+// its own byte-width.
+//
+// size must be a power of 2 <= 8.
+func (e *encoder) writeInt(val int64, size int) {
+	e.writeUint(uint64(val), size)
+}
+
+// writeUint writes an unsigned integer of byte-width size to the buffer.
+//
+// Before writing, it pads the buffer such that the integer is aligned to
+// its own byte-width.
+//
+// size must be a power of 2 <= 8.
+func (e *encoder) writeUint(val uint64, size int) {
+	e.head = align(e.head, size)
+	for i := e.head; i < e.head+size; i++ {
+		e.buffer[i] = byte(val & 0xFF)
+		val >>= 8
+	}
+	e.head += size
+}
+
+// marshalStructOrUnionInline first aligns head to the struct's or union's alignment
+// factor, and then writes its field(s) inline.
+//
+// Expects the Type t and Value v to refer to a golang struct value, not a pointer.
+func (e *encoder) marshalStructOrUnionInline(t reflect.Type, v reflect.Value) error {
+	a, err := getPayloadAlignment(t, v)
+	if err != nil {
+		return err
+	}
+	e.head = align(e.head, a)
+	if isUnionType(t) {
+		err = e.marshalUnion(t, v, a)
+	} else {
+		err = e.marshalStructFields(t, v)
+	}
+	if err != nil {
+		return err
+	}
+	e.head = align(e.head, a)
+	return nil
+}
+
+// marshalStructOrUnionPointer marshals a nullable struct's or union's reference, and then
+// marshals the value itself out-of-line.
+//
+// Expects the Type t and Value v to refer to a pointer to a golang struct.
+func (e *encoder) marshalStructOrUnionPointer(t reflect.Type, v reflect.Value) error {
+	if v.IsNil() {
+		e.writeUint(noAlloc, 8)
+		return nil
+	}
+	e.writeUint(allocPresent, 8)
+	et := t.Elem()
+	ev := v.Elem()
+	// Encode the value out-of-line.
+	payload, err := structAsPayload(et, ev)
+	if err != nil {
+		return err
+	}
+	oldHead := e.head
+	e.head = e.newObject(align(payload.InlineSize(), 8))
+	if isUnionType(et) {
+		err = e.marshalUnion(et, ev, payload.InlineAlignment())
+	} else {
+		err = e.marshalStructFields(et, ev)
+	}
+	if err != nil {
+		return err
+	}
+	e.head = oldHead
+	return nil
+}
+
+// marshalStructFields marshals the fields of a struct inline without any alignment.
+//
+// Expects the Type t and Value v to refer to a struct value, not a pointer.
+//
+// It marshals only exported struct fields.
+func (e *encoder) marshalStructFields(t reflect.Type, v reflect.Value) error {
+	for i := 0; i < t.NumField(); i++ {
+		f := t.Field(i)
+		// If it's an unexported field, ignore it.
+		if f.PkgPath != "" {
+			continue
+		}
+		var n nestedTypeData
+		if err := n.FromTag(f.Tag); err != nil {
+			return err
+		}
+		if err := e.marshal(f.Type, v.Field(i), n); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+// marshalUnion marshals a FIDL union represented as a golang struct inline,
+// without any external alignment.
+//
+// Expects the Type t and Value v to refer to a golang struct value, not a
+// pointer. The alignment field is used to align the union's field.
+func (e *encoder) marshalUnion(t reflect.Type, v reflect.Value, alignment int) error {
+	kind := v.Field(0).Uint()
+
+	// Index into the fields of the struct, adding 1 for the tag.
+	fieldIndex := int(kind) + 1
+	if fieldIndex >= t.NumField() {
+		return newValueError(ErrInvalidUnionTag, kind)
+	}
+	// Save the head for proper padding.
+	head := e.head
+	e.writeUint(kind, 4)
+
+	f := t.Field(fieldIndex)
+	var n nestedTypeData
+	if err := n.FromTag(f.Tag); err != nil {
+		return err
+	}
+	// Re-align to the union's alignment before writing its field.
+	e.head = align(e.head, alignment)
+	if err := e.marshal(f.Type, v.Field(fieldIndex), n); err != nil {
+		return err
+	}
+	s, err := getPayloadSize(t, v)
+	if err != nil {
+		return err
+	}
+	e.head = head + s
+	return nil
+}
+
+// marshalArray marshals a FIDL array inline.
+func (e *encoder) marshalArray(t reflect.Type, v reflect.Value, n nestedTypeData) error {
+	elemType := t.Elem()
+	for i := 0; i < t.Len(); i++ {
+		if err := e.marshal(elemType, v.Index(i), n); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+// marshalInline marshals a number of different supported FIDL types inline.
+func (e *encoder) marshalInline(t reflect.Type, v reflect.Value, n nestedTypeData) error {
+	switch t.Kind() {
+	case reflect.Array:
+		return e.marshalArray(t, v, n)
+	case reflect.Bool:
+		i := uint64(0)
+		if v.Bool() {
+			i = 1
+		}
+		e.writeUint(i, 1)
+	case reflect.Int8:
+		e.writeInt(v.Int(), 1)
+	case reflect.Int16:
+		e.writeInt(v.Int(), 2)
+	case reflect.Int32:
+		e.writeInt(v.Int(), 4)
+	case reflect.Int64:
+		e.writeInt(v.Int(), 8)
+	case reflect.Uint8:
+		e.writeUint(v.Uint(), 1)
+	case reflect.Uint16:
+		e.writeUint(v.Uint(), 2)
+	case reflect.Uint32:
+		e.writeUint(v.Uint(), 4)
+	case reflect.Uint64:
+		e.writeUint(v.Uint(), 8)
+	case reflect.Float32:
+		e.writeUint(uint64(math.Float32bits(float32(v.Float()))), 4)
+	case reflect.Float64:
+		e.writeUint(math.Float64bits(v.Float()), 8)
+	case reflect.Struct:
+		return e.marshalStructOrUnionInline(t, v)
+	default:
+		return newValueError(ErrInvalidInlineType, t.Name())
+	}
+	return nil
+}
+
+// marshalVector writes the vector metadata inline and the elements of the vector in a new
+// out-of-line object. Expects the value to be a regular string value, i.e. of type string.
+func (e *encoder) marshalVector(t reflect.Type, v reflect.Value, n nestedTypeData) error {
+	if !v.IsValid() {
+		e.writeUint(0, 8)
+		e.writeUint(noAlloc, 8)
+		return nil
+	}
+	max := n.Unnest()
+	if max != nil && v.Len() > *max {
+		return newExpectError(ErrVectorTooLong, *max, v.Len())
+	}
+	e.writeUint(uint64(v.Len()), 8)
+	e.writeUint(allocPresent, 8)
+	// Don't bother creating the out-of-line struct if its length is 0.
+	if v.Len() == 0 {
+		return nil
+	}
+	elemType := t.Elem()
+	elemSize, err := getSize(elemType, v.Index(0))
+	if err != nil {
+		return err
+	}
+	// Encode in the out-of-line object.
+	oldHead := e.head
+	e.head = e.newObject(v.Len() * elemSize)
+
+	if elemType.Kind() == reflect.Uint8 {
+		// optimize the fdio case of a vector of bytes
+		copy(e.buffer[e.head:], v.Bytes())
+	} else {
+		for i := 0; i < v.Len(); i++ {
+			if err := e.marshal(elemType, v.Index(i), n); err != nil {
+				return err
+			}
+		}
+	}
+	e.head = oldHead
+	return nil
+}
+
+// marshalString writes the string metadata inline and the bytes of the string in a new
+// out-of-line object. Expects the value to be a regular string value, i.e. of type string.
+func (e *encoder) marshalString(v reflect.Value, n nestedTypeData) error {
+	if !v.IsValid() {
+		e.writeUint(0, 8)
+		e.writeUint(noAlloc, 8)
+		return nil
+	}
+	s := v.String()
+	max := n.Unnest()
+	if max != nil && len(s) > *max {
+		return newExpectError(ErrStringTooLong, *max, len(s))
+	}
+	e.writeUint(uint64(len(s)), 8)
+	e.writeUint(allocPresent, 8)
+
+	// Create a new out-of-line object and write bytes of the string.
+	head := e.newObject(len(s))
+	for i := 0; i < len(s); i++ {
+		e.buffer[head+i] = s[i]
+	}
+	return nil
+}
+
+// marshalHandle marshals a Fuchsia handle type, and ensures that the handle is
+// valid if it is not nullable.
+func (e *encoder) marshalHandle(v reflect.Value, n nestedTypeData) error {
+	// The underlying type of all the handles is a uint32, so we're
+	// safe calling Uint(). This will panic if that is no longer true.
+	raw := zx.Handle(v.Uint())
+	if raw == zx.HandleInvalid {
+		if !n.nullable {
+			return ErrUnexpectedNullHandle
+		}
+		e.writeUint(uint64(noHandle), 4)
+		return nil
+	}
+	e.handles = append(e.handles, raw)
+	e.writeUint(uint64(handlePresent), 4)
+	return nil
+}
+
+// marshalPointer marshals nullable FIDL types that are represented by golang pointer
+// indirections. The input type and value should be the dereference of the golang pointers,
+// that is, if we're marshalling *string, we should get string.
+func (e *encoder) marshalPointer(t reflect.Type, v reflect.Value, n nestedTypeData) error {
+	switch t.Elem().Kind() {
+	case reflect.Slice:
+		return e.marshalVector(t.Elem(), v.Elem(), n)
+	case reflect.String:
+		return e.marshalString(v.Elem(), n)
+	case reflect.Struct:
+		return e.marshalStructOrUnionPointer(t, v)
+	}
+	return newValueError(ErrInvalidPointerType, t.Name())
+}
+
+// marshal is the central recursive function core to marshalling, and
+// traverses the tree-like structure of the input type t. v represents
+// the value associated with the type t.
+func (e *encoder) marshal(t reflect.Type, v reflect.Value, n nestedTypeData) error {
+	switch t.Kind() {
+	case reflect.Ptr:
+		return e.marshalPointer(t, v, n)
+	case reflect.Slice:
+		return e.marshalVector(t, v, n)
+	case reflect.String:
+		return e.marshalString(v, n)
+	}
+	if isHandleType(t) {
+		return e.marshalHandle(v, n)
+	}
+	if isInterfaceType(t) || isInterfaceRequestType(t) {
+		// An interface is represented by a Proxy, whose first field is
+		// a zx.Channel, and we can just marshal that. Same goes for an
+		// interface request, which is just an InterfaceRequest whose
+		// first field is a zx.Channel.
+		return e.marshalHandle(v.Field(0), n)
+	}
+	return e.marshalInline(t, v, n)
+}
+
+// MarshalHeader encodes the FIDL message header into the beginning of data.
+func MarshalHeader(header *MessageHeader, data []byte) {
+	// Clear the buffer so we can append to it.
+	e := encoder{buffer: data[:0]}
+	e.head = e.newObject(MessageHeaderSize)
+	e.writeUint(uint64(header.Txid), 4)
+	e.writeUint(uint64(header.Reserved), 4)
+	e.writeUint(uint64(header.Flags), 4)
+	e.writeUint(uint64(header.Ordinal), 4)
+}
+
+// Marshal the FIDL payload in s into data and handles.
+//
+// s must be a pointer to a struct, since the primary object in a FIDL message
+// is always a struct.
+//
+// Marshal traverses the value s recursively, following nested type values via
+// reflection in order to encode the FIDL struct.
+func Marshal(s Payload, data []byte, handles []zx.Handle) (int, int, error) {
+	// First, let's make sure we have the right type in s.
+	t := reflect.TypeOf(s)
+	if t.Kind() != reflect.Ptr {
+		return 0, 0, errors.New("expected a pointer")
+	}
+	t = t.Elem()
+	if t.Kind() != reflect.Struct {
+		return 0, 0, errors.New("primary object must be a struct")
+	}
+
+	// Now, let's get the value of s, marshal the header into a starting
+	// buffer, and then marshal the rest of the payload in s.
+	v := reflect.ValueOf(s).Elem()
+	e := encoder{buffer: data[:0], handles: handles[:0]}
+	e.head = e.newObject(s.InlineSize())
+	if err := e.marshalStructFields(t, v); err != nil {
+		return 0, 0, err
+	}
+	return len(e.buffer), len(e.handles), nil
+}
+
+// decoder represents the decoding context that is necessary to maintain
+// across recursive calls within the same FIDL object.
+type decoder struct {
+	// head is the index into buffer at which new data will be read from for the current
+	// object. It must be updated before reading from a new out-of-line object, and then
+	// fixed when that object is finished.
+	head int
+
+	// nextObject is the byte index of the next out-of-line object in buffer.
+	nextObject int
+
+	// buffer represents the buffer we're decoding from.
+	buffer []byte
+
+	// handles represents the input untyped handled we're decoding.
+	handles []zx.Handle
+}
+
+// readInt reads a signed integer value of byte-width size from the buffer.
+//
+// Before it reads, however, it moves the head forward so as to be naturally
+// aligned with the byte-width of the integer it is reading.
+//
+// size must be a power of 2 <= 8.
+func (d *decoder) readInt(size int) int64 {
+	return int64(d.readUint(size))
+}
+
+// readUint reads an unsigned integer value of byte-width size from the buffer.
+//
+// Before it reads, however, it moves the head forward so as to be naturally
+// aligned with the byte-width of the integer it is reading.
+//
+// size must be a power of 2 <= 8.
+func (d *decoder) readUint(size int) uint64 {
+	d.head = align(d.head, size)
+	var val uint64
+	for i := d.head + size - 1; i >= d.head; i-- {
+		val <<= 8
+		val |= uint64(d.buffer[i])
+	}
+	d.head += size
+	return val
+}
+
+// unmarshalStructOrUnionInline unmarshals a struct or union inline based on Type t
+// into Value v, first aligning head to the alignment of the value.
+//
+// Expects the Type t and Value v to refer to a golang struct value, not a pointer.
+func (d *decoder) unmarshalStructOrUnionInline(t reflect.Type, v reflect.Value) error {
+	a, err := getPayloadAlignment(t, v)
+	if err != nil {
+		return err
+	}
+	d.head = align(d.head, a)
+	if isUnionType(t) {
+		err = d.unmarshalUnion(t, v, a)
+	} else {
+		err = d.unmarshalStructFields(t, v)
+	}
+	if err != nil {
+		return err
+	}
+	d.head = align(d.head, a)
+	return nil
+}
+
+// unmarshalStructOrUnionPointer unmarshals a pointer to a golang struct (i.e. a
+// nullable FIDL struct or union) into the Value v.
+//
+// Expects the Type t and Value v to refer to a pointer to a golang struct.
+func (d *decoder) unmarshalStructOrUnionPointer(t reflect.Type, v reflect.Value) error {
+	if d.readUint(8) == noAlloc {
+		v.Set(reflect.Zero(t))
+		return nil
+	}
+	// Create the new struct.
+	v.Set(reflect.New(t.Elem()))
+	et := t.Elem()
+	ev := v.Elem()
+
+	// Set up the out-of-line space and the head.
+	oldHead := d.head
+	d.head = d.nextObject
+	payload, err := structAsPayload(et, ev)
+	if err != nil {
+		return err
+	}
+	d.nextObject += align(payload.InlineSize(), 8)
+
+	// Unmarshal the value itself out-of-line.
+	if isUnionType(et) {
+		err = d.unmarshalUnion(et, ev, payload.InlineAlignment())
+	} else {
+		err = d.unmarshalStructFields(et, ev)
+	}
+	if err != nil {
+		return err
+	}
+
+	// Fix up head to the old head if it's a nullable struct.
+	d.head = oldHead
+	return nil
+}
+
+// unmarshalStructFields unmarshals the exported fields of the struct at d.head into
+// the Value v.
+//
+// Expects the Type t and Value v to refer to a struct value, not a pointer.
+func (d *decoder) unmarshalStructFields(t reflect.Type, v reflect.Value) error {
+	for i := 0; i < t.NumField(); i++ {
+		f := t.Field(i)
+		// If it's an unexported field, ignore it.
+		if f.PkgPath != "" {
+			continue
+		}
+		var n nestedTypeData
+		if err := n.FromTag(f.Tag); err != nil {
+			return err
+		}
+		if err := d.unmarshal(f.Type, v.Field(i), n); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+// unmarshalUnion unmarshals a FIDL union at d.head into the Value v (a golang
+// struct) without any external alignment.
+//
+// Expects the Type t and Value v to refer to a golang struct value, not a pointer.
+// The alignment field is used to align to the union's field before reading.
+func (d *decoder) unmarshalUnion(t reflect.Type, v reflect.Value, alignment int) error {
+	// Save the head for proper padding.
+	head := d.head
+	kind := d.readUint(4)
+
+	// Index into the fields of the struct, adding 1 for the tag.
+	fieldIndex := int(kind) + 1
+	if fieldIndex >= t.NumField() {
+		return ErrInvalidUnionTag
+	}
+	v.Field(0).SetUint(kind)
+
+	f := t.Field(fieldIndex)
+	var n nestedTypeData
+	if err := n.FromTag(f.Tag); err != nil {
+		return err
+	}
+	d.head = align(d.head, alignment)
+	if err := d.unmarshal(f.Type, v.Field(fieldIndex), n); err != nil {
+		return err
+	}
+	s, err := getPayloadSize(t, v)
+	if err != nil {
+		return err
+	}
+	d.head = head + s
+	return nil
+}
+
+// unmarshalArray unmarshals an array inline based on Type t into Value v, taking into account
+// nestedTypeData n, since an array is a container type.
+func (d *decoder) unmarshalArray(t reflect.Type, v reflect.Value, n nestedTypeData) error {
+	elemType := t.Elem()
+	for i := 0; i < t.Len(); i++ {
+		if err := d.unmarshal(elemType, v.Index(i), n); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+// unmarshalInline unmarshals a variety of types inline, or delegates to their types' specific
+// unmarshalling functions.
+func (d *decoder) unmarshalInline(t reflect.Type, v reflect.Value, n nestedTypeData) error {
+	switch t.Kind() {
+	case reflect.Array:
+		return d.unmarshalArray(t, v, n)
+	case reflect.Bool:
+		i := d.readUint(1)
+		switch i {
+		case 0:
+			v.SetBool(false)
+		case 1:
+			v.SetBool(true)
+		default:
+			return newValueError(ErrInvalidBoolValue, i)
+		}
+	case reflect.Int8:
+		v.SetInt(d.readInt(1))
+	case reflect.Int16:
+		v.SetInt(d.readInt(2))
+	case reflect.Int32:
+		v.SetInt(d.readInt(4))
+	case reflect.Int64:
+		v.SetInt(d.readInt(8))
+	case reflect.Uint8:
+		v.SetUint(d.readUint(1))
+	case reflect.Uint16:
+		v.SetUint(d.readUint(2))
+	case reflect.Uint32:
+		v.SetUint(d.readUint(4))
+	case reflect.Uint64:
+		v.SetUint(d.readUint(8))
+	case reflect.Float32:
+		v.SetFloat(float64(math.Float32frombits(uint32(d.readUint(4)))))
+	case reflect.Float64:
+		v.SetFloat(math.Float64frombits(d.readUint(8)))
+	case reflect.Struct:
+		return d.unmarshalStructOrUnionInline(t, v)
+	default:
+		return newValueError(ErrInvalidInlineType, t.Name())
+	}
+	return nil
+}
+
+// unmarshalVector unmarshals an out-of-line FIDL vector into a golang slice which is placed
+// into v. nestedTypeData is also necessary because a vector can have a maximum size). The
+// expected types and values are either pointers, i.e. *[]int8 or an "inline" vector value
+// i.e. []int8.
+func (d *decoder) unmarshalVector(t reflect.Type, v reflect.Value, n nestedTypeData) error {
+	size := int64(d.readUint(8))
+	if size < 0 {
+		return newExpectError(ErrVectorTooLong, math.MaxInt64, size)
+	}
+	if ptr := d.readUint(8); ptr == noAlloc {
+		if t.Kind() != reflect.Ptr {
+			return newValueError(ErrUnexpectedNullRef, "vector")
+		}
+		v.Set(reflect.Zero(t))
+		return nil
+	}
+	max := n.Unnest()
+	if max != nil && int(size) > *max {
+		return newExpectError(ErrVectorTooLong, *max, size)
+	}
+
+	// Create the slice with reflection.
+	sliceType := t
+	elemType := t.Elem()
+	if t.Kind() == reflect.Ptr {
+		sliceType = elemType
+		elemType = sliceType.Elem()
+	}
+	s := reflect.MakeSlice(sliceType, int(size), int(size))
+
+	// Unmarshal the out-of-line structure.
+	oldHead := d.head
+	d.head = d.nextObject
+	// TODO(mknyszek): Get rid of this extra reflect.New somehow.
+	elemSize, err := getSize(elemType, reflect.New(elemType).Elem())
+	if err != nil {
+		return err
+	}
+	d.nextObject += align(int(size)*elemSize, 8)
+	if elemType.Kind() == reflect.Uint8 {
+		copy(s.Bytes(), d.buffer[d.head:])
+	} else {
+		for i := 0; i < int(size); i++ {
+			if err := d.unmarshal(elemType, s.Index(i), n); err != nil {
+				return err
+			}
+		}
+	}
+	d.head = oldHead
+	if t.Kind() == reflect.Ptr {
+		v.Set(reflect.New(t.Elem()))
+		v.Elem().Set(s)
+	} else {
+		v.Set(s)
+	}
+	return nil
+}
+
+// unmarshalString unmarshals an out-of-line FIDL string into a golang string which is placed
+// into v. nestedTypeData is also necessary because it can have a maximum size). The expected
+// types and values are either pointers, i.e. *string or an "inline" string value. i.e. string.
+// This method uses whether or not the type is a golang pointer type to determine if it is
+// nullable.
+func (d *decoder) unmarshalString(t reflect.Type, v reflect.Value, n nestedTypeData) error {
+	size := int64(d.readUint(8))
+	if size < 0 {
+		return newExpectError(ErrStringTooLong, math.MaxInt64, size)
+	}
+	if ptr := d.readUint(8); ptr == noAlloc {
+		if t.Kind() != reflect.Ptr {
+			return newValueError(ErrUnexpectedNullRef, "string")
+		}
+		v.Set(reflect.Zero(t))
+		return nil
+	}
+	max := n.Unnest()
+	if max != nil && int(size) > *max {
+		return newExpectError(ErrStringTooLong, *max, size)
+	}
+	s := string(d.buffer[d.nextObject : d.nextObject+int(size)])
+	if t.Kind() == reflect.Ptr {
+		v.Set(reflect.New(t.Elem()))
+		v.Elem().Set(reflect.ValueOf(s))
+	} else {
+		v.Set(reflect.ValueOf(s))
+	}
+	d.nextObject += align(int(size), 8)
+	return nil
+}
+
+// unmarshalHandle unmarshals a handle into a value, validating that it is valid if the handle is
+// not nullable.
+func (d *decoder) unmarshalHandle(v reflect.Value, n nestedTypeData) error {
+	h := d.readUint(4)
+	switch h {
+	case uint64(noHandle):
+		if !n.nullable {
+			return ErrUnexpectedNullHandle
+		}
+		v.SetUint(uint64(zx.HandleInvalid))
+	case uint64(handlePresent):
+		if len(d.handles) == 0 {
+			return ErrNotEnoughHandles
+		}
+		v.SetUint(uint64(d.handles[0]))
+		d.handles = d.handles[1:]
+	default:
+		return newValueError(ErrBadHandleEncoding, h)
+	}
+	return nil
+}
+
+// unmarshalPointer unmarshals nullable FIDL types that are represented by golang pointer
+// indirections. The expected types and values t and v are pointers, i.e. they start with *.
+func (d *decoder) unmarshalPointer(t reflect.Type, v reflect.Value, n nestedTypeData) error {
+	switch t.Elem().Kind() {
+	case reflect.Slice:
+		return d.unmarshalVector(t, v, n)
+	case reflect.String:
+		return d.unmarshalString(t, v, n)
+	case reflect.Struct:
+		return d.unmarshalStructOrUnionPointer(t, v)
+	}
+	return newValueError(ErrInvalidPointerType, t.Name())
+}
+
+// unmarshal is the central recursive function core to unmarshalling, and
+// traverses the tree-like structure of the input type t. v represents
+// the value associated with the type t.
+func (d *decoder) unmarshal(t reflect.Type, v reflect.Value, n nestedTypeData) error {
+	switch t.Kind() {
+	case reflect.Ptr:
+		return d.unmarshalPointer(t, v, n)
+	case reflect.Slice:
+		return d.unmarshalVector(t, v, n)
+	case reflect.String:
+		return d.unmarshalString(t, v, n)
+	}
+	if isHandleType(t) {
+		return d.unmarshalHandle(v, n)
+	}
+	if isInterfaceType(t) || isInterfaceRequestType(t) {
+		// An interface is represented by a Proxy, whose first field is
+		// a zx.Channel, and we can just marshal that. Same goes for an
+		// interface request, which is just an InterfaceRequest whose
+		// first field is a zx.Channel.
+		return d.unmarshalHandle(v.Field(0), n)
+	}
+	return d.unmarshalInline(t, v, n)
+}
+
+// UnmarshalHeader parses a FIDL header in the data into m.
+func UnmarshalHeader(data []byte, m *MessageHeader) error {
+	if len(data) < 16 {
+		return ErrMessageTooSmall
+	}
+	d := decoder{buffer: data}
+	m.Txid = uint32(d.readUint(4))
+	m.Reserved = uint32(d.readUint(4))
+	m.Flags = uint32(d.readUint(4))
+	m.Ordinal = uint32(d.readUint(4))
+	return nil
+}
+
+// Unmarshal parses the encoded FIDL payload in data and handles, storing the
+// decoded payload in s.
+//
+// The value pointed to by s must be a pointer to a golang struct which represents
+// the decoded primary object of a FIDL message. The data decode process is guided
+// by the structure of the struct pointed to by s.
+//
+// TODO(mknyszek): More rigorously validate the input.
+func Unmarshal(data []byte, handles []zx.Handle, s Payload) error {
+	// First, let's make sure we have the right type in s.
+	t := reflect.TypeOf(s)
+	if t.Kind() != reflect.Ptr {
+		return errors.New("expected a pointer")
+	}
+	t = t.Elem()
+	if t.Kind() != reflect.Struct {
+		return errors.New("primary object must be a struct")
+	}
+
+	// Get the payload's value and unmarshal it.
+	nextObject := align(s.InlineSize(), 8)
+	d := decoder{
+		buffer:     data,
+		handles:    handles,
+		nextObject: nextObject,
+	}
+	return d.unmarshalStructFields(t, reflect.ValueOf(s).Elem())
+}
diff --git a/src/syscall/zx/fidl/encoding_test.go b/src/syscall/zx/fidl/encoding_test.go
new file mode 100644
index 0000000..41af868
--- /dev/null
+++ b/src/syscall/zx/fidl/encoding_test.go
@@ -0,0 +1,188 @@
+// Copyright 2018 The Go 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 fuchsia
+
+package fidl_test
+
+import (
+	"reflect"
+	"syscall/zx"
+	"testing"
+
+	. "fidl/bindings"
+	. "fuchsia/go/go_fidl_bindings_test"
+)
+
+func testIdentity(t *testing.T, input Payload, expectSize int, output Payload) {
+	var respb [zx.ChannelMaxMessageBytes]byte
+	var resph [zx.ChannelMaxMessageHandles]zx.Handle
+	nb, nh, err := Marshal(input, respb[:], resph[:])
+	if err != nil {
+		t.Fatal(err)
+	}
+	if nb != expectSize {
+		t.Fatalf("expected size %d but got %d: %v", expectSize, nb, respb[:nb])
+	}
+	if err := Unmarshal(respb[:nb], resph[:nh], output); err != nil {
+		t.Fatal(err)
+	}
+	if !reflect.DeepEqual(input, output) {
+		t.Fatalf("expected: %v, got: %v", input, output)
+	}
+}
+
+func TestEncodingIdentity(t *testing.T) {
+	t.Run("Header", func(t *testing.T) {
+		var buf [MessageHeaderSize]byte
+		m := MessageHeader{
+			Txid:     1215,
+			Reserved: 0,
+			Flags:    111111,
+			Ordinal:  889,
+		}
+		MarshalHeader(&m, buf[:])
+
+		var header MessageHeader
+		if err := UnmarshalHeader(buf[:], &header); err != nil {
+			t.Fatal(err)
+		}
+		if m != header {
+			t.Fatalf("expected: %v, got: %v", m, header)
+		}
+	})
+	t.Run("Simple", func(t *testing.T) {
+		testIdentity(t, &TestSimple{X: 124}, 8, &TestSimple{})
+		testIdentity(t, &TestSimpleBool{X: true}, 8, &TestSimpleBool{})
+	})
+	t.Run("Alignment", func(t *testing.T) {
+		testIdentity(t, &TestAlignment1{X: -36, Y: -10, Z: 51}, 8, &TestAlignment1{})
+		testIdentity(t, &TestAlignment2{
+			A: 1212141,
+			B: 908935,
+			C: -1,
+			D: 125,
+			E: -22,
+			F: 111,
+			G: 1515,
+			H: 65535,
+			I: 1515,
+		}, 24, &TestAlignment2{})
+	})
+	t.Run("Floats", func(t *testing.T) {
+		testIdentity(t, &TestFloat1{A: -36.0}, 8, &TestFloat1{})
+		testIdentity(t, &TestFloat2{A: -1254918271.0}, 8, &TestFloat2{})
+		testIdentity(t, &TestFloat3{A: 1241.1, B: 0.2141, C: 20, D: 0.0}, 32, &TestFloat3{})
+	})
+	t.Run("Arrays", func(t *testing.T) {
+		testIdentity(t, &TestArray1{A: [5]int8{1, 77, 2, 4, 5}}, 8, &TestArray1{})
+		testIdentity(t, &TestArray2{A: -1.0, B: [1]float32{0.2}}, 16, &TestArray2{})
+		testIdentity(t, &TestArray3{
+			A: -999,
+			B: [3]uint16{11, 12, 13},
+			C: 1021,
+		}, 24, &TestArray3{})
+		testIdentity(t, &TestArray4{
+			A: [9]bool{true, false, false, true, false, true, true, true, true},
+		}, 16, &TestArray4{})
+	})
+	t.Run("Strings", func(t *testing.T) {
+		testIdentity(t, &TestString1{A: "str", B: nil}, 40, &TestString1{})
+		testIdentity(t, &TestString2{A: [2]string{"hello", "g"}}, 48, &TestString2{})
+		s := "bye"
+		testIdentity(t, &TestString3{
+			A: [2]string{"boop", "g"},
+			B: [2]*string{&s, nil},
+		}, 88, &TestString3{})
+	})
+	t.Run("Vectors", func(t *testing.T) {
+		v1 := []int64{-1}
+		testIdentity(t, &TestVector1{
+			A: []int8{1, 2, 3, 4},
+			B: nil,
+			C: []int32{99},
+			D: &v1,
+		}, 88, &TestVector1{})
+		v2 := []string{"x", "hello"}
+		testIdentity(t, &TestVector2{
+			A: [2][]int8{{9, -1}, {}},
+			B: [][]int8{{-111, 41}, {-1, -1, -1, -1}},
+			C: []*[]string{nil, &v2},
+		}, 200, &TestVector2{})
+	})
+	t.Run("Structs", func(t *testing.T) {
+		testIdentity(t, &TestStruct1{
+			A: TestSimple{
+				X: -9999,
+			},
+			B: &TestSimple{
+				X: 1254125,
+			},
+		}, 24, &TestStruct1{})
+		v1 := []int64{101010}
+		testIdentity(t, &TestStruct2{
+			A: TestArray1{
+				A: [5]int8{1, 77, 2, 4, 5},
+			},
+			B: TestFloat1{
+				A: 2.81212,
+			},
+			C: TestVector1{
+				A: []int8{1, 2, 3, 4},
+				B: nil,
+				C: []int32{99},
+				D: &v1,
+			},
+			D: &TestString1{
+				A: "str",
+				B: nil,
+			},
+		}, 152, &TestStruct2{})
+	})
+	t.Run("Unions", func(t *testing.T) {
+		u1 := Union1{}
+		u1.SetB(TestSimple{X: 555})
+		testIdentity(t, &TestUnion1{
+			A: u1,
+			B: nil,
+		}, 24, &TestUnion1{})
+		testIdentity(t, &TestUnion2{
+			A: []Union1{u1, u1, u1},
+			B: []*Union1{&u1, nil, nil},
+		}, 120, &TestUnion2{})
+	})
+	t.Run("Handles", func(t *testing.T) {
+		vmo, err := zx.NewVMO(10, 0)
+		if err != nil {
+			t.Fatalf("failed to create vmo: %v", err)
+		}
+		testIdentity(t, &TestHandle1{
+			A: zx.Handle(22),
+			B: zx.HandleInvalid,
+			C: vmo,
+			D: zx.VMO(zx.HandleInvalid),
+		}, 16, &TestHandle1{})
+		testIdentity(t, &TestHandle2{
+			A: []zx.Handle{zx.Handle(vmo)},
+			B: []zx.VMO{zx.VMO(zx.HandleInvalid)},
+		}, 48, &TestHandle2{})
+		vmo.Close()
+	})
+	t.Run("Interfaces", func(t *testing.T) {
+		h0, h1, err := zx.NewChannel(0)
+		defer h0.Close()
+		defer h1.Close()
+		if err != nil {
+			t.Fatalf("failed to create vmo: %v", err)
+		}
+		testIdentity(t, &TestInterface1{
+			A: Test1Interface(Proxy{Channel: h0}),
+			B: Test1Interface(Proxy{Channel: zx.Channel(zx.HandleInvalid)}),
+			C: Test1InterfaceRequest(InterfaceRequest{Channel: h1}),
+			D: Test1InterfaceRequest(InterfaceRequest{
+				Channel: zx.Channel(zx.HandleInvalid),
+			}),
+		}, 16, &TestInterface1{})
+	})
+}
diff --git a/src/syscall/zx/fidl/errors.go b/src/syscall/zx/fidl/errors.go
new file mode 100644
index 0000000..17f7e8f
--- /dev/null
+++ b/src/syscall/zx/fidl/errors.go
@@ -0,0 +1,149 @@
+// Copyright 2018 The Go 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 fuchsia
+
+package fidl
+
+import (
+	"reflect"
+	"strconv"
+)
+
+// ValidationError represents an error produced in validating a FIDL structure.
+type ValidationError interface {
+	error
+
+	// Code returns the underlying ErrorCode value, which all ValidationErrors
+	// must have.
+	Code() ErrorCode
+}
+
+// ErrorCode represents a set of machine-readable error codes each ValidationError
+// has.
+type ErrorCode uint32
+
+const (
+	ErrUnknownOrdinal ErrorCode = iota
+	ErrInvalidInlineType
+	ErrInvalidPointerType
+	ErrVectorTooLong
+	ErrStringTooLong
+	ErrUnexpectedOrdinal
+	ErrUnexpectedNullHandle
+	ErrUnexpectedNullRef
+	ErrInvalidBoolValue
+	ErrNotEnoughHandles
+	ErrBadHandleEncoding
+	ErrBadRefEncoding
+	ErrMessageTooSmall
+	ErrStructIsNotPayload
+	ErrInvalidUnionTag
+)
+
+// Error implements error for ErrorCode
+func (e ErrorCode) Error() string {
+	switch e {
+	case ErrUnknownOrdinal:
+		return "unknown ordinal"
+	case ErrInvalidInlineType:
+		return "invalid inline type"
+	case ErrInvalidPointerType:
+		return "invalid pointer type"
+	case ErrVectorTooLong:
+		return "vector exceeds maximum size"
+	case ErrStringTooLong:
+		return "string exceeds maximum size"
+	case ErrUnexpectedOrdinal:
+		return "unexpected ordinal"
+	case ErrUnexpectedNullHandle:
+		return "unexpected null handle"
+	case ErrUnexpectedNullRef:
+		return "unexpected null reference"
+	case ErrInvalidBoolValue:
+		return "unexpected boolean value"
+	case ErrNotEnoughHandles:
+		return "not enough handles"
+	case ErrBadHandleEncoding:
+		return "bad encoding for handle"
+	case ErrBadRefEncoding:
+		return "bad encoding for ref"
+	case ErrMessageTooSmall:
+		return "message too small to have FIDL header"
+	case ErrStructIsNotPayload:
+		return "golang struct type must implement Payload"
+	default:
+		return "unknown error code"
+	}
+}
+
+// Code implements the ValidationError interface.
+func (e ErrorCode) Code() ErrorCode {
+	return e
+}
+
+// stringer is an interface for types for which a string representation
+// may be derived.
+type stringer interface {
+	String() string
+}
+
+// toString generates the string representation for a limited set of types.
+func toString(value interface{}) string {
+	if e, ok := value.(error); ok {
+		return e.Error()
+	}
+	if s, ok := value.(stringer); ok {
+		return s.String()
+	}
+	t := reflect.TypeOf(value)
+	switch t.Kind() {
+	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+		return strconv.FormatInt(reflect.ValueOf(value).Int(), 10)
+	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+		return strconv.FormatUint(reflect.ValueOf(value).Uint(), 10)
+	case reflect.String:
+		return value.(string)
+	default:
+		return "##BADVALUE##"
+	}
+}
+
+// valueError represents an error that refers to a single value.
+type valueError struct {
+	ErrorCode
+	value interface{}
+}
+
+func newValueError(code ErrorCode, value interface{}) valueError {
+	return valueError{
+		ErrorCode: code,
+		value:     value,
+	}
+}
+
+func (e valueError) Error() string {
+	return e.ErrorCode.Error() + ": " + toString(e.value)
+}
+
+// expectError represents an error that refers to the expectation of a
+// certain value, and displays a comparison between the actual value and
+// the expected value.
+type expectError struct {
+	ErrorCode
+	expect interface{}
+	actual interface{}
+}
+
+func newExpectError(code ErrorCode, expect, actual interface{}) expectError {
+	return expectError{
+		ErrorCode: code,
+		expect:    expect,
+		actual:    actual,
+	}
+}
+
+func (e expectError) Error() string {
+	return e.ErrorCode.Error() + ": expected " + toString(e.expect) + ", got " + toString(e.actual)
+}
diff --git a/src/syscall/zx/fidl/interface.go b/src/syscall/zx/fidl/interface.go
new file mode 100644
index 0000000..e46f959
--- /dev/null
+++ b/src/syscall/zx/fidl/interface.go
@@ -0,0 +1,163 @@
+// Copyright 2018 The Go 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 fuchsia
+
+package fidl
+
+import (
+	"syscall/zx"
+	"syscall/zx/zxwait"
+)
+
+// ServiceRequest is an abstraction over a FIDL interface request which is
+// intended to be used as part of service discovery.
+type ServiceRequest interface {
+	// Name returns the name of the service being requested.
+	Name() string
+
+	// ToChannel returns the underlying channel of the ServiceRequest.
+	ToChannel() zx.Channel
+}
+
+// InterfaceRequest is a wrapper type around a channel and represents the server side
+// of a FIDL interface, to be sent to a server as a request.
+type InterfaceRequest struct {
+	zx.Channel
+}
+
+// NewInterfaceRequest generates two sides of a channel with one layer of
+// type casts out of the way to minimize the amount of generated code. Semantically,
+// the two sides of the channel represent the interface request and the client
+// side of the interface (the proxy). It returns an error on failure.
+func NewInterfaceRequest() (InterfaceRequest, *Proxy, error) {
+	h0, h1, err := zx.NewChannel(0)
+	if err != nil {
+		return InterfaceRequest{}, nil, err
+	}
+	return InterfaceRequest{Channel: h0}, &Proxy{Channel: h1}, nil
+}
+
+// Proxy represents the client side of a FIDL interface.
+type Proxy struct {
+	// Channel is the underlying channel endpoint for this interface.
+	zx.Channel
+}
+
+// IsValid returns true if the underlying channel is a valid handle.
+func (p Proxy) IsValid() bool {
+	h := zx.Handle(p.Channel)
+	return h.IsValid()
+}
+
+// Send sends the request payload over the channel with the specified ordinal
+// without a response.
+func (p *Proxy) Send(ordinal uint32, req Payload) error {
+	respb := messageBytesPool.Get().([]byte)
+	resph := messageHandlesPool.Get().([]zx.Handle)
+
+	defer messageBytesPool.Put(respb)
+	defer messageHandlesPool.Put(resph)
+
+	// Marshal the message into the buffer.
+	header := MessageHeader{
+		Txid:    0, // Txid == 0 for messages without a response.
+		Ordinal: ordinal,
+	}
+	nb, nh, err := MarshalMessage(&header, req, respb[:], resph[:])
+	if err != nil {
+		return err
+	}
+
+	// Write the encoded bytes to the channel.
+	return p.Channel.Write(respb[:nb], resph[:nh], 0)
+}
+
+// Recv waits for an event and writes the response into the response payload.
+func (p *Proxy) Recv(ordinal uint32, resp Payload) error {
+	respb := messageBytesPool.Get().([]byte)
+	resph := messageHandlesPool.Get().([]zx.Handle)
+
+	defer messageBytesPool.Put(respb)
+	defer messageHandlesPool.Put(resph)
+
+	// Wait on the channel to be readable or close.
+	h := zx.Handle(p.Channel)
+	sigs, err := zxwait.Wait(h,
+		zx.SignalChannelReadable|zx.SignalChannelPeerClosed,
+		zx.TimensecInfinite,
+	)
+	if err != nil {
+		return err
+	}
+	// If it is closed and not readable, let's just report that and stop here.
+	if (sigs&zx.SignalChannelPeerClosed) != 0 && (sigs&zx.SignalChannelReadable) == 0 {
+		return &zx.Error{Status: zx.ErrPeerClosed}
+	}
+	// Otherwise, now we can read!
+	nb, nh, err := p.Channel.Read(respb[:], resph[:], 0)
+	if err != nil {
+		return err
+	}
+
+	// Unmarshal the message.
+	var header MessageHeader
+	if err := UnmarshalMessage(respb[:nb], resph[:nh], &header, resp); err != nil {
+		return err
+	}
+	if header.Ordinal != ordinal {
+		return newExpectError(ErrUnexpectedOrdinal, ordinal, header.Ordinal)
+	}
+	return nil
+}
+
+// Call sends the request payload over the channel with the specified ordinal
+// and synchronously waits for a response. It then writes the response into the
+// response payload.
+func (p *Proxy) Call(ordinal uint32, req Payload, resp Payload) error {
+	respb := messageBytesPool.Get().([]byte)
+	resph := messageHandlesPool.Get().([]zx.Handle)
+
+	defer messageBytesPool.Put(respb)
+	defer messageHandlesPool.Put(resph)
+
+	// Marshal the message into the buffer
+	header := MessageHeader{
+		Ordinal: ordinal,
+	}
+	nb, nh, err := MarshalMessage(&header, req, respb[:], resph[:])
+	if err != nil {
+		return err
+	}
+
+	// Make the IPC call.
+	cnb, cnh, err := p.Channel.Call(0, zx.TimensecInfinite, respb[:nb], resph[:nh], respb[:], resph[:])
+	if err != nil {
+		return err
+	}
+
+	// Unmarshal the message.
+	if err := UnmarshalMessage(respb[:cnb], resph[:cnh], &header, resp); err != nil {
+		return err
+	}
+	if header.Ordinal != ordinal {
+		return newExpectError(ErrUnexpectedOrdinal, ordinal, header.Ordinal)
+	}
+	return nil
+}
+
+// Stub represents a generated type which wraps the server-side implementation of a
+// FIDL interface.
+//
+// It contains logic which is able to dispatch into the correct implementation given
+// the incoming message ordinal and its data.
+type Stub interface {
+	// Dispatch dispatches into the appropriate method implementation for a FIDL
+	// interface by using the ordinal.
+	//
+	// It also takes the data as bytes and transforms it into arguments usable by
+	// the method implementation. It then optionally returns a response if the
+	// method has a response.
+	Dispatch(ordinal uint32, bytes []byte, handles []zx.Handle) (Payload, error)
+}
diff --git a/src/syscall/zx/fidl/message.go b/src/syscall/zx/fidl/message.go
new file mode 100644
index 0000000..d2417df
--- /dev/null
+++ b/src/syscall/zx/fidl/message.go
@@ -0,0 +1,68 @@
+// Copyright 2018 The Go 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 fuchsia
+
+package fidl
+
+import (
+	"sync"
+
+	"syscall/zx"
+)
+
+// messageBytesPool is a pool of buffers that can fit the data part of any
+// FIDL message.
+var messageBytesPool = sync.Pool{
+	New: func() interface{} {
+		return make([]byte, zx.ChannelMaxMessageBytes)
+	},
+}
+
+// messageHandlesPool is a pool of buffers that can fit the handles part of
+// any FIDL message.
+var messageHandlesPool = sync.Pool{
+	New: func() interface{} {
+		return make([]zx.Handle, zx.ChannelMaxMessageHandles)
+	},
+}
+
+// MessageHeaderSize is the size of the encoded message header.
+const MessageHeaderSize int = 16
+
+// MessageHeader is a header information for a message. This struct
+// corresponds to the C type fidl_message_header_t.
+type MessageHeader struct {
+	Txid     uint32
+	Reserved uint32
+	Flags    uint32
+	Ordinal  uint32
+}
+
+// Payload is an interface implemented by every FIDL structure.
+type Payload interface {
+	// InlineSize returns the inline size of the structure, without any
+	// out-of-line structures.
+	InlineSize() int
+
+	// InlineAlignment returns the alignment of the structure.
+	InlineAlignment() int
+}
+
+// MarshalMessage is a convenience function for marshalling a full FIDL message,
+// that is, header and payload.
+func MarshalMessage(header *MessageHeader, s Payload, data []byte, handles []zx.Handle) (int, int, error) {
+	MarshalHeader(header, data[:MessageHeaderSize])
+	nb, nh, err := Marshal(s, data[MessageHeaderSize:], handles[:])
+	return nb + MessageHeaderSize, nh, err
+}
+
+// UnmarshalMessage is a convenience function for unmarshalling a full FIDL message,
+// that is, header and payload.
+func UnmarshalMessage(data []byte, handles []zx.Handle, header *MessageHeader, s Payload) error {
+	if err := UnmarshalHeader(data[:MessageHeaderSize], header); err != nil {
+		return err
+	}
+	return Unmarshal(data[MessageHeaderSize:], handles[:], s)
+}
diff --git a/src/syscall/zx/handle.go b/src/syscall/zx/handle.go
new file mode 100644
index 0000000..8731eee
--- /dev/null
+++ b/src/syscall/zx/handle.go
@@ -0,0 +1,574 @@
+// Copyright 2016 The Go 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 fuchsia
+
+package zx
+
+import "unsafe"
+
+// Process-wide FDIO handles.
+var (
+	StdioHandles     [3][3]Handle // 3 stdio files, each with up to 3 (fdio.MaxHandles) handles
+	StdioHandleTypes [3]int
+	CwdHandle        Handle
+	ProcHandle       Handle
+	VMARRoot         VMAR
+	RootNSMap        map[string]Handle
+)
+
+const ZX_CPRNG_DRAW_MAX_LEN = 256
+
+type HandleInfo uint32
+
+func NewHandleInfo(t, arg uint32) HandleInfo {
+	return HandleInfo((t & 0xFFFF) | ((arg & 0xFFFF) << 16))
+}
+
+func (hi HandleInfo) Type() uint32 {
+	return uint32(hi) & 0xFFFF
+}
+
+func (hi HandleInfo) Arg() uint32 {
+	return (uint32(hi) >> 16) & 0xFFFF
+}
+
+type Socket Handle
+
+func (s *Socket) Handle() *Handle {
+	return (*Handle)(s)
+}
+
+func (s *Socket) Read(data []byte, flags uint32) (n int, err error) {
+	var actual uint
+	var p unsafe.Pointer
+	if len(data) > 0 {
+		p = unsafe.Pointer(&data[0])
+	}
+	status := sys_socket_read(Handle(*s), flags, p, uint(len(data)), &actual)
+	if status != ErrOk {
+		return int(actual), Error{Status: status, Text: "zx.Socket.Read"}
+	}
+	return int(actual), nil
+}
+
+func (s *Socket) Write(data []byte, flags uint32) (n int, err error) {
+	var p unsafe.Pointer
+	if len(data) > 0 {
+		p = unsafe.Pointer(&data[0])
+	}
+	var actual uint
+	status := sys_socket_write(Handle(*s), flags, p, uint(len(data)), &actual)
+	if status != ErrOk {
+		return int(actual), Error{Status: status, Text: "zx.Socket.Write"}
+	}
+	return int(actual), nil
+}
+
+func (s *Socket) Share(h Handle) error {
+	if status := sys_socket_share(Handle(*s), h); status != ErrOk {
+		return Error{Status: status, Text: "zx.Socket.Share"}
+	}
+	return nil
+}
+
+func (s *Socket) Accept(h *Handle) error {
+	if status := sys_socket_accept(Handle(*s), h); status != ErrOk {
+		return Error{Status: status, Text: "zx.Socket.Accept"}
+	}
+	return nil
+}
+
+func (s *Socket) Close() error {
+	h := Handle(*s)
+	err := h.Close()
+	*s = Socket(HandleInvalid)
+	return err
+}
+
+func NewSocket(flags uint32) (s0, s1 Socket, err error) {
+	var h0, h1 Handle
+	if status := sys_socket_create(flags, &h0, &h1); status != ErrOk {
+		return Socket(HandleInvalid), Socket(HandleInvalid), Error{Status: status, Text: "zx.Socket"}
+	}
+	return Socket(h0), Socket(h1), nil
+}
+
+type Event Handle
+
+func NewEvent(options uint32) (e Event, err error) {
+	var h Handle
+	if status := Sys_event_create(options, &h); status != ErrOk {
+		return Event(HandleInvalid), Error{Status: status, Text: "zx.Event"}
+	}
+	return Event(h), nil
+}
+
+func (e *Event) Handle() *Handle {
+	return (*Handle)(e)
+}
+
+func (e *Event) Close() error {
+	h := Handle(*e)
+	err := h.Close()
+	*e = Event(HandleInvalid)
+	return err
+}
+
+func (e *Event) Duplicate(rights Rights) (Event, error) {
+	h := Handle(*e)
+	h, err := h.Duplicate(rights)
+	if err != nil {
+		return Event(HandleInvalid), err
+	}
+	return Event(h), nil
+}
+
+func (h *Handle) Close() error {
+	if status := Sys_handle_close(*h); status != ErrOk {
+		return Error{Status: status, Text: "zx.Handle.Close"}
+	}
+	*h = HandleInvalid
+	return nil
+}
+
+func (h *Handle) Duplicate(rights Rights) (Handle, error) {
+	var dup Handle
+	if status := sys_handle_duplicate(*h, rights, &dup); status != ErrOk {
+		return HandleInvalid, Error{Status: status, Text: "zx.Handle.Duplicate"}
+	}
+	return dup, nil
+}
+
+func (h *Handle) Signal(clearMask, setMask Signals) error {
+	if status := Sys_object_signal(*h, uint32(clearMask), uint32(setMask)); status != ErrOk {
+		return Error{Status: status, Text: "zx.Handle.Signal"}
+	}
+	return nil
+}
+
+func (h *Handle) SignalPeer(clearMask, setMask Signals) error {
+	if status := Sys_object_signal_peer(*h, uint32(clearMask), uint32(setMask)); status != ErrOk {
+		return Error{Status: status, Text: "zx.Handle.SignalPeer"}
+	}
+	return nil
+}
+
+func (h *Handle) SetCookie(scope Handle, cookie uint64) error {
+	if status := Sys_object_set_cookie(*h, scope, cookie); status != ErrOk {
+		return Error{Status: status, Text: "zx.Handle.SetCookie"}
+	}
+	return nil
+}
+
+func (h *Handle) GetCookie(scope Handle) (uint64, error) {
+	var cookie uint64
+	if status := Sys_object_get_cookie(*h, scope, &cookie); status != ErrOk {
+		return 0, Error{Status: status, Text: "zx.Handle.GetCookie"}
+	}
+	return cookie, nil
+}
+
+func (h *Handle) GetProperty(property uint32, data []byte) error {
+	var numBytes = uint(len(data))
+	var dataPtr unsafe.Pointer
+	if numBytes > 0 {
+		dataPtr = unsafe.Pointer(&data[0])
+	}
+	if status := Sys_object_get_property(*h, property, dataPtr, numBytes); status != ErrOk {
+		return Error{Status: status, Text: "zx.Handle.GetProperty"}
+	}
+	return nil
+}
+
+func (h *Handle) SetProperty(property uint32, data []byte) error {
+	var numBytes = uint(len(data))
+	var dataPtr unsafe.Pointer
+	if numBytes > 0 {
+		dataPtr = unsafe.Pointer(&data[0])
+	}
+	if status := Sys_object_set_property(*h, property, dataPtr, numBytes); status != ErrOk {
+		return Error{Status: status, Text: "zx.Handle.SetProperty"}
+	}
+	return nil
+}
+
+func (h *Handle) IsValid() bool {
+	return *h > HandleInvalid
+}
+
+func WaitMany(items []WaitItem, timeout Time) error {
+	if status := sys_object_wait_many(&items[0], uint(len(items)), timeout); status != ErrOk {
+		return Error{Status: status, Text: "zx.Handle.WaitMany"}
+	}
+	return nil
+}
+
+const (
+	ChannelMaxMessageBytes   = 65536
+	ChannelMaxMessageHandles = 64
+)
+
+type Channel Handle
+
+func (c *Channel) Handle() *Handle {
+	return (*Handle)(c)
+}
+
+func (c *Channel) Close() error {
+	h := Handle(*c)
+	err := h.Close()
+	*c = Channel(HandleInvalid)
+	return err
+}
+
+func (c *Channel) Read(data []byte, handles []Handle, flags uint32) (numBytes, numHandles uint32, err error) {
+	numBytes = uint32(len(data))
+	numHandles = uint32(len(handles))
+	var dataPtr unsafe.Pointer
+	if len(data) > 0 {
+		dataPtr = unsafe.Pointer(&data[0])
+	}
+	var handlePtr *Handle
+	if len(handles) > 0 {
+		handlePtr = &handles[0]
+	}
+	if status := sys_channel_read(Handle(*c), flags, dataPtr, handlePtr, numBytes, numHandles, &numBytes, &numHandles); status != ErrOk {
+		err = Error{Status: status, Text: "zx.Channel.Read"}
+	}
+	return numBytes, numHandles, err
+}
+
+func (c *Channel) Write(data []byte, handles []Handle, flags uint32) error {
+	var dataPtr unsafe.Pointer
+	if len(data) > 0 {
+		dataPtr = unsafe.Pointer(&data[0])
+	}
+	var handlePtr *Handle
+	if len(handles) > 0 {
+		handlePtr = &handles[0]
+	}
+	status := sys_channel_write(Handle(*c), flags, dataPtr, uint32(len(data)), handlePtr, uint32(len(handles)))
+	if status != ErrOk {
+		return Error{Status: status, Text: "zx.Channel.Write"}
+	}
+	return nil
+}
+
+func (c *Channel) Call(flags uint32, deadline Time, wData []byte, wHandles []Handle, rData []byte, rHandles []Handle) (actualBytes, actualHandles uint32, err error) {
+	var writeDataPtr uintptr
+	if len(wData) > 0 {
+		writeDataPtr = uintptr(unsafe.Pointer(&wData[0]))
+	}
+	var writeHandlePtr *Handle
+	if len(wHandles) > 0 {
+		writeHandlePtr = &wHandles[0]
+	}
+	var readDataPtr uintptr
+	if len(rData) > 0 {
+		readDataPtr = uintptr(unsafe.Pointer(&rData[0]))
+	}
+	var readHandlePtr *Handle
+	if len(rHandles) > 0 {
+		readHandlePtr = &rHandles[0]
+	}
+	args := &ChannelCallArgs{
+		WriteBytes:      writeDataPtr,
+		WriteHandles:    writeHandlePtr,
+		ReadBytes:       readDataPtr,
+		ReadHandles:     readHandlePtr,
+		WriteNumBytes:   uint32(len(wData)),
+		WriteNumHandles: uint32(len(wHandles)),
+		ReadNumBytes:    uint32(len(rData)),
+		ReadNumHandles:  uint32(len(rHandles)),
+	}
+
+	status := Sys_channel_call(Handle(*c), flags, deadline, args, &actualBytes, &actualHandles)
+	if status != ErrOk {
+		err = Error{Status: status, Text: "zx.Channel.Call"}
+	}
+	return actualBytes, actualHandles, err
+}
+
+func NewChannel(flags uint32) (c0, c1 Channel, err error) {
+	var h0, h1 Handle
+	if status := sys_channel_create(flags, &h0, &h1); status != ErrOk {
+		return Channel(HandleInvalid), Channel(HandleInvalid), Error{Status: status, Text: "zx.Channel"}
+	}
+	return Channel(h0), Channel(h1), nil
+}
+
+const (
+	PortWaitAsyncOnce = iota
+	PortWaitAsyncRepeating
+)
+
+const (
+	PortPacketTypeUser = iota
+	PortPacketTypeSignalOne
+	PortPacketTypeSignalRepeating
+)
+
+const (
+	PacketHeaderSize = uint(unsafe.Sizeof(PacketHeader{}))
+	PacketMaxSize    = uint(unsafe.Sizeof(Packet{}))
+)
+
+type PacketHeader struct {
+	Key   uint64
+	Type  uint32
+	Extra uint32
+}
+
+// Packet describes the unit of communication via an FDIO protocol
+type Packet struct {
+	Hdr   PacketHeader
+	Bytes [32]uint8
+}
+
+func (p *Packet) Signal() *PacketSignal {
+	return (*PacketSignal)(unsafe.Pointer(p))
+}
+
+type PortPacket interface {
+	Header() *PacketHeader
+	Length() int
+}
+
+// PacketSignal describes packets of type PortPacketTypeSignal
+type PacketSignal struct {
+	Hdr      PacketHeader
+	Trigger  Signals
+	Observed Signals
+	Count    uint64
+}
+
+func (s *PacketSignal) Header() *PacketHeader {
+	return &s.Hdr
+}
+
+func (s *PacketSignal) Length() int {
+	return int(unsafe.Sizeof(*s))
+}
+
+type Port Handle
+
+func (p *Port) Handle() *Handle {
+	return (*Handle)(p)
+}
+
+func (p *Port) Close() error {
+	h := Handle(*p)
+	err := h.Close()
+	*p = Port(HandleInvalid)
+	return err
+}
+
+// Queue a PortPacket, which may have a varying size.
+func (p *Port) Queue(packet PortPacket) error {
+	if status := Sys_port_queue(Handle(*p), (*int)(unsafe.Pointer(packet.Header()))); status != ErrOk {
+		return Error{Status: status, Text: "zx.Port.Queue"}
+	}
+	return nil
+}
+
+// Wait for a Packet, which must be as large as the largest
+// possible packet that may be received.
+func (p *Port) Wait(packet *Packet, deadline Time) error {
+	if status := Sys_port_wait(Handle(*p), deadline, (*int)(unsafe.Pointer(packet))); status != ErrOk {
+		return Error{Status: status, Text: "zx.Port.Wait"}
+	}
+	return nil
+}
+
+func (p *Port) Cancel(source Handle, key uint64) error {
+	if status := Sys_port_cancel(Handle(*p), source, key); status != ErrOk {
+		return Error{Status: status, Text: "zx.Port.Cancel"}
+	}
+	return nil
+}
+
+func (p *Port) WaitAsync(handle Handle, key uint64, signals Signals, options uint32) error {
+	if status := Sys_object_wait_async(handle, Handle(*p), key, signals, options); status != ErrOk {
+		return Error{Status: status, Text: "fdio.Port.WaitAsync"}
+	}
+	return nil
+}
+
+func NewPort(options uint32) (Port, error) {
+	var h Handle
+	if status := Sys_port_create(options, &h); status != ErrOk {
+		return Port(HandleInvalid), Error{Status: status, Text: "zx.Port"}
+	}
+	return Port(h), nil
+}
+
+type VMO Handle
+
+func (vmo *VMO) Handle() *Handle {
+	return (*Handle)(vmo)
+}
+
+func (vmo *VMO) Clone(options uint32, offset, size uint64) (VMO, error) {
+	var h Handle
+	if status := Sys_vmo_clone(Handle(*vmo), options, offset, size, &h); status != ErrOk {
+		return VMO(HandleInvalid), Error{Status: status, Text: "zx.VMO.Clone"}
+	}
+	return VMO(h), nil
+}
+
+func (vmo *VMO) Read(b []byte, offset uint64) error {
+	if status := sys_vmo_read(Handle(*vmo), unsafe.Pointer(&b[0]), offset, uint(len(b))); status != ErrOk {
+		return Error{Status: status, Text: "zx.VMO.Read"}
+	}
+	return nil
+}
+
+func (vmo *VMO) Write(b []byte, offset uint64) error {
+	if status := sys_vmo_write(Handle(*vmo), unsafe.Pointer(&b[0]), offset, uint(len(b))); status != ErrOk {
+		return Error{Status: status, Text: "zx.VMO.Write"}
+	}
+	return nil
+}
+
+func (vmo *VMO) Size() (uint64, error) {
+	var size uint64
+	if status := sys_vmo_get_size(Handle(*vmo), &size); status != ErrOk {
+		return size, Error{Status: status, Text: "zx.VMO.Size"}
+	}
+	return size, nil
+}
+
+func (vmo *VMO) SetSize(size uint64) error {
+	if status := sys_vmo_set_size(Handle(*vmo), size); status != ErrOk {
+		return Error{Status: status, Text: "zx.VMO.SetSize"}
+	}
+	return nil
+}
+
+func (vmo *VMO) OpRange(op uint32, offset, size uint64, b []byte) error {
+	if status := sys_vmo_op_range(Handle(*vmo), op, offset, size, unsafe.Pointer(&b[0]), uint(len(b))); status != ErrOk {
+		return Error{Status: status, Text: "zx.VMO.OpRange"}
+	}
+	return nil
+}
+
+func (vmo *VMO) Close() error {
+	h := Handle(*vmo)
+	err := h.Close()
+	*vmo = VMO(HandleInvalid)
+	return err
+}
+
+func NewVMO(size uint64, options VMOOption) (VMO, error) {
+	var h Handle
+	if status := Sys_vmo_create(size, uint32(options), &h); status != ErrOk {
+		return VMO(HandleInvalid), Error{Status: status, Text: "zx.VMO"}
+	}
+	return VMO(h), nil
+}
+
+type VMAR Handle
+
+func (v VMAR) Destroy() error {
+	if status := sys_vmar_destroy(Handle(v)); status != ErrOk {
+		return Error{Status: status, Text: "zx.VMAR.Destroy"}
+	}
+	return nil
+}
+
+var mapErr error = Error{Status: 1, Text: "zx.VMAR.Map"}
+
+func (v VMAR) Map(vmarOffset uint64, vmo VMO, vmoOffset, len uint64, flags VMFlag) (addr uintptr, err error) {
+	status := sys_vmar_map_old(Handle(v), uint64(vmarOffset), Handle(vmo), vmoOffset, uint64(len), uint32(flags), (*Vaddr)(&addr))
+	if status != ErrOk {
+		println("zx.VMAR.Map failed: status: ", status)
+		return 0, mapErr
+	}
+	return addr, nil
+}
+
+var unmapErr error = Error{Status: 1, Text: "zx.VMAR.Unmap"}
+
+func (v VMAR) Unmap(addr uintptr, len uint64) error {
+	status := Sys_vmar_unmap(Handle(v), Vaddr(addr), uint64(len))
+	if status != ErrOk {
+		println(status)
+		return unmapErr
+	}
+	return nil
+}
+
+func (v VMAR) Protect(addr uintptr, len uint64, flags VMFlag) error {
+	status := sys_vmar_protect_old(Handle(v), Vaddr(addr), uint64(len), uint32(flags))
+	if status != ErrOk {
+		return Error{Status: status, Text: "zx.VMAR.Protect"}
+	}
+	return nil
+}
+
+func NewVMAR(parent VMAR, offset, size uint64, flags VMFlag) (child VMAR, addr uintptr, err error) {
+	var childHandle Handle
+	status := sys_vmar_allocate_old(Handle(parent), uint64(offset), uint64(size), uint32(flags), &childHandle, (*Vaddr)(&addr))
+	if status != ErrOk {
+		return 0, 0, Error{Status: status, Text: "zx.NewVMAR"}
+	}
+	return VMAR(childHandle), addr, nil
+}
+
+type Log Handle
+
+func NewLog(options uint32) Log {
+	var h Handle
+	status := Sys_debuglog_create(HandleInvalid, options, &h)
+	if status != ErrOk {
+		return Log(HandleInvalid)
+	}
+	return Log(h)
+}
+
+func (l *Log) Handle() *Handle {
+	return (*Handle)(l)
+}
+
+func (l Log) Write(b []byte) (n int, err error) {
+	status := Sys_log_write(Handle(l), uint32(len(b)), unsafe.Pointer(&b[0]), 0)
+	if status != ErrOk {
+		return 0, Error{Status: status, Text: "zx.Log.Write"}
+	}
+	return len(b), nil
+}
+
+func (l Log) Read(b []byte) (n int, err error) {
+	status := Sys_log_read(Handle(l), uint32(len(b)), unsafe.Pointer(&b[0]), 0)
+	if status != ErrOk {
+		return 0, Error{Status: status, Text: "zx.Log.Read"}
+	}
+	return len(b), nil
+}
+
+func (l *Log) Close() (err error) {
+	h := Handle(*l)
+	err = h.Close()
+	*l = Log(HandleInvalid)
+	return err
+}
+
+func RandRead(b []byte) {
+	Sys_cprng_draw(unsafe.Pointer(&b[0]), uint(len(b)))
+}
+
+// Error is a Status with associated error text.
+// It is used as a Go error.
+type Error struct {
+	Status Status
+	Text   string
+}
+
+func (e Error) Error() string {
+	if e.Text == "" {
+		return "zx.Status: " + e.Status.String()
+	}
+	return e.Status.String() + ": " + e.Text
+}
diff --git a/src/syscall/zx/io/impl.go b/src/syscall/zx/io/impl.go
new file mode 100644
index 0000000..26d33bd
--- /dev/null
+++ b/src/syscall/zx/io/impl.go
@@ -0,0 +1,1855 @@
+// Copyright 2018 The Go 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 fuchsia
+
+package io
+
+import (
+	_bindings "syscall/zx/fidl"
+	_zx "syscall/zx"
+)
+
+const (
+	KOpenRightReadable uint32 = 0x00000001
+	KOpenRightWritable uint32 = 0x00000002
+	KOpenRightAdmin uint32 = 0x00000004
+	KOpenFlagCreate uint32 = 0x00010000
+	KOpenFlagCreateIfAbsent uint32 = 0x00020000
+	KOpenFlagTruncate uint32 = 0x00040000
+	KOpenFlagDirectory uint32 = 0x00080000
+	KOpenFlagAppend uint32 = 0x00100000
+	KOpenFlagNoRemote uint32 = 0x00200000
+	KOpenFlagNodeReference uint32 = 0x00400000
+	KOpenFlagDescribe uint32 = 0x00800000
+	KOpenFlagStatus uint32 = 0x01000000
+	KModeProtectionMask uint32 = 0x00FFF
+	KModeTypeMask uint32 = 0xFF000
+	KModeTypeDirectory uint32 = 0x04000
+	KModeTypeBlockDevice uint32 = 0x06000
+	KModeTypeFile uint32 = 0x08000
+	KModeTypeSocket uint32 = 0x0C000
+	KModeTypeService uint32 = 0x10000
+	KMaxIoctlHandles uint64 = 2
+	KMaxBuf uint64 = 8192
+	KNodeAttributeFlagCreationTime uint32 = 0x00000001
+	KNodeAttributeFlagModificationTime uint32 = 0x00000002
+	KVmoFlagRead uint32 = 0x00000001
+	KVmoFlagWrite uint32 = 0x00000002
+	KVmoFlagExec uint32 = 0x00000004
+	KVmoFlagPrivate uint32 = 0x00010000
+	KDirentTypeUnknown uint32 = 0
+	KDirentTypeDirectory uint32 = 4
+	KDirentTypeBlockDevice uint32 = 6
+	KDirentTypeFile uint32 = 8
+	KDirentTypeSocket uint32 = 12
+	KDirentTypeService uint32 = 16
+)
+
+type SeekOrigin uint32
+const (
+	SeekOriginStart SeekOrigin = 0
+	SeekOriginCurrent SeekOrigin = 1
+	SeekOriginEnd SeekOrigin = 2
+)
+type Service struct {
+	Reserved uint8 
+}
+
+// Implements Payload.
+func (_ *Service) InlineAlignment() int {
+	return 1
+}
+
+// Implements Payload.
+func (_ *Service) InlineSize() int {
+	return 1
+}
+type FileObject struct {
+	Event _zx.Event `fidl:"*"`
+}
+
+// Implements Payload.
+func (_ *FileObject) InlineAlignment() int {
+	return 4
+}
+
+// Implements Payload.
+func (_ *FileObject) InlineSize() int {
+	return 4
+}
+type DirectoryObject struct {
+	Reserved uint8 
+}
+
+// Implements Payload.
+func (_ *DirectoryObject) InlineAlignment() int {
+	return 1
+}
+
+// Implements Payload.
+func (_ *DirectoryObject) InlineSize() int {
+	return 1
+}
+type Pipe struct {
+	Socket _zx.Socket 
+}
+
+// Implements Payload.
+func (_ *Pipe) InlineAlignment() int {
+	return 4
+}
+
+// Implements Payload.
+func (_ *Pipe) InlineSize() int {
+	return 4
+}
+type Vmofile struct {
+	Vmo _zx.VMO 
+	Offset uint64 
+	Length uint64 
+}
+
+// Implements Payload.
+func (_ *Vmofile) InlineAlignment() int {
+	return 8
+}
+
+// Implements Payload.
+func (_ *Vmofile) InlineSize() int {
+	return 24
+}
+type Device struct {
+	Event _zx.Event `fidl:"*"`
+}
+
+// Implements Payload.
+func (_ *Device) InlineAlignment() int {
+	return 4
+}
+
+// Implements Payload.
+func (_ *Device) InlineSize() int {
+	return 4
+}
+type NodeAttributes struct {
+	Mode uint32 
+	Id uint64 
+	ContentSize uint64 
+	StorageSize uint64 
+	LinkCount uint64 
+	CreationTime uint64 
+	ModificationTime uint64 
+}
+
+// Implements Payload.
+func (_ *NodeAttributes) InlineAlignment() int {
+	return 8
+}
+
+// Implements Payload.
+func (_ *NodeAttributes) InlineSize() int {
+	return 56
+}
+type ObjectInfoTag uint32
+const (
+	ObjectInfoService ObjectInfoTag = iota
+	ObjectInfoFile ObjectInfoTag = iota
+	ObjectInfoDirectory ObjectInfoTag = iota
+	ObjectInfoPipe ObjectInfoTag = iota
+	ObjectInfoVmofile ObjectInfoTag = iota
+	ObjectInfoDevice ObjectInfoTag = iota
+)
+
+// ObjectInfo is a FIDL union.
+type ObjectInfo struct {
+	ObjectInfoTag `fidl:"tag"`
+	Service Service 
+	File FileObject 
+	Directory DirectoryObject 
+	Pipe Pipe 
+	Vmofile Vmofile 
+	Device Device 
+}
+
+// Implements Payload.
+func (_ *ObjectInfo) InlineAlignment() int {
+	return 8
+}
+
+// Implements Payload.
+func (_ *ObjectInfo) InlineSize() int {
+	return 32
+}
+
+func (u *ObjectInfo) Which() ObjectInfoTag {
+	return u.ObjectInfoTag
+}
+
+func (u *ObjectInfo) SetService(service Service) {
+	u.ObjectInfoTag = ObjectInfoService
+	u.Service = service
+}
+
+func (u *ObjectInfo) SetFile(file FileObject) {
+	u.ObjectInfoTag = ObjectInfoFile
+	u.File = file
+}
+
+func (u *ObjectInfo) SetDirectory(directory DirectoryObject) {
+	u.ObjectInfoTag = ObjectInfoDirectory
+	u.Directory = directory
+}
+
+func (u *ObjectInfo) SetPipe(pipe Pipe) {
+	u.ObjectInfoTag = ObjectInfoPipe
+	u.Pipe = pipe
+}
+
+func (u *ObjectInfo) SetVmofile(vmofile Vmofile) {
+	u.ObjectInfoTag = ObjectInfoVmofile
+	u.Vmofile = vmofile
+}
+
+func (u *ObjectInfo) SetDevice(device Device) {
+	u.ObjectInfoTag = ObjectInfoDevice
+	u.Device = device
+}
+
+// Request for Clone.
+type ObjectCloneRequest struct {
+	Flags uint32 
+	Object ObjectInterfaceRequest 
+}
+
+// Implements Payload.
+func (_ *ObjectCloneRequest) InlineAlignment() int {
+	return 0
+}
+
+// Implements Payload.
+func (_ *ObjectCloneRequest) InlineSize() int {
+	return 8
+}
+// Clone has no response.
+// Request for Close.
+type ObjectCloseRequest struct {
+}
+
+// Implements Payload.
+func (_ *ObjectCloseRequest) InlineAlignment() int {
+	return 0
+}
+
+// Implements Payload.
+func (_ *ObjectCloseRequest) InlineSize() int {
+	return 0
+}
+// Response for Close.
+type ObjectCloseResponse struct {
+	S _zx.Status 
+}
+
+// Implements Payload.
+func (_ *ObjectCloseResponse) InlineAlignment() int {
+	return 0
+}
+
+// Implements Payload.
+func (_ *ObjectCloseResponse) InlineSize() int {
+	return 4
+}
+// Request for ListInterfaces.
+type ObjectListInterfacesRequest struct {
+}
+
+// Implements Payload.
+func (_ *ObjectListInterfacesRequest) InlineAlignment() int {
+	return 0
+}
+
+// Implements Payload.
+func (_ *ObjectListInterfacesRequest) InlineSize() int {
+	return 0
+}
+// Response for ListInterfaces.
+type ObjectListInterfacesResponse struct {
+	Interfaces []string 
+}
+
+// Implements Payload.
+func (_ *ObjectListInterfacesResponse) InlineAlignment() int {
+	return 0
+}
+
+// Implements Payload.
+func (_ *ObjectListInterfacesResponse) InlineSize() int {
+	return 16
+}
+// Request for Bind.
+type ObjectBindRequest struct {
+	Iface string 
+}
+
+// Implements Payload.
+func (_ *ObjectBindRequest) InlineAlignment() int {
+	return 0
+}
+
+// Implements Payload.
+func (_ *ObjectBindRequest) InlineSize() int {
+	return 16
+}
+// Bind has no response.
+// Request for Describe.
+type ObjectDescribeRequest struct {
+}
+
+// Implements Payload.
+func (_ *ObjectDescribeRequest) InlineAlignment() int {
+	return 0
+}
+
+// Implements Payload.
+func (_ *ObjectDescribeRequest) InlineSize() int {
+	return 0
+}
+// Response for Describe.
+type ObjectDescribeResponse struct {
+	Info ObjectInfo 
+}
+
+// Implements Payload.
+func (_ *ObjectDescribeResponse) InlineAlignment() int {
+	return 0
+}
+
+// Implements Payload.
+func (_ *ObjectDescribeResponse) InlineSize() int {
+	return 32
+}
+// Request for OnOpen.
+// OnOpen has no request.
+// Response for OnOpen.
+type ObjectOnOpenResponse struct {
+	S _zx.Status 
+	Info *ObjectInfo 
+}
+
+// Implements Payload.
+func (_ *ObjectOnOpenResponse) InlineAlignment() int {
+	return 0
+}
+
+// Implements Payload.
+func (_ *ObjectOnOpenResponse) InlineSize() int {
+	return 16
+}
+
+type ObjectInterface _bindings.Proxy
+
+func (p *ObjectInterface) Clone(flags uint32,object ObjectInterfaceRequest) error {
+	req_ := ObjectCloneRequest{
+		Flags: flags,
+		Object: object,
+	}
+	err := ((*_bindings.Proxy)(p)).Send(2147483649, &req_)
+	return err
+}
+func (p *ObjectInterface) Close() (_zx.Status, error) {
+	req_ := ObjectCloseRequest{
+	}
+	resp_ := ObjectCloseResponse{}
+	err := ((*_bindings.Proxy)(p)).Call(2147483650, &req_, &resp_)
+	return resp_.S, err
+}
+func (p *ObjectInterface) ListInterfaces() ([]string, error) {
+	req_ := ObjectListInterfacesRequest{
+	}
+	resp_ := ObjectListInterfacesResponse{}
+	err := ((*_bindings.Proxy)(p)).Call(2147483652, &req_, &resp_)
+	return resp_.Interfaces, err
+}
+func (p *ObjectInterface) Bind(iface string) error {
+	req_ := ObjectBindRequest{
+		Iface: iface,
+	}
+	err := ((*_bindings.Proxy)(p)).Send(2147483653, &req_)
+	return err
+}
+func (p *ObjectInterface) Describe() (ObjectInfo, error) {
+	req_ := ObjectDescribeRequest{
+	}
+	resp_ := ObjectDescribeResponse{}
+	err := ((*_bindings.Proxy)(p)).Call(2147483654, &req_, &resp_)
+	return resp_.Info, err
+}
+func (p *ObjectInterface) ExpectOnOpen() (_zx.Status, *ObjectInfo, error) {
+	resp_ := ObjectOnOpenResponse{}
+	err := ((*_bindings.Proxy)(p)).Recv(2147483655, &resp_)
+	return resp_.S, resp_.Info, err
+}
+
+// Object server interface.
+type Object interface {
+	Clone(flags uint32,object ObjectInterfaceRequest) error
+	Close() (_zx.Status, error)
+	ListInterfaces() ([]string, error)
+	Bind(iface string) error
+	Describe() (ObjectInfo, error)
+}
+
+type ObjectInterfaceRequest _bindings.InterfaceRequest
+
+func NewObjectInterfaceRequest() (ObjectInterfaceRequest, *ObjectInterface, error) {
+	req, cli, err := _bindings.NewInterfaceRequest()
+	return ObjectInterfaceRequest(req), (*ObjectInterface)(cli), err
+}
+
+type ObjectStub struct {
+	Impl Object
+}
+
+func (s *ObjectStub) Dispatch(ord uint32, b_ []byte, h_ []_zx.Handle) (_bindings.Payload, error) {
+	switch ord {
+	case 2147483649:
+		in_ := ObjectCloneRequest{}
+		if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+			return nil, err_
+		}
+		err_ := s.Impl.Clone(in_.Flags,in_.Object)
+		return nil, err_
+	case 2147483650:
+		in_ := ObjectCloseRequest{}
+		if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+			return nil, err_
+		}
+		out_ := ObjectCloseResponse{}
+		s, err_ := s.Impl.Close()
+		out_.S = s
+		return &out_, err_
+	case 2147483652:
+		in_ := ObjectListInterfacesRequest{}
+		if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+			return nil, err_
+		}
+		out_ := ObjectListInterfacesResponse{}
+		interfaces, err_ := s.Impl.ListInterfaces()
+		out_.Interfaces = interfaces
+		return &out_, err_
+	case 2147483653:
+		in_ := ObjectBindRequest{}
+		if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+			return nil, err_
+		}
+		err_ := s.Impl.Bind(in_.Iface)
+		return nil, err_
+	case 2147483654:
+		in_ := ObjectDescribeRequest{}
+		if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+			return nil, err_
+		}
+		out_ := ObjectDescribeResponse{}
+		info, err_ := s.Impl.Describe()
+		out_.Info = info
+		return &out_, err_
+	}
+	return nil, _bindings.ErrUnknownOrdinal
+}
+
+type ObjectService struct {
+	_bindings.BindingSet
+}
+
+func (s *ObjectService) Add(impl Object, c _zx.Channel, onError func(error)) (_bindings.BindingKey, error) {
+	return s.BindingSet.Add(&ObjectStub{Impl: impl}, c, onError)
+}
+
+func (s *ObjectService) EventProxyFor(key _bindings.BindingKey) (*ObjectEventProxy, bool) {
+	pxy, err := s.BindingSet.ProxyFor(key)
+	return (*ObjectEventProxy)(pxy), err
+}
+
+type ObjectEventProxy _bindings.Proxy
+
+func (p *ObjectEventProxy) OnOpen(s _zx.Status,info *ObjectInfo) error {
+	event_ := ObjectOnOpenResponse{
+		S: s,
+		Info: info,
+	}
+	return ((*_bindings.Proxy)(p)).Send(2147483655, &event_)
+}
+
+
+
+// Request for Sync.
+type NodeSyncRequest struct {
+}
+
+// Implements Payload.
+func (_ *NodeSyncRequest) InlineAlignment() int {
+	return 0
+}
+
+// Implements Payload.
+func (_ *NodeSyncRequest) InlineSize() int {
+	return 0
+}
+// Response for Sync.
+type NodeSyncResponse struct {
+	S _zx.Status 
+}
+
+// Implements Payload.
+func (_ *NodeSyncResponse) InlineAlignment() int {
+	return 0
+}
+
+// Implements Payload.
+func (_ *NodeSyncResponse) InlineSize() int {
+	return 4
+}
+// Request for GetAttr.
+type NodeGetAttrRequest struct {
+}
+
+// Implements Payload.
+func (_ *NodeGetAttrRequest) InlineAlignment() int {
+	return 0
+}
+
+// Implements Payload.
+func (_ *NodeGetAttrRequest) InlineSize() int {
+	return 0
+}
+// Response for GetAttr.
+type NodeGetAttrResponse struct {
+	S _zx.Status 
+	Attributes NodeAttributes 
+}
+
+// Implements Payload.
+func (_ *NodeGetAttrResponse) InlineAlignment() int {
+	return 0
+}
+
+// Implements Payload.
+func (_ *NodeGetAttrResponse) InlineSize() int {
+	return 64
+}
+// Request for SetAttr.
+type NodeSetAttrRequest struct {
+	Flags uint32 
+	Attributes NodeAttributes 
+}
+
+// Implements Payload.
+func (_ *NodeSetAttrRequest) InlineAlignment() int {
+	return 0
+}
+
+// Implements Payload.
+func (_ *NodeSetAttrRequest) InlineSize() int {
+	return 64
+}
+// Response for SetAttr.
+type NodeSetAttrResponse struct {
+	S _zx.Status 
+}
+
+// Implements Payload.
+func (_ *NodeSetAttrResponse) InlineAlignment() int {
+	return 0
+}
+
+// Implements Payload.
+func (_ *NodeSetAttrResponse) InlineSize() int {
+	return 4
+}
+// Request for Ioctl.
+type NodeIoctlRequest struct {
+	Opcode uint32 
+	MaxOut uint64 
+	Handles []_zx.Handle `fidl:"2"`
+	In []uint8 `fidl:"8192"`
+}
+
+// Implements Payload.
+func (_ *NodeIoctlRequest) InlineAlignment() int {
+	return 0
+}
+
+// Implements Payload.
+func (_ *NodeIoctlRequest) InlineSize() int {
+	return 48
+}
+// Response for Ioctl.
+type NodeIoctlResponse struct {
+	S _zx.Status 
+	Handles []_zx.Handle `fidl:"2"`
+	Out []uint8 `fidl:"8192"`
+}
+
+// Implements Payload.
+func (_ *NodeIoctlResponse) InlineAlignment() int {
+	return 0
+}
+
+// Implements Payload.
+func (_ *NodeIoctlResponse) InlineSize() int {
+	return 40
+}
+
+type NodeInterface _bindings.Proxy
+
+func (p *NodeInterface) Sync() (_zx.Status, error) {
+	req_ := NodeSyncRequest{
+	}
+	resp_ := NodeSyncResponse{}
+	err := ((*_bindings.Proxy)(p)).Call(2164260865, &req_, &resp_)
+	return resp_.S, err
+}
+func (p *NodeInterface) GetAttr() (_zx.Status, NodeAttributes, error) {
+	req_ := NodeGetAttrRequest{
+	}
+	resp_ := NodeGetAttrResponse{}
+	err := ((*_bindings.Proxy)(p)).Call(2164260866, &req_, &resp_)
+	return resp_.S, resp_.Attributes, err
+}
+func (p *NodeInterface) SetAttr(flags uint32,attributes NodeAttributes) (_zx.Status, error) {
+	req_ := NodeSetAttrRequest{
+		Flags: flags,
+		Attributes: attributes,
+	}
+	resp_ := NodeSetAttrResponse{}
+	err := ((*_bindings.Proxy)(p)).Call(2164260867, &req_, &resp_)
+	return resp_.S, err
+}
+func (p *NodeInterface) Ioctl(opcode uint32,maxOut uint64,handles []_zx.Handle,in []uint8) (_zx.Status, []_zx.Handle, []uint8, error) {
+	req_ := NodeIoctlRequest{
+		Opcode: opcode,
+		MaxOut: maxOut,
+		Handles: handles,
+		In: in,
+	}
+	resp_ := NodeIoctlResponse{}
+	err := ((*_bindings.Proxy)(p)).Call(2164260868, &req_, &resp_)
+	return resp_.S, resp_.Handles, resp_.Out, err
+}
+
+// Node server interface.
+type Node interface {
+	Clone(flags uint32,object ObjectInterfaceRequest) error
+	Close() (_zx.Status, error)
+	ListInterfaces() ([]string, error)
+	Bind(iface string) error
+	Describe() (ObjectInfo, error)
+	Sync() (_zx.Status, error)
+	GetAttr() (_zx.Status, NodeAttributes, error)
+	SetAttr(flags uint32,attributes NodeAttributes) (_zx.Status, error)
+	Ioctl(opcode uint32,maxOut uint64,handles []_zx.Handle,in []uint8) (_zx.Status, []_zx.Handle, []uint8, error)
+}
+
+type NodeInterfaceRequest _bindings.InterfaceRequest
+
+func NewNodeInterfaceRequest() (NodeInterfaceRequest, *NodeInterface, error) {
+	req, cli, err := _bindings.NewInterfaceRequest()
+	return NodeInterfaceRequest(req), (*NodeInterface)(cli), err
+}
+
+type NodeStub struct {
+	Impl Node
+}
+
+func (s *NodeStub) Dispatch(ord uint32, b_ []byte, h_ []_zx.Handle) (_bindings.Payload, error) {
+	switch ord {
+	case 2147483649:
+		in_ := ObjectCloneRequest{}
+		if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+			return nil, err_
+		}
+		err_ := s.Impl.Clone(in_.Flags,in_.Object)
+		return nil, err_
+	case 2147483650:
+		in_ := ObjectCloseRequest{}
+		if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+			return nil, err_
+		}
+		out_ := ObjectCloseResponse{}
+		s, err_ := s.Impl.Close()
+		out_.S = s
+		return &out_, err_
+	case 2147483652:
+		in_ := ObjectListInterfacesRequest{}
+		if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+			return nil, err_
+		}
+		out_ := ObjectListInterfacesResponse{}
+		interfaces, err_ := s.Impl.ListInterfaces()
+		out_.Interfaces = interfaces
+		return &out_, err_
+	case 2147483653:
+		in_ := ObjectBindRequest{}
+		if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+			return nil, err_
+		}
+		err_ := s.Impl.Bind(in_.Iface)
+		return nil, err_
+	case 2147483654:
+		in_ := ObjectDescribeRequest{}
+		if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+			return nil, err_
+		}
+		out_ := ObjectDescribeResponse{}
+		info, err_ := s.Impl.Describe()
+		out_.Info = info
+		return &out_, err_
+	case 2164260865:
+		in_ := NodeSyncRequest{}
+		if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+			return nil, err_
+		}
+		out_ := NodeSyncResponse{}
+		s, err_ := s.Impl.Sync()
+		out_.S = s
+		return &out_, err_
+	case 2164260866:
+		in_ := NodeGetAttrRequest{}
+		if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+			return nil, err_
+		}
+		out_ := NodeGetAttrResponse{}
+		s, attributes, err_ := s.Impl.GetAttr()
+		out_.S = s
+		out_.Attributes = attributes
+		return &out_, err_
+	case 2164260867:
+		in_ := NodeSetAttrRequest{}
+		if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+			return nil, err_
+		}
+		out_ := NodeSetAttrResponse{}
+		s, err_ := s.Impl.SetAttr(in_.Flags,in_.Attributes)
+		out_.S = s
+		return &out_, err_
+	case 2164260868:
+		in_ := NodeIoctlRequest{}
+		if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+			return nil, err_
+		}
+		out_ := NodeIoctlResponse{}
+		s, handles, out, err_ := s.Impl.Ioctl(in_.Opcode,in_.MaxOut,in_.Handles,in_.In)
+		out_.S = s
+		out_.Handles = handles
+		out_.Out = out
+		return &out_, err_
+	}
+	return nil, _bindings.ErrUnknownOrdinal
+}
+
+type NodeService struct {
+	_bindings.BindingSet
+}
+
+func (s *NodeService) Add(impl Node, c _zx.Channel, onError func(error)) (_bindings.BindingKey, error) {
+	return s.BindingSet.Add(&NodeStub{Impl: impl}, c, onError)
+}
+
+func (s *NodeService) EventProxyFor(key _bindings.BindingKey) (*NodeEventProxy, bool) {
+	pxy, err := s.BindingSet.ProxyFor(key)
+	return (*NodeEventProxy)(pxy), err
+}
+
+type NodeEventProxy _bindings.Proxy
+
+func (p *NodeEventProxy) OnOpen(s _zx.Status,info *ObjectInfo) error {
+	event_ := ObjectOnOpenResponse{
+		S: s,
+		Info: info,
+	}
+	return ((*_bindings.Proxy)(p)).Send(2147483655, &event_)
+}
+
+
+
+// Request for Read.
+type FileReadRequest struct {
+	Count uint64 
+}
+
+// Implements Payload.
+func (_ *FileReadRequest) InlineAlignment() int {
+	return 0
+}
+
+// Implements Payload.
+func (_ *FileReadRequest) InlineSize() int {
+	return 8
+}
+// Response for Read.
+type FileReadResponse struct {
+	S _zx.Status 
+	Data []uint8 `fidl:"8192"`
+}
+
+// Implements Payload.
+func (_ *FileReadResponse) InlineAlignment() int {
+	return 0
+}
+
+// Implements Payload.
+func (_ *FileReadResponse) InlineSize() int {
+	return 24
+}
+// Request for ReadAt.
+type FileReadAtRequest struct {
+	Count uint64 
+	Offset uint64 
+}
+
+// Implements Payload.
+func (_ *FileReadAtRequest) InlineAlignment() int {
+	return 0
+}
+
+// Implements Payload.
+func (_ *FileReadAtRequest) InlineSize() int {
+	return 16
+}
+// Response for ReadAt.
+type FileReadAtResponse struct {
+	S _zx.Status 
+	Data []uint8 `fidl:"8192"`
+}
+
+// Implements Payload.
+func (_ *FileReadAtResponse) InlineAlignment() int {
+	return 0
+}
+
+// Implements Payload.
+func (_ *FileReadAtResponse) InlineSize() int {
+	return 24
+}
+// Request for Write.
+type FileWriteRequest struct {
+	Data []uint8 `fidl:"8192"`
+}
+
+// Implements Payload.
+func (_ *FileWriteRequest) InlineAlignment() int {
+	return 0
+}
+
+// Implements Payload.
+func (_ *FileWriteRequest) InlineSize() int {
+	return 16
+}
+// Response for Write.
+type FileWriteResponse struct {
+	S _zx.Status 
+	Actual uint64 
+}
+
+// Implements Payload.
+func (_ *FileWriteResponse) InlineAlignment() int {
+	return 0
+}
+
+// Implements Payload.
+func (_ *FileWriteResponse) InlineSize() int {
+	return 16
+}
+// Request for WriteAt.
+type FileWriteAtRequest struct {
+	Data []uint8 `fidl:"8192"`
+	Offset uint64 
+}
+
+// Implements Payload.
+func (_ *FileWriteAtRequest) InlineAlignment() int {
+	return 0
+}
+
+// Implements Payload.
+func (_ *FileWriteAtRequest) InlineSize() int {
+	return 24
+}
+// Response for WriteAt.
+type FileWriteAtResponse struct {
+	S _zx.Status 
+	Actual uint64 
+}
+
+// Implements Payload.
+func (_ *FileWriteAtResponse) InlineAlignment() int {
+	return 0
+}
+
+// Implements Payload.
+func (_ *FileWriteAtResponse) InlineSize() int {
+	return 16
+}
+// Request for Seek.
+type FileSeekRequest struct {
+	Offset int64 
+	Start SeekOrigin 
+}
+
+// Implements Payload.
+func (_ *FileSeekRequest) InlineAlignment() int {
+	return 0
+}
+
+// Implements Payload.
+func (_ *FileSeekRequest) InlineSize() int {
+	return 16
+}
+// Response for Seek.
+type FileSeekResponse struct {
+	S _zx.Status 
+	Offset uint64 
+}
+
+// Implements Payload.
+func (_ *FileSeekResponse) InlineAlignment() int {
+	return 0
+}
+
+// Implements Payload.
+func (_ *FileSeekResponse) InlineSize() int {
+	return 16
+}
+// Request for Truncate.
+type FileTruncateRequest struct {
+	Length uint64 
+}
+
+// Implements Payload.
+func (_ *FileTruncateRequest) InlineAlignment() int {
+	return 0
+}
+
+// Implements Payload.
+func (_ *FileTruncateRequest) InlineSize() int {
+	return 8
+}
+// Response for Truncate.
+type FileTruncateResponse struct {
+	S _zx.Status 
+}
+
+// Implements Payload.
+func (_ *FileTruncateResponse) InlineAlignment() int {
+	return 0
+}
+
+// Implements Payload.
+func (_ *FileTruncateResponse) InlineSize() int {
+	return 4
+}
+// Request for GetFlags.
+type FileGetFlagsRequest struct {
+}
+
+// Implements Payload.
+func (_ *FileGetFlagsRequest) InlineAlignment() int {
+	return 0
+}
+
+// Implements Payload.
+func (_ *FileGetFlagsRequest) InlineSize() int {
+	return 0
+}
+// Response for GetFlags.
+type FileGetFlagsResponse struct {
+	S _zx.Status 
+	Flags uint32 
+}
+
+// Implements Payload.
+func (_ *FileGetFlagsResponse) InlineAlignment() int {
+	return 0
+}
+
+// Implements Payload.
+func (_ *FileGetFlagsResponse) InlineSize() int {
+	return 8
+}
+// Request for SetFlags.
+type FileSetFlagsRequest struct {
+	Flags uint32 
+}
+
+// Implements Payload.
+func (_ *FileSetFlagsRequest) InlineAlignment() int {
+	return 0
+}
+
+// Implements Payload.
+func (_ *FileSetFlagsRequest) InlineSize() int {
+	return 4
+}
+// Response for SetFlags.
+type FileSetFlagsResponse struct {
+	S _zx.Status 
+}
+
+// Implements Payload.
+func (_ *FileSetFlagsResponse) InlineAlignment() int {
+	return 0
+}
+
+// Implements Payload.
+func (_ *FileSetFlagsResponse) InlineSize() int {
+	return 4
+}
+// Request for GetVmo.
+type FileGetVmoRequest struct {
+	Flags uint32 
+}
+
+// Implements Payload.
+func (_ *FileGetVmoRequest) InlineAlignment() int {
+	return 0
+}
+
+// Implements Payload.
+func (_ *FileGetVmoRequest) InlineSize() int {
+	return 4
+}
+// Response for GetVmo.
+type FileGetVmoResponse struct {
+	S _zx.Status 
+	Vmo _zx.VMO 
+}
+
+// Implements Payload.
+func (_ *FileGetVmoResponse) InlineAlignment() int {
+	return 0
+}
+
+// Implements Payload.
+func (_ *FileGetVmoResponse) InlineSize() int {
+	return 8
+}
+// Request for GetVmoAt.
+type FileGetVmoAtRequest struct {
+	Flags uint32 
+	Offset uint64 
+	Length uint64 
+}
+
+// Implements Payload.
+func (_ *FileGetVmoAtRequest) InlineAlignment() int {
+	return 0
+}
+
+// Implements Payload.
+func (_ *FileGetVmoAtRequest) InlineSize() int {
+	return 24
+}
+// Response for GetVmoAt.
+type FileGetVmoAtResponse struct {
+	S _zx.Status 
+	Vmo _zx.VMO 
+}
+
+// Implements Payload.
+func (_ *FileGetVmoAtResponse) InlineAlignment() int {
+	return 0
+}
+
+// Implements Payload.
+func (_ *FileGetVmoAtResponse) InlineSize() int {
+	return 8
+}
+
+type FileInterface _bindings.Proxy
+
+func (p *FileInterface) Read(count uint64) (_zx.Status, []uint8, error) {
+	req_ := FileReadRequest{
+		Count: count,
+	}
+	resp_ := FileReadResponse{}
+	err := ((*_bindings.Proxy)(p)).Call(2181038081, &req_, &resp_)
+	return resp_.S, resp_.Data, err
+}
+func (p *FileInterface) ReadAt(count uint64,offset uint64) (_zx.Status, []uint8, error) {
+	req_ := FileReadAtRequest{
+		Count: count,
+		Offset: offset,
+	}
+	resp_ := FileReadAtResponse{}
+	err := ((*_bindings.Proxy)(p)).Call(2181038082, &req_, &resp_)
+	return resp_.S, resp_.Data, err
+}
+func (p *FileInterface) Write(data []uint8) (_zx.Status, uint64, error) {
+	req_ := FileWriteRequest{
+		Data: data,
+	}
+	resp_ := FileWriteResponse{}
+	err := ((*_bindings.Proxy)(p)).Call(2181038083, &req_, &resp_)
+	return resp_.S, resp_.Actual, err
+}
+func (p *FileInterface) WriteAt(data []uint8,offset uint64) (_zx.Status, uint64, error) {
+	req_ := FileWriteAtRequest{
+		Data: data,
+		Offset: offset,
+	}
+	resp_ := FileWriteAtResponse{}
+	err := ((*_bindings.Proxy)(p)).Call(2181038084, &req_, &resp_)
+	return resp_.S, resp_.Actual, err
+}
+func (p *FileInterface) Seek(offset int64,start SeekOrigin) (_zx.Status, uint64, error) {
+	req_ := FileSeekRequest{
+		Offset: offset,
+		Start: start,
+	}
+	resp_ := FileSeekResponse{}
+	err := ((*_bindings.Proxy)(p)).Call(2181038085, &req_, &resp_)
+	return resp_.S, resp_.Offset, err
+}
+func (p *FileInterface) Truncate(length uint64) (_zx.Status, error) {
+	req_ := FileTruncateRequest{
+		Length: length,
+	}
+	resp_ := FileTruncateResponse{}
+	err := ((*_bindings.Proxy)(p)).Call(2181038086, &req_, &resp_)
+	return resp_.S, err
+}
+func (p *FileInterface) GetFlags() (_zx.Status, uint32, error) {
+	req_ := FileGetFlagsRequest{
+	}
+	resp_ := FileGetFlagsResponse{}
+	err := ((*_bindings.Proxy)(p)).Call(2181038087, &req_, &resp_)
+	return resp_.S, resp_.Flags, err
+}
+func (p *FileInterface) SetFlags(flags uint32) (_zx.Status, error) {
+	req_ := FileSetFlagsRequest{
+		Flags: flags,
+	}
+	resp_ := FileSetFlagsResponse{}
+	err := ((*_bindings.Proxy)(p)).Call(2181038088, &req_, &resp_)
+	return resp_.S, err
+}
+func (p *FileInterface) GetVmo(flags uint32) (_zx.Status, _zx.VMO, error) {
+	req_ := FileGetVmoRequest{
+		Flags: flags,
+	}
+	resp_ := FileGetVmoResponse{}
+	err := ((*_bindings.Proxy)(p)).Call(2181038089, &req_, &resp_)
+	return resp_.S, resp_.Vmo, err
+}
+func (p *FileInterface) GetVmoAt(flags uint32,offset uint64,length uint64) (_zx.Status, _zx.VMO, error) {
+	req_ := FileGetVmoAtRequest{
+		Flags: flags,
+		Offset: offset,
+		Length: length,
+	}
+	resp_ := FileGetVmoAtResponse{}
+	err := ((*_bindings.Proxy)(p)).Call(2181038090, &req_, &resp_)
+	return resp_.S, resp_.Vmo, err
+}
+
+// File server interface.
+type File interface {
+	Clone(flags uint32,object ObjectInterfaceRequest) error
+	Close() (_zx.Status, error)
+	ListInterfaces() ([]string, error)
+	Bind(iface string) error
+	Describe() (ObjectInfo, error)
+	Sync() (_zx.Status, error)
+	GetAttr() (_zx.Status, NodeAttributes, error)
+	SetAttr(flags uint32,attributes NodeAttributes) (_zx.Status, error)
+	Ioctl(opcode uint32,maxOut uint64,handles []_zx.Handle,in []uint8) (_zx.Status, []_zx.Handle, []uint8, error)
+	Read(count uint64) (_zx.Status, []uint8, error)
+	ReadAt(count uint64,offset uint64) (_zx.Status, []uint8, error)
+	Write(data []uint8) (_zx.Status, uint64, error)
+	WriteAt(data []uint8,offset uint64) (_zx.Status, uint64, error)
+	Seek(offset int64,start SeekOrigin) (_zx.Status, uint64, error)
+	Truncate(length uint64) (_zx.Status, error)
+	GetFlags() (_zx.Status, uint32, error)
+	SetFlags(flags uint32) (_zx.Status, error)
+	GetVmo(flags uint32) (_zx.Status, _zx.VMO, error)
+	GetVmoAt(flags uint32,offset uint64,length uint64) (_zx.Status, _zx.VMO, error)
+}
+
+type FileInterfaceRequest _bindings.InterfaceRequest
+
+func NewFileInterfaceRequest() (FileInterfaceRequest, *FileInterface, error) {
+	req, cli, err := _bindings.NewInterfaceRequest()
+	return FileInterfaceRequest(req), (*FileInterface)(cli), err
+}
+
+type FileStub struct {
+	Impl File
+}
+
+func (s *FileStub) Dispatch(ord uint32, b_ []byte, h_ []_zx.Handle) (_bindings.Payload, error) {
+	switch ord {
+	case 2147483649:
+		in_ := ObjectCloneRequest{}
+		if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+			return nil, err_
+		}
+		err_ := s.Impl.Clone(in_.Flags,in_.Object)
+		return nil, err_
+	case 2147483650:
+		in_ := ObjectCloseRequest{}
+		if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+			return nil, err_
+		}
+		out_ := ObjectCloseResponse{}
+		s, err_ := s.Impl.Close()
+		out_.S = s
+		return &out_, err_
+	case 2147483652:
+		in_ := ObjectListInterfacesRequest{}
+		if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+			return nil, err_
+		}
+		out_ := ObjectListInterfacesResponse{}
+		interfaces, err_ := s.Impl.ListInterfaces()
+		out_.Interfaces = interfaces
+		return &out_, err_
+	case 2147483653:
+		in_ := ObjectBindRequest{}
+		if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+			return nil, err_
+		}
+		err_ := s.Impl.Bind(in_.Iface)
+		return nil, err_
+	case 2147483654:
+		in_ := ObjectDescribeRequest{}
+		if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+			return nil, err_
+		}
+		out_ := ObjectDescribeResponse{}
+		info, err_ := s.Impl.Describe()
+		out_.Info = info
+		return &out_, err_
+	case 2164260865:
+		in_ := NodeSyncRequest{}
+		if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+			return nil, err_
+		}
+		out_ := NodeSyncResponse{}
+		s, err_ := s.Impl.Sync()
+		out_.S = s
+		return &out_, err_
+	case 2164260866:
+		in_ := NodeGetAttrRequest{}
+		if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+			return nil, err_
+		}
+		out_ := NodeGetAttrResponse{}
+		s, attributes, err_ := s.Impl.GetAttr()
+		out_.S = s
+		out_.Attributes = attributes
+		return &out_, err_
+	case 2164260867:
+		in_ := NodeSetAttrRequest{}
+		if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+			return nil, err_
+		}
+		out_ := NodeSetAttrResponse{}
+		s, err_ := s.Impl.SetAttr(in_.Flags,in_.Attributes)
+		out_.S = s
+		return &out_, err_
+	case 2164260868:
+		in_ := NodeIoctlRequest{}
+		if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+			return nil, err_
+		}
+		out_ := NodeIoctlResponse{}
+		s, handles, out, err_ := s.Impl.Ioctl(in_.Opcode,in_.MaxOut,in_.Handles,in_.In)
+		out_.S = s
+		out_.Handles = handles
+		out_.Out = out
+		return &out_, err_
+	case 2181038081:
+		in_ := FileReadRequest{}
+		if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+			return nil, err_
+		}
+		out_ := FileReadResponse{}
+		s, data, err_ := s.Impl.Read(in_.Count)
+		out_.S = s
+		out_.Data = data
+		return &out_, err_
+	case 2181038082:
+		in_ := FileReadAtRequest{}
+		if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+			return nil, err_
+		}
+		out_ := FileReadAtResponse{}
+		s, data, err_ := s.Impl.ReadAt(in_.Count,in_.Offset)
+		out_.S = s
+		out_.Data = data
+		return &out_, err_
+	case 2181038083:
+		in_ := FileWriteRequest{}
+		if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+			return nil, err_
+		}
+		out_ := FileWriteResponse{}
+		s, actual, err_ := s.Impl.Write(in_.Data)
+		out_.S = s
+		out_.Actual = actual
+		return &out_, err_
+	case 2181038084:
+		in_ := FileWriteAtRequest{}
+		if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+			return nil, err_
+		}
+		out_ := FileWriteAtResponse{}
+		s, actual, err_ := s.Impl.WriteAt(in_.Data,in_.Offset)
+		out_.S = s
+		out_.Actual = actual
+		return &out_, err_
+	case 2181038085:
+		in_ := FileSeekRequest{}
+		if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+			return nil, err_
+		}
+		out_ := FileSeekResponse{}
+		s, offset, err_ := s.Impl.Seek(in_.Offset,in_.Start)
+		out_.S = s
+		out_.Offset = offset
+		return &out_, err_
+	case 2181038086:
+		in_ := FileTruncateRequest{}
+		if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+			return nil, err_
+		}
+		out_ := FileTruncateResponse{}
+		s, err_ := s.Impl.Truncate(in_.Length)
+		out_.S = s
+		return &out_, err_
+	case 2181038087:
+		in_ := FileGetFlagsRequest{}
+		if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+			return nil, err_
+		}
+		out_ := FileGetFlagsResponse{}
+		s, flags, err_ := s.Impl.GetFlags()
+		out_.S = s
+		out_.Flags = flags
+		return &out_, err_
+	case 2181038088:
+		in_ := FileSetFlagsRequest{}
+		if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+			return nil, err_
+		}
+		out_ := FileSetFlagsResponse{}
+		s, err_ := s.Impl.SetFlags(in_.Flags)
+		out_.S = s
+		return &out_, err_
+	case 2181038089:
+		in_ := FileGetVmoRequest{}
+		if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+			return nil, err_
+		}
+		out_ := FileGetVmoResponse{}
+		s, vmo, err_ := s.Impl.GetVmo(in_.Flags)
+		out_.S = s
+		out_.Vmo = vmo
+		return &out_, err_
+	case 2181038090:
+		in_ := FileGetVmoAtRequest{}
+		if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+			return nil, err_
+		}
+		out_ := FileGetVmoAtResponse{}
+		s, vmo, err_ := s.Impl.GetVmoAt(in_.Flags,in_.Offset,in_.Length)
+		out_.S = s
+		out_.Vmo = vmo
+		return &out_, err_
+	}
+	return nil, _bindings.ErrUnknownOrdinal
+}
+
+type FileService struct {
+	_bindings.BindingSet
+}
+
+func (s *FileService) Add(impl File, c _zx.Channel, onError func(error)) (_bindings.BindingKey, error) {
+	return s.BindingSet.Add(&FileStub{Impl: impl}, c, onError)
+}
+
+func (s *FileService) EventProxyFor(key _bindings.BindingKey) (*FileEventProxy, bool) {
+	pxy, err := s.BindingSet.ProxyFor(key)
+	return (*FileEventProxy)(pxy), err
+}
+
+type FileEventProxy _bindings.Proxy
+
+func (p *FileEventProxy) OnOpen(s _zx.Status,info *ObjectInfo) error {
+	event_ := ObjectOnOpenResponse{
+		S: s,
+		Info: info,
+	}
+	return ((*_bindings.Proxy)(p)).Send(2147483655, &event_)
+}
+
+
+
+// Request for Open.
+type DirectoryOpenRequest struct {
+	Flags uint32 
+	Mode uint32 
+	Path string 
+	Object ObjectInterfaceRequest 
+}
+
+// Implements Payload.
+func (_ *DirectoryOpenRequest) InlineAlignment() int {
+	return 0
+}
+
+// Implements Payload.
+func (_ *DirectoryOpenRequest) InlineSize() int {
+	return 32
+}
+// Open has no response.
+// Request for Unlink.
+type DirectoryUnlinkRequest struct {
+	Path string 
+}
+
+// Implements Payload.
+func (_ *DirectoryUnlinkRequest) InlineAlignment() int {
+	return 0
+}
+
+// Implements Payload.
+func (_ *DirectoryUnlinkRequest) InlineSize() int {
+	return 16
+}
+// Response for Unlink.
+type DirectoryUnlinkResponse struct {
+	S _zx.Status 
+}
+
+// Implements Payload.
+func (_ *DirectoryUnlinkResponse) InlineAlignment() int {
+	return 0
+}
+
+// Implements Payload.
+func (_ *DirectoryUnlinkResponse) InlineSize() int {
+	return 4
+}
+// Request for ReadDirents.
+type DirectoryReadDirentsRequest struct {
+	MaxOut uint64 
+}
+
+// Implements Payload.
+func (_ *DirectoryReadDirentsRequest) InlineAlignment() int {
+	return 0
+}
+
+// Implements Payload.
+func (_ *DirectoryReadDirentsRequest) InlineSize() int {
+	return 8
+}
+// Response for ReadDirents.
+type DirectoryReadDirentsResponse struct {
+	S _zx.Status 
+	Dirents []uint8 `fidl:"8192"`
+}
+
+// Implements Payload.
+func (_ *DirectoryReadDirentsResponse) InlineAlignment() int {
+	return 0
+}
+
+// Implements Payload.
+func (_ *DirectoryReadDirentsResponse) InlineSize() int {
+	return 24
+}
+// Request for Rewind.
+type DirectoryRewindRequest struct {
+}
+
+// Implements Payload.
+func (_ *DirectoryRewindRequest) InlineAlignment() int {
+	return 0
+}
+
+// Implements Payload.
+func (_ *DirectoryRewindRequest) InlineSize() int {
+	return 0
+}
+// Response for Rewind.
+type DirectoryRewindResponse struct {
+	S _zx.Status 
+}
+
+// Implements Payload.
+func (_ *DirectoryRewindResponse) InlineAlignment() int {
+	return 0
+}
+
+// Implements Payload.
+func (_ *DirectoryRewindResponse) InlineSize() int {
+	return 4
+}
+// Request for GetToken.
+type DirectoryGetTokenRequest struct {
+}
+
+// Implements Payload.
+func (_ *DirectoryGetTokenRequest) InlineAlignment() int {
+	return 0
+}
+
+// Implements Payload.
+func (_ *DirectoryGetTokenRequest) InlineSize() int {
+	return 0
+}
+// Response for GetToken.
+type DirectoryGetTokenResponse struct {
+	S _zx.Status 
+	Token _zx.Handle 
+}
+
+// Implements Payload.
+func (_ *DirectoryGetTokenResponse) InlineAlignment() int {
+	return 0
+}
+
+// Implements Payload.
+func (_ *DirectoryGetTokenResponse) InlineSize() int {
+	return 8
+}
+// Request for Rename.
+type DirectoryRenameRequest struct {
+	Src string 
+	DstParentToken _zx.Handle 
+	Dst string 
+}
+
+// Implements Payload.
+func (_ *DirectoryRenameRequest) InlineAlignment() int {
+	return 0
+}
+
+// Implements Payload.
+func (_ *DirectoryRenameRequest) InlineSize() int {
+	return 40
+}
+// Response for Rename.
+type DirectoryRenameResponse struct {
+	S _zx.Status 
+}
+
+// Implements Payload.
+func (_ *DirectoryRenameResponse) InlineAlignment() int {
+	return 0
+}
+
+// Implements Payload.
+func (_ *DirectoryRenameResponse) InlineSize() int {
+	return 4
+}
+// Request for Link.
+type DirectoryLinkRequest struct {
+	Src string 
+	DstParentToken _zx.Handle 
+	Dst string 
+}
+
+// Implements Payload.
+func (_ *DirectoryLinkRequest) InlineAlignment() int {
+	return 0
+}
+
+// Implements Payload.
+func (_ *DirectoryLinkRequest) InlineSize() int {
+	return 40
+}
+// Response for Link.
+type DirectoryLinkResponse struct {
+	S _zx.Status 
+}
+
+// Implements Payload.
+func (_ *DirectoryLinkResponse) InlineAlignment() int {
+	return 0
+}
+
+// Implements Payload.
+func (_ *DirectoryLinkResponse) InlineSize() int {
+	return 4
+}
+
+type DirectoryInterface _bindings.Proxy
+
+func (p *DirectoryInterface) Open(flags uint32,mode uint32,path string,object ObjectInterfaceRequest) error {
+	req_ := DirectoryOpenRequest{
+		Flags: flags,
+		Mode: mode,
+		Path: path,
+		Object: object,
+	}
+	err := ((*_bindings.Proxy)(p)).Send(2197815297, &req_)
+	return err
+}
+func (p *DirectoryInterface) Unlink(path string) (_zx.Status, error) {
+	req_ := DirectoryUnlinkRequest{
+		Path: path,
+	}
+	resp_ := DirectoryUnlinkResponse{}
+	err := ((*_bindings.Proxy)(p)).Call(2197815298, &req_, &resp_)
+	return resp_.S, err
+}
+func (p *DirectoryInterface) ReadDirents(maxOut uint64) (_zx.Status, []uint8, error) {
+	req_ := DirectoryReadDirentsRequest{
+		MaxOut: maxOut,
+	}
+	resp_ := DirectoryReadDirentsResponse{}
+	err := ((*_bindings.Proxy)(p)).Call(2197815299, &req_, &resp_)
+	return resp_.S, resp_.Dirents, err
+}
+func (p *DirectoryInterface) Rewind() (_zx.Status, error) {
+	req_ := DirectoryRewindRequest{
+	}
+	resp_ := DirectoryRewindResponse{}
+	err := ((*_bindings.Proxy)(p)).Call(2197815300, &req_, &resp_)
+	return resp_.S, err
+}
+func (p *DirectoryInterface) GetToken() (_zx.Status, _zx.Handle, error) {
+	req_ := DirectoryGetTokenRequest{
+	}
+	resp_ := DirectoryGetTokenResponse{}
+	err := ((*_bindings.Proxy)(p)).Call(2197815301, &req_, &resp_)
+	return resp_.S, resp_.Token, err
+}
+func (p *DirectoryInterface) Rename(src string,dstParentToken _zx.Handle,dst string) (_zx.Status, error) {
+	req_ := DirectoryRenameRequest{
+		Src: src,
+		DstParentToken: dstParentToken,
+		Dst: dst,
+	}
+	resp_ := DirectoryRenameResponse{}
+	err := ((*_bindings.Proxy)(p)).Call(2197815302, &req_, &resp_)
+	return resp_.S, err
+}
+func (p *DirectoryInterface) Link(src string,dstParentToken _zx.Handle,dst string) (_zx.Status, error) {
+	req_ := DirectoryLinkRequest{
+		Src: src,
+		DstParentToken: dstParentToken,
+		Dst: dst,
+	}
+	resp_ := DirectoryLinkResponse{}
+	err := ((*_bindings.Proxy)(p)).Call(2197815303, &req_, &resp_)
+	return resp_.S, err
+}
+
+// Directory server interface.
+type Directory interface {
+	Clone(flags uint32,object ObjectInterfaceRequest) error
+	Close() (_zx.Status, error)
+	ListInterfaces() ([]string, error)
+	Bind(iface string) error
+	Describe() (ObjectInfo, error)
+	Sync() (_zx.Status, error)
+	GetAttr() (_zx.Status, NodeAttributes, error)
+	SetAttr(flags uint32,attributes NodeAttributes) (_zx.Status, error)
+	Ioctl(opcode uint32,maxOut uint64,handles []_zx.Handle,in []uint8) (_zx.Status, []_zx.Handle, []uint8, error)
+	Open(flags uint32,mode uint32,path string,object ObjectInterfaceRequest) error
+	Unlink(path string) (_zx.Status, error)
+	ReadDirents(maxOut uint64) (_zx.Status, []uint8, error)
+	Rewind() (_zx.Status, error)
+	GetToken() (_zx.Status, _zx.Handle, error)
+	Rename(src string,dstParentToken _zx.Handle,dst string) (_zx.Status, error)
+	Link(src string,dstParentToken _zx.Handle,dst string) (_zx.Status, error)
+}
+
+type DirectoryInterfaceRequest _bindings.InterfaceRequest
+
+func NewDirectoryInterfaceRequest() (DirectoryInterfaceRequest, *DirectoryInterface, error) {
+	req, cli, err := _bindings.NewInterfaceRequest()
+	return DirectoryInterfaceRequest(req), (*DirectoryInterface)(cli), err
+}
+
+type DirectoryStub struct {
+	Impl Directory
+}
+
+func (s *DirectoryStub) Dispatch(ord uint32, b_ []byte, h_ []_zx.Handle) (_bindings.Payload, error) {
+	switch ord {
+	case 2147483649:
+		in_ := ObjectCloneRequest{}
+		if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+			return nil, err_
+		}
+		err_ := s.Impl.Clone(in_.Flags,in_.Object)
+		return nil, err_
+	case 2147483650:
+		in_ := ObjectCloseRequest{}
+		if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+			return nil, err_
+		}
+		out_ := ObjectCloseResponse{}
+		s, err_ := s.Impl.Close()
+		out_.S = s
+		return &out_, err_
+	case 2147483652:
+		in_ := ObjectListInterfacesRequest{}
+		if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+			return nil, err_
+		}
+		out_ := ObjectListInterfacesResponse{}
+		interfaces, err_ := s.Impl.ListInterfaces()
+		out_.Interfaces = interfaces
+		return &out_, err_
+	case 2147483653:
+		in_ := ObjectBindRequest{}
+		if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+			return nil, err_
+		}
+		err_ := s.Impl.Bind(in_.Iface)
+		return nil, err_
+	case 2147483654:
+		in_ := ObjectDescribeRequest{}
+		if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+			return nil, err_
+		}
+		out_ := ObjectDescribeResponse{}
+		info, err_ := s.Impl.Describe()
+		out_.Info = info
+		return &out_, err_
+	case 2164260865:
+		in_ := NodeSyncRequest{}
+		if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+			return nil, err_
+		}
+		out_ := NodeSyncResponse{}
+		s, err_ := s.Impl.Sync()
+		out_.S = s
+		return &out_, err_
+	case 2164260866:
+		in_ := NodeGetAttrRequest{}
+		if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+			return nil, err_
+		}
+		out_ := NodeGetAttrResponse{}
+		s, attributes, err_ := s.Impl.GetAttr()
+		out_.S = s
+		out_.Attributes = attributes
+		return &out_, err_
+	case 2164260867:
+		in_ := NodeSetAttrRequest{}
+		if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+			return nil, err_
+		}
+		out_ := NodeSetAttrResponse{}
+		s, err_ := s.Impl.SetAttr(in_.Flags,in_.Attributes)
+		out_.S = s
+		return &out_, err_
+	case 2164260868:
+		in_ := NodeIoctlRequest{}
+		if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+			return nil, err_
+		}
+		out_ := NodeIoctlResponse{}
+		s, handles, out, err_ := s.Impl.Ioctl(in_.Opcode,in_.MaxOut,in_.Handles,in_.In)
+		out_.S = s
+		out_.Handles = handles
+		out_.Out = out
+		return &out_, err_
+	case 2197815297:
+		in_ := DirectoryOpenRequest{}
+		if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+			return nil, err_
+		}
+		err_ := s.Impl.Open(in_.Flags,in_.Mode,in_.Path,in_.Object)
+		return nil, err_
+	case 2197815298:
+		in_ := DirectoryUnlinkRequest{}
+		if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+			return nil, err_
+		}
+		out_ := DirectoryUnlinkResponse{}
+		s, err_ := s.Impl.Unlink(in_.Path)
+		out_.S = s
+		return &out_, err_
+	case 2197815299:
+		in_ := DirectoryReadDirentsRequest{}
+		if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+			return nil, err_
+		}
+		out_ := DirectoryReadDirentsResponse{}
+		s, dirents, err_ := s.Impl.ReadDirents(in_.MaxOut)
+		out_.S = s
+		out_.Dirents = dirents
+		return &out_, err_
+	case 2197815300:
+		in_ := DirectoryRewindRequest{}
+		if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+			return nil, err_
+		}
+		out_ := DirectoryRewindResponse{}
+		s, err_ := s.Impl.Rewind()
+		out_.S = s
+		return &out_, err_
+	case 2197815301:
+		in_ := DirectoryGetTokenRequest{}
+		if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+			return nil, err_
+		}
+		out_ := DirectoryGetTokenResponse{}
+		s, token, err_ := s.Impl.GetToken()
+		out_.S = s
+		out_.Token = token
+		return &out_, err_
+	case 2197815302:
+		in_ := DirectoryRenameRequest{}
+		if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+			return nil, err_
+		}
+		out_ := DirectoryRenameResponse{}
+		s, err_ := s.Impl.Rename(in_.Src,in_.DstParentToken,in_.Dst)
+		out_.S = s
+		return &out_, err_
+	case 2197815303:
+		in_ := DirectoryLinkRequest{}
+		if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+			return nil, err_
+		}
+		out_ := DirectoryLinkResponse{}
+		s, err_ := s.Impl.Link(in_.Src,in_.DstParentToken,in_.Dst)
+		out_.S = s
+		return &out_, err_
+	}
+	return nil, _bindings.ErrUnknownOrdinal
+}
+
+type DirectoryService struct {
+	_bindings.BindingSet
+}
+
+func (s *DirectoryService) Add(impl Directory, c _zx.Channel, onError func(error)) (_bindings.BindingKey, error) {
+	return s.BindingSet.Add(&DirectoryStub{Impl: impl}, c, onError)
+}
+
+func (s *DirectoryService) EventProxyFor(key _bindings.BindingKey) (*DirectoryEventProxy, bool) {
+	pxy, err := s.BindingSet.ProxyFor(key)
+	return (*DirectoryEventProxy)(pxy), err
+}
+
+type DirectoryEventProxy _bindings.Proxy
+
+func (p *DirectoryEventProxy) OnOpen(s _zx.Status,info *ObjectInfo) error {
+	event_ := ObjectOnOpenResponse{
+		S: s,
+		Info: info,
+	}
+	return ((*_bindings.Proxy)(p)).Send(2147483655, &event_)
+}
+
diff --git a/src/syscall/zx/mkfuchsia.go b/src/syscall/zx/mkfuchsia.go
new file mode 100644
index 0000000..f717a62
--- /dev/null
+++ b/src/syscall/zx/mkfuchsia.go
@@ -0,0 +1,875 @@
+// Copyright 2016 The Go 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
+
+// Parses syscalls.abigen of Fuchsia's zircon kernel and produces Go
+// assembly for calling the system calls.
+//
+// Regenerate syscall/zx with:
+//
+//	go run mkfuchsia.go -stubs > syscalls_fuchsia.go
+//	go run mkfuchsia.go -goarch=amd64 > syscalls_fuchsia_amd64.s
+//	go run mkfuchsia.go -goarch=arm64 > syscalls_fuchsia_arm64.s
+//	gofmt -w *.go
+package main
+
+import (
+	"bytes"
+	"flag"
+	"fmt"
+	"io/ioutil"
+	"log"
+	"os"
+	"path/filepath"
+	"strings"
+	"unicode/utf8"
+)
+
+var (
+	stubs       = flag.Bool("stubs", false, "print only Go function stubs")
+	goarch      = flag.String("goarch", "amd64", "arch to print asm for")
+	fuchsiaRoot = flag.String("fuchsia_root", filepath.Join(os.Getenv("HOME"), "fuchsia"), "path to fuchsia root")
+)
+
+func main() {
+	flag.Parse()
+	sdkArch := ""
+	switch *goarch {
+	case "amd64":
+		sdkArch = "x86_64"
+	case "arm64":
+		sdkArch = "aarch64"
+	default:
+		log.Fatalf("GOARCH=%s not supported", *goarch)
+	}
+	_ = sdkArch
+
+	syscallsFile := filepath.Join(*fuchsiaRoot, "/zircon/system/public/zircon/syscalls.abigen")
+	if args := flag.Args(); len(args) != 0 {
+		syscallsFile = args[0]
+	}
+
+	b, err := ioutil.ReadFile(syscallsFile)
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	p := &parser{
+		buf:  b,
+		line: 1,
+		name: syscallsFile,
+	}
+	syscalls, err := p.parse()
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	buf := new(bytes.Buffer)
+	if *stubs {
+		fmt.Fprint(buf, stubsHeader[1:])
+		for _, call := range syscalls {
+			fmt.Fprintf(buf, "//go:cgo_import_dynamic vdso_zx_%s zx_%s \"libzircon.so\"\n", call.name, call.name)
+		}
+		fmt.Fprint(buf, "\n")
+		for _, call := range syscalls {
+			fmt.Fprintf(buf, "//go:linkname vdso_zx_%s vdso_zx_%s\n", call.name, call.name)
+		}
+		fmt.Fprint(buf, "\nvar (\n")
+		for _, call := range syscalls {
+			fmt.Fprintf(buf, "\tvdso_zx_%s uintptr\n", call.name)
+		}
+		fmt.Fprint(buf, ")\n\n")
+		for _, call := range syscalls {
+			fmt.Fprint(buf, "//go:noescape\n")
+			fmt.Fprint(buf, "//go:nosplit\n")
+			printStub(buf, call)
+			fmt.Fprint(buf, "\n")
+		}
+	} else {
+		fmt.Fprint(buf, asmHeader[1:])
+		for _, call := range syscalls {
+			fmt.Fprint(buf, "// ")
+			printStub(buf, call)
+			printAsm(buf, call)
+			fmt.Fprint(buf, "\n")
+		}
+	}
+	buf.WriteTo(os.Stdout)
+}
+
+const stubsHeader = `
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Zircon system calls for the Fuchsia OS.
+// Generated by mkfuchsia.go, do not edit.
+
+package zx
+
+import "unsafe"
+
+`
+
+const asmHeader = `
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Zircon system calls for the Fuchsia OS.
+// Generated by mkfuchsia.go, do not edit.
+
+#include "textflag.h"
+
+`
+
+func printStub(buf *bytes.Buffer, call zirconSyscallDef) {
+	fmt.Fprintf(buf, "func %s(", call.sysname())
+	for i, arg := range call.args {
+		if arg.atype == (zirconType{}) {
+			continue
+		}
+		if i > 0 {
+			fmt.Fprint(buf, ", ")
+		}
+		fmt.Fprintf(buf, "%s ", arg.aname)
+		printGoType(buf, arg.atype)
+	}
+	fmt.Fprint(buf, ")")
+	if call.ret != (zirconType{}) {
+		fmt.Fprint(buf, " ")
+		printGoType(buf, call.ret)
+	}
+	fmt.Fprint(buf, "\n")
+}
+
+// amd64RegArgs is the amd64 registers in function argument calling convention order
+var amd64RegArgs = []string{"DI", "SI", "DX", "CX", "R8", "R9", "R12", "R13"}
+
+// arm64RegArgs is the arm64 registers in function argument calling convention order
+var arm64RegArgs = []string{"R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7"}
+
+// blockingSyscalls is a map of known syscalls which may block.
+var blockingSyscalls = map[string]bool{
+	"port_wait":        true,
+	"object_wait_one":  true,
+	"object_wait_many": true,
+}
+
+const ZIRCON_SYSCALL_MAGIC = 0x00ff00ff00000000
+
+func printAsm(buf *bytes.Buffer, call zirconSyscallDef) {
+	// The summed size of all arguments
+	argSize := 0
+	for _, arg := range call.args {
+		sz := typeSize(arg.atype)
+		if *goarch == "arm64" && sz == 1 {
+			sz = 8
+		}
+		for argSize%sz != 0 {
+			// Add padding until the 'argSize' is aligned to the type we are adding
+			argSize++
+		}
+		argSize += sz
+	}
+	if argSize%8 == 4 {
+		// Force the return argument on the stack to be 8-byte aligned, not 4-byte aligned
+		argSize += 4
+	}
+	retSize := typeSize(call.ret)
+
+	var frameSize int
+	var regArgs []string
+	var callIns, retReg, suffix4, suffix8 string
+	switch *goarch {
+	case "amd64":
+		regArgs = amd64RegArgs
+		callIns = "CALL"
+		retReg = "AX"
+		suffix8 = "Q"
+		suffix4 = "L"
+		switch len(call.args) {
+		case 7:
+			frameSize = 16 + 8
+		case 8:
+			frameSize = 16 + 2*8
+		}
+	case "arm64":
+		regArgs = arm64RegArgs
+		callIns = "BL"
+		retReg = "R0"
+		suffix8 = "D"
+		suffix4 = "W"
+	default:
+		panic(fmt.Sprintf("goarch=%s not supported", *goarch))
+	}
+
+	fmt.Fprintf(buf, "TEXT ·%s(SB),NOSPLIT,$%d-%d\n", call.sysname(), frameSize, argSize+retSize)
+
+	if _, ok := blockingSyscalls[call.name]; ok {
+		fmt.Fprintf(buf, "\tCALL runtime·entersyscall(SB)\n")
+	}
+	off := 0
+	for i, arg := range call.args {
+		name := arg.aname
+		suffix := suffix8
+		t := arg.atype
+		if typeSize(t) == 4 {
+			suffix = suffix4
+		}
+		sz := typeSize(t)
+		if *goarch == "arm64" && sz == 1 {
+			sz = 8
+		}
+		for off%sz != 0 {
+			// Add padding until the offset is aligned to the type we are accessing
+			off++
+		}
+
+		fmt.Fprintf(buf, "\tMOV%s %s+%d(FP), %s\n", suffix, name, off, regArgs[i])
+		off += sz
+	}
+	switch *goarch {
+	case "amd64":
+		if len(call.args) >= 7 {
+			fmt.Fprintf(buf, "\tMOVQ SP, BP   // BP is preserved across vsdo call by the x86-64 ABI\n")
+			fmt.Fprintf(buf, "\tANDQ $~15, SP // stack alignment for x86-64 ABI\n")
+			if len(call.args) == 8 {
+				fmt.Fprintf(buf, "\tPUSHQ R13\n")
+			}
+			fmt.Fprintf(buf, "\tPUSHQ R12\n")
+		}
+		fmt.Fprintf(buf, "\tMOVQ vdso_zx_%s(SB), AX\n", call.name)
+		fmt.Fprintf(buf, "\tCALL AX\n")
+		if len(call.args) >= 7 {
+			fmt.Fprintf(buf, "\tPOPQ R12\n")
+			if len(call.args) == 8 {
+				fmt.Fprintf(buf, "\tPOPQ R13\n")
+			}
+			fmt.Fprintf(buf, "\tMOVQ BP, SP\n")
+		}
+	case "arm64":
+		fmt.Fprintf(buf, "\tBL vdso_zx_%s(SB)\n", call.name)
+	}
+	if retSize := typeSize(call.ret); retSize > 0 {
+		suffix := suffix8
+		if retSize == 4 {
+			suffix = suffix4
+		}
+		fmt.Fprintf(buf, "\tMOV%s %s, ret+%d(FP)\n", suffix, retReg, argSize)
+	}
+	if _, ok := blockingSyscalls[call.name]; ok {
+		fmt.Fprintf(buf, "\t%s runtime·exitsyscall(SB)\n", callIns)
+	}
+	fmt.Fprintf(buf, "\tRET\n")
+}
+
+func typeSize(t zirconType) int {
+	regSize := 8
+	if *goarch == "arm" {
+		regSize = 4
+	}
+	if t.isArray {
+		return regSize
+	}
+	switch t.named {
+	case zx_function_pointer:
+		return regSize
+	case zx_void:
+		return 0
+	case zx_any:
+		return 0
+	case zx_bool:
+		return 1
+	case zx_int, zx_uint, zx_uintptr_t, zx_size_t:
+		return regSize
+	case zx_char, zx_uint8_t:
+		return 1
+	case zx_int16_t, zx_uint16_t:
+		return 2
+	case zx_int32_t, zx_uint32_t:
+		return 4
+	case zx_int64_t, zx_uint64_t:
+		return 8
+	case zx_status_t:
+		return 4
+	case zx_clock_t:
+		return 4
+	case zx_time_t:
+		return 8
+	case zx_duration_t:
+		return 8
+	case zx_koid_t:
+		return 8
+	case zx_handle_t:
+		return 4
+	case zx_signals_t:
+		return 4
+	case zx_rights_t:
+		return 4
+	case zx_vaddr_t, zx_paddr_t:
+		return regSize
+	case zx_process_info_t:
+		panic("cannot pass zx_process_info_t")
+	case zx_exception_status_t, zx_exception_behaviour_t:
+		return 4
+	default:
+		panic(fmt.Sprintf("UNKNOWN(%s)", t.named))
+	}
+}
+
+func printGoType(buf *bytes.Buffer, t zirconType) {
+	if t.isArray {
+		if t.named == zx_any {
+			fmt.Fprint(buf, "unsafe.Pointer")
+			return
+		}
+		fmt.Fprint(buf, "*")
+	}
+	switch t.named {
+	case zx_void:
+		fmt.Fprint(buf, "BAD(void)")
+	case zx_any:
+		fmt.Fprint(buf, "BAD(any)")
+	case zx_bool:
+		fmt.Fprint(buf, "bool")
+	case zx_uint:
+		fmt.Fprint(buf, "uint")
+	case zx_int:
+		fmt.Fprint(buf, "int")
+	case zx_char, zx_uint8_t:
+		fmt.Fprint(buf, "uint8")
+	case zx_int16_t:
+		fmt.Fprint(buf, "int16")
+	case zx_uint16_t:
+		fmt.Fprint(buf, "uint16")
+	case zx_int32_t:
+		fmt.Fprint(buf, "int32")
+	case zx_uint32_t:
+		fmt.Fprint(buf, "uint32")
+	case zx_int64_t:
+		fmt.Fprint(buf, "int64")
+	case zx_uint64_t:
+		fmt.Fprint(buf, "uint64")
+	case zx_uintptr_t:
+		fmt.Fprint(buf, "uintptr")
+	case zx_status_t:
+		fmt.Fprint(buf, "Status")
+	case zx_clock_t:
+		fmt.Fprint(buf, "Clock")
+	case zx_time_t:
+		fmt.Fprint(buf, "Time")
+	case zx_duration_t:
+		fmt.Fprint(buf, "Duration")
+	case zx_koid_t:
+		fmt.Fprint(buf, "Koid")
+	case zx_handle_t:
+		fmt.Fprint(buf, "Handle")
+	case zx_signals_t:
+		fmt.Fprint(buf, "Signals")
+	case zx_wait_item_t:
+		fmt.Fprint(buf, "WaitItem")
+	case zx_rights_t:
+		fmt.Fprint(buf, "Rights")
+	case zx_vaddr_t:
+		fmt.Fprint(buf, "Vaddr")
+	case zx_paddr_t:
+		fmt.Fprint(buf, "Paddr")
+	case zx_size_t:
+		fmt.Fprint(buf, "uint")
+	case zx_process_info_t:
+		fmt.Fprint(buf, "ProcessInfo")
+	case zx_exception_status_t:
+		fmt.Fprint(buf, "ExceptionStatus")
+	case zx_exception_behaviour_t:
+		fmt.Fprint(buf, "ExceptionBehaviour")
+	case zx_rrec_t:
+		fmt.Fprint(buf, "Rrec")
+	case zx_channel_call_args_t:
+		fmt.Fprint(buf, "ChannelCallArgs")
+	case zx_fifo_state_t:
+		fmt.Fprint(buf, "FIFOState")
+	case zx_smc_parameters_t:
+		fmt.Fprint(buf, "SMCParameters")
+	case zx_smc_result_t:
+		fmt.Fprint(buf, "SMCResult")
+	default:
+		panic(fmt.Sprintf("UNKNOWN type: %s", t.named))
+	}
+}
+
+func (p *parser) parse() (syscalls []zirconSyscallDef, err error) {
+	if len(p.buf) == 0 {
+		return syscalls, nil
+	}
+
+	p.nextRune()
+	for {
+		t, lit := p.nextToken()
+		if lit == "syscall" {
+			call, err := p.parseSyscall()
+			if err != nil {
+				return nil, err
+			}
+			if strings.Contains(call.name, "_test") {
+				continue
+			}
+			// The PCI syscalls are DDK-only and temporary, so exclude generation of
+			// helpers for them
+			if strings.HasPrefix(call.name, "pci_") {
+				continue
+			}
+			// The hypervisor syscalls have complex parameter and return types. Skip
+			// generation for these until we need them.
+			if strings.HasPrefix(call.name, "guest_") || strings.HasPrefix(call.name, "vcpu_") {
+				continue
+			}
+			syscalls = append(syscalls, call)
+			continue
+		}
+		if t == tokenEOF {
+			return syscalls, nil
+		}
+		if t == tokenBad {
+			return nil, p.errorf("bad token: %s", lit)
+		}
+		return nil, p.errorf("unexpected token: %q (literal %q)", t, lit)
+	}
+}
+
+func (p *parser) expect(want token) {
+	t, lit := p.nextToken()
+	if t != want {
+		p.panicf("expected %q but got %q (literal %q)", want, t, lit)
+	}
+}
+
+func (p *parser) parseAttributes() (attr []string, err error) {
+	for {
+		p.skipWhitespace()
+		if p.r == '(' {
+			return
+		}
+		attr = append(attr, p.nextIdent())
+		p.skipWhitespace()
+		if p.r == ',' {
+			p.nextRune()
+		}
+	}
+}
+
+func (p *parser) parseArg() (arg zirconArg, err error) {
+	if p.r == ')' {
+		return
+	}
+	arg.aname = p.nextIdent()
+	p.expect(':')
+	atype, err := p.parseType()
+	if err != nil {
+		return
+	}
+	arg.atype = atype
+	p.skipWhitespace()
+	if isLetter(p.r) {
+		arg.constraint = p.nextIdent()
+		p.skipWhitespace()
+	}
+	return
+}
+
+func (p *parser) parseSyscall() (call zirconSyscallDef, err error) {
+	call.name = p.nextIdent()
+	attr, err := p.parseAttributes()
+	if err != nil {
+		return zirconSyscallDef{}, err
+	}
+	for _, a := range attr {
+		if a == "vdsocall" {
+			call.vdsocall = true
+		}
+	}
+	call.attr = attr
+	p.expect('(')
+	for {
+		p.skipWhitespace()
+		if p.r == ')' {
+			p.nextRune()
+			break
+		}
+		arg, err := p.parseArg()
+		if err != nil {
+			return zirconSyscallDef{}, err
+		}
+		if arg.aname == "" {
+			break
+		}
+		call.args = append(call.args, arg)
+		if p.r == ',' {
+			p.nextRune()
+		}
+	}
+	p.skipWhitespace()
+	if p.r != ';' {
+		kw := p.nextIdent()
+		if kw != "returns" {
+			p.panicf("expected \"returns\" but got \"%s\"", kw)
+		}
+		p.expect('(')
+		first := true
+		for {
+			p.skipWhitespace()
+			if p.r == ')' {
+				p.nextRune()
+				break
+			}
+			if first {
+				first = false
+				rtype, err := p.parseType()
+				if err != nil {
+					return zirconSyscallDef{}, err
+				}
+				call.ret = rtype
+			} else {
+				arg, err := p.parseArg()
+				if err != nil {
+					return zirconSyscallDef{}, err
+				}
+				// Extra return types are returned as pointers.
+				arg.atype.isArray = true
+				arg.atype.arraySize = "1"
+				call.args = append(call.args, arg)
+			}
+			if p.r == ',' {
+				p.nextRune()
+			}
+		}
+	}
+	p.skipWhitespace()
+	p.expect(';')
+	return call, nil
+}
+
+func (p *parser) parseType() (t zirconType, err error) {
+	ident := p.nextIdent()
+	n, ok := zirconTypeNamedStr[ident]
+	if !ok {
+		return t, p.errorf("unknown type name: %s", ident)
+	}
+	t.named = n
+	p.skipWhitespace()
+	if p.r == '[' {
+		p.nextRune()
+		t.isArray = true
+		t.arraySize = p.nextIdent()
+		p.skipWhitespace()
+		for p.r == '*' {
+			p.nextRune()
+			t.arraySize += " * " + p.nextIdent()
+		}
+		p.expect(']')
+	}
+	return t, nil
+}
+
+type parser struct {
+	buf       []byte
+	off       int
+	line, col int
+	name      string
+
+	r rune
+}
+
+type token rune
+
+const (
+	tokenEOF    token = -1
+	tokenBad    token = -2
+	tokenIdent  token = -3
+	tokenNumber token = -4
+)
+
+func (t token) String() string {
+	switch t {
+	case tokenEOF:
+		return "token(EOF)"
+	case tokenBad:
+		return "token(BAD)"
+	case tokenIdent:
+		return "token(Ident)"
+	case tokenNumber:
+		return "token(Number)"
+	default:
+		return "token(" + string(t) + ")"
+	}
+}
+
+func (p *parser) nextToken() (t token, lit string) {
+	p.skipWhitespace()
+
+	if isLetter(p.r) {
+		lit = p.nextIdent()
+		return tokenIdent, lit
+	}
+	if isNumber(p.r) {
+		lit = p.nextNumber()
+		return tokenNumber, lit
+	}
+
+	r := p.r
+	p.nextRune()
+	switch r {
+	case -1:
+		return tokenEOF, ""
+	case '(', ')', '*', ',', ';', ':', '[', ']':
+		return token(r), ""
+	case '#':
+		p.skipComment()
+		return p.nextToken()
+	}
+	return tokenBad, fmt.Sprintf("%q", r)
+}
+
+func (p *parser) nextIdent() string {
+	p.skipWhitespace()
+	if !isLetter(p.r) && !isNumber(p.r) {
+		p.panicf("expected ident but got %q", p.r)
+	}
+	off := p.off - 1
+	for isLetter(p.r) || isNumber(p.r) {
+		p.nextRune()
+	}
+	r := string(p.buf[off : p.off-1])
+	if r == "type" {
+		// "type" is a reserved word in Go.
+		return "typ"
+	}
+	return r
+}
+
+func (p *parser) nextNumber() string {
+	p.skipWhitespace()
+	if !isNumber(p.r) {
+		p.panicf("expected number but got %q", p.r)
+	}
+	off := p.off - 1
+	for isNumber(p.r) {
+		p.nextRune()
+	}
+	return string(p.buf[off : p.off-1])
+}
+
+func (p *parser) skipWhitespace() {
+	for p.r == ' ' || p.r == '\t' || p.r == '\n' {
+		p.nextRune()
+	}
+}
+
+func (p *parser) skipComment() {
+	// skip until end of line
+	p.nextRune()
+	for p.r != '\n' && p.r >= 0 {
+		p.nextRune()
+	}
+}
+
+func (p *parser) nextRune() {
+	if p.off >= len(p.buf) {
+		p.r = -1
+		return
+	}
+	if p.r == '\n' {
+		p.line++
+		p.col = 0
+	} else {
+		p.col += utf8.RuneLen(p.r)
+	}
+
+	r, w := utf8.DecodeRune(p.buf[p.off:])
+	if r == utf8.RuneError && w == 1 {
+		p.r = -1
+		p.panicf("input is not UTF-8")
+		return
+	}
+	p.r = r
+	p.off += w
+}
+
+func (p *parser) panicf(format string, args ...interface{}) {
+	panic(parsePanic{err: p.errorf(format, args...)})
+}
+
+func (p *parser) errorf(format string, args ...interface{}) error {
+	return fmt.Errorf("%s:%d:%d: %s", p.name, p.line, p.col, fmt.Sprintf(format, args...))
+}
+
+func isLetter(r rune) bool { return 'a' <= r && r <= 'z' || 'A' <= r && r <= 'Z' || r == '_' }
+func isNumber(r rune) bool { return '0' <= r && r <= '9' }
+
+type parsePanic struct {
+	err error
+}
+
+func (pp parsePanic) String() string { return pp.err.Error() }
+
+type zirconArg struct {
+	aname      string
+	atype      zirconType
+	constraint string
+}
+
+type zirconSyscallDef struct {
+	name     string
+	ret      zirconType
+	attr     []string
+	args     []zirconArg
+	vdsocall bool
+}
+
+func (call zirconSyscallDef) sysname() string {
+	if call.exported() {
+		return "Sys_" + call.name
+	}
+	return "sys_" + call.name
+}
+
+func (call zirconSyscallDef) exported() bool {
+	switch call.name {
+	case "handle_duplicate",
+		"object_set_profile",
+		"object_wait_many",
+		"channel_create",
+		"channel_read",
+		"channel_read_etc",
+		"channel_write",
+		"pci_get_bar",
+		"pci_map_interrupt",
+		"pci_query_irq_mode",
+		"pci_set_irq_mode",
+		"pci_init",
+		"pci_add_subtract_to_range",
+		"socket_create",
+		"socket_read",
+		"socket_write",
+		"socket_accept",
+		"socket_share",
+		"system_get_dcache_line_size",
+		"system_get_features",
+		"vmar_allocate",
+		"vmar_allocate_old",
+		"vmar_destroy",
+		"vmar_map_old",
+		"vmar_protect_old",
+		"vmo_read",
+		"vmo_write",
+		"vmo_get_size",
+		"vmo_set_size",
+		"vmo_op_range":
+		return false
+	default:
+		return true
+	}
+}
+
+type zirconType struct {
+	named     zirconTypeNamed
+	isArray   bool
+	arraySize string
+}
+
+type zirconTypeNamed int
+
+const (
+	zx_void zirconTypeNamed = iota
+	zx_any
+	zx_bool
+	zx_uint
+	zx_int
+	zx_char
+	zx_uint8_t
+	zx_int16_t
+	zx_uint16_t
+	zx_int32_t
+	zx_uint32_t
+	zx_int64_t
+	zx_uint64_t
+	zx_uintptr_t
+	zx_size_t
+	zx_status_t
+	zx_clock_t
+	zx_time_t
+	zx_duration_t
+	zx_koid_t
+	zx_handle_t
+	zx_signals_t
+	zx_signals_state_t
+	zx_smc_parameters_t
+	zx_smc_result_t
+	zx_wait_item_t
+	zx_rights_t
+	zx_vaddr_t
+	zx_paddr_t
+	zx_process_info_t
+	zx_exception_status_t
+	zx_exception_behaviour_t
+	zx_function_pointer
+	zx_rrec_t
+	zx_channel_call_args_t
+	zx_fifo_state_t
+)
+
+var zirconTypeNamedStr = map[string]zirconTypeNamed{
+	"any":                      zx_any,
+	"void":                     zx_void,
+	"bool":                     zx_bool,
+	"unsigned int":             zx_uint,
+	"int":                      zx_int,
+	"char":                     zx_char,
+	"uint8_t":                  zx_uint8_t,
+	"int16_t":                  zx_int16_t,
+	"int32_t":                  zx_int32_t,
+	"int64_t":                  zx_int64_t,
+	"uint16_t":                 zx_uint16_t,
+	"uint32_t":                 zx_uint32_t,
+	"uint64_t":                 zx_uint64_t,
+	"uintptr_t":                zx_uintptr_t,
+	"size_t":                   zx_size_t,
+	"zx_status_t":              zx_status_t, // int32_t
+	"zx_clock_t":               zx_uint32_t,
+	"zx_time_t":                zx_time_t,     // uint64_t monotonic time
+	"zx_duration_t":            zx_duration_t, // uint64_t nanoseconds
+	"zx_koid_t":                zx_koid_t,
+	"zx_handle_t":              zx_handle_t, // int32_t
+	"zx_futex_t":               zx_int,
+	"zx_signals_t":             zx_signals_t,
+	"zx_signals_state_t":       zx_signals_state_t,
+	"zx_wait_item_t":           zx_wait_item_t,
+	"zx_rights_t":              zx_rights_t,
+	"zx_vaddr_t":               zx_vaddr_t,
+	"zx_paddr_t":               zx_paddr_t,
+	"zx_smc_parameters_t":      zx_smc_parameters_t,
+	"zx_smc_result_t":          zx_smc_result_t,
+	"zx_process_info_t":        zx_process_info_t,
+	"zx_exception_status_t":    zx_exception_status_t,
+	"zx_exception_behaviour_t": zx_exception_behaviour_t,
+	"zx_function_pointer":      zx_function_pointer,
+	"zx_rrec_t":                zx_rrec_t,
+	"zx_channel_call_args_t":   zx_channel_call_args_t,
+	"zx_fifo_state_t":          zx_fifo_state_t,
+	// TODO(smklein): Remove the following temporary types. They could be blacklisted, but this is
+	// easier.
+	"zx_cache_policy_t":        zx_int,
+	"zx_port_packet_t":         zx_int,
+	"zx_pci_init_arg_t":        zx_int,
+	"zx_pci_irq_mode_t":        zx_int,
+	"zx_pci_resource_t":        zx_int,
+	"zx_pcie_device_info_t":    zx_int,
+	"zx_pcie_get_nth_info_t":   zx_int,
+	"zx_vcpu_create_args_t":    zx_int,
+	"zx_system_powerctl_arg_t": zx_int,
+	"zx_handle_info_t":         zx_int,
+	"zx_profile_info_t":        zx_int,
+	"zx_pci_bar_t":             zx_int,
+}
diff --git a/src/syscall/zx/mxerror/mxerror.go b/src/syscall/zx/mxerror/mxerror.go
new file mode 100644
index 0000000..87d0437
--- /dev/null
+++ b/src/syscall/zx/mxerror/mxerror.go
@@ -0,0 +1,46 @@
+// Copyright 2017 The Go 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 fuchsia
+
+package mxerror
+
+import (
+	"fmt"
+	"syscall/zx"
+)
+
+// Status extracts an zx.Status from an error.
+func Status(err error) zx.Status {
+	if err == nil {
+		return zx.ErrOk
+	}
+	if s, hasStatus := err.(zx.Error); hasStatus {
+		return s.Status
+	}
+	return zx.ErrInternal
+}
+
+// Prependf prepends a format string onto an error.
+// If the error is an zx.Error, the status code is retained.
+func Prependf(err error, format string, args ...interface{}) error {
+	str := fmt.Sprintf(format, args...)
+	if e, isError := err.(zx.Error); isError {
+		if e.Text == "" {
+			e.Text = str
+		} else {
+			e.Text = str + ": " + e.Text
+		}
+		return e
+	}
+	return fmt.Errorf("%s: %v", str, err)
+}
+
+// Errorf creates an error with an zx.Status code.
+func Errorf(s zx.Status, format string, args ...interface{}) error {
+	return zx.Error{
+		Status: s,
+		Text:   fmt.Sprintf(format, args...),
+	}
+}
diff --git a/src/syscall/zx/mxnet/ctypes.go b/src/syscall/zx/mxnet/ctypes.go
new file mode 100644
index 0000000..5c1c6c9
--- /dev/null
+++ b/src/syscall/zx/mxnet/ctypes.go
@@ -0,0 +1,153 @@
+// Copyright 2017 The Go 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 fuchsia
+
+package mxnet
+
+// Types from <lib/fdio/socket.h>.
+// These were extracted from cgo by building the program:
+//
+//	package typesextract
+//
+//	// #include <arpa/inet.h>
+//	// #include <netdb.h>
+//	// #include <netinet/in.h>
+//	// #include <netinet/tcp.h>
+//	// #include <sys/ioctl.h>
+//	// #include <sys/socket.h>
+//	// #include <sys/types.h>
+//	// #include <lib/fdio/socket.h>
+//	import "C"
+//
+//	func F() {
+//		_ = C.struct_addrinfo{}
+//		_ = C.struct_sockaddr_in{}
+//		_ = C.struct_sockaddr_in6{}
+//		_ = C.struct_mxrio_gai_req{}
+//		_ = C.struct_mxrio_gai_reply{}
+//		_ = C.struct_mxrio_sockaddr_reply{}
+//		_ = C.struct_mxrio_sockopt_req_reply{}
+//		_ = C.struct_fdio_socket_msg{}
+//		_ = C.AF_INET
+//		_ = C.AF_INET6
+//		_ = C.MXRIO_GAI_REQ_NODE_MAXLEN
+//		_ = C.MXRIO_GAI_REQ_SERVICE_MAXLEN
+//		_ = C.MXRIO_GAI_REPLY_MAX
+//	}
+//
+// Then the names were cleaned up manually, with commands like:
+//	s/_t$//
+//	s/_Ctype_struct_/c_/
+//	s/_Ctype_/c_/
+//	...
+//
+// Two big changes are c_in_port and c_in_addr, which for historcical
+// UNIX reasons have terrible type representations, so we treat them
+// as byte arrays.
+//
+// This will probably all be FIDL one day.
+
+const SOCK_STREAM = 1
+const SOCK_DGRAM = 2
+
+const AF_INET = 2
+const AF_INET6 = 10
+
+const MXRIO_GAI_REQ_NODE_MAXLEN = 256
+const MXRIO_GAI_REQ_SERVICE_MAXLEN = 256
+const MXRIO_GAI_REPLY_MAX = 4
+
+type c_socklen uint32
+type c_in_port [2]byte // uint16 in C, but stored in network order
+type c_sa_family uint16
+type c_in_addr [4]byte // uint32 in C, but stored in network order
+type c_ulong uint64
+
+type c_addrinfo struct {
+	ai_flags    int32
+	ai_family   int32
+	ai_socktype int32
+	ai_protocol int32
+	ai_addrlen  c_socklen
+	_           [4]byte
+	// The following pointers are unused on the wire.
+	ai_addr      uintptr // *c_sockaddr
+	ai_canonname uintptr // *int8
+	ai_next      uintptr // *c_addrinfo
+}
+
+type c_mxrio_gai_reply struct {
+	res [MXRIO_GAI_REPLY_MAX]struct {
+		ai   c_addrinfo
+		addr c_sockaddr_storage
+	}
+	nres   int32
+	retval int32
+}
+
+type c_mxrio_gai_req struct {
+	node_is_null    uint8
+	service_is_null uint8
+	hints_is_null   uint8
+	reserved        uint8
+	reserved2       uint32
+	node            [MXRIO_GAI_REQ_NODE_MAXLEN]uint8
+	service         [MXRIO_GAI_REQ_SERVICE_MAXLEN]uint8
+	hints           c_addrinfo
+}
+
+type c_mxrio_sockaddr_reply struct {
+	addr c_sockaddr_storage
+	len  c_socklen
+	_    [4]byte
+}
+
+type c_mxrio_sockopt_req_reply struct {
+	level   int32
+	optname int32
+	optval  [8]uint8
+	optlen  c_socklen
+}
+
+type c_sockaddr struct {
+	sa_family c_sa_family
+	sa_data   [14]uint8
+}
+
+type c_sockaddr_in struct {
+	sin_family c_sa_family
+	sin_port   c_in_port // network order
+	sin_addr   c_in_addr
+	sin_zero   [8]uint8
+}
+
+type c_in6_addr [16]byte
+
+type c_sockaddr_in6 struct {
+	sin6_family   c_sa_family
+	sin6_port     c_in_port // network order
+	sin6_flowinfo uint32
+	sin6_addr     c_in6_addr
+	sin6_scope_id uint32
+}
+
+type c_sockaddr_storage struct {
+	ss_family    c_sa_family
+	_            [6]byte
+	__ss_align   c_ulong
+	__ss_padding [112]uint8
+}
+
+type c_fdio_socket_msg_hdr struct {
+	addr    c_sockaddr_storage
+	addrlen c_socklen
+	flags   int32
+}
+
+type c_fdio_socket_msg struct {
+	hdr  c_fdio_socket_msg_hdr
+	data [1]uint8
+	_    [7]byte
+}
diff --git a/src/syscall/zx/mxnet/mxnet.go b/src/syscall/zx/mxnet/mxnet.go
new file mode 100644
index 0000000..2c81b01
--- /dev/null
+++ b/src/syscall/zx/mxnet/mxnet.go
@@ -0,0 +1,154 @@
+// Copyright 2017 The Go 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 fuchsia
+
+// Package mxnet contains types for talking to Fuchsia's fdio net interface.
+package mxnet
+
+import (
+	"syscall/zx"
+	"unsafe"
+)
+
+const ZX_SOCKET_HALF_CLOSE = 1
+const ZX_SOCKET_READABLE = zx.SignalObject0
+const ZX_SOCKET_WRITABLE = zx.SignalObject1
+const ZX_SOCKET_PEER_CLOSED = zx.SignalObject2
+const MXSIO_SIGNAL_INCOMING = zx.SignalUser0
+const MXSIO_SIGNAL_OUTGOING = zx.SignalUser1
+const MXSIO_SIGNAL_CONNECTED = zx.SignalUser3
+const MXSIO_SIGNAL_HALFCLOSED = zx.SignalUser4
+
+// Addr is an IP address.
+// It has either len == 4 (if it is IPv4) or len == 16 (IPv6).
+type Addr string
+
+// TODO(crawshaw): consider cleaning up these interfaces by migrating to
+// an address type that captures everything:
+//
+//	type Address struct {
+//		Addr [16]byte
+//		IPv4 bool
+//		Port uint16
+//	}
+
+const SockaddrLen = c_sockaddr_in6_len
+const SockmsgHdrLen = c_fdio_socket_msg_hdr_len
+const SockaddrReplyLen = c_mxrio_sockaddr_reply_len
+
+func EncodeSockmsgHdr(dst []byte, addr Addr, port uint16, flags int) (err error) {
+	if len(dst) < SockmsgHdrLen {
+		return errString("mxnet.EncodeSockmsgHdr: dst too short")
+	}
+	var n int
+	if addr != "" || port != 0 {
+		n, err = EncodeSockaddr(dst, addr, port)
+		if err != nil {
+			return err
+		}
+	}
+	hdr := (*c_fdio_socket_msg_hdr)(unsafe.Pointer(&dst[0]))
+	hdr.addrlen = c_socklen(n)
+	hdr.flags = int32(flags)
+	return nil
+}
+
+func DecodeSockmsgHdr(src []byte) (addr Addr, port uint16, flags int, err error) {
+	if len(src) < SockmsgHdrLen {
+		return "", 0, 0, errString("mxnet.DecodeSockmsgHdr: src too short")
+	}
+	addr, port, err = DecodeSockaddr(src)
+	if err != nil {
+		return "", 0, 0, err
+	}
+	hdr := (*c_fdio_socket_msg_hdr)(unsafe.Pointer(&src[0]))
+	flags = int(hdr.flags)
+	return addr, port, flags, nil
+}
+
+func DecodeSockaddr(data []byte) (addr Addr, port uint16, err error) {
+	if len(data) < 2 {
+		return "", 0, errString("mxnet:DecodeSockaddr: data too short")
+	}
+	family := uint16(data[0]) | uint16(data[1])<<8
+	switch family {
+	case AF_INET:
+		if len(data) < int(unsafe.Sizeof(c_sockaddr_in{})) {
+			return "", 0, errString("mxnet:DecodeSockaddr: data too short for ipv4")
+		}
+		v := (*c_sockaddr_in)(unsafe.Pointer(&data[0]))
+		port = uint16(data[3]) | uint16(data[2])<<8
+		if !isZeros(v.sin_addr[:]) {
+			addr = Addr(v.sin_addr[:])
+		}
+		return addr, port, nil
+	case AF_INET6:
+		if len(data) < int(unsafe.Sizeof(c_sockaddr_in6{})) {
+			return "", 0, errString("mxnet:DecodeSockaddr: data too short for ipv6")
+		}
+		v := (*c_sockaddr_in6)(unsafe.Pointer(&data[0]))
+		port = uint16(data[3]) | uint16(data[2])<<8
+		if !isZeros(v.sin6_addr[:]) {
+			addr = Addr(v.sin6_addr[:])
+		}
+		return addr, port, nil
+	default:
+		return "", 0, errString("mxnet:DecodeSockaddr: unknown family")
+	}
+}
+
+func EncodeSockaddr(dst []byte, addr Addr, port uint16) (int, error) {
+	switch len(addr) {
+	case 0, 4:
+		if len(dst) < c_sockaddr_in_len {
+			return 0, errString("mxnet: dst too small for c_sockaddr_in")
+		}
+		sockaddr := c_sockaddr_in{sin_family: AF_INET}
+		sockaddr.sin_port.setPort(port)
+		copy(sockaddr.sin_addr[:], addr)
+		srcb := (*[unsafe.Sizeof(sockaddr)]byte)(unsafe.Pointer(&sockaddr))[:]
+		return copy(dst, srcb), nil
+	case 16:
+		if len(dst) < c_sockaddr_in_len {
+			return 0, errString("mxnet: dst too small for c_sockaddr_in6")
+		}
+		sockaddr := c_sockaddr_in6{sin6_family: AF_INET6}
+		sockaddr.sin6_port.setPort(port)
+		copy(sockaddr.sin6_addr[:], addr)
+		srcb := (*[unsafe.Sizeof(sockaddr)]byte)(unsafe.Pointer(&sockaddr))[:]
+		return copy(dst, srcb), nil
+	default:
+		return 0, errString("mxnet: bad address length")
+	}
+}
+
+type errString string
+
+func (err errString) Error() string { return string(err) }
+
+const (
+	c_sockaddr_in_len          = int(unsafe.Sizeof(c_sockaddr_in{}))
+	c_sockaddr_in6_len         = int(unsafe.Sizeof(c_sockaddr_in6{}))
+	c_fdio_socket_msg_hdr_len  = int(unsafe.Sizeof(c_fdio_socket_msg_hdr{}))
+	c_mxrio_sockaddr_reply_len = int(unsafe.Sizeof(c_mxrio_sockaddr_reply{}))
+)
+
+func (v c_in_port) port() uint16 {
+	return uint16(v[0])<<8 | uint16(v[1])
+}
+
+func (v *c_in_port) setPort(port uint16) {
+	v[0] = uint8(port >> 8)
+	v[1] = uint8(port)
+}
+
+func isZeros(buf []byte) bool {
+	for i := 0; i < len(buf); i++ {
+		if buf[i] != 0 {
+			return false
+		}
+	}
+	return true
+}
diff --git a/src/syscall/zx/mxruntime/mxruntime.go b/src/syscall/zx/mxruntime/mxruntime.go
new file mode 100644
index 0000000..39d3a4b
--- /dev/null
+++ b/src/syscall/zx/mxruntime/mxruntime.go
@@ -0,0 +1,29 @@
+// Copyright 2016 The Fuchsia 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 fuchsia
+
+// Package mxruntime provides access to FDIO process state.
+package mxruntime
+
+// TODO: move process handle globals from mx into mxruntime.
+
+import "syscall/zx"
+
+type HandleType uint16
+
+const (
+	HandleUser0 HandleType = 0xF0
+	HandleUser1 HandleType = 0xF1
+	HandleUser2 HandleType = 0xF2
+)
+
+type HandleInfo struct {
+	Type HandleType
+	Arg  uint16
+}
+
+func GetStartupHandle(info HandleInfo) zx.Handle {
+	return getStartupHandle(info)
+}
diff --git a/src/syscall/zx/mxruntime/mxruntime_cgo.go b/src/syscall/zx/mxruntime/mxruntime_cgo.go
new file mode 100644
index 0000000..af77ab1
--- /dev/null
+++ b/src/syscall/zx/mxruntime/mxruntime_cgo.go
@@ -0,0 +1,18 @@
+// Copyright 2016 The Fuchsia 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 fuchsia
+
+package mxruntime
+
+import "syscall/zx"
+
+// #include "zircon/process.h"
+import "C"
+
+func getStartupHandle(info HandleInfo) zx.Handle {
+	id := uint32(info.Arg)<<16 | uint32(info.Type)
+	h := C.zx_take_startup_handle(C.uint32_t(id))
+	return zx.Handle(h)
+}
diff --git a/src/syscall/zx/mxruntime/mxruntime_stubs.go b/src/syscall/zx/mxruntime/mxruntime_stubs.go
new file mode 100644
index 0000000..3edf16d
--- /dev/null
+++ b/src/syscall/zx/mxruntime/mxruntime_stubs.go
@@ -0,0 +1,12 @@
+// Copyright 2016 The Fuchsia 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 fuchsia
+// +build !cgo
+
+package mxruntime
+
+func getStartupHandle(info HandleInfo) zx.Handle {
+	panic("mxruntime.GetStartupHandle not implemented")
+}
diff --git a/src/syscall/zx/net/impl.go b/src/syscall/zx/net/impl.go
new file mode 100644
index 0000000..0934a9b
--- /dev/null
+++ b/src/syscall/zx/net/impl.go
@@ -0,0 +1,447 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+//
+// WARNING: This file is machine generated by fidlgen.
+
+// +build fuchsia
+
+package net
+
+import (
+	_bindings "syscall/zx/fidl"
+	_zx "syscall/zx"
+)
+
+const (
+)
+
+type SocketDomain uint32
+const (
+	SocketDomainInet SocketDomain = 2
+	SocketDomainInet6 SocketDomain = 10
+)
+type SocketType uint32
+const (
+	SocketTypeStream SocketType = 1
+	SocketTypeDgram SocketType = 2
+)
+type SocketProtocol uint32
+const (
+	SocketProtocolIp SocketProtocol = 0
+	SocketProtocolIcmp SocketProtocol = 1
+	SocketProtocolTcp SocketProtocol = 6
+	SocketProtocolUdp SocketProtocol = 17
+	SocketProtocolIpv6 SocketProtocol = 41
+	SocketProtocolIcmpv6 SocketProtocol = 58
+)
+type AddrInfoStatus uint32
+const (
+	AddrInfoStatusOk AddrInfoStatus = 0
+	AddrInfoStatusBadFlags AddrInfoStatus = 1
+	AddrInfoStatusNoName AddrInfoStatus = 2
+	AddrInfoStatusAgain AddrInfoStatus = 3
+	AddrInfoStatusFail AddrInfoStatus = 4
+	AddrInfoStatusNoData AddrInfoStatus = 5
+	AddrInfoStatusBufferOverflow AddrInfoStatus = 6
+	AddrInfoStatusSystemError AddrInfoStatus = 7
+)
+type IPv4Address struct {
+	Addr [4]uint8 
+}
+
+// Implements Payload.
+func (_ *IPv4Address) InlineAlignment() int {
+	return 1
+}
+
+// Implements Payload.
+func (_ *IPv4Address) InlineSize() int {
+	return 4
+}
+type IPv6Address struct {
+	Addr [16]uint8 
+}
+
+// Implements Payload.
+func (_ *IPv6Address) InlineAlignment() int {
+	return 1
+}
+
+// Implements Payload.
+func (_ *IPv6Address) InlineSize() int {
+	return 16
+}
+type Subnet struct {
+	Addr IpAddress 
+	PrefixLen uint8 
+}
+
+// Implements Payload.
+func (_ *Subnet) InlineAlignment() int {
+	return 4
+}
+
+// Implements Payload.
+func (_ *Subnet) InlineSize() int {
+	return 24
+}
+type MacAddress struct {
+	Addr [6]uint8 
+}
+
+// Implements Payload.
+func (_ *MacAddress) InlineAlignment() int {
+	return 1
+}
+
+// Implements Payload.
+func (_ *MacAddress) InlineSize() int {
+	return 6
+}
+type String struct {
+	Val [256]uint8 
+	Len uint32 
+}
+
+// Implements Payload.
+func (_ *String) InlineAlignment() int {
+	return 4
+}
+
+// Implements Payload.
+func (_ *String) InlineSize() int {
+	return 260
+}
+type AddrInfoHints struct {
+	Flags int32 
+	Family int32 
+	SockType int32 
+	Protocol int32 
+}
+
+// Implements Payload.
+func (_ *AddrInfoHints) InlineAlignment() int {
+	return 4
+}
+
+// Implements Payload.
+func (_ *AddrInfoHints) InlineSize() int {
+	return 16
+}
+type AddrStorage struct {
+	Val [16]uint8 
+	Len uint32 
+}
+
+// Implements Payload.
+func (_ *AddrStorage) InlineAlignment() int {
+	return 4
+}
+
+// Implements Payload.
+func (_ *AddrStorage) InlineSize() int {
+	return 20
+}
+type AddrInfo struct {
+	Flags int32 
+	Family int32 
+	SockType int32 
+	Protocol int32 
+	IpAddr AddrStorage 
+	Port uint16 
+}
+
+// Implements Payload.
+func (_ *AddrInfo) InlineAlignment() int {
+	return 4
+}
+
+// Implements Payload.
+func (_ *AddrInfo) InlineSize() int {
+	return 40
+}
+type IpAddressTag uint32
+const (
+	IpAddressIpv4 IpAddressTag = iota
+	IpAddressIpv6 IpAddressTag = iota
+)
+
+// IpAddress is a FIDL union.
+type IpAddress struct {
+	IpAddressTag `fidl:"tag"`
+	Ipv4 IPv4Address 
+	Ipv6 IPv6Address 
+}
+
+// Implements Payload.
+func (_ *IpAddress) InlineAlignment() int {
+	return 4
+}
+
+// Implements Payload.
+func (_ *IpAddress) InlineSize() int {
+	return 20
+}
+
+func (u *IpAddress) Which() IpAddressTag {
+	return u.IpAddressTag
+}
+
+func (u *IpAddress) SetIpv4(ipv4 IPv4Address) {
+	u.IpAddressTag = IpAddressIpv4
+	u.Ipv4 = ipv4
+}
+
+func (u *IpAddress) SetIpv6(ipv6 IPv6Address) {
+	u.IpAddressTag = IpAddressIpv6
+	u.Ipv6 = ipv6
+}
+const (
+	ConnectivityOnNetworkReachableOrdinal uint32 = 1
+)
+// Request for OnNetworkReachable.
+// OnNetworkReachable has no request.
+// Response for OnNetworkReachable.
+type ConnectivityOnNetworkReachableResponse struct {
+	Reachable bool 
+}
+
+// Implements Payload.
+func (_ *ConnectivityOnNetworkReachableResponse) InlineAlignment() int {
+	return 0
+}
+
+// Implements Payload.
+func (_ *ConnectivityOnNetworkReachableResponse) InlineSize() int {
+	return 4
+}
+
+type ConnectivityInterface _bindings.Proxy
+
+func (p *ConnectivityInterface) ExpectOnNetworkReachable() (bool, error) {
+	resp_ := ConnectivityOnNetworkReachableResponse{}
+	err := ((*_bindings.Proxy)(p)).Recv(ConnectivityOnNetworkReachableOrdinal, &resp_)
+	return resp_.Reachable, err
+}
+
+// Connectivity server interface.
+type Connectivity interface {
+}
+
+type ConnectivityInterfaceRequest _bindings.InterfaceRequest
+
+func NewConnectivityInterfaceRequest() (ConnectivityInterfaceRequest, *ConnectivityInterface, error) {
+	req, cli, err := _bindings.NewInterfaceRequest()
+	return ConnectivityInterfaceRequest(req), (*ConnectivityInterface)(cli), err
+}
+// Implements ServiceRequest.
+func (_ ConnectivityInterfaceRequest) Name() string {
+	return "fuchsia.net.Connectivity"
+}
+func (c ConnectivityInterfaceRequest) ToChannel() _zx.Channel {
+	return c.Channel
+}
+
+const ConnectivityName = "fuchsia.net.Connectivity"
+
+type ConnectivityStub struct {
+	Impl Connectivity
+}
+
+func (s *ConnectivityStub) Dispatch(ord uint32, b_ []byte, h_ []_zx.Handle) (_bindings.Payload, error) {
+	switch ord {
+	}
+	return nil, _bindings.ErrUnknownOrdinal
+}
+
+type ConnectivityService struct {
+	_bindings.BindingSet
+}
+
+func (s *ConnectivityService) Add(impl Connectivity, c _zx.Channel, onError func(error)) (_bindings.BindingKey, error) {
+	return s.BindingSet.Add(&ConnectivityStub{Impl: impl}, c, onError)
+}
+
+func (s *ConnectivityService) EventProxyFor(key _bindings.BindingKey) (*ConnectivityEventProxy, bool) {
+	pxy, err := s.BindingSet.ProxyFor(key)
+	return (*ConnectivityEventProxy)(pxy), err
+}
+
+type ConnectivityEventProxy _bindings.Proxy
+
+func (p *ConnectivityEventProxy) OnNetworkReachable(reachable bool) error {
+	event_ := ConnectivityOnNetworkReachableResponse{
+		Reachable: reachable,
+	}
+	return ((*_bindings.Proxy)(p)).Send(ConnectivityOnNetworkReachableOrdinal, &event_)
+}
+
+
+const (
+	LegacySocketProviderOpenSocketOrdinal uint32 = 1
+	LegacySocketProviderGetAddrInfoOrdinal uint32 = 2
+)
+// Request for OpenSocket.
+type LegacySocketProviderOpenSocketRequest struct {
+	Domain SocketDomain 
+	Type SocketType 
+	Protocol SocketProtocol 
+}
+
+// Implements Payload.
+func (_ *LegacySocketProviderOpenSocketRequest) InlineAlignment() int {
+	return 0
+}
+
+// Implements Payload.
+func (_ *LegacySocketProviderOpenSocketRequest) InlineSize() int {
+	return 12
+}
+// Response for OpenSocket.
+type LegacySocketProviderOpenSocketResponse struct {
+	S _zx.Socket 
+	Status int32 
+}
+
+// Implements Payload.
+func (_ *LegacySocketProviderOpenSocketResponse) InlineAlignment() int {
+	return 0
+}
+
+// Implements Payload.
+func (_ *LegacySocketProviderOpenSocketResponse) InlineSize() int {
+	return 8
+}
+// Request for GetAddrInfo.
+type LegacySocketProviderGetAddrInfoRequest struct {
+	Node *String 
+	Service *String 
+	Hints *AddrInfoHints 
+}
+
+// Implements Payload.
+func (_ *LegacySocketProviderGetAddrInfoRequest) InlineAlignment() int {
+	return 0
+}
+
+// Implements Payload.
+func (_ *LegacySocketProviderGetAddrInfoRequest) InlineSize() int {
+	return 24
+}
+// Response for GetAddrInfo.
+type LegacySocketProviderGetAddrInfoResponse struct {
+	Status AddrInfoStatus 
+	Nres int32 
+	Ai0 *AddrInfo 
+	Ai1 *AddrInfo 
+	Ai2 *AddrInfo 
+	Ai3 *AddrInfo 
+}
+
+// Implements Payload.
+func (_ *LegacySocketProviderGetAddrInfoResponse) InlineAlignment() int {
+	return 0
+}
+
+// Implements Payload.
+func (_ *LegacySocketProviderGetAddrInfoResponse) InlineSize() int {
+	return 40
+}
+
+type LegacySocketProviderInterface _bindings.Proxy
+
+func (p *LegacySocketProviderInterface) OpenSocket(domain SocketDomain,type_ SocketType,protocol SocketProtocol) (_zx.Socket, int32, error) {
+	req_ := LegacySocketProviderOpenSocketRequest{
+		Domain: domain,
+		Type: type_,
+		Protocol: protocol,
+	}
+	resp_ := LegacySocketProviderOpenSocketResponse{}
+	err := ((*_bindings.Proxy)(p)).Call(LegacySocketProviderOpenSocketOrdinal, &req_, &resp_)
+	return resp_.S, resp_.Status, err
+}
+func (p *LegacySocketProviderInterface) GetAddrInfo(node *String,service *String,hints *AddrInfoHints) (AddrInfoStatus, int32, *AddrInfo, *AddrInfo, *AddrInfo, *AddrInfo, error) {
+	req_ := LegacySocketProviderGetAddrInfoRequest{
+		Node: node,
+		Service: service,
+		Hints: hints,
+	}
+	resp_ := LegacySocketProviderGetAddrInfoResponse{}
+	err := ((*_bindings.Proxy)(p)).Call(LegacySocketProviderGetAddrInfoOrdinal, &req_, &resp_)
+	return resp_.Status, resp_.Nres, resp_.Ai0, resp_.Ai1, resp_.Ai2, resp_.Ai3, err
+}
+
+// LegacySocketProvider server interface.
+type LegacySocketProvider interface {
+	OpenSocket(domain SocketDomain,type_ SocketType,protocol SocketProtocol) (_zx.Socket, int32, error)
+	GetAddrInfo(node *String,service *String,hints *AddrInfoHints) (AddrInfoStatus, int32, *AddrInfo, *AddrInfo, *AddrInfo, *AddrInfo, error)
+}
+
+type LegacySocketProviderInterfaceRequest _bindings.InterfaceRequest
+
+func NewLegacySocketProviderInterfaceRequest() (LegacySocketProviderInterfaceRequest, *LegacySocketProviderInterface, error) {
+	req, cli, err := _bindings.NewInterfaceRequest()
+	return LegacySocketProviderInterfaceRequest(req), (*LegacySocketProviderInterface)(cli), err
+}
+// Implements ServiceRequest.
+func (_ LegacySocketProviderInterfaceRequest) Name() string {
+	return "fuchsia.net.LegacySocketProvider"
+}
+func (c LegacySocketProviderInterfaceRequest) ToChannel() _zx.Channel {
+	return c.Channel
+}
+
+const LegacySocketProviderName = "fuchsia.net.LegacySocketProvider"
+
+type LegacySocketProviderStub struct {
+	Impl LegacySocketProvider
+}
+
+func (s *LegacySocketProviderStub) Dispatch(ord uint32, b_ []byte, h_ []_zx.Handle) (_bindings.Payload, error) {
+	switch ord {
+	case LegacySocketProviderOpenSocketOrdinal:
+		in_ := LegacySocketProviderOpenSocketRequest{}
+		if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+			return nil, err_
+		}
+		out_ := LegacySocketProviderOpenSocketResponse{}
+		s, status, err_ := s.Impl.OpenSocket(in_.Domain,in_.Type,in_.Protocol)
+		out_.S = s
+		out_.Status = status
+		return &out_, err_
+	case LegacySocketProviderGetAddrInfoOrdinal:
+		in_ := LegacySocketProviderGetAddrInfoRequest{}
+		if err_ := _bindings.Unmarshal(b_, h_, &in_); err_ != nil {
+			return nil, err_
+		}
+		out_ := LegacySocketProviderGetAddrInfoResponse{}
+		status, nres, ai0, ai1, ai2, ai3, err_ := s.Impl.GetAddrInfo(in_.Node,in_.Service,in_.Hints)
+		out_.Status = status
+		out_.Nres = nres
+		out_.Ai0 = ai0
+		out_.Ai1 = ai1
+		out_.Ai2 = ai2
+		out_.Ai3 = ai3
+		return &out_, err_
+	}
+	return nil, _bindings.ErrUnknownOrdinal
+}
+
+type LegacySocketProviderService struct {
+	_bindings.BindingSet
+}
+
+func (s *LegacySocketProviderService) Add(impl LegacySocketProvider, c _zx.Channel, onError func(error)) (_bindings.BindingKey, error) {
+	return s.BindingSet.Add(&LegacySocketProviderStub{Impl: impl}, c, onError)
+}
+
+func (s *LegacySocketProviderService) EventProxyFor(key _bindings.BindingKey) (*LegacySocketProviderEventProxy, bool) {
+	pxy, err := s.BindingSet.ProxyFor(key)
+	return (*LegacySocketProviderEventProxy)(pxy), err
+}
+
+type LegacySocketProviderEventProxy _bindings.Proxy
+
+
+
diff --git a/src/syscall/zx/syscalls_fuchsia.go b/src/syscall/zx/syscalls_fuchsia.go
new file mode 100644
index 0000000..7eaa63e
--- /dev/null
+++ b/src/syscall/zx/syscalls_fuchsia.go
@@ -0,0 +1,939 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Zircon system calls for the Fuchsia OS.
+// Generated by mkfuchsia.go, do not edit.
+
+package zx
+
+import "unsafe"
+
+//go:cgo_import_dynamic vdso_zx_clock_get zx_clock_get "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_clock_get_new zx_clock_get_new "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_clock_get_monotonic zx_clock_get_monotonic "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_nanosleep zx_nanosleep "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_ticks_get zx_ticks_get "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_ticks_per_second zx_ticks_per_second "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_deadline_after zx_deadline_after "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_clock_adjust zx_clock_adjust "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_system_get_dcache_line_size zx_system_get_dcache_line_size "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_system_get_num_cpus zx_system_get_num_cpus "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_system_get_version zx_system_get_version "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_system_get_physmem zx_system_get_physmem "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_system_get_features zx_system_get_features "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_cache_flush zx_cache_flush "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_handle_close zx_handle_close "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_handle_close_many zx_handle_close_many "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_handle_duplicate zx_handle_duplicate "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_handle_replace zx_handle_replace "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_object_wait_one zx_object_wait_one "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_object_wait_many zx_object_wait_many "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_object_wait_async zx_object_wait_async "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_object_signal zx_object_signal "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_object_signal_peer zx_object_signal_peer "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_object_get_property zx_object_get_property "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_object_set_property zx_object_set_property "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_object_set_cookie zx_object_set_cookie "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_object_get_cookie zx_object_get_cookie "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_object_get_info zx_object_get_info "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_object_get_child zx_object_get_child "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_object_set_profile zx_object_set_profile "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_channel_create zx_channel_create "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_channel_read zx_channel_read "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_channel_read_etc zx_channel_read_etc "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_channel_write zx_channel_write "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_channel_call_noretry zx_channel_call_noretry "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_channel_call_finish zx_channel_call_finish "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_channel_call zx_channel_call "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_socket_create zx_socket_create "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_socket_write zx_socket_write "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_socket_read zx_socket_read "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_socket_share zx_socket_share "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_socket_accept zx_socket_accept "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_thread_exit zx_thread_exit "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_thread_create zx_thread_create "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_thread_start zx_thread_start "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_thread_read_state zx_thread_read_state "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_thread_write_state zx_thread_write_state "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_thread_set_priority zx_thread_set_priority "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_process_exit zx_process_exit "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_process_create zx_process_create "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_process_start zx_process_start "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_process_read_memory zx_process_read_memory "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_process_write_memory zx_process_write_memory "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_job_create zx_job_create "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_job_set_policy zx_job_set_policy "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_task_bind_exception_port zx_task_bind_exception_port "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_task_resume zx_task_resume "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_task_suspend zx_task_suspend "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_task_suspend_token zx_task_suspend_token "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_task_resume_from_exception zx_task_resume_from_exception "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_task_kill zx_task_kill "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_event_create zx_event_create "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_eventpair_create zx_eventpair_create "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_futex_wait zx_futex_wait "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_futex_wake zx_futex_wake "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_futex_requeue zx_futex_requeue "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_port_create zx_port_create "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_port_queue zx_port_queue "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_port_wait zx_port_wait "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_port_cancel zx_port_cancel "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_timer_create zx_timer_create "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_timer_set zx_timer_set "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_timer_cancel zx_timer_cancel "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_vmo_create zx_vmo_create "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_vmo_read zx_vmo_read "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_vmo_write zx_vmo_write "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_vmo_get_size zx_vmo_get_size "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_vmo_set_size zx_vmo_set_size "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_vmo_op_range zx_vmo_op_range "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_vmo_clone zx_vmo_clone "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_vmo_set_cache_policy zx_vmo_set_cache_policy "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_vmar_allocate_old zx_vmar_allocate_old "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_vmar_map_old zx_vmar_map_old "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_vmar_protect_old zx_vmar_protect_old "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_vmar_allocate zx_vmar_allocate "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_vmar_destroy zx_vmar_destroy "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_vmar_map zx_vmar_map "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_vmar_unmap zx_vmar_unmap "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_vmar_protect zx_vmar_protect "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_cprng_draw_once zx_cprng_draw_once "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_cprng_draw zx_cprng_draw "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_cprng_draw_new zx_cprng_draw_new "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_cprng_add_entropy zx_cprng_add_entropy "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_fifo_create zx_fifo_create "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_fifo_read zx_fifo_read "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_fifo_write zx_fifo_write "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_profile_create zx_profile_create "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_vmar_unmap_handle_close_thread_exit zx_vmar_unmap_handle_close_thread_exit "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_futex_wake_handle_close_thread_exit zx_futex_wake_handle_close_thread_exit "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_log_write zx_log_write "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_log_read zx_log_read "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_debuglog_create zx_debuglog_create "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_debuglog_write zx_debuglog_write "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_debuglog_read zx_debuglog_read "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_ktrace_read zx_ktrace_read "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_ktrace_control zx_ktrace_control "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_ktrace_write zx_ktrace_write "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_mtrace_control zx_mtrace_control "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_debug_read zx_debug_read "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_debug_write zx_debug_write "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_debug_send_command zx_debug_send_command "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_interrupt_create zx_interrupt_create "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_interrupt_bind zx_interrupt_bind "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_interrupt_wait zx_interrupt_wait "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_interrupt_destroy zx_interrupt_destroy "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_interrupt_ack zx_interrupt_ack "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_interrupt_trigger zx_interrupt_trigger "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_ioports_request zx_ioports_request "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_vmo_create_contiguous zx_vmo_create_contiguous "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_vmo_create_physical zx_vmo_create_physical "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_iommu_create zx_iommu_create "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_bti_create zx_bti_create "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_bti_pin zx_bti_pin "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_bti_release_quarantine zx_bti_release_quarantine "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_pmt_unpin zx_pmt_unpin "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_framebuffer_get_info zx_framebuffer_get_info "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_framebuffer_set_range zx_framebuffer_set_range "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_pc_firmware_tables zx_pc_firmware_tables "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_smc_call zx_smc_call "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_resource_create zx_resource_create "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_system_mexec zx_system_mexec "libzircon.so"
+//go:cgo_import_dynamic vdso_zx_system_powerctl zx_system_powerctl "libzircon.so"
+
+//go:linkname vdso_zx_clock_get vdso_zx_clock_get
+//go:linkname vdso_zx_clock_get_new vdso_zx_clock_get_new
+//go:linkname vdso_zx_clock_get_monotonic vdso_zx_clock_get_monotonic
+//go:linkname vdso_zx_nanosleep vdso_zx_nanosleep
+//go:linkname vdso_zx_ticks_get vdso_zx_ticks_get
+//go:linkname vdso_zx_ticks_per_second vdso_zx_ticks_per_second
+//go:linkname vdso_zx_deadline_after vdso_zx_deadline_after
+//go:linkname vdso_zx_clock_adjust vdso_zx_clock_adjust
+//go:linkname vdso_zx_system_get_dcache_line_size vdso_zx_system_get_dcache_line_size
+//go:linkname vdso_zx_system_get_num_cpus vdso_zx_system_get_num_cpus
+//go:linkname vdso_zx_system_get_version vdso_zx_system_get_version
+//go:linkname vdso_zx_system_get_physmem vdso_zx_system_get_physmem
+//go:linkname vdso_zx_system_get_features vdso_zx_system_get_features
+//go:linkname vdso_zx_cache_flush vdso_zx_cache_flush
+//go:linkname vdso_zx_handle_close vdso_zx_handle_close
+//go:linkname vdso_zx_handle_close_many vdso_zx_handle_close_many
+//go:linkname vdso_zx_handle_duplicate vdso_zx_handle_duplicate
+//go:linkname vdso_zx_handle_replace vdso_zx_handle_replace
+//go:linkname vdso_zx_object_wait_one vdso_zx_object_wait_one
+//go:linkname vdso_zx_object_wait_many vdso_zx_object_wait_many
+//go:linkname vdso_zx_object_wait_async vdso_zx_object_wait_async
+//go:linkname vdso_zx_object_signal vdso_zx_object_signal
+//go:linkname vdso_zx_object_signal_peer vdso_zx_object_signal_peer
+//go:linkname vdso_zx_object_get_property vdso_zx_object_get_property
+//go:linkname vdso_zx_object_set_property vdso_zx_object_set_property
+//go:linkname vdso_zx_object_set_cookie vdso_zx_object_set_cookie
+//go:linkname vdso_zx_object_get_cookie vdso_zx_object_get_cookie
+//go:linkname vdso_zx_object_get_info vdso_zx_object_get_info
+//go:linkname vdso_zx_object_get_child vdso_zx_object_get_child
+//go:linkname vdso_zx_object_set_profile vdso_zx_object_set_profile
+//go:linkname vdso_zx_channel_create vdso_zx_channel_create
+//go:linkname vdso_zx_channel_read vdso_zx_channel_read
+//go:linkname vdso_zx_channel_read_etc vdso_zx_channel_read_etc
+//go:linkname vdso_zx_channel_write vdso_zx_channel_write
+//go:linkname vdso_zx_channel_call_noretry vdso_zx_channel_call_noretry
+//go:linkname vdso_zx_channel_call_finish vdso_zx_channel_call_finish
+//go:linkname vdso_zx_channel_call vdso_zx_channel_call
+//go:linkname vdso_zx_socket_create vdso_zx_socket_create
+//go:linkname vdso_zx_socket_write vdso_zx_socket_write
+//go:linkname vdso_zx_socket_read vdso_zx_socket_read
+//go:linkname vdso_zx_socket_share vdso_zx_socket_share
+//go:linkname vdso_zx_socket_accept vdso_zx_socket_accept
+//go:linkname vdso_zx_thread_exit vdso_zx_thread_exit
+//go:linkname vdso_zx_thread_create vdso_zx_thread_create
+//go:linkname vdso_zx_thread_start vdso_zx_thread_start
+//go:linkname vdso_zx_thread_read_state vdso_zx_thread_read_state
+//go:linkname vdso_zx_thread_write_state vdso_zx_thread_write_state
+//go:linkname vdso_zx_thread_set_priority vdso_zx_thread_set_priority
+//go:linkname vdso_zx_process_exit vdso_zx_process_exit
+//go:linkname vdso_zx_process_create vdso_zx_process_create
+//go:linkname vdso_zx_process_start vdso_zx_process_start
+//go:linkname vdso_zx_process_read_memory vdso_zx_process_read_memory
+//go:linkname vdso_zx_process_write_memory vdso_zx_process_write_memory
+//go:linkname vdso_zx_job_create vdso_zx_job_create
+//go:linkname vdso_zx_job_set_policy vdso_zx_job_set_policy
+//go:linkname vdso_zx_task_bind_exception_port vdso_zx_task_bind_exception_port
+//go:linkname vdso_zx_task_resume vdso_zx_task_resume
+//go:linkname vdso_zx_task_suspend vdso_zx_task_suspend
+//go:linkname vdso_zx_task_suspend_token vdso_zx_task_suspend_token
+//go:linkname vdso_zx_task_resume_from_exception vdso_zx_task_resume_from_exception
+//go:linkname vdso_zx_task_kill vdso_zx_task_kill
+//go:linkname vdso_zx_event_create vdso_zx_event_create
+//go:linkname vdso_zx_eventpair_create vdso_zx_eventpair_create
+//go:linkname vdso_zx_futex_wait vdso_zx_futex_wait
+//go:linkname vdso_zx_futex_wake vdso_zx_futex_wake
+//go:linkname vdso_zx_futex_requeue vdso_zx_futex_requeue
+//go:linkname vdso_zx_port_create vdso_zx_port_create
+//go:linkname vdso_zx_port_queue vdso_zx_port_queue
+//go:linkname vdso_zx_port_wait vdso_zx_port_wait
+//go:linkname vdso_zx_port_cancel vdso_zx_port_cancel
+//go:linkname vdso_zx_timer_create vdso_zx_timer_create
+//go:linkname vdso_zx_timer_set vdso_zx_timer_set
+//go:linkname vdso_zx_timer_cancel vdso_zx_timer_cancel
+//go:linkname vdso_zx_vmo_create vdso_zx_vmo_create
+//go:linkname vdso_zx_vmo_read vdso_zx_vmo_read
+//go:linkname vdso_zx_vmo_write vdso_zx_vmo_write
+//go:linkname vdso_zx_vmo_get_size vdso_zx_vmo_get_size
+//go:linkname vdso_zx_vmo_set_size vdso_zx_vmo_set_size
+//go:linkname vdso_zx_vmo_op_range vdso_zx_vmo_op_range
+//go:linkname vdso_zx_vmo_clone vdso_zx_vmo_clone
+//go:linkname vdso_zx_vmo_set_cache_policy vdso_zx_vmo_set_cache_policy
+//go:linkname vdso_zx_vmar_allocate_old vdso_zx_vmar_allocate_old
+//go:linkname vdso_zx_vmar_map_old vdso_zx_vmar_map_old
+//go:linkname vdso_zx_vmar_protect_old vdso_zx_vmar_protect_old
+//go:linkname vdso_zx_vmar_allocate vdso_zx_vmar_allocate
+//go:linkname vdso_zx_vmar_destroy vdso_zx_vmar_destroy
+//go:linkname vdso_zx_vmar_map vdso_zx_vmar_map
+//go:linkname vdso_zx_vmar_unmap vdso_zx_vmar_unmap
+//go:linkname vdso_zx_vmar_protect vdso_zx_vmar_protect
+//go:linkname vdso_zx_cprng_draw_once vdso_zx_cprng_draw_once
+//go:linkname vdso_zx_cprng_draw vdso_zx_cprng_draw
+//go:linkname vdso_zx_cprng_draw_new vdso_zx_cprng_draw_new
+//go:linkname vdso_zx_cprng_add_entropy vdso_zx_cprng_add_entropy
+//go:linkname vdso_zx_fifo_create vdso_zx_fifo_create
+//go:linkname vdso_zx_fifo_read vdso_zx_fifo_read
+//go:linkname vdso_zx_fifo_write vdso_zx_fifo_write
+//go:linkname vdso_zx_profile_create vdso_zx_profile_create
+//go:linkname vdso_zx_vmar_unmap_handle_close_thread_exit vdso_zx_vmar_unmap_handle_close_thread_exit
+//go:linkname vdso_zx_futex_wake_handle_close_thread_exit vdso_zx_futex_wake_handle_close_thread_exit
+//go:linkname vdso_zx_log_write vdso_zx_log_write
+//go:linkname vdso_zx_log_read vdso_zx_log_read
+//go:linkname vdso_zx_debuglog_create vdso_zx_debuglog_create
+//go:linkname vdso_zx_debuglog_write vdso_zx_debuglog_write
+//go:linkname vdso_zx_debuglog_read vdso_zx_debuglog_read
+//go:linkname vdso_zx_ktrace_read vdso_zx_ktrace_read
+//go:linkname vdso_zx_ktrace_control vdso_zx_ktrace_control
+//go:linkname vdso_zx_ktrace_write vdso_zx_ktrace_write
+//go:linkname vdso_zx_mtrace_control vdso_zx_mtrace_control
+//go:linkname vdso_zx_debug_read vdso_zx_debug_read
+//go:linkname vdso_zx_debug_write vdso_zx_debug_write
+//go:linkname vdso_zx_debug_send_command vdso_zx_debug_send_command
+//go:linkname vdso_zx_interrupt_create vdso_zx_interrupt_create
+//go:linkname vdso_zx_interrupt_bind vdso_zx_interrupt_bind
+//go:linkname vdso_zx_interrupt_wait vdso_zx_interrupt_wait
+//go:linkname vdso_zx_interrupt_destroy vdso_zx_interrupt_destroy
+//go:linkname vdso_zx_interrupt_ack vdso_zx_interrupt_ack
+//go:linkname vdso_zx_interrupt_trigger vdso_zx_interrupt_trigger
+//go:linkname vdso_zx_ioports_request vdso_zx_ioports_request
+//go:linkname vdso_zx_vmo_create_contiguous vdso_zx_vmo_create_contiguous
+//go:linkname vdso_zx_vmo_create_physical vdso_zx_vmo_create_physical
+//go:linkname vdso_zx_iommu_create vdso_zx_iommu_create
+//go:linkname vdso_zx_bti_create vdso_zx_bti_create
+//go:linkname vdso_zx_bti_pin vdso_zx_bti_pin
+//go:linkname vdso_zx_bti_release_quarantine vdso_zx_bti_release_quarantine
+//go:linkname vdso_zx_pmt_unpin vdso_zx_pmt_unpin
+//go:linkname vdso_zx_framebuffer_get_info vdso_zx_framebuffer_get_info
+//go:linkname vdso_zx_framebuffer_set_range vdso_zx_framebuffer_set_range
+//go:linkname vdso_zx_pc_firmware_tables vdso_zx_pc_firmware_tables
+//go:linkname vdso_zx_smc_call vdso_zx_smc_call
+//go:linkname vdso_zx_resource_create vdso_zx_resource_create
+//go:linkname vdso_zx_system_mexec vdso_zx_system_mexec
+//go:linkname vdso_zx_system_powerctl vdso_zx_system_powerctl
+
+var (
+	vdso_zx_clock_get                           uintptr
+	vdso_zx_clock_get_new                       uintptr
+	vdso_zx_clock_get_monotonic                 uintptr
+	vdso_zx_nanosleep                           uintptr
+	vdso_zx_ticks_get                           uintptr
+	vdso_zx_ticks_per_second                    uintptr
+	vdso_zx_deadline_after                      uintptr
+	vdso_zx_clock_adjust                        uintptr
+	vdso_zx_system_get_dcache_line_size         uintptr
+	vdso_zx_system_get_num_cpus                 uintptr
+	vdso_zx_system_get_version                  uintptr
+	vdso_zx_system_get_physmem                  uintptr
+	vdso_zx_system_get_features                 uintptr
+	vdso_zx_cache_flush                         uintptr
+	vdso_zx_handle_close                        uintptr
+	vdso_zx_handle_close_many                   uintptr
+	vdso_zx_handle_duplicate                    uintptr
+	vdso_zx_handle_replace                      uintptr
+	vdso_zx_object_wait_one                     uintptr
+	vdso_zx_object_wait_many                    uintptr
+	vdso_zx_object_wait_async                   uintptr
+	vdso_zx_object_signal                       uintptr
+	vdso_zx_object_signal_peer                  uintptr
+	vdso_zx_object_get_property                 uintptr
+	vdso_zx_object_set_property                 uintptr
+	vdso_zx_object_set_cookie                   uintptr
+	vdso_zx_object_get_cookie                   uintptr
+	vdso_zx_object_get_info                     uintptr
+	vdso_zx_object_get_child                    uintptr
+	vdso_zx_object_set_profile                  uintptr
+	vdso_zx_channel_create                      uintptr
+	vdso_zx_channel_read                        uintptr
+	vdso_zx_channel_read_etc                    uintptr
+	vdso_zx_channel_write                       uintptr
+	vdso_zx_channel_call_noretry                uintptr
+	vdso_zx_channel_call_finish                 uintptr
+	vdso_zx_channel_call                        uintptr
+	vdso_zx_socket_create                       uintptr
+	vdso_zx_socket_write                        uintptr
+	vdso_zx_socket_read                         uintptr
+	vdso_zx_socket_share                        uintptr
+	vdso_zx_socket_accept                       uintptr
+	vdso_zx_thread_exit                         uintptr
+	vdso_zx_thread_create                       uintptr
+	vdso_zx_thread_start                        uintptr
+	vdso_zx_thread_read_state                   uintptr
+	vdso_zx_thread_write_state                  uintptr
+	vdso_zx_thread_set_priority                 uintptr
+	vdso_zx_process_exit                        uintptr
+	vdso_zx_process_create                      uintptr
+	vdso_zx_process_start                       uintptr
+	vdso_zx_process_read_memory                 uintptr
+	vdso_zx_process_write_memory                uintptr
+	vdso_zx_job_create                          uintptr
+	vdso_zx_job_set_policy                      uintptr
+	vdso_zx_task_bind_exception_port            uintptr
+	vdso_zx_task_resume                         uintptr
+	vdso_zx_task_suspend                        uintptr
+	vdso_zx_task_suspend_token                  uintptr
+	vdso_zx_task_resume_from_exception          uintptr
+	vdso_zx_task_kill                           uintptr
+	vdso_zx_event_create                        uintptr
+	vdso_zx_eventpair_create                    uintptr
+	vdso_zx_futex_wait                          uintptr
+	vdso_zx_futex_wake                          uintptr
+	vdso_zx_futex_requeue                       uintptr
+	vdso_zx_port_create                         uintptr
+	vdso_zx_port_queue                          uintptr
+	vdso_zx_port_wait                           uintptr
+	vdso_zx_port_cancel                         uintptr
+	vdso_zx_timer_create                        uintptr
+	vdso_zx_timer_set                           uintptr
+	vdso_zx_timer_cancel                        uintptr
+	vdso_zx_vmo_create                          uintptr
+	vdso_zx_vmo_read                            uintptr
+	vdso_zx_vmo_write                           uintptr
+	vdso_zx_vmo_get_size                        uintptr
+	vdso_zx_vmo_set_size                        uintptr
+	vdso_zx_vmo_op_range                        uintptr
+	vdso_zx_vmo_clone                           uintptr
+	vdso_zx_vmo_set_cache_policy                uintptr
+	vdso_zx_vmar_allocate_old                   uintptr
+	vdso_zx_vmar_map_old                        uintptr
+	vdso_zx_vmar_protect_old                    uintptr
+	vdso_zx_vmar_allocate                       uintptr
+	vdso_zx_vmar_destroy                        uintptr
+	vdso_zx_vmar_map                            uintptr
+	vdso_zx_vmar_unmap                          uintptr
+	vdso_zx_vmar_protect                        uintptr
+	vdso_zx_cprng_draw_once                     uintptr
+	vdso_zx_cprng_draw                          uintptr
+	vdso_zx_cprng_draw_new                      uintptr
+	vdso_zx_cprng_add_entropy                   uintptr
+	vdso_zx_fifo_create                         uintptr
+	vdso_zx_fifo_read                           uintptr
+	vdso_zx_fifo_write                          uintptr
+	vdso_zx_profile_create                      uintptr
+	vdso_zx_vmar_unmap_handle_close_thread_exit uintptr
+	vdso_zx_futex_wake_handle_close_thread_exit uintptr
+	vdso_zx_log_write                           uintptr
+	vdso_zx_log_read                            uintptr
+	vdso_zx_debuglog_create                     uintptr
+	vdso_zx_debuglog_write                      uintptr
+	vdso_zx_debuglog_read                       uintptr
+	vdso_zx_ktrace_read                         uintptr
+	vdso_zx_ktrace_control                      uintptr
+	vdso_zx_ktrace_write                        uintptr
+	vdso_zx_mtrace_control                      uintptr
+	vdso_zx_debug_read                          uintptr
+	vdso_zx_debug_write                         uintptr
+	vdso_zx_debug_send_command                  uintptr
+	vdso_zx_interrupt_create                    uintptr
+	vdso_zx_interrupt_bind                      uintptr
+	vdso_zx_interrupt_wait                      uintptr
+	vdso_zx_interrupt_destroy                   uintptr
+	vdso_zx_interrupt_ack                       uintptr
+	vdso_zx_interrupt_trigger                   uintptr
+	vdso_zx_ioports_request                     uintptr
+	vdso_zx_vmo_create_contiguous               uintptr
+	vdso_zx_vmo_create_physical                 uintptr
+	vdso_zx_iommu_create                        uintptr
+	vdso_zx_bti_create                          uintptr
+	vdso_zx_bti_pin                             uintptr
+	vdso_zx_bti_release_quarantine              uintptr
+	vdso_zx_pmt_unpin                           uintptr
+	vdso_zx_framebuffer_get_info                uintptr
+	vdso_zx_framebuffer_set_range               uintptr
+	vdso_zx_pc_firmware_tables                  uintptr
+	vdso_zx_smc_call                            uintptr
+	vdso_zx_resource_create                     uintptr
+	vdso_zx_system_mexec                        uintptr
+	vdso_zx_system_powerctl                     uintptr
+)
+
+//go:noescape
+//go:nosplit
+func Sys_clock_get(clock_id uint32) Time
+
+//go:noescape
+//go:nosplit
+func Sys_clock_get_new(clock_id uint32, out *Time) Status
+
+//go:noescape
+//go:nosplit
+func Sys_clock_get_monotonic() Time
+
+//go:noescape
+//go:nosplit
+func Sys_nanosleep(deadline Time) Status
+
+//go:noescape
+//go:nosplit
+func Sys_ticks_get() uint64
+
+//go:noescape
+//go:nosplit
+func Sys_ticks_per_second() uint64
+
+//go:noescape
+//go:nosplit
+func Sys_deadline_after(nanoseconds Duration) Time
+
+//go:noescape
+//go:nosplit
+func Sys_clock_adjust(handle Handle, clock_id uint32, offset int64) Status
+
+//go:noescape
+//go:nosplit
+func sys_system_get_dcache_line_size() uint32
+
+//go:noescape
+//go:nosplit
+func Sys_system_get_num_cpus() uint32
+
+//go:noescape
+//go:nosplit
+func Sys_system_get_version(version *uint8, version_size uint) Status
+
+//go:noescape
+//go:nosplit
+func Sys_system_get_physmem() uint64
+
+//go:noescape
+//go:nosplit
+func sys_system_get_features(kind uint32, out *uint32) Status
+
+//go:noescape
+//go:nosplit
+func Sys_cache_flush(addr unsafe.Pointer, size uint, options uint32) Status
+
+//go:noescape
+//go:nosplit
+func Sys_handle_close(handle Handle) Status
+
+//go:noescape
+//go:nosplit
+func Sys_handle_close_many(handles *Handle, num_handles uint) Status
+
+//go:noescape
+//go:nosplit
+func sys_handle_duplicate(handle Handle, rights Rights, out *Handle) Status
+
+//go:noescape
+//go:nosplit
+func Sys_handle_replace(handle Handle, rights Rights, out *Handle) Status
+
+//go:noescape
+//go:nosplit
+func Sys_object_wait_one(handle Handle, signals Signals, deadline Time, observed *Signals) Status
+
+//go:noescape
+//go:nosplit
+func sys_object_wait_many(items *WaitItem, count uint, deadline Time) Status
+
+//go:noescape
+//go:nosplit
+func Sys_object_wait_async(handle Handle, port Handle, key uint64, signals Signals, options uint32) Status
+
+//go:noescape
+//go:nosplit
+func Sys_object_signal(handle Handle, clear_mask uint32, set_mask uint32) Status
+
+//go:noescape
+//go:nosplit
+func Sys_object_signal_peer(handle Handle, clear_mask uint32, set_mask uint32) Status
+
+//go:noescape
+//go:nosplit
+func Sys_object_get_property(handle Handle, property uint32, value unsafe.Pointer, value_size uint) Status
+
+//go:noescape
+//go:nosplit
+func Sys_object_set_property(handle Handle, property uint32, value unsafe.Pointer, value_size uint) Status
+
+//go:noescape
+//go:nosplit
+func Sys_object_set_cookie(handle Handle, scope Handle, cookie uint64) Status
+
+//go:noescape
+//go:nosplit
+func Sys_object_get_cookie(handle Handle, scope Handle, cookie *uint64) Status
+
+//go:noescape
+//go:nosplit
+func Sys_object_get_info(handle Handle, topic uint32, buffer unsafe.Pointer, buffer_size uint, actual_count *uint, avail_count *uint) Status
+
+//go:noescape
+//go:nosplit
+func Sys_object_get_child(handle Handle, koid uint64, rights Rights, out *Handle) Status
+
+//go:noescape
+//go:nosplit
+func sys_object_set_profile(handle Handle, profile Handle, options uint32) Status
+
+//go:noescape
+//go:nosplit
+func sys_channel_create(options uint32, out0 *Handle, out1 *Handle) Status
+
+//go:noescape
+//go:nosplit
+func sys_channel_read(handle Handle, options uint32, bytes unsafe.Pointer, handles *Handle, num_bytes uint32, num_handles uint32, actual_bytes *uint32, actual_handles *uint32) Status
+
+//go:noescape
+//go:nosplit
+func sys_channel_read_etc(handle Handle, options uint32, bytes unsafe.Pointer, handles *int, num_bytes uint32, num_handles uint32, actual_bytes *uint32, actual_handles *uint32) Status
+
+//go:noescape
+//go:nosplit
+func sys_channel_write(handle Handle, options uint32, bytes unsafe.Pointer, num_bytes uint32, handles *Handle, num_handles uint32) Status
+
+//go:noescape
+//go:nosplit
+func Sys_channel_call_noretry(handle Handle, options uint32, deadline Time, args *ChannelCallArgs, actual_bytes *uint32, actual_handles *uint32) Status
+
+//go:noescape
+//go:nosplit
+func Sys_channel_call_finish(deadline Time, args *ChannelCallArgs, actual_bytes *uint32, actual_handles *uint32) Status
+
+//go:noescape
+//go:nosplit
+func Sys_channel_call(handle Handle, options uint32, deadline Time, args *ChannelCallArgs, actual_bytes *uint32, actual_handles *uint32) Status
+
+//go:noescape
+//go:nosplit
+func sys_socket_create(options uint32, out0 *Handle, out1 *Handle) Status
+
+//go:noescape
+//go:nosplit
+func sys_socket_write(handle Handle, options uint32, buffer unsafe.Pointer, buffer_size uint, actual *uint) Status
+
+//go:noescape
+//go:nosplit
+func sys_socket_read(handle Handle, options uint32, buffer unsafe.Pointer, buffer_size uint, actual *uint) Status
+
+//go:noescape
+//go:nosplit
+func sys_socket_share(handle Handle, socket_to_share Handle) Status
+
+//go:noescape
+//go:nosplit
+func sys_socket_accept(handle Handle, out_socket *Handle) Status
+
+//go:noescape
+//go:nosplit
+func Sys_thread_exit()
+
+//go:noescape
+//go:nosplit
+func Sys_thread_create(process Handle, name *uint8, name_size uint, options uint32, out *Handle) Status
+
+//go:noescape
+//go:nosplit
+func Sys_thread_start(handle Handle, thread_entry Vaddr, stack Vaddr, arg1 uintptr, arg2 uintptr) Status
+
+//go:noescape
+//go:nosplit
+func Sys_thread_read_state(handle Handle, kind uint32, buffer unsafe.Pointer, buffer_size uint) Status
+
+//go:noescape
+//go:nosplit
+func Sys_thread_write_state(handle Handle, kind uint32, buffer unsafe.Pointer, buffer_size uint) Status
+
+//go:noescape
+//go:nosplit
+func Sys_thread_set_priority(prio int32) Status
+
+//go:noescape
+//go:nosplit
+func Sys_process_exit(retcode int64)
+
+//go:noescape
+//go:nosplit
+func Sys_process_create(job Handle, name *uint8, name_size uint, options uint32, proc_handle *Handle, vmar_handle *Handle) Status
+
+//go:noescape
+//go:nosplit
+func Sys_process_start(handle Handle, thread Handle, entry Vaddr, stack Vaddr, arg1 Handle, arg2 uintptr) Status
+
+//go:noescape
+//go:nosplit
+func Sys_process_read_memory(proc Handle, vaddr Vaddr, buffer unsafe.Pointer, buffer_size uint, actual *uint) Status
+
+//go:noescape
+//go:nosplit
+func Sys_process_write_memory(proc Handle, vaddr Vaddr, buffer unsafe.Pointer, buffer_size uint, actual *uint) Status
+
+//go:noescape
+//go:nosplit
+func Sys_job_create(parent_job Handle, options uint32, out *Handle) Status
+
+//go:noescape
+//go:nosplit
+func Sys_job_set_policy(job Handle, options uint32, topic uint32, policy unsafe.Pointer, count uint32) Status
+
+//go:noescape
+//go:nosplit
+func Sys_task_bind_exception_port(handle Handle, port Handle, key uint64, options uint32) Status
+
+//go:noescape
+//go:nosplit
+func Sys_task_resume(handle Handle, options uint32) Status
+
+//go:noescape
+//go:nosplit
+func Sys_task_suspend(handle Handle, token *Handle) Status
+
+//go:noescape
+//go:nosplit
+func Sys_task_suspend_token(handle Handle, token *Handle) Status
+
+//go:noescape
+//go:nosplit
+func Sys_task_resume_from_exception(handle Handle, port Handle, options uint32) Status
+
+//go:noescape
+//go:nosplit
+func Sys_task_kill(handle Handle) Status
+
+//go:noescape
+//go:nosplit
+func Sys_event_create(options uint32, out *Handle) Status
+
+//go:noescape
+//go:nosplit
+func Sys_eventpair_create(options uint32, out0 *Handle, out1 *Handle) Status
+
+//go:noescape
+//go:nosplit
+func Sys_futex_wait(value_ptr *int, current_value int32, deadline Time) Status
+
+//go:noescape
+//go:nosplit
+func Sys_futex_wake(value_ptr *int, count uint32) Status
+
+//go:noescape
+//go:nosplit
+func Sys_futex_requeue(wake_ptr *int, wake_count uint32, current_value int32, requeue_ptr *int, requeue_count uint32) Status
+
+//go:noescape
+//go:nosplit
+func Sys_port_create(options uint32, out *Handle) Status
+
+//go:noescape
+//go:nosplit
+func Sys_port_queue(handle Handle, packet *int) Status
+
+//go:noescape
+//go:nosplit
+func Sys_port_wait(handle Handle, deadline Time, packet *int) Status
+
+//go:noescape
+//go:nosplit
+func Sys_port_cancel(handle Handle, source Handle, key uint64) Status
+
+//go:noescape
+//go:nosplit
+func Sys_timer_create(options uint32, clock_id uint32, out *Handle) Status
+
+//go:noescape
+//go:nosplit
+func Sys_timer_set(handle Handle, deadline Time, slack Duration) Status
+
+//go:noescape
+//go:nosplit
+func Sys_timer_cancel(handle Handle) Status
+
+//go:noescape
+//go:nosplit
+func Sys_vmo_create(size uint64, options uint32, out *Handle) Status
+
+//go:noescape
+//go:nosplit
+func sys_vmo_read(handle Handle, buffer unsafe.Pointer, offset uint64, buffer_size uint) Status
+
+//go:noescape
+//go:nosplit
+func sys_vmo_write(handle Handle, buffer unsafe.Pointer, offset uint64, buffer_size uint) Status
+
+//go:noescape
+//go:nosplit
+func sys_vmo_get_size(handle Handle, size *uint64) Status
+
+//go:noescape
+//go:nosplit
+func sys_vmo_set_size(handle Handle, size uint64) Status
+
+//go:noescape
+//go:nosplit
+func sys_vmo_op_range(handle Handle, op uint32, offset uint64, size uint64, buffer unsafe.Pointer, buffer_size uint) Status
+
+//go:noescape
+//go:nosplit
+func Sys_vmo_clone(handle Handle, options uint32, offset uint64, size uint64, out *Handle) Status
+
+//go:noescape
+//go:nosplit
+func Sys_vmo_set_cache_policy(handle Handle, cache_policy uint32) Status
+
+//go:noescape
+//go:nosplit
+func sys_vmar_allocate_old(parent_vmar Handle, offset uint64, size uint64, map_flags uint32, child_vmar *Handle, child_addr *Vaddr) Status
+
+//go:noescape
+//go:nosplit
+func sys_vmar_map_old(handle Handle, vmar_offset uint64, vmo Handle, vmo_offset uint64, len uint64, map_flags uint32, mapped_addr *Vaddr) Status
+
+//go:noescape
+//go:nosplit
+func sys_vmar_protect_old(handle Handle, addr Vaddr, len uint64, prot_flags uint32) Status
+
+//go:noescape
+//go:nosplit
+func sys_vmar_allocate(parent_vmar Handle, offset uint64, size uint64, map_flags uint32, child_vmar *Handle, child_addr *Vaddr) Status
+
+//go:noescape
+//go:nosplit
+func sys_vmar_destroy(handle Handle) Status
+
+//go:noescape
+//go:nosplit
+func Sys_vmar_map(handle Handle, vmar_offset uint64, vmo Handle, vmo_offset uint64, len uint64, map_flags uint32, mapped_addr *Vaddr) Status
+
+//go:noescape
+//go:nosplit
+func Sys_vmar_unmap(handle Handle, addr Vaddr, len uint64) Status
+
+//go:noescape
+//go:nosplit
+func Sys_vmar_protect(handle Handle, addr Vaddr, len uint64, prot_flags uint32) Status
+
+//go:noescape
+//go:nosplit
+func Sys_cprng_draw_once(buffer unsafe.Pointer, buffer_size uint) Status
+
+//go:noescape
+//go:nosplit
+func Sys_cprng_draw(buffer unsafe.Pointer, buffer_size uint)
+
+//go:noescape
+//go:nosplit
+func Sys_cprng_draw_new(buffer unsafe.Pointer, data_size uint) Status
+
+//go:noescape
+//go:nosplit
+func Sys_cprng_add_entropy(buffer unsafe.Pointer, len uint) Status
+
+//go:noescape
+//go:nosplit
+func Sys_fifo_create(elem_count uint, elem_size uint, options uint32, out0 *Handle, out1 *Handle) Status
+
+//go:noescape
+//go:nosplit
+func Sys_fifo_read(handle Handle, elem_size uint, data unsafe.Pointer, count uint, actual_count *uint) Status
+
+//go:noescape
+//go:nosplit
+func Sys_fifo_write(handle Handle, elem_size uint, data unsafe.Pointer, count uint, actual_count *uint) Status
+
+//go:noescape
+//go:nosplit
+func Sys_profile_create(resource Handle, profile *int, out *Handle) Status
+
+//go:noescape
+//go:nosplit
+func Sys_vmar_unmap_handle_close_thread_exit(vmar_handle Handle, addr Vaddr, size uint, handle Handle) Status
+
+//go:noescape
+//go:nosplit
+func Sys_futex_wake_handle_close_thread_exit(value_ptr *int, count uint32, new_value int32, handle Handle)
+
+//go:noescape
+//go:nosplit
+func Sys_log_write(handle Handle, len uint32, buffer unsafe.Pointer, options uint32) Status
+
+//go:noescape
+//go:nosplit
+func Sys_log_read(handle Handle, len uint32, buffer unsafe.Pointer, options uint32) Status
+
+//go:noescape
+//go:nosplit
+func Sys_debuglog_create(resource Handle, options uint32, out *Handle) Status
+
+//go:noescape
+//go:nosplit
+func Sys_debuglog_write(handle Handle, options uint32, buffer unsafe.Pointer, buffer_size uint) Status
+
+//go:noescape
+//go:nosplit
+func Sys_debuglog_read(handle Handle, options uint32, buffer unsafe.Pointer, buffer_size uint) Status
+
+//go:noescape
+//go:nosplit
+func Sys_ktrace_read(handle Handle, data unsafe.Pointer, offset uint32, data_size uint, actual *uint) Status
+
+//go:noescape
+//go:nosplit
+func Sys_ktrace_control(handle Handle, action uint32, options uint32, ptr unsafe.Pointer) Status
+
+//go:noescape
+//go:nosplit
+func Sys_ktrace_write(handle Handle, id uint32, arg0 uint32, arg1 uint32) Status
+
+//go:noescape
+//go:nosplit
+func Sys_mtrace_control(handle Handle, kind uint32, action uint32, options uint32, ptr unsafe.Pointer, ptr_size uint) Status
+
+//go:noescape
+//go:nosplit
+func Sys_debug_read(handle Handle, buffer *uint8, buffer_size *uint) Status
+
+//go:noescape
+//go:nosplit
+func Sys_debug_write(buffer *uint8, buffer_size uint) Status
+
+//go:noescape
+//go:nosplit
+func Sys_debug_send_command(resource Handle, buffer *uint8, buffer_size uint) Status
+
+//go:noescape
+//go:nosplit
+func Sys_interrupt_create(src_obj Handle, src_num uint32, options uint32, out *Handle) Status
+
+//go:noescape
+//go:nosplit
+func Sys_interrupt_bind(handle Handle, port Handle, key uint64, options uint32) Status
+
+//go:noescape
+//go:nosplit
+func Sys_interrupt_wait(handle Handle, out_timestamp *Time) Status
+
+//go:noescape
+//go:nosplit
+func Sys_interrupt_destroy(handle Handle) Status
+
+//go:noescape
+//go:nosplit
+func Sys_interrupt_ack(handle Handle) Status
+
+//go:noescape
+//go:nosplit
+func Sys_interrupt_trigger(handle Handle, options uint32, timestamp Time) Status
+
+//go:noescape
+//go:nosplit
+func Sys_ioports_request(resource Handle, io_addr uint16, len uint32) Status
+
+//go:noescape
+//go:nosplit
+func Sys_vmo_create_contiguous(bti Handle, size uint, alignment_log2 uint32, out *Handle) Status
+
+//go:noescape
+//go:nosplit
+func Sys_vmo_create_physical(resource Handle, paddr Paddr, size uint, out *Handle) Status
+
+//go:noescape
+//go:nosplit
+func Sys_iommu_create(resource Handle, typ uint32, desc unsafe.Pointer, desc_size uint, out *Handle) Status
+
+//go:noescape
+//go:nosplit
+func Sys_bti_create(iommu Handle, options uint32, bti_id uint64, out *Handle) Status
+
+//go:noescape
+//go:nosplit
+func Sys_bti_pin(handle Handle, options uint32, vmo Handle, offset uint64, size uint64, addrs *Paddr, addrs_count uint, out *Handle) Status
+
+//go:noescape
+//go:nosplit
+func Sys_bti_release_quarantine(handle Handle) Status
+
+//go:noescape
+//go:nosplit
+func Sys_pmt_unpin(handle Handle) Status
+
+//go:noescape
+//go:nosplit
+func Sys_framebuffer_get_info(resource Handle, format *uint32, width *uint32, height *uint32, stride *uint32) Status
+
+//go:noescape
+//go:nosplit
+func Sys_framebuffer_set_range(resource Handle, vmo Handle, len uint32, format uint32, width uint32, height uint32, stride uint32) Status
+
+//go:noescape
+//go:nosplit
+func Sys_pc_firmware_tables(handle Handle, acpi_rsdp *Paddr, smbios *Paddr) Status
+
+//go:noescape
+//go:nosplit
+func Sys_smc_call(handle Handle, parameters *SMCParameters, out_smc_result *SMCResult) Status
+
+//go:noescape
+//go:nosplit
+func Sys_resource_create(parent_rsrc Handle, options uint32, base uint64, size uint, name *uint8, name_size uint, resource_out *Handle) Status
+
+//go:noescape
+//go:nosplit
+func Sys_system_mexec(resource Handle, kernel Handle, bootimage Handle) Status
+
+//go:noescape
+//go:nosplit
+func Sys_system_powerctl(resource Handle, cmd uint32, arg *int) Status
diff --git a/src/syscall/zx/syscalls_fuchsia_amd64.s b/src/syscall/zx/syscalls_fuchsia_amd64.s
new file mode 100644
index 0000000..f6477d3
--- /dev/null
+++ b/src/syscall/zx/syscalls_fuchsia_amd64.s
@@ -0,0 +1,1421 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Zircon system calls for the Fuchsia OS.
+// Generated by mkfuchsia.go, do not edit.
+
+#include "textflag.h"
+
+// func Sys_clock_get(clock_id uint32) Time
+TEXT ·Sys_clock_get(SB),NOSPLIT,$0-16
+	MOVL clock_id+0(FP), DI
+	MOVQ vdso_zx_clock_get(SB), AX
+	CALL AX
+	MOVQ AX, ret+8(FP)
+	RET
+
+// func Sys_clock_get_new(clock_id uint32, out *Time) Status
+TEXT ·Sys_clock_get_new(SB),NOSPLIT,$0-20
+	MOVL clock_id+0(FP), DI
+	MOVQ out+8(FP), SI
+	MOVQ vdso_zx_clock_get_new(SB), AX
+	CALL AX
+	MOVL AX, ret+16(FP)
+	RET
+
+// func Sys_clock_get_monotonic() Time
+TEXT ·Sys_clock_get_monotonic(SB),NOSPLIT,$0-8
+	MOVQ vdso_zx_clock_get_monotonic(SB), AX
+	CALL AX
+	MOVQ AX, ret+0(FP)
+	RET
+
+// func Sys_nanosleep(deadline Time) Status
+TEXT ·Sys_nanosleep(SB),NOSPLIT,$0-12
+	MOVQ deadline+0(FP), DI
+	MOVQ vdso_zx_nanosleep(SB), AX
+	CALL AX
+	MOVL AX, ret+8(FP)
+	RET
+
+// func Sys_ticks_get() uint64
+TEXT ·Sys_ticks_get(SB),NOSPLIT,$0-8
+	MOVQ vdso_zx_ticks_get(SB), AX
+	CALL AX
+	MOVQ AX, ret+0(FP)
+	RET
+
+// func Sys_ticks_per_second() uint64
+TEXT ·Sys_ticks_per_second(SB),NOSPLIT,$0-8
+	MOVQ vdso_zx_ticks_per_second(SB), AX
+	CALL AX
+	MOVQ AX, ret+0(FP)
+	RET
+
+// func Sys_deadline_after(nanoseconds Duration) Time
+TEXT ·Sys_deadline_after(SB),NOSPLIT,$0-16
+	MOVQ nanoseconds+0(FP), DI
+	MOVQ vdso_zx_deadline_after(SB), AX
+	CALL AX
+	MOVQ AX, ret+8(FP)
+	RET
+
+// func Sys_clock_adjust(handle Handle, clock_id uint32, offset int64) Status
+TEXT ·Sys_clock_adjust(SB),NOSPLIT,$0-20
+	MOVL handle+0(FP), DI
+	MOVL clock_id+4(FP), SI
+	MOVQ offset+8(FP), DX
+	MOVQ vdso_zx_clock_adjust(SB), AX
+	CALL AX
+	MOVL AX, ret+16(FP)
+	RET
+
+// func sys_system_get_dcache_line_size() uint32
+TEXT ·sys_system_get_dcache_line_size(SB),NOSPLIT,$0-4
+	MOVQ vdso_zx_system_get_dcache_line_size(SB), AX
+	CALL AX
+	MOVL AX, ret+0(FP)
+	RET
+
+// func Sys_system_get_num_cpus() uint32
+TEXT ·Sys_system_get_num_cpus(SB),NOSPLIT,$0-4
+	MOVQ vdso_zx_system_get_num_cpus(SB), AX
+	CALL AX
+	MOVL AX, ret+0(FP)
+	RET
+
+// func Sys_system_get_version(version *uint8, version_size uint) Status
+TEXT ·Sys_system_get_version(SB),NOSPLIT,$0-20
+	MOVQ version+0(FP), DI
+	MOVQ version_size+8(FP), SI
+	MOVQ vdso_zx_system_get_version(SB), AX
+	CALL AX
+	MOVL AX, ret+16(FP)
+	RET
+
+// func Sys_system_get_physmem() uint64
+TEXT ·Sys_system_get_physmem(SB),NOSPLIT,$0-8
+	MOVQ vdso_zx_system_get_physmem(SB), AX
+	CALL AX
+	MOVQ AX, ret+0(FP)
+	RET
+
+// func sys_system_get_features(kind uint32, out *uint32) Status
+TEXT ·sys_system_get_features(SB),NOSPLIT,$0-20
+	MOVL kind+0(FP), DI
+	MOVQ out+8(FP), SI
+	MOVQ vdso_zx_system_get_features(SB), AX
+	CALL AX
+	MOVL AX, ret+16(FP)
+	RET
+
+// func Sys_cache_flush(addr unsafe.Pointer, size uint, options uint32) Status
+TEXT ·Sys_cache_flush(SB),NOSPLIT,$0-28
+	MOVQ addr+0(FP), DI
+	MOVQ size+8(FP), SI
+	MOVL options+16(FP), DX
+	MOVQ vdso_zx_cache_flush(SB), AX
+	CALL AX
+	MOVL AX, ret+24(FP)
+	RET
+
+// func Sys_handle_close(handle Handle) Status
+TEXT ·Sys_handle_close(SB),NOSPLIT,$0-12
+	MOVL handle+0(FP), DI
+	MOVQ vdso_zx_handle_close(SB), AX
+	CALL AX
+	MOVL AX, ret+8(FP)
+	RET
+
+// func Sys_handle_close_many(handles *Handle, num_handles uint) Status
+TEXT ·Sys_handle_close_many(SB),NOSPLIT,$0-20
+	MOVQ handles+0(FP), DI
+	MOVQ num_handles+8(FP), SI
+	MOVQ vdso_zx_handle_close_many(SB), AX
+	CALL AX
+	MOVL AX, ret+16(FP)
+	RET
+
+// func sys_handle_duplicate(handle Handle, rights Rights, out *Handle) Status
+TEXT ·sys_handle_duplicate(SB),NOSPLIT,$0-20
+	MOVL handle+0(FP), DI
+	MOVL rights+4(FP), SI
+	MOVQ out+8(FP), DX
+	MOVQ vdso_zx_handle_duplicate(SB), AX
+	CALL AX
+	MOVL AX, ret+16(FP)
+	RET
+
+// func Sys_handle_replace(handle Handle, rights Rights, out *Handle) Status
+TEXT ·Sys_handle_replace(SB),NOSPLIT,$0-20
+	MOVL handle+0(FP), DI
+	MOVL rights+4(FP), SI
+	MOVQ out+8(FP), DX
+	MOVQ vdso_zx_handle_replace(SB), AX
+	CALL AX
+	MOVL AX, ret+16(FP)
+	RET
+
+// func Sys_object_wait_one(handle Handle, signals Signals, deadline Time, observed *Signals) Status
+TEXT ·Sys_object_wait_one(SB),NOSPLIT,$0-28
+	CALL runtime·entersyscall(SB)
+	MOVL handle+0(FP), DI
+	MOVL signals+4(FP), SI
+	MOVQ deadline+8(FP), DX
+	MOVQ observed+16(FP), CX
+	MOVQ vdso_zx_object_wait_one(SB), AX
+	CALL AX
+	MOVL AX, ret+24(FP)
+	CALL runtime·exitsyscall(SB)
+	RET
+
+// func sys_object_wait_many(items *WaitItem, count uint, deadline Time) Status
+TEXT ·sys_object_wait_many(SB),NOSPLIT,$0-28
+	CALL runtime·entersyscall(SB)
+	MOVQ items+0(FP), DI
+	MOVQ count+8(FP), SI
+	MOVQ deadline+16(FP), DX
+	MOVQ vdso_zx_object_wait_many(SB), AX
+	CALL AX
+	MOVL AX, ret+24(FP)
+	CALL runtime·exitsyscall(SB)
+	RET
+
+// func Sys_object_wait_async(handle Handle, port Handle, key uint64, signals Signals, options uint32) Status
+TEXT ·Sys_object_wait_async(SB),NOSPLIT,$0-28
+	MOVL handle+0(FP), DI
+	MOVL port+4(FP), SI
+	MOVQ key+8(FP), DX
+	MOVL signals+16(FP), CX
+	MOVL options+20(FP), R8
+	MOVQ vdso_zx_object_wait_async(SB), AX
+	CALL AX
+	MOVL AX, ret+24(FP)
+	RET
+
+// func Sys_object_signal(handle Handle, clear_mask uint32, set_mask uint32) Status
+TEXT ·Sys_object_signal(SB),NOSPLIT,$0-20
+	MOVL handle+0(FP), DI
+	MOVL clear_mask+4(FP), SI
+	MOVL set_mask+8(FP), DX
+	MOVQ vdso_zx_object_signal(SB), AX
+	CALL AX
+	MOVL AX, ret+16(FP)
+	RET
+
+// func Sys_object_signal_peer(handle Handle, clear_mask uint32, set_mask uint32) Status
+TEXT ·Sys_object_signal_peer(SB),NOSPLIT,$0-20
+	MOVL handle+0(FP), DI
+	MOVL clear_mask+4(FP), SI
+	MOVL set_mask+8(FP), DX
+	MOVQ vdso_zx_object_signal_peer(SB), AX
+	CALL AX
+	MOVL AX, ret+16(FP)
+	RET
+
+// func Sys_object_get_property(handle Handle, property uint32, value unsafe.Pointer, value_size uint) Status
+TEXT ·Sys_object_get_property(SB),NOSPLIT,$0-28
+	MOVL handle+0(FP), DI
+	MOVL property+4(FP), SI
+	MOVQ value+8(FP), DX
+	MOVQ value_size+16(FP), CX
+	MOVQ vdso_zx_object_get_property(SB), AX
+	CALL AX
+	MOVL AX, ret+24(FP)
+	RET
+
+// func Sys_object_set_property(handle Handle, property uint32, value unsafe.Pointer, value_size uint) Status
+TEXT ·Sys_object_set_property(SB),NOSPLIT,$0-28
+	MOVL handle+0(FP), DI
+	MOVL property+4(FP), SI
+	MOVQ value+8(FP), DX
+	MOVQ value_size+16(FP), CX
+	MOVQ vdso_zx_object_set_property(SB), AX
+	CALL AX
+	MOVL AX, ret+24(FP)
+	RET
+
+// func Sys_object_set_cookie(handle Handle, scope Handle, cookie uint64) Status
+TEXT ·Sys_object_set_cookie(SB),NOSPLIT,$0-20
+	MOVL handle+0(FP), DI
+	MOVL scope+4(FP), SI
+	MOVQ cookie+8(FP), DX
+	MOVQ vdso_zx_object_set_cookie(SB), AX
+	CALL AX
+	MOVL AX, ret+16(FP)
+	RET
+
+// func Sys_object_get_cookie(handle Handle, scope Handle, cookie *uint64) Status
+TEXT ·Sys_object_get_cookie(SB),NOSPLIT,$0-20
+	MOVL handle+0(FP), DI
+	MOVL scope+4(FP), SI
+	MOVQ cookie+8(FP), DX
+	MOVQ vdso_zx_object_get_cookie(SB), AX
+	CALL AX
+	MOVL AX, ret+16(FP)
+	RET
+
+// func Sys_object_get_info(handle Handle, topic uint32, buffer unsafe.Pointer, buffer_size uint, actual_count *uint, avail_count *uint) Status
+TEXT ·Sys_object_get_info(SB),NOSPLIT,$0-44
+	MOVL handle+0(FP), DI
+	MOVL topic+4(FP), SI
+	MOVQ buffer+8(FP), DX
+	MOVQ buffer_size+16(FP), CX
+	MOVQ actual_count+24(FP), R8
+	MOVQ avail_count+32(FP), R9
+	MOVQ vdso_zx_object_get_info(SB), AX
+	CALL AX
+	MOVL AX, ret+40(FP)
+	RET
+
+// func Sys_object_get_child(handle Handle, koid uint64, rights Rights, out *Handle) Status
+TEXT ·Sys_object_get_child(SB),NOSPLIT,$0-36
+	MOVL handle+0(FP), DI
+	MOVQ koid+8(FP), SI
+	MOVL rights+16(FP), DX
+	MOVQ out+24(FP), CX
+	MOVQ vdso_zx_object_get_child(SB), AX
+	CALL AX
+	MOVL AX, ret+32(FP)
+	RET
+
+// func sys_object_set_profile(handle Handle, profile Handle, options uint32) Status
+TEXT ·sys_object_set_profile(SB),NOSPLIT,$0-20
+	MOVL handle+0(FP), DI
+	MOVL profile+4(FP), SI
+	MOVL options+8(FP), DX
+	MOVQ vdso_zx_object_set_profile(SB), AX
+	CALL AX
+	MOVL AX, ret+16(FP)
+	RET
+
+// func sys_channel_create(options uint32, out0 *Handle, out1 *Handle) Status
+TEXT ·sys_channel_create(SB),NOSPLIT,$0-28
+	MOVL options+0(FP), DI
+	MOVQ out0+8(FP), SI
+	MOVQ out1+16(FP), DX
+	MOVQ vdso_zx_channel_create(SB), AX
+	CALL AX
+	MOVL AX, ret+24(FP)
+	RET
+
+// func sys_channel_read(handle Handle, options uint32, bytes unsafe.Pointer, handles *Handle, num_bytes uint32, num_handles uint32, actual_bytes *uint32, actual_handles *uint32) Status
+TEXT ·sys_channel_read(SB),NOSPLIT,$32-52
+	MOVL handle+0(FP), DI
+	MOVL options+4(FP), SI
+	MOVQ bytes+8(FP), DX
+	MOVQ handles+16(FP), CX
+	MOVL num_bytes+24(FP), R8
+	MOVL num_handles+28(FP), R9
+	MOVQ actual_bytes+32(FP), R12
+	MOVQ actual_handles+40(FP), R13
+	MOVQ SP, BP   // BP is preserved across vsdo call by the x86-64 ABI
+	ANDQ $~15, SP // stack alignment for x86-64 ABI
+	PUSHQ R13
+	PUSHQ R12
+	MOVQ vdso_zx_channel_read(SB), AX
+	CALL AX
+	POPQ R12
+	POPQ R13
+	MOVQ BP, SP
+	MOVL AX, ret+48(FP)
+	RET
+
+// func sys_channel_read_etc(handle Handle, options uint32, bytes unsafe.Pointer, handles *int, num_bytes uint32, num_handles uint32, actual_bytes *uint32, actual_handles *uint32) Status
+TEXT ·sys_channel_read_etc(SB),NOSPLIT,$32-52
+	MOVL handle+0(FP), DI
+	MOVL options+4(FP), SI
+	MOVQ bytes+8(FP), DX
+	MOVQ handles+16(FP), CX
+	MOVL num_bytes+24(FP), R8
+	MOVL num_handles+28(FP), R9
+	MOVQ actual_bytes+32(FP), R12
+	MOVQ actual_handles+40(FP), R13
+	MOVQ SP, BP   // BP is preserved across vsdo call by the x86-64 ABI
+	ANDQ $~15, SP // stack alignment for x86-64 ABI
+	PUSHQ R13
+	PUSHQ R12
+	MOVQ vdso_zx_channel_read_etc(SB), AX
+	CALL AX
+	POPQ R12
+	POPQ R13
+	MOVQ BP, SP
+	MOVL AX, ret+48(FP)
+	RET
+
+// func sys_channel_write(handle Handle, options uint32, bytes unsafe.Pointer, num_bytes uint32, handles *Handle, num_handles uint32) Status
+TEXT ·sys_channel_write(SB),NOSPLIT,$0-44
+	MOVL handle+0(FP), DI
+	MOVL options+4(FP), SI
+	MOVQ bytes+8(FP), DX
+	MOVL num_bytes+16(FP), CX
+	MOVQ handles+24(FP), R8
+	MOVL num_handles+32(FP), R9
+	MOVQ vdso_zx_channel_write(SB), AX
+	CALL AX
+	MOVL AX, ret+40(FP)
+	RET
+
+// func Sys_channel_call_noretry(handle Handle, options uint32, deadline Time, args *ChannelCallArgs, actual_bytes *uint32, actual_handles *uint32) Status
+TEXT ·Sys_channel_call_noretry(SB),NOSPLIT,$0-44
+	MOVL handle+0(FP), DI
+	MOVL options+4(FP), SI
+	MOVQ deadline+8(FP), DX
+	MOVQ args+16(FP), CX
+	MOVQ actual_bytes+24(FP), R8
+	MOVQ actual_handles+32(FP), R9
+	MOVQ vdso_zx_channel_call_noretry(SB), AX
+	CALL AX
+	MOVL AX, ret+40(FP)
+	RET
+
+// func Sys_channel_call_finish(deadline Time, args *ChannelCallArgs, actual_bytes *uint32, actual_handles *uint32) Status
+TEXT ·Sys_channel_call_finish(SB),NOSPLIT,$0-36
+	MOVQ deadline+0(FP), DI
+	MOVQ args+8(FP), SI
+	MOVQ actual_bytes+16(FP), DX
+	MOVQ actual_handles+24(FP), CX
+	MOVQ vdso_zx_channel_call_finish(SB), AX
+	CALL AX
+	MOVL AX, ret+32(FP)
+	RET
+
+// func Sys_channel_call(handle Handle, options uint32, deadline Time, args *ChannelCallArgs, actual_bytes *uint32, actual_handles *uint32) Status
+TEXT ·Sys_channel_call(SB),NOSPLIT,$0-44
+	MOVL handle+0(FP), DI
+	MOVL options+4(FP), SI
+	MOVQ deadline+8(FP), DX
+	MOVQ args+16(FP), CX
+	MOVQ actual_bytes+24(FP), R8
+	MOVQ actual_handles+32(FP), R9
+	MOVQ vdso_zx_channel_call(SB), AX
+	CALL AX
+	MOVL AX, ret+40(FP)
+	RET
+
+// func sys_socket_create(options uint32, out0 *Handle, out1 *Handle) Status
+TEXT ·sys_socket_create(SB),NOSPLIT,$0-28
+	MOVL options+0(FP), DI
+	MOVQ out0+8(FP), SI
+	MOVQ out1+16(FP), DX
+	MOVQ vdso_zx_socket_create(SB), AX
+	CALL AX
+	MOVL AX, ret+24(FP)
+	RET
+
+// func sys_socket_write(handle Handle, options uint32, buffer unsafe.Pointer, buffer_size uint, actual *uint) Status
+TEXT ·sys_socket_write(SB),NOSPLIT,$0-36
+	MOVL handle+0(FP), DI
+	MOVL options+4(FP), SI
+	MOVQ buffer+8(FP), DX
+	MOVQ buffer_size+16(FP), CX
+	MOVQ actual+24(FP), R8
+	MOVQ vdso_zx_socket_write(SB), AX
+	CALL AX
+	MOVL AX, ret+32(FP)
+	RET
+
+// func sys_socket_read(handle Handle, options uint32, buffer unsafe.Pointer, buffer_size uint, actual *uint) Status
+TEXT ·sys_socket_read(SB),NOSPLIT,$0-36
+	MOVL handle+0(FP), DI
+	MOVL options+4(FP), SI
+	MOVQ buffer+8(FP), DX
+	MOVQ buffer_size+16(FP), CX
+	MOVQ actual+24(FP), R8
+	MOVQ vdso_zx_socket_read(SB), AX
+	CALL AX
+	MOVL AX, ret+32(FP)
+	RET
+
+// func sys_socket_share(handle Handle, socket_to_share Handle) Status
+TEXT ·sys_socket_share(SB),NOSPLIT,$0-12
+	MOVL handle+0(FP), DI
+	MOVL socket_to_share+4(FP), SI
+	MOVQ vdso_zx_socket_share(SB), AX
+	CALL AX
+	MOVL AX, ret+8(FP)
+	RET
+
+// func sys_socket_accept(handle Handle, out_socket *Handle) Status
+TEXT ·sys_socket_accept(SB),NOSPLIT,$0-20
+	MOVL handle+0(FP), DI
+	MOVQ out_socket+8(FP), SI
+	MOVQ vdso_zx_socket_accept(SB), AX
+	CALL AX
+	MOVL AX, ret+16(FP)
+	RET
+
+// func Sys_thread_exit()
+TEXT ·Sys_thread_exit(SB),NOSPLIT,$0-0
+	MOVQ vdso_zx_thread_exit(SB), AX
+	CALL AX
+	RET
+
+// func Sys_thread_create(process Handle, name *uint8, name_size uint, options uint32, out *Handle) Status
+TEXT ·Sys_thread_create(SB),NOSPLIT,$0-44
+	MOVL process+0(FP), DI
+	MOVQ name+8(FP), SI
+	MOVQ name_size+16(FP), DX
+	MOVL options+24(FP), CX
+	MOVQ out+32(FP), R8
+	MOVQ vdso_zx_thread_create(SB), AX
+	CALL AX
+	MOVL AX, ret+40(FP)
+	RET
+
+// func Sys_thread_start(handle Handle, thread_entry Vaddr, stack Vaddr, arg1 uintptr, arg2 uintptr) Status
+TEXT ·Sys_thread_start(SB),NOSPLIT,$0-44
+	MOVL handle+0(FP), DI
+	MOVQ thread_entry+8(FP), SI
+	MOVQ stack+16(FP), DX
+	MOVQ arg1+24(FP), CX
+	MOVQ arg2+32(FP), R8
+	MOVQ vdso_zx_thread_start(SB), AX
+	CALL AX
+	MOVL AX, ret+40(FP)
+	RET
+
+// func Sys_thread_read_state(handle Handle, kind uint32, buffer unsafe.Pointer, buffer_size uint) Status
+TEXT ·Sys_thread_read_state(SB),NOSPLIT,$0-28
+	MOVL handle+0(FP), DI
+	MOVL kind+4(FP), SI
+	MOVQ buffer+8(FP), DX
+	MOVQ buffer_size+16(FP), CX
+	MOVQ vdso_zx_thread_read_state(SB), AX
+	CALL AX
+	MOVL AX, ret+24(FP)
+	RET
+
+// func Sys_thread_write_state(handle Handle, kind uint32, buffer unsafe.Pointer, buffer_size uint) Status
+TEXT ·Sys_thread_write_state(SB),NOSPLIT,$0-28
+	MOVL handle+0(FP), DI
+	MOVL kind+4(FP), SI
+	MOVQ buffer+8(FP), DX
+	MOVQ buffer_size+16(FP), CX
+	MOVQ vdso_zx_thread_write_state(SB), AX
+	CALL AX
+	MOVL AX, ret+24(FP)
+	RET
+
+// func Sys_thread_set_priority(prio int32) Status
+TEXT ·Sys_thread_set_priority(SB),NOSPLIT,$0-12
+	MOVL prio+0(FP), DI
+	MOVQ vdso_zx_thread_set_priority(SB), AX
+	CALL AX
+	MOVL AX, ret+8(FP)
+	RET
+
+// func Sys_process_exit(retcode int64)
+TEXT ·Sys_process_exit(SB),NOSPLIT,$0-8
+	MOVQ retcode+0(FP), DI
+	MOVQ vdso_zx_process_exit(SB), AX
+	CALL AX
+	RET
+
+// func Sys_process_create(job Handle, name *uint8, name_size uint, options uint32, proc_handle *Handle, vmar_handle *Handle) Status
+TEXT ·Sys_process_create(SB),NOSPLIT,$0-52
+	MOVL job+0(FP), DI
+	MOVQ name+8(FP), SI
+	MOVQ name_size+16(FP), DX
+	MOVL options+24(FP), CX
+	MOVQ proc_handle+32(FP), R8
+	MOVQ vmar_handle+40(FP), R9
+	MOVQ vdso_zx_process_create(SB), AX
+	CALL AX
+	MOVL AX, ret+48(FP)
+	RET
+
+// func Sys_process_start(handle Handle, thread Handle, entry Vaddr, stack Vaddr, arg1 Handle, arg2 uintptr) Status
+TEXT ·Sys_process_start(SB),NOSPLIT,$0-44
+	MOVL handle+0(FP), DI
+	MOVL thread+4(FP), SI
+	MOVQ entry+8(FP), DX
+	MOVQ stack+16(FP), CX
+	MOVL arg1+24(FP), R8
+	MOVQ arg2+32(FP), R9
+	MOVQ vdso_zx_process_start(SB), AX
+	CALL AX
+	MOVL AX, ret+40(FP)
+	RET
+
+// func Sys_process_read_memory(proc Handle, vaddr Vaddr, buffer unsafe.Pointer, buffer_size uint, actual *uint) Status
+TEXT ·Sys_process_read_memory(SB),NOSPLIT,$0-44
+	MOVL proc+0(FP), DI
+	MOVQ vaddr+8(FP), SI
+	MOVQ buffer+16(FP), DX
+	MOVQ buffer_size+24(FP), CX
+	MOVQ actual+32(FP), R8
+	MOVQ vdso_zx_process_read_memory(SB), AX
+	CALL AX
+	MOVL AX, ret+40(FP)
+	RET
+
+// func Sys_process_write_memory(proc Handle, vaddr Vaddr, buffer unsafe.Pointer, buffer_size uint, actual *uint) Status
+TEXT ·Sys_process_write_memory(SB),NOSPLIT,$0-44
+	MOVL proc+0(FP), DI
+	MOVQ vaddr+8(FP), SI
+	MOVQ buffer+16(FP), DX
+	MOVQ buffer_size+24(FP), CX
+	MOVQ actual+32(FP), R8
+	MOVQ vdso_zx_process_write_memory(SB), AX
+	CALL AX
+	MOVL AX, ret+40(FP)
+	RET
+
+// func Sys_job_create(parent_job Handle, options uint32, out *Handle) Status
+TEXT ·Sys_job_create(SB),NOSPLIT,$0-20
+	MOVL parent_job+0(FP), DI
+	MOVL options+4(FP), SI
+	MOVQ out+8(FP), DX
+	MOVQ vdso_zx_job_create(SB), AX
+	CALL AX
+	MOVL AX, ret+16(FP)
+	RET
+
+// func Sys_job_set_policy(job Handle, options uint32, topic uint32, policy unsafe.Pointer, count uint32) Status
+TEXT ·Sys_job_set_policy(SB),NOSPLIT,$0-36
+	MOVL job+0(FP), DI
+	MOVL options+4(FP), SI
+	MOVL topic+8(FP), DX
+	MOVQ policy+16(FP), CX
+	MOVL count+24(FP), R8
+	MOVQ vdso_zx_job_set_policy(SB), AX
+	CALL AX
+	MOVL AX, ret+32(FP)
+	RET
+
+// func Sys_task_bind_exception_port(handle Handle, port Handle, key uint64, options uint32) Status
+TEXT ·Sys_task_bind_exception_port(SB),NOSPLIT,$0-28
+	MOVL handle+0(FP), DI
+	MOVL port+4(FP), SI
+	MOVQ key+8(FP), DX
+	MOVL options+16(FP), CX
+	MOVQ vdso_zx_task_bind_exception_port(SB), AX
+	CALL AX
+	MOVL AX, ret+24(FP)
+	RET
+
+// func Sys_task_resume(handle Handle, options uint32) Status
+TEXT ·Sys_task_resume(SB),NOSPLIT,$0-12
+	MOVL handle+0(FP), DI
+	MOVL options+4(FP), SI
+	MOVQ vdso_zx_task_resume(SB), AX
+	CALL AX
+	MOVL AX, ret+8(FP)
+	RET
+
+// func Sys_task_suspend(handle Handle, token *Handle) Status
+TEXT ·Sys_task_suspend(SB),NOSPLIT,$0-20
+	MOVL handle+0(FP), DI
+	MOVQ token+8(FP), SI
+	MOVQ vdso_zx_task_suspend(SB), AX
+	CALL AX
+	MOVL AX, ret+16(FP)
+	RET
+
+// func Sys_task_suspend_token(handle Handle, token *Handle) Status
+TEXT ·Sys_task_suspend_token(SB),NOSPLIT,$0-20
+	MOVL handle+0(FP), DI
+	MOVQ token+8(FP), SI
+	MOVQ vdso_zx_task_suspend_token(SB), AX
+	CALL AX
+	MOVL AX, ret+16(FP)
+	RET
+
+// func Sys_task_resume_from_exception(handle Handle, port Handle, options uint32) Status
+TEXT ·Sys_task_resume_from_exception(SB),NOSPLIT,$0-20
+	MOVL handle+0(FP), DI
+	MOVL port+4(FP), SI
+	MOVL options+8(FP), DX
+	MOVQ vdso_zx_task_resume_from_exception(SB), AX
+	CALL AX
+	MOVL AX, ret+16(FP)
+	RET
+
+// func Sys_task_kill(handle Handle) Status
+TEXT ·Sys_task_kill(SB),NOSPLIT,$0-12
+	MOVL handle+0(FP), DI
+	MOVQ vdso_zx_task_kill(SB), AX
+	CALL AX
+	MOVL AX, ret+8(FP)
+	RET
+
+// func Sys_event_create(options uint32, out *Handle) Status
+TEXT ·Sys_event_create(SB),NOSPLIT,$0-20
+	MOVL options+0(FP), DI
+	MOVQ out+8(FP), SI
+	MOVQ vdso_zx_event_create(SB), AX
+	CALL AX
+	MOVL AX, ret+16(FP)
+	RET
+
+// func Sys_eventpair_create(options uint32, out0 *Handle, out1 *Handle) Status
+TEXT ·Sys_eventpair_create(SB),NOSPLIT,$0-28
+	MOVL options+0(FP), DI
+	MOVQ out0+8(FP), SI
+	MOVQ out1+16(FP), DX
+	MOVQ vdso_zx_eventpair_create(SB), AX
+	CALL AX
+	MOVL AX, ret+24(FP)
+	RET
+
+// func Sys_futex_wait(value_ptr *int, current_value int32, deadline Time) Status
+TEXT ·Sys_futex_wait(SB),NOSPLIT,$0-28
+	MOVQ value_ptr+0(FP), DI
+	MOVL current_value+8(FP), SI
+	MOVQ deadline+16(FP), DX
+	MOVQ vdso_zx_futex_wait(SB), AX
+	CALL AX
+	MOVL AX, ret+24(FP)
+	RET
+
+// func Sys_futex_wake(value_ptr *int, count uint32) Status
+TEXT ·Sys_futex_wake(SB),NOSPLIT,$0-20
+	MOVQ value_ptr+0(FP), DI
+	MOVL count+8(FP), SI
+	MOVQ vdso_zx_futex_wake(SB), AX
+	CALL AX
+	MOVL AX, ret+16(FP)
+	RET
+
+// func Sys_futex_requeue(wake_ptr *int, wake_count uint32, current_value int32, requeue_ptr *int, requeue_count uint32) Status
+TEXT ·Sys_futex_requeue(SB),NOSPLIT,$0-36
+	MOVQ wake_ptr+0(FP), DI
+	MOVL wake_count+8(FP), SI
+	MOVL current_value+12(FP), DX
+	MOVQ requeue_ptr+16(FP), CX
+	MOVL requeue_count+24(FP), R8
+	MOVQ vdso_zx_futex_requeue(SB), AX
+	CALL AX
+	MOVL AX, ret+32(FP)
+	RET
+
+// func Sys_port_create(options uint32, out *Handle) Status
+TEXT ·Sys_port_create(SB),NOSPLIT,$0-20
+	MOVL options+0(FP), DI
+	MOVQ out+8(FP), SI
+	MOVQ vdso_zx_port_create(SB), AX
+	CALL AX
+	MOVL AX, ret+16(FP)
+	RET
+
+// func Sys_port_queue(handle Handle, packet *int) Status
+TEXT ·Sys_port_queue(SB),NOSPLIT,$0-20
+	MOVL handle+0(FP), DI
+	MOVQ packet+8(FP), SI
+	MOVQ vdso_zx_port_queue(SB), AX
+	CALL AX
+	MOVL AX, ret+16(FP)
+	RET
+
+// func Sys_port_wait(handle Handle, deadline Time, packet *int) Status
+TEXT ·Sys_port_wait(SB),NOSPLIT,$0-28
+	CALL runtime·entersyscall(SB)
+	MOVL handle+0(FP), DI
+	MOVQ deadline+8(FP), SI
+	MOVQ packet+16(FP), DX
+	MOVQ vdso_zx_port_wait(SB), AX
+	CALL AX
+	MOVL AX, ret+24(FP)
+	CALL runtime·exitsyscall(SB)
+	RET
+
+// func Sys_port_cancel(handle Handle, source Handle, key uint64) Status
+TEXT ·Sys_port_cancel(SB),NOSPLIT,$0-20
+	MOVL handle+0(FP), DI
+	MOVL source+4(FP), SI
+	MOVQ key+8(FP), DX
+	MOVQ vdso_zx_port_cancel(SB), AX
+	CALL AX
+	MOVL AX, ret+16(FP)
+	RET
+
+// func Sys_timer_create(options uint32, clock_id uint32, out *Handle) Status
+TEXT ·Sys_timer_create(SB),NOSPLIT,$0-20
+	MOVL options+0(FP), DI
+	MOVL clock_id+4(FP), SI
+	MOVQ out+8(FP), DX
+	MOVQ vdso_zx_timer_create(SB), AX
+	CALL AX
+	MOVL AX, ret+16(FP)
+	RET
+
+// func Sys_timer_set(handle Handle, deadline Time, slack Duration) Status
+TEXT ·Sys_timer_set(SB),NOSPLIT,$0-28
+	MOVL handle+0(FP), DI
+	MOVQ deadline+8(FP), SI
+	MOVQ slack+16(FP), DX
+	MOVQ vdso_zx_timer_set(SB), AX
+	CALL AX
+	MOVL AX, ret+24(FP)
+	RET
+
+// func Sys_timer_cancel(handle Handle) Status
+TEXT ·Sys_timer_cancel(SB),NOSPLIT,$0-12
+	MOVL handle+0(FP), DI
+	MOVQ vdso_zx_timer_cancel(SB), AX
+	CALL AX
+	MOVL AX, ret+8(FP)
+	RET
+
+// func Sys_vmo_create(size uint64, options uint32, out *Handle) Status
+TEXT ·Sys_vmo_create(SB),NOSPLIT,$0-28
+	MOVQ size+0(FP), DI
+	MOVL options+8(FP), SI
+	MOVQ out+16(FP), DX
+	MOVQ vdso_zx_vmo_create(SB), AX
+	CALL AX
+	MOVL AX, ret+24(FP)
+	RET
+
+// func sys_vmo_read(handle Handle, buffer unsafe.Pointer, offset uint64, buffer_size uint) Status
+TEXT ·sys_vmo_read(SB),NOSPLIT,$0-36
+	MOVL handle+0(FP), DI
+	MOVQ buffer+8(FP), SI
+	MOVQ offset+16(FP), DX
+	MOVQ buffer_size+24(FP), CX
+	MOVQ vdso_zx_vmo_read(SB), AX
+	CALL AX
+	MOVL AX, ret+32(FP)
+	RET
+
+// func sys_vmo_write(handle Handle, buffer unsafe.Pointer, offset uint64, buffer_size uint) Status
+TEXT ·sys_vmo_write(SB),NOSPLIT,$0-36
+	MOVL handle+0(FP), DI
+	MOVQ buffer+8(FP), SI
+	MOVQ offset+16(FP), DX
+	MOVQ buffer_size+24(FP), CX
+	MOVQ vdso_zx_vmo_write(SB), AX
+	CALL AX
+	MOVL AX, ret+32(FP)
+	RET
+
+// func sys_vmo_get_size(handle Handle, size *uint64) Status
+TEXT ·sys_vmo_get_size(SB),NOSPLIT,$0-20
+	MOVL handle+0(FP), DI
+	MOVQ size+8(FP), SI
+	MOVQ vdso_zx_vmo_get_size(SB), AX
+	CALL AX
+	MOVL AX, ret+16(FP)
+	RET
+
+// func sys_vmo_set_size(handle Handle, size uint64) Status
+TEXT ·sys_vmo_set_size(SB),NOSPLIT,$0-20
+	MOVL handle+0(FP), DI
+	MOVQ size+8(FP), SI
+	MOVQ vdso_zx_vmo_set_size(SB), AX
+	CALL AX
+	MOVL AX, ret+16(FP)
+	RET
+
+// func sys_vmo_op_range(handle Handle, op uint32, offset uint64, size uint64, buffer unsafe.Pointer, buffer_size uint) Status
+TEXT ·sys_vmo_op_range(SB),NOSPLIT,$0-44
+	MOVL handle+0(FP), DI
+	MOVL op+4(FP), SI
+	MOVQ offset+8(FP), DX
+	MOVQ size+16(FP), CX
+	MOVQ buffer+24(FP), R8
+	MOVQ buffer_size+32(FP), R9
+	MOVQ vdso_zx_vmo_op_range(SB), AX
+	CALL AX
+	MOVL AX, ret+40(FP)
+	RET
+
+// func Sys_vmo_clone(handle Handle, options uint32, offset uint64, size uint64, out *Handle) Status
+TEXT ·Sys_vmo_clone(SB),NOSPLIT,$0-36
+	MOVL handle+0(FP), DI
+	MOVL options+4(FP), SI
+	MOVQ offset+8(FP), DX
+	MOVQ size+16(FP), CX
+	MOVQ out+24(FP), R8
+	MOVQ vdso_zx_vmo_clone(SB), AX
+	CALL AX
+	MOVL AX, ret+32(FP)
+	RET
+
+// func Sys_vmo_set_cache_policy(handle Handle, cache_policy uint32) Status
+TEXT ·Sys_vmo_set_cache_policy(SB),NOSPLIT,$0-12
+	MOVL handle+0(FP), DI
+	MOVL cache_policy+4(FP), SI
+	MOVQ vdso_zx_vmo_set_cache_policy(SB), AX
+	CALL AX
+	MOVL AX, ret+8(FP)
+	RET
+
+// func sys_vmar_allocate_old(parent_vmar Handle, offset uint64, size uint64, map_flags uint32, child_vmar *Handle, child_addr *Vaddr) Status
+TEXT ·sys_vmar_allocate_old(SB),NOSPLIT,$0-52
+	MOVL parent_vmar+0(FP), DI
+	MOVQ offset+8(FP), SI
+	MOVQ size+16(FP), DX
+	MOVL map_flags+24(FP), CX
+	MOVQ child_vmar+32(FP), R8
+	MOVQ child_addr+40(FP), R9
+	MOVQ vdso_zx_vmar_allocate_old(SB), AX
+	CALL AX
+	MOVL AX, ret+48(FP)
+	RET
+
+// func sys_vmar_map_old(handle Handle, vmar_offset uint64, vmo Handle, vmo_offset uint64, len uint64, map_flags uint32, mapped_addr *Vaddr) Status
+TEXT ·sys_vmar_map_old(SB),NOSPLIT,$24-60
+	MOVL handle+0(FP), DI
+	MOVQ vmar_offset+8(FP), SI
+	MOVL vmo+16(FP), DX
+	MOVQ vmo_offset+24(FP), CX
+	MOVQ len+32(FP), R8
+	MOVL map_flags+40(FP), R9
+	MOVQ mapped_addr+48(FP), R12
+	MOVQ SP, BP   // BP is preserved across vsdo call by the x86-64 ABI
+	ANDQ $~15, SP // stack alignment for x86-64 ABI
+	PUSHQ R12
+	MOVQ vdso_zx_vmar_map_old(SB), AX
+	CALL AX
+	POPQ R12
+	MOVQ BP, SP
+	MOVL AX, ret+56(FP)
+	RET
+
+// func sys_vmar_protect_old(handle Handle, addr Vaddr, len uint64, prot_flags uint32) Status
+TEXT ·sys_vmar_protect_old(SB),NOSPLIT,$0-36
+	MOVL handle+0(FP), DI
+	MOVQ addr+8(FP), SI
+	MOVQ len+16(FP), DX
+	MOVL prot_flags+24(FP), CX
+	MOVQ vdso_zx_vmar_protect_old(SB), AX
+	CALL AX
+	MOVL AX, ret+32(FP)
+	RET
+
+// func sys_vmar_allocate(parent_vmar Handle, offset uint64, size uint64, map_flags uint32, child_vmar *Handle, child_addr *Vaddr) Status
+TEXT ·sys_vmar_allocate(SB),NOSPLIT,$0-52
+	MOVL parent_vmar+0(FP), DI
+	MOVQ offset+8(FP), SI
+	MOVQ size+16(FP), DX
+	MOVL map_flags+24(FP), CX
+	MOVQ child_vmar+32(FP), R8
+	MOVQ child_addr+40(FP), R9
+	MOVQ vdso_zx_vmar_allocate(SB), AX
+	CALL AX
+	MOVL AX, ret+48(FP)
+	RET
+
+// func sys_vmar_destroy(handle Handle) Status
+TEXT ·sys_vmar_destroy(SB),NOSPLIT,$0-12
+	MOVL handle+0(FP), DI
+	MOVQ vdso_zx_vmar_destroy(SB), AX
+	CALL AX
+	MOVL AX, ret+8(FP)
+	RET
+
+// func Sys_vmar_map(handle Handle, vmar_offset uint64, vmo Handle, vmo_offset uint64, len uint64, map_flags uint32, mapped_addr *Vaddr) Status
+TEXT ·Sys_vmar_map(SB),NOSPLIT,$24-60
+	MOVL handle+0(FP), DI
+	MOVQ vmar_offset+8(FP), SI
+	MOVL vmo+16(FP), DX
+	MOVQ vmo_offset+24(FP), CX
+	MOVQ len+32(FP), R8
+	MOVL map_flags+40(FP), R9
+	MOVQ mapped_addr+48(FP), R12
+	MOVQ SP, BP   // BP is preserved across vsdo call by the x86-64 ABI
+	ANDQ $~15, SP // stack alignment for x86-64 ABI
+	PUSHQ R12
+	MOVQ vdso_zx_vmar_map(SB), AX
+	CALL AX
+	POPQ R12
+	MOVQ BP, SP
+	MOVL AX, ret+56(FP)
+	RET
+
+// func Sys_vmar_unmap(handle Handle, addr Vaddr, len uint64) Status
+TEXT ·Sys_vmar_unmap(SB),NOSPLIT,$0-28
+	MOVL handle+0(FP), DI
+	MOVQ addr+8(FP), SI
+	MOVQ len+16(FP), DX
+	MOVQ vdso_zx_vmar_unmap(SB), AX
+	CALL AX
+	MOVL AX, ret+24(FP)
+	RET
+
+// func Sys_vmar_protect(handle Handle, addr Vaddr, len uint64, prot_flags uint32) Status
+TEXT ·Sys_vmar_protect(SB),NOSPLIT,$0-36
+	MOVL handle+0(FP), DI
+	MOVQ addr+8(FP), SI
+	MOVQ len+16(FP), DX
+	MOVL prot_flags+24(FP), CX
+	MOVQ vdso_zx_vmar_protect(SB), AX
+	CALL AX
+	MOVL AX, ret+32(FP)
+	RET
+
+// func Sys_cprng_draw_once(buffer unsafe.Pointer, buffer_size uint) Status
+TEXT ·Sys_cprng_draw_once(SB),NOSPLIT,$0-20
+	MOVQ buffer+0(FP), DI
+	MOVQ buffer_size+8(FP), SI
+	MOVQ vdso_zx_cprng_draw_once(SB), AX
+	CALL AX
+	MOVL AX, ret+16(FP)
+	RET
+
+// func Sys_cprng_draw(buffer unsafe.Pointer, buffer_size uint)
+TEXT ·Sys_cprng_draw(SB),NOSPLIT,$0-16
+	MOVQ buffer+0(FP), DI
+	MOVQ buffer_size+8(FP), SI
+	MOVQ vdso_zx_cprng_draw(SB), AX
+	CALL AX
+	RET
+
+// func Sys_cprng_draw_new(buffer unsafe.Pointer, data_size uint) Status
+TEXT ·Sys_cprng_draw_new(SB),NOSPLIT,$0-20
+	MOVQ buffer+0(FP), DI
+	MOVQ data_size+8(FP), SI
+	MOVQ vdso_zx_cprng_draw_new(SB), AX
+	CALL AX
+	MOVL AX, ret+16(FP)
+	RET
+
+// func Sys_cprng_add_entropy(buffer unsafe.Pointer, len uint) Status
+TEXT ·Sys_cprng_add_entropy(SB),NOSPLIT,$0-20
+	MOVQ buffer+0(FP), DI
+	MOVQ len+8(FP), SI
+	MOVQ vdso_zx_cprng_add_entropy(SB), AX
+	CALL AX
+	MOVL AX, ret+16(FP)
+	RET
+
+// func Sys_fifo_create(elem_count uint, elem_size uint, options uint32, out0 *Handle, out1 *Handle) Status
+TEXT ·Sys_fifo_create(SB),NOSPLIT,$0-44
+	MOVQ elem_count+0(FP), DI
+	MOVQ elem_size+8(FP), SI
+	MOVL options+16(FP), DX
+	MOVQ out0+24(FP), CX
+	MOVQ out1+32(FP), R8
+	MOVQ vdso_zx_fifo_create(SB), AX
+	CALL AX
+	MOVL AX, ret+40(FP)
+	RET
+
+// func Sys_fifo_read(handle Handle, elem_size uint, data unsafe.Pointer, count uint, actual_count *uint) Status
+TEXT ·Sys_fifo_read(SB),NOSPLIT,$0-44
+	MOVL handle+0(FP), DI
+	MOVQ elem_size+8(FP), SI
+	MOVQ data+16(FP), DX
+	MOVQ count+24(FP), CX
+	MOVQ actual_count+32(FP), R8
+	MOVQ vdso_zx_fifo_read(SB), AX
+	CALL AX
+	MOVL AX, ret+40(FP)
+	RET
+
+// func Sys_fifo_write(handle Handle, elem_size uint, data unsafe.Pointer, count uint, actual_count *uint) Status
+TEXT ·Sys_fifo_write(SB),NOSPLIT,$0-44
+	MOVL handle+0(FP), DI
+	MOVQ elem_size+8(FP), SI
+	MOVQ data+16(FP), DX
+	MOVQ count+24(FP), CX
+	MOVQ actual_count+32(FP), R8
+	MOVQ vdso_zx_fifo_write(SB), AX
+	CALL AX
+	MOVL AX, ret+40(FP)
+	RET
+
+// func Sys_profile_create(resource Handle, profile *int, out *Handle) Status
+TEXT ·Sys_profile_create(SB),NOSPLIT,$0-28
+	MOVL resource+0(FP), DI
+	MOVQ profile+8(FP), SI
+	MOVQ out+16(FP), DX
+	MOVQ vdso_zx_profile_create(SB), AX
+	CALL AX
+	MOVL AX, ret+24(FP)
+	RET
+
+// func Sys_vmar_unmap_handle_close_thread_exit(vmar_handle Handle, addr Vaddr, size uint, handle Handle) Status
+TEXT ·Sys_vmar_unmap_handle_close_thread_exit(SB),NOSPLIT,$0-36
+	MOVL vmar_handle+0(FP), DI
+	MOVQ addr+8(FP), SI
+	MOVQ size+16(FP), DX
+	MOVL handle+24(FP), CX
+	MOVQ vdso_zx_vmar_unmap_handle_close_thread_exit(SB), AX
+	CALL AX
+	MOVL AX, ret+32(FP)
+	RET
+
+// func Sys_futex_wake_handle_close_thread_exit(value_ptr *int, count uint32, new_value int32, handle Handle)
+TEXT ·Sys_futex_wake_handle_close_thread_exit(SB),NOSPLIT,$0-24
+	MOVQ value_ptr+0(FP), DI
+	MOVL count+8(FP), SI
+	MOVL new_value+12(FP), DX
+	MOVL handle+16(FP), CX
+	MOVQ vdso_zx_futex_wake_handle_close_thread_exit(SB), AX
+	CALL AX
+	RET
+
+// func Sys_log_write(handle Handle, len uint32, buffer unsafe.Pointer, options uint32) Status
+TEXT ·Sys_log_write(SB),NOSPLIT,$0-28
+	MOVL handle+0(FP), DI
+	MOVL len+4(FP), SI
+	MOVQ buffer+8(FP), DX
+	MOVL options+16(FP), CX
+	MOVQ vdso_zx_log_write(SB), AX
+	CALL AX
+	MOVL AX, ret+24(FP)
+	RET
+
+// func Sys_log_read(handle Handle, len uint32, buffer unsafe.Pointer, options uint32) Status
+TEXT ·Sys_log_read(SB),NOSPLIT,$0-28
+	MOVL handle+0(FP), DI
+	MOVL len+4(FP), SI
+	MOVQ buffer+8(FP), DX
+	MOVL options+16(FP), CX
+	MOVQ vdso_zx_log_read(SB), AX
+	CALL AX
+	MOVL AX, ret+24(FP)
+	RET
+
+// func Sys_debuglog_create(resource Handle, options uint32, out *Handle) Status
+TEXT ·Sys_debuglog_create(SB),NOSPLIT,$0-20
+	MOVL resource+0(FP), DI
+	MOVL options+4(FP), SI
+	MOVQ out+8(FP), DX
+	MOVQ vdso_zx_debuglog_create(SB), AX
+	CALL AX
+	MOVL AX, ret+16(FP)
+	RET
+
+// func Sys_debuglog_write(handle Handle, options uint32, buffer unsafe.Pointer, buffer_size uint) Status
+TEXT ·Sys_debuglog_write(SB),NOSPLIT,$0-28
+	MOVL handle+0(FP), DI
+	MOVL options+4(FP), SI
+	MOVQ buffer+8(FP), DX
+	MOVQ buffer_size+16(FP), CX
+	MOVQ vdso_zx_debuglog_write(SB), AX
+	CALL AX
+	MOVL AX, ret+24(FP)
+	RET
+
+// func Sys_debuglog_read(handle Handle, options uint32, buffer unsafe.Pointer, buffer_size uint) Status
+TEXT ·Sys_debuglog_read(SB),NOSPLIT,$0-28
+	MOVL handle+0(FP), DI
+	MOVL options+4(FP), SI
+	MOVQ buffer+8(FP), DX
+	MOVQ buffer_size+16(FP), CX
+	MOVQ vdso_zx_debuglog_read(SB), AX
+	CALL AX
+	MOVL AX, ret+24(FP)
+	RET
+
+// func Sys_ktrace_read(handle Handle, data unsafe.Pointer, offset uint32, data_size uint, actual *uint) Status
+TEXT ·Sys_ktrace_read(SB),NOSPLIT,$0-44
+	MOVL handle+0(FP), DI
+	MOVQ data+8(FP), SI
+	MOVL offset+16(FP), DX
+	MOVQ data_size+24(FP), CX
+	MOVQ actual+32(FP), R8
+	MOVQ vdso_zx_ktrace_read(SB), AX
+	CALL AX
+	MOVL AX, ret+40(FP)
+	RET
+
+// func Sys_ktrace_control(handle Handle, action uint32, options uint32, ptr unsafe.Pointer) Status
+TEXT ·Sys_ktrace_control(SB),NOSPLIT,$0-28
+	MOVL handle+0(FP), DI
+	MOVL action+4(FP), SI
+	MOVL options+8(FP), DX
+	MOVQ ptr+16(FP), CX
+	MOVQ vdso_zx_ktrace_control(SB), AX
+	CALL AX
+	MOVL AX, ret+24(FP)
+	RET
+
+// func Sys_ktrace_write(handle Handle, id uint32, arg0 uint32, arg1 uint32) Status
+TEXT ·Sys_ktrace_write(SB),NOSPLIT,$0-20
+	MOVL handle+0(FP), DI
+	MOVL id+4(FP), SI
+	MOVL arg0+8(FP), DX
+	MOVL arg1+12(FP), CX
+	MOVQ vdso_zx_ktrace_write(SB), AX
+	CALL AX
+	MOVL AX, ret+16(FP)
+	RET
+
+// func Sys_mtrace_control(handle Handle, kind uint32, action uint32, options uint32, ptr unsafe.Pointer, ptr_size uint) Status
+TEXT ·Sys_mtrace_control(SB),NOSPLIT,$0-36
+	MOVL handle+0(FP), DI
+	MOVL kind+4(FP), SI
+	MOVL action+8(FP), DX
+	MOVL options+12(FP), CX
+	MOVQ ptr+16(FP), R8
+	MOVQ ptr_size+24(FP), R9
+	MOVQ vdso_zx_mtrace_control(SB), AX
+	CALL AX
+	MOVL AX, ret+32(FP)
+	RET
+
+// func Sys_debug_read(handle Handle, buffer *uint8, buffer_size *uint) Status
+TEXT ·Sys_debug_read(SB),NOSPLIT,$0-28
+	MOVL handle+0(FP), DI
+	MOVQ buffer+8(FP), SI
+	MOVQ buffer_size+16(FP), DX
+	MOVQ vdso_zx_debug_read(SB), AX
+	CALL AX
+	MOVL AX, ret+24(FP)
+	RET
+
+// func Sys_debug_write(buffer *uint8, buffer_size uint) Status
+TEXT ·Sys_debug_write(SB),NOSPLIT,$0-20
+	MOVQ buffer+0(FP), DI
+	MOVQ buffer_size+8(FP), SI
+	MOVQ vdso_zx_debug_write(SB), AX
+	CALL AX
+	MOVL AX, ret+16(FP)
+	RET
+
+// func Sys_debug_send_command(resource Handle, buffer *uint8, buffer_size uint) Status
+TEXT ·Sys_debug_send_command(SB),NOSPLIT,$0-28
+	MOVL resource+0(FP), DI
+	MOVQ buffer+8(FP), SI
+	MOVQ buffer_size+16(FP), DX
+	MOVQ vdso_zx_debug_send_command(SB), AX
+	CALL AX
+	MOVL AX, ret+24(FP)
+	RET
+
+// func Sys_interrupt_create(src_obj Handle, src_num uint32, options uint32, out *Handle) Status
+TEXT ·Sys_interrupt_create(SB),NOSPLIT,$0-28
+	MOVL src_obj+0(FP), DI
+	MOVL src_num+4(FP), SI
+	MOVL options+8(FP), DX
+	MOVQ out+16(FP), CX
+	MOVQ vdso_zx_interrupt_create(SB), AX
+	CALL AX
+	MOVL AX, ret+24(FP)
+	RET
+
+// func Sys_interrupt_bind(handle Handle, port Handle, key uint64, options uint32) Status
+TEXT ·Sys_interrupt_bind(SB),NOSPLIT,$0-28
+	MOVL handle+0(FP), DI
+	MOVL port+4(FP), SI
+	MOVQ key+8(FP), DX
+	MOVL options+16(FP), CX
+	MOVQ vdso_zx_interrupt_bind(SB), AX
+	CALL AX
+	MOVL AX, ret+24(FP)
+	RET
+
+// func Sys_interrupt_wait(handle Handle, out_timestamp *Time) Status
+TEXT ·Sys_interrupt_wait(SB),NOSPLIT,$0-20
+	MOVL handle+0(FP), DI
+	MOVQ out_timestamp+8(FP), SI
+	MOVQ vdso_zx_interrupt_wait(SB), AX
+	CALL AX
+	MOVL AX, ret+16(FP)
+	RET
+
+// func Sys_interrupt_destroy(handle Handle) Status
+TEXT ·Sys_interrupt_destroy(SB),NOSPLIT,$0-12
+	MOVL handle+0(FP), DI
+	MOVQ vdso_zx_interrupt_destroy(SB), AX
+	CALL AX
+	MOVL AX, ret+8(FP)
+	RET
+
+// func Sys_interrupt_ack(handle Handle) Status
+TEXT ·Sys_interrupt_ack(SB),NOSPLIT,$0-12
+	MOVL handle+0(FP), DI
+	MOVQ vdso_zx_interrupt_ack(SB), AX
+	CALL AX
+	MOVL AX, ret+8(FP)
+	RET
+
+// func Sys_interrupt_trigger(handle Handle, options uint32, timestamp Time) Status
+TEXT ·Sys_interrupt_trigger(SB),NOSPLIT,$0-20
+	MOVL handle+0(FP), DI
+	MOVL options+4(FP), SI
+	MOVQ timestamp+8(FP), DX
+	MOVQ vdso_zx_interrupt_trigger(SB), AX
+	CALL AX
+	MOVL AX, ret+16(FP)
+	RET
+
+// func Sys_ioports_request(resource Handle, io_addr uint16, len uint32) Status
+TEXT ·Sys_ioports_request(SB),NOSPLIT,$0-20
+	MOVL resource+0(FP), DI
+	MOVQ io_addr+4(FP), SI
+	MOVL len+8(FP), DX
+	MOVQ vdso_zx_ioports_request(SB), AX
+	CALL AX
+	MOVL AX, ret+16(FP)
+	RET
+
+// func Sys_vmo_create_contiguous(bti Handle, size uint, alignment_log2 uint32, out *Handle) Status
+TEXT ·Sys_vmo_create_contiguous(SB),NOSPLIT,$0-36
+	MOVL bti+0(FP), DI
+	MOVQ size+8(FP), SI
+	MOVL alignment_log2+16(FP), DX
+	MOVQ out+24(FP), CX
+	MOVQ vdso_zx_vmo_create_contiguous(SB), AX
+	CALL AX
+	MOVL AX, ret+32(FP)
+	RET
+
+// func Sys_vmo_create_physical(resource Handle, paddr Paddr, size uint, out *Handle) Status
+TEXT ·Sys_vmo_create_physical(SB),NOSPLIT,$0-36
+	MOVL resource+0(FP), DI
+	MOVQ paddr+8(FP), SI
+	MOVQ size+16(FP), DX
+	MOVQ out+24(FP), CX
+	MOVQ vdso_zx_vmo_create_physical(SB), AX
+	CALL AX
+	MOVL AX, ret+32(FP)
+	RET
+
+// func Sys_iommu_create(resource Handle, typ uint32, desc unsafe.Pointer, desc_size uint, out *Handle) Status
+TEXT ·Sys_iommu_create(SB),NOSPLIT,$0-36
+	MOVL resource+0(FP), DI
+	MOVL typ+4(FP), SI
+	MOVQ desc+8(FP), DX
+	MOVQ desc_size+16(FP), CX
+	MOVQ out+24(FP), R8
+	MOVQ vdso_zx_iommu_create(SB), AX
+	CALL AX
+	MOVL AX, ret+32(FP)
+	RET
+
+// func Sys_bti_create(iommu Handle, options uint32, bti_id uint64, out *Handle) Status
+TEXT ·Sys_bti_create(SB),NOSPLIT,$0-28
+	MOVL iommu+0(FP), DI
+	MOVL options+4(FP), SI
+	MOVQ bti_id+8(FP), DX
+	MOVQ out+16(FP), CX
+	MOVQ vdso_zx_bti_create(SB), AX
+	CALL AX
+	MOVL AX, ret+24(FP)
+	RET
+
+// func Sys_bti_pin(handle Handle, options uint32, vmo Handle, offset uint64, size uint64, addrs *Paddr, addrs_count uint, out *Handle) Status
+TEXT ·Sys_bti_pin(SB),NOSPLIT,$32-60
+	MOVL handle+0(FP), DI
+	MOVL options+4(FP), SI
+	MOVL vmo+8(FP), DX
+	MOVQ offset+16(FP), CX
+	MOVQ size+24(FP), R8
+	MOVQ addrs+32(FP), R9
+	MOVQ addrs_count+40(FP), R12
+	MOVQ out+48(FP), R13
+	MOVQ SP, BP   // BP is preserved across vsdo call by the x86-64 ABI
+	ANDQ $~15, SP // stack alignment for x86-64 ABI
+	PUSHQ R13
+	PUSHQ R12
+	MOVQ vdso_zx_bti_pin(SB), AX
+	CALL AX
+	POPQ R12
+	POPQ R13
+	MOVQ BP, SP
+	MOVL AX, ret+56(FP)
+	RET
+
+// func Sys_bti_release_quarantine(handle Handle) Status
+TEXT ·Sys_bti_release_quarantine(SB),NOSPLIT,$0-12
+	MOVL handle+0(FP), DI
+	MOVQ vdso_zx_bti_release_quarantine(SB), AX
+	CALL AX
+	MOVL AX, ret+8(FP)
+	RET
+
+// func Sys_pmt_unpin(handle Handle) Status
+TEXT ·Sys_pmt_unpin(SB),NOSPLIT,$0-12
+	MOVL handle+0(FP), DI
+	MOVQ vdso_zx_pmt_unpin(SB), AX
+	CALL AX
+	MOVL AX, ret+8(FP)
+	RET
+
+// func Sys_framebuffer_get_info(resource Handle, format *uint32, width *uint32, height *uint32, stride *uint32) Status
+TEXT ·Sys_framebuffer_get_info(SB),NOSPLIT,$0-44
+	MOVL resource+0(FP), DI
+	MOVQ format+8(FP), SI
+	MOVQ width+16(FP), DX
+	MOVQ height+24(FP), CX
+	MOVQ stride+32(FP), R8
+	MOVQ vdso_zx_framebuffer_get_info(SB), AX
+	CALL AX
+	MOVL AX, ret+40(FP)
+	RET
+
+// func Sys_framebuffer_set_range(resource Handle, vmo Handle, len uint32, format uint32, width uint32, height uint32, stride uint32) Status
+TEXT ·Sys_framebuffer_set_range(SB),NOSPLIT,$24-36
+	MOVL resource+0(FP), DI
+	MOVL vmo+4(FP), SI
+	MOVL len+8(FP), DX
+	MOVL format+12(FP), CX
+	MOVL width+16(FP), R8
+	MOVL height+20(FP), R9
+	MOVL stride+24(FP), R12
+	MOVQ SP, BP   // BP is preserved across vsdo call by the x86-64 ABI
+	ANDQ $~15, SP // stack alignment for x86-64 ABI
+	PUSHQ R12
+	MOVQ vdso_zx_framebuffer_set_range(SB), AX
+	CALL AX
+	POPQ R12
+	MOVQ BP, SP
+	MOVL AX, ret+32(FP)
+	RET
+
+// func Sys_pc_firmware_tables(handle Handle, acpi_rsdp *Paddr, smbios *Paddr) Status
+TEXT ·Sys_pc_firmware_tables(SB),NOSPLIT,$0-28
+	MOVL handle+0(FP), DI
+	MOVQ acpi_rsdp+8(FP), SI
+	MOVQ smbios+16(FP), DX
+	MOVQ vdso_zx_pc_firmware_tables(SB), AX
+	CALL AX
+	MOVL AX, ret+24(FP)
+	RET
+
+// func Sys_smc_call(handle Handle, parameters *SMCParameters, out_smc_result *SMCResult) Status
+TEXT ·Sys_smc_call(SB),NOSPLIT,$0-28
+	MOVL handle+0(FP), DI
+	MOVQ parameters+8(FP), SI
+	MOVQ out_smc_result+16(FP), DX
+	MOVQ vdso_zx_smc_call(SB), AX
+	CALL AX
+	MOVL AX, ret+24(FP)
+	RET
+
+// func Sys_resource_create(parent_rsrc Handle, options uint32, base uint64, size uint, name *uint8, name_size uint, resource_out *Handle) Status
+TEXT ·Sys_resource_create(SB),NOSPLIT,$24-52
+	MOVL parent_rsrc+0(FP), DI
+	MOVL options+4(FP), SI
+	MOVQ base+8(FP), DX
+	MOVQ size+16(FP), CX
+	MOVQ name+24(FP), R8
+	MOVQ name_size+32(FP), R9
+	MOVQ resource_out+40(FP), R12
+	MOVQ SP, BP   // BP is preserved across vsdo call by the x86-64 ABI
+	ANDQ $~15, SP // stack alignment for x86-64 ABI
+	PUSHQ R12
+	MOVQ vdso_zx_resource_create(SB), AX
+	CALL AX
+	POPQ R12
+	MOVQ BP, SP
+	MOVL AX, ret+48(FP)
+	RET
+
+// func Sys_system_mexec(resource Handle, kernel Handle, bootimage Handle) Status
+TEXT ·Sys_system_mexec(SB),NOSPLIT,$0-20
+	MOVL resource+0(FP), DI
+	MOVL kernel+4(FP), SI
+	MOVL bootimage+8(FP), DX
+	MOVQ vdso_zx_system_mexec(SB), AX
+	CALL AX
+	MOVL AX, ret+16(FP)
+	RET
+
+// func Sys_system_powerctl(resource Handle, cmd uint32, arg *int) Status
+TEXT ·Sys_system_powerctl(SB),NOSPLIT,$0-20
+	MOVL resource+0(FP), DI
+	MOVL cmd+4(FP), SI
+	MOVQ arg+8(FP), DX
+	MOVQ vdso_zx_system_powerctl(SB), AX
+	CALL AX
+	MOVL AX, ret+16(FP)
+	RET
+
diff --git a/src/syscall/zx/syscalls_fuchsia_arm64.s b/src/syscall/zx/syscalls_fuchsia_arm64.s
new file mode 100644
index 0000000..13a2a13
--- /dev/null
+++ b/src/syscall/zx/syscalls_fuchsia_arm64.s
@@ -0,0 +1,1248 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Zircon system calls for the Fuchsia OS.
+// Generated by mkfuchsia.go, do not edit.
+
+#include "textflag.h"
+
+// func Sys_clock_get(clock_id uint32) Time
+TEXT ·Sys_clock_get(SB),NOSPLIT,$0-16
+	MOVW clock_id+0(FP), R0
+	BL vdso_zx_clock_get(SB)
+	MOVD R0, ret+8(FP)
+	RET
+
+// func Sys_clock_get_new(clock_id uint32, out *Time) Status
+TEXT ·Sys_clock_get_new(SB),NOSPLIT,$0-20
+	MOVW clock_id+0(FP), R0
+	MOVD out+8(FP), R1
+	BL vdso_zx_clock_get_new(SB)
+	MOVW R0, ret+16(FP)
+	RET
+
+// func Sys_clock_get_monotonic() Time
+TEXT ·Sys_clock_get_monotonic(SB),NOSPLIT,$0-8
+	BL vdso_zx_clock_get_monotonic(SB)
+	MOVD R0, ret+0(FP)
+	RET
+
+// func Sys_nanosleep(deadline Time) Status
+TEXT ·Sys_nanosleep(SB),NOSPLIT,$0-12
+	MOVD deadline+0(FP), R0
+	BL vdso_zx_nanosleep(SB)
+	MOVW R0, ret+8(FP)
+	RET
+
+// func Sys_ticks_get() uint64
+TEXT ·Sys_ticks_get(SB),NOSPLIT,$0-8
+	BL vdso_zx_ticks_get(SB)
+	MOVD R0, ret+0(FP)
+	RET
+
+// func Sys_ticks_per_second() uint64
+TEXT ·Sys_ticks_per_second(SB),NOSPLIT,$0-8
+	BL vdso_zx_ticks_per_second(SB)
+	MOVD R0, ret+0(FP)
+	RET
+
+// func Sys_deadline_after(nanoseconds Duration) Time
+TEXT ·Sys_deadline_after(SB),NOSPLIT,$0-16
+	MOVD nanoseconds+0(FP), R0
+	BL vdso_zx_deadline_after(SB)
+	MOVD R0, ret+8(FP)
+	RET
+
+// func Sys_clock_adjust(handle Handle, clock_id uint32, offset int64) Status
+TEXT ·Sys_clock_adjust(SB),NOSPLIT,$0-20
+	MOVW handle+0(FP), R0
+	MOVW clock_id+4(FP), R1
+	MOVD offset+8(FP), R2
+	BL vdso_zx_clock_adjust(SB)
+	MOVW R0, ret+16(FP)
+	RET
+
+// func sys_system_get_dcache_line_size() uint32
+TEXT ·sys_system_get_dcache_line_size(SB),NOSPLIT,$0-4
+	BL vdso_zx_system_get_dcache_line_size(SB)
+	MOVW R0, ret+0(FP)
+	RET
+
+// func Sys_system_get_num_cpus() uint32
+TEXT ·Sys_system_get_num_cpus(SB),NOSPLIT,$0-4
+	BL vdso_zx_system_get_num_cpus(SB)
+	MOVW R0, ret+0(FP)
+	RET
+
+// func Sys_system_get_version(version *uint8, version_size uint) Status
+TEXT ·Sys_system_get_version(SB),NOSPLIT,$0-20
+	MOVD version+0(FP), R0
+	MOVD version_size+8(FP), R1
+	BL vdso_zx_system_get_version(SB)
+	MOVW R0, ret+16(FP)
+	RET
+
+// func Sys_system_get_physmem() uint64
+TEXT ·Sys_system_get_physmem(SB),NOSPLIT,$0-8
+	BL vdso_zx_system_get_physmem(SB)
+	MOVD R0, ret+0(FP)
+	RET
+
+// func sys_system_get_features(kind uint32, out *uint32) Status
+TEXT ·sys_system_get_features(SB),NOSPLIT,$0-20
+	MOVW kind+0(FP), R0
+	MOVD out+8(FP), R1
+	BL vdso_zx_system_get_features(SB)
+	MOVW R0, ret+16(FP)
+	RET
+
+// func Sys_cache_flush(addr unsafe.Pointer, size uint, options uint32) Status
+TEXT ·Sys_cache_flush(SB),NOSPLIT,$0-28
+	MOVD addr+0(FP), R0
+	MOVD size+8(FP), R1
+	MOVW options+16(FP), R2
+	BL vdso_zx_cache_flush(SB)
+	MOVW R0, ret+24(FP)
+	RET
+
+// func Sys_handle_close(handle Handle) Status
+TEXT ·Sys_handle_close(SB),NOSPLIT,$0-12
+	MOVW handle+0(FP), R0
+	BL vdso_zx_handle_close(SB)
+	MOVW R0, ret+8(FP)
+	RET
+
+// func Sys_handle_close_many(handles *Handle, num_handles uint) Status
+TEXT ·Sys_handle_close_many(SB),NOSPLIT,$0-20
+	MOVD handles+0(FP), R0
+	MOVD num_handles+8(FP), R1
+	BL vdso_zx_handle_close_many(SB)
+	MOVW R0, ret+16(FP)
+	RET
+
+// func sys_handle_duplicate(handle Handle, rights Rights, out *Handle) Status
+TEXT ·sys_handle_duplicate(SB),NOSPLIT,$0-20
+	MOVW handle+0(FP), R0
+	MOVW rights+4(FP), R1
+	MOVD out+8(FP), R2
+	BL vdso_zx_handle_duplicate(SB)
+	MOVW R0, ret+16(FP)
+	RET
+
+// func Sys_handle_replace(handle Handle, rights Rights, out *Handle) Status
+TEXT ·Sys_handle_replace(SB),NOSPLIT,$0-20
+	MOVW handle+0(FP), R0
+	MOVW rights+4(FP), R1
+	MOVD out+8(FP), R2
+	BL vdso_zx_handle_replace(SB)
+	MOVW R0, ret+16(FP)
+	RET
+
+// func Sys_object_wait_one(handle Handle, signals Signals, deadline Time, observed *Signals) Status
+TEXT ·Sys_object_wait_one(SB),NOSPLIT,$0-28
+	CALL runtime·entersyscall(SB)
+	MOVW handle+0(FP), R0
+	MOVW signals+4(FP), R1
+	MOVD deadline+8(FP), R2
+	MOVD observed+16(FP), R3
+	BL vdso_zx_object_wait_one(SB)
+	MOVW R0, ret+24(FP)
+	BL runtime·exitsyscall(SB)
+	RET
+
+// func sys_object_wait_many(items *WaitItem, count uint, deadline Time) Status
+TEXT ·sys_object_wait_many(SB),NOSPLIT,$0-28
+	CALL runtime·entersyscall(SB)
+	MOVD items+0(FP), R0
+	MOVD count+8(FP), R1
+	MOVD deadline+16(FP), R2
+	BL vdso_zx_object_wait_many(SB)
+	MOVW R0, ret+24(FP)
+	BL runtime·exitsyscall(SB)
+	RET
+
+// func Sys_object_wait_async(handle Handle, port Handle, key uint64, signals Signals, options uint32) Status
+TEXT ·Sys_object_wait_async(SB),NOSPLIT,$0-28
+	MOVW handle+0(FP), R0
+	MOVW port+4(FP), R1
+	MOVD key+8(FP), R2
+	MOVW signals+16(FP), R3
+	MOVW options+20(FP), R4
+	BL vdso_zx_object_wait_async(SB)
+	MOVW R0, ret+24(FP)
+	RET
+
+// func Sys_object_signal(handle Handle, clear_mask uint32, set_mask uint32) Status
+TEXT ·Sys_object_signal(SB),NOSPLIT,$0-20
+	MOVW handle+0(FP), R0
+	MOVW clear_mask+4(FP), R1
+	MOVW set_mask+8(FP), R2
+	BL vdso_zx_object_signal(SB)
+	MOVW R0, ret+16(FP)
+	RET
+
+// func Sys_object_signal_peer(handle Handle, clear_mask uint32, set_mask uint32) Status
+TEXT ·Sys_object_signal_peer(SB),NOSPLIT,$0-20
+	MOVW handle+0(FP), R0
+	MOVW clear_mask+4(FP), R1
+	MOVW set_mask+8(FP), R2
+	BL vdso_zx_object_signal_peer(SB)
+	MOVW R0, ret+16(FP)
+	RET
+
+// func Sys_object_get_property(handle Handle, property uint32, value unsafe.Pointer, value_size uint) Status
+TEXT ·Sys_object_get_property(SB),NOSPLIT,$0-28
+	MOVW handle+0(FP), R0
+	MOVW property+4(FP), R1
+	MOVD value+8(FP), R2
+	MOVD value_size+16(FP), R3
+	BL vdso_zx_object_get_property(SB)
+	MOVW R0, ret+24(FP)
+	RET
+
+// func Sys_object_set_property(handle Handle, property uint32, value unsafe.Pointer, value_size uint) Status
+TEXT ·Sys_object_set_property(SB),NOSPLIT,$0-28
+	MOVW handle+0(FP), R0
+	MOVW property+4(FP), R1
+	MOVD value+8(FP), R2
+	MOVD value_size+16(FP), R3
+	BL vdso_zx_object_set_property(SB)
+	MOVW R0, ret+24(FP)
+	RET
+
+// func Sys_object_set_cookie(handle Handle, scope Handle, cookie uint64) Status
+TEXT ·Sys_object_set_cookie(SB),NOSPLIT,$0-20
+	MOVW handle+0(FP), R0
+	MOVW scope+4(FP), R1
+	MOVD cookie+8(FP), R2
+	BL vdso_zx_object_set_cookie(SB)
+	MOVW R0, ret+16(FP)
+	RET
+
+// func Sys_object_get_cookie(handle Handle, scope Handle, cookie *uint64) Status
+TEXT ·Sys_object_get_cookie(SB),NOSPLIT,$0-20
+	MOVW handle+0(FP), R0
+	MOVW scope+4(FP), R1
+	MOVD cookie+8(FP), R2
+	BL vdso_zx_object_get_cookie(SB)
+	MOVW R0, ret+16(FP)
+	RET
+
+// func Sys_object_get_info(handle Handle, topic uint32, buffer unsafe.Pointer, buffer_size uint, actual_count *uint, avail_count *uint) Status
+TEXT ·Sys_object_get_info(SB),NOSPLIT,$0-44
+	MOVW handle+0(FP), R0
+	MOVW topic+4(FP), R1
+	MOVD buffer+8(FP), R2
+	MOVD buffer_size+16(FP), R3
+	MOVD actual_count+24(FP), R4
+	MOVD avail_count+32(FP), R5
+	BL vdso_zx_object_get_info(SB)
+	MOVW R0, ret+40(FP)
+	RET
+
+// func Sys_object_get_child(handle Handle, koid uint64, rights Rights, out *Handle) Status
+TEXT ·Sys_object_get_child(SB),NOSPLIT,$0-36
+	MOVW handle+0(FP), R0
+	MOVD koid+8(FP), R1
+	MOVW rights+16(FP), R2
+	MOVD out+24(FP), R3
+	BL vdso_zx_object_get_child(SB)
+	MOVW R0, ret+32(FP)
+	RET
+
+// func sys_object_set_profile(handle Handle, profile Handle, options uint32) Status
+TEXT ·sys_object_set_profile(SB),NOSPLIT,$0-20
+	MOVW handle+0(FP), R0
+	MOVW profile+4(FP), R1
+	MOVW options+8(FP), R2
+	BL vdso_zx_object_set_profile(SB)
+	MOVW R0, ret+16(FP)
+	RET
+
+// func sys_channel_create(options uint32, out0 *Handle, out1 *Handle) Status
+TEXT ·sys_channel_create(SB),NOSPLIT,$0-28
+	MOVW options+0(FP), R0
+	MOVD out0+8(FP), R1
+	MOVD out1+16(FP), R2
+	BL vdso_zx_channel_create(SB)
+	MOVW R0, ret+24(FP)
+	RET
+
+// func sys_channel_read(handle Handle, options uint32, bytes unsafe.Pointer, handles *Handle, num_bytes uint32, num_handles uint32, actual_bytes *uint32, actual_handles *uint32) Status
+TEXT ·sys_channel_read(SB),NOSPLIT,$0-52
+	MOVW handle+0(FP), R0
+	MOVW options+4(FP), R1
+	MOVD bytes+8(FP), R2
+	MOVD handles+16(FP), R3
+	MOVW num_bytes+24(FP), R4
+	MOVW num_handles+28(FP), R5
+	MOVD actual_bytes+32(FP), R6
+	MOVD actual_handles+40(FP), R7
+	BL vdso_zx_channel_read(SB)
+	MOVW R0, ret+48(FP)
+	RET
+
+// func sys_channel_read_etc(handle Handle, options uint32, bytes unsafe.Pointer, handles *int, num_bytes uint32, num_handles uint32, actual_bytes *uint32, actual_handles *uint32) Status
+TEXT ·sys_channel_read_etc(SB),NOSPLIT,$0-52
+	MOVW handle+0(FP), R0
+	MOVW options+4(FP), R1
+	MOVD bytes+8(FP), R2
+	MOVD handles+16(FP), R3
+	MOVW num_bytes+24(FP), R4
+	MOVW num_handles+28(FP), R5
+	MOVD actual_bytes+32(FP), R6
+	MOVD actual_handles+40(FP), R7
+	BL vdso_zx_channel_read_etc(SB)
+	MOVW R0, ret+48(FP)
+	RET
+
+// func sys_channel_write(handle Handle, options uint32, bytes unsafe.Pointer, num_bytes uint32, handles *Handle, num_handles uint32) Status
+TEXT ·sys_channel_write(SB),NOSPLIT,$0-44
+	MOVW handle+0(FP), R0
+	MOVW options+4(FP), R1
+	MOVD bytes+8(FP), R2
+	MOVW num_bytes+16(FP), R3
+	MOVD handles+24(FP), R4
+	MOVW num_handles+32(FP), R5
+	BL vdso_zx_channel_write(SB)
+	MOVW R0, ret+40(FP)
+	RET
+
+// func Sys_channel_call_noretry(handle Handle, options uint32, deadline Time, args *ChannelCallArgs, actual_bytes *uint32, actual_handles *uint32) Status
+TEXT ·Sys_channel_call_noretry(SB),NOSPLIT,$0-44
+	MOVW handle+0(FP), R0
+	MOVW options+4(FP), R1
+	MOVD deadline+8(FP), R2
+	MOVD args+16(FP), R3
+	MOVD actual_bytes+24(FP), R4
+	MOVD actual_handles+32(FP), R5
+	BL vdso_zx_channel_call_noretry(SB)
+	MOVW R0, ret+40(FP)
+	RET
+
+// func Sys_channel_call_finish(deadline Time, args *ChannelCallArgs, actual_bytes *uint32, actual_handles *uint32) Status
+TEXT ·Sys_channel_call_finish(SB),NOSPLIT,$0-36
+	MOVD deadline+0(FP), R0
+	MOVD args+8(FP), R1
+	MOVD actual_bytes+16(FP), R2
+	MOVD actual_handles+24(FP), R3
+	BL vdso_zx_channel_call_finish(SB)
+	MOVW R0, ret+32(FP)
+	RET
+
+// func Sys_channel_call(handle Handle, options uint32, deadline Time, args *ChannelCallArgs, actual_bytes *uint32, actual_handles *uint32) Status
+TEXT ·Sys_channel_call(SB),NOSPLIT,$0-44
+	MOVW handle+0(FP), R0
+	MOVW options+4(FP), R1
+	MOVD deadline+8(FP), R2
+	MOVD args+16(FP), R3
+	MOVD actual_bytes+24(FP), R4
+	MOVD actual_handles+32(FP), R5
+	BL vdso_zx_channel_call(SB)
+	MOVW R0, ret+40(FP)
+	RET
+
+// func sys_socket_create(options uint32, out0 *Handle, out1 *Handle) Status
+TEXT ·sys_socket_create(SB),NOSPLIT,$0-28
+	MOVW options+0(FP), R0
+	MOVD out0+8(FP), R1
+	MOVD out1+16(FP), R2
+	BL vdso_zx_socket_create(SB)
+	MOVW R0, ret+24(FP)
+	RET
+
+// func sys_socket_write(handle Handle, options uint32, buffer unsafe.Pointer, buffer_size uint, actual *uint) Status
+TEXT ·sys_socket_write(SB),NOSPLIT,$0-36
+	MOVW handle+0(FP), R0
+	MOVW options+4(FP), R1
+	MOVD buffer+8(FP), R2
+	MOVD buffer_size+16(FP), R3
+	MOVD actual+24(FP), R4
+	BL vdso_zx_socket_write(SB)
+	MOVW R0, ret+32(FP)
+	RET
+
+// func sys_socket_read(handle Handle, options uint32, buffer unsafe.Pointer, buffer_size uint, actual *uint) Status
+TEXT ·sys_socket_read(SB),NOSPLIT,$0-36
+	MOVW handle+0(FP), R0
+	MOVW options+4(FP), R1
+	MOVD buffer+8(FP), R2
+	MOVD buffer_size+16(FP), R3
+	MOVD actual+24(FP), R4
+	BL vdso_zx_socket_read(SB)
+	MOVW R0, ret+32(FP)
+	RET
+
+// func sys_socket_share(handle Handle, socket_to_share Handle) Status
+TEXT ·sys_socket_share(SB),NOSPLIT,$0-12
+	MOVW handle+0(FP), R0
+	MOVW socket_to_share+4(FP), R1
+	BL vdso_zx_socket_share(SB)
+	MOVW R0, ret+8(FP)
+	RET
+
+// func sys_socket_accept(handle Handle, out_socket *Handle) Status
+TEXT ·sys_socket_accept(SB),NOSPLIT,$0-20
+	MOVW handle+0(FP), R0
+	MOVD out_socket+8(FP), R1
+	BL vdso_zx_socket_accept(SB)
+	MOVW R0, ret+16(FP)
+	RET
+
+// func Sys_thread_exit()
+TEXT ·Sys_thread_exit(SB),NOSPLIT,$0-0
+	BL vdso_zx_thread_exit(SB)
+	RET
+
+// func Sys_thread_create(process Handle, name *uint8, name_size uint, options uint32, out *Handle) Status
+TEXT ·Sys_thread_create(SB),NOSPLIT,$0-44
+	MOVW process+0(FP), R0
+	MOVD name+8(FP), R1
+	MOVD name_size+16(FP), R2
+	MOVW options+24(FP), R3
+	MOVD out+32(FP), R4
+	BL vdso_zx_thread_create(SB)
+	MOVW R0, ret+40(FP)
+	RET
+
+// func Sys_thread_start(handle Handle, thread_entry Vaddr, stack Vaddr, arg1 uintptr, arg2 uintptr) Status
+TEXT ·Sys_thread_start(SB),NOSPLIT,$0-44
+	MOVW handle+0(FP), R0
+	MOVD thread_entry+8(FP), R1
+	MOVD stack+16(FP), R2
+	MOVD arg1+24(FP), R3
+	MOVD arg2+32(FP), R4
+	BL vdso_zx_thread_start(SB)
+	MOVW R0, ret+40(FP)
+	RET
+
+// func Sys_thread_read_state(handle Handle, kind uint32, buffer unsafe.Pointer, buffer_size uint) Status
+TEXT ·Sys_thread_read_state(SB),NOSPLIT,$0-28
+	MOVW handle+0(FP), R0
+	MOVW kind+4(FP), R1
+	MOVD buffer+8(FP), R2
+	MOVD buffer_size+16(FP), R3
+	BL vdso_zx_thread_read_state(SB)
+	MOVW R0, ret+24(FP)
+	RET
+
+// func Sys_thread_write_state(handle Handle, kind uint32, buffer unsafe.Pointer, buffer_size uint) Status
+TEXT ·Sys_thread_write_state(SB),NOSPLIT,$0-28
+	MOVW handle+0(FP), R0
+	MOVW kind+4(FP), R1
+	MOVD buffer+8(FP), R2
+	MOVD buffer_size+16(FP), R3
+	BL vdso_zx_thread_write_state(SB)
+	MOVW R0, ret+24(FP)
+	RET
+
+// func Sys_thread_set_priority(prio int32) Status
+TEXT ·Sys_thread_set_priority(SB),NOSPLIT,$0-12
+	MOVW prio+0(FP), R0
+	BL vdso_zx_thread_set_priority(SB)
+	MOVW R0, ret+8(FP)
+	RET
+
+// func Sys_process_exit(retcode int64)
+TEXT ·Sys_process_exit(SB),NOSPLIT,$0-8
+	MOVD retcode+0(FP), R0
+	BL vdso_zx_process_exit(SB)
+	RET
+
+// func Sys_process_create(job Handle, name *uint8, name_size uint, options uint32, proc_handle *Handle, vmar_handle *Handle) Status
+TEXT ·Sys_process_create(SB),NOSPLIT,$0-52
+	MOVW job+0(FP), R0
+	MOVD name+8(FP), R1
+	MOVD name_size+16(FP), R2
+	MOVW options+24(FP), R3
+	MOVD proc_handle+32(FP), R4
+	MOVD vmar_handle+40(FP), R5
+	BL vdso_zx_process_create(SB)
+	MOVW R0, ret+48(FP)
+	RET
+
+// func Sys_process_start(handle Handle, thread Handle, entry Vaddr, stack Vaddr, arg1 Handle, arg2 uintptr) Status
+TEXT ·Sys_process_start(SB),NOSPLIT,$0-44
+	MOVW handle+0(FP), R0
+	MOVW thread+4(FP), R1
+	MOVD entry+8(FP), R2
+	MOVD stack+16(FP), R3
+	MOVW arg1+24(FP), R4
+	MOVD arg2+32(FP), R5
+	BL vdso_zx_process_start(SB)
+	MOVW R0, ret+40(FP)
+	RET
+
+// func Sys_process_read_memory(proc Handle, vaddr Vaddr, buffer unsafe.Pointer, buffer_size uint, actual *uint) Status
+TEXT ·Sys_process_read_memory(SB),NOSPLIT,$0-44
+	MOVW proc+0(FP), R0
+	MOVD vaddr+8(FP), R1
+	MOVD buffer+16(FP), R2
+	MOVD buffer_size+24(FP), R3
+	MOVD actual+32(FP), R4
+	BL vdso_zx_process_read_memory(SB)
+	MOVW R0, ret+40(FP)
+	RET
+
+// func Sys_process_write_memory(proc Handle, vaddr Vaddr, buffer unsafe.Pointer, buffer_size uint, actual *uint) Status
+TEXT ·Sys_process_write_memory(SB),NOSPLIT,$0-44
+	MOVW proc+0(FP), R0
+	MOVD vaddr+8(FP), R1
+	MOVD buffer+16(FP), R2
+	MOVD buffer_size+24(FP), R3
+	MOVD actual+32(FP), R4
+	BL vdso_zx_process_write_memory(SB)
+	MOVW R0, ret+40(FP)
+	RET
+
+// func Sys_job_create(parent_job Handle, options uint32, out *Handle) Status
+TEXT ·Sys_job_create(SB),NOSPLIT,$0-20
+	MOVW parent_job+0(FP), R0
+	MOVW options+4(FP), R1
+	MOVD out+8(FP), R2
+	BL vdso_zx_job_create(SB)
+	MOVW R0, ret+16(FP)
+	RET
+
+// func Sys_job_set_policy(job Handle, options uint32, topic uint32, policy unsafe.Pointer, count uint32) Status
+TEXT ·Sys_job_set_policy(SB),NOSPLIT,$0-36
+	MOVW job+0(FP), R0
+	MOVW options+4(FP), R1
+	MOVW topic+8(FP), R2
+	MOVD policy+16(FP), R3
+	MOVW count+24(FP), R4
+	BL vdso_zx_job_set_policy(SB)
+	MOVW R0, ret+32(FP)
+	RET
+
+// func Sys_task_bind_exception_port(handle Handle, port Handle, key uint64, options uint32) Status
+TEXT ·Sys_task_bind_exception_port(SB),NOSPLIT,$0-28
+	MOVW handle+0(FP), R0
+	MOVW port+4(FP), R1
+	MOVD key+8(FP), R2
+	MOVW options+16(FP), R3
+	BL vdso_zx_task_bind_exception_port(SB)
+	MOVW R0, ret+24(FP)
+	RET
+
+// func Sys_task_resume(handle Handle, options uint32) Status
+TEXT ·Sys_task_resume(SB),NOSPLIT,$0-12
+	MOVW handle+0(FP), R0
+	MOVW options+4(FP), R1
+	BL vdso_zx_task_resume(SB)
+	MOVW R0, ret+8(FP)
+	RET
+
+// func Sys_task_suspend(handle Handle, token *Handle) Status
+TEXT ·Sys_task_suspend(SB),NOSPLIT,$0-20
+	MOVW handle+0(FP), R0
+	MOVD token+8(FP), R1
+	BL vdso_zx_task_suspend(SB)
+	MOVW R0, ret+16(FP)
+	RET
+
+// func Sys_task_suspend_token(handle Handle, token *Handle) Status
+TEXT ·Sys_task_suspend_token(SB),NOSPLIT,$0-20
+	MOVW handle+0(FP), R0
+	MOVD token+8(FP), R1
+	BL vdso_zx_task_suspend_token(SB)
+	MOVW R0, ret+16(FP)
+	RET
+
+// func Sys_task_resume_from_exception(handle Handle, port Handle, options uint32) Status
+TEXT ·Sys_task_resume_from_exception(SB),NOSPLIT,$0-20
+	MOVW handle+0(FP), R0
+	MOVW port+4(FP), R1
+	MOVW options+8(FP), R2
+	BL vdso_zx_task_resume_from_exception(SB)
+	MOVW R0, ret+16(FP)
+	RET
+
+// func Sys_task_kill(handle Handle) Status
+TEXT ·Sys_task_kill(SB),NOSPLIT,$0-12
+	MOVW handle+0(FP), R0
+	BL vdso_zx_task_kill(SB)
+	MOVW R0, ret+8(FP)
+	RET
+
+// func Sys_event_create(options uint32, out *Handle) Status
+TEXT ·Sys_event_create(SB),NOSPLIT,$0-20
+	MOVW options+0(FP), R0
+	MOVD out+8(FP), R1
+	BL vdso_zx_event_create(SB)
+	MOVW R0, ret+16(FP)
+	RET
+
+// func Sys_eventpair_create(options uint32, out0 *Handle, out1 *Handle) Status
+TEXT ·Sys_eventpair_create(SB),NOSPLIT,$0-28
+	MOVW options+0(FP), R0
+	MOVD out0+8(FP), R1
+	MOVD out1+16(FP), R2
+	BL vdso_zx_eventpair_create(SB)
+	MOVW R0, ret+24(FP)
+	RET
+
+// func Sys_futex_wait(value_ptr *int, current_value int32, deadline Time) Status
+TEXT ·Sys_futex_wait(SB),NOSPLIT,$0-28
+	MOVD value_ptr+0(FP), R0
+	MOVW current_value+8(FP), R1
+	MOVD deadline+16(FP), R2
+	BL vdso_zx_futex_wait(SB)
+	MOVW R0, ret+24(FP)
+	RET
+
+// func Sys_futex_wake(value_ptr *int, count uint32) Status
+TEXT ·Sys_futex_wake(SB),NOSPLIT,$0-20
+	MOVD value_ptr+0(FP), R0
+	MOVW count+8(FP), R1
+	BL vdso_zx_futex_wake(SB)
+	MOVW R0, ret+16(FP)
+	RET
+
+// func Sys_futex_requeue(wake_ptr *int, wake_count uint32, current_value int32, requeue_ptr *int, requeue_count uint32) Status
+TEXT ·Sys_futex_requeue(SB),NOSPLIT,$0-36
+	MOVD wake_ptr+0(FP), R0
+	MOVW wake_count+8(FP), R1
+	MOVW current_value+12(FP), R2
+	MOVD requeue_ptr+16(FP), R3
+	MOVW requeue_count+24(FP), R4
+	BL vdso_zx_futex_requeue(SB)
+	MOVW R0, ret+32(FP)
+	RET
+
+// func Sys_port_create(options uint32, out *Handle) Status
+TEXT ·Sys_port_create(SB),NOSPLIT,$0-20
+	MOVW options+0(FP), R0
+	MOVD out+8(FP), R1
+	BL vdso_zx_port_create(SB)
+	MOVW R0, ret+16(FP)
+	RET
+
+// func Sys_port_queue(handle Handle, packet *int) Status
+TEXT ·Sys_port_queue(SB),NOSPLIT,$0-20
+	MOVW handle+0(FP), R0
+	MOVD packet+8(FP), R1
+	BL vdso_zx_port_queue(SB)
+	MOVW R0, ret+16(FP)
+	RET
+
+// func Sys_port_wait(handle Handle, deadline Time, packet *int) Status
+TEXT ·Sys_port_wait(SB),NOSPLIT,$0-28
+	CALL runtime·entersyscall(SB)
+	MOVW handle+0(FP), R0
+	MOVD deadline+8(FP), R1
+	MOVD packet+16(FP), R2
+	BL vdso_zx_port_wait(SB)
+	MOVW R0, ret+24(FP)
+	BL runtime·exitsyscall(SB)
+	RET
+
+// func Sys_port_cancel(handle Handle, source Handle, key uint64) Status
+TEXT ·Sys_port_cancel(SB),NOSPLIT,$0-20
+	MOVW handle+0(FP), R0
+	MOVW source+4(FP), R1
+	MOVD key+8(FP), R2
+	BL vdso_zx_port_cancel(SB)
+	MOVW R0, ret+16(FP)
+	RET
+
+// func Sys_timer_create(options uint32, clock_id uint32, out *Handle) Status
+TEXT ·Sys_timer_create(SB),NOSPLIT,$0-20
+	MOVW options+0(FP), R0
+	MOVW clock_id+4(FP), R1
+	MOVD out+8(FP), R2
+	BL vdso_zx_timer_create(SB)
+	MOVW R0, ret+16(FP)
+	RET
+
+// func Sys_timer_set(handle Handle, deadline Time, slack Duration) Status
+TEXT ·Sys_timer_set(SB),NOSPLIT,$0-28
+	MOVW handle+0(FP), R0
+	MOVD deadline+8(FP), R1
+	MOVD slack+16(FP), R2
+	BL vdso_zx_timer_set(SB)
+	MOVW R0, ret+24(FP)
+	RET
+
+// func Sys_timer_cancel(handle Handle) Status
+TEXT ·Sys_timer_cancel(SB),NOSPLIT,$0-12
+	MOVW handle+0(FP), R0
+	BL vdso_zx_timer_cancel(SB)
+	MOVW R0, ret+8(FP)
+	RET
+
+// func Sys_vmo_create(size uint64, options uint32, out *Handle) Status
+TEXT ·Sys_vmo_create(SB),NOSPLIT,$0-28
+	MOVD size+0(FP), R0
+	MOVW options+8(FP), R1
+	MOVD out+16(FP), R2
+	BL vdso_zx_vmo_create(SB)
+	MOVW R0, ret+24(FP)
+	RET
+
+// func sys_vmo_read(handle Handle, buffer unsafe.Pointer, offset uint64, buffer_size uint) Status
+TEXT ·sys_vmo_read(SB),NOSPLIT,$0-36
+	MOVW handle+0(FP), R0
+	MOVD buffer+8(FP), R1
+	MOVD offset+16(FP), R2
+	MOVD buffer_size+24(FP), R3
+	BL vdso_zx_vmo_read(SB)
+	MOVW R0, ret+32(FP)
+	RET
+
+// func sys_vmo_write(handle Handle, buffer unsafe.Pointer, offset uint64, buffer_size uint) Status
+TEXT ·sys_vmo_write(SB),NOSPLIT,$0-36
+	MOVW handle+0(FP), R0
+	MOVD buffer+8(FP), R1
+	MOVD offset+16(FP), R2
+	MOVD buffer_size+24(FP), R3
+	BL vdso_zx_vmo_write(SB)
+	MOVW R0, ret+32(FP)
+	RET
+
+// func sys_vmo_get_size(handle Handle, size *uint64) Status
+TEXT ·sys_vmo_get_size(SB),NOSPLIT,$0-20
+	MOVW handle+0(FP), R0
+	MOVD size+8(FP), R1
+	BL vdso_zx_vmo_get_size(SB)
+	MOVW R0, ret+16(FP)
+	RET
+
+// func sys_vmo_set_size(handle Handle, size uint64) Status
+TEXT ·sys_vmo_set_size(SB),NOSPLIT,$0-20
+	MOVW handle+0(FP), R0
+	MOVD size+8(FP), R1
+	BL vdso_zx_vmo_set_size(SB)
+	MOVW R0, ret+16(FP)
+	RET
+
+// func sys_vmo_op_range(handle Handle, op uint32, offset uint64, size uint64, buffer unsafe.Pointer, buffer_size uint) Status
+TEXT ·sys_vmo_op_range(SB),NOSPLIT,$0-44
+	MOVW handle+0(FP), R0
+	MOVW op+4(FP), R1
+	MOVD offset+8(FP), R2
+	MOVD size+16(FP), R3
+	MOVD buffer+24(FP), R4
+	MOVD buffer_size+32(FP), R5
+	BL vdso_zx_vmo_op_range(SB)
+	MOVW R0, ret+40(FP)
+	RET
+
+// func Sys_vmo_clone(handle Handle, options uint32, offset uint64, size uint64, out *Handle) Status
+TEXT ·Sys_vmo_clone(SB),NOSPLIT,$0-36
+	MOVW handle+0(FP), R0
+	MOVW options+4(FP), R1
+	MOVD offset+8(FP), R2
+	MOVD size+16(FP), R3
+	MOVD out+24(FP), R4
+	BL vdso_zx_vmo_clone(SB)
+	MOVW R0, ret+32(FP)
+	RET
+
+// func Sys_vmo_set_cache_policy(handle Handle, cache_policy uint32) Status
+TEXT ·Sys_vmo_set_cache_policy(SB),NOSPLIT,$0-12
+	MOVW handle+0(FP), R0
+	MOVW cache_policy+4(FP), R1
+	BL vdso_zx_vmo_set_cache_policy(SB)
+	MOVW R0, ret+8(FP)
+	RET
+
+// func sys_vmar_allocate_old(parent_vmar Handle, offset uint64, size uint64, map_flags uint32, child_vmar *Handle, child_addr *Vaddr) Status
+TEXT ·sys_vmar_allocate_old(SB),NOSPLIT,$0-52
+	MOVW parent_vmar+0(FP), R0
+	MOVD offset+8(FP), R1
+	MOVD size+16(FP), R2
+	MOVW map_flags+24(FP), R3
+	MOVD child_vmar+32(FP), R4
+	MOVD child_addr+40(FP), R5
+	BL vdso_zx_vmar_allocate_old(SB)
+	MOVW R0, ret+48(FP)
+	RET
+
+// func sys_vmar_map_old(handle Handle, vmar_offset uint64, vmo Handle, vmo_offset uint64, len uint64, map_flags uint32, mapped_addr *Vaddr) Status
+TEXT ·sys_vmar_map_old(SB),NOSPLIT,$0-60
+	MOVW handle+0(FP), R0
+	MOVD vmar_offset+8(FP), R1
+	MOVW vmo+16(FP), R2
+	MOVD vmo_offset+24(FP), R3
+	MOVD len+32(FP), R4
+	MOVW map_flags+40(FP), R5
+	MOVD mapped_addr+48(FP), R6
+	BL vdso_zx_vmar_map_old(SB)
+	MOVW R0, ret+56(FP)
+	RET
+
+// func sys_vmar_protect_old(handle Handle, addr Vaddr, len uint64, prot_flags uint32) Status
+TEXT ·sys_vmar_protect_old(SB),NOSPLIT,$0-36
+	MOVW handle+0(FP), R0
+	MOVD addr+8(FP), R1
+	MOVD len+16(FP), R2
+	MOVW prot_flags+24(FP), R3
+	BL vdso_zx_vmar_protect_old(SB)
+	MOVW R0, ret+32(FP)
+	RET
+
+// func sys_vmar_allocate(parent_vmar Handle, offset uint64, size uint64, map_flags uint32, child_vmar *Handle, child_addr *Vaddr) Status
+TEXT ·sys_vmar_allocate(SB),NOSPLIT,$0-52
+	MOVW parent_vmar+0(FP), R0
+	MOVD offset+8(FP), R1
+	MOVD size+16(FP), R2
+	MOVW map_flags+24(FP), R3
+	MOVD child_vmar+32(FP), R4
+	MOVD child_addr+40(FP), R5
+	BL vdso_zx_vmar_allocate(SB)
+	MOVW R0, ret+48(FP)
+	RET
+
+// func sys_vmar_destroy(handle Handle) Status
+TEXT ·sys_vmar_destroy(SB),NOSPLIT,$0-12
+	MOVW handle+0(FP), R0
+	BL vdso_zx_vmar_destroy(SB)
+	MOVW R0, ret+8(FP)
+	RET
+
+// func Sys_vmar_map(handle Handle, vmar_offset uint64, vmo Handle, vmo_offset uint64, len uint64, map_flags uint32, mapped_addr *Vaddr) Status
+TEXT ·Sys_vmar_map(SB),NOSPLIT,$0-60
+	MOVW handle+0(FP), R0
+	MOVD vmar_offset+8(FP), R1
+	MOVW vmo+16(FP), R2
+	MOVD vmo_offset+24(FP), R3
+	MOVD len+32(FP), R4
+	MOVW map_flags+40(FP), R5
+	MOVD mapped_addr+48(FP), R6
+	BL vdso_zx_vmar_map(SB)
+	MOVW R0, ret+56(FP)
+	RET
+
+// func Sys_vmar_unmap(handle Handle, addr Vaddr, len uint64) Status
+TEXT ·Sys_vmar_unmap(SB),NOSPLIT,$0-28
+	MOVW handle+0(FP), R0
+	MOVD addr+8(FP), R1
+	MOVD len+16(FP), R2
+	BL vdso_zx_vmar_unmap(SB)
+	MOVW R0, ret+24(FP)
+	RET
+
+// func Sys_vmar_protect(handle Handle, addr Vaddr, len uint64, prot_flags uint32) Status
+TEXT ·Sys_vmar_protect(SB),NOSPLIT,$0-36
+	MOVW handle+0(FP), R0
+	MOVD addr+8(FP), R1
+	MOVD len+16(FP), R2
+	MOVW prot_flags+24(FP), R3
+	BL vdso_zx_vmar_protect(SB)
+	MOVW R0, ret+32(FP)
+	RET
+
+// func Sys_cprng_draw_once(buffer unsafe.Pointer, buffer_size uint) Status
+TEXT ·Sys_cprng_draw_once(SB),NOSPLIT,$0-20
+	MOVD buffer+0(FP), R0
+	MOVD buffer_size+8(FP), R1
+	BL vdso_zx_cprng_draw_once(SB)
+	MOVW R0, ret+16(FP)
+	RET
+
+// func Sys_cprng_draw(buffer unsafe.Pointer, buffer_size uint)
+TEXT ·Sys_cprng_draw(SB),NOSPLIT,$0-16
+	MOVD buffer+0(FP), R0
+	MOVD buffer_size+8(FP), R1
+	BL vdso_zx_cprng_draw(SB)
+	RET
+
+// func Sys_cprng_draw_new(buffer unsafe.Pointer, data_size uint) Status
+TEXT ·Sys_cprng_draw_new(SB),NOSPLIT,$0-20
+	MOVD buffer+0(FP), R0
+	MOVD data_size+8(FP), R1
+	BL vdso_zx_cprng_draw_new(SB)
+	MOVW R0, ret+16(FP)
+	RET
+
+// func Sys_cprng_add_entropy(buffer unsafe.Pointer, len uint) Status
+TEXT ·Sys_cprng_add_entropy(SB),NOSPLIT,$0-20
+	MOVD buffer+0(FP), R0
+	MOVD len+8(FP), R1
+	BL vdso_zx_cprng_add_entropy(SB)
+	MOVW R0, ret+16(FP)
+	RET
+
+// func Sys_fifo_create(elem_count uint, elem_size uint, options uint32, out0 *Handle, out1 *Handle) Status
+TEXT ·Sys_fifo_create(SB),NOSPLIT,$0-44
+	MOVD elem_count+0(FP), R0
+	MOVD elem_size+8(FP), R1
+	MOVW options+16(FP), R2
+	MOVD out0+24(FP), R3
+	MOVD out1+32(FP), R4
+	BL vdso_zx_fifo_create(SB)
+	MOVW R0, ret+40(FP)
+	RET
+
+// func Sys_fifo_read(handle Handle, elem_size uint, data unsafe.Pointer, count uint, actual_count *uint) Status
+TEXT ·Sys_fifo_read(SB),NOSPLIT,$0-44
+	MOVW handle+0(FP), R0
+	MOVD elem_size+8(FP), R1
+	MOVD data+16(FP), R2
+	MOVD count+24(FP), R3
+	MOVD actual_count+32(FP), R4
+	BL vdso_zx_fifo_read(SB)
+	MOVW R0, ret+40(FP)
+	RET
+
+// func Sys_fifo_write(handle Handle, elem_size uint, data unsafe.Pointer, count uint, actual_count *uint) Status
+TEXT ·Sys_fifo_write(SB),NOSPLIT,$0-44
+	MOVW handle+0(FP), R0
+	MOVD elem_size+8(FP), R1
+	MOVD data+16(FP), R2
+	MOVD count+24(FP), R3
+	MOVD actual_count+32(FP), R4
+	BL vdso_zx_fifo_write(SB)
+	MOVW R0, ret+40(FP)
+	RET
+
+// func Sys_profile_create(resource Handle, profile *int, out *Handle) Status
+TEXT ·Sys_profile_create(SB),NOSPLIT,$0-28
+	MOVW resource+0(FP), R0
+	MOVD profile+8(FP), R1
+	MOVD out+16(FP), R2
+	BL vdso_zx_profile_create(SB)
+	MOVW R0, ret+24(FP)
+	RET
+
+// func Sys_vmar_unmap_handle_close_thread_exit(vmar_handle Handle, addr Vaddr, size uint, handle Handle) Status
+TEXT ·Sys_vmar_unmap_handle_close_thread_exit(SB),NOSPLIT,$0-36
+	MOVW vmar_handle+0(FP), R0
+	MOVD addr+8(FP), R1
+	MOVD size+16(FP), R2
+	MOVW handle+24(FP), R3
+	BL vdso_zx_vmar_unmap_handle_close_thread_exit(SB)
+	MOVW R0, ret+32(FP)
+	RET
+
+// func Sys_futex_wake_handle_close_thread_exit(value_ptr *int, count uint32, new_value int32, handle Handle)
+TEXT ·Sys_futex_wake_handle_close_thread_exit(SB),NOSPLIT,$0-24
+	MOVD value_ptr+0(FP), R0
+	MOVW count+8(FP), R1
+	MOVW new_value+12(FP), R2
+	MOVW handle+16(FP), R3
+	BL vdso_zx_futex_wake_handle_close_thread_exit(SB)
+	RET
+
+// func Sys_log_write(handle Handle, len uint32, buffer unsafe.Pointer, options uint32) Status
+TEXT ·Sys_log_write(SB),NOSPLIT,$0-28
+	MOVW handle+0(FP), R0
+	MOVW len+4(FP), R1
+	MOVD buffer+8(FP), R2
+	MOVW options+16(FP), R3
+	BL vdso_zx_log_write(SB)
+	MOVW R0, ret+24(FP)
+	RET
+
+// func Sys_log_read(handle Handle, len uint32, buffer unsafe.Pointer, options uint32) Status
+TEXT ·Sys_log_read(SB),NOSPLIT,$0-28
+	MOVW handle+0(FP), R0
+	MOVW len+4(FP), R1
+	MOVD buffer+8(FP), R2
+	MOVW options+16(FP), R3
+	BL vdso_zx_log_read(SB)
+	MOVW R0, ret+24(FP)
+	RET
+
+// func Sys_debuglog_create(resource Handle, options uint32, out *Handle) Status
+TEXT ·Sys_debuglog_create(SB),NOSPLIT,$0-20
+	MOVW resource+0(FP), R0
+	MOVW options+4(FP), R1
+	MOVD out+8(FP), R2
+	BL vdso_zx_debuglog_create(SB)
+	MOVW R0, ret+16(FP)
+	RET
+
+// func Sys_debuglog_write(handle Handle, options uint32, buffer unsafe.Pointer, buffer_size uint) Status
+TEXT ·Sys_debuglog_write(SB),NOSPLIT,$0-28
+	MOVW handle+0(FP), R0
+	MOVW options+4(FP), R1
+	MOVD buffer+8(FP), R2
+	MOVD buffer_size+16(FP), R3
+	BL vdso_zx_debuglog_write(SB)
+	MOVW R0, ret+24(FP)
+	RET
+
+// func Sys_debuglog_read(handle Handle, options uint32, buffer unsafe.Pointer, buffer_size uint) Status
+TEXT ·Sys_debuglog_read(SB),NOSPLIT,$0-28
+	MOVW handle+0(FP), R0
+	MOVW options+4(FP), R1
+	MOVD buffer+8(FP), R2
+	MOVD buffer_size+16(FP), R3
+	BL vdso_zx_debuglog_read(SB)
+	MOVW R0, ret+24(FP)
+	RET
+
+// func Sys_ktrace_read(handle Handle, data unsafe.Pointer, offset uint32, data_size uint, actual *uint) Status
+TEXT ·Sys_ktrace_read(SB),NOSPLIT,$0-44
+	MOVW handle+0(FP), R0
+	MOVD data+8(FP), R1
+	MOVW offset+16(FP), R2
+	MOVD data_size+24(FP), R3
+	MOVD actual+32(FP), R4
+	BL vdso_zx_ktrace_read(SB)
+	MOVW R0, ret+40(FP)
+	RET
+
+// func Sys_ktrace_control(handle Handle, action uint32, options uint32, ptr unsafe.Pointer) Status
+TEXT ·Sys_ktrace_control(SB),NOSPLIT,$0-28
+	MOVW handle+0(FP), R0
+	MOVW action+4(FP), R1
+	MOVW options+8(FP), R2
+	MOVD ptr+16(FP), R3
+	BL vdso_zx_ktrace_control(SB)
+	MOVW R0, ret+24(FP)
+	RET
+
+// func Sys_ktrace_write(handle Handle, id uint32, arg0 uint32, arg1 uint32) Status
+TEXT ·Sys_ktrace_write(SB),NOSPLIT,$0-20
+	MOVW handle+0(FP), R0
+	MOVW id+4(FP), R1
+	MOVW arg0+8(FP), R2
+	MOVW arg1+12(FP), R3
+	BL vdso_zx_ktrace_write(SB)
+	MOVW R0, ret+16(FP)
+	RET
+
+// func Sys_mtrace_control(handle Handle, kind uint32, action uint32, options uint32, ptr unsafe.Pointer, ptr_size uint) Status
+TEXT ·Sys_mtrace_control(SB),NOSPLIT,$0-36
+	MOVW handle+0(FP), R0
+	MOVW kind+4(FP), R1
+	MOVW action+8(FP), R2
+	MOVW options+12(FP), R3
+	MOVD ptr+16(FP), R4
+	MOVD ptr_size+24(FP), R5
+	BL vdso_zx_mtrace_control(SB)
+	MOVW R0, ret+32(FP)
+	RET
+
+// func Sys_debug_read(handle Handle, buffer *uint8, buffer_size *uint) Status
+TEXT ·Sys_debug_read(SB),NOSPLIT,$0-28
+	MOVW handle+0(FP), R0
+	MOVD buffer+8(FP), R1
+	MOVD buffer_size+16(FP), R2
+	BL vdso_zx_debug_read(SB)
+	MOVW R0, ret+24(FP)
+	RET
+
+// func Sys_debug_write(buffer *uint8, buffer_size uint) Status
+TEXT ·Sys_debug_write(SB),NOSPLIT,$0-20
+	MOVD buffer+0(FP), R0
+	MOVD buffer_size+8(FP), R1
+	BL vdso_zx_debug_write(SB)
+	MOVW R0, ret+16(FP)
+	RET
+
+// func Sys_debug_send_command(resource Handle, buffer *uint8, buffer_size uint) Status
+TEXT ·Sys_debug_send_command(SB),NOSPLIT,$0-28
+	MOVW resource+0(FP), R0
+	MOVD buffer+8(FP), R1
+	MOVD buffer_size+16(FP), R2
+	BL vdso_zx_debug_send_command(SB)
+	MOVW R0, ret+24(FP)
+	RET
+
+// func Sys_interrupt_create(src_obj Handle, src_num uint32, options uint32, out *Handle) Status
+TEXT ·Sys_interrupt_create(SB),NOSPLIT,$0-28
+	MOVW src_obj+0(FP), R0
+	MOVW src_num+4(FP), R1
+	MOVW options+8(FP), R2
+	MOVD out+16(FP), R3
+	BL vdso_zx_interrupt_create(SB)
+	MOVW R0, ret+24(FP)
+	RET
+
+// func Sys_interrupt_bind(handle Handle, port Handle, key uint64, options uint32) Status
+TEXT ·Sys_interrupt_bind(SB),NOSPLIT,$0-28
+	MOVW handle+0(FP), R0
+	MOVW port+4(FP), R1
+	MOVD key+8(FP), R2
+	MOVW options+16(FP), R3
+	BL vdso_zx_interrupt_bind(SB)
+	MOVW R0, ret+24(FP)
+	RET
+
+// func Sys_interrupt_wait(handle Handle, out_timestamp *Time) Status
+TEXT ·Sys_interrupt_wait(SB),NOSPLIT,$0-20
+	MOVW handle+0(FP), R0
+	MOVD out_timestamp+8(FP), R1
+	BL vdso_zx_interrupt_wait(SB)
+	MOVW R0, ret+16(FP)
+	RET
+
+// func Sys_interrupt_destroy(handle Handle) Status
+TEXT ·Sys_interrupt_destroy(SB),NOSPLIT,$0-12
+	MOVW handle+0(FP), R0
+	BL vdso_zx_interrupt_destroy(SB)
+	MOVW R0, ret+8(FP)
+	RET
+
+// func Sys_interrupt_ack(handle Handle) Status
+TEXT ·Sys_interrupt_ack(SB),NOSPLIT,$0-12
+	MOVW handle+0(FP), R0
+	BL vdso_zx_interrupt_ack(SB)
+	MOVW R0, ret+8(FP)
+	RET
+
+// func Sys_interrupt_trigger(handle Handle, options uint32, timestamp Time) Status
+TEXT ·Sys_interrupt_trigger(SB),NOSPLIT,$0-20
+	MOVW handle+0(FP), R0
+	MOVW options+4(FP), R1
+	MOVD timestamp+8(FP), R2
+	BL vdso_zx_interrupt_trigger(SB)
+	MOVW R0, ret+16(FP)
+	RET
+
+// func Sys_ioports_request(resource Handle, io_addr uint16, len uint32) Status
+TEXT ·Sys_ioports_request(SB),NOSPLIT,$0-20
+	MOVW resource+0(FP), R0
+	MOVD io_addr+4(FP), R1
+	MOVW len+8(FP), R2
+	BL vdso_zx_ioports_request(SB)
+	MOVW R0, ret+16(FP)
+	RET
+
+// func Sys_vmo_create_contiguous(bti Handle, size uint, alignment_log2 uint32, out *Handle) Status
+TEXT ·Sys_vmo_create_contiguous(SB),NOSPLIT,$0-36
+	MOVW bti+0(FP), R0
+	MOVD size+8(FP), R1
+	MOVW alignment_log2+16(FP), R2
+	MOVD out+24(FP), R3
+	BL vdso_zx_vmo_create_contiguous(SB)
+	MOVW R0, ret+32(FP)
+	RET
+
+// func Sys_vmo_create_physical(resource Handle, paddr Paddr, size uint, out *Handle) Status
+TEXT ·Sys_vmo_create_physical(SB),NOSPLIT,$0-36
+	MOVW resource+0(FP), R0
+	MOVD paddr+8(FP), R1
+	MOVD size+16(FP), R2
+	MOVD out+24(FP), R3
+	BL vdso_zx_vmo_create_physical(SB)
+	MOVW R0, ret+32(FP)
+	RET
+
+// func Sys_iommu_create(resource Handle, typ uint32, desc unsafe.Pointer, desc_size uint, out *Handle) Status
+TEXT ·Sys_iommu_create(SB),NOSPLIT,$0-36
+	MOVW resource+0(FP), R0
+	MOVW typ+4(FP), R1
+	MOVD desc+8(FP), R2
+	MOVD desc_size+16(FP), R3
+	MOVD out+24(FP), R4
+	BL vdso_zx_iommu_create(SB)
+	MOVW R0, ret+32(FP)
+	RET
+
+// func Sys_bti_create(iommu Handle, options uint32, bti_id uint64, out *Handle) Status
+TEXT ·Sys_bti_create(SB),NOSPLIT,$0-28
+	MOVW iommu+0(FP), R0
+	MOVW options+4(FP), R1
+	MOVD bti_id+8(FP), R2
+	MOVD out+16(FP), R3
+	BL vdso_zx_bti_create(SB)
+	MOVW R0, ret+24(FP)
+	RET
+
+// func Sys_bti_pin(handle Handle, options uint32, vmo Handle, offset uint64, size uint64, addrs *Paddr, addrs_count uint, out *Handle) Status
+TEXT ·Sys_bti_pin(SB),NOSPLIT,$0-60
+	MOVW handle+0(FP), R0
+	MOVW options+4(FP), R1
+	MOVW vmo+8(FP), R2
+	MOVD offset+16(FP), R3
+	MOVD size+24(FP), R4
+	MOVD addrs+32(FP), R5
+	MOVD addrs_count+40(FP), R6
+	MOVD out+48(FP), R7
+	BL vdso_zx_bti_pin(SB)
+	MOVW R0, ret+56(FP)
+	RET
+
+// func Sys_bti_release_quarantine(handle Handle) Status
+TEXT ·Sys_bti_release_quarantine(SB),NOSPLIT,$0-12
+	MOVW handle+0(FP), R0
+	BL vdso_zx_bti_release_quarantine(SB)
+	MOVW R0, ret+8(FP)
+	RET
+
+// func Sys_pmt_unpin(handle Handle) Status
+TEXT ·Sys_pmt_unpin(SB),NOSPLIT,$0-12
+	MOVW handle+0(FP), R0
+	BL vdso_zx_pmt_unpin(SB)
+	MOVW R0, ret+8(FP)
+	RET
+
+// func Sys_framebuffer_get_info(resource Handle, format *uint32, width *uint32, height *uint32, stride *uint32) Status
+TEXT ·Sys_framebuffer_get_info(SB),NOSPLIT,$0-44
+	MOVW resource+0(FP), R0
+	MOVD format+8(FP), R1
+	MOVD width+16(FP), R2
+	MOVD height+24(FP), R3
+	MOVD stride+32(FP), R4
+	BL vdso_zx_framebuffer_get_info(SB)
+	MOVW R0, ret+40(FP)
+	RET
+
+// func Sys_framebuffer_set_range(resource Handle, vmo Handle, len uint32, format uint32, width uint32, height uint32, stride uint32) Status
+TEXT ·Sys_framebuffer_set_range(SB),NOSPLIT,$0-36
+	MOVW resource+0(FP), R0
+	MOVW vmo+4(FP), R1
+	MOVW len+8(FP), R2
+	MOVW format+12(FP), R3
+	MOVW width+16(FP), R4
+	MOVW height+20(FP), R5
+	MOVW stride+24(FP), R6
+	BL vdso_zx_framebuffer_set_range(SB)
+	MOVW R0, ret+32(FP)
+	RET
+
+// func Sys_pc_firmware_tables(handle Handle, acpi_rsdp *Paddr, smbios *Paddr) Status
+TEXT ·Sys_pc_firmware_tables(SB),NOSPLIT,$0-28
+	MOVW handle+0(FP), R0
+	MOVD acpi_rsdp+8(FP), R1
+	MOVD smbios+16(FP), R2
+	BL vdso_zx_pc_firmware_tables(SB)
+	MOVW R0, ret+24(FP)
+	RET
+
+// func Sys_smc_call(handle Handle, parameters *SMCParameters, out_smc_result *SMCResult) Status
+TEXT ·Sys_smc_call(SB),NOSPLIT,$0-28
+	MOVW handle+0(FP), R0
+	MOVD parameters+8(FP), R1
+	MOVD out_smc_result+16(FP), R2
+	BL vdso_zx_smc_call(SB)
+	MOVW R0, ret+24(FP)
+	RET
+
+// func Sys_resource_create(parent_rsrc Handle, options uint32, base uint64, size uint, name *uint8, name_size uint, resource_out *Handle) Status
+TEXT ·Sys_resource_create(SB),NOSPLIT,$0-52
+	MOVW parent_rsrc+0(FP), R0
+	MOVW options+4(FP), R1
+	MOVD base+8(FP), R2
+	MOVD size+16(FP), R3
+	MOVD name+24(FP), R4
+	MOVD name_size+32(FP), R5
+	MOVD resource_out+40(FP), R6
+	BL vdso_zx_resource_create(SB)
+	MOVW R0, ret+48(FP)
+	RET
+
+// func Sys_system_mexec(resource Handle, kernel Handle, bootimage Handle) Status
+TEXT ·Sys_system_mexec(SB),NOSPLIT,$0-20
+	MOVW resource+0(FP), R0
+	MOVW kernel+4(FP), R1
+	MOVW bootimage+8(FP), R2
+	BL vdso_zx_system_mexec(SB)
+	MOVW R0, ret+16(FP)
+	RET
+
+// func Sys_system_powerctl(resource Handle, cmd uint32, arg *int) Status
+TEXT ·Sys_system_powerctl(SB),NOSPLIT,$0-20
+	MOVW resource+0(FP), R0
+	MOVW cmd+4(FP), R1
+	MOVD arg+8(FP), R2
+	BL vdso_zx_system_powerctl(SB)
+	MOVW R0, ret+16(FP)
+	RET
+
diff --git a/src/syscall/zx/types.go b/src/syscall/zx/types.go
new file mode 100644
index 0000000..d6c3870
--- /dev/null
+++ b/src/syscall/zx/types.go
@@ -0,0 +1,439 @@
+// Copyright 2016 The Go 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 fuchsia
+
+package zx
+
+import "unsafe"
+
+type Status int32    // zx_status_t
+type Handle uint32   // zx_handle_t
+type Clock uint32    // zx_clock_t,
+type Time int64      // zx_time_t, nanoseconds
+type Duration int64  // zx_duration_t, nanoseconds
+type Signals uint32  // zx_signals_t
+type Rights uint32   // zx_rights_t
+type Paddr uintptr   // zx_paddr_t
+type Vaddr uintptr   // zx_vaddr_t
+
+type WaitItem struct {
+	Handle  Handle
+	WaitFor Signals
+	Pending Signals
+} // zx_wait_item_t
+
+const HandleInvalid = Handle(0)
+
+// deprecated name
+const HANDLE_INVALID = Handle(0)
+
+const HandleSize = uint64(unsafe.Sizeof(Handle(0)))
+
+const ZX_MAX_NAME_LEN = 32
+
+const (
+	ZX_RREC_DELETED = 0
+	ZX_RREC_SELF    = 1
+	ZX_RREC_DATA    = 2
+	ZX_RREC_IRQ     = 3
+	ZX_RREC_MMIO    = 4
+	ZX_RREC_IOPORT  = 5
+)
+
+const (
+	ZX_RACT_ENABLE  = 1
+	ZX_RACT_DISABLE = 2
+)
+
+const (
+	ZX_RREC_SELF_GENERIC = 0
+	ZX_RREC_SELF_ROOT    = 1
+)
+
+type RrecSelf struct {
+	Type        uint16 // ZX_RREC_SELF
+	Subtype     uint16
+	Options     uint32
+	Koid        uint64
+	RecordCount uint32
+	ChildCount  uint32
+	_           [2]uint32
+	Name        [ZX_MAX_NAME_LEN]uint8
+} // zx_rrec_self_t
+
+type RrecMMIO struct {
+	Type     uint16 // ZX_RREC_MMIO
+	Subtype  uint16
+	Options  uint32
+	PhysBase uint64
+	PhysSize uint64
+	_        [10]uint32
+} // zx_rrec_mmio_t
+
+type RrecIRQ struct {
+	Type     uint16 // ZX_RREC_IRQ
+	Subtype  uint16
+	Options  uint32
+	IRQBase  uint32
+	IRQCount uint32
+	_        [12]uint32
+} // zx_rrec_irq_t
+
+type RrecIOPort struct {
+	Type      uint16 // ZX_RREC_IOPORT
+	Subtype   uint16
+	Options   uint32
+	PortBase  uint32
+	PortCount uint32
+	_         [12]uint32
+} // zx_rrec_ioport_t
+
+type RrecData struct {
+	Type    uint16
+	Subtype uint16
+	Options uint32 // low 4 bits are count
+	Data    [56]uint8
+} // zx_rrec_data_t
+
+type Rrec struct {
+	typ uint16
+	_   [62]uint8
+} // zx_rrec_t
+
+func (r *Rrec) Box() RrecValue {
+	switch r.typ {
+	case ZX_RREC_DELETED:
+		return nil
+	case ZX_RREC_SELF:
+		return (*RrecSelf)(unsafe.Pointer(r))
+	case ZX_RREC_DATA:
+		return (*RrecData)(unsafe.Pointer(r))
+	case ZX_RREC_IRQ:
+		return (*RrecIRQ)(unsafe.Pointer(r))
+	case ZX_RREC_MMIO:
+		return (*RrecMMIO)(unsafe.Pointer(r))
+	case ZX_RREC_IOPORT:
+		return (*RrecIOPort)(unsafe.Pointer(r))
+	default:
+		return nil
+	}
+}
+
+type RrecValue interface {
+	rrec()
+}
+
+func (*RrecSelf) rrec()   {}
+func (*RrecData) rrec()   {}
+func (*RrecIRQ) rrec()    {}
+func (*RrecMMIO) rrec()   {}
+func (*RrecIOPort) rrec() {}
+
+type ChannelCallArgs struct {
+	WriteBytes      uintptr
+	WriteHandles    *Handle
+	ReadBytes       uintptr
+	ReadHandles     *Handle
+	WriteNumBytes   uint32
+	WriteNumHandles uint32
+	ReadNumBytes    uint32
+	ReadNumHandles  uint32
+}
+
+type FIFOState struct {
+	head, tail uint64
+}
+
+type SMCParameters struct {
+	funcID                             uint32
+	arg1, arg2, arg3, arg4, arg5, arg6 uint64
+	clientId, secureOSID               uint16
+}
+
+type SMCResult struct {
+	arg0, arg1, arg2, arg3 uint64
+}
+
+// Status codes. See zircon/system/public/zircon/errors.h
+const (
+	ErrOk Status = -iota
+	ErrInternal
+	ErrNotSupported
+	ErrNoResources
+	ErrNoMemory
+	ErrCallFailed
+	ErrInterruptedRetry
+	_ // -7
+	_ // -8
+	_ // -9
+	ErrInvalidArgs
+	ErrBadHandle
+	ErrWrongType
+	ErrBadSyscall
+	ErrOutOfRange
+	ErrBufferTooSmall
+	_ // -16
+	_ // -17
+	_ // -18
+	_ // -19
+	ErrBadState
+	ErrTimedOut
+	ErrShouldWait
+	ErrCanceled
+	ErrPeerClosed
+	ErrNotFound
+	ErrAlreadyExists
+	ErrAlreadyBound
+	ErrUnavailable
+	_ // -29
+	ErrAccessDenied
+	_ // -31
+	_ // -32
+	_ // -33
+	_ // -34
+	_ // -35
+	_ // -36
+	_ // -37
+	_ // -38
+	_ // -39
+	ErrIO
+	ErrIORefused
+	ErrIODataIntegrity
+	ErrIODataLoss
+	_ // -44
+	_ // -45
+	_ // -46
+	_ // -47
+	_ // -48
+	_ // -49
+	ErrBadPath
+	ErrNotDir
+	ErrNotFile
+	ErrFileBig
+	ErrNoSpace
+	ErrNotEmpty
+	_ // -56
+	_ // -57
+	_ // -58
+	_ // -59
+	ErrStop
+	ErrNext
+	_ // -62
+	_ // -63
+	_ // -64
+	_ // -65
+	_ // -66
+	_ // -67
+	_ // -68
+	_ // -69
+	ErrProtocolNotSupported
+	ErrAddressUnreachable
+	ErrAddressInUse
+	ErrNotConnected
+	ErrConnectionRefused
+	ErrConnectionReset
+	ErrConnectionAborted
+
+	// deprecated
+	ErrHandleClosed = ErrCanceled
+	ErrRemoteClosed = ErrPeerClosed
+)
+
+const (
+	SignalObject0 = (1 << iota)
+	SignalObject1
+	SignalObject2
+	SignalObject3
+	SignalObject4
+	SignalObject5
+	SignalObject6
+	SignalObject7
+	SignalObject8
+	SignalObject9
+	SignalObject10
+	SignalObject11
+	SignalObject12
+	SignalObject13
+	SignalObject14
+	SignalObject15
+	SignalObject16
+	SignalObject17
+	SignalObject18
+	SignalObject19
+	SignalObject20
+	SignalObject21
+	SignalObject22
+	SignalObject23
+
+	SignalUser0
+	SignalUser1
+	SignalUser2
+	SignalUser3
+	SignalUser4
+	SignalUser5
+	SignalUser6
+	SignalUser7
+
+	// Aliases
+	SignalHandleClosed = SignalObject23
+
+	// Event
+	SignalEventSignaled = SignalObject3
+	SignalEventMask     = SignalUserAll | SignalEventSignaled
+
+	// EventPair
+	SignalEpairSignaled   = SignalObject3
+	SignalEpairPeerClosed = SignalObject2
+
+	// Channel
+	SignalChannelReadable   = SignalObject0
+	SignalChannelWritable   = SignalObject1
+	SignalChannelPeerClosed = SignalObject2
+
+	// Socket
+	SignalSocketReadable         = SignalObject0
+	SignalSocketWritable         = SignalObject1
+	SignalSocketPeerClosed       = SignalObject2
+	SignalSocketReadDisabled     = SignalObject4
+	SignalSocketWriteDisabled    = SignalObject5
+	SignalSocketControlReadable  = SignalObject6
+	SignalSocketControlWriteable = SignalObject7
+	SignalSocketAccept           = SignalObject8
+	SignalSocketShare            = SignalObject9
+
+	// Port
+	SignalPortReadable   = SignalObject0
+	SignalPortPeerClosed = SignalObject2
+	SignalPortSignaled   = SignalObject3
+
+	// Resource
+	SignalResourceReadable   = SignalObject0
+	SignalResourceWritable   = SignalObject1
+	SignalResourceChildAdded = SignalObject2
+
+	// Fifo
+	SignalFIFOReadable   = SignalObject0
+	SignalFIFOWritable   = SignalObject1
+	SignalFIFOPeerClosed = SignalObject2
+	SignalFIFOSignalMask = SignalFIFOReadable | SignalFIFOWritable | SignalFIFOPeerClosed
+
+	// Task signals (process, thread, job)
+	SignalTaskTerminated = SignalObject3
+	SignalTaskSignalMask = SignalObject3
+
+	// Job
+	SignalJobSignaled = SignalObject3
+
+	// Process
+	SignalProccessSignaled = SignalObject3
+
+	// Thread
+	SignalThreadSignaled = SignalObject3
+
+	SignalObjectAll = (0xfffff)
+	SignalUserAll   = Signals(15 << 4)
+	SignalNone      = Signals(0)
+)
+
+const (
+	RightDuplicate = Rights(1 << iota)
+	RightTransfer
+	RightRead
+	RightWrite
+	RightExecute
+	RightDebug
+	RightSameRights = Rights(1 << 31)
+	RightNone       = Rights(0)
+)
+
+// Topics for object_get_info
+const (
+	_ = iota
+	ObjectInfoHandleValid
+	ObjectInfoHandleBasic
+	ObjectInfoProcess
+	ObjectInfoProcessThreads
+	ObjectInfoResourceChildren
+	ObjectInfoResourceRecords
+	ObjectInfoVMAR
+)
+
+// Options for socket_create
+const (
+	SocketStream     = iota            // 0
+	SocketDatagram   = 1 << (iota - 1) // 1
+	SocketHasControl                   // 2
+	SocketHasAccept                    // 4
+)
+
+// Options for socket_write
+const (
+	_                   = iota // 0
+	SocketShutdownWrite        // 1
+	SocketShutdownRead         // 2
+)
+
+// Options for socket_write and socket_read
+const (
+	SocketControl = 1 << 2
+)
+
+const (
+	_                          = iota // 0
+	_                                 // 1
+	PropNumStateKinds                 // ZX_PROP_NUM_STATE_KINDS
+	PropName                          // ZX_PROP_NAME
+	PropRegisterFS                    // ZX_PROP_REGISTER_FS
+	PropProcessDebugAddr              // ZX_PROP_PROCESS_DEBUG_ADDR
+	PropProcessVDSOBaseAddress        // ZX_PROP_PROCESS_VDSO_BASE_ADDRESS
+	PropJobMaxHeight                  // ZX_PROP_JOB_MAX_HEIGHT
+)
+
+const (
+	TimensecInfinite = Time(0x7FFFFFFFFFFFFFFF)
+)
+
+// EOF is used like io.EOF.
+//
+// When package io is linked in, at initialization this value is
+// rewritten to be equivalent to io.EOF, so that the io.Readers
+// and io.Writers in this package meet their specs.
+var EOF error = eof{}
+
+type eof struct{}
+
+func (eof) Error() string { return "zx.EOF" }
+
+// EPIPE is used like syscall.EPIPE
+
+// When package syscall is linked in, at initialization this value is
+// rewritten to be equivalent to syscall.EPIPE.
+
+var EPIPE error = epipe{}
+
+type epipe struct{}
+
+func (epipe) Error() string { return "errno(32)" }
+
+type VMOOption int
+
+const (
+	VMOOptionNonResizable VMOOption = 1 << 0 // ZX_VMO_NON_RESIZABLE
+)
+
+type VMFlag int
+
+const (
+	VMFlagPermRead          VMFlag = 1 << 0 // ZX_VM_FLAG_PERM_READ
+	VMFlagPermWrite         VMFlag = 1 << 1 // ZX_VM_FLAG_PERM_WRITE
+	VMFlagPermExecute       VMFlag = 1 << 2 // ZX_VM_FLAG_PERM_EXECUTE
+	VMFlagCompact           VMFlag = 1 << 3 // ZX_VM_FLAG_COMPACT
+	VMFlagSpecific          VMFlag = 1 << 4 // ZX_VM_FLAG_SPECIFIC
+	VMFlagSpecificOverwrite VMFlag = 1 << 5 // ZX_VM_FLAG_SPECIFIC_OVERWRITE
+	VMFlagCanMapSpecific    VMFlag = 1 << 6 // ZX_VM_FLAG_CAN_MAP_SPECIFIC
+	VMFlagCanMapRead        VMFlag = 1 << 7 // ZX_VM_FLAG_CAN_MAP_READ
+	VMFlagCanMapWrite       VMFlag = 1 << 8 // ZX_VM_FLAG_CAN_MAP_WRITE
+	VMFlagCanMapExecute     VMFlag = 1 << 9 // ZX_VM_FLAG_CAN_MAP_EXECUTE
+)
diff --git a/src/syscall/zx/types_string.go b/src/syscall/zx/types_string.go
new file mode 100644
index 0000000..aac9809
--- /dev/null
+++ b/src/syscall/zx/types_string.go
@@ -0,0 +1,68 @@
+// generated by stringer -type=Status; DO NOT EDIT
+
+// +build fuchsia
+
+package zx
+
+const (
+	_Status_name_0 = "ErrNoSpaceErrFileBigErrNotFileErrNotDirErrBadPath"
+	_Status_name_1 = "ErrIODataLossErrIODataIntegrityErrIORefusedErrIO"
+	_Status_name_2 = "ErrAccessDenied"
+	_Status_name_3 = "ErrUnavailableErrAlreadyBoundErrAlreadyExistsErrNotFoundErrPeerClosedErrCanceledErrShouldWaitErrTimedOutErrBadState"
+	_Status_name_4 = "ErrBufferTooSmallErrOutOfRangeErrBadSyscallErrWrongTypeErrBadHandleErrInvalidArgs"
+	_Status_name_5 = "ErrInterruptedRetryErrCallFailedErrNoMemoryErrNoResourcesErrNotSupportedErrInternalErrOk"
+)
+
+var (
+	_Status_index_0 = [...]uint8{0, 10, 20, 30, 39, 49}
+	_Status_index_1 = [...]uint8{0, 13, 31, 43, 48}
+	_Status_index_2 = [...]uint8{0, 15}
+	_Status_index_3 = [...]uint8{0, 14, 29, 45, 56, 69, 80, 93, 104, 115}
+	_Status_index_4 = [...]uint8{0, 17, 30, 43, 55, 67, 81}
+	_Status_index_5 = [...]uint8{0, 19, 32, 43, 57, 72, 83, 88}
+)
+
+func (i Status) String() string {
+	switch {
+	case -54 <= i && i <= -50:
+		i -= -54
+		return _Status_name_0[_Status_index_0[i]:_Status_index_0[i+1]]
+	case -43 <= i && i <= -40:
+		i -= -43
+		return _Status_name_1[_Status_index_1[i]:_Status_index_1[i+1]]
+	case i == -30:
+		return _Status_name_2
+	case -28 <= i && i <= -20:
+		i -= -28
+		return _Status_name_3[_Status_index_3[i]:_Status_index_3[i+1]]
+	case -15 <= i && i <= -10:
+		i -= -15
+		return _Status_name_4[_Status_index_4[i]:_Status_index_4[i+1]]
+	case -6 <= i && i <= 0:
+		i -= -6
+		return _Status_name_5[_Status_index_5[i]:_Status_index_5[i+1]]
+	default:
+		var buf [20]byte
+		return "zx.Status(" + string(itoa(buf[:], int(i))) + ")"
+	}
+}
+
+func itoa(buf []byte, val int) []byte {
+	i := len(buf) - 1
+	neg := false
+	if val < 0 {
+		neg = true
+		val = 0 - val
+	}
+	for val >= 10 {
+		buf[i] = byte(val%10 + '0')
+		i--
+		val /= 10
+	}
+	buf[i] = byte(val + '0')
+	if neg {
+		i--
+		buf[i] = '-'
+	}
+	return buf[i:]
+}
diff --git a/src/syscall/zx/zxsocket/client.go b/src/syscall/zx/zxsocket/client.go
new file mode 100644
index 0000000..03b1135
--- /dev/null
+++ b/src/syscall/zx/zxsocket/client.go
@@ -0,0 +1,178 @@
+// Copyright 2016 The Go 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 fuchsia
+
+package zxsocket
+
+import (
+	"errors"
+	"syscall/zx"
+	"syscall/zx/mxnet"
+	"unsafe"
+)
+
+// Bind is BSD Sockets bind on a *Socket.
+func (s *Socket) Bind(addr mxnet.Addr, port uint16) error {
+	b := make([]byte, mxnet.SockaddrLen)
+	addrlen, err := mxnet.EncodeSockaddr(b, addr, port)
+	if err != nil {
+		return err
+	}
+	b = b[:addrlen]
+	_, err = s.Misc(OpBind, 0, b, nil, nil)
+	return err
+}
+
+// Connect is BSD Sockets connect on a *Socket.
+func (s *Socket) Connect(addr mxnet.Addr, port uint16) error {
+	b := make([]byte, mxnet.SockaddrLen)
+	addrlen, err := mxnet.EncodeSockaddr(b, addr, port)
+	if err != nil {
+		return err
+	}
+	b = b[:addrlen]
+
+	_, err = s.Misc(OpConnect, 0, b, nil, nil)
+	if err != nil && status(err) == zx.ErrShouldWait {
+		obs, err := s.Wait(mxnet.MXSIO_SIGNAL_OUTGOING, zx.TimensecInfinite)
+		switch status(err) {
+		case zx.ErrOk:
+			switch {
+			case obs&mxnet.MXSIO_SIGNAL_CONNECTED != 0:
+				return nil
+			default:
+				// TODO: Use opSetSockOpt to get the reason of the error.
+				return errors.New("zxsocket.Connect: OpConnect was not successful")
+			}
+		default:
+			return err
+		}
+	}
+	return err
+}
+
+// txn completes the client-side part of the RIO transaction.
+func (s *Socket) txn(msg *Msg) (uint32, error) {
+	if !msg.IsValid() {
+		return 0, zx.Error{Status: zx.ErrInvalidArgs, Text: "zxsocket.txn"}
+	}
+
+	msgBytes := (*[MessageSizeMax]byte)(unsafe.Pointer(msg))
+	numBytes, err := WriteControl(s.socket, msgBytes[:MessageHeaderSize+msg.Datalen])
+	if err != nil {
+		return 0, err
+	}
+	numBytes, err = ReadControl(s.socket, msgBytes[:])
+	if err != nil {
+		return 0, err
+	}
+
+	if !msg.IsValidIncoming(uint32(numBytes)) {
+		return 0, zx.Error{Status: zx.ErrIO, Text: "zxsocket.txn"}
+	}
+
+	// Check for remote error
+	status := zx.Status(msg.Arg)
+	if status < 0 {
+		return 0, zx.Error{Status: status, Text: "zxsocket.txn"}
+	}
+	return uint32(status), nil
+}
+
+func (s *Socket) ListenStream(backlog int) error {
+	b := make([]byte, 4)
+	b[0] = byte(backlog)
+	b[1] = byte(backlog >> 8)
+	b[2] = byte(backlog >> 16)
+	b[3] = byte(backlog >> 24)
+	_, err := s.Misc(OpListen, 0, b, nil, nil)
+	return err
+}
+
+func (s *Socket) Accept() (*Socket, error) {
+	if s.flags&SocketFlagsDidListen == 0 {
+		return nil, errors.New("zxsocket.Accept: listen was not called")
+	}
+
+	var h zx.Handle
+	for {
+		err := s.socket.Accept(&h)
+		if err == nil {
+			break
+		}
+		if status(err) != zx.ErrShouldWait {
+			return nil, err
+		}
+		s.socket.Handle().SignalPeer(0, zx.SignalUser7)
+		// TODO: non-blocking support, pass this to the poller
+		const ZX_SOCKET_ACCEPT = zx.SignalSocketAccept
+		const ZX_SOCKET_PEER_CLOSED = zx.SignalSocketPeerClosed
+		pending, err := s.Wait(ZX_SOCKET_ACCEPT|ZX_SOCKET_PEER_CLOSED, zx.TimensecInfinite)
+		if err != nil {
+			return nil, err
+		}
+		if pending&ZX_SOCKET_ACCEPT != 0 {
+			continue
+		}
+		if pending&ZX_SOCKET_PEER_CLOSED != 0 {
+			return nil, zx.Error{Status: zx.ErrPeerClosed, Text: "zxsocket"}
+		}
+	}
+	return NewSocket(zx.Socket(h)), nil
+}
+
+func (s *Socket) getName(op uint32, debug string) (addr mxnet.Addr, port uint16, err error) {
+	out := make([]byte, mxnet.SockaddrReplyLen)
+	_, err = s.Misc(OpGetSockname, 0, nil, out, nil)
+	if err != nil {
+		return "", 0, err
+	}
+	addr, port, err = mxnet.DecodeSockaddr(out)
+	if err != nil {
+		return "", 0, err
+	}
+
+	return addr, port, nil
+}
+
+func (s *Socket) SockName() (addr mxnet.Addr, port uint16, err error) {
+	return s.getName(OpGetSockname, "GetSockName")
+}
+
+func (s *Socket) PeerName() (addr mxnet.Addr, port uint16, err error) {
+	return s.getName(OpGetPeerName, "GetPeerName")
+}
+
+func (s *Socket) Misc(op uint32, off int64, in, out []byte, handles []zx.Handle) (n int, err error) {
+	if len(in) > MessageChunkSize || len(out) > MessageChunkSize {
+		return 0, zx.Error{Status: zx.ErrInvalidArgs, Text: "zxsocket.Misc"}
+	}
+
+	var msg Msg
+	msg.SetOp(op)
+	msg.Arg = int32(len(out))
+	msg.Datalen = uint32(len(in))
+	msg.SetOff(off)
+	copy(msg.Data[:], in)
+
+	if len(handles) > 0 {
+		copy(msg.Handle[:], handles)
+		msg.Hcount = uint32(len(handles))
+	}
+	if _, err = s.txn(&msg); err != nil {
+		return 0, err
+	}
+
+	if int(msg.Datalen) > len(out) {
+		return 0, zx.Error{Status: zx.ErrIO, Text: "zxsocket.Misc"}
+	}
+	n = copy(out, msg.Data[:msg.Datalen])
+
+	if op == OpListen {
+		s.flags |= SocketFlagsDidListen
+	}
+
+	return n, nil
+}
diff --git a/src/syscall/zx/zxsocket/message.go b/src/syscall/zx/zxsocket/message.go
new file mode 100644
index 0000000..b3a89a9
--- /dev/null
+++ b/src/syscall/zx/zxsocket/message.go
@@ -0,0 +1,227 @@
+// Copyright 2017 The Go 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 fuchsia
+
+package zxsocket
+
+import (
+	"unsafe"
+
+	"syscall/zx"
+)
+
+const (
+	// MessageChunkSize is the largest size of 'data' in an zxsocket message
+	MessageChunkSize = 900
+
+	// MessageSizeMax is the largest size of a zxsocket message
+	MessageSizeMax = uint32(unsafe.Sizeof(Msg{}))
+
+	// MessageHeaderSize is the size of zxsocket message without 'data'
+	MessageHeaderSize = uint32(unsafe.Sizeof(MsgHeader{}))
+
+	// MessageMaxHandles is the maximum number of handles a message may carry.
+	// In reality, zx.Sockets can't hold handles, but this is used to support
+	// the deprecated RemoteIO protocol over a socket.
+	MessageMaxHandles = 3
+)
+
+// Custom errors for zxsocket RemoteIO.
+var (
+	// If returned from dispatcher callback, indicates that the dispatcher should immediately
+	// disconnect with no additional callbacks.
+	ErrDisconnectNoCallback = zx.Error{Status: 1, Text: "fdio.Dispatcher"}
+	// If returned from dispatcher callback, indicates that there are no more messages to read.
+	ErrNoWork = zx.Error{Status: -9999, Text: "fdio.Dispatcher.NoWork"}
+	// If returned from dispatcher callback, indicates that the message was handed to another
+	// server.
+	ErrIndirect = zx.Error{Status: -9998, Text: "fdio.Dispatcher.Indirect"}
+)
+
+const (
+	OpFlagOneHandle = uint32(0x100 + iota)
+)
+
+// Values for op. Each one will signify a request for a different operation.
+// This is a copy of the list in fdio/message.go, with the non-socket-related
+// options removed. Note that these are deprecated. We will be migrating to
+// FIDL2 ordinals soon.
+const (
+	_ = uint32(iota)
+	OpClose
+	OpClone = uint32(iota) | OpFlagOneHandle
+	OpOpen  = uint32(iota) | OpFlagOneHandle
+	_       = uint32(iota) // OpMisc
+	OpRead
+	OpWrite
+	_ // OpSeek
+	_ // OpStat
+	_ // OpReaddir
+	OpIoctl
+	_                                          // OpUnlink
+	_                                          // OpReadAt
+	_                                          // OpWriteAt
+	_                                          // OpTruncate
+	_         = uint32(iota) | OpFlagOneHandle // OpRename
+	OpConnect = uint32(iota)
+	OpBind
+	OpListen
+	OpGetSockname
+	OpGetPeerName
+	OpGetSockOpt
+	OpSetSockOpt
+	OpGetAddrInfo
+	_                                  // OpSetAttr
+	_                                  // OpSync
+	_ = uint32(iota) | OpFlagOneHandle // OpLink
+	_ = uint32(iota)                   // OpMmap
+	OpFcntl
+	OpNumOps = uint32(iota) // The total number of operations
+)
+
+type Protocol uint32
+
+// All available FDIO protocols
+const (
+	// The SERVICE protocol allows access to a generic interface.
+	ProtocolService = Protocol(iota)
+	// The FILE protocol allows access to a regular file.
+	ProtocolFile
+	// The DIRECTORY protocol allows access to a directory, which may
+	// contain additional nodes.
+	ProtocolDirectory
+	// The PIPE protocol uses message ports as simple, no-flow-control io pipes.
+	ProtocolPipe
+	// The VMOFILE protocol accesses a file as a VMO.
+	ProtocolVMOFile
+	// The DEVICE protocol allows access to a generic device.
+	ProtocolDevice
+	// The SOCKET protocol provides socket access.
+	ProtocolSocket
+	ProtocolSocketConnected
+)
+
+const (
+	OpenFlagDescribe = 0x00800000
+)
+
+// FIDL2 message header
+type FIDLHeader struct {
+	Txid      uint32
+	reserved0 uint32
+	flags     uint32
+	op        uint32
+}
+
+type MsgHeader struct {
+	FIDLHeader
+	Datalen   uint32
+	Arg       int32
+	arg2      int64
+	reserved1 int32
+	Hcount    uint32
+	Handle    [4]zx.Handle // 3 handles + reply pipe, unused here though.
+}
+
+func (m *MsgHeader) Op() uint32 {
+	return m.op & 0x3FFF
+}
+func (m *MsgHeader) SetOp(v uint32) {
+	m.op = (v & 0x3FFF)
+}
+func (m *MsgHeader) OpHandleCount() uint32 {
+	return (m.op >> 8) & 3
+}
+func (m *MsgHeader) Off() int64 {
+	return m.arg2
+}
+func (m *MsgHeader) SetOff(v int64) {
+	m.arg2 = v
+}
+func (m *MsgHeader) Mode() uint32 {
+	return uint32(m.arg2)
+}
+func (m *MsgHeader) SetMode(v uint32) {
+	m.arg2 = int64(v)
+}
+func (m *MsgHeader) Protocol() Protocol {
+	return Protocol(m.arg2)
+}
+func (m *MsgHeader) SetProtocol(p Protocol) {
+	m.arg2 = int64(p)
+}
+func (m *MsgHeader) IoctlOp() uint32 {
+	return uint32(m.arg2)
+}
+func (m *MsgHeader) SetIoctlOp(v uint32) {
+	m.arg2 = int64(v)
+}
+func (m *MsgHeader) FcntlFlags() uint32 {
+	return uint32(m.arg2)
+}
+func (m *MsgHeader) SetFcntlFlags(v uint32) {
+	m.arg2 = int64(v)
+}
+
+// Msg is the message sent in the zxsocket protocol.
+type Msg struct {
+	MsgHeader
+	Data [MessageChunkSize]uint8
+}
+
+func (m *Msg) CallMsg(c *zx.Channel) (numBytes, numHandles uint32, err error) {
+	wData := (*[MessageSizeMax]byte)(unsafe.Pointer(m))[:MessageHeaderSize+m.Datalen]
+	var wHandles []zx.Handle
+	if m.Hcount > 0 {
+		wHandles = m.Handle[:m.Hcount]
+	}
+	rData := (*[MessageSizeMax]byte)(unsafe.Pointer(m))[:]
+	rHandles := m.Handle[:]
+	numBytes, numHandles, err = c.Call(0, zx.TimensecInfinite, wData, wHandles, rData, rHandles)
+	m.Hcount = numHandles
+	return
+}
+
+// ReadMsg reads a message from a socket.
+func (m *Msg) ReadMsg(s zx.Socket) (numBytes int, numHandles uint32, err error) {
+	msgBytes := (*[MessageSizeMax]byte)(unsafe.Pointer(m))
+	// TODO: why is numBytes int?
+	numBytes, err = s.Read(msgBytes[:], zx.SocketControl)
+	numHandles = 0
+	m.Hcount = numHandles
+	return
+}
+
+// WriteMsg writes a message to a socket.
+func (m *Msg) WriteMsg(s zx.Socket) (int, error) {
+	msgBytes := (*[MessageSizeMax]byte)(unsafe.Pointer(m))
+	data := msgBytes[:MessageHeaderSize+m.Datalen]
+	return s.Write(data, zx.SocketControl)
+}
+
+// WriteMsg writes a message to a channel.
+func (m *Msg) WriteChannelMsg(c *zx.Channel) error {
+	msgBytes := (*[MessageSizeMax]byte)(unsafe.Pointer(m))
+	data := msgBytes[:MessageHeaderSize+m.Datalen]
+	var handles []zx.Handle
+	if m.Hcount > 0 {
+		handles = m.Handle[:m.Hcount]
+	}
+	return c.Write(data, handles, 0)
+}
+
+func (m *Msg) IsValid() bool {
+	if m.Datalen > MessageChunkSize || m.Hcount != 0 {
+		return false
+	}
+	return true
+}
+
+func (m *Msg) IsValidIncoming(size uint32) bool {
+	if (size < MessageHeaderSize) || m.Datalen != (size-MessageHeaderSize) {
+		return false
+	}
+	return m.IsValid()
+}
diff --git a/src/syscall/zx/zxsocket/server.go b/src/syscall/zx/zxsocket/server.go
new file mode 100644
index 0000000..211babf
--- /dev/null
+++ b/src/syscall/zx/zxsocket/server.go
@@ -0,0 +1,69 @@
+// Copyright 2017 The Go 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 fuchsia
+
+package zxsocket
+
+import (
+	"syscall/zx"
+)
+
+// ServerHandler is the type of the callback which contains the remoteio "server". It is called from
+// the server handler function.
+// - msg.Datalen represents the size of the incoming/outgoing message in msg.Data.
+// - Return values are placed in msg.Arg. Negative is error.
+type ServerHandler func(msg *Msg, rh zx.Socket, cookie int64) zx.Status
+
+// Handler reads a single RIO message from the handle h. If the message is valid, the callback
+// cb is invoked. If the callback is successful, a response may be sent back on handle h.
+func Handler(h zx.Socket, cb interface{}, cookie int64) error {
+	var msg Msg
+
+	serverCb := cb.(ServerHandler)
+	if h == 0 {
+		// The remote side has been closed. Send our final callback and leave.
+		msg.SetOp(OpClose)
+		msg.Arg = 0
+		msg.Datalen = 0
+		msg.Hcount = 0
+		serverCb(&msg, 0, cookie)
+		return nil
+	}
+	msg.Hcount = MessageMaxHandles
+	numBytesInt, _, err := msg.ReadMsg(h)
+	numBytes := uint32(numBytesInt)
+	if err != nil {
+		if mxerr, hasStatus := err.(zx.Error); hasStatus && mxerr.Status == zx.ErrBadState {
+			return ErrNoWork
+		}
+		return err
+	}
+	if !msg.IsValidIncoming(numBytes) {
+		return zx.Error{Status: zx.ErrInvalidArgs, Text: "zxsocket.Handler"}
+	}
+
+	isClose := (msg.Op() == OpClose)
+	status := serverCb(&msg, h, cookie)
+	msg.Arg = int32(status)
+	if zx.Status(msg.Arg) == ErrIndirect.Status {
+		// The callback is handling the reply itself
+		return nil
+	} else if status < 0 || !msg.IsValid() {
+		// zx.Error case
+		msg.Datalen = 0
+		if msg.Arg >= 0 {
+			// TODO(smklein): This error code may change. It currently is set to "ERR_FAULT" in
+			// Zircon, but is scheduled to change.
+			msg.Arg = int32(zx.ErrIO)
+		}
+	}
+
+	_, err = msg.WriteMsg(h)
+	if isClose {
+		// Signals that a close callback is not necessary -- the op has already completed
+		return ErrDisconnectNoCallback
+	}
+	return err
+}
diff --git a/src/syscall/zx/zxsocket/socket.go b/src/syscall/zx/zxsocket/socket.go
new file mode 100644
index 0000000..d38b9f5
--- /dev/null
+++ b/src/syscall/zx/zxsocket/socket.go
@@ -0,0 +1,380 @@
+// Copyright 2017 The Go 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 fuchsia
+
+package zxsocket
+
+import (
+	"io"
+	"syscall/zx"
+	"syscall/zx/fdio"
+	fidlIo "syscall/zx/io"
+	"syscall/zx/mxnet"
+	"syscall/zx/zxwait"
+)
+
+// Status extracts an zx.Status from an error. This is duplicated from syscall/zx/merror,
+// but we can't import that directly because it causes an import loop.
+func status(err error) zx.Status {
+	if err == nil {
+		return zx.ErrOk
+	}
+	if s, hasStatus := err.(zx.Error); hasStatus {
+		return s.Status
+	}
+	return zx.ErrInternal
+}
+
+// Socket is an fdio.FDIO socket.
+type Socket struct {
+	socket zx.Socket
+
+	dgram bool
+	flags uint32
+}
+
+// Socket flags
+const (
+	SocketFlagsDidListen = 1 << iota // zxsocket._DID_LISTEN
+)
+
+func NewSocket(s zx.Socket) *Socket {
+	return &Socket{socket: s}
+}
+
+func (s *Socket) Wait(signals zx.Signals, timeout zx.Time) (observed zx.Signals, err error) {
+	return zxwait.Wait(zx.Handle(s.socket), signals, timeout)
+}
+
+// Handles returns the underlying handles for this Socket.
+func (s *Socket) Handles() []zx.Handle {
+	return []zx.Handle{zx.Handle(s.socket)}
+}
+
+// Clone makes a clone of the object.
+func (s *Socket) Clone() (fdio.FDIO, error) {
+	return nil, zx.Error{Status: zx.ErrNotSupported, Text: "zxsocket.Socket.Clone"}
+}
+
+// Close closes the object.
+func (s *Socket) Close() error {
+	if s.socket == 0 {
+		return nil
+	}
+	var msg Msg
+	msg.SetOp(OpClose)
+
+	_, err := s.txn(&msg)
+
+	s.socket.Close()
+	s.socket = 0
+
+	if err != nil {
+		return err
+	}
+	return nil
+}
+
+// Sync implements fdio.FDIO for Socket.
+func (s *Socket) Sync() error {
+	return zx.Error{Status: zx.ErrNotSupported, Text: "zxsocket.Socket"}
+}
+
+// GetAttr implements fdio.FDIO for Socket.
+func (s *Socket) GetAttr() (fidlIo.NodeAttributes, error) {
+	return fidlIo.NodeAttributes{}, zx.Error{Status: zx.ErrNotSupported, Text: "zxsocket.Socket"}
+}
+
+// SetAttr implements fdio.FDIO for Socket.
+func (s *Socket) SetAttr(flags uint32, attr fidlIo.NodeAttributes) error {
+	return zx.Error{Status: zx.ErrNotSupported, Text: "zxsocket.Socket"}
+}
+
+// Ioctl implements fdio.FDIO for Socket.
+func (s *Socket) Ioctl(op uint32, max uint64, in []byte, _ []zx.Handle) ([]byte, []zx.Handle, error) {
+	var msg Msg
+	if len(in) > fdio.IoctlMaxInput {
+		return nil, nil, zx.Error{Status: zx.ErrInvalidArgs, Text: "zxsocket.Ioctl"}
+	}
+
+	if fdio.IoctlKind(op) != fdio.IoctlKindDefault {
+		return nil, nil, zx.Error{Status: zx.ErrNotSupported, Text: "zxsocket.Ioctl"}
+	}
+
+	out := make([]byte, MessageSizeMax)
+	msg.SetOp(OpIoctl)
+	msg.Datalen = uint32(len(in))
+	msg.Arg = int32(len(out))
+	msg.SetIoctlOp(op)
+	copy(msg.Data[:], in)
+
+	_, err := s.txn(&msg)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	copy(out, msg.Data[:msg.Datalen])
+	return out[:msg.Datalen], nil, nil
+}
+
+// Read implements fdio.FDIO for Socket.
+func (s *Socket) Read(data []byte) (n int, err error) {
+	if s.dgram {
+		b, _, _, _, err := s.RecvMsg(len(data))
+		n = copy(data, b)
+		return n, err
+	}
+	// c.f. mxsio_read_stream in zircon/system/ulib/fdio/remoteio.c
+	for {
+		n, err = s.socket.Read(data, 0)
+		switch status(err) {
+		case zx.ErrOk:
+			return n, nil
+		case zx.ErrPeerClosed:
+			return 0, io.EOF
+		case zx.ErrShouldWait:
+			obs, err := s.Wait(zx.SignalSocketReadable|zx.SignalSocketPeerClosed, zx.TimensecInfinite)
+			switch status(err) {
+			case zx.ErrOk:
+				switch {
+				case obs&zx.SignalSocketReadable != 0:
+					continue
+				case obs&zx.SignalSocketPeerClosed != 0:
+					return 0, io.EOF
+				}
+			case zx.ErrBadHandle, zx.ErrCanceled:
+				return 0, io.EOF
+			default:
+				return 0, err
+			}
+		default:
+			return 0, err
+		}
+	}
+}
+
+// ReadAt implements fdio.FDIO for Socket.
+func (s *Socket) ReadAt(data []byte, off int64) (int, error) {
+	return 0, zx.Error{Status: zx.ErrNotSupported, Text: "zxsocket.Socket"}
+}
+
+// Write implements fdio.FDIO for Socket.
+func (s *Socket) Write(data []byte) (int, error) {
+	if s.dgram {
+		n, err := s.SendMsg(data, "", 0)
+		return n, err
+	}
+
+	// c.f. zxsio_write_stream
+	var total int
+	for {
+		n, err := s.socket.Write(data, 0)
+		total += n
+
+		switch status(err) {
+		case zx.ErrOk:
+			return total, nil
+		case zx.ErrShouldWait:
+			obs, err := s.Wait(zx.SignalSocketWritable|zx.SignalSocketPeerClosed|zx.SignalSocketWriteDisabled, zx.TimensecInfinite)
+			if err != nil {
+				return total, err
+			}
+			if obs&zx.SignalSocketPeerClosed != 0 || obs&zx.SignalSocketWriteDisabled != 0 {
+				return total, zx.Error{Status: zx.ErrPeerClosed, Text: "zxsocket.Socket.Write"}
+			}
+			if obs&zx.SignalSocketWritable != 0 {
+				data = data[n:]
+				continue
+			}
+			// This case should be impossible:
+			return total, zx.Error{Status: zx.ErrInternal, Text: "zxsocket.Socket.Write(impossible state)"}
+		default:
+			return total, err
+		}
+	}
+}
+
+// WriteAt implements fdio.FDIO for Socket.
+func (s *Socket) WriteAt(data []byte, off int64) (int, error) {
+	return 0, zx.Error{Status: zx.ErrNotSupported, Text: "zxsocket.Socket"}
+}
+
+// Seek implements fdio.FDIO for Socket.
+func (s *Socket) Seek(offset int64, whence int) (int64, error) {
+	return 0, zx.Error{Status: zx.ErrNotSupported, Text: "zxsocket.Socket"}
+}
+
+// Truncate implements fdio.FDIO for Socket.
+func (s *Socket) Truncate(length uint64) error {
+	return zx.Error{Status: zx.ErrNotSupported, Text: "zxsocket.Socket"}
+}
+
+// Open implements fdio.FDIO for Socket.
+func (s *Socket) Open(path string, flags uint32, mode uint32) (fdio.FDIO, error) {
+	return nil, zx.Error{Status: zx.ErrNotSupported, Text: "zxsocket.Socket"}
+}
+
+// Link implements fdio.FDIO for Socket.
+func (s *Socket) Link(oldpath, newpath string) error {
+	return zx.Error{Status: zx.ErrNotSupported, Text: "zxsocket.Socket"}
+}
+
+// Rename implements fdio.FDIO for Socket.
+func (s *Socket) Rename(oldpath, newpath string) error {
+	return zx.Error{Status: zx.ErrNotSupported, Text: "zxsocket.Socket"}
+}
+
+// Unlink implements fdio.FDIO for Socket.
+func (s *Socket) Unlink(path string) error {
+	return zx.Error{Status: zx.ErrNotSupported, Text: "zxsocket.Socket"}
+}
+
+// ReadDirents implements fdio.FDIO for Socket.
+func (s *Socket) ReadDirents(max uint64) ([]byte, error) {
+	return nil, zx.Error{Status: zx.ErrNotSupported, Text: "zxsocket.Socket"}
+}
+
+// Rewind implements fdio.FDIO for Socket.
+func (s *Socket) Rewind() error {
+	return zx.Error{Status: zx.ErrNotSupported, Text: "zxsocket.Socket"}
+}
+
+func (s *Socket) RecvMsg(maxLen int) (b []byte, flags int, addr string, port uint16, err error) {
+	mlen := maxLen + mxnet.SockmsgHdrLen
+	msgdata := make([]byte, mlen)
+	n, err := s.recvMsg(msgdata)
+	if err != nil {
+		return nil, 0, "", 0, err
+	}
+	msgdata = msgdata[:n]
+	addrstr, port, flags, err := mxnet.DecodeSockmsgHdr(msgdata)
+	if err != nil {
+		return nil, 0, "", 0, err
+	}
+	return msgdata[mxnet.SockmsgHdrLen:], flags, string(addrstr), port, nil
+}
+
+func (s *Socket) recvMsg(data []byte) (int, error) {
+	for {
+		n, err := s.socket.Read(data, 0)
+		switch status(err) {
+		case zx.ErrOk:
+			return n, err
+		case zx.ErrShouldWait:
+			if n != 0 {
+				return n, zx.Error{Status: zx.ErrInternal, Text: "zsocket.Socket.recvMsg(datagram short-read)"}
+			}
+
+			obs, err := s.Wait(zx.SignalSocketReadable|zx.SignalSocketPeerClosed|zx.SignalSocketReadDisabled, zx.TimensecInfinite)
+			if err != nil {
+				return n, err
+			}
+			if obs&zx.SignalSocketReadable != 0 {
+				continue
+			}
+			if obs&zx.SignalSocketPeerClosed != 0 || obs&zx.SignalSocketReadDisabled != 0 {
+				return n, zx.Error{Status: zx.ErrPeerClosed, Text: "zxsocket.Socket.recvMsg"}
+			}
+			return n, zx.Error{Status: zx.ErrInternal, Text: "zxsocket.Socket.recvMsg"}
+		default:
+			return n, err
+		}
+	}
+}
+
+func (s *Socket) SendMsg(b []byte, addr string, port uint16) (int, error) {
+	data := make([]byte, len(b)+mxnet.SockmsgHdrLen)
+	err := mxnet.EncodeSockmsgHdr(data, mxnet.Addr(addr), port, 0)
+	if err != nil {
+		return 0, err
+	}
+	copy(data[mxnet.SockmsgHdrLen:], b)
+
+	for {
+		n, err := s.socket.Write(data, 0)
+		switch status(err) {
+		case zx.ErrOk:
+			return len(b), nil
+		case zx.ErrShouldWait:
+			if n != 0 {
+				return n, zx.Error{Status: zx.ErrInternal, Text: "zxsocket.Socket.SendMsg(datagram short-write)"}
+			}
+
+			obs, err := s.Wait(zx.SignalSocketWritable|zx.SignalSocketPeerClosed|zx.SignalSocketWriteDisabled, zx.TimensecInfinite)
+			if err != nil {
+				return 0, err
+			}
+			if obs&zx.SignalSocketWritable != 0 {
+				continue
+			}
+			if obs&zx.SignalSocketPeerClosed != 0 || obs&zx.SignalSocketWriteDisabled != 0 {
+				return 0, zx.Error{Status: zx.ErrPeerClosed, Text: "zxsocket.Socket.SendMsg"}
+			}
+			return 0, zx.Error{Status: zx.ErrInternal, Text: "zxsocket.Socket.SendMsg(impossible state)"}
+		default:
+			if n != 0 {
+				return n, zx.Error{Status: zx.ErrInternal, Text: "zxsocket.Socket.SendMsg(datagram short-write)"}
+			}
+			return 0, err
+		}
+	}
+}
+
+// SetDgram marks a *Socket as a datagram (UDP) socket.
+// A different protocol is used internally.
+func (s *Socket) SetDgram() {
+	s.dgram = true
+}
+
+func ReadControl(s zx.Socket, data []byte) (n int, err error) {
+	// c.f. zxsocket._read_control in zircon/system/ulib/fdio/remoteio.c
+	for {
+		n, err = s.Read(data, zx.SocketControl)
+		switch status(err) {
+		case zx.ErrOk:
+			return n, nil
+		case zx.ErrPeerClosed:
+			return 0, io.EOF
+		case zx.ErrShouldWait:
+			obs, err := zxwait.Wait(
+				zx.Handle(s),
+				zx.SignalSocketControlReadable|zx.SignalSocketPeerClosed,
+				zx.TimensecInfinite,
+			)
+			switch status(err) {
+			case zx.ErrOk:
+				switch {
+				case obs&zx.SignalSocketControlReadable != 0:
+					continue
+				case obs&zx.SignalSocketPeerClosed != 0:
+					return 0, io.EOF
+				}
+			case zx.ErrBadHandle, zx.ErrCanceled:
+				return 0, io.EOF
+			default:
+				return 0, err
+			}
+		default:
+			return 0, err
+		}
+	}
+}
+
+func WriteControl(s zx.Socket, data []byte) (int, error) {
+	// c.f. zxsocket._write_control
+	for {
+		n, err := s.Write(data, zx.SocketControl)
+		switch status(err) {
+		case zx.ErrOk:
+			return n, nil
+		case zx.ErrShouldWait:
+			_, err := zxwait.Wait(zx.Handle(s), zx.SignalSocketControlWriteable, zx.TimensecInfinite)
+			if err != nil {
+				return n, err
+			}
+			continue
+		}
+	}
+}
diff --git a/src/syscall/zx/zxwait/zxwait.go b/src/syscall/zx/zxwait/zxwait.go
new file mode 100644
index 0000000..f96b941
--- /dev/null
+++ b/src/syscall/zx/zxwait/zxwait.go
@@ -0,0 +1,178 @@
+// Copyright 2018 The Go 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 fuchsia
+
+// Package zxwait implements a Zircon port waiter compatible with goroutines.
+//
+// The function Wait can be used to wait on a handle without consuming
+// an OS thread or resorting to event-driven programming.
+package zxwait
+
+import (
+	"sync"
+	"sync/atomic"
+	"syscall/zx"
+
+	_ "unsafe" // for go:linkname
+)
+
+// Wait waits for signals on handle.
+//
+// The goroutine that calls Wait is parked until a signal is observed or the
+// handle is closed. No OS thread is tied up while Wait is blocked.
+//
+// Semantically it is equivalent to calling the WaitOne method on a zx.Handle.
+// However it is not implemented with zx_object_wait_one, instead it uses
+// zx_object_wait_async and a port to wait for signals.
+func Wait(handle zx.Handle, signals zx.Signals, timeout zx.Time) (observed zx.Signals, err error) {
+	// TODO: support finite timeouts.
+	if timeout != zx.TimensecInfinite {
+		if status := zx.Sys_object_wait_one(handle, signals, timeout, &observed); status != zx.ErrOk {
+			return observed, zx.Error{Status: status, Text: "zxwait.Wait"}
+		}
+		return observed, nil
+	}
+	sysWaiterOnce.Do(sysWaiterInit)
+	return sysWaiter.Wait(handle, signals)
+}
+
+//go:linkname gopark runtime.gopark
+func gopark(unlockf func(g uintptr, waiting *waitingG) bool, waitng *waitingG, reason string, traceEv byte, traceskip int)
+
+//go:linkname goready runtime.goready
+func goready(g uintptr, traceskip int)
+
+// waitingG is used to track a parked g waiting on a singal.
+//
+// A waitingG is represented by a unique key, which is also
+// its positional index in the waiter's all slice. This key
+// is not a GCed pointer, so it can be safely passed to the
+// kernel and returned at a later time.
+type waitingG struct {
+	key   uint64 // index into all, stable identifier passed to kernel
+	g     uintptr
+	obs   uint32  // zx.Signals
+	ready uintptr // set when g is set by unlockf or obs set by dequeue
+}
+
+// A waiter is a zircon port that parks goroutines waiting on signals.
+//
+// Currently there is only one instance of waiter per process, stored
+// in sysWaiter. It is however a self-contained object and multiple
+// of them can safely exist concurrently.
+type waiter struct {
+	port zx.Port
+
+	mu   sync.Mutex
+	free []*waitingG
+	all  []*waitingG
+}
+
+func newWaiter() *waiter {
+	port, err := zx.NewPort(0)
+	if err != nil {
+		panic(err) // misuse of system call, no useful recovery
+	}
+	w := &waiter{
+		port: port,
+	}
+	go w.dequeue()
+	return w
+}
+
+var sysWaiterOnce sync.Once
+var sysWaiter *waiter
+
+func sysWaiterInit() {
+	sysWaiter = newWaiter()
+}
+
+// dequeue is a dedicated goroutine to waiting on the waiter's port.
+func (w *waiter) dequeue() {
+	var pkt zx.Packet
+	for {
+		err := w.port.Wait(&pkt, zx.TimensecInfinite)
+		if err != nil {
+			panic(err)
+		}
+
+		w.mu.Lock()
+		waiting := w.all[pkt.Hdr.Key]
+		w.mu.Unlock()
+
+		obs := pkt.Signal().Observed
+
+		atomic.StoreUint32(&waiting.obs, uint32(obs))
+		if atomic.CompareAndSwapUintptr(&waiting.ready, 0, 1) {
+			// We beat unlockf, goroutine never parked.
+			continue
+		}
+		// We were beaten by unlockf, so waiting.g has a real value.
+		g := atomic.LoadUintptr(&waiting.g)
+		goready(g, 0)
+	}
+}
+
+// Wait waits for signals on handle.
+//
+// See the package function Wait for more commentary.
+func (w *waiter) Wait(handle zx.Handle, signals zx.Signals) (observed zx.Signals, err error) {
+	var waiting *waitingG
+
+	w.mu.Lock()
+	if len(w.free) == 0 {
+		waiting = &waitingG{
+			key: uint64(len(w.all)),
+		}
+		w.all = append(w.all, waiting)
+	} else {
+		waiting = w.free[len(w.free)-1]
+		w.free = w.free[:len(w.free)-1]
+	}
+	w.mu.Unlock()
+
+	var pkt zx.Packet
+	pkt.Hdr.Key = waiting.key
+	pkt.Signal().Trigger = signals
+
+	const ZX_WAIT_ASYNC_ONCE = 0
+	if err = w.port.WaitAsync(handle, pkt.Hdr.Key, signals, ZX_WAIT_ASYNC_ONCE); err != nil {
+		return 0, err
+	}
+
+	const traceEv = 24
+	gopark(w.unlockf, waiting, "zxwait", traceEv, 0)
+
+	obs := atomic.LoadUint32(&waiting.obs)
+
+	*waiting = waitingG{key: waiting.key} // clear waitingG for reuse
+
+	w.mu.Lock()
+	w.free = append(w.free, waiting)
+	w.mu.Unlock()
+
+	return zx.Signals(obs), nil
+}
+
+// unlockf is passed as a callback to gopark.
+//
+// Reporting true will park the goroutine until goready is called.
+//
+// Reporting false will immediately start running the goroutine
+// again, and nothing else should call goready.
+//
+// This method is called without a 'g', so it can do very little.
+// Avoid the stack. Don't use anything with 'g'-based runtime
+// support (like sync.Mutex). Do as little as possible.
+func (w *waiter) unlockf(g uintptr, waiting *waitingG) bool {
+	atomic.StoreUintptr(&waiting.g, g)
+
+	// If we can set ready, then this executed before dequeue
+	// and the goroutine will be parked.
+	//
+	// If we cannot set it, then dequeue has already run and
+	// waiting.obs is set, so do not park the goroutine.
+	return atomic.CompareAndSwapUintptr(&waiting.ready, 0, 1)
+}
diff --git a/src/syscall/zx/zxwait/zxwait.s b/src/syscall/zx/zxwait/zxwait.s
new file mode 100644
index 0000000..a35105e
--- /dev/null
+++ b/src/syscall/zx/zxwait/zxwait.s
@@ -0,0 +1,5 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Empty assembly file so empty func definitions work.
diff --git a/src/syscall/zx/zxwait/zxwait_test.go b/src/syscall/zx/zxwait/zxwait_test.go
new file mode 100644
index 0000000..b649344
--- /dev/null
+++ b/src/syscall/zx/zxwait/zxwait_test.go
@@ -0,0 +1,84 @@
+// Copyright 2017 The Go 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 fuchsia
+
+package zxwait_test
+
+import (
+	"runtime"
+	"sync"
+	"syscall/zx"
+	"syscall/zx/zxwait"
+	"testing"
+)
+
+func TestWaitPreexisting(t *testing.T) {
+	c0, c1, err := zx.NewChannel(0)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer c0.Close()
+	defer c1.Close()
+
+	obs, err := zxwait.Wait(*c0.Handle(), zx.SignalChannelWritable, zx.TimensecInfinite)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if obs&zx.SignalChannelWritable == 0 {
+		t.Errorf("want zx.SignalChannelWritable, got obs=%x", obs)
+	}
+
+	obs, err = zxwait.Wait(*c1.Handle(), zx.SignalChannelWritable, zx.TimensecInfinite)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if obs&zx.SignalChannelWritable == 0 {
+		t.Errorf("want zx.SignalChannelWritable, got obs=%x", obs)
+	}
+}
+
+func TestWait(t *testing.T) {
+	t.Logf("GOMAXPROCS=%v", runtime.GOMAXPROCS(0))
+	c0s := make([]zx.Channel, 100)
+	c1s := make([]zx.Channel, len(c0s))
+	allObs := make([]zx.Signals, len(c0s))
+
+	var wg sync.WaitGroup
+	for i := range c0s {
+		var err error
+		c0s[i], c1s[i], err = zx.NewChannel(0)
+		if err != nil {
+			t.Fatal(err)
+		}
+		wg.Add(1)
+		go func(i int) {
+			obs, err := zxwait.Wait(*c0s[i].Handle(), zx.SignalChannelReadable, zx.TimensecInfinite)
+			if err != nil {
+				t.Fatal(err)
+			}
+			allObs[i] = obs
+			//t.Logf("signal for channel %d received", i)
+			//fmt.Printf("TEST: signal for channel %d received\n", i)
+			wg.Done()
+		}(i)
+	}
+
+	b := []byte("hello")
+	for i, c1 := range c1s {
+		//t.Logf("writing on channel %d", i)
+		//fmt.Printf("TEST: writing on channel %d\n", i)
+		if err := c1.Write(b, nil, 0); err != nil {
+			t.Errorf("failed to write on channel %d: %v", i, err)
+		}
+	}
+
+	wg.Wait()
+
+	for i, obs := range allObs {
+		if obs&zx.SignalChannelWritable == 0 {
+			t.Errorf("channel %d: obs=%x want zx.SignalChannelReadable", i, obs)
+		}
+	}
+}
diff --git a/src/time/sys_fuchsia.go b/src/time/sys_fuchsia.go
new file mode 100644
index 0000000..6fdb086
--- /dev/null
+++ b/src/time/sys_fuchsia.go
@@ -0,0 +1,29 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package time
+
+func initLocal() {
+	localLoc.name = "UTC"
+}
+
+func read(fd uintptr, buf []byte) (int, error) {
+	panic("TODO")
+}
+
+func open(name string) (uintptr, error) {
+	panic("TODO")
+}
+
+func closefd(fd uintptr) {
+	panic("TODO")
+}
+
+func preadn(fd uintptr, buf []byte, off int) error {
+	panic("TODO")
+}
+
+func isNotExist(err error) bool {
+	panic("TODO")
+}
diff --git a/src/time/zoneinfo_fuchsia.go b/src/time/zoneinfo_fuchsia.go
new file mode 100644
index 0000000..09a6696
--- /dev/null
+++ b/src/time/zoneinfo_fuchsia.go
@@ -0,0 +1,7 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package time
+
+var zoneSources = []string{}