使用 __kernel_vsyscall 调用写入系统调用不起作用
Using __kernel_vsyscall to call write system call not working
我写了一个示例程序来使用 __kernel_vsyscall
进行系统调用
#include <stdio.h>
#include <sys/auxv.h>
int main()
{
unsigned long sysinfo = getauxval(AT_SYSINFO);
unsigned long syscall_num = 1; // 1 is system call number for exit
long exit_status = 42;
asm ("movl %0, %%eax\n"
"movl %1, %%ebx\n"
"call *%2"
:
:"m" (syscall_num), "m" (exit_status), "m" (sysinfo)
:"eax", "ebx");
printf("sysinfo:%lx\n", sysinfo);
return 0;
}
这段调用 exit(42)
的代码工作正常。
$gcc userprog.c -o userprog -m32
$ ./userprog
$ echo $?
42
但是当我尝试调用 write(1, "hello world", 12)
时,它失败了
#include <stdio.h>
#include <sys/auxv.h>
int main()
{
unsigned long sysinfo = getauxval(AT_SYSINFO);
unsigned long syscall_num = 4; // 4 is system call number for write
char buffer[] = "hello world";
int buffer_length = sizeof(buffer);
asm ("movl %0, %%eax\n"
"movl %1, %%ebx\n"
"movl %2, %%ecx\n"
"movl %3, %%edx\n"
"call *%2"
:
:"m" (syscall_num), "i"(1), "m" (buffer), "m"(buffer_length)
:"eax", "ebx", "ecx");
printf("sysinfo:%lx\n", sysinfo);
return 0;
}
由于分段错误而失败。
dmesg:
[43453.401815] userprog[13528]: segfault at 6c6c6568 ip 000000006c6c6568 sp 00000000ffc647ac error 14 in libc-2.27.so[f7cf3000+1d2000]
[43453.401821] Code: Bad RIP value.
你的内联汇编中的 "call *%2"
似乎是错误的。您可以很容易地在 gdb
中查看:
(gdb) layout asm
(gdb) break main
Breakpoint 1 at 0x5eb: file test.c, line 31.
(gdb) run
从内联 asm 生成的代码对我来说是这样的:
0x5655562b <main+94> mov -0x34(%ebp),%eax
0x5655562e <main+97> mov [=11=]x1,%ebx
0x56555633 <main+102> mov -0x28(%ebp),%ecx
0x56555636 <main+105> mov -0x30(%ebp),%edx
0x56555639 <main+108> call *-0x28(%ebp)
在调用地址中断:
(gdb) break *0x56555639
(gdb) c
(gdb) si
Cannot access memory at address 0x6c6c6568)
我认为您的程序集应该如下所示:
asm ("movl %0, %%eax\n"
"movl %1, %%ebx\n"
"movl %2, %%ecx\n"
"movl %3, %%edx\n"
"call *%4"
:
:"m" (syscall_num), "i"(1), "m" (buffer), "m"(buffer_length), "m"(sysinfo)
:"eax", "ebx", "ecx", "edx");
请注意,您的 clobber 列表中也缺少 edx
。
我写了一个示例程序来使用 __kernel_vsyscall
进行系统调用
#include <stdio.h>
#include <sys/auxv.h>
int main()
{
unsigned long sysinfo = getauxval(AT_SYSINFO);
unsigned long syscall_num = 1; // 1 is system call number for exit
long exit_status = 42;
asm ("movl %0, %%eax\n"
"movl %1, %%ebx\n"
"call *%2"
:
:"m" (syscall_num), "m" (exit_status), "m" (sysinfo)
:"eax", "ebx");
printf("sysinfo:%lx\n", sysinfo);
return 0;
}
这段调用 exit(42)
的代码工作正常。
$gcc userprog.c -o userprog -m32
$ ./userprog
$ echo $?
42
但是当我尝试调用 write(1, "hello world", 12)
时,它失败了
#include <stdio.h>
#include <sys/auxv.h>
int main()
{
unsigned long sysinfo = getauxval(AT_SYSINFO);
unsigned long syscall_num = 4; // 4 is system call number for write
char buffer[] = "hello world";
int buffer_length = sizeof(buffer);
asm ("movl %0, %%eax\n"
"movl %1, %%ebx\n"
"movl %2, %%ecx\n"
"movl %3, %%edx\n"
"call *%2"
:
:"m" (syscall_num), "i"(1), "m" (buffer), "m"(buffer_length)
:"eax", "ebx", "ecx");
printf("sysinfo:%lx\n", sysinfo);
return 0;
}
由于分段错误而失败。
dmesg:
[43453.401815] userprog[13528]: segfault at 6c6c6568 ip 000000006c6c6568 sp 00000000ffc647ac error 14 in libc-2.27.so[f7cf3000+1d2000]
[43453.401821] Code: Bad RIP value.
你的内联汇编中的 "call *%2"
似乎是错误的。您可以很容易地在 gdb
中查看:
(gdb) layout asm
(gdb) break main
Breakpoint 1 at 0x5eb: file test.c, line 31.
(gdb) run
从内联 asm 生成的代码对我来说是这样的:
0x5655562b <main+94> mov -0x34(%ebp),%eax
0x5655562e <main+97> mov [=11=]x1,%ebx
0x56555633 <main+102> mov -0x28(%ebp),%ecx
0x56555636 <main+105> mov -0x30(%ebp),%edx
0x56555639 <main+108> call *-0x28(%ebp)
在调用地址中断:
(gdb) break *0x56555639
(gdb) c
(gdb) si
Cannot access memory at address 0x6c6c6568)
我认为您的程序集应该如下所示:
asm ("movl %0, %%eax\n"
"movl %1, %%ebx\n"
"movl %2, %%ecx\n"
"movl %3, %%edx\n"
"call *%4"
:
:"m" (syscall_num), "i"(1), "m" (buffer), "m"(buffer_length), "m"(sysinfo)
:"eax", "ebx", "ecx", "edx");
请注意,您的 clobber 列表中也缺少 edx
。