ELF Header:
  Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
  Class:                             ELF32
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           Intel 80386
  Version:                           0x1
  Entry point address:               0x8048310
  Start of program headers:          52 (bytes into file)
  Start of section headers:          5984 (bytes into file)
  Flags:                             0x0
  Size of this header:               52 (bytes)
  Size of program headers:           32 (bytes)
  Number of program headers:         9
  Size of section headers:           40 (bytes)
  Number of section headers:         30
  Section header string table index: 29
Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .interp           PROGBITS        08048154 000154 000013 00   A  0   0  1
  [ 2] .note.ABI-tag     NOTE            08048168 000168 000020 00   A  0   0  4
  [ 3] .note.gnu.build-i NOTE            08048188 000188 000024 00   A  0   0  4
  [ 4] .gnu.hash         GNU_HASH        080481ac 0001ac 000020 04   A  5   0  4
  [ 5] .dynsym           DYNSYM          080481cc 0001cc 000050 10   A  6   1  4
  [ 6] .dynstr           STRTAB          0804821c 00021c 00004a 00   A  0   0  1
  [ 7] .gnu.version      VERSYM          08048266 000266 00000a 02   A  5   0  2
  [ 8] .gnu.version_r    VERNEED         08048270 000270 000020 00   A  6   1  4
  [ 9] .rel.dyn          REL             08048290 000290 000008 08   A  5   0  4
  [10] .rel.plt          REL             08048298 000298 000010 08  AI  5  23  4
  [11] .init             PROGBITS        080482a8 0002a8 000023 00  AX  0   0  4
  [12] .plt              PROGBITS        080482d0 0002d0 000030 04  AX  0   0 16
  [13] .plt.got          PROGBITS        08048300 000300 000008 08  AX  0   0  8
  [14] .text             PROGBITS        08048310 000310 0001c2 00  AX  0   0 16
  [15] .fini             PROGBITS        080484d4 0004d4 000014 00  AX  0   0  4
  [16] .rodata           PROGBITS        080484e8 0004e8 000015 00   A  0   0  4
  [17] .eh_frame_hdr     PROGBITS        08048500 000500 000044 00   A  0   0  4
  [18] .eh_frame         PROGBITS        08048544 000544 000110 00   A  0   0  4
  [19] .init_array       INIT_ARRAY      08049f0c 000f0c 000004 04  WA  0   0  4
  [20] .fini_array       FINI_ARRAY      08049f10 000f10 000004 04  WA  0   0  4
  [21] .dynamic          DYNAMIC         08049f14 000f14 0000e8 08  WA  6   0  4
  [22] .got              PROGBITS        08049ffc 000ffc 000004 04  WA  0   0  4
  [23] .got.plt          PROGBITS        0804a000 001000 000014 04  WA  0   0  4
  [24] .data             PROGBITS        0804a014 001014 000008 00  WA  0   0  4
  [25] .bss              NOBITS          0804a01c 00101c 000004 00  WA  0   0  1
  [26] .comment          PROGBITS        00000000 00101c 000029 01  MS  0   0  1
  [27] .symtab           SYMTAB          00000000 001048 000410 10     28  44  4
  [28] .strtab           STRTAB          00000000 001458 000200 00      0   0  1
  [29] .shstrtab         STRTAB          00000000 001658 000105 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  L (link order), O (extra OS processing required), G (group), T (TLS),
  C (compressed), x (unknown), o (OS specific), E (exclude),
  p (processor specific)
There are no section groups in this file.
Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  PHDR           0x000034 0x08048034 0x08048034 0x00120 0x00120 R   0x4
  INTERP         0x000154 0x08048154 0x08048154 0x00013 0x00013 R   0x1
      [Requesting program interpreter: /lib/ld-linux.so.2]
  LOAD           0x000000 0x08048000 0x08048000 0x00654 0x00654 R E 0x1000
  LOAD           0x000f0c 0x08049f0c 0x08049f0c 0x00110 0x00114 RW  0x1000
  DYNAMIC        0x000f14 0x08049f14 0x08049f14 0x000e8 0x000e8 RW  0x4
  NOTE           0x000168 0x08048168 0x08048168 0x00044 0x00044 R   0x4
  GNU_EH_FRAME   0x000500 0x08048500 0x08048500 0x00044 0x00044 R   0x4
  GNU_STACK      0x000000 0x00000000 0x00000000 0x00000 0x00000 RW  0x10
  GNU_RELRO      0x000f0c 0x08049f0c 0x08049f0c 0x000f4 0x000f4 R   0x1
 Section to Segment mapping:
  Segment Sections...
   00
   01     .interp
   02     .interp .note.ABI-tag .note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rel.dyn .rel.plt .init .plt .plt.got .text .fini .rodata .eh_frame_hdr .eh_frame
   03     .init_array .fini_array .dynamic .got .got.plt .data .bss
   04     .dynamic
   05     .note.ABI-tag .note.gnu.build-id
   06     .eh_frame_hdr
   07
   08     .init_array .fini_array .dynamic .got
Dynamic section at offset 0xf14 contains 24 entries:
  Tag        Type                         Name/Value
 0x00000001 (NEEDED)                     Shared library: [libc.so.6]
 0x0000000c (INIT)                       0x80482a8
 0x0000000d (FINI)                       0x80484d4
 0x00000019 (INIT_ARRAY)                 0x8049f0c
 0x0000001b (INIT_ARRAYSZ)               4 (bytes)
 0x0000001a (FINI_ARRAY)                 0x8049f10
 0x0000001c (FINI_ARRAYSZ)               4 (bytes)
 0x6ffffef5 (GNU_HASH)                   0x80481ac
 0x00000005 (STRTAB)                     0x804821c
 0x00000006 (SYMTAB)                     0x80481cc
 0x0000000a (STRSZ)                      74 (bytes)
 0x0000000b (SYMENT)                     16 (bytes)
 0x00000015 (DEBUG)                      0x0
 0x00000003 (PLTGOT)                     0x804a000
 0x00000002 (PLTRELSZ)                   16 (bytes)
 0x00000014 (PLTREL)                     REL
 0x00000017 (JMPREL)                     0x8048298
 0x00000011 (REL)                        0x8048290
 0x00000012 (RELSZ)                      8 (bytes)
 0x00000013 (RELENT)                     8 (bytes)
 0x6ffffffe (VERNEED)                    0x8048270
 0x6fffffff (VERNEEDNUM)                 1
 0x6ffffff0 (VERSYM)                     0x8048266
 0x00000000 (NULL)                       0x0
Relocation section '.rel.dyn' at offset 0x290 contains 1 entry:
 Offset     Info    Type            Sym.Value  Sym. Name
08049ffc  00000206 R_386_GLOB_DAT    00000000   __gmon_start__
Relocation section '.rel.plt' at offset 0x298 contains 2 entries:
 Offset     Info    Type            Sym.Value  Sym. Name
0804a00c  00000107 R_386_JUMP_SLOT   00000000   puts@GLIBC_2.0
0804a010  00000307 R_386_JUMP_SLOT   00000000   __libc_start_main@GLIBC_2.0
The decoding of unwind sections for machine type Intel 80386 is not currently supported.
Symbol table '.dynsym' contains 5 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 00000000     0 FUNC    GLOBAL DEFAULT  UND puts@GLIBC_2.0 (2)
     2: 00000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__
     3: 00000000     0 FUNC    GLOBAL DEFAULT  UND __libc_start_main@GLIBC_2.0 (2)
     4: 080484ec     4 OBJECT  GLOBAL DEFAULT   16 _IO_stdin_used
Symbol table '.symtab' contains 65 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 08048154     0 SECTION LOCAL  DEFAULT    1
     2: 08048168     0 SECTION LOCAL  DEFAULT    2
     3: 08048188     0 SECTION LOCAL  DEFAULT    3
     4: 080481ac     0 SECTION LOCAL  DEFAULT    4
     5: 080481cc     0 SECTION LOCAL  DEFAULT    5
     6: 0804821c     0 SECTION LOCAL  DEFAULT    6
     7: 08048266     0 SECTION LOCAL  DEFAULT    7
     8: 08048270     0 SECTION LOCAL  DEFAULT    8
     9: 08048290     0 SECTION LOCAL  DEFAULT    9
    10: 08048298     0 SECTION LOCAL  DEFAULT   10
    11: 080482a8     0 SECTION LOCAL  DEFAULT   11
    12: 080482d0     0 SECTION LOCAL  DEFAULT   12
    13: 08048300     0 SECTION LOCAL  DEFAULT   13
    14: 08048310     0 SECTION LOCAL  DEFAULT   14
    15: 080484d4     0 SECTION LOCAL  DEFAULT   15
    16: 080484e8     0 SECTION LOCAL  DEFAULT   16
    17: 08048500     0 SECTION LOCAL  DEFAULT   17
    18: 08048544     0 SECTION LOCAL  DEFAULT   18
    19: 08049f0c     0 SECTION LOCAL  DEFAULT   19
    20: 08049f10     0 SECTION LOCAL  DEFAULT   20
    21: 08049f14     0 SECTION LOCAL  DEFAULT   21
    22: 08049ffc     0 SECTION LOCAL  DEFAULT   22
    23: 0804a000     0 SECTION LOCAL  DEFAULT   23
    24: 0804a014     0 SECTION LOCAL  DEFAULT   24
    25: 0804a01c     0 SECTION LOCAL  DEFAULT   25
    26: 00000000     0 SECTION LOCAL  DEFAULT   26
    27: 00000000     0 FILE    LOCAL  DEFAULT  ABS crtstuff.c
    28: 08048370     0 FUNC    LOCAL  DEFAULT   14 deregister_tm_clones
    29: 080483b0     0 FUNC    LOCAL  DEFAULT   14 register_tm_clones
    30: 080483f0     0 FUNC    LOCAL  DEFAULT   14 __do_global_dtors_aux
    31: 0804a01c     1 OBJECT  LOCAL  DEFAULT   25 completed.7283
    32: 08049f10     0 OBJECT  LOCAL  DEFAULT   20 __do_global_dtors_aux_fin
    33: 08048420     0 FUNC    LOCAL  DEFAULT   14 frame_dummy
    34: 08049f0c     0 OBJECT  LOCAL  DEFAULT   19 __frame_dummy_init_array_
    35: 00000000     0 FILE    LOCAL  DEFAULT  ABS hello_world_c.c
    36: 00000000     0 FILE    LOCAL  DEFAULT  ABS crtstuff.c
    37: 08048650     0 OBJECT  LOCAL  DEFAULT   18 __FRAME_END__
    38: 00000000     0 FILE    LOCAL  DEFAULT  ABS
    39: 08049f10     0 NOTYPE  LOCAL  DEFAULT   19 __init_array_end
    40: 08049f14     0 OBJECT  LOCAL  DEFAULT   21 _DYNAMIC
    41: 08049f0c     0 NOTYPE  LOCAL  DEFAULT   19 __init_array_start
    42: 08048500     0 NOTYPE  LOCAL  DEFAULT   17 __GNU_EH_FRAME_HDR
    43: 0804a000     0 OBJECT  LOCAL  DEFAULT   23 _GLOBAL_OFFSET_TABLE_
    44: 080484d0     2 FUNC    GLOBAL DEFAULT   14 __libc_csu_fini
    45: 08048360     4 FUNC    GLOBAL HIDDEN    14 __x86.get_pc_thunk.bx
    46: 0804a014     0 NOTYPE  WEAK   DEFAULT   24 data_start
    47: 0804a01c     0 NOTYPE  GLOBAL DEFAULT   24 _edata
    48: 080484d4     0 FUNC    GLOBAL DEFAULT   15 _fini
    49: 0804a014     0 NOTYPE  GLOBAL DEFAULT   24 __data_start
    50: 00000000     0 FUNC    GLOBAL DEFAULT  UND puts@@GLIBC_2.0
    51: 00000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__
    52: 0804a018     0 OBJECT  GLOBAL HIDDEN    24 __dso_handle
    53: 080484ec     4 OBJECT  GLOBAL DEFAULT   16 _IO_stdin_used
    54: 00000000     0 FUNC    GLOBAL DEFAULT  UND __libc_start_main@@GLIBC_
    55: 08048470    93 FUNC    GLOBAL DEFAULT   14 __libc_csu_init
    56: 0804a020     0 NOTYPE  GLOBAL DEFAULT   25 _end
    57: 08048350     2 FUNC    GLOBAL HIDDEN    14 _dl_relocate_static_pie
    58: 08048310     0 FUNC    GLOBAL DEFAULT   14 _start
    59: 080484e8     4 OBJECT  GLOBAL DEFAULT   16 _fp_hw
    60: 0804a01c     0 NOTYPE  GLOBAL DEFAULT   25 __bss_start
    61: 08048426    56 FUNC    GLOBAL DEFAULT   14 main
    62: 0804845e     0 FUNC    GLOBAL HIDDEN    14 __x86.get_pc_thunk.ax
    63: 0804a01c     0 OBJECT  GLOBAL HIDDEN    24 __TMC_END__
    64: 080482a8     0 FUNC    GLOBAL DEFAULT   11 _init
