사용자와 커널 가상 주소 사이의 관계는 이전의 여러 질문(아래 링크)에서 논의되었지만, 제가 이해하는 한 사용자 프로세스는할 수 없다커널 주소를 읽거나 씁니다.
그래서,어떻게사용자 프로세스가 커널에서 데이터를 공유하고 수신합니까?
기억을 통해서인가? 그렇다면 메모리 레이아웃은 어디에 있습니까? 어쩌면 CPU 레지스터일까요?
관련 질문:
답변1
예를 들어 보겠습니다. 간단한 x86안녕하세요 세계메시지를 인쇄 stdout
하고 종료하는 Linux 프로그램입니다. 여러 데이터 항목을 커널에 전달해야 합니다.
- 출력할 텍스트 문자열,
- 종료 코드.
FASM으로 컴파일된 어셈블리 코드는 다음과 같습니다.
format ELF executable
segment readable executable
; system call numbers
SYS_EXIT=1
SYS_WRITE=4
; file descriptors
STDOUT=1
entry $
start:
mov eax, SYS_WRITE
mov ebx, STDOUT
mov ecx, message
mov edx, messageLength
int 0x80
mov eax, SYS_EXIT
xor ebx, ebx ; exit code 0
int 0x80
message:
db "Hello, world!",0xa
messageLength=$-message
이 프로그램이 주요 목표(메시지 출력)를 달성하기 위해 수행하는 모든 작업은 다음과 같습니다.
sys_write
stdout
시스템 호출 번호(syscall용), 파일 설명자( ), 메시지 주소 및 메시지 길이를 나타내는 값 으로 적절한 CPU 레지스터를 설정합니다.- 이 경우 소프트웨어 인터럽트 0x80을 통해 시스템 호출을 수행합니다.
종료에도 비슷한 순서가 있습니다. 레지스터를 시스템 호출 번호와 종료 코드로 설정한 다음 시스템 호출을 실행합니다.
어떤 레지스터가 어떤 값으로 설정되는지는 시스템 호출에 의해 정의됩니다.호출 규칙.
커널이 시스템 호출 핸들러 실행을 시작한 후 핸들러는 애플리케이션의 컨텍스트에서 레지스터 값을 읽고 호출 규칙에 따라 해석합니다. 특히 시스템 호출을 보면 sys_write
메시지의 길이와 주소를 가져와 이를 사용하여 사용자 공간 메모리에서 읽습니다. 그런 다음 이 데이터(파일 설명자와 함께)가 실제 작업을 수행할 드라이버에 전달됩니다.
답변2
사용자 프로세스가 커널 주소를 읽거나 쓸 수 없습니다.
아니요. 하지만 커널은 필요에 따라 사용자 주소를 읽고 쓸 수 있습니다. Linux 시스템 호출은 CPU 레지스터의 시스템 호출 번호와 매개변수를 전달합니다. ("Linux 시스템 호출 호출 규칙"과 같은 것을 찾으십시오.)
이러한 인수 중 일부는 포인터일 수 있으며, 이 경우 커널은 사용자 주소 공간의 지정된 위치에서 데이터를 찾는 방법을 알고 있습니다. 내가 이해한 바로는 커널은 데이터를 사용하기 전에 실제로 데이터를 커널 공간에 복사합니다. (그렇지 않으면 다른 사용자 공간 스레드가 시스템 호출 중에 데이터를 수정할 수 있습니다.) 그러나 데이터 위치는 프로그램 요구 사항에 따라 사용자 주소 공간의 어느 위치에나 있을 수 있습니다.