Lecture/System Programming

System Programming - Assembly Language Fundamentals, 어셈블리어

Ezcho 2023. 4. 13. 00:30

1. First Assembly Language Program

1. 두개를 더하는 프로그램

간단한 assmebly언어 프로그램이다.

1. 메인프로시저를 시작한다.(프로그램의 엔트리포인트)

2. 5를 EAX레지스터에 둔다.

3. 6을 EAX레지스터에 더한다. 새로운 값 11을 얻는다.

5. ExitProcess라는 윈도우 서비스를 호출한다. 프로그램을 멈추고 OS로 컨트롤을 반환한다.

6. 메인프로시저의 끝 표시다.

 

2. 변수를 더하는 프로그램

 

.data, .code로 데이터영역과 코드영역을 구분한다.

2. sum 변수가 선언되었다. 이상황에서 우리는 메모리에 32비트를 할당하고, 0으로 초기화한다.

 

 

2. Integer Literals

정수 리터럴은 선택적인 부호, 하나 이상의 숫자, 그리고 숫자의 기본(base)을 나타내는 선택적인 진수 문자로 이루어진 것을 말합니다.

예를들어 10진수에서 123, -456과 같은 정수 리터럴은 부호가 선택적으로 붙은 숫자들입니다.

 

양식은 (+ / -) digits (radix)

 

 

3. 상수 정수식 (Constan Integer Expression)

상수 정수식은 정수 리터럴과 산술 연산자를 사용하여 수학적 식을 만드는것을 의미합니다. 이러한 식을통해 나온 결과는 32비트로 저장됩니다. 즉, 0부터 FFFFFFFFh(16진수) 까지 값으로 표현할 수 있습니다.

 

상수 정수식은 어셈블리 타임에만 평가될 수 있으며, 실행중에는 평가될 수 없습니다. 따라서 상수 정수식의 결과는 컴파일 시점에 결정되며, 런타임에는 변하지 않습니다. 이러한 특징은 상수 값이 필요한 경우 매우 유용합니다.

 

Arithmetic operators 산수연산자

• 연산자 우선 순위: 표현식이 두 개 이상의 연산자를 포함할 때 묵시적 연산 순서

 

4. Real Number Literals(floating-point literals)

실수 리터럴 (즉, 부동 소수점 리터럴)

10진 실수 또는 16진수로 인코딩된 부동 소수점을 나타냅니다.

10진 실수

  • 부호 선택적, 정수 다음에 소수점, 선택적인 분수를 표현하는 정수, 선택적 지수가 옵니다.
  • [sign] + integer [integer] [exponent]
  • 적어도 하나의 숫자와 소수점이 필요합니다.
  • 예시: 2. | +3.0 | -44.2E+05 | 26.E5

인코딩된 실수

  •  IEEE 부동 소수점 형식을 사용하여 16진수로 실수를 나타냅니다.
  • 예시: 10진수 +1.0의 이진 표현: 0011 1111 1000 0000 0000 0000 0000 0000
  • 이 값은 어셈블리 언어에서 short real로 인코딩됩니다. 3F800000r

5. Character Literals

단일 또는 인용부호로 둘러싸인 단일문자 인데, 어셈블러는 문자의 이진 ASCII코드를 메모리에 저장합니다.

'A' = 65 or 41h 로 저장합니다.

 

6. String Literals

스페이스를 포함한 Character 의 시퀀스는 메모리에 똑같이 정수 바이트값의 시퀀스로 메모리에 저장됩니다.

the string literal “ABCD” contains the four bytes 41h, 42h, 43h, 44h

 

7. Reversed Words

리버스워드(예약어) 는 특별한 의미를 가지며 해당하는 맥락에서만 사용할 수 있는 단어들입니다.

이는 대소문자를 구분하지 않고 여러 종류들의 예약어가 있습니다.

1. MOV, ADD, MUL 같은 명령어

2. 레지스터이름(EAX)

3. 어셈블러가 프로그램을 어떻게 조립해야하는지 알려주는 지시어(directives)

4. 변수 및 피연산자의 크기와 사용 정보를 제공하는 속성(attributes), Byte, Word등이 있습니다.

5. 상수 표현식에서 사용되는 연산자(+, -, MOD 등등)

 

8. Identifiers

식별자는 프로그래머가 선택한 이름입니다. 변수, 상수, 절차 또는 코드 레이블을 식별할 수 있습니다.

식별자의 형성 규칙은 다음과 같습니다

1. 1~247자의 문자

