DUJINLABS.COM

Linux v6.18.37 · ARM64

reloc_test_syms.S — 말로 풀어 읽기

이 파일은 왜 필요한가요?

프로그램을 링크하거나 다른 주소에 배치하면 명령과 데이터 안에 든 주소 표현도 맞춰야 합니다. 이 파일은 다양한 방식으로 같은 심볼을 읽게 해 재배치 결과를 시험합니다. 실제 새 커널을 복사하는 코드는 아닙니다.

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

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

먼저 알아둘 개념: 전처리·어셈블·링크·실행, 주소와 주소가 가리키는 내용, 재배치와 상대 주소, 정렬과 경계, 호출 주소와 복귀 주소

처음 읽을 때

주소를 직접 저장한 경우와 “여기서 몇 바이트 떨어져 있다”를 저장한 경우를 비교하세요. 상대값은 기준 주소를 더해야 실제 주소가 됩니다.

더 깊이 살펴볼 때

ADRP의 4 KiB 계산 단위, signed MOVW 재배치, 16·32비트 값의 확장 방식과 최종 링크 배치를 따로 검토해 보세요.

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

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

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

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

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

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

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

먼저 그림으로 살펴보기

절대·상대 재배치 검사용 코드
화살표: 처리 흐름입니다. 조건이 적힌 단계에서는 해당 조건에 따라 경로가 갈립니다.

16·32·64비트 절대 데이터

원본 1–25행

링커는 명령의 빈 주소 조각을 채웁니다

링커는 명령의 빈 주소 조각을 채웁니다의 세 단계 비교
화살표는 도구 사이 정보 전달과 주소 구성 관계입니다. 링크 단계와 CPU 실행 단계를 구분해 읽습니다.
그림의 각 단계를 글로 읽기

1. 어셈블 단계

명령에 주소 이름을 썼다고 그 순간 최종 숫자가 정해지지는 않습니다.

2. 링크 단계

모든 재배치가 같은 식은 아닙니다. 절대 주소 조각도 따로 있습니다.

3. 완성된 명령 사용

주소를 구하는 것과 그 주소의 메모리를 읽는 것은 별도 동작입니다.

#include <linux/linkage.h>

C의 테스트 배열에서 호출할 작은 어셈블리 함수들의 시작·끝·정렬을 선언하는 linkage 매크로를 가져옵니다. 실제 재배치 검사는 아래 명령과 리터럴 데이터를 적재한 뒤 수행합니다. #include는 전처리 단계에서 헤더 내용을 가져옵니다. CPU가 이 줄에서 함수를 호출하는 동작은 없습니다.

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

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

SYM_FUNC_START(absolute_data64)

모듈 로더의 R_AARCH64_ABS64 재배치가 올바른지 검사하는 작은 함수입니다. 주소의 메모리를 읽는 테스트가 아니라 절대 심볼값을 상수 데이터로 받아 x0에 반환합니다. 이 선언은 함수 심볼과 정렬을 정하고, ARM64 정의에서는 간접 호출이 도착할 BTI C 명령도 진입부에 넣습니다. 여기서는 전역 심벌로 정의하므로 다른 오브젝트에서도 이 함수 이름을 참조할 수 있습니다. 모듈용 EXPORT_SYMBOL 등록은 별도입니다.

8행 그림 · 어셈블·링크 단계

함수·코드 범위: absolute_data64

빌드 도구
처리 전소스의 명령·배치 표기
이 줄의 효과SYM_FUNC_START(absolute_data64)
CPU 레지스터
처리 전해당 없음
이 줄의 효과지시문 자체는 레지스터를 쓰지 않습니다.

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

  • 함수 시작 매크로는 심벌·정렬 정보와 BTI 진입 명령 등을 배치할 수 있습니다. 생성된 명령의 실행과 심벌 선언을 구분합니다.
	ldr	x0, 0f

뒤의 64비트 리터럴을 x0에 읽습니다. 모듈 재배치가 끝났다면 그 자리에는 sym64_abs의 실제 테스트 상수 0xffff880000cccccc가 들어 있어야 합니다. 이 LDR 리터럴 형식은 PC 기준으로 레이블 위치를 찾아 그곳의 메모리를 읽습니다. 레이블 주소 자체를 구하는 ADR과 구분합니다.

9행 그림 · 메모리 읽기

함수·코드 범위: absolute_data64

x0
이 명령을 실행하기 직전명령 직전 x0의 값
이 명령을 실행한 직후메모리[0f]의 값

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

  • =심벌이면 주소 상수를 리터럴 풀에서 읽는 의사 명령입니다. 레이블만 적힌 LDR은 해당 위치의 메모리를 읽습니다.
	ret

읽은 절대값을 테스트 호출자에게 반환합니다. reloc_test_core.c는 기대 상수와 비교하여 통과 여부를 출력합니다. 피연산자가 없는 RET는 LR(x30)에 들어 있는 주소에서 실행을 이어갑니다.

10행 그림 · 호출과 실행 위치

함수·코드 범위: absolute_data64

읽는 값lr
PC
이 명령을 실행하기 직전명령 직전 PC의 값
이 명령을 실행한 직후명령 직전 lr의 값

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

  • 새 복귀 주소를 LR에 기록하지 않습니다. RET 역시 메모리의 스택 값을 자동으로 꺼내는 명령은 아닙니다.
0:	.quad	sym64_abs

이 .quad은 CPU 명령이 아니라 항목당 8바이트 데이터와 필요한 재배치 정보를 내보내는 어셈블러 지시문입니다. 아직 확정되지 않은 심벌 값은 링크 또는 모듈 적재 시의 재배치 처리로 채웁니다. 이 테스트 함수가 실행될 때에는 앞의 load 명령이 채워진 데이터를 읽습니다. 64비트 절대 심볼 재배치가 적용될 데이터 자리를 만듭니다. sym64_abs는 C 파일에서 .set으로 정의한 숫자 심볼이며 일반 변수의 저장 내용을 읽는 것은 아닙니다.

11행 그림 · 어셈블·링크 단계

함수·코드 범위: absolute_data64

빌드 도구
처리 전소스의 명령·배치 표기
이 줄의 효과0: .quad sym64_abs
CPU 레지스터
처리 전해당 없음
이 줄의 효과지시문 자체는 레지스터를 쓰지 않습니다.

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

SYM_FUNC_END(absolute_data64)

도구에 이 코드 범위의 끝을 알려 크기와 심볼 정보를 기록합니다. CPU가 이 줄 때문에 자동으로 반환하지는 않습니다.

12행 그림 · 어셈블·링크 단계

함수·코드 범위: absolute_data64

빌드 도구
처리 전소스의 명령·배치 표기
이 줄의 효과SYM_FUNC_END(absolute_data64)
CPU 레지스터
처리 전해당 없음
이 줄의 효과지시문 자체는 레지스터를 쓰지 않습니다.

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

  • 끝 표기 자체가 RET나 분기를 실행하지는 않습니다.
SYM_FUNC_START(absolute_data32)

R_AARCH64_ABS32 재배치를 검사하는 함수입니다. 32비트 리터럴을 읽은 결과가 C 쪽의 기대값 0xf800cccc와 같은지 확인합니다. 이 선언은 함수 심볼과 정렬을 정하고, ARM64 정의에서는 간접 호출이 도착할 BTI C 명령도 진입부에 넣습니다. 여기서는 전역 심벌로 정의하므로 다른 오브젝트에서도 이 함수 이름을 참조할 수 있습니다. 모듈용 EXPORT_SYMBOL 등록은 별도입니다.

