]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/cgo/internal/test: test PPC64 ELFv2 call/plt stub generation
authorPaul E. Murphy <murp@ibm.com>
Wed, 17 May 2023 18:26:11 +0000 (13:26 -0500)
committerPaul Murphy <murp@ibm.com>
Fri, 22 Sep 2023 15:06:17 +0000 (15:06 +0000)
Verify functional stubs are inserted between TOC and NOTOC functions.

The implementation of the stub varies depending on -buildmode and
GOPPC64. Today, the type of stub generated by the internal linker
is roughly determined by the following

{GOPPC64 < 10, GOPPC64 >= 10} x {-buildmode=pie, -buildmode=default}

Change-Id: Ib9b3eef252bfcd357a476134d3503cb996bc285b
Reviewed-on: https://go-review.googlesource.com/c/go/+/496916
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Bryan Mills <bcmills@google.com>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
Reviewed-by: Lynn Boger <laboger@linux.vnet.ibm.com>
src/cmd/cgo/internal/test/callstub_linux_ppc64le.go [new file with mode: 0644]
src/cmd/cgo/internal/test/linux_ppc64le_test.go [new file with mode: 0644]
src/cmd/cgo/internal/test/stubtest_linux_ppc64le.S [new file with mode: 0644]

diff --git a/src/cmd/cgo/internal/test/callstub_linux_ppc64le.go b/src/cmd/cgo/internal/test/callstub_linux_ppc64le.go
new file mode 100644 (file)
index 0000000..93c29e1
--- /dev/null
@@ -0,0 +1,20 @@
+// Copyright 2023 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cgotest
+
+// extern int notoc_func(void);
+// int TestPPC64Stubs(void) {
+//     return notoc_func();
+// }
+import "C"
+import "testing"
+
+func testPPC64CallStubs(t *testing.T) {
+       // Verify the trampolines run on the testing machine. If they
+       // do not, or are missing, a crash is expected.
+       if C.TestPPC64Stubs() != 0 {
+               t.Skipf("This test requires binutils 2.35 or newer.")
+       }
+}
diff --git a/src/cmd/cgo/internal/test/linux_ppc64le_test.go b/src/cmd/cgo/internal/test/linux_ppc64le_test.go
new file mode 100644 (file)
index 0000000..67b6b16
--- /dev/null
@@ -0,0 +1,13 @@
+// Copyright 2023 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build ppc64le && linux && cgo
+
+package cgotest
+
+import "testing"
+
+func TestPPC64CallStubs(t *testing.T) {
+       testPPC64CallStubs(t)
+}
diff --git a/src/cmd/cgo/internal/test/stubtest_linux_ppc64le.S b/src/cmd/cgo/internal/test/stubtest_linux_ppc64le.S
new file mode 100644 (file)
index 0000000..0c51970
--- /dev/null
@@ -0,0 +1,122 @@
+// Copyright 2023 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// When linking C ELFv2 objects, the Go linker may need to insert calling stubs.
+// A call stub is usually needed when the ELFv2 st_other attribute is different
+// between caller and callee.
+//
+// The type of call stub inserted will vary depending on GOPPC64 and the
+// buildmode (e.g pie builds shared code, default builds fixed-position code).
+// CI is set up to run for P8 and P10 machines, and this test is run in both
+// pie and default modes.
+//
+// Several functions are written with interesting st_other attributes, and
+// call each other to test various calling combinations which require stubs.
+//
+// The call tree is as follows, starting from TestPPC64Stubs (A C function):
+// TestPPC64Stubs (compiled PIC by default by Go)
+//   notoc_func          [called TOC -> NOTOC (but R2 is preserved)]
+//     toc_func          [called NOTOC -> TOC]
+//       notoc_nor2_func [called TOC -> NOTOC]
+//       random          [dynamic TOC call]
+//     random           [dynamic NOTOC call]
+//
+// Depending on the GOPPC64/buildmode used, and type of call, one of 7 stubs may need inserted:
+//
+// TOC   -> NOTOC:     Save R2, call global entry. (valid for any GOPPC64)
+//                      TOC save slot is rewrittent to restore TOC.
+// NOTOC -> TOC [P10]: A PIC call stub using P10 instructions to call the global entry
+// NOTOC -> TOC [P8]:  A PIC call stub using P8 instructions to call the global entry
+//
+// TOC   -> dynamic:              A PLT call stub is generated which saves R2.
+//                                 TOC save slot is rewritten to restore TOC.
+// NOTOC -> dynamic [P10]:        A stub using pcrel instructions is generated.
+// NOTOC -> dynamic [P8/default]: A P8 compatible, non-PIC stub is generated
+// NOTOC -> dynamic [P8/pie]:     A P8 compatible, PIC stub is generated
+//
+//
+// Some notes about other cases:
+//   TOC -> TOC, NOTOC -> NOTOC, NOTOC -> TOC  local calls do not require require call stubs.
+//   TOC -> NOTOC (R2 is preserved, st_other==0): A special case where a call stub is not needed.
+
+// This test requires a binutils with power10 and ELFv2 1.5 support. This is earliest verified version.
+.if .gasversion. >= 23500
+
+// A function which does not guarantee R2 is preserved.
+// R2 is clobbered here to ensure the stubs preserve it.
+       .globl  notoc_nor2_func
+       .type   notoc_nor2_func, @function
+notoc_nor2_func:
+       .localentry notoc_nor2_func,1
+       li      2,0
+       blr
+
+// A function which expects R2 to hold TOC, and has a distinct local entry.
+       .globl  toc_func
+       .type   toc_func, @function
+toc_func:
+       addis   2,12,.TOC.-toc_func@ha
+       addi    2,2,.TOC.-toc_func@l
+       .localentry toc_func, .-toc_func
+       mflr    0
+       std     0,16(1)
+       stdu    1,-32(1)
+
+       // Call a NOTOC function which clobbers R2.
+       bl      notoc_nor2_func
+       nop
+
+       // Call libc random. This should generate a TOC relative plt stub.
+       bl      random
+       nop
+
+       addi    1,1,32
+       ld      0,16(1)
+       mtlr    0
+       blr
+
+// An ELFv2 st_other==0 function. It preserves R2 (TOC), but does not use it.
+       .globl  notoc_func
+       .type   notoc_func, @function
+notoc_func:
+       // Save R2 and LR and stack a frame.
+       mflr    0
+       std     0,16(1)
+       stdu    1,-32(1)
+
+       // Save R2 in TOC save slot.
+       std     2,24(1)
+
+       // clobber R2
+       li      2,0
+
+       // Call type2_func. A call stub from notoc to toc should be inserted.
+       bl      toc_func@notoc
+
+       // Call libc random. A notoc plt stub should be inserted.
+       bl      random@notoc
+
+       // Return 0 to indicate the test ran.
+       li      3,0
+
+       // Restore R2
+       ld      2,24(1)
+
+       // Restore LR and pop stack
+       addi    1,1,32
+       ld      0,16(1)
+       mtlr    0
+       blr
+
+.else
+
+// A stub for older binutils
+       .globl  notoc_func
+       .type   notoc_func, @function
+notoc_func:
+       // Return 1 to indicate the test was skipped.
+       li      3,1
+       blr
+
+.endif