swed@DESKTOP-K5N5PON:~$ nasm -f elf32 calculator.asm -o calculator.o
ld -m elf_i386 calculator.o -o calculator.elf
swed@DESKTOP-K5N5PON:~$ ./calculator.elf
Result: 12
swed@DESKTOP-K5N5PON:~$ cp calculator.elf /mnt/c/Users/Swed/Desktop/
swed@DESKTOP-K5N5PON:~$ readelf -a calculator.elf | grep -E 'result_prefix|sum_str'
     2: 0804a000     0 NOTYPE  LOCAL  DEFAULT    2 result_prefix
     3: 0804a008     0 NOTYPE  LOCAL  DEFAULT    2 sum_str
C:\Users\Swed\source\repos\x86_Emulator\x64\Debug>x86_Emulator.exe calculator.elf

Запуск программы из файла: calculator.elf...
Объем выделенной памяти эмулятора: 256 MB
Загрузка сегмента PT_LOAD:
  p_vaddr: 0x8048000
  p_memsz: 148 байт
  p_filesz: 148 байт
Загрузка сегмента PT_LOAD:
  p_vaddr: 0x8049000
  p_memsz: 95 байт
  p_filesz: 95 байт
Загрузка сегмента PT_LOAD:
  p_vaddr: 0x804a000
  p_memsz: 11 байт
  p_filesz: 11 байт
ELF-файл успешно загружен. Точка входа: 0x8049000
Result: 05
Программа из ELF-файла успешно выполнена!  swed@DESKTOP-K5N5PON:~$ readelf -a calculator.elf
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:               0x8049000
  Start of program headers:          52 (bytes into file)
  Start of section headers:          8436 (bytes into file)
  Flags:                             0x0
  Size of this header:               52 (bytes)
  Size of program headers:           32 (bytes)
  Number of program headers:         3
  Size of section headers:           40 (bytes)
  Number of section headers:         6
  Section header string table index: 5

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .text             PROGBITS        08049000 001000 00005f 00  AX  0   0 16
  [ 2] .data             PROGBITS        0804a000 002000 00000b 00  WA  0   0  4
  [ 3] .symtab           SYMTAB          00000000 00200c 000080 10      4   4  4
  [ 4] .strtab           STRTAB          00000000 00208c 00003e 00      0   0  1
  [ 5] .shstrtab         STRTAB          00000000 0020ca 000027 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),
  D (mbind), p (processor specific)

There are no section groups in this file.

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  LOAD           0x000000 0x08048000 0x08048000 0x00094 0x00094 R   0x1000
  LOAD           0x001000 0x08049000 0x08049000 0x0005f 0x0005f R E 0x1000
  LOAD           0x002000 0x0804a000 0x0804a000 0x0000b 0x0000b RW  0x1000

 Section to Segment mapping:
  Segment Sections...
   00
   01     .text
   02     .data

There is no dynamic section in this file.

There are no relocations in this file.
No processor specific unwind information to decode

Symbol table '.symtab' contains 8 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 00000000     0 FILE    LOCAL  DEFAULT  ABS calculator.asm
     2: 0804a000     0 NOTYPE  LOCAL  DEFAULT    2 result_prefix
     3: 0804a008     0 NOTYPE  LOCAL  DEFAULT    2 sum_str
     4: 08049000     0 NOTYPE  GLOBAL DEFAULT    1 _start
     5: 0804a00b     0 NOTYPE  GLOBAL DEFAULT    2 __bss_start
     6: 0804a00b     0 NOTYPE  GLOBAL DEFAULT    2 _edata
     7: 0804a00c     0 NOTYPE  GLOBAL DEFAULT    2 _end

No version information found in this file. swed@DESKTOP-K5N5PON:~$ ./calculator.elf
Result: 12
Работай с этим кодом: // Instructions.cpp
#include "Emulator.h"
#include <iostream>
#include <stdint.h>
#include <string>
// Реализация обработчиков инструкций

// MOV EAX, imm32
void Emulator::instr_MOV_EAX_imm32() {
    uint32_t imm = fetch_dword();
    regs.EAX = imm;
}

// MOV EBX, imm32
void Emulator::instr_MOV_EBX_imm32() {
    uint32_t imm = fetch_dword();
    regs.EBX = imm;
}

// MOV ECX, imm32
void Emulator::instr_MOV_ECX_imm32() {
    uint32_t imm = fetch_dword();
    regs.ECX = imm;
}

// MOV EDX, imm32
void Emulator::instr_MOV_EDX_imm32() {
    uint32_t imm = fetch_dword();
    regs.EDX = imm;
}

// ADD EAX, imm32
void Emulator::instr_ADD_EAX_imm32() {
    uint32_t imm = fetch_dword();
    regs.EAX += imm;
    update_ZF(regs.EAX);
}

// SUB EAX, imm32
void Emulator::instr_SUB_EAX_imm32() {
    uint32_t imm = fetch_dword();
    regs.EAX -= imm;
    update_ZF(regs.EAX);
}

// INC EAX
void Emulator::instr_INC_EAX() {
    regs.EAX += 1;
    update_ZF(regs.EAX);
}

// DEC EAX
void Emulator::instr_DEC_EAX() {
    regs.EAX -= 1;
    update_ZF(regs.EAX);
}

// MUL EAX
void Emulator::instr_MUL_EAX() {
    uint8_t modrm = fetch_byte();
    // Для простоты реализуем только MUL EAX
    if ((modrm & 0x38) == 0x20) { // Проверяем, что это MUL r/m32
        regs.EAX *= regs.EAX;
        update_ZF(regs.EAX);
    }
    else {
        std::cout << "MUL instruction with unsupported operand.\n";
        // Можно установить флаг ошибки или завершить выполнение
    }
}

// JMP rel32
void Emulator::instr_JMP_rel32() {
    int32_t rel = fetch_dword();
    regs.EIP += rel;
}

// CMP регистр, imm8
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;

        // Zero Flag
        if (result == 0)
            regs.EFLAGS |= ZF;
        else
            regs.EFLAGS &= ~ZF;

        // Carry Flag
        if (*reg_ptr < imm8)
            regs.EFLAGS |= CF;
        else
            regs.EFLAGS &= ~CF;

        // Sign Flag (SF)
        if (result & (1 << 31))
            regs.EFLAGS |= (1 << 7); // Предполагаем, что SF находится в бит 7
        else
            regs.EFLAGS &= ~(1 << 7);

        // Overflow Flag (OF) - необходимо корректно реализовать
        // Здесь может быть упрощение, для точной реализации требуется дополнительная логика
    }
    else {
        std::cout << "CMP instruction with unsupported register.\n";
        // Можно установить флаг ошибки или завершить выполнение
    }
}

// JE rel8
void Emulator::instr_JE_rel8() {
    int8_t rel = fetch_byte();
    if (regs.EFLAGS & ZF) {
        regs.EIP += rel;
    }
}

// JNE rel8
void Emulator::instr_JNE_rel8() {
    int8_t rel = fetch_byte();
    if (!(regs.EFLAGS & ZF)) {
        regs.EIP += rel;
    }
}

