chapter 05 프로시저

71
Chapter 05 프프프프 팀팀 : 팀팀팀 / 팀팀 : 팀팀팀 , 팀팀팀 , 팀팀팀 , 팀팀팀 팀팀팀 : 2013 팀 4팀 18 팀

Upload: parson

Post on 21-Jan-2016

41 views

Category:

Documents


4 download

DESCRIPTION

발표일 : 2013 년 4 월 18 일. Chapter 05 프로시저. 팀장 : 박태영 / 팀원 : 조정민 , 이지영 , 이숭운 , 권승현. 박태영. 팀원 구성현황. 조정민. 5.1 간단한 소개. 이 장은 입출력 과 문자열 처리와 관련된 일을 간단하게 사용할 수 있는 편리한 라이브러리를 소개하는 장이다 . 이 장은 서브루틴을 호출하여 프로그램을 어떻게 처리하기 쉬운 단위로 나누는가와 - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: Chapter 05  프로시저

Chapter 05 프로시저

팀장 : 박태영 / 팀원 : 조정민 , 이지영 , 이숭운 , 권승현

발표일 : 2013 년 4 월 18 일

Page 2: Chapter 05  프로시저

팀원 구성현황

박태영

구 분 성 명 핸 드 폰 이메일 비 고

팀 장 박태영 010-6250-5242 [email protected]

5.4

팀 원 조정민 010-3648-8055 [email protected] 5.1,5.2

이지영 010-9596-4948 [email protected]

5.3

이숭운 010-8831-7520 [email protected] 5.5

권승현 010-9580-8639 [email protected] 5.6

Page 3: Chapter 05  프로시저

5.1 간단한 소개

이 장은 입출력과 문자열 처리와 관련된 일을 간단하게 사용할 수 있는 편리한 라이브러리를 소개하는 장이다 .

이 장은 서브루틴을 호출하여 프로그램을 어떻게 처리하기 쉬운 단위로 나누는가와

프로그래밍 언어는 서브루틴 호출을 추적하기 위해서 실행 시간 스택을 어떻게 사용하는가에 대한 것도 알아볼 것이다 .

5.3 절에서 Irvine32.lib 와 Irvine16.lib 라는 이름의 링크 라이브러리로부터 프로시저를 어떻게 호출하는지를 보여준다 .

조정민

Page 4: Chapter 05  프로시저

메인 루틴에 대응되는 단어로 , 프로그램 중의 하나 이상의 장소에서 필요할 때마다 반복해서 사용할 수 있는 부분적 프로그램으로 , 그 자체가 독립해서 사용되는 일 없이 메인 루틴과 결부 시킴으로써 그 기능을 완수한다

서브루틴 본체를 프로그램 중의 한 장소에만 실행시에 호출하는방법을 폐쇄 서브루틴이라고 한다 .

서브루틴의 본체를 프로그램 중의 필요한 개소에 직접 전개하는 방식을 개방 서브루틴이라고 한다 .

서브루틴 ( 프로시저 ) 이란 ?조정민

Page 5: Chapter 05  프로시저

5.2 외부 라이브러리 링크

링크라이브러리기계어 코드로 어셈블된 프로시저를 포함하고 있는 파일하나 이상의 소스 파일로 시작하며소스 파일은 오브젝트 파일로 어셈블된다 .오브젝트 파일은 링커 유틸리티가 인식하는 특별한 형식의

파일에 삽입된다 .

조정민

Page 6: Chapter 05  프로시저

5.2.1 배경 정보

링크 라이브러리는 기계어 코드로 어셈블된 프로시저를 포함하고 있는 파일이다 . 다시 말해 링크 라이브러리 안에 있는 프로시저들은 메크로 비슷한 것이라고 보면 된다 .

WriteString 프로시저를 호출하여 콘솔 윈도우에 문자열을 출력한다고 하자 , 프로그램 소스는 WriteString 을 식별하는 PROTO 디렉티브를 포함해야 한다 .

조정민

smu
PROTO 디렉티브 는 프로시저의 프로토 타입을 선언하는것 이라고 보면 된다.(C에서 함수를 미리 정의하는것과 동일)
Page 7: Chapter 05  프로시저

WriteString PROTOCall WriteString

문자열을 출력하는 프로시저

프로그램이 어셈블될 때 어셈블러는 CALL 명령어의 목표 주소를 빈칸으로 두며 , 이것은 링커에 의해 채워진다 .

링커는 링크 라이브러리에서 WriteString 을 찾아서 적절한 기계어 명령어들을 링크 라이브러리로부터 프로그램 실행파일로 복사한다 .

만약 호출한 프로시저가 ( 위의 WriteString) 링크 라이브러리에 없다면 링커는 오류 메시지를 내놓고 실행파일을 만들지 않는다 .

Call 명령어는 WriteString 을 실행한다 .

조정민

Page 8: Chapter 05  프로시저

Link hello. obj irvine32.lib kernel32.lib

링커 명령 옵션링커 유틸리티는 프로그램의 오브젝트 파일들을 하나 이상의 다른

오브젝트 파일과 링크 라이브러리와 합친다 . 예를 들어 다음 명령은 hello.obj 파일을 irvine32.lib 와 kernel32.lib 에 링크한다 .

조정민

링크시키는 link 명령어

Hello 라는 이름의 오브젝트 파일을

Irvine32 라이브러리와

Kernel32 라이브러리링크

Page 9: Chapter 05  프로시저

32 비트 프로그램 링크마이크로소프트 Windows 플랫폼 소프트웨어 개발 키트의 일부인

kernel.lib 파일은 kernel32.dll 이라는 파일에 있는 시스템 함수에 대한 링크 정보를 포함한다 . Kernel32.dil 은 MS-Windows 의

기본이 되는 부분이며 동적 링크 라이브러리 라고 한다 . 이 파일은 문자 기반 입출력을 수행하는 실행 함수를 포함한다 .

조정민

내 프로그램 Irvine32.lib

kernel32.lib

kernel32.dll

자동으로 링크

Link 명령어로 링크 가능

자동으로

링크

실행

