src/runtime/libfuzzer_amd64.s 159 lines View on github.com → Search inside
1// Copyright 2019 The Go Authors. All rights reserved.2// Use of this source code is governed by a BSD-style3// license that can be found in the LICENSE file.45//go:build libfuzzer67#include "go_asm.h"8#include "go_tls.h"9#include "textflag.h"1011// Based on race_amd64.s; see commentary there.1213#ifdef GOOS_windows14#define RARG0 CX15#define RARG1 DX16#define RARG2 R817#define RARG3 R918#else19#define RARG0 DI20#define RARG1 SI21#define RARG2 DX22#define RARG3 CX23#endif2425// void runtime·libfuzzerCall4(fn, hookId int, s1, s2 unsafe.Pointer, result uintptr)26// Calls C function fn from libFuzzer and passes 4 arguments to it.27TEXT	runtime·libfuzzerCall4(SB), NOSPLIT, $0-4028	MOVQ	fn+0(FP), AX29	MOVQ	hookId+8(FP), RARG030	MOVQ	s1+16(FP), RARG131	MOVQ	s2+24(FP), RARG232	MOVQ	result+32(FP), RARG33334	get_tls(R12)35	MOVQ	g(R12), R1436	MOVQ	g_m(R14), R133738	// Switch to g0 stack.39	MOVQ	SP, R12		// callee-saved, preserved across the CALL40	MOVQ	m_g0(R13), R1041	CMPQ	R10, R1442	JE	call	// already on g043	MOVQ	(g_sched+gobuf_sp)(R10), SP44call:45	ANDQ	$~15, SP	// alignment for gcc ABI46	CALL	AX47	MOVQ	R12, SP48	RET4950// void runtime·libfuzzerCallTraceIntCmp(fn, arg0, arg1, fakePC uintptr)51// Calls C function fn from libFuzzer and passes 2 arguments to it after52// manipulating the return address so that libfuzzer's integer compare hooks53// work54// libFuzzer's compare hooks obtain the caller's address from the compiler55// builtin __builtin_return_address. Since we invoke the hooks always56// from the same native function, this builtin would always return the same57// value. Internally, the libFuzzer hooks call through to the always inlined58// HandleCmp and thus can't be mimicked without patching libFuzzer.59//60// We solve this problem via an inline assembly trampoline construction that61// translates a runtime argument `fake_pc` in the range [0, 512) into a call to62// a hook with a fake return address whose lower 9 bits are `fake_pc` up to a63// constant shift. This is achieved by pushing a return address pointing into64// 512 ret instructions at offset `fake_pc` onto the stack and then jumping65// directly to the address of the hook.66//67// Note: We only set the lowest 9 bits of the return address since only these68// bits are used by the libFuzzer value profiling mode for integer compares, see69// https://github.com/llvm/llvm-project/blob/704d92607d26e696daba596b72cb70effe79a872/compiler-rt/lib/fuzzer/FuzzerTracePC.cpp#L39070// as well as71// https://github.com/llvm/llvm-project/blob/704d92607d26e696daba596b72cb70effe79a872/compiler-rt/lib/fuzzer/FuzzerValueBitMap.h#L3472// ValueProfileMap.AddValue() truncates its argument to 16 bits and shifts the73// PC to the left by log_2(128)=7, which means that only the lowest 16 - 7 bits74// of the return address matter. String compare hooks use the lowest 12 bits,75// but take the return address as an argument and thus don't require the76// indirection through a trampoline.77// TODO: Remove the inline assembly trampoline once a PC argument has been added to libfuzzer's int compare hooks.78TEXT	runtime·libfuzzerCallTraceIntCmp(SB), NOSPLIT, $0-3279	MOVQ	fn+0(FP), AX80	MOVQ	arg0+8(FP), RARG081	MOVQ	arg1+16(FP), RARG182	MOVQ	fakePC+24(FP), R88384	get_tls(R12)85	MOVQ	g(R12), R1486	MOVQ	g_m(R14), R138788	// Switch to g0 stack.89	MOVQ	SP, R12		// callee-saved, preserved across the CALL90	MOVQ	m_g0(R13), R1091	CMPQ	R10, R1492	JE	call	// already on g093	MOVQ	(g_sched+gobuf_sp)(R10), SP94call:95	ANDQ	$~15, SP	// alignment for gcc ABI96	SUBQ	$8, SP97	// Load the address of the end of the function and push it into the stack.98	// This address will be jumped to after executing the return instruction99	// from the return sled. There we reset the stack pointer and return.100	MOVQ    $end_of_function<>(SB), BX101	PUSHQ   BX102	// Load the starting address of the return sled into BX.103	MOVQ    $ret_sled<>(SB), BX104	// Load the address of the i'th return instruction from the return sled.105	// The index is given in the fakePC argument.106	ADDQ    R8, BX107	PUSHQ   BX108	// Call the original function with the fakePC return address on the stack.109	// Function arguments arg0 and arg1 are passed in the registers specified110	// by the x64 calling convention.111	JMP     AX112// This code will not be executed and is only there to satisfy assembler113// check of a balanced stack.114not_reachable:115	POPQ    BX116	POPQ    BX117	RET118119TEXT end_of_function<>(SB), NOSPLIT, $0-0120	MOVQ	R12, SP121	RET122123#define REPEAT_8(a) a \124  a \125  a \126  a \127  a \128  a \129  a \130  a131132#define REPEAT_512(a) REPEAT_8(REPEAT_8(REPEAT_8(a)))133134TEXT ret_sled<>(SB), NOSPLIT, $0-0135	REPEAT_512(RET)136137// void runtime·libfuzzerCallWithTwoByteBuffers(fn, start, end *byte)138// Calls C function fn from libFuzzer and passes 2 arguments of type *byte to it.139TEXT	runtime·libfuzzerCallWithTwoByteBuffers(SB), NOSPLIT, $0-24140	MOVQ	fn+0(FP), AX141	MOVQ	start+8(FP), RARG0142	MOVQ	end+16(FP), RARG1143144	get_tls(R12)145	MOVQ	g(R12), R14146	MOVQ	g_m(R14), R13147148	// Switch to g0 stack.149	MOVQ	SP, R12		// callee-saved, preserved across the CALL150	MOVQ	m_g0(R13), R10151	CMPQ	R10, R14152	JE	call	// already on g0153	MOVQ	(g_sched+gobuf_sp)(R10), SP154call:155	ANDQ	$~15, SP	// alignment for gcc ABI156	CALL	AX157	MOVQ	R12, SP158	RET

Findings

✓ No findings reported for this file.

Get this view in your editor

Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.