DUJINLABS.COM

Linux v6.18.37 · ARM64

reloc_test_syms.S — 절대·상대 재배치 검사용 코드

여러 재배치 방식으로 동일한 심볼 값을 읽는 작은 함수들입니다. 커널을 옮기는 relocate_kernel.S와 달리, 링커와 모듈 재배치 처리가 기대한 값을 만드는지 검사할 때 사용합니다.

역할과 입력

  • sym64_abs·sym32_abs·sym16_abs: 절대 심볼
  • sym64_rel·memstart_addr: PC 상대 또는 상대 데이터 참조

원본 .S · 빌드 조건: Makefile · 명령·주소 표기 읽는 법

85줄 · SHA-256: 53531eb1477105e42eb8a58cfb865524412c91ea3f53bf70aeae255450a5aa19

구조와 흐름

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

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

리터럴 데이터는 RET 뒤에 있으므로 정상 경로에서 명령으로 실행되지 않습니다. 16비트 버전은 ADR로 데이터 주소를 얻어 LDRH로 읽습니다. .short 뒤의 0은 정렬을 위한 두 번째 16비트 값입니다.

reloc_test_syms.S · L1–L25
1/* SPDX-License-Identifier: GPL-2.0-only */
2/*
3 * Copyright (C) 2017 Linaro, Ltd. <ard.biesheuvel@linaro.org>
4 */
5
6#include <linux/linkage.h>
7
8SYM_FUNC_START(absolute_data64)
9	ldr	x0, 0f
10	ret
110:	.quad	sym64_abs
12SYM_FUNC_END(absolute_data64)
13
14SYM_FUNC_START(absolute_data32)
15	ldr	w0, 0f
16	ret
170:	.long	sym32_abs
18SYM_FUNC_END(absolute_data32)
19
20SYM_FUNC_START(absolute_data16)
21	adr	x0, 0f
22	ldrh	w0, [x0]
23	ret
240:	.short	sym16_abs, 0
25SYM_FUNC_END(absolute_data16)
L6
C의 테스트 배열에서 호출할 작은 어셈블리 함수들의 시작·끝·정렬을 선언하는 linkage 매크로를 가져옵니다. 실제 재배치 검사는 아래 명령과 리터럴 데이터를 적재한 뒤 수행합니다. #include는 전처리 단계에서 헤더 내용을 가져옵니다. CPU가 이 줄에서 함수를 호출하는 동작은 없습니다.
L8
모듈 로더의 R_AARCH64_ABS64 재배치가 올바른지 검사하는 작은 함수입니다. 주소의 메모리를 읽는 테스트가 아니라 절대 심볼값을 상수 데이터로 받아 x0에 반환합니다. 이 선언은 함수 심볼과 정렬을 정하고, ARM64 정의에서는 간접 호출이 도착할 BTI C 명령도 진입부에 넣습니다. 여기서는 전역 심벌로 정의하므로 다른 오브젝트에서도 이 함수 이름을 참조할 수 있습니다. 모듈용 EXPORT_SYMBOL 등록은 별도입니다.
L9
뒤의 64비트 리터럴을 x0에 읽습니다. 모듈 재배치가 끝났다면 그 자리에는 sym64_abs의 실제 테스트 상수 0xffff880000cccccc가 들어 있어야 합니다. 이 LDR 리터럴 형식은 PC 기준으로 레이블 위치를 찾아 그곳의 메모리를 읽습니다. 레이블 주소 자체를 구하는 ADR과 구분합니다.
L10
읽은 절대값을 테스트 호출자에게 반환합니다. reloc_test_core.c는 기대 상수와 비교하여 통과 여부를 출력합니다. 피연산자가 없는 RET는 LR(x30)에 들어 있는 주소에서 실행을 이어갑니다.
L11
이 .quad은 CPU 명령이 아니라 항목당 8바이트 데이터와 필요한 재배치 정보를 내보내는 어셈블러 지시문입니다. 아직 확정되지 않은 심벌 값은 링크 또는 모듈 적재 시의 재배치 처리로 채웁니다. 이 테스트 함수가 실행될 때에는 앞의 load 명령이 채워진 데이터를 읽습니다. 64비트 절대 심볼 재배치가 적용될 데이터 자리를 만듭니다. sym64_abs는 C 파일에서 .set으로 정의한 숫자 심볼이며 일반 변수의 저장 내용을 읽는 것은 아닙니다.
L12
(absolute_data64)의 심볼 타입과 크기를 기록합니다. 실행을 끝내는 RET를 생성하지 않습니다.
L14
R_AARCH64_ABS32 재배치를 검사하는 함수입니다. 32비트 리터럴을 읽은 결과가 C 쪽의 기대값 0xf800cccc와 같은지 확인합니다. 이 선언은 함수 심볼과 정렬을 정하고, ARM64 정의에서는 간접 호출이 도착할 BTI C 명령도 진입부에 넣습니다. 여기서는 전역 심벌로 정의하므로 다른 오브젝트에서도 이 함수 이름을 참조할 수 있습니다. 모듈용 EXPORT_SYMBOL 등록은 별도입니다.
L15
32비트 절대 심볼 리터럴을 w0에 읽습니다. W 레지스터에 쓰면 x0 상위 32비트가 0이 되므로 64비트 C 반환값도 0x00000000f800cccc가 됩니다. 이 LDR 리터럴 형식은 PC 기준으로 레이블 위치를 찾아 그곳의 메모리를 읽습니다. 레이블 주소 자체를 구하는 ADR과 구분합니다.
L16
32비트 절대 심볼을 읽은 결과를 x0로 반환하여 C 쪽 기대값과 비교하게 합니다. 피연산자가 없는 RET는 LR(x30)에 들어 있는 주소에서 실행을 이어갑니다.
L17
이 .long은 CPU 명령이 아니라 항목당 4바이트 데이터와 필요한 재배치 정보를 내보내는 어셈블러 지시문입니다. 아직 확정되지 않은 심벌 값은 링크 또는 모듈 적재 시의 재배치 처리로 채웁니다. 이 테스트 함수가 실행될 때에는 앞의 load 명령이 채워진 데이터를 읽습니다. sym32_abs 값을 32비트 데이터 필드에 채우도록 ABS32 재배치를 만듭니다.
L18
(absolute_data32)의 심볼 타입과 크기를 기록합니다. 실행을 끝내는 RET를 생성하지 않습니다.
L20
R_AARCH64_ABS16 재배치를 검사하는 함수입니다. 16비트 테스트 상수 0xf8cc를 읽어 C 코드의 기대값과 비교합니다. 이 선언은 함수 심볼과 정렬을 정하고, ARM64 정의에서는 간접 호출이 도착할 BTI C 명령도 진입부에 넣습니다. 여기서는 전역 심벌로 정의하므로 다른 오브젝트에서도 이 함수 이름을 참조할 수 있습니다. 모듈용 EXPORT_SYMBOL 등록은 별도입니다.
L21
16비트 리터럴에는 LDRH 리터럴 형식이 없으므로 먼저 뒤의 데이터 주소를 x0에 구합니다. 여기서 얻는 것은 레이블의 주소이며, 그 위치의 메모리 내용은 아직 읽지 않습니다.
L22
그 주소에서 16비트 값을 0으로 확장하여 w0에 읽습니다. 결과 x0는 테스트 상수 0xf8cc가 됩니다.
L23
16비트 절대 심볼값을 테스트 호출자에게 돌려줍니다. 피연산자가 없는 RET는 LR(x30)에 들어 있는 주소에서 실행을 이어갑니다.
L24
이 .short은 CPU 명령이 아니라 항목당 2바이트 데이터와 필요한 재배치 정보를 내보내는 어셈블러 지시문입니다. 아직 확정되지 않은 심벌 값은 링크 또는 모듈 적재 시의 재배치 처리로 채웁니다. 이 테스트 함수가 실행될 때에는 앞의 load 명령이 채워진 데이터를 읽습니다. ABS16 재배치로 채울 sym16_abs와 뒤따르는 16비트 0을 배치합니다. 앞의 halfword가 검사 대상이고 뒤의 0은 데이터 크기를 맞추는 공간입니다.
L25
(absolute_data16)의 심볼 타입과 크기를 기록합니다. 실행을 끝내는 RET를 생성하지 않습니다.

