DUJINLABS.COM

Linux v6.18.37 · ARM64

kuser32.S — 말로 풀어 읽기

이 파일은 왜 필요한가요?

64비트 커널이 32비트 사용자 프로그램에 제공할 작은 도우미 코드를 담는 파일입니다. .inst에 적힌 숫자는 AArch32 명령의 인코딩입니다. 커널이 그 명령을 자기 실행 흐름에서 바로 실행하는 것이 아니라, 사용자에게 매핑할 코드 바이트로 포함합니다.

명령·지시문·라벨을 원본 줄 번호에 맞춰 설명합니다. 주석과 빈 줄을 포함한 전체 원문은 아래에 따로 두었습니다. 매크로 정의와 조건부 코드는 모두 차례대로 실행되는 명령 목록이 아닙니다.

기존 코드 분석과 함께 읽기 · 원본 파일 · 설명 원고

먼저 알아둘 개념: 전처리·어셈블·링크·실행, 어셈블러 지시문, 경쟁과 원자적 변경, 비교 결과와 조건 분기, 호출 규약

처음 읽을 때

비교 후 교환은 먼저 값이 기대와 같은지 확인한 뒤 새 값을 쓰는 작업입니다. 두 작업 사이에 다른 CPU가 값을 바꾸지 않았는지를 배타적 저장 결과로 확인합니다.

더 깊이 살펴볼 때

비교 불일치와 배타적 저장 실패는 다른 사건입니다. 반복 분기가 어느 경우에만 실행되는지 EQ 조건과 상태 레지스터를 따라가 보세요. release 저장과 DMB의 역할도 구분합니다.

한 줄씩 레지스터와 메모리 상태 보기

각 코드 아래의 ‘행 그림’을 펼치면, 그 줄에서 읽는 값과 실행 전·후의 상태를 나란히 볼 수 있습니다. 여기서 ‘명령 직전’은 지금 보고 있는 명령이 실행되기 바로 전을 뜻합니다. 함수 진입 때나 소스의 바로 윗줄을 가리키는 말은 아닙니다. 앞서 실행한 명령이 값을 바꿨다면 그 결과가 들어 있습니다.

소스로 정해지는 상수, 호출자가 넘기는 값, 실제 실행에서 정해지는 주소를 구분해서 읽어야 합니다. 주소 숫자를 몰라도 무엇을 가리키는지와 어디서 받아 오는지는 설명할 수 있습니다. ‘명령 직전 x0의 값’처럼 일반 표기로 남은 곳은 한 명령의 동작을 나타내며, 특정 호출 경로의 값까지 확인했다는 뜻은 아닙니다.

일반 명령은 그 한 줄의 효과를, 매크로는 여러 명령을 묶은 주요 결과를 표시합니다. 함수 호출은 호출 직후의 PC와 LR까지만 나타냅니다. 메모리 접근은 정상적으로 끝나는 경우를 가정합니다. 생략된 항목까지 모두 보존된다는 뜻은 아닙니다.

화살표 →는 같은 항목의 전후 비교입니다. 메모리 칸에는 주소와 크기를 따로 적었습니다. SP가 줄어들면 낮은 주소 쪽을 사용하며, 화면의 위아래와 메모리 주소 방향은 별개입니다. 전처리·어셈블·링크 지시문은 CPU 실행과 구분합니다.

‘이전·다음 행’은 소스에 적힌 순서입니다. 분기·반복·호출이 있으므로 파일 위에서 아래로 실제 실행된다고 가정하지 않습니다. 값이 여러 줄에 걸쳐 이어지는 모습은 cpu-reset.S의 단계별 예제에서 보실 수 있습니다.

총 44개 줄에 그림을 붙였습니다. 기존 코드와 설명은 그 아래에서 이어집니다.

먼저 그림으로 살펴보기

고정 주소에 놓이는 AArch32 보조 코드
화살표: 처리 흐름입니다. 조건이 적힌 단계에서는 해당 조건에 따라 경로가 갈립니다.

데이터로 포함한 사용자 코드

원본 1–22행

#include <asm/unistd.h>

ARM64의 시스템 호출 관련 정의를 포함합니다. 다만 아래 helper는 syscall 명령을 수행하는 래퍼가 아니라 사용자 공간에 매핑된 AArch32 명령으로 비교·교환, 장벽, TLS 조회를 직접 수행합니다. #include는 전처리 단계에서 헤더 내용을 가져옵니다. CPU가 이 줄에서 함수를 호출하는 동작은 없습니다.

16행 그림 · 전처리 단계
소스
처리 전전처리 전
이 줄의 효과#include <asm/unistd.h>
CPU 레지스터
처리 전해당 없음
이 줄의 효과실행되는 CPU 명령이 없습니다.

→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.

	.section .rodata

32비트 호환 프로그램에 제공할 명령 바이트를 커널의 읽기 전용 데이터 영역에 둡니다. ARM64 커널이 이곳을 직접 실행하는 대신, 나중에 AArch32 사용자용 고정 주소 페이지로 복사하여 실행 가능하게 매핑합니다. 이는 빌드 중 출력할 바이트의 섹션을 선택하는 지시문이며, 실행 중 PC나 SP를 옮기지 않습니다.

18행 그림 · 어셈블·링크 단계
빌드 도구
처리 전소스의 명령·배치 표기
이 줄의 효과.section .rodata
CPU 레지스터
처리 전해당 없음
이 줄의 효과지시문 자체는 레지스터를 쓰지 않습니다.

→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.

	.align	5

첫 helper를 32바이트 경계에 맞춥니다. 이 파일은 각 helper의 고정 주소와 마지막 버전 필드 위치를 맞춰야 하므로 정렬이 ABI의 일부입니다. AArch64의 .align 인자는 바이트 수가 아니라 2의 지수입니다. 빌드할 때 필요한 패딩을 넣어 그 경계를 맞춥니다.

19행 그림 · 어셈블·링크 단계
빌드 도구
처리 전소스의 명령·배치 표기
이 줄의 효과.align 5
CPU 레지스터
처리 전해당 없음
이 줄의 효과지시문 자체는 레지스터를 쓰지 않습니다.

→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.

	.globl	__kuser_helper_start

helper 블록의 시작 심볼을 다른 파일에서도 참조할 수 있게 합니다. vdso.c가 복사할 바이트 범위를 계산할 때 끝 심볼과 함께 사용합니다. 이 표기는 심벌을 다른 오브젝트에서도 참조할 수 있게 하며 CPU가 실행하는 명령을 추가하지 않습니다.

