업무일지 입니다.
오늘 어셈블리 수업내용은 좀 헷갈리는 부분이 있어
그림을 첨부합니다. (발로 그렸음)
그림이 다소 애매모호 하고 틀린부분이 있을수 있으니,
나머지는 여러분의 상상력에 맏기도록 하겠습니다. (just imagine!!)
*어셈블리 함수 모양
.386 ;16비트 호환가능 표시
.MODEL FLAT ;
PUBLIC _Emb ; 외부에서 함수에 접근이 가능하도록
.CODE ; 여기서 부터 시작
_Emb PROC NEAR32 ;함수의 시작
mov eax, 1234
ret ;리턴
_Emb ENDP ;함수의 끝
END ;프로그램 끝 (.CODE와 한쌍)
위와 같이 함수를 만들고
C프로그램에서 함수를 호출하도록 한다.
#include <stdio.h>
int Emb();
int main()
{
int iNum;
iNum = Emb();
printf("return value :: %d\n");
return 0;
}
함수에서 리턴값으로 1234를 넣었고,
우리가 만든 프로그램은 리턴값을 변수에 저장 하고, 이를 화면에 출력한다.
* 어셈블리는 인자를 인식하지 않아!
위의 c코드에서 Emb하수 선언시에 인자를 넣고,
호출시에도 인자를 넣었다.
어셈블리 코드에 아무것도 수정하지 않았지만 오류가 나지 않았다.
* 인자를 활용해 보자
#include <stdio.h>
int Emb(int
,
int
);
int main()
{
int iNum;
iNum = Emb(3, 4);
printf("return value :: %d\n", iNum);
return 0;
}
이번에는 Emb함수에 정수 2개를 인자로 실어서 보내보기로 한다.
우리가 원하는 값은 인자 둘이 더해진 값이 나오는 것이다.
.386
.MODEL FLAT
PUBLIC _Emb
.CODE
_Emb PROC NEAR32
push ebp ;base pointer 값을 스택에 밀어 넣는다. Entry Code
mov ebp, esp ;esp와 ebp를 같은 위치에 자리시킨다. Entry Code
;sub esp, 8
;mov [ebp - 4], 50
;mov [ebp - 8], 25 ;변수를 쓸 경우 필요한 코드이다.
mov eax, [ebp + 8] ;첫번째 인자 땡겨옴 eax = 3
add eax, [ebp + 12] ;두번째 인자 더함 eax = eax + 4
mov esp, ebp ;Exit Code
pop ebp ;Exit Code
ret ;Exit Code
_Emb ENDP
END
인자가 위치한곳을 Proc의 ebp를 기준으로 잡아준다.
(어셈블리는 주소연산없고 4바이트 단위임)
인자의 위치는 함수호출 규약에 따른다. (stdcall, cdecl ....)
어셈블리 코드에서 함수를 만들 때, entry code 2줄과 exit code 3줄이 필요하다.
프록시저에서 스택을 새로 만들기 위해 ebp와 esp를
재설정 해줘야 하는데, 이 레지스터들은 하나만 존재한다.
하지만 함수가 끝나면 원래의 값 (즉, main :: stack의 앞뒤)으로 돌아가야 한다.
그래서 ebp값을 스택에 백업해야 하는 과정에서 생겨나는 코드이다.
entry code는 ebp 값을 push한 후에 ebp값의 재설정
exit code는 esp값을 재설정 한 후에 ebp값 pop 그리고 return까지
즉, 레지스터를 함수 시작전의 값으로 되돌리는 과정이다.
* 함수호출시 약속
함수호출 전후로 레지스터값이 변하면 안된다.
(단, eax는 변해도 상관이 없다)
그래서 eax를 제외한 나머지 레지스터를 사용해야 할 경우
push를 이용하여 stack에 적재하고 난뒤 (백업) 사용하고,
그 값을 pop을 이용해서 값을 복원한다.
.386
.MODEL FLAT
PUBLIC _Emb
.CODE
_Emb PROC NEAR32
push ebp ;Entry Code
mov ebp, esp ;Entry Code
push ebx
push ecx ;사용할 레지스터 값을 push한다.
mov ebx, [ebp + 8]
mov ecx, [ebp + 12]
mov eax, [ebp + 16]
add ebx, ecx
add eax, ebx
pop ecx
pop ebx ;사용한 레지스터를 pop한다.
mov esp, ebp ;Exit Code
pop ebp ;Exit Code
ret ;Exit Code
_Emb ENDP
END
* 어셈블리 코드에서 포인터를 사용해보자
Emb(3, &iNum);
.386
.MODEL FLAT
PUBLIC _Emb
.CODE
_Emb PROC NEAR32
push ebp ;Entry Code
mov ebp, esp ;Entry Code
push ebx ;ebx쓸꺼니까 백업해둔다
mov eax, [ebp + 8]
inc eax
mov ebx, [ebp + 12] ;iNum의 주소를 레지스터로 이동
mov [ebx], eax ;포인터 사용이다.
pop ebx ;ebx를 불러낸다
mov eax, 0 ;안전할수 있다.
mov esp, ebp ;Exit Code
pop ebp ;Exit Code
ret ;Exit Code
_Emb ENDP
END
역시나 인자는 ebp를 기준으로 컨트롤한다
ebx에 iNum의 주소를 넣고, 포인터를 이용한다.
C에서는 *를 이용하지만, 어셈블리에서는 []를 이용한다.
* 어셈블리로 더블 포인터
.386
.MODEL FLAT
PUBLIC _Emb
.CODE
_Emb PROC NEAR32
push ebp ;Entry Code
mov ebp, esp ;Entry Code
push ebx ;ebx쓸꺼니까 백업해둔다
mov eax, [ebp + 8]
dec eax
mov ebx, [ebp + 12] ;ebx -> p
mov ebx, [ebx] ;p -> iNum (더블 포인터 처리)
mov [ebx], eax ;iNum = 2
pop ebx ;ebx를 불러낸다
mov eax, 0 ;안전할수 있다.
mov esp, ebp ;Exit Code
pop ebp ;Exit Code
ret ;Exit Code
_Emb ENDP
END
특별한 점은 없다.
C언어에서 처럼 더블포인터 써주면 된다.
mov ebx, [ebx]
가 좀 신기하긴 했음.
* 어셈블리 코드에서 구조체 컨트롤
Emb(&st); //st는 구조체이다.
.386
.MODEL FLAT
PUBLIC _Emb
.CODE
_Emb PROC NEAR32
push ebp ;Entry Code
mov ebp, esp ;Entry Code
push eax
push ebx
mov eax, [ebp + 8] ;eax가 구조체의 처음을 가르킨다.
mov ebx, [esp + 4] ;ebx에 esp + 4(old eax)값을 대입
mov [eax], ebx ;구조체의 처음에 old eax 넣음
mov ebx, [esp] ;ebx값이 변해서 esp(old ebx)값 복구
mov [eax + 4], ebx ;구조체에서 4만큼 떨어진곳에 ebx 대입
mov [eax + 8], ecx ;구조체에서 8만큼 떨어진곳에 ecx 대입
mov [eax + 12], edx ;구조체에서 8만큼 떨어진곳에 ecx 대입
mov eax, 0 ;안전할수 있다.
pop ebx
pop eax
mov esp, ebp ;Exit Code
pop ebp ;Exit Code
ret ;Exit Code
_Emb ENDP ;ENDP 함수의 끝 }
END ;.code END가 한쌍
(그림그리다가 표현의 한계점에...........)
우선 구조체를 컨트롤하기 위해서는 최소 2개의 레지스터가 필요하기 때문에
eax, ebx를 푸쉬합니다.
다음 eax가 구조체 st를 가리키게 합니다.
mov eax, [ebp + 8]
이제 eax값을 st.eax에 넣어야 하는데 우리가 필요한 값은 old eax이기 때문에
[esp + 8]값을 [eax]에 넣어야 합니다.
그런데 memory to memory가 불가능 하기 때문에
일단 ebx에 [esp + 8]값을 저장한 다음 [eax]에 ebp값을 넣어야 합니다.
mov ebx, [esp + 4]
mov [eax], ebx
이제 ebx값을 st.ebx에 넣어야 하는데 ebx는 앞에서 사용했고,
우리가 필요한 값은 old ebx가 됩니다.
그래서 ebx의 값을 복구 시키고 [eax + 4]의 자리에 넣어줘야 합니다.
mov ebx, [esp]
mov [eax + 4], ebx
이제는 ecx와 edx값을 구조체에 넣어줘야 하는데
ecx와 edx는 건드린적이 없고 memory to memory가 아니기 때문에
그냥 넣어주면 됩니다.
mov [eax + 8], ecx
mov [eax + 12], edx
'코스웨어 > 12년 내장형하드웨어' 카테고리의 다른 글
터보C 2.0 함수 목록 (가나다 순) (0) | 2012.09.06 |
---|---|
어셈블리 소스입니다. (3) | 2012.09.06 |
20120906-Project.zip (0) | 2012.09.06 |
터보씨 시절 사용되던 함수들 모음. (4) | 2012.09.06 |
[Assembly] 9월 3일 업무일지 By.정철 (3) | 2012.09.03 |
assembly 나눗셈 (8) | 2012.09.03 |
cl 12.00 버전 안되는 분들 by.정철 (3) | 2012.08.31 |
[터보 C]2012/08/30 작업일지(터보 C 설치하는 법) - by 이창현 (3) | 2012.08.30 |