// AND EAX, imm32
void Emulator::instr_AND_EAX_imm32() {
    uint32_t imm = fetch_dword();
    regs.EAX &= imm;
    update_ZF(regs.EAX);
}

// AND ECX, imm32
void Emulator::instr_AND_ECX_imm32() {
    uint32_t imm = fetch_dword();
    regs.ECX &= imm;
    update_ZF(regs.ECX);
}

// OR EAX, imm32
void Emulator::instr_OR_EAX_imm32() {
    uint32_t imm = fetch_dword();
    regs.EAX |= imm;
    update_ZF(regs.EAX);
}

// OR ECX, imm32
void Emulator::instr_OR_ECX_imm32() {
    uint32_t imm = fetch_dword();
    regs.ECX |= imm;
    update_ZF(regs.ECX);
}

// XOR EAX, imm32
void Emulator::instr_XOR_EAX_imm32() {
    uint32_t imm = fetch_dword();
    regs.EAX ^= imm;
    update_ZF(regs.EAX);
}

// SUB EBX, imm32
void Emulator::instr_SUB_EBX_imm32() {
    uint32_t imm = fetch_dword();
    regs.EBX -= imm;
    update_ZF(regs.EBX);
}

// CMP EAX, 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;
    else
        regs.EFLAGS &= ~ZF;
    // Дополнительно можно установить другие флаги (CF, OF и т.д.)
}

// Обработчик инструкции RET
void Emulator::instr_RET() {
    if (regs.ESP + 4 > memory.size()) {
        std::cout << "Stack underflow on RET.\n";
        error_flag = true;
        running = false;
        return;
    }

    // Pop the return address from the stack
    uint32_t return_address = read_memory_dword(regs.ESP);
    regs.ESP += 4;

    // Jump to the return address
    regs.EIP = return_address;
}

// Обработчик инструкции SUB r32, imm32
void Emulator::instr_SUB_r32_imm32() {
    uint8_t modrm = fetch_byte();
    uint8_t reg_opcode = (modrm >> 3) & 0x07; // Извлекаем поле reg из ModRM

    if (reg_opcode != 5) { // Для инструкции SUB reg, imm32, reg_opcode должен быть 5
        std::cout << "Unsupported SUB instruction with reg opcode: " << (int)reg_opcode << "\n";
        return;
    }

    uint32_t imm32 = fetch_dword(); // Извлекаем непосредственное значение
    uint8_t rm = regm_rm(modrm); // Извлекаем регистр назначения из ModRM
    uint32_t* reg_ptr = get_register_by_code(rm);

    if (reg_ptr) {
        *reg_ptr -= imm32;
        update_ZF(*reg_ptr);
    }
    else {
        std::cout << "SUB instruction with unsupported register.\n";
    }
}
void Emulator::instr_CMP_r32_rm32() {
    uint8_t modrm = fetch_byte();

    uint8_t mod = (modrm >> 6) & 0x03;
    uint8_t reg_code = (modrm >> 3) & 0x07; // Источник: r32
    uint8_t rm_code = modrm & 0x07;         // Назначение: r/m32

    uint32_t* reg = get_register_by_code(reg_code); // Источник
    uint32_t* rm;

    if (mod == 3) {
        rm = get_register_by_code(rm_code);

        if (!rm) {
            std::cout << "Неизвестный регистр в CMP r/m32, r32.\n";
            error_flag = true;
            running = false;
            return;
        }
    }
    else {
        // Для простоты реализуем только регистровый режим
        std::cout << "Поддерживается только регистровый режим для CMP r/m32, r32.\n";
        error_flag = true;
        running = false;
        return;
    }

    // Выполняем сравнение
    uint32_t result = *rm - *reg;

    // Обновляем флаги
    // Zero Flag (ZF)
    if (result == 0)
        regs.EFLAGS |= ZF;
    else
        regs.EFLAGS &= ~ZF;

    // Sign Flag (SF)
    if (result & 0x80000000)
        regs.EFLAGS |= SF;
    else
        regs.EFLAGS &= ~SF;

    // Carry Flag (CF)
    if (*rm < *reg)
        regs.EFLAGS |= CF;
    else
        regs.EFLAGS &= ~CF;

    // Overflow Flag (OF)
    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;
    else
        regs.EFLAGS &= ~OF;
}
void Emulator::instr_MOV_rm8_imm8() {
    uint8_t modrm = fetch_byte();
    uint8_t mod = (modrm & 0xC0) >> 6;
    // uint8_t reg = (modrm & 0x38) >> 3; // Не используется для MOV r/m8, imm8
    uint8_t rm = (modrm & 0x07);       // Назначение: r/m8

    uint8_t imm8 = fetch_byte();

    if (mod == 3) { // Регистр
        uint32_t* dest_reg = get_register_by_code(rm);
        if (dest_reg) {
            // Только младший байт регистра
            uint8_t* dest_reg_byte = reinterpret_cast<uint8_t*>(dest_reg);
            dest_reg_byte[0] = imm8;
        }
        else {
            std::cout << "Неизвестный регистр в MOV r/m8, imm8.\n";
            error_flag = true;
            running = false;
        }
    }
    else { // Память
        uint32_t address = calculate_address(modrm);
        if (error_flag) {
            return; // Ошибка уже установлена в calculate_address
        }

        if (address >= memory.size()) {
            std::cout << "Memory access out of bounds in MOV r/m8, imm8.\n";
            error_flag = true;
            running = false;
            return;
        }

        memory[address] = imm8;
    }
}

// Обработчик инструкции MUL r/m32
void Emulator::instr_MUL_rm32(uint8_t modrm) {
    uint8_t mod = (modrm & 0xC0) >> 6;
    // uint8_t reg = (modrm & 0x38) >> 3; // Не используется для MUL r/m32
    uint8_t rm = (modrm & 0x07);       // Источник: r/m32

    uint32_t operand = 0;

    if (mod == 3) { // Регистр
        uint32_t* src_reg = get_register_by_code(rm);
        if (src_reg) {
            operand = *src_reg;
        }
        else {
            std::cout << "Неизвестный регистр в MUL r/m32.\n";
            error_flag = true;
            running = false;
            return;
        }
    }
    else {
        uint32_t address = calculate_address(modrm);
        if (error_flag) return;
        operand = read_memory_dword(address);
    }

    // Выполнение умножения: EDX:EAX = EAX * operand
    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);

    update_ZF(regs.EAX);
}

// Реализация обработчика для DIV r/m32
void Emulator::instr_DIV_rm32(uint8_t modrm) {
    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 {
            std::cout << "Неизвестный регистр в DIV r/m32.\n";
            error_flag = true;
            running = false;
            return;
        }
    }
    else { // Операнд из памяти
        uint32_t address = calculate_address(modrm);
        if (error_flag) return;
        operand = read_memory_dword(address); // Чтение операнда из памяти
    }

    if (operand == 0) {
        std::cout << "Деление на ноль.\n";
        error_flag = true;
        running = false;
        return;
    }

    // Выполнение деления: EDX:EAX = EAX / operand
    uint64_t dividend = (static_cast<uint64_t>(regs.EDX) << 32) | regs.EAX;
    regs.EAX = static_cast<uint32_t>(dividend / operand);
    regs.EDX = static_cast<uint32_t>(dividend % operand);
    update_ZF(regs.EAX);
}

