Text file
src/runtime/libfuzzer_loong64.s
Documentation: runtime
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.
23TEXT 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
38call:
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.
45TEXT 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
58call:
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.
69TEXT 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
84call:
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
106TEXT ret_sled(SB), NOSPLIT, $0-0
107 REPEAT_128(RET_SLED);
108
109end_of_function:
110 MOVV R23, R3
111 MOVV savedRetAddr-8(SP), R1
112 RET
View as plain text