Skip to content

Commit edf5b64

Browse files
evanjfmeum
andauthored
compilepkg: cgo assembly uses the C compiler (#3648)
* compilepkg: cgo assembly uses the C compiler This changes compilepkg to use the C compiler for .S and .s files to use the C compiler, like go build does. Previously it would use the Go assembler, which is used for pure Go packages. This should help fix issue: #3411 I have added a cgo test for this issue that is intended to work with both arm64 and amd64 machines. I have only tested it on Linux amd64 and Darwin arm64. Without this change it fails to build with the following output. This fails to parse the assembly file because it uses the Go assembler. ERROR: rules_go/tests/core/cgo/asm/BUILD.bazel:3:11: GoCompilePkg tests/core/cgo/asm/asm.a failed: (Exit 1): builder failed: error executing command (from target //tests/core/cgo/asm:asm) bazel-out/k8-opt-exec-2B5CBBC6/bin/external/go_sdk/builder_reset/builder compilepkg -sdk external/go_sdk -installsuffix linux_amd64 -src tests/core/cgo/asm/cgoasm.go -src tests/core/cgo/asm/asm_amd64.S ... tests/core/cgo/asm/asm_amd64.S:4: expected identifier, found "." asm: assembly of tests/core/cgo/asm/asm_amd64.S failed compilepkg: error running subcommand external/go_sdk/pkg/tool/linux_amd64/asm: exit status 1 * add build constraint: unix && (amd64 || arm64) * run buildifier; make asm conditional * assembly fixes for Mac OS X and Linux * Change build constraint to (amd64 || arm64): Should work on Windows The tests were failing on Windows because rules_go incorrectly believed this was a "native" Go package. I think this should work on Windows. --------- Co-authored-by: Fabian Meumertzheim <[email protected]>
1 parent 6e10f8c commit edf5b64

File tree

6 files changed

+112
-16
lines changed

6 files changed

+112
-16
lines changed

go/tools/builders/compilepkg.go

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,7 @@ func compileArchive(
273273
hSrcs[i] = src.filename
274274
}
275275
haveCgo := len(cgoSrcs)+len(cSrcs)+len(cxxSrcs)+len(objcSrcs)+len(objcxxSrcs) > 0
276+
packageUsesCgo := cgoEnabled && haveCgo
276277

277278
// Instrument source files for coverage.
278279
if coverMode != "" {
@@ -329,12 +330,11 @@ func compileArchive(
329330
// If we have cgo, generate separate C and go files, and compile the
330331
// C files.
331332
var objFiles []string
332-
if cgoEnabled && haveCgo {
333-
// TODO(#2006): Compile .s and .S files with cgo2, not the Go assembler.
334-
// If cgo is not enabled or we don't have other cgo sources, don't
335-
// compile .S files.
333+
if packageUsesCgo {
334+
// If the package uses Cgo, compile .s and .S files with cgo2, not the Go assembler.
335+
// Otherwise: the .s/.S files will be compiled with the Go assembler later
336336
var srcDir string
337-
srcDir, goSrcs, objFiles, err = cgo2(goenv, goSrcs, cgoSrcs, cSrcs, cxxSrcs, objcSrcs, objcxxSrcs, nil, hSrcs, packagePath, packageName, cc, cppFlags, cFlags, cxxFlags, objcFlags, objcxxFlags, ldFlags, cgoExportHPath)
337+
srcDir, goSrcs, objFiles, err = cgo2(goenv, goSrcs, cgoSrcs, cSrcs, cxxSrcs, objcSrcs, objcxxSrcs, sSrcs, hSrcs, packagePath, packageName, cc, cppFlags, cFlags, cxxFlags, objcFlags, objcxxFlags, ldFlags, cgoExportHPath)
338338
if err != nil {
339339
return err
340340
}
@@ -355,7 +355,7 @@ func compileArchive(
355355
if err != nil {
356356
return err
357357
}
358-
if cgoEnabled && len(cgoSrcs) != 0 {
358+
if packageUsesCgo {
359359
// cgo generated code imports some extra packages.
360360
imports["runtime/cgo"] = nil
361361
imports["syscall"] = nil
@@ -458,28 +458,32 @@ func compileArchive(
458458
}()
459459
}
460460

461-
// If there are assembly files, and this is go1.12+, generate symbol ABIs.
461+
// If there are Go assembly files and this is go1.12+: generate symbol ABIs.
462+
// This excludes Cgo packages: they use the C compiler for assembly.
462463
asmHdrPath := ""
463464
if len(srcs.sSrcs) > 0 {
464465
asmHdrPath = filepath.Join(workDir, "go_asm.h")
465466
}
466-
symabisPath, err := buildSymabisFile(goenv, srcs.sSrcs, srcs.hSrcs, asmHdrPath)
467-
if symabisPath != "" {
468-
if !goenv.shouldPreserveWorkDir {
469-
defer os.Remove(symabisPath)
467+
var symabisPath string
468+
if !packageUsesCgo {
469+
symabisPath, err = buildSymabisFile(goenv, srcs.sSrcs, srcs.hSrcs, asmHdrPath)
470+
if symabisPath != "" {
471+
if !goenv.shouldPreserveWorkDir {
472+
defer os.Remove(symabisPath)
473+
}
474+
}
475+
if err != nil {
476+
return err
470477
}
471-
}
472-
if err != nil {
473-
return err
474478
}
475479

476480
// Compile the filtered .go files.
477481
if err := compileGo(goenv, goSrcs, packagePath, importcfgPath, embedcfgPath, asmHdrPath, symabisPath, gcFlags, pgoprofile, outPath); err != nil {
478482
return err
479483
}
480484

481-
// Compile the .s files.
482-
if len(srcs.sSrcs) > 0 {
485+
// Compile the .s files if we are not a cgo package; cgo is assembled by cc above
486+
if len(srcs.sSrcs) > 0 && !packageUsesCgo {
483487
includeSet := map[string]struct{}{
484488
filepath.Join(os.Getenv("GOROOT"), "pkg", "include"): {},
485489
workDir: {},

tests/core/cgo/asm/BUILD.bazel

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
2+
3+
go_library(
4+
name = "asm",
5+
srcs = [
6+
"asm_amd64.S",
7+
"asm_arm64.S",
8+
"cgoasm.go",
9+
],
10+
cgo = True,
11+
importpath = "github.com/bazelbuild/rules_go/tests/core/cgo/asm",
12+
)
13+
14+
go_test(
15+
name = "asm_test",
16+
srcs = [
17+
"cgoasm_test.go",
18+
],
19+
embed = [":asm"],
20+
)

tests/core/cgo/asm/asm_amd64.S

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/*
2+
https://stackoverflow.com/questions/73435637/how-can-i-fix-usr-bin-ld-warning-trap-o-missing-note-gnu-stack-section-imp
3+
*/
4+
#if defined(__ELF__) && defined(__GNUC__)
5+
.section .note.GNU-stack,"",@progbits
6+
#endif
7+
8+
/*
9+
define this symbol both with and without underscore.
10+
It seems like Mac OS X wants the underscore, but Linux does not.
11+
*/
12+
.global example_asm_func
13+
.global _example_asm_func
14+
.text
15+
example_asm_func:
16+
_example_asm_func:
17+
mov $42, %rax
18+
ret
19+
20+
#if NOT_DEFINED
21+
#error "should not fail"
22+
#endif

tests/core/cgo/asm/asm_arm64.S

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/*
2+
define this symbol both with and without underscore.
3+
It seems like Mac OS X wants the underscore, but Linux does not.
4+
*/
5+
.global example_asm_func
6+
.global _example_asm_func
7+
.p2align 2 /* ld: warning: arm64 function not 4-byte aligned */
8+
example_asm_func:
9+
_example_asm_func:
10+
mov x0, #44
11+
ret
12+
13+
#if NOT_DEFINED
14+
#error "should not fail"
15+
#endif

tests/core/cgo/asm/cgoasm.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
//go:build amd64 || arm64
2+
3+
package asm
4+
5+
/*
6+
extern int example_asm_func();
7+
*/
8+
import "C"
9+
10+
func callAssembly() int {
11+
return int(C.example_asm_func())
12+
}

tests/core/cgo/asm/cgoasm_test.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//go:build amd64 || arm64
2+
3+
package asm
4+
5+
import (
6+
"runtime"
7+
"testing"
8+
)
9+
10+
func TestNativeAssembly(t *testing.T) {
11+
expectedGOARCH := map[string]int{
12+
"amd64": 42,
13+
"arm64": 44,
14+
}
15+
expected := expectedGOARCH[runtime.GOARCH]
16+
if expected == 0 {
17+
t.Fatalf("expected=0 for GOARCH=%s; missing value?", runtime.GOARCH)
18+
}
19+
actual := callAssembly()
20+
if actual != expected {
21+
t.Errorf("callAssembly()=%d; expected=%d", actual, expected)
22+
}
23+
}

0 commit comments

Comments
 (0)