// 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);
    // Инициализируем сегментные регистры (по умолчанию можно установить базу 0)
    regs.CS = 0;
    regs.DS = 0;
    regs.SS = memory_size; // Стек начинается в конце памяти
    regs.ES = 0;
    regs.FS = 0;
    regs.GS = 0;

    // Устанавливаем текущие сегменты на сегменты по умолчанию
    current_data_segment = &regs.DS;
    current_code_segment = &regs.CS;
}
void Emulator::set_segment_override(uint8_t prefix) {
    switch (prefix) {
    case 0x2E: // CS
        current_code_segment = &regs.CS;
        break;
    case 0x36: // SS
        current_data_segment = &regs.SS;
        break;
    case 0x3E: // DS
        current_data_segment = &regs.DS;
        break;
    case 0x26: // ES
        current_data_segment = &regs.ES;
        break;
    case 0x64: // FS
        current_data_segment = &regs.FS;
        break;
    case 0x65: // GS
        current_data_segment = &regs.GS;
        break;
    default:
        // Неизвестный префикс сегмента, можно игнорировать или установить ошибку
        std::cout << "Неизвестный сегментный префикс: 0x" << std::hex << (int)prefix << "\n";
        break;
    }
}
// Реализация метода 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();

            // Список префиксов
            const std::vector<uint8_t> prefixes = {
                0xF2, // REPNE/REPNZ
                0xF3, // REP/REPE/REPZ
                0xF0, // LOCK
                0x2E, // CS segment override
                0x36, // SS segment override
                0x3E, // DS segment override
                0x26, // ES segment override
                0x64, // FS segment override
                0x65, // GS segment override
                0x66, // Operand-size override
                0x67  // Address-size override
            };

            // Обработка префиксов
            while (std::find(prefixes.begin(), prefixes.end(), opcode) != prefixes.end()) {
                switch (opcode) {
                case 0xF2:
                    regs.repne_prefix = true;
                    break;
                case 0xF3:
                    regs.rep_prefix = true;
                    break;
                case 0xF0:
                    regs.lock_prefix = true;
                    break;
                case 0x66:
                    regs.operand_size_override = true;
                    break;
                case 0x67:
                    regs.address_size_override = true;
                    break;
                case 0x2E:
                case 0x36:
                case 0x3E:
                case 0x26:
                case 0x64:
                case 0x65:
                    set_segment_override(opcode);
                    break;
                    // Обработка других префиксов по необходимости
                default:
                    break;
                }

                std::cout << "Обнаружен префикс: 0x" << std::hex << (int)opcode << "\n";
                opcode = fetch_byte(); // Читаем следующий байт как опкод инструкции
            }

            // Проверка на двухбайтовый опкод
            bool is_extended = false;
            if (opcode == 0x0F) {
                is_extended = true;
                opcode = fetch_byte(); // Читаем второй байт опкода
            }

            if (is_extended) {
                auto it = extended_instruction_set.find(opcode);
                if (it != extended_instruction_set.end()) {
                    InstructionHandler handler = it->second;
                    (this->*handler)();
                }
                else {
                    std::cout << "Неизвестный двухбайтовый opcode: 0x0F 0x"
                        << std::hex << (int)opcode << "\n";
                    error_flag = true;
                    running = false;
                }
            }
            else {
                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;
                }
            }

            // После выполнения инструкции сбросить префиксы
            reset_segment_override();
            reset_prefixes();

        }
        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;
        }
    }
}

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;
}
// Метод 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;
    std::cout << "calculate_address called with mod=" << (int)mod << ", rm=" << (int)rm << "\n";
    uint32_t address = 0;

    if (mod == 0) {
        if (rm == 5) {
            // [disp32]
            uint32_t disp32 = fetch_dword();
            address = disp32;
        }
        else if (rm == 4) {
            // SIB byte
            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 byte с 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 byte с 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;
    }

    // Добавьте базу сегмента к вычисленному адресу
    // Для Data Segment
    address += *current_data_segment;

    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_GROUP1_Ev_Iz_83;
    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_GROUP1_Ev_Iz_81;
    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
    instruction_set[0x8D] = &Emulator::instr_LEA_r32_m;
    instruction_set[0xA4] = &Emulator::instr_MOVSB; // MOVSB opcode

    extended_instruction_set[0x84] = &Emulator::instr_JE_rel32;
    extended_instruction_set[0x85] = &Emulator::instr_JNE_rel32;
    extended_instruction_set[0x8F] = &Emulator::instr_JG_rel32;
    extended_instruction_set[0x8C] = &Emulator::instr_JL_rel32;
    extended_instruction_set[0x1E] = &Emulator::instr_NOP_EAX;
    extended_instruction_set[0x1E] = &Emulator::instr_NOP_m16_m32;
    instruction_set[0xFB] = &Emulator::instr_STI;
}
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_byte(uint32_t address, uint8_t value) {
    if (address >= memory.size()) {
        std::cerr << "Ошибка: Пытаетесь записать byte за пределы памяти. Адрес: 0x"
            << std::hex << address << std::dec << "\n";
        error_flag = true;    // Устанавливаем флаг ошибки
        running = false;      // Останавливаем выполнение эмулятора
        return;
    }
    memory[address] = value;  // Записываем байт в память
}
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)
}
// 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;
}
void Emulator::instr_NOP_EAX() {
    // Эта инструкция ничего не делает, можно просто вывести сообщение
    std::cout << "Выполнен NOP [EAX]\n";
}
void Emulator::instr_STI() {
    // Устанавливаем флаг прерываний (IF)
    regs.EFLAGS |= IF_FLAG;
    std::cout << "Выполнен STI: Установлен флаг прерываний (IF).\n";
}
void Emulator::instr_NOP_m16_m32() {
    // Инструкция NOP m16/32 имеет модификатор размера операнда
    // Если установлен префикс 0x66, то размер операнда 16 бит, иначе 32 бита
    bool operand_size = regs.operand_size_override;

    uint8_t modrm = fetch_byte();
    uint32_t address = calculate_address(modrm);

    if (operand_size) {
        // Чтение 16-битного операнда для NOP m16
        uint16_t temp = read_memory_byte(address) | (read_memory_byte(address + 1) << 8);
        // NOP не изменяет ничего, просто читаем для эмуляции
    }
    else {
        // Чтение 32-битного операнда для NOP m32
        uint32_t temp = read_memory_dword(address);
        // NOP не изменяет ничего, просто читаем для эмуляции
    }

    // NOP ничего не делает, поэтому ничего не изменяем
}
// 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();
    std::cout << "Executing ADD EAX, " << imm << " (Before EAX: " << regs.EAX << ")\n";
    regs.EAX += imm;
    std::cout << "After EAX: " << regs.EAX << "\n";
    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;
}
// Обработчик инструкции JE rel32 (0x0F 0x84)
void Emulator::instr_JE_rel32() {
    int32_t rel32 = fetch_dword(); // Читаем относительное смещение
    if (regs.EFLAGS & ZF) { // Проверка флага равенства
        regs.EIP += rel32;
    }
}