14행 그림 · 어셈블·링크 단계

함수·코드 범위: absolute_data32

빌드 도구
처리 전소스의 명령·배치 표기
이 줄의 효과SYM_FUNC_START(absolute_data32)
CPU 레지스터
처리 전해당 없음
이 줄의 효과지시문 자체는 레지스터를 쓰지 않습니다.

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

  • 함수 시작 매크로는 심벌·정렬 정보와 BTI 진입 명령 등을 배치할 수 있습니다. 생성된 명령의 실행과 심벌 선언을 구분합니다.
	ldr	w0, 0f

32비트 절대 심볼 리터럴을 w0에 읽습니다. W 레지스터에 쓰면 x0 상위 32비트가 0이 되므로 64비트 C 반환값도 0x00000000f800cccc가 됩니다. 이 LDR 리터럴 형식은 PC 기준으로 레이블 위치를 찾아 그곳의 메모리를 읽습니다. 레이블 주소 자체를 구하는 ADR과 구분합니다.

15행 그림 · 메모리 읽기

함수·코드 범위: absolute_data32

w0
이 명령을 실행하기 직전명령 직전 w0의 값
이 명령을 실행한 직후메모리[0f]의 값
x0[63:32]
이 명령을 실행하기 직전명령 직전 x0[63:32]의 값
이 명령을 실행한 직후0

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

  • =심벌이면 주소 상수를 리터럴 풀에서 읽는 의사 명령입니다. 레이블만 적힌 LDR은 해당 위치의 메모리를 읽습니다.
	ret

32비트 절대 심볼을 읽은 결과를 x0로 반환하여 C 쪽 기대값과 비교하게 합니다. 피연산자가 없는 RET는 LR(x30)에 들어 있는 주소에서 실행을 이어갑니다.

16행 그림 · 호출과 실행 위치

함수·코드 범위: absolute_data32

읽는 값lr
PC
이 명령을 실행하기 직전명령 직전 PC의 값
이 명령을 실행한 직후명령 직전 lr의 값

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

  • 새 복귀 주소를 LR에 기록하지 않습니다. RET 역시 메모리의 스택 값을 자동으로 꺼내는 명령은 아닙니다.
0:	.long	sym32_abs

이 .long은 CPU 명령이 아니라 항목당 4바이트 데이터와 필요한 재배치 정보를 내보내는 어셈블러 지시문입니다. 아직 확정되지 않은 심벌 값은 링크 또는 모듈 적재 시의 재배치 처리로 채웁니다. 이 테스트 함수가 실행될 때에는 앞의 load 명령이 채워진 데이터를 읽습니다. sym32_abs 값을 32비트 데이터 필드에 채우도록 ABS32 재배치를 만듭니다.

17행 그림 · 어셈블·링크 단계

함수·코드 범위: absolute_data32

빌드 도구
처리 전소스의 명령·배치 표기
이 줄의 효과0: .long sym32_abs
CPU 레지스터
처리 전해당 없음
이 줄의 효과지시문 자체는 레지스터를 쓰지 않습니다.

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

SYM_FUNC_END(absolute_data32)

도구에 이 코드 범위의 끝을 알려 크기와 심볼 정보를 기록합니다. CPU가 이 줄 때문에 자동으로 반환하지는 않습니다.

18행 그림 · 어셈블·링크 단계

함수·코드 범위: absolute_data32

빌드 도구
처리 전소스의 명령·배치 표기
이 줄의 효과SYM_FUNC_END(absolute_data32)
CPU 레지스터
처리 전해당 없음
이 줄의 효과지시문 자체는 레지스터를 쓰지 않습니다.

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

  • 끝 표기 자체가 RET나 분기를 실행하지는 않습니다.
SYM_FUNC_START(absolute_data16)

R_AARCH64_ABS16 재배치를 검사하는 함수입니다. 16비트 테스트 상수 0xf8cc를 읽어 C 코드의 기대값과 비교합니다. 이 선언은 함수 심볼과 정렬을 정하고, ARM64 정의에서는 간접 호출이 도착할 BTI C 명령도 진입부에 넣습니다. 여기서는 전역 심벌로 정의하므로 다른 오브젝트에서도 이 함수 이름을 참조할 수 있습니다. 모듈용 EXPORT_SYMBOL 등록은 별도입니다.

20행 그림 · 어셈블·링크 단계

함수·코드 범위: absolute_data16

빌드 도구
처리 전소스의 명령·배치 표기
이 줄의 효과SYM_FUNC_START(absolute_data16)
CPU 레지스터
처리 전해당 없음
이 줄의 효과지시문 자체는 레지스터를 쓰지 않습니다.

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

  • 함수 시작 매크로는 심벌·정렬 정보와 BTI 진입 명령 등을 배치할 수 있습니다. 생성된 명령의 실행과 심벌 선언을 구분합니다.
	adr	x0, 0f

16비트 리터럴에는 LDRH 리터럴 형식이 없으므로 먼저 뒤의 데이터 주소를 x0에 구합니다. 여기서 얻는 것은 레이블의 주소이며, 그 위치의 메모리 내용은 아직 읽지 않습니다.

21행 그림 · 주소·값 구분

함수·코드 범위: absolute_data16

x0
이 명령을 실행하기 직전명령 직전 x0의 값
이 명령을 실행한 직후주소(0f)

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

  • 주소 계산이며 그 주소의 메모리는 읽지 않습니다.
	ldrh	w0, [x0]

그 주소에서 16비트 값을 0으로 확장하여 w0에 읽습니다. 결과 x0는 테스트 상수 0xf8cc가 됩니다.

22행 그림 · 메모리 읽기

함수·코드 범위: absolute_data16

읽는 값x0
메모리[이전 x0] · 2바이트
이 명령을 실행하기 직전M0 (이 주소에 저장된 값)
이 명령을 실행한 직후M0 (이 주소에 저장된 값)
w0
이 명령을 실행하기 직전명령 직전 w0의 값
이 명령을 실행한 직후M0를 0으로 확장
x0[63:32]
이 명령을 실행하기 직전명령 직전 x0[63:32]의 값
이 명령을 실행한 직후0

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

  • 주소 계산에 의한 기준 레지스터 갱신은 없습니다. 다만 LDR/LDP의 목적 레지스터가 기준 레지스터와 같으면 읽은 값이 그 레지스터를 덮어씁니다.
	ret

16비트 절대 심볼값을 테스트 호출자에게 돌려줍니다. 피연산자가 없는 RET는 LR(x30)에 들어 있는 주소에서 실행을 이어갑니다.

23행 그림 · 호출과 실행 위치

함수·코드 범위: absolute_data16

읽는 값lr
PC
이 명령을 실행하기 직전명령 직전 PC의 값
이 명령을 실행한 직후명령 직전 lr의 값

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

  • 새 복귀 주소를 LR에 기록하지 않습니다. RET 역시 메모리의 스택 값을 자동으로 꺼내는 명령은 아닙니다.
0:	.short	sym16_abs, 0

