Kernel-provided User Helpers

 

커널 메모리의 코드 및 데이터 일부를 유저가 직접 호출 또는 접근할 수 있도록 유일하게 허용한 페이지이다.

  • Posix syscall을 사용하지 않고 직접 유저 공간에서 호출하므로 매우 빠른 속도가 요구되는 코드를 수행할 수 있다.
  • 하이 벡터를 사용하는 프로세서에서 CONFIG_KUSER_HELPERS 커널 옵션을 사용하여 제공한다.
    • 로우 벡터에서는 kuser helper 코드를 지원하지 않는다.
  • arm에서 가상 주소 0xffff_0000로 시작하는 페이지를 사용하는 하이 벡터 페이지의 사용하지 않는 윗 부분을 이용한다.
    • 현재 0xffff_0f60 ~ 0xffff0fff 까지 범위에서 사용하고 있다.

 

코드 위치

현재 커널은 하이벡터 페이지의 가장 윗 부분을 이용하여 다음 4개의 함수와 1개의 상수 값을 제공한다.

  • __kuser_cmpxchg64()
  • __kuser_memory_barrier()
  • __kuser_cmpxchg()
  • __kuser_get_tls()
  • __kuser_helper_version 상수

 

코드가 위치한 주소는 다음 그림과 같다.

 

Kernel provided User Helper 버전 확인

가상 주소: 0xffff_0ffc

 

사용 방법

#define __kuser_helper_version (*(int32_t *)0xffff0ffc)

void check_kuser_version(void)
{
        if (__kuser_helper_version < 2) {
                fprintf(stderr, "can't do atomic operations, kernel too old\n");
                abort();
        }
}

버전 값이 2보다 작은 경우 커널이 너무 오래되어서 atomic operation을 지원하지 않는 것을 알 수 있다.

 

__kuser_cmpxchg64() 함수

가상 주소: 0xffff_0f60

 

사용방법

typedef int (__kuser_cmpxchg64_t)(const int64_t *oldval,
                                  const int64_t *newval,
                                  volatile int64_t *ptr);
#define __kuser_cmpxchg64 (*(__kuser_cmpxchg64_t *)0xffff0f60)

int64_t atomic_add64(volatile int64_t *ptr, int64_t val)
{
        int64_t old, new;

        do {
                old = *ptr;
                new = old + val;
        } while(__kuser_cmpxchg64(&old, &new, ptr));

        return new;
}

64bit 값이 담긴 ptr 포인터 주소에 val 값을 atomic하게 더한다.

  • __kuser_cmpxchg64() 함수는 64bit 현재 값이 oldval과 같은 경우 newval을 atomic 하게 저장하고 성공리에 0을 반환한다. 그 외의 값은 oldval과 newval이 달라 저장하지 않은 경우이다.

 

 3가지 구현  방법

Kernel-provided User Helper code 중 kuser_cmpxchg64() 함수는 시스템에 따라 3 가지의 구현 중 하나를 사용한다.

  1. fastpath
    • ARMv6K를 포함하여 이후 버전의 ARM 아키텍처는 user space에서 직접 cmpxchg 및 cmpxchg64 atomic operation을 수행할 수 있다.
      • ARM SMP 시스템에서 사용하는 atomic operation
        • ARMv6: swp
        • ARMv7: ldrex/strex이 권장 사용되며, swp는 호환목적으로 s/w emulation 방법을 사용하여 구현되어 있다.(비권장)
  2. slowpath for SMP
    • fastpath를 지원하지 않는 SMP 아키텍처를 사용하는 경우 CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG 커널 옵션을 사용하여 arm syscall을 사용하여 커널로 진입하여 64bit cmpxchg atomic operation을 수행하는 방법이다.
  3. slowpath for UP
    • UP 시스템에서 atomic을 포기하고 순서대로 진행하는 방법으로 인터럽트가 커널에서 호출되는 경우에 한하여 fixup을 수행하여 보강한다.

 

NEEDS_SYSCALL_FOR_CMPXCHG

  • arm 아키텍처로 집중해서 이 커널 옵션을 보면 ARMv6 이전 SMP 프로세서(아직은 이렇게 만든 SoC가 없는 것 같다. 하지만 미래에 어떤 회사가 만들지 모르는 법이므로…)는 직접 user space에서 atomic하게 cmpxchg를 수행할 수 없다. 따라서 느리더라도 POSIX call을 사용하여 커널에 진입한 후 처리하도록 이 방법을 사용하여야 한다.

 

