어셈블·링크·실행 과정 문서의 검증 코드다. if __name__ == "__main__": 아래가 자체 테스트다.
"""어셈블·링크·실행 과정 검증 (MASM이 없어 파이썬 흉내로 확인).
문서: 11.어셈블·링크·실행 과정
주장:
1. 네 단계: 편집기 → 어셈블러 → 링커 → 운영체제 로더. 원본을 고치면 2~4단계를 다시 한다.
2. 문서 예시 리스팅 파일의 오프셋은 앞 줄의 오프셋에 앞 줄 기계어의 바이트 수를 더한 값이다.
00000000 66 B8 0000 (4바이트) → 00000004
00000004 B9 00000005 (5바이트) → 00000009
00000009 66 03 C1 (3바이트) → 0000000C
0000000C E2 FB (2바이트) → 0000000E
3. loop L1의 FBh는 8비트 부호 있는 수로 -5다. 0000000Eh + (-5) = 00000009h = L1.
4. 이 반복을 흉내 내면 AX = 5 + 4 + 3 + 2 + 1 = 15 (000Fh).
5. 만들어지는 파일: 어셈블러 → 목적 파일, 리스팅 파일 / 링커 → 실행 파일, 맵 파일.
"""
LISTING = [
(0x00000000, "66 B8 0000", "mov ax,0"),
(0x00000004, "B9 00000005", "mov ecx,5"),
(0x00000009, "66 03 C1", "L1:add ax,cx"),
(0x0000000C, "E2 FB", "loop L1"),
]
END = 0x0000000E
STEPS = [("편집기", "원본 파일"), ("어셈블러", "목적 파일"), ("링커", "실행 파일"), ("운영체제 로더", "출력")]
SIDE = {"어셈블러": "리스팅 파일", "링커": "맵 파일"}
LINKER_INPUT = ["목적 파일", "링크 라이브러리"]
def nbytes(code):
return sum(len(tok) // 2 for tok in code.split())
def signed8(b):
return b - 256 if b >= 128 else b
def run_loop():
ax, ecx = 0, 5
turns = 0
while True:
ax = (ax + (ecx & 0xFFFF)) & 0xFFFF # add ax,cx
turns += 1
ecx = (ecx - 1) & 0xFFFFFFFF # loop: ECX를 1 줄이고 0이 아니면 뛴다
if ecx == 0:
break
return ax, turns
def main():
assert [s[0] for s in STEPS] == ["편집기", "어셈블러", "링커", "운영체제 로더"]
assert len(STEPS) == 4 and list(SIDE) == ["어셈블러", "링커"]
print("[OK] 네 단계와 곁가지 파일 둘")
sizes = [nbytes(code) for _, code, _ in LISTING]
assert sizes == [4, 5, 3, 2]
off = 0
for (want, code, _), size in zip(LISTING, sizes):
assert off == want
off += size
assert off == END == sum(sizes) == 14
print("[OK] 리스팅 파일의 오프셋 00, 04, 09, 0C, 끝 0E = 바이트 수 4, 5, 3, 2의 누적")
assert signed8(0xFB) == -5
assert END + signed8(0xFB) == 0x00000009 == LISTING[2][0]
print("[OK] FBh = -5, 0Eh - 5 = 09h (L1)")
ax, turns = run_loop()
assert (ax, turns) == (15, 5) and ax == 0x000F
print("[OK] 흉내 실행: AX = 15 (5번 돈다)")
# 카드: jmp/loop 변위 계산 연습. 다음 명령 오프셋 0020h, 목표 0012h → 변위 -14 = F2h
disp = 0x12 - 0x20
assert disp == -14 and (disp & 0xFF) == 0xF2 and signed8(0xF2) == -14
# 카드: 3바이트, 2바이트, 5바이트 명령이 00000010h부터 놓이면 오프셋은 10h, 13h, 15h, 다음은 1Ah
offs, o = [], 0x10
for size in (3, 2, 5):
offs.append(o)
o += size
assert offs == [0x10, 0x13, 0x15] and o == 0x1A
print("[OK] 카드: 변위 F2h, 오프셋 10h·13h·15h·1Ah")
print("ALL CHECKS PASSED")
if __name__ == "__main__":
main()