Page 10: Chapter 05  프로시저

Irvine32.lib 와 Irvine16.lib 의 역할

Irvine32.lib 는 입출력할 때에 MS-Windows API 와 링크하는 피로시저를 포함한다 .(32 비트 보호모드에서 작성되는 프로그램을 위한 것 ) Irvine16.lib 는 입출력할 때에 MS-DOS 인터럽트를 수행하는 프로시저를 포함한다 .(16 비트 실제주소 모드로 작성되는 프로그램을 위한 것 )

조정민

Page 11: Chapter 05  프로시저

• 링크 라이브러리 (link library) 는 기계어 코드로 어셈블된 프로시저 ( 서브루틴 ) 를 포함하고 있는 파일이다 .

• 링크 라이브러리는 하나 이상의 소스 파일로 시작하며 , 소스 파일은 오브젝트 파일로 어셈블된다 . 오브젝트 파일은 링커 유틸리티가 인식하는 특별한 형식의 파일에 삽입된다 .

• 프로그램이 WriteString 프로시저를 호출하여 콘솔 윈도우에 문자열을 출력한다고 하자 . 프로그램소스는 WriteString 프로시저를 식별하는 PROTO 디렉티브를 포함해야 한다 .

이지영

5.3 책의 링크 라이브러리

Page 12: Chapter 05  프로시저

• WrtieString PROTO

• 다음에 CALL 명령어는 WriteString 을 수행한다 .

• call WriteString

• 프로그램이 어셈블될 때에 어셈블러는 CALL 명령어의 목표 주소를 빈캄으로 두며 , 이것은 링커에 의해서 채워질 것이다 . 링커는 링크 라이브러리에서 WtringString 을 찾아서 적잘한 기계어 명령어들을 링크 라이브러리로부터 프로그램 실행파일로 복사한다 . 여러분이 호출한 프로시저가 링크 라이브러리에 없다면 링커는 오류 메시시지를 내놓고 실행파일을 만들지 않는다 .

이지영

Page 13: Chapter 05  프로시저

개별 프로시저 설명• ClossFile = (Irvine32 전용 ) 이전에 생성하거나 열었던 파일을

닫음

• 파일은 EAX 로 전달되는 32 비트 정수 핸들로 식별됨 .

• Clrscr = 콘솔 윈도우를 깨끗하게 지움 . 일반적으로 프로그램의 시작과 끝에서 호출 .

• * 먼저 WaitMsg 를 호출하여 프로그램을 멈추게 할 필요가 있다 .

이지영

Page 14: Chapter 05  프로시저

• Crlf = 콘솔 윈도우에서 커서를 다음 줄의 시작으로 가게 함 .

ASCII 문자코드 0Dh 와 0Ah 값으로 구성되는 문자열을 출력 .

• GetMseconds = EAX 레지스터에 자정이후의 경과시간을 msec 단위로 얻음 .

• GetTextColor = 콘솔 윈도우에서 지정된 행과 열에 커서를 위치 . 기본적인 윈도우 X 좌표 : 0~79, Y 좌표 : 0~24

이지영

Page 15: Chapter 05  프로시저

• DumpMem = 일정 범위 위치의 메모리를 콘솔 윈도우에 16진수로 출력 .

메모리의 시작주소 -ESI, 출력단위크기 -EBX, 출력단위개수 -ECX 로 전달 .

• DumpRegs = EAX,EBX,ECX,EDX,ESI,EDI,EBP,ESP,EIP,EFL 레지스터를 16 진수로 출력 .

CF,SF,ZF,OF,AF,PF 플래그의 값도 출력 .

• EIP 의 출력 값은 DumpRegs 에 대한 호출 다음 명령어의 오프셋 . DumpRegs 는 CPU 스냅샷을 출력 .

이지영

Page 16: Chapter 05  프로시저

• MsgBox = (Irvine32 전용 ) 제목을 선택사항으로 갖는 그래픽 팝업 메시지 상자를 표시한다 . 상자 안에 나타낼 문자열의 오프셋을 EDX 에 전달한다 . 선택사항으로 상자의 제목 문자열의 오프셋을 EBX 에 전달한다 .

• 제목을 빈칸으로 두려면 EBX 를 0 으로 설정한다 .

• MsgBoxAsk = (Irvine32 전용 ) Yes 아 No 버턴을 갖는 그래픽 팝업 메시지 상자를 표시한다 . 상자 안에 나타낼 질문 문자열의 오프셋을 EDX 에 전달한다 선택 사항으로 상자의 제목 문자열의 오프셋을 EBX 에 전달한다 .

• 제목을 빈칸으로 두려면 EBX 를 0 으로 설정한다 . MsgBoxAsk 는 EAX 에 사용자가 어떤 버튼을 선택했는지를 알려주는 정수 IDYES(6 과같음 ) 또는 IDNO(7 과 같음 ) 를 반환한다 .

이지영

Page 17: Chapter 05  프로시저

• ParseInteger32 = 부호있는 10 진수 문자열을 32 비트 이진수로 변환한다 . 숫자가 아닌 문자 앞에 있는 모든 유효한 자리 숫자가 변환된다 . 앞에 있는 빈캄은 무시한다 . 문자열의 오프셋을 EDX 에 , 문자열의 길이를 ECX 에 전달한다 . 이진수는 EAX 에 반환된다 .

• Random32 = 32 비트 난수 정수를 생성하고 EAX 에 반환한다 . 이 프로시저가 반복적으로

• 호출될 때에 무작위로 발생하는 난수를 시뮬레이션하는 수열을 생성하며 , 이 수열의 각 수를 의사 난수 정수 (pseudorandom inte-ger) 라고 부른다 . 숫자들은 시드 (seed) 라고 하는 입력을 갖는

• 간단한 함수를 사용하여 생성된다 . 함수는 난수를 생성하는 공식에서 시드를 사용한다 . 다음에이어지는 난수는 이전에 생성된 난수를 시드로 사용하여 생성된다 . 이러한 점 때문에 난수라는 용어는 의사 난수를 의미한다 .

이지영