__kuser_cmpxchg64:

user space에서 64 bit atomic operation을 처리하기 위해 이러한 기능에 대한 아키텍처의 지원 여부에 따라 구현 방법을 3가지로 달리 구현되었다.

1) 커널에 위탁 처리하는 방법

arch/arm/kernel/entry-armv.S

/*
 * Due to the length of some sequences, __kuser_cmpxchg64 spans 2 regular
 * kuser "slots", therefore 0xffff0f80 is not used as a valid entry point.
 */

__kuser_cmpxchg64:                              @ 0xffff0f60

#if defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG)

        /*
         * Poor you.  No fast solution possible...
         * The kernel itself must perform the operation.
         * A special ghost syscall is used for that (see traps.c).
         */
        stmfd   sp!, {r7, lr}
        ldr     r7, 1f                  @ it's 20 bits
        swi     __ARM_NR_cmpxchg64
        ldmfd   sp!, {r7, pc}
1:      .word   __ARM_NR_cmpxchg64

CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG 커널 옵션은 주로 user space에서 atomic operation을 지원하지 못하는 SMP 아키텍처에서 사용한다. atomic operation이 필요한 경우 커널은 인터럽트되지 않도록 블럭한 후 처리할 수 있기 때문에 user space에서의 kuser_cmpxchg64 요청은 arm syscall을 사용하여 커널에 위탁하여 처리하고 그 결과를 내려보내주게 구현되었다.

  • 코드 라인 15에서 r7, lr 레지스터 사용해야 하므로 잠시 스택에 보관한다.
  • 코드 라인 16~17에서 r7에 __ARM_NR_cmpxchg64에 해당하는 arm syscall 넘버를 대입한 후 swi swi 명령을 사용하여 arm syscall 호출을 수행한다.
  • 코드 라인 18에서 스택으로 부터 r7을 복구하고, lr 주소로 jump 한다.

 

2) atomic이 지원되는 아키텍처에서 직접 수행하는 방법

#elif defined(CONFIG_CPU_32v6K)

        stmfd   sp!, {r4, r5, r6, r7}
        ldrd    r4, r5, [r0]                    @ load old val
        ldrd    r6, r7, [r1]                    @ load new val
        smp_dmb arm
1:      ldrexd  r0, r1, [r2]                    @ load current val
        eors    r3, r0, r4                      @ compare with oldval (1)
        eoreqs  r3, r1, r5                      @ compare with oldval (2)
        strexdeq r3, r6, r7, [r2]               @ store newval if eq
        teqeq   r3, #1                          @ success?
        beq     1b                              @ if no then retry
        smp_dmb arm
        rsbs    r0, r3, #0                      @ set returned val and C flag
        ldmfd   sp!, {r4, r5, r6, r7}
        usr_ret lr

