프로그램 틀 문서의 검증 코드다. if __name__ == "__main__": 아래가 자체 테스트다.
"""프로그램 틀 검증 (MASM이 없어 파이썬 흉내로 확인).
문서: 10.프로그램 틀
주장:
1. AddTwo: mov eax,5 / add eax,6 → EAX = 0000000Bh (11).
2. AddSub2: 10000h + 40000h - 20000h → EAX = 00030000h, finalVal = 30000h.
3. 디버거 출력 EAX=00030000 은 AddTwo가 아니라 AddSub 쪽 결과다.
EFL=00000206의 짝수 플래그(PF) = 1 도 30000h(아래 8비트 00h)와 맞고 0Bh(1이 세 개)와는 안 맞는다.
4. 두 프로그램 모두 CF = SF = ZF = OF = 0 으로 끝난다.
5. 틀의 줄 순서: .386 → .model → .stack → PROTO → .data → .code → main PROC … main ENDP → END main.
6. 카드: mov eax,7 / add eax,9 → 10h. val1 = 5000h, val2 = 3000h, val3 = 1000h → 7000h.
"""
MASK = 0xFFFFFFFF
class CPU:
def __init__(self):
self.reg = {"eax": 0}
self.mem = {}
self.flags = {"CF": 0, "ZF": 0, "SF": 0, "OF": 0, "PF": 0}
def val(self, src):
if isinstance(src, int):
return src
return self.reg[src] if src in self.reg else self.mem[src]
def put(self, dst, v):
if dst in self.reg:
self.reg[dst] = v & MASK
else:
self.mem[dst] = v & MASK
def setflags(self, a, b, r, sub):
res = r & MASK
self.flags["ZF"] = int(res == 0)
self.flags["SF"] = res >> 31
self.flags["PF"] = int(bin(res & 0xFF).count("1") % 2 == 0)
if sub:
self.flags["CF"] = int(a < b)
self.flags["OF"] = int(((a ^ b) & (a ^ res)) >> 31)
else:
self.flags["CF"] = int(r > MASK)
self.flags["OF"] = int((~(a ^ b) & (a ^ res) & MASK) >> 31)
def mov(self, dst, src):
self.put(dst, self.val(src))
def add(self, dst, src):
a, b = self.val(dst), self.val(src)
self.setflags(a, b, a + b, False)
self.put(dst, a + b)
def sub(self, dst, src):
a, b = self.val(dst), self.val(src)
self.setflags(a, b, a - b, True)
self.put(dst, a - b)
def add_two(x=5, y=6):
c = CPU()
c.mov("eax", x)
c.add("eax", y)
return c
def add_sub2(v1=0x10000, v2=0x40000, v3=0x20000):
c = CPU()
c.mem.update(val1=v1, val2=v2, val3=v3, finalVal=0)
c.mov("eax", "val1")
c.add("eax", "val2")
c.sub("eax", "val3")
c.mov("finalVal", "eax")
return c
TEMPLATE = [".386", ".model flat,stdcall", ".stack 4096", "ExitProcess PROTO, dwExitCode:DWORD",
".data", ".code", "main PROC", "INVOKE ExitProcess,0", "main ENDP", "END main"]
def main():
c = add_two()
assert c.reg["eax"] == 0x0000000B == 11
f1 = dict(c.flags)
print("[OK] AddTwo: EAX = 0000000Bh")
c2 = add_sub2()
assert c2.reg["eax"] == 0x00030000 and c2.mem["finalVal"] == 0x30000
f2 = dict(c2.flags)
print("[OK] AddSub2: EAX = 00030000h, finalVal = 30000h")
assert c.reg["eax"] != 0x00030000
assert f2["PF"] == 1 and f1["PF"] == 0
assert (0x206 >> 2) & 1 == 1
print("[OK] 디버거 출력의 EAX=00030000, EFL=206h(PF = 1)은 AddSub 결과와 맞고 AddTwo(0Bh, PF = 0)와는 안 맞는다")
for f in (f1, f2):
assert (f["CF"], f["SF"], f["ZF"], f["OF"]) == (0, 0, 0, 0)
print("[OK] 두 프로그램 모두 CF = SF = ZF = OF = 0")
order = [TEMPLATE.index(x) for x in (".data", ".code", "main PROC", "main ENDP", "END main")]
assert order == sorted(order) and TEMPLATE[-1] == "END main"
assert TEMPLATE.index(".stack 4096") < TEMPLATE.index(".data")
assert 4096 == 0x1000
print("[OK] 틀의 줄 순서, 스택 4096바이트 = 1000h")
assert add_two(7, 9).reg["eax"] == 0x10
t = CPU()
t.mem.update(val1=0x10000, val2=0x40000, val3=0x20000, finalVal=0)
t.mov("eax", "val1"); assert t.reg["eax"] == 0x00010000
t.add("eax", "val2"); assert t.reg["eax"] == 0x00050000
t.sub("eax", "val3"); assert t.reg["eax"] == 0x00030000
u = CPU()
u.mem.update(val1=0x5000, val2=0x3000, val3=0x1000, finalVal=0)
u.mov("eax", "val1"); assert u.reg["eax"] == 0x5000
u.add("eax", "val2"); assert u.reg["eax"] == 0x8000
u.sub("eax", "val3"); assert u.reg["eax"] == 0x7000
u.mov("finalVal", "eax"); assert (u.reg["eax"], u.mem["finalVal"]) == (0x7000, 0x7000)
assert add_sub2(0x5000, 0x3000, 0x1000).reg["eax"] == 0x7000
print("[OK] 추적 표 10000h → 50000h → 30000h, 카드: 7 + 9 = 10h, 5000h → 8000h → 7000h")
print("ALL CHECKS PASSED")
if __name__ == "__main__":
main()