20행 그림 · 어셈블·링크 단계
빌드 도구
처리 전소스의 명령·배치 표기
이 줄의 효과.globl __kuser_helper_start
CPU 레지스터
처리 전해당 없음
이 줄의 효과지시문 자체는 레지스터를 쓰지 않습니다.

→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.

__kuser_helper_start:

AArch32 사용자 helper 바이트 블록의 시작입니다. 시작·끝 사이의 데이터를 사용자에게 매핑할 helper 페이지에 복사합니다. 레이블은 이 위치에 붙인 이름이며, 이름을 적는 것만으로 CPU 명령이 추가되지는 않습니다.

21행 그림 · 위치에 이름 붙이기
레이블
처리 전현재 배치 위치
이 줄의 효과__kuser_helper_start
CPU 레지스터
처리 전그대로
이 줄의 효과레이블 자체가 값을 바꾸지 않습니다.

→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.

64비트 비교 후 교환

원본 23–37행

비교 불일치와 배타적 저장 실패는 다릅니다

비교 불일치와 배타적 저장 실패는 다릅니다의 세 단계 비교
A와 B는 가상 값입니다. 화살표는 메모리 읽기·쓰기 방향이며, 배타적 저장 실패는 비교 불일치와 구분합니다.

움직임으로 따라가기 · 재생하거나 한 단계씩 고정해 보실 수 있습니다.

비교 불일치와 배타적 저장 실패는 다릅니다 · 1단계

1단계 고정

GIF 원본 열기

그림의 각 단계를 글로 읽기

1. 현재 값 읽기

이 예제는 기대값과 현재 값이 같아서 저장을 시도할 수 있습니다.

2. 동시 접근으로 저장 실패

비교가 맞아도 배타적 저장은 실패할 수 있어 다시 읽고 검사합니다.

3. 재검사 뒤 저장 성공

재검사에서 기대값과 다르면 실패로 끝납니다. 언제나 성공하는 반복이 아닙니다.

__kuser_cmpxchg64:			// 0xffff0f60

0xffff0f60에서 호출하는 64비트 비교 후 교환 helper입니다. r0는 기대한 64비트 값의 주소, r1은 새 값의 주소, r2는 변경할 메모리 주소를 받습니다. 명령은 .inst로 넣은 AArch32 코드입니다. 레이블은 이 위치에 붙인 이름이며, 이름을 적는 것만으로 CPU 명령이 추가되지는 않습니다.

23행 그림 · 위치에 이름 붙이기
레이블
처리 전현재 배치 위치
이 줄의 효과__kuser_cmpxchg64
CPU 레지스터
처리 전그대로
이 줄의 효과레이블 자체가 값을 바꾸지 않습니다.

→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.

	.inst	0xe92d00f0		//	push		{r4, r5, r6, r7}

r4~r7을 사용자 스택에 저장합니다. 기대값과 새 값의 64비트 쌍을 이 레지스터들에 보관하지만, 호출자에게 돌아갈 때는 원래 값을 보존해야 합니다. 여기서 .inst는 어셈블 단계에 숫자로 적힌 명령어 인코딩을 내보냅니다. 이 파일의 바이트열은 32비트 사용자 모드에서 AArch32 명령으로 실행됩니다.

AArch32 PUSH {r4,r5,r6,r7}: SP를 16 낮추고 callee-saved 네 레지스터를 보존합니다.

24행 그림 · AArch32 명령의 상태 변화

바이트를 명령으로 읽으면 push {r4, r5, r6, r7}입니다.

메모리[이전 SP − 16 + 0]
이 명령을 실행하기 직전기존 값
이 명령을 실행한 직후명령 직전 r4의 값
메모리[이전 SP − 16 + 4]
이 명령을 실행하기 직전기존 값
이 명령을 실행한 직후명령 직전 r5의 값
메모리[이전 SP − 16 + 8]
이 명령을 실행하기 직전기존 값
이 명령을 실행한 직후명령 직전 r6의 값
메모리[이전 SP − 16 + 12]
이 명령을 실행하기 직전기존 값
이 명령을 실행한 직후명령 직전 r7의 값
SP
이 명령을 실행하기 직전명령 직전 SP의 값
이 명령을 실행한 직후명령 직전 SP의 값 − 16

→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.

  • .inst는 빌드할 때 아래 AArch32 명령의 바이트를 만듭니다. 그림은 사용자가 그 바이트를 실행할 때의 상태 변화입니다.
	.inst	0xe1c040d0		//	ldrd		r4, r5, [r0]

r0가 가리키는 기대값을 하위·상위 32비트 r4·r5에 읽습니다. 이후 실제 메모리 값과 두 부분을 모두 비교합니다. 여기서 .inst는 어셈블 단계에 숫자로 적힌 명령어 인코딩을 내보냅니다. 이 파일의 바이트열은 32비트 사용자 모드에서 AArch32 명령으로 실행됩니다.

LDRD r4,r5,[r0]: 비교할 기존 64비트 값을 포인터 r0에서 읽습니다.

25행 그림 · AArch32 명령의 상태 변화

바이트를 명령으로 읽으면 ldrd r4, r5, [r0]입니다.

읽는 값r0
r4
이 명령을 실행하기 직전명령 직전 r4의 값
이 명령을 실행한 직후메모리[명령 직전 r0의 값 + 0]의 32비트 값
r5
이 명령을 실행하기 직전명령 직전 r5의 값
이 명령을 실행한 직후메모리[명령 직전 r0의 값 + 4]의 32비트 값

→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.

  • .inst는 빌드할 때 아래 AArch32 명령의 바이트를 만듭니다. 그림은 사용자가 그 바이트를 실행할 때의 상태 변화입니다.
	.inst	0xe1c160d0		//	ldrd		r6, r7, [r1]

r1이 가리키는 새 64비트 값을 r6·r7에 읽습니다. 비교가 성공한 경우에만 이 쌍을 대상 메모리에 저장합니다. 여기서 .inst는 어셈블 단계에 숫자로 적힌 명령어 인코딩을 내보냅니다. 이 파일의 바이트열은 32비트 사용자 모드에서 AArch32 명령으로 실행됩니다.

LDRD r6,r7,[r1]: 저장할 새 64비트 값을 포인터 r1에서 읽습니다.

26행 그림 · AArch32 명령의 상태 변화

바이트를 명령으로 읽으면 ldrd r6, r7, [r1]입니다.

읽는 값r1
r6
이 명령을 실행하기 직전명령 직전 r6의 값
이 명령을 실행한 직후메모리[명령 직전 r1의 값 + 0]의 32비트 값
r7
이 명령을 실행하기 직전명령 직전 r7의 값
이 명령을 실행한 직후메모리[명령 직전 r1의 값 + 4]의 32비트 값

