제어 명령어(Control Instructions)

프로그램의 흐름 제어에서 고수준 언어의 표준은

C언어 문법을 이야기할 수 있습니다.

 

C언어의 창시자인 데니스 리치가 이미

1970년대에 if문, switch case와 break와 continue를

사용하는 지금의 분기문(branch)를 확립했습니다.

또 많은 프로그래머들이 사랑하는 도구인

for, while, do while 루프를 만들었습니다.

 

그리고는 goto 문과 label을 남겨두었는데

그가 커니핸 교수와 공동 저술한 C언어 교재인

'K&R C프로그래밍 언어'에서도 불가피한 상황에만

goto문을 사용하기 위해 남겨뒀다고 밝힙니다.

 

goto와 label은 어셈블리어에서 jmp(점프)

명령어와 label과 같습니다. 차이점은

어셈블리어에서는 위의 C언어에서 사용하는

제어문이 없기 때문에 직접 분기문을 만들어서

사용해야 합니다. 간단한 if 문의 경우 대충

비스무리하게 흉내를 내면 되지만 복잡한

분기문들을 어셈블리어로 만드는 일은

다소 빡빡합니다. jmp 문을 사용해보면

비로소 C언어의 위대함을 알게 됩니다.

아니 모든 고수준(high level) 언어의 편리함에

뙇하고 감탄을 할 수 밖에 없습니다.

 

데니스 리치는 개인적으로 가장 존경하는

레전드 top 3 프로그래머로 꼽는데

어셈블리어를 좀 더 알아갈 수록

그의 생전 가치를 재발견하는 것 같습니다.

(데니스 리치는 2011년 세상을 떠났다.

스티브 잡스가 투병 중 사망한 후 얼마

지나지 않아서인데 프로그래머로는

레전드지만 대중적으로 잡스 보다

유명인은 아니어서 조용히 묻혔다는

이야기다. 후에 언론에서 그의 업적을

재평가 하기도 했음)

 

jump 명령어 - 무조건 / 조건 제어

이번 포스팅에서는 jump 명령어들을 알아보겠습니다.

 

jump 명령어들이라고 하니까 이상합니다.

goto 문은 그냥 label로 날아가는 것 아닌가?

 

jump에는 여러가지 조건에 따라 점프의

로직이 달라지기 때문입니다.

크게 무조건 jump 와 조건 jump 가 있는데

조건 jump에서는 CPU의 상태를

기록하는 flag 레지스터의 값에 따라

분기하여 jump를 하는 명령어들입니다.

 

무조건 jump

무조건 jump 라고 하니까 약간 예능 같은데요.

 

명령어의 사용법은 jmp <라벨> 입니다.

 

아무 코드 없이 시도할 수 있는 코드는

jmp _start 입니다. _start 는 시작점이니까

무한루프하겠지요. jmp가 하는 일은

무한정 라벨이 있는 위치로 이동 하는 것 입니다.

위치란 건 당연히 라벨이 있는 메모리 주소이고

그 다음에 실행할 위치가 RIP 레지스터에 저장됩니다.

(RIP - 다음 명령어가 저장된 메모리 주소)

section .text
    global _start

_start:
    jmp _start

아무것도 안하는 코드지만 내부적으로는

무한루프하고 있습니다. 무한루프를

종료하려면 Ctrl + C 로 인터럽트합니다.

(리눅스 터미널에서)

 

조건 Jump

쩜프를 하는데 조건식의 결과에 따라

할 수도 있고 안할 수도 있습니다.

 

조건식은 cmp (compare 비교 명령어)을

사용합니다만, cmp가 없다면 Flag

레지스터의 값을 체크하여 조건에 따라

점프하도록 되어있습니다.

 

일단 다음의 명령어를 알아보면,

 

cmp <피연산자1> <피연산자2>

 

이것이 하는 실제 동작은

피연산자1에서 피연산자2를 뺀 후에

0이 나오면 Flag 레지스터의 ZF(zero flag)

비트를 1로 설정합니다.

 

예제로 보면...

 

mov rax, 1