이 .short은 CPU 명령이 아니라 항목당 2바이트 데이터와 필요한 재배치 정보를 내보내는 어셈블러 지시문입니다. 아직 확정되지 않은 심벌 값은 링크 또는 모듈 적재 시의 재배치 처리로 채웁니다. 이 테스트 함수가 실행될 때에는 앞의 load 명령이 채워진 데이터를 읽습니다. ABS16 재배치로 채울 sym16_abs와 뒤따르는 16비트 0을 배치합니다. 앞의 halfword가 검사 대상이고 뒤의 0은 데이터 크기를 맞추는 공간입니다.

24행 그림 · 어셈블·링크 단계

함수·코드 범위: absolute_data16

빌드 도구
처리 전소스의 명령·배치 표기
이 줄의 효과0: .short sym16_abs, 0
CPU 레지스터
처리 전해당 없음
이 줄의 효과지시문 자체는 레지스터를 쓰지 않습니다.

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

SYM_FUNC_END(absolute_data16)

도구에 이 코드 범위의 끝을 알려 크기와 심볼 정보를 기록합니다. CPU가 이 줄 때문에 자동으로 반환하지는 않습니다.

25행 그림 · 어셈블·링크 단계

함수·코드 범위: absolute_data16

빌드 도구
처리 전소스의 명령·배치 표기
이 줄의 효과SYM_FUNC_END(absolute_data16)
CPU 레지스터
처리 전해당 없음
이 줄의 효과지시문 자체는 레지스터를 쓰지 않습니다.

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

  • 끝 표기 자체가 RET나 분기를 실행하지는 않습니다.

MOVW 재배치 조합

원본 26–41행

SYM_FUNC_START(signed_movw)

부호 있는 MOVW 재배치를 통해 64비트 절대값을 만드는 테스트입니다. 명령의 즉시값뿐 아니라 부호에 따른 MOVZ/MOVN 선택이 올바르게 적용되는지도 확인합니다. 이 선언은 함수 심볼과 정렬을 정하고, ARM64 정의에서는 간접 호출이 도착할 BTI C 명령도 진입부에 넣습니다. 여기서는 전역 심벌로 정의하므로 다른 오브젝트에서도 이 함수 이름을 참조할 수 있습니다. 모듈용 EXPORT_SYMBOL 등록은 별도입니다.

27행 그림 · 어셈블·링크 단계

함수·코드 범위: signed_movw

빌드 도구
처리 전소스의 명령·배치 표기
이 줄의 효과SYM_FUNC_START(signed_movw)
CPU 레지스터
처리 전해당 없음
이 줄의 효과지시문 자체는 레지스터를 쓰지 않습니다.

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

  • 함수 시작 매크로는 심벌·정렬 정보와 BTI 진입 명령 등을 배치할 수 있습니다. 생성된 명령의 실행과 심벌 선언을 구분합니다.
	movz	x0, #:abs_g2_s:sym64_abs

sym64_abs의 비트 32~47에 해당하는 그룹을 부호 있는 재배치로 넣습니다. 이 테스트 상수는 음수로 해석되는 값이므로 모듈 로더가 MOVN 형식도 선택할 수 있습니다. 소스에 MOVZ라고 적힌 것만 보고 나머지 상위 비트가 항상 0이라고 설명하면 안 됩니다. 이 재배치는 명령어의 즉시값 비트를 채우는 것이며, 실행 중 심벌이 가리키는 메모리 데이터를 읽는 작업은 아닙니다.

:abs_g2_s:는 signed MOVW 재배치입니다. 음수 값 구성에는 링커가 MOVN 형태를 선택할 수 있어 원문 MOVZ만으로 상위 비트를 단정하지 않습니다.

28행 그림 · 상수의 비트 조각 구성

함수·코드 범위: signed_movw

x0
이 명령을 실행하기 직전명령 직전 x0의 값
이 명령을 실행한 직후심벌의 부호에 맞게 MOVZ 또는 MOVN으로 구성한 값

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

  • 부호 있는 재배치가 실제 명령의 MOVZ/MOVN 선택에도 영향을 주므로 남은 비트를 항상 0이라고 표시하지 않습니다.
	movk	x0, #:abs_g1_nc:sym64_abs

비트 16~31 그룹을 MOVK로 덮어씁니다. 이미 만든 나머지 비트는 유지하며 _nc는 이 부분 재배치에서 별도 overflow 검사를 하지 않는다는 뜻입니다.

29행 그림 · 상수의 비트 조각 구성

함수·코드 범위: signed_movw

읽는 값x0
x0
이 명령을 실행하기 직전명령 직전 x0의 값
이 명령을 실행한 직후명령 직전 값에서 [31:16]만 :abs_g1_nc:sym64_abs로 교체

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

  • 선택한 16비트 이외의 비트는 그대로 남습니다.
	movk	x0, #:abs_g0_nc:sym64_abs

하위 16비트를 채워 테스트용 64비트 절대값을 완성합니다. MOVK는 선택한 16비트 조각만 덮어쓰고 나머지 비트는 유지합니다.

30행 그림 · 상수의 비트 조각 구성

함수·코드 범위: signed_movw

읽는 값x0
x0
이 명령을 실행하기 직전명령 직전 x0의 값
이 명령을 실행한 직후명령 직전 값에서 [15:0]만 :abs_g0_nc:sym64_abs로 교체

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

  • 선택한 16비트 이외의 비트는 그대로 남습니다.
	ret

조립한 값을 C 테스트에 돌려줍니다. 기대값은 absolute_data64와 같은 0xffff880000cccccc입니다. 피연산자가 없는 RET는 LR(x30)에 들어 있는 주소에서 실행을 이어갑니다.

31행 그림 · 호출과 실행 위치

함수·코드 범위: signed_movw

읽는 값lr
PC
이 명령을 실행하기 직전명령 직전 PC의 값
이 명령을 실행한 직후명령 직전 lr의 값

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

  • 새 복귀 주소를 LR에 기록하지 않습니다. RET 역시 메모리의 스택 값을 자동으로 꺼내는 명령은 아닙니다.
SYM_FUNC_END(signed_movw)

도구에 이 코드 범위의 끝을 알려 크기와 심볼 정보를 기록합니다. CPU가 이 줄 때문에 자동으로 반환하지는 않습니다.

32행 그림 · 어셈블·링크 단계

함수·코드 범위: signed_movw

빌드 도구
처리 전소스의 명령·배치 표기
이 줄의 효과SYM_FUNC_END(signed_movw)
CPU 레지스터
처리 전해당 없음
이 줄의 효과지시문 자체는 레지스터를 쓰지 않습니다.

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

  • 끝 표기 자체가 RET나 분기를 실행하지는 않습니다.
SYM_FUNC_START(unsigned_movw)

부호 없는 MOVW 재배치 네 개로 64비트 절대값을 만드는 테스트입니다. 상위 그룹부터 각 16비트 조각을 채웁니다. 이 선언은 함수 심볼과 정렬을 정하고, ARM64 정의에서는 간접 호출이 도착할 BTI C 명령도 진입부에 넣습니다. 여기서는 전역 심벌로 정의하므로 다른 오브젝트에서도 이 함수 이름을 참조할 수 있습니다. 모듈용 EXPORT_SYMBOL 등록은 별도입니다.

34행 그림 · 어셈블·링크 단계

함수·코드 범위: unsigned_movw

