]> Cypherpunks.ru repositories - gostls13.git/commitdiff
runtime/cgo: avoid taking the address of crosscall2 in code
authorCherry Mui <cherryyz@google.com>
Sat, 7 Oct 2023 00:53:27 +0000 (20:53 -0400)
committerCherry Mui <cherryyz@google.com>
Thu, 12 Oct 2023 00:43:51 +0000 (00:43 +0000)
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 #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>
src/cmd/cgo/internal/testcarchive/carchive_test.go
src/runtime/cgo/asm_386.s
src/runtime/cgo/asm_amd64.s
src/runtime/cgo/asm_arm.s
src/runtime/cgo/asm_arm64.s
src/runtime/cgo/asm_loong64.s
src/runtime/cgo/asm_mips64x.s
src/runtime/cgo/asm_mipsx.s
src/runtime/cgo/asm_ppc64x.s
src/runtime/cgo/asm_riscv64.s
src/runtime/cgo/asm_s390x.s

index cc810f9d3e255198889d8ec50e51616b2580c6a5..b140a9c61378a76cc0b28101a4a6add84c7845d8 100644 (file)
@@ -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)
+       }
+}
index 086e20b02f50c3eb9eda89ac5053367ed8ce65b0..f9a662aa88f485f94cfe2a6d5b24a8a0753dcb48 100644 (file)
@@ -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.
index 48afe4ef620363a8a51c3a2a876b7f0b2e559989..6bf1363e902ec9bd300798c71eb574c881182de4 100644 (file)
@@ -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.
index f7f99772a6ce88b12bc16db01c69390d8220204e..095e9c06c9bf0a81c2cf0b8f5a34b575a3bd538e 100644 (file)
@@ -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.
index ce8909b49273e51e0f498468af172b8e125a887c..5492dc142c842abfa0a26bc9e729ff20666a25db 100644 (file)
@@ -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.
index 3b514ffc4a195345087621abb5c92e47e9475653..19c8d743341a0b9d7893c2c448010af97b4e4dca 100644 (file)
@@ -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.
index 0a8fbbbef05d11e2f68b72b7ce56746dbafa8fec..af817d5ea6ed3bf0d6ac0b370b09ff338ada0ace 100644 (file)
@@ -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.
index a57ae97d7e96a19f0db77ffa026a43ad0fab773b..198c59a33e7a0c61e8f48e5c3c2dd783b41d847a 100644 (file)
@@ -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.
index c258c7c2a080fd8e89df0f70171e1aca2649d29a..a3897459f5047e9e1b6598511938881deb71ec92 100644 (file)
@@ -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.
index 08c4ed846671da32b10428d272307e7bce14d6a4..d75a5438429e9d62f0bf1b6a5779593ccfe67fce 100644 (file)
@@ -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.
index bb0dfc1e313d9a747a7c961a431a32fd4e8a3aae..8f74fd5fe7810e44f0b3afd9489836d4e73dab60 100644 (file)
@@ -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.