aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCherry Mui <cherryyz@google.com>2023-10-06 20:53:27 -0400
committerCherry Mui <cherryyz@google.com>2023-10-30 20:36:26 +0000
commit7b04d81cbc2e45172c17e62943a777286a3341be (patch)
tree54de14373fcd4074b45ce84caa62c1587815c922
parentf9a31cda3c8a92e81989af4167c9ae5bfbb8ea5e (diff)
downloadgo-7b04d81cbc2e45172c17e62943a777286a3341be.tar.gz
go-7b04d81cbc2e45172c17e62943a777286a3341be.zip
[release-branch.go1.21] runtime/cgo: avoid taking the address of crosscall2 in code
Currently, set_crosscall2 takes the address of crosscall2 without using the GOT, which, on some architectures, results in a PC-relative relocation (e.g. R_AARCH64_ADR_PREL_PG_HI21 on ARM64) to the crosscall2 symbol. But crosscall2 is dynamically exported, so the C linker thinks it may bind to a symbol from a different DSO. Some C linker may not like a PC-relative relocation to such a symbol. Using a local trampoline to avoid taking the address of a dynamically exported symbol. It may be possible to not dynamically export crosscall2. But this CL is safer for backport. Later we may remove the trampolines after unexport crosscall2, if they are not needed. Fixes #63509. Updates #62556. Change-Id: Id28457f65ef121d3f87d8189803abc65ed453283 Reviewed-on: https://go-review.googlesource.com/c/go/+/533535 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Ian Lance Taylor <iant@google.com> (cherry picked from commit 872d7181f4084461441787c70ffd1354314987af) Reviewed-on: https://go-review.googlesource.com/c/go/+/534915 Reviewed-by: David Chase <drchase@google.com>
-rw-r--r--src/cmd/cgo/internal/testcarchive/carchive_test.go32
-rw-r--r--src/runtime/cgo/asm_386.s7
-rw-r--r--src/runtime/cgo/asm_amd64.s7
-rw-r--r--src/runtime/cgo/asm_arm.s7
-rw-r--r--src/runtime/cgo/asm_arm64.s7
-rw-r--r--src/runtime/cgo/asm_loong64.s7
-rw-r--r--src/runtime/cgo/asm_mips64x.s7
-rw-r--r--src/runtime/cgo/asm_mipsx.s7
-rw-r--r--src/runtime/cgo/asm_ppc64x.s7
-rw-r--r--src/runtime/cgo/asm_riscv64.s7
-rw-r--r--src/runtime/cgo/asm_s390x.s7
11 files changed, 92 insertions, 10 deletions
diff --git a/src/cmd/cgo/internal/testcarchive/carchive_test.go b/src/cmd/cgo/internal/testcarchive/carchive_test.go
index cc810f9d3e..b140a9c613 100644
--- a/src/cmd/cgo/internal/testcarchive/carchive_test.go
+++ b/src/cmd/cgo/internal/testcarchive/carchive_test.go
@@ -1365,3 +1365,35 @@ func TestDeepStack(t *testing.T) {
t.Error(err)
}
}
+
+func TestSharedObject(t *testing.T) {
+ // Test that we can put a Go c-archive into a C shared object.
+ globalSkip(t)
+ testenv.MustHaveGoBuild(t)
+ testenv.MustHaveCGO(t)
+ testenv.MustHaveBuildMode(t, "c-archive")
+
+ t.Parallel()
+
+ if !testWork {
+ defer func() {
+ os.Remove("libgo_s.a")
+ os.Remove("libgo_s.h")
+ os.Remove("libgo_s.so")
+ }()
+ }
+
+ cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo_s.a", "./libgo")
+ out, err := cmd.CombinedOutput()
+ t.Logf("%v\n%s", cmd.Args, out)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ ccArgs := append(cc, "-shared", "-o", "libgo_s.so", "libgo_s.a")
+ out, err = exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput()
+ t.Logf("%v\n%s", ccArgs, out)
+ if err != nil {
+ t.Fatal(err)
+ }
+}
diff --git a/src/runtime/cgo/asm_386.s b/src/runtime/cgo/asm_386.s
index 086e20b02f..f9a662aa88 100644
--- a/src/runtime/cgo/asm_386.s
+++ b/src/runtime/cgo/asm_386.s
@@ -6,12 +6,17 @@
// Set the x_crosscall2_ptr C function pointer variable point to crosscall2.
// It's such a pointer chain: _crosscall2_ptr -> x_crosscall2_ptr -> crosscall2
+// Use a local trampoline, to avoid taking the address of a dynamically exported
+// function.
TEXT ·set_crosscall2(SB),NOSPLIT,$0-0
MOVL _crosscall2_ptr(SB), AX
- MOVL $crosscall2(SB), BX
+ MOVL $crosscall2_trampoline<>(SB), BX
MOVL BX, (AX)
RET
+TEXT crosscall2_trampoline<>(SB),NOSPLIT,$0-0
+ JMP crosscall2(SB)
+
// Called by C code generated by cmd/cgo.
// func crosscall2(fn, a unsafe.Pointer, n int32, ctxt uintptr)
// Saves C callee-saved registers and calls cgocallback with three arguments.
diff --git a/src/runtime/cgo/asm_amd64.s b/src/runtime/cgo/asm_amd64.s
index f254622f23..e319094a45 100644
--- a/src/runtime/cgo/asm_amd64.s
+++ b/src/runtime/cgo/asm_amd64.s
@@ -7,12 +7,17 @@
// Set the x_crosscall2_ptr C function pointer variable point to crosscall2.
// It's such a pointer chain: _crosscall2_ptr -> x_crosscall2_ptr -> crosscall2
+// Use a local trampoline, to avoid taking the address of a dynamically exported
+// function.
TEXT ·set_crosscall2(SB),NOSPLIT,$0-0
MOVQ _crosscall2_ptr(SB), AX
- MOVQ $crosscall2(SB), BX
+ MOVQ $crosscall2_trampoline<>(SB), BX
MOVQ BX, (AX)
RET
+TEXT crosscall2_trampoline<>(SB),NOSPLIT,$0-0
+ JMP crosscall2(SB)
+
// Called by C code generated by cmd/cgo.
// func crosscall2(fn, a unsafe.Pointer, n int32, ctxt uintptr)
// Saves C callee-saved registers and calls cgocallback with three arguments.
diff --git a/src/runtime/cgo/asm_arm.s b/src/runtime/cgo/asm_arm.s
index f7f99772a6..095e9c06c9 100644
--- a/src/runtime/cgo/asm_arm.s
+++ b/src/runtime/cgo/asm_arm.s
@@ -6,12 +6,17 @@
// Set the x_crosscall2_ptr C function pointer variable point to crosscall2.
// It's such a pointer chain: _crosscall2_ptr -> x_crosscall2_ptr -> crosscall2
+// Use a local trampoline, to avoid taking the address of a dynamically exported
+// function.
TEXT ·set_crosscall2(SB),NOSPLIT,$0-0
MOVW _crosscall2_ptr(SB), R1
- MOVW $crosscall2(SB), R2
+ MOVW $crosscall2_trampoline<>(SB), R2
MOVW R2, (R1)
RET
+TEXT crosscall2_trampoline<>(SB),NOSPLIT,$0-0
+ JMP crosscall2(SB)
+
// Called by C code generated by cmd/cgo.
// func crosscall2(fn, a unsafe.Pointer, n int32, ctxt uintptr)
// Saves C callee-saved registers and calls cgocallback with three arguments.
diff --git a/src/runtime/cgo/asm_arm64.s b/src/runtime/cgo/asm_arm64.s
index ce8909b492..5492dc142c 100644
--- a/src/runtime/cgo/asm_arm64.s
+++ b/src/runtime/cgo/asm_arm64.s
@@ -7,12 +7,17 @@
// Set the x_crosscall2_ptr C function pointer variable point to crosscall2.
// It's such a pointer chain: _crosscall2_ptr -> x_crosscall2_ptr -> crosscall2
+// Use a local trampoline, to avoid taking the address of a dynamically exported
+// function.
TEXT ·set_crosscall2(SB),NOSPLIT,$0-0
MOVD _crosscall2_ptr(SB), R1
- MOVD $crosscall2(SB), R2
+ MOVD $crosscall2_trampoline<>(SB), R2
MOVD R2, (R1)
RET
+TEXT crosscall2_trampoline<>(SB),NOSPLIT,$0-0
+ JMP crosscall2(SB)
+
// Called by C code generated by cmd/cgo.
// func crosscall2(fn, a unsafe.Pointer, n int32, ctxt uintptr)
// Saves C callee-saved registers and calls cgocallback with three arguments.
diff --git a/src/runtime/cgo/asm_loong64.s b/src/runtime/cgo/asm_loong64.s
index 3b514ffc4a..19c8d74334 100644
--- a/src/runtime/cgo/asm_loong64.s
+++ b/src/runtime/cgo/asm_loong64.s
@@ -7,12 +7,17 @@
// Set the x_crosscall2_ptr C function pointer variable point to crosscall2.
// It's such a pointer chain: _crosscall2_ptr -> x_crosscall2_ptr -> crosscall2
+// Use a local trampoline, to avoid taking the address of a dynamically exported
+// function.
TEXT ·set_crosscall2(SB),NOSPLIT,$0-0
MOVV _crosscall2_ptr(SB), R5
- MOVV $crosscall2(SB), R6
+ MOVV $crosscall2_trampoline<>(SB), R6
MOVV R6, (R5)
RET
+TEXT crosscall2_trampoline<>(SB),NOSPLIT,$0-0
+ JMP crosscall2(SB)
+
// Called by C code generated by cmd/cgo.
// func crosscall2(fn, a unsafe.Pointer, n int32, ctxt uintptr)
// Saves C callee-saved registers and calls cgocallback with three arguments.
diff --git a/src/runtime/cgo/asm_mips64x.s b/src/runtime/cgo/asm_mips64x.s
index 0a8fbbbef0..af817d5ea6 100644
--- a/src/runtime/cgo/asm_mips64x.s
+++ b/src/runtime/cgo/asm_mips64x.s
@@ -8,12 +8,17 @@
// Set the x_crosscall2_ptr C function pointer variable point to crosscall2.
// It's such a pointer chain: _crosscall2_ptr -> x_crosscall2_ptr -> crosscall2
+// Use a local trampoline, to avoid taking the address of a dynamically exported
+// function.
TEXT ·set_crosscall2(SB),NOSPLIT,$0-0
MOVV _crosscall2_ptr(SB), R5
- MOVV $crosscall2(SB), R6
+ MOVV $crosscall2_trampoline<>(SB), R6
MOVV R6, (R5)
RET
+TEXT crosscall2_trampoline<>(SB),NOSPLIT,$0-0
+ JMP crosscall2(SB)
+
// Called by C code generated by cmd/cgo.
// func crosscall2(fn, a unsafe.Pointer, n int32, ctxt uintptr)
// Saves C callee-saved registers and calls cgocallback with three arguments.
diff --git a/src/runtime/cgo/asm_mipsx.s b/src/runtime/cgo/asm_mipsx.s
index a57ae97d7e..198c59a33e 100644
--- a/src/runtime/cgo/asm_mipsx.s
+++ b/src/runtime/cgo/asm_mipsx.s
@@ -8,12 +8,17 @@
// Set the x_crosscall2_ptr C function pointer variable point to crosscall2.
// It's such a pointer chain: _crosscall2_ptr -> x_crosscall2_ptr -> crosscall2
+// Use a local trampoline, to avoid taking the address of a dynamically exported
+// function.
TEXT ·set_crosscall2(SB),NOSPLIT,$0-0
MOVW _crosscall2_ptr(SB), R5
- MOVW $crosscall2(SB), R6
+ MOVW $crosscall2_trampoline<>(SB), R6
MOVW R6, (R5)
RET
+TEXT crosscall2_trampoline<>(SB),NOSPLIT,$0-0
+ JMP crosscall2(SB)
+
// Called by C code generated by cmd/cgo.
// func crosscall2(fn, a unsafe.Pointer, n int32, ctxt uintptr)
// Saves C callee-saved registers and calls cgocallback with three arguments.
diff --git a/src/runtime/cgo/asm_ppc64x.s b/src/runtime/cgo/asm_ppc64x.s
index c258c7c2a0..a3897459f5 100644
--- a/src/runtime/cgo/asm_ppc64x.s
+++ b/src/runtime/cgo/asm_ppc64x.s
@@ -16,7 +16,9 @@
DEFINE_PPC64X_FUNCDESC(_crosscall2<>, crosscall2)
#define CROSSCALL2_FPTR $_crosscall2<>(SB)
#else
-#define CROSSCALL2_FPTR $crosscall2(SB)
+// Use a local trampoline, to avoid taking the address of a dynamically exported
+// function.
+#define CROSSCALL2_FPTR $crosscall2_trampoline<>(SB)
#endif
// Set the x_crosscall2_ptr C function pointer variable point to crosscall2.
@@ -27,6 +29,9 @@ TEXT ·set_crosscall2(SB),NOSPLIT,$0-0
MOVD R6, (R5)
RET
+TEXT crosscall2_trampoline<>(SB),NOSPLIT,$0-0
+ JMP crosscall2(SB)
+
// Called by C code generated by cmd/cgo.
// func crosscall2(fn, a unsafe.Pointer, n int32, ctxt uintptr)
// Saves C callee-saved registers and calls cgocallback with three arguments.
diff --git a/src/runtime/cgo/asm_riscv64.s b/src/runtime/cgo/asm_riscv64.s
index 08c4ed8466..d75a543842 100644
--- a/src/runtime/cgo/asm_riscv64.s
+++ b/src/runtime/cgo/asm_riscv64.s
@@ -6,12 +6,17 @@
// Set the x_crosscall2_ptr C function pointer variable point to crosscall2.
// It's such a pointer chain: _crosscall2_ptr -> x_crosscall2_ptr -> crosscall2
+// Use a local trampoline, to avoid taking the address of a dynamically exported
+// function.
TEXT ·set_crosscall2(SB),NOSPLIT,$0-0
MOV _crosscall2_ptr(SB), X7
- MOV $crosscall2(SB), X8
+ MOV $crosscall2_trampoline<>(SB), X8
MOV X8, (X7)
RET
+TEXT crosscall2_trampoline<>(SB),NOSPLIT,$0-0
+ JMP crosscall2(SB)
+
// Called by C code generated by cmd/cgo.
// func crosscall2(fn, a unsafe.Pointer, n int32, ctxt uintptr)
// Saves C callee-saved registers and calls cgocallback with three arguments.
diff --git a/src/runtime/cgo/asm_s390x.s b/src/runtime/cgo/asm_s390x.s
index bb0dfc1e31..8f74fd5fe7 100644
--- a/src/runtime/cgo/asm_s390x.s
+++ b/src/runtime/cgo/asm_s390x.s
@@ -6,12 +6,17 @@
// Set the x_crosscall2_ptr C function pointer variable point to crosscall2.
// It's such a pointer chain: _crosscall2_ptr -> x_crosscall2_ptr -> crosscall2
+// Use a local trampoline, to avoid taking the address of a dynamically exported
+// function.
TEXT ·set_crosscall2(SB),NOSPLIT,$0-0
MOVD _crosscall2_ptr(SB), R1
- MOVD $crosscall2(SB), R2
+ MOVD $crosscall2_trampoline<>(SB), R2
MOVD R2, (R1)
RET
+TEXT crosscall2_trampoline<>(SB),NOSPLIT,$0-0
+ JMP crosscall2(SB)
+
// Called by C code generated by cmd/cgo.
// func crosscall2(fn, a unsafe.Pointer, n int32, ctxt uintptr)
// Saves C callee-saved registers and calls cgocallback with three arguments.