Subprogram-2

calling conventions(호출 규약)
호출하는 코드와 서브프로그램(callee)는 서로 같은 데이터 전송 방식을 써야한다.
고급 언어에서는 호출 규약(calling conventions)라는 기본적인 데이터 전송 방법이 존재한다.

고급언어와 어셈블리가 함께 작업하기 위해서는 어셈블리 코드들도 반드시
고급언어에서의 규약과 일치해야 한다.
스택에 인자들을 전달하기
서브프로그램으로 스택을 통해 인자들을 전달한다.
CALL 명령을 하기 전 스택에 미리 인자들을 푸시(push)되어 진다.
만일 인자의 크기가 더블워드보다 작다면, 반드시 푸시전 더블워드로 변환되어야 한다.

스택에 저장된 인자들이 스택에서 팝(pop)하는 것은 불가능하다.
그대신에 스택 자체에는 접근이 가능하다.

이는 서브프로그램 어디서든 인자에 접근 할 수 있게 하기 위해서이고,
CALL 명령 이전 스택에 푸시해둔(top에 위치) 리턴 주소를 잃지 않기 위해서 이다.
    EBP
서브프로그램에서 스택을 추가로 이용하기 때문에 ESP만 이용할 경우 인자에 접근시 오류를 낼 확률이 크다.
따라서 80386에서는 EBP라는 또 다른 레지스터를 사용 가능하게 하였다.

C호출 규약에서는 반드시 서브프로그램이 먼저 EBP의 값을 스택에 저장하고 EBP와 ESP를 같게 만든다.
이를 통해 EBP의 값을 변경하지 않더라도 스택에 데이터가 푸시되고 팝 됨에 따라 ESP가 변경될 수 있게 한다.
subprogram_label:
push ebp
mov ebp, esp
;
;subprogram code
;
pop ebp
ret
C 호출 규약에서는 스택에 푸시되었던 인자들이 호출자의 코드에서 제거하더록 명시되어 있다.(이는 언어마다 다름)
파스칼의 호출 규약에서는 서브프로그램이 이를 제거하라고 명시되어 있다.(pascal 명령어 사용)

C 언어에서 이와 같은 규약을 지원하지 않는 이유는  C 언어가 가변 개수의 인자를 가짐을 지원하기 때문이다.(printf, scanf)
이러한 형식의 함수들은 스택에서 인자들을 지우는 명령들의 횟수가 달라진다.
즉, 스택에서부터 인자들을 제거하는 명령이 함수의 호출마다 달라지게 된다.
push dword 1 // 1
call fun
add esp,4 //
위 코드는 C 호출 규약을 이용하여 서브프로그램을 호출하는 소스이다.
3행의 add를 통해 인자를 제거하였다. pop을 사용하여 이와 같은 명령을 할 수 있지만,
레지스터에 값을 저장해야 하기 때문에 add를 사용하면 더 빠르다.
sub3.asm
스택은 지역변수들의 편리한 저장 창고이다.(C에서 보통의 변수_automatic을 저장하는 곳)
이는 재진입 서브프로그램을 만드는데 유용하다.
void clac_sum(int n, int *sump){
int i,sum=0;
for(i=1;i<=n;i++){
sum+=i;
*sump=sum;
}
}
위와 같은 C코드를 아래의 어셈블리 코드로 만들 수 있다.
cal_sum:
push ebp
mov ebp,esp
sub esp,4 ; sum
mov dword [ebp-4],0 ;sum=0
mov ebx,1 ;ebx(i)=1
for_loop:
cmp ebx,[ebp+8] ;i<=n?
jnle end_for
add [ebp-4],ebx ;sum+=i
inc ebx
jmp short for_loop
end_for:
mov ebx,[ebp+12] ;ebx=sump
mov eax,[ebp-4] ;eax=sum
mov [ebx],eax ;*sump=sum
mov esp,ebp
pop ebp
ret
ENTER & LEAVE
ENTER 와 LEAVE 명령어는 프로그램의 시작과 끝에 스택프레임(stack frame)을 관리해준다.
ENTER는 시작부분의 명령을 처리하고, LEAVE 명령은 마지막 부분의 명령을 처리한다.
ENTER명령은 두개의 즉시 피연산자를 가진다. (C호출규약에서는 두번째 피연산자는 언제나 0이다.)
첫번째 인자는 지역변수가 필요로 하는 바이트의 크기를 나타낸다.
LEAVE명령은 피연산자를 가지지 않는다.

(ENTER와 LEAVE 명령들이 서브프로그램의 시작과 끝을 간단하게 해주지만 잘쓰이지 않는다.
왜냐하면 동일한 간단한 명령들의 모임보다 더 느리기 때문이다.)
subprogram_label:
enter LOCAL_BYTES,0
;
;subprogram code
;
leave
ret
multi-module program(다중 모듈 프로그램)
한 개보다 많은 수의 목적파일(object)들로 구성된 프로그램을 말한다.
extern
extern을 사용하여 외부 모듈에서 global로 정의된 라벨들을 사용할 수 있다.(C의 extern과 명령이 다름)
extern get_int,print_sum
global
global get_int,print_sum
global은 전역 코드 라벨뿐만 아니라 전역 변수에도 사용할 수 있다.
C의 extern과 비슷함.