빌드 도구
처리 전소스의 명령·배치 표기
이 줄의 효과SYM_FUNC_START(unsigned_movw)
CPU 레지스터
처리 전해당 없음
이 줄의 효과지시문 자체는 레지스터를 쓰지 않습니다.

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

  • 함수 시작 매크로는 심벌·정렬 정보와 BTI 진입 명령 등을 배치할 수 있습니다. 생성된 명령의 실행과 심벌 선언을 구분합니다.
	movz	x0, #:abs_g3:sym64_abs

sym64_abs의 최상위 비트 48~63을 넣고 다른 비트는 초기화합니다. 뒤의 세 MOVK가 나머지 48비트를 채웁니다. 이 재배치는 명령어의 즉시값 비트를 채우는 것이며, 실행 중 심벌이 가리키는 메모리 데이터를 읽는 작업은 아닙니다.

35행 그림 · 상수의 비트 조각 구성

함수·코드 범위: unsigned_movw

x0
이 명령을 실행하기 직전명령 직전 x0의 값
이 명령을 실행한 직후:abs_g3:sym64_abs의 16비트 조각을 [63:48]에 배치, 나머지는 0

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

	movk	x0, #:abs_g2_nc:sym64_abs

비트 32~47을 채웁니다. 앞서 넣은 최상위 16비트는 그대로 보존합니다. MOVK는 선택한 16비트 조각만 덮어쓰고 나머지 비트는 유지합니다.

36행 그림 · 상수의 비트 조각 구성

함수·코드 범위: unsigned_movw

읽는 값x0
x0
이 명령을 실행하기 직전명령 직전 x0의 값
이 명령을 실행한 직후명령 직전 값에서 [47:32]만 :abs_g2_nc:sym64_abs로 교체

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

  • 선택한 16비트 이외의 비트는 그대로 남습니다.
	movk	x0, #:abs_g1_nc:sym64_abs

비트 16~31을 채워 절대값을 계속 구성합니다. MOVK는 선택한 16비트 조각만 덮어쓰고 나머지 비트는 유지합니다.

37행 그림 · 상수의 비트 조각 구성

함수·코드 범위: unsigned_movw

읽는 값x0
x0
이 명령을 실행하기 직전명령 직전 x0의 값
이 명령을 실행한 직후명령 직전 값에서 [31:16]만 :abs_g1_nc:sym64_abs로 교체

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

  • 선택한 16비트 이외의 비트는 그대로 남습니다.
	movk	x0, #:abs_g0_nc:sym64_abs

하위 16비트를 채워 64비트 테스트 상수를 완성합니다. MOVK는 선택한 16비트 조각만 덮어쓰고 나머지 비트는 유지합니다.

38행 그림 · 상수의 비트 조각 구성

함수·코드 범위: unsigned_movw

읽는 값x0
x0
이 명령을 실행하기 직전명령 직전 x0의 값
이 명령을 실행한 직후명령 직전 값에서 [15:0]만 :abs_g0_nc:sym64_abs로 교체

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

  • 선택한 16비트 이외의 비트는 그대로 남습니다.
	ret

부호 없는 MOVW 재배치로 구성한 값이 기대 상수와 같은지 C 코드가 확인하도록 반환합니다. 피연산자가 없는 RET는 LR(x30)에 들어 있는 주소에서 실행을 이어갑니다.

39행 그림 · 호출과 실행 위치

함수·코드 범위: unsigned_movw

읽는 값lr
PC
이 명령을 실행하기 직전명령 직전 PC의 값
이 명령을 실행한 직후명령 직전 lr의 값

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

  • 새 복귀 주소를 LR에 기록하지 않습니다. RET 역시 메모리의 스택 값을 자동으로 꺼내는 명령은 아닙니다.
SYM_FUNC_END(unsigned_movw)

도구에 이 코드 범위의 끝을 알려 크기와 심볼 정보를 기록합니다. CPU가 이 줄 때문에 자동으로 반환하지는 않습니다.

40행 그림 · 어셈블·링크 단계

함수·코드 범위: unsigned_movw

빌드 도구
처리 전소스의 명령·배치 표기
이 줄의 효과SYM_FUNC_END(unsigned_movw)
CPU 레지스터
처리 전해당 없음
이 줄의 효과지시문 자체는 레지스터를 쓰지 않습니다.

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

  • 끝 표기 자체가 RET나 분기를 실행하지는 않습니다.

페이지 경계 근처의 ADRP

원본 42–62행

	.align	12

다음 테스트를 4KiB 경계 기준으로 배치합니다. ADRP는 커널의 PAGE_SIZE 설정과 별개로 4KiB 단위 페이지 주소를 계산하므로 이 경계가 중요합니다. AArch64의 .align 인자는 바이트 수가 아니라 2의 지수입니다. 빌드할 때 필요한 패딩을 넣어 그 경계를 맞춥니다.

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

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

	.space	0xff8

0xff8바이트를 채워 다음 테스트를 4KiB 경계 가까이에 놓습니다. 재배치 명령의 위치가 페이지 경계에 가까울 때도 주소 계산이 맞는지 시험하기 위한 배치입니다.

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

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

SYM_FUNC_START(relative_adrp)

같은 테스트 모듈의 sym64_rel 주소를 ADRP+ADD로 만드는 함수입니다. 결과는 변수의 값이 아니라 변수 자체의 주소여야 합니다. 이 선언은 함수 심볼과 정렬을 정하고, ARM64 정의에서는 간접 호출이 도착할 BTI C 명령도 진입부에 넣습니다. 여기서는 전역 심벌로 정의하므로 다른 오브젝트에서도 이 함수 이름을 참조할 수 있습니다. 모듈용 EXPORT_SYMBOL 등록은 별도입니다.

44행 그림 · 어셈블·링크 단계

함수·코드 범위: relative_adrp

빌드 도구
처리 전소스의 명령·배치 표기
이 줄의 효과SYM_FUNC_START(relative_adrp)
CPU 레지스터
처리 전해당 없음
이 줄의 효과지시문 자체는 레지스터를 쓰지 않습니다.

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

  • 함수 시작 매크로는 심벌·정렬 정보와 BTI 진입 명령 등을 배치할 수 있습니다. 생성된 명령의 실행과 심벌 선언을 구분합니다.
	adrp	x0, sym64_rel

PC 상대 페이지 재배치로 sym64_rel이 속한 4KiB 페이지 주소를 x0에 만듭니다. 모듈이 어느 주소에 적재됐는지에 따라 명령의 즉시값이 조정됩니다. 여기서 얻는 것은 레이블의 주소이며, 그 위치의 메모리 내용은 아직 읽지 않습니다. ADRP가 만드는 주소는 4KiB 경계까지만입니다. 심벌의 하위 12비트가 0이면 그 자체가 심벌 주소이고, 그렇지 않으면 별도 오프셋 계산이 필요합니다.

45행 그림 · 주소·값 구분

함수·코드 범위: relative_adrp

x0
이 명령을 실행하기 직전명령 직전 x0의 값
이 명령을 실행한 직후주소(sym64_rel)의 하위 12비트를 0으로 만든 값

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

  • ADRP의 페이지 단위는 4KiB입니다.
	add	x0, x0, #:lo12:sym64_rel

심볼 주소의 하위 12비트를 더해 페이지 안의 정확한 바이트 주소를 완성합니다. 이 ADD 형식은 NZCV 조건 플래그를 바꾸지 않습니다.

46행 그림 · 레지스터 상태

함수·코드 범위: relative_adrp

