|
@@ -100,12 +100,19 @@ asm (
|
|
|
" shl $32, %r8\n"
|
|
|
" orq $0x7f7f7f7f, %r8\n"
|
|
|
" movq %r8, %r9\n"
|
|
|
- " movq %r8, %r10\n"
|
|
|
- " movq %r8, %r11\n"
|
|
|
- " movq %r8, %r12\n"
|
|
|
- " movq %r8, %r13\n"
|
|
|
- " movq %r8, %r14\n"
|
|
|
- " movq %r8, %r15\n"
|
|
|
+ " incq %r9\n"
|
|
|
+ " movq %r9, %r10\n"
|
|
|
+ " incq %r10\n"
|
|
|
+ " movq %r10, %r11\n"
|
|
|
+ " incq %r11\n"
|
|
|
+ " movq %r11, %r12\n"
|
|
|
+ " incq %r12\n"
|
|
|
+ " movq %r12, %r13\n"
|
|
|
+ " incq %r13\n"
|
|
|
+ " movq %r13, %r14\n"
|
|
|
+ " incq %r14\n"
|
|
|
+ " movq %r14, %r15\n"
|
|
|
+ " incq %r15\n"
|
|
|
" ret\n"
|
|
|
" .code32\n"
|
|
|
" .popsection\n"
|
|
@@ -128,12 +135,13 @@ int check_regs64(void)
|
|
|
int err = 0;
|
|
|
int num = 8;
|
|
|
uint64_t *r64 = ®s64.r8;
|
|
|
+ uint64_t expected = 0x7f7f7f7f7f7f7f7fULL;
|
|
|
|
|
|
if (!kernel_is_64bit)
|
|
|
return 0;
|
|
|
|
|
|
do {
|
|
|
- if (*r64 == 0x7f7f7f7f7f7f7f7fULL)
|
|
|
+ if (*r64 == expected++)
|
|
|
continue; /* register did not change */
|
|
|
if (syscall_addr != (long)&int80) {
|
|
|
/*
|
|
@@ -147,18 +155,17 @@ int check_regs64(void)
|
|
|
continue;
|
|
|
}
|
|
|
} else {
|
|
|
- /* INT80 syscall entrypoint can be used by
|
|
|
+ /*
|
|
|
+ * INT80 syscall entrypoint can be used by
|
|
|
* 64-bit programs too, unlike SYSCALL/SYSENTER.
|
|
|
* Therefore it must preserve R12+
|
|
|
* (they are callee-saved registers in 64-bit C ABI).
|
|
|
*
|
|
|
- * This was probably historically not intended,
|
|
|
- * but R8..11 are clobbered (cleared to 0).
|
|
|
- * IOW: they are the only registers which aren't
|
|
|
- * preserved across INT80 syscall.
|
|
|
+ * Starting in Linux 4.17 (and any kernel that
|
|
|
+ * backports the change), R8..11 are preserved.
|
|
|
+ * Historically (and probably unintentionally), they
|
|
|
+ * were clobbered or zeroed.
|
|
|
*/
|
|
|
- if (*r64 == 0 && num <= 11)
|
|
|
- continue;
|
|
|
}
|
|
|
printf("[FAIL]\tR%d has changed:%016llx\n", num, *r64);
|
|
|
err++;
|