golang/go · error

%s: missing .go_export section

Error message

%s: missing .go_export section

What it means

After elf.Open succeeds on a gccgo shared library, the code looks for the .go_export section, which gccgo writes to record embedded package metadata. If the section is nil, the file is ELF but not a gccgo-produced shared library, and readpkglist aborts via base.Fatal.

Source

Thrown at src/cmd/go/internal/work/action.go:409

	b.objdirSeq++
	return str.WithFilePathSeparator(filepath.Join(b.WorkDir, fmt.Sprintf("b%03d", b.objdirSeq)))
}

// readpkglist returns the list of packages that were built into the shared library
// at shlibpath. For the native toolchain this list is stored, newline separated, in
// an ELF note with name "Go\x00\x00" and type 1. For GCCGO it is extracted from the
// .go_export section.
func readpkglist(s *modload.Loader, shlibpath string) (pkgs []*load.Package) {
	var stk load.ImportStack
	if cfg.BuildToolchainName == "gccgo" {
		f, err := elf.Open(shlibpath)
		if err != nil {
			base.Fatal(fmt.Errorf("failed to open shared library: %v", err))
		}
		defer f.Close()
		sect := f.Section(".go_export")
		if sect == nil {
			base.Fatal(fmt.Errorf("%s: missing .go_export section", shlibpath))
		}
		data, err := sect.Data()
		if err != nil {
			base.Fatal(fmt.Errorf("%s: failed to read .go_export section: %v", shlibpath, err))
		}
		pkgpath := []byte("pkgpath ")
		for _, line := range bytes.Split(data, []byte{'\n'}) {
			if path, found := bytes.CutPrefix(line, pkgpath); found {
				path = bytes.TrimSuffix(path, []byte{';'})
				pkgs = append(pkgs, load.LoadPackageWithFlags(s, string(path), base.Cwd(), &stk, nil, 0))
			}
		}
	} else {
		pkglistbytes, err := buildid.ReadELFNote(shlibpath, "Go\x00\x00", 1)
		if err != nil {
			base.Fatalf("readELFNote failed: %v", err)
		}
		scanner := bufio.NewScanner(bytes.NewBuffer(pkglistbytes))

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Run 'go clean -cache' to remove cross-toolchain artifacts.
  2. Rebuild all shared libraries with the same gccgo toolchain you're building with now.
  3. Confirm with 'readelf -S <path>' whether .go_export is present.
  4. Avoid mixing -buildmode=shared outputs between gc and gccgo in the same GOCACHE.

Example fix

// before: cache has gc-produced .so but build is gccgo
$ go build -compiler=gccgo -buildmode=shared -linkshared ./...
// error: libstd.so: missing .go_export section

// after
$ go clean -cache
$ go build -compiler=gccgo -buildmode=shared std
$ go build -compiler=gccgo -linkshared ./...
Defensive patterns

Strategy: validation

Validate before calling

// Confirm an ELF is gccgo-produced by checking for .go_export.
func isGccgoShlib(path string) bool {
    f, err := elf.Open(path)
    if err != nil { return false }
    defer f.Close()
    return f.Section(".go_export") != nil
}

Prevention

When it happens

Trigger: A non-gccgo ELF shared library (e.g. one produced by the gc compiler's -buildmode=shared, or a plain C .so) is referenced where a gccgo .so is expected. Cache corruption mixing toolchains can also do this.

Common situations: Switching between gc and gccgo without 'go clean -cache'; pointing -pkgdir at a tree built by the other compiler; a hand-written makefile that mixes toolchains.

Related errors


AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12). Data as JSON: /api/errors/a1f6cff7bc841a47. Report an issue: GitHub.