MOVW 재배치 조합

signed_movw는 상위 48비트 내 signed 그룹에서 시작하고, unsigned_movw는 g3부터 네 조각을 구성합니다. MOVK는 해당 16비트 이외의 비트를 보존합니다. :abs_gN: 표기는 어셈블러와 링커가 처리하며 CPU가 문자열을 해석하지 않습니다.

reloc_test_syms.S · L26–L41
26
27SYM_FUNC_START(signed_movw)
28	movz	x0, #:abs_g2_s:sym64_abs
29	movk	x0, #:abs_g1_nc:sym64_abs
30	movk	x0, #:abs_g0_nc:sym64_abs
31	ret
32SYM_FUNC_END(signed_movw)
33
34SYM_FUNC_START(unsigned_movw)
35	movz	x0, #:abs_g3:sym64_abs
36	movk	x0, #:abs_g2_nc:sym64_abs
37	movk	x0, #:abs_g1_nc:sym64_abs
38	movk	x0, #:abs_g0_nc:sym64_abs
39	ret
40SYM_FUNC_END(unsigned_movw)
41
L27
부호 있는 MOVW 재배치를 통해 64비트 절대값을 만드는 테스트입니다. 명령의 즉시값뿐 아니라 부호에 따른 MOVZ/MOVN 선택이 올바르게 적용되는지도 확인합니다. 이 선언은 함수 심볼과 정렬을 정하고, ARM64 정의에서는 간접 호출이 도착할 BTI C 명령도 진입부에 넣습니다. 여기서는 전역 심벌로 정의하므로 다른 오브젝트에서도 이 함수 이름을 참조할 수 있습니다. 모듈용 EXPORT_SYMBOL 등록은 별도입니다.
L28
sym64_abs의 비트 32~47에 해당하는 그룹을 부호 있는 재배치로 넣습니다. 이 테스트 상수는 음수로 해석되는 값이므로 모듈 로더가 MOVN 형식도 선택할 수 있습니다. 소스에 MOVZ라고 적힌 것만 보고 나머지 상위 비트가 항상 0이라고 설명하면 안 됩니다. 이 재배치는 명령어의 즉시값 비트를 채우는 것이며, 실행 중 심벌이 가리키는 메모리 데이터를 읽는 작업은 아닙니다.
L29
비트 16~31 그룹을 MOVK로 덮어씁니다. 이미 만든 나머지 비트는 유지하며 _nc는 이 부분 재배치에서 별도 overflow 검사를 하지 않는다는 뜻입니다.
L30
하위 16비트를 채워 테스트용 64비트 절대값을 완성합니다. MOVK는 선택한 16비트 조각만 덮어쓰고 나머지 비트는 유지합니다.
L31
조립한 값을 C 테스트에 돌려줍니다. 기대값은 absolute_data64와 같은 0xffff880000cccccc입니다. 피연산자가 없는 RET는 LR(x30)에 들어 있는 주소에서 실행을 이어갑니다.
L32
(signed_movw)의 심볼 타입과 크기를 기록합니다. 실행을 끝내는 RET를 생성하지 않습니다.
L34
부호 없는 MOVW 재배치 네 개로 64비트 절대값을 만드는 테스트입니다. 상위 그룹부터 각 16비트 조각을 채웁니다. 이 선언은 함수 심볼과 정렬을 정하고, ARM64 정의에서는 간접 호출이 도착할 BTI C 명령도 진입부에 넣습니다. 여기서는 전역 심벌로 정의하므로 다른 오브젝트에서도 이 함수 이름을 참조할 수 있습니다. 모듈용 EXPORT_SYMBOL 등록은 별도입니다.
L35
sym64_abs의 최상위 비트 48~63을 넣고 다른 비트는 초기화합니다. 뒤의 세 MOVK가 나머지 48비트를 채웁니다. 이 재배치는 명령어의 즉시값 비트를 채우는 것이며, 실행 중 심벌이 가리키는 메모리 데이터를 읽는 작업은 아닙니다.
L36
비트 32~47을 채웁니다. 앞서 넣은 최상위 16비트는 그대로 보존합니다. MOVK는 선택한 16비트 조각만 덮어쓰고 나머지 비트는 유지합니다.
L37
비트 16~31을 채워 절대값을 계속 구성합니다. MOVK는 선택한 16비트 조각만 덮어쓰고 나머지 비트는 유지합니다.
L38
하위 16비트를 채워 64비트 테스트 상수를 완성합니다. MOVK는 선택한 16비트 조각만 덮어쓰고 나머지 비트는 유지합니다.
L39
부호 없는 MOVW 재배치로 구성한 값이 기대 상수와 같은지 C 코드가 확인하도록 반환합니다. 피연산자가 없는 RET는 LR(x30)에 들어 있는 주소에서 실행을 이어갑니다.
L40
(unsigned_movw)의 심볼 타입과 크기를 기록합니다. 실행을 끝내는 RET를 생성하지 않습니다.