CONFIG_CPU_32v6K는 user space에서도 atomic operation을 사용할 수 있는 armv6 이상의 SMP 아키텍처에서 사용하는 커널 옵션이다. 이러한 경우 user space에서 직접 ldrex 및 strex를 사용하여 atomic operation을 수행할 수 있다.

  • 코드 라인 3에서 r4~r7까지 레지스터를 스택에 백업한다.
  • 코드 라인 4에서 r0(old)가 가리키는 주소에서 double word(64bit) 값을 읽어서 r4와 r5 레지스터에 저장한다.
    • ldr r4, [r0]; ldr r5, [r0, #4]와 동일한 결과다.
  • 코드 라인 5에서 r1(new)가 가리키는 주소에서 double word(64bit) 값을 읽어서 r6와 r7 레지스터에 저장한다.
  • 코드 라인 6에서 다음 ldrexd를 호출하기 전에 dmb를 사용하여 메모리에 대해 order 문제가 생기지 않도록 한다.
  • 코드 라인 7에서 r2(ptr)가 가리키는 주소에서 double word(64bit) 값을 읽어서 r0와 r1 레지스터에  저장한다.
  • 코드 라인 8~10에서 읽은 ptr 값(r0, r1)과 old 값(r4, r5)가 비교를 하여 같은 경우 r2 주소에 new(r6, r7) 값을 저장하되 결과를 r3에 저장한다.
  • 코드 라인 11~12에서 저장 시 이 캐시 라인이 exclusive되지 않아 결과(r3)이 실패(#1)한 경우 다시 레이블 1로 이동하여 성공할 때까지 반복한다.
    • 다른 cpu에서 이 exclusive한 캐시라인에 접근하는 경우 open되어 strex 명령을 수행 시 실패를 얻게된다.
  • 코드 라인 13에서 다시 메모리 배리어를 사용하여 order 문제가 생기지 않도록 한다.
  • 코드 라인 14에서 0에서 r3(0=기록한 경우, 그 외=oldval과 newval이 달라 기록하지 않은 경우)와 캐리(C)까지 뺀 후 r0 레지스터에 담는다.
  • 코드 라인 15~16에서 스택에 백업해둔 레지스터들을 복구하고 lr 주소로 복귀한다.

 

3) UP 시스템에서 atomic 구현

#elif !defined(CONFIG_SMP)

#ifdef CONFIG_MMU

        /*
         * The only thing that can break atomicity in this cmpxchg64
         * implementation is either an IRQ or a data abort exception
         * causing another process/thread to be scheduled in the middle of
         * the critical sequence.  The same strategy as for cmpxchg is used.
         */
        stmfd   sp!, {r4, r5, r6, lr}
        ldmia   r0, {r4, r5}                    @ load old val
        ldmia   r1, {r6, lr}                    @ load new val
1:      ldmia   r2, {r0, r1}                    @ load current val
        eors    r3, r0, r4                      @ compare with oldval (1)
        eoreqs  r3, r1, r5                      @ compare with oldval (2)
2:      stmeqia r2, {r6, lr}                    @ store newval if eq
        rsbs    r0, r3, #0                      @ set return val and C flag
        ldmfd   sp!, {r4, r5, r6, pc}

        .text
kuser_cmpxchg64_fixup:
        @ Called from kuser_cmpxchg_fixup.
        @ r4 = address of interrupted insn (must be preserved).
        @ sp = saved regs. r7 and r8 are clobbered.
        @ 1b = first critical insn, 2b = last critical insn.
        @ If r4 >= 1b and r4 <= 2b then saved pc_usr is set to 1b.
        mov     r7, #0xffff0fff
        sub     r7, r7, #(0xffff0fff - (0xffff0f60 + (1b - __kuser_cmpxchg64)))
        subs    r8, r4, r7
        rsbcss  r8, r8, #(2b - 1b)
        strcs   r7, [sp, #S_PC]
#if __LINUX_ARM_ARCH__ < 6
        bcc     kuser_cmpxchg32_fixup
#endif
        ret     lr
        .previous
#endif

        kuser_pad __kuser_cmpxchg64, 64

user space에서 atomic이 구현되지 않는 UP 아키텍처에서 __kuser_cmpxchg64 함수의 기능 구현은 atomic과 관련 없이 단순하게 구현되어 있다. 그 구현 루틴 아래에 위치한 kuser_cmpxchg64_fixup 루틴을 살펴보기 전에는 그 어떠한 atomic 관련한 부가 루틴도 찾아 볼 수가 없다. atomic에 대한 보장을 위해 자세한 것은 kuser_cmpxchg64_fixup 레이블에서 설명하기로 한다.

  • 코드 라인 11에서 r4, r5, r6, lr 레지스터를 스택에 백업해둔다.
  • 코드 라인 12에서 r0위치에 있는 64bit old 값을 r4와 r5 레지스터에 로드한다.
  • 코드 라인 13에서 r1 위치에 있는 64bit new 값을 r6와 lr 레지스터에 로드한다.
  • 코드 라인 14에서 r2 위치에 있는 64bit ptr 값을 r0와 r1 레지스터에 로드한다.
  • 코드 라인 15~17에서 old 값과 ptr 값을 비교하여 같은 경우 new 값을 ptr에 저장한다.
  • 코드 라인 18에서 0에서 r3(0=기록한 경우, 그 외=old 값과 new 값이 달라 기록하지 않은 경우)와 캐리(C)까지 뺀 후 r0 레지스터에 담는다.
  • 코드 라인 19에서 스택에 백업해둔 레지스터들을 복구하고 lr 주소로 복귀한다.
kuser_cmpxchg64_fixup:

user space에서 atomic이 구현되지 않는 UP 아키텍처에서 __kuser_cmpxchg64 루틴을 수행 시 atomic하게 처리해야 하는 구간 즉, 레이블 1과 레이블 2 사이를 수행하는 도중에 irq, fiq, dabt 등을 만나게 되는 경우 해당 exception을 처리한 후 되돌아갈 주소를 atomic 구간의 가장 윗 부분으로 바꾸기 위해 스택의 pt_regs의 pc를 조작하는 방법을 사용한다.

  • 코드 라인 28~29에서 atomic operation이 시작되는 레이블 1:의 가상 주소 값을 알아온다.
    • r7 <- ffff0f60 + (1b – __kuser_cmpxchg64)를 대입하고 싶지만 operand에 사용하는 값의 크기 제한으로 인해 두 개의 명령을 사용하였다.
  • 코드 라인 30~32에서 인터럽트 되었을 때의 pc 주소가 담긴 r4 레지스터 값이 atomic 하게 처리할 구간 범위(레이블 1: ~ 레이블 2:)인 경우 스택에 저장해 둔 pt_regs 구조체 중 pc 위치에 레이블 1 주소를 저장하여 다시 인터럽트 복귀 시 atomic operation을 다시 시도하게 변경한다.
  • 코드 라인 33~35에서 arm 아키텍처가 버전 6보다 이전인 경우에는 위의 atomic opeation 수행 도중 인터럽트 된 것이 아니라면  kuser_cmpxchg32 명령 수행 도중에 발생한 일인지 확인하여 역시 같은 방식으로 복귀 주소를 변경하게 한다.

 

__kuser_memory_barrier:

arch/arm/kernel/entry-armv.S

__kuser_memory_barrier:                         @ 0xffff0fa0
        smp_dmb arm
        usr_ret lr

        kuser_pad __kuser_memory_barrier, 32

SMP 시스템에서 메모리 배리어를 사용하여 이전 로직의 메모리 액세스와 연관하여 order 문제가 생기지 않도록 막는다.

 

__kuser_cmpxchg:

user space에서 32 bit atomic operation을 처리하기 위해 이러한 기능에 대한 아키텍처의 지원 여부에 따라 구현 방법을 3가지로 달리 구현되었다.

1) 커널에 위탁 처리하는 방법

arch/arm/kernel/entry-armv.S

__kuser_cmpxchg:                                @ 0xffff0fc0

#if defined(CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG)

        /*
         * Poor you.  No fast solution possible...
         * The kernel itself must perform the operation.
         * A special ghost syscall is used for that (see traps.c).
         */
        stmfd   sp!, {r7, lr}
        ldr     r7, 1f                  @ it's 20 bits
        swi     __ARM_NR_cmpxchg
        ldmfd   sp!, {r7, pc}
1:      .word   __ARM_NR_cmpxchg

CONFIG_NEEDS_SYSCALL_FOR_CMPXCHG 커널 옵션은 주로 user space에서 atomic operation을 지원하지 못하는 SMP 아키텍처에서 사용한다. atomic operation이 필요한 경우 커널은 인터럽트되지 않도록 블럭한 후 처리할 수 있기 때문에 user space에서의 kuser_cmpxchg 요청은 arm syscall을 사용하여 커널에 위탁하여 처리하고 그 결과를 내려보내주게 구현되었다.

  • 코드 라인 10에서 r7, lr 레지스터 사용해야 하므로 잠시 스택에 보관한다.
  • 코드 라인 11~12에서 r7에 __ARM_NR_cmpxchg64에 해당하는 arm syscall 넘버를 대입한 후 swi swi 명령을 사용하여 arm syscall 호출을 수행한다.
  • 코드 라인 13에서 스택으로 부터 r7을 복구하고, lr 주소로 jump 한다.

 

2) UP 시스템에서 atomic 구현