Page 18: Chapter 05  프로시저

• Randomize = Random32 와 RandomRange 프로시저의 시작 시드값을 초기화한다 .

• 시드는 100 분의 1 초 단위의 시간 값과 같다 . (Randomize) 프로그램이 Random32 와 RandomRange 를 호출할 때마다 생성되는 난수열은 다를 것이고 , 어떠한 나수열도 유일할 것이다 . Randomize 를 프로그램의 시작에서 한 번만 호출할 필요가 있다 .

• RandomRange = 0 부터 n-1 까지의 범위의 난수 정수를 생성한다 . 여기서 n 은 EAX 레지스터에전달되는 입력 매개변수이다 . 난수 정수는 EAX 에 반환된다 . 다음 예는 0 과 4999 사이의 하나의 난수 정수를 생성하여 EAX 에 넣는다 .

이지영

Page 19: Chapter 05  프로시저

• ReadInt = 키보드에서 32 비트 부호있는 정수를 읽어서 값을 EAX 에 반환한다 . 숫자 앞의 + 와 - 기호는 선택사항으로 입력할 수 있으며 숫자의 나머지 자리는 숫자로만 구성될 수 있다 .

• ReadInt 는 Overflow 플래그를 1 로 설정하고 입력된 값이 32비트 부호 있는 정수로 표시될 수 없다면 오류 메시지를 표시한다 . 반환값은 숫자가 아닌 문자를 만날 때까지의 모든 유효 자리로부터 계산된다 .

• ex) +123ABC 를 입력한다면 반환되는 값은 +123 이다 .• ReadString = 키보드에서 문자열을 읽어 들이고 Enter 키를

누를때에 멈춘다 . 버퍼의 오프셋을 EDX 에 전달하고 ECX 를 ( 문자열 종료 널 바이트에 대한 공간을 확보하기 위하여 ) 사용자가 입력할 수 있는 최대 문자수에 1 을 더한 값을 설정한다 . 프로시저는 사용자가 입력한 문자수를 EAX 에 반환한다 .

이지영

Page 20: Chapter 05  프로시저

• SetTextColor = (Irvine32 전용 ) 텍스트 출력에 대한 전경색과 배경색을 설정한다 .

• SetTextColor 를 호출할 때에 색 속성을 AX 에 지정한다 . 다음의 미리 정의된 색상 상수가 전경색과 배경색 모두에 대해서 사용될 수 있다 .

• 색상 상수는 include 파일 Irvine32.inc 와 Irvine16.inc 에서 정의된다 . 배경색에 16 을 곱하고 전경색을 더한다 .

• WaitMsg = "Press any key to continue..." 라는 메시지를 표시하고 사용자가 키를 누르기를 기다린다 .

• 이 프로시저는 데이터가 화면이 스크롤되어 사라지기 전에 화면을 정지시키고자 할 때에 유용하다 . 이 프로시저는 입력 매개변수가 없다 .

이지영

Page 21: Chapter 05  프로시저

• WriteBin = 정수를 ASCII 이진수 형식으로 콘솔 윈도우에 출력한다 . 정수를 EAX 에 전달한다 .

• 이진수 비트는 읽기 쉽도록 4 개씩 묶어서 표시된다 .

• WriteBinB = 32 비트 정수를 ASCII 이진수 형식으로 콘솔 윈도우에 출력한다 . 값을 EAX 레지스터에 전달하고 EBX 는 표시할 크기를 바이트 단위 (1,2,3) 로 지시하게 한다 .

• 비트들을 읽기 쉽도록 4 개씩의 그룹으로 표시된다 .

이지영

Page 22: Chapter 05  프로시저

• WriteChar = 콘솔 윈도우에 하나의 문자를 출력한다 . 문자 ( 또는 문자의 ASCII) 를 AL 에 전달한다 .

• WriteDec 프로시저는 32 비트 부호없는 정수를 앞에 0 이 없는 10 진수 형식으로 콘솔 윈도우에 출력한다음 정수를 EAX 에 전달한다

• WriteHex 프로시저는 32 비트 부호없는 정수를 8 자리 16 진수 형식으로 콘솔 윈도우에 출력한 후 필요하면 앞에 0 들이 삽입된다 . 정수를 EAX 에 전달한다 .

• WriteHexB 프로시저는 32 비트 부호없는 정수를 16 비트 형식으로 콘솔 윈도우에 출력한다 .

• 필요하면 앞에 0 들이 삽입된다 . 정수를 EAX 에 전달하고 EBX 는 표시할 크기를 바이트 단위 (1,2,4) 로 나타내게 한다 .

• WriteInt 프로시저는 32 비트 부호있는 정수를 부호는 포함하고 앞에 0 이 없는 10 진수 형식으로 콘솔 윈도우에 출력한다 . 정수를 EAX 에 전달한다 .

이지영

Page 23: Chapter 05  프로시저

• WriteString 프로시저는 널 종료 문자열을 콘솔 윈도우에 출력한다 . 문자열의 오프셋을 EDX 에 전달한다 .

• WriteToFile = (Irvine 32 전용 ) 프로시저는 버퍼의 내용을 출력 파일에 저장한다 . 유효한 파일 핸들을 EAX 에 , 버퍼의 오프셋을 EDX 에 , 출력할 바이트 수를 ECX 에 전달한다 .

• 프로시저가 반환될 때에 EAX 는 출력된 바이트 수를 포함한다 .

• WriteWindowsMsg = (Irvine32 전용 ) 가장 최근에 생성한 오류의 메시지를 포함하는 문자열을 표시한다 . 여러분의 프로그램이 파일을 생성하거나 열 수 없을 때에 가장 유용한다 .

• 다음 예는 입력을 위해서 파일 열기를 시도하고 , 오류를 발견하면 오류 메시지를 표시하려고 WriteWindowsMsg 를 호출한다 .

이지영

Page 24: Chapter 05  프로시저

5.4 스택 연산

자료 구조의 하나로 , 자료의 삽입과 삭제가 끝에서만 일어나는 선형목록