→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.

  • .inst는 빌드할 때 아래 AArch32 명령의 바이트를 만듭니다. 그림은 사용자가 그 바이트를 실행할 때의 상태 변화입니다.
	.inst	0xe1b20f9f		// 1:	ldrexd		r0, r1, [r2]

대상 r2의 64비트 값을 r0·r1에 exclusive load합니다. 이 읽기 이후 다른 접근 때문에 배타적 저장이 실패할 수 있으므로 뒤에서 저장 결과를 검사합니다. 여기서 .inst는 어셈블 단계에 숫자로 적힌 명령어 인코딩을 내보냅니다. 이 파일의 바이트열은 32비트 사용자 모드에서 AArch32 명령으로 실행됩니다.

LDREXD r0,r1,[r2]: 대상의 64비트 값을 배타적으로 읽고 로컬 배타적 모니터를 설정합니다.

27행 그림 · AArch32 명령의 상태 변화

바이트를 명령으로 읽으면 ldrexd r0, r1, [r2]입니다.

읽는 값r2
r0
이 명령을 실행하기 직전명령 직전 r0의 값
이 명령을 실행한 직후메모리[명령 직전 r2의 값 + 0]의 32비트 값
r1
이 명령을 실행하기 직전명령 직전 r1의 값
이 명령을 실행한 직후메모리[명령 직전 r2의 값 + 4]의 32비트 값
배타적 접근 감시
이 명령을 실행하기 직전이전 감시 상태
이 명령을 실행한 직후이 주소에 대한 배타적 load 상태

→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.

  • .inst는 빌드할 때 아래 AArch32 명령의 바이트를 만듭니다. 그림은 사용자가 그 바이트를 실행할 때의 상태 변화입니다.
	.inst	0xe0303004		//	eors		r3, r0, r4

읽은 값의 하위 32비트 r0와 기대값 r4를 XOR하여 같은지 검사합니다. 같으면 r3=0과 Z=1이 되어 상위 부분 비교를 이어갑니다. 여기서 .inst는 어셈블 단계에 숫자로 적힌 명령어 인코딩을 내보냅니다. 이 파일의 바이트열은 32비트 사용자 모드에서 AArch32 명령으로 실행됩니다.

EORS r3,r0,r4: 하위 워드 차이를 XOR로 검사합니다. 같으면 Z=1입니다.

28행 그림 · AArch32 명령의 상태 변화

바이트를 명령으로 읽으면 eors r3, r0, r4입니다.

읽는 값r0r4
r3
이 명령을 실행하기 직전명령 직전 r3의 값
이 명령을 실행한 직후명령 직전 r0의 값 XOR 명령 직전 r4의 값
APSR.NZCV
이 명령을 실행하기 직전명령 직전 APSR.NZCV의 값
이 명령을 실행한 직후논리 연산은 N/Z와 shifter carry를 반영하고 V는 유지

→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.

  • .inst는 빌드할 때 아래 AArch32 명령의 바이트를 만듭니다. 그림은 사용자가 그 바이트를 실행할 때의 상태 변화입니다.
	.inst	0x00313005		//	eoreqs		r3, r1, r5

하위 부분이 같을 때만 상위 r1과 r5를 비교합니다. 두 부분이 모두 같아야 다음 조건부 64비트 저장을 시도합니다. 여기서 .inst는 어셈블 단계에 숫자로 적힌 명령어 인코딩을 내보냅니다. 이 파일의 바이트열은 32비트 사용자 모드에서 AArch32 명령으로 실행됩니다.

EOREQS r3,r1,r5: 하위 워드가 같은 경우에만 상위 워드도 비교합니다.

29행 그림 · AArch32 명령의 상태 변화

바이트를 명령으로 읽으면 eoreqs r3, r1, r5입니다.

읽는 값r1r5
r3
이 명령을 실행하기 직전명령 직전 r3의 값
이 명령을 실행한 직후Z=1이면 명령 직전 r1의 값 XOR 명령 직전 r5의 값, 아니면 그대로
APSR.NZCV
이 명령을 실행하기 직전명령 직전 APSR.NZCV의 값
이 명령을 실행한 직후Z=1인 경우만 N/Z/C를 갱신, V는 유지

→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.

  • .inst는 빌드할 때 아래 AArch32 명령의 바이트를 만듭니다. 그림은 사용자가 그 바이트를 실행할 때의 상태 변화입니다.
	.inst	0x01a23e96		//	stlexdeq	r3, r6, [r2]

비교가 일치하면 r6·r7의 새 값을 r2 주소에 release 성격의 exclusive store로 기록하려고 합니다. r3에는 저장 성공 시 0, 배타적 접근 실패 시 1이 들어갑니다. 여기서 .inst는 어셈블 단계에 숫자로 적힌 명령어 인코딩을 내보냅니다. 이 파일의 바이트열은 32비트 사용자 모드에서 AArch32 명령으로 실행됩니다.

STLEXDEQ r3,r6,[r2]: 두 워드가 같으면 r6/r7을 release 배타적 저장합니다. r3=0이면 성공, 1이면 경쟁 등으로 실패입니다.

30행 그림 · AArch32 명령의 상태 변화

바이트를 명령으로 읽으면 stlexdeq r3, r6, [r2]입니다.

메모리[이전 r2]
이 명령을 실행하기 직전기존 값
이 명령을 실행한 직후Z=1이고 배타적 store 성공이면 명령 직전 r6의 값·r7, 아니면 그대로
r3
이 명령을 실행하기 직전명령 직전 r3의 값
이 명령을 실행한 직후Z=1이면 성공 0 / 실패 1, Z=0이면 그대로

→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.

  • 조건부 release 배타적 저장입니다. 성공 여부와 별개로 다음 NZCV는 TEQEQ가 검사합니다.
  • .inst는 빌드할 때 아래 AArch32 명령의 바이트를 만듭니다. 그림은 사용자가 그 바이트를 실행할 때의 상태 변화입니다.
	.inst	0x03330001		//	teqeq		r3, #1

실제 저장을 시도한 경우 그 결과 r3가 1인지 검사합니다. 값 불일치는 즉시 실패로 돌려주지만, 다른 접근과의 충돌로 저장만 실패한 경우는 다시 시도할 수 있습니다. 여기서 .inst는 어셈블 단계에 숫자로 적힌 명령어 인코딩을 내보냅니다. 이 파일의 바이트열은 32비트 사용자 모드에서 AArch32 명령으로 실행됩니다.

