这在 Valgrind 的
VALGRIND_DO_CLIENT_REQUEST_EXPR
中意味着什么?
__asm__ volatile (
__SPECIAL_INSTRUCTION_PREAMBLE
/* %RDX = client_request ( %RAX ) */
"xchgq %rbx, %rbx"
: "=d" (_zzq_result)
: "a" (&_zzq_args[0]), "0" (_zzq_default)
: "cc", "memory"
)
其中
__SPECIAL_INSTRUCTION_PREAMBLE
定义为:
#define __SPECIAL_INSTRUCTION_PREAMBLE \
"rolq $3, %%rdi ; rolq $13, %%rdi\n\t" \
"rolq $61, %%rdi ; rolq $51, %%rdi\n\t"
似乎有些黑魔法。
“客户端”可执行文件无法直接与 Valgrind 主机交互。客户端和主机有独立的内存空间。与 Purify 和 Sanitizers 等工具不同,Valgrind 无法为客户端提供任何 C 函数来自省来自 Valgrind 主机的任何信息。
客户端请求机制使用短的 asm 前导码作为 Valgrind 主机的标记。这是一个没有副作用的指令序列,也是任何编译器都不会发出的序列。如果编译器生成的代码被 Valgrind 错误地视为客户端请求,那将是一个大问题。您提供的 amd64 示例使用 RDI 的 4 次左循环,总共 128 位,保持不变。接下来是 RBX 与自身的交换。其他 CPU 架构使用类似的“无操作”序列来发出客户端请求信号。
由于这些指令不执行任何操作,因此它们可以编译成发布版本,并且只有非常小的大小和运行时开销。
这里是 Valgrind 源代码中的注释,解释了这些特殊指令(在 VEX/priv/guest_amd64_toIR.c 中 - 在 Valgrind 中我们可以互换使用“guest”和“client”)。
/* "Special" instructions.
This instruction decoder can decode three special instructions
which mean nothing natively (are no-ops as far as regs/mem are
concerned) but have meaning for supporting Valgrind. A special
instruction is flagged by the 16-byte preamble 48C1C703 48C1C70D
48C1C73D 48C1C733 (in the standard interpretation, that means: rolq
$3, %rdi; rolq $13, %rdi; rolq $61, %rdi; rolq $51, %rdi).
Following that, one of the following 3 are allowed (standard
interpretation in parentheses):
4887DB (xchgq %rbx,%rbx) %RDX = client_request ( %RAX )
4887C9 (xchgq %rcx,%rcx) %RAX = guest_NRADDR
4887D2 (xchgq %rdx,%rdx) call-noredir *%RAX
4887F6 (xchgq %rdi,%rdi) IR injection
Any other bytes following the 16-byte preamble are illegal and
constitute a failure in instruction decoding. This all assumes
that the preamble will never occur except in specific code
fragments designed for Valgrind to catch.
No prefixes may precede a "Special" instruction.
*/
以及相应的代码
/* Spot "Special" instructions (see comment at top of file). */
{
const UChar* code = guest_code + delta;
/* Spot the 16-byte preamble:
48C1C703 rolq $3, %rdi
48C1C70D rolq $13, %rdi
48C1C73D rolq $61, %rdi
48C1C733 rolq $51, %rdi
*/
if (code[ 0] == 0x48 && code[ 1] == 0xC1 && code[ 2] == 0xC7
&& code[ 3] == 0x03 &&
code[ 4] == 0x48 && code[ 5] == 0xC1 && code[ 6] == 0xC7
&& code[ 7] == 0x0D &&
code[ 8] == 0x48 && code[ 9] == 0xC1 && code[10] == 0xC7
&& code[11] == 0x3D &&
code[12] == 0x48 && code[13] == 0xC1 && code[14] == 0xC7
&& code[15] == 0x33) {
/* Got a "Special" instruction preamble. Which one is it? */
if (code[16] == 0x48 && code[17] == 0x87
&& code[18] == 0xDB /* xchgq %rbx,%rbx */) {
/* %RDX = client_request ( %RAX ) */
DIP("%%rdx = client_request ( %%rax )\n");
delta += 19;
jmp_lit(&dres, Ijk_ClientReq, guest_RIP_bbstart+delta);
vassert(dres.whatNext == Dis_StopHere);
goto decode_success;
}
else