System Progaramming -4- Data Transfers, Addressing, and Arithmetic

Shy·2023년 4월 11일
0

시스템프로그래밍

목록 보기
2/5

Data Transfer Instructions

1. Introduction

In high-level languages, compilers perform strict type checking

  • To help you avoid possible errors such as mismatching variables and data

On the other hand, assemblers let you do just about anything you want, as long as the processor’s instruction set can do what you ask

  • Assembly language forces you to pay attention to data storage and machine-specific details

Introduction
고급 프로그래밍 언어에서는 컴파일러가 엄격한 타입 검사를 수행하여 변수와 데이터의 불일치와 같은 가능한 오류를 방지합니다. 반면, 어셈블러는 프로세서의 명령어 세트가 원하는 작업을 수행할 수 있는 한, 원하는 작업을 수행할 수 있습니다. 어셈블리 언어는 데이터 저장 및 기계 특정 세부 사항에 주의를 기울이도록 강요합니다.

2. Operand Types

x86 instruction formats

  • Instructions can have zero, one, two, or three operands

  • There are three basic types of operands

    • Immediate: uses a numeric literal expression
    • Register: uses a named register in the CPU
    • Memory: references a memory location
OperandDescription
reg88-bit general purpose register: AH, AL, BH, BL, CF, CL, DH, DL
reg1616-bit general purpose register: AX, BX, CX, DX, SI, DI, SP, BP
reg3232-bit general purpose register: EAX, EBX, ECX, EDX, ESI, EDI, ESP, EBP
regAny general-purpose register
sreg16-bit segment register: CS, DS, SS, ES, FD, GS
imm8-, 16-, or 32-bit immediate value
imm88-bit immediate byte value
imm1616-bit immediate word value
imm3232-bit immediate doubleword value
reg/mem88-bit operand, which can be an 8-bit general register or memory byte
reg/mem1616-bit operand, which can be a 16-bit general register or memory word
reg/mem3216-bit operand, which can be a 16-bit general register or memory doubleword
memAn 8-,16- or 32-bit memory operand

2.Operand Types
x86 명령어 형식에는 0, 1, 2, 3개의 피연산자가 있을 수 있습니다. 피연산자의 기본 유형은 다음과 같습니다.

  • Immediate: 숫자 리터럴 표현식을 사용합니다.
  • Register: CPU의 명명된 레지스터를 사용합니다.
  • Memory: 메모리 위치를 참조합니다.

이러한 피연산자들은 다양한 크기의 레지스터와 메모리 영역을 사용하여 값을 저장하거나 전달할 수 있습니다. 표에서 볼 수 있듯이, 각각의 피연산자는 다양한 크기(8비트, 16비트, 32비트)와 유형(reg, sreg, imm, reg/mem 등)을 가질 수 있습니다.

예를 들어, 레지스터 피연산자는 8비트, 16비트, 32비트 크기의 일반 목적 레지스터를 사용할 수 있으며, 이들은 각각 AH, AL, BH, BL 등과 같은 이름으로 지정됩니다.

즉, x86 어셈블리 언어에서는 다양한 크기와 유형의 피연산자를 사용하여 데이터를 저장하고 전송하는 데 사용되는 명령어 형식을 제공합니다. 이를 통해 프로그래머는 레지스터와 메모리를 효율적으로 사용하여 복잡한 연산을 수행할 수 있습니다.

3. Direct Memory Operands

Variable names are references to offsets within the data segment
• E.g.) .data, var1 BYTE 10h, mov a1 var1

  • Var1’s size attribute is byte and it contains the value 10 hexadecimal
  • The last instruction copies its value into the AL register
  • Suppose var1 were located at offset 10400h
    • » Then the last instruction would be assembled into the following machine instruction: A0 00010400
    • » The first byte: the operation code (opcode)
    • » The remaining part: the 32-bit hexadecimal address of var1
  • You can optionally use the brackets with direct operands

3.Direct Memory Operands
변수 이름은 데이터 세그먼트 내의 오프셋에 대한 참조입니다. 예를 들어, 변수 var1의 크기 속성은 바이트이고 10진수 값이 있습니다. 마지막 명령어는 이 값을 AL 레지스터로 복사합니다. var1이 오프셋 10400h에 위치한다면, 마지막 명령어는 다음 기계 명령어로 조립됩니다: A0 00010400. 첫 번째 바이트는 연산 코드(opcode)이고 나머지 부분은 var1의 32비트 16진수 주소입니다. 대괄호를 사용하여 직접 피연산자를 선택적으로 사용할 수 있습니다.

4. MOV Instruction

Copy data from a source operand to a destination operand
Basic format: MOV destination, source

  • The destination operand’s contents change, but the source operand is unchanged
  • The right to left movement of data is similar to the assignment statement in C++ or Java
    MOV is very flexible in its use of operands, as long as the following rules are observed:
    • Both operands must be the same size
    • Both operands cannot be memory operands
    • The instruction pointer register (IP, EIP, or RIP) cannot be a destination operand
    • The standard MOV instruction formats

Memory to Memory

  • A single MOV instruction cannot be used to move data directly from one memory location to another
  • Instead, you must move the source operand’s value to a register before assigning its value to a memory operand
  • You must consider the minimum number of bytes required by an integer constant when copying it to a variable or register
  • Overlapping Values
    • The righthand-side code example shows how the same 32-bit register can be modified using differently sized data
      • When oneWord is moved to AX, it overwrites the existing value of AL
      • When oneDword is moved to EAX, it overwrites AX
      • Finally, when 0 is moved to AX, it overwrites the lower half of EAX

4.MOV Instruction
MOV 명령어는 데이터를 원본 피연산자에서 목적 피연산자로 복사합니다. 기본 형식은 다음과 같습니다: MOV destination, source. 목적 피연산자의 내용이 변경되지만 원본 피연산자는 변경되지 않습니다. 데이터의 오른쪽에서 왼쪽으로 이동하는 것은 C++ 또는 Java의 할당문과 유사합니다.

MOV는 다음 규칙을 지키는 한 피연산자 사용에 매우 유연합니다:

  • 두 피연산자의 크기는 같아야 합니다.
  • 두 피연산자는 모두 메모리 피연산자일 수 없습니다.
  • 명령어 포인터 레지스터(IP, EIP, 또는 RIP)는 목적 피연산자가 될 수 없습니다.

Memory to Memory
단일 MOV 명령어를 사용하여 데이터를 한 메모리 위치에서 다른 메모리 위치로 직접 이동할 수 없습니다. 대신 원본 피연산자의 값을 레지스터로 이동한 다음 메모리 피연산자에 값을 할당해야 합니다. 정수 상수에 필요한 최소 바이트 수를 고려하여 변수 또는 레지스터로 복사해야 합니다.

Overlapping Values
오른쪽 코드 예제는 동일한 32비트 레지스터를 다양한 크기의 데이터로 수정하는 방법을 보여줍니다. oneWord가 AX로 이동하면 AL의 기존 값이 덮어쓰여집니다. oneDword가 EAX로 이동하면 AX가 덮어쓰여집니다. 마지막으로 0이 AX로 이동하면 EAX의 하위 절반을 덮어

5. Zero/Sign Extension of Integers

Copying Smaller Values to Larger Ones

  • MOV cannot directly copy data from a smaller operand to a larger one
  • Suppose count (unsigned, 16 bits) must be moved to ECX (32 bits)
    • We can set ECX to zero and move count to CX
  • What happens if we try the same approach with a signed integer equal to -16?
    .data
    signedVal SWORD -16		; FFF0h (-16)
    .code
    mov ecx,0
    mov cx,signedVal		;ECX = 0000FFF0h (+65,520)
    • The value in ECX (+65,520) is completely different from -16
      mov ecx,0FFFFFFFFh
      mov cx,signedVal		;ECX = FFFFFFF0h (-16)
    • The sign extension
      • » To use the highest bit of the source operand (1) to fill the upper 16 bits of the destination operand, ECX
      • » Fortunately, Intel provides MOVZX and MOVSX instructions to deal with both unsigned and signed integers

MOVZX Instruction (move with zero-extend)

  • Copy the contents of a source operand into a destination operand and zero-extends the value to 16 or 32 bits
  • This instruction is only used with unsigned integers
  • There are three variants
    MOVZX reg32,reg/mem8
    MOVZX reg32,reg/mem16
    MOVZX reg16,reg/mem8
    • The first operand (a register) is the destination and the second is the source
    • The source operand cannot be a constant
.data
byteVal BYTE 10001111b
.code
movzx ax,byteVal		;AX = 000000001000111b
  • The following examples use registers for all operands, showing all the size variations:
mov		bx, 0A69Bh
movzx 	eax, bx			; EAX = 0000A69Bh
movzx	edx, b1			; EDX = 0000009Bh
movzx	cx, b1			; CX = 009Bh
  • The following examples use memory operands for the source and produce the same results:
.data
byte1 BYTE 9Bh
word1 WORD 0A69Bh
.code
movzx eax,word1			; EAX = 0000A69Bh
movzx edx,byte1			; EDX = 0000009Bh
movzx cx,byte			; CX = 009Bh

MOVSX Instruction (move with sign-extend)

  • Copy the contents of a source operand into a destination operand and sign-extends the value to 16 or 32 bits
  • This instruction is only used with signed integers
  • There are three variants:
MOVSX reg32,reg/mem8
MOVSX reg32,reg/mem16
MOVSX reg16,reg/mem8
  • An operand is sign-extended by taking the smaller operand’s highest bit and repeating (replicating) the bit throughout the extended bits in the destination operand
    .data
    byteVal BYTE 10001111b
    .code
    movsx ax,byteVal		; AX = 1111111110001111b
    • A hexadecimal constant has its highest bit set if its most significant hexadecimal digit is greater than 7
      mov		bx,0A69Bh
      movsx	eax,bx			; EAX = FFFFA69Bh
      movsx	edx,bl			; EDX = FFFFFF9Bh
      movsx	cx,bl			; CX = FF9Bh