TEQEQ r3,#1: 비교가 같았던 경로에서 배타적 저장 실패 여부를 검사합니다.

31행 그림 · AArch32 명령의 상태 변화

바이트를 명령으로 읽으면 teqeq r3, #1입니다.

APSR.N/Z/C
이 명령을 실행하기 직전명령 직전 APSR.N의 값/Z/C
이 명령을 실행한 직후Z=1이면 r3 XOR 1의 논리 연산 플래그, 아니면 그대로

→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.

  • .inst는 빌드할 때 아래 AArch32 명령의 바이트를 만듭니다. 그림은 사용자가 그 바이트를 실행할 때의 상태 변화입니다.
	.inst	0x0afffff9		//	beq		1b

exclusive store 결과가 1이면 앞의 exclusive load로 돌아갑니다. 메모리가 바뀌었을 수 있으므로 비교까지 다시 수행합니다. 여기서 .inst는 어셈블 단계에 숫자로 적힌 명령어 인코딩을 내보냅니다. 이 파일의 바이트열은 32비트 사용자 모드에서 AArch32 명령으로 실행됩니다.

BEQ는 배타적 저장 실패일 때 27행 LDREXD부터 재시도합니다.

32행 그림 · AArch32 명령의 상태 변화

바이트를 명령으로 읽으면 beq 1b입니다.

읽는 값APSR.Z
PC
이 명령을 실행하기 직전명령 직전 PC의 값
이 명령을 실행한 직후Z=1이면 이 helper의 배타적 load 재시도 지점, 아니면 다음 명령

→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.

  • .inst는 빌드할 때 아래 AArch32 명령의 바이트를 만듭니다. 그림은 사용자가 그 바이트를 실행할 때의 상태 변화입니다.
	.inst	0xf57ff05b		//	dmb		ish

Inner Shareable 범위의 메모리 접근 순서를 보장하여 helper가 제공하는 비교·교환의 메모리 장벽 의미를 마무리합니다. 여기서 .inst는 어셈블 단계에 숫자로 적힌 명령어 인코딩을 내보냅니다. 이 파일의 바이트열은 32비트 사용자 모드에서 AArch32 명령으로 실행됩니다.

DMB ISH로 공유 메모리 접근 순서를 보장합니다.

33행 그림 · AArch32 명령의 상태 변화

바이트를 명령으로 읽으면 dmb ish입니다.

메모리 관찰 순서
이 명령을 실행하기 직전장벽 전
이 명령을 실행한 직후ISH 범위의 접근 순서를 보장

→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.

  • .inst는 빌드할 때 아래 AArch32 명령의 바이트를 만듭니다. 그림은 사용자가 그 바이트를 실행할 때의 상태 변화입니다.
	.inst	0xe2730000		//	rsbs		r0, r3, #0

0-r3를 r0에 만들고 조건 플래그도 갱신합니다. 성공하면 반환값 0과 carry 설정, 실패하면 0이 아닌 값과 carry 해제가 되어 helper ABI에 맞게 결과를 돌려줍니다. 여기서 .inst는 어셈블 단계에 숫자로 적힌 명령어 인코딩을 내보냅니다. 이 파일의 바이트열은 32비트 사용자 모드에서 AArch32 명령으로 실행됩니다.

RSBS r0,r3,#0: r0=−r3를 반환하며 조건 플래그도 설정합니다. 성공은 r3=0이므로 r0=0입니다.

34행 그림 · AArch32 명령의 상태 변화

바이트를 명령으로 읽으면 rsbs r0, r3, #0입니다.

읽는 값r3
r0
이 명령을 실행하기 직전명령 직전 r0의 값
이 명령을 실행한 직후0 − 명령 직전 r3의 값
APSR.NZCV
이 명령을 실행하기 직전명령 직전 APSR.NZCV의 값
이 명령을 실행한 직후뺄셈 결과의 N/Z/C/V

→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.

  • .inst는 빌드할 때 아래 AArch32 명령의 바이트를 만듭니다. 그림은 사용자가 그 바이트를 실행할 때의 상태 변화입니다.
	.inst	0xe8bd00f0		//	pop		{r4, r5, r6, r7}

작업용으로 사용한 r4~r7을 호출 전 값으로 복원합니다. 여기서 .inst는 어셈블 단계에 숫자로 적힌 명령어 인코딩을 내보냅니다. 이 파일의 바이트열은 32비트 사용자 모드에서 AArch32 명령으로 실행됩니다.

POP으로 r4–r7을 복원하고 SP를 16 증가시킵니다.

35행 그림 · AArch32 명령의 상태 변화

바이트를 명령으로 읽으면 pop {r4, r5, r6, r7}입니다.

r4
이 명령을 실행하기 직전명령 직전 r4의 값
이 명령을 실행한 직후메모리[명령 직전 SP의 값 + 0]
r5
이 명령을 실행하기 직전명령 직전 r5의 값
이 명령을 실행한 직후메모리[명령 직전 SP의 값 + 4]
r6
이 명령을 실행하기 직전명령 직전 r6의 값
이 명령을 실행한 직후메모리[명령 직전 SP의 값 + 8]
r7
이 명령을 실행하기 직전명령 직전 r7의 값
이 명령을 실행한 직후메모리[명령 직전 SP의 값 + 12]
SP
이 명령을 실행하기 직전명령 직전 SP의 값
이 명령을 실행한 직후명령 직전 SP의 값 + 16

→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.

  • .inst는 빌드할 때 아래 AArch32 명령의 바이트를 만듭니다. 그림은 사용자가 그 바이트를 실행할 때의 상태 변화입니다.
	.inst	0xe12fff1e		//	bx		lr

LR로 복귀합니다. BX이므로 AArch32 호출자의 ARM/Thumb 실행 상태에 맞춰 돌아갑니다. 여기서 .inst는 어셈블 단계에 숫자로 적힌 명령어 인코딩을 내보냅니다. 이 파일의 바이트열은 32비트 사용자 모드에서 AArch32 명령으로 실행됩니다.

BX LR로 AArch32 호출자의 주소와 명령 상태로 복귀합니다.

36행 그림 · AArch32 명령의 상태 변화

바이트를 명령으로 읽으면 bx lr입니다.

읽는 값LR
PC
이 명령을 실행하기 직전명령 직전 PC의 값
이 명령을 실행한 직후명령 직전 LR의 값이 지정한 복귀 주소
명령어 상태
이 명령을 실행하기 직전이전 명령어 상태
이 명령을 실행한 직후LR bit 0에 따른 ARM/Thumb 상태

