trampolines_ppc64le.s raw

   1  // SPDX-License-Identifier: Apache-2.0
   2  // SPDX-FileCopyrightText: 2026 The Ebitengine Authors
   3  
   4  //go:build !cgo && linux
   5  
   6  #include "textflag.h"
   7  #include "go_asm.h"
   8  
   9  // These trampolines map the C ABI to Go ABI and call into the Go equivalent functions.
  10  //
  11  // PPC64LE ELFv2 ABI stack frame layout:
  12  //   0(R1)  = backchain (pointer to caller's frame)
  13  //   8(R1)  = CR save area
  14  //   16(R1) = LR save area
  15  //   24(R1) = reserved
  16  //   32(R1) = parameter save area (minimum 64 bytes for 8 args)
  17  //
  18  // Two patterns are used depending on call direction:
  19  //
  20  // C→Go trampolines: The C caller already provides a 32-byte linkage area.
  21  //   Save LR/CR into caller's frame at 16(R1)/8(R1) BEFORE allocating,
  22  //   then use MOVDU to allocate and set backchain atomically.
  23  //
  24  // Go→C trampolines: Go callers don't provide ELFv2 linkage area.
  25  //   Allocate frame first with MOVDU, then save LR/CR into OUR frame.
  26  
  27  TEXT x_cgo_init_trampoline(SB), NOSPLIT|NOFRAME, $0-0
  28  	MOVD LR, 16(R1)
  29  	MOVW CR, R0
  30  	MOVD R0, 8(R1)
  31  
  32  	MOVDU R1, -32(R1)
  33  
  34  	// R3, R4 already have the arguments
  35  	MOVD ·x_cgo_init_call(SB), R12
  36  	MOVD (R12), R12
  37  	MOVD R12, CTR
  38  	CALL CTR
  39  
  40  	ADD $32, R1
  41  
  42  	MOVD 16(R1), LR
  43  	MOVD 8(R1), R0
  44  	MOVW R0, CR
  45  	RET
  46  
  47  TEXT x_cgo_thread_start_trampoline(SB), NOSPLIT|NOFRAME, $0-0
  48  	MOVD LR, 16(R1)
  49  	MOVW CR, R0
  50  	MOVD R0, 8(R1)
  51  
  52  	MOVDU R1, -32(R1)
  53  
  54  	MOVD ·x_cgo_thread_start_call(SB), R12
  55  	MOVD (R12), R12
  56  	MOVD R12, CTR
  57  	CALL CTR
  58  
  59  	ADD $32, R1
  60  
  61  	MOVD 16(R1), LR
  62  	MOVD 8(R1), R0
  63  	MOVW R0, CR
  64  	RET
  65  
  66  // void (*_cgo_setenv)(char**)
  67  // C arg: R3 = pointer to env
  68  // This is C→Go: caller is C ABI.
  69  TEXT x_cgo_setenv_trampoline(SB), NOSPLIT|NOFRAME, $0-0
  70  	MOVD LR, 16(R1)
  71  	MOVW CR, R0
  72  	MOVD R0, 8(R1)
  73  
  74  	MOVDU R1, -32(R1)
  75  
  76  	MOVD ·x_cgo_setenv_call(SB), R12
  77  	MOVD (R12), R12
  78  	MOVD R12, CTR
  79  	CALL CTR
  80  
  81  	ADD $32, R1
  82  
  83  	MOVD 16(R1), LR
  84  	MOVD 8(R1), R0
  85  	MOVW R0, CR
  86  	RET
  87  
  88  TEXT x_cgo_unsetenv_trampoline(SB), NOSPLIT|NOFRAME, $0-0
  89  	MOVD LR, 16(R1)
  90  	MOVW CR, R0
  91  	MOVD R0, 8(R1)
  92  
  93  	MOVDU R1, -32(R1)
  94  
  95  	MOVD ·x_cgo_unsetenv_call(SB), R12
  96  	MOVD (R12), R12
  97  	MOVD R12, CTR
  98  	CALL CTR
  99  
 100  	ADD $32, R1
 101  
 102  	MOVD 16(R1), LR
 103  	MOVD 8(R1), R0
 104  	MOVW R0, CR
 105  	RET
 106  
 107  TEXT x_cgo_notify_runtime_init_done_trampoline(SB), NOSPLIT|NOFRAME, $0-0
 108  	MOVD LR, 16(R1)
 109  	MOVW CR, R0
 110  	MOVD R0, 8(R1)
 111  
 112  	MOVDU R1, -32(R1)
 113  
 114  	CALL ·x_cgo_notify_runtime_init_done(SB)
 115  
 116  	ADD $32, R1
 117  
 118  	MOVD 16(R1), LR
 119  	MOVD 8(R1), R0
 120  	MOVW R0, CR
 121  	RET
 122  
 123  TEXT x_cgo_bindm_trampoline(SB), NOSPLIT|NOFRAME, $0-0
 124  	MOVD LR, 16(R1)
 125  	MOVW CR, R0
 126  	MOVD R0, 8(R1)
 127  
 128  	MOVDU R1, -32(R1)
 129  
 130  	CALL ·x_cgo_bindm(SB)
 131  
 132  	ADD $32, R1
 133  
 134  	MOVD 16(R1), LR
 135  	MOVD 8(R1), R0
 136  	MOVW R0, CR
 137  	RET
 138  
 139  TEXT ·setg_trampoline(SB), NOSPLIT|NOFRAME, $0-16
 140  	// Save LR, CR, and R31 to non-volatile registers (C ABI preserves R14-R31)
 141  	MOVD LR, R20
 142  	MOVW CR, R21
 143  	MOVD R31, R22 // save R31 because load_g clobbers it
 144  
 145  	// Load arguments from Go stack
 146  	MOVD 32(R1), R12 // setg function pointer
 147  	MOVD 40(R1), R3  // g pointer → first C arg
 148  
 149  	// Allocate ELFv2 frame for the C callee (32 bytes minimum)
 150  	MOVDU R1, -32(R1)
 151  
 152  	// Call setg_gcc which stores g to TLS
 153  	MOVD R12, CTR
 154  	CALL CTR
 155  
 156  	// setg_gcc stored g to TLS but restored old g in R30.
 157  	// Call load_g to reload g from TLS into R30.
 158  	// Note: load_g clobbers R31
 159  	CALL runtime·load_g(SB)
 160  
 161  	// Deallocate frame
 162  	ADD $32, R1
 163  
 164  	// Clear R0 before returning to Go code.
 165  	// Go uses R0 as a constant 0 for things like "std r0,X(r1)" to zero stack locations.
 166  	// C/assembly functions may leave garbage in R0.
 167  	XOR R0, R0, R0
 168  
 169  	// Restore LR, CR, and R31 from non-volatile registers
 170  	MOVD R22, R31 // restore R31
 171  	MOVD R20, LR
 172  	MOVW R21, CR
 173  	RET
 174  
 175  TEXT threadentry_trampoline(SB), NOSPLIT|NOFRAME, $0-0
 176  	MOVD LR, 16(R1)
 177  	MOVW CR, R0
 178  	MOVD R0, 8(R1)
 179  
 180  	MOVDU R1, -32(R1)
 181  
 182  	MOVD ·threadentry_call(SB), R12
 183  	MOVD (R12), R12
 184  	MOVD R12, CTR
 185  	CALL CTR
 186  
 187  	ADD $32, R1
 188  
 189  	MOVD 16(R1), LR
 190  	MOVD 8(R1), R0
 191  	MOVW R0, CR
 192  	RET
 193  
 194  TEXT ·call5(SB), NOSPLIT|NOFRAME, $0-56
 195  	MOVD LR, R20
 196  	MOVW CR, R21
 197  
 198  	// Load arguments from Go stack into C argument registers
 199  	// Go placed args at 32(R1), 40(R1), etc.
 200  	MOVD 32(R1), R12 // fn
 201  	MOVD 40(R1), R3  // a1 → first C arg
 202  	MOVD 48(R1), R4  // a2 → second C arg
 203  	MOVD 56(R1), R5  // a3 → third C arg
 204  	MOVD 64(R1), R6  // a4 → fourth C arg
 205  	MOVD 72(R1), R7  // a5 → fifth C arg
 206  
 207  	MOVDU R1, -32(R1)
 208  
 209  	MOVD R12, CTR
 210  	CALL CTR
 211  
 212  	// Store return value
 213  	// After MOVDU -32, original 80(R1) is now at 80+32=112(R1)
 214  	MOVD R3, (80+32)(R1)
 215  
 216  	// Deallocate frame
 217  	ADD $32, R1
 218  
 219  	// Clear R0 before returning to Go code.
 220  	// Go uses R0 as a constant 0 register for things like "std r0,X(r1)"
 221  	// to zero stack locations. C functions may leave garbage in R0.
 222  	XOR R0, R0, R0
 223  
 224  	// Restore LR/CR from non-volatile registers
 225  	MOVD R20, LR
 226  	MOVW R21, CR
 227  	RET
 228