이 섹션에서는 정수의 제로/부호 확장에 대해 설명하고 있습니다.

Copying Smaller Values to Larger Ones
MOV 명령어는 작은 피연산자에서 큰 피연산자로 데이터를 직접 복사할 수 없습니다. 예를 들어, 부호 없는 16비트 정수 count를 32비트 정수 ECX로 옮기려면 ECX를 0으로 설정한 다음 count를 CX로 이동할 수 있습니다.

그러나 동일한 접근 방식을 사용하여 값이 -16인 부호 있는 정수를 복사하면 ECX의 값(65,520)은 -16과 완전히 다릅니다. 부호 확장을 사용하여 출처 피연산자의 최상위 비트(1)를 목적 피연산자인 ECX의 상위 16비트로 채울 수 있습니다. 다행히도 인텔은 부호 없는 정수와 부호 있는 정수를 처리하는 MOVZX와 MOVSX 명령어를 제공합니다.

MOVZX Instruction (move with zero-extend)
MOVZX 명령어는 소스 피연산자의 내용을 대상 피연산자로 복사하고 값을 16비트 또는 32비트로 확장하여 0으로 채웁니다. 이 명령어는 부호 없는 정수에만 사용됩니다. 세 가지 변형이 있습니다.

MOVZX reg32,reg/mem8
MOVZX reg32,reg/mem16
MOVZX reg16,reg/mem8

첫 번째 피연산자(레지스터)는 대상이고 두 번째 피연산자는 소스입니다. 소스 피연산자는 상수가 될 수 없습니다.

.data
byteVal BYTE 10001111b
.code
movzx ax,byteVal    ;AX = 0000000010001111b

위 예제에서 byteVal의 값을 ax 레지스터로 옮기고 나머지 비트를 0으로 채웁니다.

다음 예제들은 모든 피연산자에 레지스터를 사용하여 가능한 모든 크기 변형을 보여줍니다:

mov     bx, 0A69Bh
movzx   eax, bx         ; EAX = 0000A69Bh
movzx   edx, b1         ; EDX = 0000009Bh
movzx   cx, b1          ; CX = 009Bh

다음 예제들은 소스에 메모리 피연산자를 사용하고 동일한 결과를 생성합니다:

.data
byte1 BYTE 9Bh
word1 WORD 0A69Bh
.code
movzx eax,word1         ; EAX = 0000A69Bh
movzx edx,byte1         ; EDX = 0000009Bh
movzx cx,byte1          ; CX = 009Bh

이 예제들에서 볼 수 있듯이, MOVZX 명령어는 작은 크기의 값을 더 큰 레지스터로 옮길 때 상위 비트를 0으로 채워줍니다. 이렇게 함으로써 부호 없는 정수를 올바르게 확장할 수 있습니다.

MOVSX Instruction (move with sign-extend) 은 소스 피연산자의 내용을 목적지 피연산자로 복사하고 값을 16 또는 32비트로 부호 확장합니다. 이 명령은 부호 있는 정수에만 사용됩니다. MOVSX는 다음 세 가지 변형이 있습니다:

MOVSX reg32,reg/mem8
MOVSX reg32,reg/mem16
MOVSX reg16,reg/mem8

피연산자는 작은 피연산자의 최상위 비트를 취하여 목적지 피연산자의 확장된 비트에 반복(복제)하여 부호 확장됩니다. 예를 들면:

.data
byteVal BYTE 10001111b
.code
movsx ax,byteVal        ; AX = 1111111110001111b

다음 예제는 모든 피연산자에 레지스터를 사용하여 가능한 모든 크기 변형을 보여줍니다:

mov     bx,0A69Bh
movsx   eax,bx          ; EAX = FFFFA69Bh
movsx   edx,b1          ; EDX = FFFFFF9Bh
movsx   cx,b1           ; CX = FF9Bh

이러한 예제들에서 볼 수 있듯이, MOVSX 명령어는 작은 크기의 값을 더 큰 레지스터로 옮길 때 부호를 확장하여 부호 있는 정수를 올바르게 처리할 수 있습니다.

6. LAHF and SAHF Instructions

The LAHF (load status flags into AH) instruction

  • Copy the low byte of the EFLAGS register into AH
  • The following flags are copied
    • Sign, Zero, Auxiliary Carry, Parity, and Carry
  • Using this instruction, you can easily save a copy of the flags in a variable for safekeeping
.data
saveflags BYTE ?
.code
lafh					; load flags into AH
mov saveflags,ah		; save them in a variable

The SAHF (store AH into status flags) instruction

  • Copy AH into the low byte of the EFLAGS (or RFLAGS) register
mov	ah,saveflags		; load saved flags into AH
sahf					; copy into Flags register

LAHF (load status flags into AH) 명령은 EFLAGS 레지스터의 하위 바이트를 AH 레지스터로 복사합니다. 다음 플래그들이 복사됩니다: Sign, Zero, Auxiliary Carry, Parity, and Carry. 이 명령어를 사용하면 변수에 플래그의 사본을 쉽게 저장할 수 있습니다.

.data
saveflags BYTE ?
.code
lafh                    ; load flags into AH
mov saveflags,ah        ; save them in a variable

SAHF (store AH into status flags) 명령은 AH 레지스터의 내용을 EFLAGS (또는 RFLAGS) 레지스터의 하위 바이트로 복사합니다.

mov    ah,saveflags        ; load saved flags into AH
sahf                       ; copy into Flags register

이렇게 LAHF와 SAHF 명령어를 사용하여 플래그 레지스터의 상태를 저장하고 복원할 수 있습니다. 이 기능은 특정 연산이 완료된 후 플래그 레지스터를 이전 상태로 되돌려 놓아야 할 때 유용합니다.

7. XCHG Instruction (exchange data)

Exchange the contents of two operands
There are three variants:

XCHG reg, reg
XCHG reg, mem
XCHG mem, reg

The rules for operands are the same as those for the MOV instruction

  • Except that XCHG does not accept immediate operands
xchg ax,bx			; exchange 16-bit regs
xchg ah,al			; exchange 8-bit regs
xchg var1,bx		; exchange 16-bit mem op with BX
xchg eax,ebx		; exchange 32-bit regs

To exchange two memory operands, use a register as a temporary container and combine MOV with XCHG

mov ax,val1
xchg ax,val2
mov val1,ax

XCHG 명령어는 두 피연산자의 내용을 교환합니다. 다음 세 가지 변형이 있습니다:

XCHG reg, reg
XCHG reg, mem
XCHG mem, reg

피연산자에 대한 규칙은 MOV 명령어와 동일합니다. 단, XCHG는 즉시 피연산자를 허용하지 않습니다.

xchg ax,bx         ; exchange 16-bit regs
xchg ah,a1         ; exchange 8-bit regs
xchg var1,bx       ; exchange 16-bit mem op with BX
xchg eax,ebx       ; exchange 32-bit regs

두 메모리 피연산자를 교환하려면 레지스터를 임시 컨테이너로 사용하고 MOV와 XCHG를 결합합니다.

mov ax,val1
xchg ax,val2
mov val1,ax

8. Direct-Offset Operands

You can add a displacement to the name of a variable, creating a direct-offset operand
This lets you access memory locations that may not have explicit labels

arrayB BYTE 10h,20h,30h,40h,50h
mov al, arrayB		; AL = 10h
  • We can access the second byte in the array by adding 1 to the offset of arrayB
mov al, [arrayB+1]		; AL = 20h
mov al, [arrayB+2]		; AL = 30h
  • An expression such as arrayB+1 produces what is called an effective address by adding a constant to the variable’s offset
  • Surrounding an effective address with brackets makes it clear that the expression is dereferenced to obtain the contents of memory at the address
  • The brackets are not mandatory in MASM, but we highly recommend their use for clarity
  • MASM has no built-in range checking for effective addresses
    mov al, array[B+20]		; AL = ??
    • Suppose that arrayB holds five bytes, then, the instruction retrieves a byte of memory outside the array
    • The result is a sneaky logic bug, so be extra careful when checking array references

Word and Doubleword Arrays

  • In an array of 16-bit words, the offset of each array element is 2 bytes beyond the previous one
.data
arrayW WORD 100h,200h,300h
.code
mov ax,arrayW				; AX = 100h
mov ax,[arrayW+2]			; AX = 200h
  • Similarly, the second element in a doubleword array is 4 bytes beyond the first one
.data
arrayD DWORD 10000h,20000h
.code
mov eax,arrayD				; EAX = 10000h
mov eax,[arrayD+4]			; EAX = 20000h

변수 이름에 이동 값을 추가하여 직접 오프셋 피연산자를 만들 수 있습니다. 이를 통해 명시적 레이블이 없는 메모리 위치에 액세스할 수 있습니다.

arrayB BYTE 10h,20h,30h,40h,50h
mov a1, arrayB     ; AL = 10h

arrayB의 오프셋에 1을 추가하여 배열의 두 번째 바이트에 액세스할 수 있습니다.

mov a1, [arrayB+1]     ; AL = 20h
mov a1, [arrayB+2]     ; AL = 30h

오프셋에 상수를 더함으로써 변수의 오프셋과 효과적인 주소를 생성하는 표현식이 만들어집니다. 이 표현식을 괄호로 묶어 주소에서 메모리 내용을 참조하는 것이라는 것을 명확하게 합니다. 괄호는 MASM에서 필수적이지는 않지만, 명확성을 위해 사용하는 것이 좋습니다.

MASM에는 효과적인 주소에 대한 범위 검사가 내장되어 있지 않습니다.

mov a1, array[B+20]     ; AL = ??