2. 대소문자를 구분하지 않습니다.

3. 첫글자는 AtoZ or atoz or _ or @ or ? or $ 이어야 합니다.

4. 이후 문자들은 숫자일 수 있습니다.

5. 식별자는 어셈블러예약어(mov, EAX)등과 같을 수 없습니다.

 

9. Directives

지시어는 소스 코드에 포함된 명령어로 어셈블러에 의해 인식되고 처리됩니다.

1. 지시어는 실행 시간에 실행되지 않지만, 변수, 매크로 및 프로시저를 정의할 수 있습니다.

2. 지시어는 메모리 세그먼트에 이름을 할당하거나 어셈블러와 관련된 다양한 관리 작업을 수행할 수 있습니다.

3. 대소문자를 구분하지 않습니다

4. 명령어와 지시어의 차이를 보여주는 예시

  • DWORD 지시어는 프로그램에서 더블워드 변수를 위한 공간을 예약하도록 어셈블러에 지시합니다.
  • MOV명령어는 실행 시간에 myVar의 내용을 EAX레지스터에 복사합니다.

5. 인텔 프로세서를 위한 모든 어셈블러는 동일한 명령어 집합을 공유하지만, 일반적으로 서로 다른 지시어 집합을 가지고 있습니다.

지시어의 중요한 기능중 하나는 프로그램 섹션 또는 세그먼트를 정의하는 것입니다.

세그먼트란 프로그램의 다른 목적을 가진 섹션입니다.

.data 지시어는 변수를 정의하기위해 사용될 수 있는 세그먼트를 식별합니다.

.code 지시어는 실행 가능한 명령어가 포함된 프로그램의 영역을 식별합니다.

.stack 지시어는 런타임 스택을 보관하는 프로그램 영역을 식별하며 크기를 설정합니다.

예) .stack 100h는 스택의 크기를 100h(256Byte)로 설정합니다.

 

10. Instruction

instruction은 프로그램을 어셈블 할때 실행가능한 문장입니다.

어셈블러는 명령어를 기계어 바이트로 번역하여 실행시킬 수 있도록 합니다. 이 기계어 바이트는 런타임동안 CPU에 의해 로드되고 실행됩니다. 명령어는 다음과 같은 기본적인 구성 요소가 존재합니다.

1. Label: 선택

2. memonic(명령어 메모닉): 필수

3. Operands: 일반적으로 필수

4. 주석: 선택적

 

라벨은 해당 명령어를 참조하는 식별자입니다.

명령어 메모닉은 해당 명령어의 작업을 나타냅니다.

피연산자는 메모리 또는 레지스터에 대한 작업을 지시합니다.

주석은 코드에 대한 설명이나 해설을 제공하기 위해 사용됩니다.

 

10-1 Label(라벨)

라벨은 명령어와 데이터에 대한 위치 표시자로서 기능하는 식별자입니다.

데이터라벨과 코드라벨 두종류가있습니다.

1. 명령어 바로 앞에 위치한 라벨은 해당 명령어의 주소를 나타냅니다.

2. 변수 바로 앞에 위치한 라벨은 해당 변수의 주소를 나타냅니다.

 

데이터 라벨은 변수의 위치를 식별하는 역할을 하며, 코드에서 해당 변수를 참조할 때 편리하게 사용됩니다. 예를들어, "count"라는 이름의 변수를 정의하는 데이터 라벨을 사용할 수 있습니다.

- count DWORD 100 (count는 데이터라벨)

 

어셈블러는 각 라벨에 숫자 주소를 할당합니다. 라벨 다음에 여러 개의 데이터 항목을 정의할 수 있습니다.

- array DWORD 1024, 2048

            DWORD 4096, 8192

 

라벨은 코드 영역에서도 지정할 수 있습니다. 코드영역에서 라벨은 반드시 클론(:) 으로 끝나야 합니다.

코드라벨은 점프 및 루프명령어의 대상으로 사용됩니다.

예를 들어, JMP 명령어는 "target"이라는 이름의 라벨로 표시된 위치로 프로그램 제어를 전환할 수 있습니다. 코드 라벨은 명령어와 동일한 라인에 있을 수도 있고, 별도의 라인에 있을 수도 있습니다.

target:
	mov ax,bx
	...
	jmp target

라벨이름은 식별자와 동일한 규칙을 따릅니다. 라벨은 같은 프로시저 내에서 고유해야합니다.

