팀별 초안

Report
발표일 : 2013년 5월 5일
팀장 :박태영 / 팀원 : 조정민, 이지영, 이지훈, 이숭운, 권승현
박태영
구 분
성
팀장
팀원
명
핸 드 폰
이메일
비
고
박태영
010-6250-5242
[email protected]
m
5.4
조정민
010-3648-8055
[email protected]
5.2
이지영
010-9596-4948
[email protected]
om
5.3
이숭운
010-8831-7520
[email protected]
m
5.5
권승현
010-9580-8639
[email protected]
com
5.6
조정민
 이 장은 입출력과 문자열 처리와 관련된 일을 간단하게 사용할 수
있는 편리한 라이브러리를 소개하는 장이다.
 이 장은 서브루틴을 호출하여 프로그램을 어떻게 처리하기 쉬운
단위로 나누는가와
 프로그래밍 언어는 서브루틴 호출을 추적하기 위해서 실행 시간
스택을 어떻게 사용하는가에 대한 것도 알아볼 것이다.
5.3절에서 Irvine32.lib와 Irvine16.lib라는 이름의 링크
라이브러리로부터 프로시저를 어떻게 호출하는지를 보여준다.
조정민
 서브루틴이란?
메인 루틴에 대응되는
단어로, 프로그램 중의
하나 이상의 장소에서
필요할 때마다 반복해서
사용할 수 있는 부분적
프로그램으로, 그 자체가
독립해서 사용되는 일
없이 메인 루틴과 결부
시킴으로써 그 기능을
완수한다
 서브루틴 본체를 프로그램 중의 한 장소에만 실행시에 호출하는
방법을 폐쇄 서브루틴이라고 한다.
 서브루틴의 본체를 프로그램 중의 필요한 개소에 직접 전개하는
방식을 개방 서브루틴이라고 한다.
조정민
 Irvine32.lib는 입출력할 때에 MS-Windows API와
링크하는 피로시저를 포함한다.(32비트 보호모드에서
작성되는 프로그램을 위한 것)
 Irvine16.lib는 입출력할 때에 MS-DOS 인터럽트를