예를 들어, arrayB가 5 바이트를 저장하고 있다면, 이 명령어는 배열 외부의 메모리 바이트를 검색합니다. 결과적으로 이는 논리적인 버그가 될 수 있으므로 배열 참조를 확인할 때 주의해야 합니다.

단어와 더블워드 배열에서는 16비트 워드의 배열에서 각 배열 요소의 오프셋이 이전 요소보다 2바이트 더 멀리 있습니다.

.data
arrayW WORD 100h,200h,300h
.code
mov ax,arrayW				; AX = 100h
mov ax,[arrayW+2]			; AX = 200h

비슷하게, 더블워드 배열의 두 번째 요소는 첫 번째 요소보다 4 바이트 더 멀리 있습니다.

.data
arrayD DWORD 10000h,20000h
.code
mov eax,arrayD				; EAX = 10000h
mov eax,[arrayD+4]			; EAX = 20000h

직접 오프셋 피연산자를 사용하면 명시적인 레이블이 없는 메모리 위치에 액세스할 수 있습니다. 더블워드 배열이나 워드 배열에서 각 요소의 오프셋은 이전 요소보다 일정한 바이트 수만큼 더 멀리 있습니다. 이를 통해 배열의 요소를 쉽게 참조하고 값을 불러오거나 저장할 수 있습니다. 하지만 효과적인 주소에 대한 범위 검사가 없기 때문에 배열 참조를 확인할 때 주의를 기울여야 합니다. 그렇지 않으면 논리적인 버그가 발생할 수 있습니다.

9. Example Program (Moves)

; Data Transfer Examples (Moves.asm)

.386
.model flat,stdcall
.stack 4096
ExitProcess PROTO,dwExitCode:DWORD
.data
val1 WORD 1000h
val2 WORD 2000h
arrayB aBYTE 10h,20h,30h,40h,50h
arrayW WORD 100h,200h,300h
arrayD DWORD 10000h,20000h

.code
main PROC

; 	Demonstrating MOVZX instruction:
		mov bx,0A69Bh
        movzx eax,bx		; EAX = 0000A69Bh
        movzx edx,bl		; EDX = 0000009Bh
        movzx cx,bl			; CX = 009Bh
        
;   Demonstrating MOVSX instruction:
    	mov bx,0A69Bh
        movsx eax,bx		; EAX = FFFFA69Bh 
        movsx edx,bl		; EDX = FFFFFF9Bh
        mov bl,7Bh
        movsx cx,bl			; CX = 007Bh
        
;	Memory-to-memory exchange:
		mov ax,val1			; AX = 1000h
        xchg ax,val2		; AX = 2000h, val2 = 1000h
        mov val1,ax			; val1 = 2000h
        
;	Direct-Offset Addressing (byte array):
		mov al,arrayB		; AL = 10h
        mov al,[arrayB+1]	; AL = 20h
        mov al,[arrayB+2]	; AL = 30h
        
;	Direct-Offset Addressing (word array):
		mov ax, arrayW		; AX = 100h
        mov ax,[arrayW+2]	; AX = 200h

;	Direct-Offset Addressing (Doubleword array):
		mov eax,arrayD		; EAX = 10000h
        mov eax,[arrayD+4]	; EAX = 20000h
        mov eax,[arrayD+4]	; EAX = 20000h
		INVOKE ExitProcess, 0
main ENDP
END main

Displaying CPU Flags in the Visual Studio Debugger

  • How to display the CPU status flags during a debugging session
    • Select Windows from the Debug menu, then select Registers from the Windows menu
    • Inside the Registers window, right-click and select Flags from the dropdown list
    • You must be currently debugging a program in order to see these menu options
  • The following table identifies the flag symbols used inside the Registers window
FlagNameOverflowDirectionInterrputSignZeroAux CarryParityCarry
SymbolOVUPEIPLZRACPECY
  • Each flag is assigned a value of 0 (clear) or 1 (set)

예제 프로그램 (Moves.asm)은 데이터 전송 관련 명령어들을 활용하여 다양한 데이터 이동 및 변환 작업을 수행하는 코드입니다. 이 프로그램은 주로 MOVZX, MOVSX, XCHG, 그리고 Direct-Offset addressing 기법들을 보여주고 있습니다.

  • MOVZX와 MOVSX 명령어는 각각 부호 없는 정수 및 부호 있는 정수를 확장할 때 사용됩니다.
  • XCHG 명령어는 두 피연산자의 내용을 서로 교환할 때 사용됩니다.
  • Direct-Offset addressing은 변수 이름에 오프셋을 추가하여 명시적인 레이블이 없는 메모리 위치에 액세스할 수 있게 합니다.

그리고 이 프로그램에서는 바이트 배열, 워드 배열, 그리고 더블워드 배열을 사용하여 Direct-Offset addressing 기법을 시연합니다.

Visual Studio 디버거에서 CPU 플래그를 표시하는 방법에 대해 설명합니다. 디버깅 세션 중에 CPU 상태 플래그를 표시하려면, 디버그 메뉴에서 Windows를 선택한 다음, Windows 메뉴에서 레지스터를 선택하세요. 레지스터 창에서 마우스 오른쪽 버튼을 클릭하고 드롭다운 목록에서 플래그를 선택합니다. 이 메뉴 옵션을 보려면 프로그램을 디버깅 중이어야 합니다.

레지스터 창에서 사용되는 플래그 심볼들을 아래 표에서 확인할 수 있습니다.

각 플래그는 0 (지워짐) 또는 1 (설정)의 값을 가집니다.

Addition and Subtraction

1. INC and DEC Instructions

INC reg/mem
DEC reg/mem

The INC (increment) instruction adds 1 to a register or memory operand
and DEC (decrement) instruction subtracts 1 from a register or memory operand

.data
myWord WORD 1000h
.code
inc myWord				; myWord = 1001h
mov bx,myWord
dec bx					; BX = 1000h

Flags

  • The Overflow, Zero, Sign, Auxiliary Carry, and Parity flags are changed according to the value of the destination operand
  • The INC and DEC instructions do not affect the Carry flag surprisingly

INC와 DEC 명령어

INC reg/mem
DEC reg/mem

INC (증가) 명령어는 레지스터 또는 메모리 피연산자에 1을 더하고, DEC (감소) 명령어는 레지스터 또는 메모리 피연산자에서 1을 뺍니다.

플래그

  • 오버플로, 제로, 부호, 보조 캐리 및 패리티 플래그는 대상 피연산자의 값에 따라 변경됩니다.
  • 놀랍게도 INC와 DEC 명령어는 캐리 플래그에 영향을 주지 않습니다.

2. ADD Instruction

Add a source operand to a destination operand of the same size

ADD dest,source
  • Source is unchanged by the operation, and the sum is stored in the destination operand
  • The set of possible operands is the same as for the MOV instruction
.data
var1 DWORD 10000h
var2 DWORD 20000h
.code
mov eax,var1			; EAX = 10000h
add eax,var2			; EAX = 30000H

Flags

  • The Carry, Zero, Sign, Overflow, Auxiliary Carry, and Parity flags are changed according to the value that is placed in the destination operand

2.ADD 명령어
동일한 크기의 피연산자인 소스 피연산자를 대상 피연산자에 더합니다.

  • 연산으로 인해 소스는 변경되지 않으며, 합계는 대상 피연산자에 저장됩니다.
  • 가능한 피연산자의 집합은 MOV 명령어와 동일합니다.

플래그

  • 캐리, 제로, 부호, 오버플로, 보조 캐리 및 패리티 플래그는 대상 피연산자에 배치되는 값에 따라 변경됩니다.

3. SUB Instruction

Subtract a source operand from a destination operand

SUB dest,source
  • The set of possible operands is the same as for the ADD and MOV instruction
.data
var1 DWORD 30000h
var2 DWORD 10000h
.code
mov eax,var1			; EAX = 30000h
sub eax,var2			; EAX = 20000h

Flags

  • The Carry, Zero, Sign, Overflow, Auxiliary Carry, and Parity flags are changed according to the value that is placed in the destination operand

3.SUB 명령어
소스 피연산자를 대상 피연산자에서 뺍니다.

  • 가능한 피연산자 집합은 ADD와 MOV 명령어와 동일합니다.

    플래그
  • 캐리, 제로, 부호, 오버플로, 보조 캐리 및 패리티 플래그는 대상 피연산자에 배치되는 값에 따라 변경됩니다.

4. NEG Instruction (negate)

Reverses the sign of a number by converting the number to its two’s complement

NEG reg
NEG mem
  • The two’s complement of a number can be found by reversing all the bits in the destination operand and adding 1

Flags

  • The Carry, Zero, Sign, Overflow, Auxiliary Carry, and Parity flags are changed according to the value that is placed in the destination operand

4.NEG 명령어 (부정)
숫자의 부호를 바꾸기 위해 숫자를 2의 보수로 변환합니다.

  • 숫자의 2의 보수는 대상 피연산자의 모든 비트를 반전시키고 1을 더함으로써 찾을 수 있습니다.

플래그

  • 캐리, 제로, 부호, 오버플로, 보조 캐리 및 패리티 플래그는 대상 피연산자에 배치되는 값에 따라 변경됩니다.

5. Implementing Arithmetic Expressions

Now, you can simulate what a C++ compiler might do when a statement such as this:

Rval = -Xval + (Yval - Zval);

Suppose that the following signed 32-bit variables will be used

Rval SDWORD ?
Xval SDWORD 26
Yval SDWORD 30
Zval SDWORD 40

First, we negate a copy of Xval and store it in a register
Then Yval is copied to a register and Zval is subtracted
Finally, the two terms (in EAX and EBX) are added

; first term: -Xval
mov eax,Xval
neg eax					; EAX = -26

; second term: (Yval - Zval)
mov ebx,Yval
sub ebx,Zval			; EBX = -10

; add the terms and store;
add eax,ebx
mov Rval,eax			; -36

