지능 3

인터럽트 호출 3(#BP, 중단점)

8086

정수 3

CD 이브

지능 imm8

통화 중단 imm8

8086

정수 13

안으로

EFLAGS.OF=1인 경우 인터럽트 4(#OF, 오버플로) 호출

8086

~ 안으로

설명:

지능 3인터럽트 3을 생성하기 위한 것이며 인터럽트 번호가 여기 opcode에 직접 존재하지 않고 암시적으로 3으로 설정된다는 점을 제외하고 작업 설명의 INT n 명령어와 동일합니다.

이 인터럽트는 특별한 1바이트 명령어를 배치하는 디버거에 의해 사용됩니다. 지능 3(코드 CCh) 명령의 첫 번째 바이트 또는 단일 바이트 명령 대신.

2바이트 코드 INT 3(코드 CD03h)을 사용하여 이 인터럽트를 호출하는 두 번째 방법이 있습니다. 하지만 이 방법실제로 사용되지 않음, 모든 x86 어셈블러는 기본적으로 니모닉을 해석합니다. 지능 3 CCh 코드와 함께 1바이트 명령으로(그러나 이것은 2바이트 코드를 수동으로 프로그래밍할 가능성을 배제하지 않습니다). 코드의 크기 외에도 1바이트 및 2바이트 명령의 처리도 다릅니다. 지능 3. EV86 모드(CR4.VME = 1)에서 단일 바이트 명령어에 의해 생성된 인터럽트는 인터럽트 리디렉션 맵(모드 2, 모드 3, 모드 5에 대해 설명됨)에 의해 리디렉션되지 않으며 항상 다음을 통해 보호 모드 핸들러에 의해 처리됩니다. IDT 테이블의 설명자. 또한 V86 모드에서는 이 인터럽트에 대해 IOPL 필드 검사가 수행되지 않으므로 EFLAGS.IOPL< 3, то есть однобайтная команда не является IOPL-чувствительной .

작업:

여기에 제시된 알고리즘은 명령을 실행할 때 프로세서의 동작을 설명할 뿐만 아니라 지능 3외부 인터럽트 또는 예외 생성.

그런 다음 고토 실제 주소 모드;

IF(EFLAGS.VM = 1 및 EFLAGS.IOPL< 3 AND

(CR4.VME = 0 또는 CR4.VME = 1 및 IRB[n] = 1)

) (* IRB[n]은 인터럽트 리디렉션 맵에서 인터럽트 n에 해당하는 비트입니다. *)

#GP(0); (모드에서 소프트웨어 인터럽트 INT n: (1) EFLAGS.IOPL의 V86< 3, (2) EV86 Режим 2 *)

또 다른 (* 보호 모드 또는 V86/EV86 모드 *)

IF(EFLAGS.VM = 1 및 CR4.VME = 1 및

(INT n) 및 IRB[n] = 0)

그 외 고토 보호 모드; (* 하드웨어 인터럽트, 예외, 모드에서 소프트웨어 인터럽트 INT n: (1) 보호 모드, (2) EFLAGS.IOPL = 3이 있는 V86, (3) EV86 모드 1 또는 모드 4 *)

실제 주소 모드:

IF ((인터럽트 번호 * 4) + IVT 인터럽트 벡터 테이블에 액세스할 때 세그먼트 외부 3) THEN #GP; FI;

IF (6바이트에 대한 스택 공간 없음) THEN #SS; FI;

EFLAGS.IF = 0; (* 인터럽트 플래그 리셋 *)

EFLAGS.TF = 0; (* 트랩 플래그 재설정 *)

EFLAGS.AC = 0; (* 정렬 제어 모드 플래그 재설정 *)

CS = IVT[인터럽트 번호 * 4].selector;

EIP = IVT[인터럽트 번호 * 4].offset AND 0x0000FFFFh;

(* 실제 주소 지정 모드에서 계속... *)

EV86-모드: (* CR0.PE = 1, EFLAGS.VM = 1, CR4.VME = 1, EV86 모드 - 소프트웨어 인터럽트 INT n, IRB[n] = 0 - 모드 3 또는 모드 5 *)

IF(V86 작업 스택에는 6바이트를 위한 공간이 없음) THEN #SS(0); FI;

tempFLAGS = 플래그;

tempFLAGS.NT = 0;

그런 다음 EFLAGS.IF = 0; (* 인터럽트 활성화 플래그 리셋 *)

tempFLAGS.IF = EFLAGS.VIF;

EFLAGS.VIF = 0; (* 가상 인터럽트 플래그 재설정 *)

EFLAGS.TF = 0; (* 트랩 플래그 재설정 *)

푸시(tempFLAGS);

(* 스택에 오류 코드가 푸시되지 않습니다 *)

CS = IVT_V86[인터럽트 번호 * 4].selector; (* IVT_V86 인터럽트 벡터 테이블은 V86 태스크 주소 공간의 시작 부분에 위치 *)

EIP = IVT_V86[인터럽트 번호 * 4].offset AND 0x0000FFFFh; (* EIP 레지스터의 상위 16비트는 0으로 설정됨 *)

(* EV86 모드에서 계속... *)

보호 모드: (* CR0.PE = 1, 하드웨어 인터럽트, 예외, 모드에서 소프트웨어 인터럽트 INT n: (1) 보호 모드, (2) EFLAGS.IOPL이 있는 V86 = 3, (3) EV86 모드 1 또는 모드 4 *)

IF ((인터럽트 번호 * 8) + 7은 IDT 테이블에 속하지 않음) THEN #GP(인터럽트 번호 * 8 + 2 + EXT); FI;

(* 이하, 에러코드 파라미터에서 +2라는 용어는 에러코드의 IDT 비트를 설정하는 것을 의미하고, +EXT라는 용어는 에러를 발생시킨 인터럽트가 소프트웨어 EXT인지 여부에 따라 에러코드의 EXT 비트를 설정하는 것을 의미한다. = 0 또는 외부 EXT = 1 * )

디스크립터의 AR 바이트는 인터럽트 게이트, 트랩 게이트 또는 태스크 게이트를 지정해야 합니다. 그렇지 않으면 #GP(인터럽트 번호 * 8 + 2 + EXT);

IF(소프트웨어 인터럽트 또는 예외) (* 즉, INT n, INT 3, INT01, BOUND 또는 INTO 중 하나 *)

IF(CPL > 게이트웨이 DPL)

#GP(인터럽트 번호 * 8 + 2); (* CR0.PE = 1, 게이트웨이 DPL< CPL, программное прерывание *)

게이트웨이가 있어야 합니다. 그렇지 않으면 #NP(인터럽트 번호 * 8 + 2 + EXT);

IF(작업 게이트웨이)

그런 다음 고토 태스크 게이트;

이동 TRAP-OR-INT-GATE; (* CR0.PE = 1, 인터럽트 또는 트랩 게이트 *)

TRAP-OR-INT-GATE: (* 보호 모드 또는 V86/EV86 모드, 트랩 또는 인터럽트 게이트웨이 *)

게이트웨이 설명자에 지정된 새 CS 선택자와 LDT 또는 GDT의 해당 설명자 확인:

선택자는 null이 아니어야 합니다. 그렇지 않으면 #GP(EXT);

선택기 인덱스는 설명자 테이블 내에 있어야 합니다. 그렇지 않으면 #GP(selector + EXT);

선택한 디스크립터는 코드 세그먼트 디스크립터여야 합니다. 그렇지 않으면 #GP(selector + EXT);

세그먼트가 있어야 합니다(P = 1). 그렇지 않으면 #NP(selector + EXT);

IF(코드 세그먼트 불일치) AND(코드 세그먼트의 DPL< CPL)

EFLAGS.VM = 0인 경우

그런 다음 고토 INT-TO-INTER-PRIV; (* CR0.PE = 1, EFLAGS.VM = 0, 인터럽트 또는 트랩 게이트, 일치하지 않는 코드 세그먼트, 코드 세그먼트 DPL< CPL *)

ELSE(*EFLAGS.VM=1*)

IF (새 코드 세그먼트의 DPL ≠ 0) THEN #GP(코드 세그먼트 선택기 + EXT); FI;

이동 INT-FROM-V86-MODE;(* CR0.PE = 1, EFLAGS.VM = 1, 인터럽트 또는 트랩 게이트, 코드 세그먼트 DPL = 0, CPL = 3 *)

또 다른 (* CR0.PE = 1, 인터럽트 또는 트랩 게이트, DPL = CPL과 일치하는 코드 세그먼트 또는 일치하지 않는 코드 세그먼트 *)

IF EFLAGS.VM = 1 THEN #GP(코드 세그먼트 선택기 + EXT); FI;

IF ((협상된 코드 세그먼트) OR (코드 세그먼트 DPL = CPL))

그런 다음 고토 INT-TO-INTRA-PRIV; (* CR0.PE = 1, 인터럽트 또는 트랩 게이트, 일치하는 세그먼트의 경우 코드 세그먼트 DPL ≤ CPL, 일치하지 않는 세그먼트의 경우 코드 세그먼트 DPL = CPL *)

ELSE #GP(코드 세그먼트 선택기 + EXT); (* 일치하는 세그먼트의 경우 DPL > CPL 또는 일치하지 않는 세그먼트의 경우 DPL ≠ CPL *)

INT-TO-INTER-PRIV: (* 보호 모드, 인터럽트 또는 트랩 게이트, 불일치 코드 세그먼트, 코드 세그먼트 DPL< CPL *)

IF(현재 TSS 32비트)

TSSstackAddress = (새 코드 세그먼트 DPL * 8) + 4

IF((TSSstackAddress + 5) > TSS 제한) (* (TSSstackAddress + 7) >

NewSS = [기본 TSS + TSSstackAddress + 4]; (*2바이트 로드*)

(* 4바이트 로드 *)

또 다른 (* 현재 TSS 16비트 *)

TSSstackAddress = (새 코드 세그먼트 DPL * 4) + 2

IF((TSSstackAddress + 3) > TSS 제한) (* (TSSstackAddress + 4) > TSS 제한 - 일부 프로세서 모델의 경우 *)

THEN #TS(현재 TSS 선택기 + EXT);

NewESP = [기본 TSS + TSSstackAddress]; (*2바이트 로드*)

NewSS = [기본 TSS + TSSstackAddress + 2]; (*2바이트 로드*)

선택기의 RPL은 새 코드 세그먼트의 DPL과 같아야 합니다. 그렇지 않으면 #TS(SS 선택기 + EXT);

스택 세그먼트의 DPL은 새 코드 세그먼트의 DPL과 같아야 합니다. 그렇지 않으면 #TS(SS selector + EXT);

IF(32비트 게이트웨이)

THEN 새 스택에는 20바이트(오류 코드가 있는 경우 24바이트)를 위한 공간이 있어야 합니다. 그렇지 않으면 #SS(EXT)

ELSE 새 스택에는 10바이트(오류 코드가 있는 경우 12바이트)를 위한 공간이 있어야 합니다. 그렇지 않으면 #SS(EXT)

SS:ESP = TSS(NewSS:NewESP); (* TSS에서 새로운 SS 및 eSP 값 다운로드 *)

IF(32비트 게이트웨이)

그 다음에

ELSE CS:IP = 게이트(선택기:오프셋);

SS 레지스터의 숨겨진 부분에 SS 디스크립터를 로드합니다.

IF(32비트 게이트웨이)

Push(오래된 스택에 대한 긴 포인터 - SS:ESP);

Push(리턴 포인트에 대한 긴 포인터 - CS:EIP); (*3단어가 4단어로 채워짐*)

푸시(오류 코드);

Push(오래된 스택에 대한 긴 포인터 - SS:SP); (*2단어*)

Push(리턴 포인트에 대한 긴 포인터 - CS:IP); (*2단어*)

푸시(오류 코드);

CPL = 새로운 코드 세그먼트의 DPL;

IF(인터럽트 게이트웨이) THEN EFLAGS.IF = 0 FI; (* 인터럽트 플래그 리셋 *)

EFLAGS.RF = 0;

(* 높은 권한 수준에서 보호 모드로 계속 실행... *)

INT-FROM-V86-모드: (* V86/EV86 모드, 인터럽트 또는 트랩 게이트, DPL = 0, CPL = 3 *)

(* 현재 TSS는 V86 모드에서 항상 32비트입니다 *)

IF(TSS 제한< 9) (*TSS 한도< 11 - для некоторых моделей процессоров *)

THEN #TS(현재 TSS 선택기 + EXT);

NewSS = [기본 TSS + 8]; (*2바이트 로드*)

NewESP = [기본 TSS + 4]; (* 4바이트 로드 *)

새로운 NewSS 스택 세그먼트의 선택자와 LDT 또는 GDT의 해당 설명자 확인:

선택자는 null이 아니어야 합니다. 그렇지 않으면 #TS(EXT);

선택자 인덱스는 설명자 테이블 내에 있어야 합니다. 그렇지 않으면 #TS(SS selector + EXT);

선택기의 RPL은 0이어야 합니다. 그렇지 않으면 #TS(SS 선택기 + EXT);

스택 세그먼트의 DPL은 0이어야 합니다. 그렇지 않으면 #TS(SS selector + EXT);

디스크립터는 쓰기 가능한 데이터 세그먼트 디스크립터(W = 1) 형식이어야 하며, 그렇지 않으면 #TS(SS selector + EXT);

세그먼트가 있어야 합니다(P = 1). 그렇지 않으면 #SS(SS 선택기 + EXT);

IF(32비트 게이트웨이)

새 스택에는 36바이트(오류 코드가 있는 경우 40바이트)를 위한 공간이 있어야 합니다. 그렇지 않으면 #SS(EXT)

새 명령어 포인터는 새 코드 세그먼트 내에 있어야 합니다. 그렇지 않으면 #GP(EXT); (* 명령어 포인터는 게이트웨이 디스크립터의 OFFSET 필드 값에 의해 결정됨 *)

TempEflags = EFLAGS;

EFLAGS.VM = 0; (* 프로세서는 보호 모드에서 인터럽트를 처리하기 위해 V86 모드를 종료합니다 *)

IF(인터럽트 게이트웨이)

그런 다음 EFLAGS.IF = 0;

CPL=0; (* 권한 수준 0으로 전환 *)

SS:ESP = TSS(NewSS:NewESP); (* TSS에서 SS0 및 ESP0 값 로드 *)

푸시(GS);

푸시(FS); (*두 단어로 확장*)

푸시(DS); (*두 단어로 확장*)

푸시(ES); (*두 단어로 확장*)

GS = 0; (* 세그먼트 레지스터는 0이 됩니다. 보호 모드에서 널 선택기의 후속 사용은 허용되지 않습니다 *)

푸시(TempSS); (*두 단어로 확장*)

푸시(TempEflags);

푸시(CS); (*두 단어로 확장*)

푸시(오류 코드); (* 있는 경우 4바이트 *)

CS:EIP = 게이트(선택기:오프셋); (* 부하 선택기: 32비트 게이트웨이 핸들에서 오프셋 *)

ELSE(*16비트 게이트웨이*)

새 스택에는 18바이트(오류 코드가 있는 경우 20바이트)를 위한 공간이 있어야 합니다. 그렇지 않으면 #SS(EXT)

(* 스택에 16비트 레지스터 값을 저장하는 것은 32비트 게이트웨이와 유사 *)

(* VM 플래그가 스택에 저장되지 않고 복귀 시 EFLAGS 이미지에서 복원되지 않기 때문에 16비트 세그먼트에서 IRET 명령을 사용하여 인터럽트에서 V86 모드로 다시 돌아가는 것은 불가능합니다 *)

(* 권한 수준이 0인 보호 모드에서 계속 실행... *)

내부에서 내부로: (* CR0.PE = 1, DPL = CPL 또는 DPL ≤ CPL과 일치하는 세그먼트 *)

IF(32비트 게이트웨이)

THEN 새 스택에는 12바이트(오류 코드가 있는 경우 16바이트)를 위한 공간이 있어야 합니다. 그렇지 않으면 #SS(EXT)

ELSE 새 스택에는 6바이트(오류 코드가 있는 경우 8바이트)를 위한 공간이 있어야 합니다. 그렇지 않으면 #SS(EXT)

새 명령어 포인터는 새 코드 세그먼트 내에 있어야 합니다. 그렇지 않으면 #GP(EXT);

IF(32비트 게이트웨이)

Push(리턴 포인트에 대한 긴 포인터); (*3단어가 4단어로 채워짐*)

CS:EIP = 게이트(선택기:오프셋); (* 부하 선택기: 32비트 게이트웨이 핸들에서 오프셋 *)

푸시(오류 코드); (* 있는 경우 4바이트 *)

Push(리턴 포인트에 대한 긴 포인터); (*2단어*)

CS:IP = 게이트(선택기:오프셋); (* 로드 선택기: 16비트 게이트웨이 디스크립터에서 오프셋 *)

푸시(오류 코드); (* 있는 경우 2바이트 *)

CS 설명자를 CS 레지스터의 숨겨진 부분에 로드합니다.

IF(인터럽트 게이트웨이) THEN EFLAGS.IF = 0; FI;

(* 권한 수준을 변경하지 않고 보호 모드에서 계속 실행... *)

작업 게이트: (* CR0.PE = 1, 작업 게이트 *)

작업 게이트웨이 핸들에서 TSS 선택기 확인:

선택기는 GDT(TI 비트 = 0)를 지정해야 하며, 그렇지 않으면 #GP(TSS 선택기 + EXT);

선택기 인덱스는 GDT 테이블 내에 있어야 합니다. 그렇지 않으면 #GP(TSS 선택기 + EXT);

선택한 선택기에 대한 해당 TSS 설명자 확인:

TSS 설명자는 자유 TSS 유형(TYPE.B = 0)을 가져야 하며, 그렇지 않으면 #GP(TSS 선택기 + EXT);

TSS가 있어야 합니다(P = 1). 그렇지 않으면 #NP(TSS 선택기 + EXT);

TSS에 대한 SWITCH-TASKS(첨부 포함); (* 여기서 "중첩 포함"은 컨텍스트가 초기화될 때 새 작업플래그 EFLAGS.NT = 1이 설정되고 중단된(이전) 작업의 TSS 선택기가 TSS 세그먼트의 LINK 필드에 복사됩니다. 주소 지정 및 멀티태스킹: 멀티태스킹 지원 *)

IF(인터럽트는 오류 코드가 있는 특수한 상황임)

스택에 오류 코드를 위한 공간이 있어야 합니다. 그렇지 않으면 #SS(EXT);

푸시(오류 코드);

EIP 명령 포인터는 CS 세그먼트 내에 있어야 합니다. 그렇지 않으면 #GP(EXT);

(* 주소 지정 및 멀티태스킹: 멀티태스킹 지원에 설명된 대로 새 작업 컨텍스트를 로드하면 추가 검사가 제공됩니다. *)

(* 새 작업의 맥락에서 계속... *)

보호 모드 예외:

지능 3, 그러나 외부 인터럽트나 예외가 생성될 때도 마찬가지입니다. 조금 EXT외부 인터럽트 오류 코드에서).

  • 기술자 벡터인터럽트의 (인덱스)가 인터럽트 디스크립터 테이블(IDT) 내에 있지 않습니다.
  • 처리 중인 핸들에 해당하는 핸들 벡터인터럽트의 (인덱스)는 트랩 게이트, 인터럽트 게이트 또는 태스크 게이트에 대한 핸들이 아닙니다.
  • 소프트웨어 인터럽트 또는 소프트웨어 예외가 발생하는 경우(즉, INT n , INT 3 , INT01, BOUND 또는 INTO의 경우 중 하나) 현재 권한 수준(CPL) 작업 더보기 권한 수준(DPL) 게이트웨이 설명자 IDT 테이블에서 -
  • 해당 처리에서 세그먼트 선택기 벡터트랩 게이트, 인터럽트 게이트 또는 태스크 게이트에 대한 인터럽트 핸들의 (인덱스)는 널 선택기입니다.
  • 트랩 게이트 디스크립터 또는 인터럽트 게이트 디스크립터의 세그먼트 선택기 인덱스가 해당 디스크립터 테이블의 한계에 속하지 않습니다.
  • 인터럽트에 해당하는 작업 게이트 설명자의 TSS 선택기 인덱스가 범위를 벗어났습니다. 전역 설명자 테이블(GDT);
  • 기술자새 코드 세그먼트는 코드 세그먼트 설명자가 아닙니다.
  • (DPL) 새로운 협상 코드 세그먼트가 더 큽니다. 현재 권한 수준(CPL) 작업 -
  • 처리 권한 수준일치하지 않는 새 코드 세그먼트의 (DPL)이 다음과 같지 않습니다. 현재 권한 수준(CPL) 작업 -
  • 인터럽트 대응 태스크 게이트 서술자의 TSS 선택자는 다음을 가리킨다. 로컬 디스크립터 테이블(LDT);
  • 새 작업의 TSS 핸들은 다음과 같이 표시됩니다. 바쁘다- TYPE.B ≠ 1.
  • 새 값을 읽어야 하는 주소 스택 포인터(SS:eSP), TSS 세그먼트 외부 ;
  • 새 스택 세그먼트의 선택자는 null 선택자입니다.
  • 새 스택 세그먼트의 선택기 인덱스가 해당 설명자 테이블에 속하지 않습니다.
  • 요청된 권한 수준(RPL) 새 스택 세그먼트의 선택기가 다음과 같지 않습니다. (DPL) 새로운 코드 세그먼트 -
  • 처리 권한 수준새 스택 세그먼트의 (DPL)이 다음과 같지 않습니다. 처리 권한 수준(DPL) 새로운 코드 세그먼트 -
  • 새 스택 세그먼트는 쓰기 가능한 데이터 세그먼트가 아닙니다.
  • 트랩 게이트, 인터럽트 게이트, 태스크 게이트 또는 TSS 핸들에 대한 해당 인터럽트 핸들은 다음과 같이 표시됩니다. 부재자(기술자의 P 비트는 클리어);
  • 새 코드 세그먼트가 없습니다(비트 P 세그먼트 디스크립터가 재설정됨).
  • 값의 스택(스택 전환이 발생한 경우 새 스택 포함)에 쓸 때 반품 주소, 스택 포인터, 깃발또는 오류 코드, 스택 세그먼트가 범위를 벗어났습니다.
  • 새 스택 세그먼트가 존재하지 않습니다(세그먼트 설명자의 P 비트가 지워짐).

실제 주소 지정 모드의 특수 상황:

여기에 제시된 예외 목록은 명령을 실행할 때뿐만 아니라 프로세서의 동작을 특징짓습니다. 지능 3, 그러나 외부 인터럽트나 예외가 생성될 때도 마찬가지입니다.

V86 모드의 특수 상황:

여기에 제시된 예외 목록은 명령을 실행할 때뿐만 아니라 프로세서의 동작을 특징짓습니다. 지능 3, 그러나 외부 인터럽트나 예외가 생성될 때도 마찬가지입니다. 조금 EXT오류 코드에서 인터럽트된 프로그램 외부의 이벤트를 나타내는 데 사용됩니다(

MASM, TASM 및 WASM 어셈블러는 서로 다릅니다. 그러나 간단한 프로그램을 만드는 것은 어셈블리와 연결 자체를 제외하고는 실질적으로 차이가 없습니다.

따라서 MASM, TASM 및 WASM에 대한 첫 번째 프로그램은 다음을 출력합니다. 영문자현재 커서 위치, 즉 왼쪽에 "A" 상단 모서리화면:

모델 작은 .code ORG 100h 시작: MOV AH,2 MOV DL,41h INT 21h INT 20h END 시작 텍스트 에디터- 예를 들어, WINDOWS의 노트북(메모장)에서(단, Word에서나 다른 "멋진"에서는 아님). 그러나 PSPad와 같은 구문 강조 기능이 있는 "고급" 텍스트 편집기를 권장합니다(섹션 참조). 그런 다음 이 파일을 .asm 확장자로 저장합니다(예: MYPROG 폴더). 파일 이름을 test로 지정합시다. 그래서 우리는 C:\MYPROG\atest.asm을 얻었습니다.

노트
첫 번째 명령에서 02h 대신 2를 썼습니다. MASM, TASM 및 WASM은 Emu8086과 같은 "자유"를 허용합니다. 02h를 쓸 수 있지만 오류는 없습니다.

프로그램에 대한 설명:

.모델 작은- 첫 번째 줄. .model 지시문은 특정 파일 유형에 대한 메모리 모델을 정의합니다. 우리의 경우 이것은 COM 파일이므로 코드, 데이터 및 스택 세그먼트를 결합하는 작은 모델을 선택합니다. 작은 모델은 COM 파일을 생성하도록 설계되었습니다.

.암호- 두 번째 줄. 이 지시문은 코드 세그먼트를 시작합니다.

ORG 100시간- 3번째 줄. 이 명령은 프로그램 카운터를 100h로 설정합니다. COM 파일을 메모리에 로드할 때 DOS가 PSP 데이터 블록( 십진수 256은 16진수 100h와 같습니다. 프로그램 코드는 이 블록 뒤에만 있습니다. COM 파일로 컴파일하는 모든 프로그램은 이 지시문으로 시작해야 합니다.

시작: MOV AH, 02h- 네 번째 줄. 시작 레이블은 프로그램의 첫 번째 명령 앞에 위치하며 프로그램이 시작하는 명령을 나타내기 위해 END 지시문에서 사용됩니다. MOV 명령어는 두 번째 피연산자의 값을 첫 번째 피연산자에 배치합니다. 즉, 값 02h는 레지스터 AH에 배치됩니다. 무엇을 위한 것입니까? 02h는 화면에 문자를 출력하는 DOS 함수입니다. 우리는 DOS용 프로그램을 작성하고 있으므로 다음 명령을 사용합니다. 운영 체제(OS). 그리고 인터럽트 21h가 이 특정 레지스터를 사용하기 때문에 우리는 이 함수(또는 오히려 그 번호)를 AH 레지스터에 씁니다.

MOV DL, 41시간- 다섯 번째 줄. 문자 코드 "A"가 DL 레지스터에 입력됩니다. "A"의 ASCII 문자 코드는 숫자 41h입니다.

지능 21시간- 6번째 줄. 이것은 바로 인터럽트 21h - AH 레지스터에 지정된 DOS 시스템 기능을 호출하는 명령입니다(이 예에서는 기능 02h). INT 21h 명령은 프로그램과 OS 간의 주요 상호 작용 수단입니다.

지능 20시간- 7번째 줄. 이것은 운영 체제에 프로그램을 종료하고 제어를 콘솔 응용 프로그램으로 넘기도록 지시하는 인터럽트입니다. 프로그램이 이미 컴파일되어 OS에서 실행된 경우 INT 20h 명령은 OS(예: DOS)로 우리를 반환합니다.

종료 시작- 8번째 줄. END 지시어는 프로그램을 종료함과 동시에 실행을 시작해야 하는 레이블을 나타냅니다.

어셈블러란?

어셈블러는 저수준 프로그래밍 언어입니다. 각 프로세서에는 자체 어셈블러가 있습니다. 어셈블러에서 프로그래밍하면 컴퓨터 하드웨어와 직접 작업하게 됩니다. 어셈블리 언어 소스 텍스트는 컴파일 후 프로세서 명령 코드로 변환되는 명령(니모닉)으로 구성됩니다.

어셈블러에서 프로그램을 개발하는 것은 매우 어려운 일입니다. 보낸 시간의 대가로 효과적인 프로그램을 얻을 수 있습니다. 어셈블러 프로그램은 프로세서의 모든 주기가 중요할 때 작성됩니다. 어셈블러에서는 프로세서에 특정 명령을 제공하고 불필요한 가비지를 제공하지 않습니다. 이것이 프로그램 실행의 고속을 보장하는 것입니다.

어셈블러를 올바르게 사용하려면 마이크로프로세서 시스템의 프로그램 모델을 알아야 합니다. 프로그래머의 관점에서 마이크로프로세서 시스템은 다음과 같이 구성됩니다.

  1. 마이크로프로세서
  2. 메모리
  3. I/O 장치.

프로그래밍 모델은 문헌에 잘 설명되어 있습니다.

어셈블리 구문

어셈블러에서 프로그램 라인의 일반적인 형식

<Метка>: <Оператор> <Операнды> ; <Комментарий>

레이블 필드. 레이블은 기호와 밑줄로 구성될 수 있습니다. 레이블은 조건부 및 무조건 점프 작업에 사용됩니다.

연산자 필드. 이 필드에는 니모닉 명령이 포함됩니다. 예를 들어 니모닉 이동

피연산자 필드. 연산자(연산자 필드)가 있는 경우에만 피연산자가 있을 수 있습니다. 피연산자가 없거나 여러 개일 수 있습니다. 피연산자는 일부 작업(보내기, 추가 등)을 수행해야 하는 데이터일 수 있습니다.

댓글 필드. 프로그램의 구두 반주를 위해서는 해설이 필요합니다. 심볼 뒤에 있는 모든 것 ; 의견을 고려했습니다.

최초의 어셈블리 언어 프로그램

이 기사에서는 i80x86 프로세서용 어셈블러를 사용하고 다음 소프트웨어를 사용합니다.

  • TASM - 볼랜드 터보 어셈블러 - 컴파일러
  • TLINK - Borland Turbo Linker - 링크 편집기(링커)

구체적으로 Tasm 2.0.

전통적으로 우리의 첫 번째 프로그램은 "Hello world!"라는 문자열을 출력할 것입니다. 화면에.

샘플.asm 파일

작은 모델 ; 메모리 모델.스택 100h ; 스택 size.data 설정 ; 프로그램 데이터 세그먼트 시작 HelloMsg DB "Hello World!",13,10,"$" .code ; 코드 세그먼트 시작 mov ax,@DATA ; 데이터 세그먼트 주소를 AX 레지스터로 이동 mov ds,ax ; DS 레지스터를 데이터 세그먼트로 설정 mov ah,09h ; 화면에 문자열을 출력하는 DOS 함수 mov dx,offset HelloMsg ; 오프셋을 문자열의 시작 부분으로 설정합니다. int 21h ; 출력 문자열 mov ax,4C00h ; DOS 프로그램 종료 함수 int 21h ; 프로그램 종료

보시다시피 프로그램은 데이터 세그먼트, 코드 세그먼트 및 스택 세그먼트와 같은 세그먼트로 나뉩니다.

모든 것을 순서대로 고려합시다.

.model small 지시문은 메모리 모델을 지정합니다. 소형 모델은 코드용 1세그먼트, 데이터 및 스택용 1세그먼트입니다. 데이터와 스택은 같은 세그먼트에 있습니다. 소형, 중형, 소형과 같은 다른 메모리 모델이 있습니다. 선택한 메모리 모델에 따라 프로그램의 세그먼트가 겹치거나 메모리에 별도의 세그먼트가 있을 수 있습니다.

.stack 100h 지시문은 스택 크기를 설정합니다. 스택은 후속 복원과 함께 일부 정보를 저장하는 데 필요합니다. 특히 스택은 인터럽트에 사용됩니다. 이 경우 FLAGS 레지스터, CS 레지스터 및 IP 레지스터의 내용이 스택에 저장됩니다. 다음으로 인터럽트 프로그램이 실행되고 이러한 레지스터의 값이 복원됩니다.

  • FLAGS 레지스터에는 프로세서가 명령을 실행한 후 생성되는 기호가 포함되어 있습니다.
  • CS(코드 세그먼트) 레지스터에는 코드 세그먼트의 주소가 포함됩니다.
  • 레지스터 IP(명령 포인터) - 명령 포인터. 여기에는 다음에 실행할 명령어의 주소(CS 코드 세그먼트에 대한 주소)가 포함됩니다.

상세 설명단순한 기사를 넘어선다.

.data 지시문은 프로그램 데이터 세그먼트의 시작을 정의합니다. 데이터 세그먼트는 "변수"를 정의합니다. 필요한 데이터에 대한 메모리 예약이 있습니다. .data 뒤에 줄이 있습니다.
HelloMsg DB "Hello World!",13,10,"$"

여기서 HelloMsg는 "Hello World!" 문자열의 시작 부분과 일치하는 기호 이름입니다. (인용없이). 즉, 이것은 데이터 세그먼트에 대한 문자열의 첫 번째 문자 주소입니다. DB(Define Byte) 지시문은 사용 가능한 메모리 영역을 바이트 단위로 정의합니다. 13,10 - 문자 코드 새로운 라인및 캐리지 리턴, $ 문자는 DOS 기능 09h가 올바르게 작동하는 데 필요합니다. 따라서 문자열은 메모리에서 15바이트를 차지합니다.

.code 지시문은 프로그램의 코드 세그먼트(CS - 코드 세그먼트)의 시작을 정의합니다. 다음은 명령 니모닉을 포함하는 프로그램의 행입니다.

mov 명령어에 대해 알아보겠습니다.

이동<приёмник>, <источник>

mov 명령은 이동 명령입니다. 소스의 내용을 대상으로 보냅니다. 전송은 레지스터-레지스터, 레지스터-메모리, 메모리-레지스터일 수 있지만 메모리-메모리 전송은 없습니다. 모든 것이 프로세서의 레지스터를 통과합니다.

데이터로 작업하려면 데이터 세그먼트 레지스터를 설정해야 합니다. 설정은 @DATA 데이터 세그먼트의 주소를 DS(데이터 세그먼트) 레지스터에 쓰는 것입니다. 이 레지스터에 주소를 직접 쓰는 것은 불가능합니다. 이것은 아키텍처이므로 AX 레지스터를 사용합니다. AX에서는 코드 세그먼트의 주소를 씁니다.

그런 다음 AX 레지스터의 내용을 DS 레지스터로 보냅니다.

그 후 DS 레지스터는 데이터 세그먼트의 시작 주소를 포함합니다. 주소 DS:0000h에는 문자 H가 포함됩니다. 세그먼트 및 오프셋에 대해 알고 있다고 가정합니다.

주소는 두 부분으로 구성됩니다.<Сегмент>:<Смещение>여기서 세그먼트는 2바이트이고 오프셋은 2바이트입니다. 모든 메모리 셀에 대한 액세스는 4바이트로 나타납니다.

mov 아,09h
mov dx, 오프셋 HelloMsg
정수 21시간

여기서 AH 레지스터에 숫자 09h를 씁니다. 화면에 라인을 표시하는 21번째 인터럽트의 기능 번호입니다.

다음 줄에서 DX 레지스터의 줄 시작 부분에 주소(당황)를 씁니다.

다음으로 인터럽트 21h를 호출합니다. 이것은 DOS 기능을 위한 인터럽트입니다. 인터럽트 - 실행 중인 프로그램이 인터럽트되고 인터럽트 프로그램이 실행을 시작할 때. 인터럽트 번호는 일련의 문자를 화면에 인쇄하는 DOS 서브루틴의 주소를 결정합니다.

아마도 질문이 있을 것입니다. AH 레지스터에 함수 번호 09h를 쓰는 이유는 무엇입니까? 그리고 왜 DX 레지스터에 쓰여진 라인에 대한 오프셋이 있습니까?
대답은 간단합니다. 각 기능에 대해 이 기능에 대한 입력 데이터를 포함하는 특정 레지스터가 정의됩니다. "e. 도움말"에서 특정 기능에 필요한 레지스터를 확인할 수 있습니다.

movax, 4C00h
정수 21시간

mov ax,4C00h - 함수 번호를 AX 레지스터로 보냅니다. 기능 4C00h - 프로그램을 종료합니다.

int 21h - 인터럽트 수행(실제로 종료)

끝 - 프로그램의 끝.

end 지시문 뒤에 컴파일러는 모든 것을 무시하므로 원하는 대로 작성할 수 있습니다. :)

끝까지 읽으셨다면 당신이 영웅입니다!

마이코 G.V. IBM PC용 어셈블러: - M.: "Business-Inform", "Sirin" 1999 - 212 p.