-> 같은 코드라벨을 프로그램의 여러 부분에서 사용할 수 있지만, 각각의 라벨은 해당 프로시저 내에서 고유해야합니다.

 

10-2 Mnemonic

지시를 식별하는 짧은 단어

• mov, add 및 sub와 같은 어셈블리 언어 명령 니모닉은 그들이 수행하는 작업 유형에 대한 힌트를 제공합니다.

 

 

10-3 Operands

오퍼랜드는 instruction에서 입력, 또는 출력에 사용되는 값입니다.

어셈블리어 명령어는 오퍼랜드를 0~ 3개까지 가질 수 있습니다.

1. 레지스터, 메모리 오퍼랜드, 정수식 또는 입출력 포트가 될 수 있습니다.

2. 메모리 오퍼랜드를 마드는 방법은 여러가지가 있습니다: 변수 이름, 대괄호로 둘러싸인 레지스터 등

-> 변수이름은 변수의 주소를 의미하며 컴퓨터가 해당 주소의 메모리 내용을 참조하도록 지시합니다.

 3. 예시

stc			;set Carry flag
inc eax			;add 1 to EAX
mov count, ebx		;move EBX to count
imul eax, ebx, 5

 명령어에 여러개의 오퍼랜드가 있는 경우..

1. 첫번째는 목적지 오퍼랜드로 불림

2. 두번쨰는 일반적으로 소스 오퍼랜드로 불림

3. 일반적으로 목적지오퍼랜드의 내용이 instruction 에서 수정됩니다.

 

10-4 Comment(주석)

주석의 경우 프로그램 작성자가 프로그램의 디자인에 대한 정보를 소스 코드를 읽는 사람에게 전달하는 중요한 방법입니다.

프로그램 목록의 상단에 일반적으로 다음 정보가 포함됩니다

1. 프로그램 목적에 대한 설명

2. 프로그램을 생성하고/또는 수정한 사람의 이름

3. 프로그램 생성 및 수정 날짜

4. 프로그램 구현에 대한 기술적인 참고 사항 • 한 줄 코멘트

5. 세미콜론 (;) 문자로 시작합니다.

6. 같은 줄에서 세미콜론 이후의 모든 문자는 어셈블러에 의해 무시됩니다. • 블록 코멘트

7. COMMENT 지시문과 사용자 지정 기호로 시작합니다.

8. 이후의 모든 텍스트 줄은 사용자 지정 기호가 다시 나올 때까지 어셈블러에 의해 무시됩니다.

 

10-5 NOP(Operation이 없는 instruction)

놉.

놉은 가장안전하고 무의미한 명령어입니다. 프로그램 저장소를 1바이트 차지하고 아무일도 안합니다.

컴파일러와 어셈블러가 효율적인 주소 경계에 코드를 맞추기 위해 때때로 사용합니다.

 

1. 첫번째 mov 명령어는 3개의 기계 코드 바이트를 생성합니다.

2. NOP 명령어는 세번째 명령어의 주소를 더블 워드 경계(4의 배수) 에 맞춥니다.

 x86 프로세서는 짝수의 더블워드 주소에서 코드와 데이터를 더 빠르게 로드 할 수 있도록 설계되었습니다.

 

11. Example: Adding and Subtracting Integers

1. Add Two Program

 1~3: Comment 

4: .386 은 이것이 32비트 프로그램임을 식별합니다.

5: .Model 지시어는 프로그램의 메모리 모델(flat)을 선택하고 절차에 대한 호출 규칙(stdcall)을 식별합니다.

6: runTime Stack 4096 바이트로 설정했습니다. 크기가 이 이상으로 커지면 stack overflow 오류가 발생합니다.

7: 윈도우 서비스인 표준 ExitProcess 함수의 프로토타입이 선언됩니다. 프로토타입은 팜수이름, PROTO, 그리고 입력 매개변수 목록으로 구성됩니다.

-> 입력 매개변수는 dwExitCode라고 불리며, 0이 아닌 반환값은 일반적으로 오류 코드 번호를 나타냅니다.

-> 따라서, 당신은 어셈블리 프로그램을 서브루틴 또는 프로세스로 생각할 수 있으며, 이들은 OS에 의해 호출됩니다.

16: End directive는 마지막으로 어셈블 될 라인을 표시하고 프로그램 진입점(main)을 식별하는데 사용됩니다.

->라벨 main은 10번라인에서 선언되었으며 프로그램이 실행을 시작할 주소를 표시합니다.

 

자세히 하나하나 봅시다

 

1. MODEL directive

.model(.model flat, stdcall)