자료의 삽입 , 삭제가 일어나는 곳을 스택의 톱 (top) 이라고 하며 자료를스택에 넣는 것을 푸시 (push), 스택에서 자료를 꺼내는 것을 팝 (pop) 이라 한다

스택에 마지막으로 넣은 값이 항상 맨 먼저 꺼내는 값이기 때문에스택은 LIFO(Lask-In First-Out) 구조라고도 부른다 .

새로운 접시는 스택의 맨 위에 추가할 수 있지만 , 스택의 바닥이나 ,중간에 추가할 수는 없음

박태영

Page 25: Chapter 05  프로시저

다음 그림과 같이 10 개의 숫자를 쌓아 놓을 때에 만들어진 것을 스택(stack) 이라고 말할 수 있다 .

스택에 마지막으로 넣은 값이 항상 맨 먼저 꺼내는 값이기 때문에 스택은 LIFO(Last-In First-Out) 구조라고도 부른다 .

박태영

1098765

1

4

23

TOP

bottom

새로운 값은 스택의 맨 위에 추가되고 스택의 기존 값은

맨 위부터 제거됨

Page 26: Chapter 05  프로시저

5.4.1 실행시간 스택

실행시간 스택 : 스택 포인터 레지스터라고 하는 ESP 레지스터를 사용하여 CPU 가 직접 관리하는 메모리 배열

ESP(extended destination index): 직접 조작하는 일은 거의 없으며 CALL,RET,PUSH,POP 과 같은 명령어를 사용하여 간접적으로 수정함

스택에 있는 어떤 위치에 대한 32 비트

오프셋을 저장함ESP 는 항상 스택에서 푸쉬 된

마지막 정수를 가리킨다 .

Page 27: Chapter 05  프로시저

* 단일 값을 포함하는 스택

ESP = 00001000h

박태영

00000006

Offset

00000FF4

00000FF0

00000FF8

00000FFC

000001000

이것은 프로그램이 32 비트 모드에서 수행되고 있는 경우임

16 비트 실제 주소 모드에서 SP(Stack Point) 레지스터가 가장 최근에 푸쉬된 값을 가리키며 스택 엔트리들은 대개 16 비트 길이임

각 스택의 위치는 32 비트를 저장함

Page 28: Chapter 05  프로시저

5.4.2 Push 연산박태영

00000006

BEFORE

00000FF4

00000FF0

00000FF8

00000FFC

000001000

AFTER

00000006

000000A5

000001000

00000FFC

00000FFC

00000FF4

00000FF0

ESP

ESP-4

32 비트 push 연산은 스택 포인터를 4 씩 감소시키고 값을 스택 포인터가 가리키는 스택 위치로 복사함

그림 1

그림 2

Page 29: Chapter 05  프로시저

5.4.2 Pop 연산박태영

00000006

000000A5

00000001

00000002

BEFORE

00000FF4

00000FF0

00000FF8

00000FFC

000001000

AFTER

00000006

000000A5

00000001

000001000

00000FFC

00000FFC

00000FF4

00000FF0

ESP

ESP

Pop 연산은 스택에서 팝된 후에 스택 포인터는 스택의 그 다음 높은 주소를 가리키도록 증가된다

ESP 아래의 스택 영역은 논리적으로 빈 상태 (logically empty)이며현재의 프로그램이 스택에 값을 푸쉬하는 명령어를 수행할 때 덮어 쓰임

00000002+4

Page 30: Chapter 05  프로시저

스택 응용• 프로그램에서 실행시간 스택의 몇 가지 중요한 용도는 다음과 같다

1. 스택은 레지스터가 한 가지 이상의 목적으로 사용될 때에 레지스터를 위한 간편한 임시 저장 영역으로 사용된다 . 레지스터가 수정된 뒤에 원래의 값으로 복원될 수 있다 .

2. CALL 명령어를 수행할 때에 CPU 는 현재 서브루틴의 복귀 주소를 스택에 저장한다 .

3. 서브루틴을 호출할 때에 인수 (argument) 라고 하는 입력 값을 스택에 푸쉬하여 전달한다 .

4. 스택은 서브루틴 내의 지역 변수를 위한 임시 저장 공간을 제공한다 .

박태영

Page 31: Chapter 05  프로시저

5.4.2 PUSH 와 POP 명령어

PUSH 명령어는 먼저 ESP 를 감소시키고 다음에 소스 피연산자를 스택에 복사한다 .

16 비트 피연산자는 ESP 를 2 씩 감소시킨다 .

32 비트 피연산자는 ESP 를 4 씩 감소시킨다 .

세개의 명령어 형식이 있다

PUSH reg/mem16

PUSH reg/mem32

PUSH imm32

PUSH 명령어

명령어 피연산자 표기법 p111 참조

박태영

Page 32: Chapter 05  프로시저

POP 명령어는 먼저 ESP 가 가리키는 스택 원소의 내용을 16비트 또는 32 비트 목적지 피연산자로 복사하고 다음에 ESP 를 증가시킨다 .

피연산자가 16 비트이면 ESP 는 2 씩 증가되며 32비트이면 ESP 는 4 씩 증가된다 .

POP reg/mem16

POP reg/mem32

POP 명령어

박태영

Page 33: Chapter 05  프로시저

• (PUSH Flags Double) (POP Flags Double) PUSHFD 명령어는 32 비트 EFLAGS 레지스터를

스택에 푸쉬한다

POPDF 명령어는 스택을 EFLAGS 로 팝 한다

32 비트 피연산자는 ESP 를 4 씩 감소시킨다

PUSHFD 와 POPFD 명령어

16 비트 프로그램은 16 비트 FLAGS 레지스터를 스택에 푸쉬하기 위해서 PUSHF 명령어를 사용하고FLAGS 로 팝 하기 위해서 POPF 를 사용한다 .

박태영

Page 34: Chapter 05  프로시저

PUSHAD, PUSHA, POPAD, POPA 명령어 PUSHAD 명령어는 모든 32 비트 범용 레지스터를 EAX,

ECX, EDX, EBX,ESP (PUSHAD 를 실행하기 이전 값 ), EBP,ESI,EDI 의 순서로 푸쉬한다