5.산술 표현식 구현
이제 다음과 같은 문장이 C++ 컴파일러에서 어떻게 처리되는지 시뮬레이션할 수 있습니다:

다음과 같은 부호 있는 32비트 변수가 사용된다고 가정합니다.

먼저 Xval의 복사본을 부정하고 레지스터에 저장합니다.
그런 다음 Yval을 레지스터에 복사하고 Zval을 뺍니다.
마지막으로 두 항 (EAX 및 EBX)을 더합니다.

6. Flags Affected by Addition and Subtraction

When executing arithmetic instructions, we often want to know something about the result

  • Is it negative, positive, or zero?
  • Is it too large or too small to fit into the destination operand?
  • Answers to such questions can help us detect calculation errors

We use the values of CPU status flags

  • To check the outcome of arithmetic operations
  • To activate conditional branching instructions, the basic tools of program logic

A quick overview of the status flags

  • The Carry flag indicates unsigned integer overflow
    • E.g.) if an instruction has an 8-bit destination operand but the instruction generates a result larger than 11111111 binary, the Carry flag is set
  • The Overflow flag indicates signed integer overflow
    • E.g.) if an instruction has a 16-bit destination operand but it generates a negative result smaller than -32,768 decimal, the Overflow flag is set
  • The Zero flag indicates that an operation produced zero
    • E.g.) if an operand is subtracted from another of equal value, the Zero flag is set
  • The Sign flag indicates that an operation produced a negative result
    • If the most significant bit (MSB) of the destination operand is set, the Sign flag is set
  • The Parity flag indicates whether or not an even number of 1 bits occurs in the least significant byte of the destination operand, immediately after an arithmetic or boolean instruction has executed
  • The Auxiliary Carry flag is set when a 1 bit carries out of position 3 in the least significant byte of the destination operand

Unsigned Operations: Zero, Carry, and Auxiliary Carry

  • The Zero flag is set when the result of an arithmetic operation equals zero
mov ecx,1
sub ecx,1				; ECX = 0, ZF =1
mov eax,0FFFFFFFFh
inc eax					; EAX = 0, ZF = 1
inc eax					; EAX = 1, ZF = 0
dec eax					; EAX = 0, ZF = 1
  • Addition and the Carry Flag
    • When adding two unsigned integers, the Carry flag is a copy of the carry out of the MSB of the destination operand
    • CF = 1 when the sum exceeds the storage size of its destination operand
mov al,0FFh
add al,1			; AL = 00, CF = 1

mov ax,00FFg
add ax,1			; AX = 0100h, CF = 0		

mov ax,0FFFFg
add ax,1			; AX = 0000, CF = 1

Unsigned Operations: Zero, Carry, and Auxiliary Carry

  • Subtraction and the Carry Flag
    • A subtract operation sets the Carry flag when a larger unsigned integer is subtracted from a smaller one
      mov al,1
      sub al,2			; AL = FFh, CF = 1
    • The INC and DEC instructions do not affect the Carry flag
    • Applying the NEG instruction to a nonzero operand always sets the Carry flag
  • Auxiliary Carry Flag (AC)
    • Indicate a carry or borrow out of bit 3 in the destination operand
    mov al,0Fh
    add al,1					; AC = 1
  • Parity Flag (PF)
    • This flag is set when the least significant byte of the destination has an even number of 1 bits
    mov al,10001100b
    add al,00000001b			; AL = 10001110, PF = 1
    sub al,10000000b			; AL = 00001110, PF = 0

Signed Operations: Sign and Overflow Flags

  • Sign Flag

    • This flag is set when the result of a signed arithmetic operation is negative
    mov eax,4
    sub eax,5				; EAX = -1, SF = 1
    • From a mechanical point of view, the Sign flag is a copy of the destination operand’s high bit
    mov bl,1				; BL = 01h
    sub bl,2				; BL = FFh (-1), SF = 1
  • Overflow Flag

    • This flag is set when the result of a signed arithmetic operation overflows or underflows the destination operand
    mov al, +127
    add al,1				; OF = 1
    
    mov al,-128
    sub al,1				; OF = 1
  • The Addition Test

    • Overflow occurs when
      • » Adding two positive operands generates a negative sum
      • » Adding two negative operands generates a positive sum
    • Overflow never occurs when the signs of two addition operands are different
  • How the Hardware Detects Overflow

    • The CPU uses an interesting mechanism to determine the state of the Overflow flag after an addition or subtraction operation
    • The value that carries out of the highest bit position is XORed with the carry into the high bit of the result
    • The resulting value is placed in the Overflow flag
  • NEG Instruction

    • Produce an invalid result if the destination operand cannot be stored correctly
    mov al,-128				; AL = 10000000b
    neg al					; AL = 10000000b, OF = 1
    
    mov al,+127				; AL = 01111111b
    neg al					; AL = 10000001b, OF = 0
  • The CPU does NOT know whether an arithmetic operation is signed or unsigned!

    • You (the programmer) decide which flags to interpret and which to ignore, based on your knowledge of the type of operation performed

6.덧셈과 뺄셈에 의해 영향을 받는 플래그
산술 명령어를 실행할 때 결과에 대해 알고 싶은 것이 종종 있습니다.

  • 결과가 음수, 양수, 아니면 0인가요?
  • 결과가 대상 피연산자에 저장하기에 너무 크거나 작은가요?
  • 이러한 질문에 대한 답변은 계산 오류를 발견하는 데 도움이 됩니다.

CPU 상태 플래그의 값을 사용합니다.

  • 산술 연산의 결과를 확인하기 위해
  • 조건 분기 명령어를 활성화하여 프로그램 로직의 기본 도구를 사용합니다.

상태 플래그의 간단한 개요입니다.

  • 캐리(Carry) 플래그는 부호 없는 정수 오버플로를 나타냅니다.
    • 예: 명령어가 8비트 대상 피연산자를 가지고 있지만 명령어가 11111111 이진수보다 큰 결과를 생성하면 캐리 플래그가 설정됩니다.
  • 오버플로(Overflow) 플래그는 부호 있는 정수 오버플로를 나타냅니다.
    • 예: 명령어가 16비트 대상 피연산자를 가지고 있지만 -32,768보다 작은 음수 결과를 생성하면 오버플로 플래그가 설정됩니다.
  • 제로(Zero) 플래그는 연산이 0을 생성했음을 나타냅니다.
    • 예: 같은 값을 가진 피연산자에서 다른 피연산자를 빼면 제로 플래그가 설정됩니다.
  • 부호 플래그는 연산이 음수 결과를 생성했음을 나타냅니다.
    • 대상 피연산자의 최상위 비트(MSB)가 설정되면 부호 플래그가 설정됩니다.
  • 패리티 플래그는 산술 또는 부울 명령어가 실행된 직후 대상 피연산자의 최하위 바이트에서 1 비트의 짝수 개수가 발생하는지 여부를 나타냅니다.
  • 보조 캐리 플래그는 대상 피연산자의 최하위 바이트에서 3 위치에서 1 비트가 나올 때 설정됩니다.

부호 없는 연산: 제로, 캐리 및 보조 캐리

  • 제로(Zero) 플래그는 산술 연산 결과가 0과 같을 때 설정됩니다.
  • 덧셈과 캐리(Carry) 플래그
    • 두 부호 없는 정수를 더할 때 캐리 플래그는 대상 피연산자의 최상위 비트(MSB)에서 나온 캐리의 복사본입니다.
    • 합이 대상 피연산자의 저장 크기를 초과하면 CF = 1이 됩니다.
  • 뺄셈과 캐리 플래그
    • 더 큰 부호 없는 정수에서 더 작은 정수를 뺄 때 뺄셈 연산은 캐리 플래그를 설정합니다.
    • INC 및 DEC 명령어는 캐리 플래그에 영향을 주지 않습니다.
    • 0이 아닌 피연산자에 NEG 명령어를 적용하면 항상 캐리 플래그가 설정됩니다.
  • 보조 캐리 플래그 (AC)
    • 대상 피연산자의 비트 3에서 캐리나 차용이 발생하면 나타납니다.
  • 패리티 플래그 (PF)
    • 대상의 최하위 바이트에 1 비트의 짝수 개수가 있을 때 설정됩니다.

부호 있는 연산: 부호 및 오버플로 플래그

  • 부호(Sign) 플래그
    • 부호 있는 산술 연산의 결과가 음수일 때 설정됩니다.
    • 기계적 관점에서 부호 플래그는 대상 피연산자의 최상위 비트(high bit)의 복사본입니다.
  • Overflow Flag (오버플로 플래그)
    • 오버플로 플래그는 signed 산술 연산의 결과가 대상 피연산자를 오버플로(overflow) 또는 언더플로(underflow)시킬 때 설정됩니다.
  • 덧셈 테스트 (The Addition Test)
    • 오버플로가 발생하는 경우:
      • 양수 두 개를 더했을 때 음수 합계가 생성되는 경우
      • 음수 두 개를 더했을 때 양수 합계가 생성되는 경우
    • 덧셈 피연산자의 부호가 다른 경우 오버플로가 발생하지 않습니다.
  • 하드웨어에서 오버플로를 감지하는 방법
    • CPU는 덧셈이나 뺄셈 연산 후 오버플로 플래그의 상태를 결정하기 위해 흥미로운 메커니즘을 사용합니다.
    • 최상위 비트 위치에서 carry out된 값은 결과의 최상위 비트에 carry in된 값과 XOR됩니다.
    • 결과값이 오버플로 플래그에 저장됩니다.
  • NEG Instruction
    • 대상 피연산자를 제대로 저장할 수 없는 경우 잘못된 결과를 생성합니다.
    • CPU는 산술 연산이 signed 또는 unsigned인지 CPU는 알 수 없습니다. 프로그래머인 당신이 수행된 연산의 유형에 대한 지식에 기반하여 해석할 플래그와 무시할 플래그를 결정해야 합니다.
    • 즉, 프로그래머는 연산이 signed인지 unsigned인지를 고려하여 적절한 플래그를 사용해야 합니다. 예를 들어, signed 연산의 경우 Sign 플래그와 Overflow 플래그를 사용하여 결과가 정확한지 확인할 수 있습니다. 반면에 unsigned 연산의 경우 Carry 플래그를 사용하여 결과가 올바른지 확인할 수 있습니다. 이렇게 프로그래머는 연산의 유형에 따라 플래그를 해석하여 올바른 결과를 얻을 수 있습니다.