→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.

  • .inst는 빌드할 때 아래 AArch32 명령의 바이트를 만듭니다. 그림은 사용자가 그 바이트를 실행할 때의 상태 변화입니다.

메모리 배리어와 32비트 비교 후 교환

원본 38–53행

	.align	5

앞의 64비트 비교·교환 코드 뒤를 32바이트 경계까지 채워 memory barrier helper의 고정 위치를 맞춥니다. AArch64의 .align 인자는 바이트 수가 아니라 2의 지수입니다. 빌드할 때 필요한 패딩을 넣어 그 경계를 맞춥니다.

38행 그림 · 어셈블·링크 단계
빌드 도구
처리 전소스의 명령·배치 표기
이 줄의 효과.align 5
CPU 레지스터
처리 전해당 없음
이 줄의 효과지시문 자체는 레지스터를 쓰지 않습니다.

→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.

__kuser_memory_barrier:			// 0xffff0fa0

0xffff0fa0의 메모리 장벽 helper입니다. 예전 AArch32 프로그램이 이 고정 주소를 호출하여 공유 메모리 접근 순서를 보장할 수 있습니다. 레이블은 이 위치에 붙인 이름이며, 이름을 적는 것만으로 CPU 명령이 추가되지는 않습니다.

39행 그림 · 위치에 이름 붙이기
레이블
처리 전현재 배치 위치
이 줄의 효과__kuser_memory_barrier
CPU 레지스터
처리 전그대로
이 줄의 효과레이블 자체가 값을 바꾸지 않습니다.

→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.

	.inst	0xf57ff05b		//	dmb		ish

DMB ISH를 실행하여 Inner Shareable 영역의 앞뒤 메모리 접근 순서를 보장합니다. 데이터를 복사하거나 캐시 전체를 지우는 helper가 아닙니다. 여기서 .inst는 어셈블 단계에 숫자로 적힌 명령어 인코딩을 내보냅니다. 이 파일의 바이트열은 32비트 사용자 모드에서 AArch32 명령으로 실행됩니다.

DMB ISH 하나를 실행하는 메모리 배리어 helper입니다.

40행 그림 · AArch32 명령의 상태 변화

바이트를 명령으로 읽으면 dmb ish입니다.

메모리 관찰 순서
이 명령을 실행하기 직전장벽 전
이 명령을 실행한 직후ISH 범위의 접근 순서를 보장

→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.

  • .inst는 빌드할 때 아래 AArch32 명령의 바이트를 만듭니다. 그림은 사용자가 그 바이트를 실행할 때의 상태 변화입니다.
	.inst	0xe12fff1e		//	bx		lr

메모리 장벽을 수행한 뒤 AArch32 호출자의 LR로 돌아갑니다. 여기서 .inst는 어셈블 단계에 숫자로 적힌 명령어 인코딩을 내보냅니다. 이 파일의 바이트열은 32비트 사용자 모드에서 AArch32 명령으로 실행됩니다.

BX LR로 사용자 호출자에게 복귀합니다.

41행 그림 · AArch32 명령의 상태 변화

바이트를 명령으로 읽으면 bx lr입니다.

읽는 값LR
PC
이 명령을 실행하기 직전명령 직전 PC의 값
이 명령을 실행한 직후명령 직전 LR의 값이 지정한 복귀 주소
명령어 상태
이 명령을 실행하기 직전이전 명령어 상태
이 명령을 실행한 직후LR bit 0에 따른 ARM/Thumb 상태

→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.

  • .inst는 빌드할 때 아래 AArch32 명령의 바이트를 만듭니다. 그림은 사용자가 그 바이트를 실행할 때의 상태 변화입니다.
	.align	5

다음 32비트 비교·교환 helper가 지정된 32바이트 슬롯 경계에서 시작하도록 맞춥니다. AArch64의 .align 인자는 바이트 수가 아니라 2의 지수입니다. 빌드할 때 필요한 패딩을 넣어 그 경계를 맞춥니다.

43행 그림 · 어셈블·링크 단계
빌드 도구
처리 전소스의 명령·배치 표기
이 줄의 효과.align 5
CPU 레지스터
처리 전해당 없음
이 줄의 효과지시문 자체는 레지스터를 쓰지 않습니다.

→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.

__kuser_cmpxchg:			// 0xffff0fc0

0xffff0fc0의 32비트 비교 후 교환 helper입니다. r0는 기대값, r1은 새 값, r2는 변경할 주소입니다. 현재 값이 기대값과 같을 때만 메모리를 바꿉니다. 레이블은 이 위치에 붙인 이름이며, 이름을 적는 것만으로 CPU 명령이 추가되지는 않습니다.

44행 그림 · 위치에 이름 붙이기
레이블
처리 전현재 배치 위치
이 줄의 효과__kuser_cmpxchg
CPU 레지스터
처리 전그대로
이 줄의 효과레이블 자체가 값을 바꾸지 않습니다.

→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.

	.inst	0xe1923f9f		// 1:	ldrex		r3, [r2]

대상 주소 r2에서 현재 32비트 값을 r3에 exclusive load합니다. 뒤의 배타적 저장과 함께 동시 접근을 감지하는 읽기·수정·쓰기 시도를 만듭니다. 여기서 .inst는 어셈블 단계에 숫자로 적힌 명령어 인코딩을 내보냅니다. 이 파일의 바이트열은 32비트 사용자 모드에서 AArch32 명령으로 실행됩니다.

LDREX r3,[r2]: 대상 32비트 값을 배타적으로 읽습니다.

45행 그림 · AArch32 명령의 상태 변화

바이트를 명령으로 읽으면 ldrex r3, [r2]입니다.

읽는 값r2
r3
이 명령을 실행하기 직전명령 직전 r3의 값
이 명령을 실행한 직후메모리[명령 직전 r2의 값 + 0]의 32비트 값
배타적 접근 감시
이 명령을 실행하기 직전이전 감시 상태
이 명령을 실행한 직후이 주소에 대한 배타적 load 상태

→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.

  • .inst는 빌드할 때 아래 AArch32 명령의 바이트를 만듭니다. 그림은 사용자가 그 바이트를 실행할 때의 상태 변화입니다.
	.inst	0xe0533000		//	subs		r3, r3, r0

현재 값에서 기대값 r0를 빼 두 값이 같은지 검사합니다. 같으면 r3=0과 Z=1이 되어 저장을 시도하고, 다르면 저장을 생략합니다. 여기서 .inst는 어셈블 단계에 숫자로 적힌 명령어 인코딩을 내보냅니다. 이 파일의 바이트열은 32비트 사용자 모드에서 AArch32 명령으로 실행됩니다.