수행하는 프로시저를 포함한다.(16비트 실제주소
모드로 작성되는 프로그램을 위한 것)
이지영
• 링크 라이브러리(link library)는 기계어 코드
로 어셈블된 프로시저(서브루틴)를 포함하고
있는 파일이다.
• 링크 라이브러리는 하나 이상의 소스 파일로
시작하며, 소스 파일은 오브젝트 파일로 어셈
블된다. 오브젝트 파일은 링커 유틸리티가 인
식하는 특별한 형식의 파일에 삽입된다.
• 프로그램이 WriteString 프로시저를 호출하여
콘솔 윈도우에 문자열을 출력한다고 하자. 프
로그램소스는 WriteString 프로시저를 식별하
는 PROTO 디렉티브를 포함해야 한다.
이지영
• WrtieString PROTO
• 다음에 CALL 명령어는 WriteString 을 수행한
다.
• call WriteString
• 프로그램이 어셈블될 때에 어셈블러는 CALL
명령어의 목표 주소를 빈캄으로 두며, 이것은
링커에 의해서 채워질 것이다. 링커는 링크 라
이브러리에서 WtringString 을 찾아서 적잘한
기계어 명령어들을 링크 라이브러리로부터 프
로그램 실행파일로 복사한다. 여러분이 호출
한 프로시저가 링크 라이브러리에 없다면 링
커는 오류 메시시지를 내놓고 실행파일을 만
들지 않는다.
이지영
• ClossFile = (Irvine32전용) 이전에 생성하
거나 열었던 파일을 닫음
• 파일은 EAX로 전달되는 32비트 정수 핸들
로 식별됨.
• Clrscr = 콘솔 윈도우를 깨끗하게 지움. 일
반적으로 프로그램의 시작과 끝에서 호출.
• *먼저 WaitMsg를 호출하여 프로그램을 멈
추게 할 필요가 있다.
이지영
• CreateOutputFile = (Irvine32전용) 새 디스크
파일을 생성하고 출력모드로 염. 반환 될 때에
성공적으로 생성되었다면 EAX는 유효한 파일
핸들(32비트정수)을 가짐.
• Crlf = 콘솔 윈도우에서 커서를 다음 줄의 시작
으로 나아가게 함. ASCII문자코드 0Dh 와 0Ah
값으로 구성되는 문자열을 출력.
• Delay = 지정된 msec단위의 시간동안 프로그
램을 멈추게 함. Delay를 호출하기전에 EAX
에 원하는 시간 간격을 설정해야함.
이지영
• DumpMem = 일정 범위 위치의 메모리를 콘솔
윈도우에 16진수로 출력. 메모리의 시작주소ESI,출력단위크기-EBX,출력단위개수-ECX로
전달.
• DumpRegs = EAX,EBX,ECX,EDX,ESI,EDI,E
BP,ESP,EIP,EFL 레지스터를 16진수로 출력.
• CF,SF,ZF,OF,AF,PF 플래그의 값도 출력.
• EIP의 출력 값은 DumpRegs에 대한 호출 다
음 명령어의 오프셋. DumpRegs는 CPU스냅
샷을 출력.
이지영
• GetCommandTail = 프로그램의 명령어 행
을 널 종료 문자열로 복사.
• 명령어 행이 비어있으면 1, 아니면 0이 됨.
• Encrypt = 시작할 때에 GetCommandTail을
호출하여 두 파일 이름을 가져올 수 있음.
호출할 때에 EDX는 129바이트 이상의 크
기를 갖는 배열의 오프셋을 포함.
이지영
• GetMaxXY = (Irvine32전용) 콘솔 윈도우
버퍼의 크기를 반환. 입력 매개변수를 갖지
않음.
• GetMseconds = EAX 레지스터에 자정이후
의 경과시간을 msec 단위로 얻음.
• GetTextColor = 콘솔 윈도우에서 지정된 행
과 열에 커서를 위치. 기본적인 윈도우 X좌
표 : 0~79, Y좌표 : 0~24
이지영
• Gotoxy = 화면에서 지정된 행과 열에 커서
를 위치하게 한다. 기본적으로 콘솔 윈도우
의 X좌표의 범위는 0부터 79까지이며 , Y좌
표의범위는 0부터 24까지이다. Gotoxy를
호출할 때에 DH에 Y좌표(행)을 DL에 X좌
표(열)를 전달한다.
이지영
• IsDigit = AL에 있는 문자가 유효한 10진수
자리수인지 여부를 결정한다. 이 프로시저
를 호출할 때에 AL 에 ASCII 문자를 전달한
다. 프로시저는 AL 이 유효한 10진수 자리
수를 갖고 있으면 Zero 플래그를 1로 설정
한다. 그렇지 않으면 Zero 플래그는 0으로
된다.
이지영
• MsgBox = (Irvine32전용) 제목을 선택사항
으로 갖는 그래픽 팝업 메시지 상자를 표시
한다. 상자 안에 나타낼 문자열의 오프셋을
EDX 에 전달한다. 선택사항으로 상자의 제
목 문자열의 오프셋을 EBX에 전달한다.
• 제목을 빈칸으로 두려면 EBX를 0으로 설정
한다.
이지영
• MsgBoxAsk = (Irvine32 전용) Yes아 No 버
턴을 갖는 그래픽 팝업 메시지 상자를 표시
한다. 상자 안에 나타낼 질문 문자열의 오프
셋을 EDX 에 전달한다 선택 사항으로 상자
의 제목 문자열의 오프셋을 EBX에 전달한
다.
• 제목을 빈칸으로 두려면 EBX를 0으로 설정
한다. MsgBoxAsk 는 EAX에 사용자가 어떤
버튼을 선택했는지를 알려주는 정수
IDYES(6과같음) 또는 IDNO(7과 같음)를
반환한다.
이지영
• OpenInputFile = (Irvine32 전용) 입력을 위
해서 기존 파일을 연다. 파일 이름의 오프셋
을 EDX 에 전달한다.
• 프로시저가 반환될 때에 파일이 성공적으
로 열려있으면 EAX는 유요한 파일 핸들을
갖고 , 그렇지 않으면 EAX는
INVALID_HANDLE_VALUE(미리 정의된
상수)와 같다.
이지영
• ParseDecimal32 = 부호없는 10진수 문자
열을 32비트 이진수로 변환한다. 숫자가 아
닌 문자 앞에 있는 모든 유효한 자리 숫자가
변환된다. 앞에 있는 빈칸은 무시한다.
• 문자열의 오프셋을 EDX에, 문자열의 길이
를 ECX에 전달한다. 이진수는 EAX에 반환
된다.
이지영
• ParseInteger32 = 부호있는 10진수 문자열
을 32비트 이진수로 변환한다. 숫자가 아닌
문자 앞에 있는 모든 유효한 자리 숫자가
변환된다. 앞에 있는 빈캄은 무시한다. 문자
열의 오프셋을 EDX에, 문자열의 길이를
ECX에 전달한다. 이진수는 EAX에 반환된
다.
이지영
• Random32 = 32비트 난수 정수를 생성하고
EAX에 반환한다. 이 프로시저가 반복적으로
• 호출될 때에 무작위로 발생하는 난수를 시뮬
레이션하는 수열을 생성하며, 이 수열의 각 수
를 의사 난수 정수(pseudorandom integer) 라
고 부른다. 숫자들은 시드(seed)라고 하는 입
력을 갖는
• 간단한 함수를 사용하여 생성된다. 함수는 난
수를 생성하는 공식에서 시드를 사용한다. 다
음에이어지는 난수는 이전에 생성된 난수를
시드로 사용하여 생성된다. 이러한 점 때문에
난수라는 용어는 의사 난수를 의미한다.
이지영
• Randomize = Random32와
RandomRange 프로시저의 시작 시드값을
초기화한다.
• 시드는 100분의 1초 단위의 시간 값과 같다.
(Randomize) 프로그램이 Random32와
RandomRange 를 호출할 때마다 생성되는
난수열은 다를 것이고, 어떠한 나수열도 유
일할 것이다. Randomize를 프로그램의 시
작에서 한 번만 호출할 필요가 있다.
이지영
• RandomRange = 0부터 n-1 까지의 범위의
난수 정수를 생성한다. 여기서 n은 EAX레
지스터에전달되는 입력 매개변수이다. 난
수 정수는 EAX에 반환된다. 다음 예는 0과
4999 사이의 하나의 난수 정수를 생성하여
EAX에 넣는다.
• ReadChar 프로시저는 키보드에서 한 문자
를 읽고, 이 문자를 AL 레지스터에 반환한
다. 이 문자는 콘솔 윈도우에 출력되지 않는
다.
이지영
• ReadDec = 키보드에 32비트 부호없는 10
진수를 읽어서 값을 EAX에 반환한다.
• 앞에 있는 빈칸은 무시된다. 반환값은 숫자
가 아닌 문자를 만날 때까지의 모든 유효한
자리 숫자로부터 계산된다. 예를 들어
123ABC를 입력하였다면 EAX에 반환되는
값은 123 이다.
이지영
• ReadFromFile = (Invine32 전용) 입력 파일
을 버퍼로 읽는다. 열린 파일 핸들을 EAX에,
버퍼의 오프셋을 EDX에, 읽을 최대 바이트
수를 ECX에 전달한다. 프로시저가 반환될
때 CF = 0 이면 EAX는 파일에서 읽은 바이
트 수를 포함하며, CF = 1 이면 EAX는 무
엇이 잘못되었는지를 설명하는 시스템 오
류 코드를 포함한다.
이지영
• ReadHex = 키보드에서 32비트 16진수 정
수를 읽어서 값을 EAX에 반환한다. 잘못된
문자에 대한 어떠한 오류 검사도 수행하지
않는다. A부터 F까지의 자리 숫자에 대해서
대문자와 소문자를 모두 사용할 수 있다. 최
대 8자리 입력될 수 있다. (추가되는 문자는
무시된다.) 앞에 빈칸들도 무시된다.
이지영
• ReadInt = 키보드에서 32비트 부호있는 정수
를 읽어서 값을 EAX에 반환한다. 숫자 앞의 +
와 - 기호는 선택사항으로 입력할 수 있으며
숫자의 나머지 자리는 숫자로만 구성될 수 있
다.
• ReadInt는 Overflow 플래그를 1로 설정하고
입력된 값이 32비트 부호 있는 정수로 표시될
수 없다면 오류 메시지를 표시한다. 반환값은
숫자가 아닌 문자를 만날 때까지의 모든 유효
자리로부터 계산된다.
• 예를 들어서 +123ABC를 입력한다면 반환되
는 값은 +123 이다.
이지영
• ReadKey = 기다리지 않는 키보드 확인을 수
행한다. 키 입력이 발견되지 않으면 Zero 플래
그가 1로 설정된다. 키 입력이 발견된다면
Zero 플래그는 0으로 해제되고 AL은 0 또는
ASCII 코드를 포함한다.
• AL이 0을 포함한다면 사용자는 특수키(기능
키, 커서 화살표 등)를 누른 것일 수 있다. AH
레지스터는 가상 스캔 코드를 포함하고, DX는
가상 키 코드를, EBX는 키보드 플래그 비트를
포함한다.
• EAX와 EDX의 상반부는 덮어 쓰인다. 11장에
서 ReadKey 데 대한 세부 사항을 상세히 설명
할 것이다.
이지영
• ReadString = 키보드에서 문자열을 읽어
들이고 Enter 키를 누를때에 멈춘다. 버퍼
의 오프셋을 EDX에 전달하고 ECX를 (문자
열 종료 널 바이트에 대한 공간을 확보하기
위하여) 사용자가 입력할 수 있는 최대 문
자수에 1을 더한 값을 설정한다. 프로시저
는 사용자가 입력한 문자수를 EAX에 반환
한다.
이지영
• SetTextColor = (Irvine32 전용) 텍스트 출력
에 대한 전경색과 배경색을 설정한다.
• SetTextColor를 호출할 때에 색 속성을 AX
에 지정한다. 다음의 미리 정의된 색상 상수
가 전경색과 배경색 모두에 대해서 사용될
수 있다.
• 색상 상수는 include 파일 Irvine32.inc 와
Irvine16.inc 에서 정의된다. 배경색에 16을
곱하고 전경색을 더한다.
이지영
• StrLength = 널 종료 문자열의 길이를 반환
한다. 문자열의 오프셋을 ECX에 전달한다.
• 프로시저는 문자열의 길이를 EAX에 반환
한다.
• WaitMsg = "Press any key to continue..."
라는 메시지를 표시하고 사용자가 키를 누
르기를 기다린다. 이 프로시저는 데이터가
화면이 스크롤되어 사라지기 전에 화면을
정지시키고자 할 때에 유용하다. 이 프로시
저는 입력 매개변수가 없다.
이지영
• WriteBin = 정수를 ASCII 이진수 형식으로 콘
솔 윈도우에 출력한다. 정수를 EAX에 전달한
다.
• 이진수 비트는 읽기 쉽도록 4개씩 묶어서 표
시된다.
• WriteBinB = 32비트 정수를 ASCII 이진수 형
식으로 콘솔 윈도우에 출력한다. 값을 EAX 레
지스터에 전달하고 EBX는 표시할 크기를 바
이트 단위 (1,2,3)로 지시하게 한다. 비트들을
읽기 쉽도록 4개씩의 그룹으로 표시된다.
이지영
• 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에 전달한다.
이지영
• WriteString 프로시저는 널 종료 문자열을
콘솔 윈도우에 출력한다. 문자열의 오프셋
을 EDX에 전달한다.
• WriteToFile = (Irvine 32전용) 프로시저는
버퍼의 내용을 출력 파일에 저장한다. 유효
한 파일 핸들을 EAX에 , 버퍼의 오프셋을
EDX에, 출력할 바이트 수를 ECX에 전달한
다. 프로시저가 반환될 때에 EAX는 출력된
바이트 수를 포함한다.
이지영
• WriteWindowsMsg = (Irvine32 전용) 가장
최근에 생성한 오류의 메시지를 포함하는
문자열을 표시한다. 여러분의 프로그램이
파일을 생성하거나 열 수 없을 때에 가장 유
용한다.
• 다음 예는 입력을 위해서 파일 열기를 시도
하고, 오류를 발견하면 오류 메시지를 표시
하려고 WriteWindowsMsg를 호출한다.
박태영
 10개의 접시를 쌓아 놓을 때에 만들어진 것을 스택 이라 함
 스택의 중간에서 접시를 빼내는 것은 가능할 수 있으나, 맨 위에서부터
