Linux 5.0-rc5 소스 코드를 살펴보던 중 arch/x86/entry/syscalls/syscall_64.tbl
x32에 대한 별도의 시스템 호출 번호가 없다는 것을 발견했습니다 mmap
.
그렇다면 우리가 사용자 공간에서 x32 ABI를 사용하고 있어 4GiB 이상의 매핑된 주소를 제공하지 않는다는 것을 커널이 어떻게 알 수 있을까요?
또는 일반적으로 주소를 반환할 수 있는 시스템 호출은 우리가 x32를 사용하고 있고 4GiB 이상을 반환하지 않는다는 것을 어떻게 알 수 있습니까?
답변1
x32 시스템 호출을 하려는 프로세스는 시스템 호출 번호에 비트가 설정되어 커널이 이를 구별할 수 있습니다.
syscall(2) 맨페이지에서:
[5] The x32 ABI uses the same instruction as the x86_64 ABI and is used on the same processors. To differentiate between them, the bit mask __X32_SYSCALL_BIT is bitwise-ORed into the system call number for system calls under the x32 ABI. Both system call tables are available though, so setting the bit is not a hard requirement.
x32는 진정한 독립형 환경이 아닙니다. x32 프로그램은 x64 시스템 호출을 수행할 수 있으며 그 반대도 마찬가지입니다. 이는 x64 및 x32와 병렬로 지원될 수도 있는 ia32 에뮬레이션과 다릅니다.
이 비트는 다음 함수를 통해 커널에서 확인됩니다 in_x32_syscall()
.
static inline bool in_x32_syscall(void)
{
#ifdef CONFIG_X86_X32_ABI
if (task_pt_regs(current)->orig_ax & __X32_SYSCALL_BIT)
return true;
#endif
return false;
}
커널 코드가 mmap()
이를 구현하는 위치를 찾는 것은 독자의 연습 과제로 남겨집니다(어렵지 않습니다). x32 바이너리의 execve()의 경우 커널은 __X32_SYSCALL_BIT
저장된 레지스터(시스템 호출 번호)에 명시적으로 자체적으로 설정됩니다.RAX
답변2
다음 함수 서명을 보면 mmap
:
void *mmap(void *addr, size_t length, int prot, int flags,
int fd, off_t offset);
length
메모리 크기( )가 매개변수라는 것을 알 수 있습니다 size_t
.
이제 size_t
그것은플랫폼 종속성유형. size_t
32비트 플랫폼에서는 32비트이고, 64비트 플랫폼에서는 64비트입니다.
마찬가지이다 void *
. 32비트 아키텍처의 포인터는 32비트 주소입니다.
따라서 커널은 알 필요가 없으며 컴파일러는 실제로 이에 대해 관심을 갖습니다.