| // 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 (ppc64 || ppc64le) && linux && cgo | |
| // 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 |