이 파일은 왜 필요한가요?
프로그램을 링크하거나 다른 주소에 배치하면 명령과 데이터 안에 든 주소 표현도 맞춰야 합니다. 이 파일은 다양한 방식으로 같은 심볼을 읽게 해 재배치 결과를 시험합니다. 실제 새 커널을 복사하는 코드는 아닙니다.
명령·지시문·라벨을 원본 줄 번호에 맞춰 설명합니다. 주석과 빈 줄을 포함한 전체 원문은 아래에 따로 두었습니다. 매크로 정의와 조건부 코드는 모두 차례대로 실행되는 명령 목록이 아닙니다.
기존 코드 분석과 함께 읽기 · 원본 파일 · 설명 원고
먼저 알아둘 개념: 전처리·어셈블·링크·실행, 주소와 주소가 가리키는 내용, 재배치와 상대 주소, 정렬과 경계, 호출 주소와 복귀 주소
처음 읽을 때
주소를 직접 저장한 경우와 “여기서 몇 바이트 떨어져 있다”를 저장한 경우를 비교하세요. 상대값은 기준 주소를 더해야 실제 주소가 됩니다.
더 깊이 살펴볼 때
ADRP의 4 KiB 계산 단위, signed MOVW 재배치, 16·32비트 값의 확장 방식과 최종 링크 배치를 따로 검토해 보세요.
한 줄씩 레지스터와 메모리 상태 보기
각 코드 아래의 ‘행 그림’을 펼치면, 그 줄에서 읽는 값과 실행 전·후의 상태를 나란히 볼 수 있습니다. 여기서 ‘명령 직전’은 지금 보고 있는 명령이 실행되기 바로 전을 뜻합니다. 함수 진입 때나 소스의 바로 윗줄을 가리키는 말은 아닙니다. 앞서 실행한 명령이 값을 바꿨다면 그 결과가 들어 있습니다.
소스로 정해지는 상수, 호출자가 넘기는 값, 실제 실행에서 정해지는 주소를 구분해서 읽어야 합니다. 주소 숫자를 몰라도 무엇을 가리키는지와 어디서 받아 오는지는 설명할 수 있습니다. ‘명령 직전 x0의 값’처럼 일반 표기로 남은 곳은 한 명령의 동작을 나타내며, 특정 호출 경로의 값까지 확인했다는 뜻은 아닙니다.
일반 명령은 그 한 줄의 효과를, 매크로는 여러 명령을 묶은 주요 결과를 표시합니다. 함수 호출은 호출 직후의 PC와 LR까지만 나타냅니다. 메모리 접근은 정상적으로 끝나는 경우를 가정합니다. 생략된 항목까지 모두 보존된다는 뜻은 아닙니다.
화살표 →는 같은 항목의 전후 비교입니다. 메모리 칸에는 주소와 크기를 따로 적었습니다. SP가 줄어들면 낮은 주소 쪽을 사용하며, 화면의 위아래와 메모리 주소 방향은 별개입니다. 전처리·어셈블·링크 지시문은 CPU 실행과 구분합니다.
‘이전·다음 행’은 소스에 적힌 순서입니다. 분기·반복·호출이 있으므로 파일 위에서 아래로 실제 실행된다고 가정하지 않습니다. 값이 여러 줄에 걸쳐 이어지는 모습은 cpu-reset.S의 단계별 예제에서 보실 수 있습니다.
총 69개 줄에 그림을 붙였습니다. 기존 코드와 설명은 그 아래에서 이어집니다.
먼저 그림으로 살펴보기
16·32·64비트 절대 데이터
#include <linux/linkage.h>C의 테스트 배열에서 호출할 작은 어셈블리 함수들의 시작·끝·정렬을 선언하는 linkage 매크로를 가져옵니다. 실제 재배치 검사는 아래 명령과 리터럴 데이터를 적재한 뒤 수행합니다. #include는 전처리 단계에서 헤더 내용을 가져옵니다. CPU가 이 줄에서 함수를 호출하는 동작은 없습니다.
6행 그림 · 전처리 단계
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
SYM_FUNC_START(absolute_data64)모듈 로더의 R_AARCH64_ABS64 재배치가 올바른지 검사하는 작은 함수입니다. 주소의 메모리를 읽는 테스트가 아니라 절대 심볼값을 상수 데이터로 받아 x0에 반환합니다. 이 선언은 함수 심볼과 정렬을 정하고, ARM64 정의에서는 간접 호출이 도착할 BTI C 명령도 진입부에 넣습니다. 여기서는 전역 심벌로 정의하므로 다른 오브젝트에서도 이 함수 이름을 참조할 수 있습니다. 모듈용 EXPORT_SYMBOL 등록은 별도입니다.
8행 그림 · 어셈블·링크 단계
함수·코드 범위: absolute_data64
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 함수 시작 매크로는 심벌·정렬 정보와 BTI 진입 명령 등을 배치할 수 있습니다. 생성된 명령의 실행과 심벌 선언을 구분합니다.
ldr x0, 0f뒤의 64비트 리터럴을 x0에 읽습니다. 모듈 재배치가 끝났다면 그 자리에는 sym64_abs의 실제 테스트 상수 0xffff880000cccccc가 들어 있어야 합니다. 이 LDR 리터럴 형식은 PC 기준으로 레이블 위치를 찾아 그곳의 메모리를 읽습니다. 레이블 주소 자체를 구하는 ADR과 구분합니다.
9행 그림 · 메모리 읽기
함수·코드 범위: absolute_data64
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- =심벌이면 주소 상수를 리터럴 풀에서 읽는 의사 명령입니다. 레이블만 적힌 LDR은 해당 위치의 메모리를 읽습니다.
ret읽은 절대값을 테스트 호출자에게 반환합니다. reloc_test_core.c는 기대 상수와 비교하여 통과 여부를 출력합니다. 피연산자가 없는 RET는 LR(x30)에 들어 있는 주소에서 실행을 이어갑니다.
10행 그림 · 호출과 실행 위치
함수·코드 범위: absolute_data64
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 새 복귀 주소를 LR에 기록하지 않습니다. RET 역시 메모리의 스택 값을 자동으로 꺼내는 명령은 아닙니다.
0: .quad sym64_abs이 .quad은 CPU 명령이 아니라 항목당 8바이트 데이터와 필요한 재배치 정보를 내보내는 어셈블러 지시문입니다. 아직 확정되지 않은 심벌 값은 링크 또는 모듈 적재 시의 재배치 처리로 채웁니다. 이 테스트 함수가 실행될 때에는 앞의 load 명령이 채워진 데이터를 읽습니다. 64비트 절대 심볼 재배치가 적용될 데이터 자리를 만듭니다. sym64_abs는 C 파일에서 .set으로 정의한 숫자 심볼이며 일반 변수의 저장 내용을 읽는 것은 아닙니다.
11행 그림 · 어셈블·링크 단계
함수·코드 범위: absolute_data64
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
SYM_FUNC_END(absolute_data64)도구에 이 코드 범위의 끝을 알려 크기와 심볼 정보를 기록합니다. CPU가 이 줄 때문에 자동으로 반환하지는 않습니다.
12행 그림 · 어셈블·링크 단계
함수·코드 범위: absolute_data64
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 끝 표기 자체가 RET나 분기를 실행하지는 않습니다.
SYM_FUNC_START(absolute_data32)R_AARCH64_ABS32 재배치를 검사하는 함수입니다. 32비트 리터럴을 읽은 결과가 C 쪽의 기대값 0xf800cccc와 같은지 확인합니다. 이 선언은 함수 심볼과 정렬을 정하고, ARM64 정의에서는 간접 호출이 도착할 BTI C 명령도 진입부에 넣습니다. 여기서는 전역 심벌로 정의하므로 다른 오브젝트에서도 이 함수 이름을 참조할 수 있습니다. 모듈용 EXPORT_SYMBOL 등록은 별도입니다.
14행 그림 · 어셈블·링크 단계
함수·코드 범위: absolute_data32
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 함수 시작 매크로는 심벌·정렬 정보와 BTI 진입 명령 등을 배치할 수 있습니다. 생성된 명령의 실행과 심벌 선언을 구분합니다.
ldr w0, 0f32비트 절대 심볼 리터럴을 w0에 읽습니다. W 레지스터에 쓰면 x0 상위 32비트가 0이 되므로 64비트 C 반환값도 0x00000000f800cccc가 됩니다. 이 LDR 리터럴 형식은 PC 기준으로 레이블 위치를 찾아 그곳의 메모리를 읽습니다. 레이블 주소 자체를 구하는 ADR과 구분합니다.
15행 그림 · 메모리 읽기
함수·코드 범위: absolute_data32
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- =심벌이면 주소 상수를 리터럴 풀에서 읽는 의사 명령입니다. 레이블만 적힌 LDR은 해당 위치의 메모리를 읽습니다.
ret32비트 절대 심볼을 읽은 결과를 x0로 반환하여 C 쪽 기대값과 비교하게 합니다. 피연산자가 없는 RET는 LR(x30)에 들어 있는 주소에서 실행을 이어갑니다.
16행 그림 · 호출과 실행 위치
함수·코드 범위: absolute_data32
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 새 복귀 주소를 LR에 기록하지 않습니다. RET 역시 메모리의 스택 값을 자동으로 꺼내는 명령은 아닙니다.
0: .long sym32_abs이 .long은 CPU 명령이 아니라 항목당 4바이트 데이터와 필요한 재배치 정보를 내보내는 어셈블러 지시문입니다. 아직 확정되지 않은 심벌 값은 링크 또는 모듈 적재 시의 재배치 처리로 채웁니다. 이 테스트 함수가 실행될 때에는 앞의 load 명령이 채워진 데이터를 읽습니다. sym32_abs 값을 32비트 데이터 필드에 채우도록 ABS32 재배치를 만듭니다.
17행 그림 · 어셈블·링크 단계
함수·코드 범위: absolute_data32
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
SYM_FUNC_END(absolute_data32)도구에 이 코드 범위의 끝을 알려 크기와 심볼 정보를 기록합니다. CPU가 이 줄 때문에 자동으로 반환하지는 않습니다.
18행 그림 · 어셈블·링크 단계
함수·코드 범위: absolute_data32
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 끝 표기 자체가 RET나 분기를 실행하지는 않습니다.
SYM_FUNC_START(absolute_data16)R_AARCH64_ABS16 재배치를 검사하는 함수입니다. 16비트 테스트 상수 0xf8cc를 읽어 C 코드의 기대값과 비교합니다. 이 선언은 함수 심볼과 정렬을 정하고, ARM64 정의에서는 간접 호출이 도착할 BTI C 명령도 진입부에 넣습니다. 여기서는 전역 심벌로 정의하므로 다른 오브젝트에서도 이 함수 이름을 참조할 수 있습니다. 모듈용 EXPORT_SYMBOL 등록은 별도입니다.
20행 그림 · 어셈블·링크 단계
함수·코드 범위: absolute_data16
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 함수 시작 매크로는 심벌·정렬 정보와 BTI 진입 명령 등을 배치할 수 있습니다. 생성된 명령의 실행과 심벌 선언을 구분합니다.
adr x0, 0f16비트 리터럴에는 LDRH 리터럴 형식이 없으므로 먼저 뒤의 데이터 주소를 x0에 구합니다. 여기서 얻는 것은 레이블의 주소이며, 그 위치의 메모리 내용은 아직 읽지 않습니다.
21행 그림 · 주소·값 구분
함수·코드 범위: absolute_data16
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 주소 계산이며 그 주소의 메모리는 읽지 않습니다.
ldrh w0, [x0]그 주소에서 16비트 값을 0으로 확장하여 w0에 읽습니다. 결과 x0는 테스트 상수 0xf8cc가 됩니다.
22행 그림 · 메모리 읽기
함수·코드 범위: absolute_data16
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 주소 계산에 의한 기준 레지스터 갱신은 없습니다. 다만 LDR/LDP의 목적 레지스터가 기준 레지스터와 같으면 읽은 값이 그 레지스터를 덮어씁니다.
ret16비트 절대 심볼값을 테스트 호출자에게 돌려줍니다. 피연산자가 없는 RET는 LR(x30)에 들어 있는 주소에서 실행을 이어갑니다.
23행 그림 · 호출과 실행 위치
함수·코드 범위: absolute_data16
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 새 복귀 주소를 LR에 기록하지 않습니다. RET 역시 메모리의 스택 값을 자동으로 꺼내는 명령은 아닙니다.
0: .short sym16_abs, 0이 .short은 CPU 명령이 아니라 항목당 2바이트 데이터와 필요한 재배치 정보를 내보내는 어셈블러 지시문입니다. 아직 확정되지 않은 심벌 값은 링크 또는 모듈 적재 시의 재배치 처리로 채웁니다. 이 테스트 함수가 실행될 때에는 앞의 load 명령이 채워진 데이터를 읽습니다. ABS16 재배치로 채울 sym16_abs와 뒤따르는 16비트 0을 배치합니다. 앞의 halfword가 검사 대상이고 뒤의 0은 데이터 크기를 맞추는 공간입니다.
24행 그림 · 어셈블·링크 단계
함수·코드 범위: absolute_data16
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
SYM_FUNC_END(absolute_data16)도구에 이 코드 범위의 끝을 알려 크기와 심볼 정보를 기록합니다. CPU가 이 줄 때문에 자동으로 반환하지는 않습니다.
25행 그림 · 어셈블·링크 단계
함수·코드 범위: absolute_data16
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 끝 표기 자체가 RET나 분기를 실행하지는 않습니다.
MOVW 재배치 조합
SYM_FUNC_START(signed_movw)부호 있는 MOVW 재배치를 통해 64비트 절대값을 만드는 테스트입니다. 명령의 즉시값뿐 아니라 부호에 따른 MOVZ/MOVN 선택이 올바르게 적용되는지도 확인합니다. 이 선언은 함수 심볼과 정렬을 정하고, ARM64 정의에서는 간접 호출이 도착할 BTI C 명령도 진입부에 넣습니다. 여기서는 전역 심벌로 정의하므로 다른 오브젝트에서도 이 함수 이름을 참조할 수 있습니다. 모듈용 EXPORT_SYMBOL 등록은 별도입니다.
27행 그림 · 어셈블·링크 단계
함수·코드 범위: signed_movw
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 함수 시작 매크로는 심벌·정렬 정보와 BTI 진입 명령 등을 배치할 수 있습니다. 생성된 명령의 실행과 심벌 선언을 구분합니다.
movz x0, #:abs_g2_s:sym64_abssym64_abs의 비트 32~47에 해당하는 그룹을 부호 있는 재배치로 넣습니다. 이 테스트 상수는 음수로 해석되는 값이므로 모듈 로더가 MOVN 형식도 선택할 수 있습니다. 소스에 MOVZ라고 적힌 것만 보고 나머지 상위 비트가 항상 0이라고 설명하면 안 됩니다. 이 재배치는 명령어의 즉시값 비트를 채우는 것이며, 실행 중 심벌이 가리키는 메모리 데이터를 읽는 작업은 아닙니다.
:abs_g2_s:는 signed MOVW 재배치입니다. 음수 값 구성에는 링커가 MOVN 형태를 선택할 수 있어 원문 MOVZ만으로 상위 비트를 단정하지 않습니다.
28행 그림 · 상수의 비트 조각 구성
함수·코드 범위: signed_movw
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 부호 있는 재배치가 실제 명령의 MOVZ/MOVN 선택에도 영향을 주므로 남은 비트를 항상 0이라고 표시하지 않습니다.
movk x0, #:abs_g1_nc:sym64_abs비트 16~31 그룹을 MOVK로 덮어씁니다. 이미 만든 나머지 비트는 유지하며 _nc는 이 부분 재배치에서 별도 overflow 검사를 하지 않는다는 뜻입니다.
29행 그림 · 상수의 비트 조각 구성
함수·코드 범위: signed_movw
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 선택한 16비트 이외의 비트는 그대로 남습니다.
movk x0, #:abs_g0_nc:sym64_abs하위 16비트를 채워 테스트용 64비트 절대값을 완성합니다. MOVK는 선택한 16비트 조각만 덮어쓰고 나머지 비트는 유지합니다.
30행 그림 · 상수의 비트 조각 구성
함수·코드 범위: signed_movw
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 선택한 16비트 이외의 비트는 그대로 남습니다.
ret조립한 값을 C 테스트에 돌려줍니다. 기대값은 absolute_data64와 같은 0xffff880000cccccc입니다. 피연산자가 없는 RET는 LR(x30)에 들어 있는 주소에서 실행을 이어갑니다.
31행 그림 · 호출과 실행 위치
함수·코드 범위: signed_movw
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 새 복귀 주소를 LR에 기록하지 않습니다. RET 역시 메모리의 스택 값을 자동으로 꺼내는 명령은 아닙니다.
SYM_FUNC_END(signed_movw)도구에 이 코드 범위의 끝을 알려 크기와 심볼 정보를 기록합니다. CPU가 이 줄 때문에 자동으로 반환하지는 않습니다.
32행 그림 · 어셈블·링크 단계
함수·코드 범위: signed_movw
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 끝 표기 자체가 RET나 분기를 실행하지는 않습니다.
SYM_FUNC_START(unsigned_movw)부호 없는 MOVW 재배치 네 개로 64비트 절대값을 만드는 테스트입니다. 상위 그룹부터 각 16비트 조각을 채웁니다. 이 선언은 함수 심볼과 정렬을 정하고, ARM64 정의에서는 간접 호출이 도착할 BTI C 명령도 진입부에 넣습니다. 여기서는 전역 심벌로 정의하므로 다른 오브젝트에서도 이 함수 이름을 참조할 수 있습니다. 모듈용 EXPORT_SYMBOL 등록은 별도입니다.
34행 그림 · 어셈블·링크 단계
함수·코드 범위: unsigned_movw
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 함수 시작 매크로는 심벌·정렬 정보와 BTI 진입 명령 등을 배치할 수 있습니다. 생성된 명령의 실행과 심벌 선언을 구분합니다.
movz x0, #:abs_g3:sym64_abssym64_abs의 최상위 비트 48~63을 넣고 다른 비트는 초기화합니다. 뒤의 세 MOVK가 나머지 48비트를 채웁니다. 이 재배치는 명령어의 즉시값 비트를 채우는 것이며, 실행 중 심벌이 가리키는 메모리 데이터를 읽는 작업은 아닙니다.
35행 그림 · 상수의 비트 조각 구성
함수·코드 범위: unsigned_movw
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
movk x0, #:abs_g2_nc:sym64_abs비트 32~47을 채웁니다. 앞서 넣은 최상위 16비트는 그대로 보존합니다. MOVK는 선택한 16비트 조각만 덮어쓰고 나머지 비트는 유지합니다.
36행 그림 · 상수의 비트 조각 구성
함수·코드 범위: unsigned_movw
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 선택한 16비트 이외의 비트는 그대로 남습니다.
movk x0, #:abs_g1_nc:sym64_abs비트 16~31을 채워 절대값을 계속 구성합니다. MOVK는 선택한 16비트 조각만 덮어쓰고 나머지 비트는 유지합니다.
37행 그림 · 상수의 비트 조각 구성
함수·코드 범위: unsigned_movw
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 선택한 16비트 이외의 비트는 그대로 남습니다.
movk x0, #:abs_g0_nc:sym64_abs하위 16비트를 채워 64비트 테스트 상수를 완성합니다. MOVK는 선택한 16비트 조각만 덮어쓰고 나머지 비트는 유지합니다.
38행 그림 · 상수의 비트 조각 구성
함수·코드 범위: unsigned_movw
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 선택한 16비트 이외의 비트는 그대로 남습니다.
ret부호 없는 MOVW 재배치로 구성한 값이 기대 상수와 같은지 C 코드가 확인하도록 반환합니다. 피연산자가 없는 RET는 LR(x30)에 들어 있는 주소에서 실행을 이어갑니다.
39행 그림 · 호출과 실행 위치
함수·코드 범위: unsigned_movw
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 새 복귀 주소를 LR에 기록하지 않습니다. RET 역시 메모리의 스택 값을 자동으로 꺼내는 명령은 아닙니다.
SYM_FUNC_END(unsigned_movw)도구에 이 코드 범위의 끝을 알려 크기와 심볼 정보를 기록합니다. CPU가 이 줄 때문에 자동으로 반환하지는 않습니다.
40행 그림 · 어셈블·링크 단계
함수·코드 범위: unsigned_movw
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 끝 표기 자체가 RET나 분기를 실행하지는 않습니다.
페이지 경계 근처의 ADRP
.align 12다음 테스트를 4KiB 경계 기준으로 배치합니다. ADRP는 커널의 PAGE_SIZE 설정과 별개로 4KiB 단위 페이지 주소를 계산하므로 이 경계가 중요합니다. AArch64의 .align 인자는 바이트 수가 아니라 2의 지수입니다. 빌드할 때 필요한 패딩을 넣어 그 경계를 맞춥니다.
42행 그림 · 어셈블·링크 단계
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.space 0xff80xff8바이트를 채워 다음 테스트를 4KiB 경계 가까이에 놓습니다. 재배치 명령의 위치가 페이지 경계에 가까울 때도 주소 계산이 맞는지 시험하기 위한 배치입니다.
43행 그림 · 어셈블·링크 단계
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
SYM_FUNC_START(relative_adrp)같은 테스트 모듈의 sym64_rel 주소를 ADRP+ADD로 만드는 함수입니다. 결과는 변수의 값이 아니라 변수 자체의 주소여야 합니다. 이 선언은 함수 심볼과 정렬을 정하고, ARM64 정의에서는 간접 호출이 도착할 BTI C 명령도 진입부에 넣습니다. 여기서는 전역 심벌로 정의하므로 다른 오브젝트에서도 이 함수 이름을 참조할 수 있습니다. 모듈용 EXPORT_SYMBOL 등록은 별도입니다.
44행 그림 · 어셈블·링크 단계
함수·코드 범위: relative_adrp
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 함수 시작 매크로는 심벌·정렬 정보와 BTI 진입 명령 등을 배치할 수 있습니다. 생성된 명령의 실행과 심벌 선언을 구분합니다.
adrp x0, sym64_relPC 상대 페이지 재배치로 sym64_rel이 속한 4KiB 페이지 주소를 x0에 만듭니다. 모듈이 어느 주소에 적재됐는지에 따라 명령의 즉시값이 조정됩니다. 여기서 얻는 것은 레이블의 주소이며, 그 위치의 메모리 내용은 아직 읽지 않습니다. ADRP가 만드는 주소는 4KiB 경계까지만입니다. 심벌의 하위 12비트가 0이면 그 자체가 심벌 주소이고, 그렇지 않으면 별도 오프셋 계산이 필요합니다.
45행 그림 · 주소·값 구분
함수·코드 범위: relative_adrp
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- ADRP의 페이지 단위는 4KiB입니다.
add x0, x0, #:lo12:sym64_rel심볼 주소의 하위 12비트를 더해 페이지 안의 정확한 바이트 주소를 완성합니다. 이 ADD 형식은 NZCV 조건 플래그를 바꾸지 않습니다.
46행 그림 · 레지스터 상태
함수·코드 범위: relative_adrp
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 결과는 목적 레지스터 폭에 맞습니다. 이 형식은 NZCV를 바꾸지 않습니다.
ret구한 sym64_rel 주소를 반환합니다. C 테스트는 &sym64_rel과 일치하는지 확인합니다. 피연산자가 없는 RET는 LR(x30)에 들어 있는 주소에서 실행을 이어갑니다.
47행 그림 · 호출과 실행 위치
함수·코드 범위: relative_adrp
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 새 복귀 주소를 LR에 기록하지 않습니다. RET 역시 메모리의 스택 값을 자동으로 꺼내는 명령은 아닙니다.
SYM_FUNC_END(relative_adrp)도구에 이 코드 범위의 끝을 알려 크기와 심볼 정보를 기록합니다. CPU가 이 줄 때문에 자동으로 반환하지는 않습니다.
48행 그림 · 어셈블·링크 단계
함수·코드 범위: relative_adrp
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 끝 표기 자체가 RET나 분기를 실행하지는 않습니다.
.align 12다음 ADRP 테스트의 배치 기준도 4KiB 경계에 맞춥니다. AArch64의 .align 인자는 바이트 수가 아니라 2의 지수입니다. 빌드할 때 필요한 패딩을 넣어 그 경계를 맞춥니다.
50행 그림 · 어셈블·링크 단계
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
.space 0xffc0xffc바이트를 채워 다음 테스트를 페이지 경계 가까이에 놓습니다. 명령 위치의 페이지 계산과 먼 심볼 재배치 처리를 확인하기 위한 공간입니다.
51행 그림 · 어셈블·링크 단계
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
SYM_FUNC_START(relative_adrp_far)모듈 내부 심볼 대신 커널의 memstart_addr 주소를 대상으로 ADRP 재배치를 시험합니다. 모듈과 커널 사이 거리에 따른 처리도 검증 대상입니다. 이 선언은 함수 심볼과 정렬을 정하고, ARM64 정의에서는 간접 호출이 도착할 BTI C 명령도 진입부에 넣습니다. 여기서는 전역 심벌로 정의하므로 다른 오브젝트에서도 이 함수 이름을 참조할 수 있습니다. 모듈용 EXPORT_SYMBOL 등록은 별도입니다.
52행 그림 · 어셈블·링크 단계
함수·코드 범위: relative_adrp_far
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 함수 시작 매크로는 심벌·정렬 정보와 BTI 진입 명령 등을 배치할 수 있습니다. 생성된 명령의 실행과 심벌 선언을 구분합니다.
adrp x0, memstart_addrmemstart_addr가 있는 4KiB 페이지 주소를 만듭니다. 모듈 로더는 이 외부 심볼의 최종 주소를 이용해 ADRP 재배치를 적용합니다. 여기서 얻는 것은 레이블의 주소이며, 그 위치의 메모리 내용은 아직 읽지 않습니다. ADRP가 만드는 주소는 4KiB 경계까지만입니다. 심벌의 하위 12비트가 0이면 그 자체가 심벌 주소이고, 그렇지 않으면 별도 오프셋 계산이 필요합니다.
53행 그림 · 주소·값 구분
함수·코드 범위: relative_adrp_far
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- ADRP의 페이지 단위는 4KiB입니다.
add x0, x0, #:lo12:memstart_addrmemstart_addr의 페이지 내부 오프셋을 더해 변수의 주소를 완성합니다. memstart_addr에 저장된 물리 메모리 시작값을 읽는 명령은 아닙니다. 이 ADD 형식은 NZCV 조건 플래그를 바꾸지 않습니다.
54행 그림 · 레지스터 상태
함수·코드 범위: relative_adrp_far
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 결과는 목적 레지스터 폭에 맞습니다. 이 형식은 NZCV를 바꾸지 않습니다.
ret&memstart_addr와 비교할 주소를 x0로 반환합니다. 피연산자가 없는 RET는 LR(x30)에 들어 있는 주소에서 실행을 이어갑니다.
55행 그림 · 호출과 실행 위치
함수·코드 범위: relative_adrp_far
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 새 복귀 주소를 LR에 기록하지 않습니다. RET 역시 메모리의 스택 값을 자동으로 꺼내는 명령은 아닙니다.
SYM_FUNC_END(relative_adrp_far)도구에 이 코드 범위의 끝을 알려 크기와 심볼 정보를 기록합니다. CPU가 이 줄 때문에 자동으로 반환하지는 않습니다.
56행 그림 · 어셈블·링크 단계
함수·코드 범위: relative_adrp_far
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 끝 표기 자체가 RET나 분기를 실행하지는 않습니다.
SYM_FUNC_START(relative_adr)ADRP의 페이지 계산 없이 ADR 한 명령으로 PC 상대 주소를 만드는 재배치 테스트입니다. 이 선언은 함수 심볼과 정렬을 정하고, ARM64 정의에서는 간접 호출이 도착할 BTI C 명령도 진입부에 넣습니다. 여기서는 전역 심벌로 정의하므로 다른 오브젝트에서도 이 함수 이름을 참조할 수 있습니다. 모듈용 EXPORT_SYMBOL 등록은 별도입니다.
58행 그림 · 어셈블·링크 단계
함수·코드 범위: relative_adr
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 함수 시작 매크로는 심벌·정렬 정보와 BTI 진입 명령 등을 배치할 수 있습니다. 생성된 명령의 실행과 심벌 선언을 구분합니다.
adr x0, sym64_relR_AARCH64_ADR_PREL_LO21 재배치를 통해 sym64_rel의 주소를 x0에 만듭니다. 주소 차이가 ADR이 표현할 수 있는 범위에 들어가는지도 로더가 처리합니다. 여기서 얻는 것은 레이블의 주소이며, 그 위치의 메모리 내용은 아직 읽지 않습니다.
59행 그림 · 주소·값 구분
함수·코드 범위: relative_adr
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 주소 계산이며 그 주소의 메모리는 읽지 않습니다.
retADR로 계산한 주소를 C 테스트의 &sym64_rel과 비교하도록 반환합니다. 피연산자가 없는 RET는 LR(x30)에 들어 있는 주소에서 실행을 이어갑니다.
60행 그림 · 호출과 실행 위치
함수·코드 범위: relative_adr
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 새 복귀 주소를 LR에 기록하지 않습니다. RET 역시 메모리의 스택 값을 자동으로 꺼내는 명령은 아닙니다.
SYM_FUNC_END(relative_adr)도구에 이 코드 범위의 끝을 알려 크기와 심볼 정보를 기록합니다. CPU가 이 줄 때문에 자동으로 반환하지는 않습니다.
61행 그림 · 어셈블·링크 단계
함수·코드 범위: relative_adr
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 끝 표기 자체가 RET나 분기를 실행하지는 않습니다.
상대 데이터를 절대 주소로 복원
SYM_FUNC_START(relative_data64)64비트 PC 상대 데이터 재배치를 검사하는 함수입니다. 리터럴에는 주소 자체가 아니라 그 리터럴 위치에서 심볼까지의 차이가 들어갑니다. 이 선언은 함수 심볼과 정렬을 정하고, ARM64 정의에서는 간접 호출이 도착할 BTI C 명령도 진입부에 넣습니다. 여기서는 전역 심벌로 정의하므로 다른 오브젝트에서도 이 함수 이름을 참조할 수 있습니다. 모듈용 EXPORT_SYMBOL 등록은 별도입니다.
63행 그림 · 어셈블·링크 단계
함수·코드 범위: relative_data64
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 함수 시작 매크로는 심벌·정렬 정보와 BTI 진입 명령 등을 배치할 수 있습니다. 생성된 명령의 실행과 심벌 선언을 구분합니다.
adr x1, 0f상대 오프셋이 저장된 리터럴의 주소를 x1에 구합니다. 이 주소가 나중에 오프셋을 더할 기준점이 됩니다. 여기서 얻는 것은 레이블의 주소이며, 그 위치의 메모리 내용은 아직 읽지 않습니다.
64행 그림 · 주소·값 구분
함수·코드 범위: relative_data64
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 주소 계산이며 그 주소의 메모리는 읽지 않습니다.
ldr x0, [x1]리터럴의 64비트 상대 오프셋을 x0에 읽습니다. 실제로 x1 주소의 메모리 8바이트를 x0에 읽습니다. 이 주소 형식은 기준 레지스터 x1 자체를 갱신하지 않습니다.
65행 그림 · 메모리 읽기
함수·코드 범위: relative_data64
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 주소 계산에 의한 기준 레지스터 갱신은 없습니다. 다만 LDR/LDP의 목적 레지스터가 기준 레지스터와 같으면 읽은 값이 그 레지스터를 덮어씁니다.
add x0, x0, x1리터럴 위치 x1에 오프셋을 더해 sym64_rel의 실제 주소를 복원합니다. 이 ADD 형식은 NZCV 조건 플래그를 바꾸지 않습니다.
66행 그림 · 레지스터 상태
함수·코드 범위: relative_data64
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 결과는 목적 레지스터 폭에 맞습니다. 이 형식은 NZCV를 바꾸지 않습니다.
retPREL64로 복원한 주소가 &sym64_rel과 같은지 검사하도록 반환합니다. 피연산자가 없는 RET는 LR(x30)에 들어 있는 주소에서 실행을 이어갑니다.
67행 그림 · 호출과 실행 위치
함수·코드 범위: relative_data64
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 새 복귀 주소를 LR에 기록하지 않습니다. RET 역시 메모리의 스택 값을 자동으로 꺼내는 명령은 아닙니다.
0: .quad sym64_rel - .이 .quad은 CPU 명령이 아니라 항목당 8바이트 데이터와 필요한 재배치 정보를 내보내는 어셈블러 지시문입니다. 아직 확정되지 않은 심벌 값은 링크 또는 모듈 적재 시의 재배치 처리로 채웁니다. 이 테스트 함수가 실행될 때에는 앞의 load 명령이 채워진 데이터를 읽습니다. sym64_rel 주소에서 현재 데이터 위치를 뺀 64비트 값을 놓도록 PREL64 재배치를 만듭니다. 점(.)은 이 데이터가 놓이는 위치입니다.
이 .quad가 놓인 주소를 기준으로 한 차이를 저장하므로 실행 시 같은 위치 x1을 더하면 sym64_rel 주소가 됩니다.
68행 그림 · 어셈블·링크 단계
함수·코드 범위: relative_data64
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
SYM_FUNC_END(relative_data64)도구에 이 코드 범위의 끝을 알려 크기와 심볼 정보를 기록합니다. CPU가 이 줄 때문에 자동으로 반환하지는 않습니다.
69행 그림 · 어셈블·링크 단계
함수·코드 범위: relative_data64
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 끝 표기 자체가 RET나 분기를 실행하지는 않습니다.
SYM_FUNC_START(relative_data32)32비트 PC 상대 데이터 재배치를 검사합니다. 상대값을 저장한 위치의 주소에 읽어 온 값을 더해 심볼 주소를 만드는 방식입니다. 이 선언은 함수 심볼과 정렬을 정하고, ARM64 정의에서는 간접 호출이 도착할 BTI C 명령도 진입부에 넣습니다. 여기서는 전역 심벌로 정의하므로 다른 오브젝트에서도 이 함수 이름을 참조할 수 있습니다. 모듈용 EXPORT_SYMBOL 등록은 별도입니다.
71행 그림 · 어셈블·링크 단계
함수·코드 범위: relative_data32
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 함수 시작 매크로는 심벌·정렬 정보와 BTI 진입 명령 등을 배치할 수 있습니다. 생성된 명령의 실행과 심벌 선언을 구분합니다.
adr x1, 0f32비트 상대 오프셋 리터럴의 주소를 x1에 구합니다. 여기서 얻는 것은 레이블의 주소이며, 그 위치의 메모리 내용은 아직 읽지 않습니다.
72행 그림 · 주소·값 구분
함수·코드 범위: relative_data32
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 주소 계산이며 그 주소의 메모리는 읽지 않습니다.
ldr w0, [x1]32비트 상대값을 w0에 읽습니다. 이 명령은 x0 상위 비트를 0으로 만듭니다. 따라서 모든 부호 있는 32비트 오프셋을 64비트로 부호 확장하는 일반 해법으로 읽어서는 안 되며 이 테스트의 배치와 함께 봐야 합니다. 이 주소 형식은 기준 레지스터 x1 자체를 갱신하지 않습니다.
73행 그림 · 메모리 읽기
함수·코드 범위: relative_data32
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 주소 계산에 의한 기준 레지스터 갱신은 없습니다. 다만 LDR/LDP의 목적 레지스터가 기준 레지스터와 같으면 읽은 값이 그 레지스터를 덮어씁니다.
add x0, x0, x1읽은 상대값을 리터럴의 실제 주소에 더하여 테스트 심볼 주소를 만듭니다. 이 ADD 형식은 NZCV 조건 플래그를 바꾸지 않습니다.
74행 그림 · 레지스터 상태
함수·코드 범위: relative_data32
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 결과는 목적 레지스터 폭에 맞습니다. 이 형식은 NZCV를 바꾸지 않습니다.
retPREL32 결과를 C 코드가 예상한 sym64_rel 주소와 비교하도록 반환합니다. 피연산자가 없는 RET는 LR(x30)에 들어 있는 주소에서 실행을 이어갑니다.
75행 그림 · 호출과 실행 위치
함수·코드 범위: relative_data32
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 새 복귀 주소를 LR에 기록하지 않습니다. RET 역시 메모리의 스택 값을 자동으로 꺼내는 명령은 아닙니다.
0: .long sym64_rel - .이 .long은 CPU 명령이 아니라 항목당 4바이트 데이터와 필요한 재배치 정보를 내보내는 어셈블러 지시문입니다. 아직 확정되지 않은 심벌 값은 링크 또는 모듈 적재 시의 재배치 처리로 채웁니다. 이 테스트 함수가 실행될 때에는 앞의 load 명령이 채워진 데이터를 읽습니다. 심볼과 이 리터럴 사이의 차이를 32비트 필드에 기록하도록 PREL32 재배치를 만듭니다.
76행 그림 · 어셈블·링크 단계
함수·코드 범위: relative_data32
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
SYM_FUNC_END(relative_data32)도구에 이 코드 범위의 끝을 알려 크기와 심볼 정보를 기록합니다. CPU가 이 줄 때문에 자동으로 반환하지는 않습니다.
77행 그림 · 어셈블·링크 단계
함수·코드 범위: relative_data32
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 끝 표기 자체가 RET나 분기를 실행하지는 않습니다.
SYM_FUNC_START(relative_data16)16비트 PC 상대 데이터 재배치를 검사하는 함수입니다. 작은 폭의 상대 데이터도 로더가 올바르게 기록하는지 확인합니다. 이 선언은 함수 심볼과 정렬을 정하고, ARM64 정의에서는 간접 호출이 도착할 BTI C 명령도 진입부에 넣습니다. 여기서는 전역 심벌로 정의하므로 다른 오브젝트에서도 이 함수 이름을 참조할 수 있습니다. 모듈용 EXPORT_SYMBOL 등록은 별도입니다.
79행 그림 · 어셈블·링크 단계
함수·코드 범위: relative_data16
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 함수 시작 매크로는 심벌·정렬 정보와 BTI 진입 명령 등을 배치할 수 있습니다. 생성된 명령의 실행과 심벌 선언을 구분합니다.
adr x1, 0f16비트 상대 오프셋이 놓인 주소를 x1에 구합니다. 여기서 얻는 것은 레이블의 주소이며, 그 위치의 메모리 내용은 아직 읽지 않습니다.
80행 그림 · 주소·값 구분
함수·코드 범위: relative_data16
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 주소 계산이며 그 주소의 메모리는 읽지 않습니다.
ldrsh w0, [x1]16비트 상대값을 부호 확장하여 w0에 읽습니다. 다만 목적지가 W 레지스터이므로 x0 전체를 64비트 부호 확장한 것은 아닙니다. 이 소스의 실제 읽기 폭을 그대로 구분해야 합니다. 이 주소 형식은 기준 레지스터 x1 자체를 갱신하지 않습니다.
81행 그림 · 메모리 읽기
함수·코드 범위: relative_data16
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 주소 계산에 의한 기준 레지스터 갱신은 없습니다. 다만 LDR/LDP의 목적 레지스터가 기준 레지스터와 같으면 읽은 값이 그 레지스터를 덮어씁니다.
add x0, x0, x1리터럴 기준 주소와 읽은 값을 더하여 테스트 심볼의 주소를 계산합니다. 이 ADD 형식은 NZCV 조건 플래그를 바꾸지 않습니다.
82행 그림 · 레지스터 상태
함수·코드 범위: relative_data16
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 결과는 목적 레지스터 폭에 맞습니다. 이 형식은 NZCV를 바꾸지 않습니다.
retPREL16 주소 계산 결과를 C 쪽 기대값과 비교하도록 반환합니다. 피연산자가 없는 RET는 LR(x30)에 들어 있는 주소에서 실행을 이어갑니다.
83행 그림 · 호출과 실행 위치
함수·코드 범위: relative_data16
→는 같은 항목의 실행 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 새 복귀 주소를 LR에 기록하지 않습니다. RET 역시 메모리의 스택 값을 자동으로 꺼내는 명령은 아닙니다.
0: .short sym64_rel - ., 0이 .short은 CPU 명령이 아니라 항목당 2바이트 데이터와 필요한 재배치 정보를 내보내는 어셈블러 지시문입니다. 아직 확정되지 않은 심벌 값은 링크 또는 모듈 적재 시의 재배치 처리로 채웁니다. 이 테스트 함수가 실행될 때에는 앞의 load 명령이 채워진 데이터를 읽습니다. sym64_rel과 현재 위치의 차이를 16비트 데이터로 재배치하고, 뒤에 16비트 0을 추가합니다. 검사 대상은 앞의 상대값 필드입니다.
84행 그림 · 어셈블·링크 단계
함수·코드 범위: relative_data16
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
SYM_FUNC_END(relative_data16)도구에 이 코드 범위의 끝을 알려 크기와 심볼 정보를 기록합니다. CPU가 이 줄 때문에 자동으로 반환하지는 않습니다.
85행 그림 · 어셈블·링크 단계
함수·코드 범위: relative_data16
→는 같은 항목의 처리 전과 후를 비교하는 표시입니다. 메모리 주소의 증가 방향이나 데이터 전송 경로를 뜻하지 않습니다.
- 끝 표기 자체가 RET나 분기를 실행하지는 않습니다.
설명한 뒤 함께 생각해 볼 질문
RET 뒤에 데이터가 있어도 되나요?
정상 실행이 RET에서 다른 곳으로 이동하므로 뒤의 리터럴을 실행하지 않습니다. 앞의 LDR 등이 그 위치를 데이터로 읽습니다.
상대 데이터에 x1을 더하는 이유는 무엇인가요?
리터럴에는 목표 심볼과 리터럴 위치의 차이가 있습니다. 그 위치를 다시 더해 목표 주소를 복구합니다.
테스트가 한 번 통과하면 모든 배치도 보장되나요?
아닙니다. 이 코드의 값, 거리, 정렬 조건에서 해당 재배치 처리를 확인한 결과입니다.
주석을 포함한 전체 원문
1/* SPDX-License-Identifier: GPL-2.0-only */2/*3* Copyright (C) 2017 Linaro, Ltd. <ard.biesheuvel@linaro.org>4*/56#include <linux/linkage.h>78SYM_FUNC_START(absolute_data64)9ldr x0, 0f10ret110: .quad sym64_abs12SYM_FUNC_END(absolute_data64)1314SYM_FUNC_START(absolute_data32)15ldr w0, 0f16ret170: .long sym32_abs18SYM_FUNC_END(absolute_data32)1920SYM_FUNC_START(absolute_data16)21adr x0, 0f22ldrh w0, [x0]23ret240: .short sym16_abs, 025SYM_FUNC_END(absolute_data16)2627SYM_FUNC_START(signed_movw)28movz x0, #:abs_g2_s:sym64_abs29movk x0, #:abs_g1_nc:sym64_abs30movk x0, #:abs_g0_nc:sym64_abs31ret32SYM_FUNC_END(signed_movw)3334SYM_FUNC_START(unsigned_movw)35movz x0, #:abs_g3:sym64_abs36movk x0, #:abs_g2_nc:sym64_abs37movk x0, #:abs_g1_nc:sym64_abs38movk x0, #:abs_g0_nc:sym64_abs39ret40SYM_FUNC_END(unsigned_movw)4142.align 1243.space 0xff844SYM_FUNC_START(relative_adrp)45adrp x0, sym64_rel46add x0, x0, #:lo12:sym64_rel47ret48SYM_FUNC_END(relative_adrp)4950.align 1251.space 0xffc52SYM_FUNC_START(relative_adrp_far)53adrp x0, memstart_addr54add x0, x0, #:lo12:memstart_addr55ret56SYM_FUNC_END(relative_adrp_far)5758SYM_FUNC_START(relative_adr)59adr x0, sym64_rel60ret61SYM_FUNC_END(relative_adr)6263SYM_FUNC_START(relative_data64)64adr x1, 0f65ldr x0, [x1]66add x0, x0, x167ret680: .quad sym64_rel - .69SYM_FUNC_END(relative_data64)7071SYM_FUNC_START(relative_data32)72adr x1, 0f73ldr w0, [x1]74add x0, x0, x175ret760: .long sym64_rel - .77SYM_FUNC_END(relative_data32)7879SYM_FUNC_START(relative_data16)80adr x1, 0f81ldrsh w0, [x1]82add x0, x0, x183ret840: .short sym64_rel - ., 085SYM_FUNC_END(relative_data16)