// Обработчик инструкции JNE rel32 (0x0F 0x85)
void Emulator::instr_JNE_rel32() {
    int32_t rel32 = fetch_dword(); // Читаем относительное смещение
    if (!(regs.EFLAGS & ZF)) { // Проверка флага неравенства
        regs.EIP += rel32;
    }
}

// Обработчик инструкции JG rel32 (0x0F 0x8F)
void Emulator::instr_JG_rel32() {
    int32_t rel32 = fetch_dword(); // Читаем относительное смещение
    bool zf = (regs.EFLAGS & ZF) != 0;
    bool sf = (regs.EFLAGS & SF) != 0;
    bool of = (regs.EFLAGS & OF) != 0;
    if (!zf && (sf == of)) {
        regs.EIP += rel32;
    }
}
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);

    //std::cout << "DIV instruction: Dividend = " << dividend << ", Operand = " << operand
        //<< ", EAX = " << regs.EAX << ", EDX = " << regs.EDX << "\n";

    update_ZF(regs.EAX);
}
void Emulator::instr_LEA_r32_m() {
    uint8_t modrm = fetch_byte();
    uint8_t mod = (modrm >> 6) & 0x03;
    uint8_t reg = (modrm >> 3) & 0x07; // Destination register code
    uint8_t rm = modrm & 0x07;         // Source operand

    // Calculate the effective address
    uint32_t address = calculate_address(modrm);
    if (error_flag)
        return;

    // Get the destination register
    uint32_t* dest_reg = get_register_by_code(reg);
    if (!dest_reg) {
        std::cout << "Unknown destination register in LEA.\n";
        error_flag = true;
        running = false;
        return;
    }

    // Store the effective address into the destination register
    *dest_reg = address;
}
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() {
    // Пример использования префикса LOCK
    bool is_locked = regs.lock_prefix;

    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) {
            if (is_locked) {
                // Реализуйте логику блокировки при необходимости
                // Например, вывод сообщения
                std::cout << "LOCK prefix applied to ADD r32, r/m32.\n";
            }
            *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);
        // Обновите другие флаги, если необходимо
    }
    reset_prefixes();
}
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;
}
// Обработчик для opcode 0x81 (32-битное непосредственное значение)
void Emulator::instr_GROUP1_Ev_Iz_81() {
    uint8_t modrm = fetch_byte();
    uint8_t mod = (modrm >> 6) & 0x03;
    uint8_t reg_opcode = (modrm >> 3) & 0x07; // Поле reg в ModRM
    uint8_t rm = modrm & 0x07;

    uint32_t* dest_reg = nullptr;
    if (mod == 3) { // Режим регистр-регистр
        dest_reg = get_register_by_code(rm);
    }
    else {
        // Обработка памяти (не реализовано)
        std::cout << "Memory operands not implemented for opcode 0x81.\n";
        error_flag = true;
        running = false;
        return;
    }

    uint32_t imm32 = fetch_dword(); // Чтение 32-битного непосредственного значения

    switch (reg_opcode) {
    case 0: // ADD
        *dest_reg += imm32;
        update_ZF(*dest_reg);
        break;
    case 1: // OR
        *dest_reg |= imm32;
        update_ZF(*dest_reg);
        break;
    case 2: // ADC
        // Реализуйте ADC при необходимости
        break;
    case 3: // SBB
        // Реализуйте SBB при необходимости
        break;
    case 4: // AND
        *dest_reg &= imm32;
        update_ZF(*dest_reg);
        break;
    case 5: // SUB
        *dest_reg -= imm32;
        update_ZF(*dest_reg);
        break;
    case 6: // XOR
        *dest_reg ^= imm32;
        update_ZF(*dest_reg);
        break;
    case 7: // CMP
    {
        uint32_t result = *dest_reg - imm32;
        update_ZF(result);
        // Обновите другие флаги при необходимости
    }
    break;
    default:
        std::cout << "Unsupported reg opcode in opcode 0x81: " << (int)reg_opcode << "\n";
        error_flag = true;
        running = false;
        break;
    }
}

