首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >glibc中的getpid工作流程是什么?

glibc中的getpid工作流程是什么?
EN

Stack Overflow用户
提问于 2017-04-06 08:25:12
回答 1查看 1.6K关注 0票数 1

情况如下:

我正在尝试做项目,它破解了github中的内核。内核版本是Linux3.18.6。

使用QEMU模拟环境。

在我的应用程序中,我试图通过遵循them.The方式来理解syscall过程,以完成我的目标就像shell程序一样。我只是创建一些命令来运行相对的syscall。也许这张照片很简单。一些命令

代码很简单,如下所示:

1使用。

代码语言:javascript
运行
复制
int Getpid(int argc, char **argv)
{
    pid_t pid;
    pid = getpid();
    printf("current process's pid:%d\n",pid);
    return 0;
}

2直接使用int $0x80。

代码语言:javascript
运行
复制
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调试syscall进程时,当我输入getpid执行时,它只在berakpoint sys_getpid停止一次。当我一次又一次地做这件事时,它只是不停地输出。

显然,正如我所理解的,int $0x80的使用是绝对正确的。

为了解决这个问题,我做了一些研究。我下载了glibc源代码(glibc-2.25),以了解api getpid如何包装$0x80。不幸的是,它不在那里,或者我只是找不到合适的位置。

一些在glibc中的代码。

代码语言:javascript
运行
复制
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;
}

如果我搞错了密码,请告诉我,塔克。

如代码所示,getpid的定义不包含在glibc中。在阅读了一些数据后,有人说是VDSO..。

注意,AFAIK,简单系统成本的很大一部分是从用户空间转移到内核和后台的。因此,对于一些系统(可能是一天的时间,getpid .)VDSO甚至可以避免这种情况(技术上也可能避免执行真正的syscall)。

在这个男人身上:

C库/内核差异,因为glibc版本2.3.4,getpid()的glibc包装函数缓存PID,以便在进程反复调用getpid()时避免额外的系统调用。通常,这种缓存是不可见的,但是它的正确操作依赖于对fork(2)、v叉(2)和克隆(2)的包装函数的支持:如果应用程序通过使用syscall(2)绕过这些系统调用的glibc包装器,那么在子进程中调用getpid()将返回错误的值(准确地说:它将返回父进程的PID )。关于getpid()甚至在通过glibc包装函数调用克隆(2)时也可能返回错误值的情况,请参见克隆(2)。

虽然有这么多解释,我还是搞不懂API的工作过程。

相比之下,API时间很容易理解。时间的定义:

代码语言:javascript
运行
复制
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;
}

然后,

代码语言:javascript
运行
复制
#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)

最后,它是嵌入式asm,通常使用内核源代码的方式。

代码语言:javascript
运行
复制
#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一次?如果可能的话,有些推荐信是值得赞赏的。

谢谢你的帮助。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-04-06 09:19:30

首先,请注意,glibc源代码几乎不可能导航。

正如您已经注意到的,文档声明getpid()缓存其结果。你找到的代码看起来像

代码语言:javascript
运行
复制
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;
}

不过是个包装。它查找一个getpid符号,并调用该函数。这个功能就是你需要找到的。它被别名为__getpid()函数,您将在sysdeps/unix/sysv/linux/getpid.c文件中找到该函数,并且本文的底部也显示了这个函数。

现在--您可能正在查看与当前glibc不匹配的glibc源代码--2016年11月此承诺中的getpid()缓存发生了很大变化,据我所知,更改将是2017年2月发布的glibc-2.25的一部分。

缓存其值以避免多次调用getpid() syscall的旧的getpid()实现可以在下面看到:http://repo.or.cz/glibc.git/blob/93eb85ceb25ee7aff432ddea0abf559f53d7a5fc:/sysdeps/unix/sysv/linux/getpid.c,如

代码语言:javascript
运行
复制
static inline __attribute__((always_inline)) pid_t
really_getpid (pid_t oldval)
{
  if (__glibc_likely (oldval == 0))
    {
      pid_t selftid = THREAD_GETMEM (THREAD_SELF, tid);
      if (__glibc_likely (selftid != 0))
    return selftid;
    }

  INTERNAL_SYSCALL_DECL (err);
  pid_t result = INTERNAL_SYSCALL (getpid, err, 0);

  /* We do not set the PID field in the TID here since we might be
     called from a signal handler while the thread executes fork.  */
  if (oldval == 0)
    THREAD_SETMEM (THREAD_SELF, tid, result);
  return result;
}
#endif

pid_t
__getpid (void)
{
#if !IS_IN (libc)
  INTERNAL_SYSCALL_DECL (err);
  pid_t result = INTERNAL_SYSCALL (getpid, err, 0);
#else
  pid_t result = THREAD_GETMEM (THREAD_SELF, pid);
  if (__glibc_unlikely (result <= 0))
    result = really_getpid (result);
#endif
  return result;
}

libc_hidden_def (__getpid)
weak_alias (__getpid, getpid)
libc_hidden_def (getpid)
票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/43249684

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档