빼내는 것이 훨씬 더 일반적임
 새로운 접시는 스택의 맨 위에 추가할 수 있지만, 스택의 바닥이나,
중간에 추가할 수는 없음
박태영
 다음 그림과 같이 10개의 접시를 쌓아 놓을 때에 만들어진 것을 스택
(stack)이라고 말할 수 있다.
10
9
8
7
6
5
4
3
2
1
TOP
bottom
새로운 값은 스택의 맨 위에 추가되고 스택의 기존 값은 맨 위부터 제거됨
스택에 마지막으로 넣은 값이 항상 맨 먼저 꺼내는 값이기 때문에
스택은 LIFO(Last-In First-Out) 구조라고도 부른다.
 실행시간 스택은 스택 포인터 레지스터라고 하는 ESP레지스
터를 사용함
 ESP 레지스터는 스택에 있는 어떤 위치에 대한 32비트 오프
셋을 저장함
 ESP를 직접 조작하는 일은 거의 없으며
 ESP는 CALL,RET,PUSH,POP과 같은 명령어를 사용하여 간
접적으로 수정함
 ESP는 항상 스택의 맨 위에 추가된 마지막 저수를 가리킴
박태영
 간단한 펜티엄 CPU 블록도  구성요소들 간의 상호 작용
명령어 포인터는 명령어가 실행되기 전에
저장되는 공간인 코드 캐시를 참조함
코드 캐시
데이터 버스
명령어 포인터
주소 버스
명령어 해독기
명령어 해독기는 코드 캐시에서
읽어서 출력을 제어장치로 보냄
메모리
코드 데이터
제어 장치
레지스터
ALU
데이터 캐시
부동소수점 장치
박태영
 간단한 펜티엄 CPU 블록도  구성요소들 간의 상호 작용