// Обработчик для opcode 0x83 (8-битное непосредственное значение)
void Emulator::instr_GROUP1_Ev_Iz_83() {
    uint8_t modrm = fetch_byte();
    uint8_t mod = (modrm >> 6) & 0x03;
    uint8_t reg_opcode = (modrm >> 3) & 0x07; // Поле reg в ModRM
    uint8_t rm = modrm & 0x07;

    uint32_t* dest_reg = nullptr;
    if (mod == 3) { // Режим регистр-регистр
        dest_reg = get_register_by_code(rm);
    }
    else {
        // Обработка памяти (не реализовано)
        std::cout << "Memory operands not implemented for opcode 0x83.\n";
        error_flag = true;
        running = false;
        return;
    }

    int8_t imm8 = static_cast<int8_t>(fetch_byte()); // Чтение 8-битного непосредственного значения

    // Знаковое расширение до 32 бит
    int32_t sign_extended_imm = static_cast<int32_t>(imm8);

    switch (reg_opcode) {
    case 0: // ADD
        *dest_reg += sign_extended_imm;
        update_ZF(*dest_reg);
        break;
    case 1: // OR
        *dest_reg |= sign_extended_imm;
        update_ZF(*dest_reg);
        break;
    case 2: // ADC
        // Реализуйте ADC при необходимости
        break;
    case 3: // SBB
        // Реализуйте SBB при необходимости
        break;
    case 4: // AND
        *dest_reg &= sign_extended_imm;
        update_ZF(*dest_reg);
        break;
    case 5: // SUB
        *dest_reg -= sign_extended_imm;
        update_ZF(*dest_reg);
        break;
    case 6: // XOR
        *dest_reg ^= sign_extended_imm;
        update_ZF(*dest_reg);
        break;
    case 7: // CMP
    {
        uint32_t result = *dest_reg - sign_extended_imm;
        update_ZF(result);
        // Обновите другие флаги при необходимости
    }
    break;
    default:
        std::cout << "Unsupported reg opcode in opcode 0x83: " << (int)reg_opcode << "\n";
        error_flag = true;
        running = false;
        break;
    }
}
void Emulator::instr_JL_rel32() {
    int32_t rel32 = fetch_dword(); // Читаем относительное смещение
    bool sf = (regs.EFLAGS & SF) != 0;
    bool of = (regs.EFLAGS & OF) != 0;
    if (sf != of) {
        regs.EIP += rel32;
    }
}
void Emulator::instr_MOVSB() {
    // Обработка префиксов REP/REPE/REPNE
    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(byte);

            // Для `REPNE` можно добавить условия выхода
            if (is_repne && (regs.EFLAGS & ZF)) {
                break;
            }

            if (is_rep && regs.ECX == 0) {
                break;
            }
        }

        // Сброс префиксов после выполнения
        reset_prefixes();
    }
    else {
        // Обычное выполнение MOVSB без повторения
        uint8_t byte = read_memory_byte(regs.ESI);
        write_memory_byte(regs.EDI, byte);
        regs.ESI += 1;
        regs.EDI += 1;

        // Обновление флагов по необходимости
        update_ZF(byte);
    }
}

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;
        }
    }
    // ...
}
// 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.print_registers(true);
    // Запуск эмулятора
    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;
}
C:\Users\Swed\source\repos\x86_Emulator\x64\Debug>x86_Emulator.exe main.elf