읽는 값x0
x0
이 명령을 실행하기 직전명령 직전 x0의 값
이 명령을 실행한 직후명령 직전 x0의 값 + :lo12:sym64_rel

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

  • 결과는 목적 레지스터 폭에 맞습니다. 이 형식은 NZCV를 바꾸지 않습니다.
	ret

구한 sym64_rel 주소를 반환합니다. C 테스트는 &sym64_rel과 일치하는지 확인합니다. 피연산자가 없는 RET는 LR(x30)에 들어 있는 주소에서 실행을 이어갑니다.

47행 그림 · 호출과 실행 위치

함수·코드 범위: relative_adrp

읽는 값lr
PC
이 명령을 실행하기 직전명령 직전 PC의 값
이 명령을 실행한 직후명령 직전 lr의 값

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

  • 새 복귀 주소를 LR에 기록하지 않습니다. RET 역시 메모리의 스택 값을 자동으로 꺼내는 명령은 아닙니다.
SYM_FUNC_END(relative_adrp)

도구에 이 코드 범위의 끝을 알려 크기와 심볼 정보를 기록합니다. CPU가 이 줄 때문에 자동으로 반환하지는 않습니다.

48행 그림 · 어셈블·링크 단계

함수·코드 범위: relative_adrp

빌드 도구
처리 전소스의 명령·배치 표기
이 줄의 효과SYM_FUNC_END(relative_adrp)
CPU 레지스터
처리 전해당 없음
이 줄의 효과지시문 자체는 레지스터를 쓰지 않습니다.

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

  • 끝 표기 자체가 RET나 분기를 실행하지는 않습니다.
	.align	12

다음 ADRP 테스트의 배치 기준도 4KiB 경계에 맞춥니다. AArch64의 .align 인자는 바이트 수가 아니라 2의 지수입니다. 빌드할 때 필요한 패딩을 넣어 그 경계를 맞춥니다.

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

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

	.space	0xffc

0xffc바이트를 채워 다음 테스트를 페이지 경계 가까이에 놓습니다. 명령 위치의 페이지 계산과 먼 심볼 재배치 처리를 확인하기 위한 공간입니다.

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

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

SYM_FUNC_START(relative_adrp_far)

모듈 내부 심볼 대신 커널의 memstart_addr 주소를 대상으로 ADRP 재배치를 시험합니다. 모듈과 커널 사이 거리에 따른 처리도 검증 대상입니다. 이 선언은 함수 심볼과 정렬을 정하고, ARM64 정의에서는 간접 호출이 도착할 BTI C 명령도 진입부에 넣습니다. 여기서는 전역 심벌로 정의하므로 다른 오브젝트에서도 이 함수 이름을 참조할 수 있습니다. 모듈용 EXPORT_SYMBOL 등록은 별도입니다.

52행 그림 · 어셈블·링크 단계

함수·코드 범위: relative_adrp_far

빌드 도구
처리 전소스의 명령·배치 표기
이 줄의 효과SYM_FUNC_START(relative_adrp_far)
CPU 레지스터
처리 전해당 없음
이 줄의 효과지시문 자체는 레지스터를 쓰지 않습니다.

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

  • 함수 시작 매크로는 심벌·정렬 정보와 BTI 진입 명령 등을 배치할 수 있습니다. 생성된 명령의 실행과 심벌 선언을 구분합니다.
	adrp	x0, memstart_addr

memstart_addr가 있는 4KiB 페이지 주소를 만듭니다. 모듈 로더는 이 외부 심볼의 최종 주소를 이용해 ADRP 재배치를 적용합니다. 여기서 얻는 것은 레이블의 주소이며, 그 위치의 메모리 내용은 아직 읽지 않습니다. ADRP가 만드는 주소는 4KiB 경계까지만입니다. 심벌의 하위 12비트가 0이면 그 자체가 심벌 주소이고, 그렇지 않으면 별도 오프셋 계산이 필요합니다.

53행 그림 · 주소·값 구분

함수·코드 범위: relative_adrp_far

x0
이 명령을 실행하기 직전명령 직전 x0의 값
이 명령을 실행한 직후주소(memstart_addr)의 하위 12비트를 0으로 만든 값

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

  • ADRP의 페이지 단위는 4KiB입니다.
	add	x0, x0, #:lo12:memstart_addr

memstart_addr의 페이지 내부 오프셋을 더해 변수의 주소를 완성합니다. memstart_addr에 저장된 물리 메모리 시작값을 읽는 명령은 아닙니다. 이 ADD 형식은 NZCV 조건 플래그를 바꾸지 않습니다.

54행 그림 · 레지스터 상태

함수·코드 범위: relative_adrp_far

읽는 값x0
x0
이 명령을 실행하기 직전명령 직전 x0의 값
이 명령을 실행한 직후명령 직전 x0의 값 + :lo12:memstart_addr

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

  • 결과는 목적 레지스터 폭에 맞습니다. 이 형식은 NZCV를 바꾸지 않습니다.
	ret

&memstart_addr와 비교할 주소를 x0로 반환합니다. 피연산자가 없는 RET는 LR(x30)에 들어 있는 주소에서 실행을 이어갑니다.

55행 그림 · 호출과 실행 위치

함수·코드 범위: relative_adrp_far

읽는 값lr
PC
이 명령을 실행하기 직전명령 직전 PC의 값
이 명령을 실행한 직후명령 직전 lr의 값

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

  • 새 복귀 주소를 LR에 기록하지 않습니다. RET 역시 메모리의 스택 값을 자동으로 꺼내는 명령은 아닙니다.
SYM_FUNC_END(relative_adrp_far)

도구에 이 코드 범위의 끝을 알려 크기와 심볼 정보를 기록합니다. CPU가 이 줄 때문에 자동으로 반환하지는 않습니다.

56행 그림 · 어셈블·링크 단계

함수·코드 범위: relative_adrp_far

빌드 도구
처리 전소스의 명령·배치 표기
이 줄의 효과SYM_FUNC_END(relative_adrp_far)
CPU 레지스터
처리 전해당 없음
이 줄의 효과지시문 자체는 레지스터를 쓰지 않습니다.

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

  • 끝 표기 자체가 RET나 분기를 실행하지는 않습니다.
SYM_FUNC_START(relative_adr)

ADRP의 페이지 계산 없이 ADR 한 명령으로 PC 상대 주소를 만드는 재배치 테스트입니다. 이 선언은 함수 심볼과 정렬을 정하고, ARM64 정의에서는 간접 호출이 도착할 BTI C 명령도 진입부에 넣습니다. 여기서는 전역 심벌로 정의하므로 다른 오브젝트에서도 이 함수 이름을 참조할 수 있습니다. 모듈용 EXPORT_SYMBOL 등록은 별도입니다.

58행 그림 · 어셈블·링크 단계

함수·코드 범위: relative_adr

빌드 도구
처리 전소스의 명령·배치 표기
이 줄의 효과SYM_FUNC_START(relative_adr)
CPU 레지스터
처리 전해당 없음
이 줄의 효과지시문 자체는 레지스터를 쓰지 않습니다.

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

  • 함수 시작 매크로는 심벌·정렬 정보와 BTI 진입 명령 등을 배치할 수 있습니다. 생성된 명령의 실행과 심벌 선언을 구분합니다.
	adr	x0, sym64_rel