Offset
000001000
00000006
ESP = 00001000h
00000FFC
00000FF8
00000FF4
00000FF0
 각 스택의 위치는 32비트를 저장함
이것은 프로그램이 32비트 모드에서 수행되고 있는 경우임
16비트 실제 주소 모드에서 SP레지스터가 가장 최근에 푸쉬된 값을
가리키며 스택 엔트리들은 대개 16비트 길이임
• 32비트 push 연산은 스택 포인터를 4씩 감소시키고 값을
스택 포인터가 가리키는 스택 위치로 복사함
• ESP 레지스터는 항상 스택의 맨 위를 가리킴
• 실행시간 스택은 메모리에서 높은 주소부
터 낮은 주소로 아래 방향으로 커짐
박태영

스택에 정수를 push 하기
BEFORE
000001000
AFTER
00000006
ESP
ESP
00000FFC
00000006
000001000
000000A5
00000FFC
00000FFC
00000FF8
00000FF4
00000FF4
00000FF0
00000FF0
00000001과 00000002를 push 한 후의 스택
Offset
000001000
00000006
00000FFC
000000A5
00000FF8
00000001
00000FF4
00000002
00000FF0
ESP
박태영
 Pop 연산
BEFORE
000001000
00000FFC
AFTER
00000006
00000006
000001000
000000A5
000000A5
00000FFC
00000001
00000FFC
00000FF8
00000001
00000FF4
00000002
ESP
00000FF4
ESP
00000FF0
00000FF0

Pop연산은 스택에서 팝된 후에 스택 포인터는
스택의 그 다음 높은 주소를 가리키도록 (스택 원소 크기
만큼) 증가됨
 ESP 아래의 스택 영역은 논리적으로 빈 상태(logically empty)이며
