Consider the following assembly program:
bits 64
global _start
_start:
mov rax, 0x0000111111111111
add byte [rax*1+0x0], al
jmp _start
When you compile this with nasm and ld (on Ubuntu, kernel 5.4.0-48-generic, Ryzen 3900X), you get a segfault:
$ ./segfault-addr
[1] 107116 segmentation fault (core dumped) ./segfault-addr
When you attach gdb you can see the address that caused this fault:
(gdb) p $_siginfo._sifields._sigfault.si_addr
$1 = (void *) 0x111111111111
However, if you set any of the 16 most significant bits to 1 like this:
bits 64
global _start
_start:
mov rax, 0x0001111111111111
add byte [rax*1+0x0], al
jmp _start
You obviously still get a segfault, but now the address is NULL:
(gdb) p $_siginfo._sifields._sigfault.si_addr
$1 = (void *) 0x0
Why is this happening? Is it caused by gdb, Linux, or the CPU itself?
Is there anything I can do to prevent this behavior?