#elif __LINUX_ARM_ARCH__ < 6

#ifdef CONFIG_MMU

        /*
         * The only thing that can break atomicity in this cmpxchg
         * implementation is either an IRQ or a data abort exception
         * causing another process/thread to be scheduled in the middle
         * of the critical sequence.  To prevent this, code is added to
         * the IRQ and data abort exception handlers to set the pc back
         * to the beginning of the critical section if it is found to be
         * within that critical section (see kuser_cmpxchg_fixup).
         */
1:      ldr     r3, [r2]                        @ load current val
        subs    r3, r3, r0                      @ compare with oldval
2:      streq   r1, [r2]                        @ store newval if eq
        rsbs    r0, r3, #0                      @ set return val and C flag
        usr_ret lr

        .text
kuser_cmpxchg32_fixup:
        @ Called from kuser_cmpxchg_check macro.
        @ r4 = address of interrupted insn (must be preserved).
        @ sp = saved regs. r7 and r8 are clobbered.
        @ 1b = first critical insn, 2b = last critical insn.
        @ If r4 >= 1b and r4 <= 2b then saved pc_usr is set to 1b.
        mov     r7, #0xffff0fff
        sub     r7, r7, #(0xffff0fff - (0xffff0fc0 + (1b - __kuser_cmpxchg)))
        subs    r8, r4, r7
        rsbcss  r8, r8, #(2b - 1b)
        strcs   r7, [sp, #S_PC]
        ret     lr
        .previous

#else
#warning "NPTL on non MMU needs fixing"
        mov     r0, #-1
        adds    r0, r0, #0
        usr_ret lr
#endif

user space에서 atomic이 구현되지 않는 UP 아키텍처에서 __kuser_cmpxchg 함수의 기능 구현은 atomic과 관련 없이 단순하게 구현되어 있다. 그 구현 루틴 아래에 위치한 kuser_cmpxchg_fixup 루틴을 살펴보기 전에는 그 어떠한 atomic 관련한 부가 루틴도 찾아 볼 수가 없다. atomic에 대한 보장을 위해 자세한 것은 kuser_cmpxchg_fixup 레이블에서 설명하기로 한다.

  • 코드 라인 14에서 r2(ptr)위치에 있는 값을 r3 레지스터에 로드한다.
  • 코드 라인 15~16에서 r0(old) 레지스터 값과 r3 레지스터 값을 비교하여 같은 경우 r1(new) 레지스터 값을 r2(ptr) 레지스터가 가리키는 주소에 저장한다.
  • 코드 라인 17~18은 0에서 r3(0=기록한 경우, 그 외=old 값과 new 값이 달라 기록하지 않은 경우)와 캐리(C)까지 뺀 후 r0 레지스터에 담고 lr 주소로 복귀한다.
kuser_cmpxchg_fixup:

user space에서 atomic이 구현되지 않는 UP 아키텍처에서 __kuser_cmpxchg 루틴을 수행 시 atomic하게 처리해야 하는 구간 즉, 레이블 1과 레이블 2 사이를 수행하는 도중에 irq, fiq, dabt 등을 만나게 되는 경우 해당 exception을 처리한 후 되돌아갈 주소를 atomic 구간의 가장 윗 부분으로 바꾸기 위해 스택의 pt_regs의 pc를 조작하는 방법을 사용한다.

  • 코드 라인 27~28에서 atomic operation이 시작되는 레이블 1:의 가상 주소 값을 알아온다.
    • r7 <- ffff0fc0 + (1b – __kuser_cmpxchg)를 대입하고 싶지만 operand에 사용하는 값의 크기 제한으로 인해 두 개의 명령을 사용하였다.
  • 코드 라인 29~32에서 인터럽트 되었을 때의 pc 주소가 담긴 r4 레지스터 값이 atomic 하게 처리할 구간 범위(레이블 1: ~ 레이블 2:)인 경우 스택에 저장해 둔 pt_regs 구조체 중 pc 위치에 레이블 1 주소를 저장하여 다시 인터럽트 복귀 시 atomic operation을 다시 처음 부터 시도하게 변경하고 lr 주소로 복귀한다.

 

3) atomic이 지원되는 아키텍처에서 직접 수행하는 방법

