상황은 다음과 같습니다 :glibc의 getpid 작업 절차는 무엇입니까?
나는 github에서 커널을 해킹하는 project을하려고합니다. 커널 버전은 linux-3.18.6입니다.
QEMU는 환경을 시뮬레이트하는 데 사용됩니다.
내 응용 프로그램에서 나는 그들을 따라가 syscall 프로 시저를 이해하려고 시도합니다. 내 목표를 완료하는 방법은 쉘 프로그램과 같습니다. 상대 시스템 호출을 실행하기위한 명령을 작성합니다. 어쩌면 사진을 통해 간단 할 수도 있습니다.
1 사용 API의 GETPID을 다음과 같이 some commands
코드는 간단하다.
int Getpid(int argc, char **argv)
{
pid_t pid;
pid = getpid();
printf("current process's pid:%d\n",pid);
return 0;
}
2 int $ 0x80을 직접 사용하십시오.
내 응용 프로그램이 단지 pid 1로 실행되기 때문에 getpid 명령을 입력 할 때마다 1을 반환합니다. 물론 사실입니다.
이상한 일은 gysc를 사용하여 syscall 프로세스를 디버깅 할 때 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;
}
잘못된 코드가있는 경우 알려주십시오.
코드에서 알 수 있듯이 getpid의 정의는 glibc에 포함되어 있지 않습니다. 일부 데이터를 읽은 후 누군가가 the VDSO...라고 말했습니다.
간단한 시스템 콜 비용 의 상당 부분을 차지하는 AFAIK는 사용자 공간에서 커널로 돌아가는 중입니다. 따라서 일부 시스템 호출의 경우 (아마도 gettimeofday, getpid ...) VDSO는 심지어 을 피할 수 있습니다 (기술적으로는 실제 시스템 콜을하지 않을 수도 있음). 사람 GETPID pgae에서
: glibc는 버전 2.3.4, GETPID에 대한 glibc는 래퍼 기능() 캐시의 PID, 이후
C 라이브러리/커널 차이 추가 시스템 호출을 피하기 위해 프로세스가 getpid()를 반복적으로 호출 할 때.일반적으로이 캐싱은 표시되지 않지만 올바른 작업은 fork (2), vfork (2) 및 clone (2)에 대한 래퍼 함수의 지원에 의존합니다. 응용 프로그램이 glibc 래퍼를 무시하고 syscall (2)를 호출하면 자식에서 getpid()를 호출하면 잘못된 값이 반환됩니다. 정확히 말하면 은 부모 프로세스의 PID를 반환합니다. disgl35c wrapper 함수를 통해 을 호출 할 때 getpid()가 잘못된 값을 반환 할 수있는 경우를 clone (2)를 참조하십시오.
많은 설명이 끝나기는하지만 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)
마지막으로, 임베디드 것 ASM, 커널 소스를 사용하는 일반적인 방법.
#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) 후에 다시 설정되어야합니다. –
답변 해 주셔서 감사합니다. dlsym을 사용하는 getpid의 메커니즘은 무엇입니까? 왜 getpid의 실현은 다른 것들과 다른가요? 그게 내가 알고 싶은 것. 감사. –