SUBS r3,r3,r0: 현재 값과 기대값을 비교합니다. 일치하면 Z=1입니다.

46행 그림 · AArch32 명령의 상태 변화

바이트를 명령으로 읽으면 subs r3, r3, r0입니다.

읽는 값r3r0
r3
이 명령을 실행하기 직전명령 직전 r3의 값
이 명령을 실행한 직후명령 직전 r3의 값 − 명령 직전 r0의 값
APSR.NZCV
이 명령을 실행하기 직전명령 직전 APSR.NZCV의 값
이 명령을 실행한 직후뺄셈 결과의 N/Z/C/V

→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.

  • .inst는 빌드할 때 아래 AArch32 명령의 바이트를 만듭니다. 그림은 사용자가 그 바이트를 실행할 때의 상태 변화입니다.
	.inst	0x01823e91		//	stlexeq		r3, r1, [r2]

비교가 같을 때만 새 값 r1을 r2 주소에 release 성격의 exclusive store로 기록합니다. r3는 성공 여부가 되어 0이면 성공, 1이면 재시도 대상입니다. 여기서 .inst는 어셈블 단계에 숫자로 적힌 명령어 인코딩을 내보냅니다. 이 파일의 바이트열은 32비트 사용자 모드에서 AArch32 명령으로 실행됩니다.

STLEXEQ r3,r1,[r2]: 일치할 때만 새 값 r1을 release 배타적 저장하고 결과를 r3에 남깁니다.

47행 그림 · AArch32 명령의 상태 변화

바이트를 명령으로 읽으면 stlexeq r3, r1, [r2]입니다.

메모리[이전 r2]
이 명령을 실행하기 직전기존 값
이 명령을 실행한 직후Z=1이고 배타적 store 성공이면 명령 직전 r1의 값, 아니면 그대로
r3
이 명령을 실행하기 직전명령 직전 r3의 값
이 명령을 실행한 직후Z=1이면 성공 0 / 실패 1, Z=0이면 그대로

→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.

  • 조건부 release 배타적 저장입니다. 성공 여부와 별개로 다음 NZCV는 TEQEQ가 검사합니다.
  • .inst는 빌드할 때 아래 AArch32 명령의 바이트를 만듭니다. 그림은 사용자가 그 바이트를 실행할 때의 상태 변화입니다.
	.inst	0x03330001		//	teqeq		r3, #1

저장을 시도한 경우 r3가 실패 코드 1인지 검사합니다. 값 자체의 불일치와 exclusive store 충돌을 구분합니다. 여기서 .inst는 어셈블 단계에 숫자로 적힌 명령어 인코딩을 내보냅니다. 이 파일의 바이트열은 32비트 사용자 모드에서 AArch32 명령으로 실행됩니다.

TEQEQ r3,#1: 배타적 저장 실패일 때 Z=1을 만듭니다.

48행 그림 · AArch32 명령의 상태 변화

바이트를 명령으로 읽으면 teqeq r3, #1입니다.

APSR.N/Z/C
이 명령을 실행하기 직전명령 직전 APSR.N의 값/Z/C
이 명령을 실행한 직후Z=1이면 r3 XOR 1의 논리 연산 플래그, 아니면 그대로

→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.

  • .inst는 빌드할 때 아래 AArch32 명령의 바이트를 만듭니다. 그림은 사용자가 그 바이트를 실행할 때의 상태 변화입니다.
	.inst	0x0afffffa		//	beq		1b

저장 충돌이면 다시 읽기부터 시작합니다. 다른 실행 주체가 값을 바꾸었을 수 있으므로 같은 기대값인지 재검사합니다. 여기서 .inst는 어셈블 단계에 숫자로 적힌 명령어 인코딩을 내보냅니다. 이 파일의 바이트열은 32비트 사용자 모드에서 AArch32 명령으로 실행됩니다.

BEQ는 저장 경쟁으로 실패했을 때 45행부터 다시 읽습니다. 값이 처음부터 다르면 이 반복에 들어가지 않습니다.

49행 그림 · AArch32 명령의 상태 변화

바이트를 명령으로 읽으면 beq 1b입니다.

읽는 값APSR.Z
PC
이 명령을 실행하기 직전명령 직전 PC의 값
이 명령을 실행한 직후Z=1이면 이 helper의 배타적 load 재시도 지점, 아니면 다음 명령

→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.

  • .inst는 빌드할 때 아래 AArch32 명령의 바이트를 만듭니다. 그림은 사용자가 그 바이트를 실행할 때의 상태 변화입니다.
	.inst	0xf57ff05b		//	dmb		ish

DMB ISH로 공유 메모리 접근 순서를 정리합니다. 비교·교환 결과만 반환하는 것에 더해 helper의 장벽 동작을 제공하는 줄입니다. 여기서 .inst는 어셈블 단계에 숫자로 적힌 명령어 인코딩을 내보냅니다. 이 파일의 바이트열은 32비트 사용자 모드에서 AArch32 명령으로 실행됩니다.

DMB ISH로 비교·교환과 다른 메모리 접근 사이의 순서를 보장합니다.

50행 그림 · AArch32 명령의 상태 변화

바이트를 명령으로 읽으면 dmb ish입니다.

메모리 관찰 순서
이 명령을 실행하기 직전장벽 전
이 명령을 실행한 직후ISH 범위의 접근 순서를 보장

→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.

  • .inst는 빌드할 때 아래 AArch32 명령의 바이트를 만듭니다. 그림은 사용자가 그 바이트를 실행할 때의 상태 변화입니다.
	.inst	0xe2730000		//	rsbs		r0, r3, #0

0-r3를 반환값 r0에 넣으면서 carry 플래그를 갱신합니다. 성공은 0과 carry 설정, 실패는 0이 아닌 값과 carry 해제로 호출자에게 전달합니다. 여기서 .inst는 어셈블 단계에 숫자로 적힌 명령어 인코딩을 내보냅니다. 이 파일의 바이트열은 32비트 사용자 모드에서 AArch32 명령으로 실행됩니다.

RSBS r0,r3,#0으로 결과와 플래그를 만듭니다. 성공은 0, 비교 불일치는 비0을 반환합니다.

51행 그림 · AArch32 명령의 상태 변화

바이트를 명령으로 읽으면 rsbs r0, r3, #0입니다.

읽는 값r3
r0
이 명령을 실행하기 직전명령 직전 r0의 값
이 명령을 실행한 직후0 − 명령 직전 r3의 값
APSR.NZCV
이 명령을 실행하기 직전명령 직전 APSR.NZCV의 값
이 명령을 실행한 직후뺄셈 결과의 N/Z/C/V