void Emulator::instr_IDIV_rm32(uint8_t modrm) {
    uint8_t mod = (modrm & 0xC0) >> 6;
    uint8_t rm = (modrm & 0x07);       // Источник: r/m32

    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 {
            std::cout << "Неизвестный регистр в IDIV r/m32.\n";
            error_flag = true;
            running = false;
            return;
        }
    }
    else { // Операнд из памяти
        uint32_t address = calculate_address(modrm);
        if (error_flag) return;
        operand = read_memory_dword(address); // Чтение операнда из памяти
    }

    if (operand == 0) {
        std::cout << "Деление на ноль.\n";
        error_flag = true;
        running = false;
        return;
    }

    // Выполнение деления: EDX:EAX = EAX / operand
    int64_t dividend = (static_cast<int64_t>(regs.EDX) << 32) | regs.EAX;
    regs.EAX = static_cast<uint32_t>(dividend / operand);
    regs.EDX = static_cast<uint32_t>(dividend % operand);

    update_ZF(regs.EAX);
}

// Общий обработчик для opcode 0xF7
void Emulator::instr_F7() {
    uint8_t modrm = fetch_byte();
    uint8_t reg = (modrm >> 3) & 0x07; // /digit

    switch (reg) {
    case 4: // MUL r/m32
        instr_MUL_rm32(modrm);
        break;
    case 6: // DIV r/m32
        instr_DIV_rm32(modrm);
        break;
    case 7: // IDIV r/m32
        instr_IDIV_rm32(modrm);
        break;
    default:
        std::cout << "F7 instruction with unsupported /digit: " << static_cast<int>(reg) << "\n";
        error_flag = true;
        running = false;
        break;
    }
}

void Emulator::instr_MOV_rm8_r8() {
    uint8_t modrm = fetch_byte();
    uint8_t mod = (modrm >> 6) & 0x03;
    uint8_t rm = modrm & 0x07;
    uint8_t reg = (modrm >> 3) & 0x07;

    uint8_t* src_reg = get_register8_by_code(reg);
    if (!src_reg) {
        std::cout << "Unknown source register in MOV r/m8, r8.\n";
        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) {
            std::cout << "Unknown destination register in MOV r/m8, r8.\n";
            error_flag = true;
            running = false;
            return;
        }
        *dest_reg = value;
    }

    else {
        // Режим регистр-память
        uint32_t address = 0;
        if (rm == 4) {
            // SIB байт
            uint8_t sib = fetch_byte();
            int32_t displacement = 0;
            if (mod == 1) {
                displacement = static_cast<int8_t>(fetch_byte());
            }
            else if (mod == 2) {
                displacement = static_cast<int32_t>(fetch_dword());
            }
            address = calculate_sib_address(mod, sib, displacement);
        }
        else {
            int32_t displacement = 0;
            if (mod == 1) {
                displacement = static_cast<int8_t>(fetch_byte());
            }
            else if (mod == 2) {
                displacement = static_cast<int32_t>(fetch_dword());
            }
            address = *get_register_by_code(rm) + displacement;
        }
        if (address >= memory.size()) {
            std::cout << "Memory access out of bounds in MOV r/m8, r8.\n";
            error_flag = true;
            running = false;
            return;
        }
        memory[address] = value;
    }
    
}

void Emulator::instr_ADD_AL_imm8() {
    uint8_t imm8 = fetch_byte();
    uint8_t* al = reinterpret_cast<uint8_t*>(&regs.EAX);
    *al += imm8;
    update_ZF(*al); // Обновляем флаг ZF на основе 8-битного результата
}

void Emulator::instr_MOV_ESI_imm32() {
    regs.ESI = fetch_dword();
}

// INT n (0xCD)
void Emulator::instr_INT() {
    uint8_t int_number = fetch_byte();
    if (int_number == 0x80) {
        // Обработка системного вызова Linux
        uint32_t syscall_number = regs.EAX;
        switch (syscall_number) {
        case 3: { // sys_read
            uint32_t fd = regs.EBX;
            uint32_t buf = regs.ECX;
            uint32_t count = regs.EDX;

            if (fd == 0) { // stdin
                std::string input;
                std::getline(std::cin, input);

                // Читаем не более count байтов
                input = input.substr(0, count);

                // Записываем введённые данные в память
                for (size_t i = 0; i < input.size(); ++i) {
                    memory[buf + i] = static_cast<uint8_t>(input[i]);
                }

                // Если введённых данных меньше, чем запрошено, заполняем оставшиеся нулями
                for (size_t i = input.size(); i < count; ++i) {
                    memory[buf + i] = 0;
                }

                // Возвращаем количество прочитанных байтов в EAX
                regs.EAX = input.size();
            }
            else {
                std::cout << "Unsupported file descriptor in sys_read: " << fd << "\n";
                regs.EAX = -1; // Возвращаем -1 в случае ошибки
            }
            break;
        }
        case 4: { // sys_write
            uint32_t fd = regs.EBX;
            uint32_t buf = regs.ECX;
            uint32_t count = regs.EDX;
            if (fd == 1) { // stdout
                std::string output;
                for (uint32_t i = 0; i < count; ++i) {
                    output += static_cast<char>(memory[buf + i]);
                }
                std::cout << output; // Вывод строки
            }
            break;
        }
        case 1: { // sys_exit
            running = false;
            break;
        }
        default:
            std::cout << "Неизвестный системный вызов: " << syscall_number << "\n";
            running = false;
            break;
        }
    }
    else {
        std::cout << "Неизвестное прерывание: INT " << (int)int_number << "\n";
        running = false;
    }
}

void Emulator::instr_MOV_MEM_EAX() {
    uint32_t address = fetch_dword();
    if (address + 4 > memory.size()) {
        throw std::runtime_error("Выход за пределы памяти при MOV [address], EAX");
    }
    memory[address] = regs.EAX & 0xFF;
    memory[address + 1] = (regs.EAX >> 8) & 0xFF;
    memory[address + 2] = (regs.EAX >> 16) & 0xFF;
    memory[address + 3] = (regs.EAX >> 24) & 0xFF;
}

void Emulator::instr_MOV_EAX_MEM() {
    uint32_t address = fetch_dword();
    if (address + 4 > memory.size()) {
        throw std::runtime_error("Выход за пределы памяти при MOV EAX, [address]");
    }
    regs.EAX = memory[address] |
        (memory[address + 1] << 8) |
        (memory[address + 2] << 16) |
        (memory[address + 3] << 24);
}
// CMP EAX, EBX
void Emulator::instr_CMP_EAX_EBX() {
    uint8_t modrm = fetch_byte(); // Получаем ModRM байт
    uint8_t reg = (modrm >> 3) & 0x07; // Извлекаем регистры
    uint8_t rm = modrm & 0x07;

    // Проверяем, что регистры соответствуют EAX и EBX
    if (reg == 0 && rm == 3) { // 0 для EAX и 3 для EBX
        uint32_t result = regs.EAX - regs.EBX;

        // Zero Flag (ZF)
        if (result == 0)
            regs.EFLAGS |= ZF;
        else
            regs.EFLAGS &= ~ZF;

        // Sign Flag (SF)
        if (result & (1 << 31))
            regs.EFLAGS |= SF;
        else
            regs.EFLAGS &= ~SF;

        // Остальная обработка флагов
    }
    else {
        std::cout << "CMP instruction with unsupported register combination.\n";
        error_flag = true;
        running = false;
    }
}