페이지 경계 근처의 ADRP

4 KiB 정렬 후 .space로 위치를 옮겨 ADRP와 ADD 조합을 시험합니다. SYM_FUNC_START의 정렬 및 BTI가 실제 위치에 영향을 주므로 .space 값만으로 최종 PC를 단정하지 않습니다. ADRP는 4 KiB 기준 주소를, ADD는 하위 12비트를 더합니다.

reloc_test_syms.S · L42–L62
42	.align	12
43	.space	0xff8
44SYM_FUNC_START(relative_adrp)
45	adrp	x0, sym64_rel
46	add	x0, x0, #:lo12:sym64_rel
47	ret
48SYM_FUNC_END(relative_adrp)
49
50	.align	12
51	.space	0xffc
52SYM_FUNC_START(relative_adrp_far)
53	adrp	x0, memstart_addr
54	add	x0, x0, #:lo12:memstart_addr
55	ret
56SYM_FUNC_END(relative_adrp_far)
57
58SYM_FUNC_START(relative_adr)
59	adr	x0, sym64_rel
60	ret
61SYM_FUNC_END(relative_adr)
62
L42
다음 테스트를 4KiB 경계 기준으로 배치합니다. ADRP는 커널의 PAGE_SIZE 설정과 별개로 4KiB 단위 페이지 주소를 계산하므로 이 경계가 중요합니다. AArch64의 .align 인자는 바이트 수가 아니라 2의 지수입니다. 빌드할 때 필요한 패딩을 넣어 그 경계를 맞춥니다.
L43
0xff8바이트를 채워 다음 테스트를 4KiB 경계 가까이에 놓습니다. 재배치 명령의 위치가 페이지 경계에 가까울 때도 주소 계산이 맞는지 시험하기 위한 배치입니다.
L44
같은 테스트 모듈의 sym64_rel 주소를 ADRP+ADD로 만드는 함수입니다. 결과는 변수의 값이 아니라 변수 자체의 주소여야 합니다. 이 선언은 함수 심볼과 정렬을 정하고, ARM64 정의에서는 간접 호출이 도착할 BTI C 명령도 진입부에 넣습니다. 여기서는 전역 심벌로 정의하므로 다른 오브젝트에서도 이 함수 이름을 참조할 수 있습니다. 모듈용 EXPORT_SYMBOL 등록은 별도입니다.
L45
PC 상대 페이지 재배치로 sym64_rel이 속한 4KiB 페이지 주소를 x0에 만듭니다. 모듈이 어느 주소에 적재됐는지에 따라 명령의 즉시값이 조정됩니다. 여기서 얻는 것은 레이블의 주소이며, 그 위치의 메모리 내용은 아직 읽지 않습니다. ADRP가 만드는 주소는 4KiB 경계까지만입니다. 심벌의 하위 12비트가 0이면 그 자체가 심벌 주소이고, 그렇지 않으면 별도 오프셋 계산이 필요합니다.
L46
심볼 주소의 하위 12비트를 더해 페이지 안의 정확한 바이트 주소를 완성합니다. 이 ADD 형식은 NZCV 조건 플래그를 바꾸지 않습니다.
L47
구한 sym64_rel 주소를 반환합니다. C 테스트는 &sym64_rel과 일치하는지 확인합니다. 피연산자가 없는 RET는 LR(x30)에 들어 있는 주소에서 실행을 이어갑니다.
L48
(relative_adrp)의 심볼 타입과 크기를 기록합니다. 실행을 끝내는 RET를 생성하지 않습니다.
L50
다음 ADRP 테스트의 배치 기준도 4KiB 경계에 맞춥니다. AArch64의 .align 인자는 바이트 수가 아니라 2의 지수입니다. 빌드할 때 필요한 패딩을 넣어 그 경계를 맞춥니다.
L51
0xffc바이트를 채워 다음 테스트를 페이지 경계 가까이에 놓습니다. 명령 위치의 페이지 계산과 먼 심볼 재배치 처리를 확인하기 위한 공간입니다.
L52
모듈 내부 심볼 대신 커널의 memstart_addr 주소를 대상으로 ADRP 재배치를 시험합니다. 모듈과 커널 사이 거리에 따른 처리도 검증 대상입니다. 이 선언은 함수 심볼과 정렬을 정하고, ARM64 정의에서는 간접 호출이 도착할 BTI C 명령도 진입부에 넣습니다. 여기서는 전역 심벌로 정의하므로 다른 오브젝트에서도 이 함수 이름을 참조할 수 있습니다. 모듈용 EXPORT_SYMBOL 등록은 별도입니다.
L53
memstart_addr가 있는 4KiB 페이지 주소를 만듭니다. 모듈 로더는 이 외부 심볼의 최종 주소를 이용해 ADRP 재배치를 적용합니다. 여기서 얻는 것은 레이블의 주소이며, 그 위치의 메모리 내용은 아직 읽지 않습니다. ADRP가 만드는 주소는 4KiB 경계까지만입니다. 심벌의 하위 12비트가 0이면 그 자체가 심벌 주소이고, 그렇지 않으면 별도 오프셋 계산이 필요합니다.
L54
memstart_addr의 페이지 내부 오프셋을 더해 변수의 주소를 완성합니다. memstart_addr에 저장된 물리 메모리 시작값을 읽는 명령은 아닙니다. 이 ADD 형식은 NZCV 조건 플래그를 바꾸지 않습니다.
L55
&memstart_addr와 비교할 주소를 x0로 반환합니다. 피연산자가 없는 RET는 LR(x30)에 들어 있는 주소에서 실행을 이어갑니다.
L56
(relative_adrp_far)의 심볼 타입과 크기를 기록합니다. 실행을 끝내는 RET를 생성하지 않습니다.
L58
ADRP의 페이지 계산 없이 ADR 한 명령으로 PC 상대 주소를 만드는 재배치 테스트입니다. 이 선언은 함수 심볼과 정렬을 정하고, ARM64 정의에서는 간접 호출이 도착할 BTI C 명령도 진입부에 넣습니다. 여기서는 전역 심벌로 정의하므로 다른 오브젝트에서도 이 함수 이름을 참조할 수 있습니다. 모듈용 EXPORT_SYMBOL 등록은 별도입니다.
L59
R_AARCH64_ADR_PREL_LO21 재배치를 통해 sym64_rel의 주소를 x0에 만듭니다. 주소 차이가 ADR이 표현할 수 있는 범위에 들어가는지도 로더가 처리합니다. 여기서 얻는 것은 레이블의 주소이며, 그 위치의 메모리 내용은 아직 읽지 않습니다.
L60
ADR로 계산한 주소를 C 테스트의 &sym64_rel과 비교하도록 반환합니다. 피연산자가 없는 RET는 LR(x30)에 들어 있는 주소에서 실행을 이어갑니다.
L61
(relative_adr)의 심볼 타입과 크기를 기록합니다. 실행을 끝내는 RET를 생성하지 않습니다.

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