#else

        smp_dmb arm
1:      ldrex   r3, [r2]
        subs    r3, r3, r0
        strexeq r3, r1, [r2]
        teqeq   r3, #1
        beq     1b
        rsbs    r0, r3, #0
        /* beware -- each __kuser slot must be 8 instructions max */
        ALT_SMP(b       __kuser_memory_barrier)
        ALT_UP(usr_ret  lr)

#endif

        kuser_pad __kuser_cmpxchg, 32

user space에서도 atomic operation을 사용할 수 있는 armv6 이상의 SMP 아키텍처에서 사용하는 커널 옵션이다. 이러한 경우 user space에서 직접 ldrex 및 strex를 사용하여 atomic operation을 수행할 수 있다.

  • 코드 라인 3에서 메모리 배리어를 사용하여 이전 로직의 메모리 액세스와 연관하여 order 문제가 생기지 않도록 막는다.
  • 코드 라인 4~6에서 r2(ptr)가 가리키는 주소에서 값을 읽은 값을 r3 레지스터에 저장한다. 이 값과 r0(old) 값을 비교하여 같은 경우 r1(new) 값을 r2(ptr)가 가리키는 주소에 저장한다. 저장 결과는 r3에 담는다. (성공=0, 실패=1)
  • 코드 라인 7~8에서 저장 시 이 캐시 라인이 exclusive되지 않아 결과(r3)이 실패(#1)한 경우 다시 레이블 1로 이동하여 성공할 때까지 반복한다.
    • 다른 cpu에서 이 exclusive한 캐시라인에 접근하는 경우 open되어 strex 명령을 수행 시 실패를 얻게된다.
  • 코드 라인 9는 0에서 r3(0=기록한 경우, 그 외=oldval과 newval이 달라 기록하지 않은 경우)와 캐리(C)까지 뺀 후 r0 레지스터에 담는다.
  • 코드 라인 11~12에서 복귀를 하되 SMP 시스템인 경우 다시 메모리 배리어를 사용하여 order 문제가 생기지 않도록 한다.

 

__kuser_get_tls:

arch/arm/kernel/entry-armv.S

__kuser_get_tls:                        @ 0xffff0fe0
        ldr     r0, [pc, #(16 - 8)]     @ read TLS, set in kuser_get_tls_init
        usr_ret lr
        mrc     p15, 0, r0, c13, c0, 3  @ 0xffff0fe8 hardware TLS code
        kuser_pad __kuser_get_tls, 16
        .rep    3
        .word   0                       @ 0xffff0ff0 software TLS value, then
        .endr

TLS(Thread Local Storage) 값을 알아온다.  2가지의 구현을 사용한다.

  • S/W TLS
    • 0xffff_0ff0 주소에 TLS 값을 보관해두고 그 값을 읽어 사용한다.
  • H/W TLS
    • user 에서 읽기만 가능한 TPIDRURO 레지스터에서 값을 읽어 사용한다.

 

  • 코드 라인 2~3에서 0xfff_0ff0 위치에서 TLS 값을 가져와 r0 레지스터에 담고 lr 주소로 복귀한다.
  • 코드 라인 4에는 TPIDRURO 레지스터에서 값을 읽어 r0 레지스터에 담는 코드를 두었다.
    • H/W TLS 레지스터를 지원하는 경우 이 코드를 복사하여 코드 라인 2의 주소인 0xffff_0fe0에 복사하기 위해 사용된다.
      • setup_arch() -> paging_init() -> devicemaps_init() -> early_trap_init() -> kuser_init() 함수 내부에 다음 코드를 찾을 수 있다.
        • memcpy(vectors + 0xfe0, vectors + 0xfe8, 4);

 

매크로 함수

usr_ret 매크로

arch/arm/kernel/entry-armv.S

        .macro  usr_ret, reg
#ifdef CONFIG_ARM_THUMB
        bx      \reg
#else
        ret     \reg
#endif
        .endm

\reg 주소로 복귀한다.

 

kuser_pad 매크로

arch/arm/kernel/entry-armv.S

        .macro  kuser_pad, sym, size
        .if     (. - \sym) & 3
        .rept   4 - (. - \sym) & 3
        .byte   0
        .endr
        .endif
        .rept   (\size - (. - \sym)) / 4
        .word   0xe7fddef1
        .endr
        .endm

현재 주소 위치 – sym 주소가 4바이트 단위로 정렬되지 않은 경우 정렬을 위해 0으로 채운다.(0~3 바이트) 그 이후 sym 주소부터 size 만큼의 공간 중 현재 위치부터 0xe7fddef1 값으로 채운다.

  • 예) kuser_pad __kuser_memory_barrier, 32
    • __kuser_memory_barrier 함수 위치 부터 32 바이트 공간내에서 빈 자리를 0xe7fddef1 값으로 채운다.
      • 0xffff0fa0: 0xf57ff05b 0xe12fff1e 0xe7fddef1 0xe7fddef1
      • 0xffff0fb0: 0xe7fddef1 0xe7fddef1 0xe7fddef1 0xe7fddef1

 

참고

답글 남기기

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다.