void Emulator::instr_JG_rel8() {
    int8_t rel = fetch_byte();

    bool zf = (regs.EFLAGS & ZF) != 0;
    bool sf = (regs.EFLAGS & SF) != 0;
    bool of = (regs.EFLAGS & OF) != 0;

    // JG переходит, если ZF = 0 и SF = OF
    if (!zf && (sf == of)) {
        regs.EIP += rel;
    }
}
// Реализация инструкции IMUL reg, r/m32, imm32
void Emulator::instr_IMUL_reg_rm32_imm32() {
    // Before reading ModRM byte, EIP points to it
    std::cout << "EIP before fetch_byte (ModRM): 0x" << std::hex << regs.EIP << "\n";

    uint8_t modrm = fetch_byte(); // Read ModRM byte
    uint8_t mod = modrm >> 6;
    uint8_t reg_code = (modrm >> 3) & 0x07; // Destination register
    uint8_t rm_code = modrm & 0x07;         // Source operand

    // Debug output
    std::cout << "Executing IMUL with modrm: 0x" << std::hex << (int)modrm << "\n";
    std::cout << "Destination reg code: " << (int)reg_code << ", Source rm code: " << (int)rm_code << "\n";
    std::cout << "EIP after fetch_byte (ModRM): 0x" << std::hex << regs.EIP << "\n";

    uint32_t* dest_reg = get_register_by_code(reg_code);
    uint32_t* src_reg = nullptr;

    if (mod == 3) { // Register-register mode
        src_reg = get_register_by_code(rm_code);
        if (!src_reg) {
            std::cout << "Unknown source register in IMUL.\n";
            error_flag = true;
            running = false;
            return;
        }
    }
    else {
        std::cout << "Unsupported addressing mode in IMUL.\n";
        error_flag = true;
        running = false;
        return;
    }

    // Check if dest_reg is valid
    if (!dest_reg) {
        std::cout << "Unknown destination register in IMUL.\n";
        error_flag = true;
        running = false;
        return;
    }

    // Before reading imm32, EIP points to it
    std::cout << "EIP before fetch_dword (imm32): 0x" << std::hex << regs.EIP << "\n";

    uint32_t imm32 = fetch_dword(); // Read immediate value imm32

    // After reading imm32, EIP should have been incremented by 4
    std::cout << "EIP after fetch_dword (imm32): 0x" << std::hex << regs.EIP << "\n";
    // Debug output of imm32
    std::cout << "Immediate value: " << std::dec << imm32 << "\n";

    // Perform signed multiplication
    int32_t result = static_cast<int32_t>(*src_reg) * static_cast<int32_t>(imm32);
    *dest_reg = static_cast<uint32_t>(result);

    // Update flags appropriately
    update_ZF(*dest_reg);
    // Update other flags (CF, OF) if necessary
}

void Emulator::instr_SUB_AL_imm8() {
    uint8_t imm8 = fetch_byte();
    uint8_t* al = reinterpret_cast<uint8_t*>(&regs.EAX);
    *al -= imm8;
    update_ZF(*al);
}
void Emulator::instr_JMP_rel8() {
    int8_t rel = fetch_byte();
    regs.EIP += rel;
}
void Emulator::instr_JB_rel8() {
    int8_t rel = fetch_byte();
    if (regs.EFLAGS & CF) {
        regs.EIP += rel;
    }
}

void Emulator::instr_JA_rel8() {
    int8_t rel = fetch_byte();
    bool cf = (regs.EFLAGS & CF) != 0;
    bool zf = (regs.EFLAGS & ZF) != 0;
    if (!cf && !zf) {
        regs.EIP += rel;
    }
}
void Emulator::instr_INC_ECX() {
    regs.ECX += 1;
    update_ZF(regs.ECX);
}
void Emulator::instr_MOV_r8_imm8() {
    uint8_t opcode = memory[regs.EIP - 1]; // Последний прочитанный опкод
    uint8_t reg_code = opcode - 0xB0; // Регистры AL, CL, DL, BL, AH, CH, DH, BH идут от 0xB0 до 0xB7

    uint8_t imm8 = fetch_byte();
    uint8_t* reg = get_register8_by_code(reg_code);

    if (!reg) {
        std::cout << "Unknown register in MOV r8, imm8.\n";
        error_flag = true;
        running = false;
        return;
    }

    *reg = imm8;
}
void Emulator::instr_SUB_rm8_imm8() {
    uint8_t modrm = fetch_byte();
    uint8_t opcode = (modrm >> 3) & 0x07;
    uint8_t rm_code = modrm & 0x07;

    if (opcode != 5) {
        std::cout << "Unsupported opcode in SUB rm8, imm8.\n";
        error_flag = true;
        running = false;
        return;
    }

    uint8_t imm8 = fetch_byte();
    uint8_t* dest = get_register8_by_code(rm_code);

    if (!dest) {
        std::cout << "Unknown register in SUB rm8, imm8.\n";
        error_flag = true;
        running = false;
        return;
    }

    *dest -= imm8;

    update_ZF(*dest);
}
void Emulator::instr_MOV_r8_rm8() {
    uint8_t modrm = fetch_byte();
    uint8_t mod = modrm >> 6;
    uint8_t reg_code = (modrm >> 3) & 0x07; // Назначение: r8
    uint8_t rm = modrm & 0x07;              // Источник: r/m8

    uint8_t* reg = get_register8_by_code(reg_code);
    if (!reg) {
        std::cout << "Unknown register in MOV r8, rm8.\n";
        error_flag = true;
        running = false;
        return;
    }

    uint32_t address = 0;

    if (mod == 0) {
        if (rm == 4) {
            // Обработка SIB байта
            uint8_t sib = fetch_byte();
            address = calculate_sib_address(mod, sib, 0);
        }
        else if (rm == 5) {
            // [disp32]
            address = fetch_dword();
        }
        else {
            // [reg]
            uint32_t* rm_reg = get_register_by_code(rm);
            if (rm_reg) {
                address = *rm_reg;
            }
            else {
                std::cout << "Unknown base register in MOV r8, rm8.\n";
                error_flag = true;
                running = false;
                return;
            }
        }
    }
    else if (mod == 1) {
        int8_t disp8 = static_cast<int8_t>(fetch_byte());
        if (rm == 4) {
            // Обработка SIB байта
            uint8_t sib = fetch_byte();
            address = calculate_sib_address(mod, sib, disp8);
        }
        else {
            // [reg + disp8]
            uint32_t* rm_reg = get_register_by_code(rm);
            if (rm_reg) {
                address = *rm_reg + disp8;
            }
            else {
                std::cout << "Unknown base register in MOV r8, rm8.\n";
                error_flag = true;
                running = false;
                return;
            }
        }
    }
    else if (mod == 2) {
        int32_t disp32 = static_cast<int32_t>(fetch_dword());
        if (rm == 4) {
            // Обработка SIB байта
            uint8_t sib = fetch_byte();
            address = calculate_sib_address(mod, sib, disp32);
        }
        else {
            // [reg + disp32]
            uint32_t* rm_reg = get_register_by_code(rm);
            if (rm_reg) {
                address = *rm_reg + disp32;
            }
            else {
                std::cout << "Unknown base register in MOV r8, rm8.\n";
                error_flag = true;
                running = false;
                return;
            }
        }
    }
    else if (mod == 3) {
        // MOV r8, r8
        uint8_t* rm_reg = get_register8_by_code(rm);
        if (rm_reg) {
            *reg = *rm_reg;
        }
        else {
            std::cout << "Unknown register in MOV r8, rm8.\n";
            error_flag = true;
            running = false;
        }
        return;
    }
    else {
        std::cout << "Unsupported mod in MOV r8, rm8.\n";
        error_flag = true;
        running = false;
        return;
    }

    if (address >= memory.size()) {
        std::cout << "Memory access out of bounds in MOV r8, [address].\n";
        error_flag = true;
        running = false;
        return;
    }

    *reg = memory[address];
}
// MOV EBP, imm32
void Emulator::instr_MOV_EBP_imm32() {
    uint32_t imm = fetch_dword();
    regs.EBP = imm;
}
// MOV ESP, imm32
void Emulator::instr_MOV_ESP_imm32() {
    uint32_t imm = fetch_dword();
    regs.ESP = imm;
}