현재의 프로그램이 스택에 값을 푸쉬하는 명령어를 수행할 때 덮어
쓰임
• 프로그램에서 실행시간 스택의 몇 가지 중요한 용도는 다음과 같다
• 스택은 레지스터가 한 가지 이상의 목적으로 사용될 때에 레지스터를
위한 간편한 임시 저장 영역으로 사용된다. 레지스터가 수정된 뒤에
원래의 값으로 복원될 수 있다.
• CALL 명령어를 수행할 때에 CPU는 현재 서브루틴의 복귀 주소를 스
택에 저장한다.
• 서브루틴을 호출할 때에 인수(argument)라고 하는 입력 값을 스택에
푸쉬하여 전달한다.
• 스택은 서브루틴 내으 ㅣ지역 변수를 위한 임시 저장 공간을 제공한
다.
박태영
 PUSH와 POP명령어
PUSH 명령어
ESP를 감소시키고 소스 피연산자를 스택에 복사한다.
16비트 피연산자는 ESP를 2씩 감소시킨다
32비트 피연산자는 ESP를 4씩 감소시킨다
세개의 명령어 형식이 있다
PUSH reg/mem16
PUSH reg/mem32
PUSH imm32
박태영
 PUSH와 POP명령어
PUSH 명령어
ESP를 감소시키고 소스 피연산자를 스택에
16비트 피연산자는 ESP를 2씩 감소시킨다
32비트 피연산자는 ESP를 4씩 감소시킨다
세개의 명령어 형식이 있다
복사한다.
PUSH reg/mem16
PUSH reg/mem32
PUSH imm32
 PUSHFD와 POPFD명령어
ESP를 감소시키고 소스 피연산자를 스택에 복사한다.
16비트 피연산자는 ESP를 2씩 감소시킨다 pushdf
32비트 피연산자는 ESP를 4씩 감소시킨다 popfd
세개의 명령어 형식이 있다
16비트 프로그램은 16비트 FLAGS 레지스터를 스택에 푸쉬하기 위해서
PUSHF 명령어를 사용하고
FLAGS로 팝하기 위해서 POPF를 사용한다.
박태영
ESP를 감소시키고 소스 피연산자를 스택에 복사한다.
16비트 피연산자는 ESP를 2씩 감소시킨다
32비트 피연산자는 ESP를 4씩 감소시킨다
세개의 명령어 형식이 있다
Pushfd
; save the flags
;
; any sequence of statements here…
;
Popfd
; restore the flags

이런 형태의 push와 pop을 사용할 때에 프로그램의 실행 경로가 POPFD 명령어
를 건너뛰지 않도록 확실히 해야 한다
박태영
 PUSHAD, PUSHA, POPAD, POPA 명령어
PUSHAD 명령어는 모든 32비트 범용 레지스터를 EAX, ECX, EDX, EBX,
ESP (PUSHAD를 실행하기 이전 값), EBP,ESI,EDI의 순서로 푸쉬한다
 ESP (PUSHAD를 실행하기 이전 값), EBP,ESI,EDI의 순서로 푸쉬한다
80286에서 도입된 PUSHA 명령어는 16비트 범용 레지스터들(AX,CX,DX,
BX,SP,BP,SI,DI)을 나열된 순서대로 스택에 푸쉬한다
POPAD 명렁어는 같은 레지스터들을 반대 순서로 스택에서 팝한다
POPA 명령어는 같은 레지스터들을 반대 순서로 팝한다
PUSH reg/mem16
PUSH reg/mem32
PUSH imm32
박태영
 예제: 문자열을 역순으로 배치하기
TITLE Reversing a String (RevStr.asm)
INCLUDE Irvine32.inc
.data
aName Size = ($ - aName) =1
.code
Main PROC
; Push the name on the stack.
mov exc,nameSize
mov esi,0
L1: movzx eax, aName[esi]
Push eax
Inc esi
Loop L1
; get character
; push on stack
; Pop the name from the stack, in reverse,
; and store in the aName array.
mov ecx,nameSize
mov esi,0
L2: pop eax
Mov aName[esi],a1
Inc esi
Loop L2
; Display the name.
Mov edx, OFFSET aName
CALL WriteString
Call crlf
Exit
Main ENDP
END main
; get character
; push on stack
박태영
 복습문제
1.어떤 두 레지스터가 (보호모드에서) 스택을 다루는가?
2.실행시간 스택은 스택 추상 자료형과 어떻게 다른가?
3.스택은 왜 LITE 구조라고 부르는가?
4.32비트 값이 스택에 푸쉬될 때 ESP에 무슨 일이 일어나는가?
5.(참/거짓) Irvine32 라이브러리를 사용할 때에 32비트 값만 스택에 푸쉬되
6.어야 한다.
7.(참/거짓) Irvine16 라이브러리를 사용할 때에 16비트 값만 스택에 푸쉬되
8.어야 한다.
9.(참/거짓)PUSH 명령어는 즉시(immediate) 피연산자를 가질 수 없다.
10.어떤 명령어가 모든 32비트 EFLAGS 레지스터를 스택에 푸쉬하는가?
11.어떤 명령어가 스택을 EFLAGS 레지스터로 팝하는가?
12.도전: (NASM이라는) 다른 어셈블러는 PUSH 명령어가 여러 개의 특정한
레지스터를 사용하는 것을 허용한다. 왜 이러한 방법이 MASM에서의 PUS
HAD명령어보다 더 좋은가? 다음은 NASM 예이다.PUSH EAX EBX ECX
13. 도전 : PUSH 명령어가 없다고 가정하자. PUSH EAX와 똑같은 동작을
수행하는 연속된 두개의 다른 명령어를 적으시오.
이숭운
 고급언어를 이미 배웠다면 프로그램을 서브루틴으로 나누는 것이