어셈블러에게 사용할 메모리 모델을 알려줍니다.

- 32비트 프로그램에서는 항상 flat 메모리 모델을 사용합니다.

- stdcall 키워드는 프로시저가 호출될 때 런타임 스택을 어떻게 관리할지 어셈블러에게 알려줍니다.

 

2. Stack directive

.stack(.stack 4096)

프로그램의 런타임 stack 에 예약할 메모리 바이트 수를 어셈블러에게 알려줍니다.

- 4096은 우리가 사용할 메모리 크기보다 크지만, 이 값은 프로세서의 메모리 관리 시스템에서 메모리 페이지의 크기에 해당합니다.

- 모든 최신 프로그램은 하위 루틴을 호출할 때 스택을 사용합니다.

1. 전달된 배개변수를 보유하기위해

2. 함수를 호출한 코드의 주소를 보유하기위해 -CPU는 이 주소를 사용하여 함수 호출이 끝날 때 함수가 호출된 위치로 돌아갑니다.

- 또한 런타임 스택은 로컬 변수를 보유할 수 있습니다.

 

3. Code Directive

.code

프로그램의 코드 영역, 즉 실행가능한 명령어가 포함된 영역의 시작점을 표시합니다.

- 일반적으로 .code 다음줄은 프로그램의 진입점을 선언하는데, 규칙에 따라 일반적으로 main이라는 프로시저 이름을 사용합니다.

- 프로그램의 진입점은 프로그램이 실행할 엔트리포인트 입니다.

 

4. ENDP Directive

main ENDP

프로시저의 끝을 표시합니다.

- 우리 프로그램에는 main이라는 프로시저가 있으므로 ENDP 디렉티브도 동일한 이름을 사용해야합니다.

 

5. END Directive

END main

프로그램의 끝을 표시하고, 프로그램 진입점을 참조합니다.

- END 디렉티브 이후에 프로그램에 더 많은 줄을 추가해도 어셈블러는 무시합니다.

 

24~26은 우선 건너뛰었습니다.

 

12. Assembling, Linking, and Running Programs

 

어셈블리 언어로 작성된 소스 프로그램은 직접 실행될 수 없으며, 번역되거나 실행 가능한 코드로 어셈블될 필요가 있습니다.

어셈블러는 컴파일러와 매우 유사합니다. 어셈블러는 기계어로 된 파일인 오브젝트 파일을 생성합니다.

그러나 오브젝트 파일은 아직 실행할 준비가 되어 있지 않습니다.

이 파일은 또 다른 프로그램인 링커로 전달되어 실행 가능한 파일이 생성됩니다.

 

Step1: 프로그래머는 텍스트 편집기를 사용하여 소스파일을 생성합니다(ASCII형 텍스트파일)

Step2: 어셈블러는 소스 파일을 읽고 프로그램의 기계어 번역인 오브젝트 파일을 생성합니다. 선택적으로 어셈블러는 Listing File을 생성할 수 도있습니다. 만약 오류가 발생하면 Step1으로 돌아가서 다시 프로그램을 수정해야합니다.

Step3: 링커는 오브젝트 파일을 읽고 링크 라이브러리에서 프로시저를 호출하는지 확인합니다.

링커는 필요한 프로시저를 링크 라이브러리에서 복사하여 오브젝트 파일과 결합하고 실행가능한 파일을 생성합니다.

Step4: OS로더 유틸리티는 실행 가능한 파일을 메모리에 읽고 프로그램의 시작 주소로 CPU를 분기시키며, 프로그램이 실행됩니다.
 
 
Step 2에서 생성되는 Listing 파일이란게 있는데 이게 뭔지 알아보자.
 

13. Listing File 

 

리스팅 파일은 다음과 같은 내용을 포함합니다.

1. 프로그램의 소스 코드 복사본: 각 줄의 줄 번호, 각 명령의 숫자 주소, 각 명령의 기계어 바이트(16진수) 및 심볼 테이블이 포함됩니다.

2. 심볼 테이블: 모든 프로그램 식별자, 세그먼트 이름 및 관련 정보가 포함됩니다.

 

그래서 코드를 보면

9행: 코드세그먼트의 시작 위치는 00000000h 입니다.(entry point)  이 주소는 프로그램의 메모리 풋 프린트의 시작점을 기준으로 상대적인 주소입니다. 하지만 프로그램이 메모리에 로드될 때 절대적인 메모리 주소로 변환됩니다.

10-11행: 시작주소는 00000000 입니다.

