【问题标题】:Using __kernel_vsyscall to call write system call not working使用 __kernel_vsyscall 调用 write 系统调用不起作用
【发布时间】:2020-01-15 06:21:12
【问题描述】:

我写了一个示例程序来使用__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.

【问题讨论】:

标签: c linux system-calls vdso


【解决方案1】:

您的内联汇编中的 "call *%2" 似乎是错误的。您可以在gdb 中轻松查看:

(gdb) layout asm
(gdb) break main
    Breakpoint 1 at 0x5eb: file test.c, line 31.
(gdb) run

从内联汇编生成的代码对我来说如下所示:

0x5655562b <main+94>    mov    -0x34(%ebp),%eax
0x5655562e <main+97>    mov    $0x1,%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

【讨论】:

  • 感谢指正。但这不会在屏幕上打印“hello world”。还缺少什么
  • 对。好吧,用"r"(buffer) 替换"m"(buffer) 也为我解决了这个问题......
  • 我可以知道将“m”替换为“r”的原因
  • 我必须承认我在这类东西方面没有受过很好的训练,但是使用你原来的 asm 代码,ecx 被设置为0x6c6c6568,它代表hell 部分的字符串,所以值而不是它的地址。 "r" 只是修复了这个问题并将ecx 初始化为堆栈上的字符串地址。
猜你喜欢
  • 2012-10-29
  • 1970-01-01
  • 2021-01-13
  • 1970-01-01
  • 1970-01-01
  • 2014-02-22
  • 1970-01-01
  • 2017-09-12
  • 1970-01-01
相关资源
最近更新 更多