얼마나 유용한지 알 것이다.
 어셈블리 언어에서는 일반적으로 서브루틴의 의미로 프로시저라는
용어를 사용한다.
 어셈블리 언어는 객체지향 프로그래밍보다 오래 전에 만들어져서
객체지향 언어에서 볼 수 있는 형식 구조로 되어있지 않다.
이숭운
 프로시저의 정의
 비공식적으로 프로시저는 이름이 부여된, return 문으로 끝나는
문장들의 블록으로 정의할 수 있다.
 프로시저는 PROC와 ENDP 디렉티브를 사용하여 선언된다.
프로시저는 (유효한 식별자인) 이름을 부여 받는다.
우리가 지금까지 작성했던 각 프로그램은 다음 예와 같이
main 이라는 이름의 프로시저를 가지고 있다.
main PROC
.
.
main ENDP
이숭운
 프로그램의 시작 프로시저가 아닌 다른 프로시저를 만들 때 프로시저는
RET 명령어로 끝난다. RET는 CPU가 프로시저를 호출했던 위치로
되돌아가게 한다.
sample PROC
.
.
ret
sample ENDP
 시작 프로시저는 (main)는 exit 문으로 끝나기 때문에 특별한 경우이다.
INCLUDE Irvine32.inc 문을 사용할 때, exit는 프로그램을 종료하는
시스템 프로시저인 ExitProcess 를 호출하는 것에 대한 별명이다.
INVOKE ExitProcess, 0
INCLUDE Irvine16.inc 문을 사용한다면 exit는 .EXIT 어셈블러 디랙티브로 변환된다.
이 디렉티브는 어셈블러가 다음의 두 명령어를 만들도록 한다.
mov ah, 4C0 0h
int 21h
;
;
call MS - DOS function 4ch
terminate program
이숭운
 프로시저의 레이블
 기본적으로 레이블은 선언된 프로시저 내에서만 사용할 수 있다.
이 규칙은 점프와 루프 명령어에 영향을 준다.
다음 예에서 Destination이라는 레이블은 JMP 명령어와 같은
프로시저에 있어야 한다.
jmp Destination
 이중 콜론(::)으로 표시하는 레이블을 선언하여 이 제한을 벗어나는
것이 가능하다.
Destination ::
이숭운
 프로시저는 실행시간 스택을 반환하고 조정하는 자동화된 방식을
가지고 있다.
 프로시저 바깥으로 직접 이동한다면 실행시간 스택은 쉽게 훼손될
수 있다.
예제: 세 개의 정수의 합
세 개의 32비트 정수의 합을 계산하는 Sumof라는 프로시저를
만들어 보자. 관련된 정수는 호출되기 전에 EAX, EBX, ECX에
저장되어 있다고 가정할 것이다. 프로시저는 EAX에 합을 반환한다.
SumOf PROC
add eax, ebx
add eax, ecx
ret
SumOf ENDP
이숭운
 프로시저의 문서화
다음은 프로시저의 시작 부분에 넣을 수 있는 정보에 대한 몇 가지 제안이다.
 프로시저가 수행하는 모든 작업에 대한 설명
 입력매개변수와 사용법. Receives와 같은 단어를 레이블로 사용하며
입력 매개변수의 입력 값에 대한 특정 요구사항이 있으면 여기에
기재하라.
 프로시저가 반환하는 값에 대한 설명. Returns과 같은 단어를
레이블로 사용한다.
 프로시저가 호출되기 이전에 충족되어야 하는 전제조건(precondition)
이라고 하는 특별한 요구사항에 대한 목록. 이것은 Requires라는
단어를 레이블로 사용할 수 있다.
우리가 선택한 Receives, Returns, Requires와 같은 설명 레이블은 절대적인 것이
아니다;
다른 유용한 이름들이 종종 사용된다.
이숭운
이러한 생각들을 유념하면서 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
ret
SumOf ENDP
C와 C++와 같은 고급언어로 작성된 함수는 8비트 값은 AL에,
16비트 값은 AX에, 그리고 32비트 값은 EAX에 반환한다.
이숭운
 CALL 명령어는 프로세서가 새로운 메모리 위치에서 수행을
시작하도록 지시하여 프로시저를 호출한다.
 프로시저는 RET(return from procedure) 명령어를 사용하여
프로세서가 프로시저를 호출했던 프로그램 위치로 되돌아오게
한다.
 기계적으로 말하면 CALL 명령어는 복귀 주소를 스택에 푸쉬하고
