어셈블리어와 기계어 문서의 검증 코드다. if __name__ == "__main__": 아래가 자체 테스트다.
"""어셈블리어와 기계어 검증 (MASM이 없어 파이썬 흉내로 확인).
문서: 01.어셈블리어와 기계어
주장:
1. 어셈블리 네 줄(mov eax,A / mul B / add eax,C / call WriteInt)과 기계어 네 줄이 한 줄에 하나씩 짝지어진다.
2. 문서 예시의 기계어 첫 바이트는 인텔 명령 부호와 맞는다.
A1 = mov eax,메모리 / F7 /4 = mul / 03 /r = add 레지스터,메모리 / E8 = call.
F7 25 의 25h = 00 100 101b (가운데 100b = 4 → MUL),
03 05 의 05h = 00 000 101b (가운데 000b = EAX).
3. 변수 주소 00000000, 00000004, 00000008은 4씩 떨어져 있다 (32비트 변수 셋).
4. 네 줄을 흉내 내면 EAX = A * B + C 다.
5. 카드: 16진수 한 글자는 4비트, 기계어 03 05 00000008 은 6바이트.
"""
import random
ASM = ["mov eax,A", "mul B", "add eax,C", "call WriteInt"]
MACHINE = ["A1 00000000", "F7 25 00000004", "03 05 00000008", "E8 00500000"]
OPCODES = {0xA1: "mov eax,mem", 0xF7: "group3", 0x03: "add r32,r/m32", 0xE8: "call rel32"}
GROUP3 = {4: "mul", 5: "imul", 6: "div", 7: "idiv", 2: "not", 3: "neg", 0: "test"}
REG32 = ["eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi"]
def modrm(b):
return b >> 6, (b >> 3) & 7, b & 7
def decode(line):
parts = line.split()
op = int(parts[0], 16)
kind = OPCODES[op]
if kind == "group3":
mod, reg, rm = modrm(int(parts[1], 16))
assert (mod, rm) == (0, 5) # 주소 32비트가 바로 뒤따르는 꼴
return GROUP3[reg], int(parts[2], 16)
if kind == "add r32,r/m32":
mod, reg, rm = modrm(int(parts[1], 16))
assert (mod, rm) == (0, 5)
return "add " + REG32[reg], int(parts[2], 16)
if kind == "mov eax,mem":
return "mov eax", int(parts[1], 16)
return "call", int(parts[1], 16)
def run(a, b, c):
"""네 줄을 흉내 낸다. 32비트 부호 없는 곱의 아래 32비트가 EAX에 남는다."""
mem = {0: a, 4: b, 8: c}
eax = edx = 0
out = None
for line in MACHINE:
what, arg = decode(line)
if what == "mov eax":
eax = mem[arg]
elif what == "mul":
prod = eax * mem[arg]
eax, edx = prod & 0xFFFFFFFF, prod >> 32
elif what == "add eax":
eax = (eax + mem[arg]) & 0xFFFFFFFF
elif what == "call":
out = eax
return out
def main():
assert len(ASM) == len(MACHINE) == 4
names = [decode(m)[0] for m in MACHINE]
assert names == ["mov eax", "mul", "add eax", "call"]
for a, n in zip(ASM, names):
assert a.split()[0] == n.split()[0]
print("[OK] 문서 예시: 어셈블리 네 줄 = 기계어 네 줄, 줄마다 같은 명령")
assert modrm(0x25) == (0, 4, 5) and modrm(0x05) == (0, 0, 5)
print("[OK] 25h = 00 100 101b (MUL), 05h = 00 000 101b (EAX)")
addrs = [decode(m)[1] for m in MACHINE[:3]]
assert addrs == [0, 4, 8]
print("[OK] A, B, C의 주소 0, 4, 8: 4바이트씩 떨어짐")
assert run(3, 4, 5) == 17
rnd = random.Random(1)
for _ in range(1000):
a, b, c = (rnd.randrange(0, 60000) for _ in range(3))
assert run(a, b, c) == (a * b + c) & 0xFFFFFFFF
print("[OK] 흉내 실행: A*B+C (3*4+5 = 17, 무작위 1,000회)")
nbytes = sum(len(tok) // 2 for tok in "03 05 00000008".split())
assert nbytes == 6 and len("00000008") * 4 == 32
print("[OK] 카드: 03 05 00000008 은 6바이트, 16진 여덟 글자 = 32비트")
print("ALL CHECKS PASSED")
if __name__ == "__main__":
main()