→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.

  • .inst는 빌드할 때 아래 AArch32 명령의 바이트를 만듭니다. 그림은 사용자가 그 바이트를 실행할 때의 상태 변화입니다.
	.inst	0xe12fff1e		//	bx		lr

32비트 비교·교환 결과를 남긴 채 LR의 호출 지점으로 돌아갑니다. 여기서 .inst는 어셈블 단계에 숫자로 적힌 명령어 인코딩을 내보냅니다. 이 파일의 바이트열은 32비트 사용자 모드에서 AArch32 명령으로 실행됩니다.

BX LR로 사용자 코드에 복귀합니다.

52행 그림 · AArch32 명령의 상태 변화

바이트를 명령으로 읽으면 bx lr입니다.

읽는 값LR
PC
이 명령을 실행하기 직전명령 직전 PC의 값
이 명령을 실행한 직후명령 직전 LR의 값이 지정한 복귀 주소
명령어 상태
이 명령을 실행하기 직전이전 명령어 상태
이 명령을 실행한 직후LR bit 0에 따른 ARM/Thumb 상태

→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.

  • .inst는 빌드할 때 아래 AArch32 명령의 바이트를 만듭니다. 그림은 사용자가 그 바이트를 실행할 때의 상태 변화입니다.

TLS와 버전 슬롯

원본 54–65행

	.align	5

TLS helper의 고정 주소를 맞추기 위해 다음 코드를 32바이트 경계에 배치합니다. AArch64의 .align 인자는 바이트 수가 아니라 2의 지수입니다. 빌드할 때 필요한 패딩을 넣어 그 경계를 맞춥니다.

54행 그림 · 어셈블·링크 단계
빌드 도구
처리 전소스의 명령·배치 표기
이 줄의 효과.align 5
CPU 레지스터
처리 전해당 없음
이 줄의 효과지시문 자체는 레지스터를 쓰지 않습니다.

→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.

__kuser_get_tls:			// 0xffff0fe0

0xffff0fe0의 TLS 조회 helper입니다. AArch32 프로그램이 현재 스레드의 thread pointer를 얻기 위해 사용하는 고정 주소 진입점입니다. 레이블은 이 위치에 붙인 이름이며, 이름을 적는 것만으로 CPU 명령이 추가되지는 않습니다.

55행 그림 · 위치에 이름 붙이기
레이블
처리 전현재 배치 위치
이 줄의 효과__kuser_get_tls
CPU 레지스터
처리 전그대로
이 줄의 효과레이블 자체가 값을 바꾸지 않습니다.

→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.

	.inst	0xee1d0f70		//	mrc		p15, 0, r0, c13, c0, 3

AArch32의 TPIDRURO에 해당하는 CP15 스레드 식별 레지스터를 읽어 r0로 돌려줄 값을 준비합니다. ARM64 커널이 호환 태스크를 위해 유지하는 사용자 TLS 값입니다. 여기서 .inst는 어셈블 단계에 숫자로 적힌 명령어 인코딩을 내보냅니다. 이 파일의 바이트열은 32비트 사용자 모드에서 AArch32 명령으로 실행됩니다.

MRC p15,0,r0,c13,c0,3: TPIDRURO에서 32비트 TLS 포인터를 읽습니다.

56행 그림 · AArch32 명령의 상태 변화

바이트를 명령으로 읽으면 mrc p15, 0, r0, c13, c0, 3입니다.

읽는 값TPIDRURO
r0
이 명령을 실행하기 직전명령 직전 r0의 값
이 명령을 실행한 직후TPIDRURO의 사용자 TLS 값

→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.

  • .inst는 빌드할 때 아래 AArch32 명령의 바이트를 만듭니다. 그림은 사용자가 그 바이트를 실행할 때의 상태 변화입니다.
	.inst	0xe12fff1e		//	bx		lr

TLS 포인터를 r0에 둔 채 호출자에게 돌아갑니다. 여기서 .inst는 어셈블 단계에 숫자로 적힌 명령어 인코딩을 내보냅니다. 이 파일의 바이트열은 32비트 사용자 모드에서 AArch32 명령으로 실행됩니다.

읽은 r0를 그대로 두고 BX LR로 반환합니다.

57행 그림 · AArch32 명령의 상태 변화

바이트를 명령으로 읽으면 bx lr입니다.

읽는 값LR
PC
이 명령을 실행하기 직전명령 직전 PC의 값
이 명령을 실행한 직후명령 직전 LR의 값이 지정한 복귀 주소
명령어 상태
이 명령을 실행하기 직전이전 명령어 상태
이 명령을 실행한 직후LR bit 0에 따른 ARM/Thumb 상태

→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.

  • .inst는 빌드할 때 아래 AArch32 명령의 바이트를 만듭니다. 그림은 사용자가 그 바이트를 실행할 때의 상태 변화입니다.
	.rep	5

뒤의 32비트 0을 다섯 번 배치하여 TLS helper 뒤의 고정 크기 공간을 채웁니다. CPU가 다섯 번 반복 실행하는 루프는 아닙니다.

58행 그림 · 어셈블·링크 단계
빌드 도구
처리 전소스의 명령·배치 표기
이 줄의 효과.rep 5
CPU 레지스터
처리 전해당 없음
이 줄의 효과지시문 자체는 레지스터를 쓰지 않습니다.

→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.

	.word	0

이 .word는 어셈블 단계에서 4바이트의 0을 내보내는 데이터 지시문입니다. CPU가 0을 계산하거나 저장하는 실행 명령은 아닙니다. 패딩용 4바이트 0을 놓습니다. 위 .rep 5와 합쳐 총 20바이트를 차지하여 버전 필드가 0xffff0ffc 위치에 오게 합니다.

59행 그림 · 어셈블·링크 단계
빌드 도구
처리 전소스의 명령·배치 표기
이 줄의 효과.word 0
CPU 레지스터
처리 전해당 없음
이 줄의 효과지시문 자체는 레지스터를 쓰지 않습니다.

→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.

	.endr

패딩용 0을 다섯 번 생성하는 범위를 마칩니다. 결과적으로 뒤의 버전 필드가 정해진 페이지 끝 위치에 놓입니다.

60행 그림 · 어셈블·링크 단계
빌드 도구
처리 전소스의 명령·배치 표기
이 줄의 효과.endr
CPU 레지스터
처리 전해당 없음
이 줄의 효과지시문 자체는 레지스터를 쓰지 않습니다.

→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.

