Skip to content

Commit

Permalink
runtime/cgo: avoid taking the address of crosscall2 in code
Browse files Browse the repository at this point in the history
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 <[email protected]>
Reviewed-by: Ian Lance Taylor <[email protected]>
  • Loading branch information
cherrymui committed Oct 12, 2023
1 parent 3b0fc5a commit 872d718
Show file tree
Hide file tree
Showing 11 changed files with 92 additions and 10 deletions.
32 changes: 32 additions & 0 deletions src/cmd/cgo/internal/testcarchive/carchive_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}
7 changes: 6 additions & 1 deletion src/runtime/cgo/asm_386.s
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
7 changes: 6 additions & 1 deletion src/runtime/cgo/asm_amd64.s
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
7 changes: 6 additions & 1 deletion src/runtime/cgo/asm_arm.s
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
7 changes: 6 additions & 1 deletion src/runtime/cgo/asm_arm64.s
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
7 changes: 6 additions & 1 deletion src/runtime/cgo/asm_loong64.s
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
7 changes: 6 additions & 1 deletion src/runtime/cgo/asm_mips64x.s
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
7 changes: 6 additions & 1 deletion src/runtime/cgo/asm_mipsx.s
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
7 changes: 6 additions & 1 deletion src/runtime/cgo/asm_ppc64x.s
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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.
Expand Down
7 changes: 6 additions & 1 deletion src/runtime/cgo/asm_riscv64.s
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
7 changes: 6 additions & 1 deletion src/runtime/cgo/asm_s390x.s
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down

0 comments on commit 872d718

Please sign in to comment.