호출되는 프로시저의 주소를 명령어 포인터로 복사한다.
이숭운
 프로시저가 반환될 준비가 될 때에 RET 명령어는 복귀 주소를
스택에 명령어 포인터로 팝한다.
 32비트 모드에서 CPU는 EIP(instruction)가 가리키는 메모리에서
명령어를 수행한다. 16비트 모드에서는 IP가 명령어를 가리킨다.
이숭운
 호출과 반환 예제
main 에서 CALL 명령어가 오프셋 00000020에 있다고 가정하자.
이 명령어는 일반적으로 5 바이트의 기계어 코드를 필요로 한다.
그래서 다음 문장(여기서는 MOV)은 오프셋 00000025에 위치한다.
00000020
00000025
main PROC
call
MySub
mov eax, ebx
다음에 MySub의 첫 번째 명령어가 오프셋 00000040에 있다고 하자.
00000040
MySub PROC
mov eax, edx
.
.
ret
MySub ENDP
이숭운
CALL 명령어가 실행될 때에 (그림 5-8) call의 다음주소(00000025)가
스택에 푸쉬되고 MySub의 주소가 EIP에 적재된다. MySub에 있는
모든 명령어는 RET 명령어를 만날 때까지 실행된다.
RET 명령어가 실행될 때에 ESP가 가리키는 스택 값이 EIP로
팝된다. (그림 5-9의 단계1)
단계 2에서 ESP는 감소하여 스택의 이전 값을 가리킨다.(단계 2)
step 1:
????
00000025
ESP
ESP
????
00000025
EIP
00000025
00000040
EIP
step 2:
ESP
그림 5-8 CALL 명령어 수행
????
그림 5-9 RET 명령어 수행
이숭운
 중첩된 프로시저의 호출
중첩된 프로시저의 호출(nested procedure call)은 호출된
프로시저가 처음 프로시저로 변환되기 전에 다른 프로시저를 호출 할
때 일어난다.
(ret to main)
(ret to Sub1)
(ret to Sub2)
main
ESP
PROC
.
.
call Sub1
exit
main ENDP
Sub1 PROC
.
.
call Sub2
ret
Sub ENDP
그림 5-10 중첩된 프로시저의 호출
Sub2 PROC
.
.
call Sub3
ret
Sub2 ENDP
Sub3 PROC
.
.
ret
Sub3 ENDP
이숭운
반환된 후에 ESP는 그 다음 높은 주소의 스택 엔트리를 가리킨다.
Sub2의 끝의 RET 명령어가 실행되려고 할 때 스택은 다음과 같이
나타난다.
(ret to main)
(ret to Sub1)
ESP
마지막으로 Sub1이 반환될 때에 스택 [ESP]은 명령어 포인터로
팝되고 프로그램 실행은 main에서 계속된다.
(ret to main)
ESP
확실히, 스택은 중첩된 프로시저 호출을 포함하여, 정보를 기억하는 데
유용한 장치임이 입증되었다.일반적으로 스택 구조는 프로그램이
특정한 순서로 수행한 단계를 재추적해야 하는 상황에서 사용된다.
이숭운
 레지스터 인수의 프로시저 전달
 정수 배열의 합을 계산하는 것과 같은 표준 연산을 수행하는
프로시저를 작성한다면 프로시저 내에서 특정한 변수를 참조하는
것은 좋지 않다. 그렇게 한다면 프로시저는 특정한 한의 배열에만
사용 될 수 있다.
 더 좋은 방법은 배열의 오프셋을 프로시저에 전달하고 배열 원소의
명시하는 정수도 전달하는 것이다. 이것들을 인수(argument) 또는
입력 매개변수(input parameter)라고 한다.
어셈블리 언어에서는 인수를 범용레지스터로 전달하는 것이
일반적이다.
이숭운
이전 절에서 EAX, EBX, ECX에 있는 정수를 더하는 SumOf라는
간단한 프로시저를 만들었다. main에서 SumOf를 호출하기 전에
EAX, EBX, ECX에 값을 지정한다.
.data
theSum DWORD ?
.code
main PROC
mov eax, 10000h
mov ebx, 20000h
mov ecx, 30000h
call
Sumof
mov theSum, eax
;
;
;
;
;
argument
argument
argument
EAX = (EAX + EBX + ECX)
save the sum
CALL 문 뒤에 EAX에 있는 합을 변수로 복사하는 동작은 선택사항이다.
이숭운
 C++이나 Java로 이미 작성해 보았을 지도 모르는 매우 일반적인
루프의 유형은 정수 배열의 합을 계산하는 것이다.
 이것은 어셈블리 언어로 매우 쉽게 구현되며 가능한 한 빠르게
