I will give you an example of the quote of wikipedia:
The red zone is well-known to cause problems for x86-64 kernel developers, as the CPU itself doesn't respect the red zone when calling interrupt handlers. This leads to a subtle kernel breakage as the ABI contradicts the CPU behavior.
In my kernel, I use Linux memcpy() c function:
void *memcpy(void *dest, const void *src,
size_t count)
{
char *tmp = dest;
const char *s = src;
while (count--)
*tmp++ = *s++;
return dest;
}
And the disassembly is:
0000000000000000 <memcpy>:
0: f3 0f 1e fa endbr64
4: 55 push %rbp
5: 48 89 e5 mov %rsp,%rbp
8: 48 8d 05 f9 ff ff ff lea -0x7(%rip),%rax # 8 <memcpy+0x8>
f: 49 bb 00 00 00 00 00 movabs $0x0,%r11
16: 00 00 00
19: 4c 01 d8 add %r11,%rax
1c: 48 89 7d e8 mov %rdi,-0x18(%rbp)
20: 48 89 75 e0 mov %rsi,-0x20(%rbp)
24: 48 89 55 d8 mov %rdx,-0x28(%rbp)
28: 48 8b 45 e8 mov -0x18(%rbp),%rax
2c: 48 89 45 f8 mov %rax,-0x8(%rbp)
30: 48 8b 45 e0 mov -0x20(%rbp),%rax
34: 48 89 45 f0 mov %rax,-0x10(%rbp)
38: eb 1d jmp 57 <memcpy+0x57>
3a: 48 8b 55 f0 mov -0x10(%rbp),%rdx
3e: 48 8d 42 01 lea 0x1(%rdx),%rax
42: 48 89 45 f0 mov %rax,-0x10(%rbp)
46: 48 8b 45 f8 mov -0x8(%rbp),%rax
4a: 48 8d 48 01 lea 0x1(%rax),%rcx
4e: 48 89 4d f8 mov %rcx,-0x8(%rbp)
52: 0f b6 12 movzbl (%rdx),%edx
55: 88 10 mov %dl,(%rax)
57: 48 8b 45 d8 mov -0x28(%rbp),%rax
5b: 48 8d 50 ff lea -0x1(%rax),%rdx
5f: 48 89 55 d8 mov %rdx,-0x28(%rbp)
63: 48 85 c0 test %rax,%rax
66: 75 d2 jne 3a <memcpy+0x3a>
68: 48 8b 45 e8 mov -0x18(%rbp),%rax
6c: 5d pop %rbp
6d: c3 retq
Note the instruction in 1c to 24, three arguments stored on stack by "mov" but not "push", the same as 2c and 34 are the two local variables.
And now is the problem.
I compiled my x86_64 kernel on ubuntu, with gcc default x64 abi(sysv amd64 abi, implicit red zone). When run into this function, called by exec, surely will trigger copy-on-write(means will cause page-fault exception first), the variables address and %RSP look like:
screen shot of debug session 1
You can see the %RSP is adjacent ABOVE the stored args and localvars, so guess what whill happen when exception raised on an x86_64 machine ---- cpu autosave at least 5 registers on stack ---- they override the args and localvars.
And then compiled it with option -mno-red-zone, the beginning part of disassembly:
0000000000000000 <memchr>:
0: f3 0f 1e fa endbr64
4: 55 push %rbp
5: 48 89 e5 mov %rsp,%rbp
8: 48 83 ec 28 sub $0x28,%rsp
c: 48 8d 05 f9 ff ff ff lea -0x7(%rip),%rax # c <memchr+0xc>
Note the difference with the former? It preserve the stack space of args and localvars with
8: 48 83 ec 28 sub $0x28,%rsp
And the running result:screen shot of debug session 2
Now the %RSP is BELOW the args and localvars.
So the core reason is that: in leaf function in normal case, there is no need to adjust %RSP to stack top, so with red-zone mechanism %RSP won't be adjusted. But in kernel, the kernel code and exception/interrrupt code share the kernel-stack(unless you prepare isolate stack for exception/interrupt , for X86_64 cpu it is IST), when leaf function interrupted, args and localvars will be override