// MOV EDI, imm32
void Emulator::instr_MOV_EDI_imm32() {
    uint32_t imm = fetch_dword();
    regs.EDI = imm;
}
void Emulator::instr_MOV_r32_r_m32() {
    uint8_t modrm = fetch_byte();
    uint8_t mod = (modrm >> 6) & 0x03;
    uint8_t reg_code = (modrm >> 3) & 0x07; // Регистр назначения (r32)
    uint8_t rm = modrm & 0x07;              // Источник (r/m32)

    uint32_t* dest_reg = get_register_by_code(reg_code);

    if (mod == 3) { // Режим регистр-регистр
        uint32_t* src_reg = get_register_by_code(rm);
        if (dest_reg && src_reg) {
            *dest_reg = *src_reg;
        }
        else {
            std::cout << "Неизвестный регистр в MOV r32, r/m32.\n";
            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 {
            std::cout << "Неизвестный регистр назначения в MOV r32, r/m32.\n";
            error_flag = true;
            running = false;
        }
    }
}
void Emulator::instr_ADD_r32_rm32() {
    uint8_t modrm = fetch_byte();
    uint8_t mod = (modrm >> 6) & 0x03;
    uint8_t reg_code = (modrm >> 3) & 0x07; // Destination register (r32)
    uint8_t rm_code = modrm & 0x07;         // Source (r/m32)

    uint32_t* dest_reg = get_register_by_code(reg_code);

    if (mod == 3) { // Register-register mode
        uint32_t* src_reg = get_register_by_code(rm_code);
        if (dest_reg && src_reg) {
            *dest_reg += *src_reg;
            update_ZF(*dest_reg);
            // Update other flags as needed
        }
        else {
            std::cout << "Unknown register in ADD r32, r/m32.\n";
            error_flag = true;
            running = false;
        }
    }
    else {
        // Handle memory operands if needed
    }
}
void Emulator::instr_ADD_rm32_r32() {
    uint8_t modrm = fetch_byte();
    uint8_t mod = (modrm >> 6) & 0x03;
    uint8_t reg_code = (modrm >> 3) & 0x07; // Источник: r32
    uint8_t rm_code = modrm & 0x07;         // Назначение: r/m32

    uint32_t* src_reg = get_register_by_code(reg_code);

    if (mod == 3) { // Режим регистр-регистр
        uint32_t* dest_reg = get_register_by_code(rm_code);
        if (src_reg && dest_reg) {
            *dest_reg += *src_reg;
            update_ZF(*dest_reg);
            // Обновите другие флаги, если необходимо (Carry, Overflow и т.д.)
        }
        else {
            std::cout << "Неизвестный регистр в ADD r/m32, r32.\n";
            error_flag = true;
            running = false;
        }
    }
    else { // Операнд r/m32 является памятью
        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(value);
        // Обновите другие флаги, если необходимо
    }
}
void Emulator::instr_CMP_AL_imm8() {
    uint8_t imm8 = fetch_byte();
    uint8_t al = regs.EAX & 0xFF;
    uint8_t result = al - imm8;

    // Update Zero Flag (ZF)
    if (result == 0)
        regs.EFLAGS |= ZF;
    else
        regs.EFLAGS &= ~ZF;

    // Update Sign Flag (SF)
    if (result & 0x80)
        regs.EFLAGS |= SF;
    else
        regs.EFLAGS &= ~SF;

    // Update Carry Flag (CF)
    if (al < imm8)
        regs.EFLAGS |= CF;
    else
        regs.EFLAGS &= ~CF;

    // Update Overflow Flag (OF)
    bool overflow = ((al ^ imm8) & (al ^ result) & 0x80) != 0;
    if (overflow)
        regs.EFLAGS |= OF;
    else
        regs.EFLAGS &= ~OF;
}
void Emulator::instr_JL_rel8() {
    int8_t rel = fetch_byte();

    bool sf = (regs.EFLAGS & SF) != 0;
    bool of = (regs.EFLAGS & OF) != 0;

    // JL переходит, если SF != OF
    if (sf != of) {
        regs.EIP += rel;
    }
}

void Emulator::instr_XOR_r32_rm32() {
    uint8_t modrm = fetch_byte();
    uint8_t mod = (modrm >> 6) & 0x03;
    uint8_t reg = (modrm >> 3) & 0x07; // Source register (r32)
    uint8_t rm = modrm & 0x07;         // Destination (r/m32)

    if (mod == 3) { // Register-register mode
        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(*dest_reg);
        }
        else {
            std::cout << "Unknown register in XOR r/m32, r32.\n";
            error_flag = true;
            running = false;
        }
    }
    // ...
}
void Emulator::instr_CALL_rel32() {
    // Fetch the relative 32-bit offset
    int32_t rel32 = fetch_dword();

    // Calculate the return address (current EIP)
    uint32_t return_address = regs.EIP;

    // Push the return address onto the stack
    regs.ESP -= 4;
    write_memory_dword(regs.ESP, return_address);

    // Update EIP to jump to the target address
    regs.EIP += rel32;
}
void Emulator::instr_MOV_r32_rm32() {
    uint8_t modrm = fetch_byte();
    uint8_t mod = (modrm >> 6) & 0x03;
    uint8_t reg = (modrm >> 3) & 0x07; // Source register (r32)
    uint8_t rm = modrm & 0x07;         // Destination (r/m32)

    if (mod == 3) { // Register-register mode
        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 {
            std::cout << "Unknown register in MOV r/m32, r32.\n";
            error_flag = true;
            running = false;
        }
    }
    // ...
}
// Emulator.cpp
#include "Emulator.h"
#include <iostream>
#include <algorithm>

