mirror of
https://github.com/golang/go
synced 2024-11-02 09:28:34 +00:00
cmd/cgo/internal/test: test PPC64 ELFv2 call/plt stub generation
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>
This commit is contained in:
parent
c8caad423c
commit
bf5d8c02ba
3 changed files with 155 additions and 0 deletions
20
src/cmd/cgo/internal/test/callstub_linux_ppc64le.go
Normal file
20
src/cmd/cgo/internal/test/callstub_linux_ppc64le.go
Normal file
|
@ -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.")
|
||||
}
|
||||
}
|
13
src/cmd/cgo/internal/test/linux_ppc64le_test.go
Normal file
13
src/cmd/cgo/internal/test/linux_ppc64le_test.go
Normal file
|
@ -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)
|
||||
}
|
122
src/cmd/cgo/internal/test/stubtest_linux_ppc64le.S
Normal file
122
src/cmd/cgo/internal/test/stubtest_linux_ppc64le.S
Normal file
|
@ -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
|
Loading…
Reference in a new issue