80286 에서 도입된 PUSHA 명령어는 16 비트 범용 레지스터들 (AX,CX,DX,BX,SP,BP,SI,DI) 을 나열된 순서대로 스택에 푸쉬 한다

POPAD 명령어는 같은 레지스터들을 반대 순서로 스택에서 팝 한다

POPA 명령어는 같은 레지스터들을 반대 순서로 팝 한다

인텔 80286 은 1982 년에 개발된 16 비트 개인용 컴퓨터 마이크로프로세서이다 .

(PUSH All Double) (POP All Double)

박태영

Page 35: Chapter 05  프로시저

5.5 프로시저의 정의와 사용

고급언어를 이미 배웠다면 프로그램을 서브루틴으로 나누는 것이 얼마나 유용한지 알 것이다 .

어셈블리 언어에서는 일반적으로 서브루틴의 의미로 프로시저라는 용어를 사용한다 .

어셈블리 언어는 객체지향 프로그래밍보다 오래 전에 만들어져서 객체지향 언어에서 볼 수 있는 형식 구조로 되어있지 않다 .

이숭운

Page 36: Chapter 05  프로시저

5.5.1 PROC 디렉티브

비공식적으로 프로시저는 이름이 부여된 , return 문으로 끝나는 문장들의 블록으로 정의할 수 있다 .

프로시저는 PROC 와 ENDP 디렉티브를 사용하여 선언된다 . 프로시저는 ( 유효한 식별자인 ) 이름을 부여 받는다 . 우리가 지금까지 작성했던 각 프로그램은 다음 예와 같이 main 이라는 이름의 프로시저를 가지고 있다 .

이숭운

프로시저의 정의

main PROC..main ENDP

Page 37: Chapter 05  프로시저

프로그램의 시작 프로시저가 아닌 다른 프로시저를 만들 때 프로시저는 RET 명령어로 끝난다 . RET 는 CPU 가 프로시저를 호출했던 위치로 되돌아가게 한다 .

시작 프로시저는 (main) 는 exit 문으로 끝나기 때문에 특별한 경우이다 . INCLUDE Irvine32.inc 문을 사용할 때 , exit 는 프로그램을 종료하는 시스템 프로시저인 ExitProcess 를 호출하는 것에 대한 별명이다 .

이숭운

sample PROC . .

retsample ENDP

INVOKE ExitProcess, 0

INCLUDE Irvine16.inc 문을 사용한다면 exit 는 .EXIT 어셈블러 디랙티브로 변환된다 . 이 디렉티브는 어셈블러가 다음의 두 명령어를 만들도록 한다 .

mov ah, 4C0 0h ; call MS - DOS function 4ch int 21h ; terminate program

Page 38: Chapter 05  프로시저

기본적으로 레이블은 선언된 프로시저 내에서만 사용할 수 있다 . 이 규칙은 점프와 루프 명령어에 영향을 준다 . 다음 예에서 Destination 이라는 레이블은 JMP 명령어와 같은 프로시저에 있어야 한다 .

이중 콜론 (::) 으로 표시하는 레이블을 선언하여 이 제한을 벗어나는 것이 가능하다 .

이숭운

프로시저의 레이블

jmp Destination

Destination ::

Page 39: Chapter 05  프로시저

프로시저는 실행시간 스택을 반환하고 조정하는 자동화된 방식을 가지고 있다 .

프로시저 바깥으로 직접 이동한다면 실행시간 스택은 쉽게 훼손될 수 있다 .

예제 : 세 개의 정수의 합세 개의 32 비트 정수의 합을 계산하는 Sumof 라는 프로시저를 만들어 보자 . 관련된 정수는 호출되기 전에 EAX, EBX, ECX 에 저장되어 있다고 가정할 것이다 . 프로시저는 EAX 에 합을 반환한다 .

이숭운

SumOf PROC add eax, ebx add eax, ecx retSumOf ENDP

Page 40: Chapter 05  프로시저

다음은 프로시저의 시작 부분에 넣을 수 있는 정보에 대한 몇 가지 제안이다 .

프로시저가 수행하는 모든 작업에 대한 설명 입력매개변수와 사용법 . Receives 와 같은 단어를 레이블로 사용하며 입력 매개변수의 입력 값에 대한 특정 요구사항이 있으면 여기에 기재하라 . 프로시저가 반환하는 값에 대한 설명 . Returns 과 같은 단어를 레이블로 사용한다 . 프로시저가 호출되기 이전에 충족되어야 하는 전제조건 (precondition) 이라고 하는 특별한 요구사항에 대한 목록 . 이것은 Requires 라는 단어를 레이블로 사용할 수 있다 .

이숭운

프로시저의 문서화

우리가 선택한 Receives, Returns, Requires 와 같은 설명 레이블은 절대적인 것이 아니다 ; 다른 유용한 이름들이 종종 사용된다 .

Page 41: Chapter 05  프로시저

이러한 생각들을 유념하면서 SumOf 프로시저를 적절히 문서화 해보자

이숭운

;----------------------------------------------------------------------------------------------SumOf PROC;; Calculates and returns the sum of three 32-bit integers.; Receives : EAX, EBX, ECX, the three integers. May be; signed or unsigned.; Returns : EAX = sum;---------------------------------------------------------------------------------------------- add eax, ebx add eax, ecx retSumOf ENDP

C 와 C++ 와 같은 고급언어로 작성된 함수는 8 비트 값은 AL 에 ,

16 비트 값은 AX 에 , 그리고 32 비트 값은 EAX 에 반환한다 .

Page 42: Chapter 05  프로시저

5.5.2 CALL 과 RET 명령어

CALL 명령어는 프로세서가 새로운 메모리 위치에서 수행을 시작하도록 지시하여 프로시저를 호출한다 .

프로시저는 RET(return from procedure) 명령어를 사용하여 프로세서가 프로시저를 호출했던 프로그램 위치로 되돌아오게 한다 .

기계적으로 말하면 CALL 명령어는 복귀 주소를 스택에 푸쉬하고 호출되는 프로시저의 주소를 명령어 포인터로 복사한다 .