수행되도록 작성될 수 있다. 예를 들어서 루프 안에서 변수 대신에
레지스터를 사용할 수 있다.
이숭운
호출하는 프로그램에서 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 zero
L1: add eax, [esi]
; add each integer to sum
add esi, TYPE DWORD
; point to next integer
loop L1
; repeat for array size
pop ecx
; restore ECX, ESI
pop esi
ArraySum ENDP
이 프로시저에는 배열 이름이나 배열 크기에 대해서 아무것도 특정하게
지정되지 않았다. 이 프로시저는 32비트 정수 배열의 합이 필요한
어떠한 프로그램에서도 사용될 수 있다.
이숭운
ArraySum 호출 다음은 array의 주소를 ESI에, 배열 카운트를 ECX에
전달하는 ArraySum 을 호출하는 예이다. 호출한 후에 EAX에 있는 합을
변수로 복사한다.
.data
array
DWORD 100000h, 200000h, 300000h, 400000h, 500000h,
theSum DWORD ?
.code
main 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
이숭운
 순서도는 프로그램 논리를 그리는 잘 확립된 방법이다.
 순서도에서 각 도형은 하나의 논리 단계를 나타내고
도형을 연결하는 화살표 선은 논리단계의 순서를 보여준다.
이숭운
 기본 순서도 도형
분기 방향을 보여주기 위해서
yes와 no와 같은 텍스트 표기를
결정(decision) 심볼 옆에
붙인다
begin/end
yes
decision
Process (task)
프로세스(process) 심볼은 하나
이상의 밀접하게 관련되는
명령어를 포함한다.
no
Procedure call
 명령어들은 구문적으로 올바를 필요는 없다.
ex) CX에 1을 더하는 데에 다음 프로세스 심볼을 모두 사용할 수 있다.
cx = cx + 1
add cx, 1
이숭운
 ArraySum 프로시저에 대한 순서도
begin
push esi, ecx
eax = 0
add eax.[esi]
add esi, 4
push esi
push ecx
mov eax, 0
AS1:
add eax, [esi]
add esi, 4
loop AS1
ecx = ecx – 1
pop ecx
pop esi
yes
ecx > 0?
pop ecx, esi
end
 LOOP가 레이블로 제어권을
전달하는지를 (CX 값에 따라서)
결정해야 하기 때문에 LOOP
명령어에 대해서 결정 심볼을
사용한다. 함께 넣은 코드는 원래의
프로시저의 소스를 보여준다
이숭운
 ArraySum 예에서 ECX와 ESI는 프로시저의 시작에서 스택에
푸쉬되고 끝에서 팝된다.
 프로시저가 수정하는 레지스터는 항상 복원하여, 호출하는 프로그램이
어떠한 레지스터 값도 바뀌지 않음을 확신할 수 있도록 한다.
 이 규칙에 대한 예외는 반환값으로 사용하는 레지스터(대개 EAX)에
적용된다. 이 레지스터들은 푸쉬와 팝을 하지 않는다.
이숭운
 USES 연산자
 USES는 어셈블러가 두 가지 일을 하도록 알려준다.
1. 프로시저의 시작에 스택에 레지스터를 저장하는 PUSH 명령어 생성한다.
2. 프로시저의 끝에 레지스터값을 복원하는 POP명령어를 생성한다.
 USES 연산자는 PROC의 바로 뒤에 오며 레지스터들을 같은 줄에
(컴마가 아닌) 빈칸이나 탭으로 구분하여 나열한다.
이숭운
 5.5.3절의 ArraySum 프로시저는 ESI 와 ECX 를 저장하고 복원하기 위해서 PUSH 와
POP명령어를 사용했다
ArraySum PROC USES esi ecx
mov
eax, 0
L1 :
add
eax, [esi]
add
esi , TYPE DWORD
ret
ArraaySum ENDP
; set the sum to zero
; add each integer to sum
; point to next integer
; sum is in EAX
디버깅 팁
 어셈블러가 생성한 코드는 USES 의 사용 결과를 보여준다.
ArraySum
push
push
mov
L1 :
add
add
loop
PROC
esi
esi
eax, 0
eax, [esi]
esi , TYPE DWORD
L1
; set the sum to zero
; add each integer to sum
; point to next integer
; repeat for array size
마이크로소프트 비쥬얼 스튜디오 ( Visual
Studio) 디버거를 사용할 때에, 여러분은
MASA의 고급 연산자와 디렉티브가
생성한 숨겨진 기계어 명령어를 볼 수
있다. View 메뉴에서 Debug windows를
선택하라. 그리고 Disassembly를
선택하라. 이 윈도우는 프로그램 소스
코드를 어셈블러가 생성한 숨겨진 기계어
명령어와 함께 표시한다.
pop
ecx
pop
esi
ret
ArraaySum ENDP
[예외] 프로시저가 레지스터(대개 EAX) 에 값을
변환할 때에 적용되는 레지스터 저장에
대해서 우리가 새로운 규칙에 대한 중요한
예외가 있다. 이 경우에 반환 레지스터는
푸쉬되거나 팝되지 않아야 한다. 예를 들어서
SumOf 프로시저에서 EAX를 푸쉬하고
팝한다면 프로시저의 반환값은 없어질 것이다
SumOf PROC
push
eax
add
eax, ebx
add
eax, ecx
pop
eax
SumOf ENDP
;
;
;
;
;
sum of three integers
save EAX
calculate the sum
of EAX, EBX, ECX
lost the sum !

similar documents