I wrote a sample program to use __kernel_vsyscall for system call
#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;
}
This code which calls exit(42) works fine.
$gcc userprog.c -o userprog -m32
$ ./userprog
$ echo $?
42
But when I tried to call write(1, "hello world", 12), it failed
#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;
}
It fails with segmentation fault.
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.
-
Related: stackoverflow.com/questions/9506353/…dragosht– dragosht2020年01月15日 08:52:49 +00:00Commented Jan 15, 2020 at 8:52
1 Answer 1
That "call *%2" in your inline assembly seems wrong. And you can check this out in gdb quite easily:
(gdb) layout asm
(gdb) break main
Breakpoint 1 at 0x5eb: file test.c, line 31.
(gdb) run
The code generated from the inline asm looks like this for me:
0x5655562b <main+94> mov -0x34(%ebp),%eax
0x5655562e <main+97> mov 0ドルx1,%ebx
0x56555633 <main+102> mov -0x28(%ebp),%ecx
0x56555636 <main+105> mov -0x30(%ebp),%edx
0x56555639 <main+108> call *-0x28(%ebp)
Break at the call address:
(gdb) break *0x56555639
(gdb) c
(gdb) si
Cannot access memory at address 0x6c6c6568)
I think your assembly should look something like this:
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");
Please note you were also missing edx in your clobber list.
answered Jan 15, 2020 at 8:01
dragosht
3,2732 gold badges26 silver badges33 bronze badges
Sign up to request clarification or add additional context in comments.
4 Comments
md.jamal
Thanks for correcting. But this does nor print "hello world" on the screen. Anything more is missing
dragosht
Right. Well, replacing
"m"(buffer) with "r"(buffer) also fixed that for me ...md.jamal
May i know the reason for replacing "m" with "r"
dragosht
I must admit I'm not so well trained in this kind of stuff, but with your original asm code,
ecx was being set up to 0x6c6c6568 which stands for the hell part of the string, so the value instead of it's address. "r" simply fixed that and initialized ecx to the string address on the stack.lang-c