11행: 첫번째 실행 가능한 문장입니다. 16진수 바이트 00000005는 기계어 명령어(B8)과 그 명령에 의해 EAX에 할당되는 32비트 상수값 00000005를 나타냅니다.  여기서 B8은 opcode 입니다.

12행:  프로그램 시작점에서 5바이트 떨어진 곳에서 실행가능한 명령입니다.(주솟값은 상대적이므로)

14행: invoke 지시문 입니다.

15-16행: 이는 코드에 삽입된것처럼 보이지만, 이는 어셈블러가 자동으로 생성한 PUSH 및 CALL문 명령어입니다.

invoke 지시문을 사용하면 프로그래머는 함수를 호출하기 위해 명령어를 작성하는 대신 간단한 지시문을 사용할 수 있습니다.

 

14. 데이터 정의 - Intrinsic Data Types

 

 데이터 타입은 위와 같이 고를 수 있습니다.

1. BYTE: 8비트 언사인드 Int(B)

2. SBYTE: 8비트 사인 Int(S)

3. WORD: 16비트 언사인드 Int

4. SWORD: 16비트 사인 Int

5. DWORD: 32비트 언사인드 Int (D)

6. SDWORD: 32비트 사인 Int (SD)

7. FWORD: 48비트 Int(Far pointer in Protected mode)

8. QWORD: 64비트 Int(Q)

9. TBYTE: 80비트 인트

10. REAL4, REAL8, REAL10 각각 32, 64, 80비트 short long extended

 

1. 데이터 정의 지시어

메모리 내에 변수를 저장하고, 변수의 이름을 정의할 수 있는 지시어입니다. 이러한 변수는 미리정의된 기본 데이터 타입 중 하나를 기반으로 생성됩니다.

Example: count DWORD 12345

이름: 변수에 할당되는 선택적인 이름(count)는 식별자 규칙을 준수합니다.

지시어: BYTE, WORD, DWORD 등 기본 데이터유형 뿐 아니라 모든 레거시 데이터 정의 지시문을 사용할 수 있습니다.

Initializer: 변수의 값을 설정하는 것을 의미합니다. 초기화 하지 않으려면 ? 를 사용할 수 있습니다. 이는 어센블러에 의해 이진 데이터로 변환됩니다.

 

 

 

[line13]에 중지점을 설정하고 프로그램을 한 줄씩 실행하여 디버거에서 실행합니다.

[line15]를 실행한 후 sum 변수의 값을 확인합니다.

 

2. BYTE와 SBYTE Data정의

 

1. 하나 또는 그 이상의 부호 없는 또는 부호 있는 값을 저장할 공간을 할당합니다.

2. 각 초기값은 8비트의 저장 공간에 맞아야합니다.

3. 옵션으로 제공되는 이름은 해당 변수의 시작 위치로부터의 오프셋을 표시하는 레이블입니다.

-> 값 1이 데이터 세그먼트의 오프셋 0000에서 1바이트의 저장 공간을 차지하고 있다면, 값 2는 자동으로 오프셋 0001에 위치합니다.

4. DB 지시어는 8비트 변수를 정의하는 데에도 사용될 수 있으며, 부호 있는 또는 부호 없는 값을 지정할 수 있습니다.

– MultipleInitializers

• 여러 이니셜라이저가 사용되는 경우, 라벨은 첫 번째 이니셜라이저의 오프셋만 나타냅니다.

• 모든 데이터 정의에 라벨이 필요한 것은 아닙니다.
–> 어떤 라벨로도 시작된 바이트의 배열을 계속하려면, 우리는 다음 줄에 추가 바이트를 정의할 수 있습니다:

• 단일 데이터 정의 내에서, 이니셜라이저는 다른 자료형을 사용할 수 있습니다.

 

문자열 정의하기

문자열을 정의하려면 단어들을 큰 따옴표로 둘러싸면 됩니다.

이후에 문자열은 0으로 종료되므로 0을 적어줍니다. 이는 많은 프로그래밍 언어에서 쓰는 방법입니다.

 

dh 와 ah 설명

 

16진수 코드 0dh와 0ah는 줄바꿈 문자로 각각 CR/LF로도 불립니다.

표준 출력으로 작성될 때, 이들은 현재 줄 다음 줄의 왼쪽 열로 커서를 이동합니다.

라인 연속 문자 ( \ )는 두 개의 소스 코드 줄을 단일 문으로 연결합니다.

라인 연속 문자는 줄의 마지막 문자여야합니다.