이숭운

Page 43: Chapter 05  프로시저

프로시저가 반환될 준비가 될 때에 RET 명령어는 복귀 주소를 스택에 명령어 포인터로 팝한다 .

32 비트 모드에서 CPU 는 EIP(instruction) 가 가리키는 메모리에서 명령어를 수행한다 . 16 비트 모드에서는 IP 가 명령어를 가리킨다 .

이숭운

Page 44: Chapter 05  프로시저

main 에서 CALL 명령어가 오프셋 00000020 에 있다고 가정하자 .이 명령어는 일반적으로 5 바이트의 기계어 코드를 필요로 한다 . 그래서 다음 문장 ( 여기서는 MOV) 은 오프셋 00000025 에 위치한다 .

이숭운

호출과 반환 예제

main PROC00000020 call MySub00000025 mov eax, ebx

다음에 MySub 의 첫 번째 명령어가 오프셋 00000040 에 있다고 하자 .

MySub PROC00000040 mov eax, edx . . ret MySub ENDP

Page 45: Chapter 05  프로시저

CALL 명령어가 실행될 때에 ( 그림 5-8) call 의 다음주소 (00000025) 가스택에 푸쉬되고 MySub 의 주소가 EIP 에 적재된다 . MySub 에 있는 모든 명령어는 RET 명령어를 만날 때까지 실행된다 . RET 명령어가 실행될 때에 ESP 가 가리키는 스택 값이 EIP 로 팝된다 . ( 그림 5-9 의 단계 1)단계 2 에서 ESP 는 감소하여 스택의 이전 값을 가리킨다 .( 단계 2)

이숭운

????

00000025 ESP

00000040

EIP

그림 5-8 CALL 명령어 수행

????

00000025 00000025ESP

EIP

step 1:

step 2:

????ESP

그림 5-9 RET 명령어 수행

Page 46: Chapter 05  프로시저

중첩된 프로시저의 호출 (nested procedure call) 은 호출된 프로시저가 처음 프로시저로 변환되기 전에 다른 프로시저를 호출 할 때 일어난다 .

이숭운

중첩된 프로시저의 호출

(ret to main)

(ret to Sub1)

(ret to Sub2) ESP

main PROC..call Sub1exitmain ENDP

Sub1 PROC..call Sub2retSub ENDP

Sub2 PROC..call Sub3retSub2 ENDP

Sub3 PROC..retSub3 ENDP

그림 5-10 중첩된 프로시저의 호출

Page 47: Chapter 05  프로시저

반환된 후에 ESP 는 그 다음 높은 주소의 스택 엔트리를 가리킨다 . Sub2 의 끝의 RET 명령어가 실행되려고 할 때 스택은 다음과 같이 나타난다 .

이숭운

(ret to main)

(ret to Sub1) ESP

마지막으로 Sub1 이 반환될 때에 스택 [ESP] 은 명령어 포인터로 팝되고 프로그램 실행은 main 에서 계속된다 .

(ret to main) ESP

확실히 , 스택은 중첩된 프로시저 호출을 포함하여 , 정보를 기억하는 데유용한 장치임이 입증되었다 . 일반적으로 스택 구조는 프로그램이 특정한 순서로 수행한 단계를 재추적해야 하는 상황에서 사용된다 .

Page 48: Chapter 05  프로시저

정수 배열의 합을 계산하는 것과 같은 표준 연산을 수행하는 프로시저를 작성한다면 프로시저 내에서 특정한 변수를 참조하는 것은 좋지 않다 . 그렇게 한다면 프로시저는 특정한 한의 배열에만 사용 될 수 있다 .

더 좋은 방법은 배열의 오프셋을 프로시저에 전달하고 배열 원소의 명시하는 정수도 전달하는 것이다 . 이것들을 인수 (argument) 또는 입력 매개변수 (input parameter) 라고 한다 .

어셈블리 언어에서는 인수를 범용레지스터로 전달하는 것이 일반적이다 .

이숭운

레지스터 인수의 프로시저 전달

Page 49: Chapter 05  프로시저

이전 절에서 EAX, EBX, ECX 에 있는 정수를 더하는 SumOf 라는 간단한 프로시저를 만들었다 . main 에서 SumOf 를 호출하기 전에 EAX, EBX, ECX 에 값을 지정한다 .

이숭운

.datatheSum DWORD ?.codemain PROC mov eax, 10000h ; argument mov ebx, 20000h ; argument mov ecx, 30000h ; argument call Sumof ; EAX = (EAX + EBX + ECX) mov theSum, eax ; save the sum

CALL 문 뒤에 EAX 에 있는 합을 변수로 복사하는 동작은 선택사항이다 .

Page 50: Chapter 05  프로시저

5.5.3 예제 : 정수 배열의 합

C++ 이나 Java 로 이미 작성해 보았을 지도 모르는 매우 일반적인 루프의 유형은 정수 배열의 합을 계산하는 것이다 .

이것은 어셈블리 언어로 매우 쉽게 구현되며 가능한 한 빠르게 수행되도록 작성될 수 있다 . 예를 들어서 루프 안에서 변수 대신에

레지스터를 사용할 수 있다 .

이숭운

Page 51: Chapter 05  프로시저

호출하는 프로그램에서 32 비트 정수 배열의 포인터와 배열 값의개수인 두 개의 매개 변수를 받는 ArraySum 프로시저를 만들어 보자 .이 프로시저는 배열의 합을 계산하여 EAX 로 반환한다 .

이숭운

;---------------------------------------------------------------------ArraySum PROC;; Calculates the sum of an array of 32-bit integers.; Receives : ESI = the array offset; ECX = number of elements in the array; Returns : EAX = sum of the array elements;--------------------------------------------------------------------- push esi ; save ESI, ECX push ecx mov eax, 0 ; set the sum to zeroL1: add eax, [esi] ; add each integer to sum add esi, TYPE DWORD ; point to next integerloop L1 ; repeat for array size pop ecx ; restore ECX, ESI pop esi ArraySum ENDP

