이 코드는 어떤 문제를 푸나요?
시그널 처리기는 원래 프로그램의 실행을 잠깐 빌려 실행됩니다. 처리기가 끝난 뒤 돌아가려면 중단한 상태를 사용자 스택에 보존해야 합니다. arm64는 확장 context record, x86은 FP/xstate를 포함한 프레임, RISC-V는 해당 ABI의 레지스터와 벡터 상태를 사용합니다. 대표로 arm64 프레임 배치 초기화를 읽습니다.
읽을 범위: v6.18.37 · arch/arm64/kernel/signal.c · init_user_layout 156–169행입니다. 아래에 이 범위의 원문과 각 줄의 설명을 실었습니다. 주제 전체의 흐름과 다른 경로는 기존 분석에서 함께 읽으실 수 있습니다.
먼저 알아둘 개념
사용자 프레임
사용자가 수정할 수 있는 메모리입니다. sigreturn은 이 내용을 신뢰하지 않고 복원 가능한 상태인지 검사해야 합니다.
가변 길이 확장
SVE/SME 등 큰 상태를 담기 위해 고정 구조체 뒤에 확장 record 배치가 필요할 수 있습니다.
정렬
스택과 record의 ABI가 요구하는 주소 경계입니다. 단순히 필요한 바이트 수만 더하면 되는 것은 아닙니다.
처음 읽을 때
기본 프레임, 확장 공간, 종료 표시를 한 메모리 그림에 표시하십시오.
더 깊이 살펴볼 때
예약 공간의 한계, extra_context 연결, 복귀 시 권한 검사의 필요성을 이어서 검토하십시오.
그림으로 보는 변화

1. 배치 계산 초기화
레이아웃 계산 구조를 0으로 초기화합니다.
화살표는 커널의 계산 상태 변경이며 사용자 스택 쓰기와 구분합니다.
2. 고정 영역 뒤에서 시작
__reserved까지의 offset을 현재 크기로 삼습니다.
메모리 그림에서 낮은 offset에서 높은 offset으로 공간을 잡습니다.
3. 종료·확장 여유 확보
terminator와 extra_context 공간을 한계에서 뺍니다.
남은 크기는 일반 context record를 배치할 수 있는 여유입니다.
init_user_layout를 한 줄씩 읽기
줄 번호는 v6.18.37 원문 기준입니다. 주석·빈 줄을 포함한 함수 전체를 먼저 보고, 그 아래에서 각 줄을 설명합니다.
static void init_user_layout(struct rt_sigframe_user_layout *user)
{
const size_t reserved_size =
sizeof(user->sigframe->uc.uc_mcontext.__reserved);
memset(user, 0, sizeof(*user));
user->size = offsetof(struct rt_sigframe, uc.uc_mcontext.__reserved);
user->limit = user->size + reserved_size;
user->limit -= TERMINATOR_SIZE;
user->limit -= EXTRA_CONTEXT_SIZE;
/* Reserve space for extension and terminator ^ */
}static void init_user_layout(struct rt_sigframe_user_layout *user)시그널 프레임을 배치할 때 사용할 커널 측 계산 구조를 초기화합니다. 매개변수 이름 user가 곧 __user 메모리라는 뜻은 아닙니다.
const size_t reserved_size =고정 시그널 구조 안에 예약된 확장 공간의 크기를 계산할 상수를 선언합니다.
sizeof(user->sigframe->uc.uc_mcontext.__reserved);sizeof는 __reserved 필드의 타입 크기를 구합니다. 이 표현식은 user->sigframe의 주소를 실제로 역참조하여 사용자 데이터를 읽는 동작이 아닙니다.
memset(user, 0, sizeof(*user));레이아웃 관리 구조 자체를 0으로 만듭니다. 아직 사용자 스택 전체에 시그널 프레임을 복사하는 단계는 아닙니다.
user->size = offsetof(struct rt_sigframe, uc.uc_mcontext.__reserved);고정 프레임 시작에서 __reserved까지의 바이트 거리를 구해 현재 사용 크기의 출발점으로 정합니다.
user->limit = user->size + reserved_size;고정 부분 끝에 reserved_size를 더해 확장 기록이 들어갈 초기 한계를 구합니다.
user->limit -= TERMINATOR_SIZE;마지막 종료 표시가 들어갈 자리를 미리 빼 둡니다. 가변 기록을 가득 채워도 끝을 표시할 공간이 남아야 합니다.
user->limit -= EXTRA_CONTEXT_SIZE;추가 확장 영역을 가리킬 extra_context 공간도 미리 확보합니다. 일반 기록의 여유 공간과 관리용 공간을 구분합니다.
함께 생각해 볼 질문
memset(user)는 사용자 스택을 지웁니까?
이 함수의 user는 레이아웃 관리 구조체 포인터입니다. 이름만 보고 사용자 주소라고 판단하면 안 됩니다.
시그널 처리기가 return만 하면 커널 상태가 복원됩니까?
트램펄린과 rt_sigreturn 경로가 프레임을 읽고 검사하여 복원합니다.
큰 벡터 상태는 시그널 비용에 영향을 줍니까?
예. 저장할 데이터와 프레임 크기가 증가할 수 있습니다.
출처와 읽은 범위
Linux stable v6.18.37 · arch/arm64/kernel/signal.c
해당 버전 원본 파일 · 기존 코드 분석 · 설명 원고