R_AARCH64_ADR_PREL_LO21 재배치를 통해 sym64_rel의 주소를 x0에 만듭니다. 주소 차이가 ADR이 표현할 수 있는 범위에 들어가는지도 로더가 처리합니다. 여기서 얻는 것은 레이블의 주소이며, 그 위치의 메모리 내용은 아직 읽지 않습니다.

59행 그림 · 주소·값 구분

함수·코드 범위: relative_adr

x0
이 명령을 실행하기 직전명령 직전 x0의 값
이 명령을 실행한 직후주소(sym64_rel)

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

  • 주소 계산이며 그 주소의 메모리는 읽지 않습니다.
	ret

ADR로 계산한 주소를 C 테스트의 &sym64_rel과 비교하도록 반환합니다. 피연산자가 없는 RET는 LR(x30)에 들어 있는 주소에서 실행을 이어갑니다.

60행 그림 · 호출과 실행 위치

함수·코드 범위: relative_adr

읽는 값lr
PC
이 명령을 실행하기 직전명령 직전 PC의 값
이 명령을 실행한 직후명령 직전 lr의 값

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

  • 새 복귀 주소를 LR에 기록하지 않습니다. RET 역시 메모리의 스택 값을 자동으로 꺼내는 명령은 아닙니다.
SYM_FUNC_END(relative_adr)

도구에 이 코드 범위의 끝을 알려 크기와 심볼 정보를 기록합니다. CPU가 이 줄 때문에 자동으로 반환하지는 않습니다.

61행 그림 · 어셈블·링크 단계

함수·코드 범위: relative_adr

빌드 도구
처리 전소스의 명령·배치 표기
이 줄의 효과SYM_FUNC_END(relative_adr)
CPU 레지스터
처리 전해당 없음
이 줄의 효과지시문 자체는 레지스터를 쓰지 않습니다.

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

  • 끝 표기 자체가 RET나 분기를 실행하지는 않습니다.

상대 데이터를 절대 주소로 복원

원본 63–85행

SYM_FUNC_START(relative_data64)

64비트 PC 상대 데이터 재배치를 검사하는 함수입니다. 리터럴에는 주소 자체가 아니라 그 리터럴 위치에서 심볼까지의 차이가 들어갑니다. 이 선언은 함수 심볼과 정렬을 정하고, ARM64 정의에서는 간접 호출이 도착할 BTI C 명령도 진입부에 넣습니다. 여기서는 전역 심벌로 정의하므로 다른 오브젝트에서도 이 함수 이름을 참조할 수 있습니다. 모듈용 EXPORT_SYMBOL 등록은 별도입니다.

63행 그림 · 어셈블·링크 단계

함수·코드 범위: relative_data64

빌드 도구
처리 전소스의 명령·배치 표기
이 줄의 효과SYM_FUNC_START(relative_data64)
CPU 레지스터
처리 전해당 없음
이 줄의 효과지시문 자체는 레지스터를 쓰지 않습니다.

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

  • 함수 시작 매크로는 심벌·정렬 정보와 BTI 진입 명령 등을 배치할 수 있습니다. 생성된 명령의 실행과 심벌 선언을 구분합니다.
	adr	x1, 0f

상대 오프셋이 저장된 리터럴의 주소를 x1에 구합니다. 이 주소가 나중에 오프셋을 더할 기준점이 됩니다. 여기서 얻는 것은 레이블의 주소이며, 그 위치의 메모리 내용은 아직 읽지 않습니다.

64행 그림 · 주소·값 구분

함수·코드 범위: relative_data64

x1
이 명령을 실행하기 직전명령 직전 x1의 값
이 명령을 실행한 직후주소(0f)

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

  • 주소 계산이며 그 주소의 메모리는 읽지 않습니다.
	ldr	x0, [x1]

리터럴의 64비트 상대 오프셋을 x0에 읽습니다. 실제로 x1 주소의 메모리 8바이트를 x0에 읽습니다. 이 주소 형식은 기준 레지스터 x1 자체를 갱신하지 않습니다.

65행 그림 · 메모리 읽기

함수·코드 범위: relative_data64

읽는 값x1
메모리[이전 x1] · 8바이트
이 명령을 실행하기 직전M0 (이 주소에 저장된 값)
이 명령을 실행한 직후M0 (이 주소에 저장된 값)
x0
이 명령을 실행하기 직전명령 직전 x0의 값
이 명령을 실행한 직후M0

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

  • 주소 계산에 의한 기준 레지스터 갱신은 없습니다. 다만 LDR/LDP의 목적 레지스터가 기준 레지스터와 같으면 읽은 값이 그 레지스터를 덮어씁니다.
	add	x0, x0, x1

리터럴 위치 x1에 오프셋을 더해 sym64_rel의 실제 주소를 복원합니다. 이 ADD 형식은 NZCV 조건 플래그를 바꾸지 않습니다.

66행 그림 · 레지스터 상태

함수·코드 범위: relative_data64

읽는 값x0x1
x0
이 명령을 실행하기 직전명령 직전 x0의 값
이 명령을 실행한 직후명령 직전 x0의 값 + 명령 직전 x1의 값

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

  • 결과는 목적 레지스터 폭에 맞습니다. 이 형식은 NZCV를 바꾸지 않습니다.
	ret

PREL64로 복원한 주소가 &sym64_rel과 같은지 검사하도록 반환합니다. 피연산자가 없는 RET는 LR(x30)에 들어 있는 주소에서 실행을 이어갑니다.

67행 그림 · 호출과 실행 위치

함수·코드 범위: relative_data64

읽는 값lr
PC
이 명령을 실행하기 직전명령 직전 PC의 값
이 명령을 실행한 직후명령 직전 lr의 값

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

  • 새 복귀 주소를 LR에 기록하지 않습니다. RET 역시 메모리의 스택 값을 자동으로 꺼내는 명령은 아닙니다.
0:	.quad	sym64_rel - .

이 .quad은 CPU 명령이 아니라 항목당 8바이트 데이터와 필요한 재배치 정보를 내보내는 어셈블러 지시문입니다. 아직 확정되지 않은 심벌 값은 링크 또는 모듈 적재 시의 재배치 처리로 채웁니다. 이 테스트 함수가 실행될 때에는 앞의 load 명령이 채워진 데이터를 읽습니다. sym64_rel 주소에서 현재 데이터 위치를 뺀 64비트 값을 놓도록 PREL64 재배치를 만듭니다. 점(.)은 이 데이터가 놓이는 위치입니다.

이 .quad가 놓인 주소를 기준으로 한 차이를 저장하므로 실행 시 같은 위치 x1을 더하면 sym64_rel 주소가 됩니다.

68행 그림 · 어셈블·링크 단계

함수·코드 범위: relative_data64

빌드 도구
처리 전소스의 명령·배치 표기
이 줄의 효과0: .quad sym64_rel - .
CPU 레지스터
처리 전해당 없음
이 줄의 효과지시문 자체는 레지스터를 쓰지 않습니다.

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

SYM_FUNC_END(relative_data64)

도구에 이 코드 범위의 끝을 알려 크기와 심볼 정보를 기록합니다. CPU가 이 줄 때문에 자동으로 반환하지는 않습니다.

69행 그림 · 어셈블·링크 단계

함수·코드 범위: relative_data64

빌드 도구
처리 전소스의 명령·배치 표기
이 줄의 효과SYM_FUNC_END(relative_data64)
CPU 레지스터
처리 전해당 없음
이 줄의 효과지시문 자체는 레지스터를 쓰지 않습니다.

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

  • 끝 표기 자체가 RET나 분기를 실행하지는 않습니다.