이 프로시저에는 배열 이름이나 배열 크기에 대해서 아무것도 특정하게 지정되지 않았다 . 이 프로시저는 32 비트 정수 배열의 합이 필요한 어떠한 프로그램에서도 사용될 수 있다 .

Page 52: Chapter 05  프로시저

ArraySum 호출 다음은 array 의 주소를 ESI 에 , 배열 카운트를 ECX 에 전달하는 ArraySum 을 호출하는 예이다 . 호출한 후에 EAX 에 있는 합을 변수로 복사한다 .

이숭운

.dataarray DWORD 100000h, 200000h, 300000h, 400000h, 500000h,theSum DWORD ?.codemain PROC mov esi, OFFSET array ; ESI point to array mov ecx, LENGTHOF array ; ECX = array count call ArraySum ; calculate the sum mov theSum ; returned in EAX

Page 53: Chapter 05  프로시저

5.5.4 순서도

순서도는 프로그램 논리를 그리는 잘 확립된 방법이다 .

순서도에서 각 도형은 하나의 논리 단계를 나타내고 도형을 연결하는 화살표 선은 논리단계의 순서를 보여준다 .

이숭운

Page 54: Chapter 05  프로시저

분기 방향을 보여주기 위해서 yes와 no 와 같은 텍스트 표기를 결정(decision) 심볼 옆에 붙인다

프로세스 (process) 심볼은 하나 이상의 밀접하게 관련되는 명령어를 포함한다 .

기본 순서도 도형

명령어들은 구문적으로 올바를 필요는 없다 . ex) CX 에 1 을 더하는 데에 다음 프로세스 심볼을 모두 사용할 수 있다 .

이숭운

begin/end

Process (task)

Procedure call

decisionyes

no

cx = cx + 1 add cx, 1

Page 55: Chapter 05  프로시저

ArraySum 프로시저에 대한 순서도

이숭운

LOOP 가 레이블로 제어권을 전달하는지를 (CX 값에 따라서 ) 결정해야 하기 때문에 LOOP 명령어에 대해서 결정 심볼을 사용한다 . 함께 넣은 코드는 원래의 프로시저의 소스를 보여준다

begin

push esi, ecx

eax = 0

add eax.[esi]

add esi, 4

ecx = ecx – 1

pop ecx, esi

ecx > 0?

end

yes

push esipush ecxmov eax, 0

AS1:add eax, [esi]add esi, 4loop AS1

pop ecxpop esi

Page 56: Chapter 05  프로시저

5.5.5 레지스터 저장 및 복원

ArraySum 예에서 ECX 와 ESI 는 프로시저의 시작에서 스택에 푸쉬되고 끝에서 팝된다 .

프로시저가 수정하는 레지스터는 항상 복원하여 , 호출하는 프로그램이 어떠한 레지스터 값도 바뀌지 않음을 확신할 수 있도록 한다 .

이 규칙에 대한 예외는 반환값으로 사용하는 레지스터 ( 대개 EAX) 에 적용된다 . 이 레지스터들은 푸쉬와 팝을 하지 않는다 .

이숭운

Page 57: Chapter 05  프로시저

USES 연산자

이숭운

USES 는 어셈블러가 두 가지 일을 하도록 알려준다 .1. 프로시저의 시작에 스택에 레지스터를 저장하는 PUSH 명령어 생성한다 .

2. 프로시저의 끝에 레지스터값을 복원하는 POP 명령어를 생성한다 .

USES 연산자는 PROC 의 바로 뒤에 오며 레지스터들을 같은 줄에 (컴마가 아닌 ) 빈칸이나 탭으로 구분하여 나열한다 .

Page 58: Chapter 05  프로시저

5.5.3 절의 ArraySum 프로시저는 ESI 와 ECX 를 저장하고 복원하기 위해서 PUSH 와 POP 명령어를 사용했다

이숭운

ArraySum PROC USES esi ecx mov eax, 0 ; set the sum to zeroL1 : add eax, [esi] ; add each integer to sum add esi , TYPE DWORD ; point to next integer

ret ; sum is in EAXArraySum ENDP

어셈블러가 생성한 코드는 USES 의 사용 결과를 보여준다 .ArraySum PROC push esi push esi mov eax, 0 ; set the sum to zeroL1 : add eax, [esi] ; add each integer to sum add esi , TYPE DWORD ; point to next integer loop L1 ; repeat for array size

pop ecx pop esi ret ArraySum ENDP

디버깅 팁마이크로소프트 비쥬얼 스튜디오 ( Visual Studio) 디버거를 사용할 때에 , 여러분은 MASA 의 고급 연산자와 디렉티브가 생성한 숨겨진 기계어 명령어를 볼 수 있다 . View 메뉴에서 Debug windows 를 선택하라 . 그리고 Disassembly 를 선택하라 . 이 윈도우는 프로그램 소스 코드를 어셈블러가 생성한 숨겨진 기계어 명령어와 함께 표시한다 .

[ 예외 ] 프로시저가 레지스터 ( 대개 EAX) 에 값을 변환할 때에 적용되는 레지스터 저장에 대해서 우리가 새로운 규칙에 대한 중요한 예외가 있다 . 이 경우에 반환 레지스터는 푸쉬되거나 팝되지 않아야 한다 . 예를 들어서 SumOf 프로시저에서 EAX 를 푸쉬하고 팝한다면 프로시저의 반환값은 없어질 것이다

SumOf PROC ; sum of three integers push eax ; save EAX add eax, ebx ; calculate the sum add eax, ecx ; of EAX, EBX, ECX pop eax ; lost the sum !SumOf ENDP

Page 59: Chapter 05  프로시저

• 기능적 분해 or 하향식 설계

• 큰 문제는 작은 작업으로 쉽게 나누어 질 수 있음• 프로그램은 각 프로시저를 개별적으로 테스트하면 관리하기

더 쉬움• 하향식 설계는 프로시저가 서로 어떻게 관련되는지 알 수

있음• 전체 설계가 확실히 되었을 때 , 상세한 부분에 더 쉽게