Запуск программы из файла: main.elf...
Объем выделенной памяти эмулятора: 256 MB
Загрузка сегмента PT_LOAD:
  p_vaddr: 0x0
  p_memsz: 980 байт
  p_filesz: 980 байт
Загрузка сегмента PT_LOAD:
  p_vaddr: 0x1000
  p_memsz: 500 байт
  p_filesz: 500 байт
Загрузка сегмента PT_LOAD:
  p_vaddr: 0x2000
  p_memsz: 252 байт
  p_filesz: 252 байт
Загрузка сегмента PT_LOAD:
  p_vaddr: 0x3ed8
  p_memsz: 308 байт
  p_filesz: 304 байт
ELF-файл успешно загружен. Точка входа: 0x1070
Обнаружен префикс: 0xf3
calculate_address called with mod=3, rm=3
Unsupported ModR/M mod value in calculate_address.

Программа из ELF-файла не выполнена.
swed@DESKTOP-K5N5PON:~$ readelf -a main
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:                              DYN (Position-Independent Executable file)
  Machine:                           Intel 80386
  Version:                           0x1
  Entry point address:               0x1070
  Start of program headers:          52 (bytes into file)
  Start of section headers:          13780 (bytes into file)
  Flags:                             0x0
  Size of this header:               52 (bytes)
  Size of program headers:           32 (bytes)
  Number of program headers:         11
  Size of section headers:           40 (bytes)
  Number of section headers:         29
  Section header string table index: 28

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        00000194 000194 000013 00   A  0   0  1
  [ 2] .note.gnu.bu[...] NOTE            000001a8 0001a8 000024 00   A  0   0  4
  [ 3] .note.ABI-tag     NOTE            000001cc 0001cc 000020 00   A  0   0  4
  [ 4] .gnu.hash         GNU_HASH        000001ec 0001ec 000020 04   A  5   0  4
  [ 5] .dynsym           DYNSYM          0000020c 00020c 000080 10   A  6   1  4
  [ 6] .dynstr           STRTAB          0000028c 00028c 0000a6 00   A  0   0  1
  [ 7] .gnu.version      VERSYM          00000332 000332 000010 02   A  5   0  2
  [ 8] .gnu.version_r    VERNEED         00000344 000344 000040 00   A  6   1  4
  [ 9] .rel.dyn          REL             00000384 000384 000040 08   A  5   0  4
  [10] .rel.plt          REL             000003c4 0003c4 000010 08  AI  5  22  4
  [11] .init             PROGBITS        00001000 001000 000024 00  AX  0   0  4
  [12] .plt              PROGBITS        00001030 001030 000030 04  AX  0   0 16
  [13] .plt.got          PROGBITS        00001060 001060 000008 08  AX  0   0  8
  [14] .text             PROGBITS        00001070 001070 000169 00  AX  0   0 16
  [15] .fini             PROGBITS        000011dc 0011dc 000018 00  AX  0   0  4
  [16] .rodata           PROGBITS        00002000 002000 000015 00   A  0   0  4
  [17] .eh_frame_hdr     PROGBITS        00002018 002018 000034 00   A  0   0  4
  [18] .eh_frame         PROGBITS        0000204c 00204c 0000b0 00   A  0   0  4
  [19] .init_array       INIT_ARRAY      00003ed8 002ed8 000004 04  WA  0   0  4
  [20] .fini_array       FINI_ARRAY      00003edc 002edc 000004 04  WA  0   0  4
  [21] .dynamic          DYNAMIC         00003ee0 002ee0 0000f8 08  WA  6   0  4
  [22] .got              PROGBITS        00003fd8 002fd8 000028 04  WA  0   0  4
  [23] .data             PROGBITS        00004000 003000 000008 00  WA  0   0  4
  [24] .bss              NOBITS          00004008 003008 000004 00  WA  0   0  1
  [25] .comment          PROGBITS        00000000 003008 00002b 01  MS  0   0  1
  [26] .symtab           SYMTAB          00000000 003034 000280 10     27  18  4
  [27] .strtab           STRTAB          00000000 0032b4 000221 00      0   0  1
  [28] .shstrtab         STRTAB          00000000 0034d5 0000fc 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
  PHDR           0x000034 0x00000034 0x00000034 0x00160 0x00160 R   0x4
  INTERP         0x000194 0x00000194 0x00000194 0x00013 0x00013 R   0x1
      [Requesting program interpreter: /lib/ld-linux.so.2]
  LOAD           0x000000 0x00000000 0x00000000 0x003d4 0x003d4 R   0x1000
  LOAD           0x001000 0x00001000 0x00001000 0x001f4 0x001f4 R E 0x1000
  LOAD           0x002000 0x00002000 0x00002000 0x000fc 0x000fc R   0x1000
  LOAD           0x002ed8 0x00003ed8 0x00003ed8 0x00130 0x00134 RW  0x1000
  DYNAMIC        0x002ee0 0x00003ee0 0x00003ee0 0x000f8 0x000f8 RW  0x4
  NOTE           0x0001a8 0x000001a8 0x000001a8 0x00044 0x00044 R   0x4
  GNU_EH_FRAME   0x002018 0x00002018 0x00002018 0x00034 0x00034 R   0x4
  GNU_STACK      0x000000 0x00000000 0x00000000 0x00000 0x00000 RW  0x10
  GNU_RELRO      0x002ed8 0x00003ed8 0x00003ed8 0x00128 0x00128 R   0x1

 Section to Segment mapping:
  Segment Sections...
   00
   01     .interp
   02     .interp .note.gnu.build-id .note.ABI-tag .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rel.dyn .rel.plt
   03     .init .plt .plt.got .text .fini
   04     .rodata .eh_frame_hdr .eh_frame
   05     .init_array .fini_array .dynamic .got .data .bss
   06     .dynamic
   07     .note.gnu.build-id .note.ABI-tag
   08     .eh_frame_hdr
   09
   10     .init_array .fini_array .dynamic .got

