diff options
author | Cherry Mui <cherryyz@google.com> | 2023-10-06 20:53:27 -0400 |
---|---|---|
committer | Cherry Mui <cherryyz@google.com> | 2023-10-30 20:36:26 +0000 |
commit | 7b04d81cbc2e45172c17e62943a777286a3341be (patch) | |
tree | 54de14373fcd4074b45ce84caa62c1587815c922 | |
parent | f9a31cda3c8a92e81989af4167c9ae5bfbb8ea5e (diff) | |
download | go-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.go | 32 | ||||
-rw-r--r-- | src/runtime/cgo/asm_386.s | 7 | ||||
-rw-r--r-- | src/runtime/cgo/asm_amd64.s | 7 | ||||
-rw-r--r-- | src/runtime/cgo/asm_arm.s | 7 | ||||
-rw-r--r-- | src/runtime/cgo/asm_arm64.s | 7 | ||||
-rw-r--r-- | src/runtime/cgo/asm_loong64.s | 7 | ||||
-rw-r--r-- | src/runtime/cgo/asm_mips64x.s | 7 | ||||
-rw-r--r-- | src/runtime/cgo/asm_mipsx.s | 7 | ||||
-rw-r--r-- | src/runtime/cgo/asm_ppc64x.s | 7 | ||||
-rw-r--r-- | src/runtime/cgo/asm_riscv64.s | 7 | ||||
-rw-r--r-- | src/runtime/cgo/asm_s390x.s | 7 |
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 cc810f9d3e2..b140a9c6137 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 086e20b02f5..f9a662aa88f 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 f254622f231..e319094a456 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 f7f99772a6c..095e9c06c9b 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 ce8909b4927..5492dc142c8 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 3b514ffc4a1..19c8d743341 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 0a8fbbbef05..af817d5ea6e 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 a57ae97d7e9..198c59a33e7 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 c258c7c2a08..a3897459f50 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 08c4ed84667..d75a5438429 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 bb0dfc1e313..8f74fd5fe78 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. |