7. Example Program (AddSubTest)

; Addition and Subtraction (AddSubTest.asm)
.386
.model flat,stdcall
.stack 4096
ExitProcess proto,dwExitCode:dword
.data
Rval SDWORD ?
Xval SDWORD 26
Yval SDWORD 30
Zval SDWORD 40

.code
main PROC
	; INC and DEC
    mov ax,1000h
    inc ax						; 1001h
    dec ax						; 1000h
    
    ; Expression: Rval = -Xval + (Yval - Zval)
    mov eax,Xval
    neg eax						; -26
    mov ebx,Yval
    sub ebx,Zval				; -10
    add eax,ebx
    mov Rval,eax				; -36
    
    ; Zero flag example:
    mov cx,1
    sub cx,1					; ZF = 1
    mov ax,0FFFFh
    inc ax						; ZF = 1
    
    ; Sign flag example:
    mov cx,0
    sub cx,1					; SF = 1
    mov ax,7FFFg
    add ax,2					; SF = 1

	; Carry flag example:
    mov al,0FFh
    add al,1					; CF = 1, AL = 00
    
    ; Overflow flag example:
    mov al,+127
    add al,1					; OF = 1
    mov al,-128
    sub al,1					; OF = 1

	INVOKE ExitProcess,0
main ENDP
END main

Data-Related Operators and Directives

  • Data-related operators and directives are not executable instructions
    • instead, they are interpreted by the assembler
  • You can use assembly language directives to get information about the addresses and size characteristics of data
    • The OFFSET operator returns the distance of a variable from the beginning of its enclosing segment
    • The PTR operator lets you override an operand’s default size
    • The TYPE operator returns the size (in bytes) of an operand or of each element in an array
    • The LENGTHOF operator returns the number of elements in an array
    • The SIZEOF operator returns the number of bytes used by an array initializer

데이터 관련 연산자와 지시문

  • 데이터 관련 연산자와 지시문은 실행 가능한 명령어가 아닙니다.
    • 대신 어셈블러에 의해 해석됩니다.
  • 어셈블리 언어 지시문을 사용하여 데이터의 주소 및 크기 특성에 대한 정보를 얻을 수 있습니다.
    • OFFSET 연산자는 변수가 속한 세그먼트의 시작부터 변수까지의 거리를 반환합니다.
    • PTR 연산자는 피연산자의 기본 크기를 재정의할 수 있게 해줍니다.
    • TYPE 연산자는 피연산자의 크기(바이트 단위) 또는 배열의 각 요소를 반환합니다.
    • LENGTHOF 연산자는 배열의 요소 개수를 반환합니다.
    • SIZEOF 연산자는 배열 초기화식에 사용된 바이트 수를 반환합니다.

1. OFFSET Operator

  • Return the offset of a data label
    • The offset represents the distance, in bytes, of the label from the beginning of the data segment
  • OFFSET Examples
    • Suppose that bVal were located at offset 00404000 (hexadecimal)
    .data
    bVal BYTE ?
    wVal WORD ?
    dVal DWORD ?
    dVal2 DWORD ?
    mov esi,OFFSET bVal				; ESI = 00404000h
    mov esi,OFFSET wVAL				; ESI = 00404001h
    mov esi,OFFSET dVal				; ESI = 00404003h
    mov esi,OFFSET dVal2				; ESI = 00404007h
  • OFFSET can also be applied to a direct-offset operand
    .data
    myArray WORD 1,2,3,4,5
    .code
    mov esi,OFFSET myArray + 4
    • ESI points to the third integer in the array
  • You can initialize a doubleword variable with the offset of another variable, effectively creating a pointer
    .data
    bigArray DWORD 500 DUP (?)
    pArray DWORD bigArray
    mov esi.pArray
    • pArray points to the beginning of bigArray
    • The pointer’s value is loaded into ESI, so the register can point to the beginning of the array

1.OFFSET 연산자

  • 데이터 레이블의 오프셋을 반환합니다.
    • 오프셋은 레이블이 데이터 세그먼트 시작점으로부터 바이트 단위로 얼마나 떨어져 있는지를 나타냅니다.
  • OFFSET 예제
    • 예를 들어 bVal이 오프셋 00404000(16진수)에 위치한다고 가정합니다.
    • OFFSET은 직접 오프셋 피연산자에도 적용할 수 있습니다.
    • ESI는 배열의 세 번째 정수를 가리킵니다.
    • 또 다른 변수의 오프셋으로 더블워드 변수를 초기화하여 포인터를 만들 수 있습니다.
    • pArray는 bigArray의 시작을 가리킵니다.
    • 포인터의 값이 ESI에 로드되므로 레지스터가 배열의 시작을 가리킬 수 있습니다.

2. ALIGN Directive

  • Aligns a variable on a byte, word, doubleword, or paragraph boundary
    ALIGN bound
    • Bound can be 1, 2, 4, 8, or 16
      • 1: the next variable is aligned on a 1-byte boundary (the default)
      • 2: the next variable is aligned on an even-numbered address
      • 4: the next address is a multiple of 4
      • 16: the next address is a multiple of 16, a paragraph boundary
    • The assembler can insert one or more empty bytes before the variable to fix the alignment
    • The CPU can process data stored at even-numbered addresses more quickly than those at odd-numbered addresses
      bVal BYTE ?				; 00404000h
      ALIGN 2
      wVal WORD ?				; 00404002h
      bVal2 BYTE ?				; 00404004h
      ALIGN 4
      dVal DWORD ? 				; 00404008h
      dVal2 DWORD ?				; 0040400Ch

2.ALIGN 지시문

  • 변수를 바이트, 워드, 더블워드 또는 문단 경계에 정렬합니다.
  • Bound는 1, 2, 4, 8 또는 16이 될 수 있습니다.
    • 1: 다음 변수가 1바이트 경계에 정렬됩니다(기본값).
    • 2: 다음 변수가 짝수 주소에 정렬됩니다.
    • 4: 다음 주소가 4의 배수입니다.
    • 16: 다음 주소가 16의 배수이며 문단 경계입니다.
  • 어셈블러는 변수 앞에 하나 이상의 빈 바이트를 삽입하여 정렬을 수정할 수 있습니다.
  • CPU는 짝수 주소에 저장된 데이터를 홀수 주소에 저장된 데이터보다 더 빠르게 처리할 수 있습니다.
    bVal BYTE ?				; 00404000h
    ALIGN 2
    wVal WORD ?				; 00404002h
    bVal2 BYTE ?				; 00404004h
    ALIGN 4
    dVal DWORD ? 				; 00404008h
    dVal2 DWORD ?				; 0040400Ch

3. PTR Operator

  • You can use the PTR operator to override the declared size of an operand
  • This is only necessary when you’re trying to access the operand using a size attribute that is different from the one assumed by the assembler
    .data
    myDouble DWORD 12345678h
    .code
    mov ax,myDouble				;error
    • The WORD PTR operator makes it possible to move the low-order word (5678h) to AX
      mov ax, WORD PTR myDouble
      • x86 processors use the little endian storage format, in which the low-order byte is stored at the variable’s starting address
  • PTR must be used in combination with one of the standard assembler data types, BYTE, SBYTE, WORD, SWORD, DWORD, SDWORD, FWORD, QWORD, or TBYTE.
.data
myDouble DWORD 12345678h
.code
mov ax,myDouble						; error
mov ax,WORD PTR myDouble	

mov ax,WORD PTR [myDouble+2]		; 1234h
mov bl,BYTE PTR myDouble			; 78h

  • Moving Smaller Values into Larger Destinations
.data
wordList WORD 5678h,1234h
.code
mov eax,DWORD PTR wordList			; EAX = 12345678h

3.PTR Operator

  • PTR 연산자를 사용하여 피연산자의 선언된 크기를 재정의할 수 있습니다.
  • 이는 어셈블러가 가정한 것과 다른 크기 속성을 사용하여 피연산자에 접근하려고 할 때만 필요합니다.
  • WORD PTR 연산자를 사용하면 하위 워드(5678h)를 AX로 이동시킬 수 있습니다.
  • x86 프로세서는 하위 바이트가 변수의 시작 주소에 저장되는 리틀 엔디안 저장 형식을 사용합니다.
  • PTR는 BYTE, SBYTE, WORD, SWORD, DWORD, SDWORD, FWORD, QWORD 또는 TBYTE 중 하나의 표준 어셈블러 데이터 유형과 함께 사용해야 합니다.

    위의 예제에서 PTR 연산자를 사용하여 변수의 실제 선언된 크기와 다른 크기의 데이터를 처리하는 방법을 확인할 수 있습니다.

4. TYPE Operator

  • Return the size, in bytes, of a single element of a variable
.data
var1 BYTE ?
var2 WORD ?
var3 DWORD ?
var4 QWORD ?
Expressionvalue
TYPE var 11
TYPE var 22
TYPE var 34
TYPE var 48

4.TYPE Operator

  • TYPE 연산자는 변수의 단일 요소의 크기(바이트 단위)를 반환합니다.

    TYPE 연산자를 사용하면 각 변수의 크기를 바이트 단위로 확인할 수 있습니다. 이는 특정 변수나 배열의 크기를 계산하거나 처리할 때 유용하게 사용됩니다.

5. LENGTHOF Operator

