diff --git a/src/cmd/compile/internal/importer/gcimporter.go b/src/cmd/compile/internal/importer/gcimporter.go
index f6ec6554a85b5ae30d8f3dcc7b2ece8e26bebb8f..0aa779441a7a3a364ed81aa689f752efce6bd6ee 100644
--- a/src/cmd/compile/internal/importer/gcimporter.go
+++ b/src/cmd/compile/internal/importer/gcimporter.go
@@ -9,9 +9,11 @@ import (
 	"bufio"
 	"fmt"
 	"go/build"
+	"internal/goroot"
 	"internal/pkgbits"
 	"io"
 	"os"
+	"path"
 	"path/filepath"
 	"strings"
 
@@ -21,7 +23,26 @@ import (
 // debugging/development support
 const debug = false
 
-var pkgExts = [...]string{".a", ".o"}
+func lookupGorootExport(pkgpath, srcRoot, srcDir string) (string, bool) {
+	pkgpath = filepath.ToSlash(pkgpath)
+	m, err := goroot.PkgfileMap()
+	if err != nil {
+		return "", false
+	}
+	if export, ok := m[pkgpath]; ok {
+		return export, true
+	}
+	vendorPrefix := "vendor"
+	if strings.HasPrefix(srcDir, filepath.Join(srcRoot, "cmd")) {
+		vendorPrefix = path.Join("cmd", vendorPrefix)
+	}
+	pkgpath = path.Join(vendorPrefix, pkgpath)
+	fmt.Fprintln(os.Stderr, "looking up ", pkgpath)
+	export, ok := m[pkgpath]
+	return export, ok
+}
+
+var pkgExts = [...]string{".a", ".o"} // a file from the build cache will have no extension
 
 // FindPkg returns the filename and unique package id for an import
 // path based on package information provided by build.Import (using
@@ -43,11 +64,18 @@ func FindPkg(path, srcDir string) (filename, id string) {
 		}
 		bp, _ := build.Import(path, srcDir, build.FindOnly|build.AllowBinary)
 		if bp.PkgObj == "" {
-			id = path // make sure we have an id to print in error message
-			return
+			var ok bool
+			if bp.Goroot {
+				filename, ok = lookupGorootExport(path, bp.SrcRoot, srcDir)
+			}
+			if !ok {
+				id = path // make sure we have an id to print in error message
+				return
+			}
+		} else {
+			noext = strings.TrimSuffix(bp.PkgObj, ".a")
+			id = bp.ImportPath
 		}
-		noext = strings.TrimSuffix(bp.PkgObj, ".a")
-		id = bp.ImportPath
 
 	case build.IsLocalImport(path):
 		// "./x" -> "/this/directory/x.ext", "/this/directory/x"
@@ -68,6 +96,11 @@ func FindPkg(path, srcDir string) (filename, id string) {
 		}
 	}
 
+	if filename != "" {
+		if f, err := os.Stat(filename); err == nil && !f.IsDir() {
+			return
+		}
+	}
 	// try extensions
 	for _, ext := range pkgExts {
 		filename = noext + ext
diff --git a/src/cmd/compile/internal/importer/gcimporter_test.go b/src/cmd/compile/internal/importer/gcimporter_test.go
index 2fbd3f00d24a73897dd3f6a881d9f0829a97d3b3..ac502e6e37e8d6a8c5eeea6b53263d2fb95df2e7 100644
--- a/src/cmd/compile/internal/importer/gcimporter_test.go
+++ b/src/cmd/compile/internal/importer/gcimporter_test.go
@@ -13,6 +13,7 @@ import (
 	"internal/testenv"
 	"os"
 	"os/exec"
+	"path"
 	"path/filepath"
 	"runtime"
 	"strings"
@@ -37,14 +38,19 @@ func skipSpecialPlatforms(t *testing.T) {
 
 // compile runs the compiler on filename, with dirname as the working directory,
 // and writes the output file to outdirname.
-func compile(t *testing.T, dirname, filename, outdirname string) string {
+// compile gives the resulting package a packagepath of testdata/<filebasename>.
+func compile(t *testing.T, dirname, filename, outdirname string, packagefiles map[string]string) string {
 	// filename must end with ".go"
-	if !strings.HasSuffix(filename, ".go") {
+	basename, ok := strings.CutSuffix(filepath.Base(filename), ".go")
+	if !ok {
 		t.Fatalf("filename doesn't end in .go: %s", filename)
 	}
-	basename := filepath.Base(filename)
-	outname := filepath.Join(outdirname, basename[:len(basename)-2]+"o")
-	cmd := exec.Command(testenv.GoToolPath(t), "tool", "compile", "-p", strings.TrimSuffix(outname, ".o"), "-o", outname, filename)
+	objname := basename + ".o"
+	outname := filepath.Join(outdirname, objname)
+	importcfgfile := filepath.Join(outdirname, basename) + ".importcfg"
+	testenv.WriteImportcfg(t, importcfgfile, packagefiles)
+	pkgpath := path.Join("testdata", basename)
+	cmd := exec.Command(testenv.GoToolPath(t), "tool", "compile", "-p", pkgpath, "-D", "testdata", "-importcfg", importcfgfile, "-o", outname, filename)
 	cmd.Dir = dirname
 	out, err := cmd.CombinedOutput()
 	if err != nil {
@@ -129,7 +135,7 @@ func TestImportTestdata(t *testing.T) {
 		tmpdir := mktmpdir(t)
 		defer os.RemoveAll(tmpdir)
 
-		compile(t, "testdata", testfile, filepath.Join(tmpdir, "testdata"))
+		compile(t, "testdata", testfile, filepath.Join(tmpdir, "testdata"), nil)
 		path := "./testdata/" + strings.TrimSuffix(testfile, ".go")
 
 		if pkg := testPath(t, path, tmpdir); pkg != nil {
@@ -436,8 +442,8 @@ func TestIssue13566(t *testing.T) {
 	if err != nil {
 		t.Fatal(err)
 	}
-	compile(t, "testdata", "a.go", testoutdir)
-	compile(t, testoutdir, bpath, testoutdir)
+	compile(t, "testdata", "a.go", testoutdir, nil)
+	compile(t, testoutdir, bpath, testoutdir, map[string]string{"testdata/a": filepath.Join(testoutdir, "a.o")})
 
 	// import must succeed (test for issue at hand)
 	pkg := importPkg(t, "./testdata/b", tmpdir)
@@ -513,7 +519,7 @@ func TestIssue15517(t *testing.T) {
 	tmpdir := mktmpdir(t)
 	defer os.RemoveAll(tmpdir)
 
-	compile(t, "testdata", "p.go", filepath.Join(tmpdir, "testdata"))
+	compile(t, "testdata", "p.go", filepath.Join(tmpdir, "testdata"), nil)
 
 	// Multiple imports of p must succeed without redeclaration errors.
 	// We use an import path that's not cleaned up so that the eventual
@@ -618,7 +624,7 @@ func importPkg(t *testing.T, path, srcDir string) *types2.Package {
 func compileAndImportPkg(t *testing.T, name string) *types2.Package {
 	tmpdir := mktmpdir(t)
 	defer os.RemoveAll(tmpdir)
-	compile(t, "testdata", name+".go", filepath.Join(tmpdir, "testdata"))
+	compile(t, "testdata", name+".go", filepath.Join(tmpdir, "testdata"), nil)
 	return importPkg(t, "./testdata/"+name, tmpdir)
 }
 
diff --git a/src/cmd/dist/buildtool.go b/src/cmd/dist/buildtool.go
index e2699f7656bfa428caef027bed841cfe22d4193a..2a4490b201a9f7fb9cce56934ce260e72424843a 100644
--- a/src/cmd/dist/buildtool.go
+++ b/src/cmd/dist/buildtool.go
@@ -63,6 +63,7 @@ var bootstrapDirs = []string{
 	"internal/coverage",
 	"internal/buildcfg",
 	"internal/goexperiment",
+	"internal/goroot",
 	"internal/goversion",
 	"internal/pkgbits",
 	"internal/race",
diff --git a/src/cmd/internal/archive/archive_test.go b/src/cmd/internal/archive/archive_test.go
index cca65af8ed01c547a33083731e94f8ad8f9fc412..f5315856c15f22c74552515d7bdebf9b2f3873f8 100644
--- a/src/cmd/internal/archive/archive_test.go
+++ b/src/cmd/internal/archive/archive_test.go
@@ -113,11 +113,14 @@ func buildGoobj(t *testing.T) goobjPaths {
 			go1src := filepath.Join("testdata", "go1.go")
 			go2src := filepath.Join("testdata", "go2.go")
 
-			out, err := exec.Command(gotool, "tool", "compile", "-p=p", "-o", go1obj, go1src).CombinedOutput()
+			importcfgfile := filepath.Join(buildDir, "importcfg")
+			testenv.WriteImportcfg(t, importcfgfile, nil)
+
+			out, err := exec.Command(gotool, "tool", "compile", "-importcfg="+importcfgfile, "-p=p", "-o", go1obj, go1src).CombinedOutput()
 			if err != nil {
 				return fmt.Errorf("go tool compile -o %s %s: %v\n%s", go1obj, go1src, err, out)
 			}
-			out, err = exec.Command(gotool, "tool", "compile", "-p=p", "-o", go2obj, go2src).CombinedOutput()
+			out, err = exec.Command(gotool, "tool", "compile", "-importcfg="+importcfgfile, "-p=p", "-o", go2obj, go2src).CombinedOutput()
 			if err != nil {
 				return fmt.Errorf("go tool compile -o %s %s: %v\n%s", go2obj, go2src, err, out)
 			}
diff --git a/src/cmd/link/link_test.go b/src/cmd/link/link_test.go
index 35babe61fc0ec93084c9a8c7260517c0244ef426..ce065721649d30baa25bc8bbbb30064f54ce98c0 100644
--- a/src/cmd/link/link_test.go
+++ b/src/cmd/link/link_test.go
@@ -50,19 +50,22 @@ func main() {}
 
 	tmpdir := t.TempDir()
 
+	importcfgfile := filepath.Join(tmpdir, "importcfg")
+	testenv.WriteImportcfg(t, importcfgfile, nil)
+
 	err := os.WriteFile(filepath.Join(tmpdir, "main.go"), []byte(source), 0666)
 	if err != nil {
 		t.Fatalf("failed to write main.go: %v\n", err)
 	}
 
-	cmd := exec.Command(testenv.GoToolPath(t), "tool", "compile", "-p=main", "main.go")
+	cmd := exec.Command(testenv.GoToolPath(t), "tool", "compile", "-importcfg="+importcfgfile, "-p=main", "main.go")
 	cmd.Dir = tmpdir
 	out, err := cmd.CombinedOutput()
 	if err != nil {
 		t.Fatalf("failed to compile main.go: %v, output: %s\n", err, out)
 	}
 
-	cmd = exec.Command(testenv.GoToolPath(t), "tool", "link", "main.o")
+	cmd = exec.Command(testenv.GoToolPath(t), "tool", "link", "-importcfg="+importcfgfile, "main.o")
 	cmd.Dir = tmpdir
 	out, err = cmd.CombinedOutput()
 	if err != nil {
@@ -98,9 +101,12 @@ func TestIssue28429(t *testing.T) {
 		}
 	}
 
+	importcfgfile := filepath.Join(tmpdir, "importcfg")
+	testenv.WriteImportcfg(t, importcfgfile, nil)
+
 	// Compile a main package.
 	write("main.go", "package main; func main() {}")
-	runGo("tool", "compile", "-p=main", "main.go")
+	runGo("tool", "compile", "-importcfg="+importcfgfile, "-p=main", "main.go")
 	runGo("tool", "pack", "c", "main.a", "main.o")
 
 	// Add an extra section with a short, non-.o name.
@@ -110,7 +116,7 @@ func TestIssue28429(t *testing.T) {
 
 	// Verify that the linker does not attempt
 	// to compile the extra section.
-	runGo("tool", "link", "main.a")
+	runGo("tool", "link", "-importcfg="+importcfgfile, "main.a")
 }
 
 func TestUnresolved(t *testing.T) {
@@ -236,15 +242,18 @@ void foo() {
 	cc := strings.TrimSpace(runGo("env", "CC"))
 	cflags := strings.Fields(runGo("env", "GOGCCFLAGS"))
 
+	importcfgfile := filepath.Join(tmpdir, "importcfg")
+	testenv.WriteImportcfg(t, importcfgfile, nil)
+
 	// Compile, assemble and pack the Go and C code.
 	runGo("tool", "asm", "-p=main", "-gensymabis", "-o", "symabis", "x.s")
-	runGo("tool", "compile", "-symabis", "symabis", "-p=main", "-o", "x1.o", "main.go")
+	runGo("tool", "compile", "-importcfg="+importcfgfile, "-symabis", "symabis", "-p=main", "-o", "x1.o", "main.go")
 	runGo("tool", "asm", "-p=main", "-o", "x2.o", "x.s")
 	run(cc, append(cflags, "-c", "-o", "x3.o", "x.c")...)
 	runGo("tool", "pack", "c", "x.a", "x1.o", "x2.o", "x3.o")
 
 	// Now attempt to link using the internal linker.
-	cmd := exec.Command(testenv.GoToolPath(t), "tool", "link", "-linkmode=internal", "x.a")
+	cmd := exec.Command(testenv.GoToolPath(t), "tool", "link", "-importcfg="+importcfgfile, "-linkmode=internal", "x.a")
 	cmd.Dir = tmpdir
 	out, err := cmd.CombinedOutput()
 	if err == nil {
@@ -778,20 +787,25 @@ func TestIndexMismatch(t *testing.T) {
 	mObj := filepath.Join(tmpdir, "main.o")
 	exe := filepath.Join(tmpdir, "main.exe")
 
+	importcfgFile := filepath.Join(tmpdir, "stdlib.importcfg")
+	testenv.WriteImportcfg(t, importcfgFile, nil)
+	importcfgWithAFile := filepath.Join(tmpdir, "witha.importcfg")
+	testenv.WriteImportcfg(t, importcfgWithAFile, map[string]string{"a": aObj})
+
 	// Build a program with main package importing package a.
-	cmd := exec.Command(testenv.GoToolPath(t), "tool", "compile", "-p=a", "-o", aObj, aSrc)
+	cmd := exec.Command(testenv.GoToolPath(t), "tool", "compile", "-importcfg="+importcfgFile, "-p=a", "-o", aObj, aSrc)
 	t.Log(cmd)
 	out, err := cmd.CombinedOutput()
 	if err != nil {
 		t.Fatalf("compiling a.go failed: %v\n%s", err, out)
 	}
-	cmd = exec.Command(testenv.GoToolPath(t), "tool", "compile", "-p=main", "-I", tmpdir, "-o", mObj, mSrc)
+	cmd = exec.Command(testenv.GoToolPath(t), "tool", "compile", "-importcfg="+importcfgWithAFile, "-p=main", "-I", tmpdir, "-o", mObj, mSrc)
 	t.Log(cmd)
 	out, err = cmd.CombinedOutput()
 	if err != nil {
 		t.Fatalf("compiling main.go failed: %v\n%s", err, out)
 	}
-	cmd = exec.Command(testenv.GoToolPath(t), "tool", "link", "-L", tmpdir, "-o", exe, mObj)
+	cmd = exec.Command(testenv.GoToolPath(t), "tool", "link", "-importcfg="+importcfgWithAFile, "-L", tmpdir, "-o", exe, mObj)
 	t.Log(cmd)
 	out, err = cmd.CombinedOutput()
 	if err != nil {
@@ -800,13 +814,13 @@ func TestIndexMismatch(t *testing.T) {
 
 	// Now, overwrite a.o with the object of b.go. This should
 	// result in an index mismatch.
-	cmd = exec.Command(testenv.GoToolPath(t), "tool", "compile", "-p=a", "-o", aObj, bSrc)
+	cmd = exec.Command(testenv.GoToolPath(t), "tool", "compile", "-importcfg="+importcfgFile, "-p=a", "-o", aObj, bSrc)
 	t.Log(cmd)
 	out, err = cmd.CombinedOutput()
 	if err != nil {
 		t.Fatalf("compiling a.go failed: %v\n%s", err, out)
 	}
-	cmd = exec.Command(testenv.GoToolPath(t), "tool", "link", "-L", tmpdir, "-o", exe, mObj)
+	cmd = exec.Command(testenv.GoToolPath(t), "tool", "link", "-importcfg="+importcfgWithAFile, "-L", tmpdir, "-o", exe, mObj)
 	t.Log(cmd)
 	out, err = cmd.CombinedOutput()
 	if err == nil {
diff --git a/src/cmd/objdump/objdump_test.go b/src/cmd/objdump/objdump_test.go
index bbf942503a24131ba8cf91fea8399b293ad6ce37..fa6a1b9a68cd8c3cca417ff14f1635e9e1e7b7c7 100644
--- a/src/cmd/objdump/objdump_test.go
+++ b/src/cmd/objdump/objdump_test.go
@@ -297,8 +297,11 @@ func TestDisasmPIE(t *testing.T) {
 func TestDisasmGoobj(t *testing.T) {
 	mustHaveDisasm(t)
 
+	importcfgfile := filepath.Join(tmp, "hello.importcfg")
+	testenv.WriteImportcfg(t, importcfgfile, nil)
+
 	hello := filepath.Join(tmp, "hello.o")
-	args := []string{"tool", "compile", "-p=main", "-o", hello}
+	args := []string{"tool", "compile", "-p=main", "-importcfg=" + importcfgfile, "-o", hello}
 	args = append(args, "testdata/fmthello.go")
 	out, err := exec.Command(testenv.GoToolPath(t), args...).CombinedOutput()
 	if err != nil {
diff --git a/src/cmd/pack/pack_test.go b/src/cmd/pack/pack_test.go
index 146c27c00a401161d946083605ddbf027dd93fad..5f16abcb02eb7d89fa750aa223755f557472de65 100644
--- a/src/cmd/pack/pack_test.go
+++ b/src/cmd/pack/pack_test.go
@@ -177,11 +177,14 @@ func TestHello(t *testing.T) {
 		return doRun(t, dir, args...)
 	}
 
+	importcfgfile := filepath.Join(dir, "hello.importcfg")
+	testenv.WriteImportcfg(t, importcfgfile, nil)
+
 	goBin := testenv.GoToolPath(t)
 	run(goBin, "build", "cmd/pack") // writes pack binary to dir
-	run(goBin, "tool", "compile", "-p=main", "hello.go")
+	run(goBin, "tool", "compile", "-importcfg="+importcfgfile, "-p=main", "hello.go")
 	run("./pack", "grc", "hello.a", "hello.o")
-	run(goBin, "tool", "link", "-o", "a.out", "hello.a")
+	run(goBin, "tool", "link", "-importcfg="+importcfgfile, "-o", "a.out", "hello.a")
 	out := run("./a.out")
 	if out != "hello world\n" {
 		t.Fatalf("incorrect output: %q, want %q", out, "hello world\n")
@@ -244,12 +247,16 @@ func TestLargeDefs(t *testing.T) {
 		return doRun(t, dir, args...)
 	}
 
+	importcfgfile := filepath.Join(dir, "hello.importcfg")
+	testenv.WriteImportcfg(t, importcfgfile, nil)
+
 	goBin := testenv.GoToolPath(t)
 	run(goBin, "build", "cmd/pack") // writes pack binary to dir
-	run(goBin, "tool", "compile", "-p=large", "large.go")
+	run(goBin, "tool", "compile", "-importcfg="+importcfgfile, "-p=large", "large.go")
 	run("./pack", "grc", "large.a", "large.o")
-	run(goBin, "tool", "compile", "-p=main", "-I", ".", "main.go")
-	run(goBin, "tool", "link", "-L", ".", "-o", "a.out", "main.o")
+	testenv.WriteImportcfg(t, importcfgfile, map[string]string{"large": filepath.Join(dir, "large.o")})
+	run(goBin, "tool", "compile", "-importcfg="+importcfgfile, "-p=main", "main.go")
+	run(goBin, "tool", "link", "-importcfg="+importcfgfile, "-L", ".", "-o", "a.out", "main.o")
 	out := run("./a.out")
 	if out != "ok\n" {
 		t.Fatalf("incorrect output: %q, want %q", out, "ok\n")
diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go
index eed5c462be20a1c875f949459f577f78bdd7b646..25556ac04c6c55735c42aaa3f9c5b9ec930e6a59 100644
--- a/src/go/build/deps_test.go
+++ b/src/go/build/deps_test.go
@@ -535,7 +535,7 @@ var depsRules = `
 	internal/fuzz, internal/testlog, runtime/pprof, regexp
 	< testing/internal/testdeps;
 
-	OS, flag, testing, internal/cfg, internal/platform
+	OS, flag, testing, internal/cfg, internal/platform, internal/goroot
 	< internal/testenv;
 
 	OS, encoding/base64
diff --git a/src/go/importer/importer_test.go b/src/go/importer/importer_test.go
index 1b8353e8fa63af863a63ec8ea200f291c0c2f24e..3c391380383228599cb24ed80f5f9b44da116260 100644
--- a/src/go/importer/importer_test.go
+++ b/src/go/importer/importer_test.go
@@ -25,15 +25,12 @@ func TestForCompiler(t *testing.T) {
 	testenv.MustHaveGoBuild(t)
 
 	const thePackage = "math/big"
-	out, err := exec.Command(testenv.GoToolPath(t), "list", "-f={{context.Compiler}}:{{.Target}}", thePackage).CombinedOutput()
+	out, err := exec.Command(testenv.GoToolPath(t), "list", "-export", "-f={{context.Compiler}}:{{.Export}}", thePackage).CombinedOutput()
 	if err != nil {
 		t.Fatalf("go list %s: %v\n%s", thePackage, err, out)
 	}
-	target := strings.TrimSpace(string(out))
-	compiler, target, _ := strings.Cut(target, ":")
-	if !strings.HasSuffix(target, ".a") {
-		t.Fatalf("unexpected package %s target %q (not *.a)", thePackage, target)
-	}
+	export := strings.TrimSpace(string(out))
+	compiler, target, _ := strings.Cut(export, ":")
 
 	if compiler == "gccgo" {
 		t.Skip("golang.org/issue/22500")
diff --git a/src/go/internal/gcimporter/gcimporter.go b/src/go/internal/gcimporter/gcimporter.go
index 0b27a954041821d834e4f7082e85e44713d2ec00..0ec464056c0f7bd6eb05e91ab6071275b87b4f88 100644
--- a/src/go/internal/gcimporter/gcimporter.go
+++ b/src/go/internal/gcimporter/gcimporter.go
@@ -11,9 +11,11 @@ import (
 	"go/build"
 	"go/token"
 	"go/types"
+	"internal/goroot"
 	"internal/pkgbits"
 	"io"
 	"os"
+	"path"
 	"path/filepath"
 	"strings"
 )
@@ -21,7 +23,25 @@ import (
 // debugging/development support
 const debug = false
 
-var pkgExts = [...]string{".a", ".o"}
+func lookupGorootExport(pkgpath, srcRoot, srcDir string) (string, bool) {
+	pkgpath = filepath.ToSlash(pkgpath)
+	m, err := goroot.PkgfileMap()
+	if err != nil {
+		return "", false
+	}
+	if export, ok := m[pkgpath]; ok {
+		return export, true
+	}
+	vendorPrefix := "vendor"
+	if strings.HasPrefix(srcDir, filepath.Join(srcRoot, "cmd")) {
+		vendorPrefix = path.Join("cmd", vendorPrefix)
+	}
+	pkgpath = path.Join(vendorPrefix, pkgpath)
+	export, ok := m[pkgpath]
+	return export, ok
+}
+
+var pkgExts = [...]string{".a", ".o"} // a file from the build cache will have no extension
 
 // FindPkg returns the filename and unique package id for an import
 // path based on package information provided by build.Import (using
@@ -43,11 +63,18 @@ func FindPkg(path, srcDir string) (filename, id string) {
 		}
 		bp, _ := build.Import(path, srcDir, build.FindOnly|build.AllowBinary)
 		if bp.PkgObj == "" {
-			id = path // make sure we have an id to print in error message
-			return
+			var ok bool
+			if bp.Goroot {
+				filename, ok = lookupGorootExport(path, bp.SrcRoot, srcDir)
+			}
+			if !ok {
+				id = path // make sure we have an id to print in error message
+				return
+			}
+		} else {
+			noext = strings.TrimSuffix(bp.PkgObj, ".a")
+			id = bp.ImportPath
 		}
-		noext = strings.TrimSuffix(bp.PkgObj, ".a")
-		id = bp.ImportPath
 
 	case build.IsLocalImport(path):
 		// "./x" -> "/this/directory/x.ext", "/this/directory/x"
@@ -68,6 +95,11 @@ func FindPkg(path, srcDir string) (filename, id string) {
 		}
 	}
 
+	if filename != "" {
+		if f, err := os.Stat(filename); err == nil && !f.IsDir() {
+			return
+		}
+	}
 	// try extensions
 	for _, ext := range pkgExts {
 		filename = noext + ext
diff --git a/src/go/internal/gcimporter/gcimporter_test.go b/src/go/internal/gcimporter/gcimporter_test.go
index 275287d428a82acfac3f8457713edef4a9f37021..de6a791dc86fab48c42c08cbd10f84d36062c90d 100644
--- a/src/go/internal/gcimporter/gcimporter_test.go
+++ b/src/go/internal/gcimporter/gcimporter_test.go
@@ -11,6 +11,7 @@ import (
 	"internal/testenv"
 	"os"
 	"os/exec"
+	"path"
 	"path/filepath"
 	"runtime"
 	"strings"
@@ -44,14 +45,19 @@ func skipSpecialPlatforms(t *testing.T) {
 
 // compile runs the compiler on filename, with dirname as the working directory,
 // and writes the output file to outdirname.
-func compile(t *testing.T, dirname, filename, outdirname string) string {
+// compile gives the resulting package a packagepath of testdata/<filebasename>.
+func compile(t *testing.T, dirname, filename, outdirname string, packagefiles map[string]string) string {
 	// filename must end with ".go"
-	if !strings.HasSuffix(filename, ".go") {
+	basename, ok := strings.CutSuffix(filepath.Base(filename), ".go")
+	if !ok {
 		t.Fatalf("filename doesn't end in .go: %s", filename)
 	}
-	basename := filepath.Base(filename)
-	outname := filepath.Join(outdirname, basename[:len(basename)-2]+"o")
-	cmd := exec.Command(testenv.GoToolPath(t), "tool", "compile", "-p", strings.TrimSuffix(outname, ".o"), "-o", outname, filename)
+	objname := basename + ".o"
+	outname := filepath.Join(outdirname, objname)
+	importcfgfile := filepath.Join(outdirname, basename) + ".importcfg"
+	testenv.WriteImportcfg(t, importcfgfile, packagefiles)
+	pkgpath := path.Join("testdata", basename)
+	cmd := exec.Command(testenv.GoToolPath(t), "tool", "compile", "-p", pkgpath, "-D", "testdata", "-importcfg", importcfgfile, "-o", outname, filename)
 	cmd.Dir = dirname
 	out, err := cmd.CombinedOutput()
 	if err != nil {
@@ -139,7 +145,7 @@ func TestImportTestdata(t *testing.T) {
 		tmpdir := mktmpdir(t)
 		defer os.RemoveAll(tmpdir)
 
-		compile(t, "testdata", testfile, filepath.Join(tmpdir, "testdata"))
+		compile(t, "testdata", testfile, filepath.Join(tmpdir, "testdata"), nil)
 		path := "./testdata/" + strings.TrimSuffix(testfile, ".go")
 
 		if pkg := testPath(t, path, tmpdir); pkg != nil {
@@ -209,7 +215,7 @@ func TestImportTypeparamTests(t *testing.T) {
 
 			// Compile and import, and compare the resulting package with the package
 			// that was type-checked directly.
-			compile(t, rootDir, entry.Name(), filepath.Join(tmpdir, "testdata"))
+			compile(t, rootDir, entry.Name(), filepath.Join(tmpdir, "testdata"), nil)
 			pkgName := strings.TrimSuffix(entry.Name(), ".go")
 			imported := importPkg(t, "./testdata/"+pkgName, tmpdir)
 			checked := checkFile(t, filename, src)
@@ -564,8 +570,8 @@ func TestIssue13566(t *testing.T) {
 	if err != nil {
 		t.Fatal(err)
 	}
-	compile(t, "testdata", "a.go", testoutdir)
-	compile(t, testoutdir, bpath, testoutdir)
+	compile(t, "testdata", "a.go", testoutdir, nil)
+	compile(t, testoutdir, bpath, testoutdir, map[string]string{"testdata/a": filepath.Join(testoutdir, "a.o")})
 
 	// import must succeed (test for issue at hand)
 	pkg := importPkg(t, "./testdata/b", tmpdir)
@@ -596,7 +602,7 @@ func TestTypeNamingOrder(t *testing.T) {
 	defer os.RemoveAll(tmpdir)
 	testoutdir := filepath.Join(tmpdir, "testdata")
 
-	compile(t, "testdata", "g.go", testoutdir)
+	compile(t, "testdata", "g.go", testoutdir, nil)
 
 	// import must succeed (test for issue at hand)
 	_ = importPkg(t, "./testdata/g", tmpdir)
@@ -666,7 +672,7 @@ func TestIssue15517(t *testing.T) {
 	tmpdir := mktmpdir(t)
 	defer os.RemoveAll(tmpdir)
 
-	compile(t, "testdata", "p.go", filepath.Join(tmpdir, "testdata"))
+	compile(t, "testdata", "p.go", filepath.Join(tmpdir, "testdata"), nil)
 
 	// Multiple imports of p must succeed without redeclaration errors.
 	// We use an import path that's not cleaned up so that the eventual
@@ -773,7 +779,7 @@ func importPkg(t *testing.T, path, srcDir string) *types.Package {
 func compileAndImportPkg(t *testing.T, name string) *types.Package {
 	tmpdir := mktmpdir(t)
 	defer os.RemoveAll(tmpdir)
-	compile(t, "testdata", name+".go", filepath.Join(tmpdir, "testdata"))
+	compile(t, "testdata", name+".go", filepath.Join(tmpdir, "testdata"), nil)
 	return importPkg(t, "./testdata/"+name, tmpdir)
 }
 
diff --git a/src/internal/abi/abi_test.go b/src/internal/abi/abi_test.go
index 51d26f69aecae940313b34f900471849cb0f63dd..f0d8dceb3ec9c14b9970afc9389ccd800647d768 100644
--- a/src/internal/abi/abi_test.go
+++ b/src/internal/abi/abi_test.go
@@ -42,6 +42,9 @@ func TestFuncPCCompileError(t *testing.T) {
 	symabi := filepath.Join(tmpdir, "symabi")
 	obj := filepath.Join(tmpdir, "x.o")
 
+	importcfgfile := filepath.Join(tmpdir, "hello.importcfg")
+	testenv.WriteImportcfg(t, importcfgfile, nil)
+
 	// parse assembly code for symabi.
 	cmd := exec.Command(testenv.GoToolPath(t), "tool", "asm", "-gensymabis", "-o", symabi, asmSrc)
 	out, err := cmd.CombinedOutput()
@@ -50,7 +53,7 @@ func TestFuncPCCompileError(t *testing.T) {
 	}
 
 	// compile go code.
-	cmd = exec.Command(testenv.GoToolPath(t), "tool", "compile", "-p=p", "-symabis", symabi, "-o", obj, goSrc)
+	cmd = exec.Command(testenv.GoToolPath(t), "tool", "compile", "-importcfg="+importcfgfile, "-p=p", "-symabis", symabi, "-o", obj, goSrc)
 	out, err = cmd.CombinedOutput()
 	if err == nil {
 		t.Fatalf("go tool compile did not fail")
diff --git a/src/internal/goroot/gc.go b/src/internal/goroot/gc.go
index 5517598519c18ca1047a4b52b0305b2255cc80b9..79403d29fc02e55c30a929be3eee2478f02e6062 100644
--- a/src/internal/goroot/gc.go
+++ b/src/internal/goroot/gc.go
@@ -69,8 +69,8 @@ func (gd *gccgoDirs) init() {
 	const prefix = "libraries: ="
 	var dirs []string
 	for _, dirEntry := range dirsEntries {
-		if after, found := strings.CutPrefix(dirEntry, prefix); found {
-			dirs = filepath.SplitList(after)
+		if strings.HasPrefix(dirEntry, prefix) {
+			dirs = filepath.SplitList(strings.TrimPrefix(dirEntry, prefix))
 			break
 		}
 	}
diff --git a/src/internal/goroot/importcfg.go b/src/internal/goroot/importcfg.go
new file mode 100644
index 0000000000000000000000000000000000000000..51d0d77604fe9f1017ca89bcbd655ae1564de59c
--- /dev/null
+++ b/src/internal/goroot/importcfg.go
@@ -0,0 +1,66 @@
+// Copyright 2022 The Go 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 goroot
+
+import (
+	"bytes"
+	"fmt"
+	"os/exec"
+	"strings"
+	"sync"
+)
+
+// Importcfg returns an importcfg file to be passed to the
+// Go compiler that contains the cached paths for the .a files for the
+// standard library.
+func Importcfg() (string, error) {
+	var icfg bytes.Buffer
+
+	m, err := PkgfileMap()
+	if err != nil {
+		return "", err
+	}
+	fmt.Fprintf(&icfg, "# import config")
+	for importPath, export := range m {
+		if importPath != "unsafe" && export != "" { // unsafe
+			fmt.Fprintf(&icfg, "\npackagefile %s=%s", importPath, export)
+		}
+	}
+	s := icfg.String()
+	return s, nil
+}
+
+var (
+	stdlibPkgfileMap map[string]string
+	stdlibPkgfileErr error
+	once             sync.Once
+)
+
+// PkgfileMap returns a map of package paths to the location on disk
+// of the .a file for the package.
+// The caller must not modify the map.
+func PkgfileMap() (map[string]string, error) {
+	once.Do(func() {
+		m := make(map[string]string)
+		output, err := exec.Command("go", "list", "-export", "-e", "-f", "{{.ImportPath}} {{.Export}}", "std", "cmd").Output()
+		if err != nil {
+			stdlibPkgfileErr = err
+		}
+		for _, line := range strings.Split(string(output), "\n") {
+			if line == "" {
+				continue
+			}
+			sp := strings.SplitN(line, " ", 2)
+			if len(sp) != 2 {
+				err = fmt.Errorf("determining pkgfile map: invalid line in go list output: %q", line)
+				return
+			}
+			importPath, export := sp[0], sp[1]
+			m[importPath] = export
+		}
+		stdlibPkgfileMap = m
+	})
+	return stdlibPkgfileMap, stdlibPkgfileErr
+}
diff --git a/src/internal/testenv/testenv.go b/src/internal/testenv/testenv.go
index fe34a92d9c9e6c44b7f58015cedef5ec0785875e..ae8413efb6ad46b5f7c88a4dfa3970f30a79d7fe 100644
--- a/src/internal/testenv/testenv.go
+++ b/src/internal/testenv/testenv.go
@@ -16,6 +16,7 @@ import (
 	"flag"
 	"fmt"
 	"internal/cfg"
+	"internal/goroot"
 	"internal/platform"
 	"os"
 	"os/exec"
@@ -461,3 +462,20 @@ func RunWithTimeout(t testing.TB, cmd *exec.Cmd) ([]byte, error) {
 
 	return b.Bytes(), err
 }
+
+// WriteImportcfg writes an importcfg file used by the compiler or linker to
+// dstPath containing entries for the packages in std and cmd in addition
+// to the package to package file mappings in additionalPackageFiles.
+func WriteImportcfg(t testing.TB, dstPath string, additionalPackageFiles map[string]string) {
+	importcfg, err := goroot.Importcfg()
+	for k, v := range additionalPackageFiles {
+		importcfg += fmt.Sprintf("\npackagefile %s=%s", k, v)
+	}
+	if err != nil {
+		t.Fatalf("preparing the importcfg failed: %s", err)
+	}
+	os.WriteFile(dstPath, []byte(importcfg), 0655)
+	if err != nil {
+		t.Fatalf("writing the importcfg failed: %s", err)
+	}
+}
diff --git a/src/internal/types/errors/codes_test.go b/src/internal/types/errors/codes_test.go
index 6f671a94c6edc986ae4757faf3d0bf8b20399539..2490ade5c369754bb5a879f8cb21de186027d65c 100644
--- a/src/internal/types/errors/codes_test.go
+++ b/src/internal/types/errors/codes_test.go
@@ -11,6 +11,7 @@ import (
 	"go/importer"
 	"go/parser"
 	"go/token"
+	"internal/testenv"
 	"reflect"
 	"strings"
 	"testing"
@@ -19,6 +20,8 @@ import (
 )
 
 func TestErrorCodeExamples(t *testing.T) {
+	testenv.MustHaveGoBuild(t) // go command needed to resolve std .a files for importer.Default().
+
 	walkCodes(t, func(name string, value int, spec *ast.ValueSpec) {
 		t.Run(name, func(t *testing.T) {
 			doc := spec.Doc.Text()
diff --git a/src/runtime/align_test.go b/src/runtime/align_test.go
index d3bdf007dccf1e18b7cced5cb3f8ef311238f3c4..5f225d63c4c5a9ab5eb14967122a9adfd5d26029 100644
--- a/src/runtime/align_test.go
+++ b/src/runtime/align_test.go
@@ -12,6 +12,7 @@ import (
 	"go/printer"
 	"go/token"
 	"go/types"
+	"internal/testenv"
 	"os"
 	"regexp"
 	"runtime"
@@ -22,6 +23,8 @@ import (
 // Check that 64-bit fields on which we apply atomic operations
 // are aligned to 8 bytes. This can be a problem on 32-bit systems.
 func TestAtomicAlignment(t *testing.T) {
+	testenv.MustHaveGoBuild(t) // go command needed to resolve std .a files for importer.Default().
+
 	// Read the code making the tables above, to see which fields and
 	// variables we are currently checking.
 	checked := map[string]bool{}