c0mpos3r

Subroutines 본문

Develop/Assembly

Subroutines

음대생 2024. 7. 4. 14:31

서브루틴은 함수이다.

프로그램에서 반복 가능한 다양한 작업을 수행하기 위해 호출할 수 있는 재사용 가능한 코드 조각이다.

 

서브루틴은 이전에 사용한 것과 같은 레이블(예: start:)을 사용하여 선언되지만, 서브루틴에 도달하기 위해 JMP 명령어를 사용하지 않고 대신 새로운 명령어를 CALL을 사용한다. 또한 함수를 실행한 후 프로그램으로 돌아갈 때도 JMP 명령어를 사용하지 않는다. 서브루틴에서 프로그램으로 돌아가려면 RET 명령을 사용한다.

 

왜 서브루틴에 JMP를 사용하지 않을까?

서브루틴 작성의 가장 큰 장점은 재사용이 가능하다는 점이다. 코드의 어느 곳에서나 서브루틴을 사용하려면 코드의 어느 부분에서 점프했는지, 어디로 다시 점프해야 하는지 판단하기 위한 로직을 작성해야 한다. 이렇게 하면 코드가 원치 않는 레이블로 가득 차게 된다.

 

하지만 CALL과 RET을 사용하면 어셈블리에서 스택이라는 것을 사용하여 이 문제를 처리한다.

 

스택

스택은 특별한 유형의 메모리이다. 이전에 사용했던 것과 동일한 유형의 메모리이지만 프로그램에서 사용하는 방식이 특별하다.

 

스택은 LIFO(Last In First Out) 메모리라고 한다. 스택을 부엌에 있는 접시 더미라고 생각하면 된다. 스택에 마지막으로 올려놓은 접시는 다음에 접시를 사용할 때 스택에서 가장 먼저 꺼낼 접시이다.

 

하지만 어셈블리의 스택은 접시를 저장하는 것이 아닌 값을 저장하는 것이다. 스택에는 변수, 주소 또는 기타 프로그램과 같은 많은 것들을 저장할 수 있다. 나중에 복원할 값을 임시로 저장하기 위해 서브루틴을 호출할 때 스택을 사용해야 한다.

 

함수가 사용해야 하는 모든 레지스터는 PUSH 명령을 사용해 안전하게 보관할 수 있도록 현재 값을 스택에 저장해야 한다. 그런 다음 로직을 완료한 후 이러한 레지스터는 POP 명령어를 사용해 원래 값을 복원할 수 있다. 즉, 함수를 호출하기 전과 후에 레지스터의 모든 값이 동일하게 유지된다. 서브루틴에서 이 부분을 처리하면 레지스터에 어떤 변화가 생기는지 걱정하지 않고 함수를 호출할 수 있다.

 

CALL과 RET 명령도 스택을 사용한다. 서브루틴을 호출하면 프로그램에서 호출한 주소가 스택으로 푸시된다. 그런 다음 이 주소는 RET에 의해 스택에서 튀어나오고 프로그램은 코드의 해당 위치로 다시 점프한다. 그렇게 때문에 레이블에는 항상 JMP를 사용하되 함수에는 CALL을 사용해야 한다.

 

helloworld-len.asm

SECTION  .data
msg      db     'Hello, brave new world!', 0Ah

SECTION  .text
global   _start

_start:

     mov     eax, msg              ; 메시지 문자열의 주소를 EAX로 이동한다.
     call    strlen                ; 함수를 호출하여 문자열의 길이를 계산한다.
     
     mov     edx, eax              ; 함수는 결과를 EAX로 남긴다.
     mov     ecx, msg              ; 이전과 동일합니다.
     mov     ebx, 1
     mov     eax, 4
     int     80h
     
strlen:                            ; 이것이 우리의 첫 번째 함수 선언이다.
     push     ebx                  ; 이 함수에서 EBX를 사용하는 동안 스택에 값을 푸시하여 보존한다. 
     mov      ebx, eax             ; EAX의 주소를 EBX로 이동한다(둘 다 메모리에서 동일한 세그먼트를 가리킴)
                                   
nextchar:                          ; 
    cmp       byte [eax], 0           
    jz        finished
    inc       eax
    jmp       nextchar
    
finished:
    sub       eax, ebx
    pop       ebx                    ; 스택의 값을 EBX로 다시 팝한다.
    ret                              ; 함수가 호출된 위치로 돌아간다.

 

Result

~$ nasm -f elf helloworld-len.asm
~$ ld -m elf_i386 helloworld-len.o -o helloworld-len
~$ ./helloworld-len
Hello, brave new world!

 

이 글은 https://asmtutor.com/#lesson4의 자료를 참고하여 작성되었습니다.

이 글은 상업적 목적이 아닌 개인이 공부한 내용을 정리하기 위한 글입니다. 

'Develop > Assembly' 카테고리의 다른 글

NULL terminating bytes  (0) 2024.07.04
External include files  (0) 2024.07.04
Calculate string length  (0) 2024.07.04
Proper program exit  (0) 2024.07.04
Hello, world!  (0) 2024.07.04