SYM_FUNC_START(relative_data32)

32비트 PC 상대 데이터 재배치를 검사합니다. 상대값을 저장한 위치의 주소에 읽어 온 값을 더해 심볼 주소를 만드는 방식입니다. 이 선언은 함수 심볼과 정렬을 정하고, ARM64 정의에서는 간접 호출이 도착할 BTI C 명령도 진입부에 넣습니다. 여기서는 전역 심벌로 정의하므로 다른 오브젝트에서도 이 함수 이름을 참조할 수 있습니다. 모듈용 EXPORT_SYMBOL 등록은 별도입니다.

71행 그림 · 어셈블·링크 단계

함수·코드 범위: relative_data32

빌드 도구
처리 전소스의 명령·배치 표기
이 줄의 효과SYM_FUNC_START(relative_data32)
CPU 레지스터
처리 전해당 없음
이 줄의 효과지시문 자체는 레지스터를 쓰지 않습니다.

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

  • 함수 시작 매크로는 심벌·정렬 정보와 BTI 진입 명령 등을 배치할 수 있습니다. 생성된 명령의 실행과 심벌 선언을 구분합니다.
	adr	x1, 0f

32비트 상대 오프셋 리터럴의 주소를 x1에 구합니다. 여기서 얻는 것은 레이블의 주소이며, 그 위치의 메모리 내용은 아직 읽지 않습니다.

72행 그림 · 주소·값 구분

함수·코드 범위: relative_data32

x1
이 명령을 실행하기 직전명령 직전 x1의 값
이 명령을 실행한 직후주소(0f)

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

  • 주소 계산이며 그 주소의 메모리는 읽지 않습니다.
	ldr	w0, [x1]

32비트 상대값을 w0에 읽습니다. 이 명령은 x0 상위 비트를 0으로 만듭니다. 따라서 모든 부호 있는 32비트 오프셋을 64비트로 부호 확장하는 일반 해법으로 읽어서는 안 되며 이 테스트의 배치와 함께 봐야 합니다. 이 주소 형식은 기준 레지스터 x1 자체를 갱신하지 않습니다.

73행 그림 · 메모리 읽기

함수·코드 범위: relative_data32

읽는 값x1
메모리[이전 x1] · 4바이트
이 명령을 실행하기 직전M0 (이 주소에 저장된 값)
이 명령을 실행한 직후M0 (이 주소에 저장된 값)
w0
이 명령을 실행하기 직전명령 직전 w0의 값
이 명령을 실행한 직후M0
x0[63:32]
이 명령을 실행하기 직전명령 직전 x0[63:32]의 값
이 명령을 실행한 직후0

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

  • 주소 계산에 의한 기준 레지스터 갱신은 없습니다. 다만 LDR/LDP의 목적 레지스터가 기준 레지스터와 같으면 읽은 값이 그 레지스터를 덮어씁니다.
	add	x0, x0, x1

읽은 상대값을 리터럴의 실제 주소에 더하여 테스트 심볼 주소를 만듭니다. 이 ADD 형식은 NZCV 조건 플래그를 바꾸지 않습니다.

74행 그림 · 레지스터 상태

함수·코드 범위: relative_data32

읽는 값x0x1
x0
이 명령을 실행하기 직전명령 직전 x0의 값
이 명령을 실행한 직후명령 직전 x0의 값 + 명령 직전 x1의 값

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

  • 결과는 목적 레지스터 폭에 맞습니다. 이 형식은 NZCV를 바꾸지 않습니다.
	ret

PREL32 결과를 C 코드가 예상한 sym64_rel 주소와 비교하도록 반환합니다. 피연산자가 없는 RET는 LR(x30)에 들어 있는 주소에서 실행을 이어갑니다.

75행 그림 · 호출과 실행 위치

함수·코드 범위: relative_data32

읽는 값lr
PC
이 명령을 실행하기 직전명령 직전 PC의 값
이 명령을 실행한 직후명령 직전 lr의 값

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

  • 새 복귀 주소를 LR에 기록하지 않습니다. RET 역시 메모리의 스택 값을 자동으로 꺼내는 명령은 아닙니다.
0:	.long	sym64_rel - .

이 .long은 CPU 명령이 아니라 항목당 4바이트 데이터와 필요한 재배치 정보를 내보내는 어셈블러 지시문입니다. 아직 확정되지 않은 심벌 값은 링크 또는 모듈 적재 시의 재배치 처리로 채웁니다. 이 테스트 함수가 실행될 때에는 앞의 load 명령이 채워진 데이터를 읽습니다. 심볼과 이 리터럴 사이의 차이를 32비트 필드에 기록하도록 PREL32 재배치를 만듭니다.

76행 그림 · 어셈블·링크 단계

함수·코드 범위: relative_data32

빌드 도구
처리 전소스의 명령·배치 표기
이 줄의 효과0: .long sym64_rel - .
CPU 레지스터
처리 전해당 없음
이 줄의 효과지시문 자체는 레지스터를 쓰지 않습니다.

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

SYM_FUNC_END(relative_data32)

도구에 이 코드 범위의 끝을 알려 크기와 심볼 정보를 기록합니다. CPU가 이 줄 때문에 자동으로 반환하지는 않습니다.

77행 그림 · 어셈블·링크 단계

함수·코드 범위: relative_data32

빌드 도구
처리 전소스의 명령·배치 표기
이 줄의 효과SYM_FUNC_END(relative_data32)
CPU 레지스터
처리 전해당 없음
이 줄의 효과지시문 자체는 레지스터를 쓰지 않습니다.

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

  • 끝 표기 자체가 RET나 분기를 실행하지는 않습니다.
SYM_FUNC_START(relative_data16)

16비트 PC 상대 데이터 재배치를 검사하는 함수입니다. 작은 폭의 상대 데이터도 로더가 올바르게 기록하는지 확인합니다. 이 선언은 함수 심볼과 정렬을 정하고, ARM64 정의에서는 간접 호출이 도착할 BTI C 명령도 진입부에 넣습니다. 여기서는 전역 심벌로 정의하므로 다른 오브젝트에서도 이 함수 이름을 참조할 수 있습니다. 모듈용 EXPORT_SYMBOL 등록은 별도입니다.

79행 그림 · 어셈블·링크 단계

함수·코드 범위: relative_data16

빌드 도구
처리 전소스의 명령·배치 표기
이 줄의 효과SYM_FUNC_START(relative_data16)
CPU 레지스터
처리 전해당 없음
이 줄의 효과지시문 자체는 레지스터를 쓰지 않습니다.

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

  • 함수 시작 매크로는 심벌·정렬 정보와 BTI 진입 명령 등을 배치할 수 있습니다. 생성된 명령의 실행과 심벌 선언을 구분합니다.
	adr	x1, 0f

16비트 상대 오프셋이 놓인 주소를 x1에 구합니다. 여기서 얻는 것은 레이블의 주소이며, 그 위치의 메모리 내용은 아직 읽지 않습니다.

80행 그림 · 주소·값 구분

함수·코드 범위: relative_data16

x1
이 명령을 실행하기 직전명령 직전 x1의 값
이 명령을 실행한 직후주소(0f)

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

  • 주소 계산이며 그 주소의 메모리는 읽지 않습니다.
	ldrsh	w0, [x1]