// Конструктор
Emulator::Emulator(size_t memory_size) {
    memory.resize(memory_size, 0);
    initialize_instruction_set();
    regs.ESP = static_cast<uint32_t>(memory_size);
}
// Реализация метода write_memory
void Emulator::write_memory(uint32_t address, const uint8_t* data, size_t size) {
    if (address + size > memory.size()) {
        std::cerr << "Ошибка: Пытаетесь записать за пределы памяти. Адрес: 0x"
            << std::hex << address << ", Размер: " << std::dec << size << "\n";
        error_flag = true;
        running = false;
        return;
    }
    std::memcpy(&memory[address], data, size);
}
// Реализация метода set_eip
void Emulator::set_eip(uint32_t address) {
    if (address >= memory.size()) {
        std::cerr << "Ошибка: Установка EIP за пределами памяти. Адрес: 0x"
            << std::hex << address << "\n";
        error_flag = true;
        running = false;
        return;
    }
    regs.EIP = address;
}
uint8_t Emulator::read_memory_byte(uint32_t address) const {
    if (address >= memory.size()) {
        throw std::runtime_error("Чтение памяти вне границ");
    }
    return memory[address];
}

uint32_t Emulator::read_memory_dword(uint32_t address) const {
    if (address + 4 > memory.size()) {
        throw std::runtime_error("Чтение памяти вне границ");
    }
    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;
    return value;
}

// Метод load_program
void Emulator::load_program(const std::vector<uint8_t>& program, size_t load_address, bool set_eip) {
    if (load_address + program.size() > memory.size()) {
        throw std::runtime_error("Размер программы превышает лимиты памяти");
    }
    std::copy(program.begin(), program.end(), memory.begin() + load_address);
    if (set_eip) {
        regs.EIP = load_address;
    }
}

// Метод run
void Emulator::run() {
    running = true;
    while (running) {
        try {
            uint8_t opcode = fetch_byte();
            //std::cout << "Opcode: 0x" << std::hex << (int)opcode << " at EIP: 0x" << std::hex << regs.EIP - 1 << "\n";

            // Проверка на префиксы
            const std::vector<uint8_t> prefixes = { /* префиксы */ };
            while (std::find(prefixes.begin(), prefixes.end(), opcode) != prefixes.end()) {
                std::cout << "Пропуск префикса: 0x" << std::hex << (int)opcode << "\n";
                opcode = fetch_byte();
            }

            auto it = instruction_set.find(opcode);
            if (it != instruction_set.end()) {
                InstructionHandler handler = it->second;
                (this->*handler)();
            }
            else {
                std::cout << "Неизвестный opcode: 0x" << std::hex << (int)opcode << "\n";
                error_flag = true; // Установка флага ошибки
                running = false;
            }

            // After instruction execution, log registers and EIP
            //print_registers(true); // Use the existing method to print registers
            //std::cout << "EIP after execution: 0x" << std::hex << regs.EIP << "\n";

        }
        catch (const std::exception& e) {
            std::cerr << "Exception caught: " << e.what() << "\n";
            error_flag = true;
            running = false;
        }
        catch (...) {
            std::cerr << "Unknown exception caught.\n";
            error_flag = true;
            running = false;
        }
    }
}

// Метод print_registers
void Emulator::print_registers(bool hex_output) const {
    if (hex_output) {
        std::cout << std::hex;
        std::cout << "EAX: 0x" << regs.EAX << "\n";
        std::cout << "EBX: 0x" << regs.EBX << "\n";
        std::cout << "ECX: 0x" << regs.ECX << "\n";
        std::cout << "EDX: 0x" << regs.EDX << "\n";
        std::cout << "ESI: 0x" << regs.ESI << "\n";
        std::cout << "EDI: 0x" << regs.EDI << "\n";
        std::cout << "ESP: 0x" << regs.ESP << "\n";
        std::cout << "EBP: 0x" << regs.EBP << "\n";
        std::cout << "EIP: 0x" << regs.EIP << "\n";
        std::cout << "EFLAGS: 0x" << regs.EFLAGS << "\n";
        std::cout << std::dec; // Возвращаемся к десятичной системе счисления
    }
    else {
        std::cout << "EAX: " << regs.EAX << "\n";
        std::cout << "EBX: " << regs.EBX << "\n";
        std::cout << "ECX: " << regs.ECX << "\n";
        std::cout << "EDX: " << regs.EDX << "\n";
        std::cout << "ESI: " << regs.ESI << "\n";
        std::cout << "EDI: " << regs.EDI << "\n";
        std::cout << "ESP: " << regs.ESP << "\n";
        std::cout << "EBP: " << regs.EBP << "\n";
        std::cout << "EIP: " << regs.EIP << "\n";
        std::cout << "EFLAGS: " << regs.EFLAGS << "\n";
    }
}

uint32_t Emulator::calculate_sib_address(uint8_t mod, uint8_t sib, int32_t displacement) {
    uint8_t scale = (sib >> 6) & 0x03;
    uint8_t index = (sib >> 3) & 0x07;
    uint8_t base = sib & 0x07;

    uint32_t base_value = 0;
    uint32_t index_value = 0;

    // Получаем значение base
    if (base == 5) {
        if (mod == 0) {
            // base = 0, disp32 используется вместо base
            base_value = 0;
            displacement += fetch_dword(); // Дополнительный disp32
        }
        else {
            base_value = *get_register_by_code(base);
        }
    }
    else {
        base_value = *get_register_by_code(base);
    }

    // Получаем значение index
    if (index != 4) { // Если index не равно 4 (4 означает, что index не используется)
        index_value = *get_register_by_code(index) << scale;
    }

    uint32_t address = base_value + index_value + displacement;
    return address;
}

uint32_t Emulator::calculate_address(uint8_t modrm) {
    uint8_t mod = (modrm >> 6) & 0x03;
    uint8_t rm = modrm & 0x07;
    uint32_t address = 0;

    if (mod == 0) {
        if (rm == 5) {
            // [disp32]
            uint32_t disp32 = fetch_dword();
            address = disp32;
        }
        else if (rm == 4) {
            // SIB байт без смещения
            uint8_t sib = fetch_byte();
            address = calculate_sib_address(mod, sib, 0);
        }
        else {
            // [reg]
            address = *get_register_by_code(rm);
        }
    }
    else if (mod == 1) {
        int8_t disp8 = static_cast<int8_t>(fetch_byte());
        if (rm == 4) {
            // SIB байт с disp8
            uint8_t sib = fetch_byte();
            address = calculate_sib_address(mod, sib, disp8);
        }
        else {
            // [reg + disp8]
            address = *get_register_by_code(rm) + disp8;
        }
    }
    else if (mod == 2) {
        int32_t disp32 = static_cast<int32_t>(fetch_dword());
        if (rm == 4) {
            // SIB байт с disp32
            uint8_t sib = fetch_byte();
            address = calculate_sib_address(mod, sib, disp32);
        }
        else {
            // [reg + disp32]
            address = *get_register_by_code(rm) + disp32;
        }
    }
    else {
        std::cout << "Unsupported ModR/M mod value in calculate_address.\n";
        error_flag = true;
        running = false;
        return 0;
    }

    if (address >= memory.size()) {
        std::cout << "Address out of bounds: 0x" << std::hex << address << "\n";
        error_flag = true;
        running = false;
    }

    return address;
}

