github.com/twelsh-aw/go/src@v0.0.0-20230516233729-a56fe86a7c81/runtime/libfuzzer_arm64.s (about) 1 // Copyright 2019 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_arm64.s; see commentary there. 11 12 #define RARG0 R0 13 #define RARG1 R1 14 #define RARG2 R2 15 #define RARG3 R3 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·libfuzzerCallTraceIntCmp(fn, arg0, arg1, fakePC uintptr) 22 // Calls C function fn from libFuzzer and passes 2 arguments to it after 23 // manipulating the return address so that libfuzzer's integer compare hooks 24 // work. 25 // The problem statement and solution are documented in detail in libfuzzer_amd64.s. 26 // See commentary there. 27 TEXT runtime·libfuzzerCallTraceIntCmp(SB), NOSPLIT, $8-32 28 MOVD fn+0(FP), R9 29 MOVD arg0+8(FP), RARG0 30 MOVD arg1+16(FP), RARG1 31 MOVD fakePC+24(FP), R8 32 // Save the original return address in a local variable 33 MOVD R30, savedRetAddr-8(SP) 34 35 MOVD g_m(g), R10 36 37 // Switch to g0 stack. 38 MOVD RSP, R19 // callee-saved, preserved across the CALL 39 MOVD m_g0(R10), R11 40 CMP R11, g 41 BEQ call // already on g0 42 MOVD (g_sched+gobuf_sp)(R11), R12 43 MOVD R12, RSP 44 call: 45 // Load address of the ret sled into the default register for the return 46 // address. 47 ADR ret_sled, R30 48 // Clear the lowest 2 bits of fakePC. All ARM64 instructions are four 49 // bytes long, so we cannot get better return address granularity than 50 // multiples of 4. 51 AND $-4, R8, R8 52 // Add the offset of the fake_pc-th ret. 53 ADD R8, R30, R30 54 // Call the function by jumping to it and reusing all registers except 55 // for the modified return address register R30. 56 JMP (R9) 57 58 // The ret sled for ARM64 consists of 128 br instructions jumping to the 59 // end of the function. Each instruction is 4 bytes long. The sled thus 60 // has the same byte length of 4 * 128 = 512 as the x86_64 sled, but 61 // coarser granularity. 62 #define RET_SLED \ 63 JMP end_of_function; 64 65 ret_sled: 66 REPEAT_128(RET_SLED); 67 68 end_of_function: 69 MOVD R19, RSP 70 MOVD savedRetAddr-8(SP), R30 71 RET 72 73 // void runtime·libfuzzerCall4(fn, hookId int, s1, s2 unsafe.Pointer, result uintptr) 74 // Calls C function fn from libFuzzer and passes 4 arguments to it. 75 TEXT runtime·libfuzzerCall4(SB), NOSPLIT, $0-40 76 MOVD fn+0(FP), R9 77 MOVD hookId+8(FP), RARG0 78 MOVD s1+16(FP), RARG1 79 MOVD s2+24(FP), RARG2 80 MOVD result+32(FP), RARG3 81 82 MOVD g_m(g), R10 83 84 // Switch to g0 stack. 85 MOVD RSP, R19 // callee-saved, preserved across the CALL 86 MOVD m_g0(R10), R11 87 CMP R11, g 88 BEQ call // already on g0 89 MOVD (g_sched+gobuf_sp)(R11), R12 90 MOVD R12, RSP 91 call: 92 BL R9 93 MOVD R19, RSP 94 RET 95 96 // void runtime·libfuzzerCallWithTwoByteBuffers(fn, start, end *byte) 97 // Calls C function fn from libFuzzer and passes 2 arguments of type *byte to it. 98 TEXT runtime·libfuzzerCallWithTwoByteBuffers(SB), NOSPLIT, $0-24 99 MOVD fn+0(FP), R9 100 MOVD start+8(FP), R0 101 MOVD end+16(FP), R1 102 103 MOVD g_m(g), R10 104 105 // Switch to g0 stack. 106 MOVD RSP, R19 // callee-saved, preserved across the CALL 107 MOVD m_g0(R10), R11 108 CMP R11, g 109 BEQ call // already on g0 110 MOVD (g_sched+gobuf_sp)(R11), R12 111 MOVD R12, RSP 112 call: 113 BL R9 114 MOVD R19, RSP 115 RET