16비트 상대값을 부호 확장하여 w0에 읽습니다. 다만 목적지가 W 레지스터이므로 x0 전체를 64비트 부호 확장한 것은 아닙니다. 이 소스의 실제 읽기 폭을 그대로 구분해야 합니다. 이 주소 형식은 기준 레지스터 x1 자체를 갱신하지 않습니다.

81행 그림 · 메모리 읽기

함수·코드 범위: relative_data16

읽는 값x1
메모리[이전 x1] · 2바이트
이 명령을 실행하기 직전M0 (이 주소에 저장된 값)
이 명령을 실행한 직후M0 (이 주소에 저장된 값)
w0
이 명령을 실행하기 직전명령 직전 w0의 값
이 명령을 실행한 직후16비트 M0를 목적 폭으로 부호 확장
x0[63:32]
이 명령을 실행하기 직전명령 직전 x0[63:32]의 값
이 명령을 실행한 직후0

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

  • 주소 계산에 의한 기준 레지스터 갱신은 없습니다. 다만 LDR/LDP의 목적 레지스터가 기준 레지스터와 같으면 읽은 값이 그 레지스터를 덮어씁니다.
	add	x0, x0, x1

리터럴 기준 주소와 읽은 값을 더하여 테스트 심볼의 주소를 계산합니다. 이 ADD 형식은 NZCV 조건 플래그를 바꾸지 않습니다.

82행 그림 · 레지스터 상태

함수·코드 범위: relative_data16

읽는 값x0x1
x0
이 명령을 실행하기 직전명령 직전 x0의 값
이 명령을 실행한 직후명령 직전 x0의 값 + 명령 직전 x1의 값

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

  • 결과는 목적 레지스터 폭에 맞습니다. 이 형식은 NZCV를 바꾸지 않습니다.
	ret

PREL16 주소 계산 결과를 C 쪽 기대값과 비교하도록 반환합니다. 피연산자가 없는 RET는 LR(x30)에 들어 있는 주소에서 실행을 이어갑니다.

83행 그림 · 호출과 실행 위치

함수·코드 범위: relative_data16

읽는 값lr
PC
이 명령을 실행하기 직전명령 직전 PC의 값
이 명령을 실행한 직후명령 직전 lr의 값

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

  • 새 복귀 주소를 LR에 기록하지 않습니다. RET 역시 메모리의 스택 값을 자동으로 꺼내는 명령은 아닙니다.
0:	.short	sym64_rel - ., 0

이 .short은 CPU 명령이 아니라 항목당 2바이트 데이터와 필요한 재배치 정보를 내보내는 어셈블러 지시문입니다. 아직 확정되지 않은 심벌 값은 링크 또는 모듈 적재 시의 재배치 처리로 채웁니다. 이 테스트 함수가 실행될 때에는 앞의 load 명령이 채워진 데이터를 읽습니다. sym64_rel과 현재 위치의 차이를 16비트 데이터로 재배치하고, 뒤에 16비트 0을 추가합니다. 검사 대상은 앞의 상대값 필드입니다.

84행 그림 · 어셈블·링크 단계

함수·코드 범위: relative_data16

빌드 도구
처리 전소스의 명령·배치 표기
이 줄의 효과0: .short sym64_rel - ., 0
CPU 레지스터
처리 전해당 없음
이 줄의 효과지시문 자체는 레지스터를 쓰지 않습니다.

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

SYM_FUNC_END(relative_data16)

도구에 이 코드 범위의 끝을 알려 크기와 심볼 정보를 기록합니다. CPU가 이 줄 때문에 자동으로 반환하지는 않습니다.

85행 그림 · 어셈블·링크 단계

함수·코드 범위: relative_data16

빌드 도구
처리 전소스의 명령·배치 표기
이 줄의 효과SYM_FUNC_END(relative_data16)
CPU 레지스터
처리 전해당 없음
이 줄의 효과지시문 자체는 레지스터를 쓰지 않습니다.

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

  • 끝 표기 자체가 RET나 분기를 실행하지는 않습니다.

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

RET 뒤에 데이터가 있어도 되나요?

정상 실행이 RET에서 다른 곳으로 이동하므로 뒤의 리터럴을 실행하지 않습니다. 앞의 LDR 등이 그 위치를 데이터로 읽습니다.

상대 데이터에 x1을 더하는 이유는 무엇인가요?

리터럴에는 목표 심볼과 리터럴 위치의 차이가 있습니다. 그 위치를 다시 더해 목표 주소를 복구합니다.

테스트가 한 번 통과하면 모든 배치도 보장되나요?

아닙니다. 이 코드의 값, 거리, 정렬 조건에서 해당 재배치 처리를 확인한 결과입니다.

주석을 포함한 전체 원문

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

1/* SPDX-License-Identifier: GPL-2.0-only */2/*3 * Copyright (C) 2017 Linaro, Ltd. <[email protected]>4 */56#include <linux/linkage.h>78SYM_FUNC_START(absolute_data64)9	ldr	x0, 0f10	ret110:	.quad	sym64_abs12SYM_FUNC_END(absolute_data64)1314SYM_FUNC_START(absolute_data32)15	ldr	w0, 0f16	ret170:	.long	sym32_abs18SYM_FUNC_END(absolute_data32)1920SYM_FUNC_START(absolute_data16)21	adr	x0, 0f22	ldrh	w0, [x0]23	ret240:	.short	sym16_abs, 025SYM_FUNC_END(absolute_data16)2627SYM_FUNC_START(signed_movw)28	movz	x0, #:abs_g2_s:sym64_abs29	movk	x0, #:abs_g1_nc:sym64_abs30	movk	x0, #:abs_g0_nc:sym64_abs31	ret32SYM_FUNC_END(signed_movw)3334SYM_FUNC_START(unsigned_movw)35	movz	x0, #:abs_g3:sym64_abs36	movk	x0, #:abs_g2_nc:sym64_abs37	movk	x0, #:abs_g1_nc:sym64_abs38	movk	x0, #:abs_g0_nc:sym64_abs39	ret40SYM_FUNC_END(unsigned_movw)4142	.align	1243	.space	0xff844SYM_FUNC_START(relative_adrp)45	adrp	x0, sym64_rel46	add	x0, x0, #:lo12:sym64_rel47	ret48SYM_FUNC_END(relative_adrp)4950	.align	1251	.space	0xffc52SYM_FUNC_START(relative_adrp_far)53	adrp	x0, memstart_addr54	add	x0, x0, #:lo12:memstart_addr55	ret56SYM_FUNC_END(relative_adrp_far)5758SYM_FUNC_START(relative_adr)59	adr	x0, sym64_rel60	ret61SYM_FUNC_END(relative_adr)6263SYM_FUNC_START(relative_data64)64	adr	x1, 0f65	ldr	x0, [x1]66	add	x0, x0, x167	ret680:	.quad	sym64_rel - .69SYM_FUNC_END(relative_data64)7071SYM_FUNC_START(relative_data32)72	adr	x1, 0f73	ldr	w0, [x1]74	add	x0, x0, x175	ret760:	.long	sym64_rel - .77SYM_FUNC_END(relative_data32)7879SYM_FUNC_START(relative_data16)80	adr	x1, 0f81	ldrsh	w0, [x1]82	add	x0, x0, x183	ret840:	.short	sym64_rel - ., 085SYM_FUNC_END(relative_data16)
맨 위로 ↑