// Инициализация таблицы инструкций
void Emulator::initialize_instruction_set() {
    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[0x05] = &Emulator::instr_ADD_EAX_imm32;
    instruction_set[0x2D] = &Emulator::instr_SUB_EAX_imm32;
    instruction_set[0x40] = &Emulator::instr_INC_EAX;
    instruction_set[0x48] = &Emulator::instr_DEC_EAX;
    instruction_set[0xF7] = &Emulator::instr_F7;
    instruction_set[0xE9] = &Emulator::instr_JMP_rel32;
    instruction_set[0x83] = &Emulator::instr_CMP_reg_imm8;
    instruction_set[0x74] = &Emulator::instr_JE_rel8;
    instruction_set[0x75] = &Emulator::instr_JNE_rel8;
    instruction_set[0x25] = &Emulator::instr_AND_EAX_imm32;
    instruction_set[0x21] = &Emulator::instr_AND_ECX_imm32;
    instruction_set[0x0D] = &Emulator::instr_OR_EAX_imm32;
    instruction_set[0x35] = &Emulator::instr_XOR_EAX_imm32;
    instruction_set[0x81] = &Emulator::instr_SUB_r32_imm32; // Обработчик SUB r32, imm32
    instruction_set[0x3D] = &Emulator::instr_CMP_EAX_imm32;
    instruction_set[0x0E] = &Emulator::instr_OR_ECX_imm32;
    instruction_set[0xC3] = &Emulator::instr_RET; // Обработчик RET
    instruction_set[0xA3] = &Emulator::instr_MOV_MEM_EAX; // MOV [address], EAX
    instruction_set[0xA1] = &Emulator::instr_MOV_EAX_MEM; // MOV EAX, [address]
    instruction_set[0xCD] = &Emulator::instr_INT; // INT n
    instruction_set[0x89] = &Emulator::instr_MOV_r32_rm32;
    instruction_set[0x31] = &Emulator::instr_XOR_r32_rm32;
    instruction_set[0x04] = &Emulator::instr_ADD_AL_imm8;
    instruction_set[0x88] = &Emulator::instr_MOV_rm8_r8;
    instruction_set[0xC6] = &Emulator::instr_MOV_rm8_imm8;
    instruction_set[0x39] = &Emulator::instr_CMP_r32_rm32; // CMP r/m32, r32
    instruction_set[0x7F] = &Emulator::instr_JG_rel8;     // JG rel8
    instruction_set[0x7C] = &Emulator::instr_JL_rel8;     // JL rel8
    instruction_set[0x8A] = &Emulator::instr_MOV_r8_rm8;
    instruction_set[0x80] = &Emulator::instr_SUB_rm8_imm8;
    instruction_set[0xB7] = &Emulator::instr_MOV_r8_imm8;
    instruction_set[0x69] = &Emulator::instr_IMUL_reg_rm32_imm32;
    instruction_set[0x72] = &Emulator::instr_JB_rel8;
    instruction_set[0x77] = &Emulator::instr_JA_rel8;
    instruction_set[0x41] = &Emulator::instr_INC_ECX;
    instruction_set[0xEB] = &Emulator::instr_JMP_rel8;
    instruction_set[0x2C] = &Emulator::instr_SUB_AL_imm8;
    instruction_set[0x3C] = &Emulator::instr_CMP_AL_imm8;
    instruction_set[0x01] = &Emulator::instr_ADD_rm32_r32;
    instruction_set[0x03] = &Emulator::instr_ADD_r32_rm32; // ADD r32, r/m32
    instruction_set[0x6B] = &Emulator::instr_IMUL_reg_rm32_imm8;
    instruction_set[0x8B] = &Emulator::instr_MOV_r32_r_m32; // Добавляем обработчик для MOV r32, r/m32
    instruction_set[0xBB] = &Emulator::instr_MOV_EBX_imm32;
    instruction_set[0xBD] = &Emulator::instr_MOV_EBP_imm32; // MOV EBP, imm32
    instruction_set[0xBC] = &Emulator::instr_MOV_ESP_imm32; // MOV ESP, imm32
    instruction_set[0xBE] = &Emulator::instr_MOV_ESI_imm32;
    instruction_set[0xBF] = &Emulator::instr_MOV_EDI_imm32; // MOV EDI, imm32
    instruction_set[0xE8] = &Emulator::instr_CALL_rel32; // MOV rel32, CALL rel32
}
void Emulator::instr_IMUL_reg_rm32_imm8() {
    // Fetch ModRM byte
    uint8_t modrm = fetch_byte();
    uint8_t mod = modrm >> 6;
    uint8_t reg_code = (modrm >> 3) & 0x07; // Destination register
    uint8_t rm_code = modrm & 0x07;         // Source operand

    uint32_t* dest_reg = get_register_by_code(reg_code);
    uint32_t operand = 0;

    // Determine the operand based on addressing mode
    if (mod == 3) { // Register-direct mode
        uint32_t* src_reg = get_register_by_code(rm_code);
        if (!src_reg) {
            std::cout << "Unknown source register in IMUL.\n";
            error_flag = true;
            running = false;
            return;
        }
        operand = *src_reg;
    }
    else {
        // For simplicity, handle only register-direct mode
        std::cout << "Unsupported addressing mode in IMUL.\n";
        error_flag = true;
        running = false;
        return;
    }

    // Fetch immediate 8-bit value
    int8_t imm8 = static_cast<int8_t>(fetch_byte());

    // Perform multiplication
    int32_t result = static_cast<int32_t>(operand) * imm8;
    *dest_reg = static_cast<uint32_t>(result);

    // Update flags as necessary
    update_ZF(*dest_reg);
    // Update other flags (CF, OF) if necessary
}
void Emulator::write_memory_dword(uint32_t address, uint32_t value) {
    if (address + 4 > memory.size()) {
        std::cerr << "Ошибка: Память для записи dword выходит за пределы. Адрес: 0x"
            << std::hex << address << "\n";
        error_flag = true;
        running = false;
        return;
    }
    memory[address] = value & 0xFF;
    memory[address + 1] = (value >> 8) & 0xFF;
    memory[address + 2] = (value >> 16) & 0xFF;
    memory[address + 3] = (value >> 24) & 0xFF;
}

// Обновление Zero Flag (ZF)
void Emulator::update_ZF(uint32_t result) {
    if (result == 0)
        regs.EFLAGS |= ZF;
    else
        regs.EFLAGS &= ~ZF;
}

// Вспомогательные методы