Dynamic section at offset 0x2ee0 contains 27 entries:
  Tag        Type                         Name/Value
 0x00000001 (NEEDED)                     Shared library: [libc.so.6]
 0x0000000c (INIT)                       0x1000
 0x0000000d (FINI)                       0x11dc
 0x00000019 (INIT_ARRAY)                 0x3ed8
 0x0000001b (INIT_ARRAYSZ)               4 (bytes)
 0x0000001a (FINI_ARRAY)                 0x3edc
 0x0000001c (FINI_ARRAYSZ)               4 (bytes)
 0x6ffffef5 (GNU_HASH)                   0x1ec
 0x00000005 (STRTAB)                     0x28c
 0x00000006 (SYMTAB)                     0x20c
 0x0000000a (STRSZ)                      166 (bytes)
 0x0000000b (SYMENT)                     16 (bytes)
 0x00000015 (DEBUG)                      0x0
 0x00000003 (PLTGOT)                     0x3fd8
 0x00000002 (PLTRELSZ)                   16 (bytes)
 0x00000014 (PLTREL)                     REL
 0x00000017 (JMPREL)                     0x3c4
 0x00000011 (REL)                        0x384
 0x00000012 (RELSZ)                      64 (bytes)
 0x00000013 (RELENT)                     8 (bytes)
 0x0000001e (FLAGS)                      BIND_NOW
 0x6ffffffb (FLAGS_1)                    Flags: NOW PIE
 0x6ffffffe (VERNEED)                    0x344
 0x6fffffff (VERNEEDNUM)                 1
 0x6ffffff0 (VERSYM)                     0x332
 0x6ffffffa (RELCOUNT)                   4
 0x00000000 (NULL)                       0x0