– Count the number of elements in an array, defined by the values appearing on the same line as its label

  1. LENGTHOF Operator
  • LENGTHOF 연산자는 레이블과 같은 줄에 나타나는 값에 의해 정의된 배열의 요소 수를 계산합니다.

    이 연산자를 사용하면 배열 내의 요소 수를 확인할 수 있으며, 이는 배열을 처리할 때 반복문의 범위를 결정하는 데 유용하게 사용될 수 있습니다.

6. SIZEOF Operator

  • Returns a value that is equivalent to multiplying LENGTHOF by TYPE
.data
intArray WORD 32 DUP(0)
.code
mov eax,SIZEOF intArray			; EAX = 64

6.SIZEOF Operator

  • SIZEOF 연산자는 LENGTHOF와 TYPE을 곱한 값과 동일한 값을 반환합니다.

    SIZEOF를 사용하면 변수나 배열이 차지하는 전체 바이트 크기를 얻을 수 있습니다. 이는 메모리 할당이나 복사 작업을 수행할 때 유용하게 사용됩니다.

7. LABEL Directive

  • This directive lets you insert a label and give it a size attribute without allocating any storage
    • All standard size attributes (BYTE, WORD, …) can be used with LABEL
  • A common use of LABEL is to provide an alternative name and size attribute for the variable declared next in the data segment
.data
val16 LABEL WORD
val32 DWORD 12345678h
.code
mov ax,val16				; AX = 5678h
mov dx,[val16+2]			; DX = 1234h

val16 is an alias for the same storage location as val32.
The LABEL directive itself allocates no storage

.data
LongValue LABEL DWORD
val1 WORD 5678h
val2 WORD 1234h
.code
mov eax,LongValue			; EAX = 12345678h

Sometimes we need to construct a larger integer from two smaller integers.

7.LABEL Directive

  • 이 디렉티브를 사용하면 레이블을 삽입하고 크기 속성을 지정할 수 있으며 스토리지를 할당하지 않습니다.
    • 모든 표준 크기 속성 (BYTE, WORD, ...)은 LABEL과 함께 사용할 수 있습니다.
  • LABEL의 일반적인 사용법은 데이터 세그먼트에서 다음으로 선언된 변수에 대한 대체 이름과 크기 속성을 제공하는 것입니다.

    val16은 val32와 동일한 저장 위치에 대한 별칭입니다.
    LABEL 디렉티브 자체는 스토리지를 할당하지 않습니다.

    때로는 두 개의 작은 정수로부터 더 큰 정수를 구성해야 할 경우가 있습니다. 이 경우 LABEL 디렉티브를 사용하여 두 변수를 하나의 큰 정수로 취급할 수 있습니다.

Indirect Addressing

Indirect addressing

  • Direct addressing is rarely used for array processing because it is impractical to use constant offsets to address more than a few array elements
  • Instead, we use a register as a pointer (called indirect addressing) and manipulate the register’s value
  • When an operand uses indirect addressing, it is called an indirect operand

Indirect Addressing
간접 주소 지정은 배열 처리에 대한 주소 지정 방식입니다. 상수 오프셋을 사용하여 배열 요소를 직접 주소 지정하는 것이 비효율적이기 때문에 간접 주소 지정이 필요합니다. 이 방식에서는 레지스터를 포인터로 사용하고 레지스터의 값을 조작합니다. 피연산자가 간접 주소 지정을 사용하면 간접 피연산자라고 합니다.

1. Indirect Operands

Protected Mode

  • An indirect operand can be any 32-bit general-purpose register surrounded by brackets
  • The register is assumed to contain the address of some data
    .data
    byteVal BYTE 10h
    .code
    mov esi,OFFSET byteVal
    mov al,[esi]					; AL = 10h
    • MOV instruction uses the indirect operand as the source, the offset in ESI is dereferenced, and a byte is moved to AL
  • If the destination operand uses indirect addressing, a new value is placed in memory at the location pointed to by the register
    mov [esi],bl
    • The contents of the BL register are copied to the memory location addressed by ESI

Using PTR with Indirect Operands

  • The size of an operand may not be evident from the context of an instruction
    inc [esi]				; error: operand must have size
    inc BYTE PTR [esi]
    • The PTR operator confirms the operand size

1.Indirect Operands
보호 모드(Protected Mode)에서 간접 피연산자는 대괄호로 둘러싸인 32비트 범용 레지스터가 될 수 있습니다. 레지스터는 데이터의 주소를 포함한다고 가정합니다.

MOV 명령어에서 간접 피연산자를 소스로 사용하면 ESI의 오프셋이 참조 해제되고 바이트가 AL로 이동합니다. 대상 피연산자가 간접 주소 지정을 사용하면 레지스터가 가리키는 위치에 새 값이 메모리에 배치됩니다.

BL 레지스터의 내용이 ESI가 주소 지정하는 메모리 위치에 복사됩니다.
간접 피연산자를 사용할 때 명령어의 맥락에서 피연산자의 크기를 명확하게 파악할 수 없는 경우 PTR 연산자를 사용하여 피연산자 크기를 확인할 수 있습니다.

2. Arrays

Indirect operands are ideal tools for stepping through arrays

.data
arrayB BYTE 10h,20h,30h
.code
mov esi,OFFSET arrayB
mov al,[esi]				; AL = 10h
inc esi
mov al,[esi]				; AL = 20h
inc esi
mov al,[esi]				; AL = 30h
  • If we use an array of 16-bit integers, we add 2 to ESI to address each subsequent array element
.data
arrayW WORD 1000h,2000h,3000h
.code
mov esi,OFFSET arrayW
mov al,[esi]				; AL = 1000h
inc esi,2
mov al,[esi]				; AL = 2000h
inc esi,2
mov al,[esi]				; AL = 3000h

Example: Adding 32-Bit Integers

.data
arrayD DWORD 10000h,20000h,30000h
.code
mov esi,OFFSET arrayD
mov eax,[esi]				; first number
inc esi,4
mov eax,[esi]				; second number
inc esi,4
mov eax,[esi]				; third number

2.Arrays
간접 피연산자는 배열을 순회하는 데 이상적인 도구입니다.

16비트 정수 배열을 사용하는 경우, 각 연속 배열 요소의 주소를 지정하기 위해 ESI에 2를 더합니다.

예시: 32비트 정수 더하기

위 예제에서는 ESI 레지스터를 사용하여 배열 arrayD의 오프셋을 가져옵니다. 그리고 각 배열 요소를 더하고 그 결과를 EAX 레지스터에 저장합니다. ESI 레지스터에 4를 더하여 각 배열 요소에 접근할 수 있습니다. 이 예제에서는 세 개의 32비트 정수를 더하는 방법을 보여줍니다. EAX 레지스터에는 최종 합계 값이 저장됩니다.

3. Indexed Operands

  • An indexed operand adds a constant to a register to generate an effective address

  • Any of the 32-bit general-purpose registers may be used as index registers

    • The first notational form combines the name of a variable with a register

      • The variable name is translated by the assembler into a constant that represents the variable’s offset
      arrayB[esi][arrayB + esi]
      arrayD[ebx][arrayD + ebx]
  • Indexed operands are ideally suited to array processing

    • The index register should be initialized to zero before accessing the first array element
    .data
    arrayB BYTE 10h,20h,30h
    .code
    mov esi,0
    mov al,arrayB[esi]
    • The last statement adds ESI ti the offset of arrayB
    • The address generated by the expression [arrayB + ESI] is dereferenced and the byte in memory is copied to AL
  • Adding Displacements

    • The second type of indexed addressing combines a register with a constant offset
    • The index register holds the base address of an array or structure, and the constant identifies offsets of various array elements
    data
    arrayW WORD 1000h,2000h,3000h
    .code
    mov esi,OFFSET arrayW
    mov ax,[esi]			; AX = 1000h
    mov ax,[esi+2]		; AX = 2000h
    mov ax,[esi+4]		; AX = 3000h
  • Using 16-Bit Registers

    • It is usual to use 16-bit registers as indexed operands in real-address mode
      • In that case, you are limited to using SI, DI, BX, or BP
      mov al,arrayB[si]
      mov ax,arrayW[di]
      mov eax,arrayD[bx] 
  • Scale Factors in Indexed Operands

    • Indexed operands must take into account the size of each array element when calculating offsets
    .data
    arrayD DWORD 100h, 200h, 300h, 400h
    .code
    mov esi,3 * TYPE arrayD				; offset of arrayD[3]
    mov eax,arrayD[esi]					; EAX = 400h
    • Intel designers wanted to make a common operation easier for compiler writers, so they provided a way for offsets to be calculated, using a scale factor
    • The scale factor is the size of the array component (word = 2, doubleword = 4, or quadword = 8)
.data
arrayD DWORD 1,2,3,4
.code
mov esi,3						; subscript
mov eax,arrayD[esi*4]			; EAX = 4

mov esi,3						; subscript
mov eax,arrayD[esi*TYPE arrayD]	;EAX