uint8_t Emulator::fetch_byte() {
    if (regs.EIP >= memory.size()) {
        throw std::runtime_error("EIP вне границ памяти");
    }
    return memory[regs.EIP++];
}

// Реализация fetch_dword с проверкой увеличения EIP
uint32_t Emulator::fetch_dword() {
    if (regs.EIP + 4 > memory.size()) {
        throw std::runtime_error("EIP вне границ памяти для загрузки dword");
    }
    uint32_t value = 0;
    // x86 uses little endian
    value = static_cast<uint32_t>(memory[regs.EIP]) |
        (static_cast<uint32_t>(memory[regs.EIP + 1]) << 8) |
        (static_cast<uint32_t>(memory[regs.EIP + 2]) << 16) |
        (static_cast<uint32_t>(memory[regs.EIP + 3]) << 24);

    regs.EIP += 4;

    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);          // AL
    case 1: return reinterpret_cast<uint8_t*>(&regs.ECX);          // CL
    case 2: return reinterpret_cast<uint8_t*>(&regs.EDX);          // DL
    case 3: return reinterpret_cast<uint8_t*>(&regs.EBX);          // BL
    case 4: return reinterpret_cast<uint8_t*>(&regs.EAX) + 1;      // AH
    case 5: return reinterpret_cast<uint8_t*>(&regs.ECX) + 1;      // CH
    case 6: return reinterpret_cast<uint8_t*>(&regs.EDX) + 1;      // DH
    case 7: return reinterpret_cast<uint8_t*>(&regs.EBX) + 1;      // BH
    default: return nullptr;
    }
}

uint8_t Emulator::regm_rm(uint8_t modrm) {
    return modrm & 0x07; // Извлекаем регистровый код (rm)
}
// main.cpp
#include "Emulator.h"
#include "file_utils.h"
#include "elf_loader.h"
#include <iostream>
#include <vector>
#include <cstdint>
#include <string>

bool run_program_from_file(const std::string& filename) {
    Emulator emulator(1024 * 1024); // 1 MB памяти

    // Загрузка программы из бинарного файла
    std::vector<uint8_t> program = load_program_from_file(filename);
    if (program.empty()) {
        std::cerr << "Ошибка: Не удалось загрузить программу из файла: " << filename << "\n";
        return false;
    }

    // Загрузка программы в память по адресу 0x0000 и установка EIP
    emulator.load_program(program, 0x0000, true);

    // Запуск эмулятора
    emulator.run();

    // Проверка на ошибки
    return !emulator.has_error();
}

bool run_program_from_elf(const std::string& filename) {
    Emulator emulator(256 * 1024 * 1024); // 256 MB памяти

    // Загрузка ELF-файла
    bool load_result = load_elf(filename, emulator);
    if (!load_result) {
        std::cerr << "Ошибка: Не удалось загрузить ELF-файл.\n";
        return false;
    }

    // Запуск эмулятора
    emulator.run();

    // Проверка на ошибки
    return !emulator.has_error();
}

int main(int argc, char* argv[]) {
    // Проверка наличия аргумента командной строки
    if (argc > 1) {
        std::string program_filename = argv[1];
        std::cout << "\nЗапуск программы из файла: " << program_filename << "...\n";

        // Определение типа файла по расширению
        if (program_filename.size() >= 4 &&
            program_filename.substr(program_filename.size() - 4) == ".elf") {
            // Запуск как ELF-файл
            bool elf_result = run_program_from_elf(program_filename);

            if (elf_result) {
                std::cout << "\nПрограмма из ELF-файла успешно выполнена!\n";
            }
            else {
                std::cout << "\nПрограмма из ELF-файла не выполнена.\n";
            }
        }
        else {
            // Запуск как flat binary
            bool file_result = run_program_from_file(program_filename);

            if (file_result) {
                std::cout << "\nПрограмма из файла успешно выполнена!\n";
            }
            else {
                std::cout << "\nПрограмма из файла не выполнена.\n";
            }
        }
    }
    else {
        // Если файл не указан, можно запустить тесты или вывести инструкции
        std::cout << "Использование: " << argv[0] << " <имя_файла.(elf|bin)>\n";
    }

    return 0;
}
; calculator.asm
; Простая калькуляторная программа для ELF32
; Выполняет арифметические операции и выводит результат через системные вызовы Linux

BITS 32
SECTION .text
    global _start

_start:
    ; mov eax, 5          ; Загрузка 5 в EAX
    mov eax, 5

    ; add eax, 7          ; Добавление 7 к EAX (EAX = 12)
    add eax, 7

    ; mov ebx, eax        ; Копирование EAX в EBX
    mov ebx, eax

    ; mov ecx, sum_str    ; Установка ECX на адрес "sum_str"
    mov ecx, sum_str

    ; xor edx, edx        ; Очистка EDX перед делением
    xor edx, edx

    ; mov esi, 10         ; Загрузка 10 в ESI
    mov esi, 10

    ; div esi             ; Деление EAX на ESI, результат в EAX, остаток в EDX
    div esi

    ; add al, '0'         ; Преобразование десятков в ASCII ('1')
    add al, '0'

    ; mov [ecx], al       ; Сохранение десятков в sum_str[0]
    mov [ecx], al

    ; mov eax, edx        ; Перемещение остатка в EAX (EAX = 2)
    mov eax, edx

    ; add al, '0'         ; Преобразование единиц в ASCII ('2')
    add al, '0'

    ; mov [ecx+1], al     ; Сохранение единиц в sum_str[1]
    mov [ecx+1], al

    ; mov byte [ecx+2], 0x0A ; Добавление символа новой строки в sum_str[2]
    mov byte [ecx+2], 0x0A

    ; mov eax, 4          ; Номер системного вызова sys_write
    mov eax, 4

    ; mov ebx, 1          ; Дескриптор файла 1 (stdout)
    mov ebx, 1

    ; mov ecx, result_prefix ; Адрес строки "Result: "
    mov ecx, result_prefix

    ; mov edx, 8          ; Длина строки "Result: "
    mov edx, 8

    ; int 0x80            ; Вызов системного прерывания для вывода "Result: "
    int 0x80

    ; mov eax, 4          ; Номер системного вызова sys_write
    mov eax, 4

    ; mov ebx, 1          ; Дескриптор файла 1 (stdout)
    mov ebx, 1

    ; mov ecx, sum_str    ; Адрес строки "sum_str" (результат)
    mov ecx, sum_str

    ; mov edx, 3          ; Длина строки "sum_str" (2 цифры + новая строка)
    mov edx, 3

    ; int 0x80            ; Вызов системного прерывания для вывода суммы
    int 0x80

    ; mov eax, 1          ; Номер системного вызова sys_exit
    mov eax, 1

    ; mov ebx, 0          ; Код выхода 0
    mov ebx, 0

    ; int 0x80            ; Вызов системного прерывания для выхода
    int 0x80

SECTION .data
    ; Строка "Result: " (8 байт) начинается на метке result_prefix
    result_prefix db 'Result: '

    ; Строка для суммы "sum_str" (3 байта) инициализирована нулями
    sum_str       db 0x00, 0x00, 0x00