Relocation section '.rel.dyn' at offset 0x384 contains 8 entries:
 Offset     Info    Type            Sym.Value  Sym. Name
00003ed8  00000008 R_386_RELATIVE
00003edc  00000008 R_386_RELATIVE
00003ff8  00000008 R_386_RELATIVE
00004004  00000008 R_386_RELATIVE
00003fec  00000206 R_386_GLOB_DAT    00000000   _ITM_deregisterTM[...]
00003ff0  00000306 R_386_GLOB_DAT    00000000   __cxa_finalize@GLIBC_2.1.3
00003ff4  00000506 R_386_GLOB_DAT    00000000   __gmon_start__
00003ffc  00000606 R_386_GLOB_DAT    00000000   _ITM_registerTMCl[...]

Relocation section '.rel.plt' at offset 0x3c4 contains 2 entries:
 Offset     Info    Type            Sym.Value  Sym. Name
00003fe4  00000107 R_386_JUMP_SLOT   00000000   __libc_start_main@GLIBC_2.34
00003fe8  00000407 R_386_JUMP_SLOT   00000000   puts@GLIBC_2.0
No processor specific unwind information to decode

Symbol table '.dynsym' contains 8 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 00000000     0 FUNC    GLOBAL DEFAULT  UND _[...]@GLIBC_2.34 (2)
     2: 00000000     0 NOTYPE  WEAK   DEFAULT  UND _ITM_deregisterT[...]
     3: 00000000     0 FUNC    WEAK   DEFAULT  UND [...]@GLIBC_2.1.3 (3)
     4: 00000000     0 FUNC    GLOBAL DEFAULT  UND puts@GLIBC_2.0 (4)
     5: 00000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__
     6: 00000000     0 NOTYPE  WEAK   DEFAULT  UND _ITM_registerTMC[...]
     7: 00002004     4 OBJECT  GLOBAL DEFAULT   16 _IO_stdin_used