Histogram for `.gnu.hash' bucket list length (total of 2 buckets):
 Length  Number     % of total  Coverage
      0  1          ( 50.0%)
      1  1          ( 50.0%)    100.0%
Version symbols section '.gnu.version' contains 5 entries:
 Addr: 0000000008048266  Offset: 0x000266  Link: 5 (.dynsym)
  000:   0 (*local*)       2 (GLIBC_2.0)     0 (*local*)       2 (GLIBC_2.0)
  004:   1 (*global*)
Version needs section '.gnu.version_r' contains 1 entry:
 Addr: 0x0000000008048270  Offset: 0x000270  Link: 6 (.dynstr)
  000000: Version: 1  File: libc.so.6  Cnt: 1
  0x0010:   Name: GLIBC_2.0  Flags: none  Version: 2
Displaying notes found in: .note.ABI-tag
  Owner                 Data size       Description
  GNU                  0x00000010       NT_GNU_ABI_TAG (ABI version tag)
    OS: Linux, ABI: 3.2.0
Displaying notes found in: .note.gnu.build-id
  Owner                 Data size       Description
  GNU                  0x00000014       NT_GNU_BUILD_ID (unique build ID bitstring)
    Build ID: 36918d6313b2fc56f28954cf919bd23455ee602d
swed@DESKTOP-K5N5PON:~$ objdump -d hello_world_c
hello_world_c:     file format elf32-i386
Disassembly of section .init:
080482a8 <_init>:
 80482a8:       53                      push   %ebx
 80482a9:       83 ec 08                sub    $0x8,%esp
 80482ac:       e8 af 00 00 00          call   8048360 <__x86.get_pc_thunk.bx>
 80482b1:       81 c3 4f 1d 00 00       add    $0x1d4f,%ebx
 80482b7:       8b 83 fc ff ff ff       mov    -0x4(%ebx),%eax
 80482bd:       85 c0                   test   %eax,%eax
 80482bf:       74 05                   je     80482c6 <_init+0x1e>
 80482c1:       e8 3a 00 00 00          call   8048300 <__gmon_start__@plt>
 80482c6:       83 c4 08                add    $0x8,%esp
 80482c9:       5b                      pop    %ebx
 80482ca:       c3                      ret
Disassembly of section .plt:
080482d0 <.plt>:
 80482d0:       ff 35 04 a0 04 08       pushl  0x804a004
 80482d6:       ff 25 08 a0 04 08       jmp    *0x804a008
 80482dc:       00 00                   add    %al,(%eax)
        ...
080482e0 <puts@plt>:
 80482e0:       ff 25 0c a0 04 08       jmp    *0x804a00c
 80482e6:       68 00 00 00 00          push   $0x0
 80482eb:       e9 e0 ff ff ff          jmp    80482d0 <.plt>
080482f0 <__libc_start_main@plt>:
 80482f0:       ff 25 10 a0 04 08       jmp    *0x804a010
 80482f6:       68 08 00 00 00          push   $0x8
 80482fb:       e9 d0 ff ff ff          jmp    80482d0 <.plt>
Disassembly of section .plt.got:
08048300 <__gmon_start__@plt>:
 8048300:       ff 25 fc 9f 04 08       jmp    *0x8049ffc
 8048306:       66 90                   xchg   %ax,%ax
Disassembly of section .text:
08048310 <_start>:
 8048310:       31 ed                   xor    %ebp,%ebp
 8048312:       5e                      pop    %esi
 8048313:       89 e1                   mov    %esp,%ecx
 8048315:       83 e4 f0                and    $0xfffffff0,%esp
 8048318:       50                      push   %eax
 8048319:       54                      push   %esp
 804831a:       52                      push   %edx
 804831b:       e8 23 00 00 00          call   8048343 <_start+0x33>
 8048320:       81 c3 e0 1c 00 00       add    $0x1ce0,%ebx
 8048326:       8d 83 d0 e4 ff ff       lea    -0x1b30(%ebx),%eax
 804832c:       50                      push   %eax
 804832d:       8d 83 70 e4 ff ff       lea    -0x1b90(%ebx),%eax
 8048333:       50                      push   %eax
 8048334:       51                      push   %ecx
 8048335:       56                      push   %esi
 8048336:       c7 c0 26 84 04 08       mov    $0x8048426,%eax
 804833c:       50                      push   %eax
 804833d:       e8 ae ff ff ff          call   80482f0 <__libc_start_main@plt>
 8048342:       f4                      hlt
 8048343:       8b 1c 24                mov    (%esp),%ebx
 8048346:       c3                      ret
 8048347:       66 90                   xchg   %ax,%ax
 8048349:       66 90                   xchg   %ax,%ax
 804834b:       66 90                   xchg   %ax,%ax
 804834d:       66 90                   xchg   %ax,%ax
 804834f:       90                      nop
08048350 <_dl_relocate_static_pie>:
 8048350:       f3 c3                   repz ret
 8048352:       66 90                   xchg   %ax,%ax
 8048354:       66 90                   xchg   %ax,%ax
 8048356:       66 90                   xchg   %ax,%ax
 8048358:       66 90                   xchg   %ax,%ax
 804835a:       66 90                   xchg   %ax,%ax
 804835c:       66 90                   xchg   %ax,%ax
 804835e:       66 90                   xchg   %ax,%ax
08048360 <__x86.get_pc_thunk.bx>:
 8048360:       8b 1c 24                mov    (%esp),%ebx
 8048363:       c3                      ret
 8048364:       66 90                   xchg   %ax,%ax
 8048366:       66 90                   xchg   %ax,%ax
 8048368:       66 90                   xchg   %ax,%ax
 804836a:       66 90                   xchg   %ax,%ax
 804836c:       66 90                   xchg   %ax,%ax
 804836e:       66 90                   xchg   %ax,%ax
08048370 <deregister_tm_clones>:
 8048370:       b8 1c a0 04 08          mov    $0x804a01c,%eax
 8048375:       3d 1c a0 04 08          cmp    $0x804a01c,%eax
 804837a:       74 24                   je     80483a0 <deregister_tm_clones+0x30>
 804837c:       b8 00 00 00 00          mov    $0x0,%eax
 8048381:       85 c0                   test   %eax,%eax
 8048383:       74 1b                   je     80483a0 <deregister_tm_clones+0x30>
 8048385:       55                      push   %ebp
 8048386:       89 e5                   mov    %esp,%ebp
 8048388:       83 ec 14                sub    $0x14,%esp
 804838b:       68 1c a0 04 08          push   $0x804a01c
 8048390:       ff d0                   call   *%eax
 8048392:       83 c4 10                add    $0x10,%esp
 8048395:       c9                      leave
 8048396:       c3                      ret
 8048397:       89 f6                   mov    %esi,%esi
 8048399:       8d bc 27 00 00 00 00    lea    0x0(%edi,%eiz,1),%edi
 80483a0:       f3 c3                   repz ret
 80483a2:       8d b4 26 00 00 00 00    lea    0x0(%esi,%eiz,1),%esi
 80483a9:       8d bc 27 00 00 00 00    lea    0x0(%edi,%eiz,1),%edi
080483b0 <register_tm_clones>:
 80483b0:       b8 1c a0 04 08          mov    $0x804a01c,%eax
 80483b5:       2d 1c a0 04 08          sub    $0x804a01c,%eax
 80483ba:       c1 f8 02                sar    $0x2,%eax
 80483bd:       89 c2                   mov    %eax,%edx
 80483bf:       c1 ea 1f                shr    $0x1f,%edx
 80483c2:       01 d0                   add    %edx,%eax
 80483c4:       d1 f8                   sar    %eax
 80483c6:       74 20                   je     80483e8 <register_tm_clones+0x38>
 80483c8:       ba 00 00 00 00          mov    $0x0,%edx
 80483cd:       85 d2                   test   %edx,%edx
 80483cf:       74 17                   je     80483e8 <register_tm_clones+0x38>
 80483d1:       55                      push   %ebp
 80483d2:       89 e5                   mov    %esp,%ebp
 80483d4:       83 ec 10                sub    $0x10,%esp
 80483d7:       50                      push   %eax
 80483d8:       68 1c a0 04 08          push   $0x804a01c
 80483dd:       ff d2                   call   *%edx
 80483df:       83 c4 10                add    $0x10,%esp
 80483e2:       c9                      leave
 80483e3:       c3                      ret
 80483e4:       8d 74 26 00             lea    0x0(%esi,%eiz,1),%esi
 80483e8:       f3 c3                   repz ret
 80483ea:       8d b6 00 00 00 00       lea    0x0(%esi),%esi
080483f0 <__do_global_dtors_aux>:
 80483f0:       80 3d 1c a0 04 08 00    cmpb   $0x0,0x804a01c
 80483f7:       75 17                   jne    8048410 <__do_global_dtors_aux+0x20>
 80483f9:       55                      push   %ebp
 80483fa:       89 e5                   mov    %esp,%ebp
 80483fc:       83 ec 08                sub    $0x8,%esp
 80483ff:       e8 6c ff ff ff          call   8048370 <deregister_tm_clones>
 8048404:       c6 05 1c a0 04 08 01    movb   $0x1,0x804a01c
 804840b:       c9                      leave
 804840c:       c3                      ret
 804840d:       8d 76 00                lea    0x0(%esi),%esi
 8048410:       f3 c3                   repz ret
 8048412:       8d b4 26 00 00 00 00    lea    0x0(%esi,%eiz,1),%esi
 8048419:       8d bc 27 00 00 00 00    lea    0x0(%edi,%eiz,1),%edi
08048420 <frame_dummy>:
 8048420:       55                      push   %ebp
 8048421:       89 e5                   mov    %esp,%ebp
 8048423:       5d                      pop    %ebp
 8048424:       eb 8a                   jmp    80483b0 <register_tm_clones>
08048426 <main>:
 8048426:       8d 4c 24 04             lea    0x4(%esp),%ecx
 804842a:       83 e4 f0                and    $0xfffffff0,%esp
 804842d:       ff 71 fc                pushl  -0x4(%ecx)
 8048430:       55                      push   %ebp
 8048431:       89 e5                   mov    %esp,%ebp
 8048433:       53                      push   %ebx
 8048434:       51                      push   %ecx
 8048435:       e8 24 00 00 00          call   804845e <__x86.get_pc_thunk.ax>
 804843a:       05 c6 1b 00 00          add    $0x1bc6,%eax
 804843f:       83 ec 0c                sub    $0xc,%esp
 8048442:       8d 90 f0 e4 ff ff       lea    -0x1b10(%eax),%edx
 8048448:       52                      push   %edx
 8048449:       89 c3                   mov    %eax,%ebx
 804844b:       e8 90 fe ff ff          call   80482e0 <puts@plt>
 8048450:       83 c4 10                add    $0x10,%esp
 8048453:       90                      nop
 8048454:       8d 65 f8                lea    -0x8(%ebp),%esp
 8048457:       59                      pop    %ecx
 8048458:       5b                      pop    %ebx
 8048459:       5d                      pop    %ebp
 804845a:       8d 61 fc                lea    -0x4(%ecx),%esp
 804845d:       c3                      ret
0804845e <__x86.get_pc_thunk.ax>:
 804845e:       8b 04 24                mov    (%esp),%eax
 8048461:       c3                      ret
 8048462:       66 90                   xchg   %ax,%ax
 8048464:       66 90                   xchg   %ax,%ax
 8048466:       66 90                   xchg   %ax,%ax
 8048468:       66 90                   xchg   %ax,%ax
 804846a:       66 90                   xchg   %ax,%ax
 804846c:       66 90                   xchg   %ax,%ax
 804846e:       66 90                   xchg   %ax,%ax
08048470 <__libc_csu_init>:
 8048470:       55                      push   %ebp
 8048471:       57                      push   %edi
 8048472:       56                      push   %esi
 8048473:       53                      push   %ebx
 8048474:       e8 e7 fe ff ff          call   8048360 <__x86.get_pc_thunk.bx>
 8048479:       81 c3 87 1b 00 00       add    $0x1b87,%ebx
 804847f:       83 ec 0c                sub    $0xc,%esp
 8048482:       8b 6c 24 28             mov    0x28(%esp),%ebp
 8048486:       8d b3 10 ff ff ff       lea    -0xf0(%ebx),%esi
 804848c:       e8 17 fe ff ff          call   80482a8 <_init>
 8048491:       8d 83 0c ff ff ff       lea    -0xf4(%ebx),%eax
 8048497:       29 c6                   sub    %eax,%esi
 8048499:       c1 fe 02                sar    $0x2,%esi
 804849c:       85 f6                   test   %esi,%esi
 804849e:       74 25                   je     80484c5 <__libc_csu_init+0x55>
 80484a0:       31 ff                   xor    %edi,%edi
 80484a2:       8d b6 00 00 00 00       lea    0x0(%esi),%esi
 80484a8:       83 ec 04                sub    $0x4,%esp
 80484ab:       55                      push   %ebp
 80484ac:       ff 74 24 2c             pushl  0x2c(%esp)
 80484b0:       ff 74 24 2c             pushl  0x2c(%esp)
 80484b4:       ff 94 bb 0c ff ff ff    call   *-0xf4(%ebx,%edi,4)
 80484bb:       83 c7 01                add    $0x1,%edi
 80484be:       83 c4 10                add    $0x10,%esp
 80484c1:       39 fe                   cmp    %edi,%esi
 80484c3:       75 e3                   jne    80484a8 <__libc_csu_init+0x38>
 80484c5:       83 c4 0c                add    $0xc,%esp
 80484c8:       5b                      pop    %ebx
 80484c9:       5e                      pop    %esi
 80484ca:       5f                      pop    %edi
 80484cb:       5d                      pop    %ebp
 80484cc:       c3                      ret
 80484cd:       8d 76 00                lea    0x0(%esi),%esi
080484d0 <__libc_csu_fini>:
 80484d0:       f3 c3                   repz ret
Disassembly of section .fini:
080484d4 <_fini>:
 80484d4:       53                      push   %ebx
 80484d5:       83 ec 08                sub    $0x8,%esp
 80484d8:       e8 83 fe ff ff          call   8048360 <__x86.get_pc_thunk.bx>
 80484dd:       81 c3 23 1b 00 00       add    $0x1b23,%ebx
 80484e3:       83 c4 08                add    $0x8,%esp
 80484e6:       5b                      pop    %ebx
 80484e7:       c3                      ret
2024-10-12 13:01:49.822 [INFO] Running ELF file: hello_world_c.elf
2024-10-12 13:01:49.823 [DEBUG] Instruction set initialized with 100 instructions and 6 extended instructions.
2024-10-12 13:01:49.823 [DEBUG] Segment overrides reset to default segments.
2024-10-12 13:01:49.823 [DEBUG] Emulator initialized with memory size: 0 bytes.
2024-10-12 13:01:49.824 [INFO] ELF_BASE_ADDRESS єёЄрэютыхэ эр 0x08048000
2024-10-12 13:01:49.824 [INFO] Memory resized to 1620 bytes.
2024-10-12 13:01:49.824 [INFO] Resized memory to accommodate segment at 0x00
2024-10-12 13:01:49.824 [DEBUG] Wrote 1620 bytes to address 0x00000000
2024-10-12 13:01:49.824 [DEBUG] Loaded segment: VAddr=0x00, Size=0x54
2024-10-12 13:01:49.824 [INFO] Memory resized to 8224 bytes.
2024-10-12 13:01:49.824 [INFO] Resized memory to accommodate segment at 0x0C
2024-10-12 13:01:49.824 [DEBUG] Wrote 272 bytes to address 0x00001F0C
2024-10-12 13:01:49.824 [DEBUG] Wrote 4 bytes to address 0x0000201C
2024-10-12 13:01:49.824 [DEBUG] Loaded segment: VAddr=0x0C, Size=0x14
2024-10-12 13:01:49.825 [INFO] EIP set to virtual address 0x08048310, physical address 0x00000310
2024-10-12 13:01:49.825 [DEBUG] Stack initialized at ESP = 0x0804A000
2024-10-12 13:01:49.825 [INFO] ELF file loaded successfully. Entry point at EIP=0x10
2024-10-12 13:01:49.825 [INFO] Emulation started.
2024-10-12 13:01:49.825 [DEBUG] Fetched byte 31 from virtual address 0x08048310 (physical address 0x00000310)
2024-10-12 13:01:49.825 [DEBUG] Fetched byte 31 from virtual address 0x08048310 (physical address 0x00000310)
2024-10-12 13:01:49.825 [DEBUG] Fetched opcode: 0x31
2024-10-12 13:01:49.825 [INFO] Executing instruction: XOR r32, r/m32.
2024-10-12 13:01:49.825 [DEBUG] Fetched byte ED from virtual address 0x08048311 (physical address 0x00000311)
2024-10-12 13:01:49.825 [DEBUG] XORed value 0x0x00000000 from register CH with register CH, result: 0x0x00000000.
2024-10-12 13:01:49.825 [DEBUG] Fetched byte 5E from virtual address 0x08048312 (physical address 0x00000312)
2024-10-12 13:01:49.825 [DEBUG] Fetched byte 5E from virtual address 0x08048312 (physical address 0x00000312)
2024-10-12 13:01:49.825 [DEBUG] Fetched opcode: 0x5E
2024-10-12 13:01:49.825 [ERROR] Stack underflow on POP ESI.
2024-10-12 13:01:49.825 [INFO] Emulation stopped.
2024-10-12 13:01:49.825 [ERROR] ELF program execution failed.
// Emulator.cpp
#include "Emulator.h"
#include <algorithm>
#include <stdexcept>
#include <format>
#include <sstream>
#include "Logger.h"
#include "utils.h"
Emulator::Emulator(size_t memory_size) : memory(0) {
    memory.resize(memory_size, 0);
    ELF_BASE_ADDRESS = 0x08048000;
    initialize_instruction_set();
    regs.EAX = regs.EBX = regs.ECX = regs.EDX = regs.ESI = regs.EDI = 0;
    if (memory_size > 0) {
        regs.ESP = static_cast<uint32_t>(memory_size - 16);
        initialize_stack();
    }
    else {
        regs.ESP = 0;
    }
    regs.CS = regs.DS = regs.SS = regs.ES = regs.FS = regs.GS = ELF_BASE_ADDRESS;
    reset_segment_override();
    current_brk = data_segment_start;
    Logger::get_instance().log(LogLevel::DEBUG, "Emulator initialized with memory size: " + std::to_string(memory_size) + " bytes.");
}
void Emulator::initialize_after_resize() {
    if (memory.size() > 0 && regs.ESP == 0) {
        regs.ESP = static_cast<uint32_t>(memory.size() - 16);
        initialize_stack();
        Logger::get_instance().log(LogLevel::INFO, "Stack initialized after memory resize.");
    }
}
void Emulator::initialize_stack() {
    regs.ESP = STACK_BASE_VADDR;
    uint32_t required_memory_size = STACK_BASE_VADDR - ELF_BASE_ADDRESS;
    if (memory.size() < required_memory_size) {
        memory.resize(required_memory_size, 0);
        Logger::get_instance().log(LogLevel::INFO, "Memory resized to " + std::to_string(required_memory_size) + " bytes to accommodate the stack.");
    }
    Logger::get_instance().log(LogLevel::DEBUG, "Stack initialized at ESP = " + addr_to_hex(regs.ESP));
}
void Emulator::resize_memory(uint32_t new_size) {
    if (new_size > memory.size()) {
        memory.resize(new_size, 0);
        Logger::get_instance().log(LogLevel::INFO, "Memory resized to " + std::to_string(new_size) + " bytes.");
    }
}
uint32_t Emulator::allocate_memory(uint32_t addr, uint32_t length) {
    uint32_t new_addr = current_brk;
    current_brk += length;
    if (current_brk > memory.size()) {
        resize_memory(current_brk);
        Logger::get_instance().log(LogLevel::DEBUG, "Allocated memory up to " + addr_to_hex(current_brk));
    }
    return new_addr;
}
void Emulator::write_memory(uint32_t address, const uint8_t* data, size_t size) {
    if (address + size > memory.size()) {
        Logger::get_instance().log(LogLevel::ERROR, "Attempted to write beyond memory bounds. Address: 0x" + addr_to_hex(address) + ", Size: " + std::to_string(size));
        error_flag = true;
        running = false;
        return;
    }
    std::memcpy(&memory[address], data, size);
    Logger::get_instance().log(LogLevel::DEBUG, "Wrote " + std::to_string(size) + " bytes to address " + addr_to_hex(address));
}
void Emulator::set_eip(uint32_t address) {
    try {
        uint32_t physical_address = translate_virtual_address(address);
        regs.EIP = address;
        Logger::get_instance().log(LogLevel::INFO, "EIP set to virtual address " + addr_to_hex(regs.EIP) + ", physical address " + addr_to_hex(physical_address));
    }
    catch (const std::runtime_error& e) {
        Logger::get_instance().log(LogLevel::ERROR, "Failed to set EIP to address " + addr_to_hex(address) + ": " + e.what());
        error_flag = true;
        running = false;
    }
}
void Emulator::load_program(const std::vector<uint8_t>& program, uint32_t segment_vaddr, uint32_t segment_offset, bool set_eip_flag) {
    uint32_t required_memory_size = segment_offset + program.size();
    if (required_memory_size > memory.size()) {
        memory.resize(required_memory_size, 0);
        Logger::get_instance().log(LogLevel::INFO, "Memory resized to " + std::to_string(required_memory_size) + " bytes to load the program.");
    }
    std::copy(program.begin(), program.end(), memory.begin() + segment_offset);
    Logger::get_instance().log(LogLevel::DEBUG, "Program loaded at segment offset " + addr_to_hex(segment_offset) + " with size " + std::to_string(program.size()) + " bytes.");
    bool segment_exists = false;
    for (const auto& seg : loaded_segments) if (seg.p_vaddr == segment_vaddr) { segment_exists = true; break; }
    if (!segment_exists) {
        Segment seg; seg.p_vaddr = segment_vaddr; seg.p_memsz = program.size(); seg.p_offset = segment_offset; loaded_segments.push_back(seg);
        Logger::get_instance().log(LogLevel::DEBUG, "New segment added: vaddr=" + addr_to_hex(seg.p_vaddr) + ", size=" + std::to_string(seg.p_memsz) + " bytes.");
    }
    if (set_eip_flag) {
        if (segment_vaddr >= ELF_BASE_ADDRESS && (segment_vaddr - ELF_BASE_ADDRESS) < memory.size()) {
            regs.EIP = segment_vaddr;
            Logger::get_instance().log(LogLevel::INFO, "EIP set to program entry point at " + addr_to_hex(regs.EIP));
        }
        else {
            Logger::get_instance().log(LogLevel::ERROR, "Ошибка: Установка EIP за пределами памяти. Адрес: 0x" + addr_to_hex(segment_vaddr));
            error_flag = true;
            running = false;
        }
    }
}
void Emulator::run() {
    running = true;
    Logger::get_instance().log(LogLevel::INFO, "Emulation started.");
    while (running) {
        try {
            bool prefix_present;
            do {
                prefix_present = false;
                uint8_t prefix = fetch_byte();
                switch (prefix) {
                case 0xF0: regs.lock_prefix = true; prefix_present = true; Logger::get_instance().log(LogLevel::DEBUG, "LOCK prefix detected."); break;
                case 0xF2: regs.repne_prefix = true; prefix_present = true; Logger::get_instance().log(LogLevel::DEBUG, "REPNE prefix detected."); break;
                case 0xF3: regs.rep_prefix = true; prefix_present = true; Logger::get_instance().log(LogLevel::DEBUG, "REP prefix detected."); break;
                case 0x2E: case 0x36: case 0x3E: case 0x26: case 0x64: case 0x65: set_segment_override(prefix); prefix_present = true; Logger::get_instance().log(LogLevel::DEBUG, "Segment override prefix detected: 0x" + byte_to_hex(prefix)); break;
                case 0x66: regs.operand_size_override = true; prefix_present = true; Logger::get_instance().log(LogLevel::DEBUG, "Operand-size override prefix detected."); break;
                case 0x67: regs.address_size_override = true; prefix_present = true; Logger::get_instance().log(LogLevel::DEBUG, "Address-size override prefix detected."); break;
                default: regs.EIP--; prefix_present = false; break;
                }
            } while (prefix_present);
            uint8_t opcode = fetch_byte();
            Logger::get_instance().log(LogLevel::DEBUG, "Fetched opcode: 0x" + byte_to_hex(opcode));
            if (opcode == 0x0F) {
                uint8_t ext_opcode = fetch_byte();
                Logger::get_instance().log(LogLevel::DEBUG, "Fetched extended opcode: 0x" + byte_to_hex(ext_opcode));
                auto it = extended_instruction_set.find(ext_opcode);
                if (it != extended_instruction_set.end()) (this->*(it->second))();
                else { Logger::get_instance().log(LogLevel::ERROR, "Unknown extended opcode: 0x0F 0x" + byte_to_hex(ext_opcode)); error_flag = true; running = false; }
            }
            else {
                auto it = instruction_set.find(opcode);
                if (it != instruction_set.end()) (this->*(it->second))();
                else { Logger::get_instance().log(LogLevel::ERROR, "Unknown opcode: 0x" + byte_to_hex(opcode)); error_flag = true; running = false; }
            }
            reset_prefixes();
        }
        catch (const std::exception& e) {
            Logger::get_instance().log(LogLevel::ERROR, std::string("Exception caught: ") + e.what());
            error_flag = true;
            running = false;
        }
    }
    Logger::get_instance().log(LogLevel::INFO, "Emulation stopped.");
}
void Emulator::print_registers(bool hex_output) const {
    std::ostringstream oss;
    if (hex_output) {
        oss << std::hex << "EAX: 0x" << regs.EAX << ", " << "EBX: 0x" << regs.EBX << ", " << "ECX: 0x" << regs.ECX << ", " << "EDX: 0x" << regs.EDX << ", " << "ESI: 0x" << regs.ESI << ", " << "EDI: 0x" << regs.EDI << ", " << "ESP: 0x" << regs.ESP << ", " << "EBP: 0x" << regs.EBP << ", " << "EIP: 0x" << regs.EIP << ", " << "EFLAGS: 0x" << regs.EFLAGS << std::dec;
    }
    else {
        oss << "EAX: " << regs.EAX << ", " << "EBX: " << regs.EBX << ", " << "ECX: " << regs.ECX << ", " << "EDX: " << regs.EDX << ", " << "ESI: " << regs.ESI << ", " << "EDI: " << regs.EDI << ", " << "ESP: " << regs.ESP << ", " << "EBP: " << regs.EBP << ", " << "EIP: " << regs.EIP << ", " << "EFLAGS: " << regs.EFLAGS;
    }
    Logger::get_instance().log(LogLevel::INFO, "Register States: " + oss.str());
}
void Emulator::reset_prefixes() {
    regs.lock_prefix = false;
    regs.rep_prefix = false;
    regs.repne_prefix = false;
    regs.operand_size_override = false;
    regs.address_size_override = false;
}
void Emulator::reset_segment_override() {
    current_data_segment = &regs.DS;
    current_code_segment = &regs.CS;
    Logger::get_instance().log(LogLevel::DEBUG, "Segment overrides reset to default segments.");
}
void Emulator::set_segment_override(uint8_t prefix) {
    switch (prefix) {
    case 0x2E: current_code_segment = &regs.CS; Logger::get_instance().log(LogLevel::DEBUG, "Segment override: CS"); break;
    case 0x36: current_data_segment = &regs.SS; Logger::get_instance().log(LogLevel::DEBUG, "Segment override: SS"); break;
    case 0x3E: current_data_segment = &regs.DS; Logger::get_instance().log(LogLevel::DEBUG, "Segment override: DS"); break;
    case 0x26: current_data_segment = &regs.ES; Logger::get_instance().log(LogLevel::DEBUG, "Segment override: ES"); break;
    case 0x64: current_data_segment = &regs.FS; Logger::get_instance().log(LogLevel::DEBUG, "Segment override: FS"); break;
    case 0x65: current_data_segment = &regs.GS; Logger::get_instance().log(LogLevel::DEBUG, "Segment override: GS"); break;
    default: Logger::get_instance().log(LogLevel::WARNING, "Unknown segment override prefix: 0x" + byte_to_hex(prefix)); break;
    }
}
uint8_t Emulator::fetch_byte() {
    uint32_t virtual_address = regs.EIP;
    uint32_t physical_address;
    try {
        physical_address = translate_virtual_address(virtual_address);
    }
    catch (const std::runtime_error& e) {
        throw std::runtime_error(std::string("EIP out of bounds: ") + e.what());
    }
    if (physical_address >= memory.size()) throw std::runtime_error("Address out of bounds: " + addr_to_hex(physical_address));
    uint8_t byte = memory[physical_address];
    regs.EIP += 1;
    Logger::get_instance().log(LogLevel::DEBUG, "Fetched byte " + byte_to_hex(byte) + " from virtual address " + addr_to_hex(virtual_address) + " (physical address " + addr_to_hex(physical_address) + ")");
    return byte;
}
uint16_t Emulator::fetch_word() {
    uint32_t virtual_address = regs.EIP;
    uint32_t physical_address;
    try {
        physical_address = translate_virtual_address(virtual_address);
    }
    catch (const std::runtime_error& e) {
        throw std::runtime_error(std::string("EIP вне границ памяти: ") + e.what());
    }
    if (physical_address + 2 > memory.size()) throw std::runtime_error("Address out of bounds for word: 0x" + addr_to_hex(physical_address));
    uint16_t value = static_cast<uint16_t>(memory[physical_address]) | (static_cast<uint16_t>(memory[physical_address + 1]) << 8);
    regs.EIP += 2;
    Logger::get_instance().log(LogLevel::DEBUG, "Fetched word 0x" + byte_to_hex(value) + " from physical address " + addr_to_hex(physical_address));
    return value;
}
std::string Emulator::register_name(uint8_t code) const {
    static const std::string reg_names[8] = { "AL", "CL", "DL", "BL", "AH", "CH", "DH", "BH" };
    if (code < 8) {
        return reg_names[code];
    }
    return "UNKNOWN";
}
uint32_t Emulator::fetch_dword() {
    uint32_t virtual_address = regs.EIP;
    uint32_t physical_address;
    try {
        physical_address = translate_virtual_address(virtual_address);
    }
    catch (const std::runtime_error& e) {
        throw std::runtime_error(std::string("EIP вне границ памяти: ") + e.what());
    }
    if (physical_address + 4 > memory.size()) throw std::runtime_error("Address out of bounds for dword: 0x" + addr_to_hex(physical_address));
    uint32_t value = static_cast<uint32_t>(memory[physical_address]) | (static_cast<uint32_t>(memory[physical_address + 1]) << 8) | (static_cast<uint32_t>(memory[physical_address + 2]) << 16) | (static_cast<uint32_t>(memory[physical_address + 3]) << 24);
    regs.EIP += 4;
    Logger::get_instance().log(LogLevel::DEBUG, "Fetched dword 0x" + byte_to_hex(value) + " from physical address " + addr_to_hex(physical_address));
    return value;
}
uint32_t* Emulator::get_register_by_code(uint8_t code) {
    switch (code) {
    case 0: return &regs.EAX;
    case 1: return &regs.ECX;
    case 2: return &regs.EDX;
    case 3: return &regs.EBX;
    case 4: return &regs.ESP;
    case 5: return &regs.EBP;
    case 6: return &regs.ESI;
    case 7: return &regs.EDI;
    default: return nullptr;
    }
}
uint8_t* Emulator::get_register8_by_code(uint8_t code) {
    switch (code) {
    case 0: return reinterpret_cast<uint8_t*>(&regs.EAX);
    case 1: return reinterpret_cast<uint8_t*>(&regs.ECX);
    case 2: return reinterpret_cast<uint8_t*>(&regs.EDX);
    case 3: return reinterpret_cast<uint8_t*>(&regs.EBX);
    case 4: return reinterpret_cast<uint8_t*>(&regs.EAX) + 1;
    case 5: return reinterpret_cast<uint8_t*>(&regs.ECX) + 1;
    case 6: return reinterpret_cast<uint8_t*>(&regs.EDX) + 1;
    case 7: return reinterpret_cast<uint8_t*>(&regs.EBX) + 1;
    default: return nullptr;
    }
}
uint8_t Emulator::regm_rm(uint8_t modrm) {
    return modrm & 0x07;
}
uint32_t Emulator::translate_virtual_address(uint32_t virtual_addr) const {
    for (const auto& segment : loaded_segments) {
        if (virtual_addr >= segment.p_vaddr && virtual_addr < segment.p_vaddr + segment.p_memsz) {
            uint32_t physical_address = virtual_addr - segment.p_vaddr + segment.p_offset;
            if (physical_address >= memory.size()) throw std::runtime_error("Physical address out of bounds during translation.");
            return physical_address;
        }
    }
    throw std::runtime_error("Virtual address " + addr_to_hex(virtual_addr) + " does not map to any loaded segment.");
}
void Emulator::set_elf_base_address(uint32_t address) {
    ELF_BASE_ADDRESS = address;
    Logger::get_instance().log(LogLevel::INFO, "ELF_BASE_ADDRESS установлен на " + addr_to_hex(ELF_BASE_ADDRESS));
}
void Emulator::write_memory_dword(uint32_t address, uint32_t value) {
    if (address + 3 >= memory.size()) {
        memory.resize(address + 4, 0);
        Logger::get_instance().log(LogLevel::WARNING, "Memory resized to " + std::to_string(address + 4) + " bytes to accommodate dword write.");
    }
    memory[address] = value & 0xFF;
    memory[address + 1] = (value >> 8) & 0xFF;
    memory[address + 2] = (value >> 16) & 0xFF;
    memory[address + 3] = (value >> 24) & 0xFF;
    Logger::get_instance().log(LogLevel::DEBUG, "Wrote dword 0x" + byte_to_hex(value) + " to address " + addr_to_hex(address));
}
void Emulator::write_memory_byte(uint32_t address, uint8_t value) {
    if (address >= memory.size()) {
        memory.resize(address + 1, 0);
        Logger::get_instance().log(LogLevel::WARNING, "Memory resized to " + std::to_string(address + 1) + " bytes to accommodate byte write.");
    }
    memory[address] = value;
    Logger::get_instance().log(LogLevel::DEBUG, "Wrote byte 0x" + byte_to_hex(value) + " to address " + addr_to_hex(address));
}
uint8_t Emulator::read_memory_byte(uint32_t virtual_addr) {
    uint32_t physical_address = translate_virtual_address(virtual_addr);
    if (physical_address >= memory.size()) {
        Logger::get_instance().log(LogLevel::ERROR, "Memory access out of bounds in read_memory_byte at virtual address " + addr_to_hex(virtual_addr) + " (physical address " + addr_to_hex(physical_address) + ").");
        error_flag = true;
        running = false;
        return 0;
    }
    uint8_t value = memory[physical_address];
    Logger::get_instance().log(LogLevel::DEBUG, "Read byte 0x" + byte_to_hex(value) + " from address " + addr_to_hex(virtual_addr) + " (physical address " + addr_to_hex(physical_address) + ")");
    return value;
}
uint32_t Emulator::read_memory_dword(uint32_t address) const {
    if (address + 3 >= memory.size()) {
        Logger::get_instance().log(LogLevel::WARNING, "Attempted to read dword from out-of-bounds address " + addr_to_hex(address));
        return 0;
    }
    uint32_t value = 0;
    value |= static_cast<uint32_t>(memory[address]);
    value |= static_cast<uint32_t>(memory[address + 1]) << 8;
    value |= static_cast<uint32_t>(memory[address + 2]) << 16;
    value |= static_cast<uint32_t>(memory[address + 3]) << 24;
    Logger::get_instance().log(LogLevel::DEBUG, "Read dword 0x" + byte_to_hex(value) + " from address " + addr_to_hex(address));
    return value;
}
uint32_t Emulator::calculate_sib_address(uint8_t mod, uint8_t sib, int32_t displacement) {
    uint8_t scale = (sib >> 6) & 0x03, index = (sib >> 3) & 0x07, base = sib & 0x07;
    uint32_t base_value = (base == 5 && mod == 0) ? 0 : *get_register_by_code(base);
    uint32_t index_value = (index != 4) ? (*get_register_by_code(index) << scale) : 0;
    uint32_t address = base_value + index_value + displacement;
    Logger::get_instance().log(LogLevel::DEBUG, "Calculated SIB address: base=" + addr_to_hex(base_value) + ", index=" + addr_to_hex(index_value) + ", displacement=" + std::to_string(displacement) + ", resulting address=" + addr_to_hex(address));
    return address;
}
uint32_t Emulator::calculate_address(uint8_t modrm) {
    uint8_t mod = (modrm >> 6) & 0x03, rm = modrm & 0x07;
    uint32_t virtual_address = 0;
    if (rm == 4) {
        uint8_t sib = fetch_byte();
        int32_t displacement = (mod == 0 && (sib & 0x07) == 5) ? static_cast<int32_t>(fetch_dword()) : (mod == 1) ? static_cast<int32_t>(static_cast<int8_t>(fetch_byte())) : (mod == 2) ? static_cast<int32_t>(fetch_dword()) : 0;
        virtual_address = calculate_sib_address(mod, sib, displacement);
    }
    else {
        int32_t displacement = (mod == 0 && rm == 5) ? static_cast<int32_t>(fetch_dword()) : (mod == 1) ? static_cast<int32_t>(static_cast<int8_t>(fetch_byte())) : (mod == 2) ? static_cast<int32_t>(fetch_dword()) : 0;
        virtual_address = (mod == 0 && rm == 5) ? displacement : *get_register_by_code(rm) + displacement;
    }
    Logger::get_instance().log(LogLevel::DEBUG, "Calculated address: 0x" + addr_to_hex(virtual_address));
    return virtual_address;
}
void Emulator::set_segment_register(const std::string& segment, uint32_t value) {
    if (segment == "CS") regs.CS = value;
    else if (segment == "DS") regs.DS = value;
    else if (segment == "SS") regs.SS = value;
    else if (segment == "ES") regs.ES = value;
    else if (segment == "FS") regs.FS = value;
    else if (segment == "GS") regs.GS = value;
    else { Logger::get_instance().log(LogLevel::ERROR, "Unknown segment register: " + segment); return; }
    Logger::get_instance().log(LogLevel::INFO, "Segment register " + segment + " set to " + addr_to_hex(value));
}
Emulator::Operand Emulator::decode_operand(uint8_t modrm) {
    Operand operand;
    uint8_t mod = (modrm >> 6) & 0x03, rm = modrm & 0x07;
    if (mod == 3) { operand.is_memory = false; operand.register_code = rm; }
    else { operand.is_memory = true; operand.address = calculate_address(modrm); }
    Logger::get_instance().log(LogLevel::DEBUG, "Decoded operand: is_memory=" + std::to_string(operand.is_memory) + ", address=" + (operand.is_memory ? addr_to_hex(operand.address) : "N/A") + ", register_code=" + std::to_string(operand.register_code));
    return operand;
}
void Emulator::initialize_instruction_set() {
    instruction_set[0x00] = &Emulator::instr_ADD_rm8_r8;
    instruction_set[0x01] = &Emulator::instr_ADD_rm32_r32;
    instruction_set[0x03] = &Emulator::instr_ADD_r32_rm32;
    instruction_set[0x04] = &Emulator::instr_ADD_AL_imm8;
    instruction_set[0x05] = &Emulator::instr_ADD_EAX_imm32;
    instruction_set[0x09] = &Emulator::instr_OR_rm32_r32;
    instruction_set[0x0D] = &Emulator::instr_OR_EAX_imm32;
    instruction_set[0x0E] = &Emulator::instr_OR_ECX_imm32;
    instruction_set[0x20] = &Emulator::instr_AND_rm8_r8;
    instruction_set[0x21] = &Emulator::instr_AND_rm32_r32;
    instruction_set[0x25] = &Emulator::instr_AND_EAX_imm32;
    instruction_set[0x29] = &Emulator::instr_SUB_r32_rm32;
    instruction_set[0x2C] = &Emulator::instr_SUB_AL_imm8;
    instruction_set[0x2D] = &Emulator::instr_SUB_EAX_imm32;
    instruction_set[0x31] = &Emulator::instr_XOR_r32_rm32;
    instruction_set[0x34] = &Emulator::instr_XOR_AL_imm8;
    instruction_set[0x35] = &Emulator::instr_XOR_EAX_imm32;
    instruction_set[0x39] = &Emulator::instr_CMP_r32_rm32;
    instruction_set[0x3C] = &Emulator::instr_CMP_AL_imm8;
    instruction_set[0x3D] = &Emulator::instr_CMP_EAX_imm32;
    instruction_set[0x40] = &Emulator::instr_INC_EAX;
    instruction_set[0x41] = &Emulator::instr_INC_ECX;
    instruction_set[0x48] = &Emulator::instr_DEC_EAX;
    instruction_set[0x50] = &Emulator::instr_PUSH_EAX;
    instruction_set[0x51] = &Emulator::instr_PUSH_ECX;
    instruction_set[0x52] = &Emulator::instr_PUSH_EDX;
    instruction_set[0x53] = &Emulator::instr_PUSH_EBX;
    instruction_set[0x54] = &Emulator::instr_PUSH_ESP;
    instruction_set[0x55] = &Emulator::instr_PUSH_EBP;
    instruction_set[0x56] = &Emulator::instr_PUSH_ESI;
    instruction_set[0x57] = &Emulator::instr_PUSH_EDI;
    instruction_set[0x58] = &Emulator::instr_POP_EAX;
    instruction_set[0x59] = &Emulator::instr_POP_ECX;
    instruction_set[0x5A] = &Emulator::instr_POP_EDX;
    instruction_set[0x5B] = &Emulator::instr_POP_EBX;
    instruction_set[0x5C] = &Emulator::instr_POP_ESP;
    instruction_set[0x5D] = &Emulator::instr_POP_EBP;
    instruction_set[0x5E] = &Emulator::instr_POP_ESI;
    instruction_set[0x5F] = &Emulator::instr_POP_EDI;
    instruction_set[0x60] = &Emulator::instr_PUSHAD;
    instruction_set[0x68] = &Emulator::instr_PUSH_imm32;
    instruction_set[0x6A] = &Emulator::instr_PUSH_imm8;
    instruction_set[0x69] = &Emulator::instr_IMUL_reg_rm32_imm32;
    instruction_set[0x6B] = &Emulator::instr_IMUL_reg_rm32_imm8;
    instruction_set[0x6C] = &Emulator::instr_INSB;
    instruction_set[0x72] = &Emulator::instr_JB_rel8;
    instruction_set[0x74] = &Emulator::instr_JE_rel8;
    instruction_set[0x75] = &Emulator::instr_JNE_rel8;
    instruction_set[0x77] = &Emulator::instr_JA_rel8;
    instruction_set[0x7C] = &Emulator::instr_JL_rel8;
    instruction_set[0x7F] = &Emulator::instr_JG_rel8;
    instruction_set[0x80] = &Emulator::instr_SUB_rm8_imm8;
    instruction_set[0x81] = &Emulator::instr_GROUP1_Ev_Iz_81;
    instruction_set[0x83] = &Emulator::instr_GROUP1_Ev_Iz_83;
    instruction_set[0x85] = &Emulator::instr_TEST_rm32_r32;
    instruction_set[0x88] = &Emulator::instr_MOV_rm8_r8;
    instruction_set[0x89] = &Emulator::instr_MOV_rm32_r32;
    instruction_set[0x8A] = &Emulator::instr_MOV_r8_rm8;
    instruction_set[0x8B] = &Emulator::instr_MOV_r32_r_m32;
    instruction_set[0x8D] = &Emulator::instr_LEA_r32_m;
    instruction_set[0x90] = &Emulator::instr_NOP;
    instruction_set[0xA1] = &Emulator::instr_MOV_EAX_MEM;
    instruction_set[0xA3] = &Emulator::instr_MOV_MEM_EAX;
    instruction_set[0xA4] = &Emulator::instr_MOVSB;
    instruction_set[0xB7] = &Emulator::instr_MOV_r8_imm8;
    instruction_set[0xB8] = &Emulator::instr_MOV_EAX_imm32;
    instruction_set[0xB9] = &Emulator::instr_MOV_ECX_imm32;
    instruction_set[0xBA] = &Emulator::instr_MOV_EDX_imm32;
    instruction_set[0xBB] = &Emulator::instr_MOV_EBX_imm32;
    instruction_set[0xBC] = &Emulator::instr_MOV_ESP_imm32;
    instruction_set[0xBD] = &Emulator::instr_MOV_EBP_imm32;
    instruction_set[0xBE] = &Emulator::instr_MOV_ESI_imm32;
    instruction_set[0xBF] = &Emulator::instr_MOV_EDI_imm32;
    instruction_set[0xC1] = &Emulator::instr_GROUP2_Ev_Ib;
    instruction_set[0xC2] = &Emulator::instr_RET_near_imm16;
    instruction_set[0xC3] = &Emulator::instr_RET;
    instruction_set[0xC6] = &Emulator::instr_MOV_rm8_imm8;
    instruction_set[0xC7] = &Emulator::instr_MOV_Ev_Iv;
    instruction_set[0xC9] = &Emulator::instr_LEAVE;
    instruction_set[0xCD] = &Emulator::instr_INT;
    instruction_set[0xCC] = &Emulator::instr_INT3;
    instruction_set[0xD0] = &Emulator::instr_GROUP2_Ev_Ib;
    instruction_set[0xE2] = &Emulator::instr_LOOP_rel8;
    instruction_set[0xE3] = &Emulator::instr_JECXZ_rel8;
    instruction_set[0xE8] = &Emulator::instr_CALL_rel32;
    instruction_set[0xE9] = &Emulator::instr_JMP_rel32;
    instruction_set[0xEB] = &Emulator::instr_JMP_rel8;
    instruction_set[0xEC] = &Emulator::instr_IN_AL_DX;
    instruction_set[0xEE] = &Emulator::instr_OUT_DX_AL;
    instruction_set[0xF4] = &Emulator::instr_HLT;
    instruction_set[0xF6] = &Emulator::instr_F6;
    instruction_set[0xF7] = &Emulator::instr_F7;
    instruction_set[0xF8] = &Emulator::instr_CLC;
    instruction_set[0xF9] = &Emulator::instr_STC;
    instruction_set[0xFA] = &Emulator::instr_CLI;
    instruction_set[0xFB] = &Emulator::instr_STI;
    instruction_set[0xFC] = &Emulator::instr_CLD;
    instruction_set[0xFD] = &Emulator::instr_STD;
    instruction_set[0xFE] = &Emulator::instr_INC_DEC_group;
    instruction_set[0xFF] = &Emulator::instr_GROUP5;
    extended_instruction_set[0x1E] = &Emulator::instr_ENDBR32;
    extended_instruction_set[0x84] = &Emulator::instr_JE_rel32;
    extended_instruction_set[0x85] = &Emulator::instr_JNE_rel32;
    extended_instruction_set[0x8C] = &Emulator::instr_JL_rel32;
    extended_instruction_set[0x8F] = &Emulator::instr_JG_rel32;
    extended_instruction_set[0xAF] = &Emulator::instr_IMUL_r32_rm32;
    Logger::get_instance().log(LogLevel::DEBUG, "Instruction set initialized with " + std::to_string(instruction_set.size()) + " instructions and " + std::to_string(extended_instruction_set.size()) + " extended instructions.");
}
// Instructions.cpp
#include "Emulator.h"
#include <iostream>
#include <stdint.h>
#include <string>
#include "Logger.h"
#include "utils.h"
void Emulator::update_ZF_FLAG(uint32_t result) {
    if (result == 0)
        regs.EFLAGS |= ZF_FLAG;
    else
        regs.EFLAGS &= ~ZF_FLAG;
}
void Emulator::instr_IMUL_reg_rm32_imm8() {
    uint8_t modrm = fetch_byte();
    uint8_t mod = modrm >> 6;
    uint8_t reg_code = (modrm >> 3) & 0x07;
    uint8_t rm_code = modrm & 0x07;
    uint32_t* dest_reg = get_register_by_code(reg_code);
    if (!dest_reg) {
        Logger::get_instance().log(LogLevel::ERROR, "Unknown destination register in IMUL.");
        error_flag = true;
        running = false;
        return;
    }
    uint32_t operand = 0;
    if (mod == 3) {
        uint32_t* src_reg = get_register_by_code(rm_code);
        if (!src_reg) {
            Logger::get_instance().log(LogLevel::ERROR, "Unknown source register in IMUL.");
            error_flag = true;
            running = false;
            return;
        }
        operand = *src_reg;
    }
    else {
        Logger::get_instance().log(LogLevel::ERROR, "Unsupported addressing mode in IMUL.");
        error_flag = true;
        running = false;
        return;
    }
    int8_t imm8 = static_cast<int8_t>(fetch_byte());
    int32_t result = static_cast<int32_t>(operand) * imm8;
    *dest_reg = static_cast<uint32_t>(result);
    update_ZF_FLAG(*dest_reg);
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: IMUL reg, r/m32, imm8.");
}
void Emulator::instr_MOV_EAX_imm32() {
    uint32_t imm = fetch_dword();
    regs.EAX = imm;
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: MOV EAX, imm32.");
}
void Emulator::instr_PUSH_EAX() { push(regs.EAX); }
void Emulator::instr_PUSH_ECX() { push(regs.ECX); }
void Emulator::instr_PUSH_EDX() { push(regs.EDX); }
void Emulator::instr_PUSH_EBX() { push(regs.EBX); }
void Emulator::instr_PUSH_ESP() { push(regs.ESP); }
void Emulator::instr_PUSH_EBP() { push(regs.EBP); }
void Emulator::instr_PUSH_ESI() { push(regs.ESI); }
void Emulator::instr_PUSH_EDI() { push(regs.EDI); }
void Emulator::instr_CLD() {
    regs.EFLAGS &= ~DF_FLAG;
    Logger::get_instance().log(LogLevel::DEBUG, "Executed CLD (Direction Flag cleared).");
}
void Emulator::instr_PUSH_imm8() {
    int8_t imm8 = static_cast<int8_t>(fetch_byte());
    push(static_cast<uint32_t>(imm8));
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: PUSH imm8.");
}
void Emulator::push(uint32_t value) {
    if (regs.ESP < 4) {
        Logger::get_instance().log(LogLevel::ERROR, "Stack overflow on push.");
        error_flag = true;
        running = false;
        return;
    }
    regs.ESP -= 4;
    write_memory_dword(regs.ESP, value);
}
void Emulator::instr_NOP_EAX() {
    Logger::get_instance().log(LogLevel::DEBUG, "Executed NOP [EAX].");
}
void Emulator::instr_POP_ESP() {
    if (regs.ESP + 4 > memory.size()) {
        Logger::get_instance().log(LogLevel::ERROR, "Stack underflow on POP ESP.");
        error_flag = true;
        running = false;
        return;
    }
    regs.ESP = read_memory_dword(regs.ESP);
    regs.ESP += 4;
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: POP ESP.");
}
void Emulator::instr_POP_EBX() {
    if (regs.ESP + 4 > memory.size()) {
        Logger::get_instance().log(LogLevel::ERROR, "Stack underflow on POP EBX.");
        error_flag = true;
        running = false;
        return;
    }
    regs.EBX = read_memory_dword(regs.ESP);
    regs.ESP += 4;
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: POP EBX.");
}
void Emulator::instr_POP_EDX() {
    if (regs.ESP + 4 > memory.size()) {
        Logger::get_instance().log(LogLevel::ERROR, "Stack underflow on POP EDX.");
        error_flag = true;
        running = false;
        return;
    }
    regs.EDX = read_memory_dword(regs.ESP);
    regs.ESP += 4;
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: POP EDX.");
}
void Emulator::instr_POP_ECX() {
    if (regs.ESP + 4 > memory.size()) {
        Logger::get_instance().log(LogLevel::ERROR, "Stack underflow on POP ECX.");
        error_flag = true;
        running = false;
        return;
    }
    regs.ECX = read_memory_dword(regs.ESP);
    regs.ESP += 4;
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: POP ECX.");
}
void Emulator::instr_POP_EAX() {
    if (regs.ESP + 4 > memory.size()) {
        Logger::get_instance().log(LogLevel::ERROR, "Stack underflow on POP EAX.");
        error_flag = true;
        running = false;
        return;
    }
    regs.EAX = read_memory_dword(regs.ESP);
    regs.ESP += 4;
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: POP EAX.");
}
void Emulator::instr_POP_ESI() {
    if (regs.ESP + 4 > memory.size()) {
        Logger::get_instance().log(LogLevel::ERROR, "Stack underflow on POP ESI.");
        error_flag = true;
        running = false;
        return;
    }
    regs.ESI = read_memory_dword(regs.ESP);
    regs.ESP += 4;
    Logger::get_instance().log(LogLevel::DEBUG, "Executed instruction POP ESI.");
}
void Emulator::instr_POP_EDI() {
    if (regs.ESP + 4 > memory.size()) {
        Logger::get_instance().log(LogLevel::ERROR, "Stack underflow on POP EDI.");
        error_flag = true;
        running = false;
        return;
    }
    regs.EDI = read_memory_dword(regs.ESP);
    regs.ESP += 4;
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: POP EDI.");
}
void Emulator::instr_MOV_Ev_Iv() {
    uint8_t modrm = fetch_byte();
    Operand operand = decode_operand(modrm);
    uint32_t immediate = fetch_dword();
    if (operand.is_memory) {
        write_memory_dword(operand.address, immediate);
    }
    else {
        uint32_t* reg = get_register_by_code(operand.register_code);
        if (!reg) {
            Logger::get_instance().log(LogLevel::ERROR, "Unknown register in MOV Ev, Iv.");
            error_flag = true;
            running = false;
            return;
        }
        *reg = immediate;
    }
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: MOV Ev, Iv.");
}
void Emulator::instr_INC_rm32(uint8_t modrm) {
    Operand operand = decode_operand(modrm);
    uint32_t value;
    if (operand.is_memory) {
        value = read_memory_dword(operand.address);
        value++;
        write_memory_dword(operand.address, value);
    }
    else {
        uint32_t* reg = get_register_by_code(operand.register_code);
        (*reg)++;
        value = *reg;
    }
    update_ZF_FLAG(operand.is_memory ? read_memory_dword(operand.address) : *get_register_by_code(operand.register_code));
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: INC rm32.");
}
void Emulator::instr_DEC_rm32(uint8_t modrm) {
    Operand operand = decode_operand(modrm);
    uint32_t value;
    if (operand.is_memory) {
        value = read_memory_dword(operand.address);
        value--;
        write_memory_dword(operand.address, value);
    }
    else {
        uint32_t* reg = get_register_by_code(operand.register_code);
        (*reg)--;
        value = *reg;
    }
    update_ZF_FLAG(operand.is_memory ? read_memory_dword(operand.address) : *get_register_by_code(operand.register_code));
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: DEC rm32.");
}
void Emulator::instr_IMUL_r32() {
    uint8_t modrm = fetch_byte();
    Operand operand = decode_operand(modrm);
    int32_t value;
    if (operand.is_memory) {
        value = static_cast<int32_t>(read_memory_dword(operand.address));
    }
    else {
        uint32_t* reg = get_register_by_code(operand.register_code);
        if (!reg) {
            Logger::get_instance().log(LogLevel::ERROR, "Unknown register in IMUL r32.");
            error_flag = true;
            running = false;
            return;
        }
        value = static_cast<int32_t>(*reg);
    }
    int64_t result = static_cast<int64_t>(static_cast<int32_t>(regs.EAX)) * value;
    regs.EAX = static_cast<uint32_t>(result & 0xFFFFFFFF);
    regs.EDX = static_cast<uint32_t>((result >> 32) & 0xFFFFFFFF);
    if (regs.EDX != 0) {
        regs.EFLAGS |= CF_FLAG | OF_FLAG;
    }
    else {
        regs.EFLAGS &= ~(CF_FLAG | OF_FLAG);
    }
    update_ZF_FLAG(regs.EAX);
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: IMUL r32.");
}
void Emulator::instr_DIV_r32() {
    uint8_t modrm = fetch_byte();
    Operand operand = decode_operand(modrm);
    uint32_t divisor;
    uint64_t dividend = ((uint64_t)regs.EDX << 32) | regs.EAX;
    if (operand.is_memory) {
        divisor = read_memory_dword(operand.address);
    }
    else {
        uint32_t* reg = get_register_by_code(operand.register_code);
        if (!reg) {
            Logger::get_instance().log(LogLevel::ERROR, "Unknown register in DIV r32.");
            error_flag = true;
            running = false;
            return;
        }
        divisor = *reg;
    }
    if (divisor == 0) {
        Logger::get_instance().log(LogLevel::ERROR, "Division by zero in DIV r32.");
        error_flag = true;
        running = false;
        return;
    }
    regs.EAX = static_cast<uint32_t>(dividend / divisor);
    regs.EDX = static_cast<uint32_t>(dividend % divisor);
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: DIV r32.");
}
void Emulator::instr_IDIV_r32() {
    uint8_t modrm = fetch_byte();
    Operand operand = decode_operand(modrm);
    int32_t divisor;
    int64_t dividend = ((int64_t)(int32_t)regs.EDX << 32) | regs.EAX;
    if (operand.is_memory) {
        divisor = static_cast<int32_t>(read_memory_dword(operand.address));
    }
    else {
        uint32_t* reg = get_register_by_code(operand.register_code);
        if (!reg) {
            Logger::get_instance().log(LogLevel::ERROR, "Unknown register in IDIV r32.");
            error_flag = true;
            running = false;
            return;
        }
        divisor = static_cast<int32_t>(*reg);
    }
    if (divisor == 0) {
        Logger::get_instance().log(LogLevel::ERROR, "Division by zero in IDIV r32.");
        error_flag = true;
        running = false;
        return;
    }
    regs.EAX = static_cast<uint32_t>(dividend / divisor);
    regs.EDX = static_cast<uint32_t>(dividend % divisor);
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: IDIV r32.");
}
void Emulator::instr_ROR_rm32_imm8() {
    uint8_t modrm = fetch_byte();
    Operand operand = decode_operand(modrm);
    uint8_t imm8 = fetch_byte() % 32;
    uint32_t value;
    if (operand.is_memory) {
        value = read_memory_dword(operand.address);
        value = (value >> imm8) | (value << (32 - imm8));
        write_memory_dword(operand.address, value);
    }
    else {
        uint32_t* reg = get_register_by_code(operand.register_code);
        *reg = (*reg >> imm8) | (*reg << (32 - imm8));
        value = *reg;
    }
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: ROR rm32, imm8.");
}
void Emulator::instr_RET_near_imm16() {
    if (regs.ESP + 4 > memory.size()) {
        Logger::get_instance().log(LogLevel::ERROR, "Stack underflow on RET.");
        error_flag = true;
        running = false;
        return;
    }
    uint32_t return_address = read_memory_dword(regs.ESP);
    regs.ESP += 4;
    uint16_t imm16 = fetch_word();
    regs.ESP += imm16;
    regs.EIP = return_address;
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: RET_near_imm16.");
}
void Emulator::instr_PUSHF() {
    push(regs.EFLAGS);
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: PUSHF.");
}
void Emulator::instr_POPF() {
    if (regs.ESP + 4 > memory.size()) {
        Logger::get_instance().log(LogLevel::ERROR, "Stack underflow on POPF.");
        error_flag = true;
        running = false;
        return;
    }
    regs.EFLAGS = read_memory_dword(regs.ESP);
    regs.ESP += 4;
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: POPF.");
}
void Emulator::instr_IN_AL_DX() {
    uint16_t port = regs.EDX & 0xFFFF;
    uint8_t input_value = 0xFF;
    regs.EAX = (regs.EAX & 0xFFFFFF00) | input_value;
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: IN AL, DX.");
}
void Emulator::instr_OUT_DX_AL() {
    uint16_t port = regs.EDX & 0xFFFF;
    uint8_t value = regs.EAX & 0xFF;
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: OUT DX, AL.");
}
void Emulator::instr_MOV_rm32_r32() {
    uint8_t modrm = fetch_byte();
    Operand dest = decode_operand(modrm);
    uint8_t reg_code = (modrm >> 3) & 0x07;
    uint32_t* src_reg = get_register_by_code(reg_code);
    if (!src_reg) {
        Logger::get_instance().log(LogLevel::ERROR, "Unknown source register in MOV rm32, r32.");
        error_flag = true;
        running = false;
        return;
    }
    if (dest.is_memory) {
        write_memory_dword(dest.address, *src_reg);
    }
    else {
        uint32_t* dest_reg = get_register_by_code(dest.register_code);
        if (!dest_reg) {
            Logger::get_instance().log(LogLevel::ERROR, "Unknown destination register in MOV rm32, r32.");
            error_flag = true;
            running = false;
            return;
        }
        *dest_reg = *src_reg;
    }
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: MOV rm32, r32.");
}
void Emulator::instr_MOV_rm16_r16() {
    uint8_t modrm = fetch_byte();
    Operand dest = decode_operand(modrm);
    uint8_t reg_code = (modrm >> 3) & 0x07;
    uint16_t* src_reg = reinterpret_cast<uint16_t*>(get_register_by_code(reg_code));
    if (!src_reg) {
        Logger::get_instance().log(LogLevel::ERROR, "Unknown source register in MOV rm16, r16.");
        error_flag = true;
        running = false;
        return;
    }
    if (dest.is_memory) {
        write_memory_byte(dest.address, *src_reg & 0xFF);
        write_memory_byte(dest.address + 1, (*src_reg >> 8) & 0xFF);
    }
    else {
        uint16_t* dest_reg = reinterpret_cast<uint16_t*>(get_register_by_code(dest.register_code));
        if (!dest_reg) {
            Logger::get_instance().log(LogLevel::ERROR, "Unknown destination register in MOV rm16, r16.");
            error_flag = true;
            running = false;
            return;
        }
        *dest_reg = *src_reg;
    }
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: MOV rm16, r16.");
}
void Emulator::instr_MOV_r16_rm16() {
    uint8_t modrm = fetch_byte();
    Operand src = decode_operand(modrm);
    uint8_t reg_code = (modrm >> 3) & 0x07;
    uint16_t* dest_reg = reinterpret_cast<uint16_t*>(get_register_by_code(reg_code));
    if (!dest_reg) {
        Logger::get_instance().log(LogLevel::ERROR, "Unknown destination register in MOV r16, rm16.");
        error_flag = true;
        running = false;
        return;
    }
    if (src.is_memory) {
        uint16_t value = read_memory_byte(src.address) | (read_memory_byte(src.address + 1) << 8);
        *dest_reg = value;
    }
    else {
        uint16_t* src_reg = reinterpret_cast<uint16_t*>(get_register_by_code(src.register_code));
        if (!src_reg) {
            Logger::get_instance().log(LogLevel::ERROR, "Unknown source register in MOV r16, rm16.");
            error_flag = true;
            running = false;
            return;
        }
        *dest_reg = *src_reg;
    }
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: MOV r16, rm16.");
}
void Emulator::instr_LEA() {
    uint8_t modrm = fetch_byte();
    uint8_t reg_code = (modrm >> 3) & 0x07;
    uint32_t* dest_reg = get_register_by_code(reg_code);
    if (!dest_reg) {
        Logger::get_instance().log(LogLevel::ERROR, "Unknown destination register in LEA.");
        error_flag = true;
        running = false;
        return;
    }
    uint32_t address = calculate_address(modrm);
    if (error_flag)
        return;
    *dest_reg = address;
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: LEA.");
}
void Emulator::instr_LEAVE() {
    regs.ESP = regs.EBP;
    if (regs.ESP + 4 > memory.size()) {
        Logger::get_instance().log(LogLevel::ERROR, "Stack underflow on LEAVE.");
        error_flag = true;
        running = false;
        return;
    }
    regs.EBP = read_memory_dword(regs.ESP);
    regs.ESP += 4;
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: LEAVE.");
}
void Emulator::instr_CALL_rm32(uint8_t modrm) {
    Operand operand = decode_operand(modrm);
    uint32_t address = operand.is_memory ? read_memory_dword(operand.address) : *get_register_by_code(operand.register_code);
    push(regs.EIP);
    regs.EIP = address;
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: CALL rm32.");
}
void Emulator::instr_JMP_rm32(uint8_t modrm) {
    Operand operand = decode_operand(modrm);
    uint32_t address = operand.is_memory ? read_memory_dword(operand.address) : *get_register_by_code(operand.register_code);
    regs.EIP = address;
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: JMP rm32.");
}
void Emulator::instr_PUSH_rm32(uint8_t modrm) {
    Operand operand = decode_operand(modrm);
    uint32_t value = operand.is_memory ? read_memory_dword(operand.address) : *get_register_by_code(operand.register_code);
    push(value);
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: PUSH rm32.");
}
void Emulator::instr_PUSH_imm32() {
    uint32_t imm32 = fetch_dword();
    push(imm32);
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: PUSH imm32.");
}
void Emulator::instr_GROUP5() {
    uint8_t modrm = fetch_byte();
    uint8_t reg = (modrm >> 3) & 0x07;
    switch (reg) {
    case 0:
        instr_INC_rm32(modrm);
        break;
    case 1:
        instr_DEC_rm32(modrm);
        break;
    case 2:
        instr_CALL_rm32(modrm);
        break;
    case 3:
        Logger::get_instance().log(LogLevel::ERROR, "CALL far not supported.");
        error_flag = true;
        running = false;
        break;
    case 4:
        instr_JMP_rm32(modrm);
        break;
    case 5:
        Logger::get_instance().log(LogLevel::ERROR, "JMP far not supported.");
        error_flag = true;
        running = false;
        break;
    case 6:
        instr_PUSH_rm32(modrm);
        break;
    case 7:
        instr_NOT_rm32(modrm);
        break;
    default:
        Logger::get_instance().log(LogLevel::ERROR, "Unknown subtype for 0xFF: " + std::to_string(reg));
        error_flag = true;
        running = false;
        break;
    }
}
void Emulator::instr_TEST_rm32_r32() {
    uint8_t modrm = fetch_byte();
    uint8_t mod = (modrm >> 6) & 0x03;
    uint8_t reg = (modrm >> 3) & 0x07;
    uint8_t rm = modrm & 0x07;
    uint32_t operand1 = 0;
    uint32_t operand2 = 0;
    uint32_t* reg_operand2 = get_register_by_code(reg);
    if (!reg_operand2) {
        Logger::get_instance().log(LogLevel::ERROR, "Unknown register in TEST r/m32, r32.");
        error_flag = true;
        running = false;
        return;
    }
    operand2 = *reg_operand2;
    if (mod == 3) {
        uint32_t* reg_operand1 = get_register_by_code(rm);
        if (!reg_operand1) {
            Logger::get_instance().log(LogLevel::ERROR, "Unknown register in TEST r/m32, r32.");
            error_flag = true;
            running = false;
            return;
        }
        operand1 = *reg_operand1;
    }
    else {
        uint32_t address = calculate_address(modrm);
        operand1 = read_memory_dword(address);
    }
    uint32_t result = operand1 & operand2;
    regs.EFLAGS &= ~(CF_FLAG | OF_FLAG);
    if (result == 0)
        regs.EFLAGS |= ZF_FLAG;
    else
        regs.EFLAGS &= ~ZF_FLAG;
    if (result & 0x80000000)
        regs.EFLAGS |= SF_FLAG;
    else
        regs.EFLAGS &= ~SF_FLAG;
    update_PF(static_cast<uint8_t>(result & 0xFF));
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: TEST rm32, r32.");
}
void Emulator::instr_ENDBR32() {
    uint8_t last_byte = fetch_byte();
    if (last_byte != 0xFB) {
        Logger::get_instance().log(LogLevel::ERROR, "Expected byte 0xFB after opcode 0x1E for ENDBR32, found: 0x" + byte_to_hex(last_byte));
        error_flag = true;
        running = false;
        return;
    }
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: ENDBR32.");
}
void Emulator::instr_STD() {
    regs.EFLAGS |= DF_FLAG;
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: STD.");
}
void Emulator::instr_NOP() {
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: NOP.");
}
void Emulator::instr_PUSHAD() {
    uint32_t temp_esp = regs.ESP;
    push(regs.EAX);
    push(regs.ECX);
    push(regs.EDX);
    push(regs.EBX);
    push(temp_esp);
    push(regs.EBP);
    push(regs.ESI);
    push(regs.EDI);
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: PUSHAD.");
}
void Emulator::instr_REP_MOVSB() {
    while (regs.ECX != 0) {
        uint8_t byte = read_memory_byte(regs.ESI);
        write_memory_byte(regs.EDI, byte);
        if (regs.EFLAGS & DF_FLAG) {
            regs.ESI -= 1;
            regs.EDI -= 1;
        }
        else {
            regs.ESI += 1;
            regs.EDI += 1;
        }
        regs.ECX -= 1;
    }
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: REP MOVSB.");
}
void Emulator::instr_NOT_rm32(uint8_t modrm) {
    Operand operand = decode_operand(modrm);
    if (operand.is_memory) {
        uint32_t value = read_memory_dword(operand.address);
        value = ~value;
        write_memory_dword(operand.address, value);
    }
    else {
        uint32_t* reg = get_register_by_code(operand.register_code);
        if (!reg) {
            Logger::get_instance().log(LogLevel::ERROR, "Unknown register in NOT r/m32.");
            error_flag = true;
            running = false;
            return;
        }
        *reg = ~(*reg);
    }
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: NOT r/m32.");
}
void Emulator::instr_NOP_m16_m32() {
    bool operand_size = regs.operand_size_override;
    uint8_t modrm = fetch_byte();
    uint8_t mod = (modrm >> 6) & 0x03;
    if (mod == 3) {
        uint8_t rm = modrm & 0x07;
        uint32_t* reg = get_register_by_code(rm);
        if (reg) {
            uint32_t temp = *reg;
        }
        else {
            Logger::get_instance().log(LogLevel::ERROR, "Unknown register in NOP r/m32.");
            error_flag = true;
            running = false;
            return;
        }
    }
    else {
        uint32_t address = calculate_address(modrm);
        if (operand_size) {
            uint16_t temp = read_memory_byte(address) | (read_memory_byte(address + 1) << 8);
        }
        else {
            uint32_t temp = read_memory_dword(address);
        }
    }
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: NOP m16/m32.");
}
void Emulator::instr_MOV_EBX_imm32() {
    uint32_t imm = fetch_dword();
    regs.EBX = imm;
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: MOV EBX, imm32.");
}
void Emulator::instr_MOV_ECX_imm32() {
    uint32_t imm = fetch_dword();
    regs.ECX = imm;
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: MOV ECX, imm32.");
}
void Emulator::instr_MOV_EDX_imm32() {
    uint32_t imm = fetch_dword();
    regs.EDX = imm;
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: MOV EDX, imm32.");
}
void Emulator::instr_ADD_EAX_imm32() {
    if (regs.rep_prefix || regs.repne_prefix) {
        Logger::get_instance().log(LogLevel::ERROR, "REP prefix ignored for ADD EAX, imm32.");
        error_flag = true;
        running = false;
        return;
    }
    uint32_t imm = fetch_dword();
    regs.EAX += imm;
    update_ZF_FLAG(regs.EAX);
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: ADD EAX, imm32.");
}
void Emulator::instr_SUB_EAX_imm32() {
    uint32_t imm = fetch_dword();
    regs.EAX -= imm;
    update_ZF_FLAG(regs.EAX);
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: SUB EAX, imm32.");
}
void Emulator::instr_INC_EAX() {
    regs.EAX += 1;
    update_ZF_FLAG(regs.EAX);
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: INC EAX.");
}
void Emulator::instr_DEC_EAX() {
    regs.EAX -= 1;
    update_ZF_FLAG(regs.EAX);
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: DEC EAX.");
}
void Emulator::instr_MUL_EAX() {
    uint8_t modrm = fetch_byte();
    if ((modrm & 0x38) == 0x20) {
        regs.EAX *= regs.EAX;
        update_ZF_FLAG(regs.EAX);
        Logger::get_instance().log(LogLevel::INFO, "Executed instruction: MUL EAX.");
    }
    else {
        Logger::get_instance().log(LogLevel::ERROR, "MUL instruction with unsupported operand.");
    }
}
void Emulator::instr_JMP_rel32() {
    int32_t rel = fetch_dword();
    regs.EIP += rel;
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: JMP rel32.");
}
void Emulator::instr_CMP_reg_imm8() {
    uint8_t modrm = fetch_byte();
    uint8_t reg = (modrm >> 3) & 0x07;
    uint8_t imm8 = fetch_byte();
    uint32_t* reg_ptr = get_register_by_code(regm_rm(modrm));
    if (reg_ptr) {
        uint32_t result = *reg_ptr - imm8;
        if (result == 0)
            regs.EFLAGS |= ZF_FLAG;
        else
            regs.EFLAGS &= ~ZF_FLAG;
        if (*reg_ptr < imm8)
            regs.EFLAGS |= CF_FLAG;
        else
            regs.EFLAGS &= ~CF_FLAG;
        if (result & (1 << 31))
            regs.EFLAGS |= (1 << 7);
        else
            regs.EFLAGS &= ~(1 << 7);
        Logger::get_instance().log(LogLevel::INFO, "Executed instruction: CMP reg, imm8.");
    }
    else {
        Logger::get_instance().log(LogLevel::ERROR, "CMP instruction with unsupported register.");
        error_flag = true;
        running = false;
    }
}
void Emulator::instr_JE_rel8() {
    int8_t rel = fetch_byte();
    if (regs.EFLAGS & ZF_FLAG) {
        regs.EIP += rel;
    }
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: JE rel8.");
}
void Emulator::instr_JNE_rel8() {
    int8_t rel = fetch_byte();
    if (!(regs.EFLAGS & ZF_FLAG)) {
        regs.EIP += rel;
    }
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: JNE rel8.");
}
void Emulator::instr_AND_EAX_imm32() {
    uint32_t imm = fetch_dword();
    regs.EAX &= imm;
    update_ZF_FLAG(regs.EAX);
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: AND EAX, imm32.");
}
void Emulator::instr_AND_ECX_imm32() {
    uint32_t imm = fetch_dword();
    regs.ECX &= imm;
    update_ZF_FLAG(regs.ECX);
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: AND ECX, imm32.");
}
void Emulator::instr_OR_EAX_imm32() {
    uint32_t imm = fetch_dword();
    regs.EAX |= imm;
    update_ZF_FLAG(regs.EAX);
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: OR EAX, imm32.");
}
void Emulator::instr_OR_ECX_imm32() {
    uint32_t imm = fetch_dword();
    regs.ECX |= imm;
    update_ZF_FLAG(regs.ECX);
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: OR ECX, imm32.");
}
void Emulator::instr_XOR_EAX_imm32() {
    uint32_t imm = fetch_dword();
    regs.EAX ^= imm;
    update_ZF_FLAG(regs.EAX);
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: XOR EAX, imm32.");
}
void Emulator::instr_SUB_EBX_imm32() {
    uint32_t imm = fetch_dword();
    regs.EBX -= imm;
    update_ZF_FLAG(regs.EBX);
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: SUB EBX, imm32.");
}
void Emulator::instr_CMP_EAX_imm32() {
    uint32_t imm = fetch_dword();
    uint32_t result = regs.EAX - imm;
    if (regs.EAX == imm)
        regs.EFLAGS |= ZF_FLAG;
    else
        regs.EFLAGS &= ~ZF_FLAG;
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: CMP EAX, imm32.");
}
void Emulator::instr_RET() {
    if (regs.ESP + 4 > memory.size()) {
        Logger::get_instance().log(LogLevel::ERROR, "Stack underflow on RET.");
        error_flag = true;
        running = false;
        return;
    }
    uint32_t return_address = read_memory_dword(regs.ESP);
    regs.ESP += 4;
    regs.EIP = return_address;
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: RET.");
}
void Emulator::instr_SUB_r32_imm32() {
    uint8_t modrm = fetch_byte();
    uint8_t reg_opcode = (modrm >> 3) & 0x07;
    if (reg_opcode != 5) {
        Logger::get_instance().log(LogLevel::ERROR, "Unsupported SUB instruction with reg opcode: " + std::to_string(reg_opcode));
        return;
    }
    uint32_t imm32 = fetch_dword();
    uint8_t rm = regm_rm(modrm);
    uint32_t* reg_ptr = get_register_by_code(rm);
    if (reg_ptr) {
        *reg_ptr -= imm32;
        update_ZF_FLAG(*reg_ptr);
        Logger::get_instance().log(LogLevel::INFO, "Executed instruction: SUB r32, imm32.");
    }
    else {
        Logger::get_instance().log(LogLevel::ERROR, "SUB instruction with unsupported register.");
    }
}
void Emulator::instr_CMP_r32_rm32() {
    uint8_t modrm = fetch_byte();
    uint8_t mod = (modrm >> 6) & 0x03;
    uint8_t reg_code = (modrm >> 3) & 0x07;
    uint8_t rm_code = modrm & 0x07;
    uint32_t* reg = get_register_by_code(reg_code);
    uint32_t* rm;
    if (mod == 3) {
        rm = get_register_by_code(rm_code);
        if (!rm) {
            Logger::get_instance().log(LogLevel::ERROR, "Unknown register in CMP r/m32, r32.");
            error_flag = true;
            running = false;
            return;
        }
    }
    else {
        Logger::get_instance().log(LogLevel::ERROR, "Only register mode supported for CMP r/m32, r32.");
        error_flag = true;
        running = false;
        return;
    }
    uint32_t result = *rm - *reg;
    if (result == 0)
        regs.EFLAGS |= ZF_FLAG;
    else
        regs.EFLAGS &= ~ZF_FLAG;
    if (result & 0x80000000)
        regs.EFLAGS |= SF_FLAG;
    else
        regs.EFLAGS &= ~SF_FLAG;
    if (*rm < *reg)
        regs.EFLAGS |= CF_FLAG;
    else
        regs.EFLAGS &= ~CF_FLAG;
    uint32_t sign_rm = *rm & 0x80000000;
    uint32_t sign_reg = *reg & 0x80000000;
    uint32_t sign_result = result & 0x80000000;
    if ((sign_rm != sign_reg) && (sign_rm != sign_result))
        regs.EFLAGS |= OF_FLAG;
    else
        regs.EFLAGS &= ~OF_FLAG;
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: CMP r32, rm32.");
}
void Emulator::instr_JE_rel32() {
    int32_t rel32 = fetch_dword();
    if (regs.EFLAGS & ZF_FLAG) {
        regs.EIP += rel32;
    }
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: JE rel32.");
}
void Emulator::instr_JNE_rel32() {
    int32_t rel32 = fetch_dword();
    if (!(regs.EFLAGS & ZF_FLAG)) {
        regs.EIP += rel32;
    }
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: JNE rel32.");
}
void Emulator::instr_JG_rel32() {
    int32_t rel32 = fetch_dword();
    bool zf_flag = (regs.EFLAGS & ZF_FLAG) != 0;
    bool sf_flag = (regs.EFLAGS & SF_FLAG) != 0;
    bool of_flag = (regs.EFLAGS & OF_FLAG) != 0;
    if (!zf_flag && (sf_flag == of_flag)) {
        regs.EIP += rel32;
    }
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: JG rel32.");
}
void Emulator::instr_MOV_rm8_imm8() {
    uint8_t modrm = fetch_byte();
    Operand operand = decode_operand(modrm);
    uint8_t imm8 = fetch_byte();
    if (operand.is_memory) {
        write_memory_byte(translate_virtual_address(operand.address), imm8);
    }
    else {
        uint8_t* reg = get_register8_by_code(operand.register_code);
        if (reg) {
            *reg = imm8;
        }
        else {
            Logger::get_instance().log(LogLevel::ERROR, "Unknown register in MOV r/m8, imm8.");
            error_flag = true;
            running = false;
            return;
        }
    }
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: MOV rm8, imm8.");
}
void Emulator::instr_MUL_rm32(uint8_t modrm) {
    uint8_t mod = (modrm & 0xC0) >> 6;
    uint8_t rm = (modrm & 0x07);
    uint32_t operand = 0;
    if (mod == 3) {
        uint32_t* src_reg = get_register_by_code(rm);
        if (src_reg) {
            operand = *src_reg;
        }
        else {
            Logger::get_instance().log(LogLevel::ERROR, "Unknown register in MUL r/m32.");
            error_flag = true;
            running = false;
            return;
        }
    }
    else {
        uint32_t address = calculate_address(modrm);
        operand = read_memory_dword(address);
    }
    uint64_t result = static_cast<uint64_t>(regs.EAX) * static_cast<uint64_t>(operand);
    regs.EAX = static_cast<uint32_t>(result & 0xFFFFFFFF);
    regs.EDX = static_cast<uint32_t>((result >> 32) & 0xFFFFFFFF);
    if (regs.EDX != 0) {
        regs.EFLAGS |= CF_FLAG | OF_FLAG;
    }
    else {
        regs.EFLAGS &= ~(CF_FLAG | OF_FLAG);
    }
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: MUL rm32.");
}
void Emulator::instr_DIV_rm32(uint8_t modrm) {
    Logger::get_instance().log(LogLevel::INFO, "Executing instruction: DIV r/m32.");
    uint8_t mod = (modrm >> 6) & 0x03;
    uint8_t rm = modrm & 0x07;
    uint32_t operand = 0;
    if (mod == 3) {
        uint32_t* src_reg = get_register_by_code(rm);
        if (src_reg) {
            operand = *src_reg;
        }
        else {
            Logger::get_instance().log(LogLevel::ERROR, "Unknown register in DIV r/m32.");
            error_flag = true;
            running = false;
            return;
        }
    }
    else {
        uint32_t address = calculate_address(modrm);
        operand = read_memory_dword(address);
    }
    if (operand == 0) {
        Logger::get_instance().log(LogLevel::ERROR, "Division by zero in DIV r/m32.");
        error_flag = true;
        running = false;
        return;
    }
    uint64_t dividend = ((uint64_t)regs.EDX << 32) | regs.EAX;
    regs.EAX = static_cast<uint32_t>(dividend / operand);
    regs.EDX = static_cast<uint32_t>(dividend % operand);
}
void Emulator::instr_LEA_r32_m() {
    Logger::get_instance().log(LogLevel::INFO, "Executing instruction: LEA r32, m.");
    uint8_t modrm = fetch_byte();
    uint8_t mod = modrm >> 6;
    uint8_t reg = (modrm >> 3) & 0x07;
    uint8_t rm = modrm & 0x07;
    if (mod == 3) {
        Logger::get_instance().log(LogLevel::ERROR, "Invalid LEA instruction with mod == 3.");
        error_flag = true;
        running = false;
        return;
    }
    uint32_t address = calculate_address(modrm);
    if (error_flag)
        return;
    uint32_t* dest_reg = get_register_by_code(reg);
    if (!dest_reg) {
        Logger::get_instance().log(LogLevel::ERROR, "Unknown destination register in LEA.");
        error_flag = true;
        running = false;
        return;
    }
    *dest_reg = address;
}
void Emulator::instr_IDIV_rm32(uint8_t modrm) {
    Logger::get_instance().log(LogLevel::INFO, "Executing instruction: IDIV r/m32.");
    uint8_t mod = (modrm >> 6) & 0x03;
    uint8_t rm = modrm & 0x07;
    int32_t operand = 0;
    if (mod == 3) {
        int32_t* src_reg = reinterpret_cast<int32_t*>(get_register_by_code(rm));
        if (src_reg) {
            operand = *src_reg;
        }
        else {
            Logger::get_instance().log(LogLevel::ERROR, "Unknown register in IDIV r/m32.");
            error_flag = true;
            running = false;
            return;
        }
    }
    else {
        uint32_t address = calculate_address(modrm);
        operand = read_memory_dword(address);
    }
    if (operand == 0) {
        Logger::get_instance().log(LogLevel::ERROR, "Division by zero in IDIV r/m32.");
        error_flag = true;
        running = false;
        return;
    }
    int64_t dividend = ((int64_t)(int32_t)regs.EDX << 32) | regs.EAX;
    regs.EAX = static_cast<uint32_t>(dividend / operand);
    regs.EDX = static_cast<uint32_t>(dividend % operand);
}
void Emulator::instr_F7() {
    Logger::get_instance().log(LogLevel::INFO, "Executing instruction: F7.");
    uint8_t modrm = fetch_byte();
    uint8_t reg = (modrm >> 3) & 0x07;
    switch (reg) {
    case 4:
        instr_MUL_rm32(modrm);
        break;
    case 6:
        instr_DIV_rm32(modrm);
        break;
    case 7:
        instr_IDIV_rm32(modrm);
        break;
    default:
        Logger::get_instance().log(LogLevel::ERROR, "Unsupported operation in group 0xF7: " + std::to_string(reg));
        error_flag = true;
        running = false;
        break;
    }
}
void Emulator::instr_MOV_rm8_r8() {
    Logger::get_instance().log(LogLevel::INFO, "Executing instruction: MOV r/m8, r8.");
    uint8_t modrm = fetch_byte();
    uint8_t mod = (modrm >> 6) & 0x03;
    uint8_t reg_code = (modrm >> 3) & 0x07;
    uint8_t rm = modrm & 0x07;
    uint8_t* src_reg = get_register8_by_code(reg_code);
    if (!src_reg) {
        Logger::get_instance().log(LogLevel::ERROR, "Unknown source register in MOV r/m8, r8.");
        error_flag = true;
        running = false;
        return;
    }
    uint8_t value = *src_reg;
    if (mod == 3) {
        uint8_t* dest_reg = get_register8_by_code(rm);
        if (!dest_reg) {
            Logger::get_instance().log(LogLevel::ERROR, "Unknown destination register in MOV r/m8, r8.");
            error_flag = true;
            running = false;
            return;
        }
        *dest_reg = value;
    }
    else {
        uint32_t address_virtual = calculate_address(modrm);
        if (error_flag) {
            return;
        }
        uint32_t physical_address;
        try {
            physical_address = translate_virtual_address(address_virtual);
        }
        catch (const std::runtime_error& e) {
            throw std::runtime_error("MOV r/m8, r8: " + std::string(e.what()));
        }
        write_memory_byte(physical_address, value);
    }
}
void Emulator::instr_ADD_AL_imm8() {
    Logger::get_instance().log(LogLevel::INFO, "Executing instruction: ADD AL, imm8.");
    uint8_t imm8 = fetch_byte();
    uint8_t* al = reinterpret_cast<uint8_t*>(&regs.EAX);
    *al += imm8;
    update_ZF_FLAG(*al);
}
void Emulator::instr_POP_EBP() {
    Logger::get_instance().log(LogLevel::INFO, "Executing instruction: POP EBP.");
    if (regs.ESP + 4 > memory.size()) {
        Logger::get_instance().log(LogLevel::ERROR, "Stack underflow on POP EBP.");
        error_flag = true;
        running = false;
        return;
    }
    regs.EBP = read_memory_dword(regs.ESP);
    regs.ESP += 4;
    Logger::get_instance().log(LogLevel::INFO, "Executed POP EBP. EBP: 0x" + addr_to_hex(regs.EBP));
}
void Emulator::instr_MOV_ESI_imm32() {
    Logger::get_instance().log(LogLevel::INFO, "Executing instruction: MOV ESI, imm32.");
    regs.ESI = fetch_dword();
}
void Emulator::sys_read() {
    Logger::get_instance().log(LogLevel::INFO, "Executing syscall: sys_read.");
    uint32_t fd = regs.EBX;
    uint32_t buf = regs.ECX;
    uint32_t count = regs.EDX;
    if (fd != 0) {
        Logger::get_instance().log(LogLevel::ERROR, "sys_read: Only stdin (fd = 0) is supported.");
        regs.EAX = static_cast<uint32_t>(-1);
        return;
    }
    std::string input;
    std::getline(std::cin, input);
    if (input.size() < count) {
        input += '\n';
    }
    if (input.size() > count) {
        input = input.substr(0, count);
    }
    for (size_t i = 0; i < input.size(); ++i) {
        uint32_t virtual_addr = buf + static_cast<uint32_t>(i);
        uint32_t physical_addr = translate_virtual_address(virtual_addr);
        if (physical_addr >= memory.size()) {
            memory.resize(physical_addr + 1, 0);
        }
        memory[physical_addr] = static_cast<uint8_t>(input[i]);
    }
    regs.EAX = static_cast<uint32_t>(input.size());
}
void Emulator::instr_INT() {
    uint8_t int_number = fetch_byte();
    if (int_number == 0x80) {
        uint32_t syscall_number = regs.EAX;
        switch (syscall_number) {
        case 1:
            running = false;
            break;
        case 3:
            sys_read();
            break;
        case 4: {
            uint32_t fd = regs.EBX;
            uint32_t buf_virtual = regs.ECX;
            uint32_t count = regs.EDX;
            if (fd == 1) {
                try {
                    uint32_t buf_physical = translate_virtual_address(buf_virtual);
                    if (buf_physical + count > memory.size()) {
                        throw std::runtime_error("Buffer out of bounds in sys_write");
                    }
                    std::string output;
                    for (uint32_t i = 0; i < count; ++i) {
                        output += static_cast<char>(memory[buf_physical + i]);
                    }
                    std::cout << output;
                    regs.EAX = count;
                }
                catch (const std::exception& e) {
                    Logger::get_instance().log(LogLevel::ERROR, "Buffer out of bounds in sys_write: " + std::string(e.what()));
                    regs.EAX = -1;
                }
            }
            else {
                regs.EAX = -1;
            }
            break;
        }
        case 45: {
            uint32_t addr = regs.EBX;
            if (addr == 0) {
                regs.EAX = current_brk;
            }
            else {
                if (addr > current_brk) {
                    bool mapped = false;
                    for (const auto& seg : loaded_segments) {
                        if (addr >= seg.p_vaddr && addr <= (seg.p_vaddr + seg.p_memsz)) {
                            mapped = true;
                            break;
                        }
                    }
                    if (!mapped) {
                        uint32_t min_vaddr = ELF_BASE_ADDRESS;
                        uint32_t new_max_vaddr = addr;
                        uint32_t new_required_size = new_max_vaddr - min_vaddr;
                        if (new_required_size > memory.size()) {
                            resize_memory(new_required_size);
                            Logger::get_instance().log(LogLevel::DEBUG, "Emulator memory resized to 0x" + addr_to_hex(new_required_size) + " bytes on brk() call.");
                        }
                        Segment heap_segment;
                        heap_segment.p_vaddr = current_brk;
                        heap_segment.p_memsz = addr - current_brk;
                        heap_segment.p_offset = current_brk - min_vaddr;
                        loaded_segments.push_back(heap_segment);
                        std::fill(memory.begin() + heap_segment.p_offset, memory.begin() + heap_segment.p_offset + heap_segment.p_memsz, 0);
                    }
                }
                current_brk = addr;
                regs.EAX = current_brk;
            }
            break;
        }
        case 91:
            regs.EAX = 0;
            break;
        case 5:
            regs.EAX = 3;
            break;
        case 6:
            regs.EAX = 0;
            break;
        case 197: {
            uint32_t fd = regs.EBX;
            uint32_t buf = regs.ECX;
            memset(&memory[buf], 0, 104);
            regs.EAX = 0;
            break;
        }
        default:
            Logger::get_instance().log(LogLevel::ERROR, "Unknown syscall: " + std::to_string(syscall_number));
            running = false;
            break;
        }
    }
    else {
        Logger::get_instance().log(LogLevel::ERROR, "Unknown interrupt: INT " + std::to_string(int_number));
        error_flag = true;
        running = false;
    }
}
void Emulator::instr_MOV_MEM_EAX() {
    uint32_t address_virtual = fetch_dword();
    uint32_t physical_address = translate_virtual_address(address_virtual);
    write_memory_dword(physical_address, regs.EAX);
}
void Emulator::instr_MOV_EAX_MEM() {
    uint32_t address_virtual = fetch_dword();
    uint32_t physical_address = translate_virtual_address(address_virtual);
    regs.EAX = read_memory_dword(physical_address);
}
void Emulator::instr_CMP_EAX_EBX() {
    Logger::get_instance().log(LogLevel::INFO, "Executing instruction: CMP EAX, EBX.");
    uint8_t modrm = fetch_byte();
    uint8_t reg = (modrm >> 3) & 0x07;
    uint8_t rm = modrm & 0x07;
    if (reg == 0 && rm == 3) {
        uint32_t result = regs.EAX - regs.EBX;
        if (result == 0)
            regs.EFLAGS |= ZF_FLAG;
        else
            regs.EFLAGS &= ~ZF_FLAG;
        if (result & 0x80000000)
            regs.EFLAGS |= SF_FLAG;
        else
            regs.EFLAGS &= ~SF_FLAG;
        if (regs.EAX < regs.EBX)
            regs.EFLAGS |= CF_FLAG;
        else
            regs.EFLAGS &= ~CF_FLAG;
        uint32_t sign_rm = regs.EAX & 0x80000000;
        uint32_t sign_reg = regs.EBX & 0x80000000;
        uint32_t sign_result = result & 0x80000000;
        if ((sign_rm != sign_reg) && (sign_rm != sign_result))
            regs.EFLAGS |= OF_FLAG;
        else
            regs.EFLAGS &= ~OF_FLAG;
    }
    else {
        Logger::get_instance().log(LogLevel::ERROR, "CMP instruction with unsupported register combination.");
        error_flag = true;
        running = false;
    }
}
void Emulator::instr_JG_rel8() {
    Logger::get_instance().log(LogLevel::INFO, "Executing instruction: JG rel8.");
    int8_t rel = fetch_byte();
    bool zf_flag = (regs.EFLAGS & ZF_FLAG) != 0;
    bool sf_flag = (regs.EFLAGS & SF_FLAG) != 0;
    bool of_flag = (regs.EFLAGS & OF_FLAG) != 0;
    if (!zf_flag && (sf_flag == of_flag)) {
        regs.EIP += rel;
    }
}
void Emulator::instr_IMUL_reg_rm32_imm32() {
    Logger::get_instance().log(LogLevel::INFO, "Executing instruction: IMUL reg, r/m32, imm32.");
    uint8_t modrm = fetch_byte();
    uint8_t mod = modrm >> 6;
    uint8_t reg_code = (modrm >> 3) & 0x07;
    uint8_t rm_code = modrm & 0x07;
    uint32_t* dest_reg = get_register_by_code(reg_code);
    uint32_t* src_reg = nullptr;
    if (mod == 3) {
        src_reg = get_register_by_code(rm_code);
        if (!src_reg) {
            Logger::get_instance().log(LogLevel::ERROR, "Unknown source register in IMUL.");
            error_flag = true;
            running = false;
            return;
        }
    }
    else {
        Logger::get_instance().log(LogLevel::ERROR, "Unsupported addressing mode in IMUL.");
        error_flag = true;
        running = false;
        return;
    }
    if (!dest_reg) {
        Logger::get_instance().log(LogLevel::ERROR, "Unknown destination register in IMUL.");
        error_flag = true;
        running = false;
        return;
    }
    uint32_t imm32 = fetch_dword();
    int32_t result = static_cast<int32_t>(*src_reg) * static_cast<int32_t>(imm32);
    *dest_reg = static_cast<uint32_t>(result);
    update_ZF_FLAG(*dest_reg);
}
void Emulator::instr_SUB_AL_imm8() {
    Logger::get_instance().log(LogLevel::INFO, "Executing instruction: SUB AL, imm8.");
    uint8_t imm8 = fetch_byte();
    uint8_t* al = reinterpret_cast<uint8_t*>(&regs.EAX);
    *al -= imm8;
    update_ZF_FLAG(*al);
}
void Emulator::instr_JMP_rel8() {
    Logger::get_instance().log(LogLevel::INFO, "Executing instruction: JMP rel8.");
    int8_t rel = fetch_byte();
    regs.EIP += rel;
}
void Emulator::instr_JB_rel8() {
    Logger::get_instance().log(LogLevel::INFO, "Executing instruction: JB rel8.");
    int8_t rel = fetch_byte();
    if (regs.EFLAGS & CF_FLAG) {
        regs.EIP += rel;
    }
}
void Emulator::instr_JA_rel8() {
    Logger::get_instance().log(LogLevel::INFO, "Executing instruction: JA rel8.");
    int8_t rel = fetch_byte();
    bool cf_flag = (regs.EFLAGS & CF_FLAG) != 0;
    bool zf_flag = (regs.EFLAGS & ZF_FLAG) != 0;
    if (!cf_flag && !zf_flag) {
        regs.EIP += rel;
    }
}
void Emulator::instr_INC_ECX() {
    Logger::get_instance().log(LogLevel::INFO, "Executing instruction: INC ECX.");
    regs.ECX += 1;
    update_ZF_FLAG(regs.ECX);
}
void Emulator::instr_MOV_r8_imm8() {
    Logger::get_instance().log(LogLevel::INFO, "Executing instruction: MOV r8, imm8.");
    uint8_t opcode = memory[regs.EIP - 1];
    uint8_t reg_code = opcode - 0xB0;
    uint8_t imm8 = fetch_byte();
    uint8_t* reg = get_register8_by_code(reg_code);
    if (!reg) {
        Logger::get_instance().log(LogLevel::ERROR, "Unknown register in MOV r8, imm8.");
        error_flag = true;
        running = false;
        return;
    }
    *reg = imm8;
}
void Emulator::instr_SUB_rm8_imm8() {
    Logger::get_instance().log(LogLevel::INFO, "Executing instruction: SUB r/m8, imm8.");
    uint8_t modrm = fetch_byte();
    uint8_t opcode = (modrm >> 3) & 0x07;
    uint8_t rm_code = modrm & 0x07;
    if (opcode != 5) {
        Logger::get_instance().log(LogLevel::ERROR, "Unsupported opcode in SUB r/m8, imm8.");
        error_flag = true;
        running = false;
        return;
    }
    uint8_t imm8 = fetch_byte();
    uint8_t* dest = get_register8_by_code(rm_code);
    if (!dest) {
        Logger::get_instance().log(LogLevel::ERROR, "Unknown register in SUB r/m8, imm8.");
        error_flag = true;
        running = false;
        return;
    }
    *dest -= imm8;
    update_ZF_FLAG(*dest);
}
void Emulator::instr_MOV_r8_r8() {
    Logger::get_instance().log(LogLevel::INFO, "Executing instruction: MOV r8, r8.");
    uint8_t modrm = fetch_byte();
    uint8_t mod = (modrm >> 6) & 0x03;
    if (mod != 3) {
        Logger::get_instance().log(LogLevel::ERROR, "Operands must be registers (mod != 3).");
        error_flag = true;
        running = false;
        return;
    }
    uint8_t reg_code = (modrm >> 3) & 0x07;
    uint8_t rm_code = modrm & 0x07;
    uint8_t* src_reg = get_register8_by_code(reg_code);
    uint8_t* dest_reg = get_register8_by_code(rm_code);
    if (!src_reg || !dest_reg) {
        Logger::get_instance().log(LogLevel::ERROR, "Unknown register code.");
        error_flag = true;
        running = false;
        return;
    }
    *dest_reg = *src_reg;
    Logger::get_instance().log(
        LogLevel::DEBUG,
        "Moved value 0x" + byte_to_hex(*src_reg) +
        " from register " + register_name(reg_code) +
        " to register " + register_name(rm_code) + "."
    );
}
void Emulator::instr_MOV_r8_rm8() {
    Logger::get_instance().log(LogLevel::INFO, "Executing instruction: MOV r8, r/m8.");
    uint8_t modrm = fetch_byte();
    uint8_t mod = modrm >> 6;
    uint8_t reg_code = (modrm >> 3) & 0x07;
    uint8_t rm = modrm & 0x07;
    uint8_t* reg = get_register8_by_code(reg_code);
    if (!reg) {
        Logger::get_instance().log(LogLevel::ERROR, "Unknown destination register in MOV r8, r/m8.");
        error_flag = true;
        running = false;
        return;
    }
    if (mod == 3) {
        uint8_t* rm_reg = get_register8_by_code(rm);
        if (rm_reg) {
            *reg = *rm_reg;
        }
        else {
            Logger::get_instance().log(LogLevel::ERROR, "Unknown source register in MOV r8, r/m8.");
            error_flag = true;
            running = false;
        }
    }
    else {
        uint32_t address = calculate_address(modrm);
        if (error_flag) return;
        uint8_t value = read_memory_byte(address);
        *reg = value;
    }
}
void Emulator::instr_MOV_EBP_imm32() {
    Logger::get_instance().log(LogLevel::INFO, "Executing instruction: MOV EBP, imm32.");
    uint32_t imm = fetch_dword();
    regs.EBP = imm;
}
void Emulator::instr_MOV_ESP_imm32() {
    Logger::get_instance().log(LogLevel::INFO, "Executing instruction: MOV ESP, imm32.");
    uint32_t imm = fetch_dword();
    regs.ESP = imm;
}
void Emulator::instr_MOV_EDI_imm32() {
    Logger::get_instance().log(LogLevel::INFO, "Executing instruction: MOV EDI, imm32.");
    uint32_t imm = fetch_dword();
    regs.EDI = imm;
}
void Emulator::instr_MOV_r32_r_m32() {
    Logger::get_instance().log(LogLevel::INFO, "Executing instruction: MOV r32, r/m32.");
    uint8_t modrm = fetch_byte();
    uint8_t mod = (modrm >> 6) & 0x03;
    uint8_t reg = (modrm >> 3) & 0x07;
    uint8_t rm = modrm & 0x07;
    uint32_t* dest_reg = get_register_by_code(reg);
    if (mod == 3) {
        uint32_t* src_reg = get_register_by_code(rm);
        if (dest_reg && src_reg) {
            *dest_reg = *src_reg;
        }
        else {
            Logger::get_instance().log(LogLevel::ERROR, "Unknown register in MOV r32, r/m32.");
            error_flag = true;
            running = false;
        }
    }
    else {
        uint32_t address = calculate_address(modrm);
        if (error_flag) return;
        uint32_t value = read_memory_dword(address);
        if (dest_reg) {
            *dest_reg = value;
        }
        else {
            Logger::get_instance().log(LogLevel::ERROR, "Unknown destination register in MOV r32, r/m32.");
            error_flag = true;
            running = false;
        }
    }
}
void Emulator::instr_ADD_r32_rm32() {
    uint8_t modrm = fetch_byte();
    uint32_t* reg_ptr = get_register_by_code((modrm >> 3) & 0x07);
    if (!reg_ptr) {
        Logger::get_instance().log(LogLevel::ERROR, "Unknown destination register in ADD r32, r/m32.");
        error_flag = true;
        running = false;
        return;
    }
    Operand operand = decode_operand(modrm);
    uint32_t value;
    if (operand.is_memory) {
        value = read_memory_dword(operand.address);
    }
    else {
        uint32_t* reg = get_register_by_code(operand.register_code);
        if (!reg) {
            Logger::get_instance().log(LogLevel::ERROR, "Unknown source register in ADD r32, r/m32.");
            error_flag = true;
            running = false;
            return;
        }
        value = *reg;
    }
    *reg_ptr += value;
    update_ZF_FLAG(*reg_ptr);
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: ADD r32, r/m32.");
}
void Emulator::instr_ADD_rm32_r32() {
    Logger::get_instance().log(LogLevel::INFO, "Executing instruction: ADD r/m32, r32.");
    bool is_locked = regs.lock_prefix;
    uint8_t modrm = fetch_byte();
    uint8_t mod = (modrm >> 6) & 0x03;
    uint8_t reg_code = (modrm >> 3) & 0x07;
    uint8_t rm_code = modrm & 0x07;
    uint32_t* src_reg = get_register_by_code(reg_code);
    if (!src_reg) {
        Logger::get_instance().log(LogLevel::ERROR, "Unknown source register in ADD r/m32, r32.");
        error_flag = true;
        running = false;
        return;
    }
    if (mod == 3) {
        uint32_t* dest_reg = get_register_by_code(rm_code);
        if (!dest_reg) {
            Logger::get_instance().log(LogLevel::ERROR, "Unknown destination register in ADD r/m32, r32.");
            error_flag = true;
            running = false;
            return;
        }
        if (is_locked) {
            Logger::get_instance().log(LogLevel::DEBUG, "LOCK prefix applied to ADD r/m32, r32.");
        }
        *dest_reg += *src_reg;
        update_ZF_FLAG(*dest_reg);
    }
    else {
        uint32_t address = calculate_address(modrm);
        if (error_flag) return;
        uint32_t value = read_memory_dword(address);
        value += *src_reg;
        write_memory_dword(address, value);
        update_ZF_FLAG(value);
    }
    reset_prefixes();
}
void Emulator::instr_CMP_AL_imm8() {
    Logger::get_instance().log(LogLevel::INFO, "Executing instruction: CMP AL, imm8.");
    uint8_t imm8 = fetch_byte();
    uint8_t al = regs.EAX & 0xFF;
    uint8_t result = al - imm8;
    if (result == 0)
        regs.EFLAGS |= ZF_FLAG;
    else
        regs.EFLAGS &= ~ZF_FLAG;
    if (result & 0x80)
        regs.EFLAGS |= SF_FLAG;
    else
        regs.EFLAGS &= ~SF_FLAG;
    if (al < imm8)
        regs.EFLAGS |= CF_FLAG;
    else
        regs.EFLAGS &= ~CF_FLAG;
    bool overflow = ((al ^ imm8) & (al ^ result) & 0x80) != 0;
    if (overflow)
        regs.EFLAGS |= OF_FLAG;
    else
        regs.EFLAGS &= ~OF_FLAG;
    Logger::get_instance().log(
        LogLevel::DEBUG,
        "Compared AL (0x" + byte_to_hex(al) + ") with imm8 (0x" + byte_to_hex(imm8) +
        "), result: 0x" + byte_to_hex(result) + "."
    );
}
void Emulator::instr_JL_rel8() {
    Logger::get_instance().log(LogLevel::INFO, "Executing instruction: JL rel8.");
    int8_t rel = fetch_byte();
    bool sf_flag = (regs.EFLAGS & SF_FLAG) != 0;
    bool of_flag = (regs.EFLAGS & OF_FLAG) != 0;
    if (sf_flag != of_flag) {
        regs.EIP += rel;
        Logger::get_instance().log(LogLevel::DEBUG, "Jumping to EIP: 0x" + addr_to_hex(regs.EIP));
    }
}
void Emulator::instr_XOR_r32_rm32() {
    Logger::get_instance().log(LogLevel::INFO, "Executing instruction: XOR r32, r/m32.");
    uint8_t modrm = fetch_byte();
    uint8_t mod = (modrm >> 6) & 0x03;
    uint8_t reg = (modrm >> 3) & 0x07;
    uint8_t rm = modrm & 0x07;
    if (mod == 3) {
        uint32_t* src_reg = get_register_by_code(reg);
        uint32_t* dest_reg = get_register_by_code(rm);
        if (src_reg && dest_reg) {
            *dest_reg ^= *src_reg;
            update_ZF_FLAG(*dest_reg);
            Logger::get_instance().log(
                LogLevel::DEBUG,
                "XORed value 0x" + addr_to_hex(*src_reg) +
                " from register " + register_name(reg) +
                " with register " + register_name(rm) +
                ", result: 0x" + addr_to_hex(*dest_reg) + "."
            );
        }
        else {
            Logger::get_instance().log(LogLevel::ERROR, "Unknown register in XOR r/m32, r32.");
            error_flag = true;
            running = false;
        }
    }
}
void Emulator::instr_CALL_rel32() {
    Logger::get_instance().log(LogLevel::INFO, "Executing instruction: CALL rel32.");
    int32_t rel32 = fetch_dword();
    push(regs.EIP);
    regs.EIP += rel32;
    Logger::get_instance().log(LogLevel::DEBUG, "Calling function, jumped to EIP: 0x" + addr_to_hex(regs.EIP));
}
void Emulator::instr_GROUP1_Ev_Iz_81() {
    Logger::get_instance().log(LogLevel::INFO, "Executing instruction: Group 1 Ev, Iz (opcode 0x81).");
    uint8_t modrm = fetch_byte();
    uint8_t mod = (modrm >> 6) & 0x03;
    uint8_t reg_opcode = (modrm >> 3) & 0x07;
    uint8_t rm = modrm & 0x07;
    uint32_t* dest_reg = nullptr;
    if (mod == 3) {
        dest_reg = get_register_by_code(rm);
    }
    else {
        Logger::get_instance().log(LogLevel::ERROR, "Memory operands not implemented for opcode 0x81.");
        error_flag = true;
        running = false;
        return;
    }
    uint32_t imm32 = fetch_dword();
    switch (reg_opcode) {
    case 0: // ADD
        *dest_reg += imm32;
        update_ZF_FLAG(*dest_reg);
        Logger::get_instance().log(LogLevel::DEBUG, "Added 0x" + addr_to_hex(imm32) + " to register " + register_name(rm) + ".");
        break;
    case 1: // OR
        *dest_reg |= imm32;
        update_ZF_FLAG(*dest_reg);
        break;
    case 4: // AND
        *dest_reg &= imm32;
        update_ZF_FLAG(*dest_reg);
        break;
    case 5: // SUB
        *dest_reg -= imm32;
        update_ZF_FLAG(*dest_reg);
        break;
    case 6: // XOR
        *dest_reg ^= imm32;
        update_ZF_FLAG(*dest_reg);
        break;
    case 7: // CMP
    {
        uint32_t result = *dest_reg - imm32;
        update_ZF_FLAG(result);
        Logger::get_instance().log(LogLevel::DEBUG, "Compared register " + register_name(rm) + " with 0x" + addr_to_hex(imm32) + ".");
        break;
    }
    default:
        Logger::get_instance().log(LogLevel::ERROR, "Unsupported reg opcode in opcode 0x81: " + std::to_string(reg_opcode));
        error_flag = true;
        running = false;
        break;
    }
}
void Emulator::instr_GROUP1_Ev_Iz_83() {
    Logger::get_instance().log(LogLevel::INFO, "Executing instruction: Group 1 Ev, Iz (opcode 0x83).");
    uint8_t modrm = fetch_byte();
    uint8_t mod = (modrm >> 6) & 0x03;
    uint8_t reg_opcode = (modrm >> 3) & 0x07;
    uint8_t rm = modrm & 0x07;
    uint32_t* dest_reg = nullptr;
    if (mod == 3) {
        dest_reg = get_register_by_code(rm);
    }
    else {
        Logger::get_instance().log(LogLevel::ERROR, "Memory operands not implemented for opcode 0x83.");
        error_flag = true;
        running = false;
        return;
    }
    int8_t imm8 = static_cast<int8_t>(fetch_byte());
    int32_t sign_extended_imm = static_cast<int32_t>(imm8);
    switch (reg_opcode) {
    case 0: // ADD
        *dest_reg += sign_extended_imm;
        update_ZF_FLAG(*dest_reg);
        Logger::get_instance().log(LogLevel::DEBUG, "Added sign-extended imm8 (0x" + byte_to_hex(imm8) + ") to register " + register_name(rm) + ".");
        break;
    case 1: // OR
        *dest_reg |= sign_extended_imm;
        update_ZF_FLAG(*dest_reg);
        break;
    case 4: // AND
        *dest_reg &= sign_extended_imm;
        update_ZF_FLAG(*dest_reg);
        break;
    case 5: // SUB
        *dest_reg -= sign_extended_imm;
        update_ZF_FLAG(*dest_reg);
        break;
    case 6: // XOR
        *dest_reg ^= sign_extended_imm;
        update_ZF_FLAG(*dest_reg);
        break;
    case 7: // CMP
    {
        uint32_t result = *dest_reg - sign_extended_imm;
        update_ZF_FLAG(result);
        Logger::get_instance().log(LogLevel::DEBUG, "Compared register " + register_name(rm) + " with sign-extended imm8 (0x" + byte_to_hex(imm8) + ").");
        break;
    }
    default:
        Logger::get_instance().log(LogLevel::ERROR, "Unsupported reg opcode in opcode 0x83: " + std::to_string(reg_opcode));
        error_flag = true;
        running = false;
        break;
    }
}
void Emulator::instr_JL_rel32() {
    Logger::get_instance().log(LogLevel::INFO, "Executing instruction: JL rel32.");
    int32_t rel32 = fetch_dword();
    bool sf_flag = (regs.EFLAGS & SF_FLAG) != 0;
    bool of_flag = (regs.EFLAGS & OF_FLAG) != 0;
    if (sf_flag != of_flag) {
        regs.EIP += rel32;
        Logger::get_instance().log(LogLevel::DEBUG, "Jumping to EIP: 0x" + addr_to_hex(regs.EIP));
    }
}
void Emulator::instr_MOVSB() {
    Logger::get_instance().log(LogLevel::INFO, "Executing instruction: MOVSB.");
    if (regs.rep_prefix || regs.repne_prefix) {
        bool is_rep = regs.rep_prefix;
        bool is_repne = regs.repne_prefix;
        while (regs.ECX != 0) {
            uint8_t byte = read_memory_byte(regs.ESI);
            write_memory_byte(regs.EDI, byte);
            regs.ESI += 1;
            regs.EDI += 1;
            regs.ECX -= 1;
            update_ZF_FLAG(byte);
            if (is_repne && (regs.EFLAGS & ZF_FLAG)) {
                break;
            }
            if (is_rep && regs.ECX == 0) {
                break;
            }
        }
        reset_prefixes();
    }
    else {
        uint8_t byte = read_memory_byte(regs.ESI);
        write_memory_byte(regs.EDI, byte);
        regs.ESI += 1;
        regs.EDI += 1;
        update_ZF_FLAG(byte);
    }
    Logger::get_instance().log(LogLevel::DEBUG, "MOVSB completed, updated ESI: 0x" + addr_to_hex(regs.ESI) + ", EDI: 0x" + addr_to_hex(regs.EDI));
}
void Emulator::instr_ADD_rm8_r8() {
    Logger::get_instance().log(LogLevel::INFO, "Executing instruction: ADD r/m8, r8.");
    uint8_t modrm = fetch_byte();
    uint8_t mod = (modrm >> 6) & 0x03;
    uint8_t reg_code = (modrm >> 3) & 0x07;
    uint8_t rm = modrm & 0x07;
    uint8_t* src_reg = get_register8_by_code(reg_code);
    if (!src_reg) {
        Logger::get_instance().log(LogLevel::ERROR, "Unknown source register in ADD r/m8, r8.");
        error_flag = true;
        running = false;
        return;
    }
    if (mod == 3) {
        uint8_t* dest_reg = get_register8_by_code(rm);
        if (!dest_reg) {
            Logger::get_instance().log(LogLevel::ERROR, "Unknown destination register in ADD r/m8, r8.");
            error_flag = true;
            running = false;
            return;
        }
        *dest_reg += *src_reg;
        update_ZF_FLAG(*dest_reg);
    }
    else {
        uint32_t address = calculate_address(modrm);
        if (error_flag) return;
        uint8_t value = read_memory_byte(address);
        value += *src_reg;
        write_memory_byte(address, value);
        update_ZF_FLAG(value);
    }
}
void Emulator::instr_XOR_AL_imm8() {
    uint8_t imm8 = fetch_byte();
    uint8_t* al = reinterpret_cast<uint8_t*>(&regs.EAX);
    *al ^= imm8;
    if (*al == 0)
        regs.EFLAGS |= ZF_FLAG;
    else
        regs.EFLAGS &= ~ZF_FLAG;
    if (*al & 0x80)
        regs.EFLAGS |= SF_FLAG;
    else
        regs.EFLAGS &= ~SF_FLAG;
    update_PF(*al);
    regs.EFLAGS &= ~CF_FLAG;
    regs.EFLAGS &= ~OF_FLAG;
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: XOR AL, imm8.");
}
void Emulator::update_PF(uint8_t result) {
    // Count the number of set bits
    uint8_t count = 0;
    for (int i = 0; i < 8; ++i) {
        if (result & (1 << i))
            count++;
    }
    if (count % 2 == 0)
        regs.EFLAGS |= PF_FLAG;
    else
        regs.EFLAGS &= ~PF_FLAG;
}
void Emulator::instr_AND_rm8_r8() {
    uint8_t modrm = fetch_byte();
    uint8_t mod = (modrm >> 6) & 0x03;
    uint8_t reg_code = (modrm >> 3) & 0x07;
    uint8_t rm = modrm & 0x07;
    uint8_t* reg = get_register8_by_code(reg_code);
    if (!reg) {
        Logger::get_instance().log(LogLevel::ERROR, "Unknown source register in AND r/m8, r8.");
        error_flag = true;
        running = false;
        return;
    }
    uint8_t value;
    if (mod == 3) {
        uint8_t* dest_reg = get_register8_by_code(rm);
        if (!dest_reg) {
            Logger::get_instance().log(LogLevel::ERROR, "Unknown destination register in AND r/m8, r8.");
            error_flag = true;
            running = false;
            return;
        }
        *dest_reg &= *reg;
        value = *dest_reg;
        update_ZF_FLAG(value);
    }
    else {
        uint32_t address = calculate_address(modrm);
        if (error_flag) return;
        value = read_memory_byte(address);
        value &= *reg;
        write_memory_byte(address, value);
        update_ZF_FLAG(value);
    }
    regs.EFLAGS &= ~(CF_FLAG | OF_FLAG);
    if ((value & 0x80) != 0)
        regs.EFLAGS |= SF_FLAG;
    else
        regs.EFLAGS &= ~SF_FLAG;
    update_PF(value);
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: AND r/m8, r8.");
}
void Emulator::instr_INSB() {
    try {
        uint32_t port = regs.EDX;
        uint32_t address = regs.EDI;
        uint8_t input_byte = 0x00;
        write_memory_byte(address, input_byte);
        if (regs.EFLAGS & DF_FLAG) regs.EDI -= 1;
        else regs.EDI += 1;
        Logger::get_instance().log(LogLevel::INFO, "Executed instruction: INSB.");
    }
    catch (const std::exception& e) {
        Logger::get_instance().log(LogLevel::ERROR, std::string("Exception in INSB handler: ") + e.what());
        error_flag = true;
        running = false;
    }
}
void Emulator::instr_IMUL_r32_rm32() {
    uint8_t modrm = fetch_byte();
    uint8_t mod = modrm >> 6;
    uint8_t reg_code = (modrm >> 3) & 0x07;
    uint8_t rm_code = modrm & 0x07;
    uint32_t* dest_reg = get_register_by_code(reg_code);
    uint32_t operand = 0;
    if (mod == 3) {
        uint32_t* src_reg = get_register_by_code(rm_code);
        if (!src_reg) {
            Logger::get_instance().log(LogLevel::ERROR, "Unknown source register in IMUL r32, r/m32.");
            error_flag = true;
            running = false;
            return;
        }
        operand = *src_reg;
    }
    else {
        uint32_t address = calculate_address(modrm);
        if (error_flag) return;
        operand = read_memory_dword(address);
    }
    if (!dest_reg) {
        Logger::get_instance().log(LogLevel::ERROR, "Unknown destination register in IMUL r32, r/m32.");
        error_flag = true;
        running = false;
        return;
    }
    int64_t result = static_cast<int64_t>(static_cast<int32_t>(*dest_reg)) * static_cast<int64_t>(static_cast<int32_t>(operand));
    *dest_reg = static_cast<uint32_t>(result & 0xFFFFFFFF);
    if (result == static_cast<int64_t>(static_cast<int32_t>(*dest_reg))) {
        regs.EFLAGS &= ~CF_FLAG;
        regs.EFLAGS &= ~OF_FLAG;
    }
    else {
        regs.EFLAGS |= CF_FLAG;
        regs.EFLAGS |= OF_FLAG;
    }
    update_ZF_FLAG(*dest_reg);
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: IMUL r32, r/m32.");
}
void Emulator::instr_INC_rm8(uint8_t modrm) {
    Operand operand = decode_operand(modrm);
    uint8_t value;
    if (operand.is_memory) {
        value = read_memory_byte(operand.address);
        value++;
        write_memory_byte(operand.address, value);
    }
    else {
        uint8_t* reg = get_register8_by_code(operand.register_code);
        (*reg)++;
        value = *reg;
    }
    update_ZF_FLAG(value);
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: INC r/m8.");
}
void Emulator::instr_DEC_rm8(uint8_t modrm) {
    Operand operand = decode_operand(modrm);
    uint8_t value;
    if (operand.is_memory) {
        value = read_memory_byte(operand.address);
        value--;
        write_memory_byte(operand.address, value);
    }
    else {
        uint8_t* reg = get_register8_by_code(operand.register_code);
        (*reg)--;
        value = *reg;
    }
    update_ZF_FLAG(value);
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: DEC r/m8.");
}
void Emulator::instr_SUB_rm32_imm32() {
    uint8_t modrm = fetch_byte();
    Operand operand = decode_operand(modrm);
    uint32_t imm32 = fetch_dword();
    uint32_t value;
    if (operand.is_memory) {
        value = read_memory_dword(operand.address);
        value -= imm32;
        write_memory_dword(operand.address, value);
    }
    else {
        uint32_t* reg = get_register_by_code(operand.register_code);
        (*reg) -= imm32;
        value = *reg;
    }
    update_ZF_FLAG(value);
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: SUB r/m32, imm32.");
}
void Emulator::instr_OR_rm32_r32() {
    uint8_t modrm = fetch_byte();
    Operand dest = decode_operand(modrm);
    uint8_t reg_code = (modrm >> 3) & 0x07;
    uint32_t* src_reg = get_register_by_code(reg_code);
    uint32_t value;
    if (dest.is_memory) {
        value = read_memory_dword(dest.address);
        value |= *src_reg;
        write_memory_dword(dest.address, value);
    }
    else {
        uint32_t* dest_reg = get_register_by_code(dest.register_code);
        *dest_reg |= *src_reg;
        value = *dest_reg;
    }
    update_ZF_FLAG(value);
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: OR r/m32, r32.");
}
void Emulator::instr_AND_rm32_r32() {
    uint8_t modrm = fetch_byte();
    Operand dest = decode_operand(modrm);
    uint8_t reg_code = (modrm >> 3) & 0x07;
    uint32_t* src_reg = get_register_by_code(reg_code);
    uint32_t value;
    if (dest.is_memory) {
        value = read_memory_dword(dest.address);
        value &= *src_reg;
        write_memory_dword(dest.address, value);
    }
    else {
        uint32_t* dest_reg = get_register_by_code(dest.register_code);
        *dest_reg &= *src_reg;
        value = *dest_reg;
    }
    update_ZF_FLAG(value);
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: AND r/m32, r32.");
}
void Emulator::instr_XOR_rm32_r32() {
    uint8_t modrm = fetch_byte();
    Operand dest = decode_operand(modrm);
    uint8_t reg_code = (modrm >> 3) & 0x07;
    uint32_t* src_reg = get_register_by_code(reg_code);
    uint32_t value;
    if (dest.is_memory) {
        value = read_memory_dword(dest.address);
        value ^= *src_reg;
        write_memory_dword(dest.address, value);
    }
    else {
        uint32_t* dest_reg = get_register_by_code(dest.register_code);
        *dest_reg ^= *src_reg;
        value = *dest_reg;
    }
    update_ZF_FLAG(value);
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: XOR r/m32, r32.");
}
void Emulator::instr_ROL_rm32_imm8(uint8_t modrm, uint8_t imm8) {
    Operand operand = decode_operand(modrm);
    uint32_t value;
    if (operand.is_memory) {
        value = read_memory_dword(operand.address);
        value = (value << imm8) | (value >> (32 - imm8));
        write_memory_dword(operand.address, value);
    }
    else {
        uint32_t* reg = get_register_by_code(operand.register_code);
        *reg = (*reg << imm8) | (*reg >> (32 - imm8));
        value = *reg;
    }
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: ROL r/m32, imm8.");
}
void Emulator::instr_ROR_rm32_imm8(uint8_t modrm, uint8_t imm8) {
    Operand operand = decode_operand(modrm);
    uint32_t value;
    if (operand.is_memory) {
        value = read_memory_dword(operand.address);
        value = (value >> imm8) | (value << (32 - imm8));
        write_memory_dword(operand.address, value);
    }
    else {
        uint32_t* reg = get_register_by_code(operand.register_code);
        *reg = (*reg >> imm8) | (*reg << (32 - imm8));
        value = *reg;
    }
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: ROR r/m32, imm8.");
}
void Emulator::instr_SAR_rm32_imm8(uint8_t modrm, uint8_t imm8) {
    Operand operand = decode_operand(modrm);
    uint32_t value;
    if (operand.is_memory) {
        value = read_memory_dword(operand.address);
        value = static_cast<int32_t>(value) >> imm8;
        write_memory_dword(operand.address, value);
    }
    else {
        uint32_t* reg = get_register_by_code(operand.register_code);
        *reg = static_cast<int32_t>(*reg) >> imm8;
        value = *reg;
    }
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: SAR r/m32, imm8.");
}
void Emulator::instr_SHL_rm32_imm8(uint8_t modrm, uint8_t imm8) {
    Operand operand = decode_operand(modrm);
    uint32_t value;
    if (operand.is_memory) {
        value = read_memory_dword(operand.address);
        value <<= imm8;
        write_memory_dword(operand.address, value);
    }
    else {
        uint32_t* reg = get_register_by_code(operand.register_code);
        *reg <<= imm8;
        value = *reg;
    }
    update_ZF_FLAG(value);
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: SHL r/m32, imm8.");
}
void Emulator::instr_SHR_rm32_imm8(uint8_t modrm, uint8_t imm8) {
    Operand operand = decode_operand(modrm);
    uint32_t value;
    if (operand.is_memory) {
        value = read_memory_dword(operand.address);
        value >>= imm8;
        write_memory_dword(operand.address, value);
    }
    else {
        uint32_t* reg = get_register_by_code(operand.register_code);
        *reg >>= imm8;
        value = *reg;
    }
    update_ZF_FLAG(value);
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: SHR r/m32, imm8.");
}
void Emulator::instr_SHR_rm32_imm8() {
    uint8_t modrm = fetch_byte();
    Operand operand = decode_operand(modrm);
    uint8_t imm8 = fetch_byte();
    uint32_t value;
    if (operand.is_memory) {
        value = read_memory_dword(operand.address);
        value >>= imm8;
        write_memory_dword(operand.address, value);
    }
    else {
        uint32_t* reg = get_register_by_code(operand.register_code);
        (*reg) >>= imm8;
        value = *reg;
    }
    update_ZF_FLAG(value);
    // Обновите флаги CF и OF
}
void Emulator::instr_JMP_rel16() {
    int16_t rel16 = static_cast<int16_t>(fetch_word());
    regs.EIP += rel16;
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: JMP rel16.");
}
void Emulator::instr_JZ_rel8() {
    int8_t rel8 = static_cast<int8_t>(fetch_byte());
    if (regs.EFLAGS & ZF_FLAG) {
        regs.EIP += rel8;
    }
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: JZ rel8.");
}
void Emulator::instr_JNZ_rel8() {
    int8_t rel8 = static_cast<int8_t>(fetch_byte());
    if (!(regs.EFLAGS & ZF_FLAG)) {
        regs.EIP += rel8;
    }
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: JNZ rel8.");
}
void Emulator::instr_CLC() {
    regs.EFLAGS &= ~CF_FLAG;
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: CLC.");
}
void Emulator::instr_STC() {
    regs.EFLAGS |= CF_FLAG;
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: STC.");
}
void Emulator::instr_CLI() {
    regs.EFLAGS &= ~IF_FLAG;
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: CLI.");
}
void Emulator::instr_STI() {
    regs.EFLAGS |= IF_FLAG;
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: STI.");
}
void Emulator::instr_HLT() {
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: HLT. Stopping emulator.");
    running = false;
}
void Emulator::instr_INC_DEC_group() {
    uint8_t modrm = fetch_byte();
    uint8_t reg_opcode = (modrm >> 3) & 0x07;
    switch (reg_opcode) {
    case 0:
        instr_INC_rm8(modrm);
        break;
    case 1:
        instr_DEC_rm8(modrm);
        break;
    default:
        Logger::get_instance().log(LogLevel::ERROR, "Unsupported operation in group 0xFE: " + std::to_string(reg_opcode));
        error_flag = true;
        running = false;
        break;
    }
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: INC/DEC group.");
}
void Emulator::instr_GROUP2_Ev_Ib() {
    uint8_t modrm = fetch_byte();
    uint8_t reg_opcode = (modrm >> 3) & 0x07;
    uint8_t imm8 = fetch_byte();
    switch (reg_opcode) {
    case 0:
        instr_ROL_rm32_imm8(modrm, imm8);
        break;
    case 1:
        instr_ROR_rm32_imm8(modrm, imm8);
        break;
    case 4:
        instr_SHL_rm32_imm8(modrm, imm8);
        break;
    case 5:
        instr_SHR_rm32_imm8(modrm, imm8);
        break;
    case 7:
        instr_SAR_rm32_imm8(modrm, imm8);
        break;
    default:
        Logger::get_instance().log(LogLevel::ERROR, "Unsupported operation in group 0xC1: " + std::to_string(reg_opcode));
        error_flag = true;
        running = false;
        break;
    }
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: GROUP2 Ev, Ib.");
}
void Emulator::instr_INT3() {
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: INT3. Breakpoint encountered.");
    running = false;
}
void Emulator::instr_MUL_r32() {
    uint8_t modrm = fetch_byte();
    Operand operand = decode_operand(modrm);
    uint32_t value;
    if (operand.is_memory) {
        value = read_memory_dword(operand.address);
    }
    else {
        uint32_t* reg = get_register_by_code(operand.register_code);
        value = *reg;
    }
    uint64_t result = static_cast<uint64_t>(regs.EAX) * value;
    regs.EAX = static_cast<uint32_t>(result & 0xFFFFFFFF);
    regs.EDX = static_cast<uint32_t>((result >> 32) & 0xFFFFFFFF);
    if (regs.EDX != 0) {
        regs.EFLAGS |= CF_FLAG | OF_FLAG;
    }
    else {
        regs.EFLAGS &= ~(CF_FLAG | OF_FLAG);
    }
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: MUL r32.");
}
void Emulator::instr_ADD_rm32_imm32() {
    uint8_t modrm = fetch_byte();
    Operand operand = decode_operand(modrm);
    uint32_t imm32 = fetch_dword();
    uint32_t value;
    if (operand.is_memory) {
        value = read_memory_dword(operand.address);
        value += imm32;
        write_memory_dword(operand.address, value);
    }
    else {
        uint32_t* reg = get_register_by_code(operand.register_code);
        (*reg) += imm32;
        value = *reg;
    }
    update_ZF_FLAG(value);
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: ADD r/m32, imm32.");
}
void Emulator::instr_LOOP_rel8() {
    int8_t rel8 = static_cast<int8_t>(fetch_byte());
    regs.ECX -= 1;
    if (regs.ECX != 0) {
        regs.EIP += rel8;
    }
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: LOOP rel8.");
}
void Emulator::instr_JECXZ_rel8() {
    int8_t rel8 = static_cast<int8_t>(fetch_byte());
    if (regs.ECX == 0) {
        regs.EIP += rel8;
    }
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: JECXZ rel8.");
}
void Emulator::instr_TEST_rm8_imm8(uint8_t modrm) {
    Operand operand = decode_operand(modrm);
    uint8_t imm8 = fetch_byte();
    uint8_t value;
    if (operand.is_memory) {
        value = read_memory_byte(translate_virtual_address(operand.address));
    }
    else {
        uint8_t* reg = get_register8_by_code(operand.register_code);
        if (!reg) {
            Logger::get_instance().log(LogLevel::ERROR, "Unknown register in TEST r/m8, imm8.");
            error_flag = true;
            running = false;
            return;
        }
        value = *reg;
    }
    uint8_t result = value & imm8;
    regs.EFLAGS &= ~(CF_FLAG | OF_FLAG);
    if (result == 0) {
        regs.EFLAGS |= ZF_FLAG;
    }
    else {
        regs.EFLAGS &= ~ZF_FLAG;
    }
    if (result & 0x80) {
        regs.EFLAGS |= SF_FLAG;
    }
    else {
        regs.EFLAGS &= ~SF_FLAG;
    }
    update_PF(result);
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: TEST r/m8, imm8.");
}
void Emulator::instr_NOT_rm8(uint8_t modrm) {
    Operand operand = decode_operand(modrm);
    if (operand.is_memory) {
        uint8_t value = read_memory_byte(translate_virtual_address(operand.address));
        value = ~value;
        write_memory_byte(translate_virtual_address(operand.address), value);
    }
    else {
        uint8_t* reg = get_register8_by_code(operand.register_code);
        if (!reg) {
            Logger::get_instance().log(LogLevel::ERROR, "Unknown register in NOT r/m8.");
            error_flag = true;
            running = false;
            return;
        }
        *reg = ~(*reg);
    }
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: NOT r/m8.");
}
void Emulator::instr_NEG_rm8(uint8_t modrm) {
    Operand operand = decode_operand(modrm);
    uint8_t value;
    if (operand.is_memory) {
        value = read_memory_byte(translate_virtual_address(operand.address));
        uint8_t result = -value;
        write_memory_byte(translate_virtual_address(operand.address), result);
        if (value != 0) {
            regs.EFLAGS |= CF_FLAG;
        }
        else {
            regs.EFLAGS &= ~CF_FLAG;
        }
        if (result == 0) {
            regs.EFLAGS |= ZF_FLAG;
        }
        else {
            regs.EFLAGS &= ~ZF_FLAG;
        }
        if (result & 0x80) {
            regs.EFLAGS |= SF_FLAG;
        }
        else {
            regs.EFLAGS &= ~SF_FLAG;
        }
        bool overflow = ((value & result & 0x80) != 0);
        if (overflow) {
            regs.EFLAGS |= OF_FLAG;
        }
        else {
            regs.EFLAGS &= ~OF_FLAG;
        }
        update_PF(result);
    }
    else {
        uint8_t* reg = get_register8_by_code(operand.register_code);
        if (!reg) {
            Logger::get_instance().log(LogLevel::ERROR, "Unknown register in NEG r/m8.");
            error_flag = true;
            running = false;
            return;
        }
        uint8_t result = -(*reg);
        *reg = result;
        if (*reg != 0) {
            regs.EFLAGS |= CF_FLAG;
        }
        else {
            regs.EFLAGS &= ~CF_FLAG;
        }
        if (result == 0) {
            regs.EFLAGS |= ZF_FLAG;
        }
        else {
            regs.EFLAGS &= ~ZF_FLAG;
        }
        if (result & 0x80) {
            regs.EFLAGS |= SF_FLAG;
        }
        else {
            regs.EFLAGS &= ~SF_FLAG;
        }
        bool overflow = ((*reg) & result & 0x80) != 0;
        if (overflow) {
            regs.EFLAGS |= OF_FLAG;
        }
        else {
            regs.EFLAGS &= ~OF_FLAG;
        }
        update_PF(result);
    }
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: NEG r/m8.");
}
void Emulator::instr_MUL_rm8(uint8_t modrm) {
    Operand operand = decode_operand(modrm);
    uint8_t value;
    uint8_t* al = reinterpret_cast<uint8_t*>(&regs.EAX);
    if (operand.is_memory) {
        value = read_memory_byte(translate_virtual_address(operand.address));
    }
    else {
        uint8_t* reg = get_register8_by_code(operand.register_code);
        if (!reg) {
            Logger::get_instance().log(LogLevel::ERROR, "Unknown register in MUL r/m8.");
            error_flag = true;
            running = false;
            return;
        }
        value = *reg;
    }
    uint16_t result = (*al) * value;
    regs.EAX = (regs.EAX & 0xFFFF0000) | result;
    if (result > 0xFF) {
        regs.EFLAGS |= CF_FLAG | OF_FLAG;
    }
    else {
        regs.EFLAGS &= ~(CF_FLAG | OF_FLAG);
    }
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: MUL r/m8.");
}
void Emulator::instr_IMUL_rm8(uint8_t modrm) {
    Operand operand = decode_operand(modrm);
    int8_t value;
    int8_t al = static_cast<int8_t>(regs.EAX & 0xFF);
    if (operand.is_memory) {
        value = static_cast<int8_t>(read_memory_byte(translate_virtual_address(operand.address)));
    }
    else {
        uint8_t* reg = get_register8_by_code(operand.register_code);
        if (!reg) {
            Logger::get_instance().log(LogLevel::ERROR, "Unknown register in IMUL r/m8.");
            error_flag = true;
            running = false;
            return;
        }
        value = static_cast<int8_t>(*reg);
    }
    int16_t result = al * value;
    regs.EAX = (regs.EAX & 0xFFFF0000) | static_cast<uint16_t>(result);
    if (result > 127 || result < -128) {
        regs.EFLAGS |= CF_FLAG | OF_FLAG;
    }
    else {
        regs.EFLAGS &= ~(CF_FLAG | OF_FLAG);
    }
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: IMUL r/m8.");
}
void Emulator::instr_DIV_rm8(uint8_t modrm) {
    Operand operand = decode_operand(modrm);
    uint8_t divisor;
    uint16_t ax = regs.EAX & 0xFFFF;
    if (operand.is_memory) {
        divisor = read_memory_byte(translate_virtual_address(operand.address));
    }
    else {
        uint8_t* reg = get_register8_by_code(operand.register_code);
        if (!reg) {
            Logger::get_instance().log(LogLevel::ERROR, "Unknown register in DIV r/m8.");
            error_flag = true;
            running = false;
            return;
        }
        divisor = *reg;
    }
    if (divisor == 0) {
        Logger::get_instance().log(LogLevel::ERROR, "Division by zero in DIV r/m8.");
        error_flag = true;
        running = false;
        return;
    }
    uint8_t quotient = ax / divisor;
    uint8_t remainder = ax % divisor;
    regs.EAX = (regs.EAX & 0xFFFF0000) | quotient;
    regs.EDX = (regs.EDX & 0xFFFFFF00) | remainder;
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: DIV r/m8.");
}
void Emulator::instr_IDIV_rm8(uint8_t modrm) {
    Operand operand = decode_operand(modrm);
    int8_t divisor;
    int16_t ax = static_cast<int16_t>(regs.EAX & 0xFFFF);
    if (operand.is_memory) {
        divisor = static_cast<int8_t>(read_memory_byte(translate_virtual_address(operand.address)));
    }
    else {
        uint8_t* reg = get_register8_by_code(operand.register_code);
        if (!reg) {
            Logger::get_instance().log(LogLevel::ERROR, "Unknown register in IDIV r/m8.");
            error_flag = true;
            running = false;
            return;
        }
        divisor = static_cast<int8_t>(*reg);
    }
    if (divisor == 0) {
        Logger::get_instance().log(LogLevel::ERROR, "Division by zero in IDIV r/m8.");
        error_flag = true;
        running = false;
        return;
    }
    int8_t quotient = ax / divisor;
    int8_t remainder = ax % divisor;
    regs.EAX = (regs.EAX & 0xFFFF0000) | static_cast<uint8_t>(quotient);
    regs.EDX = (regs.EDX & 0xFFFFFF00) | static_cast<uint8_t>(remainder);
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: IDIV r/m8.");
}
void Emulator::instr_F6() {
    uint8_t modrm = fetch_byte();
    uint8_t reg_opcode = (modrm >> 3) & 0x07;
    switch (reg_opcode) {
    case 0:
        instr_TEST_rm8_imm8(modrm);
        break;
    case 2:
        instr_NOT_rm8(modrm);
        break;
    case 3:
        instr_NEG_rm8(modrm);
        break;
    case 4:
        instr_MUL_rm8(modrm);
        break;
    case 5:
        instr_IMUL_rm8(modrm);
        break;
    case 6:
        instr_DIV_rm8(modrm);
        break;
    case 7:
        instr_IDIV_rm8(modrm);
        break;
    default:
        Logger::get_instance().log(LogLevel::ERROR, "Unsupported operation in group 0xF6: " + std::to_string(reg_opcode));
        error_flag = true;
        running = false;
        return;
    }
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: F6 group.");
}
void Emulator::instr_MOV_r32_rm32() {
    uint8_t modrm = fetch_byte();
    uint8_t mod = (modrm >> 6) & 0x03;
    uint8_t reg = (modrm >> 3) & 0x07;
    uint8_t rm = modrm & 0x07;
    if (mod == 3) {
        uint32_t* src_reg = get_register_by_code(reg);
        uint32_t* dest_reg = get_register_by_code(rm);
        if (src_reg && dest_reg) {
            *dest_reg = *src_reg;
        }
        else {
            Logger::get_instance().log(LogLevel::ERROR, "Unknown register in MOV r/m32, r32.");
            error_flag = true;
            running = false;
            return;
        }
    }
    else {
        uint32_t address = calculate_address(modrm);
        if (error_flag) return;
        uint32_t value = read_memory_dword(address);
        uint32_t* reg_ptr = get_register_by_code(reg);
        if (reg_ptr) {
            *reg_ptr = value;
        }
        else {
            Logger::get_instance().log(LogLevel::ERROR, "Unknown destination register in MOV r/m32, r32.");
            error_flag = true;
            running = false;
            return;
        }
    }
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: MOV r/m32, r32.");
}
void Emulator::instr_SUB_r32_rm32() {
    uint8_t modrm = fetch_byte();
    Operand operand = decode_operand(modrm);
    uint32_t value;
    if (operand.is_memory) {
        value = read_memory_dword(operand.address);
    }
    else {
        uint32_t* reg = get_register_by_code(operand.register_code);
        if (!reg) {
            Logger::get_instance().log(LogLevel::ERROR, "Unknown register in SUB r32, rm32.");
            error_flag = true;
            running = false;
            return;
        }
        value = *reg;
    }
    uint32_t* reg_ptr = get_register_by_code((modrm >> 3) & 0x07);
    if (!reg_ptr) {
        Logger::get_instance().log(LogLevel::ERROR, "Unknown destination register in SUB r32, rm32.");
        error_flag = true;
        running = false;
        return;
    }
    *reg_ptr -= value;
    update_ZF_FLAG(*reg_ptr);
    Logger::get_instance().log(LogLevel::INFO, "Executed instruction: SUB r32, rm32.");
}
// Emulator.h
#ifndef EMULATOR_H
#define EMULATOR_H
#include <vector>
#include <unordered_map>
#include <functional>
#include <cstdint>
#include <string>
class Emulator {
public:
    uint32_t ELF_BASE_ADDRESS; // Базовый адрес ELF
    struct Segment {
        uint32_t p_vaddr;
        uint32_t p_memsz;
        uint32_t p_offset;  // Смещение сегмента в файле
    };
    std::vector<Segment> loaded_segments;
    Emulator(size_t memory_size);
    void load_program(const std::vector<uint8_t>& program, uint32_t segment_vaddr, uint32_t segment_offset, bool set_eip);
    void run();
    void print_registers(bool hex_output = false) const;
    bool has_error() const { return error_flag; }
    void write_memory(uint32_t address, const uint8_t* data, size_t size);
    size_t get_memory_size() const { return memory.size(); }
    void resize_memory(uint32_t new_size);
    void set_eip(uint32_t address);
    void set_elf_base_address(uint32_t address);
    void set_segment_register(const std::string& segment, uint32_t value);
    void initialize_after_resize();
    uint32_t allocate_memory(uint32_t addr, uint32_t length);
    void initialize_stack();
    static const uint32_t STACK_BASE_VADDR = 0x0804A000; // Верхний адрес стека
    static const uint32_t STACK_SIZE = 0x2000;          // Размер стека (8 КБ)
    static const uint32_t STACK_START_VADDR = STACK_BASE_VADDR - STACK_SIZE; // Нижний адрес стека
private:
    struct Operand {
        bool is_memory;
        uint32_t address;
        uint32_t register_code;
    };
    struct Registers {
        uint32_t EAX, EBX, ECX, EDX, ESI, EDI, ESP, EBP;
        uint32_t EIP;
        uint32_t EFLAGS;
        uint32_t CS, DS, SS, ES, FS, GS;
        bool lock_prefix = false;
        bool rep_prefix = false;
        bool repne_prefix = false;
        bool operand_size_override = false;
        bool address_size_override = false;
        Registers() : EAX(0), EBX(0), ECX(0), EDX(0),
            ESI(0), EDI(0), ESP(0), EBP(0),
            EIP(0), EFLAGS(0),
            CS(0), DS(0), SS(0), ES(0), FS(0), GS(0) {}
    } regs;
    std::vector<uint8_t> memory;
    bool running = false;
    bool error_flag = false;
    uint32_t current_brk = 0;
    uint32_t data_segment_start = 0x08000000; // Начальный адрес для сегмента данных
    typedef void (Emulator::* InstructionHandler)();
    std::unordered_map<uint8_t, InstructionHandler> instruction_set;
    std::unordered_map<uint8_t, InstructionHandler> extended_instruction_set;
    void initialize_instruction_set();
    void reset_prefixes();
    // Переопределения сегментов
    void reset_segment_override();
    void set_segment_override(uint8_t prefix);
    // Флаги
    const uint32_t CF_FLAG = 1 << 0;    // Carry Flag
    const uint32_t PF_FLAG = 1 << 2;    // Parity Flag
    const uint32_t AF_FLAG = 1 << 4;    // Auxiliary Carry Flag
    const uint32_t ZF_FLAG = 1 << 6;    // Zero Flag
    const uint32_t SF_FLAG = 1 << 7;    // Sign Flag
    const uint32_t OF_FLAG = 1 << 11;   // Overflow Flag
    const uint32_t DF_FLAG = 1 << 10;   // Direction Flag
    const uint32_t IF_FLAG = 1 << 9;    // Interrupt Enable Flag
    // Текущие сегментные указатели
    uint32_t* current_data_segment;
    uint32_t* current_code_segment;
    // Объявление методов обработки инструкций
    void instr_MOV_Ev_Iv();
    void instr_MOV_EAX_imm32();
    void instr_MOV_EBX_imm32();
    void instr_MOV_ECX_imm32();
    void instr_MOV_EDX_imm32();
    void instr_ADD_EAX_imm32();
    void instr_SUB_EAX_imm32();
    void instr_INC_EAX();
    void instr_DEC_EAX();
    void instr_MUL_EAX();
    void instr_JMP_rel32();
    void instr_CMP_reg_imm8();
    void instr_JE_rel8();
    void instr_JNE_rel8();
    void instr_AND_EAX_imm32();
    void instr_AND_ECX_imm32();
    void instr_OR_EAX_imm32();
    void instr_XOR_EAX_imm32();
    void instr_SUB_r32_imm32();
    void instr_CMP_EAX_imm32();
    void instr_OR_ECX_imm32();
    void instr_RET();
    void instr_MOV_MEM_EAX();
    void instr_MOV_EAX_MEM();
    void instr_CMP_EAX_EBX();
    void instr_JG_rel8();
    void instr_JL_rel8();
    void instr_CMP_r32_rm32();
    void instr_IMUL_reg_rm32_imm32();
    void instr_JB_rel8();
    void instr_JA_rel8();
    void instr_INC_ECX();
    void instr_JMP_rel8();
    void instr_MOV_r8_imm8();
    void instr_SUB_AL_imm8();
    void instr_SUB_rm8_imm8();
    void instr_MOV_rm8_imm8();
    void instr_ADD_AL_imm8();
    void instr_MOV_ESI_imm32();
    void instr_INT();
    void instr_F7();
    void instr_MUL_rm32(uint8_t modrm);
    void instr_DIV_rm32(uint8_t modrm);
    void instr_IDIV_rm32(uint8_t modrm);
    void instr_XOR_r32_rm32();
    void instr_ADD_rm32_r32();
    void instr_CMP_AL_imm8();
    void instr_ADD_r32_rm32();
    void instr_SUB_EBX_imm32();
    void instr_IMUL_reg_rm32_imm8();
    void instr_MOV_r32_r_m32();
    void instr_MOV_EBP_imm32();
    void instr_MOV_ESP_imm32();
    void instr_MOV_EDI_imm32();
    void instr_CALL_rel32();
    void instr_GROUP1_Ev_Iz_81();
    void instr_GROUP1_Ev_Iz_83();
    void instr_LEA_r32_m();
    void instr_MOVSB();
    void instr_JNE_rel32();
    void instr_JG_rel32();
    void instr_JE_rel32();
    void instr_NOP_EAX();
    void instr_NOP_m16_m32();
    void instr_JL_rel32();
    void instr_ENDBR32();
    void instr_PUSH_EDI();
    void instr_PUSH_ESI();
    void instr_PUSH_EBP();
    void instr_PUSH_EBX();
    void instr_PUSH_EDX();
    void instr_PUSH_ECX();
    void instr_PUSH_EAX();
    void instr_PUSH_ESP();
    void instr_POP_EAX();
    void instr_POP_ECX();
    void instr_POP_EDX();
    void instr_POP_EBX();
    void instr_POP_ESP();
    void instr_POP_EBP();
    void instr_POP_ESI();
    void instr_POP_EDI();
    void instr_PUSH_imm8();
    void instr_GROUP5();
    void instr_INC_rm32(uint8_t modrm);
    void instr_DEC_rm32(uint8_t modrm);
    void instr_JMP_rm32(uint8_t modrm);
    void instr_PUSH_rm32(uint8_t modrm);
    void instr_PUSH_imm32();
    void instr_ADD_rm8_r8();
    void instr_NOP();
    void instr_PUSHAD();
    void instr_REP_MOVSB();
    void instr_XOR_AL_imm8();
    void instr_LEAVE();
    void instr_AND_rm8_r8();
    void instr_NOT_rm32(uint8_t modrm);
    void instr_TEST_rm32_r32();
    void instr_INSB();
    void instr_IMUL_r32_rm32();
    void instr_INC_DEC_group();
    void instr_GROUP2_Ev_Ib();
    void instr_F6();
    void instr_LOOP_rel8();
    void instr_JECXZ_rel8();
    void instr_SUB_r32_rm32();
    // Методы для инструкций сдвига и вращения
    void instr_ROL_rm32_imm8(uint8_t modrm, uint8_t imm8);
    void instr_ROR_rm32_imm8(uint8_t modrm, uint8_t imm8);
    void instr_SAR_rm32_imm8(uint8_t modrm, uint8_t imm8);
    void instr_SHL_rm32_imm8(uint8_t modrm, uint8_t imm8);
    void instr_SHR_rm32_imm8(uint8_t modrm, uint8_t imm8);
    // Методы для группы инструкций F6
    void instr_TEST_rm8_imm8(uint8_t modrm);
    void instr_NEG_rm8(uint8_t modrm);
    void instr_MUL_rm8(uint8_t modrm);
    void instr_IMUL_rm8(uint8_t modrm);
    void instr_DIV_rm8(uint8_t modrm);
    void instr_IDIV_rm8(uint8_t modrm);
    // Арифметические операции
    void instr_INC_rm8(uint8_t modrm);
    void instr_DEC_rm8(uint8_t modrm);
    void instr_ADD_rm32_imm32();
    void instr_SUB_rm32_imm32();
    void instr_MUL_r32();
    void instr_IMUL_r32();
    void instr_DIV_r32();
    void instr_IDIV_r32();
    // Логические операции
    void instr_OR_rm32_r32();
    void instr_AND_rm32_r32();
    void instr_XOR_rm32_r32();
    void instr_NOT_rm8(uint8_t modrm);
    // Операции сдвига и вращения
    void instr_ROR_rm32_imm8();
    void instr_SHL_rm32_imm8();
    void instr_SHR_rm32_imm8();
    // Переходы и вызовы
    void instr_JMP_rel16();
    void instr_JZ_rel8();
    void instr_JNZ_rel8();
    void instr_CALL_rm32(uint8_t modrm);
    void instr_RET_near_imm16();
    // Работа с флагами
    void instr_CLC();
    void instr_STC();
    void instr_CLI();
    void instr_STI();
    void instr_CLD();
    void instr_STD();
    void instr_PUSHF();
    void instr_POPF();
    // Операции ввода-вывода
    void instr_IN_AL_DX();
    void instr_OUT_DX_AL();
    // Операции с регистрами и памятью
    void instr_MOV_rm32_r32();
    void instr_MOV_r32_rm32();
    void instr_MOV_rm16_r16();
    void instr_MOV_r16_rm16();
    void instr_MOV_rm8_r8();
    void instr_MOV_r8_rm8();
    void instr_MOV_r8_r8();
    void instr_LEA();
    // Другие инструкции
    void instr_HLT();
    void instr_INT3();
    // Вспомогательные методы
    std::string register_name(uint8_t code) const;
    uint8_t fetch_byte();
    uint32_t fetch_dword();
    uint16_t fetch_word();
    uint32_t* get_register_by_code(uint8_t code);
    uint8_t* get_register8_by_code(uint8_t code);
    uint8_t regm_rm(uint8_t modrm);
    uint32_t calculate_address(uint8_t modrm);
    uint32_t calculate_sib_address(uint8_t mod, uint8_t sib, int32_t displacement);
    void update_ZF_FLAG(uint32_t result);
    void update_PF(uint8_t result);
    uint8_t read_memory_byte(uint32_t virtual_addr);
    uint32_t read_memory_dword(uint32_t address) const;
    void write_memory_dword(uint32_t address, uint32_t value);
    void write_memory_byte(uint32_t address, uint8_t value);
    void push(uint32_t value);
    uint32_t translate_virtual_address(uint32_t virtual_addr) const;
    Operand decode_operand(uint8_t modrm);
    void sys_read();
};
#endif // EMULATOR_H