라인 연속문자의 설명

DUP 연산자
• 정수 표현식을 카운터로 사용하여 여러 데이터 항목에 대한 저장소를 할당합니다.
• 문자열이나 배열을 위한 공간을 할당할 때 특히 유용합니다.
• 초기화되거나 초기화되지 않은 데이터와 함께 사용할 수 있습니다.

 

 

Defining WORD, SWORD

16비트 정수형 을 위해 하나이상의 공간 만들기

 

 

1. word1 을 아주큰 정수형 값으로 지정

2. word2를 아주작은 signed value로 지정

3. word3을 정의 값은 초기화 하지 않음

4. val1 DW 

 

Arrayof 16-Bit Words

 

Symbolic Constants

어셈블러(Symbol) Constant는 어셈블리 프로그래밍에서 사용되는 상수(constant)의 일종입니다. 이러한 상수는 매크로나 심볼릭 상수(symbolic constant)로 정의됩니다. 매크로나 심볼릭 상수는 코드 내에서 여러 번 사용되는 상수값을 대체하기 위해 사용됩니다.

매크로는 코드의 재사용성을 높이기 위해 자주 사용되는 코드 블록을 정의하는 데 사용됩니다. 매크로는 매개변수(parameter)를 가질 수 있으며, 매개변수를 사용하여 매크로의 동작을 조정할 수 있습니다.

심볼릭 상수는 상수값에 이름을 부여하여 코드를 읽기 쉽고 이해하기 쉽게 만들어 줍니다. 상수값이 변경되는 경우, 이를 참조하는 모든 코드에서 상수값을 변경해야 합니다. 하지만, 심볼릭 상수를 사용하면 상수값을 한 곳에서만 변경하면 되므로 코드 수정이 간편해집니다.

예를 들어, 다음과 같은 심볼릭 상수를 정의할 수 있습니다.

 

MAX_SIZE EQU 100

 

이렇게 정의된 MAX_SIZE는 코드에서 변수처럼 사용할 수 있으며, 이 값을 변경하면 코드 전체에서 변경된 값을 사용하게 됩니다. 이러한 방식으로 심볼릭 상수를 사용하면 코드를 읽기 쉽고 이해하기 쉽게 만들 수 있습니다.

등호 처리

코더가 프로그램을 짜면 ex) name = expression;

어셈블러 전처리기에서는 아래와 같이 번역됩니다.

 

COUNT = 500;

mov eax COUNT

mov eax 500

 

배열과 문자열의 크기 계산하기

배열의 크기를 직접 지정하는것은 프로그래밍 오류를 발생시킬 가능성이 있기 때문에 좋지 않다, 이렇기 때문에 어셈블러가 크기를 자동으로 계산하도록 하는것이 좋습니다. 이를 위해서 어셈블러에서 제공하는 특별한 기호를 사용합니다.

 

list BYTE 10, 20, 30, 40
ListSize = ($ - list)

$는 현재 위치 카운터를 참조합니다. 위치 카운터는 프로그램 문장에 연결된 주소의 오프셋입니다. $을 사용해서

 

 

 

위의 내용은 배열의 크기를 계산할 때, byte 이외의 값들이 들어있는 경우, 전체 배열의 크기를 각 배열 요소의 크기로 나누어야 한다는 것을 설명하고 있습니다. 예를 들어, 2바이트(16비트) 값을 갖는 워드 배열이 있다면, 해당 배열의 크기를 계산할 때 전체 배열의 크기를 2로 나누어야 합니다. 같은 방법으로, 4바이트(32비트) 값을 갖는 더블워드 배열의 경우, 전체 배열의 크기를 4로 나누어야 합니다. 이렇게 하지 않으면 배열 요소의 개수를 잘못 계산할 수 있습니다.

 

 

TEXTEQU

위에서 EQU로 정수를 빠르게 매크로화 하는 법에 대해서 알아보았는데 이번엔 TEXTEQU로 텍스트를 빠르게 매크로화 하는것을 알아보자.

첫 번째 형식에서는 텍스트가 매크로에 직접 할당됩니다.

두 번째 형식에서는 매크로가 기존 텍스트 매크로의 내용을 할당받습니다.

세 번째 형식에서는 매크로에 상수 정수 표현식이 할당됩니다.

 

첫번째의 예시
세번째의 예시

텍스트 매크로는 서로 연결하여 사용할 수 있으며, TEXTEQU 지시문으로 정의된 심볼은 언제든지 재정의 할수 있습니다.