집중할 수 있음

권승현

5.6 프로시저를 사용한 프로그램 설계

Page 60: Chapter 05  프로시저

• 프로그램 작성시 명세 [ 설명서 ] 를 작성

• 전체 문제를 개별 작업으로 나눔• 기능적 분해 or 하향식 설계

• 프로그램은 각 프로시저를 개별적으로 테스트하면 관리하기 더 쉬움

• 하향식 설계는 프로시저가 서로 어떻게 관련되는지 알 수 있음

• 전체 설계가 확실히 되었을 때 , 상세한 부분에 더 쉽게 집중할 수 있음

권승현

5.6 프로시저를 사용한 프로그램 설계

Page 61: Chapter 05  프로시저

Summation

Program (main)

Clrscr PromptForIntegers

WriteString ReadInt

ArraySum Dispaly-Sum

WriteString WriteInt

구조 차트(Struture Chart)

권승현

Page 62: Chapter 05  프로시저

정수 합 계산 프로그램 ( 설계 )

Integer Summation Program

Prompt user for three integers

Calculate the sum of the array

Display the sum

프로그램 작성에 대비하여 프로시저 이름을 각 작업에 부여

Main • PromptForIntegers• ArraySum• DisplaySum

권승현

Page 63: Chapter 05  프로시저

Main • Clrscr ; 화면을 지움• PromptForIntegers WriteString ; 문자열 출력 Read Int

• ArraySum ; 정수들의 합• DisplaySum WriteString ; 정수열 출력 WriteInt ; 정수열 입력

권승현

Page 64: Chapter 05  프로시저

스터브 프로그램 최소 버전의 프로그램

이 프로그램은 빈 ( 또는 거의 빈 ) 프로시저만 포함한다 .

프로그램은 어셈블 되고 실행되지만 , 어떠한 유용한 일도 하지 않는다 .

스터브 프로그램은 모든 프로시저 호출에 대한 계획을 수립하고 ,

프로시저 간의 종속성을 검토하고 세부 동작을 코딩 하기 전에 구조적인 설계를 개선할 기회를 제공한다 .

권승현

Page 65: Chapter 05  프로시저

권승현

TITLE Integer Summation Program

; 이 프로그램은 사용자를 위해 세 개의 정수를 계산; 한 배열에 있는 수들을 저장 , 그 배열의 정수들의 합을 계산 ,

; 그리고 화면에 합계를 출력한다 .

INCLUDE Irvine32.inc ; 헤더파일.code

main PROC

; 출력 : Clrscr, PromptForIntegers, ArraySum, DisplaySum

exit

Main ENDP

권승현

Page 66: Chapter 05  프로시저

PromptForIntegers PROC

; 유저를 위해 세계의 정수를 계산 , 한 배열 안에 정수들을 입력; 받음 : ESI - 8 바이트로 구성되는 워드 정수 값 , ECX = 배열 크기; 반환 : 없음; 출력 : ReadInt, WriteString

ret

PromptForIntegers ENDP

ArraySum PROC

;32 비트의 정수로 이루어진 배열의 합을 계산; 받음 : ESI 배열로 나타냄 , ECX = 배열 크기; 반환 : EAX = 배열 원소들의 합

ret

권승현

Page 67: Chapter 05  프로시저

DisplaySum PROC

; 화면에 합을 출력; 받음 : EAX = 합; 반환 : 없음; 출력 : WriteString, WriteInt

ret

DisplaySum ENDP

END main

// 스터브 프로그램 종료

권승현

Page 68: Chapter 05  프로시저

정수 합 계산 구현

INCLUDE Irvine32.inc ; 헤더파일

Integer_COUNT = 3 ; 세 개의 정수의 배열 선언

.data

str1 BYTE “Enter a signed integer : “ , 0 ; 화면의 안내문 str2 BYTE “The sum of the integers is : “ , 0 ; 화면의 안내문 array DWORD INTEGER_COUNT DUP ( ? ) ; 배열 크기에 대해 변경 할 시.code

권승현

Page 69: Chapter 05  프로시저

main PROC ; main 함수 시작

call Clrscr ; 화면 지움 mov esi, OFFSET array ; esi 값에 array 배열 값을 복사 mov ecx, INTEGER_COUNT ; ecx 값에 INTEGER_COUNT 값을복사 call PromptForIntegers ; 프로시저 배열 포인터를 전달 call ArraySum ; 호출 call DisplaySum ; 호출 exit ; 종료

main ENDP ; main 함수 종료

권승현

Page 70: Chapter 05  프로시저

PromptForIntegers PROC USES ecx edx esi ; 함수 시작과 레지스터 이름 열거 mov edx, OFFSET str1 ; edx 값에 str1 값을 복사

L1 : call WriteString ; 정수 입력 안내문 출력 반복 call ReadInt ; 정수를 입력 받음 call Cr.lf ; 개행 mov [esi] , eax ; [esi] 주소에 eax 값을 복사 add esi, TYPE DWORD ; 정수를 esi 배열에 추가한다다음 정수로 loop L1 ; 루프 반복 ret ; EAX = 배열의 원소들의 합

PromptForIntegers ENDP ; 함수 종료

권승현

Page 71: Chapter 05  프로시저

ArraySum PROC USES esi ecx ; 함수 시작과 레지스터 이름 열거 mov eax , 0 ; eax 를 0 으로 초기화

L1 : add eax , [esi] ; 덧셈 연산 루프 반복 eax+esi[ 주소값 ]

add esi, TYPE DWORD ; 정수를 esi 배열에 추가한다loop L1 ; 배열 크기로 반복

ret ; 종료 - 합의 값은 EAX

ArraySum ENDP - 함수DisplaySum PROC USES edx ; 함수 시작과 레지스터 이름 열거

mov edx, OFFSET str2 ; edx 값에 str2 주소값을 복사 - 결과 call WriteString ; 문자열 출력 call WriteInt ; 정수 출력 – EAX 값 call C r.lf ; 개행ret ; EAX 반환

DisplaySum ENDP ; 함수 종료END main ; main 함수 종료

권승현