3.인덱스 피연산자(Indexed Operands)

  • 인덱스 피연산자는 레지스터에 상수를 더하여 유효한 주소를 생성합니다.
  • 모든 32비트 범용 레지스터는 인덱스 레지스터로 사용될 수 있습니다.
  • 첫 번째 표기법은 변수 이름과 레지스터를 결합합니다.
    • 변수 이름은 어셈블러에 의해 변수의 오프셋을 나타내는 상수로 변환됩니다.
  • 인덱스 피연산자는 배열 처리에 이상적입니다.
    • 인덱스 레지스터는 첫 번째 배열 요소에 접근하기 전에 0으로 초기화되어야 합니다.
    • 마지막 문장은 ESI를 arrayB의 오프셋에 더합니다.
    • [arrayB + ESI] 표현식으로 생성된 주소는 역참조되고 메모리의 바이트가 AL로 복사됩니다.
  • 상수 더하기
    • 레지스터와 상수 오프셋을 결합하는 인덱스 주소 지정의 두 번째 유형입니다.
    • 인덱스 레지스터는 배열이나 구조의 기본 주소를 유지하고, 상수는 각 배열 요소의 오프셋을 식별합니다.
  • 16비트 레지스터 사용
    • 실 주소 모드에서 16비트 레지스터를 인덱스 피연산자로 사용하는 것이 일반적입니다.
      • 이 경우 SI, DI, BX, 또는 BP만 사용할 수 있습니다.
  • 인덱스 피연산자의 스케일 요소
    • 인덱스 피연산자는 오프셋을 계산할 때 배열 요소의 크기를 고려해야 합니다.
    • 인텔 설계자들은 컴파일러 작성자들이 일반적인 작업을 더 쉽게 수행할 수 있도록 오프셋을 계산하기 위해 스케일 요소를 사용하는 방법을 제공하고 싶었습니다.
    • 스케일 요소는 배열 구성 요소의 크기입니다(워드 = 2, 더블워드 = 4, 쿼드워드 = 8).

이러한 스케일 요소를 사용하면 배열 인덱스에 따라 오프셋을 보다 효율적으로 계산할 수 있습니다. 첨자(subscript)와 배열 요소의 크기를 곱하여 오프셋을 생성하므로 배열 요소에 더 쉽게 접근할 수 있습니다. 이 기능은 배열 처리를 더 간단하게 만들어 주며, 컴파일러가 생성한 코드를 최적화하는 데 도움이 됩니다.

4. Pointers

  • A variable containing the address of another variable is called a pointer
  • Pointers are a great tool for manipulating arrays and data structures because the address they hold can be modified at runtime
    • E.g.) You might use a system call to allocate a block of memory and save the address of that block in a variable
  • A pointer’s size is affected by the processor’s current mode (32-bit or 64-bit)
    .data
    arrayB byte 10h,20h,30h,40h
    prtB dword arrayB
    • In this 32-bit code example, ptrB contains the offset of arrayB
    • Optionally, you can declare ptrB with the OFFSET operator to make the relationship clearer:
    ptrB dword OFFSET arrayB
  • The 32-bit mode programs in this course use near pointers, so they are stored in doubleword variables
arrayB BYTE 10h,20h,30h,40h
arrayW WORD 1000h,2000h,3000h

ptrB DWORD arrayB
ptrW DWORD arrayW

ptrB DWORD OFFSET arrayB
ptrW DWORD OFFSET arrayW
  • Using the TYPEDEF Operator
    • The TYPEDEF operator lets you create a user-defined type that has all the status of a built-in type when defining variables
    • TYPEDEF is ideal for creating pointer variables
      • E.g.) The following declaration creates a new data type PBYTE that is a pointer to bytes:
      PBYTE TYPEDEF PTR BYTE
      .data
      arrayB BYTE 10h,20h,30h,40h
      ptr1 PBYTE ?		;uninitialized
      ptr2 PBYTE arrayB	; points to an array
      • » This declaration would usually be placed near the beginning of a program, before the data segment
      • » Then, variables could be defined using PBYTE
  • Example Program: Pointers
    • This program uses TYPDEF to create three pointer types (PBYTE, PWORD, PDWORD)
    • It creates several pointers, assigns several array offsets, and dereferences the pointers
TITLE Pointers		(Pointers.asm)
.386
.model flat,stdcall
.stack 4096
ExitProcess proto,dwExitCode:dword
;Create user-defined types
PBYTE TYPEDEF PTR BYTE				; pointer to bytes
PBYTE TYPEDEF PTR WORD				; pointer to words
PBYTE TYPEDEF PTR DWORD				; pointer to doublewords

.data
arrayB BYTE 10h,20h,30h
arrayW WORD 1,2,3
arrayD DWORD 4,5,6

;Create sine pointer variables
ptr1 PBYTE arrayB
ptr2 PWORD arrayW
ptr3 PDWORD arrayD

.code
main PROC
; Use the pointers to access data.
	mov esi,ptr1
    mov al,[esi]				; 10h
    mov esi,ptr2
    mov ax,[esi]				; 1
    mov esi,ptr3
    mov al,[esi]				; 4
    invoke ExitProcess,0
 main ENDP
 END main

4.포인터

  • 포인터는 다른 변수의 주소를 포함하는 변수를 의미합니다.
  • 포인터는 배열 및 데이터 구조를 조작하는 데 유용한 도구입니다. 왜냐하면 포인터가 가지고 있는 주소를 런타임에 수정할 수 있기 때문입니다.
    • 예를 들어, 메모리 블록을 할당하기 위한 시스템 호출을 사용하고 해당 블록의 주소를 변수에 저장할 수 있습니다.
  • 포인터의 크기는 프로세서의 현재 모드(32비트 또는 64비트)에 영향을 받습니다.
  • 이 32비트 코드 예제에서 ptrB는 arrayB의 오프셋을 포함합니다.
  • 선택적으로 OFFSET 연산자를 사용하여 ptrB를 선언하여 관계를 명확하게 할 수 있습니다.
  • 이 과정에서 사용하는 32비트 모드 프로그램은 근처(near) 포인터를 사용하므로, 이들은 더블워드 변수에 저장됩니다
  • TYPEDEF 연산자 사용
    • TYPEDEF 연산자를 사용하면 변수를 정의할 때 내장된 유형의 모든 상태를 가진 사용자 정의 유형을 생성할 수 있습니다.
    • TYPEDEF는 포인터 변수를 생성하는 데 이상적입니다.
      • 예를 들어, 다음 선언은 바이트를 가리키는 포인터인 새로운 데이터 유형 PBYTE를 생성합니다.
    • 이 선언은 일반적으로 프로그램 시작 부분 근처, 데이터 세그먼트 전에 배치됩니다.
    • 그런 다음 PBYTE를 사용하여 변수를 정의할 수 있습니다.
  • 예제 프로그램: 포인터
    • 이 프로그램은 TYPEDEF를 사용하여 3개의 포인터 유형(PBYTE, PWORD, PDWORD)을 생성합니다.
    • 여러 포인터를 생성하고, 여러 배열 오프셋을 할당하고, 포인터를 역참조합니다.

이 예제 프로그램은 다음과 같은 작업을 수행합니다:

  1. TYPEDEF를 사용하여 바이트, 워드, 더블워드를 가리키는 세 가지 포인터 유형(PBYTE, PWORD, PDWORD)을 생성합니다.
  2. .data 섹션에서 세 가지 배열(arrayB, arrayW, arrayD)과 이들에 대한 포인터(ptr1, ptr2, ptr3)를 정의합니다.
  3. .code 섹션에서 포인터를 사용하여 데이터에 접근하고 값을 읽습니다. 예를 들어, mov al,[esi] 명령은 포인터가 가리키는 주소에서 값을 읽어 AL 레지스터에 저장합니다.

이 프로그램은 포인터를 사용하여 각 배열의 첫 번째 요소에 접근하고 값을 읽습니다. 이를 확장하여 포인터를 사용해 배열 내의 다른 요소에도 접근할 수 있습니다.

JMP and LOOP Instructions

  • The CPU loads and executes programs sequentially, but an instruction might be conditional
    • It transfers control to a new location in the program based on the values of CPU status flags
  • Assembly language programs use conditional instructions to implement high-level statements such as IF statements and loops
    • Each of the conditional statements involves a possible transfer of control (jump) to a different memory address
    • A transfer of control, or branch, is a way of altering the order in which statements are executed
  • Two basic types of transfers
    • Unconditional Transfer
      • Control is transferred to a new location in all cases
      • A new address is loaded into the instruction pointer, causing execution to continue at the new address
    • Conditional Transfer
      • The program branches if a certain condition is true
      • A wide variety of conditional transfer instructions can be combined to create conditional logic structures
      • The CPU interprets true/false conditions based on the contents of the ECX and Flags registers

JMP 및 LOOP 명령어

  • CPU는 프로그램을 순차적으로 로드하고 실행하지만, 명령어는 조건부일 수 있습니다.
    • CPU 상태 플래그의 값에 따라 프로그램의 새 위치로 제어를 전달합니다.
  • 어셈블리 언어 프로그램은 조건부 명령어를 사용하여 IF 문과 루프와 같은 고수준 문장을 구현합니다.
    • 조건부 문장은 모두 다른 메모리 주소로의 제어 이전(점프)을 포함합니다.
    • 제어 이전 또는 분기는 명령문이 실행되는 순서를 변경하는 방법입니다.
  • 두 가지 기본 전송 유형
    • 무조건 전송
      • 모든 경우에 새 위치로 제어가 전달됩니다.
      • 명령 포인터에 새 주소가 로드되어 새 주소에서 실행이 계속됩니다.
    • 조건부 전송
      • 특정 조건이 참인 경우 프로그램이 분기됩니다.
      • 다양한 조건부 전송 명령어를 결합하여 조건부 논리 구조를 생성할 수 있습니다.
      • CPU는 ECX 및 Flags 레지스터의 내용을 기반으로 참/거짓 조건을 해석합니다.

1.JMP Instruction

  • This instruction causes an unconditional transfer to a destination, identified by a code label that is translated by the assembler into an offset
    JMP destination
  • The offset of destination is moved into the instruction pointer, causing execution to continue at the new location
  • Creating a Loop
    • The JMP instruction provides an easy way to create a loop by jumping to a label at the top of the loop
    top:
    		.
          	.
         jmp top			;repeat the endless loop
    • JMP is unconditional, so a loop like this will continue endlessly unless another way is found to exit the loop

