역할과 입력
- 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비트 값입니다.
1/* SPDX-License-Identifier: GPL-2.0-only */
2/*
3 * Copyright (C) 2017 Linaro, Ltd. <[email protected]>
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가 문자열을 해석하지 않습니다.
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비트를 더합니다.
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를 더합니다. 이 함수들은 임의의 모든 음수 오프셋 처리기가 아니라 원본 시험 조건에 따른 코드입니다.
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 구조체 배치에서 생성됩니다. 숫자를 고정하지 않고 원래 기호를 사용했습니다.