Apologies for any inaccuracies in my previous explanation. Below, I'll provide a brief clarification based
on verification across both ARM64 and x86 platforms:
arm64:
Without kprobe/kprobe_multi Hook:
(gdb) disassemble vfs_read
Dump of assembler code for function vfs_read:
0xffffc000803ca308 <+0>: bti c // ARM64 BTI security instruction
0xffffc000803ca30c <+4>: nop
0xffffc000803ca310 <+8>: nop
0xffffc000803ca314 <+12>: paciasp
0xffffc000803ca318 <+16>: sub sp, sp, #0xa0
With kprobe/kprobe_multi Hook:
(gdb) disassemble vfs_read
Dump of assembler code for function vfs_read:
0xffffc000803ca308 <+0>: brk #0x4 // BTI replaced by breakpoint
0xffffc000803ca30c <+4>: mov x9, x30
0xffffc000803ca310 <+8>: nop
0xffffc000803ca314 <+12>: paciasp
0xffffc000803ca318 <+16>: sub sp, sp, #0xa0
kprobe directly overwrites the first instruction (bti c → brk #0x4). Hook address (0xffffc000803ca308) matches
the symbol address exactly.
x86_64:
Without kprobe/kprobe_multi Hook:
(gdb) disassemble vfs_read
Dump of assembler code for function vfs_read:
0xffffffff82112b40 <+0>: endbr64 // x86 CET security instruction
0xffffffff82112b44 <+4>: nopl 0x0(%rax,%rax,1)
0xffffffff82112b49 <+9>: push %r15
0xffffffff82112b4b <+11>: mov %rsi,%r15
0xffffffff82112b4e <+14>: push %r14
0xffffffff82112b50 <+16>: push %r13
With kprobe/kprobe_multi Hook:
(gdb) disassemble vfs_read
Dump of assembler code for function vfs_read:
0xffffffff82112b40 <+0>: endbr64 // Preserved security instruction
0xffffffff82112b44 <+4>: call 0xffffffffa1830000 // Hook replaces nopl
0xffffffff82112b49 <+9>: push %r15
0xffffffff82112b4b <+11>: mov %rsi,%r15
0xffffffff82112b4e <+14>: push %r14
0xffffffff82112b50 <+16>: push %r13
kprobe preserves endbr64 and overwrites the subsequent instruction (nopl → call). Hook address (0xffffffff82112b44)
requires -4 offset (0xffffffff82112b40) to match the symbol address.
ARM64 hooks replace the very first instruction (including security features like BTI), while x86_64 hooks target the instruction
immediately after endbr64, creating a 4-byte offset that must be compensated for when resolving symbol addresses.