cmp rax, byte 1

je _someLabel

 

rax는 1이고 byte 1과 비교합니다.

비교한다는 것은 값을 빼서

0이 되는지 확인한다는 말입니다.

 

0 0000 0001 ---  1

0 1111 1111 --- -1 (2의 보수)

--------------------

1 0000 0000 (자리 올림한 것은 사라짐)

8비트로 간략하게 생략했으나 결론은

두 값의 뺄셈이 0이 된다. 즉 ZERO다.

ZERO flag를 1로 바꾼다. JE는 Equal ->

CMP 결과값이 0이고 ZF가 1이 되면

JUMP 한다는 말입니다. 말이 엄청 꼬이는데

레지스터를 만든 사람이 그렇게 만들어놨습니다.

 

C언어로는 이 정도가 될 것 같습니다.

if(rax == 1) goto _someLabel;

 

조건 점프는 아래와 같습니다.

jump 어셈블리어 NASM

여기다가 플래그에 따라 점프도 있는데

우선은 조건 점프를 먼저 익히도록 합니다.

 

뭐가 많은 것 같은데 다음과 같은 코드로

여러 조건을 만들어 몇번 테스트 해보면 

적응이 수월할 것 입니다.

 

%include "myInc.inc"

section .data
    text0 db "[-- Control-- ]", 10, 0
    text1 db "Label-1", 10, 0
    text2 db "Label-2", 10, 0
    text3 db "Label-3", 10, 0
    text4 db "Label-4", 10, 0
    text5 db "Label-5", 10, 0

    var1 dq 5 ;이것을 조작해서 여러 조건을 만들어 테스트
    var2 dq 5

section .bss
    ;no uninitialized data

section .text
    global _start

_start:
    nop ;just placeholder
    print text0
    ; mov rax, 25
    ; cmp rax, byte 20
    ; jbe _label3
    mov rax, qword [var1]
    cmp rax, qword [var2]
    je _label4
    mov qword [var2], rax ;jne 일때 실행
    nop
_label1:
    print text1
_label2:
    print text2
_label3:
    print text3
_label4:
    print text4
_label5:
    print text5

_last:
    ;terminate the program
    exitProgram

 

myInc.inc는 그냥 서브루틴과 매크로입니다.

%macro print 1
    mov rdi, %1
    call _strlen
    call _printString
%endmacro

%macro exitProgram 0
    mov rax, 60
    mov rdi, 0
    syscall
%endmacro

;**************************************
;separate _strlen and _printString
_strlen:
    push rdi ;push rdi
    xor rcx, rcx

_str_next:
    cmp [rdi], byte 0
    jz  _str_null

    inc rcx
    inc rdi
    jmp _str_next

_str_null:
    pop rdi ;pop rdi (rdi recovered)
    ret

_printString:
    mov rsi, rdi
    mov rdx, rcx
    mov rax, 1
    mov rdi, 1 ;stdout
    syscall
    ret

 

C언어 처럼 처음부터 복잡한 조건문을

만들기는 좀처럼 쉽지가 않습니다.

사용법이 좀 익숙해지면 자신만의 코드를

만들어 봅니다. goto문의 시대로 다시

돌아가는 느낌이 들지도 모르겠네요.

 

현대에는 goto문을 무조건 금기시 하는데

왜 그래야하는지는 잘 안가르쳐 줍니다.

어셈블리어에서는 왜 현대에 goto문을

안쓰는지 알 수 있습니다. 기본적으로는

이것들이 모두 goto문과 같습니다.

goto문을 많이 사용할 수록 디버깅이 힘들어집니다.

 

어셈블리어에서는 어떤 명령어를 사용해서

분기를 컨트롤 할 것 인가 염두할 필요가 있습니다.

 

tutorials/Assembly/Nasm/jump at main · neokayken/tutorials

 

GitHub - neokayken/tutorials: programming tutorial for beginner

programming tutorial for beginner. Contribute to neokayken/tutorials development by creating an account on GitHub.

github.com

 

공유하기

facebook twitter kakaoTalk kakaostory naver band