1.JMP 명령어

  • 이 명령어는 어셈블러에 의해 오프셋으로 변환되는 코드 레이블로 지정된 대상으로 무조건 전송을 수행합니다
  • 목적지의 오프셋이 명령 포인터로 이동하여 새 위치에서 실행이 계속됩니다.
  • 루프 생성
    • JMP 명령어를 사용하여 루프 상단의 레이블로 점프하여 루프를 생성하는 쉬운 방법을 제공합니다.
    top:
    		.
          	.
         jmp top			;repeat the endless loop
    • JMP는 무조건적이므로 이러한 루프는 루프를 종료할 다른 방법을 찾지 않는 한 무한히 계속됩니다.

2.LOOP Instruction

– Loop According to ECX Counter
– This instruction repeats a block of statements a specific number of times
– ECX is automatically used as a counter and is decremented each time the loop repeats

LOOP destination
  • The loop destination must be within -128 to +127 bytes of the current location counter
  • The execution of the LOOP
    1. It subtracts 1 from ECX
    2. Next, it compares ECX to zero
    • If ECX is not equal to zero, a jump is taken to the label identified by destination
    • Otherwise, if ECX equals zero, no jump takes place, and control passes to the instruction following the loop
  • An example
	mov ax,0
	mov ecx,5
L1:
	inc ax
    loop L1
  • When the loop ends, AX = 5 and ECX = 0
  • A common programming error in using LOOP
    • To initialize ECX to zero before beginning a loop
      • If this happens, the LOOP instruction decrements ECX to FFFFFFFFh, and the loop repeats 4,294,967,296 times!
      • If CX is the loop counter (in real-address mode), it repeats 65,536 times
  • You might create a loop that is large enough to exceed the allowed relative jump range of the LOOP instruction
    • Following is an example of an error message generated by MASM:
    error A2075: jump destination too far : by 14 byte(s)
  • If you need to modify ECX inside a loop, you can save it in a variable at the beginning of the loop and restore it just before the LOOP instruction
.data
count DWORD ?
.code
	mov ecx,100			;set loop count
top:
	mov count,ecx		; save the count
    .
    mov ecx,20			; modify ECX
    .
    mov ecx,count		;restore loop count
    loop top
  • Nested Loops
    • When creating a loop inside another loop, you should consider the outer loop counter in ECX
    • You can save it in a variable
    .data
    count DWORD ?
    .code
      mov ecx, 100			; set outer loop count
    L1:
      mov count,ecx			; save outer loop count
      mov ecx,20				; set inner loop count
    L2:
      .
      .
      loop L2					; repeat the inner loop
      mov ecx,count			; restore outer loop count
      loop L1					; repeat the outer loop
    • As a general rule, nested loops more than two levels deep are difficult to write
    • If the algorithm you’re using requires deep loop nesting, move some of the inner loops into subroutines

2.LOOP 명령어

  • ECX 카운터에 따라 루프를 수행합니다.
  • 이 명령어는 특정 횟수만큼 문장 블록을 반복합니다.
  • ECX는 자동으로 카운터로 사용되며 루프가 반복될 때마다 감소합니다.
  • 루프 목적지는 현재 위치 카운터에서 -128에서 +127 바이트 범위 내에 있어야 합니다.
  • LOOP 명령어의 실행
    • ECX에서 1을 뺍니다.
    • 다음으로 ECX를 0과 비교합니다.
      • ECX가 0이 아닌 경우, destination으로 지정된 레이블로 점프가 수행됩니다.
      • 그렇지 않고 ECX가 0이면 점프가 발생하지 않고 제어가 루프 이후의 명령으로 전달됩니다.
  • 예시:
  • 루프가 끝날 때, AX = 5 및 ECX = 0입니다.
  • LOOP를 사용할 때 일반적인 프로그래밍 오류
    • 루프 시작 전에 ECX를 0으로 초기화합니다.
    • 이렇게 되면, LOOP 명령어가 ECX를 FFFFFFFFh로 감소시키고 루프가 4,294,967,296회 반복됩니다!
    • CX가 루프 카운터인 경우(실주소 모드에서), 65,536회 반복됩니다.
  • LOOP 명령어의 허용되는 상대 점프 범위를 초과하는 충분히 큰 루프를 생성할 수 있습니다.
    • 다음은 MASM에서 생성하는 오류 메시지의 예입니다.
  • 루프 내에서 ECX를 수정해야 할 경우, 루프 시작 부분에서 변수에 저장하고 LOOP 명령어 바로 전에 복원할 수 있습니다.
  • 중첩 루프
    • 다른 루프 내에 루프를 생성할 때, ECX의 외부 루프 카운터를 고려해야 합니다.
    • 변수에 저장할 수 있습니다.
    • 일반적으로 두 개 이상의 레벨이 있는 중첩 루프는 작성하기 어렵습니다.
    • 사용 중인 알고리즘이 깊은 루프 중첩이 필요한 경우 내부 루프의 일부를 서브루틴으로 이동

3. Displaying an Array in the Visual Studio Debugger

  • How to display the contents of an array in a debugging session
    • From the [Debug] menu, select [Windows] – [Memory] – [Memory 1]
  • Them a memory window will appear
    • In the Address field at the top of the memory window, type the ‘&’ character, followed by the name of the array, and press Enter
      • Then, the memory window will display a block of memory starting at the array’s address
    • If your array values are doublewords, you can right-click inside the memory window and select 4-byte integer from the popup menu
    • You can also select from different formats, including Hexadecimal Display, signed decimal integer (called Signed Display), or unsigned decimal integer (called Unsigned Display) formats

3.Visual Studio 디버거에서 배열 표시하기
디버깅 세션에서 배열의 내용을 표시하는 방법입니다.

  • [Debug] 메뉴에서 [Windows] → [Memory] → [Memory 1]을 선택합니다.
  • 그러면 메모리 창이 나타납니다.
    • 메모리 창 상단의 주소 필드에 '&' 문자를 입력한 다음 배열의 이름을 입력하고 Enter 키를 누릅니다.
      • 그러면 메모리 창에 배열의 주소에서 시작하는 메모리 블록이 표시됩니다.
    • 배열 값이 더블워드인 경우 메모리 창 내에서 마우스 오른쪽 버튼을 클릭하고 팝업 메뉴에서 4바이트 정수를 선택할 수 있습니다.
    • 16진수 표시, 부호 있는 10진 정수(부호 있는 표시라고 함) 또는 부호 없는 10진 정수(부호 없는 표시라고 함) 형식을 포함한 다양한 형식을 선택할 수 있습니다.

4.Summing an Integer Array

  1. Assign the array’s address to a register that will serve as an indexed operand
  2. Initialize the loop counter to the length of the array
  3. Assign zero to the register that accumulates the sum
  4. Create a label to mark the beginning of the loop
  5. In the loop body, add a single array element to the sum
  6. Point to the next array element
  7. Use a LOOP instruction to repeat the loop
 Copying a String				(CopyStr.asm)
 .386
 .model flat,stdcall
 .stack 4096
 ExitProcess proto,dwExitCodeL:dword
 .data
 intarray DWORD 10000h,20000h,30000h,40000h
 
 .code
 main PROC
 	mov edi,OFFSET intarray			; 1: EDI = address of intarray
    mov ecx,LENGTHOF intarray		; 2: initialize loop counter
    mov eax,0						; 3: sum = 0
 L1:								; 4: mark beginning of loop
 	add eax,[edi]					; 5: add an integer
    add edi,TYPE intarray			; 6: repeat untill ECX = 0
    loop L1
    invoke ExitProcess,0
 main ENDP
 END main

4.정수 배열 합하기
1. 배열의 주소를 인덱싱된 피연산자로 사용할 레지스터에 할당합니다.
2. 루프 카운터를 배열의 길이로 초기화합니다.
3. 합계를 누적하는 레지스터에 0을 할당합니다.
4. 루프 시작 부분에 레이블을 만듭니다.
5. 루프 본문에서 배열 요소를 합계에 더합니다.
6. 다음 배열 요소를 가리키도록 합니다.
7. 루프를 반복하려면 LOOP 명령어를 사용합니다.

5.Copying a String

  • An assembly language program using a loop that copies a string, represented as an array of bytes with a null terminator value

    Copying a String				(CopyStr.asm)
    .386
    .model flat,stdcall
    .stack 4096
    ExitProcess proto,dwExitCodeL:dword
    .data
    source BYTE "This is the source string",0
    target BYTE SIZEOF source DUP(0)
    
    .code
    main PROC
    	mov esi,0				; index register
       mov ecx,SIZEOF source	; loop counter
    L1:
    	mov al,sources[esi]		; get a character from source
       mov target[esi], al		; store it in the target
       inc esi					; move to next character
       loop L1					; repeat for entire string
       
       invoke ExitProcess,0
    main ENDP
    END main
    • The MOV instruction cannot have two memory operands, so each character is moved from the source string to AL, then from AL to the target string

5.문자열 복사하기

  • 널 종료 값이 있는 바이트 배열로 표현된 문자열을 복사하는 루프를 사용하는 어셈블리 언어 프로그램입니다.

위의 예제는 다음과 같이 작동합니다.

  1. 인덱스 레지스터인 ESI를 0으로 초기화합니다.
  2. 루프 카운터인 ECX를 source 문자열의 크기로 초기화합니다.
  3. 루프(L1)가 시작됩니다.
  4. AL 레지스터에 source 문자열에서 문자를 가져옵니다.
  5. 가져온 문자를 target 문자열에 저장합니다.
  6. ESI를 증가시켜 다음 문자로 이동합니다.
  7. 전체 문자열에 대해 L1 루프를 반복합니다.

루프가 완료되면, source 문자열의 모든 문자가 target 문자열로 복사됩니다. 프로그램은 ExitProcess를 호출하여 종료합니다.

이 예제에서는 MOV 명령어가 두 개의 메모리 피연산자를 가질 수 없으므로, 각 문자를 source 문자열에서 AL로 이동한 다음, AL에서 target 문자열로 이동합니다.

profile
스벨트 자바스크립트 익히는중...

0개의 댓글