본문 바로가기

리눅스 커널의 구조와 원리/ARM Processor

[ARM] tst 명령어를 실행하면 ARM CPSR 레지스터가 어떻게 변경될까?

tst 명령어를 실행하면 ARM CPSR 레지스터가 어떻게 변경될까?


tst 명령어는 연산자와 비연산자 사이 AND 비트 연산을 수행합니다.


AND 비트 연산 결과에 따라 CPSR 레지스터 Z 비트는 다음과 같이 변경됩니다.

Z: 0 ( AND 비트 연산 결과가 1인 경우)

Z: 1 ( AND 비트 연산 결과가 0인 경우)


tst 명령어가 위와 같이 동작하는지 증명하기 위해 T32 디버거를 실행해 보겠습니다.

다음 화면은 tst 명령어를 실행하기 직전입니다. 

NSR:80107E6C|ret_to_user_from_irq:        ldr     r2,[r9,#0x8]

NSR:80107E70|                             cmp     r2,#0x7F000000   ; r2,#2130706432

NSR:80107E74|                             blne    0x8010B5FC       ; addr_limit_check_failed

NSR:80107E78|                             ldr     r1,[r9]

NSR:80107E7C|_____________________________tst_____r1,#0x0F_________;_r1,#15

NSR:80107E80|                             bne     0x80107E48       ; slow_work_pending

NSR:80107E84|no_work_pending:             bl      0x801E9CE8       ; trace_hardirqs_on


N _  R0          0  R8          0   

Z Z  R1          2  R9          0

C _  R2          0  R10         0

V _  R3          0  R11         0

Q _  R4   00020000  R12         0

     R5          0  R13  C000D000

0 _  R6          0  R14         0

1 _  R7          0  PC   80107E7C

2 _  SPSR       10  CPSR 400001D3


R1가 2(이진수 10)이니 0xF와 AND 비트 연산을 하면 1이 될 것입니다.

1111 (0xF)

  10 (2: R1) 

------

   1 (연산 결과)


다음은 "tst r1,#0x0F" 명령어를 실행한 후 결과입니다.

NSR:80107E6C|ret_to_user_from_irq:        ldr     r2,[r9,#0x8]

NSR:80107E70|                             cmp     r2,#0x7F000000   ; r2,#2130706432

NSR:80107E74|                             blne    0x8010B5FC       ; addr_limit_check_failed

NSR:80107E78|                             ldr     r1,[r9]

NSR:80107E7C|                             tst     r1,#0x0F         ; r1,#15

NSR:80107E80|_____________________________bne_____0x80107E48_______;_slow_work_pending

NSR:80107E84|no_work_pending:             bl      0x801E9CE8       ; trace_hardirqs_on


N _  R0          0  R8          0   

Z _  R1          2  R9          0

C _  R2          0  R10         0

V _  R3          0  R11         0

Q _  R4   00020000  R12         0

     R5          0  R13  C000D000

0 _  R6          0  R14         0

1 _  R7          0  PC   80107E80

2 _  SPSR       10  CPSR     01D3


여기서 눈을 크게 뜨고 봐야 할 중요한 정보는 ARM CPSR 레지스터입니다.

CPSR 레지스터가 0x1D3으로 변경됐습니다. CPSR 레지스터 Z 비트가 0이란 이야기입니다.


bne 명령어는 'branch not equal'이란 뜻입니다. Z가 0이면 브랜치하겠다는 의미입니다.

bne 0x80107E48 ;slow_work_pending


CPSR 레지스터 Z 비트가 0이니 slow_work_pending 레이블로 브랜치 할 것입니다.

NSR:80107E80|_____________________________bne_____0x80107E48_______;_slow_work_pending


이 결과를 예상하면서 위 "bne 0x80107E48 ;slow_work_pending" 코드를 실행하니 

slow_work_pending 레이블로 브랜치했습니다.

NSR:80107E48|E1A0000D__slow_work_pending:__cpy_____r0,r13

NSR:80107E4C|E1A02008                      cpy     r2,r8

NSR:80107E50|EB000D82                      bl      0x8010B460       ; do_work_pending

NSR:80107E54|E3500000                      cmp     r0,#0x0          ; r0,#0

NSR:80107E58|0A000009                      beq     0x80107E84       ; no_work_pending

NSR:80107E5C|B3A07000                      movlt   r7,#0x0          ; r7,#0

NSR:80107E60|E89D007F                      ldm     r13,{r0-r6}

NSR:80107E64|EA000032                      b       0x80107F34       ; local_restart


이번엔 r1 레지스터가 0x1000 일 때 tst 명령어가 어떤 동작을 하는지 확인해봅시다.

NSR:80107E6C|ret_to_user_from_irq:        ldr     r2,[r9,#0x8]

NSR:80107E70|                             cmp     r2,#0x7F000000   ; r2,#2130706432

NSR:80107E74|                             blne    0x8010B5FC       ; addr_limit_check_failed

NSR:80107E78|                             ldr     r1,[r9]

NSR:80107E7C|_____________________________tst_____r1,#0x0F_________;_r1,#15

NSR:80107E80|                             bne     0x80107E48       ; slow_work_pending

NSR:80107E84|no_work_pending:             bl      0x801E9CE8       ; trace_hardirqs_on


N _  R0          0  R8          0   

Z _  R1       1000  R9          0

C _  R2          0  R10         0

V _  R3          0  R11         0

Q _  R4   00020000  R12         0

     R5          0  R13  C000D000

0 _  R6          0  R14         0

1 _  R7          0  PC   80107E7C

2 _  SPSR       10  CPSR     01D3


위 명령어를 실행하기 전 CPSR 레지스터는 0x1D3이고 R1이 0x1000이란 사실을 기억합시다.

0xF는 이진수로 1111이고 R1가 저장하고 있는 0x1000은 이진수로 1111_0000_0000_0000 일 것입니다.


따라서 AND 비트 연산 결과는 0일 것입니다.

1111_0000_0000_0000  ( 0x1000: R1)

               1111  ( 0xF)

--------------------------------------------- AND 연산

            0    (결과)


이 사실을 염두해두고 "tst r1,#0x0F" 명령어를 T32로 실행하겠습니다.

결과 화면은 다음과 같습니다.


NSR:80107E6C|ret_to_user_from_irq:        ldr     r2,[r9,#0x8]

NSR:80107E70|                             cmp     r2,#0x7F000000   ; r2,#2130706432

NSR:80107E74|                             blne    0x8010B5FC       ; addr_limit_check_failed

NSR:80107E78|                             ldr     r1,[r9]

NSR:80107E7C|                             tst     r1,#0x0F         ; r1,#15

NSR:80107E80|_____________________________bne_____0x80107E48_______;_slow_work_pending

NSR:80107E84|no_work_pending:             bl      0x801E9CE8       ; trace_hardirqs_on


[레지스터 세트]

N _  R0          0  R8          0   

Z Z  R1       1000  R9          0

C _  R2          0  R10         0

V _  R3          0  R11         0

Q _  R4   00020000  R12         0

     R5          0  R13  C000D000

0 _  R6          0  R14         0

1 _  R7          0  PC   80107E80

2 _  SPSR       10  CPSR 400001D3


CPSR 레지스터가 400001D3 이고 Z 비트가 1이 됐습니다.

레지스터 세트에서 붉은색으로 표시된 부분을 눈으로 따라가 보시기 바랍니다.

N _  R0          0  R8          0   

Z Z  R1       1000  R9          0


Z 필드가 켜져 있습니다.


Z 비트가 1인데 다음 bne 명령어를 실행하면 어떻게 실행할까요? 

NSR:80107E80|_____________________________bne_____0x80107E48_______;_slow_work_pending

NSR:80107E84|no_work_pending:             bl      0x801E9CE8       ; trace_hardirqs_on


당연히 slow_work_pending 레이블로 브랜치하지 않고 80107E84 주소로 브랜치할 것입니다.

NSR:80107E6C|ret_to_user_from_irq:        ldr     r2,[r9,#0x8]

NSR:80107E70|                             cmp     r2,#0x7F000000   ; r2,#2130706432

NSR:80107E74|                             blne    0x8010B5FC       ; addr_limit_check_failed

NSR:80107E78|                             ldr     r1,[r9]

NSR:80107E7C|                             tst     r1,#0x0F         ; r1,#15

NSR:80107E80|                             bne     0x80107E48       ; slow_work_pending

NSR:80107E84|no_work_pending:_____________bl______0x801E9CE8_______;_trace_hardirqs_on