The situation is as below:
I am trying to do the project which hacks the kernel in github. Kernel version is linux-3.18.6.
QEMU is used to simulate the environment.
In my application, I try to understand the syscall procedure by follow them.The way to complete my aim is just like the shell program. I just create some commands to run the relative syscall. Maybe it's simple through the picture. some commands
Code is simple as follows:
1 Use API getpid.
int Getpid(int argc, char **argv)
{
pid_t pid;
pid = getpid();
printf("current process's pid:%d\n",pid);
return 0;
}
2 Use int $0x80 directly.
int GetpidAsm(int argc, char **argv)
{
pid_t pid;
asm volatile(
"mov $20, %%eax\n\t"
"int $0x80\n\t"
"mov %%eax, %0\n\t"
:"=m"(pid)
);
printf("current process's pid(ASM):%d\n",pid);
return 0;
}
Because my application just run in the process with pid 1, so every time I type command getpid, it returns 1. Of course that's true.
The weird thing is that when I use gdb to debug the syscall process, it stops at the berakpoint sys_getpid only once when I type getpid to execute. When I do it again and again, it just outputs without stopping.
Obviously, the use of int $0x80 is absolutely correct as I understand.
To fix the problem, I did some research. I download the glibc source(glibc-2.25) code to see how the api getpid wraps int $0x80. Unfortunately, it wasn't there or I just didn't find the right position.
some code in glibc.
pid_t getpid(void)
{
pid_t (*f)(void);
f = (pid_t (*)(void)) dlsym (RTLD_NEXT, "getpid");
if (f == NULL)
error (EXIT_FAILURE, 0, "dlsym (RTLD_NEXT, \"getpid\"): %s", dlerror ());
return (pid2 = f()) + 26;
}
If I got the wrong code, please tell me,tks.
As the code indicates, the definition of getpid is not contained in glibc. After read some data, someone said the VDSO....
Notice that, AFAIK, a significant part of the cost of simple syscalls is going from user-space to kernel and back. Hence, for some syscalls (probably gettimeofday, getpid ...) the VDSO might avoid even that (and technically might avoid doing a real syscall).
In the man getpid pgae:
C library/kernel differences Since glibc version 2.3.4, the glibc wrapper function for getpid() caches PIDs, so as to avoid additional system calls when a process calls getpid() repeatedly. Normally this caching is invisible, but its correct operation relies on support in the wrapper functions for fork(2), vfork(2), and clone(2): if an application bypasses the glibc wrappers for these system calls by using syscall(2), then a call to getpid() in the child will return the wrong value (to be precise: it will return the PID of the parent process). See also clone(2) for dis‐ cussion of a case where getpid() may return the wrong value even when invoking clone(2) via the glibc wrapper function.
Though there exit so many explain, I can't figure out the work procedure of API getpid.
As a contrast, API time is easy to understand. The definition of time:
time_t
time (time_t *t)
{
INTERNAL_SYSCALL_DECL (err);
time_t res = INTERNAL_SYSCALL (time, err, 1, NULL);
/* There cannot be any error. */
if (t != NULL)
*t = res;
return res;
}
then,
#define INTERNAL_SYSCALL(name, err, nr, args...) \
internal_syscall##nr ("li\t%0, %2\t\t\t# " #name "\n\t", \
"IK" (SYS_ify (name)), \
0, err, args)
Finally, it's embedded asm, the normal way to use kernel source.
#define internal_syscall1(v0_init, input, number, err, arg1) \
({ \
long _sys_result; \
\
{ \
register long __s0 asm ("$16") __attribute__ ((unused)) \
= (number); \
register long __v0 asm ("$2"); \
register long __a0 asm ("$4") = (long) (arg1); \
register long __a3 asm ("$7"); \
__asm__ volatile ( \
".set\tnoreorder\n\t" \
v0_init \
"syscall\n\t" \
".set reorder" \
: "=r" (__v0), "=r" (__a3) \
: input, "r" (__a0) \
: __SYSCALL_CLOBBERS); \
err = __a3; \
_sys_result = __v0; \
} \
_sys_result; \
})
Can somebody explain clearly how the API getpid works? Why the getpid just trap into the syscall sys_getpid only once? Some references is admired if possible.
Thanks for your help.