我想要做的project它在github中篡改内核。内核版本是linux-3.18.6。
QEMU用于模拟环境。
在我的应用程序中,我尝试通过遵循它们来了解系统调用过程。完成我的目标的方式就像shell程序一样。我只是创建一些命令来运行相关的系统调用。也许这在图片中很简单。 some commands
代码很简单如下:
1使用API GETPID。
int Getpid(int argc, char **argv)
{
pid_t pid;
pid = getpid();
printf("current process's pid:%d\n",pid);
return 0;
}
2直接使用int $ 0x80。
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;
}
因为我的应用程序只是运行在pid 1的进程中,所以每次输入命令getpid时,它都会返回1.当然这是真的。
奇怪的是,当我使用gdb调试系统调用进程时,它只在输入getpid执行时停止在berakpoint sys_getpid一次。当我一次又一次地做,它只是输出而不停止。
显然,使用int $ 0x80是绝对正确的,据我所知。
要解决这个问题,我做了一些研究。 我下载了glibc源码(glibc-2.25)来查看api getpid如何包装int $ 0x80。不幸的是,它不在那里,或者我没有找到正确的位置。
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;
}
如果我得到了错误的代码,请告诉我,tks。
如代码所示,getpid的定义不包含在glibc中。读完一些数据后,有人说the VDSO...。
注意,据我所知,简单的系统调用 成本的显著部分从用户空间将内核和背部。因此,对于某些系统调用 (可能是gettimeofday,getpid ...),VDSO可能会避免即使那 (并在技术上可能会避免做一个真正的系统调用)。
在男子GETPID PGAE:
C库/内核差异 由于glibc的版本2.3.4,为GETPID glibc的包装函数() 缓存的PID,以避免额外的系统调用当进程 重复调用getpid()。正常情况下,这种缓存是不可见的,但其 正确的操作依赖于对分支函数 fork(2),vfork(2)和clone(2)的支持:如果应用程序绕过glibc通过使用这些系统调用的包装系统调用(2),然后调用 getpid()将返回错误的值(准确地说:它会返回父进程的PID)。即使当 通过glibc包装函数调用clone(2)时,getpid()也可能返回错误的值,请参阅clone(2)中的dis- 。
尽管有这么多的解释,我无法弄清楚API getpid的工作过程。
作为对比,API时间很容易理解。时间 定义:
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;
}
然后,
#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)
最后,它是嵌入汇编,采用内核源代码的正常方式。
#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; \
})
有人可以清楚地解释API getpid的工作原理吗?为什么getpid只能陷入syscall sys_getpid一次?如果可能的话,可以推荐一些参考。
感谢您的帮助。
到底什么是你的问题?您已阅读手册:glibc会缓存getpid-syscall返回的值。显然,这个缓存必须在子进程中的fork(2)之后重新设置。 –
感谢您的回答。 getpid使用dlsym的机制是什么?为什么getpid的实现与其他实现不同?这就是我想知道的。谢谢。 –