리터럴에는 sym64_rel−현재 위치를 저장합니다. 실행할 때 그 리터럴 위치 x1을 다시 더합니다. relative_data32는 W0로 읽어 상위 32비트를 0으로 만들고, relative_data16은 LDRSH W0로 32비트까지 부호 확장한 뒤 X0를 더합니다. 이 함수들은 임의의 모든 음수 오프셋 처리기가 아니라 원본 시험 조건에 따른 코드입니다.

reloc_test_syms.S · L63–L85
63SYM_FUNC_START(relative_data64)
64	adr	x1, 0f
65	ldr	x0, [x1]
66	add	x0, x0, x1
67	ret
680:	.quad	sym64_rel - .
69SYM_FUNC_END(relative_data64)
70
71SYM_FUNC_START(relative_data32)
72	adr	x1, 0f
73	ldr	w0, [x1]
74	add	x0, x0, x1
75	ret
760:	.long	sym64_rel - .
77SYM_FUNC_END(relative_data32)
78
79SYM_FUNC_START(relative_data16)
80	adr	x1, 0f
81	ldrsh	w0, [x1]
82	add	x0, x0, x1
83	ret
840:	.short	sym64_rel - ., 0
85SYM_FUNC_END(relative_data16)
L63
64비트 PC 상대 데이터 재배치를 검사하는 함수입니다. 리터럴에는 주소 자체가 아니라 그 리터럴 위치에서 심볼까지의 차이가 들어갑니다. 이 선언은 함수 심볼과 정렬을 정하고, ARM64 정의에서는 간접 호출이 도착할 BTI C 명령도 진입부에 넣습니다. 여기서는 전역 심벌로 정의하므로 다른 오브젝트에서도 이 함수 이름을 참조할 수 있습니다. 모듈용 EXPORT_SYMBOL 등록은 별도입니다.
L64
상대 오프셋이 저장된 리터럴의 주소를 x1에 구합니다. 이 주소가 나중에 오프셋을 더할 기준점이 됩니다. 여기서 얻는 것은 레이블의 주소이며, 그 위치의 메모리 내용은 아직 읽지 않습니다.
L65
리터럴의 64비트 상대 오프셋을 x0에 읽습니다. 실제로 x1 주소의 메모리 8바이트를 x0에 읽습니다. 이 주소 형식은 기준 레지스터 x1 자체를 갱신하지 않습니다.
L66
리터럴 위치 x1에 오프셋을 더해 sym64_rel의 실제 주소를 복원합니다. 이 ADD 형식은 NZCV 조건 플래그를 바꾸지 않습니다.
L67
PREL64로 복원한 주소가 &sym64_rel과 같은지 검사하도록 반환합니다. 피연산자가 없는 RET는 LR(x30)에 들어 있는 주소에서 실행을 이어갑니다.
L68
이 .quad은 CPU 명령이 아니라 항목당 8바이트 데이터와 필요한 재배치 정보를 내보내는 어셈블러 지시문입니다. 아직 확정되지 않은 심벌 값은 링크 또는 모듈 적재 시의 재배치 처리로 채웁니다. 이 테스트 함수가 실행될 때에는 앞의 load 명령이 채워진 데이터를 읽습니다. sym64_rel 주소에서 현재 데이터 위치를 뺀 64비트 값을 놓도록 PREL64 재배치를 만듭니다. 점(.)은 이 데이터가 놓이는 위치입니다.
L69
(relative_data64)의 심볼 타입과 크기를 기록합니다. 실행을 끝내는 RET를 생성하지 않습니다.
L71
32비트 PC 상대 데이터 재배치를 검사합니다. 상대값을 저장한 위치의 주소에 읽어 온 값을 더해 심볼 주소를 만드는 방식입니다. 이 선언은 함수 심볼과 정렬을 정하고, ARM64 정의에서는 간접 호출이 도착할 BTI C 명령도 진입부에 넣습니다. 여기서는 전역 심벌로 정의하므로 다른 오브젝트에서도 이 함수 이름을 참조할 수 있습니다. 모듈용 EXPORT_SYMBOL 등록은 별도입니다.
L72
32비트 상대 오프셋 리터럴의 주소를 x1에 구합니다. 여기서 얻는 것은 레이블의 주소이며, 그 위치의 메모리 내용은 아직 읽지 않습니다.
L73
32비트 상대값을 w0에 읽습니다. 이 명령은 x0 상위 비트를 0으로 만듭니다. 따라서 모든 부호 있는 32비트 오프셋을 64비트로 부호 확장하는 일반 해법으로 읽어서는 안 되며 이 테스트의 배치와 함께 봐야 합니다. 이 주소 형식은 기준 레지스터 x1 자체를 갱신하지 않습니다.
L74
읽은 상대값을 리터럴의 실제 주소에 더하여 테스트 심볼 주소를 만듭니다. 이 ADD 형식은 NZCV 조건 플래그를 바꾸지 않습니다.
L75
PREL32 결과를 C 코드가 예상한 sym64_rel 주소와 비교하도록 반환합니다. 피연산자가 없는 RET는 LR(x30)에 들어 있는 주소에서 실행을 이어갑니다.
L76
이 .long은 CPU 명령이 아니라 항목당 4바이트 데이터와 필요한 재배치 정보를 내보내는 어셈블러 지시문입니다. 아직 확정되지 않은 심벌 값은 링크 또는 모듈 적재 시의 재배치 처리로 채웁니다. 이 테스트 함수가 실행될 때에는 앞의 load 명령이 채워진 데이터를 읽습니다. 심볼과 이 리터럴 사이의 차이를 32비트 필드에 기록하도록 PREL32 재배치를 만듭니다.
L77
(relative_data32)의 심볼 타입과 크기를 기록합니다. 실행을 끝내는 RET를 생성하지 않습니다.
L79
16비트 PC 상대 데이터 재배치를 검사하는 함수입니다. 작은 폭의 상대 데이터도 로더가 올바르게 기록하는지 확인합니다. 이 선언은 함수 심볼과 정렬을 정하고, ARM64 정의에서는 간접 호출이 도착할 BTI C 명령도 진입부에 넣습니다. 여기서는 전역 심벌로 정의하므로 다른 오브젝트에서도 이 함수 이름을 참조할 수 있습니다. 모듈용 EXPORT_SYMBOL 등록은 별도입니다.
L80
16비트 상대 오프셋이 놓인 주소를 x1에 구합니다. 여기서 얻는 것은 레이블의 주소이며, 그 위치의 메모리 내용은 아직 읽지 않습니다.
L81
16비트 상대값을 부호 확장하여 w0에 읽습니다. 다만 목적지가 W 레지스터이므로 x0 전체를 64비트 부호 확장한 것은 아닙니다. 이 소스의 실제 읽기 폭을 그대로 구분해야 합니다. 이 주소 형식은 기준 레지스터 x1 자체를 갱신하지 않습니다.
L82
리터럴 기준 주소와 읽은 값을 더하여 테스트 심볼의 주소를 계산합니다. 이 ADD 형식은 NZCV 조건 플래그를 바꾸지 않습니다.
L83
PREL16 주소 계산 결과를 C 쪽 기대값과 비교하도록 반환합니다. 피연산자가 없는 RET는 LR(x30)에 들어 있는 주소에서 실행을 이어갑니다.
L84
이 .short은 CPU 명령이 아니라 항목당 2바이트 데이터와 필요한 재배치 정보를 내보내는 어셈블러 지시문입니다. 아직 확정되지 않은 심벌 값은 링크 또는 모듈 적재 시의 재배치 처리로 채웁니다. 이 테스트 함수가 실행될 때에는 앞의 load 명령이 채워진 데이터를 읽습니다. sym64_rel과 현재 위치의 차이를 16비트 데이터로 재배치하고, 뒤에 16비트 0을 추가합니다. 검사 대상은 앞의 상대값 필드입니다.
L85
(relative_data16)의 심볼 타입과 크기를 기록합니다. 실행을 끝내는 RET를 생성하지 않습니다.