Symbol table '.symtab' contains 40 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 00000000     0 FILE    LOCAL  DEFAULT  ABS Scrt1.o
     2: 000001cc    32 OBJECT  LOCAL  DEFAULT    3 __abi_tag
     3: 00000000     0 FILE    LOCAL  DEFAULT  ABS crtstuff.c
     4: 000010b0     0 FUNC    LOCAL  DEFAULT   14 deregister_tm_clones
     5: 000010f0     0 FUNC    LOCAL  DEFAULT   14 register_tm_clones
     6: 00001140     0 FUNC    LOCAL  DEFAULT   14 __do_global_dtors_aux
     7: 00004008     1 OBJECT  LOCAL  DEFAULT   24 completed.0
     8: 00003edc     0 OBJECT  LOCAL  DEFAULT   20 __do_global_dtor[...]
     9: 00001190     0 FUNC    LOCAL  DEFAULT   14 frame_dummy
    10: 00003ed8     0 OBJECT  LOCAL  DEFAULT   19 __frame_dummy_in[...]
    11: 00000000     0 FILE    LOCAL  DEFAULT  ABS main.c
    12: 00000000     0 FILE    LOCAL  DEFAULT  ABS crtstuff.c
    13: 000020f8     0 OBJECT  LOCAL  DEFAULT   18 __FRAME_END__
    14: 00000000     0 FILE    LOCAL  DEFAULT  ABS
    15: 00003ee0     0 OBJECT  LOCAL  DEFAULT   21 _DYNAMIC
    16: 00002018     0 NOTYPE  LOCAL  DEFAULT   17 __GNU_EH_FRAME_HDR
    17: 00003fd8     0 OBJECT  LOCAL  DEFAULT   22 _GLOBAL_OFFSET_TABLE_
    18: 00000000     0 FUNC    GLOBAL DEFAULT  UND __libc_start_mai[...]
    19: 00000000     0 NOTYPE  WEAK   DEFAULT  UND _ITM_deregisterT[...]
    20: 000010a0     4 FUNC    GLOBAL HIDDEN    14 __x86.get_pc_thunk.bx
    21: 00004000     0 NOTYPE  WEAK   DEFAULT   23 data_start
    22: 00004008     0 NOTYPE  GLOBAL DEFAULT   23 _edata
    23: 000011dc     0 FUNC    GLOBAL HIDDEN    15 _fini
    24: 00001199     0 FUNC    GLOBAL HIDDEN    14 __x86.get_pc_thunk.dx
    25: 00000000     0 FUNC    WEAK   DEFAULT  UND __cxa_finalize@G[...]
    26: 00004000     0 NOTYPE  GLOBAL DEFAULT   23 __data_start
    27: 00000000     0 FUNC    GLOBAL DEFAULT  UND puts@GLIBC_2.0
    28: 00000000     0 NOTYPE  WEAK   DEFAULT  UND __gmon_start__
    29: 00004004     0 OBJECT  GLOBAL HIDDEN    23 __dso_handle
    30: 00002004     4 OBJECT  GLOBAL DEFAULT   16 _IO_stdin_used
    31: 0000400c     0 NOTYPE  GLOBAL DEFAULT   24 _end
    32: 00001070    48 FUNC    GLOBAL DEFAULT   14 _start
    33: 00002000     4 OBJECT  GLOBAL DEFAULT   16 _fp_hw
    34: 00004008     0 NOTYPE  GLOBAL DEFAULT   24 __bss_start
    35: 0000119d    56 FUNC    GLOBAL DEFAULT   14 main
    36: 000011d5     0 FUNC    GLOBAL HIDDEN    14 __x86.get_pc_thunk.ax
    37: 00004008     0 OBJECT  GLOBAL HIDDEN    23 __TMC_END__
    38: 00000000     0 NOTYPE  WEAK   DEFAULT  UND _ITM_registerTMC[...]
    39: 00001000     0 FUNC    GLOBAL HIDDEN    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 8 entries:
 Addr: 0x0000000000000332  Offset: 0x000332  Link: 5 (.dynsym)
  000:   0 (*local*)       2 (GLIBC_2.34)    1 (*global*)      3 (GLIBC_2.1.3)
  004:   4 (GLIBC_2.0)     1 (*global*)      1 (*global*)      1 (*global*)

Version needs section '.gnu.version_r' contains 1 entry:
 Addr: 0x0000000000000344  Offset: 0x000344  Link: 6 (.dynstr)
  000000: Version: 1  File: libc.so.6  Cnt: 3
  0x0010:   Name: GLIBC_2.0  Flags: none  Version: 4
  0x0020:   Name: GLIBC_2.1.3  Flags: none  Version: 3
  0x0030:   Name: GLIBC_2.34  Flags: none  Version: 2

Displaying notes found in: .note.gnu.build-id
  Owner                Data size        Description
  GNU                  0x00000014       NT_GNU_BUILD_ID (unique build ID bitstring)
    Build ID: d8150e8db169812669012992f6413ac23eb1c8bb

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
Сама программа:
main.c
 #include <stdio.h>

void main() {
    printf("Hello World!\n");
}
Но она не работает в моём эмуляторе. Отправь исправленный код для того что бы программа полноценно работала.