golang/go · error

package using cgo has Go assembly file %s

Error message

package using cgo has Go assembly file %s

What it means

For cgo packages, the gas function compiles .s assembly files with gcc (the C assembler). Before doing so it scans each file's bytes for Go-plan9-assembler directives TEXT, DATA, or GLOBL (at the start or after a newline). If any are present, the build aborts because a cgo package cannot mix Go-style assembly with C-style assembly; the flagged file must use GAS syntax instead.

Source

Thrown at src/cmd/go/internal/work/exec.go:2546

func (noToolchain) cc(b *Builder, a *Action, ofile, cfile string) error {
	return noCompiler()
}

// gcc runs the gcc C compiler to create an object from a single C file.
func (b *Builder) gcc(a *Action, workdir, out string, flags []string, cfile string) error {
	p := a.Package
	return b.ccompile(a, out, flags, cfile, b.GccCmd(p.Dir, workdir))
}

// gas runs the gcc c compiler to create an object file from a single C assembly file.
func (b *Builder) gas(a *Action, workdir, out string, flags []string, sfile string) error {
	p := a.Package
	data, err := os.ReadFile(sfile)
	if err == nil {
		if bytes.HasPrefix(data, []byte("TEXT")) || bytes.Contains(data, []byte("\nTEXT")) ||
			bytes.HasPrefix(data, []byte("DATA")) || bytes.Contains(data, []byte("\nDATA")) ||
			bytes.HasPrefix(data, []byte("GLOBL")) || bytes.Contains(data, []byte("\nGLOBL")) {
			return fmt.Errorf("package using cgo has Go assembly file %s", sfile)
		}
	}
	return b.ccompile(a, out, flags, sfile, b.GccCmd(p.Dir, workdir))
}

// gxx runs the g++ C++ compiler to create an object from a single C++ file.
func (b *Builder) gxx(a *Action, workdir, out string, flags []string, cxxfile string) error {
	p := a.Package
	return b.ccompile(a, out, flags, cxxfile, b.GxxCmd(p.Dir, workdir))
}

// gfortran runs the gfortran Fortran compiler to create an object from a single Fortran file.
func (b *Builder) gfortran(a *Action, workdir, out string, flags []string, ffile string) error {
	p := a.Package
	return b.ccompile(a, out, flags, ffile, b.gfortranCmd(p.Dir, workdir))
}

// ccompile runs the given C or C++ compiler and creates an object from a single source file.

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Open the flagged .s file and confirm it uses Go-assembler directives (TEXT/DATA/GLOBL)
  2. Rewrite the file in standard GAS (C) assembly syntax, or remove it
  3. Move the Go assembly into a separate non-cgo package that builds with the gc assembler

Example fix

// before (Go asm in a cgo package .s file)
TEXT ·myFunc(SB), $0
    RET
// after (GAS syntax, or delete and implement in Go)
myfunc:
    ret
Defensive patterns

Strategy: validation

Validate before calling

// Scan .s files for Go-assembler directives before a cgo build
func hasGoAsmDirectives(path string) bool {
    data, err := os.ReadFile(path)
    if err != nil { return false }
    for _, d := range []string{"TEXT", "DATA", "GLOBL"} {
        if bytes.HasPrefix(data, []byte(d)) || bytes.Contains(data, []byte("\n"+d)) {
            return true
        }
    }
    return false
}

Prevention

When it happens

Trigger: Fires in gas when bytes.HasPrefix or bytes.Contains matches TEXT, DATA, or GLOBL in an assembly file of a package that uses cgo.

Common situations: Copying a Go assembly file (from a non-cgo package) into a cgo package, or writing Go-assembler syntax in a .s file that is compiled through the cgo/gcc path.

Related errors


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