매크로 정의와 확장

각 정의는 v6.18.37 원문입니다. 역슬래시 인자는 사용 위치의 값으로 치환되며, 안쪽 매크로와 조건부 블록은 이후 단계에서 다시 처리됩니다.

SYM_FUNC_END

아래 정의의 인자 치환, 조건부 생성과 중첩 매크로를 통해 코드를 만듭니다. SYM 계열의 타입·범위·BTI 차이는 공통 표기 설명에 정리했습니다.

include/linux/linkage.h L248–L249

앞뒤 조건을 포함한 원문

#define SYM_FUNC_END(name)				\
	SYM_END(name, SYM_T_FUNC)

SYM_FUNC_START

아래 정의의 인자 치환, 조건부 생성과 중첩 매크로를 통해 코드를 만듭니다. SYM 계열의 타입·범위·BTI 차이는 공통 표기 설명에 정리했습니다.

arch/arm64/include/asm/linkage.h L18–L20

앞뒤 조건을 포함한 원문

#define SYM_FUNC_START(name)				\
	SYM_START(name, SYM_L_GLOBAL, SYM_A_ALIGN)	\
	bti c ;
include/linux/linkage.h L209–L210

앞뒤 조건을 포함한 원문

#define SYM_FUNC_START(name)				\
	SYM_START(name, SYM_L_GLOBAL, SYM_A_ALIGN)

상수·구조체 오프셋

S_*·THREAD_*·FREGS_* 등의 구조체 오프셋은 빌드한 C 구조체 배치에서 생성됩니다. 숫자를 고정하지 않고 원래 기호를 사용했습니다.

asm-offsets.c의 생성 식

    맨 위로 ↑