internal/fakecgo: use C ABI in amd64 trampolines (#394)
Go might expect (in the future) that x_cgo_init_trampoline trampolines and friends honor the C calling convention, i.e. callee-saved (aka non-volatile) registers shouldn't be clobbered by the called function. It is more future proof, safer, and more standard, to use R11 as a temporary register.
- commit
- 4f3cc2789f2e2d70a6fe3cda1d183244c90804bd
- author
- Quim Muntal · · 2026-01-23 04:02 UTC
- committer
- GitHub · · 2026-01-23 04:02 UTC
- parent
- a280c0d
- signature
- GPG Unverified
B5690EEEBB952194The key is unknown
1 file · +22 -29
M internal/fakecgo/trampolines_amd64.s +22 -29
| @@ -7,12 +7,6 @@ | |||
| 7 | 7 | trampoline for emulating required C functions for cgo in go (see cgo.go) | |
| 8 | 8 | (we convert cdecl calling convention to go and vice-versa) | |
| 9 | 9 | ||
| 10 | - | Since we're called from go and call into C we can cheat a bit with the calling conventions: | |
| 11 | - | - in go all the registers are caller saved | |
| 12 | - | - in C we have a couple of callee saved registers | |
| 13 | - | ||
| 14 | - | => we can use BX, R12, R13, R14, R15 instead of the stack | |
| 15 | - | ||
| 16 | 10 | C Calling convention cdecl used here (we only need integer args): | |
| 17 | 11 | 1. arg: DI | |
| 18 | 12 | 2. arg: SI | |
| @@ -22,6 +16,7 @@ C Calling convention cdecl used here (we only need integer args): | |||
| 22 | 16 | 6. arg: R9 | |
| 23 | 17 | We don't need floats with these functions -> AX=0 | |
| 24 | 18 | return value will be in AX | |
| 19 | + | temporary register is R11 | |
| 25 | 20 | */ | |
| 26 | 21 | #include "textflag.h" | |
| 27 | 22 | #include "go_asm.h" | |
| @@ -32,46 +27,44 @@ return value will be in AX | |||
| 32 | 27 | TEXT x_cgo_init_trampoline(SB), NOSPLIT, $16 | |
| 33 | 28 | MOVQ DI, AX | |
| 34 | 29 | MOVQ SI, BX | |
| 35 | - | MOVQ ·x_cgo_init_call(SB), DX | |
| 36 | - | MOVQ (DX), CX | |
| 37 | - | CALL CX | |
| 30 | + | MOVQ ·x_cgo_init_call(SB), R11 | |
| 31 | + | MOVQ (R11), R11 | |
| 32 | + | CALL R11 | |
| 38 | 33 | RET | |
| 39 | 34 | ||
| 40 | 35 | TEXT x_cgo_thread_start_trampoline(SB), NOSPLIT, $8 | |
| 41 | 36 | MOVQ DI, AX | |
| 42 | - | MOVQ ·x_cgo_thread_start_call(SB), DX | |
| 43 | - | MOVQ (DX), CX | |
| 44 | - | CALL CX | |
| 37 | + | MOVQ ·x_cgo_thread_start_call(SB), R11 | |
| 38 | + | MOVQ (R11), R11 | |
| 39 | + | CALL R11 | |
| 45 | 40 | RET | |
| 46 | 41 | ||
| 47 | 42 | TEXT x_cgo_setenv_trampoline(SB), NOSPLIT, $8 | |
| 48 | 43 | MOVQ DI, AX | |
| 49 | - | MOVQ ·x_cgo_setenv_call(SB), DX | |
| 50 | - | MOVQ (DX), CX | |
| 51 | - | CALL CX | |
| 44 | + | MOVQ ·x_cgo_setenv_call(SB), R11 | |
| 45 | + | MOVQ (R11), R11 | |
| 46 | + | CALL R11 | |
| 52 | 47 | RET | |
| 53 | 48 | ||
| 54 | 49 | TEXT x_cgo_unsetenv_trampoline(SB), NOSPLIT, $8 | |
| 55 | 50 | MOVQ DI, AX | |
| 56 | - | MOVQ ·x_cgo_unsetenv_call(SB), DX | |
| 57 | - | MOVQ (DX), CX | |
| 58 | - | CALL CX | |
| 51 | + | MOVQ ·x_cgo_unsetenv_call(SB), R11 | |
| 52 | + | MOVQ (R11), R11 | |
| 53 | + | CALL R11 | |
| 59 | 54 | RET | |
| 60 | 55 | ||
| 61 | 56 | TEXT x_cgo_notify_runtime_init_done_trampoline(SB), NOSPLIT, $0 | |
| 62 | - | CALL ·x_cgo_notify_runtime_init_done(SB) | |
| 63 | - | RET | |
| 57 | + | JMP ·x_cgo_notify_runtime_init_done(SB) | |
| 64 | 58 | ||
| 65 | 59 | TEXT x_cgo_bindm_trampoline(SB), NOSPLIT, $0 | |
| 66 | - | CALL ·x_cgo_bindm(SB) | |
| 67 | - | RET | |
| 60 | + | JMP ·x_cgo_bindm(SB) | |
| 68 | 61 | ||
| 69 | 62 | // func setg_trampoline(setg uintptr, g uintptr) | |
| 70 | 63 | TEXT ·setg_trampoline(SB), NOSPLIT, $0-16 | |
| 71 | 64 | MOVQ G+8(FP), DI | |
| 72 | - | MOVQ setg+0(FP), BX | |
| 65 | + | MOVQ setg+0(FP), R11 | |
| 73 | 66 | XORL AX, AX | |
| 74 | - | CALL BX | |
| 67 | + | CALL R11 | |
| 75 | 68 | RET | |
| 76 | 69 | ||
| 77 | 70 | TEXT threadentry_trampoline(SB), NOSPLIT, $0 | |
| @@ -83,15 +76,15 @@ TEXT threadentry_trampoline(SB), NOSPLIT, $0 | |||
| 83 | 76 | PXOR X15, X15 | |
| 84 | 77 | ||
| 85 | 78 | MOVQ DI, AX | |
| 86 | - | MOVQ ·threadentry_call(SB), DX | |
| 87 | - | MOVQ (DX), CX | |
| 88 | - | CALL CX | |
| 79 | + | MOVQ ·threadentry_call(SB), R11 | |
| 80 | + | MOVQ (R11), R11 | |
| 81 | + | CALL R11 | |
| 89 | 82 | ||
| 90 | 83 | POP_REGS_HOST_TO_ABI0() | |
| 91 | 84 | RET | |
| 92 | 85 | ||
| 93 | 86 | TEXT ·call5(SB), NOSPLIT, $0-56 | |
| 94 | - | MOVQ fn+0(FP), BX | |
| 87 | + | MOVQ fn+0(FP), R11 | |
| 95 | 88 | MOVQ a1+8(FP), DI | |
| 96 | 89 | MOVQ a2+16(FP), SI | |
| 97 | 90 | MOVQ a3+24(FP), DX | |
| @@ -105,7 +98,7 @@ TEXT ·call5(SB), NOSPLIT, $0-56 | |||
| 105 | 98 | SUBQ $16, SP // allocate space for alignment | |
| 106 | 99 | ANDQ $-16, SP // align on 16 bytes for SSE | |
| 107 | 100 | ||
| 108 | - | CALL BX | |
| 101 | + | CALL R11 | |
| 109 | 102 | ||
| 110 | 103 | MOVQ BP, SP // get SP back | |
| 111 | 104 | POPQ BP // restore BP | |
| @@ -7,12 +7,6 @@ | |||||
| 7 | trampoline for emulating required C functions for cgo in go (see cgo.go) | 7 | trampoline for emulating required C functions for cgo in go (see cgo.go) | ||
| 8 | (we convert cdecl calling convention to go and vice-versa) | 8 | (we convert cdecl calling convention to go and vice-versa) | ||
| 9 | 9 | ||||
| 10 | - | Since we're called from go and call into C we can cheat a bit with the calling conventions: | |||
| 11 | - | - in go all the registers are caller saved | |||
| 12 | - | - in C we have a couple of callee saved registers | |||
| 13 | - | ||||
| 14 | - | => we can use BX, R12, R13, R14, R15 instead of the stack | |||
| 15 | - | ||||
| 16 | C Calling convention cdecl used here (we only need integer args): | 10 | C Calling convention cdecl used here (we only need integer args): | ||
| 17 | 1. arg: DI | 11 | 1. arg: DI | ||
| 18 | 2. arg: SI | 12 | 2. arg: SI | ||
| @@ -22,6 +16,7 @@ C Calling convention cdecl used here (we only need integer args): | |||||
| 22 | 6. arg: R9 | 16 | 6. arg: R9 | ||
| 23 | We don't need floats with these functions -> AX=0 | 17 | We don't need floats with these functions -> AX=0 | ||
| 24 | return value will be in AX | 18 | return value will be in AX | ||
| 19 | + | temporary register is R11 | |||
| 25 | */ | 20 | */ | ||
| 26 | #include "textflag.h" | 21 | #include "textflag.h" | ||
| 27 | #include "go_asm.h" | 22 | #include "go_asm.h" | ||
| @@ -32,46 +27,44 @@ return value will be in AX | |||||
| 32 | TEXT x_cgo_init_trampoline(SB), NOSPLIT, $16 | 27 | TEXT x_cgo_init_trampoline(SB), NOSPLIT, $16 | ||
| 33 | MOVQ DI, AX | 28 | MOVQ DI, AX | ||
| 34 | MOVQ SI, BX | 29 | MOVQ SI, BX | ||
| 35 | - | MOVQ ·x_cgo_init_call(SB), DX | 30 | + | MOVQ ·x_cgo_init_call(SB), R11 |
| 36 | - | MOVQ (DX), CX | 31 | + | MOVQ (R11), R11 |
| 37 | - | CALL CX | 32 | + | CALL R11 |
| 38 | RET | 33 | RET | ||
| 39 | 34 | ||||
| 40 | TEXT x_cgo_thread_start_trampoline(SB), NOSPLIT, $8 | 35 | TEXT x_cgo_thread_start_trampoline(SB), NOSPLIT, $8 | ||
| 41 | MOVQ DI, AX | 36 | MOVQ DI, AX | ||
| 42 | - | MOVQ ·x_cgo_thread_start_call(SB), DX | 37 | + | MOVQ ·x_cgo_thread_start_call(SB), R11 |
| 43 | - | MOVQ (DX), CX | 38 | + | MOVQ (R11), R11 |
| 44 | - | CALL CX | 39 | + | CALL R11 |
| 45 | RET | 40 | RET | ||
| 46 | 41 | ||||
| 47 | TEXT x_cgo_setenv_trampoline(SB), NOSPLIT, $8 | 42 | TEXT x_cgo_setenv_trampoline(SB), NOSPLIT, $8 | ||
| 48 | MOVQ DI, AX | 43 | MOVQ DI, AX | ||
| 49 | - | MOVQ ·x_cgo_setenv_call(SB), DX | 44 | + | MOVQ ·x_cgo_setenv_call(SB), R11 |
| 50 | - | MOVQ (DX), CX | 45 | + | MOVQ (R11), R11 |
| 51 | - | CALL CX | 46 | + | CALL R11 |
| 52 | RET | 47 | RET | ||
| 53 | 48 | ||||
| 54 | TEXT x_cgo_unsetenv_trampoline(SB), NOSPLIT, $8 | 49 | TEXT x_cgo_unsetenv_trampoline(SB), NOSPLIT, $8 | ||
| 55 | MOVQ DI, AX | 50 | MOVQ DI, AX | ||
| 56 | - | MOVQ ·x_cgo_unsetenv_call(SB), DX | 51 | + | MOVQ ·x_cgo_unsetenv_call(SB), R11 |
| 57 | - | MOVQ (DX), CX | 52 | + | MOVQ (R11), R11 |
| 58 | - | CALL CX | 53 | + | CALL R11 |
| 59 | RET | 54 | RET | ||
| 60 | 55 | ||||
| 61 | TEXT x_cgo_notify_runtime_init_done_trampoline(SB), NOSPLIT, $0 | 56 | TEXT x_cgo_notify_runtime_init_done_trampoline(SB), NOSPLIT, $0 | ||
| 62 | - | CALL ·x_cgo_notify_runtime_init_done(SB) | 57 | + | JMP ·x_cgo_notify_runtime_init_done(SB) |
| 63 | - | RET | |||
| 64 | 58 | ||||
| 65 | TEXT x_cgo_bindm_trampoline(SB), NOSPLIT, $0 | 59 | TEXT x_cgo_bindm_trampoline(SB), NOSPLIT, $0 | ||
| 66 | - | CALL ·x_cgo_bindm(SB) | 60 | + | JMP ·x_cgo_bindm(SB) |
| 67 | - | RET | |||
| 68 | 61 | ||||
| 69 | // func setg_trampoline(setg uintptr, g uintptr) | 62 | // func setg_trampoline(setg uintptr, g uintptr) | ||
| 70 | TEXT ·setg_trampoline(SB), NOSPLIT, $0-16 | 63 | TEXT ·setg_trampoline(SB), NOSPLIT, $0-16 | ||
| 71 | MOVQ G+8(FP), DI | 64 | MOVQ G+8(FP), DI | ||
| 72 | - | MOVQ setg+0(FP), BX | 65 | + | MOVQ setg+0(FP), R11 |
| 73 | XORL AX, AX | 66 | XORL AX, AX | ||
| 74 | - | CALL BX | 67 | + | CALL R11 |
| 75 | RET | 68 | RET | ||
| 76 | 69 | ||||
| 77 | TEXT threadentry_trampoline(SB), NOSPLIT, $0 | 70 | TEXT threadentry_trampoline(SB), NOSPLIT, $0 | ||
| @@ -83,15 +76,15 @@ TEXT threadentry_trampoline(SB), NOSPLIT, $0 | |||||
| 83 | PXOR X15, X15 | 76 | PXOR X15, X15 | ||
| 84 | 77 | ||||
| 85 | MOVQ DI, AX | 78 | MOVQ DI, AX | ||
| 86 | - | MOVQ ·threadentry_call(SB), DX | 79 | + | MOVQ ·threadentry_call(SB), R11 |
| 87 | - | MOVQ (DX), CX | 80 | + | MOVQ (R11), R11 |
| 88 | - | CALL CX | 81 | + | CALL R11 |
| 89 | 82 | ||||
| 90 | POP_REGS_HOST_TO_ABI0() | 83 | POP_REGS_HOST_TO_ABI0() | ||
| 91 | RET | 84 | RET | ||
| 92 | 85 | ||||
| 93 | TEXT ·call5(SB), NOSPLIT, $0-56 | 86 | TEXT ·call5(SB), NOSPLIT, $0-56 | ||
| 94 | - | MOVQ fn+0(FP), BX | 87 | + | MOVQ fn+0(FP), R11 |
| 95 | MOVQ a1+8(FP), DI | 88 | MOVQ a1+8(FP), DI | ||
| 96 | MOVQ a2+16(FP), SI | 89 | MOVQ a2+16(FP), SI | ||
| 97 | MOVQ a3+24(FP), DX | 90 | MOVQ a3+24(FP), DX | ||
| @@ -105,7 +98,7 @@ TEXT ·call5(SB), NOSPLIT, $0-56 | |||||
| 105 | SUBQ $16, SP // allocate space for alignment | 98 | SUBQ $16, SP // allocate space for alignment | ||
| 106 | ANDQ $-16, SP // align on 16 bytes for SSE | 99 | ANDQ $-16, SP // align on 16 bytes for SSE | ||
| 107 | 100 | ||||
| 108 | - | CALL BX | 101 | + | CALL R11 |
| 109 | 102 | ||||
| 110 | MOVQ BP, SP // get SP back | 103 | MOVQ BP, SP // get SP back | ||
| 111 | POPQ BP // restore BP | 104 | POPQ BP // restore BP | ||