__kuser_helper_version:			// 0xffff0ffc

0xffff0ffc의 helper 버전 필드 위치입니다. 프로그램은 이 값을 읽어 제공되는 helper ABI 버전을 확인할 수 있습니다. 레이블은 이 위치에 붙인 이름이며, 이름을 적는 것만으로 CPU 명령이 추가되지는 않습니다.

62행 그림 · 위치에 이름 붙이기
레이블
처리 전현재 배치 위치
이 줄의 효과__kuser_helper_version
CPU 레지스터
처리 전그대로
이 줄의 효과레이블 자체가 값을 바꾸지 않습니다.

→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.

	.word	((__kuser_helper_end - __kuser_helper_start) >> 5)

이 .word는 같은 섹션의 두 레이블 사이 크기를 어셈블 단계에서 계산하여 4바이트 정수로 기록합니다. 실행 중 CPU가 이 뺄셈과 시프트를 수행하는 줄은 아닙니다. helper 블록 크기를 32바이트 단위로 나눈 값을 버전 필드에 기록합니다. 이 배치에서는 블록이 0xa0바이트이므로 값은 5입니다. helper 함수 개수를 세는 표현으로 읽으면 안 됩니다.

helper의 전체 길이 160바이트를 32로 나누므로 버전 값은 5입니다.

63행 그림 · 어셈블·링크 단계
빌드 도구
처리 전소스의 명령·배치 표기
이 줄의 효과.word ((__kuser_helper_end - __kuser_helper_start) >> 5)
CPU 레지스터
처리 전해당 없음
이 줄의 효과지시문 자체는 레지스터를 쓰지 않습니다.

→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.

	.globl	__kuser_helper_end

복사할 helper 블록의 끝 주소를 다른 파일에서도 참조할 수 있게 합니다. 이 표기는 심벌을 다른 오브젝트에서도 참조할 수 있게 하며 CPU가 실행하는 명령을 추가하지 않습니다.

64행 그림 · 어셈블·링크 단계
빌드 도구
처리 전소스의 명령·배치 표기
이 줄의 효과.globl __kuser_helper_end
CPU 레지스터
처리 전해당 없음
이 줄의 효과지시문 자체는 레지스터를 쓰지 않습니다.

→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.

__kuser_helper_end:

helper 블록의 끝을 표시합니다. 시작 주소와의 차이로 복사 크기와 버전 필드 값을 결정합니다. 레이블은 이 위치에 붙인 이름이며, 이름을 적는 것만으로 CPU 명령이 추가되지는 않습니다.

65행 그림 · 위치에 이름 붙이기
레이블
처리 전현재 배치 위치
이 줄의 효과__kuser_helper_end
CPU 레지스터
처리 전그대로
이 줄의 효과레이블 자체가 값을 바꾸지 않습니다.

→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.

설명한 뒤 함께 생각해 볼 질문

새 값을 그냥 STR로 쓰면 안 되나요?

읽기와 쓰기 사이의 경쟁을 놓칠 수 있습니다. 배타적 저장은 그 사이의 충돌을 감지하고 재시도할 기회를 줍니다.

값이 기대와 다르면 계속 반복하나요?

비교 불일치는 실패로 반환합니다. 저장을 시도했으나 배타적 저장이 실패한 경우가 재시도 대상입니다.

AArch64 파일에 r0가 등장해도 되나요?

여기서는 AArch32 명령을 .inst 바이트로 담고 있습니다. 일반 AArch64 명령의 x0와 다른 실행 환경입니다.

주석을 포함한 전체 원문

Linux stable v6.18.37 · arch/arm64/kernel/kuser32.S

1/* SPDX-License-Identifier: GPL-2.0 */2/*3 * AArch32 user helpers.4 * Based on the kuser helpers in arch/arm/kernel/entry-armv.S.5 *6 * Copyright (C) 2005-2011 Nicolas Pitre <nico@fluxnic.net>7 * Copyright (C) 2012-2018 ARM Ltd.8 *9 * The kuser helpers below are mapped at a fixed address by10 * aarch32_setup_additional_pages() and are provided for compatibility11 * reasons with 32 bit (aarch32) applications that need them.12 *13 * See Documentation/arch/arm/kernel_user_helpers.rst for formal definitions.14 */1516#include <asm/unistd.h>1718	.section .rodata19	.align	520	.globl	__kuser_helper_start21__kuser_helper_start:2223__kuser_cmpxchg64:			// 0xffff0f6024	.inst	0xe92d00f0		//	push		{r4, r5, r6, r7}25	.inst	0xe1c040d0		//	ldrd		r4, r5, [r0]26	.inst	0xe1c160d0		//	ldrd		r6, r7, [r1]27	.inst	0xe1b20f9f		// 1:	ldrexd		r0, r1, [r2]28	.inst	0xe0303004		//	eors		r3, r0, r429	.inst	0x00313005		//	eoreqs		r3, r1, r530	.inst	0x01a23e96		//	stlexdeq	r3, r6, [r2]31	.inst	0x03330001		//	teqeq		r3, #132	.inst	0x0afffff9		//	beq		1b33	.inst	0xf57ff05b		//	dmb		ish34	.inst	0xe2730000		//	rsbs		r0, r3, #035	.inst	0xe8bd00f0		//	pop		{r4, r5, r6, r7}36	.inst	0xe12fff1e		//	bx		lr3738	.align	539__kuser_memory_barrier:			// 0xffff0fa040	.inst	0xf57ff05b		//	dmb		ish41	.inst	0xe12fff1e		//	bx		lr4243	.align	544__kuser_cmpxchg:			// 0xffff0fc045	.inst	0xe1923f9f		// 1:	ldrex		r3, [r2]46	.inst	0xe0533000		//	subs		r3, r3, r047	.inst	0x01823e91		//	stlexeq		r3, r1, [r2]48	.inst	0x03330001		//	teqeq		r3, #149	.inst	0x0afffffa		//	beq		1b50	.inst	0xf57ff05b		//	dmb		ish51	.inst	0xe2730000		//	rsbs		r0, r3, #052	.inst	0xe12fff1e		//	bx		lr5354	.align	555__kuser_get_tls:			// 0xffff0fe056	.inst	0xee1d0f70		//	mrc		p15, 0, r0, c13, c0, 357	.inst	0xe12fff1e		//	bx		lr58	.rep	559	.word	060	.endr6162__kuser_helper_version:			// 0xffff0ffc63	.word	((__kuser_helper_end - __kuser_helper_start) >> 5)64	.globl	__kuser_helper_end65__kuser_helper_end:
맨 위로 ↑