# Kernel module relocation과 instruction range

v6.18.37 / arch/arm64/kernel/module.c

모듈을 빌드할 때 아직 정해지지 않은 주소는 적재 시점에 채웁니다. arm64·x86·RISC-V 모두 ELF 재배치를 쓰지만 명령어의 즉시값 위치와 표현 범위가 다릅니다. 대표로 arm64가 절대값, 위치 상대값, 4KiB 페이지 상대값을 계산하는 작은 함수를 읽습니다.

## do_reloc

```c

static u64 do_reloc(enum aarch64_reloc_op reloc_op, __le32 *place, u64 val)
{
	switch (reloc_op) {
	case RELOC_OP_ABS:
		return val;
	case RELOC_OP_PREL:
		return val - (u64)place;
	case RELOC_OP_PAGE:
		return (val & ~0xfff) - ((u64)place & ~0xfff);
	case RELOC_OP_NONE:
		return 0;
	}

	pr_err("do_reloc: unknown relocation operation %d\n", reloc_op);
	return 0;
}

```

### 35행

```c

static u64 do_reloc(enum aarch64_reloc_op reloc_op, __le32 *place, u64 val)

```

재배치 연산 종류, 패치 위치 place, 상위에서 준비한 기호 값 val을 받아 계산 결과를 반환합니다. __le32 포인터 타입은 명령어 저장 형식을 드러내지만 이 함수에서는 직접 쓰지 않습니다.

### 37행

```c

	switch (reloc_op) {

```

재배치가 요구한 계산 방식을 분기합니다.

### 38행

```c

	case RELOC_OP_ABS:

```

절대 주소 연산의 경우입니다.

### 39행

```c

		return val;

```

절대형은 전달받은 기호 값과 가산값의 결과 val을 그대로 사용합니다.

### 40행

```c

	case RELOC_OP_PREL:

```

패치 위치를 기준으로 하는 상대 주소 연산의 경우입니다.

### 41행

```c

		return val - (u64)place;

```

목적값에서 현재 패치 위치 P를 빼 상대 거리를 구합니다. place의 포인터 숫자를 u64로 바꾸어 계산합니다.

### 42행

```c

	case RELOC_OP_PAGE:

```

AArch64의 4KiB 페이지 상대 연산의 경우입니다.

### 43행

```c

		return (val & ~0xfff) - ((u64)place & ~0xfff);

```

목적지와 현재 위치에서 각각 하위 12비트를 지우고 두 경계 주소의 차이를 구합니다. Linux PAGE_SIZE와 ADRP의 4KiB 단위를 혼동하지 않습니다.

### 44행

```c

	case RELOC_OP_NONE:

```

아무 계산을 요구하지 않는 종류의 경우입니다.

### 45행

```c

		return 0;

```

NONE에는 0을 돌려줍니다.

### 48행

```c

	pr_err("do_reloc: unknown relocation operation %d\n", reloc_op);

```

알 수 없는 연산 값이 들어오면 진단 메시지를 남깁니다.

### 49행

```c

	return 0;

```

알 수 없는 경우도 이 helper는 0으로 반환합니다. 전체 로더가 재배치 형식과 범위를 검증하는 주변 경로까지 함께 봐야 합니다.

