016. 주소지정 모드하고의 차이
주소지정 모드와의 차이

TITLE Main
.DOSSEG
.8086
.NO87
.MODEL TINY
.DATA
addy DW exit
.CODE
.STARTUP
mov ax, addy
mov bx, OFFSET addy
jmp exit
jmp addy
jmp ax
jmp WORD PTR [bx]
exit:
; 프로그램 종료
mov ah, 4Ch
xor al, al ; 리턴값 0
int 21h
ENDexit label 그리고 .DATA addy DW exit
exit은 Statements의 구성 중 name 에 속한다. 어셈블 시점에 이름 대신 오프셋으로 바뀌어 바이너리에 박힌다.
Programmer's Guide p.21 — Statements
[[name:]] [[operation]] [[operands]] [[;comment]]name: Labels the statement, so that instructions elsewhere in the program can refer to the statement by name. The name field can label a variable, type, segment, or code location.

어셈블해보면 .exit name 의 오프셋은 0110이다.
jmp exit의 바이너리 값이EB08인데 Code View에서JMP 0110이라고 보여준다.
addy 변수의 값을 확인해보자. addy가 사용된 Statment 를 확인해보자
가장 직관적인 Statment mov bx, OFFSET addy를 확인해보면 addy의 오프셋은 0116이다.

d cs:0x0116 로 덤프했다.
0116오프셋의 값은100117오프셋의 값은01
리틀엔디언으로 메모리에 저장하기 때문에 원래의 값은 0110 2바이트다. exit name의 오프셋과 동일하다.
addy DB exit또는addy DD exit하면?
addy DB exit의 경우 “error A2071: initializer magnitude too large for specified size” 오류가 발생해 어셈블 실패한다.
- “initializer magnitude”가
exitname 오프셋의 크기 - “specified size”가
DB - 각각의 크기를 어셈블 시점에 알 수 있다.
addy DD exit의 경우 “error A2118: cannot have segment address references with TINY model” 오류가 발생해 어셈블 실패한다.
참고
DD에 코드 레이블을 넣으면 segment:offset 쌍(far pointer)을 저장하려 하는데, TINY 모델은 세그먼트가 하나뿐이라 세그먼트 주소 참조 자체가 금지된다. (error A2118).
mov ax, addy

Code View에서 MOV AX,WORD PTR [0116]라고 보여준다.
addy는 직접 메모리 피연산자로 사용되었다. 이를 어떻게 알 수 있을까?
- 코드 뷰의
[]는 메모리의 주소의 값을 사용해라는 말이다. 따라서0x0116주소의 값을 WORD로 읽어서 AX에 저장한다.- 어셈블 도중 주소값이 바이너리에
1601으로 박힌 것에서도 직접 메모리 피연산자임을 확인할 수 있다.
- 어셈블 도중 주소값이 바이너리에
- 직접 메모리 피연산자에서 “주소를 나타내는 상수나 심볼을 피연산자로 사용 가능”이라고 했다.
addy라는 변수를 사용하는 것이 이 케이스에 해당한다.- 소거법으로 생각해보면 레지스터 피연산자는 아니고 간접 피연산자도 아니고(4개 레지스터에 해당하지 않음) 즉시 피연산자도 아니다. ([[015. 간접 피연산자#mov-bx-offset-table|
mov bx, OFFSET table]] 참고)
- 소거법으로 생각해보면 레지스터 피연산자는 아니고 간접 피연산자도 아니고(4개 레지스터에 해당하지 않음) 즉시 피연산자도 아니다. ([[015. 간접 피연산자#mov-bx-offset-table|

실행하면 “AX”의 값은 0110으로 바뀐다.
0116주소에서 2바이트를 읽은 결과를 대입한 것이다.
- 위의
d cs:0x0116로 덤프 결과 참고
mov bx, OFFSET addy

[[015. 간접 피연산자#mov-bx-offset-table|mov bx, OFFSET table]]에서 봤듯이 “OFFSET Operator”가 변수에 붙으면 즉시 피연산자로 취급한다.
- 어셈블 시점에 주소가 바이너리에 박힌다.
BB1601- Code View도
[]을 빼고0116으로 보여준다.
- 주소에 역참조하지 않고 주소 자체를 값으로 사용한다.

실행 결과 “BX”에 주소 자체가 값(0116)으로 저장되었다.
- 레지스터에 저장하니 리틀 엔디언 적용되지 않았죠?!
jmp exit
위에서 봤듯이 name 은 어셈블 시점에 오프셋으로 바이너리에 저장된다.
강사님은 직접 메모리 피연산자라고 설명한다.
jmp addy

우선 이 동작이 name 처럼 바이너리에 addy 주소가 박혀서 점프한다고 생각해보자. 데이터 섹션에 점프를..? 이상하다.
- 따라서 즉시 피연산자는 아니다.
그래서 addy 변수에 어떤 주소값이 있고 그 주소로 점프한다고 직관적으로 이해할 수 있다.
- 대신에
addy변수에 들어있는 주소값은 동적으로 바뀔 수 있다.
어셈블 결과 Code View는 JMP WORD PTR [0116] 이라고 보여준다.
addy의 주소0116(메모리)에서 어떤 값을 2바이트로 읽는다.
이번 경우도 addy는 직접 메모리 피연산자로 사용되었다. 어셈블 시점에 이 변수의 주소는 바이너리에 박히지만 실행 중 역참조가 발생한다.
jmp ax
위의 [[#mov-ax-addy|mov ax, addy]]의 결과를 확인해보자. “ax”에는 addy의 값 즉 exit의 주소 0110이 들어간다.
따라서 jmp exit과 동일하게 동작한다.
jmp WORD PTR [bx]
드디어 간접 피연산자가 나왔다.
조건에 만족한다.
bx사용[]사용
Code View는 다음과 같이 보여준다.
JMP WORD PTR [BX]- 실행 중에
bx의 값은OFFSET addy로 결정된다.addy변수의 주소다. - 이 주소에 역참조해서 2바이트로 읽는다. 이 값은
exitname의 주소0110이다.addy DW exit로 변수에 저장된 값
0110으로 점프한다.