Text file
src/runtime/libfuzzer_loong64.s
1 // Copyright 2025 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 //go:build libfuzzer
6
7 #include "go_asm.h"
8 #include "textflag.h"
9
10 // Based on race_loong64.s; see commentary there.
11
12 #define RARG0 R4
13 #define RARG1 R5
14 #define RARG2 R6
15 #define RARG3 R7
16
17 #define REPEAT_2(a) a a
18 #define REPEAT_8(a) REPEAT_2(REPEAT_2(REPEAT_2(a)))
19 #define REPEAT_128(a) REPEAT_2(REPEAT_8(REPEAT_8(a)))
20
21 // void runtime·libfuzzerCall4(fn, hookId int, s1, s2 unsafe.Pointer, result uintptr)
22 // Calls C function fn from libFuzzer and passes 4 arguments to it.
23 TEXT runtime·libfuzzerCall4<ABIInternal>(SB), NOSPLIT, $0-0
24 MOVV R4, R12 // fn
25 MOVV R5, RARG0 // hookId
26 MOVV R6, RARG1 // s1
27 MOVV R7, RARG2 // s2
28 MOVV R8, RARG3 // result
29
30 MOVV g_m(g), R13
31
32 // Switch to g0 stack.
33 MOVV R3, R23 // callee-saved, preserved across the CALL
34 MOVV m_g0(R13), R14
35 BEQ R14, g, call // already on g0
36 MOVV (g_sched+gobuf_sp)(R14), R3
37
38 call:
39 JAL (R12)
40 MOVV R23, R3
41 RET
42
43 // void runtime·libfuzzerCallWithTwoByteBuffers(fn, start, end *byte)
44 // Calls C function fn from libFuzzer and passes 2 arguments of type *byte to it.
45 TEXT runtime·libfuzzerCallWithTwoByteBuffers<ABIInternal>(SB), NOSPLIT, $0-0
46 MOVV R4, R12 // fn
47 MOVV R5, RARG0 // start
48 MOVV R6, RARG1 // end
49
50 MOVV g_m(g), R13
51
52 // Switch to g0 stack.
53 MOVV R3, R23 // callee-saved, preserved across the CALL
54 MOVV m_g0(R13), R14
55 BEQ R14, g, call // already on g0
56 MOVV (g_sched+gobuf_sp)(R14), R3
57
58 call:
59 JAL (R12)
60 MOVV R23, R3
61 RET
62
63 // void runtime·libfuzzerCallTraceIntCmp(fn, arg0, arg1, fakePC uintptr)
64 // Calls C function fn from libFuzzer and passes 2 arguments to it after
65 // manipulating the return address so that libfuzzer's integer compare hooks
66 // work.
67 // The problem statement and solution are documented in detail in libfuzzer_amd64.s.
68 // See commentary there.
69 TEXT runtime·libfuzzerCallTraceIntCmp<ABIInternal>(SB), NOSPLIT, $0-0
70 MOVV R4, R12 // fn
71 MOVV R5, RARG0 // arg0
72 MOVV R6, RARG1 // arg1
73 // Save the original return address in a local variable
74 MOVV R1, savedRetAddr-8(SP)
75
76 MOVV g_m(g), R13
77
78 // Switch to g0 stack.
79 MOVV R3, R23 // callee-saved, preserved across the CALL
80 MOVV m_g0(R13), R14
81 BEQ R14, g, call // already on g0
82 MOVV (g_sched+gobuf_sp)(R14), R3
83
84 call:
85 // Load address of the ret sled into the default register for the return
86 // address.
87 MOVV $ret_sled(SB), R1
88 // Clear the lowest 2 bits of fakePC. All Loong64 instructions are four
89 // bytes long, so we cannot get better return address granularity than
90 // multiples of 4.
91 AND $-4, R7
92 // Load the address of the i'th return instruction from the return sled.
93 // The index is given in the fakePC argument.
94 ADDV R7, R1
95 // Call the function by jumping to it and reusing all registers except
96 // for the modified return address register R1.
97 JMP (R12)
98
99 // The ret sled for Loong64 consists of 128 br instructions jumping to the
100 // end of the function. Each instruction is 4 bytes long. The sled thus has
101 // the same byte length of 4 * 128 = 512 as the x86_64 sled, but coarser
102 // granularity.
103 #define RET_SLED \
104 JMP end_of_function;
105
106 TEXT ret_sled(SB), NOSPLIT, $0-0
107 REPEAT_128(RET_SLED);
108
109 end_of_function:
110 MOVV R23, R3
111 MOVV savedRetAddr-8(SP), R1
112 RET
113
View as plain text